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