From 0834f5fa794bb9c53897e1bc5835de117d7f2db5 Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Thu, 25 Aug 2011 14:43:15 +0000 Subject: [PATCH] [FREELDR] - Implement real mode entry point for amd64 (amd64 freeldr starts but dies later, it cannot yet switch back to real mode, which is a bit more complicated) - delete empty folders svn path=/trunk/; revision=53443 --- reactos/boot/freeldr/freeldr/CMakeLists.txt | 7 +- .../boot/freeldr/freeldr/arch/amd64/entry.S | 10 + .../freeldr/freeldr/arch/realmode/amd64.S | 274 +++++++++++------- .../freeldr/include/arch/pc/x86common.h | 25 +- 4 files changed, 202 insertions(+), 114 deletions(-) diff --git a/reactos/boot/freeldr/freeldr/CMakeLists.txt b/reactos/boot/freeldr/freeldr/CMakeLists.txt index 911ac08923a..33391b2f6a6 100644 --- a/reactos/boot/freeldr/freeldr/CMakeLists.txt +++ b/reactos/boot/freeldr/freeldr/CMakeLists.txt @@ -1,9 +1,14 @@ -if(ARCH MATCHES i386 OR ARCH MATCHES amd64) +if(ARCH MATCHES i386) CreateBootSectorTarget2(frldr16 ${CMAKE_CURRENT_SOURCE_DIR}/arch/realmode/i386.S ${CMAKE_CURRENT_BINARY_DIR}/frldr16.bin F800) +elseif(ARCH MATCHES amd64) + CreateBootSectorTarget2(frldr16 + ${CMAKE_CURRENT_SOURCE_DIR}/arch/realmode/amd64.S + ${CMAKE_CURRENT_BINARY_DIR}/frldr16.bin + F800) endif() include_directories(BEFORE include) diff --git a/reactos/boot/freeldr/freeldr/arch/amd64/entry.S b/reactos/boot/freeldr/freeldr/arch/amd64/entry.S index 242275bb387..9a30d85c81a 100644 --- a/reactos/boot/freeldr/freeldr/arch/amd64/entry.S +++ b/reactos/boot/freeldr/freeldr/arch/amd64/entry.S @@ -3,10 +3,20 @@ #include #include +EXTERN BootMain:PROC + .code64 PUBLIC RealEntryPoint RealEntryPoint: + //mov ax, LMODE_DS + //mov ds, ax + //mov word ptr [HEX(b8000)], HEX(0e00) + '1' + + /* GO! */ + xor rcx, rcx + call BootMain + PUBLIC FrldrBootDrive FrldrBootDrive: diff --git a/reactos/boot/freeldr/freeldr/arch/realmode/amd64.S b/reactos/boot/freeldr/freeldr/arch/realmode/amd64.S index 1958a5411b3..4124523b5c0 100644 --- a/reactos/boot/freeldr/freeldr/arch/realmode/amd64.S +++ b/reactos/boot/freeldr/freeldr/arch/realmode/amd64.S @@ -1,8 +1,8 @@ #include -#include +#include "../../include/arch/pc/x86common.h" -#define IMAGE_DOS_HEADER_e_lfanew 36 +#define IMAGE_DOS_HEADER_e_lfanew 60 #define IMAGE_FILE_HEADER_SIZE 20 #define IMAGE_OPTIONAL_HEADER_AddressOfEntryPoint 16 @@ -13,7 +13,7 @@ #include "fathelp.inc" .org 512 -RealEntryPoint: +Startup: cli @@ -25,41 +25,98 @@ RealEntryPoint: mov gs, ax mov ss, ax - /* checkPoint Charlie - where it all began... */ - mov si, offset CheckPoint0 + /* Setup a real mode stack */ + mov sp, word ptr ds:[stack16] + + /* Output first status */ + mov si, offset Msg_Starting call writestr - /* Setup a real mode stack */ - mov sp, stack16 + /* Enable A20 address line */ + call EnableA20 - /* Zero BootDrive and BootPartition */ - xor eax, eax - mov BootDrive, eax - mov BootPartition, eax + /* Check the CPU */ + call CheckFor64BitSupport + test al, al + jnz .LongModeSupported - /* Store the boot drive */ - mov BootDrive, dl + /* Output failure message */ + mov si, offset Msg_Unsupported + call writestr - /* Store the boot partition */ - mov BootPartition, dh + /* Wait for a keypress */ + int HEX(16) + jmp SoftReboot + +Msg_Unsupported: + .ascii "This CPU is not supported.", CR, LF + .ascii "Press any key to reboot...", NUL + +Msg_Starting: + .ascii "Starting FreeLoader...", CR, LF, NUL + +Msg_LongModeSupported: + .ascii "Long mode support detected.", CR, LF, NUL + +.LongModeSupported: + /* Output status */ + mov si, offset Msg_LongModeSupported + call writestr /* Load the GDT */ - lgdt gdtptr - /* Load the IDT */ -// lidt idtptr + lgdt fword ptr [gdtptr] - call x86_16_EnableA20 + /* Build the startup page tables */ + call BuildPageTables - /* checkPoint Charlie - where it all began... */ - mov si, offset CheckPoint1 + /* Safe real mode entry point in shared memory */ + mov dword ptr ds:[BSS_RealModeEntry], offset RealModeEntryPoint + + /* Address the image with es segment */ + mov ax, FREELDR_PE_BASE / 16 + mov es, ax + + /* Get address of optional header */ + mov eax, dword ptr es:[IMAGE_DOS_HEADER_e_lfanew] + add eax, 4 + IMAGE_FILE_HEADER_SIZE + + /* Get address of entry point */ + mov eax, dword ptr es:[eax + IMAGE_OPTIONAL_HEADER_AddressOfEntryPoint] + add eax, FREELDR_PE_BASE + + /* Save entry point */ + mov dword ptr ds:[LongModeEntryPoint], eax + + /* Restore es */ + xor ax, ax + mov es, ax + + /* Output status */ + mov si, offset Msg_SwitchToLongMode call writestr - call x86_16_BuildPageTables + jmp ExitToLongMode - /* checkPoint Charlie - where it all began... */ - mov si, offset CheckPoint2 - call writestr +Msg_SwitchToLongMode: + .ascii "Switching to long mode....", CR, LF, NUL +.align 4 +gdt: + .word HEX(0000), HEX(0000), HEX(0000), HEX(0000) /* 00: NULL descriptor */ + .word HEX(0000), HEX(0000), HEX(0000), HEX(0000) /* 08: */ + .word HEX(0000), HEX(0000), HEX(9800), HEX(0020) /* 10: long mode cs */ + .word HEX(ffff), HEX(0000), HEX(f300), HEX(00cf) /* 18: long mode ds */ + .word HEX(FFFF), HEX(0000), HEX(9E00), HEX(0000) /* 16-bit real mode CS */ + .word HEX(FFFF), HEX(0000), HEX(9200), HEX(0000) /* 16-bit real mode DS */ + .word HEX(FFFF), HEX(0000), HEX(9B00), HEX(00CF) /* 30: compat mode cs */ + +/* GDT table pointer */ +gdtptr: + .word HEX(37) /* Limit */ + .long offset gdt /* Base Address */ + + +CheckFor64BitSupport: /* Check if CPU supports CPUID */ pushfd pop eax @@ -70,107 +127,97 @@ RealEntryPoint: pushfd pop eax cmp eax,ebx - jz no_cpuid_support_detected + jnz .CheckForPAE + mov si, offset .Msg_NoCpuidSupport + call writestr + xor al, al + ret + +.Msg_NoCpuidSupport: + .ascii "The system doesn't support CPUID.", CR, LF, NUL + +.CheckForPAE: /* CPUID support detected - getting the PAE/PGE */ - mov eax,1 // Fn0000_0001 - PAE in EDX[6] cpuid - xor eax,eax and edx, HEX(00a0) - test edx,edx // are PAE and PGE bits set? - jz no_x64_support_detected + cmp edx, HEX(00a0) + je .CheckForLongMode - /* PAE and PGE are here */ + mov si, offset .Msg_NoPAE + call writestr + xor al, al + ret +.Msg_NoPAE: + .ascii "PAE or PGE not set.", CR, LF, NUL + +.CheckForLongMode: xor edx, edx mov eax, HEX(80000001) cpuid and edx, HEX(20000000) test edx,edx - jz no_x64_support_detected + jnz .Success - /* X64 Processor */ - - /* checkPoint Charlie - where it all began... */ - mov si, offset CheckPoint3 + mov si, offset .Msg_NoLongMode call writestr + xor al, al + ret - /* 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 +.Msg_NoLongMode: + .ascii "Long mode is not supported.", CR, LF, NUL - /* Get address of entry point */ - mov eax, dword ptr ds:[eax + IMAGE_OPTIONAL_HEADER_AddressOfEntryPoint] - - /* Store the address in the callback return variable */ - mov dword ptr ds:[CallbackReturnAddress], eax - -switch64: - mov - jmp x86_16_ReturnToLong +.Success: + xor al, al + inc al + ret -no_x64_support_detected: - mov si, offset NotAnX64Processor // Loading message - call writestr - jmp fail - -no_cpuid_support_detected: - mov si, offset NoCPUIDSupport // Loading message - call writestr - -fail: - jmp fail - nop - nop - -/* - * We define 512 2MB pages at the start of memory, so we can access the first - * 1 GB as if paging was disabled - */ -x86_16_BuildPageTables: +BuildPageTables: pusha push es - /* Get segment of pml4 */ - mov eax, offset pml4_startup - shr eax, 4 + /* Get segment of the PML4 */ + mov eax, PML4_ADDRESS / 16 mov es, ax cld xor di, di /* One entry in the PML4 pointing to PDP */ - mov eax, offset pdp_startup - or eax, HEX(00f) + mov eax, PDP_ADDRESS + or eax, HEX(0f) stosd + /* clear rest */ xor eax, eax - mov cx, HEX(03ff) + mov cx, 1023 rep stosd /* One entry in the PDP pointing to PD */ - mov eax, offset pd_startup - or eax, HEX(00f) + mov eax, PD_ADDRESS + or eax, HEX(0f) stosd + /* clear rest */ xor eax, eax - mov ecx, HEX(03ff) + mov ecx, 1023 rep stosd - /* 512 entries in the PD defining a 2MB page each */ + /* 512 entries in the PD, each defining a 2MB page each */ mov ecx, 512 mov eax, HEX(008f) -Bpt2: +.Bpt2: mov es: [di], eax mov dword ptr es: [di + 4], 0 - add eax, 512 << 12 // add 512 4k pages + add eax, 512 * 4096 // add 512 4k pages add di, 8 - /* Loop it */ + /* Loop all PDEs */ dec cx - jnz Bpt2 + jnz .Bpt2 /* Return */ pop es @@ -178,13 +225,21 @@ Bpt2: ret +/******************************************************************************/ + +#define MSR_EFER HEX(C0000080) +#define LMODE_CS HEX(10) + +/* This is the entry point from long mode */ +RealModeEntryPoint: -x86_16_ReturnToLong: - - cli +ExitToLongMode: + /* Disable interrupts */ + cli + /* Set correct segment registers */ xor ax,ax mov ds,ax mov es,ax @@ -192,34 +247,57 @@ x86_16_ReturnToLong: mov gs,ax mov ss,ax - /* Get the return address off the stack */ - pop word ptr code64ret + /* Safe current stack pointer */ + mov word ptr ds:[stack16], sp - /* Save 16-bit stack pointer */ - mov stack16, sp - - mov eax, 0x00a0 // Set PAE and PGE: 10100000b + /* Set PAE and PGE: 10100000b */ + mov eax, HEX(00a0) mov cr4, eax - mov edx, offset pml4_startup // Point cr3 at PML4 + /* Point cr3 at the PML4 */ + mov edx, PML4_ADDRESS mov cr3, edx - mov ecx, HEX(0C0000080) // Specify EFER MSR - rdmsr // Enable long mode + /* Enable long mode */ + mov ecx, MSR_EFER + rdmsr or eax, HEX(00000100) wrmsr - mov ebx, cr0 // Activate long mode - or ebx, HEX(080000001) // by enabling paging and protection simultaneously - mov cr0, ebx // skipping protected mode entirely + /* Activate long mode by enabling paging and protection simultaneously, + skipping protected mode entirely */ + mov ebx, cr0 + or ebx, HEX(80000001) + mov cr0, ebx - //jmp LMODE_CS:offset LongCat //Load CS with 64 bit segment and flush the instruction cache - // Do a long jmp to the CallbackReturn address + /* Clear prefetch queue & correct CS */ + ljmp16 LMODE_CS, InLongMode +InLongMode: + DB 66h, 0B8h, 18h, 00h // mov ax, LMODE_DS + DB 66h, 8Eh, 0D8h // mov ds, ax + DB 66h, 66h, 0C7h, 04h, 25h, 00h, 80h, 0Bh, 00h, 31h, 0Eh + //mov word ptr [HEX(b8000)], HEX(0e00) + '1' + + .byte HEX(0ff), HEX(25) // opcode of indirect jump + .long 1 // relative address of LongModeEntryPoint + nop +LongModeEntryPoint: + .long 0, 0 + + int HEX(16) + jmp SoftReboot + + + /* 16-bit stack pointer */ +stack16: + .word STACK16ADDR #include "helpers.inc" +.org (FREELDR_PE_BASE - FREELDR_BASE - 1) +.byte 0 .endcode16 END diff --git a/reactos/boot/freeldr/freeldr/include/arch/pc/x86common.h b/reactos/boot/freeldr/freeldr/include/arch/pc/x86common.h index 1e85f214630..7322da60c92 100644 --- a/reactos/boot/freeldr/freeldr/include/arch/pc/x86common.h +++ b/reactos/boot/freeldr/freeldr/include/arch/pc/x86common.h @@ -4,6 +4,11 @@ #endif /* Memory layout */ +//#ifdef _M_AMD64 +#define PML4_ADDRESS HEX(1000) /* One page PML4 page table */ +#define PDP_ADDRESS HEX(2000) /* One page PDP page table */ +#define PD_ADDRESS HEX(3000) /* One page PD page table */ +//#endif #define STACK16ADDR HEX(6F00) /* The 16-bit stack top will be at 0000:6F00 */ #define BSS_START HEX(6F00) #define FREELDR_BASE HEX(F800) @@ -60,21 +65,7 @@ #define REGS_GS 30 #define REGS_EFLAGS 32 - -// Flag Masks -#define I386FLAG_CF HEX(0001) // Carry Flag -#define I386FLAG_RESV1 HEX(0002) // Reserved - Must be 1 -#define I386FLAG_PF HEX(0004) // Parity Flag -#define I386FLAG_RESV2 HEX(0008) // Reserved - Must be 0 -#define I386FLAG_AF HEX(0010) // Auxiliary Flag -#define I386FLAG_RESV3 HEX(0020) // Reserved - Must be 0 -#define I386FLAG_ZF HEX(0040) // Zero Flag -#define I386FLAG_SF HEX(0080) // Sign Flag -#define I386FLAG_TF HEX(0100) // Trap Flag (Single Step) -#define I386FLAG_IF HEX(0200) // Interrupt Flag -#define I386FLAG_DF HEX(0400) // Direction Flag -#define I386FLAG_OF HEX(0800) // Overflow Flag - +/* Flag Masks */ #define CR0_PE_SET HEX(00000001) /* OR this value with CR0 to enable pmode */ #define CR0_PE_CLR HEX(FFFFFFFE) /* AND this value with CR0 to disable pmode */ @@ -85,6 +76,10 @@ #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 */ +//#else +/* Long mode selectors */ +#define LMODE_CS HEX(10) +#define LMODE_DS HEX(18) //#endif /* Makes "x" a global variable or label */