• Ntdebugging Blog

    Bcdedit Tips and Tricks For Debugging Part 1

    • 6 Comments

    Hello everyone, my name is Sean Walker, and I am on the Platforms OEM team in Washington.  This article is for those people who have had a hard time switching from the old boot.ini configuration to the new BCD store (myself included). Doing the simple tasks such as enabling kernel debugging over com1 are easy to do with bcdedit.exe or the msconfig GUI, you just enable them and reboot the computer. However, if you need to do something more advanced such as break into the early boot process during resume from hibernation, things get a lot more complicated.

     

    This article has some samples for enabling and disabling debug settings that you may not be familiar with, and a list of bcdedit debug settings for Windows Vista/Server 2008 and Windows 7/Server 2008 R2.  This information has been helpful to me for quickly and accurately getting to the debug at hand rather than fumbling around with bcdedit.  Much of the following information has been taken from various sources, including the windbg help files, the OEM team blog, the MSDN bcdedit reference, and the WHDC debugger site.

     

    NOTE: For the examples below, you will need to run bcdedit.exe from an administrator (UAC-elevated) command prompt.  To output a summary view of the current state of the BCD store, just run "bcdedit.exe" from the command prompt.  To get detailed information about all of the store(s) that Windows knows about, use the following command:

    bcdedit /enum all

     

    What is a BCD store?

    A BCD store is a binary file that contains boot configuration data for Windows, basically it is a small registry file.  Boot applications use the system BCD store, located on the system partition, during the boot process.  You can also create additional BCD stores in separate files but only one store at a time can be designated as the system store.

     

    NOTE: The "/store" switch can be used to specify a particular BCD store for bcdedit commands (instead of the default store).  To enumerate all the settings in another BCD store, in this case e:\bcd_store\BCD, use the following command:

    bcdedit /store e:\bcd_store\BCD /enum all

     

    This will show you which options are currently set, and what their values are.  When /store switch is omitted, the system store is used.

     

    Using bootdebug

    To enable debugging for early boot problems, you may need to enable the bootdebug switch.  This is easy to do with bcdedit:

    bcdedit /set bootdebug on

     

    However, this only sets bootdebug for the current "boot application", which is generally winload.exe, so it does not break into the very early boot process.  There are multiple applications used for booting, hibernating, and resuming (bootmgr.exe, winload.exe and winresume.exe are examples of these).  Each application (called BCD Objects) has its own settings (called BCD Elements) in the BCD store and each can be modified globally and/or individually.

     

    So, to deal with different (or multiple) debug scenarios, you just enable boot debugging based on the boot application you are concerned with.  For early debugging, you can enable bootdebug for bootmgr:

    bcdedit /set {bootmgr} bootdebug on

     

    To set bootdebug for winload.exe (which will most often be your current, and default, boot object) all three of the following will give you the same result:

    bcdedit /set bootdebug on

    bcdedit /set {current} bootdebug on

    bcdedit /set {default} bootdebug on

     

    If you are modifying the settings in another store, or are booted into another OS on the same computer (such as WinPE), you need to specify the location of the BCD store:

    bcdedit /store d:\Boot\BCD /set {default} bootdebug on

     

    Not all of the boot objects have "friendly" names, so you may need to specify the full GUID (Globally Unique ID) to modify it.  As an example, if you wanted to enable bootdebug on resume from hibernation, you would include the identifier (see figure 1) for the "Resume from Hibernate" object:

    bcdedit /set {89a932d0-d5bc-11e0-a0af-00215add5ebc} bootdebug on

     

    image001

    Figure 1: Color coded bcdedit output

     

    Why won't my USB or 1394 debug work?

    When there are multiple debug ports of a certain type in a computer Windows may not default to the correct one for your situation.  This happens most commonly when there are either multiple 1394 host controllers or USB EHCI controllers.  When this occurs it can range from a slight inconvenience (different port is used so the cable needs to be plugged into another port), to complete failure (internal port is used, which is not accessible).  In the case of USB debugging the Intel USB 2.0 specification only provides one debug port, so debugging is not possible if the wrong host controller is used.

     

    There are several caveats with USB debugging, not the least of which is that you need to buy a separate, expensive, debug cable.  Some of the difficulties and implementation details necessary to get USB debugging to work are encompassed in the WHDC USB FAQ and in Setting Up Kernel Debugging with USB 2.0.

     

    NOTE: A correction to the WHDC USB documentation for Windows 7/Windows 2008 R2 is that the busparams switch now takes decimal rather than hexadecimal values, and the "loadoptions" parameter is no longer required.  So, to enable the busparams element (for USB or 1394 debugging) in Vista/2008, you would use something like this:

    bcdedit /set {current} loadoptions busparams=0.1D.7

     

    And the Win7/2008 R2 example would be:

    bcdedit /set {current} busparams 0.29.7

     

    In the case of loadoptions or busparams, deleting the setting is not as easy as changing a flag from yes to no. You must specifically delete the value to get rid of it, and one of the examples below can be used:

     

    For Vista/2008:

    bcdedit /deletevalue {current} loadoptions

     

    And Windows 7/2008 R2:

    bcdedit /deletevalue {current} busparams

     

    Bcdedit settings and examples

    This is just scratching the surface of using bcdedit for your troubleshooting and/or debugging needs, so there are more articles to follow. Part 2 will include some more detailed debugging scenarios, such as Hyper-V guest and host debugging.  Below is a consolidated table with many of the debugging switches/settings as well as a number of different usage examples.

     

    Table of debug-related bcdedit settings

    Option

    Description

    bootdebug

    Enables or disables the boot debugger for a specified boot entry. Although this command works for any boot entry, it is effective only for boot applications.

    Enable value(s): on, 1

    Disable value(s): off, 0

    Bcdedit /set bootdebug on

    debug

    Enables or disables the kernel debugger for a specified boot entry.

    Enable value(s): on, 1

    Disable value(s): off, 0

    /dbgsettings

    Used to modify the global settings for the debug connection (does not include hypervisor).  Values:

    Can change all settings at once instead of using the /set command to change them individually. Usage example:

    bcdedit /dbgsettings 1394 channel:30

    debugport

    Used to specify the debugger type.

    Values:

    Serial port – com1, com2, comx

    1394 port – 1394

    USB port - USB

    channel

    Specifies 1394 channel used.

    Values:

    Decimal integer between 0 and 62, inclusive.

    baudrate

    Used to specify the baud rate of a serial debug port.

    Values: 9600, 19200, 38400, 57600, 115200

    targetname

    Specifies a string to use as the identification for the USB 2.0 connection. This string can be any value.

    Usage example:

    bcdedit /dbgsettings usb targetname:usbdebug

    /hypervisorsettings

    Used the same way as /dbgsettings to configure all settings at once.

    Usage example:

    bcdedit /hypervisorsettings 1394 channel:10

    hypervisordebug

    Enables or disables hypervisor debug mode. This is for debugging a Hyper-V host system.

    Enable value(s): on, 1

    Disable value(s): off, 0

    Usage example:

    bcdedit /set {current} hypervisordebug on

    /noumex

    Specifies that the kernel debugger ignores user-mode exceptions. By default, the kernel debugger breaks for certain user-mode exceptions, such as STATUS_BREAKPOINT and STATUS_SINGLE_STEP. The /noumex parameter is effective only when there is no user-mode debugger attached to the process.

    /start

    This option specifies the debugger start policy. If a start policy is not specified, ACTIVE is the default.

    Values: active, disable, autoenable

    loadoptions

    Used to describe settings that are not covered by other types. One setting that is relevant here is busparams.

    Values: Any value followed by the setting.

    Usage example (Vista/2008):

    bcdedit /set {current} loadoptions busparams=0.1d.0

    busparams

    A boot setting (specified with loadoptions key word) used to point to the PCI address of the debugger in use. The PCI bus, device, and function are used, in the format bb.dd.ff. This is generally used to identify the location of a 1394 or USB debug port. In Vista/2008, hexadecimal values are used, whereas decimal values are used for Win7.

    Values: Decimal values between 0 and 255.

    Usage example:

    In Win7 - bcdedit /set busparams 0.29.0

    In Vista - bcdedit /set loadoptions busparams=0.1d.0

    kernel

    The loadoptions parameter used to point to a different kernel binary. This can be used to test with a checked or instrumented version of the kernel without replacing the existing one. The updated binary MUST be placed in the %windir%\system32 folder to be used

    Values: The 8.3 filename of the replacement kernel include the exe extension.

    Usage examples:

    In Win7 – bcdedit /set kernel kernchk.exe

    In Vista - bcdedit /set loadoptions kernel=kernchk.exe

    hal

    The loadoptions parameter used to point to a different hal binary. This can be used to test with a checked or instrumented version of the kernel without replacing the existing one. The updated binary MUST be placed in the %windir%\system32 folder to be used

    Values: the 8.3 filename of the replacement kernel include the .dll extension.

    Usage examples:

    In Win7 – bcdedit /set hal halchk.dll

    In Vista - bcdedit /set loadoptions hal=halchk.dll

    testsigning

    Controls whether Windows 7, Windows Server 2008, or Windows Vista will load any type of test-signed kernel-mode code. This option is not set by default, which means test-signed kernel-mode drivers on 64-bit versions of Windows 7, Windows Server 2008, and Windows Vista will not load without setting the testsigning switch

    Enable value(s): on, 1

    Disable value(s): off, 0

    Usage example:

    Bcdedit /set testsigning on

     

  • Ntdebugging Blog

    Determining The Interrupt Line For A Particular PCI-E Slot

    • 5 Comments

    Hi debuggers, this is Graham McIntyre again. These days I’m working more closely with hardware so I thought I’d share some hardware related debugging tips.  I recently debugged an issue where a PCI-E storage device failed to work after hot swapping it from one slot to another slot on the system without rebooting.  We determined the issue was due to the device not receiving interrupts once it was moved.   So in the process I learned how line based interrupts are routed to a particular PCI slot.    Interrupt routing is quite a hefty subject, but here’s one example of how to determine what the expected interrupt line is for a particular PCI-E slot using a live kernel debug.

     

    There are two ways the routing can be defined in the ACPI tables:

    1. Static routing (most common for APIC systems)
    2. Link Node routing (most common for PIC systems)

     

    Since APIC is much more common, I am focusing on method 1 for static routing. Though, it is legal to use Link Node routing with IOAPICs, it’s not common, so I am omitting how to parse that.  This is also specifically for devices that use physical line based interrupts (LBI), not Message Signaled Interrupts (MSI).

     

    Here is the general method for determining the static routing IRQ for a particular device:

    1. Locate the devstack for the device, and determine its parent devices in the PCI hierarchy. (!pcitree)
    2. Determine the interrupt pin which the device uses
    3. Walk the parent devices to find the closest PCI Routing Table (_PRT) which will describe the mapping of interrupt pin to IRQ.
      1. If the parent device does not have a _PRT, then swizzle the pin, since the pin number can change when moving to the upstream side of the PCI bridge (you may end up swizzling the pin several times).  We will discuss how to swizzle the pin number later in this article.
      2. If the parent device has a _PRT, then move to the next step
    4. Convert the IntPin number from PCI to ACPI numbering
    5. Parse the _PRT method to find the static routing table
    6. Find the routing entry which represents our IntPin

     

    Here’s the in-depth steps, along with an example:

     

    Step 1:  Locate the devstack for the device, and determine its parent devices in the PCI hierarchy.

     

    To determine this, use !pcitree to dump the PCI hierarchy. Then locate your device by ven/dev ID.  You could also use !devnode to dump the hierarchy.

     

    The way !pcitree shows the hierarchy may be a little confusing.  When it encounters a PCI bridge, it dumps the child buses under the bridge. The indenting tells you what bus a device is on. A device is always indented one level from the entry of the parent bus.  In my case, I know the device I'm interested in is VEN FEFE DEV 1550.

    kd> !pcitree

    Bus 0x0 (FDO Ext fffffa80053efe00)

      (d=0,  f=0) 80863406 devext 0xfffffa80054d51b0 devstack 0xfffffa80054d5060 0600 Bridge/HOST to PCI

      (d=1,  f=0) 80863408 devext 0xfffffa80054d9b70 devstack 0xfffffa80054d9a20 0604 Bridge/PCI to PCI

      Bus 0x1 (FDO Ext fffffa80054e8680)

        (d=0,  f=0) 14e41639 devext 0xfffffa80051b91b0 devstack 0xfffffa80051b9060 0200 Network Controller/Ethernet

        (d=0,  f=1) 14e41639 devext 0xfffffa80051ba1b0 devstack 0xfffffa80051ba060 0200 Network Controller/Ethernet

      (d=3,  f=0) 8086340a devext 0xfffffa80054dab70 devstack 0xfffffa80054daa20 0604 Bridge/PCI to PCI

      Bus 0x2 (FDO Ext fffffa80054e9460)

        (d=0,  f=0) 14e41639 devext 0xfffffa80051bcb70 devstack 0xfffffa80051bca20 0200 Network Controller/Ethernet

        (d=0,  f=1) 14e41639 devext 0xfffffa80051cab70 devstack 0xfffffa80051caa20 0200 Network Controller/Ethernet

      (d=4,  f=0) 8086340b devext 0xfffffa80054dbb70 devstack 0xfffffa80054dba20 0604 Bridge/PCI to PCI

      Bus 0x3 (FDO Ext fffffa80054ec190)

        (d=0,  f=0) 10000079 devext 0xfffffa80051cd1b0 devstack 0xfffffa80051cd060 0104 Mass Storage Controller/RAID

      (d=5,  f=0) 8086340c devext 0xfffffa80054dcb70 devstack 0xfffffa80054dca20 0604 Bridge/PCI to PCI

      Bus 0x4 (FDO Ext fffffa80054ede00)

        No devices have been enumerated on this bus.

      (d=6,  f=0) 8086340d devext 0xfffffa80054ddb70 devstack 0xfffffa80054dda20 0604 Bridge/PCI to PCI

      Bus 0x5 (FDO Ext fffffa80054ee9c0)

        No devices have been enumerated on this bus.

      (d=7,  f=0) 8086340e devext 0xfffffa80054deb70 devstack 0xfffffa80054dea20 0604 Bridge/PCI to PCI << Root Port

      Bus 0x6 (FDO Ext fffffa80054f1190)

        (d=0,  f=0) abcd8632 devext 0xfffffa80051d91b0 devstack 0xfffffa80051d9060 0604 Bridge/PCI to PCI << Upstream switch port

        Bus 0x7 (FDO Ext fffffa80051cd850)

          (d=4,  f=0) abcd8632 devext 0xfffffa80051d71b0 devstack 0xfffffa80051d7060 0604 Bridge/PCI to PCI

          Bus 0x8 (FDO Ext fffffa8006f44ac0)

            No devices have been enumerated on this bus.

          (d=5,  f=0) abcd8632 devext 0xfffffa80058d6a10 devstack 0xfffffa80058d68c0 0604 Bridge/PCI to PCI

          Bus 0x9 (FDO Ext fffffa80051ba850)

            No devices have been enumerated on this bus.

          (d=6,  f=0) abcd8632 devext 0xfffffa8007075b70 devstack 0xfffffa8007075a20 0604 Bridge/PCI to PCI << Parent PDO (Downstream Switch Port)

          Bus 0xa (FDO Ext fffffa8007312b60)

            (d=0,  f=0) fefe1550 devext 0xfffffa8006f67b70 devstack 0xfffffa8006f67a20 0180 Mass Storage Controller/'Other' << Device

          (d=7,  f=0) abcd8632 devext 0xfffffa80051e5b70 devstack 0xfffffa80051e5a20 0604 Bridge/PCI to PCI

          Bus 0xb (FDO Ext fffffa80052d2e00)

            No devices have been enumerated on this bus.

      (d=14, f=0) 8086342e devext 0xfffffa80054dfb70 devstack 0xfffffa80054dfa20 0800 Base System Device/Interrupt Controller

      (d=14, f=1) 80863422 devext 0xfffffa80054e0b70 devstack 0xfffffa80054e0a20 0800 Base System Device/Interrupt Controller

      (d=14, f=2) 80863423 devext 0xfffffa80054e1b70 devstack 0xfffffa80054e1a20 0800 Base System Device/Interrupt Controller

      (d=1a, f=0) 80862937 devext 0xfffffa80054e2b70 devstack 0xfffffa80054e2a20 0c03 Serial Bus Controller/USB

      (d=1a, f=1) 80862938 devext 0xfffffa80054e31b0 devstack 0xfffffa80054e3060 0c03 Serial Bus Controller/USB

      (d=1a, f=7) 8086293c devext 0xfffffa80054e3b70 devstack 0xfffffa80054e3a20 0c03 Serial Bus Controller/USB

      (d=1d, f=0) 80862934 devext 0xfffffa80054e41b0 devstack 0xfffffa80054e4060 0c03 Serial Bus Controller/USB

      (d=1d, f=1) 80862935 devext 0xfffffa80054e4b70 devstack 0xfffffa80054e4a20 0c03 Serial Bus Controller/USB

      (d=1d, f=7) 8086293a devext 0xfffffa80054e51b0 devstack 0xfffffa80054e5060 0c03 Serial Bus Controller/USB

      (d=1e, f=0) 8086244e devext 0xfffffa80054e5b70 devstack 0xfffffa80054e5a20 0604 Bridge/PCI to PCI

      Bus 0xc (FDO Ext fffffa80054f2e00)

        (d=3,  f=0) 102b0532 devext 0xfffffa80051d51b0 devstack 0xfffffa80051d5060 0300 Display Controller/VGA

      (d=1f, f=0) 80862918 devext 0xfffffa80054e61b0 devstack 0xfffffa80054e6060 0601 Bridge/PCI to ISA

      (d=1f, f=2) 80862921 devext 0xfffffa80054e6b70 devstack 0xfffffa80054e6a20 0101 Mass Storage Controller/IDE

    Total PCI Root busses processed = 1

    Total PCI Segments processed = 1

     

    To recap the devices in the tree (Bus,Device,Function):

    (0,7,0) : Root Port, PCI-PCI Bridge (devstack 0xfffffa80054dea20)

        (6,0,0) : Upstream Switch Port (devstack 0xfffffa80051d9060)

            (7,6,0) : Downstream Switch Port (the PDO for the slot) (devstack 0xfffffa8007075a20)

                (a,0,0) : Device  (devstack 0xfffffa8006f67a20)

     

    I scanned the output looking for my ven/dev ID, and found it at Bus A, Device 0, Function 0.

     

    Step 2:  Determine which interrupt pin the device uses.

     

    For this step, you can use !pci to dump the PCI config space for the device. The output will show you the interrupt pin the device uses, labeled as IntPin.

    !pci 1 a 0 0

    PCI Bus 10

    00:0  FEFE:1550.01  Cmd[0007:imb...]  Sts[0018:c....]  Device  SubID:1344:1008  Other mass storage controller

          cf8:800a0000  IntPin:1  IntLine:2e  Rom:0  cis:0  cap:40

          MEM[2]:df5fd000  MEM[3]:df5fc000  IO[4]:cff1       MEM[5]:df5fe000 

     

    So our IntPin is 1.

     

    Step 3: Walk the parent devices to find the closest PCI Routing Table (_PRT) which will describe the mapping of interrupt pin to IRQ.

     

    Now, we will traverse the parent PCI devnodes until we find a PCI bridge which has an associated ACPI object with a _PRT method. This may be the root port, or an integrated bridge.

    1. Start by running !devstack on the parent.  We can determine the parent device using the indentations of the !pcitree output.
    2. If the devstack shows an ACPI filter driver, then dump the filter using !acpikd.acpiext to find the associated AcpiObject
    3. Dump the ACPI object and its children to see if it has a _PRT method defined
      1. If it does not have a _PRT, then you need to swizzle the Interrupt Pin to find what the pin number will be on the upstream side of the bridge
        1. We have to use a method called “swizzling” because the pin may become a different pin on the upstream side of the bridge. The way to calculate the pin is:
          1. IntPin = ((((IntPin -1) + DeviceNumber) % 4) +1)
        2. Where IntPin is the current IntPin value, and DeviceNumber the device number of the device you’re swizzling.
        3. You will start with the IntPin value from !pci output of the device itself. If you need to swizzle multiple times, you take the result of the previous swizzle as the input to the next swizzle
        4. The device number for the first time will be the device number of the target device, and subsequent times will be the device number of the parent device you’re swizzling.
      2. If it does have a _PRT, then move onto Step 4.

     

    Example:

    First, we’ll swizzle the pin of the device itself (a,0,0).  The IntPin is 1 so:

                    IntPin = ((((1-1)+0) % 4) +1)    << The Swizzled Pin is still IntPin 1

     

    Next, I dumped the parent device (7,6,0), !devstack  0xfffffa8007075a20. It didn’t have an ACPI filter driver on the stack. So I need to swizzle the pin.

          IntPin = ((((1-1)+6) % 4) +1)    << The Swizzled Pin is now 3

     

    I now dump the next parent up, (6,0,0), !devstack 0xfffffa80051d9060. It also didn’t have an ACPI filter driver on the stack so I need to swizzle the pin again.

          IntPin = ((((3-1)+0) % 4) +1)    << The Swizzled Pin is still 3

     

    I am now at the root port. The first devstack which has a _PRT method in my case is the root port.

    kd> !devstack 0xfffffa80054dea20

      !DevObj   !DrvObj            !DevExt   ObjectName

      fffffa80054f1040  \Driver\pci        fffffa80054f1190 

      fffffa80054e5800  \Driver\ACPI       fffffa80051c1510  << Has an ACPI filter driver in the devstack

    > fffffa80054dea20  \Driver\pci        fffffa80054deb70  NTPNP_PCI0006

    !DevNode fffffa80054e1750 :

      DeviceInst is "PCI\VEN_8086&DEV_340E&SUBSYS_02351028&REV_13\3&33fd14ca&0&38"

      ServiceName is "pci"

    kd> !acpikd.acpiext fffffa80051c1510

    ACPI!DEVICE_EXTENSION fffffa80051c1510 - 70000

      DevObject  fffffa80054e5800  PhysObject  fffffa80054dea20  NextObject   fffffa80054dea20

      AcpiObject fffffa80052e3890  ParentExt   fffffa80051c07d0

      PnpState   Started   OldPnpState Stopped

      Dispatch   fffff880011cbb50

      RefCounts  4-Device 1-Irp 0-Hiber 0-Wake

      State      D0       

      SxD Table  S0->D0 S4->D3 S5->D3

      Flags      0540100002000240

        Types    Filter Enumerated ValidPnP

        Caps     PCIBus

        Props    HasAddress Enabled AcpiPower


    Dump the namespace object. Use /s to display the subtree under this object and look for a _PRT method.

    kd> !amli dns /s fffffa80052e3890

     

    ACPI Name Space: \_SB.PCI0.PEX7 (fffffa80052e3890)

    Device(PEX7)

    | Integer(_ADR:Value=0x0000000000070000[458752])

    | Integer(_STA:Value=0x000000000000000f[15])

    | Method(_PRT:Flags=0x0,CodeBuff=fffffa80052e3aa9,Len=144) << A _PRT method exists for this object

     

    Now, we have a swizzled IntPin value of 3, and a pointer to the _PRT method.  We can move on to the next step.

     

    Step 4: Convert the pin number from PCI to ACPI numbering

     

    The !pci or !devext output, and subsequent swizzling will show pin numbering in PCI format where 1 = INTA. But the ACPI table uses 0 for INTA. So you need to subtract one from the PCI pin number to get the ACPI pin number.

     

    PCI pin number

    ACPI pin number

    INTA

    1

    0

    INTB

    2

    1

    INTC

    3

    2

    INTD

    4

    3

     

    Once you’ve converted to ACPI pin numbering, you have to dump the _PRT method to find the package which maps to that pin number.

     

    For my example since the PCI IntPin value is 3, which corresponds to INTC, the ACPI pin number is 2

     

    Step 5: Parse the _PRT method to find the static routing table

     

    Now that we located the correct _PRT entry, we need to use the AMLI debugger extension to parse the method and find the static routing table.  The command !amli u will unassemble an ACPI method

    kd> !amli u \_SB.PCI0.PEX7._PRT

    AMLI_DBGERR: Failed to get address of ACPI!gDebugger

     

    fffffa80052e3aa9 : If(LNot(PICF))

    fffffa80052e3ab1 : {

    fffffa80052e3ab1 : | Name(P10B, Package(0x4)

    fffffa80052e3ab9 : | {

    fffffa80052e3ab9 : | | Package(0x4)

    fffffa80052e3abc : | | {

    fffffa80052e3abc : | | | 0xffff,

    fffffa80052e3abf : | | | 0x0,

    fffffa80052e3ac1 : | | | LK00,

    fffffa80052e3ac5 : | | | 0x0

    fffffa80052e3ac7 : | | },

    fffffa80052e3ac7 : | | Package(0x4)

    fffffa80052e3aca : | | {

    fffffa80052e3aca : | | | 0xffff,

    fffffa80052e3acd : | | | 0x1,

    fffffa80052e3acf : | | | LK01,

    fffffa80052e3ad3 : | | | 0x0

    fffffa80052e3ad5 : | | },

    fffffa80052e3ad5 : | | Package(0x4)

    fffffa80052e3ad8 : | | {

    fffffa80052e3ad8 : | | | 0xffff,

    fffffa80052e3adb : | | | 0x2,

    fffffa80052e3add : | | | LK02,

    fffffa80052e3ae1 : | | | 0x0

    fffffa80052e3ae3 : | | },

    fffffa80052e3ae3 : | | Package(0x4)

    fffffa80052e3ae6 : | | {

    fffffa80052e3ae6 : | | | 0xffff,

    fffffa80052e3ae9 : | | | 0x3,

    fffffa80052e3aeb : | | | LK03,

    fffffa80052e3aef : | | | 0x0

    fffffa80052e3af1 : | | }

    fffffa80052e3af1 : | })

    fffffa80052e3af1 : | Store(P10B, Local0)

    fffffa80052e3af7 : }

    fffffa80052e3af7 : Else

    fffffa80052e3af9 : {

    fffffa80052e3af9 : | Name(A10B, Package(0x4)

    fffffa80052e3b01 : | {

    fffffa80052e3b01 : | | Package(0x4)

    fffffa80052e3b04 : | | {

    fffffa80052e3b04 : | | | 0xffff,

    fffffa80052e3b07 : | | | 0x0,

    fffffa80052e3b09 : | | | 0x0,

    fffffa80052e3b0b : | | | 0x26

    fffffa80052e3b0d : | | },

    fffffa80052e3b0d : | | Package(0x4)

    fffffa80052e3b10 : | | {

    fffffa80052e3b10 : | | | 0xffff,

    fffffa80052e3b13 : | | | 0x1,

    fffffa80052e3b15 : | | | 0x0,

    fffffa80052e3b17 : | | | 0x2d

    fffffa80052e3b19 : | | },

    fffffa80052e3b19 : | | Package(0x4)

    fffffa80052e3b1c : | | {

    fffffa80052e3b1c : | | | 0xffff,

    fffffa80052e3b1f : | | | 0x2,

    fffffa80052e3b21 : | | | 0x0,

    fffffa80052e3b23 : | | | 0x2f

    fffffa80052e3b25 : | | },

    fffffa80052e3b25 : | | Package(0x4)

    fffffa80052e3b28 : | | {

    fffffa80052e3b28 : | | | 0xffff,

    fffffa80052e3b2b : | | | 0x3,

    fffffa80052e3b2d : | | | 0x0,

    fffffa80052e3b2f : | | | 0x2e

    fffffa80052e3b31 : | | }

    fffffa80052e3b31 : | })

    fffffa80052e3b31 : | Store(A10B, Local0)

    fffffa80052e3b37 : }

    fffffa80052e3b37 : Return(Local0)

    fffffa80052e3b39 : Zero

    fffffa80052e3b3a : Zero

    fffffa80052e3b3b : Zero

    fffffa80052e3b3c : Zero

    fffffa80052e3b3d : Zero

    fffffa80052e3b3e : Zero

    fffffa80052e3b3f : Zero

    fffffa80052e3b40 : HNSO

    fffffa80052e3b44 : Not(Zero, )

    fffffa80052e3b47 : Zero

    fffffa80052e3b48 : Zero

    fffffa80052e3b49 : AMLI_DBGERR: UnAsmOpcode: invalid opcode class 0

    AMLI_DBGERR: Failed to unassemble scope at 382d4a0 (size=4096)

     

    There are 2 different _PRT tables here, each with 4 packages (think of it as 2 arrays, each containing 4 structures). The first is using link nodes, the second is using static interrupts.  The first list is used if we are in PIC mode, the second if we are in APIC mode.

     

    We can check the value of PICF to determine the mode. (I expect it to be APIC but let’s check)

    kd> !amli dns \PICF

     

    ACPI Name Space: \PICF (fffffa80052ded18)

    Integer(PICF:Value=0x0000000000000001[1])

     

    So we’re in APIC mode (PICF != 0), we use the static routing mode. So we will use the 2nd table.  What does each package represent?  Each is a PCI Routing Table. From ACPI spec section 6.2.12, which describes the _PRT:

    Table 6-14   Mapping Fields

    Field

    Type

    Description

    Address

    DWORD

    The address of the device (uses the same format as _ADR).

    Pin

    BYTE

    The PCI pin number of the device (0–INTA, 1–INTB, 2–INTC, 3–INTD).

    Source

    NamePath

    Or

    BYTE

    Name of the device that allocates the interrupt to which the above pin is connected. The name can be a fully qualified path, a relative path, or a simple name segment that utilizes the namespace search rules. Note: This field is a NamePath and not a String literal, meaning that it should not be surrounded by quotes. If this field is the integer constant Zero (or a BYTE value of 0), then the interrupt is allocated from the global interrupt pool.

    Source Index

    DWORD

    Index that indicates which resource descriptor in the resource template of the device pointed to in the Source field this interrupt is allocated from. If the Source field is the BYTE value zero, then this field is the global system interrupt number to which the pin is connected.

     

    fffffa80052e3af9 : | Name(A10B, Package(0x4)

    fffffa80052e3b01 : | {

    fffffa80052e3b01 : | | Package(0x4)

    fffffa80052e3b04 : | | {

    fffffa80052e3b04 : | | | 0xffff,

    fffffa80052e3b07 : | | | 0x0,          << INTA

    fffffa80052e3b09 : | | | 0x0,

    fffffa80052e3b0b : | | | 0x26  << Interrupt line

    fffffa80052e3b0d : | | },

    fffffa80052e3b0d : | | Package(0x4)

    fffffa80052e3b10 : | | {

    fffffa80052e3b10 : | | | 0xffff,

    fffffa80052e3b13 : | | | 0x1,          << INTB

    fffffa80052e3b15 : | | | 0x0,

    fffffa80052e3b17 : | | | 0x2d

    fffffa80052e3b19 : | | },

    fffffa80052e3b19 : | | Package(0x4)

    fffffa80052e3b1c : | | {

    fffffa80052e3b1c : | | | 0xffff,

    fffffa80052e3b1f : | | | 0x2,          << INTC

    fffffa80052e3b21 : | | | 0x0,

    fffffa80052e3b23 : | | | 0x2f

    fffffa80052e3b25 : | | },

    fffffa80052e3b25 : | | Package(0x4)

    fffffa80052e3b28 : | | {

    fffffa80052e3b28 : | | | 0xffff,

    fffffa80052e3b2b : | | | 0x3,          << INTD

    fffffa80052e3b2d : | | | 0x0,

    fffffa80052e3b2f : | | | 0x2e

    fffffa80052e3b31 : | | }

    fffffa80052e3b31 : | })

     

    Step 6 - Find the routing entry which represents our IntPin

     

    Now, we just have to locate the entry in the routing table with a IntPin value of 2.

     

    fffffa80052e3b19 : | | Package(0x4)

    fffffa80052e3b1c : | | {

    fffffa80052e3b1c : | | | 0xffff,

    fffffa80052e3b1f : | | | 0x2, <<< IntPin 2 (INTC)

    fffffa80052e3b21 : | | | 0x0,

    fffffa80052e3b23 : | | | 0x2f << IRQ is 0x2f

     

    So the device should be assigned IRQ 0x2F.   However, you may have noticed from the !pci output above that in this case the device was actually assigned IntLine (IRQ) 0x2e!  Since the wrong interrupt line was assigned after the device changed slots in the system, the device did not receive interrupts and hence was not functional.

     

    I hope this was useful to help understand how interrupts are assigned to LBI devices.

     

    More reading / references:

     

    PCI IRQ Routing on a Multiprocessor ACPI System:

    http://msdn.microsoft.com/en-us/windows/hardware/gg454523.aspx#EDD

     

    ACPI 4.0 spec

    http://www.acpi.info/DOWNLOADS/ACPIspec40a.doc

Page 1 of 1 (2 items)