dev-arm: Implement a SMMUv3 model
This is an implementation of the SMMUv3 architecture. What can it do? - Single-stage and nested translation with 4k or 64k granule. 16k would be straightforward to add. - Large pages are supported. - Works with any gem5 device as long as it is issuing packets with a valid (Sub)StreamId What it can't do? - Fragment stage 1 page when the underlying stage 2 page is smaller. S1 page size > S2 page size is not supported - Invalidations take zero time. This wouldn't be hard to fix. - Checkpointing is not supported - Stall/resume for faulting transactions is not supported Additional contributors: - Michiel W. van Tol <Michiel.VanTol@arm.com> - Giacomo Travaglini <giacomo.travaglini@arm.com> Change-Id: Ibc606fccd9199b2c1ba739c6335c846ffaa4d564 Signed-off-by: Giacomo Travaglini <giacomo.travaglini@arm.com> Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com> Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/19008 Maintainer: Andreas Sandberg <andreas.sandberg@arm.com> Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
committed by
Giacomo Travaglini
parent
f2be9f195c
commit
2574dc41a6
@@ -44,6 +44,7 @@ if env['TARGET_ISA'] == 'arm':
|
||||
SimObject('FlashDevice.py')
|
||||
SimObject('Gic.py')
|
||||
SimObject('RealView.py')
|
||||
SimObject('SMMUv3.py')
|
||||
SimObject('UFSHostDevice.py')
|
||||
SimObject('EnergyCtrl.py')
|
||||
SimObject('NoMali.py')
|
||||
@@ -66,6 +67,15 @@ if env['TARGET_ISA'] == 'arm':
|
||||
Source('pl111.cc')
|
||||
Source('hdlcd.cc')
|
||||
Source('kmi.cc')
|
||||
Source('smmu_v3.cc');
|
||||
Source('smmu_v3_caches.cc');
|
||||
Source('smmu_v3_cmdexec.cc');
|
||||
Source('smmu_v3_events.cc');
|
||||
Source('smmu_v3_ports.cc');
|
||||
Source('smmu_v3_proc.cc');
|
||||
Source('smmu_v3_ptops.cc');
|
||||
Source('smmu_v3_slaveifc.cc');
|
||||
Source('smmu_v3_transl.cc');
|
||||
Source('timer_sp804.cc')
|
||||
Source('gpu_nomali.cc')
|
||||
Source('pci_host.cc')
|
||||
@@ -88,6 +98,8 @@ if env['TARGET_ISA'] == 'arm':
|
||||
DebugFlag('GIC')
|
||||
DebugFlag('ITS')
|
||||
DebugFlag('RVCTRL')
|
||||
DebugFlag('SMMUv3')
|
||||
DebugFlag('SMMUv3Hazard')
|
||||
DebugFlag('EnergyCtrl')
|
||||
DebugFlag('UFSHostDevice')
|
||||
DebugFlag('VGIC')
|
||||
|
||||
209
src/dev/arm/SMMUv3.py
Normal file
209
src/dev/arm/SMMUv3.py
Normal file
@@ -0,0 +1,209 @@
|
||||
# Copyright (c) 2013, 2018-2019 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.
|
||||
#
|
||||
# Authors: Stan Czerniawski
|
||||
# Giacomo Travaglini
|
||||
|
||||
from m5.params import *
|
||||
from m5.proxy import *
|
||||
from m5.util.fdthelper import *
|
||||
from m5.SimObject import *
|
||||
from MemObject import MemObject
|
||||
|
||||
class SMMUv3SlaveInterface(MemObject):
|
||||
type = 'SMMUv3SlaveInterface'
|
||||
cxx_header = 'dev/arm/smmu_v3_slaveifc.hh'
|
||||
|
||||
slave = SlavePort('Device port')
|
||||
ats_master = MasterPort('ATS master port')
|
||||
ats_slave = SlavePort('ATS slave port')
|
||||
|
||||
port_width = Param.Unsigned(16, 'Port width in bytes (= 1 beat)')
|
||||
wrbuf_slots = Param.Unsigned(16, 'Write buffer size (in beats)')
|
||||
xlate_slots = Param.Unsigned(16, 'Translation slots')
|
||||
|
||||
utlb_entries = Param.Unsigned(32, 'Micro TLB size (entries)')
|
||||
utlb_assoc = Param.Unsigned(0, 'Micro TLB associativity (0=full)')
|
||||
utlb_policy = Param.String('rr', 'Micro TLB replacement policy')
|
||||
utlb_enable = Param.Bool(True, 'Micro TLB enable')
|
||||
utlb_lat = Param.Cycles(1, 'Micro TLB lookup latency')
|
||||
utlb_slots = Param.Cycles(1, 'Micro TLB lookup slots')
|
||||
|
||||
tlb_entries = Param.Unsigned(2048, 'Main TLB size (entries)')
|
||||
tlb_assoc = Param.Unsigned(4, 'Main TLB associativity (0=full)')
|
||||
tlb_policy = Param.String('rr', 'Main TLB replacement policy')
|
||||
tlb_enable = Param.Bool(True, 'Main TLB enable')
|
||||
tlb_lat = Param.Cycles(3, 'Main TLB lookup latency')
|
||||
tlb_slots = Param.Cycles(3, 'Main TLB lookup slots')
|
||||
|
||||
prefetch_enable = Param.Bool(False,
|
||||
'Enable prefetch')
|
||||
prefetch_reserve_last_way = Param.Bool(True,
|
||||
'Reserve last way of the main TLB for prefetched entries')
|
||||
|
||||
class SMMUv3(MemObject):
|
||||
type = 'SMMUv3'
|
||||
cxx_header = 'dev/arm/smmu_v3.hh'
|
||||
|
||||
master = MasterPort('Master port')
|
||||
master_walker = MasterPort(
|
||||
'Master port for SMMU initiated HWTW requests (optional)')
|
||||
control = SlavePort('Control port for accessing memory-mapped registers')
|
||||
sample_period = Param.Clock('10us', 'Stats sample period')
|
||||
reg_map = Param.AddrRange('Address range for control registers')
|
||||
system = Param.System(Parent.any, "System this device is part of")
|
||||
|
||||
slave_interfaces = VectorParam.SMMUv3SlaveInterface([], "Slave interfaces")
|
||||
|
||||
# SLAVE INTERFACE<->SMMU link parameters
|
||||
ifc_smmu_lat = Param.Cycles(8, 'IFC to SMMU communication latency')
|
||||
smmu_ifc_lat = Param.Cycles(8, 'SMMU to IFC communication latency')
|
||||
|
||||
# SMMU parameters
|
||||
xlate_slots = Param.Unsigned(64, 'SMMU translation slots')
|
||||
ptw_slots = Param.Unsigned(16, 'SMMU page table walk slots')
|
||||
|
||||
master_port_width = Param.Unsigned(16,
|
||||
'Master port width in bytes (= 1 beat)')
|
||||
|
||||
tlb_entries = Param.Unsigned(2048, 'TLB size (entries)')
|
||||
tlb_assoc = Param.Unsigned(4, 'TLB associativity (0=full)')
|
||||
tlb_policy = Param.String('rr', 'TLB replacement policy')
|
||||
tlb_enable = Param.Bool(False, 'TLB enable')
|
||||
tlb_lat = Param.Cycles(3, 'TLB lookup latency')
|
||||
tlb_slots = Param.Cycles(3, 'TLB lookup slots')
|
||||
|
||||
cfg_entries = Param.Unsigned(64, 'Config cache size (entries)')
|
||||
cfg_assoc = Param.Unsigned(4, 'Config cache associativity (0=full)')
|
||||
cfg_policy = Param.String('rr', 'Config cache replacement policy')
|
||||
cfg_enable = Param.Bool(True, 'Config cache enable')
|
||||
cfg_lat = Param.Cycles(3, 'Config cache lookup latency')
|
||||
cfg_slots = Param.Cycles(3, 'Config cache lookup slots')
|
||||
|
||||
ipa_entries = Param.Unsigned(128, 'IPA cache size (entries)')
|
||||
ipa_assoc = Param.Unsigned(4, 'IPA cache associativity (0=full)')
|
||||
ipa_policy = Param.String('rr', 'IPA cache replacement policy')
|
||||
ipa_enable = Param.Bool(False, 'IPA cache enable')
|
||||
ipa_lat = Param.Cycles(3, 'IPA cache lookup lantency')
|
||||
ipa_slots = Param.Cycles(3, 'IPA cache lookup slots')
|
||||
|
||||
walk_S1L0 = Param.Unsigned(4, 'Walk cache S1L0 size (entries)')
|
||||
walk_S1L1 = Param.Unsigned(28, 'Walk cache S1L1 size (entries)')
|
||||
walk_S1L2 = Param.Unsigned(348, 'Walk cache S1L2 size (entries)')
|
||||
walk_S1L3 = Param.Unsigned(4, 'Walk cache S1L3 size (entries)')
|
||||
walk_S2L0 = Param.Unsigned(4, 'Walk cache S2L0 size (entries)')
|
||||
walk_S2L1 = Param.Unsigned(28, 'Walk cache S2L1 size (entries)')
|
||||
walk_S2L2 = Param.Unsigned(92, 'Walk cache S2L2 size (entries)')
|
||||
walk_S2L3 = Param.Unsigned(4, 'Walk cache S2L3 size (entries)')
|
||||
walk_assoc = Param.Unsigned(4, 'Walk cache associativity (0=full)')
|
||||
walk_policy = Param.String('rr', 'Walk cache replacement policy')
|
||||
walk_enable = Param.Bool(True, 'Walk cache enable')
|
||||
wc_nonfinal_enable = Param.Bool(False,
|
||||
'Nonfinal translations use walk cache')
|
||||
wc_s1_levels = Param.Unsigned(7,
|
||||
'S1 PT levels cached in walk cache (bit 0 is L0, bit 1 is L1, etc)')
|
||||
wc_s2_levels = Param.Unsigned(7,
|
||||
'S2 PT levels cached in walk cache (bit 0 is L0, bit 1 is L1, etc)')
|
||||
|
||||
walk_lat = Param.Cycles(4, 'Walk cache lookup latency')
|
||||
walk_slots = Param.Cycles(4, 'Walk cache lookup slots')
|
||||
|
||||
# [28:27] ST_LEVEL = 0b01, 2-level Stream Table supported in addition
|
||||
# to Linear Stream table.
|
||||
# [25:24] STALL_MODEL = 0b01, Stall is not supported, all faults
|
||||
# terminate transaction.
|
||||
# [22:21] TTENDIAN = 0b10, Endianness support for translation table walks
|
||||
# (0b10 = Little-endian).
|
||||
# [19] CD2L = 0b1, 2-level CD table supported.
|
||||
# [18] VMID16 = 0b1, 16-bit VMID supported.
|
||||
# [12] ASID16 = 0b1, 16-bit ASID supported.
|
||||
# [3:2] TTF = 0b10, Translation Table Formats (Stage 1/2)
|
||||
# (0b10 = AArch64).
|
||||
# [1] S1P = 0b1, Stage 1 translation supported.
|
||||
# [0] S2P = 0b1, Stage 2 translation supported.
|
||||
smmu_idr0 = Param.UInt32(0x094C100F, "SMMU_IDR0 register");
|
||||
|
||||
# [25:21] CMDQS = 0b00101, Maximum number of Command queue entries
|
||||
# as log 2 (entries) (0b00101 = 32 entries).
|
||||
smmu_idr1 = Param.UInt32(0x00A00000, "SMMU_IDR1 register");
|
||||
|
||||
smmu_idr2 = Param.UInt32(0, "SMMU_IDR2 register");
|
||||
smmu_idr3 = Param.UInt32(0, "SMMU_IDR3 register");
|
||||
smmu_idr4 = Param.UInt32(0, "SMMU_IDR4 register");
|
||||
|
||||
# [6] GRAN64K = 0b1, 64KB translation granule supported.
|
||||
# [4] GRAN4K = 0b1, 4KB translation granule supported.
|
||||
# [2:0] OAS = 0b101, Output Address Size (0b101 = 48-bit).
|
||||
smmu_idr5 = Param.UInt32(0x55, "SMMU_IDR5 register");
|
||||
smmu_iidr = Param.UInt32(0, "SMMU_IIDR register");
|
||||
|
||||
# [7:0] (0 = SMMUv3.0) (1 = SMMUv3.1)
|
||||
smmu_aidr = Param.UInt32(0, "SMMU_AIDR register");
|
||||
|
||||
def generateDeviceTree(self, state):
|
||||
reg_addr = self.reg_map.start
|
||||
reg_size = self.reg_map.size()
|
||||
node = FdtNode("smmuv3@%x" % long(reg_addr))
|
||||
node.appendCompatible("arm,smmu-v3")
|
||||
node.append(FdtPropertyWords("reg",
|
||||
state.addrCells(reg_addr) +
|
||||
state.sizeCells(reg_size)))
|
||||
node.append(FdtPropertyWords("#iommu-cells", [1]))
|
||||
|
||||
node.appendPhandle(self)
|
||||
yield node
|
||||
|
||||
def connect(self, device, bus):
|
||||
"""
|
||||
Helper method used to connect the SMMU. The master could
|
||||
be either a dma port (if the SMMU is attached directly to a
|
||||
dma device), or to a master port (this is the case where the SMMU
|
||||
is attached to a bridge).
|
||||
"""
|
||||
|
||||
self.master = bus.slave
|
||||
self.control = bus.master
|
||||
|
||||
slave_interface = SMMUv3SlaveInterface()
|
||||
|
||||
if hasattr(device, "master"):
|
||||
slave_interface.slave = device.master
|
||||
elif hasattr(device, "dma"):
|
||||
slave_interface.slave = device.dma
|
||||
else:
|
||||
print("Unable to attach SMMUv3\n")
|
||||
sys.exit(1)
|
||||
|
||||
self.slave_interfaces.append(slave_interface)
|
||||
58
src/dev/arm/amba.hh
Normal file
58
src/dev/arm/amba.hh
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
* Authors: Giacomo Travaglini
|
||||
*/
|
||||
|
||||
#ifndef __DEV_ARM_AMBA_HH__
|
||||
#define __DEV_ARM_AMBA_HH__
|
||||
|
||||
#include "mem/packet.hh"
|
||||
|
||||
namespace AMBA
|
||||
{
|
||||
|
||||
typedef MasterID OrderID;
|
||||
|
||||
static OrderID
|
||||
orderId(PacketPtr pkt)
|
||||
{
|
||||
return pkt->req->masterId();
|
||||
}
|
||||
|
||||
} // namespace AMBA
|
||||
|
||||
#endif // __DEV_ARM_AMBA_HH__
|
||||
781
src/dev/arm/smmu_v3.cc
Normal file
781
src/dev/arm/smmu_v3.cc
Normal file
@@ -0,0 +1,781 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018-2019 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.
|
||||
*
|
||||
* Authors: Stan Czerniawski
|
||||
*/
|
||||
|
||||
#include "dev/arm/smmu_v3.hh"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
|
||||
#include "base/bitfield.hh"
|
||||
#include "base/cast.hh"
|
||||
#include "base/logging.hh"
|
||||
#include "base/trace.hh"
|
||||
#include "base/types.hh"
|
||||
#include "debug/Checkpoint.hh"
|
||||
#include "debug/SMMUv3.hh"
|
||||
#include "dev/arm/smmu_v3_transl.hh"
|
||||
#include "mem/packet_access.hh"
|
||||
#include "sim/system.hh"
|
||||
|
||||
SMMUv3::SMMUv3(SMMUv3Params *params) :
|
||||
MemObject(params),
|
||||
system(*params->system),
|
||||
masterId(params->system->getMasterId(this)),
|
||||
masterPort(name() + ".master", *this),
|
||||
masterTableWalkPort(name() + ".master_walker", *this),
|
||||
controlPort(name() + ".control", *this, params->reg_map),
|
||||
tlb(params->tlb_entries, params->tlb_assoc, params->tlb_policy),
|
||||
configCache(params->cfg_entries, params->cfg_assoc, params->cfg_policy),
|
||||
ipaCache(params->ipa_entries, params->ipa_assoc, params->ipa_policy),
|
||||
walkCache({ { params->walk_S1L0, params->walk_S1L1,
|
||||
params->walk_S1L2, params->walk_S1L3,
|
||||
params->walk_S2L0, params->walk_S2L1,
|
||||
params->walk_S2L2, params->walk_S2L3 } },
|
||||
params->walk_assoc, params->walk_policy),
|
||||
tlbEnable(params->tlb_enable),
|
||||
configCacheEnable(params->cfg_enable),
|
||||
ipaCacheEnable(params->ipa_enable),
|
||||
walkCacheEnable(params->walk_enable),
|
||||
tableWalkPortEnable(false),
|
||||
walkCacheNonfinalEnable(params->wc_nonfinal_enable),
|
||||
walkCacheS1Levels(params->wc_s1_levels),
|
||||
walkCacheS2Levels(params->wc_s2_levels),
|
||||
masterPortWidth(params->master_port_width),
|
||||
tlbSem(params->tlb_slots),
|
||||
ifcSmmuSem(1),
|
||||
smmuIfcSem(1),
|
||||
configSem(params->cfg_slots),
|
||||
ipaSem(params->ipa_slots),
|
||||
walkSem(params->walk_slots),
|
||||
masterPortSem(1),
|
||||
transSem(params->xlate_slots),
|
||||
ptwSem(params->ptw_slots),
|
||||
cycleSem(1),
|
||||
tlbLat(params->tlb_lat),
|
||||
ifcSmmuLat(params->ifc_smmu_lat),
|
||||
smmuIfcLat(params->smmu_ifc_lat),
|
||||
configLat(params->cfg_lat),
|
||||
ipaLat(params->ipa_lat),
|
||||
walkLat(params->walk_lat),
|
||||
slaveInterfaces(params->slave_interfaces),
|
||||
commandExecutor(name() + ".cmd_exec", *this),
|
||||
regsMap(params->reg_map),
|
||||
processCommandsEvent(this)
|
||||
{
|
||||
fatal_if(regsMap.size() != SMMU_REG_SIZE,
|
||||
"Invalid register map size: %#x different than SMMU_REG_SIZE = %#x\n",
|
||||
regsMap.size(), SMMU_REG_SIZE);
|
||||
|
||||
// Init smmu registers to 0
|
||||
memset(®s, 0, sizeof(regs));
|
||||
|
||||
// Setup RO ID registers
|
||||
regs.idr0 = params->smmu_idr0;
|
||||
regs.idr1 = params->smmu_idr1;
|
||||
regs.idr2 = params->smmu_idr2;
|
||||
regs.idr3 = params->smmu_idr3;
|
||||
regs.idr4 = params->smmu_idr4;
|
||||
regs.idr5 = params->smmu_idr5;
|
||||
regs.iidr = params->smmu_iidr;
|
||||
regs.aidr = params->smmu_aidr;
|
||||
|
||||
// TODO: At the moment it possible to set the ID registers to hold
|
||||
// any possible value. It would be nice to have a sanity check here
|
||||
// at construction time in case some idx registers are programmed to
|
||||
// store an unallowed values or if the are configuration conflicts.
|
||||
warn("SMMUv3 IDx register values unchecked\n");
|
||||
|
||||
for (auto ifc : slaveInterfaces)
|
||||
ifc->setSMMU(this);
|
||||
}
|
||||
|
||||
bool
|
||||
SMMUv3::masterRecvTimingResp(PacketPtr pkt)
|
||||
{
|
||||
DPRINTF(SMMUv3, "[t] master resp addr=%#x size=%#x\n",
|
||||
pkt->getAddr(), pkt->getSize());
|
||||
|
||||
// @todo: We need to pay for this and not just zero it out
|
||||
pkt->headerDelay = pkt->payloadDelay = 0;
|
||||
|
||||
SMMUProcess *proc =
|
||||
safe_cast<SMMUProcess *>(pkt->popSenderState());
|
||||
|
||||
runProcessTiming(proc, pkt);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
SMMUv3::masterRecvReqRetry()
|
||||
{
|
||||
assert(!packetsToRetry.empty());
|
||||
|
||||
while (!packetsToRetry.empty()) {
|
||||
SMMUAction a = packetsToRetry.front();
|
||||
|
||||
assert(a.type==ACTION_SEND_REQ || a.type==ACTION_SEND_REQ_FINAL);
|
||||
|
||||
DPRINTF(SMMUv3, "[t] master retr addr=%#x size=%#x\n",
|
||||
a.pkt->getAddr(), a.pkt->getSize());
|
||||
|
||||
if (!masterPort.sendTimingReq(a.pkt))
|
||||
break;
|
||||
|
||||
packetsToRetry.pop();
|
||||
|
||||
/*
|
||||
* ACTION_SEND_REQ_FINAL means that we have just forwarded the packet
|
||||
* on the master interface; this means that we no longer hold on to
|
||||
* that transaction and therefore can accept a new one.
|
||||
* If the slave port was stalled then unstall it (send retry).
|
||||
*/
|
||||
if (a.type == ACTION_SEND_REQ_FINAL)
|
||||
scheduleSlaveRetries();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
SMMUv3::masterTableWalkRecvTimingResp(PacketPtr pkt)
|
||||
{
|
||||
DPRINTF(SMMUv3, "[t] master HWTW resp addr=%#x size=%#x\n",
|
||||
pkt->getAddr(), pkt->getSize());
|
||||
|
||||
// @todo: We need to pay for this and not just zero it out
|
||||
pkt->headerDelay = pkt->payloadDelay = 0;
|
||||
|
||||
SMMUProcess *proc =
|
||||
safe_cast<SMMUProcess *>(pkt->popSenderState());
|
||||
|
||||
runProcessTiming(proc, pkt);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
SMMUv3::masterTableWalkRecvReqRetry()
|
||||
{
|
||||
assert(tableWalkPortEnable);
|
||||
assert(!packetsTableWalkToRetry.empty());
|
||||
|
||||
while (!packetsTableWalkToRetry.empty()) {
|
||||
SMMUAction a = packetsTableWalkToRetry.front();
|
||||
|
||||
assert(a.type==ACTION_SEND_REQ);
|
||||
|
||||
DPRINTF(SMMUv3, "[t] master HWTW retr addr=%#x size=%#x\n",
|
||||
a.pkt->getAddr(), a.pkt->getSize());
|
||||
|
||||
if (!masterTableWalkPort.sendTimingReq(a.pkt))
|
||||
break;
|
||||
|
||||
packetsTableWalkToRetry.pop();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SMMUv3::scheduleSlaveRetries()
|
||||
{
|
||||
for (auto ifc : slaveInterfaces) {
|
||||
ifc->scheduleDeviceRetry();
|
||||
}
|
||||
}
|
||||
|
||||
SMMUAction
|
||||
SMMUv3::runProcess(SMMUProcess *proc, PacketPtr pkt)
|
||||
{
|
||||
if (system.isAtomicMode()) {
|
||||
return runProcessAtomic(proc, pkt);
|
||||
} else if (system.isTimingMode()) {
|
||||
return runProcessTiming(proc, pkt);
|
||||
} else {
|
||||
panic("Not in timing or atomic mode!");
|
||||
}
|
||||
}
|
||||
|
||||
SMMUAction
|
||||
SMMUv3::runProcessAtomic(SMMUProcess *proc, PacketPtr pkt)
|
||||
{
|
||||
SMMUAction action;
|
||||
Tick delay = 0;
|
||||
bool finished = false;
|
||||
|
||||
do {
|
||||
action = proc->run(pkt);
|
||||
|
||||
switch (action.type) {
|
||||
case ACTION_SEND_REQ:
|
||||
// Send an MMU initiated request on the table walk port if it is
|
||||
// enabled. Otherwise, fall through and handle same as the final
|
||||
// ACTION_SEND_REQ_FINAL request.
|
||||
if (tableWalkPortEnable) {
|
||||
delay += masterTableWalkPort.sendAtomic(action.pkt);
|
||||
pkt = action.pkt;
|
||||
break;
|
||||
}
|
||||
M5_FALLTHROUGH;
|
||||
case ACTION_SEND_REQ_FINAL:
|
||||
delay += masterPort.sendAtomic(action.pkt);
|
||||
pkt = action.pkt;
|
||||
break;
|
||||
|
||||
case ACTION_SEND_RESP:
|
||||
case ACTION_SEND_RESP_ATS:
|
||||
case ACTION_SLEEP:
|
||||
finished = true;
|
||||
break;
|
||||
|
||||
case ACTION_DELAY:
|
||||
delay += action.delay;
|
||||
break;
|
||||
|
||||
case ACTION_TERMINATE:
|
||||
panic("ACTION_TERMINATE in atomic mode\n");
|
||||
|
||||
default:
|
||||
panic("Unknown action\n");
|
||||
}
|
||||
} while (!finished);
|
||||
|
||||
action.delay = delay;
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
SMMUAction
|
||||
SMMUv3::runProcessTiming(SMMUProcess *proc, PacketPtr pkt)
|
||||
{
|
||||
SMMUAction action = proc->run(pkt);
|
||||
|
||||
switch (action.type) {
|
||||
case ACTION_SEND_REQ:
|
||||
// Send an MMU initiated request on the table walk port if it is
|
||||
// enabled. Otherwise, fall through and handle same as the final
|
||||
// ACTION_SEND_REQ_FINAL request.
|
||||
if (tableWalkPortEnable) {
|
||||
action.pkt->pushSenderState(proc);
|
||||
|
||||
DPRINTF(SMMUv3, "[t] master HWTW req addr=%#x size=%#x\n",
|
||||
action.pkt->getAddr(), action.pkt->getSize());
|
||||
|
||||
if (packetsTableWalkToRetry.empty()
|
||||
&& masterTableWalkPort.sendTimingReq(action.pkt)) {
|
||||
scheduleSlaveRetries();
|
||||
} else {
|
||||
DPRINTF(SMMUv3, "[t] master HWTW req needs retry,"
|
||||
" qlen=%d\n", packetsTableWalkToRetry.size());
|
||||
packetsTableWalkToRetry.push(action);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
M5_FALLTHROUGH;
|
||||
case ACTION_SEND_REQ_FINAL:
|
||||
action.pkt->pushSenderState(proc);
|
||||
|
||||
DPRINTF(SMMUv3, "[t] master req addr=%#x size=%#x\n",
|
||||
action.pkt->getAddr(), action.pkt->getSize());
|
||||
|
||||
if (packetsToRetry.empty() && masterPort.sendTimingReq(action.pkt)) {
|
||||
scheduleSlaveRetries();
|
||||
} else {
|
||||
DPRINTF(SMMUv3, "[t] master req needs retry, qlen=%d\n",
|
||||
packetsToRetry.size());
|
||||
packetsToRetry.push(action);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ACTION_SEND_RESP:
|
||||
// @todo: We need to pay for this and not just zero it out
|
||||
action.pkt->headerDelay = action.pkt->payloadDelay = 0;
|
||||
|
||||
DPRINTF(SMMUv3, "[t] slave resp addr=%#x size=%#x\n",
|
||||
action.pkt->getAddr(),
|
||||
action.pkt->getSize());
|
||||
|
||||
assert(action.ifc);
|
||||
action.ifc->schedTimingResp(action.pkt);
|
||||
|
||||
delete proc;
|
||||
break;
|
||||
|
||||
case ACTION_SEND_RESP_ATS:
|
||||
// @todo: We need to pay for this and not just zero it out
|
||||
action.pkt->headerDelay = action.pkt->payloadDelay = 0;
|
||||
|
||||
DPRINTF(SMMUv3, "[t] ATS slave resp addr=%#x size=%#x\n",
|
||||
action.pkt->getAddr(), action.pkt->getSize());
|
||||
|
||||
assert(action.ifc);
|
||||
action.ifc->schedAtsTimingResp(action.pkt);
|
||||
|
||||
delete proc;
|
||||
break;
|
||||
|
||||
case ACTION_DELAY:
|
||||
case ACTION_SLEEP:
|
||||
break;
|
||||
|
||||
case ACTION_TERMINATE:
|
||||
delete proc;
|
||||
break;
|
||||
|
||||
default:
|
||||
panic("Unknown action\n");
|
||||
}
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
void
|
||||
SMMUv3::processCommands()
|
||||
{
|
||||
DPRINTF(SMMUv3, "processCommands()\n");
|
||||
|
||||
if (system.isAtomicMode()) {
|
||||
SMMUAction a = runProcessAtomic(&commandExecutor, NULL);
|
||||
(void) a;
|
||||
} else if (system.isTimingMode()) {
|
||||
if (!commandExecutor.isBusy())
|
||||
runProcessTiming(&commandExecutor, NULL);
|
||||
} else {
|
||||
panic("Not in timing or atomic mode!");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SMMUv3::processCommand(const SMMUCommand &cmd)
|
||||
{
|
||||
switch (cmd.type) {
|
||||
case CMD_PRF_CONFIG:
|
||||
DPRINTF(SMMUv3, "CMD_PREFETCH_CONFIG - ignored\n");
|
||||
break;
|
||||
|
||||
case CMD_PRF_ADDR:
|
||||
DPRINTF(SMMUv3, "CMD_PREFETCH_ADDR - ignored\n");
|
||||
break;
|
||||
|
||||
case CMD_INV_STE:
|
||||
DPRINTF(SMMUv3, "CMD_INV_STE sid=%#x\n", cmd.data[0]);
|
||||
configCache.invalidateSID(cmd.data[0]);
|
||||
break;
|
||||
|
||||
case CMD_INV_CD:
|
||||
DPRINTF(SMMUv3, "CMD_INV_CD sid=%#x ssid=%#x\n",
|
||||
cmd.data[0], cmd.data[1]);
|
||||
configCache.invalidateSSID(cmd.data[0], cmd.data[1]);
|
||||
break;
|
||||
|
||||
case CMD_INV_CD_ALL:
|
||||
DPRINTF(SMMUv3, "CMD_INV_CD_ALL sid=%#x\n", cmd.data[0]);
|
||||
configCache.invalidateSID(cmd.data[0]);
|
||||
break;
|
||||
|
||||
case CMD_INV_ALL:
|
||||
DPRINTF(SMMUv3, "CMD_INV_ALL\n");
|
||||
configCache.invalidateAll();
|
||||
break;
|
||||
|
||||
case CMD_TLBI_ALL:
|
||||
DPRINTF(SMMUv3, "CMD_TLBI_ALL\n");
|
||||
for (auto slave_interface : slaveInterfaces) {
|
||||
slave_interface->microTLB->invalidateAll();
|
||||
slave_interface->mainTLB->invalidateAll();
|
||||
}
|
||||
tlb.invalidateAll();
|
||||
ipaCache.invalidateAll();
|
||||
walkCache.invalidateAll();
|
||||
break;
|
||||
|
||||
case CMD_TLBI_ASID:
|
||||
DPRINTF(SMMUv3, "CMD_TLBI_ASID asid=%#x vmid=%#x\n",
|
||||
cmd.data[0], cmd.data[1]);
|
||||
for (auto slave_interface : slaveInterfaces) {
|
||||
slave_interface->microTLB->invalidateASID(
|
||||
cmd.data[0], cmd.data[1]);
|
||||
slave_interface->mainTLB->invalidateASID(
|
||||
cmd.data[0], cmd.data[1]);
|
||||
}
|
||||
tlb.invalidateASID(cmd.data[0], cmd.data[1]);
|
||||
walkCache.invalidateASID(cmd.data[0], cmd.data[1]);
|
||||
break;
|
||||
|
||||
case CMD_TLBI_VAAL:
|
||||
DPRINTF(SMMUv3, "CMD_TLBI_VAAL va=%#08x vmid=%#x\n",
|
||||
cmd.data[0], cmd.data[1]);
|
||||
for (auto slave_interface : slaveInterfaces) {
|
||||
slave_interface->microTLB->invalidateVAA(
|
||||
cmd.data[0], cmd.data[1]);
|
||||
slave_interface->mainTLB->invalidateVAA(
|
||||
cmd.data[0], cmd.data[1]);
|
||||
}
|
||||
tlb.invalidateVAA(cmd.data[0], cmd.data[1]);
|
||||
break;
|
||||
|
||||
case CMD_TLBI_VAA:
|
||||
DPRINTF(SMMUv3, "CMD_TLBI_VAA va=%#08x vmid=%#x\n",
|
||||
cmd.data[0], cmd.data[1]);
|
||||
for (auto slave_interface : slaveInterfaces) {
|
||||
slave_interface->microTLB->invalidateVAA(
|
||||
cmd.data[0], cmd.data[1]);
|
||||
slave_interface->mainTLB->invalidateVAA(
|
||||
cmd.data[0], cmd.data[1]);
|
||||
}
|
||||
tlb.invalidateVAA(cmd.data[0], cmd.data[1]);
|
||||
walkCache.invalidateVAA(cmd.data[0], cmd.data[1]);
|
||||
break;
|
||||
|
||||
case CMD_TLBI_VAL:
|
||||
DPRINTF(SMMUv3, "CMD_TLBI_VAL va=%#08x asid=%#x vmid=%#x\n",
|
||||
cmd.data[0], cmd.data[1], cmd.data[2]);
|
||||
for (auto slave_interface : slaveInterfaces) {
|
||||
slave_interface->microTLB->invalidateVA(
|
||||
cmd.data[0], cmd.data[1], cmd.data[2]);
|
||||
slave_interface->mainTLB->invalidateVA(
|
||||
cmd.data[0], cmd.data[1], cmd.data[2]);
|
||||
}
|
||||
tlb.invalidateVA(cmd.data[0], cmd.data[1], cmd.data[2]);
|
||||
break;
|
||||
|
||||
case CMD_TLBI_VA:
|
||||
DPRINTF(SMMUv3, "CMD_TLBI_VA va=%#08x asid=%#x vmid=%#x\n",
|
||||
cmd.data[0], cmd.data[1], cmd.data[2]);
|
||||
for (auto slave_interface : slaveInterfaces) {
|
||||
slave_interface->microTLB->invalidateVA(
|
||||
cmd.data[0], cmd.data[1], cmd.data[2]);
|
||||
slave_interface->mainTLB->invalidateVA(
|
||||
cmd.data[0], cmd.data[1], cmd.data[2]);
|
||||
}
|
||||
tlb.invalidateVA(cmd.data[0], cmd.data[1], cmd.data[2]);
|
||||
walkCache.invalidateVA(cmd.data[0], cmd.data[1], cmd.data[2]);
|
||||
break;
|
||||
|
||||
case CMD_TLBI_VM_IPAL:
|
||||
DPRINTF(SMMUv3, "CMD_TLBI_VM_IPAL ipa=%#08x vmid=%#x\n",
|
||||
cmd.data[0], cmd.data[1]);
|
||||
// This does not invalidate TLBs containing
|
||||
// combined Stage1 + Stage2 translations, as per the spec.
|
||||
ipaCache.invalidateIPA(cmd.data[0], cmd.data[1]);
|
||||
walkCache.invalidateVMID(cmd.data[1]);
|
||||
break;
|
||||
|
||||
case CMD_TLBI_VM_IPA:
|
||||
DPRINTF(SMMUv3, "CMD_TLBI_VM_IPA ipa=%#08x vmid=%#x\n",
|
||||
cmd.data[0], cmd.data[1]);
|
||||
// This does not invalidate TLBs containing
|
||||
// combined Stage1 + Stage2 translations, as per the spec.
|
||||
ipaCache.invalidateIPA(cmd.data[0], cmd.data[1]);
|
||||
walkCache.invalidateVMID(cmd.data[1]);
|
||||
break;
|
||||
|
||||
case CMD_TLBI_VM_S12:
|
||||
DPRINTF(SMMUv3, "CMD_TLBI_VM_S12 vmid=%#x\n", cmd.data[0]);
|
||||
for (auto slave_interface : slaveInterfaces) {
|
||||
slave_interface->microTLB->invalidateVMID(cmd.data[0]);
|
||||
slave_interface->mainTLB->invalidateVMID(cmd.data[0]);
|
||||
}
|
||||
tlb.invalidateVMID(cmd.data[0]);
|
||||
ipaCache.invalidateVMID(cmd.data[0]);
|
||||
walkCache.invalidateVMID(cmd.data[0]);
|
||||
break;
|
||||
|
||||
case CMD_RESUME_S:
|
||||
DPRINTF(SMMUv3, "CMD_RESUME_S\n");
|
||||
panic("resume unimplemented");
|
||||
break;
|
||||
|
||||
default:
|
||||
warn("Unimplemented command %#x\n", cmd.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const PageTableOps*
|
||||
SMMUv3::getPageTableOps(uint8_t trans_granule)
|
||||
{
|
||||
static V8PageTableOps4k ptOps4k;
|
||||
static V8PageTableOps64k ptOps64k;
|
||||
|
||||
switch (trans_granule) {
|
||||
case TRANS_GRANULE_4K: return &ptOps4k;
|
||||
case TRANS_GRANULE_64K: return &ptOps64k;
|
||||
default:
|
||||
panic("Unknown translation granule size %d", trans_granule);
|
||||
}
|
||||
}
|
||||
|
||||
Tick
|
||||
SMMUv3::readControl(PacketPtr pkt)
|
||||
{
|
||||
DPRINTF(SMMUv3, "readControl: addr=%08x size=%d\n",
|
||||
pkt->getAddr(), pkt->getSize());
|
||||
|
||||
int offset = pkt->getAddr() - regsMap.start();
|
||||
assert(offset >= 0 && offset < SMMU_REG_SIZE);
|
||||
|
||||
if (inSecureBlock(offset)) {
|
||||
warn("smmu: secure registers (0x%x) are not implemented\n",
|
||||
offset);
|
||||
}
|
||||
|
||||
auto reg_ptr = regs.data + offset;
|
||||
|
||||
switch (pkt->getSize()) {
|
||||
case sizeof(uint32_t):
|
||||
pkt->setLE<uint32_t>(*reinterpret_cast<uint32_t *>(reg_ptr));
|
||||
break;
|
||||
case sizeof(uint64_t):
|
||||
pkt->setLE<uint64_t>(*reinterpret_cast<uint64_t *>(reg_ptr));
|
||||
break;
|
||||
default:
|
||||
panic("smmu: unallowed access size: %d bytes\n", pkt->getSize());
|
||||
break;
|
||||
}
|
||||
|
||||
pkt->makeAtomicResponse();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Tick
|
||||
SMMUv3::writeControl(PacketPtr pkt)
|
||||
{
|
||||
int offset = pkt->getAddr() - regsMap.start();
|
||||
assert(offset >= 0 && offset < SMMU_REG_SIZE);
|
||||
|
||||
DPRINTF(SMMUv3, "writeControl: addr=%08x size=%d data=%16x\n",
|
||||
pkt->getAddr(), pkt->getSize(),
|
||||
pkt->getSize() == sizeof(uint64_t) ?
|
||||
pkt->getLE<uint64_t>() : pkt->getLE<uint32_t>());
|
||||
|
||||
switch (offset) {
|
||||
case offsetof(SMMURegs, cr0):
|
||||
assert(pkt->getSize() == sizeof(uint32_t));
|
||||
regs.cr0 = regs.cr0ack = pkt->getLE<uint32_t>();
|
||||
break;
|
||||
|
||||
case offsetof(SMMURegs, cr1):
|
||||
case offsetof(SMMURegs, cr2):
|
||||
case offsetof(SMMURegs, strtab_base_cfg):
|
||||
case offsetof(SMMURegs, eventq_cons):
|
||||
case offsetof(SMMURegs, eventq_irq_cfg1):
|
||||
case offsetof(SMMURegs, priq_cons):
|
||||
assert(pkt->getSize() == sizeof(uint32_t));
|
||||
*reinterpret_cast<uint32_t *>(regs.data + offset) =
|
||||
pkt->getLE<uint32_t>();
|
||||
break;
|
||||
|
||||
case offsetof(SMMURegs, cmdq_prod):
|
||||
assert(pkt->getSize() == sizeof(uint32_t));
|
||||
*reinterpret_cast<uint32_t *>(regs.data + offset) =
|
||||
pkt->getLE<uint32_t>();
|
||||
schedule(processCommandsEvent, nextCycle());
|
||||
break;
|
||||
|
||||
case offsetof(SMMURegs, strtab_base):
|
||||
case offsetof(SMMURegs, eventq_irq_cfg0):
|
||||
assert(pkt->getSize() == sizeof(uint64_t));
|
||||
*reinterpret_cast<uint64_t *>(regs.data + offset) =
|
||||
pkt->getLE<uint64_t>();
|
||||
break;
|
||||
|
||||
case offsetof(SMMURegs, cmdq_base):
|
||||
assert(pkt->getSize() == sizeof(uint64_t));
|
||||
*reinterpret_cast<uint64_t *>(regs.data + offset) =
|
||||
pkt->getLE<uint64_t>();
|
||||
regs.cmdq_cons = 0;
|
||||
regs.cmdq_prod = 0;
|
||||
break;
|
||||
|
||||
|
||||
case offsetof(SMMURegs, eventq_base):
|
||||
assert(pkt->getSize() == sizeof(uint64_t));
|
||||
*reinterpret_cast<uint64_t *>(regs.data + offset) =
|
||||
pkt->getLE<uint64_t>();
|
||||
regs.eventq_cons = 0;
|
||||
regs.eventq_prod = 0;
|
||||
break;
|
||||
|
||||
case offsetof(SMMURegs, priq_base):
|
||||
assert(pkt->getSize() == sizeof(uint64_t));
|
||||
*reinterpret_cast<uint64_t *>(regs.data + offset) =
|
||||
pkt->getLE<uint64_t>();
|
||||
regs.priq_cons = 0;
|
||||
regs.priq_prod = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (inSecureBlock(offset)) {
|
||||
warn("smmu: secure registers (0x%x) are not implemented\n",
|
||||
offset);
|
||||
} else {
|
||||
warn("smmu: write to read-only/undefined register at 0x%x\n",
|
||||
offset);
|
||||
}
|
||||
}
|
||||
|
||||
pkt->makeAtomicResponse();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
SMMUv3::inSecureBlock(uint32_t offs) const
|
||||
{
|
||||
if (offs >= offsetof(SMMURegs, _secure_regs) && offs < SMMU_SECURE_SZ)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
SMMUv3::init()
|
||||
{
|
||||
// make sure both sides are connected and have the same block size
|
||||
if (!masterPort.isConnected())
|
||||
fatal("Master port is not connected.\n");
|
||||
|
||||
// If the second master port is connected for the table walks, enable
|
||||
// the mode to send table walks through this port instead
|
||||
if (masterTableWalkPort.isConnected())
|
||||
tableWalkPortEnable = true;
|
||||
|
||||
// notify the master side of our address ranges
|
||||
for (auto ifc : slaveInterfaces) {
|
||||
ifc->sendRange();
|
||||
}
|
||||
|
||||
if (controlPort.isConnected())
|
||||
controlPort.sendRangeChange();
|
||||
}
|
||||
|
||||
void
|
||||
SMMUv3::regStats()
|
||||
{
|
||||
MemObject::regStats();
|
||||
|
||||
using namespace Stats;
|
||||
|
||||
for (size_t i = 0; i < slaveInterfaces.size(); i++) {
|
||||
slaveInterfaces[i]->microTLB->regStats(
|
||||
csprintf("%s.utlb%d", name(), i));
|
||||
slaveInterfaces[i]->mainTLB->regStats(
|
||||
csprintf("%s.maintlb%d", name(), i));
|
||||
}
|
||||
|
||||
tlb.regStats(name() + ".tlb");
|
||||
configCache.regStats(name() + ".cfg");
|
||||
ipaCache.regStats(name() + ".ipa");
|
||||
walkCache.regStats(name() + ".walk");
|
||||
|
||||
steL1Fetches
|
||||
.name(name() + ".steL1Fetches")
|
||||
.desc("STE L1 fetches")
|
||||
.flags(pdf);
|
||||
|
||||
steFetches
|
||||
.name(name() + ".steFetches")
|
||||
.desc("STE fetches")
|
||||
.flags(pdf);
|
||||
|
||||
cdL1Fetches
|
||||
.name(name() + ".cdL1Fetches")
|
||||
.desc("CD L1 fetches")
|
||||
.flags(pdf);
|
||||
|
||||
cdFetches
|
||||
.name(name() + ".cdFetches")
|
||||
.desc("CD fetches")
|
||||
.flags(pdf);
|
||||
|
||||
translationTimeDist
|
||||
.init(0, 2000000, 2000)
|
||||
.name(name() + ".translationTimeDist")
|
||||
.desc("Time to translate address")
|
||||
.flags(pdf);
|
||||
|
||||
ptwTimeDist
|
||||
.init(0, 2000000, 2000)
|
||||
.name(name() + ".ptwTimeDist")
|
||||
.desc("Time to walk page tables")
|
||||
.flags(pdf);
|
||||
}
|
||||
|
||||
DrainState
|
||||
SMMUv3::drain()
|
||||
{
|
||||
panic("SMMUv3 doesn't support draining\n");
|
||||
}
|
||||
|
||||
void
|
||||
SMMUv3::serialize(CheckpointOut &cp) const
|
||||
{
|
||||
DPRINTF(Checkpoint, "Serializing SMMUv3\n");
|
||||
|
||||
SERIALIZE_ARRAY(regs.data, sizeof(regs.data) / sizeof(regs.data[0]));
|
||||
}
|
||||
|
||||
void
|
||||
SMMUv3::unserialize(CheckpointIn &cp)
|
||||
{
|
||||
DPRINTF(Checkpoint, "Unserializing SMMUv3\n");
|
||||
|
||||
UNSERIALIZE_ARRAY(regs.data, sizeof(regs.data) / sizeof(regs.data[0]));
|
||||
}
|
||||
|
||||
Port&
|
||||
SMMUv3::getPort(const std::string &name, PortID id)
|
||||
{
|
||||
if (name == "master") {
|
||||
return masterPort;
|
||||
} else if (name == "master_walker") {
|
||||
return masterTableWalkPort;
|
||||
} else if (name == "control") {
|
||||
return controlPort;
|
||||
} else {
|
||||
return MemObject::getPort(name, id);
|
||||
}
|
||||
}
|
||||
|
||||
SMMUv3*
|
||||
SMMUv3Params::create()
|
||||
{
|
||||
return new SMMUv3(this);
|
||||
}
|
||||
195
src/dev/arm/smmu_v3.hh
Normal file
195
src/dev/arm/smmu_v3.hh
Normal file
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018-2019 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.
|
||||
*
|
||||
* Authors: Stan Czerniawski
|
||||
*/
|
||||
|
||||
#ifndef __DEV_ARM_SMMU_V3_HH__
|
||||
#define __DEV_ARM_SMMU_V3_HH__
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/statistics.hh"
|
||||
#include "dev/arm/smmu_v3_caches.hh"
|
||||
#include "dev/arm/smmu_v3_cmdexec.hh"
|
||||
#include "dev/arm/smmu_v3_defs.hh"
|
||||
#include "dev/arm/smmu_v3_events.hh"
|
||||
#include "dev/arm/smmu_v3_ports.hh"
|
||||
#include "dev/arm/smmu_v3_proc.hh"
|
||||
#include "dev/arm/smmu_v3_ptops.hh"
|
||||
#include "dev/arm/smmu_v3_slaveifc.hh"
|
||||
#include "mem/mem_object.hh"
|
||||
#include "mem/packet.hh"
|
||||
#include "params/SMMUv3.hh"
|
||||
#include "sim/eventq.hh"
|
||||
|
||||
/**
|
||||
* @file:
|
||||
* This is an implementation of the SMMUv3 architecture.
|
||||
*
|
||||
* What can it do?
|
||||
* - Single-stage and nested translation with 4k or 64k granule. 16k would
|
||||
* be straightforward to add.
|
||||
* - Large pages are supported.
|
||||
* - Works with any gem5 device as long as it is issuing packets with a
|
||||
* valid (Sub)StreamId
|
||||
*
|
||||
* What it can't do?
|
||||
* - Fragment stage 1 page when the underlying stage 2 page is smaller. S1
|
||||
* page size > S2 page size is not supported
|
||||
* - Invalidations take zero time. This wouldn't be hard to fix.
|
||||
* - Checkpointing is not supported
|
||||
* - Stall/resume for faulting transactions is not supported
|
||||
*/
|
||||
class SMMUTranslationProcess;
|
||||
|
||||
class SMMUv3 : public MemObject
|
||||
{
|
||||
protected:
|
||||
|
||||
friend class SMMUProcess;
|
||||
friend class SMMUTranslationProcess;
|
||||
friend class SMMUCommandExecProcess;
|
||||
friend class SMMUv3SlaveInterface;
|
||||
|
||||
const System &system;
|
||||
const MasterID masterId;
|
||||
|
||||
SMMUMasterPort masterPort;
|
||||
SMMUMasterTableWalkPort masterTableWalkPort;
|
||||
SMMUControlPort controlPort;
|
||||
|
||||
ARMArchTLB tlb;
|
||||
ConfigCache configCache;
|
||||
IPACache ipaCache;
|
||||
WalkCache walkCache;
|
||||
|
||||
const bool tlbEnable;
|
||||
const bool configCacheEnable;
|
||||
const bool ipaCacheEnable;
|
||||
const bool walkCacheEnable;
|
||||
bool tableWalkPortEnable;
|
||||
|
||||
const bool walkCacheNonfinalEnable;
|
||||
const unsigned walkCacheS1Levels;
|
||||
const unsigned walkCacheS2Levels;
|
||||
const unsigned masterPortWidth; // in bytes
|
||||
|
||||
SMMUSemaphore tlbSem;
|
||||
SMMUSemaphore ifcSmmuSem;
|
||||
SMMUSemaphore smmuIfcSem;
|
||||
SMMUSemaphore configSem;
|
||||
SMMUSemaphore ipaSem;
|
||||
SMMUSemaphore walkSem;
|
||||
SMMUSemaphore masterPortSem;
|
||||
|
||||
SMMUSemaphore transSem; // max N transactions in SMMU
|
||||
SMMUSemaphore ptwSem; // max N concurrent PTWs
|
||||
SMMUSemaphore cycleSem; // max 1 table walk per cycle
|
||||
|
||||
// Timing parameters
|
||||
const Cycles tlbLat;
|
||||
const Cycles ifcSmmuLat;
|
||||
const Cycles smmuIfcLat;
|
||||
const Cycles configLat;
|
||||
const Cycles ipaLat;
|
||||
const Cycles walkLat;
|
||||
|
||||
// Stats
|
||||
Stats::Scalar steL1Fetches;
|
||||
Stats::Scalar steFetches;
|
||||
Stats::Scalar cdL1Fetches;
|
||||
Stats::Scalar cdFetches;
|
||||
Stats::Distribution translationTimeDist;
|
||||
Stats::Distribution ptwTimeDist;
|
||||
|
||||
std::vector<SMMUv3SlaveInterface *> slaveInterfaces;
|
||||
|
||||
SMMUCommandExecProcess commandExecutor;
|
||||
|
||||
const AddrRange regsMap;
|
||||
SMMURegs regs;
|
||||
|
||||
bool inSecureBlock(uint32_t offs) const;
|
||||
|
||||
std::queue<SMMUAction> packetsToRetry;
|
||||
std::queue<SMMUAction> packetsTableWalkToRetry;
|
||||
|
||||
|
||||
void scheduleSlaveRetries();
|
||||
|
||||
SMMUAction runProcess(SMMUProcess *proc, PacketPtr pkt);
|
||||
SMMUAction runProcessAtomic(SMMUProcess *proc, PacketPtr pkt);
|
||||
SMMUAction runProcessTiming(SMMUProcess *proc, PacketPtr pkt);
|
||||
|
||||
void processCommands();
|
||||
EventWrapper<SMMUv3, &SMMUv3::processCommands> processCommandsEvent;
|
||||
|
||||
void processCommand(const SMMUCommand &cmd);
|
||||
|
||||
const PageTableOps *getPageTableOps(uint8_t trans_granule);
|
||||
|
||||
public:
|
||||
SMMUv3(SMMUv3Params *p);
|
||||
virtual ~SMMUv3() {}
|
||||
|
||||
virtual void init() override;
|
||||
virtual void regStats() override;
|
||||
|
||||
Tick slaveRecvAtomic(PacketPtr pkt, PortID id);
|
||||
bool slaveRecvTimingReq(PacketPtr pkt, PortID id);
|
||||
bool masterRecvTimingResp(PacketPtr pkt);
|
||||
void masterRecvReqRetry();
|
||||
|
||||
bool masterTableWalkRecvTimingResp(PacketPtr pkt);
|
||||
void masterTableWalkRecvReqRetry();
|
||||
|
||||
Tick readControl(PacketPtr pkt);
|
||||
Tick writeControl(PacketPtr pkt);
|
||||
|
||||
DrainState drain() override;
|
||||
void serialize(CheckpointOut &cp) const override;
|
||||
void unserialize(CheckpointIn &cp) override;
|
||||
|
||||
virtual Port &getPort(const std::string &name,
|
||||
PortID id = InvalidPortID) override;
|
||||
};
|
||||
|
||||
#endif /* __DEV_ARM_SMMU_V3_HH__ */
|
||||
1226
src/dev/arm/smmu_v3_caches.cc
Normal file
1226
src/dev/arm/smmu_v3_caches.cc
Normal file
File diff suppressed because it is too large
Load Diff
348
src/dev/arm/smmu_v3_caches.hh
Normal file
348
src/dev/arm/smmu_v3_caches.hh
Normal file
@@ -0,0 +1,348 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2018-2019 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.
|
||||
*
|
||||
* Authors: Stan Czerniawski
|
||||
*/
|
||||
|
||||
#ifndef __DEV_ARM_SMMU_V3_CACHES_HH__
|
||||
#define __DEV_ARM_SMMU_V3_CACHES_HH__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/random.hh"
|
||||
#include "base/statistics.hh"
|
||||
#include "base/types.hh"
|
||||
|
||||
#define WALK_CACHE_LEVELS 4
|
||||
|
||||
enum {
|
||||
SMMU_CACHE_REPL_ROUND_ROBIN,
|
||||
SMMU_CACHE_REPL_RANDOM,
|
||||
SMMU_CACHE_REPL_LRU,
|
||||
};
|
||||
|
||||
class SMMUv3BaseCache
|
||||
{
|
||||
protected:
|
||||
int replacementPolicy;
|
||||
size_t nextToReplace;
|
||||
Random random;
|
||||
uint32_t useStamp;
|
||||
|
||||
Stats::Formula averageLookups;
|
||||
Stats::Scalar totalLookups;
|
||||
|
||||
Stats::Formula averageMisses;
|
||||
Stats::Scalar totalMisses;
|
||||
|
||||
Stats::Formula averageUpdates;
|
||||
Stats::Scalar totalUpdates;
|
||||
|
||||
Stats::Formula averageHitRate;
|
||||
|
||||
Stats::Scalar insertions;
|
||||
|
||||
static int decodePolicyName(const std::string &policy_name);
|
||||
|
||||
public:
|
||||
SMMUv3BaseCache(const std::string &policy_name, uint32_t seed);
|
||||
virtual ~SMMUv3BaseCache() {}
|
||||
|
||||
virtual void regStats(const std::string &name);
|
||||
};
|
||||
|
||||
class SMMUTLB : public SMMUv3BaseCache
|
||||
{
|
||||
public:
|
||||
enum AllocPolicy {
|
||||
ALLOC_ANY_WAY,
|
||||
ALLOC_ANY_BUT_LAST_WAY,
|
||||
ALLOC_LAST_WAY,
|
||||
};
|
||||
|
||||
struct Entry
|
||||
{
|
||||
bool valid;
|
||||
bool prefetched;
|
||||
mutable uint32_t lastUsed;
|
||||
|
||||
// TAGS
|
||||
uint32_t sid;
|
||||
uint32_t ssid;
|
||||
Addr va;
|
||||
Addr vaMask;
|
||||
|
||||
// EXTRA TAGS
|
||||
uint16_t asid;
|
||||
uint16_t vmid;
|
||||
|
||||
// OUTPUTS
|
||||
Addr pa;
|
||||
uint8_t permissions;
|
||||
};
|
||||
|
||||
SMMUTLB(unsigned numEntries, unsigned _associativity,
|
||||
const std::string &policy);
|
||||
SMMUTLB(const SMMUTLB& tlb) = delete;
|
||||
virtual ~SMMUTLB() {}
|
||||
|
||||
const Entry *lookup(uint32_t sid, uint32_t ssid, Addr va,
|
||||
bool updStats=true);
|
||||
const Entry *lookupAnyVA(uint32_t sid, uint32_t ssid,
|
||||
bool updStats=true);
|
||||
void store(const Entry &incoming, AllocPolicy alloc);
|
||||
|
||||
void invalidateVA(Addr va, uint16_t asid, uint16_t vmid);
|
||||
void invalidateVAA(Addr va, uint16_t vmid);
|
||||
void invalidateASID(uint16_t asid, uint16_t vmid);
|
||||
void invalidateVMID(uint16_t vmid);
|
||||
void invalidateAll();
|
||||
|
||||
private:
|
||||
typedef std::vector<Entry> Set;
|
||||
std::vector<Set> sets;
|
||||
|
||||
size_t associativity;
|
||||
|
||||
size_t pickSetIdx(Addr va) const;
|
||||
size_t pickEntryIdxToReplace(const Set &set, AllocPolicy alloc);
|
||||
};
|
||||
|
||||
class ARMArchTLB : public SMMUv3BaseCache
|
||||
{
|
||||
public:
|
||||
struct Entry
|
||||
{
|
||||
bool valid;
|
||||
mutable uint32_t lastUsed;
|
||||
|
||||
// TAGS
|
||||
Addr va;
|
||||
Addr vaMask;
|
||||
uint16_t asid;
|
||||
uint16_t vmid;
|
||||
|
||||
// OUTPUTS
|
||||
Addr pa;
|
||||
uint8_t permissions;
|
||||
};
|
||||
|
||||
ARMArchTLB(unsigned numEntries, unsigned _associativity,
|
||||
const std::string &policy);
|
||||
virtual ~ARMArchTLB() {}
|
||||
|
||||
const Entry *lookup(Addr va, uint16_t asid, uint16_t vmid,
|
||||
bool updStats=true);
|
||||
|
||||
void store(const Entry &incoming);
|
||||
|
||||
void invalidateVA(Addr va, uint16_t asid, uint16_t vmid);
|
||||
void invalidateVAA(Addr va, uint16_t vmid);
|
||||
void invalidateASID(uint16_t asid, uint16_t vmid);
|
||||
void invalidateVMID(uint16_t vmid);
|
||||
void invalidateAll();
|
||||
|
||||
private:
|
||||
typedef std::vector<Entry> Set;
|
||||
std::vector<Set> sets;
|
||||
|
||||
size_t associativity;
|
||||
|
||||
size_t pickSetIdx(Addr va, uint16_t asid, uint16_t vmid) const;
|
||||
size_t pickEntryIdxToReplace(const Set &set);
|
||||
};
|
||||
|
||||
class IPACache : public SMMUv3BaseCache
|
||||
{
|
||||
public:
|
||||
struct Entry
|
||||
{
|
||||
bool valid;
|
||||
mutable uint32_t lastUsed;
|
||||
|
||||
// TAGS
|
||||
Addr ipa;
|
||||
Addr ipaMask;
|
||||
uint16_t vmid;
|
||||
|
||||
// OUTPUTS
|
||||
Addr pa;
|
||||
uint8_t permissions;
|
||||
};
|
||||
|
||||
IPACache(unsigned numEntries, unsigned _associativity,
|
||||
const std::string &policy);
|
||||
virtual ~IPACache() {}
|
||||
|
||||
const Entry *lookup(Addr ipa, uint16_t vmid, bool updStats=true);
|
||||
void store(const Entry &incoming);
|
||||
|
||||
void invalidateIPA(Addr ipa, uint16_t vmid);
|
||||
void invalidateIPAA(Addr ipa);
|
||||
void invalidateVMID(uint16_t vmid);
|
||||
void invalidateAll();
|
||||
|
||||
private:
|
||||
typedef std::vector<Entry> Set;
|
||||
std::vector<Set> sets;
|
||||
|
||||
size_t associativity;
|
||||
|
||||
size_t pickSetIdx(Addr ipa, uint16_t vmid) const;
|
||||
size_t pickEntryIdxToReplace(const Set &set);
|
||||
};
|
||||
|
||||
class ConfigCache : public SMMUv3BaseCache
|
||||
{
|
||||
public:
|
||||
struct Entry
|
||||
{
|
||||
bool valid;
|
||||
mutable uint32_t lastUsed;
|
||||
|
||||
// TAGS
|
||||
uint32_t sid;
|
||||
uint32_t ssid;
|
||||
|
||||
// OUTPUTS
|
||||
bool stage1_en;
|
||||
bool stage2_en;
|
||||
Addr ttb0;
|
||||
Addr ttb1;
|
||||
Addr httb;
|
||||
uint16_t asid;
|
||||
uint16_t vmid;
|
||||
uint8_t stage1_tg;
|
||||
uint8_t stage2_tg;
|
||||
};
|
||||
|
||||
ConfigCache(unsigned numEntries, unsigned _associativity,
|
||||
const std::string &policy);
|
||||
virtual ~ConfigCache() {}
|
||||
|
||||
const Entry *lookup(uint32_t sid, uint32_t ssid, bool updStats=true);
|
||||
void store(const Entry &incoming);
|
||||
|
||||
void invalidateSSID(uint32_t sid, uint32_t ssid);
|
||||
void invalidateSID(uint32_t sid);
|
||||
void invalidateAll();
|
||||
|
||||
private:
|
||||
typedef std::vector<Entry> Set;
|
||||
std::vector<Set> sets;
|
||||
|
||||
size_t associativity;
|
||||
|
||||
size_t pickSetIdx(uint32_t sid, uint32_t ssid) const;
|
||||
size_t pickEntryIdxToReplace(const Set &set);
|
||||
};
|
||||
|
||||
class WalkCache : public SMMUv3BaseCache
|
||||
{
|
||||
public:
|
||||
struct Entry
|
||||
{
|
||||
bool valid;
|
||||
mutable uint32_t lastUsed;
|
||||
|
||||
// TAGS
|
||||
Addr va;
|
||||
Addr vaMask;
|
||||
uint16_t asid;
|
||||
uint16_t vmid;
|
||||
unsigned stage;
|
||||
unsigned level;
|
||||
|
||||
// OUTPUTS
|
||||
bool leaf;
|
||||
Addr pa;
|
||||
uint8_t permissions;
|
||||
};
|
||||
|
||||
WalkCache(const std::array<unsigned, 2*WALK_CACHE_LEVELS> &_sizes,
|
||||
unsigned _associativity, const std::string &policy);
|
||||
virtual ~WalkCache() {}
|
||||
|
||||
const Entry *lookup(Addr va, Addr vaMask, uint16_t asid, uint16_t vmid,
|
||||
unsigned stage, unsigned level, bool updStats=true);
|
||||
void store(const Entry &incoming);
|
||||
|
||||
void invalidateVA(Addr va, uint16_t asid, uint16_t vmid);
|
||||
void invalidateVAA(Addr va, uint16_t vmid);
|
||||
void invalidateASID(uint16_t asid, uint16_t vmid);
|
||||
void invalidateVMID(uint16_t vmid);
|
||||
void invalidateAll();
|
||||
|
||||
void regStats(const std::string &name) override;
|
||||
|
||||
protected:
|
||||
unsigned int lookupsByStageLevel[2][WALK_CACHE_LEVELS];
|
||||
Stats::Formula averageLookupsByStageLevel[2][WALK_CACHE_LEVELS];
|
||||
Stats::Scalar totalLookupsByStageLevel[2][WALK_CACHE_LEVELS];
|
||||
|
||||
unsigned int missesByStageLevel[2][WALK_CACHE_LEVELS];
|
||||
Stats::Formula averageMissesByStageLevel[2][WALK_CACHE_LEVELS];
|
||||
Stats::Scalar totalMissesByStageLevel[2][WALK_CACHE_LEVELS];
|
||||
|
||||
unsigned int updatesByStageLevel[2][WALK_CACHE_LEVELS];
|
||||
Stats::Formula averageUpdatesByStageLevel[2][WALK_CACHE_LEVELS];
|
||||
Stats::Scalar totalUpdatesByStageLevel[2][WALK_CACHE_LEVELS];
|
||||
|
||||
Stats::Formula averageHitRateByStageLevel[2][WALK_CACHE_LEVELS];
|
||||
|
||||
Stats::Scalar insertionsByStageLevel[2][WALK_CACHE_LEVELS];
|
||||
|
||||
private:
|
||||
typedef std::vector<Entry> Set;
|
||||
std::vector<Set> sets;
|
||||
|
||||
size_t associativity;
|
||||
std::array<unsigned, 2*WALK_CACHE_LEVELS> sizes;
|
||||
std::array<unsigned, 2*WALK_CACHE_LEVELS> offsets;
|
||||
|
||||
size_t pickSetIdx(Addr va, Addr vaMask,
|
||||
unsigned stage, unsigned level) const;
|
||||
|
||||
size_t pickEntryIdxToReplace(const Set &set,
|
||||
unsigned stage, unsigned level);
|
||||
};
|
||||
|
||||
#endif /* __DEV_ARM_SMMU_V3_CACHES_HH__ */
|
||||
81
src/dev/arm/smmu_v3_cmdexec.cc
Normal file
81
src/dev/arm/smmu_v3_cmdexec.cc
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018-2019 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.
|
||||
*
|
||||
* Authors: Stan Czerniawski
|
||||
*/
|
||||
|
||||
#include "dev/arm/smmu_v3_cmdexec.hh"
|
||||
|
||||
#include "base/bitfield.hh"
|
||||
#include "dev/arm/smmu_v3.hh"
|
||||
|
||||
void
|
||||
SMMUCommandExecProcess::main(Yield &yield)
|
||||
{
|
||||
SMMUAction a;
|
||||
a.type = ACTION_INITIAL_NOP;
|
||||
a.pkt = NULL;
|
||||
a.ifc = nullptr;
|
||||
a.delay = 0;
|
||||
yield(a);
|
||||
|
||||
while (true) {
|
||||
busy = true;
|
||||
|
||||
while (true) {
|
||||
int sizeMask =
|
||||
mask(smmu.regs.cmdq_base & Q_BASE_SIZE_MASK) & Q_CONS_PROD_MASK;
|
||||
|
||||
if ((smmu.regs.cmdq_cons & sizeMask) ==
|
||||
(smmu.regs.cmdq_prod & sizeMask))
|
||||
break; // command queue empty
|
||||
|
||||
Addr cmdAddr =
|
||||
(smmu.regs.cmdq_base & Q_BASE_ADDR_MASK) +
|
||||
(smmu.regs.cmdq_cons & sizeMask) * sizeof(SMMUCommand);
|
||||
|
||||
// This deliberately resets the error field in cmdq_cons!
|
||||
smmu.regs.cmdq_cons = (smmu.regs.cmdq_cons + 1) & sizeMask;
|
||||
|
||||
doRead(yield, cmdAddr, &cmd, sizeof(SMMUCommand));
|
||||
smmu.processCommand(cmd);
|
||||
}
|
||||
|
||||
busy = false;
|
||||
|
||||
doSleep(yield);
|
||||
}
|
||||
}
|
||||
70
src/dev/arm/smmu_v3_cmdexec.hh
Normal file
70
src/dev/arm/smmu_v3_cmdexec.hh
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018-2019 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.
|
||||
*
|
||||
* Authors: Stan Czerniawski
|
||||
*/
|
||||
|
||||
#ifndef __DEV_ARM_SMMU_V3_CMDEXEC_HH__
|
||||
#define __DEV_ARM_SMMU_V3_CMDEXEC_HH__
|
||||
|
||||
#include "dev/arm/smmu_v3_defs.hh"
|
||||
#include "dev/arm/smmu_v3_proc.hh"
|
||||
|
||||
class SMMUv3;
|
||||
|
||||
class SMMUCommandExecProcess : public SMMUProcess
|
||||
{
|
||||
private:
|
||||
SMMUCommand cmd;
|
||||
|
||||
bool busy;
|
||||
|
||||
virtual void main(Yield &yield);
|
||||
|
||||
public:
|
||||
SMMUCommandExecProcess(const std::string &name, SMMUv3 &_smmu) :
|
||||
SMMUProcess(name, _smmu),
|
||||
busy(false)
|
||||
{
|
||||
reinit();
|
||||
}
|
||||
|
||||
virtual ~SMMUCommandExecProcess() {}
|
||||
|
||||
bool isBusy() const { return busy; }
|
||||
};
|
||||
|
||||
#endif /* __DEV_ARM_SMMU_V3_CMDEXEC_HH__ */
|
||||
363
src/dev/arm/smmu_v3_defs.hh
Normal file
363
src/dev/arm/smmu_v3_defs.hh
Normal file
@@ -0,0 +1,363 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018-2019 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.
|
||||
*
|
||||
* Authors: Stan Czerniawski
|
||||
*/
|
||||
|
||||
#ifndef __DEV_ARM_SMMU_V3_DEFS_HH__
|
||||
#define __DEV_ARM_SMMU_V3_DEFS_HH__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "base/bitunion.hh"
|
||||
|
||||
enum {
|
||||
SMMU_SECURE_SZ = 0x184, // Secure regs are within page0
|
||||
SMMU_PAGE_ZERO_SZ = 0x10000,
|
||||
SMMU_PAGE_ONE_SZ = 0x10000,
|
||||
SMMU_REG_SIZE = SMMU_PAGE_ONE_SZ + SMMU_PAGE_ZERO_SZ
|
||||
};
|
||||
|
||||
enum {
|
||||
STE_CONFIG_ABORT = 0x0,
|
||||
STE_CONFIG_BYPASS = 0x4,
|
||||
STE_CONFIG_STAGE1_ONLY = 0x5,
|
||||
STE_CONFIG_STAGE2_ONLY = 0x6,
|
||||
STE_CONFIG_STAGE1_AND_2 = 0x7,
|
||||
};
|
||||
|
||||
enum {
|
||||
STAGE1_CFG_1L = 0x0,
|
||||
STAGE1_CFG_2L_4K = 0x1,
|
||||
STAGE1_CFG_2L_64K = 0x2,
|
||||
};
|
||||
|
||||
enum {
|
||||
ST_CFG_SPLIT_SHIFT = 6,
|
||||
ST_CD_ADDR_SHIFT = 5,
|
||||
CD_TTB_SHIFT = 4,
|
||||
STE_S2TTB_SHIFT = 4,
|
||||
};
|
||||
|
||||
enum {
|
||||
TRANS_GRANULE_4K = 0x0,
|
||||
TRANS_GRANULE_64K = 0x1,
|
||||
TRANS_GRANULE_16K = 0x2,
|
||||
TRANS_GRANULE_INVALID = 0x3,
|
||||
};
|
||||
|
||||
enum {
|
||||
ST_BASE_ADDR_MASK = 0x0000ffffffffffe0ULL,
|
||||
ST_CFG_SIZE_MASK = 0x000000000000003fULL,
|
||||
ST_CFG_SPLIT_MASK = 0x00000000000007c0ULL,
|
||||
ST_CFG_FMT_MASK = 0x0000000000030000ULL,
|
||||
ST_CFG_FMT_LINEAR = 0x0000000000000000ULL,
|
||||
ST_CFG_FMT_2LEVEL = 0x0000000000010000ULL,
|
||||
ST_L2_SPAN_MASK = 0x000000000000001fULL,
|
||||
ST_L2_ADDR_MASK = 0x0000ffffffffffe0ULL,
|
||||
|
||||
VMT_BASE_ADDR_MASK = 0x0000ffffffffffe0ULL,
|
||||
VMT_BASE_SIZE_MASK = 0x000000000000001fULL,
|
||||
|
||||
Q_CONS_PROD_MASK = 0x00000000000fffffULL,
|
||||
Q_BASE_ADDR_MASK = 0x0000ffffffffffe0ULL,
|
||||
Q_BASE_SIZE_MASK = 0x000000000000001fULL,
|
||||
|
||||
E_BASE_ENABLE_MASK = 0x8000000000000000ULL,
|
||||
E_BASE_ADDR_MASK = 0x0000fffffffffffcULL,
|
||||
};
|
||||
|
||||
union SMMURegs
|
||||
{
|
||||
uint8_t data[SMMU_REG_SIZE];
|
||||
|
||||
struct
|
||||
{
|
||||
uint32_t idr0; // 0x0000
|
||||
uint32_t idr1; // 0x0004
|
||||
uint32_t idr2; // 0x0008
|
||||
uint32_t idr3; // 0x000c
|
||||
uint32_t idr4; // 0x0010
|
||||
uint32_t idr5; // 0x0014
|
||||
uint32_t iidr; // 0x0018
|
||||
uint32_t aidr; // 0x001c
|
||||
uint32_t cr0; // 0x0020
|
||||
uint32_t cr0ack; // 0x0024
|
||||
uint32_t cr1; // 0x0028
|
||||
uint32_t cr2; // 0x002c
|
||||
uint32_t _pad1; // 0x0030
|
||||
uint32_t _pad2; // 0x0034
|
||||
uint32_t _pad3; // 0x0038
|
||||
uint32_t _pad4; // 0x003c
|
||||
uint32_t statusr; // 0x0040
|
||||
uint32_t gbpa; // 0x0044
|
||||
uint32_t agbpa; // 0x0048
|
||||
uint32_t _pad5; // 0x004c
|
||||
uint32_t irq_ctrl; // 0x0050
|
||||
uint32_t irq_ctrlack; // 0x0054
|
||||
uint32_t _pad6; // 0x0058
|
||||
uint32_t _pad7; // 0x005c
|
||||
|
||||
uint32_t gerror; // 0x0060
|
||||
uint32_t gerrorn; // 0x0064
|
||||
uint64_t gerror_irq_cfg0; // 0x0068, 64 bit
|
||||
uint32_t gerror_irq_cfg1; // 0x0070
|
||||
uint32_t gerror_irq_cfg2; // 0x0074
|
||||
uint32_t _pad_1; // 0x0078
|
||||
uint32_t _pad_2; // 0x007c
|
||||
|
||||
uint64_t strtab_base; // 0x0080, 64 bit
|
||||
uint32_t strtab_base_cfg; // 0x0088
|
||||
|
||||
uint64_t cmdq_base; // 0x0090, 64 bit
|
||||
uint32_t cmdq_prod; // 0x0098
|
||||
uint32_t cmdq_cons; // 0x009c
|
||||
uint64_t eventq_base; // 0x00a0, 64 bit
|
||||
uint32_t _pad8; // 0x00a8
|
||||
uint32_t _pad9; // 0x00ac
|
||||
uint64_t eventq_irq_cfg0; // 0x00b0, 64 bit
|
||||
uint32_t eventq_irq_cfg1; // 0x00b8
|
||||
uint32_t eventq_irq_cfg2; // 0x00bc
|
||||
uint64_t priq_base; // 0x00c0, 64 bit
|
||||
uint32_t _pad10; // 0x00c8
|
||||
uint32_t _pad11; // 0x00cc
|
||||
|
||||
uint64_t priq_irq_cfg0; // 0x00d0
|
||||
uint32_t priq_irq_cfg1; // 0x00d8
|
||||
uint32_t priq_irq_cfg2; // 0x00dc
|
||||
|
||||
uint32_t _pad12[8]; // 0x00e0 - 0x0100
|
||||
uint32_t gatos_ctrl; // 0x0100
|
||||
uint32_t _pad13; // 0x0104
|
||||
uint64_t gatos_sid; // 0x0108
|
||||
uint64_t gatos_addr; // 0x0110
|
||||
uint64_t gatos_par; // 0x0118
|
||||
uint32_t _pad14[24]; // 0x0120
|
||||
uint32_t vatos_sel; // 0x0180
|
||||
|
||||
uint32_t _pad15[8095]; // 0x184 - 0x7ffc
|
||||
|
||||
uint8_t _secure_regs[SMMU_SECURE_SZ]; // 0x8000 - 0x8180
|
||||
|
||||
uint32_t _pad16[8095]; // 0x8184 - 0x10000
|
||||
|
||||
// Page 1
|
||||
uint32_t _pad17[42]; // 0x10000
|
||||
uint32_t eventq_prod; // 0x100A8
|
||||
uint32_t eventq_cons; // 0x100AC
|
||||
|
||||
uint32_t _pad18[6]; // 0x100B0
|
||||
uint32_t priq_prod; // 0x100C8
|
||||
uint32_t priq_cons; // 0x100CC
|
||||
};
|
||||
};
|
||||
|
||||
struct StreamTableEntry
|
||||
{
|
||||
BitUnion64(DWORD0)
|
||||
Bitfield<0> valid;
|
||||
Bitfield<3, 1> config;
|
||||
Bitfield<5, 4> s1fmt;
|
||||
Bitfield<51, 6> s1ctxptr;
|
||||
Bitfield<63, 59> s1cdmax;
|
||||
EndBitUnion(DWORD0)
|
||||
DWORD0 dw0;
|
||||
|
||||
BitUnion64(DWORD1)
|
||||
Bitfield<1, 0> s1dss;
|
||||
Bitfield<3, 2> s1cir;
|
||||
Bitfield<5, 4> s1cor;
|
||||
Bitfield<7, 6> s1csh;
|
||||
Bitfield<8> s2hwu59;
|
||||
Bitfield<9> s2hwu60;
|
||||
Bitfield<10> s2hwu61;
|
||||
Bitfield<11> s2hwu62;
|
||||
Bitfield<12> dre;
|
||||
Bitfield<16, 13> cont;
|
||||
Bitfield<17> dcp;
|
||||
Bitfield<18> ppar;
|
||||
Bitfield<19> mev;
|
||||
Bitfield<27> s1stalld;
|
||||
Bitfield<29, 28> eats;
|
||||
Bitfield<31, 30> strw;
|
||||
Bitfield<35, 32> memattr;
|
||||
Bitfield<36> mtcfg;
|
||||
Bitfield<40, 37> alloccfg;
|
||||
Bitfield<45, 44> shcfg;
|
||||
Bitfield<47, 46> nscfg;
|
||||
Bitfield<49, 48> privcfg;
|
||||
Bitfield<51, 50> instcfg;
|
||||
EndBitUnion(DWORD1)
|
||||
DWORD1 dw1;
|
||||
|
||||
BitUnion64(DWORD2)
|
||||
Bitfield<15, 0> s2vmid;
|
||||
Bitfield<37, 32> s2t0sz;
|
||||
Bitfield<39, 38> s2sl0;
|
||||
Bitfield<41, 40> s2ir0;
|
||||
Bitfield<43, 42> s2or0;
|
||||
Bitfield<45, 44> s2sh0;
|
||||
Bitfield<47, 46> s2tg;
|
||||
Bitfield<50, 48> s2ps;
|
||||
Bitfield<51> s2aa64;
|
||||
Bitfield<52> s2endi;
|
||||
Bitfield<53> s2affd;
|
||||
Bitfield<54> s2ptw;
|
||||
Bitfield<55> s2hd;
|
||||
Bitfield<56> s2ha;
|
||||
Bitfield<57> s2s;
|
||||
Bitfield<58> s2r;
|
||||
EndBitUnion(DWORD2)
|
||||
DWORD2 dw2;
|
||||
|
||||
BitUnion64(DWORD3)
|
||||
Bitfield<51, 4> s2ttb;
|
||||
EndBitUnion(DWORD3)
|
||||
DWORD3 dw3;
|
||||
|
||||
uint64_t _pad[4];
|
||||
};
|
||||
|
||||
struct ContextDescriptor
|
||||
{
|
||||
BitUnion64(DWORD0)
|
||||
Bitfield<5, 0> t0sz;
|
||||
Bitfield<7, 6> tg0;
|
||||
Bitfield<9, 8> ir0;
|
||||
Bitfield<11, 10> or0;
|
||||
Bitfield<13, 12> sh0;
|
||||
Bitfield<14> epd0;
|
||||
Bitfield<15> endi;
|
||||
Bitfield<21, 16> t1sz;
|
||||
Bitfield<23, 22> tg1;
|
||||
Bitfield<25, 24> ir1;
|
||||
Bitfield<27, 26> or1;
|
||||
Bitfield<29, 28> sh1;
|
||||
Bitfield<30> epd1;
|
||||
Bitfield<31> valid;
|
||||
Bitfield<34, 32> ips;
|
||||
Bitfield<35> affd;
|
||||
Bitfield<36> wxn;
|
||||
Bitfield<37> uwxn;
|
||||
Bitfield<39, 38> tbi;
|
||||
Bitfield<40> pan;
|
||||
Bitfield<41> aa64;
|
||||
Bitfield<42> hd;
|
||||
Bitfield<43> ha;
|
||||
Bitfield<44> s;
|
||||
Bitfield<45> r;
|
||||
Bitfield<46> a;
|
||||
Bitfield<47> aset;
|
||||
Bitfield<63, 48> asid;
|
||||
EndBitUnion(DWORD0)
|
||||
DWORD0 dw0;
|
||||
|
||||
BitUnion64(DWORD1)
|
||||
Bitfield<0> nscfg0;
|
||||
Bitfield<1> had0;
|
||||
Bitfield<51, 4> ttb0;
|
||||
Bitfield<60> hwu0g59;
|
||||
Bitfield<61> hwu0g60;
|
||||
Bitfield<62> hwu0g61;
|
||||
Bitfield<63> hwu0g62;
|
||||
EndBitUnion(DWORD1)
|
||||
DWORD1 dw1;
|
||||
|
||||
BitUnion64(DWORD2)
|
||||
Bitfield<0> nscfg1;
|
||||
Bitfield<1> had1;
|
||||
Bitfield<51, 4> ttb1;
|
||||
Bitfield<60> hwu1g59;
|
||||
Bitfield<61> hwu1g60;
|
||||
Bitfield<62> hwu1g61;
|
||||
Bitfield<63> hwu1g62;
|
||||
EndBitUnion(DWORD2)
|
||||
DWORD2 dw2;
|
||||
|
||||
uint64_t mair;
|
||||
uint64_t amair;
|
||||
uint64_t _pad[3];
|
||||
};
|
||||
|
||||
enum SMMUCommandType {
|
||||
CMD_PRF_CONFIG = 0x1000,
|
||||
CMD_PRF_ADDR = 0x1001,
|
||||
CMD_INV_STE = 0x1100,
|
||||
CMD_INV_CD = 0x1101,
|
||||
CMD_INV_CD_ALL = 0x1102,
|
||||
CMD_INV_ALL = 0x1104,
|
||||
CMD_TLBI_ALL = 0x1110,
|
||||
CMD_TLBI_ASID = 0x1111,
|
||||
CMD_TLBI_VAAL = 0x1112,
|
||||
CMD_TLBI_VAA = 0x1113,
|
||||
CMD_TLBI_VAL = 0x1114,
|
||||
CMD_TLBI_VA = 0x1115,
|
||||
CMD_TLBI_VM_IPAL = 0x1120,
|
||||
CMD_TLBI_VM_IPA = 0x1121,
|
||||
CMD_TLBI_VM_S12 = 0x1122,
|
||||
CMD_RESUME_S = 0x1200,
|
||||
};
|
||||
|
||||
struct SMMUCommand
|
||||
{
|
||||
uint32_t type;
|
||||
uint32_t data[3];
|
||||
};
|
||||
|
||||
enum SMMUEventTypes {
|
||||
EVT_FAULT = 0x0001,
|
||||
};
|
||||
|
||||
enum SMMUEventFlags {
|
||||
EVF_WRITE = 0x0001,
|
||||
};
|
||||
|
||||
struct SMMUEvent
|
||||
{
|
||||
uint16_t type;
|
||||
uint16_t stag;
|
||||
uint32_t flags;
|
||||
uint32_t streamId;
|
||||
uint32_t substreamId;
|
||||
uint64_t va;
|
||||
uint64_t ipa;
|
||||
};
|
||||
|
||||
enum {
|
||||
SMMU_MAX_TRANS_ID = 64
|
||||
};
|
||||
|
||||
#endif /* __DEV_ARM_SMMU_V3_DEFS_HH__ */
|
||||
54
src/dev/arm/smmu_v3_events.cc
Normal file
54
src/dev/arm/smmu_v3_events.cc
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2018-2019 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.
|
||||
*
|
||||
* Authors: Stan Czerniawski
|
||||
*/
|
||||
|
||||
#include "dev/arm/smmu_v3_events.hh"
|
||||
|
||||
#include "dev/arm/smmu_v3_slaveifc.hh"
|
||||
|
||||
void
|
||||
SMMUDeviceRetryEvent::process()
|
||||
{
|
||||
smmuIfc.sendDeviceRetry();
|
||||
}
|
||||
|
||||
const std::string
|
||||
SMMUDeviceRetryEvent::name() const
|
||||
{
|
||||
return smmuIfc.name() + ".device_retry_event";
|
||||
}
|
||||
66
src/dev/arm/smmu_v3_events.hh
Normal file
66
src/dev/arm/smmu_v3_events.hh
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2018-2019 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.
|
||||
*
|
||||
* Authors: Stan Czerniawski
|
||||
*/
|
||||
|
||||
#ifndef __DEV_ARM_SMMU_V3_EVENTS_HH__
|
||||
#define __DEV_ARM_SMMU_V3_EVENTS_HH__
|
||||
|
||||
#include <base/types.hh>
|
||||
#include <sim/eventq.hh>
|
||||
|
||||
class SMMUv3SlaveInterface;
|
||||
|
||||
class SMMUDeviceRetryEvent : public Event
|
||||
{
|
||||
private:
|
||||
SMMUv3SlaveInterface &smmuIfc;
|
||||
|
||||
public:
|
||||
SMMUDeviceRetryEvent(SMMUv3SlaveInterface &ifc)
|
||||
: smmuIfc(ifc)
|
||||
{}
|
||||
|
||||
void process();
|
||||
|
||||
const std::string name() const;
|
||||
|
||||
const char *description() const
|
||||
{ return "SlaveRetryEvent"; }
|
||||
};
|
||||
|
||||
#endif /* __DEV_ARM_SMMU_V3_EVENTS_HH__ */
|
||||
178
src/dev/arm/smmu_v3_ports.cc
Normal file
178
src/dev/arm/smmu_v3_ports.cc
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018-2019 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.
|
||||
*
|
||||
* Authors: Stan Czerniawski
|
||||
*/
|
||||
|
||||
#include "dev/arm/smmu_v3_ports.hh"
|
||||
|
||||
#include "base/logging.hh"
|
||||
#include "dev/arm/smmu_v3.hh"
|
||||
#include "dev/arm/smmu_v3_slaveifc.hh"
|
||||
|
||||
SMMUMasterPort::SMMUMasterPort(const std::string &_name, SMMUv3 &_smmu) :
|
||||
MasterPort(_name, &_smmu),
|
||||
smmu(_smmu)
|
||||
{}
|
||||
|
||||
bool
|
||||
SMMUMasterPort::recvTimingResp(PacketPtr pkt)
|
||||
{
|
||||
return smmu.masterRecvTimingResp(pkt);
|
||||
}
|
||||
|
||||
void
|
||||
SMMUMasterPort::recvReqRetry()
|
||||
{
|
||||
return smmu.masterRecvReqRetry();
|
||||
}
|
||||
|
||||
SMMUMasterTableWalkPort::SMMUMasterTableWalkPort(const std::string &_name,
|
||||
SMMUv3 &_smmu) :
|
||||
MasterPort(_name, &_smmu),
|
||||
smmu(_smmu)
|
||||
{}
|
||||
|
||||
bool
|
||||
SMMUMasterTableWalkPort::recvTimingResp(PacketPtr pkt)
|
||||
{
|
||||
return smmu.masterTableWalkRecvTimingResp(pkt);
|
||||
}
|
||||
|
||||
void
|
||||
SMMUMasterTableWalkPort::recvReqRetry()
|
||||
{
|
||||
return smmu.masterTableWalkRecvReqRetry();
|
||||
}
|
||||
|
||||
SMMUSlavePort::SMMUSlavePort(const std::string &_name,
|
||||
SMMUv3SlaveInterface &_ifc,
|
||||
PortID _id)
|
||||
:
|
||||
QueuedSlavePort(_name, &_ifc, respQueue, _id),
|
||||
ifc(_ifc),
|
||||
respQueue(_ifc, *this)
|
||||
{}
|
||||
|
||||
void
|
||||
SMMUSlavePort::recvFunctional(PacketPtr pkt)
|
||||
{
|
||||
if (!respQueue.trySatisfyFunctional(pkt))
|
||||
recvAtomic(pkt);
|
||||
}
|
||||
|
||||
Tick
|
||||
SMMUSlavePort::recvAtomic(PacketPtr pkt)
|
||||
{
|
||||
return ifc.recvAtomic(pkt);
|
||||
}
|
||||
|
||||
bool
|
||||
SMMUSlavePort::recvTimingReq(PacketPtr pkt)
|
||||
{
|
||||
return ifc.recvTimingReq(pkt);
|
||||
}
|
||||
|
||||
SMMUControlPort::SMMUControlPort(const std::string &_name,
|
||||
SMMUv3 &_smmu, AddrRange _addrRange)
|
||||
:
|
||||
SimpleTimingPort(_name, &_smmu),
|
||||
smmu(_smmu),
|
||||
addrRange(_addrRange)
|
||||
{}
|
||||
|
||||
Tick
|
||||
SMMUControlPort::recvAtomic(PacketPtr pkt)
|
||||
{
|
||||
Addr addr = pkt->getAddr();
|
||||
unsigned size = pkt->getSize();
|
||||
|
||||
if (!addrRange.contains(addr) || !addrRange.contains(addr+size))
|
||||
panic("SMMU: invalid address on control port %x, packet size %d",
|
||||
addr, size);
|
||||
|
||||
// @todo: We need to pay for this and not just zero it out
|
||||
pkt->headerDelay = pkt->payloadDelay = 0;
|
||||
|
||||
return pkt->isRead() ? smmu.readControl(pkt) : smmu.writeControl(pkt);
|
||||
}
|
||||
|
||||
AddrRangeList
|
||||
SMMUControlPort::getAddrRanges() const
|
||||
{
|
||||
AddrRangeList list;
|
||||
list.push_back(addrRange);
|
||||
return list;
|
||||
}
|
||||
|
||||
SMMUATSMasterPort::SMMUATSMasterPort(const std::string &_name,
|
||||
SMMUv3SlaveInterface &_ifc) :
|
||||
QueuedMasterPort(_name, &_ifc, reqQueue, snoopRespQueue),
|
||||
ifc(_ifc),
|
||||
reqQueue(_ifc, *this),
|
||||
snoopRespQueue(_ifc, *this)
|
||||
{}
|
||||
|
||||
bool
|
||||
SMMUATSMasterPort::recvTimingResp(PacketPtr pkt)
|
||||
{
|
||||
return ifc.atsMasterRecvTimingResp(pkt);
|
||||
}
|
||||
|
||||
SMMUATSSlavePort::SMMUATSSlavePort(const std::string &_name,
|
||||
SMMUv3SlaveInterface &_ifc) :
|
||||
QueuedSlavePort(_name, &_ifc, respQueue),
|
||||
ifc(_ifc),
|
||||
respQueue(_ifc, *this)
|
||||
{}
|
||||
|
||||
void
|
||||
SMMUATSSlavePort::recvFunctional(PacketPtr pkt)
|
||||
{
|
||||
panic("Functional access on ATS port!");
|
||||
}
|
||||
|
||||
Tick
|
||||
SMMUATSSlavePort::recvAtomic(PacketPtr pkt)
|
||||
{
|
||||
return ifc.atsSlaveRecvAtomic(pkt);
|
||||
}
|
||||
|
||||
bool
|
||||
SMMUATSSlavePort::recvTimingReq(PacketPtr pkt)
|
||||
{
|
||||
return ifc.atsSlaveRecvTimingReq(pkt);
|
||||
}
|
||||
143
src/dev/arm/smmu_v3_ports.hh
Normal file
143
src/dev/arm/smmu_v3_ports.hh
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018-2019 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.
|
||||
*
|
||||
* Authors: Stan Czerniawski
|
||||
*/
|
||||
|
||||
#ifndef __DEV_ARM_SMMU_V3_PORTS_HH__
|
||||
#define __DEV_ARM_SMMU_V3_PORTS_HH__
|
||||
|
||||
#include "mem/qport.hh"
|
||||
#include "mem/tport.hh"
|
||||
|
||||
class SMMUv3;
|
||||
class SMMUv3SlaveInterface;
|
||||
|
||||
class SMMUMasterPort : public MasterPort
|
||||
{
|
||||
protected:
|
||||
SMMUv3 &smmu;
|
||||
|
||||
virtual bool recvTimingResp(PacketPtr pkt);
|
||||
virtual void recvReqRetry();
|
||||
|
||||
public:
|
||||
SMMUMasterPort(const std::string &_name, SMMUv3 &_smmu);
|
||||
virtual ~SMMUMasterPort() {}
|
||||
};
|
||||
|
||||
// Separate master port to send MMU initiated requests on
|
||||
class SMMUMasterTableWalkPort : public MasterPort
|
||||
{
|
||||
protected:
|
||||
SMMUv3 &smmu;
|
||||
|
||||
virtual bool recvTimingResp(PacketPtr pkt);
|
||||
virtual void recvReqRetry();
|
||||
|
||||
public:
|
||||
SMMUMasterTableWalkPort(const std::string &_name, SMMUv3 &_smmu);
|
||||
virtual ~SMMUMasterTableWalkPort() {}
|
||||
};
|
||||
|
||||
class SMMUSlavePort : public QueuedSlavePort
|
||||
{
|
||||
protected:
|
||||
SMMUv3SlaveInterface &ifc;
|
||||
RespPacketQueue respQueue;
|
||||
|
||||
virtual void recvFunctional(PacketPtr pkt);
|
||||
virtual Tick recvAtomic(PacketPtr pkt);
|
||||
virtual bool recvTimingReq(PacketPtr pkt);
|
||||
|
||||
public:
|
||||
SMMUSlavePort(const std::string &_name,
|
||||
SMMUv3SlaveInterface &_ifc,
|
||||
PortID _id = InvalidPortID);
|
||||
virtual ~SMMUSlavePort() {}
|
||||
|
||||
virtual AddrRangeList getAddrRanges() const
|
||||
{ return AddrRangeList { AddrRange(0, UINT64_MAX) }; }
|
||||
};
|
||||
|
||||
class SMMUControlPort : public SimpleTimingPort
|
||||
{
|
||||
protected:
|
||||
SMMUv3 &smmu;
|
||||
AddrRange addrRange;
|
||||
|
||||
virtual Tick recvAtomic(PacketPtr pkt);
|
||||
virtual AddrRangeList getAddrRanges() const;
|
||||
|
||||
public:
|
||||
SMMUControlPort(const std::string &_name, SMMUv3 &_smmu,
|
||||
AddrRange _addrRange);
|
||||
virtual ~SMMUControlPort() {}
|
||||
};
|
||||
|
||||
class SMMUATSMasterPort : public QueuedMasterPort
|
||||
{
|
||||
protected:
|
||||
SMMUv3SlaveInterface &ifc;
|
||||
ReqPacketQueue reqQueue;
|
||||
SnoopRespPacketQueue snoopRespQueue;
|
||||
|
||||
virtual bool recvTimingResp(PacketPtr pkt);
|
||||
|
||||
public:
|
||||
SMMUATSMasterPort(const std::string &_name, SMMUv3SlaveInterface &_ifc);
|
||||
virtual ~SMMUATSMasterPort() {}
|
||||
};
|
||||
|
||||
class SMMUATSSlavePort : public QueuedSlavePort
|
||||
{
|
||||
protected:
|
||||
SMMUv3SlaveInterface &ifc;
|
||||
RespPacketQueue respQueue;
|
||||
|
||||
virtual void recvFunctional(PacketPtr pkt);
|
||||
virtual Tick recvAtomic(PacketPtr pkt);
|
||||
virtual bool recvTimingReq(PacketPtr pkt);
|
||||
|
||||
virtual AddrRangeList getAddrRanges() const
|
||||
{ return AddrRangeList(); }
|
||||
|
||||
public:
|
||||
SMMUATSSlavePort(const std::string &_name, SMMUv3SlaveInterface &_ifc);
|
||||
virtual ~SMMUATSSlavePort() {}
|
||||
};
|
||||
|
||||
#endif /* __DEV_ARM_SMMU_V3_PORTS_HH__ */
|
||||
209
src/dev/arm/smmu_v3_proc.cc
Normal file
209
src/dev/arm/smmu_v3_proc.cc
Normal file
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018-2019 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.
|
||||
*
|
||||
* Authors: Stan Czerniawski
|
||||
*/
|
||||
|
||||
#include "dev/arm/smmu_v3_proc.hh"
|
||||
|
||||
#include "dev/arm/smmu_v3.hh"
|
||||
#include "sim/system.hh"
|
||||
|
||||
SMMUProcess::SMMUProcess(const std::string &name, SMMUv3 &_smmu) :
|
||||
coroutine(NULL),
|
||||
myName(name),
|
||||
smmu(_smmu)
|
||||
{}
|
||||
|
||||
SMMUProcess::~SMMUProcess()
|
||||
{
|
||||
delete coroutine;
|
||||
}
|
||||
|
||||
void
|
||||
SMMUProcess::wakeup()
|
||||
{
|
||||
smmu.runProcess(this, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
SMMUProcess::reinit()
|
||||
{
|
||||
delete coroutine;
|
||||
coroutine = new Coroutine(
|
||||
std::bind(&SMMUProcess::main, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
void
|
||||
SMMUProcess::doRead(Yield &yield, Addr addr, void *ptr, size_t size)
|
||||
{
|
||||
doSemaphoreDown(yield, smmu.masterPortSem);
|
||||
doDelay(yield, Cycles(1)); // request - assume 1 cycle
|
||||
doSemaphoreUp(smmu.masterPortSem);
|
||||
|
||||
SMMUAction a;
|
||||
a.type = ACTION_SEND_REQ;
|
||||
|
||||
RequestPtr req = std::make_shared<Request>(
|
||||
addr, size, 0, smmu.masterId);
|
||||
|
||||
req->taskId(ContextSwitchTaskId::DMA);
|
||||
|
||||
a.pkt = new Packet(req, MemCmd::ReadReq);
|
||||
a.pkt->dataStatic(ptr);
|
||||
|
||||
a.delay = 0;
|
||||
|
||||
PacketPtr pkt = yield(a).get();
|
||||
|
||||
assert(pkt);
|
||||
// >= because we may get the whole cache line
|
||||
assert(pkt->getSize() >= size);
|
||||
|
||||
delete pkt;
|
||||
}
|
||||
|
||||
void
|
||||
SMMUProcess::doWrite(Yield &yield, Addr addr, const void *ptr, size_t size)
|
||||
{
|
||||
unsigned nbeats = (size + (smmu.masterPortWidth-1)) / smmu.masterPortWidth;
|
||||
|
||||
doSemaphoreDown(yield, smmu.masterPortSem);
|
||||
doDelay(yield, Cycles(nbeats));
|
||||
doSemaphoreUp(smmu.masterPortSem);
|
||||
|
||||
|
||||
SMMUAction a;
|
||||
a.type = ACTION_SEND_REQ;
|
||||
|
||||
RequestPtr req = std::make_shared<Request>(
|
||||
addr, size, 0, smmu.masterId);
|
||||
|
||||
req->taskId(ContextSwitchTaskId::DMA);
|
||||
|
||||
a.pkt = new Packet(req, MemCmd::WriteReq);
|
||||
a.pkt->dataStatic(ptr);
|
||||
|
||||
PacketPtr pkt = yield(a).get();
|
||||
|
||||
delete pkt;
|
||||
}
|
||||
|
||||
void
|
||||
SMMUProcess::doDelay(Yield &yield, Cycles cycles)
|
||||
{
|
||||
if (smmu.system.isTimingMode())
|
||||
scheduleWakeup(smmu.clockEdge(cycles));
|
||||
|
||||
SMMUAction a;
|
||||
a.type = ACTION_DELAY;
|
||||
a.delay = cycles * smmu.clockPeriod();
|
||||
yield(a);
|
||||
}
|
||||
|
||||
void
|
||||
SMMUProcess::doSleep(Yield &yield)
|
||||
{
|
||||
SMMUAction a;
|
||||
a.type = ACTION_SLEEP;
|
||||
yield(a);
|
||||
}
|
||||
|
||||
void
|
||||
SMMUProcess::doSemaphoreDown(Yield &yield, SMMUSemaphore &sem)
|
||||
{
|
||||
while (sem.count == 0) {
|
||||
sem.queue.push(this);
|
||||
doSleep(yield);
|
||||
}
|
||||
|
||||
sem.count--;
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
SMMUProcess::doSemaphoreUp(SMMUSemaphore &sem)
|
||||
{
|
||||
sem.count++;
|
||||
if (!sem.queue.empty()) {
|
||||
SMMUProcess *next_proc = sem.queue.front();
|
||||
sem.queue.pop();
|
||||
|
||||
// Schedule event in the current tick instead of
|
||||
// calling the function directly to avoid overflowing
|
||||
// the stack in this coroutine.
|
||||
next_proc->scheduleWakeup(curTick());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SMMUProcess::doWaitForSignal(Yield &yield, SMMUSignal &sig)
|
||||
{
|
||||
sig.waiting.push_back(this);
|
||||
doSleep(yield);
|
||||
}
|
||||
|
||||
void
|
||||
SMMUProcess::doBroadcastSignal(SMMUSignal &sig)
|
||||
{
|
||||
if (!sig.waiting.empty()) {
|
||||
for (auto it : sig.waiting) {
|
||||
// Schedule event in the current tick instead of
|
||||
// calling the function directly to avoid overflowing
|
||||
// the stack in this coroutine.
|
||||
it->scheduleWakeup(curTick());
|
||||
}
|
||||
|
||||
sig.waiting.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SMMUProcess::scheduleWakeup(Tick when)
|
||||
{
|
||||
auto *ep = new EventWrapper<
|
||||
SMMUProcess, &SMMUProcess::wakeup> (this, true);
|
||||
|
||||
smmu.schedule(ep, when);
|
||||
}
|
||||
|
||||
SMMUAction
|
||||
SMMUProcess::run(PacketPtr pkt)
|
||||
{
|
||||
assert(coroutine != NULL);
|
||||
assert(*coroutine);
|
||||
return (*coroutine)(pkt).get();
|
||||
}
|
||||
136
src/dev/arm/smmu_v3_proc.hh
Normal file
136
src/dev/arm/smmu_v3_proc.hh
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018-2019 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.
|
||||
*
|
||||
* Authors: Stan Czerniawski
|
||||
*/
|
||||
|
||||
#ifndef __DEV_ARM_SMMU_V3_PROC_HH__
|
||||
#define __DEV_ARM_SMMU_V3_PROC_HH__
|
||||
|
||||
#include <list>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
|
||||
#include "base/coroutine.hh"
|
||||
#include "base/types.hh"
|
||||
#include "mem/packet.hh"
|
||||
|
||||
class SMMUv3SlaveInterface;
|
||||
|
||||
/*
|
||||
* The meaning of these becomes apparent when you
|
||||
* look at runProcessAtomic()/runProcessTiming().
|
||||
*/
|
||||
enum SMMUActionType {
|
||||
ACTION_INITIAL_NOP,
|
||||
ACTION_SEND_REQ,
|
||||
ACTION_SEND_REQ_FINAL,
|
||||
ACTION_SEND_RESP,
|
||||
ACTION_SEND_RESP_ATS,
|
||||
ACTION_DELAY,
|
||||
ACTION_SLEEP,
|
||||
ACTION_TERMINATE,
|
||||
};
|
||||
|
||||
struct SMMUAction
|
||||
{
|
||||
SMMUActionType type;
|
||||
PacketPtr pkt;
|
||||
SMMUv3SlaveInterface *ifc;
|
||||
Tick delay;
|
||||
};
|
||||
|
||||
class SMMUv3;
|
||||
class SMMUProcess;
|
||||
|
||||
struct SMMUSemaphore
|
||||
{
|
||||
explicit SMMUSemaphore(unsigned _max) :
|
||||
count(_max), max(_max)
|
||||
{}
|
||||
|
||||
unsigned count;
|
||||
unsigned max;
|
||||
std::queue<SMMUProcess *> queue;
|
||||
};
|
||||
|
||||
struct SMMUSignal
|
||||
{
|
||||
std::list<SMMUProcess *> waiting;
|
||||
};
|
||||
|
||||
class SMMUProcess : public Packet::SenderState
|
||||
{
|
||||
private:
|
||||
typedef m5::Coroutine<PacketPtr, SMMUAction> Coroutine;
|
||||
|
||||
Coroutine *coroutine;
|
||||
std::string myName;
|
||||
|
||||
void wakeup();
|
||||
|
||||
protected:
|
||||
typedef Coroutine::CallerType Yield;
|
||||
|
||||
SMMUv3 &smmu;
|
||||
|
||||
void reinit();
|
||||
|
||||
virtual void main(Yield &yield) = 0;
|
||||
|
||||
void doRead(Yield &yield, Addr addr, void *ptr, size_t size);
|
||||
void doWrite(Yield &yield, Addr addr, const void *ptr, size_t size);
|
||||
void doDelay(Yield &yield, Cycles cycles);
|
||||
void doSleep(Yield &yield);
|
||||
|
||||
void doSemaphoreDown(Yield &yield, SMMUSemaphore &sem);
|
||||
void doSemaphoreUp(SMMUSemaphore &sem);
|
||||
|
||||
void doWaitForSignal(Yield &yield, SMMUSignal &sig);
|
||||
void doBroadcastSignal(SMMUSignal &sig);
|
||||
|
||||
void scheduleWakeup(Tick when);
|
||||
|
||||
public:
|
||||
SMMUProcess(const std::string &name, SMMUv3 &_smmu);
|
||||
virtual ~SMMUProcess();
|
||||
|
||||
SMMUAction run(PacketPtr pkt);
|
||||
|
||||
const std::string name() const { return myName; };
|
||||
};
|
||||
|
||||
#endif /* __DEV_ARM_SMMU_V3_PROC_HH__ */
|
||||
316
src/dev/arm/smmu_v3_ptops.cc
Normal file
316
src/dev/arm/smmu_v3_ptops.cc
Normal file
@@ -0,0 +1,316 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018-2019 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.
|
||||
*
|
||||
* Authors: Stan Czerniawski
|
||||
*/
|
||||
|
||||
#include "dev/arm/smmu_v3_ptops.hh"
|
||||
|
||||
#include "base/bitfield.hh"
|
||||
#include "base/logging.hh"
|
||||
|
||||
bool
|
||||
V7LPageTableOps::isValid(pte_t pte, unsigned level) const
|
||||
{
|
||||
switch (level) {
|
||||
case 1: return pte & 0x1;
|
||||
case 2: return pte & 0x1;
|
||||
case 3: return (pte & 0x1) && (pte & 0x2);
|
||||
default: panic("bad level %d", level);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
V7LPageTableOps::isLeaf(pte_t pte, unsigned level) const
|
||||
{
|
||||
switch (level) {
|
||||
case 1: return !(pte & 0x2);
|
||||
case 2: return !(pte & 0x2);
|
||||
case 3: return true;
|
||||
default: panic("bad level %d", level);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
V7LPageTableOps::isWritable(pte_t pte, unsigned level, bool stage2) const
|
||||
{
|
||||
return stage2 ? bits(pte, 7, 6)==3 : bits(pte, 7)==0;
|
||||
}
|
||||
|
||||
Addr
|
||||
V7LPageTableOps::nextLevelPointer(pte_t pte, unsigned level) const
|
||||
{
|
||||
if (isLeaf(pte, level)) {
|
||||
switch (level) {
|
||||
case 1: return mbits(pte, 39, 30);
|
||||
case 2: return mbits(pte, 39, 21);
|
||||
case 3: return mbits(pte, 39, 12);
|
||||
default: panic("bad level %d", level);
|
||||
}
|
||||
} else {
|
||||
return mbits(pte, 39, 12);
|
||||
}
|
||||
}
|
||||
|
||||
Addr
|
||||
V7LPageTableOps::index(Addr va, unsigned level) const
|
||||
{
|
||||
// In theory this should be configurable...
|
||||
const int n = 12;
|
||||
|
||||
switch (level) {
|
||||
case 1: return bits(va, 26+n, 30) << 3; break;
|
||||
case 2: return bits(va, 29, 21) << 3; break;
|
||||
case 3: return bits(va, 20, 12) << 3; break;
|
||||
default: panic("bad level %d", level);
|
||||
}
|
||||
}
|
||||
|
||||
Addr
|
||||
V7LPageTableOps::pageMask(pte_t pte, unsigned level) const
|
||||
{
|
||||
switch (level) {
|
||||
case 1: return ~mask(30);
|
||||
case 2: return ~mask(21);
|
||||
case 3: return bits(pte, 52) ? ~mask(16) : ~mask(12);
|
||||
default: panic("bad level %d", level);
|
||||
}
|
||||
}
|
||||
|
||||
Addr
|
||||
V7LPageTableOps::walkMask(unsigned level) const
|
||||
{
|
||||
switch (level) {
|
||||
case 1: return mask(39, 30);
|
||||
case 2: return mask(39, 21);
|
||||
case 3: return mask(39, 12);
|
||||
default: panic("bad level %d", level);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned
|
||||
V7LPageTableOps::firstLevel() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned
|
||||
V7LPageTableOps::lastLevel() const
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
bool
|
||||
V8PageTableOps4k::isValid(pte_t pte, unsigned level) const
|
||||
{
|
||||
switch (level) {
|
||||
case 0: return pte & 0x1;
|
||||
case 1: return pte & 0x1;
|
||||
case 2: return pte & 0x1;
|
||||
case 3: return (pte & 0x1) && (pte & 0x2);
|
||||
default: panic("bad level %d", level);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
V8PageTableOps4k::isLeaf(pte_t pte, unsigned level) const
|
||||
{
|
||||
switch (level) {
|
||||
case 0: return false;
|
||||
case 1: return !(pte & 0x2);
|
||||
case 2: return !(pte & 0x2);
|
||||
case 3: return true;
|
||||
default: panic("bad level %d", level);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
V8PageTableOps4k::isWritable(pte_t pte, unsigned level, bool stage2) const
|
||||
{
|
||||
return stage2 ? bits(pte, 7, 6)==3 : bits(pte, 7)==0;
|
||||
}
|
||||
|
||||
Addr
|
||||
V8PageTableOps4k::nextLevelPointer(pte_t pte, unsigned level) const
|
||||
{
|
||||
if (isLeaf(pte, level)) {
|
||||
switch (level) {
|
||||
// no level 0 here
|
||||
case 1: return mbits(pte, 47, 30);
|
||||
case 2: return mbits(pte, 47, 21);
|
||||
case 3: return mbits(pte, 47, 12);
|
||||
default: panic("bad level %d", level);
|
||||
}
|
||||
} else {
|
||||
return mbits(pte, 47, 12);
|
||||
}
|
||||
}
|
||||
|
||||
Addr
|
||||
V8PageTableOps4k::index(Addr va, unsigned level) const
|
||||
{
|
||||
switch (level) {
|
||||
case 0: return bits(va, 47, 39) << 3; break;
|
||||
case 1: return bits(va, 38, 30) << 3; break;
|
||||
case 2: return bits(va, 29, 21) << 3; break;
|
||||
case 3: return bits(va, 20, 12) << 3; break;
|
||||
default: panic("bad level %d", level);
|
||||
}
|
||||
}
|
||||
|
||||
Addr
|
||||
V8PageTableOps4k::pageMask(pte_t pte, unsigned level) const
|
||||
{
|
||||
switch (level) {
|
||||
// no level 0 here
|
||||
case 1: return ~mask(30);
|
||||
case 2: return ~mask(21);
|
||||
case 3: return bits(pte, 52) ? ~mask(16) : ~mask(12);
|
||||
default: panic("bad level %d", level);
|
||||
}
|
||||
}
|
||||
|
||||
Addr
|
||||
V8PageTableOps4k::walkMask(unsigned level) const
|
||||
{
|
||||
switch (level) {
|
||||
case 0: return mask(47, 39);
|
||||
case 1: return mask(47, 30);
|
||||
case 2: return mask(47, 21);
|
||||
case 3: return mask(47, 12);
|
||||
default: panic("bad level %d", level);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned
|
||||
V8PageTableOps4k::firstLevel() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned
|
||||
V8PageTableOps4k::lastLevel() const
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
bool
|
||||
V8PageTableOps64k::isValid(pte_t pte, unsigned level) const
|
||||
{
|
||||
switch (level) {
|
||||
case 1: return pte & 0x1;
|
||||
case 2: return pte & 0x1;
|
||||
case 3: return (pte & 0x1) && (pte & 0x2);
|
||||
default: panic("bad level %d", level);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
V8PageTableOps64k::isLeaf(pte_t pte, unsigned level) const
|
||||
{
|
||||
switch (level) {
|
||||
case 1: return false;
|
||||
case 2: return !(pte & 0x2);
|
||||
case 3: return true;
|
||||
default: panic("bad level %d", level);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
V8PageTableOps64k::isWritable(pte_t pte, unsigned level, bool stage2) const
|
||||
{
|
||||
return stage2 ? bits(pte, 7, 6)==3 : bits(pte, 7)==0;
|
||||
}
|
||||
|
||||
Addr
|
||||
V8PageTableOps64k::nextLevelPointer(pte_t pte, unsigned level) const
|
||||
{
|
||||
if (isLeaf(pte, level)) {
|
||||
switch (level) {
|
||||
// no level 1 here
|
||||
case 2: return mbits(pte, 47, 29);
|
||||
case 3: return mbits(pte, 47, 16);
|
||||
default: panic("bad level %d", level);
|
||||
}
|
||||
} else {
|
||||
return mbits(pte, 47, 16);
|
||||
}
|
||||
}
|
||||
|
||||
Addr
|
||||
V8PageTableOps64k::index(Addr va, unsigned level) const
|
||||
{
|
||||
switch (level) {
|
||||
case 1: return bits(va, 47, 42) << 3; break;
|
||||
case 2: return bits(va, 41, 29) << 3; break;
|
||||
case 3: return bits(va, 28, 16) << 3; break;
|
||||
default: panic("bad level %d", level);
|
||||
}
|
||||
}
|
||||
|
||||
Addr
|
||||
V8PageTableOps64k::pageMask(pte_t pte, unsigned level) const
|
||||
{
|
||||
switch (level) {
|
||||
// no level 1 here
|
||||
case 2: return ~mask(29);
|
||||
case 3: return bits(pte, 52) ? ~mask(21) : ~mask(16);
|
||||
default: panic("bad level %d", level);
|
||||
}
|
||||
}
|
||||
|
||||
Addr
|
||||
V8PageTableOps64k::walkMask(unsigned level) const
|
||||
{
|
||||
switch (level) {
|
||||
case 1: return mask(47, 42);
|
||||
case 2: return mask(47, 29);
|
||||
case 3: return mask(47, 16);
|
||||
default: panic("bad level %d", level);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned
|
||||
V8PageTableOps64k::firstLevel() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned
|
||||
V8PageTableOps64k::lastLevel() const
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
101
src/dev/arm/smmu_v3_ptops.hh
Normal file
101
src/dev/arm/smmu_v3_ptops.hh
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018-2019 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.
|
||||
*
|
||||
* Authors: Stan Czerniawski
|
||||
*/
|
||||
|
||||
#ifndef __DEV_ARM_SMMU_V3_PTOPS_HH__
|
||||
#define __DEV_ARM_SMMU_V3_PTOPS_HH__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "base/types.hh"
|
||||
|
||||
struct PageTableOps
|
||||
{
|
||||
typedef int64_t pte_t;
|
||||
|
||||
virtual bool isValid(pte_t pte, unsigned level) const = 0;
|
||||
virtual bool isLeaf(pte_t pte, unsigned level) const = 0;
|
||||
virtual bool isWritable(pte_t pte, unsigned level, bool stage2) const = 0;
|
||||
virtual Addr nextLevelPointer(pte_t pte, unsigned level) const = 0;
|
||||
virtual Addr index(Addr va, unsigned level) const = 0;
|
||||
virtual Addr pageMask(pte_t pte, unsigned level) const = 0;
|
||||
virtual Addr walkMask(unsigned level) const = 0;
|
||||
virtual unsigned firstLevel() const = 0;
|
||||
virtual unsigned lastLevel() const = 0;
|
||||
};
|
||||
|
||||
struct V7LPageTableOps : public PageTableOps
|
||||
{
|
||||
virtual bool isValid(pte_t pte, unsigned level) const;
|
||||
virtual bool isLeaf(pte_t pte, unsigned level) const;
|
||||
virtual bool isWritable(pte_t pte, unsigned level, bool stage2) const;
|
||||
virtual Addr nextLevelPointer(pte_t pte, unsigned level) const;
|
||||
virtual Addr index(Addr va, unsigned level) const;
|
||||
virtual Addr pageMask(pte_t pte, unsigned level) const;
|
||||
virtual Addr walkMask(unsigned level) const;
|
||||
virtual unsigned firstLevel() const;
|
||||
virtual unsigned lastLevel() const;
|
||||
};
|
||||
|
||||
struct V8PageTableOps4k : public PageTableOps
|
||||
{
|
||||
virtual bool isValid(pte_t pte, unsigned level) const;
|
||||
virtual bool isLeaf(pte_t pte, unsigned level) const;
|
||||
virtual bool isWritable(pte_t pte, unsigned level, bool stage2) const;
|
||||
virtual Addr nextLevelPointer(pte_t pte, unsigned level) const;
|
||||
virtual Addr index(Addr va, unsigned level) const;
|
||||
virtual Addr pageMask(pte_t pte, unsigned level) const;
|
||||
virtual Addr walkMask(unsigned level) const;
|
||||
virtual unsigned firstLevel() const;
|
||||
virtual unsigned lastLevel() const;
|
||||
};
|
||||
|
||||
struct V8PageTableOps64k : public PageTableOps
|
||||
{
|
||||
virtual bool isValid(pte_t pte, unsigned level) const;
|
||||
virtual bool isLeaf(pte_t pte, unsigned level) const;
|
||||
virtual bool isWritable(pte_t pte, unsigned level, bool stage2) const;
|
||||
virtual Addr nextLevelPointer(pte_t pte, unsigned level) const;
|
||||
virtual Addr index(Addr va, unsigned level) const;
|
||||
virtual Addr pageMask(pte_t pte, unsigned level) const;
|
||||
virtual Addr walkMask(unsigned level) const;
|
||||
virtual unsigned firstLevel() const;
|
||||
virtual unsigned lastLevel() const;
|
||||
};
|
||||
|
||||
#endif /* __DEV_ARM_SMMU_V3_PTOPS_HH__ */
|
||||
263
src/dev/arm/smmu_v3_slaveifc.cc
Normal file
263
src/dev/arm/smmu_v3_slaveifc.cc
Normal file
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* Copyright (c) 2019 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.
|
||||
*
|
||||
* Authors: Stan Czerniawski
|
||||
* Giacomo Travaglini
|
||||
*/
|
||||
|
||||
#include "dev/arm/smmu_v3_slaveifc.hh"
|
||||
|
||||
#include "debug/SMMUv3.hh"
|
||||
#include "dev/arm/smmu_v3.hh"
|
||||
#include "dev/arm/smmu_v3_transl.hh"
|
||||
|
||||
SMMUv3SlaveInterface::SMMUv3SlaveInterface(
|
||||
const SMMUv3SlaveInterfaceParams *p) :
|
||||
MemObject(p),
|
||||
smmu(nullptr),
|
||||
microTLB(new SMMUTLB(p->utlb_entries,
|
||||
p->utlb_assoc,
|
||||
p->utlb_policy)),
|
||||
mainTLB(new SMMUTLB(p->tlb_entries,
|
||||
p->tlb_assoc,
|
||||
p->tlb_policy)),
|
||||
microTLBEnable(p->utlb_enable),
|
||||
mainTLBEnable(p->tlb_enable),
|
||||
slavePortSem(1),
|
||||
microTLBSem(p->utlb_slots),
|
||||
mainTLBSem(p->tlb_slots),
|
||||
microTLBLat(p->utlb_lat),
|
||||
mainTLBLat(p->tlb_lat),
|
||||
slavePort(new SMMUSlavePort(csprintf("%s.slave", name()), *this)),
|
||||
atsSlavePort(name() + ".atsSlave", *this),
|
||||
atsMasterPort(name() + ".atsMaster", *this),
|
||||
portWidth(p->port_width),
|
||||
wrBufSlotsRemaining(p->wrbuf_slots),
|
||||
xlateSlotsRemaining(p->xlate_slots),
|
||||
prefetchEnable(p->prefetch_enable),
|
||||
prefetchReserveLastWay(
|
||||
p->prefetch_reserve_last_way),
|
||||
deviceNeedsRetry(false),
|
||||
atsDeviceNeedsRetry(false),
|
||||
sendDeviceRetryEvent(*this),
|
||||
atsSendDeviceRetryEvent(this)
|
||||
{}
|
||||
|
||||
void
|
||||
SMMUv3SlaveInterface::sendRange()
|
||||
{
|
||||
if (slavePort->isConnected()) {
|
||||
inform("Slave port is connected to %d\n",
|
||||
slavePort->getMasterPort().name());
|
||||
|
||||
slavePort->sendRangeChange();
|
||||
} else {
|
||||
fatal("Slave port is not connected.\n");
|
||||
}
|
||||
}
|
||||
|
||||
Port&
|
||||
SMMUv3SlaveInterface::getPort(const std::string &name, PortID id)
|
||||
{
|
||||
if (name == "ats_master") {
|
||||
return atsMasterPort;
|
||||
} else if (name == "slave") {
|
||||
return *slavePort;
|
||||
} else if (name == "ats_slave") {
|
||||
return atsSlavePort;
|
||||
} else {
|
||||
return MemObject::getPort(name, id);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SMMUv3SlaveInterface::schedTimingResp(PacketPtr pkt)
|
||||
{
|
||||
slavePort->schedTimingResp(pkt, nextCycle());
|
||||
}
|
||||
|
||||
void
|
||||
SMMUv3SlaveInterface::schedAtsTimingResp(PacketPtr pkt)
|
||||
{
|
||||
atsSlavePort.schedTimingResp(pkt, nextCycle());
|
||||
|
||||
if (atsDeviceNeedsRetry) {
|
||||
atsDeviceNeedsRetry = false;
|
||||
schedule(atsSendDeviceRetryEvent, nextCycle());
|
||||
}
|
||||
}
|
||||
|
||||
Tick
|
||||
SMMUv3SlaveInterface::recvAtomic(PacketPtr pkt)
|
||||
{
|
||||
DPRINTF(SMMUv3, "[a] req from %s addr=%#x size=%#x\n",
|
||||
slavePort->getMasterPort().name(),
|
||||
pkt->getAddr(), pkt->getSize());
|
||||
|
||||
std::string proc_name = csprintf("%s.port", name());
|
||||
SMMUTranslationProcess proc(proc_name, *smmu, *this);
|
||||
proc.beginTransaction(SMMUTranslRequest::fromPacket(pkt));
|
||||
|
||||
SMMUAction a = smmu->runProcessAtomic(&proc, pkt);
|
||||
assert(a.type == ACTION_SEND_RESP);
|
||||
|
||||
return a.delay;
|
||||
}
|
||||
|
||||
bool
|
||||
SMMUv3SlaveInterface::recvTimingReq(PacketPtr pkt)
|
||||
{
|
||||
DPRINTF(SMMUv3, "[t] req from %s addr=%#x size=%#x\n",
|
||||
slavePort->getMasterPort().name(),
|
||||
pkt->getAddr(), pkt->getSize());
|
||||
|
||||
// @todo: We need to pay for this and not just zero it out
|
||||
pkt->headerDelay = pkt->payloadDelay = 0;
|
||||
|
||||
unsigned nbeats =
|
||||
(pkt->getSize() + (portWidth-1)) / portWidth;
|
||||
|
||||
if (xlateSlotsRemaining==0 ||
|
||||
(pkt->isWrite() && wrBufSlotsRemaining < nbeats))
|
||||
{
|
||||
deviceNeedsRetry = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
xlateSlotsRemaining--;
|
||||
if (pkt->isWrite())
|
||||
wrBufSlotsRemaining -= nbeats;
|
||||
|
||||
std::string proc_name = csprintf("%s.port", name());
|
||||
SMMUTranslationProcess *proc =
|
||||
new SMMUTranslationProcess(proc_name, *smmu, *this);
|
||||
proc->beginTransaction(SMMUTranslRequest::fromPacket(pkt));
|
||||
|
||||
smmu->runProcessTiming(proc, pkt);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Tick
|
||||
SMMUv3SlaveInterface::atsSlaveRecvAtomic(PacketPtr pkt)
|
||||
{
|
||||
DPRINTF(SMMUv3, "[a] ATS slave req addr=%#x size=%#x\n",
|
||||
pkt->getAddr(), pkt->getSize());
|
||||
|
||||
std::string proc_name = csprintf("%s.atsport", name());
|
||||
const bool ats_request = true;
|
||||
SMMUTranslationProcess proc(
|
||||
proc_name, *smmu, *this);
|
||||
proc.beginTransaction(SMMUTranslRequest::fromPacket(pkt, ats_request));
|
||||
|
||||
SMMUAction a = smmu->runProcessAtomic(&proc, pkt);
|
||||
assert(a.type == ACTION_SEND_RESP_ATS);
|
||||
|
||||
return a.delay;
|
||||
}
|
||||
|
||||
bool
|
||||
SMMUv3SlaveInterface::atsSlaveRecvTimingReq(PacketPtr pkt)
|
||||
{
|
||||
DPRINTF(SMMUv3, "[t] ATS slave req addr=%#x size=%#x\n",
|
||||
pkt->getAddr(), pkt->getSize());
|
||||
|
||||
// @todo: We need to pay for this and not just zero it out
|
||||
pkt->headerDelay = pkt->payloadDelay = 0;
|
||||
|
||||
if (xlateSlotsRemaining == 0) {
|
||||
deviceNeedsRetry = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
xlateSlotsRemaining--;
|
||||
|
||||
std::string proc_name = csprintf("%s.atsport", name());
|
||||
const bool ats_request = true;
|
||||
SMMUTranslationProcess *proc =
|
||||
new SMMUTranslationProcess(proc_name, *smmu, *this);
|
||||
proc->beginTransaction(SMMUTranslRequest::fromPacket(pkt, ats_request));
|
||||
|
||||
smmu->runProcessTiming(proc, pkt);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SMMUv3SlaveInterface::atsMasterRecvTimingResp(PacketPtr pkt)
|
||||
{
|
||||
DPRINTF(SMMUv3, "[t] ATS master resp addr=%#x size=%#x\n",
|
||||
pkt->getAddr(), pkt->getSize());
|
||||
|
||||
// @todo: We need to pay for this and not just zero it out
|
||||
pkt->headerDelay = pkt->payloadDelay = 0;
|
||||
|
||||
SMMUProcess *proc =
|
||||
safe_cast<SMMUProcess *>(pkt->popSenderState());
|
||||
|
||||
smmu->runProcessTiming(proc, pkt);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
SMMUv3SlaveInterface::sendDeviceRetry()
|
||||
{
|
||||
slavePort->sendRetryReq();
|
||||
}
|
||||
|
||||
void
|
||||
SMMUv3SlaveInterface::atsSendDeviceRetry()
|
||||
{
|
||||
DPRINTF(SMMUv3, "ATS retry\n");
|
||||
atsSlavePort.sendRetryReq();
|
||||
}
|
||||
|
||||
void
|
||||
SMMUv3SlaveInterface::scheduleDeviceRetry()
|
||||
{
|
||||
if (deviceNeedsRetry && !sendDeviceRetryEvent.scheduled()) {
|
||||
DPRINTF(SMMUv3, "sched slave retry\n");
|
||||
deviceNeedsRetry = false;
|
||||
schedule(sendDeviceRetryEvent, nextCycle());
|
||||
}
|
||||
}
|
||||
|
||||
SMMUv3SlaveInterface*
|
||||
SMMUv3SlaveInterfaceParams::create()
|
||||
{
|
||||
return new SMMUv3SlaveInterface(this);
|
||||
}
|
||||
131
src/dev/arm/smmu_v3_slaveifc.hh
Normal file
131
src/dev/arm/smmu_v3_slaveifc.hh
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018-2019 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.
|
||||
*
|
||||
* Authors: Stan Czerniawski
|
||||
*/
|
||||
|
||||
#ifndef __DEV_ARM_SMMU_V3_SLAVEIFC_HH__
|
||||
#define __DEV_ARM_SMMU_V3_SLAVEIFC_HH__
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "dev/arm/smmu_v3_caches.hh"
|
||||
#include "dev/arm/smmu_v3_defs.hh"
|
||||
#include "dev/arm/smmu_v3_events.hh"
|
||||
#include "dev/arm/smmu_v3_ports.hh"
|
||||
#include "dev/arm/smmu_v3_proc.hh"
|
||||
#include "mem/mem_object.hh"
|
||||
#include "params/SMMUv3SlaveInterface.hh"
|
||||
|
||||
class SMMUTranslationProcess;
|
||||
class SMMUv3;
|
||||
class SMMUSlavePort;
|
||||
|
||||
class SMMUv3SlaveInterface : public MemObject
|
||||
{
|
||||
public:
|
||||
SMMUv3 *smmu;
|
||||
SMMUTLB* microTLB;
|
||||
SMMUTLB* mainTLB;
|
||||
|
||||
const bool microTLBEnable;
|
||||
const bool mainTLBEnable;
|
||||
|
||||
SMMUSemaphore slavePortSem;
|
||||
SMMUSemaphore microTLBSem;
|
||||
SMMUSemaphore mainTLBSem;
|
||||
|
||||
const Cycles microTLBLat;
|
||||
const Cycles mainTLBLat;
|
||||
|
||||
SMMUSlavePort *slavePort;
|
||||
SMMUATSSlavePort atsSlavePort;
|
||||
SMMUATSMasterPort atsMasterPort;
|
||||
|
||||
// in bytes
|
||||
const unsigned portWidth;
|
||||
|
||||
unsigned wrBufSlotsRemaining;
|
||||
unsigned xlateSlotsRemaining;
|
||||
|
||||
const bool prefetchEnable;
|
||||
const bool prefetchReserveLastWay;
|
||||
|
||||
std::list<SMMUTranslationProcess *> duplicateReqs;
|
||||
SMMUSignal duplicateReqRemoved;
|
||||
|
||||
std::list<SMMUTranslationProcess *> dependentReads[SMMU_MAX_TRANS_ID];
|
||||
std::list<SMMUTranslationProcess *> dependentWrites[SMMU_MAX_TRANS_ID];
|
||||
SMMUSignal dependentReqRemoved;
|
||||
|
||||
// Receiving translation requests from the master device
|
||||
Tick recvAtomic(PacketPtr pkt);
|
||||
bool recvTimingReq(PacketPtr pkt);
|
||||
void schedTimingResp(PacketPtr pkt);
|
||||
|
||||
Tick atsSlaveRecvAtomic(PacketPtr pkt);
|
||||
bool atsSlaveRecvTimingReq(PacketPtr pkt);
|
||||
bool atsMasterRecvTimingResp(PacketPtr pkt);
|
||||
void schedAtsTimingResp(PacketPtr pkt);
|
||||
|
||||
void scheduleDeviceRetry();
|
||||
void sendDeviceRetry();
|
||||
void atsSendDeviceRetry();
|
||||
|
||||
bool deviceNeedsRetry;
|
||||
bool atsDeviceNeedsRetry;
|
||||
|
||||
SMMUDeviceRetryEvent sendDeviceRetryEvent;
|
||||
EventWrapper<
|
||||
SMMUv3SlaveInterface,
|
||||
&SMMUv3SlaveInterface::atsSendDeviceRetry> atsSendDeviceRetryEvent;
|
||||
|
||||
Port& getPort(const std::string &name, PortID id);
|
||||
|
||||
public:
|
||||
SMMUv3SlaveInterface(const SMMUv3SlaveInterfaceParams *p);
|
||||
|
||||
~SMMUv3SlaveInterface()
|
||||
{
|
||||
delete microTLB;
|
||||
delete mainTLB;
|
||||
}
|
||||
|
||||
void setSMMU(SMMUv3 *_smmu) { smmu = _smmu; }
|
||||
void sendRange();
|
||||
};
|
||||
|
||||
#endif /* __DEV_ARM_SMMU_V3_SLAVEIFC_HH__ */
|
||||
1443
src/dev/arm/smmu_v3_transl.cc
Normal file
1443
src/dev/arm/smmu_v3_transl.cc
Normal file
File diff suppressed because it is too large
Load Diff
190
src/dev/arm/smmu_v3_transl.hh
Normal file
190
src/dev/arm/smmu_v3_transl.hh
Normal file
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018-2019 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.
|
||||
*
|
||||
* Authors: Stan Czerniawski
|
||||
*/
|
||||
|
||||
#ifndef __DEV_ARM_SMMU_V3_TRANSL_HH__
|
||||
#define __DEV_ARM_SMMU_V3_TRANSL_HH__
|
||||
|
||||
#include "dev/arm/smmu_v3_proc.hh"
|
||||
#include "dev/arm/smmu_v3_ptops.hh"
|
||||
#include "dev/arm/smmu_v3_slaveifc.hh"
|
||||
#include "mem/packet.hh"
|
||||
|
||||
struct SMMUTranslRequest
|
||||
{
|
||||
Addr addr;
|
||||
unsigned size;
|
||||
uint32_t sid; // streamId
|
||||
uint32_t ssid; // substreamId
|
||||
bool isWrite;
|
||||
bool isPrefetch;
|
||||
bool isAtsRequest;
|
||||
|
||||
PacketPtr pkt;
|
||||
|
||||
static SMMUTranslRequest fromPacket(PacketPtr pkt, bool ats = false);
|
||||
static SMMUTranslRequest prefetch(Addr addr, uint32_t sid, uint32_t ssid);
|
||||
};
|
||||
|
||||
class SMMUTranslationProcess : public SMMUProcess
|
||||
{
|
||||
private:
|
||||
struct TranslContext
|
||||
{
|
||||
bool stage1Enable;
|
||||
bool stage2Enable;
|
||||
Addr ttb0, ttb1, httb;
|
||||
uint16_t asid;
|
||||
uint16_t vmid;
|
||||
uint8_t stage1TranslGranule;
|
||||
uint8_t stage2TranslGranule;
|
||||
};
|
||||
|
||||
enum FaultType
|
||||
{
|
||||
FAULT_NONE,
|
||||
FAULT_TRANSLATION, // F_TRANSLATION
|
||||
FAULT_PERMISSION, // F_PERMISSION
|
||||
};
|
||||
|
||||
struct TranslResult
|
||||
{
|
||||
FaultType fault;
|
||||
Addr addr;
|
||||
Addr addrMask;
|
||||
bool writable;
|
||||
};
|
||||
|
||||
SMMUv3SlaveInterface &ifc;
|
||||
|
||||
SMMUTranslRequest request;
|
||||
TranslContext context;
|
||||
|
||||
Tick recvTick;
|
||||
Tick faultTick;
|
||||
|
||||
virtual void main(Yield &yield);
|
||||
|
||||
TranslResult bypass(Addr addr) const;
|
||||
TranslResult smmuTranslation(Yield &yield);
|
||||
|
||||
bool microTLBLookup(Yield &yield, TranslResult &tr);
|
||||
bool ifcTLBLookup(Yield &yield, TranslResult &tr, bool &wasPrefetched);
|
||||
bool smmuTLBLookup(Yield &yield, TranslResult &tr);
|
||||
|
||||
void microTLBUpdate(Yield &yield, const TranslResult &tr);
|
||||
void ifcTLBUpdate(Yield &yield, const TranslResult &tr);
|
||||
void smmuTLBUpdate(Yield &yield, const TranslResult &tr);
|
||||
|
||||
bool configCacheLookup(Yield &yield, TranslContext &tc);
|
||||
void configCacheUpdate(Yield &yield, const TranslContext &tc);
|
||||
bool findConfig(Yield &yield, TranslContext &tc, TranslResult &tr);
|
||||
|
||||
void walkCacheLookup(Yield &yield,
|
||||
const WalkCache::Entry *&walkEntry,
|
||||
Addr addr, uint16_t asid, uint16_t vmid,
|
||||
unsigned stage, unsigned level);
|
||||
|
||||
void walkCacheUpdate(Yield &yield, Addr va, Addr vaMask, Addr pa,
|
||||
unsigned stage, unsigned level,
|
||||
bool leaf, uint8_t permissions);
|
||||
|
||||
TranslResult walkStage1And2(Yield &yield, Addr addr,
|
||||
const PageTableOps *pt_ops,
|
||||
unsigned level, Addr walkPtr);
|
||||
|
||||
TranslResult walkStage2(Yield &yield, Addr addr, bool final_tr,
|
||||
const PageTableOps *pt_ops,
|
||||
unsigned level, Addr walkPtr);
|
||||
|
||||
TranslResult translateStage1And2(Yield &yield, Addr addr);
|
||||
TranslResult translateStage2(Yield &yield, Addr addr, bool final_tr);
|
||||
|
||||
TranslResult combineTranslations(const TranslResult &s1tr,
|
||||
const TranslResult &s2tr) const;
|
||||
|
||||
/**
|
||||
* Used to force ordering on transactions with same
|
||||
* (SID, SSID, 4k page) to avoid multiple identical
|
||||
* page-table walks.
|
||||
*/
|
||||
bool hazard4kCheck();
|
||||
void hazard4kRegister();
|
||||
void hazard4kHold(Yield &yield);
|
||||
void hazard4kRelease();
|
||||
|
||||
/**
|
||||
* Used to force ordering on transactions with the same orderId.
|
||||
* This attempts to model AXI IDs.
|
||||
*/
|
||||
void hazardIdRegister();
|
||||
void hazardIdHold(Yield &yield);
|
||||
void hazardIdRelease();
|
||||
|
||||
void issuePrefetch(Addr addr);
|
||||
|
||||
void completeTransaction(Yield &yield, const TranslResult &tr);
|
||||
void completePrefetch(Yield &yield);
|
||||
|
||||
void sendEvent(Yield &yield, const SMMUEvent &ev);
|
||||
|
||||
void doReadSTE(Yield &yield, StreamTableEntry &ste, uint32_t sid);
|
||||
void doReadCD(Yield &yield, ContextDescriptor &cd,
|
||||
const StreamTableEntry &ste, uint32_t sid, uint32_t ssid);
|
||||
void doReadConfig(Yield &yield, Addr addr, void *ptr, size_t size,
|
||||
uint32_t sid, uint32_t ssid);
|
||||
void doReadPTE(Yield &yield, Addr va, Addr addr, void *ptr,
|
||||
unsigned stage, unsigned level);
|
||||
|
||||
public:
|
||||
SMMUTranslationProcess(const std::string &name, SMMUv3 &_smmu,
|
||||
SMMUv3SlaveInterface &_ifc)
|
||||
:
|
||||
SMMUProcess(name, _smmu),
|
||||
ifc(_ifc)
|
||||
{
|
||||
reinit();
|
||||
}
|
||||
|
||||
virtual ~SMMUTranslationProcess() {}
|
||||
|
||||
void beginTransaction(const SMMUTranslRequest &req);
|
||||
void resumeTransaction();
|
||||
};
|
||||
|
||||
#endif /* __DEV_ARM_SMMU_V3_TRANSL_HH__ */
|
||||
Reference in New Issue
Block a user