Skip to content
Draft
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
32 changes: 31 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,37 @@ ifeq ($(call has, VIRTIOGPU), 1)
OBJS_EXTRA += vgpu-display.o
endif

# console
SEMU_CONSOLE ?= both
SEMU_CONSOLE := $(strip $(SEMU_CONSOLE))
override ENABLE_VIRTIOCONSOLE := 0
override ENABLE_UART8250 := 0
ifeq ($(SEMU_CONSOLE),virtio)
override ENABLE_VIRTIOCONSOLE := 1
else ifeq ($(SEMU_CONSOLE),both)
override ENABLE_VIRTIOCONSOLE := 1
override ENABLE_UART8250 := 1
else ifeq ($(SEMU_CONSOLE),uart8250)
override ENABLE_UART8250 := 1
else ifeq ($(SEMU_CONSOLE),uart)
override ENABLE_UART8250 := 1
else
$(error SEMU_CONSOLE must be virtio, uart8250, or both)
endif

$(call set-feature, VIRTIOCONSOLE)
$(call set-feature, UART8250)

ifeq ($(call has, VIRTIOCONSOLE), 1)
OBJS_EXTRA += virtio-console.o
VIRTIO_CONSOLE_PATH ?= /tmp/semu-hvc0
OPTS += --virtio-console-path $(VIRTIO_CONSOLE_PATH)
endif

ifeq ($(call has, UART8250), 1)
OBJS_EXTRA += uart.o
endif

ifneq ($(filter 1,$(call has, VIRTIOGPU) $(call has, VIRTIOINPUT)),)
OBJS_EXTRA += window-sw.o
endif
Expand All @@ -227,7 +258,6 @@ OBJS := \
ram.o \
utils.o \
plic.o \
uart.o \
main.o \
aclint.o \
coro.o \
Expand Down
37 changes: 34 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ A minimalist RISC-V system emulator capable of running Linux the kernel and corr
- Privilege levels: S and U modes
- Control and status registers (CSR)
- Virtual memory system: RV32 MMU
- UART: 8250/16550
- UART: 8250/16550 console
- PLIC (platform-level interrupt controller): 32 interrupts, no priority
- Standard SBI, with the timer extension
- I/O support using VirtIO standard:
- virtio-blk acquires disk image from the host.
- virtio-console exposes an additional guest console as `/dev/hvc0`.
- virtio-net is mapped as TAP interface.
- virtio-snd uses [PortAudio](https://github.com/PortAudio/portaudio) for sound playback on the host with one limitations:
- As some unknown issues in guest Linux OS (confirmed in v6.7 and v6.12), you need
Expand Down Expand Up @@ -67,7 +68,7 @@ With the default external-root build, `make check` uses `Image`, `minimal.dtb`,
and `ext4.img`, and boots `semu` headlessly with an equivalent command line:

```shell
$ ./semu -k Image -c 1 -b minimal.dtb -H -d ext4.img
$ ./semu -k Image -c 1 -b minimal.dtb -H -d ext4.img --virtio-console-path /tmp/semu-hvc0
```

If `ENABLE_EXTERNAL_ROOT=0` is used, `make check` switches to the legacy
Expand All @@ -90,6 +91,33 @@ Enter `root` to access shell.

You can exit the emulator using: \<Ctrl-a x\>. (press Ctrl+A, leave it, afterwards press X)

By default, `make check` enables both the 8250 UART console and
virtio-console. The UART is the primary console, so boot logs and the main
login prompt appear in the terminal that ran `make check`. The virtio-console
device is also exposed to the guest as `/dev/hvc0`, and `make check` creates a
host endpoint at `/tmp/semu-hvc0`.

Open another host terminal to attach to the virtio-console:

```shell
$ screen /tmp/semu-hvc0
```

Inside the guest, confirm both consoles are active with:

```shell
# cat /proc/consoles
# grep hvc0 /etc/inittab
```

To use only one console implementation at build time, override
`SEMU_CONSOLE`:

```shell
$ make check SEMU_CONSOLE=uart8250
$ make check SEMU_CONSOLE=virtio
```

To test virtio-gpu with a visible SDL window, run `semu` manually without `-H`.
Make sure `sdl2-config` is in `PATH`, then build the emulator, DTB, kernel, and
test tools disk. Press `Ctrl+Alt+G` to release the mouse cursor from the SDL
Expand Down Expand Up @@ -119,7 +147,7 @@ project and can be listed in the guest with:
## Usage

```shell
./semu -k linux-image [-b dtb-file] [-d disk-image] [-i initrd-image] [-s shared-directory] [-H]
./semu -k linux-image [-b dtb-file] [-d disk-image] [-i initrd-image] [-s shared-directory] [-H] [--virtio-console-path path]
```

* `linux-image` is the path to the Linux kernel `Image`.
Expand All @@ -129,6 +157,9 @@ project and can be listed in the guest with:
from `rootfs.cpio` via `scripts/rootfs_ext4.sh`.
* `shared-directory` is optional, as it specifies the path of a directory on the host that will be shared with the guest operating system through virtio-fs, enabling file access from the guest via a virtual filesystem mount.
* `-H` (or `--headless`) skips SDL window creation; useful for CI and `make check`.
* `virtio-console-path` is optional, as it creates a host-side symlink to the
pseudo-terminal connected to the guest `/dev/hvc0`. The default used by
`make check` is `/tmp/semu-hvc0`.
* `initrd-image` is optional and only used on the *legacy* boot path.
The default `minimal.dtb` built with `ENABLE_EXTERNAL_ROOT=1` does not
advertise initrd placement, so `-i` there requires either
Expand Down
1 change: 1 addition & 0 deletions configs/buildroot.config
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,5 @@ BR2_TARGET_ROOTFS_CPIO_FULL=y
# BR2_TARGET_ROOTFS_CPIO_DRACUT is not set
BR2_TARGET_ROOTFS_CPIO_NONE=y
# BR2_TARGET_ROOTFS_TAR is not set
BR2_ROOTFS_POST_BUILD_SCRIPT="../target/post-build.sh"
BR2_PACKAGE_BUSYBOX_CONFIG="busybox.config"
2 changes: 1 addition & 1 deletion configs/linux.config
Original file line number Diff line number Diff line change
Expand Up @@ -834,7 +834,7 @@ CONFIG_SERIAL_CORE_CONSOLE=y
# CONFIG_NULL_TTY is not set
# CONFIG_SERIAL_DEV_BUS is not set
# CONFIG_TTY_PRINTK is not set
# CONFIG_VIRTIO_CONSOLE is not set
CONFIG_VIRTIO_CONSOLE=y
# CONFIG_IPMI_HANDLER is not set
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_VIRTIO=y
Expand Down
56 changes: 56 additions & 0 deletions device.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ void plic_write(hart_t *core,
uint32_t value);
/* UART */

#if SEMU_HAS(UART8250)

#define IRQ_UART 1
#define IRQ_UART_BIT (1 << IRQ_UART)

Expand Down Expand Up @@ -85,6 +87,7 @@ void u8250_write(hart_t *core,
void u8250_check_ready(u8250_state_t *uart);
void u8250_flush_out(u8250_state_t *uart);
void capture_keyboard_input();
#endif /* SEMU_HAS(UART8250) */

/* virtio-net */

Expand Down Expand Up @@ -347,6 +350,54 @@ uint32_t virtio_gpu_register_scanout(virtio_gpu_state_t *vgpu,
uint32_t height);
#endif /* SEMU_HAS(VIRTIOGPU) */

/* VirtIO-Console */

#if SEMU_HAS(VIRTIOCONSOLE)

#define IRQ_VCONSOLE 10
#define IRQ_VCONSOLE_BIT (1 << IRQ_VCONSOLE)

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

typedef struct {
/* feature negotiation */
uint32_t DeviceFeaturesSel;
uint32_t DriverFeatures;
uint32_t DriverFeaturesSel;
/* queue config */
uint32_t QueueSel;
virtio_console_queue_t queues[2];
/* status */
uint32_t Status;
uint32_t InterruptStatus;
/* supplied by environment */
uint32_t *ram;
int in_fd;
int out_fd;
} virtio_console_state_t;

void virtio_console_read(hart_t *core,
virtio_console_state_t *vcon,
uint32_t addr,
uint8_t width,
uint32_t *value);
void virtio_console_write(hart_t *core,
virtio_console_state_t *vcon,
uint32_t addr,
uint8_t width,
uint32_t value);
void virtio_console_init(virtio_console_state_t *vcon);
void virtio_console_refresh_rx(virtio_console_state_t *vcon);

#endif /* SEMU_HAS(VIRTIOCONSOLE) */

/* ACLINT MTIMER */
typedef struct {
/* A MTIMER device has two separate base addresses: one for the MTIME
Expand Down Expand Up @@ -558,7 +609,9 @@ typedef struct {
uint32_t *disk;
vm_t vm;
plic_state_t plic;
#if SEMU_HAS(UART8250)
u8250_state_t uart;
#endif
#if SEMU_HAS(VIRTIONET)
virtio_net_state_t vnet;
#endif
Expand All @@ -581,6 +634,9 @@ typedef struct {
#if SEMU_HAS(VIRTIOGPU)
virtio_gpu_state_t vgpu;
#endif
#if SEMU_HAS(VIRTIOCONSOLE)
virtio_console_state_t vconsole;
#endif
#if SEMU_HAS(VIRTIOINPUT) || SEMU_HAS(VIRTIOGPU)
/* Use self-pipe trick to unblock the emulator loop when the window backend
* has queued work, such as input events or window shutdown. When all harts
Expand Down
10 changes: 10 additions & 0 deletions feature.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,15 @@
#define SEMU_FEATURE_VIRTIOGPU 1
#endif

/* virtio-console */
#ifndef SEMU_FEATURE_VIRTIOCONSOLE
#define SEMU_FEATURE_VIRTIOCONSOLE 1
#endif

/* 8250/16550 UART console */
#ifndef SEMU_FEATURE_UART8250
#define SEMU_FEATURE_UART8250 0
#endif

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