5c1e7241dd1ce3ad506b732c9c6e67b10d34d72a
[reactos.git] / reactos / boot / freeldr / freeldr / arch / i386 / multiboot.S
1 /*
2 * FreeLoader
3 * Copyright (C) 1998-2002 Brian Palmer <brianp@sginet.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include <asm.inc>
21 #include <arch/pc/x86common.h>
22 #include <multiboot.h>
23
24
25 /* Multiboot support
26 *
27 * Allows freeldr to be loaded as a "multiboot kernel" by
28 * other boot loaders like Grub
29 * This code is not referenced from anywhere. GRUB searches for
30 * the header signature and uses the header to load it.
31 */
32
33 #define MB_INFO_SIZE 90
34 #define MB_INFO_FLAGS_OFFSET 0
35 #define MB_INFO_BOOT_DEVICE_OFFSET 12
36 #define MB_INFO_COMMAND_LINE_OFFSET 16
37 #define CMDLINE_SIZE 256
38
39 /*
40 * We want to execute at 0x8000 (to be compatible with bootsector
41 * loading), but Grub only allows loading of multiboot kernels
42 * above 1MB. So we let Grub load us there and then relocate
43 * ourself to 0x8000
44 */
45 #define INITIAL_BASE HEX(200000)
46
47 /* Align 32 bits boundary */
48 .align 4
49
50 /* Multiboot header */
51 MultibootHeader:
52 /* magic */
53 .long MULTIBOOT_HEADER_MAGIC
54 /* flags */
55 .long MULTIBOOT_HEADER_FLAGS
56 /* checksum */
57 .long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
58 /* header_addr */
59 .long INITIAL_BASE + MultibootHeader - FREELDR_BASE
60 /* load_addr */
61 .long INITIAL_BASE
62 /* load_end_addr */
63 .long INITIAL_BASE + __bss_start__ - FREELDR_BASE
64 /* bss_end_addr */
65 .long INITIAL_BASE + __bss_end__ - FREELDR_BASE
66 /* entry_addr */
67 .long INITIAL_BASE + MultibootEntry - FREELDR_BASE
68
69 MultibootEntry:
70 cli /* Even after setting up the our IDT below we are
71 * not ready to handle hardware interrupts (no entries
72 * in IDT), so there's no sti here. Interrupts will be
73 * enabled in due time */
74
75 /* Although the multiboot spec says we should be called with the
76 * segment registers set to 4GB flat mode, let's be sure and set up
77 * our own */
78 lgdt gdtptrhigh + INITIAL_BASE - FREELDR_BASE
79 /* Reload segment selectors */
80 //ljmp $PMODE_CS, $(mb1 + INITIAL_BASE - FREELDR_BASE)
81 jmp far ptr PMODE_CS: (mb1 + INITIAL_BASE - FREELDR_BASE)
82 mb1:
83 mov dx, PMODE_DS
84 mov ds, dx
85 mov es, dx
86
87 /* Check for valid multiboot signature */
88 cmp eax, MULTIBOOT_BOOTLOADER_MAGIC
89 jne mbfail
90
91 /* Store multiboot info in a safe place */
92 mov esi, ebx
93 mov edi, offset mb_info + INITIAL_BASE - FREELDR_BASE
94 mov ecx, MB_INFO_SIZE
95 rep movsb
96
97 /* Save commandline */
98 mov edx, [ebx + MB_INFO_FLAGS_OFFSET]
99 test dword ptr [ebx + MB_INFO_FLAGS_OFFSET], MB_INFO_FLAG_COMMAND_LINE
100 jz mb3
101 mov esi, [ebx + MB_INFO_COMMAND_LINE_OFFSET]
102 mov edi, offset cmdline + INITIAL_BASE - FREELDR_BASE
103 mov ecx, CMDLINE_SIZE
104 mb2: lodsb
105 stosb
106 test al, al
107 jz mb3
108 dec ecx
109 jnz mb2
110 mb3:
111
112 /* Copy to low mem */
113 mov esi, INITIAL_BASE
114 mov edi, FREELDR_BASE
115 mov ecx, (offset __bss_end__ - FREELDR_BASE)
116 add ecx, 3
117 shr ecx, 2
118 rep movsd
119
120 /* Load the GDT and IDT */
121 lgdt gdtptr
122 lidt i386idtptr
123
124 /* Clear prefetch queue & correct CS,
125 * jump to low mem */
126 //ljmp $PMODE_CS, $mb4
127 jmp far ptr PMODE_CS:mb4
128 mb4:
129 /* Reload segment selectors */
130 mov dx, PMODE_DS
131 mov ds, dx
132 mov es, dx
133 mov fs, dx
134 mov gs, dx
135 mov ss, dx
136 mov esp, STACK32ADDR
137
138 mov ebx, offset mb_info
139 /* See if the boot device was passed in */
140 mov edx, [ebx + MB_INFO_FLAGS_OFFSET]
141 test edx, MB_INFO_FLAG_BOOT_DEVICE
142 jz mb5
143 /* Retrieve boot device info */
144 mov eax, [ebx + MB_INFO_BOOT_DEVICE_OFFSET]
145 shr eax, 16
146 inc al
147 mov byte ptr [_FrldrBootPartition], al
148 mov byte ptr [_FrldrBootDrive], ah
149 jmp mb6
150 mb5: /* No boot device known, assume first partition of first harddisk */
151 mov byte ptr [_FrldrBootDrive], HEX(80)
152 mov byte ptr [_FrldrBootPartition], 1
153 mb6:
154 /* Check for command line */
155 mov eax, offset cmdline
156 test dword ptr [ebx + MB_INFO_FLAGS_OFFSET], MB_INFO_FLAG_COMMAND_LINE
157 jnz mb7
158 xor eax, eax
159 mb7:
160
161 /* GO! */
162 push eax
163 call _BootMain
164
165 mbfail:
166 int 3
167 mbstop: jmp mbstop /* We should never get here */
168
169 mb_info:
170 .fill MB_INFO_SIZE, 1, 0
171
172 cmdline:
173 .fill CMDLINE_SIZE, 1, 0
174
175 .align 4 /* force 4-byte alignment */
176 gdt:
177 /* NULL Descriptor */
178 .word HEX(0000)
179 .word HEX(0000)
180 .word HEX(0000)
181 .word HEX(0000)
182
183 /* 32-bit flat CS */
184 .word HEX(FFFF)
185 .word HEX(0000)
186 .word HEX(9A00)
187 .word HEX(00CF)
188
189 /* 32-bit flat DS */
190 .word HEX(FFFF)
191 .word HEX(0000)
192 .word HEX(9200)
193 .word HEX(00CF)
194
195 /* 16-bit real mode CS */
196 .word HEX(FFFF)
197 .word HEX(0000)
198 .word HEX(9E00)
199 .word HEX(0000)
200
201 /* 16-bit real mode DS */
202 .word HEX(FFFF)
203 .word HEX(0000)
204 .word HEX(9200)
205 .word HEX(0000)
206
207 /* GDT table pointer */
208 gdtptr:
209 .word HEX(27) /* Limit */
210 .long gdt /* Base Address */
211
212 /* Initial GDT table pointer for multiboot */
213 gdtptrhigh:
214 .word HEX(27) /* Limit */
215 .long gdt + INITIAL_BASE - FREELDR_BASE /* Base Address */