target-mips: add KScratch registers
[qemu/ar7.git] / pc-bios / optionrom / linuxboot.S
blob5bc0af08e0f7dc7abdf55320baf0461170342f0f
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:
79         /* Compute initrd address */
80         mov             $0xe801, %ax
81         xor             %cx, %cx
82         xor             %dx, %dx
83         int             $0x15
85         /* Output could be in AX/BX or CX/DX */
86         or              %cx, %cx
87         jnz             1f
88         or              %dx, %dx
89         jnz             1f
90         mov             %ax, %cx
91         mov             %bx, %dx
94         or              %dx, %dx
95         jnz             2f
96         addw            $1024, %cx            /* add 1 MB */
97         movzwl          %cx, %edi
98         shll            $10, %edi             /* convert to bytes */
99         jmp             3f
102         addw            $16777216 >> 16, %dx  /* add 16 MB */
103         movzwl          %dx, %edi
104         shll            $16, %edi             /* convert to bytes */
107         read_fw         FW_CFG_INITRD_SIZE
108         subl            %eax, %edi
109         andl            $-4096, %edi          /* EDI = start of initrd */
111         /* We need to load the kernel into memory we can't access in 16 bit
112            mode, so let's get into 32 bit mode, write the kernel and jump
113            back again. */
115         /* Reserve space on the stack for our GDT descriptor. */
116         mov             %esp, %ebp
117         sub             $16, %esp
119         /* Now create the GDT descriptor */
120         movw            $((3 * 8) - 1), -16(%bp)
121         mov             %cs, %eax
122         movzwl          %ax, %eax
123         shl             $4, %eax
124         addl            $gdt, %eax
125         movl            %eax, -14(%bp)
127         /* And load the GDT */
128         data32 lgdt     -16(%bp)
129         mov             %ebp, %esp
131         /* Get us to protected mode now */
132         mov             $1, %eax
133         mov             %eax, %cr0
135         /* So we can set ES to a 32-bit segment */
136         mov             $0x10, %eax
137         mov             %eax, %es
139         /* We're now running in 16-bit CS, but 32-bit ES! */
141         /* Load kernel and initrd */
142         pushl           %edi
143         read_fw_blob_addr32_edi(FW_CFG_INITRD)
144         read_fw_blob_addr32(FW_CFG_KERNEL)
145         read_fw_blob_addr32(FW_CFG_CMDLINE)
147         read_fw         FW_CFG_SETUP_ADDR
148         mov             %eax, %edi
149         mov             %eax, %ebx
150         read_fw_blob_addr32_edi(FW_CFG_SETUP)
152         /* Update the header with the initrd address we chose above */
153         popl            %es:0x218(%ebx)
155         /* And now jump into Linux! */
156         mov             $0, %eax
157         mov             %eax, %cr0
159         /* ES = CS */
160         mov             %cs, %ax
161         mov             %ax, %es
163         jmp             boot_kernel
165 /* Variables */
167 .align 4, 0
168 gdt:
169         /* 0x00 */
170 .byte   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
172         /* 0x08: code segment (base=0, limit=0xfffff, type=32bit code exec/read, DPL=0, 4k) */
173 .byte   0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00
175         /* 0x10: data segment (base=0, limit=0xfffff, type=32bit data read/write, DPL=0, 4k) */
176 .byte   0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00
178 BOOT_ROM_END