mirror of https://github.com/xemu-project/xemu.git
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:
commit
8c1ecb5904
|
@ -26,6 +26,11 @@ file_type_emacs = makefile
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 4
|
indent_size = 4
|
||||||
|
|
||||||
|
[*.{s,S}]
|
||||||
|
indent_style = tab
|
||||||
|
indent_size = 8
|
||||||
|
file_type_emacs = asm
|
||||||
|
|
||||||
[*.{vert,frag}]
|
[*.{vert,frag}]
|
||||||
file_type_emacs = glsl
|
file_type_emacs = glsl
|
||||||
|
|
||||||
|
|
|
@ -284,5 +284,5 @@ matrix:
|
||||||
|
|
||||||
# Run check-tcg against softmmu targets
|
# Run check-tcg against softmmu targets
|
||||||
- env:
|
- 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"
|
- TEST_CMD="make -j3 check-tcg V=1"
|
||||||
|
|
|
@ -470,6 +470,7 @@ M: Richard Henderson <rth@twiddle.net>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: hw/alpha/
|
F: hw/alpha/
|
||||||
F: hw/isa/smc37c669-superio.c
|
F: hw/isa/smc37c669-superio.c
|
||||||
|
F: tests/tcg/alpha/system/
|
||||||
|
|
||||||
ARM Machines
|
ARM Machines
|
||||||
------------
|
------------
|
||||||
|
@ -2563,6 +2564,13 @@ F: docs/pvrdma.txt
|
||||||
F: contrib/rdmacm-mux/*
|
F: contrib/rdmacm-mux/*
|
||||||
F: qapi/rdma.json
|
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
|
||||||
-------------------------
|
-------------------------
|
||||||
Build and test automation
|
Build and test automation
|
||||||
|
|
4
Makefile
4
Makefile
|
@ -1009,7 +1009,9 @@ $(filter %.1 %.7 %.8,$(DOCS)): scripts/texi2pod.pl
|
||||||
%/coverage-report.html:
|
%/coverage-report.html:
|
||||||
@mkdir -p $*
|
@mkdir -p $*
|
||||||
$(call quiet-command,\
|
$(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 $@, \
|
-p --html --html-details -o $@, \
|
||||||
"GEN", "coverage-report.html")
|
"GEN", "coverage-report.html")
|
||||||
|
|
||||||
|
|
|
@ -238,3 +238,19 @@ endif
|
||||||
|
|
||||||
generated-files-y += config-target.h
|
generated-files-y += config-target.h
|
||||||
Makefile: $(generated-files-y)
|
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
|
||||||
|
|
|
@ -39,3 +39,4 @@ CONFIG_MICROBIT=y
|
||||||
CONFIG_FSL_IMX25=y
|
CONFIG_FSL_IMX25=y
|
||||||
CONFIG_FSL_IMX7=y
|
CONFIG_FSL_IMX7=y
|
||||||
CONFIG_FSL_IMX6UL=y
|
CONFIG_FSL_IMX6UL=y
|
||||||
|
CONFIG_SEMIHOSTING=y
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
#
|
#
|
||||||
#CONFIG_MILKYMIST_TMU2=n # disabling it actually causes compile-time failures
|
#CONFIG_MILKYMIST_TMU2=n # disabling it actually causes compile-time failures
|
||||||
|
|
||||||
|
CONFIG_SEMIHOSTING=y
|
||||||
|
|
||||||
# Boards:
|
# Boards:
|
||||||
#
|
#
|
||||||
CONFIG_LM32=y
|
CONFIG_LM32=y
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
# Default configuration for m68k-softmmu
|
# Default configuration for m68k-softmmu
|
||||||
|
|
||||||
|
CONFIG_SEMIHOSTING=y
|
||||||
|
|
||||||
# Boards:
|
# Boards:
|
||||||
#
|
#
|
||||||
CONFIG_AN5206=y
|
CONFIG_AN5206=y
|
||||||
|
|
|
@ -35,6 +35,7 @@ CONFIG_MIPS_CPS=y
|
||||||
CONFIG_MIPS_ITU=y
|
CONFIG_MIPS_ITU=y
|
||||||
CONFIG_R4K=y
|
CONFIG_R4K=y
|
||||||
CONFIG_MALTA=y
|
CONFIG_MALTA=y
|
||||||
|
CONFIG_SEMIHOSTING=y
|
||||||
CONFIG_PCNET_PCI=y
|
CONFIG_PCNET_PCI=y
|
||||||
CONFIG_MIPSSIM=y
|
CONFIG_MIPSSIM=y
|
||||||
CONFIG_ACPI_SMBUS=y
|
CONFIG_ACPI_SMBUS=y
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
# Default configuration for nios2-softmmu
|
# Default configuration for nios2-softmmu
|
||||||
|
|
||||||
|
CONFIG_SEMIHOSTING=y
|
||||||
|
|
||||||
# Boards:
|
# Boards:
|
||||||
#
|
#
|
||||||
CONFIG_NIOS2_10M50=y
|
CONFIG_NIOS2_10M50=y
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
# Default configuration for Xtensa
|
# Default configuration for Xtensa
|
||||||
|
|
||||||
|
CONFIG_SEMIHOSTING=y
|
||||||
|
|
||||||
# Boards:
|
# Boards:
|
||||||
#
|
#
|
||||||
CONFIG_XTENSA_SIM=y
|
CONFIG_XTENSA_SIM=y
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
#include "qemu/sockets.h"
|
#include "qemu/sockets.h"
|
||||||
#include "sysemu/hw_accel.h"
|
#include "sysemu/hw_accel.h"
|
||||||
#include "sysemu/kvm.h"
|
#include "sysemu/kvm.h"
|
||||||
#include "exec/semihost.h"
|
#include "hw/semihosting/semihost.h"
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
|
|
||||||
#ifdef CONFIG_USER_ONLY
|
#ifdef CONFIG_USER_ONLY
|
||||||
|
|
|
@ -29,6 +29,7 @@ source pci/Kconfig
|
||||||
source rdma/Kconfig
|
source rdma/Kconfig
|
||||||
source scsi/Kconfig
|
source scsi/Kconfig
|
||||||
source sd/Kconfig
|
source sd/Kconfig
|
||||||
|
source semihosting/Kconfig
|
||||||
source smbios/Kconfig
|
source smbios/Kconfig
|
||||||
source ssi/Kconfig
|
source ssi/Kconfig
|
||||||
source timer/Kconfig
|
source timer/Kconfig
|
||||||
|
|
|
@ -36,6 +36,7 @@ devices-dirs-$(CONFIG_SOFTMMU) += watchdog/
|
||||||
devices-dirs-$(CONFIG_SOFTMMU) += xen/
|
devices-dirs-$(CONFIG_SOFTMMU) += xen/
|
||||||
devices-dirs-$(CONFIG_MEM_DEVICE) += mem/
|
devices-dirs-$(CONFIG_MEM_DEVICE) += mem/
|
||||||
devices-dirs-$(CONFIG_SOFTMMU) += smbios/
|
devices-dirs-$(CONFIG_SOFTMMU) += smbios/
|
||||||
|
devices-dirs-y += semihosting/
|
||||||
devices-dirs-y += core/
|
devices-dirs-y += core/
|
||||||
common-obj-y += $(devices-dirs-y)
|
common-obj-y += $(devices-dirs-y)
|
||||||
obj-y += $(devices-dirs-y)
|
obj-y += $(devices-dirs-y)
|
||||||
|
|
|
@ -55,7 +55,7 @@
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
#include "hw/empty_slot.h"
|
#include "hw/empty_slot.h"
|
||||||
#include "sysemu/kvm.h"
|
#include "sysemu/kvm.h"
|
||||||
#include "exec/semihost.h"
|
#include "hw/semihosting/semihost.h"
|
||||||
#include "hw/mips/cps.h"
|
#include "hw/mips/cps.h"
|
||||||
|
|
||||||
#define ENVP_ADDR 0x80002000l
|
#define ENVP_ADDR 0x80002000l
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
config SEMIHOSTING
|
||||||
|
bool
|
|
@ -0,0 +1,2 @@
|
||||||
|
obj-$(CONFIG_SEMIHOSTING) += config.o
|
||||||
|
obj-$(CONFIG_SEMIHOSTING) += console.o
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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_ */
|
|
@ -51,12 +51,23 @@ static inline const char *semihosting_get_cmdline(void)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
|
static inline Chardev *semihosting_get_chardev(void)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#else /* !CONFIG_USER_ONLY */
|
||||||
bool semihosting_enabled(void);
|
bool semihosting_enabled(void);
|
||||||
SemihostingTarget semihosting_get_target(void);
|
SemihostingTarget semihosting_get_target(void);
|
||||||
const char *semihosting_get_arg(int i);
|
const char *semihosting_get_arg(int i);
|
||||||
int semihosting_get_argc(void);
|
int semihosting_get_argc(void);
|
||||||
const char *semihosting_get_cmdline(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 */
|
|
@ -193,5 +193,6 @@ extern QemuOptsList qemu_nic_opts;
|
||||||
extern QemuOptsList qemu_net_opts;
|
extern QemuOptsList qemu_net_opts;
|
||||||
extern QemuOptsList qemu_global_opts;
|
extern QemuOptsList qemu_global_opts;
|
||||||
extern QemuOptsList qemu_mon_opts;
|
extern QemuOptsList qemu_mon_opts;
|
||||||
|
extern QemuOptsList qemu_semihosting_config_opts;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -6,4 +6,6 @@ obj-y = main.o syscall.o strace.o mmap.o signal.o \
|
||||||
obj-$(TARGET_HAS_BFLT) += flatload.o
|
obj-$(TARGET_HAS_BFLT) += flatload.o
|
||||||
obj-$(TARGET_I386) += vm86.o
|
obj-$(TARGET_I386) += vm86.o
|
||||||
obj-$(TARGET_ARM) += arm/nwfpe/
|
obj-$(TARGET_ARM) += arm/nwfpe/
|
||||||
|
obj-$(TARGET_ARM) += arm/semihost.o
|
||||||
|
obj-$(TARGET_AARCH64) += arm/semihost.o
|
||||||
obj-$(TARGET_M68K) += m68k-sim.o
|
obj-$(TARGET_M68K) += m68k-sim.o
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -4025,12 +4025,12 @@ STEXI
|
||||||
Enable semihosting mode (ARM, M68K, Xtensa, MIPS, Nios II only).
|
Enable semihosting mode (ARM, M68K, Xtensa, MIPS, Nios II only).
|
||||||
ETEXI
|
ETEXI
|
||||||
DEF("semihosting-config", HAS_ARG, QEMU_OPTION_semihosting_config,
|
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",
|
" semihosting configuration\n",
|
||||||
QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32 |
|
QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32 |
|
||||||
QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2)
|
QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2)
|
||||||
STEXI
|
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
|
@findex -semihosting-config
|
||||||
Enable and configure semihosting (ARM, M68K, Xtensa, MIPS, Nios II only).
|
Enable and configure semihosting (ARM, M68K, Xtensa, MIPS, Nios II only).
|
||||||
@table @option
|
@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})
|
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}
|
or to GDB (@code{gdb}). The default is @code{auto}, which means @code{gdb}
|
||||||
during debug sessions and @code{native} otherwise.
|
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},...
|
@item arg=@var{str1},arg=@var{str2},...
|
||||||
Allows the user to pass input arguments, and can be used multiple times to build
|
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
|
up a list. The old-style @code{-kernel}/@code{-append} method of passing a
|
||||||
|
|
|
@ -40,3 +40,4 @@ stub-obj-y += pci-host-piix.o
|
||||||
stub-obj-y += ram-block.o
|
stub-obj-y += ram-block.o
|
||||||
stub-obj-y += ramfb.o
|
stub-obj-y += ramfb.o
|
||||||
stub-obj-y += fw_cfg.o
|
stub-obj-y += fw_cfg.o
|
||||||
|
stub-obj-$(CONFIG_SOFTMMU) += semihost.o
|
||||||
|
|
|
@ -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)
|
||||||
|
{
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
* Arm "Angel" semihosting syscalls
|
* Arm "Angel" semihosting syscalls
|
||||||
*
|
*
|
||||||
* Copyright (c) 2005, 2007 CodeSourcery.
|
* Copyright (c) 2005, 2007 CodeSourcery.
|
||||||
|
* Copyright (c) 2019 Linaro
|
||||||
* Written by Paul Brook.
|
* Written by Paul Brook.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
* 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 "qemu/osdep.h"
|
||||||
|
|
||||||
#include "cpu.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
|
#ifdef CONFIG_USER_ONLY
|
||||||
#include "qemu.h"
|
#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_u64(val, args + (n) * 8) : \
|
||||||
put_user_u32(val, args + (n) * 4))
|
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)
|
target_ulong do_arm_semihosting(CPUARMState *env)
|
||||||
{
|
{
|
||||||
ARMCPU *cpu = arm_env_get_cpu(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));
|
return set_swi_errno(ts, close(arg0));
|
||||||
}
|
}
|
||||||
case TARGET_SYS_WRITEC:
|
case TARGET_SYS_WRITEC:
|
||||||
{
|
qemu_semihosting_console_out(env, args, 1);
|
||||||
char c;
|
return 0xdeadbeef;
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case TARGET_SYS_WRITE0:
|
case TARGET_SYS_WRITE0:
|
||||||
if (!(s = lock_user_string(args)))
|
return qemu_semihosting_console_out(env, args, 0);
|
||||||
/* 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;
|
|
||||||
case TARGET_SYS_WRITE:
|
case TARGET_SYS_WRITE:
|
||||||
GET_ARG(0);
|
GET_ARG(0);
|
||||||
GET_ARG(1);
|
GET_ARG(1);
|
||||||
|
@ -337,13 +331,15 @@ target_ulong do_arm_semihosting(CPUARMState *env)
|
||||||
} else {
|
} else {
|
||||||
s = lock_user(VERIFY_READ, arg1, len, 1);
|
s = lock_user(VERIFY_READ, arg1, len, 1);
|
||||||
if (!s) {
|
if (!s) {
|
||||||
/* FIXME - should this error code be -TARGET_EFAULT ? */
|
/* Return bytes not written on error */
|
||||||
return (uint32_t)-1;
|
return len;
|
||||||
}
|
}
|
||||||
ret = set_swi_errno(ts, write(arg0, s, len));
|
ret = set_swi_errno(ts, write(arg0, s, len));
|
||||||
unlock_user(s, arg1, 0);
|
unlock_user(s, arg1, 0);
|
||||||
if (ret == (uint32_t)-1)
|
if (ret == (uint32_t)-1) {
|
||||||
return -1;
|
ret = 0;
|
||||||
|
}
|
||||||
|
/* Return bytes not written */
|
||||||
return len - ret;
|
return len - ret;
|
||||||
}
|
}
|
||||||
case TARGET_SYS_READ:
|
case TARGET_SYS_READ:
|
||||||
|
@ -358,19 +354,21 @@ target_ulong do_arm_semihosting(CPUARMState *env)
|
||||||
} else {
|
} else {
|
||||||
s = lock_user(VERIFY_WRITE, arg1, len, 0);
|
s = lock_user(VERIFY_WRITE, arg1, len, 0);
|
||||||
if (!s) {
|
if (!s) {
|
||||||
/* FIXME - should this error code be -TARGET_EFAULT ? */
|
/* return bytes not read */
|
||||||
return (uint32_t)-1;
|
return len;
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
ret = set_swi_errno(ts, read(arg0, s, len));
|
ret = set_swi_errno(ts, read(arg0, s, len));
|
||||||
} while (ret == -1 && errno == EINTR);
|
} while (ret == -1 && errno == EINTR);
|
||||||
unlock_user(s, arg1, len);
|
unlock_user(s, arg1, len);
|
||||||
if (ret == (uint32_t)-1)
|
if (ret == (uint32_t)-1) {
|
||||||
return -1;
|
ret = 0;
|
||||||
|
}
|
||||||
|
/* Return bytes not read */
|
||||||
return len - ret;
|
return len - ret;
|
||||||
}
|
}
|
||||||
case TARGET_SYS_READC:
|
case TARGET_SYS_READC:
|
||||||
/* XXX: Read from debug console. Not implemented. */
|
qemu_log_mask(LOG_UNIMP, "%s: SYS_READC not implemented", __func__);
|
||||||
return 0;
|
return 0;
|
||||||
case TARGET_SYS_ISTTY:
|
case TARGET_SYS_ISTTY:
|
||||||
GET_ARG(0);
|
GET_ARG(0);
|
||||||
|
@ -404,7 +402,7 @@ target_ulong do_arm_semihosting(CPUARMState *env)
|
||||||
return buf.st_size;
|
return buf.st_size;
|
||||||
}
|
}
|
||||||
case TARGET_SYS_TMPNAM:
|
case TARGET_SYS_TMPNAM:
|
||||||
/* XXX: Not implemented. */
|
qemu_log_mask(LOG_UNIMP, "%s: SYS_TMPNAM not implemented", __func__);
|
||||||
return -1;
|
return -1;
|
||||||
case TARGET_SYS_REMOVE:
|
case TARGET_SYS_REMOVE:
|
||||||
GET_ARG(0);
|
GET_ARG(0);
|
||||||
|
@ -509,14 +507,16 @@ target_ulong do_arm_semihosting(CPUARMState *env)
|
||||||
|
|
||||||
output_size = ts->info->arg_end - ts->info->arg_start;
|
output_size = ts->info->arg_end - ts->info->arg_start;
|
||||||
if (!output_size) {
|
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;
|
output_size = 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (output_size > input_size) {
|
if (output_size > input_size) {
|
||||||
/* Not enough space to store command-line arguments. */
|
/* Not enough space to store command-line arguments. */
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -570,8 +570,10 @@ target_ulong do_arm_semihosting(CPUARMState *env)
|
||||||
GET_ARG(0);
|
GET_ARG(0);
|
||||||
|
|
||||||
#ifdef CONFIG_USER_ONLY
|
#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) {
|
if (!ts->heap_limit) {
|
||||||
abi_ulong ret;
|
abi_ulong ret;
|
||||||
|
|
||||||
|
@ -619,7 +621,8 @@ target_ulong do_arm_semihosting(CPUARMState *env)
|
||||||
}
|
}
|
||||||
case TARGET_SYS_EXIT:
|
case TARGET_SYS_EXIT:
|
||||||
if (is_a64(env)) {
|
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
|
* so the application-exit type can return a subcode which
|
||||||
* is the exit status code from the application.
|
* is the exit status code from the application.
|
||||||
*/
|
*/
|
||||||
|
@ -632,14 +635,17 @@ target_ulong do_arm_semihosting(CPUARMState *env)
|
||||||
ret = 1;
|
ret = 1;
|
||||||
}
|
}
|
||||||
} else {
|
} 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;
|
ret = (args == ADP_Stopped_ApplicationExit) ? 0 : 1;
|
||||||
}
|
}
|
||||||
gdb_exit(env, ret);
|
gdb_exit(env, ret);
|
||||||
exit(ret);
|
exit(ret);
|
||||||
case TARGET_SYS_SYNCCACHE:
|
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
|
* virtual address range. This is a nop for us since we don't
|
||||||
* implement caches. This is only present on A64.
|
* implement caches. This is only present on A64.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
#include "exec/cpu_ldst.h"
|
#include "exec/cpu_ldst.h"
|
||||||
#include "arm_ldst.h"
|
#include "arm_ldst.h"
|
||||||
#include <zlib.h> /* For crc32 */
|
#include <zlib.h> /* For crc32 */
|
||||||
#include "exec/semihost.h"
|
#include "hw/semihosting/semihost.h"
|
||||||
#include "sysemu/cpus.h"
|
#include "sysemu/cpus.h"
|
||||||
#include "sysemu/kvm.h"
|
#include "sysemu/kvm.h"
|
||||||
#include "fpu/softfloat.h"
|
#include "fpu/softfloat.h"
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
#include "qemu/host-utils.h"
|
#include "qemu/host-utils.h"
|
||||||
#include "qemu/qemu-print.h"
|
#include "qemu/qemu-print.h"
|
||||||
|
|
||||||
#include "exec/semihost.h"
|
#include "hw/semihosting/semihost.h"
|
||||||
#include "exec/gen-icount.h"
|
#include "exec/gen-icount.h"
|
||||||
|
|
||||||
#include "exec/helper-proto.h"
|
#include "exec/helper-proto.h"
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
#include "qemu/bitops.h"
|
#include "qemu/bitops.h"
|
||||||
#include "qemu/qemu-print.h"
|
#include "qemu/qemu-print.h"
|
||||||
#include "arm_ldst.h"
|
#include "arm_ldst.h"
|
||||||
#include "exec/semihost.h"
|
#include "hw/semihosting/semihost.h"
|
||||||
|
|
||||||
#include "exec/helper-proto.h"
|
#include "exec/helper-proto.h"
|
||||||
#include "exec/helper-gen.h"
|
#include "exec/helper-gen.h"
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "qemu/host-utils.h"
|
#include "qemu/host-utils.h"
|
||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
#include "exec/semihost.h"
|
#include "hw/semihosting/semihost.h"
|
||||||
#include "exec/log.h"
|
#include "exec/log.h"
|
||||||
|
|
||||||
bool lm32_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
bool lm32_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#include "exec/helper-proto.h"
|
#include "exec/helper-proto.h"
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "exec/cpu_ldst.h"
|
#include "exec/cpu_ldst.h"
|
||||||
#include "exec/semihost.h"
|
#include "hw/semihosting/semihost.h"
|
||||||
|
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
obj-y += translate.o dsp_helper.o op_helper.o lmi_helper.o helper.o cpu.o
|
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_SOFTMMU) += machine.o cp0_timer.o
|
||||||
obj-$(CONFIG_KVM) += kvm.o
|
obj-$(CONFIG_KVM) += kvm.o
|
||||||
|
|
|
@ -2,7 +2,9 @@ DEF_HELPER_3(raise_exception_err, noreturn, env, i32, int)
|
||||||
DEF_HELPER_2(raise_exception, noreturn, env, i32)
|
DEF_HELPER_2(raise_exception, noreturn, env, i32)
|
||||||
DEF_HELPER_1(raise_exception_debug, noreturn, env)
|
DEF_HELPER_1(raise_exception_debug, noreturn, env)
|
||||||
|
|
||||||
|
#ifndef CONFIG_USER_ONLY
|
||||||
DEF_HELPER_1(do_semihosting, void, env)
|
DEF_HELPER_1(do_semihosting, void, env)
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef TARGET_MIPS64
|
#ifdef TARGET_MIPS64
|
||||||
DEF_HELPER_4(sdl, void, env, tl, tl, int)
|
DEF_HELPER_4(sdl, void, env, tl, tl, int)
|
||||||
|
|
|
@ -22,7 +22,8 @@
|
||||||
#include "qemu/log.h"
|
#include "qemu/log.h"
|
||||||
#include "exec/helper-proto.h"
|
#include "exec/helper-proto.h"
|
||||||
#include "exec/softmmu-semi.h"
|
#include "exec/softmmu-semi.h"
|
||||||
#include "exec/semihost.h"
|
#include "hw/semihosting/semihost.h"
|
||||||
|
#include "hw/semihosting/console.h"
|
||||||
|
|
||||||
typedef enum UHIOp {
|
typedef enum UHIOp {
|
||||||
UHI_exit = 1,
|
UHI_exit = 1,
|
||||||
|
@ -329,13 +330,12 @@ void helper_do_semihosting(CPUMIPSState *env)
|
||||||
p2 = strstr(p, "%d");
|
p2 = strstr(p, "%d");
|
||||||
if (p2) {
|
if (p2) {
|
||||||
int char_num = p2 - p;
|
int char_num = p2 - p;
|
||||||
char *buf = g_malloc(char_num + 1);
|
GString *s = g_string_new_len(p, char_num);
|
||||||
strncpy(buf, p, char_num);
|
g_string_append_printf(s, "%d%s", (int)gpr[5], p2 + 2);
|
||||||
buf[char_num] = '\0';
|
gpr[2] = qemu_semihosting_log_out(s->str, s->len);
|
||||||
gpr[2] = printf("%s%d%s", buf, (int)gpr[5], p2 + 2);
|
g_string_free(s, true);
|
||||||
g_free(buf);
|
|
||||||
} else {
|
} else {
|
||||||
gpr[2] = printf("%s", p);
|
gpr[2] = qemu_semihosting_log_out(p, strlen(p));
|
||||||
}
|
}
|
||||||
FREE_TARGET_STRING(p, gpr[4]);
|
FREE_TARGET_STRING(p, gpr[4]);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
|
|
||||||
#include "exec/helper-proto.h"
|
#include "exec/helper-proto.h"
|
||||||
#include "exec/helper-gen.h"
|
#include "exec/helper-gen.h"
|
||||||
#include "exec/semihost.h"
|
#include "hw/semihosting/semihost.h"
|
||||||
|
|
||||||
#include "target/mips/trace.h"
|
#include "target/mips/trace.h"
|
||||||
#include "trace-tcg.h"
|
#include "trace-tcg.h"
|
||||||
|
@ -13726,6 +13726,14 @@ static inline bool is_uhi(int sdbbp_code)
|
||||||
#endif
|
#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)
|
static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx)
|
||||||
{
|
{
|
||||||
int rx, ry;
|
int rx, ry;
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
#include "exec/cpu_ldst.h"
|
#include "exec/cpu_ldst.h"
|
||||||
#include "exec/log.h"
|
#include "exec/log.h"
|
||||||
#include "exec/helper-proto.h"
|
#include "exec/helper-proto.h"
|
||||||
#include "exec/semihost.h"
|
#include "hw/semihosting/semihost.h"
|
||||||
|
|
||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
#include "qemu/qemu-print.h"
|
#include "qemu/qemu-print.h"
|
||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
#include "exec/cpu_ldst.h"
|
#include "exec/cpu_ldst.h"
|
||||||
#include "exec/semihost.h"
|
#include "hw/semihosting/semihost.h"
|
||||||
#include "exec/translator.h"
|
#include "exec/translator.h"
|
||||||
|
|
||||||
#include "exec/helper-proto.h"
|
#include "exec/helper-proto.h"
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "chardev/char-fe.h"
|
#include "chardev/char-fe.h"
|
||||||
#include "exec/helper-proto.h"
|
#include "exec/helper-proto.h"
|
||||||
#include "exec/semihost.h"
|
#include "hw/semihosting/semihost.h"
|
||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
#include "qemu/log.h"
|
#include "qemu/log.h"
|
||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
|
|
|
@ -8,6 +8,7 @@ ENV PACKAGES \
|
||||||
bzip2-devel \
|
bzip2-devel \
|
||||||
ccache \
|
ccache \
|
||||||
clang \
|
clang \
|
||||||
|
cyrus-sasl-devel \
|
||||||
device-mapper-multipath-devel \
|
device-mapper-multipath-devel \
|
||||||
findutils \
|
findutils \
|
||||||
flex \
|
flex \
|
||||||
|
@ -23,13 +24,17 @@ ENV PACKAGES \
|
||||||
libaio-devel \
|
libaio-devel \
|
||||||
libasan \
|
libasan \
|
||||||
libattr-devel \
|
libattr-devel \
|
||||||
|
libblockdev-mpath-devel \
|
||||||
libcap-devel \
|
libcap-devel \
|
||||||
libcap-ng-devel \
|
libcap-ng-devel \
|
||||||
libcurl-devel \
|
libcurl-devel \
|
||||||
libfdt-devel \
|
libfdt-devel \
|
||||||
|
libiscsi-devel \
|
||||||
libjpeg-devel \
|
libjpeg-devel \
|
||||||
|
libpmem-devel \
|
||||||
libpng-devel \
|
libpng-devel \
|
||||||
librbd-devel \
|
librbd-devel \
|
||||||
|
libseccomp-devel \
|
||||||
libssh2-devel \
|
libssh2-devel \
|
||||||
libubsan \
|
libubsan \
|
||||||
libusbx-devel \
|
libusbx-devel \
|
||||||
|
@ -74,10 +79,12 @@ ENV PACKAGES \
|
||||||
pixman-devel \
|
pixman-devel \
|
||||||
python3 \
|
python3 \
|
||||||
PyYAML \
|
PyYAML \
|
||||||
|
rdma-core-devel \
|
||||||
SDL2-devel \
|
SDL2-devel \
|
||||||
snappy-devel \
|
snappy-devel \
|
||||||
sparse \
|
sparse \
|
||||||
spice-server-devel \
|
spice-server-devel \
|
||||||
|
systemd-devel \
|
||||||
systemtap-sdt-devel \
|
systemtap-sdt-devel \
|
||||||
tar \
|
tar \
|
||||||
usbredir-devel \
|
usbredir-devel \
|
||||||
|
|
|
@ -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
|
|
@ -27,9 +27,7 @@ bad=""
|
||||||
notrun=""
|
notrun=""
|
||||||
casenotrun=""
|
casenotrun=""
|
||||||
interrupt=true
|
interrupt=true
|
||||||
|
makecheck=false
|
||||||
# by default don't output timestamps
|
|
||||||
timestamp=${TIMESTAMP:=false}
|
|
||||||
|
|
||||||
_init_error()
|
_init_error()
|
||||||
{
|
{
|
||||||
|
@ -88,6 +86,22 @@ _full_platform_details()
|
||||||
echo "$os/$platform $host $kernel"
|
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
|
# $1 = prog to look for
|
||||||
set_prog_path()
|
set_prog_path()
|
||||||
{
|
{
|
||||||
|
@ -254,8 +268,8 @@ other options
|
||||||
-misalign misalign memory allocations
|
-misalign misalign memory allocations
|
||||||
-n show me, do not run tests
|
-n show me, do not run tests
|
||||||
-o options -o options to pass to qemu-img create/convert
|
-o options -o options to pass to qemu-img create/convert
|
||||||
-T output timestamps
|
|
||||||
-c mode cache mode
|
-c mode cache mode
|
||||||
|
-makecheck pretty print output for make check
|
||||||
|
|
||||||
testlist options
|
testlist options
|
||||||
-g group[,group...] include tests from these groups
|
-g group[,group...] include tests from these groups
|
||||||
|
@ -403,7 +417,10 @@ testlist options
|
||||||
command -v xxdiff >/dev/null 2>&1 && diff=xxdiff
|
command -v xxdiff >/dev/null 2>&1 && diff=xxdiff
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
|
-makecheck) # makecheck friendly output
|
||||||
|
makecheck=true
|
||||||
|
xpand=false
|
||||||
|
;;
|
||||||
-n) # show me, don't do it
|
-n) # show me, don't do it
|
||||||
showme=true
|
showme=true
|
||||||
xpand=false
|
xpand=false
|
||||||
|
@ -416,8 +433,7 @@ testlist options
|
||||||
cachemode=true
|
cachemode=true
|
||||||
xpand=false
|
xpand=false
|
||||||
;;
|
;;
|
||||||
-T) # turn on timestamp output
|
-T) # deprecated timestamp option
|
||||||
timestamp=true
|
|
||||||
xpand=false
|
xpand=false
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
@ -633,12 +649,6 @@ _wallclock()
|
||||||
date "+%H %M %S" | awk '{ print $1*3600 + $2*60 + $3 }'
|
date "+%H %M %S" | awk '{ print $1*3600 + $2*60 + $3 }'
|
||||||
}
|
}
|
||||||
|
|
||||||
_timestamp()
|
|
||||||
{
|
|
||||||
now=$(date "+%T")
|
|
||||||
printf %s " [$now]"
|
|
||||||
}
|
|
||||||
|
|
||||||
_wrapup()
|
_wrapup()
|
||||||
{
|
{
|
||||||
if $showme
|
if $showme
|
||||||
|
@ -704,23 +714,54 @@ END { if (NR > 0) {
|
||||||
|
|
||||||
trap "_wrapup; exit \$status" 0 1 2 3 15
|
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
|
[ -f $TIMESTAMP_FILE ] || touch $TIMESTAMP_FILE
|
||||||
|
|
||||||
FULL_IMGFMT_DETAILS=$(_full_imgfmt_details)
|
FULL_IMGFMT_DETAILS=$(_full_imgfmt_details)
|
||||||
FULL_HOST_DETAILS=$(_full_platform_details)
|
FULL_HOST_DETAILS=$(_full_platform_details)
|
||||||
|
|
||||||
cat <<EOF
|
if ! $makecheck; then
|
||||||
QEMU -- "$QEMU_PROG" $QEMU_OPTIONS
|
_full_env_details
|
||||||
QEMU_IMG -- "$QEMU_IMG_PROG" $QEMU_IMG_OPTIONS
|
fi
|
||||||
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
|
|
||||||
|
|
||||||
seq="check"
|
seq="check"
|
||||||
|
|
||||||
|
@ -728,42 +769,43 @@ seq="check"
|
||||||
|
|
||||||
for seq in $list
|
for seq in $list
|
||||||
do
|
do
|
||||||
err=false
|
err=false # error flag
|
||||||
printf %s "$seq"
|
printdiff=false # show diff to reference output?
|
||||||
|
status="" # test result summary
|
||||||
|
results="" # test result details
|
||||||
|
|
||||||
if [ -n "$TESTS_REMAINING_LOG" ] ; then
|
if [ -n "$TESTS_REMAINING_LOG" ] ; then
|
||||||
sed -e "s/$seq//" -e 's/ / /' -e 's/^ *//' $TESTS_REMAINING_LOG > $TESTS_REMAINING_LOG.tmp
|
sed -e "s/$seq//" -e 's/ / /' -e 's/^ *//' $TESTS_REMAINING_LOG > $TESTS_REMAINING_LOG.tmp
|
||||||
mv $TESTS_REMAINING_LOG.tmp $TESTS_REMAINING_LOG
|
mv $TESTS_REMAINING_LOG.tmp $TESTS_REMAINING_LOG
|
||||||
sync
|
sync
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
lasttime=$(sed -n -e "/^$seq /s/.* //p" <$TIMESTAMP_FILE)
|
||||||
|
starttime=$(date "+%T")
|
||||||
|
_report_test_start $seq $starttime $lasttime
|
||||||
|
|
||||||
if $showme
|
if $showme
|
||||||
then
|
then
|
||||||
echo
|
status="not run"
|
||||||
continue
|
|
||||||
elif [ -f expunged ] && $expunge && egrep "^$seq([ ]|\$)" expunged >/dev/null
|
elif [ -f expunged ] && $expunge && egrep "^$seq([ ]|\$)" expunged >/dev/null
|
||||||
then
|
then
|
||||||
echo " - expunged"
|
status="not run"
|
||||||
|
results="expunged"
|
||||||
rm -f $seq.out.bad
|
rm -f $seq.out.bad
|
||||||
echo "/^$seq\$/d" >>$tmp.expunged
|
echo "/^$seq\$/d" >>$tmp.expunged
|
||||||
elif [ ! -f "$source_iotests/$seq" ]
|
elif [ ! -f "$source_iotests/$seq" ]
|
||||||
then
|
then
|
||||||
echo " - no such test?"
|
status="not run"
|
||||||
|
results="no such test?"
|
||||||
echo "/^$seq\$/d" >>$tmp.expunged
|
echo "/^$seq\$/d" >>$tmp.expunged
|
||||||
else
|
else
|
||||||
# really going to try and run this one
|
# really going to try and run this one
|
||||||
#
|
#
|
||||||
rm -f $seq.out.bad
|
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 core $seq.notrun
|
||||||
rm -f $seq.casenotrun
|
rm -f $seq.casenotrun
|
||||||
|
|
||||||
start=$(_wallclock)
|
start=$(_wallclock)
|
||||||
$timestamp && printf %s " [$(date "+%T")]"
|
|
||||||
|
|
||||||
if [ "$(head -n 1 "$source_iotests/$seq")" == "#!/usr/bin/env python" ]; then
|
if [ "$(head -n 1 "$source_iotests/$seq")" == "#!/usr/bin/env python" ]; then
|
||||||
run_command="$PYTHON $seq"
|
run_command="$PYTHON $seq"
|
||||||
|
@ -781,26 +823,26 @@ do
|
||||||
$run_command >$tmp.out 2>&1)
|
$run_command >$tmp.out 2>&1)
|
||||||
fi
|
fi
|
||||||
sts=$?
|
sts=$?
|
||||||
$timestamp && _timestamp
|
|
||||||
stop=$(_wallclock)
|
stop=$(_wallclock)
|
||||||
|
|
||||||
if [ -f core ]
|
if [ -f core ]
|
||||||
then
|
then
|
||||||
printf " [dumped core]"
|
|
||||||
mv core $seq.core
|
mv core $seq.core
|
||||||
|
status="fail"
|
||||||
|
results="[dumped core] $seq.core"
|
||||||
err=true
|
err=true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -f $seq.notrun ]
|
if [ -f $seq.notrun ]
|
||||||
then
|
then
|
||||||
$timestamp || printf " [not run] "
|
# overwrites timestamp output
|
||||||
$timestamp && echo " [not run]" && printf %s " $seq -- "
|
status="not run"
|
||||||
cat $seq.notrun
|
results="$(cat $seq.notrun)"
|
||||||
notrun="$notrun $seq"
|
|
||||||
else
|
else
|
||||||
if [ $sts -ne 0 ]
|
if [ $sts -ne 0 ]
|
||||||
then
|
then
|
||||||
printf %s " [failed, exit status $sts]"
|
status="fail"
|
||||||
|
results=$(printf %s "[failed, exit status $sts]")
|
||||||
err=true
|
err=true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -821,22 +863,23 @@ do
|
||||||
|
|
||||||
if [ ! -f "$reference" ]
|
if [ ! -f "$reference" ]
|
||||||
then
|
then
|
||||||
echo " - no qualified output"
|
status="fail"
|
||||||
|
reason="no qualified output"
|
||||||
err=true
|
err=true
|
||||||
else
|
else
|
||||||
if diff -w "$reference" $tmp.out >/dev/null 2>&1
|
if diff -w "$reference" $tmp.out >/dev/null 2>&1
|
||||||
then
|
then
|
||||||
echo ""
|
if ! $err; then
|
||||||
if $err
|
status="pass"
|
||||||
then
|
thistime=$(expr $stop - $start)
|
||||||
:
|
echo "$seq $thistime" >>$tmp.time
|
||||||
else
|
|
||||||
echo "$seq $(expr $stop - $start)" >>$tmp.time
|
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo " - output mismatch (see $seq.out.bad)"
|
|
||||||
mv $tmp.out $seq.out.bad
|
mv $tmp.out $seq.out.bad
|
||||||
$diff -w "$reference" "$PWD"/$seq.out.bad
|
$diff -w "$reference" "$PWD"/$seq.out.bad
|
||||||
|
status="fail"
|
||||||
|
results="output mismatch (see $seq.out.bad)"
|
||||||
|
printdiff=true
|
||||||
err=true
|
err=true
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
@ -850,13 +893,27 @@ do
|
||||||
|
|
||||||
# come here for each test, except when $showme is true
|
# come here for each test, except when $showme is true
|
||||||
#
|
#
|
||||||
if $err
|
_report_test_result $seq "$status" "$starttime" "$lasttime" "$thistime" "$results"
|
||||||
then
|
case "$status" in
|
||||||
bad="$bad $seq"
|
"pass")
|
||||||
n_bad=$(expr $n_bad + 1)
|
try=$(expr $try + 1)
|
||||||
quick=false
|
;;
|
||||||
fi
|
"fail")
|
||||||
[ -f $seq.notrun ] || try=$(expr $try + 1)
|
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"
|
seq="after_$seq"
|
||||||
done
|
done
|
||||||
|
|
|
@ -1,8 +1,21 @@
|
||||||
#
|
#
|
||||||
# QA groups control file
|
# QA groups control file
|
||||||
# Defines test groups
|
# Defines test groups
|
||||||
|
#
|
||||||
|
# Some notes about the groups:
|
||||||
|
#
|
||||||
# - do not start group names with a digit
|
# - 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
|
# test-group association ... one line per test
|
||||||
|
@ -32,11 +45,11 @@
|
||||||
023 rw auto
|
023 rw auto
|
||||||
024 rw backing auto quick
|
024 rw backing auto quick
|
||||||
025 rw auto quick
|
025 rw auto quick
|
||||||
026 rw blkdbg auto
|
026 rw blkdbg
|
||||||
027 rw auto quick
|
027 rw auto quick
|
||||||
028 rw backing auto quick
|
028 rw backing quick
|
||||||
029 rw auto quick
|
029 rw auto quick
|
||||||
030 rw auto backing
|
030 rw backing
|
||||||
031 rw auto quick
|
031 rw auto quick
|
||||||
032 rw auto quick
|
032 rw auto quick
|
||||||
033 rw auto quick
|
033 rw auto quick
|
||||||
|
@ -46,35 +59,35 @@
|
||||||
037 rw auto backing quick
|
037 rw auto backing quick
|
||||||
038 rw auto backing quick
|
038 rw auto backing quick
|
||||||
039 rw auto quick
|
039 rw auto quick
|
||||||
040 rw auto
|
040 rw
|
||||||
041 rw auto backing
|
041 rw backing
|
||||||
042 rw auto quick
|
042 rw auto quick
|
||||||
043 rw auto backing
|
043 rw auto backing
|
||||||
044 rw auto
|
044 rw
|
||||||
045 rw auto quick
|
045 rw quick
|
||||||
046 rw auto aio quick
|
046 rw auto aio quick
|
||||||
047 rw auto quick
|
047 rw auto quick
|
||||||
048 img auto quick
|
048 img auto quick
|
||||||
049 rw auto
|
049 rw auto
|
||||||
050 rw auto backing quick
|
050 rw auto backing quick
|
||||||
051 rw auto
|
051 rw
|
||||||
052 rw auto backing quick
|
052 rw auto backing quick
|
||||||
053 rw auto quick
|
053 rw auto quick
|
||||||
054 rw auto quick
|
054 rw auto quick
|
||||||
055 rw auto
|
055 rw
|
||||||
056 rw auto backing
|
056 rw backing
|
||||||
057 rw auto
|
057 rw
|
||||||
058 rw auto quick
|
058 rw quick
|
||||||
059 rw auto quick
|
059 rw auto quick
|
||||||
060 rw auto quick
|
060 rw auto quick
|
||||||
061 rw auto
|
061 rw auto
|
||||||
062 rw auto quick
|
062 rw auto quick
|
||||||
063 rw auto quick
|
063 rw auto quick
|
||||||
064 rw auto quick
|
064 rw auto quick
|
||||||
065 rw auto quick
|
065 rw quick
|
||||||
066 rw auto quick
|
066 rw auto quick
|
||||||
067 rw auto quick
|
067 rw quick
|
||||||
068 rw auto quick
|
068 rw quick
|
||||||
069 rw auto quick
|
069 rw auto quick
|
||||||
070 rw auto quick
|
070 rw auto quick
|
||||||
071 rw auto quick
|
071 rw auto quick
|
||||||
|
@ -91,18 +104,18 @@
|
||||||
082 rw auto quick
|
082 rw auto quick
|
||||||
083 rw auto
|
083 rw auto
|
||||||
084 img auto quick
|
084 img auto quick
|
||||||
085 rw auto
|
085 rw
|
||||||
086 rw auto quick
|
086 rw auto quick
|
||||||
087 rw auto quick
|
087 rw quick
|
||||||
088 rw auto quick
|
088 rw auto quick
|
||||||
089 rw auto quick
|
089 rw auto quick
|
||||||
090 rw auto quick
|
090 rw auto quick
|
||||||
091 rw auto migration
|
091 rw auto migration
|
||||||
092 rw auto quick
|
092 rw auto quick
|
||||||
093 auto
|
093 throttle
|
||||||
094 rw auto quick
|
094 rw auto quick
|
||||||
095 rw auto quick
|
095 rw quick
|
||||||
096 rw auto quick
|
096 rw quick
|
||||||
097 rw auto backing
|
097 rw auto backing
|
||||||
098 rw auto backing quick
|
098 rw auto backing quick
|
||||||
099 rw auto quick
|
099 rw auto quick
|
||||||
|
@ -118,60 +131,60 @@
|
||||||
109 rw auto
|
109 rw auto
|
||||||
110 rw auto backing quick
|
110 rw auto backing quick
|
||||||
111 rw auto quick
|
111 rw auto quick
|
||||||
112 rw auto
|
112 rw
|
||||||
113 rw auto quick
|
113 rw auto quick
|
||||||
114 rw auto quick
|
114 rw auto quick
|
||||||
115 rw auto
|
115 rw
|
||||||
116 rw auto quick
|
116 rw auto quick
|
||||||
117 rw auto
|
117 rw auto
|
||||||
118 rw auto
|
118 rw
|
||||||
119 rw auto quick
|
119 rw auto quick
|
||||||
120 rw auto quick
|
120 rw auto quick
|
||||||
121 rw auto
|
121 rw
|
||||||
122 rw auto
|
122 rw auto
|
||||||
123 rw auto quick
|
123 rw auto quick
|
||||||
124 rw auto backing
|
124 rw backing
|
||||||
125 rw auto
|
125 rw
|
||||||
126 rw auto backing
|
126 rw auto backing
|
||||||
127 rw auto backing quick
|
127 rw backing quick
|
||||||
128 rw auto quick
|
128 rw auto quick
|
||||||
129 rw auto quick
|
129 rw quick
|
||||||
130 rw auto quick
|
130 rw auto quick
|
||||||
131 rw auto quick
|
131 rw auto quick
|
||||||
132 rw auto quick
|
132 rw quick
|
||||||
133 auto quick
|
133 auto quick
|
||||||
134 rw auto quick
|
134 rw auto quick
|
||||||
135 rw auto
|
135 rw auto
|
||||||
136 rw auto
|
136 rw
|
||||||
137 rw auto
|
137 rw auto
|
||||||
138 rw auto quick
|
138 rw auto quick
|
||||||
139 rw auto quick
|
139 rw quick
|
||||||
140 rw auto quick
|
140 rw auto quick
|
||||||
141 rw auto quick
|
141 rw auto quick
|
||||||
142 auto
|
142 auto
|
||||||
143 auto quick
|
143 auto quick
|
||||||
144 rw auto quick
|
144 rw quick
|
||||||
145 auto quick
|
145 quick
|
||||||
146 auto quick
|
146 auto quick
|
||||||
147 auto
|
147 img
|
||||||
148 rw auto quick
|
148 rw quick
|
||||||
149 rw auto sudo
|
149 rw sudo
|
||||||
150 rw auto quick
|
150 rw auto quick
|
||||||
151 rw auto
|
151 rw
|
||||||
152 rw auto quick
|
152 rw quick
|
||||||
153 rw auto quick
|
153 rw quick
|
||||||
154 rw auto backing quick
|
154 rw auto backing quick
|
||||||
155 rw auto
|
155 rw
|
||||||
156 rw auto quick
|
156 rw auto quick
|
||||||
157 auto
|
157 quick
|
||||||
158 rw auto quick
|
158 rw auto quick
|
||||||
159 rw auto quick
|
159 rw auto quick
|
||||||
160 rw auto quick
|
160 rw auto quick
|
||||||
161 rw auto quick
|
161 rw auto quick
|
||||||
162 auto quick
|
162 quick
|
||||||
163 rw auto
|
163 rw
|
||||||
165 rw auto quick
|
165 rw quick
|
||||||
169 rw auto quick migration
|
169 rw quick migration
|
||||||
170 rw auto quick
|
170 rw auto quick
|
||||||
171 rw auto quick
|
171 rw auto quick
|
||||||
172 auto
|
172 auto
|
||||||
|
@ -180,74 +193,74 @@
|
||||||
175 auto quick
|
175 auto quick
|
||||||
176 rw auto backing
|
176 rw auto backing
|
||||||
177 rw auto quick
|
177 rw auto quick
|
||||||
178 auto
|
178 img
|
||||||
179 rw auto quick
|
179 rw auto quick
|
||||||
181 rw auto migration
|
181 rw auto migration
|
||||||
182 rw auto quick
|
182 rw quick
|
||||||
183 rw auto migration
|
183 rw migration
|
||||||
184 rw auto quick
|
184 rw auto quick
|
||||||
185 rw auto
|
185 rw
|
||||||
186 rw auto
|
186 rw auto
|
||||||
187 rw auto
|
187 rw auto
|
||||||
188 rw auto quick
|
188 rw quick
|
||||||
189 rw auto
|
189 rw
|
||||||
190 rw auto quick
|
190 rw auto quick
|
||||||
191 rw auto
|
191 rw auto
|
||||||
192 rw auto quick
|
192 rw auto quick
|
||||||
194 rw auto migration quick
|
194 rw migration quick
|
||||||
195 rw auto quick
|
195 rw auto quick
|
||||||
196 rw auto quick migration
|
196 rw quick migration
|
||||||
197 rw auto quick
|
197 rw auto quick
|
||||||
198 rw auto
|
198 rw
|
||||||
199 rw auto migration
|
199 rw migration
|
||||||
200 rw auto
|
200 rw
|
||||||
201 rw auto migration
|
201 rw auto migration
|
||||||
202 rw auto quick
|
202 rw quick
|
||||||
203 rw auto migration
|
203 rw migration
|
||||||
204 rw auto quick
|
204 rw quick
|
||||||
205 rw auto quick
|
205 rw quick
|
||||||
206 rw auto
|
206 rw
|
||||||
207 rw auto
|
207 rw auto
|
||||||
208 rw auto quick
|
208 rw quick
|
||||||
209 rw auto quick
|
209 rw quick
|
||||||
210 rw auto
|
210 rw auto
|
||||||
211 rw auto quick
|
211 rw auto quick
|
||||||
212 rw auto quick
|
212 rw auto quick
|
||||||
213 rw auto quick
|
213 rw auto quick
|
||||||
214 rw auto
|
214 rw auto
|
||||||
215 rw auto quick
|
215 rw auto quick
|
||||||
216 rw auto quick
|
216 rw quick
|
||||||
217 rw auto quick
|
217 rw auto quick
|
||||||
218 rw auto quick
|
218 rw quick
|
||||||
219 rw auto
|
219 rw
|
||||||
220 rw auto
|
220 rw auto
|
||||||
221 rw auto quick
|
221 rw auto quick
|
||||||
222 rw auto quick
|
222 rw quick
|
||||||
223 rw auto quick
|
223 rw quick
|
||||||
224 rw auto quick
|
224 rw quick
|
||||||
225 rw auto quick
|
225 rw auto quick
|
||||||
226 auto quick
|
226 auto quick
|
||||||
227 auto quick
|
227 quick
|
||||||
228 rw auto quick
|
228 rw quick
|
||||||
229 auto quick
|
229 auto quick
|
||||||
231 auto quick
|
231 auto quick
|
||||||
232 auto quick
|
232 quick
|
||||||
233 auto quick
|
233 auto quick
|
||||||
234 auto quick migration
|
234 quick migration
|
||||||
235 auto quick
|
235 quick
|
||||||
236 auto quick
|
236 quick
|
||||||
237 rw auto quick
|
237 rw auto quick
|
||||||
238 auto quick
|
238 quick
|
||||||
239 rw auto quick
|
239 rw auto quick
|
||||||
240 auto quick
|
240 quick
|
||||||
241 rw auto quick
|
241 rw auto quick
|
||||||
242 rw auto quick
|
242 rw quick
|
||||||
243 rw auto quick
|
243 rw auto quick
|
||||||
244 rw auto quick
|
244 rw auto quick
|
||||||
245 rw auto
|
245 rw
|
||||||
246 rw auto quick
|
246 rw quick
|
||||||
247 rw auto quick
|
247 rw quick
|
||||||
248 rw auto quick
|
248 rw quick
|
||||||
249 rw auto quick
|
249 rw auto quick
|
||||||
252 rw auto backing quick
|
252 rw auto backing quick
|
||||||
253 rw auto quick
|
253 rw auto quick
|
||||||
|
|
|
@ -96,6 +96,7 @@ else
|
||||||
# build options for bare programs are usually pretty different. They
|
# build options for bare programs are usually pretty different. They
|
||||||
# are expected to provide their own build recipes.
|
# are expected to provide their own build recipes.
|
||||||
-include $(SRC_PATH)/tests/tcg/minilib/Makefile.target
|
-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
|
-include $(SRC_PATH)/tests/tcg/$(TARGET_BASE_ARCH)/Makefile.softmmu-target
|
||||||
ifneq ($(TARGET_BASE_ARCH),$(TARGET_NAME))
|
ifneq ($(TARGET_BASE_ARCH),$(TARGET_NAME))
|
||||||
-include $(SRC_PATH)/tests/tcg/$(TARGET_NAME)/Makefile.softmmu-target
|
-include $(SRC_PATH)/tests/tcg/$(TARGET_NAME)/Makefile.softmmu-target
|
||||||
|
|
|
@ -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
|
|
@ -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:
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
|
@ -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
|
|
@ -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 = .;
|
||||||
|
}
|
|
@ -27,7 +27,7 @@ CFLAGS+=-m32
|
||||||
LINK_SCRIPT=$(I386_SYSTEM_SRC)/kernel.ld
|
LINK_SCRIPT=$(I386_SYSTEM_SRC)/kernel.ld
|
||||||
LDFLAGS=-Wl,-T$(LINK_SCRIPT) -Wl,-melf_i386
|
LDFLAGS=-Wl,-T$(LINK_SCRIPT) -Wl,-melf_i386
|
||||||
# FIXME: move to common once x86_64 is bootstrapped
|
# FIXME: move to common once x86_64 is bootstrapped
|
||||||
TESTS+=$(X86_TESTS)
|
TESTS+=$(X86_TESTS) $(MULTIARCH_TESTS)
|
||||||
endif
|
endif
|
||||||
CFLAGS+=-nostdlib -ggdb -O0 $(MINILIB_INC)
|
CFLAGS+=-nostdlib -ggdb -O0 $(MINILIB_INC)
|
||||||
LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc
|
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)
|
%: %.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS)
|
||||||
$(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)
|
$(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)
|
||||||
|
|
||||||
|
memory: CFLAGS+=-DCHECK_UNALIGNED=1
|
||||||
|
|
||||||
# Running
|
# Running
|
||||||
QEMU_OPTS+=-device isa-debugcon,chardev=output -device isa-debug-exit,iobase=0xf4,iosize=0x4 -kernel
|
QEMU_OPTS+=-device isa-debugcon,chardev=output -device isa-debug-exit,iobase=0xf4,iosize=0x4 -kernel
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -119,6 +119,9 @@ void ml_printf(const char *fmt, ...)
|
||||||
str = va_arg(ap, char*);
|
str = va_arg(ap, char*);
|
||||||
print_str(str);
|
print_str(str);
|
||||||
break;
|
break;
|
||||||
|
case 'c':
|
||||||
|
__sys_outc(va_arg(ap, int));
|
||||||
|
break;
|
||||||
case '%':
|
case '%':
|
||||||
__sys_outc(*fmt);
|
__sys_outc(*fmt);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -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))
|
|
@ -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
128
vl.c
|
@ -116,7 +116,7 @@ int main(int argc, char **argv)
|
||||||
#include "qapi/opts-visitor.h"
|
#include "qapi/opts-visitor.h"
|
||||||
#include "qapi/clone-visitor.h"
|
#include "qapi/clone-visitor.h"
|
||||||
#include "qom/object_interfaces.h"
|
#include "qom/object_interfaces.h"
|
||||||
#include "exec/semihost.h"
|
#include "hw/semihosting/semihost.h"
|
||||||
#include "crypto/init.h"
|
#include "crypto/init.h"
|
||||||
#include "sysemu/replay.h"
|
#include "sysemu/replay.h"
|
||||||
#include "qapi/qapi-events-run-state.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 = {
|
static QemuOptsList qemu_fw_cfg_opts = {
|
||||||
.name = "fw_cfg",
|
.name = "fw_cfg",
|
||||||
.implied_opt_name = "name",
|
.implied_opt_name = "name",
|
||||||
|
@ -1351,80 +1332,6 @@ static void configure_msg(QemuOpts *opts)
|
||||||
enable_timestamp_msg = qemu_opt_get_bool(opts, "timestamp", true);
|
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. */
|
/* Now we still need this for compatibility with XEN. */
|
||||||
bool has_igd_gfx_passthru;
|
bool has_igd_gfx_passthru;
|
||||||
|
@ -3743,37 +3650,10 @@ int main(int argc, char **argv, char **envp)
|
||||||
nb_option_roms++;
|
nb_option_roms++;
|
||||||
break;
|
break;
|
||||||
case QEMU_OPTION_semihosting:
|
case QEMU_OPTION_semihosting:
|
||||||
semihosting.enabled = true;
|
qemu_semihosting_enable();
|
||||||
semihosting.target = SEMIHOSTING_TARGET_AUTO;
|
|
||||||
break;
|
break;
|
||||||
case QEMU_OPTION_semihosting_config:
|
case QEMU_OPTION_semihosting_config:
|
||||||
semihosting.enabled = true;
|
if (qemu_semihosting_config_options(optarg) != 0) {
|
||||||
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);
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -4290,6 +4170,8 @@ int main(int argc, char **argv, char **envp)
|
||||||
|
|
||||||
qemu_opts_foreach(qemu_find_opts("chardev"),
|
qemu_opts_foreach(qemu_find_opts("chardev"),
|
||||||
chardev_init_func, NULL, &error_fatal);
|
chardev_init_func, NULL, &error_fatal);
|
||||||
|
/* now chardevs have been created we may have semihosting to connect */
|
||||||
|
qemu_semihosting_connect_chardevs();
|
||||||
|
|
||||||
#ifdef CONFIG_VIRTFS
|
#ifdef CONFIG_VIRTFS
|
||||||
qemu_opts_foreach(qemu_find_opts("fsdev"),
|
qemu_opts_foreach(qemu_find_opts("fsdev"),
|
||||||
|
|
Loading…
Reference in New Issue