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