Skip to content

Commit

Permalink
Implement virtio-gpu device
Browse files Browse the repository at this point in the history
  • Loading branch information
shengwen-tw committed Jun 18, 2024
1 parent 03f5acb commit 1120c97
Show file tree
Hide file tree
Showing 10 changed files with 1,570 additions and 2 deletions.
31 changes: 31 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ include mk/common.mk
CC ?= gcc
CFLAGS := -O2 -g -Wall -Wextra
CFLAGS += -include common.h
LDFLAGS :=

OBJS_EXTRA :=
# command line option
OPTS :=

LDFLAGS += -lpthread

# virtio-blk
ENABLE_VIRTIOBLK ?= 1
$(call set-feature, VIRTIOBLK)
Expand Down Expand Up @@ -36,6 +39,34 @@ ifeq ($(call has, VIRTIONET), 1)
OBJS_EXTRA += virtio-net.o
endif

# virtio-gpu
ENABLE_VIRTIOGPU ?= 1
ifneq ($(UNAME_S),Linux)
ENABLE_VIRTIOGPU := 0
endif

# SDL2
ENABLE_SDL ?= 1
ifeq (, $(shell which sdl2-config))
$(warning No sdl2-config in $$PATH. Check SDL2 installation in advance)
override ENABLE_SDL := 0
endif

ifeq ($(ENABLE_SDL),0)
override ENABLE_VIRTIOGPU := 0
endif

ifeq ($(ENABLE_SDL),1)
ifeq ($(ENABLE_VIRTIOGPU),1)
CFLAGS += $(shell sdl2-config --cflags)
LDFLAGS += $(shell sdl2-config --libs)
OBJS_EXTRA += window.o
OBJS_EXTRA += virtio-gpu.o
endif
endif

$(call set-feature, VIRTIOGPU)

BIN = semu
all: $(BIN) minimal.dtb

Expand Down
56 changes: 55 additions & 1 deletion device.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

#define RAM_SIZE (512 * 1024 * 1024)
#define DTB_SIZE (1 * 1024 * 1024)
#define INITRD_SIZE (8 * 1024 * 1024)
#define INITRD_SIZE (65 * 1024 * 1024)

void ram_read(vm_t *core,
uint32_t *mem,
Expand Down Expand Up @@ -171,6 +171,57 @@ void virtio_blk_write(vm_t *vm,
uint32_t *virtio_blk_init(virtio_blk_state_t *vblk, char *disk_file);
#endif /* SEMU_HAS(VIRTIOBLK) */

/* VirtIO-GPU */

#if SEMU_HAS(VIRTIOGPU)

#define IRQ_VGPU 4
#define IRQ_VGPU_BIT (1 << IRQ_VGPU)

typedef struct {
uint32_t QueueNum;
uint32_t QueueDesc;
uint32_t QueueAvail;
uint32_t QueueUsed;
uint16_t last_avail;
bool ready;
} virtio_gpu_queue_t;

typedef struct {
/* feature negotiation */
uint32_t DeviceFeaturesSel;
uint32_t DriverFeatures;
uint32_t DriverFeaturesSel;
/* queue config */
uint32_t QueueSel;
virtio_gpu_queue_t queues[2];
/* status */
uint32_t Status;
uint32_t InterruptStatus;
/* supplied by environment */
uint32_t *ram;
/* implementation-specific */
void *priv;
} virtio_gpu_state_t;

void virtio_gpu_read(vm_t *vm,
virtio_gpu_state_t *vgpu,
uint32_t addr,
uint8_t width,
uint32_t *value);

void virtio_gpu_write(vm_t *vm,
virtio_gpu_state_t *vgpu,
uint32_t addr,
uint8_t width,
uint32_t value);

void virtio_gpu_init(virtio_gpu_state_t *vgpu);
void virtio_gpu_add_scanout(virtio_gpu_state_t *vgpu,
uint32_t width,
uint32_t height);
#endif /* SEMU_HAS(VIRTIOGPU) */

/* memory mapping */

typedef struct {
Expand All @@ -184,6 +235,9 @@ typedef struct {
#endif
#if SEMU_HAS(VIRTIOBLK)
virtio_blk_state_t vblk;
#endif
#if SEMU_HAS(VIRTIOGPU)
virtio_gpu_state_t vgpu;
#endif
uint64_t timer;
} emu_state_t;
5 changes: 5 additions & 0 deletions feature.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,10 @@
#define SEMU_FEATUREVIRTIONET 1
#endif

/* virtio-gpu */
#ifndef SEMU_FEATUREVIRTIOGPU
#define SEMU_FEATUREVIRTIOGPU 1
#endif

/* Feature test macro */
#define SEMU_HAS(x) SEMU_FEATURE_##x
84 changes: 84 additions & 0 deletions list.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#pragma once

#include <stddef.h>

#define container_of(ptr, type, member) \
((type *) ((void *) ptr - offsetof(type, member)))

#define list_entry(ptr, type, member) container_of(ptr, type, member)

#define list_first_entry(ptr, type, member) \
list_entry((ptr)->next, type, member)

#define list_prev_entry(pos, member) \
list_entry((pos)->member.prev, typeof(*(pos)), member)

#define list_next_entry(pos, member) \
list_entry((pos)->member.next, typeof(*(pos)), member)

#define list_entry_is_head(pos, head, member) (&pos->member == (head))

#define list_for_each(pos, head) \
for ((pos) = (head)->next; (pos) != (head); (pos) = (pos)->next)

#define list_for_each_safe(pos, _next, head) \
for (pos = (head)->next, _next = (pos)->next; (pos) != (head); \
(pos) = _next, _next = (pos)->next)

#define list_for_each_entry(pos, head, member) \
for (pos = list_first_entry(head, __typeof__(*pos), member); \
&pos->member != (head); pos = list_next_entry(pos, member))

#define LIST_HEAD_INIT(name) \
{ \
.prev = (&name), .next = (&name) \
}

#define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name)

struct list_head {
struct list_head *next, *prev;
};

static inline void INIT_LIST_HEAD(struct list_head *list)
{
list->prev = list;
list->next = list;
}

static inline int list_empty(const struct list_head *head)
{
return head->next == head;
}

static int list_is_last(const struct list_head *list,
const struct list_head *head)
{
return list->next == head;
}

static inline void list_add(struct list_head *new, struct list_head *list)
{
new->prev = list->prev;
new->next = list;
list->prev->next = new;
list->prev = new;
}

static inline void list_del(struct list_head *list)
{
list->next->prev = list->prev;
list->prev->next = list->next;
}

static void list_del_init(struct list_head *entry)
{
list_del(entry);
INIT_LIST_HEAD(entry);
}

static inline void list_move(struct list_head *list, struct list_head *new_head)
{
list_del(list);
list_add(new_head, list);
}
37 changes: 37 additions & 0 deletions main.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <assert.h>
#include <fcntl.h>
#include <getopt.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Expand All @@ -11,6 +12,7 @@
#include "device.h"
#include "riscv.h"
#include "riscv_private.h"
#include "window.h"

#define PRIV(x) ((emu_state_t *) x->priv)

Expand Down Expand Up @@ -72,6 +74,18 @@ static void emu_update_vblk_interrupts(vm_t *vm)
}
#endif

#if SEMU_HAS(VIRTIOGPU)
static void emu_update_vgpu_interrupts(vm_t *vm)
{
emu_state_t *data = (emu_state_t *) vm->priv;
if (data->vgpu.InterruptStatus)
data->plic.active |= IRQ_VGPU_BIT;
else
data->plic.active &= ~IRQ_VGPU_BIT;
plic_update_interrupts(vm, &data->plic);
}
#endif

static void mem_load(vm_t *vm, uint32_t addr, uint8_t width, uint32_t *value)
{
emu_state_t *data = PRIV(vm);
Expand Down Expand Up @@ -104,6 +118,12 @@ static void mem_load(vm_t *vm, uint32_t addr, uint8_t width, uint32_t *value)
virtio_blk_read(vm, &data->vblk, addr & 0xFFFFF, width, value);
emu_update_vblk_interrupts(vm);
return;
#endif
#if SEMU_HAS(VIRTIOGPU)
case 0x43: /* virtio-gpu */
virtio_gpu_read(vm, &data->vgpu, addr & 0xFFFFF, width, value);
emu_update_vgpu_interrupts(vm);
return;
#endif
}
}
Expand Down Expand Up @@ -142,6 +162,12 @@ static void mem_store(vm_t *vm, uint32_t addr, uint8_t width, uint32_t value)
virtio_blk_write(vm, &data->vblk, addr & 0xFFFFF, width, value);
emu_update_vblk_interrupts(vm);
return;
#endif
#if SEMU_HAS(VIRTIOGPU)
case 0x43: /* virtio-gpu */
virtio_gpu_write(vm, &data->vgpu, addr & 0xFFFFF, width, value);
emu_update_vgpu_interrupts(vm);
return;
#endif
}
}
Expand Down Expand Up @@ -423,6 +449,12 @@ static int semu_start(int argc, char **argv)
emu.vblk.ram = emu.ram;
emu.disk = virtio_blk_init(&(emu.vblk), disk_file);
#endif
#if SEMU_HAS(VIRTIOGPU)
emu.vgpu.ram = emu.ram;
virtio_gpu_init(&(emu.vgpu));
virtio_gpu_add_scanout(&(emu.vgpu), 1024, 768);
window_init();
#endif

/* Emulate */
uint32_t peripheral_update_ctr = 0;
Expand All @@ -444,6 +476,11 @@ static int semu_start(int argc, char **argv)
if (emu.vblk.InterruptStatus)
emu_update_vblk_interrupts(&vm);
#endif

#if SEMU_HAS(VIRTIOGPU)
if (emu.vgpu.InterruptStatus)
emu_update_vgpu_interrupts(&vm);
#endif
}

if (vm.insn_count > emu.timer)
Expand Down
11 changes: 10 additions & 1 deletion minimal.dts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
chosen {
bootargs = "earlycon console=ttyS0";
stdout-path = "serial0";
linux,initrd-start = <0x1f700000>; /* @403 MiB (503 * 1024 * 1024) */
/* Reserve 65MiB for initrd image */
linux,initrd-start = <0x1be00000>; /* @406 MiB (446 * 1024 * 1024) */
linux,initrd-end = <0x1fefffff>; /* @511 MiB (511 * 1024 * 1024 - 1) */
};

Expand Down Expand Up @@ -81,5 +82,13 @@
interrupts = <3>;
};
#endif

#if SEMU_FEATURE_VIRTIOGPU
gpu0: virtio@4300000 {
compatible = "virtio,mmio";
reg = <0x4300000 0x200>;
interrupts = <4>;
};
#endif
};
};
Loading

0 comments on commit 1120c97

Please sign in to comment.