vgic.cc revision 12092
16145SN/A/*
26145SN/A * Copyright (c) 2013 ARM Limited
36145SN/A * All rights reserved
46145SN/A *
56145SN/A * The license below extends only to copyright in the software and shall
66145SN/A * not be construed as granting a license to any other intellectual
76145SN/A * property including but not limited to intellectual property relating
86145SN/A * to a hardware implementation of the functionality of the software
96145SN/A * licensed hereunder.  You may use the software subject to the license
106145SN/A * terms below provided that you ensure that this notice is replicated
116145SN/A * unmodified and in its entirety in all distributions of the software,
126145SN/A * modified or unmodified, in source code or in binary form.
136145SN/A *
146145SN/A * Redistribution and use in source and binary forms, with or without
156145SN/A * modification, are permitted provided that the following conditions are
166145SN/A * met: redistributions of source code must retain the above copyright
176145SN/A * notice, this list of conditions and the following disclaimer;
186145SN/A * redistributions in binary form must reproduce the above copyright
196145SN/A * notice, this list of conditions and the following disclaimer in the
206145SN/A * documentation and/or other materials provided with the distribution;
216145SN/A * neither the name of the copyright holders nor the names of its
226145SN/A * contributors may be used to endorse or promote products derived from
236145SN/A * this software without specific prior written permission.
246145SN/A *
256145SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
266145SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
276145SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
286145SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
297832SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
307832SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
319356Snilay@cs.wisc.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
328232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
337054SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
348257SBrad.Beckmann@amd.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
358255SBrad.Beckmann@amd.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
367054SN/A *
376145SN/A * Authors: Matt Evans
387055SN/A */
397055SN/A
407054SN/A#include "dev/arm/vgic.hh"
418257SBrad.Beckmann@amd.com
426145SN/A#include "base/trace.hh"
436145SN/A#include "debug/Checkpoint.hh"
446145SN/A#include "debug/VGIC.hh"
456145SN/A#include "dev/arm/base_gic.hh"
466145SN/A#include "dev/terminal.hh"
476145SN/A#include "mem/packet.hh"
486145SN/A#include "mem/packet_access.hh"
4911096Snilay@cs.wisc.edu
5011096Snilay@cs.wisc.eduVGic::VGic(const Params *p)
5111096Snilay@cs.wisc.edu    : PioDevice(p), platform(p->platform), gic(p->gic), vcpuAddr(p->vcpu_addr),
5211096Snilay@cs.wisc.edu      hvAddr(p->hv_addr), pioDelay(p->pio_delay),
5311096Snilay@cs.wisc.edu      maintInt(p->ppint)
546145SN/A{
556881SN/A    for (int x = 0; x < VGIC_CPU_MAX; x++) {
566881SN/A        postVIntEvent[x] = new PostVIntEvent(x, p->platform);
576285SN/A        maintIntPosted[x] = false;
5811663Stushar@ece.gatech.edu        vIntPosted[x] = false;
5911663Stushar@ece.gatech.edu    }
6011663Stushar@ece.gatech.edu    assert(sys->numRunningContexts() <= VGIC_CPU_MAX);
6111663Stushar@ece.gatech.edu}
6211663Stushar@ece.gatech.edu
6311663Stushar@ece.gatech.eduVGic::~VGic()
6411663Stushar@ece.gatech.edu{
6511663Stushar@ece.gatech.edu    for (int x = 0; x < VGIC_CPU_MAX; x++)
669594Snilay@cs.wisc.edu        delete postVIntEvent[x];
679594Snilay@cs.wisc.edu}
688257SBrad.Beckmann@amd.com
698257SBrad.Beckmann@amd.comTick
708257SBrad.Beckmann@amd.comVGic::read(PacketPtr pkt)
716881SN/A{
7210078Snilay@cs.wisc.edu    Addr addr = pkt->getAddr();
739869Sjthestness@gmail.com
747054SN/A    if (addr >= vcpuAddr && addr < vcpuAddr + GICV_SIZE)
758257SBrad.Beckmann@amd.com        return readVCpu(pkt);
766145SN/A    else if (addr >= hvAddr && addr < hvAddr + GICH_REG_SIZE)
778257SBrad.Beckmann@amd.com        return readCtrl(pkt);
7811663Stushar@ece.gatech.edu    else
7911663Stushar@ece.gatech.edu        panic("Read to unknown address %#x\n", pkt->getAddr());
8011663Stushar@ece.gatech.edu}
8111663Stushar@ece.gatech.edu
827054SN/ATick
836145SN/AVGic::write(PacketPtr pkt)
8411663Stushar@ece.gatech.edu{
859594Snilay@cs.wisc.edu    Addr addr = pkt->getAddr();
869594Snilay@cs.wisc.edu
878257SBrad.Beckmann@amd.com    if (addr >= vcpuAddr && addr < vcpuAddr + GICV_SIZE)
8811663Stushar@ece.gatech.edu        return writeVCpu(pkt);
8911663Stushar@ece.gatech.edu    else if (addr >= hvAddr && addr < hvAddr + GICH_REG_SIZE)
906881SN/A        return writeCtrl(pkt);
918257SBrad.Beckmann@amd.com    else
928257SBrad.Beckmann@amd.com        panic("Write to unknown address %#x\n", pkt->getAddr());
938257SBrad.Beckmann@amd.com}
9411663Stushar@ece.gatech.edu
9511663Stushar@ece.gatech.eduTick
968257SBrad.Beckmann@amd.comVGic::readVCpu(PacketPtr pkt)
9711663Stushar@ece.gatech.edu{
9811663Stushar@ece.gatech.edu    Addr daddr = pkt->getAddr() - vcpuAddr;
997054SN/A
1006145SN/A    ContextID ctx_id = pkt->req->contextId();
1016145SN/A    assert(ctx_id < VGIC_CPU_MAX);
1028257SBrad.Beckmann@amd.com    struct vcpuIntData *vid = &vcpuData[ctx_id];
1039799Snilay@cs.wisc.edu
1047054SN/A    DPRINTF(VGIC, "VGIC VCPU read register %#x\n", daddr);
1057054SN/A
1067054SN/A    switch (daddr) {
1078257SBrad.Beckmann@amd.com      case GICV_CTLR:
1088257SBrad.Beckmann@amd.com        pkt->set<uint32_t>(vid->vctrl);
10910005Snilay@cs.wisc.edu        break;
1108257SBrad.Beckmann@amd.com      case GICV_IAR: {
11111320Ssteve.reinhardt@amd.com          int i = findHighestPendingLR(vid);
1127054SN/A          if (i < 0 || !vid->vctrl.En) {
1136881SN/A              pkt->set<uint32_t>(1023); // "No int" marker
1148257SBrad.Beckmann@amd.com          } else {
1157054SN/A              ListReg *lr = &vid->LR[i];
11611096Snilay@cs.wisc.edu
11711096Snilay@cs.wisc.edu              pkt->set<uint32_t>(lr->VirtualID |
11811096Snilay@cs.wisc.edu                                 (((int)lr->CpuID) << 10));
11911096Snilay@cs.wisc.edu              // We don't support auto-EOI of HW interrupts via real GIC!
12011096Snilay@cs.wisc.edu              // Fortunately, KVM doesn't use this.  How about Xen...? Ulp!
12111096Snilay@cs.wisc.edu              if (lr->HW)
1226145SN/A                  panic("VGIC does not support 'HW' List Register feature (LR %#x)!\n",
1237054SN/A                        *lr);
1247054SN/A              lr->State = LR_ACTIVE;
1257054SN/A              DPRINTF(VGIC, "Consumed interrupt %d (cpu%d) from LR%d (EOI%d)\n",
1267054SN/A                      lr->VirtualID, lr->CpuID, i, lr->EOI);
1276145SN/A          }
1287054SN/A      } break;
1298257SBrad.Beckmann@amd.com      default:
1308257SBrad.Beckmann@amd.com        panic("VGIC VCPU read of bad address %#x\n", daddr);
1318257SBrad.Beckmann@amd.com    }
1328257SBrad.Beckmann@amd.com
1338257SBrad.Beckmann@amd.com    updateIntState(ctx_id);
1348257SBrad.Beckmann@amd.com
13511096Snilay@cs.wisc.edu    pkt->makeAtomicResponse();
1368257SBrad.Beckmann@amd.com    return pioDelay;
1377054SN/A}
13811320Ssteve.reinhardt@amd.com
1397054SN/ATick
14011096Snilay@cs.wisc.eduVGic::readCtrl(PacketPtr pkt)
14111096Snilay@cs.wisc.edu{
14211096Snilay@cs.wisc.edu    Addr daddr = pkt->getAddr() - hvAddr;
1437054SN/A
1447054SN/A    ContextID ctx_id = pkt->req->contextId();
1457054SN/A
1467054SN/A    DPRINTF(VGIC, "VGIC HVCtrl read register %#x\n", daddr);
1479799Snilay@cs.wisc.edu
1489799Snilay@cs.wisc.edu    /* Munge the address: 0-0xfff is the usual space banked by requester CPU.
1499799Snilay@cs.wisc.edu     * Anything > that is 0x200-sized slices of 'per CPU' regs.
1507054SN/A     */
1517054SN/A    if (daddr & ~0x1ff) {
1526895SN/A        ctx_id = (daddr >> 9);
1536895SN/A        if (ctx_id > 8)
1546895SN/A            panic("VGIC: Weird unbanked hv ctrl address %#x!\n", daddr);
1557054SN/A        daddr &= ~0x1ff;
15611663Stushar@ece.gatech.edu    }
1577054SN/A    assert(ctx_id < VGIC_CPU_MAX);
1587832SN/A    struct vcpuIntData *vid = &vcpuData[ctx_id];
1597832SN/A
16011320Ssteve.reinhardt@amd.com    switch (daddr) {
1618257SBrad.Beckmann@amd.com      case GICH_HCR:
1628257SBrad.Beckmann@amd.com        pkt->set<uint32_t>(vid->hcr);
1638257SBrad.Beckmann@amd.com        break;
1648257SBrad.Beckmann@amd.com
1658257SBrad.Beckmann@amd.com      case GICH_VTR:
1668257SBrad.Beckmann@amd.com        pkt->set<uint32_t>(0x44000000 | (NUM_LR - 1));
1678257SBrad.Beckmann@amd.com        break;
1687054SN/A
1697054SN/A      case GICH_VMCR:
1707054SN/A        pkt->set<uint32_t>(
1717054SN/A            ((uint32_t)vid->VMPriMask << 27) |
1729799Snilay@cs.wisc.edu            ((uint32_t)vid->VMBP << 21) |
1737054SN/A            ((uint32_t)vid->VMABP << 18) |
1747054SN/A            ((uint32_t)vid->VEM << 9) |
1757054SN/A            ((uint32_t)vid->VMCBPR << 4) |
1767054SN/A            ((uint32_t)vid->VMFiqEn << 3) |
1777054SN/A            ((uint32_t)vid->VMAckCtl << 2) |
1788257SBrad.Beckmann@amd.com            ((uint32_t)vid->VMGrp1En << 1) |
17911320Ssteve.reinhardt@amd.com            ((uint32_t)vid->VMGrp0En << 0)
1808257SBrad.Beckmann@amd.com            );
1817054SN/A        break;
1828257SBrad.Beckmann@amd.com
1838257SBrad.Beckmann@amd.com      case GICH_MISR:
1848257SBrad.Beckmann@amd.com        pkt->set<uint32_t>(getMISR(vid));
18511663Stushar@ece.gatech.edu        break;
18611663Stushar@ece.gatech.edu
1877054SN/A      case GICH_EISR0:
1887054SN/A        pkt->set<uint32_t>(vid->eisr & 0xffffffff);
1898257SBrad.Beckmann@amd.com        break;
1908257SBrad.Beckmann@amd.com
1918257SBrad.Beckmann@amd.com      case GICH_EISR1:
1928257SBrad.Beckmann@amd.com        pkt->set<uint32_t>(vid->eisr >> 32);
19311663Stushar@ece.gatech.edu        break;
19411663Stushar@ece.gatech.edu
1957054SN/A      case GICH_ELSR0: {
1968257SBrad.Beckmann@amd.com          uint32_t bm = 0;
1978257SBrad.Beckmann@amd.com          for (int i = 0; i < ((NUM_LR < 32) ? NUM_LR : 32); i++) {
1988257SBrad.Beckmann@amd.com              if (!vid->LR[i].State)
1998257SBrad.Beckmann@amd.com                  bm |= 1 << i;
2008257SBrad.Beckmann@amd.com          }
20111663Stushar@ece.gatech.edu          pkt->set<uint32_t>(bm);
2029799Snilay@cs.wisc.edu      } break;
2037054SN/A
2047054SN/A      case GICH_ELSR1: {
2057054SN/A          uint32_t bm = 0;
2066145SN/A          for (int i = 32; i < NUM_LR; i++) {
2076145SN/A              if (!vid->LR[i].State)
2087054SN/A                  bm |= 1 << (i-32);
20911096Snilay@cs.wisc.edu          }
21011096Snilay@cs.wisc.edu          pkt->set<uint32_t>(bm);
2117054SN/A      } break;
2127054SN/A
2137054SN/A      case GICH_APR0:
2146145SN/A        warn_once("VGIC GICH_APR read!\n");
2157054SN/A        pkt->set<uint32_t>(0);
2167054SN/A        break;
2177054SN/A
2187054SN/A      case GICH_LR0:
2197054SN/A      case GICH_LR1:
2207054SN/A      case GICH_LR2:
2217054SN/A      case GICH_LR3:
2227054SN/A        pkt->set<uint32_t>(vid->LR[(daddr - GICH_LR0) >> 2]);
2237054SN/A        break;
2247054SN/A
2257054SN/A      default:
2267054SN/A        panic("VGIC HVCtrl read of bad address %#x\n", daddr);
2277054SN/A    }
2287054SN/A
2297054SN/A    pkt->makeAtomicResponse();
2307054SN/A    return pioDelay;
2317054SN/A}
2327054SN/A
2337054SN/ATick
2347054SN/AVGic::writeVCpu(PacketPtr pkt)
2357054SN/A{
2367054SN/A    Addr daddr = pkt->getAddr() - vcpuAddr;
2377054SN/A
2387054SN/A    ContextID ctx_id = pkt->req->contextId();
2397054SN/A    assert(ctx_id < VGIC_CPU_MAX);
2407054SN/A    struct vcpuIntData *vid = &vcpuData[ctx_id];
2417054SN/A
2426145SN/A    DPRINTF(VGIC, "VGIC VCPU write register %#x <= %#x\n", daddr, pkt->get<uint32_t>());
2436145SN/A
2446145SN/A    switch (daddr) {
2456145SN/A      case GICV_CTLR:
2467054SN/A        vid->vctrl = pkt->get<uint32_t>();
24711096Snilay@cs.wisc.edu        break;
24811096Snilay@cs.wisc.edu      case GICV_PMR:
2496145SN/A        vid->VMPriMask = pkt->get<uint32_t>();
2507054SN/A        break;
2517054SN/A      case GICV_EOIR: {
2527054SN/A          // We don't handle the split EOI-then-DIR mode.  Linux (guest)
2536145SN/A          // doesn't need it though.
2546145SN/A          assert(!vid->vctrl.EOImode);
2557054SN/A          uint32_t w = pkt->get<uint32_t>();
25611096Snilay@cs.wisc.edu          unsigned int virq = w & 0x3ff;
25711096Snilay@cs.wisc.edu          unsigned int vcpu = (w >> 10) & 7;
25811096Snilay@cs.wisc.edu          int i = findLRForVIRQ(vid, virq, vcpu);
2596145SN/A          if (i < 0) {
2607054SN/A              DPRINTF(VGIC, "EOIR: No LR for irq %d(cpu%d)\n", virq, vcpu);
2616145SN/A          } else {
2626145SN/A              DPRINTF(VGIC, "EOIR: Found LR%d for irq %d(cpu%d)\n", i, virq, vcpu);
2637054SN/A              ListReg *lr = &vid->LR[i];
26411096Snilay@cs.wisc.edu              lr->State = 0;
26511096Snilay@cs.wisc.edu              // Maintenance interrupt -- via eisr -- is flagged when
2666145SN/A              // LRs have EOI=1 and State=INVALID!
2677054SN/A          }
2687054SN/A      } break;
2697054SN/A      default:
2707054SN/A        panic("VGIC VCPU write %#x to unk address %#x\n", pkt->get<uint32_t>(), daddr);
2716145SN/A    }
2727054SN/A
2737054SN/A    // This updates the EISRs and flags IRQs:
2746145SN/A    updateIntState(ctx_id);
2757054SN/A
27610005Snilay@cs.wisc.edu    pkt->makeAtomicResponse();
2777054SN/A    return pioDelay;
2787054SN/A}
2797054SN/A
2807054SN/ATick
2817054SN/AVGic::writeCtrl(PacketPtr pkt)
2827054SN/A{
2837054SN/A    Addr daddr = pkt->getAddr() - hvAddr;
2847054SN/A
2857054SN/A    ContextID ctx_id = pkt->req->contextId();
2867054SN/A
2877054SN/A    DPRINTF(VGIC, "VGIC HVCtrl write register %#x <= %#x\n", daddr, pkt->get<uint32_t>());
2887054SN/A
2896145SN/A    /* Munge the address: 0-0xfff is the usual space banked by requester CPU.
2906145SN/A     * Anything > that is 0x200-sized slices of 'per CPU' regs.
2917780SN/A     */
2927780SN/A    if (daddr & ~0x1ff) {
2937780SN/A        ctx_id = (daddr >> 9);
2947780SN/A        if (ctx_id > 8)
2957780SN/A            panic("VGIC: Weird unbanked hv ctrl address %#x!\n", daddr);
2966145SN/A        daddr &= ~0x1ff;
2977054SN/A    }
2986145SN/A    assert(ctx_id < VGIC_CPU_MAX);
299    struct vcpuIntData *vid = &vcpuData[ctx_id];
300
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