--- /dev/null
+# Copyright (c) 2012 ARM Limited
+# All rights reserved.
+#
+# The license below extends only to copyright in the software and shall
+# not be construed as granting a license to any other intellectual
+# property including but not limited to intellectual property relating
+# to a hardware implementation of the functionality of the software
+# licensed hereunder. You may use the software subject to the license
+# terms below provided that you ensure that this notice is replicated
+# unmodified and in its entirety in all distributions of the software,
+# modified or unmodified, in source code or in binary form.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors: Andreas Sandberg
+
+from m5.params import *
+from m5.proxy import *
+
+from Device import PioDevice
+from Platform import Platform
+
+class BaseGic(PioDevice):
+ type = 'BaseGic'
+ abstract = True
+ cxx_header = "dev/arm/base_gic.hh"
+
+ platform = Param.Platform(Parent.any, "Platform this device is part of.")
+
+class Pl390(BaseGic):
+ type = 'Pl390'
+ cxx_header = "dev/arm/gic_pl390.hh"
+
+ dist_addr = Param.Addr(0x1f001000, "Address for distributor")
+ cpu_addr = Param.Addr(0x1f000100, "Address for cpu")
+ dist_pio_delay = Param.Latency('10ns', "Delay for PIO r/w to distributor")
+ cpu_pio_delay = Param.Latency('10ns', "Delay for PIO r/w to cpu interface")
+ int_latency = Param.Latency('10ns', "Delay for interrupt to get to CPU")
+ it_lines = Param.UInt32(128, "Number of interrupt lines supported (max = 1020)")
+
from Terminal import Terminal
from Uart import Uart
from SimpleMemory import SimpleMemory
+from Gic import *
class AmbaDevice(BasicPioDevice):
type = 'AmbaDevice'
type = 'AmbaIntDevice'
abstract = True
cxx_header = "dev/arm/amba_device.hh"
- gic = Param.Gic(Parent.any, "Gic to use for interrupting")
+ gic = Param.BaseGic(Parent.any, "Gic to use for interrupting")
int_num = Param.UInt32("Interrupt number that connects to GIC")
int_delay = Param.Latency("100ns",
"Time between action and interrupt generation by device")
cxx_header = "dev/arm/amba_device.hh"
pio_addr = Param.Addr("Address for AMBA slave interface")
pio_latency = Param.Latency("10ns", "Time between action and write/read result by AMBA DMA Device")
- gic = Param.Gic(Parent.any, "Gic to use for interrupting")
+ gic = Param.BaseGic(Parent.any, "Gic to use for interrupting")
int_num = Param.UInt32("Interrupt number that connects to GIC")
amba_id = Param.UInt32("ID of AMBA device for kernel detection")
proc_id1 = Param.UInt32(0x0C000222, "Processor ID, SYS_PROCID1")
idreg = Param.UInt32(0x00000000, "ID Register, SYS_ID")
-class Gic(PioDevice):
- type = 'Gic'
- cxx_header = "dev/arm/gic.hh"
- platform = Param.Platform(Parent.any, "Platform this device is part of.")
- dist_addr = Param.Addr(0x1f001000, "Address for distributor")
- cpu_addr = Param.Addr(0x1f000100, "Address for cpu")
- dist_pio_delay = Param.Latency('10ns', "Delay for PIO r/w to distributor")
- cpu_pio_delay = Param.Latency('10ns', "Delay for PIO r/w to cpu interface")
- int_latency = Param.Latency('10ns', "Delay for interrupt to get to CPU")
- it_lines = Param.UInt32(128, "Number of interrupt lines supported (max = 1020)")
-
class AmbaFake(AmbaDevice):
type = 'AmbaFake'
cxx_header = "dev/arm/amba_fake.hh"
class Pl011(Uart):
type = 'Pl011'
cxx_header = "dev/arm/pl011.hh"
- gic = Param.Gic(Parent.any, "Gic to use for interrupting")
+ gic = Param.BaseGic(Parent.any, "Gic to use for interrupting")
int_num = Param.UInt32("Interrupt number that connects to GIC")
end_on_eot = Param.Bool(False, "End the simulation when a EOT is received on the UART")
int_delay = Param.Latency("100ns", "Time between action and interrupt generation by UART")
class Sp804(AmbaDevice):
type = 'Sp804'
cxx_header = "dev/arm/timer_sp804.hh"
- gic = Param.Gic(Parent.any, "Gic to use for interrupting")
+ gic = Param.BaseGic(Parent.any, "Gic to use for interrupting")
int_num0 = Param.UInt32("Interrupt number that connects to GIC")
clock0 = Param.Clock('1MHz', "Clock speed of the input")
int_num1 = Param.UInt32("Interrupt number that connects to GIC")
class CpuLocalTimer(BasicPioDevice):
type = 'CpuLocalTimer'
cxx_header = "dev/arm/timer_cpulocal.hh"
- gic = Param.Gic(Parent.any, "Gic to use for interrupting")
+ gic = Param.BaseGic(Parent.any, "Gic to use for interrupting")
int_num_timer = Param.UInt32("Interrrupt number used per-cpu to GIC")
int_num_watchdog = Param.UInt32("Interrupt number for per-cpu watchdog to GIC")
# Override the default clock
class RealViewPBX(RealView):
uart = Pl011(pio_addr=0x10009000, int_num=44)
realview_io = RealViewCtrl(pio_addr=0x10000000)
- gic = Gic()
+ gic = Pl390()
timer0 = Sp804(int_num0=36, int_num1=36, pio_addr=0x10011000)
timer1 = Sp804(int_num0=37, int_num1=37, pio_addr=0x10012000)
local_cpu_timer = CpuLocalTimer(int_num_timer=29, int_num_watchdog=30, pio_addr=0x1f000600)
class RealViewEB(RealView):
uart = Pl011(pio_addr=0x10009000, int_num=44)
realview_io = RealViewCtrl(pio_addr=0x10000000)
- gic = Gic(dist_addr=0x10041000, cpu_addr=0x10040000)
+ gic = Pl390(dist_addr=0x10041000, cpu_addr=0x10040000)
timer0 = Sp804(int_num0=36, int_num1=36, pio_addr=0x10011000)
timer1 = Sp804(int_num0=37, int_num1=37, pio_addr=0x10012000)
clcd = Pl111(pio_addr=0x10020000, int_num=23)
pci_cfg_base = 0x30000000
uart = Pl011(pio_addr=0x1c090000, int_num=37)
realview_io = RealViewCtrl(proc_id0=0x14000000, proc_id1=0x14000000, pio_addr=0x1C010000)
- gic = Gic(dist_addr=0x2C001000, cpu_addr=0x2C002000)
+ gic = Pl390(dist_addr=0x2C001000, cpu_addr=0x2C002000)
local_cpu_timer = CpuLocalTimer(int_num_timer=29, int_num_watchdog=30, pio_addr=0x2C080000)
timer0 = Sp804(int_num0=34, int_num1=34, pio_addr=0x1C110000, clock0='1MHz', clock1='1MHz')
timer1 = Sp804(int_num0=35, int_num1=35, pio_addr=0x1C120000, clock0='1MHz', clock1='1MHz')
Import('*')
if env['TARGET_ISA'] == 'arm':
+ SimObject('Gic.py')
SimObject('RealView.py')
Source('a9scu.cc')
Source('amba_device.cc')
Source('amba_fake.cc')
- Source('gic.cc')
+ Source('base_gic.cc')
+ Source('gic_pl390.cc')
Source('pl011.cc')
Source('pl111.cc')
Source('kmi.cc')
#ifndef __DEV_ARM_AMBA_DEVICE_HH__
#define __DEV_ARM_AMBA_DEVICE_HH__
-#include "dev/arm/gic.hh"
+#include "dev/arm/base_gic.hh"
#include "dev/dma_device.hh"
#include "dev/io_device.hh"
#include "mem/packet.hh"
{
protected:
int intNum;
- Gic *gic;
+ BaseGic *gic;
Tick intDelay;
public:
Addr pioSize;
Tick pioDelay;
int intNum;
- Gic *gic;
+ BaseGic *gic;
public:
typedef AmbaDmaDeviceParams Params;
--- /dev/null
+/*
+ * Copyright (c) 2012 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Andreas Sandberg
+ */
+
+#include "dev/arm/base_gic.hh"
+
+#include "params/BaseGic.hh"
+
+BaseGic::BaseGic(const Params *p)
+ : PioDevice(p),
+ platform(p->platform)
+{
+}
+
+BaseGic::~BaseGic()
+{
+}
+
+const BaseGic::Params *
+BaseGic::params() const
+{
+ return dynamic_cast<const Params *>(_params);
+}
--- /dev/null
+/*
+ * Copyright (c) 2012 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Andreas Sandberg
+ */
+
+/** @file
+ * Base class for ARM GIC implementations
+ */
+
+#ifndef __DEV_ARM_BASE_GIC_H__
+#define __DEV_ARM_BASE_GIC_H__
+
+#include "dev/io_device.hh"
+
+class Platform;
+
+class BaseGic : public PioDevice
+{
+ public:
+ typedef struct BaseGicParams Params;
+
+ BaseGic(const Params *p);
+ virtual ~BaseGic();
+
+ const Params * params() const;
+
+ /**
+ * Post an interrupt from a device that is connected to the GIC.
+ *
+ * Depending on the configuration, the GIC will pass this interrupt
+ * on through to a CPU.
+ *
+ * @param num number of interrupt to send
+ */
+ virtual void sendInt(uint32_t num) = 0;
+
+ /**
+ * Interface call for private peripheral interrupts.
+ *
+ * @param num number of interrupt to send
+ * @param cpu CPU to forward interrupt to
+ */
+ virtual void sendPPInt(uint32_t num, uint32_t cpu) = 0;
+
+ /**
+ * Clear an interrupt from a device that is connected to the GIC.
+ *
+ * Depending on the configuration, the GIC may de-assert it's CPU
+ * line.
+ *
+ * @param num number of interrupt to send
+ */
+ virtual void clearInt(uint32_t num) = 0;
+
+ protected:
+ /** Platform this GIC belongs to. */
+ Platform *platform;
+};
+
+#endif
+++ /dev/null
-/*
- * Copyright (c) 2010 ARM Limited
- * All rights reserved
- *
- * The license below extends only to copyright in the software and shall
- * not be construed as granting a license to any other intellectual
- * property including but not limited to intellectual property relating
- * to a hardware implementation of the functionality of the software
- * licensed hereunder. You may use the software subject to the license
- * terms below provided that you ensure that this notice is replicated
- * unmodified and in its entirety in all distributions of the software,
- * modified or unmodified, in source code or in binary form.
- *
- * Copyright (c) 2005 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Ali Saidi
- * Prakash Ramrakhyani
- */
-
-#include "base/trace.hh"
-#include "debug/Checkpoint.hh"
-#include "debug/GIC.hh"
-#include "debug/IPI.hh"
-#include "debug/Interrupt.hh"
-#include "dev/arm/gic.hh"
-#include "dev/arm/realview.hh"
-#include "dev/terminal.hh"
-#include "mem/packet.hh"
-#include "mem/packet_access.hh"
-
-Gic::Gic(const Params *p)
- : PioDevice(p), platform(p->platform), distAddr(p->dist_addr),
- cpuAddr(p->cpu_addr), distPioDelay(p->dist_pio_delay),
- cpuPioDelay(p->cpu_pio_delay), intLatency(p->int_latency),
- enabled(false), itLines(p->it_lines)
-{
- itLinesLog2 = ceilLog2(itLines);
-
- for (int x = 0; x < CPU_MAX; x++) {
- cpuEnabled[x] = false;
- cpuPriority[x] = 0xff;
- cpuBpr[x] = 0;
- // Initialize cpu highest int
- cpuHighestInt[x] = SPURIOUS_INT;
- postIntEvent[x] = new PostIntEvent(x, p->platform);
- }
- DPRINTF(Interrupt, "cpuEnabled[0]=%d cpuEnabled[1]=%d\n", cpuEnabled[0],
- cpuEnabled[1]);
-
- for (int x = 0; x < INT_BITS_MAX; x++) {
- intEnabled[x] = 0;
- pendingInt[x] = 0;
- activeInt[x] = 0;
- }
-
- for (int x = 0; x < INT_LINES_MAX; x++) {
- intPriority[x] = 0;
- cpuTarget[x] = 0;
- }
-
- for (int x = 0; x < INT_BITS_MAX*2; x++) {
- intConfig[x] = 0;
- }
-
- for (int x = 0; x < SGI_MAX; x++) {
- cpuSgiActive[x] = 0;
- cpuSgiPending[x] = 0;
- }
- for (int x = 0; x < CPU_MAX; x++) {
- cpuPpiActive[x] = 0;
- cpuPpiPending[x] = 0;
- }
-
- for (int i = 0; i < CPU_MAX; i++) {
- for (int j = 0; j < (SGI_MAX + PPI_MAX); j++) {
- bankedIntPriority[i][j] = 0;
- }
- }
-
- RealView *rv = dynamic_cast<RealView*>(p->platform);
- assert(rv);
- rv->setGic(this);
-
-}
-
-Tick
-Gic::read(PacketPtr pkt)
-{
-
- Addr addr = pkt->getAddr();
-
- if (addr >= distAddr && addr < distAddr + DIST_SIZE)
- return readDistributor(pkt);
- else if (addr >= cpuAddr && addr < cpuAddr + CPU_SIZE)
- return readCpu(pkt);
- else
- panic("Read to unknown address %#x\n", pkt->getAddr());
-}
-
-
-Tick
-Gic::write(PacketPtr pkt)
-{
-
- Addr addr = pkt->getAddr();
-
- if (addr >= distAddr && addr < distAddr + DIST_SIZE)
- return writeDistributor(pkt);
- else if (addr >= cpuAddr && addr < cpuAddr + CPU_SIZE)
- return writeCpu(pkt);
- else
- panic("Write to unknown address %#x\n", pkt->getAddr());
-}
-
-Tick
-Gic::readDistributor(PacketPtr pkt)
-{
- Addr daddr = pkt->getAddr() - distAddr;
- pkt->allocate();
-
- int ctx_id = pkt->req->contextId();
-
- DPRINTF(GIC, "gic distributor read register %#x\n", daddr);
-
- if (daddr >= ICDISER_ST && daddr < ICDISER_ED + 4) {
- assert((daddr-ICDISER_ST) >> 2 < 32);
- pkt->set<uint32_t>(intEnabled[(daddr-ICDISER_ST)>>2]);
- goto done;
- }
-
- if (daddr >= ICDICER_ST && daddr < ICDICER_ED + 4) {
- assert((daddr-ICDICER_ST) >> 2 < 32);
- pkt->set<uint32_t>(intEnabled[(daddr-ICDICER_ST)>>2]);
- goto done;
- }
-
- if (daddr >= ICDISPR_ST && daddr < ICDISPR_ED + 4) {
- assert((daddr-ICDISPR_ST) >> 2 < 32);
- pkt->set<uint32_t>(pendingInt[(daddr-ICDISPR_ST)>>2]);
- goto done;
- }
-
- if (daddr >= ICDICPR_ST && daddr < ICDICPR_ED + 4) {
- assert((daddr-ICDICPR_ST) >> 2 < 32);
- pkt->set<uint32_t>(pendingInt[(daddr-ICDICPR_ST)>>2]);
- goto done;
- }
-
- if (daddr >= ICDABR_ST && daddr < ICDABR_ED + 4) {
- assert((daddr-ICDABR_ST) >> 2 < 32);
- pkt->set<uint32_t>(activeInt[(daddr-ICDABR_ST)>>2]);
- goto done;
- }
-
- if (daddr >= ICDIPR_ST && daddr < ICDIPR_ED + 4) {
- Addr int_num;
- int_num = daddr - ICDIPR_ST;
- assert(int_num < INT_LINES_MAX);
- DPRINTF(Interrupt, "Reading interrupt priority at int# %#x \n",int_num);
-
- uint8_t* int_p;
- if (int_num < (SGI_MAX + PPI_MAX))
- int_p = bankedIntPriority[ctx_id];
- else
- int_p = intPriority;
-
- switch (pkt->getSize()) {
- case 1:
- pkt->set<uint8_t>(int_p[int_num]);
- break;
- case 2:
- assert((int_num + 1) < INT_LINES_MAX);
- pkt->set<uint16_t>(int_p[int_num] |
- int_p[int_num+1] << 8);
- break;
- case 4:
- assert((int_num + 3) < INT_LINES_MAX);
- pkt->set<uint32_t>(int_p[int_num] |
- int_p[int_num+1] << 8 |
- int_p[int_num+2] << 16 |
- int_p[int_num+3] << 24);
- break;
- default:
- panic("Invalid size while reading priority regs in GIC: %d\n",
- pkt->getSize());
- }
- goto done;
- }
-
- if (daddr >= ICDIPTR_ST && daddr < ICDIPTR_ED + 4) {
- Addr int_num;
- int_num = (daddr-ICDIPTR_ST) ;
- DPRINTF(GIC, "Reading processor target register for int# %#x \n",
- int_num);
- assert(int_num < INT_LINES_MAX);
-
- // First 31 interrupts only target single processor (SGI)
- if (int_num > 31) {
- if (pkt->getSize() == 1) {
- pkt->set<uint8_t>(cpuTarget[int_num]);
- } else {
- assert(pkt->getSize() == 4);
- int_num = mbits(int_num, 31, 2);
- pkt->set<uint32_t>(cpuTarget[int_num] |
- cpuTarget[int_num+1] << 8 |
- cpuTarget[int_num+2] << 16 |
- cpuTarget[int_num+3] << 24) ;
- }
- } else {
- int ctx_id = pkt->req->contextId();
- assert(ctx_id < sys->numRunningContexts());
- pkt->set<uint32_t>(ctx_id);
- }
- goto done;
- }
-
- if (daddr >= ICDICFR_ST && daddr < ICDICFR_ED + 4) {
- assert((daddr-ICDICFR_ST) >> 2 < 64);
- /** @todo software generated interrutps and PPIs
- * can't be configured in some ways
- */
- pkt->set<uint32_t>(intConfig[(daddr-ICDICFR_ST)>>2]);
- goto done;
- }
-
- switch(daddr) {
- case ICDDCR:
- pkt->set<uint32_t>(enabled);
- break;
- case ICDICTR:
- uint32_t tmp;
- tmp = ((sys->numRunningContexts() - 1) << 5) |
- (itLines/INT_BITS_MAX -1);
- pkt->set<uint32_t>(tmp);
- break;
- default:
- panic("Tried to read Gic distributor at offset %#x\n", daddr);
- break;
- }
-done:
- pkt->makeAtomicResponse();
- return distPioDelay;
-}
-
-Tick
-Gic::readCpu(PacketPtr pkt)
-{
- Addr daddr = pkt->getAddr() - cpuAddr;
- pkt->allocate();
-
- assert(pkt->req->hasContextId());
- int ctx_id = pkt->req->contextId();
- assert(ctx_id < sys->numRunningContexts());
-
- DPRINTF(GIC, "gic cpu read register %#x cpu context: %d\n", daddr,
- ctx_id);
-
- switch(daddr) {
- case ICCICR:
- pkt->set<uint32_t>(cpuEnabled[ctx_id]);
- break;
- case ICCPMR:
- pkt->set<uint32_t>(cpuPriority[ctx_id]);
- break;
- case ICCBPR:
- pkt->set<uint32_t>(cpuBpr[ctx_id]);
- break;
- case ICCIAR:
- if (enabled && cpuEnabled[ctx_id]) {
- int active_int = cpuHighestInt[ctx_id];
- IAR iar = 0;
- iar.ack_id = active_int;
- iar.cpu_id = 0;
- if (active_int < SGI_MAX) {
- // this is a software interrupt from another CPU
- if (!cpuSgiPending[active_int])
- panic("Interrupt %d active but no CPU generated it?\n",
- active_int);
- for (int x = 0; x < CPU_MAX; x++) {
- // See which CPU generated the interrupt
- uint8_t cpugen =
- bits(cpuSgiPending[active_int], 7 + 8 * x, 8 * x);
- if (cpugen & (1 << ctx_id)) {
- iar.cpu_id = x;
- break;
- }
- }
- uint64_t sgi_num = ULL(1) << (ctx_id + 8 * iar.cpu_id);
- cpuSgiActive[iar.ack_id] |= sgi_num;
- cpuSgiPending[iar.ack_id] &= ~sgi_num;
- } else if (active_int < (SGI_MAX + PPI_MAX) ) {
- uint32_t int_num = 1 << (cpuHighestInt[ctx_id] - SGI_MAX);
- cpuPpiActive[ctx_id] |= int_num;
- updateRunPri();
- cpuPpiPending[ctx_id] &= ~int_num;
-
- } else {
- uint32_t int_num = 1 << intNumToBit(cpuHighestInt[ctx_id]);
- activeInt[intNumToWord(cpuHighestInt[ctx_id])] |= int_num;
- updateRunPri();
- pendingInt[intNumToWord(cpuHighestInt[ctx_id])] &= ~int_num;
- }
-
- DPRINTF(Interrupt,"CPU %d reading IAR.id=%d IAR.cpu=%d, iar=0x%x\n",
- ctx_id, iar.ack_id, iar.cpu_id, iar);
- cpuHighestInt[ctx_id] = SPURIOUS_INT;
- updateIntState(-1);
- pkt->set<uint32_t>(iar);
- platform->intrctrl->clear(ctx_id, ArmISA::INT_IRQ, 0);
- } else {
- pkt->set<uint32_t>(SPURIOUS_INT);
- }
-
- break;
- case ICCRPR:
- pkt->set<uint32_t>(iccrpr[0]);
- break;
- case ICCHPIR:
- pkt->set<uint32_t>(0);
- panic("Need to implement HPIR");
- break;
- default:
- panic("Tried to read Gic cpu at offset %#x\n", daddr);
- break;
- }
- pkt->makeAtomicResponse();
- return cpuPioDelay;
-}
-
-
-Tick
-Gic::writeDistributor(PacketPtr pkt)
-{
- Addr daddr = pkt->getAddr() - distAddr;
- pkt->allocate();
-
- assert(pkt->req->hasContextId());
- int ctx_id = pkt->req->contextId();
-
- DPRINTF(GIC, "gic distributor write register %#x size %#x value %#x \n",
- daddr, pkt->getSize(), pkt->get<uint32_t>());
-
- if (daddr >= ICDISER_ST && daddr < ICDISER_ED + 4) {
- assert((daddr-ICDISER_ST) >> 2 < 32);
- intEnabled[(daddr-ICDISER_ST) >> 2] |= pkt->get<uint32_t>();
- goto done;
- }
-
- if (daddr >= ICDICER_ST && daddr < ICDICER_ED + 4) {
- assert((daddr-ICDICER_ST) >> 2 < 32);
- intEnabled[(daddr-ICDICER_ST) >> 2] &= ~pkt->get<uint32_t>();
- goto done;
- }
-
- if (daddr >= ICDISPR_ST && daddr < ICDISPR_ED + 4) {
- assert((daddr-ICDISPR_ST) >> 2 < 32);
- pendingInt[(daddr-ICDISPR_ST) >> 2] |= pkt->get<uint32_t>();
- pendingInt[0] &= SGI_MASK; // Don't allow SGIs to be changed
- updateIntState((daddr-ICDISPR_ST) >> 2);
- goto done;
- }
-
- if (daddr >= ICDICPR_ST && daddr < ICDICPR_ED + 4) {
- assert((daddr-ICDICPR_ST) >> 2 < 32);
- pendingInt[(daddr-ICDICPR_ST) >> 2] &= ~pkt->get<uint32_t>();
- pendingInt[0] &= SGI_MASK; // Don't allow SGIs to be changed
- updateIntState((daddr-ICDICPR_ST) >> 2);
- goto done;
- }
-
- if (daddr >= ICDIPR_ST && daddr < ICDIPR_ED + 4) {
- Addr int_num = daddr - ICDIPR_ST;
- assert(int_num < INT_LINES_MAX);
- uint8_t* int_p;
- if (int_num < (SGI_MAX + PPI_MAX))
- int_p = bankedIntPriority[ctx_id];
- else
- int_p = intPriority;
- uint32_t tmp;
- switch(pkt->getSize()) {
- case 1:
- tmp = pkt->get<uint8_t>();
- int_p[int_num] = bits(tmp, 7, 0);
- break;
- case 2:
- tmp = pkt->get<uint16_t>();
- int_p[int_num] = bits(tmp, 7, 0);
- int_p[int_num + 1] = bits(tmp, 15, 8);
- break;
- case 4:
- tmp = pkt->get<uint32_t>();
- int_p[int_num] = bits(tmp, 7, 0);
- int_p[int_num + 1] = bits(tmp, 15, 8);
- int_p[int_num + 2] = bits(tmp, 23, 16);
- int_p[int_num + 3] = bits(tmp, 31, 24);
- break;
- default:
- panic("Invalid size when writing to priority regs in Gic: %d\n",
- pkt->getSize());
- }
-
- updateIntState(-1);
- updateRunPri();
- goto done;
- }
-
- if (daddr >= ICDIPTR_ST && daddr < ICDIPTR_ED + 4) {
- Addr int_num = (daddr-ICDIPTR_ST) ;
- assert(int_num < INT_LINES_MAX);
- // First 31 interrupts only target single processor
- if (int_num >= SGI_MAX) {
- if (pkt->getSize() == 1) {
- uint8_t tmp = pkt->get<uint8_t>();
- cpuTarget[int_num] = tmp & 0xff;
- } else {
- assert (pkt->getSize() == 4);
- int_num = mbits(int_num, 31, 2);
- uint32_t tmp = pkt->get<uint32_t>();
- cpuTarget[int_num] = bits(tmp, 7, 0);
- cpuTarget[int_num+1] = bits(tmp, 15, 8);
- cpuTarget[int_num+2] = bits(tmp, 23, 16);
- cpuTarget[int_num+3] = bits(tmp, 31, 24);
- }
- updateIntState((daddr-ICDIPTR_ST)>>2);
- }
- goto done;
- }
-
- if (daddr >= ICDICFR_ST && daddr < ICDICFR_ED + 4) {
- assert((daddr-ICDICFR_ST) >> 2 < 64);
- intConfig[(daddr-ICDICFR_ST)>>2] = pkt->get<uint32_t>();
- if (pkt->get<uint32_t>() & NN_CONFIG_MASK)
- warn("GIC N:N mode selected and not supported at this time\n");
- goto done;
- }
-
- switch(daddr) {
- case ICDDCR:
- enabled = pkt->get<uint32_t>();
- DPRINTF(Interrupt, "Distributor enable flag set to = %d\n", enabled);
- break;
- case ICDSGIR:
- softInt(ctx_id, pkt->get<uint32_t>());
- break;
- default:
- panic("Tried to write Gic distributor at offset %#x\n", daddr);
- break;
- }
-
-done:
- pkt->makeAtomicResponse();
- return distPioDelay;
-}
-
-Tick
-Gic::writeCpu(PacketPtr pkt)
-{
- Addr daddr = pkt->getAddr() - cpuAddr;
- pkt->allocate();
-
- assert(pkt->req->hasContextId());
- int ctx_id = pkt->req->contextId();
- IAR iar;
-
- DPRINTF(GIC, "gic cpu write register cpu:%d %#x val: %#x\n",
- ctx_id, daddr, pkt->get<uint32_t>());
-
- switch(daddr) {
- case ICCICR:
- cpuEnabled[ctx_id] = pkt->get<uint32_t>();
- break;
- case ICCPMR:
- cpuPriority[ctx_id] = pkt->get<uint32_t>();
- break;
- case ICCBPR:
- cpuBpr[ctx_id] = pkt->get<uint32_t>();
- break;
- case ICCEOIR:
- iar = pkt->get<uint32_t>();
- if (iar.ack_id < SGI_MAX) {
- // Clear out the bit that corrseponds to the cleared int
- uint64_t clr_int = ULL(1) << (ctx_id + 8 * iar.cpu_id);
- if (!(cpuSgiActive[iar.ack_id] & clr_int))
- panic("Done handling a SGI that isn't active?\n");
- cpuSgiActive[iar.ack_id] &= ~clr_int;
- } else if (iar.ack_id < (SGI_MAX + PPI_MAX) ) {
- uint32_t int_num = 1 << (iar.ack_id - SGI_MAX);
- if (!(cpuPpiActive[ctx_id] & int_num))
- panic("CPU %d Done handling a PPI interrupt that isn't active?\n", ctx_id);
- cpuPpiActive[ctx_id] &= ~int_num;
- } else {
- uint32_t int_num = 1 << intNumToBit(iar.ack_id);
- if (!(activeInt[intNumToWord(iar.ack_id)] & int_num))
- panic("Done handling interrupt that isn't active?\n");
- activeInt[intNumToWord(iar.ack_id)] &= ~int_num;
- }
- updateRunPri();
- DPRINTF(Interrupt, "CPU %d done handling intr IAR = %d from cpu %d\n",
- ctx_id, iar.ack_id, iar.cpu_id);
- break;
- default:
- panic("Tried to write Gic cpu at offset %#x\n", daddr);
- break;
- }
- if (cpuEnabled[ctx_id]) updateIntState(-1);
- pkt->makeAtomicResponse();
- return cpuPioDelay;
-}
-
-void
-Gic::softInt(int ctx_id, SWI swi)
-{
- switch (swi.list_type) {
- case 1:
- // interrupt all
- uint8_t cpu_list;
- cpu_list = 0;
- for (int x = 0; x < CPU_MAX; x++)
- cpu_list |= cpuEnabled[x] ? 1 << x : 0;
- swi.cpu_list = cpu_list;
- break;
- case 2:
- // interrupt requesting cpu only
- swi.cpu_list = 1 << ctx_id;
- break;
- // else interrupt cpus specified
- }
-
- DPRINTF(IPI, "Generating softIRQ from CPU %d for %#x\n", ctx_id,
- swi.cpu_list);
- for (int i = 0; i < CPU_MAX; i++) {
- DPRINTF(IPI, "Processing CPU %d\n", i);
- if (!cpuEnabled[i])
- continue;
- if (swi.cpu_list & (1 << i))
- cpuSgiPending[swi.sgi_id] |= (1 << i) << (8 * ctx_id);
- DPRINTF(IPI, "SGI[%d]=%#x\n", swi.sgi_id, cpuSgiPending[swi.sgi_id]);
- }
- updateIntState(-1);
-}
-
-uint64_t
-Gic::genSwiMask(int cpu)
-{
- if (cpu > 7)
- panic("Invalid CPU ID\n");
- return ULL(0x0101010101010101) << cpu;
-}
-
-void
-Gic::updateIntState(int hint)
-{
- for (int cpu = 0; cpu < CPU_MAX; cpu++) {
- if (!cpuEnabled[cpu])
- continue;
- if (cpu >= sys->numContexts())
- break;
-
- /*@todo use hint to do less work. */
- int highest_int = SPURIOUS_INT;
- // Priorities below that set in ICCPMR can be ignored
- uint8_t highest_pri = cpuPriority[cpu];
-
- // Check SGIs
- for (int swi = 0; swi < SGI_MAX; swi++) {
- if (!cpuSgiPending[swi])
- continue;
- if (cpuSgiPending[swi] & genSwiMask(cpu))
- if (highest_pri > bankedIntPriority[cpu][swi]) {
- highest_pri = bankedIntPriority[cpu][swi];
- highest_int = swi;
- }
- }
-
- // Check PPIs
- if (cpuPpiPending[cpu]) {
- for (int ppi = 0; ppi < PPI_MAX; ppi++) {
- if (cpuPpiPending[cpu] & (1 << ppi))
- if (highest_pri > bankedIntPriority[cpu][SGI_MAX + ppi]) {
- highest_pri = bankedIntPriority[cpu][SGI_MAX + ppi];
- highest_int = SGI_MAX + ppi;
- }
- }
- }
-
- bool mp_sys = sys->numRunningContexts() > 1;
- // Check other ints
- for (int x = 0; x < (itLines/INT_BITS_MAX); x++) {
- if (intEnabled[x] & pendingInt[x]) {
- for (int y = 0; y < INT_BITS_MAX; y++) {
- uint32_t int_nm = x * INT_BITS_MAX + y;
- DPRINTF(GIC, "Checking for interrupt# %d \n",int_nm);
- /* Set current pending int as highest int for current cpu
- if the interrupt's priority higher than current prioirty
- and if currrent cpu is the target (for mp configs only)
- */
- if ((bits(intEnabled[x], y) & bits(pendingInt[x], y)) &&
- (intPriority[int_nm] < highest_pri))
- if ( (!mp_sys) || (cpuTarget[int_nm] & (1 << cpu))) {
- highest_pri = intPriority[int_nm];
- highest_int = int_nm;
- }
- }
- }
- }
-
- cpuHighestInt[cpu] = highest_int;
-
- if (highest_int == SPURIOUS_INT)
- continue;
-
- /* @todo make this work for more than one cpu, need to handle 1:N, N:N
- * models */
- if (enabled && cpuEnabled[cpu] && (highest_pri < cpuPriority[cpu]) &&
- !(activeInt[intNumToWord(highest_int)]
- & (1 << intNumToBit(highest_int)))) {
-
- DPRINTF(Interrupt, "Posting interrupt %d to cpu%d\n", highest_int,
- cpu);
- postInt(cpu, curTick() + intLatency);
- }
- }
-}
-
-void
-Gic::updateRunPri()
-{
- for (int cpu = 0; cpu < CPU_MAX; cpu++) {
- if (!cpuEnabled[cpu])
- continue;
- uint8_t maxPriority = 0xff;
- for (int i = 0; i < itLines; i++){
- if (i < SGI_MAX) {
- if ((cpuSgiActive[i] & genSwiMask(cpu)) &&
- (bankedIntPriority[cpu][i] < maxPriority))
- maxPriority = bankedIntPriority[cpu][i];
- } else if (i < (SGI_MAX + PPI_MAX)) {
- if ((cpuPpiActive[cpu] & ( 1 << (i - SGI_MAX))) &&
- (bankedIntPriority[cpu][i] < maxPriority))
- maxPriority = bankedIntPriority[cpu][i];
-
- } else {
- if (activeInt[intNumToWord(i)] & (1 << intNumToBit(i)))
- if (intPriority[i] < maxPriority)
- maxPriority = intPriority[i];
- }
- }
- iccrpr[cpu] = maxPriority;
- }
-}
-
-void
-Gic::sendInt(uint32_t num)
-{
- DPRINTF(Interrupt, "Received Interupt number %d, cpuTarget %#x: \n",
- num, cpuTarget[num]);
- if (cpuTarget[num] & (cpuTarget[num] - 1))
- panic("Multiple targets for peripheral interrupts is not supported\n");
- pendingInt[intNumToWord(num)] |= 1 << intNumToBit(num);
- updateIntState(intNumToWord(num));
-
-}
-
-void
-Gic::sendPPInt(uint32_t num, uint32_t cpu)
-{
- DPRINTF(Interrupt, "Received Interrupt number %d, cpuTarget %#x: \n",
- num, cpu);
- cpuPpiPending[cpu] |= 1 << (num - SGI_MAX);
- updateIntState(intNumToWord(num));
-}
-
-void
-Gic::clearInt(uint32_t number)
-{
- /* @todo assume edge triggered only at the moment. Nothing to do. */
-}
-
-void
-Gic::postInt(uint32_t cpu, Tick when)
-{
- if (!(postIntEvent[cpu]->scheduled()))
- eventq->schedule(postIntEvent[cpu], when);
-}
-
-AddrRangeList
-Gic::getAddrRanges() const
-{
- AddrRangeList ranges;
- ranges.push_back(RangeSize(distAddr, DIST_SIZE));
- ranges.push_back(RangeSize(cpuAddr, CPU_SIZE));
- return ranges;
-}
-
-
-void
-Gic::serialize(std::ostream &os)
-{
- DPRINTF(Checkpoint, "Serializing Arm GIC\n");
-
- SERIALIZE_SCALAR(distAddr);
- SERIALIZE_SCALAR(cpuAddr);
- SERIALIZE_SCALAR(distPioDelay);
- SERIALIZE_SCALAR(cpuPioDelay);
- SERIALIZE_SCALAR(enabled);
- SERIALIZE_SCALAR(itLines);
- SERIALIZE_SCALAR(itLinesLog2);
- SERIALIZE_ARRAY(intEnabled, INT_BITS_MAX);
- SERIALIZE_ARRAY(pendingInt, INT_BITS_MAX);
- SERIALIZE_ARRAY(activeInt, INT_BITS_MAX);
- SERIALIZE_ARRAY(iccrpr, CPU_MAX);
- SERIALIZE_ARRAY(intPriority, INT_LINES_MAX);
- SERIALIZE_ARRAY(cpuTarget, INT_LINES_MAX);
- SERIALIZE_ARRAY(intConfig, INT_BITS_MAX * 2);
- SERIALIZE_ARRAY(cpuEnabled, CPU_MAX);
- SERIALIZE_ARRAY(cpuPriority, CPU_MAX);
- SERIALIZE_ARRAY(cpuBpr, CPU_MAX);
- SERIALIZE_ARRAY(cpuHighestInt, CPU_MAX);
- SERIALIZE_ARRAY(cpuSgiActive, SGI_MAX);
- SERIALIZE_ARRAY(cpuSgiPending, SGI_MAX);
- SERIALIZE_ARRAY(cpuPpiActive, CPU_MAX);
- SERIALIZE_ARRAY(cpuPpiPending, CPU_MAX);
- SERIALIZE_ARRAY(*bankedIntPriority, CPU_MAX * (SGI_MAX + PPI_MAX));
- SERIALIZE_SCALAR(irqEnable);
- Tick interrupt_time[CPU_MAX];
- for (uint32_t cpu = 0; cpu < CPU_MAX; cpu++) {
- interrupt_time[cpu] = 0;
- if (postIntEvent[cpu]->scheduled()) {
- interrupt_time[cpu] = postIntEvent[cpu]->when();
- }
- }
- SERIALIZE_ARRAY(interrupt_time, CPU_MAX);
-
-}
-
-void
-Gic::unserialize(Checkpoint *cp, const std::string §ion)
-{
- DPRINTF(Checkpoint, "Unserializing Arm GIC\n");
-
- UNSERIALIZE_SCALAR(distAddr);
- UNSERIALIZE_SCALAR(cpuAddr);
- UNSERIALIZE_SCALAR(distPioDelay);
- UNSERIALIZE_SCALAR(cpuPioDelay);
- UNSERIALIZE_SCALAR(enabled);
- UNSERIALIZE_SCALAR(itLines);
- UNSERIALIZE_SCALAR(itLinesLog2);
- UNSERIALIZE_ARRAY(intEnabled, INT_BITS_MAX);
- UNSERIALIZE_ARRAY(pendingInt, INT_BITS_MAX);
- UNSERIALIZE_ARRAY(activeInt, INT_BITS_MAX);
- UNSERIALIZE_ARRAY(iccrpr, CPU_MAX);
- UNSERIALIZE_ARRAY(intPriority, INT_LINES_MAX);
- UNSERIALIZE_ARRAY(cpuTarget, INT_LINES_MAX);
- UNSERIALIZE_ARRAY(intConfig, INT_BITS_MAX * 2);
- UNSERIALIZE_ARRAY(cpuEnabled, CPU_MAX);
- UNSERIALIZE_ARRAY(cpuPriority, CPU_MAX);
- UNSERIALIZE_ARRAY(cpuBpr, CPU_MAX);
- UNSERIALIZE_ARRAY(cpuHighestInt, CPU_MAX);
- UNSERIALIZE_ARRAY(cpuSgiActive, SGI_MAX);
- UNSERIALIZE_ARRAY(cpuSgiPending, SGI_MAX);
- UNSERIALIZE_ARRAY(cpuPpiActive, CPU_MAX);
- UNSERIALIZE_ARRAY(cpuPpiPending, CPU_MAX);
- UNSERIALIZE_ARRAY(*bankedIntPriority, CPU_MAX * (SGI_MAX + PPI_MAX));
- UNSERIALIZE_SCALAR(irqEnable);
-
- Tick interrupt_time[CPU_MAX];
- UNSERIALIZE_ARRAY(interrupt_time, CPU_MAX);
-
- for (uint32_t cpu = 0; cpu < CPU_MAX; cpu++) {
- if (interrupt_time[cpu])
- schedule(postIntEvent[cpu], interrupt_time[cpu]);
- }
-
-}
-
-Gic *
-GicParams::create()
-{
- return new Gic(this);
-}
-
-/* Functions for debugging and testing */
-void
-Gic::driveSPI(unsigned int spiVect)
-{
- DPRINTF(GIC, "Received SPI Vector:%x Enable: %d\n", spiVect, irqEnable);
- pendingInt[1] |= spiVect;
- if (irqEnable && enabled) {
- updateIntState(-1);
- }
-}
-
-void
-Gic::driveIrqEn( bool state)
-{
- irqEnable = state;
- DPRINTF(GIC, " Enabling Irq\n");
- updateIntState(-1);
-}
-
-void
-Gic::driveLegIRQ(bool state)
-{
- if (irqEnable && !(!enabled && cpuEnabled[0])) {
- if (state) {
- DPRINTF(GIC, "Driving Legacy Irq\n");
- platform->intrctrl->post(0, ArmISA::INT_IRQ, 0);
- }
- else platform->intrctrl->clear(0, ArmISA::INT_IRQ, 0);
- }
-}
-
-void
-Gic::driveLegFIQ(bool state)
-{
- if (state)
- platform->intrctrl->post(0, ArmISA::INT_FIQ, 0);
- else platform->intrctrl->clear(0, ArmISA::INT_FIQ, 0);
-}
+++ /dev/null
-/*
- * Copyright (c) 2010 ARM Limited
- * All rights reserved
- *
- * The license below extends only to copyright in the software and shall
- * not be construed as granting a license to any other intellectual
- * property including but not limited to intellectual property relating
- * to a hardware implementation of the functionality of the software
- * licensed hereunder. You may use the software subject to the license
- * terms below provided that you ensure that this notice is replicated
- * unmodified and in its entirety in all distributions of the software,
- * modified or unmodified, in source code or in binary form.
- *
- * Copyright (c) 2005 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Ali Saidi
- */
-
-
-/** @file
- * Implementiation of a PL390 GIC
- */
-
-#ifndef __DEV_ARM_GIC_H__
-#define __DEV_ARM_GIC_H__
-
-#include "base/bitunion.hh"
-#include "dev/io_device.hh"
-#include "dev/platform.hh"
-#include "cpu/intr_control.hh"
-#include "params/Gic.hh"
-
-/** @todo this code only assumes one processor for now. Low word
- * of intEnabled and pendingInt need to be replicated per CPU.
- * bottom 31 interrupts (7 words) need to be replicated for
- * for interrupt priority register, processor target registers
- * interrupt config registers */
-
-class Gic : public PioDevice
-{
- protected:
- // distributor memory addresses
- static const int ICDDCR = 0x000; // control register
- static const int ICDICTR = 0x004; // controller type
- static const int ICDIIDR = 0x008; // implementer id
- static const int ICDISER_ST = 0x100; // interrupt set enable
- static const int ICDISER_ED = 0x17c;
- static const int ICDICER_ST = 0x180; // interrupt clear enable
- static const int ICDICER_ED = 0x1fc;
- static const int ICDISPR_ST = 0x200; // set pending interrupt
- static const int ICDISPR_ED = 0x27c;
- static const int ICDICPR_ST = 0x280; // clear pending interrupt
- static const int ICDICPR_ED = 0x2fc;
- static const int ICDABR_ST = 0x300; // active bit registers
- static const int ICDABR_ED = 0x37c;
- static const int ICDIPR_ST = 0x400; // interrupt priority registers
- static const int ICDIPR_ED = 0x7f8;
- static const int ICDIPTR_ST = 0x800; // processor target registers
- static const int ICDIPTR_ED = 0xbf8;
- static const int ICDICFR_ST = 0xc00; // interrupt config registers
- static const int ICDICFR_ED = 0xcfc;
- static const int ICDSGIR = 0xf00; // software generated interrupt
- static const int DIST_SIZE = 0xfff;
-
- // cpu memory addressesa
- static const int ICCICR = 0x00; // CPU control register
- static const int ICCPMR = 0x04; // Interrupt priority mask
- static const int ICCBPR = 0x08; // binary point register
- static const int ICCIAR = 0x0C; // interrupt ack register
- static const int ICCEOIR = 0x10; // end of interrupt
- static const int ICCRPR = 0x14; // runing priority
- static const int ICCHPIR = 0x18; // highest pending interrupt
- static const int ICCABPR = 0x1c; // aliased binary point
- static const int ICCIIDR = 0xfc; // cpu interface id register
- static const int CPU_SIZE = 0xff;
-
- static const int SGI_MAX = 16; // Number of Software Gen Interrupts
- static const int PPI_MAX = 16; // Number of Private Peripheral Interrupts
-
- /** Mask off SGI's when setting/clearing pending bits */
- static const int SGI_MASK = 0xFFFF0000;
-
- /** Mask for bits that config N:N mode in ICDICFR's */
- static const int NN_CONFIG_MASK = 0x55555555;
-
- static const int CPU_MAX = 8; // Max number of supported CPU interfaces
- static const int SPURIOUS_INT = 1023;
- static const int INT_BITS_MAX = 32;
- static const int INT_LINES_MAX = 1020;
-
- BitUnion32(SWI)
- Bitfield<3,0> sgi_id;
- Bitfield<23,16> cpu_list;
- Bitfield<25,24> list_type;
- EndBitUnion(SWI)
-
- BitUnion32(IAR)
- Bitfield<9,0> ack_id;
- Bitfield<12,10> cpu_id;
- EndBitUnion(IAR)
-
- Platform *platform;
-
- /** Distributor address GIC listens at */
- Addr distAddr;
-
- /** CPU address GIC listens at */
- /** @todo is this one per cpu? */
- Addr cpuAddr;
-
- /** Latency for a distributor operation */
- Tick distPioDelay;
-
- /** Latency for a cpu operation */
- Tick cpuPioDelay;
-
- /** Latency for a interrupt to get to CPU */
- Tick intLatency;
-
- /** Gic enabled */
- bool enabled;
-
- /** Number of itLines enabled */
- uint32_t itLines;
-
- uint32_t itLinesLog2;
-
- /** interrupt enable bits for all possible 1020 interupts.
- * one bit per interrupt, 32 bit per word = 32 words */
- uint32_t intEnabled[INT_BITS_MAX];
-
- /** interrupt pending bits for all possible 1020 interupts.
- * one bit per interrupt, 32 bit per word = 32 words */
- uint32_t pendingInt[INT_BITS_MAX];
-
- /** interrupt active bits for all possible 1020 interupts.
- * one bit per interrupt, 32 bit per word = 32 words */
- uint32_t activeInt[INT_BITS_MAX];
-
- /** read only running priroity register, 1 per cpu*/
- uint32_t iccrpr[CPU_MAX];
-
- /** an 8 bit priority (lower is higher priority) for each
- * of the 1020 possible supported interrupts.
- */
- uint8_t intPriority[INT_LINES_MAX];
-
- /** an 8 bit cpu target id for each shared peripheral interrupt
- * of the 1020 possible supported interrupts.
- */
- uint8_t cpuTarget[INT_LINES_MAX];
-
- /** 2 bit per interrupt signaling if it's level or edge sensitive
- * and if it is 1:N or N:N */
- uint32_t intConfig[INT_BITS_MAX*2];
-
- /** CPU enabled */
- bool cpuEnabled[CPU_MAX];
-
- /** CPU priority */
- uint8_t cpuPriority[CPU_MAX];
-
- /** Binary point registers */
- uint8_t cpuBpr[CPU_MAX];
-
- /** highest interrupt that is interrupting CPU */
- uint32_t cpuHighestInt[CPU_MAX];
-
- /** One bit per cpu per software interrupt that is pending for each possible
- * sgi source. Indexed by SGI number. Each byte in generating cpu id and
- * bits in position is destination id. e.g. 0x4 = CPU 0 generated interrupt
- * for CPU 2. */
- uint64_t cpuSgiPending[SGI_MAX];
- uint64_t cpuSgiActive[SGI_MAX];
-
- /** One bit per private peripheral interrupt. Only upper 16 bits
- * will be used since PPI interrupts are numberred from 16 to 32 */
- uint32_t cpuPpiPending[CPU_MAX];
- uint32_t cpuPpiActive[CPU_MAX];
-
- /** Banked interrupt prioirty registers for SGIs and PPIs */
- uint8_t bankedIntPriority[CPU_MAX][SGI_MAX + PPI_MAX];
-
- /** IRQ Enable Used for debug */
- bool irqEnable;
-
- /** software generated interrupt
- * @param data data to decode that indicates which cpus to interrupt
- */
- void softInt(int ctx_id, SWI swi);
-
- /** See if some processor interrupt flags need to be enabled/disabled
- * @param hint which set of interrupts needs to be checked
- */
- void updateIntState(int hint);
-
- /** Update the register that records priority of the highest priority
- * active interrupt*/
- void updateRunPri();
-
- /** generate a bit mask to check cpuSgi for an interrupt. */
- uint64_t genSwiMask(int cpu);
-
- int intNumToWord(int num) const { return num >> 5; }
- int intNumToBit(int num) const { return num % 32; }
-
- /** Post an interrupt to a CPU
- */
- void postInt(uint32_t cpu, Tick when);
-
- /** Event definition to post interrupt to CPU after a delay
- */
- class PostIntEvent : public Event
- {
- private:
- uint32_t cpu;
- Platform *platform;
- public:
- PostIntEvent( uint32_t c, Platform* p)
- : cpu(c), platform(p)
- { }
- void process() { platform->intrctrl->post(cpu, ArmISA::INT_IRQ, 0);}
- const char *description() const { return "Post Interrupt to CPU"; }
- };
- PostIntEvent *postIntEvent[CPU_MAX];
-
- public:
- typedef GicParams Params;
- const Params *
- params() const
- {
- return dynamic_cast<const Params *>(_params);
- }
- Gic(const Params *p);
-
- /** Return the address ranges used by the Gic
- * This is the distributor address + all cpu addresses
- */
- virtual AddrRangeList getAddrRanges() const;
-
- /** A PIO read to the device, immediately split up into
- * readDistributor() or readCpu()
- */
- virtual Tick read(PacketPtr pkt);
-
- /** A PIO read to the device, immediately split up into
- * writeDistributor() or writeCpu()
- */
- virtual Tick write(PacketPtr pkt);
-
- /** Handle a read to the distributor poriton of the GIC
- * @param pkt packet to respond to
- */
- Tick readDistributor(PacketPtr pkt);
-
- /** Handle a read to the cpu poriton of the GIC
- * @param pkt packet to respond to
- */
- Tick readCpu(PacketPtr pkt);
-
- /** Handle a write to the distributor poriton of the GIC
- * @param pkt packet to respond to
- */
- Tick writeDistributor(PacketPtr pkt);
-
- /** Handle a write to the cpu poriton of the GIC
- * @param pkt packet to respond to
- */
- Tick writeCpu(PacketPtr pkt);
-
- /** Post an interrupt from a device that is connected to the Gic.
- * Depending on the configuration, the gic will pass this interrupt
- * on through to a CPU.
- * @param number number of interrupt to send */
- void sendInt(uint32_t number);
-
- /** Interface call for private peripheral interrupts */
- void sendPPInt(uint32_t num, uint32_t cpu);
-
- /** Clear an interrupt from a device that is connected to the Gic
- * Depending on the configuration, the gic may de-assert it's cpu line
- * @param number number of interrupt to send */
- void clearInt(uint32_t number);
-
- /* Various functions fer testing and debugging */
- void driveSPI(uint32_t spi);
- void driveLegIRQ(bool state);
- void driveLegFIQ(bool state);
- void driveIrqEn(bool state);
-
- virtual void serialize(std::ostream &os);
- virtual void unserialize(Checkpoint *cp, const std::string §ion);
-
-};
-
-#endif //__DEV_ARM_GIC_H__
--- /dev/null
+/*
+ * Copyright (c) 2010 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Copyright (c) 2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ * Prakash Ramrakhyani
+ */
+
+#include "base/trace.hh"
+#include "debug/Checkpoint.hh"
+#include "debug/GIC.hh"
+#include "debug/IPI.hh"
+#include "debug/Interrupt.hh"
+#include "dev/arm/gic_pl390.hh"
+#include "dev/arm/realview.hh"
+#include "dev/terminal.hh"
+#include "mem/packet.hh"
+#include "mem/packet_access.hh"
+
+Pl390::Pl390(const Params *p)
+ : BaseGic(p), distAddr(p->dist_addr),
+ cpuAddr(p->cpu_addr), distPioDelay(p->dist_pio_delay),
+ cpuPioDelay(p->cpu_pio_delay), intLatency(p->int_latency),
+ enabled(false), itLines(p->it_lines)
+{
+ itLinesLog2 = ceilLog2(itLines);
+
+ for (int x = 0; x < CPU_MAX; x++) {
+ cpuEnabled[x] = false;
+ cpuPriority[x] = 0xff;
+ cpuBpr[x] = 0;
+ // Initialize cpu highest int
+ cpuHighestInt[x] = SPURIOUS_INT;
+ postIntEvent[x] = new PostIntEvent(x, p->platform);
+ }
+ DPRINTF(Interrupt, "cpuEnabled[0]=%d cpuEnabled[1]=%d\n", cpuEnabled[0],
+ cpuEnabled[1]);
+
+ for (int x = 0; x < INT_BITS_MAX; x++) {
+ intEnabled[x] = 0;
+ pendingInt[x] = 0;
+ activeInt[x] = 0;
+ }
+
+ for (int x = 0; x < INT_LINES_MAX; x++) {
+ intPriority[x] = 0;
+ cpuTarget[x] = 0;
+ }
+
+ for (int x = 0; x < INT_BITS_MAX*2; x++) {
+ intConfig[x] = 0;
+ }
+
+ for (int x = 0; x < SGI_MAX; x++) {
+ cpuSgiActive[x] = 0;
+ cpuSgiPending[x] = 0;
+ }
+ for (int x = 0; x < CPU_MAX; x++) {
+ cpuPpiActive[x] = 0;
+ cpuPpiPending[x] = 0;
+ }
+
+ for (int i = 0; i < CPU_MAX; i++) {
+ for (int j = 0; j < (SGI_MAX + PPI_MAX); j++) {
+ bankedIntPriority[i][j] = 0;
+ }
+ }
+
+ RealView *rv = dynamic_cast<RealView*>(p->platform);
+ assert(rv);
+ rv->setGic(this);
+
+}
+
+Tick
+Pl390::read(PacketPtr pkt)
+{
+
+ Addr addr = pkt->getAddr();
+
+ if (addr >= distAddr && addr < distAddr + DIST_SIZE)
+ return readDistributor(pkt);
+ else if (addr >= cpuAddr && addr < cpuAddr + CPU_SIZE)
+ return readCpu(pkt);
+ else
+ panic("Read to unknown address %#x\n", pkt->getAddr());
+}
+
+
+Tick
+Pl390::write(PacketPtr pkt)
+{
+
+ Addr addr = pkt->getAddr();
+
+ if (addr >= distAddr && addr < distAddr + DIST_SIZE)
+ return writeDistributor(pkt);
+ else if (addr >= cpuAddr && addr < cpuAddr + CPU_SIZE)
+ return writeCpu(pkt);
+ else
+ panic("Write to unknown address %#x\n", pkt->getAddr());
+}
+
+Tick
+Pl390::readDistributor(PacketPtr pkt)
+{
+ Addr daddr = pkt->getAddr() - distAddr;
+ pkt->allocate();
+
+ int ctx_id = pkt->req->contextId();
+
+ DPRINTF(GIC, "gic distributor read register %#x\n", daddr);
+
+ if (daddr >= ICDISER_ST && daddr < ICDISER_ED + 4) {
+ assert((daddr-ICDISER_ST) >> 2 < 32);
+ pkt->set<uint32_t>(intEnabled[(daddr-ICDISER_ST)>>2]);
+ goto done;
+ }
+
+ if (daddr >= ICDICER_ST && daddr < ICDICER_ED + 4) {
+ assert((daddr-ICDICER_ST) >> 2 < 32);
+ pkt->set<uint32_t>(intEnabled[(daddr-ICDICER_ST)>>2]);
+ goto done;
+ }
+
+ if (daddr >= ICDISPR_ST && daddr < ICDISPR_ED + 4) {
+ assert((daddr-ICDISPR_ST) >> 2 < 32);
+ pkt->set<uint32_t>(pendingInt[(daddr-ICDISPR_ST)>>2]);
+ goto done;
+ }
+
+ if (daddr >= ICDICPR_ST && daddr < ICDICPR_ED + 4) {
+ assert((daddr-ICDICPR_ST) >> 2 < 32);
+ pkt->set<uint32_t>(pendingInt[(daddr-ICDICPR_ST)>>2]);
+ goto done;
+ }
+
+ if (daddr >= ICDABR_ST && daddr < ICDABR_ED + 4) {
+ assert((daddr-ICDABR_ST) >> 2 < 32);
+ pkt->set<uint32_t>(activeInt[(daddr-ICDABR_ST)>>2]);
+ goto done;
+ }
+
+ if (daddr >= ICDIPR_ST && daddr < ICDIPR_ED + 4) {
+ Addr int_num;
+ int_num = daddr - ICDIPR_ST;
+ assert(int_num < INT_LINES_MAX);
+ DPRINTF(Interrupt, "Reading interrupt priority at int# %#x \n",int_num);
+
+ uint8_t* int_p;
+ if (int_num < (SGI_MAX + PPI_MAX))
+ int_p = bankedIntPriority[ctx_id];
+ else
+ int_p = intPriority;
+
+ switch (pkt->getSize()) {
+ case 1:
+ pkt->set<uint8_t>(int_p[int_num]);
+ break;
+ case 2:
+ assert((int_num + 1) < INT_LINES_MAX);
+ pkt->set<uint16_t>(int_p[int_num] |
+ int_p[int_num+1] << 8);
+ break;
+ case 4:
+ assert((int_num + 3) < INT_LINES_MAX);
+ pkt->set<uint32_t>(int_p[int_num] |
+ int_p[int_num+1] << 8 |
+ int_p[int_num+2] << 16 |
+ int_p[int_num+3] << 24);
+ break;
+ default:
+ panic("Invalid size while reading priority regs in GIC: %d\n",
+ pkt->getSize());
+ }
+ goto done;
+ }
+
+ if (daddr >= ICDIPTR_ST && daddr < ICDIPTR_ED + 4) {
+ Addr int_num;
+ int_num = (daddr-ICDIPTR_ST) ;
+ DPRINTF(GIC, "Reading processor target register for int# %#x \n",
+ int_num);
+ assert(int_num < INT_LINES_MAX);
+
+ // First 31 interrupts only target single processor (SGI)
+ if (int_num > 31) {
+ if (pkt->getSize() == 1) {
+ pkt->set<uint8_t>(cpuTarget[int_num]);
+ } else {
+ assert(pkt->getSize() == 4);
+ int_num = mbits(int_num, 31, 2);
+ pkt->set<uint32_t>(cpuTarget[int_num] |
+ cpuTarget[int_num+1] << 8 |
+ cpuTarget[int_num+2] << 16 |
+ cpuTarget[int_num+3] << 24) ;
+ }
+ } else {
+ int ctx_id = pkt->req->contextId();
+ assert(ctx_id < sys->numRunningContexts());
+ pkt->set<uint32_t>(ctx_id);
+ }
+ goto done;
+ }
+
+ if (daddr >= ICDICFR_ST && daddr < ICDICFR_ED + 4) {
+ assert((daddr-ICDICFR_ST) >> 2 < 64);
+ /** @todo software generated interrutps and PPIs
+ * can't be configured in some ways
+ */
+ pkt->set<uint32_t>(intConfig[(daddr-ICDICFR_ST)>>2]);
+ goto done;
+ }
+
+ switch(daddr) {
+ case ICDDCR:
+ pkt->set<uint32_t>(enabled);
+ break;
+ case ICDICTR:
+ uint32_t tmp;
+ tmp = ((sys->numRunningContexts() - 1) << 5) |
+ (itLines/INT_BITS_MAX -1);
+ pkt->set<uint32_t>(tmp);
+ break;
+ default:
+ panic("Tried to read Gic distributor at offset %#x\n", daddr);
+ break;
+ }
+done:
+ pkt->makeAtomicResponse();
+ return distPioDelay;
+}
+
+Tick
+Pl390::readCpu(PacketPtr pkt)
+{
+ Addr daddr = pkt->getAddr() - cpuAddr;
+ pkt->allocate();
+
+ assert(pkt->req->hasContextId());
+ int ctx_id = pkt->req->contextId();
+ assert(ctx_id < sys->numRunningContexts());
+
+ DPRINTF(GIC, "gic cpu read register %#x cpu context: %d\n", daddr,
+ ctx_id);
+
+ switch(daddr) {
+ case ICCICR:
+ pkt->set<uint32_t>(cpuEnabled[ctx_id]);
+ break;
+ case ICCPMR:
+ pkt->set<uint32_t>(cpuPriority[ctx_id]);
+ break;
+ case ICCBPR:
+ pkt->set<uint32_t>(cpuBpr[ctx_id]);
+ break;
+ case ICCIAR:
+ if (enabled && cpuEnabled[ctx_id]) {
+ int active_int = cpuHighestInt[ctx_id];
+ IAR iar = 0;
+ iar.ack_id = active_int;
+ iar.cpu_id = 0;
+ if (active_int < SGI_MAX) {
+ // this is a software interrupt from another CPU
+ if (!cpuSgiPending[active_int])
+ panic("Interrupt %d active but no CPU generated it?\n",
+ active_int);
+ for (int x = 0; x < CPU_MAX; x++) {
+ // See which CPU generated the interrupt
+ uint8_t cpugen =
+ bits(cpuSgiPending[active_int], 7 + 8 * x, 8 * x);
+ if (cpugen & (1 << ctx_id)) {
+ iar.cpu_id = x;
+ break;
+ }
+ }
+ uint64_t sgi_num = ULL(1) << (ctx_id + 8 * iar.cpu_id);
+ cpuSgiActive[iar.ack_id] |= sgi_num;
+ cpuSgiPending[iar.ack_id] &= ~sgi_num;
+ } else if (active_int < (SGI_MAX + PPI_MAX) ) {
+ uint32_t int_num = 1 << (cpuHighestInt[ctx_id] - SGI_MAX);
+ cpuPpiActive[ctx_id] |= int_num;
+ updateRunPri();
+ cpuPpiPending[ctx_id] &= ~int_num;
+
+ } else {
+ uint32_t int_num = 1 << intNumToBit(cpuHighestInt[ctx_id]);
+ activeInt[intNumToWord(cpuHighestInt[ctx_id])] |= int_num;
+ updateRunPri();
+ pendingInt[intNumToWord(cpuHighestInt[ctx_id])] &= ~int_num;
+ }
+
+ DPRINTF(Interrupt,"CPU %d reading IAR.id=%d IAR.cpu=%d, iar=0x%x\n",
+ ctx_id, iar.ack_id, iar.cpu_id, iar);
+ cpuHighestInt[ctx_id] = SPURIOUS_INT;
+ updateIntState(-1);
+ pkt->set<uint32_t>(iar);
+ platform->intrctrl->clear(ctx_id, ArmISA::INT_IRQ, 0);
+ } else {
+ pkt->set<uint32_t>(SPURIOUS_INT);
+ }
+
+ break;
+ case ICCRPR:
+ pkt->set<uint32_t>(iccrpr[0]);
+ break;
+ case ICCHPIR:
+ pkt->set<uint32_t>(0);
+ panic("Need to implement HPIR");
+ break;
+ default:
+ panic("Tried to read Gic cpu at offset %#x\n", daddr);
+ break;
+ }
+ pkt->makeAtomicResponse();
+ return cpuPioDelay;
+}
+
+
+Tick
+Pl390::writeDistributor(PacketPtr pkt)
+{
+ Addr daddr = pkt->getAddr() - distAddr;
+ pkt->allocate();
+
+ assert(pkt->req->hasContextId());
+ int ctx_id = pkt->req->contextId();
+
+ DPRINTF(GIC, "gic distributor write register %#x size %#x value %#x \n",
+ daddr, pkt->getSize(), pkt->get<uint32_t>());
+
+ if (daddr >= ICDISER_ST && daddr < ICDISER_ED + 4) {
+ assert((daddr-ICDISER_ST) >> 2 < 32);
+ intEnabled[(daddr-ICDISER_ST) >> 2] |= pkt->get<uint32_t>();
+ goto done;
+ }
+
+ if (daddr >= ICDICER_ST && daddr < ICDICER_ED + 4) {
+ assert((daddr-ICDICER_ST) >> 2 < 32);
+ intEnabled[(daddr-ICDICER_ST) >> 2] &= ~pkt->get<uint32_t>();
+ goto done;
+ }
+
+ if (daddr >= ICDISPR_ST && daddr < ICDISPR_ED + 4) {
+ assert((daddr-ICDISPR_ST) >> 2 < 32);
+ pendingInt[(daddr-ICDISPR_ST) >> 2] |= pkt->get<uint32_t>();
+ pendingInt[0] &= SGI_MASK; // Don't allow SGIs to be changed
+ updateIntState((daddr-ICDISPR_ST) >> 2);
+ goto done;
+ }
+
+ if (daddr >= ICDICPR_ST && daddr < ICDICPR_ED + 4) {
+ assert((daddr-ICDICPR_ST) >> 2 < 32);
+ pendingInt[(daddr-ICDICPR_ST) >> 2] &= ~pkt->get<uint32_t>();
+ pendingInt[0] &= SGI_MASK; // Don't allow SGIs to be changed
+ updateIntState((daddr-ICDICPR_ST) >> 2);
+ goto done;
+ }
+
+ if (daddr >= ICDIPR_ST && daddr < ICDIPR_ED + 4) {
+ Addr int_num = daddr - ICDIPR_ST;
+ assert(int_num < INT_LINES_MAX);
+ uint8_t* int_p;
+ if (int_num < (SGI_MAX + PPI_MAX))
+ int_p = bankedIntPriority[ctx_id];
+ else
+ int_p = intPriority;
+ uint32_t tmp;
+ switch(pkt->getSize()) {
+ case 1:
+ tmp = pkt->get<uint8_t>();
+ int_p[int_num] = bits(tmp, 7, 0);
+ break;
+ case 2:
+ tmp = pkt->get<uint16_t>();
+ int_p[int_num] = bits(tmp, 7, 0);
+ int_p[int_num + 1] = bits(tmp, 15, 8);
+ break;
+ case 4:
+ tmp = pkt->get<uint32_t>();
+ int_p[int_num] = bits(tmp, 7, 0);
+ int_p[int_num + 1] = bits(tmp, 15, 8);
+ int_p[int_num + 2] = bits(tmp, 23, 16);
+ int_p[int_num + 3] = bits(tmp, 31, 24);
+ break;
+ default:
+ panic("Invalid size when writing to priority regs in Gic: %d\n",
+ pkt->getSize());
+ }
+
+ updateIntState(-1);
+ updateRunPri();
+ goto done;
+ }
+
+ if (daddr >= ICDIPTR_ST && daddr < ICDIPTR_ED + 4) {
+ Addr int_num = (daddr-ICDIPTR_ST) ;
+ assert(int_num < INT_LINES_MAX);
+ // First 31 interrupts only target single processor
+ if (int_num >= SGI_MAX) {
+ if (pkt->getSize() == 1) {
+ uint8_t tmp = pkt->get<uint8_t>();
+ cpuTarget[int_num] = tmp & 0xff;
+ } else {
+ assert (pkt->getSize() == 4);
+ int_num = mbits(int_num, 31, 2);
+ uint32_t tmp = pkt->get<uint32_t>();
+ cpuTarget[int_num] = bits(tmp, 7, 0);
+ cpuTarget[int_num+1] = bits(tmp, 15, 8);
+ cpuTarget[int_num+2] = bits(tmp, 23, 16);
+ cpuTarget[int_num+3] = bits(tmp, 31, 24);
+ }
+ updateIntState((daddr-ICDIPTR_ST)>>2);
+ }
+ goto done;
+ }
+
+ if (daddr >= ICDICFR_ST && daddr < ICDICFR_ED + 4) {
+ assert((daddr-ICDICFR_ST) >> 2 < 64);
+ intConfig[(daddr-ICDICFR_ST)>>2] = pkt->get<uint32_t>();
+ if (pkt->get<uint32_t>() & NN_CONFIG_MASK)
+ warn("GIC N:N mode selected and not supported at this time\n");
+ goto done;
+ }
+
+ switch(daddr) {
+ case ICDDCR:
+ enabled = pkt->get<uint32_t>();
+ DPRINTF(Interrupt, "Distributor enable flag set to = %d\n", enabled);
+ break;
+ case ICDSGIR:
+ softInt(ctx_id, pkt->get<uint32_t>());
+ break;
+ default:
+ panic("Tried to write Gic distributor at offset %#x\n", daddr);
+ break;
+ }
+
+done:
+ pkt->makeAtomicResponse();
+ return distPioDelay;
+}
+
+Tick
+Pl390::writeCpu(PacketPtr pkt)
+{
+ Addr daddr = pkt->getAddr() - cpuAddr;
+ pkt->allocate();
+
+ assert(pkt->req->hasContextId());
+ int ctx_id = pkt->req->contextId();
+ IAR iar;
+
+ DPRINTF(GIC, "gic cpu write register cpu:%d %#x val: %#x\n",
+ ctx_id, daddr, pkt->get<uint32_t>());
+
+ switch(daddr) {
+ case ICCICR:
+ cpuEnabled[ctx_id] = pkt->get<uint32_t>();
+ break;
+ case ICCPMR:
+ cpuPriority[ctx_id] = pkt->get<uint32_t>();
+ break;
+ case ICCBPR:
+ cpuBpr[ctx_id] = pkt->get<uint32_t>();
+ break;
+ case ICCEOIR:
+ iar = pkt->get<uint32_t>();
+ if (iar.ack_id < SGI_MAX) {
+ // Clear out the bit that corrseponds to the cleared int
+ uint64_t clr_int = ULL(1) << (ctx_id + 8 * iar.cpu_id);
+ if (!(cpuSgiActive[iar.ack_id] & clr_int))
+ panic("Done handling a SGI that isn't active?\n");
+ cpuSgiActive[iar.ack_id] &= ~clr_int;
+ } else if (iar.ack_id < (SGI_MAX + PPI_MAX) ) {
+ uint32_t int_num = 1 << (iar.ack_id - SGI_MAX);
+ if (!(cpuPpiActive[ctx_id] & int_num))
+ panic("CPU %d Done handling a PPI interrupt that isn't active?\n", ctx_id);
+ cpuPpiActive[ctx_id] &= ~int_num;
+ } else {
+ uint32_t int_num = 1 << intNumToBit(iar.ack_id);
+ if (!(activeInt[intNumToWord(iar.ack_id)] & int_num))
+ panic("Done handling interrupt that isn't active?\n");
+ activeInt[intNumToWord(iar.ack_id)] &= ~int_num;
+ }
+ updateRunPri();
+ DPRINTF(Interrupt, "CPU %d done handling intr IAR = %d from cpu %d\n",
+ ctx_id, iar.ack_id, iar.cpu_id);
+ break;
+ default:
+ panic("Tried to write Gic cpu at offset %#x\n", daddr);
+ break;
+ }
+ if (cpuEnabled[ctx_id]) updateIntState(-1);
+ pkt->makeAtomicResponse();
+ return cpuPioDelay;
+}
+
+void
+Pl390::softInt(int ctx_id, SWI swi)
+{
+ switch (swi.list_type) {
+ case 1:
+ // interrupt all
+ uint8_t cpu_list;
+ cpu_list = 0;
+ for (int x = 0; x < CPU_MAX; x++)
+ cpu_list |= cpuEnabled[x] ? 1 << x : 0;
+ swi.cpu_list = cpu_list;
+ break;
+ case 2:
+ // interrupt requesting cpu only
+ swi.cpu_list = 1 << ctx_id;
+ break;
+ // else interrupt cpus specified
+ }
+
+ DPRINTF(IPI, "Generating softIRQ from CPU %d for %#x\n", ctx_id,
+ swi.cpu_list);
+ for (int i = 0; i < CPU_MAX; i++) {
+ DPRINTF(IPI, "Processing CPU %d\n", i);
+ if (!cpuEnabled[i])
+ continue;
+ if (swi.cpu_list & (1 << i))
+ cpuSgiPending[swi.sgi_id] |= (1 << i) << (8 * ctx_id);
+ DPRINTF(IPI, "SGI[%d]=%#x\n", swi.sgi_id, cpuSgiPending[swi.sgi_id]);
+ }
+ updateIntState(-1);
+}
+
+uint64_t
+Pl390::genSwiMask(int cpu)
+{
+ if (cpu > 7)
+ panic("Invalid CPU ID\n");
+ return ULL(0x0101010101010101) << cpu;
+}
+
+void
+Pl390::updateIntState(int hint)
+{
+ for (int cpu = 0; cpu < CPU_MAX; cpu++) {
+ if (!cpuEnabled[cpu])
+ continue;
+ if (cpu >= sys->numContexts())
+ break;
+
+ /*@todo use hint to do less work. */
+ int highest_int = SPURIOUS_INT;
+ // Priorities below that set in ICCPMR can be ignored
+ uint8_t highest_pri = cpuPriority[cpu];
+
+ // Check SGIs
+ for (int swi = 0; swi < SGI_MAX; swi++) {
+ if (!cpuSgiPending[swi])
+ continue;
+ if (cpuSgiPending[swi] & genSwiMask(cpu))
+ if (highest_pri > bankedIntPriority[cpu][swi]) {
+ highest_pri = bankedIntPriority[cpu][swi];
+ highest_int = swi;
+ }
+ }
+
+ // Check PPIs
+ if (cpuPpiPending[cpu]) {
+ for (int ppi = 0; ppi < PPI_MAX; ppi++) {
+ if (cpuPpiPending[cpu] & (1 << ppi))
+ if (highest_pri > bankedIntPriority[cpu][SGI_MAX + ppi]) {
+ highest_pri = bankedIntPriority[cpu][SGI_MAX + ppi];
+ highest_int = SGI_MAX + ppi;
+ }
+ }
+ }
+
+ bool mp_sys = sys->numRunningContexts() > 1;
+ // Check other ints
+ for (int x = 0; x < (itLines/INT_BITS_MAX); x++) {
+ if (intEnabled[x] & pendingInt[x]) {
+ for (int y = 0; y < INT_BITS_MAX; y++) {
+ uint32_t int_nm = x * INT_BITS_MAX + y;
+ DPRINTF(GIC, "Checking for interrupt# %d \n",int_nm);
+ /* Set current pending int as highest int for current cpu
+ if the interrupt's priority higher than current prioirty
+ and if currrent cpu is the target (for mp configs only)
+ */
+ if ((bits(intEnabled[x], y) & bits(pendingInt[x], y)) &&
+ (intPriority[int_nm] < highest_pri))
+ if ( (!mp_sys) || (cpuTarget[int_nm] & (1 << cpu))) {
+ highest_pri = intPriority[int_nm];
+ highest_int = int_nm;
+ }
+ }
+ }
+ }
+
+ cpuHighestInt[cpu] = highest_int;
+
+ if (highest_int == SPURIOUS_INT)
+ continue;
+
+ /* @todo make this work for more than one cpu, need to handle 1:N, N:N
+ * models */
+ if (enabled && cpuEnabled[cpu] && (highest_pri < cpuPriority[cpu]) &&
+ !(activeInt[intNumToWord(highest_int)]
+ & (1 << intNumToBit(highest_int)))) {
+
+ DPRINTF(Interrupt, "Posting interrupt %d to cpu%d\n", highest_int,
+ cpu);
+ postInt(cpu, curTick() + intLatency);
+ }
+ }
+}
+
+void
+Pl390::updateRunPri()
+{
+ for (int cpu = 0; cpu < CPU_MAX; cpu++) {
+ if (!cpuEnabled[cpu])
+ continue;
+ uint8_t maxPriority = 0xff;
+ for (int i = 0; i < itLines; i++){
+ if (i < SGI_MAX) {
+ if ((cpuSgiActive[i] & genSwiMask(cpu)) &&
+ (bankedIntPriority[cpu][i] < maxPriority))
+ maxPriority = bankedIntPriority[cpu][i];
+ } else if (i < (SGI_MAX + PPI_MAX)) {
+ if ((cpuPpiActive[cpu] & ( 1 << (i - SGI_MAX))) &&
+ (bankedIntPriority[cpu][i] < maxPriority))
+ maxPriority = bankedIntPriority[cpu][i];
+
+ } else {
+ if (activeInt[intNumToWord(i)] & (1 << intNumToBit(i)))
+ if (intPriority[i] < maxPriority)
+ maxPriority = intPriority[i];
+ }
+ }
+ iccrpr[cpu] = maxPriority;
+ }
+}
+
+void
+Pl390::sendInt(uint32_t num)
+{
+ DPRINTF(Interrupt, "Received Interupt number %d, cpuTarget %#x: \n",
+ num, cpuTarget[num]);
+ if (cpuTarget[num] & (cpuTarget[num] - 1))
+ panic("Multiple targets for peripheral interrupts is not supported\n");
+ pendingInt[intNumToWord(num)] |= 1 << intNumToBit(num);
+ updateIntState(intNumToWord(num));
+
+}
+
+void
+Pl390::sendPPInt(uint32_t num, uint32_t cpu)
+{
+ DPRINTF(Interrupt, "Received Interrupt number %d, cpuTarget %#x: \n",
+ num, cpu);
+ cpuPpiPending[cpu] |= 1 << (num - SGI_MAX);
+ updateIntState(intNumToWord(num));
+}
+
+void
+Pl390::clearInt(uint32_t number)
+{
+ /* @todo assume edge triggered only at the moment. Nothing to do. */
+}
+
+void
+Pl390::postInt(uint32_t cpu, Tick when)
+{
+ if (!(postIntEvent[cpu]->scheduled()))
+ eventq->schedule(postIntEvent[cpu], when);
+}
+
+AddrRangeList
+Pl390::getAddrRanges() const
+{
+ AddrRangeList ranges;
+ ranges.push_back(RangeSize(distAddr, DIST_SIZE));
+ ranges.push_back(RangeSize(cpuAddr, CPU_SIZE));
+ return ranges;
+}
+
+
+void
+Pl390::serialize(std::ostream &os)
+{
+ DPRINTF(Checkpoint, "Serializing Arm GIC\n");
+
+ SERIALIZE_SCALAR(distAddr);
+ SERIALIZE_SCALAR(cpuAddr);
+ SERIALIZE_SCALAR(distPioDelay);
+ SERIALIZE_SCALAR(cpuPioDelay);
+ SERIALIZE_SCALAR(enabled);
+ SERIALIZE_SCALAR(itLines);
+ SERIALIZE_SCALAR(itLinesLog2);
+ SERIALIZE_ARRAY(intEnabled, INT_BITS_MAX);
+ SERIALIZE_ARRAY(pendingInt, INT_BITS_MAX);
+ SERIALIZE_ARRAY(activeInt, INT_BITS_MAX);
+ SERIALIZE_ARRAY(iccrpr, CPU_MAX);
+ SERIALIZE_ARRAY(intPriority, INT_LINES_MAX);
+ SERIALIZE_ARRAY(cpuTarget, INT_LINES_MAX);
+ SERIALIZE_ARRAY(intConfig, INT_BITS_MAX * 2);
+ SERIALIZE_ARRAY(cpuEnabled, CPU_MAX);
+ SERIALIZE_ARRAY(cpuPriority, CPU_MAX);
+ SERIALIZE_ARRAY(cpuBpr, CPU_MAX);
+ SERIALIZE_ARRAY(cpuHighestInt, CPU_MAX);
+ SERIALIZE_ARRAY(cpuSgiActive, SGI_MAX);
+ SERIALIZE_ARRAY(cpuSgiPending, SGI_MAX);
+ SERIALIZE_ARRAY(cpuPpiActive, CPU_MAX);
+ SERIALIZE_ARRAY(cpuPpiPending, CPU_MAX);
+ SERIALIZE_ARRAY(*bankedIntPriority, CPU_MAX * (SGI_MAX + PPI_MAX));
+ SERIALIZE_SCALAR(irqEnable);
+ Tick interrupt_time[CPU_MAX];
+ for (uint32_t cpu = 0; cpu < CPU_MAX; cpu++) {
+ interrupt_time[cpu] = 0;
+ if (postIntEvent[cpu]->scheduled()) {
+ interrupt_time[cpu] = postIntEvent[cpu]->when();
+ }
+ }
+ SERIALIZE_ARRAY(interrupt_time, CPU_MAX);
+
+}
+
+void
+Pl390::unserialize(Checkpoint *cp, const std::string §ion)
+{
+ DPRINTF(Checkpoint, "Unserializing Arm GIC\n");
+
+ UNSERIALIZE_SCALAR(distAddr);
+ UNSERIALIZE_SCALAR(cpuAddr);
+ UNSERIALIZE_SCALAR(distPioDelay);
+ UNSERIALIZE_SCALAR(cpuPioDelay);
+ UNSERIALIZE_SCALAR(enabled);
+ UNSERIALIZE_SCALAR(itLines);
+ UNSERIALIZE_SCALAR(itLinesLog2);
+ UNSERIALIZE_ARRAY(intEnabled, INT_BITS_MAX);
+ UNSERIALIZE_ARRAY(pendingInt, INT_BITS_MAX);
+ UNSERIALIZE_ARRAY(activeInt, INT_BITS_MAX);
+ UNSERIALIZE_ARRAY(iccrpr, CPU_MAX);
+ UNSERIALIZE_ARRAY(intPriority, INT_LINES_MAX);
+ UNSERIALIZE_ARRAY(cpuTarget, INT_LINES_MAX);
+ UNSERIALIZE_ARRAY(intConfig, INT_BITS_MAX * 2);
+ UNSERIALIZE_ARRAY(cpuEnabled, CPU_MAX);
+ UNSERIALIZE_ARRAY(cpuPriority, CPU_MAX);
+ UNSERIALIZE_ARRAY(cpuBpr, CPU_MAX);
+ UNSERIALIZE_ARRAY(cpuHighestInt, CPU_MAX);
+ UNSERIALIZE_ARRAY(cpuSgiActive, SGI_MAX);
+ UNSERIALIZE_ARRAY(cpuSgiPending, SGI_MAX);
+ UNSERIALIZE_ARRAY(cpuPpiActive, CPU_MAX);
+ UNSERIALIZE_ARRAY(cpuPpiPending, CPU_MAX);
+ UNSERIALIZE_ARRAY(*bankedIntPriority, CPU_MAX * (SGI_MAX + PPI_MAX));
+ UNSERIALIZE_SCALAR(irqEnable);
+
+ Tick interrupt_time[CPU_MAX];
+ UNSERIALIZE_ARRAY(interrupt_time, CPU_MAX);
+
+ for (uint32_t cpu = 0; cpu < CPU_MAX; cpu++) {
+ if (interrupt_time[cpu])
+ schedule(postIntEvent[cpu], interrupt_time[cpu]);
+ }
+
+}
+
+Pl390 *
+Pl390Params::create()
+{
+ return new Pl390(this);
+}
+
+/* Functions for debugging and testing */
+void
+Pl390::driveSPI(unsigned int spiVect)
+{
+ DPRINTF(GIC, "Received SPI Vector:%x Enable: %d\n", spiVect, irqEnable);
+ pendingInt[1] |= spiVect;
+ if (irqEnable && enabled) {
+ updateIntState(-1);
+ }
+}
+
+void
+Pl390::driveIrqEn( bool state)
+{
+ irqEnable = state;
+ DPRINTF(GIC, " Enabling Irq\n");
+ updateIntState(-1);
+}
+
+void
+Pl390::driveLegIRQ(bool state)
+{
+ if (irqEnable && !(!enabled && cpuEnabled[0])) {
+ if (state) {
+ DPRINTF(GIC, "Driving Legacy Irq\n");
+ platform->intrctrl->post(0, ArmISA::INT_IRQ, 0);
+ }
+ else platform->intrctrl->clear(0, ArmISA::INT_IRQ, 0);
+ }
+}
+
+void
+Pl390::driveLegFIQ(bool state)
+{
+ if (state)
+ platform->intrctrl->post(0, ArmISA::INT_FIQ, 0);
+ else platform->intrctrl->clear(0, ArmISA::INT_FIQ, 0);
+}
--- /dev/null
+/*
+ * Copyright (c) 2010 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Copyright (c) 2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ */
+
+
+/** @file
+ * Implementiation of a PL390 GIC
+ */
+
+#ifndef __DEV_ARM_GIC_PL390_H__
+#define __DEV_ARM_GIC_PL390_H__
+
+#include "base/bitunion.hh"
+#include "cpu/intr_control.hh"
+#include "dev/arm/base_gic.hh"
+#include "dev/io_device.hh"
+#include "dev/platform.hh"
+#include "params/Pl390.hh"
+
+/** @todo this code only assumes one processor for now. Low word
+ * of intEnabled and pendingInt need to be replicated per CPU.
+ * bottom 31 interrupts (7 words) need to be replicated for
+ * for interrupt priority register, processor target registers
+ * interrupt config registers */
+
+class Pl390 : public BaseGic
+{
+ protected:
+ // distributor memory addresses
+ static const int ICDDCR = 0x000; // control register
+ static const int ICDICTR = 0x004; // controller type
+ static const int ICDIIDR = 0x008; // implementer id
+ static const int ICDISER_ST = 0x100; // interrupt set enable
+ static const int ICDISER_ED = 0x17c;
+ static const int ICDICER_ST = 0x180; // interrupt clear enable
+ static const int ICDICER_ED = 0x1fc;
+ static const int ICDISPR_ST = 0x200; // set pending interrupt
+ static const int ICDISPR_ED = 0x27c;
+ static const int ICDICPR_ST = 0x280; // clear pending interrupt
+ static const int ICDICPR_ED = 0x2fc;
+ static const int ICDABR_ST = 0x300; // active bit registers
+ static const int ICDABR_ED = 0x37c;
+ static const int ICDIPR_ST = 0x400; // interrupt priority registers
+ static const int ICDIPR_ED = 0x7f8;
+ static const int ICDIPTR_ST = 0x800; // processor target registers
+ static const int ICDIPTR_ED = 0xbf8;
+ static const int ICDICFR_ST = 0xc00; // interrupt config registers
+ static const int ICDICFR_ED = 0xcfc;
+ static const int ICDSGIR = 0xf00; // software generated interrupt
+ static const int DIST_SIZE = 0xfff;
+
+ // cpu memory addressesa
+ static const int ICCICR = 0x00; // CPU control register
+ static const int ICCPMR = 0x04; // Interrupt priority mask
+ static const int ICCBPR = 0x08; // binary point register
+ static const int ICCIAR = 0x0C; // interrupt ack register
+ static const int ICCEOIR = 0x10; // end of interrupt
+ static const int ICCRPR = 0x14; // runing priority
+ static const int ICCHPIR = 0x18; // highest pending interrupt
+ static const int ICCABPR = 0x1c; // aliased binary point
+ static const int ICCIIDR = 0xfc; // cpu interface id register
+ static const int CPU_SIZE = 0xff;
+
+ static const int SGI_MAX = 16; // Number of Software Gen Interrupts
+ static const int PPI_MAX = 16; // Number of Private Peripheral Interrupts
+
+ /** Mask off SGI's when setting/clearing pending bits */
+ static const int SGI_MASK = 0xFFFF0000;
+
+ /** Mask for bits that config N:N mode in ICDICFR's */
+ static const int NN_CONFIG_MASK = 0x55555555;
+
+ static const int CPU_MAX = 8; // Max number of supported CPU interfaces
+ static const int SPURIOUS_INT = 1023;
+ static const int INT_BITS_MAX = 32;
+ static const int INT_LINES_MAX = 1020;
+
+ BitUnion32(SWI)
+ Bitfield<3,0> sgi_id;
+ Bitfield<23,16> cpu_list;
+ Bitfield<25,24> list_type;
+ EndBitUnion(SWI)
+
+ BitUnion32(IAR)
+ Bitfield<9,0> ack_id;
+ Bitfield<12,10> cpu_id;
+ EndBitUnion(IAR)
+
+ /** Distributor address GIC listens at */
+ Addr distAddr;
+
+ /** CPU address GIC listens at */
+ /** @todo is this one per cpu? */
+ Addr cpuAddr;
+
+ /** Latency for a distributor operation */
+ Tick distPioDelay;
+
+ /** Latency for a cpu operation */
+ Tick cpuPioDelay;
+
+ /** Latency for a interrupt to get to CPU */
+ Tick intLatency;
+
+ /** Gic enabled */
+ bool enabled;
+
+ /** Number of itLines enabled */
+ uint32_t itLines;
+
+ uint32_t itLinesLog2;
+
+ /** interrupt enable bits for all possible 1020 interupts.
+ * one bit per interrupt, 32 bit per word = 32 words */
+ uint32_t intEnabled[INT_BITS_MAX];
+
+ /** interrupt pending bits for all possible 1020 interupts.
+ * one bit per interrupt, 32 bit per word = 32 words */
+ uint32_t pendingInt[INT_BITS_MAX];
+
+ /** interrupt active bits for all possible 1020 interupts.
+ * one bit per interrupt, 32 bit per word = 32 words */
+ uint32_t activeInt[INT_BITS_MAX];
+
+ /** read only running priroity register, 1 per cpu*/
+ uint32_t iccrpr[CPU_MAX];
+
+ /** an 8 bit priority (lower is higher priority) for each
+ * of the 1020 possible supported interrupts.
+ */
+ uint8_t intPriority[INT_LINES_MAX];
+
+ /** an 8 bit cpu target id for each shared peripheral interrupt
+ * of the 1020 possible supported interrupts.
+ */
+ uint8_t cpuTarget[INT_LINES_MAX];
+
+ /** 2 bit per interrupt signaling if it's level or edge sensitive
+ * and if it is 1:N or N:N */
+ uint32_t intConfig[INT_BITS_MAX*2];
+
+ /** CPU enabled */
+ bool cpuEnabled[CPU_MAX];
+
+ /** CPU priority */
+ uint8_t cpuPriority[CPU_MAX];
+
+ /** Binary point registers */
+ uint8_t cpuBpr[CPU_MAX];
+
+ /** highest interrupt that is interrupting CPU */
+ uint32_t cpuHighestInt[CPU_MAX];
+
+ /** One bit per cpu per software interrupt that is pending for each possible
+ * sgi source. Indexed by SGI number. Each byte in generating cpu id and
+ * bits in position is destination id. e.g. 0x4 = CPU 0 generated interrupt
+ * for CPU 2. */
+ uint64_t cpuSgiPending[SGI_MAX];
+ uint64_t cpuSgiActive[SGI_MAX];
+
+ /** One bit per private peripheral interrupt. Only upper 16 bits
+ * will be used since PPI interrupts are numberred from 16 to 32 */
+ uint32_t cpuPpiPending[CPU_MAX];
+ uint32_t cpuPpiActive[CPU_MAX];
+
+ /** Banked interrupt prioirty registers for SGIs and PPIs */
+ uint8_t bankedIntPriority[CPU_MAX][SGI_MAX + PPI_MAX];
+
+ /** IRQ Enable Used for debug */
+ bool irqEnable;
+
+ /** software generated interrupt
+ * @param data data to decode that indicates which cpus to interrupt
+ */
+ void softInt(int ctx_id, SWI swi);
+
+ /** See if some processor interrupt flags need to be enabled/disabled
+ * @param hint which set of interrupts needs to be checked
+ */
+ void updateIntState(int hint);
+
+ /** Update the register that records priority of the highest priority
+ * active interrupt*/
+ void updateRunPri();
+
+ /** generate a bit mask to check cpuSgi for an interrupt. */
+ uint64_t genSwiMask(int cpu);
+
+ int intNumToWord(int num) const { return num >> 5; }
+ int intNumToBit(int num) const { return num % 32; }
+
+ /** Post an interrupt to a CPU
+ */
+ void postInt(uint32_t cpu, Tick when);
+
+ /** Event definition to post interrupt to CPU after a delay
+ */
+ class PostIntEvent : public Event
+ {
+ private:
+ uint32_t cpu;
+ Platform *platform;
+ public:
+ PostIntEvent( uint32_t c, Platform* p)
+ : cpu(c), platform(p)
+ { }
+ void process() { platform->intrctrl->post(cpu, ArmISA::INT_IRQ, 0);}
+ const char *description() const { return "Post Interrupt to CPU"; }
+ };
+ PostIntEvent *postIntEvent[CPU_MAX];
+
+ public:
+ typedef Pl390Params Params;
+ const Params *
+ params() const
+ {
+ return dynamic_cast<const Params *>(_params);
+ }
+ Pl390(const Params *p);
+
+ /** Return the address ranges used by the Gic
+ * This is the distributor address + all cpu addresses
+ */
+ virtual AddrRangeList getAddrRanges() const;
+
+ /** A PIO read to the device, immediately split up into
+ * readDistributor() or readCpu()
+ */
+ virtual Tick read(PacketPtr pkt);
+
+ /** A PIO read to the device, immediately split up into
+ * writeDistributor() or writeCpu()
+ */
+ virtual Tick write(PacketPtr pkt);
+
+ /** Handle a read to the distributor poriton of the GIC
+ * @param pkt packet to respond to
+ */
+ Tick readDistributor(PacketPtr pkt);
+
+ /** Handle a read to the cpu poriton of the GIC
+ * @param pkt packet to respond to
+ */
+ Tick readCpu(PacketPtr pkt);
+
+ /** Handle a write to the distributor poriton of the GIC
+ * @param pkt packet to respond to
+ */
+ Tick writeDistributor(PacketPtr pkt);
+
+ /** Handle a write to the cpu poriton of the GIC
+ * @param pkt packet to respond to
+ */
+ Tick writeCpu(PacketPtr pkt);
+
+ /** Post an interrupt from a device that is connected to the Gic.
+ * Depending on the configuration, the gic will pass this interrupt
+ * on through to a CPU.
+ * @param number number of interrupt to send */
+ void sendInt(uint32_t number);
+
+ /** Interface call for private peripheral interrupts */
+ void sendPPInt(uint32_t num, uint32_t cpu);
+
+ /** Clear an interrupt from a device that is connected to the Gic
+ * Depending on the configuration, the gic may de-assert it's cpu line
+ * @param number number of interrupt to send */
+ void clearInt(uint32_t number);
+
+ /* Various functions fer testing and debugging */
+ void driveSPI(uint32_t spi);
+ void driveLegIRQ(bool state);
+ void driveLegFIQ(bool state);
+ void driveIrqEn(bool state);
+
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string §ion);
+
+};
+
+#endif //__DEV_ARM_GIC_H__
#include "dev/arm/amba_device.hh"
#include "params/Pl050.hh"
-class Gic;
-
class Pl050 : public AmbaIntDevice, public VncKeyboard, public VncMouse
{
protected:
#include "debug/Checkpoint.hh"
#include "debug/Uart.hh"
#include "dev/arm/amba_device.hh"
-#include "dev/arm/gic.hh"
+#include "dev/arm/base_gic.hh"
#include "dev/arm/pl011.hh"
#include "dev/terminal.hh"
#include "mem/packet.hh"
#include "dev/uart.hh"
#include "params/Pl011.hh"
-class Gic;
+class BaseGic;
class Pl011 : public Uart
{
int intNum;
/** Gic to use for interrupting */
- Gic *gic;
+ BaseGic *gic;
/** Should the simulation end on an EOT */
bool endOnEOT;
#include "debug/PL111.hh"
#include "debug/Uart.hh"
#include "dev/arm/amba_device.hh"
-#include "dev/arm/gic.hh"
+#include "dev/arm/base_gic.hh"
#include "dev/arm/pl111.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
+#include "sim/system.hh"
// clang complains about std::set being overloaded with Packet::set if
// we open up the entire namespace std
#include "params/Pl111.hh"
#include "sim/serialize.hh"
-class Gic;
class VncInput;
class Bitmap;
#include "config/the_isa.hh"
#include "cpu/intr_control.hh"
-#include "dev/arm/gic.hh"
+#include "dev/arm/base_gic.hh"
#include "dev/arm/realview.hh"
#include "dev/terminal.hh"
#include "sim/system.hh"
#include "dev/platform.hh"
#include "params/RealView.hh"
-class Gic;
+class BaseGic;
class IdeController;
class System;
/** Pointer to the system */
System *system;
- Gic *gic;
+ BaseGic *gic;
public:
typedef RealViewParams Params;
RealView(const Params *p);
/** Give platform a pointer to interrupt controller */
- void setGic(Gic *_gic) { gic = _gic; }
+ void setGic(BaseGic *_gic) { gic = _gic; }
/**
* Cause the cpu to post a serial interrupt to the CPU.
#include "base/trace.hh"
#include "debug/Checkpoint.hh"
#include "debug/Timer.hh"
-#include "dev/arm/gic.hh"
+#include "dev/arm/base_gic.hh"
#include "dev/arm/timer_cpulocal.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
* Technical Reference Manual rev r2p2 (ARM DDI 0407F)
*/
-class Gic;
+class BaseGic;
class CpuLocalTimer : public BasicPioDevice
{
static const int CPU_MAX = 8;
/** Pointer to the GIC for causing an interrupt */
- Gic *gic;
+ BaseGic *gic;
/** Timers that do the actual work */
Timer localTimer[CPU_MAX];
#include "base/trace.hh"
#include "debug/Checkpoint.hh"
#include "debug/Timer.hh"
-#include "dev/arm/gic.hh"
+#include "dev/arm/base_gic.hh"
#include "dev/arm/timer_sp804.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
* This implements the dual Sp804 timer block
*/
-class Gic;
+class BaseGic;
class Sp804 : public AmbaDevice
{
};
/** Pointer to the GIC for causing an interrupt */
- Gic *gic;
+ BaseGic *gic;
/** Timers that do the actual work */
Timer timer0;