Skip to content

Commit 801ff1a

Browse files
pm215awojasinski
authored andcommitted
semihosting: Allow optional use of semihosting from userspace
Currently our semihosting implementations generally prohibit use of semihosting calls in system emulation from the guest userspace. This is a very long standing behaviour justified originally "to provide some semblance of security" (since code with access to the semihosting ABI can do things like read and write arbitrary files on the host system). However, it is sometimes useful to be able to run trusted guest code which performs semihosting calls from guest userspace, notably for test code. Add a command line suboption to the existing semihosting-config option group so that you can explicitly opt in to semihosting from guest userspace with -semihosting-config userspace=on (There is no equivalent option for the user-mode emulator, because there by definition all code runs in userspace and has access to semihosting already.) This commit adds the infrastructure for the command line option and adds a bool 'is_user' parameter to the function semihosting_userspace_enabled() that target code can use to check whether it should be permitting the semihosting call for userspace. It mechanically makes all the callsites pass 'false', so they continue checking "is semihosting enabled in general". Subsequent commits will make each target that implements semihosting honour the userspace=on option by passing the correct value and removing whatever "don't do this for userspace" checking they were doing by hand. Signed-off-by: Peter Maydell <[email protected]> Acked-by: Alex Bennée <[email protected]> Reviewed-by: Alistair Francis <[email protected]> Reviewed-by: Philippe Mathieu-Daudé <[email protected]> Reviewed-by: Richard Henderson <[email protected]> Message-Id: <[email protected]> Signed-off-by: Richard Henderson <[email protected]> (cherry picked from commit 5202861)
1 parent 90a8699 commit 801ff1a

File tree

9 files changed

+35
-16
lines changed

9 files changed

+35
-16
lines changed

include/semihosting/semihost.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ typedef enum SemihostingTarget {
2727
} SemihostingTarget;
2828

2929
#ifdef CONFIG_USER_ONLY
30-
static inline bool semihosting_enabled(void)
30+
static inline bool semihosting_enabled(bool is_user)
3131
{
3232
return true;
3333
}
@@ -52,7 +52,13 @@ static inline const char *semihosting_get_cmdline(void)
5252
return NULL;
5353
}
5454
#else /* !CONFIG_USER_ONLY */
55-
bool semihosting_enabled(void);
55+
/**
56+
* semihosting_enabled:
57+
* @is_user: true if guest code is in usermode (i.e. not privileged)
58+
*
59+
* Return true if guest code is allowed to make semihosting calls.
60+
*/
61+
bool semihosting_enabled(bool is_user);
5662
SemihostingTarget semihosting_get_target(void);
5763
const char *semihosting_get_arg(int i);
5864
int semihosting_get_argc(void);

qemu-options.hx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4540,12 +4540,12 @@ SRST
45404540
information about the facilities this enables.
45414541
ERST
45424542
DEF("semihosting-config", HAS_ARG, QEMU_OPTION_semihosting_config,
4543-
"-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,arg=str[,...]]\n" \
4543+
"-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,userspace=on|off][,arg=str[,...]]\n" \
45444544
" semihosting configuration\n",
45454545
QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA |
45464546
QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV)
45474547
SRST
4548-
``-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,arg=str[,...]]``
4548+
``-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,userspace=on|off][,arg=str[,...]]``
45494549
Enable and configure semihosting (ARM, M68K, Xtensa, MIPS, Nios II, RISC-V
45504550
only).
45514551

@@ -4572,6 +4572,13 @@ SRST
45724572
Send the output to a chardev backend output for native or auto
45734573
output when not in gdb
45744574

4575+
``userspace=on|off``
4576+
Allows code running in guest userspace to access the semihosting
4577+
interface. The default is that only privileged guest code can
4578+
make semihosting calls. Note that setting ``userspace=on`` should
4579+
only be used if all guest code is trusted (for example, in
4580+
bare-metal test case code).
4581+
45754582
``arg=str1,arg=str2,...``
45764583
Allows the user to pass input arguments, and can be used
45774584
multiple times to build up a list. The old-style

semihosting/config.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ QemuOptsList qemu_semihosting_config_opts = {
3434
{
3535
.name = "enable",
3636
.type = QEMU_OPT_BOOL,
37+
}, {
38+
.name = "userspace",
39+
.type = QEMU_OPT_BOOL,
3740
}, {
3841
.name = "target",
3942
.type = QEMU_OPT_STRING,
@@ -50,6 +53,7 @@ QemuOptsList qemu_semihosting_config_opts = {
5053

5154
typedef struct SemihostingConfig {
5255
bool enabled;
56+
bool userspace_enabled;
5357
SemihostingTarget target;
5458
char **argv;
5559
int argc;
@@ -59,9 +63,9 @@ typedef struct SemihostingConfig {
5963
static SemihostingConfig semihosting;
6064
static const char *semihost_chardev;
6165

62-
bool semihosting_enabled(void)
66+
bool semihosting_enabled(bool is_user)
6367
{
64-
return semihosting.enabled;
68+
return semihosting.enabled && (!is_user || semihosting.userspace_enabled);
6569
}
6670

6771
SemihostingTarget semihosting_get_target(void)
@@ -137,6 +141,8 @@ int qemu_semihosting_config_options(const char *optarg)
137141
if (opts != NULL) {
138142
semihosting.enabled = qemu_opt_get_bool(opts, "enable",
139143
true);
144+
semihosting.userspace_enabled = qemu_opt_get_bool(opts, "userspace",
145+
false);
140146
const char *target = qemu_opt_get(opts, "target");
141147
/* setup of chardev is deferred until they are initialised */
142148
semihost_chardev = qemu_opt_get(opts, "chardev");

softmmu/vl.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1911,7 +1911,7 @@ static void qemu_apply_machine_options(QDict *qdict)
19111911
current_machine->boot_order = boot_order;
19121912
current_machine->boot_once = boot_once;
19131913

1914-
if (semihosting_enabled() && !semihosting_get_argc()) {
1914+
if (semihosting_enabled(false) && !semihosting_get_argc()) {
19151915
/* fall back to the -kernel/-append */
19161916
semihosting_arg_fallback(current_machine->kernel_filename, current_machine->kernel_cmdline);
19171917
}

stubs/semihost.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ QemuOptsList qemu_semihosting_config_opts = {
2323
};
2424

2525
/* Queries to config status default to off */
26-
bool semihosting_enabled(void)
26+
bool semihosting_enabled(bool is_user)
2727
{
2828
return false;
2929
}

target/arm/translate-a64.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2122,7 +2122,7 @@ static void disas_exc(DisasContext *s, uint32_t insn)
21222122
* it is required for halting debug disabled: it will UNDEF.
21232123
* Secondly, "HLT 0xf000" is the A64 semihosting syscall instruction.
21242124
*/
2125-
if (semihosting_enabled() && imm16 == 0xf000) {
2125+
if (semihosting_enabled(false) && imm16 == 0xf000) {
21262126
#ifndef CONFIG_USER_ONLY
21272127
/* In system mode, don't allow userspace access to semihosting,
21282128
* to provide some semblance of security (and for consistency

target/arm/translate.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1130,7 +1130,7 @@ static inline void gen_hlt(DisasContext *s, int imm)
11301130
* semihosting, to provide some semblance of security
11311131
* (and for consistency with our 32-bit semihosting).
11321132
*/
1133-
if (semihosting_enabled() &&
1133+
if (semihosting_enabled(false) &&
11341134
#ifndef CONFIG_USER_ONLY
11351135
s->current_el != 0 &&
11361136
#endif
@@ -6549,7 +6549,7 @@ static bool trans_BKPT(DisasContext *s, arg_BKPT *a)
65496549
/* BKPT is OK with ECI set and leaves it untouched */
65506550
s->eci_handled = true;
65516551
if (arm_dc_feature(s, ARM_FEATURE_M) &&
6552-
semihosting_enabled() &&
6552+
semihosting_enabled(false) &&
65536553
#ifndef CONFIG_USER_ONLY
65546554
!IS_USER(s) &&
65556555
#endif
@@ -8772,7 +8772,7 @@ static bool trans_SVC(DisasContext *s, arg_SVC *a)
87728772
{
87738773
const uint32_t semihost_imm = s->thumb ? 0xab : 0x123456;
87748774

8775-
if (!arm_dc_feature(s, ARM_FEATURE_M) && semihosting_enabled() &&
8775+
if (!arm_dc_feature(s, ARM_FEATURE_M) && semihosting_enabled(false) &&
87768776
#ifndef CONFIG_USER_ONLY
87778777
!IS_USER(s) &&
87788778
#endif

target/m68k/op_helper.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ static void cf_interrupt_all(CPUM68KState *env, int is_hw)
203203
cf_rte(env);
204204
return;
205205
case EXCP_HALT_INSN:
206-
if (semihosting_enabled()
206+
if (semihosting_enabled(false)
207207
&& (env->sr & SR_S) != 0
208208
&& (env->pc & 3) == 0
209209
&& cpu_lduw_code(env, env->pc - 4) == 0x4e71

target/xtensa/translate.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2402,9 +2402,9 @@ static uint32_t test_exceptions_simcall(DisasContext *dc,
24022402
bool ill = true;
24032403
#else
24042404
/* Between RE.2 and RE.3 simcall opcode's become nop for the hardware. */
2405-
bool ill = dc->config->hw_version <= 250002 && !semihosting_enabled();
2405+
bool ill = dc->config->hw_version <= 250002 && !semihosting_enabled(false);
24062406
#endif
2407-
if (ill || !semihosting_enabled()) {
2407+
if (ill || !semihosting_enabled(false)) {
24082408
qemu_log_mask(LOG_GUEST_ERROR, "SIMCALL but semihosting is disabled\n");
24092409
}
24102410
return ill ? XTENSA_OP_ILL : 0;
@@ -2414,7 +2414,7 @@ static void translate_simcall(DisasContext *dc, const OpcodeArg arg[],
24142414
const uint32_t par[])
24152415
{
24162416
#ifndef CONFIG_USER_ONLY
2417-
if (semihosting_enabled()) {
2417+
if (semihosting_enabled(false)) {
24182418
gen_helper_simcall(cpu_env);
24192419
}
24202420
#endif

0 commit comments

Comments
 (0)