mirror of
https://github.com/reactos/reactos.git
synced 2025-04-28 01:11:35 +00:00
[FREELDR] Add support for loading Linux in x64 FreeLdr. Part 1/2: ASM code.
Add also ASM implementation for intrinsics that may not be always present on MSVC (e.g. MSVC 2010).
This commit is contained in:
parent
21c51eed05
commit
25badcfbbd
5 changed files with 254 additions and 60 deletions
|
@ -143,7 +143,8 @@ elseif(ARCH STREQUAL "amd64")
|
|||
list(APPEND FREELDR_COMMON_ASM_SOURCE
|
||||
arch/amd64/entry.S
|
||||
arch/amd64/int386.S
|
||||
arch/amd64/pnpbios.S)
|
||||
arch/amd64/pnpbios.S
|
||||
arch/amd64/linux.S)
|
||||
|
||||
list(APPEND FREELDR_NTLDR_SOURCE
|
||||
ntldr/arch/amd64/winldr.c)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
|
||||
#include <asm.inc>
|
||||
#include <arch/pc/x86common.h>
|
||||
#include <arch/pc/pcbios.h>
|
||||
|
||||
EXTERN BootMain:PROC
|
||||
// EXTERN cmdline:DWORD
|
||||
|
@ -75,50 +76,71 @@ Reboot:
|
|||
/* Stop the floppy drive motor */
|
||||
call DiskStopFloppyMotor
|
||||
|
||||
/* Set the function ID */
|
||||
/* Set the function ID and switch to real mode (we don't return) */
|
||||
mov bx, FNID_Reboot
|
||||
|
||||
/* Switch to real mode (we don't return) */
|
||||
jmp SwitchToReal
|
||||
|
||||
|
||||
/*
|
||||
* VOID __cdecl ChainLoadBiosBootSectorCode(
|
||||
* IN UCHAR BootDrive OPTIONAL,
|
||||
* IN ULONG BootPartition OPTIONAL);
|
||||
* VOID __cdecl Relocator16Boot(
|
||||
* IN REGS* In<rcx>,
|
||||
* IN USHORT StackSegment<dx>,
|
||||
* IN USHORT StackPointer<r8w>,
|
||||
* IN USHORT CodeSegment<r9w>,
|
||||
* IN USHORT CodePointer<rsp+40>);
|
||||
*
|
||||
* RETURNS: Nothing
|
||||
* RETURNS: Nothing.
|
||||
*
|
||||
* NOTE: The implementation of this function is similar to that of Int386(),
|
||||
* with the proviso that no attempt is done to save the original values of
|
||||
* the registers since we will not need them anyway, as we do not return back
|
||||
* to the caller but instead place the machine in a permanent new CPU state.
|
||||
*/
|
||||
PUBLIC ChainLoadBiosBootSectorCode
|
||||
ChainLoadBiosBootSectorCode:
|
||||
/* Set the boot drive */
|
||||
mov dl, [esp + 4]
|
||||
test dl, dl
|
||||
jnz set_part
|
||||
mov dl, byte ptr [FrldrBootDrive]
|
||||
PUBLIC Relocator16Boot
|
||||
Relocator16Boot:
|
||||
|
||||
/* Set the boot partition */
|
||||
set_part:
|
||||
mov eax, [esp + 8]
|
||||
test eax, eax
|
||||
jnz continue
|
||||
mov eax, dword ptr [FrldrBootPartition]
|
||||
continue:
|
||||
/* Store the 1-byte truncated partition number in DH */
|
||||
mov dh, al
|
||||
/* Save home registers */
|
||||
mov qword ptr [rsp + 8], rcx
|
||||
mov word ptr [rsp + 16], dx
|
||||
mov word ptr [rsp + 24], r8w
|
||||
mov word ptr [rsp + 32], r9w
|
||||
|
||||
#if 0
|
||||
/* Save non-volatile registers */
|
||||
push rbx
|
||||
push rsi
|
||||
push rdi
|
||||
#endif
|
||||
|
||||
/* Copy input registers */
|
||||
mov rsi, qword ptr [rsp + 8]
|
||||
mov rdi, BSS_RegisterSet
|
||||
mov rcx, REGS_SIZE / 4
|
||||
rep movsd
|
||||
|
||||
/* Set the stack segment/offset */
|
||||
// Since BSS_CallbackReturn contains a ULONG, store in its high word
|
||||
// the stack segment and in its low word the stack offset.
|
||||
mov ax, word ptr [rsp + 16]
|
||||
shl eax, 16
|
||||
mov ax, word ptr [rsp + 24]
|
||||
mov dword ptr [BSS_CallbackReturn], eax
|
||||
|
||||
/*
|
||||
* Don't stop the floppy drive motor when we are just booting a bootsector,
|
||||
* a drive, or a partition. If we were to stop the floppy motor, the BIOS
|
||||
* wouldn't be informed and if the next read is to a floppy then the BIOS
|
||||
* will still think the motor is on and this will result in a read error.
|
||||
* Set the code segment/offset (Copy entry point)
|
||||
* NOTE: We permanently *ERASE* the contents of ds:[BSS_RealModeEntry]
|
||||
* but it is not a problem since we are going to place the machine in
|
||||
* a permanent new CPU state.
|
||||
*/
|
||||
// call DiskStopFloppyMotor
|
||||
// Since BSS_RealModeEntry contains a ULONG, store in its high word
|
||||
// the code segment and in its low word the code offset.
|
||||
mov ax, word ptr [rsp + 32]
|
||||
shl eax, 16
|
||||
mov ax, word ptr [rsp + 40]
|
||||
mov dword ptr [BSS_RealModeEntry], eax
|
||||
|
||||
/* Set the function ID */
|
||||
mov bx, FNID_ChainLoadBiosBootSectorCode
|
||||
|
||||
/* Switch to real mode (we don't return) */
|
||||
/* Set the function ID and switch to real mode (we don't return) */
|
||||
mov bx, FNID_Relocator16Boot
|
||||
jmp SwitchToReal
|
||||
|
||||
|
||||
|
@ -166,7 +188,7 @@ jumpvector:
|
|||
.word CMODE_CS
|
||||
|
||||
SwitchToRealCompSegment:
|
||||
/* Note: In fact the CPU is in 32 bit mode here. But it will interprete
|
||||
/* Note: In fact the CPU is in 32 bit mode here. But it will interpret
|
||||
the generated instructions accordingly. rax will become eax */
|
||||
|
||||
/* Step 2 - deactivate long mode, by disabling paging */
|
||||
|
@ -191,18 +213,30 @@ CallRealMode_return:
|
|||
/////////////////////////////////////////
|
||||
|
||||
|
||||
//void __lgdt(void *Source);
|
||||
// void __fastfail(unsigned int Code<rcx>);
|
||||
PUBLIC __fastfail
|
||||
__fastfail:
|
||||
// mov ecx, [rsp + 4]
|
||||
int HEX(29)
|
||||
|
||||
// void __lgdt(void *Source<rcx>);
|
||||
PUBLIC __lgdt
|
||||
__lgdt:
|
||||
lgdt fword ptr [rcx]
|
||||
ret
|
||||
|
||||
//void __ltr(unsigned short Source);
|
||||
// void __ltr(unsigned short Source<rcx>);
|
||||
PUBLIC __ltr
|
||||
__ltr:
|
||||
ltr cx
|
||||
ret
|
||||
|
||||
// void _sgdt(void *Destination<rcx>);
|
||||
PUBLIC __sgdt
|
||||
__sgdt:
|
||||
sgdt fword ptr [rcx]
|
||||
ret
|
||||
|
||||
|
||||
/* 64-bit stack pointer */
|
||||
stack64:
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <asm.inc>
|
||||
#include <arch/pc/x86common.h>
|
||||
#include <arch/pc/pcbios.h>
|
||||
|
||||
.code64
|
||||
|
||||
EXTERN CallRealMode:PROC
|
||||
|
@ -40,7 +41,7 @@ Int386:
|
|||
push rsi
|
||||
push rdi
|
||||
|
||||
/* Alloc stack space for home registers */
|
||||
/* Alloc stack space for home registers (+ alignment) */
|
||||
sub rsp, 40
|
||||
//.ENDPROLOG
|
||||
|
||||
|
@ -68,11 +69,11 @@ int386_2:
|
|||
|
||||
/* Copy output registers */
|
||||
mov rsi, BSS_RegisterSet
|
||||
mov rdi, [r11 + 24]
|
||||
mov rdi, qword ptr [r11 + 24]
|
||||
mov rcx, REGS_SIZE / 4
|
||||
rep movsd
|
||||
|
||||
/* cleanup and return */
|
||||
/* Cleanup and return */
|
||||
add rsp, 40
|
||||
pop rdi
|
||||
pop rsi
|
||||
|
|
159
boot/freeldr/freeldr/arch/amd64/linux.S
Normal file
159
boot/freeldr/freeldr/arch/amd64/linux.S
Normal file
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <asm.inc>
|
||||
#include <arch/pc/x86common.h>
|
||||
#include <arch/pc/pcbios.h>
|
||||
|
||||
EXTERN DiskStopFloppyMotor:PROC
|
||||
EXTERN Relocator16Boot:PROC
|
||||
EXTERN FrldrBootDrive:BYTE
|
||||
EXTERN FrldrBootPartition:DWORD
|
||||
|
||||
.code64
|
||||
|
||||
Regs:
|
||||
.space REGS_SIZE
|
||||
|
||||
/*
|
||||
* VOID __cdecl BootLinuxKernel(
|
||||
* IN ULONG KernelSize<ecx>,
|
||||
* IN PVOID KernelCurrentLoadAddress<rdx>,
|
||||
* IN PVOID KernelTargetLoadAddress<r8>,
|
||||
* IN UCHAR DriveNumber<r9b>,
|
||||
* IN ULONG PartitionNumber<rsp+40>);
|
||||
*/
|
||||
PUBLIC BootLinuxKernel
|
||||
BootLinuxKernel:
|
||||
|
||||
/* Save home registers */
|
||||
mov r11, rsp
|
||||
mov dword ptr [r11 + 8], ecx
|
||||
mov qword ptr [r11 + 16], rdx
|
||||
mov qword ptr [r11 + 24], r8
|
||||
mov byte ptr [r11 + 32], r9b
|
||||
|
||||
/* Save non-volatile registers */
|
||||
push rsi
|
||||
push rdi
|
||||
|
||||
/* Allocate stack space for home registers (+ alignment) */
|
||||
sub rsp, (8*4 + 8)
|
||||
//.ENDPROLOG
|
||||
|
||||
/* Stop the floppy drive motor */
|
||||
call DiskStopFloppyMotor
|
||||
|
||||
/* Set all segment registers to 0x9000 */
|
||||
mov ax, HEX(9000)
|
||||
mov word ptr [Regs + REGS_DS], ax
|
||||
mov word ptr [Regs + REGS_ES], ax
|
||||
mov word ptr [Regs + REGS_FS], ax
|
||||
mov word ptr [Regs + REGS_GS], ax
|
||||
|
||||
/* Set the boot drive */
|
||||
xor edx, edx
|
||||
mov dl, byte ptr [r11 + 32]
|
||||
test dl, dl
|
||||
jnz set_part
|
||||
mov dl, byte ptr /*ds:*/[FrldrBootDrive]
|
||||
|
||||
/* Set the boot partition */
|
||||
set_part:
|
||||
mov eax, dword ptr [r11 + 40]
|
||||
test eax, eax
|
||||
jnz continue
|
||||
mov eax, dword ptr /*ds:*/[FrldrBootPartition]
|
||||
continue:
|
||||
/* Store the 1-byte truncated partition number in DH */
|
||||
mov dh, al
|
||||
|
||||
mov dword ptr [Regs + REGS_EDX], edx
|
||||
|
||||
/*
|
||||
* Relocate the kernel image to its final destination (can be as low as 0x10000).
|
||||
* The reason we can overwrite low memory is because this code executes
|
||||
* between 0000:8000 and 0000:FFFF. That leaves space for 32k of code
|
||||
* before we start interfering with Linux kernel address space.
|
||||
*/
|
||||
|
||||
/* Get KernelSize in ECX */
|
||||
xor rcx, rcx // Put the 64..32 higher bits to zero
|
||||
mov ecx, dword ptr [r11 + 8]
|
||||
test rcx, rcx // If size is zero, do not perform relocations
|
||||
jz after_reloc
|
||||
|
||||
/* Load the source and target addresses */
|
||||
mov rsi, qword ptr [r11 + 16] // HEX(100000) // LINUX_KERNEL_LOAD_ADDRESS
|
||||
mov rdi, qword ptr [r11 + 24] // HEX(10000)
|
||||
|
||||
//
|
||||
// FIXME: Support relocating *upwards*, overlapping regions, aligned addresses,
|
||||
// etc... !! See memmove code.
|
||||
//
|
||||
/* Check how we should perform relocation */
|
||||
cmp rdi, rsi
|
||||
je after_reloc // target == source: do not perform relocations
|
||||
ja reloc_up // target > source: relocate up
|
||||
// jb reloc_down // target < source: relocate down (default)
|
||||
|
||||
reloc_down:
|
||||
/* Move the kernel down - Start with low addresses and increment them */
|
||||
cld
|
||||
#if 0
|
||||
rep movsb
|
||||
#else
|
||||
mov rdx, rcx // Copy the total number of bytes in EDX
|
||||
and rdx, HEX(0FFFFFFFC) // Number of bytes we copy using DWORDs
|
||||
xor rdx, rcx // Number of remaining bytes to copy after the DWORDs
|
||||
shr rcx, 2 // Count number of DWORDs
|
||||
rep movsd // Move DWORDs
|
||||
mov rcx, rdx // Count number of remaining bytes
|
||||
rep movsb // Move bytes
|
||||
#endif
|
||||
jmp after_reloc
|
||||
|
||||
reloc_up:
|
||||
/* Move the kernel up - Start with high addresses and decrement them */
|
||||
std
|
||||
add rsi, rcx
|
||||
add rdi, rcx
|
||||
dec rsi
|
||||
dec rdi
|
||||
rep movsb
|
||||
// jmp after_reloc
|
||||
|
||||
after_reloc:
|
||||
|
||||
mov word ptr [rsp-8 + 40], HEX(0000) // CodePointer
|
||||
mov r9w, HEX(9020) // CodeSegment
|
||||
mov r8w, HEX(9000) // StackPointer
|
||||
mov dx, HEX(9000) // StackSegment
|
||||
mov rcx, offset Regs
|
||||
call Relocator16Boot
|
||||
|
||||
/* Cleanup and return */
|
||||
add rsp, (8*4 + 8)
|
||||
pop rdi
|
||||
pop rsi
|
||||
|
||||
/* We must never get there */
|
||||
int 3
|
||||
|
||||
END
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
.code16
|
||||
|
||||
/* fat helper code */
|
||||
/* FAT helper code */
|
||||
#include "fathelp.inc"
|
||||
|
||||
.org 512
|
||||
|
@ -107,20 +107,20 @@ Msg_SwitchToLongMode:
|
|||
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(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) /* 20: 16-bit real mode CS */
|
||||
.word HEX(FFFF), HEX(0000), HEX(9200), HEX(0000) /* 28: 16-bit real mode DS */
|
||||
.word HEX(FFFF), HEX(0000), HEX(9B00), HEX(00CF) /* 30: compat mode cs */
|
||||
.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 */
|
||||
.word HEX(37) /* Limit */
|
||||
.long offset gdt /* Base Address */
|
||||
|
||||
|
||||
CheckFor64BitSupport:
|
||||
/* Check if CPU supports CPUID */
|
||||
/* Check whether the CPU supports CPUID */
|
||||
pushad
|
||||
pushfd
|
||||
pop eax
|
||||
|
@ -130,7 +130,7 @@ CheckFor64BitSupport:
|
|||
popfd
|
||||
pushfd
|
||||
pop eax
|
||||
cmp eax,ebx
|
||||
cmp eax, ebx
|
||||
jnz .CheckForPAE
|
||||
|
||||
mov si, offset .Msg_NoCpuidSupport
|
||||
|
@ -144,10 +144,10 @@ CheckFor64BitSupport:
|
|||
|
||||
.CheckForPAE:
|
||||
/* 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
|
||||
and edx, HEX(00a0)
|
||||
cmp edx, HEX(00a0)
|
||||
and edx, HEX(00A0)
|
||||
cmp edx, HEX(00A0)
|
||||
je .CheckForLongMode
|
||||
|
||||
mov si, offset .Msg_NoPAE
|
||||
|
@ -164,7 +164,7 @@ CheckFor64BitSupport:
|
|||
mov eax, HEX(80000001)
|
||||
cpuid
|
||||
and edx, HEX(20000000)
|
||||
test edx,edx
|
||||
test edx, edx
|
||||
jnz .Success
|
||||
|
||||
mov si, offset .Msg_NoLongMode
|
||||
|
@ -195,7 +195,7 @@ BuildPageTables:
|
|||
|
||||
/* One entry in the PML4 pointing to PDP */
|
||||
mov eax, PDP_ADDRESS
|
||||
or eax, HEX(0f)
|
||||
or eax, HEX(0F)
|
||||
stosd
|
||||
|
||||
/* clear rest */
|
||||
|
@ -205,7 +205,7 @@ BuildPageTables:
|
|||
|
||||
/* One entry in the PDP pointing to PD */
|
||||
mov eax, PD_ADDRESS
|
||||
or eax, HEX(0f)
|
||||
or eax, HEX(0F)
|
||||
stosd
|
||||
|
||||
/* clear rest */
|
||||
|
@ -218,8 +218,8 @@ BuildPageTables:
|
|||
mov eax, HEX(008f)
|
||||
|
||||
.Bpt2:
|
||||
mov es: [di], eax
|
||||
mov dword ptr es: [di + 4], 0
|
||||
mov es:[di], eax
|
||||
mov dword ptr es:[di + 4], 0
|
||||
add eax, 512 * 4096 // add 512 4k pages
|
||||
add di, 8
|
||||
|
||||
|
@ -242,7 +242,7 @@ BuildPageTables:
|
|||
RealModeEntryPoint:
|
||||
/* Disable Protected Mode */
|
||||
mov eax, cr0
|
||||
and eax, HEX(0fffffffe) // ~0x00000001
|
||||
and eax, HEX(0FFFFFFFE) // ~0x00000001
|
||||
mov cr0, eax
|
||||
|
||||
/* Clear prefetch queue & correct CS */
|
||||
|
@ -295,7 +295,7 @@ ExitToLongMode:
|
|||
mov word ptr ds:[stack16], sp
|
||||
|
||||
/* Set PAE and PGE: 10100000b */
|
||||
mov eax, HEX(00a0)
|
||||
mov eax, HEX(00A0)
|
||||
mov cr4, eax
|
||||
|
||||
/* Point cr3 at the PML4 */
|
||||
|
@ -322,7 +322,7 @@ InLongMode:
|
|||
//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 64bit indirect jump
|
||||
.byte HEX(0FF), HEX(25) // opcode of 64bit indirect jump
|
||||
.long 1 // relative address of LongModeEntryPoint
|
||||
nop
|
||||
LongModeEntryPoint:
|
||||
|
@ -334,11 +334,10 @@ LongModeEntryPoint:
|
|||
CallbackTable:
|
||||
.word Int386
|
||||
.word Reboot
|
||||
.word ChainLoadBiosBootSectorCode
|
||||
.word Relocator16Boot
|
||||
.word PxeCallApi
|
||||
.word PnpBiosGetDeviceNodeCount
|
||||
.word PnpBiosGetDeviceNode
|
||||
.word 0 // BootLinuxKernel
|
||||
|
||||
/* 16-bit stack pointer */
|
||||
stack16:
|
||||
|
|
Loading…
Reference in a new issue