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.
22 #include <multiboot.h>
25 EXTERN __bss_start__:DWORD
26 EXTERN __bss_end__:DWORD
27 EXTERN i386idtptr:FWORD
36 /* Setup segment registers */
45 mov sp, word ptr ds:stack16
55 /* Zero BootDrive and BootPartition */
57 mov dword ptr [_BootDrive], eax
58 mov dword ptr [_BootPartition], eax
60 /* Store the boot drive */
61 mov byte ptr [_BootDrive], dl
63 /* Store the boot partition */
64 mov byte ptr [_BootPartition], dh
75 /* We should never get here */
82 * Switches the processor to protected mode
88 cli /* None of these */
90 /* We don't know what values are currently */
91 /* in the segment registers. So we are */
92 /* going to reload them with sane values. */
93 /* Of course CS has to already be valid. */
94 /* We are currently in real-mode so we */
95 /* need real-mode segment values. */
103 /* Get the return address off the stack */
104 pop word ptr ds:[code32ret]
106 /* Save 16-bit stack pointer */
107 mov word ptr ds:[stack16], sp
114 /* Enable Protected Mode */
119 /* Clear prefetch queue & correct CS */
120 ljmp16 PMODE_CS, inpmode
126 /* Setup segment selectors */
133 mov esp, dword ptr [stack32]
135 /* Put the return address back onto the stack */
136 push dword ptr [code32ret]
138 /* Now return in p-mode! */
142 * Switches the processor back to real mode
145 PUBLIC switch_to_real
148 /* We don't know what values are currently */
149 /* in the segment registers. So we are */
150 /* going to reload them with sane values. */
151 /* Of course CS has to already be valid. */
152 /* We are currently in protected-mode so we */
153 /* need protected-mode segment values. */
161 /* Get the return address off the stack */
162 pop dword ptr [code16ret]
164 /* Save 32-bit stack pointer */
165 mov dword ptr [stack32], esp
167 /* jmp to 16-bit segment to set the limit correctly */
168 ljmp RMODE_CS, switch_to_real16
173 /* Restore segment registers to correct limit */
181 /* Disable Protected Mode */
186 /* Clear prefetch queue & correct CS */
187 //ljmp16 0, offset inrmode
188 jmp far ptr 0:inrmode
198 /* Clear out the high 16-bits of ESP */
199 /* This is needed because I have one */
200 /* machine that hangs when booted to dos if */
201 /* anything other than 0x0000 is in the high */
202 /* 16-bits of ESP. Even though real-mode */
203 /* code should only use SP and not ESP. */
206 mov sp, word ptr ds:[stack16]
208 /* Put the return address back onto the stack */
209 push word ptr ds:[code16ret]
211 /* Load IDTR with real mode value */
214 sti /* These are ok now */
216 /* Now return in r-mode! */
221 * Needed for enabling the a20 address line
224 .word HEX(00eb), HEX(00eb) // jmp $+2, jmp $+2
226 cmp al, HEX(ff) // legacy-free machine without keyboard
227 jz empty_8042_ret // controllers on Intel Macs read back 0xFF
237 * Enable the A20 address line (to allow access to over 1mb)
248 mov al, HEX(D1) // command write
251 mov al, HEX(DF) // A20 on
264 * Disable the A20 address line
276 mov al, HEX(D1) // command write
279 mov al, HEX(DD) // A20 off
293 * Allows freeldr to be loaded as a "multiboot kernel" by
294 * other boot loaders like Grub
297 #define MB_INFO_SIZE 90
298 #define MB_INFO_FLAGS_OFFSET 0
299 #define MB_INFO_BOOT_DEVICE_OFFSET 12
300 #define MB_INFO_COMMAND_LINE_OFFSET 16
301 #define CMDLINE_SIZE 256
304 * We want to execute at 0x8000 (to be compatible with bootsector
305 * loading), but Grub only allows loading of multiboot kernels
306 * above 1MB. So we let Grub load us there and then relocate
309 #define FREELDR_BASE HEX(8000)
310 #define INITIAL_BASE HEX(200000)
312 /* Align 32 bits boundary */
315 /* Multiboot header */
318 .long MULTIBOOT_HEADER_MAGIC
320 .long MULTIBOOT_HEADER_FLAGS
322 .long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
324 .long INITIAL_BASE + MultibootHeader - FREELDR_BASE
328 .long INITIAL_BASE + __bss_start__ - FREELDR_BASE
330 .long INITIAL_BASE + __bss_end__ - FREELDR_BASE
332 .long INITIAL_BASE + MultibootEntry - FREELDR_BASE
335 cli /* Even after setting up the our IDT below we are
336 * not ready to handle hardware interrupts (no entries
337 * in IDT), so there's no sti here. Interrupts will be
338 * enabled in due time */
340 /* Although the multiboot spec says we should be called with the
341 * segment registers set to 4GB flat mode, let's be sure and set up
343 lgdt gdtptrhigh + INITIAL_BASE - FREELDR_BASE
344 /* Reload segment selectors */
345 ljmp PMODE_CS, (mb1 + INITIAL_BASE - FREELDR_BASE)
346 //jmp far ptr PMODE_CS: (offset mb1 + INITIAL_BASE - FREELDR_BASE)
352 /* Check for valid multiboot signature */
353 cmp eax, MULTIBOOT_BOOTLOADER_MAGIC
356 /* Store multiboot info in a safe place */
358 mov edi, offset mb_info + INITIAL_BASE - FREELDR_BASE
359 mov ecx, MB_INFO_SIZE
362 /* Save commandline */
363 mov edx, [ebx + MB_INFO_FLAGS_OFFSET]
364 test dword ptr [ebx + MB_INFO_FLAGS_OFFSET], MB_INFO_FLAG_COMMAND_LINE
366 mov esi, [ebx + MB_INFO_COMMAND_LINE_OFFSET]
367 mov edi, offset cmdline + INITIAL_BASE - FREELDR_BASE
368 mov ecx, CMDLINE_SIZE
377 /* Copy to low mem */
378 mov esi, INITIAL_BASE
379 mov edi, FREELDR_BASE
380 mov ecx, (offset __bss_end__ - FREELDR_BASE)
385 /* Load the GDT and IDT */
389 /* Clear prefetch queue & correct CS,
392 //jmp far ptr PMODE_CS:mb4
394 /* Reload segment selectors */
403 mov ebx, offset mb_info
404 /* See if the boot device was passed in */
405 mov edx, [ebx + MB_INFO_FLAGS_OFFSET]
406 test edx, MB_INFO_FLAG_BOOT_DEVICE
408 /* Retrieve boot device info */
409 mov eax, [ebx + MB_INFO_BOOT_DEVICE_OFFSET]
412 mov byte ptr _BootPartition, al
413 mov byte ptr _BootDrive, ah
415 mb5: /* No boot device known, assume first partition of first harddisk */
416 mov byte ptr _BootDrive, HEX(80)
417 mov byte ptr _BootPartition, 1
419 /* Check for command line */
420 mov eax, offset cmdline
421 test dword ptr [ebx + MB_INFO_FLAGS_OFFSET], MB_INFO_FLAG_COMMAND_LINE
435 jmp mbstop /* We should never get here */
440 /* 16-bit stack pointer */
444 /* 32-bit stack pointer */
448 /* 16-bit return address */
452 /* 32-bit return address */
457 .align 4 /* force 4-byte alignment */
459 /* NULL Descriptor */
477 /* 16-bit real mode CS */
483 /* 16-bit real mode DS */
489 /* GDT table pointer */
491 .word HEX(27) /* Limit */
492 .long gdt /* Base Address */
494 /* Initial GDT table pointer for multiboot */
496 .word HEX(27) /* Limit */
497 .long gdt + INITIAL_BASE - FREELDR_BASE /* Base Address */
499 /* Real-mode IDT pointer */
501 .word HEX(3ff) /* Limit */
502 .long 0 /* Base Address */
505 .fill MB_INFO_SIZE, 1, 0
508 .fill CMDLINE_SIZE, 1, 0
514 PUBLIC _BootPartition