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
24 #include <arch/pc/x86common.h>
25 #include <multiboot.h>
29 PUBLIC _RealEntryPoint
32 /* Setup segment selectors */
40 /* Setup protected mode stack */
41 mov esp, dword ptr [stack32]
46 /* Continue execution */
47 jmp dword ptr [_ContinueAddress]
55 /* Store BootDrive and BootPartition */
58 mov dword ptr [_FrldrBootDrive], eax
60 mov dword ptr [_FrldrBootPartition], eax
67 /* We should never get here */
74 * Switches the processor to protected mode
77 EXTERN(switch_to_prot)
81 cli /* None of these */
83 /* We don't know what values are currently */
84 /* in the segment registers. So we are */
85 /* going to reload them with sane values. */
86 /* Of course CS has to already be valid. */
87 /* We are currently in real-mode so we */
88 /* need real-mode segment values. */
96 /* Get the return address off the stack */
97 pop word ptr ds:[code32ret]
99 /* Save 16-bit stack pointer */
100 mov word ptr ds:[stack16], sp
107 /* Enable Protected Mode */
112 /* Clear prefetch queue & correct CS */
113 //ljmp PMODE_CS, inpmode
114 jmp far ptr PMODE_CS:inpmode
119 /* Setup segment selectors */
126 mov esp, dword ptr [stack32]
128 /* Put the return address back onto the stack */
129 push dword ptr [code32ret]
131 /* Now return in p-mode! */
135 * Switches the processor back to real mode
138 EXTERN(switch_to_real)
142 /* We don't know what values are currently */
143 /* in the segment registers. So we are */
144 /* going to reload them with sane values. */
145 /* Of course CS has to already be valid. */
146 /* We are currently in protected-mode so we */
147 /* need protected-mode segment values. */
155 /* Get the return address off the stack */
156 pop dword ptr [code16ret]
158 /* Save 32-bit stack pointer */
159 mov dword ptr [stack32], esp
161 /* jmp to 16-bit segment to set the limit correctly */
162 ljmp RMODE_CS, switch_to_real16
167 /* Restore segment registers to correct limit */
175 /* Disable Protected Mode */
180 /* Clear prefetch queue & correct CS */
182 jmp far ptr 0:inrmode
192 /* Clear out the high 16-bits of ESP */
193 /* This is needed because I have one */
194 /* machine that hangs when booted to dos if */
195 /* anything other than 0x0000 is in the high */
196 /* 16-bits of ESP. Even though real-mode */
197 /* code should only use SP and not ESP. */
200 mov sp, word ptr ds:[stack16]
202 /* Put the return address back onto the stack */
203 push word ptr ds:[code16ret]
205 /* Load IDTR with real mode value */
208 sti /* These are ok now */
210 /* Now return in r-mode! */
215 * Needed for enabling the a20 address line
219 .word 0x00eb,0x00eb // jmp $+2, jmp $+2
221 cmp al, HEX(ff) // legacy-free machine without keyboard
222 jz empty_8042_ret // controllers on Intel Macs read back 0xFF
229 * Enable the A20 address line (to allow access to over 1mb)
240 mov al, HEX(D1) // command write
243 mov al, HEX(DF) // A20 on
254 * Disable the A20 address line
265 mov al, HEX(D1) // command write
268 mov al, HEX(DD) // A20 off
280 * Allows freeldr to be loaded as a "multiboot kernel" by
281 * other boot loaders like Grub
284 #define MB_INFO_SIZE 90
285 #define MB_INFO_FLAGS_OFFSET 0
286 #define MB_INFO_BOOT_DEVICE_OFFSET 12
287 #define MB_INFO_COMMAND_LINE_OFFSET 16
288 #define CMDLINE_SIZE 256
291 * We want to execute at 0x8000 (to be compatible with bootsector
292 * loading), but Grub only allows loading of multiboot kernels
293 * above 1MB. So we let Grub load us there and then relocate
296 #define FREELDR_BASE HEX(8000)
297 #define INITIAL_BASE HEX(200000)
299 /* Align 32 bits boundary */
302 /* Multiboot header */
305 .long MULTIBOOT_HEADER_MAGIC
307 .long MULTIBOOT_HEADER_FLAGS
309 .long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
311 .long INITIAL_BASE + MultibootHeader - FREELDR_BASE
315 .long INITIAL_BASE + __bss_start__ - FREELDR_BASE
317 .long INITIAL_BASE + __bss_end__ - FREELDR_BASE
319 .long INITIAL_BASE + MultibootEntry - FREELDR_BASE
322 cli /* Even after setting up the our IDT below we are
323 * not ready to handle hardware interrupts (no entries
324 * in IDT), so there's no sti here. Interrupts will be
325 * enabled in due time */
327 /* Although the multiboot spec says we should be called with the
328 * segment registers set to 4GB flat mode, let's be sure and set up
330 lgdt gdtptrhigh + INITIAL_BASE - FREELDR_BASE
331 /* Reload segment selectors */
332 //ljmp $PMODE_CS, $(mb1 + INITIAL_BASE - FREELDR_BASE)
333 jmp far ptr PMODE_CS: (mb1 + INITIAL_BASE - FREELDR_BASE)
339 /* Check for valid multiboot signature */
340 cmp eax, MULTIBOOT_BOOTLOADER_MAGIC
343 /* Store multiboot info in a safe place */
345 mov edi, offset mb_info + INITIAL_BASE - FREELDR_BASE
346 mov ecx, MB_INFO_SIZE
349 /* Save commandline */
350 mov edx, [ebx + MB_INFO_FLAGS_OFFSET]
351 test dword ptr [ebx + MB_INFO_FLAGS_OFFSET], MB_INFO_FLAG_COMMAND_LINE
353 mov esi, [ebx + MB_INFO_COMMAND_LINE_OFFSET]
354 mov edi, offset cmdline + INITIAL_BASE - FREELDR_BASE
355 mov ecx, CMDLINE_SIZE
364 /* Copy to low mem */
365 mov esi, INITIAL_BASE
366 mov edi, FREELDR_BASE
367 mov ecx, (offset __bss_end__ - FREELDR_BASE)
372 /* Load the GDT and IDT */
376 /* Clear prefetch queue & correct CS,
378 //ljmp $PMODE_CS, $mb4
379 jmp far ptr PMODE_CS:mb4
381 /* Reload segment selectors */
390 mov ebx, offset mb_info
391 /* See if the boot device was passed in */
392 mov edx, [ebx + MB_INFO_FLAGS_OFFSET]
393 test edx, MB_INFO_FLAG_BOOT_DEVICE
395 /* Retrieve boot device info */
396 mov eax, [ebx + MB_INFO_BOOT_DEVICE_OFFSET]
399 mov byte ptr [_FrldrBootPartition], al
400 mov byte ptr [_FrldrBootDrive], ah
402 mb5: /* No boot device known, assume first partition of first harddisk */
403 mov byte ptr [_FrldrBootDrive], HEX(80)
404 mov byte ptr [_FrldrBootPartition], 1
406 /* Check for command line */
407 mov eax, offset cmdline
408 test dword ptr [ebx + MB_INFO_FLAGS_OFFSET], MB_INFO_FLAG_COMMAND_LINE
421 mbstop: jmp mbstop /* We should never get here */
425 /* 16-bit stack pointer */
429 /* 32-bit stack pointer */
433 /* 16-bit return address */
437 /* 32-bit return address */
442 .align 4 /* force 4-byte alignment */
444 /* NULL Descriptor */
462 /* 16-bit real mode CS */
468 /* 16-bit real mode DS */
474 /* GDT table pointer */
476 .word HEX(27) /* Limit */
477 .long gdt /* Base Address */
479 /* Initial GDT table pointer for multiboot */
481 .word HEX(27) /* Limit */
482 .long gdt + INITIAL_BASE - FREELDR_BASE /* Base Address */
484 /* Real-mode IDT pointer */
486 .word HEX(3ff) /* Limit */
487 .long 0 /* Base Address */
490 .fill MB_INFO_SIZE, 1, 0
493 .fill CMDLINE_SIZE, 1, 0
495 PUBLIC _FrldrBootDrive
499 PUBLIC _FrldrBootPartition