]> git.saurik.com Git - apple/xnu.git/blobdiff - tools/lldbmacros/apic.py
xnu-2422.1.72.tar.gz
[apple/xnu.git] / tools / lldbmacros / apic.py
diff --git a/tools/lldbmacros/apic.py b/tools/lldbmacros/apic.py
new file mode 100644 (file)
index 0000000..506d986
--- /dev/null
@@ -0,0 +1,354 @@
+from xnu import *
+from misc import DoReadMsr64, DoWriteMsr64
+
+######################################
+# Globals
+######################################
+lapic_base_addr = 0xfee00000
+ioapic_base_addr = 0xfec00000
+ioapic_index_off = 0x0
+ioapic_data_off = 0x10
+
+
+######################################
+# LAPIC Helper functions
+######################################
+def IsArchX86_64():
+    """ Determines if target machine is x86_64  
+        Returns:
+            True if running on x86_64, False otherwise
+    """
+    return kern.arch == "x86_64"
+        
+
+@static_var('x2apic_enabled', -1)
+def IsX2ApicEnabled():
+    """ Reads the APIC configuration MSR to determine if APIC is operating
+        in x2APIC mode. The MSR is read the first time this function is
+        called, and the answer is remembered for all subsequent calls.
+        Returns:
+            True if APIC is x2APIC mode
+            False if not
+    """
+    apic_cfg_msr = 0x1b
+    apic_cfg_msr_x2en_mask = 0xc00
+    if IsX2ApicEnabled.x2apic_enabled < 0:
+        if (int(DoReadMsr64(apic_cfg_msr, xnudefines.lcpu_self)) & apic_cfg_msr_x2en_mask == 
+            apic_cfg_msr_x2en_mask):
+            IsX2ApicEnabled.x2apic_enabled = 1
+        else:
+            IsX2ApicEnabled.x2apic_enabled = 0
+    return IsX2ApicEnabled.x2apic_enabled == 1
+
+def DoLapicRead32(offset, cpu):
+    """ Read the specified 32-bit LAPIC register
+        Params:
+            offset: int - index of LAPIC register to read
+            cpu: int - cpu ID
+        Returns:
+            The 32-bit LAPIC register value
+    """
+    if IsX2ApicEnabled():
+        return DoReadMsr64(offset >> 4, cpu)
+    else:
+        return ReadPhysInt(lapic_base_addr + offset, 32, cpu)
+
+def DoLapicWrite32(offset, val, cpu):
+    """ Write the specified 32-bit LAPIC register
+        Params:
+            offset: int - index of LAPIC register to write
+            val: int - write value
+            cpu: int - cpu ID
+        Returns:
+            True if success, False if error
+    """
+    if IsX2ApicEnabled():
+        return DoWriteMsr64(offset >> 4, cpu, val)
+    else:
+        return WritePhysInt(lapic_base_addr + offset, val, 32)
+
+######################################
+# LAPIC Register Print functions
+######################################
+def GetLapicVersionFields(reg_val):
+    """ Helper function for DoLapicDump that prints the fields of the
+        version register. 
+        Params:
+            reg_val: int - the value of the version register to print
+        Returns:   
+            string showing the fields
+    """
+    lvt_num = (reg_val >> 16) + 1
+    version = reg_val & 0xff
+    return "[VERSION={:d} MaxLVT={:d}]".format(lvt_num, version)
+    
+def GetLapicSpuriousVectorFields(reg_val):
+    """ Helper function for DoLapicDump that prints the fields of the
+        spurious vector register.
+        Params:
+            reg_val: int - the value of the spurious vector registre to print
+        Returns:   
+            string showing the fields
+    """
+    vector = reg_val & 0xff
+    enabled = (reg_val & 0x100) >> 8
+    return "[VEC={:3d} ENABLED={:d}]".format(vector, enabled)
+  
+def GetLapicIcrHiFields(reg_val):
+    """ Helper function for DoLapicDump that prints the fields of the 
+        upper 32-bits of the Interrupt Control Register (ICR).
+        Params:
+            reg_val: int - the value of the ICR to show
+        Returns:   
+            string showing the fields
+    """
+    dest = reg_val >> 24
+    return "[DEST={:d}]".format(dest)
+
+def GetLapicTimerDivideFields(reg_val):
+    """ Helper function for DoLapicDump that prints the fields of the
+        timer divide register.
+        Params:
+            reg_val: int - the value of the timer divide register
+        Returns:   
+            string showing the fields
+    """
+    divide_val = ((reg_val & 0x8) >> 1) | (reg_val & 0x3)
+    if divide_val == 0x7:
+        divide_by = 1
+    else:
+        divide_by = 2 << divide_val
+    return "[Divide by {:d}]".format(divide_by)
+
+def GetApicFields(reg_val):
+    """ Helper function for DoLapicDump and DoIoapicDump that prints the
+        fields of the APIC register.
+        Params:
+            reg_val: int - the value of the APIC register to print
+        Returns:   
+            string showing the fields
+    """
+    vector = reg_val & 0xff
+    tsc_deadline = reg_val & 0x40000
+    periodic = reg_val & 0x20000
+    masked = reg_val & 0x10000
+    trigger = reg_val & 0x8000
+    polarity = reg_val & 0x2000
+    pending = reg_val & 0x1000
+
+    ret_str = "[VEC={:3d} MASK={:3s} TRIG={:5s} POL={:4s} PEND={:3s}".format( 
+        vector,
+        "no" if masked == 0 else "yes",
+        "edge" if trigger == 0 else "level",
+        "low" if polarity == 0 else "high",
+        "no" if pending == 0 else "yes")
+    if not periodic == 0:
+        ret_str += " PERIODIC"
+    if not tsc_deadline == 0:
+        ret_str += " TSC_DEADLINE"
+    ret_str += "]"
+    return ret_str
+
+def DoLapicDump():
+    """ Prints all LAPIC registers
+    """
+    print "LAPIC operating mode: {:s}".format(
+        "x2APIC" if IsX2ApicEnabled() else "xAPIC")
+    # LAPIC register offset, register name, field formatting function
+    lapic_dump_table = [
+        (0x020, "ID", None),
+        (0x030, "VERSION", GetLapicVersionFields),
+        (0x080, "TASK PRIORITY", None),
+        (0x0A0, "PROCESSOR PRIORITY", None),
+        (0x0D0, "LOGICAL DEST", None),
+        (0x0E0, "DEST FORMAT", None),
+        (0x0F0, "SPURIOUS VECTOR", GetLapicSpuriousVectorFields),
+        (0x100, "ISR[031:000]", None),
+        (0x110, "ISR[063:032]", None),
+        (0x120, "ISR[095:064]", None),
+        (0x130, "ISR[127:096]", None),
+        (0x140, "ISR[159:128]", None),
+        (0x150, "ISR[191:160]", None),
+        (0x160, "ISR[223:192]", None),
+        (0x170, "ISR[225:224]", None),
+        (0x180, "TMR[031:000]", None),
+        (0x190, "TMR[063:032]", None),
+        (0x1A0, "TMR[095:064]", None),
+        (0x1B0, "TMR[127:096]", None),
+        (0x1C0, "TMR[159:128]", None),
+        (0x1D0, "TMR[191:160]", None),
+        (0x1E0, "TMR[223:192]", None),
+        (0x1F0, "TMR[225:224]", None),
+        (0x200, "IRR[031:000]", None),
+        (0x210, "IRR[063:032]", None),
+        (0x220, "IRR[095:064]", None),
+        (0x230, "IRR[127:096]", None),
+        (0x240, "IRR[159:128]", None),
+        (0x250, "IRR[191:160]", None),
+        (0x260, "IRR[223:192]", None),
+        (0x270, "IRR[225:224]", None),
+        (0x280, "ERROR STATUS", None),
+        (0x300, "Interrupt Command LO", GetApicFields),
+        (0x310, "Interrupt Command HI", GetLapicIcrHiFields),
+        (0x320, "LVT Timer", GetApicFields),
+        (0x350, "LVT LINT0", GetApicFields),
+        (0x360, "LVT LINT1", GetApicFields),
+        (0x370, "LVT Error", GetApicFields),
+        (0x340, "LVT PerfMon", GetApicFields),
+        (0x330, "LVT Thermal", GetApicFields),
+        (0x3e0, "Timer Divide", GetLapicTimerDivideFields),
+        (0x380, "Timer Init Count", None),
+        (0x390, "Timer Cur Count", None)]
+    for reg in lapic_dump_table:
+        reg_val = DoLapicRead32(reg[0], xnudefines.lcpu_self)
+        if reg[2] == None:
+            print "LAPIC[{:#05x}] {:21s}: {:#010x}".format(reg[0], reg[1], reg_val)
+        else:
+            print "LAPIC[{:#05x}] {:21s}: {:#010x} {:s}".format(reg[0], reg[1],
+                reg_val, reg[2](reg_val))
+
+######################################
+# IOAPIC Helper functions
+######################################
+def DoIoApicRead(offset):
+    """ Read the specified IOAPIC register
+        Params:
+            offset: int - index of IOAPIC register to read
+        Returns:
+            int 32-bit read value
+    """
+    WritePhysInt(ioapic_base_addr + ioapic_index_off, offset, 8)
+    return ReadPhysInt(ioapic_base_addr + ioapic_data_off, 32)
+
+def DoIoApicWrite(offset, val):
+    """ Write the specified IOAPIC register
+        Params:
+            offset: int - index of IOAPIC register to write
+        Returns:
+            True if success, False if error
+    """
+    WritePhysInt(ioapic_base_addr + ioapic_index_off, offset, 8)
+    return WritePhysInt(ioapic_base_addr + ioapic_data_off, val, 32)
+
+def DoIoApicDump():
+    """ Prints all IOAPIC registers
+    """
+    # Show IOAPIC ID register
+    ioapic_id = DoIoApicRead(0)
+    print "IOAPIC[0x00] {:9s}: {:#010x}".format("ID", ioapic_id)
+    # Show IOAPIC Version register
+    ioapic_ver = DoIoApicRead(1)
+    maxredir = ((ioapic_ver >> 16) & 0xff) + 1
+    print "IOAPIC[0x01] {:9s}: {:#010x}".format("VERSION", ioapic_ver) +\
+        "       [MAXREDIR={:02d} PRQ={:d} VERSION={:#04x}]".format(
+            maxredir,
+            ioapic_ver >> 15 & 0x1,
+            ioapic_ver & 0xff)
+    # Show IOAPIC redirect regsiters
+    for redir in range(maxredir):
+        redir_val_lo = DoIoApicRead(0x10 + redir * 2)
+        redir_val_hi = DoIoApicRead(0x10 + (redir * 2) + 1)
+        print "IOAPIC[{:#04x}] IOREDIR{:02d}: {:#08x}{:08x} {:s}".format(
+            0x10 + (redir * 2),
+            redir, 
+            redir_val_hi,
+            redir_val_lo,
+            GetApicFields(redir_val_lo))
+
+######################################
+# LLDB commands
+######################################
+@lldb_command('lapic_read32')
+def LapicRead32(cmd_args=None):
+    """ Read the LAPIC register at the specified offset. The CPU can
+        be optionally specified
+        Syntax: lapic_read32 <offset> [lcpu]
+    """
+    if cmd_args == None or len(cmd_args) < 1:
+        print LapicRead32.__doc__
+        return
+    if not IsArchX86_64():
+        print "lapic_read32 not supported on this architecture."
+        return
+    
+    lcpu = xnudefines.lcpu_self
+    if len(cmd_args) > 1:
+        lcpu = ArgumentStringToInt(cmd_args[1])
+
+    offset = ArgumentStringToInt(cmd_args[0])
+    read_val = DoLapicRead32(offset, lcpu)
+    print "LAPIC[{:#05x}]: {:#010x}".format(offset, read_val)
+
+@lldb_command('lapic_write32')
+def LapicWrite32(cmd_args=None):
+    """ Write the LAPIC register at the specified offset. The CPU can
+        be optionally specified. Prints an error message if there was a
+        failure. Prints nothing upon success.
+        Syntax: lapic_write32 <offset> <val> [lcpu]
+    """
+    if cmd_args == None or len(cmd_args) < 2:
+        print LapicWrite32.__doc__
+        return
+    if not IsArchX86_64():
+        print "lapic_write32 not supported on this architecture."
+        return
+    offset = ArgumentStringToInt(cmd_args[0])
+    write_val = ArgumentStringToInt(cmd_args[1])
+    lcpu = xnudefines.lcpu_self
+    if len(cmd_args) > 2:
+        lcpu = ArgumentStringToInt(cmd_args[2])
+    if not DoLapicWrite32(offset, write_val, lcpu):
+        print "lapic_write32 FAILED"
+
+@lldb_command('lapic_dump')
+def LapicDump(cmd_args=None):
+    """ Prints all LAPIC entries
+    """
+    if not IsArchX86_64():
+        print "lapic_dump not supported on this architecture."
+        return
+    DoLapicDump()
+
+@lldb_command('ioapic_read32')
+def IoApicRead32(cmd_args=None):
+    """ Read the IOAPIC register at the specified offset.
+        Syntax: ioapic_read32 <offset>
+    """
+    if cmd_args == None or len(cmd_args) < 1:
+        print IoApicRead32.__doc__
+        return
+    if not IsArchX86_64():
+        print "ioapic_read32 not supported on this architecture."
+        return
+
+    offset = ArgumentStringToInt(cmd_args[0])
+    read_val = DoIoApicRead(offset)
+    print "IOAPIC[{:#04x}]: {:#010x}".format(offset, read_val)
+
+@lldb_command('ioapic_write32')
+def IoApicWrite32(cmd_args=None):
+    """ Write the IOAPIC register at the specified offset.
+        Syntax: ioapic_write32 <offset> <val>
+    """
+    if cmd_args == None or len(cmd_args) < 2:
+        print IoApicWrite32.__doc__
+        return
+    if not IsArchX86_64():
+        print "ioapic_write32 not supported on this architecture."
+        return
+
+    offset = ArgumentStringToInt(cmd_args[0])
+    write_val = ArgumentStringToInt(cmd_args[1])
+    if not DoIoApicWrite(offset, write_val):
+        print "ioapic_write32 FAILED"
+    return
+
+@lldb_command('ioapic_dump')
+def IoApicDump(cmd_args=None):
+    """ Prints all IOAPIC entries
+    """
+    if not IsArchX86_64():
+        print "ioapic_dump not supported on this architecture."
+        return
+    DoIoApicDump()
+