在ARMv7/v8架构的虚拟化扩展中,HCR2(Hyp Configuration Register 2)和HDCR(Hyp Debug Control Register)是两个关键的系统寄存器,它们为hypervisor提供了对非安全世界(Non-secure world)的精细控制能力。作为在EL2(Hypervisor层)运行的软件,我们需要通过这些寄存器来管理客户机(Guest OS)的行为。
HCR2主要关注内存系统控制,特别是stage 2转换表的缓存属性覆盖;而HDCR则专注于调试和性能监控相关的陷阱控制。这两个寄存器共同构成了ARM虚拟化环境中的关键控制平面。
HCR2是一个32位寄存器,当前版本中实际使用的只有最低两位:
code复制31 0
+---------------------------------------------------------------+
| Reserved |
+---+---+-------------------------------------------------------+
|ID |CD | Reserved |
+---+---+-------------------------------------------------------+
ID (bit [1]): Instruction cacheability disable
CD (bit [0]): Data cacheability disable
在虚拟化环境中,hypervisor通常需要确保某些关键内存区域的访问不被缓存。例如:
设备模拟场景:
当客户机访问虚拟设备时,hypervisor需要捕获这些访问并模拟设备行为。此时设置CD位可以确保设备寄存器的访问总是到达物理硬件,避免缓存带来的不一致性。
安全监控场景:
安全监控程序可能需要拦截客户机的特定内存访问。通过ID/CD位的设置,可以确保监控程序看到的是实时的内存状态,而非缓存中的陈旧数据。
调试场景:
在调试客户机时,设置ID位可以确保指令获取总是来自内存,便于设置断点和观察代码执行流程。
HCR2的访问遵循ARM的特权模型:
c复制if (!FEAT_AA32EL2) {
Undefined();
} else if (EL == EL0) {
Undefined();
} else if (EL == EL1) {
if (EL2Enabled() && FEAT_AA64EL2 && !ELUsingAArch32(EL2) && HSTR_EL2.T1 == 1) {
TrapToEL2();
} else if (EL2Enabled() && FEAT_AA32EL2 && ELUsingAArch32(EL2) && HSTR.T1 == 1) {
TrapToEL2();
} else {
Undefined();
}
} else if (EL == EL2) {
AccessAllowed();
} else if (EL == EL3) {
if (SCR.NS == 0) {
Undefined();
} else {
AccessAllowed();
}
}
关键提示:在EL1尝试访问HCR2通常会触发陷阱到EL2,这是hypervisor监控客户机行为的重要机制。开发者可以利用这点实现透明的寄存器虚拟化。
HDCR是一个功能丰富的32位寄存器,主要分为以下几个功能区域:
code复制31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| |H |M |T |H | | |H | | |T | |H | | | |T |T |T |T |H |T |T | | |H |
|R |P |T |D |L |R |R |C |R |R |T |R |P |R |R |R |D |D |D |D |P |P |P |R |R |P |
|E |M |P |C |P |E |E |C |E |E |R |E |M |E |E |E |R |O |A |E |M |M |M |E |E |M |
|S |F |M |C | |S |S |D |S |S |F |S |D |S |S |S |A |S | | |E |C |R |S |S |N |
|0 |Z |E | | |0 |0 | |0 |0 | |0 | |0 |0 |0 | |A | | | |R | |0 |0 | |
| |O | | | | | | | | | | | | | | | | | | | | | | | | |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
HPMFZO (bit 29): Hypervisor Performance Monitors Freeze-on-overflow
HLP (bit 26): Hypervisor Long event counter enable
HPMN (bits [4:0]): Number of event counters accessible from EL1
TDCC (bit 27): Trap DCC
TTRF (bit 19): Trap Trace Filter Control
TDRA (bit 11): Trap Debug ROM Address
TDE (bit 8): Trap Debug exceptions
assembly复制// 设置HPMN=4,允许EL1访问前4个性能计数器
MOV r0, #4
ORR r0, r0, #(1 << 26) // 设置HLP位,启用64位溢出检测
ORR r0, r0, #(1 << 29) // 设置HPMFZO,溢出时冻结计数器
MCR p15, 4, r0, c1, c1, 1 // 写入HDCR
assembly复制// 配置调试陷阱
MOV r0, #0
ORR r0, r0, #(1 << 27) // 启用DCC陷阱(TDCC)
ORR r0, r0, #(1 << 19) // 启用Trace Filter陷阱(TTRF)
ORR r0, r0, #(1 << 11) // 启用Debug ROM地址陷阱(TDRA)
ORR r0, r0, #(1 << 8) // 将调试异常路由到EL2(TDE)
MCR p15, 4, r0, c1, c1, 1 // 写入HDCR
HDCR的访问权限模型与HCR2类似,但增加了对EL3的特别处理:
c复制if (!FEAT_AA32EL2) {
Undefined();
} else if (EL == EL0) {
Undefined();
} else if (EL == EL1) {
if (EL2Enabled() && FEAT_AA64EL2 && !ELUsingAArch32(EL2) && HSTR_EL2.T1 == 1) {
TrapToEL2();
} else if (EL2Enabled() && FEAT_AA32EL2 && ELUsingAArch32(EL2) && HSTR.T1 == 1) {
TrapToEL2();
} else {
Undefined();
}
} else if (EL == EL2) {
if (EL3Implemented() && MDCR_EL3.TDA == 1) {
if (EL3SDDUndef()) {
Undefined();
} else {
TrapToEL3();
}
} else {
AccessAllowed();
}
} else if (EL == EL3) {
if (SCR.NS == 0) {
Undefined();
} else {
AccessAllowed();
}
}
在KVM等虚拟化环境中,hypervisor通常会在VM入口处配置这些寄存器。以下是一个典型的配置流程:
VM创建时:
VM运行时:
VM退出时:
可能原因:
解决方案:
assembly复制// 确保计数器启用
MRC p15, 0, r0, c9, c12, 0 // 读取PMCR
BIC r0, r0, #(1 << 6) // 清除DP位
MCR p15, 0, r0, c9, c12, 0 // 写回PMCR
MRC p15, 4, r0, c1, c1, 1 // 读取HDCR
BIC r0, r0, #(1 << 17) // 清除HPMD位
ORR r0, r0, #(1 << 7) // 设置HPME位
MCR p15, 4, r0, c1, c1, 1 // 写回HDCR
可能原因:
解决方案:
assembly复制// 确保调试异常路由正确
MRC p15, 4, r0, c1, c1, 1 // 读取HDCR
ORR r0, r0, #(1 << 8) // 设置TDE位
MCR p15, 4, r0, c1, c1, 1 // 写回HDCR
MRC p15, 4, r0, c1, c1, 0 // 读取HCR
BIC r0, r0, #(1 << 27) // 清除TGE位
MCR p15, 4, r0, c1, c1, 0 // 写回HCR
可能原因:
解决方案:
assembly复制// 确保缓存控制生效
MRC p15, 4, r0, c1, c1, 0 // 读取HCR
ORR r0, r0, #(1 << 0) // 设置VM位
MCR p15, 4, r0, c1, c1, 0 // 写回HCR
MRC p15, 4, r0, c1, c1, 3 // 读取HCR2
ORR r0, r0, #(1 << 0) // 设置CD位
ORR r0, r0, #(1 << 1) // 设置ID位
MCR p15, 4, r0, c1, c1, 3 // 写回HCR2
谨慎使用HCR2的ID/CD位:
强制Non-cacheable会显著降低性能,应仅对关键区域使用。可以通过stage 2页表精细控制缓存属性,而非全局设置。
合理分配性能计数器:
根据工作负载特点,通过HDCR.HPMN将计数器分配给EL1或保留给EL2使用。例如:
利用调试陷阱优化:
对于频繁触发的调试事件(如特定地址访问),考虑使用HDCR的陷阱控制位替代完整的异常处理,减少上下文切换开销。
在ARMv8架构中,这些寄存器的功能被重新组织:
当ARM TrustZone安全扩展启用时,这些寄存器的行为会受到影响:
根据ARM架构的演进路线,以下特性值得关注:
FEAT_PMUv3p9:
将引入更灵活的性能计数器分配机制,可能扩展HDCR.HPMN的功能
FEAT_Debugv8p8:
预计会增强调试陷阱控制,提供更精细的异常过滤机制
FEAT_VHE(Virtualization Host Extensions):
在支持VHE的系统中,这些寄存器的访问模型会有变化,EL2可以更高效地管理客户机状态