You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1315 lines
30 KiB
1315 lines
30 KiB
/*++
|
|
|
|
Copyright (c) 1994 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
x86bios.c
|
|
|
|
Abstract:
|
|
|
|
This module implements supplies the HAL interface to the 386/486
|
|
real mode emulator for the purpose of emulating BIOS calls..
|
|
|
|
Author:
|
|
|
|
David N. Cutler (davec) 13-Nov-1994
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "nthal.h"
|
|
#include "hal.h"
|
|
#include "xm86.h"
|
|
#include "x86new.h"
|
|
#include "pci.h"
|
|
|
|
//
|
|
// Define the size of low memory.
|
|
//
|
|
|
|
#define LOW_MEMORY_SIZE 0x800
|
|
|
|
//
|
|
// Define storage for low emulated memory.
|
|
//
|
|
|
|
UCHAR x86BiosLowMemory[LOW_MEMORY_SIZE + 3];
|
|
ULONG x86BiosScratchMemory;
|
|
|
|
//
|
|
// Define storage to capture the base address of I/O space, the base address
|
|
// of I/O memory space, and the base address of the video frame buffer.
|
|
//
|
|
|
|
ULONG_PTR x86BiosFrameBuffer;
|
|
ULONG_PTR x86BiosIoMemory;
|
|
ULONG_PTR x86BiosIoSpace;
|
|
|
|
//
|
|
// Define an area of storage to allow for buffer passing between the BIOS
|
|
// and native mode code.
|
|
//
|
|
|
|
ULONG_PTR x86BiosTransferMemory = 0;
|
|
ULONG x86BiosTransferLength = 0;
|
|
|
|
//
|
|
// Define BIOS initialized state.
|
|
//
|
|
|
|
BOOLEAN x86BiosInitialized = FALSE;
|
|
|
|
//
|
|
// Define storage for PCI BIOS initialization state.
|
|
//
|
|
|
|
UCHAR XmNumberPciBusses = 0;
|
|
BOOLEAN XmPciBiosPresent = FALSE;
|
|
PGETSETPCIBUSDATA XmGetPciData;
|
|
PGETSETPCIBUSDATA XmSetPciData;
|
|
|
|
|
|
ULONG XmPCIConfigAddress = 0; // Current Value of emulated PCI Address Port
|
|
|
|
ULONG
|
|
x86BiosReadPciAddressPort(
|
|
IN XM_OPERATION_DATATYPE DataType,
|
|
IN USHORT PortNumber
|
|
);
|
|
|
|
VOID
|
|
x86BiosWritePciAddressPort(
|
|
IN XM_OPERATION_DATATYPE DataType,
|
|
IN USHORT PortNumber,
|
|
IN ULONG Value
|
|
);
|
|
|
|
ULONG
|
|
x86BiosReadPciDataPort(
|
|
IN XM_OPERATION_DATATYPE DataType,
|
|
IN USHORT PortNumber
|
|
);
|
|
|
|
VOID
|
|
x86BiosWritePciDataPort(
|
|
IN XM_OPERATION_DATATYPE DataType,
|
|
IN USHORT PortNumber,
|
|
IN ULONG Value
|
|
);
|
|
|
|
ULONG
|
|
x86BiosReadIoSpace (
|
|
IN XM_OPERATION_DATATYPE DataType,
|
|
IN USHORT PortNumber
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function reads from emulated I/O space.
|
|
|
|
Arguments:
|
|
|
|
DataType - Supplies the datatype for the read operation.
|
|
|
|
PortNumber - Supplies the port number in I/O space to read from.
|
|
|
|
Return Value:
|
|
|
|
The value read from I/O space is returned as the function value.
|
|
|
|
N.B. If an aligned operation is specified, then the individual
|
|
bytes are read from the specified port one at a time and
|
|
assembled into the specified datatype.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG Result;
|
|
|
|
union {
|
|
PUCHAR Byte;
|
|
PUSHORT Word;
|
|
PULONG Long;
|
|
} u;
|
|
|
|
//
|
|
// If we have access to the HAL config space routines intercept accesses to
|
|
// the PCI Config Ports and emulate them.
|
|
//
|
|
|
|
if (XmPciBiosPresent) {
|
|
|
|
if ((PCI_TYPE1_ADDR_PORT <= PortNumber) &&
|
|
(PortNumber <= (PCI_TYPE1_ADDR_PORT + 3))) {
|
|
|
|
return x86BiosReadPciAddressPort(DataType,
|
|
PortNumber - PCI_TYPE1_ADDR_PORT);
|
|
|
|
} else if ((XmPCIConfigAddress & (1 << 31)) &&
|
|
(PCI_TYPE1_DATA_PORT <= PortNumber) &&
|
|
(PortNumber <= (PCI_TYPE1_DATA_PORT + 3))) {
|
|
|
|
return x86BiosReadPciDataPort(DataType,
|
|
PortNumber - PCI_TYPE1_DATA_PORT);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Compute port address and read port.
|
|
//
|
|
|
|
u.Long = (PULONG)(x86BiosIoSpace + PortNumber);
|
|
if (DataType == BYTE_DATA) {
|
|
Result = READ_PORT_UCHAR(u.Byte);
|
|
|
|
} else if (DataType == LONG_DATA) {
|
|
if (((ULONG_PTR)u.Long & 0x3) != 0) {
|
|
Result = (READ_PORT_UCHAR(u.Byte + 0)) |
|
|
(READ_PORT_UCHAR(u.Byte + 1) << 8) |
|
|
(READ_PORT_UCHAR(u.Byte + 2) << 16) |
|
|
(READ_PORT_UCHAR(u.Byte + 3) << 24);
|
|
|
|
} else {
|
|
Result = READ_PORT_ULONG(u.Long);
|
|
}
|
|
|
|
} else {
|
|
if (((ULONG_PTR)u.Word & 0x1) != 0) {
|
|
Result = (READ_PORT_UCHAR(u.Byte + 0)) |
|
|
(READ_PORT_UCHAR(u.Byte + 1) << 8);
|
|
|
|
} else {
|
|
Result = READ_PORT_USHORT(u.Word);
|
|
}
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
VOID
|
|
x86BiosWriteIoSpace (
|
|
IN XM_OPERATION_DATATYPE DataType,
|
|
IN USHORT PortNumber,
|
|
IN ULONG Value
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function write to emulated I/O space.
|
|
|
|
N.B. If an aligned operation is specified, then the individual
|
|
bytes are written to the specified port one at a time.
|
|
|
|
Arguments:
|
|
|
|
DataType - Supplies the datatype for the write operation.
|
|
|
|
PortNumber - Supplies the port number in I/O space to write to.
|
|
|
|
Value - Supplies the value to write.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
union {
|
|
PUCHAR Byte;
|
|
PUSHORT Word;
|
|
PULONG Long;
|
|
} u;
|
|
|
|
//
|
|
// If we have access to the HAL config space routines intercept accesses to
|
|
// the PCI Config Ports and emulate them.
|
|
//
|
|
|
|
if (XmPciBiosPresent) {
|
|
|
|
if ((PCI_TYPE1_ADDR_PORT <= PortNumber) &&
|
|
(PortNumber <= (PCI_TYPE1_ADDR_PORT + 3))) {
|
|
|
|
x86BiosWritePciAddressPort(DataType,
|
|
PortNumber - PCI_TYPE1_ADDR_PORT,
|
|
Value);
|
|
return;
|
|
|
|
} else if ((XmPCIConfigAddress & (1 << 31)) &&
|
|
(PCI_TYPE1_DATA_PORT <= PortNumber) &&
|
|
(PortNumber <= (PCI_TYPE1_DATA_PORT + 3))) {
|
|
|
|
x86BiosWritePciDataPort(DataType,
|
|
PortNumber - PCI_TYPE1_DATA_PORT,
|
|
Value);
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Compute port address and read port.
|
|
//
|
|
|
|
u.Long = (PULONG)(x86BiosIoSpace + PortNumber);
|
|
if (DataType == BYTE_DATA) {
|
|
WRITE_PORT_UCHAR(u.Byte, (UCHAR)Value);
|
|
|
|
} else if (DataType == LONG_DATA) {
|
|
if (((ULONG_PTR)u.Long & 0x3) != 0) {
|
|
WRITE_PORT_UCHAR(u.Byte + 0, (UCHAR)(Value));
|
|
WRITE_PORT_UCHAR(u.Byte + 1, (UCHAR)(Value >> 8));
|
|
WRITE_PORT_UCHAR(u.Byte + 2, (UCHAR)(Value >> 16));
|
|
WRITE_PORT_UCHAR(u.Byte + 3, (UCHAR)(Value >> 24));
|
|
|
|
} else {
|
|
WRITE_PORT_ULONG(u.Long, Value);
|
|
}
|
|
|
|
} else {
|
|
if (((ULONG_PTR)u.Word & 0x1) != 0) {
|
|
WRITE_PORT_UCHAR(u.Byte + 0, (UCHAR)(Value));
|
|
WRITE_PORT_UCHAR(u.Byte + 1, (UCHAR)(Value >> 8));
|
|
|
|
} else {
|
|
WRITE_PORT_USHORT(u.Word, (USHORT)Value);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
PVOID
|
|
x86BiosTranslateAddress (
|
|
IN USHORT Segment,
|
|
IN USHORT Offset
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This translates a segment/offset address into a memory address.
|
|
|
|
Arguments:
|
|
|
|
Segment - Supplies the segment register value.
|
|
|
|
Offset - Supplies the offset within segment.
|
|
|
|
Return Value:
|
|
|
|
The memory address of the translated segment/offset pair is
|
|
returned as the function value.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG Value;
|
|
|
|
//
|
|
// Compute the logical memory address and case on high hex digit of
|
|
// the resultant address.
|
|
//
|
|
|
|
Value = Offset + (Segment << 4);
|
|
Offset = (USHORT)(Value & 0xffff);
|
|
Value &= 0xf0000;
|
|
switch ((Value >> 16) & 0xf) {
|
|
|
|
//
|
|
// Interrupt vector/stack space.
|
|
//
|
|
|
|
case 0x0:
|
|
if (Offset > LOW_MEMORY_SIZE) {
|
|
x86BiosScratchMemory = 0;
|
|
return (PVOID)&x86BiosScratchMemory;
|
|
|
|
} else {
|
|
return (PVOID)(&x86BiosLowMemory[0] + Offset);
|
|
}
|
|
|
|
//
|
|
// The memory range from 0x10000 to 0x8ffff reads as zero
|
|
// and writes are ignored.
|
|
//
|
|
|
|
case 0x1:
|
|
case 0x3:
|
|
case 0x4:
|
|
case 0x5:
|
|
case 0x6:
|
|
case 0x7:
|
|
case 0x8:
|
|
x86BiosScratchMemory = 0;
|
|
return (PVOID)&x86BiosScratchMemory;
|
|
|
|
case 0x9:
|
|
//
|
|
// BUGBUG: Found a VGA adapter loaded in segment 9
|
|
// Emulator assumptions about video adapters needs to be
|
|
// looked at
|
|
//
|
|
return (PVOID)(x86BiosIoMemory + Offset + Value);
|
|
|
|
//
|
|
// The memory range from 0x20000 to 0x20fff is used to transfer
|
|
// buffers between native mode and emulated mode.
|
|
//
|
|
|
|
case 0x2:
|
|
if (Offset < x86BiosTransferLength) {
|
|
return (PVOID)(x86BiosTransferMemory + Offset);
|
|
} else {
|
|
x86BiosScratchMemory = 0;
|
|
return (PVOID)&x86BiosScratchMemory;
|
|
}
|
|
|
|
//
|
|
// The memory range from 0xa0000 to 0xbffff maps to the
|
|
// framebuffer if previously specified, otherwise I/O memory.
|
|
//
|
|
|
|
case 0xa:
|
|
case 0xb:
|
|
if (x86BiosFrameBuffer != 0) {
|
|
return (PVOID)(x86BiosFrameBuffer + Offset + Value);
|
|
}
|
|
|
|
//
|
|
// The memory range from 0xc0000 to 0xfffff maps to I/O memory
|
|
//
|
|
|
|
case 0xc:
|
|
case 0xd:
|
|
case 0xe:
|
|
case 0xf:
|
|
return (PVOID)(x86BiosIoMemory + Offset + Value);
|
|
|
|
DEFAULT_UNREACHABLE;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
x86BiosInitializeBios (
|
|
IN PVOID BiosIoSpace,
|
|
IN PVOID BiosIoMemory
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function initializes x86 BIOS emulation.
|
|
|
|
Arguments:
|
|
|
|
BiosIoSpace - Supplies the base address of the I/O space to be used
|
|
for BIOS emulation.
|
|
|
|
BiosIoMemory - Supplies the base address of the I/O memory to be
|
|
used for BIOS emulation.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Initialize x86 BIOS emulation.
|
|
//
|
|
|
|
x86BiosInitializeBiosShadowed(BiosIoSpace,
|
|
BiosIoMemory,
|
|
NULL);
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
x86BiosInitializeBiosEx (
|
|
IN PVOID BiosIoSpace,
|
|
IN PVOID BiosIoMemory,
|
|
IN PVOID BiosFrameBuffer,
|
|
IN PVOID BiosTransferMemory,
|
|
IN ULONG TransferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function initializes x86 BIOS emulation.
|
|
|
|
Arguments:
|
|
|
|
BiosIoSpace - Supplies the base address of the I/O space to be used
|
|
for BIOS emulation.
|
|
|
|
BiosIoMemory - Supplies the base address of the I/O memory to be
|
|
used for BIOS emulation.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Initialize x86 BIOS emulation.
|
|
//
|
|
|
|
x86BiosInitializeBiosShadowed(BiosIoSpace,
|
|
BiosIoMemory,
|
|
BiosFrameBuffer
|
|
);
|
|
|
|
x86BiosTransferMemory = (ULONG_PTR)BiosTransferMemory;
|
|
x86BiosTransferLength = TransferLength;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
x86BiosInitializeBiosShadowed (
|
|
IN PVOID BiosIoSpace,
|
|
IN PVOID BiosIoMemory,
|
|
IN PVOID BiosFrameBuffer
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function initializes x86 BIOS emulation.
|
|
|
|
Arguments:
|
|
|
|
BiosIoSpace - Supplies the base address of the I/O space to be used
|
|
for BIOS emulation.
|
|
|
|
BiosIoMemory - Supplies the base address of the I/O memory to be
|
|
used for BIOS emulation.
|
|
|
|
BiosFrameBuffer - Supplies the base address of the video frame buffer
|
|
to be used for bios emulation.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Zero low memory.
|
|
//
|
|
|
|
memset(&x86BiosLowMemory, 0, LOW_MEMORY_SIZE);
|
|
|
|
//
|
|
// Save base address of I/O memory and I/O space.
|
|
//
|
|
|
|
x86BiosIoSpace = (ULONG_PTR)BiosIoSpace;
|
|
x86BiosIoMemory = (ULONG_PTR)BiosIoMemory;
|
|
x86BiosFrameBuffer = (ULONG_PTR)BiosFrameBuffer;
|
|
|
|
//
|
|
// Initialize the emulator and the BIOS.
|
|
//
|
|
|
|
XmInitializeEmulator(0,
|
|
LOW_MEMORY_SIZE,
|
|
x86BiosReadIoSpace,
|
|
x86BiosWriteIoSpace,
|
|
x86BiosTranslateAddress);
|
|
|
|
x86BiosInitialized = TRUE;
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
x86BiosInitializeBiosShadowedPci (
|
|
IN PVOID BiosIoSpace,
|
|
IN PVOID BiosIoMemory,
|
|
IN PVOID BiosFrameBuffer,
|
|
IN UCHAR NumberPciBusses,
|
|
IN PGETSETPCIBUSDATA GetPciData,
|
|
IN PGETSETPCIBUSDATA SetPciData
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function initializes x86 BIOS emulation and also sets up the
|
|
emulator with BIOS shadowed and PCI functions enabled. Since the
|
|
PCI specification requires BIOS shadowing, there isn't any need
|
|
to provide a function that turns on the PCI functions, but doesn't
|
|
shadow the BIOS.
|
|
|
|
Arguments:
|
|
|
|
BiosIoSpace - Supplies the base address of the I/O space to be used
|
|
for BIOS emulation.
|
|
|
|
BiosIoMemory - Supplies the base address of the I/O memory to be
|
|
used for BIOS emulation.
|
|
|
|
BiosFrameBuffer - Supplies the base address of the video frame buffer
|
|
to be used for bios emulation.
|
|
|
|
NumberPciBusses - Supplies the number of PCI busses in the system.
|
|
|
|
GetPciData - Supplies the address of a function to read the PCI
|
|
configuration space.
|
|
|
|
SetPciData - Supplies the address of a function to write the PCI
|
|
configuration space.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Enable PCI BIOS support.
|
|
//
|
|
|
|
XmPciBiosPresent = TRUE;
|
|
XmGetPciData = GetPciData;
|
|
XmSetPciData = SetPciData;
|
|
XmNumberPciBusses = NumberPciBusses;
|
|
|
|
//
|
|
// Initialize x86 BIOS emulation.
|
|
//
|
|
|
|
x86BiosInitializeBiosShadowed(BiosIoSpace,
|
|
BiosIoMemory,
|
|
BiosFrameBuffer);
|
|
|
|
return;
|
|
}
|
|
|
|
XM_STATUS
|
|
x86BiosExecuteInterrupt (
|
|
IN UCHAR Number,
|
|
IN OUT PXM86_CONTEXT Context,
|
|
IN PVOID BiosIoSpace OPTIONAL,
|
|
IN PVOID BiosIoMemory OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function executes an interrupt by calling the x86 emulator.
|
|
|
|
Arguments:
|
|
|
|
Number - Supplies the number of the interrupt that is to be emulated.
|
|
|
|
Context - Supplies a pointer to an x86 context structure.
|
|
|
|
BiosIoSpace - Supplies an optional base address of the I/O space
|
|
to be used for BIOS emulation.
|
|
|
|
BiosIoMemory - Supplies an optional base address of the I/O memory
|
|
to be used for BIOS emulation.
|
|
|
|
Return Value:
|
|
|
|
The emulation completion status.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Execute x86 interrupt.
|
|
//
|
|
|
|
return x86BiosExecuteInterruptShadowed(Number,
|
|
Context,
|
|
BiosIoSpace,
|
|
BiosIoMemory,
|
|
NULL);
|
|
}
|
|
|
|
XM_STATUS
|
|
x86BiosExecuteInterruptShadowed (
|
|
IN UCHAR Number,
|
|
IN OUT PXM86_CONTEXT Context,
|
|
IN PVOID BiosIoSpace OPTIONAL,
|
|
IN PVOID BiosIoMemory OPTIONAL,
|
|
IN PVOID BiosFrameBuffer OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function executes an interrupt by calling the x86 emulator.
|
|
|
|
Arguments:
|
|
|
|
Number - Supplies the number of the interrupt that is to be emulated.
|
|
|
|
Context - Supplies a pointer to an x86 context structure.
|
|
|
|
BiosIoSpace - Supplies an optional base address of the I/O space
|
|
to be used for BIOS emulation.
|
|
|
|
BiosIoMemory - Supplies an optional base address of the I/O memory
|
|
to be used for BIOS emulation.
|
|
|
|
BiosFrameBuffer - Supplies an optional base address of the video
|
|
frame buffer to be used for bios emulation.
|
|
|
|
Return Value:
|
|
|
|
The emulation completion status.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
XM_STATUS Status;
|
|
|
|
//
|
|
// If a new base address is specified, then set the appropriate base.
|
|
//
|
|
|
|
if (BiosIoSpace != NULL) {
|
|
x86BiosIoSpace = (ULONG_PTR)BiosIoSpace;
|
|
}
|
|
|
|
if (BiosIoMemory != NULL) {
|
|
x86BiosIoMemory = (ULONG_PTR)BiosIoMemory;
|
|
}
|
|
|
|
if (BiosFrameBuffer != NULL) {
|
|
x86BiosFrameBuffer = (ULONG_PTR)BiosFrameBuffer;
|
|
}
|
|
|
|
//
|
|
// Execute the specified interrupt.
|
|
//
|
|
|
|
Status = XmEmulateInterrupt(Number, Context);
|
|
if (Status != XM_SUCCESS) {
|
|
DbgPrint("HAL: Interrupt emulation failed, status %lx\n", Status);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
XM_STATUS
|
|
x86BiosExecuteInterruptShadowedPci (
|
|
IN UCHAR Number,
|
|
IN OUT PXM86_CONTEXT Context,
|
|
IN PVOID BiosIoSpace OPTIONAL,
|
|
IN PVOID BiosIoMemory OPTIONAL,
|
|
IN PVOID BiosFrameBuffer OPTIONAL,
|
|
IN UCHAR NumberPciBusses,
|
|
IN PGETSETPCIBUSDATA GetPciData,
|
|
IN PGETSETPCIBUSDATA SetPciData
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function executes an interrupt by calling the x86 emulator.
|
|
|
|
Arguments:
|
|
|
|
Number - Supplies the number of the interrupt that is to be emulated.
|
|
|
|
Context - Supplies a pointer to an x86 context structure.
|
|
|
|
BiosIoSpace - Supplies an optional base address of the I/O space
|
|
to be used for BIOS emulation.
|
|
|
|
BiosIoMemory - Supplies an optional base address of the I/O memory
|
|
to be used for BIOS emulation.
|
|
|
|
NumberPciBusses - Supplies the number of PCI busses in the system.
|
|
|
|
GetPciData - Supplies the address of a function to read the PCI
|
|
configuration space.
|
|
|
|
SetPciData - Supplies the address of a function to write the PCI
|
|
configuration space.
|
|
|
|
Return Value:
|
|
|
|
The emulation completion status.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Enable PCI BIOS support.
|
|
//
|
|
|
|
XmPciBiosPresent = TRUE;
|
|
XmGetPciData = GetPciData;
|
|
XmSetPciData = SetPciData;
|
|
XmNumberPciBusses = NumberPciBusses;
|
|
|
|
//
|
|
// Execute x86 interrupt.
|
|
//
|
|
|
|
return x86BiosExecuteInterruptShadowed(Number,
|
|
Context,
|
|
BiosIoSpace,
|
|
BiosIoMemory,
|
|
BiosFrameBuffer);
|
|
}
|
|
|
|
XM_STATUS
|
|
x86BiosInitializeAdapter(
|
|
IN ULONG Adapter,
|
|
IN OUT PXM86_CONTEXT Context OPTIONAL,
|
|
IN PVOID BiosIoSpace OPTIONAL,
|
|
IN PVOID BiosIoMemory OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function initializes the adapter whose BIOS starts at the
|
|
specified 20-bit address.
|
|
|
|
Arguments:
|
|
|
|
Adpater - Supplies the 20-bit address of the BIOS for the adapter
|
|
to be initialized.
|
|
|
|
Return Value:
|
|
|
|
The emulation completion status.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Initialize the specified adapter.
|
|
//
|
|
|
|
return x86BiosInitializeAdapterShadowed(Adapter,
|
|
Context,
|
|
BiosIoSpace,
|
|
BiosIoMemory,
|
|
NULL);
|
|
}
|
|
|
|
XM_STATUS
|
|
x86BiosInitializeAdapterShadowed (
|
|
IN ULONG Adapter,
|
|
IN OUT PXM86_CONTEXT Context OPTIONAL,
|
|
IN PVOID BiosIoSpace OPTIONAL,
|
|
IN PVOID BiosIoMemory OPTIONAL,
|
|
IN PVOID BiosFrameBuffer OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function initializes the adapter whose BIOS starts at the
|
|
specified 20-bit address.
|
|
|
|
Arguments:
|
|
|
|
Adpater - Supplies the 20-bit address of the BIOS for the adapter
|
|
to be initialized.
|
|
|
|
Return Value:
|
|
|
|
The emulation completion status.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PUCHAR Byte;
|
|
XM86_CONTEXT State;
|
|
USHORT Offset;
|
|
USHORT Segment;
|
|
XM_STATUS Status;
|
|
|
|
//
|
|
// If BIOS emulation has not been initialized, then return an error.
|
|
//
|
|
|
|
if (x86BiosInitialized == FALSE) {
|
|
return XM_EMULATOR_NOT_INITIALIZED;
|
|
}
|
|
|
|
//
|
|
// If an emulator context is not specified, then use a default
|
|
// context.
|
|
//
|
|
|
|
if (ARGUMENT_PRESENT(Context) == FALSE) {
|
|
State.Eax = 0;
|
|
State.Ecx = 0;
|
|
State.Edx = 0;
|
|
State.Ebx = 0;
|
|
State.Ebp = 0;
|
|
State.Esi = 0;
|
|
State.Edi = 0;
|
|
Context = &State;
|
|
}
|
|
|
|
//
|
|
// If a new base address is specified, then set the appropriate base.
|
|
//
|
|
|
|
if (BiosIoSpace != NULL) {
|
|
x86BiosIoSpace = (ULONG_PTR)BiosIoSpace;
|
|
}
|
|
|
|
if (BiosIoMemory != NULL) {
|
|
x86BiosIoMemory = (ULONG_PTR)BiosIoMemory;
|
|
}
|
|
|
|
if (BiosFrameBuffer != NULL) {
|
|
x86BiosFrameBuffer = (ULONG_PTR)BiosFrameBuffer;
|
|
}
|
|
|
|
//
|
|
// If the specified adpater is not BIOS code, then return an error.
|
|
//
|
|
|
|
Segment = (USHORT)((Adapter >> 4) & 0xf000);
|
|
Offset = (USHORT)(Adapter & 0xffff);
|
|
Byte = (PUCHAR)x86BiosTranslateAddress(Segment, Offset);
|
|
|
|
if ((*Byte++ != 0x55) || (*Byte != 0xaa)) {
|
|
return XM_ILLEGAL_CODE_SEGMENT;
|
|
}
|
|
|
|
//
|
|
// Call the BIOS code to initialize the specified adapter.
|
|
//
|
|
|
|
Adapter += 3;
|
|
Segment = (USHORT)((Adapter >> 4) & 0xf000);
|
|
Offset = (USHORT)(Adapter & 0xffff);
|
|
Status = XmEmulateFarCall(Segment, Offset, Context);
|
|
if (Status != XM_SUCCESS) {
|
|
DbgPrint("HAL: Adapter initialization falied, status %lx\n", Status);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
XM_STATUS
|
|
x86BiosInitializeAdapterShadowedPci(
|
|
IN ULONG Adapter,
|
|
IN OUT PXM86_CONTEXT Context OPTIONAL,
|
|
IN PVOID BiosIoSpace OPTIONAL,
|
|
IN PVOID BiosIoMemory OPTIONAL,
|
|
IN PVOID BiosFrameBuffer OPTIONAL,
|
|
IN UCHAR NumberPciBusses,
|
|
IN PGETSETPCIBUSDATA GetPciData,
|
|
IN PGETSETPCIBUSDATA SetPciData
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function initializes the adapter whose BIOS starts at the
|
|
specified 20-bit address.
|
|
|
|
Arguments:
|
|
|
|
Adpater - Supplies the 20-bit address of the BIOS for the adapter
|
|
to be initialized.
|
|
|
|
Return Value:
|
|
|
|
The emulation completion status.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Enable PCI BIOS support.
|
|
//
|
|
|
|
XmPciBiosPresent = TRUE;
|
|
XmGetPciData = GetPciData;
|
|
XmSetPciData = SetPciData;
|
|
XmNumberPciBusses = NumberPciBusses;
|
|
|
|
//
|
|
// Initialize the specified adapter.
|
|
//
|
|
|
|
return x86BiosInitializeAdapterShadowed(Adapter,
|
|
Context,
|
|
BiosIoSpace,
|
|
BiosIoMemory,
|
|
BiosFrameBuffer);
|
|
}
|
|
|
|
ULONG
|
|
x86BiosReadPciAddressPort(
|
|
IN XM_OPERATION_DATATYPE DataType,
|
|
IN USHORT PortNumber
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function reads from emulated I/O space.
|
|
|
|
Arguments:
|
|
|
|
DataType - Supplies the datatype for the read operation.
|
|
|
|
PortNumber - Supplies the port number in I/O space to read from.
|
|
|
|
Return Value:
|
|
|
|
The value read from I/O space is returned as the function value.
|
|
|
|
N.B. If an aligned operation is specified, then the individual
|
|
bytes are read from the specified port one at a time and
|
|
assembled into the specified datatype.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG Result;
|
|
|
|
//
|
|
// We assume that DataType is the number of bytes - 1. If this ever changes
|
|
// then this routine needs to be rewritten.
|
|
//
|
|
C_ASSERT(BYTE_DATA == 0);
|
|
C_ASSERT(WORD_DATA == 1);
|
|
C_ASSERT(LONG_DATA == 3);
|
|
|
|
//
|
|
// If we don't have access to the HAL config space routines just return 0.
|
|
//
|
|
if (!XmPciBiosPresent) {
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Make sure they aren't trying to read past the end of the register, we'll
|
|
// fill any extra bytes with zeroes.
|
|
//
|
|
|
|
if ((PortNumber + DataType) > 3) {
|
|
|
|
ASSERT(0);
|
|
DataType = 3 - PortNumber;
|
|
}
|
|
|
|
//
|
|
// Compute port address and read port.
|
|
//
|
|
|
|
switch (DataType) {
|
|
|
|
case BYTE_DATA:
|
|
Result = (ULONG)*(((PUCHAR)&XmPCIConfigAddress) + PortNumber);
|
|
break;
|
|
|
|
case WORD_DATA:
|
|
Result = (ULONG)*(USHORT UNALIGNED *)(((PUCHAR)&XmPCIConfigAddress) + PortNumber);
|
|
break;
|
|
|
|
case 2: // Special case that results from reading 4 bytes starting at port CF9
|
|
Result = (ULONG)*(USHORT UNALIGNED *)(((PUCHAR)&XmPCIConfigAddress) + PortNumber);
|
|
Result |= ((ULONG)*(((PUCHAR)&XmPCIConfigAddress) + 3)) << 16;
|
|
break;
|
|
|
|
case LONG_DATA:
|
|
ASSERT(PortNumber == 0);
|
|
Result = (ULONG)XmPCIConfigAddress;
|
|
break;
|
|
|
|
default:
|
|
ASSERT(0);
|
|
Result = 0;
|
|
break;
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
VOID
|
|
x86BiosWritePciAddressPort(
|
|
IN XM_OPERATION_DATATYPE DataType,
|
|
IN USHORT PortNumber,
|
|
IN ULONG Value
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function write to emulated I/O space.
|
|
|
|
N.B. If an aligned operation is specified, then the individual
|
|
bytes are written to the specified port one at a time.
|
|
|
|
Arguments:
|
|
|
|
DataType - Supplies the datatype for the write operation.
|
|
|
|
PortNumber - Supplies the port number in I/O space to write to.
|
|
|
|
Value - Supplies the value to write.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// We assume that DataType is the number of bytes - 1. If this ever changes
|
|
// then this routine needs to be rewritten.
|
|
//
|
|
C_ASSERT(BYTE_DATA == 0);
|
|
C_ASSERT(WORD_DATA == 1);
|
|
C_ASSERT(LONG_DATA == 3);
|
|
|
|
//
|
|
// If we don't have access to the HAL config space routines just ignore.
|
|
//
|
|
if (!XmPciBiosPresent) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Make sure they aren't trying to write past the end of the register, we'll
|
|
// ignore any extra bytes.
|
|
//
|
|
|
|
if ((PortNumber + DataType) > 3) {
|
|
|
|
ASSERT(0);
|
|
DataType = 3 - PortNumber;
|
|
}
|
|
|
|
//
|
|
// Compute port address and write port.
|
|
//
|
|
|
|
switch (DataType) {
|
|
|
|
case BYTE_DATA:
|
|
*(((PUCHAR)&XmPCIConfigAddress) + PortNumber) = (UCHAR)Value;
|
|
break;
|
|
|
|
case WORD_DATA:
|
|
*(USHORT UNALIGNED *)(((PUCHAR)&XmPCIConfigAddress) + PortNumber) = (USHORT)Value;
|
|
break;
|
|
|
|
case 2: // Special case that results from reading 4 bytes starting at port CF9
|
|
*(USHORT UNALIGNED *)(((PUCHAR)&XmPCIConfigAddress) + PortNumber) = (USHORT)Value;
|
|
*(((PUCHAR)&XmPCIConfigAddress) + 3) = (UCHAR)(Value >> 16);
|
|
break;
|
|
|
|
case LONG_DATA:
|
|
ASSERT(PortNumber == 0);
|
|
XmPCIConfigAddress = Value;
|
|
break;
|
|
|
|
default:
|
|
ASSERT(0);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Clean up low order two bits, these are forced to zero in the real
|
|
// hardware.
|
|
//
|
|
|
|
XmPCIConfigAddress &= ~0x3;
|
|
|
|
return;
|
|
}
|
|
|
|
ULONG
|
|
x86BiosReadPciDataPort(
|
|
IN XM_OPERATION_DATATYPE DataType,
|
|
IN USHORT PortNumber
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function reads from emulated I/O space.
|
|
|
|
Arguments:
|
|
|
|
DataType - Supplies the datatype for the read operation.
|
|
|
|
PortNumber - Supplies the port number in I/O space to read from.
|
|
|
|
Return Value:
|
|
|
|
The value read from I/O space is returned as the function value.
|
|
|
|
N.B. If an aligned operation is specified, then the individual
|
|
bytes are read from the specified port one at a time and
|
|
assembled into the specified datatype.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG Result;
|
|
PCI_SLOT_NUMBER Slot;
|
|
|
|
//
|
|
// We assume that DataType is the number of bytes - 1. If this ever changes
|
|
// then this routine needs to be rewritten.
|
|
//
|
|
C_ASSERT(BYTE_DATA == 0);
|
|
C_ASSERT(WORD_DATA == 1);
|
|
C_ASSERT(LONG_DATA == 3);
|
|
|
|
//
|
|
// Make sure they aren't trying to read past the end of the register, we'll
|
|
// ignore any extra bytes.
|
|
//
|
|
|
|
if ((PortNumber + DataType) > 3) {
|
|
|
|
ASSERT(0);
|
|
DataType = 3 - PortNumber;
|
|
}
|
|
|
|
//
|
|
// Unpack the Slot/Function information
|
|
//
|
|
Slot.u.AsULONG = 0;
|
|
Slot.u.bits.DeviceNumber = (XmPCIConfigAddress >> 11) & 0x1F;
|
|
Slot.u.bits.FunctionNumber = (XmPCIConfigAddress >> 8) & 0x07;
|
|
|
|
if (XmGetPciData((XmPCIConfigAddress >> 16) & 0xFF, // Bus Number
|
|
Slot.u.AsULONG, // Device, Function
|
|
&Result,
|
|
(XmPCIConfigAddress & 0xFF) | PortNumber, // Offset
|
|
DataType + 1 // Length
|
|
) == 0)
|
|
{
|
|
Result = (ULONG)(1 << ((DataType + 1) << 3)) - 1;
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
VOID
|
|
x86BiosWritePciDataPort(
|
|
IN XM_OPERATION_DATATYPE DataType,
|
|
IN USHORT PortNumber,
|
|
IN ULONG Value
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function write to emulated I/O space.
|
|
|
|
N.B. If an aligned operation is specified, then the individual
|
|
bytes are written to the specified port one at a time.
|
|
|
|
Arguments:
|
|
|
|
DataType - Supplies the datatype for the write operation.
|
|
|
|
PortNumber - Supplies the port number in I/O space to write to.
|
|
|
|
Value - Supplies the value to write.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PCI_SLOT_NUMBER Slot;
|
|
|
|
//
|
|
// We assume that DataType is the number of bytes - 1. If this ever changes
|
|
// then this routine needs to be rewritten.
|
|
//
|
|
C_ASSERT(BYTE_DATA == 0);
|
|
C_ASSERT(WORD_DATA == 1);
|
|
C_ASSERT(LONG_DATA == 3);
|
|
|
|
//
|
|
// Make sure they aren't trying to write past the end of the register, we'll
|
|
// ignore any extra bytes.
|
|
//
|
|
|
|
if ((PortNumber + DataType) > 3) {
|
|
|
|
ASSERT(0);
|
|
DataType = 3 - PortNumber;
|
|
}
|
|
|
|
//
|
|
// Unpack the Slot/Function information
|
|
//
|
|
Slot.u.AsULONG = 0;
|
|
Slot.u.bits.DeviceNumber = (XmPCIConfigAddress >> 11) & 0x1F;
|
|
Slot.u.bits.FunctionNumber = (XmPCIConfigAddress >> 8) & 0x07;
|
|
|
|
if (XmSetPciData((XmPCIConfigAddress >> 16) & 0xFF, // Bus Number
|
|
Slot.u.AsULONG, // Device, Function
|
|
&Value,
|
|
(XmPCIConfigAddress & 0xFF) | PortNumber, // Offset
|
|
DataType + 1 // Length
|
|
) == 0)
|
|
{
|
|
ASSERT(0);
|
|
}
|
|
}
|