arch
core
drivers
guest
include
mm
scripts
tests
tools
···
1
1
+
build/
2
2
+
build-host/
3
3
+
build-linux/
4
4
+
dist/
···
1
1
+
PROJECT := ariel
2
2
+
TARGET := aarch64-none-elf
3
3
+
BUILD := build
4
4
+
HV_ELF := $(BUILD)/hypervisor.elf
5
5
+
HV_BIN := $(BUILD)/hypervisor.bin
6
6
+
GUEST_ELF := $(BUILD)/guest/diag.elf
7
7
+
GUEST_BIN := $(BUILD)/guest/diag.bin
8
8
+
MAP := $(BUILD)/hypervisor.map
9
9
+
OBJDUMP := $(BUILD)/hypervisor.objdump
10
10
+
READELF := $(BUILD)/hypervisor.readelf
11
11
+
DIST := dist
12
12
+
RELEASE_DIR := $(DIST)/$(PROJECT)-qemu-virt-aarch64
13
13
+
RELEASE_TAR := $(DIST)/$(PROJECT)-qemu-virt-aarch64.tar.gz
14
14
+
15
15
+
CC := clang
16
16
+
LD := ld.lld
17
17
+
OBJCOPY := llvm-objcopy
18
18
+
OBJDUMP_TOOL := llvm-objdump
19
19
+
READELF_TOOL := llvm-readelf
20
20
+
PYTHON ?= python3
21
21
+
QEMU ?= qemu-system-aarch64
22
22
+
QEMU_RAM ?= 1G
23
23
+
comma := ,
24
24
+
LINUX_DIR ?= /tmp/ariel-linux
25
25
+
LINUX_IMAGE_URL ?= http://deb.debian.org/debian/dists/bookworm/main/installer-arm64/current/images/netboot/debian-installer/arm64/linux
26
26
+
LINUX_INITRD_URL ?= http://deb.debian.org/debian/dists/bookworm/main/installer-arm64/current/images/netboot/debian-installer/arm64/initrd.gz
27
27
+
LINUX_INITRD_BYTES := $(if $(LINUX_INITRD),$(shell stat -c %s "$(LINUX_INITRD)" 2>/dev/null),)
28
28
+
LINUX_INITRD_SIZE := $(if $(LINUX_INITRD),$(if $(LINUX_INITRD_BYTES),$(LINUX_INITRD_BYTES),0),0)
29
29
+
LINUX_INITRD_DEVICE := $(if $(LINUX_INITRD),-device loader$(comma)file=$(LINUX_INITRD)$(comma)addr=0x46000000$(comma)force-raw=on,)
30
30
+
31
31
+
COMMON_CFLAGS := --target=$(TARGET) -std=c11 -ffreestanding -fno-builtin \
32
32
+
-fno-stack-protector -fno-unwind-tables -fno-asynchronous-unwind-tables \
33
33
+
-fno-exceptions -mgeneral-regs-only -mstrict-align -Wall -Wextra -Werror \
34
34
+
-Wconversion -Wsign-conversion -Wmissing-prototypes -Wstrict-prototypes \
35
35
+
-Iinclude -I.
36
36
+
EXTRA_CFLAGS ?=
37
37
+
HV_CFLAGS := $(COMMON_CFLAGS) -O2 -g -D__HYPERVISOR__ $(EXTRA_CFLAGS)
38
38
+
GUEST_CFLAGS := $(COMMON_CFLAGS) -O2 -g -D__GUEST__
39
39
+
ASFLAGS := --target=$(TARGET) -g -Iinclude -I.
40
40
+
LDFLAGS := -nostdlib -static --fatal-warnings
41
41
+
42
42
+
HV_C_SRCS := \
43
43
+
arch/aarch64/arch.c \
44
44
+
core/main.c core/el2_mmu.c core/fdt.c core/guest_loader.c core/log.c core/mmio_policy.c core/panic.c core/policy.c core/psci.c core/selftest.c \
45
45
+
core/string.c core/sysreg.c core/trap.c core/vcpu.c core/monitor.c \
46
46
+
drivers/gicv3.c drivers/pl011.c drivers/timer.c \
47
47
+
mm/allocator.c mm/stage2.c
48
48
+
HV_S_SRCS := arch/aarch64/entry.S arch/aarch64/vectors.S arch/aarch64/vcpu.S arch/aarch64/guest_blob.S
49
49
+
GUEST_C_SRCS := guest/main.c
50
50
+
GUEST_S_SRCS := guest/start.S
51
51
+
52
52
+
HV_OBJS := $(HV_C_SRCS:%.c=$(BUILD)/%.o) $(HV_S_SRCS:%.S=$(BUILD)/%.o)
53
53
+
GUEST_OBJS := $(GUEST_C_SRCS:%.c=$(BUILD)/%.o) $(GUEST_S_SRCS:%.S=$(BUILD)/%.o)
54
54
+
55
55
+
.PHONY: all clean run run-linux linux-artifacts test-linux-smoke test-diagnostic-smoke test-host test ci release debug objdump readelf
56
56
+
all: $(HV_ELF) $(HV_BIN) $(OBJDUMP) $(READELF)
57
57
+
58
58
+
$(BUILD):
59
59
+
mkdir -p $(BUILD)
60
60
+
61
61
+
$(BUILD)/guest/%.o: guest/%.c
62
62
+
mkdir -p $(dir $@)
63
63
+
$(CC) $(GUEST_CFLAGS) -c $< -o $@
64
64
+
65
65
+
$(BUILD)/%.o: %.c
66
66
+
mkdir -p $(dir $@)
67
67
+
$(CC) $(HV_CFLAGS) -c $< -o $@
68
68
+
69
69
+
$(BUILD)/%.o: %.S
70
70
+
mkdir -p $(dir $@)
71
71
+
$(CC) $(ASFLAGS) -c $< -o $@
72
72
+
73
73
+
$(BUILD)/arch/aarch64/guest_blob.o: arch/aarch64/guest_blob.S $(GUEST_BIN)
74
74
+
mkdir -p $(dir $@)
75
75
+
$(CC) $(ASFLAGS) -c $< -o $@
76
76
+
77
77
+
$(GUEST_ELF): $(GUEST_OBJS) guest/linker.ld
78
78
+
mkdir -p $(dir $@)
79
79
+
$(LD) $(LDFLAGS) -T guest/linker.ld $(GUEST_OBJS) -o $@
80
80
+
81
81
+
$(GUEST_BIN): $(GUEST_ELF)
82
82
+
$(OBJCOPY) -O binary $< $@
83
83
+
84
84
+
$(HV_ELF): $(HV_OBJS) linker.ld
85
85
+
mkdir -p $(dir $@)
86
86
+
$(LD) $(LDFLAGS) -T linker.ld -Map=$(MAP) $(HV_OBJS) -o $@
87
87
+
88
88
+
$(HV_BIN): $(HV_ELF)
89
89
+
$(OBJCOPY) -O binary $< $@
90
90
+
91
91
+
$(OBJDUMP): $(HV_ELF)
92
92
+
$(OBJDUMP_TOOL) -d -S $< > $@
93
93
+
94
94
+
$(READELF): $(HV_ELF)
95
95
+
$(READELF_TOOL) -a $< > $@
96
96
+
97
97
+
run: $(HV_ELF)
98
98
+
$(QEMU) -M virt,virtualization=on,gic-version=3 -cpu cortex-a57 -m $(QEMU_RAM) \
99
99
+
-nographic -serial mon:stdio -kernel $(HV_ELF)
100
100
+
101
101
+
run-linux:
102
102
+
@if [ -z "$(LINUX_IMAGE)" ] || [ -z "$(LINUX_DTB)" ]; then \
103
103
+
echo "usage: make run-linux LINUX_IMAGE=/path/Image LINUX_DTB=/path/qemu-virt.dtb [LINUX_INITRD=/path/initrd]"; \
104
104
+
echo "builds a Linux-profile hypervisor and loads Image+DTB into guest RAM"; \
105
105
+
else \
106
106
+
$(MAKE) -B BUILD=build-linux EXTRA_CFLAGS="-DCONFIG_BOOT_LINUX=1 -DCONFIG_LINUX_INITRD_SIZE=$(LINUX_INITRD_SIZE)ull" all && \
107
107
+
$(QEMU) -M virt,virtualization=on,gic-version=3 -cpu cortex-a57 -m $(QEMU_RAM) \
108
108
+
-nographic -serial mon:stdio -kernel build-linux/hypervisor.elf \
109
109
+
-device loader,file=$(LINUX_IMAGE),addr=0x42000000,force-raw=on \
110
110
+
-device loader,file=$(LINUX_DTB),addr=0x71e00000,force-raw=on \
111
111
+
$(LINUX_INITRD_DEVICE); \
112
112
+
fi
113
113
+
114
114
+
linux-artifacts:
115
115
+
mkdir -p $(LINUX_DIR)
116
116
+
$(QEMU) -M virt,virtualization=on,gic-version=3,dumpdtb=$(LINUX_DIR)/virt.dtb -cpu cortex-a57 -m $(QEMU_RAM) -nographic
117
117
+
curl -L --fail --show-error --output $(LINUX_DIR)/debian-arm64-linux $(LINUX_IMAGE_URL)
118
118
+
curl -L --fail --show-error --output $(LINUX_DIR)/debian-arm64-initrd.gz $(LINUX_INITRD_URL)
119
119
+
120
120
+
test-linux-smoke: linux-artifacts
121
121
+
bash -o pipefail -c 'timeout 180s $(MAKE) run-linux LINUX_IMAGE=$(LINUX_DIR)/debian-arm64-linux LINUX_DTB=$(LINUX_DIR)/virt.dtb LINUX_INITRD=$(LINUX_DIR)/debian-arm64-initrd.gz 2>&1 | tee $(LINUX_DIR)/linux-smoke.log; status=$${PIPESTATUS[0]}; test $$status -eq 0 -o $$status -eq 124'
122
122
+
grep -q 'Booting Linux on physical CPU' $(LINUX_DIR)/linux-smoke.log
123
123
+
grep -q 'Kernel command line: console=ttyAMA0 earlycon' $(LINUX_DIR)/linux-smoke.log
124
124
+
grep -q 'CPU: All CPU(s) started at EL1' $(LINUX_DIR)/linux-smoke.log
125
125
+
grep -q 'Trying to unpack rootfs image as initramfs' $(LINUX_DIR)/linux-smoke.log
126
126
+
grep -q 'Freeing initrd memory' $(LINUX_DIR)/linux-smoke.log
127
127
+
grep -q 'Run /init as init process' $(LINUX_DIR)/linux-smoke.log
128
128
+
! grep -q 'Initramfs unpacking failed' $(LINUX_DIR)/linux-smoke.log
129
129
+
! grep -q 'Kernel panic' $(LINUX_DIR)/linux-smoke.log
130
130
+
131
131
+
test-diagnostic-smoke: $(HV_ELF)
132
132
+
bash -o pipefail -c 'printf "status\n" | timeout 14s $(MAKE) run 2>&1 | tee $(BUILD)/diagnostic-smoke.log; status=$${PIPESTATUS[1]}; test $$status -eq 0 -o $$status -eq 124'
133
133
+
grep -q 'ariel qemu-virt-aarch64' $(BUILD)/diagnostic-smoke.log
134
134
+
grep -q 'guest: diagnostic guest: requested hv id' $(BUILD)/diagnostic-smoke.log
135
135
+
grep -q 'monitor entered reason=guest requested pause' $(BUILD)/diagnostic-smoke.log
136
136
+
! grep -q 'panic:' $(BUILD)/diagnostic-smoke.log
137
137
+
138
138
+
test-host:
139
139
+
mkdir -p build-host
140
140
+
$(CC) -std=c11 -Wall -Wextra -Werror -Iinclude tests/host/test_hv_types.c -o build-host/test_hv_types
141
141
+
build-host/test_hv_types
142
142
+
$(PYTHON) tests/test_log_decode.py
143
143
+
$(PYTHON) scripts/check_release.py
144
144
+
145
145
+
test: all test-host test-diagnostic-smoke
146
146
+
147
147
+
ci: clean release
148
148
+
149
149
+
release: test
150
150
+
scripts/release.sh
151
151
+
152
152
+
debug: $(HV_ELF)
153
153
+
@echo "gdb command: gdb-multiarch $(HV_ELF) -ex 'target remote :1234'"
154
154
+
$(QEMU) -M virt,virtualization=on,gic-version=3 -cpu cortex-a57 -m $(QEMU_RAM) \
155
155
+
-nographic -serial mon:stdio -S -gdb tcp::1234 -kernel $(HV_ELF)
156
156
+
157
157
+
objdump: $(OBJDUMP)
158
158
+
readelf: $(READELF)
159
159
+
160
160
+
clean:
161
161
+
rm -rf $(BUILD)
···
1
1
+
# ariel
2
2
+
3
3
+
AArch64 EL2 hypervisor for QEMU virt that boots at EL2, sets up exception vectors, writes a stage 2 guest IPA space and loads a bundled EL1 diagnostic guest/an external linux image and traps privileged guest activity as well as applying compiled policy tables and exposes a UART monitor over QEMU stdio
4
4
+
5
5
+
## Build/Run
6
6
+
7
7
+
```sh
8
8
+
make clean
9
9
+
make
10
10
+
```
11
11
+
12
12
+
```sh
13
13
+
make run
14
14
+
```
15
15
+
16
16
+
Equivalent QEMU shape
17
17
+
18
18
+
```sh
19
19
+
qemu-system-aarch64 \
20
20
+
-M virt,virtualization=on,gic-version=3 \
21
21
+
-cpu cortex-a57 \
22
22
+
-m 1G \
23
23
+
-nographic \
24
24
+
-serial mon:stdio \
25
25
+
-kernel build/hypervisor.elf
26
26
+
```
27
27
+
28
28
+
Run a Linux arm64 `Image` with a QEMU `virt` DTB
29
29
+
30
30
+
```sh
31
31
+
make run-linux \
32
32
+
LINUX_IMAGE=/path/Image \
33
33
+
LINUX_DTB=/path/qemu-virt.dtb
34
34
+
```
35
35
+
36
36
+
Or just do it with an initrd
37
37
+
38
38
+
```sh
39
39
+
make run-linux \
40
40
+
LINUX_IMAGE=/path/Image \
41
41
+
LINUX_DTB=/path/qemu-virt.dtb \
42
42
+
LINUX_INITRD=/path/initrd.gz
43
43
+
```
44
44
+
45
45
+
Fetch the tested Debian installer artifacts and smoke test the Linux path
46
46
+
47
47
+
```sh
48
48
+
make test-linux-smoke
49
49
+
```
50
50
+
and complete the local gate
51
51
+
52
52
+
```sh
53
53
+
make test
54
54
+
make release
55
55
+
```
56
56
+
57
57
+
## Memory
58
58
+
59
59
+
```text
60
60
+
hypervisor link PA 0x40080000
61
61
+
guest IPA base 0x40000000
62
62
+
guest backing PA 0x42000000
63
63
+
guest RAM size 0x30000000 768 MiB
64
64
+
diagnostic entry IPA 0x40000000
65
65
+
diagnostic stack top 0x40100000
66
66
+
Linux Image load PA 0x42000000
67
67
+
Linux Image entry IPA Image text_offset + 0x40000000
68
68
+
Linux initrd PA 0x46000000
69
69
+
Linux initrd IPA 0x44000000
70
70
+
Linux DTB PA 0x71e00000
71
71
+
Linux DTB IPA 0x6fe00000
72
72
+
PL011 UART PA 0x09000000
73
73
+
GICD PA 0x08000000
74
74
+
GICR PA 0x080a0000
75
75
+
```
76
76
+
77
77
+
S2 uses 2 MiB block mappings for guest RAM. The guest sees the IPA range `0x40000000..0x70000000` which EL2 maps onto the PA range `0x42000000..0x72000000`. MMIO isn't passed through by default andkKnown device ranges are handled through policy or emulation layers
78
78
+
79
79
+
## Trap Path
80
80
+
81
81
+
EL1 traps enter the EL2 vector table and the assembly path saves general registers and exception state into `struct trap_frame`
82
82
+
83
83
+
```text
84
84
+
x0-x30
85
85
+
sp_el0
86
86
+
sp_el1
87
87
+
elr_el2
88
88
+
spsr_el2
89
89
+
esr_el2
90
90
+
far_el2
91
91
+
hpfar_el2
92
92
+
```
93
93
+
94
94
+
## Hypercalls
95
95
+
96
96
+
97
97
+
```c
98
98
+
enum {
99
99
+
HVC_GET_HV_ID = 0,
100
100
+
HVC_DUMP_LOG = 1,
101
101
+
HVC_GET_STATUS = 2,
102
102
+
HVC_PAUSE = 3,
103
103
+
HVC_GUEST_CONSOLE_WRITE = 4,
104
104
+
HVC_REPORT_EXCEPTION = 5,
105
105
+
};
106
106
+
```
107
107
+
108
108
+
Guest side call pattern
109
109
+
110
110
+
```c
111
111
+
static inline unsigned long hvc(unsigned long op,
112
112
+
unsigned long a1,
113
113
+
unsigned long a2,
114
114
+
unsigned long a3)
115
115
+
{
116
116
+
register unsigned long x0 asm("x0") = op;
117
117
+
register unsigned long x1 asm("x1") = a1;
118
118
+
register unsigned long x2 asm("x2") = a2;
119
119
+
register unsigned long x3 asm("x3") = a3;
120
120
+
121
121
+
asm volatile("hvc #0"
122
122
+
: "+r"(x0)
123
123
+
: "r"(x1), "r"(x2), "r"(x3)
124
124
+
: "memory");
125
125
+
return x0;
126
126
+
}
127
127
+
```
128
128
+
129
129
+
Console write from guest IPA memory
130
130
+
131
131
+
```c
132
132
+
const char msg[] = "guest online";
133
133
+
hvc(HVC_GUEST_CONSOLE_WRITE, (unsigned long)msg, sizeof(msg) - 1, 0);
134
134
+
```
135
135
+
136
136
+
Pause into the EL2 monitor:
137
137
+
138
138
+
```c
139
139
+
hvc(HVC_PAUSE, 0, 0, 0);
140
140
+
```
141
141
+
142
142
+
## Logs
143
143
+
144
144
+
```sh
145
145
+
make run 2>&1 | tee uart.log
146
146
+
python3 tools/log_decode.py --summary < uart.log
147
147
+
```
···
1
1
+
#include "hv/arch.h"
2
2
+
#include "hv/config.h"
3
3
+
#include "hv/mmio.h"
4
4
+
#include "hv/panic.h"
5
5
+
#include "hv/uart.h"
6
6
+
#include "hv/vcpu.h"
7
7
+
8
8
+
uint64_t arch_current_el(void)
9
9
+
{
10
10
+
uint64_t v;
11
11
+
__asm__ volatile("mrs %0, CurrentEL" : "=r"(v));
12
12
+
return (v >> 2u) & 0x3u;
13
13
+
}
14
14
+
15
15
+
uint64_t arch_mpidr_el1(void)
16
16
+
{
17
17
+
uint64_t v;
18
18
+
__asm__ volatile("mrs %0, mpidr_el1" : "=r"(v));
19
19
+
return v;
20
20
+
}
21
21
+
22
22
+
uint64_t arch_cntpct_el0(void)
23
23
+
{
24
24
+
uint64_t v;
25
25
+
__asm__ volatile("mrs %0, cntpct_el0" : "=r"(v));
26
26
+
return v;
27
27
+
}
28
28
+
29
29
+
uint64_t arch_cntfrq_el0(void)
30
30
+
{
31
31
+
uint64_t v;
32
32
+
__asm__ volatile("mrs %0, cntfrq_el0" : "=r"(v));
33
33
+
return v;
34
34
+
}
35
35
+
36
36
+
uint64_t arch_irq_save(void)
37
37
+
{
38
38
+
uint64_t flags;
39
39
+
__asm__ volatile("mrs %0, daif\nmsr daifset, #0xf\nisb" : "=r"(flags) :: "memory");
40
40
+
return flags;
41
41
+
}
42
42
+
43
43
+
void arch_irq_restore(uint64_t flags)
44
44
+
{
45
45
+
__asm__ volatile("msr daif, %0\nisb" :: "r"(flags) : "memory");
46
46
+
}
47
47
+
48
48
+
void arch_dump_el2_state(void)
49
49
+
{
50
50
+
uint64_t current_el;
51
51
+
uint64_t hcr;
52
52
+
uint64_t vtcr;
53
53
+
uint64_t vttbr;
54
54
+
uint64_t vbar;
55
55
+
uint64_t sctlr;
56
56
+
uint64_t mair;
57
57
+
uint64_t sp;
58
58
+
59
59
+
__asm__ volatile(
60
60
+
"mrs %0, CurrentEL\n"
61
61
+
"mrs %1, hcr_el2\n"
62
62
+
"mrs %2, vtcr_el2\n"
63
63
+
"mrs %3, vttbr_el2\n"
64
64
+
"mrs %4, vbar_el2\n"
65
65
+
"mrs %5, sctlr_el2\n"
66
66
+
"mrs %6, mair_el2\n"
67
67
+
"mov %7, sp\n"
68
68
+
: "=r"(current_el), "=r"(hcr), "=r"(vtcr), "=r"(vttbr),
69
69
+
"=r"(vbar), "=r"(sctlr), "=r"(mair), "=r"(sp));
70
70
+
71
71
+
uart_puts("cpu current_el=");
72
72
+
uart_put_hex64(current_el);
73
73
+
uart_puts(" hcr_el2=");
74
74
+
uart_put_hex64(hcr);
75
75
+
uart_puts(" vtcr_el2=");
76
76
+
uart_put_hex64(vtcr);
77
77
+
uart_puts(" vttbr_el2=");
78
78
+
uart_put_hex64(vttbr);
79
79
+
uart_puts("\n");
80
80
+
uart_puts("cpu vbar_el2=");
81
81
+
uart_put_hex64(vbar);
82
82
+
uart_puts(" sctlr_el2=");
83
83
+
uart_put_hex64(sctlr);
84
84
+
uart_puts(" mair_el2=");
85
85
+
uart_put_hex64(mair);
86
86
+
uart_puts(" sp=");
87
87
+
uart_put_hex64(sp);
88
88
+
uart_puts("\n");
89
89
+
}
90
90
+
91
91
+
void arch_install_vectors(void)
92
92
+
{
93
93
+
if (!hv_is_aligned_u64((uint64_t)(uintptr_t)__vectors_el2, 2048u)) {
94
94
+
panic("VBAR_EL2 vector table is not 2KB aligned");
95
95
+
}
96
96
+
__asm__ volatile("msr vbar_el2, %0\nisb" :: "r"(__vectors_el2) : "memory");
97
97
+
}
98
98
+
99
99
+
void arch_tlbi_vmalle1is(void)
100
100
+
{
101
101
+
__asm__ volatile("dsb ish\n tlbi vmalle1is\n dsb ish\n isb" ::: "memory");
102
102
+
}
103
103
+
104
104
+
void arch_enable_el2_mmu(uint64_t ttbr0, uint64_t tcr, uint64_t mair)
105
105
+
{
106
106
+
uint64_t sctlr;
107
107
+
108
108
+
__asm__ volatile(
109
109
+
"dsb sy\n"
110
110
+
"msr ttbr0_el2, %0\n"
111
111
+
"msr tcr_el2, %1\n"
112
112
+
"msr mair_el2, %2\n"
113
113
+
"isb\n"
114
114
+
"tlbi alle2\n"
115
115
+
"dsb sy\n"
116
116
+
"isb\n"
117
117
+
:: "r"(ttbr0), "r"(tcr), "r"(mair)
118
118
+
: "memory");
119
119
+
120
120
+
__asm__ volatile("mrs %0, sctlr_el2" : "=r"(sctlr));
121
121
+
sctlr |= HV_BIT(0) | HV_BIT(2) | HV_BIT(12);
122
122
+
__asm__ volatile(
123
123
+
"msr sctlr_el2, %0\n"
124
124
+
"isb\n"
125
125
+
:: "r"(sctlr)
126
126
+
: "memory");
127
127
+
}
128
128
+
129
129
+
void arch_el2_configure(uint64_t vttbr, uint64_t vtcr)
130
130
+
{
131
131
+
const uint64_t mair = 0x000000000000ff00ull | 0x0000000000000004ull;
132
132
+
uint64_t hcr = 0;
133
133
+
134
134
+
hcr |= HV_BIT(31);
135
135
+
hcr |= HV_BIT(0);
136
136
+
#if !CONFIG_BOOT_LINUX
137
137
+
hcr |= HV_BIT(26);
138
138
+
#endif
139
139
+
hcr |= HV_BIT(22);
140
140
+
hcr |= HV_BIT(21);
141
141
+
hcr |= HV_BIT(19);
142
142
+
#if !CONFIG_BOOT_LINUX
143
143
+
hcr |= HV_BIT(20);
144
144
+
hcr |= HV_BIT(18) | HV_BIT(17) | HV_BIT(16) | HV_BIT(15);
145
145
+
#endif
146
146
+
#if CONFIG_ENABLE_WFI_TRAPS
147
147
+
hcr |= HV_BIT(14) | HV_BIT(13);
148
148
+
#endif
149
149
+
150
150
+
__asm__ volatile(
151
151
+
"msr mair_el2, %0\n"
152
152
+
"msr vtcr_el2, %1\n"
153
153
+
"msr vttbr_el2, %2\n"
154
154
+
"msr mdcr_el2, %3\n"
155
155
+
"msr cptr_el2, %4\n"
156
156
+
"msr cnthctl_el2, %5\n"
157
157
+
"msr hcr_el2, %6\n"
158
158
+
"isb\n"
159
159
+
:: "r"(mair), "r"(vtcr), "r"(vttbr),
160
160
+
"r"(0ull), "r"(0x33ffull), "r"(3ull), "r"(hcr)
161
161
+
: "memory");
162
162
+
}
163
163
+
164
164
+
void arch_prepare_guest_entry(struct vcpu *vcpu)
165
165
+
{
166
166
+
BUG_ON(vcpu == (struct vcpu *)0);
167
167
+
__asm__ volatile(
168
168
+
"msr sctlr_el1, %0\n"
169
169
+
"msr ttbr0_el1, %1\n"
170
170
+
"msr ttbr1_el1, %2\n"
171
171
+
"msr tcr_el1, %3\n"
172
172
+
"msr mair_el1, %4\n"
173
173
+
"msr vbar_el1, %5\n"
174
174
+
"msr cntkctl_el1, %6\n"
175
175
+
"isb\n"
176
176
+
:: "r"(vcpu->sysregs.sctlr_el1), "r"(vcpu->sysregs.ttbr0_el1),
177
177
+
"r"(vcpu->sysregs.ttbr1_el1), "r"(vcpu->sysregs.tcr_el1),
178
178
+
"r"(vcpu->sysregs.mair_el1), "r"(vcpu->sysregs.vbar_el1),
179
179
+
"r"(vcpu->sysregs.cntkctl_el1)
180
180
+
: "memory");
181
181
+
}
182
182
+
183
183
+
void arch_capture_el1_sysregs(struct vcpu *vcpu)
184
184
+
{
185
185
+
BUG_ON(vcpu == (struct vcpu *)0);
186
186
+
__asm__ volatile(
187
187
+
"mrs %0, vbar_el1\n"
188
188
+
"mrs %1, elr_el1\n"
189
189
+
"mrs %2, spsr_el1\n"
190
190
+
"mrs %3, esr_el1\n"
191
191
+
"mrs %4, far_el1\n"
192
192
+
: "=r"(vcpu->sysregs.vbar_el1), "=r"(vcpu->sysregs.elr_el1),
193
193
+
"=r"(vcpu->sysregs.spsr_el1), "=r"(vcpu->sysregs.esr_el1),
194
194
+
"=r"(vcpu->sysregs.far_el1));
195
195
+
}
196
196
+
197
197
+
void arch_sync_el1_sysregs(const struct vcpu *vcpu)
198
198
+
{
199
199
+
BUG_ON(vcpu == (const struct vcpu *)0);
200
200
+
__asm__ volatile(
201
201
+
"dsb sy\n"
202
202
+
"msr mair_el1, %0\n"
203
203
+
"msr tcr_el1, %1\n"
204
204
+
"msr ttbr0_el1, %2\n"
205
205
+
"msr ttbr1_el1, %3\n"
206
206
+
"msr vbar_el1, %4\n"
207
207
+
"msr cntkctl_el1, %5\n"
208
208
+
"msr cpacr_el1, %6\n"
209
209
+
"isb\n"
210
210
+
"msr sctlr_el1, %7\n"
211
211
+
"isb\n"
212
212
+
:: "r"(vcpu->sysregs.mair_el1), "r"(vcpu->sysregs.tcr_el1),
213
213
+
"r"(vcpu->sysregs.ttbr0_el1), "r"(vcpu->sysregs.ttbr1_el1),
214
214
+
"r"(vcpu->sysregs.vbar_el1), "r"(vcpu->sysregs.cntkctl_el1),
215
215
+
"r"(vcpu->sysregs.cpacr_el1), "r"(vcpu->sysregs.sctlr_el1)
216
216
+
: "memory");
217
217
+
}
218
218
+
219
219
+
void arch_advance_guest_pc(struct vcpu *vcpu)
220
220
+
{
221
221
+
BUG_ON(vcpu == (struct vcpu *)0);
222
222
+
vcpu->pc += 4u;
223
223
+
}
224
224
+
225
225
+
void arch_inject_guest_undef(struct vcpu *vcpu)
226
226
+
{
227
227
+
const uint64_t current_el_spx_sync = 0x200u;
228
228
+
const uint64_t pstate_el1h_daif = 0x3c5u;
229
229
+
230
230
+
BUG_ON(vcpu == (struct vcpu *)0);
231
231
+
arch_capture_el1_sysregs(vcpu);
232
232
+
if (!hv_is_aligned_u64(vcpu->sysregs.vbar_el1, 2048u)) {
233
233
+
vcpu->state = VCPU_PAUSED;
234
234
+
return;
235
235
+
}
236
236
+
237
237
+
vcpu->sysregs.elr_el1 = vcpu->pc;
238
238
+
vcpu->sysregs.spsr_el1 = vcpu->pstate;
239
239
+
vcpu->sysregs.esr_el1 = 0u;
240
240
+
vcpu->sysregs.far_el1 = 0u;
241
241
+
vcpu->pc = vcpu->sysregs.vbar_el1 + current_el_spx_sync;
242
242
+
vcpu->pstate = pstate_el1h_daif;
243
243
+
vcpu->stats.injected_undefs++;
244
244
+
245
245
+
__asm__ volatile(
246
246
+
"msr elr_el1, %0\n"
247
247
+
"msr spsr_el1, %1\n"
248
248
+
"msr esr_el1, %2\n"
249
249
+
"msr far_el1, %3\n"
250
250
+
"isb\n"
251
251
+
:: "r"(vcpu->sysregs.elr_el1), "r"(vcpu->sysregs.spsr_el1),
252
252
+
"r"(vcpu->sysregs.esr_el1), "r"(vcpu->sysregs.far_el1)
253
253
+
: "memory");
254
254
+
}
255
255
+
256
256
+
void arch_halt(void)
257
257
+
{
258
258
+
for (;;) {
259
259
+
__asm__ volatile("wfe");
260
260
+
}
261
261
+
}
···
1
1
+
.section .text.entry, "ax"
2
2
+
.global _start
3
3
+
.type _start, %function
4
4
+
_start:
5
5
+
mov x19, x0
6
6
+
mrs x0, mpidr_el1
7
7
+
and x0, x0, #0xff
8
8
+
cbz x0, 1f
9
9
+
0: wfe
10
10
+
b 0b
11
11
+
12
12
+
1: ldr x0, =__boot_stack_top
13
13
+
mov sp, x0
14
14
+
ldr x0, =__bss_start
15
15
+
ldr x1, =__bss_end
16
16
+
2: cmp x0, x1
17
17
+
b.hs 3f
18
18
+
str xzr, [x0], #8
19
19
+
b 2b
20
20
+
3: mov x0, x19
21
21
+
bl hv_main
22
22
+
4: wfe
23
23
+
b 4b
24
24
+
25
25
+
.section .bss.stack, "aw", %nobits
26
26
+
.align 12
27
27
+
__boot_stack:
28
28
+
.skip 0x10000
29
29
+
__boot_stack_top:
···
1
1
+
.section .rodata.guest, "a"
2
2
+
.balign 16
3
3
+
.global __guest_image_start
4
4
+
__guest_image_start:
5
5
+
.incbin "build/guest/diag.bin"
6
6
+
.global __guest_image_end
7
7
+
__guest_image_end:
8
8
+
.balign 16
···
1
1
+
.section .text, "ax"
2
2
+
.global arch_vcpu_enter
3
3
+
.type arch_vcpu_enter, %function
4
4
+
arch_vcpu_enter:
5
5
+
msr daifset, #0xf
6
6
+
mov x30, x0
7
7
+
ldr x1, [x30, #248]
8
8
+
msr sp_el0, x1
9
9
+
ldr x1, [x30, #256]
10
10
+
msr sp_el1, x1
11
11
+
ldr x1, [x30, #264]
12
12
+
msr elr_el2, x1
13
13
+
ldr x1, [x30, #272]
14
14
+
msr spsr_el2, x1
15
15
+
ldp x0, x1, [x30, #0]
16
16
+
ldp x2, x3, [x30, #16]
17
17
+
ldp x4, x5, [x30, #32]
18
18
+
ldp x6, x7, [x30, #48]
19
19
+
ldp x8, x9, [x30, #64]
20
20
+
ldp x10, x11, [x30, #80]
21
21
+
ldp x12, x13, [x30, #96]
22
22
+
ldp x14, x15, [x30, #112]
23
23
+
ldp x16, x17, [x30, #128]
24
24
+
ldp x18, x19, [x30, #144]
25
25
+
ldp x20, x21, [x30, #160]
26
26
+
ldp x22, x23, [x30, #176]
27
27
+
ldp x24, x25, [x30, #192]
28
28
+
ldp x26, x27, [x30, #208]
29
29
+
ldp x28, x29, [x30, #224]
30
30
+
ldr x30, [x30, #240]
31
31
+
eret
···
1
1
+
.section .text.vectors, "ax"
2
2
+
.align 11
3
3
+
.global __vectors_el2
4
4
+
__vectors_el2:
5
5
+
b vector_current_sync
6
6
+
.org __vectors_el2 + 0x080
7
7
+
b vector_current_irq
8
8
+
.org __vectors_el2 + 0x100
9
9
+
b vector_current_fiq
10
10
+
.org __vectors_el2 + 0x180
11
11
+
b vector_current_serror
12
12
+
.org __vectors_el2 + 0x200
13
13
+
b vector_current_sync
14
14
+
.org __vectors_el2 + 0x280
15
15
+
b vector_current_irq
16
16
+
.org __vectors_el2 + 0x300
17
17
+
b vector_current_fiq
18
18
+
.org __vectors_el2 + 0x380
19
19
+
b vector_current_serror
20
20
+
.org __vectors_el2 + 0x400
21
21
+
b vector_lower_sync
22
22
+
.org __vectors_el2 + 0x480
23
23
+
b vector_lower_irq
24
24
+
.org __vectors_el2 + 0x500
25
25
+
b vector_lower_fiq
26
26
+
.org __vectors_el2 + 0x580
27
27
+
b vector_lower_serror
28
28
+
.org __vectors_el2 + 0x600
29
29
+
b vector_lower_sync
30
30
+
.org __vectors_el2 + 0x680
31
31
+
b vector_lower_irq
32
32
+
.org __vectors_el2 + 0x700
33
33
+
b vector_lower_fiq
34
34
+
.org __vectors_el2 + 0x780
35
35
+
b vector_lower_serror
36
36
+
37
37
+
.macro SAVE_FRAME
38
38
+
sub sp, sp, #304
39
39
+
stp x0, x1, [sp, #0]
40
40
+
stp x2, x3, [sp, #16]
41
41
+
stp x4, x5, [sp, #32]
42
42
+
stp x6, x7, [sp, #48]
43
43
+
stp x8, x9, [sp, #64]
44
44
+
stp x10, x11, [sp, #80]
45
45
+
stp x12, x13, [sp, #96]
46
46
+
stp x14, x15, [sp, #112]
47
47
+
stp x16, x17, [sp, #128]
48
48
+
stp x18, x19, [sp, #144]
49
49
+
stp x20, x21, [sp, #160]
50
50
+
stp x22, x23, [sp, #176]
51
51
+
stp x24, x25, [sp, #192]
52
52
+
stp x26, x27, [sp, #208]
53
53
+
stp x28, x29, [sp, #224]
54
54
+
str x30, [sp, #240]
55
55
+
mrs x1, sp_el0
56
56
+
str x1, [sp, #248]
57
57
+
mrs x1, sp_el1
58
58
+
str x1, [sp, #256]
59
59
+
mrs x1, elr_el2
60
60
+
str x1, [sp, #264]
61
61
+
mrs x1, spsr_el2
62
62
+
str x1, [sp, #272]
63
63
+
mrs x1, esr_el2
64
64
+
str x1, [sp, #280]
65
65
+
mrs x1, far_el2
66
66
+
str x1, [sp, #288]
67
67
+
mrs x1, hpfar_el2
68
68
+
str x1, [sp, #296]
69
69
+
.endm
70
70
+
71
71
+
.macro RESTORE_FRAME
72
72
+
ldr x1, [sp, #248]
73
73
+
msr sp_el0, x1
74
74
+
ldr x1, [sp, #256]
75
75
+
msr sp_el1, x1
76
76
+
ldr x1, [sp, #264]
77
77
+
msr elr_el2, x1
78
78
+
ldr x1, [sp, #272]
79
79
+
msr spsr_el2, x1
80
80
+
ldp x0, x1, [sp, #0]
81
81
+
ldp x2, x3, [sp, #16]
82
82
+
ldp x4, x5, [sp, #32]
83
83
+
ldp x6, x7, [sp, #48]
84
84
+
ldp x8, x9, [sp, #64]
85
85
+
ldp x10, x11, [sp, #80]
86
86
+
ldp x12, x13, [sp, #96]
87
87
+
ldp x14, x15, [sp, #112]
88
88
+
ldp x16, x17, [sp, #128]
89
89
+
ldp x18, x19, [sp, #144]
90
90
+
ldp x20, x21, [sp, #160]
91
91
+
ldp x22, x23, [sp, #176]
92
92
+
ldp x24, x25, [sp, #192]
93
93
+
ldp x26, x27, [sp, #208]
94
94
+
ldp x28, x29, [sp, #224]
95
95
+
ldr x30, [sp, #240]
96
96
+
add sp, sp, #304
97
97
+
.endm
98
98
+
99
99
+
vector_lower_sync:
100
100
+
SAVE_FRAME
101
101
+
mov x0, sp
102
102
+
bl trap_handle_lower_sync
103
103
+
RESTORE_FRAME
104
104
+
eret
105
105
+
106
106
+
vector_lower_irq:
107
107
+
vector_lower_fiq:
108
108
+
vector_lower_serror:
109
109
+
vector_current_irq:
110
110
+
vector_current_fiq:
111
111
+
vector_current_serror:
112
112
+
SAVE_FRAME
113
113
+
mov x0, sp
114
114
+
bl trap_handle_irq
115
115
+
RESTORE_FRAME
116
116
+
eret
117
117
+
118
118
+
vector_current_sync:
119
119
+
SAVE_FRAME
120
120
+
mov x0, sp
121
121
+
bl trap_handle_current_sync
122
122
+
RESTORE_FRAME
123
123
+
eret
···
1
1
+
#include "hv/arch.h"
2
2
+
#include "hv/config.h"
3
3
+
#include "hv/el2_mmu.h"
4
4
+
#include "hv/string.h"
5
5
+
#include "hv/uart.h"
6
6
+
7
7
+
#define EL2_PT_ENTRIES 512u
8
8
+
#define EL2_L1_SHIFT 30u
9
9
+
#define EL2_L2_SHIFT 21u
10
10
+
#define EL2_L2_SIZE (1ull << EL2_L2_SHIFT)
11
11
+
#define EL2_DESC_VALID HV_BIT(0)
12
12
+
#define EL2_DESC_TABLE HV_BIT(1)
13
13
+
#define EL2_DESC_AF HV_BIT(10)
14
14
+
#define EL2_DESC_SH_INNER (3ull << 8u)
15
15
+
#define EL2_DESC_ATTR_NORMAL (1ull << 2u)
16
16
+
#define EL2_DESC_ATTR_DEVICE (0ull << 2u)
17
17
+
#define EL2_DESC_PXN HV_BIT(53)
18
18
+
#define EL2_DESC_UXN HV_BIT(54)
19
19
+
#define EL2_MAIR ((0xffull << 8u) | 0x04ull)
20
20
+
21
21
+
static uint64_t g_el2_l1[EL2_PT_ENTRIES] __attribute__((aligned(4096)));
22
22
+
static uint64_t g_el2_l2[2][EL2_PT_ENTRIES] __attribute__((aligned(4096)));
23
23
+
static uint64_t g_guard_low;
24
24
+
static uint64_t g_guard_high;
25
25
+
static bool g_ready;
26
26
+
static bool g_enabled;
27
27
+
28
28
+
static uint64_t block_desc(uint64_t pa, bool device, bool executable)
29
29
+
{
30
30
+
uint64_t desc = (pa & 0x0000ffffffe00000ull) | EL2_DESC_VALID | EL2_DESC_AF;
31
31
+
desc |= device ? EL2_DESC_ATTR_DEVICE : (EL2_DESC_ATTR_NORMAL | EL2_DESC_SH_INNER);
32
32
+
if (!executable) {
33
33
+
desc |= EL2_DESC_PXN | EL2_DESC_UXN;
34
34
+
}
35
35
+
return desc;
36
36
+
}
37
37
+
38
38
+
static bool install_block(uint64_t pa, bool device, bool executable)
39
39
+
{
40
40
+
uint64_t l1 = (pa >> EL2_L1_SHIFT) & 0x1ffu;
41
41
+
uint64_t l2 = (pa >> EL2_L2_SHIFT) & 0x1ffu;
42
42
+
if (l1 >= HV_ARRAY_SIZE(g_el2_l2)) {
43
43
+
return false;
44
44
+
}
45
45
+
g_el2_l1[l1] = ((uint64_t)(uintptr_t)g_el2_l2[l1] & 0x0000fffffffff000ull) |
46
46
+
EL2_DESC_TABLE | EL2_DESC_VALID;
47
47
+
g_el2_l2[l1][l2] = block_desc(pa, device, executable);
48
48
+
return true;
49
49
+
}
50
50
+
51
51
+
void el2_mmu_init_plan(void)
52
52
+
{
53
53
+
uint64_t image_start = HV_ALIGN_DOWN((uint64_t)(uintptr_t)__image_start, EL2_L2_SIZE);
54
54
+
uint64_t image_end = HV_ALIGN_UP((uint64_t)(uintptr_t)__image_end, EL2_L2_SIZE);
55
55
+
56
56
+
hv_memset(g_el2_l1, 0, sizeof(g_el2_l1));
57
57
+
hv_memset(g_el2_l2, 0, sizeof(g_el2_l2));
58
58
+
g_guard_low = image_start >= EL2_L2_SIZE ? image_start - EL2_L2_SIZE : 0u;
59
59
+
g_guard_high = image_end;
60
60
+
g_ready = true;
61
61
+
g_enabled = false;
62
62
+
63
63
+
for (uint64_t pa = image_start; pa < image_end; pa += EL2_L2_SIZE) {
64
64
+
if (!install_block(pa, false, true)) {
65
65
+
g_ready = false;
66
66
+
}
67
67
+
}
68
68
+
for (uint64_t pa = CONFIG_GUEST_RAM_BASE;
69
69
+
pa < CONFIG_GUEST_RAM_BASE + CONFIG_GUEST_RAM_SIZE;
70
70
+
pa += EL2_L2_SIZE) {
71
71
+
if (!install_block(pa, false, false)) {
72
72
+
g_ready = false;
73
73
+
}
74
74
+
}
75
75
+
if (!install_block(CONFIG_UART_BASE, true, false) ||
76
76
+
!install_block(CONFIG_GICD_BASE, true, false) ||
77
77
+
!install_block(CONFIG_GICR_BASE, true, false) ||
78
78
+
!install_block(0x0a000000ull, true, false)) {
79
79
+
g_ready = false;
80
80
+
}
81
81
+
}
82
82
+
83
83
+
uint64_t el2_mmu_root(void)
84
84
+
{
85
85
+
return (uint64_t)(uintptr_t)g_el2_l1;
86
86
+
}
87
87
+
88
88
+
uint64_t el2_mmu_tcr(void)
89
89
+
{
90
90
+
uint64_t tcr = 0u;
91
91
+
tcr |= 25ull;
92
92
+
tcr |= (1ull << 8u);
93
93
+
tcr |= (1ull << 10u);
94
94
+
tcr |= (3ull << 12u);
95
95
+
tcr |= (2ull << 16u);
96
96
+
return tcr;
97
97
+
}
98
98
+
99
99
+
uint64_t el2_mmu_mair(void)
100
100
+
{
101
101
+
return EL2_MAIR;
102
102
+
}
103
103
+
104
104
+
void el2_mmu_enable(void)
105
105
+
{
106
106
+
if (!g_ready) {
107
107
+
return;
108
108
+
}
109
109
+
arch_enable_el2_mmu(el2_mmu_root(), el2_mmu_tcr(), el2_mmu_mair());
110
110
+
g_enabled = true;
111
111
+
}
112
112
+
113
113
+
void el2_mmu_dump(void)
114
114
+
{
115
115
+
uart_puts("el2mmu planned=");
116
116
+
uart_puts(g_ready ? "yes" : "no");
117
117
+
uart_puts(" enabled=");
118
118
+
uart_puts(g_enabled ? "yes" : "no");
119
119
+
uart_puts(" root=");
120
120
+
uart_put_hex64(el2_mmu_root());
121
121
+
uart_puts(" tcr=");
122
122
+
uart_put_hex64(el2_mmu_tcr());
123
123
+
uart_puts(" mair=");
124
124
+
uart_put_hex64(el2_mmu_mair());
125
125
+
uart_puts(" guard_low=");
126
126
+
uart_put_hex64(g_guard_low);
127
127
+
uart_puts(" guard_high=");
128
128
+
uart_put_hex64(g_guard_high);
129
129
+
uart_puts("\n");
130
130
+
}
131
131
+
132
132
+
bool el2_mmu_selftest(void)
133
133
+
{
134
134
+
return g_ready &&
135
135
+
g_enabled &&
136
136
+
hv_is_aligned_u64(el2_mmu_root(), CONFIG_PAGE_SIZE) &&
137
137
+
(g_guard_high == 0u || (g_guard_high & (EL2_L2_SIZE - 1u)) == 0u);
138
138
+
}
···
1
1
+
#include "hv/fdt.h"
2
2
+
#include "hv/string.h"
3
3
+
#include "hv/uart.h"
4
4
+
5
5
+
#define FDT_MAGIC 0xd00dfeedu
6
6
+
#define FDT_BEGIN_NODE 1u
7
7
+
#define FDT_END_NODE 2u
8
8
+
#define FDT_PROP 3u
9
9
+
#define FDT_NOP 4u
10
10
+
#define FDT_END 9u
11
11
+
#define FDT_MAX_SIZE 0x00200000u
12
12
+
#define FDT_MAX_DEPTH 16u
13
13
+
14
14
+
struct fdt_header_view {
15
15
+
uint32_t totalsize;
16
16
+
uint32_t off_dt_struct;
17
17
+
uint32_t off_dt_strings;
18
18
+
uint32_t size_dt_strings;
19
19
+
uint32_t size_dt_struct;
20
20
+
};
21
21
+
22
22
+
struct fdt_property_ref {
23
23
+
uint8_t *value;
24
24
+
uint32_t len;
25
25
+
};
26
26
+
27
27
+
static uint32_t be32(const void *ptr)
28
28
+
{
29
29
+
const uint8_t *p = (const uint8_t *)ptr;
30
30
+
return ((uint32_t)p[0] << 24u) | ((uint32_t)p[1] << 16u) |
31
31
+
((uint32_t)p[2] << 8u) | (uint32_t)p[3];
32
32
+
}
33
33
+
34
34
+
static uint64_t read_cells(const uint32_t *cells, uint32_t count)
35
35
+
{
36
36
+
uint64_t value = 0;
37
37
+
for (uint32_t i = 0; i < count; i++) {
38
38
+
value = (value << 32u) | (uint64_t)be32(&cells[i]);
39
39
+
}
40
40
+
return value;
41
41
+
}
42
42
+
43
43
+
static uint32_t align4_u32(uint32_t value)
44
44
+
{
45
45
+
return (value + 3u) & ~3u;
46
46
+
}
47
47
+
48
48
+
static const uint8_t *align4(const uint8_t *p)
49
49
+
{
50
50
+
uintptr_t v = (uintptr_t)p;
51
51
+
v = (v + 3u) & ~(uintptr_t)3u;
52
52
+
return (const uint8_t *)v;
53
53
+
}
54
54
+
55
55
+
static bool read_header(const uint8_t *fdt, struct fdt_header_view *h)
56
56
+
{
57
57
+
if (fdt == (const uint8_t *)0 || h == (struct fdt_header_view *)0) {
58
58
+
return false;
59
59
+
}
60
60
+
if (be32(fdt) != FDT_MAGIC) {
61
61
+
return false;
62
62
+
}
63
63
+
64
64
+
h->totalsize = be32(fdt + 4u);
65
65
+
h->off_dt_struct = be32(fdt + 8u);
66
66
+
h->off_dt_strings = be32(fdt + 12u);
67
67
+
h->size_dt_strings = be32(fdt + 32u);
68
68
+
h->size_dt_struct = be32(fdt + 36u);
69
69
+
if (h->totalsize < 40u || h->totalsize > FDT_MAX_SIZE) {
70
70
+
return false;
71
71
+
}
72
72
+
if (h->off_dt_struct >= h->totalsize || h->off_dt_strings >= h->totalsize) {
73
73
+
return false;
74
74
+
}
75
75
+
if (h->size_dt_struct > h->totalsize - h->off_dt_struct ||
76
76
+
h->size_dt_strings > h->totalsize - h->off_dt_strings) {
77
77
+
return false;
78
78
+
}
79
79
+
return true;
80
80
+
}
81
81
+
82
82
+
static bool string_in_block(const char *s, const uint8_t *start, const uint8_t *end)
83
83
+
{
84
84
+
const uint8_t *p = (const uint8_t *)s;
85
85
+
if (p < start || p >= end) {
86
86
+
return false;
87
87
+
}
88
88
+
while (p < end) {
89
89
+
if (*p == 0u) {
90
90
+
return true;
91
91
+
}
92
92
+
p++;
93
93
+
}
94
94
+
return false;
95
95
+
}
96
96
+
97
97
+
static bool node_name_is_memory(const char *name)
98
98
+
{
99
99
+
return hv_strncmp(name, "memory", 6u) == 0;
100
100
+
}
101
101
+
102
102
+
static bool find_property(uint64_t fdt_pa, const char *node_name,
103
103
+
const char *prop_name, struct fdt_property_ref *ref)
104
104
+
{
105
105
+
uint8_t *fdt = (uint8_t *)(uintptr_t)fdt_pa;
106
106
+
struct fdt_header_view h;
107
107
+
uint8_t *struct_p;
108
108
+
uint8_t *struct_end;
109
109
+
const uint8_t *strings;
110
110
+
const uint8_t *strings_end;
111
111
+
bool wanted_node[FDT_MAX_DEPTH];
112
112
+
uint32_t depth = 0;
113
113
+
114
114
+
if (node_name == (const char *)0 || prop_name == (const char *)0 ||
115
115
+
ref == (struct fdt_property_ref *)0 || !read_header(fdt, &h)) {
116
116
+
return false;
117
117
+
}
118
118
+
hv_memset(wanted_node, 0, sizeof(wanted_node));
119
119
+
struct_p = fdt + h.off_dt_struct;
120
120
+
struct_end = struct_p + h.size_dt_struct;
121
121
+
strings = fdt + h.off_dt_strings;
122
122
+
strings_end = strings + h.size_dt_strings;
123
123
+
124
124
+
while (struct_p + 4u <= struct_end) {
125
125
+
uint32_t token = be32(struct_p);
126
126
+
struct_p += 4u;
127
127
+
if (token == FDT_BEGIN_NODE) {
128
128
+
const char *name = (const char *)struct_p;
129
129
+
if (!string_in_block(name, struct_p, struct_end) || depth + 1u >= FDT_MAX_DEPTH) {
130
130
+
return false;
131
131
+
}
132
132
+
wanted_node[depth] = hv_strcmp(name, node_name) == 0;
133
133
+
while (struct_p < struct_end && *struct_p != 0u) {
134
134
+
struct_p++;
135
135
+
}
136
136
+
if (struct_p >= struct_end) {
137
137
+
return false;
138
138
+
}
139
139
+
struct_p = (uint8_t *)align4(struct_p + 1u);
140
140
+
depth++;
141
141
+
} else if (token == FDT_END_NODE) {
142
142
+
if (depth == 0u) {
143
143
+
return false;
144
144
+
}
145
145
+
depth--;
146
146
+
wanted_node[depth] = false;
147
147
+
} else if (token == FDT_PROP) {
148
148
+
uint32_t len;
149
149
+
uint32_t nameoff;
150
150
+
const char *name;
151
151
+
if (struct_p + 8u > struct_end) {
152
152
+
return false;
153
153
+
}
154
154
+
len = be32(struct_p);
155
155
+
nameoff = be32(struct_p + 4u);
156
156
+
struct_p += 8u;
157
157
+
if (nameoff >= h.size_dt_strings || len > (uint32_t)(struct_end - struct_p)) {
158
158
+
return false;
159
159
+
}
160
160
+
name = (const char *)(strings + nameoff);
161
161
+
if (!string_in_block(name, strings, strings_end)) {
162
162
+
return false;
163
163
+
}
164
164
+
if (depth != 0u && wanted_node[depth - 1u] && hv_strcmp(name, prop_name) == 0) {
165
165
+
ref->value = struct_p;
166
166
+
ref->len = len;
167
167
+
return true;
168
168
+
}
169
169
+
struct_p = (uint8_t *)align4(struct_p + len);
170
170
+
} else if (token == FDT_NOP) {
171
171
+
continue;
172
172
+
} else if (token == FDT_END) {
173
173
+
return false;
174
174
+
} else {
175
175
+
return false;
176
176
+
}
177
177
+
}
178
178
+
return false;
179
179
+
}
180
180
+
181
181
+
static bool find_memory_property(uint64_t fdt_pa, const char *prop_name,
182
182
+
struct fdt_property_ref *ref)
183
183
+
{
184
184
+
uint8_t *fdt = (uint8_t *)(uintptr_t)fdt_pa;
185
185
+
struct fdt_header_view h;
186
186
+
uint8_t *struct_p;
187
187
+
uint8_t *struct_end;
188
188
+
const uint8_t *strings;
189
189
+
const uint8_t *strings_end;
190
190
+
bool memory_node[FDT_MAX_DEPTH];
191
191
+
uint32_t depth = 0;
192
192
+
193
193
+
if (prop_name == (const char *)0 || ref == (struct fdt_property_ref *)0 ||
194
194
+
!read_header(fdt, &h)) {
195
195
+
return false;
196
196
+
}
197
197
+
hv_memset(memory_node, 0, sizeof(memory_node));
198
198
+
struct_p = fdt + h.off_dt_struct;
199
199
+
struct_end = struct_p + h.size_dt_struct;
200
200
+
strings = fdt + h.off_dt_strings;
201
201
+
strings_end = strings + h.size_dt_strings;
202
202
+
203
203
+
while (struct_p + 4u <= struct_end) {
204
204
+
uint32_t token = be32(struct_p);
205
205
+
struct_p += 4u;
206
206
+
if (token == FDT_BEGIN_NODE) {
207
207
+
const char *name = (const char *)struct_p;
208
208
+
if (!string_in_block(name, struct_p, struct_end) || depth + 1u >= FDT_MAX_DEPTH) {
209
209
+
return false;
210
210
+
}
211
211
+
memory_node[depth] = node_name_is_memory(name);
212
212
+
while (struct_p < struct_end && *struct_p != 0u) {
213
213
+
struct_p++;
214
214
+
}
215
215
+
if (struct_p >= struct_end) {
216
216
+
return false;
217
217
+
}
218
218
+
struct_p = (uint8_t *)align4(struct_p + 1u);
219
219
+
depth++;
220
220
+
} else if (token == FDT_END_NODE) {
221
221
+
if (depth == 0u) {
222
222
+
return false;
223
223
+
}
224
224
+
depth--;
225
225
+
memory_node[depth] = false;
226
226
+
} else if (token == FDT_PROP) {
227
227
+
uint32_t len;
228
228
+
uint32_t nameoff;
229
229
+
const char *name;
230
230
+
if (struct_p + 8u > struct_end) {
231
231
+
return false;
232
232
+
}
233
233
+
len = be32(struct_p);
234
234
+
nameoff = be32(struct_p + 4u);
235
235
+
struct_p += 8u;
236
236
+
if (nameoff >= h.size_dt_strings || len > (uint32_t)(struct_end - struct_p)) {
237
237
+
return false;
238
238
+
}
239
239
+
name = (const char *)(strings + nameoff);
240
240
+
if (!string_in_block(name, strings, strings_end)) {
241
241
+
return false;
242
242
+
}
243
243
+
if (depth != 0u && memory_node[depth - 1u] &&
244
244
+
hv_strcmp(name, prop_name) == 0) {
245
245
+
ref->value = struct_p;
246
246
+
ref->len = len;
247
247
+
return true;
248
248
+
}
249
249
+
struct_p = (uint8_t *)align4(struct_p + len);
250
250
+
} else if (token == FDT_NOP) {
251
251
+
continue;
252
252
+
} else if (token == FDT_END) {
253
253
+
return false;
254
254
+
} else {
255
255
+
return false;
256
256
+
}
257
257
+
}
258
258
+
return false;
259
259
+
}
260
260
+
261
261
+
static void write_be64(uint8_t *p, uint64_t value)
262
262
+
{
263
263
+
for (uint32_t i = 0; i < 8u; i++) {
264
264
+
p[i] = (uint8_t)(value >> (56u - (i * 8u)));
265
265
+
}
266
266
+
}
267
267
+
268
268
+
static void write_be32(uint8_t *p, uint32_t value)
269
269
+
{
270
270
+
p[0] = (uint8_t)(value >> 24u);
271
271
+
p[1] = (uint8_t)(value >> 16u);
272
272
+
p[2] = (uint8_t)(value >> 8u);
273
273
+
p[3] = (uint8_t)value;
274
274
+
}
275
275
+
276
276
+
static bool patch_string_prop(uint64_t fdt_pa, const char *node, const char *prop,
277
277
+
const char *value)
278
278
+
{
279
279
+
struct fdt_property_ref ref;
280
280
+
size_t len;
281
281
+
if (value == (const char *)0 || !find_property(fdt_pa, node, prop, &ref)) {
282
282
+
return false;
283
283
+
}
284
284
+
len = hv_strlen(value) + 1u;
285
285
+
if (len > ref.len) {
286
286
+
return false;
287
287
+
}
288
288
+
hv_memset(ref.value, 0, ref.len);
289
289
+
hv_memcpy(ref.value, value, len);
290
290
+
return true;
291
291
+
}
292
292
+
293
293
+
static bool repurpose_string_prop(uint64_t fdt_pa, const char *node_name,
294
294
+
const char *prop_name, const char *value)
295
295
+
{
296
296
+
uint8_t *fdt = (uint8_t *)(uintptr_t)fdt_pa;
297
297
+
struct fdt_header_view h;
298
298
+
uint8_t *struct_p;
299
299
+
uint8_t *struct_end;
300
300
+
uint8_t *strings;
301
301
+
const uint8_t *strings_end;
302
302
+
bool wanted_node[FDT_MAX_DEPTH];
303
303
+
uint32_t depth = 0;
304
304
+
size_t value_len;
305
305
+
size_t prop_len;
306
306
+
307
307
+
if (node_name == (const char *)0 || prop_name == (const char *)0 ||
308
308
+
value == (const char *)0 || !read_header(fdt, &h)) {
309
309
+
return false;
310
310
+
}
311
311
+
312
312
+
value_len = hv_strlen(value) + 1u;
313
313
+
prop_len = hv_strlen(prop_name) + 1u;
314
314
+
hv_memset(wanted_node, 0, sizeof(wanted_node));
315
315
+
struct_p = fdt + h.off_dt_struct;
316
316
+
struct_end = struct_p + h.size_dt_struct;
317
317
+
strings = fdt + h.off_dt_strings;
318
318
+
strings_end = strings + h.size_dt_strings;
319
319
+
320
320
+
while (struct_p + 4u <= struct_end) {
321
321
+
uint32_t token = be32(struct_p);
322
322
+
struct_p += 4u;
323
323
+
if (token == FDT_BEGIN_NODE) {
324
324
+
const char *name = (const char *)struct_p;
325
325
+
if (!string_in_block(name, struct_p, struct_end) || depth + 1u >= FDT_MAX_DEPTH) {
326
326
+
return false;
327
327
+
}
328
328
+
wanted_node[depth] = hv_strcmp(name, node_name) == 0;
329
329
+
while (struct_p < struct_end && *struct_p != 0u) {
330
330
+
struct_p++;
331
331
+
}
332
332
+
if (struct_p >= struct_end) {
333
333
+
return false;
334
334
+
}
335
335
+
struct_p = (uint8_t *)align4(struct_p + 1u);
336
336
+
depth++;
337
337
+
} else if (token == FDT_END_NODE) {
338
338
+
if (depth == 0u) {
339
339
+
return false;
340
340
+
}
341
341
+
depth--;
342
342
+
wanted_node[depth] = false;
343
343
+
} else if (token == FDT_PROP) {
344
344
+
uint32_t len;
345
345
+
uint32_t nameoff;
346
346
+
char *name;
347
347
+
if (struct_p + 8u > struct_end) {
348
348
+
return false;
349
349
+
}
350
350
+
len = be32(struct_p);
351
351
+
nameoff = be32(struct_p + 4u);
352
352
+
struct_p += 8u;
353
353
+
if (nameoff >= h.size_dt_strings || len > (uint32_t)(struct_end - struct_p)) {
354
354
+
return false;
355
355
+
}
356
356
+
name = (char *)(strings + nameoff);
357
357
+
if (!string_in_block(name, strings, strings_end)) {
358
358
+
return false;
359
359
+
}
360
360
+
if (depth != 0u && wanted_node[depth - 1u] &&
361
361
+
len >= value_len && hv_strlen(name) + 1u >= prop_len) {
362
362
+
hv_memset(name, 0, hv_strlen(name) + 1u);
363
363
+
hv_memcpy(name, prop_name, prop_len);
364
364
+
hv_memset(struct_p, 0, len);
365
365
+
hv_memcpy(struct_p, value, value_len);
366
366
+
return true;
367
367
+
}
368
368
+
struct_p = (uint8_t *)align4(struct_p + len);
369
369
+
} else if (token == FDT_NOP) {
370
370
+
continue;
371
371
+
} else if (token == FDT_END) {
372
372
+
return false;
373
373
+
} else {
374
374
+
return false;
375
375
+
}
376
376
+
}
377
377
+
return false;
378
378
+
}
379
379
+
380
380
+
static bool patch_u64_prop(uint64_t fdt_pa, const char *node, const char *prop,
381
381
+
uint64_t value)
382
382
+
{
383
383
+
struct fdt_property_ref ref;
384
384
+
if (!find_property(fdt_pa, node, prop, &ref) || ref.len < 8u) {
385
385
+
return false;
386
386
+
}
387
387
+
write_be64(ref.value, value);
388
388
+
return true;
389
389
+
}
390
390
+
391
391
+
static bool find_node_end(uint64_t fdt_pa, const char *node_name, uint8_t **out)
392
392
+
{
393
393
+
uint8_t *fdt = (uint8_t *)(uintptr_t)fdt_pa;
394
394
+
struct fdt_header_view h;
395
395
+
uint8_t *struct_p;
396
396
+
uint8_t *struct_end;
397
397
+
bool wanted_node[FDT_MAX_DEPTH];
398
398
+
uint32_t depth = 0;
399
399
+
400
400
+
if (node_name == (const char *)0 || out == (uint8_t **)0 || !read_header(fdt, &h)) {
401
401
+
return false;
402
402
+
}
403
403
+
hv_memset(wanted_node, 0, sizeof(wanted_node));
404
404
+
struct_p = fdt + h.off_dt_struct;
405
405
+
struct_end = struct_p + h.size_dt_struct;
406
406
+
407
407
+
while (struct_p + 4u <= struct_end) {
408
408
+
uint8_t *token_p = struct_p;
409
409
+
uint32_t token = be32(struct_p);
410
410
+
struct_p += 4u;
411
411
+
if (token == FDT_BEGIN_NODE) {
412
412
+
const char *name = (const char *)struct_p;
413
413
+
if (!string_in_block(name, struct_p, struct_end) || depth + 1u >= FDT_MAX_DEPTH) {
414
414
+
return false;
415
415
+
}
416
416
+
wanted_node[depth] = hv_strcmp(name, node_name) == 0;
417
417
+
while (struct_p < struct_end && *struct_p != 0u) {
418
418
+
struct_p++;
419
419
+
}
420
420
+
if (struct_p >= struct_end) {
421
421
+
return false;
422
422
+
}
423
423
+
struct_p = (uint8_t *)align4(struct_p + 1u);
424
424
+
depth++;
425
425
+
} else if (token == FDT_END_NODE) {
426
426
+
if (depth == 0u) {
427
427
+
return false;
428
428
+
}
429
429
+
if (wanted_node[depth - 1u]) {
430
430
+
*out = token_p;
431
431
+
return true;
432
432
+
}
433
433
+
depth--;
434
434
+
wanted_node[depth] = false;
435
435
+
} else if (token == FDT_PROP) {
436
436
+
uint32_t len;
437
437
+
if (struct_p + 8u > struct_end) {
438
438
+
return false;
439
439
+
}
440
440
+
len = be32(struct_p);
441
441
+
struct_p += 8u;
442
442
+
if (len > (uint32_t)(struct_end - struct_p)) {
443
443
+
return false;
444
444
+
}
445
445
+
struct_p = (uint8_t *)align4(struct_p + len);
446
446
+
} else if (token == FDT_NOP) {
447
447
+
continue;
448
448
+
} else if (token == FDT_END) {
449
449
+
return false;
450
450
+
} else {
451
451
+
return false;
452
452
+
}
453
453
+
}
454
454
+
return false;
455
455
+
}
456
456
+
457
457
+
static bool append_chosen_prop(uint64_t fdt_pa, uint64_t max_size, const char *prop,
458
458
+
const uint8_t *value, uint32_t len)
459
459
+
{
460
460
+
uint8_t *fdt = (uint8_t *)(uintptr_t)fdt_pa;
461
461
+
struct fdt_header_view h;
462
462
+
uint8_t *insert;
463
463
+
uint8_t *strings;
464
464
+
uint32_t prop_name_len;
465
465
+
uint32_t value_len;
466
466
+
uint32_t record_size;
467
467
+
uint32_t growth;
468
468
+
uint32_t nameoff;
469
469
+
470
470
+
if (prop == (const char *)0 || value == (const uint8_t *)0 ||
471
471
+
max_size > FDT_MAX_SIZE || !read_header(fdt, &h) ||
472
472
+
!find_node_end(fdt_pa, "chosen", &insert)) {
473
473
+
return false;
474
474
+
}
475
475
+
476
476
+
prop_name_len = (uint32_t)hv_strlen(prop) + 1u;
477
477
+
value_len = align4_u32(len);
478
478
+
record_size = 12u + value_len;
479
479
+
growth = record_size + prop_name_len;
480
480
+
if (max_size < h.totalsize || growth > max_size - h.totalsize) {
481
481
+
return false;
482
482
+
}
483
483
+
484
484
+
nameoff = h.size_dt_strings;
485
485
+
hv_memmove(insert + record_size, insert, h.totalsize - (uint32_t)(insert - fdt));
486
486
+
write_be32(insert, FDT_PROP);
487
487
+
write_be32(insert + 4u, len);
488
488
+
write_be32(insert + 8u, nameoff);
489
489
+
hv_memset(insert + 12u, 0, value_len);
490
490
+
hv_memcpy(insert + 12u, value, len);
491
491
+
492
492
+
strings = fdt + h.off_dt_strings + record_size;
493
493
+
hv_memcpy(strings + h.size_dt_strings, prop, prop_name_len);
494
494
+
write_be32(fdt + 4u, h.totalsize + growth);
495
495
+
write_be32(fdt + 12u, h.off_dt_strings + record_size);
496
496
+
write_be32(fdt + 32u, h.size_dt_strings + prop_name_len);
497
497
+
write_be32(fdt + 36u, h.size_dt_struct + record_size);
498
498
+
return true;
499
499
+
}
500
500
+
501
501
+
static bool ensure_chosen_u64(uint64_t fdt_pa, uint64_t max_size, const char *prop,
502
502
+
uint64_t value)
503
503
+
{
504
504
+
uint8_t buf[8];
505
505
+
if (patch_u64_prop(fdt_pa, "chosen", prop, value)) {
506
506
+
return true;
507
507
+
}
508
508
+
write_be64(buf, value);
509
509
+
return append_chosen_prop(fdt_pa, max_size, prop, buf, sizeof(buf));
510
510
+
}
511
511
+
512
512
+
bool fdt_patch_memory(uint64_t fdt_pa, uint64_t base, uint64_t size)
513
513
+
{
514
514
+
struct fdt_property_ref ref;
515
515
+
516
516
+
if (size == 0u || !find_memory_property(fdt_pa, "reg", &ref) || ref.len < 16u) {
517
517
+
return false;
518
518
+
}
519
519
+
520
520
+
write_be64(ref.value, base);
521
521
+
write_be64(ref.value + 8u, size);
522
522
+
if (ref.len > 16u) {
523
523
+
hv_memset(ref.value + 16u, 0, ref.len - 16u);
524
524
+
}
525
525
+
return true;
526
526
+
}
527
527
+
528
528
+
bool fdt_probe(uint64_t fdt_pa, struct fdt_platform_info *info)
529
529
+
{
530
530
+
const uint8_t *fdt = (const uint8_t *)(uintptr_t)fdt_pa;
531
531
+
struct fdt_header_view h;
532
532
+
const uint8_t *struct_p;
533
533
+
const uint8_t *struct_end;
534
534
+
const uint8_t *strings;
535
535
+
const uint8_t *strings_end;
536
536
+
bool memory_node[FDT_MAX_DEPTH];
537
537
+
bool chosen_node[FDT_MAX_DEPTH];
538
538
+
uint32_t depth = 0;
539
539
+
uint32_t address_cells = 2u;
540
540
+
uint32_t size_cells = 2u;
541
541
+
542
542
+
if (info == (struct fdt_platform_info *)0) {
543
543
+
return false;
544
544
+
}
545
545
+
hv_memset(info, 0, sizeof(*info));
546
546
+
if (fdt_pa == 0u || !hv_is_aligned_u64(fdt_pa, 8u)) {
547
547
+
return false;
548
548
+
}
549
549
+
if (!read_header(fdt, &h)) {
550
550
+
return false;
551
551
+
}
552
552
+
553
553
+
hv_memset(memory_node, 0, sizeof(memory_node));
554
554
+
hv_memset(chosen_node, 0, sizeof(chosen_node));
555
555
+
struct_p = fdt + h.off_dt_struct;
556
556
+
struct_end = struct_p + h.size_dt_struct;
557
557
+
strings = fdt + h.off_dt_strings;
558
558
+
strings_end = strings + h.size_dt_strings;
559
559
+
560
560
+
while (struct_p + 4u <= struct_end) {
561
561
+
uint32_t token = be32(struct_p);
562
562
+
struct_p += 4u;
563
563
+
564
564
+
if (token == FDT_BEGIN_NODE) {
565
565
+
const char *name = (const char *)struct_p;
566
566
+
if (!string_in_block(name, struct_p, struct_end) || depth + 1u >= FDT_MAX_DEPTH) {
567
567
+
return false;
568
568
+
}
569
569
+
memory_node[depth] = node_name_is_memory(name);
570
570
+
chosen_node[depth] = hv_strcmp(name, "chosen") == 0;
571
571
+
while (struct_p < struct_end && *struct_p != 0u) {
572
572
+
struct_p++;
573
573
+
}
574
574
+
if (struct_p >= struct_end) {
575
575
+
return false;
576
576
+
}
577
577
+
struct_p = align4(struct_p + 1u);
578
578
+
depth++;
579
579
+
} else if (token == FDT_END_NODE) {
580
580
+
if (depth == 0u) {
581
581
+
return false;
582
582
+
}
583
583
+
depth--;
584
584
+
memory_node[depth] = false;
585
585
+
chosen_node[depth] = false;
586
586
+
} else if (token == FDT_PROP) {
587
587
+
uint32_t len;
588
588
+
uint32_t nameoff;
589
589
+
const char *prop_name;
590
590
+
const uint8_t *value;
591
591
+
592
592
+
if (struct_p + 8u > struct_end) {
593
593
+
return false;
594
594
+
}
595
595
+
len = be32(struct_p);
596
596
+
nameoff = be32(struct_p + 4u);
597
597
+
struct_p += 8u;
598
598
+
if (nameoff >= h.size_dt_strings || len > (uint32_t)(struct_end - struct_p)) {
599
599
+
return false;
600
600
+
}
601
601
+
prop_name = (const char *)(strings + nameoff);
602
602
+
if (!string_in_block(prop_name, strings, strings_end)) {
603
603
+
return false;
604
604
+
}
605
605
+
value = struct_p;
606
606
+
607
607
+
if (depth == 1u && hv_strcmp(prop_name, "#address-cells") == 0 && len >= 4u) {
608
608
+
address_cells = be32(value);
609
609
+
} else if (depth == 1u && hv_strcmp(prop_name, "#size-cells") == 0 && len >= 4u) {
610
610
+
size_cells = be32(value);
611
611
+
} else if (depth != 0u && hv_strcmp(prop_name, "device_type") == 0 &&
612
612
+
len >= 7u && hv_strcmp((const char *)value, "memory") == 0) {
613
613
+
memory_node[depth - 1u] = true;
614
614
+
} else if (depth != 0u && memory_node[depth - 1u] &&
615
615
+
hv_strcmp(prop_name, "reg") == 0 &&
616
616
+
address_cells <= 2u && size_cells <= 2u &&
617
617
+
len >= (address_cells + size_cells) * 4u) {
618
618
+
const uint32_t *cells = (const uint32_t *)value;
619
619
+
info->memory_base = read_cells(cells, address_cells);
620
620
+
info->memory_size = read_cells(cells + address_cells, size_cells);
621
621
+
} else if (depth != 0u && chosen_node[depth - 1u]) {
622
622
+
if (hv_strcmp(prop_name, "bootargs") == 0 && len != 0u) {
623
623
+
info->bootargs = (const char *)value;
624
624
+
} else if (hv_strcmp(prop_name, "linux,initrd-start") == 0 && len >= 4u) {
625
625
+
info->initrd_start = read_cells((const uint32_t *)value, len >= 8u ? 2u : 1u);
626
626
+
} else if (hv_strcmp(prop_name, "linux,initrd-end") == 0 && len >= 4u) {
627
627
+
info->initrd_end = read_cells((const uint32_t *)value, len >= 8u ? 2u : 1u);
628
628
+
}
629
629
+
}
630
630
+
631
631
+
struct_p = align4(struct_p + len);
632
632
+
} else if (token == FDT_NOP) {
633
633
+
continue;
634
634
+
} else if (token == FDT_END) {
635
635
+
info->valid = true;
636
636
+
info->fdt_pa = fdt_pa;
637
637
+
info->size = h.totalsize;
638
638
+
return true;
639
639
+
} else {
640
640
+
return false;
641
641
+
}
642
642
+
}
643
643
+
644
644
+
return false;
645
645
+
}
646
646
+
647
647
+
bool fdt_patch_linux_guest(uint64_t fdt_pa, uint64_t max_size, const char *bootargs,
648
648
+
uint64_t initrd_start, uint64_t initrd_end)
649
649
+
{
650
650
+
struct fdt_platform_info info;
651
651
+
bool ok = true;
652
652
+
653
653
+
if (!fdt_probe(fdt_pa, &info)) {
654
654
+
return false;
655
655
+
}
656
656
+
if (bootargs != (const char *)0) {
657
657
+
ok = patch_string_prop(fdt_pa, "chosen", "bootargs", bootargs) ||
658
658
+
repurpose_string_prop(fdt_pa, "chosen", "bootargs", bootargs) ||
659
659
+
append_chosen_prop(fdt_pa, max_size, "bootargs",
660
660
+
(const uint8_t *)bootargs,
661
661
+
(uint32_t)hv_strlen(bootargs) + 1u);
662
662
+
}
663
663
+
if (initrd_start != 0u && initrd_end > initrd_start) {
664
664
+
ok = ok && ensure_chosen_u64(fdt_pa, max_size, "linux,initrd-start", initrd_start);
665
665
+
ok = ok && ensure_chosen_u64(fdt_pa, max_size, "linux,initrd-end", initrd_end);
666
666
+
}
667
667
+
return ok;
668
668
+
}
669
669
+
670
670
+
void fdt_dump(const struct fdt_platform_info *info)
671
671
+
{
672
672
+
if (info == (const struct fdt_platform_info *)0 || !info->valid) {
673
673
+
uart_puts("fdt unavailable\n");
674
674
+
return;
675
675
+
}
676
676
+
uart_puts("fdt pa=");
677
677
+
uart_put_hex64(info->fdt_pa);
678
678
+
uart_puts(" size=");
679
679
+
uart_put_dec64(info->size);
680
680
+
uart_puts(" memory=");
681
681
+
uart_put_hex64(info->memory_base);
682
682
+
uart_puts("+");
683
683
+
uart_put_hex64(info->memory_size);
684
684
+
if (info->initrd_start != 0u || info->initrd_end != 0u) {
685
685
+
uart_puts(" initrd=");
686
686
+
uart_put_hex64(info->initrd_start);
687
687
+
uart_puts("-");
688
688
+
uart_put_hex64(info->initrd_end);
689
689
+
}
690
690
+
uart_puts("\n");
691
691
+
if (info->bootargs != (const char *)0) {
692
692
+
uart_puts("bootargs ");
693
693
+
uart_puts(info->bootargs);
694
694
+
uart_puts("\n");
695
695
+
}
696
696
+
}
···
1
1
+
#include "hv/arch.h"
2
2
+
#include "hv/config.h"
3
3
+
#include "hv/fdt.h"
4
4
+
#include "hv/guest_loader.h"
5
5
+
#include "hv/string.h"
6
6
+
7
7
+
#define ARM64_IMAGE_MAGIC 0x644d5241u
8
8
+
#define ARM64_IMAGE_MAGIC_OFFSET 0x38u
9
9
+
#define ARM64_IMAGE_TEXT_OFFSET 0x08u
10
10
+
#define ARM64_IMAGE_SIZE_OFFSET 0x10u
11
11
+
#define LINUX_BOOTARGS "console=ttyAMA0 earlycon"
12
12
+
13
13
+
static uint32_t read_le32(const uint8_t *p)
14
14
+
{
15
15
+
return (uint32_t)p[0] | ((uint32_t)p[1] << 8u) |
16
16
+
((uint32_t)p[2] << 16u) | ((uint32_t)p[3] << 24u);
17
17
+
}
18
18
+
19
19
+
static uint64_t read_le64(const uint8_t *p)
20
20
+
{
21
21
+
return (uint64_t)read_le32(p) | ((uint64_t)read_le32(p + 4u) << 32u);
22
22
+
}
23
23
+
24
24
+
bool guest_load_diagnostic(struct guest_image_info *info)
25
25
+
{
26
26
+
uintptr_t guest_start;
27
27
+
uintptr_t guest_end;
28
28
+
uint64_t guest_size;
29
29
+
30
30
+
if (info == (struct guest_image_info *)0) {
31
31
+
return false;
32
32
+
}
33
33
+
34
34
+
guest_start = (uintptr_t)__guest_image_start;
35
35
+
guest_end = (uintptr_t)__guest_image_end;
36
36
+
guest_size = (uint64_t)(guest_end - guest_start);
37
37
+
38
38
+
if (guest_size == 0u || guest_size > CONFIG_GUEST_RAM_SIZE) {
39
39
+
return false;
40
40
+
}
41
41
+
if (hv_range_overlaps(CONFIG_GUEST_RAM_BASE, CONFIG_GUEST_RAM_SIZE,
42
42
+
(uint64_t)(uintptr_t)__image_start,
43
43
+
(uint64_t)((uintptr_t)__image_end - (uintptr_t)__image_start))) {
44
44
+
return false;
45
45
+
}
46
46
+
47
47
+
hv_memset((void *)(uintptr_t)CONFIG_GUEST_RAM_BASE, 0, CONFIG_GUEST_RAM_SIZE);
48
48
+
hv_memcpy((void *)(uintptr_t)CONFIG_GUEST_RAM_BASE, (const void *)guest_start, (size_t)guest_size);
49
49
+
50
50
+
info->kind = GUEST_PAYLOAD_DIAGNOSTIC;
51
51
+
info->ipa_entry = CONFIG_GUEST_ENTRY;
52
52
+
info->ipa_load = CONFIG_GUEST_IPA_BASE;
53
53
+
info->size = guest_size;
54
54
+
info->dtb_ipa = 0u;
55
55
+
info->initrd_ipa = 0u;
56
56
+
info->initrd_size = 0u;
57
57
+
return true;
58
58
+
}
59
59
+
60
60
+
bool guest_validate_linux_image_header(const void *image, uint64_t size,
61
61
+
struct guest_image_info *info)
62
62
+
{
63
63
+
const uint8_t *p = (const uint8_t *)image;
64
64
+
uint64_t text_offset;
65
65
+
uint64_t image_size;
66
66
+
uint64_t entry;
67
67
+
68
68
+
if (image == (const void *)0 || info == (struct guest_image_info *)0 || size < 0x40u) {
69
69
+
return false;
70
70
+
}
71
71
+
if (read_le32(p + ARM64_IMAGE_MAGIC_OFFSET) != ARM64_IMAGE_MAGIC) {
72
72
+
return false;
73
73
+
}
74
74
+
75
75
+
text_offset = read_le64(p + ARM64_IMAGE_TEXT_OFFSET);
76
76
+
image_size = read_le64(p + ARM64_IMAGE_SIZE_OFFSET);
77
77
+
if (image_size == 0u) {
78
78
+
image_size = size;
79
79
+
}
80
80
+
if (image_size > CONFIG_GUEST_RAM_SIZE || text_offset >= CONFIG_GUEST_RAM_SIZE) {
81
81
+
return false;
82
82
+
}
83
83
+
if (hv_add_overflow_u64(CONFIG_GUEST_IPA_BASE, text_offset, &entry)) {
84
84
+
return false;
85
85
+
}
86
86
+
87
87
+
info->kind = GUEST_PAYLOAD_LINUX_IMAGE;
88
88
+
info->ipa_entry = entry;
89
89
+
info->ipa_load = entry;
90
90
+
info->size = image_size;
91
91
+
info->dtb_ipa = 0u;
92
92
+
info->initrd_ipa = 0u;
93
93
+
info->initrd_size = 0u;
94
94
+
return true;
95
95
+
}
96
96
+
97
97
+
bool guest_load_external_linux(struct guest_image_info *info, paddr_t image_pa,
98
98
+
uint64_t image_max_size, paddr_t dtb_pa,
99
99
+
uint64_t dtb_max_size, paddr_t initrd_pa,
100
100
+
uint64_t initrd_size)
101
101
+
{
102
102
+
struct fdt_platform_info dtb_info;
103
103
+
uint64_t initrd_start = 0u;
104
104
+
uint64_t initrd_end = 0u;
105
105
+
106
106
+
if (info == (struct guest_image_info *)0 ||
107
107
+
image_max_size == 0u || image_max_size > CONFIG_GUEST_RAM_SIZE) {
108
108
+
return false;
109
109
+
}
110
110
+
if (!guest_validate_linux_image_header((const void *)(uintptr_t)image_pa,
111
111
+
image_max_size, info)) {
112
112
+
return false;
113
113
+
}
114
114
+
if (!fdt_probe(dtb_pa, &dtb_info) || dtb_info.size > dtb_max_size) {
115
115
+
return false;
116
116
+
}
117
117
+
if (initrd_size != 0u) {
118
118
+
if (initrd_size > CONFIG_LINUX_INITRD_MAX_SIZE ||
119
119
+
initrd_pa != CONFIG_LINUX_INITRD_PA ||
120
120
+
hv_add_overflow_u64(CONFIG_LINUX_INITRD_IPA, initrd_size, &initrd_end) ||
121
121
+
initrd_end > CONFIG_LINUX_DTB_IPA) {
122
122
+
return false;
123
123
+
}
124
124
+
initrd_start = CONFIG_LINUX_INITRD_IPA;
125
125
+
}
126
126
+
if (!fdt_patch_memory(dtb_pa, CONFIG_GUEST_IPA_BASE, CONFIG_GUEST_RAM_SIZE)) {
127
127
+
return false;
128
128
+
}
129
129
+
if (!fdt_patch_linux_guest(dtb_pa, dtb_max_size, LINUX_BOOTARGS,
130
130
+
initrd_start, initrd_end)) {
131
131
+
return false;
132
132
+
}
133
133
+
if (!fdt_probe(dtb_pa, &dtb_info)) {
134
134
+
return false;
135
135
+
}
136
136
+
fdt_dump(&dtb_info);
137
137
+
138
138
+
info->kind = GUEST_PAYLOAD_LINUX_IMAGE;
139
139
+
info->ipa_load = CONFIG_GUEST_IPA_BASE;
140
140
+
info->dtb_ipa = CONFIG_LINUX_DTB_IPA;
141
141
+
if (initrd_start != 0u && initrd_end > initrd_start) {
142
142
+
info->initrd_ipa = initrd_start;
143
143
+
info->initrd_size = initrd_end - initrd_start;
144
144
+
}
145
145
+
return true;
146
146
+
}
···
1
1
+
#include "hv/arch.h"
2
2
+
#include "hv/config.h"
3
3
+
#include "hv/log.h"
4
4
+
#include "hv/string.h"
5
5
+
#include "hv/timer.h"
6
6
+
#include "hv/uart.h"
7
7
+
8
8
+
struct log_ring {
9
9
+
struct log_event events[CONFIG_LOG_CAPACITY];
10
10
+
volatile unsigned lock;
11
11
+
uint64_t next_seq;
12
12
+
uint32_t write_index;
13
13
+
bool wrapped;
14
14
+
};
15
15
+
16
16
+
static struct log_ring g_log;
17
17
+
static struct log_ring g_log_selftest_backup;
18
18
+
19
19
+
static void lock_log(void)
20
20
+
{
21
21
+
while (__atomic_test_and_set(&g_log.lock, __ATOMIC_ACQUIRE)) {
22
22
+
}
23
23
+
}
24
24
+
25
25
+
static void unlock_log(void)
26
26
+
{
27
27
+
__atomic_clear(&g_log.lock, __ATOMIC_RELEASE);
28
28
+
}
29
29
+
30
30
+
void log_init(void)
31
31
+
{
32
32
+
hv_memset(&g_log, 0, sizeof(g_log));
33
33
+
}
34
34
+
35
35
+
void log_event_commit(const struct log_event *event)
36
36
+
{
37
37
+
if (event == (const struct log_event *)0) {
38
38
+
return;
39
39
+
}
40
40
+
41
41
+
uint64_t irq_flags = arch_irq_save();
42
42
+
lock_log();
43
43
+
struct log_event *slot = &g_log.events[g_log.write_index];
44
44
+
*slot = *event;
45
45
+
slot->seq = g_log.next_seq++;
46
46
+
slot->cpu = arch_mpidr_el1() & 0xffu;
47
47
+
slot->timestamp = timer_now();
48
48
+
g_log.write_index++;
49
49
+
if (g_log.write_index == CONFIG_LOG_CAPACITY) {
50
50
+
g_log.write_index = 0;
51
51
+
g_log.wrapped = true;
52
52
+
}
53
53
+
unlock_log();
54
54
+
arch_irq_restore(irq_flags);
55
55
+
}
56
56
+
57
57
+
void log_simple(enum log_kind kind, uint32_t reason, uint64_t a, uint64_t b)
58
58
+
{
59
59
+
struct log_event ev;
60
60
+
hv_memset(&ev, 0, sizeof(ev));
61
61
+
ev.kind = (uint32_t)kind;
62
62
+
ev.reason = reason;
63
63
+
ev.iss = a;
64
64
+
ev.elr = b;
65
65
+
log_event_commit(&ev);
66
66
+
}
67
67
+
68
68
+
static const char *kind_name(uint32_t kind)
69
69
+
{
70
70
+
switch (kind) {
71
71
+
case LOG_BOOT: return "boot";
72
72
+
case LOG_TRAP: return "trap";
73
73
+
case LOG_POLICY: return "policy";
74
74
+
case LOG_HVC: return "hvc";
75
75
+
case LOG_ABORT: return "abort";
76
76
+
case LOG_MONITOR: return "monitor";
77
77
+
case LOG_PANIC: return "panic";
78
78
+
case LOG_SELFTEST: return "selftest";
79
79
+
default: return "unknown";
80
80
+
}
81
81
+
}
82
82
+
83
83
+
void log_dump(unsigned limit)
84
84
+
{
85
85
+
uint64_t irq_flags = arch_irq_save();
86
86
+
lock_log();
87
87
+
uint32_t count = g_log.wrapped ? CONFIG_LOG_CAPACITY : g_log.write_index;
88
88
+
if (limit != 0u && limit < count) {
89
89
+
count = limit;
90
90
+
}
91
91
+
92
92
+
uint32_t start = g_log.wrapped ? g_log.write_index : 0u;
93
93
+
if (g_log.wrapped && count < CONFIG_LOG_CAPACITY) {
94
94
+
start = (g_log.write_index + CONFIG_LOG_CAPACITY - count) % CONFIG_LOG_CAPACITY;
95
95
+
}
96
96
+
97
97
+
for (uint32_t i = 0; i < count; i++) {
98
98
+
const struct log_event *ev = &g_log.events[(start + i) % CONFIG_LOG_CAPACITY];
99
99
+
uart_puts("event seq=");
100
100
+
uart_put_dec64(ev->seq);
101
101
+
uart_puts(" cpu=");
102
102
+
uart_put_dec64(ev->cpu);
103
103
+
uart_puts(" vcpu=");
104
104
+
uart_put_dec64(ev->vcpu);
105
105
+
uart_puts(" ts=");
106
106
+
uart_put_dec64(ev->timestamp);
107
107
+
uart_puts(" kind=");
108
108
+
uart_puts(kind_name(ev->kind));
109
109
+
uart_puts(" ec=");
110
110
+
uart_put_hex64(ev->ec);
111
111
+
uart_puts(" iss=");
112
112
+
uart_put_hex64(ev->iss);
113
113
+
uart_puts(" elr=");
114
114
+
uart_put_hex64(ev->elr);
115
115
+
uart_puts(" far=");
116
116
+
uart_put_hex64(ev->far);
117
117
+
uart_puts(" hpfar=");
118
118
+
uart_put_hex64(ev->hpfar);
119
119
+
uart_puts(" sysreg=");
120
120
+
uart_put_hex64(ev->sysreg_key);
121
121
+
uart_puts(" name=");
122
122
+
uart_puts(ev->name != (const char *)0 ? ev->name : "-");
123
123
+
uart_puts(" dir=");
124
124
+
uart_puts(ev->is_read != 0u ? "read" : "write");
125
125
+
uart_puts(" rt=");
126
126
+
uart_put_dec64(ev->rt);
127
127
+
uart_puts(" operand=");
128
128
+
uart_put_hex64(ev->operand);
129
129
+
uart_puts(" result=");
130
130
+
uart_put_hex64(ev->result);
131
131
+
uart_puts(" action=");
132
132
+
uart_put_dec64(ev->action);
133
133
+
uart_puts(" pstate=");
134
134
+
uart_put_hex64(ev->pstate);
135
135
+
uart_puts(" reason=");
136
136
+
uart_put_dec64(ev->reason);
137
137
+
uart_puts("\n");
138
138
+
}
139
139
+
unlock_log();
140
140
+
arch_irq_restore(irq_flags);
141
141
+
}
142
142
+
143
143
+
void log_clear(void)
144
144
+
{
145
145
+
uint64_t irq_flags = arch_irq_save();
146
146
+
lock_log();
147
147
+
hv_memset(g_log.events, 0, sizeof(g_log.events));
148
148
+
g_log.write_index = 0;
149
149
+
g_log.wrapped = false;
150
150
+
unlock_log();
151
151
+
arch_irq_restore(irq_flags);
152
152
+
}
153
153
+
154
154
+
bool log_selftest(void)
155
155
+
{
156
156
+
g_log_selftest_backup = g_log;
157
157
+
log_init();
158
158
+
for (uint32_t i = 0; i < CONFIG_LOG_CAPACITY + 3u; i++) {
159
159
+
log_simple(LOG_SELFTEST, i, i, i + 1u);
160
160
+
}
161
161
+
bool ok = g_log.wrapped && g_log.next_seq == (uint64_t)CONFIG_LOG_CAPACITY + 3u;
162
162
+
g_log = g_log_selftest_backup;
163
163
+
return ok;
164
164
+
}
···
1
1
+
#include "hv/allocator.h"
2
2
+
#include "hv/arch.h"
3
3
+
#include "hv/config.h"
4
4
+
#include "hv/el2_mmu.h"
5
5
+
#include "hv/fdt.h"
6
6
+
#include "hv/gicv3.h"
7
7
+
#include "hv/guest_loader.h"
8
8
+
#include "hv/log.h"
9
9
+
#include "hv/monitor.h"
10
10
+
#include "hv/panic.h"
11
11
+
#include "hv/platform.h"
12
12
+
#include "hv/policy.h"
13
13
+
#include "hv/selftest.h"
14
14
+
#include "hv/stage2.h"
15
15
+
#include "hv/string.h"
16
16
+
#include "hv/timer.h"
17
17
+
#include "hv/uart.h"
18
18
+
#include "hv/vcpu.h"
19
19
+
20
20
+
static struct vcpu g_boot_vcpu;
21
21
+
static uint8_t g_allocator_pool[CONFIG_PAGE_SIZE * 16u] __attribute__((aligned(4096)));
22
22
+
static struct fdt_platform_info g_platform_info;
23
23
+
24
24
+
const struct fdt_platform_info *platform_info(void)
25
25
+
{
26
26
+
return &g_platform_info;
27
27
+
}
28
28
+
29
29
+
static void print_banner(void)
30
30
+
{
31
31
+
uart_puts("\n");
32
32
+
uart_puts(HV_PROJECT_NAME " " HV_BUILD_MODE "\n");
33
33
+
uart_puts("build id=" HV_BUILD_ID "\n");
34
34
+
}
35
35
+
36
36
+
void hv_main(uint64_t boot_dtb_pa)
37
37
+
{
38
38
+
struct guest_image_info guest_info;
39
39
+
40
40
+
uart_init();
41
41
+
print_banner();
42
42
+
log_init();
43
43
+
timer_init();
44
44
+
monitor_init();
45
45
+
46
46
+
if (arch_current_el() != 2u) {
47
47
+
panic_with_code("hypervisor must start at EL2", arch_current_el());
48
48
+
}
49
49
+
if (fdt_probe(boot_dtb_pa, &g_platform_info)) {
50
50
+
log_simple(LOG_BOOT, 30u, g_platform_info.fdt_pa, g_platform_info.size);
51
51
+
} else {
52
52
+
hv_memset(&g_platform_info, 0, sizeof(g_platform_info));
53
53
+
log_simple(LOG_BOOT, 31u, boot_dtb_pa, 0u);
54
54
+
}
55
55
+
56
56
+
arch_install_vectors();
57
57
+
el2_mmu_init_plan();
58
58
+
el2_mmu_enable();
59
59
+
allocator_init((paddr_t)(uintptr_t)g_allocator_pool, sizeof(g_allocator_pool));
60
60
+
policy_init();
61
61
+
#if CONFIG_BOOT_LINUX
62
62
+
(void)policy_set_profile(POLICY_PROFILE_LINUX_BOOT);
63
63
+
#endif
64
64
+
stage2_init();
65
65
+
#if CONFIG_BOOT_LINUX
66
66
+
if (!guest_load_external_linux(&guest_info, CONFIG_LINUX_IMAGE_LOAD_PA,
67
67
+
CONFIG_LINUX_IMAGE_MAX_SIZE, CONFIG_LINUX_DTB_PA,
68
68
+
CONFIG_LINUX_DTB_MAX_SIZE, CONFIG_LINUX_INITRD_PA,
69
69
+
CONFIG_LINUX_INITRD_SIZE)) {
70
70
+
panic("external Linux Image load failed");
71
71
+
}
72
72
+
#else
73
73
+
if (!guest_load_diagnostic(&guest_info)) {
74
74
+
panic("diagnostic guest load failed");
75
75
+
}
76
76
+
#endif
77
77
+
log_simple(LOG_BOOT, 10u, guest_info.ipa_load, guest_info.size);
78
78
+
if (!stage2_map_range(CONFIG_GUEST_IPA_BASE, CONFIG_GUEST_RAM_BASE, CONFIG_GUEST_RAM_SIZE,
79
79
+
S2_MEM_NORMAL, S2_PERM_R | S2_PERM_W | S2_PERM_X)) {
80
80
+
panic("stage2 guest RAM map failed");
81
81
+
}
82
82
+
83
83
+
gicv3_init();
84
84
+
arch_el2_configure(stage2_vttbr(), stage2_vtcr());
85
85
+
selftests_run_or_panic();
86
86
+
87
87
+
vcpu_init(&g_boot_vcpu, 0u, guest_info.ipa_entry, CONFIG_GUEST_STACK_TOP);
88
88
+
vcpu_set_current(&g_boot_vcpu);
89
89
+
arch_prepare_guest_entry(&g_boot_vcpu);
90
90
+
if (guest_info.kind == GUEST_PAYLOAD_LINUX_IMAGE) {
91
91
+
vcpu_write_gpr(&g_boot_vcpu, 0u, guest_info.dtb_ipa);
92
92
+
vcpu_write_gpr(&g_boot_vcpu, 1u, 0u);
93
93
+
vcpu_write_gpr(&g_boot_vcpu, 2u, 0u);
94
94
+
vcpu_write_gpr(&g_boot_vcpu, 3u, 0u);
95
95
+
}
96
96
+
97
97
+
uart_puts("launching guest entry=");
98
98
+
uart_put_hex64(g_boot_vcpu.pc);
99
99
+
uart_puts(" stack=");
100
100
+
uart_put_hex64(g_boot_vcpu.sp_el1);
101
101
+
uart_puts("\n");
102
102
+
g_boot_vcpu.state = VCPU_RUNNING;
103
103
+
timer_vcpu_sync(&g_boot_vcpu);
104
104
+
gicv3_flush_vcpu_state(&g_boot_vcpu);
105
105
+
arch_vcpu_enter(&g_boot_vcpu);
106
106
+
panic("arch_vcpu_enter returned");
107
107
+
}
···
1
1
+
#include "hv/config.h"
2
2
+
#include "hv/mmio.h"
3
3
+
#include "hv/mmio_policy.h"
4
4
+
#include "hv/uart.h"
5
5
+
#include "hv/vcpu.h"
6
6
+
7
7
+
static const struct mmio_policy_region g_mmio_regions[] = {
8
8
+
{ CONFIG_UART_BASE, CONFIG_UART_SIZE, "pl011-uart", MMIO_POLICY_EMULATE_PL011 },
9
9
+
{ CONFIG_GICD_BASE, CONFIG_GICD_SIZE, "gicd", MMIO_POLICY_EMULATE_READONLY_DEVICE },
10
10
+
{ CONFIG_GITS_BASE, CONFIG_GITS_SIZE, "gits", MMIO_POLICY_EMULATE_READONLY_DEVICE },
11
11
+
{ CONFIG_GICR_BASE, CONFIG_GICR_SIZE, "gicr", MMIO_POLICY_EMULATE_READONLY_DEVICE },
12
12
+
{ CONFIG_RTC_BASE, CONFIG_RTC_SIZE, "pl031-rtc", MMIO_POLICY_EMULATE_READONLY_DEVICE },
13
13
+
{ CONFIG_FW_CFG_BASE, CONFIG_FW_CFG_SIZE, "fw-cfg", MMIO_POLICY_EMULATE_READONLY_DEVICE },
14
14
+
{ CONFIG_GPIO_BASE, CONFIG_GPIO_SIZE, "pl061-gpio", MMIO_POLICY_EMULATE_READONLY_DEVICE },
15
15
+
{ CONFIG_PCI_ECAM_BASE, CONFIG_PCI_ECAM_SIZE, "pci-ecam", MMIO_POLICY_EMULATE_ZERO },
16
16
+
{ 0x0a000000ull, 0x00004000ull, "virtio-mmio", MMIO_POLICY_EMULATE_VIRTIO_MMIO },
17
17
+
};
18
18
+
19
19
+
const struct mmio_policy_region *mmio_policy_lookup(ipa_t ipa)
20
20
+
{
21
21
+
for (uint32_t i = 0; i < HV_ARRAY_SIZE(g_mmio_regions); i++) {
22
22
+
uint64_t end;
23
23
+
if (hv_add_overflow_u64(g_mmio_regions[i].base, g_mmio_regions[i].size, &end)) {
24
24
+
continue;
25
25
+
}
26
26
+
if (ipa >= g_mmio_regions[i].base && ipa < end) {
27
27
+
return &g_mmio_regions[i];
28
28
+
}
29
29
+
}
30
30
+
return (const struct mmio_policy_region *)0;
31
31
+
}
32
32
+
33
33
+
static bool decode_abort_access(uint64_t esr, bool *is_write, uint32_t *rt)
34
34
+
{
35
35
+
if ((esr & HV_BIT(24)) == 0u) {
36
36
+
return false;
37
37
+
}
38
38
+
*rt = (uint32_t)((esr >> 16u) & 0x1fu);
39
39
+
*is_write = (esr & HV_BIT(6)) != 0u;
40
40
+
return true;
41
41
+
}
42
42
+
43
43
+
static uint64_t virtio_read(uint64_t off)
44
44
+
{
45
45
+
if ((off & ~0x1ffull) != 0u) {
46
46
+
return 0u;
47
47
+
}
48
48
+
off &= 0x1ffu;
49
49
+
switch (off) {
50
50
+
case 0x000u: return 0x74726976u;
51
51
+
case 0x004u: return 2u;
52
52
+
case 0x008u: return 3u;
53
53
+
case 0x00cu: return 0x41524945u;
54
54
+
case 0x010u: return 0u;
55
55
+
case 0x034u: return 0u;
56
56
+
case 0x070u: return 0u;
57
57
+
default: return 0u;
58
58
+
}
59
59
+
}
60
60
+
61
61
+
static uint64_t readonly_device_read32(ipa_t ipa)
62
62
+
{
63
63
+
if (!hv_is_aligned_u64(ipa, 4u)) {
64
64
+
return 0u;
65
65
+
}
66
66
+
return (uint64_t)mmio_read32((uintptr_t)ipa);
67
67
+
}
68
68
+
69
69
+
bool mmio_policy_emulate(struct vcpu *vcpu, ipa_t ipa, uint64_t esr_el2)
70
70
+
{
71
71
+
const struct mmio_policy_region *region = mmio_policy_lookup(ipa);
72
72
+
bool is_write;
73
73
+
uint32_t rt;
74
74
+
uint64_t off;
75
75
+
uint64_t value = 0u;
76
76
+
77
77
+
if (vcpu == (struct vcpu *)0 || region == (const struct mmio_policy_region *)0 ||
78
78
+
!decode_abort_access(esr_el2, &is_write, &rt)) {
79
79
+
return false;
80
80
+
}
81
81
+
82
82
+
off = ipa - region->base;
83
83
+
if (region->action == MMIO_POLICY_EMULATE_PL011) {
84
84
+
if (is_write && off == 0u) {
85
85
+
uart_putc((char)(vcpu_read_gpr(vcpu, rt) & 0xffu));
86
86
+
} else if (!is_write && off == 0x18u) {
87
87
+
value = 0x10u;
88
88
+
}
89
89
+
} else if (region->action == MMIO_POLICY_EMULATE_VIRTIO_MMIO) {
90
90
+
if (!is_write) {
91
91
+
value = virtio_read(off);
92
92
+
}
93
93
+
} else if (region->action == MMIO_POLICY_EMULATE_READONLY_DEVICE) {
94
94
+
if (!is_write) {
95
95
+
value = readonly_device_read32(ipa);
96
96
+
}
97
97
+
} else if (region->action != MMIO_POLICY_EMULATE_ZERO) {
98
98
+
return false;
99
99
+
}
100
100
+
101
101
+
if (!is_write) {
102
102
+
vcpu_write_gpr(vcpu, rt, value);
103
103
+
}
104
104
+
return true;
105
105
+
}
106
106
+
107
107
+
void mmio_policy_dump(void)
108
108
+
{
109
109
+
for (uint32_t i = 0; i < HV_ARRAY_SIZE(g_mmio_regions); i++) {
110
110
+
uart_puts("mmio name=");
111
111
+
uart_puts(g_mmio_regions[i].name);
112
112
+
uart_puts(" base=");
113
113
+
uart_put_hex64(g_mmio_regions[i].base);
114
114
+
uart_puts(" size=");
115
115
+
uart_put_hex64(g_mmio_regions[i].size);
116
116
+
uart_puts(" action=");
117
117
+
uart_put_dec64((uint64_t)g_mmio_regions[i].action);
118
118
+
uart_puts("\n");
119
119
+
}
120
120
+
}
···
1
1
+
#include "hv/allocator.h"
2
2
+
#include "hv/gicv3.h"
3
3
+
#include "hv/el2_mmu.h"
4
4
+
#include "hv/log.h"
5
5
+
#include "hv/monitor.h"
6
6
+
#include "hv/mmio_policy.h"
7
7
+
#include "hv/platform.h"
8
8
+
#include "hv/policy.h"
9
9
+
#include "hv/psci.h"
10
10
+
#include "hv/stage2.h"
11
11
+
#include "hv/string.h"
12
12
+
#include "hv/timer.h"
13
13
+
#include "hv/uart.h"
14
14
+
15
15
+
static char g_line[96];
16
16
+
static uint32_t g_pos;
17
17
+
static bool g_paused;
18
18
+
static struct vcpu g_snapshot;
19
19
+
static bool g_snapshot_valid;
20
20
+
21
21
+
static void help(void)
22
22
+
{
23
23
+
#if CONFIG_MONITOR_MUTATION
24
24
+
uart_puts("commands: help status vcpu regs sysregs snapshot restore log log clear policy profile psci mappings mmio el2mmu fdt translate read64 write64 dump unmap irq irq clear resume pause reboot shutdown\n");
25
25
+
#else
26
26
+
uart_puts("commands: help status vcpu regs sysregs snapshot snapshot show log policy psci mappings mmio el2mmu fdt translate read64 dump resume pause\n");
27
27
+
#endif
28
28
+
}
29
29
+
30
30
+
static bool is_space(char c)
31
31
+
{
32
32
+
return c == ' ' || c == '\t';
33
33
+
}
34
34
+
35
35
+
static const char *skip_spaces(const char *s)
36
36
+
{
37
37
+
while (is_space(*s)) {
38
38
+
s++;
39
39
+
}
40
40
+
return s;
41
41
+
}
42
42
+
43
43
+
static bool starts_with_command(const char *line, const char *cmd)
44
44
+
{
45
45
+
size_t n = hv_strlen(cmd);
46
46
+
return hv_strncmp(line, cmd, n) == 0 && (line[n] == '\0' || is_space(line[n]));
47
47
+
}
48
48
+
49
49
+
static bool digit_value(char c, uint64_t *out)
50
50
+
{
51
51
+
if (c >= '0' && c <= '9') {
52
52
+
*out = (uint64_t)(c - '0');
53
53
+
return true;
54
54
+
}
55
55
+
if (c >= 'a' && c <= 'f') {
56
56
+
*out = 10u + (uint64_t)(c - 'a');
57
57
+
return true;
58
58
+
}
59
59
+
if (c >= 'A' && c <= 'F') {
60
60
+
*out = 10u + (uint64_t)(c - 'A');
61
61
+
return true;
62
62
+
}
63
63
+
return false;
64
64
+
}
65
65
+
66
66
+
static bool parse_u64(const char **cursor, uint64_t *out)
67
67
+
{
68
68
+
const char *s = skip_spaces(*cursor);
69
69
+
uint64_t base = 10u;
70
70
+
uint64_t value = 0u;
71
71
+
uint64_t digit;
72
72
+
bool any = false;
73
73
+
74
74
+
if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
75
75
+
base = 16u;
76
76
+
s += 2;
77
77
+
}
78
78
+
while (digit_value(*s, &digit)) {
79
79
+
if (digit >= base) {
80
80
+
return false;
81
81
+
}
82
82
+
if (value > (UINT64_MAX - digit) / base) {
83
83
+
return false;
84
84
+
}
85
85
+
value = (value * base) + digit;
86
86
+
any = true;
87
87
+
s++;
88
88
+
}
89
89
+
if (!any) {
90
90
+
return false;
91
91
+
}
92
92
+
*cursor = s;
93
93
+
*out = value;
94
94
+
return true;
95
95
+
}
96
96
+
97
97
+
static bool ipa_to_host(uint64_t ipa, uint64_t len, uintptr_t *host)
98
98
+
{
99
99
+
struct stage2_translation tr;
100
100
+
uint64_t end;
101
101
+
uint64_t tr_end;
102
102
+
uint64_t off;
103
103
+
104
104
+
if (host == (uintptr_t *)0 || len == 0u || hv_add_overflow_u64(ipa, len, &end)) {
105
105
+
return false;
106
106
+
}
107
107
+
if (!stage2_translate(ipa, &tr) ||
108
108
+
hv_add_overflow_u64(tr.ipa_base, tr.size, &tr_end) ||
109
109
+
end > tr_end) {
110
110
+
return false;
111
111
+
}
112
112
+
off = ipa - tr.ipa_base;
113
113
+
*host = (uintptr_t)(tr.pa_base + off);
114
114
+
return true;
115
115
+
}
116
116
+
117
117
+
static void monitor_translate(const char *args)
118
118
+
{
119
119
+
uint64_t ipa;
120
120
+
struct stage2_translation tr;
121
121
+
if (!parse_u64(&args, &ipa)) {
122
122
+
uart_puts("usage translate <ipa>\n");
123
123
+
return;
124
124
+
}
125
125
+
if (!stage2_translate(ipa, &tr)) {
126
126
+
uart_puts("translate unmapped ipa=");
127
127
+
uart_put_hex64(ipa);
128
128
+
uart_puts("\n");
129
129
+
return;
130
130
+
}
131
131
+
uart_puts("translate ipa=");
132
132
+
uart_put_hex64(ipa);
133
133
+
uart_puts(" block=");
134
134
+
uart_put_hex64(tr.ipa_base);
135
135
+
uart_puts(" pa=");
136
136
+
uart_put_hex64(tr.pa_base + (ipa - tr.ipa_base));
137
137
+
uart_puts(" perms=");
138
138
+
uart_put_hex64(tr.perms);
139
139
+
uart_puts(" desc=");
140
140
+
uart_put_hex64(tr.desc);
141
141
+
uart_puts("\n");
142
142
+
}
143
143
+
144
144
+
static void monitor_read64(const char *args)
145
145
+
{
146
146
+
uint64_t ipa;
147
147
+
uintptr_t host;
148
148
+
if (!parse_u64(&args, &ipa) || !hv_is_aligned_u64(ipa, 8u)) {
149
149
+
uart_puts("usage read64 <aligned-ipa>\n");
150
150
+
return;
151
151
+
}
152
152
+
if (!ipa_to_host(ipa, 8u, &host)) {
153
153
+
uart_puts("read64 unmapped\n");
154
154
+
return;
155
155
+
}
156
156
+
uart_puts("read64 ");
157
157
+
uart_put_hex64(ipa);
158
158
+
uart_puts("=");
159
159
+
uart_put_hex64(*(volatile uint64_t *)host);
160
160
+
uart_puts("\n");
161
161
+
}
162
162
+
163
163
+
static void monitor_write64(const char *args)
164
164
+
{
165
165
+
#if CONFIG_MONITOR_MUTATION
166
166
+
uint64_t ipa;
167
167
+
uint64_t value;
168
168
+
uintptr_t host;
169
169
+
if (!parse_u64(&args, &ipa) || !parse_u64(&args, &value) || !hv_is_aligned_u64(ipa, 8u)) {
170
170
+
uart_puts("usage write64 <aligned-ipa> <value>\n");
171
171
+
return;
172
172
+
}
173
173
+
if (!ipa_to_host(ipa, 8u, &host)) {
174
174
+
uart_puts("write64 unmapped\n");
175
175
+
return;
176
176
+
}
177
177
+
*(volatile uint64_t *)host = value;
178
178
+
uart_puts("write64 ok\n");
179
179
+
#else
180
180
+
(void)args;
181
181
+
uart_puts("write64 disabled\n");
182
182
+
#endif
183
183
+
}
184
184
+
185
185
+
static void monitor_dump(const char *args)
186
186
+
{
187
187
+
uint64_t ipa;
188
188
+
uint64_t len;
189
189
+
uintptr_t host;
190
190
+
if (!parse_u64(&args, &ipa) || !parse_u64(&args, &len) || len > 256u) {
191
191
+
uart_puts("usage dump <ipa> <len<=256>\n");
192
192
+
return;
193
193
+
}
194
194
+
if (!ipa_to_host(ipa, len, &host)) {
195
195
+
uart_puts("dump unmapped\n");
196
196
+
return;
197
197
+
}
198
198
+
for (uint64_t i = 0; i < len; i++) {
199
199
+
if ((i & 0x0full) == 0u) {
200
200
+
uart_puts("\n");
201
201
+
uart_put_hex64(ipa + i);
202
202
+
uart_puts(":");
203
203
+
}
204
204
+
uart_puts(" ");
205
205
+
uint8_t b = *(volatile uint8_t *)(host + i);
206
206
+
static const char hex[] = "0123456789abcdef";
207
207
+
uart_putc(hex[b >> 4u]);
208
208
+
uart_putc(hex[b & 0x0fu]);
209
209
+
}
210
210
+
uart_puts("\n");
211
211
+
}
212
212
+
213
213
+
static void monitor_unmap(const char *args)
214
214
+
{
215
215
+
#if CONFIG_MONITOR_MUTATION
216
216
+
uint64_t ipa;
217
217
+
if (!parse_u64(&args, &ipa)) {
218
218
+
uart_puts("usage unmap <2MiB-aligned-ipa>\n");
219
219
+
return;
220
220
+
}
221
221
+
if (!stage2_unmap_range(HV_ALIGN_DOWN(ipa, 0x200000ull), 0x200000ull)) {
222
222
+
uart_puts("unmap failed\n");
223
223
+
return;
224
224
+
}
225
225
+
uart_puts("unmap ok\n");
226
226
+
#else
227
227
+
(void)args;
228
228
+
uart_puts("unmap disabled\n");
229
229
+
#endif
230
230
+
}
231
231
+
232
232
+
static void monitor_irq(const char *args, struct vcpu *vcpu)
233
233
+
{
234
234
+
#if CONFIG_MONITOR_MUTATION
235
235
+
uint64_t intid;
236
236
+
args = skip_spaces(args);
237
237
+
if (hv_strncmp(args, "clear", 5u) == 0 && is_space(args[5])) {
238
238
+
args = skip_spaces(args + 5u);
239
239
+
if (vcpu == (struct vcpu *)0 || !parse_u64(&args, &intid) || intid >= 64u) {
240
240
+
uart_puts("usage irq clear <intid<64>\n");
241
241
+
return;
242
242
+
}
243
243
+
vcpu_clear_pending_irq(vcpu, (uint32_t)intid);
244
244
+
gicv3_flush_vcpu_state(vcpu);
245
245
+
uart_puts("irq cleared intid=");
246
246
+
uart_put_dec64(intid);
247
247
+
uart_puts("\n");
248
248
+
return;
249
249
+
}
250
250
+
if (vcpu == (struct vcpu *)0 || !parse_u64(&args, &intid) || intid >= 64u) {
251
251
+
uart_puts("usage irq <intid<64> | irq clear <intid<64>\n");
252
252
+
return;
253
253
+
}
254
254
+
vcpu_set_pending_irq(vcpu, (uint32_t)intid);
255
255
+
gicv3_flush_vcpu_state(vcpu);
256
256
+
uart_puts("irq pending intid=");
257
257
+
uart_put_dec64(intid);
258
258
+
uart_puts("\n");
259
259
+
#else
260
260
+
(void)args;
261
261
+
(void)vcpu;
262
262
+
uart_puts("irq disabled\n");
263
263
+
#endif
264
264
+
}
265
265
+
266
266
+
static void monitor_profile(const char *args)
267
267
+
{
268
268
+
#if CONFIG_MONITOR_MUTATION
269
269
+
args = skip_spaces(args);
270
270
+
if (*args == '\0') {
271
271
+
uart_puts("policy profile=");
272
272
+
uart_puts(policy_profile_name(policy_get_profile()));
273
273
+
uart_puts("\n");
274
274
+
return;
275
275
+
}
276
276
+
if (!policy_set_profile_name(args)) {
277
277
+
uart_puts("usage profile strict|diagnostic|linux-boot|debug\n");
278
278
+
return;
279
279
+
}
280
280
+
uart_puts("policy profile=");
281
281
+
uart_puts(policy_profile_name(policy_get_profile()));
282
282
+
uart_puts("\n");
283
283
+
#else
284
284
+
(void)args;
285
285
+
uart_puts("profile disabled\n");
286
286
+
#endif
287
287
+
}
288
288
+
289
289
+
static void monitor_snapshot(struct vcpu *vcpu)
290
290
+
{
291
291
+
if (vcpu == (struct vcpu *)0) {
292
292
+
uart_puts("snapshot no-vcpu\n");
293
293
+
return;
294
294
+
}
295
295
+
g_snapshot = *vcpu;
296
296
+
g_snapshot_valid = true;
297
297
+
log_simple(LOG_MONITOR, 610u, vcpu->pc, vcpu->pstate);
298
298
+
uart_puts("snapshot saved pc=");
299
299
+
uart_put_hex64(g_snapshot.pc);
300
300
+
uart_puts(" pstate=");
301
301
+
uart_put_hex64(g_snapshot.pstate);
302
302
+
uart_puts("\n");
303
303
+
}
304
304
+
305
305
+
static void monitor_snapshot_show(void)
306
306
+
{
307
307
+
if (!g_snapshot_valid) {
308
308
+
uart_puts("snapshot empty\n");
309
309
+
return;
310
310
+
}
311
311
+
uart_puts("snapshot pc=");
312
312
+
uart_put_hex64(g_snapshot.pc);
313
313
+
uart_puts(" pstate=");
314
314
+
uart_put_hex64(g_snapshot.pstate);
315
315
+
uart_puts(" sp_el1=");
316
316
+
uart_put_hex64(g_snapshot.sp_el1);
317
317
+
uart_puts(" traps=");
318
318
+
uart_put_dec64(g_snapshot.stats.traps);
319
319
+
uart_puts("\n");
320
320
+
}
321
321
+
322
322
+
static void monitor_restore(struct vcpu *vcpu)
323
323
+
{
324
324
+
#if CONFIG_MONITOR_MUTATION
325
325
+
if (vcpu == (struct vcpu *)0 || !g_snapshot_valid) {
326
326
+
uart_puts("restore no-snapshot\n");
327
327
+
return;
328
328
+
}
329
329
+
*vcpu = g_snapshot;
330
330
+
vcpu_set_current(vcpu);
331
331
+
log_simple(LOG_MONITOR, 611u, vcpu->pc, vcpu->pstate);
332
332
+
uart_puts("restore ok pc=");
333
333
+
uart_put_hex64(vcpu->pc);
334
334
+
uart_puts("\n");
335
335
+
#else
336
336
+
(void)vcpu;
337
337
+
uart_puts("restore disabled\n");
338
338
+
#endif
339
339
+
}
340
340
+
341
341
+
static void show_sysregs(const struct vcpu *vcpu)
342
342
+
{
343
343
+
if (vcpu == (const struct vcpu *)0) {
344
344
+
return;
345
345
+
}
346
346
+
uart_puts("sysregs sctlr=");
347
347
+
uart_put_hex64(vcpu->sysregs.sctlr_el1);
348
348
+
uart_puts(" ttbr0=");
349
349
+
uart_put_hex64(vcpu->sysregs.ttbr0_el1);
350
350
+
uart_puts(" ttbr1=");
351
351
+
uart_put_hex64(vcpu->sysregs.ttbr1_el1);
352
352
+
uart_puts(" tcr=");
353
353
+
uart_put_hex64(vcpu->sysregs.tcr_el1);
354
354
+
uart_puts(" mair=");
355
355
+
uart_put_hex64(vcpu->sysregs.mair_el1);
356
356
+
uart_puts(" vbar=");
357
357
+
uart_put_hex64(vcpu->sysregs.vbar_el1);
358
358
+
uart_puts("\n");
359
359
+
}
360
360
+
361
361
+
static bool command(const char *line, struct vcpu *vcpu)
362
362
+
{
363
363
+
if (hv_strcmp(line, "help") == 0) {
364
364
+
help();
365
365
+
} else if (hv_strcmp(line, "status") == 0) {
366
366
+
vcpu_dump(vcpu);
367
367
+
timer_dump();
368
368
+
gicv3_dump();
369
369
+
} else if (hv_strcmp(line, "vcpu") == 0 || hv_strcmp(line, "regs") == 0) {
370
370
+
vcpu_dump(vcpu);
371
371
+
} else if (hv_strcmp(line, "snapshot") == 0) {
372
372
+
monitor_snapshot(vcpu);
373
373
+
} else if (hv_strcmp(line, "snapshot show") == 0) {
374
374
+
monitor_snapshot_show();
375
375
+
} else if (hv_strcmp(line, "restore") == 0) {
376
376
+
monitor_restore(vcpu);
377
377
+
} else if (hv_strcmp(line, "sysregs") == 0) {
378
378
+
show_sysregs(vcpu);
379
379
+
} else if (hv_strcmp(line, "log") == 0) {
380
380
+
log_dump(128u);
381
381
+
} else if (hv_strcmp(line, "log clear") == 0) {
382
382
+
#if CONFIG_MONITOR_MUTATION
383
383
+
log_clear();
384
384
+
#else
385
385
+
uart_puts("log clear disabled\n");
386
386
+
#endif
387
387
+
} else if (hv_strcmp(line, "policy") == 0) {
388
388
+
policy_dump();
389
389
+
} else if (starts_with_command(line, "profile")) {
390
390
+
monitor_profile(line + hv_strlen("profile"));
391
391
+
} else if (hv_strcmp(line, "psci") == 0) {
392
392
+
psci_dump();
393
393
+
} else if (hv_strcmp(line, "mappings") == 0) {
394
394
+
stage2_dump();
395
395
+
allocator_dump();
396
396
+
} else if (hv_strcmp(line, "mmio") == 0) {
397
397
+
mmio_policy_dump();
398
398
+
} else if (hv_strcmp(line, "el2mmu") == 0) {
399
399
+
el2_mmu_dump();
400
400
+
} else if (hv_strcmp(line, "fdt") == 0) {
401
401
+
fdt_dump(platform_info());
402
402
+
} else if (starts_with_command(line, "translate")) {
403
403
+
monitor_translate(line + hv_strlen("translate"));
404
404
+
} else if (starts_with_command(line, "read64")) {
405
405
+
monitor_read64(line + hv_strlen("read64"));
406
406
+
} else if (starts_with_command(line, "write64")) {
407
407
+
monitor_write64(line + hv_strlen("write64"));
408
408
+
} else if (starts_with_command(line, "dump")) {
409
409
+
monitor_dump(line + hv_strlen("dump"));
410
410
+
} else if (starts_with_command(line, "unmap")) {
411
411
+
monitor_unmap(line + hv_strlen("unmap"));
412
412
+
} else if (starts_with_command(line, "irq")) {
413
413
+
monitor_irq(line + hv_strlen("irq"), vcpu);
414
414
+
} else if (hv_strcmp(line, "resume") == 0) {
415
415
+
if (vcpu != (struct vcpu *)0) {
416
416
+
vcpu->state = VCPU_RUNNING;
417
417
+
}
418
418
+
g_paused = false;
419
419
+
return true;
420
420
+
} else if (hv_strcmp(line, "pause") == 0) {
421
421
+
g_paused = true;
422
422
+
} else if (hv_strcmp(line, "reboot") == 0 || hv_strcmp(line, "shutdown") == 0) {
423
423
+
#if CONFIG_MONITOR_MUTATION
424
424
+
uart_puts("platform power control is not implemented; halting\n");
425
425
+
for (;;) {
426
426
+
__asm__ volatile("wfe");
427
427
+
}
428
428
+
#else
429
429
+
uart_puts("power control disabled\n");
430
430
+
#endif
431
431
+
} else if (line[0] != '\0') {
432
432
+
uart_puts("error unknown-command\n");
433
433
+
}
434
434
+
return false;
435
435
+
}
436
436
+
437
437
+
void monitor_init(void)
438
438
+
{
439
439
+
g_pos = 0;
440
440
+
g_paused = false;
441
441
+
g_snapshot_valid = false;
442
442
+
}
443
443
+
444
444
+
void monitor_poll(void)
445
445
+
{
446
446
+
char c;
447
447
+
while (uart_getc_nonblocking(&c)) {
448
448
+
if (c == '\r' || c == '\n') {
449
449
+
g_line[g_pos] = '\0';
450
450
+
(void)command(g_line, vcpu_current());
451
451
+
g_pos = 0;
452
452
+
uart_puts("hv> ");
453
453
+
} else if ((c == '\b' || c == 0x7f) && g_pos != 0u) {
454
454
+
g_pos--;
455
455
+
} else if (g_pos + 1u < sizeof(g_line) && c >= ' ' && c <= '~') {
456
456
+
g_line[g_pos++] = c;
457
457
+
} else {
458
458
+
uart_puts("error input-too-long\n");
459
459
+
g_pos = 0;
460
460
+
}
461
461
+
}
462
462
+
}
463
463
+
464
464
+
void monitor_loop(struct vcpu *vcpu, const char *reason)
465
465
+
{
466
466
+
g_paused = true;
467
467
+
if (vcpu != (struct vcpu *)0) {
468
468
+
vcpu->state = VCPU_PAUSED;
469
469
+
}
470
470
+
uart_puts("monitor entered reason=");
471
471
+
uart_puts(reason);
472
472
+
uart_puts("\nhv> ");
473
473
+
while (g_paused) {
474
474
+
monitor_poll();
475
475
+
__asm__ volatile("wfe");
476
476
+
}
477
477
+
}
···
1
1
+
#include "hv/arch.h"
2
2
+
#include "hv/log.h"
3
3
+
#include "hv/panic.h"
4
4
+
#include "hv/uart.h"
5
5
+
#include "hv/vcpu.h"
6
6
+
7
7
+
void panic_with_code(const char *reason, uint64_t code)
8
8
+
{
9
9
+
struct log_event ev;
10
10
+
ev.seq = 0;
11
11
+
ev.cpu = 0;
12
12
+
ev.vcpu = vcpu_current() != (struct vcpu *)0 ? vcpu_current()->id : UINT64_MAX;
13
13
+
ev.timestamp = 0;
14
14
+
ev.kind = LOG_PANIC;
15
15
+
ev.ec = 0;
16
16
+
ev.iss = code;
17
17
+
ev.elr = 0;
18
18
+
ev.far = 0;
19
19
+
ev.hpfar = 0;
20
20
+
ev.sysreg_key = 0;
21
21
+
ev.is_read = 0;
22
22
+
ev.rt = 0;
23
23
+
ev.operand = code;
24
24
+
ev.result = 0;
25
25
+
ev.action = LOG_ACT_PANIC;
26
26
+
ev.reason = 999u;
27
27
+
ev.pstate = 0;
28
28
+
ev.name = reason;
29
29
+
log_event_commit(&ev);
30
30
+
31
31
+
uart_puts("\nPANIC reason=");
32
32
+
uart_puts(reason);
33
33
+
uart_puts(" code=");
34
34
+
uart_put_hex64(code);
35
35
+
uart_puts(" current_el=");
36
36
+
uart_put_dec64(arch_current_el());
37
37
+
uart_puts("\n");
38
38
+
arch_dump_el2_state();
39
39
+
vcpu_dump(vcpu_current());
40
40
+
uart_puts("recent log:\n");
41
41
+
log_dump(32u);
42
42
+
arch_halt();
43
43
+
}
44
44
+
45
45
+
void panic(const char *reason)
46
46
+
{
47
47
+
panic_with_code(reason, 0u);
48
48
+
}
···
1
1
+
#include "hv/arch.h"
2
2
+
#include "hv/config.h"
3
3
+
#include "hv/policy.h"
4
4
+
#include "hv/string.h"
5
5
+
#include "hv/timer.h"
6
6
+
#include "hv/uart.h"
7
7
+
8
8
+
#define KEY(op0, op1, crn, crm, op2) SYSREG_KEY_CONST((op0), (op1), (crn), (crm), (op2))
9
9
+
#define RO_ID(name, op0, op1, crn, crm, op2, val) \
10
10
+
{ KEY(op0, op1, crn, crm, op2), name, POLICY_CLASS_ID, POLICY_EMULATE_READ, POLICY_DENY_UNDEF, val, 0, 1, 100 }
11
11
+
#define SHADOW_RW(name, op0, op1, crn, crm, op2, field, mask) \
12
12
+
{ KEY(op0, op1, crn, crm, op2), name, POLICY_CLASS_MMU, POLICY_EMULATE_READ, POLICY_WRITE_MASK, 0, mask, 1, 101 }
13
13
+
#define SHADOW_THREAD(name, op0, op1, crn, crm, op2) \
14
14
+
{ KEY(op0, op1, crn, crm, op2), name, POLICY_CLASS_THREAD, POLICY_EMULATE_READ, POLICY_EMULATE_WRITE, 0, UINT64_MAX, 1, 102 }
15
15
+
#define DENY_REG(name, op0, op1, crn, crm, op2, cls) \
16
16
+
{ KEY(op0, op1, crn, crm, op2), name, cls, POLICY_DENY_UNDEF, POLICY_DENY_UNDEF, 0, 0, 1, 200 }
17
17
+
18
18
+
static const struct policy_entry g_policy[] = {
19
19
+
RO_ID("midr_el1", 3, 0, 0, 0, 0, 0x00000000410fd034ull),
20
20
+
RO_ID("mpidr_el1", 3, 0, 0, 0, 5, 0x80000000ull),
21
21
+
RO_ID("id_aa64pfr0_el1", 3, 0, 0, 4, 0, 0x0000000000000011ull),
22
22
+
RO_ID("id_aa64pfr1_el1", 3, 0, 0, 4, 1, 0x0ull),
23
23
+
RO_ID("id_aa64isar0_el1", 3, 0, 0, 6, 0, 0x0ull),
24
24
+
RO_ID("id_aa64isar1_el1", 3, 0, 0, 6, 1, 0x0ull),
25
25
+
RO_ID("id_aa64mmfr0_el1", 3, 0, 0, 7, 0, 0x0000000000001122ull),
26
26
+
RO_ID("id_aa64mmfr1_el1", 3, 0, 0, 7, 1, 0x0ull),
27
27
+
RO_ID("clidr_el1", 3, 1, 0, 0, 1, 0x0ull),
28
28
+
{ KEY(3, 2, 0, 0, 0), "csselr_el1", POLICY_CLASS_MISC, POLICY_EMULATE_READ, POLICY_EMULATE_WRITE, 0, 0xfu, 1, 103 },
29
29
+
RO_ID("ctr_el0", 3, 3, 0, 0, 1, 0x8444c004ull),
30
30
+
RO_ID("dczid_el0", 3, 3, 0, 0, 7, 0x4ull),
31
31
+
{ KEY(3, 0, 1, 0, 0), "sctlr_el1", POLICY_CLASS_MMU, POLICY_EMULATE_READ, POLICY_WRITE_MASK, 0x30d00800ull, 0x0000000030d0dfffull, 1, 104 },
32
32
+
DENY_REG("actlr_el1", 3, 0, 1, 0, 1, POLICY_CLASS_MISC),
33
33
+
{ KEY(3, 0, 1, 0, 2), "cpacr_el1", POLICY_CLASS_MMU, POLICY_EMULATE_READ, POLICY_WRITE_MASK, 0, 0x00300000ull, 1, 105 },
34
34
+
DENY_REG("hcr_el2", 3, 4, 1, 1, 0, POLICY_CLASS_EL2_EL3),
35
35
+
DENY_REG("scr_el3", 3, 6, 1, 1, 0, POLICY_CLASS_EL2_EL3),
36
36
+
{ KEY(3, 0, 2, 0, 0), "ttbr0_el1", POLICY_CLASS_MMU, POLICY_EMULATE_READ, POLICY_EMULATE_WRITE, 0, 0x0000fffffffff000ull, 1, 106 },
37
37
+
{ KEY(3, 0, 2, 0, 1), "ttbr1_el1", POLICY_CLASS_MMU, POLICY_EMULATE_READ, POLICY_EMULATE_WRITE, 0, 0x0000fffffffff000ull, 1, 107 },
38
38
+
{ KEY(3, 0, 2, 0, 2), "tcr_el1", POLICY_CLASS_MMU, POLICY_EMULATE_READ, POLICY_WRITE_MASK, 0, 0x00000003ff3fffffull, 1, 108 },
39
39
+
DENY_REG("vttbr_el2", 3, 4, 2, 1, 0, POLICY_CLASS_EL2_EL3),
40
40
+
DENY_REG("pmcr_el0", 3, 3, 9, 12, 0, POLICY_CLASS_PMU),
41
41
+
{ KEY(3, 0, 10, 2, 0), "mair_el1", POLICY_CLASS_MMU, POLICY_EMULATE_READ, POLICY_EMULATE_WRITE, 0xffull, UINT64_MAX, 1, 109 },
42
42
+
{ KEY(3, 0, 12, 0, 0), "vbar_el1", POLICY_CLASS_MMU, POLICY_EMULATE_READ, POLICY_EMULATE_WRITE, 0, 0x0000fffffffff800ull, 1, 110 },
43
43
+
DENY_REG("rvbar_el1", 3, 0, 12, 0, 1, POLICY_CLASS_MISC),
44
44
+
SHADOW_THREAD("contextidr_el1", 3, 0, 13, 0, 1),
45
45
+
SHADOW_THREAD("tpidr_el1", 3, 0, 13, 0, 4),
46
46
+
SHADOW_THREAD("tpidrro_el0", 3, 3, 13, 0, 3),
47
47
+
{ KEY(3, 0, 14, 1, 0), "cntkctl_el1", POLICY_CLASS_TIMER, POLICY_EMULATE_READ, POLICY_WRITE_MASK, 0, 0x3u, 1, 111 },
48
48
+
{ KEY(3, 3, 14, 3, 0), "cntv_tval_el0", POLICY_CLASS_TIMER, POLICY_EMULATE_READ, POLICY_EMULATE_WRITE, 0, UINT64_MAX, 1, 112 },
49
49
+
{ KEY(3, 3, 14, 3, 1), "cntv_ctl_el0", POLICY_CLASS_TIMER, POLICY_EMULATE_READ, POLICY_WRITE_MASK, 0, 0x7u, 1, 113 },
50
50
+
{ KEY(3, 3, 14, 3, 2), "cntv_cval_el0", POLICY_CLASS_TIMER, POLICY_EMULATE_READ, POLICY_EMULATE_WRITE, 0, UINT64_MAX, 1, 114 },
51
51
+
{ KEY(2, 0, 0, 2, 2), "mdscr_el1", POLICY_CLASS_DEBUG, POLICY_EMULATE_READ, POLICY_WRITE_MASK, 0, 0ull, 1, 115 },
52
52
+
};
53
53
+
54
54
+
static enum policy_profile g_profile;
55
55
+
static struct policy_entry g_effective_entry;
56
56
+
57
57
+
void policy_init(void)
58
58
+
{
59
59
+
g_profile = POLICY_PROFILE_STRICT;
60
60
+
}
61
61
+
62
62
+
const char *policy_profile_name(enum policy_profile profile)
63
63
+
{
64
64
+
switch (profile) {
65
65
+
case POLICY_PROFILE_STRICT: return "strict";
66
66
+
case POLICY_PROFILE_DIAGNOSTIC: return "diagnostic";
67
67
+
case POLICY_PROFILE_LINUX_BOOT: return "linux-boot";
68
68
+
case POLICY_PROFILE_DEBUG: return "debug";
69
69
+
default: return "unknown";
70
70
+
}
71
71
+
}
72
72
+
73
73
+
bool policy_set_profile(enum policy_profile profile)
74
74
+
{
75
75
+
if (profile > POLICY_PROFILE_DEBUG) {
76
76
+
return false;
77
77
+
}
78
78
+
g_profile = profile;
79
79
+
return true;
80
80
+
}
81
81
+
82
82
+
bool policy_set_profile_name(const char *name)
83
83
+
{
84
84
+
if (name == (const char *)0) {
85
85
+
return false;
86
86
+
}
87
87
+
if (hv_strcmp(name, "strict") == 0) {
88
88
+
return policy_set_profile(POLICY_PROFILE_STRICT);
89
89
+
}
90
90
+
if (hv_strcmp(name, "diagnostic") == 0) {
91
91
+
return policy_set_profile(POLICY_PROFILE_DIAGNOSTIC);
92
92
+
}
93
93
+
if (hv_strcmp(name, "linux-boot") == 0) {
94
94
+
return policy_set_profile(POLICY_PROFILE_LINUX_BOOT);
95
95
+
}
96
96
+
if (hv_strcmp(name, "debug") == 0) {
97
97
+
return policy_set_profile(POLICY_PROFILE_DEBUG);
98
98
+
}
99
99
+
return false;
100
100
+
}
101
101
+
102
102
+
enum policy_profile policy_get_profile(void)
103
103
+
{
104
104
+
return g_profile;
105
105
+
}
106
106
+
107
107
+
const struct policy_entry *sysreg_policy_lookup(uint64_t key)
108
108
+
{
109
109
+
for (uint32_t i = 0; i < HV_ARRAY_SIZE(g_policy); i++) {
110
110
+
if (g_policy[i].key == key) {
111
111
+
return &g_policy[i];
112
112
+
}
113
113
+
}
114
114
+
return (const struct policy_entry *)0;
115
115
+
}
116
116
+
117
117
+
static uint64_t *shadow_slot(struct vcpu *vcpu, uint64_t key)
118
118
+
{
119
119
+
if (key == KEY(3, 0, 1, 0, 0)) return &vcpu->sysregs.sctlr_el1;
120
120
+
if (key == KEY(3, 0, 1, 0, 2)) return &vcpu->sysregs.cpacr_el1;
121
121
+
if (key == KEY(3, 0, 2, 0, 0)) return &vcpu->sysregs.ttbr0_el1;
122
122
+
if (key == KEY(3, 0, 2, 0, 1)) return &vcpu->sysregs.ttbr1_el1;
123
123
+
if (key == KEY(3, 0, 2, 0, 2)) return &vcpu->sysregs.tcr_el1;
124
124
+
if (key == KEY(3, 0, 10, 2, 0)) return &vcpu->sysregs.mair_el1;
125
125
+
if (key == KEY(3, 0, 12, 0, 0)) return &vcpu->sysregs.vbar_el1;
126
126
+
if (key == KEY(3, 0, 13, 0, 1)) return &vcpu->sysregs.contextidr_el1;
127
127
+
if (key == KEY(3, 0, 13, 0, 4)) return &vcpu->sysregs.tpidr_el1;
128
128
+
if (key == KEY(3, 3, 13, 0, 3)) return &vcpu->sysregs.tpidrro_el0;
129
129
+
if (key == KEY(3, 0, 14, 1, 0)) return &vcpu->sysregs.cntkctl_el1;
130
130
+
if (key == KEY(3, 3, 14, 3, 0)) return &vcpu->sysregs.cntv_tval_el0;
131
131
+
if (key == KEY(3, 3, 14, 3, 1)) return &vcpu->sysregs.cntv_ctl_el0;
132
132
+
if (key == KEY(3, 3, 14, 3, 2)) return &vcpu->sysregs.cntv_cval_el0;
133
133
+
if (key == KEY(3, 2, 0, 0, 0)) return &vcpu->sysregs.csselr_el1;
134
134
+
if (key == KEY(2, 0, 0, 2, 2)) return &vcpu->sysregs.mdscr_el1;
135
135
+
return (uint64_t *)0;
136
136
+
}
137
137
+
138
138
+
static bool is_el1_mmu_key(uint64_t key)
139
139
+
{
140
140
+
return key == KEY(3, 0, 1, 0, 0) ||
141
141
+
key == KEY(3, 0, 1, 0, 2) ||
142
142
+
key == KEY(3, 0, 2, 0, 0) ||
143
143
+
key == KEY(3, 0, 2, 0, 1) ||
144
144
+
key == KEY(3, 0, 2, 0, 2) ||
145
145
+
key == KEY(3, 0, 10, 2, 0) ||
146
146
+
key == KEY(3, 0, 12, 0, 0) ||
147
147
+
key == KEY(3, 0, 14, 1, 0);
148
148
+
}
149
149
+
150
150
+
static const struct policy_entry *effective_entry(const struct policy_entry *entry)
151
151
+
{
152
152
+
if (entry == (const struct policy_entry *)0) {
153
153
+
return (const struct policy_entry *)0;
154
154
+
}
155
155
+
156
156
+
g_effective_entry = *entry;
157
157
+
if (g_profile == POLICY_PROFILE_DIAGNOSTIC) {
158
158
+
if (g_effective_entry.access_class == POLICY_CLASS_PMU ||
159
159
+
g_effective_entry.access_class == POLICY_CLASS_MISC) {
160
160
+
g_effective_entry.read_policy = POLICY_DENY_SKIP;
161
161
+
g_effective_entry.write_policy = POLICY_DENY_SKIP;
162
162
+
}
163
163
+
} else if (g_profile == POLICY_PROFILE_LINUX_BOOT) {
164
164
+
if (g_effective_entry.access_class == POLICY_CLASS_PMU ||
165
165
+
g_effective_entry.key == KEY(3, 0, 12, 0, 1)) {
166
166
+
g_effective_entry.read_policy = POLICY_DENY_SKIP;
167
167
+
g_effective_entry.write_policy = POLICY_DENY_SKIP;
168
168
+
}
169
169
+
if (g_effective_entry.access_class == POLICY_CLASS_MMU) {
170
170
+
g_effective_entry.writable_mask = UINT64_MAX;
171
171
+
}
172
172
+
if (g_effective_entry.key == KEY(3, 3, 9, 12, 0)) {
173
173
+
g_effective_entry.reset_value = 0u;
174
174
+
}
175
175
+
} else if (g_profile == POLICY_PROFILE_DEBUG) {
176
176
+
if (g_effective_entry.access_class == POLICY_CLASS_DEBUG ||
177
177
+
g_effective_entry.access_class == POLICY_CLASS_PMU) {
178
178
+
g_effective_entry.read_policy = POLICY_EMULATE_READ;
179
179
+
g_effective_entry.write_policy = POLICY_WRITE_MASK;
180
180
+
g_effective_entry.writable_mask = 0u;
181
181
+
}
182
182
+
}
183
183
+
return &g_effective_entry;
184
184
+
}
185
185
+
186
186
+
bool policy_apply_sysreg(struct vcpu *vcpu, const struct sysreg_access *access,
187
187
+
uint64_t operand, struct policy_decision *decision)
188
188
+
{
189
189
+
if (vcpu == (struct vcpu *)0 || access == (const struct sysreg_access *)0 ||
190
190
+
decision == (struct policy_decision *)0) {
191
191
+
return false;
192
192
+
}
193
193
+
hv_memset(decision, 0, sizeof(*decision));
194
194
+
const struct policy_entry *entry = effective_entry(sysreg_policy_lookup(access->key));
195
195
+
decision->entry = entry;
196
196
+
decision->action = POLICY_DENY_SKIP;
197
197
+
decision->reason = 250u;
198
198
+
199
199
+
if (entry == (const struct policy_entry *)0) {
200
200
+
return true;
201
201
+
}
202
202
+
203
203
+
decision->action = access->is_read ? entry->read_policy : entry->write_policy;
204
204
+
decision->reason = entry->violation_reason;
205
205
+
206
206
+
uint64_t *slot = shadow_slot(vcpu, access->key);
207
207
+
switch (decision->action) {
208
208
+
case POLICY_EMULATE_READ:
209
209
+
decision->value = slot != (uint64_t *)0 ? *slot : entry->reset_value;
210
210
+
return true;
211
211
+
case POLICY_EMULATE_WRITE:
212
212
+
if (slot == (uint64_t *)0) {
213
213
+
decision->action = POLICY_DENY_UNDEF;
214
214
+
return true;
215
215
+
}
216
216
+
*slot = operand & entry->writable_mask;
217
217
+
decision->value = *slot;
218
218
+
if (g_profile == POLICY_PROFILE_LINUX_BOOT && is_el1_mmu_key(access->key)) {
219
219
+
arch_sync_el1_sysregs(vcpu);
220
220
+
}
221
221
+
timer_vcpu_sync(vcpu);
222
222
+
return true;
223
223
+
case POLICY_WRITE_MASK:
224
224
+
if (slot == (uint64_t *)0) {
225
225
+
decision->action = POLICY_DENY_UNDEF;
226
226
+
return true;
227
227
+
}
228
228
+
*slot = (*slot & ~entry->writable_mask) | (operand & entry->writable_mask);
229
229
+
decision->value = *slot;
230
230
+
if (g_profile == POLICY_PROFILE_LINUX_BOOT && is_el1_mmu_key(access->key)) {
231
231
+
arch_sync_el1_sysregs(vcpu);
232
232
+
}
233
233
+
timer_vcpu_sync(vcpu);
234
234
+
return true;
235
235
+
case POLICY_DENY_SKIP:
236
236
+
case POLICY_DENY_UNDEF:
237
237
+
case POLICY_PAUSE:
238
238
+
case POLICY_PANIC:
239
239
+
case POLICY_ALLOW_NATIVE:
240
240
+
default:
241
241
+
return true;
242
242
+
}
243
243
+
}
244
244
+
245
245
+
void policy_dump(void)
246
246
+
{
247
247
+
uart_puts("policy profile=");
248
248
+
uart_puts(policy_profile_name(g_profile));
249
249
+
uart_puts("\n");
250
250
+
for (uint32_t i = 0; i < HV_ARRAY_SIZE(g_policy); i++) {
251
251
+
const struct policy_entry *entry = effective_entry(&g_policy[i]);
252
252
+
uart_puts("policy key=");
253
253
+
uart_put_hex64(entry->key);
254
254
+
uart_puts(" name=");
255
255
+
uart_puts(entry->name);
256
256
+
uart_puts(" read=");
257
257
+
uart_put_dec64((uint64_t)entry->read_policy);
258
258
+
uart_puts(" write=");
259
259
+
uart_put_dec64((uint64_t)entry->write_policy);
260
260
+
uart_puts(" mask=");
261
261
+
uart_put_hex64(entry->writable_mask);
262
262
+
uart_puts("\n");
263
263
+
}
264
264
+
}
265
265
+
266
266
+
bool policy_selftest(void)
267
267
+
{
268
268
+
enum policy_profile saved = g_profile;
269
269
+
bool profile_ok;
270
270
+
for (uint32_t i = 0; i < HV_ARRAY_SIZE(g_policy); i++) {
271
271
+
if (sysreg_policy_lookup(g_policy[i].key) != &g_policy[i]) {
272
272
+
return false;
273
273
+
}
274
274
+
for (uint32_t j = i + 1u; j < HV_ARRAY_SIZE(g_policy); j++) {
275
275
+
if (g_policy[i].key == g_policy[j].key) {
276
276
+
return false;
277
277
+
}
278
278
+
}
279
279
+
}
280
280
+
profile_ok = policy_set_profile_name("linux-boot") &&
281
281
+
policy_get_profile() == POLICY_PROFILE_LINUX_BOOT &&
282
282
+
policy_set_profile(saved);
283
283
+
return sysreg_policy_lookup(KEY(3, 4, 1, 1, 0)) != (const struct policy_entry *)0 &&
284
284
+
sysreg_policy_lookup(KEY(3, 7, 15, 15, 7)) == (const struct policy_entry *)0 &&
285
285
+
profile_ok;
286
286
+
}
···
1
1
+
#include "hv/arch.h"
2
2
+
#include "hv/log.h"
3
3
+
#include "hv/psci.h"
4
4
+
#include "hv/string.h"
5
5
+
#include "hv/uart.h"
6
6
+
7
7
+
#define PSCI32_VERSION 0x84000000ull
8
8
+
#define PSCI32_CPU_SUSPEND 0x84000001ull
9
9
+
#define PSCI32_CPU_OFF 0x84000002ull
10
10
+
#define PSCI32_CPU_ON 0x84000003ull
11
11
+
#define PSCI32_AFFINITY_INFO 0x84000004ull
12
12
+
#define PSCI32_SYSTEM_OFF 0x84000008ull
13
13
+
#define PSCI32_SYSTEM_RESET 0x84000009ull
14
14
+
#define PSCI32_FEATURES 0x8400000aull
15
15
+
#define PSCI64_CPU_SUSPEND 0xc4000001ull
16
16
+
#define PSCI64_CPU_ON 0xc4000003ull
17
17
+
#define PSCI64_AFFINITY_INFO 0xc4000004ull
18
18
+
19
19
+
#define PSCI_RET_SUCCESS 0ull
20
20
+
#define PSCI_RET_NOT_SUPPORTED UINT64_MAX
21
21
+
#define PSCI_RET_INVALID_PARAMETERS (~0ull - 1ull)
22
22
+
#define PSCI_RET_DENIED (~0ull - 2ull)
23
23
+
24
24
+
static uint64_t g_calls;
25
25
+
static uint64_t g_denied_cpu_on;
26
26
+
static uint64_t g_last_function;
27
27
+
28
28
+
static void log_psci(struct vcpu *vcpu, uint64_t fid, uint64_t ret)
29
29
+
{
30
30
+
struct log_event ev;
31
31
+
hv_memset(&ev, 0, sizeof(ev));
32
32
+
ev.kind = LOG_HVC;
33
33
+
ev.vcpu = vcpu != (struct vcpu *)0 ? vcpu->id : UINT64_MAX;
34
34
+
ev.operand = fid;
35
35
+
ev.result = ret;
36
36
+
ev.reason = 320u;
37
37
+
ev.name = "psci";
38
38
+
log_event_commit(&ev);
39
39
+
}
40
40
+
41
41
+
bool psci_handle_call(struct vcpu *vcpu, uint64_t function_id)
42
42
+
{
43
43
+
uint64_t ret = PSCI_RET_NOT_SUPPORTED;
44
44
+
45
45
+
if (vcpu == (struct vcpu *)0) {
46
46
+
return false;
47
47
+
}
48
48
+
49
49
+
g_calls++;
50
50
+
g_last_function = function_id;
51
51
+
switch (function_id) {
52
52
+
case PSCI32_VERSION:
53
53
+
ret = 0x00010001ull;
54
54
+
break;
55
55
+
case PSCI32_FEATURES: {
56
56
+
uint64_t query = vcpu_read_gpr(vcpu, 1u);
57
57
+
if (query == PSCI32_VERSION || query == PSCI32_FEATURES ||
58
58
+
query == PSCI32_AFFINITY_INFO || query == PSCI64_AFFINITY_INFO ||
59
59
+
query == PSCI32_SYSTEM_OFF || query == PSCI32_SYSTEM_RESET) {
60
60
+
ret = PSCI_RET_SUCCESS;
61
61
+
}
62
62
+
break;
63
63
+
}
64
64
+
case PSCI32_AFFINITY_INFO:
65
65
+
case PSCI64_AFFINITY_INFO:
66
66
+
ret = PSCI_RET_SUCCESS;
67
67
+
break;
68
68
+
case PSCI32_CPU_SUSPEND:
69
69
+
case PSCI64_CPU_SUSPEND:
70
70
+
ret = PSCI_RET_DENIED;
71
71
+
break;
72
72
+
case PSCI32_CPU_ON:
73
73
+
case PSCI64_CPU_ON:
74
74
+
g_denied_cpu_on++;
75
75
+
ret = PSCI_RET_DENIED;
76
76
+
break;
77
77
+
case PSCI32_CPU_OFF:
78
78
+
ret = PSCI_RET_DENIED;
79
79
+
break;
80
80
+
case PSCI32_SYSTEM_OFF:
81
81
+
case PSCI32_SYSTEM_RESET:
82
82
+
log_psci(vcpu, function_id, PSCI_RET_SUCCESS);
83
83
+
uart_puts("psci power request function=");
84
84
+
uart_put_hex64(function_id);
85
85
+
uart_puts("; halting\n");
86
86
+
arch_halt();
87
87
+
default:
88
88
+
ret = PSCI_RET_NOT_SUPPORTED;
89
89
+
break;
90
90
+
}
91
91
+
92
92
+
vcpu_write_gpr(vcpu, 0u, ret);
93
93
+
log_psci(vcpu, function_id, ret);
94
94
+
arch_advance_guest_pc(vcpu);
95
95
+
return true;
96
96
+
}
97
97
+
98
98
+
void psci_dump(void)
99
99
+
{
100
100
+
uart_puts("psci calls=");
101
101
+
uart_put_dec64(g_calls);
102
102
+
uart_puts(" denied_cpu_on=");
103
103
+
uart_put_dec64(g_denied_cpu_on);
104
104
+
uart_puts(" last=");
105
105
+
uart_put_hex64(g_last_function);
106
106
+
uart_puts("\n");
107
107
+
}
···
1
1
+
#include "hv/allocator.h"
2
2
+
#include "hv/arch.h"
3
3
+
#include "hv/config.h"
4
4
+
#include "hv/el2_mmu.h"
5
5
+
#include "hv/log.h"
6
6
+
#include "hv/panic.h"
7
7
+
#include "hv/policy.h"
8
8
+
#include "hv/selftest.h"
9
9
+
#include "hv/stage2.h"
10
10
+
#include "hv/sysreg.h"
11
11
+
12
12
+
static void require(bool ok, const char *name)
13
13
+
{
14
14
+
if (!ok) {
15
15
+
panic(name);
16
16
+
}
17
17
+
log_simple(LOG_SELFTEST, 0u, (uint64_t)(uintptr_t)name, 0u);
18
18
+
}
19
19
+
20
20
+
void selftests_run_or_panic(void)
21
21
+
{
22
22
+
require(hv_is_aligned_u64((uint64_t)(uintptr_t)__vectors_el2, 2048u), "selftest vectors alignment");
23
23
+
require(stage2_selftest(), "selftest stage2 descriptors");
24
24
+
require(el2_mmu_selftest(), "selftest el2 mmu plan");
25
25
+
require(CONFIG_GUEST_RAM_SIZE != 0u && hv_is_aligned_u64(CONFIG_GUEST_RAM_BASE, CONFIG_PAGE_SIZE),
26
26
+
"selftest guest memory bounds");
27
27
+
require(policy_selftest(), "selftest policy table");
28
28
+
require(sysreg_selftest(), "selftest sysreg decoder");
29
29
+
require(log_selftest(), "selftest log wraparound");
30
30
+
require(allocator_selftest(), "selftest allocator");
31
31
+
32
32
+
uint64_t hcr;
33
33
+
uint64_t sctlr;
34
34
+
uint64_t vttbr;
35
35
+
__asm__ volatile("mrs %0, hcr_el2" : "=r"(hcr));
36
36
+
__asm__ volatile("mrs %0, sctlr_el2" : "=r"(sctlr));
37
37
+
__asm__ volatile("mrs %0, vttbr_el2" : "=r"(vttbr));
38
38
+
require((hcr & HV_BIT(0)) != 0u && (hcr & HV_BIT(31)) != 0u, "selftest hcr trap sanity");
39
39
+
require((sctlr & (HV_BIT(0) | HV_BIT(2) | HV_BIT(12))) ==
40
40
+
(HV_BIT(0) | HV_BIT(2) | HV_BIT(12)), "selftest sctlr el2 mmu enabled");
41
41
+
require((vttbr & 0x0000fffffffff000ull) == stage2_vttbr(), "selftest vttbr root");
42
42
+
}
···
1
1
+
#include "hv/string.h"
2
2
+
3
3
+
void *hv_memset(void *dst, int value, size_t len)
4
4
+
{
5
5
+
unsigned char *p = (unsigned char *)dst;
6
6
+
while (len-- != 0u) {
7
7
+
*p++ = (unsigned char)value;
8
8
+
}
9
9
+
return dst;
10
10
+
}
11
11
+
12
12
+
void *hv_memcpy(void *dst, const void *src, size_t len)
13
13
+
{
14
14
+
unsigned char *d = (unsigned char *)dst;
15
15
+
const unsigned char *s = (const unsigned char *)src;
16
16
+
while (len-- != 0u) {
17
17
+
*d++ = *s++;
18
18
+
}
19
19
+
return dst;
20
20
+
}
21
21
+
22
22
+
void *hv_memmove(void *dst, const void *src, size_t len)
23
23
+
{
24
24
+
unsigned char *d = (unsigned char *)dst;
25
25
+
const unsigned char *s = (const unsigned char *)src;
26
26
+
if (d == s || len == 0u) {
27
27
+
return dst;
28
28
+
}
29
29
+
if (d < s) {
30
30
+
while (len-- != 0u) {
31
31
+
*d++ = *s++;
32
32
+
}
33
33
+
} else {
34
34
+
d += len;
35
35
+
s += len;
36
36
+
while (len-- != 0u) {
37
37
+
*--d = *--s;
38
38
+
}
39
39
+
}
40
40
+
return dst;
41
41
+
}
42
42
+
43
43
+
int hv_memcmp(const void *a, const void *b, size_t len)
44
44
+
{
45
45
+
const unsigned char *pa = (const unsigned char *)a;
46
46
+
const unsigned char *pb = (const unsigned char *)b;
47
47
+
for (size_t i = 0; i < len; i++) {
48
48
+
if (pa[i] != pb[i]) {
49
49
+
return (int)pa[i] - (int)pb[i];
50
50
+
}
51
51
+
}
52
52
+
return 0;
53
53
+
}
54
54
+
55
55
+
size_t hv_strlen(const char *s)
56
56
+
{
57
57
+
size_t n = 0;
58
58
+
while (s[n] != '\0') {
59
59
+
n++;
60
60
+
}
61
61
+
return n;
62
62
+
}
63
63
+
64
64
+
int hv_strcmp(const char *a, const char *b)
65
65
+
{
66
66
+
while (*a != '\0' && *a == *b) {
67
67
+
a++;
68
68
+
b++;
69
69
+
}
70
70
+
return (int)(unsigned char)*a - (int)(unsigned char)*b;
71
71
+
}
72
72
+
73
73
+
int hv_strncmp(const char *a, const char *b, size_t n)
74
74
+
{
75
75
+
for (size_t i = 0; i < n; i++) {
76
76
+
if (a[i] == '\0' || a[i] != b[i]) {
77
77
+
return (int)(unsigned char)a[i] - (int)(unsigned char)b[i];
78
78
+
}
79
79
+
}
80
80
+
return 0;
81
81
+
}
82
82
+
83
83
+
void *memset(void *dst, int value, size_t len)
84
84
+
{
85
85
+
return hv_memset(dst, value, len);
86
86
+
}
87
87
+
88
88
+
void *memcpy(void *dst, const void *src, size_t len)
89
89
+
{
90
90
+
return hv_memcpy(dst, src, len);
91
91
+
}
92
92
+
93
93
+
void *memmove(void *dst, const void *src, size_t len)
94
94
+
{
95
95
+
return hv_memmove(dst, src, len);
96
96
+
}
97
97
+
98
98
+
int memcmp(const void *a, const void *b, size_t len)
99
99
+
{
100
100
+
return hv_memcmp(a, b, len);
101
101
+
}
···
1
1
+
#include "hv/sysreg.h"
2
2
+
3
3
+
uint64_t sysreg_key_make(uint32_t op0, uint32_t op1, uint32_t crn, uint32_t crm, uint32_t op2)
4
4
+
{
5
5
+
return ((uint64_t)(op0 & 0x3u) << 14u) |
6
6
+
((uint64_t)(op1 & 0x7u) << 11u) |
7
7
+
((uint64_t)(crn & 0xfu) << 7u) |
8
8
+
((uint64_t)(crm & 0xfu) << 3u) |
9
9
+
(uint64_t)(op2 & 0x7u);
10
10
+
}
11
11
+
12
12
+
bool sysreg_decode_from_esr_iss(uint64_t iss, struct sysreg_access *out)
13
13
+
{
14
14
+
if (out == (struct sysreg_access *)0) {
15
15
+
return false;
16
16
+
}
17
17
+
out->op0 = (uint32_t)((iss >> 20u) & 0x3u);
18
18
+
out->op2 = (uint32_t)((iss >> 17u) & 0x7u);
19
19
+
out->op1 = (uint32_t)((iss >> 14u) & 0x7u);
20
20
+
out->crn = (uint32_t)((iss >> 10u) & 0xfu);
21
21
+
out->rt = (uint32_t)((iss >> 5u) & 0x1fu);
22
22
+
out->crm = (uint32_t)((iss >> 1u) & 0xfu);
23
23
+
out->is_read = ((iss & 1u) == ESR_SYSREG_DIR_READ);
24
24
+
out->key = sysreg_key_make(out->op0, out->op1, out->crn, out->crm, out->op2);
25
25
+
return true;
26
26
+
}
27
27
+
28
28
+
struct sysreg_name {
29
29
+
uint64_t key;
30
30
+
const char *name;
31
31
+
};
32
32
+
33
33
+
#define KEY(op0, op1, crn, crm, op2) SYSREG_KEY_CONST((op0), (op1), (crn), (crm), (op2))
34
34
+
35
35
+
static const struct sysreg_name g_names[] = {
36
36
+
{ KEY(3, 0, 0, 0, 0), "midr_el1" },
37
37
+
{ KEY(3, 0, 0, 0, 5), "mpidr_el1" },
38
38
+
{ KEY(3, 0, 0, 4, 0), "id_aa64pfr0_el1" },
39
39
+
{ KEY(3, 0, 0, 4, 1), "id_aa64pfr1_el1" },
40
40
+
{ KEY(3, 0, 0, 6, 0), "id_aa64isar0_el1" },
41
41
+
{ KEY(3, 0, 0, 6, 1), "id_aa64isar1_el1" },
42
42
+
{ KEY(3, 0, 0, 7, 0), "id_aa64mmfr0_el1" },
43
43
+
{ KEY(3, 0, 0, 7, 1), "id_aa64mmfr1_el1" },
44
44
+
{ KEY(3, 1, 0, 0, 1), "clidr_el1" },
45
45
+
{ KEY(3, 2, 0, 0, 0), "csselr_el1" },
46
46
+
{ KEY(3, 3, 0, 0, 1), "ctr_el0" },
47
47
+
{ KEY(3, 3, 0, 0, 7), "dczid_el0" },
48
48
+
{ KEY(3, 0, 1, 0, 0), "sctlr_el1" },
49
49
+
{ KEY(3, 0, 1, 0, 1), "actlr_el1" },
50
50
+
{ KEY(3, 0, 1, 0, 2), "cpacr_el1" },
51
51
+
{ KEY(3, 4, 1, 1, 0), "hcr_el2" },
52
52
+
{ KEY(3, 6, 1, 1, 0), "scr_el3" },
53
53
+
{ KEY(3, 0, 2, 0, 0), "ttbr0_el1" },
54
54
+
{ KEY(3, 0, 2, 0, 1), "ttbr1_el1" },
55
55
+
{ KEY(3, 0, 2, 0, 2), "tcr_el1" },
56
56
+
{ KEY(3, 4, 2, 1, 0), "vttbr_el2" },
57
57
+
{ KEY(3, 3, 9, 12, 0), "pmcr_el0" },
58
58
+
{ KEY(3, 0, 10, 2, 0), "mair_el1" },
59
59
+
{ KEY(3, 0, 12, 0, 0), "vbar_el1" },
60
60
+
{ KEY(3, 0, 12, 0, 1), "rvbar_el1" },
61
61
+
{ KEY(3, 0, 13, 0, 1), "contextidr_el1" },
62
62
+
{ KEY(3, 0, 13, 0, 4), "tpidr_el1" },
63
63
+
{ KEY(3, 3, 13, 0, 3), "tpidrro_el0" },
64
64
+
{ KEY(3, 0, 14, 1, 0), "cntkctl_el1" },
65
65
+
{ KEY(3, 3, 14, 3, 0), "cntv_tval_el0" },
66
66
+
{ KEY(3, 3, 14, 3, 1), "cntv_ctl_el0" },
67
67
+
{ KEY(3, 3, 14, 3, 2), "cntv_cval_el0" },
68
68
+
{ KEY(2, 0, 0, 2, 2), "mdscr_el1" },
69
69
+
};
70
70
+
71
71
+
const char *sysreg_key_name(uint64_t key)
72
72
+
{
73
73
+
for (uint32_t i = 0; i < HV_ARRAY_SIZE(g_names); i++) {
74
74
+
if (g_names[i].key == key) {
75
75
+
return g_names[i].name;
76
76
+
}
77
77
+
}
78
78
+
return "unknown";
79
79
+
}
80
80
+
81
81
+
bool sysreg_selftest(void)
82
82
+
{
83
83
+
struct sysreg_access a;
84
84
+
uint64_t iss = (3ull << 20u) | (0ull << 17u) | (0ull << 14u) |
85
85
+
(0ull << 10u) | (0ull << 5u) | (0ull << 1u) | 1ull;
86
86
+
if (!sysreg_decode_from_esr_iss(iss, &a)) {
87
87
+
return false;
88
88
+
}
89
89
+
return a.is_read && a.rt == 0u && a.key == KEY(3, 0, 0, 0, 0);
90
90
+
}
···
1
1
+
#include "hv/arch.h"
2
2
+
#include "hv/config.h"
3
3
+
#include "hv/gicv3.h"
4
4
+
#include "hv/log.h"
5
5
+
#include "hv/monitor.h"
6
6
+
#include "hv/panic.h"
7
7
+
#include "hv/policy.h"
8
8
+
#include "hv/psci.h"
9
9
+
#include "hv/stage2.h"
10
10
+
#include "hv/string.h"
11
11
+
#include "hv/sysreg.h"
12
12
+
#include "hv/timer.h"
13
13
+
#include "hv/trap.h"
14
14
+
#include "hv/uart.h"
15
15
+
16
16
+
#define HVC_GET_HV_ID 0u
17
17
+
#define HVC_DUMP_LOG 1u
18
18
+
#define HVC_GET_STATUS 2u
19
19
+
#define HVC_PAUSE 3u
20
20
+
#define HVC_GUEST_CONSOLE_WRITE 4u
21
21
+
#define HVC_REPORT_EXCEPTION 5u
22
22
+
#define HVC_ERR_UNKNOWN UINT64_MAX
23
23
+
24
24
+
static uint32_t action_to_log(enum policy_action action)
25
25
+
{
26
26
+
switch (action) {
27
27
+
case POLICY_EMULATE_READ: return LOG_ACT_EMULATE_READ;
28
28
+
case POLICY_EMULATE_WRITE: return LOG_ACT_EMULATE_WRITE;
29
29
+
case POLICY_WRITE_MASK: return LOG_ACT_WRITE_MASK;
30
30
+
case POLICY_DENY_SKIP: return LOG_ACT_DENY_SKIP;
31
31
+
case POLICY_DENY_UNDEF: return LOG_ACT_DENY_UNDEF;
32
32
+
case POLICY_PAUSE: return LOG_ACT_PAUSE;
33
33
+
case POLICY_PANIC: return LOG_ACT_PANIC;
34
34
+
case POLICY_ALLOW_NATIVE:
35
35
+
default: return LOG_ACT_NONE;
36
36
+
}
37
37
+
}
38
38
+
39
39
+
static void log_trap_event(const struct vcpu *vcpu, const struct trap_frame *frame,
40
40
+
const struct sysreg_access *access,
41
41
+
const struct policy_decision *decision,
42
42
+
uint64_t operand)
43
43
+
{
44
44
+
struct log_event ev;
45
45
+
hv_memset(&ev, 0, sizeof(ev));
46
46
+
ev.kind = LOG_TRAP;
47
47
+
ev.vcpu = vcpu->id;
48
48
+
ev.ec = esr_ec(frame->esr_el2);
49
49
+
ev.iss = frame->esr_el2 & 0x01ffffffu;
50
50
+
ev.elr = frame->elr_el2;
51
51
+
ev.far = frame->far_el2;
52
52
+
ev.hpfar = frame->hpfar_el2;
53
53
+
ev.pstate = frame->spsr_el2;
54
54
+
if (access != (const struct sysreg_access *)0) {
55
55
+
ev.sysreg_key = access->key;
56
56
+
ev.is_read = access->is_read ? 1u : 0u;
57
57
+
ev.rt = access->rt;
58
58
+
ev.name = decision->entry != (const struct policy_entry *)0 ?
59
59
+
decision->entry->name : sysreg_key_name(access->key);
60
60
+
}
61
61
+
if (decision != (const struct policy_decision *)0) {
62
62
+
ev.action = action_to_log(decision->action);
63
63
+
ev.result = decision->value;
64
64
+
ev.reason = decision->reason;
65
65
+
}
66
66
+
ev.operand = operand;
67
67
+
log_event_commit(&ev);
68
68
+
}
69
69
+
70
70
+
static bool guest_ptr_to_host(uint64_t ipa, uint64_t len, const char **out)
71
71
+
{
72
72
+
uint64_t end;
73
73
+
if (out == (const char **)0 || hv_add_overflow_u64(ipa, len, &end)) {
74
74
+
return false;
75
75
+
}
76
76
+
if (ipa < CONFIG_GUEST_IPA_BASE ||
77
77
+
end > (CONFIG_GUEST_IPA_BASE + CONFIG_GUEST_RAM_SIZE)) {
78
78
+
return false;
79
79
+
}
80
80
+
*out = (const char *)(uintptr_t)(CONFIG_GUEST_RAM_BASE + (ipa - CONFIG_GUEST_IPA_BASE));
81
81
+
return true;
82
82
+
}
83
83
+
84
84
+
static void handle_hvc(struct vcpu *vcpu)
85
85
+
{
86
86
+
uint64_t num = vcpu_read_gpr(vcpu, 0u);
87
87
+
vcpu->stats.hvc_calls++;
88
88
+
89
89
+
struct log_event ev;
90
90
+
hv_memset(&ev, 0, sizeof(ev));
91
91
+
ev.kind = LOG_HVC;
92
92
+
ev.vcpu = vcpu->id;
93
93
+
ev.ec = ESR_EC_HVC64;
94
94
+
ev.iss = vcpu->last_esr & 0x01ffffffu;
95
95
+
ev.elr = vcpu->pc;
96
96
+
ev.far = vcpu->last_far;
97
97
+
ev.hpfar = vcpu->last_hpfar;
98
98
+
ev.pstate = vcpu->pstate;
99
99
+
ev.operand = num;
100
100
+
ev.action = LOG_ACT_NONE;
101
101
+
ev.reason = 300u;
102
102
+
103
103
+
switch (num) {
104
104
+
case HVC_GET_HV_ID:
105
105
+
vcpu_write_gpr(vcpu, 0u, 0x415249454cull);
106
106
+
ev.result = 0x415249454cull;
107
107
+
break;
108
108
+
case HVC_DUMP_LOG:
109
109
+
log_dump(64u);
110
110
+
vcpu_write_gpr(vcpu, 0u, 0u);
111
111
+
break;
112
112
+
case HVC_GET_STATUS:
113
113
+
vcpu_write_gpr(vcpu, 0u, (uint64_t)vcpu->state);
114
114
+
ev.result = (uint64_t)vcpu->state;
115
115
+
break;
116
116
+
case HVC_PAUSE:
117
117
+
vcpu->state = VCPU_PAUSED;
118
118
+
vcpu_write_gpr(vcpu, 0u, 0u);
119
119
+
log_event_commit(&ev);
120
120
+
monitor_loop(vcpu, "guest requested pause");
121
121
+
return;
122
122
+
case HVC_GUEST_CONSOLE_WRITE: {
123
123
+
const char *s = (const char *)0;
124
124
+
uint64_t ptr = vcpu_read_gpr(vcpu, 1u);
125
125
+
uint64_t len = vcpu_read_gpr(vcpu, 2u);
126
126
+
if (len > 256u || !guest_ptr_to_host(ptr, len, &s)) {
127
127
+
vcpu_write_gpr(vcpu, 0u, HVC_ERR_UNKNOWN);
128
128
+
ev.reason = 301u;
129
129
+
break;
130
130
+
}
131
131
+
uart_puts("guest: ");
132
132
+
for (uint64_t i = 0; i < len; i++) {
133
133
+
uart_putc(s[i]);
134
134
+
}
135
135
+
uart_puts("\n");
136
136
+
vcpu_write_gpr(vcpu, 0u, 0u);
137
137
+
break;
138
138
+
}
139
139
+
case HVC_REPORT_EXCEPTION: {
140
140
+
uint64_t guest_esr = vcpu_read_gpr(vcpu, 1u);
141
141
+
uint64_t guest_elr = vcpu_read_gpr(vcpu, 2u);
142
142
+
uint64_t guest_far = vcpu_read_gpr(vcpu, 3u);
143
143
+
struct log_event ge;
144
144
+
hv_memset(&ge, 0, sizeof(ge));
145
145
+
ge.kind = LOG_ABORT;
146
146
+
ge.vcpu = vcpu->id;
147
147
+
ge.ec = esr_ec(guest_esr);
148
148
+
ge.iss = guest_esr & 0x01ffffffu;
149
149
+
ge.elr = guest_elr;
150
150
+
ge.far = guest_far;
151
151
+
ge.action = LOG_ACT_NONE;
152
152
+
ge.reason = 303u;
153
153
+
ge.pstate = vcpu->pstate;
154
154
+
ge.name = "guest_exception_report";
155
155
+
log_event_commit(&ge);
156
156
+
vcpu_write_gpr(vcpu, 0u, 0u);
157
157
+
break;
158
158
+
}
159
159
+
default:
160
160
+
if ((num & 0xffff0000ull) == 0x84000000ull ||
161
161
+
(num & 0xffff0000ull) == 0xc4000000ull) {
162
162
+
log_event_commit(&ev);
163
163
+
(void)psci_handle_call(vcpu, num);
164
164
+
return;
165
165
+
}
166
166
+
vcpu_write_gpr(vcpu, 0u, HVC_ERR_UNKNOWN);
167
167
+
ev.reason = 302u;
168
168
+
break;
169
169
+
}
170
170
+
171
171
+
log_event_commit(&ev);
172
172
+
}
173
173
+
174
174
+
static void handle_sysreg(struct vcpu *vcpu, const struct trap_frame *frame)
175
175
+
{
176
176
+
struct sysreg_access access;
177
177
+
struct policy_decision decision;
178
178
+
uint64_t operand = 0;
179
179
+
180
180
+
if (!sysreg_decode_from_esr_iss(frame->esr_el2 & 0x01ffffffu, &access)) {
181
181
+
panic("failed to decode sysreg iss");
182
182
+
}
183
183
+
184
184
+
if (!access.is_read) {
185
185
+
operand = vcpu_read_gpr(vcpu, access.rt);
186
186
+
}
187
187
+
188
188
+
if (!policy_apply_sysreg(vcpu, &access, operand, &decision)) {
189
189
+
panic("policy engine failed");
190
190
+
}
191
191
+
192
192
+
if (access.is_read && decision.action == POLICY_EMULATE_READ) {
193
193
+
vcpu_write_gpr(vcpu, access.rt, decision.value);
194
194
+
}
195
195
+
196
196
+
log_trap_event(vcpu, frame, &access, &decision, operand);
197
197
+
vcpu->stats.sysreg_traps++;
198
198
+
199
199
+
switch (decision.action) {
200
200
+
case POLICY_EMULATE_READ:
201
201
+
case POLICY_EMULATE_WRITE:
202
202
+
case POLICY_WRITE_MASK:
203
203
+
case POLICY_DENY_SKIP:
204
204
+
arch_advance_guest_pc(vcpu);
205
205
+
break;
206
206
+
case POLICY_DENY_UNDEF:
207
207
+
arch_inject_guest_undef(vcpu);
208
208
+
if (vcpu->state == VCPU_PAUSED) {
209
209
+
monitor_loop(vcpu, "policy could not inject undefined instruction");
210
210
+
}
211
211
+
break;
212
212
+
case POLICY_PAUSE:
213
213
+
vcpu->state = VCPU_PAUSED;
214
214
+
monitor_loop(vcpu, "policy pause");
215
215
+
break;
216
216
+
case POLICY_PANIC:
217
217
+
panic("policy panic action");
218
218
+
case POLICY_ALLOW_NATIVE:
219
219
+
default:
220
220
+
panic("unsafe native sysreg policy");
221
221
+
}
222
222
+
}
223
223
+
224
224
+
void trap_handle_lower_sync(struct trap_frame *frame)
225
225
+
{
226
226
+
struct vcpu *vcpu = vcpu_current();
227
227
+
if (vcpu == (struct vcpu *)0) {
228
228
+
panic("trap without current vcpu");
229
229
+
}
230
230
+
vcpu_load_frame(vcpu, frame);
231
231
+
gicv3_sync_vcpu_state(vcpu);
232
232
+
vcpu->stats.traps++;
233
233
+
vcpu->state = VCPU_RUNNING;
234
234
+
235
235
+
uint32_t ec = esr_ec(frame->esr_el2);
236
236
+
switch (ec) {
237
237
+
case ESR_EC_SYSREG:
238
238
+
handle_sysreg(vcpu, frame);
239
239
+
break;
240
240
+
case ESR_EC_HVC64:
241
241
+
handle_hvc(vcpu);
242
242
+
break;
243
243
+
case ESR_EC_SMC64: {
244
244
+
uint64_t function_id = vcpu_read_gpr(vcpu, 0u);
245
245
+
if ((function_id & 0xffff0000ull) == 0x84000000ull ||
246
246
+
(function_id & 0xffff0000ull) == 0xc4000000ull) {
247
247
+
(void)psci_handle_call(vcpu, function_id);
248
248
+
} else {
249
249
+
vcpu->stats.smc_denied++;
250
250
+
struct policy_decision d;
251
251
+
hv_memset(&d, 0, sizeof(d));
252
252
+
d.action = POLICY_DENY_UNDEF;
253
253
+
d.reason = 400u;
254
254
+
log_trap_event(vcpu, frame, (const struct sysreg_access *)0, &d, 0u);
255
255
+
arch_inject_guest_undef(vcpu);
256
256
+
if (vcpu->state == VCPU_PAUSED) {
257
257
+
monitor_loop(vcpu, "guest smc denied");
258
258
+
}
259
259
+
}
260
260
+
break;
261
261
+
}
262
262
+
case ESR_EC_WFI_WFE:
263
263
+
vcpu->stats.wfx_traps++;
264
264
+
log_simple(LOG_TRAP, 401u, frame->esr_el2, frame->elr_el2);
265
265
+
arch_advance_guest_pc(vcpu);
266
266
+
break;
267
267
+
case ESR_EC_IABT_LOWER:
268
268
+
vcpu->stats.instruction_aborts++;
269
269
+
if (stage2_handle_abort(vcpu, frame, true)) {
270
270
+
break;
271
271
+
}
272
272
+
monitor_loop(vcpu, "guest instruction abort");
273
273
+
break;
274
274
+
case ESR_EC_DABT_LOWER:
275
275
+
vcpu->stats.data_aborts++;
276
276
+
if (stage2_handle_abort(vcpu, frame, false)) {
277
277
+
break;
278
278
+
}
279
279
+
monitor_loop(vcpu, "guest data abort");
280
280
+
break;
281
281
+
case ESR_EC_BRK64:
282
282
+
case ESR_EC_UNKNOWN:
283
283
+
default:
284
284
+
vcpu->stats.unknown_exceptions++;
285
285
+
log_simple(LOG_TRAP, 404u, frame->esr_el2, frame->elr_el2);
286
286
+
monitor_loop(vcpu, "guest unknown or brk exception");
287
287
+
break;
288
288
+
}
289
289
+
290
290
+
timer_vcpu_sync(vcpu);
291
291
+
gicv3_flush_vcpu_state(vcpu);
292
292
+
vcpu_store_frame(vcpu, frame);
293
293
+
}
294
294
+
295
295
+
void trap_handle_current_sync(struct trap_frame *frame)
296
296
+
{
297
297
+
panic_with_code("unexpected EL2 synchronous exception", frame != (struct trap_frame *)0 ? frame->esr_el2 : 0u);
298
298
+
}
299
299
+
300
300
+
void trap_handle_irq(struct trap_frame *frame)
301
301
+
{
302
302
+
uint32_t irq = gicv3_ack_irq();
303
303
+
struct log_event ev;
304
304
+
hv_memset(&ev, 0, sizeof(ev));
305
305
+
ev.kind = LOG_TRAP;
306
306
+
ev.vcpu = vcpu_current() != (struct vcpu *)0 ? vcpu_current()->id : UINT64_MAX;
307
307
+
ev.ec = 0xffu;
308
308
+
ev.iss = irq;
309
309
+
ev.elr = frame != (struct trap_frame *)0 ? frame->elr_el2 : 0u;
310
310
+
ev.pstate = frame != (struct trap_frame *)0 ? frame->spsr_el2 : 0u;
311
311
+
ev.reason = irq >= 1020u ? 501u : 500u;
312
312
+
log_event_commit(&ev);
313
313
+
if (irq < 1020u) {
314
314
+
gicv3_eoi(irq);
315
315
+
}
316
316
+
}
···
1
1
+
#include "hv/config.h"
2
2
+
#include "hv/arch.h"
3
3
+
#include "hv/panic.h"
4
4
+
#include "hv/string.h"
5
5
+
#include "hv/uart.h"
6
6
+
#include "hv/vcpu.h"
7
7
+
8
8
+
_Static_assert(offsetof(struct trap_frame, x) == 0u, "trap_frame x offset");
9
9
+
_Static_assert(offsetof(struct trap_frame, sp_el0) == 248u, "trap_frame sp_el0 offset");
10
10
+
_Static_assert(offsetof(struct trap_frame, sp_el1) == 256u, "trap_frame sp_el1 offset");
11
11
+
_Static_assert(offsetof(struct trap_frame, elr_el2) == 264u, "trap_frame elr offset");
12
12
+
_Static_assert(offsetof(struct trap_frame, spsr_el2) == 272u, "trap_frame spsr offset");
13
13
+
_Static_assert(offsetof(struct trap_frame, esr_el2) == 280u, "trap_frame esr offset");
14
14
+
_Static_assert(offsetof(struct trap_frame, far_el2) == 288u, "trap_frame far offset");
15
15
+
_Static_assert(offsetof(struct trap_frame, hpfar_el2) == 296u, "trap_frame hpfar offset");
16
16
+
_Static_assert(sizeof(struct trap_frame) == 304u, "trap_frame size");
17
17
+
18
18
+
_Static_assert(offsetof(struct vcpu, x) == 0u, "vcpu x offset");
19
19
+
_Static_assert(offsetof(struct vcpu, sp_el0) == 248u, "vcpu sp_el0 offset");
20
20
+
_Static_assert(offsetof(struct vcpu, sp_el1) == 256u, "vcpu sp_el1 offset");
21
21
+
_Static_assert(offsetof(struct vcpu, pc) == 264u, "vcpu pc offset");
22
22
+
_Static_assert(offsetof(struct vcpu, pstate) == 272u, "vcpu pstate offset");
23
23
+
24
24
+
static struct vcpu *g_current_vcpu;
25
25
+
26
26
+
void vcpu_init(struct vcpu *vcpu, uint32_t id, uint64_t entry, uint64_t stack_top)
27
27
+
{
28
28
+
BUG_ON(vcpu == (struct vcpu *)0);
29
29
+
hv_memset(vcpu, 0, sizeof(*vcpu));
30
30
+
vcpu->id = id;
31
31
+
vcpu->state = VCPU_CREATED;
32
32
+
vcpu->pc = entry;
33
33
+
vcpu->pstate = 0x3c5u;
34
34
+
vcpu->sp_el1 = stack_top;
35
35
+
vcpu->sysregs.sctlr_el1 = 0x30d00800ull;
36
36
+
vcpu->sysregs.mair_el1 = 0xffull;
37
37
+
vcpu->sysregs.cntkctl_el1 = 0u;
38
38
+
vcpu->pending_virtual_irq = 0u;
39
39
+
vcpu->active_virtual_irq = 0u;
40
40
+
vcpu->state = VCPU_READY;
41
41
+
}
42
42
+
43
43
+
void vcpu_load_frame(struct vcpu *vcpu, const struct trap_frame *frame)
44
44
+
{
45
45
+
BUG_ON(vcpu == (struct vcpu *)0 || frame == (const struct trap_frame *)0);
46
46
+
for (uint32_t i = 0; i < 31u; i++) {
47
47
+
vcpu->x[i] = frame->x[i];
48
48
+
}
49
49
+
vcpu->sp_el0 = frame->sp_el0;
50
50
+
vcpu->sp_el1 = frame->sp_el1;
51
51
+
vcpu->pc = frame->elr_el2;
52
52
+
vcpu->pstate = frame->spsr_el2;
53
53
+
vcpu->last_esr = frame->esr_el2;
54
54
+
vcpu->last_far = frame->far_el2;
55
55
+
vcpu->last_hpfar = frame->hpfar_el2;
56
56
+
arch_capture_el1_sysregs(vcpu);
57
57
+
}
58
58
+
59
59
+
void vcpu_store_frame(const struct vcpu *vcpu, struct trap_frame *frame)
60
60
+
{
61
61
+
BUG_ON(vcpu == (const struct vcpu *)0 || frame == (struct trap_frame *)0);
62
62
+
for (uint32_t i = 0; i < 31u; i++) {
63
63
+
frame->x[i] = vcpu->x[i];
64
64
+
}
65
65
+
frame->sp_el0 = vcpu->sp_el0;
66
66
+
frame->sp_el1 = vcpu->sp_el1;
67
67
+
frame->elr_el2 = vcpu->pc;
68
68
+
frame->spsr_el2 = vcpu->pstate;
69
69
+
}
70
70
+
71
71
+
uint64_t vcpu_read_gpr(const struct vcpu *vcpu, uint32_t rt)
72
72
+
{
73
73
+
BUG_ON(vcpu == (const struct vcpu *)0);
74
74
+
if (rt >= 31u) {
75
75
+
return 0u;
76
76
+
}
77
77
+
return vcpu->x[rt];
78
78
+
}
79
79
+
80
80
+
void vcpu_write_gpr(struct vcpu *vcpu, uint32_t rt, uint64_t value)
81
81
+
{
82
82
+
BUG_ON(vcpu == (struct vcpu *)0);
83
83
+
if (rt < 31u) {
84
84
+
vcpu->x[rt] = value;
85
85
+
}
86
86
+
}
87
87
+
88
88
+
void vcpu_set_pending_irq(struct vcpu *vcpu, uint32_t intid)
89
89
+
{
90
90
+
BUG_ON(vcpu == (struct vcpu *)0);
91
91
+
if (intid < 64u) {
92
92
+
vcpu->pending_virtual_irq |= (1ull << intid);
93
93
+
}
94
94
+
}
95
95
+
96
96
+
void vcpu_clear_pending_irq(struct vcpu *vcpu, uint32_t intid)
97
97
+
{
98
98
+
BUG_ON(vcpu == (struct vcpu *)0);
99
99
+
if (intid < 64u) {
100
100
+
vcpu->pending_virtual_irq &= ~(1ull << intid);
101
101
+
}
102
102
+
}
103
103
+
104
104
+
struct vcpu *vcpu_current(void)
105
105
+
{
106
106
+
return g_current_vcpu;
107
107
+
}
108
108
+
109
109
+
void vcpu_set_current(struct vcpu *vcpu)
110
110
+
{
111
111
+
g_current_vcpu = vcpu;
112
112
+
}
113
113
+
114
114
+
void vcpu_dump(const struct vcpu *vcpu)
115
115
+
{
116
116
+
if (vcpu == (const struct vcpu *)0) {
117
117
+
uart_puts("vcpu none\n");
118
118
+
return;
119
119
+
}
120
120
+
uart_puts("vcpu id=");
121
121
+
uart_put_dec64(vcpu->id);
122
122
+
uart_puts(" state=");
123
123
+
uart_put_dec64((uint64_t)vcpu->state);
124
124
+
uart_puts(" pc=");
125
125
+
uart_put_hex64(vcpu->pc);
126
126
+
uart_puts(" pstate=");
127
127
+
uart_put_hex64(vcpu->pstate);
128
128
+
uart_puts(" sp_el1=");
129
129
+
uart_put_hex64(vcpu->sp_el1);
130
130
+
uart_puts(" traps=");
131
131
+
uart_put_dec64(vcpu->stats.traps);
132
132
+
uart_puts(" injected_undefs=");
133
133
+
uart_put_dec64(vcpu->stats.injected_undefs);
134
134
+
uart_puts(" pending_irq=");
135
135
+
uart_put_hex64(vcpu->pending_virtual_irq);
136
136
+
uart_puts(" virq_inj=");
137
137
+
uart_put_dec64(vcpu->stats.virtual_irqs_injected);
138
138
+
uart_puts(" virq_done=");
139
139
+
uart_put_dec64(vcpu->stats.virtual_irqs_completed);
140
140
+
uart_puts("\n");
141
141
+
for (uint32_t i = 0; i < 31u; i++) {
142
142
+
uart_puts("x");
143
143
+
uart_put_dec64(i);
144
144
+
uart_puts("=");
145
145
+
uart_put_hex64(vcpu->x[i]);
146
146
+
uart_puts((i % 4u) == 3u ? "\n" : " ");
147
147
+
}
148
148
+
uart_puts("\n");
149
149
+
}
···
1
1
+
#include "hv/config.h"
2
2
+
#include "hv/gicv3.h"
3
3
+
#include "hv/log.h"
4
4
+
#include "hv/mmio.h"
5
5
+
#include "hv/uart.h"
6
6
+
#include "hv/vcpu.h"
7
7
+
8
8
+
#define GICD_CTLR 0x0000u
9
9
+
#define GICD_TYPER 0x0004u
10
10
+
#define GICR_CTLR 0x0000u
11
11
+
#define GICR_WAKER 0x0014u
12
12
+
#define GICR_WAKER_PROCESSOR_SLEEP (1u << 1)
13
13
+
#define GICR_WAKER_CHILDREN_ASLEEP (1u << 2)
14
14
+
15
15
+
static uintptr_t gicd(uint32_t off)
16
16
+
{
17
17
+
return (uintptr_t)(CONFIG_GICD_BASE + (uint64_t)off);
18
18
+
}
19
19
+
20
20
+
static uintptr_t gicr(uint32_t off)
21
21
+
{
22
22
+
return (uintptr_t)(CONFIG_GICR_BASE + (uint64_t)off);
23
23
+
}
24
24
+
25
25
+
void gicv3_init(void)
26
26
+
{
27
27
+
uint32_t typer = mmio_read32(gicd(GICD_TYPER));
28
28
+
mmio_write32(gicd(GICD_CTLR), 0u);
29
29
+
30
30
+
uint32_t waker = mmio_read32(gicr(GICR_WAKER));
31
31
+
waker &= ~GICR_WAKER_PROCESSOR_SLEEP;
32
32
+
mmio_write32(gicr(GICR_WAKER), waker);
33
33
+
for (uint32_t i = 0; i < 100000u; i++) {
34
34
+
if ((mmio_read32(gicr(GICR_WAKER)) & GICR_WAKER_CHILDREN_ASLEEP) == 0u) {
35
35
+
break;
36
36
+
}
37
37
+
}
38
38
+
39
39
+
__asm__ volatile(
40
40
+
"msr ICC_SRE_EL2, %0\n"
41
41
+
"isb\n"
42
42
+
"msr ICC_SRE_EL1, %0\n"
43
43
+
"isb\n"
44
44
+
"msr ICC_PMR_EL1, %1\n"
45
45
+
"msr ICC_IGRPEN1_EL1, %0\n"
46
46
+
"isb\n"
47
47
+
:: "r"(1ull), "r"(0xffull)
48
48
+
: "memory");
49
49
+
50
50
+
mmio_write32(gicd(GICD_CTLR), 0x3u);
51
51
+
log_simple(LOG_BOOT, 20u, typer, 0u);
52
52
+
gicv3_vcpu_init();
53
53
+
}
54
54
+
55
55
+
void gicv3_dump(void)
56
56
+
{
57
57
+
uart_puts("gicv3 gicd=");
58
58
+
uart_put_hex64(CONFIG_GICD_BASE);
59
59
+
uart_puts(" gicr=");
60
60
+
uart_put_hex64(CONFIG_GICR_BASE);
61
61
+
uart_puts(" typer=");
62
62
+
uart_put_hex64(mmio_read32(gicd(GICD_TYPER)));
63
63
+
uart_puts("\n");
64
64
+
}
65
65
+
66
66
+
uint32_t gicv3_ack_irq(void)
67
67
+
{
68
68
+
uint64_t irq;
69
69
+
__asm__ volatile("mrs %0, ICC_IAR1_EL1" : "=r"(irq));
70
70
+
return (uint32_t)(irq & 0x3ffu);
71
71
+
}
72
72
+
73
73
+
void gicv3_eoi(uint32_t irq)
74
74
+
{
75
75
+
__asm__ volatile("msr ICC_EOIR1_EL1, %0\nisb" :: "r"((uint64_t)irq) : "memory");
76
76
+
}
77
77
+
78
78
+
void gicv3_vcpu_init(void)
79
79
+
{
80
80
+
__asm__ volatile(
81
81
+
"msr ICH_HCR_EL2, %0\n"
82
82
+
"msr ICH_VMCR_EL2, %1\n"
83
83
+
"msr ICH_LR0_EL2, xzr\n"
84
84
+
"isb\n"
85
85
+
:: "r"(1ull), "r"(0xff0000ull)
86
86
+
: "memory");
87
87
+
}
88
88
+
89
89
+
void gicv3_sync_vcpu_state(struct vcpu *vcpu)
90
90
+
{
91
91
+
uint64_t lr;
92
92
+
uint64_t state;
93
93
+
94
94
+
if (vcpu == (struct vcpu *)0 || vcpu->active_virtual_irq == 0u) {
95
95
+
return;
96
96
+
}
97
97
+
98
98
+
__asm__ volatile("mrs %0, ICH_LR0_EL2" : "=r"(lr));
99
99
+
state = (lr >> 62u) & 0x3u;
100
100
+
if (state == 0u) {
101
101
+
vcpu_clear_pending_irq(vcpu, (uint32_t)vcpu->active_virtual_irq);
102
102
+
vcpu->active_virtual_irq = 0u;
103
103
+
vcpu->stats.virtual_irqs_completed++;
104
104
+
}
105
105
+
}
106
106
+
107
107
+
void gicv3_flush_vcpu_state(struct vcpu *vcpu)
108
108
+
{
109
109
+
if (vcpu == (struct vcpu *)0) {
110
110
+
return;
111
111
+
}
112
112
+
113
113
+
if ((vcpu->pending_virtual_irq & (1ull << CONFIG_VTIMER_IRQ)) == 0u) {
114
114
+
vcpu->active_virtual_irq = 0u;
115
115
+
__asm__ volatile("msr ICH_LR0_EL2, xzr\nisb" ::: "memory");
116
116
+
return;
117
117
+
}
118
118
+
119
119
+
uint64_t lr = (uint64_t)CONFIG_VTIMER_IRQ | (1ull << 62u) | (1ull << 60u);
120
120
+
if (vcpu->active_virtual_irq != CONFIG_VTIMER_IRQ) {
121
121
+
vcpu->stats.virtual_irqs_injected++;
122
122
+
}
123
123
+
vcpu->active_virtual_irq = CONFIG_VTIMER_IRQ;
124
124
+
__asm__ volatile("msr ICH_LR0_EL2, %0\nisb" :: "r"(lr) : "memory");
125
125
+
}
···
1
1
+
#include "hv/config.h"
2
2
+
#include "hv/mmio.h"
3
3
+
#include "hv/uart.h"
4
4
+
5
5
+
#define UART_DR 0x000u
6
6
+
#define UART_FR 0x018u
7
7
+
#define UART_IBRD 0x024u
8
8
+
#define UART_FBRD 0x028u
9
9
+
#define UART_LCRH 0x02cu
10
10
+
#define UART_CR 0x030u
11
11
+
#define UART_IMSC 0x038u
12
12
+
#define UART_ICR 0x044u
13
13
+
#define UART_FR_TXFF (1u << 5)
14
14
+
#define UART_FR_RXFE (1u << 4)
15
15
+
16
16
+
static uintptr_t uart_addr(uint32_t off)
17
17
+
{
18
18
+
return (uintptr_t)(CONFIG_UART_BASE + (uint64_t)off);
19
19
+
}
20
20
+
21
21
+
void uart_init(void)
22
22
+
{
23
23
+
mmio_write32(uart_addr(UART_CR), 0u);
24
24
+
mmio_write32(uart_addr(UART_ICR), 0x7ffu);
25
25
+
mmio_write32(uart_addr(UART_IBRD), 1u);
26
26
+
mmio_write32(uart_addr(UART_FBRD), 40u);
27
27
+
mmio_write32(uart_addr(UART_LCRH), (3u << 5));
28
28
+
mmio_write32(uart_addr(UART_IMSC), 0u);
29
29
+
mmio_write32(uart_addr(UART_CR), (1u << 9) | (1u << 8) | 1u);
30
30
+
}
31
31
+
32
32
+
void uart_putc(char c)
33
33
+
{
34
34
+
if (c == '\n') {
35
35
+
uart_putc('\r');
36
36
+
}
37
37
+
while ((mmio_read32(uart_addr(UART_FR)) & UART_FR_TXFF) != 0u) {
38
38
+
}
39
39
+
mmio_write32(uart_addr(UART_DR), (uint32_t)(unsigned char)c);
40
40
+
}
41
41
+
42
42
+
void uart_puts(const char *s)
43
43
+
{
44
44
+
while (*s != '\0') {
45
45
+
uart_putc(*s++);
46
46
+
}
47
47
+
}
48
48
+
49
49
+
void uart_put_hex64(uint64_t value)
50
50
+
{
51
51
+
static const char hex[] = "0123456789abcdef";
52
52
+
uart_puts("0x");
53
53
+
for (int shift = 60; shift >= 0; shift -= 4) {
54
54
+
uart_putc(hex[(value >> (unsigned)shift) & 0xfu]);
55
55
+
}
56
56
+
}
57
57
+
58
58
+
void uart_put_dec64(uint64_t value)
59
59
+
{
60
60
+
char buf[21];
61
61
+
unsigned pos = 0;
62
62
+
if (value == 0u) {
63
63
+
uart_putc('0');
64
64
+
return;
65
65
+
}
66
66
+
while (value != 0u && pos < sizeof(buf)) {
67
67
+
buf[pos++] = (char)('0' + (value % 10u));
68
68
+
value /= 10u;
69
69
+
}
70
70
+
while (pos != 0u) {
71
71
+
uart_putc(buf[--pos]);
72
72
+
}
73
73
+
}
74
74
+
75
75
+
bool uart_getc_nonblocking(char *out)
76
76
+
{
77
77
+
if ((mmio_read32(uart_addr(UART_FR)) & UART_FR_RXFE) != 0u) {
78
78
+
return false;
79
79
+
}
80
80
+
*out = (char)(mmio_read32(uart_addr(UART_DR)) & 0xffu);
81
81
+
return true;
82
82
+
}
···
1
1
+
#include "hv/arch.h"
2
2
+
#include "hv/config.h"
3
3
+
#include "hv/timer.h"
4
4
+
#include "hv/uart.h"
5
5
+
#include "hv/vcpu.h"
6
6
+
7
7
+
static uint64_t g_cntfrq;
8
8
+
9
9
+
void timer_init(void)
10
10
+
{
11
11
+
g_cntfrq = arch_cntfrq_el0();
12
12
+
}
13
13
+
14
14
+
uint64_t timer_now(void)
15
15
+
{
16
16
+
return arch_cntpct_el0();
17
17
+
}
18
18
+
19
19
+
void timer_dump(void)
20
20
+
{
21
21
+
uart_puts("timer cntfrq=");
22
22
+
uart_put_dec64(g_cntfrq);
23
23
+
uart_puts(" cntpct=");
24
24
+
uart_put_dec64(timer_now());
25
25
+
uart_puts("\n");
26
26
+
}
27
27
+
28
28
+
void timer_vcpu_sync(struct vcpu *vcpu)
29
29
+
{
30
30
+
if (vcpu == (struct vcpu *)0) {
31
31
+
return;
32
32
+
}
33
33
+
34
34
+
uint64_t ctl = vcpu->sysregs.cntv_ctl_el0;
35
35
+
bool enabled = (ctl & 1u) != 0u;
36
36
+
bool masked = (ctl & 2u) != 0u;
37
37
+
if (!enabled || masked) {
38
38
+
vcpu_clear_pending_irq(vcpu, CONFIG_VTIMER_IRQ);
39
39
+
return;
40
40
+
}
41
41
+
42
42
+
if (timer_now() >= vcpu->sysregs.cntv_cval_el0) {
43
43
+
vcpu->sysregs.cntv_ctl_el0 |= 4u;
44
44
+
vcpu_set_pending_irq(vcpu, CONFIG_VTIMER_IRQ);
45
45
+
} else {
46
46
+
vcpu->sysregs.cntv_ctl_el0 &= ~4ull;
47
47
+
vcpu_clear_pending_irq(vcpu, CONFIG_VTIMER_IRQ);
48
48
+
}
49
49
+
}
···
1
1
+
OUTPUT_ARCH(aarch64)
2
2
+
ENTRY(_guest_start)
3
3
+
4
4
+
GUEST_BASE = 0x40000000;
5
5
+
6
6
+
SECTIONS
7
7
+
{
8
8
+
. = GUEST_BASE;
9
9
+
__guest_start_addr = .;
10
10
+
11
11
+
.text : ALIGN(4096) {
12
12
+
KEEP(*(.text.entry))
13
13
+
KEEP(*(.text.vectors))
14
14
+
*(.text .text.*)
15
15
+
}
16
16
+
17
17
+
.rodata : ALIGN(16) {
18
18
+
*(.rodata .rodata.*)
19
19
+
}
20
20
+
21
21
+
.data : ALIGN(16) {
22
22
+
*(.data .data.*)
23
23
+
}
24
24
+
25
25
+
.bss : ALIGN(16) {
26
26
+
__guest_bss_start = .;
27
27
+
*(.bss .bss.* COMMON)
28
28
+
__guest_bss_end = .;
29
29
+
}
30
30
+
31
31
+
. = ALIGN(4096);
32
32
+
__guest_image_end = .;
33
33
+
}
···
1
1
+
#include <stdint.h>
2
2
+
#include <stddef.h>
3
3
+
4
4
+
void guest_main(void);
5
5
+
uint64_t guest_hvc_call(uint64_t num, uint64_t a1, uint64_t a2);
6
6
+
7
7
+
static size_t guest_strlen(const char *s)
8
8
+
{
9
9
+
size_t n = 0;
10
10
+
while (s[n] != '\0') {
11
11
+
n++;
12
12
+
}
13
13
+
return n;
14
14
+
}
15
15
+
16
16
+
static uint64_t hvc_call(uint64_t num, uint64_t a1, uint64_t a2)
17
17
+
{
18
18
+
return guest_hvc_call(num, a1, a2);
19
19
+
}
20
20
+
21
21
+
static void console(const char *s)
22
22
+
{
23
23
+
(void)hvc_call(4u, (uint64_t)(uintptr_t)s, guest_strlen(s));
24
24
+
}
25
25
+
26
26
+
static uint64_t read_midr(void)
27
27
+
{
28
28
+
uint64_t v;
29
29
+
__asm__ volatile("mrs %0, midr_el1" : "=r"(v));
30
30
+
return v;
31
31
+
}
32
32
+
33
33
+
static uint64_t read_pfr0(void)
34
34
+
{
35
35
+
uint64_t v;
36
36
+
__asm__ volatile("mrs %0, id_aa64pfr0_el1" : "=r"(v));
37
37
+
return v;
38
38
+
}
39
39
+
40
40
+
static uint64_t read_cntv_ctl(void)
41
41
+
{
42
42
+
uint64_t v;
43
43
+
__asm__ volatile("mrs %0, cntv_ctl_el0" : "=r"(v));
44
44
+
return v;
45
45
+
}
46
46
+
47
47
+
static void write_sctlr(uint64_t v)
48
48
+
{
49
49
+
__asm__ volatile("msr sctlr_el1, %0" :: "r"(v) : "memory");
50
50
+
}
51
51
+
52
52
+
static void write_vbar(uint64_t v)
53
53
+
{
54
54
+
__asm__ volatile("msr vbar_el1, %0" :: "r"(v) : "memory");
55
55
+
}
56
56
+
57
57
+
static void write_ttbr0(uint64_t v)
58
58
+
{
59
59
+
__asm__ volatile("msr ttbr0_el1, %0" :: "r"(v) : "memory");
60
60
+
}
61
61
+
62
62
+
static void write_tcr(uint64_t v)
63
63
+
{
64
64
+
__asm__ volatile("msr tcr_el1, %0" :: "r"(v) : "memory");
65
65
+
}
66
66
+
67
67
+
static void write_actlr(uint64_t v)
68
68
+
{
69
69
+
__asm__ volatile("msr actlr_el1, %0" :: "r"(v) : "memory");
70
70
+
}
71
71
+
72
72
+
static uint64_t attempt_hcr_el2_read(void)
73
73
+
{
74
74
+
uint64_t v;
75
75
+
__asm__ volatile("mrs %0, hcr_el2" : "=r"(v));
76
76
+
return v;
77
77
+
}
78
78
+
79
79
+
static uint64_t read_unknown_sysreg(void)
80
80
+
{
81
81
+
uint64_t v;
82
82
+
__asm__ volatile("mrs %0, S3_7_C15_C15_7" : "=r"(v));
83
83
+
return v;
84
84
+
}
85
85
+
86
86
+
void guest_main(void)
87
87
+
{
88
88
+
console("diagnostic guest: start");
89
89
+
uint64_t midr = read_midr();
90
90
+
(void)midr;
91
91
+
console("diagnostic guest: read midr_el1");
92
92
+
93
93
+
uint64_t pfr0 = read_pfr0();
94
94
+
(void)pfr0;
95
95
+
console("diagnostic guest: read id_aa64pfr0_el1");
96
96
+
97
97
+
write_sctlr(0x30d00800u);
98
98
+
console("diagnostic guest: wrote sctlr_el1 shadow");
99
99
+
100
100
+
write_vbar(0x40000800u);
101
101
+
console("diagnostic guest: wrote vbar_el1 vector base");
102
102
+
103
103
+
write_ttbr0(0u);
104
104
+
console("diagnostic guest: wrote ttbr0_el1 shadow");
105
105
+
106
106
+
write_tcr(0u);
107
107
+
console("diagnostic guest: wrote tcr_el1 shadow");
108
108
+
109
109
+
uint64_t cntv = read_cntv_ctl();
110
110
+
(void)cntv;
111
111
+
console("diagnostic guest: read cntv_ctl_el0");
112
112
+
113
113
+
(void)hvc_call(0u, 0u, 0u);
114
114
+
console("diagnostic guest: requested hv id");
115
115
+
116
116
+
(void)hvc_call(1u, 0u, 0u);
117
117
+
console("diagnostic guest: requested log dump");
118
118
+
119
119
+
console("diagnostic guest: attempting denied hcr_el2 read");
120
120
+
(void)attempt_hcr_el2_read();
121
121
+
console("diagnostic guest: returned through guest undefined vector");
122
122
+
123
123
+
__asm__ volatile("brk #0");
124
124
+
console("diagnostic guest: returned through guest brk vector");
125
125
+
126
126
+
console("diagnostic guest: attempting unknown sysreg read");
127
127
+
(void)read_unknown_sysreg();
128
128
+
console("diagnostic guest: returned from unknown sysreg read");
129
129
+
130
130
+
console("diagnostic guest: attempting denied actlr_el1 write");
131
131
+
write_actlr(1u);
132
132
+
console("diagnostic guest: unexpected return from denied actlr_el1");
133
133
+
(void)hvc_call(3u, 0u, 0u);
134
134
+
}
···
1
1
+
.section .text.entry, "ax"
2
2
+
.global _guest_start
3
3
+
.type _guest_start, %function
4
4
+
_guest_start:
5
5
+
ldr x0, =__guest_stack_top
6
6
+
mov sp, x0
7
7
+
ldr x0, =__guest_bss_start
8
8
+
ldr x1, =__guest_bss_end
9
9
+
1: cmp x0, x1
10
10
+
b.hs 2f
11
11
+
str xzr, [x0], #8
12
12
+
b 1b
13
13
+
2: ldr x0, =guest_vectors
14
14
+
msr vbar_el1, x0
15
15
+
isb
16
16
+
bl guest_main
17
17
+
3: hvc #3
18
18
+
wfe
19
19
+
b 3b
20
20
+
21
21
+
.global guest_hvc_call
22
22
+
.type guest_hvc_call, %function
23
23
+
guest_hvc_call:
24
24
+
hvc #0
25
25
+
ret
26
26
+
27
27
+
.section .text.vectors, "ax"
28
28
+
.align 11
29
29
+
guest_vectors:
30
30
+
b guest_exception
31
31
+
.org guest_vectors + 0x080
32
32
+
b guest_exception
33
33
+
.org guest_vectors + 0x100
34
34
+
b guest_exception
35
35
+
.org guest_vectors + 0x180
36
36
+
b guest_exception
37
37
+
.org guest_vectors + 0x200
38
38
+
b guest_exception
39
39
+
.org guest_vectors + 0x280
40
40
+
b guest_exception
41
41
+
.org guest_vectors + 0x300
42
42
+
b guest_exception
43
43
+
.org guest_vectors + 0x380
44
44
+
b guest_exception
45
45
+
.org guest_vectors + 0x400
46
46
+
b guest_exception
47
47
+
.org guest_vectors + 0x480
48
48
+
b guest_exception
49
49
+
.org guest_vectors + 0x500
50
50
+
b guest_exception
51
51
+
.org guest_vectors + 0x580
52
52
+
b guest_exception
53
53
+
.org guest_vectors + 0x600
54
54
+
b guest_exception
55
55
+
.org guest_vectors + 0x680
56
56
+
b guest_exception
57
57
+
.org guest_vectors + 0x700
58
58
+
b guest_exception
59
59
+
.org guest_vectors + 0x780
60
60
+
b guest_exception
61
61
+
62
62
+
guest_exception:
63
63
+
mrs x4, esr_el1
64
64
+
mrs x5, elr_el1
65
65
+
mrs x6, far_el1
66
66
+
mov x0, #5
67
67
+
mov x1, x4
68
68
+
mov x2, x5
69
69
+
mov x3, x6
70
70
+
hvc #0
71
71
+
mov x0, #4
72
72
+
ldr x1, =guest_exception_msg
73
73
+
mov x2, #(guest_exception_msg_end - guest_exception_msg)
74
74
+
hvc #0
75
75
+
add x5, x5, #4
76
76
+
msr elr_el1, x5
77
77
+
isb
78
78
+
eret
79
79
+
80
80
+
.section .rodata
81
81
+
guest_exception_msg:
82
82
+
.ascii "guest exception vector"
83
83
+
guest_exception_msg_end:
84
84
+
85
85
+
.section .bss.stack, "aw", %nobits
86
86
+
.align 12
87
87
+
__guest_stack:
88
88
+
.skip 0x10000
89
89
+
__guest_stack_top:
···
1
1
+
#ifndef HV_ALLOCATOR_H
2
2
+
#define HV_ALLOCATOR_H
3
3
+
4
4
+
#include "hv/types.h"
5
5
+
6
6
+
void allocator_init(paddr_t base, uint64_t size);
7
7
+
void *alloc_page(void);
8
8
+
bool allocator_owns(paddr_t addr, uint64_t size);
9
9
+
bool allocator_selftest(void);
10
10
+
void allocator_dump(void);
11
11
+
12
12
+
#endif
···
1
1
+
#ifndef HV_ARCH_H
2
2
+
#define HV_ARCH_H
3
3
+
4
4
+
#include "hv/types.h"
5
5
+
6
6
+
struct trap_frame;
7
7
+
struct vcpu;
8
8
+
9
9
+
extern char __bss_start[];
10
10
+
extern char __bss_end[];
11
11
+
extern char __image_start[];
12
12
+
extern char __image_end[];
13
13
+
extern char __vectors_el2[];
14
14
+
extern char __guest_image_start[];
15
15
+
extern char __guest_image_end[];
16
16
+
17
17
+
uint64_t arch_current_el(void);
18
18
+
uint64_t arch_mpidr_el1(void);
19
19
+
uint64_t arch_cntpct_el0(void);
20
20
+
uint64_t arch_cntfrq_el0(void);
21
21
+
uint64_t arch_irq_save(void);
22
22
+
void arch_irq_restore(uint64_t flags);
23
23
+
void arch_dump_el2_state(void);
24
24
+
void arch_el2_configure(uint64_t vttbr, uint64_t vtcr);
25
25
+
void arch_enable_el2_mmu(uint64_t ttbr0, uint64_t tcr, uint64_t mair);
26
26
+
void arch_install_vectors(void);
27
27
+
void arch_prepare_guest_entry(struct vcpu *vcpu);
28
28
+
void arch_capture_el1_sysregs(struct vcpu *vcpu);
29
29
+
void arch_sync_el1_sysregs(const struct vcpu *vcpu);
30
30
+
void arch_vcpu_enter(struct vcpu *vcpu);
31
31
+
void arch_halt(void) __attribute__((noreturn));
32
32
+
void arch_inject_guest_undef(struct vcpu *vcpu);
33
33
+
void arch_advance_guest_pc(struct vcpu *vcpu);
34
34
+
void arch_tlbi_vmalle1is(void);
35
35
+
void hv_main(uint64_t boot_dtb_pa);
36
36
+
37
37
+
#endif
···
1
1
+
#ifndef HV_CONFIG_H
2
2
+
#define HV_CONFIG_H
3
3
+
4
4
+
#define HV_PROJECT_NAME "ariel"
5
5
+
#define HV_BUILD_MODE "qemu-virt-aarch64"
6
6
+
#define HV_BUILD_ID "reproducible-local"
7
7
+
8
8
+
#define CONFIG_PLATFORM_QEMU_VIRT 1
9
9
+
#define CONFIG_HV_LOAD_ADDRESS 0x40080000ull
10
10
+
#define CONFIG_UART_BASE 0x09000000ull
11
11
+
#define CONFIG_UART_SIZE 0x00001000ull
12
12
+
#define CONFIG_RTC_BASE 0x09010000ull
13
13
+
#define CONFIG_RTC_SIZE 0x00001000ull
14
14
+
#define CONFIG_FW_CFG_BASE 0x09020000ull
15
15
+
#define CONFIG_FW_CFG_SIZE 0x00001000ull
16
16
+
#define CONFIG_GPIO_BASE 0x09030000ull
17
17
+
#define CONFIG_GPIO_SIZE 0x00001000ull
18
18
+
#define CONFIG_PCI_ECAM_BASE 0x4010000000ull
19
19
+
#define CONFIG_PCI_ECAM_SIZE 0x10000000ull
20
20
+
#define CONFIG_GICD_BASE 0x08000000ull
21
21
+
#define CONFIG_GICD_SIZE 0x00010000ull
22
22
+
#define CONFIG_GITS_BASE 0x08080000ull
23
23
+
#define CONFIG_GITS_SIZE 0x00020000ull
24
24
+
#define CONFIG_GICR_BASE 0x080A0000ull
25
25
+
#define CONFIG_GICR_SIZE 0x00F60000ull
26
26
+
27
27
+
#define CONFIG_PAGE_SIZE 4096ull
28
28
+
#define CONFIG_HV_STACK_SIZE 0x10000ull
29
29
+
#define CONFIG_GUEST_IPA_BASE 0x40000000ull
30
30
+
#define CONFIG_GUEST_RAM_BASE 0x42000000ull
31
31
+
#define CONFIG_GUEST_RAM_SIZE 0x30000000ull
32
32
+
#define CONFIG_GUEST_STACK_TOP (CONFIG_GUEST_IPA_BASE + 0x00100000ull)
33
33
+
#define CONFIG_GUEST_ENTRY CONFIG_GUEST_IPA_BASE
34
34
+
#define CONFIG_LINUX_IMAGE_LOAD_PA CONFIG_GUEST_RAM_BASE
35
35
+
#define CONFIG_LINUX_IMAGE_MAX_SIZE CONFIG_GUEST_RAM_SIZE
36
36
+
#define CONFIG_LINUX_INITRD_PA (CONFIG_GUEST_RAM_BASE + 0x04000000ull)
37
37
+
#define CONFIG_LINUX_INITRD_IPA (CONFIG_GUEST_IPA_BASE + 0x04000000ull)
38
38
+
#define CONFIG_LINUX_INITRD_MAX_SIZE 0x2be00000ull
39
39
+
#ifndef CONFIG_LINUX_INITRD_SIZE
40
40
+
#define CONFIG_LINUX_INITRD_SIZE 0ull
41
41
+
#endif
42
42
+
#define CONFIG_LINUX_DTB_PA (CONFIG_GUEST_RAM_BASE + 0x2fe00000ull)
43
43
+
#define CONFIG_LINUX_DTB_IPA (CONFIG_GUEST_IPA_BASE + 0x2fe00000ull)
44
44
+
#define CONFIG_LINUX_DTB_MAX_SIZE 0x00200000ull
45
45
+
46
46
+
#ifndef CONFIG_BOOT_LINUX
47
47
+
#define CONFIG_BOOT_LINUX 0
48
48
+
#endif
49
49
+
50
50
+
#ifndef CONFIG_MONITOR_MUTATION
51
51
+
#define CONFIG_MONITOR_MUTATION 0
52
52
+
#endif
53
53
+
54
54
+
#define CONFIG_LOG_CAPACITY 256u
55
55
+
#define CONFIG_POLICY_STRICT 1
56
56
+
#define CONFIG_ENABLE_WFI_TRAPS 1
57
57
+
#define CONFIG_ENABLE_SMC_TRAPS 1
58
58
+
#define CONFIG_ENABLE_DEBUG_LOG 1
59
59
+
#define CONFIG_VTIMER_IRQ 27u
60
60
+
61
61
+
#endif
···
1
1
+
#ifndef HV_EL2_MMU_H
2
2
+
#define HV_EL2_MMU_H
3
3
+
4
4
+
#include "hv/types.h"
5
5
+
6
6
+
void el2_mmu_init_plan(void);
7
7
+
void el2_mmu_enable(void);
8
8
+
uint64_t el2_mmu_root(void);
9
9
+
uint64_t el2_mmu_tcr(void);
10
10
+
uint64_t el2_mmu_mair(void);
11
11
+
void el2_mmu_dump(void);
12
12
+
bool el2_mmu_selftest(void);
13
13
+
14
14
+
#endif
···
1
1
+
#ifndef HV_FDT_H
2
2
+
#define HV_FDT_H
3
3
+
4
4
+
#include "hv/types.h"
5
5
+
6
6
+
struct fdt_platform_info {
7
7
+
bool valid;
8
8
+
uint64_t fdt_pa;
9
9
+
uint64_t size;
10
10
+
uint64_t memory_base;
11
11
+
uint64_t memory_size;
12
12
+
uint64_t initrd_start;
13
13
+
uint64_t initrd_end;
14
14
+
const char *bootargs;
15
15
+
};
16
16
+
17
17
+
bool fdt_probe(uint64_t fdt_pa, struct fdt_platform_info *info);
18
18
+
bool fdt_patch_memory(uint64_t fdt_pa, uint64_t base, uint64_t size);
19
19
+
bool fdt_patch_linux_guest(uint64_t fdt_pa, uint64_t max_size, const char *bootargs,
20
20
+
uint64_t initrd_start, uint64_t initrd_end);
21
21
+
void fdt_dump(const struct fdt_platform_info *info);
22
22
+
23
23
+
#endif
···
1
1
+
#ifndef HV_GICV3_H
2
2
+
#define HV_GICV3_H
3
3
+
4
4
+
#include "hv/types.h"
5
5
+
6
6
+
struct vcpu;
7
7
+
8
8
+
void gicv3_init(void);
9
9
+
void gicv3_dump(void);
10
10
+
uint32_t gicv3_ack_irq(void);
11
11
+
void gicv3_eoi(uint32_t irq);
12
12
+
void gicv3_vcpu_init(void);
13
13
+
void gicv3_sync_vcpu_state(struct vcpu *vcpu);
14
14
+
void gicv3_flush_vcpu_state(struct vcpu *vcpu);
15
15
+
16
16
+
#endif
···
1
1
+
#ifndef HV_GUEST_LOADER_H
2
2
+
#define HV_GUEST_LOADER_H
3
3
+
4
4
+
#include "hv/types.h"
5
5
+
6
6
+
enum guest_payload_kind {
7
7
+
GUEST_PAYLOAD_DIAGNOSTIC = 0,
8
8
+
GUEST_PAYLOAD_LINUX_IMAGE = 1,
9
9
+
};
10
10
+
11
11
+
struct guest_image_info {
12
12
+
enum guest_payload_kind kind;
13
13
+
uint64_t ipa_entry;
14
14
+
uint64_t ipa_load;
15
15
+
uint64_t size;
16
16
+
uint64_t dtb_ipa;
17
17
+
uint64_t initrd_ipa;
18
18
+
uint64_t initrd_size;
19
19
+
};
20
20
+
21
21
+
bool guest_load_diagnostic(struct guest_image_info *info);
22
22
+
bool guest_load_external_linux(struct guest_image_info *info, paddr_t image_pa,
23
23
+
uint64_t image_max_size, paddr_t dtb_pa,
24
24
+
uint64_t dtb_max_size, paddr_t initrd_pa,
25
25
+
uint64_t initrd_size);
26
26
+
bool guest_validate_linux_image_header(const void *image, uint64_t size,
27
27
+
struct guest_image_info *info);
28
28
+
29
29
+
#endif
···
1
1
+
#ifndef HV_LOG_H
2
2
+
#define HV_LOG_H
3
3
+
4
4
+
#include "hv/types.h"
5
5
+
6
6
+
enum log_kind {
7
7
+
LOG_BOOT = 1,
8
8
+
LOG_TRAP = 2,
9
9
+
LOG_POLICY = 3,
10
10
+
LOG_HVC = 4,
11
11
+
LOG_ABORT = 5,
12
12
+
LOG_MONITOR = 6,
13
13
+
LOG_PANIC = 7,
14
14
+
LOG_SELFTEST = 8,
15
15
+
};
16
16
+
17
17
+
enum log_action {
18
18
+
LOG_ACT_NONE = 0,
19
19
+
LOG_ACT_EMULATE_READ,
20
20
+
LOG_ACT_EMULATE_WRITE,
21
21
+
LOG_ACT_WRITE_MASK,
22
22
+
LOG_ACT_DENY_SKIP,
23
23
+
LOG_ACT_DENY_UNDEF,
24
24
+
LOG_ACT_PAUSE,
25
25
+
LOG_ACT_PANIC,
26
26
+
};
27
27
+
28
28
+
struct log_event {
29
29
+
uint64_t seq;
30
30
+
uint64_t cpu;
31
31
+
uint64_t vcpu;
32
32
+
uint64_t timestamp;
33
33
+
uint32_t kind;
34
34
+
uint32_t ec;
35
35
+
uint64_t iss;
36
36
+
uint64_t elr;
37
37
+
uint64_t far;
38
38
+
uint64_t hpfar;
39
39
+
uint64_t sysreg_key;
40
40
+
uint32_t is_read;
41
41
+
uint32_t rt;
42
42
+
uint64_t operand;
43
43
+
uint64_t result;
44
44
+
uint32_t action;
45
45
+
uint32_t reason;
46
46
+
uint64_t pstate;
47
47
+
const char *name;
48
48
+
};
49
49
+
50
50
+
void log_init(void);
51
51
+
void log_event_commit(const struct log_event *event);
52
52
+
void log_simple(enum log_kind kind, uint32_t reason, uint64_t a, uint64_t b);
53
53
+
void log_dump(unsigned limit);
54
54
+
void log_clear(void);
55
55
+
bool log_selftest(void);
56
56
+
57
57
+
#endif
···
1
1
+
#ifndef HV_MMIO_H
2
2
+
#define HV_MMIO_H
3
3
+
4
4
+
#include "hv/types.h"
5
5
+
6
6
+
static inline void hv_dmb_ish(void)
7
7
+
{
8
8
+
__asm__ volatile("dmb ish" ::: "memory");
9
9
+
}
10
10
+
11
11
+
static inline void hv_dsb_ish(void)
12
12
+
{
13
13
+
__asm__ volatile("dsb ish" ::: "memory");
14
14
+
}
15
15
+
16
16
+
static inline void hv_dsb_sy(void)
17
17
+
{
18
18
+
__asm__ volatile("dsb sy" ::: "memory");
19
19
+
}
20
20
+
21
21
+
static inline void hv_isb(void)
22
22
+
{
23
23
+
__asm__ volatile("isb" ::: "memory");
24
24
+
}
25
25
+
26
26
+
static inline uint32_t mmio_read32(uintptr_t addr)
27
27
+
{
28
28
+
uint32_t value = *(volatile uint32_t *)addr;
29
29
+
hv_dmb_ish();
30
30
+
return value;
31
31
+
}
32
32
+
33
33
+
static inline void mmio_write32(uintptr_t addr, uint32_t value)
34
34
+
{
35
35
+
hv_dmb_ish();
36
36
+
*(volatile uint32_t *)addr = value;
37
37
+
hv_dmb_ish();
38
38
+
}
39
39
+
40
40
+
#endif
···
1
1
+
#ifndef HV_MMIO_POLICY_H
2
2
+
#define HV_MMIO_POLICY_H
3
3
+
4
4
+
#include "hv/types.h"
5
5
+
6
6
+
struct vcpu;
7
7
+
8
8
+
enum mmio_policy_action {
9
9
+
MMIO_POLICY_DENY = 0,
10
10
+
MMIO_POLICY_EMULATE_ZERO,
11
11
+
MMIO_POLICY_EMULATE_PL011,
12
12
+
MMIO_POLICY_EMULATE_VIRTIO_MMIO,
13
13
+
MMIO_POLICY_EMULATE_READONLY_DEVICE,
14
14
+
MMIO_POLICY_ALLOW_STAGE2,
15
15
+
};
16
16
+
17
17
+
struct mmio_policy_region {
18
18
+
ipa_t base;
19
19
+
uint64_t size;
20
20
+
const char *name;
21
21
+
enum mmio_policy_action action;
22
22
+
};
23
23
+
24
24
+
const struct mmio_policy_region *mmio_policy_lookup(ipa_t ipa);
25
25
+
bool mmio_policy_emulate(struct vcpu *vcpu, ipa_t ipa, uint64_t esr_el2);
26
26
+
void mmio_policy_dump(void);
27
27
+
28
28
+
#endif
···
1
1
+
#ifndef HV_MONITOR_H
2
2
+
#define HV_MONITOR_H
3
3
+
4
4
+
#include "hv/vcpu.h"
5
5
+
6
6
+
void monitor_init(void);
7
7
+
void monitor_poll(void);
8
8
+
void monitor_loop(struct vcpu *vcpu, const char *reason);
9
9
+
10
10
+
#endif
···
1
1
+
#ifndef HV_PANIC_H
2
2
+
#define HV_PANIC_H
3
3
+
4
4
+
#include "hv/types.h"
5
5
+
6
6
+
void panic(const char *reason) __attribute__((noreturn));
7
7
+
void panic_with_code(const char *reason, uint64_t code) __attribute__((noreturn));
8
8
+
9
9
+
#define BUG_ON(cond) do { if (cond) { panic("BUG_ON: " #cond); } } while (0)
10
10
+
11
11
+
#endif
···
1
1
+
#ifndef HV_PLATFORM_H
2
2
+
#define HV_PLATFORM_H
3
3
+
4
4
+
#include "hv/fdt.h"
5
5
+
6
6
+
const struct fdt_platform_info *platform_info(void);
7
7
+
8
8
+
#endif
···
1
1
+
#ifndef HV_POLICY_H
2
2
+
#define HV_POLICY_H
3
3
+
4
4
+
#include "hv/log.h"
5
5
+
#include "hv/sysreg.h"
6
6
+
#include "hv/vcpu.h"
7
7
+
8
8
+
enum policy_access_class {
9
9
+
POLICY_CLASS_ID = 1,
10
10
+
POLICY_CLASS_MMU,
11
11
+
POLICY_CLASS_TIMER,
12
12
+
POLICY_CLASS_THREAD,
13
13
+
POLICY_CLASS_DEBUG,
14
14
+
POLICY_CLASS_PMU,
15
15
+
POLICY_CLASS_EL2_EL3,
16
16
+
POLICY_CLASS_MISC,
17
17
+
};
18
18
+
19
19
+
enum policy_action {
20
20
+
POLICY_ALLOW_NATIVE = 0,
21
21
+
POLICY_EMULATE_READ,
22
22
+
POLICY_EMULATE_WRITE,
23
23
+
POLICY_WRITE_MASK,
24
24
+
POLICY_DENY_SKIP,
25
25
+
POLICY_DENY_UNDEF,
26
26
+
POLICY_PAUSE,
27
27
+
POLICY_PANIC,
28
28
+
};
29
29
+
30
30
+
struct policy_entry {
31
31
+
uint64_t key;
32
32
+
const char *name;
33
33
+
enum policy_access_class access_class;
34
34
+
enum policy_action read_policy;
35
35
+
enum policy_action write_policy;
36
36
+
uint64_t reset_value;
37
37
+
uint64_t writable_mask;
38
38
+
uint32_t logging_level;
39
39
+
uint32_t violation_reason;
40
40
+
};
41
41
+
42
42
+
struct policy_decision {
43
43
+
const struct policy_entry *entry;
44
44
+
enum policy_action action;
45
45
+
uint64_t value;
46
46
+
uint32_t reason;
47
47
+
};
48
48
+
49
49
+
enum policy_profile {
50
50
+
POLICY_PROFILE_STRICT = 0,
51
51
+
POLICY_PROFILE_DIAGNOSTIC,
52
52
+
POLICY_PROFILE_LINUX_BOOT,
53
53
+
POLICY_PROFILE_DEBUG,
54
54
+
};
55
55
+
56
56
+
void policy_init(void);
57
57
+
bool policy_set_profile(enum policy_profile profile);
58
58
+
bool policy_set_profile_name(const char *name);
59
59
+
enum policy_profile policy_get_profile(void);
60
60
+
const char *policy_profile_name(enum policy_profile profile);
61
61
+
const struct policy_entry *sysreg_policy_lookup(uint64_t key);
62
62
+
bool policy_apply_sysreg(struct vcpu *vcpu, const struct sysreg_access *access,
63
63
+
uint64_t operand, struct policy_decision *decision);
64
64
+
void policy_dump(void);
65
65
+
bool policy_selftest(void);
66
66
+
67
67
+
#endif
···
1
1
+
#ifndef HV_PSCI_H
2
2
+
#define HV_PSCI_H
3
3
+
4
4
+
#include "hv/vcpu.h"
5
5
+
6
6
+
bool psci_handle_call(struct vcpu *vcpu, uint64_t function_id);
7
7
+
void psci_dump(void);
8
8
+
9
9
+
#endif
···
1
1
+
#ifndef HV_SELFTEST_H
2
2
+
#define HV_SELFTEST_H
3
3
+
4
4
+
void selftests_run_or_panic(void);
5
5
+
6
6
+
#endif
···
1
1
+
#ifndef HV_STAGE2_H
2
2
+
#define HV_STAGE2_H
3
3
+
4
4
+
#include "hv/types.h"
5
5
+
6
6
+
enum stage2_mem_type {
7
7
+
S2_MEM_NORMAL = 0,
8
8
+
S2_MEM_DEVICE = 1,
9
9
+
};
10
10
+
11
11
+
enum stage2_perm {
12
12
+
S2_PERM_R = 1u,
13
13
+
S2_PERM_W = 2u,
14
14
+
S2_PERM_X = 4u,
15
15
+
};
16
16
+
17
17
+
struct stage2_translation {
18
18
+
bool mapped;
19
19
+
ipa_t ipa_base;
20
20
+
paddr_t pa_base;
21
21
+
uint64_t size;
22
22
+
uint64_t desc;
23
23
+
uint32_t perms;
24
24
+
enum stage2_mem_type type;
25
25
+
};
26
26
+
27
27
+
struct trap_frame;
28
28
+
struct vcpu;
29
29
+
30
30
+
void stage2_init(void);
31
31
+
bool stage2_map_range(ipa_t ipa, paddr_t pa, uint64_t size, enum stage2_mem_type type, uint32_t perms);
32
32
+
bool stage2_unmap_range(ipa_t ipa, uint64_t size);
33
33
+
bool stage2_translate(ipa_t ipa, struct stage2_translation *out);
34
34
+
ipa_t stage2_ipa_from_abort(uint64_t far_el2, uint64_t hpfar_el2);
35
35
+
bool stage2_handle_abort(struct vcpu *vcpu, const struct trap_frame *frame, bool instruction);
36
36
+
uint64_t stage2_vttbr(void);
37
37
+
uint64_t stage2_vtcr(void);
38
38
+
void stage2_dump(void);
39
39
+
bool stage2_selftest(void);
40
40
+
41
41
+
#endif
···
1
1
+
#ifndef HV_STRING_H
2
2
+
#define HV_STRING_H
3
3
+
4
4
+
#include <stddef.h>
5
5
+
#include <stdint.h>
6
6
+
7
7
+
void *hv_memset(void *dst, int value, size_t len);
8
8
+
void *hv_memcpy(void *dst, const void *src, size_t len);
9
9
+
void *hv_memmove(void *dst, const void *src, size_t len);
10
10
+
int hv_memcmp(const void *a, const void *b, size_t len);
11
11
+
void *memset(void *dst, int value, size_t len);
12
12
+
void *memcpy(void *dst, const void *src, size_t len);
13
13
+
void *memmove(void *dst, const void *src, size_t len);
14
14
+
int memcmp(const void *a, const void *b, size_t len);
15
15
+
size_t hv_strlen(const char *s);
16
16
+
int hv_strcmp(const char *a, const char *b);
17
17
+
int hv_strncmp(const char *a, const char *b, size_t n);
18
18
+
19
19
+
#endif
···
1
1
+
#ifndef HV_SYSREG_H
2
2
+
#define HV_SYSREG_H
3
3
+
4
4
+
#include "hv/types.h"
5
5
+
6
6
+
#define ESR_EC_SHIFT 26u
7
7
+
#define ESR_EC_MASK 0x3fu
8
8
+
#define ESR_EC_UNKNOWN 0x00u
9
9
+
#define ESR_EC_WFI_WFE 0x01u
10
10
+
#define ESR_EC_SMC64 0x17u
11
11
+
#define ESR_EC_HVC64 0x16u
12
12
+
#define ESR_EC_SYSREG 0x18u
13
13
+
#define ESR_EC_IABT_LOWER 0x20u
14
14
+
#define ESR_EC_DABT_LOWER 0x24u
15
15
+
#define ESR_EC_BRK64 0x3cu
16
16
+
17
17
+
#define ESR_SYSREG_DIR_READ 1u
18
18
+
#define ESR_SYSREG_DIR_WRITE 0u
19
19
+
20
20
+
struct sysreg_access {
21
21
+
uint32_t op0;
22
22
+
uint32_t op1;
23
23
+
uint32_t crn;
24
24
+
uint32_t crm;
25
25
+
uint32_t op2;
26
26
+
uint32_t rt;
27
27
+
bool is_read;
28
28
+
uint64_t key;
29
29
+
};
30
30
+
31
31
+
#define SYSREG_KEY_CONST(op0, op1, crn, crm, op2) \
32
32
+
((((uint64_t)((op0) & 0x3u)) << 14u) | \
33
33
+
(((uint64_t)((op1) & 0x7u)) << 11u) | \
34
34
+
(((uint64_t)((crn) & 0xfu)) << 7u) | \
35
35
+
(((uint64_t)((crm) & 0xfu)) << 3u) | \
36
36
+
((uint64_t)((op2) & 0x7u)))
37
37
+
38
38
+
static inline uint32_t esr_ec(uint64_t esr)
39
39
+
{
40
40
+
return (uint32_t)((esr >> ESR_EC_SHIFT) & ESR_EC_MASK);
41
41
+
}
42
42
+
43
43
+
uint64_t sysreg_key_make(uint32_t op0, uint32_t op1, uint32_t crn, uint32_t crm, uint32_t op2);
44
44
+
bool sysreg_decode_from_esr_iss(uint64_t iss, struct sysreg_access *out);
45
45
+
const char *sysreg_key_name(uint64_t key);
46
46
+
bool sysreg_selftest(void);
47
47
+
48
48
+
#endif
···
1
1
+
#ifndef HV_TIMER_H
2
2
+
#define HV_TIMER_H
3
3
+
4
4
+
#include "hv/types.h"
5
5
+
6
6
+
struct vcpu;
7
7
+
8
8
+
void timer_init(void);
9
9
+
uint64_t timer_now(void);
10
10
+
void timer_dump(void);
11
11
+
void timer_vcpu_sync(struct vcpu *vcpu);
12
12
+
13
13
+
#endif
···
1
1
+
#ifndef HV_TRAP_H
2
2
+
#define HV_TRAP_H
3
3
+
4
4
+
#include "hv/vcpu.h"
5
5
+
6
6
+
void trap_handle_lower_sync(struct trap_frame *frame);
7
7
+
void trap_handle_current_sync(struct trap_frame *frame);
8
8
+
void trap_handle_irq(struct trap_frame *frame);
9
9
+
10
10
+
#endif
···
1
1
+
#ifndef HV_TYPES_H
2
2
+
#define HV_TYPES_H
3
3
+
4
4
+
#include <stdbool.h>
5
5
+
#include <stddef.h>
6
6
+
#include <stdint.h>
7
7
+
8
8
+
#define HV_ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
9
9
+
#define HV_BIT(n) (1ull << (n))
10
10
+
#define HV_MASK(width) ((width) == 64u ? UINT64_MAX : ((1ull << (width)) - 1ull))
11
11
+
#define HV_ALIGN_UP(x, a) (((x) + ((a) - 1ull)) & ~((a) - 1ull))
12
12
+
#define HV_ALIGN_DOWN(x, a) ((x) & ~((a) - 1ull))
13
13
+
14
14
+
typedef uint64_t paddr_t;
15
15
+
typedef uint64_t vaddr_t;
16
16
+
typedef uint64_t ipa_t;
17
17
+
18
18
+
static inline bool hv_is_aligned_u64(uint64_t value, uint64_t alignment)
19
19
+
{
20
20
+
return alignment != 0u && (value & (alignment - 1u)) == 0u;
21
21
+
}
22
22
+
23
23
+
static inline bool hv_add_overflow_u64(uint64_t a, uint64_t b, uint64_t *out)
24
24
+
{
25
25
+
*out = a + b;
26
26
+
return *out < a;
27
27
+
}
28
28
+
29
29
+
static inline bool hv_range_overlaps(uint64_t a_base, uint64_t a_size,
30
30
+
uint64_t b_base, uint64_t b_size)
31
31
+
{
32
32
+
uint64_t a_end;
33
33
+
uint64_t b_end;
34
34
+
35
35
+
if (a_size == 0u || b_size == 0u) {
36
36
+
return false;
37
37
+
}
38
38
+
if (hv_add_overflow_u64(a_base, a_size, &a_end) ||
39
39
+
hv_add_overflow_u64(b_base, b_size, &b_end)) {
40
40
+
return true;
41
41
+
}
42
42
+
return a_base < b_end && b_base < a_end;
43
43
+
}
44
44
+
45
45
+
#endif
···
1
1
+
#ifndef HV_UART_H
2
2
+
#define HV_UART_H
3
3
+
4
4
+
#include "hv/types.h"
5
5
+
6
6
+
void uart_init(void);
7
7
+
void uart_putc(char c);
8
8
+
void uart_puts(const char *s);
9
9
+
void uart_put_hex64(uint64_t value);
10
10
+
void uart_put_dec64(uint64_t value);
11
11
+
bool uart_getc_nonblocking(char *out);
12
12
+
13
13
+
#endif
···
1
1
+
#ifndef HV_VCPU_H
2
2
+
#define HV_VCPU_H
3
3
+
4
4
+
#include "hv/types.h"
5
5
+
6
6
+
enum vcpu_run_state {
7
7
+
VCPU_CREATED = 0,
8
8
+
VCPU_READY,
9
9
+
VCPU_RUNNING,
10
10
+
VCPU_PAUSED,
11
11
+
VCPU_PANICKED,
12
12
+
};
13
13
+
14
14
+
struct el1_sysreg_shadow {
15
15
+
uint64_t sctlr_el1;
16
16
+
uint64_t ttbr0_el1;
17
17
+
uint64_t ttbr1_el1;
18
18
+
uint64_t tcr_el1;
19
19
+
uint64_t mair_el1;
20
20
+
uint64_t vbar_el1;
21
21
+
uint64_t contextidr_el1;
22
22
+
uint64_t tpidr_el1;
23
23
+
uint64_t tpidrro_el0;
24
24
+
uint64_t cntv_ctl_el0;
25
25
+
uint64_t cntv_tval_el0;
26
26
+
uint64_t cntv_cval_el0;
27
27
+
uint64_t cntkctl_el1;
28
28
+
uint64_t cpacr_el1;
29
29
+
uint64_t mdscr_el1;
30
30
+
uint64_t csselr_el1;
31
31
+
uint64_t elr_el1;
32
32
+
uint64_t spsr_el1;
33
33
+
uint64_t esr_el1;
34
34
+
uint64_t far_el1;
35
35
+
};
36
36
+
37
37
+
struct vcpu_stats {
38
38
+
uint64_t traps;
39
39
+
uint64_t sysreg_traps;
40
40
+
uint64_t hvc_calls;
41
41
+
uint64_t smc_denied;
42
42
+
uint64_t wfx_traps;
43
43
+
uint64_t data_aborts;
44
44
+
uint64_t instruction_aborts;
45
45
+
uint64_t unknown_exceptions;
46
46
+
uint64_t injected_undefs;
47
47
+
uint64_t virtual_irqs_injected;
48
48
+
uint64_t virtual_irqs_completed;
49
49
+
};
50
50
+
51
51
+
struct vcpu {
52
52
+
uint64_t x[31];
53
53
+
uint64_t sp_el0;
54
54
+
uint64_t sp_el1;
55
55
+
uint64_t pc;
56
56
+
uint64_t pstate;
57
57
+
struct el1_sysreg_shadow sysregs;
58
58
+
uint64_t pending_virtual_irq;
59
59
+
uint64_t active_virtual_irq;
60
60
+
uint32_t id;
61
61
+
enum vcpu_run_state state;
62
62
+
uint64_t last_esr;
63
63
+
uint64_t last_far;
64
64
+
uint64_t last_hpfar;
65
65
+
struct vcpu_stats stats;
66
66
+
};
67
67
+
68
68
+
struct trap_frame {
69
69
+
uint64_t x[31];
70
70
+
uint64_t sp_el0;
71
71
+
uint64_t sp_el1;
72
72
+
uint64_t elr_el2;
73
73
+
uint64_t spsr_el2;
74
74
+
uint64_t esr_el2;
75
75
+
uint64_t far_el2;
76
76
+
uint64_t hpfar_el2;
77
77
+
};
78
78
+
79
79
+
void vcpu_init(struct vcpu *vcpu, uint32_t id, uint64_t entry, uint64_t stack_top);
80
80
+
void vcpu_load_frame(struct vcpu *vcpu, const struct trap_frame *frame);
81
81
+
void vcpu_store_frame(const struct vcpu *vcpu, struct trap_frame *frame);
82
82
+
uint64_t vcpu_read_gpr(const struct vcpu *vcpu, uint32_t rt);
83
83
+
void vcpu_write_gpr(struct vcpu *vcpu, uint32_t rt, uint64_t value);
84
84
+
void vcpu_set_pending_irq(struct vcpu *vcpu, uint32_t intid);
85
85
+
void vcpu_clear_pending_irq(struct vcpu *vcpu, uint32_t intid);
86
86
+
struct vcpu *vcpu_current(void);
87
87
+
void vcpu_set_current(struct vcpu *vcpu);
88
88
+
void vcpu_dump(const struct vcpu *vcpu);
89
89
+
90
90
+
#endif
···
1
1
+
OUTPUT_ARCH(aarch64)
2
2
+
ENTRY(_start)
3
3
+
4
4
+
HV_BASE = 0x40080000;
5
5
+
6
6
+
SECTIONS
7
7
+
{
8
8
+
. = HV_BASE;
9
9
+
__image_start = .;
10
10
+
11
11
+
.text : ALIGN(4096) {
12
12
+
KEEP(*(.text.entry))
13
13
+
KEEP(*(.text.vectors))
14
14
+
*(.text .text.*)
15
15
+
}
16
16
+
17
17
+
.rodata : ALIGN(4096) {
18
18
+
*(.rodata .rodata.*)
19
19
+
}
20
20
+
21
21
+
.data : ALIGN(4096) {
22
22
+
*(.data .data.*)
23
23
+
}
24
24
+
25
25
+
.bss : ALIGN(4096) {
26
26
+
__bss_start = .;
27
27
+
*(.bss .bss.* COMMON)
28
28
+
__bss_end = .;
29
29
+
}
30
30
+
31
31
+
. = ALIGN(4096);
32
32
+
__image_end = .;
33
33
+
}
···
1
1
+
#include "hv/allocator.h"
2
2
+
#include "hv/config.h"
3
3
+
#include "hv/panic.h"
4
4
+
#include "hv/string.h"
5
5
+
#include "hv/uart.h"
6
6
+
7
7
+
#define MAX_ALLOC_PAGES 1024u
8
8
+
9
9
+
static paddr_t g_base;
10
10
+
static uint64_t g_size;
11
11
+
static uint8_t g_used[MAX_ALLOC_PAGES];
12
12
+
static uint64_t g_pages;
13
13
+
14
14
+
void allocator_init(paddr_t base, uint64_t size)
15
15
+
{
16
16
+
BUG_ON(!hv_is_aligned_u64(base, CONFIG_PAGE_SIZE));
17
17
+
BUG_ON(!hv_is_aligned_u64(size, CONFIG_PAGE_SIZE));
18
18
+
g_base = base;
19
19
+
g_size = size;
20
20
+
g_pages = size / CONFIG_PAGE_SIZE;
21
21
+
BUG_ON(g_pages > MAX_ALLOC_PAGES);
22
22
+
hv_memset(g_used, 0, sizeof(g_used));
23
23
+
}
24
24
+
25
25
+
void *alloc_page(void)
26
26
+
{
27
27
+
for (uint64_t i = 0; i < g_pages; i++) {
28
28
+
if (g_used[i] == 0u) {
29
29
+
g_used[i] = 1u;
30
30
+
return (void *)(uintptr_t)(g_base + (i * CONFIG_PAGE_SIZE));
31
31
+
}
32
32
+
}
33
33
+
return (void *)0;
34
34
+
}
35
35
+
36
36
+
bool allocator_owns(paddr_t addr, uint64_t size)
37
37
+
{
38
38
+
uint64_t end;
39
39
+
uint64_t alloc_end;
40
40
+
if (hv_add_overflow_u64(addr, size, &end) ||
41
41
+
hv_add_overflow_u64(g_base, g_size, &alloc_end)) {
42
42
+
return false;
43
43
+
}
44
44
+
return addr >= g_base && end <= alloc_end;
45
45
+
}
46
46
+
47
47
+
bool allocator_selftest(void)
48
48
+
{
49
49
+
if (!hv_is_aligned_u64(g_base, CONFIG_PAGE_SIZE) || g_pages == 0u) {
50
50
+
return false;
51
51
+
}
52
52
+
uint64_t free_count = 0;
53
53
+
for (uint64_t i = 0; i < g_pages; i++) {
54
54
+
if (g_used[i] == 0u) {
55
55
+
free_count++;
56
56
+
}
57
57
+
}
58
58
+
return free_count != 0u && allocator_owns(g_base, CONFIG_PAGE_SIZE);
59
59
+
}
60
60
+
61
61
+
void allocator_dump(void)
62
62
+
{
63
63
+
uint64_t used = 0;
64
64
+
for (uint64_t i = 0; i < g_pages; i++) {
65
65
+
if (g_used[i] != 0u) {
66
66
+
used++;
67
67
+
}
68
68
+
}
69
69
+
uart_puts("allocator base=");
70
70
+
uart_put_hex64(g_base);
71
71
+
uart_puts(" size=");
72
72
+
uart_put_hex64(g_size);
73
73
+
uart_puts(" pages=");
74
74
+
uart_put_dec64(g_pages);
75
75
+
uart_puts(" used=");
76
76
+
uart_put_dec64(used);
77
77
+
uart_puts("\n");
78
78
+
}
···
1
1
+
#include "hv/allocator.h"
2
2
+
#include "hv/arch.h"
3
3
+
#include "hv/config.h"
4
4
+
#include "hv/log.h"
5
5
+
#include "hv/mmio_policy.h"
6
6
+
#include "hv/panic.h"
7
7
+
#include "hv/stage2.h"
8
8
+
#include "hv/string.h"
9
9
+
#include "hv/sysreg.h"
10
10
+
#include "hv/trap.h"
11
11
+
#include "hv/uart.h"
12
12
+
#include "hv/vcpu.h"
13
13
+
14
14
+
#define S2_ENTRIES 512u
15
15
+
#define S2_L1_SHIFT 30u
16
16
+
#define S2_L2_SHIFT 21u
17
17
+
#define S2_L1_SIZE (1ull << S2_L1_SHIFT)
18
18
+
#define S2_L2_SIZE (1ull << S2_L2_SHIFT)
19
19
+
#define S2_DESC_VALID HV_BIT(0)
20
20
+
#define S2_DESC_TABLE HV_BIT(1)
21
21
+
#define S2_DESC_AF HV_BIT(10)
22
22
+
#define S2_DESC_SH_INNER (3ull << 8u)
23
23
+
#define S2_DESC_MEMATTR_NORMAL (0xfull << 2u)
24
24
+
#define S2_DESC_MEMATTR_DEVICE (0x0ull << 2u)
25
25
+
#define S2_DESC_S2AP_R (1ull << 6u)
26
26
+
#define S2_DESC_S2AP_W (1ull << 7u)
27
27
+
#define S2_DESC_XN (3ull << 53u)
28
28
+
29
29
+
static uint64_t g_l1[S2_ENTRIES] __attribute__((aligned(65536)));
30
30
+
static uint64_t g_l2_tables[4][S2_ENTRIES] __attribute__((aligned(4096)));
31
31
+
static uint32_t g_l2_used;
32
32
+
33
33
+
static uint64_t desc_addr(uint64_t addr)
34
34
+
{
35
35
+
return addr & 0x0000fffffffff000ull;
36
36
+
}
37
37
+
38
38
+
void stage2_init(void)
39
39
+
{
40
40
+
hv_memset(g_l1, 0, sizeof(g_l1));
41
41
+
hv_memset(g_l2_tables, 0, sizeof(g_l2_tables));
42
42
+
g_l2_used = 0;
43
43
+
}
44
44
+
45
45
+
static uint64_t *ensure_l2(uint64_t l1_index)
46
46
+
{
47
47
+
if (l1_index >= S2_ENTRIES) {
48
48
+
return (uint64_t *)0;
49
49
+
}
50
50
+
if ((g_l1[l1_index] & S2_DESC_VALID) != 0u) {
51
51
+
return (uint64_t *)(uintptr_t)desc_addr(g_l1[l1_index]);
52
52
+
}
53
53
+
if (g_l2_used >= HV_ARRAY_SIZE(g_l2_tables)) {
54
54
+
return (uint64_t *)0;
55
55
+
}
56
56
+
uint64_t *table = g_l2_tables[g_l2_used++];
57
57
+
g_l1[l1_index] = ((uint64_t)(uintptr_t)table & 0x0000fffffffff000ull) |
58
58
+
S2_DESC_TABLE | S2_DESC_VALID;
59
59
+
return table;
60
60
+
}
61
61
+
62
62
+
static uint64_t block_desc(paddr_t pa, enum stage2_mem_type type, uint32_t perms)
63
63
+
{
64
64
+
uint64_t desc = (pa & 0x0000ffffffe00000ull) | S2_DESC_VALID | S2_DESC_AF;
65
65
+
desc |= (type == S2_MEM_NORMAL) ? (S2_DESC_MEMATTR_NORMAL | S2_DESC_SH_INNER) :
66
66
+
S2_DESC_MEMATTR_DEVICE;
67
67
+
if ((perms & S2_PERM_R) != 0u) {
68
68
+
desc |= S2_DESC_S2AP_R;
69
69
+
}
70
70
+
if ((perms & S2_PERM_W) != 0u) {
71
71
+
desc |= S2_DESC_S2AP_W;
72
72
+
}
73
73
+
if ((perms & S2_PERM_X) == 0u) {
74
74
+
desc |= S2_DESC_XN;
75
75
+
}
76
76
+
return desc;
77
77
+
}
78
78
+
79
79
+
static bool descriptor_valid(uint64_t desc)
80
80
+
{
81
81
+
if ((desc & S2_DESC_VALID) == 0u) {
82
82
+
return false;
83
83
+
}
84
84
+
if ((desc & S2_DESC_AF) == 0u) {
85
85
+
return false;
86
86
+
}
87
87
+
if (!hv_is_aligned_u64(desc_addr(desc), S2_L2_SIZE)) {
88
88
+
return false;
89
89
+
}
90
90
+
return true;
91
91
+
}
92
92
+
93
93
+
static uint64_t *lookup_l2(uint64_t l1_index)
94
94
+
{
95
95
+
if (l1_index >= S2_ENTRIES || (g_l1[l1_index] & S2_DESC_VALID) == 0u) {
96
96
+
return (uint64_t *)0;
97
97
+
}
98
98
+
if ((g_l1[l1_index] & S2_DESC_TABLE) == 0u) {
99
99
+
return (uint64_t *)0;
100
100
+
}
101
101
+
return (uint64_t *)(uintptr_t)desc_addr(g_l1[l1_index]);
102
102
+
}
103
103
+
104
104
+
bool stage2_map_range(ipa_t ipa, paddr_t pa, uint64_t size, enum stage2_mem_type type, uint32_t perms)
105
105
+
{
106
106
+
uint64_t ipa_end;
107
107
+
uint64_t pa_end;
108
108
+
109
109
+
if (size == 0u || perms == 0u) {
110
110
+
return false;
111
111
+
}
112
112
+
if (!hv_is_aligned_u64(ipa, S2_L2_SIZE) || !hv_is_aligned_u64(pa, S2_L2_SIZE) ||
113
113
+
!hv_is_aligned_u64(size, S2_L2_SIZE)) {
114
114
+
return false;
115
115
+
}
116
116
+
if (hv_add_overflow_u64(ipa, size, &ipa_end) ||
117
117
+
hv_add_overflow_u64(pa, size, &pa_end)) {
118
118
+
return false;
119
119
+
}
120
120
+
if (ipa_end <= ipa || pa_end <= pa) {
121
121
+
return false;
122
122
+
}
123
123
+
if (hv_range_overlaps(pa, size, (uint64_t)(uintptr_t)__image_start,
124
124
+
(uint64_t)((uintptr_t)__image_end - (uintptr_t)__image_start))) {
125
125
+
return false;
126
126
+
}
127
127
+
128
128
+
for (uint64_t off = 0; off < size; off += S2_L2_SIZE) {
129
129
+
uint64_t cur_ipa = ipa + off;
130
130
+
uint64_t l1_index = (cur_ipa >> S2_L1_SHIFT) & 0x1ffu;
131
131
+
uint64_t l2_index = (cur_ipa >> S2_L2_SHIFT) & 0x1ffu;
132
132
+
uint64_t *l2 = ensure_l2(l1_index);
133
133
+
if (l2 == (uint64_t *)0 || (l2[l2_index] & S2_DESC_VALID) != 0u) {
134
134
+
return false;
135
135
+
}
136
136
+
uint64_t desc = block_desc(pa + off, type, perms);
137
137
+
if (!descriptor_valid(desc)) {
138
138
+
return false;
139
139
+
}
140
140
+
l2[l2_index] = desc;
141
141
+
}
142
142
+
arch_tlbi_vmalle1is();
143
143
+
return true;
144
144
+
}
145
145
+
146
146
+
bool stage2_unmap_range(ipa_t ipa, uint64_t size)
147
147
+
{
148
148
+
if (size == 0u || !hv_is_aligned_u64(ipa, S2_L2_SIZE) ||
149
149
+
!hv_is_aligned_u64(size, S2_L2_SIZE)) {
150
150
+
return false;
151
151
+
}
152
152
+
153
153
+
for (uint64_t off = 0; off < size; off += S2_L2_SIZE) {
154
154
+
uint64_t cur_ipa = ipa + off;
155
155
+
uint64_t l1_index = (cur_ipa >> S2_L1_SHIFT) & 0x1ffu;
156
156
+
uint64_t l2_index = (cur_ipa >> S2_L2_SHIFT) & 0x1ffu;
157
157
+
uint64_t *l2 = lookup_l2(l1_index);
158
158
+
if (l2 == (uint64_t *)0 || (l2[l2_index] & S2_DESC_VALID) == 0u) {
159
159
+
return false;
160
160
+
}
161
161
+
}
162
162
+
163
163
+
for (uint64_t off = 0; off < size; off += S2_L2_SIZE) {
164
164
+
uint64_t cur_ipa = ipa + off;
165
165
+
uint64_t l1_index = (cur_ipa >> S2_L1_SHIFT) & 0x1ffu;
166
166
+
uint64_t l2_index = (cur_ipa >> S2_L2_SHIFT) & 0x1ffu;
167
167
+
uint64_t *l2 = lookup_l2(l1_index);
168
168
+
l2[l2_index] = 0u;
169
169
+
}
170
170
+
arch_tlbi_vmalle1is();
171
171
+
return true;
172
172
+
}
173
173
+
174
174
+
bool stage2_translate(ipa_t ipa, struct stage2_translation *out)
175
175
+
{
176
176
+
uint64_t l1_index = (ipa >> S2_L1_SHIFT) & 0x1ffu;
177
177
+
uint64_t l2_index = (ipa >> S2_L2_SHIFT) & 0x1ffu;
178
178
+
uint64_t *l2 = lookup_l2(l1_index);
179
179
+
uint64_t desc;
180
180
+
181
181
+
if (out != (struct stage2_translation *)0) {
182
182
+
hv_memset(out, 0, sizeof(*out));
183
183
+
}
184
184
+
if (l2 == (uint64_t *)0 || (l2[l2_index] & S2_DESC_VALID) == 0u) {
185
185
+
return false;
186
186
+
}
187
187
+
188
188
+
desc = l2[l2_index];
189
189
+
if (out != (struct stage2_translation *)0) {
190
190
+
out->mapped = true;
191
191
+
out->ipa_base = HV_ALIGN_DOWN(ipa, S2_L2_SIZE);
192
192
+
out->pa_base = desc_addr(desc);
193
193
+
out->size = S2_L2_SIZE;
194
194
+
out->desc = desc;
195
195
+
if ((desc & S2_DESC_S2AP_R) != 0u) {
196
196
+
out->perms |= S2_PERM_R;
197
197
+
}
198
198
+
if ((desc & S2_DESC_S2AP_W) != 0u) {
199
199
+
out->perms |= S2_PERM_W;
200
200
+
}
201
201
+
if ((desc & S2_DESC_XN) == 0u) {
202
202
+
out->perms |= S2_PERM_X;
203
203
+
}
204
204
+
out->type = (desc & S2_DESC_MEMATTR_NORMAL) == S2_DESC_MEMATTR_NORMAL ?
205
205
+
S2_MEM_NORMAL : S2_MEM_DEVICE;
206
206
+
}
207
207
+
return true;
208
208
+
}
209
209
+
210
210
+
ipa_t stage2_ipa_from_abort(uint64_t far_el2, uint64_t hpfar_el2)
211
211
+
{
212
212
+
return ((hpfar_el2 & 0x0000000ffffffff0ull) << 8u) | (far_el2 & 0xfffull);
213
213
+
}
214
214
+
215
215
+
static bool dfsc_is_translation(uint32_t dfsc)
216
216
+
{
217
217
+
return dfsc >= 0x04u && dfsc <= 0x07u;
218
218
+
}
219
219
+
220
220
+
bool stage2_handle_abort(struct vcpu *vcpu, const struct trap_frame *frame, bool instruction)
221
221
+
{
222
222
+
ipa_t ipa;
223
223
+
ipa_t block_ipa;
224
224
+
paddr_t block_pa;
225
225
+
uint32_t dfsc;
226
226
+
struct log_event ev;
227
227
+
228
228
+
if (vcpu == (struct vcpu *)0 || frame == (const struct trap_frame *)0) {
229
229
+
return false;
230
230
+
}
231
231
+
232
232
+
ipa = stage2_ipa_from_abort(frame->far_el2, frame->hpfar_el2);
233
233
+
dfsc = (uint32_t)(frame->esr_el2 & 0x3fu);
234
234
+
hv_memset(&ev, 0, sizeof(ev));
235
235
+
ev.kind = LOG_ABORT;
236
236
+
ev.vcpu = vcpu->id;
237
237
+
ev.ec = esr_ec(frame->esr_el2);
238
238
+
ev.iss = frame->esr_el2 & 0x01ffffffu;
239
239
+
ev.elr = frame->elr_el2;
240
240
+
ev.far = ipa;
241
241
+
ev.hpfar = frame->hpfar_el2;
242
242
+
ev.pstate = frame->spsr_el2;
243
243
+
ev.reason = instruction ? 406u : 407u;
244
244
+
245
245
+
const struct mmio_policy_region *mmio = mmio_policy_lookup(ipa);
246
246
+
if (mmio != (const struct mmio_policy_region *)0) {
247
247
+
ev.reason = 410u;
248
248
+
ev.name = mmio->name;
249
249
+
ev.action = (uint32_t)mmio->action;
250
250
+
if (mmio_policy_emulate(vcpu, ipa, frame->esr_el2)) {
251
251
+
ev.reason = 411u;
252
252
+
log_event_commit(&ev);
253
253
+
arch_advance_guest_pc(vcpu);
254
254
+
return true;
255
255
+
}
256
256
+
log_event_commit(&ev);
257
257
+
return false;
258
258
+
}
259
259
+
260
260
+
if (!dfsc_is_translation(dfsc) ||
261
261
+
ipa < CONFIG_GUEST_IPA_BASE ||
262
262
+
ipa >= CONFIG_GUEST_IPA_BASE + CONFIG_GUEST_RAM_SIZE) {
263
263
+
log_event_commit(&ev);
264
264
+
return false;
265
265
+
}
266
266
+
267
267
+
block_ipa = HV_ALIGN_DOWN(ipa, S2_L2_SIZE);
268
268
+
block_pa = CONFIG_GUEST_RAM_BASE + (block_ipa - CONFIG_GUEST_IPA_BASE);
269
269
+
if (!stage2_map_range(block_ipa, block_pa, S2_L2_SIZE, S2_MEM_NORMAL,
270
270
+
S2_PERM_R | S2_PERM_W | S2_PERM_X)) {
271
271
+
log_event_commit(&ev);
272
272
+
return false;
273
273
+
}
274
274
+
275
275
+
ev.reason = instruction ? 408u : 409u;
276
276
+
ev.result = block_pa;
277
277
+
log_event_commit(&ev);
278
278
+
return true;
279
279
+
}
280
280
+
281
281
+
uint64_t stage2_vttbr(void)
282
282
+
{
283
283
+
return (uint64_t)(uintptr_t)g_l1;
284
284
+
}
285
285
+
286
286
+
uint64_t stage2_vtcr(void)
287
287
+
{
288
288
+
uint64_t vtcr = 0;
289
289
+
vtcr |= 24ull;
290
290
+
vtcr |= (1ull << 6u);
291
291
+
vtcr |= (1ull << 8u);
292
292
+
vtcr |= (1ull << 10u);
293
293
+
vtcr |= (3ull << 12u);
294
294
+
vtcr |= (2ull << 16u);
295
295
+
return vtcr;
296
296
+
}
297
297
+
298
298
+
void stage2_dump(void)
299
299
+
{
300
300
+
uart_puts("stage2 root=");
301
301
+
uart_put_hex64(stage2_vttbr());
302
302
+
uart_puts(" vtcr=");
303
303
+
uart_put_hex64(stage2_vtcr());
304
304
+
uart_puts(" l2_tables=");
305
305
+
uart_put_dec64(g_l2_used);
306
306
+
uart_puts("\n");
307
307
+
for (uint32_t l1 = 0; l1 < S2_ENTRIES; l1++) {
308
308
+
if ((g_l1[l1] & S2_DESC_VALID) == 0u) {
309
309
+
continue;
310
310
+
}
311
311
+
uint64_t *l2 = (uint64_t *)(uintptr_t)desc_addr(g_l1[l1]);
312
312
+
for (uint32_t l2i = 0; l2i < S2_ENTRIES; l2i++) {
313
313
+
if ((l2[l2i] & S2_DESC_VALID) != 0u) {
314
314
+
uart_puts("mapping ipa=");
315
315
+
uart_put_hex64(((uint64_t)l1 << S2_L1_SHIFT) | ((uint64_t)l2i << S2_L2_SHIFT));
316
316
+
uart_puts(" desc=");
317
317
+
uart_put_hex64(l2[l2i]);
318
318
+
uart_puts("\n");
319
319
+
}
320
320
+
}
321
321
+
}
322
322
+
}
323
323
+
324
324
+
bool stage2_selftest(void)
325
325
+
{
326
326
+
if (!hv_is_aligned_u64((uint64_t)(uintptr_t)g_l1, 65536u)) {
327
327
+
return false;
328
328
+
}
329
329
+
for (uint32_t i = 0; i < S2_ENTRIES; i++) {
330
330
+
if ((g_l1[i] & S2_DESC_VALID) != 0u && (g_l1[i] & S2_DESC_TABLE) == 0u) {
331
331
+
return false;
332
332
+
}
333
333
+
if ((g_l1[i] & S2_DESC_VALID) != 0u) {
334
334
+
uint64_t *l2 = (uint64_t *)(uintptr_t)desc_addr(g_l1[i]);
335
335
+
for (uint32_t j = 0; j < S2_ENTRIES; j++) {
336
336
+
if ((l2[j] & S2_DESC_VALID) != 0u && !descriptor_valid(l2[j])) {
337
337
+
return false;
338
338
+
}
339
339
+
}
340
340
+
}
341
341
+
}
342
342
+
return stage2_vttbr() == (uint64_t)(uintptr_t)g_l1;
343
343
+
}
···
1
1
+
from pathlib import Path
2
2
+
import re
3
3
+
import sys
4
4
+
5
5
+
6
6
+
root = Path(__file__).resolve().parents[1]
7
7
+
8
8
+
text_files = [
9
9
+
*root.glob("core/**/*.c"),
10
10
+
*root.glob("drivers/**/*.c"),
11
11
+
*root.glob("mm/**/*.c"),
12
12
+
*root.glob("arch/**/*.c"),
13
13
+
*root.glob("guest/**/*.c"),
14
14
+
*root.glob("include/**/*.h"),
15
15
+
*root.glob("tools/**/*.py"),
16
16
+
*root.glob("scripts/**/*.py"),
17
17
+
root / "Makefile",
18
18
+
root / "README.md",
19
19
+
]
20
20
+
21
21
+
blocked = ["HV_" + "VERSION", "0" + ".1.0", "get_hv_" + "version"]
22
22
+
23
23
+
for path in text_files:
24
24
+
text = path.read_text()
25
25
+
if any(item in text for item in blocked):
26
26
+
print(f"project versioning residue in {path.relative_to(root)}")
27
27
+
sys.exit(1)
28
28
+
29
29
+
for path in [*root.glob("core/**/*.c"), *root.glob("drivers/**/*.c"), *root.glob("mm/**/*.c"), *root.glob("arch/**/*.c"), *root.glob("guest/**/*.c"), *root.glob("include/**/*.h")]:
30
30
+
text = path.read_text()
31
31
+
if re.search(r"/\*|//", text):
32
32
+
print(f"source comment residue in {path.relative_to(root)}")
33
33
+
sys.exit(1)
34
34
+
35
35
+
config = (root / "include/hv/config.h").read_text()
36
36
+
if "#define CONFIG_MONITOR_MUTATION 0" not in config:
37
37
+
print("monitor mutation must default off")
38
38
+
sys.exit(1)
39
39
+
40
40
+
monitor = (root / "core/monitor.c").read_text()
41
41
+
required = [
42
42
+
"write64 disabled",
43
43
+
"unmap disabled",
44
44
+
"irq disabled",
45
45
+
"profile disabled",
46
46
+
"restore disabled",
47
47
+
"log clear disabled",
48
48
+
]
49
49
+
for item in required:
50
50
+
if item not in monitor:
51
51
+
print(f"missing monitor gate: {item}")
52
52
+
sys.exit(1)
53
53
+
54
54
+
makefile = (root / "Makefile").read_text()
55
55
+
for target in ["test-host", "test-diagnostic-smoke", "test-linux-smoke", "ci", "release"]:
56
56
+
if f"{target}:" not in makefile:
57
57
+
print(f"missing target {target}")
58
58
+
sys.exit(1)
···
1
1
+
#!/usr/bin/env bash
2
2
+
set -eu
3
3
+
4
4
+
project=ariel
5
5
+
profile=qemu-virt-aarch64
6
6
+
dist=dist
7
7
+
release_dir="$dist/$project-$profile"
8
8
+
archive="$dist/$project-$profile.tar.gz"
9
9
+
10
10
+
rm -rf "$release_dir" "$archive" "$archive.sha256"
11
11
+
mkdir -p "$release_dir/bin" "$release_dir/tools" "$release_dir/manifests"
12
12
+
13
13
+
cp build/hypervisor.elf "$release_dir/bin/"
14
14
+
cp build/hypervisor.bin "$release_dir/bin/"
15
15
+
cp build/hypervisor.map "$release_dir/manifests/"
16
16
+
cp build/hypervisor.readelf "$release_dir/manifests/"
17
17
+
cp build/hypervisor.objdump "$release_dir/manifests/"
18
18
+
cp README.md "$release_dir/"
19
19
+
cp Makefile "$release_dir/"
20
20
+
cp tools/log_decode.py "$release_dir/tools/"
21
21
+
22
22
+
find "$release_dir" -type f -print | sort | while read -r file; do
23
23
+
sha256sum "$file"
24
24
+
done > "$release_dir/manifests/SHA256SUMS"
25
25
+
26
26
+
tar --sort=name --owner=0 --group=0 --numeric-owner -czf "$archive" -C "$dist" "$project-$profile"
27
27
+
sha256sum "$archive" > "$archive.sha256"
28
28
+
printf '%s\n' "$archive"
···
1
1
+
#include "hv/types.h"
2
2
+
3
3
+
#include <assert.h>
4
4
+
#include <stdint.h>
5
5
+
6
6
+
int main(void)
7
7
+
{
8
8
+
uint64_t out = 0;
9
9
+
10
10
+
assert(!hv_add_overflow_u64(1u, 2u, &out));
11
11
+
assert(out == 3u);
12
12
+
assert(hv_add_overflow_u64(UINT64_MAX, 1u, &out));
13
13
+
assert(hv_range_overlaps(10u, 5u, 14u, 3u));
14
14
+
assert(!hv_range_overlaps(10u, 4u, 14u, 3u));
15
15
+
assert(hv_range_overlaps(UINT64_MAX - 1u, 4u, 0u, 1u));
16
16
+
assert(hv_is_aligned_u64(0x4000u, 0x1000u));
17
17
+
assert(!hv_is_aligned_u64(0x4001u, 0x1000u));
18
18
+
assert(!hv_is_aligned_u64(0x4000u, 0u));
19
19
+
assert(HV_ALIGN_DOWN(0x12345ull, 0x1000ull) == 0x12000ull);
20
20
+
assert(HV_ALIGN_UP(0x12345ull, 0x1000ull) == 0x13000ull);
21
21
+
assert(HV_MASK(64u) == UINT64_MAX);
22
22
+
assert(HV_MASK(12u) == 0xfffull);
23
23
+
return 0;
24
24
+
}
···
1
1
+
import subprocess
2
2
+
import sys
3
3
+
4
4
+
5
5
+
def run_log_decode(input_text: str, *args: str) -> str:
6
6
+
proc = subprocess.run(
7
7
+
[sys.executable, "tools/log_decode.py", *args],
8
8
+
input=input_text,
9
9
+
text=True,
10
10
+
check=True,
11
11
+
capture_output=True,
12
12
+
)
13
13
+
return proc.stdout
14
14
+
15
15
+
16
16
+
sample = "event seq=7 vcpu=0 kind=trap ec=0x18 name=sctlr_el1 dir=write action=3 reason=104\n"
17
17
+
18
18
+
plain = run_log_decode(sample)
19
19
+
assert "seq=7" in plain
20
20
+
assert "name=sctlr_el1" in plain
21
21
+
22
22
+
summary = run_log_decode(sample, "--summary")
23
23
+
assert "events: 1" in summary
24
24
+
assert "trap: 1" in summary
25
25
+
assert "sctlr_el1: 1" in summary
···
1
1
+
#!/usr/bin/env python3
2
2
+
from __future__ import annotations
3
3
+
4
4
+
import argparse
5
5
+
from collections import Counter
6
6
+
import shlex
7
7
+
import sys
8
8
+
9
9
+
10
10
+
def parse(line: str) -> dict[str, str]:
11
11
+
parts = shlex.split(line.strip())
12
12
+
if not parts or parts[0] != "event":
13
13
+
return {}
14
14
+
out: dict[str, str] = {}
15
15
+
for part in parts[1:]:
16
16
+
if "=" in part:
17
17
+
key, value = part.split("=", 1)
18
18
+
out[key] = value
19
19
+
return out
20
20
+
21
21
+
22
22
+
def emit_event(event: dict[str, str]) -> None:
23
23
+
print(
24
24
+
"seq={seq} vcpu={vcpu} kind={kind} ec={ec} name={name} "
25
25
+
"dir={dir} action={action} reason={reason}".format(
26
26
+
seq=event.get("seq", "-"),
27
27
+
vcpu=event.get("vcpu", "-"),
28
28
+
kind=event.get("kind", "-"),
29
29
+
ec=event.get("ec", "-"),
30
30
+
name=event.get("name", "-"),
31
31
+
dir=event.get("dir", "-"),
32
32
+
action=event.get("action", "-"),
33
33
+
reason=event.get("reason", "-"),
34
34
+
)
35
35
+
)
36
36
+
37
37
+
38
38
+
def print_counter(title: str, counter: Counter[str]) -> None:
39
39
+
print(title)
40
40
+
for key, count in counter.most_common():
41
41
+
print(f" {key}: {count}")
42
42
+
43
43
+
44
44
+
def main() -> int:
45
45
+
parser = argparse.ArgumentParser()
46
46
+
parser.add_argument("--summary", action="store_true", help="print aggregate trace counters")
47
47
+
parser.add_argument("--events", action="store_true", help="print normalized events with --summary")
48
48
+
args = parser.parse_args()
49
49
+
50
50
+
events: list[dict[str, str]] = []
51
51
+
for line in sys.stdin:
52
52
+
event = parse(line)
53
53
+
if not event:
54
54
+
continue
55
55
+
events.append(event)
56
56
+
if not args.summary or args.events:
57
57
+
emit_event(event)
58
58
+
59
59
+
if args.summary:
60
60
+
print(f"events: {len(events)}")
61
61
+
print_counter("by-kind", Counter(e.get("kind", "-") for e in events))
62
62
+
print_counter("by-ec", Counter(e.get("ec", "-") for e in events))
63
63
+
print_counter("by-sysreg", Counter(e.get("name", "-") for e in events if e.get("kind") == "trap"))
64
64
+
print_counter("by-action", Counter(e.get("action", "-") for e in events))
65
65
+
print_counter("by-reason", Counter(e.get("reason", "-") for e in events))
66
66
+
return 0
67
67
+
68
68
+
69
69
+
if __name__ == "__main__":
70
70
+
raise SystemExit(main())