Various testing updates

- semihosting re-factor (used in system tests)
   - aarch64 and alpha system tests
   - editorconfig tweak for .S
   - some docker image updates
   - iotests clean-up (without make check inclusion)
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCgAdFiEEZoWumedRZ7yvyN81+9DbCVqeKkQFAlztYToACgkQ+9DbCVqe
 KkQU9wf/Uv5qBgDn9MwcCt8tzHTX/i21QHwFLBbCmFoUwZjSridZ2KV6Ma3ig4mF
 xY+8Cr5oZT186V+aD39K6KCZKqZRulIpRVNkOKXEfAAklUoAyQs95Wa8F8LtO1eG
 vOtOYEdkXQQiAnlnQ+eaGiZQ2mpbCbREa10JrBhxp6iXh0PYcvtD7iAlOldqIvd2
 hDRwOgTtYoiiKh6UdediAgQsRvv6oNPHFUOjWgrGxfhPWKbjCVKl7VS4furg9zux
 j/S0E0xYKhj+JNq3arjiMUMl19TauCBQLrbQpphd1jOl1s7bELRjAuaKM60TVIbW
 Hd2/PYbGnkpyUcJQh0Pr1cb4RMcznw==
 =lvtu
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/stsquad/tags/pull-testing-next-280519-2' into staging

Various testing updates

  - semihosting re-factor (used in system tests)
  - aarch64 and alpha system tests
  - editorconfig tweak for .S
  - some docker image updates
  - iotests clean-up (without make check inclusion)

# gpg: Signature made Tue 28 May 2019 17:26:34 BST
# gpg:                using RSA key 6685AE99E75167BCAFC8DF35FBD0DB095A9E2A44
# gpg: Good signature from "Alex Bennée (Master Work Key) <alex.bennee@linaro.org>" [full]
# Primary key fingerprint: 6685 AE99 E751 67BC AFC8  DF35 FBD0 DB09 5A9E 2A44

* remotes/stsquad/tags/pull-testing-next-280519-2: (27 commits)
  tests/qemu-iotests: re-format output to for make check-block
  tests/qemu-iotests/group: Re-use the "auto" group for tests that can always run
  Makefile.target: support per-target coverage reports
  Makefile: include per-target build directories in coverage report
  Makefile: fix coverage-report reference to BUILD_DIR
  .travis.yml: enable aarch64-softmmu and alpha-softmmu tcg tests
  tests/tcg/alpha: add system boot.S
  tests/tcg/multiarch: expand system memory test to cover more
  tests/tcg/minilib: support %c format char
  tests/tcg/multiarch: move the system memory test
  tests/tcg/aarch64: add system boot.S
  editorconfig: add settings for .s/.S files
  tests/tcg/multiarch: add hello world system test
  tests/tcg/multiarch: add support for multiarch system tests
  tests/docker: Test more components on the Fedora default image
  tests/docker: add ubuntu 18.04
  MAINTAINERS: update for semihostings new home
  target/mips: convert UHI_plog to use common semihosting code
  target/mips: only build mips-semi for softmmu
  target/arm: correct return values for WRITE/READ in arm-semi
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2019-05-28 17:38:32 +01:00
commit 8c1ecb5904
58 changed files with 2178 additions and 580 deletions

View file

@ -26,6 +26,11 @@ file_type_emacs = makefile
indent_style = space
indent_size = 4
[*.{s,S}]
indent_style = tab
indent_size = 8
file_type_emacs = asm
[*.{vert,frag}]
file_type_emacs = glsl

View file

@ -284,5 +284,5 @@ matrix:
# Run check-tcg against softmmu targets
- env:
- CONFIG="--target-list=xtensa-softmmu,arm-softmmu"
- CONFIG="--target-list=xtensa-softmmu,arm-softmmu,aarch64-softmmu,alpha-softmmu"
- TEST_CMD="make -j3 check-tcg V=1"

View file

@ -470,6 +470,7 @@ M: Richard Henderson <rth@twiddle.net>
S: Maintained
F: hw/alpha/
F: hw/isa/smc37c669-superio.c
F: tests/tcg/alpha/system/
ARM Machines
------------
@ -2563,6 +2564,13 @@ F: docs/pvrdma.txt
F: contrib/rdmacm-mux/*
F: qapi/rdma.json
Semihosting
M: Alex Bennée <alex.bennee@linaro.org>
L: qemu-devel@nongnu.org
S: Maintained
F: hw/semihosting/
F: include/hw/semihosting/
Build and test automation
-------------------------
Build and test automation

View file

@ -1009,7 +1009,9 @@ $(filter %.1 %.7 %.8,$(DOCS)): scripts/texi2pod.pl
%/coverage-report.html:
@mkdir -p $*
$(call quiet-command,\
gcovr -r $(SRC_PATH) --object-directory $(BUILD_PATH) \
gcovr -r $(SRC_PATH) \
$(foreach t, $(TARGET_DIRS), --object-directory $(BUILD_DIR)/$(t)) \
--object-directory $(BUILD_DIR) \
-p --html --html-details -o $@, \
"GEN", "coverage-report.html")

View file

@ -238,3 +238,19 @@ endif
generated-files-y += config-target.h
Makefile: $(generated-files-y)
# Reports/Analysis
#
# The target specific coverage report only cares about target specific
# blobs and not the shared code.
#
%/coverage-report.html:
@mkdir -p $*
$(call quiet-command,\
gcovr -r $(SRC_PATH) --object-directory $(CURDIR) \
-p --html --html-details -o $@, \
"GEN", "coverage-report.html")
.PHONY: coverage-report
coverage-report: $(CURDIR)/reports/coverage/coverage-report.html

View file

@ -39,3 +39,4 @@ CONFIG_MICROBIT=y
CONFIG_FSL_IMX25=y
CONFIG_FSL_IMX7=y
CONFIG_FSL_IMX6UL=y
CONFIG_SEMIHOSTING=y

View file

@ -4,6 +4,8 @@
#
#CONFIG_MILKYMIST_TMU2=n # disabling it actually causes compile-time failures
CONFIG_SEMIHOSTING=y
# Boards:
#
CONFIG_LM32=y

View file

@ -1,5 +1,7 @@
# Default configuration for m68k-softmmu
CONFIG_SEMIHOSTING=y
# Boards:
#
CONFIG_AN5206=y

View file

@ -35,6 +35,7 @@ CONFIG_MIPS_CPS=y
CONFIG_MIPS_ITU=y
CONFIG_R4K=y
CONFIG_MALTA=y
CONFIG_SEMIHOSTING=y
CONFIG_PCNET_PCI=y
CONFIG_MIPSSIM=y
CONFIG_ACPI_SMBUS=y

View file

@ -1,5 +1,7 @@
# Default configuration for nios2-softmmu
CONFIG_SEMIHOSTING=y
# Boards:
#
CONFIG_NIOS2_10M50=y

View file

@ -1,5 +1,7 @@
# Default configuration for Xtensa
CONFIG_SEMIHOSTING=y
# Boards:
#
CONFIG_XTENSA_SIM=y

View file

@ -37,7 +37,7 @@
#include "qemu/sockets.h"
#include "sysemu/hw_accel.h"
#include "sysemu/kvm.h"
#include "exec/semihost.h"
#include "hw/semihosting/semihost.h"
#include "exec/exec-all.h"
#ifdef CONFIG_USER_ONLY

View file

@ -29,6 +29,7 @@ source pci/Kconfig
source rdma/Kconfig
source scsi/Kconfig
source sd/Kconfig
source semihosting/Kconfig
source smbios/Kconfig
source ssi/Kconfig
source timer/Kconfig

View file

@ -36,6 +36,7 @@ devices-dirs-$(CONFIG_SOFTMMU) += watchdog/
devices-dirs-$(CONFIG_SOFTMMU) += xen/
devices-dirs-$(CONFIG_MEM_DEVICE) += mem/
devices-dirs-$(CONFIG_SOFTMMU) += smbios/
devices-dirs-y += semihosting/
devices-dirs-y += core/
common-obj-y += $(devices-dirs-y)
obj-y += $(devices-dirs-y)

View file

@ -55,7 +55,7 @@
#include "qemu/error-report.h"
#include "hw/empty_slot.h"
#include "sysemu/kvm.h"
#include "exec/semihost.h"
#include "hw/semihosting/semihost.h"
#include "hw/mips/cps.h"
#define ENVP_ADDR 0x80002000l

3
hw/semihosting/Kconfig Normal file
View file

@ -0,0 +1,3 @@
config SEMIHOSTING
bool

View file

@ -0,0 +1,2 @@
obj-$(CONFIG_SEMIHOSTING) += config.o
obj-$(CONFIG_SEMIHOSTING) += console.o

186
hw/semihosting/config.c Normal file
View file

@ -0,0 +1,186 @@
/*
* Semihosting configuration
*
* Copyright (c) 2015 Imagination Technologies
* Copyright (c) 2019 Linaro Ltd
*
* This controls the configuration of semihosting for all guest
* targets that support it. Architecture specific handling is handled
* in target/HW/HW-semi.c
*
* Semihosting is sightly strange in that it is also supported by some
* linux-user targets. However in that use case no configuration of
* the outputs and command lines is supported.
*
* The config module is common to all softmmu targets however as vl.c
* needs to link against the helpers.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "qemu/option.h"
#include "qemu/config-file.h"
#include "qemu/error-report.h"
#include "hw/semihosting/semihost.h"
#include "chardev/char.h"
QemuOptsList qemu_semihosting_config_opts = {
.name = "semihosting-config",
.implied_opt_name = "enable",
.head = QTAILQ_HEAD_INITIALIZER(qemu_semihosting_config_opts.head),
.desc = {
{
.name = "enable",
.type = QEMU_OPT_BOOL,
}, {
.name = "target",
.type = QEMU_OPT_STRING,
}, {
.name = "chardev",
.type = QEMU_OPT_STRING,
}, {
.name = "arg",
.type = QEMU_OPT_STRING,
},
{ /* end of list */ }
},
};
typedef struct SemihostingConfig {
bool enabled;
SemihostingTarget target;
Chardev *chardev;
const char **argv;
int argc;
const char *cmdline; /* concatenated argv */
} SemihostingConfig;
static SemihostingConfig semihosting;
static const char *semihost_chardev;
bool semihosting_enabled(void)
{
return semihosting.enabled;
}
SemihostingTarget semihosting_get_target(void)
{
return semihosting.target;
}
const char *semihosting_get_arg(int i)
{
if (i >= semihosting.argc) {
return NULL;
}
return semihosting.argv[i];
}
int semihosting_get_argc(void)
{
return semihosting.argc;
}
const char *semihosting_get_cmdline(void)
{
if (semihosting.cmdline == NULL && semihosting.argc > 0) {
semihosting.cmdline = g_strjoinv(" ", (gchar **)semihosting.argv);
}
return semihosting.cmdline;
}
static int add_semihosting_arg(void *opaque,
const char *name, const char *val,
Error **errp)
{
SemihostingConfig *s = opaque;
if (strcmp(name, "arg") == 0) {
s->argc++;
/* one extra element as g_strjoinv() expects NULL-terminated array */
s->argv = g_realloc(s->argv, (s->argc + 1) * sizeof(void *));
s->argv[s->argc - 1] = val;
s->argv[s->argc] = NULL;
}
return 0;
}
/* Use strings passed via -kernel/-append to initialize semihosting.argv[] */
void semihosting_arg_fallback(const char *file, const char *cmd)
{
char *cmd_token;
/* argv[0] */
add_semihosting_arg(&semihosting, "arg", file, NULL);
/* split -append and initialize argv[1..n] */
cmd_token = strtok(g_strdup(cmd), " ");
while (cmd_token) {
add_semihosting_arg(&semihosting, "arg", cmd_token, NULL);
cmd_token = strtok(NULL, " ");
}
}
Chardev *semihosting_get_chardev(void)
{
return semihosting.chardev;
}
void qemu_semihosting_enable(void)
{
semihosting.enabled = true;
semihosting.target = SEMIHOSTING_TARGET_AUTO;
}
int qemu_semihosting_config_options(const char *optarg)
{
QemuOptsList *opt_list = qemu_find_opts("semihosting-config");
QemuOpts *opts = qemu_opts_parse_noisily(opt_list, optarg, false);
semihosting.enabled = true;
if (opts != NULL) {
semihosting.enabled = qemu_opt_get_bool(opts, "enable",
true);
const char *target = qemu_opt_get(opts, "target");
/* setup of chardev is deferred until they are initialised */
semihost_chardev = qemu_opt_get(opts, "chardev");
if (target != NULL) {
if (strcmp("native", target) == 0) {
semihosting.target = SEMIHOSTING_TARGET_NATIVE;
} else if (strcmp("gdb", target) == 0) {
semihosting.target = SEMIHOSTING_TARGET_GDB;
} else if (strcmp("auto", target) == 0) {
semihosting.target = SEMIHOSTING_TARGET_AUTO;
} else {
error_report("unsupported semihosting-config %s",
optarg);
return 1;
}
} else {
semihosting.target = SEMIHOSTING_TARGET_AUTO;
}
/* Set semihosting argument count and vector */
qemu_opt_foreach(opts, add_semihosting_arg,
&semihosting, NULL);
} else {
error_report("unsupported semihosting-config %s", optarg);
return 1;
}
return 0;
}
void qemu_semihosting_connect_chardevs(void)
{
/* We had to defer this until chardevs were created */
if (semihost_chardev) {
Chardev *chr = qemu_chr_find(semihost_chardev);
if (chr == NULL) {
error_report("semihosting chardev '%s' not found",
semihost_chardev);
exit(1);
}
semihosting.chardev = chr;
}
}

84
hw/semihosting/console.c Normal file
View file

@ -0,0 +1,84 @@
/*
* Semihosting Console Support
*
* Copyright (c) 2015 Imagination Technologies
* Copyright (c) 2019 Linaro Ltd
*
* This provides support for outputting to a semihosting console.
*
* While most semihosting implementations support reading and writing
* to arbitrary file descriptors we treat the console as something
* specifically for debugging interaction. This means messages can be
* re-directed to gdb (if currently being used to debug) or even
* re-directed elsewhere.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "cpu.h"
#include "hw/semihosting/semihost.h"
#include "hw/semihosting/console.h"
#include "exec/gdbstub.h"
#include "qemu/log.h"
#include "chardev/char.h"
int qemu_semihosting_log_out(const char *s, int len)
{
Chardev *chardev = semihosting_get_chardev();
if (chardev) {
return qemu_chr_write_all(chardev, (uint8_t *) s, len);
} else {
return write(STDERR_FILENO, s, len);
}
}
/*
* A re-implementation of lock_user_string that we can use locally
* instead of relying on softmmu-semi. Hopefully we can deprecate that
* in time. We either copy len bytes if specified or until we find a NULL.
*/
static GString *copy_user_string(CPUArchState *env, target_ulong addr, int len)
{
CPUState *cpu = ENV_GET_CPU(env);
GString *s = g_string_sized_new(len ? len : 128);
uint8_t c;
bool done;
do {
if (cpu_memory_rw_debug(cpu, addr++, &c, 1, 0) == 0) {
s = g_string_append_c(s, c);
done = len ? s->len == len : c == 0;
} else {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: passed inaccessible address " TARGET_FMT_lx,
__func__, addr);
done = true;
}
} while (!done);
return s;
}
static void semihosting_cb(CPUState *cs, target_ulong ret, target_ulong err)
{
if (ret == (target_ulong) -1) {
qemu_log("%s: gdb console output failed ("TARGET_FMT_ld")",
__func__, err);
}
}
int qemu_semihosting_console_out(CPUArchState *env, target_ulong addr, int len)
{
GString *s = copy_user_string(env, addr, len);
int out = s->len;
if (use_gdb_syscalls()) {
gdb_do_syscall(semihosting_cb, "write,2,%x,%x", addr, s->len);
} else {
out = qemu_semihosting_log_out(s->str, s->len);
}
g_string_free(s, true);
return out;
}

View file

@ -0,0 +1,38 @@
/*
* Semihosting Console
*
* Copyright (c) 2019 Linaro Ltd
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef _SEMIHOST_CONSOLE_H_
#define _SEMIHOST_CONSOLE_H_
/**
* qemu_semihosting_console_out:
* @env: CPUArchState
* @s: host address of guest string
* @len: length of string or 0 (string is null terminated)
*
* Send a guest string to the debug console. This may be the remote
* gdb session if a softmmu guest is currently being debugged.
*
* Returns: number of bytes written.
*/
int qemu_semihosting_console_out(CPUArchState *env, target_ulong s, int len);
/**
* qemu_semihosting_log_out:
* @s: pointer to string
* @len: length of string
*
* Send a string to the debug output. Unlike console_out these strings
* can't be sent to a remote gdb instance as they don't exist in guest
* memory.
*
* Returns: number of bytes written
*/
int qemu_semihosting_log_out(const char *s, int len);
#endif /* _SEMIHOST_CONSOLE_H_ */

View file

@ -51,12 +51,23 @@ static inline const char *semihosting_get_cmdline(void)
{
return NULL;
}
#else
static inline Chardev *semihosting_get_chardev(void)
{
return NULL;
}
#else /* !CONFIG_USER_ONLY */
bool semihosting_enabled(void);
SemihostingTarget semihosting_get_target(void);
const char *semihosting_get_arg(int i);
int semihosting_get_argc(void);
const char *semihosting_get_cmdline(void);
#endif
void semihosting_arg_fallback(const char *file, const char *cmd);
Chardev *semihosting_get_chardev(void);
/* for vl.c hooks */
void qemu_semihosting_enable(void);
int qemu_semihosting_config_options(const char *opt);
void qemu_semihosting_connect_chardevs(void);
#endif /* CONFIG_USER_ONLY */
#endif
#endif /* SEMIHOST_H */

View file

@ -193,5 +193,6 @@ extern QemuOptsList qemu_nic_opts;
extern QemuOptsList qemu_net_opts;
extern QemuOptsList qemu_global_opts;
extern QemuOptsList qemu_mon_opts;
extern QemuOptsList qemu_semihosting_config_opts;
#endif

View file

@ -6,4 +6,6 @@ obj-y = main.o syscall.o strace.o mmap.o signal.o \
obj-$(TARGET_HAS_BFLT) += flatload.o
obj-$(TARGET_I386) += vm86.o
obj-$(TARGET_ARM) += arm/nwfpe/
obj-$(TARGET_ARM) += arm/semihost.o
obj-$(TARGET_AARCH64) += arm/semihost.o
obj-$(TARGET_M68K) += m68k-sim.o

24
linux-user/arm/semihost.c Normal file
View file

@ -0,0 +1,24 @@
/*
* ARM Semihosting Console Support
*
* Copyright (c) 2019 Linaro Ltd
*
* Currently ARM is unique in having support for semihosting support
* in linux-user. So for now we implement the common console API but
* just for arm linux-user.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "cpu.h"
#include "hw/semihosting/console.h"
#include "qemu.h"
int qemu_semihosting_console_out(CPUArchState *env, target_ulong addr, int len)
{
void *s = lock_user_string(addr);
len = write(STDERR_FILENO, s, len ? len : strlen(s));
unlock_user(s, addr, 0);
return len;
}

View file

@ -4025,12 +4025,12 @@ STEXI
Enable semihosting mode (ARM, M68K, Xtensa, MIPS, Nios II only).
ETEXI
DEF("semihosting-config", HAS_ARG, QEMU_OPTION_semihosting_config,
"-semihosting-config [enable=on|off][,target=native|gdb|auto][,arg=str[,...]]\n" \
"-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,arg=str[,...]]\n" \
" semihosting configuration\n",
QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32 |
QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2)
STEXI
@item -semihosting-config [enable=on|off][,target=native|gdb|auto][,arg=str[,...]]
@item -semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,arg=str[,...]]
@findex -semihosting-config
Enable and configure semihosting (ARM, M68K, Xtensa, MIPS, Nios II only).
@table @option
@ -4038,6 +4038,8 @@ Enable and configure semihosting (ARM, M68K, Xtensa, MIPS, Nios II only).
Defines where the semihosting calls will be addressed, to QEMU (@code{native})
or to GDB (@code{gdb}). The default is @code{auto}, which means @code{gdb}
during debug sessions and @code{native} otherwise.
@item chardev=@var{str1}
Send the output to a chardev backend output for native or auto output when not in gdb
@item arg=@var{str1},arg=@var{str2},...
Allows the user to pass input arguments, and can be used multiple times to build
up a list. The old-style @code{-kernel}/@code{-append} method of passing a

View file

@ -40,3 +40,4 @@ stub-obj-y += pci-host-piix.o
stub-obj-y += ram-block.o
stub-obj-y += ramfb.o
stub-obj-y += fw_cfg.o
stub-obj-$(CONFIG_SOFTMMU) += semihost.o

70
stubs/semihost.c Normal file
View file

@ -0,0 +1,70 @@
/*
* Semihosting Stubs for SoftMMU
*
* Copyright (c) 2019 Linaro Ltd
*
* Stubs for SoftMMU targets that don't actually do semihosting.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "qemu/option.h"
#include "qemu/error-report.h"
#include "hw/semihosting/semihost.h"
/* Empty config */
QemuOptsList qemu_semihosting_config_opts = {
.name = "",
.head = QTAILQ_HEAD_INITIALIZER(qemu_semihosting_config_opts.head),
.desc = {
{ /* end of list */ }
},
};
/* Queries to config status default to off */
bool semihosting_enabled(void)
{
return false;
}
SemihostingTarget semihosting_get_target(void)
{
return SEMIHOSTING_TARGET_AUTO;
}
/*
* All the rest are empty subs. We could g_assert_not_reached() but
* that adds extra weight to the final binary. Waste not want not.
*/
void qemu_semihosting_enable(void)
{
}
int qemu_semihosting_config_options(const char *optarg)
{
return 1;
}
const char *semihosting_get_arg(int i)
{
return NULL;
}
int semihosting_get_argc(void)
{
return 0;
}
const char *semihosting_get_cmdline(void)
{
return NULL;
}
void semihosting_arg_fallback(const char *file, const char *cmd)
{
}
void qemu_semihosting_connect_chardevs(void)
{
}

View file

@ -2,6 +2,7 @@
* Arm "Angel" semihosting syscalls
*
* Copyright (c) 2005, 2007 CodeSourcery.
* Copyright (c) 2019 Linaro
* Written by Paul Brook.
*
* This program is free software; you can redistribute it and/or modify
@ -16,12 +17,18 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
* ARM Semihosting is documented in:
* Semihosting for AArch32 and AArch64 Release 2.0
* https://static.docs.arm.com/100863/0200/semihosting.pdf
*/
#include "qemu/osdep.h"
#include "cpu.h"
#include "exec/semihost.h"
#include "hw/semihosting/semihost.h"
#include "hw/semihosting/console.h"
#include "qemu/log.h"
#ifdef CONFIG_USER_ONLY
#include "qemu.h"
@ -239,6 +246,15 @@ static target_ulong arm_gdb_syscall(ARMCPU *cpu, gdb_syscall_complete_cb cb,
put_user_u64(val, args + (n) * 8) : \
put_user_u32(val, args + (n) * 4))
/*
* Do a semihosting call.
*
* The specification always says that the "return register" either
* returns a specific value or is corrupted, so we don't need to
* report to our caller whether we are returning a value or trying to
* leave the register unchanged. We use 0xdeadbeef as the return value
* when there isn't a defined return value for the call.
*/
target_ulong do_arm_semihosting(CPUARMState *env)
{
ARMCPU *cpu = arm_env_get_cpu(env);
@ -299,32 +315,10 @@ target_ulong do_arm_semihosting(CPUARMState *env)
return set_swi_errno(ts, close(arg0));
}
case TARGET_SYS_WRITEC:
{
char c;
if (get_user_u8(c, args))
/* FIXME - should this error code be -TARGET_EFAULT ? */
return (uint32_t)-1;
/* Write to debug console. stderr is near enough. */
if (use_gdb_syscalls()) {
return arm_gdb_syscall(cpu, arm_semi_cb, "write,2,%x,1", args);
} else {
return write(STDERR_FILENO, &c, 1);
}
}
qemu_semihosting_console_out(env, args, 1);
return 0xdeadbeef;
case TARGET_SYS_WRITE0:
if (!(s = lock_user_string(args)))
/* FIXME - should this error code be -TARGET_EFAULT ? */
return (uint32_t)-1;
len = strlen(s);
if (use_gdb_syscalls()) {
return arm_gdb_syscall(cpu, arm_semi_cb, "write,2,%x,%x",
args, len);
} else {
ret = write(STDERR_FILENO, s, len);
}
unlock_user(s, args, 0);
return ret;
return qemu_semihosting_console_out(env, args, 0);
case TARGET_SYS_WRITE:
GET_ARG(0);
GET_ARG(1);
@ -337,13 +331,15 @@ target_ulong do_arm_semihosting(CPUARMState *env)
} else {
s = lock_user(VERIFY_READ, arg1, len, 1);
if (!s) {
/* FIXME - should this error code be -TARGET_EFAULT ? */
return (uint32_t)-1;
/* Return bytes not written on error */
return len;
}
ret = set_swi_errno(ts, write(arg0, s, len));
unlock_user(s, arg1, 0);
if (ret == (uint32_t)-1)
return -1;
if (ret == (uint32_t)-1) {
ret = 0;
}
/* Return bytes not written */
return len - ret;
}
case TARGET_SYS_READ:
@ -358,19 +354,21 @@ target_ulong do_arm_semihosting(CPUARMState *env)
} else {
s = lock_user(VERIFY_WRITE, arg1, len, 0);
if (!s) {
/* FIXME - should this error code be -TARGET_EFAULT ? */
return (uint32_t)-1;
/* return bytes not read */
return len;
}
do {
ret = set_swi_errno(ts, read(arg0, s, len));
} while (ret == -1 && errno == EINTR);
unlock_user(s, arg1, len);
if (ret == (uint32_t)-1)
return -1;
if (ret == (uint32_t)-1) {
ret = 0;
}
/* Return bytes not read */
return len - ret;
}
case TARGET_SYS_READC:
/* XXX: Read from debug console. Not implemented. */
qemu_log_mask(LOG_UNIMP, "%s: SYS_READC not implemented", __func__);
return 0;
case TARGET_SYS_ISTTY:
GET_ARG(0);
@ -404,7 +402,7 @@ target_ulong do_arm_semihosting(CPUARMState *env)
return buf.st_size;
}
case TARGET_SYS_TMPNAM:
/* XXX: Not implemented. */
qemu_log_mask(LOG_UNIMP, "%s: SYS_TMPNAM not implemented", __func__);
return -1;
case TARGET_SYS_REMOVE:
GET_ARG(0);
@ -509,14 +507,16 @@ target_ulong do_arm_semihosting(CPUARMState *env)
output_size = ts->info->arg_end - ts->info->arg_start;
if (!output_size) {
/* We special-case the "empty command line" case (argc==0).
Just provide the terminating 0. */
/*
* We special-case the "empty command line" case (argc==0).
* Just provide the terminating 0.
*/
output_size = 1;
}
#endif
if (output_size > input_size) {
/* Not enough space to store command-line arguments. */
/* Not enough space to store command-line arguments. */
return -1;
}
@ -570,8 +570,10 @@ target_ulong do_arm_semihosting(CPUARMState *env)
GET_ARG(0);
#ifdef CONFIG_USER_ONLY
/* Some C libraries assume the heap immediately follows .bss, so
allocate it using sbrk. */
/*
* Some C libraries assume the heap immediately follows .bss, so
* allocate it using sbrk.
*/
if (!ts->heap_limit) {
abi_ulong ret;
@ -619,7 +621,8 @@ target_ulong do_arm_semihosting(CPUARMState *env)
}
case TARGET_SYS_EXIT:
if (is_a64(env)) {
/* The A64 version of this call takes a parameter block,
/*
* The A64 version of this call takes a parameter block,
* so the application-exit type can return a subcode which
* is the exit status code from the application.
*/
@ -632,14 +635,17 @@ target_ulong do_arm_semihosting(CPUARMState *env)
ret = 1;
}
} else {
/* ARM specifies only Stopped_ApplicationExit as normal
* exit, everything else is considered an error */
/*
* ARM specifies only Stopped_ApplicationExit as normal
* exit, everything else is considered an error
*/
ret = (args == ADP_Stopped_ApplicationExit) ? 0 : 1;
}
gdb_exit(env, ret);
exit(ret);
case TARGET_SYS_SYNCCACHE:
/* Clean the D-cache and invalidate the I-cache for the specified
/*
* Clean the D-cache and invalidate the I-cache for the specified
* virtual address range. This is a nop for us since we don't
* implement caches. This is only present on A64.
*/

View file

@ -16,7 +16,7 @@
#include "exec/cpu_ldst.h"
#include "arm_ldst.h"
#include <zlib.h> /* For crc32 */
#include "exec/semihost.h"
#include "hw/semihosting/semihost.h"
#include "sysemu/cpus.h"
#include "sysemu/kvm.h"
#include "fpu/softfloat.h"

View file

@ -29,7 +29,7 @@
#include "qemu/host-utils.h"
#include "qemu/qemu-print.h"
#include "exec/semihost.h"
#include "hw/semihosting/semihost.h"
#include "exec/gen-icount.h"
#include "exec/helper-proto.h"

View file

@ -30,7 +30,7 @@
#include "qemu/bitops.h"
#include "qemu/qemu-print.h"
#include "arm_ldst.h"
#include "exec/semihost.h"
#include "hw/semihosting/semihost.h"
#include "exec/helper-proto.h"
#include "exec/helper-gen.h"

View file

@ -22,7 +22,7 @@
#include "exec/exec-all.h"
#include "qemu/host-utils.h"
#include "sysemu/sysemu.h"
#include "exec/semihost.h"
#include "hw/semihosting/semihost.h"
#include "exec/log.h"
bool lm32_cpu_tlb_fill(CPUState *cs, vaddr address, int size,

View file

@ -21,7 +21,7 @@
#include "exec/helper-proto.h"
#include "exec/exec-all.h"
#include "exec/cpu_ldst.h"
#include "exec/semihost.h"
#include "hw/semihosting/semihost.h"
#if defined(CONFIG_USER_ONLY)

View file

@ -1,4 +1,5 @@
obj-y += translate.o dsp_helper.o op_helper.o lmi_helper.o helper.o cpu.o
obj-y += gdbstub.o msa_helper.o mips-semi.o
obj-y += gdbstub.o msa_helper.o
obj-$(CONFIG_SOFTMMU) += mips-semi.o
obj-$(CONFIG_SOFTMMU) += machine.o cp0_timer.o
obj-$(CONFIG_KVM) += kvm.o

View file

@ -2,7 +2,9 @@ DEF_HELPER_3(raise_exception_err, noreturn, env, i32, int)
DEF_HELPER_2(raise_exception, noreturn, env, i32)
DEF_HELPER_1(raise_exception_debug, noreturn, env)
#ifndef CONFIG_USER_ONLY
DEF_HELPER_1(do_semihosting, void, env)
#endif
#ifdef TARGET_MIPS64
DEF_HELPER_4(sdl, void, env, tl, tl, int)

View file

@ -22,7 +22,8 @@
#include "qemu/log.h"
#include "exec/helper-proto.h"
#include "exec/softmmu-semi.h"
#include "exec/semihost.h"
#include "hw/semihosting/semihost.h"
#include "hw/semihosting/console.h"
typedef enum UHIOp {
UHI_exit = 1,
@ -329,13 +330,12 @@ void helper_do_semihosting(CPUMIPSState *env)
p2 = strstr(p, "%d");
if (p2) {
int char_num = p2 - p;
char *buf = g_malloc(char_num + 1);
strncpy(buf, p, char_num);
buf[char_num] = '\0';
gpr[2] = printf("%s%d%s", buf, (int)gpr[5], p2 + 2);
g_free(buf);
GString *s = g_string_new_len(p, char_num);
g_string_append_printf(s, "%d%s", (int)gpr[5], p2 + 2);
gpr[2] = qemu_semihosting_log_out(s->str, s->len);
g_string_free(s, true);
} else {
gpr[2] = printf("%s", p);
gpr[2] = qemu_semihosting_log_out(p, strlen(p));
}
FREE_TARGET_STRING(p, gpr[4]);
break;

View file

@ -32,7 +32,7 @@
#include "exec/helper-proto.h"
#include "exec/helper-gen.h"
#include "exec/semihost.h"
#include "hw/semihosting/semihost.h"
#include "target/mips/trace.h"
#include "trace-tcg.h"
@ -13726,6 +13726,14 @@ static inline bool is_uhi(int sdbbp_code)
#endif
}
#ifdef CONFIG_USER_ONLY
/* The above should dead-code away any calls to this..*/
static inline void gen_helper_do_semihosting(void *env)
{
g_assert_not_reached();
}
#endif
static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx)
{
int rx, ry;

View file

@ -26,7 +26,7 @@
#include "exec/cpu_ldst.h"
#include "exec/log.h"
#include "exec/helper-proto.h"
#include "exec/semihost.h"
#include "hw/semihosting/semihost.h"
#if defined(CONFIG_USER_ONLY)

View file

@ -38,7 +38,7 @@
#include "qemu/qemu-print.h"
#include "sysemu/sysemu.h"
#include "exec/cpu_ldst.h"
#include "exec/semihost.h"
#include "hw/semihosting/semihost.h"
#include "exec/translator.h"
#include "exec/helper-proto.h"

View file

@ -29,7 +29,7 @@
#include "cpu.h"
#include "chardev/char-fe.h"
#include "exec/helper-proto.h"
#include "exec/semihost.h"
#include "hw/semihosting/semihost.h"
#include "qapi/error.h"
#include "qemu/log.h"
#include "sysemu/sysemu.h"

View file

@ -8,6 +8,7 @@ ENV PACKAGES \
bzip2-devel \
ccache \
clang \
cyrus-sasl-devel \
device-mapper-multipath-devel \
findutils \
flex \
@ -23,13 +24,17 @@ ENV PACKAGES \
libaio-devel \
libasan \
libattr-devel \
libblockdev-mpath-devel \
libcap-devel \
libcap-ng-devel \
libcurl-devel \
libfdt-devel \
libiscsi-devel \
libjpeg-devel \
libpmem-devel \
libpng-devel \
librbd-devel \
libseccomp-devel \
libssh2-devel \
libubsan \
libusbx-devel \
@ -74,10 +79,12 @@ ENV PACKAGES \
pixman-devel \
python3 \
PyYAML \
rdma-core-devel \
SDL2-devel \
snappy-devel \
sparse \
spice-server-devel \
systemd-devel \
systemtap-sdt-devel \
tar \
usbredir-devel \

View file

@ -0,0 +1,57 @@
FROM ubuntu:18.04
ENV PACKAGES flex bison \
ccache \
clang \
gcc \
gettext \
git \
glusterfs-common \
libaio-dev \
libattr1-dev \
libbluetooth-dev \
libbrlapi-dev \
libbz2-dev \
libcacard-dev \
libcap-dev \
libcap-ng-dev \
libcurl4-gnutls-dev \
libdrm-dev \
libepoxy-dev \
libfdt-dev \
libgbm-dev \
libgtk-3-dev \
libibverbs-dev \
libiscsi-dev \
libjemalloc-dev \
libjpeg-turbo8-dev \
liblzo2-dev \
libncurses5-dev \
libncursesw5-dev \
libnfs-dev \
libnss3-dev \
libnuma-dev \
libpixman-1-dev \
librados-dev \
librbd-dev \
librdmacm-dev \
libsasl2-dev \
libsdl2-dev \
libseccomp-dev \
libsnappy-dev \
libspice-protocol-dev \
libspice-server-dev \
libssh2-1-dev \
libusb-1.0-0-dev \
libusbredirhost-dev \
libvdeplug-dev \
libvte-2.91-dev \
libxen-dev \
make \
python-yaml \
sparse \
texinfo \
xfslibs-dev
RUN apt-get update && \
apt-get -y install $PACKAGES
RUN dpkg -l $PACKAGES | sort > /packages.txt
ENV FEATURES clang pyyaml sdl2

View file

@ -27,9 +27,7 @@ bad=""
notrun=""
casenotrun=""
interrupt=true
# by default don't output timestamps
timestamp=${TIMESTAMP:=false}
makecheck=false
_init_error()
{
@ -88,6 +86,22 @@ _full_platform_details()
echo "$os/$platform $host $kernel"
}
_full_env_details()
{
cat <<EOF
QEMU -- "$QEMU_PROG" $QEMU_OPTIONS
QEMU_IMG -- "$QEMU_IMG_PROG" $QEMU_IMG_OPTIONS
QEMU_IO -- "$QEMU_IO_PROG" $QEMU_IO_OPTIONS
QEMU_NBD -- "$QEMU_NBD_PROG" $QEMU_NBD_OPTIONS
IMGFMT -- $FULL_IMGFMT_DETAILS
IMGPROTO -- $IMGPROTO
PLATFORM -- $FULL_HOST_DETAILS
TEST_DIR -- $TEST_DIR
SOCKET_SCM_HELPER -- $SOCKET_SCM_HELPER
EOF
}
# $1 = prog to look for
set_prog_path()
{
@ -254,8 +268,8 @@ other options
-misalign misalign memory allocations
-n show me, do not run tests
-o options -o options to pass to qemu-img create/convert
-T output timestamps
-c mode cache mode
-makecheck pretty print output for make check
testlist options
-g group[,group...] include tests from these groups
@ -403,7 +417,10 @@ testlist options
command -v xxdiff >/dev/null 2>&1 && diff=xxdiff
fi
;;
-makecheck) # makecheck friendly output
makecheck=true
xpand=false
;;
-n) # show me, don't do it
showme=true
xpand=false
@ -416,8 +433,7 @@ testlist options
cachemode=true
xpand=false
;;
-T) # turn on timestamp output
timestamp=true
-T) # deprecated timestamp option
xpand=false
;;
@ -633,12 +649,6 @@ _wallclock()
date "+%H %M %S" | awk '{ print $1*3600 + $2*60 + $3 }'
}
_timestamp()
{
now=$(date "+%T")
printf %s " [$now]"
}
_wrapup()
{
if $showme
@ -704,23 +714,54 @@ END { if (NR > 0) {
trap "_wrapup; exit \$status" 0 1 2 3 15
# Report the test start and results. For makecheck we want to pretty
# print the whole report at the end of the execution.
# args: $seq, $starttime, $lasttime
_report_test_start()
{
if ! $makecheck; then
if [ -n "$3" ]; then
local lasttime=" (last: $3s)"
fi
printf "%-8s %-10s [%s] %4s%-14s\r" "$1" "..." "$2" "..." "$lasttime"
fi
}
# args:$seq $status $starttime $lasttime $thistime $details
_report_test_result()
{
local status lasttime thistime
if $makecheck; then
if [ -n "$2" ] && [ "$2" != "pass" ]; then
status=" [$2]"
fi
printf " TEST iotest-$IMGFMT: %s%s\n" "$1" "$status"
return
fi
if [ -n "$4" ]; then
lasttime=" (last: $4s)"
fi
if [ -n "$5" ]; then
thistime=" $5s"
fi
case "$2" in
"pass") status=$(printf "\e[32m%-10s\e[0m" "$2") ;;
"fail") status=$(printf "\e[1m\e[31m%-10s\e[0m" "$2") ;;
"not run") status=$(printf "\e[33m%-10s\e[0m" "$2") ;;
*) status=$(printf "%-10s" "$2") ;;
esac
printf "%-8s %s [%s] [%s] %4s%-14s %s\n" "$1" "$status" "$3" "$(date '+%T')" "$thistime" "$lasttime" "$6"
}
[ -f $TIMESTAMP_FILE ] || touch $TIMESTAMP_FILE
FULL_IMGFMT_DETAILS=$(_full_imgfmt_details)
FULL_HOST_DETAILS=$(_full_platform_details)
cat <<EOF
QEMU -- "$QEMU_PROG" $QEMU_OPTIONS
QEMU_IMG -- "$QEMU_IMG_PROG" $QEMU_IMG_OPTIONS
QEMU_IO -- "$QEMU_IO_PROG" $QEMU_IO_OPTIONS
QEMU_NBD -- "$QEMU_NBD_PROG" $QEMU_NBD_OPTIONS
IMGFMT -- $FULL_IMGFMT_DETAILS
IMGPROTO -- $IMGPROTO
PLATFORM -- $FULL_HOST_DETAILS
TEST_DIR -- $TEST_DIR
SOCKET_SCM_HELPER -- $SOCKET_SCM_HELPER
EOF
if ! $makecheck; then
_full_env_details
fi
seq="check"
@ -728,42 +769,43 @@ seq="check"
for seq in $list
do
err=false
printf %s "$seq"
err=false # error flag
printdiff=false # show diff to reference output?
status="" # test result summary
results="" # test result details
if [ -n "$TESTS_REMAINING_LOG" ] ; then
sed -e "s/$seq//" -e 's/ / /' -e 's/^ *//' $TESTS_REMAINING_LOG > $TESTS_REMAINING_LOG.tmp
mv $TESTS_REMAINING_LOG.tmp $TESTS_REMAINING_LOG
sync
fi
lasttime=$(sed -n -e "/^$seq /s/.* //p" <$TIMESTAMP_FILE)
starttime=$(date "+%T")
_report_test_start $seq $starttime $lasttime
if $showme
then
echo
continue
status="not run"
elif [ -f expunged ] && $expunge && egrep "^$seq([ ]|\$)" expunged >/dev/null
then
echo " - expunged"
status="not run"
results="expunged"
rm -f $seq.out.bad
echo "/^$seq\$/d" >>$tmp.expunged
elif [ ! -f "$source_iotests/$seq" ]
then
echo " - no such test?"
status="not run"
results="no such test?"
echo "/^$seq\$/d" >>$tmp.expunged
else
# really going to try and run this one
#
rm -f $seq.out.bad
lasttime=$(sed -n -e "/^$seq /s/.* //p" <$TIMESTAMP_FILE)
if [ "X$lasttime" != X ]; then
printf %s " ${lasttime}s ..."
else
printf " " # prettier output with timestamps.
fi
rm -f core $seq.notrun
rm -f $seq.casenotrun
start=$(_wallclock)
$timestamp && printf %s " [$(date "+%T")]"
if [ "$(head -n 1 "$source_iotests/$seq")" == "#!/usr/bin/env python" ]; then
run_command="$PYTHON $seq"
@ -781,26 +823,26 @@ do
$run_command >$tmp.out 2>&1)
fi
sts=$?
$timestamp && _timestamp
stop=$(_wallclock)
if [ -f core ]
then
printf " [dumped core]"
mv core $seq.core
status="fail"
results="[dumped core] $seq.core"
err=true
fi
if [ -f $seq.notrun ]
then
$timestamp || printf " [not run] "
$timestamp && echo " [not run]" && printf %s " $seq -- "
cat $seq.notrun
notrun="$notrun $seq"
# overwrites timestamp output
status="not run"
results="$(cat $seq.notrun)"
else
if [ $sts -ne 0 ]
then
printf %s " [failed, exit status $sts]"
status="fail"
results=$(printf %s "[failed, exit status $sts]")
err=true
fi
@ -821,22 +863,23 @@ do
if [ ! -f "$reference" ]
then
echo " - no qualified output"
status="fail"
reason="no qualified output"
err=true
else
if diff -w "$reference" $tmp.out >/dev/null 2>&1
then
echo ""
if $err
then
:
else
echo "$seq $(expr $stop - $start)" >>$tmp.time
if ! $err; then
status="pass"
thistime=$(expr $stop - $start)
echo "$seq $thistime" >>$tmp.time
fi
else
echo " - output mismatch (see $seq.out.bad)"
mv $tmp.out $seq.out.bad
$diff -w "$reference" "$PWD"/$seq.out.bad
status="fail"
results="output mismatch (see $seq.out.bad)"
printdiff=true
err=true
fi
fi
@ -850,13 +893,27 @@ do
# come here for each test, except when $showme is true
#
if $err
then
bad="$bad $seq"
n_bad=$(expr $n_bad + 1)
quick=false
fi
[ -f $seq.notrun ] || try=$(expr $try + 1)
_report_test_result $seq "$status" "$starttime" "$lasttime" "$thistime" "$results"
case "$status" in
"pass")
try=$(expr $try + 1)
;;
"fail")
try=$(expr $try + 1)
if $makecheck; then
_full_env_details
fi
if $printdiff; then
$diff -w "$reference" "$PWD"/$seq.out.bad
fi
bad="$bad $seq"
n_bad=$(expr $n_bad + 1)
quick=false
;;
"not run")
notrun="$notrun $seq"
;;
esac
seq="after_$seq"
done

View file

@ -1,8 +1,21 @@
#
# QA groups control file
# Defines test groups
#
# Some notes about the groups:
#
# - do not start group names with a digit
#
# - quick : Tests in this group should finish within some few seconds.
#
# - img : Tests in this group can be used to excercise the qemu-img tool.
#
# - auto : Tests in this group are used during "make check" and should be
# runnable in any case. That means they should run with every QEMU binary
# (also non-x86), with every QEMU configuration (i.e. must not fail if
# an optional feature is not compiled in - but reporting a "skip" is ok),
# and work all kind of host filesystems and users (e.g. "nobody" or "root").
#
#
# test-group association ... one line per test
@ -32,11 +45,11 @@
023 rw auto
024 rw backing auto quick
025 rw auto quick
026 rw blkdbg auto
026 rw blkdbg
027 rw auto quick
028 rw backing auto quick
028 rw backing quick
029 rw auto quick
030 rw auto backing
030 rw backing
031 rw auto quick
032 rw auto quick
033 rw auto quick
@ -46,35 +59,35 @@
037 rw auto backing quick
038 rw auto backing quick
039 rw auto quick
040 rw auto
041 rw auto backing
040 rw
041 rw backing
042 rw auto quick
043 rw auto backing
044 rw auto
045 rw auto quick
044 rw
045 rw quick
046 rw auto aio quick
047 rw auto quick
048 img auto quick
049 rw auto
050 rw auto backing quick
051 rw auto
051 rw
052 rw auto backing quick
053 rw auto quick
054 rw auto quick
055 rw auto
056 rw auto backing
057 rw auto
058 rw auto quick
055 rw
056 rw backing
057 rw
058 rw quick
059 rw auto quick
060 rw auto quick
061 rw auto
062 rw auto quick
063 rw auto quick
064 rw auto quick
065 rw auto quick
065 rw quick
066 rw auto quick
067 rw auto quick
068 rw auto quick
067 rw quick
068 rw quick
069 rw auto quick
070 rw auto quick
071 rw auto quick
@ -91,18 +104,18 @@
082 rw auto quick
083 rw auto
084 img auto quick
085 rw auto
085 rw
086 rw auto quick
087 rw auto quick
087 rw quick
088 rw auto quick
089 rw auto quick
090 rw auto quick
091 rw auto migration
092 rw auto quick
093 auto
093 throttle
094 rw auto quick
095 rw auto quick
096 rw auto quick
095 rw quick
096 rw quick
097 rw auto backing
098 rw auto backing quick
099 rw auto quick
@ -118,60 +131,60 @@
109 rw auto
110 rw auto backing quick
111 rw auto quick
112 rw auto
112 rw
113 rw auto quick
114 rw auto quick
115 rw auto
115 rw
116 rw auto quick
117 rw auto
118 rw auto
118 rw
119 rw auto quick
120 rw auto quick
121 rw auto
121 rw
122 rw auto
123 rw auto quick
124 rw auto backing
125 rw auto
124 rw backing
125 rw
126 rw auto backing
127 rw auto backing quick
127 rw backing quick
128 rw auto quick
129 rw auto quick
129 rw quick
130 rw auto quick
131 rw auto quick
132 rw auto quick
132 rw quick
133 auto quick
134 rw auto quick
135 rw auto
136 rw auto
136 rw
137 rw auto
138 rw auto quick
139 rw auto quick
139 rw quick
140 rw auto quick
141 rw auto quick
142 auto
143 auto quick
144 rw auto quick
145 auto quick
144 rw quick
145 quick
146 auto quick
147 auto
148 rw auto quick
149 rw auto sudo
147 img
148 rw quick
149 rw sudo
150 rw auto quick
151 rw auto
152 rw auto quick
153 rw auto quick
151 rw
152 rw quick
153 rw quick
154 rw auto backing quick
155 rw auto
155 rw
156 rw auto quick
157 auto
157 quick
158 rw auto quick
159 rw auto quick
160 rw auto quick
161 rw auto quick
162 auto quick
163 rw auto
165 rw auto quick
169 rw auto quick migration
162 quick
163 rw
165 rw quick
169 rw quick migration
170 rw auto quick
171 rw auto quick
172 auto
@ -180,74 +193,74 @@
175 auto quick
176 rw auto backing
177 rw auto quick
178 auto
178 img
179 rw auto quick
181 rw auto migration
182 rw auto quick
183 rw auto migration
182 rw quick
183 rw migration
184 rw auto quick
185 rw auto
185 rw
186 rw auto
187 rw auto
188 rw auto quick
189 rw auto
188 rw quick
189 rw
190 rw auto quick
191 rw auto
192 rw auto quick
194 rw auto migration quick
194 rw migration quick
195 rw auto quick
196 rw auto quick migration
196 rw quick migration
197 rw auto quick
198 rw auto
199 rw auto migration
200 rw auto
198 rw
199 rw migration
200 rw
201 rw auto migration
202 rw auto quick
203 rw auto migration
204 rw auto quick
205 rw auto quick
206 rw auto
202 rw quick
203 rw migration
204 rw quick
205 rw quick
206 rw
207 rw auto
208 rw auto quick
209 rw auto quick
208 rw quick
209 rw quick
210 rw auto
211 rw auto quick
212 rw auto quick
213 rw auto quick
214 rw auto
215 rw auto quick
216 rw auto quick
216 rw quick
217 rw auto quick
218 rw auto quick
219 rw auto
218 rw quick
219 rw
220 rw auto
221 rw auto quick
222 rw auto quick
223 rw auto quick
224 rw auto quick
222 rw quick
223 rw quick
224 rw quick
225 rw auto quick
226 auto quick
227 auto quick
228 rw auto quick
227 quick
228 rw quick
229 auto quick
231 auto quick
232 auto quick
232 quick
233 auto quick
234 auto quick migration
235 auto quick
236 auto quick
234 quick migration
235 quick
236 quick
237 rw auto quick
238 auto quick
238 quick
239 rw auto quick
240 auto quick
240 quick
241 rw auto quick
242 rw auto quick
242 rw quick
243 rw auto quick
244 rw auto quick
245 rw auto
246 rw auto quick
247 rw auto quick
248 rw auto quick
245 rw
246 rw quick
247 rw quick
248 rw quick
249 rw auto quick
252 rw auto backing quick
253 rw auto quick

View file

@ -96,6 +96,7 @@ else
# build options for bare programs are usually pretty different. They
# are expected to provide their own build recipes.
-include $(SRC_PATH)/tests/tcg/minilib/Makefile.target
-include $(SRC_PATH)/tests/tcg/multiarch/system/Makefile.softmmu-target
-include $(SRC_PATH)/tests/tcg/$(TARGET_BASE_ARCH)/Makefile.softmmu-target
ifneq ($(TARGET_BASE_ARCH),$(TARGET_NAME))
-include $(SRC_PATH)/tests/tcg/$(TARGET_NAME)/Makefile.softmmu-target

View file

@ -0,0 +1,34 @@
#
# Aarch64 system tests
#
AARCH64_SYSTEM_SRC=$(SRC_PATH)/tests/tcg/aarch64/system
VPATH+=$(AARCH64_SYSTEM_SRC)
# These objects provide the basic boot code and helper functions for all tests
CRT_OBJS=boot.o
AARCH64_TEST_SRCS=$(wildcard $(AARCH64_SYSTEM_SRC)/*.c)
AARCH64_TESTS = $(patsubst $(AARCH64_SYSTEM_SRC)/%.c, %, $(AARCH64_TEST_SRCS))
CRT_PATH=$(AARCH64_SYSTEM_SRC)
LINK_SCRIPT=$(AARCH64_SYSTEM_SRC)/kernel.ld
LDFLAGS=-Wl,-T$(LINK_SCRIPT)
TESTS+=$(AARCH64_TESTS) $(MULTIARCH_TESTS)
CFLAGS+=-nostdlib -ggdb -O0 $(MINILIB_INC)
LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc
# building head blobs
.PRECIOUS: $(CRT_OBJS)
%.o: $(CRT_PATH)/%.S
$(CC) $(CFLAGS) -x assembler-with-cpp -c $< -o $@
# Build and link the tests
%: %.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS)
$(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)
memory: CFLAGS+=-DCHECK_UNALIGNED=1
# Running
QEMU_OPTS+=-M virt -cpu max -display none -semihosting-config enable=on,target=native,chardev=output -kernel

View file

@ -0,0 +1,239 @@
/*
* Minimal AArch64 system boot code.
*
* Copyright Linaro Ltd 2019
*
* Loosely based on the newlib/libgloss setup stubs. Using semihosting
* for serial output and exit functions.
*/
/*
* Semihosting interface on ARM AArch64
* See "Semihosting for AArch32 and AArch64 Relase 2.0" by ARM
* w0 - semihosting call number
* x1 - semihosting parameter
*/
#define semihosting_call hlt 0xf000
#define SYS_WRITEC 0x03 /* character to debug channel */
#define SYS_WRITE0 0x04 /* string to debug channel */
#define SYS_EXIT 0x18
.align 12
.macro ventry label
.align 7
b \label
.endm
vector_table:
/* Current EL with SP0. */
ventry curr_sp0_sync /* Synchronous */
ventry curr_sp0_irq /* Irq/vIRQ */
ventry curr_sp0_fiq /* Fiq/vFIQ */
ventry curr_sp0_serror /* SError/VSError */
/* Current EL with SPx. */
ventry curr_spx_sync /* Synchronous */
ventry curr_spx_irq /* IRQ/vIRQ */
ventry curr_spx_fiq /* FIQ/vFIQ */
ventry curr_spx_serror /* SError/VSError */
/* Lower EL using AArch64. */
ventry lower_a64_sync /* Synchronous */
ventry lower_a64_irq /* IRQ/vIRQ */
ventry lower_a64_fiq /* FIQ/vFIQ */
ventry lower_a64_serror /* SError/VSError */
/* Lower EL using AArch32. */
ventry lower_a32_sync /* Synchronous */
ventry lower_a32_irq /* IRQ/vIRQ */
ventry lower_a32_fiq /* FIQ/vFIQ */
ventry lower_a32_serror /* SError/VSError */
.text
.align 4
/* Common vector handling for now */
curr_sp0_sync:
curr_sp0_irq:
curr_sp0_fiq:
curr_sp0_serror:
curr_spx_sync:
curr_spx_irq:
curr_spx_fiq:
curr_spx_serror:
lower_a64_sync:
lower_a64_irq:
lower_a64_fiq:
lower_a64_serror:
lower_a32_sync:
lower_a32_irq:
lower_a32_fiq:
lower_a32_serror:
mov x0, SYS_WRITE0
adr x1, .error
semihosting_call
mov x0, SYS_EXIT
mov x1, 1
semihosting_call
/* never returns */
.section .rodata
.error:
.string "Terminated by exception.\n"
.text
.align 4
.global __start
__start:
/* Installs a table of exception vectors to catch and handle all
exceptions by terminating the process with a diagnostic. */
adr x0, vector_table
msr vbar_el1, x0
/* Page table setup (identity mapping). */
adrp x0, ttb
add x0, x0, :lo12:ttb
msr ttbr0_el1, x0
/*
* Setup a flat address mapping page-tables. Stage one simply
* maps RAM to the first Gb. The stage2 tables have two 2mb
* translation block entries covering a series of adjacent
* 4k pages.
*/
/* Stage 1 entry: indexed by IA[38:30] */
adr x1, . /* phys address */
bic x1, x1, #(1 << 30) - 1 /* 1GB alignment*/
add x2, x0, x1, lsr #(30 - 3) /* offset in l1 page table */
/* point to stage 2 table [47:12] */
adrp x0, ttb_stage2
orr x1, x0, #3 /* ptr to stage 2 */
str x1, [x2]
/* Stage 2 entries: indexed by IA[29:21] */
ldr x5, =(((1 << 9) - 1) << 21)
/* First block: .text/RO/execute enabled */
adr x1, . /* phys address */
bic x1, x1, #(1 << 21) - 1 /* 2mb block alignment */
and x4, x1, x5 /* IA[29:21] */
add x2, x0, x4, lsr #(21 - 3) /* offset in l2 page table */
ldr x3, =0x401 /* attr(AF, block) */
orr x1, x1, x3
str x1, [x2] /* 1st 2mb (.text & rodata) */
/* Second block: .data/RW/no execute */
adrp x1, .data
add x1, x1, :lo12:.data
bic x1, x1, #(1 << 21) - 1 /* 2mb block alignment */
and x4, x1, x5 /* IA[29:21] */
add x2, x0, x4, lsr #(21 - 3) /* offset in l2 page table */
ldr x3, =(3 << 53) | 0x401 /* attr(AF, NX, block) */
orr x1, x1, x3
str x1, [x2] /* 2nd 2mb (.data & .bss)*/
/* Setup/enable the MMU. */
/*
* TCR_EL1 - Translation Control Registers
*
* IPS[34:32] = 40-bit PA, 1TB
* TG0[14:15] = b00 => 4kb granuale
* ORGN0[11:10] = Outer: Normal, WB Read-Alloc No Write-Alloc Cacheable
* IRGN0[9:8] = Inner: Normal, WB Read-Alloc No Write-Alloc Cacheable
* T0SZ[5:0] = 2^(64 - 25)
*
* The size of T0SZ controls what the initial lookup level. It
* would be nice to start at level 2 but unfortunatly for a
* flat-mapping on the virt machine we need to handle IA's
* with at least 1gb range to see RAM. So we start with a
* level 1 lookup.
*/
ldr x0, = (2 << 32) | 25 | (3 << 10) | (3 << 8)
msr tcr_el1, x0
mov x0, #0xee /* Inner/outer cacheable WB */
msr mair_el1, x0
isb
/*
* SCTLR_EL1 - System Control Register
*
* WXN[19] = 0 = no effect, Write does not imply XN (execute never)
* I[12] = Instruction cachability control
* SA[3] = SP alignment check
* C[2] = Data cachability control
* M[0] = 1, enable stage 1 address translation for EL0/1
*/
mrs x0, sctlr_el1
ldr x1, =0x100d /* bits I(12) SA(3) C(2) M(0) */
bic x0, x0, #(1 << 1) /* clear bit A(1) */
bic x0, x0, #(1 << 19) /* clear WXN */
orr x0, x0, x1 /* set bits */
dsb sy
msr sctlr_el1, x0
isb
/*
* Enable FP registers. The standard C pre-amble will be
* saving these and A-profile compilers will use AdvSIMD
* registers unless we tell it not to.
*/
mrs x0, cpacr_el1
orr x0, x0, #(3 << 20)
msr cpacr_el1, x0
/* Setup some stack space and enter the test code.
* Assume everthing except the return value is garbage when we
* return, we won't need it.
*/
adrp x0, stack_end
add x0, x0, :lo12:stack_end
mov sp, x0
bl main
/* pass return value to sys exit */
mov x1, x0
ldr x0, =0x20026 /* ADP_Stopped_ApplicationExit */
stp x0, x1, [sp, #-16]!
mov x1, sp
mov x0, SYS_EXIT
semihosting_call
/* never returns */
/*
* Helper Functions
*/
/* Output a single character to serial port */
.global __sys_outc
__sys_outc:
stp x0, x1, [sp, #-16]!
/* pass address of c on stack */
mov x1, sp
mov x0, SYS_WRITEC
semihosting_call
ldp x0, x1, [sp], #16
ret
.data
.align 12
/* Translation table
* @4k granuale: 9 bit lookup, 512 entries
*/
ttb:
.space 4096, 0
.align 12
ttb_stage2:
.space 4096, 0
.align 12
stack:
.space 65536, 0
stack_end:

View file

@ -0,0 +1,24 @@
ENTRY(__start)
SECTIONS
{
/* virt machine, RAM starts at 1gb */
. = (1 << 30);
.text : {
*(.text)
}
.rodata : {
*(.rodata)
}
/* align r/w section to next 2mb */
. = ALIGN(1 << 21);
.data : {
*(.data)
}
.bss : {
*(.bss)
}
/DISCARD/ : {
*(.ARM.attributes)
}
}

View file

@ -0,0 +1,34 @@
#
# Alpha system tests
#
ALPHA_SYSTEM_SRC=$(SRC_PATH)/tests/tcg/alpha/system
VPATH+=$(ALPHA_SYSTEM_SRC)
# These objects provide the basic boot code and helper functions for all tests
CRT_OBJS=boot.o
ALPHA_TEST_SRCS=$(wildcard $(ALPHA_SYSTEM_SRC)/*.c)
ALPHA_TESTS = $(patsubst $(ALPHA_SYSTEM_SRC)/%.c, %, $(ALPHA_TEST_SRCS))
CRT_PATH=$(ALPHA_SYSTEM_SRC)
LINK_SCRIPT=$(ALPHA_SYSTEM_SRC)/kernel.ld
LDFLAGS=-Wl,-T$(LINK_SCRIPT)
TESTS+=$(ALPHA_TESTS) $(MULTIARCH_TESTS)
CFLAGS+=-nostdlib -g -O1 -mcpu=ev6 $(MINILIB_INC)
LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc
# building head blobs
.PRECIOUS: $(CRT_OBJS)
%.o: $(CRT_PATH)/%.S
$(CC) $(CFLAGS) -x assembler-with-cpp -c $< -o $@
# Build and link the tests
%: %.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS)
$(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)
memory: CFLAGS+=-DCHECK_UNALIGNED=0
# Running
QEMU_OPTS+=-serial chardev:output -kernel

View file

@ -0,0 +1,511 @@
/*
* Minimal Alpha system boot code.
*
* Copyright Linaro Ltd 2019
*/
.set noat
.set nomacro
.arch ev6
.text
.macro load_pci_io reg
/* For typhoon, this is
* 0xfffffc0000000000 -- kseg identity map
* + 0x10000000000 -- typhoon pio base
* + 0x1fc000000 -- typhoon pchip0 pci base
* = 0xfffffd01fc000000
*/
ldah \reg, -3 /* ff..fd0000 */
lda \reg, 0x1fc(\reg) /* ff..fd01fc */
sll \reg, 24, \reg
.endm
#define com1Rbr 0x3f8
#define com1Thr 0x3f8
#define com1Ier 0x3f9
#define com1Iir 0x3fa
#define com1Lcr 0x3fb
#define com1Mcr 0x3fc
#define com1Lsr 0x3fd
#define com1Msr 0x3fe
#define com1Scr 0x3ff
#define com1Dll 0x3f8
#define com1Dlm 0x3f9
#define PAL_halt 0
#define PAL_wrent 52
#define PAL_wrkgp 55
.text
.p2align 4
.globl _start
.ent _start
_start:
br $gp, .+4
ldah $gp, 0($gp) !gpdisp!1
lda $gp, 0($gp) !gpdisp!1
ldah $sp, $stack_end($gp) !gprelhigh
lda $sp, $stack_end($sp) !gprellow
/* Install kernel gp for exception handlers. */
mov $gp, $16
call_pal PAL_wrkgp
/* Install exception handlers. */
ldah $16, entInt($gp) !gprelhigh
lda $16, entInt($16) !gprellow
lda $17, 0
call_pal PAL_wrent
ldah $16, entArith($gp) !gprelhigh
lda $16, entArith($16) !gprellow
lda $17, 1
call_pal PAL_wrent
ldah $16, entMM($gp) !gprelhigh
lda $16, entMM($16) !gprellow
lda $17, 2
call_pal PAL_wrent
ldah $16, entIF($gp) !gprelhigh
lda $16, entIF($16) !gprellow
lda $17, 3
call_pal PAL_wrent
ldah $16, entUna($gp) !gprelhigh
lda $16, entUna($16) !gprellow
lda $17, 4
call_pal PAL_wrent
ldah $16, entSys($gp) !gprelhigh
lda $16, entSys($16) !gprellow
lda $17, 5
call_pal PAL_wrent
/*
* Initialize COM1.
*/
load_pci_io $1
lda $2, 0x87 /* outb(0x87, com1Lcr); */
stb $2, com1Lcr($1)
stb $31, com1Dlm($1) /* outb(0, com1Dlm); */
lda $2, 3 /* baudconst 3 => 56000 */
stb $2, com1Dll($1) /* outb(baudconst, com1Dll); */
lda $2, 0x07
stb $2, com1Lcr($1) /* outb(0x07, com1Lcr) */
lda $2, 0x0f
stb $2, com1Mcr($1) /* outb(0x0f, com1Mcr) */
bsr $26, main !samegp
/* fall through to _exit */
.end _start
.globl _exit
.ent _exit
_exit:
.frame $sp, 0, $26, 0
.prologue 0
/* We cannot return an error code. */
call_pal PAL_halt
.end _exit
/*
* We have received an exception that we don't handle. Log and exit.
*/
.ent log_exit
log_exit:
entInt:
entArith:
entMM:
entIF:
entUna:
entSys:
ldah $16, $errormsg($gp) !gprelhigh
lda $16, $errormsg($16) !gprellow
bsr $26, __sys_outs !samegp
bsr $26, _exit !samegp
.end log_exit
.section .rodata
$errormsg:
.string "Terminated by exception.\n"
.previous
/*
* Helper Functions
*/
/* Output a single character to serial port */
.global __sys_outc
.ent __sys_outc
__sys_outc:
.frame $sp, 0, $26, 0
.prologue 0
load_pci_io $1
/*
* while ((inb(com1Lsr) & 0x20) == 0)
* continue;
*/
1: ldbu $0, com1Lsr($1)
and $0, 0x20, $0
beq $0, 1b
/* outb(c, com1Thr); */
stb $16, com1Thr($1)
ret
.end __sys_outc
/* Output a nul-terminated string to serial port */
.global __sys_outs
.ent __sys_outs
__sys_outs:
.frame $sp, 0, $26, 0
.prologue 0
load_pci_io $1
ldbu $2, 0($16)
beq $2, 9f
/*
* while ((inb(com1Lsr) & 0x20) == 0)
* continue;
*/
1: ldbu $0, com1Lsr($1)
and $0, 0x20, $0
beq $0, 1b
/* outb(c, com1Thr); */
stb $2, com1Thr($1)
addq $16, 1, $16
ldbu $2, 0($16)
bne $2, 1b
9: ret
.end __sys_outs
/*
* Division routines that are normally in libc.
*
* These do not follow the C calling convention. Arguments are in $24+$25,
* the result is in $27. Register $28 may be clobbered; everything else
* must be saved.
*
* We store the remainder in $28, so that we can share code.
*
* We do not signal divide by zero.
*/
/*
* Unsigned 64-bit division.
*/
.globl __divqu
.ent __divqu
__divqu:
.frame $sp, 48, $23
subq $sp, 48, $sp
stq $0, 0($sp)
stq $1, 8($sp)
stq $2, 16($sp)
stq $3, 24($sp)
stq $4, 32($sp)
.prologue 0
#define mask $0
#define divisor $1
#define compare $2
#define tmp1 $3
#define tmp2 $4
#define quotient $27
#define modulus $28
mov $24, modulus
mov $25, divisor
mov $31, quotient
mov 1, mask
beq $25, 9f
/* Shift left until divisor >= modulus. */
1: cmpult divisor, modulus, compare
blt divisor, 2f
addq divisor, divisor, divisor
addq mask, mask, mask
bne compare, 1b
2: addq quotient, mask, tmp2
srl mask, 1, mask
cmpule divisor, modulus, compare
subq modulus, divisor, tmp1
cmovne compare, tmp2, quotient
srl divisor, 1, divisor
cmovne compare, tmp1, modulus
bne mask, 2b
9: ldq $0, 0($sp)
ldq $1, 8($sp)
ldq $2, 16($sp)
ldq $3, 24($sp)
ldq $4, 32($sp)
addq $sp, 48, $sp
ret $31, ($23), 1
#undef mask
#undef divisor
#undef compare
#undef tmp1
#undef tmp2
#undef quotient
#undef modulus
.end __divqu
/*
* Unsigned 64-bit remainder.
* Note that __divqu above leaves the result in $28.
*/
.globl __remqu
.ent __remqu
__remqu:
.frame $sp, 16, $23
subq $sp, 16, $sp
stq $23, 0($sp)
.prologue 0
bsr $23, __divqu
ldq $23, 0($sp)
mov $28, $27
addq $sp, 16, $sp
ret $31, ($23), 1
.end __remqu
/*
* Signed 64-bit division.
*/
.globl __divqs
.ent __divqs
__divqs:
.prologue 0
/* Common case: both arguments are positive. */
bis $24, $25, $28
bge $28, __divqu
/* At least one argument is negative. */
subq $sp, 32, $sp
stq $23, 0($sp)
stq $24, 8($sp)
stq $25, 16($sp)
/* Compute absolute values. */
subq $31, $24, $28
cmovlt $24, $28, $24
subq $31, $25, $28
cmovlt $25, $28, $25
bsr $23, __divqu
ldq $24, 8($sp)
ldq $25, 16($sp)
/* -a / b = a / -b = -(a / b) */
subq $31, $27, $23
xor $24, $25, $28
cmovlt $28, $23, $27
ldq $23, 0($sp)
addq $sp, 32, $sp
ret $31, ($23), 1
.end __divqs
/*
* Signed 64-bit remainder.
*/
.globl __remqs
.ent __remqs
__remqs:
.prologue 0
/* Common case: both arguments are positive. */
bis $24, $25, $28
bge $28, __remqu
/* At least one argument is negative. */
subq $sp, 32, $sp
stq $23, 0($sp)
stq $24, 8($sp)
stq $25, 16($sp)
/* Compute absolute values. */
subq $31, $24, $28
cmovlt $24, $28, $24
subq $31, $25, $28
cmovlt $25, $28, $25
bsr $23, __divqu
ldq $23, 0($sp)
ldq $24, 8($sp)
ldq $25, 16($sp)
/* -a % b = -(a % b); a % -b = a % b. */
subq $31, $28, $27
cmovge $24, $28, $27
addq $sp, 32, $sp
ret $31, ($23), 1
.end __remqs
/*
* Unsigned 32-bit division.
*/
.globl __divlu
.ent __divlu
__divlu:
.frame $sp, 32, $23
subq $sp, 32, $sp
stq $23, 0($sp)
stq $24, 8($sp)
stq $25, 16($sp)
.prologue 0
/* Zero extend and use the 64-bit routine. */
zap $24, 0xf0, $24
zap $25, 0xf0, $25
bsr $23, __divqu
addl $27, 0, $27
ldq $23, 0($sp)
ldq $24, 8($sp)
ldq $25, 16($sp)
addq $sp, 32, $sp
ret $31, ($23), 1
.end __divlu
/*
* Unsigned 32-bit remainder.
*/
.globl __remlu
.ent __remlu
__remlu:
.frame $sp, 32, $23
subq $sp, 32, $sp
stq $23, 0($sp)
stq $24, 8($sp)
stq $25, 16($sp)
.prologue 0
/* Zero extend and use the 64-bit routine. */
zap $24, 0xf0, $24
zap $25, 0xf0, $25
bsr $23, __divqu
/* Recall that the remainder is returned in $28. */
addl $28, 0, $27
ldq $23, 0($sp)
ldq $24, 8($sp)
ldq $25, 16($sp)
addq $sp, 32, $sp
ret $31, ($23), 1
.end __remlu
/*
* Signed 32-bit division.
*/
.globl __divls
.ent __divls
__divls:
.frame $sp, 32, $23
subq $sp, 32, $sp
stq $23, 0($sp)
stq $24, 8($sp)
stq $25, 16($sp)
.prologue 0
/* Sign extend. */
addl $24, 0, $24
addl $25, 0, $25
/* Compute absolute values. */
subq $31, $24, $28
cmovlt $24, $28, $24
subq $31, $25, $28
cmovlt $25, $28, $25
bsr $23, __divqu
ldq $24, 8($sp)
ldq $25, 16($sp)
/* Negate the unsigned result, if necessary. */
xor $24, $25, $28
subl $31, $27, $23
addl $27, 0, $27
addl $28, 0, $28
cmovlt $28, $23, $27
ldq $23, 0($sp)
addq $sp, 32, $sp
ret $31, ($23), 1
.end __divls
/*
* Signed 32-bit remainder.
*/
.globl __remls
.ent __remls
__remls:
.frame $sp, 32, $23
subq $sp, 32, $sp
stq $23, 0($sp)
stq $24, 8($sp)
stq $25, 16($sp)
.prologue 0
/* Sign extend. */
addl $24, 0, $24
addl $25, 0, $25
/* Compute absolute values. */
subq $31, $24, $28
cmovlt $24, $28, $24
subq $31, $25, $28
cmovlt $25, $28, $25
bsr $23, __divqu
ldq $23, 0($sp)
ldq $24, 8($sp)
ldq $25, 16($sp)
/* Negate the unsigned result, if necessary. */
subl $31, $28, $27
addl $28, 0, $28
cmovge $24, $28, $27
addq $sp, 32, $sp
ret $31, ($23), 1
.end __remls
.data
.p2align 4
stack:
.skip 65536
$stack_end:
.type stack,@object
.size stack, . - stack

View file

@ -0,0 +1,30 @@
ENTRY(_start)
SECTIONS
{
/* Linux kernel legacy start address. */
. = 0xfffffc0000310000;
_text = .;
.text : {
*(.text)
}
.rodata : {
*(.rodata)
}
_etext = .;
. = ALIGN(8192);
_data = .;
.got : {
*(.got)
}
.data : {
*(.sdata)
*(.data)
}
_edata = .;
.bss : {
*(.bss)
}
_end = .;
}

View file

@ -27,7 +27,7 @@ CFLAGS+=-m32
LINK_SCRIPT=$(I386_SYSTEM_SRC)/kernel.ld
LDFLAGS=-Wl,-T$(LINK_SCRIPT) -Wl,-melf_i386
# FIXME: move to common once x86_64 is bootstrapped
TESTS+=$(X86_TESTS)
TESTS+=$(X86_TESTS) $(MULTIARCH_TESTS)
endif
CFLAGS+=-nostdlib -ggdb -O0 $(MINILIB_INC)
LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc
@ -42,5 +42,7 @@ LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc
%: %.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS)
$(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)
memory: CFLAGS+=-DCHECK_UNALIGNED=1
# Running
QEMU_OPTS+=-device isa-debugcon,chardev=output -device isa-debug-exit,iobase=0xf4,iosize=0x4 -kernel

View file

@ -1,243 +0,0 @@
/*
* Memory Test
*
* This is intended to test the softmmu code and ensure we properly
* behave across normal and unaligned accesses across several pages.
* We are not replicating memory tests for stuck bits and other
* hardware level failures but looking for issues with different size
* accesses when:
*
*/
#include <inttypes.h>
#include <minilib.h>
#define TEST_SIZE (4096 * 4) /* 4 pages */
static uint8_t test_data[TEST_SIZE];
static void pdot(int count)
{
if (count % 128 == 0) {
ml_printf(".");
}
}
/*
* Fill the data with ascending value bytes. As x86 is a LE machine we
* write in ascending order and then read and high byte should either
* be zero or higher than the lower bytes.
*/
static void init_test_data_u8(void)
{
uint8_t count = 0, *ptr = &test_data[0];
int i;
ml_printf("Filling test area with u8:");
for (i = 0; i < TEST_SIZE; i++) {
*ptr++ = count++;
pdot(i);
}
ml_printf("done\n");
}
static void init_test_data_u16(int offset)
{
uint8_t count = 0;
uint16_t word, *ptr = (uint16_t *) &test_data[0];
const int max = (TEST_SIZE - offset) / sizeof(word);
int i;
ml_printf("Filling test area with u16 (offset %d):", offset);
/* Leading zeros */
for (i = 0; i < offset; i++) {
*ptr = 0;
}
ptr = (uint16_t *) &test_data[offset];
for (i = 0; i < max; i++) {
uint8_t high, low;
low = count++;
high = count++;
word = (high << 8) | low;
*ptr++ = word;
pdot(i);
}
ml_printf("done\n");
}
static void init_test_data_u32(int offset)
{
uint8_t count = 0;
uint32_t word, *ptr = (uint32_t *) &test_data[0];
const int max = (TEST_SIZE - offset) / sizeof(word);
int i;
ml_printf("Filling test area with u32 (offset %d):", offset);
/* Leading zeros */
for (i = 0; i < offset; i++) {
*ptr = 0;
}
ptr = (uint32_t *) &test_data[offset];
for (i = 0; i < max; i++) {
uint8_t b1, b2, b3, b4;
b4 = count++;
b3 = count++;
b2 = count++;
b1 = count++;
word = (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
*ptr++ = word;
pdot(i);
}
ml_printf("done\n");
}
static int read_test_data_u16(int offset)
{
uint16_t word, *ptr = (uint16_t *)&test_data[offset];
int i;
const int max = (TEST_SIZE - offset) / sizeof(word);
ml_printf("Reading u16 from %#lx (offset %d):", ptr, offset);
for (i = 0; i < max; i++) {
uint8_t high, low;
word = *ptr++;
high = (word >> 8) & 0xff;
low = word & 0xff;
if (high < low && high != 0) {
ml_printf("Error %d < %d\n", high, low);
return 1;
} else {
pdot(i);
}
}
ml_printf("done\n");
return 0;
}
static int read_test_data_u32(int offset)
{
uint32_t word, *ptr = (uint32_t *)&test_data[offset];
int i;
const int max = (TEST_SIZE - offset) / sizeof(word);
ml_printf("Reading u32 from %#lx (offset %d):", ptr, offset);
for (i = 0; i < max; i++) {
uint8_t b1, b2, b3, b4;
word = *ptr++;
b1 = word >> 24 & 0xff;
b2 = word >> 16 & 0xff;
b3 = word >> 8 & 0xff;
b4 = word & 0xff;
if ((b1 < b2 && b1 != 0) ||
(b2 < b3 && b2 != 0) ||
(b3 < b4 && b3 != 0)) {
ml_printf("Error %d, %d, %d, %d", b1, b2, b3, b4);
return 2;
} else {
pdot(i);
}
}
ml_printf("done\n");
return 0;
}
static int read_test_data_u64(int offset)
{
uint64_t word, *ptr = (uint64_t *)&test_data[offset];
int i;
const int max = (TEST_SIZE - offset) / sizeof(word);
ml_printf("Reading u64 from %#lx (offset %d):", ptr, offset);
for (i = 0; i < max; i++) {
uint8_t b1, b2, b3, b4, b5, b6, b7, b8;
word = *ptr++;
b1 = ((uint64_t) (word >> 56)) & 0xff;
b2 = ((uint64_t) (word >> 48)) & 0xff;
b3 = ((uint64_t) (word >> 40)) & 0xff;
b4 = (word >> 32) & 0xff;
b5 = (word >> 24) & 0xff;
b6 = (word >> 16) & 0xff;
b7 = (word >> 8) & 0xff;
b8 = (word >> 0) & 0xff;
if ((b1 < b2 && b1 != 0) ||
(b2 < b3 && b2 != 0) ||
(b3 < b4 && b3 != 0) ||
(b4 < b5 && b4 != 0) ||
(b5 < b6 && b5 != 0) ||
(b6 < b7 && b6 != 0) ||
(b7 < b8 && b7 != 0)) {
ml_printf("Error %d, %d, %d, %d, %d, %d, %d, %d",
b1, b2, b3, b4, b5, b6, b7, b8);
return 2;
} else {
pdot(i);
}
}
ml_printf("done\n");
return 0;
}
/* Read the test data and verify at various offsets */
int do_reads(void)
{
int r = 0;
int off = 0;
while (r == 0 && off < 8) {
r = read_test_data_u16(off);
r |= read_test_data_u32(off);
r |= read_test_data_u64(off);
off++;
}
return r;
}
int main(void)
{
int i, r = 0;
init_test_data_u8();
r = do_reads();
if (r) {
return r;
}
for (i = 0; i < 8; i++) {
init_test_data_u16(i);
r = do_reads();
if (r) {
return r;
}
}
for (i = 0; i < 8; i++) {
init_test_data_u32(i);
r = do_reads();
if (r) {
return r;
}
}
ml_printf("Test complete: %s\n", r == 0 ? "PASSED" : "FAILED");
return r;
}

View file

@ -119,6 +119,9 @@ void ml_printf(const char *fmt, ...)
str = va_arg(ap, char*);
print_str(str);
break;
case 'c':
__sys_outc(va_arg(ap, int));
break;
case '%':
__sys_outc(*fmt);
break;

View file

@ -0,0 +1,14 @@
# -*- Mode: makefile -*-
#
# Multiarch system tests
#
# We just collect the tests together here and rely on the actual guest
# architecture to add to the test dependancies and deal with the
# complications of building.
#
MULTIARCH_SYSTEM_SRC=$(SRC_PATH)/tests/tcg/multiarch/system
VPATH+=$(MULTIARCH_SYSTEM_SRC)
MULTIARCH_TEST_SRCS=$(wildcard $(MULTIARCH_SYSTEM_SRC)/*.c)
MULTIARCH_TESTS = $(patsubst $(MULTIARCH_SYSTEM_SRC)/%.c, %, $(MULTIARCH_TEST_SRCS))

View file

@ -0,0 +1,449 @@
/*
* Memory Test
*
* This is intended to test the softmmu code and ensure we properly
* behave across normal and unaligned accesses across several pages.
* We are not replicating memory tests for stuck bits and other
* hardware level failures but looking for issues with different size
* accesses when access is:
*
* - unaligned at various sizes (if -DCHECK_UNALIGNED set)
* - spanning a (softmmu) page
* - sign extension when loading
*/
#include <inttypes.h>
#include <stdbool.h>
#include <minilib.h>
#ifndef CHECK_UNALIGNED
# error "Target does not specify CHECK_UNALIGNED"
#endif
#define PAGE_SIZE 4096 /* nominal 4k "pages" */
#define TEST_SIZE (PAGE_SIZE * 4) /* 4 pages */
#define ARRAY_SIZE(x) ((sizeof(x) / sizeof((x)[0])))
__attribute__((aligned(PAGE_SIZE)))
static uint8_t test_data[TEST_SIZE];
typedef void (*init_ufn) (int offset);
typedef bool (*read_ufn) (int offset);
typedef bool (*read_sfn) (int offset, bool nf);
static void pdot(int count)
{
if (count % 128 == 0) {
ml_printf(".");
}
}
/*
* Helper macros for shift/extract so we can keep our endian handling
* in one place.
*/
#define BYTE_SHIFT(b, pos) ((uint64_t)b << (pos * 8))
#define BYTE_EXTRACT(b, pos) ((b >> (pos * 8)) & 0xff)
/*
* Fill the data with ascending value bytes.
*
* Currently we only support Little Endian machines so write in
* ascending address order. When we read higher address bytes should
* either be zero or higher than the lower bytes.
*/
static void init_test_data_u8(int unused_offset)
{
uint8_t count = 0, *ptr = &test_data[0];
int i;
(void)(unused_offset);
ml_printf("Filling test area with u8:");
for (i = 0; i < TEST_SIZE; i++) {
*ptr++ = count++;
pdot(i);
}
ml_printf("done\n");
}
/*
* Full the data with alternating positive and negative bytes. This
* should mean for reads larger than a byte all subsequent reads will
* stay either negative or positive. We never write 0.
*/
static inline uint8_t get_byte(int index, bool neg)
{
return neg ? (0xff << (index % 7)) : (0xff >> ((index % 6) + 1));
}
static void init_test_data_s8(bool neg_first)
{
uint8_t top, bottom, *ptr = &test_data[0];
int i;
ml_printf("Filling test area with s8 pairs (%s):",
neg_first ? "neg first" : "pos first");
for (i = 0; i < TEST_SIZE / 2; i++) {
*ptr++ = get_byte(i, neg_first);
*ptr++ = get_byte(i, !neg_first);
pdot(i);
}
ml_printf("done\n");
}
/*
* Zero the first few bytes of the test data in preparation for
* new offset values.
*/
static void reset_start_data(int offset)
{
uint32_t *ptr = (uint32_t *) &test_data[0];
int i;
for (i = 0; i < offset; i++) {
*ptr++ = 0;
}
}
static void init_test_data_u16(int offset)
{
uint8_t count = 0;
uint16_t word, *ptr = (uint16_t *) &test_data[offset];
const int max = (TEST_SIZE - offset) / sizeof(word);
int i;
ml_printf("Filling test area with u16 (offset %d, %p):", offset, ptr);
reset_start_data(offset);
for (i = 0; i < max; i++) {
uint8_t low = count++, high = count++;
word = BYTE_SHIFT(high, 1) | BYTE_SHIFT(low, 0);
*ptr++ = word;
pdot(i);
}
ml_printf("done @ %p\n", ptr);
}
static void init_test_data_u32(int offset)
{
uint8_t count = 0;
uint32_t word, *ptr = (uint32_t *) &test_data[offset];
const int max = (TEST_SIZE - offset) / sizeof(word);
int i;
ml_printf("Filling test area with u32 (offset %d, %p):", offset, ptr);
reset_start_data(offset);
for (i = 0; i < max; i++) {
uint8_t b4 = count++, b3 = count++;
uint8_t b2 = count++, b1 = count++;
word = BYTE_SHIFT(b1, 3) | BYTE_SHIFT(b2, 2) | BYTE_SHIFT(b3, 1) | b4;
*ptr++ = word;
pdot(i);
}
ml_printf("done @ %p\n", ptr);
}
static void init_test_data_u64(int offset)
{
uint8_t count = 0;
uint64_t word, *ptr = (uint64_t *) &test_data[offset];
const int max = (TEST_SIZE - offset) / sizeof(word);
int i;
ml_printf("Filling test area with u64 (offset %d, %p):", offset, ptr);
reset_start_data(offset);
for (i = 0; i < max; i++) {
uint8_t b8 = count++, b7 = count++;
uint8_t b6 = count++, b5 = count++;
uint8_t b4 = count++, b3 = count++;
uint8_t b2 = count++, b1 = count++;
word = BYTE_SHIFT(b1, 7) | BYTE_SHIFT(b2, 6) | BYTE_SHIFT(b3, 5) |
BYTE_SHIFT(b4, 4) | BYTE_SHIFT(b5, 3) | BYTE_SHIFT(b6, 2) |
BYTE_SHIFT(b7, 1) | b8;
*ptr++ = word;
pdot(i);
}
ml_printf("done @ %p\n", ptr);
}
static bool read_test_data_u16(int offset)
{
uint16_t word, *ptr = (uint16_t *)&test_data[offset];
int i;
const int max = (TEST_SIZE - offset) / sizeof(word);
ml_printf("Reading u16 from %#lx (offset %d):", ptr, offset);
for (i = 0; i < max; i++) {
uint8_t high, low;
word = *ptr++;
high = (word >> 8) & 0xff;
low = word & 0xff;
if (high < low && high != 0) {
ml_printf("Error %d < %d\n", high, low);
return false;
} else {
pdot(i);
}
}
ml_printf("done @ %p\n", ptr);
return true;
}
static bool read_test_data_u32(int offset)
{
uint32_t word, *ptr = (uint32_t *)&test_data[offset];
int i;
const int max = (TEST_SIZE - offset) / sizeof(word);
ml_printf("Reading u32 from %#lx (offset %d):", ptr, offset);
for (i = 0; i < max; i++) {
uint8_t b1, b2, b3, b4;
word = *ptr++;
b1 = word >> 24 & 0xff;
b2 = word >> 16 & 0xff;
b3 = word >> 8 & 0xff;
b4 = word & 0xff;
if ((b1 < b2 && b1 != 0) ||
(b2 < b3 && b2 != 0) ||
(b3 < b4 && b3 != 0)) {
ml_printf("Error %d, %d, %d, %d", b1, b2, b3, b4);
return false;
} else {
pdot(i);
}
}
ml_printf("done @ %p\n", ptr);
return true;
}
static bool read_test_data_u64(int offset)
{
uint64_t word, *ptr = (uint64_t *)&test_data[offset];
int i;
const int max = (TEST_SIZE - offset) / sizeof(word);
ml_printf("Reading u64 from %#lx (offset %d):", ptr, offset);
for (i = 0; i < max; i++) {
uint8_t b1, b2, b3, b4, b5, b6, b7, b8;
word = *ptr++;
b1 = ((uint64_t) (word >> 56)) & 0xff;
b2 = ((uint64_t) (word >> 48)) & 0xff;
b3 = ((uint64_t) (word >> 40)) & 0xff;
b4 = (word >> 32) & 0xff;
b5 = (word >> 24) & 0xff;
b6 = (word >> 16) & 0xff;
b7 = (word >> 8) & 0xff;
b8 = (word >> 0) & 0xff;
if ((b1 < b2 && b1 != 0) ||
(b2 < b3 && b2 != 0) ||
(b3 < b4 && b3 != 0) ||
(b4 < b5 && b4 != 0) ||
(b5 < b6 && b5 != 0) ||
(b6 < b7 && b6 != 0) ||
(b7 < b8 && b7 != 0)) {
ml_printf("Error %d, %d, %d, %d, %d, %d, %d, %d",
b1, b2, b3, b4, b5, b6, b7, b8);
return false;
} else {
pdot(i);
}
}
ml_printf("done @ %p\n", ptr);
return true;
}
/* Read the test data and verify at various offsets */
read_ufn read_ufns[] = { read_test_data_u16,
read_test_data_u32,
read_test_data_u64 };
bool do_unsigned_reads(void)
{
int i;
bool ok = true;
for (i = 0; i < ARRAY_SIZE(read_ufns) && ok; i++) {
#if CHECK_UNALIGNED
int off;
for (off = 0; off < 8 && ok; off++) {
ok = read_ufns[i](off);
}
#else
ok = read_ufns[i](0);
#endif
}
return ok;
}
static bool do_unsigned_test(init_ufn fn)
{
#if CHECK_UNALIGNED
bool ok = true;
int i;
for (i = 0; i < 8 && ok; i++) {
fn(i);
ok = do_unsigned_reads();
}
#else
fn(0);
return do_unsigned_reads();
#endif
}
/*
* We need to ensure signed data is read into a larger data type to
* ensure that sign extension is working properly.
*/
static bool read_test_data_s8(int offset, bool neg_first)
{
int8_t *ptr = (int8_t *)&test_data[offset];
int i;
const int max = (TEST_SIZE - offset) / 2;
ml_printf("Reading s8 pairs from %#lx (offset %d):", ptr, offset);
for (i = 0; i < max; i++) {
int16_t first, second;
bool ok;
first = *ptr++;
second = *ptr++;
if (neg_first && first < 0 && second > 0) {
pdot(i);
} else if (!neg_first && first > 0 && second < 0) {
pdot(i);
} else {
ml_printf("Error %d %c %d\n", first, neg_first ? '<' : '>', second);
return false;
}
}
ml_printf("done @ %p\n", ptr);
return true;
}
static bool read_test_data_s16(int offset, bool neg_first)
{
int16_t *ptr = (int16_t *)&test_data[offset];
int i;
const int max = (TEST_SIZE - offset) / (sizeof(*ptr));
ml_printf("Reading s16 from %#lx (offset %d, %s):", ptr,
offset, neg_first ? "neg" : "pos");
for (i = 0; i < max; i++) {
int32_t data = *ptr++;
if (neg_first && data < 0) {
pdot(i);
} else if (data > 0) {
pdot(i);
} else {
ml_printf("Error %d %c 0\n", data, neg_first ? '<' : '>');
return false;
}
}
ml_printf("done @ %p\n", ptr);
return true;
}
static bool read_test_data_s32(int offset, bool neg_first)
{
int32_t *ptr = (int32_t *)&test_data[offset];
int i;
const int max = (TEST_SIZE - offset) / (sizeof(int32_t));
ml_printf("Reading s32 from %#lx (offset %d, %s):",
ptr, offset, neg_first ? "neg" : "pos");
for (i = 0; i < max; i++) {
int64_t data = *ptr++;
if (neg_first && data < 0) {
pdot(i);
} else if (data > 0) {
pdot(i);
} else {
ml_printf("Error %d %c 0\n", data, neg_first ? '<' : '>');
return false;
}
}
ml_printf("done @ %p\n", ptr);
return true;
}
/*
* Read the test data and verify at various offsets
*
* For everything except bytes all our reads should be either positive
* or negative depending on what offset we are reading from. Currently
* we only handle LE systems.
*/
read_sfn read_sfns[] = { read_test_data_s8,
read_test_data_s16,
read_test_data_s32 };
bool do_signed_reads(bool neg_first)
{
int i;
bool ok = true;
for (i = 0; i < ARRAY_SIZE(read_sfns) && ok; i++) {
#if CHECK_UNALIGNED
int off;
for (off = 0; off < 8 && ok; off++) {
bool nf = i == 0 ? neg_first ^ (off & 1) : !(neg_first ^ (off & 1));
ok = read_sfns[i](off, nf);
}
#else
ok = read_sfns[i](0, i == 0 ? neg_first : !neg_first);
#endif
}
return ok;
}
init_ufn init_ufns[] = { init_test_data_u8,
init_test_data_u16,
init_test_data_u32,
init_test_data_u64 };
int main(void)
{
int i;
bool ok = true;
/* Run through the unsigned tests first */
for (i = 0; i < ARRAY_SIZE(init_ufns) && ok; i++) {
ok = do_unsigned_test(init_ufns[i]);
}
if (ok) {
init_test_data_s8(false);
ok = do_signed_reads(false);
}
if (ok) {
init_test_data_s8(true);
ok = do_signed_reads(true);
}
ml_printf("Test complete: %s\n", ok ? "PASSED" : "FAILED");
return ok ? 0 : -1;
}

128
vl.c
View file

@ -116,7 +116,7 @@ int main(int argc, char **argv)
#include "qapi/opts-visitor.h"
#include "qapi/clone-visitor.h"
#include "qom/object_interfaces.h"
#include "exec/semihost.h"
#include "hw/semihosting/semihost.h"
#include "crypto/init.h"
#include "sysemu/replay.h"
#include "qapi/qapi-events-run-state.h"
@ -501,25 +501,6 @@ static QemuOptsList qemu_icount_opts = {
},
};
static QemuOptsList qemu_semihosting_config_opts = {
.name = "semihosting-config",
.implied_opt_name = "enable",
.head = QTAILQ_HEAD_INITIALIZER(qemu_semihosting_config_opts.head),
.desc = {
{
.name = "enable",
.type = QEMU_OPT_BOOL,
}, {
.name = "target",
.type = QEMU_OPT_STRING,
}, {
.name = "arg",
.type = QEMU_OPT_STRING,
},
{ /* end of list */ }
},
};
static QemuOptsList qemu_fw_cfg_opts = {
.name = "fw_cfg",
.implied_opt_name = "name",
@ -1351,80 +1332,6 @@ static void configure_msg(QemuOpts *opts)
enable_timestamp_msg = qemu_opt_get_bool(opts, "timestamp", true);
}
/***********************************************************/
/* Semihosting */
typedef struct SemihostingConfig {
bool enabled;
SemihostingTarget target;
const char **argv;
int argc;
const char *cmdline; /* concatenated argv */
} SemihostingConfig;
static SemihostingConfig semihosting;
bool semihosting_enabled(void)
{
return semihosting.enabled;
}
SemihostingTarget semihosting_get_target(void)
{
return semihosting.target;
}
const char *semihosting_get_arg(int i)
{
if (i >= semihosting.argc) {
return NULL;
}
return semihosting.argv[i];
}
int semihosting_get_argc(void)
{
return semihosting.argc;
}
const char *semihosting_get_cmdline(void)
{
if (semihosting.cmdline == NULL && semihosting.argc > 0) {
semihosting.cmdline = g_strjoinv(" ", (gchar **)semihosting.argv);
}
return semihosting.cmdline;
}
static int add_semihosting_arg(void *opaque,
const char *name, const char *val,
Error **errp)
{
SemihostingConfig *s = opaque;
if (strcmp(name, "arg") == 0) {
s->argc++;
/* one extra element as g_strjoinv() expects NULL-terminated array */
s->argv = g_realloc(s->argv, (s->argc + 1) * sizeof(void *));
s->argv[s->argc - 1] = val;
s->argv[s->argc] = NULL;
}
return 0;
}
/* Use strings passed via -kernel/-append to initialize semihosting.argv[] */
static inline void semihosting_arg_fallback(const char *file, const char *cmd)
{
char *cmd_token;
/* argv[0] */
add_semihosting_arg(&semihosting, "arg", file, NULL);
/* split -append and initialize argv[1..n] */
cmd_token = strtok(g_strdup(cmd), " ");
while (cmd_token) {
add_semihosting_arg(&semihosting, "arg", cmd_token, NULL);
cmd_token = strtok(NULL, " ");
}
}
/* Now we still need this for compatibility with XEN. */
bool has_igd_gfx_passthru;
@ -3743,37 +3650,10 @@ int main(int argc, char **argv, char **envp)
nb_option_roms++;
break;
case QEMU_OPTION_semihosting:
semihosting.enabled = true;
semihosting.target = SEMIHOSTING_TARGET_AUTO;
qemu_semihosting_enable();
break;
case QEMU_OPTION_semihosting_config:
semihosting.enabled = true;
opts = qemu_opts_parse_noisily(qemu_find_opts("semihosting-config"),
optarg, false);
if (opts != NULL) {
semihosting.enabled = qemu_opt_get_bool(opts, "enable",
true);
const char *target = qemu_opt_get(opts, "target");
if (target != NULL) {
if (strcmp("native", target) == 0) {
semihosting.target = SEMIHOSTING_TARGET_NATIVE;
} else if (strcmp("gdb", target) == 0) {
semihosting.target = SEMIHOSTING_TARGET_GDB;
} else if (strcmp("auto", target) == 0) {
semihosting.target = SEMIHOSTING_TARGET_AUTO;
} else {
error_report("unsupported semihosting-config %s",
optarg);
exit(1);
}
} else {
semihosting.target = SEMIHOSTING_TARGET_AUTO;
}
/* Set semihosting argument count and vector */
qemu_opt_foreach(opts, add_semihosting_arg,
&semihosting, NULL);
} else {
error_report("unsupported semihosting-config %s", optarg);
if (qemu_semihosting_config_options(optarg) != 0) {
exit(1);
}
break;
@ -4290,6 +4170,8 @@ int main(int argc, char **argv, char **envp)
qemu_opts_foreach(qemu_find_opts("chardev"),
chardev_init_func, NULL, &error_fatal);
/* now chardevs have been created we may have semihosting to connect */
qemu_semihosting_connect_chardevs();
#ifdef CONFIG_VIRTFS
qemu_opts_foreach(qemu_find_opts("fsdev"),