Skip to content

Implement VirtIO GPU and input devices #34

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
run: |
brew install make dtc expect e2fsprogs
- name: default build
run: make
run: make ENABLE_SDL=0
shell: bash
- name: automated test
run: .ci/autorun.sh
Expand Down
59 changes: 58 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ include mk/check-libs.mk
CC ?= gcc
CFLAGS := -O2 -g -Wall -Wextra
CFLAGS += -include common.h
LDFLAGS :=

# clock frequency
CLOCK_FREQ ?= 65000000
Expand All @@ -14,7 +15,7 @@ OBJS_EXTRA :=
# command line option
OPTS :=

LDFLAGS :=
LDFLAGS := -lm -lpthread

# virtio-blk
ENABLE_VIRTIOBLK ?= 1
Expand Down Expand Up @@ -115,6 +116,62 @@ LDFLAGS += -lm
# after git submodule.
.DEFAULT_GOAL := all

# virtio-input
ENABLE_VIRTIOINPUT ?= 1
ifneq ($(UNAME_S),Linux)
ENABLE_VIRTIOINPUT := 0
endif
$(call set-feature, VIRTIOINPUT)
ifeq ($(call has, VIRTIOINPUT), 1)
OBJS_EXTRA += virtio-input.o
endif

# virtio-gpu and virgl
ENABLE_VIRTIOGPU ?= 1
ENABLE_VIRGL ?= 1
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is confusing to have VirGL here. Add comments.


# 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),1)
CFLAGS += $(shell sdl2-config --cflags)
LDFLAGS += $(shell sdl2-config --libs)
else
# Disable virtio-gpu and virgl if SDL is not set
override ENABLE_VIRTIOGPU := 0
override ENABLE_VIRGL := 0
endif

# virtio-gpu
ifneq ($(UNAME_S),Linux)
ENABLE_VIRTIOGPU := 0
endif
ifeq ($(ENABLE_VIRTIOGPU),1)
OBJS_EXTRA += window-events.o
OBJS_EXTRA += virtio-gpu.o
else
override ENABLE_VIRGL := 0
endif

# VirGL
ifeq ($(ENABLE_VIRGL),1)
CFLAGS += $(shell pkg-config virglrenderer gl egl epoxy --cflags)
LDFLAGS += $(shell pkg-config virglrenderer gl egl epoxy --libs)
OBJS_EXTRA += virgl.o
OBJS_EXTRA += window-gl.o
else
ifeq ($(ENABLE_VIRTIOGPU),1)
OBJS_EXTRA += virtio-gpu-sw.o
OBJS_EXTRA += window-sw.o
endif
endif

$(call set-feature, VIRTIOGPU)
$(call set-feature, VIRGL)

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

Expand Down
17 changes: 17 additions & 0 deletions common.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
#pragma once

#include <stddef.h>
#include <stdint.h>
#include <sys/uio.h>

#include "feature.h"

#define BITS_PER_CHAR 8
#define BITS_PER_LONG (BITS_PER_CHAR * sizeof(long))

#define unlikely(x) __builtin_expect((x), 0)
#define likely(x) __builtin_expect((x), 1)

Expand All @@ -17,6 +24,16 @@ static inline int ilog2(int x)
return 31 - __builtin_clz(x | 1);
}

static inline void set_bit(unsigned long bit, unsigned long *word)
{
*word |= (1 << bit);
}

static inline void bitmap_set_bit(unsigned long *map, unsigned long bit)
{
set_bit(bit % BITS_PER_LONG, &map[bit / BITS_PER_LONG]);
}

/* Range check
* For any variable range checking:
* if (x >= minx && x <= maxx) ...
Expand Down
36 changes: 36 additions & 0 deletions configs/buildroot.config
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ BR2_BINUTILS_VERSION_2_42_X=y
# BR2_BINUTILS_GPROFNG is not set
BR2_GCC_VERSION_14_X=y
BR2_EXTRA_GCC_CONFIG_OPTIONS="--enable-softfloat"
BR2_TOOLCHAIN_BUILDROOT_CXX=y
BR2_INSTALL_LIBSTDCPP=y
BR2_TOOLCHAIN_HEADERS_AT_LEAST="6.1"
BR2_TOOLCHAIN_GCC_AT_LEAST_14=y
BR2_TOOLCHAIN_GCC_AT_LEAST="14"
Expand All @@ -39,6 +41,40 @@ BR2_FORTIFY_SOURCE_1=y
BR2_PACKAGE_ALSA_UTILS=y
BR2_PACKAGE_ALSA_UTILS_APLAY=y
BR2_PACKAGE_ALSA_UTILS_SPEAKER_TEST=y
BR2_PACKAGE_GLMARK2=y
BR2_PACKAGE_KMSCUBE=y
BR2_PACKAGE_MESA3D_DEMOS=y
BR2_PACKAGE_MESA3D=y
BR2_PACKAGE_MESA3D_GALLIUM_DRIVER=y
BR2_PACKAGE_MESA3D_DRIVER=y
BR2_PACKAGE_MESA3D_NEEDS_X11=y
BR2_PACKAGE_MESA3D_GALLIUM_DRIVER_SWRAST=y
BR2_PACKAGE_MESA3D_GALLIUM_DRIVER_VIRGL=y
BR2_PACKAGE_MESA3D_GBM=y
BR2_PACKAGE_MESA3D_OPENGL_GLX=y
BR2_PACKAGE_MESA3D_OPENGL_EGL=y
BR2_PACKAGE_MESA3D_OPENGL_ES=y
BR2_PACKAGE_PROVIDES_LIBGBM="mesa3d"
BR2_PACKAGE_XORG7=y
BR2_PACKAGE_XSERVER_XORG_SERVER=y
BR2_PACKAGE_XSERVER_XORG_SERVER_MODULAR=y
BR2_PACKAGE_XLIB_LIBX11=y
BR2_PACKAGE_XAPP_TWM=y
BR2_PACKAGE_XAPP_XAUTH=y
BR2_PACKAGE_XAPP_XCLOCK=y
BR2_PACKAGE_XAPP_XINIT=y
BR2_PACKAGE_XDRIVER_XF86_INPUT_LIBINPUT=y
BR2_PACKAGE_XDRIVER_XF86_VIDEO_FBDEV=y
BR2_PACKAGE_XTERM=y
Comment on lines +58 to +68
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't build X11 specific packages.

BR2_PACKAGE_EUDEV=y
BR2_ROOTFS_DEVICE_CREATION_DYNAMIC_EUDEV=y
BR2_PACKAGE_PROVIDES_UDEV="eudev"
BR2_PACKAGE_HAS_UDEV=y
BR2_PACKAGE_LIBDRM=y
BR2_PACKAGE_LIBGLEW=y
BR2_PACKAGE_HAS_LIBGBM=y
BR2_PACKAGE_HAS_LIBGLES=y
BR2_PACKAGE_LIBINPUT=y
# BR2_PACKAGE_URANDOM_SCRIPTS is not set
BR2_TARGET_ROOTFS_CPIO=y
BR2_TARGET_ROOTFS_CPIO_FULL=y
Expand Down
13 changes: 10 additions & 3 deletions configs/linux.config
Original file line number Diff line number Diff line change
Expand Up @@ -759,7 +759,7 @@ CONFIG_INPUT=y
#
# CONFIG_INPUT_MOUSEDEV is not set
# CONFIG_INPUT_JOYDEV is not set
# CONFIG_INPUT_EVDEV is not set
CONFIG_INPUT_EVDEV=y
# CONFIG_INPUT_EVBUG is not set

#
Expand Down Expand Up @@ -911,13 +911,19 @@ CONFIG_MFD_SYSCON=y
#
# Graphics support
#
# CONFIG_DRM is not set
CONFIG_DRM=y
CONFIG_DRM_KMS_HELPER=y
# CONFIG_DRM_DEBUG_MODESET_LOCK is not set

#
# ARM devices
#
# end of ARM devices
CONFIG_DRM_VIRTIO_GPU=y
CONFIG_DRM_VIRTIO_GPU_KMS=y
CONFIG_DRM_PANEL=y
CONFIG_DRM_BRIDGE=y
CONFIG_DRM_PANEL_BRIDGE=y

#
# Frame buffer Devices
Expand Down Expand Up @@ -1053,9 +1059,10 @@ CONFIG_VIRTIO_ANCHOR=y
CONFIG_VIRTIO=y
CONFIG_VIRTIO_MENU=y
# CONFIG_VIRTIO_BALLOON is not set
# CONFIG_VIRTIO_INPUT is not set
CONFIG_VIRTIO_INPUT=y
CONFIG_VIRTIO_MMIO=y
# CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES is not set
CONFIG_VIRTIO_DMA_SHARED_BUFFER=y
# CONFIG_VDPA is not set
# CONFIG_VHOST_MENU is not set

Expand Down
18 changes: 18 additions & 0 deletions configs/riscv-cross-file
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[binaries]
c = 'riscv32-buildroot-linux-gnu-gcc'
strip = 'riscv32-buildroot-linux-gnu-strip'
pkgconfig = 'pkg-config'
python = '/usr/bin/python3'

[properties]
pkg_config_libdir = ['@GLOBAL_SOURCE_ROOT@' / '../buildroot/output/host/riscv32-buildroot-linux-gnu/sysroot/usr/local/lib/pkgconfig',
'@GLOBAL_SOURCE_ROOT@' / '../buildroot/output/host/riscv32-buildroot-linux-gnu/sysroot/usr/share/pkgconfig/',
'@GLOBAL_SOURCE_ROOT@' / '../buildroot/output/host/riscv32-buildroot-linux-gnu/sysroot/usr/lib/pkgconfig/'
]
sys_root = '@GLOBAL_SOURCE_ROOT@' / '../buildroot/output/host/riscv32-buildroot-linux-gnu/sysroot'

[host_machine]
system = 'linux'
cpu_family = 'riscv'
cpu = 'riscv32-ima'
endian = 'little'
121 changes: 120 additions & 1 deletion device.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@

/* RAM */

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

#define SCREEN_WIDTH 1024
#define SCREEN_HEIGHT 768

void ram_read(hart_t *core,
uint32_t *mem,
const uint32_t addr,
Expand Down Expand Up @@ -222,6 +225,115 @@ void virtio_rng_write(hart_t *vm,
void virtio_rng_init(void);
#endif /* SEMU_HAS(VIRTIORNG) */

/* VirtIO-GPU */

#if SEMU_HAS(VIRTIOGPU)

#define IRQ_VGPU 6
#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(hart_t *vm,
virtio_gpu_state_t *vgpu,
uint32_t addr,
uint8_t width,
uint32_t *value);

void virtio_gpu_write(hart_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) */

/* VirtIO Input */

#if SEMU_HAS(VIRTIOINPUT)

#define IRQ_VINPUT_KEYBOARD 7
#define IRQ_VINPUT_KEYBOARD_BIT (1 << IRQ_VINPUT_KEYBOARD)

#define IRQ_VINPUT_MOUSE 8
#define IRQ_VINPUT_MOUSE_BIT (1 << IRQ_VINPUT_MOUSE)

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

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

void virtio_input_read(hart_t *vm,
virtio_input_state_t *vinput,
uint32_t addr,
uint8_t width,
uint32_t *value);

void virtio_input_write(hart_t *vm,
virtio_input_state_t *vinput,
uint32_t addr,
uint8_t width,
uint32_t value);

void virtio_input_init(virtio_input_state_t *vinput);

void virtio_input_update_key(uint32_t key, uint32_t state);

void virtio_input_update_mouse_button_state(uint32_t button, bool pressed);

void virtio_input_update_cursor(uint32_t x, uint32_t y);
#endif /* SEMU_HAS(VIRTIOINPUT) */

/* ACLINT MTIMER */
typedef struct {
/* A MTIMER device has two separate base addresses: one for the MTIME
Expand Down Expand Up @@ -374,6 +486,13 @@ typedef struct {
#endif
#if SEMU_HAS(VIRTIORNG)
virtio_rng_state_t vrng;
#endif
#if SEMU_HAS(VIRTIOGPU)
virtio_gpu_state_t vgpu;
#endif
#if SEMU_HAS(VIRTIOINPUT)
virtio_input_state_t vkeyboard;
virtio_input_state_t vmouse;
#endif
/* ACLINT */
mtimer_state_t mtimer;
Expand Down
15 changes: 15 additions & 0 deletions feature.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,20 @@
#define SEMU_FEATURE_VIRTIOSND 1
#endif

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

/* VirGL */
#ifndef SEMU_FEATURE_VIRGL
#define SEMU_FEATURE_VIRGL 1
#endif

/* virtio-input */
#ifndef SEMU_FEATURE_VIRTIOINPUT
#define SEMU_FEATURE_VIRTIOINPUT 1
#endif

/* Feature test macro */
#define SEMU_HAS(x) SEMU_FEATURE_##x
Loading