diff --git a/hal/CMakeLists.txt b/hal/CMakeLists.txt index 299dc891accde..06b25c64ad010 100644 --- a/hal/CMakeLists.txt +++ b/hal/CMakeLists.txt @@ -5,3 +5,5 @@ if((ARCH STREQUAL "i386") OR (ARCH STREQUAL "amd64")) elseif(ARCH STREQUAL "arm") add_subdirectory(halarm) endif() + +add_subdirectory(halacpi) \ No newline at end of file diff --git a/hal/halacpi/CMakeLists.txt b/hal/halacpi/CMakeLists.txt new file mode 100644 index 0000000000000..95814f076cd81 --- /dev/null +++ b/hal/halacpi/CMakeLists.txt @@ -0,0 +1,57 @@ + +add_definitions( + -D_NTHALDLL_ + -D_NTHAL_) + +add_definitions(-DMM_NEW) + +include_directories(include ${REACTOS_SOURCE_DIR}/ntoskrnl/include) + +# Handle the spec file for the dll name +spec2def(halacpi.dll halacpi.spec ADD_IMPORTLIB) + +# The components generic +list(APPEND HAL_SOURCE + acpi/busemul.c + acpi/dispatch.c + acpi/halacpi.c + acpi/halpnpdd.c + bus/pcibus.c + generic/i386/bios.c + generic/i386/portio.c + generic/beep.c + generic/cmos.c + generic/display.c + generic/dma.c + generic/drive.c + generic/halinit.c + generic/memory.c + generic/misc.c + generic/reboot.c + generic/spinlock.c + generic/sysinfo.c + generic/usage.c + pic/pic.c + pic/profil.c + pic/timer.c + up/processor.c) + +list(APPEND HAL_ASM_SOURCE + generic/v86.S + pic/pic.S + pic/pictrap.S + pic/systimer.S) + +add_asm_files(lib_hal_pic_asm ${HAL_ASM_SOURCE}) + +add_library(halacpi MODULE + ${HAL_SOURCE} + ${lib_hal_pic_asm} + version/halacpi.rc + ${CMAKE_CURRENT_BINARY_DIR}/halacpi.def) +set_module_type(halacpi kerneldll ENTRYPOINT HalInitSystem 8) +target_link_libraries(halacpi libcntpr wdmguid) +add_dependencies(halacpi asm psdk bugcodes xdk) +add_importlibs(halacpi ntoskrnl) +#add_pch(halacpi include/hal.h SOURCE) +add_cd_file(TARGET halacpi DESTINATION reactos/system32 NO_CAB FOR all) diff --git a/hal/halacpi/acpi/busemul.c b/hal/halacpi/acpi/busemul.c new file mode 100644 index 0000000000000..b430a8473b7fc --- /dev/null +++ b/hal/halacpi/acpi/busemul.c @@ -0,0 +1,677 @@ + +/* INCLUDES *******************************************************************/ + +#include +//#define NDEBUG +#include + +/* GLOBALS ********************************************************************/ + +ULONG HalpPicVectorRedirect[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; + +extern ULONG HalpMinPciBus; +extern ULONG HalpMaxPciBus; + +extern BUS_HANDLER HalpFakePciBusHandler; +extern BOOLEAN HalpPCIConfigInitialized; +extern FADT HalpFixedAcpiDescTable; + +/* PRIVATE FUNCTIONS **********************************************************/ + +NTSTATUS +NTAPI +TranslateGlobalVectorToIsaVector( + _In_ ULONG GlobalVector, + _Out_ PULONG IsaVector) +{ + UCHAR ix; + + DPRINT("TranslateGlobalVectorToIsaVector: Global %X, Isa %X\n", GlobalVector, IsaVector); + + for (ix = 0; ix < 0x10; ix++) + { + if (HalpPicVectorRedirect[ix] == GlobalVector) + { + DPRINT("TranslateGlobalVectorToIsaVector: Vector %X\n", ix); + *IsaVector = ix; + return STATUS_SUCCESS; + } + } + + return STATUS_NOT_FOUND; +} + +NTSTATUS +NTAPI +HalacpiIrqTranslateResourcesIsa( + _Inout_opt_ PVOID Context, + _In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR Source, + _In_ RESOURCE_TRANSLATION_DIRECTION Direction, + _In_opt_ ULONG AlternativesCount, + _In_opt_ IO_RESOURCE_DESCRIPTOR Alternatives[], + _In_ PDEVICE_OBJECT PhysicalDeviceObject, + _Out_ PCM_PARTIAL_RESOURCE_DESCRIPTOR Target) +{ + ULONG Level; + ULONG Vector; + ULONG ix; + BOOLEAN IsFound = FALSE; + NTSTATUS Status; + + PAGED_CODE(); + DPRINT("HalacpiIrqTranslateResourcesIsa: Direction %X, AltCount %X\n", Direction, AlternativesCount); + //ASSERT(FALSE); // HalpDbgBreakPointEx(); + + ASSERT(Source->Type == CmResourceTypeInterrupt); + + RtlCopyMemory(Target, Source, sizeof(*Target)); + + if (Direction == TranslateChildToParent) + { + Target->u.Interrupt.Level = HalpPicVectorRedirect[Source->u.Interrupt.Level]; + Target->u.Interrupt.Vector = HalpPicVectorRedirect[Source->u.Interrupt.Vector]; + + DPRINT("HalacpiIrqTranslateResourcesIsa: Lvl %X, Vec %X\n", Target->u.Interrupt.Level, Target->u.Interrupt.Vector); + + return STATUS_SUCCESS; + } + + if (Direction != 1) + { + ASSERT(FALSE); + return STATUS_SUCCESS; + } + + Status = TranslateGlobalVectorToIsaVector(Source->u.Interrupt.Level, &Level); + if (!NT_SUCCESS(Status)) + { + ASSERT(FALSE); + return Status; + } + + Target->u.Interrupt.Level = Level; + + Status = TranslateGlobalVectorToIsaVector(Source->u.Interrupt.Vector, &Vector); + if (!NT_SUCCESS(Status)) + { + ASSERT(FALSE); + return Status; + } + + Target->u.Interrupt.Vector = Vector; + + if (!Target->u.Interrupt.Level == 9 || AlternativesCount <= 0) + { + DPRINT("HalacpiIrqTranslateResourcesIsa: Level %X, Vector %X\n", Target->u.Interrupt.Level, Target->u.Interrupt.Vector); + ASSERT(FALSE); + return STATUS_SUCCESS; + } + + for (ix = 0; ix < AlternativesCount; ix++) + { + if (Alternatives[ix].u.Interrupt.MinimumVector >= 9 && + Alternatives[ix].u.Interrupt.MaximumVector <= 9) + { + IsFound = FALSE; + break; + } + + if (Alternatives[ix].u.Interrupt.MinimumVector >= 2 && + Alternatives[ix].u.Interrupt.MaximumVector <= 2) + { + IsFound = TRUE; + } + } + + if (IsFound) + { + DPRINT("HalacpiIrqTranslateResourcesIsa: Level 2, Vector 2\n"); + + Target->u.Interrupt.Level = 2; + Target->u.Interrupt.Vector = 2; + } + else + { + DPRINT("HalacpiIrqTranslateResourcesIsa: Level %X, Vector %X\n", Target->u.Interrupt.Level, Target->u.Interrupt.Vector); + } + + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +HalacpiIrqTranslateResourceRequirementsIsa( + _Inout_opt_ PVOID Context, + _In_ PIO_RESOURCE_DESCRIPTOR Source, + _In_ PDEVICE_OBJECT PhysicalDeviceObject, + _Out_ PULONG TargetCount, + _Out_ PIO_RESOURCE_DESCRIPTOR * Target) +{ + PIO_RESOURCE_DESCRIPTOR TempIoDesc; + PIO_RESOURCE_DESCRIPTOR NewIoDesc; + ULONG IoDescCount; + ULONG VectorMin; + ULONG VectorMax; + ULONG VectorCount; + ULONG MinimumVector; + ULONG CurrentVector; + ULONG Size; + ULONG jx; + ULONG ix; + USHORT SciVector; + NTSTATUS Status; + + VectorMin = Source->u.Interrupt.MinimumVector; + VectorMax = Source->u.Interrupt.MaximumVector; + VectorCount = (VectorMax - VectorMin); + + DPRINT("HalacpiIrqTranslateResourceRequirementsIsa: Min %X, Max %X\n", VectorMin, VectorMax); + + PAGED_CODE(); + ASSERT(Source->Type == CmResourceTypeInterrupt); + + Size = (VectorCount + 3) * sizeof(IO_RESOURCE_DESCRIPTOR); + + TempIoDesc = ExAllocatePoolWithTag(PagedPool, Size, ' laH'); + if (!TempIoDesc) + { + DPRINT1("HalacpiIrqTranslateResourceRequirementsIsa: TempIoDesc is NULL\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(TempIoDesc, Size); + + ix = 0; + + if (VectorMin > 2 || VectorMax < 2) + { + RtlCopyMemory(&TempIoDesc[ix], Source, sizeof(IO_RESOURCE_DESCRIPTOR)); + ix++; + } + else + { + if (VectorMin < 2) + { + RtlCopyMemory(&TempIoDesc[ix], Source, sizeof(IO_RESOURCE_DESCRIPTOR)); + TempIoDesc->u.Interrupt.MinimumVector = VectorMin; + TempIoDesc->u.Interrupt.MaximumVector = 1; + ix++; + } + if (VectorMax > 2) + { + RtlCopyMemory(&TempIoDesc[ix], Source, sizeof(IO_RESOURCE_DESCRIPTOR)); + TempIoDesc[ix].u.Interrupt.MinimumVector = 3; + TempIoDesc[ix].u.Interrupt.MaximumVector = VectorMax; + ix++; + } + if (VectorMin > 9 || VectorMax < 9) + { + RtlCopyMemory(&TempIoDesc[ix++], Source, sizeof(IO_RESOURCE_DESCRIPTOR)); + TempIoDesc[ix].u.Interrupt.MinimumVector = 9; + TempIoDesc[ix].u.Interrupt.MaximumVector = 9; + ix++; + } + } + + IoDescCount = 0; + SciVector = HalpFixedAcpiDescTable.sci_int_vector; + + for (jx = 0; jx < ix; jx++) + { + VectorMin = TempIoDesc[jx].u.Interrupt.MinimumVector; + VectorMax = TempIoDesc[jx].u.Interrupt.MaximumVector; + + if (VectorMax >= 0x10) // PIC max + { + ExFreePoolWithTag(TempIoDesc, ' laH'); + Status = STATUS_UNSUCCESSFUL; + goto Exit; + } + + if (VectorMin >= 0x10) + { + ExFreePoolWithTag(TempIoDesc, ' laH'); + Status = STATUS_UNSUCCESSFUL; + goto Exit; + } + + if (VectorMin > SciVector || VectorMax < SciVector) + continue; + + if (VectorMin < SciVector) + { + TempIoDesc[ix].u.Interrupt.MinimumVector = VectorMin; + TempIoDesc[ix].u.Interrupt.MaximumVector = (SciVector - 1); + ix++; + } + + if (VectorMax > SciVector) + { + TempIoDesc[ix].u.Interrupt.MinimumVector = (SciVector + 1); + TempIoDesc[ix].u.Interrupt.MaximumVector = VectorMax; + ix++; + } + + RtlMoveMemory(&TempIoDesc[jx], &TempIoDesc[jx+1], ((ix - jx) * sizeof(IO_RESOURCE_DESCRIPTOR))); + + ix--; + } + + NewIoDesc = ExAllocatePoolWithTag(PagedPool, Size, ' laH'); + if (!NewIoDesc) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + ExFreePoolWithTag(TempIoDesc, ' laH'); + goto Exit; + } + + RtlZeroMemory(NewIoDesc, Size); + + for (jx = 0; jx < ix; jx++) + { + CurrentVector = TempIoDesc[jx].u.Interrupt.MinimumVector; + VectorMax = TempIoDesc[jx].u.Interrupt.MaximumVector; + + do + { + MinimumVector = CurrentVector; + while (CurrentVector < VectorMax) + { + if ((HalpPicVectorRedirect[CurrentVector] + 1) != + HalpPicVectorRedirect[CurrentVector + 1]) + { + break; + } + + CurrentVector++; + } + + RtlCopyMemory(&NewIoDesc[IoDescCount], Source, sizeof(IO_RESOURCE_DESCRIPTOR)); + + NewIoDesc[IoDescCount].u.Interrupt.MinimumVector = HalpPicVectorRedirect[MinimumVector]; + NewIoDesc[IoDescCount].u.Interrupt.MaximumVector = HalpPicVectorRedirect[CurrentVector]; + + ASSERT(NewIoDesc[IoDescCount].u.Interrupt.MinimumVector <= + NewIoDesc[IoDescCount].u.Interrupt.MaximumVector); + + IoDescCount++; + } + while (CurrentVector != VectorMax); + } + + *TargetCount = IoDescCount; + + if (IoDescCount) + *Target = NewIoDesc; + else + ExFreePoolWithTag(NewIoDesc, ' laH'); + + Status = STATUS_SUCCESS; + ExFreePoolWithTag(TempIoDesc, ' laH'); + +Exit: + +#if 0 +if (IoDescCount) +{ + PIO_RESOURCE_DESCRIPTOR Descriptor = *Target; + + for (ix = 0; ix < *TargetCount; ix++) + HalpDumpIoResourceDescriptor("", &Descriptor[ix]); +} +#endif + + return Status; +} + +NTSTATUS +NTAPI +HalacpiGetInterruptTranslator( + _In_ INTERFACE_TYPE ParentInterfaceType, + _In_ ULONG ParentBusNumber, + _In_ INTERFACE_TYPE BridgeInterfaceType, + _In_ USHORT Size, + _In_ USHORT Version, + _Out_ PTRANSLATOR_INTERFACE Translator, + _Out_ PULONG BridgeBusNumber) +{ + PAGED_CODE(); + + ASSERT(Version == 0); + ASSERT(Size >= sizeof(TRANSLATOR_INTERFACE)); + + if (BridgeInterfaceType != -1 && + BridgeInterfaceType != 1 && + BridgeInterfaceType != 2) + { + return STATUS_NOT_IMPLEMENTED; + } + + RtlZeroMemory(Translator, sizeof(TRANSLATOR_INTERFACE)); + + Translator->Size = sizeof(TRANSLATOR_INTERFACE); + Translator->Version = 0; + + Translator->InterfaceReference = HalTranslatorDereference; + Translator->InterfaceDereference = HalTranslatorDereference; + + Translator->TranslateResources = HalacpiIrqTranslateResourcesIsa; + Translator->TranslateResourceRequirements = HalacpiIrqTranslateResourceRequirementsIsa; + + return STATUS_SUCCESS; +} + +BOOLEAN +NTAPI +HalpTranslateBusAddress(IN INTERFACE_TYPE InterfaceType, + IN ULONG BusNumber, + IN PHYSICAL_ADDRESS BusAddress, + IN OUT PULONG AddressSpace, + OUT PPHYSICAL_ADDRESS TranslatedAddress) +{ + /* Translation is easy */ + TranslatedAddress->QuadPart = BusAddress.QuadPart; + return TRUE; +} + +NTSTATUS +NTAPI +HalpAssignSlotResources(IN PUNICODE_STRING RegistryPath, + IN PUNICODE_STRING DriverClassName, + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT DeviceObject, + IN INTERFACE_TYPE BusType, + IN ULONG BusNumber, + IN ULONG SlotNumber, + IN OUT PCM_RESOURCE_LIST *AllocatedResources) +{ + BUS_HANDLER BusHandler; + + DPRINT("HalpAssignSlotResources: BusType %X, BusNumber %X, SlotNumber %X\n", BusType, BusNumber, SlotNumber); + PAGED_CODE(); + + /* Only PCI is supported */ + if (BusType != PCIBus) return STATUS_NOT_IMPLEMENTED; + + /* Setup fake PCI Bus handler */ + RtlCopyMemory(&BusHandler, &HalpFakePciBusHandler, sizeof(BUS_HANDLER)); + BusHandler.BusNumber = BusNumber; + + /* Call the PCI function */ + return HalpAssignPCISlotResources(&BusHandler, + &BusHandler, + RegistryPath, + DriverClassName, + DriverObject, + DeviceObject, + SlotNumber, + AllocatedResources); +} + +BOOLEAN +NTAPI +HalpFindBusAddressTranslation(IN PHYSICAL_ADDRESS BusAddress, + IN OUT PULONG AddressSpace, + OUT PPHYSICAL_ADDRESS TranslatedAddress, + IN OUT PULONG_PTR Context, + IN BOOLEAN NextBus) +{ + /* Make sure we have a context */ + if (!Context) + return FALSE; + + /* If we have data in the context, then this shouldn't be a new lookup */ + if ((*Context != 0) && (NextBus != FALSE)) + return FALSE; + + /* Return bus data */ + TranslatedAddress->QuadPart = BusAddress.QuadPart; + + /* Set context value and return success */ + *Context = 1; + return TRUE; +} + + +/* PUBLIC FUNCTIONS **********************************************************/ + +NTSTATUS +NTAPI +HalAdjustResourceList(IN OUT PIO_RESOURCE_REQUIREMENTS_LIST * pRequirementsList) +{ + /* Deprecated, return success */ + return STATUS_SUCCESS; +} + +UCHAR +FASTCALL +HalSystemVectorDispatchEntry(IN ULONG Vector, + OUT PKINTERRUPT_ROUTINE **FlatDispatch, + OUT PKINTERRUPT_ROUTINE *NoConnection) +{ + /* Not implemented on x86 */ + return 0; +} + +ULONG +NTAPI +HalGetInterruptVector(IN INTERFACE_TYPE InterfaceType, + IN ULONG BusNumber, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL OutIrql, + OUT PKAFFINITY OutAffinity) +{ + ULONG Vector; + ULONG Level; + ULONG SystemVector; + BUS_HANDLER BusHandler; + + if (InterfaceType == Isa) + { + if (BusInterruptVector >= 0x10) + { + DPRINT1("HalGetInterruptVector: BusInterruptVector %X\n", BusInterruptVector); + ASSERT(BusInterruptVector < 0x10); // HalpDbgBreakPointEx(); + } + + Vector = HalpPicVectorRedirect[BusInterruptVector]; + Level = HalpPicVectorRedirect[BusInterruptLevel]; + } + else + { + Vector = BusInterruptVector; + Level = BusInterruptLevel; + } + + RtlCopyMemory(&BusHandler, &HalpFakePciBusHandler, sizeof(BusHandler)); + + BusHandler.BusNumber = BusNumber; + BusHandler.InterfaceType = InterfaceType; + BusHandler.ParentHandler = &BusHandler; + + SystemVector = HalpGetSystemInterruptVector(&BusHandler, + &BusHandler, + Level, + Vector, + OutIrql, + OutAffinity); + + DPRINT("HalGetInterruptVector: Level %X, Vector %X, SystemVector %X\n", Level, Vector, SystemVector); + + return SystemVector; +} + +BOOLEAN +NTAPI +HalTranslateBusAddress(IN INTERFACE_TYPE InterfaceType, + IN ULONG BusNumber, + IN PHYSICAL_ADDRESS BusAddress, + IN OUT PULONG AddressSpace, + OUT PPHYSICAL_ADDRESS TranslatedAddress) +{ + /* Look as the bus type */ + if (InterfaceType == PCIBus) + { + /* Call the PCI registered function */ + return HalPciTranslateBusAddress(PCIBus, + BusNumber, + BusAddress, + AddressSpace, + TranslatedAddress); + } + else + { + /* Translation is easy */ + TranslatedAddress->QuadPart = BusAddress.QuadPart; + return TRUE; + } +} + +ULONG +NTAPI +HalGetBusDataByOffset(IN BUS_DATA_TYPE BusDataType, + IN ULONG BusNumber, + IN ULONG SlotNumber, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length) +{ + BUS_HANDLER BusHandler; + + /* Look as the bus type */ + if (BusDataType == Cmos) + return HalpGetCmosData(0, SlotNumber, Buffer, Length); + + if (BusDataType == EisaConfiguration) + { + /* FIXME: TODO */ + ASSERT(FALSE); + return 0; + } + + if (BusDataType != PCIConfiguration) + /* Invalid bus */ + return 0; + + if (!HalpPCIConfigInitialized) + /* Invalid bus */ + return 0; + + if ((BusNumber < HalpMinPciBus) || (BusNumber > HalpMaxPciBus)) + /* Invalid bus */ + return 0; + + /* Setup fake PCI Bus handler */ + RtlCopyMemory(&BusHandler, &HalpFakePciBusHandler, sizeof(BUS_HANDLER)); + BusHandler.BusNumber = BusNumber; + + /* Call PCI function */ + return HalpGetPCIData(&BusHandler, &BusHandler, SlotNumber, Buffer, Offset, Length); +} + +ULONG +NTAPI +HalGetBusData(IN BUS_DATA_TYPE BusDataType, + IN ULONG BusNumber, + IN ULONG SlotNumber, + IN PVOID Buffer, + IN ULONG Length) +{ + /* Call the extended function */ + return HalGetBusDataByOffset(BusDataType, + BusNumber, + SlotNumber, + Buffer, + 0, + Length); +} + +ULONG +NTAPI +HalSetBusDataByOffset(IN BUS_DATA_TYPE BusDataType, + IN ULONG BusNumber, + IN ULONG SlotNumber, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length) +{ + BUS_HANDLER BusHandler; + + /* Look as the bus type */ + if (BusDataType == Cmos) + /* Call CMOS Function */ + return HalpSetCmosData(0, SlotNumber, Buffer, Length); + + if (BusDataType != PCIConfiguration) + return 0; + + if (!HalpPCIConfigInitialized) + return 0; + + /* Setup fake PCI Bus handler */ + RtlCopyMemory(&BusHandler, &HalpFakePciBusHandler, sizeof(BUS_HANDLER)); + BusHandler.BusNumber = BusNumber; + + /* Call PCI function */ + return HalpSetPCIData(&BusHandler, &BusHandler, SlotNumber, Buffer, Offset, Length); +} + +ULONG +NTAPI +HalSetBusData(IN BUS_DATA_TYPE BusDataType, + IN ULONG BusNumber, + IN ULONG SlotNumber, + IN PVOID Buffer, + IN ULONG Length) +{ + /* Call the extended function */ + return HalSetBusDataByOffset(BusDataType, + BusNumber, + SlotNumber, + Buffer, + 0, + Length); +} + +NTSTATUS +NTAPI +HalAssignSlotResources(IN PUNICODE_STRING RegistryPath, + IN PUNICODE_STRING DriverClassName, + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT DeviceObject, + IN INTERFACE_TYPE BusType, + IN ULONG BusNumber, + IN ULONG SlotNumber, + IN OUT PCM_RESOURCE_LIST * AllocatedResources) +{ + /* Check the bus type */ + if (BusType != PCIBus) + { + /* Call our internal handler */ + DPRINT("HalAssignSlotResources: BusType %X, BusNumber %X, SlotNumber %X\n", BusType, BusNumber, SlotNumber); + return HalpAssignSlotResources(RegistryPath, + DriverClassName, + DriverObject, + DeviceObject, + BusType, + BusNumber, + SlotNumber, + AllocatedResources); + } + else + { + /* Call the PCI registered function */ + DPRINT("HalAssignSlotResources: BusType %X, BusNumber %X, SlotNumber %X\n", BusType, BusNumber, SlotNumber); + return HalPciAssignSlotResources(RegistryPath, + DriverClassName, + DriverObject, + DeviceObject, + PCIBus, + BusNumber, + SlotNumber, + AllocatedResources); + } +} + +/* EOF */ diff --git a/hal/halacpi/acpi/dispatch.c b/hal/halacpi/acpi/dispatch.c new file mode 100644 index 0000000000000..6a633dc1c085a --- /dev/null +++ b/hal/halacpi/acpi/dispatch.c @@ -0,0 +1,811 @@ + +/* INCLUDES ******************************************************************/ + +#include +#include "dispatch.h" +#include "../../../drivers/usb/usbohci/hardware.h" +#include "../../../drivers/usb/usbuhci/hardware.h" + +//#define NDEBUG +#include + +/* GLOBALS *******************************************************************/ + +PPM_DISPATCH_TABLE PmAcpiDispatchTable; +ACPI_PM_DISPATCH_TABLE HalAcpiDispatchTable = +{ + 0x48414C20, // 'HAL ' + 2, + HaliAcpiTimerInit, + NULL, + HaliAcpiMachineStateInit, + HaliAcpiQueryFlags, + HalpAcpiPicStateIntact, + HalpRestoreInterruptControllerState, + HaliPciInterfaceReadConfig, + HaliPciInterfaceWriteConfig, + HaliSetVectorState, + HalpGetApicVersion, + HaliSetMaxLegacyPciBusNumber, + HaliIsVectorValid +}; + +HALP_TIMER_INFO TimerInfo; +PVOID HalpWakeVector = NULL; +BOOLEAN HalpBrokenAcpiTimer = FALSE; +BOOLEAN HalpWakeupState[2]; +BOOLEAN HalpDisableHibernate; +BOOLEAN HalpDisableS5Hibernation; + +extern FADT HalpFixedAcpiDescTable; +extern ULONG HalpWAETDeviceFlags; +extern ULONG HalpMaxPciBus; +extern ULONG HalpShutdownContext; + +/* PRIVATE FUNCTIONS *********************************************************/ + +VOID +NTAPI +HalaAcpiTimerInit(_In_ PULONG TimerPort, + _In_ BOOLEAN IsTimerValExt) +{ + DPRINT("HalaAcpiTimerInit: Port %X, IsValExt %X\n", TimerPort, IsTimerValExt); + + RtlZeroMemory(&TimerInfo, sizeof(TimerInfo)); + + TimerInfo.TimerPort = TimerPort; + + if (IsTimerValExt) + TimerInfo.ValueExt = 0x80000000; // 32-bit + else + TimerInfo.ValueExt = 0x00800000; // 24-bit + + if (!HalpBrokenAcpiTimer) + { + DPRINT("HalpBrokenAcpiTimer - FALSE\n"); + return; + } + + DPRINT1("HalaAcpiTimerInit: FIXME HalpQueryBrokenPiix4()\n"); + ASSERT(0); // HalpDbgBreakPointEx(); + +} + +VOID +NTAPI +HaliAcpiTimerInit(_In_ PULONG TimerPort, + _In_ BOOLEAN TimerValExt) +{ + PAGED_CODE(); + + DPRINT("HaliAcpiTimerInit: Port %X, ValExt %X\n", TimerPort, TimerValExt); + DPRINT("HalpFixedAcpiDescTable.flags - %08X\n", HalpFixedAcpiDescTable.flags); + + /* Is this in the init phase? */ + if (!TimerPort) + { + /* Get the data from the FADT */ + + /* System port address of the Power Management Timer Control Register Block */ + TimerPort = (PULONG)HalpFixedAcpiDescTable.pm_tmr_blk_io_port; + + /* A zero indicates TMR_VAL is implemented as a 24-bit value. + A one indicates TMR_VAL is implemented as a 32-bit value. + */ + TimerValExt = ((HalpFixedAcpiDescTable.flags & ACPI_TMR_VAL_EXT) != 0); + DPRINT1("TimerPort %X, TimerValExt %X\n", TimerPort, TimerValExt); + } + + /* FIXME: Now proceed to the timer initialization */ + HalaAcpiTimerInit(TimerPort, TimerValExt); +} + +VOID +NTAPI +HalAcpiTimerCarry(VOID) +{ + LARGE_INTEGER Value; + ULONG Time; + + Time = READ_PORT_ULONG(TimerInfo.TimerPort); + DPRINT("HalAcpiTimerCarry: Time %X\n", Time); + + Value.QuadPart = (TimerInfo.AcpiTimeValue.QuadPart + TimerInfo.ValueExt); + Value.QuadPart += ((Value.LowPart ^ Time) & TimerInfo.ValueExt); + + TimerInfo.TimerCarry = Value.HighPart; + TimerInfo.AcpiTimeValue.QuadPart = Value.QuadPart; +} + +VOID +NTAPI +HalAcpiBrokenPiix4TimerCarry(VOID) +{ + /* Nothing */ + ; +} + +VOID +NTAPI +HaliSetWakeEnable(_In_ BOOLEAN Enable) +{ + DPRINT("HaliSetWakeEnable: Enable %X\n", Enable); + + HalpWakeupState[1] = 0; + HalpWakeupState[0] = Enable; +} + +VOID +NTAPI +HaliSetWakeAlarm(_In_ ULONGLONG AlartTime, + _In_ PTIME_FIELDS WakeTimeFields) +{ + DPRINT("HaliSetWakeAlarm: AlartTime %I64X\n", AlartTime); + + if (!AlartTime) + { + DPRINT1("HaliSetWakeAlarm: AlartTime is 0\n"); + ASSERT(0); // HalpDbgBreakPointEx(); + return; + } + + ASSERT(WakeTimeFields); + + DPRINT1("HaliSetWakeAlarm: ... \n"); + ASSERT(0); // HalpDbgBreakPointEx(); +} + +/* halfplemented */ +VOID +NTAPI +HalpPowerStateCallback(_In_ PVOID CallbackContext, + _In_ PVOID Argument1, + _In_ PVOID Argument2) +{ + DPRINT("HalpPowerStateCallback: CallbackContext %X, Arg1 %X, Arg2 %X\n", CallbackContext, Argument1, Argument2); + + if (Argument1 != ULongToPtr(3)) + { + DPRINT1("HalpPowerStateCallback: Argument1 != 3\n"); + ASSERT(FALSE); // HalpDbgBreakPointEx(); + return; + } + + if (Argument2 == ULongToPtr(0)) + { + DPRINT1("HalpPowerStateCallback: FIXME HalpMapNvsArea()\n"); + //ASSERT(FALSE); // HalpDbgBreakPointEx(); + return; + } + + if (Argument2 == ULongToPtr(1)) + { + DPRINT1("HalpPowerStateCallback: FIXME HalpFreeNvsBuffers()\n"); + ASSERT(FALSE); // HalpDbgBreakPointEx(); + return; + } + + DPRINT1("HalpPowerStateCallback: Unsupported Arg2 %X\n", Argument2); + ASSERT(FALSE); // HalpDbgBreakPointEx(); +} + +NTSTATUS +NTAPI +HalpGetChipHacks(_In_ USHORT VendorID, + _In_ USHORT DeviceID, + _In_ UCHAR RevisionID, + _Out_ ULONG* OutChipHacks) +{ + KEY_VALUE_PARTIAL_INFORMATION KeyValueInfo; + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING DestinationString; + HANDLE KeyHandle = NULL; + ULONG ResultLength; + ULONG ChipHacks; + WCHAR SourceString[10]; + NTSTATUS Status; + + PAGED_CODE(); + DPRINT("HalpGetChipHacks: VendorID %X, DeviceID %X\n", VendorID, DeviceID); + + RtlInitUnicodeString(&DestinationString, L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\Control\\HAL"); + + InitializeObjectAttributes(&ObjectAttributes, &DestinationString, OBJ_CASE_INSENSITIVE, NULL, NULL); + + Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes); + if (!NT_SUCCESS(Status)) + { + DPRINT1("HalpGetChipHacks: Status %X\n", Status); + KeFlushWriteBuffer(); + return Status; + } + + swprintf(SourceString, L"%04X%04X", VendorID, DeviceID); + RtlInitUnicodeString(&DestinationString, SourceString); + + Status = ZwQueryValueKey(KeyHandle, + &DestinationString, + KeyValuePartialInformation, + &KeyValueInfo, + sizeof(KeyValueInfo), + &ResultLength); + if (!NT_SUCCESS(Status)) + { + ZwClose(KeyHandle); + KeFlushWriteBuffer(); + return Status; + } + + ChipHacks = *(PULONG)KeyValueInfo.Data; + DPRINT1("HalpGetChipHacks: ChipHacks %X\n", ChipHacks); + + if (RevisionID && (RevisionID >= (ChipHacks >> 24))) + { + DPRINT1("HalpGetChipHacks: RevisionID %X\n", RevisionID); + ASSERT(0); // HalpDbgBreakPointEx(); + ChipHacks >>= 12; + } + + ChipHacks &= 0xFFF; + + if (HalpWAETDeviceFlags & 2) + { + DPRINT1("HalpGetChipHacks: HalpWAETDeviceFlags %X\n", HalpWAETDeviceFlags); + ASSERT(0); // HalpDbgBreakPointEx(); + ChipHacks &= 0xFFFFFFFE; + } + + *OutChipHacks = ChipHacks; + + ZwClose(KeyHandle); + KeFlushWriteBuffer(); + + return Status; +} + +VOID +NTAPI +HalpStopOhciInterrupt(_In_ ULONG BusNumber, + _In_ ULONG SlotNumber) +{ + POHCI_OPERATIONAL_REGISTERS OperationalRegs; + PHYSICAL_ADDRESS PhysicalAddresses; + PCI_COMMON_CONFIG PciHeader; + ULONG ix; + + DPRINT("HalpStopOhciInterrupt: Bus %X, Slot %X\n", BusNumber, SlotNumber); + + HalGetBusData(PCIConfiguration, BusNumber, SlotNumber, &PciHeader, sizeof(PciHeader)); + + if (!(PciHeader.Command & PCI_ENABLE_MEMORY_SPACE)) + goto Exit; + + PhysicalAddresses.QuadPart = (PciHeader.u.type0.BaseAddresses[0] & PCI_ADDRESS_MEMORY_ADDRESS_MASK); + if (!PhysicalAddresses.QuadPart) + goto Exit; + + OperationalRegs = HalpMapPhysicalMemory64(PhysicalAddresses, 1); + if (!OperationalRegs) + { + DPRINT1("HalpStopOhciInterrupt: failed HalpMapPhysicalMemory64()\n"); + goto Exit; + } + + if (!OperationalRegs->HcControl.InterruptRouting) + goto Exit1; + + if (OperationalRegs->HcControl.InterruptRouting && + !OperationalRegs->HcInterruptEnable.AsULONG) + { + OperationalRegs->HcControl.AsULONG = 0; + goto Exit1; + } + + OperationalRegs->HcInterruptDisable.RootHubStatusChange = 1; + OperationalRegs->HcInterruptEnable.OwnershipChange = 1; + OperationalRegs->HcInterruptEnable.MasterInterruptEnable = 1; + + OperationalRegs->HcCommandStatus.OwnershipChangeRequest = 1; + + for (ix = 0; ix < 500; ix++) + { + KeStallExecutionProcessor(1000); + + if (!OperationalRegs->HcControl.InterruptRouting) + break; + } + +Exit1: + OperationalRegs->HcInterruptDisable.MasterInterruptEnable = 1; + HalpUnmapVirtualAddress(OperationalRegs, 1); + +Exit: + KeFlushWriteBuffer(); +} + +VOID +NTAPI +HalpStopUhciInterrupt(_In_ ULONG BusNumber, + _In_ ULONG SlotNumber, + _In_ BOOLEAN IsIntel) +{ + PCI_COMMON_CONFIG PciHeader; + PUSHORT Port; + ULONG LegacySupport = 0; + + DPRINT("HalpStopUhciInterrupt: Bus %X, Slot %X, IsIntel %X\n", BusNumber, SlotNumber, IsIntel); + + if (!IsIntel) + { + HalGetBusDataByOffset(PCIConfiguration, BusNumber, SlotNumber, &LegacySupport, PCI_LEGSUP, sizeof(LegacySupport)); + LegacySupport &= 0x4000; + HalSetBusDataByOffset(PCIConfiguration, BusNumber, SlotNumber, &LegacySupport, PCI_LEGSUP, sizeof(LegacySupport)); + + goto Exit; + } + + LegacySupport = 0; + HalSetBusDataByOffset(PCIConfiguration, BusNumber, SlotNumber, &LegacySupport, PCI_LEGSUP, sizeof(LegacySupport)); + + HalGetBusData(PCIConfiguration, BusNumber, SlotNumber, &PciHeader, sizeof(PciHeader)); + if (!(PciHeader.Command & 1)) + goto Exit; + + Port = (PUSHORT)(PciHeader.u.type0.BaseAddresses[4] & PCI_ADDRESS_IO_ADDRESS_MASK); + if (!Port) + goto Exit; + + if ((ULONG_PTR)Port >= 0xFFFF) + goto Exit; + + if (READ_PORT_USHORT(Port) & 8) + goto Exit; + + WRITE_PORT_USHORT(Port, 4); + KeStallExecutionProcessor(10000); + WRITE_PORT_USHORT(Port, 0); + +Exit: + + KeFlushWriteBuffer(); +} + +VOID +NTAPI +HalpPiix4Detect(_In_ BOOLEAN IsInitialize) +{ + BOOLEAN IsBroken440BX = FALSE; + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING DestinationString; + PCI_COMMON_CONFIG PciHeader; + PCI_SLOT_NUMBER SlotNumber; + HANDLE KeyHandle = NULL; + HANDLE Handle = NULL; + ULONG Disposition; + ULONG BusNumber; + ULONG Device; + ULONG Function; + ULONG BytesRead; + ULONG ChipHacks; + NTSTATUS Status; + + DPRINT("HalpPiix4Detect: IsInitialize %X\n", IsInitialize); + + if (IsInitialize) + { + PAGED_CODE(); + + RtlInitUnicodeString(&DestinationString, L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET"); + InitializeObjectAttributes(&ObjectAttributes, &DestinationString, OBJ_CASE_INSENSITIVE, NULL, NULL); + + Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes); + if (!NT_SUCCESS(Status)) + { + KeFlushWriteBuffer(); + return; + } + + RtlInitUnicodeString(&DestinationString, L"Control\\HAL"); + InitializeObjectAttributes(&ObjectAttributes, &DestinationString, OBJ_CASE_INSENSITIVE, KeyHandle, NULL); + + Status = ZwCreateKey(&Handle, KEY_READ, &ObjectAttributes, 0, NULL, 0, &Disposition); + if (!NT_SUCCESS(Status)) + goto Exit; + } + + for (BusNumber = 0; BusNumber < 0xFF; BusNumber++) + { + SlotNumber.u.AsULONG = 0; + + for (Device = 0; Device < 0x20; Device++) + { + for (Function = 0; Function < 8; Function++) + { + DPRINT("HalpPiix4Detect: Bus %X, Dev %X, Func %X, Slot %X\n", BusNumber, Device, Function, SlotNumber.u.AsULONG); + + SlotNumber.u.bits.DeviceNumber = Device; + SlotNumber.u.bits.FunctionNumber = Function; + + BytesRead = HalGetBusData(PCIConfiguration, BusNumber, SlotNumber.u.AsULONG, &PciHeader, 0x40); + if (!BytesRead) + goto Finish; + + if (PciHeader.VendorID == 0xFFFF) + continue; + + DPRINT("HalpPiix4Detect: VendorID %X, DeviceID %X\n", PciHeader.VendorID, PciHeader.DeviceID); + + if (IsInitialize) + { + if (PciHeader.VendorID == 0x8086 && + (PciHeader.DeviceID == 0x7190 || PciHeader.DeviceID == 0x7192) && + PciHeader.RevisionID <= 2) + { + DPRINT1("HalpPiix4Detect: PciHeader.RevisionID %X\n", PciHeader.RevisionID); + ASSERT(0); // HalpDbgBreakPointEx(); + } + + Status = HalpGetChipHacks(PciHeader.VendorID, PciHeader.DeviceID, PciHeader.RevisionID, &ChipHacks); + if (NT_SUCCESS(Status)) + { + DPRINT1("HalpPiix4Detect: ChipHacks %X\n", ChipHacks); + + if (ChipHacks & 1) + { + ASSERT(0); // HalpDbgBreakPointEx(); + HalpBrokenAcpiTimer = 1; + } + if (ChipHacks & 2) + { + ASSERT(0); // HalpDbgBreakPointEx(); + } + if (ChipHacks & 8) + { + ASSERT(0); // HalpDbgBreakPointEx(); + } + } + } + else + { + DPRINT("HalpPiix4Detect: VendorID %X, DeviceID %X\n", PciHeader.VendorID, PciHeader.DeviceID); + } + + if (PciHeader.VendorID == 0x8086 && PciHeader.DeviceID == 0x7110) + { + DPRINT1("HalpPiix4Detect: VendorID %X, DeviceID %X\n", PciHeader.VendorID, PciHeader.DeviceID); + ASSERT(0); // HalpDbgBreakPointEx(); + goto Finish; + } + + if (PciHeader.BaseClass == 0xC && PciHeader.SubClass == 3) + { + if (PciHeader.ProgIf == 0x10) + { + HalpStopOhciInterrupt(BusNumber, SlotNumber.u.AsULONG); + } + else + { + if (PciHeader.VendorID == 0x8086) + { + HalpStopUhciInterrupt(BusNumber, SlotNumber.u.AsULONG, TRUE); + } + else + { + if (PciHeader.VendorID == 0x1106) + HalpStopUhciInterrupt(BusNumber, SlotNumber.u.AsULONG, FALSE); + } + } + } + + if (Function == 0) + { + if ((PciHeader.HeaderType & PCI_MULTIFUNCTION) == 0) + break; + } + } + } + } + +Finish: + + if (!IsInitialize) + { + KeFlushWriteBuffer(); + return; + } + + if (Handle) + { + ZwClose(Handle); + Handle = 0; + } + + if (!IsBroken440BX) + goto Exit; + + DPRINT1("HalpPiix4Detect: IsBroken440BX TRUE\n"); + ASSERT(0); // HalpDbgBreakPointEx(); + +Exit: + + if (Handle) + ZwClose(Handle); + + if (KeyHandle) + ZwClose(KeyHandle); + + KeFlushWriteBuffer(); +} + +NTSTATUS +NTAPI +HalacpiInitPowerManagement( + _In_ PPM_DISPATCH_TABLE PmDriverDispatchTable, + _Out_ PPM_DISPATCH_TABLE * PmHalDispatchTable) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + PHYSICAL_ADDRESS PhysicalAddress; + PCALLBACK_OBJECT CallbackObject; + UNICODE_STRING CallbackName; + PFACS Facs; + + PAGED_CODE(); + HalpPiix4Detect(TRUE); + + DPRINT("HalacpiInitPowerManagement: FIXME HalpPutAcpiHacksInRegistry() \n"); + + PmAcpiDispatchTable = PmDriverDispatchTable; // interface with acpi.sys + + HalAcpiDispatchTable.HalAcpiTimerInterrupt = HalAcpiTimerCarry; + if (HalpBrokenAcpiTimer) + { + DPRINT1("HalacpiInitPowerManagement: HalpBrokenAcpiTimer is TRUE\n"); + ASSERT(0); // HalpDbgBreakPointEx(); + HalAcpiDispatchTable.HalAcpiTimerInterrupt = HalAcpiBrokenPiix4TimerCarry; + } + + *PmHalDispatchTable = (PPM_DISPATCH_TABLE)&HalAcpiDispatchTable; // HAL export interface + + HalSetWakeEnable = HaliSetWakeEnable; + HalSetWakeAlarm = HaliSetWakeAlarm; + + DPRINT("HalacpiInitPowerManagement: FIXME Callbacks\\PowerState \n"); + + /* Create a power callback */ + RtlInitUnicodeString(&CallbackName, L"\\Callback\\PowerState"); + + InitializeObjectAttributes(&ObjectAttributes, + &CallbackName, + (OBJ_CASE_INSENSITIVE | OBJ_PERMANENT), + NULL, + NULL); + + ExCreateCallback(&CallbackObject, &ObjectAttributes, FALSE, TRUE); + ExRegisterCallback(CallbackObject, HalpPowerStateCallback, NULL); + + if (!HalpFixedAcpiDescTable.facs) + return STATUS_SUCCESS; + + PhysicalAddress.QuadPart = HalpFixedAcpiDescTable.facs; + Facs = MmMapIoSpace(PhysicalAddress, 0x40, MmNonCached); + + if (Facs && (Facs->Signature == 'SCAF')) + HalpWakeVector = &Facs->pFirmwareWakingVector; + + return STATUS_SUCCESS; +} + +/* PM DISPATCH FUNCTIONS *****************************************************/ + +NTSTATUS +NTAPI +HaliAcpiSleep(_In_opt_ PVOID Context, + _In_opt_ PENTER_STATE_SYSTEM_HANDLER SystemHandler, + _In_opt_ PVOID SystemContext, + _In_ LONG NumberProcessors, + _In_opt_ LONG volatile * Number) +{ + UNIMPLEMENTED; + ASSERT(FALSE);//HalpDbgBreakPointEx(); + return STATUS_NOT_IMPLEMENTED; +} + +VOID +NTAPI +HaliAcpiMachineStateInit(_In_ ULONG Par1, + _In_ PHALP_STATE_DATA StateData, + _Out_ ULONG* OutInterruptModel) +{ + POWER_STATE_HANDLER handler; + HALP_STATE_CONTEXT Context; + NTSTATUS Status; + + PAGED_CODE(); + DPRINT("HaliAcpiMachineStateInit: StateData %p\n", StateData); + + HalpWakeupState[0] = 1; + HalpWakeupState[1] = 0; + + *OutInterruptModel = 0; // PIC HAL + //*OutInterruptModel = 1; // APIC HAL + + if (StateData[0].Data0) + { + handler.Type = 0; + handler.RtcWake = TRUE; + handler.Handler = HaliAcpiSleep; + + Context.AsULONG = 0; + Context.Data1 = StateData[0].Data1; + Context.Data2 = StateData[0].Data2; + Context.Flags = 0x4; + + handler.Context = UlongToPtr(Context.AsULONG); + + Status = ZwPowerInformation(SystemPowerStateHandler, &handler, sizeof(handler), NULL, 0); + ASSERT(NT_SUCCESS(Status)); + } + + if (StateData[1].Data0 && HalpWakeVector) + { + handler.Type = PowerStateSleeping2; + handler.RtcWake = TRUE; + handler.Handler = HaliAcpiSleep; + + Context.AsULONG = 0; + Context.Data1 = StateData[1].Data1; + Context.Data2 = StateData[1].Data2; + Context.Flags = 0x17; + + handler.Context = UlongToPtr(Context.AsULONG); + + Status = ZwPowerInformation(SystemPowerStateHandler, &handler, sizeof(handler), NULL, 0); + ASSERT(NT_SUCCESS(Status)); + } + + if (StateData[2].Data0 && HalpWakeVector) + { + handler.Type = PowerStateSleeping3; + handler.RtcWake = TRUE; + handler.Handler = HaliAcpiSleep; + + Context.AsULONG = 0; + Context.Data1 = StateData[2].Data1; + Context.Data2 = StateData[2].Data2; + Context.Flags = 0x17; + + handler.Context = UlongToPtr(Context.AsULONG); + + Status = ZwPowerInformation(SystemPowerStateHandler, &handler, sizeof(handler), NULL, 0); + ASSERT(NT_SUCCESS(Status)); + } + + if (!HalpDisableHibernate) + { + if (StateData[3].Data0) + { + handler.Type = PowerStateSleeping4; + handler.RtcWake = ((HalpFixedAcpiDescTable.flags & 0x80) == 0x80); + handler.Handler = HaliAcpiSleep; + + Context.AsULONG = 0; + Context.Data1 = StateData[3].Data1; + Context.Data2 = StateData[3].Data2; + Context.Flags = 0x14; + + handler.Context = UlongToPtr(Context.AsULONG); + + Status = ZwPowerInformation(SystemPowerStateHandler, &handler, sizeof(handler), NULL, 0); + ASSERT(NT_SUCCESS(Status)); + } + else if (!StateData[4].Data0) + { + KeFlushWriteBuffer(); + return; + } + else if (!HalpDisableS5Hibernation) + { + handler.Type = PowerStateSleeping4; + handler.RtcWake = ((HalpFixedAcpiDescTable.flags & 0x80) == 0x80); + handler.Handler = HaliAcpiSleep; + + Context.AsULONG = 0; + Context.Data1 = StateData[4].Data1; + Context.Data2 = StateData[4].Data2; + Context.Flags = 0x14; + + handler.Context = UlongToPtr(Context.AsULONG); + + Status = ZwPowerInformation(SystemPowerStateHandler, &handler, sizeof(handler), NULL, 0); + ASSERT(NT_SUCCESS(Status)); + } + } + + if (StateData[4].Data0) + { + handler.Type = PowerStateShutdownOff; + handler.RtcWake = FALSE; + handler.Handler = HaliAcpiSleep; + + Context.AsULONG = 0; + Context.Data1 = StateData[4].Data1; + Context.Data2 = StateData[4].Data2; + Context.Flags = 0x8; + + HalpShutdownContext = Context.AsULONG; + handler.Context = UlongToPtr(Context.AsULONG); + + Status = ZwPowerInformation(SystemPowerStateHandler, &handler, sizeof(handler), NULL, 0); + ASSERT(NT_SUCCESS(Status)); + } + + KeFlushWriteBuffer(); +} + +ULONG +NTAPI +HaliAcpiQueryFlags(VOID) +{ + UNIMPLEMENTED; + ASSERT(0);// HalpDbgBreakPointEx(); + return 0; +} + +UCHAR +NTAPI +HalpAcpiPicStateIntact(VOID) +{ + UNIMPLEMENTED; + ASSERT(0);// HalpDbgBreakPointEx(); + return 0; +} + +VOID +NTAPI +HalpRestoreInterruptControllerState(VOID) +{ + UNIMPLEMENTED; + ASSERT(0);// HalpDbgBreakPointEx(); +} + +VOID +NTAPI +HaliSetVectorState(_In_ ULONG Par1, + _In_ ULONG Par2) +{ + /* Nothing for PIC */ + return; +} + +ULONG +NTAPI +HalpGetApicVersion(_In_ ULONG Par1) +{ + UNIMPLEMENTED; + ASSERT(0);// HalpDbgBreakPointEx(); + return 0; +} + +VOID +NTAPI +HaliSetMaxLegacyPciBusNumber(_In_ ULONG MaxLegacyPciBusNumber) +{ + HalpMaxPciBus = max(HalpMaxPciBus, MaxLegacyPciBusNumber); +} + +BOOLEAN +NTAPI +HaliIsVectorValid(_In_ ULONG Vector) +{ + DPRINT("HaliIsVectorValid: Vector %X\n", Vector); + + if (Vector >= 0x10) + { + DPRINT1("HaliIsVectorValid: Vector %X\n", Vector); + //ASSERT(Vector < 0x10); + } + + return (Vector < 0x10); +} + +/* EOF */ diff --git a/hal/halacpi/acpi/dispatch.h b/hal/halacpi/acpi/dispatch.h new file mode 100644 index 0000000000000..b5bc699aa7df2 --- /dev/null +++ b/hal/halacpi/acpi/dispatch.h @@ -0,0 +1,177 @@ + +#pragma once + +#include +typedef struct _HALP_TIMER_INFO +{ + PULONG TimerPort; + LARGE_INTEGER AcpiTimeValue; + ULONG TimerCarry; + ULONG ValueExt; + LARGE_INTEGER PerformanceCounter; + ULONGLONG Unknown1; + ULONG Unknown2; +} HALP_TIMER_INFO, *PHALP_TIMER_INFO; +#include + +typedef struct _HALP_STATE_DATA { + UCHAR Data0; + UCHAR Data1; + UCHAR Data2; +} HALP_STATE_DATA, *PHALP_STATE_DATA; + +typedef union _HALP_STATE_CONTEXT { + struct { + ULONG Data1 :4; // 0 BitPosition + ULONG Data2 :4; // 4 BitPosition + ULONG Flags :8; // 8 BitPosition + ULONG Pad :16; // 16 BitPosition + }; + ULONG AsULONG; +} HALP_STATE_CONTEXT, *PHALP_STATE_CONTEXT; + +typedef VOID +(NTAPI * PHAL_ACPI_TIMER_INIT)( + _In_ PULONG TimerPort, + _In_ BOOLEAN TimerValExt +); + +typedef VOID +(NTAPI * PHAL_ACPI_MACHINE_STATE_INIT)( + _In_ ULONG Par1, + _In_ PHALP_STATE_DATA StateData, + _Out_ ULONG* OutInterruptModel +); + +typedef ULONG +(NTAPI * PHAL_ACPI_QUERY_FLAGS)( + VOID +); + +typedef UCHAR +(NTAPI * PHAL_ACPI_PIC_STATE_INTACT)( + VOID +); + +typedef VOID +(NTAPI * PHAL_RESTORE_INT_CONTROLLER_STATE)( + VOID +); + +typedef ULONG +(NTAPI * PHAL_PCI_INTERFACE_READ_CONFIG)( + _In_ PBUS_HANDLER RootBusHandler, + _In_ ULONG BusNumber, + _In_ PCI_SLOT_NUMBER SlotNumber, + _In_ PVOID Buffer, + _In_ ULONG Offset, + _In_ ULONG Length +); + +typedef ULONG +(NTAPI * PHAL_PCI_INTERFACE_WRITE_CONFIG)( + _In_ PBUS_HANDLER RootBusHandler, + _In_ ULONG BusNumber, + _In_ PCI_SLOT_NUMBER SlotNumber, + _In_ PVOID Buffer, + _In_ ULONG Offset, + _In_ ULONG Length +); + +typedef VOID +(NTAPI * PHAL_SET_VECTOR_STATE)( + _In_ ULONG Par1, + _In_ ULONG Par2 +); + +typedef VOID +(NTAPI * PHAL_SET_VECTOR_STATE)( + _In_ ULONG Par1, + _In_ ULONG Par2 +); + +typedef ULONG +(NTAPI * PHAL_GET_APIC_VERSION)( + _In_ ULONG Par1 +); + +typedef VOID +(NTAPI * PHAL_SET_MAX_LEGACY_PCI_BUS_NUMBER)( + _In_ ULONG Par1 +); + +typedef BOOLEAN +(NTAPI * PHAL_IS_VECTOR_VALID)( + _In_ ULONG Vector +); + +typedef struct _ACPI_PM_DISPATCH_TABLE +{ + ULONG Signature; + ULONG Version; + PHAL_ACPI_TIMER_INIT HalAcpiTimerInit; // HaliAcpiTimerInit + PVOID HalAcpiTimerInterrupt; + PHAL_ACPI_MACHINE_STATE_INIT HalAcpiMachineStateInit; // HaliAcpiMachineStateInit + PHAL_ACPI_QUERY_FLAGS HalAcpiQueryFlags; // HaliAcpiQueryFlags + PHAL_ACPI_PIC_STATE_INTACT HalAcpiPicStateIntact; // HalpAcpiPicStateIntact + PHAL_RESTORE_INT_CONTROLLER_STATE HalRestoreIntControllerState; // HalpRestoreInterruptControllerState + PHAL_PCI_INTERFACE_READ_CONFIG HalPciInterfaceReadConfig; // HaliPciInterfaceReadConfig + PHAL_PCI_INTERFACE_WRITE_CONFIG HalPciInterfaceWriteConfig; // HaliPciInterfaceWriteConfig + PHAL_SET_VECTOR_STATE HalSetVectorState; // HaliSetVectorState + PHAL_GET_APIC_VERSION HalGetApicVersion; // HalpGetApicVersion + PHAL_SET_MAX_LEGACY_PCI_BUS_NUMBER HalSetMaxLegacyPciBusNumber; // HaliSetMaxLegacyPciBusNumber + PHAL_IS_VECTOR_VALID HalIsVectorValid; // HaliIsVectorValid +} ACPI_PM_DISPATCH_TABLE, *PACPI_PM_DISPATCH_TABLE; + +VOID +NTAPI +HaliAcpiMachineStateInit( + _In_ ULONG Par1, + _In_ PHALP_STATE_DATA StateData, + _Out_ ULONG* OutInterruptModel +); + +ULONG +NTAPI +HaliAcpiQueryFlags( + VOID +); + +UCHAR +NTAPI +HalpAcpiPicStateIntact( + VOID +); + +VOID +NTAPI +HalpRestoreInterruptControllerState( + VOID +); + +VOID +NTAPI +HaliSetVectorState( + _In_ ULONG Par1, + _In_ ULONG Par2 +); + +ULONG +NTAPI +HalpGetApicVersion( + _In_ ULONG Par1 +); + +VOID +NTAPI +HaliSetMaxLegacyPciBusNumber( + _In_ ULONG MaxLegacyPciBusNumber +); + +BOOLEAN +NTAPI +HaliIsVectorValid( + _In_ ULONG Vector +); + +/* EOF */ diff --git a/hal/halacpi/acpi/halacpi.c b/hal/halacpi/acpi/halacpi.c new file mode 100644 index 0000000000000..9d9adf40eb677 --- /dev/null +++ b/hal/halacpi/acpi/halacpi.c @@ -0,0 +1,1241 @@ + +/* INCLUDES *******************************************************************/ + +#include +//#define NDEBUG +#include + +#if defined(ALLOC_PRAGMA) && !defined(_MINIHAL_) + #pragma alloc_text(INIT, HalAcpiGetTable) + #pragma alloc_text(INIT, HalpCheckPowerButton) + #pragma alloc_text(INIT, HalpGetNMICrashFlag) + #pragma alloc_text(INIT, HalpInitializePciBus) + #pragma alloc_text(INIT, HalReportResourceUsage) +#endif + +/* GLOBALS ********************************************************************/ + +PWCHAR HalName = L"ACPI Compatible Eisa/Isa HAL"; + +PHYSICAL_ADDRESS HalpMaxHotPlugMemoryAddress; +PHYSICAL_ADDRESS HalpLowStubPhysicalAddress; +FAST_MUTEX HalpAcpiTableCacheLock; +LIST_ENTRY HalpAcpiTableCacheList; +LIST_ENTRY HalpAcpiTableMatchList; +PACPI_BIOS_MULTI_NODE HalpAcpiMultiNode; +FADT HalpFixedAcpiDescTable; +PDEBUG_PORT_TABLE HalpDebugPortTable; +PACPI_SRAT HalpAcpiSrat; +PBOOT_TABLE HalpSimpleBootFlagTable; +PHARDWARE_PTE HalpPteForFlush; +PVOID HalpVirtAddrForFlush; +PVOID HalpLowStub; +ULONG HalpWAETDeviceFlags = 0; +ULONG HalpInvalidAcpiTable; +ULONG HalpShutdownContext = 0; +BOOLEAN HalpProcessedACPIPhase0; +BOOLEAN HalpNMIDumpFlag; + +extern BOOLEAN LessThan16Mb; +extern BOOLEAN HalpPhysicalMemoryMayAppearAbove4GB; +extern ULONG HalpBusType; +extern ULONG HalpPicVectorRedirect[16]; +extern PPM_DISPATCH_TABLE PmAcpiDispatchTable; + +/* PRIVATE FUNCTIONS **********************************************************/ + +NTSTATUS +NTAPI +HalpAcpiFindRsdtPhase0(IN PLOADER_PARAMETER_BLOCK LoaderBlock, + OUT PACPI_BIOS_MULTI_NODE* AcpiMultiNode) +{ + PCONFIGURATION_COMPONENT_DATA ComponentEntry; + PCONFIGURATION_COMPONENT_DATA Next = NULL; + PCM_PARTIAL_RESOURCE_LIST ResourceList; + PACPI_BIOS_MULTI_NODE NodeData; + SIZE_T NodeLength; + PFN_COUNT PageCount; + PVOID MappedAddress; + PHYSICAL_ADDRESS PhysicalAddress; + + DPRINT("HalpAcpiFindRsdtPhase0: ... \n"); + + /* Did we already do this once? */ + if (HalpAcpiMultiNode) + { + /* Return what we know */ + *AcpiMultiNode = HalpAcpiMultiNode; + return STATUS_SUCCESS; + } + + /* Assume failure */ + *AcpiMultiNode = NULL; + + /* Find the multi function adapter key */ + ComponentEntry = KeFindConfigurationNextEntry(LoaderBlock->ConfigurationRoot, AdapterClass, MultiFunctionAdapter, NULL, &Next); + + while (ComponentEntry) + { + /* Find the ACPI BIOS key */ + if (!_stricmp(ComponentEntry->ComponentEntry.Identifier, "ACPI BIOS")) + { + /* Found it */ + break; + } + + /* Keep searching */ + Next = ComponentEntry; + ComponentEntry = KeFindConfigurationNextEntry(LoaderBlock->ConfigurationRoot, AdapterClass, MultiFunctionAdapter, NULL, &Next); + } + + /* Make sure we found it */ + if (!ComponentEntry) + { + DPRINT1("**** HalpAcpiFindRsdtPhase0: did NOT find RSDT\n"); + return STATUS_NOT_FOUND; + } + + /* The configuration data is a resource list, and the BIOS node follows */ + ResourceList = ComponentEntry->ConfigurationData; + NodeData = (PACPI_BIOS_MULTI_NODE)(ResourceList + 1); + + /* How many E820 memory entries are there? */ + NodeLength = sizeof(ACPI_BIOS_MULTI_NODE) + ((NodeData->Count - 1) * sizeof(ACPI_E820_ENTRY)); + + /* Convert to pages */ + PageCount = (PFN_COUNT)BYTES_TO_PAGES(NodeLength); + + /* Allocate the memory */ + PhysicalAddress.QuadPart = HalpAllocPhysicalMemory(LoaderBlock, 0x1000000, PageCount, FALSE); + + if (PhysicalAddress.QuadPart) + { + /* Map it if the allocation worked */ + MappedAddress = HalpMapPhysicalMemory64(PhysicalAddress, PageCount); + } + else + { + /* Otherwise we'll have to fail */ + MappedAddress = NULL; + } + + /* Save the multi node, bail out if we didn't find it */ + HalpAcpiMultiNode = MappedAddress; + if (!HalpAcpiMultiNode) { + DPRINT1("STATUS_INSUFFICIENT_RESOURCES\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Copy the multi-node data */ + RtlCopyMemory(MappedAddress, NodeData, NodeLength); + + /* Return the data */ + *AcpiMultiNode = HalpAcpiMultiNode; + + return STATUS_SUCCESS; +} + +PVOID +NTAPI +HalpAcpiCopyBiosTable(IN PLOADER_PARAMETER_BLOCK LoaderBlock, + IN PDESCRIPTION_HEADER TableHeader) +{ + ULONG Size; + PFN_COUNT PageCount; + PHYSICAL_ADDRESS PhysAddress; + PACPI_CACHED_TABLE CachedTable; + PDESCRIPTION_HEADER CopiedTable; + + /* Size we'll need for the cached table */ + Size = TableHeader->Length + FIELD_OFFSET(ACPI_CACHED_TABLE, Header); + + if (LoaderBlock) + { + /* Phase 0: Convert to pages and use the HAL heap */ + PageCount = BYTES_TO_PAGES(Size); + PhysAddress.QuadPart = HalpAllocPhysicalMemory(LoaderBlock, 0x1000000, PageCount, FALSE); + + if (PhysAddress.QuadPart) + { + /* Map it */ + CachedTable = HalpMapPhysicalMemory64(PhysAddress, PageCount); + } + else + { + /* No memory, so nothing to map */ + CachedTable = NULL; + } + } + else + { + /* Use Mm pool */ + CachedTable = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_HAL); + } + + /* Do we have the cached table? */ + if (CachedTable) + { + /* Copy the data */ + CopiedTable = &CachedTable->Header; + RtlCopyMemory(CopiedTable, TableHeader, TableHeader->Length); + } + else + { + /* Nothing to return */ + CopiedTable = NULL; + } + + /* Return the table */ + return CopiedTable; +} + +VOID +NTAPI +HalpAcpiCacheTable(IN PDESCRIPTION_HEADER TableHeader) +{ + PACPI_CACHED_TABLE CachedTable; + + /* Get the cached table and link it */ + CachedTable = CONTAINING_RECORD(TableHeader, ACPI_CACHED_TABLE, Header); + InsertTailList(&HalpAcpiTableCacheList, &CachedTable->Links); +} + +NTSTATUS +NTAPI +HalpAcpiTableCacheInit(IN PLOADER_PARAMETER_BLOCK LoaderBlock) +{ + PLOADER_PARAMETER_EXTENSION LoaderExtension; + PACPI_BIOS_MULTI_NODE AcpiMultiNode; + PHYSICAL_ADDRESS PhysicalAddress; + PVOID MappedAddress; + ULONG TableLength; + PRSDT Rsdt; + NTSTATUS Status = STATUS_SUCCESS; + + //DPRINT("HalpAcpiTableCacheInit: LoaderBlock %X\n", LoaderBlock); + + /* Only initialize once */ + if (HalpAcpiTableCacheList.Flink) + return Status; + + /* Setup the lock and table */ + ExInitializeFastMutex(&HalpAcpiTableCacheLock); + InitializeListHead(&HalpAcpiTableCacheList); + + /* Find the RSDT */ + Status = HalpAcpiFindRsdtPhase0(LoaderBlock, &AcpiMultiNode); + if (!NT_SUCCESS(Status)) + return Status; + + PhysicalAddress.QuadPart = AcpiMultiNode->RsdtAddress.QuadPart; + + /* Map the RSDT */ + if (LoaderBlock) + { + /* Phase0: Use HAL Heap to map the RSDT, we assume it's about 2 pages */ + MappedAddress = HalpMapPhysicalMemory64(PhysicalAddress, 2); + } + else + { + /* Use an I/O map */ + MappedAddress = MmMapIoSpace(PhysicalAddress, PAGE_SIZE * 2, MmNonCached); + } + + /* Get the RSDT */ + Rsdt = MappedAddress; + if (!MappedAddress) + { + /* Fail, no memory */ + DPRINT1("HAL: Failed to map RSDT\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Validate it */ + if ((Rsdt->Header.Signature != RSDT_SIGNATURE) && + (Rsdt->Header.Signature != XSDT_SIGNATURE)) + { + /* Very bad: crash */ + HalDisplayString("Bad RSDT pointer\r\n"); + KeBugCheckEx(MISMATCHED_HAL, 4, __LINE__, 0, 0); + } + + /* We assumed two pages -- do we need less or more? */ + TableLength = ADDRESS_AND_SIZE_TO_SPAN_PAGES(PhysicalAddress.LowPart, Rsdt->Header.Length); + + if (TableLength != 2) + { + /* Are we in phase 0 or 1? */ + if (!LoaderBlock) + { + /* Unmap the old table, remap the new one, using Mm I/O space */ + MmUnmapIoSpace(MappedAddress, 2 * PAGE_SIZE); + MappedAddress = MmMapIoSpace(PhysicalAddress, (TableLength << PAGE_SHIFT), MmNonCached); + } + else + { + /* Unmap the old table, remap the new one, using HAL heap */ + HalpUnmapVirtualAddress(MappedAddress, 2); + MappedAddress = HalpMapPhysicalMemory64(PhysicalAddress, TableLength); + } + + /* Get the remapped table */ + Rsdt = MappedAddress; + if (!MappedAddress) + { + /* Fail, no memory */ + DPRINT1("HAL: Couldn't remap RSDT\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + } + + /* Now take the BIOS copy and make our own local copy */ + Rsdt = HalpAcpiCopyBiosTable(LoaderBlock, &Rsdt->Header); + if (!Rsdt) + { + /* Fail, no memory */ + DPRINT1("HAL: Couldn't remap RSDT\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Get rid of the BIOS mapping */ + if (LoaderBlock) + { + /* Use HAL heap */ + HalpUnmapVirtualAddress(MappedAddress, TableLength); + LoaderExtension = LoaderBlock->Extension; + } + else + { + /* Use Mm */ + MmUnmapIoSpace(MappedAddress, TableLength << PAGE_SHIFT); + LoaderExtension = NULL; + } + + /* Cache the RSDT */ + HalpAcpiCacheTable(&Rsdt->Header); + + /* Check for compatible loader block extension */ + if (LoaderExtension && (LoaderExtension->Size >= 0x58)) + { + /* Compatible loader: did it provide an ACPI table override? */ + if ((LoaderExtension->AcpiTable) && (LoaderExtension->AcpiTableSize)) + { + /* Great, because we don't support it! */ + DPRINT1("ACPI Table Overrides Not Supported!\n"); + } + } + + /* Done */ + return Status; +} + +VOID +NTAPI +HalpNumaInitializeStaticConfiguration(IN PLOADER_PARAMETER_BLOCK LoaderBlock) +{ + PACPI_SRAT SratTable; + + /* Get the SRAT */ + SratTable = HalAcpiGetTable(LoaderBlock, SRAT_SIGNATURE); + + HalpAcpiSrat = SratTable; + if (!HalpAcpiSrat) + return; + + UNIMPLEMENTED; + ASSERT(0);// HalpDbgBreakPointEx(); +} + +VOID +NTAPI +HalpGetHotPlugMemoryInfo(IN PLOADER_PARAMETER_BLOCK LoaderBlock) +{ + PACPI_SRAT SratTable; + + /* Get the SRAT */ + SratTable = HalAcpiGetTable(LoaderBlock, SRAT_SIGNATURE); + if (!SratTable) + return; + + UNIMPLEMENTED; + ASSERT(0);// HalpDbgBreakPointEx(); +} + +VOID +NTAPI +HalpDynamicSystemResourceConfiguration(IN PLOADER_PARAMETER_BLOCK LoaderBlock) +{ + /* For this HAL, it means to get hot plug memory information */ + HalpGetHotPlugMemoryInfo(LoaderBlock); +} + +VOID +NTAPI +HalpEndOfBoot(VOID) +{ + DPRINT1("HalpEndOfBoot: not implemented, FIXME!\n"); + //ASSERT(0);// HalpDbgBreakPointEx(); +} + +VOID +NTAPI +HalpInitBootTable(IN PLOADER_PARAMETER_BLOCK LoaderBlock) +{ + PBOOT_TABLE BootTable; + + DPRINT("HalpInitBootTable()\n"); + + /* Get the boot table */ + BootTable = HalAcpiGetTable(LoaderBlock, BOOT_SIGNATURE); + HalpSimpleBootFlagTable = BootTable; + + /* Validate it */ + if ((BootTable) && + (BootTable->Header.Length >= sizeof(BOOT_TABLE)) && + (BootTable->CMOSIndex >= 9)) + { + DPRINT1("ACPI Boot table found, but not supported!\n"); + } + else + { + /* Invalid or doesn't exist, ignore it */ + HalpSimpleBootFlagTable = 0; + } + + /* Install the end of boot handler */ + HalEndOfBoot = HalpEndOfBoot; +} + +CODE_SEG("INIT") +NTSTATUS +NTAPI +HalpSetupAcpiPhase0(IN PLOADER_PARAMETER_BLOCK LoaderBlock) +{ + PHYSICAL_ADDRESS PhysicalAddress; + ULONG_PTR EmulatedDevicesTable = 0; + PFADT Fadt; + ULONG TableLength; + NTSTATUS Status; + + DPRINT("HalpSetupAcpiPhase0()\n"); + + /* Only do this once */ + if (HalpProcessedACPIPhase0) { + DPRINT("HalpProcessedACPIPhase0 - TRUE\n"); + return STATUS_SUCCESS; + } + + /* Setup the ACPI table cache */ + Status = HalpAcpiTableCacheInit(LoaderBlock); + if (!NT_SUCCESS(Status)) { + DPRINT1("HalpSetupAcpiPhase0: Status %X\n", Status); + return Status; + } + + /* Grab the FADT */ + Fadt = HalAcpiGetTable(LoaderBlock, FADT_SIGNATURE); + if (!Fadt) { + DPRINT1("HAL: Didn't find the FACP\n"); + return STATUS_NOT_FOUND; + } + + /* Assume typical size, otherwise whatever the descriptor table says */ + TableLength = sizeof(FADT); + if (Fadt->Header.Length < TableLength) { + TableLength = Fadt->Header.Length; + } + + /* Copy it in the HAL static buffer */ + RtlCopyMemory(&HalpFixedAcpiDescTable, Fadt, TableLength); + + /* Anything special this HAL needs to do? */ + //HalpAcpiDetectMachineSpecificActions(LoaderBlock, &HalpFixedAcpiDescTable); // not need for halacpi.dll + + /* Get the debug table for KD */ + HalpDebugPortTable = HalAcpiGetTable(LoaderBlock, DBGP_SIGNATURE); + if (HalpDebugPortTable) { + DPRINT1("HalpDebugPortTable %X\n", HalpDebugPortTable); + } + + /* Initialize NUMA through the SRAT */ + HalpNumaInitializeStaticConfiguration(LoaderBlock); + + /* Initialize hotplug through the SRAT */ + HalpDynamicSystemResourceConfiguration(LoaderBlock); + if (HalpAcpiSrat) { + DPRINT1("HalpSetupAcpiPhase0: SRAT, but NUMA/HotPlug are not supported!\n"); + } + + EmulatedDevicesTable = (ULONG_PTR)HalAcpiGetTable(LoaderBlock, 'TEAW'); + if (EmulatedDevicesTable) { + HalpWAETDeviceFlags = *(PULONG)(EmulatedDevicesTable + 36); // FIXME + DPRINT1("HalpSetupAcpiPhase0: FIXME HalpWAETDeviceFlags %X\n", HalpWAETDeviceFlags); + } + + /* Can there be memory higher than 4GB? */ + if (HalpMaxHotPlugMemoryAddress.HighPart >= 1) { + /* We'll need this for DMA later */ + HalpPhysicalMemoryMayAppearAbove4GB = TRUE; + DPRINT1("HalpPhysicalMemoryMayAppearAbove4GB - TRUE\n"); + } + + /* Setup the ACPI timer */ + HaliAcpiTimerInit(NULL, FALSE); + + /* Do we have a low stub address yet? */ + if (!HalpLowStubPhysicalAddress.QuadPart) + { + /* Allocate it */ + HalpLowStubPhysicalAddress.QuadPart = HalpAllocPhysicalMemory(LoaderBlock, 0x100000, 1, FALSE); + if (HalpLowStubPhysicalAddress.QuadPart) + { + /* Map it */ + HalpLowStub = HalpMapPhysicalMemory64(HalpLowStubPhysicalAddress, 1); + } + } + + /* Grab a page for flushes */ + PhysicalAddress.QuadPart = 0x100000; + HalpVirtAddrForFlush = HalpMapPhysicalMemory64(PhysicalAddress, 1); + HalpPteForFlush = HalAddressToPte(HalpVirtAddrForFlush); + + /* Don't do this again */ + HalpProcessedACPIPhase0 = TRUE; + + /* Setup the boot table */ + HalpInitBootTable(LoaderBlock); + +#if DBG + /* Debugging code */ + { + PLIST_ENTRY ListHead, NextEntry; + PACPI_CACHED_TABLE CachedTable; + + /* Loop cached tables */ + ListHead = &HalpAcpiTableCacheList; + NextEntry = ListHead->Flink; + + while (NextEntry != ListHead) + { + /* Get the table */ + CachedTable = CONTAINING_RECORD(NextEntry, ACPI_CACHED_TABLE, Links); + + /* Compare signatures */ + if ((CachedTable->Header.Signature == RSDT_SIGNATURE) || + (CachedTable->Header.Signature == XSDT_SIGNATURE)) + { + DPRINT1("ACPI %d.0 Detected. ", (CachedTable->Header.Revision + 1)); + } + + DbgPrint("[%c%c%c%c] ", + (CachedTable->Header.Signature & 0xFF), + (CachedTable->Header.Signature & 0xFF00) >> 8, + (CachedTable->Header.Signature & 0xFF0000) >> 16, + (CachedTable->Header.Signature & 0xFF000000) >> 24); + + /* Keep going */ + NextEntry = NextEntry->Flink; + } + + DbgPrint("\n"); + } +#endif + + return STATUS_SUCCESS; +} + +PDESCRIPTION_HEADER +NTAPI +HalpAcpiGetCachedTable(IN ULONG Signature) +{ + PLIST_ENTRY ListHead, NextEntry; + PACPI_CACHED_TABLE CachedTable; + + //DPRINT("HalpAcpiGetCachedTable: Signature %X\n", Signature); + + /* Loop cached tables */ + ListHead = &HalpAcpiTableCacheList; + NextEntry = ListHead->Flink; + + while (NextEntry != ListHead) + { + /* Get the table */ + CachedTable = CONTAINING_RECORD(NextEntry, ACPI_CACHED_TABLE, Links); + + /* Compare signatures */ + if (CachedTable->Header.Signature == Signature) + return &CachedTable->Header; + + /* Keep going */ + NextEntry = NextEntry->Flink; + } + + /* Nothing found */ + return NULL; +} + +PVOID +NTAPI +HalpAcpiGetTableFromBios(IN PLOADER_PARAMETER_BLOCK LoaderBlock, + IN ULONG Signature) +{ + PHYSICAL_ADDRESS PhysicalAddress; + PXSDT Xsdt; + PRSDT Rsdt; + PFADT Fadt; + PDESCRIPTION_HEADER Header = NULL; + ULONG TableLength; + CHAR CheckSum = 0; + ULONG Offset; + ULONG EntryCount, CurrentEntry; + PCHAR CurrentByte; + PFN_COUNT PageCount; + + //DPRINT("HalpAcpiGetTableFromBios: Signature %X\n", Signature); + + /* Should not query the RSDT/XSDT by itself */ + if ((Signature == RSDT_SIGNATURE) || (Signature == XSDT_SIGNATURE)) + return NULL; + + /* Special case request for DSDT, because the FADT points to it */ + if (Signature == DSDT_SIGNATURE) + { + /* Grab the FADT */ + Fadt = HalpAcpiGetTable(LoaderBlock, FADT_SIGNATURE); + if (!Fadt) + /* Couldn't find it */ + return NULL; + + /* Grab the DSDT address and assume 2 pages */ + PhysicalAddress.HighPart = 0; + PhysicalAddress.LowPart = Fadt->dsdt; + TableLength = 2 * PAGE_SIZE; + + /* Map it */ + if (LoaderBlock) + /* Phase 0, use HAL heap */ + Header = HalpMapPhysicalMemory64(PhysicalAddress, 2); + else + /* Phase 1, use Mm */ + Header = MmMapIoSpace(PhysicalAddress, 2 * PAGE_SIZE, 0); + + /* Fail if we couldn't map it */ + if (!Header) + { + DPRINT1("HAL: Failed to map ACPI table.\n"); + return NULL; + } + + /* Validate the signature */ + if (Header->Signature != DSDT_SIGNATURE) + { + /* Fail and unmap */ + if (LoaderBlock) + /* Using HAL heap */ + HalpUnmapVirtualAddress(Header, 2); + else + /* Using Mm */ + MmUnmapIoSpace(Header, 2 * PAGE_SIZE); + + /* Didn't find anything */ + return NULL; + } + } + else + { + /* To find tables, we need the RSDT */ + Rsdt = HalpAcpiGetTable(LoaderBlock, RSDT_SIGNATURE); + if (Rsdt) + { + /* Won't be using the XSDT */ + Xsdt = NULL; + } + else + { + /* Only other choice is to use the XSDT */ + Xsdt = HalpAcpiGetTable(LoaderBlock, XSDT_SIGNATURE); + if (!Xsdt) + return NULL; + + /* Won't be using the RSDT */ + Rsdt = NULL; + } + + /* Smallest RSDT/XSDT is one without table entries */ + Offset = FIELD_OFFSET(RSDT, Tables); + if (Xsdt) + { + /* Figure out total size of table and the offset */ + TableLength = Xsdt->Header.Length; + if (TableLength < Offset) + Offset = Xsdt->Header.Length; + + /* The entries are each 64-bits, so count them */ + EntryCount = ((TableLength - Offset) / sizeof(PHYSICAL_ADDRESS)); + } + else + { + /* Figure out total size of table and the offset */ + TableLength = Rsdt->Header.Length; + if (TableLength < Offset) + Offset = Rsdt->Header.Length; + + /* The entries are each 32-bits, so count them */ + EntryCount = ((TableLength - Offset) / sizeof(ULONG)); + } + + /* Start at the beginning of the array and loop it */ + for (CurrentEntry = 0; CurrentEntry < EntryCount; CurrentEntry++) + { + /* Are we using the XSDT? */ + if (!Xsdt) + { + /* Read the 32-bit physical address */ + PhysicalAddress.LowPart = Rsdt->Tables[CurrentEntry]; + PhysicalAddress.HighPart = 0; + } + else + { + /* Read the 64-bit physical address */ + PhysicalAddress = Xsdt->Tables[CurrentEntry]; + } + + /* Had we already mapped a table? */ + if (Header) + { + /* Yes, unmap it */ + if (LoaderBlock) + /* Using HAL heap */ + HalpUnmapVirtualAddress(Header, 2); + else + /* Using Mm */ + MmUnmapIoSpace(Header, 2 * PAGE_SIZE); + } + + /* Now map this table */ + + if (!LoaderBlock) + /* Phase 1: Use HAL heap */ + Header = MmMapIoSpace(PhysicalAddress, 2 * PAGE_SIZE, MmNonCached); + else + /* Phase 0: Use Mm */ + Header = HalpMapPhysicalMemory64(PhysicalAddress, 2); + + /* Check if we mapped it */ + if (!Header) + { + DPRINT1("HAL: Failed to map ACPI table.\n"); + return NULL; + } + + /* We found it, break out */ + DPRINT("Found ACPI table %c%c%c%c at 0x%p\n", + Header->Signature & 0xFF, + (Header->Signature & 0xFF00) >> 8, + (Header->Signature & 0xFF0000) >> 16, + (Header->Signature & 0xFF000000) >> 24, + Header); + + if (Header->Signature == Signature) + break; + } + + /* Did we end up here back at the last entry? */ + if (CurrentEntry == EntryCount) + { + /* Yes, unmap the last table we processed */ + if (LoaderBlock) + HalpUnmapVirtualAddress(Header, 2); + else + MmUnmapIoSpace(Header, 2 * PAGE_SIZE); + + return NULL; + } + } + + /* Past this point, we assume something was found */ + ASSERT(Header); + + /* How many pages do we need? */ + PageCount = BYTES_TO_PAGES(Header->Length); + if (PageCount != 2) + { + /* We assumed two, but this is not the case, free the current mapping */ + if (LoaderBlock) + HalpUnmapVirtualAddress(Header, 2); + else + MmUnmapIoSpace(Header, 2 * PAGE_SIZE); + + /* Now map this table using its correct size */ + + if (!LoaderBlock) + /* Phase 1: Use HAL heap */ + Header = MmMapIoSpace(PhysicalAddress, PageCount << PAGE_SHIFT, MmNonCached); + else + /* Phase 0: Use Mm */ + Header = HalpMapPhysicalMemory64(PhysicalAddress, PageCount); + } + + /* Fail if the remapped failed */ + if (!Header) + return NULL; + + /* All tables in ACPI 3.0 other than the FACP should have correct checksum */ + if ((Header->Signature == FADT_SIGNATURE) && (Header->Revision < 3)) + return Header; + + /* Go to the end of the table */ + CheckSum = 0; + CurrentByte = (PCHAR)Header + Header->Length; + + while (CurrentByte-- != (PCHAR)Header) + CheckSum += *CurrentByte; + + /* The correct checksum is always 0, anything else is illegal */ + if (CheckSum) + { + HalpInvalidAcpiTable = Header->Signature; + DPRINT1("Checksum failed on ACPI table %c%c%c%c\n", + (Signature & 0xFF), + (Signature & 0xFF00) >> 8, + (Signature & 0xFF0000) >> 16, + (Signature & 0xFF000000) >> 24); + } + + /* Return the table */ + return Header; +} + +PVOID +NTAPI +HalpAcpiGetTable(IN PLOADER_PARAMETER_BLOCK LoaderBlock, + IN ULONG Signature) +{ + PFN_COUNT PageCount; + PDESCRIPTION_HEADER TableAddress, BiosCopy; + + //DPRINT("HalpAcpiGetTable: Signature %X\n", Signature); + + /* See if we have a cached table? */ + TableAddress = HalpAcpiGetCachedTable(Signature); + if (TableAddress) + return TableAddress; + + /* No cache, search the BIOS */ + TableAddress = HalpAcpiGetTableFromBios(LoaderBlock, Signature); + if (!TableAddress) + return NULL; + + /* Found it, copy it into our own memory */ + BiosCopy = HalpAcpiCopyBiosTable(LoaderBlock, TableAddress); + + /* Get the pages, and unmap the BIOS copy */ + PageCount = BYTES_TO_PAGES(TableAddress->Length); + + if (LoaderBlock) + /* Phase 0, use the HAL heap */ + HalpUnmapVirtualAddress(TableAddress, PageCount); + else + /* Phase 1, use Mm */ + MmUnmapIoSpace(TableAddress, PageCount << PAGE_SHIFT); + + /* Cache the bios copy */ + TableAddress = BiosCopy; + if (BiosCopy) + HalpAcpiCacheTable(BiosCopy); + + return TableAddress; +} + +CODE_SEG("INIT") +PVOID +NTAPI +HalAcpiGetTable(IN PLOADER_PARAMETER_BLOCK LoaderBlock, + IN ULONG Signature) +{ + PDESCRIPTION_HEADER TableHeader; + NTSTATUS Status; + + DPRINT("HalAcpiGetTable: Signature %X\n", Signature); + + /* Is this phase0 */ + if (LoaderBlock) + { + /* Initialize the cache first */ + Status = HalpAcpiTableCacheInit(LoaderBlock); + if (!NT_SUCCESS(Status)) + { + DPRINT1("HalAcpiGetTable: Status %X\n", Status); + return NULL; + } + } + else + { + /* Lock the cache */ + ExAcquireFastMutex(&HalpAcpiTableCacheLock); + } + + /* Get the table */ + TableHeader = HalpAcpiGetTable(LoaderBlock, Signature); + + /* Release the lock in phase 1 */ + if (!LoaderBlock) + ExReleaseFastMutex(&HalpAcpiTableCacheLock); + + /* Return the table */ + return TableHeader; +} + +VOID +NTAPI +HalpWriteResetCommand(VOID) +{ + if (HalpFixedAcpiDescTable.Header.Revision > 1 && + (HalpFixedAcpiDescTable.flags & 4) && + !(HalpFixedAcpiDescTable.boot_arch & 2)) + { + DPRINT1("HalpWriteResetCommand: Revision %X, flags %X, boot_arch %X\n", + HalpFixedAcpiDescTable.Header.Revision, HalpFixedAcpiDescTable.flags, HalpFixedAcpiDescTable.boot_arch); + + ASSERT(FALSE); // HalpDbgBreakPointEx(); + } + + /* Generate RESET signal via keyboard controller */ + WRITE_PORT_UCHAR((PUCHAR)0x64, 0xFE); +}; + +typedef VOID +(NTAPI* PM_ACPI_DISPATCH_FUNCTION0)(ULONG); + +CODE_SEG("INIT") +VOID +NTAPI +HalpCheckPowerButton(VOID) +{ + PM_ACPI_DISPATCH_FUNCTION0 Function0; + PUSHORT Port; + ULONG OldContext; + USHORT ValueA; + USHORT ValueB; + + DPRINT1("HalpCheckPowerButton: HalpShutdownContext %X\n", HalpShutdownContext); + + if ((!KiBugCheckData[0] && !InbvCheckDisplayOwnership()) || + !HalpShutdownContext) + { + DPRINT1("HalpCheckPowerButton: FIXME\n"); + ASSERT(FALSE); // HalpDbgBreakPointEx(); + return; + } + + Port = (PUSHORT)HalpFixedAcpiDescTable.pm1a_evt_blk_io_port; + ValueA = READ_PORT_USHORT(Port); + + DPRINT1("HalpCheckPowerButton: ValueA %X\n", ValueA); + + Port = (PUSHORT)HalpFixedAcpiDescTable.pm1b_evt_blk_io_port; + if (Port) + { + ValueB = (READ_PORT_USHORT(Port) | ValueA); + DPRINT1("HalpCheckPowerButton: ValueB %X\n", ValueB); + } + else + { + ValueB = ValueA; + } + + if (!(ValueB & 0x100)) + { + DPRINT1("HalpCheckPowerButton: ValueB %X\n", ValueB); + ASSERT(FALSE); // HalpDbgBreakPointEx(); + return; + } + + OldContext = HalpShutdownContext; + HalpShutdownContext = 0; + DPRINT1("HalpCheckPowerButton: OldContext %X\n", OldContext); + + Function0 = PmAcpiDispatchTable->Function[0]; + Function0(0); + + Port = (PUSHORT)HalpFixedAcpiDescTable.pm1a_evt_blk_io_port; + WRITE_PORT_USHORT(Port, ValueB); + + Port = (PUSHORT)HalpFixedAcpiDescTable.pm1b_evt_blk_io_port; + if (Port) + WRITE_PORT_USHORT(Port, ValueB); + + Port = (PUSHORT)HalpFixedAcpiDescTable.pm1a_ctrl_blk_io_port; + ValueA = READ_PORT_USHORT(Port); + + DPRINT1("HalpCheckPowerButton: ValueA %X\n", ValueA); + + WRITE_PORT_USHORT(Port, ((((OldContext & 7) | 8) << 10) | ValueA) & 0x203); + + Port = (PUSHORT)HalpFixedAcpiDescTable.pm1b_ctrl_blk_io_port; + if (!Port) + return; + + ValueB = READ_PORT_USHORT(Port); + DPRINT1("HalpCheckPowerButton: ValueB %X\n", ValueB); + + WRITE_PORT_USHORT(Port, (((((OldContext >> 4) & 7) | 8) << 10) | ValueB) & 0x203); +} + +VOID +NTAPI +HaliHaltSystem(VOID) +{ + DPRINT1("HaliHaltSystem()\n"); + + while (TRUE) + { + HalpCheckPowerButton(); + YieldProcessor(); + } +} + +CODE_SEG("INIT") +VOID +NTAPI +HalpGetNMICrashFlag(VOID) +{ + UNICODE_STRING ValueName; + UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\CrashControl"); + OBJECT_ATTRIBUTES ObjectAttributes; + ULONG ResultLength; + HANDLE Handle; + NTSTATUS Status; + KEY_VALUE_PARTIAL_INFORMATION KeyValueInformation; + + /* Set default */ + HalpNMIDumpFlag = 0; + + /* Initialize attributes */ + InitializeObjectAttributes(&ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + /* Open crash key */ + Status = ZwOpenKey(&Handle, KEY_READ, &ObjectAttributes); + if (NT_SUCCESS(Status)) + { + /* Query key value */ + RtlInitUnicodeString(&ValueName, L"NMICrashDump"); + Status = ZwQueryValueKey(Handle, + &ValueName, + KeyValuePartialInformation, + &KeyValueInformation, + sizeof(KeyValueInformation), + &ResultLength); + if (NT_SUCCESS(Status)) + { + /* Check for valid data */ + if (ResultLength == sizeof(KEY_VALUE_PARTIAL_INFORMATION)) + { + /* Read the flag */ + HalpNMIDumpFlag = KeyValueInformation.Data[0]; + } + } + + /* We're done */ + ZwClose(Handle); + } +} + +CODE_SEG("INIT") +VOID +NTAPI +HalpInitializePciBus(VOID) +{ + /* Setup the PCI stub support */ + HalpInitializePciStubs(); + + /* Set the NMI crash flag */ + HalpGetNMICrashFlag(); +} + +BOOLEAN +NTAPI +HalpGetDebugPortTable(VOID) +{ + DPRINT("HalpGetDebugPortTable()\n"); + if (!HalpDebugPortTable) + return FALSE; + + return (HalpDebugPortTable->BaseAddress.AddressSpaceID == 1); +} + +VOID +NTAPI +HalpAcpiDetectResourceListSize(OUT PULONG ListSize) +{ + PAGED_CODE(); + + /* One element if there is a SCI */ + *ListSize = (HalpFixedAcpiDescTable.sci_int_vector ? 1: 0); + + DPRINT("HalpAcpiDetectResourceListSize: *ListSize %X\n", *ListSize); + + if (HalpFixedAcpiDescTable.sci_int_vector == 0) + { + DPRINT("HalpAcpiDetectResourceListSize: sci_int_vector %X\n", HalpFixedAcpiDescTable.sci_int_vector); + //AcpiDumpFadt(&HalpFixedAcpiDescTable); + } +} + +NTSTATUS +NTAPI +HalpBuildAcpiResourceList(IN PIO_RESOURCE_REQUIREMENTS_LIST ResourceList) +{ + ULONG Interrupt; + + PAGED_CODE(); + DPRINT("HalpBuildAcpiResourceList: ResourceList %p\n", ResourceList); + + ASSERT(ResourceList != NULL); + + /* Initialize the list */ + ResourceList->BusNumber = -1; + ResourceList->AlternativeLists = 1; + ResourceList->InterfaceType = PNPBus; + ResourceList->List[0].Version = 1; + ResourceList->List[0].Revision = 1; + //ResourceList->List[0].Count = 0; + + /* Is there a SCI? */ + if (!HalpFixedAcpiDescTable.sci_int_vector) + return STATUS_SUCCESS; + + DPRINT("HalpFADT.sci_int_vector %X\n", HalpFixedAcpiDescTable.sci_int_vector); + + /* Fill out the entry for it */ + ResourceList->List[0].Descriptors[0].Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; + ResourceList->List[0].Descriptors[0].Type = CmResourceTypeInterrupt; + ResourceList->List[0].Descriptors[0].ShareDisposition = CmResourceShareShared; + + /* Get the interrupt number */ + Interrupt = HalpPicVectorRedirect[HalpFixedAcpiDescTable.sci_int_vector]; + ResourceList->List[0].Descriptors[0].u.Interrupt.MinimumVector = Interrupt; + ResourceList->List[0].Descriptors[0].u.Interrupt.MaximumVector = Interrupt; + + /* One more */ + ++ResourceList->List[0].Count; + + /* All good */ + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +HalpQueryAcpiResourceRequirements(OUT PIO_RESOURCE_REQUIREMENTS_LIST* Requirements) +{ + PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList; + ULONG Count = 0; + ULONG ListSize; + NTSTATUS Status; + + PAGED_CODE(); + DPRINT("HalpQueryAcpiResourceRequirements: Requirements %p\n", Requirements); + + /* Get ACPI resources */ + HalpAcpiDetectResourceListSize(&Count); + DPRINT("HalpQueryAcpiResourceRequirements: Resource count %X\n", Count); + + /* Compute size of the list and allocate it */ + ListSize = (FIELD_OFFSET(IO_RESOURCE_REQUIREMENTS_LIST, List[0].Descriptors) + (Count * sizeof(IO_RESOURCE_DESCRIPTOR))); + + DPRINT("HalpQueryAcpiResourceRequirements: Resource list size %X\n", ListSize); + + RequirementsList = ExAllocatePoolWithTag(PagedPool, ListSize, TAG_HAL); + if (!RequirementsList) + { + DPRINT1("HalpQueryAcpiResourceRequirements: STATUS_INSUFFICIENT_RESOURCES\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Initialize it */ + RtlZeroMemory(RequirementsList, ListSize); + RequirementsList->ListSize = ListSize; + + /* Build it */ + Status = HalpBuildAcpiResourceList(RequirementsList); + if (!NT_SUCCESS(Status)) + { + DPRINT1("HalpQueryAcpiResourceRequirements: Status %X\n", Status); + ExFreePoolWithTag(RequirementsList, TAG_HAL); + return STATUS_NO_SUCH_DEVICE; + } + + /* It worked, return it */ + *Requirements = RequirementsList; + + /* Validate the list */ + ASSERT(RequirementsList->List[0].Count == Count); + + return Status; +} + +/* PUBLIC FUNCTIONS **********************************************************/ + +CODE_SEG("INIT") +VOID +NTAPI +HalReportResourceUsage(VOID) +{ + INTERFACE_TYPE InterfaceType; + UNICODE_STRING HalString; + + DPRINT("HalReportResourceUsage()\n"); + + /* FIXME: HalpDmaFinalizeDoubleBufferingDisposition() */ + /* FIXME: Initialize DMA 64-bit support */ + /* FIXME: Initialize MCA bus */ + + /* Initialize PCI bus. */ + HalpInitializePciBus(); + + /* What kind of bus is this? */ + switch (HalpBusType) + { + /* ISA Machine */ + case MACHINE_TYPE_ISA: + InterfaceType = Isa; + break; + + /* EISA Machine */ + case MACHINE_TYPE_EISA: + InterfaceType = Eisa; + break; + + /* MCA Machine */ + case MACHINE_TYPE_MCA: + InterfaceType = MicroChannel; + break; + + /* Unknown */ + default: + InterfaceType = Internal; + break; + } + + /* Build HAL usage */ + RtlInitUnicodeString(&HalString, HalName); + HalpReportResourceUsage(&HalString, InterfaceType); + + /* Setup PCI debugging and Hibernation */ + HalpRegisterPciDebuggingDeviceInfo(); +} + +ULONG +NTAPI +HalSetTimeIncrement(IN ULONG Increment) +{ + UNIMPLEMENTED; + ASSERT(0);//HalpDbgBreakPointEx(); + return 0; +} + +/* EOF */ diff --git a/hal/halacpi/acpi/halpnpdd.c b/hal/halacpi/acpi/halpnpdd.c new file mode 100644 index 0000000000000..4df9b0b6cc7c3 --- /dev/null +++ b/hal/halacpi/acpi/halpnpdd.c @@ -0,0 +1,1029 @@ + +/* INCLUDES *******************************************************************/ + +#include +//#define NDEBUG +#include + +/* INCLUDES *******************************************************************/ + +typedef enum _EXTENSION_TYPE +{ + PdoExtensionType = 0xC0, + FdoExtensionType +} EXTENSION_TYPE; + +typedef enum _PDO_TYPE +{ + AcpiPdo = 0x81, + WdPdo = 0x82 +} PDO_TYPE; + +typedef struct _FDO_EXTENSION +{ + EXTENSION_TYPE ExtensionType; + struct _PDO_EXTENSION* ChildPdoList; + PDEVICE_OBJECT PhysicalDeviceObject; + PDEVICE_OBJECT FunctionalDeviceObject; + PDEVICE_OBJECT AttachedDeviceObject; +} FDO_EXTENSION, *PFDO_EXTENSION; + +typedef struct _PDO_EXTENSION +{ + EXTENSION_TYPE ExtensionType; + struct _PDO_EXTENSION* Next; + PDEVICE_OBJECT PhysicalDeviceObject; + PFDO_EXTENSION ParentFdoExtension; + PDO_TYPE PdoType; + PDESCRIPTION_HEADER WdTable; +} PDO_EXTENSION, *PPDO_EXTENSION; + +/* GLOBALS ********************************************************************/ + +PDRIVER_OBJECT HalpDriverObject; +PWCHAR HalHardwareIdString = L"acpipic_up"; + +/* PRIVATE FUNCTIONS **********************************************************/ + +NTSTATUS +NTAPI +HalpAddDevice(IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT TargetDevice) +{ + PDEVICE_OBJECT FdoDeviceObject; + PDEVICE_OBJECT AttachedDevice; + PDEVICE_OBJECT PdoDeviceObject; + PDEVICE_OBJECT WdDeviceObject; + PFDO_EXTENSION FdoExtension; + PPDO_EXTENSION PdoExtension; + PPDO_EXTENSION WdExtension; + PDESCRIPTION_HEADER Wdrt; + NTSTATUS Status; + + PAGED_CODE(); + DPRINT("HalpAddDevice: Driver %p, Pdo %p\n", DriverObject, TargetDevice); + + /* Create the FDO */ + Status = IoCreateDevice(DriverObject, + sizeof(FDO_EXTENSION), + NULL, + FILE_DEVICE_BUS_EXTENDER, + 0, + FALSE, + &FdoDeviceObject); + if (!NT_SUCCESS(Status)) + { + /* Should not happen */ + DPRINT1("HalpAddDevice: Status %X\n", Status); + ASSERT(FALSE);//HalpDbgBreakPointEx(); + return Status; + } + + DPRINT("HalpAddDevice: Fdo %p\n", FdoDeviceObject); + + /* Setup the FDO extension */ + FdoExtension = FdoDeviceObject->DeviceExtension; + FdoExtension->ExtensionType = FdoExtensionType; + FdoExtension->PhysicalDeviceObject = TargetDevice; + FdoExtension->FunctionalDeviceObject = FdoDeviceObject; + FdoExtension->ChildPdoList = NULL; + + /* FDO is done initializing */ + FdoDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + + /* Attach to the physical device object (the bus) */ + AttachedDevice = IoAttachDeviceToDeviceStack(FdoDeviceObject, TargetDevice); + if (!AttachedDevice) + { + /* Failed, undo everything */ + DPRINT("HalpAddDevice: return STATUS_NO_SUCH_DEVICE\n"); + IoDeleteDevice(FdoDeviceObject); + return STATUS_NO_SUCH_DEVICE; + } + + DPRINT("HalpAddDevice: AttachedDevice %p\n", AttachedDevice); + + /* Save the attachment */ + FdoExtension->AttachedDeviceObject = AttachedDevice; + + /* Create the PDO */ + Status = IoCreateDevice(DriverObject, + sizeof(PDO_EXTENSION), + NULL, + FILE_DEVICE_BUS_EXTENDER, + FILE_AUTOGENERATED_DEVICE_NAME, + FALSE, + &PdoDeviceObject); + if (!NT_SUCCESS(Status)) + { + /* Fail */ + DPRINT1("HalpAddDevice: Not created ACPI PDO. Sts %X\n", Status); + return Status; + } + + DPRINT("HalpAddDevice: IoCreateDevice ACPI PDO %p\n", PdoDeviceObject); + + /* Setup the PDO device extension */ + PdoExtension = PdoDeviceObject->DeviceExtension; + PdoExtension->ExtensionType = PdoExtensionType; + PdoExtension->PhysicalDeviceObject = PdoDeviceObject; + PdoExtension->ParentFdoExtension = FdoExtension; + PdoExtension->PdoType = AcpiPdo; + + /* Add the PDO to the head of the list */ + PdoExtension->Next = NULL; + + /* Find the ACPI watchdog table */ + Wdrt = HalAcpiGetTable(0, 'TRDW'); + if ( !Wdrt ) + { + /* Initialization is finished */ + DPRINT1("HalpAddDevice: No Watchdog.\n"); + goto Exit; + } + + /* FIXME: TODO */ + DPRINT1("HalpAddDevice: You have an ACPI Watchdog. ... \n"); + ASSERT(FALSE);//HalpDbgBreakPointEx(); + + Status = IoCreateDevice(DriverObject, + sizeof(PDO_EXTENSION), + NULL, + FILE_DEVICE_BUS_EXTENDER, + FILE_AUTOGENERATED_DEVICE_NAME, + FALSE, + &WdDeviceObject); + if (!NT_SUCCESS(Status)) + { + DPRINT1("HalpAddDevice: Not created WD DO. Status %X\n", Status); + IoDeleteDevice(PdoDeviceObject); + return Status; + } + + DPRINT("HalpAddDevice: IoCreateDevice Wd DO %p\n", WdDeviceObject); + + WdExtension = WdDeviceObject->DeviceExtension; + WdExtension->ExtensionType = PdoExtensionType; + WdExtension->PhysicalDeviceObject = WdDeviceObject; + WdExtension->ParentFdoExtension = FdoExtension; + WdExtension->PdoType = WdPdo; + WdExtension->WdTable = Wdrt; + + WdExtension->Next = NULL; + PdoExtension->Next = WdExtension; + + WdDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + +Exit: + + PdoDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + FdoExtension->ChildPdoList = PdoExtension; + + DPRINT("HalpAddDevice: return STATUS_SUCCESS\n"); + return STATUS_SUCCESS; +} + +VOID +NTAPI +HalTranslatorDereference(IN PVOID Context) +{ + ; +} + +NTSTATUS +NTAPI +HalpQueryInterface(IN PDEVICE_OBJECT DeviceObject, + IN CONST GUID* InterfaceType, + IN ULONG InterfaceBufferSize, + IN PVOID InterfaceSpecificData, + IN USHORT Version, + IN PINTERFACE Interface, + OUT PULONG_PTR OutInformation) +{ + PTRANSLATOR_INTERFACE TranslatorInterface = (PTRANSLATOR_INTERFACE)Interface; + UNICODE_STRING GuidString; + NTSTATUS Status; + + DPRINT("HalpQueryInterface: Device %p\n", DeviceObject); + + Status = RtlStringFromGUID(InterfaceType, &GuidString); + ASSERT(NT_SUCCESS(Status)); + + DPRINT("Guid %wZ\n", &GuidString); + DPRINT("BuffSize %X, Ver %X, Data %X, IFace %p\n", InterfaceBufferSize, Version, InterfaceSpecificData, Interface); + + if (RtlCompareMemory(&GUID_TRANSLATOR_INTERFACE_STANDARD, InterfaceType, sizeof(GUID)) != sizeof(GUID)) + { + DPRINT("HalpQueryInterface: STATUS_NOT_SUPPORTED\n"); + return STATUS_NOT_SUPPORTED; + } + + if (InterfaceBufferSize < sizeof(TRANSLATOR_INTERFACE)) + { + DPRINT("Return STATUS_BUFFER_TOO_SMALL\n"); + *OutInformation = sizeof(TRANSLATOR_INTERFACE); + return STATUS_BUFFER_TOO_SMALL; + } + + if (InterfaceSpecificData != ULongToPtr(2)) + { + DPRINT("InterfaceSpecificData != ULongToPtr(2)\n"); + return STATUS_NOT_SUPPORTED; + } + + TranslatorInterface->Version = 0; + TranslatorInterface->Size = sizeof(TRANSLATOR_INTERFACE); + TranslatorInterface->Context = DeviceObject; + + TranslatorInterface->InterfaceReference = HalTranslatorDereference; + TranslatorInterface->InterfaceDereference = HalTranslatorDereference; + + TranslatorInterface->TranslateResources = HalIrqTranslateResourcesRoot; + TranslatorInterface->TranslateResourceRequirements = HalIrqTranslateResourceRequirementsRoot; + + *OutInformation = sizeof(TRANSLATOR_INTERFACE); + + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +HalpQueryDeviceRelations(IN PDEVICE_OBJECT DeviceObject, + IN DEVICE_RELATION_TYPE RelationType, + OUT PDEVICE_RELATIONS* DeviceRelations) +{ + PPDO_EXTENSION PdoExtension; + PFDO_EXTENSION FdoExtension; + PDEVICE_RELATIONS PdoRelations; + PDEVICE_RELATIONS FdoRelations; + PDEVICE_OBJECT* ObjectEntry; + EXTENSION_TYPE ExtensionType; + ULONG PdoCount = 0; + ULONG Size; + ULONG ix = 0; + + DPRINT("HalpQueryDeviceRelations: RelationType %X\n", RelationType); + + /* Get FDO device extension and PDO count */ + FdoExtension = DeviceObject->DeviceExtension; + ExtensionType = FdoExtension->ExtensionType; + + /* What do they want? */ + if (RelationType != BusRelations) + { + /* The only other thing we support is a target relation for the PDO */ + if (RelationType != TargetDeviceRelation) + return STATUS_NOT_SUPPORTED; + + if (ExtensionType != PdoExtensionType) + return STATUS_NOT_SUPPORTED; + + /* Only one entry */ + PdoRelations = ExAllocatePoolWithTag(PagedPool, sizeof(DEVICE_RELATIONS), TAG_HAL); + if (!PdoRelations) + { + DPRINT1("HalpQueryDeviceRelations: STATUS_INSUFFICIENT_RESOURCES\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Fill it out and reference us */ + PdoRelations->Count = 1; + PdoRelations->Objects[0] = DeviceObject; + + ObReferenceObject(DeviceObject); + + /* Return it */ + *DeviceRelations = PdoRelations; + + return STATUS_SUCCESS; + } + + /* This better be an FDO */ + if (ExtensionType != FdoExtensionType) + /* We don't support anything else */ + return STATUS_NOT_SUPPORTED; + + /* Count how many PDOs we have */ + PdoExtension = FdoExtension->ChildPdoList; + while (PdoExtension) + { + /* Next one */ + PdoExtension = PdoExtension->Next; + PdoCount++; + } + + /* Add the PDOs that already exist in the device relations */ + if (*DeviceRelations) + PdoCount += (*DeviceRelations)->Count; + + /* Allocate our structure */ + Size = (FIELD_OFFSET(DEVICE_RELATIONS, Objects) + (PdoCount * sizeof(PDEVICE_OBJECT))); + + FdoRelations = ExAllocatePoolWithTag(PagedPool, Size, TAG_HAL); + if (!FdoRelations) + { + DPRINT1("HalpQueryDeviceRelations: STATUS_INSUFFICIENT_RESOURCES\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Save our count */ + FdoRelations->Count = PdoCount; + + /* Query existing relations */ + ObjectEntry = FdoRelations->Objects; + if (*DeviceRelations) + { + /* Check if there were any */ + if ((*DeviceRelations)->Count) + { + /* Loop them all */ + do + { + /* Copy into our structure */ + *ObjectEntry++ = (*DeviceRelations)->Objects[ix]; + } + while (++ix < (*DeviceRelations)->Count); + } + + /* Free existing structure */ + ExFreePool(*DeviceRelations); + } + + /* Now check if we have a PDO list */ + PdoExtension = FdoExtension->ChildPdoList; + if (!PdoExtension) + goto Exit; + + /* Loop the PDOs */ + do + { + /* Save our own PDO and reference it */ + *ObjectEntry++ = PdoExtension->PhysicalDeviceObject; + ObReferenceObject(PdoExtension->PhysicalDeviceObject); + + /* Go to our next PDO */ + PdoExtension = PdoExtension->Next; + } + while (PdoExtension); + +Exit: + + /* Return the new structure */ + *DeviceRelations = FdoRelations; + + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +HalpQueryCapabilities(IN PDEVICE_OBJECT DeviceObject, + OUT PDEVICE_CAPABILITIES Capabilities) +{ + PAGED_CODE(); + + DPRINT("HalpQueryCapabilities: Device %X\n", DeviceObject); + + /* Get the extension and check for valid version */ + if (Capabilities->Version != 1) + { + DPRINT1("HalpQueryCapabilities: Capabilities->Version %X\n", Capabilities->Version); + ASSERT(Capabilities->Version == 1); + return STATUS_NOT_SUPPORTED; + } + + /* Can't lock or eject us */ + Capabilities->LockSupported = FALSE; + Capabilities->EjectSupported = FALSE; + + /* Can't remove or dock us */ + Capabilities->Removable = FALSE; + Capabilities->DockDevice = FALSE; + + /* Can't access us raw */ + Capabilities->RawDeviceOK = FALSE; + + /* We have a unique ID, and don't bother the user */ + Capabilities->UniqueID = TRUE; + Capabilities->SilentInstall = TRUE; + + /* Fill out the adress */ + Capabilities->Address = InterfaceTypeUndefined; + Capabilities->UINumber = InterfaceTypeUndefined; + + /* Fill out latencies */ + Capabilities->D1Latency = 0; + Capabilities->D2Latency = 0; + Capabilities->D3Latency = 0; + + /* Fill out supported device states */ + Capabilities->DeviceState[PowerSystemWorking] = PowerDeviceD0; + Capabilities->DeviceState[PowerSystemHibernate] = PowerDeviceD3; + Capabilities->DeviceState[PowerSystemShutdown] = PowerDeviceD3; + //Capabilities->DeviceState[PowerSystemSleeping3] = PowerDeviceD3; + + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +HalpQueryResources(IN PDEVICE_OBJECT DeviceObject, + OUT PCM_RESOURCE_LIST* Resources) +{ + PPDO_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; + PCM_RESOURCE_LIST ResourceList; + PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList; + PIO_RESOURCE_DESCRIPTOR Descriptor; + PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDesc; + ULONG ix; + NTSTATUS Status; + + PAGED_CODE(); + DPRINT("HalpQueryResources: DeviceObject %X\n", DeviceObject); + + if (DeviceExtension->PdoType == WdPdo) + { + /* Watchdog doesn't */ + DPRINT1("HalpQueryResources: PdoType == WdPdo \n"); + return STATUS_SUCCESS; + } + + /* Only the ACPI PDO has requirements */ + if (DeviceExtension->PdoType != AcpiPdo) + { + /* This shouldn't happen */ + DPRINT1("HalpQueryResources: PdoType %X\n", DeviceExtension->PdoType); + return STATUS_NOT_SUPPORTED; + } + + /* Query ACPI requirements */ + Status = HalpQueryAcpiResourceRequirements(&RequirementsList); + if (!NT_SUCCESS(Status)) + { + DPRINT1("HalpQueryResources: Status %X\n", Status); + return Status; + } + + ASSERT(RequirementsList->AlternativeLists == 1); + + /* Allocate the resourcel ist */ + ResourceList = ExAllocatePoolWithTag(PagedPool, sizeof(CM_RESOURCE_LIST), TAG_HAL); + if (!ResourceList ) + { + DPRINT1("HalpQueryResources: STATUS_INSUFFICIENT_RESOURCES\n"); + Status = STATUS_INSUFFICIENT_RESOURCES; + ExFreePoolWithTag(RequirementsList, TAG_HAL); + return Status; + } + + /* Initialize it */ + RtlZeroMemory(ResourceList, sizeof(CM_RESOURCE_LIST)); + ResourceList->Count = 1; + + /* Setup the list fields */ + ResourceList->List[0].BusNumber = -1; + ResourceList->List[0].InterfaceType = PNPBus; + ResourceList->List[0].PartialResourceList.Version = 1; + ResourceList->List[0].PartialResourceList.Revision = 1; + ResourceList->List[0].PartialResourceList.Count = 0; + + /* Setup the first descriptor */ + PartialDesc = ResourceList->List[0].PartialResourceList.PartialDescriptors; + + /* Find the requirement descriptor for the SCI */ + for (ix = 0; ix < RequirementsList->List[0].Count; ix++) + { + /* Get this descriptor */ + Descriptor = &RequirementsList->List[0].Descriptors[ix]; + + DPRINT("HalpQueryResources: Desc %X, Type %X\n", Descriptor, Descriptor->Type); + + if (Descriptor->Type == CmResourceTypeInterrupt) + { + /* Copy requirements descriptor into resource descriptor */ + PartialDesc->Type = CmResourceTypeInterrupt; + PartialDesc->ShareDisposition = Descriptor->ShareDisposition; + PartialDesc->Flags = Descriptor->Flags; + + ASSERT(Descriptor->u.Interrupt.MinimumVector == Descriptor->u.Interrupt.MaximumVector); + + PartialDesc->u.Interrupt.Vector = Descriptor->u.Interrupt.MinimumVector; + PartialDesc->u.Interrupt.Level = Descriptor->u.Interrupt.MinimumVector; + PartialDesc->u.Interrupt.Affinity = 0xFFFFFFFF; + + ResourceList->List[0].PartialResourceList.Count++; + break; + } + } + + /* Return resources and success */ + *Resources = ResourceList; + ExFreePoolWithTag(RequirementsList, TAG_HAL); + + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +HalpQueryResourceRequirements(IN PDEVICE_OBJECT DeviceObject, + OUT PIO_RESOURCE_REQUIREMENTS_LIST* Requirements) +{ + PPDO_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; + PAGED_CODE(); + + DPRINT("HalpQueryResourceRequirements: Device %X\n", DeviceObject); + + /* Only the ACPI PDO has requirements */ + if (DeviceExtension->PdoType == AcpiPdo) + return HalpQueryAcpiResourceRequirements(Requirements); + + if (DeviceExtension->PdoType == WdPdo) + { + /* Watchdog doesn't */ + DPRINT1("HalpQueryResourceRequirements: Watchdog ... FIXME\n"); + ASSERT(FALSE);//HalpDbgBreakPointEx(); + return STATUS_NOT_IMPLEMENTED; + } + + /* This shouldn't happen */ + DPRINT1("HalpQueryResourceRequirements: unknown PdoType %X\n", DeviceExtension->PdoType); + ASSERT(FALSE);//HalpDbgBreakPointEx(); + + return STATUS_NOT_SUPPORTED; +} + +NTSTATUS +NTAPI +HalpQueryIdPdo(IN PDEVICE_OBJECT DeviceObject, + IN BUS_QUERY_ID_TYPE IdType, + OUT PUSHORT* BusQueryId) +{ + PPDO_EXTENSION PdoExtension; + PWCHAR CurrentId; + PWCHAR Buffer; + WCHAR Id[100]; + PDO_TYPE PdoType; + SIZE_T Length = 0; + + PAGED_CODE(); + DPRINT("HalpQueryIdPdo: IdType %X\n", IdType); + + /* Get the PDO type */ + PdoExtension = DeviceObject->DeviceExtension; + PdoType = PdoExtension->PdoType; + + /* What kind of ID is being requested? */ + switch (IdType) + { + case BusQueryDeviceID: + case BusQueryHardwareIDs: + { + /* What kind of PDO is this? */ + if (PdoType == AcpiPdo) + { + /* ACPI ID */ + CurrentId = L"ACPI_HAL\\PNP0C08"; + RtlCopyMemory(Id, CurrentId, (wcslen(CurrentId) * sizeof(WCHAR)) + sizeof(UNICODE_NULL)); + Length += ((wcslen(CurrentId) * sizeof(WCHAR)) + sizeof(UNICODE_NULL)); + + CurrentId = L"*PNP0C08"; + RtlCopyMemory(&Id[wcslen(Id) + 1], CurrentId, (wcslen(CurrentId) * sizeof(WCHAR)) + sizeof(UNICODE_NULL)); + Length += ((wcslen(CurrentId) * sizeof(WCHAR)) + sizeof(UNICODE_NULL)); + } + else if (PdoType == WdPdo) + { + /* WatchDog ID */ + CurrentId = L"ACPI_HAL\\PNP0C18"; + RtlCopyMemory(Id, CurrentId, (wcslen(CurrentId) * sizeof(WCHAR)) + sizeof(UNICODE_NULL)); + Length += ((wcslen(CurrentId) * sizeof(WCHAR)) + sizeof(UNICODE_NULL)); + + CurrentId = L"*PNP0C18"; + RtlCopyMemory(&Id[wcslen(Id) + 1], CurrentId, (wcslen(CurrentId) * sizeof(WCHAR)) + sizeof(UNICODE_NULL)); + Length += ((wcslen(CurrentId) * sizeof(WCHAR)) + sizeof(UNICODE_NULL)); + } + else + { + DPRINT1("HalpQueryIdPdo: unknown PdoType %d\n", PdoType); + return STATUS_NOT_SUPPORTED; + } + + break; + } + case BusQueryInstanceID: + { + /* Instance ID */ + CurrentId = L"0"; + RtlCopyMemory(Id, CurrentId, (wcslen(CurrentId) * sizeof(WCHAR)) + sizeof(UNICODE_NULL)); + Length += (wcslen(CurrentId) * sizeof(WCHAR)) + sizeof(UNICODE_NULL); + break; + } + case BusQueryCompatibleIDs: + /* We don't support BusQueryCompatibleIDs */ + return STATUS_NOT_SUPPORTED; + + default: + /* We don't support anything else */ + DPRINT1("HalpQueryIdPdo: unknown IdType %d\n", IdType); + return STATUS_NOT_SUPPORTED; + } + + Buffer = ExAllocatePoolWithTag(PagedPool, (Length + sizeof(UNICODE_NULL)), TAG_HAL); + if (!Buffer) + { + DPRINT1("HalpQueryIdPdo: STATUS_INSUFFICIENT_RESOURCES\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Copy the string and null-terminate it */ + RtlCopyMemory(Buffer, Id, Length); + Buffer[Length / sizeof(WCHAR)] = UNICODE_NULL; + + /* Return string */ + DPRINT("HalpQueryIdPdo: returning '%S'\n", Buffer); + *BusQueryId = Buffer; + + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +HalpQueryIdFdo(IN PDEVICE_OBJECT DeviceObject, + IN BUS_QUERY_ID_TYPE IdType, + OUT PUSHORT* BusQueryId) +{ + PWCHAR Buffer; + PWCHAR Id; + SIZE_T Length; + + PAGED_CODE(); + + /* What kind of ID is being requested? */ + switch (IdType) + { + case BusQueryDeviceID: + DPRINT1("HalpQueryIdFdo: BusQueryDeviceID\n"); + Id = HalHardwareIdString; + break; + + case BusQueryHardwareIDs: + DPRINT1("HalpQueryIdFdo: BusQueryHardwareIDs\n"); + Id = HalHardwareIdString; + break; + + case BusQueryInstanceID: + DPRINT1("HalpQueryIdFdo: BusQueryInstanceID\n"); + Id = L"0"; + break; + + default: + /* We don't support anything else */ + DPRINT1("HalpQueryIdFdo: unknown IdType %X\n", IdType); + return STATUS_NOT_SUPPORTED; + } + + Length = ((wcslen(Id) * sizeof(WCHAR)) + sizeof(UNICODE_NULL)); + + Buffer = ExAllocatePoolWithTag(PagedPool, (Length + sizeof(UNICODE_NULL)), TAG_HAL); + if (!Buffer) + { + DPRINT1("HalpQueryIdFdo: STATUS_INSUFFICIENT_RESOURCES\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlCopyMemory(Buffer, Id, Length); + Buffer[Length / sizeof(WCHAR)] = UNICODE_NULL; + + *BusQueryId = Buffer; + DPRINT1("HalpQueryIdFdo: BusQueryId - %S\n", *BusQueryId); + + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +HalpPassIrpFromFdoToPdo(IN PDEVICE_OBJECT FdoDeviceObject, + IN PIRP Irp) +{ + PFDO_EXTENSION FdoDeviceExtension; + NTSTATUS Status; + + DPRINT("HalpPassIrpFromFdoToPdo: %p, %p\n", FdoDeviceObject, Irp); + + FdoDeviceExtension = FdoDeviceObject->DeviceExtension; + IoSkipCurrentIrpStackLocation(Irp); + + Status = IoCallDriver(FdoDeviceExtension->AttachedDeviceObject, Irp); + DPRINT("HalpPassIrpFromFdoToPdo: AttachedDevice %p, Status %X\n", FdoDeviceExtension->AttachedDeviceObject, Status); + + return Status; +} + +NTSTATUS +NTAPI +HalpDispatchPnp(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + PIO_STACK_LOCATION IoStackLocation; + PFDO_EXTENSION FdoExtension; + NTSTATUS Status; + UCHAR Minor; + + PAGED_CODE(); + DPRINT("HalpDispatchPnp: Device %p, Irp %p\n", DeviceObject, Irp); + + /* Get the device extension and stack location */ + FdoExtension = DeviceObject->DeviceExtension; + IoStackLocation = IoGetCurrentIrpStackLocation(Irp); + Minor = IoStackLocation->MinorFunction; + + /* FDO? */ + if (FdoExtension->ExtensionType == FdoExtensionType) + { + /* Query the IRP type */ + switch (Minor) + { + case IRP_MN_QUERY_DEVICE_RELATIONS: + + /* Call the worker */ + DPRINT("HalpDispatchPnp: Querying device relations for FDO\n"); + Status = HalpQueryDeviceRelations(DeviceObject, + IoStackLocation->Parameters.QueryDeviceRelations.Type, + (PVOID)&Irp->IoStatus.Information); + break; + + case IRP_MN_QUERY_INTERFACE: + + /* Call the worker */ + DPRINT("HalpDispatchPnp: Querying interface for FDO\n"); + Status = HalpQueryInterface(DeviceObject, + IoStackLocation->Parameters.QueryInterface.InterfaceType, + IoStackLocation->Parameters.QueryInterface.Size, + IoStackLocation->Parameters.QueryInterface.InterfaceSpecificData, + IoStackLocation->Parameters.QueryInterface.Version, + IoStackLocation->Parameters.QueryInterface.Interface, + (PVOID)&Irp->IoStatus.Information); + break; + + case IRP_MN_QUERY_ID: + + /* Call the worker */ + DPRINT("HalpDispatchPnp: Querying ID for FDO\n"); + Status = HalpQueryIdFdo(DeviceObject, + IoStackLocation->Parameters.QueryId.IdType, + (PVOID)&Irp->IoStatus.Information); + DPRINT("HalpDispatchPnp: Querying ID for FDO. Status %X, Information %X\n", Status, Irp->IoStatus.Information); + break; + + default: + + DPRINT("HalpDispatchPnp: [FDO] not supp. Minor %X\n", Minor); + //Status = Irp->IoStatus.Status; + //break; + return HalpPassIrpFromFdoToPdo(DeviceObject, Irp); + } + + if (!NT_SUCCESS(Status) && Status != STATUS_NOT_SUPPORTED) + { + DPRINT1("HalpDispatchPnp: [FDO] Status %X\n", Status); + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; + } + if (Status != STATUS_NOT_SUPPORTED) + { + DPRINT("HalpDispatchPnp: [FDO] Status %X\n", Status); + Irp->IoStatus.Status = Status; + } + else + { + DPRINT("HalpDispatchPnp: [FDO] Status %X\n", Status); + } + + Status = HalpPassIrpFromFdoToPdo(DeviceObject, Irp); + DPRINT("HalpDispatchPnp: [FDO] Status %X\n", Status); + + return Status; + } + + if (FdoExtension->ExtensionType != PdoExtensionType) + { + DPRINT1("HalpDispatchPnp: unknown ExtType %X\n", FdoExtension->ExtensionType); + ASSERT(FALSE);//HalpDbgBreakPointEx(); + Status = STATUS_INVALID_DEVICE_REQUEST; + Irp->IoStatus.Status = Status; + goto Exit; + } + + /* This is a PDO instead */ + ASSERT(FdoExtension->ExtensionType == PdoExtensionType); + + switch (Minor) + { + case IRP_MN_START_DEVICE: + /* We only care about a PCI PDO */ + DPRINT1("HalpDispatchPnp: [FDO] Start Device\n"); + /* Complete the IRP normally */ + Status = STATUS_SUCCESS; + break; + + case IRP_MN_QUERY_REMOVE_DEVICE: + DPRINT1("HalpDispatchPnp: [FDO] Query Remove Device\n"); + Status = STATUS_UNSUCCESSFUL; + break; + + case IRP_MN_REMOVE_DEVICE: + DPRINT1("HalpDispatchPnp: [FDO] Remove Device\n"); + /* We're done */ + Status = STATUS_SUCCESS; + break; + + case IRP_MN_CANCEL_REMOVE_DEVICE: + DPRINT1("HalpDispatchPnp: [FDO] Cancel Remove Device\n"); + Status = STATUS_SUCCESS; + break; + + case IRP_MN_STOP_DEVICE: + DPRINT1("HalpDispatchPnp: [PDO] Stop Device\n"); + Status = STATUS_SUCCESS; + break; + + case IRP_MN_QUERY_STOP_DEVICE: + DPRINT1("HalpDispatchPnp: [PDO] Query Stop Device\n"); + Status = STATUS_SUCCESS; + break; + + case IRP_MN_CANCEL_STOP_DEVICE: + DPRINT1("HalpDispatchPnp: [PDO] Cancel Stop Device\n"); + Status = STATUS_SUCCESS; + break; + + case IRP_MN_SURPRISE_REMOVAL: + /* Inherit whatever status we had */ + DPRINT1("HalpDispatchPnp: [PDO] Surprise removal IRP\n"); + Status = Irp->IoStatus.Status; + break; + + case IRP_MN_QUERY_DEVICE_RELATIONS: + /* Query the device relations */ + DPRINT("HalpDispatchPnp: Querying PDO relations\n"); + Status = HalpQueryDeviceRelations(DeviceObject, + IoStackLocation->Parameters.QueryDeviceRelations.Type, + (PVOID)&Irp->IoStatus.Information); + break; + + case IRP_MN_QUERY_INTERFACE: + /* Call the worker */ + DPRINT("HalpDispatchPnp: Querying interface for PDO\n"); + Status = HalpQueryInterface(DeviceObject, + IoStackLocation->Parameters.QueryInterface.InterfaceType, + IoStackLocation->Parameters.QueryInterface.Size, + IoStackLocation->Parameters.QueryInterface.InterfaceSpecificData, + IoStackLocation->Parameters.QueryInterface.Version, + IoStackLocation->Parameters.QueryInterface.Interface, + &Irp->IoStatus.Information); + break; + + case IRP_MN_QUERY_CAPABILITIES: + /* Call the worker */ + DPRINT("HalpDispatchPnp: Querying the capabilities for the PDO\n"); + Status = HalpQueryCapabilities(DeviceObject, + IoStackLocation->Parameters.DeviceCapabilities.Capabilities); + break; + + case IRP_MN_QUERY_RESOURCES: + /* Call the worker */ + DPRINT("HalpDispatchPnp: Querying the resources for the PDO\n"); + Status = HalpQueryResources(DeviceObject, (PVOID)&Irp->IoStatus.Information); + break; + + case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: + /* Call the worker */ + DPRINT("HalpDispatchPnp: Querying the resource requirements for the PDO\n"); + Status = HalpQueryResourceRequirements(DeviceObject, (PVOID)&Irp->IoStatus.Information); + break; + + case IRP_MN_QUERY_ID: + /* Call the worker */ + DPRINT("HalpDispatchPnp: Query the ID for the PDO\n"); + Status = HalpQueryIdPdo(DeviceObject, + IoStackLocation->Parameters.QueryId.IdType, + (PVOID)&Irp->IoStatus.Information); + break; + + case IRP_MN_DEVICE_USAGE_NOTIFICATION: + /* Call the worker */ + DPRINT("HalpDispatchPnp: DEVICE_USAGE for the PDO\n"); + Status = STATUS_SUCCESS; + Irp->IoStatus.Status = Status; + break; + + default: + /* We don't handle anything else, so inherit the old state */ + DPRINT("HalpDispatchPnp: [PDO] not supp. Minor %X\n", Minor); + Status = Irp->IoStatus.Status; + DPRINT("HalpDispatchPnp: IRP completed with status %X\n", Status); + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; + } + + /* If it's not supported, inherit the old status */ + if (Status == STATUS_NOT_SUPPORTED) + Status = Irp->IoStatus.Status; + + /* Complete the IRP */ + DPRINT("IRP completed with status %X\n", Status); + Irp->IoStatus.Status = Status; + +Exit: + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; +} + +NTSTATUS +NTAPI +HalpDispatchWmi(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + UNIMPLEMENTED; + ASSERT(FALSE);//HalpDbgBreakPointEx(); + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +HalpDispatchPower(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + UNIMPLEMENTED; + ASSERT(FALSE);//HalpDbgBreakPointEx(); + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +HalpDriverEntry(IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath) +{ + NTSTATUS Status; + PDEVICE_OBJECT TargetDevice = NULL; + + PAGED_CODE(); + DPRINT("HalpDriverEntry: DriverObject %p, '%wZ'\n", DriverObject, RegistryPath); + + /* This is us */ + HalpDriverObject = DriverObject; + + /* Set up add device */ + DriverObject->DriverExtension->AddDevice = HalpAddDevice; + + /* Set up the callouts */ + DriverObject->MajorFunction[IRP_MJ_PNP] = HalpDispatchPnp; + DriverObject->MajorFunction[IRP_MJ_POWER] = HalpDispatchPower; + DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = HalpDispatchWmi; + + /* Tell the PnP manager about us */ + Status = IoReportDetectedDevice(DriverObject, + InterfaceTypeUndefined, + -1, + -1, + NULL, + NULL, + FALSE, + &TargetDevice); + + DPRINT("HalpDriverEntry: TargetDevice %p\n", TargetDevice); + ASSERT(TargetDevice); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("HalpDriverEntry: Status %X\n", Status); + ASSERT(FALSE); + return Status; + } + + HalpAddDevice(DriverObject, TargetDevice); + + /* Return to kernel */ + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +HaliInitPnpDriver(VOID) +{ + NTSTATUS Status; + UNICODE_STRING DriverString; + + PAGED_CODE(); + DPRINT("HaliInitPnpDriver()\n"); + + /* Create the driver */ + RtlInitUnicodeString(&DriverString, L"\\Driver\\ACPI_HAL"); + + Status = IoCreateDriver(&DriverString, HalpDriverEntry); + ASSERT(NT_SUCCESS(Status)); + + /* Return status */ + return Status; +} + +/* EOF */ diff --git a/hal/halacpi/bus/pcibus.c b/hal/halacpi/bus/pcibus.c new file mode 100644 index 0000000000000..4d866f03f8dd2 --- /dev/null +++ b/hal/halacpi/bus/pcibus.c @@ -0,0 +1,1057 @@ + +/* INCLUDES ******************************************************************/ + +#include +//#include "pcibus.h" + +//#define NDEBUG +#include + +#if defined(ALLOC_PRAGMA) && !defined(_MINIHAL_) + #pragma alloc_text(INIT, HalpSetupPciDeviceForDebugging) + #pragma alloc_text(INIT, HalpReleasePciDeviceForDebugging) + #pragma alloc_text(INIT, HalpQueryPciRegistryInfo) + #pragma alloc_text(INIT, HalpInitializePciStubs) + #pragma alloc_text(INIT, HalpRegisterPciDebuggingDeviceInfo) +#endif + +/* GLOBALS *******************************************************************/ + +KSPIN_LOCK HalpPCIConfigLock; +ULONG HalpMinPciBus; +ULONG HalpMaxPciBus; +BOOLEAN HalpPCIConfigInitialized; + +/* Type 1 PCI Bus */ +PCI_CONFIG_HANDLER PCIConfigHandlerType1 = +{ + /* Synchronization */ + (FncSync)HalpPCISynchronizeType1, + (FncReleaseSync)HalpPCIReleaseSynchronzationType1, + + /* Read */ + { + (FncConfigIO)HalpPCIReadUlongType1, + (FncConfigIO)HalpPCIReadUcharType1, + (FncConfigIO)HalpPCIReadUshortType1 + }, + + /* Write */ + { + (FncConfigIO)HalpPCIWriteUlongType1, + (FncConfigIO)HalpPCIWriteUcharType1, + (FncConfigIO)HalpPCIWriteUshortType1 + } +}; + +/* Type 2 PCI Bus */ +PCI_CONFIG_HANDLER PCIConfigHandlerType2 = +{ + /* Synchronization */ + (FncSync)HalpPCISynchronizeType2, + (FncReleaseSync)HalpPCIReleaseSynchronizationType2, + + /* Read */ + { + (FncConfigIO)HalpPCIReadUlongType2, + (FncConfigIO)HalpPCIReadUcharType2, + (FncConfigIO)HalpPCIReadUshortType2 + }, + + /* Write */ + { + (FncConfigIO)HalpPCIWriteUlongType2, + (FncConfigIO)HalpPCIWriteUcharType2, + (FncConfigIO)HalpPCIWriteUshortType2 + } +}; + +PCI_CONFIG_HANDLER PCIConfigHandler; + +/* PCI Operation Matrix */ +UCHAR PCIDeref[4][4] = +{ + {0, 1, 2, 2}, // ULONG-aligned offset + {1, 1, 1, 1}, // UCHAR-aligned offset + {2, 1, 2, 2}, // USHORT-aligned offset + {1, 1, 1, 1} // UCHAR-aligned offset +}; + +PCIPBUSDATA HalpFakePciBusData = +{ + { + PCI_DATA_TAG, + PCI_DATA_VERSION, + HalpReadPCIConfig, + HalpWritePCIConfig, + NULL, + NULL, + {{{0, 0, 0}}}, + {0, 0, 0, 0} + }, + {{0, 0}}, + 32, +}; + +BUS_HANDLER HalpFakePciBusHandler = +{ + 1, + PCIBus, + PCIConfiguration, + 0, + NULL, + NULL, + &HalpFakePciBusData, + 0, + NULL, + {0, 0, 0, 0}, + (PGETSETBUSDATA)HalpGetPCIData, + (PGETSETBUSDATA)HalpSetPCIData, + NULL, + HalpAssignPCISlotResources, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +PCI_TYPE1_CFG_CYCLE_BITS HalpPciDebuggingDevice[2] = {{{{0}}}}; + +/* TYPE 1 FUNCTIONS **********************************************************/ + +VOID +NTAPI +HalpPCISynchronizeType1(IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PKIRQL Irql, + IN PPCI_TYPE1_CFG_BITS PciCfg1) +{ + /* Setup the PCI Configuration Register */ + PciCfg1->u.AsULONG = 0; + PciCfg1->u.bits.BusNumber = BusHandler->BusNumber; + PciCfg1->u.bits.DeviceNumber = Slot.u.bits.DeviceNumber; + PciCfg1->u.bits.FunctionNumber = Slot.u.bits.FunctionNumber; + PciCfg1->u.bits.Enable = TRUE; + + /* Acquire the lock */ + KeRaiseIrql(HIGH_LEVEL, Irql); + KiAcquireSpinLock(&HalpPCIConfigLock); +} + +VOID +NTAPI +HalpPCIReleaseSynchronzationType1(IN PBUS_HANDLER BusHandler, + IN KIRQL Irql) +{ + PCI_TYPE1_CFG_BITS PciCfg1; + PPCIPBUSDATA BusData = (PPCIPBUSDATA)BusHandler->BusData; + + /* Clear the PCI Configuration Register */ + PciCfg1.u.AsULONG = 0; + WRITE_PORT_ULONG(BusData->Config.Type1.Address, PciCfg1.u.AsULONG); + + /* Release the lock */ + KiReleaseSpinLock(&HalpPCIConfigLock); + KeLowerIrql(Irql); +} + +TYPE1_READ(HalpPCIReadUcharType1, UCHAR) +TYPE1_READ(HalpPCIReadUshortType1, USHORT) +TYPE1_READ(HalpPCIReadUlongType1, ULONG) + +TYPE1_WRITE(HalpPCIWriteUcharType1, UCHAR) +TYPE1_WRITE(HalpPCIWriteUshortType1, USHORT) +TYPE1_WRITE(HalpPCIWriteUlongType1, ULONG) + +/* TYPE 2 FUNCTIONS **********************************************************/ + +VOID +NTAPI +HalpPCISynchronizeType2(IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PKIRQL Irql, + IN PPCI_TYPE2_ADDRESS_BITS PciCfg) +{ + PCI_TYPE2_CSE_BITS PciCfg2Cse; + PPCIPBUSDATA BusData = (PPCIPBUSDATA)BusHandler->BusData; + + /* Setup the configuration register */ + PciCfg->u.AsUSHORT = 0; + PciCfg->u.bits.Agent = (USHORT)Slot.u.bits.DeviceNumber; + PciCfg->u.bits.AddressBase = (USHORT)BusData->Config.Type2.Base; + + /* Acquire the lock */ + KeRaiseIrql(HIGH_LEVEL, Irql); + KiAcquireSpinLock(&HalpPCIConfigLock); + + /* Setup the CSE Register */ + PciCfg2Cse.u.AsUCHAR = 0; + PciCfg2Cse.u.bits.Enable = TRUE; + PciCfg2Cse.u.bits.FunctionNumber = (UCHAR)Slot.u.bits.FunctionNumber; + PciCfg2Cse.u.bits.Key = -1; + + /* Write the bus number and CSE */ + WRITE_PORT_UCHAR(BusData->Config.Type2.Forward, (UCHAR)BusHandler->BusNumber); + WRITE_PORT_UCHAR(BusData->Config.Type2.CSE, PciCfg2Cse.u.AsUCHAR); +} + +VOID +NTAPI +HalpPCIReleaseSynchronizationType2(IN PBUS_HANDLER BusHandler, + IN KIRQL Irql) +{ + PCI_TYPE2_CSE_BITS PciCfg2Cse; + PPCIPBUSDATA BusData = (PPCIPBUSDATA)BusHandler->BusData; + + /* Clear CSE and bus number */ + PciCfg2Cse.u.AsUCHAR = 0; + WRITE_PORT_UCHAR(BusData->Config.Type2.CSE, PciCfg2Cse.u.AsUCHAR); + WRITE_PORT_UCHAR(BusData->Config.Type2.Forward, 0); + + /* Release the lock */ + KiReleaseSpinLock(&HalpPCIConfigLock); + KeLowerIrql(Irql); +} + +TYPE2_READ(HalpPCIReadUcharType2, UCHAR) +TYPE2_READ(HalpPCIReadUshortType2, USHORT) +TYPE2_READ(HalpPCIReadUlongType2, ULONG) + +TYPE2_WRITE(HalpPCIWriteUcharType2, UCHAR) +TYPE2_WRITE(HalpPCIWriteUshortType2, USHORT) +TYPE2_WRITE(HalpPCIWriteUlongType2, ULONG) + +/* PCI CONFIGURATION SPACE ***************************************************/ + +VOID +NTAPI +HalpPCIConfig(IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length, + IN FncConfigIO * ConfigIO) +{ + KIRQL OldIrql; + ULONG ix; + ULONG Bytes; + UCHAR State[20]; + + /* Synchronize the operation */ + PCIConfigHandler.Synchronize(BusHandler, Slot, &OldIrql, State); + + /* Loop every increment */ + while (Length) + { + /* Find out the type of read/write we need to do */ + ix = PCIDeref[Offset % sizeof(ULONG)][Length % sizeof(ULONG)]; + + /* Do the read/write and return the number of bytes */ + Bytes = ConfigIO[ix]((PPCIPBUSDATA)BusHandler->BusData, State, Buffer, Offset); + + /* Increment the buffer position and offset, and decrease the length */ + Offset += Bytes; + Buffer += Bytes; + Length -= Bytes; + } + + /* Release the lock and PCI bus */ + PCIConfigHandler.ReleaseSynchronzation(BusHandler, OldIrql); +} + +BOOLEAN +NTAPI +HalpValidPCISlot(IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot) +{ + PCI_SLOT_NUMBER MultiSlot; + PPCIPBUSDATA BusData = (PPCIPBUSDATA)BusHandler->BusData; + UCHAR HeaderType; + //ULONG Device; + + /* Simple validation */ + if (Slot.u.bits.Reserved) + return FALSE; + + if (Slot.u.bits.DeviceNumber >= BusData->MaxDevice) + return FALSE; + + /* Function 0 doesn't need checking */ + if (!Slot.u.bits.FunctionNumber) + return TRUE; + + /* Functions 0+ need Multi-Function support, so check the slot */ + //Device = Slot.u.bits.DeviceNumber; + MultiSlot = Slot; + MultiSlot.u.bits.FunctionNumber = 0; + + /* Send function 0 request to get the header back */ + HalpReadPCIConfig(BusHandler, + MultiSlot, + &HeaderType, + FIELD_OFFSET(PCI_COMMON_CONFIG, HeaderType), + sizeof(UCHAR)); + + /* Now make sure the header is multi-function */ + if (!(HeaderType & PCI_MULTIFUNCTION) || (HeaderType == 0xFF)) + return FALSE; + + return TRUE; +} + +VOID +NTAPI +HalpReadPCIConfig(IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length) +{ + /* Validate the PCI Slot */ + if (!HalpValidPCISlot(BusHandler, Slot)) + { + /* Fill the buffer with invalid data */ + RtlFillMemory(Buffer, Length, -1); + return; + } + + /* Send the request */ + HalpPCIConfig(BusHandler, Slot, Buffer, Offset, Length, PCIConfigHandler.ConfigRead); +} + +VOID +NTAPI +HalpWritePCIConfig(IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length) +{ + /* Validate the PCI Slot */ + if (!HalpValidPCISlot(BusHandler, Slot)) + return; + + /* Send the request */ + HalpPCIConfig(BusHandler, Slot, Buffer, Offset, Length, PCIConfigHandler.ConfigWrite); +} + +/* HAL PCI FOR DEBUGGING *****************************************************/ + +CODE_SEG("INIT") +NTSTATUS +NTAPI +HalpSetupPciDeviceForDebugging(IN PVOID LoaderBlock, + IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +CODE_SEG("INIT") +NTSTATUS +NTAPI +HalpReleasePciDeviceForDebugging(IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +/* HAL PCI CALLBACKS *********************************************************/ + +ULONG +NTAPI +HalpGetPCIData(IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG SlotNumber, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length) +{ + PCI_SLOT_NUMBER Slot; + UCHAR PciBuffer[PCI_COMMON_HDR_LENGTH]; + PPCI_COMMON_CONFIG PciConfig = (PPCI_COMMON_CONFIG)PciBuffer; + ULONG Len = 0; + + Slot.u.AsULONG = SlotNumber; + + /* Normalize the length */ + if (Length > sizeof(PCI_COMMON_CONFIG)) + Length = sizeof(PCI_COMMON_CONFIG); + + /* Check if this is a vendor-specific read */ + if (Offset >= PCI_COMMON_HDR_LENGTH) + { + /* Read the header */ + HalpReadPCIConfig(BusHandler, Slot, PciConfig, 0, sizeof(ULONG)); + + /* Make sure the vendor is valid */ + if (PciConfig->VendorID == PCI_INVALID_VENDORID) + return 0; + } + else + { + /* Read the entire header */ + Len = PCI_COMMON_HDR_LENGTH; + HalpReadPCIConfig(BusHandler, Slot, PciConfig, 0, Len); + + /* Validate the vendor ID */ + if (PciConfig->VendorID == PCI_INVALID_VENDORID) + { + /* It's invalid, but we want to return this much */ + Len = sizeof(USHORT); + } + + /* Now check if there's space left */ + if (Len < Offset) + return 0; + + /* There is, so return what's after the offset and normalize */ + Len -= Offset; + if (Len > Length) + Len = Length; + + /* Copy the data into the caller's buffer */ + RtlMoveMemory(Buffer, PciBuffer + Offset, Len); + + /* Update buffer and offset, decrement total length */ + Offset += Len; + Buffer = (PVOID)((ULONG_PTR)Buffer + Len); + Length -= Len; + } + + /* Now we still have something to copy */ + if (!Length) + return Len; + + /* Check if it's vendor-specific data */ + if (Offset >= PCI_COMMON_HDR_LENGTH) + { + /* Read it now */ + HalpReadPCIConfig(BusHandler, Slot, Buffer, Offset, Length); + Len += Length; + } + + /* Update the total length read */ + return Len; +} + +ULONG +NTAPI +HalpSetPCIData(IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG SlotNumber, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length) +{ + PCI_SLOT_NUMBER Slot; + UCHAR PciBuffer[PCI_COMMON_HDR_LENGTH]; + PPCI_COMMON_CONFIG PciConfig = (PPCI_COMMON_CONFIG)PciBuffer; + ULONG Len = 0; + + Slot.u.AsULONG = SlotNumber; + + /* Normalize the length */ + if (Length > sizeof(PCI_COMMON_CONFIG)) + Length = sizeof(PCI_COMMON_CONFIG); + + /* Check if this is a vendor-specific read */ + if (Offset >= PCI_COMMON_HDR_LENGTH) + { + /* Read the header */ + HalpReadPCIConfig(BusHandler, Slot, PciConfig, 0, sizeof(ULONG)); + + /* Make sure the vendor is valid */ + if (PciConfig->VendorID == PCI_INVALID_VENDORID) + return 0; + } + else + { + /* Read the entire header and validate the vendor ID */ + Len = PCI_COMMON_HDR_LENGTH; + HalpReadPCIConfig(BusHandler, Slot, PciConfig, 0, Len); + + if (PciConfig->VendorID == PCI_INVALID_VENDORID) + return 0; + + /* Return what's after the offset and normalize */ + Len -= Offset; + if (Len > Length) + Len = Length; + + /* Copy the specific caller data */ + RtlMoveMemory(PciBuffer + Offset, Buffer, Len); + + /* Write the actual configuration data */ + HalpWritePCIConfig(BusHandler, Slot, PciBuffer + Offset, Offset, Len); + + /* Update buffer and offset, decrement total length */ + Offset += Len; + Buffer = (PVOID)((ULONG_PTR)Buffer + Len); + Length -= Len; + } + + /* Now we still have something to copy */ + if (!Length) + return Len; + + /* Check if it's vendor-specific data */ + if (Offset >= PCI_COMMON_HDR_LENGTH) + { + /* Read it now */ + HalpWritePCIConfig(BusHandler, Slot, Buffer, Offset, Length); + Len += Length; + } + + /* Update the total length read */ + return Len; +} + +static +ULONG +NTAPI +PciSize(ULONG Base, ULONG Mask) +{ + ULONG Size = Mask & Base; /* Find the significant bits */ + Size = Size & ~(Size - 1); /* Get the lowest of them to find the decode size */ + return Size; +} + +NTSTATUS +NTAPI +HalpAssignPCISlotResources(IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PUNICODE_STRING RegistryPath, + IN PUNICODE_STRING DriverClassName OPTIONAL, + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT DeviceObject OPTIONAL, + IN ULONG Slot, + IN OUT PCM_RESOURCE_LIST *AllocatedResources) +{ + PCI_COMMON_CONFIG PciConfig; + SIZE_T Address; + ULONG ResourceCount; + ULONG Size[PCI_TYPE0_ADDRESSES]; + NTSTATUS Status = STATUS_SUCCESS; + UCHAR Offset; + PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor; + PCI_SLOT_NUMBER SlotNumber; + ULONG WriteBuffer; + ULONG size; + + DPRINT1("WARNING: PCI Slot Resource Assignment is FOOBAR\n"); + + /* FIXME: Should handle 64-bit addresses */ + + /* Read configuration data */ + SlotNumber.u.AsULONG = Slot; + HalpReadPCIConfig(BusHandler, SlotNumber, &PciConfig, 0, PCI_COMMON_HDR_LENGTH); + + /* Check if we read it correctly */ + if (PciConfig.VendorID == PCI_INVALID_VENDORID) + return STATUS_NO_SUCH_DEVICE; + + /* Read the PCI configuration space for the device and store base address and + size information in temporary storage. Count the number of valid base addresses + */ + ResourceCount = 0; + for (Address = 0; Address < PCI_TYPE0_ADDRESSES; Address++) + { + if (0xffffffff == PciConfig.u.type0.BaseAddresses[Address]) + PciConfig.u.type0.BaseAddresses[Address] = 0; + + /* Memory resource */ + if (0 != PciConfig.u.type0.BaseAddresses[Address]) + { + ResourceCount++; + + Offset = (UCHAR)FIELD_OFFSET(PCI_COMMON_CONFIG, u.type0.BaseAddresses[Address]); + + /* Write 0xFFFFFFFF there */ + WriteBuffer = 0xffffffff; + HalpWritePCIConfig(BusHandler, SlotNumber, &WriteBuffer, Offset, sizeof(ULONG)); + + /* Read that figure back from the config space */ + HalpReadPCIConfig(BusHandler, SlotNumber, &Size[Address], Offset, sizeof(ULONG)); + + /* Write back initial value */ + HalpWritePCIConfig(BusHandler, SlotNumber, &PciConfig.u.type0.BaseAddresses[Address], Offset, sizeof(ULONG)); + } + } + + /* Interrupt resource */ + if (0 != PciConfig.u.type0.InterruptPin && + 0 != PciConfig.u.type0.InterruptLine && + 0xFF != PciConfig.u.type0.InterruptLine) + { + ResourceCount++; + } + + /* Allocate output buffer and initialize */ + size = sizeof(CM_RESOURCE_LIST) + (ResourceCount - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR); + + *AllocatedResources = ExAllocatePoolWithTag(PagedPool, size, TAG_HAL); + if (NULL == *AllocatedResources) + { + DPRINT1("HalpAssignPCISlotResources: STATUS_NO_MEMORY\n"); + return STATUS_NO_MEMORY; + } + + (*AllocatedResources)->Count = 1; + (*AllocatedResources)->List[0].InterfaceType = PCIBus; + (*AllocatedResources)->List[0].BusNumber = BusHandler->BusNumber; + (*AllocatedResources)->List[0].PartialResourceList.Version = 1; + (*AllocatedResources)->List[0].PartialResourceList.Revision = 1; + (*AllocatedResources)->List[0].PartialResourceList.Count = ResourceCount; + + Descriptor = (*AllocatedResources)->List[0].PartialResourceList.PartialDescriptors; + + /* Store configuration information */ + for (Address = 0; Address < PCI_TYPE0_ADDRESSES; Address++) + { + if (0 != PciConfig.u.type0.BaseAddresses[Address]) + { + if (PCI_ADDRESS_MEMORY_SPACE == (PciConfig.u.type0.BaseAddresses[Address] & 0x1)) + { + Descriptor->Type = CmResourceTypeMemory; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; /* FIXME I have no idea... */ + Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE; /* FIXME Just a guess */ + Descriptor->u.Memory.Start.QuadPart = (PciConfig.u.type0.BaseAddresses[Address] & PCI_ADDRESS_MEMORY_ADDRESS_MASK); + Descriptor->u.Memory.Length = PciSize(Size[Address], PCI_ADDRESS_MEMORY_ADDRESS_MASK); + } + else if (PCI_ADDRESS_IO_SPACE == (PciConfig.u.type0.BaseAddresses[Address] & 0x1)) + { + Descriptor->Type = CmResourceTypePort; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; /* FIXME I have no idea... */ + Descriptor->Flags = CM_RESOURCE_PORT_IO; /* FIXME Just a guess */ + Descriptor->u.Port.Start.QuadPart = PciConfig.u.type0.BaseAddresses[Address] &= PCI_ADDRESS_IO_ADDRESS_MASK; + Descriptor->u.Port.Length = PciSize(Size[Address], PCI_ADDRESS_IO_ADDRESS_MASK & 0xffff); + } + else + { + ASSERT(FALSE); + return STATUS_UNSUCCESSFUL; + } + + Descriptor++; + } + } + + if (0 != PciConfig.u.type0.InterruptPin && + 0 != PciConfig.u.type0.InterruptLine && + 0xFF != PciConfig.u.type0.InterruptLine) + { + Descriptor->Type = CmResourceTypeInterrupt; + Descriptor->ShareDisposition = CmResourceShareShared; /* FIXME Just a guess */ + Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; /* FIXME Just a guess */ + Descriptor->u.Interrupt.Level = PciConfig.u.type0.InterruptLine; + Descriptor->u.Interrupt.Vector = PciConfig.u.type0.InterruptLine; + Descriptor->u.Interrupt.Affinity = 0xFFFFFFFF; + + Descriptor++; + } + + ASSERT(Descriptor == (*AllocatedResources)->List[0].PartialResourceList.PartialDescriptors + ResourceCount); + + /* FIXME: Should store the resources in the registry resource map */ + + return Status; +} + +ULONG +NTAPI +HaliPciInterfaceReadConfig(_In_ PBUS_HANDLER RootBusHandler, + _In_ ULONG BusNumber, + _In_ PCI_SLOT_NUMBER SlotNumber, + _In_ PVOID Buffer, + _In_ ULONG Offset, + _In_ ULONG Length) +{ + BUS_HANDLER BusHandler; + + /* Setup fake PCI Bus handler */ + RtlCopyMemory(&BusHandler, &HalpFakePciBusHandler, sizeof(BUS_HANDLER)); + BusHandler.BusNumber = BusNumber; + + /* Read configuration data */ + HalpReadPCIConfig(&BusHandler, SlotNumber, Buffer, Offset, Length); + + /* Return length */ + return Length; +} + +ULONG +NTAPI +HaliPciInterfaceWriteConfig(_In_ PBUS_HANDLER RootBusHandler, + _In_ ULONG BusNumber, + _In_ PCI_SLOT_NUMBER SlotNumber, + _In_ PVOID Buffer, + _In_ ULONG Offset, + _In_ ULONG Length) +{ + BUS_HANDLER BusHandler; + + /* Setup fake PCI Bus handler */ + RtlCopyMemory(&BusHandler, &HalpFakePciBusHandler, sizeof(BUS_HANDLER)); + BusHandler.BusNumber = BusNumber; + + /* Write configuration data */ + HalpWritePCIConfig(&BusHandler, SlotNumber, Buffer, Offset, Length); + + /* Return length */ + return Length; +} + +CODE_SEG("INIT") +VOID +NTAPI +HalpRegisterPciDebuggingDeviceInfo(VOID) +{ + BOOLEAN Found = FALSE; + ULONG ix; + + PAGED_CODE(); + + /* Loop PCI debugging devices */ + for (ix = 0; ix < 2; ix++) + { + /* Reserved bit is set if we found one */ + if (HalpPciDebuggingDevice[ix].u.bits.Reserved1) + { + Found = TRUE; + break; + } + } + + /* Bail out if there aren't any */ + if (!Found) + return; + + /* FIXME: TODO */ + UNIMPLEMENTED_DBGBREAK("You have implemented the KD routines for searching PCI debugger" + "devices, but you have forgotten to implement this routine\n"); +} + +CODE_SEG("INIT") +PPCI_REGISTRY_INFO_INTERNAL +NTAPI +HalpQueryPciRegistryInfo(VOID) +{ + WCHAR NameBuffer[8]; + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING KeyName, ConfigName, IdentName; + HANDLE KeyHandle, BusKeyHandle, CardListHandle; + NTSTATUS Status; + UCHAR KeyBuffer[sizeof(CM_FULL_RESOURCE_DESCRIPTOR) + 100]; + PKEY_VALUE_FULL_INFORMATION ValueInfo = (PVOID)KeyBuffer; + UCHAR PartialKeyBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(PCI_CARD_DESCRIPTOR)]; + PKEY_VALUE_PARTIAL_INFORMATION PartialValueInfo = (PVOID)PartialKeyBuffer; + KEY_FULL_INFORMATION KeyInformation; + ULONG ResultLength; + PWSTR Tag; + ULONG ix, ElementCount; + PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor; + PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor; + PPCI_REGISTRY_INFO PciRegInfo; + PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo; + PPCI_CARD_DESCRIPTOR CardDescriptor; + ULONG Size; + + /* Setup the object attributes for the key */ + RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\Hardware\\Description\\System\\MultiFunctionAdapter"); + InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL); + + /* Open the key */ + Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes); + if (!NT_SUCCESS(Status)) + { + DPRINT1("HalpQueryPciRegistryInfo: Status %X\n", Status); + return NULL; + } + + /* Setup the receiving string */ + KeyName.Buffer = NameBuffer; + KeyName.MaximumLength = sizeof(NameBuffer); + + /* Setup the configuration and identifier key names */ + RtlInitUnicodeString(&ConfigName, L"Configuration Data"); + RtlInitUnicodeString(&IdentName, L"Identifier"); + + /* Keep looping for each ID */ + for (ix = 0; TRUE; ix++) + { + /* Setup the key name */ + RtlIntegerToUnicodeString(ix, 10, &KeyName); + InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, KeyHandle, NULL); + + /* Open it */ + Status = ZwOpenKey(&BusKeyHandle, KEY_READ, &ObjectAttributes); + if (!NT_SUCCESS(Status)) + { + /* None left, fail */ + ZwClose(KeyHandle); + return NULL; + } + + /* Read the registry data */ + Status = ZwQueryValueKey(BusKeyHandle, + &IdentName, + KeyValueFullInformation, + ValueInfo, + sizeof(KeyBuffer), + &ResultLength); + if (!NT_SUCCESS(Status)) + { + /* Failed, try the next one */ + ZwClose(BusKeyHandle); + continue; + } + + /* Get the PCI Tag and validate it */ + Tag = (PWSTR)((ULONG_PTR)ValueInfo + ValueInfo->DataOffset); + + if ((Tag[0] != L'P') || + (Tag[1] != L'C') || + (Tag[2] != L'I') || + (Tag[3])) + { + /* Not a valid PCI entry, skip it */ + ZwClose(BusKeyHandle); + continue; + } + + /* Now read our PCI structure */ + Status = ZwQueryValueKey(BusKeyHandle, + &ConfigName, + KeyValueFullInformation, + ValueInfo, + sizeof(KeyBuffer), + &ResultLength); + ZwClose(BusKeyHandle); + if (!NT_SUCCESS(Status)) + continue; + + /* We read it OK! Get the actual resource descriptors */ + FullDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((ULONG_PTR)ValueInfo + ValueInfo->DataOffset); + PartialDescriptor = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)((ULONG_PTR)FullDescriptor->PartialResourceList.PartialDescriptors); + + /* Check if this is our PCI Registry Information */ + if (PartialDescriptor->Type == CmResourceTypeDeviceSpecific) + break; + } + + ZwClose(KeyHandle); + + /* Save the PCI information for later */ + PciRegInfo = (PPCI_REGISTRY_INFO)(PartialDescriptor + 1); + + /* Assume no Card List entries */ + ElementCount = 0; + + /* Set up for checking the PCI Card List key */ + RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\PnP\\PCI\\CardList"); + InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, NULL, NULL); + + /* Attempt to open it */ + Status = ZwOpenKey(&CardListHandle, KEY_READ, &ObjectAttributes); + if (!NT_SUCCESS(Status)) + { + /* No key, no Card List */ + PciRegistryInfo = NULL; + goto Finish; + } + + /* It exists, so let's query it */ + Status = ZwQueryKey(CardListHandle, KeyFullInformation, &KeyInformation, sizeof(KEY_FULL_INFORMATION), &ResultLength); + if (!NT_SUCCESS(Status)) + { + /* Failed to query, so no info */ + PciRegistryInfo = NULL; + ZwClose(CardListHandle); + goto Finish; + } + + /* Allocate the full structure */ + Size = (sizeof(PCI_REGISTRY_INFO_INTERNAL) + (KeyInformation.Values * sizeof(PCI_CARD_DESCRIPTOR))); + + PciRegistryInfo = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_HAL); + if (!PciRegistryInfo) + { + ZwClose(CardListHandle); + goto Finish; + } + + /* Get the first card descriptor entry */ + CardDescriptor = (PPCI_CARD_DESCRIPTOR)(PciRegistryInfo + 1); + + /* Loop all the values */ + for (ix = 0; ix < KeyInformation.Values; ix++) + { + /* Attempt to get the value */ + Status = ZwEnumerateValueKey(CardListHandle, + ix, + KeyValuePartialInformation, + PartialValueInfo, + sizeof(PartialKeyBuffer), + &ResultLength); + if (!NT_SUCCESS(Status)) + break; + + /* Make sure it is correctly sized */ + if (PartialValueInfo->DataLength == sizeof(PCI_CARD_DESCRIPTOR)) + { + /* Sure is, copy it over */ + *CardDescriptor = *(PPCI_CARD_DESCRIPTOR)PartialValueInfo->Data; + + /* One more Card List entry */ + ElementCount++; + + /* Move to the next descriptor */ + CardDescriptor = (CardDescriptor + 1); + } + } + + ZwClose(CardListHandle); + +Finish: + + /* Check if we failed to get the full structure */ + if (!PciRegistryInfo) + { + /* Just allocate the basic structure then */ + PciRegistryInfo = ExAllocatePoolWithTag(NonPagedPool, sizeof(PCI_REGISTRY_INFO_INTERNAL), TAG_HAL); + if (!PciRegistryInfo) + { + DPRINT1("HalpQueryPciRegistryInfo: Status %X\n", Status); + return NULL; + } + } + + PciRegistryInfo->MajorRevision = PciRegInfo->MajorRevision; + PciRegistryInfo->MinorRevision = PciRegInfo->MinorRevision; + PciRegistryInfo->NoBuses = PciRegInfo->NoBuses; + PciRegistryInfo->HardwareMechanism = PciRegInfo->HardwareMechanism; + PciRegistryInfo->ElementCount = ElementCount; + + return PciRegistryInfo; +} + +CODE_SEG("INIT") +VOID +NTAPI +HalpInitializePciStubs(VOID) +{ + PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo; + UCHAR PciType; + PPCIPBUSDATA BusData = (PPCIPBUSDATA)HalpFakePciBusHandler.BusData; + ULONG Bus; + PCI_SLOT_NUMBER Slot; + ULONG VendorId = 0; + ULONG MaxPciBusNumber; + + /* Query registry information */ + PciRegistryInfo = HalpQueryPciRegistryInfo(); + if (!PciRegistryInfo) + { + /* Assume type 1 */ + PciType = 1; + + /* Force a manual bus scan later */ + MaxPciBusNumber = MAXULONG; + } + else + { + /* Get the PCI type */ + PciType = (PciRegistryInfo->HardwareMechanism & 0xF); + + /* Get MaxPciBusNumber and make it 0-based */ + MaxPciBusNumber = (PciRegistryInfo->NoBuses - 1); + + /* Free the info structure */ + ExFreePoolWithTag(PciRegistryInfo, TAG_HAL); + } + + /* Initialize the PCI lock */ + KeInitializeSpinLock(&HalpPCIConfigLock); + + /* Check the type of PCI bus */ + switch (PciType) + { + /* Type 1 PCI Bus */ + case 1: + + /* Copy the Type 1 handler data */ + RtlCopyMemory(&PCIConfigHandler, &PCIConfigHandlerType1, sizeof(PCIConfigHandler)); + + /* Set correct I/O Ports */ + BusData->Config.Type1.Address = PCI_TYPE1_ADDRESS_PORT; + BusData->Config.Type1.Data = PCI_TYPE1_DATA_PORT; + break; + + /* Type 2 PCI Bus */ + case 2: + + /* Copy the Type 2 handler data */ + RtlCopyMemory(&PCIConfigHandler, &PCIConfigHandlerType2, sizeof(PCIConfigHandler)); + + /* Set correct I/O Ports */ + BusData->Config.Type2.CSE = PCI_TYPE2_CSE_PORT; + BusData->Config.Type2.Forward = PCI_TYPE2_FORWARD_PORT; + BusData->Config.Type2.Base = PCI_TYPE2_ADDRESS_BASE; + + /* Only 16 devices supported, not 32 */ + BusData->MaxDevice = 0x10; + break; + + default: + /* Invalid type */ + DbgPrint("HAL: Unknown PCI type\n"); + } + + /* Run a forced bus scan if needed */ + if (MaxPciBusNumber != MAXULONG) + goto Exit; + + /* Initialize the max bus number to 0xFF */ + HalpMaxPciBus = 0xFF; + + /* Initialize the counter */ + MaxPciBusNumber = 0; + + /* Loop all possible buses */ + for (Bus = 0; Bus < HalpMaxPciBus; Bus++) + { + /* Loop all devices */ + for (Slot.u.AsULONG = 0; Slot.u.AsULONG < BusData->MaxDevice; Slot.u.AsULONG++) + { + /* Query the interface */ + if (HaliPciInterfaceReadConfig(NULL, Bus, Slot, &VendorId, 0, sizeof(ULONG))) + { + /* Validate the vendor ID */ + if ((VendorId & 0xFFFF) != PCI_INVALID_VENDORID) + { + /* Set this as the maximum ID */ + MaxPciBusNumber = Bus; + break; + } + } + } + } + +Exit: + + /* Set the real max bus number */ + HalpMaxPciBus = MaxPciBusNumber; + + /* We're done */ + HalpPCIConfigInitialized = TRUE; +} + +/* EOF */ + diff --git a/hal/halacpi/generic/beep.c b/hal/halacpi/generic/beep.c new file mode 100644 index 0000000000000..db4747a44382c --- /dev/null +++ b/hal/halacpi/generic/beep.c @@ -0,0 +1,78 @@ + +/* INCLUDES ******************************************************************/ + +#include +#include "../pic/timer.h" +//#define NDEBUG +#include + +/* PUBLIC FUNCTIONS ***********************************************************/ + +BOOLEAN +NTAPI +HalMakeBeep(IN ULONG Frequency) +{ + SYSTEM_CONTROL_PORT_B_REGISTER SystemControl; + TIMER_CONTROL_PORT_REGISTER TimerControl; + ULONG Divider; + BOOLEAN Result = FALSE; + + HalpAcquireCmosSpinLock(); + + /* Turn the timer off by disconnecting its output pin and speaker gate. */ + SystemControl.Bits = READ_PORT_UCHAR(SYSTEM_CONTROL_PORT_B); + SystemControl.SpeakerDataEnable = FALSE; + SystemControl.Timer2GateToSpeaker = FALSE; + WRITE_PORT_UCHAR(SYSTEM_CONTROL_PORT_B, SystemControl.Bits); + + if (!Frequency) + goto Exit; + + Divider = (PIT_FREQUENCY / Frequency); + + if (Divider > 0x10000) + goto Exit; + + /* Program the PIT for binary mode. */ + TimerControl.BcdMode = FALSE; + + /* Program the PIT to generate a square wave (Mode 3) on channel 2. + Channel 0 is used for the IRQ0 clock interval timer, and channel + 1 is used for DRAM refresh. + + Mode 2 gives much better accuracy, but generates an output signal + that drops to low for each input signal cycle at 0.8381 useconds. + This is too fast for the PC speaker to process and would result + in no sound being emitted. + + Mode 3 will generate a high pulse that is a bit longer and will + allow the PC speaker to notice. Additionally, take note that on + channel 2, when input goes low the counter will stop and output + will go to high. + */ + TimerControl.OperatingMode = PitOperatingMode3; + TimerControl.Channel = PitChannel2; + + /* Set the access mode that we'll use to program the reload value. */ + TimerControl.AccessMode = PitAccessModeLowHigh; + + /* Now write the programming bits */ + WRITE_PORT_UCHAR(TIMER_CONTROL_PORT, TimerControl.Bits); + + /* Next we write the reload value for channel 2 */ + WRITE_PORT_UCHAR(TIMER_CHANNEL2_DATA_PORT, Divider & 0xFF); + WRITE_PORT_UCHAR(TIMER_CHANNEL2_DATA_PORT, (Divider >> 8) & 0xFF); + + /* Reconnect the speaker to the timer and re-enable the output pin. */ + SystemControl.Bits = READ_PORT_UCHAR(SYSTEM_CONTROL_PORT_B); + SystemControl.SpeakerDataEnable = TRUE; + SystemControl.Timer2GateToSpeaker = TRUE; + WRITE_PORT_UCHAR(SYSTEM_CONTROL_PORT_B, SystemControl.Bits); + + Result = TRUE; + +Exit: + HalpReleaseCmosSpinLock(); + + return Result; +} diff --git a/hal/halacpi/generic/cmos.c b/hal/halacpi/generic/cmos.c new file mode 100644 index 0000000000000..70291b806f8f6 --- /dev/null +++ b/hal/halacpi/generic/cmos.c @@ -0,0 +1,294 @@ + +/* INCLUDES ******************************************************************/ + +#include +//#define NDEBUG +#include + +/* Conversion functions */ +#define BCD_INT(bcd) (((bcd & 0xF0) >> 4) * 10 + (bcd & 0x0F)) +#define INT_BCD(int) (UCHAR)(((int / 10) << 4) + (int % 10)) + +/* GLOBALS *******************************************************************/ + +UCHAR HalpCmosCenturyOffset = 0; +extern FADT HalpFixedAcpiDescTable; + +/* PRIVATE FUNCTIONS *********************************************************/ + +UCHAR +NTAPI +HalpReadCmos(IN UCHAR Reg) +{ + /* Select the register */ + WRITE_PORT_UCHAR(CMOS_CONTROL_PORT, Reg); + + /* Query the value */ + return READ_PORT_UCHAR(CMOS_DATA_PORT); +} + +VOID +NTAPI +HalpWriteCmos(IN UCHAR Reg, + IN UCHAR Value) +{ + /* Select the register */ + WRITE_PORT_UCHAR(CMOS_CONTROL_PORT, Reg); + + /* Write the value */ + WRITE_PORT_UCHAR(CMOS_DATA_PORT, Value); +} + +ULONG +NTAPI +HalpGetCmosData(IN ULONG BusNumber, + IN ULONG SlotNumber, + IN PVOID Buffer, + IN ULONG Length) +{ + PUCHAR Ptr = (PUCHAR)Buffer; + ULONG Address = SlotNumber; + ULONG Len = Length; + + /* Do nothing if we don't have a length */ + if (!Length) + return 0; + + /* Acquire CMOS Lock */ + HalpAcquireCmosSpinLock(); + + /* Check if this is simple CMOS */ + if (BusNumber == 0) + { + /* Loop the buffer up to 0xFF */ + while ((Len > 0) && (Address < 0x100)) + { + /* Read the data */ + *Ptr = HalpReadCmos((UCHAR)Address); + + /* Update position and length */ + Ptr++; + Address++; + Len--; + } + } + else if (BusNumber == 1) + { + /* Loop the buffer up to 0xFFFF */ + while ((Len > 0) && (Address < 0x10000)) + { + /* Write the data */ + *Ptr = HalpReadCmos((UCHAR)Address); + + /* Update position and length */ + Ptr++; + Address++; + Len--; + } + } + + /* Release CMOS Lock */ + HalpReleaseCmosSpinLock(); + + /* Return length read */ + return (Length - Len); +} + +ULONG +NTAPI +HalpSetCmosData(IN ULONG BusNumber, + IN ULONG SlotNumber, + IN PVOID Buffer, + IN ULONG Length) +{ + PUCHAR Ptr = (PUCHAR)Buffer; + ULONG Address = SlotNumber; + ULONG Len = Length; + + /* Do nothing if we don't have a length */ + if (!Length) + return 0; + + /* Acquire CMOS Lock */ + HalpAcquireCmosSpinLock(); + + /* Check if this is simple CMOS */ + if (BusNumber == 0) + { + /* Loop the buffer up to 0xFF */ + while ((Len > 0) && (Address < 0x100)) + { + /* Write the data */ + HalpWriteCmos((UCHAR)Address, *Ptr); + + /* Update position and length */ + Ptr++; + Address++; + Len--; + } + } + else if (BusNumber == 1) + { + /* Loop the buffer up to 0xFFFF */ + while ((Len > 0) && (Address < 0x10000)) + { + /* Write the data */ + HalpWriteCmos((UCHAR)Address, *Ptr); + + /* Update position and length */ + Ptr++; + Address++; + Len--; + } + } + + /* Release CMOS Lock */ + HalpReleaseCmosSpinLock(); + + /* Return length read */ + return (Length - Len); +} + +CODE_SEG("INIT") +VOID +NTAPI +HalpInitializeCmos(VOID) +{ + /* Set default century offset byte */ + if (HalpFixedAcpiDescTable.century_alarm_index) + { + HalpCmosCenturyOffset = HalpFixedAcpiDescTable.century_alarm_index; + } + else + { + HalpCmosCenturyOffset = 50; + } +} + +/* PUBLIC FUNCTIONS **********************************************************/ + +ARC_STATUS +NTAPI +HalGetEnvironmentVariable(IN PCH Name, + IN USHORT ValueLength, + IN PCH Value) +{ + UCHAR Val; + + /* Only variable supported on x86 */ + if (_stricmp(Name, "LastKnownGood")) + return ENOENT; + + HalpAcquireCmosSpinLock(); + Val = HalpReadCmos(RTC_REGISTER_B); // Query the current value + HalpReleaseCmosSpinLock(); + + /* Check the flag */ + if (Val & 0x01) + strncpy(Value, "FALSE", ValueLength); // out "FALSE" + else + strncpy(Value, "TRUE", ValueLength); // out "TRUE" + + return ESUCCESS; +} + +BOOLEAN +NTAPI +HalQueryRealTimeClock(OUT PTIME_FIELDS Time) +{ + HalpAcquireCmosSpinLock(); + + /* Loop while update is in progress */ + while ((HalpReadCmos(RTC_REGISTER_A)) & RTC_REG_A_UIP) + ; + + /* Set the time data */ + Time->Second = BCD_INT(HalpReadCmos(0)); + Time->Minute = BCD_INT(HalpReadCmos(2)); + Time->Hour = BCD_INT(HalpReadCmos(4)); + Time->Weekday = BCD_INT(HalpReadCmos(6)); + Time->Day = BCD_INT(HalpReadCmos(7)); + Time->Month = BCD_INT(HalpReadCmos(8)); + Time->Year = BCD_INT(HalpReadCmos(9)); + Time->Milliseconds = 0; + + /* FIXME: Check century byte */ + + /* Compensate for the century field */ + Time->Year += ((Time->Year > 80) ? 1900: 2000); + + HalpReleaseCmosSpinLock(); + return TRUE; +} + +ARC_STATUS +NTAPI +HalSetEnvironmentVariable(IN PCH Name, + IN PCH Value) +{ + UCHAR Val; + + /* Only variable supported on x86 */ + if (_stricmp(Name, "LastKnownGood")) + return ENOMEM; + + /* Check if this is true or false */ + if (!_stricmp(Value, "TRUE")) + { + /* It's true, acquire CMOS lock */ + HalpAcquireCmosSpinLock(); + + /* Read the current value and add the flag */ + Val = (HalpReadCmos(RTC_REGISTER_B) | 1); + } + else if (!_stricmp(Value, "FALSE")) + { + /* It's false, acquire CMOS lock */ + HalpAcquireCmosSpinLock(); + + /* Read the current value and mask out the flag */ + Val = (HalpReadCmos(RTC_REGISTER_B) & ~1); + } + else + { + /* Fail */ + return ENOMEM; + } + + /* Write new value */ + HalpWriteCmos(RTC_REGISTER_B, Val); + + /* Release the lock and return success */ + HalpReleaseCmosSpinLock(); + return ESUCCESS; +} + +BOOLEAN +NTAPI +HalSetRealTimeClock(IN PTIME_FIELDS Time) +{ + /* Acquire CMOS Lock */ + HalpAcquireCmosSpinLock(); + + /* Loop while update is in progress */ + while ((HalpReadCmos(RTC_REGISTER_A)) & RTC_REG_A_UIP); + + /* Write time fields to CMOS RTC */ + HalpWriteCmos(0, INT_BCD(Time->Second)); + HalpWriteCmos(2, INT_BCD(Time->Minute)); + HalpWriteCmos(4, INT_BCD(Time->Hour)); + HalpWriteCmos(6, INT_BCD(Time->Weekday)); + HalpWriteCmos(7, INT_BCD(Time->Day)); + HalpWriteCmos(8, INT_BCD(Time->Month)); + HalpWriteCmos(9, INT_BCD(Time->Year % 100)); + + /* FIXME: Set the century byte */ + + /* Release CMOS lock */ + HalpReleaseCmosSpinLock(); + + /* Always return TRUE */ + return TRUE; +} + +/* EOF */ diff --git a/hal/halacpi/generic/display.c b/hal/halacpi/generic/display.c new file mode 100644 index 0000000000000..ba7baca993cbf --- /dev/null +++ b/hal/halacpi/generic/display.c @@ -0,0 +1,47 @@ + +#include +//#define NDEBUG +#include +#include + +/* PUBLIC FUNCTIONS **********************************************************/ + +VOID +NTAPI +HalDisplayString(IN PCH String) +{ +#ifndef _MINIHAL_ + /* Call the Inbv driver */ + InbvDisplayString(String); +#endif +} + +VOID +NTAPI +HalAcquireDisplayOwnership(IN PHAL_RESET_DISPLAY_PARAMETERS ResetDisplayParameters) +{ + /* Stub since Windows XP implemented Inbv */ + return; +} + +VOID +NTAPI +HalQueryDisplayParameters(OUT PULONG DispSizeX, + OUT PULONG DispSizeY, + OUT PULONG CursorPosX, + OUT PULONG CursorPosY) +{ + /* Stub since Windows XP implemented Inbv */ + return; +} + +VOID +NTAPI +HalSetDisplayParameters(IN ULONG CursorPosX, + IN ULONG CursorPosY) +{ + /* Stub since Windows XP implemented Inbv */ + return; +} + +/* EOF */ diff --git a/hal/halacpi/generic/dma.c b/hal/halacpi/generic/dma.c new file mode 100644 index 0000000000000..2d1933462c831 --- /dev/null +++ b/hal/halacpi/generic/dma.c @@ -0,0 +1,2795 @@ +/* + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: hal/halx86/generic/dma.c + * PURPOSE: DMA functions + * PROGRAMMERS: David Welch (welch@mcmail.com) + * Filip Navara (navaraf@reactos.com) + * UPDATE HISTORY: + * Created 22/05/98 + */ + +/** + * @page DMA Implementation Notes + * + * Concepts: + * + * - Map register + * + * Abstract encapsulation of physically contiguous buffer that resides + * in memory accessible by both the DMA device / controller and the system. + * The map registers are allocated and distributed on demand and are + * scarce resource. + * + * The actual use of map registers is to allow transfers from/to buffer + * located in physical memory at address inaccessible by the DMA device / + * controller directly. For such transfers the map register buffers + * are used as intermediate data storage. + * + * - Master adapter + * + * A container for map registers (typically corresponding to one physical + * bus connection type). There can be master adapters for 24-bit address + * ranges, 32-bit address ranges, etc. Every time a new DMA adapter is + * created it's associated with a corresponding master adapter that + * is used for any map register allocation requests. + * + * - Bus-master / Slave DMA + * + * Slave DMA is term used for DMA transfers done by the system (E)ISA + * controller as opposed to transfers mastered by the device itself + * (hence the name). + * + * For slave DMA special care is taken to actually access the system + * controller and handle the transfers. The relevant code is in + * HalpDmaInitializeEisaAdapter, HalReadDmaCounter, IoFlushAdapterBuffers + * and IoMapTransfer. + * + * Implementation: + * + * - Allocation of map registers + * + * Initial set of map registers is allocated on the system start to + * ensure that low memory won't get filled up later. Additional map + * registers are allocated as needed by HalpGrowMapBuffers. This + * routine is called on two places: + * + * - HalGetAdapter, since we're at PASSIVE_LEVEL and it's known that + * more map registers will probably be needed. + * - IoAllocateAdapterChannel (indirectly using HalpGrowMapBufferWorker + * since we're at DISPATCH_LEVEL and call HalpGrowMapBuffers directly) + * when no more map registers are free. + * + * Note that even if no more map registers can be allocated it's not + * the end of the world. The adapters waiting for free map registers + * are queued in the master adapter's queue and once one driver hands + * back it's map registers (using IoFreeMapRegisters or indirectly using + * the execution routine callback in IoAllocateAdapterChannel) the + * queue gets processed and the map registers are reassigned. + */ + +/* INCLUDES *****************************************************************/ + +#include +#include + +#define NDEBUG +#include + +#define MAX_SG_ELEMENTS 0x10 + +#ifndef _MINIHAL_ +static KEVENT HalpDmaLock; +static KSPIN_LOCK HalpDmaAdapterListLock; +static LIST_ENTRY HalpDmaAdapterList; +static PADAPTER_OBJECT HalpEisaAdapter[8]; +#endif +static BOOLEAN HalpEisaDma; +#ifndef _MINIHAL_ +MASTER_ADAPTER HalpMasterAdapter; +LONG HalpOutstandingScatterGatherCount; /* using later */ +#endif + +static const ULONG_PTR HalpEisaPortPage[8] = { + FIELD_OFFSET(DMA_PAGE, Channel0), + FIELD_OFFSET(DMA_PAGE, Channel1), + FIELD_OFFSET(DMA_PAGE, Channel2), + FIELD_OFFSET(DMA_PAGE, Channel3), + 0, + FIELD_OFFSET(DMA_PAGE, Channel5), + FIELD_OFFSET(DMA_PAGE, Channel6), + FIELD_OFFSET(DMA_PAGE, Channel7) +}; + +#ifndef _MINIHAL_ +NTSTATUS +NTAPI +HalCalculateScatterGatherListSize( + IN PADAPTER_OBJECT AdapterObject, + IN PMDL Mdl OPTIONAL, + IN PVOID CurrentVa, + IN ULONG Length, + OUT PULONG ScatterGatherListSize, + OUT PULONG pNumberOfMapRegisters); + +NTSTATUS +NTAPI +HalBuildScatterGatherList( + IN PADAPTER_OBJECT AdapterObject, + IN PDEVICE_OBJECT DeviceObject, + IN PMDL Mdl, + IN PVOID CurrentVa, + IN ULONG Length, + IN PDRIVER_LIST_CONTROL ExecutionRoutine, + IN PVOID Context, + IN BOOLEAN WriteToDevice, + IN PVOID ScatterGatherBuffer, + IN ULONG ScatterGatherLength); + +NTSTATUS +NTAPI +HalBuildMdlFromScatterGatherList(IN PADAPTER_OBJECT AdapterObject, + IN PSCATTER_GATHER_LIST ScatterGather, + IN PMDL OriginalMdl, + OUT PMDL *TargetMdl); + + +static DMA_OPERATIONS HalpDmaOperations = { + sizeof(DMA_OPERATIONS), + (PPUT_DMA_ADAPTER)HalPutDmaAdapter, + (PALLOCATE_COMMON_BUFFER)HalAllocateCommonBuffer, + (PFREE_COMMON_BUFFER)HalFreeCommonBuffer, + (PALLOCATE_ADAPTER_CHANNEL)IoAllocateAdapterChannel, + (PFLUSH_ADAPTER_BUFFERS)IoFlushAdapterBuffers, + (PFREE_ADAPTER_CHANNEL)IoFreeAdapterChannel, + (PFREE_MAP_REGISTERS)IoFreeMapRegisters, + (PMAP_TRANSFER)IoMapTransfer, + (PGET_DMA_ALIGNMENT)HalpDmaGetDmaAlignment, + (PREAD_DMA_COUNTER)HalReadDmaCounter, + (PGET_SCATTER_GATHER_LIST)HalGetScatterGatherList, + (PPUT_SCATTER_GATHER_LIST)HalPutScatterGatherList, + (PCALCULATE_SCATTER_GATHER_LIST_SIZE)HalCalculateScatterGatherListSize, + (PBUILD_SCATTER_GATHER_LIST)HalBuildScatterGatherList, + (PBUILD_MDL_FROM_SCATTER_GATHER_LIST)HalBuildMdlFromScatterGatherList +}; +#endif + +#define MAX_MAP_REGISTERS 64 + +#define TAG_DMA ' AMD' + +/* FUNCTIONS *****************************************************************/ + +#if defined(SARCH_PC98) +/* + * Disable I/O for safety. + * FIXME: Add support for PC-98 DMA controllers. + */ +#undef WRITE_PORT_UCHAR +#undef READ_PORT_UCHAR + +#define WRITE_PORT_UCHAR(Port, Data) \ + do { \ + UNIMPLEMENTED; \ + (Port); \ + (Data); \ + } while (0) + +#define READ_PORT_UCHAR(Port) 0x00 +#endif + +#ifndef _MINIHAL_ +/* + * called at phase 0 + */ +CODE_SEG("INIT") +VOID +HalpInitDma(IN PLOADER_PARAMETER_BLOCK LoaderBlock) +{ + ULONG_PTR InitialMapRegisters; + + if (HalpBusType == MACHINE_TYPE_EISA) + { + /* + * Check if Extended DMA is available. We're just going to do a random + * read and write. + */ + WRITE_PORT_UCHAR(UlongToPtr(FIELD_OFFSET(EISA_CONTROL, DmaController2Pages.Channel2)), 0x2A); + if (READ_PORT_UCHAR(UlongToPtr(FIELD_OFFSET(EISA_CONTROL, DmaController2Pages.Channel2))) == 0x2A) + { + DPRINT1("Machine supports EISA DMA. Bus type: %lu\n", HalpBusType); + HalpEisaDma = TRUE; + } + } + + /* + * Intialize all the global variables and allocate master adapter with + * first map buffers. + */ + InitializeListHead(&HalpDmaAdapterList); + KeInitializeSpinLock(&HalpDmaAdapterListLock); + KeInitializeEvent(&HalpDmaLock, NotificationEvent, TRUE); + + /* + * Try to allocate initial set of map registers on the system start to + * ensure that low memory won't get filled up later. + */ + + HalpMasterAdapter.MaxMapRegisters = MAX_MAP_REGISTERS; + InitialMapRegisters = HalpAllocPhysicalMemory(LoaderBlock, 0x1000000, 0x10, TRUE); + if (InitialMapRegisters != 0) + { + HalpMasterAdapter.InitialMapRegistersBuffer.QuadPart = (ULONGLONG)InitialMapRegisters; + HalpMasterAdapter.InitialMapRegistersBufferLength = 0x10000; + } + + /* + * Setup the HalDispatchTable callback for creating PnP DMA adapters. It's + * used by IoGetDmaAdapter in the kernel. + */ + HalGetDmaAdapter = HalpGetDmaAdapter; +} +#endif + +/** + * @name HalpGetAdapterMaximumPhysicalAddress + * + * Get the maximum physical address acceptable by the device represented + * by the passed DMA adapter. + */ +PHYSICAL_ADDRESS +NTAPI +HalpGetAdapterMaximumPhysicalAddress(IN PADAPTER_OBJECT AdapterObject) +{ + PHYSICAL_ADDRESS HighestAddress; + + if (AdapterObject != NULL && AdapterObject->MasterDevice) + { + if (AdapterObject->Dma64BitAddresses) + { + HighestAddress.QuadPart = 0xFFFFFFFFFFFFFFFFULL; + return HighestAddress; + } + else if (AdapterObject->Dma32BitAddresses) + { + HighestAddress.QuadPart = 0xFFFFFFFF; + return HighestAddress; + } + } + + HighestAddress.QuadPart = 0xFFFFFF; + return HighestAddress; +} + +#ifndef _MINIHAL_ +/** + * @name HalpGrowMapBuffers + * + * Allocate additional, or use the initial, map buffers for DMA master adapter. + * The initial buffer was been allocated at phase 0 of the system boot. See HalpInitDma. + * + * @param MasterAdapter + * DMA master adapter to allocate buffers for. + * @param SizeOfMapBuffers + * Size of the map buffers to allocate (not including the size + * already allocated). + */ +BOOLEAN +NTAPI +HalpGrowMapBuffers(IN PADAPTER_OBJECT AdapterObject, + IN ULONG SizeOfMapBuffers) +{ + PVOID VirtualAddress; + PHYSICAL_ADDRESS PhysicalAddress; + PHYSICAL_ADDRESS HighestAcceptableAddress; + PHYSICAL_ADDRESS LowestAcceptableAddress; + PHYSICAL_ADDRESS BoundryAddressMultiple; + KIRQL OldIrql; + ULONG MapRegisterCount; + + if (AdapterObject->NumberOfMapRegisters == 0 && HalpMasterAdapter.InitialMapRegistersBufferLength) + { + /* + * in this case we use MapRegisters which were allocated at the system startup + */ + MapRegisterCount = BYTES_TO_PAGES(HalpMasterAdapter.InitialMapRegistersBufferLength); + PhysicalAddress = HalpMasterAdapter.InitialMapRegistersBuffer; + VirtualAddress = MmMapIoSpace(PhysicalAddress, + HalpMasterAdapter.InitialMapRegistersBufferLength, + MmNonCached); + + if (VirtualAddress == NULL) + { + /* if an error occurred, we no longer use the initial buffer */ + HalpMasterAdapter.InitialMapRegistersBufferLength = 0; + return FALSE; + } + } + else + { + /* Check if enough map register slots are available. */ + MapRegisterCount = BYTES_TO_PAGES(SizeOfMapBuffers); + if (MapRegisterCount + AdapterObject->NumberOfMapRegisters + (MapRegisterCount * PAGE_SIZE / 0x10000) + > HalpMasterAdapter.MaxMapRegisters) + { + DPRINT("No more map register slots available! (Current: %d | Requested: %d | Limit: %d)\n", + AdapterObject->NumberOfMapRegisters, + MapRegisterCount, + MAX_MAP_REGISTERS); + return FALSE; + } + + /* + * Allocate memory for the new map registers. For 32-bit adapters we use + * two passes in order not to waste scare resource (low memory). + */ + HighestAcceptableAddress = HalpGetAdapterMaximumPhysicalAddress(AdapterObject); + LowestAcceptableAddress.HighPart = 0; + LowestAcceptableAddress.LowPart = HighestAcceptableAddress.LowPart == 0xFFFFFFFF ? 0x1000000 : 0; + BoundryAddressMultiple.QuadPart = 0; + + VirtualAddress = MmAllocateContiguousMemorySpecifyCache(MapRegisterCount << PAGE_SHIFT, + LowestAcceptableAddress, + HighestAcceptableAddress, + BoundryAddressMultiple, + MmNonCached); + + if (!(VirtualAddress) && (LowestAcceptableAddress.LowPart)) + { + LowestAcceptableAddress.LowPart = 0; + VirtualAddress = MmAllocateContiguousMemorySpecifyCache(MapRegisterCount << PAGE_SHIFT, + LowestAcceptableAddress, + HighestAcceptableAddress, + BoundryAddressMultiple, + MmNonCached); + } + + if (!VirtualAddress) return FALSE; + + PhysicalAddress = MmGetPhysicalAddress(VirtualAddress); + } + + /* + * All the following must be done with the master adapter lock held + * to prevent corruption. + */ + KeAcquireSpinLock(&AdapterObject->SpinLock, &OldIrql); + + /* + * Setup map register entries for the buffer allocated. Each entry has + * a virtual and physical address and corresponds to PAGE_SIZE large + * buffer. + */ + if (MapRegisterCount > 0) + { + PROS_MAP_REGISTER_ENTRY CurrentEntry, PreviousEntry; + + CurrentEntry = AdapterObject->MapRegisterBase + AdapterObject->NumberOfMapRegisters; + do + { + /* + * Leave one entry free for every non-contiguous memory region + * in the map register bitmap. This ensures that we can search + * using RtlFindClearBits for contiguous map register regions. + * + * Also for non-EISA DMA leave one free entry for every 64Kb + * break, because the DMA controller can handle only coniguous + * 64Kb regions. + */ + if (CurrentEntry != AdapterObject->MapRegisterBase) + { + PreviousEntry = CurrentEntry - 1; + if ((PreviousEntry->PhysicalAddress.LowPart + PAGE_SIZE) == PhysicalAddress.LowPart) + { + if (!HalpEisaDma) + { + if ((PreviousEntry->PhysicalAddress.LowPart ^ PhysicalAddress.LowPart) & 0xFFFF0000) + { + CurrentEntry++; + AdapterObject->NumberOfMapRegisters++; + } + } + } + else + { + CurrentEntry++; + AdapterObject->NumberOfMapRegisters++; + } + } + + RtlClearBit(AdapterObject->MapRegisters, + (ULONG)(CurrentEntry - AdapterObject->MapRegisterBase)); + CurrentEntry->VirtualAddress = VirtualAddress; + CurrentEntry->PhysicalAddress = PhysicalAddress; + + PhysicalAddress.LowPart += PAGE_SIZE; + VirtualAddress = (PVOID)((ULONG_PTR)VirtualAddress + PAGE_SIZE); + + CurrentEntry++; + AdapterObject->NumberOfMapRegisters++; + MapRegisterCount--; + } while (MapRegisterCount); + } + + KeReleaseSpinLock(&AdapterObject->SpinLock, OldIrql); + + return TRUE; +} + +/** + * @name HalpAllocateAdapter + * + * Helper routine of HalGetAdapter. Allocate child adapter object and master adapter, if not allocated yet, and + * fill out some basic fields. + * + * @see HalGetAdapter + */ +static +PADAPTER_OBJECT +NTAPI +HalpAllocateAdapter(IN ULONG NumberOfMapRegisters, + IN PDEVICE_DESCRIPTION DeviceDescription, + IN BOOLEAN AllocateMasterAdapter) +{ + PADAPTER_OBJECT AdapterObject; + OBJECT_ATTRIBUTES ObjectAttributes; + NTSTATUS Status; + HANDLE Handle; + ULONG ObjectSize, SizeOfBitmap; + + /* + * Allocate MasterAdapter if it has not been allocated yet. + * We do it only when NumberOfMapRegisters != 0, because + * AdapterObjects that do not have MapRegisters, doesn't link to MasterAdapter and don't need it. + */ + if (!AllocateMasterAdapter && NumberOfMapRegisters != 0 && HalpMasterAdapter.AdapterObject == NULL) + { + /* call recursively for allocate master adapter */ + AdapterObject = HalpAllocateAdapter(NumberOfMapRegisters, DeviceDescription, TRUE); + if (!AdapterObject) return NULL; + + AdapterObject->Dma32BitAddresses = DeviceDescription->Dma32BitAddresses; + AdapterObject->MasterDevice = DeviceDescription->Master; + + HalpMasterAdapter.AdapterObject = AdapterObject; + } + + /* calculate the size of the bitmap, and total size of the AdapterObject */ + if (AllocateMasterAdapter) + { + /* For the master adapter, Compute the size, including RTL_BITMAP and bitmap bits */ + SizeOfBitmap = HalpMasterAdapter.MaxMapRegisters; + ObjectSize = sizeof(ADAPTER_OBJECT) + sizeof(RTL_BITMAP) + ((SizeOfBitmap + 7) >> 3); + ObjectSize = (ObjectSize + 3) & ~3; + } + else + { + ObjectSize = sizeof(ADAPTER_OBJECT); + } + + InitializeObjectAttributes(&ObjectAttributes, + NULL, + OBJ_KERNEL_HANDLE | OBJ_PERMANENT, + NULL, + NULL); + + Status = ObCreateObject(KernelMode, + IoAdapterObjectType, + &ObjectAttributes, + KernelMode, + NULL, + ObjectSize, + 0, + 0, + (PVOID)&AdapterObject); + if (!NT_SUCCESS(Status)) return NULL; + + RtlZeroMemory(AdapterObject, ObjectSize); + + Status = ObInsertObject(AdapterObject, + NULL, + FILE_READ_DATA | FILE_WRITE_DATA, + 0, + NULL, + &Handle); + if (!NT_SUCCESS(Status)) return NULL; + + ObReferenceObject(AdapterObject); + + ZwClose(Handle); + + /* + * we always set DmaHeader version is 1 + * see https://msdn.microsoft.com/en-us/library/windows/hardware/ff544062(v=vs.85).aspx + */ + AdapterObject->DmaHeader.Version = 1; + AdapterObject->DmaHeader.Size = ObjectSize; + AdapterObject->DmaHeader.DmaOperations = &HalpDmaOperations; + AdapterObject->MapRegistersPerChannel = 1; + AdapterObject->Dma32BitAddresses = DeviceDescription->Dma32BitAddresses; + AdapterObject->ChannelNumber = 0xFF; + + /* we link adapter object to the master adapter only when NumberOfMapRegisters != 0 */ + AdapterObject->MasterAdapter = (NumberOfMapRegisters != 0) ? HalpMasterAdapter.AdapterObject : NULL; + + KeInitializeDeviceQueue(&AdapterObject->ChannelWaitQueue); + + /* setup the MasterAdapter if allocate it. */ + if (AllocateMasterAdapter) + { + KeInitializeSpinLock(&AdapterObject->SpinLock); + InitializeListHead(&AdapterObject->AdapterQueue); + + AdapterObject->MapRegisters = (PVOID)(AdapterObject + 1); + RtlInitializeBitMap(AdapterObject->MapRegisters, + (PULONG)(AdapterObject->MapRegisters + 1), + SizeOfBitmap); + RtlSetAllBits(AdapterObject->MapRegisters); + AdapterObject->NumberOfMapRegisters = 0; + AdapterObject->CommittedMapRegisters = 0; + + AdapterObject->MapRegisterBase = ExAllocatePoolWithTag(NonPagedPool, + SizeOfBitmap * + sizeof(ROS_MAP_REGISTER_ENTRY), + TAG_DMA); + if (!AdapterObject->MapRegisterBase) + { + ObDereferenceObject(AdapterObject); + return NULL; + } + + RtlZeroMemory(AdapterObject->MapRegisterBase, + SizeOfBitmap * sizeof(ROS_MAP_REGISTER_ENTRY)); + if (!HalpGrowMapBuffers(AdapterObject, 0x10000)) + { + ObDereferenceObject(AdapterObject); + return NULL; + } + } + + return AdapterObject; +} +#endif + +/** + * @name HalpDmaInitializeEisaAdapter + * + * Setup DMA modes and extended modes for (E)ISA DMA adapter object. + */ +BOOLEAN +NTAPI +HalpDmaInitializeEisaAdapter(IN PADAPTER_OBJECT AdapterObject, + IN PDEVICE_DESCRIPTION DeviceDescription) +{ + UCHAR Controller; + DMA_MODE DmaMode = {{0 }}; + DMA_EXTENDED_MODE ExtendedMode = {{ 0 }}; + PVOID AdapterBaseVa; + + Controller = (DeviceDescription->DmaChannel & 4) ? 2 : 1; + + if (Controller == 1) + { + AdapterBaseVa = UlongToPtr(FIELD_OFFSET(EISA_CONTROL, DmaController1)); + } + else + { + AdapterBaseVa = UlongToPtr(FIELD_OFFSET(EISA_CONTROL, DmaController2)); + } + + AdapterObject->AdapterNumber = Controller; + AdapterObject->ChannelNumber = (UCHAR)(DeviceDescription->DmaChannel & 3); + AdapterObject->PagePort = (PUCHAR)HalpEisaPortPage[DeviceDescription->DmaChannel]; + AdapterObject->Width16Bits = FALSE; + AdapterObject->AdapterBaseVa = AdapterBaseVa; + + if (HalpEisaDma) + { + ExtendedMode.ChannelNumber = AdapterObject->ChannelNumber; + + switch (DeviceDescription->DmaSpeed) + { + case Compatible: ExtendedMode.TimingMode = COMPATIBLE_TIMING; break; + case TypeA: ExtendedMode.TimingMode = TYPE_A_TIMING; break; + case TypeB: ExtendedMode.TimingMode = TYPE_B_TIMING; break; + case TypeC: ExtendedMode.TimingMode = BURST_TIMING; break; + default: + return FALSE; + } + + switch (DeviceDescription->DmaWidth) + { + case Width8Bits: ExtendedMode.TransferSize = B_8BITS; break; + case Width16Bits: ExtendedMode.TransferSize = B_16BITS; break; + case Width32Bits: ExtendedMode.TransferSize = B_32BITS; break; + default: + return FALSE; + } + + if (Controller == 1) + { + WRITE_PORT_UCHAR(UlongToPtr(FIELD_OFFSET(EISA_CONTROL, DmaExtendedMode1)), + ExtendedMode.Byte); + } + else + { + WRITE_PORT_UCHAR(UlongToPtr(FIELD_OFFSET(EISA_CONTROL, DmaExtendedMode2)), + ExtendedMode.Byte); + } + } + else + { + /* + * Validate setup for non-busmaster DMA adapter. Secondary controller + * supports only 16-bit transfers and main controller supports only + * 8-bit transfers. Anything else is invalid. + */ + if (!DeviceDescription->Master) + { + if ((Controller == 2) && (DeviceDescription->DmaWidth == Width16Bits)) + { + AdapterObject->Width16Bits = TRUE; + } + else if ((Controller != 1) || (DeviceDescription->DmaWidth != Width8Bits)) + { + return FALSE; + } + } + } + + DmaMode.Channel = AdapterObject->ChannelNumber; + DmaMode.AutoInitialize = DeviceDescription->AutoInitialize; + + /* + * Set the DMA request mode. + * + * For (E)ISA bus master devices just unmask (enable) the DMA channel + * and set it to cascade mode. Otherwise just select the right one + * bases on the passed device description. + */ + if (DeviceDescription->Master) + { + DmaMode.RequestMode = CASCADE_REQUEST_MODE; + if (Controller == 1) + { + /* Set the Request Data */ + _PRAGMA_WARNING_SUPPRESS(__WARNING_DEREF_NULL_PTR) + WRITE_PORT_UCHAR(&((PDMA1_CONTROL)AdapterBaseVa)->Mode, DmaMode.Byte); + + /* Unmask DMA Channel */ + WRITE_PORT_UCHAR(&((PDMA1_CONTROL)AdapterBaseVa)->SingleMask, + AdapterObject->ChannelNumber | DMA_CLEARMASK); + } + else + { + /* Set the Request Data */ + WRITE_PORT_UCHAR(&((PDMA2_CONTROL)AdapterBaseVa)->Mode, DmaMode.Byte); + + /* Unmask DMA Channel */ + WRITE_PORT_UCHAR(&((PDMA2_CONTROL)AdapterBaseVa)->SingleMask, + AdapterObject->ChannelNumber | DMA_CLEARMASK); + } + } + else + { + if (DeviceDescription->DemandMode) + { + DmaMode.RequestMode = DEMAND_REQUEST_MODE; + } + else + { + DmaMode.RequestMode = SINGLE_REQUEST_MODE; + } + } + + AdapterObject->AdapterMode = DmaMode; + + return TRUE; +} + +#ifndef _MINIHAL_ +/** + * @name HalGetAdapter + * + * Allocate an adapter object for DMA device. + * + * @param DeviceDescription + * Structure describing the attributes of the device. + * @param NumberOfMapRegisters + * On return filled with the maximum number of map registers the + * device driver can allocate for DMA transfer operations. + * + * @return The DMA adapter on success, NULL otherwise. + * + * @implemented + */ +PADAPTER_OBJECT +NTAPI +HalGetAdapter(IN PDEVICE_DESCRIPTION DeviceDescription, + OUT PULONG NumberOfMapRegisters) +{ + PADAPTER_OBJECT AdapterObject = NULL; + BOOLEAN EisaAdapter; + ULONG MapRegisters; + ULONG MaximumLength; + KIRQL OldIrql; + + /* Validate parameters in device description */ + if (DeviceDescription->Version > DEVICE_DESCRIPTION_VERSION2) return NULL; + + /* + * See if we're going to use ISA/EISA DMA adapter. These adapters are + * special since they're reused. + * + * Also note that we check for channel number since there are only 8 DMA + * channels on ISA, so any request above this requires new adapter. + */ + if (((DeviceDescription->InterfaceType == Eisa) || + (DeviceDescription->InterfaceType == Isa)) || !(DeviceDescription->Master)) + { + if (((DeviceDescription->InterfaceType == Isa) || + (DeviceDescription->InterfaceType == Eisa)) && + (DeviceDescription->DmaChannel >= 8)) + { + EisaAdapter = FALSE; + } + else + { + EisaAdapter = TRUE; + } + } + else + { + EisaAdapter = FALSE; + } + + /* + * Disallow creating adapter for ISA/EISA DMA channel 4 since it's used + * for cascading the controllers and it's not available for software use. + */ + if ((EisaAdapter) && (DeviceDescription->DmaChannel == 4)) return NULL; + + /* + * for pci bus master devices that require scatter-gather, 32 bit addressing, we set automatically + */ + if ((DeviceDescription->InterfaceType == PCIBus) && (DeviceDescription->Master) && + (DeviceDescription->ScatterGather)) + { + DeviceDescription->Dma32BitAddresses = TRUE; + } + + /* + * Calculate the number of map registers. + * + * - For EISA and PCI scatter/gather no map registers are needed. + * - For ISA slave scatter/gather one map register is needed. + * - For all other cases the number of map registers depends on + * DeviceDescription->MaximumLength. + */ + MaximumLength = DeviceDescription->MaximumLength & MAXLONG; + if ((DeviceDescription->ScatterGather) && + ((DeviceDescription->InterfaceType == Eisa) || + (DeviceDescription->InterfaceType == PCIBus))) + { + MapRegisters = 0; + } + else if ((DeviceDescription->ScatterGather) && !(DeviceDescription->Master)) + { + MapRegisters = 1; + } + else + { + /* + * In the equation below the additional map register added by + * the "+1" accounts for the case when a transfer does not start + * at a page-aligned address. + */ + MapRegisters = BYTES_TO_PAGES(MaximumLength) + 1; + if (MapRegisters > 16) MapRegisters = 16; + + if (!HalpEisaDma) + { + if (MapRegisters > ((HalpMasterAdapter.InitialMapRegistersBufferLength / PAGE_SIZE) / 2)) + { + MapRegisters = (HalpMasterAdapter.InitialMapRegistersBufferLength / PAGE_SIZE) / 2; + } + } + } + + /* + * Acquire the DMA lock that is used to protect the EISA adapter array. + */ + KeWaitForSingleObject(&HalpDmaLock, Executive, KernelMode, FALSE, NULL); + + /* + * Now we must get ahold of the adapter object. For first eight ISA/EISA + * channels there are static adapter objects that are reused and updated + * on succesive HalGetAdapter calls. In other cases a new adapter object + * is always created and it's to the DMA adapter list (HalpDmaAdapterList). + */ + if (EisaAdapter) + { + AdapterObject = HalpEisaAdapter[DeviceDescription->DmaChannel]; + if (AdapterObject) + { + if ((AdapterObject->NeedsMapRegisters) && + (MapRegisters > AdapterObject->MapRegistersPerChannel)) + { + AdapterObject->MapRegistersPerChannel = MapRegisters; + } + } + } + + if (AdapterObject == NULL) + { + AdapterObject = HalpAllocateAdapter(MapRegisters, DeviceDescription, FALSE); + if (AdapterObject == NULL) + { + KeSetEvent(&HalpDmaLock, 0, 0); + return NULL; + } + + if (EisaAdapter) + { + HalpEisaAdapter[DeviceDescription->DmaChannel] = AdapterObject; + } + + if (MapRegisters > 0) + { + AdapterObject->NeedsMapRegisters = TRUE; + AdapterObject->MapRegistersPerChannel = MapRegisters; + + if (DeviceDescription->Master) + { + HalpMasterAdapter.AdapterObject->CommittedMapRegisters += (MapRegisters * 2); + } + else + { + HalpMasterAdapter.AdapterObject->CommittedMapRegisters += MapRegisters; + } + + if (HalpMasterAdapter.AdapterObject->CommittedMapRegisters > + HalpMasterAdapter.AdapterObject->NumberOfMapRegisters) + { + HalpGrowMapBuffers(HalpMasterAdapter.AdapterObject, 0x10000); + } + } + else + { + AdapterObject->NeedsMapRegisters = FALSE; + if (DeviceDescription->Master) + { + AdapterObject->MapRegistersPerChannel = BYTES_TO_PAGES(MaximumLength) + 1; + } + else + { + AdapterObject->MapRegistersPerChannel = 1; + } + } + } + + /* + * Release the DMA lock. HalpEisaAdapter will no longer be touched, + * so we don't need it. + */ + KeSetEvent(&HalpDmaLock, 0, 0); + + if (!EisaAdapter) + { + /* If it's not one of the static adapters, add it to the list */ + KeAcquireSpinLock(&HalpDmaAdapterListLock, &OldIrql); + InsertTailList(&HalpDmaAdapterList, &AdapterObject->AdapterList); + KeReleaseSpinLock(&HalpDmaAdapterListLock, OldIrql); + } + + /* + * Setup the values in the adapter object that are common for all + * types of buses. + */ + if (DeviceDescription->Version >= DEVICE_DESCRIPTION_VERSION1) + { + AdapterObject->IgnoreCount = DeviceDescription->IgnoreCount; + } + else + { + AdapterObject->IgnoreCount = 0; + } + + AdapterObject->Dma32BitAddresses = DeviceDescription->Dma32BitAddresses; + AdapterObject->Dma64BitAddresses = DeviceDescription->Dma64BitAddresses; + AdapterObject->ScatterGather = DeviceDescription->ScatterGather; + AdapterObject->MasterDevice = DeviceDescription->Master; + *NumberOfMapRegisters = AdapterObject->MapRegistersPerChannel; + + /* + * For non-(E)ISA adapters we have already done all the work. On the + * other hand for (E)ISA adapters we must still setup the DMA modes + * and prepare the controller. + */ + if (EisaAdapter) + { + if (!HalpDmaInitializeEisaAdapter(AdapterObject, DeviceDescription)) + { + ObDereferenceObject(AdapterObject); + return NULL; + } + } + + return AdapterObject; +} + +/** + * @name HalpGetDmaAdapter + * + * Internal routine to allocate PnP DMA adapter object. It's exported through + * HalDispatchTable and used by IoGetDmaAdapter. + * + * @see HalGetAdapter + */ +PDMA_ADAPTER +NTAPI +HalpGetDmaAdapter(IN PVOID Context, + IN PDEVICE_DESCRIPTION DeviceDescription, + OUT PULONG NumberOfMapRegisters) +{ + return &HalGetAdapter(DeviceDescription, NumberOfMapRegisters)->DmaHeader; +} + +/** + * @name HalPutDmaAdapter + * + * Internal routine to free DMA adapter and resources for reuse. It's exported + * using the DMA_OPERATIONS interface by HalGetAdapter. + * + * @see HalGetAdapter + */ +VOID +NTAPI +HalPutDmaAdapter(IN PADAPTER_OBJECT AdapterObject) +{ + KIRQL OldIrql; + if (AdapterObject->ChannelNumber == 0xFF) + { + KeAcquireSpinLock(&HalpDmaAdapterListLock, &OldIrql); + RemoveEntryList(&AdapterObject->AdapterList); + KeReleaseSpinLock(&HalpDmaAdapterListLock, OldIrql); + } + + ObDereferenceObject(AdapterObject); +} + +/** + * @name HalAllocateCommonBuffer + * + * Allocates memory that is visible to both the processor(s) and the DMA + * device. + * + * @param AdapterObject + * Adapter object representing the bus master or system dma controller. + * @param Length + * Number of bytes to allocate. + * @param LogicalAddress + * Logical address the driver can use to access the buffer. + * @param CacheEnabled + * Specifies if the memory can be cached. + * + * @return The base virtual address of the memory allocated or NULL on failure. + * + * @remarks + * On real NT x86 systems the CacheEnabled parameter is ignored, we honour + * it. If it proves to cause problems change it. + * + * @see HalFreeCommonBuffer + * + * @implemented + */ +PVOID +NTAPI +HalAllocateCommonBuffer(IN PADAPTER_OBJECT AdapterObject, + IN ULONG Length, + IN PPHYSICAL_ADDRESS LogicalAddress, + IN BOOLEAN CacheEnabled) +{ + PHYSICAL_ADDRESS LowestAcceptableAddress; + PHYSICAL_ADDRESS HighestAcceptableAddress; + PHYSICAL_ADDRESS BoundryAddressMultiple; + PVOID VirtualAddress; + + LowestAcceptableAddress.QuadPart = 0; + HighestAcceptableAddress = HalpGetAdapterMaximumPhysicalAddress(AdapterObject); + BoundryAddressMultiple.QuadPart = 0; + + /* + * For bus-master DMA devices the buffer mustn't cross 4Gb boundary. For + * slave DMA devices the 64Kb boundary mustn't be crossed since the + * controller wouldn't be able to handle it. + */ + if (AdapterObject->MasterDevice || HalpBusType == MACHINE_TYPE_EISA) + { + BoundryAddressMultiple.HighPart = 1; + } + else + { + BoundryAddressMultiple.LowPart = 0x10000; + } + + VirtualAddress = MmAllocateContiguousMemorySpecifyCache(Length, + LowestAcceptableAddress, + HighestAcceptableAddress, + BoundryAddressMultiple, + CacheEnabled ? MmCached : + MmNonCached); + if (VirtualAddress == NULL) return NULL; + + *LogicalAddress = MmGetPhysicalAddress(VirtualAddress); + + return VirtualAddress; +} + +/** + * @name HalFreeCommonBuffer + * + * Free common buffer allocated with HalAllocateCommonBuffer. + * + * @see HalAllocateCommonBuffer + * + * @implemented + */ +VOID +NTAPI +HalFreeCommonBuffer(IN PADAPTER_OBJECT AdapterObject, + IN ULONG Length, + IN PHYSICAL_ADDRESS LogicalAddress, + IN PVOID VirtualAddress, + IN BOOLEAN CacheEnabled) +{ + MmFreeContiguousMemorySpecifyCache(VirtualAddress, + Length, + CacheEnabled ? MmCached : MmNonCached); +} + +typedef struct _SCATTER_GATHER_CONTEXT { + BOOLEAN UsingUserBuffer; + PMDL Mdl; + PMDL DerivedMdl; + PVOID MapRegisterBase; + PUCHAR CurrentVa; + ULONG Length; + ULONG MapRegisterCount; + ULONG Reserved; + union + { + struct + { + WAIT_CONTEXT_BLOCK Wcb; + PDRIVER_LIST_CONTROL AdapterListControlRoutine; + PVOID AdapterListControlContext; + ULONG Reserved2; + PADAPTER_OBJECT AdapterObject; + BOOLEAN WriteToDevice; + ULONG Reserved3; + }; + SCATTER_GATHER_LIST ScatterGatherList; + }; +} SCATTER_GATHER_CONTEXT, *PSCATTER_GATHER_CONTEXT; + +/* + * Called for the non bus-master dma adapter only + */ +IO_ALLOCATION_ACTION +NTAPI +HalpScatterGatherAdapterControl(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID MapRegisterBase, + IN PVOID Context) +{ + PSCATTER_GATHER_CONTEXT AdapterControlContext = Context; + PADAPTER_OBJECT AdapterObject; + PSCATTER_GATHER_LIST ScatterGatherList; + + PSCATTER_GATHER_ELEMENT Element; + ULONG RemainingLength; + PUCHAR CurrentVa; + BOOLEAN WriteToDevice; + PDRIVER_LIST_CONTROL AdapterListControlRoutine; + PVOID AdapterListControlContext; + PMDL Mdl; + LONG ByteCount; + + /* Store the map register base for later in HalPutScatterGatherList */ + AdapterControlContext->MapRegisterBase = MapRegisterBase; + + AdapterListControlRoutine = AdapterControlContext->AdapterListControlRoutine; + AdapterListControlContext = AdapterControlContext->AdapterListControlContext; + AdapterObject = AdapterControlContext->AdapterObject; + WriteToDevice = AdapterControlContext->WriteToDevice; + + ScatterGatherList = &AdapterControlContext->ScatterGatherList; + ScatterGatherList->Reserved = (ULONG_PTR)AdapterControlContext; + CurrentVa = AdapterControlContext->CurrentVa; + Mdl = AdapterControlContext->Mdl; + RemainingLength = AdapterControlContext->Length; + + ByteCount = (PUCHAR)MmGetMdlVirtualAddress(Mdl) + Mdl->ByteCount - CurrentVa; + Element = ScatterGatherList->Elements; + + while (RemainingLength) + { + if (ByteCount > RemainingLength) + ByteCount = RemainingLength; + RemainingLength -= ByteCount; + + while (ByteCount > 0) + { + Element->Length = ByteCount; + Element->Reserved = 0; + Element->Address = IoMapTransfer(AdapterObject, + Mdl, + MapRegisterBase, + CurrentVa, + &Element->Length, + WriteToDevice); + + DPRINT("Allocated one S/G element: 0x%I64u with length: 0x%x\n", + Element->Address.QuadPart, + Element->Length); + + ASSERT(Element->Length <= ByteCount); + + CurrentVa += Element->Length; + ByteCount -= Element->Length; + ++Element; + } + + Mdl = Mdl->Next; + if (!Mdl) + { + /* add the remaining length at the last element */ + Element[-1].Length += RemainingLength; + break; + } + CurrentVa = (PUCHAR)MmGetMdlVirtualAddress(Mdl);; + ByteCount = Mdl->ByteCount; + } + + ScatterGatherList->NumberOfElements = Element - ScatterGatherList->Elements; + + DPRINT("Initiating S/G DMA with %d element(s)\n", ScatterGatherList->NumberOfElements); + + AdapterListControlRoutine(DeviceObject, + Irp, + ScatterGatherList, + AdapterListControlContext); + + return DeallocateObjectKeepRegisters; +} + +/** + * @name HalGetScatterGatherList + * + * Creates a scatter-gather list to be using in scatter/gather DMA + * + * @param AdapterObject + * Adapter object representing the bus master or system dma controller. + * @param DeviceObject + * The device target for DMA. + * @param Mdl + * The MDL that describes the buffer to be mapped. + * @param CurrentVa + * The current VA in the buffer to be mapped for transfer. + * @param Length + * Specifies the length of data in bytes to be mapped. + * @param ExecutionRoutine + * A caller supplied AdapterListControl routine to be called when DMA is available. + * @param Context + * Context passed to the AdapterListControl routine. + * @param WriteToDevice + * Indicates direction of DMA operation. + * + * @return The status of the operation. + * + * @see HalBuildScatterGatherList + * + * @implemented + */ + NTSTATUS + NTAPI + HalGetScatterGatherList(IN PADAPTER_OBJECT AdapterObject, + IN PDEVICE_OBJECT DeviceObject, + IN PMDL Mdl, + IN PVOID CurrentVa, + IN ULONG Length, + IN PDRIVER_LIST_CONTROL ExecutionRoutine, + IN PVOID Context, + IN BOOLEAN WriteToDevice) +{ + return HalBuildScatterGatherList(AdapterObject, + DeviceObject, + Mdl, + CurrentVa, + Length, + ExecutionRoutine, + Context, + WriteToDevice, + NULL, + 0); +} + +/** + * @name HalPutScatterGatherList + * + * Frees a scatter-gather list allocated from HalBuildScatterGatherList + * + * @param AdapterObject + * Adapter object representing the bus master or system dma controller. + * @param ScatterGather + * The scatter/gather list to be freed. + * @param WriteToDevice + * Indicates direction of DMA operation. + * + * @return None + * + * @see HalBuildScatterGatherList + * + * @implemented + */ + VOID + NTAPI + HalPutScatterGatherList(IN PADAPTER_OBJECT AdapterObject, + IN PSCATTER_GATHER_LIST ScatterGather, + IN BOOLEAN WriteToDevice) +{ + PSCATTER_GATHER_CONTEXT AdapterControlContext; + ULONG ByteCount; + PMDL Mdl; + PUCHAR CurrentVa; + ULONG RemainingLength; + PROS_MAP_REGISTER_ENTRY MapRegisterBase; + + InterlockedDecrement(&HalpOutstandingScatterGatherCount); + + /* + * The field 'SCATTER_GATHER_LIST::Reserved' can be in three States: + * - (== 0) - for bus-master scatter-gather, which allocated from our buffer + * - (== 1) - for bus-master scatter-gather, which allocated from user buffer + * - (== AdapterControlContext) - for slave scatter-gather. + */ + if (ScatterGather->Reserved == 0) + { + /* Our buffer */ + ExFreePoolWithTag(ScatterGather, TAG_DMA); + return; + } + else if (ScatterGather->Reserved == 1) + { + /* User allocated buffer- simply return */ + return; + } + + /* for the slave dma, we are flush the map buffers and free map registers */ + + AdapterControlContext = (PSCATTER_GATHER_CONTEXT)ScatterGather->Reserved; + Mdl = AdapterControlContext->Mdl; + CurrentVa = AdapterControlContext->CurrentVa; + RemainingLength = AdapterControlContext->Length; + MapRegisterBase = (PROS_MAP_REGISTER_ENTRY)AdapterControlContext->MapRegisterBase; + + ByteCount = (ULONG_PTR)MmGetMdlVirtualAddress(Mdl) + Mdl->ByteCount - (ULONG_PTR)CurrentVa; + + while (RemainingLength) + { + if (ByteCount) + { + if (ByteCount > RemainingLength) + ByteCount = RemainingLength; + RemainingLength -= ByteCount; + + IoFlushAdapterBuffers(AdapterObject, + Mdl, + (PVOID)MapRegisterBase, + (PVOID)CurrentVa, + ByteCount, + WriteToDevice); + + MapRegisterBase += ADDRESS_AND_SIZE_TO_SPAN_PAGES(CurrentVa, ByteCount); + } + + Mdl = Mdl->Next; + if (!Mdl) + break; + CurrentVa = MmGetMdlVirtualAddress(Mdl); + ByteCount = Mdl->ByteCount; + } + + IoFreeMapRegisters(AdapterObject, + AdapterControlContext->MapRegisterBase, + AdapterControlContext->MapRegisterCount); + + /* if you have a built mdl, then free it */ + Mdl = AdapterControlContext->DerivedMdl; + + while (Mdl) + { + if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) + MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl); + IoFreeMdl(Mdl); + + Mdl = Mdl->Next; + } + + ExFreePoolWithTag(ScatterGather, TAG_DMA); + + /* If this is our buffer, release it */ + if (!AdapterControlContext->UsingUserBuffer) + ExFreePoolWithTag(AdapterControlContext, TAG_DMA); + + DPRINT("S/G DMA has finished!\n"); +} + +/* + * @Implemented + */ +NTSTATUS +NTAPI +HalCalculateScatterGatherListSize(IN PADAPTER_OBJECT AdapterObject, + IN PMDL Mdl OPTIONAL, + IN PVOID CurrentVa, + IN ULONG Length, + OUT PULONG ScatterGatherListSize, + OUT OPTIONAL PULONG pNumberOfMapRegisters) +{ + ULONG TotalBytes, ByteCount, ByteOffset; + ULONG NumberOfMapRegisters = 0; + ULONG SgSize; + + if (Mdl) + { + ByteCount = (ULONG_PTR)MmGetMdlVirtualAddress(Mdl) + Mdl->ByteCount - (ULONG_PTR)CurrentVa; + ByteOffset = BYTE_OFFSET(CurrentVa); + TotalBytes = ByteCount; + + while (TotalBytes < Length) + { + Mdl = Mdl->Next; + if (Mdl == NULL) break; + + NumberOfMapRegisters += BYTES_TO_PAGES(ByteOffset + ByteCount); + ByteCount = Mdl->ByteCount; + ByteOffset = Mdl->ByteOffset; + + TotalBytes += ByteCount; + } + + if (TotalBytes + PAGE_SIZE < ByteOffset + Length) + return STATUS_BUFFER_TOO_SMALL; + + NumberOfMapRegisters += BYTES_TO_PAGES(ByteOffset + ByteCount - (TotalBytes - Length)); + + if (NumberOfMapRegisters > AdapterObject->MapRegistersPerChannel) + return STATUS_INSUFFICIENT_RESOURCES; + } + else + { + NumberOfMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES(CurrentVa, Length); + } + + SgSize = NumberOfMapRegisters * sizeof(SCATTER_GATHER_ELEMENT) + FIELD_OFFSET(SCATTER_GATHER_LIST, Elements); + + if (AdapterObject->NeedsMapRegisters) + { + /* + * for the slave dma, SCATTER_GATHER_LIST within the SCATTER_GATHER_CONTEXT + */ + SgSize += FIELD_OFFSET(SCATTER_GATHER_CONTEXT, ScatterGatherList); + + if (SgSize < sizeof(SCATTER_GATHER_CONTEXT)) + SgSize = sizeof(SCATTER_GATHER_CONTEXT); + } + + *ScatterGatherListSize = SgSize; + if (pNumberOfMapRegisters) *pNumberOfMapRegisters = NumberOfMapRegisters; + + return STATUS_SUCCESS; +} + +/** + * @name HalBuildScatterGatherList + * + * Creates a scatter-gather list to be using in scatter/gather DMA + * + * @param AdapterObject + * Adapter object representing the bus master or system dma controller. + * @param DeviceObject + * The device target for DMA. + * @param Mdl + * The MDL that describes the buffer to be mapped. + * @param CurrentVa + * The current VA in the buffer to be mapped for transfer. + * @param Length + * Specifies the length of data in bytes to be mapped. + * @param ExecutionRoutine + * A caller supplied AdapterListControl routine to be called when DMA is available. + * @param Context + * Context passed to the AdapterListControl routine. + * @param WriteToDevice + * Indicates direction of DMA operation. + * + * @param ScatterGatherBuffer + * User buffer for the scatter-gather list + * + * @param ScatterGatherBufferLength + * Buffer length + * + * @return The status of the operation. + * + * @see HalPutScatterGatherList + * + * @implemented + */ +NTSTATUS +NTAPI +HalBuildScatterGatherList( + IN PADAPTER_OBJECT AdapterObject, + IN PDEVICE_OBJECT DeviceObject, + IN PMDL Mdl, + IN PVOID CurrentVa, + IN ULONG Length, + IN PDRIVER_LIST_CONTROL ExecutionRoutine, + IN PVOID Context, + IN BOOLEAN WriteToDevice, + IN PVOID ScatterGatherBuffer, + IN ULONG ScatterGatherBufferLength) +{ + NTSTATUS Status; + ULONG SgSize, NumberOfMapRegisters, ByteCount, ByteOffset; + PPFN_NUMBER MdlPages; + PSCATTER_GATHER_ELEMENT Element; + PSCATTER_GATHER_LIST ScatterGatherList; + PSCATTER_GATHER_CONTEXT ScatterGatherContext; + BOOLEAN UsingUserBuffer; + + if (!Mdl) return STATUS_INVALID_PARAMETER; + + Status = HalCalculateScatterGatherListSize(AdapterObject, + Mdl, + CurrentVa, + Length, + &SgSize, + &NumberOfMapRegisters); + if (!NT_SUCCESS(Status)) return Status; + + InterlockedIncrement(&HalpOutstandingScatterGatherCount); + + if (ScatterGatherBuffer) + { + /* Checking if user buffer is enough */ + if (ScatterGatherBufferLength < SgSize) + { + InterlockedDecrement(&HalpOutstandingScatterGatherCount); + return STATUS_BUFFER_TOO_SMALL; + } + UsingUserBuffer = TRUE; + } + else + { + ScatterGatherBuffer = ExAllocatePoolWithTag(NonPagedPool, SgSize, TAG_DMA); + if (!ScatterGatherBuffer) + { + InterlockedDecrement(&HalpOutstandingScatterGatherCount); + return STATUS_INSUFFICIENT_RESOURCES; + } + UsingUserBuffer = FALSE; + } + + if (!AdapterObject->NeedsMapRegisters) + { + /* + * this is bus-master adapter + */ + + ScatterGatherList = (PSCATTER_GATHER_LIST)ScatterGatherBuffer; + ScatterGatherList->Reserved = UsingUserBuffer; + Element = ScatterGatherList->Elements; + + ByteCount = (PUCHAR)MmGetMdlVirtualAddress(Mdl) + Mdl->ByteCount - (PUCHAR)CurrentVa; + MdlPages = MmGetMdlPfnArray(Mdl); + MdlPages += ((ULONG_PTR)CurrentVa - (ULONG_PTR)PAGE_ROUND_DOWN(MmGetMdlVirtualAddress(Mdl))) >> PAGE_SHIFT; + ByteOffset = BYTE_OFFSET(CurrentVa); + + while (Length) + { + if (ByteCount > Length) + ByteCount = Length; + Length -= ByteCount; + + while (ByteCount) + { + Element->Address.QuadPart = ((ULONGLONG)*MdlPages << PAGE_SHIFT) + ByteOffset; + Element->Length = PAGE_SIZE - ByteOffset; + if (Element->Length > ByteCount) + Element->Length = ByteCount; + ByteCount -= Element->Length; + + /* + * if this element is comtiguously with previous element, + * we are concatenate them. + */ + if (Element != ScatterGatherList->Elements) + { + if (Element[-1].Address.QuadPart + Element[-1].Length == + Element->Address.QuadPart) + { + Element[-1].Length += Element->Length; + --Element; + } + } + + ByteOffset = 0; + ++Element; + ++MdlPages; + } + + Mdl = Mdl->Next; + if (!Mdl) break; + + ByteCount = Mdl->ByteCount; + ByteOffset = Mdl->ByteOffset; + MdlPages = MmGetMdlPfnArray(Mdl); + } + + /* Add a remaining length to the last element */ + if (Length) Element[-1].Length += Length; + + ScatterGatherList->NumberOfElements = Element - ScatterGatherList->Elements; + + ExecutionRoutine(DeviceObject, + DeviceObject->CurrentIrp, + ScatterGatherList, + Context); + } + else + { + ScatterGatherContext = (PSCATTER_GATHER_CONTEXT)ScatterGatherBuffer; + + /* Fill the scatter-gather context */ + ScatterGatherContext->UsingUserBuffer = UsingUserBuffer; + ScatterGatherContext->AdapterObject = AdapterObject; + ScatterGatherContext->Mdl = Mdl; + ScatterGatherContext->DerivedMdl = NULL; + ScatterGatherContext->CurrentVa = CurrentVa; + ScatterGatherContext->Length = Length; + ScatterGatherContext->MapRegisterCount = NumberOfMapRegisters; + ScatterGatherContext->AdapterListControlRoutine = ExecutionRoutine; + ScatterGatherContext->AdapterListControlContext = Context; + ScatterGatherContext->WriteToDevice = WriteToDevice; + + ScatterGatherContext->Wcb.DeviceObject = DeviceObject; + ScatterGatherContext->Wcb.DeviceContext = (PVOID)ScatterGatherContext; + ScatterGatherContext->Wcb.CurrentIrp = DeviceObject->CurrentIrp; + + Status = HalAllocateAdapterChannel(AdapterObject, + &ScatterGatherContext->Wcb, + NumberOfMapRegisters, + HalpScatterGatherAdapterControl); + + if (!NT_SUCCESS(Status)) + { + InterlockedDecrement(&HalpOutstandingScatterGatherCount); + if (!UsingUserBuffer) + ExFreePoolWithTag(ScatterGatherBuffer, TAG_DMA); + return Status; + } + } + + return STATUS_SUCCESS; +} + +/* + * @Implemented + */ +NTSTATUS +NTAPI +HalBuildMdlFromScatterGatherList(IN PADAPTER_OBJECT AdapterObject, + IN PSCATTER_GATHER_LIST ScatterGather, + IN PMDL OriginalMdl, + OUT PMDL *TargetMdl) +{ + PSCATTER_GATHER_CONTEXT AdapterControlContext = (PSCATTER_GATHER_CONTEXT)ScatterGather->Reserved; + PMDL Mdl; + PMDL NewMdl = NULL, PrevMdl = NULL; + PUCHAR MdlVa; + PPFN_NUMBER MdlPages; + PSCATTER_GATHER_ELEMENT Element; + ULONG i; + ULONG_PTR BRound, ERound; + ULONG ByteCount, PageCount; + PFN_NUMBER PfnNumber; + BOOLEAN FirstPass; + + if (!OriginalMdl) + return STATUS_INVALID_PARAMETER; + + if (!AdapterObject->NeedsMapRegisters) + { + /* + * for the bus-master scatter-gather, we are return a same Mdl + */ + *TargetMdl = OriginalMdl; + return STATUS_SUCCESS; + } + + if (AdapterControlContext && AdapterControlContext->DerivedMdl) + return STATUS_NONE_MAPPED; + + ERound = 0; + MdlVa = 0; + ByteCount = 0; + FirstPass = TRUE; + Element = ScatterGather->Elements; + + /* Allocate a new chain of mdls */ + for (i = 0; i < ScatterGather->NumberOfElements; i++, Element++) + { + BRound = BYTE_OFFSET(Element->Address.LowPart); + if (!FirstPass && (BRound || ERound)) + { + Mdl = IoAllocateMdl(MdlVa, ByteCount, FALSE, FALSE, NULL); + if (!Mdl) goto AllocFail; + + Mdl->MdlFlags |= (MDL_PAGES_LOCKED | MDL_IO_SPACE | MDL_MAPPING_CAN_FAIL); + + if (NewMdl) + { + PrevMdl->Next = Mdl; + } + else + { + NewMdl = Mdl; + } + PrevMdl = Mdl; + + ByteCount = 0; + } + FirstPass = FALSE; + + if (ByteCount == 0) + MdlVa = (PUCHAR)BRound; + ByteCount += Element->Length; + ERound = BYTE_OFFSET(Element->Address.LowPart + Element->Length); + } + + if (ByteCount != 0) + { + Mdl = IoAllocateMdl(MdlVa, ByteCount, FALSE, FALSE, NULL); + if (!Mdl) goto AllocFail; + + Mdl->MdlFlags |= (MDL_PAGES_LOCKED | MDL_IO_SPACE | MDL_MAPPING_CAN_FAIL); + + if (NewMdl) + { + PrevMdl->Next = Mdl; + } + else + { + NewMdl = Mdl; + } + } + + Mdl = NewMdl; + Element = ScatterGather->Elements; + MdlPages = MmGetMdlPfnArray(Mdl); + FirstPass = TRUE; + ERound = 0; + + /* fill the new mdls */ + for (i = 0; i < ScatterGather->NumberOfElements; i++, Element++) + { + BRound = BYTE_OFFSET(Element->Address.LowPart); + + if (!FirstPass && (BRound || ERound)) + { + Mdl = Mdl->Next; + MdlPages = MmGetMdlPfnArray(Mdl); + } + + PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(Element->Address.LowPart, Element->Length); + PfnNumber = (PFN_NUMBER)(Element->Address.QuadPart >> PAGE_SHIFT); + + while (PageCount--) + { + *MdlPages++ = PfnNumber++; + } + + ERound = BYTE_OFFSET(Element->Address.LowPart + Element->Length); + FirstPass = FALSE; + } + + *TargetMdl = NewMdl; + if (AdapterControlContext) + AdapterControlContext->DerivedMdl = NewMdl; + + return STATUS_SUCCESS; + +AllocFail: + while ((Mdl = NewMdl)) + { + NewMdl = Mdl->Next; + IoFreeMdl(Mdl); + } + return STATUS_INSUFFICIENT_RESOURCES; +} +#endif /* _MINIHAL_ */ + +/** + * @name HalpDmaGetDmaAlignment + * + * Internal routine to return the DMA alignment requirement. It's exported + * using the DMA_OPERATIONS interface by HalGetAdapter. + * + * @see HalGetAdapter + */ +ULONG +NTAPI +HalpDmaGetDmaAlignment(IN PADAPTER_OBJECT AdapterObject) +{ + return 1; +} + +/* + * @name HalReadDmaCounter + * + * Read DMA operation progress counter. + * + * @implemented + */ +ULONG +NTAPI +HalReadDmaCounter(IN PADAPTER_OBJECT AdapterObject) +{ + KIRQL OldIrql; + ULONG Count, OldCount; + + ASSERT(!AdapterObject->MasterDevice); + + /* + * Acquire the master adapter lock since we're going to mess with the + * system DMA controller registers and we really don't want anyone + * to do the same at the same time. + */ + KeAcquireSpinLock(&AdapterObject->MasterAdapter->SpinLock, &OldIrql); + + /* Send the request to the specific controller. */ + if (AdapterObject->AdapterNumber == 1) + { + PDMA1_CONTROL DmaControl1 = AdapterObject->AdapterBaseVa; + + Count = 0xffff00; + do + { + OldCount = Count; + + /* Send Reset */ + WRITE_PORT_UCHAR(&DmaControl1->ClearBytePointer, 0); + + /* Read Count */ + Count = READ_PORT_UCHAR(&DmaControl1->DmaAddressCount + [AdapterObject->ChannelNumber].DmaBaseCount); + Count |= READ_PORT_UCHAR(&DmaControl1->DmaAddressCount + [AdapterObject->ChannelNumber].DmaBaseCount) << 8; + } while (0xffff00 & (OldCount ^ Count)); + } + else + { + PDMA2_CONTROL DmaControl2 = AdapterObject->AdapterBaseVa; + + Count = 0xffff00; + do + { + OldCount = Count; + + /* Send Reset */ + WRITE_PORT_UCHAR(&DmaControl2->ClearBytePointer, 0); + + /* Read Count */ + Count = READ_PORT_UCHAR(&DmaControl2->DmaAddressCount + [AdapterObject->ChannelNumber].DmaBaseCount); + Count |= READ_PORT_UCHAR(&DmaControl2->DmaAddressCount + [AdapterObject->ChannelNumber].DmaBaseCount) << 8; + } while (0xffff00 & (OldCount ^ Count)); + } + + KeReleaseSpinLock(&AdapterObject->MasterAdapter->SpinLock, OldIrql); + + Count++; + Count &= 0xffff; + if (AdapterObject->Width16Bits) Count *= 2; + + return Count; +} + +#ifndef _MINIHAL_ +/** + * @name HalpGrowMapBufferWorker + * + * Helper routine of HalAllocateAdapterChannel for allocating map registers + * at PASSIVE_LEVEL in work item. + */ +VOID +NTAPI +HalpGrowMapBufferWorker(IN PVOID DeferredContext) +{ + PGROW_WORK_ITEM WorkItem = (PGROW_WORK_ITEM)DeferredContext; + KIRQL OldIrql; + BOOLEAN Succeeded; + + /* + * Try to allocate new map registers for the adapter. + * + * NOTE: The NT implementation actually tries to allocate more map + * registers than needed as an optimization. + */ + KeWaitForSingleObject(&HalpDmaLock, Executive, KernelMode, FALSE, NULL); + Succeeded = HalpGrowMapBuffers(WorkItem->AdapterObject->MasterAdapter, + WorkItem->NumberOfMapRegisters << PAGE_SHIFT); + KeSetEvent(&HalpDmaLock, 0, 0); + + if (Succeeded) + { + /* + * Flush the adapter queue now that new map registers are ready. The + * easiest way to do that is to call IoFreeMapRegisters to not free + * any registers. Note that we use the magic (PVOID)2 map register + * base to bypass the parameter checking. + */ + OldIrql = KfRaiseIrql(DISPATCH_LEVEL); + IoFreeMapRegisters(WorkItem->AdapterObject, (PVOID)2, 0); + KfLowerIrql(OldIrql); + } + + ExFreePool(WorkItem); +} + +/** + * @name HalAllocateAdapterChannel + * + * Setup map registers for an adapter object. + * + * @param AdapterObject + * Pointer to an ADAPTER_OBJECT to set up. + * @param WaitContextBlock + * Context block to be used with ExecutionRoutine. + * @param NumberOfMapRegisters + * Number of map registers requested. + * @param ExecutionRoutine + * Callback to call when map registers are allocated. + * + * @return + * If not enough map registers can be allocated then + * STATUS_INSUFFICIENT_RESOURCES is returned. If the function + * succeeds or the callback is queued for later delivering then + * STATUS_SUCCESS is returned. + * + * @see IoFreeAdapterChannel + * + * @implemented + */ +NTSTATUS +NTAPI +HalAllocateAdapterChannel(IN PADAPTER_OBJECT AdapterObject, + IN PWAIT_CONTEXT_BLOCK WaitContextBlock, + IN ULONG NumberOfMapRegisters, + IN PDRIVER_CONTROL ExecutionRoutine) +{ + PADAPTER_OBJECT MasterAdapter; + PGROW_WORK_ITEM WorkItem; + ULONG Index = MAXULONG; + ULONG Result; + KIRQL OldIrql; + + ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); + + /* Set up the wait context block in case we can't run right away. */ + WaitContextBlock->DeviceRoutine = ExecutionRoutine; + WaitContextBlock->NumberOfMapRegisters = NumberOfMapRegisters; + + /* Returns true if queued, else returns false and sets the queue to busy */ + if (KeInsertDeviceQueue(&AdapterObject->ChannelWaitQueue, + &WaitContextBlock->WaitQueueEntry)) + { + return STATUS_SUCCESS; + } + + MasterAdapter = AdapterObject->MasterAdapter; + + AdapterObject->NumberOfMapRegisters = NumberOfMapRegisters; + AdapterObject->CurrentWcb = WaitContextBlock; + + if ((NumberOfMapRegisters) && (AdapterObject->NeedsMapRegisters)) + { + if (NumberOfMapRegisters > AdapterObject->MapRegistersPerChannel) + { + AdapterObject->NumberOfMapRegisters = 0; + IoFreeAdapterChannel(AdapterObject); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* + * Get the map registers. This is partly complicated by the fact + * that new map registers can only be allocated at PASSIVE_LEVEL + * and we're currently at DISPATCH_LEVEL. The following code has + * two code paths: + * + * - If there is no adapter queued for map register allocation, + * try to see if enough contiguous map registers are present. + * In case they're we can just get them and proceed further. + * + * - If some adapter is already present in the queue we must + * respect the order of adapters asking for map registers and + * so the fast case described above can't take place. + * This case is also entered if not enough coniguous map + * registers are present. + * + * A work queue item is allocated and queued, the adapter is + * also queued into the master adapter queue. The worker + * routine does the job of allocating the map registers at + * PASSIVE_LEVEL and calling the ExecutionRoutine. + */ + + KeAcquireSpinLock(&MasterAdapter->SpinLock, &OldIrql); + + if (IsListEmpty(&MasterAdapter->AdapterQueue)) + { + Index = RtlFindClearBitsAndSet(MasterAdapter->MapRegisters, NumberOfMapRegisters, 0); + if (Index != MAXULONG) + { + AdapterObject->MapRegisterBase = MasterAdapter->MapRegisterBase + Index; + if (!AdapterObject->ScatterGather) + { + AdapterObject->MapRegisterBase = (PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)AdapterObject->MapRegisterBase | MAP_BASE_SW_SG); + } + } + } + + if (Index == MAXULONG) + { + InsertTailList(&MasterAdapter->AdapterQueue, &AdapterObject->AdapterQueue); + + WorkItem = ExAllocatePoolWithTag(NonPagedPool, + sizeof(GROW_WORK_ITEM), + TAG_DMA); + if (WorkItem) + { + ExInitializeWorkItem(&WorkItem->WorkQueueItem, HalpGrowMapBufferWorker, WorkItem); + WorkItem->AdapterObject = AdapterObject; + WorkItem->NumberOfMapRegisters = NumberOfMapRegisters; + + ExQueueWorkItem(&WorkItem->WorkQueueItem, DelayedWorkQueue); + } + + KeReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql); + + return STATUS_SUCCESS; + } + + KeReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql); + } + else + { + AdapterObject->MapRegisterBase = NULL; + AdapterObject->NumberOfMapRegisters = 0; + } + + AdapterObject->CurrentWcb = WaitContextBlock; + + Result = ExecutionRoutine(WaitContextBlock->DeviceObject, + WaitContextBlock->CurrentIrp, + AdapterObject->MapRegisterBase, + WaitContextBlock->DeviceContext); + + /* + * Possible return values: + * + * - KeepObject + * Don't free any resources, the ADAPTER_OBJECT is still in use and + * the caller will call IoFreeAdapterChannel later. + * + * - DeallocateObject + * Deallocate the map registers and release the ADAPTER_OBJECT, so + * someone else can use it. + * + * - DeallocateObjectKeepRegisters + * Release the ADAPTER_OBJECT, but hang on to the map registers. The + * client will later call IoFreeMapRegisters. + * + * NOTE: + * IoFreeAdapterChannel runs the queue, so it must be called unless + * the adapter object is not to be freed. + */ + if (Result == DeallocateObject) + { + IoFreeAdapterChannel(AdapterObject); + } + else if (Result == DeallocateObjectKeepRegisters) + { + AdapterObject->NumberOfMapRegisters = 0; + IoFreeAdapterChannel(AdapterObject); + } + + return STATUS_SUCCESS; +} + +/** + * @name IoFreeAdapterChannel + * + * Free DMA resources allocated by IoAllocateAdapterChannel. + * + * @param AdapterObject + * Adapter object with resources to free. + * + * @remarks + * This function releases map registers registers assigned to the DMA + * adapter. After releasing the adapter, it checks the adapter's queue + * and runs each queued device object in series until the queue is + * empty. This is the only way the device queue is emptied. + * + * @see IoAllocateAdapterChannel + * + * @implemented + */ +VOID +NTAPI +IoFreeAdapterChannel(IN PADAPTER_OBJECT AdapterObject) +{ + PADAPTER_OBJECT MasterAdapter; + PKDEVICE_QUEUE_ENTRY DeviceQueueEntry; + PWAIT_CONTEXT_BLOCK WaitContextBlock; + ULONG Index = MAXULONG; + ULONG Result; + KIRQL OldIrql; + + MasterAdapter = AdapterObject->MasterAdapter; + + for (;;) + { + /* + * To keep map registers, call here with AdapterObject-> + * NumberOfMapRegisters set to zero. This trick is used in + * HalAllocateAdapterChannel for example. + */ + if (AdapterObject->NumberOfMapRegisters) + { + IoFreeMapRegisters(AdapterObject, + AdapterObject->MapRegisterBase, + AdapterObject->NumberOfMapRegisters); + } + + DeviceQueueEntry = KeRemoveDeviceQueue(&AdapterObject->ChannelWaitQueue); + if (!DeviceQueueEntry) break; + + WaitContextBlock = CONTAINING_RECORD(DeviceQueueEntry, + WAIT_CONTEXT_BLOCK, + WaitQueueEntry); + + AdapterObject->CurrentWcb = WaitContextBlock; + AdapterObject->NumberOfMapRegisters = WaitContextBlock->NumberOfMapRegisters; + + if ((WaitContextBlock->NumberOfMapRegisters) && (AdapterObject->MasterAdapter)) + { + KeAcquireSpinLock(&MasterAdapter->SpinLock, &OldIrql); + + if (IsListEmpty(&MasterAdapter->AdapterQueue)) + { + Index = RtlFindClearBitsAndSet(MasterAdapter->MapRegisters, + WaitContextBlock->NumberOfMapRegisters, + 0); + if (Index != MAXULONG) + { + AdapterObject->MapRegisterBase = MasterAdapter->MapRegisterBase + Index; + if (!AdapterObject->ScatterGather) + { + AdapterObject->MapRegisterBase =(PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)AdapterObject->MapRegisterBase | MAP_BASE_SW_SG); + } + } + } + + if (Index == MAXULONG) + { + InsertTailList(&MasterAdapter->AdapterQueue, &AdapterObject->AdapterQueue); + KeReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql); + break; + } + + KeReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql); + } + else + { + AdapterObject->MapRegisterBase = NULL; + AdapterObject->NumberOfMapRegisters = 0; + } + + /* Call the adapter control routine. */ + Result = ((PDRIVER_CONTROL)WaitContextBlock->DeviceRoutine)(WaitContextBlock->DeviceObject, + WaitContextBlock->CurrentIrp, + AdapterObject->MapRegisterBase, + WaitContextBlock->DeviceContext); + switch (Result) + { + case KeepObject: + /* + * We're done until the caller manually calls IoFreeAdapterChannel + * or IoFreeMapRegisters. + */ + return; + + case DeallocateObjectKeepRegisters: + /* + * Hide the map registers so they aren't deallocated next time + * around. + */ + AdapterObject->NumberOfMapRegisters = 0; + break; + + default: + break; + } + } +} + +/** + * @name IoFreeMapRegisters + * + * Free map registers reserved by the system for a DMA. + * + * @param AdapterObject + * DMA adapter to free map registers on. + * @param MapRegisterBase + * Handle to map registers to free. + * @param NumberOfRegisters + * Number of map registers to be freed. + * + * @implemented + */ +VOID +NTAPI +IoFreeMapRegisters(IN PADAPTER_OBJECT AdapterObject, + IN PVOID MapRegisterBase, + IN ULONG NumberOfMapRegisters) +{ + PADAPTER_OBJECT MasterAdapter = AdapterObject->MasterAdapter; + PLIST_ENTRY ListEntry; + KIRQL OldIrql; + ULONG Index; + ULONG Result; + + ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); + + if (!(MasterAdapter) || !(MapRegisterBase)) return; + + KeAcquireSpinLock(&MasterAdapter->SpinLock, &OldIrql); + + if (NumberOfMapRegisters != 0) + { + PROS_MAP_REGISTER_ENTRY RealMapRegisterBase; + + RealMapRegisterBase = (PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)MapRegisterBase & ~MAP_BASE_SW_SG); + RtlClearBits(MasterAdapter->MapRegisters, + (ULONG)(RealMapRegisterBase - MasterAdapter->MapRegisterBase), + NumberOfMapRegisters); + } + + /* + * Now that we freed few map registers it's time to look at the master + * adapter queue and see if there is someone waiting for map registers. + */ + while (!IsListEmpty(&MasterAdapter->AdapterQueue)) + { + ListEntry = RemoveHeadList(&MasterAdapter->AdapterQueue); + AdapterObject = CONTAINING_RECORD(ListEntry, struct _ADAPTER_OBJECT, AdapterQueue); + + Index = RtlFindClearBitsAndSet(MasterAdapter->MapRegisters, + AdapterObject->NumberOfMapRegisters, + 0); + if (Index == MAXULONG) + { + InsertHeadList(&MasterAdapter->AdapterQueue, ListEntry); + break; + } + + KeReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql); + + AdapterObject->MapRegisterBase = MasterAdapter->MapRegisterBase + Index; + if (!AdapterObject->ScatterGather) + { + AdapterObject->MapRegisterBase = + (PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)AdapterObject->MapRegisterBase | MAP_BASE_SW_SG); + } + + Result = ((PDRIVER_CONTROL)AdapterObject->CurrentWcb->DeviceRoutine)(AdapterObject->CurrentWcb->DeviceObject, + AdapterObject->CurrentWcb->CurrentIrp, + AdapterObject->MapRegisterBase, + AdapterObject->CurrentWcb->DeviceContext); + switch (Result) + { + case DeallocateObjectKeepRegisters: + AdapterObject->NumberOfMapRegisters = 0; + /* fall through */ + + case DeallocateObject: + if (AdapterObject->NumberOfMapRegisters) + { + KeAcquireSpinLock(&MasterAdapter->SpinLock, &OldIrql); + RtlClearBits(MasterAdapter->MapRegisters, + (ULONG)(AdapterObject->MapRegisterBase - + MasterAdapter->MapRegisterBase), + AdapterObject->NumberOfMapRegisters); + KeReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql); + } + + IoFreeAdapterChannel(AdapterObject); + break; + + default: + break; + } + + KeAcquireSpinLock(&MasterAdapter->SpinLock, &OldIrql); + } + + KeReleaseSpinLock(&MasterAdapter->SpinLock, OldIrql); +} + +/** + * @name HalpCopyBufferMap + * + * Helper function for copying data from/to map register buffers. + * + * @see IoFlushAdapterBuffers, IoMapTransfer + */ +VOID +NTAPI +HalpCopyBufferMap(IN PMDL Mdl, + IN PROS_MAP_REGISTER_ENTRY MapRegisterBase, + IN PVOID CurrentVa, + IN ULONG Length, + IN BOOLEAN WriteToDevice) +{ + ULONG CurrentLength; + ULONG_PTR CurrentAddress; + ULONG ByteOffset; + PVOID VirtualAddress; + + VirtualAddress = MmGetSystemAddressForMdlSafe(Mdl, HighPagePriority); + if (!VirtualAddress) + { + /* + * NOTE: On real NT a mechanism with reserved pages is implemented + * to handle this case in a slow, but graceful non-fatal way. + */ + KeBugCheckEx(HAL_MEMORY_ALLOCATION, PAGE_SIZE, 0, (ULONG_PTR)__FILE__, 0); + } + + CurrentAddress = (ULONG_PTR)VirtualAddress + + (ULONG_PTR)CurrentVa - + (ULONG_PTR)MmGetMdlVirtualAddress(Mdl); + + while (Length > 0) + { + ByteOffset = BYTE_OFFSET(CurrentAddress); + CurrentLength = PAGE_SIZE - ByteOffset; + if (CurrentLength > Length) CurrentLength = Length; + + if (WriteToDevice) + { + RtlCopyMemory((PVOID)((ULONG_PTR)MapRegisterBase->VirtualAddress + ByteOffset), + (PVOID)CurrentAddress, + CurrentLength); + } + else + { + RtlCopyMemory((PVOID)CurrentAddress, + (PVOID)((ULONG_PTR)MapRegisterBase->VirtualAddress + ByteOffset), + CurrentLength); + } + + Length -= CurrentLength; + CurrentAddress += CurrentLength; + MapRegisterBase++; + } +} + +/** + * @name IoFlushAdapterBuffers + * + * Flush any data remaining in the DMA controller's memory into the host + * memory. + * + * @param AdapterObject + * The adapter object to flush. + * @param Mdl + * Original MDL to flush data into. + * @param MapRegisterBase + * Map register base that was just used by IoMapTransfer, etc. + * @param CurrentVa + * Offset into Mdl to be flushed into, same as was passed to + * IoMapTransfer. + * @param Length + * Length of the buffer to be flushed into. + * @param WriteToDevice + * TRUE if it's a write, FALSE if it's a read. + * + * @return TRUE in all cases. + * + * @remarks + * This copies data from the map register-backed buffer to the user's + * target buffer. Data are not in the user buffer until this function + * is called. + * For slave DMA transfers the controller channel is masked effectively + * stopping the current transfer. + * + * @unimplemented. + */ +BOOLEAN +NTAPI +IoFlushAdapterBuffers(IN PADAPTER_OBJECT AdapterObject, + IN PMDL Mdl, + IN PVOID MapRegisterBase, + IN PVOID CurrentVa, + IN ULONG Length, + IN BOOLEAN WriteToDevice) +{ + BOOLEAN SlaveDma = FALSE; + PROS_MAP_REGISTER_ENTRY RealMapRegisterBase; + PHYSICAL_ADDRESS HighestAcceptableAddress; + PHYSICAL_ADDRESS PhysicalAddress; + PPFN_NUMBER MdlPagesPtr; + + /* Sanity checks */ + ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); + ASSERT(AdapterObject); + + if (!AdapterObject->MasterDevice) + { + /* Mask out (disable) the DMA channel. */ + if (AdapterObject->AdapterNumber == 1) + { + PDMA1_CONTROL DmaControl1 = AdapterObject->AdapterBaseVa; + WRITE_PORT_UCHAR(&DmaControl1->SingleMask, + AdapterObject->ChannelNumber | DMA_SETMASK); + } + else + { + PDMA2_CONTROL DmaControl2 = AdapterObject->AdapterBaseVa; + WRITE_PORT_UCHAR(&DmaControl2->SingleMask, + AdapterObject->ChannelNumber | DMA_SETMASK); + } + SlaveDma = TRUE; + } + + /* This can happen if the device supports hardware scatter/gather. */ + if (MapRegisterBase == NULL) return TRUE; + + RealMapRegisterBase = (PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)MapRegisterBase & ~MAP_BASE_SW_SG); + + if (!WriteToDevice) + { + if ((ULONG_PTR)MapRegisterBase & MAP_BASE_SW_SG) + { + if (RealMapRegisterBase->Counter != MAXULONG) + { + if ((SlaveDma) && !(AdapterObject->IgnoreCount)) + { + Length -= HalReadDmaCounter(AdapterObject); + } + } + HalpCopyBufferMap(Mdl, + RealMapRegisterBase, + CurrentVa, + Length, + FALSE); + } + else + { + MdlPagesPtr = MmGetMdlPfnArray(Mdl); + MdlPagesPtr += ((ULONG_PTR)CurrentVa - (ULONG_PTR)Mdl->StartVa) >> PAGE_SHIFT; + + PhysicalAddress.QuadPart = *MdlPagesPtr << PAGE_SHIFT; + PhysicalAddress.QuadPart += BYTE_OFFSET(CurrentVa); + + HighestAcceptableAddress = HalpGetAdapterMaximumPhysicalAddress(AdapterObject); + if ((PhysicalAddress.QuadPart + Length) > HighestAcceptableAddress.QuadPart) + { + HalpCopyBufferMap(Mdl, + RealMapRegisterBase, + CurrentVa, + Length, + FALSE); + } + } + } + + RealMapRegisterBase->Counter = 0; + + return TRUE; +} + +/** + * @name IoMapTransfer + * + * Map a DMA for transfer and do the DMA if it's a slave. + * + * @param AdapterObject + * Adapter object to do the DMA on. Bus-master may pass NULL. + * @param Mdl + * Locked-down user buffer to DMA in to or out of. + * @param MapRegisterBase + * Handle to map registers to use for this dma. + * @param CurrentVa + * Index into Mdl to transfer into/out of. + * @param Length + * Length of transfer. Number of bytes actually transferred on + * output. + * @param WriteToDevice + * TRUE if it's an output DMA, FALSE otherwise. + * + * @return + * A logical address that can be used to program a DMA controller, it's + * not meaningful for slave DMA device. + * + * @remarks + * This function does a copyover to contiguous memory <16MB represented + * by the map registers if needed. If the buffer described by MDL can be + * used as is no copyover is done. + * If it's a slave transfer, this function actually performs it. + * + * @implemented + */ +PHYSICAL_ADDRESS +NTAPI +IoMapTransfer(IN PADAPTER_OBJECT AdapterObject, + IN PMDL Mdl, + IN PVOID MapRegisterBase, + IN PVOID CurrentVa, + IN OUT PULONG Length, + IN BOOLEAN WriteToDevice) +{ + PPFN_NUMBER MdlPagesPtr; + PFN_NUMBER MdlPage1, MdlPage2; + ULONG ByteOffset; + ULONG TransferOffset; + ULONG TransferLength; + BOOLEAN UseMapRegisters; + PROS_MAP_REGISTER_ENTRY RealMapRegisterBase; + PHYSICAL_ADDRESS PhysicalAddress; + PHYSICAL_ADDRESS HighestAcceptableAddress; + ULONG Counter; + DMA_MODE AdapterMode; + KIRQL OldIrql; + + /* + * Precalculate some values that are used in all cases. + * + * ByteOffset is offset inside the page at which the transfer starts. + * MdlPagesPtr is pointer inside the MDL page chain at the page where the + * transfer start. + * PhysicalAddress is physical address corresponding to the transfer + * start page and offset. + * TransferLength is the initial length of the transfer, which is reminder + * of the first page. The actual value is calculated below. + * + * Note that all the variables can change during the processing which + * takes place below. These are just initial values. + */ + ByteOffset = BYTE_OFFSET(CurrentVa); + + MdlPagesPtr = MmGetMdlPfnArray(Mdl); + MdlPagesPtr += ((ULONG_PTR)CurrentVa - (ULONG_PTR)Mdl->StartVa) >> PAGE_SHIFT; + + PhysicalAddress.QuadPart = *MdlPagesPtr << PAGE_SHIFT; + PhysicalAddress.QuadPart += ByteOffset; + + TransferLength = PAGE_SIZE - ByteOffset; + + /* + * Special case for bus master adapters with S/G support. We can directly + * use the buffer specified by the MDL, so not much work has to be done. + * + * Just return the passed VA's corresponding physical address and update + * length to the number of physically contiguous bytes found. Also + * pages crossing the 4Gb boundary aren't considered physically contiguous. + */ + if (MapRegisterBase == NULL) + { + while (TransferLength < *Length) + { + MdlPage1 = *MdlPagesPtr; + MdlPage2 = *(MdlPagesPtr + 1); + if (MdlPage1 + 1 != MdlPage2) break; + if ((MdlPage1 ^ MdlPage2) & ~0xFFFFF) break; + TransferLength += PAGE_SIZE; + MdlPagesPtr++; + } + + if (TransferLength < *Length) *Length = TransferLength; + + return PhysicalAddress; + } + + /* + * The code below applies to slave DMA adapters and bus master adapters + * without hardward S/G support. + */ + RealMapRegisterBase = (PROS_MAP_REGISTER_ENTRY)((ULONG_PTR)MapRegisterBase & ~MAP_BASE_SW_SG); + + /* + * Try to calculate the size of the transfer. We can only transfer + * pages that are physically contiguous and that don't cross the + * 64Kb boundary (this limitation applies only for ISA controllers). + */ + while (TransferLength < *Length) + { + MdlPage1 = *MdlPagesPtr; + MdlPage2 = *(MdlPagesPtr + 1); + if (MdlPage1 + 1 != MdlPage2) break; + if (!HalpEisaDma && ((MdlPage1 ^ MdlPage2) & ~0xF)) break; + TransferLength += PAGE_SIZE; + MdlPagesPtr++; + } + + if (TransferLength > *Length) TransferLength = *Length; + + /* + * If we're about to simulate software S/G and not all the pages are + * physically contiguous then we must use the map registers to store + * the data and allow the whole transfer to proceed at once. + */ + if (((ULONG_PTR)MapRegisterBase & MAP_BASE_SW_SG) && (TransferLength < *Length)) + { + UseMapRegisters = TRUE; + PhysicalAddress = RealMapRegisterBase->PhysicalAddress; + PhysicalAddress.QuadPart += ByteOffset; + TransferLength = *Length; + RealMapRegisterBase->Counter = MAXULONG; + Counter = 0; + } + else + { + /* + * This is ordinary DMA transfer, so just update the progress + * counters. These are used by IoFlushAdapterBuffers to track + * the transfer progress. + */ + UseMapRegisters = FALSE; + Counter = RealMapRegisterBase->Counter; + RealMapRegisterBase->Counter += BYTES_TO_PAGES(ByteOffset + TransferLength); + + /* + * Check if the buffer doesn't exceed the highest physical address + * limit of the device. In that case we must use the map registers to + * store the data. + */ + HighestAcceptableAddress = HalpGetAdapterMaximumPhysicalAddress(AdapterObject); + if ((PhysicalAddress.QuadPart + TransferLength) > HighestAcceptableAddress.QuadPart) + { + UseMapRegisters = TRUE; + PhysicalAddress = RealMapRegisterBase[Counter].PhysicalAddress; + PhysicalAddress.QuadPart += ByteOffset; + if ((ULONG_PTR)MapRegisterBase & MAP_BASE_SW_SG) + { + RealMapRegisterBase->Counter = MAXULONG; + Counter = 0; + } + } + } + + /* + * If we decided to use the map registers (see above) and we're about + * to transfer data to the device then copy the buffers into the map + * register memory. + */ + if ((UseMapRegisters) && (WriteToDevice)) + { + HalpCopyBufferMap(Mdl, + RealMapRegisterBase + Counter, + CurrentVa, + TransferLength, + WriteToDevice); + } + + /* + * Return the length of transfer that actually takes place. + */ + *Length = TransferLength; + + /* + * If we're doing slave (system) DMA then program the (E)ISA controller + * to actually start the transfer. + */ + if ((AdapterObject) && !(AdapterObject->MasterDevice)) + { + AdapterMode = AdapterObject->AdapterMode; + + if (WriteToDevice) + { + AdapterMode.TransferType = WRITE_TRANSFER; + } + else + { + AdapterMode.TransferType = READ_TRANSFER; + if (AdapterObject->IgnoreCount) + { + RtlZeroMemory((PUCHAR)RealMapRegisterBase[Counter].VirtualAddress + ByteOffset, + TransferLength); + } + } + + TransferOffset = PhysicalAddress.LowPart & 0xFFFF; + if (AdapterObject->Width16Bits) + { + TransferLength >>= 1; + TransferOffset >>= 1; + } + + KeAcquireSpinLock(&AdapterObject->MasterAdapter->SpinLock, &OldIrql); + + if (AdapterObject->AdapterNumber == 1) + { + PDMA1_CONTROL DmaControl1 = AdapterObject->AdapterBaseVa; + + /* Reset Register */ + WRITE_PORT_UCHAR(&DmaControl1->ClearBytePointer, 0); + + /* Set the Mode */ + WRITE_PORT_UCHAR(&DmaControl1->Mode, AdapterMode.Byte); + + /* Set the Offset Register */ + WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress, + (UCHAR)(TransferOffset)); + WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress, + (UCHAR)(TransferOffset >> 8)); + + /* Set the Page Register */ + WRITE_PORT_UCHAR(AdapterObject->PagePort + FIELD_OFFSET(EISA_CONTROL, DmaController1Pages), + (UCHAR)(PhysicalAddress.LowPart >> 16)); + if (HalpEisaDma) + { + WRITE_PORT_UCHAR(AdapterObject->PagePort + FIELD_OFFSET(EISA_CONTROL, DmaController2Pages), + 0); + } + + /* Set the Length */ + WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount, + (UCHAR)(TransferLength - 1)); + WRITE_PORT_UCHAR(&DmaControl1->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount, + (UCHAR)((TransferLength - 1) >> 8)); + + /* Unmask the Channel */ + WRITE_PORT_UCHAR(&DmaControl1->SingleMask, AdapterObject->ChannelNumber | DMA_CLEARMASK); + } + else + { + PDMA2_CONTROL DmaControl2 = AdapterObject->AdapterBaseVa; + + /* Reset Register */ + WRITE_PORT_UCHAR(&DmaControl2->ClearBytePointer, 0); + + /* Set the Mode */ + WRITE_PORT_UCHAR(&DmaControl2->Mode, AdapterMode.Byte); + + /* Set the Offset Register */ + WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress, + (UCHAR)(TransferOffset)); + WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseAddress, + (UCHAR)(TransferOffset >> 8)); + + /* Set the Page Register */ + WRITE_PORT_UCHAR(AdapterObject->PagePort + FIELD_OFFSET(EISA_CONTROL, DmaController1Pages), + (UCHAR)(PhysicalAddress.u.LowPart >> 16)); + if (HalpEisaDma) + { + WRITE_PORT_UCHAR(AdapterObject->PagePort + FIELD_OFFSET(EISA_CONTROL, DmaController2Pages), + 0); + } + + /* Set the Length */ + WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount, + (UCHAR)(TransferLength - 1)); + WRITE_PORT_UCHAR(&DmaControl2->DmaAddressCount[AdapterObject->ChannelNumber].DmaBaseCount, + (UCHAR)((TransferLength - 1) >> 8)); + + /* Unmask the Channel */ + WRITE_PORT_UCHAR(&DmaControl2->SingleMask, + AdapterObject->ChannelNumber | DMA_CLEARMASK); + } + + KeReleaseSpinLock(&AdapterObject->MasterAdapter->SpinLock, OldIrql); + } + + /* + * Return physical address of the buffer with data that is used for the + * transfer. It can either point inside the Mdl that was passed by the + * caller or into the map registers if the Mdl buffer can't be used + * directly. + */ + return PhysicalAddress; +} +#endif + +/** + * @name HalFlushCommonBuffer + * + * @implemented + */ +BOOLEAN +NTAPI +HalFlushCommonBuffer(IN PADAPTER_OBJECT AdapterObject, + IN ULONG Length, + IN PHYSICAL_ADDRESS LogicalAddress, + IN PVOID VirtualAddress) +{ + /* Function always returns true */ + return TRUE; +} + +/* + * @implemented + */ +PVOID +NTAPI +HalAllocateCrashDumpRegisters(IN PADAPTER_OBJECT AdapterObject, + IN OUT PULONG NumberOfMapRegisters) +{ + PADAPTER_OBJECT MasterAdapter = AdapterObject->MasterAdapter; + ULONG MapRegisterNumber; + + /* Check if it needs map registers */ + if (AdapterObject->NeedsMapRegisters) + { + /* Check if we have enough */ + if (*NumberOfMapRegisters > AdapterObject->MapRegistersPerChannel) + { + /* We don't, fail */ + AdapterObject->NumberOfMapRegisters = 0; + return NULL; + } + + /* Try to find free map registers */ + MapRegisterNumber = RtlFindClearBitsAndSet(MasterAdapter->MapRegisters, + *NumberOfMapRegisters, + 0); + + /* Check if nothing was found */ + if (MapRegisterNumber == MAXULONG) + { + /* No free registers found, so use the base registers */ + RtlSetBits(MasterAdapter->MapRegisters, + 0, + *NumberOfMapRegisters); + MapRegisterNumber = 0; + } + + /* Calculate the new base */ + AdapterObject->MapRegisterBase = + (PROS_MAP_REGISTER_ENTRY)(MasterAdapter->MapRegisterBase + + MapRegisterNumber); + + /* Check if scatter gather isn't supported */ + if (!AdapterObject->ScatterGather) + { + /* Set the flag */ + AdapterObject->MapRegisterBase = + (PROS_MAP_REGISTER_ENTRY) + ((ULONG_PTR)AdapterObject->MapRegisterBase | MAP_BASE_SW_SG); + } + } + else + { + AdapterObject->MapRegisterBase = NULL; + AdapterObject->NumberOfMapRegisters = 0; + } + + /* Return the base */ + return AdapterObject->MapRegisterBase; +} + +/* EOF */ diff --git a/hal/halacpi/generic/drive.c b/hal/halacpi/generic/drive.c new file mode 100644 index 0000000000000..965514ed68bf7 --- /dev/null +++ b/hal/halacpi/generic/drive.c @@ -0,0 +1,70 @@ + +/* INCLUDES ******************************************************************/ + +#include +#include + +//#define NDEBUG +#include + +/* FUNCTIONS *****************************************************************/ + +VOID +NTAPI +HalpAssignDriveLetters(IN struct _LOADER_PARAMETER_BLOCK * LoaderBlock, + IN PSTRING NtDeviceName, + OUT PUCHAR NtSystemPath, + OUT PSTRING NtSystemPathString) +{ + /* Call the kernel */ + IoAssignDriveLetters(LoaderBlock, + NtDeviceName, + NtSystemPath, + NtSystemPathString); +} + +NTSTATUS +NTAPI +HalpReadPartitionTable(IN PDEVICE_OBJECT DeviceObject, + IN ULONG SectorSize, + IN BOOLEAN ReturnRecognizedPartitions, + IN OUT PDRIVE_LAYOUT_INFORMATION * PartitionBuffer) +{ + /* Call the kernel */ + return IoReadPartitionTable(DeviceObject, + SectorSize, + ReturnRecognizedPartitions, + PartitionBuffer); +} + +NTSTATUS +NTAPI +HalpSetPartitionInformation(IN PDEVICE_OBJECT DeviceObject, + IN ULONG SectorSize, + IN ULONG PartitionNumber, + IN ULONG PartitionType) +{ + /* Call the kernel */ + return IoSetPartitionInformation(DeviceObject, + SectorSize, + PartitionNumber, + PartitionType); +} + +NTSTATUS +NTAPI +HalpWritePartitionTable(IN PDEVICE_OBJECT DeviceObject, + IN ULONG SectorSize, + IN ULONG SectorsPerTrack, + IN ULONG NumberOfHeads, + IN PDRIVE_LAYOUT_INFORMATION PartitionBuffer) +{ + /* Call the kernel */ + return IoWritePartitionTable(DeviceObject, + SectorSize, + SectorsPerTrack, + NumberOfHeads, + PartitionBuffer); +} + +/* EOF */ diff --git a/hal/halacpi/generic/halinit.c b/hal/halacpi/generic/halinit.c new file mode 100644 index 0000000000000..0922653cc2d2d --- /dev/null +++ b/hal/halacpi/generic/halinit.c @@ -0,0 +1,358 @@ + +/* INCLUDES ******************************************************************/ + +#include +//#define NDEBUG +#include + +#if defined(ALLOC_PRAGMA) && !defined(_MINIHAL_) + #pragma alloc_text(INIT, HalInitializeProcessor) + #pragma alloc_text(INIT, HalInitSystem) +#endif + +/* GLOBALS *******************************************************************/ + +KAFFINITY HalpActiveProcessors; +KAFFINITY HalpDefaultInterruptAffinity; +LIST_ENTRY HalpDmaAdapterList; +KSPIN_LOCK HalpDmaAdapterListLock; +ULONG HalpBusType; + +ADDRESS_USAGE HalpDefaultIoSpace = +{ + NULL, CmResourceTypePort, IDT_INTERNAL, + { + {0x00, 0x10}, /* DMA 1 */ + {0xC0, 0x10}, /* DMA 2 */ + {0x80, 0x10}, /* DMA EPAR */ + {0x20, 0x2}, /* PIC 1 */ + {0xA0, 0x2}, /* PIC 2 */ + {0x40, 0x4}, /* PIT 1 */ + {0x48, 0x4}, /* PIT 2 */ + {0x92, 0x1}, /* System Control Port A */ + {0x70, 0x2}, /* CMOS */ + {0xF0, 0x10}, /* x87 Coprocessor */ + {0xCF8, 0x8}, /* PCI 0 */ + {0,0}, + } +}; + +ADDRESS_USAGE HalpEisaIoSpace = +{ + NULL, CmResourceTypePort, IDT_INTERNAL, + { + {0xD0, 0x10}, /* */ + {0x400, 0x10}, /* */ + {0x480, 0x10}, /* */ + {0x4C2, 0xE}, /* */ + {0x4D4, 0x2C}, /* */ + {0x461, 0x2}, /* */ + {0x464, 0x2}, /* */ + {0x4D0, 0x2}, /* */ + {0xC84, 0x1}, /* */ + {0,0}, + } +}; + +PADDRESS_USAGE HalpAddressUsageList; + +BOOLEAN HalpPciLockSettings; +BOOLEAN LessThan16Mb = TRUE; +BOOLEAN HalpPhysicalMemoryMayAppearAbove4GB = FALSE; + +extern KSPIN_LOCK HalpSystemHardwareLock; +extern ULONG HalpFeatureBits; + +/* PRIVATE FUNCTIONS *********************************************************/ + +/* FIXME for other types of HALs there are other options. */ +CODE_SEG("INIT") +VOID +NTAPI +HalpGetParameters(IN PLOADER_PARAMETER_BLOCK LoaderBlock) +{ + PCHAR CommandLine; + + /* Make sure we have a loader block and command line */ + if (!LoaderBlock || !LoaderBlock->LoadOptions) + { + DPRINT1("HalpGetParameters: error ... \n"); + return; + } + + /* Read the command line */ + CommandLine = LoaderBlock->LoadOptions; + + /* Check if PCI is locked */ + if (strstr(CommandLine, "PCILOCK")) + HalpPciLockSettings = TRUE; + + /* Check for initial breakpoint */ + if (strstr(CommandLine, "BREAK")) + { + DPRINT1("HalpGetParameters: initial breakpoint [BREAK]\n"); + DbgBreakPoint(); + } +} + +/* FUNCTIONS *****************************************************************/ + +CODE_SEG("INIT") +VOID +NTAPI +HalInitializeProcessor( + IN ULONG ProcessorNumber, + IN PLOADER_PARAMETER_BLOCK LoaderBlock) +{ + /* Set default IDR */ + KeGetPcr()->IDR = 0xFFFFFFFB; + + /* Set default stall count */ + KeGetPcr()->StallScaleFactor = INITIAL_STALL_COUNT; + + /* Update the interrupt affinity and processor mask */ + InterlockedBitTestAndSet((PLONG)&HalpActiveProcessors, ProcessorNumber); + InterlockedBitTestAndSet((PLONG)&HalpDefaultInterruptAffinity, ProcessorNumber); + + /* Register routines for KDCOM */ + + /* Register PCI Device Functions */ + KdSetupPciDeviceForDebugging = HalpSetupPciDeviceForDebugging; + KdReleasePciDeviceforDebugging = HalpReleasePciDeviceForDebugging; + + /* Register ACPI stub */ + KdGetAcpiTablePhase0 = HalAcpiGetTable; + KdCheckPowerButton = HalpCheckPowerButton; + + /* Register memory functions */ + KdMapPhysicalMemory64 = HalpMapPhysicalMemory64; + KdUnmapVirtualAddress = HalpUnmapVirtualAddress; +} + +VOID +NTAPI +HalpInitNonBusHandler(VOID) +{ + DPRINT("HalpInitNonBusHandler()\n"); + + /* These (HalPrivateDispatchTable) should be written by the PCI driver later, but we give defaults */ + HalPciTranslateBusAddress = HalpTranslateBusAddress; + HalPciAssignSlotResources = HalpAssignSlotResources; + HalFindBusAddressTranslation = HalpFindBusAddressTranslation; +} + +CODE_SEG("INIT") +VOID +NTAPI +HalpEnableInterruptHandler(IN UCHAR Flags, + IN ULONG BusVector, + IN ULONG SystemVector, + IN KIRQL Irql, + IN PVOID Handler, + IN KINTERRUPT_MODE Mode) +{ + DPRINT("HalpEnableInterruptHandler: %X, %X, %X, %X\n", Flags, BusVector, SystemVector, Irql); + + /* Connect the interrupt */ + KeRegisterInterruptHandler(SystemVector, Handler); + + /* Enable the interrupt */ + HalEnableSystemInterrupt(SystemVector, Irql, Mode); +} + +CODE_SEG("INIT") +BOOLEAN +NTAPI +HalInitSystem(IN ULONG BootPhase, + IN PLOADER_PARAMETER_BLOCK LoaderBlock) +{ + PMEMORY_ALLOCATION_DESCRIPTOR MemDescriptor; + PKPRCB Prcb = KeGetCurrentPrcb(); + PLIST_ENTRY Entry; + KIRQL OldIrql; + /* Phase 0... save bus type */ + HalpBusType = LoaderBlock->u.I386.MachineType & 0xFF; + DPRINT1("HalInitSystem: Phase - %X, Processor - %X\n", BootPhase, Prcb->Number); + + /* Check the boot phase */ + if (BootPhase == 0) + { + /* Phase 0... save bus type */ + HalpBusType = (LoaderBlock->u.I386.MachineType & 0xFF); + + /* Get command-line parameters */ + HalpGetParameters(LoaderBlock); + + /* Check for PRCB version mismatch */ + if (Prcb->MajorVersion != PRCB_MAJOR_VERSION) { + /* No match, bugcheck */ + DPRINT1("HalInitSystem: MajorVersion %X - (%X)\n", Prcb->MajorVersion, PRCB_MAJOR_VERSION); + KeBugCheckEx(MISMATCHED_HAL, 1, Prcb->MajorVersion, PRCB_MAJOR_VERSION, 0); + } + + #if DBG + if ((Prcb->BuildType & PRCB_BUILD_DEBUG) == 0) { + DPRINT1("HalInitSystem: BuildType %X - (%X)\n", Prcb->BuildType, PRCB_BUILD_DEBUG); + KeBugCheckEx(MISMATCHED_HAL, 2, Prcb->BuildType, PRCB_BUILD_DEBUG, 0); + } + if ((Prcb->BuildType & PRCB_BUILD_UNIPROCESSOR) == PRCB_BUILD_UNIPROCESSOR) { + DPRINT1("HalInitSystem: BuildType %X - (%X)\n", Prcb->BuildType, PRCB_BUILD_UNIPROCESSOR); + KeBugCheckEx(MISMATCHED_HAL, 2, Prcb->BuildType, 0, 0); + } + #else + if ((Prcb->BuildType & PRCB_BUILD_DEBUG) == PRCB_BUILD_DEBUG) + { + DPRINT1("HalInitSystem: BuildType %X - (%X)\n", Prcb->BuildType, PRCB_BUILD_DEBUG); + KeBugCheckEx(MISMATCHED_HAL, 2, Prcb->BuildType, PRCB_BUILD_DEBUG, 0); + } + #endif + + /* Do some HAL-specific initialization */ // HalpInitPhase0_0 + if (HalpBusType == MACHINE_TYPE_MCA) { + DPRINT1("HalInitSystem: HalpBusType %X - (%X)\n", HalpBusType, MACHINE_TYPE_MCA); + KeBugCheckEx(MISMATCHED_HAL, 3, MACHINE_TYPE_MCA, 0, 0); + } + + /* Initialize ACPI */ + HalpSetupAcpiPhase0(LoaderBlock); + + /* Initialize the PICs */ + HalpInitializePICs(TRUE); + + OldIrql = KeGetCurrentIrql(); + KfRaiseIrql(OldIrql); + + /* Initialize CMOS lock */ + KeInitializeSpinLock(&HalpSystemHardwareLock); + + /* Initialize CMOS */ + HalpInitializeCmos(); + + /* Fill out HalDispatchTable */ + HalQuerySystemInformation = HaliQuerySystemInformation; + HalSetSystemInformation = HaliSetSystemInformation; + HalInitPnpDriver = HaliInitPnpDriver; + HalGetDmaAdapter = HalpGetDmaAdapter; // HaliGetDmaAdapter + HalGetInterruptTranslator = HalacpiGetInterruptTranslator; + HalInitPowerManagement = HalacpiInitPowerManagement; + + /* Fill out HalPrivateDispatchTable */ + HalResetDisplay = HalpBiosDisplayReset; + // HalAllocateMapRegisters = HalpAllocateMapRegisters; + // HalLocateHiberRanges = HaliLocateHiberRanges; + HalHaltSystem = HaliHaltSystem; + + /* Register IRQ 2 */ + HalpRegisterVector(IDT_INTERNAL, + (PRIMARY_VECTOR_BASE + 2), + (PRIMARY_VECTOR_BASE + 2), + HIGH_LEVEL); + + if (HalpBusType == MACHINE_TYPE_EISA) { + DPRINT1("HalInitSystem: FIXME HalpBusType == MACHINE_TYPE_EISA\n"); + ASSERT(FALSE);// HalpDbgBreakPointEx(); + } + + /* Setup I/O space */ + HalpDefaultIoSpace.Next = HalpAddressUsageList; // HalpDefaultPcIoSpace + HalpAddressUsageList = &HalpDefaultIoSpace; + + if (HalpBusType == MACHINE_TYPE_EISA) { + DPRINT1("HalInitSystem: HalpBusType == MACHINE_TYPE_EISA\n"); + HalpEisaIoSpace.Next = &HalpDefaultIoSpace; + HalpAddressUsageList = &HalpEisaIoSpace; + } + + /* Initialize the clock */ + DPRINT1("HalInitSystem: Initialize the clock\n"); + HalpInitializeClock(); + + /* We could be rebooting with a pending profile interrupt, so clear it here before interrupts are enabled */ + DPRINT1("HalInitSystem: clear profile interrupt\n"); + HalStopProfileInterrupt(ProfileTime); + + KeInitializeSpinLock(&HalpDmaAdapterListLock); + InitializeListHead(&HalpDmaAdapterList); + //KeInitializeEvent(&HalpNewAdapter, SynchronizationEvent, TRUE); + + for (Entry = LoaderBlock->MemoryDescriptorListHead.Flink; + Entry != &LoaderBlock->MemoryDescriptorListHead; + Entry = Entry->Flink) + { + MemDescriptor = CONTAINING_RECORD(Entry, MEMORY_ALLOCATION_DESCRIPTOR, ListEntry); + + if (MemDescriptor->MemoryType != LoaderFirmwarePermanent && + MemDescriptor->MemoryType != LoaderSpecialMemory) + { + if (MemDescriptor->BasePage + MemDescriptor->PageCount > 0x1000) // 16 Mb + LessThan16Mb = FALSE; + + if (MemDescriptor->BasePage + MemDescriptor->PageCount > 0x100000) { // 4 Gb + HalpPhysicalMemoryMayAppearAbove4GB = TRUE; + break; + } + } + } + + if (LessThan16Mb) { + DPRINT1("HalInitSystem: LessThan16Mb - TRUE\n"); + } + if (HalpPhysicalMemoryMayAppearAbove4GB) { + DPRINT1("HalInitSystem: HalpPhysicalMemoryMayAppearAbove4GB - TRUE\n"); + } + } + else if (BootPhase == 1) + { + if (Prcb->Number != 0) { + DPRINT1("HalInitSystem: Prcb->Number %X\n", Prcb->Number); + return TRUE; + } + + /* Initialize DMA. NT does this in Phase 0 */ + HalpInitDma(); + + DPRINT1("HalpInitPhase1: FIXME HalpInitReservedPages()\n"); + + /* Initialize bus handlers */ + HalpInitNonBusHandler(); + + HalpFeatureBits = HalpGetFeatureBits(); + if (HalpFeatureBits & 0x20) { + DPRINT1("FIXME HalpMovntiCopyBuffer\n"); + //ASSERT(0);//HalpDbgBreakPointEx(); + } + + /* Enable IRQ 0 */ + HalpEnableInterruptHandler((IDT_DEVICE + IDT_LATCHED), + 0, + (PRIMARY_VECTOR_BASE + 0), // 0x30 + CLOCK2_LEVEL, // 0x1C + HalpClockInterrupt, + Latched); + + /* Enable IRQ 8 */ + HalpEnableInterruptHandler((IDT_DEVICE + IDT_LATCHED), + 8, + (PRIMARY_VECTOR_BASE + 8), // 0x38 + PROFILE_LEVEL, // 0x1B + HalpProfileInterrupt, + Latched); + + DPRINT1("HalpInitPhase1: FIXME HalpAcpiTimerPerfCountHack()\n"); + + if (Prcb->CpuType == 3) // 80387 ? + { + DPRINT1("HalpInitPhase1: FIXME! Prcb->CpuType %X\n", Prcb->CpuType); + ASSERT(0);// HalpDbgBreakPointEx(); + } + } + else + { + DPRINT1("HalInitSystem: Unknown BootPhase %X\n", BootPhase); + } + + /* All done, return */ + return TRUE; +} + +/* EOF */ diff --git a/hal/halacpi/generic/i386/bios.c b/hal/halacpi/generic/i386/bios.c new file mode 100644 index 0000000000000..54acabf692dd5 --- /dev/null +++ b/hal/halacpi/generic/i386/bios.c @@ -0,0 +1,594 @@ +/* INCLUDES *******************************************************************/ + +#include +//#define NDEBUG +#include + +typedef struct _HAL_BIOS_FRAME +{ + ULONG SegSs; + ULONG Esp; + ULONG EFlags; + ULONG SegCs; + ULONG Eip; + PKTRAP_FRAME TrapFrame; + ULONG CsLimit; + ULONG CsBase; + ULONG CsFlags; + ULONG SsLimit; + ULONG SsBase; + ULONG SsFlags; + ULONG Prefix; +} HAL_BIOS_FRAME, *PHAL_BIOS_FRAME; + +/* GLOBALS ********************************************************************/ + +/* PTE Data */ +ULONG HalpSavedPfn; +HARDWARE_PTE HalpSavedPte; + +/* IDT Data */ +PVOID HalpGpfHandler; +PVOID HalpBopHandler; + +/* TSS Data */ +ULONG HalpSavedEsp0; +USHORT HalpSavedTss; + +/* IOPM Data */ +USHORT HalpSavedIopmBase; +PUSHORT HalpSavedIoMap; +USHORT HalpSavedIoMapData[IOPM_SIZE / sizeof(USHORT)][2]; +ULONG HalpSavedIoMapEntries; + +/* Where the protected mode stack is */ +//ULONG_PTR HalpSavedEsp; + +/* Where the real mode code ends */ +extern PVOID HalpRealModeEnd; + +/* Context saved for return from v86 mode */ +jmp_buf HalpSavedContext; + +BOOLEAN HalpNMIInProgress; + +/* V86 OPCODE HANDLERS ********************************************************/ + +BOOLEAN +FASTCALL +HalpOpcodeInvalid(IN PHAL_BIOS_FRAME BiosFrame) +{ + PUCHAR Inst = (PUCHAR)(BiosFrame->CsBase + BiosFrame->Eip); + + /* Print error message */ + DPRINT1("HAL: An invalid V86 opcode was encountered at address %X:%X\n" + "Opcode: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", + BiosFrame->SegCs, BiosFrame->Eip, + Inst[0], Inst[1], Inst[2], Inst[3], Inst[4], + Inst[5], Inst[6], Inst[7], Inst[8], Inst[9]); + + /* Break */ + DbgBreakPoint();//HalpDbgBreakPointEx(); + return FALSE; +} + +BOOLEAN +FASTCALL +HalpPushInt(IN PHAL_BIOS_FRAME BiosFrame, + IN ULONG Interrupt) +{ + PUSHORT Stack; + ULONG Eip; + + /* Calculate stack address (SP) */ + Stack = (PUSHORT)(BiosFrame->SsBase + (BiosFrame->Esp & 0xFFFF)); + + /* Push EFlags */ + Stack--; + *Stack = BiosFrame->EFlags & 0xFFFF; + + /* Push CS */ + Stack--; + *Stack = BiosFrame->SegCs & 0xFFFF; + + /* Push IP */ + Stack--; + *Stack = BiosFrame->Eip & 0xFFFF; + + /* Compute new CS:IP from the IVT address for this interrupt entry */ + Eip = *(PULONG)(Interrupt * 4); + BiosFrame->Eip = Eip & 0xFFFF; + BiosFrame->SegCs = Eip >> 16; + + /* Update stack address */ + BiosFrame->Esp = (ULONG_PTR)Stack & 0xFFFF; + + /* Update CS to linear */ + BiosFrame->CsBase = BiosFrame->SegCs << 4; + BiosFrame->CsLimit = 0xFFFF; + BiosFrame->CsFlags = 0; + + /* We're done */ + return TRUE; +} + +BOOLEAN +FASTCALL +HalpOpcodeINTnn(IN PHAL_BIOS_FRAME BiosFrame) +{ + UCHAR Interrupt; + PKTRAP_FRAME TrapFrame; + + /* Convert SS to linear */ + BiosFrame->SsBase = BiosFrame->SegSs << 4; + BiosFrame->SsLimit = 0xFFFF; + BiosFrame->SsFlags = 0; + + /* Increase EIP and validate */ + BiosFrame->Eip++; + if (BiosFrame->Eip > BiosFrame->CsLimit) return FALSE; + + /* Read interrupt number */ + Interrupt = *(PUCHAR)(BiosFrame->CsBase + BiosFrame->Eip); + + /* Increase EIP and push the interrupt */ + BiosFrame->Eip++; + if (HalpPushInt(BiosFrame, Interrupt)) + { + /* Update the trap frame */ + TrapFrame = BiosFrame->TrapFrame; + TrapFrame->HardwareSegSs = BiosFrame->SegSs; + TrapFrame->HardwareEsp = BiosFrame->Esp; + TrapFrame->SegCs = BiosFrame->SegCs; + TrapFrame->EFlags = BiosFrame->EFlags; + + /* Success */ + return TRUE; + } + + /* Failure */ + return FALSE; +} + +BOOLEAN +FASTCALL +HalpDispatchV86Opcode(IN PKTRAP_FRAME TrapFrame) +{ + UCHAR Instruction; + HAL_BIOS_FRAME BiosFrame; + + /* Fill out the BIOS frame */ + BiosFrame.TrapFrame = TrapFrame; + BiosFrame.SegSs = TrapFrame->HardwareSegSs; + BiosFrame.Esp = TrapFrame->HardwareEsp; + BiosFrame.EFlags = TrapFrame->EFlags; + BiosFrame.SegCs = TrapFrame->SegCs; + BiosFrame.Eip = TrapFrame->Eip; + BiosFrame.Prefix = 0; + + /* Convert CS to linear */ + BiosFrame.CsBase = BiosFrame.SegCs << 4; + BiosFrame.CsLimit = 0xFFFF; + BiosFrame.CsFlags = 0; + + /* Validate IP */ + if (BiosFrame.Eip > BiosFrame.CsLimit) return FALSE; + + /* Read IP */ + Instruction = *(PUCHAR)(BiosFrame.CsBase + BiosFrame.Eip); + if (Instruction != 0xCD) + { + /* We only support INT */ + HalpOpcodeInvalid(&BiosFrame); + return FALSE; + } + + /* Handle the interrupt */ + if (HalpOpcodeINTnn(&BiosFrame)) + { + /* Update EIP */ + TrapFrame->Eip = BiosFrame.Eip; + + /* We're done */ + return TRUE; + } + + /* Failure */ + return FALSE; +} + +/* V86 TRAP HANDLERS **********************************************************/ + +DECLSPEC_NORETURN +VOID +FASTCALL +HalpTrap0DHandler(IN PKTRAP_FRAME TrapFrame) +{ + /* Enter the trap */ + KiEnterTrap(TrapFrame); + + /* Check if this is a V86 trap */ + if (TrapFrame->EFlags & EFLAGS_V86_MASK) + { + /* Dispatch the opcode and exit the trap */ + HalpDispatchV86Opcode(TrapFrame); + KiEoiHelper(TrapFrame); + } + + /* Strange, it isn't! This can happen during NMI */ + DPRINT1("HAL: Trap0D while not in V86 mode\n"); + KiDumpTrapFrame(TrapFrame); + + ERROR_FATAL(); + while (TRUE); /* 'noreturn' function */ +} + +VOID +DECLSPEC_NORETURN +HalpTrap06(VOID) +{ + /* Restore ES/DS to known good values first */ + Ke386SetEs(KGDT_R3_DATA | RPL_MASK); + Ke386SetDs(KGDT_R3_DATA | RPL_MASK); + Ke386SetFs(KGDT_R0_PCR); + + /* Restore the stack */ + KeGetPcr()->TSS->Esp0 = HalpSavedEsp0; + + /* Return back to where we left */ + longjmp(HalpSavedContext, 1); + UNREACHABLE; +} + +/* V8086 ENTER ****************************************************************/ + +VOID +NTAPI +HalpBiosCall(VOID) +{ + /* Must be volatile so it doesn't get optimized away! */ + volatile KTRAP_FRAME V86TrapFrame; + ULONG_PTR StackOffset, CodeOffset; + + /* Save the context, check for return */ + if (_setjmp(HalpSavedContext)) + /* Returned from v86 */ + return; + + /* Kill alignment faults */ + __writecr0(__readcr0() & ~CR0_AM); + + /* Set new stack address */ + KeGetPcr()->TSS->Esp0 = ((ULONG)&V86TrapFrame - 0x20 - sizeof(FX_SAVE_AREA)); + + /* Compute segmented IP and SP offsets */ + StackOffset = ((ULONG_PTR)&HalpRealModeEnd - 4 - (ULONG_PTR)HalpRealModeStart); + CodeOffset = ((ULONG_PTR)HalpRealModeStart & 0xFFF); + + /* Now build the V86 trap frame */ + V86TrapFrame.V86Es = 0; + V86TrapFrame.V86Ds = 0; + V86TrapFrame.V86Gs = 0; + V86TrapFrame.V86Fs = 0; + V86TrapFrame.HardwareSegSs = 0x2000; + V86TrapFrame.HardwareEsp = (StackOffset + CodeOffset); + V86TrapFrame.EFlags = (__readeflags() | EFLAGS_V86_MASK | EFLAGS_IOPL); + V86TrapFrame.SegCs = 0x2000; + V86TrapFrame.Eip = CodeOffset; + + /* Exit to V86 mode */ + HalpExitToV86((PKTRAP_FRAME)&V86TrapFrame); +} + +/* FUNCTIONS ******************************************************************/ + +VOID +NTAPI +HalpBorrowTss(VOID) +{ + USHORT Tss; + PKGDTENTRY TssGdt; + ULONG_PTR TssLimit; + PKTSS TssBase; + + /* Get the current TSS and its GDT entry */ + Tss = Ke386GetTr(); + TssGdt = &((PKIPCR)KeGetPcr())->GDT[Tss / sizeof(KGDTENTRY)]; + + /* Get the KTSS limit and check if it has IOPM space */ + TssLimit = (TssGdt->LimitLow | TssGdt->HighWord.Bits.LimitHi << 16); + + /* If the KTSS doesn't have enough space this is probably an NMI or DF */ + if (TssLimit > IOPM_SIZE) + { + /* We are good to go */ + HalpSavedTss = 0; + return; + } + + /* Get the "real" TSS */ + TssGdt = &((PKIPCR)KeGetPcr())->GDT[KGDT_TSS / sizeof(KGDTENTRY)]; + TssBase = (PKTSS)(ULONG_PTR)(TssGdt->BaseLow | + TssGdt->HighWord.Bytes.BaseMid << 16 | + TssGdt->HighWord.Bytes.BaseHi << 24); + + /* Switch to it */ + KeGetPcr()->TSS = TssBase; + + /* Set it up */ + TssGdt->HighWord.Bits.Type = I386_TSS; + TssGdt->HighWord.Bits.Pres = 1; + TssGdt->HighWord.Bits.Dpl = 0; + + /* Load new TSS and return old one */ + Ke386SetTr(KGDT_TSS); + HalpSavedTss = Tss; +} + +VOID +NTAPI +HalpStoreAndClearIopm(VOID) +{ + USHORT ix, jx; + PUSHORT Entry = HalpSavedIoMap; + + /* Loop the I/O Map */ + for (ix = jx = 0; ix < (IOPM_SIZE / sizeof(USHORT)); ix++) + { + /* Check for non-FFFF entry */ + if (*Entry != 0xFFFF) + { + /* Save it */ + ASSERT(jx < 32); + HalpSavedIoMapData[jx][0] = ix; + HalpSavedIoMapData[jx][1] = *Entry; + jx++; + } + + /* Clear it */ + *Entry++ = 0; + } + + /* Terminate it */ + while (ix++ < (IOPM_FULL_SIZE / sizeof(USHORT))) + { + *Entry++ = 0xFFFF; + } + + /* Return the entries we saved */ + HalpSavedIoMapEntries = jx; +} + +VOID +NTAPI +HalpMapRealModeMemory(VOID) +{ + PHARDWARE_PTE Pte, V86Pte; + ULONG ix; + + /* Get the page table directory for the lowest meg of memory */ + Pte = HalAddressToPde(0); + HalpSavedPfn = Pte->PageFrameNumber; + HalpSavedPte = *Pte; + + /* Map it to the HAL reserved region and make it valid */ + Pte->Valid = 1; + Pte->Write = 1; + Pte->Owner = 1; + Pte->PageFrameNumber = (HalAddressToPde(0xFFC00000))->PageFrameNumber; + + /* Flush the TLB */ + HalpFlushTLB(); + + /* Now loop the first meg of memory */ + for (ix = 0; ix < 0x100000; ix += PAGE_SIZE) + { + /* Identity map it */ + Pte = HalAddressToPte(ix); + Pte->PageFrameNumber = ix >> PAGE_SHIFT; + Pte->Valid = 1; + Pte->Write = 1; + Pte->Owner = 1; + } + + /* Now get the entry for our real mode V86 code and the target */ + Pte = HalAddressToPte(0x20000); + V86Pte = HalAddressToPte(&HalpRealModeStart); + + do + { + /* Map the physical address into our real-mode region */ + Pte->PageFrameNumber = V86Pte->PageFrameNumber; + + /* Keep going until we've reached the end of our region */ + Pte++; + V86Pte++; + } + while (V86Pte <= HalAddressToPte(&HalpRealModeEnd)); + + /* Flush the TLB */ + HalpFlushTLB(); +} + +VOID +NTAPI +HalpSwitchToRealModeTrapHandlers(VOID) +{ + /* Save the current Invalid Opcode and General Protection Fault Handlers */ + HalpGpfHandler = KeQueryInterruptHandler(13); + HalpBopHandler = KeQueryInterruptHandler(6); + + /* Now set our own GPF handler to handle exceptions while in real mode */ + KeRegisterInterruptHandler(13, HalpTrap0D); + + /* And our own invalid opcode handler to detect the BOP to get us out */ + KeRegisterInterruptHandler(6, HalpTrap06); +} + +VOID +NTAPI +HalpSetupRealModeIoPermissionsAndTask(VOID) +{ + /* Switch to valid TSS */ + HalpBorrowTss(); + + /* Save a copy of the I/O Map and delete it */ + HalpSavedIoMap = (PUSHORT)KeGetPcr()->TSS->IoMaps[0].IoMap; + HalpStoreAndClearIopm(); + + /* Save the IOPM and switch to the real-mode one */ + HalpSavedIopmBase = KeGetPcr()->TSS->IoMapBase; + KeGetPcr()->TSS->IoMapBase = KiComputeIopmOffset(1); + + /* Save our stack pointer */ + HalpSavedEsp0 = KeGetPcr()->TSS->Esp0; +} + +VOID +NTAPI +HalpRestoreTrapHandlers(VOID) +{ + /* Keep dummy GPF handler in case we get an NMI during V8086 */ + if (!HalpNMIInProgress) + { + /* Not an NMI -- put back the original handler */ + KeRegisterInterruptHandler(13, HalpGpfHandler); + } + + /* Restore invalid opcode handler */ + KeRegisterInterruptHandler(6, HalpBopHandler); +} + +VOID +NTAPI +HalpRestoreIopm(VOID) +{ + ULONG ix = HalpSavedIoMapEntries; + + /* Set default state */ + RtlFillMemory(HalpSavedIoMap, IOPM_FULL_SIZE, 0xFF); + + /* Restore the backed up copy, and initialize it */ + while (ix--) + HalpSavedIoMap[HalpSavedIoMapData[ix][0]] = HalpSavedIoMapData[ix][1]; +} + +VOID +NTAPI +HalpReturnTss(VOID) +{ + PKGDTENTRY TssGdt; + PKTSS TssBase; + + /* Get the original TSS */ + TssGdt = &((PKIPCR)KeGetPcr())->GDT[HalpSavedTss / sizeof(KGDTENTRY)]; + TssBase = (PKTSS)(ULONG_PTR)(TssGdt->BaseLow | + TssGdt->HighWord.Bytes.BaseMid << 16 | + TssGdt->HighWord.Bytes.BaseHi << 24); + /* Switch to it */ + KeGetPcr()->TSS = TssBase; + + /* Set it up */ + TssGdt->HighWord.Bits.Type = I386_TSS; + TssGdt->HighWord.Bits.Pres = 1; + TssGdt->HighWord.Bits.Dpl = 0; + + /* Load old TSS */ + Ke386SetTr(HalpSavedTss); +} + +VOID +NTAPI +HalpRestoreIoPermissionsAndTask(VOID) +{ + /* Restore the stack pointer */ + KeGetPcr()->TSS->Esp0 = HalpSavedEsp0; + + /* Restore the I/O Map */ + HalpRestoreIopm(); + + /* Restore the IOPM */ + KeGetPcr()->TSS->IoMapBase = HalpSavedIopmBase; + + /* Restore the TSS */ + if (HalpSavedTss) + HalpReturnTss(); +} + +VOID +NTAPI +HalpUnmapRealModeMemory(VOID) +{ + ULONG ix; + PHARDWARE_PTE Pte; + + /* Loop the first meg of memory */ + for (ix = 0; ix < 0x100000; ix += PAGE_SIZE) + { + /* Invalidate each PTE */ + Pte = HalAddressToPte(ix); + Pte->Valid = 0; + Pte->Write = 0; + Pte->Owner = 0; + Pte->PageFrameNumber = 0; + } + + /* Restore the PDE for the lowest megabyte of memory */ + Pte = HalAddressToPde(0); + *Pte = HalpSavedPte; + Pte->PageFrameNumber = HalpSavedPfn; + + /* Flush the TLB */ + HalpFlushTLB(); +} + +BOOLEAN +NTAPI +HalpBiosDisplayReset(VOID) +{ + ULONG Flags; + PHARDWARE_PTE IdtPte; + BOOLEAN RestoreWriteProtection = FALSE; + + /* Disable interrupts */ + Flags = __readeflags(); + _disable(); + + /* Map memory available to the V8086 real-mode code */ + HalpMapRealModeMemory(); + + /* On P5, the first 7 entries of the IDT are write protected to work around + the cmpxchg8b lock errata. Unprotect them here so we can set our custom + invalid op-code handler. + */ + IdtPte = HalAddressToPte(((PKIPCR)KeGetPcr())->IDT); + RestoreWriteProtection = (IdtPte->Write != 0); + IdtPte->Write = 1; + + /* Use special invalid opcode and GPF trap handlers */ + HalpSwitchToRealModeTrapHandlers(); + + /* Configure the IOPM and TSS */ + HalpSetupRealModeIoPermissionsAndTask(); + + /* Now jump to real mode */ + HalpBiosCall(); + + /* Restore kernel trap handlers */ + HalpRestoreTrapHandlers(); + + /* Restore write permission */ + IdtPte->Write = RestoreWriteProtection; + + /* Restore TSS and IOPM */ + HalpRestoreIoPermissionsAndTask(); + + /* Restore low memory mapping */ + HalpUnmapRealModeMemory(); + + /* Restore interrupts if they were previously enabled */ + __writeeflags(Flags); + return TRUE; +} + +/* EOF */ diff --git a/hal/halacpi/generic/i386/portio.c b/hal/halacpi/generic/i386/portio.c new file mode 100644 index 0000000000000..92f7e6f7ca9a9 --- /dev/null +++ b/hal/halacpi/generic/i386/portio.c @@ -0,0 +1,119 @@ +/* + * PROJECT: ReactOS HAL + * LICENSE: GPL - See COPYING in the top level directory + * FILE: hal/halx86/generic/portio.c + * PURPOSE: I/O Functions for access to ports + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include +#define NDEBUG +#include + +/* HAL Port to Inlined Port */ +#define H2I(Port) PtrToUshort(Port) + +/* FUNCTIONS *****************************************************************/ + +VOID +NTAPI +READ_PORT_BUFFER_UCHAR(IN PUCHAR Port, + OUT PUCHAR Buffer, + IN ULONG Count) +{ + __inbytestring(H2I(Port), Buffer, Count); +} + +VOID +NTAPI +READ_PORT_BUFFER_USHORT(IN PUSHORT Port, + OUT PUSHORT Buffer, + IN ULONG Count) +{ + __inwordstring(H2I(Port), Buffer, Count); +} + +VOID +NTAPI +READ_PORT_BUFFER_ULONG(IN PULONG Port, + OUT PULONG Buffer, + IN ULONG Count) +{ + __indwordstring(H2I(Port), Buffer, Count); +} + +UCHAR +NTAPI +READ_PORT_UCHAR(IN PUCHAR Port) +{ + return __inbyte(H2I(Port)); +} + +USHORT +NTAPI +READ_PORT_USHORT(IN PUSHORT Port) +{ + return __inword(H2I(Port)); +} + +ULONG +NTAPI +READ_PORT_ULONG(IN PULONG Port) +{ + return __indword(H2I(Port)); +} + +VOID +NTAPI +WRITE_PORT_BUFFER_UCHAR(IN PUCHAR Port, + IN PUCHAR Buffer, + IN ULONG Count) +{ + __outbytestring(H2I(Port), Buffer, Count); +} + +VOID +NTAPI +WRITE_PORT_BUFFER_USHORT(IN PUSHORT Port, + IN PUSHORT Buffer, + IN ULONG Count) +{ + __outwordstring(H2I(Port), Buffer, Count); +} + +VOID +NTAPI +WRITE_PORT_BUFFER_ULONG(IN PULONG Port, + IN PULONG Buffer, + IN ULONG Count) +{ + __outdwordstring(H2I(Port), Buffer, Count); +} + +VOID +NTAPI +WRITE_PORT_UCHAR(IN PUCHAR Port, + IN UCHAR Value) +{ + __outbyte(H2I(Port), Value); +} + +VOID +NTAPI +WRITE_PORT_USHORT(IN PUSHORT Port, + IN USHORT Value) +{ + __outword(H2I(Port), Value); +} + +VOID +NTAPI +WRITE_PORT_ULONG(IN PULONG Port, + IN ULONG Value) +{ + __outdword(H2I(Port), Value); +} + +/* EOF */ diff --git a/hal/halacpi/generic/memory.c b/hal/halacpi/generic/memory.c new file mode 100644 index 0000000000000..76343dab62364 --- /dev/null +++ b/hal/halacpi/generic/memory.c @@ -0,0 +1,262 @@ + +/* INCLUDES ******************************************************************/ + +#include +//#define NDEBUG +#include + +/* Share with Mm headers? */ +#define MM_HAL_HEAP_START (PVOID)(MM_HAL_VA_START + (1024 * 1024)) + +/* GLOBALS *******************************************************************/ + +ULONG HalpUsedAllocDescriptors; +MEMORY_ALLOCATION_DESCRIPTOR HalpAllocationDescriptorArray[64]; +PVOID HalpHeapStart = MM_HAL_HEAP_START; + +/* PRIVATE FUNCTIONS *********************************************************/ + +CODE_SEG("INIT") +ULONG_PTR +NTAPI +HalpAllocPhysicalMemory(IN PLOADER_PARAMETER_BLOCK LoaderBlock, + IN ULONG MaxAddress, + IN PFN_NUMBER PageCount, + IN BOOLEAN Aligned) +{ + ULONG UsedDescriptors; + ULONG64 PhysicalAddress; + PFN_NUMBER MaxPage, BasePage, Alignment; + PLIST_ENTRY NextEntry; + PMEMORY_ALLOCATION_DESCRIPTOR MdBlock, NewBlock, FreeBlock; + + /* Highest page we'll go */ + MaxPage = MaxAddress >> PAGE_SHIFT; + + /* We need at least two blocks */ + if ((HalpUsedAllocDescriptors + 2) > 64) + return 0; + + /* Remember how many we have now */ + UsedDescriptors = HalpUsedAllocDescriptors; + + /* Loop the loader block memory descriptors */ + NextEntry = LoaderBlock->MemoryDescriptorListHead.Flink; + + while (NextEntry != &LoaderBlock->MemoryDescriptorListHead) + { + /* Get the block */ + MdBlock = CONTAINING_RECORD(NextEntry, MEMORY_ALLOCATION_DESCRIPTOR, ListEntry); + + /* No alignment by default */ + Alignment = 0; + + /* Unless requested, in which case we use a 64KB block alignment */ + if (Aligned) + Alignment = ((MdBlock->BasePage + 0x0F) & ~0x0F) - MdBlock->BasePage; + + /* Search for free memory */ + if ((MdBlock->MemoryType == LoaderFree) || + (MdBlock->MemoryType == LoaderFirmwareTemporary)) + { + /* Make sure the page is within bounds, including alignment */ + BasePage = MdBlock->BasePage; + + if ((BasePage) && + (MdBlock->PageCount >= (PageCount + Alignment)) && + ((BasePage + PageCount + Alignment) < MaxPage)) + { + /* We found an address */ + PhysicalAddress = (ULONG_PTR)(BasePage + Alignment) << PAGE_SHIFT; + break; + } + } + + /* Keep trying */ + NextEntry = NextEntry->Flink; + } + + /* If we didn't find anything, get out of here */ + if (NextEntry == &LoaderBlock->MemoryDescriptorListHead) + return 0; + + /* Okay, now get a descriptor */ + NewBlock = &HalpAllocationDescriptorArray[HalpUsedAllocDescriptors]; + NewBlock->PageCount = (ULONG)PageCount; + NewBlock->BasePage = (MdBlock->BasePage + Alignment); + NewBlock->MemoryType = LoaderHALCachedMemory; + + /* Update count */ + UsedDescriptors++; + HalpUsedAllocDescriptors = UsedDescriptors; + + /* Check if we had any alignment */ + if (Alignment) + { + /* Check if we had leftovers */ + if (MdBlock->PageCount > (PageCount + Alignment)) + { + /* Get the next descriptor */ + FreeBlock = &HalpAllocationDescriptorArray[UsedDescriptors]; + FreeBlock->PageCount = (MdBlock->PageCount - Alignment - (ULONG)PageCount); + FreeBlock->BasePage = (MdBlock->BasePage + Alignment + (ULONG)PageCount); + + /* One more */ + HalpUsedAllocDescriptors++; + + /* Insert it into the list */ + InsertHeadList(&MdBlock->ListEntry, &FreeBlock->ListEntry); + } + + /* Trim the original block to the alignment only */ + MdBlock->PageCount = Alignment; + + /* Insert the descriptor after the original one */ + InsertHeadList(&MdBlock->ListEntry, &NewBlock->ListEntry); + } + else + { + /* Consume memory from this block */ + MdBlock->BasePage += (ULONG)PageCount; + MdBlock->PageCount -= (ULONG)PageCount; + + /* Insert the descriptor before the original one */ + InsertTailList(&MdBlock->ListEntry, &NewBlock->ListEntry); + + /* Remove the entry if the whole block was allocated */ + if (MdBlock->PageCount == 0) + RemoveEntryList(&MdBlock->ListEntry); + } + + /* Return the address */ + return PhysicalAddress; +} + +PVOID +NTAPI +HalpMapPhysicalMemory64(IN PHYSICAL_ADDRESS PhysicalAddress, + IN PFN_COUNT PageCount) +{ + PHARDWARE_PTE PointerPte; + PFN_NUMBER UsedPages = 0; + PVOID VirtualAddress, BaseAddress; + + /* Start at the current HAL heap base */ + BaseAddress = HalpHeapStart; + VirtualAddress = BaseAddress; + + /* Loop until we have all the pages required */ + while (UsedPages < PageCount) + { + /* If this overflows past the HAL heap, it means there's no space */ + if (VirtualAddress == NULL) + return NULL; + + /* Get the PTE for this address */ + PointerPte = HalAddressToPte(VirtualAddress); + + /* Go to the next page */ + VirtualAddress = (PVOID)((ULONG_PTR)VirtualAddress + PAGE_SIZE); + + /* Check if the page is available */ + if (PointerPte->Valid) + { + /* PTE has data, skip it and start with a new base address */ + BaseAddress = VirtualAddress; + UsedPages = 0; + continue; + } + + /* PTE is available, keep going on this run */ + UsedPages++; + } + + /* Take the base address of the page plus the actual offset in the address */ + VirtualAddress = (PVOID)((ULONG_PTR)BaseAddress + BYTE_OFFSET(PhysicalAddress.LowPart)); + + /* If we are starting at the heap, move the heap */ + if (BaseAddress == HalpHeapStart) + { + /* Past this allocation */ + HalpHeapStart = (PVOID)((ULONG_PTR)BaseAddress + (PageCount * PAGE_SIZE)); + } + + /* Loop pages that can be mapped */ + while (UsedPages--) + { + /* Fill out the PTE */ + PointerPte = HalAddressToPte(BaseAddress); + PointerPte->PageFrameNumber = (PFN_NUMBER)(PhysicalAddress.QuadPart >> PAGE_SHIFT); + PointerPte->Valid = 1; + PointerPte->Write = 1; + + /* Move to the next address */ + PhysicalAddress.QuadPart += PAGE_SIZE; + BaseAddress = (PVOID)((ULONG_PTR)BaseAddress + PAGE_SIZE); + } + + /* Flush the TLB and return the address */ + HalpFlushTLB(); + + return VirtualAddress; +} + +VOID +NTAPI +HalpUnmapVirtualAddress(IN PVOID VirtualAddress, + IN PFN_COUNT PageCount) +{ + PHARDWARE_PTE PointerPte; + ULONG ix; + + /* Only accept valid addresses */ + if (VirtualAddress < (PVOID)MM_HAL_VA_START) + return; + + /* Align it down to page size */ + VirtualAddress = (PVOID)((ULONG_PTR)VirtualAddress & ~(PAGE_SIZE - 1)); + + /* Loop PTEs */ + PointerPte = HalAddressToPte(VirtualAddress); + + for (ix = 0; ix < PageCount; ix++) + { + *(PULONG)PointerPte = 0; + PointerPte++; + } + + /* Flush the TLB */ + HalpFlushTLB(); + + /* Put the heap back */ + if (HalpHeapStart > VirtualAddress) + HalpHeapStart = VirtualAddress; +} + +PVOID +NTAPI +HalpMapPhysicalMemoryWriteThrough64( + _In_ PHYSICAL_ADDRESS PhysicalAddress, + _In_ PFN_COUNT PageCount) +{ + PVOID VirtualAddress; + PHARDWARE_PTE Pte; + ULONG ix; + + VirtualAddress = HalpMapPhysicalMemory64(PhysicalAddress, PageCount); + + /* Get the PTE for this address */ + Pte = HalAddressToPte(VirtualAddress); + + for (ix = 0; ix < PageCount; ix++) + { + Pte->CacheDisable = 1; + Pte->WriteThrough = 1; + + Pte++; + } + + return VirtualAddress; +} + +/* EOF */ diff --git a/hal/halacpi/generic/misc.c b/hal/halacpi/generic/misc.c new file mode 100644 index 0000000000000..a897a990df259 --- /dev/null +++ b/hal/halacpi/generic/misc.c @@ -0,0 +1,95 @@ + +/* INCLUDES *******************************************************************/ + +#include +//#define NDEBUG +#include + +/* GLOBALS *******************************************************************/ + + +/* PRIVATE FUNCTIONS **********************************************************/ + +VOID +NTAPI +HalpFlushTLB(VOID) +{ + ULONG_PTR Flags, Cr4; + INT CpuInfo[4]; + ULONG_PTR PageDirectory; + + /* Disable interrupts */ + Flags = __readeflags(); + _disable(); + + /* Get page table directory base */ + PageDirectory = __readcr3(); + + /* Check for CPUID support */ + if (KeGetCurrentPrcb()->CpuID) + { + /* Check for global bit in CPU features */ + __cpuid(CpuInfo, 1); + + if (CpuInfo[3] & 0x2000) + { + /* Get current CR4 value */ + Cr4 = __readcr4(); + + /* Disable global bit */ + __writecr4(Cr4 & ~CR4_PGE); + + /* Flush TLB and re-enable global bit */ + __writecr3(PageDirectory); + __writecr4(Cr4); + + /* Restore interrupts */ + __writeeflags(Flags); + return; + } + } + + /* Legacy: just flush TLB */ + __writecr3(PageDirectory); + __writeeflags(Flags); +} + +NTSTATUS +NTAPI +HalpOpenRegistryKey(IN PHANDLE KeyHandle, + IN HANDLE RootKey, + IN PUNICODE_STRING KeyName, + IN ACCESS_MASK DesiredAccess, + IN BOOLEAN Create) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + ULONG Disposition; + + /* Setup the attributes we received */ + InitializeObjectAttributes(&ObjectAttributes, KeyName, OBJ_CASE_INSENSITIVE, RootKey, NULL); + + if (!Create) + { + /* Open the key */ + return ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes); + } + + /* Create the key */ + return ZwCreateKey(KeyHandle, DesiredAccess, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, &Disposition); +} + +/* PUBLIC FUNCTIONS **********************************************************/ + +VOID +NTAPI +HalHandleNMI(IN PVOID NmiInfo) +{ + UNIMPLEMENTED; + ASSERT(0);//HalpDbgBreakPointEx(); + + /* Freeze the system */ + while (TRUE); +} + + +/* EOF */ diff --git a/hal/halacpi/generic/reboot.c b/hal/halacpi/generic/reboot.c new file mode 100644 index 0000000000000..ab8b43bd6c453 --- /dev/null +++ b/hal/halacpi/generic/reboot.c @@ -0,0 +1,91 @@ + +/* INCLUDES ******************************************************************/ + +#include +//#define NDEBUG +#include + +/* PRIVATE FUNCTIONS *********************************************************/ + +VOID +NTAPI +HalpReboot(VOID) +{ + PHYSICAL_ADDRESS PhysicalAddress; + UCHAR Data; + PVOID ZeroPageMapping; + + DPRINT("HalpReboot()\n"); + + /* Map the first physical page */ + PhysicalAddress.QuadPart = 0; + ZeroPageMapping = HalpMapPhysicalMemoryWriteThrough64(PhysicalAddress, 1); + + /* Enable warm reboot */ + ((PUSHORT)ZeroPageMapping)[0x239] = 0x1234; + + /* Lock CMOS Access (and disable interrupts) */ + HalpAcquireCmosSpinLock(); + + /* Setup control register B */ + WRITE_PORT_UCHAR(CMOS_CONTROL_PORT, 0x0B); + KeStallExecutionProcessor(1); + + /* Read periodic register and clear the interrupt enable */ + Data = READ_PORT_UCHAR(CMOS_DATA_PORT); + KeStallExecutionProcessor(1); + WRITE_PORT_UCHAR(CMOS_DATA_PORT, Data & ~0x40); + KeStallExecutionProcessor(1); + + /* Setup control register A */ + WRITE_PORT_UCHAR(CMOS_CONTROL_PORT, 0x0A); + KeStallExecutionProcessor(1); + + /* Read divider rate and reset it */ + Data = READ_PORT_UCHAR(CMOS_DATA_PORT); + KeStallExecutionProcessor(1); + WRITE_PORT_UCHAR(CMOS_DATA_PORT, (Data & ~0x9) | 0x06); + KeStallExecutionProcessor(1); + + /* Reset neutral CMOS address */ + WRITE_PORT_UCHAR(CMOS_CONTROL_PORT, 0x15); + KeStallExecutionProcessor(1); + + /* Flush write buffers and send the reset command */ + KeFlushWriteBuffer(); + + DPRINT("HalpReboot: FIXME HalpResetAllProcessors()\n"); + //HalpResetAllProcessors(); + + HalpWriteResetCommand(); + + /* Halt the CPU */ + __halt(); +} + +/* PUBLIC FUNCTIONS **********************************************************/ + +VOID +NTAPI +HalReturnToFirmware(IN FIRMWARE_REENTRY Action) +{ + DPRINT("HalReturnToFirmware: Action %X\n", Action); + + /* Check what kind of action this is */ + switch (Action) + { + /* All recognized actions */ + case HalHaltRoutine: + case HalPowerDownRoutine: + case HalRestartRoutine: + case HalRebootRoutine: + /* Call the internal reboot function */ + HalpReboot(); + + default: + DPRINT1("HalReturnToFirmware: Unknown Action %X\n", Action); + ASSERT(FALSE); // HalpDbgBreakPointEx(); + } +} + +/* EOF */ diff --git a/hal/halacpi/generic/spinlock.c b/hal/halacpi/generic/spinlock.c new file mode 100644 index 0000000000000..8ad23501f2f50 --- /dev/null +++ b/hal/halacpi/generic/spinlock.c @@ -0,0 +1,256 @@ + +/* INCLUDES ******************************************************************/ + +/* This file is compiled twice. Once for UP and once for MP */ + +#include +//#define NDEBUG +#include + +#include + +#undef KeAcquireSpinLock +#undef KeReleaseSpinLock + +/* GLOBALS *******************************************************************/ + +ULONG_PTR HalpSystemHardwareFlags; +KSPIN_LOCK HalpSystemHardwareLock; + +/* FUNCTIONS *****************************************************************/ + +VOID +NTAPI +HalpAcquireCmosSpinLock(VOID) +{ + ULONG_PTR Flags; + + /* Get flags and disable interrupts */ + Flags = __readeflags(); + _disable(); + + /* Acquire the lock */ + KxAcquireSpinLock(&HalpSystemHardwareLock); + + /* We have the lock, save the flags now */ + HalpSystemHardwareFlags = Flags; +} + +VOID +NTAPI +HalpReleaseCmosSpinLock(VOID) +{ + ULONG_PTR Flags; + + /* Get the flags */ + Flags = HalpSystemHardwareFlags; + + /* Release the lock */ + KxReleaseSpinLock(&HalpSystemHardwareLock); + + /* Restore the flags */ + __writeeflags(Flags); +} + +KIRQL +FASTCALL +KfAcquireSpinLock(PKSPIN_LOCK SpinLock) +{ + KIRQL OldIrql; + + /* Raise to dispatch and acquire the lock */ + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + KxAcquireSpinLock(SpinLock); + return OldIrql; +} + +VOID +FASTCALL +KfReleaseSpinLock(PKSPIN_LOCK SpinLock, + KIRQL OldIrql) +{ + /* Release the lock and lower IRQL back */ + KxReleaseSpinLock(SpinLock); + KeLowerIrql(OldIrql); +} + +/* PUBLIC FUNCTIONS **********************************************************/ + +VOID +FASTCALL +KeAcquireInStackQueuedSpinLock(IN PKSPIN_LOCK SpinLock, + IN PKLOCK_QUEUE_HANDLE LockHandle) +{ + /* Set up the lock */ + LockHandle->LockQueue.Next = NULL; + LockHandle->LockQueue.Lock = SpinLock; + + /* Raise to dispatch */ + KeRaiseIrql(DISPATCH_LEVEL, &LockHandle->OldIrql); + + /* Acquire the lock */ + KxAcquireSpinLock(LockHandle->LockQueue.Lock); // HACK +} + +VOID +FASTCALL +KeAcquireInStackQueuedSpinLockRaiseToSynch(IN PKSPIN_LOCK SpinLock, + IN PKLOCK_QUEUE_HANDLE LockHandle) +{ + /* Set up the lock */ + LockHandle->LockQueue.Next = NULL; + LockHandle->LockQueue.Lock = SpinLock; + + /* Raise to synch */ + KeRaiseIrql(SYNCH_LEVEL, &LockHandle->OldIrql); + + /* Acquire the lock */ + KxAcquireSpinLock(LockHandle->LockQueue.Lock); // HACK +} + +KIRQL +FASTCALL +KeAcquireQueuedSpinLock(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber) +{ + KIRQL OldIrql; + + /* Raise to dispatch */ + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + /* Acquire the lock */ + KxAcquireSpinLock(KeGetCurrentPrcb()->LockQueue[LockNumber].Lock); // HACK + return OldIrql; +} + +KIRQL +FASTCALL +KeAcquireQueuedSpinLockRaiseToSynch(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber) +{ + KIRQL OldIrql; + + /* Raise to synch */ + KeRaiseIrql(SYNCH_LEVEL, &OldIrql); + + /* Acquire the lock */ + KxAcquireSpinLock(KeGetCurrentPrcb()->LockQueue[LockNumber].Lock); // HACK + return OldIrql; +} + +KIRQL +FASTCALL +KeAcquireSpinLockRaiseToSynch(PKSPIN_LOCK SpinLock) +{ + KIRQL OldIrql; + + /* Raise to sync */ + KeRaiseIrql(SYNCH_LEVEL, &OldIrql); + + /* Acquire the lock and return */ + KxAcquireSpinLock(SpinLock); + return OldIrql; +} + +VOID +FASTCALL +KeReleaseInStackQueuedSpinLock(IN PKLOCK_QUEUE_HANDLE LockHandle) +{ + /* Simply lower IRQL back */ + KxReleaseSpinLock(LockHandle->LockQueue.Lock); // HACK + KeLowerIrql(LockHandle->OldIrql); +} + +VOID +FASTCALL +KeReleaseQueuedSpinLock(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber, + IN KIRQL OldIrql) +{ + /* Release the lock */ + KxReleaseSpinLock(KeGetCurrentPrcb()->LockQueue[LockNumber].Lock); // HACK + + /* Lower IRQL back */ + KeLowerIrql(OldIrql); +} + +LOGICAL +FASTCALL +KeTryToAcquireQueuedSpinLock(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber, + OUT PKIRQL OldIrql) +{ +#ifdef CONFIG_SMP + ERROR_DBGBREAK("FIXME: Unused\n"); // FIXME: Unused + return FALSE; +#endif + + /* Simply raise to dispatch */ + KeRaiseIrql(DISPATCH_LEVEL, OldIrql); + + /* Add an explicit memory barrier to prevent the compiler from reordering + memory accesses across the borders of spinlocks + */ + KeMemoryBarrierWithoutFence(); + + /* Always return true on UP Machines */ + return TRUE; +} + +BOOLEAN +FASTCALL +KeTryToAcquireQueuedSpinLockRaiseToSynch(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber, + IN PKIRQL OldIrql) +{ +#ifdef CONFIG_SMP + ERROR_DBGBREAK("FIXME: Unused\n"); // FIXME: Unused + return FALSE; +#endif + + /* Simply raise to synch */ + KeRaiseIrql(SYNCH_LEVEL, OldIrql); + + /* Add an explicit memory barrier to prevent the compiler from reordering + memory accesses across the borders of spinlocks */ + KeMemoryBarrierWithoutFence(); + + /* Always return true on UP Machines */ + return TRUE; +} + +#undef KeAcquireSpinLock +VOID +NTAPI +KeAcquireSpinLock(PKSPIN_LOCK SpinLock, + PKIRQL OldIrql) +{ + /* Call the fastcall function */ + *OldIrql = KfAcquireSpinLock(SpinLock); +} + +#undef KeLowerIrql +VOID +NTAPI +KeLowerIrql(KIRQL NewIrql) +{ + /* Call the fastcall function */ + KfLowerIrql(NewIrql); +} + +#undef KeRaiseIrql +VOID +NTAPI +KeRaiseIrql(KIRQL NewIrql, + PKIRQL OldIrql) +{ + /* Call the fastcall function */ + *OldIrql = KfRaiseIrql(NewIrql); +} + +#undef KeReleaseSpinLock +VOID +NTAPI +KeReleaseSpinLock(PKSPIN_LOCK SpinLock, + KIRQL NewIrql) +{ + /* Call the fastcall function */ + KfReleaseSpinLock(SpinLock, NewIrql); +} + +/* EOF */ diff --git a/hal/halacpi/generic/sysinfo.c b/hal/halacpi/generic/sysinfo.c new file mode 100644 index 0000000000000..9b00fd19e470e --- /dev/null +++ b/hal/halacpi/generic/sysinfo.c @@ -0,0 +1,163 @@ + +/* INCLUDES *******************************************************************/ + +#include +//#define NDEBUG +#include + + +typedef +NTSTATUS +(NTAPI * PHALP_AMLI_ILLEGAL_IO_PORT_HANDLER)( + BOOLEAN IsRead, + ULONG Port, + ULONG Length, + PVOID Buffer +); + +typedef struct _AMLI_ILLEGAL_IO_PORT_ADDRESSES +{ + ULONG Start; + ULONG Length; + ULONG Param; + PHALP_AMLI_ILLEGAL_IO_PORT_HANDLER Handler; +} AMLI_ILLEGAL_IO_PORT_ADDRESSES, *PAMLI_ILLEGAL_IO_PORT_ADDRESSES; + +NTSTATUS +NTAPI +HaliHandlePCIConfigSpaceAccess( + BOOLEAN IsRead, + ULONG Port, + ULONG Length, + PVOID Buffer +); + +AMLI_ILLEGAL_IO_PORT_ADDRESSES AMLIIllegalIOPortAddresses[19] = +{ + { 0x0000, 0x10, 1, NULL }, + { 0x0020, 0x02, 0, NULL }, + { 0x0040, 0x04, 1, NULL }, + { 0x0048, 0x04, 1, NULL }, + { 0x0070, 0x02, 1, NULL }, + { 0x0074, 0x03, 1, NULL }, + { 0x0081, 0x03, 1, NULL }, + { 0x0087, 0x01, 1, NULL }, + { 0x0089, 0x01, 1, NULL }, + { 0x008A, 0x02, 1, NULL }, + { 0x008F, 0x01, 1, NULL }, + { 0x0090, 0x02, 1, NULL }, + { 0x0093, 0x02, 1, NULL }, + { 0x0096, 0x02, 1, NULL }, + { 0x00A0, 0x02, 0, NULL }, + { 0x00C0, 0x20, 1, NULL }, + { 0x04D0, 0x02, 0, NULL }, + { 0x0CF8, 0x08, 1, &HaliHandlePCIConfigSpaceAccess }, + { 0x0000, 0x00, 0, NULL } +}; + +/* FUNCTIONS ******************************************************************/ + +NTSTATUS +NTAPI +HaliHandlePCIConfigSpaceAccess(BOOLEAN IsRead, + ULONG Port, + ULONG Length, + PVOID Buffer) +{ + UNIMPLEMENTED; + ASSERT(0);//HalpDbgBreakPointEx(); + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +HaliQuerySystemInformation(IN HAL_QUERY_INFORMATION_CLASS InformationClass, + IN ULONG BufferSize, + IN OUT PVOID Buffer, + OUT PULONG ReturnedLength) +{ + ULONG Size; + PVOID LocalBuffer; + NTSTATUS Status; + + DPRINT1("HaliQuerySystemInformation: %X, %X\n", InformationClass, BufferSize); + +#define REPORT_THIS_CASE(Class) case Class: DPRINT1("FIXME: %s\n", #Class); break + + switch (InformationClass) + { + case HalQueryAMLIIllegalIOPortAddresses: + { + DPRINT1("HalQueryAMLIIllegalIOPortAddresses\n"); + Size = sizeof(AMLIIllegalIOPortAddresses); + + if (BufferSize < Size) { + *ReturnedLength = Size; + Status = STATUS_INFO_LENGTH_MISMATCH; + goto Exit; + } + + Status = 0; + LocalBuffer = AMLIIllegalIOPortAddresses; + + if (Size > BufferSize) + Size = BufferSize; + + *ReturnedLength = Size; + RtlCopyMemory(Buffer, LocalBuffer, Size); + +Exit: + //KeFlushWriteBuffer(); + return Status; + } + REPORT_THIS_CASE(HalInstalledBusInformation); + REPORT_THIS_CASE(HalProfileSourceInformation); + REPORT_THIS_CASE(HalInformationClassUnused1); + REPORT_THIS_CASE(HalPowerInformation); + REPORT_THIS_CASE(HalProcessorSpeedInformation); + REPORT_THIS_CASE(HalCallbackInformation); + REPORT_THIS_CASE(HalMapRegisterInformation); + REPORT_THIS_CASE(HalMcaLogInformation); + case HalFrameBufferCachingInformation: + { + /* FIXME: TODO */ + return STATUS_NOT_IMPLEMENTED; + } + REPORT_THIS_CASE(HalDisplayBiosInformation); + REPORT_THIS_CASE(HalProcessorFeatureInformation); + REPORT_THIS_CASE(HalNumaTopologyInterface); + REPORT_THIS_CASE(HalErrorInformation); + REPORT_THIS_CASE(HalCmcLogInformation); + REPORT_THIS_CASE(HalCpeLogInformation); + REPORT_THIS_CASE(HalQueryMcaInterface); + REPORT_THIS_CASE(HalQueryMaxHotPlugMemoryAddress); + REPORT_THIS_CASE(HalPartitionIpiInterface); + REPORT_THIS_CASE(HalPlatformInformation); + REPORT_THIS_CASE(HalQueryProfileSourceList); + REPORT_THIS_CASE(HalInitLogInformation); + REPORT_THIS_CASE(HalFrequencyInformation); + REPORT_THIS_CASE(HalProcessorBrandString); + REPORT_THIS_CASE(HalHypervisorInformation); + REPORT_THIS_CASE(HalPlatformTimerInformation); + REPORT_THIS_CASE(HalAcpiAuditInformation); + } + +#undef REPORT_THIS_CASE + + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +NTAPI +HaliSetSystemInformation(IN HAL_SET_INFORMATION_CLASS InformationClass, + IN ULONG BufferSize, + IN OUT PVOID Buffer) +{ + DPRINT1("HaliSetSystemInformation: InformationClass %X, Size %X\n", InformationClass, BufferSize); + UNIMPLEMENTED; + ASSERT(0);//HalpDbgBreakPointEx(); + return STATUS_NOT_IMPLEMENTED; +} + +/* EOF */ diff --git a/hal/halacpi/generic/usage.c b/hal/halacpi/generic/usage.c new file mode 100644 index 0000000000000..f89b43d31db13 --- /dev/null +++ b/hal/halacpi/generic/usage.c @@ -0,0 +1,561 @@ + +/* INCLUDES *******************************************************************/ + +#include +//#define NDEBUG +#include + +#if defined(ALLOC_PRAGMA) && !defined(_MINIHAL_) + #pragma alloc_text(INIT, HalpBuildPartialFromIdt) + #pragma alloc_text(INIT, HalpBuildPartialFromAddress) + #pragma alloc_text(INIT, HalpRegisterVector) + #pragma alloc_text(INIT, HalpReportResourceUsage) +#endif + +/* GLOBALS ********************************************************************/ + +/* This determines the HAL type */ +BOOLEAN HalDisableFirmwareMapper = TRUE; + +PUCHAR KdComPortInUse; +BOOLEAN HalpGetInfoFromACPI; + +IDTUsageFlags HalpIDTUsageFlags[MAXIMUM_IDTVECTOR + 1]; +IDTUsage HalpIDTUsage[MAXIMUM_IDTVECTOR + 1]; + +USHORT HalpComPortIrqMapping[5][2] = +{ + {0x03F8, 0x0004}, + {0x02F8, 0x0003}, + {0x03E8, 0x0004}, + {0x02E8, 0x0003}, + {0x0000, 0x0000} +}; + +ADDRESS_USAGE HalpComIoSpace = +{ + NULL, CmResourceTypePort, IDT_DEVICE, // 0x21 + { + {0x000002F8, 0x00000008}, /* COM 1 */ + {0x00000000, 0x00000000}, + } +}; + +PADDRESS_USAGE HalpAddressUsageList; + +UCHAR HalpSerialLen; +CHAR HalpSerialNumber[31]; + +extern KAFFINITY HalpActiveProcessors; + +/* FUNCTIONS ******************************************************************/ + +static +NTSTATUS +HalpMarkAcpiHal(VOID) +{ + NTSTATUS Status; + UNICODE_STRING KeyString; + HANDLE KeyHandle; + HANDLE Handle; + ULONG Value = (HalDisableFirmwareMapper ? 1 : 0); + + /* Open the control set key */ + RtlInitUnicodeString(&KeyString, L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET"); + + Status = HalpOpenRegistryKey(&Handle, 0, &KeyString, KEY_ALL_ACCESS, FALSE); + if (!NT_SUCCESS(Status)) + { + DPRINT1("HalpMarkAcpiHal: Status %X\n", Status); + return Status; + } + + /* Open the PNP key */ + RtlInitUnicodeString(&KeyString, L"Control\\Pnp"); + Status = HalpOpenRegistryKey(&KeyHandle, Handle, &KeyString, KEY_ALL_ACCESS, TRUE); + + /* Close root key */ + ZwClose(Handle); + + /* Check if PNP BIOS key exists */ + if (!NT_SUCCESS(Status)) + { + DPRINT1("HalpMarkAcpiHal: Status %X\n", Status); + return Status; + } + + /* Set the disable value to false -- we need the mapper */ + RtlInitUnicodeString(&KeyString, L"DisableFirmwareMapper"); + Status = ZwSetValueKey(KeyHandle, &KeyString, 0, REG_DWORD, &Value, sizeof(Value)); + + /* Close subkey */ + ZwClose(KeyHandle); + + if (!NT_SUCCESS(Status)) + DPRINT1("HalpMarkAcpiHal: Status %X\n", Status); + + /* Return status */ + return Status; +} + +static +VOID +HalpReportSerialNumber(VOID) +{ + UNICODE_STRING KeyString; + HANDLE Handle; + NTSTATUS Status; + + /* Make sure there is a serial number */ + if (!HalpSerialLen) + return; + + /* Open the system key */ + RtlInitUnicodeString(&KeyString, L"\\Registry\\Machine\\Hardware\\Description\\System"); + + Status = HalpOpenRegistryKey(&Handle, 0, &KeyString, KEY_ALL_ACCESS, FALSE); + if (!NT_SUCCESS(Status)) + { + DPRINT1("HalpReportSerialNumber: Status %X\n", Status); + return; + } + + /* Add the serial number */ + RtlInitUnicodeString(&KeyString, L"Serial Number"); + ZwSetValueKey(Handle, &KeyString, 0, REG_BINARY, HalpSerialNumber, HalpSerialLen); + + /* Close the handle */ + ZwClose(Handle); +} + +CODE_SEG("INIT") +VOID +NTAPI +HalpRegisterVector(IN UCHAR Flags, + IN ULONG BusVector, + IN ULONG SystemVector, + IN KIRQL Irql) +{ + DPRINT("HalpRegisterVector: %X, %X, %X, %X\n", Flags, BusVector, SystemVector, Irql); + + /* Save the vector flags */ + HalpIDTUsageFlags[SystemVector].Flags = Flags; + + /* Save the vector data */ + HalpIDTUsage[SystemVector].Irql = Irql; + HalpIDTUsage[SystemVector].BusReleativeVector = (UCHAR)BusVector; +} + +CODE_SEG("INIT") +VOID +NTAPI +HalpBuildPartialFromIdt(IN ULONG Entry, + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR RawDescriptor, + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR TranslatedDescriptor) +{ + /* Exclusive interrupt entry */ + RawDescriptor->Type = CmResourceTypeInterrupt; + RawDescriptor->ShareDisposition = CmResourceShareDriverExclusive; + + /* Check the interrupt type */ + if (HalpIDTUsageFlags[Entry].Flags & IDT_LATCHED) + RawDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED; + else + RawDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; + + /* Get vector and level from IDT usage */ + RawDescriptor->u.Interrupt.Vector = HalpIDTUsage[Entry].BusReleativeVector; + RawDescriptor->u.Interrupt.Level = HalpIDTUsage[Entry].BusReleativeVector; + + /* Affinity is all the CPUs */ + RawDescriptor->u.Interrupt.Affinity = HalpActiveProcessors; + + /* The translated copy is identical */ + RtlCopyMemory(TranslatedDescriptor, RawDescriptor, sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)); + + /* But the vector and IRQL must be set correctly */ + TranslatedDescriptor->u.Interrupt.Vector = Entry; + TranslatedDescriptor->u.Interrupt.Level = HalpIDTUsage[Entry].Irql; +} + +CODE_SEG("INIT") +VOID +NTAPI +HalpBuildPartialFromAddress(IN INTERFACE_TYPE Interface, + IN PADDRESS_USAGE CurrentAddress, + IN ULONG Element, + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR RawDescriptor, + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR TranslatedDescriptor) +{ + ULONG AddressSpace; + + /* Set the type and make it exclusive */ + RawDescriptor->Type = CurrentAddress->Type; + RawDescriptor->ShareDisposition = CmResourceShareDriverExclusive; + + /* Check what this is */ + if (RawDescriptor->Type == CmResourceTypePort) + { + /* Write out port data */ + AddressSpace = 1; + RawDescriptor->u.Port.Start.HighPart = 0; + RawDescriptor->u.Port.Start.LowPart = CurrentAddress->Element[Element].Start; + RawDescriptor->u.Port.Length = CurrentAddress->Element[Element].Length; + RawDescriptor->Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE; + } + else + { + /* Write out memory data */ + AddressSpace = 0; + RawDescriptor->u.Memory.Start.HighPart = 0; + RawDescriptor->u.Memory.Start.LowPart = CurrentAddress->Element[Element].Start; + RawDescriptor->u.Memory.Length = CurrentAddress->Element[Element].Length; + + if (CurrentAddress->Flags & IDT_READ_ONLY) + RawDescriptor->Flags = CM_RESOURCE_MEMORY_READ_ONLY; + else + RawDescriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE; + } + + /* Make an identical copy to begin with */ + RtlCopyMemory(TranslatedDescriptor, RawDescriptor, sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)); + + /* Check what this is */ + if (RawDescriptor->Type != CmResourceTypePort) + { + /* Translate the memory */ + HalTranslateBusAddress(Interface, + 0, + RawDescriptor->u.Memory.Start, + &AddressSpace, + &TranslatedDescriptor->u.Memory.Start); + return; + } + + /* Translate the port */ + HalTranslateBusAddress(Interface, + 0, + RawDescriptor->u.Port.Start, + &AddressSpace, + &TranslatedDescriptor->u.Port.Start); + + /* If it turns out this is memory once translated, flag it */ + if (AddressSpace == 0) + TranslatedDescriptor->Flags = CM_RESOURCE_PORT_MEMORY; +} + +static +VOID +HalpAddDescriptors(IN PCM_PARTIAL_RESOURCE_LIST List, + IN OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR * Descriptor, + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR NewDescriptor) +{ + /* We have written a new partial descriptor */ + List->Count++; + + /* Copy new descriptor into the actual list */ + RtlCopyMemory(*Descriptor, NewDescriptor, sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)); + + /* Move pointer to the next partial descriptor */ + (*Descriptor)++; +} + +static +VOID +HalpGetResourceSortValue(IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor, + OUT PULONG Scale, + OUT PLARGE_INTEGER Value) +{ + /* Sorting depends on resource type */ + switch (Descriptor->Type) + { + case CmResourceTypeInterrupt: + + /* Interrupt goes by level */ + *Scale = 0; + *Value = RtlConvertUlongToLargeInteger(Descriptor->u.Interrupt.Level); + break; + + case CmResourceTypePort: + + /* Port goes by port address */ + *Scale = 1; + *Value = Descriptor->u.Port.Start; + break; + + case CmResourceTypeMemory: + + /* Memory goes by base address */ + *Scale = 2; + *Value = Descriptor->u.Memory.Start; + break; + + default: + + /* Anything else */ + *Scale = 4; + *Value = RtlConvertUlongToLargeInteger(0); + break; + } +} + +CODE_SEG("INIT") +VOID +NTAPI +HalpReportResourceUsage(IN PUNICODE_STRING HalName, + IN INTERFACE_TYPE InterfaceType) +{ + PCM_RESOURCE_LIST RawList, TranslatedList; + PCM_FULL_RESOURCE_DESCRIPTOR RawFull, TranslatedFull; + PCM_PARTIAL_RESOURCE_DESCRIPTOR CurrentRaw, CurrentTranslated, SortedRaw, SortedTranslated; + CM_PARTIAL_RESOURCE_DESCRIPTOR RawPartial, TranslatedPartial; + PCM_PARTIAL_RESOURCE_LIST RawPartialList = NULL, TranslatedPartialList = NULL; + INTERFACE_TYPE Interface; + ULONG ListSize, Count, Port, CurrentScale, SortScale, ReportType, FlagMatch; + ULONG ix, jx, kx; + ADDRESS_USAGE* CurrentAddress; + LARGE_INTEGER CurrentSortValue, SortValue; + + DPRINT1("HalpReportResourceUsage: %wZ Detected\n", HalName); + //ASSERT(0);// HalpDbgBreakPointEx(); + + /* Check if KD is using a COM port */ + if (KdComPortInUse) + { + /* Enter it into the I/O space */ + HalpComIoSpace.Element[0].Start = PtrToUlong(KdComPortInUse); + HalpComIoSpace.Next = HalpAddressUsageList; + HalpAddressUsageList = &HalpComIoSpace; + + /* Use the debug port table if we have one */ + HalpGetInfoFromACPI = HalpGetDebugPortTable(); + DPRINT1("HalpGetInfoFromACPI %X\n", HalpGetInfoFromACPI); + + /* Check if we're using ACPI */ + if (!HalpGetInfoFromACPI) + { + /* No, so use our local table */ + for (ix = 0, Port = HalpComPortIrqMapping[ix][0]; + (Port != 0); + ix++, Port = HalpComPortIrqMapping[ix][0]) + { + /* Is this the port we want? */ + if (Port == (ULONG_PTR)KdComPortInUse) + { + /* Register it */ + DPRINT1("HalpReportResourceUsage: ix - %X\n", ix); + HalpRegisterVector(IDT_DEVICE | IDT_LATCHED, + HalpComPortIrqMapping[ix][1], + HalpComPortIrqMapping[ix][1] + + PRIMARY_VECTOR_BASE, + HIGH_LEVEL); + } + } + } + } + + /* Allocate the master raw and translated lists */ + RawList = ExAllocatePoolWithTag(NonPagedPool, (2 * PAGE_SIZE), TAG_HAL); + TranslatedList = ExAllocatePoolWithTag(NonPagedPool, (2 * PAGE_SIZE), TAG_HAL); + + if (!(RawList) || !(TranslatedList)) + { + DPRINT1("HalpReportResourceUsage: HAL_MEMORY_ALLOCATION - Bugcheck the system!\n"); + KeBugCheckEx(HAL_MEMORY_ALLOCATION, 4 * PAGE_SIZE, 1, (ULONG_PTR)__FILE__, __LINE__); + } + + /* Zero out the lists */ + RtlZeroMemory(RawList, (2 * PAGE_SIZE)); + RtlZeroMemory(TranslatedList, (2 * PAGE_SIZE)); + + /* Set the interface type to begin with */ + RawList->List[0].InterfaceType = InterfaceTypeUndefined; + + /* Loop all IDT entries that are not IRQs */ + for (ix = 0; ix < PRIMARY_VECTOR_BASE; ix++) + { + /* Check if the IDT isn't owned */ + if (!(HalpIDTUsageFlags[ix].Flags & IDT_REGISTERED)) + { + /* Then register it for internal usage */ + HalpIDTUsageFlags[ix].Flags = IDT_INTERNAL; + HalpIDTUsage[ix].BusReleativeVector = (UCHAR)ix; + } + } + + /* Our full descriptors start here */ + RawFull = &RawList->List[0]; + TranslatedFull = &TranslatedList->List[0]; + + /* Do two passes */ + for (ReportType = 0; ReportType < 2; ReportType++) + { + RawList->Count++; + RawPartialList = &RawFull->PartialResourceList; + CurrentRaw = RawPartialList->PartialDescriptors; + + TranslatedList->Count++; + TranslatedPartialList = &TranslatedFull->PartialResourceList; + CurrentTranslated = TranslatedPartialList->PartialDescriptors; + + if (ReportType == 0) + { + /* Pass 0 is for device usage */ + FlagMatch = IDT_DEVICE & ~IDT_REGISTERED; + Interface = InterfaceType; + } + else + { + /* Pass 1 is for internal HAL usage */ + FlagMatch = IDT_INTERNAL & ~IDT_REGISTERED; + Interface = Internal; + } + + /* And it is of this new interface type */ + RawFull->InterfaceType = Interface; + TranslatedFull->InterfaceType = Interface; + + /* Start looping our interrupts */ + for (ix = 0; ix <= MAXIMUM_IDTVECTOR; ix++) + { + /* Check if this entry should be parsed */ + if (!(HalpIDTUsageFlags[ix].Flags & FlagMatch)) + { + /* Skip this entry */ + continue; + } + + /* Parse it */ + HalpBuildPartialFromIdt(ix, &RawPartial, &TranslatedPartial); + + HalpAddDescriptors(RawPartialList, &CurrentRaw, &RawPartial); + HalpAddDescriptors(TranslatedPartialList, &CurrentTranslated, &TranslatedPartial); + } + + /* Start looping our address uage list */ + for (CurrentAddress = HalpAddressUsageList; + CurrentAddress; + CurrentAddress = CurrentAddress->Next) + { + for (ix = 0; (CurrentAddress->Element[ix].Length != 0); ix++) + { + /* Check if the address should be reported */ + if (!(CurrentAddress->Flags & FlagMatch) || + !(CurrentAddress->Element[ix].Length)) + { + /* Nope, skip it */ + continue; + } + + /* Otherwise, parse the entry */ + HalpBuildPartialFromAddress(Interface, + CurrentAddress, + ix, + &RawPartial, + &TranslatedPartial); + + HalpAddDescriptors(RawPartialList, &CurrentRaw, &RawPartial); + HalpAddDescriptors(TranslatedPartialList, &CurrentTranslated, &TranslatedPartial); + } + } + + /* Our full descriptors start here */ + RawFull = (PCM_FULL_RESOURCE_DESCRIPTOR)CurrentRaw; + TranslatedFull = (PCM_FULL_RESOURCE_DESCRIPTOR)CurrentTranslated; + } + + /* Get the final list of the size for the kernel call later */ + ListSize = (ULONG)((ULONG_PTR)CurrentRaw - (ULONG_PTR)RawList); + + /* Now reset back to the first full descriptor */ + RawFull = RawList->List; + TranslatedFull = TranslatedList->List; + +#if 0 //DBG +{ + DPRINT1("HalpReportResourceUsage: Dump RawList:\n"); + HalpDumpCmResourceList(RawList); + DPRINT1("HalpReportResourceUsage: Dump TranslatedList:\n"); + HalpDumpCmResourceList(TranslatedList); + //ASSERT(FALSE); +} +#endif + + /* And loop all the full descriptors */ + for (ix = 0; ix < RawList->Count; ix++) + { + /* Get the first partial descriptor in this list */ + CurrentRaw = RawFull->PartialResourceList.PartialDescriptors; + CurrentTranslated = TranslatedFull->PartialResourceList.PartialDescriptors; + + /* Get the count of partials in this list */ + Count = RawFull->PartialResourceList.Count; + + /* Loop all the partials in this list */ + for (jx = 0; jx < Count; jx++) + { + /* Get the sort value at this point */ + HalpGetResourceSortValue(CurrentRaw, &CurrentScale, &CurrentSortValue); + + /* Save the current sort pointer */ + SortedRaw = CurrentRaw; + SortedTranslated = CurrentTranslated; + + /* Loop all descriptors starting from this one */ + for (kx = jx; kx < Count; kx++) + { + /* Get the sort value at the sort point */ + HalpGetResourceSortValue(SortedRaw, &SortScale, &SortValue); + + /* Check if a swap needs to occur */ + if ((SortScale < CurrentScale) || + ((SortScale == CurrentScale) && + (SortValue.QuadPart <= CurrentSortValue.QuadPart))) + { + /* Swap raw partial with the sort location partial */ + RtlCopyMemory(&RawPartial, CurrentRaw, sizeof(RawPartial)); + RtlCopyMemory(CurrentRaw, SortedRaw, sizeof(RawPartial)); + RtlCopyMemory(SortedRaw, &RawPartial, sizeof(RawPartial)); + + /* Swap translated partial in the same way */ + RtlCopyMemory(&TranslatedPartial, CurrentTranslated, sizeof(TranslatedPartial)); + RtlCopyMemory(CurrentTranslated, SortedTranslated, sizeof(TranslatedPartial)); + RtlCopyMemory(SortedTranslated, &TranslatedPartial, sizeof(TranslatedPartial)); + + /* Update the sort value at this point */ + HalpGetResourceSortValue(CurrentRaw, &CurrentScale, &CurrentSortValue); + } + + /* The sort location has been updated */ + SortedRaw++; + SortedTranslated++; + } + + /* Move to the next partial */ + CurrentRaw++; + CurrentTranslated++; + } + + /* Move to the next full descriptor */ + RawFull = (PCM_FULL_RESOURCE_DESCRIPTOR)CurrentRaw; + TranslatedFull = (PCM_FULL_RESOURCE_DESCRIPTOR)CurrentTranslated; + } + + /* Mark this is an ACPI system, if it is */ + HalpMarkAcpiHal(); + + /* Tell the kernel about all this */ + IoReportHalResourceUsage(HalName, RawList, TranslatedList, ListSize); + + /* Free our lists */ + ExFreePoolWithTag(RawList, TAG_HAL); + ExFreePoolWithTag(TranslatedList, TAG_HAL); + + /* Get the machine's serial number */ + HalpReportSerialNumber(); + + //HalpTestAcpiHal(); +} + +/* EOF */ + diff --git a/hal/halacpi/generic/v86.S b/hal/halacpi/generic/v86.S new file mode 100644 index 0000000000000..e98c38061c870 --- /dev/null +++ b/hal/halacpi/generic/v86.S @@ -0,0 +1,33 @@ + +/* INCLUDES ******************************************************************/ + +#include +#include + +.code + +PUBLIC @HalpExitToV86@4 +@HalpExitToV86@4: + /* Point esp to the iret frame and return */ + lea esp, [ecx + KTRAP_FRAME_EIP] + iretd + +/* Here starts the real mode code */ +.code16 +PUBLIC _HalpRealModeStart +_HalpRealModeStart: + /* INT 0x10: AH = 0 (Set video Mode), AL = 0x12 (Mode 12) */ + mov eax, HEX(12) + int HEX(10) + + /* BOP */ + .byte HEX(C4), HEX(C4) + +/* The real mode stack */ +.align 4 +.space 2048 +_HalpRealModeEnd: +PUBLIC _HalpRealModeEnd +.endcode16 + +END diff --git a/hal/halacpi/halacpi.spec b/hal/halacpi/halacpi.spec new file mode 100644 index 0000000000000..13f289b657d36 --- /dev/null +++ b/hal/halacpi/halacpi.spec @@ -0,0 +1,92 @@ +@ fastcall ExAcquireFastMutex(ptr) ntoskrnl.ExiAcquireFastMutex +@ fastcall ExReleaseFastMutex(ptr) ntoskrnl.ExiReleaseFastMutex +@ fastcall 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 HalAssignSlotResources(ptr ptr ptr ptr long long long ptr) +@ stdcall HalBeginSystemInterrupt(long long ptr) +@ stdcall HalCalibratePerformanceCounter(ptr long long) +@ fastcall HalClearSoftwareInterrupt(long) +@ stdcall HalDisableSystemInterrupt(long long) +@ stdcall HalDisplayString(str) +@ stdcall HalEnableSystemInterrupt(long long long) +@ stdcall HalEndSystemInterrupt(long long) #NT use nonstandard parameters calling +@ stdcall HalFlushCommonBuffer(long long long long long) +@ stdcall HalFreeCommonBuffer(ptr long long long ptr long) +@ stdcall HalGetAdapter(ptr ptr) +@ stdcall HalGetBusData(long long long ptr long) +@ stdcall HalGetBusDataByOffset(long long long ptr long long) +@ stdcall HalGetEnvironmentVariable(str long str) +@ stdcall HalGetInterruptVector(long long long long ptr ptr) +@ stdcall HalHandleNMI(ptr) +@ stdcall HalInitSystem(long ptr) +@ stdcall HalInitializeProcessor(long ptr) +@ stdcall HalMakeBeep(long) +@ stdcall HalProcessorIdle() +@ stdcall HalQueryDisplayParameters(ptr ptr ptr ptr) +@ stdcall HalQueryRealTimeClock(ptr) +@ stdcall HalReadDmaCounter(ptr) +@ stdcall HalReportResourceUsage() +@ stdcall HalRequestIpi(long) +@ fastcall HalRequestSoftwareInterrupt(long) +@ stdcall HalReturnToFirmware(long) +@ stdcall HalSetBusData(long long long ptr long) +@ stdcall HalSetBusDataByOffset(long long long ptr long long) +@ stdcall HalSetDisplayParameters(long long) +@ stdcall HalSetEnvironmentVariable(str str) +@ stdcall HalSetProfileInterval(long) +@ stdcall HalSetRealTimeClock(ptr) +@ stdcall HalSetTimeIncrement(long) +@ stdcall HalStartNextProcessor(ptr ptr) +@ stdcall HalStartProfileInterrupt(long) +@ stdcall HalStopProfileInterrupt(long) +@ fastcall HalSystemVectorDispatchEntry(long long long) +@ stdcall HalTranslateBusAddress(long long long long ptr ptr) +@ stdcall IoAssignDriveLetters(ptr str ptr ptr) HalpAssignDriveLetters +@ stdcall IoFlushAdapterBuffers(ptr ptr ptr ptr long long) +@ stdcall IoFreeAdapterChannel(ptr) +@ stdcall IoFreeMapRegisters(ptr ptr long) +@ stdcall IoMapTransfer(ptr ptr ptr ptr ptr long) +@ stdcall IoReadPartitionTable(ptr long long ptr) HalpReadPartitionTable +@ stdcall IoSetPartitionInformation(ptr long long long) HalpSetPartitionInformation +@ stdcall IoWritePartitionTable(ptr long long long ptr) HalpWritePartitionTable +@ extern KdComPortInUse +@ fastcall KeAcquireInStackQueuedSpinLock(ptr ptr) +@ fastcall KeAcquireInStackQueuedSpinLockRaiseToSynch(ptr ptr) +@ fastcall KeAcquireQueuedSpinLock(ptr) +@ fastcall KeAcquireQueuedSpinLockRaiseToSynch(ptr) +@ stdcall KeAcquireSpinLock(ptr ptr) +@ fastcall KeAcquireSpinLockRaiseToSynch(ptr) +@ stdcall KeFlushWriteBuffer() +@ stdcall KeGetCurrentIrql() +@ stdcall KeLowerIrql(long) +@ stdcall KeQueryPerformanceCounter(ptr) +@ stdcall KeRaiseIrql(long ptr) +@ stdcall KeRaiseIrqlToDpcLevel() +@ stdcall KeRaiseIrqlToSynchLevel() +@ fastcall KeReleaseInStackQueuedSpinLock(ptr) +@ fastcall KeReleaseQueuedSpinLock(ptr long) +@ stdcall KeReleaseSpinLock(ptr long) +@ stdcall KeStallExecutionProcessor(long) +@ fastcall KeTryToAcquireQueuedSpinLock(long ptr) +@ fastcall KeTryToAcquireQueuedSpinLockRaiseToSynch(long ptr) +@ fastcall KfAcquireSpinLock(ptr) +@ fastcall KfLowerIrql(long) +@ fastcall KfRaiseIrql(long) +@ fastcall KfReleaseSpinLock(ptr long) +@ stdcall READ_PORT_BUFFER_UCHAR(ptr ptr long) +@ stdcall READ_PORT_BUFFER_ULONG(ptr ptr long) +@ stdcall READ_PORT_BUFFER_USHORT(ptr ptr long) +@ stdcall READ_PORT_UCHAR(ptr) +@ stdcall READ_PORT_ULONG(ptr) +@ stdcall READ_PORT_USHORT(ptr) +@ stdcall WRITE_PORT_BUFFER_UCHAR(ptr ptr long) +@ stdcall WRITE_PORT_BUFFER_ULONG(ptr ptr long) +@ stdcall WRITE_PORT_BUFFER_USHORT(ptr ptr long) +@ stdcall WRITE_PORT_UCHAR(ptr long) +@ stdcall WRITE_PORT_ULONG(ptr long) +@ stdcall WRITE_PORT_USHORT(ptr long) diff --git a/hal/halacpi/include/bus.h b/hal/halacpi/include/bus.h new file mode 100644 index 0000000000000..2981ec2e835ee --- /dev/null +++ b/hal/halacpi/include/bus.h @@ -0,0 +1,361 @@ +#pragma once + +/* INCLUDES ******************************************************************/ + +#define PCI_ADDRESS_MEMORY_SPACE 0x00000000 + +/* Helper Macros */ +#define PASTE2(x,y) x ## y +#define POINTER_TO_(x) PASTE2(P,x) +#define READ_FROM(x) PASTE2(READ_PORT_, x) +#define WRITE_TO(x) PASTE2(WRITE_PORT_, x) + +/* Declares a PCI Register Read/Write Routine */ +#define TYPE_DEFINE(x, y) \ + ULONG \ + NTAPI \ + x( \ + IN PPCIPBUSDATA BusData, \ + IN y PciCfg, \ + IN PUCHAR Buffer, \ + IN ULONG Offset \ + ) +#define TYPE1_DEFINE(x) TYPE_DEFINE(x, PPCI_TYPE1_CFG_BITS); +#define TYPE2_DEFINE(x) TYPE_DEFINE(x, PPCI_TYPE2_ADDRESS_BITS); + +/* Defines a PCI Register Read/Write Type 1 Routine Prologue and Epilogue */ +#define TYPE1_START(x, y) \ + TYPE_DEFINE(x, PPCI_TYPE1_CFG_BITS) \ +{ \ + ULONG i = Offset % sizeof(ULONG); \ + PciCfg->u.bits.RegisterNumber = Offset / sizeof(ULONG); \ + WRITE_PORT_ULONG(BusData->Config.Type1.Address, PciCfg->u.AsULONG); +#define TYPE1_END(y) \ + return sizeof(y); } +#define TYPE2_END TYPE1_END + +/* PCI Register Read Type 1 Routine */ +#define TYPE1_READ(x, y) \ + TYPE1_START(x, y) \ + *((POINTER_TO_(y))Buffer) = \ + READ_FROM(y)((POINTER_TO_(y))(ULONG_PTR)(BusData->Config.Type1.Data + i)); \ + TYPE1_END(y) + +/* PCI Register Write Type 1 Routine */ +#define TYPE1_WRITE(x, y) \ + TYPE1_START(x, y) \ + WRITE_TO(y)((POINTER_TO_(y))(ULONG_PTR)(BusData->Config.Type1.Data + i), \ + *((POINTER_TO_(y))Buffer)); \ + TYPE1_END(y) + +/* Defines a PCI Register Read/Write Type 2 Routine Prologue and Epilogue */ +#define TYPE2_START(x, y) \ + TYPE_DEFINE(x, PPCI_TYPE2_ADDRESS_BITS) \ +{ \ + PciCfg->u.bits.RegisterNumber = (USHORT)Offset; + +/* PCI Register Read Type 2 Routine */ +#define TYPE2_READ(x, y) \ + TYPE2_START(x, y) \ + *((POINTER_TO_(y))Buffer) = \ + READ_FROM(y)((POINTER_TO_(y))(ULONG_PTR)PciCfg->u.AsUSHORT); \ + TYPE2_END(y) + +/* PCI Register Write Type 2 Routine */ +#define TYPE2_WRITE(x, y) \ + TYPE2_START(x, y) \ + WRITE_TO(y)((POINTER_TO_(y))(ULONG_PTR)PciCfg->u.AsUSHORT, \ + *((POINTER_TO_(y))Buffer)); \ + TYPE2_END(y) + +typedef NTSTATUS +(NTAPI * PciIrqRange)( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER PciSlot, + OUT PSUPPORTED_RANGE * Interrupt +); + +typedef struct _PCIPBUSDATA +{ + PCIBUSDATA CommonData; + union + { + struct + { + PULONG Address; + ULONG Data; + } Type1; + struct + { + PUCHAR CSE; + PUCHAR Forward; + ULONG Base; + } Type2; + } Config; + ULONG MaxDevice; + PciIrqRange GetIrqRange; + BOOLEAN BridgeConfigRead; + UCHAR ParentBus; + UCHAR Subtractive; + UCHAR reserved[1]; + UCHAR SwizzleIn[4]; + RTL_BITMAP DeviceConfigured; + ULONG ConfiguredBits[PCI_MAX_DEVICES * PCI_MAX_FUNCTION / 32]; +} PCIPBUSDATA, *PPCIPBUSDATA; + +typedef ULONG +(NTAPI * FncConfigIO)( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset +); + +typedef VOID +(NTAPI * FncSync)( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PKIRQL Irql, + IN PVOID State +); + +typedef VOID +(NTAPI * FncReleaseSync)( + IN PBUS_HANDLER BusHandler, + IN KIRQL Irql +); + +typedef struct _PCI_CONFIG_HANDLER +{ + FncSync Synchronize; + FncReleaseSync ReleaseSynchronzation; + FncConfigIO ConfigRead[3]; + FncConfigIO ConfigWrite[3]; +} PCI_CONFIG_HANDLER, *PPCI_CONFIG_HANDLER; + +typedef struct _PCI_REGISTRY_INFO_INTERNAL +{ + UCHAR MajorRevision; + UCHAR MinorRevision; + UCHAR NoBuses; // Number Of Buses + UCHAR HardwareMechanism; + ULONG ElementCount; + PCI_CARD_DESCRIPTOR CardList[ANYSIZE_ARRAY]; +} PCI_REGISTRY_INFO_INTERNAL, *PPCI_REGISTRY_INFO_INTERNAL; + +/* PCI Type 1 Ports */ +#define PCI_TYPE1_ADDRESS_PORT (PULONG)0xCF8 +#define PCI_TYPE1_DATA_PORT 0xCFC + +/* PCI Type 2 Ports */ +#define PCI_TYPE2_CSE_PORT (PUCHAR)0xCF8 +#define PCI_TYPE2_FORWARD_PORT (PUCHAR)0xCFA +#define PCI_TYPE2_ADDRESS_BASE 0xC + +/* PCI Type 1 Configuration Register */ +typedef struct _PCI_TYPE1_CFG_BITS +{ + union + { + struct + { + ULONG Reserved1:2; + ULONG RegisterNumber:6; + ULONG FunctionNumber:3; + ULONG DeviceNumber:5; + ULONG BusNumber:8; + ULONG Reserved2:7; + ULONG Enable:1; + } bits; + + ULONG AsULONG; + } u; +} PCI_TYPE1_CFG_BITS, *PPCI_TYPE1_CFG_BITS; + +/* PCI Type 2 CSE Register */ +typedef struct _PCI_TYPE2_CSE_BITS +{ + union + { + struct + { + UCHAR Enable:1; + UCHAR FunctionNumber:3; + UCHAR Key:4; + } bits; + + UCHAR AsUCHAR; + } u; +} PCI_TYPE2_CSE_BITS, PPCI_TYPE2_CSE_BITS; + +/* PCI Type 2 Address Register */ +typedef struct _PCI_TYPE2_ADDRESS_BITS +{ + union + { + struct + { + USHORT RegisterNumber:8; + USHORT Agent:4; + USHORT AddressBase:4; + } bits; + + USHORT AsUSHORT; + } u; +} PCI_TYPE2_ADDRESS_BITS, *PPCI_TYPE2_ADDRESS_BITS; + +typedef struct _PCI_TYPE1_CFG_CYCLE_BITS +{ + union + { + struct + { + ULONG Reserved1:2; + ULONG RegisterNumber:6; + ULONG FunctionNumber:3; + ULONG DeviceNumber:5; + ULONG BusNumber:8; + ULONG Reserved2:8; + } bits; + ULONG AsULONG; + } u; +} PCI_TYPE1_CFG_CYCLE_BITS, *PPCI_TYPE1_CFG_CYCLE_BITS; + +/* FUNCTIONS *****************************************************************/ + +PPCI_REGISTRY_INFO_INTERNAL +NTAPI +HalpQueryPciRegistryInfo( + VOID +); + +VOID +NTAPI +HalpPCISynchronizeType1( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PKIRQL Irql, + IN PPCI_TYPE1_CFG_BITS PciCfg +); + +VOID +NTAPI +HalpPCIReleaseSynchronzationType1( + IN PBUS_HANDLER BusHandler, + IN KIRQL Irql +); + +TYPE1_DEFINE(HalpPCIReadUcharType1); +TYPE1_DEFINE(HalpPCIReadUshortType1); +TYPE1_DEFINE(HalpPCIReadUlongType1); + +TYPE1_DEFINE(HalpPCIWriteUcharType1); +TYPE1_DEFINE(HalpPCIWriteUshortType1); +TYPE1_DEFINE(HalpPCIWriteUlongType1); + +VOID +NTAPI +HalpPCISynchronizeType2( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PKIRQL Irql, + IN PPCI_TYPE2_ADDRESS_BITS PciCfg +); + +VOID +NTAPI +HalpPCIReleaseSynchronizationType2( + IN PBUS_HANDLER BusHandler, + IN KIRQL Irql +); + +TYPE2_DEFINE(HalpPCIReadUcharType2); +TYPE2_DEFINE(HalpPCIReadUshortType2); +TYPE2_DEFINE(HalpPCIReadUlongType2); + +TYPE2_DEFINE(HalpPCIWriteUcharType2); +TYPE2_DEFINE(HalpPCIWriteUshortType2); +TYPE2_DEFINE(HalpPCIWriteUlongType2); + +VOID +NTAPI +HalpReadPCIConfig( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length +); + +VOID +NTAPI +HalpWritePCIConfig( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length +); + +ULONG +NTAPI +HalpGetPCIData( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootBusHandler, + IN ULONG SlotNumber, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length +); + +ULONG +NTAPI +HalpSetPCIData( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootBusHandler, + IN ULONG SlotNumber, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length +); + +NTSTATUS +NTAPI +HalpAssignPCISlotResources( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PUNICODE_STRING RegistryPath, + IN PUNICODE_STRING DriverClassName OPTIONAL, + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT DeviceObject OPTIONAL, + IN ULONG Slot, + IN OUT PCM_RESOURCE_LIST *pAllocatedResources +); + +CODE_SEG("INIT") +VOID +NTAPI +HalpRegisterPciDebuggingDeviceInfo( + VOID +); + +ULONG +NTAPI +HalpGetCmosData( + IN ULONG BusNumber, + IN ULONG SlotNumber, + IN PVOID Buffer, + IN ULONG Length +); + +ULONG +NTAPI +HalpSetCmosData( + IN ULONG BusNumber, + IN ULONG SlotNumber, + IN PVOID Buffer, + IN ULONG Length +); + +/* EOF */ diff --git a/hal/halacpi/include/hal.h b/hal/halacpi/include/hal.h new file mode 100644 index 0000000000000..0502f3fa11961 --- /dev/null +++ b/hal/halacpi/include/hal.h @@ -0,0 +1,61 @@ + +#ifndef _HAL_PCH_ +#define _HAL_PCH_ + +/* INCLUDES ******************************************************************/ + +/* C Headers */ +#include + +/* WDK HAL Compilation hack */ +#include +#include + +#ifndef _MINIHAL_ + #undef NTSYSAPI + #define NTSYSAPI __declspec(dllimport) +#else + #undef NTSYSAPI + #define NTSYSAPI +#endif + +/* IFS/DDK/NDK Headers */ +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +/* Internal shared PCI and ACPI header */ +#include +#include + +/* Internal kernel headers */ +#define KeGetCurrentThread _KeGetCurrentThread + +#ifdef _M_AMD64 + #include + #include + #include "internal/amd64/intrin_i.h" +#else + #include + #include + #include "internal/i386/intrin_i.h" +#endif + +#define TAG_HAL ' laH' +#define TAG_BUS_HANDLER 'BusH' + +/* Internal HAL Headers */ +#include "halp.h" +#include "halacpi.h" +#include "haldma.h" +#include "bus.h" + +#endif /* _HAL_PCH_ */ diff --git a/hal/halacpi/include/halacpi.h b/hal/halacpi/include/halacpi.h new file mode 100644 index 0000000000000..df4f27f1129a3 --- /dev/null +++ b/hal/halacpi/include/halacpi.h @@ -0,0 +1,154 @@ + +#pragma once + +/* Internal HAL structure */ +typedef struct _ACPI_CACHED_TABLE +{ + LIST_ENTRY Links; + DESCRIPTION_HEADER Header; + // table follows + // ... +} ACPI_CACHED_TABLE, *PACPI_CACHED_TABLE; + + +CODE_SEG("INIT") +PVOID +NTAPI +HalAcpiGetTable( + IN PLOADER_PARAMETER_BLOCK LoaderBlock, + IN ULONG Signature +); + +CODE_SEG("INIT") +VOID +NTAPI +HalpCheckPowerButton( + VOID +); + +CODE_SEG("INIT") +NTSTATUS +NTAPI +HalpSetupAcpiPhase0( + IN PLOADER_PARAMETER_BLOCK LoaderBlock +); + +VOID +NTAPI +HaliAcpiTimerInit( + _In_ PULONG TimerPort, + _In_ BOOLEAN TimerValExt +); + +NTSTATUS +NTAPI +HalacpiGetInterruptTranslator( + _In_ INTERFACE_TYPE ParentInterfaceType, + _In_ ULONG ParentBusNumber, + _In_ INTERFACE_TYPE BridgeInterfaceType, + _In_ USHORT Size, + _In_ USHORT Version, + _Out_ PTRANSLATOR_INTERFACE Translator, + _Out_ PULONG BridgeBusNumber +); + +BOOLEAN +NTAPI +HalpTranslateBusAddress( + IN INTERFACE_TYPE InterfaceType, + IN ULONG BusNumber, + IN PHYSICAL_ADDRESS BusAddress, + IN OUT PULONG AddressSpace, + OUT PPHYSICAL_ADDRESS TranslatedAddress +); + +NTSTATUS +NTAPI +HalpAssignSlotResources( + IN PUNICODE_STRING RegistryPath, + IN PUNICODE_STRING DriverClassName, + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT DeviceObject, + IN INTERFACE_TYPE BusType, + IN ULONG BusNumber, + IN ULONG SlotNumber, + IN OUT PCM_RESOURCE_LIST * AllocatedResources +); + +BOOLEAN +NTAPI +HalpFindBusAddressTranslation( + IN PHYSICAL_ADDRESS BusAddress, + IN OUT PULONG AddressSpace, + OUT PPHYSICAL_ADDRESS TranslatedAddress, + IN OUT PULONG_PTR Context, + IN BOOLEAN NextBus +); + +NTSTATUS +NTAPI +HalacpiInitPowerManagement( + _In_ PPM_DISPATCH_TABLE PmDriverDispatchTable, + _Out_ PPM_DISPATCH_TABLE * PmHalDispatchTable +); + +VOID +NTAPI +HaliHaltSystem( + VOID +); + +PVOID +NTAPI +HalpAcpiGetTable( + IN PLOADER_PARAMETER_BLOCK LoaderBlock, + IN ULONG Signature +); + +CODE_SEG("INIT") +VOID +NTAPI +HalpReportResourceUsage( + IN PUNICODE_STRING HalName, + IN INTERFACE_TYPE InterfaceType +); + +CODE_SEG("INIT") +VOID +NTAPI +HalpInitializePciBus( + VOID +); + +CODE_SEG("INIT") +VOID +NTAPI +HalpGetNMICrashFlag( + VOID +); + +BOOLEAN +NTAPI +HalpGetDebugPortTable( + VOID +); + +NTSTATUS +NTAPI +HalpQueryAcpiResourceRequirements( + OUT PIO_RESOURCE_REQUIREMENTS_LIST* Requirements +); + +VOID +NTAPI +HalTranslatorDereference( + IN PVOID Context +); + +VOID +NTAPI +HalpWriteResetCommand( + VOID +); + +/* EOF */ diff --git a/hal/halacpi/include/haldma.h b/hal/halacpi/include/haldma.h new file mode 100644 index 0000000000000..801798a4208b9 --- /dev/null +++ b/hal/halacpi/include/haldma.h @@ -0,0 +1,387 @@ +#pragma once +extern ULONG HalpBusType; +/* + * DMA Page Register Structure + * 080 DMA RESERVED + * 081 DMA Page Register (channel 2) + * 082 DMA Page Register (channel 3) + * 083 DMA Page Register (channel 1) + * 084 DMA RESERVED + * 085 DMA RESERVED + * 086 DMA RESERVED + * 087 DMA Page Register (channel 0) + * 088 DMA RESERVED + * 089 PS/2-DMA Page Register (channel 6) + * 08A PS/2-DMA Page Register (channel 7) + * 08B PS/2-DMA Page Register (channel 5) + * 08C PS/2-DMA RESERVED + * 08D PS/2-DMA RESERVED + * 08E PS/2-DMA RESERVED + * 08F PS/2-DMA Page Register (channel 4) + */ + +typedef struct _DMA_PAGE +{ + UCHAR Reserved1; + UCHAR Channel2; + UCHAR Channel3; + UCHAR Channel1; + UCHAR Reserved2[3]; + UCHAR Channel0; + UCHAR Reserved3; + UCHAR Channel6; + UCHAR Channel7; + UCHAR Channel5; + UCHAR Reserved4[3]; + UCHAR Channel4; +} DMA_PAGE, *PDMA_PAGE; + +/* + * DMA Channel Mask Register Structure + * + * MSB LSB + * x x x x x x x x + * ------------------- - ----- + * | | | 00 - Select channel 0 mask bit + * | | \---- 01 - Select channel 1 mask bit + * | | 10 - Select channel 2 mask bit + * | | 11 - Select channel 3 mask bit + * | | + * | \---------- 0 - Clear mask bit + * | 1 - Set mask bit + * | + * \----------------------- xx - Reserved + */ + +typedef struct _DMA_CHANNEL_MASK +{ + UCHAR Channel: 2; + UCHAR SetMask: 1; + UCHAR Reserved: 5; +} DMA_CHANNEL_MASK, *PDMA_CHANNEL_MASK; + +/* + * DMA Mask Register Structure + * + * MSB LSB + * x x x x x x x x + * \---/ - - ----- ----- + * | | | | | 00 - Channel 0 select + * | | | | \---- 01 - Channel 1 select + * | | | | 10 - Channel 2 select + * | | | | 11 - Channel 3 select + * | | | | + * | | | | 00 - Verify transfer + * | | | \------------ 01 - Write transfer + * | | | 10 - Read transfer + * | | | + * | | \-------------------- 0 - Autoinitialized + * | | 1 - Non-autoinitialized + * | | + * | \------------------------ 0 - Address increment select + * | + * | 00 - Demand mode + * \------------------------------ 01 - Single mode + * 10 - Block mode + * 11 - Cascade mode + */ + +typedef union _DMA_MODE +{ + struct + { + UCHAR Channel: 2; + UCHAR TransferType: 2; + UCHAR AutoInitialize: 1; + UCHAR AddressDecrement: 1; + UCHAR RequestMode: 2; + }; + UCHAR Byte; +} DMA_MODE, *PDMA_MODE; + +/* + * DMA Extended Mode Register Structure + * + * MSB LSB + * x x x x x x x x + * - - ----- ----- ----- + * | | | | | 00 - Channel 0 select + * | | | | \---- 01 - Channel 1 select + * | | | | 10 - Channel 2 select + * | | | | 11 - Channel 3 select + * | | | | + * | | | | 00 - 8-bit I/O, by bytes + * | | | \------------ 01 - 16-bit I/O, by words, address shifted + * | | | 10 - 32-bit I/O, by bytes + * | | | 11 - 16-bit I/O, by bytes + * | | | + * | | \---------------------- 00 - Compatible + * | | 01 - Type A + * | | 10 - Type B + * | | 11 - Burst + * | | + * | \---------------------------- 0 - Terminal Count is Output + * | + * \---------------------------------0 - Disable Stop Register + * 1 - Enable Stop Register + */ + +typedef union _DMA_EXTENDED_MODE +{ + struct + { + UCHAR ChannelNumber: 2; + UCHAR TransferSize: 2; + UCHAR TimingMode: 2; + UCHAR TerminalCountIsOutput: 1; + UCHAR EnableStopRegister: 1; + }; + UCHAR Byte; +} DMA_EXTENDED_MODE, *PDMA_EXTENDED_MODE; + +/* DMA Extended Mode Register Transfer Sizes */ +#define B_8BITS 0 +#define W_16BITS 1 +#define B_32BITS 2 +#define B_16BITS 3 + +/* DMA Extended Mode Register Timing */ +#define COMPATIBLE_TIMING 0 +#define TYPE_A_TIMING 1 +#define TYPE_B_TIMING 2 +#define BURST_TIMING 3 + +/* Channel Stop Registers for each Channel */ +typedef struct _DMA_CHANNEL_STOP +{ + UCHAR ChannelLow; + UCHAR ChannelMid; + UCHAR ChannelHigh; + UCHAR Reserved; +} DMA_CHANNEL_STOP, *PDMA_CHANNEL_STOP; + +/* Transfer Types */ +#define VERIFY_TRANSFER 0x00 +#define READ_TRANSFER 0x01 +#define WRITE_TRANSFER 0x02 + +/* Request Modes */ +#define DEMAND_REQUEST_MODE 0x00 +#define SINGLE_REQUEST_MODE 0x01 +#define BLOCK_REQUEST_MODE 0x02 +#define CASCADE_REQUEST_MODE 0x03 + +#define DMA_SETMASK 4 +#define DMA_CLEARMASK 0 +#define DMA_READ 4 +#define DMA_WRITE 8 +#define DMA_SINGLE_TRANSFER 0x40 +#define DMA_AUTO_INIT 0x10 + +typedef struct _DMA1_ADDRESS_COUNT +{ + UCHAR DmaBaseAddress; + UCHAR DmaBaseCount; +} DMA1_ADDRESS_COUNT, *PDMA1_ADDRESS_COUNT; + +typedef struct _DMA2_ADDRESS_COUNT +{ + UCHAR DmaBaseAddress; + UCHAR Reserved1; + UCHAR DmaBaseCount; + UCHAR Reserved2; +} DMA2_ADDRESS_COUNT, *PDMA2_ADDRESS_COUNT; + +typedef struct _DMA1_CONTROL +{ + DMA1_ADDRESS_COUNT DmaAddressCount[4]; + UCHAR DmaStatus; + UCHAR DmaRequest; + UCHAR SingleMask; + UCHAR Mode; + UCHAR ClearBytePointer; + UCHAR MasterClear; + UCHAR ClearMask; + UCHAR AllMask; +} DMA1_CONTROL, *PDMA1_CONTROL; + +typedef struct _DMA2_CONTROL +{ + DMA2_ADDRESS_COUNT DmaAddressCount[4]; + UCHAR DmaStatus; + UCHAR Reserved1; + UCHAR DmaRequest; + UCHAR Reserved2; + UCHAR SingleMask; + UCHAR Reserved3; + UCHAR Mode; + UCHAR Reserved4; + UCHAR ClearBytePointer; + UCHAR Reserved5; + UCHAR MasterClear; + UCHAR Reserved6; + UCHAR ClearMask; + UCHAR Reserved7; + UCHAR AllMask; + UCHAR Reserved8; +} DMA2_CONTROL, *PDMA2_CONTROL; + +/* This structure defines the I/O Map of the 82537 controller. */ +typedef struct _EISA_CONTROL +{ + /* DMA Controller 1 */ + DMA1_CONTROL DmaController1; /* 00h-0Fh */ + UCHAR Reserved1[16]; /* 0Fh-1Fh */ + + /* Interrupt Controller 1 (PIC) */ + UCHAR Pic1Operation; /* 20h */ + UCHAR Pic1Interrupt; /* 21h */ + UCHAR Reserved2[30]; /* 22h-3Fh */ + + /* Timer */ + UCHAR TimerCounter; /* 40h */ + UCHAR TimerMemoryRefresh; /* 41h */ + UCHAR Speaker; /* 42h */ + UCHAR TimerOperation; /* 43h */ + UCHAR TimerMisc; /* 44h */ + UCHAR Reserved3[2]; /* 45-46h */ + UCHAR TimerCounterControl; /* 47h */ + UCHAR TimerFailSafeCounter; /* 48h */ + UCHAR Reserved4; /* 49h */ + UCHAR TimerCounter2; /* 4Ah */ + UCHAR TimerOperation2; /* 4Bh */ + UCHAR Reserved5[20]; /* 4Ch-5Fh */ + + /* NMI / Keyboard / RTC */ + UCHAR Keyboard; /* 60h */ + UCHAR NmiStatus; /* 61h */ + UCHAR Reserved6[14]; /* 62h-6Fh */ + UCHAR NmiEnable; /* 70h */ + UCHAR Reserved7[15]; /* 71h-7Fh */ + + /* DMA Page Registers Controller 1 */ + DMA_PAGE DmaController1Pages; /* 80h-8Fh */ + UCHAR Reserved8[16]; /* 90h-9Fh */ + + /* Interrupt Controller 2 (PIC) */ + UCHAR Pic2Operation; /* 0A0h */ + UCHAR Pic2Interrupt; /* 0A1h */ + UCHAR Reserved9[30]; /* 0A2h-0BFh */ + + /* DMA Controller 2 */ + DMA1_CONTROL DmaController2; /* 0C0h-0CFh */ + + /* System Reserved Ports */ + UCHAR SystemReserved[816]; /* 0D0h-3FFh */ + + /* Extended DMA Registers, Controller 1 */ + UCHAR DmaHighByteCount1[8]; /* 400h-407h */ + UCHAR Reserved10[2]; /* 408h-409h */ + UCHAR DmaChainMode1; /* 40Ah */ + UCHAR DmaExtendedMode1; /* 40Bh */ + UCHAR DmaBufferControl; /* 40Ch */ + UCHAR Reserved11[84]; /* 40Dh-460h */ + UCHAR ExtendedNmiControl; /* 461h */ + UCHAR NmiCommand; /* 462h */ + UCHAR Reserved12; /* 463h */ + UCHAR BusMaster; /* 464h */ + UCHAR Reserved13[27]; /* 465h-47Fh */ + + /* DMA Page Registers Controller 2 */ + DMA_PAGE DmaController2Pages; /* 480h-48Fh */ + UCHAR Reserved14[48]; /* 490h-4BFh */ + + /* Extended DMA Registers, Controller 2 */ + UCHAR DmaHighByteCount2[16]; /* 4C0h-4CFh */ + + /* Edge/Level Control Registers */ + UCHAR Pic1EdgeLevel; /* 4D0h */ + UCHAR Pic2EdgeLevel; /* 4D1h */ + UCHAR Reserved15[2]; /* 4D2h-4D3h */ + + /* Extended DMA Registers, Controller 2 */ + UCHAR DmaChainMode2; /* 4D4h */ + UCHAR Reserved16; /* 4D5h */ + UCHAR DmaExtendedMode2; /* 4D6h */ + UCHAR Reserved17[9]; /* 4D7h-4DFh */ + + /* DMA Stop Registers */ + DMA_CHANNEL_STOP DmaChannelStop[8]; /* 4E0h-4FFh */ +} EISA_CONTROL, *PEISA_CONTROL; + +typedef struct _ROS_MAP_REGISTER_ENTRY +{ + PVOID VirtualAddress; + PHYSICAL_ADDRESS PhysicalAddress; + ULONG Counter; +} ROS_MAP_REGISTER_ENTRY, *PROS_MAP_REGISTER_ENTRY; + +typedef struct _ADAPTER_OBJECT { + /* + * New style DMA object definition. The fact that it is at the beginning + * of the ADAPTER_OBJECT structure allows us to easily implement the + * fallback implementation of IoGetDmaAdapter. + */ + DMA_ADAPTER DmaHeader; + + /* + * For normal adapter objects pointer to master adapter that takes care + * of channel allocation. For master adapter set to NULL. + */ + struct _ADAPTER_OBJECT *MasterAdapter; + + ULONG MapRegistersPerChannel; + PVOID AdapterBaseVa; + PROS_MAP_REGISTER_ENTRY MapRegisterBase; + + ULONG NumberOfMapRegisters; + ULONG CommittedMapRegisters; + + PWAIT_CONTEXT_BLOCK CurrentWcb; + KDEVICE_QUEUE ChannelWaitQueue; + PKDEVICE_QUEUE RegisterWaitQueue; + LIST_ENTRY AdapterQueue; + KSPIN_LOCK SpinLock; + PRTL_BITMAP MapRegisters; + PUCHAR PagePort; + UCHAR ChannelNumber; + UCHAR AdapterNumber; + USHORT DmaPortAddress; + DMA_MODE AdapterMode; + BOOLEAN NeedsMapRegisters; + BOOLEAN MasterDevice; + BOOLEAN Width16Bits; + BOOLEAN ScatterGather; + BOOLEAN IgnoreCount; + BOOLEAN Dma32BitAddresses; + BOOLEAN Dma64BitAddresses; + LIST_ENTRY AdapterList; +} ADAPTER_OBJECT; + +typedef struct _MASTER_ADAPTER { + PADAPTER_OBJECT AdapterObject; + ULONG MaxMapRegisters; + ULONG InitialMapRegistersBufferLength; + PHYSICAL_ADDRESS InitialMapRegistersBuffer; +} MASTER_ADAPTER, *PMASTER_ADAPTER; + +typedef struct _GROW_WORK_ITEM { + WORK_QUEUE_ITEM WorkQueueItem; + PADAPTER_OBJECT AdapterObject; + ULONG NumberOfMapRegisters; +} GROW_WORK_ITEM, *PGROW_WORK_ITEM; + +#define MAP_BASE_SW_SG 1 + +PADAPTER_OBJECT NTAPI +HalpDmaAllocateMasterAdapter(VOID); + +PDMA_ADAPTER NTAPI +HalpGetDmaAdapter( + IN PVOID Context, + IN PDEVICE_DESCRIPTION DeviceDescription, + OUT PULONG NumberOfMapRegisters); + +ULONG NTAPI +HalpDmaGetDmaAlignment( + PADAPTER_OBJECT AdapterObject); diff --git a/hal/halacpi/include/halp.h b/hal/halacpi/include/halp.h new file mode 100644 index 0000000000000..17f4c5fdd9c67 --- /dev/null +++ b/hal/halacpi/include/halp.h @@ -0,0 +1,392 @@ + +#pragma once + +/* Mm PTE/PDE to Hal PTE/PDE */ +#define HalAddressToPde(x) (PHARDWARE_PTE)MiAddressToPde(x) +#define HalAddressToPte(x) (PHARDWARE_PTE)MiAddressToPte(x) + +/* Usage flags */ +#define IDT_REGISTERED 0x01 +#define IDT_LATCHED 0x02 +#define IDT_READ_ONLY 0x04 +#define IDT_INTERNAL 0x11 +#define IDT_DEVICE 0x21 + +typedef struct _IDTUsageFlags +{ + UCHAR Flags; +} IDTUsageFlags; + +typedef struct +{ + KIRQL Irql; + UCHAR BusReleativeVector; +} IDTUsage; + +typedef struct _HalAddressUsage +{ + struct _HalAddressUsage *Next; + CM_RESOURCE_TYPE Type; + UCHAR Flags; + struct + { + ULONG Start; + ULONG Length; + } Element[]; +} ADDRESS_USAGE, *PADDRESS_USAGE; + +/* CMOS Registers and Ports */ +#define CMOS_CONTROL_PORT (PUCHAR)0x0070 +#define CMOS_DATA_PORT (PUCHAR)0x0071 +#define RTC_REGISTER_A 0x0A +#define RTC_REG_A_UIP 0x80 +#define RTC_REGISTER_B 0x0B +#define RTC_REG_B_PI 0x40 +#define RTC_REGISTER_C 0x0C +#define RTC_REG_C_IRQ 0x80 +//#define RTC_REGISTER_D 0x0D +//#define RTC_REGISTER_CENTURY 0x32 + +/* bios.c */ +BOOLEAN +NTAPI +HalpBiosDisplayReset( + VOID +); + +VOID +__cdecl +HalpRealModeStart( + VOID +); + +VOID +__cdecl +HalpTrap0D( + VOID +); + +VOID +FASTCALL +HalpExitToV86( + PKTRAP_FRAME TrapFrame +); + +/* cmos.c */ +CODE_SEG("INIT") +VOID +NTAPI +HalpInitializeCmos( + VOID +); + +UCHAR +NTAPI +HalpReadCmos( + IN UCHAR Reg +); + +VOID +NTAPI +HalpWriteCmos( + IN UCHAR Reg, + IN UCHAR Value +); + +/* dma.c */ +PDMA_ADAPTER +NTAPI +HalpGetDmaAdapter( + IN PVOID Context, + IN PDEVICE_DESCRIPTION DeviceDescriptor, + OUT PULONG NumberOfMapRegisters +); + +NTSTATUS +NTAPI +HalpAllocateMapRegisters( + _In_ PADAPTER_OBJECT AdapterObject, + _In_ ULONG Unknown, + _In_ ULONG Unknown2, + PMAP_REGISTER_ENTRY Registers +); + +VOID +NTAPI +HaliLocateHiberRanges( + _In_ PVOID MemoryMap +); + +CODE_SEG("INIT") +VOID +HalpInitDma( + VOID +); + +/* halinit.c */ +CODE_SEG("INIT") +VOID +NTAPI +HalInitializeProcessor( + IN ULONG ProcessorNumber, + IN PLOADER_PARAMETER_BLOCK LoaderBlock +); + +CODE_SEG("INIT") +BOOLEAN +NTAPI +HalInitSystem( + IN ULONG BootPhase, + IN PLOADER_PARAMETER_BLOCK LoaderBlock +); + +/* halpnpdd.c */ +NTSTATUS +NTAPI +HaliInitPnpDriver( + VOID +); + +/* memory.c */ +CODE_SEG("INIT") +ULONG_PTR +NTAPI +HalpAllocPhysicalMemory( + IN PLOADER_PARAMETER_BLOCK LoaderBlock, + IN ULONG MaxAddress, + IN PFN_NUMBER PageCount, + IN BOOLEAN Aligned +); + +PVOID +NTAPI +HalpMapPhysicalMemory64( + IN PHYSICAL_ADDRESS PhysicalAddress, + IN PFN_COUNT PageCount +); + +VOID +NTAPI +HalpUnmapVirtualAddress( + IN PVOID VirtualAddress, + IN PFN_COUNT NumberPages +); + +PVOID +NTAPI +HalpMapPhysicalMemoryWriteThrough64( + _In_ PHYSICAL_ADDRESS PhysicalAddress, + _In_ PFN_COUNT PageCount +); + +/* mics.c */ +VOID +NTAPI +HalpFlushTLB( + VOID +); + +NTSTATUS +NTAPI +HalpOpenRegistryKey( + IN PHANDLE KeyHandle, + IN HANDLE RootKey, + IN PUNICODE_STRING KeyName, + IN ACCESS_MASK DesiredAccess, + IN BOOLEAN Create +); + +/* pcibus.c */ +CODE_SEG("INIT") +NTSTATUS +NTAPI +HalpSetupPciDeviceForDebugging( + IN PVOID LoaderBlock, + IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice +); + +CODE_SEG("INIT") +NTSTATUS +NTAPI +HalpReleasePciDeviceForDebugging( + IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice +); + +ULONG +NTAPI +HaliPciInterfaceReadConfig( + _In_ PBUS_HANDLER RootBusHandler, + _In_ ULONG BusNumber, + _In_ PCI_SLOT_NUMBER SlotNumber, + _In_ PVOID Buffer, + _In_ ULONG Offset, + _In_ ULONG Length +); + +ULONG +NTAPI +HaliPciInterfaceWriteConfig( + _In_ PBUS_HANDLER RootBusHandler, + _In_ ULONG BusNumber, + _In_ PCI_SLOT_NUMBER SlotNumber, + _In_ PVOID Buffer, + _In_ ULONG Offset, + _In_ ULONG Length +); + +VOID +NTAPI +HalpInitializePciStubs( + VOID +); + +/* pic.c */ +VOID +NTAPI +HalpInitializePICs( + IN BOOLEAN EnableInterrupts +); + +ULONG +NTAPI +HalpGetSystemInterruptVector( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity +); + +NTSTATUS +NTAPI +HalIrqTranslateResourcesRoot( + _Inout_opt_ PVOID Context, + _In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR Source, + _In_ RESOURCE_TRANSLATION_DIRECTION Direction, + _In_opt_ ULONG AlternativesCount, + _In_opt_ IO_RESOURCE_DESCRIPTOR Alternatives[], + _In_ PDEVICE_OBJECT PhysicalDeviceObject, + _Out_ PCM_PARTIAL_RESOURCE_DESCRIPTOR Target +); + +NTSTATUS +NTAPI +HalIrqTranslateResourceRequirementsRoot( + _Inout_opt_ PVOID Context, + _In_ PIO_RESOURCE_DESCRIPTOR InIoDesc, // Source + _In_ PDEVICE_OBJECT DeviceObject, // PhysicalDeviceObject, + _Out_ PULONG OutIoDescCount, // TargetCount, + _Out_ PIO_RESOURCE_DESCRIPTOR* OutIoDesc // Target +); + +/* processor.c */ +ULONG +NTAPI +HalpGetFeatureBits( + VOID +); + +/* spinlock.c */ +VOID +NTAPI +HalpAcquireCmosSpinLock( + VOID +); + +VOID +NTAPI +HalpReleaseCmosSpinLock( + VOID +); + +/* sysinfo.c */ +NTSTATUS +NTAPI +HaliQuerySystemInformation( + IN HAL_QUERY_INFORMATION_CLASS InformationClass, + IN ULONG BufferSize, + IN OUT PVOID Buffer, + OUT PULONG ReturnedLength +); + +NTSTATUS +NTAPI +HaliSetSystemInformation( + IN HAL_SET_INFORMATION_CLASS InformationClass, + IN ULONG BufferSize, + IN OUT PVOID Buffer +); + +/* timer.c */ +CODE_SEG("INIT") +VOID +NTAPI +HalpInitializeClock( + VOID +); + +//#ifdef __REACTOS__ +VOID +FASTCALL +KeUpdateSystemTime( + _In_ PKTRAP_FRAME TrapFrame, + _In_ ULONG Increment, + _In_ KIRQL Irql +); +//#else + +//#endif + +VOID +__cdecl +HalpClockInterrupt( + VOID +); + +VOID +__cdecl +HalpProfileInterrupt( + VOID +); + +/* usage.c */ +CODE_SEG("INIT") +VOID +NTAPI +HalpRegisterVector( + IN UCHAR Flags, + IN ULONG BusVector, + IN ULONG SystemVector, + IN KIRQL Irql +); + +CODE_SEG("INIT") +VOID +NTAPI +HalpReportResourceUsage( + IN PUNICODE_STRING HalName, + IN INTERFACE_TYPE InterfaceType +); + +CODE_SEG("INIT") +VOID +NTAPI +HalpBuildPartialFromIdt( + IN ULONG Entry, + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR RawDescriptor, + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR TranslatedDescriptor +); + +CODE_SEG("INIT") +VOID +NTAPI +HalpBuildPartialFromAddress( + IN INTERFACE_TYPE Interface, + IN PADDRESS_USAGE CurrentAddress, + IN ULONG Element, + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR RawDescriptor, + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR TranslatedDescriptor +); + +/* EOF */ diff --git a/hal/halacpi/pic/pic.S b/hal/halacpi/pic/pic.S new file mode 100644 index 0000000000000..7e457fbb997d2 --- /dev/null +++ b/hal/halacpi/pic/pic.S @@ -0,0 +1,111 @@ + +/* INCLUDES ******************************************************************/ + +#include +#include + +/* GLOBALS *******************************************************************/ + +.data +ASSUME CS:NOTHING, DS:NOTHING, ES:NOTHING, FS:NOTHING, GS:NOTHING + +/* FUNCTIONS *****************************************************************/ + +.code + +MACRO(DEFINE_END_INTERRUPT_WRAPPER2, WrapperName, HandlerName) +EXTERN @&HandlerName&@8:PROC +PUBLIC _&WrapperName&@12 +.PROC _&WrapperName&@12 + FPO 0, 2, 0, 0, 0, FRAME_FPO + + /* Call the C function with the same arguments we got */ + mov ecx, [esp+4] + //mov edx, [esp+8] + mov edx, [esp+12] + call @&HandlerName&@8 + + /* Check if we got a pointer back */ + test eax, eax + jnz WrapperName&_CallIntHandler + + /* No? Just return */ + ret 12 + +WrapperName&_CallIntHandler: + /* We got a pointer to call. Since it won't return, reset the stack to + the location of the stack frame. This frees up our own stack as well + as that of the functions above us, and avoids an overflow due to + excessive recursion. + The next function takes the trap frame as its (fastcall) argument. */ + //mov ecx, [esp+8] + mov ecx, [esp+12] + mov esp, ecx + mov ebp, esp + jmp eax +.ENDP +ENDM + +MACRO(DEFINE_END_INTERRUPT_WRAPPER, WrapperName, HandlerName) +EXTERN @&HandlerName&@8:PROC +PUBLIC _&WrapperName&@8 +.PROC _&WrapperName&@8 + FPO 0, 2, 0, 0, 0, FRAME_FPO + + /* Call the C function with the same arguments we got */ + mov ecx, [esp+4] + mov edx, [esp+8] + call @&HandlerName&@8 + + /* Check if we got a pointer back */ + test eax, eax + jnz WrapperName&_CallIntHandler + + /* No? Just return */ + ret 8 + +WrapperName&_CallIntHandler: + /* We got a pointer to call. Since it won't return, reset the stack to + the location of the stack frame. This frees up our own stack as well + as that of the functions above us, and avoids an overflow due to + excessive recursion. + The next function takes the trap frame as its (fastcall) argument. */ + mov ecx, [esp+8] + mov esp, ecx + mov ebp, esp + jmp eax +.ENDP +ENDM + +MACRO(DEFINE_INTERRUPT_WRAPPER, WrapperName, HandlerName) +EXTERN _&HandlerName:PROC +PUBLIC _&WrapperName +.PROC _&WrapperName + FPO 0, 0, 0, 0, 0, FRAME_FPO + + /* Call the C function */ + call _&HandlerName + + /* Check if we got a pointer back */ + test eax, eax + jnz WrapperName&_CallIntHandler + + /* No? Just return */ + ret + +WrapperName&_CallIntHandler: + /* Optimize the tail call to avoid stack overflow */ + jmp eax +.ENDP +ENDM + + +DEFINE_END_INTERRUPT_WRAPPER HalpEndSoftwareInterrupt, HalpEndSoftwareInterrupt2 + +/* NT use nonstandard parameters calling */ +DEFINE_END_INTERRUPT_WRAPPER HalEndSystemInterrupt, HalEndSystemInterrupt2 + +DEFINE_INTERRUPT_WRAPPER HalpDispatchInterrupt, HalpDispatchInterrupt2 +DEFINE_INTERRUPT_WRAPPER HalpHardwareInterruptLevel, HalpHardwareInterruptLevel2 + +END diff --git a/hal/halacpi/pic/pic.c b/hal/halacpi/pic/pic.c new file mode 100644 index 0000000000000..378dc0de9f3b8 --- /dev/null +++ b/hal/halacpi/pic/pic.c @@ -0,0 +1,1463 @@ + +/* INCLUDES *******************************************************************/ + +#include +#include "pic.h" + +//#define NDEBUG +#include + +/* GLOBALS ********************************************************************/ + +/* This table basically keeps track of level vs edge triggered interrupts. + Windows has 250+ entries, but it seems stupid to replicate that since the PIC + can't actually have that many. + + When a level interrupt is registered, the respective pointer in this table is + modified to point to a dimiss routine for level interrupts instead. + + The other thing this table does is special case IRQ7, IRQ13 and IRQ15: + + - If an IRQ line is deasserted before it is acknowledged due to a noise spike + generated by an expansion device (since the IRQ line is low during the 1st + acknowledge bus cycle), the i8259 will keep the line low for at least 100ns + When the spike passes, a pull-up resistor will return the IRQ line to high. + Since the PIC requires the input be high until the first acknowledge, the + i8259 knows that this was a spurious interrupt, and on the second interrupt + acknowledge cycle, it reports this to the CPU. Since no valid interrupt has + actually happened Intel hardcoded the chip to report IRQ7 on the master PIC + and IRQ15 on the slave PIC (IR7 either way). + + "ISA System Architecture", 3rd Edition, states that these cases should be + handled by reading the respective Interrupt Service Request (ISR) bits from + the affected PIC, and validate whether or not IR7 is set. If it isn't, then + the interrupt is spurious and should be ignored. + + Note that for a spurious IRQ15, we DO have to send an EOI to the master for + IRQ2 since the line was asserted by the slave when it received the spurious + IRQ15! + + - When the 80287/80387 math co-processor generates an FPU/NPX trap, this is + connected to IRQ13, so we have to clear the busy latch on the NPX port. +*/ +PHAL_DISMISS_INTERRUPT HalpSpecialDismissTable[16] = +{ + HalpDismissIrqGeneric, + HalpDismissIrqGeneric, + HalpDismissIrqGeneric, + HalpDismissIrqGeneric, + HalpDismissIrqGeneric, + HalpDismissIrqGeneric, + HalpDismissIrqGeneric, + HalpDismissIrq07, + HalpDismissIrqGeneric, + HalpDismissIrqGeneric, + HalpDismissIrqGeneric, + HalpDismissIrqGeneric, + HalpDismissIrqGeneric, + HalpDismissIrq13, + HalpDismissIrqGeneric, + HalpDismissIrq15 +}; + +/* These are the level IRQ dismissal functions that get copied in the table + above if the given IRQ is actually level triggered. +*/ +PHAL_DISMISS_INTERRUPT HalpSpecialDismissLevelTable[16] = +{ + HalpDismissIrqLevel, + HalpDismissIrqLevel, + HalpDismissIrqLevel, + HalpDismissIrqLevel, + HalpDismissIrqLevel, + HalpDismissIrqLevel, + HalpDismissIrqLevel, + HalpDismissIrq07Level, + HalpDismissIrqLevel, + HalpDismissIrqLevel, + HalpDismissIrqLevel, + HalpDismissIrqLevel, + HalpDismissIrqLevel, + HalpDismissIrq13Level, + HalpDismissIrqLevel, + HalpDismissIrq15Level +}; + +/* This table contains the static x86 PIC mapping between IRQLs and IRQs */ +ULONG KiI8259MaskTable[32] = +{ +#if defined(__GNUC__) || defined(__clang__) || (defined(_MSC_VER) && _MSC_VER >= 1900) + /* It Device IRQLs only start at 4 or higher, so these are just software + IRQLs that don't really change anything on the hardware + */ + 0b00000000000000000000000000000000, /* IRQL 0 */ + 0b00000000000000000000000000000000, /* IRQL 1 */ + 0b00000000000000000000000000000000, /* IRQL 2 */ + 0b00000000000000000000000000000000, /* IRQL 3 */ + + /* These next IRQLs are actually useless from the PIC perspective, because + with only 2 PICs, the mask you can send them is only 8 bits each, for 16 + bits total, so these IRQLs are masking off a phantom PIC. + */ + 0b11111111100000000000000000000000, /* IRQL 4 */ + 0b11111111110000000000000000000000, /* IRQL 5 */ + 0b11111111111000000000000000000000, /* IRQL 6 */ + 0b11111111111100000000000000000000, /* IRQL 7 */ + 0b11111111111110000000000000000000, /* IRQL 8 */ + 0b11111111111111000000000000000000, /* IRQL 9 */ + 0b11111111111111100000000000000000, /* IRQL 10 */ + 0b11111111111111110000000000000000, /* IRQL 11 */ + + /* Okay, now we're finally starting to mask off IRQs on the slave PIC, from + IRQ15 to IRQ8. This means the higher-level IRQs get less priority in the + IRQL sense. + */ + 0b11111111111111111000000000000000, /* IRQL 12 */ + 0b11111111111111111100000000000000, /* IRQL 13 */ + 0b11111111111111111110000000000000, /* IRQL 14 */ + 0b11111111111111111111000000000000, /* IRQL 15 */ + 0b11111111111111111111100000000000, /* IRQL 16 */ + 0b11111111111111111111110000000000, /* IRQL 17 */ + 0b11111111111111111111111000000000, /* IRQL 18 */ + 0b11111111111111111111111000000000, /* IRQL 19 */ + + /* Now we mask off the IRQs on the master. Notice the 0 "droplet"? You might + have also seen that IRQL 18 and 19 are essentially equal as far as the + PIC is concerned. That bit is actually IRQ8, which happens to be the RTC. + The RTC will keep firing as long as we don't reach PROFILE_LEVEL which + actually kills it. The RTC clock (unlike the system clock) is used by the + profiling APIs in the HAL, so that explains the logic. + */ + 0b11111111111111111111111010000000, /* IRQL 20 */ + 0b11111111111111111111111011000000, /* IRQL 21 */ + 0b11111111111111111111111011100000, /* IRQL 22 */ + 0b11111111111111111111111011110000, /* IRQL 23 */ + 0b11111111111111111111111011111000, /* IRQL 24 */ + 0b11111111111111111111111011111000, /* IRQL 25 */ + 0b11111111111111111111111011111010, /* IRQL 26 */ + 0b11111111111111111111111111111010, /* IRQL 27 */ + + /* IRQL 24 and 25 are actually identical, so IRQL 28 is actually the last + IRQL to modify a bit on the master PIC. It happens to modify the very + last of the IRQs, IRQ0, which corresponds to the system clock interval + timer that keeps track of time (the Windows heartbeat). We only want to + turn this off at a high-enough IRQL, which is why IRQLs 24 and 25 are the + same to give this guy a chance to come up higher. Note that IRQL 28 is + called CLOCK2_LEVEL, which explains the usage we just explained. + */ + 0b11111111111111111111111111111011, /* IRQL 28 */ + + /* We have finished off with the PIC so there's nothing left to mask at the + level of these IRQLs, making them only logical IRQLs on x86 machines. + Note that we have another 0 "droplet" you might've caught since IRQL 26. + In this case, it's the 2nd bit that never gets turned off, which is IRQ2, + the cascade IRQ that we use to bridge the slave PIC with the master PIC. + We never want to turn it off, so no matter the IRQL, it will be set to 0. + */ + 0b11111111111111111111111111111011, /* IRQL 29 */ + 0b11111111111111111111111111111011, /* IRQL 30 */ + 0b11111111111111111111111111111011 /* IRQL 31 */ +#else + 0, /* IRQL 0 */ + 0, /* IRQL 1 */ + 0, /* IRQL 2 */ + 0, /* IRQL 3 */ + 0xFF800000, /* IRQL 4 */ + 0xFFC00000, /* IRQL 5 */ + 0xFFE00000, /* IRQL 6 */ + 0xFFF00000, /* IRQL 7 */ + 0xFFF80000, /* IRQL 8 */ + 0xFFFC0000, /* IRQL 9 */ + 0xFFFE0000, /* IRQL 10 */ + 0xFFFF0000, /* IRQL 11 */ + 0xFFFF8000, /* IRQL 12 */ + 0xFFFFC000, /* IRQL 13 */ + 0xFFFFE000, /* IRQL 14 */ + 0xFFFFF000, /* IRQL 15 */ + 0xFFFFF800, /* IRQL 16 */ + 0xFFFFFC00, /* IRQL 17 */ + 0xFFFFFE00, /* IRQL 18 */ + 0xFFFFFE00, /* IRQL 19 */ + 0xFFFFFE80, /* IRQL 20 */ + 0xFFFFFEC0, /* IRQL 21 */ + 0xFFFFFEE0, /* IRQL 22 */ + 0xFFFFFEF0, /* IRQL 23 */ + 0xFFFFFEF8, /* IRQL 24 */ + 0xFFFFFEF8, /* IRQL 25 */ + 0xFFFFFEFA, /* IRQL 26 */ + 0xFFFFFFFA, /* IRQL 27 */ + 0xFFFFFFFB, /* IRQL 28 */ + 0xFFFFFFFB, /* IRQL 29 */ + 0xFFFFFFFB, /* IRQL 30 */ + 0xFFFFFFFB /* IRQL 31 */ +#endif +}; + +/* This table indicates which IRQs, if pending, can preempt a given IRQL level */ +ULONG FindHigherIrqlMask[32] = +{ +#if defined(__GNUC__) || defined(__clang__) || (defined(_MSC_VER) && _MSC_VER >= 1900) + /* Software IRQLs, at these levels all hardware interrupts can preempt. + Each higher IRQL simply enables which software IRQL can preempt the + current level. + */ + 0b11111111111111111111111111111110, /* IRQL 0 */ + 0b11111111111111111111111111111100, /* IRQL 1 */ + 0b11111111111111111111111111111000, /* IRQL 2 */ + + /* IRQL3 means only hardware IRQLs can now preempt. These last 4 zeros will + then continue throughout the rest of the list, trickling down. + */ + 0b11111111111111111111111111110000, /* IRQL 3 */ + + /* Just like in the previous list, these masks don't really mean anything + since we've only got two PICs with 16 possible IRQs total + */ + 0b00000111111111111111111111110000, /* IRQL 4 */ + 0b00000011111111111111111111110000, /* IRQL 5 */ + 0b00000001111111111111111111110000, /* IRQL 6 */ + 0b00000000111111111111111111110000, /* IRQL 7 */ + 0b00000000011111111111111111110000, /* IRQL 8 */ + 0b00000000001111111111111111110000, /* IRQL 9 */ + 0b00000000000111111111111111110000, /* IRQL 10 */ + + /* Now we start progressivly limiting which slave PIC interrupts have the + right to preempt us at each level. + */ + 0b00000000000011111111111111110000, /* IRQL 11 */ + 0b00000000000001111111111111110000, /* IRQL 12 */ + 0b00000000000000111111111111110000, /* IRQL 13 */ + 0b00000000000000011111111111110000, /* IRQL 14 */ + 0b00000000000000001111111111110000, /* IRQL 15 */ + 0b00000000000000000111111111110000, /* IRQL 16 */ + 0b00000000000000000011111111110000, /* IRQL 17 */ + 0b00000000000000000001111111110000, /* IRQL 18 */ + 0b00000000000000000001111111110000, /* IRQL 19 */ + + /* Also recall from the earlier table that IRQL 18/19 are treated the same + in order to spread the masks better thoughout the 32 IRQLs and to reflect + the fact that some bits will always stay on until much higher IRQLs since + they are system-critical. One such example is the 1 bit that you start to + see trickling down here. This is IRQ8, the RTC timer used for profiling, + so it will always preempt until we reach PROFILE_LEVEL. + */ + 0b00000000000000000001011111110000, /* IRQL 20 */ + 0b00000000000000000001001111110000, /* IRQL 21 */ + 0b00000000000000000001000111110000, /* IRQL 22 */ + 0b00000000000000000001000011110000, /* IRQL 23 */ + 0b00000000000000000001000001110000, /* IRQL 24 */ + 0b00000000000000000001000000110000, /* IRQL 25 */ + 0b00000000000000000001000000010000, /* IRQL 26 */ + + /* At this point, only the clock (IRQ0) can still preempt... */ + 0b00000000000000000000000000010000, /* IRQL 27 */ + + /* And any higher than that there's no relation with hardware PICs anymore */ + 0b00000000000000000000000000000000, /* IRQL 28 */ + 0b00000000000000000000000000000000, /* IRQL 29 */ + 0b00000000000000000000000000000000, /* IRQL 30 */ + 0b00000000000000000000000000000000 /* IRQL 31 */ +#else + 0xFFFFFFFE, /* IRQL 0 */ + 0xFFFFFFFC, /* IRQL 1 */ + 0xFFFFFFF8, /* IRQL 2 */ + 0xFFFFFFF0, /* IRQL 3 */ + 0x7FFFFF0, /* IRQL 4 */ + 0x3FFFFF0, /* IRQL 5 */ + 0x1FFFFF0, /* IRQL 6 */ + 0x0FFFFF0, /* IRQL 7 */ + 0x7FFFF0, /* IRQL 8 */ + 0x3FFFF0, /* IRQL 9 */ + 0x1FFFF0, /* IRQL 10 */ + 0x0FFFF0, /* IRQL 11 */ + 0x7FFF0, /* IRQL 12 */ + 0x3FFF0, /* IRQL 13 */ + 0x1FFF0, /* IRQL 14 */ + 0x0FFF0, /* IRQL 15 */ + 0x7FF0, /* IRQL 16 */ + 0x3FF0, /* IRQL 17 */ + 0x1FF0, /* IRQL 18 */ + 0x1FF0, /* IRQL 19 */ + 0x17F0, /* IRQL 20 */ + 0x13F0, /* IRQL 21 */ + 0x11F0, /* IRQL 22 */ + 0x10F0, /* IRQL 23 */ + 0x1070, /* IRQL 24 */ + 0x1030, /* IRQL 25 */ + 0x1010, /* IRQL 26 */ + 0x10, /* IRQL 27 */ + 0, /* IRQL 28 */ + 0, /* IRQL 29 */ + 0, /* IRQL 30 */ + 0 /* IRQL 31 */ +#endif +}; + +/* Denotes minimum required IRQL before we can process pending SW interrupts */ +KIRQL SWInterruptLookUpTable[8] = +{ + PASSIVE_LEVEL, /* IRR 0 */ + PASSIVE_LEVEL, /* IRR 1 */ + APC_LEVEL, /* IRR 2 */ + APC_LEVEL, /* IRR 3 */ + DISPATCH_LEVEL, /* IRR 4 */ + DISPATCH_LEVEL, /* IRR 5 */ + DISPATCH_LEVEL, /* IRR 6 */ + DISPATCH_LEVEL /* IRR 7 */ +}; + +/* Pending/delayed hardware interrupt handlers */ +HalpDelayedHardwareInterrupt(0); +HalpDelayedHardwareInterrupt(1); +HalpDelayedHardwareInterrupt(2); +HalpDelayedHardwareInterrupt(3); +HalpDelayedHardwareInterrupt(4); +HalpDelayedHardwareInterrupt(5); +HalpDelayedHardwareInterrupt(6); +HalpDelayedHardwareInterrupt(7); +HalpDelayedHardwareInterrupt(8); +HalpDelayedHardwareInterrupt(9); +HalpDelayedHardwareInterrupt(10); +HalpDelayedHardwareInterrupt(11); +HalpDelayedHardwareInterrupt(12); +HalpDelayedHardwareInterrupt(13); +HalpDelayedHardwareInterrupt(14); +HalpDelayedHardwareInterrupt(15); + +/* Handlers for pending interrupts */ +PHAL_SW_INTERRUPT_HANDLER SWInterruptHandlerTable[20] = +{ + (PHAL_SW_INTERRUPT_HANDLER)KiUnexpectedInterrupt, + HalpApcInterrupt, + HalpDispatchInterrupt, + (PHAL_SW_INTERRUPT_HANDLER)KiUnexpectedInterrupt, + HalpHardwareInterrupt0, + HalpHardwareInterrupt1, + HalpHardwareInterrupt2, + HalpHardwareInterrupt3, + HalpHardwareInterrupt4, + HalpHardwareInterrupt5, + HalpHardwareInterrupt6, + HalpHardwareInterrupt7, + HalpHardwareInterrupt8, + HalpHardwareInterrupt9, + HalpHardwareInterrupt10, + HalpHardwareInterrupt11, + HalpHardwareInterrupt12, + HalpHardwareInterrupt13, + HalpHardwareInterrupt14, + HalpHardwareInterrupt15 +}; + +/* Handlers for pending software interrupts when we already have a trap frame*/ +PHAL_SW_INTERRUPT_HANDLER_2ND_ENTRY SWInterruptHandlerTable2[3] = +{ + (PHAL_SW_INTERRUPT_HANDLER_2ND_ENTRY)KiUnexpectedInterrupt, + HalpApcInterrupt2ndEntry, + HalpDispatchInterrupt2ndEntry +}; + +extern ULONG HalpBusType; +extern IDTUsageFlags HalpIDTUsageFlags[MAXIMUM_IDTVECTOR + 1]; +extern KAFFINITY HalpDefaultInterruptAffinity; + +/* IRQL MANAGEMENT ************************************************************/ + +KIRQL +NTAPI +KeGetCurrentIrql(VOID) +{ + /* Return the IRQL */ + return KeGetPcr()->Irql; +} + +KIRQL +FASTCALL +KfRaiseIrql(IN KIRQL NewIrql) +{ + PKPCR Pcr = KeGetPcr(); + KIRQL CurrentIrql; + + /* Read current IRQL */ + CurrentIrql = Pcr->Irql; + +#if DBG + /* Validate correct raise */ + if (CurrentIrql > NewIrql) + { + /* Crash system */ + Pcr->Irql = PASSIVE_LEVEL; + KeBugCheck(IRQL_NOT_GREATER_OR_EQUAL); + } +#endif + + /* Set new IRQL */ + Pcr->Irql = NewIrql; + + /* Return old IRQL */ + return CurrentIrql; +} + +VOID +FASTCALL +KfLowerIrql(IN KIRQL OldIrql) +{ + ULONG EFlags; + ULONG PendingIrql, PendingIrqlMask; + PKPCR Pcr = KeGetPcr(); + PIC_MASK Mask; + +#if DBG + /* Validate correct lower */ + if (OldIrql > Pcr->Irql) + { + /* Crash system */ + Pcr->Irql = HIGH_LEVEL; + KeBugCheck(IRQL_NOT_LESS_OR_EQUAL); + } +#endif + + /* Save EFlags and disable interrupts */ + EFlags = __readeflags(); + _disable(); + + /* Set old IRQL */ + Pcr->Irql = OldIrql; + + /* Check for pending software interrupts and compare with current IRQL */ + PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[OldIrql]; + if (PendingIrqlMask) + { + /* Check if pending IRQL affects hardware state */ + BitScanReverse(&PendingIrql, PendingIrqlMask); + if (PendingIrql > DISPATCH_LEVEL) + { + /* Set new PIC mask */ + Mask.Both = Pcr->IDR & 0xFFFF; + WRITE_PORT_UCHAR(PIC1_DATA_PORT, Mask.Master); + WRITE_PORT_UCHAR(PIC2_DATA_PORT, Mask.Slave); + + /* Clear IRR bit */ + Pcr->IRR ^= (1 << PendingIrql); + } + + /* Now handle pending interrupt */ + SWInterruptHandlerTable[PendingIrql](); + } + + /* Restore interrupt state */ + __writeeflags(EFlags); +} + +/* SOFTWARE INTERRUPTS ********************************************************/ + +VOID +FASTCALL +HalRequestSoftwareInterrupt(IN KIRQL Irql) +{ + ULONG EFlags; + PKPCR Pcr = KeGetPcr(); + KIRQL PendingIrql; + + /* Save EFlags and disable interrupts */ + EFlags = __readeflags(); + _disable(); + + /* Mask out the requested bit */ + Pcr->IRR |= (1 << Irql); + + /* Check for pending software interrupts and compare with current IRQL */ + PendingIrql = SWInterruptLookUpTable[Pcr->IRR & 3]; + if (PendingIrql > Pcr->Irql) + SWInterruptHandlerTable[PendingIrql](); + + /* Restore interrupt state */ + __writeeflags(EFlags); +} + +PHAL_SW_INTERRUPT_HANDLER_2ND_ENTRY +FASTCALL +HalpEndSoftwareInterrupt2(IN KIRQL OldIrql, + IN PKTRAP_FRAME TrapFrame) +{ + ULONG PendingIrql, PendingIrqlMask, PendingIrqMask; + PKPCR Pcr = KeGetPcr(); + PIC_MASK Mask; + + UNREFERENCED_PARAMETER(TrapFrame); + + /* Set old IRQL */ + Pcr->Irql = OldIrql; + + /* Loop checking for pending interrupts */ + while (TRUE) + { + /* Check for pending software interrupts and compare with current IRQL */ + PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[OldIrql]; + if (!PendingIrqlMask) + return NULL; + + /* Check for in-service delayed interrupt */ + if (Pcr->IrrActive & 0xFFFFFFF0) + return NULL; + + /* Check if pending IRQL affects hardware state */ + BitScanReverse(&PendingIrql, PendingIrqlMask); + if (PendingIrql <= DISPATCH_LEVEL) + { + /* No need to loop checking for hardware interrupts */ + return SWInterruptHandlerTable2[PendingIrql]; + } + + /* Set new PIC mask */ + Mask.Both = Pcr->IDR & 0xFFFF; + WRITE_PORT_UCHAR(PIC1_DATA_PORT, Mask.Master); + WRITE_PORT_UCHAR(PIC2_DATA_PORT, Mask.Slave); + + /* Set active bit otherwise, and clear it from IRR */ + PendingIrqMask = (1 << PendingIrql); + Pcr->IrrActive |= PendingIrqMask; + Pcr->IRR ^= PendingIrqMask; + + /* Handle delayed hardware interrupt */ + SWInterruptHandlerTable[PendingIrql](); + + /* Handling complete */ + Pcr->IrrActive ^= PendingIrqMask; + } + + return NULL; +} + +/* EDGE INTERRUPT DISMISSAL FUNCTIONS *****************************************/ + +FORCEINLINE +BOOLEAN +_HalpDismissIrqGeneric(IN KIRQL Irql, + IN ULONG Irq, + OUT PKIRQL OldIrql) +{ + PIC_MASK Mask; + KIRQL CurrentIrql; + I8259_OCW2 Ocw2; + PKPCR Pcr = KeGetPcr(); + + /* First save current IRQL and compare it to the requested one */ + CurrentIrql = Pcr->Irql; + + /* Check if this interrupt is really allowed to happen */ + if (Irql > CurrentIrql) + { + /* Set the new IRQL and return the current one */ + Pcr->Irql = Irql; + *OldIrql = CurrentIrql; + + /* Prepare OCW2 for EOI */ + Ocw2.Bits = 0; + Ocw2.EoiMode = SpecificEoi; + + /* Check which PIC needs the EOI */ + if (Irq >= 8) + { + /* Send the EOI for the IRQ */ + WRITE_PORT_UCHAR(PIC2_CONTROL_PORT, Ocw2.Bits | ((Irq - 8) & 0xFF)); + + /* Send the EOI for IRQ2 on the master because this was cascaded */ + WRITE_PORT_UCHAR(PIC1_CONTROL_PORT, Ocw2.Bits | 2); + } + else + { + /* Send the EOI for the IRQ */ + WRITE_PORT_UCHAR(PIC1_CONTROL_PORT, Ocw2.Bits | (Irq &0xFF)); + } + + /* Enable interrupts and return success */ + _enable(); + return TRUE; + } + + /* Update the IRR so that we deliver this interrupt when the IRQL is proper */ + Pcr->IRR |= (1 << (Irq + 4)); + //DPRINT1("_HalpDismissIrqGeneric: Irql - %X, Pcr->IRR - %X\n", Irql, Pcr->IRR); + + /* Set new PIC mask to real IRQL level, since the optimization is lost now */ + Mask.Both = (KiI8259MaskTable[CurrentIrql] | Pcr->IDR) & 0xFFFF; + WRITE_PORT_UCHAR(PIC1_DATA_PORT, Mask.Master); + WRITE_PORT_UCHAR(PIC2_DATA_PORT, Mask.Slave); + + /* Now lie and say this was spurious */ + return FALSE; +} + +BOOLEAN +NTAPI +HalpDismissIrqGeneric(IN KIRQL Irql, + IN ULONG Irq, + OUT PKIRQL OldIrql) +{ + /* Run the inline code */ + return _HalpDismissIrqGeneric(Irql, Irq, OldIrql); +} + +BOOLEAN +NTAPI +HalpDismissIrq07(IN KIRQL Irql, + IN ULONG Irq, + OUT PKIRQL OldIrql) +{ + I8259_OCW3 Ocw3; + I8259_ISR Isr; + + /* Request the ISR */ + Ocw3.Bits = 0; + Ocw3.Sbo = 1; + Ocw3.ReadRequest = ReadIsr; + WRITE_PORT_UCHAR(PIC1_CONTROL_PORT, Ocw3.Bits); + + /* Read the ISR */ + Isr.Bits = READ_PORT_UCHAR(PIC1_CONTROL_PORT); + + /* Is IRQ 7 really active? If it isn't, this is spurious so fail */ + if (Isr.Irq7 == FALSE) + return FALSE; + + /* Do normal interrupt dismiss */ + return _HalpDismissIrqGeneric(Irql, Irq, OldIrql); +} + +BOOLEAN +NTAPI +HalpDismissIrq13(IN KIRQL Irql, + IN ULONG Irq, + OUT PKIRQL OldIrql) +{ + /* Clear the FPU busy latch */ + WRITE_PORT_UCHAR((PUCHAR)0x00F0, 0); + + /* Do normal interrupt dismiss */ + return _HalpDismissIrqGeneric(Irql, Irq, OldIrql); +} + +BOOLEAN +NTAPI +HalpDismissIrq15(IN KIRQL Irql, + IN ULONG Irq, + OUT PKIRQL OldIrql) +{ + I8259_OCW3 Ocw3; + I8259_OCW2 Ocw2; + I8259_ISR Isr; + + /* Request the ISR */ + Ocw3.Bits = 0; + Ocw3.Sbo = 1; /* This encodes an OCW3 vs. an OCW2 */ + Ocw3.ReadRequest = ReadIsr; + WRITE_PORT_UCHAR(PIC2_CONTROL_PORT, Ocw3.Bits); + + /* Read the ISR */ + Isr.Bits = READ_PORT_UCHAR(PIC2_CONTROL_PORT); + + /* Is IRQ15 really active (this is IR7) */ + if (Isr.Irq7 == FALSE) + { + /* It isn't, so we have to EOI IRQ2 because this was cascaded */ + Ocw2.Bits = 0; + Ocw2.EoiMode = SpecificEoi; + WRITE_PORT_UCHAR(PIC1_CONTROL_PORT, Ocw2.Bits | 2); + + /* And now fail since this was spurious */ + return FALSE; + } + + /* Do normal interrupt dismiss */ + return _HalpDismissIrqGeneric(Irql, Irq, OldIrql); +} + +/* LEVEL INTERRUPT DISMISSAL FUNCTIONS ****************************************/ + +FORCEINLINE +BOOLEAN +_HalpDismissIrqLevel(IN KIRQL Irql, + IN ULONG Irq, + OUT PKIRQL OldIrql) +{ + PIC_MASK Mask; + KIRQL CurrentIrql; + I8259_OCW2 Ocw2; + PKPCR Pcr = KeGetPcr(); + + /* Update the PIC */ + Mask.Both = (KiI8259MaskTable[Irql] | Pcr->IDR) & 0xFFFF; + WRITE_PORT_UCHAR(PIC1_DATA_PORT, Mask.Master); + WRITE_PORT_UCHAR(PIC2_DATA_PORT, Mask.Slave); + + /* Update the IRR so that we clear this interrupt when the IRQL is proper */ + Pcr->IRR |= (1 << (Irq + 4)); + + /* Save current IRQL */ + CurrentIrql = Pcr->Irql; + + /* Prepare OCW2 for EOI */ + Ocw2.Bits = 0; + Ocw2.EoiMode = SpecificEoi; + + /* Check which PIC needs the EOI */ + if (Irq >= 8) + { + /* Send the EOI for the IRQ */ + WRITE_PORT_UCHAR(PIC2_CONTROL_PORT, Ocw2.Bits | ((Irq - 8) & 0xFF)); + + /* Send the EOI for IRQ2 on the master because this was cascaded */ + WRITE_PORT_UCHAR(PIC1_CONTROL_PORT, Ocw2.Bits | 2); + } + else + { + /* Send the EOI for the IRQ */ + WRITE_PORT_UCHAR(PIC1_CONTROL_PORT, Ocw2.Bits | (Irq & 0xFF)); + } + + /* Check if this interrupt should be allowed to happen */ + if (Irql > CurrentIrql) + { + /* Set the new IRQL and return the current one */ + Pcr->Irql = Irql; + *OldIrql = CurrentIrql; + + /* Enable interrupts and return success */ + _enable(); + return TRUE; + } + + /* Now lie and say this was spurious */ + return FALSE; +} + +BOOLEAN +NTAPI +HalpDismissIrqLevel(IN KIRQL Irql, + IN ULONG Irq, + OUT PKIRQL OldIrql) +{ + /* Run the inline code */ + return _HalpDismissIrqLevel(Irql, Irq, OldIrql); +} + +BOOLEAN +NTAPI +HalpDismissIrq07Level(IN KIRQL Irql, + IN ULONG Irq, + OUT PKIRQL OldIrql) +{ + I8259_OCW3 Ocw3; + I8259_ISR Isr; + + /* Request the ISR */ + Ocw3.Bits = 0; + Ocw3.Sbo = 1; + Ocw3.ReadRequest = ReadIsr; + WRITE_PORT_UCHAR(PIC1_CONTROL_PORT, Ocw3.Bits); + + /* Read the ISR */ + Isr.Bits = READ_PORT_UCHAR(PIC1_CONTROL_PORT); + + /* Is IRQ 7 really active? If it isn't, this is spurious so fail */ + if (Isr.Irq7 == FALSE) + return FALSE; + + /* Do normal interrupt dismiss */ + return _HalpDismissIrqLevel(Irql, Irq, OldIrql); +} + +BOOLEAN +NTAPI +HalpDismissIrq13Level(IN KIRQL Irql, + IN ULONG Irq, + OUT PKIRQL OldIrql) +{ + /* Clear the FPU busy latch */ + WRITE_PORT_UCHAR((PUCHAR)0x00F0, 0); + + /* Do normal interrupt dismiss */ + return _HalpDismissIrqLevel(Irql, Irq, OldIrql); +} + +BOOLEAN +NTAPI +HalpDismissIrq15Level(IN KIRQL Irql, + IN ULONG Irq, + OUT PKIRQL OldIrql) +{ + I8259_OCW3 Ocw3; + I8259_OCW2 Ocw2; + I8259_ISR Isr; + + /* Request the ISR */ + Ocw3.Bits = 0; + Ocw3.Sbo = 1; /* This encodes an OCW3 vs. an OCW2 */ + Ocw3.ReadRequest = ReadIsr; + WRITE_PORT_UCHAR(PIC2_CONTROL_PORT, Ocw3.Bits); + + /* Read the ISR */ + Isr.Bits = READ_PORT_UCHAR(PIC2_CONTROL_PORT); + + /* Is IRQ15 really active (this is IR7) */ + if (Isr.Irq7 == FALSE) + { + /* It isn't, so we have to EOI IRQ2 because this was cascaded */ + Ocw2.Bits = 0; + Ocw2.EoiMode = SpecificEoi; + WRITE_PORT_UCHAR(PIC1_CONTROL_PORT, Ocw2.Bits | 2); + + /* And now fail since this was spurious */ + return FALSE; + } + + /* Do normal interrupt dismiss */ + return _HalpDismissIrqLevel(Irql, Irq, OldIrql); +} + +PHAL_SW_INTERRUPT_HANDLER +__cdecl +HalpHardwareInterruptLevel2(VOID) +{ + PKPCR Pcr = KeGetPcr(); + ULONG PendingIrqlMask, PendingIrql; + + /* Check for pending software interrupts and compare with current IRQL */ + PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[Pcr->Irql]; + if (!PendingIrqlMask) + return NULL; + + /* Check for in-service delayed interrupt */ + if (Pcr->IrrActive & 0xFFFFFFF0) + return NULL; + + /* Check if pending IRQL affects hardware state */ + BitScanReverse(&PendingIrql, PendingIrqlMask); + + /* Clear IRR bit */ + Pcr->IRR ^= (1 << PendingIrql); + + /* Now handle pending interrupt */ + return SWInterruptHandlerTable[PendingIrql]; +} + +/* SYSTEM INTERRUPTS **********************************************************/ + +BOOLEAN +NTAPI +HalEnableSystemInterrupt(IN ULONG Vector, + IN KIRQL Irql, + IN KINTERRUPT_MODE InterruptMode) +{ + ULONG Irq; + PKPCR Pcr = KeGetPcr(); + PIC_MASK PicMask; + + /* Validate the IRQ */ + Irq = Vector - PRIMARY_VECTOR_BASE; // Vector = (PRIMARY_VECTOR_BASE + Irq); + if ((Vector < PRIMARY_VECTOR_BASE) || (Irq >= CLOCK2_LEVEL)) + { + DPRINT1("HalEnableSystemInterrupt: wrong Vector!\n"); + __debugbreak(); + return FALSE; + } + + // ? EISA_CONTROL.Pic1EdgeLevel|Pic2EdgeLevel + + /* Check for level interrupt */ + if (InterruptMode == LevelSensitive) // 0 + { + /* Switch handler to level */ + SWInterruptHandlerTable[Irq + 4] = HalpHardwareInterruptLevel; + + /* Switch dismiss to level */ + HalpSpecialDismissTable[Irq] = HalpSpecialDismissLevelTable[Irq]; + } + + /* Disable interrupts */ + _disable(); + + /* Update software IDR */ + Pcr->IDR &= ~(1 << Irq); + + /* Set new PIC mask */ + PicMask.Both = (KiI8259MaskTable[Pcr->Irql] | Pcr->IDR) & 0xFFFF; + WRITE_PORT_UCHAR(PIC1_DATA_PORT, PicMask.Master); + WRITE_PORT_UCHAR(PIC2_DATA_PORT, PicMask.Slave); + + /* Enable interrupts and exit */ + _enable(); + return TRUE; +} + +VOID +NTAPI +HalDisableSystemInterrupt(IN ULONG Vector, + IN KIRQL Irql) +{ + ULONG IrqMask; + PIC_MASK PicMask; + + /* Compute new combined IRQ mask */ + IrqMask = 1 << (Vector - PRIMARY_VECTOR_BASE); + + /* Disable interrupts */ + _disable(); + + /* Update software IDR */ + KeGetPcr()->IDR |= IrqMask; + + /* Read current interrupt mask */ + PicMask.Master = READ_PORT_UCHAR(PIC1_DATA_PORT); + PicMask.Slave = READ_PORT_UCHAR(PIC2_DATA_PORT); + + /* Add the new disabled interrupt */ + PicMask.Both |= IrqMask; + + /* Write new interrupt mask */ + WRITE_PORT_UCHAR(PIC1_DATA_PORT, PicMask.Master); + WRITE_PORT_UCHAR(PIC2_DATA_PORT, PicMask.Slave); + + /* Bring interrupts back */ + _enable(); +} + +BOOLEAN +NTAPI +HalBeginSystemInterrupt(IN KIRQL Irql, + IN ULONG Vector, + OUT PKIRQL OldIrql) +{ + ULONG Irq; + + /* Get the IRQ and call the proper routine to handle it */ + Irq = Vector - PRIMARY_VECTOR_BASE; + return HalpSpecialDismissTable[Irq](Irql, Irq, OldIrql); +} + +PHAL_SW_INTERRUPT_HANDLER_2ND_ENTRY +FASTCALL +HalEndSystemInterrupt2(IN KIRQL OldIrql, + IN PKTRAP_FRAME TrapFrame) +{ + ULONG PendingIrql, PendingIrqlMask, PendingIrqMask; + PKPCR Pcr = KeGetPcr(); + PIC_MASK Mask; + + /* Set old IRQL */ + Pcr->Irql = OldIrql; + + /* Check for pending software interrupts and compare with current IRQL */ + PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[OldIrql]; + if (!PendingIrqlMask) + return NULL; + + /* Check for in-service delayed interrupt */ + if (Pcr->IrrActive & 0xFFFFFFF0) + return NULL; + + /* Loop checking for pending interrupts */ + while (TRUE) + { + /* Check if pending IRQL affects hardware state */ + BitScanReverse(&PendingIrql, PendingIrqlMask); + if (PendingIrql <= DISPATCH_LEVEL) + { + /* Now handle pending software interrupt */ + return SWInterruptHandlerTable2[PendingIrql]; + } + + /* Set new PIC mask */ + Mask.Both = Pcr->IDR & 0xFFFF; + WRITE_PORT_UCHAR(PIC1_DATA_PORT, Mask.Master); + WRITE_PORT_UCHAR(PIC2_DATA_PORT, Mask.Slave); + + /* Now check if this specific interrupt is already in-service */ + PendingIrqMask = (1 << PendingIrql); + if (Pcr->IrrActive & PendingIrqMask) + return NULL; + + /* Set active bit otherwise, and clear it from IRR */ + Pcr->IrrActive |= PendingIrqMask; + Pcr->IRR ^= PendingIrqMask; + + /* Handle delayed hardware interrupt */ + SWInterruptHandlerTable[PendingIrql](); + + /* Handling complete */ + Pcr->IrrActive ^= PendingIrqMask; + + /* Check if there's still interrupts pending */ + PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[Pcr->Irql]; + if (!PendingIrqlMask) + break; + } + + return NULL; +} + +/* SOFTWARE INTERRUPT TRAPS ***************************************************/ + +FORCEINLINE +DECLSPEC_NORETURN +VOID +_HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame) +{ + KIRQL CurrentIrql; + PKPCR Pcr = KeGetPcr(); + + /* Save the current IRQL and update it */ + CurrentIrql = Pcr->Irql; + Pcr->Irql = APC_LEVEL; + + /* Remove DPC from IRR */ + Pcr->IRR &= ~(1 << APC_LEVEL); + + /* Enable interrupts and call the kernel's APC interrupt handler */ + _enable(); + KiDeliverApc(((KiUserTrap(TrapFrame)) || (TrapFrame->EFlags & EFLAGS_V86_MASK)) ? + UserMode : KernelMode, + NULL, + TrapFrame); + + /* Disable interrupts and end the interrupt */ + _disable(); + HalpEndSoftwareInterrupt(CurrentIrql, TrapFrame); + + /* Exit the interrupt */ + KiEoiHelper(TrapFrame); +} + +DECLSPEC_NORETURN +VOID +FASTCALL +HalpApcInterrupt2ndEntry(IN PKTRAP_FRAME TrapFrame) +{ + /* Do the work */ + _HalpApcInterruptHandler(TrapFrame); +} + +DECLSPEC_NORETURN +VOID +FASTCALL +HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame) +{ + /* Set up a fake INT Stack */ + TrapFrame->EFlags = __readeflags(); + TrapFrame->SegCs = KGDT_R0_CODE; + TrapFrame->Eip = TrapFrame->Eax; + + /* Build the trap frame */ + KiEnterInterruptTrap(TrapFrame); + + /* Do the work */ + _HalpApcInterruptHandler(TrapFrame); +} + +FORCEINLINE +KIRQL +_HalpDispatchInterruptHandler(VOID) +{ + KIRQL CurrentIrql; + PKPCR Pcr = KeGetPcr(); + + /* Save the current IRQL and update it */ + CurrentIrql = Pcr->Irql; + Pcr->Irql = DISPATCH_LEVEL; + + /* Remove DPC from IRR */ + Pcr->IRR &= ~(1 << DISPATCH_LEVEL); + + /* Enable interrupts and call the kernel's DPC interrupt handler */ + _enable(); + KiDispatchInterrupt(); + _disable(); + + /* Return IRQL */ + return CurrentIrql; +} + +DECLSPEC_NORETURN +VOID +FASTCALL +HalpDispatchInterrupt2ndEntry(IN PKTRAP_FRAME TrapFrame) +{ + KIRQL CurrentIrql; + + /* Do the work */ + CurrentIrql = _HalpDispatchInterruptHandler(); + + /* End the interrupt */ + HalpEndSoftwareInterrupt(CurrentIrql, TrapFrame); + + /* Exit the interrupt */ + KiEoiHelper(TrapFrame); +} + +PHAL_SW_INTERRUPT_HANDLER +__cdecl +HalpDispatchInterrupt2(VOID) +{ + ULONG PendingIrqlMask, PendingIrql; + KIRQL OldIrql; + PIC_MASK Mask; + PKPCR Pcr = KeGetPcr(); + + /* Do the work */ + OldIrql = _HalpDispatchInterruptHandler(); + + /* Restore IRQL */ + Pcr->Irql = OldIrql; + + /* Check for pending software interrupts and compare with current IRQL */ + PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[OldIrql]; + if (!PendingIrqlMask) + return NULL; + + /* Check if pending IRQL affects hardware state */ + BitScanReverse(&PendingIrql, PendingIrqlMask); + if (PendingIrql > DISPATCH_LEVEL) + { + /* Set new PIC mask */ + Mask.Both = Pcr->IDR & 0xFFFF; + WRITE_PORT_UCHAR(PIC1_DATA_PORT, Mask.Master); + WRITE_PORT_UCHAR(PIC2_DATA_PORT, Mask.Slave); + + /* Clear IRR bit */ + Pcr->IRR ^= (1 << PendingIrql); + } + + /* Now handle pending interrupt */ + return SWInterruptHandlerTable[PendingIrql]; +} + +/* FUNCTIONS ******************************************************************/ + +VOID +NTAPI +HalpInitializeLegacyPICs(BOOLEAN InterruptMode) +{ + I8259_ICW1 Icw1; + I8259_ICW2 Icw2; + I8259_ICW3 Icw3; + I8259_ICW4 Icw4; + + ASSERT(!(__readeflags() & EFLAGS_INTERRUPT_MASK)); + + /* Initialize ICW1 for master, interval 8 */ + Icw1.NeedIcw4 = TRUE; + Icw1.OperatingMode = Cascade; + Icw1.Interval = Interval8; + //Icw1.InterruptMode = EdgeTriggered; + Icw1.InterruptMode = InterruptMode ? LevelTriggered : EdgeTriggered; + Icw1.Init = TRUE; + Icw1.InterruptVectorAddress = 0; + WRITE_PORT_UCHAR(PIC1_CONTROL_PORT, Icw1.Bits); + + /* ICW2 - interrupt vector offset */ + Icw2.Bits = PRIMARY_VECTOR_BASE; + WRITE_PORT_UCHAR(PIC1_DATA_PORT, Icw2.Bits); + + /* Connect slave to IRQ 2 */ + Icw3.Bits = 0; + Icw3.SlaveIrq2 = TRUE; + WRITE_PORT_UCHAR(PIC1_DATA_PORT, Icw3.Bits); + + /* Enable 8086 mode, non-automatic EOI, non-buffered mode, non special fully nested mode */ + Icw4.SystemMode = New8086Mode; + Icw4.EoiMode = NormalEoi; + Icw4.BufferedMode = NonBuffered; + Icw4.SpecialFullyNestedMode = FALSE; + Icw4.Reserved = 0; + WRITE_PORT_UCHAR(PIC1_DATA_PORT, Icw4.Bits); + + /* Mask all interrupts */ + WRITE_PORT_UCHAR(PIC1_DATA_PORT, 0xFF); + + /* Initialize ICW1 for slave, interval 8 */ + Icw1.NeedIcw4 = TRUE; + //Icw1.InterruptMode = EdgeTriggered; + Icw1.InterruptMode = InterruptMode ? LevelTriggered : EdgeTriggered; + Icw1.OperatingMode = Cascade; + Icw1.Interval = Interval8; + Icw1.Init = TRUE; + Icw1.InterruptVectorAddress = 0; /* This is only used in MCS80/85 mode */ + WRITE_PORT_UCHAR(PIC2_CONTROL_PORT, Icw1.Bits); + + /* Set interrupt vector base */ + Icw2.Bits = PRIMARY_VECTOR_BASE + 8; + WRITE_PORT_UCHAR(PIC2_DATA_PORT, Icw2.Bits); + + /* Slave ID */ + Icw3.Bits = 0; + Icw3.SlaveId = 2; + WRITE_PORT_UCHAR(PIC2_DATA_PORT, Icw3.Bits); + + /* Enable 8086 mode, non-automatic EOI, non-buffered mode, non special fully nested mode */ + Icw4.SystemMode = New8086Mode; + Icw4.EoiMode = NormalEoi; + Icw4.BufferedMode = NonBuffered; + Icw4.SpecialFullyNestedMode = FALSE; + Icw4.Reserved = 0; + WRITE_PORT_UCHAR(PIC2_DATA_PORT, Icw4.Bits); + + /* Mask all interrupts */ + WRITE_PORT_UCHAR(PIC2_DATA_PORT, 0xFF); +} + +VOID +NTAPI +HalpInitializePICs(IN BOOLEAN EnableInterrupts) +{ + ULONG EFlags; + BOOLEAN InterruptMode = FALSE; // EdgeTriggered + + DPRINT1("HalpInitializePICs: EnableInterrupts - %X\n", EnableInterrupts); + + /* Save EFlags and disable interrupts */ + EFlags = __readeflags(); + _disable(); + + if (HalpBusType & 2) + { + DPRINT1("HalpInitializePICs: HalpBusType - %X\n", HalpBusType); + ASSERT(0);//DbgBreakPoint(); + //InterruptMode = TRUE; // LevelTriggered + } + + DPRINT1("HalpInitializePICs: InterruptMode - %X\n", InterruptMode); + + /* Initialize and mask the PIC */ + HalpInitializeLegacyPICs(InterruptMode); + + /* Restore interrupt state */ + if (EnableInterrupts) + EFlags |= EFLAGS_INTERRUPT_MASK; + + __writeeflags(EFlags); +} + +ULONG +NTAPI +HalpGetRootInterruptVector(ULONG Level, + ULONG Vector, + PKIRQL OutIrql, + PKAFFINITY OutAffinity) +{ + ULONG RootVector; + + DPRINT("HalpGetRootInterruptVector: Level %X\n", Level); + + if (Level >= 0xFFFFFFD0 || Level > PROFILE_LEVEL) + { + DPRINT1("HalpGetRootInterruptVector: return 0. Level %X\n", Level); + return 0; + } + + *OutIrql = (PROFILE_LEVEL - Level); + *OutAffinity = HalpDefaultInterruptAffinity; + + ASSERT(HalpDefaultInterruptAffinity); + + RootVector = (PRIMARY_VECTOR_BASE + Level); + + DPRINT("HalpGetRootInterruptVector: Vector %X, Irql %X [%X]\n", RootVector, *OutIrql, *OutAffinity); + + return RootVector; +} + +NTSTATUS +NTAPI +HalIrqTranslateResourcesRoot(_Inout_opt_ PVOID Context, + _In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR Source, + _In_ RESOURCE_TRANSLATION_DIRECTION Direction, + _In_opt_ ULONG AlternativesCount, + _In_opt_ IO_RESOURCE_DESCRIPTOR Alternatives[], + _In_ PDEVICE_OBJECT PhysicalDeviceObject, + _Out_ PCM_PARTIAL_RESOURCE_DESCRIPTOR Target) +{ + ULONG RootVector; + KAFFINITY Affinity; + KIRQL Irql; + + PAGED_CODE(); + DPRINT1("HalIrqTranslateResourcesRoot: [%X] Source %X, Dir %X, Count %X, Alt %X\n", PhysicalDeviceObject, Source, Direction, AlternativesCount, Alternatives); + + ASSERT(Source->Type == CmResourceTypeInterrupt); + + RtlCopyMemory(Target, Source, sizeof(*Target)); + + if (Direction != 0 && Direction != 1) + { + DPRINT1("HalIrqTranslateResourcesRoot: STATUS_INVALID_PARAMETER\n"); + return STATUS_INVALID_PARAMETER; + } + + if (Direction == 1) + { + Irql = (Source->u.Interrupt.Vector - PRIMARY_VECTOR_BASE); + + Target->u.Interrupt.Vector = Irql; + Target->u.Interrupt.Level = Irql; + + Target->u.Interrupt.Affinity = -1; + + return STATUS_SUCCESS; + } + + RootVector = HalpGetRootInterruptVector(Source->u.Interrupt.Level, + Source->u.Interrupt.Vector, + &Irql, + &Affinity); + if (!RootVector) + { + DPRINT1("HalIrqTranslateResourcesRoot: STATUS_UNSUCCESSFUL\n"); + return STATUS_UNSUCCESSFUL; + } + + Target->u.Interrupt.Vector = RootVector; + Target->u.Interrupt.Level = Irql; + Target->u.Interrupt.Affinity = Affinity; + + return STATUS_TRANSLATION_COMPLETE; +} + +ULONG +NTAPI +HalpGetSystemInterruptVector(IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity) +{ + ULONG Vector; + + /* Get the root vector */ + Vector = HalpGetRootInterruptVector(BusInterruptLevel, + BusInterruptVector, + Irql, + Affinity); + + /* Check if the vector is owned by the HAL and fail if it is */ + if (HalpIDTUsageFlags[Vector].Flags & IDT_REGISTERED) + { + DPRINT1("Vector %lx is ALREADY IN USE!\n", Vector); + return 0; + } + + return Vector; +} + +NTSTATUS +NTAPI +HalIrqTranslateResourceRequirementsRoot(_Inout_opt_ PVOID Context, + _In_ PIO_RESOURCE_DESCRIPTOR InIoDesc, // Source + _In_ PDEVICE_OBJECT DeviceObject, // PhysicalDeviceObject, + _Out_ PULONG OutIoDescCount, // TargetCount, + _Out_ PIO_RESOURCE_DESCRIPTOR* OutIoDesc) // Target +{ + PIO_RESOURCE_DESCRIPTOR IoDesc; + KAFFINITY Affinity; + KIRQL Irql; + + PAGED_CODE(); + DPRINT1("HalIrqTranslateResourceRequirementsRoot: [Src] Min %X, Max %X\n", + InIoDesc->u.Interrupt.MinimumVector, + InIoDesc->u.Interrupt.MaximumVector); + + ASSERT(InIoDesc->Type == CmResourceTypeInterrupt); + + IoDesc = ExAllocatePoolWithTag(PagedPool, sizeof(IO_RESOURCE_DESCRIPTOR), TAG_HAL); + *OutIoDesc = IoDesc; + if (!IoDesc) + { + DPRINT1("HalIrqTranslateResourceRequirementsRoot: Allocate descriptor failed\n"); + ASSERT(FALSE); + return STATUS_INSUFFICIENT_RESOURCES; + } + + *OutIoDescCount = 1; + + RtlCopyMemory(*OutIoDesc, InIoDesc, sizeof(IO_RESOURCE_DESCRIPTOR)); + + (*OutIoDesc)->u.Interrupt.MinimumVector = + HalpGetRootInterruptVector(InIoDesc->u.Interrupt.MinimumVector, + InIoDesc->u.Interrupt.MinimumVector, + &Irql, + &Affinity); + + (*OutIoDesc)->u.Interrupt.MaximumVector = + HalpGetRootInterruptVector(InIoDesc->u.Interrupt.MaximumVector, + InIoDesc->u.Interrupt.MaximumVector, + &Irql, + &Affinity); + + DPRINT1("HalIrqTranslateResourceRequirementsRoot: [Trgt] Min %X, Max %X\n", + (*OutIoDesc)->u.Interrupt.MinimumVector, + (*OutIoDesc)->u.Interrupt.MaximumVector); + + return STATUS_TRANSLATION_COMPLETE; +} + +/* PUBLIC FUNCTIONS **********************************************************/ + +VOID +FASTCALL +HalClearSoftwareInterrupt(IN KIRQL Irql) +{ + /* Mask out the requested bit */ + KeGetPcr()->IRR &= ~(1 << Irql); +} + +KIRQL +NTAPI +KeRaiseIrqlToDpcLevel(VOID) +{ + PKPCR Pcr = KeGetPcr(); + KIRQL CurrentIrql; + + /* Save and update IRQL */ + CurrentIrql = Pcr->Irql; + Pcr->Irql = DISPATCH_LEVEL; + +#if DBG + /* Validate correct raise */ + if (CurrentIrql > DISPATCH_LEVEL) + KeBugCheck(IRQL_NOT_GREATER_OR_EQUAL); +#endif + + /* Return the previous value */ + return CurrentIrql; +} + +KIRQL +NTAPI +KeRaiseIrqlToSynchLevel(VOID) +{ + PKPCR Pcr = KeGetPcr(); + KIRQL CurrentIrql; + + /* Save and update IRQL */ + CurrentIrql = Pcr->Irql; + Pcr->Irql = SYNCH_LEVEL; + +#if DBG + /* Validate correct raise */ + if (CurrentIrql > SYNCH_LEVEL) + { + /* Crash system */ + KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL, + CurrentIrql, + SYNCH_LEVEL, + 0, + 1); + } +#endif + + /* Return the previous value */ + return CurrentIrql; +} + +/* EOF */ diff --git a/hal/halacpi/pic/pic.h b/hal/halacpi/pic/pic.h new file mode 100644 index 0000000000000..0486dddacd56d --- /dev/null +++ b/hal/halacpi/pic/pic.h @@ -0,0 +1,345 @@ + +#pragma once + +/* See ISA System Architecture 3rd Edition (Tom Shanley, Don Anderson, John Swindle) P. 396, 397 + These ports are controlled by the i8259 Programmable Interrupt Controller (PIC) +*/ +#define PIC1_CONTROL_PORT (PUCHAR)0x0020 +#define PIC1_DATA_PORT (PUCHAR)0x0021 +#define PIC2_CONTROL_PORT (PUCHAR)0x00A0 +#define PIC2_DATA_PORT (PUCHAR)0x00A1 + +/* Definitions for ICW/OCW Bits */ +typedef enum _I8259_ICW1_OPERATING_MODE +{ + Cascade, + Single +} I8259_ICW1_OPERATING_MODE; + +typedef enum _I8259_ICW1_INTERRUPT_MODE +{ + EdgeTriggered, + LevelTriggered +} I8259_ICW1_INTERRUPT_MODE; + +typedef enum _I8259_ICW1_INTERVAL +{ + Interval8, + Interval4 +} I8259_ICW1_INTERVAL; + +typedef enum _I8259_ICW4_SYSTEM_MODE +{ + Mcs8085Mode, + New8086Mode +} I8259_ICW4_SYSTEM_MODE; + +typedef enum _I8259_ICW4_EOI_MODE +{ + NormalEoi, + AutomaticEoi +} I8259_ICW4_EOI_MODE; + +typedef enum _I8259_ICW4_BUFFERED_MODE +{ + NonBuffered, + NonBuffered2, + BufferedSlave, + BufferedMaster +} I8259_ICW4_BUFFERED_MODE; + +typedef enum _I8259_READ_REQUEST +{ + InvalidRequest, + InvalidRequest2, + ReadIdr, + ReadIsr +} I8259_READ_REQUEST; + +typedef enum _I8259_EOI_MODE +{ + RotateAutoEoiClear, + NonSpecificEoi, + InvalidEoiMode, + SpecificEoi, + RotateAutoEoiSet, + RotateNonSpecific, + SetPriority, + RotateSpecific +} I8259_EOI_MODE; + +/* Definitions for ICW Registers */ +typedef union _I8259_ICW1 +{ + struct + { + UCHAR NeedIcw4:1; + UCHAR OperatingMode:1; + UCHAR Interval:1; + UCHAR InterruptMode:1; + UCHAR Init:1; + UCHAR InterruptVectorAddress:3; + }; + UCHAR Bits; +} I8259_ICW1, *PI8259_ICW1; + +typedef union _I8259_ICW2 +{ + struct + { + UCHAR Sbz:3; + UCHAR InterruptVector:5; + }; + UCHAR Bits; +} I8259_ICW2, *PI8259_ICW2; + +typedef union _I8259_ICW3 +{ + union + { + struct + { + UCHAR SlaveIrq0:1; + UCHAR SlaveIrq1:1; + UCHAR SlaveIrq2:1; + UCHAR SlaveIrq3:1; + UCHAR SlaveIrq4:1; + UCHAR SlaveIrq5:1; + UCHAR SlaveIrq6:1; + UCHAR SlaveIrq7:1; + }; + struct + { + UCHAR SlaveId:3; + UCHAR Reserved:5; + }; + }; + UCHAR Bits; +} I8259_ICW3, *PI8259_ICW3; + +typedef union _I8259_ICW4 +{ + struct + { + UCHAR SystemMode:1; + UCHAR EoiMode:1; + UCHAR BufferedMode:2; + UCHAR SpecialFullyNestedMode:1; + UCHAR Reserved:3; + }; + UCHAR Bits; +} I8259_ICW4, *PI8259_ICW4; + +typedef union _I8259_OCW2 +{ + struct + { + UCHAR IrqNumber:3; + UCHAR Sbz:2; + UCHAR EoiMode:3; + }; + UCHAR Bits; +} I8259_OCW2, *PI8259_OCW2; + +typedef union _I8259_OCW3 +{ + struct + { + UCHAR ReadRequest:2; + UCHAR PollCommand:1; + UCHAR Sbo:1; + UCHAR Sbz:1; + UCHAR SpecialMaskMode:2; + UCHAR Reserved:1; + }; + UCHAR Bits; +} I8259_OCW3, *PI8259_OCW3; + +typedef union _I8259_ISR +{ + union + { + struct + { + UCHAR Irq0:1; + UCHAR Irq1:1; + UCHAR Irq2:1; + UCHAR Irq3:1; + UCHAR Irq4:1; + UCHAR Irq5:1; + UCHAR Irq6:1; + UCHAR Irq7:1; + }; + }; + UCHAR Bits; +} I8259_ISR, *PI8259_ISR; + +typedef I8259_ISR I8259_IDR, *PI8259_IDR; + +typedef struct _PIC_MASK +{ + union + { + struct + { + UCHAR Master; + UCHAR Slave; + }; + USHORT Both; + }; +} PIC_MASK, *PPIC_MASK; + +#if defined(__GNUC__) + +#define HalpDelayedHardwareInterrupt(x) \ + VOID __cdecl HalpHardwareInterrupt##x(VOID); \ + VOID \ + __cdecl \ + HalpHardwareInterrupt##x(VOID) \ + { \ + asm volatile ("int $%c0\n"::"i"(PRIMARY_VECTOR_BASE + x)); \ + } + +#elif defined(_MSC_VER) + +#define HalpDelayedHardwareInterrupt(x) \ + VOID __cdecl HalpHardwareInterrupt##x(VOID); \ + VOID \ + __cdecl \ + HalpHardwareInterrupt##x(VOID) \ + { \ + __asm \ + { \ + int PRIMARY_VECTOR_BASE + x \ + } \ + } + +#else +#error Unsupported compiler +#endif + +typedef +BOOLEAN +(NTAPI *PHAL_DISMISS_INTERRUPT)( + IN KIRQL Irql, + IN ULONG Irq, + OUT PKIRQL OldIrql +); + +typedef +VOID +(__cdecl *PHAL_SW_INTERRUPT_HANDLER)( + VOID +); + +typedef +VOID +(FASTCALL *PHAL_SW_INTERRUPT_HANDLER_2ND_ENTRY)( + IN PKTRAP_FRAME TrapFrame +); + +VOID +__cdecl +HalpApcInterrupt( + VOID +); + +VOID +__cdecl +HalpDispatchInterrupt( + VOID +); + +DECLSPEC_NORETURN +VOID +FASTCALL +HalpApcInterrupt2ndEntry( + IN PKTRAP_FRAME TrapFrame +); + +DECLSPEC_NORETURN +VOID +FASTCALL +HalpDispatchInterrupt2ndEntry( + IN PKTRAP_FRAME TrapFrame +); + +VOID +NTAPI +HalpEndSoftwareInterrupt( + IN KIRQL OldIrql, + IN PKTRAP_FRAME TrapFrame +); + +VOID +__cdecl +HalpHardwareInterruptLevel( + VOID +); + +BOOLEAN +NTAPI +HalpDismissIrqGeneric( + IN KIRQL Irql, + IN ULONG Irq, + OUT PKIRQL OldIrql +); + +BOOLEAN +NTAPI +HalpDismissIrq07( + IN KIRQL Irql, + IN ULONG Irq, + OUT PKIRQL OldIrql +); + +BOOLEAN +NTAPI +HalpDismissIrq13( + IN KIRQL Irql, + IN ULONG Irq, + OUT PKIRQL OldIrql +); + +BOOLEAN +NTAPI +HalpDismissIrq15( + IN KIRQL Irql, + IN ULONG Irq, + OUT PKIRQL OldIrql +); + +BOOLEAN +NTAPI +HalpDismissIrqLevel( + IN KIRQL Irql, + IN ULONG Irq, + OUT PKIRQL OldIrql +); + +BOOLEAN +NTAPI +HalpDismissIrq07Level( + IN KIRQL Irql, + IN ULONG Irq, + OUT PKIRQL OldIrql +); + +BOOLEAN +NTAPI +HalpDismissIrq13Level( + IN KIRQL Irql, + IN ULONG Irq, + OUT PKIRQL OldIrql +); + +BOOLEAN +NTAPI +HalpDismissIrq15Level( + IN KIRQL Irql, + IN ULONG Irq, + OUT PKIRQL OldIrql +); + +/* EOF */ + diff --git a/hal/halacpi/pic/pictrap.S b/hal/halacpi/pic/pictrap.S new file mode 100644 index 0000000000000..a356f87cb340d --- /dev/null +++ b/hal/halacpi/pic/pictrap.S @@ -0,0 +1,15 @@ + +/* INCLUDES ******************************************************************/ + +#include +#include +#include + +.code + +TRAP_ENTRY HalpTrap0D, 0 +TRAP_ENTRY HalpApcInterrupt, KI_SOFTWARE_TRAP +TRAP_ENTRY HalpClockInterrupt, KI_PUSH_FAKE_ERROR_CODE +TRAP_ENTRY HalpProfileInterrupt, KI_PUSH_FAKE_ERROR_CODE + +END diff --git a/hal/halacpi/pic/profil.c b/hal/halacpi/pic/profil.c new file mode 100644 index 0000000000000..8b4473efa9ae8 --- /dev/null +++ b/hal/halacpi/pic/profil.c @@ -0,0 +1,103 @@ + +/* INCLUDES ******************************************************************/ + +#include +//#define NDEBUG +#include + +/* GLOBALS *******************************************************************/ + +BOOLEAN HalpProfilingStopped = TRUE; +UCHAR HalpProfileRate = 8; + +/* PUBLIC FUNCTIONS **********************************************************/ + +ULONG_PTR +NTAPI +HalSetProfileInterval(IN ULONG_PTR Interval) +{ + ULONG_PTR CurrentValue, NextValue; + UCHAR i; + + /* Normalize interval. 122100 ns is the smallest supported */ + Interval &= ~(1 << 31); + + if (Interval < 1221) + Interval = 1221; + + /* Highest rate value of 15 means 500 ms */ + CurrentValue = 5000000; + + for (i = 15; ; i--) + { + NextValue = (CurrentValue + 1) / 2; + if (Interval > (CurrentValue - NextValue / 2)) + break; + + CurrentValue = NextValue; + } + + /* Interval as needed by RTC */ + HalpProfileRate = i; + + /* Reset the */ + if (!HalpProfilingStopped) + HalStartProfileInterrupt(0); + + return CurrentValue; +} + +VOID +NTAPI +HalStartProfileInterrupt(IN KPROFILE_SOURCE ProfileSource) +{ + UCHAR StatusA, StatusB; + + UNREFERENCED_PARAMETER(ProfileSource); + + HalpProfilingStopped = FALSE; + + /* Acquire the CMOS lock */ + HalpAcquireCmosSpinLock(); + + /* Set the interval in Status Register A */ + StatusA = HalpReadCmos(RTC_REGISTER_A); + StatusA = (StatusA & 0xF0) | HalpProfileRate; + HalpWriteCmos(RTC_REGISTER_A, StatusA); + + /* Enable periodic interrupts in Status Register B */ + StatusB = HalpReadCmos(RTC_REGISTER_B); + StatusB = StatusB | RTC_REG_B_PI; + HalpWriteCmos(RTC_REGISTER_B, StatusB); + + /* Release the CMOS lock */ + HalpReleaseCmosSpinLock(); +} + +VOID +NTAPI +HalStopProfileInterrupt(IN KPROFILE_SOURCE ProfileSource) +{ + UCHAR StatusB; + + UNREFERENCED_PARAMETER(ProfileSource); + + /* Acquire the CMOS lock */ + HalpAcquireCmosSpinLock(); + + /* Read Status Register B */ + StatusB = HalpReadCmos(RTC_REGISTER_B); + + /* Disable periodic interrupts */ + StatusB = StatusB & ~RTC_REG_B_PI; + + /* Write new value into Status Register B */ + HalpWriteCmos(RTC_REGISTER_B, StatusB); + + HalpProfilingStopped = TRUE; + + /* Release the CMOS lock */ + HalpReleaseCmosSpinLock(); +} + +/* EOF */ diff --git a/hal/halacpi/pic/systimer.S b/hal/halacpi/pic/systimer.S new file mode 100644 index 0000000000000..90f64895625b9 --- /dev/null +++ b/hal/halacpi/pic/systimer.S @@ -0,0 +1,42 @@ + +/* INCLUDES ******************************************************************/ + +#include +#include + +/* GLOBALS *******************************************************************/ + +.data +ASSUME CS:NOTHING, DS:NOTHING, ES:NOTHING, FS:NOTHING, GS:NOTHING + +/* FUNCTIONS *****************************************************************/ + +.code + +PUBLIC _KeStallExecutionProcessor@4 +_KeStallExecutionProcessor@4: + + /* Get the number of microseconds required */ + mov ecx, [esp+4] + jecxz Done + + /* Multiply by the stall factor */ + mov eax, fs:[KPCR_STALL_SCALE_FACTOR] + mul ecx + + /* Jump to subtraction loop */ + jmp SubtractLoop + + /* Align to 16 bytes */ + .align 16 + + /* Subtract one count */ +SubtractLoop: + sub eax, 1 + jnz SubtractLoop + +Done: + /* Return */ + ret 4 + +END diff --git a/hal/halacpi/pic/timer.c b/hal/halacpi/pic/timer.c new file mode 100644 index 0000000000000..cb12139686d0d --- /dev/null +++ b/hal/halacpi/pic/timer.c @@ -0,0 +1,345 @@ + +/* INCLUDES ******************************************************************/ + +#include +#include "timer.h" + +//#define NDEBUG +#include + +#if defined(ALLOC_PRAGMA) && !defined(_MINIHAL_) + #pragma alloc_text(INIT, HalpInitializeClock) +#endif + +/* GLOBALS *******************************************************************/ + +ULONG HalpCurrentTimeIncrement; +ULONG HalpCurrentRollOver; +ULONG HalpNextMSRate = 14; +ULONG HalpLargestClockMS = 15; +LARGE_INTEGER HalpPerfCounter; +LARGE_INTEGER HalpLastPerfCounter; +ULONG HalpPerfCounterCutoff; +BOOLEAN HalpClockSetMSRate; + +static struct _HALP_ROLLOVER +{ + ULONG RollOver; + ULONG Increment; +} HalpRolloverTable[15] = +{ + {1197, 10032}, + {2394, 20064}, + {3591, 30096}, + {4767, 39952}, + {5964, 49984}, + {7161, 60016}, + {8358, 70048}, + {9555, 80080}, + {10731, 89936}, + {11949, 100144}, + {13125, 110000}, + {14322, 120032}, + {15519, 130064}, + {16695, 139920}, + {17892, 149952} +}; + +extern BOOLEAN HalpProfilingStopped; + +/* PRIVATE FUNCTIONS *********************************************************/ + +FORCEINLINE +ULONG +HalpRead8254Value(void) +{ + ULONG TimerValue; + + /* Send counter latch command for channel 0 */ + WRITE_PORT_UCHAR(TIMER_CONTROL_PORT, PIT_LATCH); + __nop(); + + /* Read the value, LSB first */ + TimerValue = READ_PORT_UCHAR(TIMER_CHANNEL0_DATA_PORT); + __nop(); + TimerValue |= (READ_PORT_UCHAR(TIMER_CHANNEL0_DATA_PORT) << 8); + + return TimerValue; +} +VOID +NTAPI +HalpSetTimerRollOver(USHORT RollOver) +{ + ULONG_PTR Flags; + TIMER_CONTROL_PORT_REGISTER TimerControl; + + DPRINT1("HalpSetTimerRollOver()\n"); + + /* Disable interrupts */ + Flags = __readeflags(); + _disable(); + + /* Program the PIT for binary mode */ + TimerControl.BcdMode = FALSE; + + /* + * Program the PIT to generate a normal rate wave (Mode 3) on channel 0. + * Channel 0 is used for the IRQ0 clock interval timer, and channel + * 1 is used for DRAM refresh. + * + * Mode 2 gives much better accuracy than Mode 3. + */ + TimerControl.OperatingMode = PitOperatingMode2; + TimerControl.Channel = PitChannel0; + + /* Set the access mode that we'll use to program the reload value */ + TimerControl.AccessMode = PitAccessModeLowHigh; + + /* Now write the programming bits */ + WRITE_PORT_UCHAR(TIMER_CONTROL_PORT, TimerControl.Bits); + + /* Next we write the reload value for channel 0 */ + WRITE_PORT_UCHAR(TIMER_CHANNEL0_DATA_PORT, RollOver & 0xFF); + WRITE_PORT_UCHAR(TIMER_CHANNEL0_DATA_PORT, RollOver >> 8); + + /* Restore interrupts if they were previously enabled */ + __writeeflags(Flags); +} + +CODE_SEG("INIT") +VOID +NTAPI +HalpInitializeClock(VOID) +{ + ULONG Increment; + USHORT RollOver; + + DPRINT1("HalpInitializeClock()\n"); + + /* Get increment and rollover for the largest time clock ms possible */ + Increment = HalpRolloverTable[HalpLargestClockMS - 1].Increment; + RollOver = (USHORT)HalpRolloverTable[HalpLargestClockMS - 1].RollOver; + + /* Set the maximum and minimum increment with the kernel */ + KeSetTimeIncrement(Increment, HalpRolloverTable[0].Increment); + + /* Set the rollover value for the timer */ + HalpSetTimerRollOver(RollOver); + + /* Save rollover and increment */ + HalpCurrentRollOver = RollOver; + HalpCurrentTimeIncrement = Increment; +} + +VOID +FASTCALL +HalpClockInterruptHandler(IN PKTRAP_FRAME TrapFrame) +{ + ULONG LastIncrement; + KIRQL Irql; + + //DPRINT("HalpClockInterruptHandler: ... \n"); + + /* Enter trap */ + KiEnterInterruptTrap(TrapFrame); + + /* Start the interrupt */ + if (!HalBeginSystemInterrupt(CLOCK2_LEVEL, (PRIMARY_VECTOR_BASE + 0), &Irql)) + { + /* Spurious, just end the interrupt */ + KiEoiHelper(TrapFrame); // DECLSPEC_NORETURN + return; + } + + /* Update the performance counter */ + HalpPerfCounter.QuadPart += HalpCurrentRollOver; + HalpPerfCounterCutoff = KiEnableTimerWatchdog; + + /* Save increment */ + LastIncrement = HalpCurrentTimeIncrement; + + /* Check if someone changed the time rate */ + if (HalpClockSetMSRate) + { + /* Update the global values */ + HalpCurrentTimeIncrement = HalpRolloverTable[HalpNextMSRate - 1].Increment; + HalpCurrentRollOver = HalpRolloverTable[HalpNextMSRate - 1].RollOver; + + /* Set new timer rollover */ + HalpSetTimerRollOver((USHORT)HalpCurrentRollOver); + + /* We're done */ + HalpClockSetMSRate = FALSE; + } + + /* Update the system time -- the kernel will exit this trap */ + KeUpdateSystemTime(TrapFrame, LastIncrement, Irql); + + ASSERT(0);//HalpDbgBreakPointEx(); + KiEoiHelper(TrapFrame); +} + +VOID +FASTCALL +HalpProfileInterruptHandler(IN PKTRAP_FRAME TrapFrame) +{ + KIRQL Irql; + + DPRINT("HalpProfileInterruptHandler: ... \n"); + + /* Enter trap */ + KiEnterInterruptTrap(TrapFrame); + + /* Start the interrupt */ + if (!HalBeginSystemInterrupt(PROFILE_LEVEL, (PRIMARY_VECTOR_BASE + 8), &Irql)) + { + /* Spurious, just end the interrupt */ + KiEoiHelper(TrapFrame); // DECLSPEC_NORETURN + ASSERT(0);//HalpDbgBreakPointEx(); + return; + } + + /* Spin until the interrupt pending bit is clear */ + HalpAcquireCmosSpinLock(); + while (HalpReadCmos(RTC_REGISTER_C) & RTC_REG_C_IRQ) + ; + HalpReleaseCmosSpinLock(); + + /* If profiling is enabled, call the kernel function */ + if (!HalpProfilingStopped) + KeProfileInterrupt(TrapFrame); + + /* Finish the interrupt */ + _disable(); + #ifdef __REACTOS__ + HalEndSystemInterrupt(Irql,TrapFrame); + #else + DPRINT1("KiEndInterrupt: FIXME! Irql %X, TrapFrame %X\n", Irql, TrapFrame); + ASSERT(FALSE);// DbgBreakPoint(); + /* NT actually uses the stack to place the pointer to the TrapFrame (really the third parameter), + but ... HalEndSystemInterrupt() is defined with only two parameters ... + */ + // ?add before?: + // _asm push (IntContext->TrapFrame) + HalEndSystemInterrupt(Irql, 0xFF /*, TrapFrame*/); // FIXME (compatible with NT) + #endif + + /* Exit the interrupt */ + #ifdef __REACTOS__ + KiEoiHelper(TrapFrame); + #else + DPRINT1("KiEndInterrupt: FIXME before calling Kei386EoiHelper()\n"); + ASSERT(FALSE);// DbgBreakPoint(); + /* NT uses non-standard call parameters */ + // ?add before?: + // _asm mov ebp, (IntContext->TrapFrame) + // _asm push ebp + Kei386EoiHelper(/*TrapFrame*/); // FIXME (compatible with NT) + #endif + + ASSERT(0);//HalpDbgBreakPointEx(); +} + +/* PUBLIC FUNCTIONS ***********************************************************/ + +/* FIXME */ +#if 0 + +HALPSTALLEXECPROC PmTimerFunction0 = HalpPmTimerStallExecProc; +HALPCALIBRATEPERFCOUNT PmTimerFunction1 = HalpPmTimerCalibratePerfCount; +HALPQUERYPERFCOUNT PmTimerFunction2 = HalpPmTimerQueryPerfCount; +HALPSETTIMEINCREMENT PmTimerFunction3 = HalpAcpiTimerSetTimeIncrement; + +LARGE_INTEGER +NTAPI +KeQueryPerformanceCounter(_Out_opt_ PLARGE_INTEGER PerformanceFrequency) +{ + return HalpPmTimerQueryPerfCount(PerformanceFrequency); +} + +#endif + +LARGE_INTEGER +NTAPI +KeQueryPerformanceCounter(OUT PLARGE_INTEGER PerformanceFrequency) +{ + LARGE_INTEGER CurrentPerfCounter; + ULONG CounterValue, ClockDelta; + KIRQL OldIrql; + + /* If caller wants performance frequency, return hardcoded value */ + if (PerformanceFrequency) + PerformanceFrequency->QuadPart = PIT_FREQUENCY; + + /* Check if we were called too early */ + if (HalpCurrentRollOver == 0) + return HalpPerfCounter; + + /* Check if interrupts are disabled */ + if(!(__readeflags() & EFLAGS_INTERRUPT_MASK)) + return HalpPerfCounter; + + /* Raise irql to DISPATCH_LEVEL */ + OldIrql = KeGetCurrentIrql(); + if (OldIrql < DISPATCH_LEVEL) + KfRaiseIrql(DISPATCH_LEVEL); + + do + { + /* Get the current performance counter value */ + CurrentPerfCounter = HalpPerfCounter; + + /* Read the 8254 counter value */ + CounterValue = HalpRead8254Value(); + + /* Repeat if the value has changed (a clock interrupt happened) */ + } + while (CurrentPerfCounter.QuadPart != HalpPerfCounter.QuadPart); + + /* After someone changed the clock rate, during the first clock cycle we + might see a counter value larger than the rollover. In this case we + pretend it already has the new rollover value. + */ + if (CounterValue > HalpCurrentRollOver) + CounterValue = HalpCurrentRollOver; + + /* The interrupt is issued on the falling edge of the OUT line, when the + counter changes from 1 to max. Calculate a clock delta, so that directly + after the interrupt it is 0, going up to (HalpCurrentRollOver - 1). + */ + ClockDelta = HalpCurrentRollOver - CounterValue; + + /* Add the clock delta */ + CurrentPerfCounter.QuadPart += ClockDelta; + + /* Check if the value is smaller then before, this means, we somehow + missed an interrupt. This is a sign that the timer interrupt + is very inaccurate. Probably a virtual machine. + */ + if (CurrentPerfCounter.QuadPart < HalpLastPerfCounter.QuadPart) + { + /* We missed an interrupt. Assume we will receive it later */ + CurrentPerfCounter.QuadPart += HalpCurrentRollOver; + } + + /* Update the last counter value */ + HalpLastPerfCounter = CurrentPerfCounter; + + /* Restore previous irql */ + if (OldIrql < DISPATCH_LEVEL) + KfLowerIrql(OldIrql); + + /* Return the result */ + return CurrentPerfCounter; +} + +VOID +NTAPI +HalCalibratePerformanceCounter(IN volatile PLONG Count, + IN ULONGLONG NewCount) +{ + UNIMPLEMENTED; + ASSERT(0);//HalpDbgBreakPointEx(); +} + +/* EOF */ diff --git a/hal/halacpi/pic/timer.h b/hal/halacpi/pic/timer.h new file mode 100644 index 0000000000000..a0cc2c3dc6f04 --- /dev/null +++ b/hal/halacpi/pic/timer.h @@ -0,0 +1,99 @@ + +#pragma once + +/* + Mode 0 - Interrupt On Terminal Count + Mode 1 - Hardware Re-triggerable One-Shot + Mode 2 - Rate Generator + Mode 3 - Square Wave Generator + Mode 4 - Software Triggered Strobe + Mode 5 - Hardware Triggered Strobe +*/ +typedef enum _TIMER_OPERATING_MODES +{ + PitOperatingMode0, + PitOperatingMode1, + PitOperatingMode2, + PitOperatingMode3, + PitOperatingMode4, + PitOperatingMode5, + PitOperatingMode2Reserved, + PitOperatingMode5Reserved +} TIMER_OPERATING_MODES; + +typedef enum _TIMER_ACCESS_MODES +{ + PitAccessModeCounterLatch, + PitAccessModeLow, + PitAccessModeHigh, + PitAccessModeLowHigh +} TIMER_ACCESS_MODES; + +typedef enum _TIMER_CHANNELS +{ + PitChannel0, + PitChannel1, + PitChannel2, + PitReadBack +} TIMER_CHANNELS; + +typedef union _TIMER_CONTROL_PORT_REGISTER +{ + struct + { + UCHAR BcdMode:1; + UCHAR OperatingMode:3; + UCHAR AccessMode:2; + UCHAR Channel:2; + }; + UCHAR Bits; +} TIMER_CONTROL_PORT_REGISTER, *PTIMER_CONTROL_PORT_REGISTER; + +/* See ISA System Architecture 3rd Edition (Tom Shanley, Don Anderson, John Swindle) P. 400 + This port is controled by the i8255 Programmable Peripheral Interface (PPI) +*/ +#define SYSTEM_CONTROL_PORT_A (PUCHAR)0x0092 +#define SYSTEM_CONTROL_PORT_B (PUCHAR)0x0061 + +typedef union _SYSTEM_CONTROL_PORT_B_REGISTER +{ + struct + { + UCHAR Timer2GateToSpeaker:1; + UCHAR SpeakerDataEnable:1; + UCHAR ParityCheckEnable:1; + UCHAR ChannelCheckEnable:1; + UCHAR RefreshRequest:1; + UCHAR Timer2Output:1; + UCHAR ChannelCheck:1; + UCHAR ParityCheck:1; + }; + UCHAR Bits; +} SYSTEM_CONTROL_PORT_B_REGISTER, *PSYSTEM_CONTROL_PORT_B_REGISTER; + +/* Commonly stated as being 1.19318MHz + + See ISA System Architecture 3rd Edition (Tom Shanley, Don Anderson, John Swindle) P. 471 + + However, the true value is closer to 1.19318181[...]81MHz since this is 1/3rd + of the NTSC color subcarrier frequency which runs at 3.57954545[...]45MHz. + + Note that Windows uses 1.193167MHz which seems to have no basis. + However, if one takes the NTSC color subcarrier frequency as being 3.579545 + (trimming the infinite series) and divides it by three, one obtains 1.19318167. + + It may be that the original NT HAL source code introduced a typo and turned + 119318167 into 1193167 by ommitting the "18". This is very plausible as the + number is quite long. +*/ +#define PIT_FREQUENCY 1193182 + +/* These ports are controlled by the i8254 Programmable Interrupt Timer (PIT) */ +#define TIMER_CHANNEL0_DATA_PORT (PUCHAR)0x0040 +#define TIMER_CHANNEL1_DATA_PORT (PUCHAR)0x0041 +#define TIMER_CHANNEL2_DATA_PORT (PUCHAR)0x0042 +#define TIMER_CONTROL_PORT (PUCHAR)0x0043 + +#define PIT_LATCH 0x00 + +/* EOF */ diff --git a/hal/halacpi/up/processor.c b/hal/halacpi/up/processor.c new file mode 100644 index 0000000000000..b7dc172514111 --- /dev/null +++ b/hal/halacpi/up/processor.c @@ -0,0 +1,219 @@ + +/* INCLUDES ******************************************************************/ + +#include +//#define NDEBUG +#include + +/* GLOBALS ********************************************************************/ + +ULONG HalpFeatureBits; + +/* CPU Signatures */ +static const CHAR CmpIntelID[] = "GenuineIntel"; +static const CHAR CmpAmdID[] = "AuthenticAMD"; +static const CHAR CmpCyrixID[] = "CyrixInstead"; +static const CHAR CmpTransmetaID[] = "GenuineTMx86"; +static const CHAR CmpCentaurID[] = "CentaurHauls"; +static const CHAR CmpRiseID[] = "RiseRiseRise"; + +/* PRIVATE FUNCTIONS *********************************************************/ + +FORCEINLINE +VOID +HalpCpuId( + PCPU_INFO CpuInfo, + ULONG Function) +{ + __cpuid((INT*)CpuInfo->AsUINT32, Function); +} + +ULONG +NTAPI +HalpGetCpuVendor(VOID) +{ + CHAR VendorString[13]; + CPU_INFO CpuInfo; + + /* Assume no Vendor ID and fail if no CPUID Support. */ + VendorString[0] = 0; + + if (KeGetCurrentPrcb()->CpuID == 0) + return 0; + + /* Get the Vendor ID */ + HalpCpuId(&CpuInfo, 0); + + /* Copy it to the PRCB and null-terminate it */ + *(ULONG*)&VendorString[0] = CpuInfo.Ebx; + *(ULONG*)&VendorString[4] = CpuInfo.Edx; + *(ULONG*)&VendorString[8] = CpuInfo.Ecx; + VendorString[12] = 0; + + /* Now check the CPU Type */ + if (!strcmp(VendorString, CmpIntelID)) + { + return CPU_INTEL; + } + else if (!strcmp(VendorString, CmpAmdID)) + { + return CPU_AMD; + } + else if (!strcmp(VendorString, CmpCyrixID)) + { + DPRINT1("HalpGetCpuVendor: Cyrix CPU support not fully tested!\n"); + return CPU_CYRIX; + } + else if (!strcmp(VendorString, CmpTransmetaID)) + { + DPRINT1("HalpGetCpuVendor: Transmeta CPU support not fully tested!\n"); + return CPU_TRANSMETA; + } + else if (!strcmp(VendorString, CmpCentaurID)) + { + DPRINT1("HalpGetCpuVendor: Centaur CPU support not fully tested!\n"); + return CPU_CENTAUR; + } + else if (!strcmp(VendorString, CmpRiseID)) + { + DPRINT1("HalpGetCpuVendor: Rise CPU support not fully tested!\n"); + return CPU_RISE; + } + + /* Unknown CPU */ + DPRINT1("HalpGetCpuVendor: %s CPU support not fully tested!\n", VendorString); + return CPU_UNKNOWN; +} + +ULONG +NTAPI +HalpGetFeatureBits(VOID) +{ + PKPRCB Prcb = KeGetCurrentPrcb(); + ULONG Vendor; + ULONG FeatureBits = 0; + ULONG CpuFeatures; + ULONGLONG MsrApicBase; + CPU_INFO CpuInfo; + + Vendor = HalpGetCpuVendor(); + if (Vendor == CPU_NONE) + return 2; + + HalpCpuId(&CpuInfo, 1); + CpuFeatures = CpuInfo.Edx; + + switch (Vendor) + { + case CPU_INTEL: + { + if (Prcb->CpuType == 6) + { + FeatureBits = 1; + + MsrApicBase = __readmsr(0x1B); // MSR_IA32_APICBASE + if (MsrApicBase & 0x800) + __writemsr(0x1B, MsrApicBase & ~0x800); // MSR_IA32_APICBASE + } + else if (Prcb->CpuType < 6) + { + FeatureBits |= 2; + } + + break; + } + case CPU_AMD: + { + CpuInfo.Eax = 0; + + HalpCpuId(&CpuInfo, 0x80000000); // HighestExFunction + if (CpuInfo.Eax < 0x80000001) + break; + + HalpCpuId(&CpuInfo, 0x80000001); // ExFeatures + if (CpuInfo.Edx & 0x100000) + FeatureBits |= 0x40; + + break; + } + default: + { + DPRINT1("HalpGetFeatureBits: CPU %d\n", Vendor); + break; + } + } + + if (CpuFeatures & 0x4000) + FeatureBits |= 4; + + if (CpuFeatures & 0x80) + FeatureBits |= 8; + + if (CpuFeatures & 2) + FeatureBits |= 0x10; + + if (CpuFeatures & 0x4000000) + FeatureBits |= 0x20; + + KeFlushWriteBuffer(); + + return FeatureBits; +} + +/* FUNCTIONS *****************************************************************/ + +VOID +NTAPI +HalpRemoveFences(VOID) +{ + DPRINT1("HalpRemoveFences FIXME!\n"); + ASSERT(FALSE);//HalpDbgBreakPointEx(); +} + +BOOLEAN +NTAPI +HalAllProcessorsStarted(VOID) +{ + DPRINT1("HalAllProcessorsStarted: HalpFeatureBits %X\n", HalpFeatureBits); + + if (HalpFeatureBits & 2) { + HalpRemoveFences(); + } + + return TRUE; +} + +BOOLEAN +NTAPI +HalStartNextProcessor(IN PLOADER_PARAMETER_BLOCK LoaderBlock, + IN PKPROCESSOR_STATE ProcessorState) +{ + /* Ready to start */ + return FALSE; +} + +VOID +NTAPI +HalProcessorIdle(VOID) +{ + /* Enable interrupts and halt the processor */ + _enable(); + __halt(); +} + +VOID +NTAPI +HalRequestIpi(KAFFINITY TargetProcessors) +{ + /* Not implemented on UP */ + __debugbreak(); +} + +VOID +NTAPI +KeFlushWriteBuffer(VOID) +{ + return; +} + +/* EOF */ diff --git a/hal/halacpi/version/halacpi.rc b/hal/halacpi/version/halacpi.rc new file mode 100644 index 0000000000000..2b5a91c022fda --- /dev/null +++ b/hal/halacpi/version/halacpi.rc @@ -0,0 +1,5 @@ +#define REACTOS_VERSION_DLL +#define REACTOS_STR_FILE_DESCRIPTION "Hardware Abstraction Layer DLL" +#define REACTOS_STR_INTERNAL_NAME "halacpi.dll" +#define REACTOS_STR_ORIGINAL_FILENAME "halacpi.dll" +#include diff --git a/hal/halx86/CMakeLists.txt b/hal/halx86/CMakeLists.txt index 193a4ab8ab827..8ac8359b977b2 100644 --- a/hal/halx86/CMakeLists.txt +++ b/hal/halx86/CMakeLists.txt @@ -60,8 +60,8 @@ if(ARCH STREQUAL "i386") # hal add_hal(hal SOURCES pic/halpic.rc COMPONENTS generic legacy up pic) - add_hal(halacpi SOURCES acpi/halacpi.rc COMPONENTS generic acpi up pic) - add_hal(halaacpi SOURCES apic/halaacpi.rc COMPONENTS generic acpi up apic) + # add_hal(halacpi SOURCES acpi/halacpi.rc COMPONENTS generic acpi up pic) + # add_hal(halaacpi SOURCES apic/halaacpi.rc COMPONENTS generic acpi up apic) add_hal(halapic SOURCES apic/halapic.rc COMPONENTS generic legacy up apic) add_hal(halxbox SOURCES xbox/halxbox.rc COMPONENTS xbox up) add_hal(halpc98 SOURCES pc98/halpc98.rc COMPONENTS pc98 up)