diff --git a/ci/examples.sh b/ci/examples.sh index 46ed5e43..6e2d750f 100755 --- a/ci/examples.sh +++ b/ci/examples.sh @@ -132,8 +132,8 @@ build_simple_zig "maaxboard" "release" build_rust "debug" simulate_rust "debug" -# build_rust "release" -# simulate_rust "release" +build_rust "release" +simulate_rust "release" # Here there are two kinds of configuration that we need to test. There is the # configuration of Microkit itself for which we test debug and release. This @@ -153,8 +153,8 @@ simulate_zig "release" "ReleaseSmall" build_virtio "qemu_virt_aarch64" "debug" build_virtio "qemu_virt_aarch64" "release" -# build_virtio "odroidc4" "debug" -# build_virtio "odroidc4" "release" +build_virtio "odroidc4" "debug" +build_virtio "odroidc4" "release" echo "" echo "CI|INFO: Passed all VMM tests" diff --git a/examples/rust/src/vmm.rs b/examples/rust/src/vmm.rs index 321b57ba..0f8a6b77 100644 --- a/examples/rust/src/vmm.rs +++ b/examples/rust/src/vmm.rs @@ -13,7 +13,7 @@ use sel4_microkit::{protection_domain, MessageInfo, Channel, Child, Handler, deb const GUEST_RAM_VADDR: usize = 0x40000000; const GUEST_DTB_VADDR: usize = 0x4f000000; const GUEST_INIT_RAM_DISK_VADDR: usize = 0x4d700000; -const GUEST_VCPU_ID: usize = 0; +const GUEST_BOOT_VCPU_ID: usize = 0; /// On the QEMU virt AArch64 platform the UART we are using has an IRQ number of 33. const UART_IRQ: usize = 33; @@ -37,10 +37,10 @@ extern "C" { kernel: usize, kernel_size: usize, dtb_src: usize, dtb_dest: usize, dtb_size: usize, initrd_src: usize, initrd_dest: usize, initrd_size: usize) -> usize; - fn virq_controller_init(boot_vpcu_id: usize) -> bool; + fn virq_controller_init() -> bool; fn virq_register(vcpu_id: usize, irq: i32, ack_fn: extern fn(usize, i32, *const c_void), ack_data: *const c_void) -> bool; - fn virq_inject(vcpu_id: usize, irq: i32) -> bool; - fn guest_start(boot_vpcu_id: usize, kernel_pc: usize, dtb: usize, initrd: usize) -> bool; + fn virq_inject(irq: i32) -> bool; + fn guest_start(kernel_pc: usize, dtb: usize, initrd: usize) -> bool; fn fault_handle(vcpu_id: usize, msginfo: MessageInfo) -> bool; } @@ -76,16 +76,17 @@ fn init() -> VmmHandler { dtb_addr, GUEST_DTB_VADDR, dtb.len(), initrd_addr, GUEST_INIT_RAM_DISK_VADDR, initrd.len() ); - // @ivanv, deal with unused vars - _ = virq_controller_init(GUEST_VCPU_ID); - _ = virq_register(GUEST_VCPU_ID, UART_IRQ as i32, uart_irq_ack, core::ptr::null()); + let success = virq_controller_init(); + assert!(success); + let success = virq_register(GUEST_BOOT_VCPU_ID, UART_IRQ as i32, uart_irq_ack, core::ptr::null()); + assert!(success); match UART_CH.irq_ack() { Ok(()) => {} Err(_e) => { debug_println!("VMM|ERROR: could not ack UART IRQ channel: {_e}"); } } - guest_start(GUEST_VCPU_ID, guest_pc, GUEST_DTB_VADDR, GUEST_INIT_RAM_DISK_VADDR); + guest_start(guest_pc, GUEST_DTB_VADDR, GUEST_INIT_RAM_DISK_VADDR); } VmmHandler {} @@ -100,7 +101,7 @@ impl Handler for VmmHandler { match channel { UART_CH => { unsafe { - let success = virq_inject(GUEST_VCPU_ID, UART_IRQ as i32); + let success = virq_inject(UART_IRQ as i32); if !success { debug_println!("VMM|ERROR: could not inject UART IRQ"); } diff --git a/examples/simple/vmm.c b/examples/simple/vmm.c index ce260e2e..bb0fa4a8 100644 --- a/examples/simple/vmm.c +++ b/examples/simple/vmm.c @@ -76,7 +76,8 @@ extern char _guest_initrd_image_end[]; /* Microkit will set this variable to the start of the guest RAM memory region. */ uintptr_t guest_ram_vaddr; -static void serial_ack(size_t vcpu_id, int irq, void *cookie) { +static void serial_ack(size_t vcpu_id, int irq, void *cookie) +{ /* * For now we by default simply ack the serial IRQ, we have not * come across a case yet where more than this needs to be done. @@ -84,7 +85,8 @@ static void serial_ack(size_t vcpu_id, int irq, void *cookie) { microkit_irq_ack(SERIAL_IRQ_CH); } -void init(void) { +void init(void) +{ /* Initialise the VMM, the VCPU(s), and start the guest */ LOG_VMM("starting \"%s\"\n", microkit_name); /* Place all the binaries in the right locations before starting the guest */ @@ -92,43 +94,44 @@ void init(void) { size_t dtb_size = _guest_dtb_image_end - _guest_dtb_image; size_t initrd_size = _guest_initrd_image_end - _guest_initrd_image; uintptr_t kernel_pc = linux_setup_images(guest_ram_vaddr, - (uintptr_t) _guest_kernel_image, - kernel_size, - (uintptr_t) _guest_dtb_image, - GUEST_DTB_VADDR, - dtb_size, - (uintptr_t) _guest_initrd_image, - GUEST_INIT_RAM_DISK_VADDR, - initrd_size - ); + (uintptr_t) _guest_kernel_image, + kernel_size, + (uintptr_t) _guest_dtb_image, + GUEST_DTB_VADDR, + dtb_size, + (uintptr_t) _guest_initrd_image, + GUEST_INIT_RAM_DISK_VADDR, + initrd_size + ); if (!kernel_pc) { LOG_VMM_ERR("Failed to initialise guest images\n"); return; } /* Initialise the virtual GIC driver */ - bool success = virq_controller_init(GUEST_VCPU_ID); + bool success = virq_controller_init(); if (!success) { LOG_VMM_ERR("Failed to initialise emulated interrupt controller\n"); return; } - success = virq_register(GUEST_VCPU_ID, SERIAL_IRQ, &serial_ack, NULL); + success = virq_register(GUEST_BOOT_VCPU_ID, SERIAL_IRQ, &serial_ack, NULL); /* Just in case there is already an interrupt available to handle, we ack it here. */ microkit_irq_ack(SERIAL_IRQ_CH); /* Finally start the guest */ - guest_start(GUEST_VCPU_ID, kernel_pc, GUEST_DTB_VADDR, GUEST_INIT_RAM_DISK_VADDR); + guest_start(kernel_pc, GUEST_DTB_VADDR, GUEST_INIT_RAM_DISK_VADDR); } -void notified(microkit_channel ch) { +void notified(microkit_channel ch) +{ switch (ch) { - case SERIAL_IRQ_CH: { - bool success = virq_inject(GUEST_VCPU_ID, SERIAL_IRQ); - if (!success) { - LOG_VMM_ERR("IRQ %d dropped on vCPU %d\n", SERIAL_IRQ, GUEST_VCPU_ID); - } - break; + case SERIAL_IRQ_CH: { + bool success = virq_inject(SERIAL_IRQ); + if (!success) { + LOG_VMM_ERR("IRQ %d dropped\n", SERIAL_IRQ); } - default: - printf("Unexpected channel, ch: 0x%lx\n", ch); + break; + } + default: + printf("Unexpected channel, ch: 0x%lx\n", ch); } } @@ -137,7 +140,8 @@ void notified(microkit_channel ch) { * Whenever our guest causes an exception, it gets delivered to this entry point for * the VMM to handle. */ -seL4_Bool fault(microkit_child child, microkit_msginfo msginfo, microkit_msginfo *reply_msginfo) { +seL4_Bool fault(microkit_child child, microkit_msginfo msginfo, microkit_msginfo *reply_msginfo) +{ bool success = fault_handle(child, msginfo); if (success) { /* Now that we have handled the fault successfully, we reply to it so diff --git a/examples/virtio-snd/client_vmm.c b/examples/virtio-snd/client_vmm.c index 5606cb07..ca844501 100644 --- a/examples/virtio-snd/client_vmm.c +++ b/examples/virtio-snd/client_vmm.c @@ -72,7 +72,8 @@ static struct virtio_snd_device virtio_sound; uintptr_t kernel_pc = 0; -void init(void) { +void init(void) +{ /* Initialise the VMM, the VCPU(s), and start the guest */ LOG_VMM("starting \"%s\"\n", microkit_name); /* Place all the binaries in the right locations before starting the guest */ @@ -80,22 +81,22 @@ void init(void) { size_t dtb_size = _guest_dtb_image_end - _guest_dtb_image; size_t initrd_size = _guest_initrd_image_end - _guest_initrd_image; kernel_pc = linux_setup_images(guest_ram_vaddr, - (uintptr_t) _guest_kernel_image, - kernel_size, - (uintptr_t) _guest_dtb_image, - GUEST_DTB_VADDR, - dtb_size, - (uintptr_t) _guest_initrd_image, - GUEST_INIT_RAM_DISK_VADDR, - initrd_size - ); + (uintptr_t) _guest_kernel_image, + kernel_size, + (uintptr_t) _guest_dtb_image, + GUEST_DTB_VADDR, + dtb_size, + (uintptr_t) _guest_initrd_image, + GUEST_INIT_RAM_DISK_VADDR, + initrd_size + ); if (!kernel_pc) { LOG_VMM_ERR("Failed to initialise guest images\n"); return; } /* Initialise the virtual GIC driver */ - bool success = virq_controller_init(GUEST_VCPU_ID); + bool success = virq_controller_init(); if (!success) { LOG_VMM_ERR("Failed to initialise emulated interrupt controller\n"); return; @@ -103,15 +104,16 @@ void init(void) { /* Initialise our sDDF ring buffers for the serial device */ serial_queue_handle_t serial_rxq, serial_txq; - serial_cli_queue_init_sys(microkit_name, &serial_rxq, serial_rx_queue, serial_rx_data, &serial_txq, serial_tx_queue, serial_tx_data); + serial_cli_queue_init_sys(microkit_name, &serial_rxq, serial_rx_queue, serial_rx_data, &serial_txq, serial_tx_queue, + serial_tx_data); /* Initialise virtIO console device */ success = virtio_mmio_console_init(&virtio_console, - VIRTIO_CONSOLE_BASE, - VIRTIO_CONSOLE_SIZE, - VIRTIO_CONSOLE_IRQ, - &serial_rxq, &serial_txq, - SERIAL_VIRT_TX_CH); + VIRTIO_CONSOLE_BASE, + VIRTIO_CONSOLE_SIZE, + VIRTIO_CONSOLE_IRQ, + &serial_rxq, &serial_txq, + SERIAL_VIRT_TX_CH); assert(success); assert(sound_cmd_req); @@ -138,37 +140,39 @@ void init(void) { while (!ATOMIC_LOAD(&shared_state->ready, __ATOMIC_ACQUIRE)); success = virtio_mmio_snd_init(&virtio_sound, - VIRTIO_SOUND_BASE, - VIRTIO_SOUND_SIZE, - VIRTIO_SOUND_IRQ, - shared_state, - &sound_queues, - sound_data, - SOUND_DRIVER_CH); + VIRTIO_SOUND_BASE, + VIRTIO_SOUND_SIZE, + VIRTIO_SOUND_IRQ, + shared_state, + &sound_queues, + sound_data, + SOUND_DRIVER_CH); assert(success); - success = guest_start(GUEST_VCPU_ID, kernel_pc, GUEST_DTB_VADDR, GUEST_INIT_RAM_DISK_VADDR); + success = guest_start(GUEST_BOOT_VCPU_ID, kernel_pc, GUEST_DTB_VADDR, GUEST_INIT_RAM_DISK_VADDR); assert(success); } -void notified(microkit_channel ch) { +void notified(microkit_channel ch) +{ switch (ch) { - case SERIAL_VIRT_RX_CH: { - /* We have received an event from the serial virtualiser, so we - * call the virtIO console handling */ - virtio_console_handle_rx(&virtio_console); - break; - } - case SOUND_DRIVER_CH: { - virtio_snd_notified(&virtio_sound); - break; - } - default: - printf("Unexpected channel, ch: 0x%lx\n", ch); + case SERIAL_VIRT_RX_CH: { + /* We have received an event from the serial virtualiser, so we + * call the virtIO console handling */ + virtio_console_handle_rx(&virtio_console); + break; + } + case SOUND_DRIVER_CH: { + virtio_snd_notified(&virtio_sound); + break; + } + default: + printf("Unexpected channel, ch: 0x%lx\n", ch); } } -seL4_Bool fault(microkit_child child, microkit_msginfo msginfo, microkit_msginfo *reply_msginfo) { +seL4_Bool fault(microkit_child child, microkit_msginfo msginfo, microkit_msginfo *reply_msginfo) +{ bool success = fault_handle(child, msginfo); if (success) { /* Now that we have handled the fault successfully, we reply to it so diff --git a/examples/virtio-snd/snd_driver_vmm.c b/examples/virtio-snd/snd_driver_vmm.c index d408a178..73441396 100644 --- a/examples/virtio-snd/snd_driver_vmm.c +++ b/examples/virtio-snd/snd_driver_vmm.c @@ -72,17 +72,19 @@ uintptr_t sound_data_paddr; static struct virtio_console_device virtio_console; -static void passthrough_device_ack(size_t vcpu_id, int irq, void *cookie) { +static void passthrough_device_ack(size_t vcpu_id, int irq, void *cookie) +{ microkit_channel irq_ch = (microkit_channel)(int64_t)cookie; microkit_irq_ack(irq_ch); } -static void register_passthrough_irq(int irq, microkit_channel irq_ch) { +static void register_passthrough_irq(int irq, microkit_channel irq_ch) +{ LOG_VMM("Register passthrough IRQ %d (channel: 0x%lx)\n", irq, irq_ch); assert(irq_ch < MAX_IRQ_CH); passthrough_irq_map[irq_ch] = irq; - int err = virq_register(GUEST_VCPU_ID, irq, &passthrough_device_ack, (void *)(int64_t)irq_ch); + int err = virq_register(GUEST_BOOT_VCPU_ID, irq, &passthrough_device_ack, (void *)(int64_t)irq_ch); if (!err) { LOG_VMM_ERR("Failed to register IRQ %d\n", irq); return; @@ -90,17 +92,19 @@ static void register_passthrough_irq(int irq, microkit_channel irq_ch) { } static bool uio_sound_fault_handler(size_t vcpu_id, - size_t offset, - size_t fsr, - seL4_UserContext *regs, - void *data) { + size_t offset, + size_t fsr, + seL4_UserContext *regs, + void *data) +{ microkit_notify(SND_CLIENT_CH); return true; } static void uio_sound_virq_ack(size_t vcpu_id, int irq, void *cookie) {} -void init(void) { +void init(void) +{ /* Initialise the VMM, the VCPU(s), and start the guest */ LOG_VMM("starting \"%s\"\n", microkit_name); /* Place all the binaries in the right locations before starting the guest */ @@ -109,22 +113,22 @@ void init(void) { size_t initrd_size = _guest_initrd_image_end - _guest_initrd_image; uintptr_t kernel_pc = linux_setup_images(guest_ram_vaddr, - (uintptr_t) _guest_kernel_image, - kernel_size, - (uintptr_t) _guest_dtb_image, - GUEST_DTB_VADDR, - dtb_size, - (uintptr_t) _guest_initrd_image, - GUEST_INIT_RAM_DISK_VADDR, - initrd_size - ); + (uintptr_t) _guest_kernel_image, + kernel_size, + (uintptr_t) _guest_dtb_image, + GUEST_DTB_VADDR, + dtb_size, + (uintptr_t) _guest_initrd_image, + GUEST_INIT_RAM_DISK_VADDR, + initrd_size + ); if (!kernel_pc) { LOG_VMM_ERR("Failed to initialise guest images\n"); return; } /* Initialise the virtual GIC driver */ - bool success = virq_controller_init(GUEST_VCPU_ID); + bool success = virq_controller_init(GUEST_BOOT_VCPU_ID); if (!success) { LOG_VMM_ERR("Failed to initialise emulated interrupt controller\n"); return; @@ -137,18 +141,19 @@ void init(void) { /* Initialise our sDDF ring buffers for the serial device */ serial_queue_handle_t serial_rxq, serial_txq; - serial_cli_queue_init_sys(microkit_name, &serial_rxq, serial_rx_queue, serial_rx_data, &serial_txq, serial_tx_queue, serial_tx_data); + serial_cli_queue_init_sys(microkit_name, &serial_rxq, serial_rx_queue, serial_rx_data, &serial_txq, serial_tx_queue, + serial_tx_data); /* Initialise virtIO console device */ success = virtio_mmio_console_init(&virtio_console, - VIRTIO_CONSOLE_BASE, - VIRTIO_CONSOLE_SIZE, - VIRTIO_CONSOLE_IRQ, - &serial_rxq, &serial_txq, - SERIAL_TX_CH); + VIRTIO_CONSOLE_BASE, + VIRTIO_CONSOLE_SIZE, + VIRTIO_CONSOLE_IRQ, + &serial_rxq, &serial_txq, + SERIAL_TX_CH); assert(success); - success = virq_register(GUEST_VCPU_ID, UIO_SND_IRQ, &uio_sound_virq_ack, NULL); + success = virq_register(GUEST_BOOT_VCPU_ID, UIO_SND_IRQ, &uio_sound_virq_ack, NULL); assert(success); success = fault_register_vm_exception_handler(UIO_SND_FAULT_ADDRESS, @@ -172,10 +177,11 @@ void init(void) { cache_clean((uintptr_t)data_paddr, sizeof(uintptr_t)); /* Finally start the guest */ - guest_start(GUEST_VCPU_ID, kernel_pc, GUEST_DTB_VADDR, GUEST_INIT_RAM_DISK_VADDR); + guest_start(GUEST_BOOT_VCPU_ID, kernel_pc, GUEST_DTB_VADDR, GUEST_INIT_RAM_DISK_VADDR); } -void notified(microkit_channel ch) { +void notified(microkit_channel ch) +{ bool success; switch (ch) { @@ -185,16 +191,16 @@ void notified(microkit_channel ch) { virtio_console_handle_rx(&virtio_console); break; case SND_CLIENT_CH: - success = virq_inject(GUEST_VCPU_ID, UIO_SND_IRQ); + success = virq_inject(UIO_SND_IRQ); if (!success) { - LOG_VMM_ERR("IRQ %d dropped on vCPU %d\n", UIO_SND_IRQ, GUEST_VCPU_ID); + LOG_VMM_ERR("IRQ %d dropped\n", UIO_SND_IRQ); } break; default: if (passthrough_irq_map[ch]) { - success = virq_inject(GUEST_VCPU_ID, passthrough_irq_map[ch]); + success = virq_inject(passthrough_irq_map[ch]); if (!success) { - LOG_VMM_ERR("IRQ %d dropped on vCPU %d\n", passthrough_irq_map[ch], GUEST_VCPU_ID); + LOG_VMM_ERR("IRQ %d dropped\n", passthrough_irq_map[ch]); } } else { printf("Unexpected channel, ch: 0x%lx\n", ch); @@ -202,7 +208,8 @@ void notified(microkit_channel ch) { } } -seL4_Bool fault(microkit_child child, microkit_msginfo msginfo, microkit_msginfo *reply_msginfo) { +seL4_Bool fault(microkit_child child, microkit_msginfo msginfo, microkit_msginfo *reply_msginfo) +{ bool success = fault_handle(child, msginfo); if (success) { /* Now that we have handled the fault successfully, we reply to it so diff --git a/examples/virtio/blk_driver_vmm.c b/examples/virtio/blk_driver_vmm.c index b1f54f06..8baa6f9a 100644 --- a/examples/virtio/blk_driver_vmm.c +++ b/examples/virtio/blk_driver_vmm.c @@ -95,7 +95,7 @@ void init(void) } /* Initialise the virtual GIC driver */ - bool success = virq_controller_init(GUEST_VCPU_ID); + bool success = virq_controller_init(); if (!success) { LOG_VMM_ERR("Failed to initialise emulated interrupt controller\n"); return; @@ -108,33 +108,33 @@ void init(void) /* Initialise our sDDF ring buffers for the serial device */ serial_queue_handle_t serial_rxq, serial_txq; - serial_cli_queue_init_sys(microkit_name, &serial_rxq, serial_rx_queue, serial_rx_data, &serial_txq, serial_tx_queue, serial_tx_data); - + serial_cli_queue_init_sys(microkit_name, &serial_rxq, serial_rx_queue, serial_rx_data, &serial_txq, serial_tx_queue, + serial_tx_data); /* Initialise virtIO console device */ success = virtio_mmio_console_init(&virtio_console, - VIRTIO_CONSOLE_BASE, - VIRTIO_CONSOLE_SIZE, - VIRTIO_CONSOLE_IRQ, - &serial_rxq, &serial_txq, - SERIAL_VIRT_TX_CH); + VIRTIO_CONSOLE_BASE, + VIRTIO_CONSOLE_SIZE, + VIRTIO_CONSOLE_IRQ, + &serial_rxq, &serial_txq, + SERIAL_VIRT_TX_CH); assert(success); /* Register the UIO IRQ */ - virq_register(GUEST_VCPU_ID, UIO_IRQ, uio_ack, NULL); + virq_register(GUEST_BOOT_VCPU_ID, UIO_IRQ, uio_ack, NULL); #if defined(BOARD_odroidc4) /* Register the SD card IRQ */ - virq_register_passthrough(GUEST_VCPU_ID, SD_IRQ, BLOCK_CH); + virq_register_passthrough(GUEST_BOOT_VCPU_ID, SD_IRQ, BLOCK_CH); #endif #if defined(BOARD_qemu_virt_aarch64) /* Register the block device IRQ */ - virq_register_passthrough(GUEST_VCPU_ID, BLOCK_IRQ, BLOCK_CH); + virq_register_passthrough(GUEST_BOOT_VCPU_ID, BLOCK_IRQ, BLOCK_CH); #endif /* Finally start the guest */ - guest_start(GUEST_VCPU_ID, kernel_pc, GUEST_DTB_VADDR, GUEST_INIT_RAM_DISK_VADDR); + guest_start(kernel_pc, GUEST_DTB_VADDR, GUEST_INIT_RAM_DISK_VADDR); } void notified(microkit_channel ch) @@ -145,7 +145,7 @@ void notified(microkit_channel ch) switch (ch) { case UIO_CH: { - int success = virq_inject(GUEST_VCPU_ID, UIO_IRQ); + int success = virq_inject(UIO_IRQ); if (!success) { LOG_VMM_ERR("Failed to inject UIO IRQ 0x%lx\n", UIO_IRQ); } @@ -162,7 +162,8 @@ void notified(microkit_channel ch) } } -seL4_Bool fault(microkit_child child, microkit_msginfo msginfo, microkit_msginfo *reply_msginfo) { +seL4_Bool fault(microkit_child child, microkit_msginfo msginfo, microkit_msginfo *reply_msginfo) +{ bool success = fault_handle(child, msginfo); if (success) { /* Now that we have handled the fault successfully, we reply to it so diff --git a/examples/virtio/client_vmm.c b/examples/virtio/client_vmm.c index 01225b49..c65542b9 100644 --- a/examples/virtio/client_vmm.c +++ b/examples/virtio/client_vmm.c @@ -41,7 +41,6 @@ extern char _guest_initrd_image_end[]; /* Microkit will set this variable to the start of the guest RAM memory region. */ uintptr_t guest_ram_vaddr; - /* Virtio Console */ #define SERIAL_VIRT_TX_CH 1 #define SERIAL_VIRT_RX_CH 2 @@ -103,7 +102,7 @@ void init(void) } /* Initialise the virtual GIC driver */ - bool success = virq_controller_init(GUEST_VCPU_ID); + bool success = virq_controller_init(); if (!success) { LOG_VMM_ERR("Failed to initialise emulated interrupt controller\n"); return; @@ -111,15 +110,16 @@ void init(void) /* Initialise our sDDF ring buffers for the serial device */ serial_queue_handle_t serial_rxq, serial_txq; - serial_cli_queue_init_sys(microkit_name, &serial_rxq, serial_rx_queue, serial_rx_data, &serial_txq, serial_tx_queue, serial_tx_data); + serial_cli_queue_init_sys(microkit_name, &serial_rxq, serial_rx_queue, serial_rx_data, &serial_txq, serial_tx_queue, + serial_tx_data); /* Initialise virtIO console device */ success = virtio_mmio_console_init(&virtio_console, - VIRTIO_CONSOLE_BASE, - VIRTIO_CONSOLE_SIZE, - VIRTIO_CONSOLE_IRQ, - &serial_rxq, &serial_txq, - SERIAL_VIRT_TX_CH); + VIRTIO_CONSOLE_BASE, + VIRTIO_CONSOLE_SIZE, + VIRTIO_CONSOLE_IRQ, + &serial_rxq, &serial_txq, + SERIAL_VIRT_TX_CH); /* virtIO block */ /* Initialise our sDDF queues for the block device */ @@ -131,16 +131,16 @@ void init(void) /* Initialise virtIO block device */ success = virtio_mmio_blk_init(&virtio_blk, - VIRTIO_BLK_BASE, VIRTIO_BLK_SIZE, VIRTIO_BLK_IRQ, - blk_data, - BLK_DATA_SIZE, - storage_info, - &blk_queue_h, - BLK_CH); + VIRTIO_BLK_BASE, VIRTIO_BLK_SIZE, VIRTIO_BLK_IRQ, + blk_data, + BLK_DATA_SIZE, + storage_info, + &blk_queue_h, + BLK_CH); assert(success); /* Finally start the guest */ - guest_start(GUEST_VCPU_ID, kernel_pc, GUEST_DTB_VADDR, GUEST_INIT_RAM_DISK_VADDR); + guest_start(kernel_pc, GUEST_DTB_VADDR, GUEST_INIT_RAM_DISK_VADDR); } void notified(microkit_channel ch) @@ -161,7 +161,8 @@ void notified(microkit_channel ch) } } -seL4_Bool fault(microkit_child child, microkit_msginfo msginfo, microkit_msginfo *reply_msginfo) { +seL4_Bool fault(microkit_child child, microkit_msginfo msginfo, microkit_msginfo *reply_msginfo) +{ bool success = fault_handle(child, msginfo); if (success) { /* Now that we have handled the fault successfully, we reply to it so diff --git a/examples/zig/src/vmm.zig b/examples/zig/src/vmm.zig index 51f9cd82..84476d0c 100644 --- a/examples/zig/src/vmm.zig +++ b/examples/zig/src/vmm.zig @@ -96,7 +96,7 @@ export fn init() callconv(.C) void { return; } // Initialise the virtual interrupt controller - if (!c.virq_controller_init(GUEST_BOOT_VCPU_ID)) { + if (!c.virq_controller_init()) { log.err("Failed to initialise virtual interrupt controller\n", .{}); return; } @@ -109,7 +109,7 @@ export fn init() callconv(.C) void { // handle, we ack it here. microkit.microkit_irq_ack(SERIAL_IRQ_CH); // Finally we can start the guest - if (!c.guest_start(GUEST_BOOT_VCPU_ID, kernel_pc, GUEST_DTB_VADDR, GUEST_INIT_RAM_DISK_VADDR)) { + if (!c.guest_start(kernel_pc, GUEST_DTB_VADDR, GUEST_INIT_RAM_DISK_VADDR)) { log.err("Failed to start guest\n", .{}); return; } @@ -118,9 +118,9 @@ export fn init() callconv(.C) void { export fn notified(ch: microkit.microkit_channel) callconv(.C) void { switch (ch) { SERIAL_IRQ_CH => { - const success = c.virq_inject(GUEST_BOOT_VCPU_ID, SERIAL_IRQ); + const success = c.virq_inject(SERIAL_IRQ); if (!success) { - log.err("IRQ {x} dropped on vCPU {x}\n", .{ SERIAL_IRQ, GUEST_BOOT_VCPU_ID }); + log.err("IRQ {x} dropped\n", .{ SERIAL_IRQ }); } }, else => log.err("Unexpected channel, ch: {x}\n", .{ ch }) diff --git a/include/libvmm/arch/aarch64/vgic/vdist.h b/include/libvmm/arch/aarch64/vgic/vdist.h index 768f39b1..5c253c9a 100644 --- a/include/libvmm/arch/aarch64/vgic/vdist.h +++ b/include/libvmm/arch/aarch64/vgic/vdist.h @@ -5,6 +5,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include @@ -246,7 +247,8 @@ static void vgic_dist_clr_pending_irq(struct gic_dist_map *dist, size_t vcpu_id, // @ivanv } -static bool vgic_dist_reg_read(size_t vcpu_id, vgic_t *vgic, uint64_t offset, uint64_t fsr, seL4_UserContext *regs) +static bool vgic_handle_fault_dist_read(size_t vcpu_id, vgic_t *vgic, uint64_t offset, uint64_t fsr, + seL4_UserContext *regs) { struct gic_dist_map *gic_dist = vgic_get_dist(vgic->registers); uint32_t reg = 0; @@ -358,7 +360,8 @@ static bool vgic_dist_reg_read(size_t vcpu_id, vgic_t *vgic, uint64_t offset, ui case RANGE32(0xDE8, 0xEFC): /* Reserved [0xDE8 - 0xE00) */ /* GIC_DIST_NSACR [0xE00 - 0xF00) - Not supported */ - break; case RANGE32(GIC_DIST_SGIR, GIC_DIST_SGIR): + break; + case RANGE32(GIC_DIST_SGIR, GIC_DIST_SGIR): reg = gic_dist->sgir; break; case RANGE32(0xF04, 0xF0C): @@ -413,7 +416,8 @@ static inline void emulate_reg_write_access(seL4_UserContext *regs, uint64_t add *reg = fault_emulate(regs, *reg, addr, fsr, fault_get_data(regs, fsr)); } -static bool vgic_dist_reg_write(size_t vcpu_id, vgic_t *vgic, uint64_t offset, uint64_t fsr, seL4_UserContext *regs) +static bool vgic_handle_fault_dist_write(size_t vcpu_id, vgic_t *vgic, uint64_t offset, uint64_t fsr, + seL4_UserContext *regs) { bool success = true; struct gic_dist_map *gic_dist = vgic_get_dist(vgic->registers); @@ -494,8 +498,8 @@ static bool vgic_dist_reg_write(size_t vcpu_id, vgic_t *vgic, uint64_t offset, u irq = CTZ(data); data &= ~(1U << irq); irq += (offset - GIC_DIST_ISPENDR0) * 8; - // @ivanv: should be checking this and other calls like it succeed - vgic_dist_set_pending_irq(vgic, vcpu_id, irq); + success = vgic_dist_set_pending_irq(vgic, vcpu_id, irq); + assert(success); } break; case RANGE32(GIC_DIST_ICPENDR0, GIC_DIST_ICPENDRN): @@ -571,11 +575,15 @@ static bool vgic_dist_reg_write(size_t vcpu_id, vgic_t *vgic, uint64_t offset, u LOG_VMM_ERR("Unknown SGIR Target List Filter mode"); goto ignore_fault; } - // @ivanv: Here we're making the assumption that there's only one vCPU, and - // we're also blindly injectnig the given IRQ to that vCPU. - // @ivanv: come back to this, do we have two writes to the TCB registers? - success = vgic_inject_irq(vcpu_id, virq); - assert(success); + for (int i = 0; i < GUEST_NUM_VCPUS; i++) { + if ((1 << i) & target_list && vcpu_is_on(i)) { + success = vgic_inject_irq(i, virq); + assert(success); + if (!success) { + return false; + } + } + } break; case RANGE32(0xF04, 0xF0C): /* Reserved */ @@ -594,7 +602,7 @@ static bool vgic_dist_reg_write(size_t vcpu_id, vgic_t *vgic, uint64_t offset, u #if defined(GIC_V3) // @ivanv: explain GICv3 specific stuff, and also don't use the hardcoded valuees case RANGE32(0x6100, 0x7F00): - // @ivanv revisit + // @ivanv revisit // data = fault_get_data(fault); // ZF_LOGF_IF(data, "bad dist: 0x%x 0x%x", offset, data); break; @@ -611,4 +619,3 @@ static bool vgic_dist_reg_write(size_t vcpu_id, vgic_t *vgic, uint64_t offset, u return success; } - diff --git a/include/libvmm/arch/aarch64/vgic/vgic.h b/include/libvmm/arch/aarch64/vgic/vgic.h index dab3759f..c64bea7f 100644 --- a/include/libvmm/arch/aarch64/vgic/vgic.h +++ b/include/libvmm/arch/aarch64/vgic/vgic.h @@ -50,8 +50,11 @@ #endif void vgic_init(); -bool fault_handle_vgic_maintenance(size_t vcpu_id); -bool handle_vgic_dist_fault(size_t vcpu_id, size_t offset, size_t fsr, seL4_UserContext *regs, void *data); -bool handle_vgic_redist_fault(size_t vcpu_id, size_t offset, size_t fsr, seL4_UserContext *regs, void *data); + +bool vgic_handle_fault_maintenance(size_t vcpu_id); + +bool vgic_handle_fault_dist(size_t vcpu_id, size_t offset, size_t fsr, seL4_UserContext *regs, void *data); +bool vgic_handle_fault_redist(size_t vcpu_id, size_t offset, size_t fsr, seL4_UserContext *regs, void *data); + bool vgic_register_irq(size_t vcpu_id, int virq_num, virq_ack_fn_t ack_fn, void *ack_data); bool vgic_inject_irq(size_t vcpu_id, int irq); diff --git a/include/libvmm/guest.h b/include/libvmm/guest.h index 91cd0364..78c4db2e 100644 --- a/include/libvmm/guest.h +++ b/include/libvmm/guest.h @@ -7,6 +7,6 @@ #include #include -bool guest_start(size_t boot_vcpu_id, uintptr_t kernel_pc, uintptr_t dtb, uintptr_t initrd); -void guest_stop(size_t boot_vcpu_id); -bool guest_restart(size_t boot_vcpu_id, uintptr_t guest_ram_vaddr, size_t guest_ram_size); +bool guest_start(uintptr_t kernel_pc, uintptr_t dtb, uintptr_t initrd); +void guest_stop(); +bool guest_restart(uintptr_t guest_ram_vaddr, size_t guest_ram_size); diff --git a/include/libvmm/util/util.h b/include/libvmm/util/util.h index d2778323..6b808ed3 100644 --- a/include/libvmm/util/util.h +++ b/include/libvmm/util/util.h @@ -12,9 +12,13 @@ #include #include -// @ivanv: these are here for convience, should not be here though -#define GUEST_VCPU_ID 0 +#define GUEST_BOOT_VCPU_ID 0 + +#ifndef GUEST_NUM_VCPUS #define GUEST_NUM_VCPUS 1 +#endif + +#define PAGE_SIZE_MIN 0x1000 // @ivanv: if we keep using this, make sure that we have a static assert // that sizeof seL4_UserContext is 0x24 diff --git a/include/libvmm/vcpu.h b/include/libvmm/vcpu.h index 83cf23af..7aaa7732 100644 --- a/include/libvmm/vcpu.h +++ b/include/libvmm/vcpu.h @@ -6,7 +6,22 @@ #pragma once +#include #include +/* + * Checks whether the given vCPU is on. + * + * Returns true if the vCPU is on, otherwise false. + * Returns false if an invalid vCPU ID is given. + */ +bool vcpu_is_on(size_t vcpu_id); + +/* + * Change the state tracking for whether a given vCPU is on. + * Does nothing if an invalid vCPU ID is given. + */ +void vcpu_set_on(size_t vcpu_id, bool on); + void vcpu_reset(size_t vcpu_id); void vcpu_print_regs(size_t vcpu_id); diff --git a/include/libvmm/virq.h b/include/libvmm/virq.h index 0b921364..ba623154 100644 --- a/include/libvmm/virq.h +++ b/include/libvmm/virq.h @@ -14,9 +14,24 @@ typedef void (*virq_ack_fn_t)(size_t vcpu_id, int irq, void *cookie); -bool virq_controller_init(size_t boot_vcpu_id); +/* + * Initialise the architecture-depedent virtual interrupt controller. + * On ARM, this is the virtual Generic Interrupt Controller (vGIC). + */ +bool virq_controller_init(); bool virq_register(size_t vcpu_id, size_t virq_num, virq_ack_fn_t ack_fn, void *ack_data); -bool virq_inject(size_t vcpu_id, int irq); + +/* + * Inject an IRQ into the boot virtual CPU. + * Note that this API requires that the IRQ has been registered (with virq_register). + */ +bool virq_inject(int irq); + +/* + * The same functionality as virq_inject, but will inject the virtual IRQ into a specific + * virtual CPU. + */ +bool virq_inject_vcpu(size_t vcpu_id, int irq); /* * These two APIs are convenient for when you want to directly passthrough an IRQ from diff --git a/src/arch/aarch64/fault.c b/src/arch/aarch64/fault.c index f40a3ded..30e03ee2 100644 --- a/src/arch/aarch64/fault.c +++ b/src/arch/aarch64/fault.c @@ -22,7 +22,8 @@ // return !CPSR_IS_THUMB(regs->spsr); // } -bool fault_advance_vcpu(size_t vcpu_id, seL4_UserContext *regs) { +bool fault_advance_vcpu(size_t vcpu_id, seL4_UserContext *regs) +{ // For now we just ignore it and continue // Assume 32-bit instruction regs->pc += 4; @@ -32,15 +33,23 @@ bool fault_advance_vcpu(size_t vcpu_id, seL4_UserContext *regs) { return (err == seL4_NoError); } -char *fault_to_string(seL4_Word fault_label) { +char *fault_to_string(seL4_Word fault_label) +{ switch (fault_label) { - case seL4_Fault_VMFault: return "virtual memory"; - case seL4_Fault_UnknownSyscall: return "unknown syscall"; - case seL4_Fault_UserException: return "user exception"; - case seL4_Fault_VGICMaintenance: return "VGIC maintenance"; - case seL4_Fault_VCPUFault: return "VCPU"; - case seL4_Fault_VPPIEvent: return "VPPI event"; - default: return "unknown fault"; + case seL4_Fault_VMFault: + return "virtual memory"; + case seL4_Fault_UnknownSyscall: + return "unknown syscall"; + case seL4_Fault_UserException: + return "user exception"; + case seL4_Fault_VGICMaintenance: + return "VGIC maintenance"; + case seL4_Fault_VCPUFault: + return "VCPU"; + case seL4_Fault_VPPIEvent: + return "VPPI event"; + default: + return "unknown fault"; } } @@ -59,7 +68,7 @@ enum fault_width { static enum fault_width fault_get_width(uint64_t fsr) { if (HSR_IS_SYNDROME_VALID(fsr) && HSR_SYNDROME_WIDTH(fsr) <= WIDTH_DOUBLEWORD) { - return (enum fault_width) (HSR_SYNDROME_WIDTH(fsr)); + return (enum fault_width)(HSR_SYNDROME_WIDTH(fsr)); } else { LOG_VMM_ERR("Received invalid FSR: 0x%lx\n", fsr); // @ivanv: reviist @@ -74,26 +83,26 @@ uint64_t fault_get_data_mask(uint64_t addr, uint64_t fsr) { uint64_t mask = 0; switch (fault_get_width(fsr)) { - case WIDTH_BYTE: - mask = 0x000000ff; - assert(!(addr & 0x0)); - break; - case WIDTH_HALFWORD: - mask = 0x0000ffff; - assert(!(addr & 0x1)); - break; - case WIDTH_WORD: - mask = 0xffffffff; - assert(!(addr & 0x3)); - break; - case WIDTH_DOUBLEWORD: - mask = ~mask; - break; - default: - LOG_VMM_ERR("unknown width: 0x%lx, from FSR: 0x%lx, addr: 0x%lx\n", - fault_get_width(fsr), fsr, addr); - assert(0); - return 0; + case WIDTH_BYTE: + mask = 0x000000ff; + assert(!(addr & 0x0)); + break; + case WIDTH_HALFWORD: + mask = 0x0000ffff; + assert(!(addr & 0x1)); + break; + case WIDTH_WORD: + mask = 0xffffffff; + assert(!(addr & 0x3)); + break; + case WIDTH_DOUBLEWORD: + mask = ~mask; + break; + default: + LOG_VMM_ERR("unknown width: 0x%lx, from FSR: 0x%lx, addr: 0x%lx\n", + fault_get_width(fsr), fsr, addr); + assert(0); + return 0; } mask <<= (addr & 0x3) * 8; return mask; @@ -108,41 +117,73 @@ seL4_Word *decode_rt(size_t reg_idx, seL4_UserContext *regs) * encodes the Syndrome Register transfer. */ switch (reg_idx) { - case 0: return ®s->x0; - case 1: return ®s->x1; - case 2: return ®s->x2; - case 3: return ®s->x3; - case 4: return ®s->x4; - case 5: return ®s->x5; - case 6: return ®s->x6; - case 7: return ®s->x7; - case 8: return ®s->x8; - case 9: return ®s->x9; - case 10: return ®s->x10; - case 11: return ®s->x11; - case 12: return ®s->x12; - case 13: return ®s->x13; - case 14: return ®s->x14; - case 15: return ®s->x15; - case 16: return ®s->x16; - case 17: return ®s->x17; - case 18: return ®s->x18; - case 19: return ®s->x19; - case 20: return ®s->x20; - case 21: return ®s->x21; - case 22: return ®s->x22; - case 23: return ®s->x23; - case 24: return ®s->x24; - case 25: return ®s->x25; - case 26: return ®s->x26; - case 27: return ®s->x27; - case 28: return ®s->x28; - case 29: return ®s->x29; - case 30: return ®s->x30; - case 31: return &wzr; - default: - LOG_VMM_ERR("failed to decode Rt, attempted to access invalid register index 0x%lx\n", reg_idx); - return NULL; + case 0: + return ®s->x0; + case 1: + return ®s->x1; + case 2: + return ®s->x2; + case 3: + return ®s->x3; + case 4: + return ®s->x4; + case 5: + return ®s->x5; + case 6: + return ®s->x6; + case 7: + return ®s->x7; + case 8: + return ®s->x8; + case 9: + return ®s->x9; + case 10: + return ®s->x10; + case 11: + return ®s->x11; + case 12: + return ®s->x12; + case 13: + return ®s->x13; + case 14: + return ®s->x14; + case 15: + return ®s->x15; + case 16: + return ®s->x16; + case 17: + return ®s->x17; + case 18: + return ®s->x18; + case 19: + return ®s->x19; + case 20: + return ®s->x20; + case 21: + return ®s->x21; + case 22: + return ®s->x22; + case 23: + return ®s->x23; + case 24: + return ®s->x24; + case 25: + return ®s->x25; + case 26: + return ®s->x26; + case 27: + return ®s->x27; + case 28: + return ®s->x28; + case 29: + return ®s->x29; + case 30: + return ®s->x30; + case 31: + return &wzr; + default: + LOG_VMM_ERR("failed to decode Rt, attempted to access invalid register index 0x%lx\n", reg_idx); + return NULL; } } @@ -195,7 +236,8 @@ uint64_t fault_emulate(seL4_UserContext *regs, uint64_t reg, uint64_t addr, uint } } -void fault_emulate_write(seL4_UserContext *regs, size_t addr, size_t fsr, size_t reg_val) { +void fault_emulate_write(seL4_UserContext *regs, size_t addr, size_t fsr, size_t reg_val) +{ // @ivanv: audit /* Get register opearand */ int rt = get_rt(fsr); @@ -219,14 +261,14 @@ bool fault_handle_vcpu_exception(size_t vcpu_id) uint32_t hsr = microkit_mr_get(seL4_VCPUFault_HSR); uint64_t hsr_ec_class = HSR_EXCEPTION_CLASS(hsr); switch (hsr_ec_class) { - case HSR_SMC_64_EXCEPTION: - return handle_smc(vcpu_id, hsr); - case HSR_WFx_EXCEPTION: - // If we get a WFI exception, we just do nothing in the VMM. - return true; - default: - LOG_VMM_ERR("unknown SMC exception, EC class: 0x%lx, HSR: 0x%lx\n", hsr_ec_class, hsr); - return false; + case HSR_SMC_64_EXCEPTION: + return handle_smc(vcpu_id, hsr); + case HSR_WFx_EXCEPTION: + // If we get a WFI exception, we just do nothing in the VMM. + return true; + default: + LOG_VMM_ERR("unknown SMC exception, EC class: 0x%lx, HSR: 0x%lx\n", hsr_ec_class, hsr); + return false; } } @@ -251,11 +293,11 @@ bool fault_handle_user_exception(size_t vcpu_id) // @ivanv: print out VM name/vCPU id when we have multiple VMs size_t fault_ip = microkit_mr_get(seL4_UserException_FaultIP); size_t number = microkit_mr_get(seL4_UserException_Number); - LOG_VMM_ERR("Invalid instruction fault at IP: 0x%lx, number: 0x%lx", fault_ip, number); + LOG_VMM_ERR("Invalid instruction fault at IP: 0x%lx, number: 0x%lx from vCPU %d\n", fault_ip, number, vcpu_id); /* All we do is dump the TCB registers. */ tcb_print_regs(vcpu_id); - return true; + return false; } // @ivanv: document where these come from @@ -270,17 +312,17 @@ bool fault_handle_unknown_syscall(size_t vcpu_id) LOG_VMM("Received syscall 0x%lx\n", syscall); switch (syscall) { - case SYSCALL_PA_TO_IPA: - // @ivanv: why do we not do anything here? - // @ivanv, how to get the physical address to translate? - LOG_VMM("Received PA translation syscall\n"); - break; - case SYSCALL_NOP: - LOG_VMM("Received NOP syscall\n"); - break; - default: - LOG_VMM_ERR("Unknown syscall: syscall number: 0x%lx, PC: 0x%lx\n", syscall, fault_ip); - return false; + case SYSCALL_PA_TO_IPA: + // @ivanv: why do we not do anything here? + // @ivanv, how to get the physical address to translate? + LOG_VMM("Received PA translation syscall\n"); + break; + case SYSCALL_NOP: + LOG_VMM("Received NOP syscall\n"); + break; + default: + LOG_VMM_ERR("Unknown syscall: syscall number: 0x%lx, PC: 0x%lx\n", syscall, fault_ip); + return false; } seL4_UserContext regs; @@ -304,7 +346,8 @@ struct vm_exception_handler { struct vm_exception_handler registered_vm_exception_handlers[MAX_VM_EXCEPTION_HANDLERS]; size_t vm_exception_handler_index = 0; -bool fault_register_vm_exception_handler(uintptr_t base, size_t size, vm_exception_handler_t callback, void *data) { +bool fault_register_vm_exception_handler(uintptr_t base, size_t size, vm_exception_handler_t callback, void *data) +{ // @ivanv audit necessary here since this code was written very quickly. Other things to check such // as the region of memory is not overlapping with other regions, also should have GIC_DIST regions // use this API. @@ -312,8 +355,7 @@ bool fault_register_vm_exception_handler(uintptr_t base, size_t size, vm_excepti return false; } - // @ivanv: use a define for page size? preMAture GENeraliZAATION - if (base % 0x1000 != 0) { + if (base % PAGE_SIZE_MIN != 0) { return false; } @@ -328,7 +370,8 @@ bool fault_register_vm_exception_handler(uintptr_t base, size_t size, vm_excepti return true; } -static bool fault_handle_registered_vm_exceptions(size_t vcpu_id, uintptr_t addr, size_t fsr, seL4_UserContext *regs) { +static bool fault_handle_registered_vm_exceptions(size_t vcpu_id, uintptr_t addr, size_t fsr, seL4_UserContext *regs) +{ for (int i = 0; i < MAX_VM_EXCEPTION_HANDLERS; i++) { uintptr_t base = registered_vm_exception_handlers[i].base; uintptr_t end = registered_vm_exception_handlers[i].end; @@ -338,7 +381,8 @@ static bool fault_handle_registered_vm_exceptions(size_t vcpu_id, uintptr_t addr bool success = callback(vcpu_id, addr - base, fsr, regs, data); if (!success) { // @ivanv: improve error message - LOG_VMM_ERR("registered virtual memory exception handler for region [0x%lx..0x%lx) at address 0x%lx failed\n", base, end, addr); + LOG_VMM_ERR("registered virtual memory exception handler for region [0x%lx..0x%lx) at address 0x%lx failed\n", base, + end, addr); } /* Whether or not the callback actually successfully handled the * exception, we return true to say that we at least found a handler @@ -372,7 +416,7 @@ bool fault_handle_vm_exception(size_t vcpu_id) size_t is_prefetch = seL4_GetMR(seL4_VMFault_PrefetchFault); bool is_write = fault_is_write(fsr); LOG_VMM_ERR("unexpected memory fault on address: 0x%lx, FSR: 0x%lx, IP: 0x%lx, is_prefetch: %s, is_write: %s\n", - addr, fsr, ip, is_prefetch ? "true" : "false", is_write ? "true" : "false"); + addr, fsr, ip, is_prefetch ? "true" : "false", is_write ? "true" : "false"); tcb_print_regs(vcpu_id); vcpu_print_regs(vcpu_id); } else { @@ -382,36 +426,37 @@ bool fault_handle_vm_exception(size_t vcpu_id) return success; } -bool fault_handle(size_t vcpu_id, microkit_msginfo msginfo) { +bool fault_handle(size_t vcpu_id, microkit_msginfo msginfo) +{ size_t label = microkit_msginfo_get_label(msginfo); bool success = false; switch (label) { - case seL4_Fault_VMFault: - success = fault_handle_vm_exception(vcpu_id); - break; - case seL4_Fault_UnknownSyscall: - success = fault_handle_unknown_syscall(vcpu_id); - break; - case seL4_Fault_UserException: - success = fault_handle_user_exception(vcpu_id); - break; - case seL4_Fault_VGICMaintenance: - success = fault_handle_vgic_maintenance(vcpu_id); - break; - case seL4_Fault_VCPUFault: - success = fault_handle_vcpu_exception(vcpu_id); - break; - case seL4_Fault_VPPIEvent: - success = fault_handle_vppi_event(vcpu_id); - break; - default: - /* We have reached a genuinely unexpected case, stop the guest. */ - LOG_VMM_ERR("unknown fault label 0x%lx, stopping guest with ID 0x%lx\n", label, vcpu_id); - microkit_vcpu_stop(vcpu_id); - /* Dump the TCB and vCPU registers to hopefully get information as - * to what has gone wrong. */ - tcb_print_regs(vcpu_id); - vcpu_print_regs(vcpu_id); + case seL4_Fault_VMFault: + success = fault_handle_vm_exception(vcpu_id); + break; + case seL4_Fault_UnknownSyscall: + success = fault_handle_unknown_syscall(vcpu_id); + break; + case seL4_Fault_UserException: + success = fault_handle_user_exception(vcpu_id); + break; + case seL4_Fault_VGICMaintenance: + success = vgic_handle_fault_maintenance(vcpu_id); + break; + case seL4_Fault_VCPUFault: + success = fault_handle_vcpu_exception(vcpu_id); + break; + case seL4_Fault_VPPIEvent: + success = fault_handle_vppi_event(vcpu_id); + break; + default: + /* We have reached a genuinely unexpected case, stop the guest. */ + LOG_VMM_ERR("unknown fault label 0x%lx, stopping guest with ID 0x%lx\n", label, vcpu_id); + microkit_vcpu_stop(vcpu_id); + /* Dump the TCB and vCPU registers to hopefully get information as + * to what has gone wrong. */ + tcb_print_regs(vcpu_id); + vcpu_print_regs(vcpu_id); } if (!success) { diff --git a/src/arch/aarch64/psci.c b/src/arch/aarch64/psci.c index fb7dc36d..e4e4d832 100644 --- a/src/arch/aarch64/psci.c +++ b/src/arch/aarch64/psci.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -37,67 +38,98 @@ bool handle_psci(size_t vcpu_id, seL4_UserContext *regs, uint64_t fn_number, uin // @ivanv: write a note about what convention we assume, should we be checking // the convention? switch (fn_number) { - case PSCI_VERSION: { - /* We support PSCI version 1.2 */ - uint32_t version = PSCI_MAJOR_VERSION(1) | PSCI_MINOR_VERSION(2); - smc_set_return_value(regs, version); - break; - } - case PSCI_CPU_ON: { - uintptr_t target_cpu = smc_get_arg(regs, 1); - // Right now we only have one vCPU and so any fault for a target vCPU - // that isn't the one that's already on we consider an error on the - // guest's side. - // @ivanv: adapt for starting other vCPUs - if (target_cpu == vcpu_id) { + case PSCI_VERSION: { + /* We support PSCI version 1.2 */ + uint32_t version = PSCI_MAJOR_VERSION(1) | PSCI_MINOR_VERSION(2); + smc_set_return_value(regs, version); + break; + } + case PSCI_CPU_ON: { + size_t target_vcpu = smc_get_arg(regs, 1); + if (target_vcpu < GUEST_NUM_VCPUS && target_vcpu >= 0) { + /* The guest has given a valid target vCPU */ + if (vcpu_is_on(target_vcpu)) { smc_set_return_value(regs, PSCI_ALREADY_ON); } else { - // The guest has requested to turn on a virtual CPU that does - // not exist. - smc_set_return_value(regs, PSCI_INVALID_PARAMETERS); + /* We have a valid target vCPU, that is not started yet. So let's turn it on. */ + uintptr_t vcpu_entry_point = smc_get_arg(regs, 2); + size_t context_id = smc_get_arg(regs, 3); + + seL4_UserContext vcpu_regs = {0}; + vcpu_regs.x0 = context_id; + vcpu_regs.spsr = 5; // PMODE_EL1h + vcpu_regs.pc = vcpu_entry_point; + + microkit_vcpu_arm_write_reg(target_vcpu, seL4_VCPUReg_VMPIDR_EL2, target_vcpu); + + seL4_Error err = seL4_TCB_WriteRegisters( + BASE_VM_TCB_CAP + target_vcpu, + false, // We'll explcitly start the guest below rather than in this call + 0, // No flags + SEL4_USER_CONTEXT_SIZE, + &vcpu_regs + ); + assert(err == seL4_NoError); + if (err != seL4_NoError) { + return err; + } + + /* Now that we have started the vCPU, we can set is as turned on. */ + vcpu_set_on(target_vcpu, true); + + LOG_VMM("starting guest vCPU (0x%lx) with entry point 0x%lx, context ID: 0x%lx\n", target_vcpu, vcpu_regs.pc, + context_id); + microkit_vcpu_restart(target_vcpu, vcpu_regs.pc); + + smc_set_return_value(regs, PSCI_SUCCESS); } - break; - } - case PSCI_MIGRATE_INFO_TYPE: - /* - * There are multiple possible return values for MIGRATE_INFO_TYPE. - * In this case returning 2 will tell the guest that this is a - * system that does not use a "Trusted OS" as the PSCI - * specification says. - */ - smc_set_return_value(regs, 2); - break; - case PSCI_FEATURES: - // @ivanv: seems weird that we just return nothing here. - smc_set_return_value(regs, PSCI_NOT_SUPPORTED); - break; - case PSCI_SYSTEM_RESET: { - // @refactor come back to - // bool success = guest_restart(); - // if (!success) { - // LOG_VMM_ERR("Failed to restart guest\n"); - // smc_set_return_value(regs, PSCI_INTERNAL_FAILURE); - // } else { - - // * If we've successfully restarted the guest, all we want to do - // * is reply to the fault that caused us to handle the PSCI call - // * so that the guest can continue executing. We do not need to - // * advance the vCPU program counter as we typically do when - // * handling a fault since the correct PC has been set when we - // * call guest_restart(). - - // return true; - // } - break; + } else { + // The guest has requested to turn on a virtual CPU that does + // not exist. + smc_set_return_value(regs, PSCI_INVALID_PARAMETERS); } - case PSCI_SYSTEM_OFF: - // @refactor, is it guaranteed that the CPU that does the vCPU request - // is the boot vcpu? - guest_stop(vcpu_id); - return true; - default: - LOG_VMM_ERR("Unhandled PSCI function ID 0x%lx\n", fn_number); - return false; + break; + } + case PSCI_MIGRATE_INFO_TYPE: + /* + * There are multiple possible return values for MIGRATE_INFO_TYPE. + * In this case returning 2 will tell the guest that this is a + * system that does not use a "Trusted OS" as the PSCI + * specification says. + */ + smc_set_return_value(regs, 2); + break; + case PSCI_FEATURES: + // @ivanv: seems weird that we just return nothing here. + smc_set_return_value(regs, PSCI_NOT_SUPPORTED); + break; + case PSCI_SYSTEM_RESET: { + // @refactor come back to + // bool success = guest_restart(); + // if (!success) { + // LOG_VMM_ERR("Failed to restart guest\n"); + // smc_set_return_value(regs, PSCI_INTERNAL_FAILURE); + // } else { + + // * If we've successfully restarted the guest, all we want to do + // * is reply to the fault that caused us to handle the PSCI call + // * so that the guest can continue executing. We do not need to + // * advance the vCPU program counter as we typically do when + // * handling a fault since the correct PC has been set when we + // * call guest_restart(). + + // return true; + // } + break; + } + case PSCI_SYSTEM_OFF: + // @refactor, is it guaranteed that the CPU that does the vCPU request + // is the boot vcpu? + guest_stop(); + return true; + default: + LOG_VMM_ERR("Unhandled PSCI function ID 0x%lx\n", fn_number); + return false; } bool success = fault_advance_vcpu(vcpu_id, regs); diff --git a/src/arch/aarch64/smc.c b/src/arch/aarch64/smc.c index cd305d5b..a0c8ad6f 100644 --- a/src/arch/aarch64/smc.c +++ b/src/arch/aarch64/smc.c @@ -63,30 +63,48 @@ inline void smc_set_return_value(seL4_UserContext *u, uint64_t val) uint64_t smc_get_arg(seL4_UserContext *u, uint64_t arg) { switch (arg) { - case 1: return u->x1; - case 2: return u->x2; - case 3: return u->x3; - case 4: return u->x4; - case 5: return u->x5; - case 6: return u->x6; - default: - LOG_VMM_ERR("trying to get SMC arg: 0x%lx, SMC only has 6 argument registers\n", arg); - // @ivanv: come back to this - return 0; + case 1: + return u->x1; + case 2: + return u->x2; + case 3: + return u->x3; + case 4: + return u->x4; + case 5: + return u->x5; + case 6: + return u->x6; + default: + LOG_VMM_ERR("trying to get SMC arg: 0x%lx, SMC only has 6 argument registers\n", arg); + // @ivanv: come back to this + return 0; } } static void smc_set_arg(seL4_UserContext *u, size_t arg, size_t val) { switch (arg) { - case 1: u->x1 = val; break; - case 2: u->x2 = val; break; - case 3: u->x3 = val; break; - case 4: u->x4 = val; break; - case 5: u->x5 = val; break; - case 6: u->x6 = val; break; - default: - LOG_VMM_ERR("trying to set SMC arg: 0x%lx, with val: 0x%lx, SMC only has 6 argument registers\n", arg, val); + case 1: + u->x1 = val; + break; + case 2: + u->x2 = val; + break; + case 3: + u->x3 = val; + break; + case 4: + u->x4 = val; + break; + case 5: + u->x5 = val; + break; + case 6: + u->x6 = val; + break; + default: + LOG_VMM_ERR("trying to set SMC arg: 0x%lx, with val: 0x%lx, SMC only has 6 argument registers\n", arg, val); } } @@ -103,15 +121,15 @@ bool handle_smc(size_t vcpu_id, uint32_t hsr) smc_call_id_t service = smc_get_call(regs.x0); switch (service) { - case SMC_CALL_STD_SERVICE: - if (fn_number < PSCI_MAX) { - return handle_psci(vcpu_id, ®s, fn_number, hsr); - } - LOG_VMM_ERR("Unhandled SMC: standard service call %lu\n", fn_number); - break; - default: - LOG_VMM_ERR("Unhandled SMC: unknown value service: 0x%lx, function number: 0x%lx\n", service, fn_number); - break; + case SMC_CALL_STD_SERVICE: + if (fn_number < PSCI_MAX) { + return handle_psci(vcpu_id, ®s, fn_number, hsr); + } + LOG_VMM_ERR("Unhandled SMC: standard service call %lu\n", fn_number); + break; + default: + LOG_VMM_ERR("Unhandled SMC: unknown value service: 0x%lx, function number: 0x%lx\n", service, fn_number); + break; } return false; diff --git a/src/arch/aarch64/tcb.c b/src/arch/aarch64/tcb.c index 2357b102..86c896db 100644 --- a/src/arch/aarch64/tcb.c +++ b/src/arch/aarch64/tcb.c @@ -9,7 +9,8 @@ #include #include -void tcb_print_regs(size_t vcpu_id) { +void tcb_print_regs(size_t vcpu_id) +{ /* * While we are potentially doing an extra system call in order to read the * TCB registers (as the VMM may have already read the TCB registers before diff --git a/src/arch/aarch64/vcpu.c b/src/arch/aarch64/vcpu.c index b41ee368..eb090dfe 100644 --- a/src/arch/aarch64/vcpu.c +++ b/src/arch/aarch64/vcpu.c @@ -25,7 +25,30 @@ #define SCTLR_EL1_NATIVE (SCTLR_EL1 | SCTLR_EL1_C | SCTLR_EL1_I | SCTLR_EL1_UCI) #define SCTLR_DEFAULT SCTLR_EL1_NATIVE -void vcpu_reset(size_t vcpu_id) { +bool vcpu_on_state[GUEST_NUM_VCPUS]; + +bool vcpu_is_on(size_t vcpu_id) +{ + assert(vcpu_id < GUEST_NUM_VCPUS); + if (vcpu_id >= GUEST_NUM_VCPUS) { + return false; + } + + return vcpu_on_state[vcpu_id]; +} + +void vcpu_set_on(size_t vcpu_id, bool on) +{ + assert(vcpu_id < GUEST_NUM_VCPUS); + if (vcpu_id >= GUEST_NUM_VCPUS) { + return; + } + + vcpu_on_state[vcpu_id] = on; +} + +void vcpu_reset(size_t vcpu_id) +{ // @ivanv this is an incredible amount of system calls // Reset registers // @ivanv: double check, shouldn't we be setting sctlr? @@ -63,7 +86,8 @@ void vcpu_reset(size_t vcpu_id) { microkit_vcpu_arm_write_reg(vcpu_id, seL4_VCPUReg_CNTKCTL_EL1, 0); } -void vcpu_print_regs(size_t vcpu_id) { +void vcpu_print_regs(size_t vcpu_id) +{ // @ivanv this is an incredible amount of system calls LOG_VMM("dumping VCPU (ID 0x%lx) registers:\n", vcpu_id); /* VM control registers EL1 */ diff --git a/src/arch/aarch64/vgic/vgic.c b/src/arch/aarch64/vgic/vgic.c index fb160566..86abdd9a 100644 --- a/src/arch/aarch64/vgic/vgic.c +++ b/src/arch/aarch64/vgic/vgic.c @@ -1,10 +1,11 @@ -/* @ivanv double check +/* * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) * Copyright 2022, UNSW (ABN 57 195 873 179) * * SPDX-License-Identifier: BSD-2-Clause */ #include +#include #include #include #include @@ -23,13 +24,13 @@ /* The driver expects the VGIC state to be initialised before calling any of the driver functionality. */ extern vgic_t vgic; -bool fault_handle_vgic_maintenance(size_t vcpu_id) +bool vgic_handle_fault_maintenance(size_t vcpu_id) { // @ivanv: reivist, also inconsistency between int and bool bool success = true; int idx = microkit_mr_get(seL4_VGICMaintenance_IDX); /* Currently not handling spurious IRQs */ - // @ivanv: wtf, this comment seems irrelevant to the code. + // @ivanv: this comment seems irrelevant to the code. assert(idx >= 0); // @ivanv: Revisit and make sure it's still correct. @@ -62,15 +63,29 @@ bool fault_handle_vgic_maintenance(size_t vcpu_id) } if (!success) { - printf("VGIC|ERROR: maintenance handler failed\n"); + LOG_VMM_ERR("vGIC maintenance handler failed\n"); assert(0); } return success; } -// @ivanv: maybe this shouldn't be here? -bool vgic_register_irq(size_t vcpu_id, int virq_num, virq_ack_fn_t ack_fn, void *ack_data) { +bool vgic_handle_fault_dist(size_t vcpu_id, size_t offset, size_t fsr, seL4_UserContext *regs, void *data) +{ + bool success = false; + if (fault_is_read(fsr)) { + success = vgic_handle_fault_dist_read(vcpu_id, &vgic, offset, fsr, regs); + assert(success); + } else { + success = vgic_handle_fault_dist_write(vcpu_id, &vgic, offset, fsr, regs); + assert(success); + } + + return success; +} + +bool vgic_register_irq(size_t vcpu_id, int virq_num, virq_ack_fn_t ack_fn, void *ack_data) +{ assert(virq_num >= 0 && virq_num != VIRQ_INVALID); struct virq_handle virq = { .virq = virq_num, @@ -83,32 +98,10 @@ bool vgic_register_irq(size_t vcpu_id, int virq_num, virq_ack_fn_t ack_fn, void bool vgic_inject_irq(size_t vcpu_id, int irq) { - LOG_IRQ("Injecting IRQ %d\n", irq); + LOG_IRQ("(vCPU %d) injecting IRQ %d\n", vcpu_id, irq); - return vgic_dist_set_pending_irq(&vgic, vcpu_id, irq); - - // @ivanv: explain why we don't check error before checking this fault stuff - // @ivanv: seperately, it seems weird to have this fault handling code here? - // @ivanv: revist - // if (!fault_handled(vcpu->vcpu_arch.fault) && fault_is_wfi(vcpu->vcpu_arch.fault)) { - // // ignore_fault(vcpu->vcpu_arch.fault); - // err = advance_vcpu_fault(regs); - // } -} - -// @ivanv: revisit this whole function -bool handle_vgic_dist_fault(size_t vcpu_id, size_t offset, size_t fsr, seL4_UserContext *regs, void *data) -{ - bool success = false; - if (fault_is_read(fsr)) { - // printf("VGIC|INFO: Read dist\n"); - success = vgic_dist_reg_read(vcpu_id, &vgic, offset, fsr, regs); - assert(success); - } else { - // printf("VGIC|INFO: Write dist\n"); - success = vgic_dist_reg_write(vcpu_id, &vgic, offset, fsr, regs); - assert(success); - } + bool success = vgic_dist_set_pending_irq(&vgic, vcpu_id, irq); + assert(success); return success; -} \ No newline at end of file +} diff --git a/src/arch/aarch64/vgic/vgic_v2.c b/src/arch/aarch64/vgic/vgic_v2.c index 62cec8bc..556ef0e9 100644 --- a/src/arch/aarch64/vgic/vgic_v2.c +++ b/src/arch/aarch64/vgic/vgic_v2.c @@ -59,7 +59,7 @@ static void vgic_dist_reset(struct gic_dist_map *gic_dist) gic_dist->typer = 0x0000fce7; /* RO */ gic_dist->iidr = 0x0200043b; /* RO */ - for (int i = 0; i < CONFIG_MAX_NUM_NODES; i++) { + for (int i = 0; i < GUEST_NUM_VCPUS; i++) { gic_dist->enable_set0[i] = 0x0000ffff; /* 16bit RO */ gic_dist->enable_clr0[i] = 0x0000ffff; /* 16bit RO */ } @@ -83,7 +83,7 @@ static void vgic_dist_reset(struct gic_dist_map *gic_dist) gic_dist->config[15] = 0x55555555; /* Configure per-processor SGI/PPI target registers */ - for (int i = 0; i < CONFIG_MAX_NUM_NODES; i++) { + for (int i = 0; i < GUEST_NUM_VCPUS; i++) { for (int j = 0; j < ARRAY_SIZE(gic_dist->targets0[i]); j++) { for (int irq = 0; irq < sizeof(uint32_t); irq++) { gic_dist->targets0[i][j] |= ((1 << i) << (irq * 8)); @@ -109,23 +109,24 @@ static void vgic_dist_reset(struct gic_dist_map *gic_dist) void vgic_init() { memset(&vgic, 0, sizeof(vgic_t)); - for (int i = 0; i < NUM_SLOTS_SPI_VIRQ; i++) { - vgic.vspis[i].virq = VIRQ_INVALID; - } - for (int i = 0; i < NUM_VCPU_LOCAL_VIRQS; i++) { - vgic.vgic_vcpu[GUEST_VCPU_ID].local_virqs[i].virq = VIRQ_INVALID; - } - for (int i = 0; i < NUM_LIST_REGS; i++) { - vgic.vgic_vcpu[GUEST_VCPU_ID].lr_shadow[i].virq = VIRQ_INVALID; - } - for (int i = 0; i < MAX_IRQ_QUEUE_LEN; i++) { - vgic.vgic_vcpu[GUEST_VCPU_ID].irq_queue.irqs[i] = NULL; - } - for (int i = 0; i < NUM_SLOTS_SPI_VIRQ; i++) { - vgic.vspis[i].virq = VIRQ_INVALID; - vgic.vspis[i].ack_fn = NULL; - vgic.vspis[i].ack_data = NULL; + + for (int vcpu = 0; vcpu < GUEST_NUM_VCPUS; vcpu++) { + for (int i = 0; i < NUM_VCPU_LOCAL_VIRQS; i++) { + vgic.vgic_vcpu[vcpu].local_virqs[i].virq = VIRQ_INVALID; + } + for (int i = 0; i < NUM_LIST_REGS; i++) { + vgic.vgic_vcpu[vcpu].lr_shadow[i].virq = VIRQ_INVALID; + } + for (int i = 0; i < MAX_IRQ_QUEUE_LEN; i++) { + vgic.vgic_vcpu[vcpu].irq_queue.irqs[i] = NULL; + } + for (int i = 0; i < NUM_SLOTS_SPI_VIRQ; i++) { + vgic.vspis[i].virq = VIRQ_INVALID; + vgic.vspis[i].ack_fn = NULL; + vgic.vspis[i].ack_data = NULL; + } } + vgic.registers = &dist; memset(vgic.registers, 0, sizeof(struct gic_dist_map)); vgic_dist_reset(vgic_get_dist(vgic.registers)); diff --git a/src/arch/aarch64/vgic/vgic_v3.c b/src/arch/aarch64/vgic/vgic_v3.c index 59e6f9d8..056487e9 100644 --- a/src/arch/aarch64/vgic/vgic_v3.c +++ b/src/arch/aarch64/vgic/vgic_v3.c @@ -45,7 +45,8 @@ vgic_t vgic; -static bool handle_vgic_redist_read_fault(size_t vcpu_id, vgic_t *vgic, uint64_t offset, uint64_t fsr, seL4_UserContext *regs) +static bool vgic_handle_fault_redist_read(size_t vcpu_id, vgic_t *vgic, uint64_t offset, uint64_t fsr, + seL4_UserContext *regs) { struct gic_dist_map *gic_dist = vgic_get_dist(vgic->registers); struct gic_redist_map *gic_redist = vgic_get_redist(vgic->registers); @@ -96,8 +97,8 @@ static bool handle_vgic_redist_read_fault(size_t vcpu_id, vgic_t *vgic, uint64_t return true; } - -static bool handle_vgic_redist_write_fault(size_t vcpu_id, vgic_t *vgic, uint64_t offset, uint64_t fsr, seL4_UserContext *regs) +static bool vgic_handle_fault_redist_write(size_t vcpu_id, vgic_t *vgic, uint64_t offset, uint64_t fsr, + seL4_UserContext *regs) { // @ivanv: why is this not reading from the redist? uintptr_t fault_addr = GIC_REDIST_PADDR + offset; @@ -134,8 +135,8 @@ static bool handle_vgic_redist_write_fault(size_t vcpu_id, vgic_t *vgic, uint64_ } break; case RANGE32(GICR_ICACTIVER0, GICR_ICACTIVER0): - // @ivanv: understand, this is a comment left over from kent - // TODO fix this + // @ivanv: understand, this is a comment left over from kent + // TODO fix this emulate_reg_write_access(regs, fault_addr, fsr, &gic_dist->active0[vcpu_id]); break; case RANGE32(GICR_IPRIORITYR0, GICR_IPRIORITYRN): @@ -147,11 +148,12 @@ static bool handle_vgic_redist_write_fault(size_t vcpu_id, vgic_t *vgic, uint64_ return true; } -bool handle_vgic_redist_fault(size_t vcpu_id, size_t offset, size_t fsr, seL4_UserContext *regs, void *data) { +bool vgic_handle_fault_redist(size_t vcpu_id, size_t offset, size_t fsr, seL4_UserContext *regs, void *data) +{ if (fault_is_read(fsr)) { - return handle_vgic_redist_read_fault(vcpu_id, &vgic, offset, fsr, regs); + return vgic_handle_fault_redist_read(vcpu_id, &vgic, offset, fsr, regs); } else { - return handle_vgic_redist_write_fault(vcpu_id, &vgic, offset, fsr, regs); + return vgic_handle_fault_redist_write(vcpu_id, &vgic, offset, fsr, regs); } } @@ -179,7 +181,8 @@ static void vgic_dist_reset(struct gic_dist_map *dist) dist->cidrn[3] = 0xB1; /* RO */ } -static void vgic_redist_reset(struct gic_redist_map *redist) { +static void vgic_redist_reset(struct gic_redist_map *redist) +{ // @ivanv: come back to, right now it's a global so we don't need to init the memory to zero // memset(redist, 0, sizeof(*redist)); redist->typer = 0x11; /* RO */ @@ -204,14 +207,15 @@ vgic_reg_t vgic_regs; void vgic_init() { // @ivanv: audit + // TODO: fix for SMP for (int i = 0; i < NUM_SLOTS_SPI_VIRQ; i++) { vgic.vspis[i].virq = VIRQ_INVALID; } for (int i = 0; i < NUM_VCPU_LOCAL_VIRQS; i++) { - vgic.vgic_vcpu[GUEST_VCPU_ID].local_virqs[i].virq = VIRQ_INVALID; + vgic.vgic_vcpu[GUEST_BOOT_VCPU_ID].local_virqs[i].virq = VIRQ_INVALID; } for (int i = 0; i < NUM_LIST_REGS; i++) { - vgic.vgic_vcpu[GUEST_VCPU_ID].lr_shadow[i].virq = VIRQ_INVALID; + vgic.vgic_vcpu[GUEST_BOOT_VCPU_ID].lr_shadow[i].virq = VIRQ_INVALID; } vgic.registers = &vgic_regs; vgic_regs.dist = &dist; diff --git a/src/arch/aarch64/virq.c b/src/arch/aarch64/virq.c index 96bccc1c..63b4251f 100644 --- a/src/arch/aarch64/virq.c +++ b/src/arch/aarch64/virq.c @@ -24,7 +24,8 @@ static void vppi_event_ack(size_t vcpu_id, int irq, void *cookie) static void sgi_ack(size_t vcpu_id, int irq, void *cookie) {} -bool virq_controller_init(size_t boot_vcpu_id) { +bool virq_controller_init() +{ bool success; vgic_init(); @@ -37,52 +38,63 @@ bool virq_controller_init(size_t boot_vcpu_id) { #endif /* Register the fault handler */ - success = fault_register_vm_exception_handler(GIC_DIST_PADDR, GIC_DIST_SIZE, handle_vgic_dist_fault, NULL); + success = fault_register_vm_exception_handler(GIC_DIST_PADDR, GIC_DIST_SIZE, vgic_handle_fault_dist, NULL); if (!success) { LOG_VMM_ERR("Failed to register fault handler for GIC distributor region\n"); return false; } #if defined(GIC_V3) - success = fault_register_vm_exception_handler(GIC_REDIST_PADDR, GIC_REDIST_SIZE, handle_vgic_redist_fault, NULL); + success = fault_register_vm_exception_handler(GIC_REDIST_PADDR, GIC_REDIST_SIZE, vgic_handle_fault_redist, NULL); if (!success) { LOG_VMM_ERR("Failed to register fault handler for GIC redistributor region\n"); return false; } #endif - success = vgic_register_irq(boot_vcpu_id, PPI_VTIMER_IRQ, &vppi_event_ack, NULL); - if (!success) { - LOG_VMM_ERR("Failed to register vCPU virtual timer IRQ: 0x%lx\n", PPI_VTIMER_IRQ); - return false; - } - success = vgic_register_irq(boot_vcpu_id, SGI_RESCHEDULE_IRQ, &sgi_ack, NULL); - if (!success) { - LOG_VMM_ERR("Failed to register vCPU SGI 0 IRQ"); - return false; - } - success = vgic_register_irq(boot_vcpu_id, SGI_FUNC_CALL, &sgi_ack, NULL); - if (!success) { - LOG_VMM_ERR("Failed to register vCPU SGI 1 IRQ"); - return false; + for (int vcpu = 0; vcpu < GUEST_NUM_VCPUS; vcpu++) { + success = vgic_register_irq(vcpu, PPI_VTIMER_IRQ, &vppi_event_ack, NULL); + if (!success) { + LOG_VMM_ERR("Failed to register vCPU virtual timer IRQ: 0x%lx\n", PPI_VTIMER_IRQ); + return false; + } + success = vgic_register_irq(vcpu, SGI_RESCHEDULE_IRQ, &sgi_ack, NULL); + if (!success) { + LOG_VMM_ERR("Failed to register vCPU SGI 0 IRQ"); + return false; + } + success = vgic_register_irq(vcpu, SGI_FUNC_CALL, &sgi_ack, NULL); + if (!success) { + LOG_VMM_ERR("Failed to register vCPU SGI 1 IRQ"); + return false; + } } return true; } -bool virq_inject(size_t vcpu_id, int irq) { +bool virq_inject_vcpu(size_t vcpu_id, int irq) +{ return vgic_inject_irq(vcpu_id, irq); } -bool virq_register(size_t vcpu_id, size_t virq_num, virq_ack_fn_t ack_fn, void *ack_data) { +bool virq_inject(int irq) +{ + return vgic_inject_irq(GUEST_BOOT_VCPU_ID, irq); +} + +bool virq_register(size_t vcpu_id, size_t virq_num, virq_ack_fn_t ack_fn, void *ack_data) +{ return vgic_register_irq(vcpu_id, virq_num, ack_fn, ack_data); } -static void virq_passthrough_ack(size_t vcpu_id, int irq, void *cookie) { +static void virq_passthrough_ack(size_t vcpu_id, int irq, void *cookie) +{ /* We are down-casting to microkit_channel so must first cast to size_t */ microkit_irq_ack((microkit_channel)(size_t)cookie); } -bool virq_register_passthrough(size_t vcpu_id, size_t irq, microkit_channel irq_ch) { +bool virq_register_passthrough(size_t vcpu_id, size_t irq, microkit_channel irq_ch) +{ assert(irq_ch < MICROKIT_MAX_CHANNELS); if (irq_ch >= MICROKIT_MAX_CHANNELS) { LOG_VMM_ERR("Invalid channel number given '0x%lx' for passthrough vIRQ 0x%lx\n", irq_ch, irq); @@ -92,7 +104,7 @@ bool virq_register_passthrough(size_t vcpu_id, size_t irq, microkit_channel irq_ LOG_VMM("Register passthrough vIRQ 0x%lx on vCPU 0x%lx (IRQ channel: 0x%lx)\n", irq, vcpu_id, irq_ch); virq_passthrough_map[irq_ch] = irq; - bool success = virq_register(GUEST_VCPU_ID, irq, &virq_passthrough_ack, (void *)(size_t)irq_ch); + bool success = virq_register(GUEST_BOOT_VCPU_ID, irq, &virq_passthrough_ack, (void *)(size_t)irq_ch); assert(success); if (!success) { LOG_VMM_ERR("Failed to register passthrough vIRQ %d\n", irq); @@ -102,16 +114,18 @@ bool virq_register_passthrough(size_t vcpu_id, size_t irq, microkit_channel irq_ return true; } -bool virq_handle_passthrough(microkit_channel irq_ch) { +bool virq_handle_passthrough(microkit_channel irq_ch) +{ assert(virq_passthrough_map[irq_ch] >= 0); if (virq_passthrough_map[irq_ch] < 0) { LOG_VMM_ERR("attempted to handle invalid passthrough IRQ channel 0x%lx\n", irq_ch); return false; } - bool success = vgic_inject_irq(GUEST_VCPU_ID, virq_passthrough_map[irq_ch]); + bool success = vgic_inject_irq(GUEST_BOOT_VCPU_ID, virq_passthrough_map[irq_ch]); if (!success) { - LOG_VMM_ERR("could not inject passthrough vIRQ 0x%lx, dropped on vCPU 0x%lx\n", virq_passthrough_map[irq_ch], GUEST_VCPU_ID); + LOG_VMM_ERR("could not inject passthrough vIRQ 0x%lx, dropped on vCPU 0x%lx\n", virq_passthrough_map[irq_ch], + GUEST_BOOT_VCPU_ID); return false; } diff --git a/src/guest.c b/src/guest.c index a3557d07..d43d8a0d 100644 --- a/src/guest.c +++ b/src/guest.c @@ -8,7 +8,8 @@ #include #include -bool guest_start(size_t boot_vcpu_id, uintptr_t kernel_pc, uintptr_t dtb, uintptr_t initrd) { +bool guest_start(uintptr_t kernel_pc, uintptr_t dtb, uintptr_t initrd) +{ /* * Set the TCB registers to what the virtual machine expects to be started with. * You will note that this is currently Linux specific as we currently do not support @@ -21,35 +22,39 @@ bool guest_start(size_t boot_vcpu_id, uintptr_t kernel_pc, uintptr_t dtb, uintpt regs.pc = kernel_pc; /* Write out all the TCB registers */ seL4_Word err = seL4_TCB_WriteRegisters( - BASE_VM_TCB_CAP + boot_vcpu_id, - false, // We'll explcitly start the guest below rather than in this call - 0, // No flags - 4, // Writing to x0, pc, and spsr. Due to the ordering of seL4_UserContext the count must be 4. - ®s - ); + BASE_VM_TCB_CAP + GUEST_BOOT_VCPU_ID, + false, // We'll explcitly start the guest below rather than in this call + 0, // No flags + 4, // Writing to x0, pc, and spsr. Due to the ordering of seL4_UserContext the count must be 4. + ®s + ); assert(err == seL4_NoError); if (err != seL4_NoError) { - LOG_VMM_ERR("Failed to write registers to boot vCPU's TCB (id is 0x%lx), error is: 0x%lx\n", boot_vcpu_id, err); + LOG_VMM_ERR("Failed to write registers to boot vCPU's TCB (id is 0x%lx), error is: 0x%lx\n", GUEST_BOOT_VCPU_ID, err); return false; } LOG_VMM("starting guest at 0x%lx, DTB at 0x%lx, initial RAM disk at 0x%lx\n", - regs.pc, regs.x0, initrd); + regs.pc, regs.x0, initrd); + + vcpu_set_on(GUEST_BOOT_VCPU_ID, true); /* Restart the boot vCPU to the program counter of the TCB associated with it */ - microkit_vcpu_restart(boot_vcpu_id, regs.pc); + microkit_vcpu_restart(GUEST_BOOT_VCPU_ID, regs.pc); return true; } -void guest_stop(size_t boot_vcpu_id) { +void guest_stop() +{ LOG_VMM("Stopping guest\n"); - microkit_vcpu_stop(boot_vcpu_id); + microkit_vcpu_stop(GUEST_BOOT_VCPU_ID); LOG_VMM("Stopped guest\n"); } -bool guest_restart(size_t boot_vcpu_id, uintptr_t guest_ram_vaddr, size_t guest_ram_size) { +bool guest_restart(uintptr_t guest_ram_vaddr, size_t guest_ram_size) +{ LOG_VMM("Attempting to restart guest\n"); // First, stop the guest - microkit_vcpu_stop(boot_vcpu_id); + microkit_vcpu_stop(GUEST_BOOT_VCPU_ID); LOG_VMM("Stopped guest\n"); // Then, we need to clear all of RAM LOG_VMM("Clearing guest RAM\n"); @@ -60,10 +65,10 @@ bool guest_restart(size_t boot_vcpu_id, uintptr_t guest_ram_vaddr, size_t guest_ // LOG_VMM_ERR("Failed to initialise guest images\n"); // return false; // } - vcpu_reset(boot_vcpu_id); + vcpu_reset(GUEST_BOOT_VCPU_ID); // Now we need to re-initialise all the VMM state // vmm_init(); - // linux_start(GUEST_VCPU_ID, kernel_pc, GUEST_DTB_VADDR, GUEST_INIT_RAM_DISK_VADDR); + // linux_start(GUEST_BOOT_VCPU_ID, kernel_pc, GUEST_DTB_VADDR, GUEST_INIT_RAM_DISK_VADDR); LOG_VMM("Restarted guest\n"); return true; } diff --git a/src/virtio/block.c b/src/virtio/block.c index 4844fb74..16077ae9 100644 --- a/src/virtio/block.c +++ b/src/virtio/block.c @@ -136,7 +136,7 @@ static void virtio_blk_used_buffer(struct virtio_device *dev, uint16_t desc) static bool virtio_blk_virq_inject(struct virtio_device *dev) { - return virq_inject(GUEST_VCPU_ID, dev->virq); + return virq_inject(dev->virq); } static void virtio_blk_set_interrupt_status(struct virtio_device *dev, diff --git a/src/virtio/console.c b/src/virtio/console.c index c21311a9..394dceda 100644 --- a/src/virtio/console.c +++ b/src/virtio/console.c @@ -162,7 +162,7 @@ static bool virtio_console_handle_tx(struct virtio_device *dev) * available data. In this case we do not set the IRQ status. */ if (transferred) { dev->data.InterruptStatus = BIT_LOW(0); - bool success = virq_inject(GUEST_VCPU_ID, dev->virq); + bool success = virq_inject(dev->virq); assert(success); if (serial_require_producer_signal(&console->txq)) { @@ -221,7 +221,7 @@ bool virtio_console_handle_rx(struct virtio_console_device *console) * available data. In this case we do not set the IRQ status. */ if (transferred) { console->virtio_device.data.InterruptStatus = BIT_LOW(0); - bool success = virq_inject(GUEST_VCPU_ID, console->virtio_device.virq); + bool success = virq_inject(console->virtio_device.virq); assert(success); return success; diff --git a/src/virtio/mmio.c b/src/virtio/mmio.c index 9362ee7d..f59388f4 100644 --- a/src/virtio/mmio.c +++ b/src/virtio/mmio.c @@ -343,7 +343,7 @@ bool virtio_mmio_register_device(virtio_device_t *dev, /* Register the virtual IRQ that will be used to communicate from the device * to the guest. This assumes that the interrupt controller is already setup. */ // @ivanv: we should check that (on AArch64) the virq is an SPI. - success = virq_register(GUEST_VCPU_ID, virq, &virtio_virq_default_ack, NULL); + success = virq_register(GUEST_BOOT_VCPU_ID, virq, &virtio_virq_default_ack, NULL); assert(success); return success; diff --git a/src/virtio/net.c b/src/virtio/net.c index a47e4c96..c75ae34a 100644 --- a/src/virtio/net.c +++ b/src/virtio/net.c @@ -138,7 +138,7 @@ static void virtq_enqueue_used(struct virtq *virtq, uint32_t desc_head, uint32_t static bool virtio_net_respond(struct virtio_device *dev) { dev->data.InterruptStatus = BIT_LOW(0); - bool success = virq_inject(GUEST_VCPU_ID, dev->virq); + bool success = virq_inject(dev->virq); assert(success); return success; diff --git a/src/virtio/sound.c b/src/virtio/sound.c index a4b1c398..f32f9c0a 100644 --- a/src/virtio/sound.c +++ b/src/virtio/sound.c @@ -147,7 +147,7 @@ static const char *code_to_str(uint32_t code) static void virtio_snd_respond(struct virtio_device *dev) { dev->data.InterruptStatus = BIT_LOW(0); - bool success = virq_inject(GUEST_VCPU_ID, dev->virq); + bool success = virq_inject(dev->virq); assert(success); }