Compare commits
No commits in common. "c7f92c43da5b5d96b4287c418beaab3e56a91137" and "66a1016a3548e244f4d96773bfa8985262e4d4b4" have entirely different histories.
c7f92c43da
...
66a1016a35
19 changed files with 260 additions and 744 deletions
|
@ -399,7 +399,6 @@ def install_git_style_hooks():
|
|||
|
||||
if not git_hooks.exists():
|
||||
mkdir(git_hooks.get_abspath())
|
||||
git_hooks.clear()
|
||||
|
||||
abs_symlink_hooks = git_hooks.islink() and \
|
||||
os.path.isabs(os.readlink(git_hooks.get_abspath()))
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright (c) 2016-2017 ARM Limited
|
||||
# Copyright (c) 2016 ARM Limited
|
||||
# All rights reserved.
|
||||
#
|
||||
# The license below extends only to copyright in the software and shall
|
||||
|
@ -44,8 +44,6 @@ m5.util.addToPath('../../')
|
|||
from common.Caches import *
|
||||
from common import CpuConfig
|
||||
|
||||
have_kvm = "kvm" in CpuConfig.cpu_names()
|
||||
|
||||
class L1I(L1_ICache):
|
||||
tag_latency = 1
|
||||
data_latency = 1
|
||||
|
@ -172,14 +170,6 @@ class AtomicCluster(CpuCluster):
|
|||
def addL1(self):
|
||||
pass
|
||||
|
||||
class KvmCluster(CpuCluster):
|
||||
def __init__(self, system, num_cpus, cpu_clock, cpu_voltage="1.0V"):
|
||||
cpu_config = [ CpuConfig.get("kvm"), None, None, None, None ]
|
||||
super(KvmCluster, self).__init__(system, num_cpus, cpu_clock,
|
||||
cpu_voltage, *cpu_config)
|
||||
def addL1(self):
|
||||
pass
|
||||
|
||||
|
||||
class SimpleSystem(LinuxArmSystem):
|
||||
cache_line_size = 64
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright (c) 2016-2017 ARM Limited
|
||||
# Copyright (c) 2016 ARM Limited
|
||||
# All rights reserved.
|
||||
#
|
||||
# The license below extends only to copyright in the software and shall
|
||||
|
@ -132,7 +132,12 @@ def main():
|
|||
root = bL.build(options)
|
||||
addEthernet(root.system, options)
|
||||
|
||||
bL.instantiate(options, checkpoint_dir=options.checkpoint_dir)
|
||||
if options.restore_from:
|
||||
checkpoint_path = os.path.join(options.checkpoint_dir,
|
||||
options.restore_from)
|
||||
else:
|
||||
checkpoint_path = None
|
||||
bL.instantiate(checkpoint_path)
|
||||
bL.run(options.checkpoint_dir)
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright (c) 2016-2017 ARM Limited
|
||||
# Copyright (c) 2016 ARM Limited
|
||||
# All rights reserved.
|
||||
#
|
||||
# The license below extends only to copyright in the software and shall
|
||||
|
@ -44,7 +44,6 @@ import argparse
|
|||
import os
|
||||
import sys
|
||||
import m5
|
||||
import m5.util
|
||||
from m5.objects import *
|
||||
|
||||
m5.util.addToPath("../../")
|
||||
|
@ -53,7 +52,6 @@ from common import SysPaths
|
|||
from common import CpuConfig
|
||||
|
||||
import devices
|
||||
from devices import AtomicCluster, KvmCluster
|
||||
|
||||
|
||||
default_dtb = 'armv8_gem5_v1_big_little_2_2.dtb'
|
||||
|
@ -63,21 +61,6 @@ default_rcs = 'bootscript.rcS'
|
|||
|
||||
default_mem_size= "2GB"
|
||||
|
||||
def _to_ticks(value):
|
||||
"""Helper function to convert a latency from string format to Ticks"""
|
||||
|
||||
return m5.ticks.fromSeconds(m5.util.convert.anyToLatency(value))
|
||||
|
||||
def _using_pdes(root):
|
||||
"""Determine if the simulator is using multiple parallel event queues"""
|
||||
|
||||
for obj in root.descendants():
|
||||
if not m5.proxy.isproxy(obj.eventq_index) and \
|
||||
obj.eventq_index != root.eventq_index:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
class BigCluster(devices.CpuCluster):
|
||||
def __init__(self, system, num_cpus, cpu_clock,
|
||||
|
@ -124,15 +107,6 @@ def createSystem(caches, kernel, bootscript, disks=[]):
|
|||
|
||||
return sys
|
||||
|
||||
cpu_types = {
|
||||
"atomic" : (AtomicCluster, AtomicCluster),
|
||||
"timing" : (BigCluster, LittleCluster),
|
||||
}
|
||||
|
||||
# Only add the KVM CPU if it has been compiled into gem5
|
||||
if devices.have_kvm:
|
||||
cpu_types["kvm"] = (KvmCluster, KvmCluster)
|
||||
|
||||
|
||||
def addOptions(parser):
|
||||
parser.add_argument("--restore-from", type=str, default=None,
|
||||
|
@ -145,9 +119,8 @@ def addOptions(parser):
|
|||
help="Disks to instantiate")
|
||||
parser.add_argument("--bootscript", type=str, default=default_rcs,
|
||||
help="Linux bootscript")
|
||||
parser.add_argument("--cpu-type", type=str, choices=cpu_types.keys(),
|
||||
default="timing",
|
||||
help="CPU simulation mode. Default: %(default)s")
|
||||
parser.add_argument("--atomic", action="store_true", default=False,
|
||||
help="Use atomic CPUs")
|
||||
parser.add_argument("--kernel-init", type=str, default="/sbin/init",
|
||||
help="Override init")
|
||||
parser.add_argument("--big-cpus", type=int, default=1,
|
||||
|
@ -162,11 +135,9 @@ def addOptions(parser):
|
|||
help="Big CPU clock frequency")
|
||||
parser.add_argument("--little-cpu-clock", type=str, default="1GHz",
|
||||
help="Little CPU clock frequency")
|
||||
parser.add_argument("--sim-quantum", type=str, default="1ms",
|
||||
help="Simulation quantum for parallel simulation. " \
|
||||
"Default: %(default)s")
|
||||
return parser
|
||||
|
||||
|
||||
def build(options):
|
||||
m5.ticks.fixGlobalFrequency()
|
||||
|
||||
|
@ -194,31 +165,35 @@ def build(options):
|
|||
root.system = system
|
||||
system.boot_osflags = " ".join(kernel_cmd)
|
||||
|
||||
AtomicCluster = devices.AtomicCluster
|
||||
|
||||
if options.big_cpus + options.little_cpus == 0:
|
||||
m5.util.panic("Empty CPU clusters")
|
||||
|
||||
big_model, little_model = cpu_types[options.cpu_type]
|
||||
|
||||
all_cpus = []
|
||||
# big cluster
|
||||
if options.big_cpus > 0:
|
||||
system.bigCluster = big_model(system, options.big_cpus,
|
||||
options.big_cpu_clock)
|
||||
system.mem_mode = system.bigCluster.memoryMode()
|
||||
all_cpus += system.bigCluster.cpus
|
||||
|
||||
if options.atomic:
|
||||
system.bigCluster = AtomicCluster(system, options.big_cpus,
|
||||
options.big_cpu_clock)
|
||||
else:
|
||||
system.bigCluster = BigCluster(system, options.big_cpus,
|
||||
options.big_cpu_clock)
|
||||
mem_mode = system.bigCluster.memoryMode()
|
||||
# little cluster
|
||||
if options.little_cpus > 0:
|
||||
system.littleCluster = little_model(system, options.little_cpus,
|
||||
options.little_cpu_clock)
|
||||
system.mem_mode = system.littleCluster.memoryMode()
|
||||
all_cpus += system.littleCluster.cpus
|
||||
if options.atomic:
|
||||
system.littleCluster = AtomicCluster(system, options.little_cpus,
|
||||
options.little_cpu_clock)
|
||||
|
||||
# Figure out the memory mode
|
||||
if options.big_cpus > 0 and options.little_cpus > 0 and \
|
||||
system.littleCluster.memoryMode() != system.littleCluster.memoryMode():
|
||||
m5.util.panic("Memory mode missmatch among CPU clusters")
|
||||
else:
|
||||
system.littleCluster = LittleCluster(system, options.little_cpus,
|
||||
options.little_cpu_clock)
|
||||
mem_mode = system.littleCluster.memoryMode()
|
||||
|
||||
if options.big_cpus > 0 and options.little_cpus > 0:
|
||||
if system.bigCluster.memoryMode() != system.littleCluster.memoryMode():
|
||||
m5.util.panic("Memory mode missmatch among CPU clusters")
|
||||
system.mem_mode = mem_mode
|
||||
|
||||
# create caches
|
||||
system.addCaches(options.caches, options.last_cache_level)
|
||||
|
@ -228,52 +203,17 @@ def build(options):
|
|||
if options.little_cpus > 0 and system.littleCluster.requireCaches():
|
||||
m5.util.panic("Little CPU model requires caches")
|
||||
|
||||
# Create a KVM VM and do KVM-specific configuration
|
||||
if issubclass(big_model, KvmCluster):
|
||||
_build_kvm(system, all_cpus)
|
||||
|
||||
# Linux device tree
|
||||
system.dtb_filename = SysPaths.binary(options.dtb)
|
||||
|
||||
return root
|
||||
|
||||
def _build_kvm(system, cpus):
|
||||
system.kvm_vm = KvmVM()
|
||||
|
||||
# Assign KVM CPUs to their own event queues / threads. This
|
||||
# has to be done after creating caches and other child objects
|
||||
# since these mustn't inherit the CPU event queue.
|
||||
if len(cpus) > 1:
|
||||
device_eq = 0
|
||||
first_cpu_eq = 1
|
||||
for idx, cpu in enumerate(cpus):
|
||||
# Child objects usually inherit the parent's event
|
||||
# queue. Override that and use the same event queue for
|
||||
# all devices.
|
||||
for obj in cpu.descendants():
|
||||
obj.eventq_index = device_eq
|
||||
cpu.eventq_index = first_cpu_eq + idx
|
||||
|
||||
|
||||
|
||||
def instantiate(options, checkpoint_dir=None):
|
||||
# Setup the simulation quantum if we are running in PDES-mode
|
||||
# (e.g., when using KVM)
|
||||
root = Root.getInstance()
|
||||
if root and _using_pdes(root):
|
||||
m5.util.inform("Running in PDES mode with a %s simulation quantum.",
|
||||
options.sim_quantum)
|
||||
root.sim_quantum = _to_ticks(options.sim_quantum)
|
||||
|
||||
def instantiate(checkpoint_path=None):
|
||||
# Get and load from the chkpt or simpoint checkpoint
|
||||
if options.restore_from:
|
||||
if checkpoint_dir and not os.path.isabs(options.restore_from):
|
||||
cpt = os.path.join(checkpoint_dir, options.restore_from)
|
||||
else:
|
||||
cpt = options.restore_from
|
||||
|
||||
m5.util.inform("Restoring from checkpoint %s", cpt)
|
||||
m5.instantiate(cpt)
|
||||
if checkpoint_path is not None:
|
||||
m5.util.inform("Restoring from checkpoint %s", checkpoint_path)
|
||||
m5.instantiate(checkpoint_path)
|
||||
else:
|
||||
m5.instantiate()
|
||||
|
||||
|
@ -301,7 +241,7 @@ def main():
|
|||
addOptions(parser)
|
||||
options = parser.parse_args()
|
||||
root = build(options)
|
||||
instantiate(options)
|
||||
instantiate(options.restore_from)
|
||||
run()
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// -*- mode:c++ -*-
|
||||
|
||||
// Copyright (c) 2010-2013,2017 ARM Limited
|
||||
// Copyright (c) 2010-2013 ARM Limited
|
||||
// All rights reserved
|
||||
//
|
||||
// The license below extends only to copyright in the software and shall
|
||||
|
@ -814,9 +814,7 @@ let {{
|
|||
|
||||
mrc14code = '''
|
||||
MiscRegIndex miscReg = (MiscRegIndex) xc->tcBase()->flattenMiscIndex(op1);
|
||||
bool can_read, undefined;
|
||||
std::tie(can_read, undefined) = canReadCoprocReg(miscReg, Scr, Cpsr);
|
||||
if (!can_read || undefined) {
|
||||
if (!canReadCoprocReg(miscReg, Scr, Cpsr, xc->tcBase())) {
|
||||
return std::make_shared<UndefinedInstruction>(machInst, false,
|
||||
mnemonic);
|
||||
}
|
||||
|
@ -838,9 +836,7 @@ let {{
|
|||
|
||||
mcr14code = '''
|
||||
MiscRegIndex miscReg = (MiscRegIndex) xc->tcBase()->flattenMiscIndex(dest);
|
||||
bool can_write, undefined;
|
||||
std::tie(can_write, undefined) = canWriteCoprocReg(miscReg, Scr, Cpsr);
|
||||
if (undefined || !can_write) {
|
||||
if (!canWriteCoprocReg(miscReg, Scr, Cpsr, xc->tcBase())) {
|
||||
return std::make_shared<UndefinedInstruction>(machInst, false,
|
||||
mnemonic);
|
||||
}
|
||||
|
@ -865,13 +861,12 @@ let {{
|
|||
xc->tcBase()->flattenMiscIndex(preFlatOp1);
|
||||
bool hypTrap = mcrMrc15TrapToHyp(miscReg, Hcr, Cpsr, Scr, Hdcr, Hstr,
|
||||
Hcptr, imm);
|
||||
bool can_read, undefined;
|
||||
std::tie(can_read, undefined) = canReadCoprocReg(miscReg, Scr, Cpsr);
|
||||
bool canRead = canReadCoprocReg(miscReg, Scr, Cpsr, xc->tcBase());
|
||||
|
||||
// if we're in non secure PL1 mode then we can trap regargless of whether
|
||||
// the register is accessable, in other modes we trap if only if the register
|
||||
// IS accessable.
|
||||
if (undefined || (!can_read && !(hypTrap && !inUserMode(Cpsr) &&
|
||||
!inSecureState(Scr, Cpsr)))) {
|
||||
if (!canRead && !(hypTrap && !inUserMode(Cpsr) && !inSecureState(Scr, Cpsr))) {
|
||||
return std::make_shared<UndefinedInstruction>(machInst, false,
|
||||
mnemonic);
|
||||
}
|
||||
|
@ -896,14 +891,12 @@ let {{
|
|||
xc->tcBase()->flattenMiscIndex(preFlatDest);
|
||||
bool hypTrap = mcrMrc15TrapToHyp(miscReg, Hcr, Cpsr, Scr, Hdcr, Hstr,
|
||||
Hcptr, imm);
|
||||
bool can_write, undefined;
|
||||
std::tie(can_write, undefined) = canWriteCoprocReg(miscReg, Scr, Cpsr);
|
||||
bool canWrite = canWriteCoprocReg(miscReg, Scr, Cpsr, xc->tcBase());
|
||||
|
||||
// if we're in non secure PL1 mode then we can trap regargless of whether
|
||||
// the register is accessable, in other modes we trap if only if the register
|
||||
// IS accessable.
|
||||
if (undefined || (!can_write && !(hypTrap && !inUserMode(Cpsr) &&
|
||||
!inSecureState(Scr, Cpsr)))) {
|
||||
if (!canWrite & !(hypTrap & !inUserMode(Cpsr) & !inSecureState(Scr, Cpsr))) {
|
||||
return std::make_shared<UndefinedInstruction>(machInst, false,
|
||||
mnemonic);
|
||||
}
|
||||
|
@ -927,13 +920,12 @@ let {{
|
|||
MiscRegIndex miscReg = (MiscRegIndex)
|
||||
xc->tcBase()->flattenMiscIndex(preFlatOp1);
|
||||
bool hypTrap = mcrrMrrc15TrapToHyp(miscReg, Cpsr, Scr, Hstr, Hcr, imm);
|
||||
bool can_read, undefined;
|
||||
std::tie(can_read, undefined) = canReadCoprocReg(miscReg, Scr, Cpsr);
|
||||
bool canRead = canReadCoprocReg(miscReg, Scr, Cpsr, xc->tcBase());
|
||||
|
||||
// if we're in non secure PL1 mode then we can trap regargless of whether
|
||||
// the register is accessable, in other modes we trap if only if the register
|
||||
// IS accessable.
|
||||
if (undefined || (!can_read && !(hypTrap && !inUserMode(Cpsr) &&
|
||||
!inSecureState(Scr, Cpsr)))) {
|
||||
if (!canRead && !(hypTrap && !inUserMode(Cpsr) && !inSecureState(Scr, Cpsr))) {
|
||||
return std::make_shared<UndefinedInstruction>(machInst, false,
|
||||
mnemonic);
|
||||
}
|
||||
|
@ -957,14 +949,12 @@ let {{
|
|||
MiscRegIndex miscReg = (MiscRegIndex)
|
||||
xc->tcBase()->flattenMiscIndex(preFlatDest);
|
||||
bool hypTrap = mcrrMrrc15TrapToHyp(miscReg, Cpsr, Scr, Hstr, Hcr, imm);
|
||||
bool can_write, undefined;
|
||||
std::tie(can_write, undefined) = canWriteCoprocReg(miscReg, Scr, Cpsr);
|
||||
bool canWrite = canWriteCoprocReg(miscReg, Scr, Cpsr, xc->tcBase());
|
||||
|
||||
// if we're in non secure PL1 mode then we can trap regargless of whether
|
||||
// the register is accessable, in other modes we trap if only if the register
|
||||
// IS accessable.
|
||||
if (undefined || (!can_write && !(hypTrap && !inUserMode(Cpsr) &&
|
||||
!inSecureState(Scr, Cpsr)))) {
|
||||
if (!canWrite & !(hypTrap & !inUserMode(Cpsr) & !inSecureState(Scr, Cpsr))) {
|
||||
return std::make_shared<UndefinedInstruction>(machInst, false,
|
||||
mnemonic);
|
||||
}
|
||||
|
|
|
@ -43,7 +43,6 @@
|
|||
#include <linux/kvm.h>
|
||||
|
||||
#include "arch/arm/kvm/base_cpu.hh"
|
||||
#include "debug/GIC.hh"
|
||||
#include "debug/Interrupt.hh"
|
||||
#include "params/MuxingKvmGic.hh"
|
||||
|
||||
|
@ -105,63 +104,6 @@ KvmKernelGicV2::setIntState(unsigned type, unsigned vcpu, unsigned irq,
|
|||
vm.setIRQLine(line, high);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
KvmKernelGicV2::getGicReg(unsigned group, unsigned vcpu, unsigned offset)
|
||||
{
|
||||
uint64_t reg;
|
||||
|
||||
assert(vcpu <= KVM_ARM_IRQ_VCPU_MASK);
|
||||
const uint32_t attr(
|
||||
(vcpu << KVM_DEV_ARM_VGIC_CPUID_SHIFT) |
|
||||
(offset << KVM_DEV_ARM_VGIC_OFFSET_SHIFT));
|
||||
|
||||
kdev.getAttrPtr(group, attr, ®);
|
||||
return (uint32_t) reg;
|
||||
}
|
||||
|
||||
void
|
||||
KvmKernelGicV2::setGicReg(unsigned group, unsigned vcpu, unsigned offset,
|
||||
unsigned value)
|
||||
{
|
||||
uint64_t reg = value;
|
||||
|
||||
assert(vcpu <= KVM_ARM_IRQ_VCPU_MASK);
|
||||
const uint32_t attr(
|
||||
(vcpu << KVM_DEV_ARM_VGIC_CPUID_SHIFT) |
|
||||
(offset << KVM_DEV_ARM_VGIC_OFFSET_SHIFT));
|
||||
|
||||
kdev.setAttrPtr(group, attr, ®);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
KvmKernelGicV2::readDistributor(ContextID ctx, Addr daddr)
|
||||
{
|
||||
auto vcpu = vm.contextIdToVCpuId(ctx);
|
||||
return getGicReg(KVM_DEV_ARM_VGIC_GRP_DIST_REGS, vcpu, daddr);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
KvmKernelGicV2::readCpu(ContextID ctx, Addr daddr)
|
||||
{
|
||||
auto vcpu = vm.contextIdToVCpuId(ctx);
|
||||
return getGicReg(KVM_DEV_ARM_VGIC_GRP_CPU_REGS, vcpu, daddr);
|
||||
}
|
||||
|
||||
void
|
||||
KvmKernelGicV2::writeDistributor(ContextID ctx, Addr daddr, uint32_t data)
|
||||
{
|
||||
auto vcpu = vm.contextIdToVCpuId(ctx);
|
||||
setGicReg(KVM_DEV_ARM_VGIC_GRP_DIST_REGS, vcpu, daddr, data);
|
||||
}
|
||||
|
||||
void
|
||||
KvmKernelGicV2::writeCpu(ContextID ctx, Addr daddr, uint32_t data)
|
||||
{
|
||||
auto vcpu = vm.contextIdToVCpuId(ctx);
|
||||
setGicReg(KVM_DEV_ARM_VGIC_GRP_CPU_REGS, vcpu, daddr, data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
MuxingKvmGic::MuxingKvmGic(const MuxingKvmGicParams *p)
|
||||
: Pl390(p),
|
||||
|
@ -179,39 +121,21 @@ MuxingKvmGic::~MuxingKvmGic()
|
|||
{
|
||||
}
|
||||
|
||||
void
|
||||
MuxingKvmGic::loadState(CheckpointIn &cp)
|
||||
{
|
||||
Pl390::loadState(cp);
|
||||
}
|
||||
|
||||
void
|
||||
MuxingKvmGic::startup()
|
||||
{
|
||||
Pl390::startup();
|
||||
usingKvm = (kernelGic != nullptr) && validKvmEnvironment();
|
||||
if (usingKvm)
|
||||
fromPl390ToKvm();
|
||||
}
|
||||
|
||||
DrainState
|
||||
MuxingKvmGic::drain()
|
||||
{
|
||||
if (usingKvm)
|
||||
fromKvmToPl390();
|
||||
return Pl390::drain();
|
||||
}
|
||||
|
||||
void
|
||||
MuxingKvmGic::drainResume()
|
||||
{
|
||||
Pl390::drainResume();
|
||||
bool use_kvm = (kernelGic != nullptr) && validKvmEnvironment();
|
||||
if (use_kvm != usingKvm) {
|
||||
// Should only occur due to CPU switches
|
||||
if (use_kvm) // from simulation to KVM emulation
|
||||
fromPl390ToKvm();
|
||||
// otherwise, drain() already sync'd the state back to the Pl390
|
||||
else // from KVM emulation to simulation
|
||||
fromKvmToPl390();
|
||||
|
||||
usingKvm = use_kvm;
|
||||
}
|
||||
|
@ -220,14 +144,19 @@ MuxingKvmGic::drainResume()
|
|||
void
|
||||
MuxingKvmGic::serialize(CheckpointOut &cp) const
|
||||
{
|
||||
// drain() already ensured Pl390 updated with KvmGic state if necessary
|
||||
Pl390::serialize(cp);
|
||||
if (!usingKvm)
|
||||
return Pl390::serialize(cp);
|
||||
|
||||
panic("Checkpointing unsupported\n");
|
||||
}
|
||||
|
||||
void
|
||||
MuxingKvmGic::unserialize(CheckpointIn &cp)
|
||||
{
|
||||
Pl390::unserialize(cp);
|
||||
if (!usingKvm)
|
||||
return Pl390::unserialize(cp);
|
||||
|
||||
panic("Checkpointing unsupported\n");
|
||||
}
|
||||
|
||||
Tick
|
||||
|
@ -301,150 +230,16 @@ MuxingKvmGic::validKvmEnvironment() const
|
|||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
MuxingKvmGic::copyDistRegister(BaseGicRegisters* from, BaseGicRegisters* to,
|
||||
ContextID ctx, Addr daddr)
|
||||
{
|
||||
auto val = from->readDistributor(ctx, daddr);
|
||||
DPRINTF(GIC, "copy dist 0x%x 0x%08x\n", daddr, val);
|
||||
to->writeDistributor(ctx, daddr, val);
|
||||
}
|
||||
|
||||
void
|
||||
MuxingKvmGic::copyCpuRegister(BaseGicRegisters* from, BaseGicRegisters* to,
|
||||
ContextID ctx, Addr daddr)
|
||||
{
|
||||
auto val = from->readCpu(ctx, daddr);
|
||||
DPRINTF(GIC, "copy cpu 0x%x 0x%08x\n", daddr, val);
|
||||
to->writeCpu(ctx, daddr, val);
|
||||
}
|
||||
|
||||
void
|
||||
MuxingKvmGic::copyBankedDistRange(BaseGicRegisters* from, BaseGicRegisters* to,
|
||||
Addr daddr, size_t size)
|
||||
{
|
||||
for (int ctx = 0; ctx < system._numContexts; ++ctx)
|
||||
for (auto a = daddr; a < daddr + size; a += 4)
|
||||
copyDistRegister(from, to, ctx, a);
|
||||
}
|
||||
|
||||
void
|
||||
MuxingKvmGic::clearBankedDistRange(BaseGicRegisters* to,
|
||||
Addr daddr, size_t size)
|
||||
{
|
||||
for (int ctx = 0; ctx < system._numContexts; ++ctx)
|
||||
for (auto a = daddr; a < daddr + size; a += 4)
|
||||
to->writeDistributor(ctx, a, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
void
|
||||
MuxingKvmGic::copyDistRange(BaseGicRegisters* from, BaseGicRegisters* to,
|
||||
Addr daddr, size_t size)
|
||||
{
|
||||
for (auto a = daddr; a < daddr + size; a += 4)
|
||||
copyDistRegister(from, to, 0, a);
|
||||
}
|
||||
|
||||
void
|
||||
MuxingKvmGic::clearDistRange(BaseGicRegisters* to,
|
||||
Addr daddr, size_t size)
|
||||
{
|
||||
for (auto a = daddr; a < daddr + size; a += 4)
|
||||
to->writeDistributor(0, a, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
void
|
||||
MuxingKvmGic::copyGicState(BaseGicRegisters* from, BaseGicRegisters* to)
|
||||
{
|
||||
Addr set, clear;
|
||||
size_t size;
|
||||
|
||||
/// CPU state (GICC_*)
|
||||
// Copy CPU Interface Control Register (CTLR),
|
||||
// Interrupt Priority Mask Register (PMR), and
|
||||
// Binary Point Register (BPR)
|
||||
for (int ctx = 0; ctx < system._numContexts; ++ctx) {
|
||||
copyCpuRegister(from, to, ctx, GICC_CTLR);
|
||||
copyCpuRegister(from, to, ctx, GICC_PMR);
|
||||
copyCpuRegister(from, to, ctx, GICC_BPR);
|
||||
}
|
||||
|
||||
|
||||
/// Distributor state (GICD_*)
|
||||
// Copy Distributor Control Register (CTLR)
|
||||
copyDistRegister(from, to, 0, GICD_CTLR);
|
||||
|
||||
// Copy interrupt-enabled statuses (I[CS]ENABLERn; R0 is per-CPU banked)
|
||||
set = Pl390::GICD_ISENABLER.start();
|
||||
clear = Pl390::GICD_ICENABLER.start();
|
||||
size = Pl390::itLines / 8;
|
||||
clearBankedDistRange(to, clear, 4);
|
||||
copyBankedDistRange(from, to, set, 4);
|
||||
|
||||
set += 4, clear += 4, size -= 4;
|
||||
clearDistRange(to, clear, size);
|
||||
copyDistRange(from, to, set, size);
|
||||
|
||||
// Copy pending interrupts (I[CS]PENDRn; R0 is per-CPU banked)
|
||||
set = Pl390::GICD_ISPENDR.start();
|
||||
clear = Pl390::GICD_ICPENDR.start();
|
||||
size = Pl390::itLines / 8;
|
||||
clearBankedDistRange(to, clear, 4);
|
||||
copyBankedDistRange(from, to, set, 4);
|
||||
|
||||
set += 4, clear += 4, size -= 4;
|
||||
clearDistRange(to, clear, size);
|
||||
copyDistRange(from, to, set, size);
|
||||
|
||||
// Copy active interrupts (I[CS]ACTIVERn; R0 is per-CPU banked)
|
||||
set = Pl390::GICD_ISACTIVER.start();
|
||||
clear = Pl390::GICD_ICACTIVER.start();
|
||||
size = Pl390::itLines / 8;
|
||||
clearBankedDistRange(to, clear, 4);
|
||||
copyBankedDistRange(from, to, set, 4);
|
||||
|
||||
set += 4, clear += 4, size -= 4;
|
||||
clearDistRange(to, clear, size);
|
||||
copyDistRange(from, to, set, size);
|
||||
|
||||
// Copy interrupt priorities (IPRIORITYRn; R0-7 are per-CPU banked)
|
||||
set = Pl390::GICD_IPRIORITYR.start();
|
||||
copyBankedDistRange(from, to, set, 32);
|
||||
|
||||
set += 32;
|
||||
size = Pl390::itLines - 32;
|
||||
copyDistRange(from, to, set, size);
|
||||
|
||||
// Copy interrupt processor target regs (ITARGETRn; R0-7 are read-only)
|
||||
set = Pl390::GICD_ITARGETSR.start() + 32;
|
||||
size = Pl390::itLines - 32;
|
||||
copyDistRange(from, to, set, size);
|
||||
|
||||
// Copy interrupt configuration registers (ICFGRn)
|
||||
set = Pl390::GICD_ICFGR.start();
|
||||
size = Pl390::itLines / 4;
|
||||
copyDistRange(from, to, set, size);
|
||||
}
|
||||
|
||||
void
|
||||
MuxingKvmGic::fromPl390ToKvm()
|
||||
{
|
||||
copyGicState(static_cast<Pl390*>(this), kernelGic);
|
||||
panic("Gic multiplexing not implemented.\n");
|
||||
}
|
||||
|
||||
void
|
||||
MuxingKvmGic::fromKvmToPl390()
|
||||
{
|
||||
copyGicState(kernelGic, static_cast<Pl390*>(this));
|
||||
|
||||
// the values read for the Interrupt Priority Mask Register (PMR)
|
||||
// have been shifted by three bits due to its having been emulated by
|
||||
// a VGIC with only 5 PMR bits in its VMCR register. Presently the
|
||||
// Linux kernel does not repair this inaccuracy, so we correct it here.
|
||||
for (int cpu = 0; cpu < system._numContexts; ++cpu) {
|
||||
cpuPriority[cpu] <<= 3;
|
||||
assert((cpuPriority[cpu] & ~0xff) == 0);
|
||||
}
|
||||
panic("Gic multiplexing not implemented.\n");
|
||||
}
|
||||
|
||||
MuxingKvmGic *
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
* model. It exposes an API that is similar to that of
|
||||
* software-emulated GIC models in gem5.
|
||||
*/
|
||||
class KvmKernelGicV2 : public BaseGicRegisters
|
||||
class KvmKernelGicV2
|
||||
{
|
||||
public:
|
||||
/**
|
||||
|
@ -117,14 +117,6 @@ class KvmKernelGicV2 : public BaseGicRegisters
|
|||
/** Address range for the distributor interface */
|
||||
const AddrRange distRange;
|
||||
|
||||
/** BaseGicRegisters interface */
|
||||
uint32_t readDistributor(ContextID ctx, Addr daddr) override;
|
||||
uint32_t readCpu(ContextID ctx, Addr daddr) override;
|
||||
|
||||
void writeDistributor(ContextID ctx, Addr daddr,
|
||||
uint32_t data) override;
|
||||
void writeCpu(ContextID ctx, Addr daddr, uint32_t data) override;
|
||||
|
||||
/* @} */
|
||||
|
||||
protected:
|
||||
|
@ -138,26 +130,6 @@ class KvmKernelGicV2 : public BaseGicRegisters
|
|||
*/
|
||||
void setIntState(unsigned type, unsigned vcpu, unsigned irq, bool high);
|
||||
|
||||
/**
|
||||
* Get value of GIC register "from" a cpu
|
||||
*
|
||||
* @param group Distributor or CPU (KVM_DEV_ARM_VGIC_GRP_{DIST,CPU}_REGS)
|
||||
* @param vcpu CPU id within KVM
|
||||
* @param offset register offset
|
||||
*/
|
||||
uint32_t getGicReg(unsigned group, unsigned vcpu, unsigned offset);
|
||||
|
||||
/**
|
||||
* Set value of GIC register "from" a cpu
|
||||
*
|
||||
* @param group Distributor or CPU (KVM_DEV_ARM_VGIC_GRP_{DIST,CPU}_REGS)
|
||||
* @param vcpu CPU id within KVM
|
||||
* @param offset register offset
|
||||
* @param value value to set register to
|
||||
*/
|
||||
void setGicReg(unsigned group, unsigned vcpu, unsigned offset,
|
||||
unsigned value);
|
||||
|
||||
/** KVM VM in the parent system */
|
||||
KvmVM &vm;
|
||||
|
||||
|
@ -174,10 +146,7 @@ class MuxingKvmGic : public Pl390
|
|||
MuxingKvmGic(const MuxingKvmGicParams *p);
|
||||
~MuxingKvmGic();
|
||||
|
||||
void loadState(CheckpointIn &cp) override;
|
||||
|
||||
void startup() override;
|
||||
DrainState drain() override;
|
||||
void drainResume() override;
|
||||
|
||||
void serialize(CheckpointOut &cp) const override;
|
||||
|
@ -207,25 +176,9 @@ class MuxingKvmGic : public Pl390
|
|||
private:
|
||||
bool usingKvm;
|
||||
|
||||
/** Multiplexing implementation */
|
||||
/** Multiplexing implementation: state transfer functions */
|
||||
void fromPl390ToKvm();
|
||||
void fromKvmToPl390();
|
||||
|
||||
void copyGicState(BaseGicRegisters* from, BaseGicRegisters* to);
|
||||
|
||||
void copyDistRegister(BaseGicRegisters* from, BaseGicRegisters* to,
|
||||
ContextID ctx, Addr daddr);
|
||||
void copyCpuRegister(BaseGicRegisters* from, BaseGicRegisters* to,
|
||||
ContextID ctx, Addr daddr);
|
||||
|
||||
void copyBankedDistRange(BaseGicRegisters* from, BaseGicRegisters* to,
|
||||
Addr daddr, size_t size);
|
||||
void clearBankedDistRange(BaseGicRegisters* to,
|
||||
Addr daddr, size_t size);
|
||||
void copyDistRange(BaseGicRegisters* from, BaseGicRegisters* to,
|
||||
Addr daddr, size_t size);
|
||||
void clearDistRange(BaseGicRegisters* to,
|
||||
Addr daddr, size_t size);
|
||||
};
|
||||
|
||||
#endif // __ARCH_ARM_KVM_GIC_HH__
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2013, 2015-2017 ARM Limited
|
||||
* Copyright (c) 2010-2013, 2015-2016 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
|
@ -41,8 +41,6 @@
|
|||
|
||||
#include "arch/arm/miscregs.hh"
|
||||
|
||||
#include <tuple>
|
||||
|
||||
#include "arch/arm/isa.hh"
|
||||
#include "base/misc.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
|
@ -1969,12 +1967,11 @@ decodeCP15Reg64(unsigned crm, unsigned opc1)
|
|||
return MISCREG_CP15_UNIMPL;
|
||||
}
|
||||
|
||||
std::tuple<bool, bool>
|
||||
canReadCoprocReg(MiscRegIndex reg, SCR scr, CPSR cpsr)
|
||||
bool
|
||||
canReadCoprocReg(MiscRegIndex reg, SCR scr, CPSR cpsr, ThreadContext *tc)
|
||||
{
|
||||
bool secure = !scr.ns;
|
||||
bool canRead = false;
|
||||
bool undefined = false;
|
||||
bool canRead;
|
||||
|
||||
switch (cpsr.mode) {
|
||||
case MODE_USER:
|
||||
|
@ -1998,19 +1995,18 @@ canReadCoprocReg(MiscRegIndex reg, SCR scr, CPSR cpsr)
|
|||
canRead = miscRegInfo[reg][MISCREG_HYP_RD];
|
||||
break;
|
||||
default:
|
||||
undefined = true;
|
||||
panic("Unrecognized mode setting in CPSR.\n");
|
||||
}
|
||||
// can't do permissions checkes on the root of a banked pair of regs
|
||||
assert(!miscRegInfo[reg][MISCREG_BANKED]);
|
||||
return std::make_tuple(canRead, undefined);
|
||||
return canRead;
|
||||
}
|
||||
|
||||
std::tuple<bool, bool>
|
||||
canWriteCoprocReg(MiscRegIndex reg, SCR scr, CPSR cpsr)
|
||||
bool
|
||||
canWriteCoprocReg(MiscRegIndex reg, SCR scr, CPSR cpsr, ThreadContext *tc)
|
||||
{
|
||||
bool secure = !scr.ns;
|
||||
bool canWrite = false;
|
||||
bool undefined = false;
|
||||
bool canWrite;
|
||||
|
||||
switch (cpsr.mode) {
|
||||
case MODE_USER:
|
||||
|
@ -2034,11 +2030,11 @@ canWriteCoprocReg(MiscRegIndex reg, SCR scr, CPSR cpsr)
|
|||
canWrite = miscRegInfo[reg][MISCREG_HYP_WR];
|
||||
break;
|
||||
default:
|
||||
undefined = true;
|
||||
panic("Unrecognized mode setting in CPSR.\n");
|
||||
}
|
||||
// can't do permissions checkes on the root of a banked pair of regs
|
||||
assert(!miscRegInfo[reg][MISCREG_BANKED]);
|
||||
return std::make_tuple(canWrite, undefined);
|
||||
return canWrite;
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2017 ARM Limited
|
||||
* Copyright (c) 2010-2016 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
|
@ -44,7 +44,6 @@
|
|||
#define __ARCH_ARM_MISCREGS_HH__
|
||||
|
||||
#include <bitset>
|
||||
#include <tuple>
|
||||
|
||||
#include "base/bitunion.hh"
|
||||
#include "base/compiler.hh"
|
||||
|
@ -1848,37 +1847,13 @@ namespace ArmISA
|
|||
EndBitUnion(CPTR)
|
||||
|
||||
|
||||
/**
|
||||
* Check for permission to read coprocessor registers.
|
||||
*
|
||||
* Checks whether an instruction at the current program mode has
|
||||
* permissions to read the coprocessor registers. This function
|
||||
* returns whether the check is undefined and if not whether the
|
||||
* read access is permitted.
|
||||
*
|
||||
* @param the misc reg indicating the coprocessor
|
||||
* @param the SCR
|
||||
* @param the CPSR
|
||||
* @return a tuple of booleans: can_read, undefined
|
||||
*/
|
||||
std::tuple<bool, bool> canReadCoprocReg(MiscRegIndex reg, SCR scr,
|
||||
CPSR cpsr);
|
||||
// Checks read access permissions to coproc. registers
|
||||
bool canReadCoprocReg(MiscRegIndex reg, SCR scr, CPSR cpsr,
|
||||
ThreadContext *tc);
|
||||
|
||||
/**
|
||||
* Check for permission to write coprocessor registers.
|
||||
*
|
||||
* Checks whether an instruction at the current program mode has
|
||||
* permissions to write the coprocessor registers. This function
|
||||
* returns whether the check is undefined and if not whether the
|
||||
* write access is permitted.
|
||||
*
|
||||
* @param the misc reg indicating the coprocessor
|
||||
* @param the SCR
|
||||
* @param the CPSR
|
||||
* @return a tuple of booleans: can_write, undefined
|
||||
*/
|
||||
std::tuple<bool, bool> canWriteCoprocReg(MiscRegIndex reg, SCR scr,
|
||||
CPSR cpsr);
|
||||
// Checks write access permissions to coproc. registers
|
||||
bool canWriteCoprocReg(MiscRegIndex reg, SCR scr, CPSR cpsr,
|
||||
ThreadContext *tc);
|
||||
|
||||
// Checks read access permissions to AArch64 system registers
|
||||
bool canReadAArch64SysReg(MiscRegIndex reg, SCR scr, CPSR cpsr,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2010, 2012-2017 ARM Limited
|
||||
* Copyright (c) 2010, 2012-2016 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
|
@ -1342,10 +1342,7 @@ TableWalker::memAttrsAArch64(ThreadContext *tc, TlbEntry &te,
|
|||
attr_hi == 2 ? 2 : 1;
|
||||
te.innerAttrs = attr_lo == 1 ? 0 :
|
||||
attr_lo == 2 ? 6 : 5;
|
||||
// Treat write-through memory as uncacheable, this is safe
|
||||
// but for performance reasons not optimal.
|
||||
te.nonCacheable = (attr_hi == 1) || (attr_hi == 2) ||
|
||||
(attr_lo == 1) || (attr_lo == 2);
|
||||
te.nonCacheable = (attr_hi == 1) || (attr_lo == 1);
|
||||
}
|
||||
} else {
|
||||
uint8_t attrIndx = lDescriptor.attrIndx();
|
||||
|
@ -1380,25 +1377,9 @@ TableWalker::memAttrsAArch64(ThreadContext *tc, TlbEntry &te,
|
|||
|
||||
// Cacheability
|
||||
te.nonCacheable = false;
|
||||
if (te.mtype == TlbEntry::MemoryType::Device) { // Device memory
|
||||
te.nonCacheable = true;
|
||||
}
|
||||
// Treat write-through memory as uncacheable, this is safe
|
||||
// but for performance reasons not optimal.
|
||||
switch (attr_hi) {
|
||||
case 0x1 ... 0x3: // Normal Memory, Outer Write-through transient
|
||||
case 0x4: // Normal memory, Outer Non-cacheable
|
||||
case 0x8 ... 0xb: // Normal Memory, Outer Write-through non-transient
|
||||
te.nonCacheable = true;
|
||||
}
|
||||
switch (attr_lo) {
|
||||
case 0x1 ... 0x3: // Normal Memory, Inner Write-through transient
|
||||
case 0x9 ... 0xb: // Normal Memory, Inner Write-through non-transient
|
||||
warn_if(!attr_hi, "Unpredictable behavior");
|
||||
case 0x4: // Device-nGnRE memory or
|
||||
// Normal memory, Inner Non-cacheable
|
||||
case 0x8: // Device-nGRE memory or
|
||||
// Normal memory, Inner Write-through non-transient
|
||||
if (te.mtype == TlbEntry::MemoryType::Device || // Device memory
|
||||
attr_hi == 0x8 || // Normal memory, Outer Non-cacheable
|
||||
attr_lo == 0x8) { // Normal memory, Inner Non-cacheable
|
||||
te.nonCacheable = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -106,7 +106,6 @@ class BaseKvmCPU : public BaseCPU
|
|||
void deallocateContext(ThreadID thread_num);
|
||||
void haltContext(ThreadID thread_num) override;
|
||||
|
||||
long getVCpuID() const { return vcpuID; }
|
||||
ThreadContext *getContext(int tn) override;
|
||||
|
||||
Counter totalInsts() const override;
|
||||
|
|
|
@ -50,7 +50,6 @@
|
|||
#include <cerrno>
|
||||
#include <memory>
|
||||
|
||||
#include "cpu/kvm/base.hh"
|
||||
#include "debug/Kvm.hh"
|
||||
#include "params/KvmVM.hh"
|
||||
#include "sim/system.hh"
|
||||
|
@ -529,21 +528,12 @@ KvmVM::createDevice(uint32_t type, uint32_t flags)
|
|||
}
|
||||
|
||||
void
|
||||
KvmVM::setSystem(System *s)
|
||||
{
|
||||
KvmVM::setSystem(System *s) {
|
||||
panic_if(system != nullptr, "setSystem() can only be called once");
|
||||
panic_if(s == nullptr, "setSystem() called with null System*");
|
||||
system = s;
|
||||
}
|
||||
|
||||
long
|
||||
KvmVM::contextIdToVCpuId(ContextID ctx) const
|
||||
{
|
||||
assert(system != nullptr);
|
||||
return dynamic_cast<BaseKvmCPU*>
|
||||
(system->getThreadContext(ctx)->getCpuPtr())->getVCpuID();
|
||||
}
|
||||
|
||||
int
|
||||
KvmVM::createVCPU(long vcpuID)
|
||||
{
|
||||
|
|
|
@ -48,7 +48,6 @@
|
|||
|
||||
// forward declarations
|
||||
struct KvmVMParams;
|
||||
class BaseKvmCPU;
|
||||
class System;
|
||||
|
||||
/**
|
||||
|
@ -406,11 +405,6 @@ class KvmVM : public SimObject
|
|||
*/
|
||||
void setSystem(System *s);
|
||||
|
||||
/**
|
||||
* Get the VCPUID for a given context
|
||||
*/
|
||||
long contextIdToVCpuId(ContextID ctx) const;
|
||||
|
||||
#if defined(__aarch64__)
|
||||
public: // ARM-specific
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2013, 2017 ARM Limited
|
||||
* Copyright (c) 2012-2013 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
|
@ -92,15 +92,4 @@ class BaseGic : public PioDevice
|
|||
Platform *platform;
|
||||
};
|
||||
|
||||
class BaseGicRegisters
|
||||
{
|
||||
public:
|
||||
virtual uint32_t readDistributor(ContextID ctx, Addr daddr) = 0;
|
||||
virtual uint32_t readCpu(ContextID ctx, Addr daddr) = 0;
|
||||
|
||||
virtual void writeDistributor(ContextID ctx, Addr daddr,
|
||||
uint32_t data) = 0;
|
||||
virtual void writeCpu(ContextID ctx, Addr daddr, uint32_t data) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -83,7 +83,7 @@ Pl390::Pl390(const Params *p)
|
|||
iccrpr[x] = 0xff;
|
||||
cpuEnabled[x] = false;
|
||||
cpuPriority[x] = 0xff;
|
||||
cpuBpr[x] = GICC_BPR_MINIMUM;
|
||||
cpuBpr[x] = 0;
|
||||
// Initialize cpu highest int
|
||||
cpuHighestInt[x] = SPURIOUS_INT;
|
||||
postIntEvent[x] = new PostIntEvent(*this, x);
|
||||
|
@ -129,64 +129,46 @@ Pl390::readDistributor(PacketPtr pkt)
|
|||
|
||||
DPRINTF(GIC, "gic distributor read register %#x\n", daddr);
|
||||
|
||||
const uint32_t resp = readDistributor(ctx, daddr, pkt->getSize());
|
||||
|
||||
switch (pkt->getSize()) {
|
||||
case 1:
|
||||
pkt->set<uint8_t>(resp);
|
||||
break;
|
||||
case 2:
|
||||
pkt->set<uint16_t>(resp);
|
||||
break;
|
||||
case 4:
|
||||
pkt->set<uint32_t>(resp);
|
||||
break;
|
||||
default:
|
||||
panic("Invalid size while reading Distributor regs in GIC: %d\n",
|
||||
pkt->getSize());
|
||||
}
|
||||
|
||||
pkt->makeAtomicResponse();
|
||||
return distPioDelay;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
Pl390::readDistributor(ContextID ctx, Addr daddr, size_t resp_sz)
|
||||
{
|
||||
if (GICD_ISENABLER.contains(daddr)) {
|
||||
uint32_t ix = (daddr - GICD_ISENABLER.start()) >> 2;
|
||||
assert(ix < 32);
|
||||
return getIntEnabled(ctx, ix);
|
||||
pkt->set<uint32_t>(getIntEnabled(ctx, ix));
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (GICD_ICENABLER.contains(daddr)) {
|
||||
uint32_t ix = (daddr - GICD_ICENABLER.start()) >> 2;
|
||||
assert(ix < 32);
|
||||
return getIntEnabled(ctx, ix);
|
||||
pkt->set<uint32_t>(getIntEnabled(ctx, ix));
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (GICD_ISPENDR.contains(daddr)) {
|
||||
uint32_t ix = (daddr - GICD_ISPENDR.start()) >> 2;
|
||||
assert(ix < 32);
|
||||
return getPendingInt(ctx, ix);
|
||||
pkt->set<uint32_t>(getPendingInt(ctx, ix));
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (GICD_ICPENDR.contains(daddr)) {
|
||||
uint32_t ix = (daddr - GICD_ICPENDR.start()) >> 2;
|
||||
assert(ix < 32);
|
||||
return getPendingInt(ctx, ix);
|
||||
pkt->set<uint32_t>(getPendingInt(ctx, ix));
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (GICD_ISACTIVER.contains(daddr)) {
|
||||
uint32_t ix = (daddr - GICD_ISACTIVER.start()) >> 2;
|
||||
assert(ix < 32);
|
||||
return getActiveInt(ctx, ix);
|
||||
pkt->set<uint32_t>(getActiveInt(ctx, ix));
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (GICD_ICACTIVER.contains(daddr)) {
|
||||
uint32_t ix = (daddr - GICD_ICACTIVER.start()) >> 2;
|
||||
assert(ix < 32);
|
||||
return getActiveInt(ctx, ix);
|
||||
pkt->set<uint32_t>(getActiveInt(ctx, ix));
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (GICD_IPRIORITYR.contains(daddr)) {
|
||||
|
@ -194,21 +176,27 @@ Pl390::readDistributor(ContextID ctx, Addr daddr, size_t resp_sz)
|
|||
assert(int_num < INT_LINES_MAX);
|
||||
DPRINTF(Interrupt, "Reading interrupt priority at int# %#x \n",int_num);
|
||||
|
||||
switch (resp_sz) {
|
||||
default: // will panic() after return to caller anyway
|
||||
switch (pkt->getSize()) {
|
||||
case 1:
|
||||
return getIntPriority(ctx, int_num);
|
||||
pkt->set<uint8_t>(getIntPriority(ctx, int_num));
|
||||
break;
|
||||
case 2:
|
||||
assert((int_num + 1) < INT_LINES_MAX);
|
||||
return (getIntPriority(ctx, int_num) |
|
||||
getIntPriority(ctx, int_num+1) << 8);
|
||||
pkt->set<uint16_t>(getIntPriority(ctx, int_num) |
|
||||
getIntPriority(ctx, int_num+1) << 8);
|
||||
break;
|
||||
case 4:
|
||||
assert((int_num + 3) < INT_LINES_MAX);
|
||||
return (getIntPriority(ctx, int_num) |
|
||||
getIntPriority(ctx, int_num+1) << 8 |
|
||||
getIntPriority(ctx, int_num+2) << 16 |
|
||||
getIntPriority(ctx, int_num+3) << 24);
|
||||
pkt->set<uint32_t>(getIntPriority(ctx, int_num) |
|
||||
getIntPriority(ctx, int_num+1) << 8 |
|
||||
getIntPriority(ctx, int_num+2) << 16 |
|
||||
getIntPriority(ctx, int_num+3) << 24);
|
||||
break;
|
||||
default:
|
||||
panic("Invalid size while reading priority regs in GIC: %d\n",
|
||||
pkt->getSize());
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (GICD_ITARGETSR.contains(daddr)) {
|
||||
|
@ -217,16 +205,33 @@ Pl390::readDistributor(ContextID ctx, Addr daddr, size_t resp_sz)
|
|||
int_num);
|
||||
assert(int_num < INT_LINES_MAX);
|
||||
|
||||
if (resp_sz == 1) {
|
||||
return getCpuTarget(ctx, int_num);
|
||||
// First 31 interrupts only target single processor (SGI)
|
||||
if (int_num > 31) {
|
||||
if (pkt->getSize() == 1) {
|
||||
pkt->set<uint8_t>(cpuTarget[int_num]);
|
||||
} else {
|
||||
assert(pkt->getSize() == 4);
|
||||
int_num = mbits(int_num, 31, 2);
|
||||
pkt->set<uint32_t>(cpuTarget[int_num] |
|
||||
cpuTarget[int_num+1] << 8 |
|
||||
cpuTarget[int_num+2] << 16 |
|
||||
cpuTarget[int_num+3] << 24) ;
|
||||
}
|
||||
} else {
|
||||
assert(resp_sz == 4);
|
||||
int_num = mbits(int_num, 31, 2);
|
||||
return (getCpuTarget(ctx, int_num) |
|
||||
getCpuTarget(ctx, int_num+1) << 8 |
|
||||
getCpuTarget(ctx, int_num+2) << 16 |
|
||||
getCpuTarget(ctx, int_num+3) << 24) ;
|
||||
assert(ctx < sys->numRunningContexts());
|
||||
uint32_t ctx_mask;
|
||||
if (gem5ExtensionsEnabled) {
|
||||
ctx_mask = ctx;
|
||||
} else {
|
||||
// convert the CPU id number into a bit mask
|
||||
ctx_mask = power(2, ctx);
|
||||
}
|
||||
// replicate the 8-bit mask 4 times in a 32-bit word
|
||||
ctx_mask |= ctx_mask << 8;
|
||||
ctx_mask |= ctx_mask << 16;
|
||||
pkt->set<uint32_t>(ctx_mask);
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (GICD_ICFGR.contains(daddr)) {
|
||||
|
@ -234,23 +239,30 @@ Pl390::readDistributor(ContextID ctx, Addr daddr, size_t resp_sz)
|
|||
assert(ix < 64);
|
||||
/** @todo software generated interrupts and PPIs
|
||||
* can't be configured in some ways */
|
||||
return intConfig[ix];
|
||||
pkt->set<uint32_t>(intConfig[ix]);
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch(daddr) {
|
||||
case GICD_CTLR:
|
||||
return enabled;
|
||||
case GICD_TYPER:
|
||||
pkt->set<uint32_t>(enabled);
|
||||
break;
|
||||
case GICD_TYPER: {
|
||||
/* The 0x100 is a made-up flag to show that gem5 extensions
|
||||
* are available,
|
||||
* write 0x200 to this register to enable it. */
|
||||
return (((sys->numRunningContexts() - 1) << 5) |
|
||||
(itLines/INT_BITS_MAX -1) |
|
||||
(haveGem5Extensions ? 0x100 : 0x0));
|
||||
uint32_t tmp = ((sys->numRunningContexts() - 1) << 5) |
|
||||
(itLines/INT_BITS_MAX -1) |
|
||||
(haveGem5Extensions ? 0x100 : 0x0);
|
||||
pkt->set<uint32_t>(tmp);
|
||||
} break;
|
||||
default:
|
||||
panic("Tried to read Gic distributor at offset %#x\n", daddr);
|
||||
break;
|
||||
}
|
||||
done:
|
||||
pkt->makeAtomicResponse();
|
||||
return distPioDelay;
|
||||
}
|
||||
|
||||
Tick
|
||||
|
@ -265,24 +277,19 @@ Pl390::readCpu(PacketPtr pkt)
|
|||
DPRINTF(GIC, "gic cpu read register %#x cpu context: %d\n", daddr,
|
||||
ctx);
|
||||
|
||||
pkt->set<uint32_t>(readCpu(ctx, daddr));
|
||||
|
||||
pkt->makeAtomicResponse();
|
||||
return cpuPioDelay;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
Pl390::readCpu(ContextID ctx, Addr daddr)
|
||||
{
|
||||
switch(daddr) {
|
||||
case GICC_IIDR:
|
||||
return 0;
|
||||
pkt->set<uint32_t>(0);
|
||||
break;
|
||||
case GICC_CTLR:
|
||||
return cpuEnabled[ctx];
|
||||
pkt->set<uint32_t>(cpuEnabled[ctx]);
|
||||
break;
|
||||
case GICC_PMR:
|
||||
return cpuPriority[ctx];
|
||||
pkt->set<uint32_t>(cpuPriority[ctx]);
|
||||
break;
|
||||
case GICC_BPR:
|
||||
return cpuBpr[ctx];
|
||||
pkt->set<uint32_t>(cpuBpr[ctx]);
|
||||
break;
|
||||
case GICC_IAR:
|
||||
if (enabled && cpuEnabled[ctx]) {
|
||||
int active_int = cpuHighestInt[ctx];
|
||||
|
@ -330,22 +337,26 @@ Pl390::readCpu(ContextID ctx, Addr daddr)
|
|||
ctx, iar.ack_id, iar.cpu_id, iar);
|
||||
cpuHighestInt[ctx] = SPURIOUS_INT;
|
||||
updateIntState(-1);
|
||||
pkt->set<uint32_t>(iar);
|
||||
platform->intrctrl->clear(ctx, ArmISA::INT_IRQ, 0);
|
||||
return iar;
|
||||
} else {
|
||||
return SPURIOUS_INT;
|
||||
pkt->set<uint32_t>(SPURIOUS_INT);
|
||||
}
|
||||
|
||||
break;
|
||||
case GICC_RPR:
|
||||
return iccrpr[0];
|
||||
pkt->set<uint32_t>(iccrpr[0]);
|
||||
break;
|
||||
case GICC_HPPIR:
|
||||
pkt->set<uint32_t>(0);
|
||||
panic("Need to implement HPIR");
|
||||
break;
|
||||
default:
|
||||
panic("Tried to read Gic cpu at offset %#x\n", daddr);
|
||||
break;
|
||||
}
|
||||
pkt->makeAtomicResponse();
|
||||
return cpuPioDelay;
|
||||
}
|
||||
|
||||
Tick
|
||||
|
@ -355,10 +366,9 @@ Pl390::writeDistributor(PacketPtr pkt)
|
|||
|
||||
assert(pkt->req->hasContextId());
|
||||
const ContextID ctx = pkt->req->contextId();
|
||||
const size_t data_sz = pkt->getSize();
|
||||
|
||||
uint32_t pkt_data M5_VAR_USED;
|
||||
switch (data_sz)
|
||||
switch (pkt->getSize())
|
||||
{
|
||||
case 1:
|
||||
pkt_data = pkt->get<uint8_t>();
|
||||
|
@ -371,143 +381,141 @@ Pl390::writeDistributor(PacketPtr pkt)
|
|||
break;
|
||||
default:
|
||||
panic("Invalid size when writing to priority regs in Gic: %d\n",
|
||||
data_sz);
|
||||
pkt->getSize());
|
||||
}
|
||||
|
||||
DPRINTF(GIC, "gic distributor write register %#x size %#x value %#x \n",
|
||||
daddr, data_sz, pkt_data);
|
||||
daddr, pkt->getSize(), pkt_data);
|
||||
|
||||
writeDistributor(ctx, daddr, pkt_data, data_sz);
|
||||
|
||||
pkt->makeAtomicResponse();
|
||||
return distPioDelay;
|
||||
}
|
||||
|
||||
void
|
||||
Pl390::writeDistributor(ContextID ctx, Addr daddr, uint32_t data,
|
||||
size_t data_sz)
|
||||
{
|
||||
if (GICD_ISENABLER.contains(daddr)) {
|
||||
uint32_t ix = (daddr - GICD_ISENABLER.start()) >> 2;
|
||||
assert(ix < 32);
|
||||
getIntEnabled(ctx, ix) |= data;
|
||||
return;
|
||||
getIntEnabled(ctx, ix) |= pkt->get<uint32_t>();
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (GICD_ICENABLER.contains(daddr)) {
|
||||
uint32_t ix = (daddr - GICD_ICENABLER.start()) >> 2;
|
||||
assert(ix < 32);
|
||||
getIntEnabled(ctx, ix) &= ~data;
|
||||
return;
|
||||
getIntEnabled(ctx, ix) &= ~pkt->get<uint32_t>();
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (GICD_ISPENDR.contains(daddr)) {
|
||||
uint32_t ix = (daddr - GICD_ISPENDR.start()) >> 2;
|
||||
auto mask = data;
|
||||
auto mask = pkt->get<uint32_t>();
|
||||
if (ix == 0) mask &= SGI_MASK; // Don't allow SGIs to be changed
|
||||
getPendingInt(ctx, ix) |= mask;
|
||||
updateIntState(ix);
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (GICD_ICPENDR.contains(daddr)) {
|
||||
uint32_t ix = (daddr - GICD_ICPENDR.start()) >> 2;
|
||||
auto mask = data;
|
||||
auto mask = pkt->get<uint32_t>();
|
||||
if (ix == 0) mask &= SGI_MASK; // Don't allow SGIs to be changed
|
||||
getPendingInt(ctx, ix) &= ~mask;
|
||||
updateIntState(ix);
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (GICD_ISACTIVER.contains(daddr)) {
|
||||
uint32_t ix = (daddr - GICD_ISACTIVER.start()) >> 2;
|
||||
getActiveInt(ctx, ix) |= data;
|
||||
return;
|
||||
getActiveInt(ctx, ix) |= pkt->get<uint32_t>();
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (GICD_ICACTIVER.contains(daddr)) {
|
||||
uint32_t ix = (daddr - GICD_ICACTIVER.start()) >> 2;
|
||||
getActiveInt(ctx, ix) &= ~data;
|
||||
return;
|
||||
getActiveInt(ctx, ix) &= ~pkt->get<uint32_t>();
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (GICD_IPRIORITYR.contains(daddr)) {
|
||||
Addr int_num = daddr - GICD_IPRIORITYR.start();
|
||||
switch(data_sz) {
|
||||
switch(pkt->getSize()) {
|
||||
case 1:
|
||||
getIntPriority(ctx, int_num) = data;
|
||||
getIntPriority(ctx, int_num) = pkt->get<uint8_t>();
|
||||
break;
|
||||
case 2: {
|
||||
getIntPriority(ctx, int_num) = bits(data, 7, 0);
|
||||
getIntPriority(ctx, int_num + 1) = bits(data, 15, 8);
|
||||
auto tmp16 = pkt->get<uint16_t>();
|
||||
getIntPriority(ctx, int_num) = bits(tmp16, 7, 0);
|
||||
getIntPriority(ctx, int_num + 1) = bits(tmp16, 15, 8);
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
getIntPriority(ctx, int_num) = bits(data, 7, 0);
|
||||
getIntPriority(ctx, int_num + 1) = bits(data, 15, 8);
|
||||
getIntPriority(ctx, int_num + 2) = bits(data, 23, 16);
|
||||
getIntPriority(ctx, int_num + 3) = bits(data, 31, 24);
|
||||
auto tmp32 = pkt->get<uint32_t>();
|
||||
getIntPriority(ctx, int_num) = bits(tmp32, 7, 0);
|
||||
getIntPriority(ctx, int_num + 1) = bits(tmp32, 15, 8);
|
||||
getIntPriority(ctx, int_num + 2) = bits(tmp32, 23, 16);
|
||||
getIntPriority(ctx, int_num + 3) = bits(tmp32, 31, 24);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
panic("Invalid size when writing to priority regs in Gic: %d\n",
|
||||
data_sz);
|
||||
pkt->getSize());
|
||||
}
|
||||
|
||||
updateIntState(-1);
|
||||
updateRunPri();
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (GICD_ITARGETSR.contains(daddr)) {
|
||||
Addr int_num = daddr - GICD_ITARGETSR.start();
|
||||
// Interrupts 0-31 are read only
|
||||
unsigned offset = SGI_MAX + PPI_MAX;
|
||||
if (int_num >= offset) {
|
||||
unsigned ix = int_num - offset; // index into cpuTarget array
|
||||
if (data_sz == 1) {
|
||||
cpuTarget[ix] = data & 0xff;
|
||||
// First 31 interrupts only target single processor
|
||||
if (int_num >= SGI_MAX) {
|
||||
if (pkt->getSize() == 1) {
|
||||
uint8_t tmp = pkt->get<uint8_t>();
|
||||
cpuTarget[int_num] = tmp & 0xff;
|
||||
} else {
|
||||
assert (data_sz == 4);
|
||||
cpuTarget[ix] = bits(data, 7, 0);
|
||||
cpuTarget[ix+1] = bits(data, 15, 8);
|
||||
cpuTarget[ix+2] = bits(data, 23, 16);
|
||||
cpuTarget[ix+3] = bits(data, 31, 24);
|
||||
assert (pkt->getSize() == 4);
|
||||
int_num = mbits(int_num, 31, 2);
|
||||
uint32_t tmp = pkt->get<uint32_t>();
|
||||
cpuTarget[int_num] = bits(tmp, 7, 0);
|
||||
cpuTarget[int_num+1] = bits(tmp, 15, 8);
|
||||
cpuTarget[int_num+2] = bits(tmp, 23, 16);
|
||||
cpuTarget[int_num+3] = bits(tmp, 31, 24);
|
||||
}
|
||||
updateIntState(int_num >> 2);
|
||||
}
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (GICD_ICFGR.contains(daddr)) {
|
||||
uint32_t ix = (daddr - GICD_ICFGR.start()) >> 2;
|
||||
assert(ix < INT_BITS_MAX*2);
|
||||
intConfig[ix] = data;
|
||||
if (data & NN_CONFIG_MASK)
|
||||
intConfig[ix] = pkt->get<uint32_t>();
|
||||
if (pkt->get<uint32_t>() & NN_CONFIG_MASK)
|
||||
warn("GIC N:N mode selected and not supported at this time\n");
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch(daddr) {
|
||||
case GICD_CTLR:
|
||||
enabled = data;
|
||||
enabled = pkt->get<uint32_t>();
|
||||
DPRINTF(Interrupt, "Distributor enable flag set to = %d\n", enabled);
|
||||
break;
|
||||
case GICD_TYPER:
|
||||
/* 0x200 is a made-up flag to enable gem5 extension functionality.
|
||||
* This reg is not normally written.
|
||||
*/
|
||||
gem5ExtensionsEnabled = (data & 0x200) && haveGem5Extensions;
|
||||
gem5ExtensionsEnabled = (
|
||||
(pkt->get<uint32_t>() & 0x200) && haveGem5Extensions);
|
||||
DPRINTF(GIC, "gem5 extensions %s\n",
|
||||
gem5ExtensionsEnabled ? "enabled" : "disabled");
|
||||
break;
|
||||
case GICD_SGIR:
|
||||
softInt(ctx, data);
|
||||
softInt(ctx, pkt->get<uint32_t>());
|
||||
break;
|
||||
default:
|
||||
panic("Tried to write Gic distributor at offset %#x\n", daddr);
|
||||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
pkt->makeAtomicResponse();
|
||||
return distPioDelay;
|
||||
}
|
||||
|
||||
Tick
|
||||
|
@ -517,36 +525,23 @@ Pl390::writeCpu(PacketPtr pkt)
|
|||
|
||||
assert(pkt->req->hasContextId());
|
||||
const ContextID ctx = pkt->req->contextId();
|
||||
const uint32_t data = pkt->get<uint32_t>();
|
||||
IAR iar;
|
||||
|
||||
DPRINTF(GIC, "gic cpu write register cpu:%d %#x val: %#x\n",
|
||||
ctx, daddr, data);
|
||||
ctx, daddr, pkt->get<uint32_t>());
|
||||
|
||||
writeCpu(ctx, daddr, data);
|
||||
|
||||
pkt->makeAtomicResponse();
|
||||
return cpuPioDelay;
|
||||
}
|
||||
|
||||
void
|
||||
Pl390::writeCpu(ContextID ctx, Addr daddr, uint32_t data)
|
||||
{
|
||||
switch(daddr) {
|
||||
case GICC_CTLR:
|
||||
cpuEnabled[ctx] = data;
|
||||
cpuEnabled[ctx] = pkt->get<uint32_t>();
|
||||
break;
|
||||
case GICC_PMR:
|
||||
cpuPriority[ctx] = data;
|
||||
cpuPriority[ctx] = pkt->get<uint32_t>();
|
||||
break;
|
||||
case GICC_BPR: {
|
||||
auto bpr = data & 0x7;
|
||||
if (bpr < GICC_BPR_MINIMUM)
|
||||
bpr = GICC_BPR_MINIMUM;
|
||||
cpuBpr[ctx] = bpr;
|
||||
case GICC_BPR:
|
||||
cpuBpr[ctx] = pkt->get<uint32_t>();
|
||||
break;
|
||||
}
|
||||
case GICC_EOIR: {
|
||||
const IAR iar = data;
|
||||
case GICC_EOIR:
|
||||
iar = pkt->get<uint32_t>();
|
||||
if (iar.ack_id < SGI_MAX) {
|
||||
// Clear out the bit that corresponds to the cleared int
|
||||
uint64_t clr_int = ULL(1) << (ctx + 8 * iar.cpu_id);
|
||||
|
@ -574,12 +569,13 @@ Pl390::writeCpu(ContextID ctx, Addr daddr, uint32_t data)
|
|||
DPRINTF(Interrupt, "CPU %d done handling intr IAR = %d from cpu %d\n",
|
||||
ctx, iar.ack_id, iar.cpu_id);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
panic("Tried to write Gic cpu at offset %#x\n", daddr);
|
||||
break;
|
||||
}
|
||||
if (cpuEnabled[ctx]) updateIntState(-1);
|
||||
pkt->makeAtomicResponse();
|
||||
return cpuPioDelay;
|
||||
}
|
||||
|
||||
Pl390::BankedRegs&
|
||||
|
@ -670,17 +666,6 @@ Pl390::genSwiMask(int cpu)
|
|||
return ULL(0x0101010101010101) << cpu;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
Pl390::getCpuPriority(unsigned cpu)
|
||||
{
|
||||
// see Table 3-2 in IHI0048B.b (GICv2)
|
||||
// mask some low-order priority bits per BPR value
|
||||
// NB: the GIC prioritization scheme is upside down:
|
||||
// lower values are higher priority; masking off bits
|
||||
// actually creates a higher priority, not lower.
|
||||
return cpuPriority[cpu] & (0xff00 >> (7 - cpuBpr[cpu]));
|
||||
}
|
||||
|
||||
void
|
||||
Pl390::updateIntState(int hint)
|
||||
{
|
||||
|
@ -691,7 +676,7 @@ Pl390::updateIntState(int hint)
|
|||
/*@todo use hint to do less work. */
|
||||
int highest_int = SPURIOUS_INT;
|
||||
// Priorities below that set in GICC_PMR can be ignored
|
||||
uint8_t highest_pri = getCpuPriority(cpu);
|
||||
uint8_t highest_pri = cpuPriority[cpu];
|
||||
|
||||
// Check SGIs
|
||||
for (int swi = 0; swi < SGI_MAX; swi++) {
|
||||
|
@ -732,8 +717,8 @@ Pl390::updateIntState(int hint)
|
|||
(getIntPriority(cpu, int_nm) < highest_pri))
|
||||
if ((!mp_sys) ||
|
||||
(gem5ExtensionsEnabled
|
||||
? (getCpuTarget(cpu, int_nm) == cpu)
|
||||
: (getCpuTarget(cpu, int_nm) & (1 << cpu)))) {
|
||||
? (cpuTarget[int_nm] == cpu)
|
||||
: (cpuTarget[int_nm] & (1 << cpu)))) {
|
||||
highest_pri = getIntPriority(cpu, int_nm);
|
||||
highest_int = int_nm;
|
||||
}
|
||||
|
@ -748,8 +733,7 @@ Pl390::updateIntState(int hint)
|
|||
|
||||
/* @todo make this work for more than one cpu, need to handle 1:N, N:N
|
||||
* models */
|
||||
if (enabled && cpuEnabled[cpu] &&
|
||||
(highest_pri < getCpuPriority(cpu)) &&
|
||||
if (enabled && cpuEnabled[cpu] && (highest_pri < cpuPriority[cpu]) &&
|
||||
!(getActiveInt(cpu, intNumToWord(highest_int))
|
||||
& (1 << intNumToBit(highest_int)))) {
|
||||
|
||||
|
@ -792,14 +776,13 @@ Pl390::updateRunPri()
|
|||
void
|
||||
Pl390::sendInt(uint32_t num)
|
||||
{
|
||||
uint8_t target = getCpuTarget(0, num);
|
||||
DPRINTF(Interrupt, "Received Interrupt number %d, cpuTarget %#x: \n",
|
||||
num, target);
|
||||
if ((target & (target - 1)) && !gem5ExtensionsEnabled)
|
||||
num, cpuTarget[num]);
|
||||
if ((cpuTarget[num] & (cpuTarget[num] - 1)) && !gem5ExtensionsEnabled)
|
||||
panic("Multiple targets for peripheral interrupts is not supported\n");
|
||||
panic_if(num < SGI_MAX + PPI_MAX,
|
||||
"sentInt() must only be used for interrupts 32 and higher");
|
||||
getPendingInt(target, intNumToWord(num)) |= 1 << intNumToBit(num);
|
||||
getPendingInt(cpuTarget[num], intNumToWord(num)) |= 1 << intNumToBit(num);
|
||||
updateIntState(intNumToWord(num));
|
||||
}
|
||||
|
||||
|
@ -897,6 +880,7 @@ Pl390::BankedRegs::serialize(CheckpointOut &cp) const
|
|||
SERIALIZE_SCALAR(pendingInt);
|
||||
SERIALIZE_SCALAR(activeInt);
|
||||
SERIALIZE_ARRAY(intPriority, SGI_MAX + PPI_MAX);
|
||||
SERIALIZE_ARRAY(cpuTarget, SGI_MAX + PPI_MAX);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -955,6 +939,7 @@ Pl390::BankedRegs::unserialize(CheckpointIn &cp)
|
|||
UNSERIALIZE_SCALAR(pendingInt);
|
||||
UNSERIALIZE_SCALAR(activeInt);
|
||||
UNSERIALIZE_ARRAY(intPriority, SGI_MAX + PPI_MAX);
|
||||
UNSERIALIZE_ARRAY(cpuTarget, SGI_MAX + PPI_MAX);
|
||||
}
|
||||
|
||||
Pl390 *
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
#include "dev/platform.hh"
|
||||
#include "params/Pl390.hh"
|
||||
|
||||
class Pl390 : public BaseGic, public BaseGicRegisters
|
||||
class Pl390 : public BaseGic
|
||||
{
|
||||
protected:
|
||||
// distributor memory addresses
|
||||
|
@ -111,10 +111,6 @@ class Pl390 : public BaseGic, public BaseGicRegisters
|
|||
static const int INT_LINES_MAX = 1020;
|
||||
static const int GLOBAL_INT_LINES = INT_LINES_MAX - SGI_MAX - PPI_MAX;
|
||||
|
||||
/** minimum value for Binary Point Register ("IMPLEMENTATION DEFINED");
|
||||
chosen for consistency with Linux's in-kernel KVM GIC model */
|
||||
static const int GICC_BPR_MINIMUM = 2;
|
||||
|
||||
BitUnion32(SWI)
|
||||
Bitfield<3,0> sgi_id;
|
||||
Bitfield<23,16> cpu_list;
|
||||
|
@ -176,11 +172,16 @@ class Pl390 : public BaseGic, public BaseGicRegisters
|
|||
* interrupt priority for SGIs and PPIs */
|
||||
uint8_t intPriority[SGI_MAX + PPI_MAX];
|
||||
|
||||
/** GICD_ITARGETSR{0..7}
|
||||
* 8b CPU target ID for each SGI and PPI */
|
||||
uint8_t cpuTarget[SGI_MAX + PPI_MAX];
|
||||
|
||||
void serialize(CheckpointOut &cp) const override;
|
||||
void unserialize(CheckpointIn &cp) override;
|
||||
|
||||
BankedRegs() :
|
||||
intEnabled(0), pendingInt(0), activeInt(0), intPriority {0}
|
||||
intEnabled(0), pendingInt(0), activeInt(0),
|
||||
intPriority {0}, cpuTarget {0}
|
||||
{}
|
||||
};
|
||||
std::vector<BankedRegs*> bankedRegs;
|
||||
|
@ -251,23 +252,12 @@ class Pl390 : public BaseGic, public BaseGicRegisters
|
|||
*/
|
||||
uint8_t cpuTarget[GLOBAL_INT_LINES];
|
||||
|
||||
uint8_t getCpuTarget(ContextID ctx, uint32_t ix) {
|
||||
assert(ctx < sys->numRunningContexts());
|
||||
uint8_t& getCpuTarget(ContextID ctx, uint32_t ix) {
|
||||
assert(ix < INT_LINES_MAX);
|
||||
if (ix < SGI_MAX + PPI_MAX) {
|
||||
// "GICD_ITARGETSR0 to GICD_ITARGETSR7 are read-only, and each
|
||||
// field returns a value that corresponds only to the processor
|
||||
// reading the register."
|
||||
uint32_t ctx_mask;
|
||||
if (gem5ExtensionsEnabled) {
|
||||
ctx_mask = ctx;
|
||||
} else {
|
||||
// convert the CPU id number into a bit mask
|
||||
ctx_mask = power(2, ctx);
|
||||
}
|
||||
return ctx_mask;
|
||||
return getBankedRegs(ctx).cpuTarget[ix];
|
||||
} else {
|
||||
return cpuTarget[ix - 32];
|
||||
return cpuTarget[ix - (SGI_MAX + PPI_MAX)];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -280,7 +270,6 @@ class Pl390 : public BaseGic, public BaseGicRegisters
|
|||
|
||||
/** CPU priority */
|
||||
uint8_t cpuPriority[CPU_MAX];
|
||||
uint8_t getCpuPriority(unsigned cpu); // BPR-adjusted priority value
|
||||
|
||||
/** Binary point registers */
|
||||
uint8_t cpuBpr[CPU_MAX];
|
||||
|
@ -404,34 +393,21 @@ class Pl390 : public BaseGic, public BaseGicRegisters
|
|||
* @param pkt packet to respond to
|
||||
*/
|
||||
Tick readDistributor(PacketPtr pkt);
|
||||
uint32_t readDistributor(ContextID ctx, Addr daddr,
|
||||
size_t resp_sz);
|
||||
uint32_t readDistributor(ContextID ctx, Addr daddr) override {
|
||||
return readDistributor(ctx, daddr, 4);
|
||||
}
|
||||
|
||||
/** Handle a read to the cpu portion of the GIC
|
||||
* @param pkt packet to respond to
|
||||
*/
|
||||
Tick readCpu(PacketPtr pkt);
|
||||
uint32_t readCpu(ContextID ctx, Addr daddr) override;
|
||||
|
||||
/** Handle a write to the distributor portion of the GIC
|
||||
* @param pkt packet to respond to
|
||||
*/
|
||||
Tick writeDistributor(PacketPtr pkt);
|
||||
void writeDistributor(ContextID ctx, Addr daddr,
|
||||
uint32_t data, size_t data_sz);
|
||||
void writeDistributor(ContextID ctx, Addr daddr,
|
||||
uint32_t data) override {
|
||||
return writeDistributor(ctx, daddr, data, 4);
|
||||
}
|
||||
|
||||
/** Handle a write to the cpu portion of the GIC
|
||||
* @param pkt packet to respond to
|
||||
*/
|
||||
Tick writeCpu(PacketPtr pkt);
|
||||
void writeCpu(ContextID ctx, Addr daddr, uint32_t data) override;
|
||||
};
|
||||
|
||||
#endif //__DEV_ARM_GIC_H__
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 2015, 2017 ARM Limited
|
||||
* Copyright (c) 2012, 2015 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
|
@ -101,33 +101,14 @@ DrainManager::resume()
|
|||
"Resuming a system that isn't fully drained, this is untested and "
|
||||
"likely to break\n");
|
||||
|
||||
panic_if(_state == DrainState::Resuming,
|
||||
"Resuming a system that is already trying to resume. This should "
|
||||
"never happen.\n");
|
||||
|
||||
panic_if(_count != 0,
|
||||
"Resume called in the middle of a drain cycle. %u objects "
|
||||
"left to drain.\n", _count);
|
||||
|
||||
// At this point in time the DrainManager and all objects will be
|
||||
// in the the Drained state. New objects (i.e., objects created
|
||||
// while resuming) will inherit the Resuming state from the
|
||||
// DrainManager, which means we have to resume objects until all
|
||||
// objects are in the Running state.
|
||||
_state = DrainState::Resuming;
|
||||
|
||||
do {
|
||||
DPRINTF(Drain, "Resuming %u objects.\n", drainableCount());
|
||||
for (auto *obj : _allDrainable) {
|
||||
if (obj->drainState() != DrainState::Running) {
|
||||
assert(obj->drainState() == DrainState::Drained ||
|
||||
obj->drainState() == DrainState::Resuming);
|
||||
obj->dmDrainResume();
|
||||
}
|
||||
}
|
||||
} while (!allInState(DrainState::Running));
|
||||
|
||||
DPRINTF(Drain, "Resuming %u objects.\n", drainableCount());
|
||||
_state = DrainState::Running;
|
||||
for (auto *obj : _allDrainable)
|
||||
obj->dmDrainResume();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -173,17 +154,6 @@ DrainManager::unregisterDrainable(Drainable *obj)
|
|||
_allDrainable.erase(o);
|
||||
}
|
||||
|
||||
bool
|
||||
DrainManager::allInState(DrainState state) const
|
||||
{
|
||||
for (const auto *obj : _allDrainable) {
|
||||
if (obj->drainState() != state)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t
|
||||
DrainManager::drainableCount() const
|
||||
{
|
||||
|
@ -219,8 +189,7 @@ Drainable::dmDrain()
|
|||
void
|
||||
Drainable::dmDrainResume()
|
||||
{
|
||||
panic_if(_drainState != DrainState::Drained &&
|
||||
_drainState != DrainState::Resuming,
|
||||
panic_if(_drainState != DrainState::Drained,
|
||||
"Trying to resume an object that hasn't been drained\n");
|
||||
|
||||
_drainState = DrainState::Running;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 2015, 2017 ARM Limited
|
||||
* Copyright (c) 2012, 2015 ARM Limited
|
||||
* All rights reserved
|
||||
*
|
||||
* The license below extends only to copyright in the software and shall
|
||||
|
@ -58,11 +58,7 @@ class Drainable;
|
|||
* all objects have entered the Drained state.
|
||||
*
|
||||
* Before resuming simulation, the simulator calls resume() to
|
||||
* transfer the object to the Running state. This in turn results in a
|
||||
* call to drainResume() for all Drainable objects in the
|
||||
* simulator. New Drainable objects may be created while resuming. In
|
||||
* such cases, the new objects will be created in the Resuming state
|
||||
* and later resumed.
|
||||
* transfer the object to the Running state.
|
||||
*
|
||||
* \note Even though the state of an object (visible to the rest of
|
||||
* the world through Drainable::getState()) could be used to determine
|
||||
|
@ -72,8 +68,7 @@ class Drainable;
|
|||
enum class DrainState {
|
||||
Running, /** Running normally */
|
||||
Draining, /** Draining buffers pending serialization/handover */
|
||||
Drained, /** Buffers drained, ready for serialization/handover */
|
||||
Resuming, /** Transient state while the simulator is resuming */
|
||||
Drained /** Buffers drained, ready for serialization/handover */
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -157,12 +152,6 @@ class DrainManager
|
|||
void unregisterDrainable(Drainable *obj);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Helper function to check if all Drainable objects are in a
|
||||
* specific state.
|
||||
*/
|
||||
bool allInState(DrainState state) const;
|
||||
|
||||
/**
|
||||
* Thread-safe helper function to get the number of Drainable
|
||||
* objects in a system.
|
||||
|
@ -272,7 +261,6 @@ class Drainable
|
|||
switch (_drainState) {
|
||||
case DrainState::Running:
|
||||
case DrainState::Drained:
|
||||
case DrainState::Resuming:
|
||||
return;
|
||||
case DrainState::Draining:
|
||||
_drainState = DrainState::Drained;
|
||||
|
|
|
@ -52,6 +52,7 @@ def upgrader(cpt):
|
|||
b_intEnabled = intEnabled[0]
|
||||
b_pendingInt = pendingInt[0]
|
||||
b_activeInt = activeInt[0]
|
||||
b_cpuTarget = cpuTarget[0:32]
|
||||
|
||||
del intEnabled[0]
|
||||
del pendingInt[0]
|
||||
|
@ -77,3 +78,4 @@ def upgrader(cpt):
|
|||
cpt.set(new_sec, 'pendingInt', b_pendingInt)
|
||||
cpt.set(new_sec, 'activeInt', b_activeInt)
|
||||
cpt.set(new_sec, 'intPriority',' '.join(intPriority))
|
||||
cpt.set(new_sec, 'cpuTarget', ' '.join(b_cpuTarget))
|
||||
|
|
Loading…
Reference in a new issue