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.
25 #include <multiboot.h>
28 EXTERN(RealEntryPoint)
32 /* Setup segment registers */
49 /* Zero BootDrive and BootPartition */
51 movl %eax,(_BootDrive)
52 movl %eax,(_BootPartition)
54 /* Store the boot drive */
57 /* Store the boot partition */
58 movb %dh,(_BootPartition)
69 /* We should never get here */
76 * Switches the processor to protected mode
79 EXTERN(switch_to_prot)
83 cli /* None of these */
85 /* We don't know what values are currently */
86 /* in the segment registers. So we are */
87 /* going to reload them with sane values. */
88 /* Of course CS has to already be valid. */
89 /* We are currently in real-mode so we */
90 /* need real-mode segment values. */
98 /* Get the return address off the stack */
101 /* Save 16-bit stack pointer */
109 /* Enable Protected Mode */
114 /* Clear prefetch queue & correct CS */
115 ljmp $PMODE_CS, $inpmode
121 /* Setup segment selectors */
130 /* Put the return address back onto the stack */
133 /* Now return in p-mode! */
137 * Switches the processor back to real mode
140 EXTERN(switch_to_real)
144 /* We don't know what values are currently */
145 /* in the segment registers. So we are */
146 /* going to reload them with sane values. */
147 /* Of course CS has to already be valid. */
148 /* We are currently in protected-mode so we */
149 /* need protected-mode segment values. */
157 /* Get the return address off the stack */
160 /* Save 32-bit stack pointer */
163 /* jmp to 16-bit segment to set the limit correctly */
164 ljmp $RMODE_CS, $switch_to_real16
169 /* Restore segment registers to correct limit */
177 /* Disable Protected Mode */
179 andl $CR0_PE_CLR,%eax
182 /* Clear prefetch queue & correct CS */
193 /* Clear out the high 16-bits of ESP */
194 /* This is needed because I have one */
195 /* machine that hangs when booted to dos if */
196 /* anything other than 0x0000 is in the high */
197 /* 16-bits of ESP. Even though real-mode */
198 /* code should only use SP and not ESP. */
203 /* Put the return address back onto the stack */
206 /* Load IDTR with real mode value */
209 sti /* These are ok now */
211 /* Now return in r-mode! */
216 * Needed for enabling the a20 address line
220 .word 0x00eb,0x00eb // jmp $+2, jmp $+2
222 cmp $0xff, %al // legacy-free machine without keyboard
223 jz empty_8042_ret // controllers on Intel Macs read back 0xFF
230 * Enable the A20 address line (to allow access to over 1mb)
241 movb $0xD1,%al // command write
244 mov $0xDF,%al // A20 on
255 * Disable the A20 address line
266 movb $0xD1,%al // command write
269 mov $0xDD,%al // A20 off
281 * Allows freeldr to be loaded as a "multiboot kernel" by
282 * other boot loaders like Grub
285 #define MB_INFO_SIZE 90
286 #define MB_INFO_FLAGS_OFFSET 0
287 #define MB_INFO_BOOT_DEVICE_OFFSET 12
288 #define MB_INFO_COMMAND_LINE_OFFSET 16
289 #define CMDLINE_SIZE 256
292 * We want to execute at 0x8000 (to be compatible with bootsector
293 * loading), but Grub only allows loading of multiboot kernels
294 * above 1MB. So we let Grub load us there and then relocate
297 #define FREELDR_BASE 0x8000
298 #define INITIAL_BASE 0x200000
300 /* Align 32 bits boundary */
303 /* Multiboot header */
306 .long MULTIBOOT_HEADER_MAGIC
308 .long MULTIBOOT_HEADER_FLAGS
310 .long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
312 .long INITIAL_BASE + MultibootHeader - FREELDR_BASE
316 .long INITIAL_BASE + __bss_start__ - FREELDR_BASE
318 .long INITIAL_BASE + __bss_end__ - FREELDR_BASE
320 .long INITIAL_BASE + MultibootEntry - FREELDR_BASE
323 cli /* Even after setting up the our IDT below we are
324 * not ready to handle hardware interrupts (no entries
325 * in IDT), so there's no sti here. Interrupts will be
326 * enabled in due time */
328 /* Although the multiboot spec says we should be called with the
329 * segment registers set to 4GB flat mode, let's be sure and set up
331 lgdt gdtptrhigh + INITIAL_BASE - FREELDR_BASE
332 /* Reload segment selectors */
333 ljmp $PMODE_CS, $(mb1 + INITIAL_BASE - FREELDR_BASE)
339 /* Check for valid multiboot signature */
340 cmpl $MULTIBOOT_BOOTLOADER_MAGIC,%eax
343 /* Store multiboot info in a safe place */
345 movl $(mb_info + INITIAL_BASE - FREELDR_BASE),%edi
346 movl $MB_INFO_SIZE,%ecx
349 /* Save commandline */
350 movl MB_INFO_FLAGS_OFFSET(%ebx),%edx
351 testl $MB_INFO_FLAG_COMMAND_LINE,MB_INFO_FLAGS_OFFSET(%ebx)
353 movl MB_INFO_COMMAND_LINE_OFFSET(%ebx),%esi
354 movl $(cmdline + INITIAL_BASE - FREELDR_BASE),%edi
355 movl $CMDLINE_SIZE,%ecx
364 /* Copy to low mem */
365 movl $INITIAL_BASE,%esi
366 movl $FREELDR_BASE,%edi
367 movl $(__bss_end__ - FREELDR_BASE),%ecx
372 /* Load the GDT and IDT */
376 /* Clear prefetch queue & correct CS,
380 /* Reload segment selectors */
387 movl $STACK32ADDR,%esp
390 /* See if the boot device was passed in */
391 movl MB_INFO_FLAGS_OFFSET(%ebx),%edx
392 testl $MB_INFO_FLAG_BOOT_DEVICE,%edx
394 /* Retrieve boot device info */
395 movl MB_INFO_BOOT_DEVICE_OFFSET(%ebx),%eax
398 movb %al,_BootPartition
401 mb5: /* No boot device known, assume first partition of first harddisk */
402 movb $0x80,_BootDrive
403 movb $1,_BootPartition
405 /* Check for command line */
407 testl $MB_INFO_FLAG_COMMAND_LINE,MB_INFO_FLAGS_OFFSET(%ebx)
416 mbfail: call switch_to_real
419 mbstop: jmp mbstop /* We should never get here */
423 /* 16-bit stack pointer */
427 /* 32-bit stack pointer */
431 /* 16-bit return address */
435 /* 32-bit return address */
440 .p2align 2 /* force 4-byte alignment */
442 /* NULL Descriptor */
460 /* 16-bit real mode CS */
466 /* 16-bit real mode DS */
472 /* GDT table pointer */
474 .word 0x27 /* Limit */
475 .long gdt /* Base Address */
477 /* Initial GDT table pointer for multiboot */
479 .word 0x27 /* Limit */
480 .long gdt + INITIAL_BASE - FREELDR_BASE /* Base Address */
482 /* Real-mode IDT pointer */
484 .word 0x3ff /* Limit */
485 .long 0 /* Base Address */
488 .fill MB_INFO_SIZE, 1, 0
491 .fill CMDLINE_SIZE, 1, 0
496 EXTERN(_BootPartition)