cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

linuxboot.S (4523B)


      1/*
      2 * Linux Boot Option ROM
      3 *
      4 * This program is free software; you can redistribute it and/or modify
      5 * it under the terms of the GNU General Public License as published by
      6 * the Free Software Foundation; either version 2 of the License, or
      7 * (at your option) any later version.
      8 *
      9 * This program is distributed in the hope that it will be useful,
     10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     12 * GNU General Public License for more details.
     13 *
     14 * You should have received a copy of the GNU General Public License
     15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
     16 *
     17 * Copyright Novell Inc, 2009
     18 *   Authors: Alexander Graf <agraf@suse.de>
     19 *
     20 * Based on code in hw/pc.c.
     21 */
     22
     23#include "optionrom.h"
     24
     25#define BOOT_ROM_PRODUCT "Linux loader"
     26
     27BOOT_ROM_START
     28
     29run_linuxboot:
     30
     31	cli
     32	cld
     33
     34	jmp		copy_kernel
     35boot_kernel:
     36
     37	read_fw		FW_CFG_SETUP_ADDR
     38
     39	mov		%eax, %ebx
     40	shr		$4, %ebx
     41
     42	/* All segments contain real_addr */
     43	mov		%bx, %ds
     44	mov		%bx, %es
     45	mov		%bx, %fs
     46	mov		%bx, %gs
     47	mov		%bx, %ss
     48
     49	/* CX = CS we want to jump to */
     50	add		$0x20, %bx
     51	mov		%bx, %cx
     52
     53	/* SP = cmdline_addr-real_addr-16 */
     54	read_fw		FW_CFG_CMDLINE_ADDR
     55	mov		%eax, %ebx
     56	read_fw		FW_CFG_SETUP_ADDR
     57	sub		%eax, %ebx
     58	sub		$16, %ebx
     59	mov		%ebx, %esp
     60
     61	/* Build indirect lret descriptor */
     62	pushw		%cx		/* CS */
     63	xor		%ax, %ax
     64	pushw		%ax		/* IP = 0 */
     65
     66	/* Clear registers */
     67	xor		%eax, %eax
     68	xor		%ebx, %ebx
     69	xor		%ecx, %ecx
     70	xor		%edx, %edx
     71	xor		%edi, %edi
     72	xor		%ebp, %ebp
     73
     74	/* Jump to Linux */
     75	lret
     76
     77
     78copy_kernel:
     79	/* Read info block in low memory (0x10000 or 0x90000) */
     80	read_fw		FW_CFG_SETUP_ADDR
     81	shr		$4, %eax
     82	mov		%eax, %es
     83	xor		%edi, %edi
     84	read_fw_blob_addr32_edi(FW_CFG_SETUP)
     85
     86	cmpw            $0x203, %es:0x206      // if protocol >= 0x203
     87	jae             1f                     // have initrd_max
     88	movl            $0x37ffffff, %es:0x22c // else assume 0x37ffffff
     891:
     90
     91	/* Check if using kernel-specified initrd address */
     92	read_fw		FW_CFG_INITRD_ADDR
     93	mov		%eax, %edi             // (load_kernel wants it in %edi)
     94	read_fw		FW_CFG_INITRD_SIZE     // find end of initrd
     95	add		%edi, %eax
     96	xor		%es:0x22c, %eax        // if it matches es:0x22c
     97	and		$-4096, %eax           // (apart from padding for page)
     98	jz		load_kernel            // then initrd is not at top
     99					       // of memory
    100
    101	/* pc.c placed the initrd at end of memory.  Compute a better
    102	 * initrd address based on e801 data.
    103	 */
    104	mov		$0xe801, %ax
    105	xor		%cx, %cx
    106	xor		%dx, %dx
    107	int		$0x15
    108
    109	/* Output could be in AX/BX or CX/DX */
    110	or		%cx, %cx
    111	jnz		1f
    112	or		%dx, %dx
    113	jnz		1f
    114	mov		%ax, %cx
    115	mov		%bx, %dx
    1161:
    117
    118	or		%dx, %dx
    119	jnz		2f
    120	addw		$1024, %cx            /* add 1 MB */
    121	movzwl		%cx, %edi
    122	shll		$10, %edi             /* convert to bytes */
    123	jmp		3f
    124
    1252:
    126	addw		$16777216 >> 16, %dx  /* add 16 MB */
    127	movzwl		%dx, %edi
    128	shll		$16, %edi             /* convert to bytes */
    129
    1303:
    131	read_fw         FW_CFG_INITRD_SIZE
    132	subl            %eax, %edi
    133	andl            $-4096, %edi          /* EDI = start of initrd */
    134	movl		%edi, %es:0x218       /* put it in the header */
    135
    136load_kernel:
    137	/* We need to load the kernel into memory we can't access in 16 bit
    138	   mode, so let's get into 32 bit mode, write the kernel and jump
    139	   back again. */
    140
    141	/* Reserve space on the stack for our GDT descriptor. */
    142	mov             %esp, %ebp
    143	sub             $16, %esp
    144
    145	/* Now create the GDT descriptor */
    146	movw		$((3 * 8) - 1), -16(%bp)
    147	mov		%cs, %eax
    148	movzwl		%ax, %eax
    149	shl		$4, %eax
    150	addl		$gdt, %eax
    151	movl		%eax, -14(%bp)
    152
    153	/* And load the GDT */
    154	data32 lgdt	-16(%bp)
    155	mov		%ebp, %esp
    156
    157	/* Get us to protected mode now */
    158	mov		$1, %eax
    159	mov		%eax, %cr0
    160
    161	/* So we can set ES to a 32-bit segment */
    162	mov		$0x10, %eax
    163	mov		%eax, %es
    164
    165	/* We're now running in 16-bit CS, but 32-bit ES! */
    166
    167	/* Load kernel and initrd */
    168	read_fw_blob_addr32_edi(FW_CFG_INITRD)
    169	read_fw_blob_addr32(FW_CFG_KERNEL)
    170	read_fw_blob_addr32(FW_CFG_CMDLINE)
    171
    172	/* And now jump into Linux! */
    173	mov		$0, %eax
    174	mov		%eax, %cr0
    175
    176	/* ES = CS */
    177	mov		%cs, %ax
    178	mov		%ax, %es
    179
    180	jmp		boot_kernel
    181
    182/* Variables */
    183
    184.align 4, 0
    185gdt:
    186	/* 0x00 */
    187.byte	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    188
    189	/* 0x08: code segment (base=0, limit=0xfffff, type=32bit code exec/read, DPL=0, 4k) */
    190.byte	0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00
    191
    192	/* 0x10: data segment (base=0, limit=0xfffff, type=32bit data read/write, DPL=0, 4k) */
    193.byte	0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00
    194
    195BOOT_ROM_END