From 9a3fe567884af08a00c92e25a3f72da71fb67235 Mon Sep 17 00:00:00 2001 From: Alan Jian Date: Fri, 14 Jun 2024 14:23:54 +0800 Subject: [PATCH] Add VirtIO driver --- CMakeLists.txt | 1 + include/config.h | 1 + include/drivers/virtio.h | 45 ++++++++++++++ src/dev.c | 4 +- src/drivers/virtio-gpu.c | 129 ++++++++++++++++----------------------- src/drivers/virtio.c | 22 +++++++ src/kmain.c | 5 -- src/log.c | 9 +++ src/platforms/virt.c | 8 +++ 9 files changed, 141 insertions(+), 83 deletions(-) create mode 100644 include/drivers/virtio.h create mode 100644 src/drivers/virtio.c diff --git a/CMakeLists.txt b/CMakeLists.txt index d4fbe16..098adba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,7 @@ add_executable(karg src/drivers/plic.c src/drivers/tty.c src/drivers/uart.c + src/drivers/virtio.c src/drivers/virtio-gpu.c src/entry.S src/init.c diff --git a/include/config.h b/include/config.h index bf0620f..fb4fd45 100644 --- a/include/config.h +++ b/include/config.h @@ -12,3 +12,4 @@ #define SCHED_TIMESLICE 10000000 #define TTY_SINK_CAPACITY 2 #define UART_RX_BUF_SIZE 128 +#define VIRTIO_RING_SIZE 128 diff --git a/include/drivers/virtio.h b/include/drivers/virtio.h new file mode 100644 index 0000000..bd3e9d6 --- /dev/null +++ b/include/drivers/virtio.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include +#include + +#define VIRTIO_DESC_FLAG_NEXT 0x1 +#define VIRTIO_DESC_FLAG_WRITE 0x2 +#define VIRTIO_DESC_FLAG_INDIRECT 0x4 + +typedef struct { + u64 addr; + u32 len; + u16 flags; + u16 next; +} virtio_desc_t; + +typedef struct { + u16 flags; + u16 idx; + u16 ring[VIRTIO_RING_SIZE]; +} virtio_avail_queue_t; + +typedef struct { + u32 id; + u32 len; +} virtio_used_elem_t; + +typedef struct { + u16 flags; + u16 idx; + virtio_used_elem_t ring[VIRTIO_RING_SIZE]; +} virtio_used_queue_t; + +#define FEATURES 0x20 +#define QUEUE_SEL 0x30 +#define QUEUE_NUM 0x38 +#define QUEUE_READY 0x44 +#define NOTIFY 0x50 +#define STATUS 0x70 +#define QUEUE_DESC_LOW 0x80 +#define QUEUE_DRIVER_LOW 0x90 +#define QUEUE_DEVICE_LOW 0xA0 + +i32 init_virtio_gpu(const dev_node_t *node); diff --git a/src/dev.c b/src/dev.c index 70ecdbf..047354d 100644 --- a/src/dev.c +++ b/src/dev.c @@ -36,8 +36,8 @@ static i32 init(void) { init_ptr++) { if (strcmp(init_ptr->compat, node->name) == 0) { i32 res = init_ptr->init(node); - log_info("loaded driver \"%s\" for device \"%s\"", - init_ptr->name, init_ptr->compat); + log_info("loaded driver %s for device %s", init_ptr->name, + init_ptr->compat); if (res < 0) return res; break; diff --git a/src/drivers/virtio-gpu.c b/src/drivers/virtio-gpu.c index d19aa1c..7c5be45 100644 --- a/src/drivers/virtio-gpu.c +++ b/src/drivers/virtio-gpu.c @@ -1,11 +1,13 @@ +#include + +#include #include #include +#include #include #include #include -MODULE_NAME("virtio_gpu"); - enum virtio_gpu_ctrl_type { /* 2d commands */ VIRTIO_GPU_CMD_GET_DISPLAY_INFO = 0x0100, @@ -112,53 +114,23 @@ struct virtio_gpu_transfer_to_host_2d { u32 padding; }; -#define VIRTQ_DESC_F_NEXT 1 -#define VIRTQ_DESC_F_WRITE 2 -#define VIRTQ_DESC_F_INDIRECT 4 +typedef struct { + usize addr; +} ctrl_blk_t; -struct virtq_desc { - u64 addr; - u32 len; - u16 flags; - u16 next; -}; +static ctrl_blk_t ctrl_blks[DRIVER_DEV_CAPACITY]; +static u32 nr_devs = 0; -struct virtq_avail { - u16 flags; - u16 idx; - u16 ring[128]; -}; - -struct virtq_used_elem { - u32 id; - u32 len; -}; - -struct virtq_used { - u16 flags; - u16 idx; - struct virtq_used_elem ring[128]; -}; - -#define REG(reg) *((volatile u32 *) (0x10008000 + (reg))) -#define FEATURES 0x20 -#define QUEUE_SEL 0x30 -#define QUEUE_NUM 0x38 -#define QUEUE_READY 0x44 -#define NOTIFY 0x50 -#define STATUS 0x70 -#define QUEUE_DESC_LOW 0x80 -#define QUEUE_DRIVER_LOW 0x90 -#define QUEUE_DEVICE_LOW 0xA0 +#define REG(num, reg) *((volatile u32 *) (ctrl_blks[num].addr + reg)) #define STATUS_ACK 1 #define STATUS_DRIVER 2 #define STATUS_DRIVER_OK 4 #define STATUS_FEATURES_OK 8 -static struct virtq_desc desc[128]; -static struct virtq_avail avail; -static struct virtq_used used; +static virtio_desc_t desc[128]; +static virtio_avail_queue_t avail; +static virtio_used_queue_t used; static struct virtio_gpu_resource_create_2d create_2d; static struct virtio_gpu_resource_attach_backing attach_backing; @@ -175,7 +147,7 @@ static struct virtio_gpu_ctrl_hdr hdr[5]; static u32 fb[FB_WIDTH * FB_HEIGHT]; static usize offset = 0; -static void flush(u32 y, u32 height) { +static void flush(u32 num, u32 y, u32 height) { while (avail.idx != used.idx) ; transfer.r.x = 0; @@ -191,31 +163,33 @@ static void flush(u32 y, u32 height) { desc[0].addr = (usize) &transfer; desc[0].len = sizeof(transfer); - desc[0].flags = VIRTQ_DESC_F_NEXT; + desc[0].flags = VIRTIO_DESC_FLAG_NEXT; desc[0].next = 1; desc[1].addr = (usize) &hdr[0]; desc[1].len = sizeof(hdr[0]); - desc[1].flags = VIRTQ_DESC_F_WRITE; + desc[1].flags = VIRTIO_DESC_FLAG_WRITE; desc[1].next = 0; desc[2].addr = (usize) &res_flush; desc[2].len = sizeof(res_flush); - desc[2].flags = VIRTQ_DESC_F_NEXT; + desc[2].flags = VIRTIO_DESC_FLAG_NEXT; desc[2].next = 3; desc[3].addr = (usize) &hdr[1]; desc[3].len = sizeof(hdr[1]); - desc[3].flags = VIRTQ_DESC_F_WRITE; + desc[3].flags = VIRTIO_DESC_FLAG_WRITE; desc[3].next = 0; avail.ring[avail.idx++ % 128] = 0; avail.ring[avail.idx++ % 128] = 2; - REG(NOTIFY) = 0; + REG(num, NOTIFY) = 0; } static i32 ioctl(u32 num, u32 req, va_list args) { - (void) num; + if (num >= nr_devs) + return -ENXIO; + switch (req) { case 0: { u32 *width = va_arg(args, u32 *); @@ -234,7 +208,7 @@ static i32 ioctl(u32 num, u32 req, va_list args) { case 2: { u32 y = va_arg(args, u32); u32 height = va_arg(args, u32); - flush(y, height); + flush(num, y, height); break; } } @@ -247,22 +221,27 @@ static driver_t driver = { .ioctl = ioctl, }; -static i32 init(void) { - REG(STATUS) = 0; - REG(STATUS) |= STATUS_ACK; - REG(STATUS) |= STATUS_DRIVER; - REG(FEATURES) = 0; - REG(STATUS) |= STATUS_FEATURES_OK; +i32 init_virtio_gpu(const dev_node_t *node) { + if (nr_devs == DRIVER_DEV_CAPACITY) + return -EAGAIN; + u32 num = nr_devs++; + ctrl_blks[num].addr = node->addr; + + REG(num, STATUS) = 0; + REG(num, STATUS) |= STATUS_ACK; + REG(num, STATUS) |= STATUS_DRIVER; + REG(num, FEATURES) = 0; + REG(num, STATUS) |= STATUS_FEATURES_OK; - REG(QUEUE_SEL) = 0; - REG(QUEUE_NUM) = 128; - REG(QUEUE_DESC_LOW) = (usize) desc; - REG(QUEUE_DRIVER_LOW) = (usize) &avail; - REG(QUEUE_DEVICE_LOW) = (usize) &used; + REG(num, QUEUE_SEL) = 0; + REG(num, QUEUE_NUM) = 128; + REG(num, QUEUE_DESC_LOW) = (usize) desc; + REG(num, QUEUE_DRIVER_LOW) = (usize) &avail; + REG(num, QUEUE_DEVICE_LOW) = (usize) &used; - REG(QUEUE_READY) = 1; + REG(num, QUEUE_READY) = 1; - REG(STATUS) |= STATUS_DRIVER_OK; + REG(num, STATUS) |= STATUS_DRIVER_OK; create_2d.hdr.type = VIRTIO_GPU_CMD_RESOURCE_CREATE_2D; create_2d.hdr.flags = 0; @@ -317,57 +296,57 @@ static i32 init(void) { desc[0].addr = (usize) &create_2d; desc[0].len = sizeof(create_2d); - desc[0].flags = VIRTQ_DESC_F_NEXT; + desc[0].flags = VIRTIO_DESC_FLAG_NEXT; desc[0].next = 1; desc[1].addr = (usize) &hdr[0]; desc[1].len = sizeof(hdr[0]); - desc[1].flags = VIRTQ_DESC_F_WRITE; + desc[1].flags = VIRTIO_DESC_FLAG_WRITE; desc[1].next = 0; desc[2].addr = (usize) &attach_backing; desc[2].len = sizeof(attach_backing); - desc[2].flags = VIRTQ_DESC_F_NEXT; + desc[2].flags = VIRTIO_DESC_FLAG_NEXT; desc[2].next = 3; desc[3].addr = (usize) &gpu_mem_entry; desc[3].len = sizeof(gpu_mem_entry); - desc[3].flags = VIRTQ_DESC_F_NEXT; + desc[3].flags = VIRTIO_DESC_FLAG_NEXT; desc[3].next = 4; desc[4].addr = (usize) &hdr[1]; desc[4].len = sizeof(hdr[1]); - desc[4].flags = VIRTQ_DESC_F_WRITE; + desc[4].flags = VIRTIO_DESC_FLAG_WRITE; desc[4].next = 0; desc[5].addr = (usize) &set_scanout; desc[5].len = sizeof(set_scanout); - desc[5].flags = VIRTQ_DESC_F_NEXT; + desc[5].flags = VIRTIO_DESC_FLAG_NEXT; desc[5].next = 6; desc[6].addr = (usize) &hdr[2]; desc[6].len = sizeof(hdr[2]); - desc[6].flags = VIRTQ_DESC_F_WRITE; + desc[6].flags = VIRTIO_DESC_FLAG_WRITE; desc[6].next = 0; desc[7].addr = (usize) &transfer; desc[7].len = sizeof(transfer); - desc[7].flags = VIRTQ_DESC_F_NEXT; + desc[7].flags = VIRTIO_DESC_FLAG_NEXT; desc[7].next = 8; desc[8].addr = (usize) &hdr[3]; desc[8].len = sizeof(hdr[3]); - desc[8].flags = VIRTQ_DESC_F_WRITE; + desc[8].flags = VIRTIO_DESC_FLAG_WRITE; desc[8].next = 0; desc[9].addr = (usize) &res_flush; desc[9].len = sizeof(res_flush); - desc[9].flags = VIRTQ_DESC_F_NEXT; + desc[9].flags = VIRTIO_DESC_FLAG_NEXT; desc[9].next = 10; desc[10].addr = (usize) &hdr[4]; desc[10].len = sizeof(hdr[4]); - desc[10].flags = VIRTQ_DESC_F_WRITE; + desc[10].flags = VIRTIO_DESC_FLAG_WRITE; desc[10].next = 0; avail.ring[avail.idx++] = 0; @@ -375,7 +354,7 @@ static i32 init(void) { avail.ring[avail.idx++] = 5; avail.ring[avail.idx++] = 7; avail.ring[avail.idx++] = 9; - REG(NOTIFY) = 0; + REG(num, NOTIFY) = 0; dev_t dev = { .driver = &driver, @@ -385,5 +364,3 @@ static i32 init(void) { return 0; } - -module_init(init); diff --git a/src/drivers/virtio.c b/src/drivers/virtio.c new file mode 100644 index 0000000..ebe2248 --- /dev/null +++ b/src/drivers/virtio.c @@ -0,0 +1,22 @@ +#include + +#include +#include +#include + +MODULE_NAME("virtio"); + +#define REG(base, reg) *((volatile u32 *) (base + reg)) +#define DEV_ID 0x8 + +static i32 init_dev(const dev_node_t *node) { + switch (REG(node->addr, DEV_ID)) { + case 16: + init_virtio_gpu(node); + log_info("initialized virtio-gpu at 0x%p", node->addr); + break; + } + return 0; +} + +dev_init("virtio", init_dev); diff --git a/src/kmain.c b/src/kmain.c index 795acaf..87d3a14 100644 --- a/src/kmain.c +++ b/src/kmain.c @@ -1,15 +1,10 @@ #include -#include -#include -#include #include void init(void); static proc_t init_proc; -MODULE_NAME("main"); - [[noreturn]] void kmain(void) { init_modules(); diff --git a/src/log.c b/src/log.c index b2ed615..2d684d5 100644 --- a/src/log.c +++ b/src/log.c @@ -34,6 +34,15 @@ static void kvprintf(const char *fmt, va_list args) { write(str, strlen(str)); break; } + case 'p': { + usize ptr = va_arg(args, usize); + char buf[sizeof(usize) * 2]; + for (isize i = sizeof(buf) - 1; i >= 0; i--) { + buf[i] = ((usize) ptr & 0xF) + '0'; + ptr >>= 4; + } + write(buf, sizeof(buf)); + } } break; default: diff --git a/src/platforms/virt.c b/src/platforms/virt.c index 55588ee..343f596 100644 --- a/src/platforms/virt.c +++ b/src/platforms/virt.c @@ -3,6 +3,14 @@ const dev_node_t DEV_TABLE[] = { {.name = "plic", .addr = 0x0C000000}, {.name = "uart8250", .addr = 0x10000000, .irq = 10, .reg_size = 1}, + {.name = "virtio", .addr = 0x10001000}, + {.name = "virtio", .addr = 0x10002000}, + {.name = "virtio", .addr = 0x10003000}, + {.name = "virtio", .addr = 0x10004000}, + {.name = "virtio", .addr = 0x10005000}, + {.name = "virtio", .addr = 0x10006000}, + {.name = "virtio", .addr = 0x10007000}, + {.name = "virtio", .addr = 0x10008000}, {}, };