[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
This commit is contained in:
Timo Kreuzer 2011-08-25 14:43:15 +00:00
parent 78a0d9fb21
commit 0834f5fa79
4 changed files with 202 additions and 114 deletions

View file

@ -1,9 +1,14 @@
if(ARCH MATCHES i386 OR ARCH MATCHES amd64) if(ARCH MATCHES i386)
CreateBootSectorTarget2(frldr16 CreateBootSectorTarget2(frldr16
${CMAKE_CURRENT_SOURCE_DIR}/arch/realmode/i386.S ${CMAKE_CURRENT_SOURCE_DIR}/arch/realmode/i386.S
${CMAKE_CURRENT_BINARY_DIR}/frldr16.bin ${CMAKE_CURRENT_BINARY_DIR}/frldr16.bin
F800) F800)
elseif(ARCH MATCHES amd64)
CreateBootSectorTarget2(frldr16
${CMAKE_CURRENT_SOURCE_DIR}/arch/realmode/amd64.S
${CMAKE_CURRENT_BINARY_DIR}/frldr16.bin
F800)
endif() endif()
include_directories(BEFORE include) include_directories(BEFORE include)

View file

@ -3,10 +3,20 @@
#include <asm.inc> #include <asm.inc>
#include <arch/pc/x86common.h> #include <arch/pc/x86common.h>
EXTERN BootMain:PROC
.code64 .code64
PUBLIC RealEntryPoint PUBLIC RealEntryPoint
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 PUBLIC FrldrBootDrive
FrldrBootDrive: FrldrBootDrive:

View file

@ -1,8 +1,8 @@
#include <asm.inc> #include <asm.inc>
#include <arch/pc/x86common.h> #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_FILE_HEADER_SIZE 20
#define IMAGE_OPTIONAL_HEADER_AddressOfEntryPoint 16 #define IMAGE_OPTIONAL_HEADER_AddressOfEntryPoint 16
@ -13,7 +13,7 @@
#include "fathelp.inc" #include "fathelp.inc"
.org 512 .org 512
RealEntryPoint: Startup:
cli cli
@ -25,41 +25,98 @@ RealEntryPoint:
mov gs, ax mov gs, ax
mov ss, ax mov ss, ax
/* checkPoint Charlie - where it all began... */ /* Setup a real mode stack */
mov si, offset CheckPoint0 mov sp, word ptr ds:[stack16]
/* Output first status */
mov si, offset Msg_Starting
call writestr call writestr
/* Setup a real mode stack */ /* Enable A20 address line */
mov sp, stack16 call EnableA20
/* Zero BootDrive and BootPartition */ /* Check the CPU */
xor eax, eax call CheckFor64BitSupport
mov BootDrive, eax test al, al
mov BootPartition, eax jnz .LongModeSupported
/* Store the boot drive */ /* Output failure message */
mov BootDrive, dl mov si, offset Msg_Unsupported
call writestr
/* Store the boot partition */ /* Wait for a keypress */
mov BootPartition, dh 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 */ /* Load the GDT */
lgdt gdtptr lgdt fword ptr [gdtptr]
/* Load the IDT */
// lidt idtptr
call x86_16_EnableA20 /* Build the startup page tables */
call BuildPageTables
/* checkPoint Charlie - where it all began... */ /* Safe real mode entry point in shared memory */
mov si, offset CheckPoint1 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 writestr
call x86_16_BuildPageTables jmp ExitToLongMode
/* checkPoint Charlie - where it all began... */ Msg_SwitchToLongMode:
mov si, offset CheckPoint2 .ascii "Switching to long mode....", CR, LF, NUL
call writestr
.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 */ /* Check if CPU supports CPUID */
pushfd pushfd
pop eax pop eax
@ -70,107 +127,97 @@ RealEntryPoint:
pushfd pushfd
pop eax pop eax
cmp eax,ebx 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 */ /* CPUID support detected - getting the PAE/PGE */
mov eax,1 // Fn0000_0001 - PAE in EDX[6] mov eax,1 // Fn0000_0001 - PAE in EDX[6]
cpuid cpuid
xor eax,eax
and edx, HEX(00a0) and edx, HEX(00a0)
test edx,edx // are PAE and PGE bits set? cmp edx, HEX(00a0)
jz no_x64_support_detected 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 xor edx, edx
mov eax, HEX(80000001) mov eax, HEX(80000001)
cpuid cpuid
and edx, HEX(20000000) and edx, HEX(20000000)
test edx,edx test edx,edx
jz no_x64_support_detected jnz .Success
/* X64 Processor */ mov si, offset .Msg_NoLongMode
/* checkPoint Charlie - where it all began... */
mov si, offset CheckPoint3
call writestr call writestr
xor al, al
ret
/* Get address of optional header */ .Msg_NoLongMode:
mov eax, dword ptr ds:[FREELDR_PE_BASE + IMAGE_DOS_HEADER_e_lfanew] .ascii "Long mode is not supported.", CR, LF, NUL
add eax, FREELDR_PE_BASE + 4 + IMAGE_FILE_HEADER_SIZE
/* Get address of entry point */ .Success:
mov eax, dword ptr ds:[eax + IMAGE_OPTIONAL_HEADER_AddressOfEntryPoint] xor al, al
inc al
/* Store the address in the callback return variable */ ret
mov dword ptr ds:[CallbackReturnAddress], eax
switch64:
mov
jmp x86_16_ReturnToLong
no_x64_support_detected: BuildPageTables:
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:
pusha pusha
push es push es
/* Get segment of pml4 */ /* Get segment of the PML4 */
mov eax, offset pml4_startup mov eax, PML4_ADDRESS / 16
shr eax, 4
mov es, ax mov es, ax
cld cld
xor di, di xor di, di
/* One entry in the PML4 pointing to PDP */ /* One entry in the PML4 pointing to PDP */
mov eax, offset pdp_startup mov eax, PDP_ADDRESS
or eax, HEX(00f) or eax, HEX(0f)
stosd stosd
/* clear rest */ /* clear rest */
xor eax, eax xor eax, eax
mov cx, HEX(03ff) mov cx, 1023
rep stosd rep stosd
/* One entry in the PDP pointing to PD */ /* One entry in the PDP pointing to PD */
mov eax, offset pd_startup mov eax, PD_ADDRESS
or eax, HEX(00f) or eax, HEX(0f)
stosd stosd
/* clear rest */ /* clear rest */
xor eax, eax xor eax, eax
mov ecx, HEX(03ff) mov ecx, 1023
rep stosd 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 ecx, 512
mov eax, HEX(008f) mov eax, HEX(008f)
Bpt2: .Bpt2:
mov es: [di], eax mov es: [di], eax
mov dword ptr es: [di + 4], 0 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 add di, 8
/* Loop it */ /* Loop all PDEs */
dec cx dec cx
jnz Bpt2 jnz .Bpt2
/* Return */ /* Return */
pop es pop es
@ -178,13 +225,21 @@ Bpt2:
ret ret
/******************************************************************************/
#define MSR_EFER HEX(C0000080)
#define LMODE_CS HEX(10)
/* This is the entry point from long mode */
RealModeEntryPoint:
x86_16_ReturnToLong: ExitToLongMode:
/* Disable interrupts */
cli cli
/* Set correct segment registers */
xor ax,ax xor ax,ax
mov ds,ax mov ds,ax
mov es,ax mov es,ax
@ -192,34 +247,57 @@ x86_16_ReturnToLong:
mov gs,ax mov gs,ax
mov ss,ax mov ss,ax
/* Get the return address off the stack */ /* Safe current stack pointer */
pop word ptr code64ret mov word ptr ds:[stack16], sp
/* Save 16-bit stack pointer */ /* Set PAE and PGE: 10100000b */
mov stack16, sp mov eax, HEX(00a0)
mov eax, 0x00a0 // Set PAE and PGE: 10100000b
mov cr4, eax 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 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) or eax, HEX(00000100)
wrmsr wrmsr
mov ebx, cr0 // Activate long mode /* Activate long mode by enabling paging and protection simultaneously,
or ebx, HEX(080000001) // by enabling paging and protection simultaneously skipping protected mode entirely */
mov cr0, ebx // 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 /* Clear prefetch queue & correct CS */
// Do a long jmp to the CallbackReturn address 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" #include "helpers.inc"
.org (FREELDR_PE_BASE - FREELDR_BASE - 1)
.byte 0
.endcode16 .endcode16
END END

View file

@ -4,6 +4,11 @@
#endif #endif
/* Memory layout */ /* 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 STACK16ADDR HEX(6F00) /* The 16-bit stack top will be at 0000:6F00 */
#define BSS_START HEX(6F00) #define BSS_START HEX(6F00)
#define FREELDR_BASE HEX(F800) #define FREELDR_BASE HEX(F800)
@ -60,21 +65,7 @@
#define REGS_GS 30 #define REGS_GS 30
#define REGS_EFLAGS 32 #define REGS_EFLAGS 32
/* Flag Masks */
// 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
#define CR0_PE_SET HEX(00000001) /* OR this value with CR0 to enable pmode */ #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 */ #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 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_CS HEX(18) /* RMode code selector, base 0 limit 64k */
#define RMODE_DS HEX(20) /* RMode data 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 //#endif
/* Makes "x" a global variable or label */ /* Makes "x" a global variable or label */