Skip to content

Commit 940a749

Browse files
authored
Merge pull request #53 from Cuda-Chen/add-virtio-snd
Implement VirtIO sound device playback
2 parents d61c9f6 + f473e91 commit 940a749

File tree

14 files changed

+1467
-4
lines changed

14 files changed

+1467
-4
lines changed

.github/workflows/main.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ jobs:
1010
- name: install-dependencies
1111
run: |
1212
sudo apt-get install build-essential device-tree-compiler expect
13+
sudo apt-get install libasound2-dev libudev-dev
1314
- name: default build
1415
run: make
1516
shell: bash

.gitmodules

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[submodule "cnfa"]
2+
path = cnfa
3+
url = https://github.com/cntools/cnfa
4+
shallow = true

Makefile

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
include mk/common.mk
2+
include mk/check-libs.mk
23

34
CC ?= gcc
45
CFLAGS := -O2 -g -Wall -Wextra
@@ -13,6 +14,8 @@ OBJS_EXTRA :=
1314
# command line option
1415
OPTS :=
1516

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

56+
# virtio-snd
57+
ENABLE_VIRTIOSND ?= 1
58+
ifneq ($(UNAME_S),$(filter $(UNAME_S),Linux))
59+
ENABLE_VIRTIOSND := 0
60+
endif
61+
62+
# Check ALSA installation
63+
ifeq ($(UNAME_S),Linux)
64+
ifeq (0, $(call check-alsa))
65+
$(warning No libasound installed. Check libasound in advance.)
66+
ENABLE_VIRTIOSND := 0
67+
endif
68+
endif
69+
$(call set-feature, VIRTIOSND)
70+
ifeq ($(call has, VIRTIOSND), 1)
71+
OBJS_EXTRA += virtio-snd.o
72+
73+
LDFLAGS += -lasound -lpthread
74+
CFLAGS += -Icnfa
75+
76+
cnfa/Makefile:
77+
git submodule update --init cnfa
78+
cnfa/os_generic: cnfa/Makefile
79+
$(MAKE) -C $(dir $<) os_generic.h
80+
CNFA_LIB := cnfa/CNFA_sf.h
81+
$(CNFA_LIB): cnfa/Makefile cnfa/os_generic
82+
$(MAKE) -C $(dir $<) CNFA_sf.h
83+
main.o: $(CNFA_LIB)
84+
85+
# suppress warning when compiling CNFA
86+
virtio-snd.o: CFLAGS += -Wno-unused-parameter -Wno-sign-compare
87+
endif
88+
89+
# .DEFAULT_GOAL should be set to all since the very first target is not all
90+
# after git submodule.
91+
.DEFAULT_GOAL := all
92+
5393
BIN = semu
5494
all: $(BIN) minimal.dtb
5595

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,12 @@ A minimalist RISC-V system emulator capable of running Linux the kernel and corr
99
- UART: 8250/16550
1010
- PLIC (platform-level interrupt controller): 32 interrupts, no priority
1111
- Standard SBI, with the timer extension
12-
- VirtIO: virtio-blk acquires disk image from the host, and virtio-net is mapped as TAP interface
12+
- Three types of I/O support using VirtIO standard:
13+
- virtio-blk acquires disk image from the host.
14+
- virtio-net is mapped as TAP interface.
15+
- virtio-snd uses ALSA for sound operation with the following limitations:
16+
- The emulator will hang if PulseAudio is enabled on host.
17+
- The playback may plays with repeating artifact.
1318

1419
## Prerequisites
1520

cnfa

Submodule cnfa added at 60bcddd

configs/buildroot.config

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ BR2_RELRO_NONE=y
3636
# BR2_RELRO_PARTIAL is not set
3737
# BR2_RELRO_FULL is not set
3838
BR2_FORTIFY_SOURCE_1=y
39+
BR2_PACKAGE_ALSA_UTILS=y
40+
BR2_PACKAGE_ALSA_UTILS_APLAY=y
41+
BR2_PACKAGE_ALSA_UTILS_SPEAKER_TEST=y
3942
# BR2_PACKAGE_URANDOM_SCRIPTS is not set
4043
BR2_TARGET_ROOTFS_CPIO=y
4144
BR2_TARGET_ROOTFS_CPIO_FULL=y

configs/linux.config

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ CONFIG_LOCALVERSION_AUTO=y
3030
CONFIG_BUILD_SALT=""
3131
CONFIG_DEFAULT_INIT=""
3232
CONFIG_DEFAULT_HOSTNAME="(none)"
33-
# CONFIG_SYSVIPC is not set
33+
CONFIG_SYSVIPC=y
34+
CONFIG_SYSVIPC_SYSCTL=y
3435
# CONFIG_POSIX_MQUEUE is not set
3536
# CONFIG_WATCH_QUEUE is not set
3637
# CONFIG_CROSS_MEMORY_ATTACH is not set
@@ -937,7 +938,9 @@ CONFIG_DUMMY_CONSOLE_ROWS=25
937938
# end of Console display driver support
938939
# end of Graphics support
939940

940-
# CONFIG_SOUND is not set
941+
CONFIG_SOUND=y
942+
CONFIG_SND=y
943+
CONFIG_SND_VIRTIO=y
941944

942945
#
943946
# HID support

device.h

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,53 @@ void aclint_sswi_write(hart_t *hart,
306306
uint8_t width,
307307
uint32_t value);
308308

309+
/* VirtIO-Sound */
310+
311+
#if SEMU_HAS(VIRTIOSND)
312+
#define IRQ_VSND 5
313+
#define IRQ_VSND_BIT (1 << IRQ_VSND)
314+
315+
typedef struct {
316+
uint32_t QueueNum;
317+
uint32_t QueueDesc;
318+
uint32_t QueueAvail;
319+
uint32_t QueueUsed;
320+
uint16_t last_avail;
321+
bool ready;
322+
} virtio_snd_queue_t;
323+
324+
typedef struct {
325+
/* feature negotiation */
326+
uint32_t DeviceFeaturesSel;
327+
uint32_t DriverFeatures;
328+
uint32_t DriverFeaturesSel;
329+
/* queue config */
330+
uint32_t QueueSel;
331+
virtio_snd_queue_t queues[4];
332+
/* status */
333+
uint32_t Status;
334+
uint32_t InterruptStatus;
335+
/* supplied by environment */
336+
uint32_t *ram;
337+
/* implementation-specific */
338+
void *priv;
339+
} virtio_snd_state_t;
340+
341+
void virtio_snd_read(hart_t *core,
342+
virtio_snd_state_t *vsnd,
343+
uint32_t addr,
344+
uint8_t width,
345+
uint32_t *value);
346+
347+
void virtio_snd_write(hart_t *core,
348+
virtio_snd_state_t *vsnd,
349+
uint32_t addr,
350+
uint8_t width,
351+
uint32_t value);
352+
353+
bool virtio_snd_init(virtio_snd_state_t *vsnd);
354+
#endif /* SEMU_HAS(VIRTIOSND) */
355+
309356
/* memory mapping */
310357
typedef struct {
311358
bool stopped;
@@ -326,4 +373,7 @@ typedef struct {
326373
mtimer_state_t mtimer;
327374
mswi_state_t mswi;
328375
sswi_state_t sswi;
376+
#if SEMU_HAS(VIRTIOSND)
377+
virtio_snd_state_t vsnd;
378+
#endif
329379
} emu_state_t;

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-snd */
16+
#ifndef SEMU_FEATURE_VIRTIOSND
17+
#define SEMU_FEATURE_VIRTIOSND 1
18+
#endif
19+
1520
/* Feature test macro */
1621
#define SEMU_HAS(x) SEMU_FEATURE_##x

main.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,18 @@ static void emu_update_swi_interrupt(hart_t *hart)
100100
aclint_sswi_update_interrupts(hart, &data->sswi);
101101
}
102102

103+
#if SEMU_HAS(VIRTIOSND)
104+
static void emu_update_vsnd_interrupts(vm_t *vm)
105+
{
106+
emu_state_t *data = PRIV(vm->hart[0]);
107+
if (data->vsnd.InterruptStatus)
108+
data->plic.active |= IRQ_VSND_BIT;
109+
else
110+
data->plic.active &= ~IRQ_VSND_BIT;
111+
plic_update_interrupts(vm, &data->plic);
112+
}
113+
#endif
114+
103115
static void mem_load(hart_t *hart,
104116
uint32_t addr,
105117
uint8_t width,
@@ -155,6 +167,13 @@ static void mem_load(hart_t *hart,
155167
emu_update_vrng_interrupts(hart->vm);
156168
return;
157169
#endif
170+
171+
#if SEMU_HAS(VIRTIOSND)
172+
case 0x47: /* virtio-snd */
173+
virtio_snd_read(hart, &data->vsnd, addr & 0xFFFFF, width, value);
174+
emu_update_vsnd_interrupts(hart->vm);
175+
return;
176+
#endif
158177
}
159178
}
160179
vm_set_exception(hart, RV_EXC_LOAD_FAULT, hart->exc_val);
@@ -209,12 +228,20 @@ static void mem_store(hart_t *hart,
209228
aclint_sswi_write(hart, &data->sswi, addr & 0xFFFFF, width, value);
210229
aclint_sswi_update_interrupts(hart, &data->sswi);
211230
return;
231+
212232
#if SEMU_HAS(VIRTIORNG)
213233
case 0x46: /* virtio-rng */
214234
virtio_rng_write(hart, &data->vrng, addr & 0xFFFFF, width, value);
215235
emu_update_vrng_interrupts(hart->vm);
216236
return;
217237
#endif
238+
239+
#if SEMU_HAS(VIRTIOSND)
240+
case 0x47: /* virtio-snd */
241+
virtio_snd_write(hart, &data->vsnd, addr & 0xFFFFF, width, value);
242+
emu_update_vsnd_interrupts(hart->vm);
243+
return;
244+
#endif
218245
}
219246
}
220247
vm_set_exception(hart, RV_EXC_STORE_FAULT, hart->exc_val);
@@ -651,6 +678,11 @@ static int semu_start(int argc, char **argv)
651678
emu.mtimer.mtimecmp = calloc(vm.n_hart, sizeof(uint64_t));
652679
emu.mswi.msip = calloc(vm.n_hart, sizeof(uint32_t));
653680
emu.sswi.ssip = calloc(vm.n_hart, sizeof(uint32_t));
681+
#if SEMU_HAS(VIRTIOSND)
682+
if (!virtio_snd_init(&(emu.vsnd)))
683+
fprintf(stderr, "No virtio-snd functioned\n");
684+
emu.vsnd.ram = emu.ram;
685+
#endif
654686

655687
/* Emulate */
656688
uint32_t peripheral_update_ctr = 0;
@@ -676,6 +708,11 @@ static int semu_start(int argc, char **argv)
676708
if (emu.vblk.InterruptStatus)
677709
emu_update_vblk_interrupts(&vm);
678710
#endif
711+
712+
#if SEMU_HAS(VIRTIOSND)
713+
if (emu.vsnd.InterruptStatus)
714+
emu_update_vsnd_interrupts(&vm);
715+
#endif
679716
}
680717

681718
emu_update_timer_interrupt(vm.hart[i]);

0 commit comments

Comments
 (0)