AArch64 EL2 hypervisor for QEMU virt that boots at EL2
1#include "hv/sysreg.h"
2
3uint64_t sysreg_key_make(uint32_t op0, uint32_t op1, uint32_t crn, uint32_t crm, uint32_t op2)
4{
5 return ((uint64_t)(op0 & 0x3u) << 14u) |
6 ((uint64_t)(op1 & 0x7u) << 11u) |
7 ((uint64_t)(crn & 0xfu) << 7u) |
8 ((uint64_t)(crm & 0xfu) << 3u) |
9 (uint64_t)(op2 & 0x7u);
10}
11
12bool sysreg_decode_from_esr_iss(uint64_t iss, struct sysreg_access *out)
13{
14 if (out == (struct sysreg_access *)0) {
15 return false;
16 }
17 out->op0 = (uint32_t)((iss >> 20u) & 0x3u);
18 out->op2 = (uint32_t)((iss >> 17u) & 0x7u);
19 out->op1 = (uint32_t)((iss >> 14u) & 0x7u);
20 out->crn = (uint32_t)((iss >> 10u) & 0xfu);
21 out->rt = (uint32_t)((iss >> 5u) & 0x1fu);
22 out->crm = (uint32_t)((iss >> 1u) & 0xfu);
23 out->is_read = ((iss & 1u) == ESR_SYSREG_DIR_READ);
24 out->key = sysreg_key_make(out->op0, out->op1, out->crn, out->crm, out->op2);
25 return true;
26}
27
28struct sysreg_name {
29 uint64_t key;
30 const char *name;
31};
32
33#define KEY(op0, op1, crn, crm, op2) SYSREG_KEY_CONST((op0), (op1), (crn), (crm), (op2))
34
35static const struct sysreg_name g_names[] = {
36 { KEY(3, 0, 0, 0, 0), "midr_el1" },
37 { KEY(3, 0, 0, 0, 5), "mpidr_el1" },
38 { KEY(3, 0, 0, 4, 0), "id_aa64pfr0_el1" },
39 { KEY(3, 0, 0, 4, 1), "id_aa64pfr1_el1" },
40 { KEY(3, 0, 0, 6, 0), "id_aa64isar0_el1" },
41 { KEY(3, 0, 0, 6, 1), "id_aa64isar1_el1" },
42 { KEY(3, 0, 0, 7, 0), "id_aa64mmfr0_el1" },
43 { KEY(3, 0, 0, 7, 1), "id_aa64mmfr1_el1" },
44 { KEY(3, 1, 0, 0, 1), "clidr_el1" },
45 { KEY(3, 2, 0, 0, 0), "csselr_el1" },
46 { KEY(3, 3, 0, 0, 1), "ctr_el0" },
47 { KEY(3, 3, 0, 0, 7), "dczid_el0" },
48 { KEY(3, 0, 1, 0, 0), "sctlr_el1" },
49 { KEY(3, 0, 1, 0, 1), "actlr_el1" },
50 { KEY(3, 0, 1, 0, 2), "cpacr_el1" },
51 { KEY(3, 4, 1, 1, 0), "hcr_el2" },
52 { KEY(3, 6, 1, 1, 0), "scr_el3" },
53 { KEY(3, 0, 2, 0, 0), "ttbr0_el1" },
54 { KEY(3, 0, 2, 0, 1), "ttbr1_el1" },
55 { KEY(3, 0, 2, 0, 2), "tcr_el1" },
56 { KEY(3, 4, 2, 1, 0), "vttbr_el2" },
57 { KEY(3, 3, 9, 12, 0), "pmcr_el0" },
58 { KEY(3, 0, 10, 2, 0), "mair_el1" },
59 { KEY(3, 0, 12, 0, 0), "vbar_el1" },
60 { KEY(3, 0, 12, 0, 1), "rvbar_el1" },
61 { KEY(3, 0, 13, 0, 1), "contextidr_el1" },
62 { KEY(3, 0, 13, 0, 4), "tpidr_el1" },
63 { KEY(3, 3, 13, 0, 3), "tpidrro_el0" },
64 { KEY(3, 0, 14, 1, 0), "cntkctl_el1" },
65 { KEY(3, 3, 14, 3, 0), "cntv_tval_el0" },
66 { KEY(3, 3, 14, 3, 1), "cntv_ctl_el0" },
67 { KEY(3, 3, 14, 3, 2), "cntv_cval_el0" },
68 { KEY(2, 0, 0, 2, 2), "mdscr_el1" },
69};
70
71const char *sysreg_key_name(uint64_t key)
72{
73 for (uint32_t i = 0; i < HV_ARRAY_SIZE(g_names); i++) {
74 if (g_names[i].key == key) {
75 return g_names[i].name;
76 }
77 }
78 return "unknown";
79}
80
81bool sysreg_selftest(void)
82{
83 struct sysreg_access a;
84 uint64_t iss = (3ull << 20u) | (0ull << 17u) | (0ull << 14u) |
85 (0ull << 10u) | (0ull << 5u) | (0ull << 1u) | 1ull;
86 if (!sysreg_decode_from_esr_iss(iss, &a)) {
87 return false;
88 }
89 return a.is_read && a.rt == 0u && a.key == KEY(3, 0, 0, 0, 0);
90}