[FREELDR]

Make freeldr/setupldr composed of a PE file and prepended raw 16bit code. The 16 bit code starts with the usual fathelp code. This brings back support for fragmented fat12/16 disks.
Later all 16 bit code is supposed to go into the raw binary chunk to be able to build freeldr with MSVC.

svn path=/trunk/; revision=52204
This commit is contained in:
Timo Kreuzer 2011-06-12 21:21:47 +00:00
parent 6a588bbcd4
commit 8c46f42495
9 changed files with 634 additions and 41 deletions

View file

@ -227,12 +227,7 @@ FoundFreeLoader:
// to the helper code. Skip the first three bytes
// because they contain a jump instruction to skip
// over the helper code in the FreeLoader image.
//jmp 0000:9003h
push 0 // push segment (0x0000)
mov bx, [HEX(8000) + HEX(0A8)] // load the RVA of the EntryPoint into eax
add bx, HEX(8003) // RVA -> VA and skip 3 bytes (jump to fathelper code)
push bx // push offset
retf // Transfer control to FreeLoader
ljmp16 0, HEX(8003)

View file

@ -420,11 +420,8 @@ LoadFileDone:
mov dl, byte ptr BP_REL(BootDrive) // Load boot drive into DL
mov dh, byte ptr ds:[BootPartition] // Load boot partition into DH
push 0 // push segment (0x0000)
mov eax, dword ptr ds:[HEX(8000) + HEX(0A8)] // load the RVA of the EntryPoint into eax
add eax, HEX(8000) // RVA -> VA
push ax // push offset
retf // Transfer control to FreeLoader
/* Transfer execution to the bootloader */
ljmp16 0, HEX(8000)
// Returns the FAT entry for a given cluster number
// On entry EAX has cluster number

View file

@ -372,12 +372,9 @@ get_fs_structures:
mov dl, byte ptr ds:[DriveNo] // dl = boot drive
mov dh, 0 // dh = boot partition
push 0 // push segment (0x0000)
mov eax, dword ptr ds:[HEX(8000) + HEX(0A8)] // load the RVA of the EntryPoint into eax
add eax, HEX(8000) // RVA -> VA
push ax // push offset
retf // Transfer control to ROSLDR
/* Transfer execution to the bootloader */
ljmp16 0, HEX(8000)
//
// searchdir:

View file

@ -14,7 +14,6 @@ if(ARCH MATCHES i386)
arch/i386/realmode.S)
else()
list(APPEND FREELDR_STARTUP_SOURCE
arch/i386/fathelp.S
arch/i386/arch.S)
endif()
elseif(ARCH MATCHES amd64)
@ -23,7 +22,6 @@ elseif(ARCH MATCHES amd64)
arch/amd64/stubs.S)
else()
list(APPEND FREELDR_STARTUP_SOURCE
arch/i386/fathelp.S
arch/amd64/arch.S)
endif()
endif()
@ -182,6 +180,11 @@ set_source_files_properties(${FREELDR_ARCH_SOURCE} PROPERTIES COMPILE_DEFINITION
add_library(freeldr_arch ${FREELDR_ARCH_SOURCE})
add_dependencies(freeldr_arch bugcodes)
CreateBootSectorTarget2(frldr16
${CMAKE_CURRENT_SOURCE_DIR}/arch/realmode/i386.S
${CMAKE_CURRENT_BINARY_DIR}/frldr16.bin
8000)
list(APPEND FREELDR_SOURCE
bootmgr.c
${FREELDR_STARTUP_SOURCE}
@ -189,24 +192,23 @@ list(APPEND FREELDR_SOURCE
${FREELDR_BASE_SOURCE}
)
add_library(freeldr SHARED ${FREELDR_SOURCE})
add_executable(freeldr_pe ${FREELDR_SOURCE})
if(NOT MSVC)
set_target_properties(freeldr PROPERTIES LINK_FLAGS "-Wl,--strip-all -Wl,--exclude-all-symbols -Wl,--file-alignment,0x1000 -Wl,-T,${CMAKE_CURRENT_SOURCE_DIR}/freeldr_i386.lnk" SUFFIX ".sys")
set_image_base(freeldr 0x8000)
set_target_properties(freeldr_pe PROPERTIES LINK_FLAGS "-Wl,--strip-all -Wl,--exclude-all-symbols -Wl,--file-alignment,0x1000 -Wl,-T,${CMAKE_CURRENT_SOURCE_DIR}/freeldr_i386.lnk")
else()
set_target_properties(freeldr PROPERTIES LINK_FLAGS "/ignore:4078 /ignore:4254 /DRIVER /FIXED /ALIGN:0x400 /SECTION:.text,ERW /SECTION:.data,RW /MERGE:.text16=.text /MERGE:.data=.text /MERGE:.rdata=.text /MERGE:.bss=.text /SUBSYSTEM:BOOT_APPLICATION" SUFFIX ".sys")
set_image_base(freeldr 0x10000)
set_target_properties(freeldr_pe PROPERTIES LINK_FLAGS "/ignore:4078 /ignore:4254 /DRIVER /FIXED /ALIGN:0x400 /SECTION:.text,ERW /SECTION:.data,RW /MERGE:.text16=.text /MERGE:.data=.text /MERGE:.rdata=.text /MERGE:.bss=.text /SUBSYSTEM:BOOT_APPLICATION")
endif()
set_subsystem(freeldr native)
set_entrypoint(freeldr mainCRTStartup)
set_subsystem(freeldr_pe native)
set_image_base(freeldr_pe 0x9000)
set_entrypoint(freeldr_pe mainCRTStartup)
if(ARCH MATCHES i386)
target_link_libraries(freeldr mini_hal)
target_link_libraries(freeldr_pe mini_hal)
endif()
target_link_libraries(freeldr
target_link_libraries(freeldr_pe
freeldr_arch
cportlib
rossym
@ -214,10 +216,17 @@ target_link_libraries(freeldr
rtl
libcntpr)
add_pch(freeldr include/freeldr.h)
add_dependencies(freeldr asm)
add_pch(freeldr_pe include/freeldr.h)
add_dependencies(freeldr_pe asm)
add_cd_file(TARGET freeldr DESTINATION loader NO_CAB FOR all)
concatenate_files(
${CMAKE_CURRENT_BINARY_DIR}/frldr16.bin
${CMAKE_CURRENT_BINARY_DIR}/freeldr_pe.exe
${CMAKE_CURRENT_BINARY_DIR}/freeldr.sys)
add_custom_target(freeldr ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/freeldr.sys)
add_cd_file(FILE ${CMAKE_CURRENT_BINARY_DIR}/freeldr.sys DESTINATION loader NO_CAB FOR all)
list(APPEND SETUPLDR_MAIN_SOURCE
bootmgr.c
@ -238,23 +247,23 @@ list(APPEND SETUPLDR_SOURCE
${FREELDR_BASE_SOURCE}
${SETUPLDR_MAIN_SOURCE})
add_library(setupldr SHARED ${SETUPLDR_SOURCE})
add_executable(setupldr_pe ${SETUPLDR_SOURCE})
if(NOT MSVC)
set_target_properties(setupldr PROPERTIES LINK_FLAGS "-Wl,--strip-all -Wl,--exclude-all-symbols -Wl,--file-alignment,0x1000 -Wl,-T,${CMAKE_CURRENT_SOURCE_DIR}/freeldr_i386.lnk" SUFFIX ".sys" COMPILE_DEFINITIONS "FREELDR_REACTOS_SETUP")
set_image_base(setupldr 0x8000)
set_target_properties(setupldr_pe PROPERTIES LINK_FLAGS "-Wl,--strip-all -Wl,--exclude-all-symbols -Wl,--file-alignment,0x1000 -Wl,-T,${CMAKE_CURRENT_SOURCE_DIR}/freeldr_i386.lnk" COMPILE_DEFINITIONS "FREELDR_REACTOS_SETUP")
else()
set_target_properties(setupldr PROPERTIES LINK_FLAGS "/DRIVER /SECTION:.text,ERWP,ALIGN=0x1000" SUFFIX ".sys" COMPILE_DEFINITIONS "FREELDR_REACTOS_SETUP")
set_target_properties(setupldr_pe PROPERTIES LINK_FLAGS "/DRIVER /SECTION:.text,ERWP,ALIGN=0x1000" COMPILE_DEFINITIONS "FREELDR_REACTOS_SETUP")
endif()
set_subsystem(setupldr native)
set_entrypoint(setupldr mainCRTStartup)
set_subsystem(setupldr_pe native)
set_image_base(setupldr_pe 0x9000)
set_entrypoint(setupldr_pe mainCRTStartup)
if(ARCH MATCHES i386)
target_link_libraries(setupldr mini_hal)
target_link_libraries(setupldr_pe mini_hal)
endif()
target_link_libraries(setupldr
target_link_libraries(setupldr_pe
freeldr_arch
cportlib
rossym
@ -262,7 +271,14 @@ target_link_libraries(setupldr
rtl
libcntpr)
add_dependencies(setupldr asm)
add_dependencies(setupldr_pe asm)
add_cd_file(TARGET setupldr DESTINATION loader NO_CAB FOR all)
concatenate_files(
${CMAKE_CURRENT_BINARY_DIR}/frldr16.bin
${CMAKE_CURRENT_BINARY_DIR}/setupldr_pe.exe
${CMAKE_CURRENT_BINARY_DIR}/setupldr.sys)
add_custom_target(setupldr ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/setupldr.sys)
add_cd_file(FILE ${CMAKE_CURRENT_BINARY_DIR}/setupldr.sys DESTINATION loader NO_CAB FOR all)

View file

@ -56,6 +56,7 @@ PUBLIC _mainCRTStartup // For Mingw32 builds where the linker looks for this sym
_mainCRTStartup:
PUBLIC start
start:
#if 0
.byte HEX(e9)
.byte HEX(fd)
.byte HEX(01)
@ -134,7 +135,7 @@ LoadFile_Done:
// Reads the entire FAT into memory at 7000:0000
ReadFatIntoMemory:
mov ax, [bp+HiddenSectors]
mov ax, [bp+HiddenSectors]
mov dx, [bp+HiddenSectors+2]
add ax, [bp+ReservedSectors]
adc dx, 0
@ -233,6 +234,7 @@ msgLoading: .asciz "Loading FreeLoader...\r\n"
.org HEX(1fe) // Pad to 510 bytes
.word HEX(0aa55) // BootSector signature
#endif
.endcode16

View file

@ -0,0 +1,225 @@
#include <asm.inc>
#include <arch/pc/x86common.h>
#define IMAGE_DOS_HEADER_e_lfanew 36
#define IMAGE_FILE_HEADER_SIZE 20
#define IMAGE_OPTIONAL_HEADER_AddressOfEntryPoint 16
.code16
/* fat helper code */
#include "fathelp.inc"
.org 512
RealEntryPoint:
cli
/* Setup real mode segment registers */
xor ax, ax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
/* checkPoint Charlie - where it all began... */
mov si, offset CheckPoint0
call writestr
/* Setup a real mode stack */
mov sp, stack16
/* Zero BootDrive and BootPartition */
xor eax, eax
mov BootDrive, eax
mov BootPartition, eax
/* Store the boot drive */
mov BootDrive, dl
/* Store the boot partition */
mov BootPartition, dh
/* Load the GDT */
lgdt gdtptr
/* Load the IDT */
// lidt idtptr
call x86_16_EnableA20
/* checkPoint Charlie - where it all began... */
mov si, offset CheckPoint1
call writestr
call x86_16_BuildPageTables
/* checkPoint Charlie - where it all began... */
mov si, offset CheckPoint2
call writestr
/* Check if CPU supports CPUID */
pushfd
pop eax
mov ebx, eax
xor eax, HEX(00200000)
push eax
popfd
pushfd
pop eax
cmp eax,ebx
jz no_cpuid_support_detected
/* 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
/* PAE and PGE are here */
xor edx, edx
mov eax, HEX(80000001)
cpuid
and edx, HEX(20000000)
test edx,edx
jz no_x64_support_detected
/* X64 Processor */
/* checkPoint Charlie - where it all began... */
mov si, offset CheckPoint3
call writestr
/* 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
/* 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
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:
pusha
push es
/* Get segment of pml4 */
mov eax, offset pml4_startup
shr eax, 4
mov es, ax
cld
xor di, di
/* One entry in the PML4 pointing to PDP */
mov eax, offset pdp_startup
or eax, HEX(00f)
stosd
/* clear rest */
xor eax, eax
mov cx, HEX(03ff)
rep stosd
/* One entry in the PDP pointing to PD */
mov eax, offset pd_startup
or eax, HEX(00f)
stosd
/* clear rest */
xor eax, eax
mov ecx, HEX(03ff)
rep stosd
/* 512 entries in the PD defining a 2MB page each */
mov ecx, 512
mov eax, HEX(008f)
Bpt2:
mov es: [di], eax
mov dword ptr es: [di + 4], 0
add eax, 512 << 12 // add 512 4k pages
add di, 8
/* Loop it */
dec cx
jnz Bpt2
/* Return */
pop es
popa
ret
x86_16_ReturnToLong:
cli
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 code64ret
/* Save 16-bit stack pointer */
mov stack16, sp
mov eax, 0x00a0 // Set PAE and PGE: 10100000b
mov cr4, eax
mov edx, offset pml4_startup // Point cr3 at PML4
mov cr3, edx
mov ecx, HEX(0C0000080) // Specify EFER MSR
rdmsr // Enable long mode
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
//jmp LMODE_CS:offset LongCat //Load CS with 64 bit segment and flush the instruction cache
// Do a long jmp to the CallbackReturn address
#include "helpers.inc"
.endcode16
END

View file

@ -0,0 +1,225 @@
// fathelp.S
// FAT12/16 Boot Sector Helper Code
// Copyright (c) 1998, 2001, 2002, 2003 Brian Palmer
//#include <asm.inc>
//org 8000h
//.text
#define BootSectorStackTop HEX(7bf2)
#define DataAreaStartHigh 2
#define DataAreaStartLow 4
#define BiosCHSDriveSizeHigh 6
#define BiosCHSDriveSizeLow 8
#define BiosCHSDriveSize 8
#define ReadSectorsOffset 10
#define ReadClusterOffset 12
#define PutCharsOffset 14
#define OEMName 3
#define BytesPerSector 11
#define SectsPerCluster 13
#define ReservedSectors 14
#define NumberOfFats 16
#define MaxRootEntries 17
#define TotalSectors 19
#define MediaDescriptor 21
#define SectorsPerFat 22
#define SectorsPerTrack 24
#define NumberOfHeads 26
#define HiddenSectors 28
#define TotalSectorsBig 32
#define BootDrive 36
#define Reserved 37
#define ExtendSig 38
#define SerialNumber 39
#define VolumeLabel 43
#define FileSystem 54
#define BootPartition HEX(7dfd)
// This code will be stored in the first 512 bytes
// of freeldr.sys. The first 3 bytes will be a jmp
// instruction to skip past the FAT helper code
// that is stored in the rest of the 512 bytes.
//
PUBLIC start
start:
// This code is loaded at 0000:8000 so we have to
// encode a jmp instruction to jump to 0000:8200
.byte HEX(e9), HEX(fd), HEX(01)
// Now starts the extra boot code that we will store
// in the first 512 bytes of freeldr.sys. This code
// allows the FAT12/16 bootsector to navigate the
// FAT table so that we can still load freeldr.sys
// even if it is fragmented.
FatHelperEntryPoint:
/* First save AX - the start cluster of freeldr.sys */
push ax
/* Display "Loading FreeLoader..." message */
mov si, offset msgLoading
call word ptr [bp-PutCharsOffset]
call ReadFatIntoMemory
/* Restore AX (start cluster) */
pop ax
// AX has start cluster of freeldr.sys
mov bx, HEX(800)
mov es,bx
LoadFile:
push ax
call IsFat12
pop ax
jnc LoadFile2
cmp ax, HEX(0ff8) // Check to see if this is the last cluster in the chain
jmp LoadFile3
LoadFile2:
cmp ax, HEX(0fff8)
LoadFile3:
jae LoadFile_Done // If so continue, if not then read then next one
push ax
xor bx,bx // Load ROSLDR starting at 0000:8000h
push es
call word ptr [bp-ReadClusterOffset]
pop es
xor bx,bx
mov bl, [bp+SectsPerCluster]
shl bx,5 // BX = BX * 512 / 16
mov ax,es // Increment the load address by
add ax,bx // The size of a cluster
mov es,ax
call IsFat12
pop ax
push es
jnc LoadFile4
call GetFatEntry12 // Get the next entry
jmp LoadFile5
LoadFile4:
call GetFatEntry16
LoadFile5:
pop es
jmp LoadFile // Load the next cluster (if any)
LoadFile_Done:
mov dl, byte ptr [bp+BootDrive] // Load the boot drive into DL
mov dh, byte ptr ds:[BootPartition] // Load the boot partition into DH
/* continue where other bootsectors start */
jmp start
// Reads the entire FAT into memory at 7000:0000
ReadFatIntoMemory:
mov ax, [bp+HiddenSectors]
mov dx, [bp+HiddenSectors+2]
add ax, [bp+ReservedSectors]
adc dx, 0
mov cx, [bp+SectorsPerFat]
mov bx, HEX(7000)
mov es,bx
xor bx,bx
call word ptr [bp-ReadSectorsOffset]
ret
// Returns the FAT entry for a given cluster number for 16-bit FAT
// On entry AX has cluster number
// On return AX has FAT entry for that cluster
GetFatEntry16:
mov cx,2 // AX = AX * 2 (since FAT16 entries are 2 bytes)
mul cx
shl dx,12
mov bx, HEX(7000)
add bx,dx
mov es,bx
mov bx,ax // Restore FAT entry offset
mov ax, es:[bx] // Get FAT entry
ret
// Returns the FAT entry for a given cluster number for 12-bit FAT
// On entry AX has cluster number
// On return AX has FAT entry for that cluster
GetFatEntry12:
push ax
mov cx,ax
shr ax,1
add ax,cx // AX = AX * 1.5 (AX = AX + (AX / 2)) (since FAT12 entries are 12 bits)
mov bx, HEX(7000)
mov es,bx
mov bx,ax // Put FAT entry offset into BX
mov ax, es:[bx] // Get FAT entry
pop cx // Get cluster number from stack
and cx,1
jz UseLow12Bits
and ax, HEX(0fff0)
shr ax,4
jmp GetFatEntry12_Done
UseLow12Bits:
and ax, HEX(0fff)
GetFatEntry12_Done:
ret
// Returns CF = 1 if this is a FAT12 file system
// Otherwise CF = 0 for FAT16
IsFat12:
mov ebx, dword ptr [bp-DataAreaStartLow]
// EBX now has the number of the starting sector of the data area
// starting from the beginning of the disk, so subtrace hidden sectors
sub ebx, dword ptr [bp+HiddenSectors]
xor eax,eax
mov ax, word ptr [bp+TotalSectors]
cmp ax, 0
jnz IsFat12_2
mov eax, dword ptr [bp+TotalSectorsBig]
// EAX now contains the number of sectors on the volume
IsFat12_2:
sub eax,ebx // Subtract data area start sector
xor edx,edx // from total sectors of volume
// EDX:EAX now contains the number of data sectors on the volume
movzx ebx, byte ptr [bp+SectsPerCluster]
div ebx
// EAX now has the number of clusters on the volume
stc
cmp eax,4085
jb IsFat12_Done
clc
IsFat12_Done:
ret
msgLoading: .asciz "Loading FreeLoader...\r\n"
.org 510 // Pad to 510 bytes
.word HEX(0aa55) // BootSector signature
END

View file

@ -0,0 +1,104 @@
Empty8042:
.word 0x00eb,0x00eb // jmp $+2, jmp $+2
in al, 0x64
cmp al, 0xff // legacy-free machine without keyboard
jz empty_8042_ret // controllers on Intel Macs read back 0xFF
test al, 0x02
jnz x86_16_Empty8042
empty_8042_ret:
ret
EnableA20:
pusha
call x86_16_Empty8042
mov al, 0xD1 // command write
out 0x64, al
call x86_16_Empty8042
mov al, 0xDF // A20 on
out 0x60, al
call x86_16_Empty8042
popa
ret
/*
* writestr
* si = pointer to zero terminated string
*/
writestr:
pushfd
pushad
writestr_top:
lodsb
and al, al
jz writestr_end
call writechr
jmp short writestr_top
writestr_end:
popad
popfd
ret
/*
* writechr
* al = character to output
*/
writechr:
pushf
pusha
mov ah, 0x0E
xor bx, bx
int 0x10
popa
popf
ret
//
// writehex[248]: Write a hex number in (AL, AX, EAX) to the console
//
writehex2:
pushfd
pushad
shl eax, 24
mov cx, 2
jmp short writehex_common
writehex4:
pushfd
pushad
shl eax, 16
mov cx, 4
jmp short writehex_common
writehex8:
pushfd
pushad
mov cx, 8
writehex_common:
.loop:
rol eax, 4
push eax
and al, HEX(0F)
cmp al, 10
jae .high
.low:
add al, '0'
jmp short .ischar
.high:
add al, 'A'-10
.ischar:
call writechr
pop eax
loop .loop
popad
popfd
ret
SoftReboot:
mov ax, HEX(40)
mov ds, ax
mov si, HEX(72)
/* Set the word at location 40:72 to 1234h */
mov word ptr [si], HEX(1234)
/* and jump to location FFFF:0 in ROM */
ljmp16 HEX(0FFFF), HEX(0000)

View file

@ -0,0 +1,32 @@
#include <asm.inc>
#include "../../include/arch/pc/x86common.h"
#define IMAGE_DOS_HEADER_e_lfanew 60
#define IMAGE_FILE_HEADER_SIZE 20
#define IMAGE_OPTIONAL_HEADER_AddressOfEntryPoint 16
.code16
/* fat helper code */
#include "fathelp.inc"
.org 512
RealEntryPoint:
/* 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 */
mov eax, dword ptr ds:[eax + IMAGE_OPTIONAL_HEADER_AddressOfEntryPoint]
add eax, FREELDR_PE_BASE
jmp ax
#include "helpers.inc"
.org (FREELDR_PE_BASE - FREELDR_BASE)
.endcode16
END