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