https://git.reactos.org/?p=reactos.git;a=commitdiff;h=9ab3246d4368eb8498ccb…
commit 9ab3246d4368eb8498ccb01a4359161e4c36ef7a
Author: Timo Kreuzer <timo.kreuzer(a)reactos.org>
AuthorDate: Sun Feb 11 19:21:01 2018 +0100
Commit: Timo Kreuzer <timo.kreuzer(a)reactos.org>
CommitDate: Thu Aug 15 14:13:54 2019 +0200
[HAL] Implement amd64 BIOS call support
The code uses FAST486 to emulate the BIOS code.
---
hal/hal.spec | 14 +--
hal/halx86/CMakeLists.txt | 4 +-
hal/halx86/amd64/x86bios.c | 280 +++++++++++++++++++++++++++++++++++--------
hal/halx86/generic/halinit.c | 4 +
hal/halx86/include/halp.h | 8 ++
5 files changed, 255 insertions(+), 55 deletions(-)
diff --git a/hal/hal.spec b/hal/hal.spec
index bfe55fa6b8e..4f8e0bec939 100644
--- a/hal/hal.spec
+++ b/hal/hal.spec
@@ -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()
diff --git a/hal/halx86/CMakeLists.txt b/hal/halx86/CMakeLists.txt
index 831131494ec..f4148eb5ec0 100644
--- a/hal/halx86/CMakeLists.txt
+++ b/hal/halx86/CMakeLists.txt
@@ -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()
diff --git a/hal/halx86/amd64/x86bios.c b/hal/halx86/amd64/x86bios.c
index 88f52421b7b..a8b7d94bc6c 100644
--- a/hal/halx86/amd64/x86bios.c
+++ b/hal/halx86/amd64/x86bios.c
@@ -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;
-
- /* Zero the VmState */
- RtlZeroMemory(&VmState, sizeof(VmState));
+ } *Ivt;
+ ULONG FlatIp;
+ PUCHAR InstructionPointer;
+
+ /* 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
diff --git a/hal/halx86/generic/halinit.c b/hal/halx86/generic/halinit.c
index 002605deb9f..90183d1fb4f 100644
--- a/hal/halx86/generic/halinit.c
+++ b/hal/halx86/generic/halinit.c
@@ -156,6 +156,10 @@ HalInitSystem(IN ULONG BootPhase,
/* Do some HAL-specific initialization */
HalpInitPhase1();
+
+#ifdef _M_AMD64
+ HalInitializeBios(0, LoaderBlock);
+#endif
}
/* All done, return */
diff --git a/hal/halx86/include/halp.h b/hal/halx86/include/halp.h
index 190bfe84636..9c03a96f43d 100644
--- a/hal/halx86/include/halp.h
+++ b/hal/halx86/include/halp.h
@@ -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 */