AArch64 EL2 hypervisor for QEMU virt that boots at EL2
7.3 kB
170 lines
1PROJECT := ariel
2TARGET := aarch64-none-elf
3BUILD := build
4HV_ELF := $(BUILD)/hypervisor.elf
5HV_BIN := $(BUILD)/hypervisor.bin
6GUEST_ELF := $(BUILD)/guest/diag.elf
7GUEST_BIN := $(BUILD)/guest/diag.bin
8MAP := $(BUILD)/hypervisor.map
9OBJDUMP := $(BUILD)/hypervisor.objdump
10READELF := $(BUILD)/hypervisor.readelf
11DIST := dist
12RELEASE_DIR := $(DIST)/$(PROJECT)-qemu-virt-aarch64
13RELEASE_TAR := $(DIST)/$(PROJECT)-qemu-virt-aarch64.tar.gz
14
15CC := clang
16LD := ld.lld
17OBJCOPY := llvm-objcopy
18OBJDUMP_TOOL := llvm-objdump
19READELF_TOOL := llvm-readelf
20PYTHON ?= python3
21QEMU ?= qemu-system-aarch64
22QEMU_RAM ?= 1G
23comma := ,
24LINUX_DIR ?= /tmp/ariel-linux
25LINUX_IMAGE_URL ?= http://deb.debian.org/debian/dists/bookworm/main/installer-arm64/current/images/netboot/debian-installer/arm64/linux
26LINUX_INITRD_URL ?= http://deb.debian.org/debian/dists/bookworm/main/installer-arm64/current/images/netboot/debian-installer/arm64/initrd.gz
27LINUX_INITRD_BYTES := $(if $(LINUX_INITRD),$(shell stat -c %s "$(LINUX_INITRD)" 2>/dev/null),)
28LINUX_INITRD_SIZE := $(if $(LINUX_INITRD),$(if $(LINUX_INITRD_BYTES),$(LINUX_INITRD_BYTES),0),0)
29LINUX_INITRD_DEVICE := $(if $(LINUX_INITRD),-device loader$(comma)file=$(LINUX_INITRD)$(comma)addr=0x46000000$(comma)force-raw=on,)
30
31COMMON_CFLAGS := --target=$(TARGET) -std=c11 -ffreestanding -fno-builtin \
32 -fno-stack-protector -fno-unwind-tables -fno-asynchronous-unwind-tables \
33 -fno-exceptions -mgeneral-regs-only -mstrict-align -Wall -Wextra -Werror \
34 -Wconversion -Wsign-conversion -Wmissing-prototypes -Wstrict-prototypes \
35 -Iinclude -I.
36EXTRA_CFLAGS ?=
37HV_CFLAGS := $(COMMON_CFLAGS) -O2 -g -D__HYPERVISOR__ $(EXTRA_CFLAGS)
38GUEST_CFLAGS := $(COMMON_CFLAGS) -O2 -g -D__GUEST__
39ASFLAGS := --target=$(TARGET) -g -Iinclude -I.
40LDFLAGS := -nostdlib -static --fatal-warnings
41
42HV_C_SRCS := \
43 arch/aarch64/arch.c \
44 core/main.c core/el2_mmu.c core/fdt.c core/guest_loader.c core/image.c core/log.c core/mmio_policy.c core/panic.c core/policy.c core/psci.c core/selftest.c \
45 core/string.c core/sysreg.c core/trap.c core/vcpu.c core/monitor.c \
46 drivers/gicv3.c drivers/pl011.c drivers/timer.c \
47 mm/allocator.c mm/stage2.c
48HV_S_SRCS := arch/aarch64/entry.S arch/aarch64/vectors.S arch/aarch64/vcpu.S arch/aarch64/guest_blob.S
49GUEST_C_SRCS := guest/main.c
50GUEST_S_SRCS := guest/start.S
51
52HV_OBJS := $(HV_C_SRCS:%.c=$(BUILD)/%.o) $(HV_S_SRCS:%.S=$(BUILD)/%.o)
53GUEST_OBJS := $(GUEST_C_SRCS:%.c=$(BUILD)/%.o) $(GUEST_S_SRCS:%.S=$(BUILD)/%.o)
54
55.PHONY: all clean run run-linux linux-artifacts test-linux-smoke test-diagnostic-smoke test-host test ci release debug objdump readelf
56all: $(HV_ELF) $(HV_BIN) $(OBJDUMP) $(READELF)
57
58$(BUILD):
59 mkdir -p $(BUILD)
60
61$(BUILD)/guest/%.o: guest/%.c
62 mkdir -p $(dir $@)
63 $(CC) $(GUEST_CFLAGS) -c $< -o $@
64
65$(BUILD)/%.o: %.c
66 mkdir -p $(dir $@)
67 $(CC) $(HV_CFLAGS) -c $< -o $@
68
69$(BUILD)/%.o: %.S
70 mkdir -p $(dir $@)
71 $(CC) $(ASFLAGS) -c $< -o $@
72
73$(BUILD)/arch/aarch64/guest_blob.o: arch/aarch64/guest_blob.S $(GUEST_BIN)
74 mkdir -p $(dir $@)
75 $(CC) $(ASFLAGS) -c $< -o $@
76
77$(GUEST_ELF): $(GUEST_OBJS) guest/linker.ld
78 mkdir -p $(dir $@)
79 $(LD) $(LDFLAGS) -T guest/linker.ld $(GUEST_OBJS) -o $@
80
81$(GUEST_BIN): $(GUEST_ELF)
82 $(OBJCOPY) -O binary $< $@
83
84$(HV_ELF): $(HV_OBJS) linker.ld
85 mkdir -p $(dir $@)
86 $(LD) $(LDFLAGS) -T linker.ld -Map=$(MAP) $(HV_OBJS) -o $@
87
88$(HV_BIN): $(HV_ELF)
89 $(OBJCOPY) -O binary $< $@
90
91$(OBJDUMP): $(HV_ELF)
92 $(OBJDUMP_TOOL) -d -S $< > $@
93
94$(READELF): $(HV_ELF)
95 $(READELF_TOOL) -a $< > $@
96
97run: $(HV_ELF)
98 $(QEMU) -M virt,virtualization=on,gic-version=3 -cpu cortex-a57 -m $(QEMU_RAM) \
99 -nographic -serial mon:stdio -kernel $(HV_ELF)
100
101run-linux:
102 @if [ -z "$(LINUX_IMAGE)" ] || [ -z "$(LINUX_DTB)" ]; then \
103 echo "usage: make run-linux LINUX_IMAGE=/path/Image LINUX_DTB=/path/qemu-virt.dtb [LINUX_INITRD=/path/initrd]"; \
104 echo "builds a Linux-profile hypervisor and loads Image+DTB into guest RAM"; \
105 else \
106 $(MAKE) -B BUILD=build-linux EXTRA_CFLAGS="-DCONFIG_BOOT_LINUX=1 -DCONFIG_LINUX_INITRD_SIZE=$(LINUX_INITRD_SIZE)ull" all && \
107 $(QEMU) -M virt,virtualization=on,gic-version=3 -cpu cortex-a57 -m $(QEMU_RAM) \
108 -nographic -serial mon:stdio -kernel build-linux/hypervisor.elf \
109 -device loader,file=$(LINUX_IMAGE),addr=0x42000000,force-raw=on \
110 -device loader,file=$(LINUX_DTB),addr=0x71e00000,force-raw=on \
111 $(LINUX_INITRD_DEVICE); \
112 fi
113
114linux-artifacts:
115 mkdir -p $(LINUX_DIR)
116 $(QEMU) -M virt,virtualization=on,gic-version=3,dumpdtb=$(LINUX_DIR)/virt.dtb -cpu cortex-a57 -m $(QEMU_RAM) -nographic
117 curl -L --fail --show-error --output $(LINUX_DIR)/debian-arm64-linux $(LINUX_IMAGE_URL)
118 curl -L --fail --show-error --output $(LINUX_DIR)/debian-arm64-initrd.gz $(LINUX_INITRD_URL)
119
120test-linux-smoke: linux-artifacts
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 grep -q 'Booting Linux on physical CPU' $(LINUX_DIR)/linux-smoke.log
123 grep -q 'Kernel command line: console=ttyAMA0 earlycon' $(LINUX_DIR)/linux-smoke.log
124 grep -q 'CPU: All CPU(s) started at EL1' $(LINUX_DIR)/linux-smoke.log
125 grep -q 'Trying to unpack rootfs image as initramfs' $(LINUX_DIR)/linux-smoke.log
126 grep -q 'Freeing initrd memory' $(LINUX_DIR)/linux-smoke.log
127 grep -q 'Run /init as init process' $(LINUX_DIR)/linux-smoke.log
128 ! grep -q 'Initramfs unpacking failed' $(LINUX_DIR)/linux-smoke.log
129 ! grep -q 'Kernel panic' $(LINUX_DIR)/linux-smoke.log
130
131test-diagnostic-smoke: $(HV_ELF)
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 grep -q 'ariel qemu-virt-aarch64' $(BUILD)/diagnostic-smoke.log
134 grep -q 'guest: diagnostic guest: requested hv id' $(BUILD)/diagnostic-smoke.log
135 grep -q 'monitor entered reason=guest requested pause' $(BUILD)/diagnostic-smoke.log
136 ! grep -q 'panic:' $(BUILD)/diagnostic-smoke.log
137
138test-host:
139 mkdir -p build-host
140 $(CC) -std=c11 -Wall -Wextra -Werror -Iinclude tests/host/test_hv_types.c -o build-host/test_hv_types
141 build-host/test_hv_types
142 $(CC) -std=c11 -Wall -Wextra -Werror -Iinclude tests/host/test_hv_interval.c -o build-host/test_hv_interval
143 build-host/test_hv_interval
144 $(CC) -std=c11 -Wall -Wextra -Werror -Iinclude tests/host/test_qemu_virt.c -o build-host/test_qemu_virt
145 build-host/test_qemu_virt
146 $(CC) -std=c11 -Wall -Wextra -Werror -Iinclude tests/host/test_hvc_abi.c -o build-host/test_hvc_abi
147 build-host/test_hvc_abi
148 $(CC) -std=c11 -Wall -Wextra -Werror -Iinclude tests/host/test_sysreg_key.c core/sysreg.c core/string.c -o build-host/test_sysreg_key
149 build-host/test_sysreg_key
150 $(PYTHON) tests/test_log_decode.py
151 $(PYTHON) scripts/verify_topology.py
152 $(PYTHON) scripts/check_release.py
153
154test: all test-host test-diagnostic-smoke
155
156ci: clean release
157
158release: test
159 scripts/release.sh
160
161debug: $(HV_ELF)
162 @echo "gdb command: gdb-multiarch $(HV_ELF) -ex 'target remote :1234'"
163 $(QEMU) -M virt,virtualization=on,gic-version=3 -cpu cortex-a57 -m $(QEMU_RAM) \
164 -nographic -serial mon:stdio -S -gdb tcp::1234 -kernel $(HV_ELF)
165
166objdump: $(OBJDUMP)
167readelf: $(READELF)
168
169clean:
170 rm -rf $(BUILD)