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