qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

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 
     27 BOOT_ROM_START
     28 
     29 run_linuxboot:
     30 
     31 	cli
     32 	cld
     33 
     34 	jmp		copy_kernel
     35 boot_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 
     78 copy_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
     89 1:
     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
    116 1:
    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 
    125 2:
    126 	addw		$16777216 >> 16, %dx  /* add 16 MB */
    127 	movzwl		%dx, %edi
    128 	shll		$16, %edi             /* convert to bytes */
    129 
    130 3:
    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 
    136 load_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
    185 gdt:
    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 
    195 BOOT_ROM_END