1 /* 2 * PROJECT: ReactOS HAL 3 * LICENSE: GPL - See COPYING in the top level directory 4 * PURPOSE: HAL Resource Report Routines 5 * PROGRAMMERS: Stefan Ginsberg (stefan.ginsberg@reactos.org) 6 */ 7 8 /* INCLUDES *******************************************************************/ 9 10 #include <hal.h> 11 12 #define NDEBUG 13 #include <debug.h> 14 15 /* GLOBALS ********************************************************************/ 16 17 BOOLEAN HalpGetInfoFromACPI; 18 BOOLEAN HalpNMIDumpFlag; 19 PUCHAR KdComPortInUse; 20 PADDRESS_USAGE HalpAddressUsageList; 21 IDTUsageFlags HalpIDTUsageFlags[MAXIMUM_IDTVECTOR+1]; 22 IDTUsage HalpIDTUsage[MAXIMUM_IDTVECTOR+1]; 23 24 USHORT HalpComPortIrqMapping[5][2] = 25 { 26 {0x3F8, 4}, 27 {0x2F8, 3}, 28 {0x3E8, 4}, 29 {0x2E8, 3}, 30 {0, 0} 31 }; 32 33 ADDRESS_USAGE HalpComIoSpace = 34 { 35 NULL, CmResourceTypePort, IDT_INTERNAL, 36 { 37 {0x2F8, 0x8}, /* COM 1 */ 38 {0,0}, 39 } 40 }; 41 42 ADDRESS_USAGE HalpDefaultIoSpace = 43 { 44 NULL, CmResourceTypePort, IDT_INTERNAL, 45 { 46 #if defined(SARCH_PC98) 47 /* PIC 1 */ 48 {0x00, 1}, 49 {0x02, 1}, 50 /* PIC 2 */ 51 {0x08, 1}, 52 {0x0A, 1}, 53 /* DMA */ 54 {0x01, 1}, 55 {0x03, 1}, 56 {0x05, 1}, 57 {0x07, 1}, 58 {0x09, 1}, 59 {0x0B, 1}, 60 {0x0D, 1}, 61 {0x0F, 1}, 62 {0x11, 1}, 63 {0x13, 1}, 64 {0x15, 1}, 65 {0x17, 1}, 66 {0x19, 1}, 67 {0x1B, 1}, 68 {0x1D, 1}, 69 {0x1F, 1}, 70 {0x21, 1}, 71 {0x23, 1}, 72 {0x25, 1}, 73 {0x27, 1}, 74 {0x29, 1}, 75 {0x2B, 1}, 76 {0x2D, 1}, 77 {0xE05, 1}, 78 {0xE07, 1}, 79 {0xE09, 1}, 80 {0xE0B, 1}, 81 /* RTC */ 82 {0x20, 1}, 83 {0x22, 1}, 84 {0x128, 1}, 85 /* System Control */ 86 {0x33, 1}, 87 {0x37, 1}, 88 /* PIT */ 89 {0x71, 1}, 90 {0x73, 1}, 91 {0x75, 1}, 92 {0x77, 1}, 93 {0x3FD9,1}, 94 {0x3FDB,1}, 95 {0x3FDD,1}, 96 {0x3FDF,1}, 97 /* x87 Coprocessor */ 98 {0xF8, 8}, 99 #else 100 {0x00, 0x20}, /* DMA 1 */ 101 {0xC0, 0x20}, /* DMA 2 */ 102 {0x80, 0x10}, /* DMA EPAR */ 103 {0x20, 0x2}, /* PIC 1 */ 104 {0xA0, 0x2}, /* PIC 2 */ 105 {0x40, 0x4}, /* PIT 1 */ 106 {0x48, 0x4}, /* PIT 2 */ 107 {0x92, 0x1}, /* System Control Port A */ 108 {0x70, 0x2}, /* CMOS */ 109 {0xF0, 0x10}, /* x87 Coprocessor */ 110 #endif 111 {0xCF8, 0x8}, /* PCI 0 */ 112 {0,0}, 113 } 114 }; 115 116 /* FUNCTIONS ******************************************************************/ 117 118 #ifndef _MINIHAL_ 119 CODE_SEG("INIT") 120 VOID 121 NTAPI 122 HalpGetResourceSortValue(IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor, 123 OUT PULONG Scale, 124 OUT PLARGE_INTEGER Value) 125 { 126 /* Sorting depends on resource type */ 127 switch (Descriptor->Type) 128 { 129 case CmResourceTypeInterrupt: 130 131 /* Interrupt goes by level */ 132 *Scale = 0; 133 *Value = RtlConvertUlongToLargeInteger(Descriptor->u.Interrupt.Level); 134 break; 135 136 case CmResourceTypePort: 137 138 /* Port goes by port address */ 139 *Scale = 1; 140 *Value = Descriptor->u.Port.Start; 141 break; 142 143 case CmResourceTypeMemory: 144 145 /* Memory goes by base address */ 146 *Scale = 2; 147 *Value = Descriptor->u.Memory.Start; 148 break; 149 150 default: 151 152 /* Anything else */ 153 *Scale = 4; 154 *Value = RtlConvertUlongToLargeInteger(0); 155 break; 156 } 157 } 158 159 CODE_SEG("INIT") 160 VOID 161 NTAPI 162 HalpBuildPartialFromIdt(IN ULONG Entry, 163 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR RawDescriptor, 164 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR TranslatedDescriptor) 165 { 166 /* Exclusive interrupt entry */ 167 RawDescriptor->Type = CmResourceTypeInterrupt; 168 RawDescriptor->ShareDisposition = CmResourceShareDriverExclusive; 169 170 /* Check the interrupt type */ 171 if (HalpIDTUsageFlags[Entry].Flags & IDT_LATCHED) 172 { 173 /* Latched */ 174 RawDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED; 175 } 176 else 177 { 178 /* Level */ 179 RawDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; 180 } 181 182 /* Get vector and level from IDT usage */ 183 RawDescriptor->u.Interrupt.Vector = HalpIDTUsage[Entry].BusReleativeVector; 184 RawDescriptor->u.Interrupt.Level = HalpIDTUsage[Entry].BusReleativeVector; 185 186 /* Affinity is all the CPUs */ 187 RawDescriptor->u.Interrupt.Affinity = HalpActiveProcessors; 188 189 /* The translated copy is identical */ 190 RtlCopyMemory(TranslatedDescriptor, RawDescriptor, sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)); 191 192 /* But the vector and IRQL must be set correctly */ 193 TranslatedDescriptor->u.Interrupt.Vector = Entry; 194 TranslatedDescriptor->u.Interrupt.Level = HalpIDTUsage[Entry].Irql; 195 } 196 197 CODE_SEG("INIT") 198 VOID 199 NTAPI 200 HalpBuildPartialFromAddress(IN INTERFACE_TYPE Interface, 201 IN PADDRESS_USAGE CurrentAddress, 202 IN ULONG Element, 203 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR RawDescriptor, 204 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR TranslatedDescriptor) 205 { 206 ULONG AddressSpace; 207 208 /* Set the type and make it exclusive */ 209 RawDescriptor->Type = CurrentAddress->Type; 210 RawDescriptor->ShareDisposition = CmResourceShareDriverExclusive; 211 212 /* Check what this is */ 213 if (RawDescriptor->Type == CmResourceTypePort) 214 { 215 /* Write out port data */ 216 AddressSpace = 1; 217 RawDescriptor->Flags = CM_RESOURCE_PORT_IO; 218 RawDescriptor->u.Port.Start.HighPart = 0; 219 RawDescriptor->u.Port.Start.LowPart = CurrentAddress->Element[Element].Start; 220 RawDescriptor->u.Port.Length = CurrentAddress->Element[Element].Length; 221 222 /* Determine if 16-bit port addresses are allowed */ 223 RawDescriptor->Flags |= HalpIs16BitPortDecodeSupported(); 224 } 225 else 226 { 227 /* Write out memory data */ 228 AddressSpace = 0; 229 RawDescriptor->Flags = (CurrentAddress->Flags & IDT_READ_ONLY) ? 230 CM_RESOURCE_MEMORY_READ_ONLY : 231 CM_RESOURCE_MEMORY_READ_WRITE; 232 RawDescriptor->u.Memory.Start.HighPart = 0; 233 RawDescriptor->u.Memory.Start.LowPart = CurrentAddress->Element[Element].Start; 234 RawDescriptor->u.Memory.Length = CurrentAddress->Element[Element].Length; 235 } 236 237 /* Make an identical copy to begin with */ 238 RtlCopyMemory(TranslatedDescriptor, RawDescriptor, sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)); 239 240 /* Check what this is */ 241 if (RawDescriptor->Type == CmResourceTypePort) 242 { 243 /* Translate the port */ 244 HalTranslateBusAddress(Interface, 245 0, 246 RawDescriptor->u.Port.Start, 247 &AddressSpace, 248 &TranslatedDescriptor->u.Port.Start); 249 250 /* If it turns out this is memory once translated, flag it */ 251 if (AddressSpace == 0) TranslatedDescriptor->Flags = CM_RESOURCE_PORT_MEMORY; 252 253 } 254 else 255 { 256 /* Translate the memory */ 257 HalTranslateBusAddress(Interface, 258 0, 259 RawDescriptor->u.Memory.Start, 260 &AddressSpace, 261 &TranslatedDescriptor->u.Memory.Start); 262 } 263 } 264 265 CODE_SEG("INIT") 266 VOID 267 NTAPI 268 HalpReportResourceUsage(IN PUNICODE_STRING HalName, 269 IN INTERFACE_TYPE InterfaceType) 270 { 271 PCM_RESOURCE_LIST RawList, TranslatedList; 272 PCM_FULL_RESOURCE_DESCRIPTOR RawFull, TranslatedFull; 273 PCM_PARTIAL_RESOURCE_DESCRIPTOR CurrentRaw, CurrentTranslated, SortedRaw, SortedTranslated; 274 CM_PARTIAL_RESOURCE_DESCRIPTOR RawPartial, TranslatedPartial; 275 PCM_PARTIAL_RESOURCE_LIST RawPartialList = NULL, TranslatedPartialList = NULL; 276 INTERFACE_TYPE Interface; 277 ULONG i, j, k, ListSize, Count, Port, Element, CurrentScale, SortScale, ReportType, FlagMatch; 278 ADDRESS_USAGE *CurrentAddress; 279 LARGE_INTEGER CurrentSortValue, SortValue; 280 DbgPrint("%wZ Detected\n", HalName); 281 282 /* Check if KD is using a COM port */ 283 if (KdComPortInUse) 284 { 285 /* Enter it into the I/O space */ 286 HalpComIoSpace.Element[0].Start = PtrToUlong(KdComPortInUse); 287 HalpComIoSpace.Next = HalpAddressUsageList; 288 HalpAddressUsageList = &HalpComIoSpace; 289 290 #if defined(SARCH_XBOX) 291 /* 292 * Do not claim interrupt resources for the KD COM port. 293 * The actual COM port lacks SERIRQ, IRQ 4 is hardwired to the NIC. 294 */ 295 UNREFERENCED_PARAMETER(Port); 296 #else 297 /* Use the debug port table if we have one */ 298 HalpGetInfoFromACPI = HalpGetDebugPortTable(); 299 300 /* Check if we're using ACPI */ 301 if (!HalpGetInfoFromACPI) 302 { 303 /* No, so use our local table */ 304 for (i = 0, Port = HalpComPortIrqMapping[i][0]; 305 Port; 306 i++, Port = HalpComPortIrqMapping[i][0]) 307 { 308 /* Is this the port we want? */ 309 if (Port == (ULONG_PTR)KdComPortInUse) 310 { 311 /* Register it */ 312 HalpRegisterVector(IDT_DEVICE | IDT_LATCHED, 313 HalpComPortIrqMapping[i][1], 314 HalpComPortIrqMapping[i][1] + 315 PRIMARY_VECTOR_BASE, 316 HIGH_LEVEL); 317 } 318 } 319 } 320 #endif 321 } 322 323 /* On non-ACPI systems, we need to build an address map */ 324 HalpBuildAddressMap(); 325 326 /* Allocate the master raw and translated lists */ 327 RawList = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE * 2, TAG_HAL); 328 TranslatedList = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE * 2, TAG_HAL); 329 if (!(RawList) || !(TranslatedList)) 330 { 331 /* Bugcheck the system */ 332 KeBugCheckEx(HAL_MEMORY_ALLOCATION, 333 4 * PAGE_SIZE, 334 1, 335 (ULONG_PTR)__FILE__, 336 __LINE__); 337 } 338 339 /* Zero out the lists */ 340 RtlZeroMemory(RawList, PAGE_SIZE * 2); 341 RtlZeroMemory(TranslatedList, PAGE_SIZE * 2); 342 343 /* Set the interface type to begin with */ 344 RawList->List[0].InterfaceType = InterfaceTypeUndefined; 345 346 /* Loop all IDT entries that are not IRQs */ 347 for (i = 0; i < PRIMARY_VECTOR_BASE; i++) 348 { 349 /* Check if the IDT isn't owned */ 350 if (!(HalpIDTUsageFlags[i].Flags & IDT_REGISTERED)) 351 { 352 /* Then register it for internal usage */ 353 HalpIDTUsageFlags[i].Flags = IDT_INTERNAL; 354 HalpIDTUsage[i].BusReleativeVector = (UCHAR)i; 355 } 356 } 357 358 /* Our full raw descriptors start here */ 359 RawFull = RawList->List; 360 361 /* Keep track of the current partial raw and translated descriptors */ 362 CurrentRaw = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)RawList->List; 363 CurrentTranslated = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)TranslatedList->List; 364 365 /* Do two passes */ 366 for (ReportType = 0; ReportType < 2; ReportType++) 367 { 368 /* Pass 0 is for device usage */ 369 if (ReportType == 0) 370 { 371 FlagMatch = IDT_DEVICE & ~IDT_REGISTERED; 372 Interface = InterfaceType; 373 } 374 else 375 { 376 /* Past 1 is for internal HAL usage */ 377 FlagMatch = IDT_INTERNAL & ~IDT_REGISTERED; 378 Interface = Internal; 379 } 380 381 /* Reset loop variables */ 382 i = Element = 0; 383 384 /* Start looping our address uage list and interrupts */ 385 CurrentAddress = HalpAddressUsageList; 386 while (TRUE) 387 { 388 /* Check for valid vector number */ 389 if (i <= MAXIMUM_IDTVECTOR) 390 { 391 /* Check if this entry should be parsed */ 392 if ((HalpIDTUsageFlags[i].Flags & FlagMatch)) 393 { 394 /* Parse it */ 395 HalpBuildPartialFromIdt(i, &RawPartial, &TranslatedPartial); 396 i++; 397 } 398 else 399 { 400 /* Skip this entry */ 401 i++; 402 continue; 403 } 404 } 405 else 406 { 407 /* This is an address instead */ 408 if (!CurrentAddress) break; 409 410 /* Check if the address should be reported */ 411 if (!(CurrentAddress->Flags & FlagMatch) || 412 !(CurrentAddress->Element[Element].Length)) 413 { 414 /* Nope, skip it */ 415 Element = 0; 416 CurrentAddress = CurrentAddress->Next; 417 continue; 418 } 419 420 /* Otherwise, parse the entry */ 421 HalpBuildPartialFromAddress(Interface, 422 CurrentAddress, 423 Element, 424 &RawPartial, 425 &TranslatedPartial); 426 Element++; 427 } 428 429 /* Check for interface change */ 430 if (RawFull->InterfaceType != Interface) 431 { 432 /* We need to add another full descriptor */ 433 RawList->Count++; 434 TranslatedList->Count++; 435 436 /* The full descriptor follows wherever we were */ 437 RawFull = (PCM_FULL_RESOURCE_DESCRIPTOR)CurrentRaw; 438 TranslatedFull = (PCM_FULL_RESOURCE_DESCRIPTOR)CurrentTranslated; 439 440 /* And it is of this new interface type */ 441 RawFull->InterfaceType = Interface; 442 TranslatedFull->InterfaceType = Interface; 443 444 /* And its partial descriptors begin here */ 445 RawPartialList = &RawFull->PartialResourceList; 446 TranslatedPartialList = &TranslatedFull->PartialResourceList; 447 448 /* And our next full descriptor should follow here */ 449 CurrentRaw = RawFull->PartialResourceList.PartialDescriptors; 450 CurrentTranslated = TranslatedFull->PartialResourceList.PartialDescriptors; 451 } 452 453 /* We have written a new partial descriptor */ 454 RawPartialList->Count++; 455 TranslatedPartialList->Count++; 456 457 /* Copy our local descriptors into the actual list */ 458 RtlCopyMemory(CurrentRaw, &RawPartial, sizeof(RawPartial)); 459 RtlCopyMemory(CurrentTranslated, &TranslatedPartial, sizeof(TranslatedPartial)); 460 461 /* Move to the next partial descriptor */ 462 CurrentRaw++; 463 CurrentTranslated++; 464 } 465 } 466 467 /* Get the final list of the size for the kernel call later */ 468 ListSize = (ULONG)((ULONG_PTR)CurrentRaw - (ULONG_PTR)RawList); 469 470 /* Now reset back to the first full descriptor */ 471 RawFull = RawList->List; 472 TranslatedFull = TranslatedList->List; 473 474 /* And loop all the full descriptors */ 475 for (i = 0; i < RawList->Count; i++) 476 { 477 /* Get the first partial descriptor in this list */ 478 CurrentRaw = RawFull->PartialResourceList.PartialDescriptors; 479 CurrentTranslated = TranslatedFull->PartialResourceList.PartialDescriptors; 480 481 /* Get the count of partials in this list */ 482 Count = RawFull->PartialResourceList.Count; 483 484 /* Loop all the partials in this list */ 485 for (j = 0; j < Count; j++) 486 { 487 /* Get the sort value at this point */ 488 HalpGetResourceSortValue(CurrentRaw, &CurrentScale, &CurrentSortValue); 489 490 /* Save the current sort pointer */ 491 SortedRaw = CurrentRaw; 492 SortedTranslated = CurrentTranslated; 493 494 /* Loop all descriptors starting from this one */ 495 for (k = j; k < Count; k++) 496 { 497 /* Get the sort value at the sort point */ 498 HalpGetResourceSortValue(SortedRaw, &SortScale, &SortValue); 499 500 /* Check if a swap needs to occur */ 501 if ((SortScale < CurrentScale) || 502 ((SortScale == CurrentScale) && 503 (SortValue.QuadPart <= CurrentSortValue.QuadPart))) 504 { 505 /* Swap raw partial with the sort location partial */ 506 RtlCopyMemory(&RawPartial, CurrentRaw, sizeof(RawPartial)); 507 RtlCopyMemory(CurrentRaw, SortedRaw, sizeof(RawPartial)); 508 RtlCopyMemory(SortedRaw, &RawPartial, sizeof(RawPartial)); 509 510 /* Swap translated partial in the same way */ 511 RtlCopyMemory(&TranslatedPartial, CurrentTranslated, sizeof(TranslatedPartial)); 512 RtlCopyMemory(CurrentTranslated, SortedTranslated, sizeof(TranslatedPartial)); 513 RtlCopyMemory(SortedTranslated, &TranslatedPartial, sizeof(TranslatedPartial)); 514 515 /* Update the sort value at this point */ 516 HalpGetResourceSortValue(CurrentRaw, &CurrentScale, &CurrentSortValue); 517 } 518 519 /* The sort location has been updated */ 520 SortedRaw++; 521 SortedTranslated++; 522 } 523 524 /* Move to the next partial */ 525 CurrentRaw++; 526 CurrentTranslated++; 527 } 528 529 /* Move to the next full descriptor */ 530 RawFull = (PCM_FULL_RESOURCE_DESCRIPTOR)CurrentRaw; 531 TranslatedFull = (PCM_FULL_RESOURCE_DESCRIPTOR)CurrentTranslated; 532 } 533 534 /* Mark this is an ACPI system, if it is */ 535 HalpMarkAcpiHal(); 536 537 /* Tell the kernel about all this */ 538 IoReportHalResourceUsage(HalName, 539 RawList, 540 TranslatedList, 541 ListSize); 542 543 /* Free our lists */ 544 ExFreePool(RawList); 545 ExFreePool(TranslatedList); 546 547 /* Get the machine's serial number */ 548 HalpReportSerialNumber(); 549 } 550 #endif /* !_MINIHAL_ */ 551 552 CODE_SEG("INIT") 553 VOID 554 NTAPI 555 HalpRegisterVector(IN UCHAR Flags, 556 IN ULONG BusVector, 557 IN ULONG SystemVector, 558 IN KIRQL Irql) 559 { 560 /* Save the vector flags */ 561 HalpIDTUsageFlags[SystemVector].Flags = Flags; 562 563 /* Save the vector data */ 564 HalpIDTUsage[SystemVector].Irql = Irql; 565 HalpIDTUsage[SystemVector].BusReleativeVector = (UCHAR)BusVector; 566 } 567 568 #ifndef _MINIHAL_ 569 CODE_SEG("INIT") 570 VOID 571 NTAPI 572 HalpEnableInterruptHandler(IN UCHAR Flags, 573 IN ULONG BusVector, 574 IN ULONG SystemVector, 575 IN KIRQL Irql, 576 IN PVOID Handler, 577 IN KINTERRUPT_MODE Mode) 578 { 579 /* Set the IDT_LATCHED flag for latched interrupts */ 580 if (Mode == Latched) Flags |= IDT_LATCHED; 581 582 /* Register the vector */ 583 HalpRegisterVector(Flags, BusVector, SystemVector, Irql); 584 585 /* Connect the interrupt */ 586 KeRegisterInterruptHandler(SystemVector, Handler); 587 588 /* Enable the interrupt */ 589 HalEnableSystemInterrupt(SystemVector, Irql, Mode); 590 } 591 592 CODE_SEG("INIT") 593 VOID 594 NTAPI 595 HalpGetNMICrashFlag(VOID) 596 { 597 UNICODE_STRING ValueName; 598 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\CrashControl"); 599 OBJECT_ATTRIBUTES ObjectAttributes; 600 ULONG ResultLength; 601 HANDLE Handle; 602 NTSTATUS Status; 603 KEY_VALUE_PARTIAL_INFORMATION KeyValueInformation; 604 605 /* Set default */ 606 HalpNMIDumpFlag = 0; 607 608 /* Initialize attributes */ 609 InitializeObjectAttributes(&ObjectAttributes, 610 &KeyName, 611 OBJ_CASE_INSENSITIVE, 612 NULL, 613 NULL); 614 615 /* Open crash key */ 616 Status = ZwOpenKey(&Handle, KEY_READ, &ObjectAttributes); 617 if (NT_SUCCESS(Status)) 618 { 619 /* Query key value */ 620 RtlInitUnicodeString(&ValueName, L"NMICrashDump"); 621 Status = ZwQueryValueKey(Handle, 622 &ValueName, 623 KeyValuePartialInformation, 624 &KeyValueInformation, 625 sizeof(KeyValueInformation), 626 &ResultLength); 627 if (NT_SUCCESS(Status)) 628 { 629 /* Check for valid data */ 630 if (ResultLength == sizeof(KEY_VALUE_PARTIAL_INFORMATION)) 631 { 632 /* Read the flag */ 633 HalpNMIDumpFlag = KeyValueInformation.Data[0]; 634 } 635 } 636 637 /* We're done */ 638 ZwClose(Handle); 639 } 640 } 641 #endif /* !_MINIHAL_ */ 642 643 /* EOF */ 644