diff options
author | ARM gem5 Developers <none@none> | 2014-01-24 15:29:34 -0600 |
---|---|---|
committer | ARM gem5 Developers <none@none> | 2014-01-24 15:29:34 -0600 |
commit | 612f8f074fa1099cf70faf495d46cc647762a031 (patch) | |
tree | bd1e99c43bf15292395eadd4b7ae3f5c823545c3 /src/arch/arm/interrupts.hh | |
parent | f3585c841e964c98911784a187fc4f081a02a0a6 (diff) | |
download | gem5-612f8f074fa1099cf70faf495d46cc647762a031.tar.xz |
arm: Add support for ARMv8 (AArch64 & AArch32)
Note: AArch64 and AArch32 interworking is not supported. If you use an AArch64
kernel you are restricted to AArch64 user-mode binaries. This will be addressed
in a later patch.
Note: Virtualization is only supported in AArch32 mode. This will also be fixed
in a later patch.
Contributors:
Giacomo Gabrielli (TrustZone, LPAE, system-level AArch64, AArch64 NEON, validation)
Thomas Grocutt (AArch32 Virtualization, AArch64 FP, validation)
Mbou Eyole (AArch64 NEON, validation)
Ali Saidi (AArch64 Linux support, code integration, validation)
Edmund Grimley-Evans (AArch64 FP)
William Wang (AArch64 Linux support)
Rene De Jong (AArch64 Linux support, performance opt.)
Matt Horsnell (AArch64 MP, validation)
Matt Evans (device models, code integration, validation)
Chris Adeniyi-Jones (AArch64 syscall-emulation)
Prakash Ramrakhyani (validation)
Dam Sunwoo (validation)
Chander Sudanthi (validation)
Stephan Diestelhorst (validation)
Andreas Hansson (code integration, performance opt.)
Eric Van Hensbergen (performance opt.)
Gabe Black
Diffstat (limited to 'src/arch/arm/interrupts.hh')
-rw-r--r-- | src/arch/arm/interrupts.hh | 112 |
1 files changed, 92 insertions, 20 deletions
diff --git a/src/arch/arm/interrupts.hh b/src/arch/arm/interrupts.hh index 7def6ddd6..8e6c2b261 100644 --- a/src/arch/arm/interrupts.hh +++ b/src/arch/arm/interrupts.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010,2012 ARM Limited + * Copyright (c) 2010, 2012-2013 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -47,6 +47,7 @@ #include "arch/arm/isa_traits.hh" #include "arch/arm/miscregs.hh" #include "arch/arm/registers.hh" +#include "arch/arm/utility.hh" #include "cpu/thread_context.hh" #include "debug/Interrupt.hh" #include "params/ArmInterrupts.hh" @@ -123,31 +124,79 @@ class Interrupts : public SimObject memset(interrupts, 0, sizeof(interrupts)); } + enum InterruptMask { + INT_MASK_M, // masked (subject to PSTATE.{A,I,F} mask bit + INT_MASK_T, // taken regardless of mask + INT_MASK_P // pending + }; + + bool takeInt(ThreadContext *tc, InterruptTypes int_type) const; + bool checkInterrupts(ThreadContext *tc) const { - if (!intStatus) + HCR hcr = tc->readMiscReg(MISCREG_HCR); + + if (!(intStatus || hcr.va || hcr.vi || hcr.vf)) return false; CPSR cpsr = tc->readMiscReg(MISCREG_CPSR); - - return ((interrupts[INT_IRQ] && !cpsr.i) || - (interrupts[INT_FIQ] && !cpsr.f) || - (interrupts[INT_ABT] && !cpsr.a) || - (interrupts[INT_RST]) || - (interrupts[INT_SEV])); + SCR scr = tc->readMiscReg(MISCREG_SCR); + + bool isHypMode = cpsr.mode == MODE_HYP; + bool isSecure = inSecureState(scr, cpsr); + bool allowVIrq = !cpsr.i && hcr.imo && !isSecure && !isHypMode; + bool allowVFiq = !cpsr.f && hcr.fmo && !isSecure && !isHypMode; + bool allowVAbort = !cpsr.a && hcr.amo && !isSecure && !isHypMode; + + bool take_irq = takeInt(tc, INT_IRQ); + bool take_fiq = takeInt(tc, INT_FIQ); + bool take_ea = takeInt(tc, INT_ABT); + + return ((interrupts[INT_IRQ] && take_irq) || + (interrupts[INT_FIQ] && take_fiq) || + (interrupts[INT_ABT] && take_ea) || + ((interrupts[INT_VIRT_IRQ] || hcr.vi) && allowVIrq) || + ((interrupts[INT_VIRT_FIQ] || hcr.vf) && allowVFiq) || + (hcr.va && allowVAbort) || + (interrupts[INT_RST]) || + (interrupts[INT_SEV]) + ); } /** - * Check the raw interrupt state. * This function is used to check if a wfi operation should sleep. If there * is an interrupt pending, even if it's masked, wfi doesn't sleep. * @return any interrupts pending */ bool - checkRaw() const + checkWfiWake(HCR hcr, CPSR cpsr, SCR scr) const + { + uint64_t maskedIntStatus; + bool virtWake; + + maskedIntStatus = intStatus & ~((1 << INT_VIRT_IRQ) | + (1 << INT_VIRT_FIQ)); + virtWake = (hcr.vi || interrupts[INT_VIRT_IRQ]) && hcr.imo; + virtWake |= (hcr.vf || interrupts[INT_VIRT_FIQ]) && hcr.fmo; + virtWake |= hcr.va && hcr.amo; + virtWake &= (cpsr.mode != MODE_HYP) && !inSecureState(scr, cpsr); + return maskedIntStatus || virtWake; + } + + uint32_t + getISR(HCR hcr, CPSR cpsr, SCR scr) { - return intStatus; + bool useHcrMux; + CPSR isr = 0; // ARM ARM states ISR reg uses same bit possitions as CPSR + + useHcrMux = (cpsr.mode != MODE_HYP) && !inSecureState(scr, cpsr); + isr.i = (useHcrMux & hcr.imo) ? (interrupts[INT_VIRT_IRQ] || hcr.vi) + : interrupts[INT_IRQ]; + isr.f = (useHcrMux & hcr.fmo) ? (interrupts[INT_VIRT_FIQ] || hcr.vf) + : interrupts[INT_FIQ]; + isr.a = (useHcrMux & hcr.amo) ? hcr.va : interrupts[INT_ABT]; + return isr; } /** @@ -172,22 +221,45 @@ class Interrupts : public SimObject Fault getInterrupt(ThreadContext *tc) { - if (!intStatus) + HCR hcr = tc->readMiscReg(MISCREG_HCR); + CPSR cpsr = tc->readMiscReg(MISCREG_CPSR); + SCR scr = tc->readMiscReg(MISCREG_SCR); + + // Calculate a few temp vars so we can work out if there's a pending + // virtual interrupt, and if its allowed to happen + // ARM ARM Issue C section B1.9.9, B1.9.11, and B1.9.13 + bool isHypMode = cpsr.mode == MODE_HYP; + bool isSecure = inSecureState(scr, cpsr); + bool allowVIrq = !cpsr.i && hcr.imo && !isSecure && !isHypMode; + bool allowVFiq = !cpsr.f && hcr.fmo && !isSecure && !isHypMode; + bool allowVAbort = !cpsr.a && hcr.amo && !isSecure && !isHypMode; + + if ( !(intStatus || (hcr.vi && allowVIrq) || (hcr.vf && allowVFiq) || + (hcr.va && allowVAbort)) ) return NoFault; - CPSR cpsr = tc->readMiscReg(MISCREG_CPSR); + bool take_irq = takeInt(tc, INT_IRQ); + bool take_fiq = takeInt(tc, INT_FIQ); + bool take_ea = takeInt(tc, INT_ABT); + - if (interrupts[INT_IRQ] && !cpsr.i) + if (interrupts[INT_IRQ] && take_irq) return new Interrupt; - if (interrupts[INT_FIQ] && !cpsr.f) + if ((interrupts[INT_VIRT_IRQ] || hcr.vi) && allowVIrq) + return new VirtualInterrupt; + if (interrupts[INT_FIQ] && take_fiq) return new FastInterrupt; - if (interrupts[INT_ABT] && !cpsr.a) - return new DataAbort(0, false, 0, - ArmFault::AsynchronousExternalAbort); + if ((interrupts[INT_VIRT_FIQ] || hcr.vf) && allowVFiq) + return new VirtualFastInterrupt; + if (interrupts[INT_ABT] && take_ea) + return new SystemError; + if (hcr.va && allowVAbort) + return new VirtualDataAbort(0, TlbEntry::DomainType::NoAccess, false, + ArmFault::AsynchronousExternalAbort); if (interrupts[INT_RST]) - return new Reset; + return new Reset; if (interrupts[INT_SEV]) - return new ArmSev; + return new ArmSev; panic("intStatus and interrupts not in sync\n"); } |