--- /dev/null
+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()
+