summaryrefslogtreecommitdiff
path: root/src/arch/arm/interrupts.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch/arm/interrupts.cc')
-rw-r--r--src/arch/arm/interrupts.cc121
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);
+}
+