// #pragma comment(exestr, "@(#) x86bios.c 1.1 95/09/28 18:40:12 nec") /*++ Copyright (c) 1994 Microsoft Corporation Module Name: x86bios.c Abstract: This module implements the platform specific interface between a device driver and the execution of x86 ROM bios code for the device. Author: David N. Cutler (davec) 17-Jun-1994 Environment: Kernel mode only. Revision History: M001 kuriyama@oa2.kb.nec.co.jp Tue Jul 18 15:45:09 JST 1995 - add check intel based bios flag M002 kuriyama@oa2.kb.nec.co.jp Thu Jul 20 15:16:52 JST 1995 - add for DPI support (NO PCI DATA structure) S003 kuriyama@oa2.kb.nec.co.jp Tue Aug 15 14:09:30 JST 1995 - bug fix for canopus PowerWindows 864PCI --*/ #define USE_BIOS_EMULATOR #include "halp.h" #include "pci.h" #include "pcip.h" #include "xm86.h" #include "x86new.h" VOID HalpReadPCIConfigUlongByOffset ( IN PCI_SLOT_NUMBER Slot, IN PULONG Buffer, IN ULONG Offset ); VOID HalpWritePCIConfigUlongByOffset ( IN PCI_SLOT_NUMBER Slot, IN PULONG Buffer, IN ULONG Offset ); VOID HalpReadPCIConfigUshortByOffset ( IN PCI_SLOT_NUMBER Slot, IN PSHORT Buffer, IN ULONG Offset ); VOID HalpWritePCIConfigUshortByOffset ( IN PCI_SLOT_NUMBER Slot, IN PSHORT Buffer, IN ULONG Offset ); // M001 +++ VOID HalpReadPCIConfigUcharByOffset ( IN PCI_SLOT_NUMBER Slot, IN PUCHAR Buffer, IN ULONG Offset ); VOID HalpWritePCIConfigUcharByOffset ( IN PCI_SLOT_NUMBER Slot, IN PUCHAR Buffer, IN ULONG Offset ); // M001 --- // // Define global data. // ULONG HalpX86BiosInitialized = FALSE; ULONG HalpEnableInt10Calls = FALSE; PVOID HalpIoMemoryBase = NULL; PVOID HalpIoControlBase=NULL; PUCHAR HalpRomBase = NULL; ULONG ROM_Length; #define BUFFER_SIZE (64*1024) UCHAR ROM_Buffer[BUFFER_SIZE]; //#define R98_PCICONFIG_START ((PULONG)(0x18ca8800 | KSEG1_BASE)) extern KSPIN_LOCK HalpPCIConfigLock; BOOLEAN HalpInitX86Emulator( VOID) { ULONG ROM_size = 0; PHYSICAL_ADDRESS PhysAddr; UCHAR BaseClass, SubClass, ProgIf;// M001 USHORT Cmd,SetCmd, VendorID, DeviceID, Slot; // M002 PUCHAR ROM_Ptr, ROM_Shadow; ULONG i; ULONG r; USHORT PciDataOffset; // M001 PCI_SLOT_NUMBER PciSlot; UCHAR header; KIRQL Irql; PhysAddr.HighPart = 0x00000000; #if 1 KeInitializeSpinLock (&HalpPCIConfigLock); //kuku KeRaiseIrql (PROFILE_LEVEL, &Irql); KiAcquireSpinLock (&HalpPCIConfigLock); #if 0 //tmp 707 // M001 // First Check ISA BIOS.Becase PCEB 0-1M Positive Decode So // I Can See ROM Image. // Create a mapping to ISA memory space, unless one already exists // HalpIoMemoryBase= (PVOID)0x40000000; ROM_size = 0xD0000; // Map to end of option ROM space // // Look for ISA option video ROM signature // ROM_Ptr = (PUCHAR) HalpIoMemoryBase + 0xC0000; HalpRomBase = ROM_Ptr; if (*ROM_Ptr == 0x55 && *(ROM_Ptr+1) == 0xAA) { // // Copy ROM to RAM. PCI Spec says you can't execute from ROM. // ROM and video RAM sometimes can't co-exist. // ROM_Length = *(ROM_Ptr+2) << 9; if (ROM_Length <= BUFFER_SIZE) { for (i=0; i> 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 0x9ffff reads as zero // and writes are ignored. // case 0x1: case 0x2: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7: case 0x8: case 0x9: x86BiosScratchMemory = 0; return (PVOID)&x86BiosScratchMemory; // // The memory range from 0xa0000 to 0xdffff maps to I/O memory. // case 0xa: case 0xb: return (PVOID)(x86BiosIoMemory + Offset + Value); case 0xc: case 0xd: return (PVOID)(HalpRomBase + Offset); // // The memory range from 0x10000 to 0x9ffff reads as zero // and writes are ignored. // case 0xe: case 0xf: x86BiosScratchMemory = 0; return (PVOID)&x86BiosScratchMemory; } // NOT REACHED - NOT EXECUTED - Prevents Compiler Warning. return (PVOID)NULL; } VOID HalpCopyROMs(VOID) { ULONG i; PUCHAR ROM_Shadow; if (ROM_Buffer[0] == 0x55 && ROM_Buffer[1] == 0xAA) { HalpRomBase = ROM_Shadow = ExAllocatePool(NonPagedPool, ROM_Length); #if defined(_X86_DBG_) DbgPrint("HalpRomBase=%0x\n",HalpRomBase); #endif // _X86_DBG_ for (i=0; i> 8)); WRITE_REGISTER_UCHAR(u.Byte + 2, (UCHAR)(Value >> 16)); WRITE_REGISTER_UCHAR(u.Byte + 3, (UCHAR)(Value >> 24)); } else { WRITE_REGISTER_ULONG(u.Long, Value); } } else { if (((ULONG)u.Word & 0x1) != 0) { WRITE_REGISTER_UCHAR(u.Byte + 0, (UCHAR)(Value)); WRITE_REGISTER_UCHAR(u.Byte + 1, (UCHAR)(Value >> 8)); } else { WRITE_REGISTER_USHORT(u.Word, (USHORT)Value); } } return; } 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. --*/ { // // Zero low memory. // memset(&x86BiosLowMemory, 0, LOW_MEMORY_SIZE); // // Save base address of I/O memory and I/O space. // x86BiosIoSpace = (ULONG)BiosIoSpace; x86BiosIoMemory = (ULONG)BiosIoMemory; // // Initialize the emulator and the BIOS. // XmInitializeEmulator(0, LOW_MEMORY_SIZE, x86BiosReadIoSpace, x86BiosWriteIoSpace, x86BiosTranslateAddress); #if defined(_X86_DBG_) DbgPrint("\n EMU INIT \n"); //DBGDBG #endif // _X86_DBG_ x86BiosInitialized = TRUE; 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. 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)BiosIoSpace; } if (BiosIoMemory != NULL) { x86BiosIoMemory = (ULONG)BiosIoMemory; } // // Execute the specified interrupt. // Status = XmEmulateInterrupt(Number, Context); if (Status != XM_SUCCESS) { #if defined(_X86_DBG_) DbgPrint("HAL: Interrupt emulation failed, status %lx\n", Status); #endif // _X86_DBG_ } return Status; } 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. --*/ { PUCHAR Byte; XM86_CONTEXT State; USHORT Offset; USHORT Segment; XM_STATUS Status; #if defined(_X86_DBG_) DbgPrint("\n BIOS INIT \n"); //DBGDBG #endif // _X86_DBG_ // // 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)BiosIoSpace; } if (BiosIoMemory != NULL) { x86BiosIoMemory = (ULONG)BiosIoMemory; } // // 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); #if defined(_X86_DBG_) DbgPrint("\n Emcall BIOS start \n"); //DBGDBG #endif // _X86_DBG_ Status = XmEmulateFarCall(Segment, Offset, Context); #if defined(_X86_DBG_) DbgPrint("\n Emcall BIOS End \n"); //DBGDBG #endif // _X86_DBG_ if (Status != XM_SUCCESS) { #if defined(_X86_DBG_) DbgPrint("HAL: Adapter initialization falied, status %lx\n", Status); #endif // _X86_DBG_ } return Status; }