From daaa55b87dc0519422d4020b9b6ac66c5cd4b753 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Gardou?= Date: Thu, 17 Jun 2010 00:20:20 +0000 Subject: [PATCH] [HAL] - yet another sync fun svn path=/branches/reactos-yarotows/; revision=47791 --- hal/halx86/generic/legacy/bussupp.c | 1511 +++++++++++++++++++++++++++ hal/halx86/generic/memory.c | 234 +++++ 2 files changed, 1745 insertions(+) create mode 100644 hal/halx86/generic/legacy/bussupp.c create mode 100644 hal/halx86/generic/memory.c diff --git a/hal/halx86/generic/legacy/bussupp.c b/hal/halx86/generic/legacy/bussupp.c new file mode 100644 index 00000000000..6faa60fb765 --- /dev/null +++ b/hal/halx86/generic/legacy/bussupp.c @@ -0,0 +1,1511 @@ +/* + * PROJECT: ReactOS HAL + * LICENSE: BSD - See COPYING.ARM in the top level directory + * FILE: hal/halx86/generic/legacy/bussupp.c + * PURPOSE: HAL Legacy Bus Support Code + * PROGRAMMERS: ReactOS Portable Systems Group + */ + +/* INCLUDES *******************************************************************/ + +#include +#define NDEBUG +#include + +/* GLOBALS ********************************************************************/ + +extern KSPIN_LOCK HalpPCIConfigLock; +ULONG HalpPciIrqMask; + +/* PRIVATE FUNCTIONS **********************************************************/ + +PBUS_HANDLER +NTAPI +HalpAllocateBusHandler(IN INTERFACE_TYPE InterfaceType, + IN BUS_DATA_TYPE BusDataType, + IN ULONG BusNumber, + IN INTERFACE_TYPE ParentBusInterfaceType, + IN ULONG ParentBusNumber, + IN ULONG BusSpecificData) +{ + PBUS_HANDLER Bus; + + /* Register the bus handler */ + HalRegisterBusHandler(InterfaceType, + BusDataType, + BusNumber, + ParentBusInterfaceType, + ParentBusNumber, + BusSpecificData, + NULL, + &Bus); + if (!Bus) return NULL; + + /* Check for a valid interface */ + if (InterfaceType != InterfaceTypeUndefined) + { + /* Allocate address ranges and zero them out */ + Bus->BusAddresses = ExAllocatePoolWithTag(NonPagedPool, + sizeof(SUPPORTED_RANGES), + ' laH'); + RtlZeroMemory(Bus->BusAddresses, sizeof(SUPPORTED_RANGES)); + + /* Build the data structure */ + Bus->BusAddresses->Version = HAL_SUPPORTED_RANGE_VERSION; + Bus->BusAddresses->Dma.Limit = 7; + Bus->BusAddresses->Memory.Limit = 0xFFFFFFFF; + Bus->BusAddresses->IO.Limit = 0xFFFF; + Bus->BusAddresses->IO.SystemAddressSpace = 1; + Bus->BusAddresses->PrefetchMemory.Base = 1; + } + + /* Return the bus address */ + return Bus; +} + +VOID +NTAPI +HalpRegisterInternalBusHandlers(VOID) +{ + PBUS_HANDLER Bus; + + /* Only do processor 1 */ + if (KeGetCurrentPrcb()->Number) return; + + /* Register root support */ + HalpInitBusHandler(); + + /* Allocate the system bus */ + Bus = HalpAllocateBusHandler(Internal, + ConfigurationSpaceUndefined, + 0, + InterfaceTypeUndefined, + 0, + 0); + if (Bus) + { + /* Set it up */ + Bus->GetInterruptVector = HalpGetSystemInterruptVector; + Bus->TranslateBusAddress = HalpTranslateSystemBusAddress; + } + + /* Allocate the CMOS bus */ + Bus = HalpAllocateBusHandler(InterfaceTypeUndefined, + Cmos, + 0, + InterfaceTypeUndefined, + 0, + 0); + if (Bus) + { + /* Set it up */ + Bus->GetBusData = HalpcGetCmosData; + Bus->SetBusData = HalpcSetCmosData; + } + + /* Allocate the CMOS bus */ + Bus = HalpAllocateBusHandler(InterfaceTypeUndefined, + Cmos, + 1, + InterfaceTypeUndefined, + 0, + 0); + if (Bus) + { + /* Set it up */ + Bus->GetBusData = HalpcGetCmosData; + Bus->SetBusData = HalpcSetCmosData; + } + + /* Allocate ISA bus */ + Bus = HalpAllocateBusHandler(Isa, + ConfigurationSpaceUndefined, + 0, + Internal, + 0, + 0); + if (Bus) + { + /* Set it up */ + Bus->GetBusData = HalpNoBusData; + Bus->BusAddresses->Memory.Limit = 0xFFFFFF; + Bus->TranslateBusAddress = HalpTranslateIsaBusAddress; + } + + /* No support for EISA or MCA */ + ASSERT(HalpBusType == MACHINE_TYPE_ISA); +} + +#ifndef _MINIHAL_ +NTSTATUS +NTAPI +HalpMarkChipsetDecode(BOOLEAN OverrideEnable) +{ + NTSTATUS Status; + UNICODE_STRING KeyString; + ULONG Data = OverrideEnable; + HANDLE KeyHandle, Handle; + + /* Open CCS key */ + RtlInitUnicodeString(&KeyString, + L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET"); + Status = HalpOpenRegistryKey(&Handle, 0, &KeyString, KEY_ALL_ACCESS, FALSE); + if (NT_SUCCESS(Status)) + { + /* Open PNP Bios key */ + RtlInitUnicodeString(&KeyString, L"Control\\Biosinfo\\PNPBios"); + Status = HalpOpenRegistryKey(&KeyHandle, + Handle, + &KeyString, + KEY_ALL_ACCESS, + TRUE); + + /* Close root key */ + ZwClose(Handle); + + /* Check if PNP BIOS key exists */ + if (NT_SUCCESS(Status)) + { + /* Set the override value */ + RtlInitUnicodeString(&KeyString, L"FullDecodeChipsetOverride"); + Status = ZwSetValueKey(KeyHandle, + &KeyString, + 0, + REG_DWORD, + &Data, + sizeof(Data)); + + /* Close subkey */ + ZwClose(KeyHandle); + } + } + + /* Return status */ + return Status; +} + +PBUS_HANDLER +NTAPI +HalpAllocateAndInitPciBusHandler(IN ULONG PciType, + IN ULONG BusNo, + IN BOOLEAN TestAllocation) +{ + PBUS_HANDLER Bus; + PPCIPBUSDATA BusData; + + /* Allocate the bus handler */ + Bus = HalpAllocateBusHandler(PCIBus, + PCIConfiguration, + BusNo, + Internal, + 0, + sizeof(PCIPBUSDATA)); + + /* Set it up */ + Bus->GetBusData = (PGETSETBUSDATA)HalpGetPCIData; + Bus->SetBusData = (PGETSETBUSDATA)HalpSetPCIData; + Bus->GetInterruptVector = (PGETINTERRUPTVECTOR)HalpGetPCIIntOnISABus; + Bus->AdjustResourceList = (PADJUSTRESOURCELIST)HalpAdjustPCIResourceList; + Bus->AssignSlotResources = (PASSIGNSLOTRESOURCES)HalpAssignPCISlotResources; + Bus->BusAddresses->Dma.Limit = 0; + + /* Get our custom bus data */ + BusData = (PPCIPBUSDATA)Bus->BusData; + + /* Setup custom bus data */ + BusData->CommonData.Tag = PCI_DATA_TAG; + BusData->CommonData.Version = PCI_DATA_VERSION; + BusData->CommonData.ReadConfig = (PciReadWriteConfig)HalpReadPCIConfig; + BusData->CommonData.WriteConfig = (PciReadWriteConfig)HalpWritePCIConfig; + BusData->CommonData.Pin2Line = (PciPin2Line)HalpPCIPin2ISALine; + BusData->CommonData.Line2Pin = (PciLine2Pin)HalpPCIISALine2Pin; + BusData->MaxDevice = PCI_MAX_DEVICES; + BusData->GetIrqRange = (PciIrqRange)HalpGetISAFixedPCIIrq; + + /* Initialize the bitmap */ + RtlInitializeBitMap(&BusData->DeviceConfigured, BusData->ConfiguredBits, 256); + + /* 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 1 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 = 16; + break; + + default: + + /* Invalid type */ + DbgPrint("HAL: Unnkown PCI type\n"); + } + + /* Return the bus handler */ + return Bus; +} + +BOOLEAN +NTAPI +HalpIsValidPCIDevice(IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot) +{ + UCHAR DataBuffer[PCI_COMMON_HDR_LENGTH]; + PPCI_COMMON_CONFIG PciHeader = (PVOID)DataBuffer; + ULONG i; + ULONG_PTR Address; + + /* Read the PCI header */ + HalpReadPCIConfig(BusHandler, Slot, PciHeader, 0, PCI_COMMON_HDR_LENGTH); + + /* Make sure it's a valid device */ + if ((PciHeader->VendorID == PCI_INVALID_VENDORID) || + (PCI_CONFIGURATION_TYPE(PciHeader) != PCI_DEVICE_TYPE)) + { + /* Bail out */ + return FALSE; + } + + /* Make sure interrupt numbers make sense */ + if (((PciHeader->u.type0.InterruptPin) && + (PciHeader->u.type0.InterruptPin > 4)) || + (PciHeader->u.type0.InterruptLine & 0x70)) + { + /* Bail out */ + return FALSE; + } + + /* Now scan PCI BARs */ + for (i = 0; i < PCI_TYPE0_ADDRESSES; i++) + { + /* Check what kind of address it is */ + Address = PciHeader->u.type0.BaseAddresses[i]; + if (Address & PCI_ADDRESS_IO_SPACE) + { + /* Highest I/O port is 65535 */ + if (Address > 0xFFFF) return FALSE; + } + else + { + /* MMIO should be higher than 0x80000 */ + if ((Address > 0xF) && (Address < 0x80000)) return FALSE; + } + + /* Is this a 64-bit address? */ + if (!(Address & PCI_ADDRESS_IO_SPACE) && + ((Address & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_64BIT)) + { + /* Check the next-next entry, since this one 64-bits wide */ + i++; + } + } + + /* Header, interrupt and address data all make sense */ + return TRUE; +} + +static BOOLEAN WarningsGiven[5]; + +NTSTATUS +NTAPI +HalpGetChipHacks(IN USHORT VendorId, + IN USHORT DeviceId, + IN UCHAR RevisionId, + IN PULONG HackFlags) +{ + UNICODE_STRING KeyName, ValueName; + NTSTATUS Status; + OBJECT_ATTRIBUTES ObjectAttributes; + HANDLE KeyHandle; + WCHAR Buffer[32]; + KEY_VALUE_PARTIAL_INFORMATION PartialInfo; + ULONG ResultLength; + + /* Setup the object attributes for the key */ + RtlInitUnicodeString(&KeyName, + L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\" + L"Control\\HAL"); + InitializeObjectAttributes(&ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + /* Open the key */ + Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes); + if (!NT_SUCCESS(Status)) return Status; + + /* Query value */ + swprintf(Buffer, L"%04X%04X", VendorId, DeviceId); + RtlInitUnicodeString(&ValueName, Buffer); + Status = ZwQueryValueKey(KeyHandle, + &ValueName, + KeyValuePartialInformation, + &PartialInfo, + sizeof(PartialInfo), + &ResultLength); + if (NT_SUCCESS(Status)) + { + /* Return the flags */ + DbgPrint("\tFound HackFlags for your chipset\n"); + *HackFlags = *(PULONG)PartialInfo.Data; + DbgPrint("\t\tHack Flags: %lx (Hack Revision: %lx-Your Revision: %lx)\n", + *HackFlags, HALP_REVISION_FROM_HACK_FLAGS(*HackFlags), RevisionId); + + /* Does it apply to this revision? */ + if ((RevisionId) && (RevisionId >= (HALP_REVISION_FROM_HACK_FLAGS(*HackFlags)))) + { + /* Read the revision flags */ + *HackFlags = HALP_REVISION_HACK_FLAGS(*HackFlags); + } + + /* Throw out revision data */ + *HackFlags = HALP_HACK_FLAGS(*HackFlags); + if (!*HackFlags) DbgPrint("\tNo HackFlags for your chipset's revision!\n"); + } + + /* Close the handle and return */ + ZwClose(KeyHandle); + return Status; +} + +BOOLEAN +NTAPI +HalpIsRecognizedCard(IN PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo, + IN PPCI_COMMON_CONFIG PciData, + IN ULONG Flags) +{ + ULONG ElementCount, i; + PPCI_CARD_DESCRIPTOR CardDescriptor; + + /* How many PCI Cards that we know about? */ + ElementCount = PciRegistryInfo->ElementCount; + if (!ElementCount) return FALSE; + + /* Loop all descriptors */ + CardDescriptor = &PciRegistryInfo->CardList[0]; + for (i = 0; i < ElementCount; i++, CardDescriptor++) + { + /* Check for flag match */ + if (CardDescriptor->Flags != Flags) continue; + + /* Check for VID-PID match */ + if ((CardDescriptor->VendorID != PciData->VendorID) || + (CardDescriptor->DeviceID != PciData->DeviceID)) + { + /* Skip */ + continue; + } + + /* Check for revision match, if requested */ + if ((CardDescriptor->Flags & HALP_CHECK_CARD_REVISION_ID) && + (CardDescriptor->RevisionID != PciData->RevisionID)) + { + /* Skip */ + continue; + } + + /* Check what kind of device this is */ + switch (PCI_CONFIGURATION_TYPE(PciData)) + { + /* CardBUS Bridge */ + case PCI_CARDBUS_BRIDGE_TYPE: + + /* This means the real device header is in the device-specific data */ + PciData = (PPCI_COMMON_CONFIG)PciData->DeviceSpecific; + + /* Normal PCI device */ + case PCI_DEVICE_TYPE: + + /* Check for subvendor match, if requested */ + if ((CardDescriptor->Flags & HALP_CHECK_CARD_SUBVENDOR_ID) && + (CardDescriptor->SubsystemVendorID != PciData->u.type0.SubVendorID)) + { + /* Skip */ + continue; + } + + /* Check for subsystem match, if requested */ + if ((CardDescriptor->Flags & HALP_CHECK_CARD_SUBSYSTEM_ID) && + (CardDescriptor->SubsystemID != PciData->u.type0.SubSystemID)) + { + /* Skip */ + continue; + } + + /* You made it! */ + return TRUE; + + /* PCI Bridge -- don't bother */ + case PCI_BRIDGE_TYPE: + default: + + /* Recognize it */ + return TRUE; + } + } + + /* This means the card isn't recognized */ + return FALSE; +} + +BOOLEAN +NTAPI +HalpIsIdeDevice(IN PPCI_COMMON_CONFIG PciData) +{ + /* Simple test first */ + if ((PciData->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) && + (PciData->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR)) + { + /* The device is nice enough to admit it */ + return TRUE; + } + + /* Symphony 82C101 */ + if (PciData->VendorID == 0x1C1C) return TRUE; + + /* ALi MS4803 or M5219 */ + if ((PciData->VendorID == 0x10B9) && + ((PciData->DeviceID == 0x5215) || (PciData->DeviceID == 0x5219))) + { + return TRUE; + } + + /* Appian Technology */ + if ((PciData->VendorID == 0x1097) && (PciData->DeviceID == 0x38)) return TRUE; + + /* Compaq Triflex Dual EIDE Controller */ + if ((PciData->VendorID == 0xE11) && (PciData->DeviceID == 0xAE33)) return TRUE; + + /* Micron PC Tech RZ1000 */ + if ((PciData->VendorID == 0x1042) && (PciData->DeviceID == 0x1000)) return TRUE; + + /* SiS 85C601 or 5513 [IDE] */ + if ((PciData->VendorID == 0x1039) && + ((PciData->DeviceID == 0x601) || (PciData->DeviceID == 0x5513))) + { + return TRUE; + } + + /* Symphony Labs W83769F */ + if ((PciData->VendorID == 0x10AD) && + ((PciData->DeviceID == 0x1) || (PciData->DeviceID == 0x150))) + { + return TRUE; + } + + /* UMC UM8673F */ + if ((PciData->VendorID == 0x1060) && (PciData->DeviceID == 0x101)) return TRUE; + + /* You've survived */ + return FALSE; +} + +BOOLEAN +NTAPI +HalpIsBridgeDevice(IN PPCI_COMMON_CONFIG PciData) +{ + /* Either this is a PCI-to-PCI Bridge, or a CardBUS Bridge */ + return (((PCI_CONFIGURATION_TYPE(PciData) == PCI_BRIDGE_TYPE) && + (PciData->BaseClass == PCI_CLASS_BRIDGE_DEV) && + (PciData->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI)) || + ((PCI_CONFIGURATION_TYPE(PciData) == PCI_CARDBUS_BRIDGE_TYPE) && + (PciData->BaseClass == PCI_CLASS_BRIDGE_DEV) && + (PciData->SubClass == PCI_SUBCLASS_BR_CARDBUS))); +} + +BOOLEAN +NTAPI +HalpGetPciBridgeConfig(IN ULONG PciType, + IN PUCHAR BusCount) +{ + PCI_SLOT_NUMBER PciSlot; + ULONG i, j, k; + UCHAR DataBuffer[PCI_COMMON_HDR_LENGTH]; + PPCI_COMMON_CONFIG PciData = (PPCI_COMMON_CONFIG)DataBuffer; + PBUS_HANDLER BusHandler; + + /* Loop PCI buses */ + PciSlot.u.bits.Reserved = 0; + for (i = 0; i < *BusCount; i++) + { + /* Get the bus handler */ + BusHandler = HalHandlerForBus(PCIBus, i); + + /* Loop every device */ + for (j = 0; j < PCI_MAX_DEVICES; j++) + { + /* Loop every function */ + PciSlot.u.bits.DeviceNumber = j; + for (k = 0; k < PCI_MAX_FUNCTION; k++) + { + /* Build the final slot structure */ + PciSlot.u.bits.FunctionNumber = k; + + /* Read the configuration information */ + HalpReadPCIConfig(BusHandler, + PciSlot, + PciData, + 0, + PCI_COMMON_HDR_LENGTH); + + /* Skip if this is an invalid function */ + if (PciData->VendorID == PCI_INVALID_VENDORID) continue; + + /* Make sure that this is a PCI bridge or a cardbus bridge */ + if (!HalpIsBridgeDevice(PciData)) continue; + + /* Not supported */ + if (!WarningsGiven[2]++) DPRINT1("Your machine has a PCI-to-PCI or CardBUS Bridge. PCI devices may fail!\n"); + continue; + } + } + } + + /* If we exited the loop, then there's no bridge to worry about */ + return FALSE; +} + +VOID +NTAPI +HalpFixupPciSupportedRanges(IN ULONG BusCount) +{ + ULONG i; + PBUS_HANDLER Bus, ParentBus; + + /* Loop all buses */ + for (i = 0; i < BusCount; i++) + { + /* Get PCI bus handler */ + Bus = HalHandlerForBus(PCIBus, i); + + /* Loop all parent buses */ + ParentBus = Bus->ParentHandler; + while (ParentBus) + { + /* Should merge addresses */ + if (!WarningsGiven[0]++) DPRINT1("Found parent bus (indicating PCI Bridge). PCI devices may fail!\n"); + + /* Check the next parent */ + ParentBus = ParentBus->ParentHandler; + } + } + + /* Loop all buses again */ + for (i = 0; i < BusCount; i++) + { + /* Get PCI bus handler */ + Bus = HalHandlerForBus(PCIBus, i); + + /* Check if this is a PCI 2.2 Bus with Subtractive Decode */ + if (!((PPCIPBUSDATA)Bus->BusData)->Subtractive) + { + /* Loop all parent buses */ + ParentBus = Bus->ParentHandler; + while (ParentBus) + { + /* But check only PCI parent buses specifically */ + if (ParentBus->InterfaceType == PCIBus) + { + /* Should trim addresses */ + if (!WarningsGiven[1]++) DPRINT1("Found parent PCI Bus (indicating PCI-to-PCI Bridge). PCI devices may fail!\n"); + } + + /* Check the next parent */ + ParentBus = ParentBus->ParentHandler; + } + } + } + + /* Loop buses one last time */ + for (i = 0; i < BusCount; i++) + { + /* Get the PCI bus handler */ + Bus = HalHandlerForBus(PCIBus, i); + + /* Sort and combine (trim) bus address range information */ + DPRINT("Warning: Bus addresses not being optimized!\n"); + } +} + +VOID +NTAPI +ShowSize(ULONG x) +{ + if (!x) return; + DbgPrint(" [size="); + if (x < 1024) + { + DbgPrint("%d", (int) x); + } + else if (x < 1048576) + { + DbgPrint("%dK", (int)(x / 1024)); + } + else if (x < 0x80000000) + { + DbgPrint("%dM", (int)(x / 1048576)); + } + else + { + DbgPrint("%d", x); + } + DbgPrint("]\n"); +} + +VOID +NTAPI +HalpDebugPciBus(IN ULONG i, + IN ULONG j, + IN ULONG k, + IN PPCI_COMMON_CONFIG PciData) +{ + extern CHAR ClassTable[3922]; + extern CHAR VendorTable[642355]; + PCHAR p, ClassName, SubClassName, VendorName, ProductName, SubVendorName; + ULONG Length; + CHAR LookupString[16] = ""; + CHAR bSubClassName[32] = ""; + CHAR bVendorName[32] = ""; + CHAR bProductName[32] = "Unknown device"; + CHAR bSubVendorName[32] = "Unknown"; + ULONG Size, Mem, b; + + /* Isolate the class name */ + sprintf(LookupString, "C %02x", PciData->BaseClass); + ClassName = strstr(ClassTable, LookupString); + if (ClassName) + { + /* Isolate the subclass name */ + ClassName += 6; + sprintf(LookupString, "\t%02x", PciData->SubClass); + SubClassName = strstr(ClassName, LookupString); + if (SubClassName) + { + /* Copy the subclass into our buffer */ + SubClassName += 5; + p = strchr(SubClassName, '\r'); + Length = p - SubClassName; + if (Length > sizeof(bSubClassName)) Length = sizeof(bSubClassName); + strncpy(bSubClassName, SubClassName, Length); + bSubClassName[Length] = '\0'; + } + } + + /* Isolate the vendor name */ + sprintf(LookupString, "\n%04x ", PciData->VendorID); + VendorName = strstr(VendorTable, LookupString); + if (VendorName) + { + /* Copy the vendor name into our buffer */ + VendorName += 7; + p = strchr(VendorName, '\r'); + Length = p - VendorName; + if (Length > sizeof(bVendorName)) Length = sizeof(bVendorName); + strncpy(bVendorName, VendorName, Length); + bVendorName[Length ] = '\0'; + + /* Isolate the product name */ + sprintf(LookupString, "\t%04x", PciData->DeviceID); + ProductName = strstr(VendorName, LookupString); + if (ProductName) + { + /* Copy the product name into our buffer */ + ProductName += 7; + p = strchr(ProductName, '\r'); + Length = p - ProductName; + if (Length > sizeof(bProductName)) Length = sizeof(bProductName); + strncpy(bProductName, ProductName, Length); + bProductName[Length] = '\0'; + + /* Isolate the subvendor and subsystem name */ + sprintf(LookupString, + "\t\t%04x %04x ", + PciData->u.type0.SubVendorID, + PciData->u.type0.SubSystemID); + SubVendorName = strstr(ProductName, LookupString); + if (SubVendorName) + { + /* Copy the subvendor name into our buffer */ + SubVendorName += 13; + p = strchr(SubVendorName, '\r'); + Length = p - SubVendorName; + if (Length > sizeof(bSubVendorName)) Length = sizeof(bSubVendorName); + strncpy(bSubVendorName, SubVendorName, Length); + bSubVendorName[Length] = '\0'; + } + } + } + + /* Print out the data */ + DbgPrint("%02x:%02x.%x %s [%02x%02x]: %s %s [%04x:%04x] (rev %02x)\n" + "\tSubsystem: %s [%04x:%04x]\n", + i, + j, + k, + bSubClassName, + PciData->BaseClass, + PciData->SubClass, + bVendorName, + bProductName, + PciData->VendorID, + PciData->DeviceID, + PciData->RevisionID, + bSubVendorName, + PciData->u.type0.SubVendorID, + PciData->u.type0.SubSystemID); + + /* Print out and decode flags */ + DbgPrint("\tFlags:"); + if (PciData->Command & PCI_ENABLE_BUS_MASTER) DbgPrint(" bus master,"); + if (PciData->Status & PCI_STATUS_66MHZ_CAPABLE) DbgPrint(" 66MHz,"); + if ((PciData->Status & PCI_STATUS_DEVSEL) == 0x200) DbgPrint(" medium devsel,"); + if ((PciData->Status & PCI_STATUS_DEVSEL) == 0x400) DbgPrint(" fast devsel,"); + DbgPrint(" latency %d", PciData->LatencyTimer); + if (PciData->u.type0.InterruptLine) DbgPrint(", IRQ %02d", PciData->u.type0.InterruptLine); + DbgPrint("\n"); + + /* Scan addresses */ + Size = 0; + for (b = 0; b < PCI_TYPE0_ADDRESSES; b++) + { + /* Check for a BAR */ + Mem = PciData->u.type0.BaseAddresses[b]; + if (Mem) + { + /* Decode the address type */ + if (Mem & PCI_ADDRESS_IO_SPACE) + { + /* Decode the size */ + Size = 1 << 2; + while (!(Mem & Size) && (Size)) Size <<= 1; + + /* Print it out */ + DbgPrint("\tI/O ports at %04lx", Mem & PCI_ADDRESS_IO_ADDRESS_MASK); + ShowSize(Size); + } + else + { + /* Decode the size */ + Size = 1 << 8; + while (!(Mem & Size) && (Size)) Size <<= 1; + + /* Print it out */ + DbgPrint("\tMemory at %08lx (%d-bit, %sprefetchable)", + Mem & PCI_ADDRESS_MEMORY_ADDRESS_MASK, + (Mem & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_32BIT ? 32 : 64, + (Mem & PCI_ADDRESS_MEMORY_PREFETCHABLE) ? "" : "non-"); + ShowSize(Size); + } + } + } +} +#endif + +VOID +NTAPI +HalpInitializePciBus(VOID) +{ +#ifndef _MINIHAL_ + PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo; + UCHAR PciType; + PCI_SLOT_NUMBER PciSlot; + ULONG i, j, k; + UCHAR DataBuffer[PCI_COMMON_HDR_LENGTH]; + PPCI_COMMON_CONFIG PciData = (PPCI_COMMON_CONFIG)DataBuffer; + PBUS_HANDLER BusHandler; + ULONG HackFlags; + BOOLEAN ExtendedAddressDecoding = FALSE; + NTSTATUS Status; + + /* Query registry information */ + PciRegistryInfo = HalpQueryPciRegistryInfo(); + if (!PciRegistryInfo) return; + + /* Initialize the PCI configuration lock */ + KeInitializeSpinLock(&HalpPCIConfigLock); + + /* Get the type and free the info structure */ + PciType = PciRegistryInfo->HardwareMechanism & 0xF; + + /* Check if this is a type 2 PCI bus with at least one bus */ + if ((PciRegistryInfo->NoBuses) && (PciType == 2)) + { + /* Setup the PCI slot */ + PciSlot.u.bits.Reserved = 0; + PciSlot.u.bits.FunctionNumber = 0; + + /* Loop all slots */ + for (i = 0; i < 32; i++) + { + /* Try to setup a Type 2 PCI slot */ + PciType = 2; + BusHandler = HalpAllocateAndInitPciBusHandler(2, 0, TRUE); + if (!BusHandler) break; + + /* Now check if it's valid */ + if (HalpIsValidPCIDevice(BusHandler, PciSlot)) break; + + /* Heh, the BIOS lied... try Type 1 */ + PciType = 1; + BusHandler = HalpAllocateAndInitPciBusHandler(1, 0, TRUE); + if (!BusHandler) break; + + /* Now check if it's valid */ + if (HalpIsValidPCIDevice(BusHandler, PciSlot)) break; + + /* Keep trying */ + PciType = 2; + } + + /* Now allocate the correct kind of handler */ + HalpAllocateAndInitPciBusHandler(PciType, 0, FALSE); + } + + /* Okay, now loop all PCI bridges */ + do + { + /* Loop all PCI buses */ + for (i = 0; i < PciRegistryInfo->NoBuses; i++) + { + /* Check if we have a handler for it */ + if (!HalHandlerForBus(PCIBus, i)) + { + /* Allocate it */ + HalpAllocateAndInitPciBusHandler(PciType, i, FALSE); + } + } + /* Go to the next bridge */ + } while (HalpGetPciBridgeConfig(PciType, &PciRegistryInfo->NoBuses)); + + /* Now build correct address range informaiton */ + HalpFixupPciSupportedRanges(PciRegistryInfo->NoBuses); + + /* Loop every bus */ + DbgPrint("\n====== PCI BUS HARDWARE DETECTION =======\n\n"); + PciSlot.u.bits.Reserved = 0; + for (i = 0; i < PciRegistryInfo->NoBuses; i++) + { + /* Get the bus handler */ + BusHandler = HalHandlerForBus(PCIBus, i); + + /* Loop every device */ + for (j = 0; j < 32; j++) + { + /* Loop every function */ + PciSlot.u.bits.DeviceNumber = j; + for (k = 0; k < 8; k++) + { + /* Build the final slot structure */ + PciSlot.u.bits.FunctionNumber = k; + + /* Read the configuration information */ + HalpReadPCIConfig(BusHandler, + PciSlot, + PciData, + 0, + PCI_COMMON_HDR_LENGTH); + + /* Skip if this is an invalid function */ + if (PciData->VendorID == PCI_INVALID_VENDORID) continue; + + /* Print out the entry */ + HalpDebugPciBus(i, j, k, PciData); + + /* Check if this is a Cardbus bridge */ + if (PCI_CONFIGURATION_TYPE(PciData) == PCI_CARDBUS_BRIDGE_TYPE) + { + /* Not supported */ + DbgPrint("\tDevice is a PCI Cardbus Bridge. It will not work!\n"); + continue; + } + + /* Check if this is a PCI device */ + if (PCI_CONFIGURATION_TYPE(PciData) != PCI_BRIDGE_TYPE) + { + /* Check if it has an interrupt pin and line registered */ + if ((PciData->u.type1.InterruptPin) && + (PciData->u.type1.InterruptLine)) + { + /* Check if this interrupt line is connected to the bus */ + if (PciData->u.type1.InterruptLine < 16) + { + /* Is this an IDE device? */ + if (!HalpIsIdeDevice(PciData)) + { + /* We'll mask out this interrupt then */ + DbgPrint("\tDevice is using IRQ %d! ISA Cards using that IRQ may fail!\n", + PciData->u.type1.InterruptLine); + HalpPciIrqMask |= (1 << PciData->u.type1.InterruptLine); + } + } + } + } + + /* Check for broken Intel chips */ + if (PciData->VendorID == 0x8086) + { + /* Check for broken 82830 PCI controller */ + if ((PciData->DeviceID == 0x04A3) && + (PciData->RevisionID < 0x11)) + { + /* Skip */ + DbgPrint("\tDevice is a broken Intel 82430 PCI Controller. It will not work!\n\n"); + continue; + } + + /* Check for broken 82378 PCI-to-ISA Bridge */ + if ((PciData->DeviceID == 0x0484) && + (PciData->RevisionID <= 3)) + { + /* Skip */ + DbgPrint("\tDevice is a broken Intel 82378 PCI-to-ISA Bridge. It will not work!\n\n"); + continue; + } + + /* Check for broken 82450 PCI Bridge */ + if ((PciData->DeviceID == 0x84C4) && + (PciData->RevisionID <= 4)) + { + DbgPrint("\tDevice is a Intel Orion 82450 PCI Bridge. It will not work!\n\n"); + continue; + } + } + + /* Do we know this card? */ + if (!ExtendedAddressDecoding) + { + /* Check for it */ + if (HalpIsRecognizedCard(PciRegistryInfo, + PciData, + HALP_CARD_FEATURE_FULL_DECODE)) + { + /* We'll do chipset checks later */ + DbgPrint("\tDevice has Extended Address Decoding. It may fail to work on older BIOSes!\n"); + ExtendedAddressDecoding = TRUE; + } + } + + /* Check if this is a USB controller */ + if ((PciData->BaseClass == PCI_CLASS_SERIAL_BUS_CTLR) && + (PciData->SubClass == PCI_SUBCLASS_SB_USB)) + { + /* Check if this is an OHCI controller */ + if (PciData->ProgIf == 0x10) + { + DbgPrint("\tDevice is an OHCI (USB) PCI Expansion Card. Turn off Legacy USB in your BIOS!\n\n"); + continue; + } + + /* Check for Intel UHCI controller */ + if (PciData->VendorID == 0x8086) + { + DbgPrint("\tDevice is an Intel UHCI (USB) Controller. Turn off Legacy USB in your BIOS!\n\n"); + continue; + } + + /* Check for VIA UHCI controller */ + if (PciData->VendorID == 0x1106) + { + DbgPrint("\tDevice is a VIA UHCI (USB) Controller. Turn off Legacy USB in your BIOS!\n\n"); + continue; + } + } + + /* Now check the registry for chipset hacks */ + Status = HalpGetChipHacks(PciData->VendorID, + PciData->DeviceID, + PciData->RevisionID, + &HackFlags); + if (NT_SUCCESS(Status)) + { + /* Check for broken ACPI routing */ + if (HackFlags & HAL_PCI_CHIP_HACK_DISABLE_ACPI_IRQ_ROUTING) + { + DbgPrint("This chipset has broken ACPI IRQ Routing! Be aware!\n\n"); + continue; + } + + /* Check for broken ACPI timer */ + if (HackFlags & HAL_PCI_CHIP_HACK_BROKEN_ACPI_TIMER) + { + DbgPrint("This chipset has a broken ACPI timer! Be aware!\n\n"); + continue; + } + + /* Check for hibernate-disable */ + if (HackFlags & HAL_PCI_CHIP_HACK_DISABLE_HIBERNATE) + { + DbgPrint("This chipset has a broken PCI device which is incompatible with hibernation. Be aware!\n\n"); + continue; + } + + /* Check for USB controllers that generate SMIs */ + if (HackFlags & HAL_PCI_CHIP_HACK_USB_SMI_DISABLE) + { + DbgPrint("This chipset has a USB controller which generates SMIs. ReactOS will likely fail to boot!\n\n"); + continue; + } + } + + /* Terminate the entry */ + DbgPrint("\n"); + } + } + } + + /* Initialize NMI Crash Flag */ + HalpGetNMICrashFlag(); + + /* Free the registry data */ + ExFreePool(PciRegistryInfo); + + /* Tell PnP if this hard supports correct decoding */ + HalpMarkChipsetDecode(ExtendedAddressDecoding); + DbgPrint("====== PCI BUS DETECTION COMPLETE =======\n\n"); +#endif +} + +VOID +NTAPI +HalpInitBusHandlers(VOID) +{ + /* Register the HAL Bus Handler support */ + HalpRegisterInternalBusHandlers(); +} + +VOID +NTAPI +HalpRegisterKdSupportFunctions(VOID) +{ + /* Register PCI Device Functions */ + KdSetupPciDeviceForDebugging = HalpSetupPciDeviceForDebugging; + KdReleasePciDeviceforDebugging = HalpReleasePciDeviceForDebugging; + + /* Register memory functions */ +#ifndef _MINIHAL_ + KdMapPhysicalMemory64 = HalpMapPhysicalMemory64; + KdUnmapVirtualAddress = HalpUnmapVirtualAddress; +#endif + + /* Register ACPI stub */ + KdCheckPowerButton = HalpCheckPowerButton; +} + +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) +{ + PBUS_HANDLER Handler; + NTSTATUS Status; + PAGED_CODE(); + DPRINT1("Slot assignment for %d on bus %d\n", BusType, BusNumber); + + /* Find the handler */ + Handler = HalReferenceHandlerForBus(BusType, BusNumber); + if (!Handler) return STATUS_NOT_FOUND; + + /* Do the assignment */ + Status = Handler->AssignSlotResources(Handler, + Handler, + RegistryPath, + DriverClassName, + DriverObject, + DeviceObject, + SlotNumber, + AllocatedResources); + + /* Dereference the handler and return */ + HalDereferenceBusHandler(Handler); + return Status; +} + +BOOLEAN +NTAPI +HaliFindBusAddressTranslation(IN PHYSICAL_ADDRESS BusAddress, + IN OUT PULONG AddressSpace, + OUT PPHYSICAL_ADDRESS TranslatedAddress, + IN OUT PULONG_PTR Context, + IN BOOLEAN NextBus) +{ + PHAL_BUS_HANDLER BusHandler; + PBUS_HANDLER Handler; + PLIST_ENTRY NextEntry; + ULONG ContextValue; + + /* Make sure we have a context */ + if (!Context) return FALSE; + ASSERT((*Context) || (NextBus == TRUE)); + + /* Read the context */ + ContextValue = *Context; + + /* Find the bus handler */ + Handler = HalpContextToBusHandler(ContextValue); + if (!Handler) return FALSE; + + /* Check if this is an ongoing lookup */ + if (NextBus) + { + /* Get the HAL bus handler */ + BusHandler = CONTAINING_RECORD(Handler, HAL_BUS_HANDLER, Handler); + NextEntry = &BusHandler->AllHandlers; + + /* Get the next one if we were already with one */ + if (ContextValue) NextEntry = NextEntry->Flink; + + /* Start scanning */ + while (TRUE) + { + /* Check if this is the last one */ + if (NextEntry == &HalpAllBusHandlers) + { + /* Quit */ + *Context = 1; + return FALSE; + } + + /* Call this translator */ + BusHandler = CONTAINING_RECORD(NextEntry, HAL_BUS_HANDLER, AllHandlers); + if (HalTranslateBusAddress(BusHandler->Handler.InterfaceType, + BusHandler->Handler.BusNumber, + BusAddress, + AddressSpace, + TranslatedAddress)) break; + + /* Try the next one */ + NextEntry = NextEntry->Flink; + } + + /* If we made it, we're done */ + *Context = (ULONG_PTR)Handler; + return TRUE; + } + + /* Try the first one through */ + if (!HalTranslateBusAddress(Handler->InterfaceType, + Handler->BusNumber, + BusAddress, + AddressSpace, + TranslatedAddress)) return FALSE; + + /* Remember for next time */ + *Context = (ULONG_PTR)Handler; + return TRUE; +} + +BOOLEAN +NTAPI +HaliTranslateBusAddress(IN INTERFACE_TYPE InterfaceType, + IN ULONG BusNumber, + IN PHYSICAL_ADDRESS BusAddress, + IN OUT PULONG AddressSpace, + OUT PPHYSICAL_ADDRESS TranslatedAddress) +{ + PBUS_HANDLER Handler; + BOOLEAN Status; + + /* Find the handler */ + Handler = HalReferenceHandlerForBus(InterfaceType, BusNumber); + if (!(Handler) || !(Handler->TranslateBusAddress)) + { + DPRINT1("No translator!\n"); + return FALSE; + } + + /* Do the assignment */ + Status = Handler->TranslateBusAddress(Handler, + Handler, + BusAddress, + AddressSpace, + TranslatedAddress); + + /* Dereference the handler and return */ + HalDereferenceBusHandler(Handler); + return Status; +} + +/* PUBLIC FUNCTIONS **********************************************************/ + +/* + * @implemented + */ +NTSTATUS +NTAPI +HalAdjustResourceList(IN PIO_RESOURCE_REQUIREMENTS_LIST *ResourceList) +{ + PBUS_HANDLER Handler; + ULONG Status; + PAGED_CODE(); + + /* Find the handler */ + Handler = HalReferenceHandlerForBus((*ResourceList)->InterfaceType, + (*ResourceList)->BusNumber); + if (!Handler) return STATUS_SUCCESS; + + /* Do the assignment */ + Status = Handler->AdjustResourceList(Handler, + Handler, + ResourceList); + + /* Dereference the handler and return */ + HalDereferenceBusHandler(Handler); + return Status; +} + +/* + * @implemented + */ +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) +{ + PAGED_CODE(); + + /* Check the bus type */ + if (BusType != PCIBus) + { + /* Call our internal handler */ + return HalpAssignSlotResources(RegistryPath, + DriverClassName, + DriverObject, + DeviceObject, + BusType, + BusNumber, + SlotNumber, + AllocatedResources); + } + else + { + /* Call the PCI registered function */ + return HalPciAssignSlotResources(RegistryPath, + DriverClassName, + DriverObject, + DeviceObject, + PCIBus, + BusNumber, + SlotNumber, + AllocatedResources); + } +} + +/* + * @implemented + */ +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); +} + +/* + * @implemented + */ +ULONG +NTAPI +HalGetBusDataByOffset(IN BUS_DATA_TYPE BusDataType, + IN ULONG BusNumber, + IN ULONG SlotNumber, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length) +{ + PBUS_HANDLER Handler; + ULONG Status; + + /* Find the handler */ + Handler = HaliReferenceHandlerForConfigSpace(BusDataType, BusNumber); + if (!Handler) return 0; + + /* Do the assignment */ + Status = Handler->GetBusData(Handler, + Handler, + SlotNumber, + Buffer, + Offset, + Length); + + /* Dereference the handler and return */ + HalDereferenceBusHandler(Handler); + return Status; +} + +/* + * @implemented + */ +ULONG +NTAPI +HalGetInterruptVector(IN INTERFACE_TYPE InterfaceType, + IN ULONG BusNumber, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity) +{ + PBUS_HANDLER Handler; + ULONG Vector; + PAGED_CODE(); + + /* Defaults */ + *Irql = 0; + *Affinity = 0; + + /* Find the handler */ + Handler = HalReferenceHandlerForBus(InterfaceType, BusNumber); + if (!Handler) return 0; + + /* Do the assignment */ + Vector = Handler->GetInterruptVector(Handler, + Handler, + BusInterruptLevel, + BusInterruptVector, + Irql, + Affinity); + if ((Vector != IRQ2VECTOR(BusInterruptLevel)) || + (*Irql != VECTOR2IRQL(IRQ2VECTOR(BusInterruptLevel)))) + { + DPRINT1("Returning IRQL %lx, Vector %lx for Level/Vector: %lx/%lx\n", + *Irql, Vector, BusInterruptLevel, BusInterruptVector); + DPRINT1("Old HAL would've returned IRQL %lx and Vector %lx\n", + VECTOR2IRQL(IRQ2VECTOR(BusInterruptLevel)), + IRQ2VECTOR(BusInterruptLevel)); + } + + /* Dereference the handler and return */ + HalDereferenceBusHandler(Handler); + return Vector; +} + +/* + * @implemented + */ +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); +} + +/* + * @implemented + */ +ULONG +NTAPI +HalSetBusDataByOffset(IN BUS_DATA_TYPE BusDataType, + IN ULONG BusNumber, + IN ULONG SlotNumber, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length) +{ + PBUS_HANDLER Handler; + ULONG Status; + + /* Find the handler */ + Handler = HaliReferenceHandlerForConfigSpace(BusDataType, BusNumber); + if (!Handler) return 0; + + /* Do the assignment */ + Status = Handler->SetBusData(Handler, + Handler, + SlotNumber, + Buffer, + Offset, + Length); + + /* Dereference the handler and return */ + HalDereferenceBusHandler(Handler); + return Status; +} + +/* + * @implemented + */ +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 + { + /* Call the bus handler */ + return HaliTranslateBusAddress(InterfaceType, + BusNumber, + BusAddress, + AddressSpace, + TranslatedAddress); + } +} + +/* EOF */ diff --git a/hal/halx86/generic/memory.c b/hal/halx86/generic/memory.c new file mode 100644 index 00000000000..74f20cbc6ed --- /dev/null +++ b/hal/halx86/generic/memory.c @@ -0,0 +1,234 @@ +/* + * PROJECT: ReactOS HAL + * LICENSE: GPL - See COPYING in the top level directory + * FILE: hal/halx86/generic/memory.c + * PURPOSE: HAL memory management + * PROGRAMMERS: ReactOS Portable Systems Group + */ + +/* INCLUDES ******************************************************************/ + +#include +#define NDEBUG +#include + +/* Share with Mm headers? */ +#define MM_HAL_VA_START (PVOID)0xFFC00000 +#define MM_HAL_HEAP_START (PVOID)((ULONG_PTR)MM_HAL_VA_START + (1024 * 1024)) + +/* GLOBALS *******************************************************************/ + +ULONG HalpUsedAllocDescriptors; +MEMORY_ALLOCATION_DESCRIPTOR HalpAllocationDescriptorArray[64]; +PVOID HalpHeapStart = MM_HAL_HEAP_START; + + +/* PRIVATE FUNCTIONS *********************************************************/ + + +ULONG +NTAPI +HalpAllocPhysicalMemory(IN PLOADER_PARAMETER_BLOCK LoaderBlock, + IN ULONG MaxAddress, + IN ULONG PageCount, + IN BOOLEAN Aligned) +{ + ULONG UsedDescriptors, Alignment, PhysicalAddress; + PFN_NUMBER MaxPage, BasePage; + 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 = (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 = 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 - Alignment) != PageCount) + { + /* Get the next descriptor */ + FreeBlock = &HalpAllocationDescriptorArray[UsedDescriptors]; + FreeBlock->PageCount = MdBlock->PageCount - Alignment - PageCount; + FreeBlock->BasePage = MdBlock->BasePage + Alignment + PageCount; + + /* One more */ + HalpUsedAllocDescriptors++; + + /* Insert it into the list */ + InsertHeadList(&MdBlock->ListEntry, &FreeBlock->ListEntry); + } + + /* Use this descriptor */ + NewBlock->PageCount = Alignment; + InsertHeadList(&MdBlock->ListEntry, &NewBlock->ListEntry); + } + else + { + /* Consume memory from this block */ + MdBlock->BasePage += PageCount; + MdBlock->PageCount -= PageCount; + + /* Insert the descriptor */ + 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 ULONG PageCount) +{ + PHARDWARE_PTE PointerPte; + ULONG 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 = 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 ULONG PageCount) +{ + PHARDWARE_PTE PointerPte; + ULONG i; + + /* Only accept valid addresses */ + if (VirtualAddress < 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 (i = 0; i < PageCount; i++) + { + *(PULONG)PointerPte = 0; + PointerPte++; + } + + /* Flush the TLB */ + HalpFlushTLB(); + + /* Put the heap back */ + if (HalpHeapStart > VirtualAddress) HalpHeapStart = VirtualAddress; +} +