diff options
Diffstat (limited to 'src/arch/arm/interrupts.cc')
-rw-r--r-- | src/arch/arm/interrupts.cc | 121 |
1 files changed, 120 insertions, 1 deletions
diff --git a/src/arch/arm/interrupts.cc b/src/arch/arm/interrupts.cc index c05ae984e..6682b75a0 100644 --- a/src/arch/arm/interrupts.cc +++ b/src/arch/arm/interrupts.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009 ARM Limited + * Copyright (c) 2009, 2012-2013 ARM Limited * All rights reserved. * * The license below extends only to copyright in the software and shall @@ -38,9 +38,128 @@ */ #include "arch/arm/interrupts.hh" +#include "arch/arm/system.hh" ArmISA::Interrupts * ArmInterruptsParams::create() { return new ArmISA::Interrupts(this); } + +bool +ArmISA::Interrupts::takeInt(ThreadContext *tc, InterruptTypes int_type) const +{ + // Table G1-17~19 of ARM V8 ARM + InterruptMask mask; + bool highest_el_is_64 = ArmSystem::highestELIs64(tc); + + CPSR cpsr = tc->readMiscReg(MISCREG_CPSR); + SCR scr; + HCR hcr; + hcr = tc->readMiscReg(MISCREG_HCR); + ExceptionLevel el = (ExceptionLevel) ((uint32_t) cpsr.el); + bool cpsr_mask_bit, scr_routing_bit, scr_fwaw_bit, hcr_mask_override_bit; + + if (!highest_el_is_64) + scr = tc->readMiscReg(MISCREG_SCR); + else + scr = tc->readMiscReg(MISCREG_SCR_EL3); + + bool is_secure = inSecureState(scr, cpsr); + + switch(int_type) { + case INT_FIQ: + cpsr_mask_bit = cpsr.f; + scr_routing_bit = scr.fiq; + scr_fwaw_bit = scr.fw; + hcr_mask_override_bit = hcr.fmo; + break; + case INT_IRQ: + cpsr_mask_bit = cpsr.i; + scr_routing_bit = scr.irq; + scr_fwaw_bit = 1; + hcr_mask_override_bit = hcr.imo; + break; + case INT_ABT: + cpsr_mask_bit = cpsr.a; + scr_routing_bit = scr.ea; + scr_fwaw_bit = scr.aw; + hcr_mask_override_bit = hcr.amo; + break; + default: + panic("Unhandled interrupt type!"); + } + + if (hcr.tge) + hcr_mask_override_bit = 1; + + if (!highest_el_is_64) { + // AArch32 + if (!scr_routing_bit) { + // SCR IRQ == 0 + if (!hcr_mask_override_bit) + mask = INT_MASK_M; + else { + if (!is_secure && (el == EL0 || el == EL1)) + mask = INT_MASK_T; + else + mask = INT_MASK_M; + } + } else { + // SCR IRQ == 1 + if ((!is_secure) && + (hcr_mask_override_bit || + (!scr_fwaw_bit && !hcr_mask_override_bit))) + mask = INT_MASK_T; + else + mask = INT_MASK_M; + } + } else { + // AArch64 + if (!scr_routing_bit) { + // SCR IRQ == 0 + if (!scr.rw) { + // SCR RW == 0 + if (!hcr_mask_override_bit) { + if (el == EL3) + mask = INT_MASK_P; + else + mask = INT_MASK_M; + } else { + if (el == EL3) + mask = INT_MASK_T; + else if (is_secure || el == EL2) + mask = INT_MASK_M; + else + mask = INT_MASK_T; + } + } else { + // SCR RW == 1 + if (!hcr_mask_override_bit) { + if (el == EL3 || el == EL2) + mask = INT_MASK_P; + else + mask = INT_MASK_M; + } else { + if (el == EL3) + mask = INT_MASK_P; + else if (is_secure || el == EL2) + mask = INT_MASK_M; + else + mask = INT_MASK_T; + } + } + } else { + // SCR IRQ == 1 + if (el == EL3) + mask = INT_MASK_M; + else + mask = INT_MASK_T; + } + } + + return ((mask == INT_MASK_T) || + ((mask == INT_MASK_M) && !cpsr_mask_bit)) && + (mask != INT_MASK_P); +} + |