Skip to content

Commit a862132

Browse files
committed
Trap guestOS to run SDL-oriented applications
To trap the guest OS SDL applications, virtual memory translation should be handled when accessing the bidirectional event queues in syscall_sdl.c. Additionally, when using the guest OS, the SDL application might be launched and terminated multiple times. To enhance the user experience, it is heuristic to properly handle three main types of exits: 1, SDL application built-in exit: The source code of the SDL application should be modified to call the syscall_exit(syscall number: 93) somewhere when executing cleanup routine before exit(). 2. Ctrl-c (SIGINT) exit: Detect the ctrl-c keycode. 3. SDL window Quit event: The source code of the SDL application should be modified to call the syscall_exit(syscall number: 93) when receiving SDL window Quit event. The main reason for handling these three types of exits is that SDL2_Mixer may malfunction if not properly initialized and destroyed, as it runs on the host side not on the guest side. Additionally, when terminating an SDL application in the guest OS, the previous SDL window should be closed. Moreover, the default audio backend of SDL2_Mixer(downloadable from brew or Linux distro pkg managers), FluidSynth, occasionally generates the warning: "fluidsynth: warning: Ringbuffer full, try increasing synth.polyphony!" This issue causes the audio to hang, leading to an unstable playback experience. Thus, dropping FluidSynth in favor of the Timidity backend, which provides a stable audio playback experience. Known issue: Calling SDL_DestroyWindow() on macOS does not close the previous SDL window. Close: #510
1 parent 80658a8 commit a862132

File tree

7 files changed

+259
-30
lines changed

7 files changed

+259
-30
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ endif
175175
$(call set-feature, SDL)
176176
ifeq ($(call has, SDL), 1)
177177
OBJS_EXT += syscall_sdl.o
178-
$(OUT)/syscall_sdl.o: CFLAGS += $(shell sdl2-config --cflags)
178+
CFLAGS += $(shell sdl2-config --cflags)
179179
# 4 GiB of memory is required to run video games.
180180
ENABLE_FULL4G := 1
181181
LDFLAGS += $(shell sdl2-config --libs) -pthread

src/devices/uart.c

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,14 @@
1111
#include <string.h>
1212
#include <unistd.h>
1313

14-
#include "uart.h"
14+
#if RV32_HAS(SDL) && RV32_HAS(SYSTEM) && !RV32_HAS(ELF_LOADER)
15+
#include <SDL.h>
16+
#include <SDL_mixer.h>
17+
18+
#include "utils.h"
19+
#endif
1520

21+
#include "uart.h"
1622
/* Emulate 8250 (plain, without loopback mode support) */
1723

1824
#define U8250_INTR_THRE 1
@@ -66,9 +72,37 @@ static uint8_t u8250_handle_in(u8250_state_t *uart)
6672
if (value == 1) { /* start of heading (Ctrl-a) */
6773
if (getchar() == 120) { /* keyboard x */
6874
printf("\n"); /* end emulator with newline */
69-
exit(0);
75+
exit(EXIT_SUCCESS);
76+
}
77+
}
78+
79+
#if RV32_HAS(SDL) && RV32_HAS(SYSTEM) && !RV32_HAS(ELF_LOADER)
80+
/*
81+
* The guestOS may repeatedly open and close the SDL window,
82+
* and the user could close the application by pressing the ctrl-c key.
83+
* Need to trap the ctrl-c key and ensure the SDL window and
84+
* SDL mixer are destroyed properly.
85+
*/
86+
SDL_VIDEO_AUDIO_DECL();
87+
extern bool audio_init;
88+
if (value == 3 /* ctrl-c */ && window) {
89+
bool sfx_or_music_thread_init = sfx_thread_init | music_thread_init;
90+
SDL_VIDEO_AUDIO_CLEANUP(window, shutdown_audio,
91+
sfx_or_music_thread_init);
92+
93+
/*
94+
* The sfx_or_music_init flag might not be set if a quick ctrl-c
95+
* occurs while the audio configuration is being initialized.
96+
* Therefore, need to destroy the audio settings by checking
97+
* audio_init flag.
98+
*/
99+
if (!sfx_or_music_thread_init && audio_init) {
100+
Mix_CloseAudio();
101+
Mix_Quit();
102+
audio_init = false;
70103
}
71104
}
105+
#endif
72106

73107
return value;
74108
}

src/emulate.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1299,7 +1299,22 @@ void ecall_handler(riscv_t *rv)
12991299
syscall_handler(rv);
13001300
#elif RV32_HAS(SYSTEM)
13011301
if (rv->priv_mode == RV_PRIV_U_MODE) {
1302-
SET_CAUSE_AND_TVAL_THEN_TRAP(rv, ECALL_U, 0);
1302+
switch (rv_get_reg(
1303+
rv,
1304+
rv_reg_a7)) { /* trap guestOS's SDL-oriented application syscall */
1305+
case 0xBEEF:
1306+
case 0xC0DE:
1307+
case 0xFEED:
1308+
case 0xBABE:
1309+
case 0xD00D:
1310+
case 93:
1311+
syscall_handler(rv);
1312+
rv->PC += 4;
1313+
break;
1314+
default:
1315+
SET_CAUSE_AND_TVAL_THEN_TRAP(rv, ECALL_U, 0);
1316+
break;
1317+
}
13031318
} else if (rv->priv_mode ==
13041319
RV_PRIV_S_MODE) { /* trap to SBI syscall handler */
13051320
rv->PC += 4;

src/syscall.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
#include <string.h>
1111
#include <sys/time.h>
1212

13+
#if RV32_HAS(SDL) && RV32_HAS(SYSTEM) && !RV32_HAS(ELF_LOADER)
14+
#include <SDL.h>
15+
#endif
16+
1317
#include "riscv.h"
1418
#include "riscv_private.h"
1519
#include "utils.h"
@@ -132,9 +136,24 @@ static void syscall_write(riscv_t *rv)
132136
rv_set_reg(rv, rv_reg_a0, -1);
133137
}
134138

135-
136139
static void syscall_exit(riscv_t *rv)
137140
{
141+
#if RV32_HAS(SDL) && RV32_HAS(SYSTEM) && !RV32_HAS(ELF_LOADER)
142+
/*
143+
* The guestOS may repeatedly open and close the SDL window,
144+
* and the user could close the application using the application’s
145+
* built-in exit function. Need to trap the built-in exit and
146+
* ensure the SDL window and SDL mixer are destroyed properly.
147+
*/
148+
SDL_VIDEO_AUDIO_DECL();
149+
if (window) {
150+
bool sfx_or_music_thread_init = sfx_thread_init | music_thread_init;
151+
SDL_VIDEO_AUDIO_CLEANUP(window, shutdown_audio,
152+
sfx_or_music_thread_init);
153+
return;
154+
}
155+
#endif
156+
138157
/* simply halt cpu and save exit code.
139158
* the application decides the usage of exit code
140159
*/

0 commit comments

Comments
 (0)