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
29static void print_banner(void)
30{
31 uart_puts("\n");
32 uart_puts(HV_PROJECT_NAME " " HV_BUILD_MODE "\n");
33 uart_puts("build id=" HV_BUILD_ID "\n");
34}
35
36void hv_main(uint64_t boot_dtb_pa)
37{
38 struct guest_image_info guest_info;
39
40 uart_init();
41 print_banner();
42 log_init();
43 timer_init();
44 monitor_init();
45
46 if (arch_current_el() != 2u) {
47 panic_with_code("hypervisor must start at EL2", arch_current_el());
48 }
49 if (fdt_probe(boot_dtb_pa, &g_platform_info)) {
50 log_simple(LOG_BOOT, 30u, g_platform_info.fdt_pa, g_platform_info.size);
51 } else {
52 hv_memset(&g_platform_info, 0, sizeof(g_platform_info));
53 log_simple(LOG_BOOT, 31u, boot_dtb_pa, 0u);
54 }
55
56 arch_install_vectors();
57 el2_mmu_init_plan();
58 el2_mmu_enable();
59 allocator_init((paddr_t)(uintptr_t)g_allocator_pool, sizeof(g_allocator_pool));
60 policy_init();
61#if CONFIG_BOOT_LINUX
62 (void)policy_set_profile(POLICY_PROFILE_LINUX_BOOT);
63#endif
64 stage2_init();
65#if CONFIG_BOOT_LINUX
66 if (!guest_load_external_linux(&guest_info, CONFIG_LINUX_IMAGE_LOAD_PA,
67 CONFIG_LINUX_IMAGE_MAX_SIZE, CONFIG_LINUX_DTB_PA,
68 CONFIG_LINUX_DTB_MAX_SIZE, CONFIG_LINUX_INITRD_PA,
69 CONFIG_LINUX_INITRD_SIZE)) {
70 panic("external Linux Image load failed");
71 }
72#else
73 if (!guest_load_diagnostic(&guest_info)) {
74 panic("diagnostic guest load failed");
75 }
76#endif
77 log_simple(LOG_BOOT, 10u, guest_info.ipa_load, guest_info.size);
78 if (!stage2_map_range(CONFIG_GUEST_IPA_BASE, CONFIG_GUEST_RAM_BASE, CONFIG_GUEST_RAM_SIZE,
79 S2_MEM_NORMAL, S2_PERM_R | S2_PERM_W | S2_PERM_X)) {
80 panic("stage2 guest RAM map failed");
81 }
82
83 gicv3_init();
84 arch_el2_configure(stage2_vttbr(), stage2_vtcr());
85 selftests_run_or_panic();
86
87 vcpu_init(&g_boot_vcpu, 0u, guest_info.ipa_entry, CONFIG_GUEST_STACK_TOP);
88 vcpu_set_current(&g_boot_vcpu);
89 arch_prepare_guest_entry(&g_boot_vcpu);
90 if (guest_info.kind == GUEST_PAYLOAD_LINUX_IMAGE) {
91 vcpu_write_gpr(&g_boot_vcpu, 0u, guest_info.dtb_ipa);
92 vcpu_write_gpr(&g_boot_vcpu, 1u, 0u);
93 vcpu_write_gpr(&g_boot_vcpu, 2u, 0u);
94 vcpu_write_gpr(&g_boot_vcpu, 3u, 0u);
95 }
96
97 uart_puts("launching guest entry=");
98 uart_put_hex64(g_boot_vcpu.pc);
99 uart_puts(" stack=");
100 uart_put_hex64(g_boot_vcpu.sp_el1);
101 uart_puts("\n");
102 g_boot_vcpu.state = VCPU_RUNNING;
103 timer_vcpu_sync(&g_boot_vcpu);
104 gicv3_flush_vcpu_state(&g_boot_vcpu);
105 arch_vcpu_enter(&g_boot_vcpu);
106 panic("arch_vcpu_enter returned");
107}