[FREELDR]

Start moving the 16 bit code into the raw binary chunk.
We now switch to protected mode before jumping to the PE entry point

svn path=/trunk/; revision=52221
This commit is contained in:
Timo Kreuzer
2011-06-13 20:03:55 +00:00
parent 4d1d576c44
commit 6be28050aa
4 changed files with 612 additions and 41 deletions
+13 -26
View File
@@ -8,27 +8,10 @@ if(ARCH MATCHES arm)
endif()
endif()
if(ARCH MATCHES i386)
if(MSVC)
list(APPEND FREELDR_BASE64K_SOURCE
arch/i386/realmode.S)
else()
list(APPEND FREELDR_STARTUP_SOURCE
arch/i386/arch.S)
endif()
elseif(ARCH MATCHES amd64)
if(MSVC)
list(APPEND FREELDR_BASE64K_SOURCE
arch/amd64/stubs.S)
else()
list(APPEND FREELDR_STARTUP_SOURCE
arch/amd64/arch.S)
endif()
endif()
if(ARCH MATCHES i386)
if(NOT MSVC)
list(APPEND FREELDR_BASE64K_SOURCE
arch/i386/entry.S
arch/i386/boot.S
arch/i386/drvmap.S
arch/i386/i386cpu.S
@@ -40,15 +23,21 @@ if(ARCH MATCHES i386)
arch/i386/linux.S
arch/i386/mb.S
arch/i386/i386bug.c)
else()
list(APPEND FREELDR_BASE64K_SOURCE
arch/i386/realmode.S)
endif()
elseif(ARCH MATCHES amd64)
if(NOT MSVC)
list(APPEND FREELDR_BASE64K_SOURCE
arch/i386/drvmap.S
arch/i386/i386cpu.S
arch/i386/i386idt.S
arch/i386/i386trap.S
arch/amd64/mb.S)
list(APPEND FREELDR_BASE64K_SOURCE
arch/i386/drvmap.S
arch/i386/i386cpu.S
arch/i386/i386idt.S
arch/i386/i386trap.S
arch/amd64/mb.S)
else()
list(APPEND FREELDR_BASE64K_SOURCE
arch/amd64/stubs.S)
endif()
endif()
@@ -187,7 +176,6 @@ CreateBootSectorTarget2(frldr16
list(APPEND FREELDR_SOURCE
bootmgr.c
${FREELDR_STARTUP_SOURCE}
${FREELDR_BASE64K_SOURCE}
${FREELDR_BASE_SOURCE}
)
@@ -242,7 +230,6 @@ if(NOT MSVC)
endif()
list(APPEND SETUPLDR_SOURCE
${FREELDR_STARTUP_SOURCE}
${FREELDR_BASE64K_SOURCE}
${FREELDR_BASE_SOURCE}
${SETUPLDR_MAIN_SOURCE})
@@ -0,0 +1,503 @@
/*
* FreeLoader
* Copyright (C) 1998-2002 Brian Palmer <brianp@sginet.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
.intel_syntax noprefix
#define HEX(y) 0x##y
#include <asm.inc>
#include <arch/pc/x86common.h>
#include <multiboot.h>
.code32
PUBLIC _RealEntryPoint
_RealEntryPoint:
/* Setup segment selectors */
mov ax, PMODE_DS
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
/* Setup protected mode stack */
mov esp, dword ptr [stack32]
/* Load the IDT */
lidt i386idtptr
/* Continue execution */
jmp dword ptr [_ContinueAddress]
_ContinueAddress:
.long _FrldrStartup
_FrldrStartup:
/* Store BootDrive and BootPartition */
xor eax, eax
mov al, dl
mov dword ptr [_FrldrBootDrive], eax
mov al, dh
mov dword ptr [_FrldrBootPartition], eax
/* GO! */
xor eax, eax
push eax
call _BootMain
/* We should never get here */
stop:
jmp stop
nop
nop
/*
* Switches the processor to protected mode
* it destroys eax
*/
EXTERN(switch_to_prot)
.code16
cli /* None of these */
/* We don't know what values are currently */
/* in the segment registers. So we are */
/* going to reload them with sane values. */
/* Of course CS has to already be valid. */
/* We are currently in real-mode so we */
/* need real-mode segment values. */
xor ax, ax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
/* Get the return address off the stack */
pop word ptr ds:[code32ret]
/* Save 16-bit stack pointer */
mov word ptr ds:[stack16], sp
/* Load the GDT */
lgdt gdtptr
/* Load the IDT */
lidt i386idtptr
/* Enable Protected Mode */
mov eax, cr0
or eax, CR0_PE_SET
mov cr0, eax
/* Clear prefetch queue & correct CS */
//ljmp PMODE_CS, inpmode
jmp far ptr PMODE_CS:inpmode
.code32
inpmode:
/* Setup segment selectors */
mov ax, PMODE_DS
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov esp, dword ptr [stack32]
/* Put the return address back onto the stack */
push dword ptr [code32ret]
/* Now return in p-mode! */
ret
/*
* Switches the processor back to real mode
* it destroys eax
*/
EXTERN(switch_to_real)
.code32
/* We don't know what values are currently */
/* in the segment registers. So we are */
/* going to reload them with sane values. */
/* Of course CS has to already be valid. */
/* We are currently in protected-mode so we */
/* need protected-mode segment values. */
mov ax, PMODE_DS
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
/* Get the return address off the stack */
pop dword ptr [code16ret]
/* Save 32-bit stack pointer */
mov dword ptr [stack32], esp
/* jmp to 16-bit segment to set the limit correctly */
ljmp RMODE_CS, switch_to_real16
switch_to_real16:
.code16
/* Restore segment registers to correct limit */
mov ax, RMODE_DS
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
/* Disable Protected Mode */
mov eax, cr0
and eax, CR0_PE_CLR
mov cr0, eax
/* Clear prefetch queue & correct CS */
//ljmp $0, $inrmode
jmp far ptr 0:inrmode
inrmode:
mov ax, cs
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
/* Clear out the high 16-bits of ESP */
/* This is needed because I have one */
/* machine that hangs when booted to dos if */
/* anything other than 0x0000 is in the high */
/* 16-bits of ESP. Even though real-mode */
/* code should only use SP and not ESP. */
xor esp, esp
mov sp, word ptr ds:[stack16]
/* Put the return address back onto the stack */
push word ptr ds:[code16ret]
/* Load IDTR with real mode value */
lidt rmode_idtptr
sti /* These are ok now */
/* Now return in r-mode! */
ret
/*
* Needed for enabling the a20 address line
*/
.code16
empty_8042:
.word 0x00eb,0x00eb // jmp $+2, jmp $+2
in al, HEX(64)
cmp al, HEX(ff) // legacy-free machine without keyboard
jz empty_8042_ret // controllers on Intel Macs read back 0xFF
test al, 2
jnz empty_8042
empty_8042_ret:
ret
/*
* Enable the A20 address line (to allow access to over 1mb)
*/
EXTERN(_EnableA20)
.code32
pusha
call switch_to_real
.code16
call empty_8042
mov al, HEX(D1) // command write
out HEX(64), al
call empty_8042
mov al, HEX(DF) // A20 on
out HEX(60), al
call empty_8042
call switch_to_prot
.code32
popa
ret
/*
* Disable the A20 address line
*/
EXTERN(_DisableA20)
.code32
pusha
call switch_to_real
.code16
call empty_8042
mov al, HEX(D1) // command write
out HEX(64), al
call empty_8042
mov al, HEX(DD) // A20 off
out HEX(60), al
call empty_8042
call switch_to_prot
.code32
popa
ret
/* Multiboot support
*
* Allows freeldr to be loaded as a "multiboot kernel" by
* other boot loaders like Grub
*/
#define MB_INFO_SIZE 90
#define MB_INFO_FLAGS_OFFSET 0
#define MB_INFO_BOOT_DEVICE_OFFSET 12
#define MB_INFO_COMMAND_LINE_OFFSET 16
#define CMDLINE_SIZE 256
/*
* We want to execute at 0x8000 (to be compatible with bootsector
* loading), but Grub only allows loading of multiboot kernels
* above 1MB. So we let Grub load us there and then relocate
* ourself to 0x8000
*/
#define FREELDR_BASE HEX(8000)
#define INITIAL_BASE HEX(200000)
/* Align 32 bits boundary */
.align 4
/* Multiboot header */
MultibootHeader:
/* magic */
.long MULTIBOOT_HEADER_MAGIC
/* flags */
.long MULTIBOOT_HEADER_FLAGS
/* checksum */
.long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
/* header_addr */
.long INITIAL_BASE + MultibootHeader - FREELDR_BASE
/* load_addr */
.long INITIAL_BASE
/* load_end_addr */
.long INITIAL_BASE + __bss_start__ - FREELDR_BASE
/* bss_end_addr */
.long INITIAL_BASE + __bss_end__ - FREELDR_BASE
/* entry_addr */
.long INITIAL_BASE + MultibootEntry - FREELDR_BASE
MultibootEntry:
cli /* Even after setting up the our IDT below we are
* not ready to handle hardware interrupts (no entries
* in IDT), so there's no sti here. Interrupts will be
* enabled in due time */
/* Although the multiboot spec says we should be called with the
* segment registers set to 4GB flat mode, let's be sure and set up
* our own */
lgdt gdtptrhigh + INITIAL_BASE - FREELDR_BASE
/* Reload segment selectors */
//ljmp $PMODE_CS, $(mb1 + INITIAL_BASE - FREELDR_BASE)
jmp far ptr PMODE_CS: (mb1 + INITIAL_BASE - FREELDR_BASE)
mb1:
mov dx, PMODE_DS
mov ds, dx
mov es, dx
/* Check for valid multiboot signature */
cmp eax, MULTIBOOT_BOOTLOADER_MAGIC
jne mbfail
/* Store multiboot info in a safe place */
mov esi, ebx
mov edi, offset mb_info + INITIAL_BASE - FREELDR_BASE
mov ecx, MB_INFO_SIZE
rep movsb
/* Save commandline */
mov edx, [ebx + MB_INFO_FLAGS_OFFSET]
test dword ptr [ebx + MB_INFO_FLAGS_OFFSET], MB_INFO_FLAG_COMMAND_LINE
jz mb3
mov esi, [ebx + MB_INFO_COMMAND_LINE_OFFSET]
mov edi, offset cmdline + INITIAL_BASE - FREELDR_BASE
mov ecx, CMDLINE_SIZE
mb2: lodsb
stosb
test al, al
jz mb3
dec ecx
jnz mb2
mb3:
/* Copy to low mem */
mov esi, INITIAL_BASE
mov edi, FREELDR_BASE
mov ecx, (offset __bss_end__ - FREELDR_BASE)
add ecx, 3
shr ecx, 2
rep movsd
/* Load the GDT and IDT */
lgdt gdtptr
lidt i386idtptr
/* Clear prefetch queue & correct CS,
* jump to low mem */
//ljmp $PMODE_CS, $mb4
jmp far ptr PMODE_CS:mb4
mb4:
/* Reload segment selectors */
mov dx, PMODE_DS
mov ds, dx
mov es, dx
mov fs, dx
mov gs, dx
mov ss, dx
mov esp, STACK32ADDR
mov ebx, offset mb_info
/* See if the boot device was passed in */
mov edx, [ebx + MB_INFO_FLAGS_OFFSET]
test edx, MB_INFO_FLAG_BOOT_DEVICE
jz mb5
/* Retrieve boot device info */
mov eax, [ebx + MB_INFO_BOOT_DEVICE_OFFSET]
shr eax, 16
inc al
mov byte ptr [_FrldrBootPartition], al
mov byte ptr [_FrldrBootDrive], ah
jmp mb6
mb5: /* No boot device known, assume first partition of first harddisk */
mov byte ptr [_FrldrBootDrive], HEX(80)
mov byte ptr [_FrldrBootPartition], 1
mb6:
/* Check for command line */
mov eax, offset cmdline
test dword ptr [ebx + MB_INFO_FLAGS_OFFSET], MB_INFO_FLAG_COMMAND_LINE
jnz mb7
xor eax, eax
mb7:
/* GO! */
push eax
call _BootMain
mbfail:
call switch_to_real
.code16
int 0x19
mbstop: jmp mbstop /* We should never get here */
.code32
/* 16-bit stack pointer */
stack16:
.word STACK16ADDR
/* 32-bit stack pointer */
stack32:
.long STACK32ADDR
/* 16-bit return address */
code16ret:
.long 0
/* 32-bit return address */
code32ret:
.long 0
.align 4 /* force 4-byte alignment */
gdt:
/* NULL Descriptor */
.word HEX(0000)
.word HEX(0000)
.word HEX(0000)
.word HEX(0000)
/* 32-bit flat CS */
.word HEX(FFFF)
.word HEX(0000)
.word HEX(9A00)
.word HEX(00CF)
/* 32-bit flat DS */
.word HEX(FFFF)
.word HEX(0000)
.word HEX(9200)
.word HEX(00CF)
/* 16-bit real mode CS */
.word HEX(FFFF)
.word HEX(0000)
.word HEX(9E00)
.word HEX(0000)
/* 16-bit real mode DS */
.word HEX(FFFF)
.word HEX(0000)
.word HEX(9200)
.word HEX(0000)
/* GDT table pointer */
gdtptr:
.word HEX(27) /* Limit */
.long gdt /* Base Address */
/* Initial GDT table pointer for multiboot */
gdtptrhigh:
.word HEX(27) /* Limit */
.long gdt + INITIAL_BASE - FREELDR_BASE /* Base Address */
/* Real-mode IDT pointer */
rmode_idtptr:
.word HEX(3ff) /* Limit */
.long 0 /* Base Address */
mb_info:
.fill MB_INFO_SIZE, 1, 0
cmdline:
.fill CMDLINE_SIZE, 1, 0
PUBLIC _FrldrBootDrive
_FrldrBootDrive:
.long 0
PUBLIC _FrldrBootPartition
_FrldrBootPartition:
.long 0
END
@@ -12,17 +12,101 @@
#include "fathelp.inc"
.org 512
RealEntryPoint:
RealModeEntryPoint:
cli
/* Setup segment registers */
xor ax, ax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
/* Setup the stack */
mov sp, word ptr ds:stack16
/* Get address of optional header */
mov eax, dword ptr ds:[FREELDR_PE_BASE + IMAGE_DOS_HEADER_e_lfanew]
add eax, FREELDR_PE_BASE + 4 + IMAGE_FILE_HEADER_SIZE
/* Jump to address of entry point */
/* Get address of entry point */
mov eax, dword ptr ds:[eax + IMAGE_OPTIONAL_HEADER_AddressOfEntryPoint]
add eax, FREELDR_PE_BASE
jmp ax
/* Safe the entry point */
mov dword ptr [BSS_EntryPoint], eax
/* Patch the long jump instruction */
mov word ptr [pm_offset], ax
/*
* Switches the processor to protected mode
* it destroys eax
*/
switch_to_prot:
/* Load the GDT */
lgdt gdtptr
/* Enable Protected Mode */
mov eax, cr0
or eax, CR0_PE_SET
mov cr0, eax
/* Clear prefetch queue & correct CS */
.byte HEX(0ea) // jmp far PMODE_CS:entry_point
pm_offset:
.word 0 // receives address of PE entry point
.word PMODE_CS
nop
/* 16-bit stack pointer */
stack16:
.word STACK16ADDR
.align 4 /* force 4-byte alignment */
gdt:
/* NULL Descriptor */
.word HEX(0000)
.word HEX(0000)
.word HEX(0000)
.word HEX(0000)
/* 32-bit flat CS */
.word HEX(FFFF)
.word HEX(0000)
.word HEX(9A00)
.word HEX(00CF)
/* 32-bit flat DS */
.word HEX(FFFF)
.word HEX(0000)
.word HEX(9200)
.word HEX(00CF)
/* 16-bit real mode CS */
.word HEX(FFFF)
.word HEX(0000)
.word HEX(9E00)
.word HEX(0000)
/* 16-bit real mode DS */
.word HEX(FFFF)
.word HEX(0000)
.word HEX(9200)
.word HEX(0000)
/* GDT table pointer */
gdtptr:
.word HEX(27) /* Limit */
.long gdt /* Base Address */
.org 1024
#include "helpers.inc"
@@ -4,8 +4,8 @@
#endif
/* Memory layout */
#define STACK16ADDR HEX(7000) /* The 16-bit stack top will be at 0000:7000 */
#define BSS_START HEX(7000)
#define STACK16ADDR HEX(6F00) /* The 16-bit stack top will be at 0000:6F00 */
#define BSS_START HEX(6F00)
#define FREELDR_BASE HEX(8000)
#define FREELDR_PE_BASE HEX(9000)
#define STACK32ADDR HEX(78000) /* The 32-bit stack top will be at 7000:8000, or 0x78000 */
@@ -17,15 +17,12 @@
#define DISKREADBUFFER_SIZE 512
/* These addresses specify the realmode "BSS section" layout */
#define BSS_CallbackAddress BSS_START + 0
#define BSS_CallbackReturn BSS_START + 8
#define BSS_BootDrive BSS_START + 16
#define BSS_BootPartition BSS_START + 20
#define BSS_EntryPoint (BSS_START + 0)
#define BSS_CallbackAddress (BSS_START + 4)
#define BSS_CallbackReturn (BSS_START + 8)
#define BSS_BootDrive (BSS_START + 12)
#define BSS_BootPartition (BSS_START + 16)
#ifdef _M_AMD64
#define FrldrBootDrive *((PULONG)BSS_BootDrive)
#define FrldrBootPartition *((PULONG)BSS_BootPartition)
#endif
// Flag Masks
#define I386FLAG_CF HEX(0001) // Carry Flag
@@ -45,13 +42,13 @@
#define CR0_PE_CLR HEX(FFFFFFFE) /* AND this value with CR0 to disable pmode */
/* Defines needed for switching between real and protected mode */
#ifdef _M_IX86
//#ifdef _M_IX86
#define NULL_DESC HEX(00) /* NULL descriptor */
#define PMODE_CS HEX(08) /* PMode code selector, base 0 limit 4g */
#define PMODE_DS HEX(10) /* PMode data selector, base 0 limit 4g */
#define RMODE_CS HEX(18) /* RMode code selector, base 0 limit 64k */
#define RMODE_DS HEX(20) /* RMode data selector, base 0 limit 64k */
#endif
//#endif
/* Makes "x" a global variable or label */
#define EXTERN(x) .global x; x: