|
7 | 7 | from capstone import Cs, CS_ARCH_ARM, CS_MODE_ARM, CS_MODE_MCLASS, CS_MODE_THUMB |
8 | 8 | from keystone import Ks, KS_ARCH_ARM, KS_MODE_ARM, KS_MODE_THUMB |
9 | 9 |
|
| 10 | +from contextlib import ContextDecorator |
| 11 | + |
10 | 12 | from qiling.const import QL_VERBOSE |
11 | 13 | from qiling.exception import QlErrorNotImplemented |
12 | 14 |
|
13 | 15 | from .arm import QlArchARM |
14 | 16 | from .arm_const import IRQ, EXC_RETURN, CONTROL, EXCP |
15 | 17 |
|
| 18 | +class QlInterruptContext(ContextDecorator): |
| 19 | + def __init__(self, ql): |
| 20 | + self.ql = ql |
| 21 | + self.reg_context = ['xpsr', 'pc', 'lr', 'r12', 'r3', 'r2', 'r1', 'r0'] |
| 22 | + |
| 23 | + def __enter__(self): |
| 24 | + for reg in self.reg_context: |
| 25 | + val = self.ql.reg.read(reg) |
| 26 | + self.ql.arch.stack_push(val) |
| 27 | + |
| 28 | + if self.ql.verbose >= QL_VERBOSE.DISASM: |
| 29 | + self.ql.log.info(f'Enter into interrupt') |
| 30 | + |
| 31 | + def __exit__(self, *exc): |
| 32 | + retval = self.ql.arch.get_pc() |
| 33 | + |
| 34 | + if retval & EXC_RETURN.MASK != EXC_RETURN.MASK: |
| 35 | + self.ql.log.warning('Interrupt Crash') |
| 36 | + self.ql.stop() |
| 37 | + |
| 38 | + else: |
| 39 | + # Exit handler mode |
| 40 | + self.ql.reg.write('ipsr', 0) |
| 41 | + |
| 42 | + # switch the stack accroding exc_return |
| 43 | + old_ctrl = self.ql.reg.read('control') |
| 44 | + if retval & EXC_RETURN.RETURN_SP: |
| 45 | + self.ql.reg.write('control', old_ctrl | CONTROL.SPSEL) |
| 46 | + else: |
| 47 | + self.ql.reg.write('control', old_ctrl & ~CONTROL.SPSEL) |
| 48 | + |
| 49 | + # Restore stack |
| 50 | + for reg in reversed(self.reg_context): |
| 51 | + val = self.ql.arch.stack_pop() |
| 52 | + if reg == 'xpsr': |
| 53 | + self.ql.reg.write('XPSR_NZCVQG', val) |
| 54 | + else: |
| 55 | + self.ql.reg.write(reg, val) |
| 56 | + |
| 57 | + if self.ql.verbose >= QL_VERBOSE.DISASM: |
| 58 | + self.ql.log.info('Exit from interrupt') |
16 | 59 |
|
17 | 60 | class QlArchCORTEX_M(QlArchARM): |
18 | 61 | def __init__(self, ql): |
19 | 62 | super().__init__(ql) |
20 | 63 |
|
21 | | - self.reg_context = ['xpsr', 'pc', 'lr', 'r12', 'r3', 'r2', 'r1', 'r0'] |
22 | | - |
23 | 64 | def intr_cb(ql, intno): |
24 | 65 | if intno == EXCP.SWI: |
25 | 66 | ql.hw.nvic.set_pending(IRQ.SVCALL) |
@@ -48,78 +89,51 @@ def step(self): |
48 | 89 | self.ql.emu_start(self.get_pc(), 0, count=1) |
49 | 90 | self.ql.hw.step() |
50 | 91 |
|
| 92 | + def stop(self): |
| 93 | + self.runable = False |
| 94 | + |
51 | 95 | def run(self, count=-1, end=None): |
| 96 | + self.runable = True |
| 97 | + |
52 | 98 | if type(end) is int: |
53 | | - end |= 1 |
| 99 | + end |= 1 |
54 | 100 |
|
55 | | - while count != 0: |
| 101 | + while self.runable and count != 0: |
56 | 102 | if self.get_pc() == end: |
57 | 103 | break |
58 | 104 |
|
59 | 105 | self.step() |
60 | | - count -= 1 |
| 106 | + count -= 1 |
61 | 107 |
|
62 | 108 | def is_handler_mode(self): |
63 | 109 | return self.ql.reg.read('ipsr') > 1 |
64 | 110 |
|
65 | 111 | def using_psp(self): |
66 | 112 | return not self.is_handler_mode() and (self.ql.reg.read('control') & CONTROL.SPSEL) > 0 |
67 | 113 |
|
68 | | - def enter_intr(self): |
69 | | - # Save Stack |
70 | | - for reg in self.reg_context: |
71 | | - val = self.ql.reg.read(reg) |
72 | | - self.ql.arch.stack_push(val) |
73 | | - |
74 | | - if self.ql.verbose >= QL_VERBOSE.DISASM: |
75 | | - self.ql.log.info(f'Enter into interrupt') |
76 | | - |
77 | | - def exit_intr(self): |
78 | | - # Exit handler mode |
79 | | - self.ql.reg.write('ipsr', 0) |
80 | | - |
81 | | - # switch the stack accroding exc_return |
82 | | - old_ctrl = self.ql.reg.read('control') |
83 | | - if self.ql.arch.get_pc() & EXC_RETURN.RETURN_SP: |
84 | | - self.ql.reg.write('control', old_ctrl | CONTROL.SPSEL) |
85 | | - else: |
86 | | - self.ql.reg.write('control', old_ctrl & ~CONTROL.SPSEL) |
87 | | - |
88 | | - # Restore stack |
89 | | - for reg in reversed(self.reg_context): |
90 | | - val = self.ql.arch.stack_pop() |
91 | | - if reg == 'xpsr': |
92 | | - self.ql.reg.write('XPSR_NZCVQG', val) |
93 | | - else: |
94 | | - self.ql.reg.write(reg, val) |
95 | | - |
96 | | - if self.ql.verbose >= QL_VERBOSE.DISASM: |
97 | | - self.ql.log.info('Exit from interrupt') |
| 114 | + def handle_interupt(self, IRQn): |
| 115 | + basepri = self.ql.reg.read('basepri') & 0xf0 |
| 116 | + if basepri and basepri <= self.ql.hw.nvic.get_priority(IRQn): |
| 117 | + return |
98 | 118 |
|
99 | | - def handle_interupt(self, IRQn): |
100 | 119 | if IRQn > IRQ.HARD_FAULT and (self.ql.reg.read('primask') & 0x1): |
101 | 120 | return |
102 | | - |
| 121 | + |
103 | 122 | if IRQn != IRQ.NMI and (self.ql.reg.read('faultmask') & 0x1): |
104 | 123 | return |
105 | 124 |
|
106 | | - basepri = self.ql.reg.read('basepri') & 0xf0 |
107 | | - if basepri != 0 and basepri <= self.ql.hw.nvic.get_priority(IRQn): |
108 | | - return |
109 | | - |
110 | 125 | if self.ql.verbose >= QL_VERBOSE.DISASM: |
111 | | - self.ql.log.info(f'Handle the IRQn: {IRQn}') |
112 | | - |
113 | | - isr = IRQn + 16 |
114 | | - offset = isr << 2 |
115 | | - |
116 | | - entry = self.ql.mem.read_ptr(offset) |
117 | | - exc_return = 0xFFFFFFFD if self.ql.arch.using_psp() else 0xFFFFFFF9 |
| 126 | + self.ql.log.debug(f'Handle the IRQn: {IRQn}') |
| 127 | + |
| 128 | + with QlInterruptContext(self.ql): |
| 129 | + isr = IRQn + 16 |
| 130 | + offset = isr * 4 |
118 | 131 |
|
119 | | - # Enter handler mode |
120 | | - self.ql.reg.write('ipsr', isr) |
| 132 | + entry = self.ql.mem.read_ptr(offset) |
| 133 | + exc_return = 0xFFFFFFFD if self.ql.arch.using_psp() else 0xFFFFFFF9 |
121 | 134 |
|
122 | | - self.ql.reg.write('pc', entry) |
123 | | - self.ql.reg.write('lr', exc_return) |
| 135 | + self.ql.reg.write('ipsr', isr) |
| 136 | + self.ql.reg.write('pc', entry) |
| 137 | + self.ql.reg.write('lr', exc_return) |
124 | 138 |
|
125 | | - self.ql.emu_start(self.ql.arch.get_pc(), 0) |
| 139 | + self.ql.emu_start(self.ql.arch.get_pc(), 0, count=0xffffff) |
0 commit comments