Apply the gem5 namespace to the codebase. Some anonymous namespaces could theoretically be removed, but since this change's main goal was to keep conflicts at a minimum, it was decided not to modify much the general shape of the files. A few missing comments of the form "// namespace X" that occurred before the newly added "} // namespace gem5" have been added for consistency. std out should not be included in the gem5 namespace, so they weren't. ProtoMessage has not been included in the gem5 namespace, since I'm not familiar with how proto works. Regarding the SystemC files, although they belong to gem5, they actually perform integration between gem5 and SystemC; therefore, it deserved its own separate namespace. Files that are automatically generated have been included in the gem5 namespace. The .isa files currently are limited to a single namespace. This limitation should be later removed to make it easier to accomodate a better API. Regarding the files in util, gem5:: was prepended where suitable. Notice that this patch was tested as much as possible given that most of these were already not previously compiling. Change-Id: Ia53d404ec79c46edaa98f654e23bc3b0e179fe2d Signed-off-by: Daniel R. Carvalho <odanrc@yahoo.com.br> Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/46323 Maintainer: Bobby R. Bruce <bbruce@ucdavis.edu> Reviewed-by: Bobby R. Bruce <bbruce@ucdavis.edu> Reviewed-by: Matthew Poremba <matthew.poremba@amd.com> Tested-by: kokoro <noreply+kokoro@google.com>
563 lines
16 KiB
C++
563 lines
16 KiB
C++
/*
|
|
* Copyright (c) 2013,2018 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.
|
|
*/
|
|
|
|
#include "dev/arm/vgic.hh"
|
|
|
|
#include "arch/arm/interrupts.hh"
|
|
#include "base/trace.hh"
|
|
#include "cpu/base.hh"
|
|
#include "debug/Checkpoint.hh"
|
|
#include "debug/VGIC.hh"
|
|
#include "dev/arm/base_gic.hh"
|
|
#include "mem/packet.hh"
|
|
#include "mem/packet_access.hh"
|
|
|
|
namespace gem5
|
|
{
|
|
|
|
VGic::VGic(const Params &p)
|
|
: PioDevice(p), gicvIIDR(p.gicv_iidr), platform(p.platform),
|
|
gic(p.gic), vcpuAddr(p.vcpu_addr), hvAddr(p.hv_addr),
|
|
pioDelay(p.pio_delay), maintInt(p.maint_int)
|
|
{
|
|
for (int x = 0; x < VGIC_CPU_MAX; x++) {
|
|
postVIntEvent[x] = new EventFunctionWrapper(
|
|
[this, x]{ processPostVIntEvent(x); },
|
|
"Post VInterrupt to CPU");
|
|
maintIntPosted[x] = false;
|
|
vIntPosted[x] = false;
|
|
}
|
|
assert(sys->threads.numRunning() <= VGIC_CPU_MAX);
|
|
}
|
|
|
|
VGic::~VGic()
|
|
{
|
|
for (int x = 0; x < VGIC_CPU_MAX; x++)
|
|
delete postVIntEvent[x];
|
|
}
|
|
|
|
Tick
|
|
VGic::read(PacketPtr pkt)
|
|
{
|
|
Addr addr = pkt->getAddr();
|
|
|
|
if (addr >= vcpuAddr && addr < vcpuAddr + GICV_SIZE)
|
|
return readVCpu(pkt);
|
|
else if (addr >= hvAddr && addr < hvAddr + GICH_REG_SIZE)
|
|
return readCtrl(pkt);
|
|
else
|
|
panic("Read to unknown address %#x\n", pkt->getAddr());
|
|
}
|
|
|
|
Tick
|
|
VGic::write(PacketPtr pkt)
|
|
{
|
|
Addr addr = pkt->getAddr();
|
|
|
|
if (addr >= vcpuAddr && addr < vcpuAddr + GICV_SIZE)
|
|
return writeVCpu(pkt);
|
|
else if (addr >= hvAddr && addr < hvAddr + GICH_REG_SIZE)
|
|
return writeCtrl(pkt);
|
|
else
|
|
panic("Write to unknown address %#x\n", pkt->getAddr());
|
|
}
|
|
|
|
Tick
|
|
VGic::readVCpu(PacketPtr pkt)
|
|
{
|
|
Addr daddr = pkt->getAddr() - vcpuAddr;
|
|
|
|
ContextID ctx_id = pkt->req->contextId();
|
|
assert(ctx_id < VGIC_CPU_MAX);
|
|
struct vcpuIntData *vid = &vcpuData[ctx_id];
|
|
|
|
DPRINTF(VGIC, "VGIC VCPU read register %#x\n", daddr);
|
|
|
|
switch (daddr) {
|
|
case GICV_CTLR:
|
|
pkt->setLE<uint32_t>(vid->vctrl);
|
|
break;
|
|
case GICV_IAR: {
|
|
int i = findHighestPendingLR(vid);
|
|
if (i < 0 || !vid->vctrl.En) {
|
|
pkt->setLE<uint32_t>(1023); // "No int" marker
|
|
} else {
|
|
ListReg *lr = &vid->LR[i];
|
|
|
|
pkt->setLE<uint32_t>(lr->VirtualID |
|
|
(((int)lr->CpuID) << 10));
|
|
// We don't support auto-EOI of HW interrupts via real GIC!
|
|
// Fortunately, KVM doesn't use this. How about Xen...? Ulp!
|
|
if (lr->HW)
|
|
panic("VGIC does not support 'HW' List Register feature (LR %#x)!\n",
|
|
*lr);
|
|
lr->State = LR_ACTIVE;
|
|
DPRINTF(VGIC, "Consumed interrupt %d (cpu%d) from LR%d (EOI%d)\n",
|
|
lr->VirtualID, lr->CpuID, i, lr->EOI);
|
|
}
|
|
} break;
|
|
case GICV_IIDR:
|
|
pkt->setLE<uint32_t>(gicvIIDR);
|
|
break;
|
|
default:
|
|
panic("VGIC VCPU read of bad address %#x\n", daddr);
|
|
}
|
|
|
|
updateIntState(ctx_id);
|
|
|
|
pkt->makeAtomicResponse();
|
|
return pioDelay;
|
|
}
|
|
|
|
Tick
|
|
VGic::readCtrl(PacketPtr pkt)
|
|
{
|
|
Addr daddr = pkt->getAddr() - hvAddr;
|
|
|
|
ContextID ctx_id = pkt->req->contextId();
|
|
|
|
DPRINTF(VGIC, "VGIC HVCtrl read register %#x\n", daddr);
|
|
|
|
/* Munge the address: 0-0xfff is the usual space banked by requestor CPU.
|
|
* Anything > that is 0x200-sized slices of 'per CPU' regs.
|
|
*/
|
|
if (daddr & ~0x1ff) {
|
|
ctx_id = (daddr >> 9);
|
|
if (ctx_id > 8)
|
|
panic("VGIC: Weird unbanked hv ctrl address %#x!\n", daddr);
|
|
daddr &= ~0x1ff;
|
|
}
|
|
assert(ctx_id < VGIC_CPU_MAX);
|
|
struct vcpuIntData *vid = &vcpuData[ctx_id];
|
|
|
|
switch (daddr) {
|
|
case GICH_HCR:
|
|
pkt->setLE<uint32_t>(vid->hcr);
|
|
break;
|
|
|
|
case GICH_VTR:
|
|
pkt->setLE<uint32_t>(0x44000000 | (NUM_LR - 1));
|
|
break;
|
|
|
|
case GICH_VMCR:
|
|
pkt->setLE<uint32_t>(
|
|
((uint32_t)vid->VMPriMask << 27) |
|
|
((uint32_t)vid->VMBP << 21) |
|
|
((uint32_t)vid->VMABP << 18) |
|
|
((uint32_t)vid->VEM << 9) |
|
|
((uint32_t)vid->VMCBPR << 4) |
|
|
((uint32_t)vid->VMFiqEn << 3) |
|
|
((uint32_t)vid->VMAckCtl << 2) |
|
|
((uint32_t)vid->VMGrp1En << 1) |
|
|
((uint32_t)vid->VMGrp0En << 0)
|
|
);
|
|
break;
|
|
|
|
case GICH_MISR:
|
|
pkt->setLE<uint32_t>(getMISR(vid));
|
|
break;
|
|
|
|
case GICH_EISR0:
|
|
pkt->setLE<uint32_t>(vid->eisr & 0xffffffff);
|
|
break;
|
|
|
|
case GICH_EISR1:
|
|
pkt->setLE<uint32_t>(vid->eisr >> 32);
|
|
break;
|
|
|
|
case GICH_ELSR0: {
|
|
uint32_t bm = 0;
|
|
for (int i = 0; i < ((NUM_LR < 32) ? NUM_LR : 32); i++) {
|
|
if (!vid->LR[i].State)
|
|
bm |= 1 << i;
|
|
}
|
|
pkt->setLE<uint32_t>(bm);
|
|
} break;
|
|
|
|
case GICH_ELSR1: {
|
|
uint32_t bm = 0;
|
|
for (int i = 32; i < NUM_LR; i++) {
|
|
if (!vid->LR[i].State)
|
|
bm |= 1 << (i-32);
|
|
}
|
|
pkt->setLE<uint32_t>(bm);
|
|
} break;
|
|
|
|
case GICH_APR0:
|
|
warn_once("VGIC GICH_APR read!\n");
|
|
pkt->setLE<uint32_t>(0);
|
|
break;
|
|
|
|
case GICH_LR0:
|
|
case GICH_LR1:
|
|
case GICH_LR2:
|
|
case GICH_LR3:
|
|
pkt->setLE<uint32_t>(vid->LR[(daddr - GICH_LR0) >> 2]);
|
|
break;
|
|
|
|
default:
|
|
panic("VGIC HVCtrl read of bad address %#x\n", daddr);
|
|
}
|
|
|
|
pkt->makeAtomicResponse();
|
|
return pioDelay;
|
|
}
|
|
|
|
Tick
|
|
VGic::writeVCpu(PacketPtr pkt)
|
|
{
|
|
Addr daddr = pkt->getAddr() - vcpuAddr;
|
|
|
|
ContextID ctx_id = pkt->req->contextId();
|
|
assert(ctx_id < VGIC_CPU_MAX);
|
|
struct vcpuIntData *vid = &vcpuData[ctx_id];
|
|
|
|
DPRINTF(VGIC, "VGIC VCPU write register %#x <= %#x\n",
|
|
daddr, pkt->getLE<uint32_t>());
|
|
|
|
switch (daddr) {
|
|
case GICV_CTLR:
|
|
vid->vctrl = pkt->getLE<uint32_t>();
|
|
break;
|
|
case GICV_PMR:
|
|
vid->VMPriMask = pkt->getLE<uint32_t>();
|
|
break;
|
|
case GICV_EOIR: {
|
|
// We don't handle the split EOI-then-DIR mode. Linux (guest)
|
|
// doesn't need it though.
|
|
assert(!vid->vctrl.EOImode);
|
|
uint32_t w = pkt->getLE<uint32_t>();
|
|
unsigned int virq = w & 0x3ff;
|
|
unsigned int vcpu = (w >> 10) & 7;
|
|
int i = findLRForVIRQ(vid, virq, vcpu);
|
|
if (i < 0) {
|
|
DPRINTF(VGIC, "EOIR: No LR for irq %d(cpu%d)\n", virq, vcpu);
|
|
} else {
|
|
DPRINTF(VGIC, "EOIR: Found LR%d for irq %d(cpu%d)\n", i, virq, vcpu);
|
|
ListReg *lr = &vid->LR[i];
|
|
lr->State = 0;
|
|
// Maintenance interrupt -- via eisr -- is flagged when
|
|
// LRs have EOI=1 and State=INVALID!
|
|
}
|
|
} break;
|
|
default:
|
|
panic("VGIC VCPU write %#x to unk address %#x\n",
|
|
pkt->getLE<uint32_t>(), daddr);
|
|
}
|
|
|
|
// This updates the EISRs and flags IRQs:
|
|
updateIntState(ctx_id);
|
|
|
|
pkt->makeAtomicResponse();
|
|
return pioDelay;
|
|
}
|
|
|
|
Tick
|
|
VGic::writeCtrl(PacketPtr pkt)
|
|
{
|
|
Addr daddr = pkt->getAddr() - hvAddr;
|
|
|
|
ContextID ctx_id = pkt->req->contextId();
|
|
|
|
DPRINTF(VGIC, "VGIC HVCtrl write register %#x <= %#x\n",
|
|
daddr, pkt->getLE<uint32_t>());
|
|
|
|
/* Munge the address: 0-0xfff is the usual space banked by requestor CPU.
|
|
* Anything > that is 0x200-sized slices of 'per CPU' regs.
|
|
*/
|
|
if (daddr & ~0x1ff) {
|
|
ctx_id = (daddr >> 9);
|
|
if (ctx_id > 8)
|
|
panic("VGIC: Weird unbanked hv ctrl address %#x!\n", daddr);
|
|
daddr &= ~0x1ff;
|
|
}
|
|
assert(ctx_id < VGIC_CPU_MAX);
|
|
struct vcpuIntData *vid = &vcpuData[ctx_id];
|
|
|
|
switch (daddr) {
|
|
case GICH_HCR:
|
|
vid->hcr = pkt->getLE<uint32_t>();
|
|
// update int state
|
|
break;
|
|
|
|
case GICH_VMCR: {
|
|
uint32_t d = pkt->getLE<uint32_t>();
|
|
vid->VMPriMask = d >> 27;
|
|
vid->VMBP = (d >> 21) & 7;
|
|
vid->VMABP = (d >> 18) & 7;
|
|
vid->VEM = (d >> 9) & 1;
|
|
vid->VMCBPR = (d >> 4) & 1;
|
|
vid->VMFiqEn = (d >> 3) & 1;
|
|
vid->VMAckCtl = (d >> 2) & 1;
|
|
vid->VMGrp1En = (d >> 1) & 1;
|
|
vid->VMGrp0En = d & 1;
|
|
} break;
|
|
|
|
case GICH_APR0:
|
|
warn_once("VGIC GICH_APR0 written, ignored\n");
|
|
break;
|
|
|
|
case GICH_LR0:
|
|
case GICH_LR1:
|
|
case GICH_LR2:
|
|
case GICH_LR3:
|
|
vid->LR[(daddr - GICH_LR0) >> 2] = pkt->getLE<uint32_t>();
|
|
// update int state
|
|
break;
|
|
|
|
default:
|
|
panic("VGIC HVCtrl write to bad address %#x\n", daddr);
|
|
}
|
|
|
|
updateIntState(ctx_id);
|
|
|
|
pkt->makeAtomicResponse();
|
|
return pioDelay;
|
|
}
|
|
|
|
|
|
uint32_t
|
|
VGic::getMISR(struct vcpuIntData *vid)
|
|
{
|
|
return (!!vid->hcr.VGrp1DIE && !vid->VMGrp1En ? 0x80 : 0) |
|
|
(!!vid->hcr.VGrp1EIE && vid->VMGrp1En ? 0x40 : 0) |
|
|
(!!vid->hcr.VGrp0DIE && !vid->VMGrp0En ? 0x20 : 0) |
|
|
(!!vid->hcr.VGrp0EIE && vid->VMGrp0En ? 0x10 : 0) |
|
|
(!!vid->hcr.NPIE && !lrPending(vid) ? 0x08 : 0) |
|
|
(!!vid->hcr.LRENPIE && vid->hcr.EOICount ? 0x04 : 0) |
|
|
(!!vid->hcr.UIE && lrValid(vid) <= 1 ? 0x02 : 0) |
|
|
(vid->eisr ? 0x01 : 0);
|
|
}
|
|
|
|
void
|
|
VGic::postVInt(uint32_t cpu, Tick when)
|
|
{
|
|
DPRINTF(VGIC, "Posting VIRQ to %d\n", cpu);
|
|
if (!(postVIntEvent[cpu]->scheduled()))
|
|
eventq->schedule(postVIntEvent[cpu], when);
|
|
}
|
|
|
|
void
|
|
VGic::unPostVInt(uint32_t cpu)
|
|
{
|
|
DPRINTF(VGIC, "Unposting VIRQ to %d\n", cpu);
|
|
auto tc = platform->system->threads[cpu];
|
|
tc->getCpuPtr()->clearInterrupt(tc->threadId(), ArmISA::INT_VIRT_IRQ, 0);
|
|
}
|
|
|
|
void
|
|
VGic::processPostVIntEvent(uint32_t cpu)
|
|
{
|
|
auto tc = platform->system->threads[cpu];
|
|
tc->getCpuPtr()->postInterrupt(tc->threadId(), ArmISA::INT_VIRT_IRQ, 0);
|
|
}
|
|
|
|
|
|
void
|
|
VGic::postMaintInt(uint32_t cpu)
|
|
{
|
|
DPRINTF(VGIC, "Posting maintenance PPI to GIC/cpu%d\n", cpu);
|
|
// Linux DT configures this as Level.
|
|
gic->sendPPInt(maintInt, cpu);
|
|
}
|
|
|
|
void
|
|
VGic::unPostMaintInt(uint32_t cpu)
|
|
{
|
|
DPRINTF(VGIC, "Unposting maintenance PPI to GIC/cpu%d\n", cpu);
|
|
gic->clearPPInt(maintInt, cpu);
|
|
}
|
|
|
|
/* Update state (in general); something concerned with ctx_id has changed.
|
|
* This may raise a maintenance interrupt.
|
|
*/
|
|
void
|
|
VGic::updateIntState(ContextID ctx_id)
|
|
{
|
|
// @todo This should update APRs!
|
|
|
|
// Build EISR contents:
|
|
// (Cached so that regs can read them without messing about again)
|
|
struct vcpuIntData *tvid = &vcpuData[ctx_id];
|
|
|
|
tvid->eisr = 0;
|
|
for (int i = 0; i < NUM_LR; i++) {
|
|
if (!tvid->LR[i].State && tvid->LR[i].EOI) {
|
|
tvid->eisr |= 1 << i;
|
|
}
|
|
}
|
|
|
|
assert(sys->threads.numRunning() <= VGIC_CPU_MAX);
|
|
for (int i = 0; i < sys->threads.numRunning(); i++) {
|
|
struct vcpuIntData *vid = &vcpuData[i];
|
|
// Are any LRs active that weren't before?
|
|
if (!vIntPosted[i]) {
|
|
if (lrPending(vid) && vid->vctrl.En) {
|
|
vIntPosted[i] = true;
|
|
postVInt(i, curTick() + 1);
|
|
}
|
|
} else if (!lrPending(vid)) {
|
|
vIntPosted[i] = false;
|
|
unPostVInt(i);
|
|
}
|
|
|
|
// Any maintenance ints to send?
|
|
if (!maintIntPosted[i]) {
|
|
if (vid->hcr.En && getMISR(vid)) {
|
|
maintIntPosted[i] = true;
|
|
postMaintInt(i);
|
|
}
|
|
} else {
|
|
if (!vid->hcr.En || !getMISR(vid)) {
|
|
unPostMaintInt(i);
|
|
maintIntPosted[i] = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
AddrRangeList
|
|
VGic::getAddrRanges() const
|
|
{
|
|
AddrRangeList ranges;
|
|
ranges.push_back(RangeSize(hvAddr, GICH_REG_SIZE));
|
|
ranges.push_back(RangeSize(vcpuAddr, GICV_SIZE));
|
|
return ranges;
|
|
}
|
|
|
|
void
|
|
VGic::serialize(CheckpointOut &cp) const
|
|
{
|
|
Tick interrupt_time[VGIC_CPU_MAX];
|
|
for (uint32_t cpu = 0; cpu < VGIC_CPU_MAX; cpu++) {
|
|
interrupt_time[cpu] = 0;
|
|
if (postVIntEvent[cpu]->scheduled()) {
|
|
interrupt_time[cpu] = postVIntEvent[cpu]->when();
|
|
}
|
|
}
|
|
|
|
DPRINTF(Checkpoint, "Serializing VGIC\n");
|
|
|
|
SERIALIZE_ARRAY(interrupt_time, VGIC_CPU_MAX);
|
|
SERIALIZE_ARRAY(maintIntPosted, VGIC_CPU_MAX);
|
|
SERIALIZE_ARRAY(vIntPosted, VGIC_CPU_MAX);
|
|
SERIALIZE_SCALAR(vcpuAddr);
|
|
SERIALIZE_SCALAR(hvAddr);
|
|
SERIALIZE_SCALAR(pioDelay);
|
|
SERIALIZE_SCALAR(maintInt);
|
|
|
|
for (uint32_t cpu = 0; cpu < VGIC_CPU_MAX; cpu++)
|
|
vcpuData[cpu].serializeSection(cp, csprintf("vcpuData%d", cpu));
|
|
}
|
|
|
|
void
|
|
VGic::vcpuIntData::serialize(CheckpointOut &cp) const
|
|
{
|
|
uint32_t vctrl_val = vctrl;
|
|
SERIALIZE_SCALAR(vctrl_val);
|
|
uint32_t hcr_val = hcr;
|
|
SERIALIZE_SCALAR(hcr_val);
|
|
uint64_t eisr_val = eisr;
|
|
SERIALIZE_SCALAR(eisr_val);
|
|
uint8_t VMGrp0En_val = VMGrp0En;
|
|
SERIALIZE_SCALAR(VMGrp0En_val);
|
|
uint8_t VMGrp1En_val = VMGrp1En;
|
|
SERIALIZE_SCALAR(VMGrp1En_val);
|
|
uint8_t VMAckCtl_val = VMAckCtl;
|
|
SERIALIZE_SCALAR(VMAckCtl_val);
|
|
uint8_t VMFiqEn_val = VMFiqEn;
|
|
SERIALIZE_SCALAR(VMFiqEn_val);
|
|
uint8_t VMCBPR_val = VMCBPR;
|
|
SERIALIZE_SCALAR(VMCBPR_val);
|
|
uint8_t VEM_val = VEM;
|
|
SERIALIZE_SCALAR(VEM_val);
|
|
uint8_t VMABP_val = VMABP;
|
|
SERIALIZE_SCALAR(VMABP_val);
|
|
uint8_t VMBP_val = VMBP;
|
|
SERIALIZE_SCALAR(VMBP_val);
|
|
uint8_t VMPriMask_val = VMPriMask;
|
|
SERIALIZE_SCALAR(VMPriMask_val);
|
|
|
|
for (int i = 0; i < NUM_LR; i++) {
|
|
ScopedCheckpointSection sec_lr(cp, csprintf("LR%d", i));
|
|
paramOut(cp, "lr", LR[i]);
|
|
}
|
|
}
|
|
|
|
void VGic::unserialize(CheckpointIn &cp)
|
|
{
|
|
DPRINTF(Checkpoint, "Unserializing Arm GIC\n");
|
|
|
|
Tick interrupt_time[VGIC_CPU_MAX];
|
|
UNSERIALIZE_ARRAY(interrupt_time, VGIC_CPU_MAX);
|
|
for (uint32_t cpu = 0; cpu < VGIC_CPU_MAX; cpu++) {
|
|
if (interrupt_time[cpu])
|
|
schedule(postVIntEvent[cpu], interrupt_time[cpu]);
|
|
|
|
vcpuData[cpu].unserializeSection(cp, csprintf("vcpuData%d", cpu));
|
|
}
|
|
UNSERIALIZE_ARRAY(maintIntPosted, VGIC_CPU_MAX);
|
|
UNSERIALIZE_ARRAY(vIntPosted, VGIC_CPU_MAX);
|
|
UNSERIALIZE_SCALAR(vcpuAddr);
|
|
UNSERIALIZE_SCALAR(hvAddr);
|
|
UNSERIALIZE_SCALAR(pioDelay);
|
|
UNSERIALIZE_SCALAR(maintInt);
|
|
}
|
|
|
|
void
|
|
VGic::vcpuIntData::unserialize(CheckpointIn &cp)
|
|
{
|
|
paramIn(cp, "vctrl_val", vctrl);
|
|
paramIn(cp, "hcr_val", hcr);
|
|
paramIn(cp, "eisr_val", eisr);
|
|
paramIn(cp, "VMGrp0En_val", VMGrp0En);
|
|
paramIn(cp, "VMGrp1En_val", VMGrp1En);
|
|
paramIn(cp, "VMAckCtl_val", VMAckCtl);
|
|
paramIn(cp, "VMFiqEn_val", VMFiqEn);
|
|
paramIn(cp, "VMCBPR_val", VMCBPR);
|
|
paramIn(cp, "VEM_val", VEM);
|
|
paramIn(cp, "VMABP_val", VMABP);
|
|
paramIn(cp, "VMPriMask_val", VMPriMask);
|
|
|
|
for (int i = 0; i < NUM_LR; i++) {
|
|
ScopedCheckpointSection sec_lr(cp, csprintf("LR%d", i));
|
|
paramIn(cp, "lr", LR[i]);
|
|
}
|
|
}
|
|
|
|
} // namespace gem5
|