Skip to content
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

Audio passthrough example #32

Open
wants to merge 8 commits into
base: main
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
147 changes: 147 additions & 0 deletions examples/audio/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
#
# Copyright 2021, Breakaway Consulting Pty. Ltd.
# Copyright 2022, UNSW (ABN 57 195 873 179)
#
# SPDX-License-Identifier: BSD-2-Clause
#

ifeq ($(strip $(MICROKIT_SDK)),)
$(error MICROKIT_SDK must be specified)
endif

ifeq ($(strip $(BOARD)),)
$(error BOARD must be specified)
endif

# Default build directory, pass BUILD_DIR=<dir> to override
BUILD_DIR ?= build
# Default config is a debug build, pass CONFIG=<debug/release/benchmark> to override
CONFIG ?= debug

# @ivanv: Check for dependencies and make sure they are installed/in the path

# @ivanv: check that all dependencies exist
# Specify that we use bash for all shell commands
SHELL=/bin/bash
# All dependencies needed to compile the VMM
QEMU := qemu-system-aarch64
QEMU_SND_BACKEND := pipewire
DTC := dtc

# ifndef TOOLCHAIN
# # Get whether the common toolchain triples exist
# TOOLCHAIN_AARCH64_LINUX_GNU := $(shell command -v aarch64-linux-gnu-gcc 2> /dev/null)
# TOOLCHAIN_AARCH64_UNKNOWN_LINUX_GNU := $(shell command -v aarch64-unknown-linux-gnu-gcc 2> /dev/null)
# # Then check if they are defined and select the appropriate one
# ifdef TOOLCHAIN_AARCH64_LINUX_GNU
# TOOLCHAIN := aarch64-linux-gnu
# else ifdef TOOLCHAIN_AARCH64_UNKNOWN_LINUX_GNU
# TOOLCHAIN := aarch64-unknown-linux-gnu
# else
# $(error "Could not find an AArch64 cross-compiler")
# endif
# endif

CC := clang
LD := ld.lld
MICROKIT_TOOL ?= $(MICROKIT_SDK)/bin/microkit

# @ivanv: need to have a step for putting in the initrd node into the DTB,
# right now it is unfortunately hard-coded.

# @ivanv: check that the path of SDK_PATH/BOARD exists
# @ivanv: Have a list of supported boards to check with, if it's not one of those
# have a helpful message that lists all the support boards.

# @ivanv: incremental builds don't work with IMAGE_DIR changing

BOARD_DIR := $(MICROKIT_SDK)/board/$(BOARD)/$(CONFIG)
VMM := ../../
VMM_TOOLS := $(VMM)/tools
VMM_SRC_DIR := $(VMM)/src
SYSTEM_DESCRIPTION := board/$(BOARD)/audio.system

IMAGE_DIR := board/$(BOARD)
LINUX := $(IMAGE_DIR)/linux
DTS := $(IMAGE_DIR)/linux.dts
DTB := $(BUILD_DIR)/linux.dtb
INITRD := $(IMAGE_DIR)/rootfs.cpio.gz

ELFS := vmm.elf

IMAGE_FILE = $(BUILD_DIR)/loader.img
REPORT_FILE = $(BUILD_DIR)/report.txt

# @ivanv: should only compile printf.o in debug
VMM_OBJS := vmm.o printf.o virq.o linux.o guest.o psci.o smc.o fault.o util.o vgic.o vgic_v2.o package_guest_images.o tcb.o vcpu.o

# Toolchain flags
# FIXME: For optimisation we should consider providing the flag -mcpu.
# FIXME: We should also consider whether -mgeneral-regs-only should be
# used to avoid the use of the FPU and therefore seL4 does not have to
# context switch the FPU.
# Note we only need -Wno-unused-command-line-argument because in Nix
# passes an extra `--gcc-toolchain` flag which we do not need.
CFLAGS := -mstrict-align \
-g3 \
-O3 \
-ffreestanding \
-nostdlib \
-Wno-unused-command-line-argument \
-Wall -Wno-unused-function -Werror \
-I$(VMM_SRC_DIR)/arch/aarch64 -I$(VMM_SRC_DIR) -I$(VMM_SRC_DIR)/util -I$(BOARD_DIR)/include \
-DBOARD_$(BOARD) \
-DCONFIG_$(CONFIG) \
-target aarch64-none-elf

LDFLAGS := -L$(BOARD_DIR)/lib
LIBS := -lmicrokit -Tmicrokit.ld

all: directories $(IMAGE_FILE)

qemu: all
if ! command -v $(QEMU) &> /dev/null; then echo "Could not find dependency: qemu-system-aarch64"; exit 1; fi
$(QEMU) -machine virt,virtualization=on,secure=off \
-cpu cortex-a53 \
-serial mon:stdio \
-device loader,file=$(IMAGE_FILE),addr=0x70000000,cpu-num=0 \
-audio driver=$(QEMU_SND_BACKEND),model=hda,id=$(QEMU_SND_BACKEND) \
-m size=2G \
-nographic

directories:
$(shell mkdir -p $(BUILD_DIR))

$(DTB): $(DTS)
if ! command -v $(DTC) &> /dev/null; then echo "Could not find dependency: Device Tree Compiler (dtc)"; exit 1; fi
# @ivanv: Shouldn't supress warnings
$(DTC) -q -I dts -O dtb $< > $@

$(BUILD_DIR)/package_guest_images.o: $(VMM_TOOLS)/package_guest_images.S $(IMAGE_DIR) $(LINUX) $(INITRD) $(DTB)
$(CC) -c -g3 -x assembler-with-cpp \
-DGUEST_KERNEL_IMAGE_PATH=\"$(LINUX)\" \
-DGUEST_DTB_IMAGE_PATH=\"$(DTB)\" \
-DGUEST_INITRD_IMAGE_PATH=\"$(INITRD)\" \
-target aarch64-none-elf \
$< -o $@

$(BUILD_DIR)/%.o: %.c Makefile
$(CC) -c $(CFLAGS) $< -o $@

$(BUILD_DIR)/%.o: $(VMM_SRC_DIR)/%.c Makefile
$(CC) -c $(CFLAGS) $< -o $@

$(BUILD_DIR)/%.o: $(VMM_SRC_DIR)/util/%.c Makefile
$(CC) -c $(CFLAGS) $< -o $@

$(BUILD_DIR)/%.o: $(VMM_SRC_DIR)/arch/aarch64/%.c Makefile
$(CC) -c $(CFLAGS) $< -o $@

$(BUILD_DIR)/%.o: $(VMM_SRC_DIR)/arch/aarch64/vgic/%.c Makefile
$(CC) -c $(CFLAGS) $< -o $@

$(BUILD_DIR)/vmm.elf: $(addprefix $(BUILD_DIR)/, $(VMM_OBJS))
$(LD) $(LDFLAGS) $^ $(LIBS) -o $@

$(IMAGE_FILE) $(REPORT_FILE): $(addprefix $(BUILD_DIR)/, $(ELFS)) $(SYSTEM_DESCRIPTION) $(IMAGE_DIR)
$(MICROKIT_TOOL) $(SYSTEM_DESCRIPTION) --search-path $(BUILD_DIR) $(IMAGE_DIR) --board $(BOARD) --config $(CONFIG) -o $(IMAGE_FILE) -r $(REPORT_FILE)
38 changes: 38 additions & 0 deletions examples/audio/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# A VMM example for pass-through audio in Linux

This example is a minimal VMM that supports Linux guests and a basic
buildroot/BusyBox root file system. This gives a basic command-line with some
common Linux utilities.

The example currently works on the following platforms:
* QEMU ARM virt

## Building with Make

```sh
make BOARD=<BOARD> MICROKIT_SDK=/path/to/sdk
```

Where `<BOARD>` is one of:
* `qemu_arm_virt`
* `odroidc4`

Other configuration options can be passed to the Makefile such as `CONFIG`
and `BUILD_DIR`, see the Makefile for details.

If you would like to simulate the QEMU board you can run the following command:
```sh
make BOARD=qemu_arm_virt MICROKIT_SDK=/path/to/sdk qemu
```

This will build the example code as well as run the QEMU command to simulate a
system running the whole system.


## Playing audio

Guest username is `root`.
```
alsactl init -U
play CantinaBand3.wav
```
47 changes: 47 additions & 0 deletions examples/audio/board/odroidc4/audio.system
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2022, UNSW (ABN 57 195 873 179)

SPDX-License-Identifier: BSD-2-Clause
-->
<system>
<!-- We allocate 256MiB of RAM for the guest. -->
<memory_region name="guest_ram" size="0x10_000_000" phys_addr="0x20000000" page_size="0x200_000" />
<memory_region name="bus1" size="0x200000" phys_addr="0xff600000" />
<memory_region name="bus2" size="0x200000" phys_addr="0xff800000" />
<memory_region name="bus3" size="0x100000" phys_addr="0xffd00000" />
<memory_region name="gic_vcpu" size="0x1_000" phys_addr="0xffc06000" />

<memory_region name="usb_ctrl" size="0x1_000" phys_addr="0xffe09000" />
<memory_region name="usb_1" size="0x40000" phys_addr="0xff400000" />
<memory_region name="usb_2" size="0x100000" phys_addr="0xff500000" />

<protection_domain name="VMM" priority="254">
<program_image path="vmm.elf" />
<map mr="guest_ram" vaddr="0x20000000" perms="rw" setvar_vaddr="guest_ram_vaddr" />
<virtual_machine name="linux" id="0">
<map mr="guest_ram" vaddr="0x20000000" perms="rwx" />
<map mr="bus1" vaddr="0xff600000" perms="rw" cached="false" />
<map mr="bus2" vaddr="0xff800000" perms="rw" cached="false" />
<map mr="bus3" vaddr="0xffd00000" perms="rw" cached="false" />
<map mr="gic_vcpu" vaddr="0xffc02000" perms="rw" cached="false" />

<map mr="usb_ctrl" vaddr="0xffe09000" perms="rw" cached="false" />
<map mr="usb_1" vaddr="0xff400000" perms="rw" cached="false" />
<map mr="usb_2" vaddr="0xff500000" perms="rw" cached="false" />

</virtual_machine>
<!-- Serial IRQ -->
<irq irq="225" id="1" trigger="edge" />

<!-- USB -->
<irq irq="48" id="2" trigger="level" /> <!-- Controller -->
<irq irq="63" id="3" trigger="level" /> <!-- USB 1 -->
<irq irq="62" id="4" trigger="level" /> <!-- USB 2 -->

<!-- @alexbr: not sure what this is -->
<irq irq="5" id="5" trigger="level" />

</protection_domain>
</system>

Binary file added examples/audio/board/odroidc4/linux
Binary file not shown.
Loading
Loading