EDK II and Windows ARM require the following registers to be trapped and emulated in sys_regs.c
:
root@localhost:~# cat /proc/kmsg | grep "sys_regs"
[EDK II bootup]
<7>[ 1830.070417] [0:qemu-system-aar: 6889] KVM sys_regs trap: Op0 = 3, Op1 = 0, CRn = 1, CRm = 0, Op2 = 0, Rt = 0, is_write = 1
<7>[ 1830.070447] [0:qemu-system-aar: 6889] KVM sys_regs trap: Op0 = 3, Op1 = 0, CRn = 1, CRm = 0, Op2 = 0, Rt = 0, is_write = 1
<7>[ 1830.550467] [2:qemu-system-aar: 6889] KVM sys_regs trap: Op0 = 3, Op1 = 0, CRn = 2, CRm = 0, Op2 = 2, Rt = 0, is_write = 1
<7>[ 1830.550510] [2:qemu-system-aar: 6889] KVM sys_regs trap: Op0 = 3, Op1 = 0, CRn = 2, CRm = 0, Op2 = 0, Rt = 0, is_write = 1
<7>[ 1830.551762] [2:qemu-system-aar: 6889] KVM sys_regs trap: Op0 = 3, Op1 = 0, CRn = 10, CRm = 2, Op2 = 0, Rt = 0, is_write = 1
<7>[ 1830.551778] [2:qemu-system-aar: 6889] KVM sys_regs trap: Op0 = 3, Op1 = 0, CRn = 1, CRm = 0, Op2 = 0, Rt = 0, is_write = 1
<7>[ 1830.551794] [2:qemu-system-aar: 6889] KVM sys_regs trap: Op0 = 3, Op1 = 0, CRn = 1, CRm = 0, Op2 = 0, Rt = 0, is_write = 1
<7>[ 1830.551809] [2:qemu-system-aar: 6889] KVM sys_regs trap: Op0 = 3, Op1 = 0, CRn = 1, CRm = 0, Op2 = 0, Rt = 0, is_write = 1
<7>[ 1830.551824] [2:qemu-system-aar: 6889] KVM sys_regs trap: Op0 = 3, Op1 = 0, CRn = 1, CRm = 0, Op2 = 0, Rt = 0, is_write = 1
<7>[ 1830.551839] [2:qemu-system-aar: 6889] KVM sys_regs trap: Op0 = 3, Op1 = 0, CRn = 1, CRm = 0, Op2 = 0, Rt = 0, is_write = 1
[After manually load bootaa64.efi]
<7>[ 2293.777493] [2:qemu-system-aar: 6889] KVM sys_regs trap: Op0 = 3, Op1 = 3, CRn = 9, CRm = 13, Op2 = 0, Rt = 8, is_write = 0 => PMCCNTR_EL0
<7>[ 2293.777546] [2:qemu-system-aar: 6889] KVM sys_regs trap: Op0 = 3, Op1 = 3, CRn = 9, CRm = 12, Op2 = 0, Rt = 8, is_write = 0 => PMCR_EL0
<7>[ 2293.777571] [2:qemu-system-aar: 6889] KVM sys_regs trap: Op0 = 3, Op1 = 3, CRn = 9, CRm = 12, Op2 = 2, Rt = 10, is_write = 1 => PMCNTENCLR_EL0
<7>[ 2293.777595] [2:qemu-system-aar: 6889] KVM sys_regs trap: Op0 = 3, Op1 = 3, CRn = 9, CRm = 12, Op2 = 3, Rt = 8, is_write = 1 => PMOVSCLR_EL0 (unimplemented)
<7>[ 2293.777617] [2:qemu-system-aar: 6889] KVM sys_regs trap: Op0 = 3, Op1 = 0, CRn = 9, CRm = 14, Op2 = 2, Rt = 10, is_write = 1 => PMINTENCLR_EL1 (unimplemented)
<7>[ 2293.777639] [2:qemu-system-aar: 6889] KVM sys_regs trap: Op0 = 3, Op1 = 3, CRn = 9, CRm = 12, Op2 = 0, Rt = 8, is_write = 1 => PMCR_EL0
<7>[ 2293.777661] [2:qemu-system-aar: 6889] KVM sys_regs trap: Op0 = 3, Op1 = 3, CRn = 14, CRm = 15, Op2 = 7, Rt = 9, is_write = 1 => PMCCFILTR_EL0
<7>[ 2293.777708] [2:qemu-system-aar: 6889] KVM sys_regs trap: Op0 = 3, Op1 = 3, CRn = 9, CRm = 12, Op2 = 1, Rt = 8, is_write = 1 => PMCNTENSET_EL0
<7>[ 2293.777738] [2:qemu-system-aar: 6889] KVM sys_regs trap: Op0 = 3, Op1 = 3, CRn = 9, CRm = 14, Op2 = 0, Rt = 9, is_write = 1 => PMUSERENR_EL0 (unimplemented)
<7>[ 2293.781100] [2:qemu-system-aar: 6889] KVM sys_regs trap: Op0 = 3, Op1 = 3, CRn = 9, CRm = 13, Op2 = 0, Rt = 20, is_write = 0 => PMCCNTR_EL0
<7>[ 2293.782409] [2:qemu-system-aar: 6889] KVM sys_regs trap: Op0 = 3, Op1 = 3, CRn = 9, CRm = 13, Op2 = 0, Rt = 19, is_write = 0 => PMCCNTR_EL0
<7>[ 2293.791457] [2:qemu-system-aar: 6889] KVM sys_regs trap: Op0 = 3, Op1 = 3, CRn = 9, CRm = 13, Op2 = 0, Rt = 8, is_write = 0 => PMCCNTR_EL0
<7>[ 2293.795274] [3:qemu-system-aar: 6889] KVM sys_regs trap: Op0 = 3, Op1 = 3, CRn = 9, CRm = 13, Op2 = 0, Rt = 19, is_write = 0 => PMCCNTR_EL0
<7>[ 2294.109411] [3:qemu-system-aar: 6889] KVM sys_regs trap: Op0 = 3, Op1 = 3, CRn = 9, CRm = 13, Op2 = 0, Rt = 8, is_write = 0 => PMCCNTR_EL0
Note that the log's value is in decimal (output with %d
), not hex! I also added some notes to make it easier to understand which register is being trapped.
The above log is generated inserting a simple prink
to this line in the code:
int kvm_handle_sys_reg(struct kvm_vcpu *vcpu, struct kvm_run *run)
{
struct sys_reg_params params;
unsigned long esr = kvm_vcpu_get_hsr(vcpu);
params.is_aarch32 = false;
params.is_32bit = false;
params.Op0 = (esr >> 20) & 3;
params.Op1 = (esr >> 14) & 0x7;
params.CRn = (esr >> 10) & 0xf;
params.CRm = (esr >> 1) & 0xf;
params.Op2 = (esr >> 17) & 0x7;
params.Rt = (esr >> 5) & 0x1f;
params.is_write = !(esr & 1);
// Stupid printk for debugging trap-and-emulate process
printk(KERN_DEBUG "KVM sys_regs trap: Op0 = %d, Op1 = %d, CRn = %d, CRm = %d, Op2 = %d, Rt = %d, is_write = %d\n", params.Op0, params.Op1, params.CRn, params.CRm, params.Op2, params.Rt, params.is_write);
return emulate_sys_reg(vcpu, ¶ms);
}
Remember to
#include <linux/kern_levels.h>
or your compiler will complain!
I also wrote a simple Python script for converting the log to strings which can be used to find the line that the registers is trapped in sys_regs.c
:
def trap(s):
a = s.split(", ")
b = []
Op0 = int(a[0].split(" = ")[1])
b.append("Op0(0b" + f'{Op0:02b}' + ")")
Op1 = int(a[1].split(" = ")[1])
b.append("Op1(0b" + f'{Op1:03b}' + ")")
CRn = int(a[2].split(" = ")[1])
b.append("CRn(0b" + f'{CRn:04b}' + ")")
CRm = int(a[3].split(" = ")[1])
b.append("CRm(0b" + f'{CRm:04b}' + ")")
Op2 = int(a[4].split(" = ")[1])
b.append("Op2(0b" + f'{Op2:03b}' + ")")
return ', '.join(b)
Save it at trap.py
. Then open your Python console, run:
>>> import trap
>>> trap.trap("Op0 = 3, Op1 = 3, CRn = 9, CRm = 13, Op2 = 0")
'Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b000)'
>>>
Replace the string passed to trap.trap()
to the line you want to convert. Then open sys_regs.c
, use CTRL+F and paste the converted string to search.
Link to registers trap code:
Register name and trap code | Description | ARM document link | Implement status |
---|---|---|---|
PMCCNTR_EL0 |
Performance Monitors Cycle Count Register | Link | Implemented |
PMCR_EL0 |
Performance Monitors Control Register | Link | Implemented |
PMCNTENCLR_EL0 |
Performance Monitors Count Enable Clear register | Link | Implemented |
PMOVSCLR_EL0 |
Performance Monitors Overflow Flag Status Clear Register | Link | Unimplemented |
PMINTENCLR_EL1 |
Performance Monitors Interrupt Enable Clear register | Link | Unimplemented |
PMCCFILTR_EL0 |
Performance Monitors Cycle Count Filter Register | Link | Implemented |
PMCNTENSET_EL0 |
Performance Monitors Count Enable Set register | Link | Implemented |
PMUSERENR_EL0 |
Performance Monitors User Enable Register | Link | Unimplemented |
The process is being made at the pmu
branch and will soon be merged back to main
branch when it finished.
You can help us to make the work faster by sending pull requests! Thank you!
Consider seeing this mail thread