mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-11 03:24:58 -06:00
maintainer updates for May (testing, plugins)
- expose ~/.cache/qemu to container builds - disable debug info in CI - allow boot.S to handle target el mode selection - new arguments for ips plugin - cleanup assets in size_memop - fix include guard in gdbstub - introduce qGDBServerVersion gdbstub query - update gdb aarch64-core.xml to support bitfields -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEZoWumedRZ7yvyN81+9DbCVqeKkQFAmhEXc4ACgkQ+9DbCVqe KkT3vwf9GtMoVDBWqWHwdV6H3rblP0k3mkApY4pTkFFSL93qApDK1gAKoklymPHJ 6agAWn/MmpqguB7yn7TnBEiJyW9CEq0DeWTz9ivPPh5vfm/2MMaXinVd4yH+GbTL uTuJg4EeRcSj8q4N4h+gROSHkH3mVOe+JlyakRKZ/PZChqjY1WRC/Hm2QdHojxlS xQBZe4Nip/mafm4yAlnyRVRbaSctmc3/xE/MomkVT+8JMdVt6yWE0HT/nIEFW6/6 psHoiV4XfROIWj5qMAWHVLekDrsqxJx8uiGv9o3+zKdhDhRZw3Oa5EE5N/oE8KmM 0s/9usRvtVD0kPh9YTfjEHWHkbPadA== =X63M -----END PGP SIGNATURE----- Merge tag 'pull-10.1-maintainer-may-2025-070625-1' of https://gitlab.com/stsquad/qemu into staging maintainer updates for May (testing, plugins) - expose ~/.cache/qemu to container builds - disable debug info in CI - allow boot.S to handle target el mode selection - new arguments for ips plugin - cleanup assets in size_memop - fix include guard in gdbstub - introduce qGDBServerVersion gdbstub query - update gdb aarch64-core.xml to support bitfields # -----BEGIN PGP SIGNATURE----- # # iQEzBAABCgAdFiEEZoWumedRZ7yvyN81+9DbCVqeKkQFAmhEXc4ACgkQ+9DbCVqe # KkT3vwf9GtMoVDBWqWHwdV6H3rblP0k3mkApY4pTkFFSL93qApDK1gAKoklymPHJ # 6agAWn/MmpqguB7yn7TnBEiJyW9CEq0DeWTz9ivPPh5vfm/2MMaXinVd4yH+GbTL # uTuJg4EeRcSj8q4N4h+gROSHkH3mVOe+JlyakRKZ/PZChqjY1WRC/Hm2QdHojxlS # xQBZe4Nip/mafm4yAlnyRVRbaSctmc3/xE/MomkVT+8JMdVt6yWE0HT/nIEFW6/6 # psHoiV4XfROIWj5qMAWHVLekDrsqxJx8uiGv9o3+zKdhDhRZw3Oa5EE5N/oE8KmM # 0s/9usRvtVD0kPh9YTfjEHWHkbPadA== # =X63M # -----END PGP SIGNATURE----- # gpg: Signature made Sat 07 Jun 2025 11:42:06 EDT # gpg: using RSA key 6685AE99E75167BCAFC8DF35FBD0DB095A9E2A44 # gpg: Good signature from "Alex Bennée (Master Work Key) <alex.bennee@linaro.org>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 6685 AE99 E751 67BC AFC8 DF35 FBD0 DB09 5A9E 2A44 * tag 'pull-10.1-maintainer-may-2025-070625-1' of https://gitlab.com/stsquad/qemu: gdbstub: update aarch64-core.xml gdbstub: Implement qGDBServerVersion packet gdbstub: assert earlier in handle_read_all_regs include/gdbstub: fix include guard in commands.h include/exec: fix assert in size_memop contrib/plugins: allow setting of instructions per quantum contrib/plugins: add a scaling factor to the ips arg tests/qtest: Avoid unaligned access in IGB test tests/tcg: make aarch64 boot.S handle different starting modes gitlab: disable debug info on CI builds tests/docker: expose $HOME/.cache/qemu as docker volume Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
commit
bc98ffdc75
11 changed files with 300 additions and 20 deletions
|
@ -24,6 +24,7 @@
|
||||||
- ccache --zero-stats
|
- ccache --zero-stats
|
||||||
- section_start configure "Running configure"
|
- section_start configure "Running configure"
|
||||||
- ../configure --enable-werror --disable-docs --enable-fdt=system
|
- ../configure --enable-werror --disable-docs --enable-fdt=system
|
||||||
|
--disable-debug-info
|
||||||
${TARGETS:+--target-list="$TARGETS"}
|
${TARGETS:+--target-list="$TARGETS"}
|
||||||
$CONFIGURE_ARGS ||
|
$CONFIGURE_ARGS ||
|
||||||
{ cat config.log meson-logs/meson-log.txt && exit 1; }
|
{ cat config.log meson-logs/meson-log.txt && exit 1; }
|
||||||
|
|
|
@ -129,20 +129,62 @@ static void plugin_exit(qemu_plugin_id_t id, void *udata)
|
||||||
qemu_plugin_scoreboard_free(vcpus);
|
qemu_plugin_scoreboard_free(vcpus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char *suffix;
|
||||||
|
unsigned long multipler;
|
||||||
|
} ScaleEntry;
|
||||||
|
|
||||||
|
/* a bit like units.h but not binary */
|
||||||
|
static const ScaleEntry scales[] = {
|
||||||
|
{ "k", 1000 },
|
||||||
|
{ "m", 1000 * 1000 },
|
||||||
|
{ "g", 1000 * 1000 * 1000 },
|
||||||
|
};
|
||||||
|
|
||||||
QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
|
QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
|
||||||
const qemu_info_t *info, int argc,
|
const qemu_info_t *info, int argc,
|
||||||
char **argv)
|
char **argv)
|
||||||
{
|
{
|
||||||
|
bool ipq_set = false;
|
||||||
|
|
||||||
for (int i = 0; i < argc; i++) {
|
for (int i = 0; i < argc; i++) {
|
||||||
char *opt = argv[i];
|
char *opt = argv[i];
|
||||||
g_auto(GStrv) tokens = g_strsplit(opt, "=", 2);
|
g_auto(GStrv) tokens = g_strsplit(opt, "=", 2);
|
||||||
if (g_strcmp0(tokens[0], "ips") == 0) {
|
if (g_strcmp0(tokens[0], "ips") == 0) {
|
||||||
max_insn_per_second = g_ascii_strtoull(tokens[1], NULL, 10);
|
char *endptr = NULL;
|
||||||
|
max_insn_per_second = g_ascii_strtoull(tokens[1], &endptr, 10);
|
||||||
if (!max_insn_per_second && errno) {
|
if (!max_insn_per_second && errno) {
|
||||||
fprintf(stderr, "%s: couldn't parse %s (%s)\n",
|
fprintf(stderr, "%s: couldn't parse %s (%s)\n",
|
||||||
__func__, tokens[1], g_strerror(errno));
|
__func__, tokens[1], g_strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (endptr && *endptr != 0) {
|
||||||
|
g_autofree gchar *lower = g_utf8_strdown(endptr, -1);
|
||||||
|
unsigned long scale = 0;
|
||||||
|
|
||||||
|
for (int j = 0; j < G_N_ELEMENTS(scales); j++) {
|
||||||
|
if (g_strcmp0(lower, scales[j].suffix) == 0) {
|
||||||
|
scale = scales[j].multipler;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scale) {
|
||||||
|
max_insn_per_second *= scale;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "bad suffix: %s\n", endptr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (g_strcmp0(tokens[0], "ipq") == 0) {
|
||||||
|
max_insn_per_quantum = g_ascii_strtoull(tokens[1], NULL, 10);
|
||||||
|
|
||||||
|
if (!max_insn_per_quantum) {
|
||||||
|
fprintf(stderr, "bad ipq value: %s\n", tokens[0]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ipq_set = true;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "option parsing failed: %s\n", opt);
|
fprintf(stderr, "option parsing failed: %s\n", opt);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -150,7 +192,10 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
|
||||||
}
|
}
|
||||||
|
|
||||||
vcpus = qemu_plugin_scoreboard_new(sizeof(vCPUTime));
|
vcpus = qemu_plugin_scoreboard_new(sizeof(vCPUTime));
|
||||||
|
|
||||||
|
if (!ipq_set) {
|
||||||
max_insn_per_quantum = max_insn_per_second / NUM_TIME_UPDATE_PER_SEC;
|
max_insn_per_quantum = max_insn_per_second / NUM_TIME_UPDATE_PER_SEC;
|
||||||
|
}
|
||||||
|
|
||||||
if (max_insn_per_quantum == 0) {
|
if (max_insn_per_quantum == 0) {
|
||||||
fprintf(stderr, "minimum of %d instructions per second needed\n",
|
fprintf(stderr, "minimum of %d instructions per second needed\n",
|
||||||
|
|
|
@ -811,6 +811,10 @@ This plugin can limit the number of Instructions Per Second that are executed::
|
||||||
* - ips=N
|
* - ips=N
|
||||||
- Maximum number of instructions per cpu that can be executed in one second.
|
- Maximum number of instructions per cpu that can be executed in one second.
|
||||||
The plugin will sleep when the given number of instructions is reached.
|
The plugin will sleep when the given number of instructions is reached.
|
||||||
|
* - ipq=N
|
||||||
|
- Instructions per quantum. How many instructions before we re-calculate time.
|
||||||
|
The lower the number the more accurate time will be, but the less efficient the plugin.
|
||||||
|
Defaults to ips/10
|
||||||
|
|
||||||
Other emulation features
|
Other emulation features
|
||||||
------------------------
|
------------------------
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<!-- Copyright (C) 2009-2012 Free Software Foundation, Inc.
|
<!-- Copyright (C) 2009-2025 Free Software Foundation, Inc.
|
||||||
Contributed by ARM Ltd.
|
Contributed by ARM Ltd.
|
||||||
|
|
||||||
Copying and distribution of this file, with or without modification,
|
Copying and distribution of this file, with or without modification,
|
||||||
|
@ -42,5 +42,53 @@
|
||||||
<reg name="sp" bitsize="64" type="data_ptr"/>
|
<reg name="sp" bitsize="64" type="data_ptr"/>
|
||||||
|
|
||||||
<reg name="pc" bitsize="64" type="code_ptr"/>
|
<reg name="pc" bitsize="64" type="code_ptr"/>
|
||||||
<reg name="cpsr" bitsize="32"/>
|
|
||||||
|
<flags id="cpsr_flags" size="4">
|
||||||
|
<!-- Stack Pointer. -->
|
||||||
|
<field name="SP" start="0" end="0"/>
|
||||||
|
|
||||||
|
<!-- Exception Level. -->
|
||||||
|
<field name="EL" start="2" end="3"/>
|
||||||
|
<!-- Execution state. -->
|
||||||
|
<field name="nRW" start="4" end="4"/>
|
||||||
|
|
||||||
|
<!-- FIQ interrupt mask. -->
|
||||||
|
<field name="F" start="6" end="6"/>
|
||||||
|
<!-- IRQ interrupt mask. -->
|
||||||
|
<field name="I" start="7" end="7"/>
|
||||||
|
<!-- SError interrupt mask. -->
|
||||||
|
<field name="A" start="8" end="8"/>
|
||||||
|
<!-- Debug exception mask. -->
|
||||||
|
<field name="D" start="9" end="9"/>
|
||||||
|
|
||||||
|
<!-- ARMv8.5-A: Branch Target Identification BTYPE. -->
|
||||||
|
<field name="BTYPE" start="10" end="11"/>
|
||||||
|
|
||||||
|
<!-- ARMv8.0-A: Speculative Store Bypass. -->
|
||||||
|
<field name="SSBS" start="12" end="12"/>
|
||||||
|
|
||||||
|
<!-- Illegal Execution state. -->
|
||||||
|
<field name="IL" start="20" end="20"/>
|
||||||
|
<!-- Software Step. -->
|
||||||
|
<field name="SS" start="21" end="21"/>
|
||||||
|
<!-- ARMv8.1-A: Privileged Access Never. -->
|
||||||
|
<field name="PAN" start="22" end="22"/>
|
||||||
|
<!-- ARMv8.2-A: User Access Override. -->
|
||||||
|
<field name="UAO" start="23" end="23"/>
|
||||||
|
<!-- ARMv8.4-A: Data Independent Timing. -->
|
||||||
|
<field name="DIT" start="24" end="24"/>
|
||||||
|
<!-- ARMv8.5-A: Tag Check Override. -->
|
||||||
|
<field name="TCO" start="25" end="25"/>
|
||||||
|
|
||||||
|
<!-- Overflow Condition flag. -->
|
||||||
|
<field name="V" start="28" end="28"/>
|
||||||
|
<!-- Carry Condition flag. -->
|
||||||
|
<field name="C" start="29" end="29"/>
|
||||||
|
<!-- Zero Condition flag. -->
|
||||||
|
<field name="Z" start="30" end="30"/>
|
||||||
|
<!-- Negative Condition flag. -->
|
||||||
|
<field name="N" start="31" end="31"/>
|
||||||
|
</flags>
|
||||||
|
<reg name="cpsr" bitsize="32" type="cpsr_flags"/>
|
||||||
|
|
||||||
</feature>
|
</feature>
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "qemu/cutils.h"
|
#include "qemu/cutils.h"
|
||||||
#include "qemu/module.h"
|
#include "qemu/module.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
|
#include "qemu/target-info.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
#include "exec/gdbstub.h"
|
#include "exec/gdbstub.h"
|
||||||
#include "gdbstub/commands.h"
|
#include "gdbstub/commands.h"
|
||||||
|
@ -1343,8 +1344,8 @@ static void handle_read_all_regs(GArray *params, void *user_ctx)
|
||||||
len += gdb_read_register(gdbserver_state.g_cpu,
|
len += gdb_read_register(gdbserver_state.g_cpu,
|
||||||
gdbserver_state.mem_buf,
|
gdbserver_state.mem_buf,
|
||||||
reg_id);
|
reg_id);
|
||||||
}
|
|
||||||
g_assert(len == gdbserver_state.mem_buf->len);
|
g_assert(len == gdbserver_state.mem_buf->len);
|
||||||
|
}
|
||||||
|
|
||||||
gdb_memtohex(gdbserver_state.str_buf, gdbserver_state.mem_buf->data, len);
|
gdb_memtohex(gdbserver_state.str_buf, gdbserver_state.mem_buf->data, len);
|
||||||
gdb_put_strbuf();
|
gdb_put_strbuf();
|
||||||
|
@ -1597,6 +1598,18 @@ static void handle_query_threads(GArray *params, void *user_ctx)
|
||||||
gdbserver_state.query_cpu = gdb_next_attached_cpu(gdbserver_state.query_cpu);
|
gdbserver_state.query_cpu = gdb_next_attached_cpu(gdbserver_state.query_cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_query_gdb_server_version(GArray *params, void *user_ctx)
|
||||||
|
{
|
||||||
|
#if defined(CONFIG_USER_ONLY)
|
||||||
|
g_string_printf(gdbserver_state.str_buf, "name:qemu-%s;version:%s;",
|
||||||
|
target_name(), QEMU_VERSION);
|
||||||
|
#else
|
||||||
|
g_string_printf(gdbserver_state.str_buf, "name:qemu-system-%s;version:%s;",
|
||||||
|
target_name(), QEMU_VERSION);
|
||||||
|
#endif
|
||||||
|
gdb_put_strbuf();
|
||||||
|
}
|
||||||
|
|
||||||
static void handle_query_first_threads(GArray *params, void *user_ctx)
|
static void handle_query_first_threads(GArray *params, void *user_ctx)
|
||||||
{
|
{
|
||||||
gdbserver_state.query_cpu = gdb_first_attached_cpu();
|
gdbserver_state.query_cpu = gdb_first_attached_cpu();
|
||||||
|
@ -1842,6 +1855,10 @@ static const GdbCmdParseEntry gdb_gen_query_table[] = {
|
||||||
.handler = handle_query_threads,
|
.handler = handle_query_threads,
|
||||||
.cmd = "sThreadInfo",
|
.cmd = "sThreadInfo",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.handler = handle_query_gdb_server_version,
|
||||||
|
.cmd = "GDBServerVersion",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.handler = handle_query_first_threads,
|
.handler = handle_query_first_threads,
|
||||||
.cmd = "fThreadInfo",
|
.cmd = "fThreadInfo",
|
||||||
|
|
|
@ -162,8 +162,8 @@ static inline unsigned memop_size(MemOp op)
|
||||||
static inline MemOp size_memop(unsigned size)
|
static inline MemOp size_memop(unsigned size)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_DEBUG_TCG
|
#ifdef CONFIG_DEBUG_TCG
|
||||||
/* Power of 2 up to 8. */
|
/* Power of 2 up to 1024 */
|
||||||
assert((size & (size - 1)) == 0 && size >= 1 && size <= 8);
|
assert(is_power_of_2(size) && size >= 1 && size <= (1 << MO_SIZE));
|
||||||
#endif
|
#endif
|
||||||
return (MemOp)ctz32(size);
|
return (MemOp)ctz32(size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef GDBSTUB_COMMANDS_H
|
#ifndef GDBSTUB_COMMANDS_H
|
||||||
#define GDBSTUB
|
#define GDBSTUB_COMMANDS_H
|
||||||
|
|
||||||
typedef void (*GdbCmdHandler)(GArray *params, void *user_ctx);
|
typedef void (*GdbCmdHandler)(GArray *params, void *user_ctx);
|
||||||
|
|
||||||
|
|
|
@ -185,8 +185,10 @@ docker:
|
||||||
|
|
||||||
docker-help: docker
|
docker-help: docker
|
||||||
|
|
||||||
|
# Where QEMU caches build artefacts
|
||||||
|
DOCKER_QEMU_CACHE_DIR := $$HOME/.cache/qemu
|
||||||
# Use a global constant ccache directory to speed up repetitive builds
|
# Use a global constant ccache directory to speed up repetitive builds
|
||||||
DOCKER_CCACHE_DIR := $$HOME/.cache/qemu-docker-ccache
|
DOCKER_QEMU_CCACHE_DIR := DOCKER_QEMU_CACHE_DIR/docker-ccache
|
||||||
|
|
||||||
# This rule if for directly running against an arbitrary docker target.
|
# This rule if for directly running against an arbitrary docker target.
|
||||||
# It is called by the expanded docker targets (e.g. make
|
# It is called by the expanded docker targets (e.g. make
|
||||||
|
@ -195,7 +197,7 @@ DOCKER_CCACHE_DIR := $$HOME/.cache/qemu-docker-ccache
|
||||||
# For example: make docker-run TEST="test-quick" IMAGE="debian:arm64" EXECUTABLE=./aarch64-linux-user/qemu-aarch64
|
# For example: make docker-run TEST="test-quick" IMAGE="debian:arm64" EXECUTABLE=./aarch64-linux-user/qemu-aarch64
|
||||||
#
|
#
|
||||||
docker-run: docker-qemu-src
|
docker-run: docker-qemu-src
|
||||||
@mkdir -p "$(DOCKER_CCACHE_DIR)"
|
@mkdir -p "$(DOCKER_QEMU_CCACHE_DIR)"
|
||||||
@if test -z "$(IMAGE)" || test -z "$(TEST)"; \
|
@if test -z "$(IMAGE)" || test -z "$(TEST)"; \
|
||||||
then echo "Invalid target $(IMAGE)/$(TEST)"; exit 1; \
|
then echo "Invalid target $(IMAGE)/$(TEST)"; exit 1; \
|
||||||
fi
|
fi
|
||||||
|
@ -222,8 +224,8 @@ docker-run: docker-qemu-src
|
||||||
-e V=$V -e J=$J -e DEBUG=$(DEBUG) \
|
-e V=$V -e J=$J -e DEBUG=$(DEBUG) \
|
||||||
-e SHOW_ENV=$(SHOW_ENV) \
|
-e SHOW_ENV=$(SHOW_ENV) \
|
||||||
$(if $(NOUSER),, \
|
$(if $(NOUSER),, \
|
||||||
-e CCACHE_DIR=/var/tmp/ccache \
|
-v $(DOCKER_QEMU_CACHE_DIR):$(DOCKER_QEMU_CACHE_DIR) \
|
||||||
-v $(DOCKER_CCACHE_DIR):/var/tmp/ccache:z \
|
-e CCACHE_DIR=$(DOCKER_QEMU_CCACHE_DIR) \
|
||||||
) \
|
) \
|
||||||
-v $$(readlink -e $(DOCKER_SRC_COPY)):/var/tmp/qemu:z$(COMMA)ro \
|
-v $$(readlink -e $(DOCKER_SRC_COPY)):/var/tmp/qemu:z$(COMMA)ro \
|
||||||
$(IMAGE) \
|
$(IMAGE) \
|
||||||
|
|
|
@ -104,10 +104,10 @@ static void igb_pci_start_hw(QOSGraphObject *obj)
|
||||||
e1000e_macreg_write(&d->e1000e, E1000_RDT(0), 0);
|
e1000e_macreg_write(&d->e1000e, E1000_RDT(0), 0);
|
||||||
e1000e_macreg_write(&d->e1000e, E1000_RDH(0), 0);
|
e1000e_macreg_write(&d->e1000e, E1000_RDH(0), 0);
|
||||||
e1000e_macreg_write(&d->e1000e, E1000_RA,
|
e1000e_macreg_write(&d->e1000e, E1000_RA,
|
||||||
le32_to_cpu(*(uint32_t *)address));
|
ldl_le_p(address));
|
||||||
e1000e_macreg_write(&d->e1000e, E1000_RA + 4,
|
e1000e_macreg_write(&d->e1000e, E1000_RA + 4,
|
||||||
E1000_RAH_AV | E1000_RAH_POOL_1 |
|
E1000_RAH_AV | E1000_RAH_POOL_1 |
|
||||||
le16_to_cpu(*(uint16_t *)(address + 4)));
|
lduw_le_p(address + 4));
|
||||||
|
|
||||||
/* Set supported receive descriptor mode */
|
/* Set supported receive descriptor mode */
|
||||||
e1000e_macreg_write(&d->e1000e,
|
e1000e_macreg_write(&d->e1000e,
|
||||||
|
|
|
@ -68,7 +68,8 @@ run-plugin-semiconsole-with-%: semiconsole
|
||||||
|
|
||||||
# vtimer test needs EL2
|
# vtimer test needs EL2
|
||||||
QEMU_EL2_MACHINE=-machine virt,virtualization=on,gic-version=2 -cpu cortex-a57 -smp 4
|
QEMU_EL2_MACHINE=-machine virt,virtualization=on,gic-version=2 -cpu cortex-a57 -smp 4
|
||||||
run-vtimer: QEMU_OPTS=$(QEMU_EL2_MACHINE) $(QEMU_BASE_ARGS) -kernel
|
QEMU_EL2_BASE_ARGS=-semihosting-config enable=on,target=native,chardev=output,arg="2"
|
||||||
|
run-vtimer: QEMU_OPTS=$(QEMU_EL2_MACHINE) $(QEMU_EL2_BASE_ARGS) -kernel
|
||||||
|
|
||||||
# Simple Record/Replay Test
|
# Simple Record/Replay Test
|
||||||
.PHONY: memory-record
|
.PHONY: memory-record
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#define semihosting_call hlt 0xf000
|
#define semihosting_call hlt 0xf000
|
||||||
#define SYS_WRITEC 0x03 /* character to debug channel */
|
#define SYS_WRITEC 0x03 /* character to debug channel */
|
||||||
#define SYS_WRITE0 0x04 /* string to debug channel */
|
#define SYS_WRITE0 0x04 /* string to debug channel */
|
||||||
|
#define SYS_GET_CMDLINE 0x15 /* get command line */
|
||||||
#define SYS_EXIT 0x18
|
#define SYS_EXIT 0x18
|
||||||
|
|
||||||
.align 12
|
.align 12
|
||||||
|
@ -70,21 +71,172 @@ lower_a32_sync:
|
||||||
lower_a32_irq:
|
lower_a32_irq:
|
||||||
lower_a32_fiq:
|
lower_a32_fiq:
|
||||||
lower_a32_serror:
|
lower_a32_serror:
|
||||||
|
adr x1, .unexp_excp
|
||||||
|
exit_msg:
|
||||||
mov x0, SYS_WRITE0
|
mov x0, SYS_WRITE0
|
||||||
adr x1, .error
|
|
||||||
semihosting_call
|
semihosting_call
|
||||||
mov x0, 1 /* EXIT_FAILURE */
|
mov x0, 1 /* EXIT_FAILURE */
|
||||||
bl _exit
|
bl _exit
|
||||||
/* never returns */
|
/* never returns */
|
||||||
|
|
||||||
.section .rodata
|
.section .rodata
|
||||||
.error:
|
.unexp_excp:
|
||||||
.string "Terminated by exception.\n"
|
.string "Unexpected exception.\n"
|
||||||
|
.high_el_msg:
|
||||||
|
.string "Started in lower EL than requested.\n"
|
||||||
|
.unexp_el0:
|
||||||
|
.string "Started in invalid EL.\n"
|
||||||
|
|
||||||
|
.align 8
|
||||||
|
.get_cmd:
|
||||||
|
.quad cmdline
|
||||||
|
.quad 128
|
||||||
|
|
||||||
.text
|
.text
|
||||||
.align 4
|
.align 4
|
||||||
.global __start
|
.global __start
|
||||||
__start:
|
__start:
|
||||||
|
/*
|
||||||
|
* Initialise the stack for whatever EL we are in before
|
||||||
|
* anything else, we need it to be able to _exit cleanly.
|
||||||
|
* It's smaller than the stack we pass to the C code but we
|
||||||
|
* don't need much.
|
||||||
|
*/
|
||||||
|
adrp x0, system_stack_end
|
||||||
|
add x0, x0, :lo12:system_stack_end
|
||||||
|
mov sp, x0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The test can set the semihosting command line to the target
|
||||||
|
* EL needed for the test. However if no semihosting args are set we will
|
||||||
|
* end up with -kernel/-append data (see semihosting_arg_fallback).
|
||||||
|
* Keep the normalised target in w11.
|
||||||
|
*/
|
||||||
|
mov x0, SYS_GET_CMDLINE
|
||||||
|
adr x1, .get_cmd
|
||||||
|
semihosting_call
|
||||||
|
adrp x10, cmdline
|
||||||
|
add x10, x10, :lo12:cmdline
|
||||||
|
ldrb w11, [x10]
|
||||||
|
|
||||||
|
/* sanity check, normalise char to EL, clamp to 1 if outside range */
|
||||||
|
subs w11, w11, #'0'
|
||||||
|
b.lt el_default
|
||||||
|
cmp w11, #3
|
||||||
|
b.gt el_default
|
||||||
|
b 1f
|
||||||
|
|
||||||
|
el_high:
|
||||||
|
adr x1, .high_el_msg
|
||||||
|
b exit_msg
|
||||||
|
|
||||||
|
el_default:
|
||||||
|
mov w11, #1
|
||||||
|
|
||||||
|
1:
|
||||||
|
/* Determine current Exception Level */
|
||||||
|
mrs x0, CurrentEL
|
||||||
|
lsr x0, x0, #2 /* CurrentEL[3:2] contains the current EL */
|
||||||
|
|
||||||
|
/* Are we already in a lower EL than we want? */
|
||||||
|
cmp w11, w0
|
||||||
|
bgt el_high
|
||||||
|
|
||||||
|
/* Branch based on current EL */
|
||||||
|
cmp x0, #3
|
||||||
|
b.eq setup_el3
|
||||||
|
cmp x0, #2
|
||||||
|
b.eq setup_el2
|
||||||
|
cmp x0, #1
|
||||||
|
b.eq at_testel /* Already at EL1, skip transition */
|
||||||
|
|
||||||
|
/* Should not be at EL0 - error out */
|
||||||
|
adr x1, .unexp_el0
|
||||||
|
b exit_msg
|
||||||
|
|
||||||
|
setup_el3:
|
||||||
|
/* Ensure we trap if we get anything wrong */
|
||||||
|
adr x0, vector_table
|
||||||
|
msr vbar_el3, x0
|
||||||
|
|
||||||
|
/* Does the test want to be at EL3? */
|
||||||
|
cmp w11, #3
|
||||||
|
beq at_testel
|
||||||
|
|
||||||
|
/* Configure EL3 to for lower states (EL2 or EL1) */
|
||||||
|
mrs x0, scr_el3
|
||||||
|
orr x0, x0, #(1 << 10) /* RW = 1: EL2/EL1 execution state is AArch64 */
|
||||||
|
orr x0, x0, #(1 << 0) /* NS = 1: Non-secure state */
|
||||||
|
msr scr_el3, x0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need to check if EL2 is actually enabled via ID_AA64PFR0_EL1,
|
||||||
|
* otherwise we should just jump straight to EL1.
|
||||||
|
*/
|
||||||
|
mrs x0, id_aa64pfr0_el1
|
||||||
|
ubfx x0, x0, #8, #4 /* Extract EL2 field (bits 11:8) */
|
||||||
|
cbz x0, el2_not_present /* If field is 0 no EL2 */
|
||||||
|
|
||||||
|
|
||||||
|
/* Prepare SPSR for exception return to EL2 */
|
||||||
|
mov x0, #0x3c9 /* DAIF bits and EL2h mode (9) */
|
||||||
|
msr spsr_el3, x0
|
||||||
|
|
||||||
|
/* Set EL2 entry point */
|
||||||
|
adr x0, setup_el2
|
||||||
|
msr elr_el3, x0
|
||||||
|
|
||||||
|
/* Return to EL2 */
|
||||||
|
eret
|
||||||
|
|
||||||
|
el2_not_present:
|
||||||
|
/* Initialize SCTLR_EL1 with reset value */
|
||||||
|
msr sctlr_el1, xzr
|
||||||
|
|
||||||
|
/* Set EL1 entry point */
|
||||||
|
adr x0, at_testel
|
||||||
|
msr elr_el3, x0
|
||||||
|
|
||||||
|
/* Prepare SPSR for exception return to EL1h with interrupts masked */
|
||||||
|
mov x0, #0x3c5 /* DAIF bits and EL1h mode (5) */
|
||||||
|
msr spsr_el3, x0
|
||||||
|
|
||||||
|
isb /* Synchronization barrier */
|
||||||
|
eret /* Jump to EL1 */
|
||||||
|
|
||||||
|
setup_el2:
|
||||||
|
/* Ensure we trap if we get anything wrong */
|
||||||
|
adr x0, vector_table
|
||||||
|
msr vbar_el2, x0
|
||||||
|
|
||||||
|
/* Does the test want to be at EL2? */
|
||||||
|
cmp w11, #2
|
||||||
|
beq at_testel
|
||||||
|
|
||||||
|
/* Configure EL2 to allow transition to EL1 */
|
||||||
|
mrs x0, hcr_el2
|
||||||
|
orr x0, x0, #(1 << 31) /* RW = 1: EL1 execution state is AArch64 */
|
||||||
|
msr hcr_el2, x0
|
||||||
|
|
||||||
|
/* Initialize SCTLR_EL1 with reset value */
|
||||||
|
msr sctlr_el1, xzr
|
||||||
|
|
||||||
|
/* Set EL1 entry point */
|
||||||
|
adr x0, at_testel
|
||||||
|
msr elr_el2, x0
|
||||||
|
|
||||||
|
/* Prepare SPSR for exception return to EL1 */
|
||||||
|
mov x0, #(0x5 << 0) /* EL1h (SPx), with interrupts disabled */
|
||||||
|
msr spsr_el2, x0
|
||||||
|
|
||||||
|
/* Return to EL1 */
|
||||||
|
eret
|
||||||
|
|
||||||
|
/*
|
||||||
|
* At the target EL for the test, usually EL1. Note we still
|
||||||
|
* set everything up as if we were at EL1.
|
||||||
|
*/
|
||||||
|
at_testel:
|
||||||
/* Installs a table of exception vectors to catch and handle all
|
/* Installs a table of exception vectors to catch and handle all
|
||||||
exceptions by terminating the process with a diagnostic. */
|
exceptions by terminating the process with a diagnostic. */
|
||||||
adr x0, vector_table
|
adr x0, vector_table
|
||||||
|
@ -198,7 +350,8 @@ __start:
|
||||||
orr x0, x0, #(3 << 16)
|
orr x0, x0, #(3 << 16)
|
||||||
msr cpacr_el1, x0
|
msr cpacr_el1, x0
|
||||||
|
|
||||||
/* Setup some stack space and enter the test code.
|
/*
|
||||||
|
* Setup some stack space before we enter the test code.
|
||||||
* Assume everything except the return value is garbage when we
|
* Assume everything except the return value is garbage when we
|
||||||
* return, we won't need it.
|
* return, we won't need it.
|
||||||
*/
|
*/
|
||||||
|
@ -233,6 +386,11 @@ __sys_outc:
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.data
|
.data
|
||||||
|
|
||||||
|
.align 8
|
||||||
|
cmdline:
|
||||||
|
.space 128, 0
|
||||||
|
|
||||||
.align 12
|
.align 12
|
||||||
|
|
||||||
/* Translation table
|
/* Translation table
|
||||||
|
@ -246,6 +404,10 @@ ttb_stage2:
|
||||||
.space 4096, 0
|
.space 4096, 0
|
||||||
|
|
||||||
.align 12
|
.align 12
|
||||||
|
system_stack:
|
||||||
|
.space 4096, 0
|
||||||
|
system_stack_end:
|
||||||
|
|
||||||
stack:
|
stack:
|
||||||
.space 65536, 0
|
.space 65536, 0
|
||||||
stack_end:
|
stack_end:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue