mirror of
https://github.com/xemu-project/xemu.git
synced 2025-02-17 10:38:52 +00:00
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_size = 4
|
||||
|
||||
[*.{s,S}]
|
||||
indent_style = tab
|
||||
indent_size = 8
|
||||
file_type_emacs = asm
|
||||
|
||||
[*.{vert,frag}]
|
||||
file_type_emacs = glsl
|
||||
|
||||
|
@ -284,5 +284,5 @@ matrix:
|
||||
|
||||
# Run check-tcg against softmmu targets
|
||||
- env:
|
||||
- CONFIG="--target-list=xtensa-softmmu,arm-softmmu"
|
||||
- CONFIG="--target-list=xtensa-softmmu,arm-softmmu,aarch64-softmmu,alpha-softmmu"
|
||||
- TEST_CMD="make -j3 check-tcg V=1"
|
||||
|
@ -470,6 +470,7 @@ M: Richard Henderson <rth@twiddle.net>
|
||||
S: Maintained
|
||||
F: hw/alpha/
|
||||
F: hw/isa/smc37c669-superio.c
|
||||
F: tests/tcg/alpha/system/
|
||||
|
||||
ARM Machines
|
||||
------------
|
||||
@ -2563,6 +2564,13 @@ F: docs/pvrdma.txt
|
||||
F: contrib/rdmacm-mux/*
|
||||
F: qapi/rdma.json
|
||||
|
||||
Semihosting
|
||||
M: Alex Bennée <alex.bennee@linaro.org>
|
||||
L: qemu-devel@nongnu.org
|
||||
S: Maintained
|
||||
F: hw/semihosting/
|
||||
F: include/hw/semihosting/
|
||||
|
||||
Build and test automation
|
||||
-------------------------
|
||||
Build and test automation
|
||||
|
4
Makefile
4
Makefile
@ -1009,7 +1009,9 @@ $(filter %.1 %.7 %.8,$(DOCS)): scripts/texi2pod.pl
|
||||
%/coverage-report.html:
|
||||
@mkdir -p $*
|
||||
$(call quiet-command,\
|
||||
gcovr -r $(SRC_PATH) --object-directory $(BUILD_PATH) \
|
||||
gcovr -r $(SRC_PATH) \
|
||||
$(foreach t, $(TARGET_DIRS), --object-directory $(BUILD_DIR)/$(t)) \
|
||||
--object-directory $(BUILD_DIR) \
|
||||
-p --html --html-details -o $@, \
|
||||
"GEN", "coverage-report.html")
|
||||
|
||||
|
@ -238,3 +238,19 @@ endif
|
||||
|
||||
generated-files-y += config-target.h
|
||||
Makefile: $(generated-files-y)
|
||||
|
||||
# Reports/Analysis
|
||||
#
|
||||
# The target specific coverage report only cares about target specific
|
||||
# blobs and not the shared code.
|
||||
#
|
||||
|
||||
%/coverage-report.html:
|
||||
@mkdir -p $*
|
||||
$(call quiet-command,\
|
||||
gcovr -r $(SRC_PATH) --object-directory $(CURDIR) \
|
||||
-p --html --html-details -o $@, \
|
||||
"GEN", "coverage-report.html")
|
||||
|
||||
.PHONY: coverage-report
|
||||
coverage-report: $(CURDIR)/reports/coverage/coverage-report.html
|
||||
|
@ -39,3 +39,4 @@ CONFIG_MICROBIT=y
|
||||
CONFIG_FSL_IMX25=y
|
||||
CONFIG_FSL_IMX7=y
|
||||
CONFIG_FSL_IMX6UL=y
|
||||
CONFIG_SEMIHOSTING=y
|
||||
|
@ -4,6 +4,8 @@
|
||||
#
|
||||
#CONFIG_MILKYMIST_TMU2=n # disabling it actually causes compile-time failures
|
||||
|
||||
CONFIG_SEMIHOSTING=y
|
||||
|
||||
# Boards:
|
||||
#
|
||||
CONFIG_LM32=y
|
||||
|
@ -1,5 +1,7 @@
|
||||
# Default configuration for m68k-softmmu
|
||||
|
||||
CONFIG_SEMIHOSTING=y
|
||||
|
||||
# Boards:
|
||||
#
|
||||
CONFIG_AN5206=y
|
||||
|
@ -35,6 +35,7 @@ CONFIG_MIPS_CPS=y
|
||||
CONFIG_MIPS_ITU=y
|
||||
CONFIG_R4K=y
|
||||
CONFIG_MALTA=y
|
||||
CONFIG_SEMIHOSTING=y
|
||||
CONFIG_PCNET_PCI=y
|
||||
CONFIG_MIPSSIM=y
|
||||
CONFIG_ACPI_SMBUS=y
|
||||
|
@ -1,5 +1,7 @@
|
||||
# Default configuration for nios2-softmmu
|
||||
|
||||
CONFIG_SEMIHOSTING=y
|
||||
|
||||
# Boards:
|
||||
#
|
||||
CONFIG_NIOS2_10M50=y
|
||||
|
@ -1,5 +1,7 @@
|
||||
# Default configuration for Xtensa
|
||||
|
||||
CONFIG_SEMIHOSTING=y
|
||||
|
||||
# Boards:
|
||||
#
|
||||
CONFIG_XTENSA_SIM=y
|
||||
|
@ -37,7 +37,7 @@
|
||||
#include "qemu/sockets.h"
|
||||
#include "sysemu/hw_accel.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "exec/semihost.h"
|
||||
#include "hw/semihosting/semihost.h"
|
||||
#include "exec/exec-all.h"
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
|
@ -29,6 +29,7 @@ source pci/Kconfig
|
||||
source rdma/Kconfig
|
||||
source scsi/Kconfig
|
||||
source sd/Kconfig
|
||||
source semihosting/Kconfig
|
||||
source smbios/Kconfig
|
||||
source ssi/Kconfig
|
||||
source timer/Kconfig
|
||||
|
@ -36,6 +36,7 @@ devices-dirs-$(CONFIG_SOFTMMU) += watchdog/
|
||||
devices-dirs-$(CONFIG_SOFTMMU) += xen/
|
||||
devices-dirs-$(CONFIG_MEM_DEVICE) += mem/
|
||||
devices-dirs-$(CONFIG_SOFTMMU) += smbios/
|
||||
devices-dirs-y += semihosting/
|
||||
devices-dirs-y += core/
|
||||
common-obj-y += $(devices-dirs-y)
|
||||
obj-y += $(devices-dirs-y)
|
||||
|
@ -55,7 +55,7 @@
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/empty_slot.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "exec/semihost.h"
|
||||
#include "hw/semihosting/semihost.h"
|
||||
#include "hw/mips/cps.h"
|
||||
|
||||
#define ENVP_ADDR 0x80002000l
|
||||
|
3
hw/semihosting/Kconfig
Normal file
3
hw/semihosting/Kconfig
Normal file
@ -0,0 +1,3 @@
|
||||
|
||||
config SEMIHOSTING
|
||||
bool
|
2
hw/semihosting/Makefile.objs
Normal file
2
hw/semihosting/Makefile.objs
Normal file
@ -0,0 +1,2 @@
|
||||
obj-$(CONFIG_SEMIHOSTING) += config.o
|
||||
obj-$(CONFIG_SEMIHOSTING) += console.o
|
186
hw/semihosting/config.c
Normal file
186
hw/semihosting/config.c
Normal file
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Semihosting configuration
|
||||
*
|
||||
* Copyright (c) 2015 Imagination Technologies
|
||||
* Copyright (c) 2019 Linaro Ltd
|
||||
*
|
||||
* This controls the configuration of semihosting for all guest
|
||||
* targets that support it. Architecture specific handling is handled
|
||||
* in target/HW/HW-semi.c
|
||||
*
|
||||
* Semihosting is sightly strange in that it is also supported by some
|
||||
* linux-user targets. However in that use case no configuration of
|
||||
* the outputs and command lines is supported.
|
||||
*
|
||||
* The config module is common to all softmmu targets however as vl.c
|
||||
* needs to link against the helpers.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qemu/config-file.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/semihosting/semihost.h"
|
||||
#include "chardev/char.h"
|
||||
|
||||
QemuOptsList qemu_semihosting_config_opts = {
|
||||
.name = "semihosting-config",
|
||||
.implied_opt_name = "enable",
|
||||
.head = QTAILQ_HEAD_INITIALIZER(qemu_semihosting_config_opts.head),
|
||||
.desc = {
|
||||
{
|
||||
.name = "enable",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
}, {
|
||||
.name = "target",
|
||||
.type = QEMU_OPT_STRING,
|
||||
}, {
|
||||
.name = "chardev",
|
||||
.type = QEMU_OPT_STRING,
|
||||
}, {
|
||||
.name = "arg",
|
||||
.type = QEMU_OPT_STRING,
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
|
||||
typedef struct SemihostingConfig {
|
||||
bool enabled;
|
||||
SemihostingTarget target;
|
||||
Chardev *chardev;
|
||||
const char **argv;
|
||||
int argc;
|
||||
const char *cmdline; /* concatenated argv */
|
||||
} SemihostingConfig;
|
||||
|
||||
static SemihostingConfig semihosting;
|
||||
static const char *semihost_chardev;
|
||||
|
||||
bool semihosting_enabled(void)
|
||||
{
|
||||
return semihosting.enabled;
|
||||
}
|
||||
|
||||
SemihostingTarget semihosting_get_target(void)
|
||||
{
|
||||
return semihosting.target;
|
||||
}
|
||||
|
||||
const char *semihosting_get_arg(int i)
|
||||
{
|
||||
if (i >= semihosting.argc) {
|
||||
return NULL;
|
||||
}
|
||||
return semihosting.argv[i];
|
||||
}
|
||||
|
||||
int semihosting_get_argc(void)
|
||||
{
|
||||
return semihosting.argc;
|
||||
}
|
||||
|
||||
const char *semihosting_get_cmdline(void)
|
||||
{
|
||||
if (semihosting.cmdline == NULL && semihosting.argc > 0) {
|
||||
semihosting.cmdline = g_strjoinv(" ", (gchar **)semihosting.argv);
|
||||
}
|
||||
return semihosting.cmdline;
|
||||
}
|
||||
|
||||
static int add_semihosting_arg(void *opaque,
|
||||
const char *name, const char *val,
|
||||
Error **errp)
|
||||
{
|
||||
SemihostingConfig *s = opaque;
|
||||
if (strcmp(name, "arg") == 0) {
|
||||
s->argc++;
|
||||
/* one extra element as g_strjoinv() expects NULL-terminated array */
|
||||
s->argv = g_realloc(s->argv, (s->argc + 1) * sizeof(void *));
|
||||
s->argv[s->argc - 1] = val;
|
||||
s->argv[s->argc] = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Use strings passed via -kernel/-append to initialize semihosting.argv[] */
|
||||
void semihosting_arg_fallback(const char *file, const char *cmd)
|
||||
{
|
||||
char *cmd_token;
|
||||
|
||||
/* argv[0] */
|
||||
add_semihosting_arg(&semihosting, "arg", file, NULL);
|
||||
|
||||
/* split -append and initialize argv[1..n] */
|
||||
cmd_token = strtok(g_strdup(cmd), " ");
|
||||
while (cmd_token) {
|
||||
add_semihosting_arg(&semihosting, "arg", cmd_token, NULL);
|
||||
cmd_token = strtok(NULL, " ");
|
||||
}
|
||||
}
|
||||
|
||||
Chardev *semihosting_get_chardev(void)
|
||||
{
|
||||
return semihosting.chardev;
|
||||
}
|
||||
|
||||
void qemu_semihosting_enable(void)
|
||||
{
|
||||
semihosting.enabled = true;
|
||||
semihosting.target = SEMIHOSTING_TARGET_AUTO;
|
||||
}
|
||||
|
||||
int qemu_semihosting_config_options(const char *optarg)
|
||||
{
|
||||
QemuOptsList *opt_list = qemu_find_opts("semihosting-config");
|
||||
QemuOpts *opts = qemu_opts_parse_noisily(opt_list, optarg, false);
|
||||
|
||||
semihosting.enabled = true;
|
||||
|
||||
if (opts != NULL) {
|
||||
semihosting.enabled = qemu_opt_get_bool(opts, "enable",
|
||||
true);
|
||||
const char *target = qemu_opt_get(opts, "target");
|
||||
/* setup of chardev is deferred until they are initialised */
|
||||
semihost_chardev = qemu_opt_get(opts, "chardev");
|
||||
if (target != NULL) {
|
||||
if (strcmp("native", target) == 0) {
|
||||
semihosting.target = SEMIHOSTING_TARGET_NATIVE;
|
||||
} else if (strcmp("gdb", target) == 0) {
|
||||
semihosting.target = SEMIHOSTING_TARGET_GDB;
|
||||
} else if (strcmp("auto", target) == 0) {
|
||||
semihosting.target = SEMIHOSTING_TARGET_AUTO;
|
||||
} else {
|
||||
error_report("unsupported semihosting-config %s",
|
||||
optarg);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
semihosting.target = SEMIHOSTING_TARGET_AUTO;
|
||||
}
|
||||
/* Set semihosting argument count and vector */
|
||||
qemu_opt_foreach(opts, add_semihosting_arg,
|
||||
&semihosting, NULL);
|
||||
} else {
|
||||
error_report("unsupported semihosting-config %s", optarg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void qemu_semihosting_connect_chardevs(void)
|
||||
{
|
||||
/* We had to defer this until chardevs were created */
|
||||
if (semihost_chardev) {
|
||||
Chardev *chr = qemu_chr_find(semihost_chardev);
|
||||
if (chr == NULL) {
|
||||
error_report("semihosting chardev '%s' not found",
|
||||
semihost_chardev);
|
||||
exit(1);
|
||||
}
|
||||
semihosting.chardev = chr;
|
||||
}
|
||||
}
|
84
hw/semihosting/console.c
Normal file
84
hw/semihosting/console.c
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Semihosting Console Support
|
||||
*
|
||||
* Copyright (c) 2015 Imagination Technologies
|
||||
* Copyright (c) 2019 Linaro Ltd
|
||||
*
|
||||
* This provides support for outputting to a semihosting console.
|
||||
*
|
||||
* While most semihosting implementations support reading and writing
|
||||
* to arbitrary file descriptors we treat the console as something
|
||||
* specifically for debugging interaction. This means messages can be
|
||||
* re-directed to gdb (if currently being used to debug) or even
|
||||
* re-directed elsewhere.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "hw/semihosting/semihost.h"
|
||||
#include "hw/semihosting/console.h"
|
||||
#include "exec/gdbstub.h"
|
||||
#include "qemu/log.h"
|
||||
#include "chardev/char.h"
|
||||
|
||||
int qemu_semihosting_log_out(const char *s, int len)
|
||||
{
|
||||
Chardev *chardev = semihosting_get_chardev();
|
||||
if (chardev) {
|
||||
return qemu_chr_write_all(chardev, (uint8_t *) s, len);
|
||||
} else {
|
||||
return write(STDERR_FILENO, s, len);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* A re-implementation of lock_user_string that we can use locally
|
||||
* instead of relying on softmmu-semi. Hopefully we can deprecate that
|
||||
* in time. We either copy len bytes if specified or until we find a NULL.
|
||||
*/
|
||||
static GString *copy_user_string(CPUArchState *env, target_ulong addr, int len)
|
||||
{
|
||||
CPUState *cpu = ENV_GET_CPU(env);
|
||||
GString *s = g_string_sized_new(len ? len : 128);
|
||||
uint8_t c;
|
||||
bool done;
|
||||
|
||||
do {
|
||||
if (cpu_memory_rw_debug(cpu, addr++, &c, 1, 0) == 0) {
|
||||
s = g_string_append_c(s, c);
|
||||
done = len ? s->len == len : c == 0;
|
||||
} else {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: passed inaccessible address " TARGET_FMT_lx,
|
||||
__func__, addr);
|
||||
done = true;
|
||||
}
|
||||
} while (!done);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static void semihosting_cb(CPUState *cs, target_ulong ret, target_ulong err)
|
||||
{
|
||||
if (ret == (target_ulong) -1) {
|
||||
qemu_log("%s: gdb console output failed ("TARGET_FMT_ld")",
|
||||
__func__, err);
|
||||
}
|
||||
}
|
||||
|
||||
int qemu_semihosting_console_out(CPUArchState *env, target_ulong addr, int len)
|
||||
{
|
||||
GString *s = copy_user_string(env, addr, len);
|
||||
int out = s->len;
|
||||
|
||||
if (use_gdb_syscalls()) {
|
||||
gdb_do_syscall(semihosting_cb, "write,2,%x,%x", addr, s->len);
|
||||
} else {
|
||||
out = qemu_semihosting_log_out(s->str, s->len);
|
||||
}
|
||||
|
||||
g_string_free(s, true);
|
||||
return out;
|
||||
}
|
38
include/hw/semihosting/console.h
Normal file
38
include/hw/semihosting/console.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Semihosting Console
|
||||
*
|
||||
* Copyright (c) 2019 Linaro Ltd
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef _SEMIHOST_CONSOLE_H_
|
||||
#define _SEMIHOST_CONSOLE_H_
|
||||
|
||||
/**
|
||||
* qemu_semihosting_console_out:
|
||||
* @env: CPUArchState
|
||||
* @s: host address of guest string
|
||||
* @len: length of string or 0 (string is null terminated)
|
||||
*
|
||||
* Send a guest string to the debug console. This may be the remote
|
||||
* gdb session if a softmmu guest is currently being debugged.
|
||||
*
|
||||
* Returns: number of bytes written.
|
||||
*/
|
||||
int qemu_semihosting_console_out(CPUArchState *env, target_ulong s, int len);
|
||||
|
||||
/**
|
||||
* qemu_semihosting_log_out:
|
||||
* @s: pointer to string
|
||||
* @len: length of string
|
||||
*
|
||||
* Send a string to the debug output. Unlike console_out these strings
|
||||
* can't be sent to a remote gdb instance as they don't exist in guest
|
||||
* memory.
|
||||
*
|
||||
* Returns: number of bytes written
|
||||
*/
|
||||
int qemu_semihosting_log_out(const char *s, int len);
|
||||
|
||||
#endif /* _SEMIHOST_CONSOLE_H_ */
|
@ -51,12 +51,23 @@ static inline const char *semihosting_get_cmdline(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
|
||||
static inline Chardev *semihosting_get_chardev(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#else /* !CONFIG_USER_ONLY */
|
||||
bool semihosting_enabled(void);
|
||||
SemihostingTarget semihosting_get_target(void);
|
||||
const char *semihosting_get_arg(int i);
|
||||
int semihosting_get_argc(void);
|
||||
const char *semihosting_get_cmdline(void);
|
||||
#endif
|
||||
void semihosting_arg_fallback(const char *file, const char *cmd);
|
||||
Chardev *semihosting_get_chardev(void);
|
||||
/* for vl.c hooks */
|
||||
void qemu_semihosting_enable(void);
|
||||
int qemu_semihosting_config_options(const char *opt);
|
||||
void qemu_semihosting_connect_chardevs(void);
|
||||
#endif /* CONFIG_USER_ONLY */
|
||||
|
||||
#endif
|
||||
#endif /* SEMIHOST_H */
|
@ -193,5 +193,6 @@ extern QemuOptsList qemu_nic_opts;
|
||||
extern QemuOptsList qemu_net_opts;
|
||||
extern QemuOptsList qemu_global_opts;
|
||||
extern QemuOptsList qemu_mon_opts;
|
||||
extern QemuOptsList qemu_semihosting_config_opts;
|
||||
|
||||
#endif
|
||||
|
@ -6,4 +6,6 @@ obj-y = main.o syscall.o strace.o mmap.o signal.o \
|
||||
obj-$(TARGET_HAS_BFLT) += flatload.o
|
||||
obj-$(TARGET_I386) += vm86.o
|
||||
obj-$(TARGET_ARM) += arm/nwfpe/
|
||||
obj-$(TARGET_ARM) += arm/semihost.o
|
||||
obj-$(TARGET_AARCH64) += arm/semihost.o
|
||||
obj-$(TARGET_M68K) += m68k-sim.o
|
||||
|
24
linux-user/arm/semihost.c
Normal file
24
linux-user/arm/semihost.c
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* ARM Semihosting Console Support
|
||||
*
|
||||
* Copyright (c) 2019 Linaro Ltd
|
||||
*
|
||||
* Currently ARM is unique in having support for semihosting support
|
||||
* in linux-user. So for now we implement the common console API but
|
||||
* just for arm linux-user.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "hw/semihosting/console.h"
|
||||
#include "qemu.h"
|
||||
|
||||
int qemu_semihosting_console_out(CPUArchState *env, target_ulong addr, int len)
|
||||
{
|
||||
void *s = lock_user_string(addr);
|
||||
len = write(STDERR_FILENO, s, len ? len : strlen(s));
|
||||
unlock_user(s, addr, 0);
|
||||
return len;
|
||||
}
|
@ -4025,12 +4025,12 @@ STEXI
|
||||
Enable semihosting mode (ARM, M68K, Xtensa, MIPS, Nios II only).
|
||||
ETEXI
|
||||
DEF("semihosting-config", HAS_ARG, QEMU_OPTION_semihosting_config,
|
||||
"-semihosting-config [enable=on|off][,target=native|gdb|auto][,arg=str[,...]]\n" \
|
||||
"-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,arg=str[,...]]\n" \
|
||||
" semihosting configuration\n",
|
||||
QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32 |
|
||||
QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2)
|
||||
STEXI
|
||||
@item -semihosting-config [enable=on|off][,target=native|gdb|auto][,arg=str[,...]]
|
||||
@item -semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,arg=str[,...]]
|
||||
@findex -semihosting-config
|
||||
Enable and configure semihosting (ARM, M68K, Xtensa, MIPS, Nios II only).
|
||||
@table @option
|
||||
@ -4038,6 +4038,8 @@ Enable and configure semihosting (ARM, M68K, Xtensa, MIPS, Nios II only).
|
||||
Defines where the semihosting calls will be addressed, to QEMU (@code{native})
|
||||
or to GDB (@code{gdb}). The default is @code{auto}, which means @code{gdb}
|
||||
during debug sessions and @code{native} otherwise.
|
||||
@item chardev=@var{str1}
|
||||
Send the output to a chardev backend output for native or auto output when not in gdb
|
||||
@item arg=@var{str1},arg=@var{str2},...
|
||||
Allows the user to pass input arguments, and can be used multiple times to build
|
||||
up a list. The old-style @code{-kernel}/@code{-append} method of passing a
|
||||
|
@ -40,3 +40,4 @@ stub-obj-y += pci-host-piix.o
|
||||
stub-obj-y += ram-block.o
|
||||
stub-obj-y += ramfb.o
|
||||
stub-obj-y += fw_cfg.o
|
||||
stub-obj-$(CONFIG_SOFTMMU) += semihost.o
|
||||
|
70
stubs/semihost.c
Normal file
70
stubs/semihost.c
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Semihosting Stubs for SoftMMU
|
||||
*
|
||||
* Copyright (c) 2019 Linaro Ltd
|
||||
*
|
||||
* Stubs for SoftMMU targets that don't actually do semihosting.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/semihosting/semihost.h"
|
||||
|
||||
/* Empty config */
|
||||
QemuOptsList qemu_semihosting_config_opts = {
|
||||
.name = "",
|
||||
.head = QTAILQ_HEAD_INITIALIZER(qemu_semihosting_config_opts.head),
|
||||
.desc = {
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
|
||||
/* Queries to config status default to off */
|
||||
bool semihosting_enabled(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
SemihostingTarget semihosting_get_target(void)
|
||||
{
|
||||
return SEMIHOSTING_TARGET_AUTO;
|
||||
}
|
||||
|
||||
/*
|
||||
* All the rest are empty subs. We could g_assert_not_reached() but
|
||||
* that adds extra weight to the final binary. Waste not want not.
|
||||
*/
|
||||
void qemu_semihosting_enable(void)
|
||||
{
|
||||
}
|
||||
|
||||
int qemu_semihosting_config_options(const char *optarg)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *semihosting_get_arg(int i)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int semihosting_get_argc(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *semihosting_get_cmdline(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void semihosting_arg_fallback(const char *file, const char *cmd)
|
||||
{
|
||||
}
|
||||
|
||||
void qemu_semihosting_connect_chardevs(void)
|
||||
{
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
* Arm "Angel" semihosting syscalls
|
||||
*
|
||||
* Copyright (c) 2005, 2007 CodeSourcery.
|
||||
* Copyright (c) 2019 Linaro
|
||||
* Written by Paul Brook.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@ -16,12 +17,18 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ARM Semihosting is documented in:
|
||||
* Semihosting for AArch32 and AArch64 Release 2.0
|
||||
* https://static.docs.arm.com/100863/0200/semihosting.pdf
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include "cpu.h"
|
||||
#include "exec/semihost.h"
|
||||
#include "hw/semihosting/semihost.h"
|
||||
#include "hw/semihosting/console.h"
|
||||
#include "qemu/log.h"
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
#include "qemu.h"
|
||||
|
||||
@ -239,6 +246,15 @@ static target_ulong arm_gdb_syscall(ARMCPU *cpu, gdb_syscall_complete_cb cb,
|
||||
put_user_u64(val, args + (n) * 8) : \
|
||||
put_user_u32(val, args + (n) * 4))
|
||||
|
||||
/*
|
||||
* Do a semihosting call.
|
||||
*
|
||||
* The specification always says that the "return register" either
|
||||
* returns a specific value or is corrupted, so we don't need to
|
||||
* report to our caller whether we are returning a value or trying to
|
||||
* leave the register unchanged. We use 0xdeadbeef as the return value
|
||||
* when there isn't a defined return value for the call.
|
||||
*/
|
||||
target_ulong do_arm_semihosting(CPUARMState *env)
|
||||
{
|
||||
ARMCPU *cpu = arm_env_get_cpu(env);
|
||||
@ -299,32 +315,10 @@ target_ulong do_arm_semihosting(CPUARMState *env)
|
||||
return set_swi_errno(ts, close(arg0));
|
||||
}
|
||||
case TARGET_SYS_WRITEC:
|
||||
{
|
||||
char c;
|
||||
|
||||
if (get_user_u8(c, args))
|
||||
/* FIXME - should this error code be -TARGET_EFAULT ? */
|
||||
return (uint32_t)-1;
|
||||
/* Write to debug console. stderr is near enough. */
|
||||
if (use_gdb_syscalls()) {
|
||||
return arm_gdb_syscall(cpu, arm_semi_cb, "write,2,%x,1", args);
|
||||
} else {
|
||||
return write(STDERR_FILENO, &c, 1);
|
||||
}
|
||||
}
|
||||
qemu_semihosting_console_out(env, args, 1);
|
||||
return 0xdeadbeef;
|
||||
case TARGET_SYS_WRITE0:
|
||||
if (!(s = lock_user_string(args)))
|
||||
/* FIXME - should this error code be -TARGET_EFAULT ? */
|
||||
return (uint32_t)-1;
|
||||
len = strlen(s);
|
||||
if (use_gdb_syscalls()) {
|
||||
return arm_gdb_syscall(cpu, arm_semi_cb, "write,2,%x,%x",
|
||||
args, len);
|
||||
} else {
|
||||
ret = write(STDERR_FILENO, s, len);
|
||||
}
|
||||
unlock_user(s, args, 0);
|
||||
return ret;
|
||||
return qemu_semihosting_console_out(env, args, 0);
|
||||
case TARGET_SYS_WRITE:
|
||||
GET_ARG(0);
|
||||
GET_ARG(1);
|
||||
@ -337,13 +331,15 @@ target_ulong do_arm_semihosting(CPUARMState *env)
|
||||
} else {
|
||||
s = lock_user(VERIFY_READ, arg1, len, 1);
|
||||
if (!s) {
|
||||
/* FIXME - should this error code be -TARGET_EFAULT ? */
|
||||
return (uint32_t)-1;
|
||||
/* Return bytes not written on error */
|
||||
return len;
|
||||
}
|
||||
ret = set_swi_errno(ts, write(arg0, s, len));
|
||||
unlock_user(s, arg1, 0);
|
||||
if (ret == (uint32_t)-1)
|
||||
return -1;
|
||||
if (ret == (uint32_t)-1) {
|
||||
ret = 0;
|
||||
}
|
||||
/* Return bytes not written */
|
||||
return len - ret;
|
||||
}
|
||||
case TARGET_SYS_READ:
|
||||
@ -358,19 +354,21 @@ target_ulong do_arm_semihosting(CPUARMState *env)
|
||||
} else {
|
||||
s = lock_user(VERIFY_WRITE, arg1, len, 0);
|
||||
if (!s) {
|
||||
/* FIXME - should this error code be -TARGET_EFAULT ? */
|
||||
return (uint32_t)-1;
|
||||
/* return bytes not read */
|
||||
return len;
|
||||
}
|
||||
do {
|
||||
ret = set_swi_errno(ts, read(arg0, s, len));
|
||||
} while (ret == -1 && errno == EINTR);
|
||||
unlock_user(s, arg1, len);
|
||||
if (ret == (uint32_t)-1)
|
||||
return -1;
|
||||
if (ret == (uint32_t)-1) {
|
||||
ret = 0;
|
||||
}
|
||||
/* Return bytes not read */
|
||||
return len - ret;
|
||||
}
|
||||
case TARGET_SYS_READC:
|
||||
/* XXX: Read from debug console. Not implemented. */
|
||||
qemu_log_mask(LOG_UNIMP, "%s: SYS_READC not implemented", __func__);
|
||||
return 0;
|
||||
case TARGET_SYS_ISTTY:
|
||||
GET_ARG(0);
|
||||
@ -404,7 +402,7 @@ target_ulong do_arm_semihosting(CPUARMState *env)
|
||||
return buf.st_size;
|
||||
}
|
||||
case TARGET_SYS_TMPNAM:
|
||||
/* XXX: Not implemented. */
|
||||
qemu_log_mask(LOG_UNIMP, "%s: SYS_TMPNAM not implemented", __func__);
|
||||
return -1;
|
||||
case TARGET_SYS_REMOVE:
|
||||
GET_ARG(0);
|
||||
@ -509,14 +507,16 @@ target_ulong do_arm_semihosting(CPUARMState *env)
|
||||
|
||||
output_size = ts->info->arg_end - ts->info->arg_start;
|
||||
if (!output_size) {
|
||||
/* We special-case the "empty command line" case (argc==0).
|
||||
Just provide the terminating 0. */
|
||||
/*
|
||||
* We special-case the "empty command line" case (argc==0).
|
||||
* Just provide the terminating 0.
|
||||
*/
|
||||
output_size = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (output_size > input_size) {
|
||||
/* Not enough space to store command-line arguments. */
|
||||
/* Not enough space to store command-line arguments. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -570,8 +570,10 @@ target_ulong do_arm_semihosting(CPUARMState *env)
|
||||
GET_ARG(0);
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
/* Some C libraries assume the heap immediately follows .bss, so
|
||||
allocate it using sbrk. */
|
||||
/*
|
||||
* Some C libraries assume the heap immediately follows .bss, so
|
||||
* allocate it using sbrk.
|
||||
*/
|
||||
if (!ts->heap_limit) {
|
||||
abi_ulong ret;
|
||||
|
||||
@ -619,7 +621,8 @@ target_ulong do_arm_semihosting(CPUARMState *env)
|
||||
}
|
||||
case TARGET_SYS_EXIT:
|
||||
if (is_a64(env)) {
|
||||
/* The A64 version of this call takes a parameter block,
|
||||
/*
|
||||
* The A64 version of this call takes a parameter block,
|
||||
* so the application-exit type can return a subcode which
|
||||
* is the exit status code from the application.
|
||||
*/
|
||||
@ -632,14 +635,17 @@ target_ulong do_arm_semihosting(CPUARMState *env)
|
||||
ret = 1;
|
||||
}
|
||||
} else {
|
||||
/* ARM specifies only Stopped_ApplicationExit as normal
|
||||
* exit, everything else is considered an error */
|
||||
/*
|
||||
* ARM specifies only Stopped_ApplicationExit as normal
|
||||
* exit, everything else is considered an error
|
||||
*/
|
||||
ret = (args == ADP_Stopped_ApplicationExit) ? 0 : 1;
|
||||
}
|
||||
gdb_exit(env, ret);
|
||||
exit(ret);
|
||||
case TARGET_SYS_SYNCCACHE:
|
||||
/* Clean the D-cache and invalidate the I-cache for the specified
|
||||
/*
|
||||
* Clean the D-cache and invalidate the I-cache for the specified
|
||||
* virtual address range. This is a nop for us since we don't
|
||||
* implement caches. This is only present on A64.
|
||||
*/
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "arm_ldst.h"
|
||||
#include <zlib.h> /* For crc32 */
|
||||
#include "exec/semihost.h"
|
||||
#include "hw/semihosting/semihost.h"
|
||||
#include "sysemu/cpus.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "fpu/softfloat.h"
|
||||
|
@ -29,7 +29,7 @@
|
||||
#include "qemu/host-utils.h"
|
||||
#include "qemu/qemu-print.h"
|
||||
|
||||
#include "exec/semihost.h"
|
||||
#include "hw/semihosting/semihost.h"
|
||||
#include "exec/gen-icount.h"
|
||||
|
||||
#include "exec/helper-proto.h"
|
||||
|
@ -30,7 +30,7 @@
|
||||
#include "qemu/bitops.h"
|
||||
#include "qemu/qemu-print.h"
|
||||
#include "arm_ldst.h"
|
||||
#include "exec/semihost.h"
|
||||
#include "hw/semihosting/semihost.h"
|
||||
|
||||
#include "exec/helper-proto.h"
|
||||
#include "exec/helper-gen.h"
|
||||
|
@ -22,7 +22,7 @@
|
||||
#include "exec/exec-all.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "exec/semihost.h"
|
||||
#include "hw/semihosting/semihost.h"
|
||||
#include "exec/log.h"
|
||||
|
||||
bool lm32_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
|
@ -21,7 +21,7 @@
|
||||
#include "exec/helper-proto.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "exec/semihost.h"
|
||||
#include "hw/semihosting/semihost.h"
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
obj-y += translate.o dsp_helper.o op_helper.o lmi_helper.o helper.o cpu.o
|
||||
obj-y += gdbstub.o msa_helper.o mips-semi.o
|
||||
obj-y += gdbstub.o msa_helper.o
|
||||
obj-$(CONFIG_SOFTMMU) += mips-semi.o
|
||||
obj-$(CONFIG_SOFTMMU) += machine.o cp0_timer.o
|
||||
obj-$(CONFIG_KVM) += kvm.o
|
||||
|
@ -2,7 +2,9 @@ DEF_HELPER_3(raise_exception_err, noreturn, env, i32, int)
|
||||
DEF_HELPER_2(raise_exception, noreturn, env, i32)
|
||||
DEF_HELPER_1(raise_exception_debug, noreturn, env)
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
DEF_HELPER_1(do_semihosting, void, env)
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_MIPS64
|
||||
DEF_HELPER_4(sdl, void, env, tl, tl, int)
|
||||
|
@ -22,7 +22,8 @@
|
||||
#include "qemu/log.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "exec/softmmu-semi.h"
|
||||
#include "exec/semihost.h"
|
||||
#include "hw/semihosting/semihost.h"
|
||||
#include "hw/semihosting/console.h"
|
||||
|
||||
typedef enum UHIOp {
|
||||
UHI_exit = 1,
|
||||
@ -329,13 +330,12 @@ void helper_do_semihosting(CPUMIPSState *env)
|
||||
p2 = strstr(p, "%d");
|
||||
if (p2) {
|
||||
int char_num = p2 - p;
|
||||
char *buf = g_malloc(char_num + 1);
|
||||
strncpy(buf, p, char_num);
|
||||
buf[char_num] = '\0';
|
||||
gpr[2] = printf("%s%d%s", buf, (int)gpr[5], p2 + 2);
|
||||
g_free(buf);
|
||||
GString *s = g_string_new_len(p, char_num);
|
||||
g_string_append_printf(s, "%d%s", (int)gpr[5], p2 + 2);
|
||||
gpr[2] = qemu_semihosting_log_out(s->str, s->len);
|
||||
g_string_free(s, true);
|
||||
} else {
|
||||
gpr[2] = printf("%s", p);
|
||||
gpr[2] = qemu_semihosting_log_out(p, strlen(p));
|
||||
}
|
||||
FREE_TARGET_STRING(p, gpr[4]);
|
||||
break;
|
||||
|
@ -32,7 +32,7 @@
|
||||
|
||||
#include "exec/helper-proto.h"
|
||||
#include "exec/helper-gen.h"
|
||||
#include "exec/semihost.h"
|
||||
#include "hw/semihosting/semihost.h"
|
||||
|
||||
#include "target/mips/trace.h"
|
||||
#include "trace-tcg.h"
|
||||
@ -13726,6 +13726,14 @@ static inline bool is_uhi(int sdbbp_code)
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
/* The above should dead-code away any calls to this..*/
|
||||
static inline void gen_helper_do_semihosting(void *env)
|
||||
{
|
||||
g_assert_not_reached();
|
||||
}
|
||||
#endif
|
||||
|
||||
static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx)
|
||||
{
|
||||
int rx, ry;
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "exec/log.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "exec/semihost.h"
|
||||
#include "hw/semihosting/semihost.h"
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
|
||||
|
@ -38,7 +38,7 @@
|
||||
#include "qemu/qemu-print.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "exec/semihost.h"
|
||||
#include "hw/semihosting/semihost.h"
|
||||
#include "exec/translator.h"
|
||||
|
||||
#include "exec/helper-proto.h"
|
||||
|
@ -29,7 +29,7 @@
|
||||
#include "cpu.h"
|
||||
#include "chardev/char-fe.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "exec/semihost.h"
|
||||
#include "hw/semihosting/semihost.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/log.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
|
@ -8,6 +8,7 @@ ENV PACKAGES \
|
||||
bzip2-devel \
|
||||
ccache \
|
||||
clang \
|
||||
cyrus-sasl-devel \
|
||||
device-mapper-multipath-devel \
|
||||
findutils \
|
||||
flex \
|
||||
@ -23,13 +24,17 @@ ENV PACKAGES \
|
||||
libaio-devel \
|
||||
libasan \
|
||||
libattr-devel \
|
||||
libblockdev-mpath-devel \
|
||||
libcap-devel \
|
||||
libcap-ng-devel \
|
||||
libcurl-devel \
|
||||
libfdt-devel \
|
||||
libiscsi-devel \
|
||||
libjpeg-devel \
|
||||
libpmem-devel \
|
||||
libpng-devel \
|
||||
librbd-devel \
|
||||
libseccomp-devel \
|
||||
libssh2-devel \
|
||||
libubsan \
|
||||
libusbx-devel \
|
||||
@ -74,10 +79,12 @@ ENV PACKAGES \
|
||||
pixman-devel \
|
||||
python3 \
|
||||
PyYAML \
|
||||
rdma-core-devel \
|
||||
SDL2-devel \
|
||||
snappy-devel \
|
||||
sparse \
|
||||
spice-server-devel \
|
||||
systemd-devel \
|
||||
systemtap-sdt-devel \
|
||||
tar \
|
||||
usbredir-devel \
|
||||
|
57
tests/docker/dockerfiles/ubuntu1804.docker
Normal file
57
tests/docker/dockerfiles/ubuntu1804.docker
Normal file
@ -0,0 +1,57 @@
|
||||
FROM ubuntu:18.04
|
||||
ENV PACKAGES flex bison \
|
||||
ccache \
|
||||
clang \
|
||||
gcc \
|
||||
gettext \
|
||||
git \
|
||||
glusterfs-common \
|
||||
libaio-dev \
|
||||
libattr1-dev \
|
||||
libbluetooth-dev \
|
||||
libbrlapi-dev \
|
||||
libbz2-dev \
|
||||
libcacard-dev \
|
||||
libcap-dev \
|
||||
libcap-ng-dev \
|
||||
libcurl4-gnutls-dev \
|
||||
libdrm-dev \
|
||||
libepoxy-dev \
|
||||
libfdt-dev \
|
||||
libgbm-dev \
|
||||
libgtk-3-dev \
|
||||
libibverbs-dev \
|
||||
libiscsi-dev \
|
||||
libjemalloc-dev \
|
||||
libjpeg-turbo8-dev \
|
||||
liblzo2-dev \
|
||||
libncurses5-dev \
|
||||
libncursesw5-dev \
|
||||
libnfs-dev \
|
||||
libnss3-dev \
|
||||
libnuma-dev \
|
||||
libpixman-1-dev \
|
||||
librados-dev \
|
||||
librbd-dev \
|
||||
librdmacm-dev \
|
||||
libsasl2-dev \
|
||||
libsdl2-dev \
|
||||
libseccomp-dev \
|
||||
libsnappy-dev \
|
||||
libspice-protocol-dev \
|
||||
libspice-server-dev \
|
||||
libssh2-1-dev \
|
||||
libusb-1.0-0-dev \
|
||||
libusbredirhost-dev \
|
||||
libvdeplug-dev \
|
||||
libvte-2.91-dev \
|
||||
libxen-dev \
|
||||
make \
|
||||
python-yaml \
|
||||
sparse \
|
||||
texinfo \
|
||||
xfslibs-dev
|
||||
RUN apt-get update && \
|
||||
apt-get -y install $PACKAGES
|
||||
RUN dpkg -l $PACKAGES | sort > /packages.txt
|
||||
ENV FEATURES clang pyyaml sdl2
|
@ -27,9 +27,7 @@ bad=""
|
||||
notrun=""
|
||||
casenotrun=""
|
||||
interrupt=true
|
||||
|
||||
# by default don't output timestamps
|
||||
timestamp=${TIMESTAMP:=false}
|
||||
makecheck=false
|
||||
|
||||
_init_error()
|
||||
{
|
||||
@ -88,6 +86,22 @@ _full_platform_details()
|
||||
echo "$os/$platform $host $kernel"
|
||||
}
|
||||
|
||||
_full_env_details()
|
||||
{
|
||||
cat <<EOF
|
||||
QEMU -- "$QEMU_PROG" $QEMU_OPTIONS
|
||||
QEMU_IMG -- "$QEMU_IMG_PROG" $QEMU_IMG_OPTIONS
|
||||
QEMU_IO -- "$QEMU_IO_PROG" $QEMU_IO_OPTIONS
|
||||
QEMU_NBD -- "$QEMU_NBD_PROG" $QEMU_NBD_OPTIONS
|
||||
IMGFMT -- $FULL_IMGFMT_DETAILS
|
||||
IMGPROTO -- $IMGPROTO
|
||||
PLATFORM -- $FULL_HOST_DETAILS
|
||||
TEST_DIR -- $TEST_DIR
|
||||
SOCKET_SCM_HELPER -- $SOCKET_SCM_HELPER
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
# $1 = prog to look for
|
||||
set_prog_path()
|
||||
{
|
||||
@ -254,8 +268,8 @@ other options
|
||||
-misalign misalign memory allocations
|
||||
-n show me, do not run tests
|
||||
-o options -o options to pass to qemu-img create/convert
|
||||
-T output timestamps
|
||||
-c mode cache mode
|
||||
-makecheck pretty print output for make check
|
||||
|
||||
testlist options
|
||||
-g group[,group...] include tests from these groups
|
||||
@ -403,7 +417,10 @@ testlist options
|
||||
command -v xxdiff >/dev/null 2>&1 && diff=xxdiff
|
||||
fi
|
||||
;;
|
||||
|
||||
-makecheck) # makecheck friendly output
|
||||
makecheck=true
|
||||
xpand=false
|
||||
;;
|
||||
-n) # show me, don't do it
|
||||
showme=true
|
||||
xpand=false
|
||||
@ -416,8 +433,7 @@ testlist options
|
||||
cachemode=true
|
||||
xpand=false
|
||||
;;
|
||||
-T) # turn on timestamp output
|
||||
timestamp=true
|
||||
-T) # deprecated timestamp option
|
||||
xpand=false
|
||||
;;
|
||||
|
||||
@ -633,12 +649,6 @@ _wallclock()
|
||||
date "+%H %M %S" | awk '{ print $1*3600 + $2*60 + $3 }'
|
||||
}
|
||||
|
||||
_timestamp()
|
||||
{
|
||||
now=$(date "+%T")
|
||||
printf %s " [$now]"
|
||||
}
|
||||
|
||||
_wrapup()
|
||||
{
|
||||
if $showme
|
||||
@ -704,23 +714,54 @@ END { if (NR > 0) {
|
||||
|
||||
trap "_wrapup; exit \$status" 0 1 2 3 15
|
||||
|
||||
# Report the test start and results. For makecheck we want to pretty
|
||||
# print the whole report at the end of the execution.
|
||||
# args: $seq, $starttime, $lasttime
|
||||
_report_test_start()
|
||||
{
|
||||
if ! $makecheck; then
|
||||
if [ -n "$3" ]; then
|
||||
local lasttime=" (last: $3s)"
|
||||
fi
|
||||
printf "%-8s %-10s [%s] %4s%-14s\r" "$1" "..." "$2" "..." "$lasttime"
|
||||
fi
|
||||
}
|
||||
# args:$seq $status $starttime $lasttime $thistime $details
|
||||
_report_test_result()
|
||||
{
|
||||
local status lasttime thistime
|
||||
if $makecheck; then
|
||||
if [ -n "$2" ] && [ "$2" != "pass" ]; then
|
||||
status=" [$2]"
|
||||
fi
|
||||
printf " TEST iotest-$IMGFMT: %s%s\n" "$1" "$status"
|
||||
return
|
||||
fi
|
||||
|
||||
if [ -n "$4" ]; then
|
||||
lasttime=" (last: $4s)"
|
||||
fi
|
||||
if [ -n "$5" ]; then
|
||||
thistime=" $5s"
|
||||
fi
|
||||
case "$2" in
|
||||
"pass") status=$(printf "\e[32m%-10s\e[0m" "$2") ;;
|
||||
"fail") status=$(printf "\e[1m\e[31m%-10s\e[0m" "$2") ;;
|
||||
"not run") status=$(printf "\e[33m%-10s\e[0m" "$2") ;;
|
||||
*) status=$(printf "%-10s" "$2") ;;
|
||||
esac
|
||||
|
||||
printf "%-8s %s [%s] [%s] %4s%-14s %s\n" "$1" "$status" "$3" "$(date '+%T')" "$thistime" "$lasttime" "$6"
|
||||
}
|
||||
|
||||
[ -f $TIMESTAMP_FILE ] || touch $TIMESTAMP_FILE
|
||||
|
||||
FULL_IMGFMT_DETAILS=$(_full_imgfmt_details)
|
||||
FULL_HOST_DETAILS=$(_full_platform_details)
|
||||
|
||||
cat <<EOF
|
||||
QEMU -- "$QEMU_PROG" $QEMU_OPTIONS
|
||||
QEMU_IMG -- "$QEMU_IMG_PROG" $QEMU_IMG_OPTIONS
|
||||
QEMU_IO -- "$QEMU_IO_PROG" $QEMU_IO_OPTIONS
|
||||
QEMU_NBD -- "$QEMU_NBD_PROG" $QEMU_NBD_OPTIONS
|
||||
IMGFMT -- $FULL_IMGFMT_DETAILS
|
||||
IMGPROTO -- $IMGPROTO
|
||||
PLATFORM -- $FULL_HOST_DETAILS
|
||||
TEST_DIR -- $TEST_DIR
|
||||
SOCKET_SCM_HELPER -- $SOCKET_SCM_HELPER
|
||||
|
||||
EOF
|
||||
if ! $makecheck; then
|
||||
_full_env_details
|
||||
fi
|
||||
|
||||
seq="check"
|
||||
|
||||
@ -728,42 +769,43 @@ seq="check"
|
||||
|
||||
for seq in $list
|
||||
do
|
||||
err=false
|
||||
printf %s "$seq"
|
||||
err=false # error flag
|
||||
printdiff=false # show diff to reference output?
|
||||
status="" # test result summary
|
||||
results="" # test result details
|
||||
|
||||
if [ -n "$TESTS_REMAINING_LOG" ] ; then
|
||||
sed -e "s/$seq//" -e 's/ / /' -e 's/^ *//' $TESTS_REMAINING_LOG > $TESTS_REMAINING_LOG.tmp
|
||||
mv $TESTS_REMAINING_LOG.tmp $TESTS_REMAINING_LOG
|
||||
sync
|
||||
fi
|
||||
|
||||
lasttime=$(sed -n -e "/^$seq /s/.* //p" <$TIMESTAMP_FILE)
|
||||
starttime=$(date "+%T")
|
||||
_report_test_start $seq $starttime $lasttime
|
||||
|
||||
if $showme
|
||||
then
|
||||
echo
|
||||
continue
|
||||
status="not run"
|
||||
elif [ -f expunged ] && $expunge && egrep "^$seq([ ]|\$)" expunged >/dev/null
|
||||
then
|
||||
echo " - expunged"
|
||||
status="not run"
|
||||
results="expunged"
|
||||
rm -f $seq.out.bad
|
||||
echo "/^$seq\$/d" >>$tmp.expunged
|
||||
elif [ ! -f "$source_iotests/$seq" ]
|
||||
then
|
||||
echo " - no such test?"
|
||||
status="not run"
|
||||
results="no such test?"
|
||||
echo "/^$seq\$/d" >>$tmp.expunged
|
||||
else
|
||||
# really going to try and run this one
|
||||
#
|
||||
rm -f $seq.out.bad
|
||||
lasttime=$(sed -n -e "/^$seq /s/.* //p" <$TIMESTAMP_FILE)
|
||||
if [ "X$lasttime" != X ]; then
|
||||
printf %s " ${lasttime}s ..."
|
||||
else
|
||||
printf " " # prettier output with timestamps.
|
||||
fi
|
||||
rm -f core $seq.notrun
|
||||
rm -f $seq.casenotrun
|
||||
|
||||
start=$(_wallclock)
|
||||
$timestamp && printf %s " [$(date "+%T")]"
|
||||
|
||||
if [ "$(head -n 1 "$source_iotests/$seq")" == "#!/usr/bin/env python" ]; then
|
||||
run_command="$PYTHON $seq"
|
||||
@ -781,26 +823,26 @@ do
|
||||
$run_command >$tmp.out 2>&1)
|
||||
fi
|
||||
sts=$?
|
||||
$timestamp && _timestamp
|
||||
stop=$(_wallclock)
|
||||
|
||||
if [ -f core ]
|
||||
then
|
||||
printf " [dumped core]"
|
||||
mv core $seq.core
|
||||
status="fail"
|
||||
results="[dumped core] $seq.core"
|
||||
err=true
|
||||
fi
|
||||
|
||||
if [ -f $seq.notrun ]
|
||||
then
|
||||
$timestamp || printf " [not run] "
|
||||
$timestamp && echo " [not run]" && printf %s " $seq -- "
|
||||
cat $seq.notrun
|
||||
notrun="$notrun $seq"
|
||||
# overwrites timestamp output
|
||||
status="not run"
|
||||
results="$(cat $seq.notrun)"
|
||||
else
|
||||
if [ $sts -ne 0 ]
|
||||
then
|
||||
printf %s " [failed, exit status $sts]"
|
||||
status="fail"
|
||||
results=$(printf %s "[failed, exit status $sts]")
|
||||
err=true
|
||||
fi
|
||||
|
||||
@ -821,22 +863,23 @@ do
|
||||
|
||||
if [ ! -f "$reference" ]
|
||||
then
|
||||
echo " - no qualified output"
|
||||
status="fail"
|
||||
reason="no qualified output"
|
||||
err=true
|
||||
else
|
||||
if diff -w "$reference" $tmp.out >/dev/null 2>&1
|
||||
then
|
||||
echo ""
|
||||
if $err
|
||||
then
|
||||
:
|
||||
else
|
||||
echo "$seq $(expr $stop - $start)" >>$tmp.time
|
||||
if ! $err; then
|
||||
status="pass"
|
||||
thistime=$(expr $stop - $start)
|
||||
echo "$seq $thistime" >>$tmp.time
|
||||
fi
|
||||
else
|
||||
echo " - output mismatch (see $seq.out.bad)"
|
||||
mv $tmp.out $seq.out.bad
|
||||
$diff -w "$reference" "$PWD"/$seq.out.bad
|
||||
status="fail"
|
||||
results="output mismatch (see $seq.out.bad)"
|
||||
printdiff=true
|
||||
err=true
|
||||
fi
|
||||
fi
|
||||
@ -850,13 +893,27 @@ do
|
||||
|
||||
# come here for each test, except when $showme is true
|
||||
#
|
||||
if $err
|
||||
then
|
||||
bad="$bad $seq"
|
||||
n_bad=$(expr $n_bad + 1)
|
||||
quick=false
|
||||
fi
|
||||
[ -f $seq.notrun ] || try=$(expr $try + 1)
|
||||
_report_test_result $seq "$status" "$starttime" "$lasttime" "$thistime" "$results"
|
||||
case "$status" in
|
||||
"pass")
|
||||
try=$(expr $try + 1)
|
||||
;;
|
||||
"fail")
|
||||
try=$(expr $try + 1)
|
||||
if $makecheck; then
|
||||
_full_env_details
|
||||
fi
|
||||
if $printdiff; then
|
||||
$diff -w "$reference" "$PWD"/$seq.out.bad
|
||||
fi
|
||||
bad="$bad $seq"
|
||||
n_bad=$(expr $n_bad + 1)
|
||||
quick=false
|
||||
;;
|
||||
"not run")
|
||||
notrun="$notrun $seq"
|
||||
;;
|
||||
esac
|
||||
|
||||
seq="after_$seq"
|
||||
done
|
||||
|
@ -1,8 +1,21 @@
|
||||
#
|
||||
# QA groups control file
|
||||
# Defines test groups
|
||||
#
|
||||
# Some notes about the groups:
|
||||
#
|
||||
# - do not start group names with a digit
|
||||
#
|
||||
# - quick : Tests in this group should finish within some few seconds.
|
||||
#
|
||||
# - img : Tests in this group can be used to excercise the qemu-img tool.
|
||||
#
|
||||
# - auto : Tests in this group are used during "make check" and should be
|
||||
# runnable in any case. That means they should run with every QEMU binary
|
||||
# (also non-x86), with every QEMU configuration (i.e. must not fail if
|
||||
# an optional feature is not compiled in - but reporting a "skip" is ok),
|
||||
# and work all kind of host filesystems and users (e.g. "nobody" or "root").
|
||||
#
|
||||
|
||||
#
|
||||
# test-group association ... one line per test
|
||||
@ -32,11 +45,11 @@
|
||||
023 rw auto
|
||||
024 rw backing auto quick
|
||||
025 rw auto quick
|
||||
026 rw blkdbg auto
|
||||
026 rw blkdbg
|
||||
027 rw auto quick
|
||||
028 rw backing auto quick
|
||||
028 rw backing quick
|
||||
029 rw auto quick
|
||||
030 rw auto backing
|
||||
030 rw backing
|
||||
031 rw auto quick
|
||||
032 rw auto quick
|
||||
033 rw auto quick
|
||||
@ -46,35 +59,35 @@
|
||||
037 rw auto backing quick
|
||||
038 rw auto backing quick
|
||||
039 rw auto quick
|
||||
040 rw auto
|
||||
041 rw auto backing
|
||||
040 rw
|
||||
041 rw backing
|
||||
042 rw auto quick
|
||||
043 rw auto backing
|
||||
044 rw auto
|
||||
045 rw auto quick
|
||||
044 rw
|
||||
045 rw quick
|
||||
046 rw auto aio quick
|
||||
047 rw auto quick
|
||||
048 img auto quick
|
||||
049 rw auto
|
||||
050 rw auto backing quick
|
||||
051 rw auto
|
||||
051 rw
|
||||
052 rw auto backing quick
|
||||
053 rw auto quick
|
||||
054 rw auto quick
|
||||
055 rw auto
|
||||
056 rw auto backing
|
||||
057 rw auto
|
||||
058 rw auto quick
|
||||
055 rw
|
||||
056 rw backing
|
||||
057 rw
|
||||
058 rw quick
|
||||
059 rw auto quick
|
||||
060 rw auto quick
|
||||
061 rw auto
|
||||
062 rw auto quick
|
||||
063 rw auto quick
|
||||
064 rw auto quick
|
||||
065 rw auto quick
|
||||
065 rw quick
|
||||
066 rw auto quick
|
||||
067 rw auto quick
|
||||
068 rw auto quick
|
||||
067 rw quick
|
||||
068 rw quick
|
||||
069 rw auto quick
|
||||
070 rw auto quick
|
||||
071 rw auto quick
|
||||
@ -91,18 +104,18 @@
|
||||
082 rw auto quick
|
||||
083 rw auto
|
||||
084 img auto quick
|
||||
085 rw auto
|
||||
085 rw
|
||||
086 rw auto quick
|
||||
087 rw auto quick
|
||||
087 rw quick
|
||||
088 rw auto quick
|
||||
089 rw auto quick
|
||||
090 rw auto quick
|
||||
091 rw auto migration
|
||||
092 rw auto quick
|
||||
093 auto
|
||||
093 throttle
|
||||
094 rw auto quick
|
||||
095 rw auto quick
|
||||
096 rw auto quick
|
||||
095 rw quick
|
||||
096 rw quick
|
||||
097 rw auto backing
|
||||
098 rw auto backing quick
|
||||
099 rw auto quick
|
||||
@ -118,60 +131,60 @@
|
||||
109 rw auto
|
||||
110 rw auto backing quick
|
||||
111 rw auto quick
|
||||
112 rw auto
|
||||
112 rw
|
||||
113 rw auto quick
|
||||
114 rw auto quick
|
||||
115 rw auto
|
||||
115 rw
|
||||
116 rw auto quick
|
||||
117 rw auto
|
||||
118 rw auto
|
||||
118 rw
|
||||
119 rw auto quick
|
||||
120 rw auto quick
|
||||
121 rw auto
|
||||
121 rw
|
||||
122 rw auto
|
||||
123 rw auto quick
|
||||
124 rw auto backing
|
||||
125 rw auto
|
||||
124 rw backing
|
||||
125 rw
|
||||
126 rw auto backing
|
||||
127 rw auto backing quick
|
||||
127 rw backing quick
|
||||
128 rw auto quick
|
||||
129 rw auto quick
|
||||
129 rw quick
|
||||
130 rw auto quick
|
||||
131 rw auto quick
|
||||
132 rw auto quick
|
||||
132 rw quick
|
||||
133 auto quick
|
||||
134 rw auto quick
|
||||
135 rw auto
|
||||
136 rw auto
|
||||
136 rw
|
||||
137 rw auto
|
||||
138 rw auto quick
|
||||
139 rw auto quick
|
||||
139 rw quick
|
||||
140 rw auto quick
|
||||
141 rw auto quick
|
||||
142 auto
|
||||
143 auto quick
|
||||
144 rw auto quick
|
||||
145 auto quick
|
||||
144 rw quick
|
||||
145 quick
|
||||
146 auto quick
|
||||
147 auto
|
||||
148 rw auto quick
|
||||
149 rw auto sudo
|
||||
147 img
|
||||
148 rw quick
|
||||
149 rw sudo
|
||||
150 rw auto quick
|
||||
151 rw auto
|
||||
152 rw auto quick
|
||||
153 rw auto quick
|
||||
151 rw
|
||||
152 rw quick
|
||||
153 rw quick
|
||||
154 rw auto backing quick
|
||||
155 rw auto
|
||||
155 rw
|
||||
156 rw auto quick
|
||||
157 auto
|
||||
157 quick
|
||||
158 rw auto quick
|
||||
159 rw auto quick
|
||||
160 rw auto quick
|
||||
161 rw auto quick
|
||||
162 auto quick
|
||||
163 rw auto
|
||||
165 rw auto quick
|
||||
169 rw auto quick migration
|
||||
162 quick
|
||||
163 rw
|
||||
165 rw quick
|
||||
169 rw quick migration
|
||||
170 rw auto quick
|
||||
171 rw auto quick
|
||||
172 auto
|
||||
@ -180,74 +193,74 @@
|
||||
175 auto quick
|
||||
176 rw auto backing
|
||||
177 rw auto quick
|
||||
178 auto
|
||||
178 img
|
||||
179 rw auto quick
|
||||
181 rw auto migration
|
||||
182 rw auto quick
|
||||
183 rw auto migration
|
||||
182 rw quick
|
||||
183 rw migration
|
||||
184 rw auto quick
|
||||
185 rw auto
|
||||
185 rw
|
||||
186 rw auto
|
||||
187 rw auto
|
||||
188 rw auto quick
|
||||
189 rw auto
|
||||
188 rw quick
|
||||
189 rw
|
||||
190 rw auto quick
|
||||
191 rw auto
|
||||
192 rw auto quick
|
||||
194 rw auto migration quick
|
||||
194 rw migration quick
|
||||
195 rw auto quick
|
||||
196 rw auto quick migration
|
||||
196 rw quick migration
|
||||
197 rw auto quick
|
||||
198 rw auto
|
||||
199 rw auto migration
|
||||
200 rw auto
|
||||
198 rw
|
||||
199 rw migration
|
||||
200 rw
|
||||
201 rw auto migration
|
||||
202 rw auto quick
|
||||
203 rw auto migration
|
||||
204 rw auto quick
|
||||
205 rw auto quick
|
||||
206 rw auto
|
||||
202 rw quick
|
||||
203 rw migration
|
||||
204 rw quick
|
||||
205 rw quick
|
||||
206 rw
|
||||
207 rw auto
|
||||
208 rw auto quick
|
||||
209 rw auto quick
|
||||
208 rw quick
|
||||
209 rw quick
|
||||
210 rw auto
|
||||
211 rw auto quick
|
||||
212 rw auto quick
|
||||
213 rw auto quick
|
||||
214 rw auto
|
||||
215 rw auto quick
|
||||
216 rw auto quick
|
||||
216 rw quick
|
||||
217 rw auto quick
|
||||
218 rw auto quick
|
||||
219 rw auto
|
||||
218 rw quick
|
||||
219 rw
|
||||
220 rw auto
|
||||
221 rw auto quick
|
||||
222 rw auto quick
|
||||
223 rw auto quick
|
||||
224 rw auto quick
|
||||
222 rw quick
|
||||
223 rw quick
|
||||
224 rw quick
|
||||
225 rw auto quick
|
||||
226 auto quick
|
||||
227 auto quick
|
||||
228 rw auto quick
|
||||
227 quick
|
||||
228 rw quick
|
||||
229 auto quick
|
||||
231 auto quick
|
||||
232 auto quick
|
||||
232 quick
|
||||
233 auto quick
|
||||
234 auto quick migration
|
||||
235 auto quick
|
||||
236 auto quick
|
||||
234 quick migration
|
||||
235 quick
|
||||
236 quick
|
||||
237 rw auto quick
|
||||
238 auto quick
|
||||
238 quick
|
||||
239 rw auto quick
|
||||
240 auto quick
|
||||
240 quick
|
||||
241 rw auto quick
|
||||
242 rw auto quick
|
||||
242 rw quick
|
||||
243 rw auto quick
|
||||
244 rw auto quick
|
||||
245 rw auto
|
||||
246 rw auto quick
|
||||
247 rw auto quick
|
||||
248 rw auto quick
|
||||
245 rw
|
||||
246 rw quick
|
||||
247 rw quick
|
||||
248 rw quick
|
||||
249 rw auto quick
|
||||
252 rw auto backing quick
|
||||
253 rw auto quick
|
||||
|
@ -96,6 +96,7 @@ else
|
||||
# build options for bare programs are usually pretty different. They
|
||||
# are expected to provide their own build recipes.
|
||||
-include $(SRC_PATH)/tests/tcg/minilib/Makefile.target
|
||||
-include $(SRC_PATH)/tests/tcg/multiarch/system/Makefile.softmmu-target
|
||||
-include $(SRC_PATH)/tests/tcg/$(TARGET_BASE_ARCH)/Makefile.softmmu-target
|
||||
ifneq ($(TARGET_BASE_ARCH),$(TARGET_NAME))
|
||||
-include $(SRC_PATH)/tests/tcg/$(TARGET_NAME)/Makefile.softmmu-target
|
||||
|
34
tests/tcg/aarch64/Makefile.softmmu-target
Normal file
34
tests/tcg/aarch64/Makefile.softmmu-target
Normal file
@ -0,0 +1,34 @@
|
||||
#
|
||||
# Aarch64 system tests
|
||||
#
|
||||
|
||||
AARCH64_SYSTEM_SRC=$(SRC_PATH)/tests/tcg/aarch64/system
|
||||
VPATH+=$(AARCH64_SYSTEM_SRC)
|
||||
|
||||
# These objects provide the basic boot code and helper functions for all tests
|
||||
CRT_OBJS=boot.o
|
||||
|
||||
AARCH64_TEST_SRCS=$(wildcard $(AARCH64_SYSTEM_SRC)/*.c)
|
||||
AARCH64_TESTS = $(patsubst $(AARCH64_SYSTEM_SRC)/%.c, %, $(AARCH64_TEST_SRCS))
|
||||
|
||||
CRT_PATH=$(AARCH64_SYSTEM_SRC)
|
||||
LINK_SCRIPT=$(AARCH64_SYSTEM_SRC)/kernel.ld
|
||||
LDFLAGS=-Wl,-T$(LINK_SCRIPT)
|
||||
TESTS+=$(AARCH64_TESTS) $(MULTIARCH_TESTS)
|
||||
CFLAGS+=-nostdlib -ggdb -O0 $(MINILIB_INC)
|
||||
LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc
|
||||
|
||||
# building head blobs
|
||||
.PRECIOUS: $(CRT_OBJS)
|
||||
|
||||
%.o: $(CRT_PATH)/%.S
|
||||
$(CC) $(CFLAGS) -x assembler-with-cpp -c $< -o $@
|
||||
|
||||
# Build and link the tests
|
||||
%: %.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS)
|
||||
$(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)
|
||||
|
||||
memory: CFLAGS+=-DCHECK_UNALIGNED=1
|
||||
|
||||
# Running
|
||||
QEMU_OPTS+=-M virt -cpu max -display none -semihosting-config enable=on,target=native,chardev=output -kernel
|
239
tests/tcg/aarch64/system/boot.S
Normal file
239
tests/tcg/aarch64/system/boot.S
Normal file
@ -0,0 +1,239 @@
|
||||
/*
|
||||
* Minimal AArch64 system boot code.
|
||||
*
|
||||
* Copyright Linaro Ltd 2019
|
||||
*
|
||||
* Loosely based on the newlib/libgloss setup stubs. Using semihosting
|
||||
* for serial output and exit functions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Semihosting interface on ARM AArch64
|
||||
* See "Semihosting for AArch32 and AArch64 Relase 2.0" by ARM
|
||||
* w0 - semihosting call number
|
||||
* x1 - semihosting parameter
|
||||
*/
|
||||
#define semihosting_call hlt 0xf000
|
||||
#define SYS_WRITEC 0x03 /* character to debug channel */
|
||||
#define SYS_WRITE0 0x04 /* string to debug channel */
|
||||
#define SYS_EXIT 0x18
|
||||
|
||||
.align 12
|
||||
|
||||
.macro ventry label
|
||||
.align 7
|
||||
b \label
|
||||
.endm
|
||||
|
||||
vector_table:
|
||||
/* Current EL with SP0. */
|
||||
ventry curr_sp0_sync /* Synchronous */
|
||||
ventry curr_sp0_irq /* Irq/vIRQ */
|
||||
ventry curr_sp0_fiq /* Fiq/vFIQ */
|
||||
ventry curr_sp0_serror /* SError/VSError */
|
||||
|
||||
/* Current EL with SPx. */
|
||||
ventry curr_spx_sync /* Synchronous */
|
||||
ventry curr_spx_irq /* IRQ/vIRQ */
|
||||
ventry curr_spx_fiq /* FIQ/vFIQ */
|
||||
ventry curr_spx_serror /* SError/VSError */
|
||||
|
||||
/* Lower EL using AArch64. */
|
||||
ventry lower_a64_sync /* Synchronous */
|
||||
ventry lower_a64_irq /* IRQ/vIRQ */
|
||||
ventry lower_a64_fiq /* FIQ/vFIQ */
|
||||
ventry lower_a64_serror /* SError/VSError */
|
||||
|
||||
/* Lower EL using AArch32. */
|
||||
ventry lower_a32_sync /* Synchronous */
|
||||
ventry lower_a32_irq /* IRQ/vIRQ */
|
||||
ventry lower_a32_fiq /* FIQ/vFIQ */
|
||||
ventry lower_a32_serror /* SError/VSError */
|
||||
|
||||
.text
|
||||
.align 4
|
||||
|
||||
/* Common vector handling for now */
|
||||
curr_sp0_sync:
|
||||
curr_sp0_irq:
|
||||
curr_sp0_fiq:
|
||||
curr_sp0_serror:
|
||||
curr_spx_sync:
|
||||
curr_spx_irq:
|
||||
curr_spx_fiq:
|
||||
curr_spx_serror:
|
||||
lower_a64_sync:
|
||||
lower_a64_irq:
|
||||
lower_a64_fiq:
|
||||
lower_a64_serror:
|
||||
lower_a32_sync:
|
||||
lower_a32_irq:
|
||||
lower_a32_fiq:
|
||||
lower_a32_serror:
|
||||
mov x0, SYS_WRITE0
|
||||
adr x1, .error
|
||||
semihosting_call
|
||||
mov x0, SYS_EXIT
|
||||
mov x1, 1
|
||||
semihosting_call
|
||||
/* never returns */
|
||||
|
||||
.section .rodata
|
||||
.error:
|
||||
.string "Terminated by exception.\n"
|
||||
|
||||
.text
|
||||
.align 4
|
||||
.global __start
|
||||
__start:
|
||||
/* Installs a table of exception vectors to catch and handle all
|
||||
exceptions by terminating the process with a diagnostic. */
|
||||
adr x0, vector_table
|
||||
msr vbar_el1, x0
|
||||
|
||||
/* Page table setup (identity mapping). */
|
||||
adrp x0, ttb
|
||||
add x0, x0, :lo12:ttb
|
||||
msr ttbr0_el1, x0
|
||||
|
||||
/*
|
||||
* Setup a flat address mapping page-tables. Stage one simply
|
||||
* maps RAM to the first Gb. The stage2 tables have two 2mb
|
||||
* translation block entries covering a series of adjacent
|
||||
* 4k pages.
|
||||
*/
|
||||
|
||||
/* Stage 1 entry: indexed by IA[38:30] */
|
||||
adr x1, . /* phys address */
|
||||
bic x1, x1, #(1 << 30) - 1 /* 1GB alignment*/
|
||||
add x2, x0, x1, lsr #(30 - 3) /* offset in l1 page table */
|
||||
|
||||
/* point to stage 2 table [47:12] */
|
||||
adrp x0, ttb_stage2
|
||||
orr x1, x0, #3 /* ptr to stage 2 */
|
||||
str x1, [x2]
|
||||
|
||||
/* Stage 2 entries: indexed by IA[29:21] */
|
||||
ldr x5, =(((1 << 9) - 1) << 21)
|
||||
|
||||
/* First block: .text/RO/execute enabled */
|
||||
adr x1, . /* phys address */
|
||||
bic x1, x1, #(1 << 21) - 1 /* 2mb block alignment */
|
||||
and x4, x1, x5 /* IA[29:21] */
|
||||
add x2, x0, x4, lsr #(21 - 3) /* offset in l2 page table */
|
||||
ldr x3, =0x401 /* attr(AF, block) */
|
||||
orr x1, x1, x3
|
||||
str x1, [x2] /* 1st 2mb (.text & rodata) */
|
||||
|
||||
/* Second block: .data/RW/no execute */
|
||||
adrp x1, .data
|
||||
add x1, x1, :lo12:.data
|
||||
bic x1, x1, #(1 << 21) - 1 /* 2mb block alignment */
|
||||
and x4, x1, x5 /* IA[29:21] */
|
||||
add x2, x0, x4, lsr #(21 - 3) /* offset in l2 page table */
|
||||
ldr x3, =(3 << 53) | 0x401 /* attr(AF, NX, block) */
|
||||
orr x1, x1, x3
|
||||
str x1, [x2] /* 2nd 2mb (.data & .bss)*/
|
||||
|
||||
/* Setup/enable the MMU. */
|
||||
|
||||
/*
|
||||
* TCR_EL1 - Translation Control Registers
|
||||
*
|
||||
* IPS[34:32] = 40-bit PA, 1TB
|
||||
* TG0[14:15] = b00 => 4kb granuale
|
||||
* ORGN0[11:10] = Outer: Normal, WB Read-Alloc No Write-Alloc Cacheable
|
||||
* IRGN0[9:8] = Inner: Normal, WB Read-Alloc No Write-Alloc Cacheable
|
||||
* T0SZ[5:0] = 2^(64 - 25)
|
||||
*
|
||||
* The size of T0SZ controls what the initial lookup level. It
|
||||
* would be nice to start at level 2 but unfortunatly for a
|
||||
* flat-mapping on the virt machine we need to handle IA's
|
||||
* with at least 1gb range to see RAM. So we start with a
|
||||
* level 1 lookup.
|
||||
*/
|
||||
ldr x0, = (2 << 32) | 25 | (3 << 10) | (3 << 8)
|
||||
msr tcr_el1, x0
|
||||
|
||||
mov x0, #0xee /* Inner/outer cacheable WB */
|
||||
msr mair_el1, x0
|
||||
isb
|
||||
|
||||
/*
|
||||
* SCTLR_EL1 - System Control Register
|
||||
*
|
||||
* WXN[19] = 0 = no effect, Write does not imply XN (execute never)
|
||||
* I[12] = Instruction cachability control
|
||||
* SA[3] = SP alignment check
|
||||
* C[2] = Data cachability control
|
||||
* M[0] = 1, enable stage 1 address translation for EL0/1
|
||||
*/
|
||||
mrs x0, sctlr_el1
|
||||
ldr x1, =0x100d /* bits I(12) SA(3) C(2) M(0) */
|
||||
bic x0, x0, #(1 << 1) /* clear bit A(1) */
|
||||
bic x0, x0, #(1 << 19) /* clear WXN */
|
||||
orr x0, x0, x1 /* set bits */
|
||||
|
||||
dsb sy
|
||||
msr sctlr_el1, x0
|
||||
isb
|
||||
|
||||
/*
|
||||
* Enable FP registers. The standard C pre-amble will be
|
||||
* saving these and A-profile compilers will use AdvSIMD
|
||||
* registers unless we tell it not to.
|
||||
*/
|
||||
mrs x0, cpacr_el1
|
||||
orr x0, x0, #(3 << 20)
|
||||
msr cpacr_el1, x0
|
||||
|
||||
/* Setup some stack space and enter the test code.
|
||||
* Assume everthing except the return value is garbage when we
|
||||
* return, we won't need it.
|
||||
*/
|
||||
adrp x0, stack_end
|
||||
add x0, x0, :lo12:stack_end
|
||||
mov sp, x0
|
||||
bl main
|
||||
|
||||
/* pass return value to sys exit */
|
||||
mov x1, x0
|
||||
ldr x0, =0x20026 /* ADP_Stopped_ApplicationExit */
|
||||
stp x0, x1, [sp, #-16]!
|
||||
mov x1, sp
|
||||
mov x0, SYS_EXIT
|
||||
semihosting_call
|
||||
/* never returns */
|
||||
|
||||
/*
|
||||
* Helper Functions
|
||||
*/
|
||||
|
||||
/* Output a single character to serial port */
|
||||
.global __sys_outc
|
||||
__sys_outc:
|
||||
stp x0, x1, [sp, #-16]!
|
||||
/* pass address of c on stack */
|
||||
mov x1, sp
|
||||
mov x0, SYS_WRITEC
|
||||
semihosting_call
|
||||
ldp x0, x1, [sp], #16
|
||||
ret
|
||||
|
||||
.data
|
||||
.align 12
|
||||
|
||||
/* Translation table
|
||||
* @4k granuale: 9 bit lookup, 512 entries
|
||||
*/
|
||||
ttb:
|
||||
.space 4096, 0
|
||||
|
||||
.align 12
|
||||
ttb_stage2:
|
||||
.space 4096, 0
|
||||
|
||||
.align 12
|
||||
stack:
|
||||
.space 65536, 0
|
||||
stack_end:
|
24
tests/tcg/aarch64/system/kernel.ld
Normal file
24
tests/tcg/aarch64/system/kernel.ld
Normal file
@ -0,0 +1,24 @@
|
||||
ENTRY(__start)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/* virt machine, RAM starts at 1gb */
|
||||
. = (1 << 30);
|
||||
.text : {
|
||||
*(.text)
|
||||
}
|
||||
.rodata : {
|
||||
*(.rodata)
|
||||
}
|
||||
/* align r/w section to next 2mb */
|
||||
. = ALIGN(1 << 21);
|
||||
.data : {
|
||||
*(.data)
|
||||
}
|
||||
.bss : {
|
||||
*(.bss)
|
||||
}
|
||||
/DISCARD/ : {
|
||||
*(.ARM.attributes)
|
||||
}
|
||||
}
|
34
tests/tcg/alpha/Makefile.softmmu-target
Normal file
34
tests/tcg/alpha/Makefile.softmmu-target
Normal file
@ -0,0 +1,34 @@
|
||||
#
|
||||
# Alpha system tests
|
||||
#
|
||||
|
||||
ALPHA_SYSTEM_SRC=$(SRC_PATH)/tests/tcg/alpha/system
|
||||
VPATH+=$(ALPHA_SYSTEM_SRC)
|
||||
|
||||
# These objects provide the basic boot code and helper functions for all tests
|
||||
CRT_OBJS=boot.o
|
||||
|
||||
ALPHA_TEST_SRCS=$(wildcard $(ALPHA_SYSTEM_SRC)/*.c)
|
||||
ALPHA_TESTS = $(patsubst $(ALPHA_SYSTEM_SRC)/%.c, %, $(ALPHA_TEST_SRCS))
|
||||
|
||||
CRT_PATH=$(ALPHA_SYSTEM_SRC)
|
||||
LINK_SCRIPT=$(ALPHA_SYSTEM_SRC)/kernel.ld
|
||||
LDFLAGS=-Wl,-T$(LINK_SCRIPT)
|
||||
TESTS+=$(ALPHA_TESTS) $(MULTIARCH_TESTS)
|
||||
CFLAGS+=-nostdlib -g -O1 -mcpu=ev6 $(MINILIB_INC)
|
||||
LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc
|
||||
|
||||
# building head blobs
|
||||
.PRECIOUS: $(CRT_OBJS)
|
||||
|
||||
%.o: $(CRT_PATH)/%.S
|
||||
$(CC) $(CFLAGS) -x assembler-with-cpp -c $< -o $@
|
||||
|
||||
# Build and link the tests
|
||||
%: %.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS)
|
||||
$(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)
|
||||
|
||||
memory: CFLAGS+=-DCHECK_UNALIGNED=0
|
||||
|
||||
# Running
|
||||
QEMU_OPTS+=-serial chardev:output -kernel
|
511
tests/tcg/alpha/system/boot.S
Normal file
511
tests/tcg/alpha/system/boot.S
Normal file
@ -0,0 +1,511 @@
|
||||
/*
|
||||
* Minimal Alpha system boot code.
|
||||
*
|
||||
* Copyright Linaro Ltd 2019
|
||||
*/
|
||||
|
||||
.set noat
|
||||
.set nomacro
|
||||
.arch ev6
|
||||
.text
|
||||
|
||||
.macro load_pci_io reg
|
||||
/* For typhoon, this is
|
||||
* 0xfffffc0000000000 -- kseg identity map
|
||||
* + 0x10000000000 -- typhoon pio base
|
||||
* + 0x1fc000000 -- typhoon pchip0 pci base
|
||||
* = 0xfffffd01fc000000
|
||||
*/
|
||||
ldah \reg, -3 /* ff..fd0000 */
|
||||
lda \reg, 0x1fc(\reg) /* ff..fd01fc */
|
||||
sll \reg, 24, \reg
|
||||
.endm
|
||||
|
||||
#define com1Rbr 0x3f8
|
||||
#define com1Thr 0x3f8
|
||||
#define com1Ier 0x3f9
|
||||
#define com1Iir 0x3fa
|
||||
#define com1Lcr 0x3fb
|
||||
#define com1Mcr 0x3fc
|
||||
#define com1Lsr 0x3fd
|
||||
#define com1Msr 0x3fe
|
||||
#define com1Scr 0x3ff
|
||||
#define com1Dll 0x3f8
|
||||
#define com1Dlm 0x3f9
|
||||
|
||||
#define PAL_halt 0
|
||||
#define PAL_wrent 52
|
||||
#define PAL_wrkgp 55
|
||||
|
||||
.text
|
||||
.p2align 4
|
||||
.globl _start
|
||||
.ent _start
|
||||
_start:
|
||||
br $gp, .+4
|
||||
ldah $gp, 0($gp) !gpdisp!1
|
||||
lda $gp, 0($gp) !gpdisp!1
|
||||
|
||||
ldah $sp, $stack_end($gp) !gprelhigh
|
||||
lda $sp, $stack_end($sp) !gprellow
|
||||
|
||||
/* Install kernel gp for exception handlers. */
|
||||
mov $gp, $16
|
||||
call_pal PAL_wrkgp
|
||||
|
||||
/* Install exception handlers. */
|
||||
ldah $16, entInt($gp) !gprelhigh
|
||||
lda $16, entInt($16) !gprellow
|
||||
lda $17, 0
|
||||
call_pal PAL_wrent
|
||||
|
||||
ldah $16, entArith($gp) !gprelhigh
|
||||
lda $16, entArith($16) !gprellow
|
||||
lda $17, 1
|
||||
call_pal PAL_wrent
|
||||
|
||||
ldah $16, entMM($gp) !gprelhigh
|
||||
lda $16, entMM($16) !gprellow
|
||||
lda $17, 2
|
||||
call_pal PAL_wrent
|
||||
|
||||
ldah $16, entIF($gp) !gprelhigh
|
||||
lda $16, entIF($16) !gprellow
|
||||
lda $17, 3
|
||||
call_pal PAL_wrent
|
||||
|
||||
ldah $16, entUna($gp) !gprelhigh
|
||||
lda $16, entUna($16) !gprellow
|
||||
lda $17, 4
|
||||
call_pal PAL_wrent
|
||||
|
||||
ldah $16, entSys($gp) !gprelhigh
|
||||
lda $16, entSys($16) !gprellow
|
||||
lda $17, 5
|
||||
call_pal PAL_wrent
|
||||
|
||||
/*
|
||||
* Initialize COM1.
|
||||
*/
|
||||
load_pci_io $1
|
||||
lda $2, 0x87 /* outb(0x87, com1Lcr); */
|
||||
stb $2, com1Lcr($1)
|
||||
stb $31, com1Dlm($1) /* outb(0, com1Dlm); */
|
||||
lda $2, 3 /* baudconst 3 => 56000 */
|
||||
stb $2, com1Dll($1) /* outb(baudconst, com1Dll); */
|
||||
lda $2, 0x07
|
||||
stb $2, com1Lcr($1) /* outb(0x07, com1Lcr) */
|
||||
lda $2, 0x0f
|
||||
stb $2, com1Mcr($1) /* outb(0x0f, com1Mcr) */
|
||||
|
||||
bsr $26, main !samegp
|
||||
|
||||
/* fall through to _exit */
|
||||
.end _start
|
||||
|
||||
.globl _exit
|
||||
.ent _exit
|
||||
_exit:
|
||||
.frame $sp, 0, $26, 0
|
||||
.prologue 0
|
||||
|
||||
/* We cannot return an error code. */
|
||||
call_pal PAL_halt
|
||||
.end _exit
|
||||
|
||||
/*
|
||||
* We have received an exception that we don't handle. Log and exit.
|
||||
*/
|
||||
.ent log_exit
|
||||
log_exit:
|
||||
entInt:
|
||||
entArith:
|
||||
entMM:
|
||||
entIF:
|
||||
entUna:
|
||||
entSys:
|
||||
ldah $16, $errormsg($gp) !gprelhigh
|
||||
lda $16, $errormsg($16) !gprellow
|
||||
bsr $26, __sys_outs !samegp
|
||||
bsr $26, _exit !samegp
|
||||
.end log_exit
|
||||
|
||||
.section .rodata
|
||||
$errormsg:
|
||||
.string "Terminated by exception.\n"
|
||||
.previous
|
||||
|
||||
/*
|
||||
* Helper Functions
|
||||
*/
|
||||
|
||||
/* Output a single character to serial port */
|
||||
.global __sys_outc
|
||||
.ent __sys_outc
|
||||
__sys_outc:
|
||||
.frame $sp, 0, $26, 0
|
||||
.prologue 0
|
||||
|
||||
load_pci_io $1
|
||||
|
||||
/*
|
||||
* while ((inb(com1Lsr) & 0x20) == 0)
|
||||
* continue;
|
||||
*/
|
||||
1: ldbu $0, com1Lsr($1)
|
||||
and $0, 0x20, $0
|
||||
beq $0, 1b
|
||||
|
||||
/* outb(c, com1Thr); */
|
||||
stb $16, com1Thr($1)
|
||||
ret
|
||||
.end __sys_outc
|
||||
|
||||
/* Output a nul-terminated string to serial port */
|
||||
.global __sys_outs
|
||||
.ent __sys_outs
|
||||
__sys_outs:
|
||||
.frame $sp, 0, $26, 0
|
||||
.prologue 0
|
||||
|
||||
load_pci_io $1
|
||||
|
||||
ldbu $2, 0($16)
|
||||
beq $2, 9f
|
||||
|
||||
/*
|
||||
* while ((inb(com1Lsr) & 0x20) == 0)
|
||||
* continue;
|
||||
*/
|
||||
1: ldbu $0, com1Lsr($1)
|
||||
and $0, 0x20, $0
|
||||
beq $0, 1b
|
||||
|
||||
/* outb(c, com1Thr); */
|
||||
stb $2, com1Thr($1)
|
||||
|
||||
addq $16, 1, $16
|
||||
ldbu $2, 0($16)
|
||||
bne $2, 1b
|
||||
|
||||
9: ret
|
||||
.end __sys_outs
|
||||
|
||||
/*
|
||||
* Division routines that are normally in libc.
|
||||
*
|
||||
* These do not follow the C calling convention. Arguments are in $24+$25,
|
||||
* the result is in $27. Register $28 may be clobbered; everything else
|
||||
* must be saved.
|
||||
*
|
||||
* We store the remainder in $28, so that we can share code.
|
||||
*
|
||||
* We do not signal divide by zero.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Unsigned 64-bit division.
|
||||
*/
|
||||
|
||||
.globl __divqu
|
||||
.ent __divqu
|
||||
__divqu:
|
||||
.frame $sp, 48, $23
|
||||
subq $sp, 48, $sp
|
||||
stq $0, 0($sp)
|
||||
stq $1, 8($sp)
|
||||
stq $2, 16($sp)
|
||||
stq $3, 24($sp)
|
||||
stq $4, 32($sp)
|
||||
.prologue 0
|
||||
|
||||
#define mask $0
|
||||
#define divisor $1
|
||||
#define compare $2
|
||||
#define tmp1 $3
|
||||
#define tmp2 $4
|
||||
#define quotient $27
|
||||
#define modulus $28
|
||||
|
||||
mov $24, modulus
|
||||
mov $25, divisor
|
||||
mov $31, quotient
|
||||
mov 1, mask
|
||||
beq $25, 9f
|
||||
|
||||
/* Shift left until divisor >= modulus. */
|
||||
1: cmpult divisor, modulus, compare
|
||||
blt divisor, 2f
|
||||
addq divisor, divisor, divisor
|
||||
addq mask, mask, mask
|
||||
bne compare, 1b
|
||||
|
||||
2: addq quotient, mask, tmp2
|
||||
srl mask, 1, mask
|
||||
cmpule divisor, modulus, compare
|
||||
subq modulus, divisor, tmp1
|
||||
cmovne compare, tmp2, quotient
|
||||
srl divisor, 1, divisor
|
||||
cmovne compare, tmp1, modulus
|
||||
bne mask, 2b
|
||||
|
||||
9: ldq $0, 0($sp)
|
||||
ldq $1, 8($sp)
|
||||
ldq $2, 16($sp)
|
||||
ldq $3, 24($sp)
|
||||
ldq $4, 32($sp)
|
||||
addq $sp, 48, $sp
|
||||
ret $31, ($23), 1
|
||||
|
||||
#undef mask
|
||||
#undef divisor
|
||||
#undef compare
|
||||
#undef tmp1
|
||||
#undef tmp2
|
||||
#undef quotient
|
||||
#undef modulus
|
||||
|
||||
.end __divqu
|
||||
|
||||
/*
|
||||
* Unsigned 64-bit remainder.
|
||||
* Note that __divqu above leaves the result in $28.
|
||||
*/
|
||||
|
||||
.globl __remqu
|
||||
.ent __remqu
|
||||
__remqu:
|
||||
.frame $sp, 16, $23
|
||||
subq $sp, 16, $sp
|
||||
stq $23, 0($sp)
|
||||
.prologue 0
|
||||
|
||||
bsr $23, __divqu
|
||||
|
||||
ldq $23, 0($sp)
|
||||
mov $28, $27
|
||||
addq $sp, 16, $sp
|
||||
ret $31, ($23), 1
|
||||
.end __remqu
|
||||
|
||||
/*
|
||||
* Signed 64-bit division.
|
||||
*/
|
||||
|
||||
.globl __divqs
|
||||
.ent __divqs
|
||||
__divqs:
|
||||
.prologue 0
|
||||
|
||||
/* Common case: both arguments are positive. */
|
||||
bis $24, $25, $28
|
||||
bge $28, __divqu
|
||||
|
||||
/* At least one argument is negative. */
|
||||
subq $sp, 32, $sp
|
||||
stq $23, 0($sp)
|
||||
stq $24, 8($sp)
|
||||
stq $25, 16($sp)
|
||||
|
||||
/* Compute absolute values. */
|
||||
subq $31, $24, $28
|
||||
cmovlt $24, $28, $24
|
||||
subq $31, $25, $28
|
||||
cmovlt $25, $28, $25
|
||||
|
||||
bsr $23, __divqu
|
||||
|
||||
ldq $24, 8($sp)
|
||||
ldq $25, 16($sp)
|
||||
|
||||
/* -a / b = a / -b = -(a / b) */
|
||||
subq $31, $27, $23
|
||||
xor $24, $25, $28
|
||||
cmovlt $28, $23, $27
|
||||
|
||||
ldq $23, 0($sp)
|
||||
addq $sp, 32, $sp
|
||||
ret $31, ($23), 1
|
||||
.end __divqs
|
||||
|
||||
/*
|
||||
* Signed 64-bit remainder.
|
||||
*/
|
||||
|
||||
.globl __remqs
|
||||
.ent __remqs
|
||||
__remqs:
|
||||
.prologue 0
|
||||
|
||||
/* Common case: both arguments are positive. */
|
||||
bis $24, $25, $28
|
||||
bge $28, __remqu
|
||||
|
||||
/* At least one argument is negative. */
|
||||
subq $sp, 32, $sp
|
||||
stq $23, 0($sp)
|
||||
stq $24, 8($sp)
|
||||
stq $25, 16($sp)
|
||||
|
||||
/* Compute absolute values. */
|
||||
subq $31, $24, $28
|
||||
cmovlt $24, $28, $24
|
||||
subq $31, $25, $28
|
||||
cmovlt $25, $28, $25
|
||||
|
||||
bsr $23, __divqu
|
||||
|
||||
ldq $23, 0($sp)
|
||||
ldq $24, 8($sp)
|
||||
ldq $25, 16($sp)
|
||||
|
||||
/* -a % b = -(a % b); a % -b = a % b. */
|
||||
subq $31, $28, $27
|
||||
cmovge $24, $28, $27
|
||||
|
||||
addq $sp, 32, $sp
|
||||
ret $31, ($23), 1
|
||||
.end __remqs
|
||||
|
||||
/*
|
||||
* Unsigned 32-bit division.
|
||||
*/
|
||||
|
||||
.globl __divlu
|
||||
.ent __divlu
|
||||
__divlu:
|
||||
.frame $sp, 32, $23
|
||||
subq $sp, 32, $sp
|
||||
stq $23, 0($sp)
|
||||
stq $24, 8($sp)
|
||||
stq $25, 16($sp)
|
||||
.prologue 0
|
||||
|
||||
/* Zero extend and use the 64-bit routine. */
|
||||
zap $24, 0xf0, $24
|
||||
zap $25, 0xf0, $25
|
||||
bsr $23, __divqu
|
||||
|
||||
addl $27, 0, $27
|
||||
ldq $23, 0($sp)
|
||||
ldq $24, 8($sp)
|
||||
ldq $25, 16($sp)
|
||||
addq $sp, 32, $sp
|
||||
ret $31, ($23), 1
|
||||
.end __divlu
|
||||
|
||||
/*
|
||||
* Unsigned 32-bit remainder.
|
||||
*/
|
||||
|
||||
.globl __remlu
|
||||
.ent __remlu
|
||||
__remlu:
|
||||
.frame $sp, 32, $23
|
||||
subq $sp, 32, $sp
|
||||
stq $23, 0($sp)
|
||||
stq $24, 8($sp)
|
||||
stq $25, 16($sp)
|
||||
.prologue 0
|
||||
|
||||
/* Zero extend and use the 64-bit routine. */
|
||||
zap $24, 0xf0, $24
|
||||
zap $25, 0xf0, $25
|
||||
bsr $23, __divqu
|
||||
|
||||
/* Recall that the remainder is returned in $28. */
|
||||
addl $28, 0, $27
|
||||
ldq $23, 0($sp)
|
||||
ldq $24, 8($sp)
|
||||
ldq $25, 16($sp)
|
||||
addq $sp, 32, $sp
|
||||
ret $31, ($23), 1
|
||||
.end __remlu
|
||||
|
||||
/*
|
||||
* Signed 32-bit division.
|
||||
*/
|
||||
|
||||
.globl __divls
|
||||
.ent __divls
|
||||
__divls:
|
||||
.frame $sp, 32, $23
|
||||
subq $sp, 32, $sp
|
||||
stq $23, 0($sp)
|
||||
stq $24, 8($sp)
|
||||
stq $25, 16($sp)
|
||||
.prologue 0
|
||||
|
||||
/* Sign extend. */
|
||||
addl $24, 0, $24
|
||||
addl $25, 0, $25
|
||||
|
||||
/* Compute absolute values. */
|
||||
subq $31, $24, $28
|
||||
cmovlt $24, $28, $24
|
||||
subq $31, $25, $28
|
||||
cmovlt $25, $28, $25
|
||||
|
||||
bsr $23, __divqu
|
||||
|
||||
ldq $24, 8($sp)
|
||||
ldq $25, 16($sp)
|
||||
|
||||
/* Negate the unsigned result, if necessary. */
|
||||
xor $24, $25, $28
|
||||
subl $31, $27, $23
|
||||
addl $27, 0, $27
|
||||
addl $28, 0, $28
|
||||
cmovlt $28, $23, $27
|
||||
|
||||
ldq $23, 0($sp)
|
||||
addq $sp, 32, $sp
|
||||
ret $31, ($23), 1
|
||||
.end __divls
|
||||
|
||||
/*
|
||||
* Signed 32-bit remainder.
|
||||
*/
|
||||
|
||||
.globl __remls
|
||||
.ent __remls
|
||||
__remls:
|
||||
.frame $sp, 32, $23
|
||||
subq $sp, 32, $sp
|
||||
stq $23, 0($sp)
|
||||
stq $24, 8($sp)
|
||||
stq $25, 16($sp)
|
||||
.prologue 0
|
||||
|
||||
/* Sign extend. */
|
||||
addl $24, 0, $24
|
||||
addl $25, 0, $25
|
||||
|
||||
/* Compute absolute values. */
|
||||
subq $31, $24, $28
|
||||
cmovlt $24, $28, $24
|
||||
subq $31, $25, $28
|
||||
cmovlt $25, $28, $25
|
||||
|
||||
bsr $23, __divqu
|
||||
|
||||
ldq $23, 0($sp)
|
||||
ldq $24, 8($sp)
|
||||
ldq $25, 16($sp)
|
||||
|
||||
/* Negate the unsigned result, if necessary. */
|
||||
subl $31, $28, $27
|
||||
addl $28, 0, $28
|
||||
cmovge $24, $28, $27
|
||||
|
||||
addq $sp, 32, $sp
|
||||
ret $31, ($23), 1
|
||||
.end __remls
|
||||
|
||||
.data
|
||||
.p2align 4
|
||||
stack:
|
||||
.skip 65536
|
||||
$stack_end:
|
||||
.type stack,@object
|
||||
.size stack, . - stack
|
30
tests/tcg/alpha/system/kernel.ld
Normal file
30
tests/tcg/alpha/system/kernel.ld
Normal file
@ -0,0 +1,30 @@
|
||||
ENTRY(_start)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/* Linux kernel legacy start address. */
|
||||
. = 0xfffffc0000310000;
|
||||
_text = .;
|
||||
.text : {
|
||||
*(.text)
|
||||
}
|
||||
.rodata : {
|
||||
*(.rodata)
|
||||
}
|
||||
_etext = .;
|
||||
|
||||
. = ALIGN(8192);
|
||||
_data = .;
|
||||
.got : {
|
||||
*(.got)
|
||||
}
|
||||
.data : {
|
||||
*(.sdata)
|
||||
*(.data)
|
||||
}
|
||||
_edata = .;
|
||||
.bss : {
|
||||
*(.bss)
|
||||
}
|
||||
_end = .;
|
||||
}
|
@ -27,7 +27,7 @@ CFLAGS+=-m32
|
||||
LINK_SCRIPT=$(I386_SYSTEM_SRC)/kernel.ld
|
||||
LDFLAGS=-Wl,-T$(LINK_SCRIPT) -Wl,-melf_i386
|
||||
# FIXME: move to common once x86_64 is bootstrapped
|
||||
TESTS+=$(X86_TESTS)
|
||||
TESTS+=$(X86_TESTS) $(MULTIARCH_TESTS)
|
||||
endif
|
||||
CFLAGS+=-nostdlib -ggdb -O0 $(MINILIB_INC)
|
||||
LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc
|
||||
@ -42,5 +42,7 @@ LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc
|
||||
%: %.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS)
|
||||
$(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)
|
||||
|
||||
memory: CFLAGS+=-DCHECK_UNALIGNED=1
|
||||
|
||||
# Running
|
||||
QEMU_OPTS+=-device isa-debugcon,chardev=output -device isa-debug-exit,iobase=0xf4,iosize=0x4 -kernel
|
||||
|
@ -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*);
|
||||
print_str(str);
|
||||
break;
|
||||
case 'c':
|
||||
__sys_outc(va_arg(ap, int));
|
||||
break;
|
||||
case '%':
|
||||
__sys_outc(*fmt);
|
||||
break;
|
||||
|
14
tests/tcg/multiarch/system/Makefile.softmmu-target
Normal file
14
tests/tcg/multiarch/system/Makefile.softmmu-target
Normal file
@ -0,0 +1,14 @@
|
||||
# -*- Mode: makefile -*-
|
||||
#
|
||||
# Multiarch system tests
|
||||
#
|
||||
# We just collect the tests together here and rely on the actual guest
|
||||
# architecture to add to the test dependancies and deal with the
|
||||
# complications of building.
|
||||
#
|
||||
|
||||
MULTIARCH_SYSTEM_SRC=$(SRC_PATH)/tests/tcg/multiarch/system
|
||||
VPATH+=$(MULTIARCH_SYSTEM_SRC)
|
||||
|
||||
MULTIARCH_TEST_SRCS=$(wildcard $(MULTIARCH_SYSTEM_SRC)/*.c)
|
||||
MULTIARCH_TESTS = $(patsubst $(MULTIARCH_SYSTEM_SRC)/%.c, %, $(MULTIARCH_TEST_SRCS))
|
449
tests/tcg/multiarch/system/memory.c
Normal file
449
tests/tcg/multiarch/system/memory.c
Normal file
@ -0,0 +1,449 @@
|
||||
/*
|
||||
* Memory Test
|
||||
*
|
||||
* This is intended to test the softmmu code and ensure we properly
|
||||
* behave across normal and unaligned accesses across several pages.
|
||||
* We are not replicating memory tests for stuck bits and other
|
||||
* hardware level failures but looking for issues with different size
|
||||
* accesses when access is:
|
||||
*
|
||||
* - unaligned at various sizes (if -DCHECK_UNALIGNED set)
|
||||
* - spanning a (softmmu) page
|
||||
* - sign extension when loading
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <minilib.h>
|
||||
|
||||
#ifndef CHECK_UNALIGNED
|
||||
# error "Target does not specify CHECK_UNALIGNED"
|
||||
#endif
|
||||
|
||||
#define PAGE_SIZE 4096 /* nominal 4k "pages" */
|
||||
#define TEST_SIZE (PAGE_SIZE * 4) /* 4 pages */
|
||||
|
||||
#define ARRAY_SIZE(x) ((sizeof(x) / sizeof((x)[0])))
|
||||
|
||||
__attribute__((aligned(PAGE_SIZE)))
|
||||
static uint8_t test_data[TEST_SIZE];
|
||||
|
||||
typedef void (*init_ufn) (int offset);
|
||||
typedef bool (*read_ufn) (int offset);
|
||||
typedef bool (*read_sfn) (int offset, bool nf);
|
||||
|
||||
static void pdot(int count)
|
||||
{
|
||||
if (count % 128 == 0) {
|
||||
ml_printf(".");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper macros for shift/extract so we can keep our endian handling
|
||||
* in one place.
|
||||
*/
|
||||
#define BYTE_SHIFT(b, pos) ((uint64_t)b << (pos * 8))
|
||||
#define BYTE_EXTRACT(b, pos) ((b >> (pos * 8)) & 0xff)
|
||||
|
||||
/*
|
||||
* Fill the data with ascending value bytes.
|
||||
*
|
||||
* Currently we only support Little Endian machines so write in
|
||||
* ascending address order. When we read higher address bytes should
|
||||
* either be zero or higher than the lower bytes.
|
||||
*/
|
||||
|
||||
static void init_test_data_u8(int unused_offset)
|
||||
{
|
||||
uint8_t count = 0, *ptr = &test_data[0];
|
||||
int i;
|
||||
(void)(unused_offset);
|
||||
|
||||
ml_printf("Filling test area with u8:");
|
||||
for (i = 0; i < TEST_SIZE; i++) {
|
||||
*ptr++ = count++;
|
||||
pdot(i);
|
||||
}
|
||||
ml_printf("done\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Full the data with alternating positive and negative bytes. This
|
||||
* should mean for reads larger than a byte all subsequent reads will
|
||||
* stay either negative or positive. We never write 0.
|
||||
*/
|
||||
|
||||
static inline uint8_t get_byte(int index, bool neg)
|
||||
{
|
||||
return neg ? (0xff << (index % 7)) : (0xff >> ((index % 6) + 1));
|
||||
}
|
||||
|
||||
static void init_test_data_s8(bool neg_first)
|
||||
{
|
||||
uint8_t top, bottom, *ptr = &test_data[0];
|
||||
int i;
|
||||
|
||||
ml_printf("Filling test area with s8 pairs (%s):",
|
||||
neg_first ? "neg first" : "pos first");
|
||||
for (i = 0; i < TEST_SIZE / 2; i++) {
|
||||
*ptr++ = get_byte(i, neg_first);
|
||||
*ptr++ = get_byte(i, !neg_first);
|
||||
pdot(i);
|
||||
}
|
||||
ml_printf("done\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Zero the first few bytes of the test data in preparation for
|
||||
* new offset values.
|
||||
*/
|
||||
static void reset_start_data(int offset)
|
||||
{
|
||||
uint32_t *ptr = (uint32_t *) &test_data[0];
|
||||
int i;
|
||||
for (i = 0; i < offset; i++) {
|
||||
*ptr++ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void init_test_data_u16(int offset)
|
||||
{
|
||||
uint8_t count = 0;
|
||||
uint16_t word, *ptr = (uint16_t *) &test_data[offset];
|
||||
const int max = (TEST_SIZE - offset) / sizeof(word);
|
||||
int i;
|
||||
|
||||
ml_printf("Filling test area with u16 (offset %d, %p):", offset, ptr);
|
||||
|
||||
reset_start_data(offset);
|
||||
|
||||
for (i = 0; i < max; i++) {
|
||||
uint8_t low = count++, high = count++;
|
||||
word = BYTE_SHIFT(high, 1) | BYTE_SHIFT(low, 0);
|
||||
*ptr++ = word;
|
||||
pdot(i);
|
||||
}
|
||||
ml_printf("done @ %p\n", ptr);
|
||||
}
|
||||
|
||||
static void init_test_data_u32(int offset)
|
||||
{
|
||||
uint8_t count = 0;
|
||||
uint32_t word, *ptr = (uint32_t *) &test_data[offset];
|
||||
const int max = (TEST_SIZE - offset) / sizeof(word);
|
||||
int i;
|
||||
|
||||
ml_printf("Filling test area with u32 (offset %d, %p):", offset, ptr);
|
||||
|
||||
reset_start_data(offset);
|
||||
|
||||
for (i = 0; i < max; i++) {
|
||||
uint8_t b4 = count++, b3 = count++;
|
||||
uint8_t b2 = count++, b1 = count++;
|
||||
word = BYTE_SHIFT(b1, 3) | BYTE_SHIFT(b2, 2) | BYTE_SHIFT(b3, 1) | b4;
|
||||
*ptr++ = word;
|
||||
pdot(i);
|
||||
}
|
||||
ml_printf("done @ %p\n", ptr);
|
||||
}
|
||||
|
||||
static void init_test_data_u64(int offset)
|
||||
{
|
||||
uint8_t count = 0;
|
||||
uint64_t word, *ptr = (uint64_t *) &test_data[offset];
|
||||
const int max = (TEST_SIZE - offset) / sizeof(word);
|
||||
int i;
|
||||
|
||||
ml_printf("Filling test area with u64 (offset %d, %p):", offset, ptr);
|
||||
|
||||
reset_start_data(offset);
|
||||
|
||||
for (i = 0; i < max; i++) {
|
||||
uint8_t b8 = count++, b7 = count++;
|
||||
uint8_t b6 = count++, b5 = count++;
|
||||
uint8_t b4 = count++, b3 = count++;
|
||||
uint8_t b2 = count++, b1 = count++;
|
||||
word = BYTE_SHIFT(b1, 7) | BYTE_SHIFT(b2, 6) | BYTE_SHIFT(b3, 5) |
|
||||
BYTE_SHIFT(b4, 4) | BYTE_SHIFT(b5, 3) | BYTE_SHIFT(b6, 2) |
|
||||
BYTE_SHIFT(b7, 1) | b8;
|
||||
*ptr++ = word;
|
||||
pdot(i);
|
||||
}
|
||||
ml_printf("done @ %p\n", ptr);
|
||||
}
|
||||
|
||||
static bool read_test_data_u16(int offset)
|
||||
{
|
||||
uint16_t word, *ptr = (uint16_t *)&test_data[offset];
|
||||
int i;
|
||||
const int max = (TEST_SIZE - offset) / sizeof(word);
|
||||
|
||||
ml_printf("Reading u16 from %#lx (offset %d):", ptr, offset);
|
||||
|
||||
for (i = 0; i < max; i++) {
|
||||
uint8_t high, low;
|
||||
word = *ptr++;
|
||||
high = (word >> 8) & 0xff;
|
||||
low = word & 0xff;
|
||||
if (high < low && high != 0) {
|
||||
ml_printf("Error %d < %d\n", high, low);
|
||||
return false;
|
||||
} else {
|
||||
pdot(i);
|
||||
}
|
||||
|
||||
}
|
||||
ml_printf("done @ %p\n", ptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool read_test_data_u32(int offset)
|
||||
{
|
||||
uint32_t word, *ptr = (uint32_t *)&test_data[offset];
|
||||
int i;
|
||||
const int max = (TEST_SIZE - offset) / sizeof(word);
|
||||
|
||||
ml_printf("Reading u32 from %#lx (offset %d):", ptr, offset);
|
||||
|
||||
for (i = 0; i < max; i++) {
|
||||
uint8_t b1, b2, b3, b4;
|
||||
word = *ptr++;
|
||||
|
||||
b1 = word >> 24 & 0xff;
|
||||
b2 = word >> 16 & 0xff;
|
||||
b3 = word >> 8 & 0xff;
|
||||
b4 = word & 0xff;
|
||||
|
||||
if ((b1 < b2 && b1 != 0) ||
|
||||
(b2 < b3 && b2 != 0) ||
|
||||
(b3 < b4 && b3 != 0)) {
|
||||
ml_printf("Error %d, %d, %d, %d", b1, b2, b3, b4);
|
||||
return false;
|
||||
} else {
|
||||
pdot(i);
|
||||
}
|
||||
}
|
||||
ml_printf("done @ %p\n", ptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool read_test_data_u64(int offset)
|
||||
{
|
||||
uint64_t word, *ptr = (uint64_t *)&test_data[offset];
|
||||
int i;
|
||||
const int max = (TEST_SIZE - offset) / sizeof(word);
|
||||
|
||||
ml_printf("Reading u64 from %#lx (offset %d):", ptr, offset);
|
||||
|
||||
for (i = 0; i < max; i++) {
|
||||
uint8_t b1, b2, b3, b4, b5, b6, b7, b8;
|
||||
word = *ptr++;
|
||||
|
||||
b1 = ((uint64_t) (word >> 56)) & 0xff;
|
||||
b2 = ((uint64_t) (word >> 48)) & 0xff;
|
||||
b3 = ((uint64_t) (word >> 40)) & 0xff;
|
||||
b4 = (word >> 32) & 0xff;
|
||||
b5 = (word >> 24) & 0xff;
|
||||
b6 = (word >> 16) & 0xff;
|
||||
b7 = (word >> 8) & 0xff;
|
||||
b8 = (word >> 0) & 0xff;
|
||||
|
||||
if ((b1 < b2 && b1 != 0) ||
|
||||
(b2 < b3 && b2 != 0) ||
|
||||
(b3 < b4 && b3 != 0) ||
|
||||
(b4 < b5 && b4 != 0) ||
|
||||
(b5 < b6 && b5 != 0) ||
|
||||
(b6 < b7 && b6 != 0) ||
|
||||
(b7 < b8 && b7 != 0)) {
|
||||
ml_printf("Error %d, %d, %d, %d, %d, %d, %d, %d",
|
||||
b1, b2, b3, b4, b5, b6, b7, b8);
|
||||
return false;
|
||||
} else {
|
||||
pdot(i);
|
||||
}
|
||||
}
|
||||
ml_printf("done @ %p\n", ptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Read the test data and verify at various offsets */
|
||||
read_ufn read_ufns[] = { read_test_data_u16,
|
||||
read_test_data_u32,
|
||||
read_test_data_u64 };
|
||||
|
||||
bool do_unsigned_reads(void)
|
||||
{
|
||||
int i;
|
||||
bool ok = true;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(read_ufns) && ok; i++) {
|
||||
#if CHECK_UNALIGNED
|
||||
int off;
|
||||
for (off = 0; off < 8 && ok; off++) {
|
||||
ok = read_ufns[i](off);
|
||||
}
|
||||
#else
|
||||
ok = read_ufns[i](0);
|
||||
#endif
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static bool do_unsigned_test(init_ufn fn)
|
||||
{
|
||||
#if CHECK_UNALIGNED
|
||||
bool ok = true;
|
||||
int i;
|
||||
for (i = 0; i < 8 && ok; i++) {
|
||||
fn(i);
|
||||
ok = do_unsigned_reads();
|
||||
}
|
||||
#else
|
||||
fn(0);
|
||||
return do_unsigned_reads();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to ensure signed data is read into a larger data type to
|
||||
* ensure that sign extension is working properly.
|
||||
*/
|
||||
|
||||
static bool read_test_data_s8(int offset, bool neg_first)
|
||||
{
|
||||
int8_t *ptr = (int8_t *)&test_data[offset];
|
||||
int i;
|
||||
const int max = (TEST_SIZE - offset) / 2;
|
||||
|
||||
ml_printf("Reading s8 pairs from %#lx (offset %d):", ptr, offset);
|
||||
|
||||
for (i = 0; i < max; i++) {
|
||||
int16_t first, second;
|
||||
bool ok;
|
||||
first = *ptr++;
|
||||
second = *ptr++;
|
||||
|
||||
if (neg_first && first < 0 && second > 0) {
|
||||
pdot(i);
|
||||
} else if (!neg_first && first > 0 && second < 0) {
|
||||
pdot(i);
|
||||
} else {
|
||||
ml_printf("Error %d %c %d\n", first, neg_first ? '<' : '>', second);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
ml_printf("done @ %p\n", ptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool read_test_data_s16(int offset, bool neg_first)
|
||||
{
|
||||
int16_t *ptr = (int16_t *)&test_data[offset];
|
||||
int i;
|
||||
const int max = (TEST_SIZE - offset) / (sizeof(*ptr));
|
||||
|
||||
ml_printf("Reading s16 from %#lx (offset %d, %s):", ptr,
|
||||
offset, neg_first ? "neg" : "pos");
|
||||
|
||||
for (i = 0; i < max; i++) {
|
||||
int32_t data = *ptr++;
|
||||
|
||||
if (neg_first && data < 0) {
|
||||
pdot(i);
|
||||
} else if (data > 0) {
|
||||
pdot(i);
|
||||
} else {
|
||||
ml_printf("Error %d %c 0\n", data, neg_first ? '<' : '>');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
ml_printf("done @ %p\n", ptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool read_test_data_s32(int offset, bool neg_first)
|
||||
{
|
||||
int32_t *ptr = (int32_t *)&test_data[offset];
|
||||
int i;
|
||||
const int max = (TEST_SIZE - offset) / (sizeof(int32_t));
|
||||
|
||||
ml_printf("Reading s32 from %#lx (offset %d, %s):",
|
||||
ptr, offset, neg_first ? "neg" : "pos");
|
||||
|
||||
for (i = 0; i < max; i++) {
|
||||
int64_t data = *ptr++;
|
||||
|
||||
if (neg_first && data < 0) {
|
||||
pdot(i);
|
||||
} else if (data > 0) {
|
||||
pdot(i);
|
||||
} else {
|
||||
ml_printf("Error %d %c 0\n", data, neg_first ? '<' : '>');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
ml_printf("done @ %p\n", ptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the test data and verify at various offsets
|
||||
*
|
||||
* For everything except bytes all our reads should be either positive
|
||||
* or negative depending on what offset we are reading from. Currently
|
||||
* we only handle LE systems.
|
||||
*/
|
||||
read_sfn read_sfns[] = { read_test_data_s8,
|
||||
read_test_data_s16,
|
||||
read_test_data_s32 };
|
||||
|
||||
bool do_signed_reads(bool neg_first)
|
||||
{
|
||||
int i;
|
||||
bool ok = true;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(read_sfns) && ok; i++) {
|
||||
#if CHECK_UNALIGNED
|
||||
int off;
|
||||
for (off = 0; off < 8 && ok; off++) {
|
||||
bool nf = i == 0 ? neg_first ^ (off & 1) : !(neg_first ^ (off & 1));
|
||||
ok = read_sfns[i](off, nf);
|
||||
}
|
||||
#else
|
||||
ok = read_sfns[i](0, i == 0 ? neg_first : !neg_first);
|
||||
#endif
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
init_ufn init_ufns[] = { init_test_data_u8,
|
||||
init_test_data_u16,
|
||||
init_test_data_u32,
|
||||
init_test_data_u64 };
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int i;
|
||||
bool ok = true;
|
||||
|
||||
/* Run through the unsigned tests first */
|
||||
for (i = 0; i < ARRAY_SIZE(init_ufns) && ok; i++) {
|
||||
ok = do_unsigned_test(init_ufns[i]);
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
init_test_data_s8(false);
|
||||
ok = do_signed_reads(false);
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
init_test_data_s8(true);
|
||||
ok = do_signed_reads(true);
|
||||
}
|
||||
|
||||
ml_printf("Test complete: %s\n", ok ? "PASSED" : "FAILED");
|
||||
return ok ? 0 : -1;
|
||||
}
|
128
vl.c
128
vl.c
@ -116,7 +116,7 @@ int main(int argc, char **argv)
|
||||
#include "qapi/opts-visitor.h"
|
||||
#include "qapi/clone-visitor.h"
|
||||
#include "qom/object_interfaces.h"
|
||||
#include "exec/semihost.h"
|
||||
#include "hw/semihosting/semihost.h"
|
||||
#include "crypto/init.h"
|
||||
#include "sysemu/replay.h"
|
||||
#include "qapi/qapi-events-run-state.h"
|
||||
@ -501,25 +501,6 @@ static QemuOptsList qemu_icount_opts = {
|
||||
},
|
||||
};
|
||||
|
||||
static QemuOptsList qemu_semihosting_config_opts = {
|
||||
.name = "semihosting-config",
|
||||
.implied_opt_name = "enable",
|
||||
.head = QTAILQ_HEAD_INITIALIZER(qemu_semihosting_config_opts.head),
|
||||
.desc = {
|
||||
{
|
||||
.name = "enable",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
}, {
|
||||
.name = "target",
|
||||
.type = QEMU_OPT_STRING,
|
||||
}, {
|
||||
.name = "arg",
|
||||
.type = QEMU_OPT_STRING,
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
|
||||
static QemuOptsList qemu_fw_cfg_opts = {
|
||||
.name = "fw_cfg",
|
||||
.implied_opt_name = "name",
|
||||
@ -1351,80 +1332,6 @@ static void configure_msg(QemuOpts *opts)
|
||||
enable_timestamp_msg = qemu_opt_get_bool(opts, "timestamp", true);
|
||||
}
|
||||
|
||||
/***********************************************************/
|
||||
/* Semihosting */
|
||||
|
||||
typedef struct SemihostingConfig {
|
||||
bool enabled;
|
||||
SemihostingTarget target;
|
||||
const char **argv;
|
||||
int argc;
|
||||
const char *cmdline; /* concatenated argv */
|
||||
} SemihostingConfig;
|
||||
|
||||
static SemihostingConfig semihosting;
|
||||
|
||||
bool semihosting_enabled(void)
|
||||
{
|
||||
return semihosting.enabled;
|
||||
}
|
||||
|
||||
SemihostingTarget semihosting_get_target(void)
|
||||
{
|
||||
return semihosting.target;
|
||||
}
|
||||
|
||||
const char *semihosting_get_arg(int i)
|
||||
{
|
||||
if (i >= semihosting.argc) {
|
||||
return NULL;
|
||||
}
|
||||
return semihosting.argv[i];
|
||||
}
|
||||
|
||||
int semihosting_get_argc(void)
|
||||
{
|
||||
return semihosting.argc;
|
||||
}
|
||||
|
||||
const char *semihosting_get_cmdline(void)
|
||||
{
|
||||
if (semihosting.cmdline == NULL && semihosting.argc > 0) {
|
||||
semihosting.cmdline = g_strjoinv(" ", (gchar **)semihosting.argv);
|
||||
}
|
||||
return semihosting.cmdline;
|
||||
}
|
||||
|
||||
static int add_semihosting_arg(void *opaque,
|
||||
const char *name, const char *val,
|
||||
Error **errp)
|
||||
{
|
||||
SemihostingConfig *s = opaque;
|
||||
if (strcmp(name, "arg") == 0) {
|
||||
s->argc++;
|
||||
/* one extra element as g_strjoinv() expects NULL-terminated array */
|
||||
s->argv = g_realloc(s->argv, (s->argc + 1) * sizeof(void *));
|
||||
s->argv[s->argc - 1] = val;
|
||||
s->argv[s->argc] = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Use strings passed via -kernel/-append to initialize semihosting.argv[] */
|
||||
static inline void semihosting_arg_fallback(const char *file, const char *cmd)
|
||||
{
|
||||
char *cmd_token;
|
||||
|
||||
/* argv[0] */
|
||||
add_semihosting_arg(&semihosting, "arg", file, NULL);
|
||||
|
||||
/* split -append and initialize argv[1..n] */
|
||||
cmd_token = strtok(g_strdup(cmd), " ");
|
||||
while (cmd_token) {
|
||||
add_semihosting_arg(&semihosting, "arg", cmd_token, NULL);
|
||||
cmd_token = strtok(NULL, " ");
|
||||
}
|
||||
}
|
||||
|
||||
/* Now we still need this for compatibility with XEN. */
|
||||
bool has_igd_gfx_passthru;
|
||||
@ -3743,37 +3650,10 @@ int main(int argc, char **argv, char **envp)
|
||||
nb_option_roms++;
|
||||
break;
|
||||
case QEMU_OPTION_semihosting:
|
||||
semihosting.enabled = true;
|
||||
semihosting.target = SEMIHOSTING_TARGET_AUTO;
|
||||
qemu_semihosting_enable();
|
||||
break;
|
||||
case QEMU_OPTION_semihosting_config:
|
||||
semihosting.enabled = true;
|
||||
opts = qemu_opts_parse_noisily(qemu_find_opts("semihosting-config"),
|
||||
optarg, false);
|
||||
if (opts != NULL) {
|
||||
semihosting.enabled = qemu_opt_get_bool(opts, "enable",
|
||||
true);
|
||||
const char *target = qemu_opt_get(opts, "target");
|
||||
if (target != NULL) {
|
||||
if (strcmp("native", target) == 0) {
|
||||
semihosting.target = SEMIHOSTING_TARGET_NATIVE;
|
||||
} else if (strcmp("gdb", target) == 0) {
|
||||
semihosting.target = SEMIHOSTING_TARGET_GDB;
|
||||
} else if (strcmp("auto", target) == 0) {
|
||||
semihosting.target = SEMIHOSTING_TARGET_AUTO;
|
||||
} else {
|
||||
error_report("unsupported semihosting-config %s",
|
||||
optarg);
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
semihosting.target = SEMIHOSTING_TARGET_AUTO;
|
||||
}
|
||||
/* Set semihosting argument count and vector */
|
||||
qemu_opt_foreach(opts, add_semihosting_arg,
|
||||
&semihosting, NULL);
|
||||
} else {
|
||||
error_report("unsupported semihosting-config %s", optarg);
|
||||
if (qemu_semihosting_config_options(optarg) != 0) {
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
@ -4290,6 +4170,8 @@ int main(int argc, char **argv, char **envp)
|
||||
|
||||
qemu_opts_foreach(qemu_find_opts("chardev"),
|
||||
chardev_init_func, NULL, &error_fatal);
|
||||
/* now chardevs have been created we may have semihosting to connect */
|
||||
qemu_semihosting_connect_chardevs();
|
||||
|
||||
#ifdef CONFIG_VIRTFS
|
||||
qemu_opts_foreach(qemu_find_opts("fsdev"),
|
||||
|
Loading…
x
Reference in New Issue
Block a user