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 /* Use the debug port table if we have one */ 291 HalpGetInfoFromACPI = HalpGetDebugPortTable(); 292 293 /* Check if we're using ACPI */ 294 if (!HalpGetInfoFromACPI) 295 { 296 /* No, so use our local table */ 297 for (i = 0, Port = HalpComPortIrqMapping[i][0]; 298 Port; 299 i++, Port = HalpComPortIrqMapping[i][0]) 300 { 301 /* Is this the port we want? */ 302 if (Port == (ULONG_PTR)KdComPortInUse) 303 { 304 /* Register it */ 305 HalpRegisterVector(IDT_DEVICE | IDT_LATCHED, 306 HalpComPortIrqMapping[i][1], 307 HalpComPortIrqMapping[i][1] + 308 PRIMARY_VECTOR_BASE, 309 HIGH_LEVEL); 310 } 311 } 312 } 313 } 314 315 /* On non-ACPI systems, we need to build an address map */ 316 HalpBuildAddressMap(); 317 318 /* Allocate the master raw and translated lists */ 319 RawList = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE * 2, TAG_HAL); 320 TranslatedList = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE * 2, TAG_HAL); 321 if (!(RawList) || !(TranslatedList)) 322 { 323 /* Bugcheck the system */ 324 KeBugCheckEx(HAL_MEMORY_ALLOCATION, 325 4 * PAGE_SIZE, 326 1, 327 (ULONG_PTR)__FILE__, 328 __LINE__); 329 } 330 331 /* Zero out the lists */ 332 RtlZeroMemory(RawList, PAGE_SIZE * 2); 333 RtlZeroMemory(TranslatedList, PAGE_SIZE * 2); 334 335 /* Set the interface type to begin with */ 336 RawList->List[0].InterfaceType = InterfaceTypeUndefined; 337 338 /* Loop all IDT entries that are not IRQs */ 339 for (i = 0; i < PRIMARY_VECTOR_BASE; i++) 340 { 341 /* Check if the IDT isn't owned */ 342 if (!(HalpIDTUsageFlags[i].Flags & IDT_REGISTERED)) 343 { 344 /* Then register it for internal usage */ 345 HalpIDTUsageFlags[i].Flags = IDT_INTERNAL; 346 HalpIDTUsage[i].BusReleativeVector = (UCHAR)i; 347 } 348 } 349 350 /* Our full raw descriptors start here */ 351 RawFull = RawList->List; 352 353 /* Keep track of the current partial raw and translated descriptors */ 354 CurrentRaw = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)RawList->List; 355 CurrentTranslated = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)TranslatedList->List; 356 357 /* Do two passes */ 358 for (ReportType = 0; ReportType < 2; ReportType++) 359 { 360 /* Pass 0 is for device usage */ 361 if (ReportType == 0) 362 { 363 FlagMatch = IDT_DEVICE & ~IDT_REGISTERED; 364 Interface = InterfaceType; 365 } 366 else 367 { 368 /* Past 1 is for internal HAL usage */ 369 FlagMatch = IDT_INTERNAL & ~IDT_REGISTERED; 370 Interface = Internal; 371 } 372 373 /* Reset loop variables */ 374 i = Element = 0; 375 376 /* Start looping our address uage list and interrupts */ 377 CurrentAddress = HalpAddressUsageList; 378 while (TRUE) 379 { 380 /* Check for valid vector number */ 381 if (i <= MAXIMUM_IDTVECTOR) 382 { 383 /* Check if this entry should be parsed */ 384 if ((HalpIDTUsageFlags[i].Flags & FlagMatch)) 385 { 386 /* Parse it */ 387 HalpBuildPartialFromIdt(i, &RawPartial, &TranslatedPartial); 388 i++; 389 } 390 else 391 { 392 /* Skip this entry */ 393 i++; 394 continue; 395 } 396 } 397 else 398 { 399 /* This is an address instead */ 400 if (!CurrentAddress) break; 401 402 /* Check if the address should be reported */ 403 if (!(CurrentAddress->Flags & FlagMatch) || 404 !(CurrentAddress->Element[Element].Length)) 405 { 406 /* Nope, skip it */ 407 Element = 0; 408 CurrentAddress = CurrentAddress->Next; 409 continue; 410 } 411 412 /* Otherwise, parse the entry */ 413 HalpBuildPartialFromAddress(Interface, 414 CurrentAddress, 415 Element, 416 &RawPartial, 417 &TranslatedPartial); 418 Element++; 419 } 420 421 /* Check for interface change */ 422 if (RawFull->InterfaceType != Interface) 423 { 424 /* We need to add another full descriptor */ 425 RawList->Count++; 426 TranslatedList->Count++; 427 428 /* The full descriptor follows wherever we were */ 429 RawFull = (PCM_FULL_RESOURCE_DESCRIPTOR)CurrentRaw; 430 TranslatedFull = (PCM_FULL_RESOURCE_DESCRIPTOR)CurrentTranslated; 431 432 /* And it is of this new interface type */ 433 RawFull->InterfaceType = Interface; 434 TranslatedFull->InterfaceType = Interface; 435 436 /* And its partial descriptors begin here */ 437 RawPartialList = &RawFull->PartialResourceList; 438 TranslatedPartialList = &TranslatedFull->PartialResourceList; 439 440 /* And our next full descriptor should follow here */ 441 CurrentRaw = RawFull->PartialResourceList.PartialDescriptors; 442 CurrentTranslated = TranslatedFull->PartialResourceList.PartialDescriptors; 443 } 444 445 /* We have written a new partial descriptor */ 446 RawPartialList->Count++; 447 TranslatedPartialList->Count++; 448 449 /* Copy our local descriptors into the actual list */ 450 RtlCopyMemory(CurrentRaw, &RawPartial, sizeof(RawPartial)); 451 RtlCopyMemory(CurrentTranslated, &TranslatedPartial, sizeof(TranslatedPartial)); 452 453 /* Move to the next partial descriptor */ 454 CurrentRaw++; 455 CurrentTranslated++; 456 } 457 } 458 459 /* Get the final list of the size for the kernel call later */ 460 ListSize = (ULONG)((ULONG_PTR)CurrentRaw - (ULONG_PTR)RawList); 461 462 /* Now reset back to the first full descriptor */ 463 RawFull = RawList->List; 464 TranslatedFull = TranslatedList->List; 465 466 /* And loop all the full descriptors */ 467 for (i = 0; i < RawList->Count; i++) 468 { 469 /* Get the first partial descriptor in this list */ 470 CurrentRaw = RawFull->PartialResourceList.PartialDescriptors; 471 CurrentTranslated = TranslatedFull->PartialResourceList.PartialDescriptors; 472 473 /* Get the count of partials in this list */ 474 Count = RawFull->PartialResourceList.Count; 475 476 /* Loop all the partials in this list */ 477 for (j = 0; j < Count; j++) 478 { 479 /* Get the sort value at this point */ 480 HalpGetResourceSortValue(CurrentRaw, &CurrentScale, &CurrentSortValue); 481 482 /* Save the current sort pointer */ 483 SortedRaw = CurrentRaw; 484 SortedTranslated = CurrentTranslated; 485 486 /* Loop all descriptors starting from this one */ 487 for (k = j; k < Count; k++) 488 { 489 /* Get the sort value at the sort point */ 490 HalpGetResourceSortValue(SortedRaw, &SortScale, &SortValue); 491 492 /* Check if a swap needs to occur */ 493 if ((SortScale < CurrentScale) || 494 ((SortScale == CurrentScale) && 495 (SortValue.QuadPart <= CurrentSortValue.QuadPart))) 496 { 497 /* Swap raw partial with the sort location partial */ 498 RtlCopyMemory(&RawPartial, CurrentRaw, sizeof(RawPartial)); 499 RtlCopyMemory(CurrentRaw, SortedRaw, sizeof(RawPartial)); 500 RtlCopyMemory(SortedRaw, &RawPartial, sizeof(RawPartial)); 501 502 /* Swap translated partial in the same way */ 503 RtlCopyMemory(&TranslatedPartial, CurrentTranslated, sizeof(TranslatedPartial)); 504 RtlCopyMemory(CurrentTranslated, SortedTranslated, sizeof(TranslatedPartial)); 505 RtlCopyMemory(SortedTranslated, &TranslatedPartial, sizeof(TranslatedPartial)); 506 507 /* Update the sort value at this point */ 508 HalpGetResourceSortValue(CurrentRaw, &CurrentScale, &CurrentSortValue); 509 } 510 511 /* The sort location has been updated */ 512 SortedRaw++; 513 SortedTranslated++; 514 } 515 516 /* Move to the next partial */ 517 CurrentRaw++; 518 CurrentTranslated++; 519 } 520 521 /* Move to the next full descriptor */ 522 RawFull = (PCM_FULL_RESOURCE_DESCRIPTOR)CurrentRaw; 523 TranslatedFull = (PCM_FULL_RESOURCE_DESCRIPTOR)CurrentTranslated; 524 } 525 526 /* Mark this is an ACPI system, if it is */ 527 HalpMarkAcpiHal(); 528 529 /* Tell the kernel about all this */ 530 IoReportHalResourceUsage(HalName, 531 RawList, 532 TranslatedList, 533 ListSize); 534 535 /* Free our lists */ 536 ExFreePool(RawList); 537 ExFreePool(TranslatedList); 538 539 /* Get the machine's serial number */ 540 HalpReportSerialNumber(); 541 } 542 #endif /* !_MINIHAL_ */ 543 544 CODE_SEG("INIT") 545 VOID 546 NTAPI 547 HalpRegisterVector(IN UCHAR Flags, 548 IN ULONG BusVector, 549 IN ULONG SystemVector, 550 IN KIRQL Irql) 551 { 552 /* Save the vector flags */ 553 HalpIDTUsageFlags[SystemVector].Flags = Flags; 554 555 /* Save the vector data */ 556 HalpIDTUsage[SystemVector].Irql = Irql; 557 HalpIDTUsage[SystemVector].BusReleativeVector = (UCHAR)BusVector; 558 } 559 560 #ifndef _MINIHAL_ 561 CODE_SEG("INIT") 562 VOID 563 NTAPI 564 HalpEnableInterruptHandler(IN UCHAR Flags, 565 IN ULONG BusVector, 566 IN ULONG SystemVector, 567 IN KIRQL Irql, 568 IN PVOID Handler, 569 IN KINTERRUPT_MODE Mode) 570 { 571 /* Set the IDT_LATCHED flag for latched interrupts */ 572 if (Mode == Latched) Flags |= IDT_LATCHED; 573 574 /* Register the vector */ 575 HalpRegisterVector(Flags, BusVector, SystemVector, Irql); 576 577 /* Connect the interrupt */ 578 KeRegisterInterruptHandler(SystemVector, Handler); 579 580 /* Enable the interrupt */ 581 HalEnableSystemInterrupt(SystemVector, Irql, Mode); 582 } 583 584 CODE_SEG("INIT") 585 VOID 586 NTAPI 587 HalpGetNMICrashFlag(VOID) 588 { 589 UNICODE_STRING ValueName; 590 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\CrashControl"); 591 OBJECT_ATTRIBUTES ObjectAttributes; 592 ULONG ResultLength; 593 HANDLE Handle; 594 NTSTATUS Status; 595 KEY_VALUE_PARTIAL_INFORMATION KeyValueInformation; 596 597 /* Set default */ 598 HalpNMIDumpFlag = 0; 599 600 /* Initialize attributes */ 601 InitializeObjectAttributes(&ObjectAttributes, 602 &KeyName, 603 OBJ_CASE_INSENSITIVE, 604 NULL, 605 NULL); 606 607 /* Open crash key */ 608 Status = ZwOpenKey(&Handle, KEY_READ, &ObjectAttributes); 609 if (NT_SUCCESS(Status)) 610 { 611 /* Query key value */ 612 RtlInitUnicodeString(&ValueName, L"NMICrashDump"); 613 Status = ZwQueryValueKey(Handle, 614 &ValueName, 615 KeyValuePartialInformation, 616 &KeyValueInformation, 617 sizeof(KeyValueInformation), 618 &ResultLength); 619 if (NT_SUCCESS(Status)) 620 { 621 /* Check for valid data */ 622 if (ResultLength == sizeof(KEY_VALUE_PARTIAL_INFORMATION)) 623 { 624 /* Read the flag */ 625 HalpNMIDumpFlag = KeyValueInformation.Data[0]; 626 } 627 } 628 629 /* We're done */ 630 ZwClose(Handle); 631 } 632 } 633 #endif /* !_MINIHAL_ */ 634 635 /* EOF */ 636