由于gem5源代码和一些出版物,我知道ARM PMU是部分实现的。
我有一个二进制文件,该文件使用perf_event在ARM处理器下基于Linux的OS上访问PMU。它可以在ARM ISA下在具有Linux内核的gem5全系统仿真中使用perf_event吗?
到目前为止,我还没有找到正确的方法。如果有人知道,我将不胜感激!
最佳答案
从2020年9月开始,gem5需要打补丁才能使用ARM PMU。
编辑:从2020年11月开始,gem5已被修补,它将包含在下一发行版中。感谢开发人员!
如何修补gem5
这不是一个干净的补丁(非常简单),它更旨在了解其工作原理。尽管如此,这是可用于gem5源存储库中的git apply
的补丁:
diff --git i/src/arch/arm/ArmISA.py w/src/arch/arm/ArmISA.py
index 2641ec3fb..3d85c1b75 100644
--- i/src/arch/arm/ArmISA.py
+++ w/src/arch/arm/ArmISA.py
@@ -36,6 +36,7 @@
from m5.params import *
from m5.proxy import *
+from m5.SimObject import SimObject
from m5.objects.ArmPMU import ArmPMU
from m5.objects.ArmSystem import SveVectorLength
from m5.objects.BaseISA import BaseISA
@@ -49,6 +50,8 @@ class ArmISA(BaseISA):
cxx_class = 'ArmISA::ISA'
cxx_header = "arch/arm/isa.hh"
+ generateDeviceTree = SimObject.recurseDeviceTree
+
system = Param.System(Parent.any, "System this ISA object belongs to")
pmu = Param.ArmPMU(NULL, "Performance Monitoring Unit")
diff --git i/src/arch/arm/ArmPMU.py w/src/arch/arm/ArmPMU.py
index 047e908b3..58553fbf9 100644
--- i/src/arch/arm/ArmPMU.py
+++ w/src/arch/arm/ArmPMU.py
@@ -40,6 +40,7 @@ from m5.params import *
from m5.params import isNullPointer
from m5.proxy import *
from m5.objects.Gic import ArmInterruptPin
+from m5.util.fdthelper import *
class ProbeEvent(object):
def __init__(self, pmu, _eventId, obj, *listOfNames):
@@ -76,6 +77,17 @@ class ArmPMU(SimObject):
_events = None
+ def generateDeviceTree(self, state):
+ node = FdtNode("pmu")
+ node.appendCompatible("arm,armv8-pmuv3")
+ # gem5 uses GIC controller interrupt notation, where PPI interrupts
+ # start to 16. However, the Linux kernel start from 0, and used a tag
+ # (set to 1) to indicate the PPI interrupt type.
+ node.append(FdtPropertyWords("interrupts", [
+ 1, int(self.interrupt.num) - 16, 0xf04
+ ]))
+ yield node
+
def addEvent(self, newObject):
if not (isinstance(newObject, ProbeEvent)
or isinstance(newObject, SoftwareIncrement)):
diff --git i/src/cpu/BaseCPU.py w/src/cpu/BaseCPU.py
index ab70d1d7f..66a49a038 100644
--- i/src/cpu/BaseCPU.py
+++ w/src/cpu/BaseCPU.py
@@ -302,6 +302,11 @@ class BaseCPU(ClockedObject):
node.appendPhandle(phandle_key)
cpus_node.append(node)
+ # Generate nodes from the BaseCPU children (and don't add them as
+ # subnode). Please note: this is mainly needed for the ISA class.
+ for child_node in self.recurseDeviceTree(state):
+ yield child_node
+
yield cpus_node
def __init__(self, **kwargs):
补丁解决了什么Linux内核使用设备树Blob(DTB)(这是一个常规文件)来声明运行内核的硬件。这用于使内核在不同体系结构之间可移植,而无需为每个硬件更改重新编译。 DTB遵循设备树引用,并从设备树源(DTS)文件(常规文本文件)进行编译。您可以了解更多here和here。
问题在于应该将PMU通过DTB声明给Linux内核。您可以了解更多here和here。在模拟系统中,由于系统是由用户指定的,因此gem5必须自行生成DTB才能传递给内核,因此后者可以识别模拟硬件。但是,问题在于gem5不会为我们的PMU生成DTB条目。
补丁做什么
该修补程序在ISA和CPU文件中添加了一个条目,以启用DTB生成递归来查找PMU。层次结构如下:CPU => ISA => PMU。然后,它将生成函数添加到PMU中,以生成唯一的DTB条目来声明PMU,并在内核中使用适当的符号来声明中断。
使用补丁运行模拟后,我们可以从DTB中看到DTS,如下所示:
cd m5out
# Decompile the DTB to get the DTS.
dtc -I dtb -O dts system.dtb > system.dts
# Find the PMU entry.
head system.dts
dtc
是设备树编译器,与sudo apt-get install device-tree-compiler
一起安装。我们最终在根节点(pmu
)下找到这个/
DTB条目:/dts-v1/;
/ {
#address-cells = <0x02>;
#size-cells = <0x02>;
interrupt-parent = <0x05>;
compatible = "arm,vexpress";
model = "V2P-CA15";
arm,hbi = <0x00>;
arm,vexpress,site = <0x0f>;
memory@80000000 {
device_type = "memory";
reg = <0x00 0x80000000 0x01 0x00>;
};
pmu {
compatible = "arm,armv8-pmuv3";
interrupts = <0x01 0x04 0xf04>;
};
cpus {
#address-cells = <0x01>;
#size-cells = <0x00>;
cpu@0 {
device_type = "cpu";
compatible = "gem5,arm-cpu";
[...]
在interrupts = <0x01 0x04 0xf04>;
行中,0x01
用来指示0x04
编号是PPI中断的编号(gem5中用20
编号声明的中断,在补丁代码中解释了16
的区别)。 0xf04
对应于一个标志(0x4
),该标志指示它是“ Activity 的高电平敏感”中断;而一个比特掩码(0xf
)则指示该中断应连接至与GIC相连的所有PE。您可以了解更多here。如果补丁程序有效并且您的
ArmPMU
正确声明,则在引导时应该会看到以下消息: [ 0.239967] hw perfevents: enabled with armv8_pmuv3 PMU driver, 32 counters available