3 * Copyright (C) 1998-2002 Brian Palmer <brianp@sginet.com>
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.
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.
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.
20 .intel_syntax noprefix
25 #include <multiboot.h>
29 EXTERN(RealEntryPoint)
33 /* Setup segment registers */
42 mov sp, word ptr ds:stack16
51 /* Zero BootDrive and BootPartition */
53 mov dword ptr [_BootDrive], eax
54 mov dword ptr [_BootPartition], eax
56 /* Store the boot drive */
57 mov byte ptr [_BootDrive], dl
59 /* Store the boot partition */
60 mov byte ptr [_BootPartition], dh
71 /* We should never get here */
78 * Switches the processor to protected mode
81 EXTERN(switch_to_prot)
85 cli /* None of these */
87 /* We don't know what values are currently */
88 /* in the segment registers. So we are */
89 /* going to reload them with sane values. */
90 /* Of course CS has to already be valid. */
91 /* We are currently in real-mode so we */
92 /* need real-mode segment values. */
100 /* Get the return address off the stack */
101 pop word ptr ds:[code32ret]
103 /* Save 16-bit stack pointer */
104 mov word ptr ds:[stack16], sp
111 /* Enable Protected Mode */
116 /* Clear prefetch queue & correct CS */
117 //ljmp PMODE_CS, inpmode
118 jmp far ptr PMODE_CS:inpmode
123 /* Setup segment selectors */
130 mov esp, dword ptr [stack32]
132 /* Put the return address back onto the stack */
133 push dword ptr [code32ret]
135 /* Now return in p-mode! */
139 * Switches the processor back to real mode
142 EXTERN(switch_to_real)
146 /* We don't know what values are currently */
147 /* in the segment registers. So we are */
148 /* going to reload them with sane values. */
149 /* Of course CS has to already be valid. */
150 /* We are currently in protected-mode so we */
151 /* need protected-mode segment values. */
159 /* Get the return address off the stack */
160 pop dword ptr [code16ret]
162 /* Save 32-bit stack pointer */
163 mov dword ptr [stack32], esp
165 /* jmp to 16-bit segment to set the limit correctly */
166 ljmp RMODE_CS, switch_to_real16
171 /* Restore segment registers to correct limit */
179 /* Disable Protected Mode */
184 /* Clear prefetch queue & correct CS */
186 jmp far ptr 0:inrmode
196 /* Clear out the high 16-bits of ESP */
197 /* This is needed because I have one */
198 /* machine that hangs when booted to dos if */
199 /* anything other than 0x0000 is in the high */
200 /* 16-bits of ESP. Even though real-mode */
201 /* code should only use SP and not ESP. */
204 mov sp, word ptr ds:[stack16]
206 /* Put the return address back onto the stack */
207 push word ptr ds:[code16ret]
209 /* Load IDTR with real mode value */
212 sti /* These are ok now */
214 /* Now return in r-mode! */
219 * Needed for enabling the a20 address line
223 .word 0x00eb,0x00eb // jmp $+2, jmp $+2
225 cmp al, HEX(ff) // legacy-free machine without keyboard
226 jz empty_8042_ret // controllers on Intel Macs read back 0xFF
233 * Enable the A20 address line (to allow access to over 1mb)
244 mov al, HEX(D1) // command write
247 mov al, HEX(DF) // A20 on
258 * Disable the A20 address line
269 mov al, HEX(D1) // command write
272 mov al, HEX(DD) // A20 off
284 * Allows freeldr to be loaded as a "multiboot kernel" by
285 * other boot loaders like Grub
288 #define MB_INFO_SIZE 90
289 #define MB_INFO_FLAGS_OFFSET 0
290 #define MB_INFO_BOOT_DEVICE_OFFSET 12
291 #define MB_INFO_COMMAND_LINE_OFFSET 16
292 #define CMDLINE_SIZE 256
295 * We want to execute at 0x8000 (to be compatible with bootsector
296 * loading), but Grub only allows loading of multiboot kernels
297 * above 1MB. So we let Grub load us there and then relocate
300 #define FREELDR_BASE HEX(8000)
301 #define INITIAL_BASE HEX(200000)
303 /* Align 32 bits boundary */
306 /* Multiboot header */
309 .long MULTIBOOT_HEADER_MAGIC
311 .long MULTIBOOT_HEADER_FLAGS
313 .long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
315 .long INITIAL_BASE + MultibootHeader - FREELDR_BASE
319 .long INITIAL_BASE + __bss_start__ - FREELDR_BASE
321 .long INITIAL_BASE + __bss_end__ - FREELDR_BASE
323 .long INITIAL_BASE + MultibootEntry - FREELDR_BASE
326 cli /* Even after setting up the our IDT below we are
327 * not ready to handle hardware interrupts (no entries
328 * in IDT), so there's no sti here. Interrupts will be
329 * enabled in due time */
331 /* Although the multiboot spec says we should be called with the
332 * segment registers set to 4GB flat mode, let's be sure and set up
334 lgdt gdtptrhigh + INITIAL_BASE - FREELDR_BASE
335 /* Reload segment selectors */
336 //ljmp $PMODE_CS, $(mb1 + INITIAL_BASE - FREELDR_BASE)
337 jmp far ptr PMODE_CS: (mb1 + INITIAL_BASE - FREELDR_BASE)
343 /* Check for valid multiboot signature */
344 cmp eax, MULTIBOOT_BOOTLOADER_MAGIC
347 /* Store multiboot info in a safe place */
349 mov edi, offset mb_info + INITIAL_BASE - FREELDR_BASE
350 mov ecx, MB_INFO_SIZE
353 /* Save commandline */
354 mov edx, [ebx + MB_INFO_FLAGS_OFFSET]
355 test dword ptr [ebx + MB_INFO_FLAGS_OFFSET], MB_INFO_FLAG_COMMAND_LINE
357 mov esi, [ebx + MB_INFO_COMMAND_LINE_OFFSET]
358 mov edi, offset cmdline + INITIAL_BASE - FREELDR_BASE
359 mov ecx, CMDLINE_SIZE
368 /* Copy to low mem */
369 mov esi, INITIAL_BASE
370 mov edi, FREELDR_BASE
371 mov ecx, (offset __bss_end__ - FREELDR_BASE)
376 /* Load the GDT and IDT */
380 /* Clear prefetch queue & correct CS,
382 //ljmp $PMODE_CS, $mb4
383 jmp far ptr PMODE_CS:mb4
385 /* Reload segment selectors */
394 mov ebx, offset mb_info
395 /* See if the boot device was passed in */
396 mov edx, [ebx + MB_INFO_FLAGS_OFFSET]
397 test edx, MB_INFO_FLAG_BOOT_DEVICE
399 /* Retrieve boot device info */
400 mov eax, [ebx + MB_INFO_BOOT_DEVICE_OFFSET]
403 mov byte ptr _BootPartition, al
404 mov byte ptr _BootDrive, ah
406 mb5: /* No boot device known, assume first partition of first harddisk */
407 mov byte ptr _BootDrive, HEX(80)
408 mov byte ptr _BootPartition, 1
410 /* Check for command line */
411 mov eax, offset cmdline
412 test dword ptr [ebx + MB_INFO_FLAGS_OFFSET], MB_INFO_FLAG_COMMAND_LINE
425 mbstop: jmp mbstop /* We should never get here */
429 /* 16-bit stack pointer */
433 /* 32-bit stack pointer */
437 /* 16-bit return address */
441 /* 32-bit return address */
446 .align 4 /* force 4-byte alignment */
448 /* NULL Descriptor */
466 /* 16-bit real mode CS */
472 /* 16-bit real mode DS */
478 /* GDT table pointer */
480 .word HEX(27) /* Limit */
481 .long gdt /* Base Address */
483 /* Initial GDT table pointer for multiboot */
485 .word HEX(27) /* Limit */
486 .long gdt + INITIAL_BASE - FREELDR_BASE /* Base Address */
488 /* Real-mode IDT pointer */
490 .word HEX(3ff) /* Limit */
491 .long 0 /* Base Address */
494 .fill MB_INFO_SIZE, 1, 0
497 .fill CMDLINE_SIZE, 1, 0
502 EXTERN(_BootPartition)