Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
erichchan999 committed Oct 24, 2024
1 parent 8bb4870 commit 4344338
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 63 deletions.
11 changes: 4 additions & 7 deletions examples/virtio/blk_driver_vmm.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <libvmm/virtio/virtio.h>
#include <libvmm/arch/aarch64/linux.h>
#include <libvmm/arch/aarch64/fault.h>
#include <libvmm/uio/uio.h>
#include <sddf/serial/queue.h>
#include <serial_config.h>

Expand Down Expand Up @@ -66,11 +67,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 */
Expand Down Expand Up @@ -120,8 +116,9 @@ 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, 0x47000000, 0x1000);
assert(success);

#if defined(BOARD_odroidc4)
/* Register the SD card IRQ */
Expand Down
16 changes: 16 additions & 0 deletions include/libvmm/uio/uio.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* Copyright 2024, UNSW
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once

#include <microkit.h>
#include <stdint.h>
#include <stdlib.h>

/* This sets up the resources needed by a userspace driver. Includes registering the uio virq and 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 region_base, size_t region_size)
45 changes: 45 additions & 0 deletions src/uio/uio.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@

/*
* Copyright 2024, UNSW
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#include <microkit.h>
#include <libvmm/util/util.h>
#include <libvmm/arch/aarch64/fault.h>
#include <libvmm/virq.h>
#include <stdint.h>
#include <stdlib.h>

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");
assert(false);
} else {
microkit_notify(ch);
}
}

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 region_base, size_t region_size)
{
bool success = virq_register(GUEST_VCPU_ID, irq, uio_ack, NULL);
assert(success);
success = fault_register_vm_exception_handler(region_base,
region_size,
&uio_notify_fault_handle,
&(void *)ch);
if (!success) {
LOG_VMM_ERR("Could not register uio virtual memory fault handler for "
"uio notify region [0x%lx..0x%lx)\n", region_base, region_base + region_size);
return false;
}
return true;
}
12 changes: 10 additions & 2 deletions tools/linux/include/uio/libuio.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,13 @@
*/
#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();

128 changes: 74 additions & 54 deletions tools/linux/uio/libuio.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,20 +57,17 @@ static int curr_map = 0;
*/
__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;
assert(!"UIO driver did not implement driver_init");
return -1;
}

__attribute__((weak)) void driver_notified()
{
assert(!"UIO driver did not implement driver_notified");
assert(!"UIO driver did not implement driver_notified");
}

void uio_notify()
void uio_irq_ack_and_enable()
{
/* Writing 1 to the UIO device ACKs the IRQ (which transfers execution to the
* VMM) and also re-enables the interrupt.
*/
int32_t one = 1;
int ret = write(main_uio_fd, &one, 4);
if (ret < 0) {
Expand All @@ -80,7 +77,44 @@ void uio_notify()
fsync(main_uio_fd);
}

static int uio_num_maps(int uio_num) {
void vmm_notify()
{
int32_t one = 1;
int ret = write(main_uio_fd, &one, 4);
if (ret < 0) {
LOG_UIO_ERR("writing 1 to device failed with ret val: %d, errno: %d\n", ret,
errno);
}
fsync(main_uio_fd);
}

static int create_epoll(void)
{
epoll_fd = epoll_create1(0);
if (epoll_fd == -1) {
LOG_NET_ERR("can't create the epoll fd.\n");
exit(1);
} else {
LOG_NET("created epoll fd %d\n", epoll_fd);
}
return epoll_fd;
}

static void bind_fd_to_epoll(int fd, int epollfd)
{
struct epoll_event sock_event;
sock_event.events = EPOLLIN;
sock_event.data.fd = fd;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &sock_event) == -1) {
LOG_NET_ERR("can't register fd %d to epoll.\n", fd);
exit(1);
} else {
LOG_NET("registered fd %d to epoll\n", fd);
}
}

static int uio_num_maps(int uio_num)
{
DIR *dir;
struct dirent *entry;
struct stat statbuf;
Expand All @@ -91,19 +125,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(&regex, "^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 */
Expand All @@ -114,7 +148,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 */
Expand All @@ -140,7 +174,8 @@ static int uio_num_maps(int uio_num) {
return count;
}

static int uio_map_size(int uio_num, int map_num) {
static int uio_map_size(int uio_num, int map_num)
{
char path[MAX_PATHNAME];
char buf[MAX_PATHNAME];

Expand All @@ -149,31 +184,32 @@ 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];

Expand All @@ -182,43 +218,42 @@ 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;
Expand All @@ -227,36 +262,24 @@ 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,
size, maps[curr_map]);

curr_map++;
}

return 0;
}

int main(int argc, char **argv)
Expand Down Expand Up @@ -292,10 +315,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) {
Expand All @@ -305,16 +325,16 @@ int main(int argc, char **argv)
}

/* Enable uio interrupt on initialisation. */
uio_notify();
uio_irq_ack_and_enable();

/* 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) !=
/* 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 driver specific maps\n", num_maps - 2);
if (driver_init(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) {
Expand Down

0 comments on commit 4344338

Please sign in to comment.