Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
Enable ALSA driver and System V IPC in Linux Kernel. For
ALSA, the debug is enabled and will be removed once
this commit is ready.

Add description of descriptor chaining, yet need refactoring
the description as well as code (exists uncertainty of
the query struct).

Succeed to initialize virtio-snd.

Handle requests in control queue, and print the address and length
of each virtq element to check the validness of self-implement
queue.

For macOS, an experimental core audio library check is implemented.

Create critical section when receiving frames. Need to investigate
whether we should dispatch an event to event queue to notify
the completion of receiving frames so that the device can move to
pcm_start state.
  • Loading branch information
Cuda-Chen committed Nov 8, 2024
1 parent a0ad61b commit 5251ec6
Show file tree
Hide file tree
Showing 14 changed files with 1,373 additions and 3 deletions.
1 change: 1 addition & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ jobs:
- name: install-dependencies
run: |
sudo apt-get install build-essential device-tree-compiler expect
sudo apt-get install libasound2-dev libudev-dev
- name: default build
run: make
shell: bash
Expand Down
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[submodule "cnfa"]
path = cnfa
url = https://github.com/cntools/cnfa
shallow = true
48 changes: 48 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
include mk/common.mk
include mk/check-libs.mk

CC ?= gcc
CFLAGS := -O2 -g -Wall -Wextra
Expand All @@ -13,6 +14,8 @@ OBJS_EXTRA :=
# command line option
OPTS :=

LDFLAGS := -lm

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

# virtio-snd
ENABLE_VIRTIOSND ?= 1
ifneq ($(UNAME_S),$(filter $(UNAME_S),Linux Darwin))
ENABLE_VIRTIOSND := 0
endif

# Check ALSA installation
ifeq ($(UNAME_S),Linux)
ifeq (0, $(call check-alsa))
$(warning No libasound installed. Check libasound in advance.)
ENABLE_VIRTIOSND := 0
endif
endif
# Check core audio installation
ifeq ($(UNAME_S),Darwin)
ifeq (0, $(call check-coreaudio))
$(warning No CoreAudio framework installed.)
ENABLE_VIRTIOSND := 0
endif
endif
$(call set-feature, VIRTIOSND)
ifeq ($(call has, VIRTIOSND), 1)
OBJS_EXTRA += virtio-snd.o

ifeq ($(UNAME_S),Linux)
LDFLAGS += -lasound -lpthread
else ifeq ($(UNAME_S),Darwin)
LDFLAGS += -framework AudioToolbox -lpthread
endif
CFLAGS += -Icnfa

cnfa/Makefile:
git submodule update --init cnfa
cnfa/os_generic: cnfa/Makefile
$(MAKE) -C $(dir $<) os_generic.h
CNFA_LIB := cnfa/CNFA_sf.h
$(CNFA_LIB): cnfa/Makefile cnfa/os_generic
$(MAKE) -C $(dir $<) CNFA_sf.h
main.o: $(CNFA_LIB)
endif

# .DEFAULT_GOAL should be set to all since the very first target is not all
# after git submodule.
.DEFAULT_GOAL := all

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

Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ A minimalist RISC-V system emulator capable of running Linux the kernel and corr
- UART: 8250/16550
- PLIC (platform-level interrupt controller): 32 interrupts, no priority
- Standard SBI, with the timer extension
- VirtIO: virtio-blk acquires disk image from the host, and virtio-net is mapped as TAP interface
- Three types of I/O support using VirtIO standard:
- virtio-blk acquires disk image from the host.
- virtio-net is mapped as TAP interface.
- virtio-snd uses ALSA for sound operation.

## Prerequisites

Expand Down
1 change: 1 addition & 0 deletions cnfa
Submodule cnfa added at 60bcdd
3 changes: 3 additions & 0 deletions configs/buildroot.config
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ BR2_RELRO_NONE=y
# BR2_RELRO_PARTIAL is not set
# BR2_RELRO_FULL is not set
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_URANDOM_SCRIPTS is not set
BR2_TARGET_ROOTFS_CPIO=y
BR2_TARGET_ROOTFS_CPIO_FULL=y
Expand Down
10 changes: 8 additions & 2 deletions configs/linux.config
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ CONFIG_LOCALVERSION_AUTO=y
CONFIG_BUILD_SALT=""
CONFIG_DEFAULT_INIT=""
CONFIG_DEFAULT_HOSTNAME="(none)"
# CONFIG_SYSVIPC is not set
CONFIG_SYSVIPC=y
CONFIG_SYSVIPC_SYSCTL=y
# CONFIG_POSIX_MQUEUE is not set
# CONFIG_WATCH_QUEUE is not set
# CONFIG_CROSS_MEMORY_ATTACH is not set
Expand Down Expand Up @@ -936,7 +937,12 @@ CONFIG_DUMMY_CONSOLE_ROWS=25
# end of Console display driver support
# end of Graphics support

# CONFIG_SOUND is not set
CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_VIRTIO=y
CONFIG_SND_VERBOSE_PRINTK=y
CONFIG_SND_DEBUG=y
CONFIG_SND_DEBUG_VERBOSE=y

#
# HID support
Expand Down
51 changes: 51 additions & 0 deletions device.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,53 @@ void clint_write(hart_t *vm,
uint8_t width,
uint32_t value);

/* VirtIO-Sound */

#if SEMU_HAS(VIRTIOSND)
#define IRQ_VSND 4
#define IRQ_VSND_BIT (1 << IRQ_VSND)

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

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

void virtio_snd_read(hart_t *core,
virtio_snd_state_t *vsnd,
uint32_t addr,
uint8_t width,
uint32_t *value);

void virtio_snd_write(hart_t *core,
virtio_snd_state_t *vsnd,
uint32_t addr,
uint8_t width,
uint32_t value);

bool virtio_snd_init(virtio_snd_state_t *vsnd);
#endif /* SEMU_HAS(VIRTIOSND) */

/* memory mapping */

typedef struct {
Expand All @@ -205,4 +252,8 @@ typedef struct {
virtio_blk_state_t vblk;
#endif
clint_state_t clint;
#if SEMU_HAS(VIRTIOSND)
virtio_snd_state_t vsnd;
#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_FEATURE_VIRTIONET 1
#endif

/* virtio-snd */
#ifndef SEMU_FEATURE_VIRTIOSND
#define SEMU_FEATURE_VIRTIOSND 1
#endif

/* Feature test macro */
#define SEMU_HAS(x) SEMU_FEATURE_##x
35 changes: 35 additions & 0 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,18 @@ static void emu_update_timer_interrupt(hart_t *hart)
clint_update_interrupts(hart, &data->clint);
}

#if SEMU_HAS(VIRTIOSND)
static void emu_update_vsnd_interrupts(vm_t *vm)
{
emu_state_t *data = PRIV(vm->hart[0]);
if (data->vsnd.InterruptStatus)
data->plic.active |= IRQ_VSND_BIT;
else
data->plic.active &= ~IRQ_VSND_BIT;
plic_update_interrupts(vm, &data->plic);
}
#endif

static void mem_load(hart_t *hart,
uint32_t addr,
uint8_t width,
Expand Down Expand Up @@ -121,6 +133,13 @@ static void mem_load(hart_t *hart,
clint_read(hart, &data->clint, addr & 0xFFFFF, width, value);
clint_update_interrupts(hart, &data->clint);
return;

#if SEMU_HAS(VIRTIOSND)
case 0x44: /* virtio-snd */
virtio_snd_read(hart, &data->vsnd, addr & 0xFFFFF, width, value);
emu_update_vsnd_interrupts(hart->vm);
return;
#endif
}
}
vm_set_exception(hart, RV_EXC_LOAD_FAULT, hart->exc_val);
Expand Down Expand Up @@ -166,6 +185,12 @@ static void mem_store(hart_t *hart,
clint_write(hart, &data->clint, addr & 0xFFFFF, width, value);
clint_update_interrupts(hart, &data->clint);
return;
#if SEMU_HAS(VIRTIOSND)
case 0x44: /* virtio-snd */
virtio_snd_write(hart, &data->vsnd, addr & 0xFFFFF, width, value);
emu_update_vsnd_interrupts(hart->vm);
return;
#endif
}
}
vm_set_exception(hart, RV_EXC_STORE_FAULT, hart->exc_val);
Expand Down Expand Up @@ -581,6 +606,11 @@ 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(VIRTIOSND)
if (!virtio_snd_init(&(emu.vsnd)))
fprintf(stderr, "No virtio-snd functioned\n");
emu.vsnd.ram = emu.ram;
#endif

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

#if SEMU_HAS(VIRTIOSND)
if (emu.vsnd.InterruptStatus)
emu_update_vsnd_interrupts(&vm);
#endif
}

emu_update_timer_interrupt(vm.hart[i]);
Expand Down
8 changes: 8 additions & 0 deletions minimal.dts
Original file line number Diff line number Diff line change
Expand Up @@ -63,5 +63,13 @@
interrupts = <3>;
};
#endif

#if SEMU_FEATURE_VIRTIOSND
snd0: virtio@4400000 {
compatible = "virtio,mmio";
reg = <0x4400000 0x200>;
interrupts = <4>;
};
#endif
};
};
35 changes: 35 additions & 0 deletions mk/check-libs.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Create a mininal ALSA program
define create-alsa-prog
echo '\
#include <alsa/asoundlib.h>\n\
int main(){\n\
snd_pcm_t *pcm;\n\
snd_pcm_open(&pcm, "default", SND_PCM_STREAM_PLAYBACK, 0);\n\
snd_pcm_close(pcm);\n\
return 0;\n\
}\n'
endef

# Create a mininal Core Audio program
define create-coreaudio-prog
echo '\
#include <CoreAudio/CoreAudio.h>\n\
int main(){\n\
AudioComponent comp;\n\
comp = AudioComponentFindNext(NULL, &desc);\n\
if (comp == NULL) exit (-1);\n\
return 0;\n\
}\n'
endef

# Check ALSA installation
define check-alsa
$(shell $(call create-alsa-prog) | $(CC) -x c -lasound -o /dev/null > /dev/null 2> /dev/null -
&& echo $$?)
endef

# Check Core Audio installation
define check-coreaudio
$(shell $(call create-coreaudio-prog) | $(CC) -x c -framework CoreAudio -o /dev/null > /dev/null 2> /dev/null -
&& echo $$?)
endef
Loading

0 comments on commit 5251ec6

Please sign in to comment.