#include "hv/allocator.h" #include "hv/arch.h" #include "hv/config.h" #include "hv/el2_mmu.h" #include "hv/fdt.h" #include "hv/gicv3.h" #include "hv/guest_loader.h" #include "hv/log.h" #include "hv/monitor.h" #include "hv/panic.h" #include "hv/platform.h" #include "hv/policy.h" #include "hv/selftest.h" #include "hv/stage2.h" #include "hv/string.h" #include "hv/timer.h" #include "hv/uart.h" #include "hv/vcpu.h" static struct vcpu g_boot_vcpu; static uint8_t g_allocator_pool[CONFIG_PAGE_SIZE * 16u] __attribute__((aligned(4096))); static struct fdt_platform_info g_platform_info; const struct fdt_platform_info *platform_info(void) { return &g_platform_info; } bool platform_selftest(void) { return CONFIG_PLATFORM_QEMU_VIRT == 1 && CONFIG_UART_BASE == 0x09000000ull && CONFIG_GICD_BASE == 0x08000000ull && CONFIG_GICR_BASE == 0x080A0000ull && CONFIG_GUEST_IPA_BASE == 0x40000000ull && CONFIG_GUEST_RAM_BASE == 0x42000000ull && CONFIG_GUEST_RAM_SIZE == 0x30000000ull && CONFIG_LINUX_DTB_PA == 0x71e00000ull; } static void print_banner(void) { uart_puts("\n"); uart_puts(HV_PROJECT_NAME " " HV_BUILD_MODE "\n"); uart_puts("build id=" HV_BUILD_ID "\n"); } void hv_main(uint64_t boot_dtb_pa) { struct guest_image_info guest_info; uart_init(); print_banner(); log_init(); timer_init(); monitor_init(); if (arch_current_el() != 2u) { panic_with_code("hypervisor must start at EL2", arch_current_el()); } if (fdt_probe(boot_dtb_pa, &g_platform_info)) { log_simple(LOG_BOOT, 30u, g_platform_info.fdt_pa, g_platform_info.size); } else { hv_memset(&g_platform_info, 0, sizeof(g_platform_info)); log_simple(LOG_BOOT, 31u, boot_dtb_pa, 0u); } arch_install_vectors(); el2_mmu_init_plan(); el2_mmu_enable(); allocator_init((paddr_t)(uintptr_t)g_allocator_pool, sizeof(g_allocator_pool)); policy_init(); #if CONFIG_BOOT_LINUX (void)policy_set_profile(POLICY_PROFILE_LINUX_BOOT); #endif stage2_init(); #if CONFIG_BOOT_LINUX if (!guest_load_external_linux(&guest_info, CONFIG_LINUX_IMAGE_LOAD_PA, CONFIG_LINUX_IMAGE_MAX_SIZE, CONFIG_LINUX_DTB_PA, CONFIG_LINUX_DTB_MAX_SIZE, CONFIG_LINUX_INITRD_PA, CONFIG_LINUX_INITRD_SIZE)) { panic("external Linux Image load failed"); } #else if (!guest_load_diagnostic(&guest_info)) { panic("diagnostic guest load failed"); } #endif log_simple(LOG_BOOT, 10u, guest_info.ipa_load, guest_info.size); if (!stage2_map_range(CONFIG_GUEST_IPA_BASE, CONFIG_GUEST_RAM_BASE, CONFIG_GUEST_RAM_SIZE, S2_MEM_NORMAL, S2_PERM_R | S2_PERM_W | S2_PERM_X)) { panic("stage2 guest RAM map failed"); } gicv3_init(); arch_el2_configure(stage2_vttbr(), stage2_vtcr()); selftests_run_or_panic(); vcpu_init(&g_boot_vcpu, 0u, guest_info.ipa_entry, CONFIG_GUEST_STACK_TOP); vcpu_set_current(&g_boot_vcpu); arch_prepare_guest_entry(&g_boot_vcpu); if (guest_info.kind == GUEST_PAYLOAD_LINUX_IMAGE) { vcpu_write_gpr(&g_boot_vcpu, 0u, guest_info.dtb_ipa); vcpu_write_gpr(&g_boot_vcpu, 1u, 0u); vcpu_write_gpr(&g_boot_vcpu, 2u, 0u); vcpu_write_gpr(&g_boot_vcpu, 3u, 0u); } uart_puts("launching guest entry="); uart_put_hex64(g_boot_vcpu.pc); uart_puts(" stack="); uart_put_hex64(g_boot_vcpu.sp_el1); uart_puts("\n"); g_boot_vcpu.state = VCPU_RUNNING; timer_vcpu_sync(&g_boot_vcpu); gicv3_flush_vcpu_state(&g_boot_vcpu); arch_vcpu_enter(&g_boot_vcpu); panic("arch_vcpu_enter returned"); }