X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/bd504ef0e0b883cdd7917b73b3574eb9ce669905..39236c6e673c41db228275375ab7fdb0f837b292:/tools/lldbmacros/apic.py diff --git a/tools/lldbmacros/apic.py b/tools/lldbmacros/apic.py new file mode 100644 index 000000000..506d98685 --- /dev/null +++ b/tools/lldbmacros/apic.py @@ -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 [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 [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 + """ + 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 + """ + 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() +