diff --git a/examples/virtio/blk_driver_vmm.c b/examples/virtio/blk_driver_vmm.c index b1f54f069..7c815b189 100644 --- a/examples/virtio/blk_driver_vmm.c +++ b/examples/virtio/blk_driver_vmm.c @@ -3,17 +3,20 @@ * * SPDX-License-Identifier: BSD-2-Clause */ -#include -#include -#include +#include +#include +#include #include -#include +#include #include +#include #include -#include -#include +#include #include #include +#include +#include +#include #define GUEST_RAM_SIZE 0x6000000 @@ -39,6 +42,12 @@ 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; +/* Passing info from VMM to block uio driver */ +driver_blk_vmm_info_passing_t *driver_blk_vmm_info_passing; +uintptr_t virt_blk_data; +uintptr_t client_vmm_1_blk_data; +uintptr_t client_vmm_2_blk_data; + /* sDDF block */ #define BLOCK_CH 1 #if defined(BOARD_odroidc4) @@ -50,6 +59,11 @@ uintptr_t guest_ram_vaddr; #define UIO_IRQ 50 #define UIO_CH 3 +/* This global is kind of redundant, but for now it's needed to be passed + * through to the uio-vmm notify handler + */ +microkit_channel uio_ch = UIO_CH; + /* Serial */ #define SERIAL_VIRT_TX_CH 4 #define SERIAL_VIRT_RX_CH 5 @@ -66,11 +80,6 @@ char *serial_tx_data; static struct virtio_console_device virtio_console; -void uio_ack(size_t vcpu_id, int irq, void *cookie) -{ - microkit_notify(UIO_CH); -} - void init(void) { /* Initialise the VMM, the VCPU(s), and start the guest */ @@ -120,8 +129,20 @@ void init(void) SERIAL_VIRT_TX_CH); assert(success); - /* Register the UIO IRQ */ - virq_register(GUEST_VCPU_ID, UIO_IRQ, uio_ack, NULL); + /* Register the block uio driver */ + success = uio_register_driver(UIO_IRQ, &uio_ch, 0x80000000, 0x1000); + assert(success); + + /* Populate vmm info passing to block uio driver */ + driver_blk_vmm_info_passing->client_data_phys[0] = virt_blk_data; + driver_blk_vmm_info_passing->client_data_phys[1] = client_vmm_1_blk_data; + driver_blk_vmm_info_passing->client_data_phys[2] = client_vmm_2_blk_data; + driver_blk_vmm_info_passing->client_data_size[0] = + BLK_DATA_REGION_SIZE_DRIV; + driver_blk_vmm_info_passing->client_data_size[1] = + BLK_DATA_REGION_SIZE_CLI0; + driver_blk_vmm_info_passing->client_data_size[2] = + BLK_DATA_REGION_SIZE_CLI1; #if defined(BOARD_odroidc4) /* Register the SD card IRQ */ diff --git a/examples/virtio/board/odroidc4/blk_driver_vm/dts/overlays/io.dts b/examples/virtio/board/odroidc4/blk_driver_vm/dts/overlays/io.dts index d83311641..611cd6def 100644 --- a/examples/virtio/board/odroidc4/blk_driver_vm/dts/overlays/io.dts +++ b/examples/virtio/board/odroidc4/blk_driver_vm/dts/overlays/io.dts @@ -17,7 +17,7 @@ 0x00 0x80000000 0x00 0x1000 0x00 0x80200000 0x00 0x200000 0x00 0x80400000 0x00 0x200000 - 0x00 0x60600000 0x00 0x200000 + 0x00 0x80600000 0x00 0x200000 >; interrupts = <0x00 18 0x04>; // IRQ = 50 @@ -27,8 +27,10 @@ uio1 { compatible = "generic-uio\0uio"; reg = < - 0x00 0x60800000 0x00 0x200000 - 0x00 0x60a00000 0x00 0x200000 + 0x00 0x80800000 0x00 0x200000 + 0x00 0x80a00000 0x00 0x200000 + 0x00 0x80c00000 0x00 0x200000 + 0x00 0x80e00000 0x00 0x200000 >; interrupts = <0x00 19 0x04>; // IRQ = 51 diff --git a/examples/virtio/board/odroidc4/virtio.system b/examples/virtio/board/odroidc4/virtio.system index 3ded57b1d..cd5d0fee7 100644 --- a/examples/virtio/board/odroidc4/virtio.system +++ b/examples/virtio/board/odroidc4/virtio.system @@ -168,20 +168,21 @@ - + - + - + - - + + + @@ -192,6 +193,11 @@ + + + + + @@ -206,16 +212,17 @@ + + + + - - - - - - - - - + + + + + + diff --git a/examples/virtio/board/qemu_virt_aarch64/blk_driver_vm/dts/overlays/io.dts b/examples/virtio/board/qemu_virt_aarch64/blk_driver_vm/dts/overlays/io.dts index d48b9ae83..84aa84202 100644 --- a/examples/virtio/board/qemu_virt_aarch64/blk_driver_vm/dts/overlays/io.dts +++ b/examples/virtio/board/qemu_virt_aarch64/blk_driver_vm/dts/overlays/io.dts @@ -15,7 +15,7 @@ reg = < 0x00 0x79800000 0x00 0x1000 0x00 0x80000000 0x00 0x1000 - 0x00 0x80200000 0x00 0x200000 + 0x00 0x80200000 0x00 0X1000 0x00 0x80400000 0x00 0x200000 0x00 0x80600000 0x00 0x200000 >; @@ -29,6 +29,8 @@ reg = < 0x00 0x80800000 0x00 0x200000 0x00 0x80a00000 0x00 0x200000 + 0x00 0x80c00000 0x00 0x200000 + 0x00 0x80e00000 0x00 0x200000 >; interrupts = <0x00 19 0x04>; // IRQ = 51 diff --git a/examples/virtio/board/qemu_virt_aarch64/virtio.system b/examples/virtio/board/qemu_virt_aarch64/virtio.system index 64d3aeb5d..6b067b428 100644 --- a/examples/virtio/board/qemu_virt_aarch64/virtio.system +++ b/examples/virtio/board/qemu_virt_aarch64/virtio.system @@ -167,20 +167,21 @@ - + - + - + - - + + + @@ -191,6 +192,11 @@ + + + + + @@ -199,16 +205,17 @@ + + + + - - - - - - - - - + + + + + + diff --git a/examples/virtio/virtio.mk b/examples/virtio/virtio.mk index 290d15d2b..8c6404310 100644 --- a/examples/virtio/virtio.mk +++ b/examples/virtio/virtio.mk @@ -37,6 +37,7 @@ CFLAGS := \ -I$(BOARD_DIR)/include \ -I$(SDDF)/include \ -I$(LIBVMM)/include \ + -I$(LIBVMM)/tools/linux/include \ -I$(VIRTIO_EXAMPLE)/include \ -I$(SDDF)/$(LWIPDIR)/include \ -I$(SDDF)/$(LWIPDIR)/include/ipv4 \ diff --git a/include/libvmm/uio/uio.h b/include/libvmm/uio/uio.h new file mode 100644 index 000000000..7f099a2cb --- /dev/null +++ b/include/libvmm/uio/uio.h @@ -0,0 +1,18 @@ +/* + * Copyright 2024, UNSW + * + * SPDX-License-Identifier: BSD-2-Clause + */ +#pragma once + +#include +#include + +/* This sets up the resources needed by a userspace driver. Includes registering + * the uio virq and vmm notify region. The uio driver will write into the notify + * region in order to transfer execution to the VMM for it to then notify other + * microkit components. + */ +bool uio_register_driver(int irq, microkit_channel *ch, + uintptr_t notify_region_base, + size_t notify_region_size); diff --git a/src/uio/uio.c b/src/uio/uio.c new file mode 100644 index 000000000..904254f16 --- /dev/null +++ b/src/uio/uio.c @@ -0,0 +1,46 @@ + +/* + * Copyright 2024, UNSW + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include + +bool uio_notify_fault_handle(size_t vcpu_id, size_t offset, size_t fsr, + seL4_UserContext *regs, void *data) { + microkit_channel ch = *(microkit_channel *)data; + if (fault_is_read(fsr)) { + LOG_VMM_ERR( + "Read into VMM notify region, but uio driver should never do that\n"); + return false; + } else { + microkit_notify(ch); + } + return true; +} + +void uio_ack(size_t vcpu_id, int irq, void *cookie) { + /* Do nothing for UIO ack */ +} + +bool uio_register_driver(int irq, microkit_channel *ch, + uintptr_t notify_region_base, + size_t notify_region_size) { + bool success = virq_register(GUEST_VCPU_ID, irq, uio_ack, NULL); + assert(success); + success = fault_register_vm_exception_handler( + notify_region_base, notify_region_size, &uio_notify_fault_handle, ch); + if (!success) { + LOG_VMM_ERR("Could not register uio virtual memory fault handler for " + "uio notify region [0x%lx..0x%lx)\n", + notify_region_base, notify_region_base + notify_region_size); + return false; + } + return true; +} diff --git a/tools/linux/include/uio/blk.h b/tools/linux/include/uio/blk.h index 22669b658..eda046dcf 100644 --- a/tools/linux/include/uio/blk.h +++ b/tools/linux/include/uio/blk.h @@ -5,7 +5,16 @@ */ #pragma once +#include #include -int driver_init(void **maps, uintptr_t *maps_phys, int num_maps, int argc, char **argv); -void driver_notified(); +#define MAX_BLK_CLIENTS 64 + +typedef struct driver_blk_vmm_info_passing { + uintptr_t client_data_phys[MAX_BLK_CLIENTS]; + size_t client_data_size[MAX_BLK_CLIENTS]; +} driver_blk_vmm_info_passing_t; + +int driver_init(int uio_fd, void **maps, uintptr_t *maps_phys, int num_maps, + int argc, char **argv); +void driver_notified(int *events_fd, int num_events); diff --git a/tools/linux/include/uio/libuio.h b/tools/linux/include/uio/libuio.h index 1ed58d6e5..2cc40a0de 100644 --- a/tools/linux/include/uio/libuio.h +++ b/tools/linux/include/uio/libuio.h @@ -5,5 +5,15 @@ */ #pragma once -/* Notify the VMM */ -void uio_notify(); +/* Notify the VMM by writing into a registered + * memory region thereby invoking a hyp trap. + */ +void vmm_notify(); + +/* Writing 1 to the UIO device ACKs the IRQ and + * also re-enables the interrupt. + */ +void uio_irq_ack_and_enable(); + +/* Drivers can add their own events to the uio event loop */ +void bind_fd_to_epoll(int fd); diff --git a/tools/linux/uio/libuio.c b/tools/linux/uio/libuio.c index b9eb167c9..8ea908ee3 100644 --- a/tools/linux/uio/libuio.c +++ b/tools/linux/uio/libuio.c @@ -17,9 +17,10 @@ #include #include -#include -#include +#include #include +#include +#include #include @@ -45,6 +46,11 @@ #define UIO_MAX_MAPS 32 #define UIO_MAX_DEV 16 +#define MAX_EVENTS 16 + +#define UIO_IRQ_MAP 0 +#define VMM_NOTIFY_MAP 1 + static int main_uio_fd; static void *maps[UIO_MAX_MAPS]; static uintptr_t maps_phys[UIO_MAX_MAPS]; @@ -52,25 +58,23 @@ static int num_maps; static int curr_map = 0; +static int epoll_fd = -1; + /* * Just happily abort if the user can't be bother to provide these functions */ -__attribute__((weak)) int driver_init(void **maps, uintptr_t *maps_phys, int num_maps, int argc, char **argv) -{ - assert(!"UIO driver did not implement driver_init"); - return -1; +__attribute__((weak)) int driver_init(int uio_fd, void **maps, + uintptr_t *maps_phys, int num_maps, + int argc, char **argv) { + assert(!"UIO driver did not implement driver_init"); + return -1; } -__attribute__((weak)) void driver_notified() -{ - assert(!"UIO driver did not implement driver_notified"); +__attribute__((weak)) void driver_notified(int *event_fds, int num_events) { + assert(!"UIO driver did not implement driver_notified"); } -void uio_notify() -{ - /* Writing 1 to the UIO device ACKs the IRQ (which transfers execution to the - * VMM) and also re-enables the interrupt. - */ +void uio_irq_ack_and_enable() { int32_t one = 1; int ret = write(main_uio_fd, &one, 4); if (ret < 0) { @@ -80,6 +84,34 @@ void uio_notify() fsync(main_uio_fd); } +void vmm_notify() { + *(uint8_t *)maps[VMM_NOTIFY_MAP] = 1; + msync(maps[VMM_NOTIFY_MAP], 1, MS_ASYNC); +} + +void bind_fd_to_epoll(int fd) { + struct epoll_event sock_event; + sock_event.events = EPOLLIN; + sock_event.data.fd = fd; + if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &sock_event) == -1) { + LOG_UIO_ERR("can't register fd %d to epoll.\n", fd); + exit(1); + } else { + LOG_UIO("registered fd %d to epoll\n", fd); + } +} + +static int create_epoll(void) { + int epoll_fd = epoll_create1(0); + if (epoll_fd == -1) { + LOG_UIO_ERR("can't create the epoll fd.\n"); + exit(1); + } else { + LOG_UIO("created epoll fd %d\n", epoll_fd); + } + return epoll_fd; +} + static int uio_num_maps(int uio_num) { DIR *dir; struct dirent *entry; @@ -91,19 +123,19 @@ static int uio_num_maps(int uio_num) { int len = snprintf(path, sizeof(path), "/sys/class/uio/uio%d/maps", uio_num); if (len < 0 || len >= sizeof(path)) { LOG_UIO_ERR("Failed to create maps path string\n"); - return -1; + exit(1); } /* Compile regex that searches for maps */ if (regcomp(®ex, "^map[0-9]+$", REG_EXTENDED) != 0) { LOG_UIO_ERR("Could not compile regex\n"); - return -1; + exit(1); } dir = opendir(path); if (dir == NULL) { LOG_UIO_ERR("Failed to open uio maps directory\n"); - return -1; + exit(1); } /* Read directory entries */ @@ -114,7 +146,7 @@ static int uio_num_maps(int uio_num) { snprintf(fullPath, sizeof(fullPath), "%s/%s", path, entry->d_name); if (len < 0 || len >= sizeof(fullPath)) { LOG_UIO_ERR("Failed to create full uio maps path\n"); - return -1; + exit(1); }; /* Check if entry is a directory */ @@ -149,31 +181,31 @@ static int uio_map_size(int uio_num, int map_num) { if (len < 0 || len >= sizeof(path)) { LOG_UIO_ERR("Failed to create uio%d map%d size path string\n", uio_num, map_num); - return -1; + exit(1); } int fd = open(path, O_RDONLY); if (fd < 0) { LOG_UIO_ERR("Failed to open %s\n", path); - return -1; + exit(1); } ssize_t ret = read(fd, buf, sizeof(buf)); if (ret < 0) { LOG_UIO_ERR("Failed to read map%d size\n", map_num); - return -1; + exit(1); } close(fd); int size = strtoul(buf, NULL, 0); if (size == 0 || size == ULONG_MAX) { LOG_UIO_ERR("Failed to convert map%d size to integer\n", map_num); - return -1; + exit(1); } return size; } -static int uio_map_addr(int uio_num, int map_num, uintptr_t *addr) { +static uintptr_t uio_map_addr(int uio_num, int map_num) { char path[MAX_PATHNAME]; char buf[MAX_PATHNAME]; @@ -182,43 +214,41 @@ static int uio_map_addr(int uio_num, int map_num, uintptr_t *addr) { if (len < 0 || len >= sizeof(path)) { LOG_UIO_ERR("Failed to create uio%d map%d addr path string\n", uio_num, map_num); - return -1; + exit(1); } int fd = open(path, O_RDONLY); if (fd < 0) { LOG_UIO_ERR("Failed to open %s\n", path); - return -1; + exit(1); } ssize_t ret = read(fd, buf, sizeof(buf)); if (ret < 0) { LOG_UIO_ERR("Failed to read map%d addr\n", map_num); - return -1; + exit(1); } close(fd); uintptr_t ret_addr = strtoul(buf, NULL, 0); if (ret_addr == 0 || ret_addr == ULONG_MAX) { LOG_UIO_ERR("Failed to convert map%d addr to integer\n", map_num); - return -1; + exit(1); } - *addr = ret_addr; - - return 0; + return ret_addr; } -static int uio_map_init(int uio_fd, int uio_num) { +static void uio_map_init(int uio_fd, int uio_num) { LOG_UIO("Initialising UIO device %d mappings\n", uio_num); int curr_num_maps = uio_num_maps(uio_num); if (curr_num_maps < 0) { LOG_UIO_ERR("Failed to get number of maps\n"); - return -1; + exit(1); } if (curr_num_maps == 0) { LOG_UIO_ERR("No maps found\n"); - return -1; + exit(1); } num_maps += curr_num_maps; @@ -227,27 +257,17 @@ static int uio_map_init(int uio_fd, int uio_num) { if (curr_map >= UIO_MAX_MAPS) { LOG_UIO_ERR("too many maps, maximum is %d\n", UIO_MAX_MAPS); close(uio_fd); - return -1; + exit(1); } int size = uio_map_size(uio_num, i); - if (size < 0) { - LOG_UIO_ERR("Failed to get size of map%d\n", i); - close(uio_fd); - return -1; - } - - if (uio_map_addr(uio_num, i, &maps_phys[curr_map]) != 0) { - LOG_UIO_ERR("Failed to get addr of map%d\n", i); - close(uio_fd); - return -1; - } + maps_phys[curr_map] = uio_map_addr(uio_num, i); if ((maps[curr_map] = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, uio_fd, i * getpagesize())) == NULL) { LOG_UIO_ERR("mmap failed, errno: %d\n", errno); close(uio_fd); - return -1; + exit(1); } LOG_UIO("mmaped map%d (driver map%d) with 0x%x bytes at %p\n", i, curr_map, @@ -255,8 +275,6 @@ static int uio_map_init(int uio_fd, int uio_num) { curr_map++; } - - return 0; } int main(int argc, char **argv) @@ -292,10 +310,7 @@ int main(int argc, char **argv) /* Initialise uio device mappings. This reads into /sys/class/uio to * determine the number of associated devices, their maps and their sizes. */ - if (uio_map_init(uio_fd, uio_num) != 0) { - LOG_UIO_ERR("Failed to initialise UIO device mappings\n"); - return 1; - } + uio_map_init(uio_fd, uio_num); /* Set /dev/uio0 as the interrupt */ if (uio_num == MAIN_UIO_NUM) { @@ -304,30 +319,48 @@ int main(int argc, char **argv) } } - /* Enable uio interrupt on initialisation. */ - uio_notify(); + /* Initialise epoll, bind uio fd to it */ + epoll_fd = create_epoll(); + bind_fd_to_epoll(main_uio_fd); - /* Initialise driver */ - /* We pass the UIO device mappings to the driver, skipping the first one which - * only contains UIO's irq status */ - LOG_UIO("Initialising driver with %d maps\n", num_maps - 1); - if (driver_init(maps + 1, maps_phys + 1, num_maps - 1, argc - 1, argv + 1) != - 0) { + /* Initialise driver, we pass the UIO device mappings to the driver, + * skipping the first one which only contains UIO's irq status, and + * the second one which contains the uio notify region. + */ + LOG_UIO("Initialising driver with %d driver specific maps\n", num_maps - 2); + if (driver_init(main_uio_fd, maps + 2, maps_phys + 2, num_maps - 2, argc - 1, + argv + 1) != 0) { LOG_UIO_ERR("Failed to initialise driver\n"); - return 1; + exit(1); } - while (true) { - int irq_count; - int read_ret = read(main_uio_fd, &irq_count, sizeof(irq_count)); - _unused(read_ret); - assert(read_ret >= 0); - LOG_UIO("received irq, count: %d\n", irq_count); + /* Enable uio interrupt */ + uio_irq_ack_and_enable(); - /* wake the guest driver up to do some real works */ - driver_notified(); + struct epoll_event events[MAX_EVENTS]; + int event_fds[MAX_EVENTS]; + while (true) { + int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1); + if (nfds == -1) { + LOG_UIO_ERR("epoll_wait failed, errno: %d\n", errno); + exit(1); } - return 0; + for (int n = 0; n < nfds; n++) { + event_fds[n] = events[n].data.fd; + if (event_fds[n] == main_uio_fd) { + int irq_count; + int read_ret = read(main_uio_fd, &irq_count, sizeof(irq_count)); + _unused(read_ret); + assert(read_ret >= 0); + LOG_UIO("received irq, count: %d\n", irq_count); + } + } + + /* wake the guest driver up to do some real works */ + driver_notified(event_fds, nfds); + } + + return 0; } diff --git a/tools/linux/uio_drivers/blk/blk.c b/tools/linux/uio_drivers/blk/blk.c index 58ce83a08..e70c5c225 100644 --- a/tools/linux/uio_drivers/blk/blk.c +++ b/tools/linux/uio_drivers/blk/blk.c @@ -4,9 +4,11 @@ * SPDX-License-Identifier: BSD-2-Clause */ #include +#include #include #include #include +#include #include #include #include @@ -14,13 +16,9 @@ #include #include #include -#include - -#include -#include - -#include #include +#include +#include /* Uncomment this to enable debug logging */ // #define DEBUG_UIO_BLOCK @@ -46,120 +44,129 @@ int storage_fd; blk_storage_info_t *blk_storage_info; blk_queue_handle_t h; -uintptr_t blk_virt_data; -uintptr_t blk_virt_data_phys; -uintptr_t blk_client_data[BLK_NUM_CLIENTS]; -uintptr_t blk_client_data_phys[BLK_NUM_CLIENTS]; - -int driver_init(void **maps, uintptr_t *maps_phys, int num_maps, int argc, char **argv) -{ - LOG_UIO_BLOCK("Initialising...\n"); - - /* Expects a storage_info map, request queue map, response queue map, virt - * data map, and BLK_NUM_CLIENT data mappings. - */ - if (num_maps != BLK_NUM_CLIENTS + 4) { - LOG_UIO_BLOCK_ERR("Expecting %d maps, got %d\n", BLK_NUM_CLIENTS + 4, - num_maps); - return -1; - } - - if (argc != 1) { - LOG_UIO_BLOCK_ERR("Expecting 1 driver argument, got %d\n", argc); - return -1; - } - - char *storage_path = argv[0]; +uintptr_t blk_client_data[BLK_NUM_CLIENTS + 1]; +uintptr_t blk_client_data_phys[BLK_NUM_CLIENTS + 1]; +size_t blk_client_data_size[BLK_NUM_CLIENTS + 1]; + +int driver_init(int uio_fd, void **maps, uintptr_t *maps_phys, int num_maps, + int argc, char **argv) { + LOG_UIO_BLOCK("Initialising...\n"); + + /* Expects a storage_info map, request queue map, response queue map, virt + * data map, and BLK_NUM_CLIENT data mappings. + */ + if (num_maps != BLK_NUM_CLIENTS + 5) { + LOG_UIO_BLOCK_ERR("Expecting %d maps, got %d\n", BLK_NUM_CLIENTS + 5, + num_maps); + return -1; + } - blk_storage_info = (blk_storage_info_t *)maps[0]; - blk_req_queue_t *req_queue = (blk_req_queue_t *)maps[1]; - blk_resp_queue_t *resp_queue = (blk_resp_queue_t *)maps[2]; - blk_virt_data = (uintptr_t)maps[3]; - blk_virt_data_phys = (uintptr_t)maps_phys[3]; + if (argc != 1) { + LOG_UIO_BLOCK_ERR("Expecting 1 driver argument, got %d\n", argc); + return -1; + } - LOG_UIO_BLOCK( - "Storage info phys addr: 0x%lx, Request queue phys addr: 0x%lx, " - "Response queue phys addr: 0x%lx, Virt data io addr: 0x%lx\n", - maps_phys[0], maps_phys[1], maps_phys[2], maps_phys[3]); + char *storage_path = argv[0]; + + driver_blk_vmm_info_passing_t *vmm_info_passing = + (driver_blk_vmm_info_passing_t *)maps[0]; + blk_storage_info = (blk_storage_info_t *)maps[1]; + blk_req_queue_t *req_queue = (blk_req_queue_t *)maps[2]; + blk_resp_queue_t *resp_queue = (blk_resp_queue_t *)maps[3]; + for (int i = 0; i < BLK_NUM_CLIENTS + 1; i++) { + blk_client_data[i] = (uintptr_t)maps[4 + i]; + blk_client_data_phys[i] = vmm_info_passing->client_data_phys[i]; + blk_client_data_size[i] = vmm_info_passing->client_data_size[i]; + } - for (int i = 0; i < BLK_NUM_CLIENTS; i++) { - blk_client_data[i] = (uintptr_t)maps[4 + i]; - blk_client_data_phys[i] = (uintptr_t)maps_phys[4 + i]; - } + LOG_UIO_BLOCK( + "Storage info phys addr: 0x%lx, Request queue phys addr: 0x%lx, " + "Response queue phys addr: 0x%lx\n", + maps_phys[1], maps_phys[2], maps_phys[3]); #ifdef DEBUG_UIO_BLOCK - LOG_UIO_BLOCK("Client data io addr:\n"); - for (int i = 0; i < BLK_NUM_CLIENTS; i++) { - printf(" client %i: 0x%lx\n", i, blk_client_data_phys[i]); - } + LOG_UIO_BLOCK("Virt data io addr, Virt data size:\n"); + printf(" 0x%lx, 0x%lx\n", blk_client_data_phys[0], + blk_client_data_size[0]); + LOG_UIO_BLOCK("Client data io addr, Client data size:\n"); + for (int i = 1; i < BLK_NUM_CLIENTS + 1; i++) { + printf(" client %i: 0x%lx, 0x%lx\n", i, blk_client_data_phys[i], + blk_client_data_size[i]); + } #endif - blk_queue_init(&h, req_queue, resp_queue, BLK_QUEUE_CAPACITY_DRIV); - printf("storage_path: %s\n", storage_path); - storage_fd = open(storage_path, O_RDWR); - if (storage_fd < 0) { - LOG_UIO_BLOCK_ERR("Failed to open storage driver: %s\n", strerror(errno)); - return -1; - } - LOG_UIO_BLOCK("Opened storage drive: %s\n", storage_path); + blk_queue_init(&h, req_queue, resp_queue, BLK_QUEUE_CAPACITY_DRIV); - struct stat storageStat; - if (fstat(storage_fd, &storageStat) < 0) { - LOG_UIO_BLOCK_ERR("Failed to get storage drive status: %s\n", strerror(errno)); - return -1; - } - - if (!S_ISBLK(storageStat.st_mode)) { - LOG_UIO_BLOCK_ERR("Storage drive is of an unsupported type\n"); - return -1; - } + storage_fd = open(storage_path, O_RDWR); + if (storage_fd < 0) { + LOG_UIO_BLOCK_ERR("Failed to open storage driver: %s\n", strerror(errno)); + return -1; + } + LOG_UIO_BLOCK("Opened storage drive: %s\n", storage_path); - /* Set drive as read-write */ - int read_only_set = 0; - if (ioctl(storage_fd, BLKROSET, &read_only_set) == -1) { - LOG_UIO_BLOCK_ERR("Failed to set storage drive as read-write: %s\n", strerror(errno)); - return -1; - } + struct stat storageStat; + if (fstat(storage_fd, &storageStat) < 0) { + LOG_UIO_BLOCK_ERR("Failed to get storage drive status: %s\n", + strerror(errno)); + return -1; + } - /* Get read only status */ - int read_only; - if (ioctl(storage_fd, BLKROGET, &read_only) == -1) { - LOG_UIO_BLOCK_ERR("Failed to get storage drive read only status: %s\n", strerror(errno)); - return -1; - } - blk_storage_info->read_only = (bool)read_only; + if (!S_ISBLK(storageStat.st_mode)) { + LOG_UIO_BLOCK_ERR("Storage drive is of an unsupported type\n"); + return -1; + } - /* Get logical sector size */ - int sector_size; - if (ioctl(storage_fd, BLKSSZGET, §or_size) == -1) { - LOG_UIO_BLOCK_ERR("Failed to get storage drive sector size: %s\n", strerror(errno)); - return -1; - } - blk_storage_info->sector_size = (uint16_t)sector_size; + /* Set drive as read-write */ + int read_only_set = 0; + if (ioctl(storage_fd, BLKROSET, &read_only_set) == -1) { + LOG_UIO_BLOCK_ERR("Failed to set storage drive as read-write: %s\n", + strerror(errno)); + return -1; + } - /* Get size */ - uint64_t size; - if (ioctl(storage_fd, BLKGETSIZE64, &size) == -1) { - LOG_UIO_BLOCK_ERR("Failed to get storage drive size: %s\n", strerror(errno)); - return -1; - } - blk_storage_info->capacity = size / BLK_TRANSFER_SIZE; + /* Get read only status */ + int read_only; + if (ioctl(storage_fd, BLKROGET, &read_only) == -1) { + LOG_UIO_BLOCK_ERR("Failed to get storage drive read only status: %s\n", + strerror(errno)); + return -1; + } + blk_storage_info->read_only = (bool)read_only; + + /* Get logical sector size */ + int sector_size; + if (ioctl(storage_fd, BLKSSZGET, §or_size) == -1) { + LOG_UIO_BLOCK_ERR("Failed to get storage drive sector size: %s\n", + strerror(errno)); + return -1; + } + blk_storage_info->sector_size = (uint16_t)sector_size; + + /* Get size */ + uint64_t size; + if (ioctl(storage_fd, BLKGETSIZE64, &size) == -1) { + LOG_UIO_BLOCK_ERR("Failed to get storage drive size: %s\n", + strerror(errno)); + return -1; + } + blk_storage_info->capacity = size / BLK_TRANSFER_SIZE; - LOG_UIO_BLOCK("Raw block device: read_only=%d, sector_size=%d, " - "capacity(sectors)=%ld\n", - (int)blk_storage_info->read_only, - blk_storage_info->sector_size, blk_storage_info->capacity); + LOG_UIO_BLOCK("Raw block device: read_only=%d, sector_size=%d, " + "capacity(sectors)=%ld\n", + (int)blk_storage_info->read_only, blk_storage_info->sector_size, + blk_storage_info->capacity); - /* Optimal size */ - /* As far as I know linux does not let you query this from userspace, set as 0 to mean undefined */ - blk_storage_info->block_size = 0; + /* Optimal size */ + /* As far as I know linux does not let you query this from userspace, set as 0 + * to mean undefined */ + blk_storage_info->block_size = 0; - /* Driver is ready to go, set ready in shared storage info page */ - __atomic_store_n(&blk_storage_info->ready, true, __ATOMIC_RELEASE); + /* Driver is ready to go, set ready in shared storage info page */ + __atomic_store_n(&blk_storage_info->ready, true, __ATOMIC_RELEASE); - LOG_UIO_BLOCK("Driver initialized\n"); + LOG_UIO_BLOCK("Driver initialized\n"); - return 0; + return 0; } /* The virtualiser gives us an io address. We need to figure out which uio @@ -167,21 +174,18 @@ int driver_init(void **maps, uintptr_t *maps_phys, int num_maps, int argc, char * virt address. */ static inline uintptr_t io_to_virt(uintptr_t io_addr) { - if (io_addr - blk_virt_data_phys < BLK_DATA_REGION_SIZE_DRIV) { - return blk_virt_data + (io_addr - blk_virt_data_phys); - } else { - for (int i = 0; i < BLK_NUM_CLIENTS; i++) { - if (io_addr - blk_client_data_phys[i] < - blk_virt_cli_data_region_size(i)) { - return blk_client_data[i] + (io_addr - blk_client_data_phys[i]); - } + for (int i = 0; i < BLK_NUM_CLIENTS + 1; i++) { + if (io_addr - blk_client_data_phys[i] < blk_client_data_size[i]) { + LOG_UIO_BLOCK("io address 0x%lx corresponds to client %d\n", io_addr, i); + return blk_client_data[i] + (io_addr - blk_client_data_phys[i]); } } + /* Didn't find a match */ assert(false); return 0; } -void driver_notified() { +void driver_notified(int *events_fds, int num_events) { int err = 0; _unused(err); blk_req_code_t req_code; @@ -211,7 +215,7 @@ void driver_notified() { success_count = 0; break; } - LOG_UIO_BLOCK("Reading from storage, io address: 0x%lx\n", req_io); + LOG_UIO_BLOCK("Reading from storage\n"); int bytes_read = read(storage_fd, (void *)io_to_virt(req_io), req_count * BLK_TRANSFER_SIZE); @@ -235,7 +239,7 @@ void driver_notified() { success_count = 0; break; } - LOG_UIO_BLOCK("Writing to storage, io address: 0x%lx\n", req_io); + LOG_UIO_BLOCK("Writing to storage\n"); int bytes_written = write(storage_fd, (void *)io_to_virt(req_io), req_count * BLK_TRANSFER_SIZE); LOG_UIO_BLOCK("Wrote to storage successfully: %d bytes\n", bytes_written); @@ -281,6 +285,7 @@ void driver_notified() { status, success_count, req_id); } - uio_notify(); + uio_irq_ack_and_enable(); + vmm_notify(); LOG_UIO_BLOCK("Notified other side\n"); } diff --git a/vmm.mk b/vmm.mk index ea1051b95..32192f114 100644 --- a/vmm.mk +++ b/vmm.mk @@ -49,7 +49,8 @@ ARCH_INDEP_FILES := src/util/printf.c \ src/virtio/mmio.c \ src/virtio/net.c \ src/virtio/sound.c \ - src/guest.c + src/guest.c \ + src/uio/uio.c \ CFILES := ${AARCH64_FILES} ${ARCH_INDEP_FILES} OBJECTS := $(subst src,libvmm,${CFILES:.c=.o}) @@ -72,6 +73,7 @@ libvmm/arch/aarch64/vgic: mkdir -p libvmm/arch/aarch64/vgic/ mkdir -p libvmm/util mkdir -p libvmm/virtio + mkdir -p libvmm/uio libvmm.a: ${OBJECTS} ar rv $@ $^ @@ -91,3 +93,4 @@ clobber:: clean rmdir src/arch/aarch64/vgic rmdir src/util rmdir src/virtio + rmdir src/uio