Skip to content

Commit ecd3666

Browse files
examples/eth_driver_vm: init
Signed-off-by: Bill Nguyen <bill.nguyen@student.unsw.edu.au>
1 parent a4c2f5d commit ecd3666

11 files changed

Lines changed: 12438 additions & 0 deletions

File tree

examples/eth_driver_vm/Makefile

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#
2+
# Copyright 2025, UNSW
3+
#
4+
# SPDX-License-Identifier: BSD-2-Clause
5+
#
6+
7+
BUILD_DIR ?= build
8+
export MICROKIT_CONFIG ?= debug
9+
10+
ifeq ($(strip $(MICROKIT_SDK)),)
11+
$(error MICROKIT_SDK must be specified)
12+
endif
13+
override MICROKIT_SDK := $(abspath $(MICROKIT_SDK))
14+
15+
ifeq ($(strip $(MICROKIT_BOARD)),)
16+
$(error MICROKIT_BOARD must be specified)
17+
endif
18+
19+
export BUILD_DIR := $(abspath $(BUILD_DIR))
20+
export EXAMPLE_DIR := $(abspath .)
21+
22+
export TARGET := aarch64-none-elf
23+
export CC := clang
24+
export LD := ld.lld
25+
export AS := llvm-as
26+
export AR := llvm-ar
27+
export DTC := dtc
28+
export RANLIB := llvm-ranlib
29+
export MICROKIT_TOOL ?= $(MICROKIT_SDK)/bin/microkit
30+
export SDDF := $(abspath ../../dep/sddf)
31+
export LIBVMM := $(abspath ../../)
32+
export LIBVMM_TOOLS := ${LIBVMM}/tools
33+
export CC_USERLEVEL := zig cc
34+
35+
IMAGE_FILE := $(BUILD_DIR)/loader.img
36+
REPORT_FILE := $(BUILD_DIR)/report.txt
37+
38+
export ECHO_INCLUDE := $(SDDF)/examples/echo_server/include
39+
40+
all: $(IMAGE_FILE)
41+
42+
$(IMAGE_FILE) $(REPORT_FILE) clean clobber: $(BUILD_DIR)/Makefile FORCE
43+
$(MAKE) -C $(BUILD_DIR) MICROKIT_SDK=$(MICROKIT_SDK) $(notdir $@)
44+
45+
$(BUILD_DIR)/Makefile: echo.mk
46+
mkdir -p $(BUILD_DIR)
47+
cp echo.mk $@
48+
49+
FORCE:

examples/eth_driver_vm/README.md

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
<!--
2+
Copyright 2025, UNSW
3+
SPDX-License-Identifier: CC-BY-SA-4.0
4+
-->
5+
6+
# Ethernet Driver VM Example
7+
8+
This example demonstrates an Ethernet driver VM running with sDDF's echo server on the Odroid C4. It is
9+
a shallow copy that only contains files that needs to be modified to accomodate the Ethernet driver
10+
VM.
11+
12+
The only files that we copied from the echo server is `echo.mk` and `meta.py` to accomodate the VM.
13+
14+
The idea is we have a userspace program in Linux that converts sDDF's network TX/RX into
15+
corresponding syscalls in a Linux raw socket.
16+
- The sDDF network control, data regions and notification from virtualisers are mapped into Linux
17+
userspace via UIO.
18+
- A promiscuous socket is opened to sniff all incoming frames. When a frame comes through from the
19+
socket, we enqueue the data into the appropriate sDDF queues and fault on a pre-determined address
20+
so the VMM can notify the RX virtualiser.
21+
- When a client wants to transmit data, we will get TX virt notifications via UIO, then we simply
22+
write the data out into the socket.
23+
24+
Even though we already have a native Ethernet driver for Odroid C4, this example is still useful as
25+
it could be used to provide Ethernet driver VM on new boards or further developed into a
26+
WiFi/Cellular/Bluetooth driver VM.
27+
28+
The example currently works on the following platforms:
29+
* HardKernel Odroid-C4
30+
31+
Things to note when using the network UIO driver:
32+
- You need to map in the control queues as uncached in the guest and native virtualisers. This is
33+
because Linux treats UIO regions as device memory thus map them uncached to userspace.
34+
35+
## Compilation
36+
To compile this example, run:
37+
```
38+
make MICROKIT_SDK=<absolute path to SDK> MICROKIT_BOARD=odroidc4 MICROKIT_CONFIG=release
39+
```
40+
41+
### Boot
42+
On a successful boot, your console will look like this:
43+
```
44+
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
45+
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
46+
2: eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc mq qlen 1000
47+
link/ether 00:1e:06:4a:35:e4 brd ff:ff:ff:ff:ff:ff
48+
[ 3.716293] meson8b-dwmac ff3f0000.ethernet eth0: Link is Up - 1Gbps/Full - flow control off
49+
[ 5.753497] random: crng init done
50+
UIO(NET): *** Starting up
51+
UIO(NET): *** Network interface: eth0
52+
UIO(NET): *** Setting up raw promiscuous socket
53+
[ 10.669821] meson8b-dwmac ff3f0000.ethernet eth0: entered promiscuous mode
54+
UIO(NET): *** Creating epoll
55+
UIO(NET): *** Binding socket to epoll
56+
UIO(NET): *** Setting up data passing page via UIO
57+
UIO(NET): -> mapped device 'uio0' with size 0x1000 @ 0xffff8454d000
58+
UIO(NET): -> rx data paddr = 0x5feff000
59+
UIO(NET): -> tx client #0 data paddr = 0x5fdff000
60+
UIO(NET): -> tx client #1 data paddr = 0x5fcff000
61+
UIO(NET): *** Setting up in sDDF net control queues
62+
UIO(NET): -> mapped device 'uio1' with size 0x3000 @ 0xffff8454a000
63+
UIO(NET): -> mapped device 'uio3' with size 0x3000 @ 0xffff84547000
64+
UIO(NET): -> mapped device 'uio2' with size 0x5000 @ 0xffff84542000
65+
UIO(NET): -> mapped device 'uio4' with size 0x5000 @ 0xffff8453d000
66+
UIO(NET): *** Setting up TX/RX fault mechanism for guest -> VMM notifications
67+
UIO(NET): -> mapped device 'uio5' with size 0x1000 @ 0xffff8453c000
68+
UIO(NET): -> mapped device 'uio6' with size 0x1000 @ 0xffff8453b000
69+
UIO(NET): *** Setting up TX/RX UIO IRQs for VMM -> guest notifications
70+
UIO(NET): *** Binding UIO TX and RX incoming interrupts to epoll
71+
UIO(NET): *** Setting up in sDDF net data queues
72+
UIO(NET): -> mapped device 'uio9' with size 0x100000 @ 0xffff8443b000
73+
UIO(NET): -> mapped device 'uio10' with size 0x200000 @ 0xffff8423b000
74+
UIO(NET): *** All initialisation successful, now sending all pending TX active before we block on events
75+
UIO(NET): *** All pending TX active have been sent thru the raw sock, entering event loop now.
76+
UIO(NET): *** You won't see any output from UIO Net anymore. Unless there is a warning or error.
77+
DHCP request finished, IP address for netif client0 is: 172.16.1.91
78+
DHCP request finished, IP address for netif client1 is: 172.16.1.90
79+
```
80+
81+
Though the MAC, IP and memory addreses would be different of course. There will be delay in the tens
82+
of seconds between the Linux userspace network driver initialisation and lwIP DHCP completion. This
83+
is due to all the components being able to initialise first before the guest can get to userspace.
84+
So lwIP will send many DHCP requests without success, with increasing timeout for each request.
85+
86+
## Future work
87+
- Support more platforms.
88+
- Fix the avalance of:
89+
`<<seL4(CPU 0) [handleInterruptEntry/56 T0x8003849400 "net_driver_vm" @20c0fc]: Spurious interrupt!>>`
90+
on debug config.
91+
- Further minimise the Linux kernel. I've reduced the kernel size to only 12.5MiB by disabling most
92+
drivers. Though there are room to push it further by disabling more features that we don't need.
93+
- Move the UIO driver into a kernel module or use iouring to reduce the context switch cost every
94+
time we send or receive a frame.
95+
- (Tying into previous) Move away from UIO, which allow us to use SIMD instructions for faster
96+
memory operations in the driver. I mentioned this as the network queue entry size isn't a power of
97+
2, so clang always generate vector loads and stores to speed things up. Which has to be disabled
98+
to make UIO happy.
99+
- Investigate mapping the queue and data regions as cached.
100+
- Properly implement WFI/WFE in libvmm so we correctly measure CPU utilisation.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<!--
2+
Copyright 2024, UNSW
3+
SPDX-License-Identifier: CC-BY-SA-4.0
4+
-->
5+
6+
# Odroid-C4 images
7+
8+
## Linux kernel
9+
10+
### Details
11+
* Image name: `linux`
12+
* Config name: `linux_config`
13+
* Git remote: https://github.com/torvalds/linux.git
14+
* Tag: v6.17 (commit hash: `e5f0a698b34ed76002dc5cff3804a61c80233a7a`)
15+
* Toolchain: `aarch64-none-elf`
16+
* Version: (Arm GNU Toolchain 12.2.Rel1 (Build arm-12.24)) 12.2.1 20221205
17+
18+
You can also get the Linux config used after booting by running the following
19+
command in userspace: `zcat /proc/config.gz`.
20+
21+
### Instructions for reproducing
22+
23+
```
24+
git clone --depth 1 --branch v6.17 https://github.com/torvalds/linux.git
25+
cp linux_config linux/.config
26+
make -C linux ARCH=arm64 CROSS_COMPILE=aarch64-none-elf- linux_config all -j$(nproc)
27+
```
28+
29+
The path to the image will be: `linux/arm64/boot/Image`.
30+
31+
## Buildroot RootFS image
32+
33+
Note that buildoot currently does not list a configuration for OdroidC4 so we just
34+
use the OdroidC2 configuration with `ethtool` enabled.

0 commit comments

Comments
 (0)