[HAL] Implement amd64 BIOS call support

The code uses FAST486 to emulate the BIOS code.
This commit is contained in:
Timo Kreuzer 2018-02-11 19:21:01 +01:00
parent f18958ffa2
commit 9ab3246d43
5 changed files with 254 additions and 54 deletions

View file

@ -6,10 +6,10 @@
@ fastcall -arch=i386 ExTryToAcquireFastMutex(ptr) ntoskrnl.ExiTryToAcquireFastMutex
@ stdcall HalAcquireDisplayOwnership(ptr)
@ stdcall HalAdjustResourceList(ptr)
@ stdcall HalAllProcessorsStarted()
@ stdcall HalAllocateAdapterChannel(ptr ptr long ptr)
@ stdcall HalAllocateCommonBuffer(ptr long ptr long)
@ stdcall HalAllocateCrashDumpRegisters(ptr ptr)
@ stdcall HalAllProcessorsStarted()
@ stdcall HalAssignSlotResources(ptr ptr ptr ptr long long long ptr)
@ stdcall -arch=i386,arm HalBeginSystemInterrupt(long long ptr)
@ stdcall HalCalibratePerformanceCounter(ptr long long)
@ -29,8 +29,8 @@
@ stdcall HalGetInterruptVector(long long long long ptr ptr)
;@ stdcall -arch=x86_64 HalHandleMcheck()
@ stdcall -arch=i386,x86_64 HalHandleNMI(ptr)
@ stdcall HalInitializeProcessor(long ptr)
@ stdcall HalInitSystem(long ptr)
@ stdcall HalInitializeProcessor(long ptr)
;@ stdcall -arch=x86_64 HalIsHyperThreadingEnabled()
@ stdcall HalMakeBeep(long)
@ stdcall HalProcessorIdle()
@ -56,7 +56,6 @@
@ fastcall -arch=arm HalSweepIcache()
@ fastcall -arch=arm HalSweepDcache()
@ fastcall HalSystemVectorDispatchEntry(long long long)
;@ stdcall -arch=x86_64 HalSystemVectorDispatchEntry()
@ stdcall HalTranslateBusAddress(long long long long ptr ptr)
@ stdcall -arch=i386,x86_64 IoAssignDriveLetters(ptr str ptr ptr) HalpAssignDriveLetters
@ stdcall IoFlushAdapterBuffers(ptr ptr ptr ptr long long)
@ -102,7 +101,8 @@
@ stdcall -arch=i386,arm WRITE_PORT_UCHAR(ptr long)
@ stdcall -arch=i386,arm WRITE_PORT_ULONG(ptr long)
@ stdcall -arch=i386,arm WRITE_PORT_USHORT(ptr long)
@ stdcall -arch=x86_64 HalInitializeBios(long ptr)
;@ stdcall -arch=x86_64 x86BiosExecuteInterrupt()
;@ stdcall -arch=x86_64 x86BiosInitializeBiosEx()
;@ stdcall -arch=x86_64 x86BiosTranslateAddress()
@ stdcall -arch=x86_64 x86BiosAllocateBuffer()
@ stdcall -arch=x86_64 x86BiosCall()
@ stdcall -arch=x86_64 x86BiosFreeBuffer()
@ stdcall -arch=x86_64 x86BiosReadMemory()
@ stdcall -arch=x86_64 x86BiosWriteMemory()

View file

@ -5,7 +5,8 @@ add_definitions(
include_directories(
include
${REACTOS_SOURCE_DIR}/ntoskrnl/include)
${REACTOS_SOURCE_DIR}/ntoskrnl/include
${REACTOS_SOURCE_DIR}/sdk/include/reactos/libs/fast486)
function(add_hal _halname)
cmake_parse_arguments(_haldata "" "" "SOURCES;COMPONENTS" ${ARGN})
@ -76,5 +77,6 @@ elseif(ARCH STREQUAL "amd64")
amd64/processor.c)
add_hal(hal SOURCES ${HAL_SOURCE} COMPONENTS generic acpi apic)
target_link_libraries(hal fast486)
endif()

View file

@ -12,7 +12,7 @@
//#define NDEBUG
#include <debug.h>
//#include "x86emu.h"
#include <fast486.h>
/* This page serves as fallback for pages used by Mm */
#define DEFAULT_PAGE 0x21
@ -43,7 +43,9 @@ DbgDumpPage(PUCHAR MemBuffer, USHORT Segment)
VOID
NTAPI
HalInitializeBios(ULONG Unknown, PLOADER_PARAMETER_BLOCK LoaderBlock)
HalInitializeBios(
_In_ ULONG Unknown,
_In_ PLOADER_PARAMETER_BLOCK LoaderBlock)
{
PPFN_NUMBER PfnArray;
PFN_NUMBER Pfn, Last;
@ -112,12 +114,12 @@ HalInitializeBios(ULONG Unknown, PLOADER_PARAMETER_BLOCK LoaderBlock)
NTSTATUS
NTAPI
x86BiosAllocateBuffer(
ULONG *Size,
USHORT *Segment,
USHORT *Offset)
_In_ ULONG *Size,
_In_ USHORT *Segment,
_In_ USHORT *Offset)
{
/* Check if the system is initialized and the buffer is large enough */
if (!x86BiosIsInitialized || *Size > PAGE_SIZE)
if (!x86BiosIsInitialized || (*Size > PAGE_SIZE))
{
/* Something was wrong, fail! */
return STATUS_INSUFFICIENT_RESOURCES;
@ -141,11 +143,11 @@ x86BiosAllocateBuffer(
NTSTATUS
NTAPI
x86BiosFreeBuffer(
USHORT Segment,
USHORT Offset)
_In_ USHORT Segment,
_In_ USHORT Offset)
{
/* Check if the system is initialized and if the address matches */
if (!x86BiosIsInitialized || Segment != 0x2000 || Offset != 0)
if (!x86BiosIsInitialized || (Segment != 0x2000) || (Offset != 0))
{
/* Something was wrong, fail */
return STATUS_INVALID_PARAMETER;
@ -165,10 +167,10 @@ x86BiosFreeBuffer(
NTSTATUS
NTAPI
x86BiosReadMemory(
USHORT Segment,
USHORT Offset,
PVOID Buffer,
ULONG Size)
_In_ USHORT Segment,
_In_ USHORT Offset,
_Out_writes_bytes_(Size) PVOID Buffer,
_In_ ULONG Size)
{
ULONG_PTR Address;
@ -176,7 +178,7 @@ x86BiosReadMemory(
Address = (Segment << 4) + Offset;
/* Check if it's valid */
if (!x86BiosIsInitialized || Address + Size > 0x100000)
if (!x86BiosIsInitialized || ((Address + Size) > 0x100000))
{
/* Invalid */
return STATUS_INVALID_PARAMETER;
@ -192,10 +194,10 @@ x86BiosReadMemory(
NTSTATUS
NTAPI
x86BiosWriteMemory(
USHORT Segment,
USHORT Offset,
PVOID Buffer,
ULONG Size)
_In_ USHORT Segment,
_In_ USHORT Offset,
_In_reads_bytes_(Size) PVOID Buffer,
_In_ ULONG Size)
{
ULONG_PTR Address;
@ -203,7 +205,7 @@ x86BiosWriteMemory(
Address = (Segment << 4) + Offset;
/* Check if it's valid */
if (!x86BiosIsInitialized || Address + Size > 0x100000)
if (!x86BiosIsInitialized || ((Address + Size) > 0x100000))
{
/* Invalid */
return STATUS_INVALID_PARAMETER;
@ -216,53 +218,237 @@ x86BiosWriteMemory(
return STATUS_SUCCESS;
}
#if 0
static
VOID
FASTCALL
x86MemRead(
PFAST486_STATE State,
ULONG Address,
PVOID Buffer,
ULONG Size)
{
/* Validate the address range */
if (((ULONG64)Address + Size) < 0x100000)
{
RtlCopyMemory(Buffer, x86BiosMemoryMapping + Address, Size);
}
else
{
RtlFillMemory(Buffer, Size, 0xCC);
DPRINT1("x86MemRead: invalid read at 0x%lx (size 0x%lx)", Address, Size);
}
}
static
VOID
FASTCALL
x86MemWrite(
PFAST486_STATE State,
ULONG Address,
PVOID Buffer,
ULONG Size)
{
/* Validate the address range */
if (((ULONG64)Address + Size) < 0x100000)
{
RtlCopyMemory(x86BiosMemoryMapping + Address, Buffer, Size);
}
else
{
DPRINT1("x86MemWrite: invalid write at 0x%lx (size 0x%lx)", Address, Size);
}
}
static
BOOLEAN
ValidatePort(
USHORT Port,
UCHAR Size,
BOOLEAN IsWrite)
{
switch (Port)
{
// VGA: https://wiki.osdev.org/VGA_Hardware#Port_0x3C0
case 0x3C0: return (Size == 1) && IsWrite;
case 0x3C1: return (Size == 1) && !IsWrite;
case 0x3C2: return (Size == 1) && IsWrite;
case 0x3C4: return IsWrite;
case 0x3C5: return (Size <= 2);
case 0x3C7: return (Size == 1) && IsWrite;
case 0x3CC: return (Size == 1) && !IsWrite;
case 0x3CE: return IsWrite;
case 0x3CF: return (Size <= 2);
case 0x3D4: return IsWrite;
case 0x3D5: return (Size <= 2);
case 0x3C6: return (Size == 1);
case 0x3C8: return (Size == 1) && IsWrite;
case 0x3C9: return (Size == 1);
case 0x3DA: return (Size == 1) && !IsWrite;
// CHECKME!
case 0x1CE: return (Size == 1) && IsWrite;
case 0x1CF: return (Size == 1);
case 0x3B6: return (Size <= 2);
}
return FALSE;
}
static
VOID
FASTCALL
x86IoRead(
PFAST486_STATE State,
USHORT Port,
PVOID Buffer,
ULONG DataCount,
UCHAR DataSize)
{
/* Validate the port */
if (!ValidatePort(Port, DataSize, FALSE))
{
DPRINT1("Invalid IO port read access (port: 0x%x, count: 0x%x)\n", Port, DataSize);
}
switch (DataSize)
{
case 1: READ_PORT_BUFFER_UCHAR((PUCHAR)(ULONG_PTR)Port, Buffer, DataCount); return;
case 2: READ_PORT_BUFFER_USHORT((PUSHORT)(ULONG_PTR)Port, Buffer, DataCount); return;
case 4: READ_PORT_BUFFER_ULONG((PULONG)(ULONG_PTR)Port, Buffer, DataCount); return;
}
}
static
VOID
FASTCALL
x86IoWrite(
PFAST486_STATE State,
USHORT Port,
PVOID Buffer,
ULONG DataCount,
UCHAR DataSize)
{
/* Validate the port */
if (!ValidatePort(Port, DataSize, TRUE))
{
DPRINT1("Invalid IO port write access (port: 0x%x, count: 0x%x)\n", Port, DataSize);
}
switch (DataSize)
{
case 1: WRITE_PORT_BUFFER_UCHAR((PUCHAR)(ULONG_PTR)Port, Buffer, DataCount); return;
case 2: WRITE_PORT_BUFFER_USHORT((PUSHORT)(ULONG_PTR)Port, Buffer, DataCount); return;
case 4: WRITE_PORT_BUFFER_ULONG((PULONG)(ULONG_PTR)Port, Buffer, DataCount); return;
}
}
static
VOID
FASTCALL
x86BOP(
PFAST486_STATE State,
UCHAR BopCode)
{
ASSERT(FALSE);
}
static
UCHAR
FASTCALL
x86IntAck (
PFAST486_STATE State)
{
ASSERT(FALSE);
return 0;
}
BOOLEAN
NTAPI
x86BiosCall(
ULONG InterruptNumber,
X86_BIOS_REGISTERS *Registers)
_In_ ULONG InterruptNumber,
_Inout_ PX86_BIOS_REGISTERS Registers)
{
X86_VM_STATE VmState;
FAST486_STATE EmulatorContext;
struct
{
USHORT Ip;
USHORT SegCs;
} *InterrupTable;
} *Ivt;
ULONG FlatIp;
PUCHAR InstructionPointer;
/* Zero the VmState */
RtlZeroMemory(&VmState, sizeof(VmState));
/* Initialize the emulator context */
Fast486Initialize(&EmulatorContext,
x86MemRead,
x86MemWrite,
x86IoRead,
x86IoWrite,
x86BOP,
x86IntAck,
NULL, // FpuCallback,
NULL); // Tlb
//RegisterBop(BOP_UNSIMULATE, CpuUnsimulateBop);
/* Copy the registers */
VmState.BiosRegisters = *Registers;
/* Set the physical memory buffer */
VmState.MemBuffer = x86BiosMemoryMapping;
EmulatorContext.GeneralRegs[FAST486_REG_EAX].Long = Registers->Eax;
EmulatorContext.GeneralRegs[FAST486_REG_EBX].Long = Registers->Ebx;
EmulatorContext.GeneralRegs[FAST486_REG_ECX].Long = Registers->Ecx;
EmulatorContext.GeneralRegs[FAST486_REG_EDX].Long = Registers->Edx;
EmulatorContext.GeneralRegs[FAST486_REG_ESI].Long = Registers->Esi;
EmulatorContext.GeneralRegs[FAST486_REG_EDI].Long = Registers->Edi;
EmulatorContext.SegmentRegs[FAST486_REG_DS].Selector = Registers->SegDs;
EmulatorContext.SegmentRegs[FAST486_REG_ES].Selector = Registers->SegEs;
/* Set Eflags */
VmState.Registers.Eflags.Long = 0; // FIXME
EmulatorContext.Flags.Long = 0;
EmulatorContext.Flags.AlwaysSet = 1;
EmulatorContext.Flags.If = 1;
/* Setup stack */
VmState.Registers.SegSs = 0; // FIXME
VmState.Registers.Sp = 0x2000 - 2; // FIXME
/* Set the stack pointer */
Fast486SetStack(&EmulatorContext, 0, 0x2000 - 2); // FIXME
/* Initialize IP from the interrupt vector table */
InterrupTable = (PVOID)x86BiosMemoryMapping;
VmState.Registers.SegCs = InterrupTable[InterruptNumber].SegCs;
VmState.Registers.Eip = InterrupTable[InterruptNumber].Ip;
/* Make the function return on IRET */
VmState.Flags.ReturnOnIret = 1;
/* Set CS:EIP from the IVT entry */
Ivt = (PVOID)x86BiosMemoryMapping;
Fast486ExecuteAt(&EmulatorContext,
Ivt[InterruptNumber].SegCs,
Ivt[InterruptNumber].Ip);
/* Call the x86 emulator */
x86Emulator(&VmState);
while (TRUE)
{
/* Step one instruction */
Fast486StepInto(&EmulatorContext);
/* Copy registers back to caller */
*Registers = VmState.BiosRegisters;
/* Check for iret */
FlatIp = (EmulatorContext.SegmentRegs[FAST486_REG_CS].Selector << 4) +
EmulatorContext.InstPtr.Long;
if (FlatIp >= 0x100000)
{
DPRINT1("x86BiosCall: invalid IP (0x%lx) during BIOS execution", FlatIp);
return FALSE;
}
/* Read the next instruction and check if it's IRET */
InstructionPointer = x86BiosMemoryMapping + FlatIp;
if (*InstructionPointer == 0xCF)
{
/* We are done! */
break;
}
}
/* Copy the registers back */
Registers->Eax = EmulatorContext.GeneralRegs[FAST486_REG_EAX].Long;
Registers->Ebx = EmulatorContext.GeneralRegs[FAST486_REG_EBX].Long;
Registers->Ecx = EmulatorContext.GeneralRegs[FAST486_REG_ECX].Long;
Registers->Edx = EmulatorContext.GeneralRegs[FAST486_REG_EDX].Long;
Registers->Esi = EmulatorContext.GeneralRegs[FAST486_REG_ESI].Long;
Registers->Edi = EmulatorContext.GeneralRegs[FAST486_REG_EDI].Long;
Registers->SegDs = EmulatorContext.SegmentRegs[FAST486_REG_DS].Selector;
Registers->SegEs = EmulatorContext.SegmentRegs[FAST486_REG_ES].Selector;
return TRUE;
}
#endif
BOOLEAN
NTAPI

View file

@ -156,6 +156,10 @@ HalInitSystem(IN ULONG BootPhase,
/* Do some HAL-specific initialization */
HalpInitPhase1();
#ifdef _M_AMD64
HalInitializeBios(0, LoaderBlock);
#endif
}
/* All done, return */

View file

@ -871,6 +871,14 @@ HalpInitProcessor(
);
#ifdef _M_AMD64
VOID
NTAPI
HalInitializeBios(
_In_ ULONG Unknown,
_In_ PLOADER_PARAMETER_BLOCK LoaderBlock
);
#define KfLowerIrql KeLowerIrql
#define KiEnterInterruptTrap(TrapFrame) /* We do all neccessary in asm code */
#define KiEoiHelper(TrapFrame) return /* Just return to the caller */