diff --git a/qiling/hw/intc/cm_nvic.py b/qiling/hw/intc/cm_nvic.py index 5470a4483..f6d0059c7 100644 --- a/qiling/hw/intc/cm_nvic.py +++ b/qiling/hw/intc/cm_nvic.py @@ -1,9 +1,10 @@ #!/usr/bin/env python3 -# +# # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # import ctypes +from qiling.arch.cortex_m_const import IRQ from qiling.hw.peripheral import QlPeripheral @@ -28,11 +29,11 @@ class Type(ctypes.Structure): def __init__(self, ql, label): super().__init__(ql, label) - + # reference: # https://www.youtube.com/watch?v=uFBNf7F3l60 - # https://developer.arm.com/documentation/ddi0439/b/Nested-Vectored-Interrupt-Controller - + # https://developer.arm.com/documentation/ddi0439/b/Nested-Vectored-Interrupt-Controller + self.instance = self.struct() ## The max number of interrupt request @@ -50,8 +51,8 @@ def __init__(self, ql, label): (self.struct.ICPR, self.clear_pending), ] - self.intrs = [] - self.interrupt_handler = self.ql.arch.interrupt_handler + self.intrs = [] + self.interrupt_handler = self.ql.arch.interrupt_handler def enable(self, IRQn): if IRQn >= 0: @@ -79,7 +80,7 @@ def set_pending(self, IRQn): self.instance.ICPR[IRQn >> self.OFFSET] |= 1 << (IRQn & self.MASK) else: self.ql.hw.scb.set_pending(IRQn) - + if self.get_enable(IRQn): self.intrs.append(IRQn) @@ -100,19 +101,33 @@ def get_priority(self, IRQn): if IRQn >= 0: return self.instance.IPR[IRQn] else: - return self.ql.hw.scb.get_priority(IRQn) - + return self.ql.hw.scb.get_priority(IRQn) + def step(self): if not self.intrs: return - self.intrs.sort(key=lambda x: self.get_priority(x)) - + self.intrs.sort(key=lambda x: self.get_priority(x)) + + postponed = [] + while self.intrs: IRQn = self.intrs.pop(0) + + basepri = self.ql.arch.regs.basepri & 0xF0 + if ( + (basepri and basepri <= self.get_priority(IRQn)) + or (IRQn > IRQ.HARD_FAULT and (self.ql.arch.regs.primask & 0x1)) + or (IRQn != IRQ.NMI and (self.ql.arch.regs.faultmask & 0x1)) + ): + postponed.append(IRQn) + continue + self.clear_pending(IRQn) self.interrupt_handler(self.ql, IRQn) + self.intrs = postponed + @QlPeripheral.monitor() def read(self, offset: int, size: int) -> int: buf = ctypes.create_string_buffer(size) @@ -132,8 +147,8 @@ def write_byte(ofs, byte): ipr = self.struct.IPR if ipr.offset <= ofs < ipr.offset + ipr.size: byte &= 0xf0 # IPR[3: 0] reserved - - ctypes.memmove(ctypes.addressof(self.instance) + ofs, bytes([byte]), 1) + + ctypes.memmove(ctypes.addressof(self.instance) + ofs, bytes([byte]), 1) for ofs in range(offset, offset + size): write_byte(ofs, value & 0xff) @@ -141,4 +156,4 @@ def write_byte(ofs, byte): @property def region(self): - return [(0, self.struct.RESERVED5.offset), (self.struct.STIR.offset, ctypes.sizeof(self.struct))] \ No newline at end of file + return [(0, self.struct.RESERVED5.offset), (self.struct.STIR.offset, ctypes.sizeof(self.struct))]