From 6be28050aabf3cb34512ca0c9a8d2cf5b42f36c8 Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Mon, 13 Jun 2011 20:03:55 +0000 Subject: [PATCH] [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 --- reactos/boot/freeldr/freeldr/CMakeLists.txt | 39 +- .../boot/freeldr/freeldr/arch/i386/entry.S | 503 ++++++++++++++++++ .../boot/freeldr/freeldr/arch/realmode/i386.S | 90 +++- .../freeldr/include/arch/pc/x86common.h | 21 +- 4 files changed, 612 insertions(+), 41 deletions(-) create mode 100644 reactos/boot/freeldr/freeldr/arch/i386/entry.S diff --git a/reactos/boot/freeldr/freeldr/CMakeLists.txt b/reactos/boot/freeldr/freeldr/CMakeLists.txt index a1f6543f400..79ff1b5bc63 100644 --- a/reactos/boot/freeldr/freeldr/CMakeLists.txt +++ b/reactos/boot/freeldr/freeldr/CMakeLists.txt @@ -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}) diff --git a/reactos/boot/freeldr/freeldr/arch/i386/entry.S b/reactos/boot/freeldr/freeldr/arch/i386/entry.S new file mode 100644 index 00000000000..0f0a10f8401 --- /dev/null +++ b/reactos/boot/freeldr/freeldr/arch/i386/entry.S @@ -0,0 +1,503 @@ +/* + * FreeLoader + * Copyright (C) 1998-2002 Brian Palmer + * + * 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 +#include +#include + +.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 diff --git a/reactos/boot/freeldr/freeldr/arch/realmode/i386.S b/reactos/boot/freeldr/freeldr/arch/realmode/i386.S index ee43a512c52..58d0710e73e 100644 --- a/reactos/boot/freeldr/freeldr/arch/realmode/i386.S +++ b/reactos/boot/freeldr/freeldr/arch/realmode/i386.S @@ -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" diff --git a/reactos/boot/freeldr/freeldr/include/arch/pc/x86common.h b/reactos/boot/freeldr/freeldr/include/arch/pc/x86common.h index a24ad5b78b4..c6526110183 100644 --- a/reactos/boot/freeldr/freeldr/include/arch/pc/x86common.h +++ b/reactos/boot/freeldr/freeldr/include/arch/pc/x86common.h @@ -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: