Merge branch 'target-arm.next' of git://git.linaro.org/people/pmaydell/qemu-arm
[qemu/opensuse.git] / pc-bios / optionrom / linuxboot.S
blob748c831160983dd711284f7af33803b6d0f07e07
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  */
23 #include "optionrom.h"
25 #define BOOT_ROM_PRODUCT "Linux loader"
27 BOOT_ROM_START
29 run_linuxboot:
31         cli
32         cld
34         jmp             copy_kernel
35 boot_kernel:
37         read_fw         FW_CFG_SETUP_ADDR
39         mov             %eax, %ebx
40         shr             $4, %ebx
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
49         /* CX = CS we want to jump to */
50         add             $0x20, %bx
51         mov             %bx, %cx
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
61         /* Build indirect lret descriptor */
62         pushw           %cx             /* CS */
63         xor             %ax, %ax
64         pushw           %ax             /* IP = 0 */
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
74         /* Jump to Linux */
75         lret
78 copy_kernel:
80         /* We need to load the kernel into memory we can't access in 16 bit
81            mode, so let's get into 32 bit mode, write the kernel and jump
82            back again. */
84         /* Reserve space on the stack for our GDT descriptor. */
85         mov             %esp, %ebp
86         sub             $16, %esp
88         /* Now create the GDT descriptor */
89         movw            $((3 * 8) - 1), -16(%bp)
90         mov             %cs, %eax
91         movzwl          %ax, %eax
92         shl             $4, %eax
93         addl            $gdt, %eax
94         movl            %eax, -14(%bp)
96         /* And load the GDT */
97         data32 lgdt     -16(%bp)
98         mov             %ebp, %esp
100         /* Get us to protected mode now */
101         mov             $1, %eax
102         mov             %eax, %cr0
104         /* So we can set ES to a 32-bit segment */
105         mov             $0x10, %eax
106         mov             %eax, %es
108         /* We're now running in 16-bit CS, but 32-bit ES! */
110         /* Load kernel and initrd */
111         read_fw_blob_addr32(FW_CFG_KERNEL)
112         read_fw_blob_addr32(FW_CFG_INITRD)
113         read_fw_blob_addr32(FW_CFG_CMDLINE)
114         read_fw_blob_addr32(FW_CFG_SETUP)
116         /* And now jump into Linux! */
117         mov             $0, %eax
118         mov             %eax, %cr0
120         /* ES = CS */
121         mov             %cs, %ax
122         mov             %ax, %es
124         jmp             boot_kernel
126 /* Variables */
128 .align 4, 0
129 gdt:
130         /* 0x00 */
131 .byte   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
133         /* 0x08: code segment (base=0, limit=0xfffff, type=32bit code exec/read, DPL=0, 4k) */
134 .byte   0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00
136         /* 0x10: data segment (base=0, limit=0xfffff, type=32bit data read/write, DPL=0, 4k) */
137 .byte   0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00
139 BOOT_ROM_END