13537SN/A/*
211581SDylan.Johnson@ARM.com * Copyright (c) 2010, 2012-2013, 2016 ARM Limited
37400SAli.Saidi@ARM.com * All rights reserved
47400SAli.Saidi@ARM.com *
57400SAli.Saidi@ARM.com * The license below extends only to copyright in the software and shall
67400SAli.Saidi@ARM.com * not be construed as granting a license to any other intellectual
77400SAli.Saidi@ARM.com * property including but not limited to intellectual property relating
87400SAli.Saidi@ARM.com * to a hardware implementation of the functionality of the software
97400SAli.Saidi@ARM.com * licensed hereunder.  You may use the software subject to the license
107400SAli.Saidi@ARM.com * terms below provided that you ensure that this notice is replicated
117400SAli.Saidi@ARM.com * unmodified and in its entirety in all distributions of the software,
127400SAli.Saidi@ARM.com * modified or unmodified, in source code or in binary form.
137400SAli.Saidi@ARM.com *
143537SN/A * Copyright (c) 2006 The Regents of The University of Michigan
153537SN/A * All rights reserved.
163537SN/A *
173537SN/A * Redistribution and use in source and binary forms, with or without
183537SN/A * modification, are permitted provided that the following conditions are
193537SN/A * met: redistributions of source code must retain the above copyright
203537SN/A * notice, this list of conditions and the following disclaimer;
213537SN/A * redistributions in binary form must reproduce the above copyright
223537SN/A * notice, this list of conditions and the following disclaimer in the
233537SN/A * documentation and/or other materials provided with the distribution;
243537SN/A * neither the name of the copyright holders nor the names of its
253537SN/A * contributors may be used to endorse or promote products derived from
263537SN/A * this software without specific prior written permission.
273537SN/A *
283537SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
293537SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
303537SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
313537SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
323537SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
333537SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
343537SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
353537SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
363537SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
373537SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
383537SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
394103SN/A *
404103SN/A * Authors: Ali Saidi
413537SN/A */
423537SN/A
436757SAli.Saidi@ARM.com#ifndef __ARCH_ARM_INTERRUPT_HH__
446757SAli.Saidi@ARM.com#define __ARCH_ARM_INTERRUPT_HH__
453537SN/A
466757SAli.Saidi@ARM.com#include "arch/arm/faults.hh"
476757SAli.Saidi@ARM.com#include "arch/arm/isa_traits.hh"
487400SAli.Saidi@ARM.com#include "arch/arm/miscregs.hh"
496757SAli.Saidi@ARM.com#include "arch/arm/registers.hh"
5010037SARM gem5 Developers#include "arch/arm/utility.hh"
513827SN/A#include "cpu/thread_context.hh"
528245Snate@binkert.org#include "debug/Interrupt.hh"
536757SAli.Saidi@ARM.com#include "params/ArmInterrupts.hh"
545647SN/A#include "sim/sim_object.hh"
553827SN/A
566757SAli.Saidi@ARM.comnamespace ArmISA
573537SN/A{
583894SN/A
595647SN/Aclass Interrupts : public SimObject
604009SN/A{
615810SN/A  private:
625810SN/A    BaseCPU * cpu;
634009SN/A
647400SAli.Saidi@ARM.com    bool interrupts[NumInterruptTypes];
654103SN/A    uint64_t intStatus;
664009SN/A
674009SN/A  public:
685810SN/A
695810SN/A    void
705810SN/A    setCPU(BaseCPU * _cpu)
715810SN/A    {
725810SN/A        cpu = _cpu;
735810SN/A    }
745810SN/A
756757SAli.Saidi@ARM.com    typedef ArmInterruptsParams Params;
765647SN/A
775647SN/A    const Params *
785647SN/A    params() const
795647SN/A    {
805647SN/A        return dynamic_cast<const Params *>(_params);
815647SN/A    }
825647SN/A
835810SN/A    Interrupts(Params * p) : SimObject(p), cpu(NULL)
844009SN/A    {
855704SN/A        clearAll();
864009SN/A    }
874009SN/A
884009SN/A
895704SN/A    void
905704SN/A    post(int int_num, int index)
913537SN/A    {
927400SAli.Saidi@ARM.com        DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index);
937400SAli.Saidi@ARM.com
947400SAli.Saidi@ARM.com        if (int_num < 0 || int_num >= NumInterruptTypes)
957400SAli.Saidi@ARM.com            panic("int_num out of bounds\n");
967400SAli.Saidi@ARM.com
977400SAli.Saidi@ARM.com        if (index != 0)
987400SAli.Saidi@ARM.com            panic("No support for other interrupt indexes\n");
997400SAli.Saidi@ARM.com
1007400SAli.Saidi@ARM.com        interrupts[int_num] = true;
1017400SAli.Saidi@ARM.com        intStatus |= ULL(1) << int_num;
1024009SN/A    }
1033894SN/A
1045704SN/A    void
1055704SN/A    clear(int int_num, int index)
1064009SN/A    {
1077847Sminkyu.jeong@arm.com        DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index);
1087400SAli.Saidi@ARM.com
1097400SAli.Saidi@ARM.com        if (int_num < 0 || int_num >= NumInterruptTypes)
1107400SAli.Saidi@ARM.com            panic("int_num out of bounds\n");
1117400SAli.Saidi@ARM.com
1127400SAli.Saidi@ARM.com        if (index != 0)
1137400SAli.Saidi@ARM.com            panic("No support for other interrupt indexes\n");
1147400SAli.Saidi@ARM.com
1157400SAli.Saidi@ARM.com        interrupts[int_num] = false;
1167400SAli.Saidi@ARM.com        intStatus &= ~(ULL(1) << int_num);
1174009SN/A    }
1183827SN/A
1195704SN/A    void
1205704SN/A    clearAll()
1214009SN/A    {
1227400SAli.Saidi@ARM.com        DPRINTF(Interrupt, "Interrupts all cleared\n");
1234103SN/A        intStatus = 0;
1247400SAli.Saidi@ARM.com        memset(interrupts, 0, sizeof(interrupts));
1254009SN/A    }
1263537SN/A
12710037SARM gem5 Developers    enum InterruptMask {
12810037SARM gem5 Developers        INT_MASK_M, // masked (subject to PSTATE.{A,I,F} mask bit
12910037SARM gem5 Developers        INT_MASK_T, // taken regardless of mask
13010037SARM gem5 Developers        INT_MASK_P  // pending
13110037SARM gem5 Developers    };
13210037SARM gem5 Developers
13310037SARM gem5 Developers    bool takeInt(ThreadContext *tc, InterruptTypes int_type) const;
13410037SARM gem5 Developers
1355704SN/A    bool
1365704SN/A    checkInterrupts(ThreadContext *tc) const
1374009SN/A    {
13810037SARM gem5 Developers        HCR  hcr  = tc->readMiscReg(MISCREG_HCR);
13910037SARM gem5 Developers
14010037SARM gem5 Developers        if (!(intStatus || hcr.va || hcr.vi || hcr.vf))
1417400SAli.Saidi@ARM.com            return false;
1427400SAli.Saidi@ARM.com
1437400SAli.Saidi@ARM.com        CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
1447400SAli.Saidi@ARM.com
14513640Sgiacomo.travaglini@arm.com        bool isHypMode   = currEL(tc) == EL2;
14611581SDylan.Johnson@ARM.com        bool isSecure    = inSecureState(tc);
14710037SARM gem5 Developers        bool allowVIrq   = !cpsr.i && hcr.imo && !isSecure && !isHypMode;
14810037SARM gem5 Developers        bool allowVFiq   = !cpsr.f && hcr.fmo && !isSecure && !isHypMode;
14910037SARM gem5 Developers        bool allowVAbort = !cpsr.a && hcr.amo && !isSecure && !isHypMode;
15010037SARM gem5 Developers
15111566Smitch.hayenga@arm.com        if ( !(intStatus || (hcr.vi && allowVIrq) || (hcr.vf && allowVFiq) ||
15211566Smitch.hayenga@arm.com               (hcr.va && allowVAbort)) )
15311566Smitch.hayenga@arm.com            return false;
15411566Smitch.hayenga@arm.com
15510037SARM gem5 Developers        bool take_irq = takeInt(tc, INT_IRQ);
15610037SARM gem5 Developers        bool take_fiq = takeInt(tc, INT_FIQ);
15710037SARM gem5 Developers        bool take_ea =  takeInt(tc, INT_ABT);
15810037SARM gem5 Developers
15910037SARM gem5 Developers        return ((interrupts[INT_IRQ] && take_irq)                   ||
16010037SARM gem5 Developers                (interrupts[INT_FIQ] && take_fiq)                   ||
16110037SARM gem5 Developers                (interrupts[INT_ABT] && take_ea)                    ||
16210037SARM gem5 Developers                ((interrupts[INT_VIRT_IRQ] || hcr.vi) && allowVIrq) ||
16310037SARM gem5 Developers                ((interrupts[INT_VIRT_FIQ] || hcr.vf) && allowVFiq) ||
16410037SARM gem5 Developers                (hcr.va && allowVAbort)                             ||
16510037SARM gem5 Developers                (interrupts[INT_RST])                               ||
16610037SARM gem5 Developers                (interrupts[INT_SEV])
16710037SARM gem5 Developers               );
1684009SN/A    }
1693537SN/A
1708285SPrakash.Ramrakhyani@arm.com    /**
1718285SPrakash.Ramrakhyani@arm.com     * This function is used to check if a wfi operation should sleep. If there
1728285SPrakash.Ramrakhyani@arm.com     * is an interrupt pending, even if it's masked, wfi doesn't sleep.
1738285SPrakash.Ramrakhyani@arm.com     * @return any interrupts pending
1748285SPrakash.Ramrakhyani@arm.com     */
1758285SPrakash.Ramrakhyani@arm.com    bool
17610037SARM gem5 Developers    checkWfiWake(HCR hcr, CPSR cpsr, SCR scr) const
1778285SPrakash.Ramrakhyani@arm.com    {
17810037SARM gem5 Developers        uint64_t maskedIntStatus;
17910037SARM gem5 Developers        bool     virtWake;
18010037SARM gem5 Developers
18110037SARM gem5 Developers        maskedIntStatus = intStatus & ~((1 << INT_VIRT_IRQ) |
18210037SARM gem5 Developers                                        (1 << INT_VIRT_FIQ));
18310037SARM gem5 Developers        virtWake  = (hcr.vi || interrupts[INT_VIRT_IRQ]) && hcr.imo;
18410037SARM gem5 Developers        virtWake |= (hcr.vf || interrupts[INT_VIRT_FIQ]) && hcr.fmo;
18510037SARM gem5 Developers        virtWake |=  hcr.va                              && hcr.amo;
18610037SARM gem5 Developers        virtWake &= (cpsr.mode != MODE_HYP) && !inSecureState(scr, cpsr);
18710037SARM gem5 Developers        return maskedIntStatus || virtWake;
18810037SARM gem5 Developers    }
18910037SARM gem5 Developers
19010037SARM gem5 Developers    uint32_t
19110037SARM gem5 Developers    getISR(HCR hcr, CPSR cpsr, SCR scr)
19210037SARM gem5 Developers    {
19310037SARM gem5 Developers        bool useHcrMux;
19410037SARM gem5 Developers        CPSR isr = 0; // ARM ARM states ISR reg uses same bit possitions as CPSR
19510037SARM gem5 Developers
19610037SARM gem5 Developers        useHcrMux = (cpsr.mode != MODE_HYP) && !inSecureState(scr, cpsr);
19710037SARM gem5 Developers        isr.i = (useHcrMux & hcr.imo) ? (interrupts[INT_VIRT_IRQ] || hcr.vi)
19810037SARM gem5 Developers                                      :  interrupts[INT_IRQ];
19910037SARM gem5 Developers        isr.f = (useHcrMux & hcr.fmo) ? (interrupts[INT_VIRT_FIQ] || hcr.vf)
20010037SARM gem5 Developers                                      :  interrupts[INT_FIQ];
20110037SARM gem5 Developers        isr.a = (useHcrMux & hcr.amo) ?  hcr.va : interrupts[INT_ABT];
20210037SARM gem5 Developers        return isr;
2038285SPrakash.Ramrakhyani@arm.com    }
2048285SPrakash.Ramrakhyani@arm.com
2059656Sandreas.sandberg@arm.com    /**
2069656Sandreas.sandberg@arm.com     * Check the state of a particular interrupt, ignoring CPSR masks.
2079656Sandreas.sandberg@arm.com     *
2089656Sandreas.sandberg@arm.com     * This method is primarily used when running the target CPU in a
2099656Sandreas.sandberg@arm.com     * hardware VM (e.g., KVM) to check if interrupts should be
2109656Sandreas.sandberg@arm.com     * delivered upon guest entry.
2119656Sandreas.sandberg@arm.com     *
2129656Sandreas.sandberg@arm.com     * @param interrupt Interrupt type to check the state of.
2139656Sandreas.sandberg@arm.com     * @return true if the interrupt is asserted, false otherwise.
2149656Sandreas.sandberg@arm.com     */
2159656Sandreas.sandberg@arm.com    bool
2169656Sandreas.sandberg@arm.com    checkRaw(InterruptTypes interrupt) const
2179656Sandreas.sandberg@arm.com    {
2189656Sandreas.sandberg@arm.com        if (interrupt >= NumInterruptTypes)
2199656Sandreas.sandberg@arm.com            panic("Interrupt number out of range.\n");
2209656Sandreas.sandberg@arm.com
2219656Sandreas.sandberg@arm.com        return interrupts[interrupt];
2229656Sandreas.sandberg@arm.com    }
2238285SPrakash.Ramrakhyani@arm.com
2245704SN/A    Fault
2255704SN/A    getInterrupt(ThreadContext *tc)
2264009SN/A    {
22711566Smitch.hayenga@arm.com        assert(checkInterrupts(tc));
22811566Smitch.hayenga@arm.com
22910037SARM gem5 Developers        HCR  hcr  = tc->readMiscReg(MISCREG_HCR);
23010037SARM gem5 Developers        CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
23110037SARM gem5 Developers
23210037SARM gem5 Developers        // Calculate a few temp vars so we can work out if there's a pending
23310037SARM gem5 Developers        // virtual interrupt, and if its allowed to happen
23410037SARM gem5 Developers        // ARM ARM Issue C section B1.9.9, B1.9.11, and B1.9.13
23513640Sgiacomo.travaglini@arm.com        bool isHypMode   = currEL(tc) == EL2;
23611581SDylan.Johnson@ARM.com        bool isSecure    = inSecureState(tc);
23710037SARM gem5 Developers        bool allowVIrq   = !cpsr.i && hcr.imo && !isSecure && !isHypMode;
23810037SARM gem5 Developers        bool allowVFiq   = !cpsr.f && hcr.fmo && !isSecure && !isHypMode;
23910037SARM gem5 Developers        bool allowVAbort = !cpsr.a && hcr.amo && !isSecure && !isHypMode;
24010037SARM gem5 Developers
24110037SARM gem5 Developers        bool take_irq = takeInt(tc, INT_IRQ);
24210037SARM gem5 Developers        bool take_fiq = takeInt(tc, INT_FIQ);
24310037SARM gem5 Developers        bool take_ea =  takeInt(tc, INT_ABT);
2447400SAli.Saidi@ARM.com
24510037SARM gem5 Developers        if (interrupts[INT_IRQ] && take_irq)
24610474Sandreas.hansson@arm.com            return std::make_shared<Interrupt>();
24710037SARM gem5 Developers        if ((interrupts[INT_VIRT_IRQ] || hcr.vi) && allowVIrq)
24810474Sandreas.hansson@arm.com            return std::make_shared<VirtualInterrupt>();
24910037SARM gem5 Developers        if (interrupts[INT_FIQ] && take_fiq)
25010474Sandreas.hansson@arm.com            return std::make_shared<FastInterrupt>();
25110037SARM gem5 Developers        if ((interrupts[INT_VIRT_FIQ] || hcr.vf) && allowVFiq)
25210474Sandreas.hansson@arm.com            return std::make_shared<VirtualFastInterrupt>();
25310037SARM gem5 Developers        if (interrupts[INT_ABT] && take_ea)
25410474Sandreas.hansson@arm.com            return std::make_shared<SystemError>();
25510037SARM gem5 Developers        if (hcr.va && allowVAbort)
25610474Sandreas.hansson@arm.com            return std::make_shared<VirtualDataAbort>(
25710474Sandreas.hansson@arm.com                0, TlbEntry::DomainType::NoAccess, false,
25810474Sandreas.hansson@arm.com                ArmFault::AsynchronousExternalAbort);
2597400SAli.Saidi@ARM.com        if (interrupts[INT_RST])
26010474Sandreas.hansson@arm.com            return std::make_shared<Reset>();
2618518Sgeoffrey.blake@arm.com        if (interrupts[INT_SEV])
26210474Sandreas.hansson@arm.com            return std::make_shared<ArmSev>();
2637400SAli.Saidi@ARM.com
2647400SAli.Saidi@ARM.com        panic("intStatus and interrupts not in sync\n");
2654009SN/A    }
2663537SN/A
2675704SN/A    void
2685704SN/A    updateIntrInfo(ThreadContext *tc)
2694009SN/A    {
2707400SAli.Saidi@ARM.com        ; // nothing to do
2714009SN/A    }
2723654SN/A
2735704SN/A    void
27410905Sandreas.sandberg@arm.com    serialize(CheckpointOut &cp) const
2754009SN/A    {
2767400SAli.Saidi@ARM.com        SERIALIZE_ARRAY(interrupts, NumInterruptTypes);
2777400SAli.Saidi@ARM.com        SERIALIZE_SCALAR(intStatus);
2784009SN/A    }
2793537SN/A
2805704SN/A    void
28110905Sandreas.sandberg@arm.com    unserialize(CheckpointIn &cp)
2824009SN/A    {
2837400SAli.Saidi@ARM.com        UNSERIALIZE_ARRAY(interrupts, NumInterruptTypes);
2847400SAli.Saidi@ARM.com        UNSERIALIZE_SCALAR(intStatus);
2854009SN/A    }
2864009SN/A};
2876757SAli.Saidi@ARM.com} // namespace ARM_ISA
2883537SN/A
2896757SAli.Saidi@ARM.com#endif // __ARCH_ARM_INTERRUPT_HH__
290