1from xnu import * 2from misc import DoReadMsr64, DoWriteMsr64 3 4###################################### 5# Globals 6###################################### 7lapic_base_addr = 0xfee00000 8ioapic_base_addr = 0xfec00000 9ioapic_index_off = 0x0 10ioapic_data_off = 0x10 11 12 13###################################### 14# LAPIC Helper functions 15###################################### 16def IsArchX86_64(): 17 """ Determines if target machine is x86_64 18 Returns: 19 True if running on x86_64, False otherwise 20 """ 21 return kern.arch == "x86_64" 22 23 24@static_var('x2apic_enabled', -1) 25def IsX2ApicEnabled(): 26 """ Reads the APIC configuration MSR to determine if APIC is operating 27 in x2APIC mode. The MSR is read the first time this function is 28 called, and the answer is remembered for all subsequent calls. 29 Returns: 30 True if APIC is x2APIC mode 31 False if not 32 """ 33 apic_cfg_msr = 0x1b 34 apic_cfg_msr_x2en_mask = 0xc00 35 if IsX2ApicEnabled.x2apic_enabled < 0: 36 if (int(DoReadMsr64(apic_cfg_msr, xnudefines.lcpu_self)) & apic_cfg_msr_x2en_mask == 37 apic_cfg_msr_x2en_mask): 38 IsX2ApicEnabled.x2apic_enabled = 1 39 else: 40 IsX2ApicEnabled.x2apic_enabled = 0 41 return IsX2ApicEnabled.x2apic_enabled == 1 42 43def DoLapicRead32(offset, cpu): 44 """ Read the specified 32-bit LAPIC register 45 Params: 46 offset: int - index of LAPIC register to read 47 cpu: int - cpu ID 48 Returns: 49 The 32-bit LAPIC register value 50 """ 51 if IsX2ApicEnabled(): 52 return DoReadMsr64(offset >> 4, cpu) 53 else: 54 return ReadPhysInt(lapic_base_addr + offset, 32, cpu) 55 56def DoLapicWrite32(offset, val, cpu): 57 """ Write the specified 32-bit LAPIC register 58 Params: 59 offset: int - index of LAPIC register to write 60 val: int - write value 61 cpu: int - cpu ID 62 Returns: 63 True if success, False if error 64 """ 65 if IsX2ApicEnabled(): 66 return DoWriteMsr64(offset >> 4, cpu, val) 67 else: 68 return WritePhysInt(lapic_base_addr + offset, val, 32) 69 70###################################### 71# LAPIC Register Print functions 72###################################### 73def GetLapicVersionFields(reg_val): 74 """ Helper function for DoLapicDump that prints the fields of the 75 version register. 76 Params: 77 reg_val: int - the value of the version register to print 78 Returns: 79 string showing the fields 80 """ 81 lvt_num = (reg_val >> 16) + 1 82 version = reg_val & 0xff 83 return "[VERSION={:d} MaxLVT={:d}]".format(lvt_num, version) 84 85def GetLapicSpuriousVectorFields(reg_val): 86 """ Helper function for DoLapicDump that prints the fields of the 87 spurious vector register. 88 Params: 89 reg_val: int - the value of the spurious vector registre to print 90 Returns: 91 string showing the fields 92 """ 93 vector = reg_val & 0xff 94 enabled = (reg_val & 0x100) >> 8 95 return "[VEC={:3d} ENABLED={:d}]".format(vector, enabled) 96 97def GetLapicIcrHiFields(reg_val): 98 """ Helper function for DoLapicDump that prints the fields of the 99 upper 32-bits of the Interrupt Control Register (ICR). 100 Params: 101 reg_val: int - the value of the ICR to show 102 Returns: 103 string showing the fields 104 """ 105 dest = reg_val >> 24 106 return "[DEST={:d}]".format(dest) 107 108def GetLapicTimerDivideFields(reg_val): 109 """ Helper function for DoLapicDump that prints the fields of the 110 timer divide register. 111 Params: 112 reg_val: int - the value of the timer divide register 113 Returns: 114 string showing the fields 115 """ 116 divide_val = ((reg_val & 0x8) >> 1) | (reg_val & 0x3) 117 if divide_val == 0x7: 118 divide_by = 1 119 else: 120 divide_by = 2 << divide_val 121 return "[Divide by {:d}]".format(divide_by) 122 123def GetApicFields(reg_val): 124 """ Helper function for DoLapicDump and DoIoapicDump that prints the 125 fields of the APIC register. 126 Params: 127 reg_val: int - the value of the APIC register to print 128 Returns: 129 string showing the fields 130 """ 131 vector = reg_val & 0xff 132 tsc_deadline = reg_val & 0x40000 133 periodic = reg_val & 0x20000 134 masked = reg_val & 0x10000 135 trigger = reg_val & 0x8000 136 polarity = reg_val & 0x2000 137 pending = reg_val & 0x1000 138 139 ret_str = "[VEC={:3d} MASK={:3s} TRIG={:5s} POL={:4s} PEND={:3s}".format( 140 vector, 141 "no" if masked == 0 else "yes", 142 "edge" if trigger == 0 else "level", 143 "low" if polarity == 0 else "high", 144 "no" if pending == 0 else "yes") 145 if not periodic == 0: 146 ret_str += " PERIODIC" 147 if not tsc_deadline == 0: 148 ret_str += " TSC_DEADLINE" 149 ret_str += "]" 150 return ret_str 151 152def DoLapicDump(): 153 """ Prints all LAPIC registers 154 """ 155 print "LAPIC operating mode: {:s}".format( 156 "x2APIC" if IsX2ApicEnabled() else "xAPIC") 157 # LAPIC register offset, register name, field formatting function 158 lapic_dump_table = [ 159 (0x020, "ID", None), 160 (0x030, "VERSION", GetLapicVersionFields), 161 (0x080, "TASK PRIORITY", None), 162 (0x0A0, "PROCESSOR PRIORITY", None), 163 (0x0D0, "LOGICAL DEST", None), 164 (0x0E0, "DEST FORMAT", None), 165 (0x0F0, "SPURIOUS VECTOR", GetLapicSpuriousVectorFields), 166 (0x100, "ISR[031:000]", None), 167 (0x110, "ISR[063:032]", None), 168 (0x120, "ISR[095:064]", None), 169 (0x130, "ISR[127:096]", None), 170 (0x140, "ISR[159:128]", None), 171 (0x150, "ISR[191:160]", None), 172 (0x160, "ISR[223:192]", None), 173 (0x170, "ISR[225:224]", None), 174 (0x180, "TMR[031:000]", None), 175 (0x190, "TMR[063:032]", None), 176 (0x1A0, "TMR[095:064]", None), 177 (0x1B0, "TMR[127:096]", None), 178 (0x1C0, "TMR[159:128]", None), 179 (0x1D0, "TMR[191:160]", None), 180 (0x1E0, "TMR[223:192]", None), 181 (0x1F0, "TMR[225:224]", None), 182 (0x200, "IRR[031:000]", None), 183 (0x210, "IRR[063:032]", None), 184 (0x220, "IRR[095:064]", None), 185 (0x230, "IRR[127:096]", None), 186 (0x240, "IRR[159:128]", None), 187 (0x250, "IRR[191:160]", None), 188 (0x260, "IRR[223:192]", None), 189 (0x270, "IRR[225:224]", None), 190 (0x280, "ERROR STATUS", None), 191 (0x300, "Interrupt Command LO", GetApicFields), 192 (0x310, "Interrupt Command HI", GetLapicIcrHiFields), 193 (0x320, "LVT Timer", GetApicFields), 194 (0x350, "LVT LINT0", GetApicFields), 195 (0x360, "LVT LINT1", GetApicFields), 196 (0x370, "LVT Error", GetApicFields), 197 (0x340, "LVT PerfMon", GetApicFields), 198 (0x330, "LVT Thermal", GetApicFields), 199 (0x3e0, "Timer Divide", GetLapicTimerDivideFields), 200 (0x380, "Timer Init Count", None), 201 (0x390, "Timer Cur Count", None)] 202 for reg in lapic_dump_table: 203 reg_val = DoLapicRead32(reg[0], xnudefines.lcpu_self) 204 if reg[2] == None: 205 print "LAPIC[{:#05x}] {:21s}: {:#010x}".format(reg[0], reg[1], reg_val) 206 else: 207 print "LAPIC[{:#05x}] {:21s}: {:#010x} {:s}".format(reg[0], reg[1], 208 reg_val, reg[2](reg_val)) 209 210###################################### 211# IOAPIC Helper functions 212###################################### 213def DoIoApicRead(offset): 214 """ Read the specified IOAPIC register 215 Params: 216 offset: int - index of IOAPIC register to read 217 Returns: 218 int 32-bit read value 219 """ 220 WritePhysInt(ioapic_base_addr + ioapic_index_off, offset, 8) 221 return ReadPhysInt(ioapic_base_addr + ioapic_data_off, 32) 222 223def DoIoApicWrite(offset, val): 224 """ Write the specified IOAPIC register 225 Params: 226 offset: int - index of IOAPIC register to write 227 Returns: 228 True if success, False if error 229 """ 230 WritePhysInt(ioapic_base_addr + ioapic_index_off, offset, 8) 231 return WritePhysInt(ioapic_base_addr + ioapic_data_off, val, 32) 232 233def DoIoApicDump(): 234 """ Prints all IOAPIC registers 235 """ 236 # Show IOAPIC ID register 237 ioapic_id = DoIoApicRead(0) 238 print "IOAPIC[0x00] {:9s}: {:#010x}".format("ID", ioapic_id) 239 # Show IOAPIC Version register 240 ioapic_ver = DoIoApicRead(1) 241 maxredir = ((ioapic_ver >> 16) & 0xff) + 1 242 print "IOAPIC[0x01] {:9s}: {:#010x}".format("VERSION", ioapic_ver) +\ 243 " [MAXREDIR={:02d} PRQ={:d} VERSION={:#04x}]".format( 244 maxredir, 245 ioapic_ver >> 15 & 0x1, 246 ioapic_ver & 0xff) 247 # Show IOAPIC redirect regsiters 248 for redir in range(maxredir): 249 redir_val_lo = DoIoApicRead(0x10 + redir * 2) 250 redir_val_hi = DoIoApicRead(0x10 + (redir * 2) + 1) 251 print "IOAPIC[{:#04x}] IOREDIR{:02d}: {:#08x}{:08x} {:s}".format( 252 0x10 + (redir * 2), 253 redir, 254 redir_val_hi, 255 redir_val_lo, 256 GetApicFields(redir_val_lo)) 257 258###################################### 259# LLDB commands 260###################################### 261@lldb_command('lapic_read32') 262def LapicRead32(cmd_args=None): 263 """ Read the LAPIC register at the specified offset. The CPU can 264 be optionally specified 265 Syntax: lapic_read32 <offset> [lcpu] 266 """ 267 if cmd_args == None or len(cmd_args) < 1: 268 print LapicRead32.__doc__ 269 return 270 if not IsArchX86_64(): 271 print "lapic_read32 not supported on this architecture." 272 return 273 274 lcpu = xnudefines.lcpu_self 275 if len(cmd_args) > 1: 276 lcpu = ArgumentStringToInt(cmd_args[1]) 277 278 offset = ArgumentStringToInt(cmd_args[0]) 279 read_val = DoLapicRead32(offset, lcpu) 280 print "LAPIC[{:#05x}]: {:#010x}".format(offset, read_val) 281 282@lldb_command('lapic_write32') 283def LapicWrite32(cmd_args=None): 284 """ Write the LAPIC register at the specified offset. The CPU can 285 be optionally specified. Prints an error message if there was a 286 failure. Prints nothing upon success. 287 Syntax: lapic_write32 <offset> <val> [lcpu] 288 """ 289 if cmd_args == None or len(cmd_args) < 2: 290 print LapicWrite32.__doc__ 291 return 292 if not IsArchX86_64(): 293 print "lapic_write32 not supported on this architecture." 294 return 295 offset = ArgumentStringToInt(cmd_args[0]) 296 write_val = ArgumentStringToInt(cmd_args[1]) 297 lcpu = xnudefines.lcpu_self 298 if len(cmd_args) > 2: 299 lcpu = ArgumentStringToInt(cmd_args[2]) 300 if not DoLapicWrite32(offset, write_val, lcpu): 301 print "lapic_write32 FAILED" 302 303@lldb_command('lapic_dump') 304def LapicDump(cmd_args=None): 305 """ Prints all LAPIC entries 306 """ 307 if not IsArchX86_64(): 308 print "lapic_dump not supported on this architecture." 309 return 310 DoLapicDump() 311 312@lldb_command('ioapic_read32') 313def IoApicRead32(cmd_args=None): 314 """ Read the IOAPIC register at the specified offset. 315 Syntax: ioapic_read32 <offset> 316 """ 317 if cmd_args == None or len(cmd_args) < 1: 318 print IoApicRead32.__doc__ 319 return 320 if not IsArchX86_64(): 321 print "ioapic_read32 not supported on this architecture." 322 return 323 324 offset = ArgumentStringToInt(cmd_args[0]) 325 read_val = DoIoApicRead(offset) 326 print "IOAPIC[{:#04x}]: {:#010x}".format(offset, read_val) 327 328@lldb_command('ioapic_write32') 329def IoApicWrite32(cmd_args=None): 330 """ Write the IOAPIC register at the specified offset. 331 Syntax: ioapic_write32 <offset> <val> 332 """ 333 if cmd_args == None or len(cmd_args) < 2: 334 print IoApicWrite32.__doc__ 335 return 336 if not IsArchX86_64(): 337 print "ioapic_write32 not supported on this architecture." 338 return 339 340 offset = ArgumentStringToInt(cmd_args[0]) 341 write_val = ArgumentStringToInt(cmd_args[1]) 342 if not DoIoApicWrite(offset, write_val): 343 print "ioapic_write32 FAILED" 344 return 345 346@lldb_command('ioapic_dump') 347def IoApicDump(cmd_args=None): 348 """ Prints all IOAPIC entries 349 """ 350 if not IsArchX86_64(): 351 print "ioapic_dump not supported on this architecture." 352 return 353 DoIoApicDump() 354 355