/*++ Copyright (c) 1997 Microsoft Corporation Module Name: acpi.c Abstract: WinDbg Extension Api for interpretting ACPI data structures Author: Stephane Plante (splante) 21-Mar-1997 Based on Code by: Peter Wieland (peterwie) 16-Oct-1995 Environment: User Mode. Revision History: --*/ #include "pch.h" UCHAR Buffer[2048]; PCCHAR DeviceStateTable[] = { "Stopped", "Inactive", "Started", "Removed", "SurpriseRemoved", "Invalid", }; PCCHAR DevicePowerStateTable[] = { "PowerDeviceUnspecified", "PowerDeviceD0", "PowerDeviceD1", "PowerDeviceD2", "PowerDeviceD3", "PowerDeviceMaximum", }; PCCHAR SystemPowerStateTable[] = { "PowerSystemUnspecified", "PowerSystemWorking", "PowerSystemSleepingS1", "PowerSystemSleepingS2", "PowerSystemSleepingS3", "PowerSystemHibernate", "PowerSystemShutdown", "PowerSystemMaximum", }; PCCHAR SystemPowerActionTable[] = { "PowerActionNone", "PowerActionReserved", "PowerActionSleep", "PowerActionHibernate", "PowerActionShutdown", "PowerActionShutdownReset", "PowerActionShutdownOff", "PowerActionWarmEject" }; CCHAR ReallyShortDevicePowerStateTable[] = { 'W', '0', '1', '2', '3', 'M', }; PCCHAR ShortDevicePowerStateTable[] = { "Dw", "D0", "D1", "D2", "D3", "Dmax", }; CCHAR ReallyShortSystemPowerStateTable[] = { 'W', '0', '1', '2', '3', '4', '5', 'M', }; PCCHAR ShortSystemPowerStateTable[] = { "Sx", "S0", "S1", "S2", "S3", "S4", "S5", "SM", }; PCCHAR WorkDone[] = { "Complete", "Pending", "Failure", "Step 0", "Step 1", "Step 2", "Step 3", "Step 4", "Step 5", "Step 6", "Step 7", "Step 8", "Step 9", "Step 10", "Step 11", "Step 12", "Step 13", "Step 14", "Step 15", "Step 16", "Step 17", "Step 18", "Step 19", "Step 20", "Step 21", "Step 22", "Step 23", "Step 24", "Step 25", "Step 26", }; FLAG_RECORD DeviceExtensionButtonEventFlags[] = { { 0x00000001, "Pwr", "\"Power Button\"" , NULL, NULL }, { 0x00000002, "Slp", "\"Sleep Button\"" , NULL, NULL }, { 0x00000004, "Lid", "\"Lid Switch\"" , NULL, NULL }, { 0x80000000, "Wake", "\"Wake Capable\"" , NULL, NULL }, }; FLAG_RECORD DeviceExtensionFlags[] = { { 0x0000000000000001, "Nev", "NeverPresent" , NULL, NULL }, { 0x0000000000000002, "!P" , "NotPresent" , NULL, NULL }, { 0x0000000000000004, "Rmv", "Removed" , NULL, NULL }, { 0x0000000000000008, "!F" , "NotFound" , NULL, NULL }, { 0x0000000000000010, "Fdo", "FunctionalDeviceObject" , NULL, NULL }, { 0x0000000000000020, "Pdo", "PhysicalDeviceObject" , NULL, NULL }, { 0x0000000000000040, "Fil", "Filter" , NULL, NULL }, { 0x0000000000010000, "Wak", "Wake" , NULL, NULL }, { 0x0000000000020000, "Raw", "RawOK" , NULL, NULL }, { 0x0000000000040000, "But", "Button" , NULL, NULL }, { 0x0000000000080000, "PS0", "AlwaysOn" , NULL, NULL }, { 0x0000000000100000, "!Fil", "NeverFilter" , NULL, NULL }, { 0x0000000000200000, "!Stop", "NeverStop" , NULL, NULL }, { 0x0000000000400000, "!Off", "NeverOverrideOff" , NULL, NULL }, { 0x0000000000800000, "ISA", "ISABus" , NULL, NULL }, { 0x0000000001000000, "EIO", "EIOBus" , NULL, NULL }, { 0x0000000002000000, "PCI", "PCIBus" , NULL, NULL }, { 0x0000000004000000, "Ser", "SerialPort" , NULL, NULL }, { 0x0000000008000000, "Tz", "ThermalZone" , NULL, NULL }, { 0x0000000010000000, "Lnk", "LinkNode" , NULL, NULL }, { 0x0000000020000000, "!UI", "NoShowInUI" , NULL, NULL }, { 0x0000000040000000, "!!UI", "NeverShowInUI" , NULL, NULL }, { 0x0000000080000000, "D3", "StartInD3" , NULL, NULL }, { 0x0000000100000000, "pci", "PCIDevice" , NULL, NULL }, { 0x0000000200000000, "PIC", "ProgrammableInterruptController" , NULL, NULL }, { 0x0000000400000000, "Dock-", "UnattachedDock" , NULL, NULL }, { 0x0000100000000000, "Adr", "HasAddress" , NULL, NULL }, { 0x0000200000000000, "HID", "HasHardwareID" , NULL, NULL }, { 0x0000400000000000, "UID", "HasUniqueID" , NULL, NULL }, { 0x0000800000000000, "hid", "FakeHardwareID" , NULL, NULL }, { 0x0001000000000000, "uid", "FakeUniqueID" , NULL, NULL }, { 0x0002000000000000, "BAD", "FailedInit" , NULL, NULL }, { 0x0004000000000000, "SRS", "Programmable" , NULL, NULL }, { 0x0008000000000000, "Fake", "NoAcpiObject" , NULL, NULL }, { 0x0010000000000000, "Excl", "Exclusive" , NULL, NULL }, { 0x0020000000000000, "Ini", "RanINI" , NULL, NULL }, { 0x0040000000000000, "Ena", "Enabled" , "!Ena", "NotEnabled" }, { 0x0080000000000000, "BAD", "Failed" , NULL, NULL }, { 0x0100000000000000, "Pwr", "AcpiPower" , NULL, NULL }, { 0x0200000000000000, "Dock", "DockProfile" , NULL, NULL }, { 0x0400000000000000, "S->D", "BuiltPowerTables" , NULL, NULL }, { 0x0800000000000000, "PME", "UsesPME" , NULL, NULL }, { 0x1000000000000000, "!Lid", "NoLidAction" , NULL, NULL }, }; FLAG_RECORD DeviceExtensionThermalFlags[] = { { 0x00000001, "Cooling", "\"Cooling Level\"" , NULL, NULL }, { 0x00000002, "Temp", "Temp" , NULL, NULL }, { 0x00000004, "Trip", "\"Trip Points\"" , NULL, NULL }, { 0x00000008, "Mode", "Mode" , NULL, NULL }, { 0x00000010, "Init", "Initialize" , NULL, NULL }, { 0x20000000, "Wait", "\"Wait for Notify\"" , NULL, NULL }, { 0x40000000, "Busy", "Busy" , NULL, NULL }, { 0x80000000, "Loop", "\"In Service Loop\"" , NULL, NULL }, }; FLAG_RECORD PM1ControlFlags[] = { { 0x0001, "", "SCI_EN" , NULL, NULL }, { 0x0002, "", "BM_RLD" , NULL, NULL }, { 0x0004, "", "GBL_RLS" , NULL, NULL }, { 0x0400, "", "SLP_TYP0" , NULL, NULL }, { 0x0800, "", "SLP_TYP1" , NULL, NULL }, { 0x1000, "", "SLP_TYP2" , NULL, NULL }, { 0x2000, "", "SLP_EN" , NULL, NULL }, }; FLAG_RECORD PM1StatusFlags[] = { { 0x0001, "", "TMR_STS" , NULL, NULL }, { 0x0010, "", "BM_STS" , NULL, NULL }, { 0x0020, "", "GBL_STS" , NULL, NULL }, { 0x0100, "", "PWRBTN_STS" , NULL, NULL }, { 0x0200, "", "SLPBTN_STS" , NULL, NULL }, { 0x0400, "", "RTC_STS" , NULL, NULL }, { 0x8000, "", "WAK_STS" , NULL, NULL }, }; FLAG_RECORD PM1EnableFlags[] = { { 0x0001, "", "TMR_EN" , NULL, NULL }, { 0x0020, "", "GBL_EN" , NULL, NULL }, { 0x0100, "", "PWRBTN_EN" , NULL, NULL }, { 0x0200, "", "SLPBTN_EN" , NULL, NULL }, { 0x0400, "", "RTC_EN" , NULL, NULL }, }; FLAG_RECORD PowerNodeFlags[] = { { 0x00001, "PO", "Present" , NULL, NULL }, { 0x00002, "Init", "Initialized" , NULL, NULL }, { 0x00004, "!STA", "\"Status Unknown\"" , NULL, NULL }, { 0x00010, "On", "On" , "Off", "Off" }, { 0x00020, "On+", "OverrideOn" , NULL, NULL }, { 0x00040, "Off-", "OverrideOff" , NULL, NULL }, { 0x00200, "On++", "AlwaysOn" , NULL, NULL }, { 0x00400, "Off--", "AlwaysOff" , NULL, NULL }, { 0x10000, "Fail", "Failed" , NULL, NULL }, { 0x20000, "Hiber", "HibernatePath" , NULL, NULL }, }; FLAG_RECORD PowerRequestFlags[] = { { 0x00001, "Dly", "Delayed", NULL, NULL }, { 0x00002, "!Q", "NoQueue", NULL, NULL }, { 0x00004, "Lck", "LockDevice", NULL, NULL }, { 0x00008, "!Lck", "UnlockDevice", NULL, NULL }, { 0x00010, "+Hbr", "LockHiber", NULL, NULL }, { 0x00020, "-Hbr", "UnlockHiber", NULL, NULL }, { 0x00040, "Can", "HasCancel", NULL, NULL }, }; VOID displayAcpiDeviceExtension( IN PDEVICE_EXTENSION DeviceExtension, IN ULONG_PTR Address, IN ULONG Verbose, IN ULONG IndentLevel ) /*++ Routine Description: This routine is responsible for displaying a device extension Arguments: DeviceExtension - Extension to display Address - Where the extension lives in memory Verbose - How much information to display IndentLevel - How much to tab it over Return Value: None --*/ { BOOL b; DEVICE_POWER_STATE k; DWORD_PTR displacement; IRP_DISPATCH_TABLE dispatchTable; PACPI_POWER_INFO powerInfo; SYSTEM_POWER_STATE s; UCHAR indent[80]; ULONG i,j; ULONG returnLength; IndentLevel = (IndentLevel > 79 ? 79 : IndentLevel); memset( indent, ' ', IndentLevel ); indent[IndentLevel] = '\0'; powerInfo = &(DeviceExtension->PowerInfo); // // Check signature // if (DeviceExtension->Signature != ACPI_SIGNATURE) { dprintf( "%s Unknown Signature. This does appear to be an " "ACPI Extension\n", indent ); return; } // // Line #1 // dprintf("%sACPI DeviceExtension - %lx - ",indent, Address); displayAcpiDeviceExtensionName( Address ); #if 0 if (DeviceExtension->Flags & DEV_PROP_HID) { if (DeviceExtension->DeviceID != NULL) { memset( Buffer, '0', 2048 ); b = ReadMemory( (ULONG_PTR) DeviceExtension->DeviceID, Buffer, 32, &returnLength ); if (!b || Buffer[0] == '\0') { dprintf(" (%lx)", DeviceExtension->DeviceID ); } else { dprintf(" %s", Buffer ); } } else { dprintf( " NULL" ); } if (DeviceExtension->Flags & DEV_PROP_UID) { if (DeviceExtension->InstanceID) { memset( Buffer, '0', 256 ); b = ReadMemory( (ULONG_PTR) DeviceExtension->InstanceID, Buffer, 256, &returnLength); if (!b || returnLength != 256 || Buffer[0] == '\0') { dprintf(" [ (%lx) ]", DeviceExtension->InstanceID ); } else { dprintf(" [%s]", Buffer ); } } else { dprintf(" [NULL]"); } } } else if (DeviceExtension->Flags & DEV_PROP_ADDRESS) { dprintf(" %lx", DeviceExtension->Address ); } #endif dprintf("\n"); // // Line #2 // dprintf( "%s DevObj %8lx PhysicalObj %8lx ", indent, DeviceExtension->DeviceObject, DeviceExtension->PhysicalDeviceObject ); if (DeviceExtension->TargetDeviceObject != NULL) { dprintf("AttachedTo %8lx", DeviceExtension->TargetDeviceObject ); } dprintf("\n"); // // Line #3 // dprintf( "%s AcpiObject %8lx ParentExt %8lx\n", indent, DeviceExtension->AcpiObject, DeviceExtension->ParentExtension ); // // Line #4 // dprintf( "%s PnpState %-8s OldPnpState %-8s\n", indent, DeviceStateTable[DeviceExtension->DeviceState], DeviceStateTable[DeviceExtension->PreviousState] ); // // Line #4 // dprintf("%s ",indent); if (DeviceExtension->ResourceList != NULL) { dprintf("CmResList %lx ", DeviceExtension->ResourceList ); } else { dprintf(" "); } if (DeviceExtension->PnpResourceList != NULL) { dprintf("PnpResList %lx ", DeviceExtension->PnpResourceList ); } else { dprintf(" "); } dprintf( "RefCounts %dD %dI %dH %dW\n", DeviceExtension->ReferenceCount, DeviceExtension->OutstandingIrpCount, DeviceExtension->HibernatePathCount, powerInfo->WakeSupportCount ); // // Line #5 // if (DeviceExtension->Flags & DEV_PROP_DOCK) { dprintf( "%s Dock %8lx ", indent, DeviceExtension->Dock ); } else { dprintf( "%s ", indent ); } dprintf( "Dispatch %8lx ", DeviceExtension->DispatchTable ); if (DeviceExtension->RemoveEvent != NULL) { dprintf("Remove %lx", DeviceExtension->RemoveEvent); } dprintf("\n"); // // Line #6 // if (powerInfo->DeviceNotifyHandler != NULL) { GetSymbol( powerInfo->DeviceNotifyHandler, Buffer, &displacement ); dprintf( "%s Handler %lx Context %8lx %s+%x\n", indent, powerInfo->DeviceNotifyHandler, powerInfo->Context, Buffer, displacement ); } // // Line #7-12 // for (k = PowerDeviceUnspecified; k <= PowerDeviceD3; k++) { if (k < PowerDeviceD3) { if (powerInfo->PowerObject[k] == NULL && powerInfo->PowerNode[k] == NULL) { continue; } } else { if (powerInfo->PowerObject[k] == NULL) { continue; } } // // Did we print on this line? // b = FALSE; dprintf("%s ", indent); if (powerInfo->PowerObject[k] != NULL) { dprintf( "_PS%c %lx ", ReallyShortDevicePowerStateTable[k], powerInfo->PowerObject[k] ); b = TRUE; } if (k <= PowerDeviceD2 && powerInfo->PowerNode[k] != NULL) { if (b) { dprintf( "%s Nodes %lx ", ShortDevicePowerStateTable[k], powerInfo->PowerNode[k] ); } else { dprintf( "%s Nodes %lx ", ShortDevicePowerStateTable[k], powerInfo->PowerNode[k] ); } } dprintf("\n"); } // // Line #13 // dprintf( "%s State %-2s", indent, ShortDevicePowerStateTable[powerInfo->PowerState]); if (powerInfo->DesiredPowerState != powerInfo->PowerState) { dprintf("->%-4s ", ShortDevicePowerStateTable[powerInfo->DesiredPowerState]); } else { dprintf(" "); } dprintf("SxD Mapping "); for (s = PowerSystemWorking; s < PowerSystemMaximum; s++) { k = powerInfo->DevicePowerMatrix[s]; if (k == PowerDeviceUnspecified) { continue; } dprintf( "S%c->D%c ", ReallyShortSystemPowerStateTable[s], ReallyShortDevicePowerStateTable[k] ); } dprintf("\n"); // // Line #14 // if (DeviceExtension->Flags & DEV_CAP_WAKE) { // // Print the start of the line // dprintf("%s ", indent); s = powerInfo->SystemWakeLevel; if (s == PowerSystemUnspecified) { dprintf("Sw->Sx " ); } else { dprintf("Sw->S%c ", ReallyShortSystemPowerStateTable[s] ); } k = DeviceExtension->PowerInfo.DeviceWakeLevel; if (k == PowerDeviceUnspecified) { dprintf("Dw->Dx " ); } else { dprintf("Dw->D%c ", ReallyShortDevicePowerStateTable[k] ); } dprintf( " Wake Pin %8d WakeCount %8x\n", powerInfo->WakeBit, powerInfo->WakeSupportCount ); } // // Line #15 // if (powerInfo->CurrentPowerRequest != NULL) { dprintf( "%s CurrentReq %lx ", indent, powerInfo->CurrentPowerRequest ); if (powerInfo->PowerRequestListEntry.Flink != (PLIST_ENTRY) (Address + FIELD_OFFSET(DEVICE_EXTENSION, PowerInfo.PowerRequestListEntry) ) ) { dprintf( "PowerReqList %lx %lx", CONTAINING_RECORD( powerInfo->PowerRequestListEntry.Flink, ACPI_POWER_REQUEST, SerialListEntry ), CONTAINING_RECORD( powerInfo->PowerRequestListEntry.Blink, ACPI_POWER_REQUEST, SerialListEntry ) ); } dprintf("\n"); } // // At this point, we are done with the common bits, and now deal with the // special parts of the extension // if ( (DeviceExtension->Flags & DEV_TYPE_FDO) ) { dprintf( "%s DPC Obj %8lx Int Object %08lx\n", indent, (Address + FIELD_OFFSET(DEVICE_EXTENSION, Fdo.InterruptDpc) ), DeviceExtension->Fdo.InterruptObject ); dprintf( "%s PM1 Status %8lx\n", indent, DeviceExtension->Fdo.Pm1Status ); dumpPM1StatusRegister( DeviceExtension->Fdo.Pm1Status, IndentLevel + 2 ); } if ( (DeviceExtension->Flags & DEV_CAP_BUTTON) ) { dprintf( "%s LidState %-8s SpinLock %x ", indent, (DeviceExtension->Button.LidState ? "TRUE" : "FALSE"), (Address + FIELD_OFFSET(DEVICE_EXTENSION, Button.SpinLock) ) ); if (DeviceExtension->Button.Events) { dumpFlags( (DeviceExtension->Button.Events), &DeviceExtensionButtonEventFlags[0], sizeof(DeviceExtensionButtonEventFlags)/sizeof(FLAG_RECORD), IndentLevel, (DUMP_FLAG_SHORT_NAME | DUMP_FLAG_NO_INDENT | DUMP_FLAG_SINGLE_LINE | DUMP_FLAG_NO_EOL) ); } dprintf("\n"); if (DeviceExtension->Button.Capabilities) { dprintf( "%s Capability %lx ", indent, DeviceExtension->Button.Capabilities ); dumpFlags( (DeviceExtension->Button.Capabilities), &DeviceExtensionButtonEventFlags[0], sizeof(DeviceExtensionButtonEventFlags)/sizeof(FLAG_RECORD), IndentLevel, (DUMP_FLAG_LONG_NAME | DUMP_FLAG_NO_INDENT | DUMP_FLAG_SINGLE_LINE | DUMP_FLAG_NO_EOL) ); dprintf("\n"); } } if ( (DeviceExtension->Flags & DEV_CAP_THERMAL_ZONE) ) { THRM_INFO thrm; dprintf( "%s Info %lx Flags %8x ", indent, DeviceExtension->Thermal.Info, DeviceExtension->Thermal.Flags ); dumpFlags( (DeviceExtension->Thermal.Flags), &DeviceExtensionThermalFlags[0], sizeof(DeviceExtensionThermalFlags)/sizeof(FLAG_RECORD), IndentLevel, (DUMP_FLAG_SHORT_NAME | DUMP_FLAG_NO_INDENT | DUMP_FLAG_SINGLE_LINE | DUMP_FLAG_NO_EOL) ); dprintf("\n"); // // Read the thermal Information and print it // b = ReadMemory( (ULONG_PTR) DeviceExtension->Thermal.Info, &thrm, sizeof(THRM_INFO), &returnLength ); if (!b || returnLength != sizeof(THRM_INFO)) { dprintf( "%s Could not read THRM_INFO @ %08lx\n", indent, DeviceExtension->Thermal.Info ); } else { displayThermalInfo( &thrm, (ULONG_PTR) DeviceExtension->Thermal.Info, Verbose, IndentLevel + 2 ); } } // // Last Line. At this point, we can dump the ACPI Flags // dprintf("%s Flags %016I64x ", indent, DeviceExtension->Flags ); dumpFlags( (DeviceExtension->Flags), &DeviceExtensionFlags[0], sizeof(DeviceExtensionFlags)/sizeof(FLAG_RECORD), IndentLevel + 4, (DUMP_FLAG_SHORT_NAME | DUMP_FLAG_NO_INDENT | DUMP_FLAG_SINGLE_LINE) ); dumpFlags( (DeviceExtension->Flags), &DeviceExtensionFlags[0], sizeof(DeviceExtensionFlags)/sizeof(FLAG_RECORD), IndentLevel + 4, (DUMP_FLAG_LONG_NAME) ); } VOID displayAcpiDeviceExtensionBrief( IN PDEVICE_EXTENSION DeviceExtension, IN ULONG_PTR Address, IN ULONG Verbose, IN ULONG IndentLevel ) /*++ Routine Description: This routine displays a one line summary of the device extension Arguments: DeviceExtension - The extension to display Address - Where the extension is located Verbose - How much information to display IndentLevel - How much whitespace to use Return Value: VOID --*/ { BOOL b; PDEVICE_EXTENSION deviceExtension; ULONG address; ULONG i; ULONG returnLength; ULONG startAddress; // // Should we print this extension? // if ( (Verbose & VERBOSE_PRESENT) && (DeviceExtension->Flags & DEV_TYPE_NOT_FOUND) ) { return; } // // Make the IndentLevel 'relative' - Device By 4 // IndentLevel /= 4; // // Indent the text // for (i = 0; i < IndentLevel; i++) { dprintf("| "); } // // Print the address of the object // dprintf("%08lx", Address ); // // Try to get the name & instance // if (DeviceExtension->Flags & DEV_PROP_HID) { if (DeviceExtension->DeviceID) { memset( Buffer, '0', 2048 ); b = ReadMemory( (ULONG_PTR) DeviceExtension->DeviceID, Buffer, 256, &returnLength ); if (b && Buffer[0] != '\0') { dprintf(" %s", Buffer ); } } else { dprintf(" "); } if (DeviceExtension->Flags & DEV_PROP_UID) { if (DeviceExtension->InstanceID) { memset( Buffer, '0', 2048 ); b = ReadMemory( (ULONG_PTR) DeviceExtension->InstanceID, Buffer, 256, &returnLength ); if (b && Buffer[0] != '\0') { dprintf("(%s)", Buffer ); } } else { dprintf(" "); } } } else if (DeviceExtension->Flags & DEV_PROP_ADDRESS) { dprintf(" %lx", DeviceExtension->Address ); } else { dprintf(" "); } if (Verbose & VERBOSE_THERMAL) { DEVICE_POWER_STATE d; SYSTEM_POWER_STATE s; if (DeviceExtension->PowerInfo.PowerState == 0) { dprintf(" Dx" ); } else { dprintf(" D%d", (DeviceExtension->PowerInfo.PowerState - 1) ); } for (s = PowerSystemWorking; s < PowerSystemMaximum; s++) { d = DeviceExtension->PowerInfo.DevicePowerMatrix[s]; if (d == PowerDeviceUnspecified) { continue; } dprintf( " S%c->D%c", ReallyShortSystemPowerStateTable[s], ReallyShortDevicePowerStateTable[d] ); } if (DeviceExtension->Flags & DEV_CAP_WAKE) { s = DeviceExtension->PowerInfo.SystemWakeLevel; if (s == PowerSystemUnspecified) { dprintf(" Sw->Sx" ); } else { dprintf(" Sw->S%c", ReallyShortSystemPowerStateTable[s] ); } d = DeviceExtension->PowerInfo.DeviceWakeLevel; if (d == PowerDeviceUnspecified) { dprintf(" Dw->Dx" ); } else { dprintf(" Dw->D%c", ReallyShortDevicePowerStateTable[d] ); } } // // If we are displaying thermal information, cut short early // dprintf("\n"); return; } dprintf(" NS %08lx", DeviceExtension->AcpiObject ); if (DeviceExtension->PowerInfo.PowerState == 0) { dprintf(" Dx" ); } else { dprintf(" D%d", (DeviceExtension->PowerInfo.PowerState - 1) ); } // // Print the device state // if (DeviceExtension->DeviceState == Stopped) { dprintf(" stop"); } else if (DeviceExtension->DeviceState == Inactive) { dprintf(" inac"); } else if (DeviceExtension->DeviceState == Started) { dprintf(" star"); } else if (DeviceExtension->DeviceState == Removed) { dprintf(" remv"); } else if (DeviceExtension->DeviceState == SurpriseRemoved) { dprintf(" surp"); } else { dprintf(" inva"); } dprintf(" %d-%d-%d", DeviceExtension->OutstandingIrpCount, DeviceExtension->ReferenceCount, DeviceExtension->HibernatePathCount ); // // Display the flags // dumpFlags( (DeviceExtension->Flags), &DeviceExtensionFlags[0], sizeof(DeviceExtensionFlags)/sizeof(FLAG_RECORD), IndentLevel + 4, (DUMP_FLAG_SHORT_NAME | DUMP_FLAG_NO_INDENT | DUMP_FLAG_SINGLE_LINE) ); // displayAcpiDeviceExtensionFlags( DeviceExtension ); } VOID displayAcpiDeviceExtensionFlags( IN PDEVICE_EXTENSION DeviceExtension ) /*++ Routine Description: This routine displays the Flag for a device extension This routine prints a new line at the end of the only line of text that it consumes Arguments: DeviceExtension - The extension whose flags to dump Return Value: None --*/ { // // Dump the flags // if (DeviceExtension->Flags & DEV_TYPE_NEVER_PRESENT) { dprintf(" Nev"); } if (DeviceExtension->Flags & DEV_TYPE_NOT_PRESENT) { dprintf(" N/P"); } if (DeviceExtension->Flags & DEV_TYPE_REMOVED) { dprintf(" Rmv"); } if (DeviceExtension->Flags & DEV_TYPE_NOT_FOUND) { dprintf(" N/F"); } if (DeviceExtension->Flags & DEV_TYPE_FDO) { dprintf(" Fdo"); } if (DeviceExtension->Flags & DEV_TYPE_PDO) { dprintf(" Pdo"); } if (DeviceExtension->Flags & DEV_TYPE_FILTER) { dprintf(" Fil"); } if (DeviceExtension->Flags & DEV_CAP_WAKE) { dprintf(" Wak"); } if (DeviceExtension->Flags & DEV_CAP_RAW) { dprintf(" Raw"); } if (DeviceExtension->Flags & DEV_CAP_BUTTON) { dprintf(" But"); } if (DeviceExtension->Flags & DEV_CAP_ALWAYS_PS0) { dprintf(" PS0"); } if (DeviceExtension->Flags & DEV_CAP_NO_FILTER) { dprintf(" !Fil"); } if (DeviceExtension->Flags & DEV_CAP_NO_STOP) { dprintf(" !Stop"); } if (DeviceExtension->Flags & DEV_CAP_NO_OVERRIDE) { dprintf(" !Off"); } if (DeviceExtension->Flags & DEV_CAP_ISA) { dprintf(" Isa"); } if (DeviceExtension->Flags & DEV_CAP_EIO) { dprintf(" Eio"); } if (DeviceExtension->Flags & DEV_CAP_PCI) { dprintf(" Pci"); } if (DeviceExtension->Flags & DEV_CAP_SERIAL) { dprintf(" Ser"); } if (DeviceExtension->Flags & DEV_CAP_THERMAL_ZONE) { dprintf(" Thrm"); } if (DeviceExtension->Flags & DEV_CAP_LINK_NODE) { dprintf(" Lnk"); } if (DeviceExtension->Flags & DEV_CAP_NO_SHOW_IN_UI) { dprintf(" !UI"); } if (DeviceExtension->Flags & DEV_CAP_NEVER_SHOW_IN_UI) { dprintf(" !!UI"); } if (DeviceExtension->Flags & DEV_CAP_START_IN_D3) { dprintf(" D3"); } if (DeviceExtension->Flags & DEV_CAP_PCI_DEVICE) { dprintf(" PciD"); } if (DeviceExtension->Flags & DEV_CAP_PIC_DEVICE) { dprintf(" PIC"); } if (DeviceExtension->Flags & DEV_CAP_UNATTACHED_DOCK) { dprintf(" Dock-"); } if (DeviceExtension->Flags & DEV_PROP_ADDRESS) { dprintf(" Adr"); } if (DeviceExtension->Flags & DEV_PROP_FIXED_HID) { dprintf(" FHid"); } else if (DeviceExtension->Flags & DEV_PROP_HID) { dprintf(" Hid"); } if (DeviceExtension->Flags & DEV_PROP_FIXED_UID) { dprintf(" FUid"); } else if (DeviceExtension->Flags & DEV_PROP_UID) { dprintf(" Uid"); } if (DeviceExtension->Flags & DEV_PROP_FAILED_INIT) { dprintf(" !INIT"); } if (DeviceExtension->Flags & DEV_PROP_SRS_PRESENT) { dprintf(" SRS"); } if (DeviceExtension->Flags & DEV_PROP_NO_OBJECT) { dprintf(" Fake"); } if (DeviceExtension->Flags & DEV_PROP_EXCLUSIVE) { dprintf(" Excl"); } if (DeviceExtension->Flags & DEV_PROP_RAN_INI) { dprintf(" Ini"); } if (!(DeviceExtension->Flags & DEV_PROP_DEVICE_ENABLED)) { dprintf(" !Ena"); } if (DeviceExtension->Flags & DEV_PROP_DEVICE_FAILED) { dprintf(" Fail"); } if (DeviceExtension->Flags & DEV_PROP_ACPI_POWER) { dprintf(" Pwr"); } if (DeviceExtension->Flags & DEV_PROP_DOCK) { dprintf(" Prof"); } if (DeviceExtension->Flags & DEV_PROP_BUILT_POWER_TABLE) { dprintf(" S->D"); } if (DeviceExtension->Flags & DEV_PROP_HAS_PME) { dprintf(" PME"); } dprintf("\n"); } VOID displayAcpiDeviceExtensionName( IN ULONG_PTR DeviceExtensionAddress ) /*++ Routine Description: This routine is tasked to with displaying the name of the device in the best possible manner Arguments: DeviceExtensionAddress - The Address of the DeviceExtension Return Value: NONE --*/ { BOOL status; DEVICE_EXTENSION deviceExtension; NSOBJ acpiObject; UCHAR nameBuffer[80]; ULONG_PTR nameAddress; ULONG returnLength; // // Read the entier extension // status = ReadMemory( DeviceExtensionAddress, &deviceExtension, sizeof(DEVICE_EXTENSION), &returnLength ); if (status && returnLength == sizeof(DEVICE_EXTENSION) ) { if (deviceExtension.Flags & DEV_PROP_HID) { if (deviceExtension.DeviceID != NULL) { // // Now, try to read the name into the buffer // status = ReadMemory( (ULONG_PTR) deviceExtension.DeviceID, nameBuffer, 79, &returnLength ); if (status && returnLength) { nameBuffer[returnLength] = '\0'; dprintf("%s",nameBuffer); } else { dprintf("(%lx)", deviceExtension.DeviceID); } } else { dprintf("NULL"); } } if (deviceExtension.Flags & DEV_PROP_UID) { if (deviceExtension.InstanceID != NULL) { // // Now, try to read the name into the buffer // status = ReadMemory( (ULONG_PTR) deviceExtension.InstanceID, nameBuffer, 79, &returnLength ); if (status && returnLength) { nameBuffer[returnLength] = '\0'; dprintf(" [%s]",nameBuffer); } else { dprintf(" [ (%lx) ]", deviceExtension.InstanceID); } } else { dprintf(" [NULL]"); } } if (deviceExtension.Flags & DEV_PROP_ADDRESS) { dprintf("%lx", deviceExtension.Address ); } return; } // // In this case, obtain the address of the ACPIObject for this device // nameAddress = (ULONG_PTR) &(deviceExtension.AcpiObject) - (ULONG_PTR) &(deviceExtension) + DeviceExtensionAddress; status = ReadMemory( nameAddress, &(deviceExtension.AcpiObject), sizeof(PNSOBJ), &returnLength ); if (status && returnLength == sizeof(PNSOBJ)) { // // Read the object // status = ReadMemory( (ULONG_PTR) deviceExtension.AcpiObject, &acpiObject, sizeof(NSOBJ), &returnLength ); if (status && returnLength == sizeof(NSOBJ)) { memcpy( nameBuffer, &(acpiObject.dwNameSeg), 4 ); nameBuffer[4] = '\0'; dprintf("Acpi(%s)", nameBuffer); return; } } dprintf("Unknown"); return; } VOID displayThermalInfo( IN PTHRM_INFO ThrmInfo, IN ULONG_PTR Address, IN ULONG Verbose, IN ULONG IndentLevel ) /*++ This routine displays a thermal information structure --*/ { BOOLEAN noIndent; UCHAR indent[80]; UINT i; IndentLevel = (IndentLevel > 79 ? 79 : IndentLevel); memset( indent, ' ', IndentLevel ); indent[IndentLevel] = '\0'; dprintf( "%s Stamp %8lx Affinity %08lx Mode %s\n", indent, ThrmInfo->Info.ThermalStamp, ThrmInfo->Info.Processors, (ThrmInfo->Mode == 0 ? "Active" : "Passive") ); dprintf( "%s SampleRate %8ss Constant1 %08lx Constant2 %08lx\n", indent, TimeToSeconds( ThrmInfo->Info.SamplingPeriod ), ThrmInfo->Info.ThermalConstant1, ThrmInfo->Info.ThermalConstant2 ); dprintf( "%s _TMP %8lx TempData %8lx CoolingLvl %2d\n", indent, ThrmInfo->TempMethod, Address + FIELD_OFFSET( THRM_INFO, Temp ), ThrmInfo->CoolingLevel ); for (i = 0; i < 10; i++) { noIndent = FALSE; if (i == 0) { dprintf( "%s Current %8sK ", indent, TempToKelvins( ThrmInfo->Info.CurrentTemperature ) ); } else if (i == 1) { dprintf( "%s Critical %8sK ", indent, TempToKelvins( ThrmInfo->Info.CriticalTripPoint ) ); } else if (i == 2) { dprintf( "%s Passive %8sK ", indent, TempToKelvins( ThrmInfo->Info.PassiveTripPoint ) ); } else { noIndent = TRUE; } if (i >= ThrmInfo->Info.ActiveTripPointCount) { if (ThrmInfo->Info.ActiveTripPoint[i] != 0 || ThrmInfo->ActiveList[i] != NULL) { if (noIndent == TRUE) { dprintf( "%s ", indent ); } dprintf( "*Active #%d %8sK Method %lx\n", i, TempToKelvins( ThrmInfo->Info.ActiveTripPoint[i] ), ThrmInfo->ActiveList[i] ); } else if (i < 3) { dprintf("\n"); } else { break; } } else { if (noIndent == TRUE) { dprintf( "%s ", indent ); } dprintf( "Active #%d %8sK Method %lx\n", i, TempToKelvins( ThrmInfo->Info.ActiveTripPoint[i] ), ThrmInfo->ActiveList[i] ); } } } VOID dumpAcpiDeviceNode( IN PACPI_DEVICE_POWER_NODE DeviceNode, IN ULONG_PTR Address, IN ULONG Verbose, IN ULONG IndentLevel ) /*++ Routine Description: This routine dumps the contents of a single device node Arguments: DeviceNode - What to dump Address - Where that node is located IndentLevel - How much whitespace to use Return Value: None --*/ { UCHAR indent[80]; IndentLevel = (IndentLevel > 79 ? 79 : IndentLevel); memset( indent, ' ', IndentLevel ); indent[IndentLevel] = '\0'; dprintf( "%sDevice Node - %08lx -> Extension - %08lx", indent, Address, DeviceNode->DeviceExtension ); if (DeviceNode->DeviceExtension != NULL) { dprintf(" - "); displayAcpiDeviceExtensionName( (ULONG_PTR) DeviceNode->DeviceExtension ); } dprintf("\n"); dprintf( "%s System %2s Device %2s Wake %s\n", indent, ShortSystemPowerStateTable[DeviceNode->SystemState], ShortDevicePowerStateTable[DeviceNode->AssociatedDeviceState], (DeviceNode->WakePowerResource ? "TRUE" : "FALSE") ); } VOID dumpAcpiDeviceNodes( IN ULONG_PTR Address, IN ULONG Verbose, IN ULONG IndentLevel ) /*++ Routine Description: This routine walks a Device Power List (given the address of the start of that list) Arguments: Address - Where in memory the first node is located Verbose - How much information to display IndentLevel - How many characters to indent Return Value: VOID --*/ { BOOL status; ACPI_DEVICE_POWER_NODE deviceNode; ACPI_POWER_DEVICE_NODE powerNode; ULONG returnLength; ULONG_PTR deviceAddress = Address; while (deviceAddress != 0) { // // Read the current node // status = ReadMemory( deviceAddress, &deviceNode, sizeof(ACPI_DEVICE_POWER_NODE), &returnLength ); if (status != TRUE || returnLength != sizeof(ACPI_DEVICE_POWER_NODE)) { dprintf( "dumpAcpiDeviceNodes: could not read device node memory " "%08lx\n", deviceAddress ); return; } // // Dump the node // dumpAcpiDeviceNode( &deviceNode, deviceAddress, Verbose, IndentLevel ); status = ReadMemory( (ULONG_PTR) deviceNode.PowerNode, &powerNode, sizeof(ACPI_POWER_DEVICE_NODE), &returnLength); if (status != TRUE || returnLength != sizeof(ACPI_POWER_DEVICE_NODE)) { dprintf( "dumpAcpiDeviceNode: could not read power node memory " "%08lx\n", deviceNode.PowerNode ); return; } // // Dump the power resource // dumpAcpiPowerNode( &powerNode, (ULONG_PTR) deviceNode.PowerNode, Verbose, IndentLevel ); // // setup next entry in the list // deviceAddress = (ULONG_PTR) deviceNode.Next; } } VOID dumpAcpiExtension( IN ULONG_PTR Address, IN ULONG Verbose, IN ULONG IndentLevel ) /*++ Routine Description: This dumps the ACPI device extension in a format that is readable by the user debugging the system Arguments: Address - Where the DeviceObject is located Verbose - How much information to display IndentLevel - How much whitespace to have Return Value: None --*/ { BOOL b; DEVICE_EXTENSION deviceExtension; PLIST_ENTRY listEntry; UCHAR indent[80]; ULONG_PTR curAddress; ULONG returnLength; ULONG_PTR stopAddress; ULONG subVerbose; IndentLevel = (IndentLevel > 79 ? 79 : IndentLevel); memset( indent, ' ', IndentLevel ); indent[IndentLevel] = '\0'; // // Read the sibling device extension // b = ReadMemory( Address, &deviceExtension, sizeof(DEVICE_EXTENSION), &returnLength ); if (!b) { dprintf( "%s***ReadMemory Failed from %p\n", Address ); return; } else if (returnLength != sizeof(DEVICE_EXTENSION) ) { dprintf( "%s***Error: Only read %08lx of %08lx bytes for %p\n", returnLength, sizeof(DEVICE_EXTENSION), Address ); return; } if ( (Verbose & VERBOSE_ALL) ) { displayAcpiDeviceExtension( &deviceExtension, Address, Verbose, IndentLevel ); } else { displayAcpiDeviceExtensionBrief( &deviceExtension, Address, Verbose, IndentLevel ); } if (! (Verbose & VERBOSE_LOOP) ) { return; } // // Determine the current and stop addresses // stopAddress = (ULONG_PTR) &(deviceExtension.ChildDeviceList) - (ULONG_PTR) &deviceExtension + Address; listEntry = deviceExtension.ChildDeviceList.Flink; // // Loop while there are children // while (listEntry != (PLIST_ENTRY) stopAddress) { // // Check for Ctrl-C // if (CheckControlC()) { break; } // // The currentAddress is at the ListEntry --- lets convert // curAddress = (ULONG_PTR) CONTAINING_RECORD( listEntry, DEVICE_EXTENSION, SiblingDeviceList ); // // Read the entry // b = ReadMemory( curAddress, &deviceExtension, sizeof(DEVICE_EXTENSION), &returnLength ); if (!b) { dprintf( "%s ***ReadMemory Failed from %p\n", curAddress ); return; } else if (returnLength != sizeof(DEVICE_EXTENSION) ) { dprintf( "%s ***Error: Only read %08lx of %08lx bytes " "for %p\n", returnLength, sizeof(DEVICE_EXTENSION), curAddress ); return; } // // Recurse // dumpAcpiExtension( curAddress, Verbose, IndentLevel + 4 ); // // Point to the next extension // listEntry = deviceExtension.SiblingDeviceList.Flink; } } VOID dumpPM1ControlRegister( IN ULONG Value, IN ULONG IndentLevel ) { // // Dump the PM1 Control Flags // dumpFlags( (Value & 0xFF), &PM1StatusFlags[0], sizeof(PM1ControlFlags) / sizeof(FLAG_RECORD), IndentLevel, (DUMP_FLAG_LONG_NAME | DUMP_FLAG_SHOW_BIT | DUMP_FLAG_TABLE) ); } VOID dumpPM1StatusRegister( IN ULONG Value, IN ULONG IndentLevel ) { // // Dump the PM1 Status Flags // dumpFlags( (Value & 0xFFFF), PM1StatusFlags, (sizeof(PM1StatusFlags) / sizeof(FLAG_RECORD)), IndentLevel, (DUMP_FLAG_LONG_NAME | DUMP_FLAG_SHOW_BIT | DUMP_FLAG_TABLE) ); // // Switch to the PM1 Enable Flags // Value >>= 16; // // Dump the PM1 Enable Flags // dumpFlags( (Value & 0xFFFF), PM1EnableFlags, (sizeof(PM1EnableFlags) / sizeof(FLAG_RECORD)), IndentLevel, (DUMP_FLAG_LONG_NAME | DUMP_FLAG_SHOW_BIT | DUMP_FLAG_TABLE) ); } VOID dumpAcpiPowerList( IN PUCHAR ListName ) /*++ This routine fetects a single Power Device List from the target and displays it Arguments: None Return Value: None --*/ { BOOL status; LIST_ENTRY listEntry; ULONG_PTR address; ULONG returnLength; // // Handle the queue list // address = GetExpression( ListName ); if (!address) { dprintf( "dumpAcpiPowerList: could not read %s\n", ListName ); } else { dprintf(" %s at %p\n", ListName, address ); status = ReadMemory( address, &listEntry, sizeof(LIST_ENTRY), &returnLength ); if (status == FALSE || returnLength != sizeof(LIST_ENTRY)) { dprintf( "dumpAcpiPowerList: could not read LIST_ENTRY at %08lx\n", address ); } else { dumpDeviceListEntry( &listEntry, address ); dprintf("\n"); } } } VOID dumpAcpiPowerLists( VOID ) /*++ Routine Description: This routine fetches the Power Device list from the target and displays it Arguments: None Return Value: None --*/ { BOOL status; LIST_ENTRY listEntry; ULONG_PTR address; ULONG returnLength; ULONG value; status = GetUlongPtr( "ACPI!AcpiPowerLock", &address ); if (status == FALSE) { dprintf("dumpAcpiPowerLists: Could not read ACPI!AcpiPowerLock\n"); return; } dprintf("ACPI Power Information\n"); if (address) { dprintf(" + ACPI!AcpiPowerLock is owned"); // // The bits other then the lowest is where the owning thread is // located. This function uses the property that -2 is every bit // except the least significant one // if ( (address & (ULONG_PTR) -2) != 0) { dprintf(" by thread at %p\n", (address & (ULONG_PTR) - 2) ); } else { dprintf("\n"); } } else { dprintf(" - ACPI!AcpiPowerLock is not owned\n"); } status = GetUlongPtr( "ACPI!AcpiPowerQueueLock", &address ); if (status == FALSE) { dprintf("dumpAcpiPowerLists: Could not read ACPI!AcpiPowerQueueLock\n"); return; } if (address) { dprintf(" + ACPI!AcpiPowerQueueLock is owned\n"); if ( (address & (ULONG_PTR) -2) != 0) { dprintf(" by thread at %p\n", (address & (ULONG_PTR) - 2) ); } else { dprintf("\n"); } } else { dprintf(" - ACPI!AcpiPowerQueueLock is not owned\n" ); } status = GetUlong( "ACPI!AcpiPowerWorkDone", &value ); if (status == FALSE) { dprintf("dumpAcpiPowerLists: Could not read ACPI!AcpiPowerWorkDone\n"); return; } dprintf(" + AcpiPowerWorkDone = %s\n", (value ? "TRUE" : "FALSE" ) ); status = GetUlong( "ACPI!AcpiPowerDpcRunning", &value ); if (status == FALSE) { dprintf("dumpAcpiPowerLists: Could not read ACPI!AcpiPowerDpcRunning\n"); return; } dprintf(" + AcpiPowerDpcRunning = %s\n", (value ? "TRUE" : "FALSE" ) ); dumpAcpiPowerList( "ACPI!AcpiPowerQueueList" ); dumpAcpiPowerList( "ACPI!AcpiPowerDelayedQueueList" ); dumpAcpiPowerList( "ACPI!AcpiPowerPhase0List" ); dumpAcpiPowerList( "ACPI!AcpiPowerPhase1List" ); dumpAcpiPowerList( "ACPI!AcpiPowerPhase2List" ); dumpAcpiPowerList( "ACPI!AcpiPowerPhase3List" ); dumpAcpiPowerList( "ACPI!AcpiPowerPhase4List" ); dumpAcpiPowerList( "ACPI!AcpiPowerPhase5List" ); dumpAcpiPowerList( "ACPI!AcpiPowerWaitWakeList" ); } VOID dumpAcpiPowerNode( IN PACPI_POWER_DEVICE_NODE PowerNode, IN ULONG_PTR Address, IN ULONG Verbose, IN ULONG IndentLevel ) /*++ Routine Description: This routine is called to display a power node Arguments: PowerNode - The power node to dump Address - Where the power node is located Verbose - How much information to display IndentLevel - How many characters to indent Return Value: None --*/ { BOOL status; NSOBJ ns; UCHAR buffer[5]; UCHAR indent[80]; ULONG returnLength; buffer[4] = '\0'; IndentLevel = (IndentLevel > 79 ? 79 : IndentLevel); memset( indent, ' ', IndentLevel ); indent[IndentLevel] = '\0'; // // Read the associated power resource object // status = ReadMemory( (ULONG_PTR) PowerNode->PowerObject, &ns, sizeof(NSOBJ), &returnLength ); if (status != FALSE && returnLength == sizeof(NSOBJ)) { memcpy( buffer, &(ns.dwNameSeg), 4 ); } else { buffer[0] = '\0'; } dprintf("%sPower Node - %08lx %s\n", indent, Address, buffer ); dprintf( "%s Resource %8lx Order %8lx WorkDone %8s\n", indent, PowerNode->PowerObject, PowerNode->ResourceOrder, WorkDone[ PowerNode->WorkDone ] ); dprintf( "%s On Method %8lx Off Method %8lx UseCounts %8lx\n", indent, PowerNode->PowerOnObject, PowerNode->PowerOffObject, PowerNode->UseCounts ); dprintf( "%s Level %8s Flags %8lx ", indent, ShortSystemPowerStateTable[PowerNode->SystemLevel], PowerNode->Flags ); dumpFlags( (PowerNode->Flags), &PowerNodeFlags[0], sizeof(PowerNodeFlags)/sizeof(FLAG_RECORD), 0, (DUMP_FLAG_SHORT_NAME | DUMP_FLAG_NO_INDENT | DUMP_FLAG_SINGLE_LINE) ); if (Verbose & VERBOSE_4) { dumpFlags( (PowerNode->Flags), &PowerNodeFlags[0], sizeof(PowerNodeFlags)/sizeof(FLAG_RECORD), IndentLevel + 4, (DUMP_FLAG_LONG_NAME) ); } } VOID dumpAcpiPowerNodes( VOID ) /*++ Routine Description: This routine fetches the Power Device list from the target and displays it Arguments: None Return Value: None --*/ { ACPI_DEVICE_POWER_NODE deviceNode; ACPI_POWER_DEVICE_NODE powerNode; BOOL status; LIST_ENTRY listEntry; PLIST_ENTRY list; ULONG_PTR addr; ULONG_PTR address; ULONG_PTR endAddress; ULONG returnLength; ULONG_PTR startAddress; status = GetUlongPtr( "ACPI!AcpiPowerLock", &address ); if (status == FALSE) { dprintf("dumpAcpiPowerNodes: Could not read ACPI!AcpiPowerLock\n"); return; } dprintf("ACPI Power Nodes\n"); if (address) { dprintf(" + ACPI!AcpiPowerLock is owned"); // // The bits other then the lowest is where the owning thread is // located. This function uses the property that -2 is every bit // except the least significant one // if ( (address & (ULONG_PTR) -2) != 0) { dprintf(" by thread at %p\n", (address & (ULONG_PTR) - 2) ); } else { dprintf("\n"); } } else { dprintf(" - ACPI!AcpiPowerLock is not owned\n"); } dprintf("Power Node List\n"); startAddress = GetExpression( "ACPI!AcpiPowerNodeList" ); if (!startAddress) { dprintf("dumpAcpiPowerNodes: could not read ACPI!AcpiPowerNodeList\n"); return; } status = ReadMemory( startAddress, &listEntry, sizeof(LIST_ENTRY), &returnLength ); if (status == FALSE || returnLength != sizeof(LIST_ENTRY)) { dprintf( "dumpAcpiPowerNodes: could not read LIST_ENTRY at %08lx\n", startAddress ); return; } // // Check to see if the list is empty // if ( (ULONG_PTR) listEntry.Flink == startAddress) { dprintf(" Empty\n"); return; } address = (ULONG_PTR) CONTAINING_RECORD( (listEntry.Flink), ACPI_POWER_DEVICE_NODE, ListEntry ); while (address != startAddress && address != 0) { // // Read the queued item // status = ReadMemory( address, &powerNode, sizeof(ACPI_POWER_DEVICE_NODE), &returnLength ); if (status == FALSE || returnLength != sizeof(ACPI_POWER_DEVICE_NODE)) { dprintf( "dumpIrpListEntry: Cannot read Node at %08lx\n", address ); return; } // // dump the node // dumpAcpiPowerNode( &powerNode, address, 0, 0 ); // // Lets walk the list of power nodes // list = powerNode.DevicePowerListHead.Flink; endAddress = ( (ULONG_PTR) &(powerNode.DevicePowerListHead) - (ULONG_PTR) &(powerNode) ) + address; // // Loop until back at the start // while (list != (PLIST_ENTRY) endAddress) { // // Crack the record // addr = (ULONG_PTR) CONTAINING_RECORD( list, ACPI_DEVICE_POWER_NODE, DevicePowerListEntry ); status = ReadMemory( addr, &deviceNode, sizeof(ACPI_DEVICE_POWER_NODE), &returnLength ); if (status == FALSE || returnLength != sizeof(ACPI_DEVICE_POWER_NODE)) { dprintf( "dumpIrpListEntry: Cannot read Node at %08lx\n", addr ); continue; } // // Dump the record // dumpAcpiDeviceNode( &deviceNode, addr, 0, 2 ); // // Next record // list = deviceNode.DevicePowerListEntry.Flink; } dprintf("\n"); // // Next record // address = (ULONG_PTR) CONTAINING_RECORD( powerNode.ListEntry.Flink, ACPI_POWER_DEVICE_NODE, ListEntry ); } } VOID dumpDeviceListEntry( IN PLIST_ENTRY ListEntry, IN ULONG_PTR Address ) /*++ Routine Description: This routine is called to dump a list of devices in one of the queues Arguments: ListEntry - The head of the list Address - The original address of the list (to see when we looped around Return Value: NONE --*/ { ULONG_PTR displacement; ACPI_POWER_REQUEST request; BOOL stat; PACPI_POWER_REQUEST nextRequest; PACPI_POWER_REQUEST requestAddress; ULONG i = 0; ULONG returnLength; // // Look at the next address // ListEntry = ListEntry->Flink; while (ListEntry != (PLIST_ENTRY) Address) { // // Crack the listEntry to determine where the powerRequest is // requestAddress = CONTAINING_RECORD( ListEntry, ACPI_POWER_REQUEST, ListEntry ); // // Read the queued item // stat = ReadMemory( (ULONG_PTR) requestAddress, &request, sizeof(ACPI_POWER_REQUEST), &returnLength ); if (stat == FALSE || returnLength != sizeof(ACPI_POWER_REQUEST)) { dprintf( "dumpDeviceListEntry: Cannot read PowerRequest at %08lx\n", requestAddress ); return; } if (request.CallBack != NULL) { GetSymbol( request.CallBack, Buffer, &displacement ); } else { Buffer[0] = '\0'; } // // Dump the entry for the device // dprintf( " %08lx\n" " DeviceExtension: %08lx", requestAddress, request.DeviceExtension ); if (request.DeviceExtension != NULL) { dprintf(" - "); displayAcpiDeviceExtensionName( (ULONG_PTR) request.DeviceExtension ); } dprintf("\n"); dprintf( " Status: %08lx %s->%s\n", request.Status, WorkDone[request.WorkDone], WorkDone[request.NextWorkDone] ); nextRequest = CONTAINING_RECORD( request.SerialListEntry.Flink, ACPI_POWER_REQUEST, SerialListEntry ); if (nextRequest != requestAddress) { dprintf( " SerialListEntry: F - %08lx B - %08lx -> %08lx\n", request.SerialListEntry.Flink, request.SerialListEntry.Blink, nextRequest ); } dprintf( " CallBack: %08lx (%s)\n" " Context: %08lx\n" " RequestType: %02lx\n" " ResultData: %08lx\n", request.CallBack, Buffer, request.Context, request.RequestType, requestAddress + (FIELD_OFFSET(ACPI_POWER_REQUEST, ResultData ) ) ); // // Dump some of the request specific information // if (request.RequestType == AcpiPowerRequestDevice) { dprintf( " RequestType: AcpiPowerRequestDevice\n" " DevicePowerState: %s\n" " Flags: %x ", DevicePowerStateTable[request.u.DevicePowerRequest.DevicePowerState], request.u.DevicePowerRequest.Flags ); dumpFlags( (request.u.DevicePowerRequest.Flags), &PowerRequestFlags[0], sizeof(PowerRequestFlags)/sizeof(FLAG_RECORD), 0, (DUMP_FLAG_LONG_NAME | DUMP_FLAG_NO_INDENT | DUMP_FLAG_SINGLE_LINE) ); } else if (request.RequestType == AcpiPowerRequestSystem) { dprintf( " RequestType: AcpiPowerRequestSystem\n" " SystemPowerState: %s\n" " SystemPowerAction: %s\n", SystemPowerStateTable[request.u.SystemPowerRequest.SystemPowerState], SystemPowerActionTable[request.u.SystemPowerRequest.SystemPowerAction] ); } else if (request.RequestType == AcpiPowerRequestWaitWake) { dprintf( " RequestType: AcpiPowerRequestWaitWake\n" " SystemPowerState: %s\n" " Flags: %x ", SystemPowerStateTable[request.u.WaitWakeRequest.SystemPowerState], request.u.WaitWakeRequest.Flags ); dumpFlags( (request.u.WaitWakeRequest.Flags), &PowerRequestFlags[0], sizeof(PowerRequestFlags)/sizeof(FLAG_RECORD), 0, (DUMP_FLAG_LONG_NAME | DUMP_FLAG_NO_INDENT | DUMP_FLAG_SINGLE_LINE) ); } // // Point to the next entry // ListEntry = request.ListEntry.Flink; } // while } VOID dumpIrpListEntry( IN PLIST_ENTRY ListEntry, IN ULONG_PTR Address ) /*++ Routine Description: This routine is called to dump a list of devices in one of the queues Arguments: ListEntry - The head of the list Address - The original address of the list (to see when we looped around Return Value: NONE --*/ { BOOL stat; DEVICE_OBJECT deviceObject; DEVICE_EXTENSION deviceExtension; IO_STACK_LOCATION irpStack; PIRP irpAddress; PIO_STACK_LOCATION tempStack; IRP irp; ULONG returnLength; // // Look at the first element in the list // ListEntry = ListEntry->Flink; // // Loop for all items in the list // while (ListEntry != (PLIST_ENTRY) Address) { irpAddress = CONTAINING_RECORD( ListEntry, IRP, Tail.Overlay.ListEntry ); // // Read the queued item // stat = ReadMemory( (ULONG_PTR) irpAddress, &irp, sizeof(IRP), &returnLength ); if (stat == FALSE || returnLength != sizeof(IRP)) { dprintf( "dumpIrpListEntry: Cannot read Irp at %08lx\n", irpAddress ); return; } // // Get the current stack location // tempStack = IoGetCurrentIrpStackLocation( &irp ); if (tempStack == NULL) { dprintf( "dumpIrpListEntry: Cannot read IrpStack for Irp at %08lx\n", irpAddress ); return; } stat = ReadMemory( (ULONG_PTR) tempStack, &irpStack, sizeof(IO_STACK_LOCATION), &returnLength ); if (stat == FALSE || returnLength != sizeof(IO_STACK_LOCATION)) { dprintf( "dumpIrpListEntry: Cannot read IoStackLocation at %08lx\n", tempStack ); return; } stat = ReadMemory( (ULONG_PTR) irpStack.DeviceObject, &deviceObject, sizeof(DEVICE_OBJECT), &returnLength ); if (stat == FALSE || returnLength != sizeof(DEVICE_OBJECT)) { dprintf( "dumpIrpListEntry: Cannot read DeviceObject at %08lx\n", irpStack.DeviceObject ); return; } stat = ReadMemory( (ULONG_PTR) deviceObject.DeviceExtension, &deviceExtension, sizeof(DEVICE_EXTENSION), &returnLength ); if (stat == FALSE || returnLength != sizeof(DEVICE_EXTENSION)) { dprintf( "dumpIrpListEntry: Cannot read DeviceExtension at %08lx\n", deviceObject.DeviceExtension ); return; } memset( Buffer, '0', 2048 ); stat = ReadMemory( (ULONG_PTR) deviceExtension.DeviceID, Buffer, 256, &returnLength ); if (stat && Buffer[0] != '\0' && returnLength != 0) { dprintf( " Irp: %08x Device: %08lx (%s)\n", irpAddress, irpStack.DeviceObject, Buffer ); } else { dprintf( " Irp: %08x Device: %08lx\n", irpAddress, irpStack.DeviceObject ); } // // Next item on the queue // ListEntry = irp.Tail.Overlay.ListEntry.Flink; } } VOID dumpNSObject( IN ULONG_PTR Address, IN ULONG Verbose, IN ULONG IndentLevel ) /*++ Routine Description: This function dumps a Name space object Arguments: Address - Where to find the object Verbose - Should the object be dumped as well? IndentLevel - How much to indent Return Value: None --*/ { BOOL b; NSOBJ ns; UCHAR buffer[5]; UCHAR indent[80]; // // Init the buffers // IndentLevel = (IndentLevel > 79 ? 79 : IndentLevel); memset( indent, ' ', IndentLevel ); indent[IndentLevel] = '\0'; buffer[4] = '\0'; // // First step is to read the root NS // b = ReadMemory( Address, &ns, sizeof(NSOBJ), NULL ); if (!b) { dprintf("%sdumpNSObject: could not read %x\n", indent,Address ); return; } if (ns.dwNameSeg != 0) { memcpy( buffer, &(ns.dwNameSeg), 4 ); } else { sprintf( buffer, " "); } dprintf( "%sNameSpace Object %s (%08lx) - Device %08lx\n", indent, buffer, Address, ns.Context ); if (Verbose & VERBOSE_NSOBJ) { dprintf( "%s Flink %08lx Blink %08lx Parent %08lx Child %08lx\n", indent, ns.list.plistNext, ns.list.plistPrev, ns.pnsParent, ns.pnsFirstChild ); } dprintf( "%s Value %08lx Length %08lx Buffer %08lx Flags %08lx", indent, ns.ObjData.uipDataValue, ns.ObjData.dwDataLen, ns.ObjData.pbDataBuff, ns.ObjData.dwfData ); if (ns.ObjData.dwfData & DATAF_BUFF_ALIAS) { dprintf(" Alias" ); } if (ns.ObjData.dwfData & DATAF_GLOBAL_LOCK) { dprintf(" Lock"); } dprintf("\n"); dumpObject( Address, &(ns.ObjData), Verbose, IndentLevel + 4); } VOID dumpNSTree( IN ULONG_PTR Address, IN ULONG Level ) /*++ Routine Description: This thing dumps the NS tree Arguments: Address - Where to find the root node --- we start dumping at the children Return Value: None --*/ { BOOL end = FALSE; BOOL b; NSOBJ ns; UCHAR buffer[5]; ULONG_PTR next; ULONG back; ULONG_PTR m1 = 0; ULONG_PTR m2 = 0; ULONG reason; ULONG dataBuffSize; buffer[4] = '\0'; // // Indent // for (m1 = 0; m1 < Level; m1 ++) { dprintf("| "); } // // First step is to read the root NS // b = ReadMemory( Address, &ns, sizeof(NSOBJ), NULL ); if (!b) { dprintf("dumpNSTree: could not read %x\n", Address ); return; } if (ns.dwNameSeg != 0) { memcpy( buffer, &(ns.dwNameSeg), 4 ); dprintf("%4s ", buffer ); } else { dprintf(" " ); } dprintf( "(%08x) - ", Address ); if (ns.Context != 0) { dprintf("Device %08lx\n", ns.Context ); } else { // // We need to read the pbDataBuff here // if (ns.ObjData.pbDataBuff != 0) { dataBuffSize = (ns.ObjData.dwDataLen > 2047 ? 2047 : ns.ObjData.dwDataLen ); b = ReadMemory( (ULONG_PTR) ns.ObjData.pbDataBuff, Buffer, dataBuffSize, NULL ); if (!b) { dprintf( "dumpNSTree: could not read %x\n", ns.ObjData.pbDataBuff ); return; } } switch(ns.ObjData.dwDataType) { default: case OBJTYPE_UNKNOWN: dprintf("Unknown\n"); break; case OBJTYPE_INTDATA: dprintf("Integer - %lx\n", ns.ObjData.uipDataValue); break; case OBJTYPE_STRDATA: Buffer[dataBuffSize+1] = '\0'; dprintf( "String - %s\n", Buffer ); break; case OBJTYPE_BUFFDATA: dprintf( "Buffer - %08lx L=%04x\n", ns.ObjData.pbDataBuff, ns.ObjData.dwDataLen ); break; case OBJTYPE_PKGDATA: { PPACKAGEOBJ package = (PPACKAGEOBJ) Buffer; dprintf("Package - NumElements %x\n",package->dwcElements); break; } case OBJTYPE_FIELDUNIT:{ PFIELDUNITOBJ fieldUnit = (PFIELDUNITOBJ) Buffer; dprintf( "FieldUnit - Parent %x Offset %x Start %x " "Num %x Flags %x\n", fieldUnit->pnsFieldParent, fieldUnit->FieldDesc.dwByteOffset, fieldUnit->FieldDesc.dwStartBitPos, fieldUnit->FieldDesc.dwNumBits, fieldUnit->FieldDesc.dwFieldFlags ); break; } case OBJTYPE_DEVICE: dprintf("Device\n"); break; case OBJTYPE_EVENT: dprintf("Event - PKEvent %x\n", ns.ObjData.pbDataBuff); break; case OBJTYPE_METHOD: { PMETHODOBJ method = (PMETHODOBJ) Buffer; dprintf( "Method - Flags %x Start %08lx Len %x\n", method->bMethodFlags, (ULONG_PTR) method->abCodeBuff - (ULONG_PTR) method + (ULONG_PTR) ns.ObjData.pbDataBuff, (ULONG) ns.ObjData.dwDataLen - sizeof(METHODOBJ) + ANYSIZE_ARRAY ); break; } case OBJTYPE_OPREGION: { POPREGIONOBJ opRegion = (POPREGIONOBJ) Buffer; dprintf( "Opregion - RegionsSpace=%08x OffSet=%x Len=%x\n", opRegion->bRegionSpace, opRegion->uipOffset, opRegion->dwLen ); break; } case OBJTYPE_BUFFFIELD: { PBUFFFIELDOBJ field = (PBUFFFIELDOBJ) Buffer; dprintf( "Buffer Field Ptr=%x Len=%x Offset=%x Start=%x" "NumBits=%x Flgas=%x\n", field->pbDataBuff, field->dwBuffLen, field->FieldDesc.dwByteOffset, field->FieldDesc.dwStartBitPos, field->FieldDesc.dwNumBits, field->FieldDesc.dwFieldFlags ); break; } case OBJTYPE_FIELD: { dprintf("Field\n"); break; } case OBJTYPE_INDEXFIELD: dprintf("Index Field\n"); break; case OBJTYPE_MUTEX: dprintf("Mutex\n"); break; case OBJTYPE_POWERRES: dprintf("Power Resource\n"); break; case OBJTYPE_PROCESSOR: dprintf("Processor\n"); break; case OBJTYPE_THERMALZONE: dprintf("Thermal Zone\n"); break; case OBJTYPE_DDBHANDLE: dprintf("DDB Handle\n"); break; case OBJTYPE_DEBUG: dprintf("Debug\n"); break; case OBJTYPE_OBJALIAS: dprintf("Object Alias\n"); break; case OBJTYPE_DATAALIAS: dprintf("Data Alias\n"); break; case OBJTYPE_BANKFIELD: dprintf("Bank Field\n"); break; } } m1 = next = (ULONG_PTR) ns.pnsFirstChild; while (next != 0 && end == FALSE) { if (CheckControlC()) { break; } b = ReadMemory( next, &ns, sizeof(NSOBJ), NULL ); if (!b) { dprintf("dumpNSTree: could not read %x\n", next ); return; } dumpNSTree( next, Level + 1); // // Do the end check tests // if ( m2 == 0) { m2 = (ULONG_PTR) ns.list.plistPrev; } else if (m1 == (ULONG_PTR) ns.list.plistNext) { end = TRUE; reason = 1; } else if (m2 == next) { end = TRUE; reason = 2; } next = (ULONG_PTR) ns.list.plistNext; } } VOID dumpObject( IN ULONG_PTR Address, IN POBJDATA Object, IN ULONG Verbose, IN ULONG IndentLevel ) /*++ Routine Description: This dumps an Objdata so that it can be understand --- great for debugging some of the AML code Arguments: Address - Where the Object is located Object - Pointer to the object Return Value: None --*/ { BOOL b; NTSTATUS status; UCHAR buffer[2048]; UCHAR indent[80]; ULONG max; ULONG returnLength; // // Init the buffers // IndentLevel = (IndentLevel > 79 ? 79 : IndentLevel); memset( indent, ' ', IndentLevel ); indent[IndentLevel] = '\0'; dprintf("%sObject Data - %08lx Type - ", indent, Address ); // // First step is to read whatever the buffer points to, if it // points to something // if (Object->pbDataBuff != 0) { max = (Object->dwDataLen > 2047 ? 2047 : Object->dwDataLen ); b = ReadMemory( (ULONG_PTR) Object->pbDataBuff, buffer, max, &returnLength ); if (!b || returnLength != max) { dprintf( "%sdumpObject: Could not read buffer %08lx (%d) %x<->%x\n", indent, Object->pbDataBuff, b, max, returnLength ); return; } } switch( Object->dwDataType ) { case OBJTYPE_INTDATA: dprintf( "%02x Value=%08lx\n", Object->dwDataType, Object->uipDataValue ); break; case OBJTYPE_STRDATA: buffer[max] = '\0'; dprintf( "%02x String=%s\n", Object->dwDataType, buffer ); break; case OBJTYPE_BUFFDATA: dprintf( "%02x Ptr=%08lx Length = %2x\n", Object->dwDataType, Object->pbDataBuff, Object->dwDataLen ); break; case OBJTYPE_PKGDATA: { PPACKAGEOBJ package = (PPACKAGEOBJ) buffer; ULONG i = 0; ULONG j = package->dwcElements; dprintf( "%02x NumElements=%02x\n", Object->dwDataType, j ); if (Verbose & VERBOSE_OBJECT) { for (; i < j; i++) { dumpObject( (ULONG_PTR) &(package->adata[i]) - (ULONG_PTR) package + (ULONG_PTR) Object->pbDataBuff, &(package->adata[i]), Verbose, IndentLevel+ 2 ); } } break; } case OBJTYPE_FIELDUNIT: { PFIELDUNITOBJ fieldUnit = (PFIELDUNITOBJ) buffer; dprintf( "%02x Parent=%08lx Offset=%08lx Start=%08x " "Num=%x Flags=%x\n", Object->dwDataType, fieldUnit->pnsFieldParent, fieldUnit->FieldDesc.dwByteOffset, fieldUnit->FieldDesc.dwStartBitPos, fieldUnit->FieldDesc.dwNumBits, fieldUnit->FieldDesc.dwFieldFlags ); break; } case OBJTYPE_DEVICE: dprintf( "%02x \n", Object->dwDataType ); break; case OBJTYPE_EVENT: dprintf( "%02x PKEvent=%08lx\n", Object->dwDataType, Object->pbDataBuff ); break; case OBJTYPE_METHOD: { PMETHODOBJ method = (PMETHODOBJ) buffer; max = Object->dwDataLen - sizeof(METHODOBJ) + ANYSIZE_ARRAY; dprintf( "%02x Flags=%x Start=%x Len=%x\n", Object->dwDataType, method->bMethodFlags, (ULONG_PTR) method->abCodeBuff - (ULONG_PTR) method + (ULONG_PTR) Object->pbDataBuff, max ); break; } case OBJTYPE_MUTEX: dprintf( "%02x Mutex=%08lx\n", Object->dwDataType, Object->pbDataBuff ); break; case OBJTYPE_OPREGION: { POPREGIONOBJ opRegion = (POPREGIONOBJ) buffer; dprintf( "%02x RegionSpace=%08x OffSet=%x " "Len=%x\n", Object->dwDataType, opRegion->bRegionSpace, opRegion->uipOffset, opRegion->dwLen ); break; } case OBJTYPE_POWERRES: { PPOWERRESOBJ powerRes = (PPOWERRESOBJ) buffer; dprintf( "%02x SystemLevel=S%d Order=%x\n", Object->dwDataType, powerRes->bSystemLevel, powerRes->bResOrder ); break; } case OBJTYPE_PROCESSOR: { PPROCESSOROBJ proc = (PPROCESSOROBJ) buffer; dprintf( "%02x AcpiID=%x PBlk=%x PBlkLen=%x\n", Object->dwDataType, proc->bApicID, proc->dwPBlk, proc->dwPBlkLen ); break; } case OBJTYPE_THERMALZONE: dprintf( "%02x \n", Object->dwDataType ); break; case OBJTYPE_BUFFFIELD: { PBUFFFIELDOBJ field = (PBUFFFIELDOBJ) buffer; dprintf( "%02x Ptr=%x Len=%x Offset=%x Start=%x " "NumBits=%x Flags=%x\n", Object->dwDataType, field->pbDataBuff, field->dwBuffLen, field->FieldDesc.dwByteOffset, field->FieldDesc.dwStartBitPos, field->FieldDesc.dwNumBits, field->FieldDesc.dwFieldFlags ); break; } case OBJTYPE_DDBHANDLE: dprintf( "%02x Handle=%x\n", Object->dwDataType, Object->pbDataBuff ); break; case OBJTYPE_DEBUG: dprintf( "%02x \n", Object->dwDataType ); break; case OBJTYPE_OBJALIAS: dprintf( "%02x NS Object=%x\n", Object->dwDataType, Object->uipDataValue ); dumpNSObject( Object->uipDataValue, Verbose, IndentLevel + 2 ); break; case OBJTYPE_DATAALIAS: { OBJDATA objData; dprintf( "%02x Data Object=%x\n", Object->dwDataType, Object->uipDataValue ); b = ReadMemory( (ULONG) Object->uipDataValue, &objData, sizeof(OBJDATA), NULL ); if (!b) { dprintf( "dumpObject: could not read %x\n", Object->uipDataValue ); return; } dumpObject( (ULONG) Object->uipDataValue, &objData, Verbose, IndentLevel + 2 ); break; } case OBJTYPE_BANKFIELD: dprintf( "%02x \n", Object->dwDataType ); break; case OBJTYPE_FIELD: dprintf( "%02x \n", Object->dwDataType ); break; case OBJTYPE_INDEXFIELD: dprintf( "%02x \n", Object->dwDataType ); break; case OBJTYPE_UNKNOWN: default: dprintf( "%02x \n", Object->dwDataType ); break; } } VOID dumpPObject( IN ULONG_PTR Address, IN ULONG Verbose, IN ULONG IndentLevel ) /*++ Routine Description: This is a wrapper for dumpObject --*/ { BOOL result; OBJDATA objdata; ULONG returnLength; result = ReadMemory( Address, &objdata, sizeof(OBJDATA), &returnLength ); if (result != TRUE || returnLength != sizeof(OBJDATA) ) { UCHAR indent[80]; IndentLevel = (IndentLevel > 79 ? 79 : IndentLevel); memset( indent, ' ', IndentLevel ); indent[IndentLevel] = '\0'; dprintf( "%sdumpPObject: Could not OBJDATA %08lx\n", indent, Address ); return; } dumpObject( Address, &objdata, Verbose, IndentLevel ); return; } PUCHAR TempToKelvins( IN ULONG Temp ) { static UCHAR buffer[80]; sprintf( buffer, "%d.%d", (Temp / 10 ), (Temp % 10) ); return buffer; } PUCHAR TimeToSeconds( IN ULONG Time ) { static UCHAR buffer[80]; sprintf( buffer, "%d.%d", (Time / 10 ), (Time % 10) ); return buffer; }