vgic.cc revision 12092
12115Shsul@eecs.umich.edu/*
21881Sbinkertn@umich.edu * Copyright (c) 2013 ARM Limited
31881Sbinkertn@umich.edu * All rights reserved
41881Sbinkertn@umich.edu *
51881Sbinkertn@umich.edu * The license below extends only to copyright in the software and shall
61881Sbinkertn@umich.edu * not be construed as granting a license to any other intellectual
71881Sbinkertn@umich.edu * property including but not limited to intellectual property relating
81881Sbinkertn@umich.edu * to a hardware implementation of the functionality of the software
91881Sbinkertn@umich.edu * licensed hereunder.  You may use the software subject to the license
101881Sbinkertn@umich.edu * terms below provided that you ensure that this notice is replicated
111881Sbinkertn@umich.edu * unmodified and in its entirety in all distributions of the software,
121881Sbinkertn@umich.edu * modified or unmodified, in source code or in binary form.
131881Sbinkertn@umich.edu *
141881Sbinkertn@umich.edu * Redistribution and use in source and binary forms, with or without
151881Sbinkertn@umich.edu * modification, are permitted provided that the following conditions are
161881Sbinkertn@umich.edu * met: redistributions of source code must retain the above copyright
171881Sbinkertn@umich.edu * notice, this list of conditions and the following disclaimer;
181881Sbinkertn@umich.edu * redistributions in binary form must reproduce the above copyright
191881Sbinkertn@umich.edu * notice, this list of conditions and the following disclaimer in the
201881Sbinkertn@umich.edu * documentation and/or other materials provided with the distribution;
211881Sbinkertn@umich.edu * neither the name of the copyright holders nor the names of its
221881Sbinkertn@umich.edu * contributors may be used to endorse or promote products derived from
231881Sbinkertn@umich.edu * this software without specific prior written permission.
241881Sbinkertn@umich.edu *
251881Sbinkertn@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
261881Sbinkertn@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
271881Sbinkertn@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
281881Sbinkertn@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
291881Sbinkertn@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
301881Sbinkertn@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
312006Sbinkertn@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
321881Sbinkertn@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
331881Sbinkertn@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
341881Sbinkertn@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
351881Sbinkertn@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
361881Sbinkertn@umich.edu *
372006Sbinkertn@umich.edu * Authors: Matt Evans
381881Sbinkertn@umich.edu */
392006Sbinkertn@umich.edu
402006Sbinkertn@umich.edu#include "dev/arm/vgic.hh"
412006Sbinkertn@umich.edu
421881Sbinkertn@umich.edu#include "base/trace.hh"
431881Sbinkertn@umich.edu#include "debug/Checkpoint.hh"
441881Sbinkertn@umich.edu#include "debug/VGIC.hh"
451881Sbinkertn@umich.edu#include "dev/arm/base_gic.hh"
461881Sbinkertn@umich.edu#include "dev/terminal.hh"
471881Sbinkertn@umich.edu#include "mem/packet.hh"
481881Sbinkertn@umich.edu#include "mem/packet_access.hh"
491881Sbinkertn@umich.edu
501881Sbinkertn@umich.eduVGic::VGic(const Params *p)
511881Sbinkertn@umich.edu    : PioDevice(p), platform(p->platform), gic(p->gic), vcpuAddr(p->vcpu_addr),
521881Sbinkertn@umich.edu      hvAddr(p->hv_addr), pioDelay(p->pio_delay),
531881Sbinkertn@umich.edu      maintInt(p->ppint)
541881Sbinkertn@umich.edu{
551881Sbinkertn@umich.edu    for (int x = 0; x < VGIC_CPU_MAX; x++) {
561881Sbinkertn@umich.edu        postVIntEvent[x] = new PostVIntEvent(x, p->platform);
571881Sbinkertn@umich.edu        maintIntPosted[x] = false;
581881Sbinkertn@umich.edu        vIntPosted[x] = false;
591881Sbinkertn@umich.edu    }
601881Sbinkertn@umich.edu    assert(sys->numRunningContexts() <= VGIC_CPU_MAX);
611881Sbinkertn@umich.edu}
621881Sbinkertn@umich.edu
631881Sbinkertn@umich.eduVGic::~VGic()
641881Sbinkertn@umich.edu{
651881Sbinkertn@umich.edu    for (int x = 0; x < VGIC_CPU_MAX; x++)
661881Sbinkertn@umich.edu        delete postVIntEvent[x];
671881Sbinkertn@umich.edu}
681881Sbinkertn@umich.edu
691881Sbinkertn@umich.eduTick
701881Sbinkertn@umich.eduVGic::read(PacketPtr pkt)
711881Sbinkertn@umich.edu{
721881Sbinkertn@umich.edu    Addr addr = pkt->getAddr();
731881Sbinkertn@umich.edu
741881Sbinkertn@umich.edu    if (addr >= vcpuAddr && addr < vcpuAddr + GICV_SIZE)
751881Sbinkertn@umich.edu        return readVCpu(pkt);
761881Sbinkertn@umich.edu    else if (addr >= hvAddr && addr < hvAddr + GICH_REG_SIZE)
771881Sbinkertn@umich.edu        return readCtrl(pkt);
781881Sbinkertn@umich.edu    else
792115Shsul@eecs.umich.edu        panic("Read to unknown address %#x\n", pkt->getAddr());
801881Sbinkertn@umich.edu}
811881Sbinkertn@umich.edu
821881Sbinkertn@umich.eduTick
831881Sbinkertn@umich.eduVGic::write(PacketPtr pkt)
841881Sbinkertn@umich.edu{
851881Sbinkertn@umich.edu    Addr addr = pkt->getAddr();
862115Shsul@eecs.umich.edu
871881Sbinkertn@umich.edu    if (addr >= vcpuAddr && addr < vcpuAddr + GICV_SIZE)
881881Sbinkertn@umich.edu        return writeVCpu(pkt);
891881Sbinkertn@umich.edu    else if (addr >= hvAddr && addr < hvAddr + GICH_REG_SIZE)
901881Sbinkertn@umich.edu        return writeCtrl(pkt);
911881Sbinkertn@umich.edu    else
921881Sbinkertn@umich.edu        panic("Write to unknown address %#x\n", pkt->getAddr());
931881Sbinkertn@umich.edu}
941881Sbinkertn@umich.edu
951881Sbinkertn@umich.eduTick
961881Sbinkertn@umich.eduVGic::readVCpu(PacketPtr pkt)
971881Sbinkertn@umich.edu{
981881Sbinkertn@umich.edu    Addr daddr = pkt->getAddr() - vcpuAddr;
991881Sbinkertn@umich.edu
1001881Sbinkertn@umich.edu    ContextID ctx_id = pkt->req->contextId();
1011881Sbinkertn@umich.edu    assert(ctx_id < VGIC_CPU_MAX);
1021881Sbinkertn@umich.edu    struct vcpuIntData *vid = &vcpuData[ctx_id];
1031881Sbinkertn@umich.edu
1041881Sbinkertn@umich.edu    DPRINTF(VGIC, "VGIC VCPU read register %#x\n", daddr);
1051881Sbinkertn@umich.edu
1061881Sbinkertn@umich.edu    switch (daddr) {
1071881Sbinkertn@umich.edu      case GICV_CTLR:
1081881Sbinkertn@umich.edu        pkt->set<uint32_t>(vid->vctrl);
1091881Sbinkertn@umich.edu        break;
1101881Sbinkertn@umich.edu      case GICV_IAR: {
1111881Sbinkertn@umich.edu          int i = findHighestPendingLR(vid);
1121881Sbinkertn@umich.edu          if (i < 0 || !vid->vctrl.En) {
1131881Sbinkertn@umich.edu              pkt->set<uint32_t>(1023); // "No int" marker
1141881Sbinkertn@umich.edu          } else {
1151881Sbinkertn@umich.edu              ListReg *lr = &vid->LR[i];
1161881Sbinkertn@umich.edu
1171881Sbinkertn@umich.edu              pkt->set<uint32_t>(lr->VirtualID |
1181881Sbinkertn@umich.edu                                 (((int)lr->CpuID) << 10));
1191881Sbinkertn@umich.edu              // We don't support auto-EOI of HW interrupts via real GIC!
1201881Sbinkertn@umich.edu              // Fortunately, KVM doesn't use this.  How about Xen...? Ulp!
1211881Sbinkertn@umich.edu              if (lr->HW)
1221881Sbinkertn@umich.edu                  panic("VGIC does not support 'HW' List Register feature (LR %#x)!\n",
1231881Sbinkertn@umich.edu                        *lr);
1241881Sbinkertn@umich.edu              lr->State = LR_ACTIVE;
1252115Shsul@eecs.umich.edu              DPRINTF(VGIC, "Consumed interrupt %d (cpu%d) from LR%d (EOI%d)\n",
1261881Sbinkertn@umich.edu                      lr->VirtualID, lr->CpuID, i, lr->EOI);
1271881Sbinkertn@umich.edu          }
1281881Sbinkertn@umich.edu      } break;
1292115Shsul@eecs.umich.edu      default:
1301881Sbinkertn@umich.edu        panic("VGIC VCPU read of bad address %#x\n", daddr);
1311881Sbinkertn@umich.edu    }
1321881Sbinkertn@umich.edu
1332115Shsul@eecs.umich.edu    updateIntState(ctx_id);
1341881Sbinkertn@umich.edu
1351881Sbinkertn@umich.edu    pkt->makeAtomicResponse();
1361881Sbinkertn@umich.edu    return pioDelay;
1371881Sbinkertn@umich.edu}
1381881Sbinkertn@umich.edu
1391881Sbinkertn@umich.eduTick
1401881Sbinkertn@umich.eduVGic::readCtrl(PacketPtr pkt)
1411881Sbinkertn@umich.edu{
1421881Sbinkertn@umich.edu    Addr daddr = pkt->getAddr() - hvAddr;
1431881Sbinkertn@umich.edu
1441881Sbinkertn@umich.edu    ContextID ctx_id = pkt->req->contextId();
1452115Shsul@eecs.umich.edu
1462115Shsul@eecs.umich.edu    DPRINTF(VGIC, "VGIC HVCtrl read register %#x\n", daddr);
1472115Shsul@eecs.umich.edu
1482115Shsul@eecs.umich.edu    /* Munge the address: 0-0xfff is the usual space banked by requester CPU.
1492115Shsul@eecs.umich.edu     * Anything > that is 0x200-sized slices of 'per CPU' regs.
1502115Shsul@eecs.umich.edu     */
1512115Shsul@eecs.umich.edu    if (daddr & ~0x1ff) {
1522115Shsul@eecs.umich.edu        ctx_id = (daddr >> 9);
1532115Shsul@eecs.umich.edu        if (ctx_id > 8)
1542115Shsul@eecs.umich.edu            panic("VGIC: Weird unbanked hv ctrl address %#x!\n", daddr);
1552115Shsul@eecs.umich.edu        daddr &= ~0x1ff;
1562115Shsul@eecs.umich.edu    }
1572115Shsul@eecs.umich.edu    assert(ctx_id < VGIC_CPU_MAX);
1582115Shsul@eecs.umich.edu    struct vcpuIntData *vid = &vcpuData[ctx_id];
1592115Shsul@eecs.umich.edu
1602115Shsul@eecs.umich.edu    switch (daddr) {
1612115Shsul@eecs.umich.edu      case GICH_HCR:
1622115Shsul@eecs.umich.edu        pkt->set<uint32_t>(vid->hcr);
1632115Shsul@eecs.umich.edu        break;
1642115Shsul@eecs.umich.edu
1652115Shsul@eecs.umich.edu      case GICH_VTR:
1661881Sbinkertn@umich.edu        pkt->set<uint32_t>(0x44000000 | (NUM_LR - 1));
1671881Sbinkertn@umich.edu        break;
1681881Sbinkertn@umich.edu
1691881Sbinkertn@umich.edu      case GICH_VMCR:
1701881Sbinkertn@umich.edu        pkt->set<uint32_t>(
1711881Sbinkertn@umich.edu            ((uint32_t)vid->VMPriMask << 27) |
1721881Sbinkertn@umich.edu            ((uint32_t)vid->VMBP << 21) |
1731881Sbinkertn@umich.edu            ((uint32_t)vid->VMABP << 18) |
1741881Sbinkertn@umich.edu            ((uint32_t)vid->VEM << 9) |
1751881Sbinkertn@umich.edu            ((uint32_t)vid->VMCBPR << 4) |
1762006Sbinkertn@umich.edu            ((uint32_t)vid->VMFiqEn << 3) |
1771881Sbinkertn@umich.edu            ((uint32_t)vid->VMAckCtl << 2) |
1781881Sbinkertn@umich.edu            ((uint32_t)vid->VMGrp1En << 1) |
1791881Sbinkertn@umich.edu            ((uint32_t)vid->VMGrp0En << 0)
1801881Sbinkertn@umich.edu            );
1811881Sbinkertn@umich.edu        break;
1821881Sbinkertn@umich.edu
1832115Shsul@eecs.umich.edu      case GICH_MISR:
1842115Shsul@eecs.umich.edu        pkt->set<uint32_t>(getMISR(vid));
1851881Sbinkertn@umich.edu        break;
1861881Sbinkertn@umich.edu
1871881Sbinkertn@umich.edu      case GICH_EISR0:
1881881Sbinkertn@umich.edu        pkt->set<uint32_t>(vid->eisr & 0xffffffff);
1891881Sbinkertn@umich.edu        break;
1902115Shsul@eecs.umich.edu
1911881Sbinkertn@umich.edu      case GICH_EISR1:
1921881Sbinkertn@umich.edu        pkt->set<uint32_t>(vid->eisr >> 32);
1932115Shsul@eecs.umich.edu        break;
1941881Sbinkertn@umich.edu
1951881Sbinkertn@umich.edu      case GICH_ELSR0: {
1961881Sbinkertn@umich.edu          uint32_t bm = 0;
1971881Sbinkertn@umich.edu          for (int i = 0; i < ((NUM_LR < 32) ? NUM_LR : 32); i++) {
1981881Sbinkertn@umich.edu              if (!vid->LR[i].State)
1992115Shsul@eecs.umich.edu                  bm |= 1 << i;
2002115Shsul@eecs.umich.edu          }
2012006Sbinkertn@umich.edu          pkt->set<uint32_t>(bm);
2022115Shsul@eecs.umich.edu      } break;
2031881Sbinkertn@umich.edu
2041881Sbinkertn@umich.edu      case GICH_ELSR1: {
2052115Shsul@eecs.umich.edu          uint32_t bm = 0;
2062115Shsul@eecs.umich.edu          for (int i = 32; i < NUM_LR; i++) {
2072115Shsul@eecs.umich.edu              if (!vid->LR[i].State)
2082115Shsul@eecs.umich.edu                  bm |= 1 << (i-32);
2092115Shsul@eecs.umich.edu          }
2102115Shsul@eecs.umich.edu          pkt->set<uint32_t>(bm);
2111881Sbinkertn@umich.edu      } break;
2121881Sbinkertn@umich.edu
2131881Sbinkertn@umich.edu      case GICH_APR0:
2141881Sbinkertn@umich.edu        warn_once("VGIC GICH_APR read!\n");
2151881Sbinkertn@umich.edu        pkt->set<uint32_t>(0);
2161881Sbinkertn@umich.edu        break;
2171881Sbinkertn@umich.edu
2181881Sbinkertn@umich.edu      case GICH_LR0:
2191881Sbinkertn@umich.edu      case GICH_LR1:
2202006Sbinkertn@umich.edu      case GICH_LR2:
2212006Sbinkertn@umich.edu      case GICH_LR3:
2221881Sbinkertn@umich.edu        pkt->set<uint32_t>(vid->LR[(daddr - GICH_LR0) >> 2]);
2231881Sbinkertn@umich.edu        break;
2241881Sbinkertn@umich.edu
2251881Sbinkertn@umich.edu      default:
2261881Sbinkertn@umich.edu        panic("VGIC HVCtrl read of bad address %#x\n", daddr);
2271881Sbinkertn@umich.edu    }
2281881Sbinkertn@umich.edu
2292006Sbinkertn@umich.edu    pkt->makeAtomicResponse();
2302006Sbinkertn@umich.edu    return pioDelay;
2312006Sbinkertn@umich.edu}
2322006Sbinkertn@umich.edu
2332006Sbinkertn@umich.eduTick
2342006Sbinkertn@umich.eduVGic::writeVCpu(PacketPtr pkt)
2352006Sbinkertn@umich.edu{
2362006Sbinkertn@umich.edu    Addr daddr = pkt->getAddr() - vcpuAddr;
2372006Sbinkertn@umich.edu
2382006Sbinkertn@umich.edu    ContextID ctx_id = pkt->req->contextId();
2392006Sbinkertn@umich.edu    assert(ctx_id < VGIC_CPU_MAX);
2402006Sbinkertn@umich.edu    struct vcpuIntData *vid = &vcpuData[ctx_id];
2412006Sbinkertn@umich.edu
2422006Sbinkertn@umich.edu    DPRINTF(VGIC, "VGIC VCPU write register %#x <= %#x\n", daddr, pkt->get<uint32_t>());
2432006Sbinkertn@umich.edu
2442006Sbinkertn@umich.edu    switch (daddr) {
2452006Sbinkertn@umich.edu      case GICV_CTLR:
2462006Sbinkertn@umich.edu        vid->vctrl = pkt->get<uint32_t>();
2472006Sbinkertn@umich.edu        break;
2482006Sbinkertn@umich.edu      case GICV_PMR:
2492006Sbinkertn@umich.edu        vid->VMPriMask = pkt->get<uint32_t>();
2502006Sbinkertn@umich.edu        break;
2512006Sbinkertn@umich.edu      case GICV_EOIR: {
2521881Sbinkertn@umich.edu          // We don't handle the split EOI-then-DIR mode.  Linux (guest)
2532006Sbinkertn@umich.edu          // doesn't need it though.
2541881Sbinkertn@umich.edu          assert(!vid->vctrl.EOImode);
2551881Sbinkertn@umich.edu          uint32_t w = pkt->get<uint32_t>();
2561881Sbinkertn@umich.edu          unsigned int virq = w & 0x3ff;
2571881Sbinkertn@umich.edu          unsigned int vcpu = (w >> 10) & 7;
2581881Sbinkertn@umich.edu          int i = findLRForVIRQ(vid, virq, vcpu);
2591881Sbinkertn@umich.edu          if (i < 0) {
2601881Sbinkertn@umich.edu              DPRINTF(VGIC, "EOIR: No LR for irq %d(cpu%d)\n", virq, vcpu);
2611881Sbinkertn@umich.edu          } else {
2621881Sbinkertn@umich.edu              DPRINTF(VGIC, "EOIR: Found LR%d for irq %d(cpu%d)\n", i, virq, vcpu);
2631881Sbinkertn@umich.edu              ListReg *lr = &vid->LR[i];
2641881Sbinkertn@umich.edu              lr->State = 0;
2651881Sbinkertn@umich.edu              // Maintenance interrupt -- via eisr -- is flagged when
2661881Sbinkertn@umich.edu              // LRs have EOI=1 and State=INVALID!
2671881Sbinkertn@umich.edu          }
2681881Sbinkertn@umich.edu      } break;
2691881Sbinkertn@umich.edu      default:
2701881Sbinkertn@umich.edu        panic("VGIC VCPU write %#x to unk address %#x\n", pkt->get<uint32_t>(), daddr);
2711881Sbinkertn@umich.edu    }
2721881Sbinkertn@umich.edu
2731881Sbinkertn@umich.edu    // This updates the EISRs and flags IRQs:
2741881Sbinkertn@umich.edu    updateIntState(ctx_id);
2751881Sbinkertn@umich.edu
2761881Sbinkertn@umich.edu    pkt->makeAtomicResponse();
2771881Sbinkertn@umich.edu    return pioDelay;
2781881Sbinkertn@umich.edu}
2791881Sbinkertn@umich.edu
2801881Sbinkertn@umich.eduTick
2811881Sbinkertn@umich.eduVGic::writeCtrl(PacketPtr pkt)
2821881Sbinkertn@umich.edu{
2832115Shsul@eecs.umich.edu    Addr daddr = pkt->getAddr() - hvAddr;
2842117Shsul@eecs.umich.edu
2852117Shsul@eecs.umich.edu    ContextID ctx_id = pkt->req->contextId();
2861881Sbinkertn@umich.edu
2872006Sbinkertn@umich.edu    DPRINTF(VGIC, "VGIC HVCtrl write register %#x <= %#x\n", daddr, pkt->get<uint32_t>());
2882006Sbinkertn@umich.edu
2892006Sbinkertn@umich.edu    /* Munge the address: 0-0xfff is the usual space banked by requester CPU.
2902006Sbinkertn@umich.edu     * Anything > that is 0x200-sized slices of 'per CPU' regs.
2911881Sbinkertn@umich.edu     */
2921881Sbinkertn@umich.edu    if (daddr & ~0x1ff) {
2931881Sbinkertn@umich.edu        ctx_id = (daddr >> 9);
2941881Sbinkertn@umich.edu        if (ctx_id > 8)
2951881Sbinkertn@umich.edu            panic("VGIC: Weird unbanked hv ctrl address %#x!\n", daddr);
2961881Sbinkertn@umich.edu        daddr &= ~0x1ff;
2972006Sbinkertn@umich.edu    }
2982006Sbinkertn@umich.edu    assert(ctx_id < VGIC_CPU_MAX);
2991881Sbinkertn@umich.edu    struct vcpuIntData *vid = &vcpuData[ctx_id];
3002115Shsul@eecs.umich.edu
301    switch (daddr) {
302      case GICH_HCR:
303        vid->hcr = pkt->get<uint32_t>();
304        // update int state
305        break;
306
307      case GICH_VMCR: {
308          uint32_t d = pkt->get<uint32_t>();
309          vid->VMPriMask = d >> 27;
310          vid->VMBP = (d >> 21) & 7;
311          vid->VMABP = (d >> 18) & 7;
312          vid->VEM = (d >> 9) & 1;
313          vid->VMCBPR = (d >> 4) & 1;
314          vid->VMFiqEn = (d >> 3) & 1;
315          vid->VMAckCtl = (d >> 2) & 1;
316          vid->VMGrp1En = (d >> 1) & 1;
317          vid->VMGrp0En = d & 1;
318      } break;
319
320      case GICH_APR0:
321        warn_once("VGIC GICH_APR0 written, ignored\n");
322        break;
323
324      case GICH_LR0:
325      case GICH_LR1:
326      case GICH_LR2:
327      case GICH_LR3:
328        vid->LR[(daddr - GICH_LR0) >> 2] = pkt->get<uint32_t>();
329        // update int state
330        break;
331
332      default:
333        panic("VGIC HVCtrl write to bad address %#x\n", daddr);
334    }
335
336    updateIntState(ctx_id);
337
338    pkt->makeAtomicResponse();
339    return pioDelay;
340}
341
342
343uint32_t
344VGic::getMISR(struct vcpuIntData *vid)
345{
346    return (!!vid->hcr.VGrp1DIE && !vid->VMGrp1En ? 0x80 : 0) |
347        (!!vid->hcr.VGrp1EIE &&  vid->VMGrp1En ? 0x40 : 0) |
348        (!!vid->hcr.VGrp0DIE && !vid->VMGrp0En ? 0x20 : 0) |
349        (!!vid->hcr.VGrp0EIE &&  vid->VMGrp0En ? 0x10 : 0) |
350        (!!vid->hcr.NPIE && !lrPending(vid) ? 0x08 : 0) |
351        (!!vid->hcr.LRENPIE && vid->hcr.EOICount ? 0x04 : 0) |
352        (!!vid->hcr.UIE && lrValid(vid) <= 1 ? 0x02 : 0) |
353        (vid->eisr ? 0x01 : 0);
354}
355
356void
357VGic::postVInt(uint32_t cpu, Tick when)
358{
359    DPRINTF(VGIC, "Posting VIRQ to %d\n", cpu);
360    if (!(postVIntEvent[cpu]->scheduled()))
361        eventq->schedule(postVIntEvent[cpu], when);
362}
363
364void
365VGic::unPostVInt(uint32_t cpu)
366{
367    DPRINTF(VGIC, "Unposting VIRQ to %d\n", cpu);
368    platform->intrctrl->clear(cpu, ArmISA::INT_VIRT_IRQ, 0);
369}
370
371void
372VGic::postMaintInt(uint32_t cpu)
373{
374    DPRINTF(VGIC, "Posting maintenance PPI to GIC/cpu%d\n", cpu);
375    // Linux DT configures this as Level.
376    gic->sendPPInt(maintInt, cpu);
377}
378
379void
380VGic::unPostMaintInt(uint32_t cpu)
381{
382    DPRINTF(VGIC, "Unposting maintenance PPI to GIC/cpu%d\n", cpu);
383    gic->clearPPInt(maintInt, cpu);
384}
385
386/* Update state (in general); something concerned with ctx_id has changed.
387 * This may raise a maintenance interrupt.
388 */
389void
390VGic::updateIntState(ContextID ctx_id)
391{
392    // @todo This should update APRs!
393
394    // Build EISR contents:
395    // (Cached so that regs can read them without messing about again)
396    struct vcpuIntData *tvid = &vcpuData[ctx_id];
397
398    tvid->eisr = 0;
399    for (int i = 0; i < NUM_LR; i++) {
400        if (!tvid->LR[i].State && tvid->LR[i].EOI) {
401            tvid->eisr |= 1 << i;
402        }
403    }
404
405    assert(sys->numRunningContexts() <= VGIC_CPU_MAX);
406    for (int i = 0; i < sys->numRunningContexts(); i++) {
407        struct vcpuIntData *vid = &vcpuData[i];
408        // Are any LRs active that weren't before?
409        if (!vIntPosted[i]) {
410            if (lrPending(vid) && vid->vctrl.En) {
411                vIntPosted[i] = true;
412                postVInt(i, curTick() + 1);
413            }
414        } else if (!lrPending(vid)) {
415            vIntPosted[i] = false;
416            unPostVInt(i);
417        }
418
419        // Any maintenance ints to send?
420        if (!maintIntPosted[i]) {
421            if (vid->hcr.En && getMISR(vid)) {
422                maintIntPosted[i] = true;
423                postMaintInt(i);
424            }
425        } else {
426            if (!vid->hcr.En || !getMISR(vid)) {
427                unPostMaintInt(i);
428                maintIntPosted[i] = false;
429            }
430        }
431    }
432}
433
434AddrRangeList
435VGic::getAddrRanges() const
436{
437    AddrRangeList ranges;
438    ranges.push_back(RangeSize(hvAddr, GICH_REG_SIZE));
439    ranges.push_back(RangeSize(vcpuAddr, GICV_SIZE));
440    return ranges;
441}
442
443void
444VGic::serialize(CheckpointOut &cp) const
445{
446    Tick interrupt_time[VGIC_CPU_MAX];
447    for (uint32_t cpu = 0; cpu < VGIC_CPU_MAX; cpu++) {
448        interrupt_time[cpu] = 0;
449        if (postVIntEvent[cpu]->scheduled()) {
450            interrupt_time[cpu] = postVIntEvent[cpu]->when();
451        }
452    }
453
454    DPRINTF(Checkpoint, "Serializing VGIC\n");
455
456    SERIALIZE_ARRAY(interrupt_time, VGIC_CPU_MAX);
457    SERIALIZE_ARRAY(maintIntPosted, VGIC_CPU_MAX);
458    SERIALIZE_ARRAY(vIntPosted, VGIC_CPU_MAX);
459    SERIALIZE_SCALAR(vcpuAddr);
460    SERIALIZE_SCALAR(hvAddr);
461    SERIALIZE_SCALAR(pioDelay);
462    SERIALIZE_SCALAR(maintInt);
463
464    for (uint32_t cpu = 0; cpu < VGIC_CPU_MAX; cpu++)
465        vcpuData[cpu].serializeSection(cp, csprintf("vcpuData%d", cpu));
466}
467
468void
469VGic::vcpuIntData::serialize(CheckpointOut &cp) const
470{
471    uint32_t vctrl_val = vctrl;
472    SERIALIZE_SCALAR(vctrl_val);
473    uint32_t hcr_val = hcr;
474    SERIALIZE_SCALAR(hcr_val);
475    uint64_t eisr_val = eisr;
476    SERIALIZE_SCALAR(eisr_val);
477    uint8_t VMGrp0En_val = VMGrp0En;
478    SERIALIZE_SCALAR(VMGrp0En_val);
479    uint8_t VMGrp1En_val = VMGrp1En;
480    SERIALIZE_SCALAR(VMGrp1En_val);
481    uint8_t VMAckCtl_val = VMAckCtl;
482    SERIALIZE_SCALAR(VMAckCtl_val);
483    uint8_t VMFiqEn_val = VMFiqEn;
484    SERIALIZE_SCALAR(VMFiqEn_val);
485    uint8_t VMCBPR_val = VMCBPR;
486    SERIALIZE_SCALAR(VMCBPR_val);
487    uint8_t VEM_val = VEM;
488    SERIALIZE_SCALAR(VEM_val);
489    uint8_t VMABP_val = VMABP;
490    SERIALIZE_SCALAR(VMABP_val);
491    uint8_t VMBP_val = VMBP;
492    SERIALIZE_SCALAR(VMBP_val);
493    uint8_t VMPriMask_val = VMPriMask;
494    SERIALIZE_SCALAR(VMPriMask_val);
495
496    for (int i = 0; i < NUM_LR; i++) {
497        ScopedCheckpointSection sec_lr(cp, csprintf("LR%d", i));
498        paramOut(cp, "lr", LR[i]);
499    }
500}
501
502void VGic::unserialize(CheckpointIn &cp)
503{
504    DPRINTF(Checkpoint, "Unserializing Arm GIC\n");
505
506    Tick interrupt_time[VGIC_CPU_MAX];
507    UNSERIALIZE_ARRAY(interrupt_time, VGIC_CPU_MAX);
508    for (uint32_t cpu = 0; cpu < VGIC_CPU_MAX; cpu++) {
509        if (interrupt_time[cpu])
510            schedule(postVIntEvent[cpu], interrupt_time[cpu]);
511
512        vcpuData[cpu].unserializeSection(cp, csprintf("vcpuData%d", cpu));
513    }
514    UNSERIALIZE_ARRAY(maintIntPosted, VGIC_CPU_MAX);
515    UNSERIALIZE_ARRAY(vIntPosted, VGIC_CPU_MAX);
516    UNSERIALIZE_SCALAR(vcpuAddr);
517    UNSERIALIZE_SCALAR(hvAddr);
518    UNSERIALIZE_SCALAR(pioDelay);
519    UNSERIALIZE_SCALAR(maintInt);
520}
521
522void
523VGic::vcpuIntData::unserialize(CheckpointIn &cp)
524{
525    paramIn(cp, "vctrl_val", vctrl);
526    paramIn(cp, "hcr_val", hcr);
527    paramIn(cp, "eisr_val", eisr);
528    paramIn(cp, "VMGrp0En_val", VMGrp0En);
529    paramIn(cp, "VMGrp1En_val", VMGrp1En);
530    paramIn(cp, "VMAckCtl_val", VMAckCtl);
531    paramIn(cp, "VMFiqEn_val", VMFiqEn);
532    paramIn(cp, "VMCBPR_val", VMCBPR);
533    paramIn(cp, "VEM_val", VEM);
534    paramIn(cp, "VMABP_val", VMABP);
535    paramIn(cp, "VMPriMask_val", VMPriMask);
536
537    for (int i = 0; i < NUM_LR; i++) {
538        ScopedCheckpointSection sec_lr(cp, csprintf("LR%d", i));
539        paramIn(cp, "lr", LR[i]);
540    }
541}
542
543VGic *
544VGicParams::create()
545{
546    return new VGic(this);
547}
548