Skip to content

Commit b71f7dc

Browse files
committed
Implement virtio-gpu device
1 parent a723e75 commit b71f7dc

File tree

10 files changed

+1510
-0
lines changed

10 files changed

+1510
-0
lines changed

Makefile

+25
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@ include mk/common.mk
33
CC ?= gcc
44
CFLAGS := -O2 -g -Wall -Wextra
55
CFLAGS += -include common.h
6+
LDFLAGS :=
67

78
OBJS_EXTRA :=
89
# command line option
910
OPTS :=
1011

12+
LDFLAGS += -lpthread
13+
1114
# virtio-blk
1215
ENABLE_VIRTIOBLK ?= 1
1316
$(call set-feature, VIRTIOBLK)
@@ -36,6 +39,28 @@ ifeq ($(call has, VIRTIONET), 1)
3639
OBJS_EXTRA += virtio-net.o
3740
endif
3841

42+
# virtio-gpu
43+
ENABLE_VIRTIOGPU ?= 1
44+
ifneq ($(UNAME_S),Linux)
45+
ENABLE_VIRTIOGPU := 0
46+
endif
47+
$(call set-feature, VIRTIOGPU)
48+
ifeq ($(call has, VIRTIOGPU), 1)
49+
OBJS_EXTRA += virtio-gpu.o
50+
endif
51+
52+
# SDL2
53+
ENABLE_SDL ?= 1
54+
ifeq ($(call has, SDL), 1)
55+
ifeq (, $(shell which sdl2-config))
56+
$(warning No sdl2-config in $$PATH. Check SDL2 installation in advance)
57+
override ENABLE_SDL := 0
58+
endif
59+
CFLAGS += `sdl2-config --cflags`
60+
LDFLAGS += `sdl2-config --libs`
61+
OBJS_EXTRA += window.o
62+
endif
63+
3964
BIN = semu
4065
all: $(BIN) minimal.dtb
4166

device.h

+54
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,57 @@ void virtio_blk_write(vm_t *vm,
171171
uint32_t *virtio_blk_init(virtio_blk_state_t *vblk, char *disk_file);
172172
#endif /* SEMU_HAS(VIRTIOBLK) */
173173

174+
/* VirtIO-GPU */
175+
176+
#if SEMU_HAS(VIRTIOGPU)
177+
178+
#define IRQ_VGPU 4
179+
#define IRQ_VGPU_BIT (1 << IRQ_VGPU)
180+
181+
typedef struct {
182+
uint32_t QueueNum;
183+
uint32_t QueueDesc;
184+
uint32_t QueueAvail;
185+
uint32_t QueueUsed;
186+
uint16_t last_avail;
187+
bool ready;
188+
} virtio_gpu_queue_t;
189+
190+
typedef struct {
191+
/* feature negotiation */
192+
uint32_t DeviceFeaturesSel;
193+
uint32_t DriverFeatures;
194+
uint32_t DriverFeaturesSel;
195+
/* queue config */
196+
uint32_t QueueSel;
197+
virtio_gpu_queue_t queues[2];
198+
/* status */
199+
uint32_t Status;
200+
uint32_t InterruptStatus;
201+
/* supplied by environment */
202+
uint32_t *ram;
203+
/* implementation-specific */
204+
void *priv;
205+
} virtio_gpu_state_t;
206+
207+
void virtio_gpu_read(vm_t *vm,
208+
virtio_gpu_state_t *vgpu,
209+
uint32_t addr,
210+
uint8_t width,
211+
uint32_t *value);
212+
213+
void virtio_gpu_write(vm_t *vm,
214+
virtio_gpu_state_t *vgpu,
215+
uint32_t addr,
216+
uint8_t width,
217+
uint32_t value);
218+
219+
void virtio_gpu_init(virtio_gpu_state_t *vgpu);
220+
void virtio_gpu_add_scanout(virtio_gpu_state_t *vgpu,
221+
uint32_t width,
222+
uint32_t height);
223+
#endif /* SEMU_HAS(VIRTIOGPU) */
224+
174225
/* memory mapping */
175226

176227
typedef struct {
@@ -184,6 +235,9 @@ typedef struct {
184235
#endif
185236
#if SEMU_HAS(VIRTIOBLK)
186237
virtio_blk_state_t vblk;
238+
#endif
239+
#if SEMU_HAS(VIRTIOGPU)
240+
virtio_gpu_state_t vgpu;
187241
#endif
188242
uint64_t timer;
189243
} emu_state_t;

feature.h

+5
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,10 @@
1212
#define SEMU_FEATUREVIRTIONET 1
1313
#endif
1414

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

list.h

+84
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

+37
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <assert.h>
22
#include <fcntl.h>
33
#include <getopt.h>
4+
#include <signal.h>
45
#include <stdio.h>
56
#include <stdlib.h>
67
#include <string.h>
@@ -11,6 +12,7 @@
1112
#include "device.h"
1213
#include "riscv.h"
1314
#include "riscv_private.h"
15+
#include "window.h"
1416

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

@@ -72,6 +74,18 @@ static void emu_update_vblk_interrupts(vm_t *vm)
7274
}
7375
#endif
7476

77+
#if SEMU_HAS(VIRTIOGPU)
78+
static void emu_update_vgpu_interrupts(vm_t *vm)
79+
{
80+
emu_state_t *data = (emu_state_t *) vm->priv;
81+
if (data->vgpu.InterruptStatus)
82+
data->plic.active |= IRQ_VGPU_BIT;
83+
else
84+
data->plic.active &= ~IRQ_VGPU_BIT;
85+
plic_update_interrupts(vm, &data->plic);
86+
}
87+
#endif
88+
7589
static void mem_load(vm_t *vm, uint32_t addr, uint8_t width, uint32_t *value)
7690
{
7791
emu_state_t *data = PRIV(vm);
@@ -104,6 +118,12 @@ static void mem_load(vm_t *vm, uint32_t addr, uint8_t width, uint32_t *value)
104118
virtio_blk_read(vm, &data->vblk, addr & 0xFFFFF, width, value);
105119
emu_update_vblk_interrupts(vm);
106120
return;
121+
#endif
122+
#if SEMU_HAS(VIRTIOGPU)
123+
case 0x43: /* virtio-gpu */
124+
virtio_gpu_read(vm, &data->vgpu, addr & 0xFFFFF, width, value);
125+
emu_update_vgpu_interrupts(vm);
126+
return;
107127
#endif
108128
}
109129
}
@@ -142,6 +162,12 @@ static void mem_store(vm_t *vm, uint32_t addr, uint8_t width, uint32_t value)
142162
virtio_blk_write(vm, &data->vblk, addr & 0xFFFFF, width, value);
143163
emu_update_vblk_interrupts(vm);
144164
return;
165+
#endif
166+
#if SEMU_HAS(VIRTIOGPU)
167+
case 0x43: /* virtio-gpu */
168+
virtio_gpu_write(vm, &data->vgpu, addr & 0xFFFFF, width, value);
169+
emu_update_vgpu_interrupts(vm);
170+
return;
145171
#endif
146172
}
147173
}
@@ -423,6 +449,12 @@ static int semu_start(int argc, char **argv)
423449
emu.vblk.ram = emu.ram;
424450
emu.disk = virtio_blk_init(&(emu.vblk), disk_file);
425451
#endif
452+
#if SEMU_HAS(VIRTIOGPU)
453+
emu.vgpu.ram = emu.ram;
454+
virtio_gpu_init(&(emu.vgpu));
455+
virtio_gpu_add_scanout(&(emu.vgpu), 1024, 768);
456+
display_window_init();
457+
#endif
426458

427459
/* Emulate */
428460
uint32_t peripheral_update_ctr = 0;
@@ -444,6 +476,11 @@ static int semu_start(int argc, char **argv)
444476
if (emu.vblk.InterruptStatus)
445477
emu_update_vblk_interrupts(&vm);
446478
#endif
479+
480+
#if SEMU_HAS(VIRTIOGPU)
481+
if (emu.vgpu.InterruptStatus)
482+
emu_update_vgpu_interrupts(&vm);
483+
#endif
447484
}
448485

449486
if (vm.insn_count > emu.timer)

minimal.dts

+8
Original file line numberDiff line numberDiff line change
@@ -81,5 +81,13 @@
8181
interrupts = <3>;
8282
};
8383
#endif
84+
85+
#if SEMU_FEATURE_VIRTIOGPU
86+
gpu0: virtio@4300000 {
87+
compatible = "virtio,mmio";
88+
reg = <0x4300000 0x200>;
89+
interrupts = <4>;
90+
};
91+
#endif
8492
};
8593
};

0 commit comments

Comments
 (0)