Skip to content

Commit

Permalink
Add VirtIO driver
Browse files Browse the repository at this point in the history
  • Loading branch information
alanjian85 committed Jun 15, 2024
1 parent ac76612 commit 9a3fe56
Show file tree
Hide file tree
Showing 9 changed files with 141 additions and 83 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions include/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@
#define SCHED_TIMESLICE 10000000
#define TTY_SINK_CAPACITY 2
#define UART_RX_BUF_SIZE 128
#define VIRTIO_RING_SIZE 128
45 changes: 45 additions & 0 deletions include/drivers/virtio.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#pragma once

#include <config.h>
#include <dev.h>
#include <types.h>

#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);
4 changes: 2 additions & 2 deletions src/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
129 changes: 53 additions & 76 deletions src/drivers/virtio-gpu.c
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
#include <drivers/virtio.h>

#include <config.h>
#include <dev.h>
#include <drivers/fb.h>
#include <errno.h>
#include <init.h>
#include <module.h>
#include <types.h>

MODULE_NAME("virtio_gpu");

enum virtio_gpu_ctrl_type {
/* 2d commands */
VIRTIO_GPU_CMD_GET_DISPLAY_INFO = 0x0100,
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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 *);
Expand All @@ -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;
}
}
Expand All @@ -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;
Expand Down Expand Up @@ -317,65 +296,65 @@ 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;
avail.ring[avail.idx++] = 2;
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,
Expand All @@ -385,5 +364,3 @@ static i32 init(void) {

return 0;
}

module_init(init);
22 changes: 22 additions & 0 deletions src/drivers/virtio.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#include <drivers/virtio.h>

#include <dev.h>
#include <log.h>
#include <module.h>

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);
5 changes: 0 additions & 5 deletions src/kmain.c
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
#include <init.h>
#include <kalloc.h>
#include <log.h>
#include <module.h>
#include <sched.h>

void init(void);

static proc_t init_proc;

MODULE_NAME("main");

[[noreturn]] void kmain(void) {
init_modules();

Expand Down
9 changes: 9 additions & 0 deletions src/log.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Loading

0 comments on commit 9a3fe56

Please sign in to comment.