Merge remote-tracking branch 'bonzini/scsi-next' into staging
[qemu/opensuse.git] / pc-bios / optionrom / multiboot.S
blob003bcfb49fa0e72429d97bfbf9dd3a464f72a105
1 /*
2  * Multiboot 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  */
21 #include "optionrom.h"
23 #define BOOT_ROM_PRODUCT "multiboot loader"
25 #define MULTIBOOT_MAGIC         0x2badb002
27 #define GS_PROT_JUMP            0
28 #define GS_GDT_DESC             6
31 BOOT_ROM_START
33 run_multiboot:
35         cli
36         cld
38         mov             %cs, %eax
39         shl             $0x4, %eax
41         /* set up a long jump descriptor that is PC relative */
43         /* move stack memory to %gs */
44         mov             %ss, %ecx
45         shl             $0x4, %ecx
46         mov             %esp, %ebx
47         add             %ebx, %ecx
48         sub             $0x20, %ecx
49         sub             $0x30, %esp
50         shr             $0x4, %ecx
51         mov             %cx, %gs
53         /* now push the indirect jump descriptor there */
54         mov             (prot_jump), %ebx
55         add             %eax, %ebx
56         movl            %ebx, %gs:GS_PROT_JUMP
57         mov             $8, %bx
58         movw            %bx, %gs:GS_PROT_JUMP + 4
60         /* fix the gdt descriptor to be PC relative */
61         movw            (gdt_desc), %bx
62         movw            %bx, %gs:GS_GDT_DESC
63         movl            (gdt_desc+2), %ebx
64         add             %eax, %ebx
65         movl            %ebx, %gs:GS_GDT_DESC + 2
67         xor             %eax, %eax
68         mov             %eax, %es
70         /* Read the bootinfo struct into RAM */
71         read_fw_blob(FW_CFG_INITRD)
73         /* FS = bootinfo_struct */
74         read_fw         FW_CFG_INITRD_ADDR
75         shr             $4, %eax
76         mov             %ax, %fs
78         /* Account for the EBDA in the multiboot structure's e801
79          * map.
80          */
81         int             $0x12
82         cwtl
83         movl            %eax, %fs:4
85         /* ES = mmap_addr */
86         mov             %fs:48, %eax
87         shr             $4, %eax
88         mov             %ax, %es
90         /* Initialize multiboot mmap structs using int 0x15(e820) */
91         xor             %ebx, %ebx
92         /* mmap start after first size */
93         movl            $4, %edi
95 mmap_loop:
96         /* entry size (mmap struct) & max buffer size (int15) */
97         movl            $20, %ecx
98         /* store entry size */
99         /* old as(1) doesn't like this insn so emit the bytes instead:
100         movl            %ecx, %es:-4(%edi)
101         */
102         .dc.b           0x26,0x67,0x66,0x89,0x4f,0xfc
103         /* e820 */
104         movl            $0x0000e820, %eax
105         /* 'SMAP' magic */
106         movl            $0x534d4150, %edx
107         int             $0x15
109 mmap_check_entry:
110         /* last entry? then we're done */
111         jb              mmap_done
112         and             %bx, %bx
113         jz              mmap_done
114         /* valid entry, so let's loop on */
116 mmap_store_entry:
117         /* %ax = entry_number * 24 */
118         mov             $24, %ax
119         mul             %bx
120         mov             %ax, %di
121         movw            %di, %fs:0x2c
122         /* %di = 4 + (entry_number * 24) */
123         add             $4, %di
124         jmp             mmap_loop
126 mmap_done:
127 real_to_prot:
128         /* Load the GDT before going into protected mode */
129 lgdt:
130         data32 lgdt     %gs:GS_GDT_DESC
132         /* get us to protected mode now */
133         movl            $1, %eax
134         movl            %eax, %cr0
136         /* the LJMP sets CS for us and gets us to 32-bit */
137 ljmp:
138         data32 ljmp     *%gs:GS_PROT_JUMP
140 prot_mode:
141 .code32
143         /* initialize all other segments */
144         movl            $0x10, %eax
145         movl            %eax, %ss
146         movl            %eax, %ds
147         movl            %eax, %es
148         movl            %eax, %fs
149         movl            %eax, %gs
151         /* Read the kernel and modules into RAM */
152         read_fw_blob(FW_CFG_KERNEL)
154         /* Jump off to the kernel */
155         read_fw         FW_CFG_KERNEL_ENTRY
156         mov             %eax, %ecx
158         /* EBX contains a pointer to the bootinfo struct */
159         read_fw         FW_CFG_INITRD_ADDR
160         movl            %eax, %ebx
162         /* EAX has to contain the magic */
163         movl            $MULTIBOOT_MAGIC, %eax
164 ljmp2:
165         jmp             *%ecx
167 /* Variables */
168 .align 4, 0
169 prot_jump:      .long prot_mode
170                 .short 8
172 .align 4, 0
173 gdt:
174         /* 0x00 */
175 .byte   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
177         /* 0x08: code segment (base=0, limit=0xfffff, type=32bit code exec/read, DPL=0, 4k) */
178 .byte   0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00
180         /* 0x10: data segment (base=0, limit=0xfffff, type=32bit data read/write, DPL=0, 4k) */
181 .byte   0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00
183         /* 0x18: code segment (base=0, limit=0x0ffff, type=16bit code exec/read/conf, DPL=0, 1b) */
184 .byte   0xff, 0xff, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00
186         /* 0x20: data segment (base=0, limit=0x0ffff, type=16bit data read/write, DPL=0, 1b) */
187 .byte   0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00
189 gdt_desc:
190 .short  (5 * 8) - 1
191 .long   gdt
193 BOOT_ROM_END