vgic.cc revision 13506:7803580f48d4
12810Srdreslin@umich.edu/*
211375Sandreas.hansson@arm.com * Copyright (c) 2013,2018 ARM Limited
311051Sandreas.hansson@arm.com * All rights reserved
411051Sandreas.hansson@arm.com *
511051Sandreas.hansson@arm.com * The license below extends only to copyright in the software and shall
611051Sandreas.hansson@arm.com * not be construed as granting a license to any other intellectual
711051Sandreas.hansson@arm.com * property including but not limited to intellectual property relating
811051Sandreas.hansson@arm.com * to a hardware implementation of the functionality of the software
911051Sandreas.hansson@arm.com * licensed hereunder.  You may use the software subject to the license
1011051Sandreas.hansson@arm.com * terms below provided that you ensure that this notice is replicated
1111051Sandreas.hansson@arm.com * unmodified and in its entirety in all distributions of the software,
1211051Sandreas.hansson@arm.com * modified or unmodified, in source code or in binary form.
1311051Sandreas.hansson@arm.com *
1411051Sandreas.hansson@arm.com * Redistribution and use in source and binary forms, with or without
1511051Sandreas.hansson@arm.com * modification, are permitted provided that the following conditions are
162810Srdreslin@umich.edu * met: redistributions of source code must retain the above copyright
172810Srdreslin@umich.edu * notice, this list of conditions and the following disclaimer;
182810Srdreslin@umich.edu * redistributions in binary form must reproduce the above copyright
192810Srdreslin@umich.edu * notice, this list of conditions and the following disclaimer in the
202810Srdreslin@umich.edu * documentation and/or other materials provided with the distribution;
212810Srdreslin@umich.edu * neither the name of the copyright holders nor the names of its
222810Srdreslin@umich.edu * contributors may be used to endorse or promote products derived from
232810Srdreslin@umich.edu * this software without specific prior written permission.
242810Srdreslin@umich.edu *
252810Srdreslin@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
262810Srdreslin@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
272810Srdreslin@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
282810Srdreslin@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
292810Srdreslin@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
302810Srdreslin@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
312810Srdreslin@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
322810Srdreslin@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
332810Srdreslin@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
342810Srdreslin@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
352810Srdreslin@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
362810Srdreslin@umich.edu *
372810Srdreslin@umich.edu * Authors: Matt Evans
382810Srdreslin@umich.edu */
392810Srdreslin@umich.edu
402810Srdreslin@umich.edu#include "dev/arm/vgic.hh"
412810Srdreslin@umich.edu
4211051Sandreas.hansson@arm.com#include "base/trace.hh"
4311051Sandreas.hansson@arm.com#include "debug/Checkpoint.hh"
442810Srdreslin@umich.edu#include "debug/VGIC.hh"
4511051Sandreas.hansson@arm.com#include "dev/arm/base_gic.hh"
4611051Sandreas.hansson@arm.com#include "mem/packet.hh"
472810Srdreslin@umich.edu#include "mem/packet_access.hh"
482810Srdreslin@umich.edu
492810Srdreslin@umich.eduVGic::VGic(const Params *p)
502810Srdreslin@umich.edu    : PioDevice(p), gicvIIDR(p->gicv_iidr), platform(p->platform),
5111051Sandreas.hansson@arm.com      gic(p->gic), vcpuAddr(p->vcpu_addr), hvAddr(p->hv_addr),
522810Srdreslin@umich.edu      pioDelay(p->pio_delay), maintInt(p->ppint)
532810Srdreslin@umich.edu{
5411051Sandreas.hansson@arm.com    for (int x = 0; x < VGIC_CPU_MAX; x++) {
552810Srdreslin@umich.edu        postVIntEvent[x] = new EventFunctionWrapper(
5611051Sandreas.hansson@arm.com            [this, x]{ processPostVIntEvent(x); },
5711051Sandreas.hansson@arm.com            "Post VInterrupt to CPU");
5811051Sandreas.hansson@arm.com        maintIntPosted[x] = false;
5911051Sandreas.hansson@arm.com        vIntPosted[x] = false;
6011051Sandreas.hansson@arm.com    }
6111288Ssteve.reinhardt@amd.com    assert(sys->numRunningContexts() <= VGIC_CPU_MAX);
6211051Sandreas.hansson@arm.com}
6311051Sandreas.hansson@arm.com
6411051Sandreas.hansson@arm.comVGic::~VGic()
6511051Sandreas.hansson@arm.com{
6611051Sandreas.hansson@arm.com    for (int x = 0; x < VGIC_CPU_MAX; x++)
6711053Sandreas.hansson@arm.com        delete postVIntEvent[x];
6811053Sandreas.hansson@arm.com}
6911051Sandreas.hansson@arm.com
7011051Sandreas.hansson@arm.comTick
7111051Sandreas.hansson@arm.comVGic::read(PacketPtr pkt)
7211197Sandreas.hansson@arm.com{
7311197Sandreas.hansson@arm.com    Addr addr = pkt->getAddr();
7411199Sandreas.hansson@arm.com
7511197Sandreas.hansson@arm.com    if (addr >= vcpuAddr && addr < vcpuAddr + GICV_SIZE)
7611197Sandreas.hansson@arm.com        return readVCpu(pkt);
7711197Sandreas.hansson@arm.com    else if (addr >= hvAddr && addr < hvAddr + GICH_REG_SIZE)
7811051Sandreas.hansson@arm.com        return readCtrl(pkt);
7911051Sandreas.hansson@arm.com    else
8011051Sandreas.hansson@arm.com        panic("Read to unknown address %#x\n", pkt->getAddr());
8111051Sandreas.hansson@arm.com}
8211051Sandreas.hansson@arm.com
8311051Sandreas.hansson@arm.comTick
8411051Sandreas.hansson@arm.comVGic::write(PacketPtr pkt)
8511051Sandreas.hansson@arm.com{
8611051Sandreas.hansson@arm.com    Addr addr = pkt->getAddr();
8711051Sandreas.hansson@arm.com
8811051Sandreas.hansson@arm.com    if (addr >= vcpuAddr && addr < vcpuAddr + GICV_SIZE)
8911051Sandreas.hansson@arm.com        return writeVCpu(pkt);
9011051Sandreas.hansson@arm.com    else if (addr >= hvAddr && addr < hvAddr + GICH_REG_SIZE)
9111051Sandreas.hansson@arm.com        return writeCtrl(pkt);
9211051Sandreas.hansson@arm.com    else
9311051Sandreas.hansson@arm.com        panic("Write to unknown address %#x\n", pkt->getAddr());
9411051Sandreas.hansson@arm.com}
9511051Sandreas.hansson@arm.com
9611051Sandreas.hansson@arm.comTick
9711051Sandreas.hansson@arm.comVGic::readVCpu(PacketPtr pkt)
9811051Sandreas.hansson@arm.com{
9911051Sandreas.hansson@arm.com    Addr daddr = pkt->getAddr() - vcpuAddr;
10011051Sandreas.hansson@arm.com
10111051Sandreas.hansson@arm.com    ContextID ctx_id = pkt->req->contextId();
10211051Sandreas.hansson@arm.com    assert(ctx_id < VGIC_CPU_MAX);
10311051Sandreas.hansson@arm.com    struct vcpuIntData *vid = &vcpuData[ctx_id];
10411051Sandreas.hansson@arm.com
10511051Sandreas.hansson@arm.com    DPRINTF(VGIC, "VGIC VCPU read register %#x\n", daddr);
10611051Sandreas.hansson@arm.com
10711051Sandreas.hansson@arm.com    switch (daddr) {
10811051Sandreas.hansson@arm.com      case GICV_CTLR:
10911051Sandreas.hansson@arm.com        pkt->setLE<uint32_t>(vid->vctrl);
11011051Sandreas.hansson@arm.com        break;
11111051Sandreas.hansson@arm.com      case GICV_IAR: {
11211051Sandreas.hansson@arm.com          int i = findHighestPendingLR(vid);
11311051Sandreas.hansson@arm.com          if (i < 0 || !vid->vctrl.En) {
11411051Sandreas.hansson@arm.com              pkt->setLE<uint32_t>(1023); // "No int" marker
11511051Sandreas.hansson@arm.com          } else {
11611051Sandreas.hansson@arm.com              ListReg *lr = &vid->LR[i];
11711051Sandreas.hansson@arm.com
11811051Sandreas.hansson@arm.com              pkt->setLE<uint32_t>(lr->VirtualID |
11911051Sandreas.hansson@arm.com                                 (((int)lr->CpuID) << 10));
12011051Sandreas.hansson@arm.com              // We don't support auto-EOI of HW interrupts via real GIC!
12111051Sandreas.hansson@arm.com              // Fortunately, KVM doesn't use this.  How about Xen...? Ulp!
12211051Sandreas.hansson@arm.com              if (lr->HW)
12311051Sandreas.hansson@arm.com                  panic("VGIC does not support 'HW' List Register feature (LR %#x)!\n",
12411051Sandreas.hansson@arm.com                        *lr);
12511051Sandreas.hansson@arm.com              lr->State = LR_ACTIVE;
12611051Sandreas.hansson@arm.com              DPRINTF(VGIC, "Consumed interrupt %d (cpu%d) from LR%d (EOI%d)\n",
12711051Sandreas.hansson@arm.com                      lr->VirtualID, lr->CpuID, i, lr->EOI);
12811051Sandreas.hansson@arm.com          }
12911051Sandreas.hansson@arm.com      } break;
13011051Sandreas.hansson@arm.com      case GICV_IIDR:
13111051Sandreas.hansson@arm.com        pkt->setLE<uint32_t>(gicvIIDR);
13211051Sandreas.hansson@arm.com        break;
13311051Sandreas.hansson@arm.com      default:
13411051Sandreas.hansson@arm.com        panic("VGIC VCPU read of bad address %#x\n", daddr);
13511051Sandreas.hansson@arm.com    }
13611051Sandreas.hansson@arm.com
13711051Sandreas.hansson@arm.com    updateIntState(ctx_id);
13811051Sandreas.hansson@arm.com
13911051Sandreas.hansson@arm.com    pkt->makeAtomicResponse();
14011051Sandreas.hansson@arm.com    return pioDelay;
14111051Sandreas.hansson@arm.com}
14211051Sandreas.hansson@arm.com
14311051Sandreas.hansson@arm.comTick
14411051Sandreas.hansson@arm.comVGic::readCtrl(PacketPtr pkt)
14511051Sandreas.hansson@arm.com{
14611051Sandreas.hansson@arm.com    Addr daddr = pkt->getAddr() - hvAddr;
14711051Sandreas.hansson@arm.com
14811051Sandreas.hansson@arm.com    ContextID ctx_id = pkt->req->contextId();
14911051Sandreas.hansson@arm.com
15011051Sandreas.hansson@arm.com    DPRINTF(VGIC, "VGIC HVCtrl read register %#x\n", daddr);
15111051Sandreas.hansson@arm.com
15211051Sandreas.hansson@arm.com    /* Munge the address: 0-0xfff is the usual space banked by requester CPU.
15311051Sandreas.hansson@arm.com     * Anything > that is 0x200-sized slices of 'per CPU' regs.
15411051Sandreas.hansson@arm.com     */
15511051Sandreas.hansson@arm.com    if (daddr & ~0x1ff) {
15611051Sandreas.hansson@arm.com        ctx_id = (daddr >> 9);
15711051Sandreas.hansson@arm.com        if (ctx_id > 8)
15811051Sandreas.hansson@arm.com            panic("VGIC: Weird unbanked hv ctrl address %#x!\n", daddr);
15911051Sandreas.hansson@arm.com        daddr &= ~0x1ff;
16011051Sandreas.hansson@arm.com    }
16111284Sandreas.hansson@arm.com    assert(ctx_id < VGIC_CPU_MAX);
16211051Sandreas.hansson@arm.com    struct vcpuIntData *vid = &vcpuData[ctx_id];
16311051Sandreas.hansson@arm.com
16411051Sandreas.hansson@arm.com    switch (daddr) {
16511051Sandreas.hansson@arm.com      case GICH_HCR:
16611051Sandreas.hansson@arm.com        pkt->setLE<uint32_t>(vid->hcr);
16711051Sandreas.hansson@arm.com        break;
16811051Sandreas.hansson@arm.com
16911284Sandreas.hansson@arm.com      case GICH_VTR:
17011284Sandreas.hansson@arm.com        pkt->setLE<uint32_t>(0x44000000 | (NUM_LR - 1));
17111284Sandreas.hansson@arm.com        break;
17211284Sandreas.hansson@arm.com
17311051Sandreas.hansson@arm.com      case GICH_VMCR:
17411284Sandreas.hansson@arm.com        pkt->setLE<uint32_t>(
17511051Sandreas.hansson@arm.com            ((uint32_t)vid->VMPriMask << 27) |
17611051Sandreas.hansson@arm.com            ((uint32_t)vid->VMBP << 21) |
17711051Sandreas.hansson@arm.com            ((uint32_t)vid->VMABP << 18) |
17811284Sandreas.hansson@arm.com            ((uint32_t)vid->VEM << 9) |
17911284Sandreas.hansson@arm.com            ((uint32_t)vid->VMCBPR << 4) |
18011284Sandreas.hansson@arm.com            ((uint32_t)vid->VMFiqEn << 3) |
18111284Sandreas.hansson@arm.com            ((uint32_t)vid->VMAckCtl << 2) |
18211051Sandreas.hansson@arm.com            ((uint32_t)vid->VMGrp1En << 1) |
18311288Ssteve.reinhardt@amd.com            ((uint32_t)vid->VMGrp0En << 0)
18411288Ssteve.reinhardt@amd.com            );
18511051Sandreas.hansson@arm.com        break;
18611051Sandreas.hansson@arm.com
18711051Sandreas.hansson@arm.com      case GICH_MISR:
18811051Sandreas.hansson@arm.com        pkt->setLE<uint32_t>(getMISR(vid));
18911286Sandreas.hansson@arm.com        break;
19011286Sandreas.hansson@arm.com
19111286Sandreas.hansson@arm.com      case GICH_EISR0:
19211051Sandreas.hansson@arm.com        pkt->setLE<uint32_t>(vid->eisr & 0xffffffff);
19311286Sandreas.hansson@arm.com        break;
19411051Sandreas.hansson@arm.com
19511051Sandreas.hansson@arm.com      case GICH_EISR1:
19611051Sandreas.hansson@arm.com        pkt->setLE<uint32_t>(vid->eisr >> 32);
19711051Sandreas.hansson@arm.com        break;
19811051Sandreas.hansson@arm.com
19911051Sandreas.hansson@arm.com      case GICH_ELSR0: {
20011051Sandreas.hansson@arm.com          uint32_t bm = 0;
20111051Sandreas.hansson@arm.com          for (int i = 0; i < ((NUM_LR < 32) ? NUM_LR : 32); i++) {
20211051Sandreas.hansson@arm.com              if (!vid->LR[i].State)
20311051Sandreas.hansson@arm.com                  bm |= 1 << i;
20411051Sandreas.hansson@arm.com          }
20511284Sandreas.hansson@arm.com          pkt->setLE<uint32_t>(bm);
20611051Sandreas.hansson@arm.com      } break;
20711051Sandreas.hansson@arm.com
20811051Sandreas.hansson@arm.com      case GICH_ELSR1: {
20911051Sandreas.hansson@arm.com          uint32_t bm = 0;
21011051Sandreas.hansson@arm.com          for (int i = 32; i < NUM_LR; i++) {
21111284Sandreas.hansson@arm.com              if (!vid->LR[i].State)
21211051Sandreas.hansson@arm.com                  bm |= 1 << (i-32);
21311284Sandreas.hansson@arm.com          }
21411051Sandreas.hansson@arm.com          pkt->setLE<uint32_t>(bm);
21511197Sandreas.hansson@arm.com      } break;
21611197Sandreas.hansson@arm.com
21711197Sandreas.hansson@arm.com      case GICH_APR0:
21811197Sandreas.hansson@arm.com        warn_once("VGIC GICH_APR read!\n");
21911051Sandreas.hansson@arm.com        pkt->setLE<uint32_t>(0);
22011284Sandreas.hansson@arm.com        break;
22111051Sandreas.hansson@arm.com
22211284Sandreas.hansson@arm.com      case GICH_LR0:
22311284Sandreas.hansson@arm.com      case GICH_LR1:
22411284Sandreas.hansson@arm.com      case GICH_LR2:
22511051Sandreas.hansson@arm.com      case GICH_LR3:
22611051Sandreas.hansson@arm.com        pkt->setLE<uint32_t>(vid->LR[(daddr - GICH_LR0) >> 2]);
22711051Sandreas.hansson@arm.com        break;
22811284Sandreas.hansson@arm.com
22911284Sandreas.hansson@arm.com      default:
23011284Sandreas.hansson@arm.com        panic("VGIC HVCtrl read of bad address %#x\n", daddr);
23111284Sandreas.hansson@arm.com    }
23211051Sandreas.hansson@arm.com
23311051Sandreas.hansson@arm.com    pkt->makeAtomicResponse();
23411051Sandreas.hansson@arm.com    return pioDelay;
23511284Sandreas.hansson@arm.com}
23611284Sandreas.hansson@arm.com
23711284Sandreas.hansson@arm.comTick
23811197Sandreas.hansson@arm.comVGic::writeVCpu(PacketPtr pkt)
23911284Sandreas.hansson@arm.com{
24011284Sandreas.hansson@arm.com    Addr daddr = pkt->getAddr() - vcpuAddr;
24111284Sandreas.hansson@arm.com
24211284Sandreas.hansson@arm.com    ContextID ctx_id = pkt->req->contextId();
24311284Sandreas.hansson@arm.com    assert(ctx_id < VGIC_CPU_MAX);
24411284Sandreas.hansson@arm.com    struct vcpuIntData *vid = &vcpuData[ctx_id];
24511284Sandreas.hansson@arm.com
24611284Sandreas.hansson@arm.com    DPRINTF(VGIC, "VGIC VCPU write register %#x <= %#x\n",
24711284Sandreas.hansson@arm.com            daddr, pkt->getLE<uint32_t>());
24811284Sandreas.hansson@arm.com
24911284Sandreas.hansson@arm.com    switch (daddr) {
25011284Sandreas.hansson@arm.com      case GICV_CTLR:
25111284Sandreas.hansson@arm.com        vid->vctrl = pkt->getLE<uint32_t>();
25211284Sandreas.hansson@arm.com        break;
25311284Sandreas.hansson@arm.com      case GICV_PMR:
25411197Sandreas.hansson@arm.com        vid->VMPriMask = pkt->getLE<uint32_t>();
25511284Sandreas.hansson@arm.com        break;
25611284Sandreas.hansson@arm.com      case GICV_EOIR: {
25711284Sandreas.hansson@arm.com          // We don't handle the split EOI-then-DIR mode.  Linux (guest)
25811284Sandreas.hansson@arm.com          // doesn't need it though.
25911284Sandreas.hansson@arm.com          assert(!vid->vctrl.EOImode);
26011284Sandreas.hansson@arm.com          uint32_t w = pkt->getLE<uint32_t>();
26111284Sandreas.hansson@arm.com          unsigned int virq = w & 0x3ff;
26211197Sandreas.hansson@arm.com          unsigned int vcpu = (w >> 10) & 7;
26311051Sandreas.hansson@arm.com          int i = findLRForVIRQ(vid, virq, vcpu);
26411051Sandreas.hansson@arm.com          if (i < 0) {
26511051Sandreas.hansson@arm.com              DPRINTF(VGIC, "EOIR: No LR for irq %d(cpu%d)\n", virq, vcpu);
26611051Sandreas.hansson@arm.com          } else {
26711051Sandreas.hansson@arm.com              DPRINTF(VGIC, "EOIR: Found LR%d for irq %d(cpu%d)\n", i, virq, vcpu);
26811284Sandreas.hansson@arm.com              ListReg *lr = &vid->LR[i];
26911284Sandreas.hansson@arm.com              lr->State = 0;
27011051Sandreas.hansson@arm.com              // Maintenance interrupt -- via eisr -- is flagged when
27111051Sandreas.hansson@arm.com              // LRs have EOI=1 and State=INVALID!
27211051Sandreas.hansson@arm.com          }
27311051Sandreas.hansson@arm.com      } break;
27411284Sandreas.hansson@arm.com      default:
27511051Sandreas.hansson@arm.com        panic("VGIC VCPU write %#x to unk address %#x\n",
27611051Sandreas.hansson@arm.com                pkt->getLE<uint32_t>(), daddr);
27711051Sandreas.hansson@arm.com    }
27811284Sandreas.hansson@arm.com
27911051Sandreas.hansson@arm.com    // This updates the EISRs and flags IRQs:
28011197Sandreas.hansson@arm.com    updateIntState(ctx_id);
28111197Sandreas.hansson@arm.com
28211197Sandreas.hansson@arm.com    pkt->makeAtomicResponse();
28311197Sandreas.hansson@arm.com    return pioDelay;
28411288Ssteve.reinhardt@amd.com}
28511051Sandreas.hansson@arm.com
28611051Sandreas.hansson@arm.comTick
28711051Sandreas.hansson@arm.comVGic::writeCtrl(PacketPtr pkt)
28811051Sandreas.hansson@arm.com{
28911051Sandreas.hansson@arm.com    Addr daddr = pkt->getAddr() - hvAddr;
29011051Sandreas.hansson@arm.com
29111051Sandreas.hansson@arm.com    ContextID ctx_id = pkt->req->contextId();
29211051Sandreas.hansson@arm.com
29311051Sandreas.hansson@arm.com    DPRINTF(VGIC, "VGIC HVCtrl write register %#x <= %#x\n",
29411051Sandreas.hansson@arm.com            daddr, pkt->getLE<uint32_t>());
29511051Sandreas.hansson@arm.com
29611051Sandreas.hansson@arm.com    /* Munge the address: 0-0xfff is the usual space banked by requester CPU.
29711051Sandreas.hansson@arm.com     * Anything > that is 0x200-sized slices of 'per CPU' regs.
29811051Sandreas.hansson@arm.com     */
29911051Sandreas.hansson@arm.com    if (daddr & ~0x1ff) {
30011051Sandreas.hansson@arm.com        ctx_id = (daddr >> 9);
30111051Sandreas.hansson@arm.com        if (ctx_id > 8)
30211051Sandreas.hansson@arm.com            panic("VGIC: Weird unbanked hv ctrl address %#x!\n", daddr);
30311051Sandreas.hansson@arm.com        daddr &= ~0x1ff;
30411051Sandreas.hansson@arm.com    }
30511051Sandreas.hansson@arm.com    assert(ctx_id < VGIC_CPU_MAX);
30611288Ssteve.reinhardt@amd.com    struct vcpuIntData *vid = &vcpuData[ctx_id];
30711051Sandreas.hansson@arm.com
30811051Sandreas.hansson@arm.com    switch (daddr) {
30911051Sandreas.hansson@arm.com      case GICH_HCR:
31011051Sandreas.hansson@arm.com        vid->hcr = pkt->getLE<uint32_t>();
31111051Sandreas.hansson@arm.com        // update int state
31211051Sandreas.hansson@arm.com        break;
31311051Sandreas.hansson@arm.com
31411051Sandreas.hansson@arm.com      case GICH_VMCR: {
31511051Sandreas.hansson@arm.com          uint32_t d = pkt->getLE<uint32_t>();
31611051Sandreas.hansson@arm.com          vid->VMPriMask = d >> 27;
31711199Sandreas.hansson@arm.com          vid->VMBP = (d >> 21) & 7;
31811051Sandreas.hansson@arm.com          vid->VMABP = (d >> 18) & 7;
31911051Sandreas.hansson@arm.com          vid->VEM = (d >> 9) & 1;
32011051Sandreas.hansson@arm.com          vid->VMCBPR = (d >> 4) & 1;
32111051Sandreas.hansson@arm.com          vid->VMFiqEn = (d >> 3) & 1;
32211051Sandreas.hansson@arm.com          vid->VMAckCtl = (d >> 2) & 1;
32311051Sandreas.hansson@arm.com          vid->VMGrp1En = (d >> 1) & 1;
32411051Sandreas.hansson@arm.com          vid->VMGrp0En = d & 1;
32511484Snikos.nikoleris@arm.com      } break;
32611051Sandreas.hansson@arm.com
32711051Sandreas.hansson@arm.com      case GICH_APR0:
32811051Sandreas.hansson@arm.com        warn_once("VGIC GICH_APR0 written, ignored\n");
32911051Sandreas.hansson@arm.com        break;
33011051Sandreas.hansson@arm.com
33111051Sandreas.hansson@arm.com      case GICH_LR0:
33211051Sandreas.hansson@arm.com      case GICH_LR1:
33311051Sandreas.hansson@arm.com      case GICH_LR2:
33411051Sandreas.hansson@arm.com      case GICH_LR3:
33511051Sandreas.hansson@arm.com        vid->LR[(daddr - GICH_LR0) >> 2] = pkt->getLE<uint32_t>();
33611051Sandreas.hansson@arm.com        // update int state
33711051Sandreas.hansson@arm.com        break;
33811051Sandreas.hansson@arm.com
33911051Sandreas.hansson@arm.com      default:
34011051Sandreas.hansson@arm.com        panic("VGIC HVCtrl write to bad address %#x\n", daddr);
34111051Sandreas.hansson@arm.com    }
34211051Sandreas.hansson@arm.com
34311199Sandreas.hansson@arm.com    updateIntState(ctx_id);
34411051Sandreas.hansson@arm.com
34511051Sandreas.hansson@arm.com    pkt->makeAtomicResponse();
34611051Sandreas.hansson@arm.com    return pioDelay;
34711051Sandreas.hansson@arm.com}
34811051Sandreas.hansson@arm.com
34911051Sandreas.hansson@arm.com
35011051Sandreas.hansson@arm.comuint32_t
35111051Sandreas.hansson@arm.comVGic::getMISR(struct vcpuIntData *vid)
35211375Sandreas.hansson@arm.com{
35311375Sandreas.hansson@arm.com    return (!!vid->hcr.VGrp1DIE && !vid->VMGrp1En ? 0x80 : 0) |
35411375Sandreas.hansson@arm.com        (!!vid->hcr.VGrp1EIE &&  vid->VMGrp1En ? 0x40 : 0) |
35511199Sandreas.hansson@arm.com        (!!vid->hcr.VGrp0DIE && !vid->VMGrp0En ? 0x20 : 0) |
35611199Sandreas.hansson@arm.com        (!!vid->hcr.VGrp0EIE &&  vid->VMGrp0En ? 0x10 : 0) |
35711199Sandreas.hansson@arm.com        (!!vid->hcr.NPIE && !lrPending(vid) ? 0x08 : 0) |
35811199Sandreas.hansson@arm.com        (!!vid->hcr.LRENPIE && vid->hcr.EOICount ? 0x04 : 0) |
35911199Sandreas.hansson@arm.com        (!!vid->hcr.UIE && lrValid(vid) <= 1 ? 0x02 : 0) |
36011199Sandreas.hansson@arm.com        (vid->eisr ? 0x01 : 0);
36111199Sandreas.hansson@arm.com}
36211199Sandreas.hansson@arm.com
36311199Sandreas.hansson@arm.comvoid
36411199Sandreas.hansson@arm.comVGic::postVInt(uint32_t cpu, Tick when)
36511199Sandreas.hansson@arm.com{
36611199Sandreas.hansson@arm.com    DPRINTF(VGIC, "Posting VIRQ to %d\n", cpu);
36711199Sandreas.hansson@arm.com    if (!(postVIntEvent[cpu]->scheduled()))
36811199Sandreas.hansson@arm.com        eventq->schedule(postVIntEvent[cpu], when);
36911199Sandreas.hansson@arm.com}
37011199Sandreas.hansson@arm.com
37111199Sandreas.hansson@arm.comvoid
37211199Sandreas.hansson@arm.comVGic::unPostVInt(uint32_t cpu)
37311199Sandreas.hansson@arm.com{
37411199Sandreas.hansson@arm.com    DPRINTF(VGIC, "Unposting VIRQ to %d\n", cpu);
37511375Sandreas.hansson@arm.com    platform->intrctrl->clear(cpu, ArmISA::INT_VIRT_IRQ, 0);
37611199Sandreas.hansson@arm.com}
37711199Sandreas.hansson@arm.com
37811051Sandreas.hansson@arm.comvoid
37911051Sandreas.hansson@arm.comVGic::processPostVIntEvent(uint32_t cpu)
38011051Sandreas.hansson@arm.com{
38111051Sandreas.hansson@arm.com     platform->intrctrl->post(cpu, ArmISA::INT_VIRT_IRQ, 0);
38211051Sandreas.hansson@arm.com}
38311199Sandreas.hansson@arm.com
38411051Sandreas.hansson@arm.com
38511199Sandreas.hansson@arm.comvoid
38611199Sandreas.hansson@arm.comVGic::postMaintInt(uint32_t cpu)
38711199Sandreas.hansson@arm.com{
38811199Sandreas.hansson@arm.com    DPRINTF(VGIC, "Posting maintenance PPI to GIC/cpu%d\n", cpu);
38911199Sandreas.hansson@arm.com    // Linux DT configures this as Level.
39011199Sandreas.hansson@arm.com    gic->sendPPInt(maintInt, cpu);
39111199Sandreas.hansson@arm.com}
39211199Sandreas.hansson@arm.com
39311199Sandreas.hansson@arm.comvoid
39411199Sandreas.hansson@arm.comVGic::unPostMaintInt(uint32_t cpu)
39511199Sandreas.hansson@arm.com{
39611199Sandreas.hansson@arm.com    DPRINTF(VGIC, "Unposting maintenance PPI to GIC/cpu%d\n", cpu);
39711484Snikos.nikoleris@arm.com    gic->clearPPInt(maintInt, cpu);
39811051Sandreas.hansson@arm.com}
39911051Sandreas.hansson@arm.com
40011484Snikos.nikoleris@arm.com/* Update state (in general); something concerned with ctx_id has changed.
40111051Sandreas.hansson@arm.com * This may raise a maintenance interrupt.
40211051Sandreas.hansson@arm.com */
40311051Sandreas.hansson@arm.comvoid
40411051Sandreas.hansson@arm.comVGic::updateIntState(ContextID ctx_id)
40511051Sandreas.hansson@arm.com{
40611051Sandreas.hansson@arm.com    // @todo This should update APRs!
40711051Sandreas.hansson@arm.com
40811051Sandreas.hansson@arm.com    // Build EISR contents:
40911051Sandreas.hansson@arm.com    // (Cached so that regs can read them without messing about again)
41011051Sandreas.hansson@arm.com    struct vcpuIntData *tvid = &vcpuData[ctx_id];
41111051Sandreas.hansson@arm.com
41211199Sandreas.hansson@arm.com    tvid->eisr = 0;
41311199Sandreas.hansson@arm.com    for (int i = 0; i < NUM_LR; i++) {
41411199Sandreas.hansson@arm.com        if (!tvid->LR[i].State && tvid->LR[i].EOI) {
41511199Sandreas.hansson@arm.com            tvid->eisr |= 1 << i;
41611199Sandreas.hansson@arm.com        }
41711284Sandreas.hansson@arm.com    }
41811284Sandreas.hansson@arm.com
41911284Sandreas.hansson@arm.com    assert(sys->numRunningContexts() <= VGIC_CPU_MAX);
42011284Sandreas.hansson@arm.com    for (int i = 0; i < sys->numRunningContexts(); i++) {
42111051Sandreas.hansson@arm.com        struct vcpuIntData *vid = &vcpuData[i];
42211051Sandreas.hansson@arm.com        // Are any LRs active that weren't before?
42311051Sandreas.hansson@arm.com        if (!vIntPosted[i]) {
42411051Sandreas.hansson@arm.com            if (lrPending(vid) && vid->vctrl.En) {
42511051Sandreas.hansson@arm.com                vIntPosted[i] = true;
42611051Sandreas.hansson@arm.com                postVInt(i, curTick() + 1);
42711051Sandreas.hansson@arm.com            }
42811051Sandreas.hansson@arm.com        } else if (!lrPending(vid)) {
42911051Sandreas.hansson@arm.com            vIntPosted[i] = false;
43011484Snikos.nikoleris@arm.com            unPostVInt(i);
43111051Sandreas.hansson@arm.com        }
43211051Sandreas.hansson@arm.com
43311051Sandreas.hansson@arm.com        // Any maintenance ints to send?
43411051Sandreas.hansson@arm.com        if (!maintIntPosted[i]) {
43511051Sandreas.hansson@arm.com            if (vid->hcr.En && getMISR(vid)) {
43611051Sandreas.hansson@arm.com                maintIntPosted[i] = true;
43711051Sandreas.hansson@arm.com                postMaintInt(i);
43811051Sandreas.hansson@arm.com            }
43911051Sandreas.hansson@arm.com        } else {
44011051Sandreas.hansson@arm.com            if (!vid->hcr.En || !getMISR(vid)) {
44111051Sandreas.hansson@arm.com                unPostMaintInt(i);
44211484Snikos.nikoleris@arm.com                maintIntPosted[i] = false;
44311483Snikos.nikoleris@arm.com            }
44411483Snikos.nikoleris@arm.com        }
44511051Sandreas.hansson@arm.com    }
44611051Sandreas.hansson@arm.com}
44711051Sandreas.hansson@arm.com
44811051Sandreas.hansson@arm.comAddrRangeList
44911051Sandreas.hansson@arm.comVGic::getAddrRanges() const
45011051Sandreas.hansson@arm.com{
45111484Snikos.nikoleris@arm.com    AddrRangeList ranges;
45211284Sandreas.hansson@arm.com    ranges.push_back(RangeSize(hvAddr, GICH_REG_SIZE));
45311051Sandreas.hansson@arm.com    ranges.push_back(RangeSize(vcpuAddr, GICV_SIZE));
45411051Sandreas.hansson@arm.com    return ranges;
45511051Sandreas.hansson@arm.com}
45611484Snikos.nikoleris@arm.com
45711051Sandreas.hansson@arm.comvoid
45811051Sandreas.hansson@arm.comVGic::serialize(CheckpointOut &cp) const
45911051Sandreas.hansson@arm.com{
46011051Sandreas.hansson@arm.com    Tick interrupt_time[VGIC_CPU_MAX];
46111051Sandreas.hansson@arm.com    for (uint32_t cpu = 0; cpu < VGIC_CPU_MAX; cpu++) {
46211051Sandreas.hansson@arm.com        interrupt_time[cpu] = 0;
46311051Sandreas.hansson@arm.com        if (postVIntEvent[cpu]->scheduled()) {
46411051Sandreas.hansson@arm.com            interrupt_time[cpu] = postVIntEvent[cpu]->when();
46511051Sandreas.hansson@arm.com        }
46611051Sandreas.hansson@arm.com    }
46711051Sandreas.hansson@arm.com
46811051Sandreas.hansson@arm.com    DPRINTF(Checkpoint, "Serializing VGIC\n");
46911051Sandreas.hansson@arm.com
47011051Sandreas.hansson@arm.com    SERIALIZE_ARRAY(interrupt_time, VGIC_CPU_MAX);
47111051Sandreas.hansson@arm.com    SERIALIZE_ARRAY(maintIntPosted, VGIC_CPU_MAX);
47211051Sandreas.hansson@arm.com    SERIALIZE_ARRAY(vIntPosted, VGIC_CPU_MAX);
47311051Sandreas.hansson@arm.com    SERIALIZE_SCALAR(vcpuAddr);
47411051Sandreas.hansson@arm.com    SERIALIZE_SCALAR(hvAddr);
47511051Sandreas.hansson@arm.com    SERIALIZE_SCALAR(pioDelay);
47611051Sandreas.hansson@arm.com    SERIALIZE_SCALAR(maintInt);
47711051Sandreas.hansson@arm.com
47811051Sandreas.hansson@arm.com    for (uint32_t cpu = 0; cpu < VGIC_CPU_MAX; cpu++)
47911051Sandreas.hansson@arm.com        vcpuData[cpu].serializeSection(cp, csprintf("vcpuData%d", cpu));
48011051Sandreas.hansson@arm.com}
48111199Sandreas.hansson@arm.com
48211199Sandreas.hansson@arm.comvoid
48311199Sandreas.hansson@arm.comVGic::vcpuIntData::serialize(CheckpointOut &cp) const
48411199Sandreas.hansson@arm.com{
48511199Sandreas.hansson@arm.com    uint32_t vctrl_val = vctrl;
48611051Sandreas.hansson@arm.com    SERIALIZE_SCALAR(vctrl_val);
48711199Sandreas.hansson@arm.com    uint32_t hcr_val = hcr;
48811051Sandreas.hansson@arm.com    SERIALIZE_SCALAR(hcr_val);
48911051Sandreas.hansson@arm.com    uint64_t eisr_val = eisr;
49011051Sandreas.hansson@arm.com    SERIALIZE_SCALAR(eisr_val);
49111051Sandreas.hansson@arm.com    uint8_t VMGrp0En_val = VMGrp0En;
49211051Sandreas.hansson@arm.com    SERIALIZE_SCALAR(VMGrp0En_val);
49311051Sandreas.hansson@arm.com    uint8_t VMGrp1En_val = VMGrp1En;
49411051Sandreas.hansson@arm.com    SERIALIZE_SCALAR(VMGrp1En_val);
49511051Sandreas.hansson@arm.com    uint8_t VMAckCtl_val = VMAckCtl;
49611051Sandreas.hansson@arm.com    SERIALIZE_SCALAR(VMAckCtl_val);
49711051Sandreas.hansson@arm.com    uint8_t VMFiqEn_val = VMFiqEn;
49811051Sandreas.hansson@arm.com    SERIALIZE_SCALAR(VMFiqEn_val);
49911051Sandreas.hansson@arm.com    uint8_t VMCBPR_val = VMCBPR;
50011051Sandreas.hansson@arm.com    SERIALIZE_SCALAR(VMCBPR_val);
50111051Sandreas.hansson@arm.com    uint8_t VEM_val = VEM;
50211051Sandreas.hansson@arm.com    SERIALIZE_SCALAR(VEM_val);
50311051Sandreas.hansson@arm.com    uint8_t VMABP_val = VMABP;
50411051Sandreas.hansson@arm.com    SERIALIZE_SCALAR(VMABP_val);
50511130Sali.jafri@arm.com    uint8_t VMBP_val = VMBP;
50611130Sali.jafri@arm.com    SERIALIZE_SCALAR(VMBP_val);
50711130Sali.jafri@arm.com    uint8_t VMPriMask_val = VMPriMask;
50811130Sali.jafri@arm.com    SERIALIZE_SCALAR(VMPriMask_val);
50911130Sali.jafri@arm.com
51011130Sali.jafri@arm.com    for (int i = 0; i < NUM_LR; i++) {
51111130Sali.jafri@arm.com        ScopedCheckpointSection sec_lr(cp, csprintf("LR%d", i));
51211130Sali.jafri@arm.com        paramOut(cp, "lr", LR[i]);
51311130Sali.jafri@arm.com    }
51411199Sandreas.hansson@arm.com}
51511130Sali.jafri@arm.com
51611130Sali.jafri@arm.comvoid VGic::unserialize(CheckpointIn &cp)
51711130Sali.jafri@arm.com{
51811130Sali.jafri@arm.com    DPRINTF(Checkpoint, "Unserializing Arm GIC\n");
51911130Sali.jafri@arm.com
52011130Sali.jafri@arm.com    Tick interrupt_time[VGIC_CPU_MAX];
52111130Sali.jafri@arm.com    UNSERIALIZE_ARRAY(interrupt_time, VGIC_CPU_MAX);
52211130Sali.jafri@arm.com    for (uint32_t cpu = 0; cpu < VGIC_CPU_MAX; cpu++) {
52311130Sali.jafri@arm.com        if (interrupt_time[cpu])
52411130Sali.jafri@arm.com            schedule(postVIntEvent[cpu], interrupt_time[cpu]);
52511130Sali.jafri@arm.com
52611130Sali.jafri@arm.com        vcpuData[cpu].unserializeSection(cp, csprintf("vcpuData%d", cpu));
52711130Sali.jafri@arm.com    }
52811130Sali.jafri@arm.com    UNSERIALIZE_ARRAY(maintIntPosted, VGIC_CPU_MAX);
52911130Sali.jafri@arm.com    UNSERIALIZE_ARRAY(vIntPosted, VGIC_CPU_MAX);
53011130Sali.jafri@arm.com    UNSERIALIZE_SCALAR(vcpuAddr);
53111130Sali.jafri@arm.com    UNSERIALIZE_SCALAR(hvAddr);
53211130Sali.jafri@arm.com    UNSERIALIZE_SCALAR(pioDelay);
53311130Sali.jafri@arm.com    UNSERIALIZE_SCALAR(maintInt);
53411130Sali.jafri@arm.com}
53511130Sali.jafri@arm.com
53611130Sali.jafri@arm.comvoid
53711130Sali.jafri@arm.comVGic::vcpuIntData::unserialize(CheckpointIn &cp)
53811051Sandreas.hansson@arm.com{
53911051Sandreas.hansson@arm.com    paramIn(cp, "vctrl_val", vctrl);
54011051Sandreas.hansson@arm.com    paramIn(cp, "hcr_val", hcr);
54111051Sandreas.hansson@arm.com    paramIn(cp, "eisr_val", eisr);
54211051Sandreas.hansson@arm.com    paramIn(cp, "VMGrp0En_val", VMGrp0En);
54311051Sandreas.hansson@arm.com    paramIn(cp, "VMGrp1En_val", VMGrp1En);
54411051Sandreas.hansson@arm.com    paramIn(cp, "VMAckCtl_val", VMAckCtl);
54511051Sandreas.hansson@arm.com    paramIn(cp, "VMFiqEn_val", VMFiqEn);
54611051Sandreas.hansson@arm.com    paramIn(cp, "VMCBPR_val", VMCBPR);
54711051Sandreas.hansson@arm.com    paramIn(cp, "VEM_val", VEM);
54811276Sandreas.hansson@arm.com    paramIn(cp, "VMABP_val", VMABP);
54911276Sandreas.hansson@arm.com    paramIn(cp, "VMPriMask_val", VMPriMask);
55011276Sandreas.hansson@arm.com
55111276Sandreas.hansson@arm.com    for (int i = 0; i < NUM_LR; i++) {
55211276Sandreas.hansson@arm.com        ScopedCheckpointSection sec_lr(cp, csprintf("LR%d", i));
55311276Sandreas.hansson@arm.com        paramIn(cp, "lr", LR[i]);
55411276Sandreas.hansson@arm.com    }
55511276Sandreas.hansson@arm.com}
55611276Sandreas.hansson@arm.com
55711051Sandreas.hansson@arm.comVGic *
55811276Sandreas.hansson@arm.comVGicParams::create()
55911276Sandreas.hansson@arm.com{
56011276Sandreas.hansson@arm.com    return new VGic(this);
56111276Sandreas.hansson@arm.com}
56211276Sandreas.hansson@arm.com