Skip to content

Commit 4719c26

Browse files
committed
Implement virtio-gpu device
1 parent d61c9f6 commit 4719c26

File tree

10 files changed

+1988
-2
lines changed

10 files changed

+1988
-2
lines changed

Makefile

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ include mk/common.mk
33
CC ?= gcc
44
CFLAGS := -O2 -g -Wall -Wextra
55
CFLAGS += -include common.h
6+
LDFLAGS :=
67

78
# clock frequency
89
CLOCK_FREQ ?= 65000000
@@ -13,6 +14,8 @@ OBJS_EXTRA :=
1314
# command line option
1415
OPTS :=
1516

17+
LDFLAGS += -lpthread
18+
1619
# virtio-blk
1720
ENABLE_VIRTIOBLK ?= 1
1821
$(call set-feature, VIRTIOBLK)
@@ -50,6 +53,33 @@ ifeq ($(call has, VIRTIONET), 1)
5053
OBJS_EXTRA += netdev.o
5154
endif
5255

56+
# virtio-gpu
57+
ENABLE_VIRTIOGPU ?= 1
58+
ifneq ($(UNAME_S),Linux)
59+
ENABLE_VIRTIOGPU := 0
60+
endif
61+
62+
# SDL2
63+
ENABLE_SDL ?= 1
64+
ifeq (, $(shell which sdl2-config))
65+
$(warning No sdl2-config in $$PATH. Check SDL2 installation in advance)
66+
override ENABLE_SDL := 0
67+
endif
68+
69+
ifeq ($(ENABLE_SDL),1)
70+
CFLAGS += $(shell sdl2-config --cflags)
71+
LDFLAGS += $(shell sdl2-config --libs)
72+
else
73+
override ENABLE_VIRTIOGPU := 0
74+
endif
75+
76+
ifeq ($(ENABLE_VIRTIOGPU),1)
77+
OBJS_EXTRA += window.o
78+
OBJS_EXTRA += virtio-gpu.o
79+
endif
80+
81+
$(call set-feature, VIRTIOGPU)
82+
5383
BIN = semu
5484
all: $(BIN) minimal.dtb
5585

device.h

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
#define RAM_SIZE (512 * 1024 * 1024)
1010
#define DTB_SIZE (1 * 1024 * 1024)
11-
#define INITRD_SIZE (8 * 1024 * 1024)
11+
#define INITRD_SIZE (65 * 1024 * 1024)
1212

1313
void ram_read(hart_t *core,
1414
uint32_t *mem,
@@ -218,6 +218,59 @@ void virtio_rng_write(hart_t *vm,
218218
void virtio_rng_init(void);
219219
#endif /* SEMU_HAS(VIRTIORNG) */
220220

221+
/* VirtIO-GPU */
222+
223+
#if SEMU_HAS(VIRTIOGPU)
224+
225+
#define IRQ_VGPU 5
226+
#define IRQ_VGPU_BIT (1 << IRQ_VGPU)
227+
228+
typedef struct {
229+
uint32_t QueueNum;
230+
uint32_t QueueDesc;
231+
uint32_t QueueAvail;
232+
uint32_t QueueUsed;
233+
uint16_t last_avail;
234+
bool ready;
235+
} virtio_gpu_queue_t;
236+
237+
typedef struct {
238+
/* feature negotiation */
239+
uint32_t DeviceFeaturesSel;
240+
uint32_t DriverFeatures;
241+
uint32_t DriverFeaturesSel;
242+
/* queue config */
243+
uint32_t QueueSel;
244+
virtio_gpu_queue_t queues[2];
245+
/* status */
246+
uint32_t Status;
247+
uint32_t InterruptStatus;
248+
/* supplied by environment */
249+
uint32_t *ram;
250+
/* implementation-specific */
251+
void *priv;
252+
} virtio_gpu_state_t;
253+
254+
void virtio_gpu_read(hart_t *vm,
255+
virtio_gpu_state_t *vgpu,
256+
uint32_t addr,
257+
uint8_t width,
258+
uint32_t *value);
259+
260+
void virtio_gpu_write(hart_t *vm,
261+
virtio_gpu_state_t *vgpu,
262+
uint32_t addr,
263+
uint8_t width,
264+
uint32_t value);
265+
266+
void semu_virgl_init(virtio_gpu_state_t *vgpu);
267+
268+
void virtio_gpu_init(virtio_gpu_state_t *vgpu);
269+
void virtio_gpu_add_scanout(virtio_gpu_state_t *vgpu,
270+
uint32_t width,
271+
uint32_t height);
272+
#endif /* SEMU_HAS(VIRTIOGPU) */
273+
221274
/* ACLINT MTIMER */
222275
typedef struct {
223276
/* A MTIMER device has two separate base addresses: one for the MTIME
@@ -321,6 +374,9 @@ typedef struct {
321374
#endif
322375
#if SEMU_HAS(VIRTIORNG)
323376
virtio_rng_state_t vrng;
377+
#endif
378+
#if SEMU_HAS(VIRTIOGPU)
379+
virtio_gpu_state_t vgpu;
324380
#endif
325381
/* ACLINT */
326382
mtimer_state_t mtimer;

feature.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,10 @@
1212
#define SEMU_FEATURE_VIRTIONET 1
1313
#endif
1414

15+
/* virtio-gpu */
16+
#ifndef SEMU_FEATURE_VIRTIOGPU
17+
#define SEMU_FEATURE_VIRTIOGPU 1
18+
#endif
19+
1520
/* Feature test macro */
1621
#define SEMU_HAS(x) SEMU_FEATURE_##x

list.h

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#pragma once
2+
3+
#include <stddef.h>
4+
5+
#define container_of(ptr, type, member) \
6+
((type *) ((void *) ptr - offsetof(type, member)))
7+
8+
#define list_entry(ptr, type, member) container_of(ptr, type, member)
9+
10+
#define list_first_entry(ptr, type, member) \
11+
list_entry((ptr)->next, type, member)
12+
13+
#define list_prev_entry(pos, member) \
14+
list_entry((pos)->member.prev, typeof(*(pos)), member)
15+
16+
#define list_next_entry(pos, member) \
17+
list_entry((pos)->member.next, typeof(*(pos)), member)
18+
19+
#define list_entry_is_head(pos, head, member) (&pos->member == (head))
20+
21+
#define list_for_each(pos, head) \
22+
for ((pos) = (head)->next; (pos) != (head); (pos) = (pos)->next)
23+
24+
#define list_for_each_safe(pos, _next, head) \
25+
for (pos = (head)->next, _next = (pos)->next; (pos) != (head); \
26+
(pos) = _next, _next = (pos)->next)
27+
28+
#define list_for_each_entry(pos, head, member) \
29+
for (pos = list_first_entry(head, __typeof__(*pos), member); \
30+
&pos->member != (head); pos = list_next_entry(pos, member))
31+
32+
#define LIST_HEAD_INIT(name) \
33+
{ \
34+
.prev = (&name), .next = (&name) \
35+
}
36+
37+
#define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name)
38+
39+
struct list_head {
40+
struct list_head *next, *prev;
41+
};
42+
43+
static inline void INIT_LIST_HEAD(struct list_head *list)
44+
{
45+
list->prev = list;
46+
list->next = list;
47+
}
48+
49+
static inline int list_empty(const struct list_head *head)
50+
{
51+
return head->next == head;
52+
}
53+
54+
static int list_is_last(const struct list_head *list,
55+
const struct list_head *head)
56+
{
57+
return list->next == head;
58+
}
59+
60+
static inline void list_add(struct list_head *new, struct list_head *list)
61+
{
62+
new->prev = list->prev;
63+
new->next = list;
64+
list->prev->next = new;
65+
list->prev = new;
66+
}
67+
68+
static inline void list_del(struct list_head *list)
69+
{
70+
list->next->prev = list->prev;
71+
list->prev->next = list->next;
72+
}
73+
74+
static void list_del_init(struct list_head *entry)
75+
{
76+
list_del(entry);
77+
INIT_LIST_HEAD(entry);
78+
}
79+
80+
static inline void list_move(struct list_head *list, struct list_head *new_head)
81+
{
82+
list_del(list);
83+
list_add(new_head, list);
84+
}

main.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "device.h"
1212
#include "riscv.h"
1313
#include "riscv_private.h"
14+
#include "window.h"
1415

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

@@ -84,6 +85,18 @@ static void emu_update_vrng_interrupts(vm_t *vm)
8485
}
8586
#endif
8687

88+
#if SEMU_HAS(VIRTIOGPU)
89+
static void emu_update_vgpu_interrupts(vm_t *vm)
90+
{
91+
emu_state_t *data = PRIV(vm->hart[0]);
92+
if (data->vgpu.InterruptStatus)
93+
data->plic.active |= IRQ_VGPU_BIT;
94+
else
95+
data->plic.active &= ~IRQ_VGPU_BIT;
96+
plic_update_interrupts(vm, &data->plic);
97+
}
98+
#endif
99+
87100
static void emu_update_timer_interrupt(hart_t *hart)
88101
{
89102
emu_state_t *data = PRIV(hart);
@@ -154,6 +167,12 @@ static void mem_load(hart_t *hart,
154167
virtio_rng_read(hart, &data->vrng, addr & 0xFFFFF, width, value);
155168
emu_update_vrng_interrupts(hart->vm);
156169
return;
170+
#endif
171+
#if SEMU_HAS(VIRTIOGPU)
172+
case 0x47: /* virtio-gpu */
173+
virtio_gpu_read(hart, &data->vgpu, addr & 0xFFFFF, width, value);
174+
emu_update_vgpu_interrupts(hart->vm);
175+
return;
157176
#endif
158177
}
159178
}
@@ -214,6 +233,12 @@ static void mem_store(hart_t *hart,
214233
virtio_rng_write(hart, &data->vrng, addr & 0xFFFFF, width, value);
215234
emu_update_vrng_interrupts(hart->vm);
216235
return;
236+
#endif
237+
#if SEMU_HAS(VIRTIOGPU)
238+
case 0x47: /* virtio-gpu */
239+
virtio_gpu_write(hart, &data->vgpu, addr & 0xFFFFF, width, value);
240+
emu_update_vgpu_interrupts(hart->vm);
241+
return;
217242
#endif
218243
}
219244
}
@@ -651,6 +676,12 @@ static int semu_start(int argc, char **argv)
651676
emu.mtimer.mtimecmp = calloc(vm.n_hart, sizeof(uint64_t));
652677
emu.mswi.msip = calloc(vm.n_hart, sizeof(uint32_t));
653678
emu.sswi.ssip = calloc(vm.n_hart, sizeof(uint32_t));
679+
#if SEMU_HAS(VIRTIOGPU)
680+
emu.vgpu.ram = emu.ram;
681+
virtio_gpu_init(&(emu.vgpu));
682+
virtio_gpu_add_scanout(&(emu.vgpu), 1024, 768);
683+
window_init();
684+
#endif
654685

655686
/* Emulate */
656687
uint32_t peripheral_update_ctr = 0;
@@ -676,6 +707,11 @@ static int semu_start(int argc, char **argv)
676707
if (emu.vblk.InterruptStatus)
677708
emu_update_vblk_interrupts(&vm);
678709
#endif
710+
711+
#if SEMU_HAS(VIRTIOGPU)
712+
if (emu.vgpu.InterruptStatus)
713+
emu_update_vgpu_interrupts(&vm);
714+
#endif
679715
}
680716

681717
emu_update_timer_interrupt(vm.hart[i]);

minimal.dts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
chosen {
1818
bootargs = "earlycon console=ttyS0";
1919
stdout-path = "serial0";
20-
linux,initrd-start = <0x1f700000>; /* @403 MiB (503 * 1024 * 1024) */
20+
/* Reserve 65MiB for initrd image */
21+
linux,initrd-start = <0x1be00000>; /* @406 MiB (446 * 1024 * 1024) */
2122
linux,initrd-end = <0x1fefffff>; /* @511 MiB (511 * 1024 * 1024 - 1) */
2223
};
2324

@@ -71,5 +72,13 @@
7172
interrupts = <4>;
7273
};
7374
#endif
75+
76+
#if SEMU_FEATURE_VIRTIOGPU
77+
gpu0: virtio@4700000 {
78+
compatible = "virtio,mmio";
79+
reg = <0x4700000 0x200>;
80+
interrupts = <5>;
81+
};
82+
#endif
7483
};
7584
};

0 commit comments

Comments
 (0)