diff --git a/platform/x86_64/qemu/board.rs b/platform/x86_64/qemu/board.rs index df2c60dc..016b8a7d 100644 --- a/platform/x86_64/qemu/board.rs +++ b/platform/x86_64/qemu/board.rs @@ -53,10 +53,12 @@ const ROOT_ZONE_UEFI_REGION: HvConfigMemoryRegion = HvConfigMemoryRegion { const ROOT_ZONE_UEFI_REGION_ID: usize = 0x3; pub const ROOT_ZONE_NAME: &str = "root-linux"; -pub const ROOT_ZONE_CMDLINE: &str = -// "BOOT_IMAGE=/boot/aster-kernel-osdk-bin SHELL=/bin/sh LOGNAME=root HOME=/ USER=root PATH=/bin:/benchmark ostd.log_level=info console=ttyS0 console=tty0 -- sh -l"; -// TODO: Asterinas -"console=ttyS0 earlyprintk=serial nointremap no_timer_check efi=noruntime pci=pcie_scan_all,lastbus=1 root=/dev/vda rw init=/init\0"; + +/// Reserved HPA range for zone1 high memory (0x1_0000_0000 -> 0x2_E000_0000). +/// Adjust if zone1 high-memory layout changes. +const ZONE1_HIGH_RESERVED_SIZE: u64 = 0x1_E000_0000; +pub const ROOT_ZONE_CMDLINE: &str = + "console=tty0 console=ttyS0 earlycon=efifb earlyprintk=serial nointremap no_timer_check efi=noruntime pci=pcie_scan_all,lastbus=1 root=/dev/vda rw init=/sbin/init\0"; //"console=ttyS0 earlyprintk=serial rdinit=/init nokaslr nointremap\0"; // noapic // video=vesafb // /lib/systemd/systemd @@ -106,13 +108,11 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 10] = [ mem_type: MEM_TYPE_RESERVED, physical_start: 0x1_0000_0000, virtual_start: 0x1_0000_0000, - size: 0x7000_0000, - }, // zone 1 + size: ZONE1_HIGH_RESERVED_SIZE, + }, // zone 1 (0x100000000 → 0x2E0000000) ]; const ROOT_ZONE_CMDLINE_ADDR: GuestPhysAddr = 0x9000; -// TODO: Asterinas -// const ROOT_ZONE_SETUP_ADDR: GuestPhysAddr = 0xf_f000; const ROOT_ZONE_SETUP_ADDR: GuestPhysAddr = 0xa000; const ROOT_ZONE_VMLINUX_ENTRY_ADDR: GuestPhysAddr = 0x10_0000; const ROOT_ZONE_SCREEN_BASE_ADDR: GuestPhysAddr = 0x7000_0000; @@ -126,14 +126,15 @@ pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { kernel_entry_gpa: ROOT_ZONE_VMLINUX_ENTRY_ADDR, cmdline_load_gpa: ROOT_ZONE_CMDLINE_ADDR, setup_load_gpa: ROOT_ZONE_SETUP_ADDR, - // TODO: Asterinas - initrd_load_gpa:0,// 0x1530_0000, - initrd_size:0,// 0x210_0000, //0x26_b000, + initrd_load_gpa: 0, // 0x1500_0000, + initrd_size: 0, //0x26_b000, rsdp_memory_region_id: ROOT_ZONE_RSDP_REGION_ID, acpi_memory_region_id: ROOT_ZONE_ACPI_REGION_ID, uefi_memory_region_id: ROOT_ZONE_UEFI_REGION_ID, // not longer than 32 bits screen_base: ROOT_ZONE_SCREEN_BASE_ADDR, + multiboot_info_paddr: 0, + multiboot_enabled: 0, }; pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [HvPciConfig { @@ -159,12 +160,9 @@ pub const ROOT_PCI_DEVS: [HvPciDevConfig; 8] = [ pci_dev!(0x0, 0x0, 0x1, 0x0, VpciDevType::Physical), // VGA controller pci_dev!(0x0, 0x0, 0x2, 0x0, VpciDevType::Physical), // Ethernet controller pci_dev!(0x0, 0x0, 0x3, 0x0, VpciDevType::Physical), // PCI bridge - // Asterinas - pci_dev!(0x0, 0x0, 0x4, 0x0, VpciDevType::Physical), // PCI bridge - pci_dev!(0x0, 0x0, 0x1f, 0x0, VpciDevType::Physical), // ISA bridge pci_dev!(0x0, 0x0, 0x1f, 0x2, VpciDevType::Physical), // SATA controller - // pci_dev!(0x0, 0x0, 0x1f, 0x3, VpciDevType::Physical), // SMBus + pci_dev!(0x0, 0x0, 0x1f, 0x3, VpciDevType::Physical), // SMBus pci_dev!(0x0, 0x1, 0x0, 0x0, VpciDevType::Physical), // SCSI controller ]; diff --git a/platform/x86_64/qemu/configs/virtio_cfg.json b/platform/x86_64/qemu/configs/virtio_cfg.json index 204df9d8..177f002f 100644 --- a/platform/x86_64/qemu/configs/virtio_cfg.json +++ b/platform/x86_64/qemu/configs/virtio_cfg.json @@ -7,46 +7,34 @@ "zone0_ipa": "0x40300000", "zonex_ipa": "0x0", "size": "0x20000000" - }, - { - "zone0_ipa": "0x100000000", - "zonex_ipa": "0x100000000", - "size": "0x70000000" } ], "devices": [ { "type": "console", - "addr": "0x5950f000", + "status": "enable", + "addr": "0xFEB00000", "len": "0x200", - "irq": 10, - "status": "enable" + "irq": "16" }, { "type": "net", - "addr": "0x5950f200", + "status": "enable", + "addr": "0xFEB00200", "len": "0x200", - "irq": 14, + "irq": "17", "tap": "tap0", - "mac": [ - "0x00", - "0x16", - "0x3e", - "0x10", - "0x10", - "0x10" - ], - "status": "enable" + "mac": ["0x00", "0x16", "0x3e", "0x10", "0x10", "0x10"] }, { "type": "blk", - "addr": "0x5950f400", + "status": "enable", + "addr": "0xFEB00400", "len": "0x200", - "irq": 11, - "img": "rootfs2.img", - "status": "enable" + "irq": "18", + "img": "/zone1_disk.img" } ] } ] -} \ No newline at end of file +} diff --git a/platform/x86_64/qemu/configs/zone1-asterinas.json b/platform/x86_64/qemu/configs/zone1-asterinas.json new file mode 100644 index 00000000..58e92943 --- /dev/null +++ b/platform/x86_64/qemu/configs/zone1-asterinas.json @@ -0,0 +1,84 @@ +{ + "name": "asterinas", + "zone_id": 1, + "cpus": [2, 3], + "memory_regions": [ + { + "type": "ram", + "physical_start": "0x40300000", + "virtual_start": "0x0", + "size": "0xe0000" + }, + { + "type": "ram", + "physical_start": "0x403e0000", + "virtual_start": "0xe0000", + "size": "0x20000" + }, + { + "type": "ram", + "physical_start": "0x40400000", + "virtual_start": "0x100000", + "size": "0x1fe00000" + }, + { + "type": "ram", + "physical_start": "0x60200000", + "virtual_start": "0x1ff00000", + "size": "0x100000" + }, + { + "type": "virtio", + "physical_start": "0xFEB00000", + "virtual_start": "0xFEB00000", + "size": "0x2000" + } + ], + "interrupts": [], + "ivc_configs": [], + "kernel_filepath": "./aster-kernel-osdk-bin", + "dtb_filepath": "null", + "kernel_load_paddr": "0x8000000", + "dtb_load_paddr": "0x00000000", + "entry_point": "0x8000", + "multiboot_enabled": true, + "multiboot_info_paddr": "0x9000000", + "kernel_cmdline": "console=hvc0 root=/dev/vda rw ostd.log_level=error", + "initramfs_filepath": "./initramfs.cpio.gz", + "initramfs_load_gpa": "0x10000000", + "arch_config": { + "ioapic_base": "0xfec00000", + "ioapic_size": "0x1000", + "boot_filepath": "mb2_boot.bin", + "boot_load_paddr": "0x8000", + "kernel_entry_gpa": "0x8000000", + "cmdline_load_gpa": "0x9000000", + "setup_load_gpa": "0x80000", + "initrd_load_gpa": "0x0", + "initrd_size": "0x0", + "rsdp_memory_region_id": 1, + "acpi_memory_region_id": 3, + "uefi_memory_region_id": 0, + "screen_base": "0x0" + }, + "pci_config": [ + { + "ecam_base": "0xb0000000", + "ecam_size": "0x200000", + "io_base": "0x0", + "io_size": "0x0", + "pci_io_base": "0x0", + "mem32_base": "0x0", + "mem32_size": "0x0", + "pci_mem32_base": "0x0", + "mem64_base": "0x0", + "mem64_size": "0x0", + "pci_mem64_base": "0x0", + "bus_range_begin": "0x0", + "bus_range_end": "0x1f", + "domain": "0x0" + } + ], + "num_pci_devs": 0, + "alloc_pci_devs": [] +} diff --git a/platform/x86_64/qemu/image/mb2_bootloader/mb2_boot.S b/platform/x86_64/qemu/image/mb2_bootloader/mb2_boot.S new file mode 100644 index 00000000..eb0cfa2b --- /dev/null +++ b/platform/x86_64/qemu/image/mb2_bootloader/mb2_boot.S @@ -0,0 +1,68 @@ +# Multiboot2 bootloader for Asterinas zone1 +# Transitions from 16-bit real mode to 32-bit protected mode, +# sets up GDT with TSS, then jumps to the kernel entry point. +# +# Entry state (from VMCS guest_regs via unrestricted guest): +# EAX = Multiboot2 magic (0x36D76289) +# EBX = Multiboot2 info pointer (GPA) +# ESI = Kernel entry point (GPA) + +.section .text +.code16 +.global mb2_entry16 +mb2_entry16: + cli + cld + + mov ebp, eax # save multiboot magic + mov edi, ebx # save multiboot info pointer + mov ecx, esi # save kernel entry point + + xor ax, ax + mov ds, ax + mov es, ax + mov ss, ax + + lgdt [mb2_gdt_desc] + mov eax, cr0 + or eax, 0x1 + mov cr0, eax + + ljmp 0x08, mb2_entry32 + +.code32 +.global mb2_entry32 +mb2_entry32: + mov ax, 0x10 + mov ds, ax + mov es, ax + mov ss, ax + mov fs, ax + mov gs, ax + + # Load TSS (entry 4 at selector 0x20) + mov ax, 0x20 + ltr ax + + # Restore Multiboot2 parameters + mov eax, ebp + mov ebx, edi + + # Set up stack + mov esp, MB2_STACK + + # Jump to kernel entry + jmp ecx + +.align 16 +mb2_gdt: + .quad 0x0000000000000000 # 0x00: null + .quad 0x00cf9b000000ffff # 0x08: 32-bit code + .quad 0x00cf93000000ffff # 0x10: 32-bit data + .quad 0x0000000000000000 # 0x18: unused + .quad MB2_TSS_DESCRIPTOR # 0x20: 32-bit available TSS +mb2_gdt_end: + +mb2_gdt_desc: + .short mb2_gdt_end - mb2_gdt - 1 + .long mb2_gdt diff --git a/platform/x86_64/qemu/image/mb2_bootloader/mb2_boot.ld b/platform/x86_64/qemu/image/mb2_bootloader/mb2_boot.ld new file mode 100644 index 00000000..dc5e8666 --- /dev/null +++ b/platform/x86_64/qemu/image/mb2_bootloader/mb2_boot.ld @@ -0,0 +1,15 @@ +OUTPUT_ARCH(i386) +BASE_ADDRESS = 0x8000; + +ENTRY(mb2_entry16) +SECTIONS +{ + . = BASE_ADDRESS; + .text : { + *(.text .text.*) + } + + /DISCARD/ : { + *(.eh_frame) *(.eh_frame_hdr) + } +} diff --git a/platform/x86_64/qemu/image/mb2_bootloader/mb2_boot.mk b/platform/x86_64/qemu/image/mb2_bootloader/mb2_boot.mk new file mode 100644 index 00000000..7cef11e9 --- /dev/null +++ b/platform/x86_64/qemu/image/mb2_bootloader/mb2_boot.mk @@ -0,0 +1,37 @@ +mb2_boot_dir := $(image_dir)/mb2_bootloader +mb2_boot_out_dir := $(image_dir)/mb2_bootloader/out + +mb2_boot_src := $(mb2_boot_dir)/mb2_boot.S +mb2_boot_lds := $(mb2_boot_dir)/mb2_boot.ld + +mb2_boot_o := $(mb2_boot_out_dir)/mb2_boot.o +mb2_boot_elf := $(mb2_boot_out_dir)/mb2_boot.elf +mb2_boot_bin := $(mb2_boot_out_dir)/mb2_boot.bin + +AS ?= as +LD ?= ld +OBJCOPY ?= objcopy + +# TSS descriptor: base=0x8048000, limit=103, type=0x89 (32-bit available TSS) +MB2_TSS_DESC := 0x8000890480000067 +MB2_STACK := 0x804a000 + +mb2_boot_flags := --32 -msyntax=intel -mnaked-reg +mb2_boot_flags += --defsym MB2_STACK=$(MB2_STACK) +mb2_boot_flags += --defsym MB2_TSS_DESCRIPTOR=$(MB2_TSS_DESC) + +mb2_boot: | $(mb2_boot_out_dir) $(mb2_boot_bin) + +$(mb2_boot_out_dir): + mkdir -p $@ + +$(mb2_boot_o): $(mb2_boot_src) + $(AS) $(mb2_boot_flags) $< -o $@ + +$(mb2_boot_elf): $(mb2_boot_o) $(mb2_boot_lds) + $(LD) -T$(mb2_boot_lds) $< -o $@ + +$(mb2_boot_bin): $(mb2_boot_elf) + $(OBJCOPY) $< --strip-all -O binary $@ + +.PHONY: mb2_boot diff --git a/platform/x86_64/qemu/platform.mk b/platform/x86_64/qemu/platform.mk index 8b4b0a6a..64607072 100644 --- a/platform/x86_64/qemu/platform.mk +++ b/platform/x86_64/qemu/platform.mk @@ -1,6 +1,7 @@ QEMU := qemu-system-x86_64 zone0_boot := $(image_dir)/bootloader/out/boot.bin +zone1_mb2_boot := $(image_dir)/mb2_bootloader/out/mb2_boot.bin zone0_setup := $(image_dir)/kernel/setup.bin zone0_vmlinux := $(image_dir)/kernel/vmlinux.bin zone0_asterinas := $(image_dir)/kernel/aster-kernel-osdk-bin @@ -53,7 +54,7 @@ QEMU_ARGS += -drive file=$(image_dir)/virtdisk/hvisor.iso,format=raw,index=0,med # QEMU_ARGS += -device loader,file="$(zone0_initrd)",addr=0x1a000000,force-raw=on # QEMU_ARGS += -append "initrd_size=$(shell stat -c%s $(zone0_initrd))" -$(hvisor_bin): elf boot +$(hvisor_bin): elf boot mb2_boot $(OBJCOPY) $(hvisor_elf) --strip-all -O binary $@ cp $(hvisor_elf) $(image_dir)/iso/boot mkdir -p $(image_dir)/iso/boot/kernel @@ -89,6 +90,9 @@ $(hvisor_bin): elf boot else \ echo "Warning: $(zone0_initrd) not found, skipping"; \ fi + if [ -f $(zone1_mb2_boot) ]; then \ + cp $(zone1_mb2_boot) $(image_dir)/iso/boot/kernel; \ + fi if command -v xorriso >/dev/null 2>&1; then \ grub-mkrescue /usr/lib/grub/x86_64-efi -o $(image_dir)/virtdisk/hvisor.iso $(image_dir)/iso; \ @@ -96,4 +100,5 @@ $(hvisor_bin): elf boot echo "Warning: xorriso not installed, skipping ISO creation"; \ fi -include $(image_dir)/bootloader/boot.mk \ No newline at end of file +include $(image_dir)/bootloader/boot.mk +include $(image_dir)/mb2_bootloader/mb2_boot.mk \ No newline at end of file diff --git a/src/arch/x86_64/boot.rs b/src/arch/x86_64/boot.rs index 98f1cfa7..25c749eb 100644 --- a/src/arch/x86_64/boot.rs +++ b/src/arch/x86_64/boot.rs @@ -174,10 +174,12 @@ pub struct BootParams { impl BootParams { pub fn fill(config: &HvZoneConfig, gpm: &mut MemorySet) -> HvResult { - if config.arch_config.setup_load_gpa == 0 { + if config.arch_config.setup_load_gpa == 0 && config.arch_config.multiboot_enabled == 0 { panic!("setup addr not set yet!"); } - + if config.arch_config.multiboot_enabled != 0 { + return Ok(()); + } let boot_params_hpa = unsafe { gpm.page_table_query(config.arch_config.setup_load_gpa) .unwrap() @@ -493,7 +495,6 @@ pub fn multiboot_init(info_addr: usize) { // println!("{:#x?}", tag_type); match tag_type { - multiboot_tag::MODULES => {} multiboot_tag::MEMORY_MAP => { multiboot_tags.memory_map_addr = Some(cur); } @@ -534,7 +535,6 @@ pub fn print_memory_map() { } } -/// copy kernel modules to the right place pub fn module_init(info_addr: usize) { println!("module_init"); @@ -548,7 +548,12 @@ pub fn module_init(info_addr: usize) { string_ptr: usize, } - let mut modules = [ModuleInfo { start: 0, end: 0, dst: 0, string_ptr: 0 }; MAX_MODULES]; + let mut modules = [ModuleInfo { + start: 0, + end: 0, + dst: 0, + string_ptr: 0, + }; MAX_MODULES]; let mut module_count = 0; let mut cur = info_addr; @@ -578,7 +583,10 @@ pub fn module_init(info_addr: usize) { for i in 0..module_count { let cstr = unsafe { CStr::from_ptr(modules[i].string_ptr as *const c_char) }; modules[i].dst = usize::from_str_radix(cstr.to_str().unwrap(), 16).unwrap(); - println!("module: start={:#x}, end={:#x}, dst={:#x}", modules[i].start, modules[i].end, modules[i].dst); + println!( + "module: start={:#x}, end={:#x}, dst={:#x}", + modules[i].start, modules[i].end, modules[i].dst + ); } // now move in order @@ -608,7 +616,8 @@ pub fn module_init(info_addr: usize) { if modules[i].dst != 0 { let size = modules[i].end - modules[i].start + 1; let dst_end = modules[i].dst + size; - let overlaps_self = modules[i].dst < modules[i].end && dst_end > modules[i].start; + let overlaps_self = + modules[i].dst < modules[i].end && dst_end > modules[i].start; unsafe { if overlaps_self { core::ptr::copy( diff --git a/src/arch/x86_64/cpu.rs b/src/arch/x86_64/cpu.rs index a662a5b1..1d281796 100644 --- a/src/arch/x86_64/cpu.rs +++ b/src/arch/x86_64/cpu.rs @@ -319,6 +319,12 @@ impl ArchCpu { self.vm_launch_guest_regs.rsi = rsi; } + pub fn set_multiboot_boot_regs(&mut self, multiboot_info_addr: u64, kernel_entry: u64) { + self.vm_launch_guest_regs.rax = 0x36D76289; // Multiboot2 magic + self.vm_launch_guest_regs.rbx = multiboot_info_addr; + self.vm_launch_guest_regs.rsi = kernel_entry; + } + fn activate_vmx(&mut self) -> HvResult { if self.vmx_on { return Ok(()); @@ -383,9 +389,11 @@ impl ArchCpu { Vmcs::clear(start_paddr)?; Vmcs::load(start_paddr)?; + // Setup VMCS control fields first (includes secondary controls like UNRESTRICTED_GUEST) + // This must be done before setup_vmcs_guest so that guest state is properly initialized + self.setup_vmcs_control()?; self.setup_vmcs_host(&self.host_stack_top as *const _ as usize)?; self.setup_vmcs_guest(entry, ROOT_ZONE_BOOT_STACK)?; - self.setup_vmcs_control()?; Ok(()) } @@ -419,18 +427,47 @@ impl ArchCpu { // enable EPT, RDTSCP, INVPCID, and unrestricted guest use SecondaryControls as CpuCtrl2; - Vmcs::set_control( + + // Debug: print secondary controls capability + let sec_ctl_cap = Msr::IA32_VMX_PROCBASED_CTLS2.read(); + let sec_ctl_allowed0 = sec_ctl_cap as u32; + let sec_ctl_allowed1 = (sec_ctl_cap >> 32) as u32; + debug!( + "[VMX] Secondary controls capability: allowed0={:#x}, allowed1={:#x}", + sec_ctl_allowed0, sec_ctl_allowed1 + ); + debug!( + "[VMX] UNRESTRICTED_GUEST bit in allowed1: {}", + (sec_ctl_allowed1 >> 7) & 1 + ); + + let desired_sec_ctl = (CpuCtrl2::ENABLE_EPT + | CpuCtrl2::ENABLE_RDTSCP + | CpuCtrl2::ENABLE_INVPCID + | CpuCtrl2::UNRESTRICTED_GUEST) + .bits(); + debug!("[VMX] Desired secondary controls: {:#x}", desired_sec_ctl); + + match Vmcs::set_control( VmcsControl32::SECONDARY_PROCBASED_EXEC_CONTROLS, Msr::IA32_VMX_PROCBASED_CTLS2, 0, - (CpuCtrl2::ENABLE_EPT - | CpuCtrl2::ENABLE_RDTSCP - // | CpuCtrl2::VIRTUALIZE_X2APIC - | CpuCtrl2::ENABLE_INVPCID - | CpuCtrl2::UNRESTRICTED_GUEST) - .bits(), + desired_sec_ctl, 0, - )?; + ) { + Ok(_) => { + let actual = VmcsControl32::SECONDARY_PROCBASED_EXEC_CONTROLS + .read() + .unwrap_or(0); + debug!( + "[VMX] Secondary controls set successfully, actual={:#x}", + actual + ); + } + Err(e) => { + error!("[VMX] Failed to set secondary controls: {:?}", e); + } + } // load guest IA32_PAT/IA32_EFER on VM entry use EntryControls as EntryCtrl; @@ -462,8 +499,8 @@ impl ArchCpu { VmcsControl32::VMEXIT_MSR_STORE_COUNT.write(0)?; VmcsControl32::VMEXIT_MSR_LOAD_COUNT.write(0)?; VmcsControl32::VMENTRY_MSR_LOAD_COUNT.write(0)?; + VmcsControl32::VMENTRY_INTERRUPTION_INFO_FIELD.write(0)?; - // pass-through exceptions, set I/O bitmap and MSR bitmaps VmcsControl32::EXCEPTION_BITMAP.write(0)?; if self.power_on { @@ -500,14 +537,14 @@ impl ArchCpu { }}; } - set_guest_segment!(ES, 0x93); // 16-bit, present, data, read/write, accessed - set_guest_segment!(CS, 0x9b); // 16-bit, present, code, exec/read, accessed + set_guest_segment!(ES, 0x93); + set_guest_segment!(CS, 0x9b); set_guest_segment!(SS, 0x93); set_guest_segment!(DS, 0x93); set_guest_segment!(FS, 0x93); set_guest_segment!(GS, 0x93); - set_guest_segment!(TR, 0x8b); // present, system, 32-bit TSS busy - set_guest_segment!(LDTR, 0x82); // present, system, LDT + set_guest_segment!(TR, 0x8b); + set_guest_segment!(LDTR, 0x82); VmcsGuestNW::GDTR_BASE.write(0)?; VmcsGuest32::GDTR_LIMIT.write(0xffff)?; @@ -527,7 +564,7 @@ impl ArchCpu { VmcsGuest32::ACTIVITY_STATE.write(0)?; VmcsGuest32::VMX_PREEMPTION_TIMER_VALUE.write(0)?; - VmcsGuest64::LINK_PTR.write(u64::MAX)?; // SDM Vol. 3C, Section 24.4.2 + VmcsGuest64::LINK_PTR.write(u64::MAX)?; VmcsGuest64::IA32_DEBUGCTL.write(0)?; VmcsGuest64::IA32_PAT.write(Msr::IA32_PAT.read())?; VmcsGuest64::IA32_EFER.write(0)?; diff --git a/src/arch/x86_64/entry.rs b/src/arch/x86_64/entry.rs index 2a6db8bd..2f1a0ecd 100644 --- a/src/arch/x86_64/entry.rs +++ b/src/arch/x86_64/entry.rs @@ -80,9 +80,9 @@ extern "C" fn rust_entry(magic: u32, info_addr: usize) { crate::clear_bss(); unsafe { PHYS_VIRT_OFFSET = X86_PHYS_VIRT_OFFSET }; boot::multiboot_init(info_addr); + boot::print_memory_map(); #[cfg(all(feature = "graphics"))] font_init(__board::GRAPHICS_FONT); - boot::print_memory_map(); rust_main(this_apic_id(), info_addr); } diff --git a/src/arch/x86_64/trap.rs b/src/arch/x86_64/trap.rs index 68c540d8..41a91ae7 100644 --- a/src/arch/x86_64/trap.rs +++ b/src/arch/x86_64/trap.rs @@ -16,20 +16,30 @@ use crate::{ arch::{ - cpu::{ArchCpu, this_cpu_id}, cpuid::{CpuIdEax, ExtendedFeaturesEcx, FeatureInfoFlags}, hpet, idt::{IdtStruct, IdtVector}, ipi, msr::Msr::{self, *}, pio::I8042_PORT, s2pt::Stage2PageFaultInfo, vmcs::*, vmx::{VmxCrAccessInfo, VmxExitInfo, VmxExitReason, VmxInterruptInfo, VmxIoExitInfo} + cpu::{this_cpu_id, ArchCpu}, + cpuid::{CpuIdEax, ExtendedFeaturesEcx, FeatureInfoFlags}, + hpet, + idt::{IdtStruct, IdtVector}, + ipi, + msr::Msr::{self, *}, + s2pt::Stage2PageFaultInfo, + vmcs::*, + vmx::{ + VmxCrAccessInfo, VmxExitInfo, VmxExitReason, VmxInstructionError, VmxInterruptInfo, + VmxIoExitInfo, + }, }, - cpu_data::{this_cpu_data, this_zone}, + cpu_data::this_cpu_data, device::{ irqchip::{ inject_vector, pic::{ioapic::irqs, lapic::VirtLocalApic}, }, - uart::{UartReg, virt_console_io_read, virt_console_io_write}, + uart::{virt_console_io_read, virt_console_io_write, UartReg}, }, error::HvResult, hypercall::HyperCall, - memory::{MMIOAccess, MemFlags, mmio_handle_access}, - zone::this_zone_id, + memory::{mmio_handle_access, MMIOAccess, MemFlags}, }; use bit_field::BitField; use core::mem::size_of; @@ -98,7 +108,6 @@ fn handle_irq(vector: u8) { IdtVector::VIRT_IPI_VECTOR => { ipi::handle_virt_ipi(); } - IdtVector::I8042_KEYBOARD_VECTOR => {} IdtVector::APIC_SPURIOUS_VECTOR | IdtVector::APIC_ERROR_VECTOR => {} _ => { if vector >= 0x20 && this_cpu_data().arch_cpu.power_on { @@ -147,7 +156,7 @@ fn handle_cpuid(arch_cpu: &mut ArchCpu) -> HvResult { res } CpuIdEax::TscInfo => CpuIdResult { - eax: 1, // Numerator for TSC frequency + eax: 1, // Numerator for TSC frequency ebx: 1, // Denominator for TSC frequency ecx: hpet::get_tsc_freq_mhz().unwrap_or(0) * 1_000_000, // TSC frequency in Hz edx: 0, // Reserved, typically 0 @@ -214,9 +223,6 @@ fn handle_external_interrupt() -> HvResult { let int_info = VmxInterruptInfo::new()?; trace!("VM-exit: external interrupt: {:#x?}", int_info); assert!(int_info.valid); - if int_info.vector == 0x21 { - // info!("External interrupt: IRQ1 (keyboard)"); - } handle_irq(int_info.vector); Ok(()) } @@ -277,14 +283,12 @@ fn handle_io_instruction(arch_cpu: &mut ArchCpu, exit_info: &VmxExitInfo) -> HvR { handle_pci_config_port_write(&io_info, value); } else if UART_COM1_PORT.contains(&io_info.port) { - if this_zone_id() == 0 { - virt_console_io_write(io_info.port, value); - } else { - virt_console_io_write(io_info.port, value); - // info!("zone1 uart write from {:x}: {:x}", io_info.port, value); - } - } else if I8042_PORT.contains(&io_info.port) { - // info!("unhandled port io write {:x} value: {:x}", io_info.port, value); + virt_console_io_write(io_info.port, value); + } else { + /* info!( + "unhandled port io write {:x} value: {:x}", + io_info.port, value + ); */ } } else { if PCI_CONFIG_ADDR_PORT.contains(&io_info.port) @@ -292,17 +296,8 @@ fn handle_io_instruction(arch_cpu: &mut ArchCpu, exit_info: &VmxExitInfo) -> HvR { value = handle_pci_config_port_read(&io_info); } else if UART_COM1_PORT.contains(&io_info.port) { - if this_zone_id() == 0 { - value = virt_console_io_read(io_info.port); - } else { - value = 0xff; - value = virt_console_io_read(io_info.port); - // info!("zone1 uart read from {:x}: {:x}", io_info.port, value); - } - } else if I8042_PORT.contains(&io_info.port) { - value = 0xff; - } - else { + value = virt_console_io_read(io_info.port); + } else { // info!("unhandled port io read {:x}", io_info.port); value = 0x0; } @@ -328,27 +323,44 @@ fn handle_io_instruction(arch_cpu: &mut ArchCpu, exit_info: &VmxExitInfo) -> HvR fn handle_msr_read(arch_cpu: &mut ArchCpu) -> HvResult { let rcx = arch_cpu.regs().rcx as u32; - if let Ok(msr) = Msr::try_from(rcx) { - let res = if msr == IA32_APIC_BASE { - let mut apic_base = unsafe { IA32_APIC_BASE.read() }; - // info!("APIC BASE: {:x}", apic_base); - apic_base |= 1 << 11 | 1 << 10; // enable xAPIC and x2APIC - Ok(apic_base) - } else if VirtLocalApic::msr_range().contains(&rcx) { + let res: HvResult = if rcx == IA32_APIC_BASE as u32 { + let mut apic_base = unsafe { IA32_APIC_BASE.read() }; + apic_base |= 1 << 11 | 1 << 10; // report xAPIC and x2APIC enabled + Ok(apic_base) + } else if VirtLocalApic::msr_range().contains(&rcx) { + if let Ok(msr) = Msr::try_from(rcx) { arch_cpu.virt_lapic.rdmsr(msr) + } else { + // MSR not in our enum but in x2APIC range — return 0 (safe default). + Ok(0) + } + } else if let Ok(msr) = Msr::try_from(rcx) { + if msr == IA32_GS_BASE { + VmcsGuestNW::GS_BASE + .read() + .map(|v| v as u64) + .map_err(|_| hv_err!(EIO)) + } else if msr == IA32_FS_BASE { + VmcsGuestNW::FS_BASE + .read() + .map(|v| v as u64) + .map_err(|_| hv_err!(EIO)) } else { hv_result_err!(ENOSYS) - }; + } + } else { + hv_result_err!(ENOSYS) + }; - if let Ok(value) = res { + match res { + Ok(value) => { debug!("VM exit: RDMSR({:#x}) -> {:#x}", rcx, value); arch_cpu.regs_mut().rax = value & 0xffff_ffff; arch_cpu.regs_mut().rdx = value >> 32; - } else { - warn!("Failed to handle RDMSR({:#x}): {:?}", rcx, res); } - } else { - // warn!("Unrecognized RDMSR({:#x})", rcx); + Err(e) => { + warn!("Failed to handle RDMSR({:#x}): {:?}", rcx, e); + } } arch_cpu.advance_guest_rip(VM_EXIT_INSTR_LEN_RDMSR)?; @@ -357,14 +369,31 @@ fn handle_msr_read(arch_cpu: &mut ArchCpu) -> HvResult { fn handle_msr_write(arch_cpu: &mut ArchCpu) -> HvResult { let rcx = arch_cpu.regs().rcx as u32; - let msr = Msr::try_from(rcx).unwrap(); let value = (arch_cpu.regs().rax & 0xffff_ffff) | (arch_cpu.regs().rdx << 32); debug!("VM exit: WRMSR({:#x}) <- {:#x}", rcx, value); - let res = if msr == IA32_APIC_BASE { - Ok(()) // ignore - } else if VirtLocalApic::msr_range().contains(&rcx) || msr == IA32_TSC_DEADLINE { - arch_cpu.virt_lapic.wrmsr(msr, value) + let msr_opt = Msr::try_from(rcx).ok(); + + let res: HvResult<()> = if rcx == IA32_APIC_BASE as u32 { + Ok(()) // ignore — guest can't change APIC mode + } else if VirtLocalApic::msr_range().contains(&rcx) { + if let Some(msr) = msr_opt { + arch_cpu.virt_lapic.wrmsr(msr, value) + } else { + // x2APIC MSR not in our enum (e.g. SELF_IPI at 0x83F). + // Silently ignore — the guest thinks it succeeded. + Ok(()) + } + } else if msr_opt == Some(IA32_TSC_DEADLINE) { + arch_cpu.virt_lapic.wrmsr(IA32_TSC_DEADLINE, value) + } else if msr_opt == Some(IA32_GS_BASE) { + VmcsGuestNW::GS_BASE + .write(value as usize) + .map_err(|_| hv_err!(EIO)) + } else if msr_opt == Some(IA32_FS_BASE) { + VmcsGuestNW::FS_BASE + .write(value as usize) + .map_err(|_| hv_err!(EIO)) } else { hv_result_err!(ENOSYS) }; @@ -381,6 +410,7 @@ fn handle_msr_write(arch_cpu: &mut ArchCpu) -> HvResult { fn handle_s2pt_violation(arch_cpu: &mut ArchCpu, exit_info: &VmxExitInfo) -> HvResult { let fault_info = Stage2PageFaultInfo::new()?; + mmio_handle_access(&mut MMIOAccess { address: fault_info.fault_guest_paddr, size: 0, @@ -392,12 +422,41 @@ fn handle_s2pt_violation(arch_cpu: &mut ArchCpu, exit_info: &VmxExitInfo) -> HvR } fn handle_triple_fault(arch_cpu: &mut ArchCpu, exit_info: &VmxExitInfo) -> HvResult { + // Print more details for debugging + info!("Triple fault details:"); + info!( + " RIP={:#x}, RSP={:#x}", + exit_info.guest_rip, + VmcsGuestNW::RSP.read().unwrap_or(0) + ); + info!( + " RAX={:#x}, RBX={:#x}, RCX={:#x}, RDX={:#x}", + arch_cpu.regs().rax, + arch_cpu.regs().rbx, + arch_cpu.regs().rcx, + arch_cpu.regs().rdx + ); + info!( + " RSI={:#x}, RDI={:#x}", + arch_cpu.regs().rsi, + arch_cpu.regs().rdi + ); + info!( + " CR0={:#x}, CR3={:#x}, CR4={:#x}", + VmcsGuestNW::CR0.read().unwrap_or(0), + VmcsGuestNW::CR3.read().unwrap_or(0), + VmcsGuestNW::CR4.read().unwrap_or(0) + ); + info!( + " CS selector={:#x}, GDTR base={:#x}", + VmcsGuest16::CS_SELECTOR.read().unwrap_or(0), + VmcsGuestNW::GDTR_BASE.read().unwrap_or(0) + ); + panic!( "VM exit: Triple fault @ {:#x}, instr length: {:x}\n {:#x?}", exit_info.guest_rip, exit_info.exit_instruction_length, arch_cpu ); - // arch_cpu.advance_guest_rip(exit_info.exit_instruction_length as _)?; - Ok(()) } pub fn handle_vmexit(arch_cpu: &mut ArchCpu) -> HvResult { @@ -405,6 +464,35 @@ pub fn handle_vmexit(arch_cpu: &mut ArchCpu) -> HvResult { debug!("VM exit: {:#x?}", exit_info); if exit_info.entry_failure { + // Get VM instruction error for more details + let vm_instr_error = + Vmcs::instruction_error().unwrap_or_else(|_| VmxInstructionError::from(0xFF)); + + // Read all guest state for debugging + let cr0 = VmcsGuestNW::CR0.read().unwrap_or(0); + let cr3 = VmcsGuestNW::CR3.read().unwrap_or(0); + let cr4 = VmcsGuestNW::CR4.read().unwrap_or(0); + let cs_ar = VmcsGuest32::CS_ACCESS_RIGHTS.read().unwrap_or(0); + let ss_ar = VmcsGuest32::SS_ACCESS_RIGHTS.read().unwrap_or(0); + let tr_ar = VmcsGuest32::TR_ACCESS_RIGHTS.read().unwrap_or(0); + let tr_limit = VmcsGuest32::TR_LIMIT.read().unwrap_or(0); + let gdtr_base = VmcsGuestNW::GDTR_BASE.read().unwrap_or(0); + let idtr_base = VmcsGuestNW::IDTR_BASE.read().unwrap_or(0); + + error!("VM entry failed!"); + error!( + " VM-instruction error: {:?} ({})", + vm_instr_error, + vm_instr_error.as_str() + ); + error!(" Guest state:"); + error!(" CR0={:#x}, CR3={:#x}, CR4={:#x}", cr0, cr3, cr4); + error!( + " CS_AR={:#x}, SS_AR={:#x}, TR_AR={:#x}, TR_LIMIT={:#x}", + cs_ar, ss_ar, tr_ar, tr_limit + ); + error!(" GDTR_BASE={:#x}, IDTR_BASE={:#x}", gdtr_base, idtr_base); + panic!("VM entry failed: {:#x?}", exit_info); } diff --git a/src/arch/x86_64/zone.rs b/src/arch/x86_64/zone.rs index af9e7090..2756745d 100644 --- a/src/arch/x86_64/zone.rs +++ b/src/arch/x86_64/zone.rs @@ -60,6 +60,8 @@ pub struct HvArchZoneConfig { /// No need to add a memory region for the framebuffer, /// Hvisor will do the job. **IMPORTANT: screen_base should be no longer than 32 bits.** pub screen_base: usize, + pub multiboot_info_paddr: u64, + pub multiboot_enabled: u32, } impl Zone { @@ -76,10 +78,9 @@ impl Zone { mem_region.physical_start as HostPhysAddr, mem_region.size as _, flags, - )); + ))?; } MEM_TYPE_VIRTIO => { - info!("Registering virtio mmio region: physical_start: {:#x}, size: {:#x}", mem_region.physical_start, mem_region.size); self.mmio_region_register( mem_region.physical_start as _, mem_region.size as _, @@ -101,16 +102,31 @@ impl Zone { /// called after cpu_set is initialized pub fn arch_zone_pre_configuration(&mut self, config: &HvZoneConfig) -> HvResult { - self.cpu_set.iter().for_each(|cpuid| { - let cpu_data = get_cpu_data(cpuid); - // boot cpu - if cpuid == self.cpu_set.first_cpu().unwrap() { - cpu_data.arch_cpu.set_boot_cpu_vm_launch_regs( - config.arch_config.kernel_entry_gpa as _, - config.arch_config.setup_load_gpa as _, - ); - } - }); + let zone_id = config.zone_id as usize; + + if zone_id != 0 && config.arch_config.multiboot_enabled != 0 { + info!("[ZONE{}] Using Multiboot2 boot mode", zone_id); + + self.cpu_set.iter().for_each(|cpuid| { + let cpu_data = get_cpu_data(cpuid); + if cpuid == self.cpu_set.first_cpu().unwrap() { + cpu_data.arch_cpu.set_multiboot_boot_regs( + config.arch_config.multiboot_info_paddr as _, + config.arch_config.kernel_entry_gpa as _, + ); + } + }); + } else { + self.cpu_set.iter().for_each(|cpuid| { + let cpu_data = get_cpu_data(cpuid); + if cpuid == self.cpu_set.first_cpu().unwrap() { + cpu_data.arch_cpu.set_boot_cpu_vm_launch_regs( + config.arch_config.kernel_entry_gpa as _, + config.arch_config.setup_load_gpa as _, + ); + } + }); + } set_msr_bitmap(config.zone_id as _); set_pio_bitmap(config.zone_id as _); @@ -147,7 +163,6 @@ impl Zone { boot::BootParams::fill(&config, &mut self.gpm); acpi::copy_to_guest_memory_region(&config, &self.cpu_set); - Ok(()) } } diff --git a/src/config.rs b/src/config.rs index aecc2759..84039045 100644 --- a/src/config.rs +++ b/src/config.rs @@ -23,7 +23,7 @@ pub const MEM_TYPE_RAM: u32 = 0; pub const MEM_TYPE_IO: u32 = 1; pub const MEM_TYPE_VIRTIO: u32 = 2; -pub const CONFIG_MAGIC_VERSION: usize = 0x5; +pub const CONFIG_MAGIC_VERSION: usize = 0x7; pub const CONFIG_MAX_MEMORY_REGIONS: usize = 64; pub type BitmapWord = u32; @@ -218,6 +218,9 @@ pub struct HvPciDevConfig { pub bus: u8, pub device: u8, pub function: u8, + pub v_bus: u8, + pub v_device: u8, + pub v_function: u8, pub dev_type: VpciDevType, } @@ -229,6 +232,9 @@ macro_rules! pci_dev { bus: $bus, device: $dev, function: $func, + v_bus: 0, + v_device: 0, + v_function: 0, dev_type: $dev_type, } }; diff --git a/src/device/irqchip/pic/ioapic.rs b/src/device/irqchip/pic/ioapic.rs index 2db67669..ffc70f2c 100644 --- a/src/device/irqchip/pic/ioapic.rs +++ b/src/device/irqchip/pic/ioapic.rs @@ -21,7 +21,13 @@ use crate::{ idt, ipi, mmio::MMIoDevice, zone::HvArchZoneConfig, - }, cpu_data::this_zone, device::irqchip::pic::inject_vector, error::HvResult, memory::{GuestPhysAddr, MMIOAccess}, platform::ROOT_ZONE_IOAPIC_BASE, zone::{Zone, this_zone_id} + }, + cpu_data::this_zone, + device::irqchip::pic::inject_vector, + error::HvResult, + memory::{GuestPhysAddr, MMIOAccess}, + platform::ROOT_ZONE_IOAPIC_BASE, + zone::{this_zone_id, Zone}, }; use alloc::{sync::Arc, vec::Vec}; use bit_field::BitField; @@ -133,11 +139,18 @@ impl VirtIoApic { entry.set_bits(0..=31, value.get_bits(0..=31)); } else { let dest = value.get_bits(24..=31); - if this_zone().read().cpu_set.contains_cpu(get_cpu_id(dest as usize)) { + if this_zone() + .read() + .cpu_set + .contains_cpu(get_cpu_id(dest as usize)) + { entry.set_bits(56..=63, dest); } else { let dest = this_apic_id() as u64; - info!("redirect irq {:x} to cpu {:x} in another zone! entry: {:x?}", index, dest, *entry); + info!( + "redirect irq {:x} to cpu {:x} in another zone! entry: {:x?}", + index, dest, *entry + ); entry.set_bits(56..=63, dest); } diff --git a/src/device/irqchip/pic/mod.rs b/src/device/irqchip/pic/mod.rs index c7b80203..8848ecf0 100644 --- a/src/device/irqchip/pic/mod.rs +++ b/src/device/irqchip/pic/mod.rs @@ -18,7 +18,10 @@ pub mod ioapic; pub mod lapic; use crate::{ - arch::{acpi, cpu::this_cpu_id, idt, iommu, ipi, msr, pio, vmcs::Vmcs}, consts::{MAX_CPU_NUM, MAX_ZONE_NUM}, cpu_data::this_zone, zone::Zone + arch::{acpi, cpu::this_cpu_id, idt, iommu, ipi, msr, pio, vmcs::Vmcs}, + consts::{MAX_CPU_NUM, MAX_ZONE_NUM}, + cpu_data::this_zone, + zone::Zone, }; use alloc::{collections::vec_deque::VecDeque, vec::Vec}; use core::arch::asm; diff --git a/src/device/virtio_trampoline.rs b/src/device/virtio_trampoline.rs index 811bb12b..24661051 100644 --- a/src/device/virtio_trampoline.rs +++ b/src/device/virtio_trampoline.rs @@ -63,13 +63,23 @@ use crate::platform::IRQ_WAKEUP_VIRTIO_DEVICE; /// non root zone's virtio request handler pub fn mmio_virtio_handler(mmio: &mut MMIOAccess, base: usize) -> HvResult { - // debug!("mmio virtio handler"); let cpu_id = this_cpu_id() as usize; let need_interrupt = if mmio.address == QUEUE_NOTIFY { 1 } else { 0 }; if need_interrupt == 1 { trace!("notify !!!, cpu id is {}", cpu_id); } mmio.address += base; + + // If the virtio bridge is not enabled (daemon not running), the device is + // absent. Return 0 for reads so the guest sees MagicValue != VIRT_MAGIC + // and skips this MMIO address. + if !VIRTIO_BRIDGE.is_enable.load(Ordering::Acquire) { + if !mmio.is_write { + mmio.value = 0; + } + return Ok(()); + } + // Ensure read old_cfg_flag before push_req let old_cfg_flag = VIRTIO_BRIDGE.cfg_flag(cpu_id); fence(Ordering::Acquire); @@ -77,7 +87,16 @@ pub fn mmio_virtio_handler(mmio: &mut MMIOAccess, base: usize) -> HvResult { // Try to push req to req_list (in VirtioBridge critical area) // To avoid concurrent access to req_list, hvisor should lock VIRTIO_BRIDGE's req_list related part (here use req_agent) let mut backoff = 1; - let mut req_agent = VIRTIO_BRIDGE.req_agent(); + let mut req_agent = match VIRTIO_BRIDGE.req_agent() { + Some(agent) => agent, + None => { + // Bridge disabled between the is_enable check and now. + if !mmio.is_write { + mmio.value = 0; + } + return Ok(()); + } + }; while req_agent.is_full() { // When root linux's cpu is in el2's finish req handler and is getting the dev lock, // if we don't release dev lock, it will cause a dead lock. @@ -88,7 +107,7 @@ pub fn mmio_virtio_handler(mmio: &mut MMIOAccess, base: usize) -> HvResult { } backoff <<= 1; backoff = backoff.min(MAX_BACKOFF); - req_agent = VIRTIO_BRIDGE.req_agent(); + req_agent = VIRTIO_BRIDGE.req_agent().unwrap(); } let hreq = HvisorDeviceReq::new( cpu_id as _, @@ -99,7 +118,6 @@ pub fn mmio_virtio_handler(mmio: &mut MMIOAccess, base: usize) -> HvResult { mmio.is_write, need_interrupt, ); - // debug!("non root sends req: {:#x?}", hreq); req_agent.push_req(hreq); drop(req_agent); @@ -128,15 +146,12 @@ pub fn mmio_virtio_handler(mmio: &mut MMIOAccess, base: usize) -> HvResult { ); count = 0; } - // check_need_wakeup_and_send_ipi(&mut is_ipi_sent); } if !mmio.is_write { // ensure cfg value is right. mmio.value = VIRTIO_BRIDGE.cfg_value(cpu_id) as _; - // debug!("non root receives value: {:#x?}", mmio.value); } } - // debug!("non root returns"); Ok(()) } @@ -189,27 +204,27 @@ impl VirtioBridgeController { } /// Get req list agent. - fn req_agent(&self) -> ReqAgent { + fn req_agent(&self) -> Option { if !self.is_enable.load(Ordering::Acquire) { - panic!("VirtioBridge not enabled"); + return None; } let guard = self.req_lock.lock(); - ReqAgent { + Some(ReqAgent { base: self.base_address.load(Ordering::Relaxed), _guard: guard, - } + }) } /// Get res list agent. - pub fn res_agent(&self) -> ResAgent { + pub fn res_agent(&self) -> Option { if !self.is_enable.load(Ordering::Acquire) { - panic!("VirtioBridge not enabled"); + return None; } let guard = self.res_lock.lock(); - ResAgent { + Some(ResAgent { base: self.base_address.load(Ordering::Relaxed), _guard: guard, - } + }) } /// Get cfg flags (0..MAX_CPUS) @@ -241,8 +256,8 @@ impl VirtioBridgeController { #[allow(unused)] pub fn need_wakeup(&self) -> bool { let base = self.base_address.load(Ordering::Relaxed); - fence(Ordering::SeqCst); let need_wakeup = unsafe { (&*(base as *const VirtioBridge)).need_wakeup.get() }; + fence(Ordering::Acquire); need_wakeup == 1 } } diff --git a/src/hypercall/mod.rs b/src/hypercall/mod.rs index 55a3b8e1..20edb7b1 100644 --- a/src/hypercall/mod.rs +++ b/src/hypercall/mod.rs @@ -139,7 +139,10 @@ impl<'a> HyperCall<'a> { "Virtio send irq operation over non-root zones: unsupported!" ); } - let mut res_agent = VIRTIO_BRIDGE.res_agent(); + let mut res_agent = match VIRTIO_BRIDGE.res_agent() { + Some(agent) => agent, + None => return HyperCallResult::Ok(0), + }; let mut map_irq = VIRTIO_IRQS.lock(); while !res_agent.is_empty() { let (_res_front, irq_id, target_zone) = res_agent.peek_front(); @@ -177,6 +180,17 @@ impl<'a> HyperCall<'a> { let config_pa = self.hv_get_real_pa(config_ipa); let config = unsafe { &*(config_pa as *const HvZoneConfig) }; + debug!( + "[ZONE_START] hv_zone_start called for zone_id={}, config_size={}, expected={}", + config.zone_id, + config_size, + core::mem::size_of::() + ); + debug!( + "[ZONE_START] kernel_load_paddr={:#x}, entry_point={:#x}", + config.kernel_load_paddr, config.entry_point + ); + debug!("hv_zone_start: config: {:#x?}", config); if !is_this_root_zone() { return hv_result_err!(