AArch64 EL2 hypervisor for QEMU virt that boots at EL2
1#include "hv/allocator.h"
2#include "hv/arch.h"
3#include "hv/config.h"
4#include "hv/el2_mmu.h"
5#include "hv/fdt.h"
6#include "hv/gicv3.h"
7#include "hv/guest_loader.h"
8#include "hv/log.h"
9#include "hv/monitor.h"
10#include "hv/panic.h"
11#include "hv/platform.h"
12#include "hv/policy.h"
13#include "hv/selftest.h"
14#include "hv/stage2.h"
15#include "hv/string.h"
16#include "hv/timer.h"
17#include "hv/uart.h"
18#include "hv/vcpu.h"
19
20static struct vcpu g_boot_vcpu;
21static uint8_t g_allocator_pool[CONFIG_PAGE_SIZE * 16u] __attribute__((aligned(4096)));
22static struct fdt_platform_info g_platform_info;
23
24const struct fdt_platform_info *platform_info(void)
25{
26 return &g_platform_info;
27}
28
29bool platform_selftest(void)
30{
31 return CONFIG_PLATFORM_QEMU_VIRT == 1 &&
32 CONFIG_UART_BASE == 0x09000000ull &&
33 CONFIG_GICD_BASE == 0x08000000ull &&
34 CONFIG_GICR_BASE == 0x080A0000ull &&
35 CONFIG_GUEST_IPA_BASE == 0x40000000ull &&
36 CONFIG_GUEST_RAM_BASE == 0x42000000ull &&
37 CONFIG_GUEST_RAM_SIZE == 0x30000000ull &&
38 CONFIG_LINUX_DTB_PA == 0x71e00000ull;
39}
40
41static void print_banner(void)
42{
43 uart_puts("\n");
44 uart_puts(HV_PROJECT_NAME " " HV_BUILD_MODE "\n");
45 uart_puts("build id=" HV_BUILD_ID "\n");
46}
47
48void hv_main(uint64_t boot_dtb_pa)
49{
50 struct guest_image_info guest_info;
51
52 uart_init();
53 print_banner();
54 log_init();
55 timer_init();
56 monitor_init();
57
58 if (arch_current_el() != 2u) {
59 panic_with_code("hypervisor must start at EL2", arch_current_el());
60 }
61 if (fdt_probe(boot_dtb_pa, &g_platform_info)) {
62 log_simple(LOG_BOOT, 30u, g_platform_info.fdt_pa, g_platform_info.size);
63 } else {
64 hv_memset(&g_platform_info, 0, sizeof(g_platform_info));
65 log_simple(LOG_BOOT, 31u, boot_dtb_pa, 0u);
66 }
67
68 arch_install_vectors();
69 el2_mmu_init_plan();
70 el2_mmu_enable();
71 allocator_init((paddr_t)(uintptr_t)g_allocator_pool, sizeof(g_allocator_pool));
72 policy_init();
73#if CONFIG_BOOT_LINUX
74 (void)policy_set_profile(POLICY_PROFILE_LINUX_BOOT);
75#endif
76 stage2_init();
77#if CONFIG_BOOT_LINUX
78 if (!guest_load_external_linux(&guest_info, CONFIG_LINUX_IMAGE_LOAD_PA,
79 CONFIG_LINUX_IMAGE_MAX_SIZE, CONFIG_LINUX_DTB_PA,
80 CONFIG_LINUX_DTB_MAX_SIZE, CONFIG_LINUX_INITRD_PA,
81 CONFIG_LINUX_INITRD_SIZE)) {
82 panic("external Linux Image load failed");
83 }
84#else
85 if (!guest_load_diagnostic(&guest_info)) {
86 panic("diagnostic guest load failed");
87 }
88#endif
89 log_simple(LOG_BOOT, 10u, guest_info.ipa_load, guest_info.size);
90 if (!stage2_map_range(CONFIG_GUEST_IPA_BASE, CONFIG_GUEST_RAM_BASE, CONFIG_GUEST_RAM_SIZE,
91 S2_MEM_NORMAL, S2_PERM_R | S2_PERM_W | S2_PERM_X)) {
92 panic("stage2 guest RAM map failed");
93 }
94
95 gicv3_init();
96 arch_el2_configure(stage2_vttbr(), stage2_vtcr());
97 selftests_run_or_panic();
98
99 vcpu_init(&g_boot_vcpu, 0u, guest_info.ipa_entry, CONFIG_GUEST_STACK_TOP);
100 vcpu_set_current(&g_boot_vcpu);
101 arch_prepare_guest_entry(&g_boot_vcpu);
102 if (guest_info.kind == GUEST_PAYLOAD_LINUX_IMAGE) {
103 vcpu_write_gpr(&g_boot_vcpu, 0u, guest_info.dtb_ipa);
104 vcpu_write_gpr(&g_boot_vcpu, 1u, 0u);
105 vcpu_write_gpr(&g_boot_vcpu, 2u, 0u);
106 vcpu_write_gpr(&g_boot_vcpu, 3u, 0u);
107 }
108
109 uart_puts("launching guest entry=");
110 uart_put_hex64(g_boot_vcpu.pc);
111 uart_puts(" stack=");
112 uart_put_hex64(g_boot_vcpu.sp_el1);
113 uart_puts("\n");
114 g_boot_vcpu.state = VCPU_RUNNING;
115 timer_vcpu_sync(&g_boot_vcpu);
116 gicv3_flush_vcpu_state(&g_boot_vcpu);
117 arch_vcpu_enter(&g_boot_vcpu);
118 panic("arch_vcpu_enter returned");
119}