Skip to content

Commit 8fb73ef

Browse files
Merge pull request #968 from cla7aye15I4nd/dev
Refactor the peripheral logger mechanism and handle the interrupt crash
2 parents bae4eec + 0cf8ecd commit 8fb73ef

File tree

15 files changed

+152
-94
lines changed

15 files changed

+152
-94
lines changed

qiling/arch/arm_const.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ class CONTROL(IntEnum):
6868
PRIV = 0b001
6969

7070
class EXC_RETURN(IntEnum):
71+
MASK = 0xfffffff0
7172
RETURN_SP = 0b0100
7273
RETURN_MODE = 0b1000
7374

qiling/arch/cortex_m.py

Lines changed: 67 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,60 @@
77
from capstone import Cs, CS_ARCH_ARM, CS_MODE_ARM, CS_MODE_MCLASS, CS_MODE_THUMB
88
from keystone import Ks, KS_ARCH_ARM, KS_MODE_ARM, KS_MODE_THUMB
99

10+
from contextlib import ContextDecorator
11+
1012
from qiling.const import QL_VERBOSE
1113
from qiling.exception import QlErrorNotImplemented
1214

1315
from .arm import QlArchARM
1416
from .arm_const import IRQ, EXC_RETURN, CONTROL, EXCP
1517

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')
1659

1760
class QlArchCORTEX_M(QlArchARM):
1861
def __init__(self, ql):
1962
super().__init__(ql)
2063

21-
self.reg_context = ['xpsr', 'pc', 'lr', 'r12', 'r3', 'r2', 'r1', 'r0']
22-
2364
def intr_cb(ql, intno):
2465
if intno == EXCP.SWI:
2566
ql.hw.nvic.set_pending(IRQ.SVCALL)
@@ -48,78 +89,51 @@ def step(self):
4889
self.ql.emu_start(self.get_pc(), 0, count=1)
4990
self.ql.hw.step()
5091

92+
def stop(self):
93+
self.runable = False
94+
5195
def run(self, count=-1, end=None):
96+
self.runable = True
97+
5298
if type(end) is int:
53-
end |= 1
99+
end |= 1
54100

55-
while count != 0:
101+
while self.runable and count != 0:
56102
if self.get_pc() == end:
57103
break
58104

59105
self.step()
60-
count -= 1
106+
count -= 1
61107

62108
def is_handler_mode(self):
63109
return self.ql.reg.read('ipsr') > 1
64110

65111
def using_psp(self):
66112
return not self.is_handler_mode() and (self.ql.reg.read('control') & CONTROL.SPSEL) > 0
67113

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
98118

99-
def handle_interupt(self, IRQn):
100119
if IRQn > IRQ.HARD_FAULT and (self.ql.reg.read('primask') & 0x1):
101120
return
102-
121+
103122
if IRQn != IRQ.NMI and (self.ql.reg.read('faultmask') & 0x1):
104123
return
105124

106-
basepri = self.ql.reg.read('basepri') & 0xf0
107-
if basepri != 0 and basepri <= self.ql.hw.nvic.get_priority(IRQn):
108-
return
109-
110125
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
118131

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
121134

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)
124138

125-
self.ql.emu_start(self.ql.arch.get_pc(), 0)
139+
self.ql.emu_start(self.ql.arch.get_pc(), 0, count=0xffffff)

qiling/core.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -859,8 +859,12 @@ def emu_stop(self):
859859
def stop(self):
860860
if self.multithread:
861861
self.os.thread_management.stop()
862+
863+
elif self.archtype in QL_ARCH_HARDWARE:
864+
self.arch.stop()
865+
862866
else:
863-
self.uc.emu_stop()
867+
self.uc.emu_stop()
864868

865869
# start emulation
866870
def emu_start(self, begin, end, timeout=0, count=0):

qiling/hw/char/stm32f4xx_usart.py

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ def __init__(self, ql, label, intn=None):
5959
self.recv_buf = bytearray()
6060
self.send_buf = bytearray()
6161

62+
@QlPeripheral.read_debug
6263
def read(self, offset: int, size: int) -> int:
6364
buf = ctypes.create_string_buffer(size)
6465
ctypes.memmove(buf, ctypes.addressof(self.usart) + offset, size)
@@ -69,26 +70,36 @@ def read(self, offset: int, size: int) -> int:
6970

7071
return retval
7172

72-
def write(self, offset: int, size: int, value: int):
73+
@QlPeripheral.write_debug
74+
def write(self, offset: int, size: int, value: int):
7375
if offset == self.struct.SR.offset:
7476
self.usart.SR &= value | USART_SR.CTS | USART_SR.LBD | USART_SR.TC | USART_SR.RXNE
7577

7678
elif offset == self.struct.DR.offset:
77-
self.transfer(value & 0xff)
78-
self.usart.SR |= USART_SR.TC
79+
self.usart.SR &= ~USART_SR.TXE
80+
self.usart.DR = value
7981

8082
else:
8183
data = (value).to_bytes(size, byteorder='little')
8284
ctypes.memmove(ctypes.addressof(self.usart) + offset, data, size)
8385

84-
def transfer(self, value: int):
85-
""" transfer data to buffer
86-
87-
Args:
88-
value (int): transfer data
86+
def transfer(self):
87+
""" transfer data from DR to shift buffer and
88+
receive data from user buffer into DR
8989
"""
90-
self.send_buf.append(value)
91-
self.ql.log.debug(f'[{self.label}] Send {repr(chr(value))}')
90+
91+
if not (self.usart.SR & USART_SR.TXE):
92+
data = self.usart.DR
93+
94+
self.usart.SR |= USART_SR.TXE
95+
self.send_buf.append(data)
96+
97+
if not (self.usart.SR & USART_SR.RXNE):
98+
# TXE bit must had been cleared
99+
if self.recv_buf:
100+
self.usart.SR |= USART_SR.RXNE
101+
self.usart.DR = self.recv_buf.pop(0)
102+
92103

93104
def send(self, data: bytes):
94105
""" send user data into USART.
@@ -109,13 +120,7 @@ def recv(self) -> bytes:
109120
return data
110121

111122
def step(self):
112-
if not (self.usart.SR & USART_SR.RXNE):
113-
if self.recv_buf:
114-
self.usart.SR |= USART_SR.RXNE
115-
self.usart.DR = self.recv_buf.pop(0)
116-
117-
if not (self.usart.SR & USART_SR.TXE):
118-
self.usart.SR |= USART_SR.TXE
123+
self.transfer()
119124

120125
if self.intn is not None:
121126
if (self.usart.CR1 & USART_CR1.PEIE and self.usart.SR & USART_SR.PE) or \

qiling/hw/gpio/stm32f4xx_gpio.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ def __init__(self, ql, label,
6464
PUPDR = pupdr_reset,
6565
)
6666

67+
@QlPeripheral.read_debug
6768
def read(self, offset: int, size: int) -> int:
6869
if offset == self.struct.BSRR.offset:
6970
return 0x00
@@ -72,6 +73,7 @@ def read(self, offset: int, size: int) -> int:
7273
ctypes.memmove(buf, ctypes.addressof(self.gpio) + offset, size)
7374
return int.from_bytes(buf.raw, byteorder='little')
7475

76+
@QlPeripheral.write_debug
7577
def write(self, offset: int, size: int, value: int):
7678
if offset == self.struct.IDR.offset:
7779
return

qiling/hw/i2c/stm32f4xx_i2c.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,13 @@ def reset(self):
6262
TRISE = 0x0002
6363
)
6464

65-
def read(self, offset: int, size: int) -> int:
66-
self.ql.log.debug(f'[{self.label.upper()}] [R] {self.find_field(offset, size):10s}')
67-
65+
@QlPeripheral.read_debug
66+
def read(self, offset: int, size: int) -> int:
6867
buf = ctypes.create_string_buffer(size)
6968
ctypes.memmove(buf, ctypes.addressof(self.i2c) + offset, size)
7069
return int.from_bytes(buf.raw, byteorder='little')
7170

71+
@QlPeripheral.write_debug
7272
def write(self, offset: int, size: int, value: int):
7373
self.ql.log.debug(f'[{self.label.upper()}] [W] {self.find_field(offset, size):10s} = {hex(value)}')
7474

qiling/hw/intc/cm4_nvic.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,15 +111,15 @@ def step(self):
111111
while self.intrs:
112112
IRQn = self.intrs.pop(0)
113113
self.clear_pending(IRQn)
114-
self.ql.arch.enter_intr()
115-
self.ql.arch.handle_interupt(IRQn)
116-
self.ql.arch.exit_intr()
114+
self.ql.arch.handle_interupt(IRQn)
117115

116+
@QlPeripheral.read_debug
118117
def read(self, offset: int, size: int) -> int:
119118
buf = ctypes.create_string_buffer(size)
120119
ctypes.memmove(buf, ctypes.addressof(self.nvic) + offset, size)
121120
return int.from_bytes(buf.raw, byteorder='little')
122121

122+
@QlPeripheral.write_debug
123123
def write(self, offset: int, size: int, value: int):
124124
def write_byte(ofs, byte):
125125
for var, func in self.triggers:

qiling/hw/misc/cm4_scb.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,11 +117,13 @@ def get_pending(self, IRQn):
117117
def get_priority(self, IRQn):
118118
return self.scb.SHP[(IRQn & 0xf) - 4]
119119

120+
@QlPeripheral.read_debug
120121
def read(self, offset: int, size: int) -> int:
121122
buf = ctypes.create_string_buffer(size)
122123
ctypes.memmove(buf, ctypes.addressof(self.scb) + offset, size)
123124
return int.from_bytes(buf.raw, byteorder='little')
124125

126+
@QlPeripheral.write_debug
125127
def write(self, offset: int, size: int, value: int):
126128
if offset == self.struct.ICSR.offset:
127129
if (value >> 28) & 1:

qiling/hw/misc/stm32f4xx_rcc.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,16 +79,14 @@ def __init__(self, ql, label, intn=None):
7979

8080
self.intn = intn
8181

82-
def read(self, offset: int, size: int) -> int:
83-
self.ql.log.debug(f'[{self.label.upper()}] [R] {self.find_field(offset, size):10s}')
84-
82+
@QlPeripheral.read_debug
83+
def read(self, offset: int, size: int) -> int:
8584
buf = ctypes.create_string_buffer(size)
8685
ctypes.memmove(buf, ctypes.addressof(self.rcc) + offset, size)
8786
return int.from_bytes(buf.raw, byteorder='little')
8887

88+
@QlPeripheral.write_debug
8989
def write(self, offset: int, size: int, value: int):
90-
self.ql.log.debug(f'[{self.label.upper()}] [W] {self.find_field(offset, size):10s} = {hex(value)}')
91-
9290
if offset == self.struct.CR.offset:
9391
value = (self.rcc.CR & RCC_CR.RO_MASK) | (value & RCC_CR.RW_MASK)
9492
elif offset == self.struct.CFGR.offset:

0 commit comments

Comments
 (0)