aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab-ci.d/buildtest-template.yml1
-rw-r--r--contrib/plugins/ips.c49
-rw-r--r--docs/about/emulation.rst4
-rw-r--r--gdb-xml/aarch64-core.xml52
-rw-r--r--gdbstub/gdbstub.c19
-rw-r--r--include/exec/memop.h4
-rw-r--r--include/gdbstub/commands.h2
-rw-r--r--tests/docker/Makefile.include10
-rw-r--r--tests/qtest/libqos/igb.c4
-rw-r--r--tests/tcg/aarch64/Makefile.softmmu-target3
-rw-r--r--tests/tcg/aarch64/system/boot.S172
11 files changed, 300 insertions, 20 deletions
diff --git a/.gitlab-ci.d/buildtest-template.yml b/.gitlab-ci.d/buildtest-template.yml
index fea4e8d..038c3c9 100644
--- a/.gitlab-ci.d/buildtest-template.yml
+++ b/.gitlab-ci.d/buildtest-template.yml
@@ -24,6 +24,7 @@
- ccache --zero-stats
- section_start configure "Running configure"
- ../configure --enable-werror --disable-docs --enable-fdt=system
+ --disable-debug-info
${TARGETS:+--target-list="$TARGETS"}
$CONFIGURE_ARGS ||
{ cat config.log meson-logs/meson-log.txt && exit 1; }
diff --git a/contrib/plugins/ips.c b/contrib/plugins/ips.c
index e5297db..f110c56 100644
--- a/contrib/plugins/ips.c
+++ b/contrib/plugins/ips.c
@@ -129,20 +129,62 @@ static void plugin_exit(qemu_plugin_id_t id, void *udata)
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,
const qemu_info_t *info, int argc,
char **argv)
{
+ bool ipq_set = false;
+
for (int i = 0; i < argc; i++) {
char *opt = argv[i];
g_auto(GStrv) tokens = g_strsplit(opt, "=", 2);
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) {
fprintf(stderr, "%s: couldn't parse %s (%s)\n",
__func__, tokens[1], g_strerror(errno));
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 {
fprintf(stderr, "option parsing failed: %s\n", opt);
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));
- max_insn_per_quantum = max_insn_per_second / NUM_TIME_UPDATE_PER_SEC;
+
+ if (!ipq_set) {
+ max_insn_per_quantum = max_insn_per_second / NUM_TIME_UPDATE_PER_SEC;
+ }
if (max_insn_per_quantum == 0) {
fprintf(stderr, "minimum of %d instructions per second needed\n",
diff --git a/docs/about/emulation.rst b/docs/about/emulation.rst
index a72591e..456d01d 100644
--- a/docs/about/emulation.rst
+++ b/docs/about/emulation.rst
@@ -811,6 +811,10 @@ This plugin can limit the number of Instructions Per Second that are executed::
* - ips=N
- 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.
+ * - 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
------------------------
diff --git a/gdb-xml/aarch64-core.xml b/gdb-xml/aarch64-core.xml
index e1e9dc3..b804651 100644
--- a/gdb-xml/aarch64-core.xml
+++ b/gdb-xml/aarch64-core.xml
@@ -1,5 +1,5 @@
<?xml version="1.0"?>
-<!-- Copyright (C) 2009-2012 Free Software Foundation, Inc.
+<!-- Copyright (C) 2009-2025 Free Software Foundation, Inc.
Contributed by ARM Ltd.
Copying and distribution of this file, with or without modification,
@@ -42,5 +42,53 @@
<reg name="sp" bitsize="64" type="data_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>
diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c
index 565f6b3..def0b7e 100644
--- a/gdbstub/gdbstub.c
+++ b/gdbstub/gdbstub.c
@@ -28,6 +28,7 @@
#include "qemu/cutils.h"
#include "qemu/module.h"
#include "qemu/error-report.h"
+#include "qemu/target-info.h"
#include "trace.h"
#include "exec/gdbstub.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,
gdbserver_state.mem_buf,
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_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);
}
+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)
{
gdbserver_state.query_cpu = gdb_first_attached_cpu();
@@ -1843,6 +1856,10 @@ static const GdbCmdParseEntry gdb_gen_query_table[] = {
.cmd = "sThreadInfo",
},
{
+ .handler = handle_query_gdb_server_version,
+ .cmd = "GDBServerVersion",
+ },
+ {
.handler = handle_query_first_threads,
.cmd = "fThreadInfo",
},
diff --git a/include/exec/memop.h b/include/exec/memop.h
index 407a47d..cf7da33 100644
--- a/include/exec/memop.h
+++ b/include/exec/memop.h
@@ -162,8 +162,8 @@ static inline unsigned memop_size(MemOp op)
static inline MemOp size_memop(unsigned size)
{
#ifdef CONFIG_DEBUG_TCG
- /* Power of 2 up to 8. */
- assert((size & (size - 1)) == 0 && size >= 1 && size <= 8);
+ /* Power of 2 up to 1024 */
+ assert(is_power_of_2(size) && size >= 1 && size <= (1 << MO_SIZE));
#endif
return (MemOp)ctz32(size);
}
diff --git a/include/gdbstub/commands.h b/include/gdbstub/commands.h
index 40f0514..bff3674 100644
--- a/include/gdbstub/commands.h
+++ b/include/gdbstub/commands.h
@@ -1,5 +1,5 @@
#ifndef GDBSTUB_COMMANDS_H
-#define GDBSTUB
+#define GDBSTUB_COMMANDS_H
typedef void (*GdbCmdHandler)(GArray *params, void *user_ctx);
diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include
index fa1cbb6..3959d8a 100644
--- a/tests/docker/Makefile.include
+++ b/tests/docker/Makefile.include
@@ -185,8 +185,10 @@ 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
-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.
# 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
#
docker-run: docker-qemu-src
- @mkdir -p "$(DOCKER_CCACHE_DIR)"
+ @mkdir -p "$(DOCKER_QEMU_CCACHE_DIR)"
@if test -z "$(IMAGE)" || test -z "$(TEST)"; \
then echo "Invalid target $(IMAGE)/$(TEST)"; exit 1; \
fi
@@ -222,8 +224,8 @@ docker-run: docker-qemu-src
-e V=$V -e J=$J -e DEBUG=$(DEBUG) \
-e SHOW_ENV=$(SHOW_ENV) \
$(if $(NOUSER),, \
- -e CCACHE_DIR=/var/tmp/ccache \
- -v $(DOCKER_CCACHE_DIR):/var/tmp/ccache:z \
+ -v $(DOCKER_QEMU_CACHE_DIR):$(DOCKER_QEMU_CACHE_DIR) \
+ -e CCACHE_DIR=$(DOCKER_QEMU_CCACHE_DIR) \
) \
-v $$(readlink -e $(DOCKER_SRC_COPY)):/var/tmp/qemu:z$(COMMA)ro \
$(IMAGE) \
diff --git a/tests/qtest/libqos/igb.c b/tests/qtest/libqos/igb.c
index f40c4ec..ab3ef6f 100644
--- a/tests/qtest/libqos/igb.c
+++ b/tests/qtest/libqos/igb.c
@@ -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_RDH(0), 0);
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,
E1000_RAH_AV | E1000_RAH_POOL_1 |
- le16_to_cpu(*(uint16_t *)(address + 4)));
+ lduw_le_p(address + 4));
/* Set supported receive descriptor mode */
e1000e_macreg_write(&d->e1000e,
diff --git a/tests/tcg/aarch64/Makefile.softmmu-target b/tests/tcg/aarch64/Makefile.softmmu-target
index 9c52475..f7a7d2b 100644
--- a/tests/tcg/aarch64/Makefile.softmmu-target
+++ b/tests/tcg/aarch64/Makefile.softmmu-target
@@ -68,7 +68,8 @@ run-plugin-semiconsole-with-%: semiconsole
# vtimer test needs EL2
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
.PHONY: memory-record
diff --git a/tests/tcg/aarch64/system/boot.S b/tests/tcg/aarch64/system/boot.S
index a5df9c1..8bfa4e4 100644
--- a/tests/tcg/aarch64/system/boot.S
+++ b/tests/tcg/aarch64/system/boot.S
@@ -16,6 +16,7 @@
#define semihosting_call hlt 0xf000
#define SYS_WRITEC 0x03 /* character to debug channel */
#define SYS_WRITE0 0x04 /* string to debug channel */
+#define SYS_GET_CMDLINE 0x15 /* get command line */
#define SYS_EXIT 0x18
.align 12
@@ -70,21 +71,172 @@ lower_a32_sync:
lower_a32_irq:
lower_a32_fiq:
lower_a32_serror:
+ adr x1, .unexp_excp
+exit_msg:
mov x0, SYS_WRITE0
- adr x1, .error
semihosting_call
mov x0, 1 /* EXIT_FAILURE */
bl _exit
/* never returns */
.section .rodata
-.error:
- .string "Terminated by exception.\n"
+.unexp_excp:
+ .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
.align 4
.global __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
exceptions by terminating the process with a diagnostic. */
adr x0, vector_table
@@ -100,7 +252,7 @@ __start:
* 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 */
@@ -198,7 +350,8 @@ __start:
orr x0, x0, #(3 << 16)
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
* return, we won't need it.
*/
@@ -233,6 +386,11 @@ __sys_outc:
ret
.data
+
+ .align 8
+cmdline:
+ .space 128, 0
+
.align 12
/* Translation table
@@ -246,6 +404,10 @@ ttb_stage2:
.space 4096, 0
.align 12
+system_stack:
+ .space 4096, 0
+system_stack_end:
+
stack:
.space 65536, 0
stack_end: