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