maintainer updates for 10.2
- clean-up remaining 32 bit armhf bits in ci - rationalise build-environment.yml for Debian and Ubuntu - generate a Debian ppc64 package list - rationalise gitlab-runner.yml for Debian and Ubuntu - new TCG plugin feature to track discontinuities - add missing CFI annotation to plugin callbacks - drop SBSA_REF from minimal Arm build - format string fix for gdbstub syscall response - simplify the gdbstub flen handling for semihosting -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEZoWumedRZ7yvyN81+9DbCVqeKkQFAmkCInQACgkQ+9DbCVqe KkSZRwf/ReHIqQMxf8TqthskX8PLGUvsvWMkJptpu0Yc4HyU6DSjdPbU4L0tOmLU ss2sb+dZncp1iRxHpqOhPJ+a987RHHzFbz2GQ/nV37D7BTwtq0iID4SxmdfiYOAm VVm/WQ0HMjIYY84rzfE6U/3H+FgL+GaPbB0WYa5CtKpMOHMl4gJgoSsxljXQrmYe BCC+Z9loVUAnKVVM5BUMP/0Agfn0CUZlUHGEn6RvmNg81dJ5DWCfO9yW1EezLZmc PhS/txAWrpTqktPxN4h+um8ILvej5FF8nnNCsxodxD1XZImWsxawxcQAcgQQJGWu dFLBMre7QSM1ddIOgdyZt+zuDcpUiA== =QEqf -----END PGP SIGNATURE----- Merge tag 'pull-10.2-maintainer-291025-1' of https://gitlab.com/stsquad/qemu into staging maintainer updates for 10.2 - clean-up remaining 32 bit armhf bits in ci - rationalise build-environment.yml for Debian and Ubuntu - generate a Debian ppc64 package list - rationalise gitlab-runner.yml for Debian and Ubuntu - new TCG plugin feature to track discontinuities - add missing CFI annotation to plugin callbacks - drop SBSA_REF from minimal Arm build - format string fix for gdbstub syscall response - simplify the gdbstub flen handling for semihosting # -----BEGIN PGP SIGNATURE----- # # iQEzBAABCgAdFiEEZoWumedRZ7yvyN81+9DbCVqeKkQFAmkCInQACgkQ+9DbCVqe # KkSZRwf/ReHIqQMxf8TqthskX8PLGUvsvWMkJptpu0Yc4HyU6DSjdPbU4L0tOmLU # ss2sb+dZncp1iRxHpqOhPJ+a987RHHzFbz2GQ/nV37D7BTwtq0iID4SxmdfiYOAm # VVm/WQ0HMjIYY84rzfE6U/3H+FgL+GaPbB0WYa5CtKpMOHMl4gJgoSsxljXQrmYe # BCC+Z9loVUAnKVVM5BUMP/0Agfn0CUZlUHGEn6RvmNg81dJ5DWCfO9yW1EezLZmc # PhS/txAWrpTqktPxN4h+um8ILvej5FF8nnNCsxodxD1XZImWsxawxcQAcgQQJGWu # dFLBMre7QSM1ddIOgdyZt+zuDcpUiA== # =QEqf # -----END PGP SIGNATURE----- # gpg: Signature made Wed 29 Oct 2025 03:19:32 PM CET # 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.2-maintainer-291025-1' of https://gitlab.com/stsquad/qemu: (35 commits) semihosting: Fix GDB File-I/O FLEN gdbstub: Fix %s formatting configs: drop SBSA_REF from minimal specification plugins/core: add missing QEMU_DISABLE_CFI annotations tests: add test with interrupted memory accesses on rv64 tests: add test for double-traps on rv64 tests: add plugin asserting correctness of discon event's to_pc target/xtensa: call plugin trap callbacks target/tricore: call plugin trap callbacks target/sparc: call plugin trap callbacks target/sh4: call plugin trap callbacks target/s390x: call plugin trap callbacks target/rx: call plugin trap callbacks target/riscv: call plugin trap callbacks target/ppc: call plugin trap callbacks target/openrisc: call plugin trap callbacks target/mips: call plugin trap callbacks target/microblaze: call plugin trap callbacks target/m68k: call plugin trap callbacks target/loongarch: call plugin trap callbacks ... Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
4889d96660
47 changed files with 1031 additions and 37 deletions
|
|
@ -107,7 +107,5 @@ ubuntu-24.04-aarch64-notcg:
|
|||
rules:
|
||||
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
|
||||
when: manual
|
||||
allow_failure: true
|
||||
- if: "$AARCH64_RUNNER_AVAILABLE"
|
||||
when: manual
|
||||
allow_failure: true
|
||||
|
|
|
|||
|
|
@ -6,4 +6,3 @@
|
|||
#
|
||||
|
||||
CONFIG_ARM_VIRT=y
|
||||
CONFIG_SBSA_REF=y
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
contrib_plugins = ['bbv', 'cache', 'cflow', 'drcov', 'execlog', 'hotblocks',
|
||||
'hotpages', 'howvec', 'hwprofile', 'ips', 'stoptrigger',
|
||||
'uftrace']
|
||||
'traps', 'uftrace']
|
||||
if host_os != 'windows'
|
||||
# lockstep uses socket.h
|
||||
contrib_plugins += 'lockstep'
|
||||
|
|
|
|||
83
contrib/plugins/traps.c
Normal file
83
contrib/plugins/traps.c
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright (C) 2025, Julian Ganz <neither@nut.email>
|
||||
*
|
||||
* Traps - count traps
|
||||
*
|
||||
* Count the number of interrupts (asyncronous events), exceptions (synchronous
|
||||
* events) and host calls (e.g. semihosting) per cpu and report those counts on
|
||||
* exit.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <qemu-plugin.h>
|
||||
|
||||
QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
|
||||
|
||||
typedef struct {
|
||||
uint64_t interrupts;
|
||||
uint64_t exceptions;
|
||||
uint64_t hostcalls;
|
||||
} TrapCounters;
|
||||
|
||||
static struct qemu_plugin_scoreboard *traps;
|
||||
|
||||
static void vcpu_discon(qemu_plugin_id_t id, unsigned int vcpu_index,
|
||||
enum qemu_plugin_discon_type type, uint64_t from_pc,
|
||||
uint64_t to_pc)
|
||||
{
|
||||
TrapCounters *rec = qemu_plugin_scoreboard_find(traps, vcpu_index);
|
||||
switch (type) {
|
||||
case QEMU_PLUGIN_DISCON_INTERRUPT:
|
||||
rec->interrupts++;
|
||||
break;
|
||||
case QEMU_PLUGIN_DISCON_EXCEPTION:
|
||||
rec->exceptions++;
|
||||
break;
|
||||
case QEMU_PLUGIN_DISCON_HOSTCALL:
|
||||
rec->hostcalls++;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void plugin_exit(qemu_plugin_id_t id, void *p)
|
||||
{
|
||||
g_autoptr(GString) report;
|
||||
report = g_string_new("VCPU, interrupts, exceptions, hostcalls\n");
|
||||
int max_vcpus = qemu_plugin_num_vcpus();
|
||||
int vcpu;
|
||||
|
||||
for (vcpu = 0; vcpu < max_vcpus; vcpu++) {
|
||||
TrapCounters *rec = qemu_plugin_scoreboard_find(traps, vcpu);
|
||||
g_string_append_printf(report,
|
||||
"% 4d, % 10"PRId64", % 10"PRId64", % 10"PRId64
|
||||
"\n", vcpu, rec->interrupts, rec->exceptions,
|
||||
rec->hostcalls);
|
||||
}
|
||||
|
||||
qemu_plugin_outs(report->str);
|
||||
qemu_plugin_scoreboard_free(traps);
|
||||
}
|
||||
|
||||
QEMU_PLUGIN_EXPORT
|
||||
int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info,
|
||||
int argc, char **argv)
|
||||
{
|
||||
if (!info->system_emulation) {
|
||||
qemu_plugin_outs("Note: interrupts are only reported in system"
|
||||
" emulation mode.");
|
||||
}
|
||||
|
||||
traps = qemu_plugin_scoreboard_new(sizeof(TrapCounters));
|
||||
|
||||
qemu_plugin_register_vcpu_discon_cb(id, QEMU_PLUGIN_DISCON_ALL,
|
||||
vcpu_discon);
|
||||
|
||||
qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1015,6 +1015,14 @@ interesting to generate them around a particular point of execution::
|
|||
# generate trace around init execution (2 seconds):
|
||||
$ uftrace dump --chrome --time-range=1753122320~1753122322 > init.json
|
||||
|
||||
Count traps
|
||||
...........
|
||||
|
||||
``contrib/plugins/traps.c``
|
||||
|
||||
This plugin counts the number of interrupts (asyncronous events), exceptions
|
||||
(synchronous events) and host calls (e.g. semihosting) per cpu.
|
||||
|
||||
Other emulation features
|
||||
------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -168,13 +168,6 @@ If you've got access to an aarch64 host that can be used as a gitlab-CI
|
|||
runner, you can set this variable to enable the tests that require this
|
||||
kind of host. The runner should be tagged with "aarch64".
|
||||
|
||||
AARCH32_RUNNER_AVAILABLE
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
If you've got access to an armhf host or an arch64 host that can run
|
||||
aarch32 EL0 code to be used as a gitlab-CI runner, you can set this
|
||||
variable to enable the tests that require this kind of host. The
|
||||
runner should be tagged with "aarch32".
|
||||
|
||||
S390X_RUNNER_AVAILABLE
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
If you've got access to an IBM Z host that can be used as a gitlab-CI
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...)
|
|||
case 's':
|
||||
i64 = va_arg(va, uint64_t);
|
||||
i32 = va_arg(va, uint32_t);
|
||||
p += snprintf(p, p_end - p, "%" PRIx64 "/%x" PRIx32, i64, i32);
|
||||
p += snprintf(p, p_end - p, "%" PRIx64 "/%" PRIx32, i64, i32);
|
||||
break;
|
||||
default:
|
||||
bad_format:
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@ enum qemu_plugin_event {
|
|||
QEMU_PLUGIN_EV_VCPU_SYSCALL_RET,
|
||||
QEMU_PLUGIN_EV_FLUSH,
|
||||
QEMU_PLUGIN_EV_ATEXIT,
|
||||
QEMU_PLUGIN_EV_VCPU_INTERRUPT,
|
||||
QEMU_PLUGIN_EV_VCPU_EXCEPTION,
|
||||
QEMU_PLUGIN_EV_VCPU_HOSTCALL,
|
||||
QEMU_PLUGIN_EV_MAX, /* total number of plugin events we support */
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ union qemu_plugin_cb_sig {
|
|||
qemu_plugin_udata_cb_t udata;
|
||||
qemu_plugin_vcpu_simple_cb_t vcpu_simple;
|
||||
qemu_plugin_vcpu_udata_cb_t vcpu_udata;
|
||||
qemu_plugin_vcpu_discon_cb_t vcpu_discon;
|
||||
qemu_plugin_vcpu_tb_trans_cb_t vcpu_tb_trans;
|
||||
qemu_plugin_vcpu_mem_cb_t vcpu_mem;
|
||||
qemu_plugin_vcpu_syscall_cb_t vcpu_syscall;
|
||||
|
|
@ -160,6 +161,9 @@ void qemu_plugin_vcpu_exit_hook(CPUState *cpu);
|
|||
void qemu_plugin_tb_trans_cb(CPUState *cpu, struct qemu_plugin_tb *tb);
|
||||
void qemu_plugin_vcpu_idle_cb(CPUState *cpu);
|
||||
void qemu_plugin_vcpu_resume_cb(CPUState *cpu);
|
||||
void qemu_plugin_vcpu_interrupt_cb(CPUState *cpu, uint64_t from);
|
||||
void qemu_plugin_vcpu_exception_cb(CPUState *cpu, uint64_t from);
|
||||
void qemu_plugin_vcpu_hostcall_cb(CPUState *cpu, uint64_t from);
|
||||
void
|
||||
qemu_plugin_vcpu_syscall(CPUState *cpu, int64_t num, uint64_t a1,
|
||||
uint64_t a2, uint64_t a3, uint64_t a4, uint64_t a5,
|
||||
|
|
@ -257,6 +261,15 @@ static inline void qemu_plugin_vcpu_idle_cb(CPUState *cpu)
|
|||
static inline void qemu_plugin_vcpu_resume_cb(CPUState *cpu)
|
||||
{ }
|
||||
|
||||
static inline void qemu_plugin_vcpu_interrupt_cb(CPUState *cpu, uint64_t from)
|
||||
{ }
|
||||
|
||||
static inline void qemu_plugin_vcpu_exception_cb(CPUState *cpu, uint64_t from)
|
||||
{ }
|
||||
|
||||
static inline void qemu_plugin_vcpu_hostcall_cb(CPUState *cpu, uint64_t from)
|
||||
{ }
|
||||
|
||||
static inline void
|
||||
qemu_plugin_vcpu_syscall(CPUState *cpu, int64_t num, uint64_t a1, uint64_t a2,
|
||||
uint64_t a3, uint64_t a4, uint64_t a5, uint64_t a6,
|
||||
|
|
|
|||
|
|
@ -161,6 +161,50 @@ typedef void (*qemu_plugin_vcpu_simple_cb_t)(qemu_plugin_id_t id,
|
|||
typedef void (*qemu_plugin_vcpu_udata_cb_t)(unsigned int vcpu_index,
|
||||
void *userdata);
|
||||
|
||||
|
||||
/**
|
||||
* enum qemu_plugin_discon_type - type of a (potential) PC discontinuity
|
||||
*
|
||||
* @QEMU_PLUGIN_DISCON_INTERRUPT: an interrupt, defined across all architectures
|
||||
* as an asynchronous event, usually originating
|
||||
* from outside the CPU
|
||||
* @QEMU_PLUGIN_DISCON_EXCEPTION: an exception, defined across all architectures
|
||||
* as a synchronous event in response to a
|
||||
* specific instruction being executed
|
||||
* @QEMU_PLUGIN_DISCON_HOSTCALL: a host call, functionally a special kind of
|
||||
* exception that is not handled by code run by
|
||||
* the vCPU but machinery outside the vCPU
|
||||
* @QEMU_PLUGIN_DISCON_ALL: all types of disconinuity events currently covered
|
||||
*/
|
||||
enum qemu_plugin_discon_type {
|
||||
QEMU_PLUGIN_DISCON_INTERRUPT = 1 << 0,
|
||||
QEMU_PLUGIN_DISCON_EXCEPTION = 1 << 1,
|
||||
QEMU_PLUGIN_DISCON_HOSTCALL = 1 << 2,
|
||||
QEMU_PLUGIN_DISCON_ALL = -1
|
||||
};
|
||||
|
||||
/**
|
||||
* typedef qemu_plugin_vcpu_discon_cb_t - vcpu discontinuity callback
|
||||
* @id: plugin ID
|
||||
* @vcpu_index: the current vcpu context
|
||||
* @type: the type of discontinuity
|
||||
* @from_pc: the source of the discontinuity, e.g. the PC before the
|
||||
* transition
|
||||
* @to_pc: the PC pointing to the next instruction to be executed
|
||||
*
|
||||
* The exact semantics of @from_pc depends on the @type of discontinuity. For
|
||||
* interrupts, @from_pc will point to the next instruction which would have
|
||||
* been executed. For exceptions and host calls, @from_pc will point to the
|
||||
* instruction that caused the exception or issued the host call. Note that
|
||||
* in the case of exceptions, the instruction may not be retired and thus not
|
||||
* observable via general instruction exec callbacks. The same may be the case
|
||||
* for some host calls such as hypervisor call "exceptions".
|
||||
*/
|
||||
typedef void (*qemu_plugin_vcpu_discon_cb_t)(qemu_plugin_id_t id,
|
||||
unsigned int vcpu_index,
|
||||
enum qemu_plugin_discon_type type,
|
||||
uint64_t from_pc, uint64_t to_pc);
|
||||
|
||||
/**
|
||||
* qemu_plugin_uninstall() - Uninstall a plugin
|
||||
* @id: this plugin's opaque ID
|
||||
|
|
@ -237,6 +281,22 @@ QEMU_PLUGIN_API
|
|||
void qemu_plugin_register_vcpu_resume_cb(qemu_plugin_id_t id,
|
||||
qemu_plugin_vcpu_simple_cb_t cb);
|
||||
|
||||
/**
|
||||
* qemu_plugin_register_vcpu_discon_cb() - register a discontinuity callback
|
||||
* @id: plugin ID
|
||||
* @type: types of discontinuities for which to call the callback
|
||||
* @cb: callback function
|
||||
*
|
||||
* The @cb function is called every time a vCPU receives a discontinuity event
|
||||
* of the specified type(s), after the vCPU was prepared to handle the event.
|
||||
* Preparation entails updating the PC, usually to some interrupt handler or
|
||||
* trap vector entry.
|
||||
*/
|
||||
QEMU_PLUGIN_API
|
||||
void qemu_plugin_register_vcpu_discon_cb(qemu_plugin_id_t id,
|
||||
enum qemu_plugin_discon_type type,
|
||||
qemu_plugin_vcpu_discon_cb_t cb);
|
||||
|
||||
/** struct qemu_plugin_tb - Opaque handle for a translation block */
|
||||
struct qemu_plugin_tb;
|
||||
/** struct qemu_plugin_insn - Opaque handle for a translated instruction */
|
||||
|
|
|
|||
|
|
@ -105,6 +105,30 @@ static void plugin_vcpu_cb__simple(CPUState *cpu, enum qemu_plugin_event ev)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable CFI checks.
|
||||
* The callback function has been loaded from an external library so we do not
|
||||
* have type information
|
||||
*/
|
||||
QEMU_DISABLE_CFI
|
||||
static void plugin_vcpu_cb__discon(CPUState *cpu,
|
||||
enum qemu_plugin_event ev,
|
||||
enum qemu_plugin_discon_type type,
|
||||
uint64_t from)
|
||||
{
|
||||
struct qemu_plugin_cb *cb, *next;
|
||||
uint64_t to = cpu->cc->get_pc(cpu);
|
||||
|
||||
if (cpu->cpu_index < plugin.num_vcpus) {
|
||||
/* iterate safely; plugins might uninstall themselves at any time */
|
||||
QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) {
|
||||
qemu_plugin_vcpu_discon_cb_t func = cb->f.vcpu_discon;
|
||||
|
||||
func(cb->ctx->id, cpu->cpu_index, type, from, to);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable CFI checks.
|
||||
* The callback function has been loaded from an external library so we do not
|
||||
|
|
@ -557,6 +581,24 @@ void qemu_plugin_vcpu_resume_cb(CPUState *cpu)
|
|||
}
|
||||
}
|
||||
|
||||
void qemu_plugin_vcpu_interrupt_cb(CPUState *cpu, uint64_t from)
|
||||
{
|
||||
plugin_vcpu_cb__discon(cpu, QEMU_PLUGIN_EV_VCPU_INTERRUPT,
|
||||
QEMU_PLUGIN_DISCON_INTERRUPT, from);
|
||||
}
|
||||
|
||||
void qemu_plugin_vcpu_exception_cb(CPUState *cpu, uint64_t from)
|
||||
{
|
||||
plugin_vcpu_cb__discon(cpu, QEMU_PLUGIN_EV_VCPU_EXCEPTION,
|
||||
QEMU_PLUGIN_DISCON_EXCEPTION, from);
|
||||
}
|
||||
|
||||
void qemu_plugin_vcpu_hostcall_cb(CPUState *cpu, uint64_t from)
|
||||
{
|
||||
plugin_vcpu_cb__discon(cpu, QEMU_PLUGIN_EV_VCPU_HOSTCALL,
|
||||
QEMU_PLUGIN_DISCON_HOSTCALL, from);
|
||||
}
|
||||
|
||||
void qemu_plugin_register_vcpu_idle_cb(qemu_plugin_id_t id,
|
||||
qemu_plugin_vcpu_simple_cb_t cb)
|
||||
{
|
||||
|
|
@ -569,6 +611,21 @@ void qemu_plugin_register_vcpu_resume_cb(qemu_plugin_id_t id,
|
|||
plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_RESUME, cb);
|
||||
}
|
||||
|
||||
void qemu_plugin_register_vcpu_discon_cb(qemu_plugin_id_t id,
|
||||
enum qemu_plugin_discon_type type,
|
||||
qemu_plugin_vcpu_discon_cb_t cb)
|
||||
{
|
||||
if (type & QEMU_PLUGIN_DISCON_INTERRUPT) {
|
||||
plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_INTERRUPT, cb);
|
||||
}
|
||||
if (type & QEMU_PLUGIN_DISCON_EXCEPTION) {
|
||||
plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_EXCEPTION, cb);
|
||||
}
|
||||
if (type & QEMU_PLUGIN_DISCON_HOSTCALL) {
|
||||
plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_HOSTCALL, cb);
|
||||
}
|
||||
}
|
||||
|
||||
void qemu_plugin_register_flush_cb(qemu_plugin_id_t id,
|
||||
qemu_plugin_simple_cb_t cb)
|
||||
{
|
||||
|
|
@ -611,6 +668,7 @@ void exec_inline_op(enum plugin_dyn_cb_type type,
|
|||
}
|
||||
}
|
||||
|
||||
QEMU_DISABLE_CFI
|
||||
void qemu_plugin_vcpu_mem_cb(CPUState *cpu, uint64_t vaddr,
|
||||
uint64_t value_low,
|
||||
uint64_t value_high,
|
||||
|
|
|
|||
|
|
@ -318,6 +318,7 @@ struct qemu_plugin_reset_data {
|
|||
bool reset;
|
||||
};
|
||||
|
||||
QEMU_DISABLE_CFI
|
||||
static void plugin_reset_destroy__locked(struct qemu_plugin_reset_data *data)
|
||||
{
|
||||
struct qemu_plugin_ctx *ctx = data->ctx;
|
||||
|
|
|
|||
|
|
@ -19,32 +19,38 @@
|
|||
- '((ansible_version.major == 2) and (ansible_version.minor >= 8)) or (ansible_version.major >= 3)'
|
||||
msg: "Unsuitable ansible version, please use version 2.8.0 or later"
|
||||
|
||||
- name: Add armhf foreign architecture to aarch64 hosts
|
||||
command: dpkg --add-architecture armhf
|
||||
when:
|
||||
- ansible_facts['distribution'] == 'Ubuntu'
|
||||
- ansible_facts['architecture'] == 'aarch64'
|
||||
|
||||
- name: Update apt cache / upgrade packages via apt
|
||||
apt:
|
||||
update_cache: yes
|
||||
upgrade: yes
|
||||
when:
|
||||
- ansible_facts['distribution'] == 'Ubuntu'
|
||||
- ansible_facts['distribution'] in ['Ubuntu', 'Debian']
|
||||
|
||||
# the package lists are updated by "make lcitool-refresh"
|
||||
- name: Include package lists based on OS and architecture
|
||||
include_vars:
|
||||
file: "ubuntu-2404-{{ ansible_facts['architecture'] }}.yaml"
|
||||
- name: Define package list file path for Ubuntu
|
||||
set_fact:
|
||||
package_file: "ubuntu/ubuntu-2404-{{ ansible_facts['architecture'] }}.yaml"
|
||||
when:
|
||||
- ansible_facts['distribution'] == 'Ubuntu'
|
||||
- ansible_facts['distribution_version'] == '24.04'
|
||||
|
||||
- name: Install packages for QEMU on Ubuntu 24.04
|
||||
- name: Define package list file path for Debian
|
||||
set_fact:
|
||||
package_file: "debian/debian-{{ ansible_facts['distribution_major_version'] }}-{{ ansible_facts['architecture'] }}.yaml"
|
||||
when:
|
||||
- ansible_facts['distribution'] == 'Debian'
|
||||
|
||||
- name: Include package lists based on OS and architecture
|
||||
include_vars:
|
||||
file: "{{ package_file }}"
|
||||
when:
|
||||
- package_file is exists
|
||||
|
||||
- name: Install packages for QEMU on Ubuntu/Debian
|
||||
package:
|
||||
name: "{{ packages }}"
|
||||
when:
|
||||
- ansible_facts['distribution'] == 'Ubuntu'
|
||||
- ansible_facts['distribution_version'] == '24.04'
|
||||
- package_file is exists
|
||||
- packages is defined
|
||||
|
||||
|
||||
134
scripts/ci/setup/debian/debian-13-ppc64le.yaml
Normal file
134
scripts/ci/setup/debian/debian-13-ppc64le.yaml
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
# THIS FILE WAS AUTO-GENERATED
|
||||
#
|
||||
# $ lcitool variables --host-arch ppc64le debian-13 qemu
|
||||
#
|
||||
# https://gitlab.com/libvirt/libvirt-ci
|
||||
|
||||
packages:
|
||||
- bash
|
||||
- bc
|
||||
- bindgen
|
||||
- bison
|
||||
- bsdextrautils
|
||||
- bzip2
|
||||
- ca-certificates
|
||||
- ccache
|
||||
- clang
|
||||
- dbus
|
||||
- debianutils
|
||||
- diffutils
|
||||
- exuberant-ctags
|
||||
- findutils
|
||||
- flex
|
||||
- gcc
|
||||
- gcovr
|
||||
- gettext
|
||||
- git
|
||||
- hostname
|
||||
- libaio-dev
|
||||
- libasan8
|
||||
- libasound2-dev
|
||||
- libattr1-dev
|
||||
- libbpf-dev
|
||||
- libbrlapi-dev
|
||||
- libbz2-dev
|
||||
- libc6-dev
|
||||
- libcacard-dev
|
||||
- libcap-ng-dev
|
||||
- libcapstone-dev
|
||||
- libcbor-dev
|
||||
- libclang-rt-dev
|
||||
- libcmocka-dev
|
||||
- libcurl4-gnutls-dev
|
||||
- libdaxctl-dev
|
||||
- libdrm-dev
|
||||
- libepoxy-dev
|
||||
- libfdt-dev
|
||||
- libffi-dev
|
||||
- libfuse3-dev
|
||||
- libgbm-dev
|
||||
- libgcrypt20-dev
|
||||
- libglib2.0-dev
|
||||
- libglusterfs-dev
|
||||
- libgnutls28-dev
|
||||
- libgtk-3-dev
|
||||
- libgtk-vnc-2.0-dev
|
||||
- libibverbs-dev
|
||||
- libiscsi-dev
|
||||
- libjemalloc-dev
|
||||
- libjpeg62-turbo-dev
|
||||
- libjson-c-dev
|
||||
- liblttng-ust-dev
|
||||
- liblzo2-dev
|
||||
- libncursesw5-dev
|
||||
- libnfs-dev
|
||||
- libnuma-dev
|
||||
- libpam0g-dev
|
||||
- libpcre2-dev
|
||||
- libpipewire-0.3-dev
|
||||
- libpixman-1-dev
|
||||
- libpng-dev
|
||||
- libpulse-dev
|
||||
- librbd-dev
|
||||
- librdmacm-dev
|
||||
- libsasl2-dev
|
||||
- libsdl2-dev
|
||||
- libsdl2-image-dev
|
||||
- libseccomp-dev
|
||||
- libselinux1-dev
|
||||
- libslirp-dev
|
||||
- libsnappy-dev
|
||||
- libsndio-dev
|
||||
- libspice-protocol-dev
|
||||
- libspice-server-dev
|
||||
- libssh-dev
|
||||
- libstd-rust-dev
|
||||
- libsystemd-dev
|
||||
- libtasn1-6-dev
|
||||
- libubsan1
|
||||
- libudev-dev
|
||||
- liburing-dev
|
||||
- libusb-1.0-0-dev
|
||||
- libusbredirhost-dev
|
||||
- libvdeplug-dev
|
||||
- libvirglrenderer-dev
|
||||
- libvte-2.91-dev
|
||||
- libxdp-dev
|
||||
- libzstd-dev
|
||||
- llvm
|
||||
- locales
|
||||
- make
|
||||
- mtools
|
||||
- multipath-tools
|
||||
- ncat
|
||||
- nettle-dev
|
||||
- ninja-build
|
||||
- openssh-client
|
||||
- pkgconf
|
||||
- python3
|
||||
- python3-numpy
|
||||
- python3-opencv
|
||||
- python3-pillow
|
||||
- python3-pip
|
||||
- python3-setuptools
|
||||
- python3-sphinx
|
||||
- python3-sphinx-rtd-theme
|
||||
- python3-tomli
|
||||
- python3-venv
|
||||
- python3-wheel
|
||||
- python3-yaml
|
||||
- rpm2cpio
|
||||
- rustc
|
||||
- sed
|
||||
- socat
|
||||
- sparse
|
||||
- swtpm
|
||||
- systemtap-sdt-dev
|
||||
- tar
|
||||
- tesseract-ocr
|
||||
- tesseract-ocr-eng
|
||||
- vulkan-tools
|
||||
- xorriso
|
||||
- zlib1g-dev
|
||||
- zstd
|
||||
|
||||
|
|
@ -56,12 +56,12 @@
|
|||
url: "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh"
|
||||
mode: 0755
|
||||
when:
|
||||
- ansible_facts['distribution'] == 'Ubuntu'
|
||||
- ansible_facts['distribution'] in ['Ubuntu', 'Debian']
|
||||
|
||||
- name: Run gitlab-runner repo setup script (DEB)
|
||||
shell: "/root/script.deb.sh"
|
||||
when:
|
||||
- ansible_facts['distribution'] == 'Ubuntu'
|
||||
- ansible_facts['distribution'] in ['Ubuntu', 'Debian']
|
||||
|
||||
- name: Install gitlab-runner (DEB)
|
||||
ansible.builtin.apt:
|
||||
|
|
@ -69,7 +69,7 @@
|
|||
update_cache: yes
|
||||
state: present
|
||||
when:
|
||||
- ansible_facts['distribution'] == 'Ubuntu'
|
||||
- ansible_facts['distribution'] in ['Ubuntu', 'Debian']
|
||||
|
||||
# RPM setup
|
||||
- name: Get gitlab-runner repo setup script (RPM)
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ packages:
|
|||
- git
|
||||
- hostname
|
||||
- libaio-dev
|
||||
- libasan6
|
||||
- libasan8
|
||||
- libasound2-dev
|
||||
- libattr1-dev
|
||||
- libbpf-dev
|
||||
|
|
@ -37,7 +37,7 @@ packages:
|
|||
- libcap-ng-dev
|
||||
- libcapstone-dev
|
||||
- libcbor-dev
|
||||
- libclang-dev
|
||||
- libclang-rt-dev
|
||||
- libcmocka-dev
|
||||
- libcurl4-gnutls-dev
|
||||
- libdaxctl-dev
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ packages:
|
|||
- git
|
||||
- hostname
|
||||
- libaio-dev
|
||||
- libasan6
|
||||
- libasan8
|
||||
- libasound2-dev
|
||||
- libattr1-dev
|
||||
- libbpf-dev
|
||||
|
|
@ -37,7 +37,7 @@ packages:
|
|||
- libcap-ng-dev
|
||||
- libcapstone-dev
|
||||
- libcbor-dev
|
||||
- libclang-dev
|
||||
- libclang-rt-dev
|
||||
- libcmocka-dev
|
||||
- libcurl4-gnutls-dev
|
||||
- libdaxctl-dev
|
||||
|
|
|
|||
|
|
@ -316,10 +316,7 @@ common_semi_flen_fstat_cb(CPUState *cs, uint64_t ret, int err)
|
|||
&size, 8, 0)) {
|
||||
ret = -1, err = EFAULT;
|
||||
} else {
|
||||
size = be64_to_cpu(size);
|
||||
if (ret != size) {
|
||||
ret = -1, err = EOVERFLOW;
|
||||
}
|
||||
ret = be64_to_cpu(size);
|
||||
}
|
||||
}
|
||||
common_semi_cb(cs, ret, err);
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "exec/helper-proto.h"
|
||||
#include "qemu/qemu-print.h"
|
||||
#include "system/memory.h"
|
||||
#include "qemu/plugin.h"
|
||||
|
||||
|
||||
#define CONVERT_BIT(X, SRC, DST) \
|
||||
|
|
@ -328,6 +329,7 @@ void alpha_cpu_do_interrupt(CPUState *cs)
|
|||
{
|
||||
CPUAlphaState *env = cpu_env(cs);
|
||||
int i = cs->exception_index;
|
||||
uint64_t last_pc = env->pc;
|
||||
|
||||
if (qemu_loglevel_mask(CPU_LOG_INT)) {
|
||||
static int count;
|
||||
|
|
@ -431,6 +433,17 @@ void alpha_cpu_do_interrupt(CPUState *cs)
|
|||
|
||||
/* Switch to PALmode. */
|
||||
env->flags |= ENV_FLAG_PAL_MODE;
|
||||
|
||||
switch (i) {
|
||||
case EXCP_SMP_INTERRUPT:
|
||||
case EXCP_CLK_INTERRUPT:
|
||||
case EXCP_DEV_INTERRUPT:
|
||||
qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
|
||||
break;
|
||||
default:
|
||||
qemu_plugin_vcpu_exception_cb(cs, last_pc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool alpha_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#endif
|
||||
#include "cpregs.h"
|
||||
#include "target/arm/gtimer.h"
|
||||
#include "qemu/plugin.h"
|
||||
|
||||
#define HELPER_H "tcg/helper.h"
|
||||
#include "exec/helper-proto.h.inc"
|
||||
|
|
@ -8783,6 +8784,24 @@ static void take_aarch32_exception(CPUARMState *env, int new_mode,
|
|||
}
|
||||
}
|
||||
|
||||
void arm_do_plugin_vcpu_discon_cb(CPUState *cs, uint64_t from)
|
||||
{
|
||||
switch (cs->exception_index) {
|
||||
case EXCP_IRQ:
|
||||
case EXCP_VIRQ:
|
||||
case EXCP_NMI:
|
||||
case EXCP_VINMI:
|
||||
case EXCP_FIQ:
|
||||
case EXCP_VFIQ:
|
||||
case EXCP_VFNMI:
|
||||
case EXCP_VSERR:
|
||||
qemu_plugin_vcpu_interrupt_cb(cs, from);
|
||||
break;
|
||||
default:
|
||||
qemu_plugin_vcpu_exception_cb(cs, from);
|
||||
}
|
||||
}
|
||||
|
||||
static void arm_cpu_do_interrupt_aarch32_hyp(CPUState *cs)
|
||||
{
|
||||
/*
|
||||
|
|
@ -9473,6 +9492,7 @@ void arm_cpu_do_interrupt(CPUState *cs)
|
|||
ARMCPU *cpu = ARM_CPU(cs);
|
||||
CPUARMState *env = &cpu->env;
|
||||
unsigned int new_el = env->exception.target_el;
|
||||
uint64_t last_pc = cs->cc->get_pc(cs);
|
||||
|
||||
assert(!arm_feature(env, ARM_FEATURE_M));
|
||||
|
||||
|
|
@ -9489,6 +9509,7 @@ void arm_cpu_do_interrupt(CPUState *cs)
|
|||
if (tcg_enabled() && arm_is_psci_call(cpu, cs->exception_index)) {
|
||||
arm_handle_psci_call(cpu);
|
||||
qemu_log_mask(CPU_LOG_INT, "...handled as PSCI call\n");
|
||||
qemu_plugin_vcpu_hostcall_cb(cs, last_pc);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -9500,6 +9521,7 @@ void arm_cpu_do_interrupt(CPUState *cs)
|
|||
#ifdef CONFIG_TCG
|
||||
if (cs->exception_index == EXCP_SEMIHOST) {
|
||||
tcg_handle_semihosting(cs);
|
||||
qemu_plugin_vcpu_hostcall_cb(cs, last_pc);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -9525,6 +9547,8 @@ void arm_cpu_do_interrupt(CPUState *cs)
|
|||
if (!kvm_enabled()) {
|
||||
cpu_set_interrupt(cs, CPU_INTERRUPT_EXITTB);
|
||||
}
|
||||
|
||||
arm_do_plugin_vcpu_discon_cb(cs, last_pc);
|
||||
}
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
||||
|
|
|
|||
|
|
@ -375,6 +375,7 @@ static inline int r14_bank_number(int mode)
|
|||
|
||||
void arm_cpu_register(const ARMCPUInfo *info);
|
||||
|
||||
void arm_do_plugin_vcpu_discon_cb(CPUState *cs, uint64_t from);
|
||||
void register_cp_regs_for_features(ARMCPU *cpu);
|
||||
void init_cpreg_list(ARMCPU *cpu);
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#if !defined(CONFIG_USER_ONLY)
|
||||
#include "hw/intc/armv7m_nvic.h"
|
||||
#endif
|
||||
#include "qemu/plugin.h"
|
||||
|
||||
static void v7m_msr_xpsr(CPUARMState *env, uint32_t mask,
|
||||
uint32_t reg, uint32_t val)
|
||||
|
|
@ -2194,6 +2195,7 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
|
|||
CPUARMState *env = &cpu->env;
|
||||
uint32_t lr;
|
||||
bool ignore_stackfaults;
|
||||
uint64_t last_pc = env->regs[15];
|
||||
|
||||
arm_log_exception(cs);
|
||||
|
||||
|
|
@ -2361,6 +2363,7 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
|
|||
g_assert_not_reached();
|
||||
#endif
|
||||
env->regs[15] += env->thumb ? 2 : 4;
|
||||
qemu_plugin_vcpu_hostcall_cb(cs, last_pc);
|
||||
return;
|
||||
case EXCP_BKPT:
|
||||
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_DEBUG, false);
|
||||
|
|
@ -2427,6 +2430,8 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
|
|||
|
||||
ignore_stackfaults = v7m_push_stack(cpu);
|
||||
v7m_exception_taken(cpu, lr, false, ignore_stackfaults);
|
||||
|
||||
arm_do_plugin_vcpu_discon_cb(cs, last_pc);
|
||||
}
|
||||
|
||||
uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include "exec/target_page.h"
|
||||
#include "accel/tcg/cpu-ldst.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "qemu/plugin.h"
|
||||
|
||||
bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
|
||||
{
|
||||
|
|
@ -102,6 +103,8 @@ void avr_cpu_do_interrupt(CPUState *cs)
|
|||
env->sregI = 0; /* clear Global Interrupt Flag */
|
||||
|
||||
cs->exception_index = -1;
|
||||
|
||||
qemu_plugin_vcpu_interrupt_cb(cs, ret);
|
||||
}
|
||||
|
||||
hwaddr avr_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include "exec/helper-proto.h"
|
||||
#include "hw/core/cpu.h"
|
||||
#include "hw/hppa/hppa_hardware.h"
|
||||
#include "qemu/plugin.h"
|
||||
|
||||
static void eval_interrupt(HPPACPU *cpu)
|
||||
{
|
||||
|
|
@ -95,6 +96,7 @@ void hppa_cpu_do_interrupt(CPUState *cs)
|
|||
CPUHPPAState *env = &cpu->env;
|
||||
int i = cs->exception_index;
|
||||
uint64_t old_psw, old_gva_offset_mask;
|
||||
uint64_t last_pc = cs->cc->get_pc(cs);
|
||||
|
||||
/* As documented in pa2.0 -- interruption handling. */
|
||||
/* step 1 */
|
||||
|
|
@ -212,6 +214,21 @@ void hppa_cpu_do_interrupt(CPUState *cs)
|
|||
env->iasq_f = 0;
|
||||
env->iasq_b = 0;
|
||||
|
||||
switch (i) {
|
||||
case EXCP_HPMC:
|
||||
case EXCP_POWER_FAIL:
|
||||
case EXCP_RC:
|
||||
case EXCP_EXT_INTERRUPT:
|
||||
case EXCP_LPMC:
|
||||
case EXCP_PER_INTERRUPT:
|
||||
case EXCP_TOC:
|
||||
qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
|
||||
break;
|
||||
default:
|
||||
qemu_plugin_vcpu_exception_cb(cs, last_pc);
|
||||
break;
|
||||
}
|
||||
|
||||
if (qemu_loglevel_mask(CPU_LOG_INT)) {
|
||||
static const char * const names[] = {
|
||||
[EXCP_HPMC] = "high priority machine check",
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include "system/runstate.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "helper-tcg.h"
|
||||
#include "qemu/plugin.h"
|
||||
|
||||
G_NORETURN void helper_raise_interrupt(CPUX86State *env, int intno,
|
||||
int next_eip_addend)
|
||||
|
|
@ -93,6 +94,7 @@ void raise_interrupt2(CPUX86State *env, int intno,
|
|||
uintptr_t retaddr)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
uint64_t last_pc = env->eip + env->segs[R_CS].base;
|
||||
|
||||
if (!is_int) {
|
||||
cpu_svm_check_intercept_param(env, SVM_EXIT_EXCP_BASE + intno,
|
||||
|
|
@ -106,6 +108,7 @@ void raise_interrupt2(CPUX86State *env, int intno,
|
|||
env->error_code = error_code;
|
||||
env->exception_is_int = is_int;
|
||||
env->exception_next_eip = env->eip + next_eip_addend;
|
||||
qemu_plugin_vcpu_exception_cb(cs, last_pc);
|
||||
cpu_loop_exit_restore(cs, retaddr);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "seg_helper.h"
|
||||
#include "access.h"
|
||||
#include "tcg-cpu.h"
|
||||
#include "qemu/plugin.h"
|
||||
|
||||
#ifdef TARGET_X86_64
|
||||
#define SET_ESP(val, sp_mask) \
|
||||
|
|
@ -1192,6 +1193,7 @@ void do_interrupt_all(X86CPU *cpu, int intno, int is_int,
|
|||
int error_code, target_ulong next_eip, int is_hw)
|
||||
{
|
||||
CPUX86State *env = &cpu->env;
|
||||
uint64_t last_pc = env->eip + env->segs[R_CS].base;
|
||||
|
||||
if (qemu_loglevel_mask(CPU_LOG_INT)) {
|
||||
if ((env->cr[0] & CR0_PE_MASK)) {
|
||||
|
|
@ -1263,6 +1265,8 @@ void do_interrupt_all(X86CPU *cpu, int intno, int is_int,
|
|||
event_inj & ~SVM_EVTINJ_VALID);
|
||||
}
|
||||
#endif
|
||||
|
||||
qemu_plugin_vcpu_interrupt_cb(CPU(cpu), last_pc);
|
||||
}
|
||||
|
||||
void do_interrupt_x86_hardirq(CPUX86State *env, int intno, int is_hw)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include "qemu/accel.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/plugin.h"
|
||||
#include "accel/accel-cpu-target.h"
|
||||
#include "accel/tcg/cpu-ldst.h"
|
||||
#include "accel/tcg/cpu-ops.h"
|
||||
|
|
@ -80,6 +81,7 @@ static void loongarch_cpu_do_interrupt(CPUState *cs)
|
|||
int cause = -1;
|
||||
bool tlbfill = FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR);
|
||||
uint32_t vec_size = FIELD_EX64(env->CSR_ECFG, CSR_ECFG, VS);
|
||||
uint64_t last_pc = env->pc;
|
||||
|
||||
if (cs->exception_index != EXCCODE_INT) {
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
|
|
@ -190,6 +192,7 @@ static void loongarch_cpu_do_interrupt(CPUState *cs)
|
|||
__func__, env->pc, env->CSR_ERA,
|
||||
cause, env->CSR_BADV, env->CSR_DERA, vector,
|
||||
env->CSR_ECFG, env->CSR_ESTAT);
|
||||
qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
|
||||
} else {
|
||||
if (tlbfill) {
|
||||
set_pc(env, env->CSR_TLBRENTRY);
|
||||
|
|
@ -208,6 +211,7 @@ static void loongarch_cpu_do_interrupt(CPUState *cs)
|
|||
tlbfill ? env->CSR_TLBRBADV : env->CSR_BADV,
|
||||
env->CSR_BADI, env->gpr[11], cs->cpu_index,
|
||||
env->CSR_ASID);
|
||||
qemu_plugin_vcpu_exception_cb(cs, last_pc);
|
||||
}
|
||||
cs->exception_index = -1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include "exec/helper-proto.h"
|
||||
#include "accel/tcg/cpu-ldst.h"
|
||||
#include "semihosting/semihost.h"
|
||||
#include "qemu/plugin.h"
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
|
||||
|
|
@ -183,6 +184,21 @@ static const char *m68k_exception_name(int index)
|
|||
return "Unassigned";
|
||||
}
|
||||
|
||||
static void do_plugin_vcpu_interrupt_cb(CPUState *cs, uint64_t from)
|
||||
{
|
||||
switch (cs->exception_index) {
|
||||
case EXCP_SPURIOUS ... EXCP_INT_LEVEL_7:
|
||||
qemu_plugin_vcpu_interrupt_cb(cs, from);
|
||||
break;
|
||||
case EXCP_SEMIHOSTING:
|
||||
qemu_plugin_vcpu_hostcall_cb(cs, from);
|
||||
break;
|
||||
default:
|
||||
qemu_plugin_vcpu_exception_cb(cs, from);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void cf_interrupt_all(CPUM68KState *env, int is_hw)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
|
|
@ -203,6 +219,7 @@ static void cf_interrupt_all(CPUM68KState *env, int is_hw)
|
|||
return;
|
||||
case EXCP_SEMIHOSTING:
|
||||
do_m68k_semihosting(env, env->dregs[0]);
|
||||
qemu_plugin_vcpu_hostcall_cb(cs, retaddr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -239,6 +256,8 @@ static void cf_interrupt_all(CPUM68KState *env, int is_hw)
|
|||
env->aregs[7] = sp;
|
||||
/* Jump to vector. */
|
||||
env->pc = cpu_ldl_mmuidx_ra(env, env->vbr + vector, MMU_KERNEL_IDX, 0);
|
||||
|
||||
do_plugin_vcpu_interrupt_cb(cs, retaddr);
|
||||
}
|
||||
|
||||
static inline void do_stack_frame(CPUM68KState *env, uint32_t *sp,
|
||||
|
|
@ -277,6 +296,7 @@ static void m68k_interrupt_all(CPUM68KState *env, int is_hw)
|
|||
uint32_t sp;
|
||||
uint32_t vector;
|
||||
uint16_t sr, oldsr;
|
||||
uint64_t last_pc = env->pc;
|
||||
|
||||
if (!is_hw) {
|
||||
switch (cs->exception_index) {
|
||||
|
|
@ -417,6 +437,8 @@ static void m68k_interrupt_all(CPUM68KState *env, int is_hw)
|
|||
env->aregs[7] = sp;
|
||||
/* Jump to vector. */
|
||||
env->pc = cpu_ldl_mmuidx_ra(env, env->vbr + vector, MMU_KERNEL_IDX, 0);
|
||||
|
||||
do_plugin_vcpu_interrupt_cb(cs, last_pc);
|
||||
}
|
||||
|
||||
static void do_interrupt_all(CPUM68KState *env, int is_hw)
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "qemu/host-utils.h"
|
||||
#include "exec/log.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "qemu/plugin.h"
|
||||
|
||||
|
||||
G_NORETURN
|
||||
|
|
@ -35,6 +36,7 @@ static void mb_unaligned_access_internal(CPUState *cs, uint64_t addr,
|
|||
{
|
||||
CPUMBState *env = cpu_env(cs);
|
||||
uint32_t esr, iflags;
|
||||
uint64_t last_pc = env->pc;
|
||||
|
||||
/* Recover the pc and iflags from the corresponding insn_start. */
|
||||
cpu_restore_state(cs, retaddr);
|
||||
|
|
@ -54,6 +56,7 @@ static void mb_unaligned_access_internal(CPUState *cs, uint64_t addr,
|
|||
env->ear = addr;
|
||||
env->esr = esr;
|
||||
cs->exception_index = EXCP_HW_EXCP;
|
||||
qemu_plugin_vcpu_exception_cb(cs, last_pc);
|
||||
cpu_loop_exit(cs);
|
||||
}
|
||||
|
||||
|
|
@ -152,6 +155,7 @@ void mb_cpu_do_interrupt(CPUState *cs)
|
|||
CPUMBState *env = &cpu->env;
|
||||
uint32_t t, msr = mb_cpu_read_msr(env);
|
||||
bool set_esr;
|
||||
uint64_t last_pc = env->pc;
|
||||
|
||||
/* IMM flag cannot propagate across a branch and into the dslot. */
|
||||
assert((env->iflags & (D_FLAG | IMM_FLAG)) != (D_FLAG | IMM_FLAG));
|
||||
|
|
@ -256,6 +260,12 @@ void mb_cpu_do_interrupt(CPUState *cs)
|
|||
env->res_addr = RES_ADDR_NONE;
|
||||
env->iflags = 0;
|
||||
|
||||
if (cs->exception_index == EXCP_IRQ) {
|
||||
qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
|
||||
} else {
|
||||
qemu_plugin_vcpu_exception_cb(cs, last_pc);
|
||||
}
|
||||
|
||||
if (!set_esr) {
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
" to pc=%08x msr=%08x\n", env->pc, msr);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "qemu/plugin.h"
|
||||
|
||||
#include "cpu.h"
|
||||
#include "internal.h"
|
||||
|
|
@ -1034,6 +1035,7 @@ void mips_cpu_do_interrupt(CPUState *cs)
|
|||
bool update_badinstr = 0;
|
||||
target_ulong offset;
|
||||
int cause = -1;
|
||||
uint64_t last_pc = env->active_tc.PC;
|
||||
|
||||
if (qemu_loglevel_mask(CPU_LOG_INT)
|
||||
&& cs->exception_index != EXCP_EXT_INTERRUPT) {
|
||||
|
|
@ -1052,6 +1054,7 @@ void mips_cpu_do_interrupt(CPUState *cs)
|
|||
cs->exception_index = EXCP_NONE;
|
||||
mips_semihosting(env);
|
||||
env->active_tc.PC += env->error_code;
|
||||
qemu_plugin_vcpu_hostcall_cb(cs, last_pc);
|
||||
return;
|
||||
case EXCP_DSS:
|
||||
env->CP0_Debug |= 1 << CP0DB_DSS;
|
||||
|
|
@ -1336,6 +1339,14 @@ void mips_cpu_do_interrupt(CPUState *cs)
|
|||
env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr,
|
||||
env->CP0_DEPC);
|
||||
}
|
||||
switch (cs->exception_index) {
|
||||
case EXCP_NMI:
|
||||
case EXCP_EXT_INTERRUPT:
|
||||
qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
|
||||
break;
|
||||
default:
|
||||
qemu_plugin_vcpu_exception_cb(cs, last_pc);
|
||||
}
|
||||
cs->exception_index = EXCP_NONE;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,11 +25,13 @@
|
|||
#ifndef CONFIG_USER_ONLY
|
||||
#include "hw/loader.h"
|
||||
#endif
|
||||
#include "qemu/plugin.h"
|
||||
|
||||
void openrisc_cpu_do_interrupt(CPUState *cs)
|
||||
{
|
||||
CPUOpenRISCState *env = cpu_env(cs);
|
||||
int exception = cs->exception_index;
|
||||
uint64_t last_pc = env->pc;
|
||||
|
||||
env->epcr = env->pc;
|
||||
|
||||
|
|
@ -98,6 +100,19 @@ void openrisc_cpu_do_interrupt(CPUState *cs)
|
|||
cpu_abort(cs, "Unhandled exception 0x%x\n", exception);
|
||||
}
|
||||
|
||||
switch (exception) {
|
||||
case EXCP_RESET:
|
||||
/* Resets are already exposed to plugins through a dedicated callback */
|
||||
break;
|
||||
case EXCP_TICK:
|
||||
case EXCP_INT:
|
||||
qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
|
||||
break;
|
||||
default:
|
||||
qemu_plugin_vcpu_exception_cb(cs, last_pc);
|
||||
break;
|
||||
}
|
||||
|
||||
cs->exception_index = -1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "internal.h"
|
||||
#include "helper_regs.h"
|
||||
#include "hw/ppc/ppc.h"
|
||||
#include "qemu/plugin.h"
|
||||
|
||||
#include "trace.h"
|
||||
|
||||
|
|
@ -404,11 +405,31 @@ static void powerpc_mcheck_checkstop(CPUPPCState *env)
|
|||
powerpc_checkstop(env, "machine check with MSR[ME]=0");
|
||||
}
|
||||
|
||||
static void powerpc_do_plugin_vcpu_interrupt_cb(CPUState *cs, int excp,
|
||||
uint64_t from)
|
||||
{
|
||||
switch (excp) {
|
||||
case POWERPC_EXCP_NONE:
|
||||
break;
|
||||
case POWERPC_EXCP_FIT:
|
||||
case POWERPC_EXCP_WDT:
|
||||
case POWERPC_EXCP_PIT:
|
||||
case POWERPC_EXCP_SMI:
|
||||
case POWERPC_EXCP_PERFM:
|
||||
case POWERPC_EXCP_THERM:
|
||||
qemu_plugin_vcpu_interrupt_cb(cs, from);
|
||||
break;
|
||||
default:
|
||||
qemu_plugin_vcpu_exception_cb(cs, from);
|
||||
}
|
||||
}
|
||||
|
||||
static void powerpc_excp_40x(PowerPCCPU *cpu, int excp)
|
||||
{
|
||||
CPUPPCState *env = &cpu->env;
|
||||
target_ulong msr, new_msr, vector;
|
||||
int srr0 = SPR_SRR0, srr1 = SPR_SRR1;
|
||||
uint64_t last_pc = env->nip;
|
||||
|
||||
/* new srr1 value excluding must-be-zero bits */
|
||||
msr = env->msr & ~0x783f0000ULL;
|
||||
|
|
@ -456,6 +477,7 @@ static void powerpc_excp_40x(PowerPCCPU *cpu, int excp)
|
|||
if (!FIELD_EX64_FE(env->msr) || !FIELD_EX64(env->msr, MSR, FP)) {
|
||||
trace_ppc_excp_fp_ignore();
|
||||
powerpc_reset_excp_state(cpu);
|
||||
qemu_plugin_vcpu_exception_cb(env_cpu(env), last_pc);
|
||||
return;
|
||||
}
|
||||
env->spr[SPR_40x_ESR] = ESR_FP;
|
||||
|
|
@ -510,12 +532,14 @@ static void powerpc_excp_40x(PowerPCCPU *cpu, int excp)
|
|||
env->spr[srr0] = env->nip;
|
||||
env->spr[srr1] = msr;
|
||||
powerpc_set_excp_state(cpu, vector, new_msr);
|
||||
powerpc_do_plugin_vcpu_interrupt_cb(env_cpu(env), excp, last_pc);
|
||||
}
|
||||
|
||||
static void powerpc_excp_6xx(PowerPCCPU *cpu, int excp)
|
||||
{
|
||||
CPUPPCState *env = &cpu->env;
|
||||
target_ulong msr, new_msr, vector;
|
||||
uint64_t last_pc = env->nip;
|
||||
|
||||
/* new srr1 value excluding must-be-zero bits */
|
||||
msr = env->msr & ~0x783f0000ULL;
|
||||
|
|
@ -567,6 +591,7 @@ static void powerpc_excp_6xx(PowerPCCPU *cpu, int excp)
|
|||
if (!FIELD_EX64_FE(env->msr) || !FIELD_EX64(env->msr, MSR, FP)) {
|
||||
trace_ppc_excp_fp_ignore();
|
||||
powerpc_reset_excp_state(cpu);
|
||||
qemu_plugin_vcpu_exception_cb(env_cpu(env), last_pc);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
|
|
@ -653,12 +678,14 @@ static void powerpc_excp_6xx(PowerPCCPU *cpu, int excp)
|
|||
env->spr[SPR_SRR0] = env->nip;
|
||||
env->spr[SPR_SRR1] = msr;
|
||||
powerpc_set_excp_state(cpu, vector, new_msr);
|
||||
powerpc_do_plugin_vcpu_interrupt_cb(env_cpu(env), excp, last_pc);
|
||||
}
|
||||
|
||||
static void powerpc_excp_7xx(PowerPCCPU *cpu, int excp)
|
||||
{
|
||||
CPUPPCState *env = &cpu->env;
|
||||
target_ulong msr, new_msr, vector;
|
||||
uint64_t last_pc = env->nip;
|
||||
|
||||
/* new srr1 value excluding must-be-zero bits */
|
||||
msr = env->msr & ~0x783f0000ULL;
|
||||
|
|
@ -708,6 +735,7 @@ static void powerpc_excp_7xx(PowerPCCPU *cpu, int excp)
|
|||
if (!FIELD_EX64_FE(env->msr) || !FIELD_EX64(env->msr, MSR, FP)) {
|
||||
trace_ppc_excp_fp_ignore();
|
||||
powerpc_reset_excp_state(cpu);
|
||||
qemu_plugin_vcpu_exception_cb(env_cpu(env), last_pc);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
|
|
@ -758,6 +786,7 @@ static void powerpc_excp_7xx(PowerPCCPU *cpu, int excp)
|
|||
if (lev == 1 && cpu->vhyp) {
|
||||
cpu->vhyp_class->hypercall(cpu->vhyp, cpu);
|
||||
powerpc_reset_excp_state(cpu);
|
||||
qemu_plugin_vcpu_hostcall_cb(env_cpu(env), last_pc);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -803,12 +832,14 @@ static void powerpc_excp_7xx(PowerPCCPU *cpu, int excp)
|
|||
env->spr[SPR_SRR0] = env->nip;
|
||||
env->spr[SPR_SRR1] = msr;
|
||||
powerpc_set_excp_state(cpu, vector, new_msr);
|
||||
powerpc_do_plugin_vcpu_interrupt_cb(env_cpu(env), excp, last_pc);
|
||||
}
|
||||
|
||||
static void powerpc_excp_74xx(PowerPCCPU *cpu, int excp)
|
||||
{
|
||||
CPUPPCState *env = &cpu->env;
|
||||
target_ulong msr, new_msr, vector;
|
||||
uint64_t last_pc = env->nip;
|
||||
|
||||
/* new srr1 value excluding must-be-zero bits */
|
||||
msr = env->msr & ~0x783f0000ULL;
|
||||
|
|
@ -858,6 +889,7 @@ static void powerpc_excp_74xx(PowerPCCPU *cpu, int excp)
|
|||
if (!FIELD_EX64_FE(env->msr) || !FIELD_EX64(env->msr, MSR, FP)) {
|
||||
trace_ppc_excp_fp_ignore();
|
||||
powerpc_reset_excp_state(cpu);
|
||||
qemu_plugin_vcpu_exception_cb(env_cpu(env), last_pc);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
|
|
@ -908,6 +940,7 @@ static void powerpc_excp_74xx(PowerPCCPU *cpu, int excp)
|
|||
if (lev == 1 && cpu->vhyp) {
|
||||
cpu->vhyp_class->hypercall(cpu->vhyp, cpu);
|
||||
powerpc_reset_excp_state(cpu);
|
||||
qemu_plugin_vcpu_hostcall_cb(env_cpu(env), last_pc);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -947,6 +980,7 @@ static void powerpc_excp_74xx(PowerPCCPU *cpu, int excp)
|
|||
env->spr[SPR_SRR0] = env->nip;
|
||||
env->spr[SPR_SRR1] = msr;
|
||||
powerpc_set_excp_state(cpu, vector, new_msr);
|
||||
powerpc_do_plugin_vcpu_interrupt_cb(env_cpu(env), excp, last_pc);
|
||||
}
|
||||
|
||||
static void powerpc_excp_ppe42(PowerPCCPU *cpu, int excp)
|
||||
|
|
@ -1073,6 +1107,7 @@ static void powerpc_excp_booke(PowerPCCPU *cpu, int excp)
|
|||
CPUPPCState *env = &cpu->env;
|
||||
target_ulong msr, new_msr, vector;
|
||||
int srr0 = SPR_SRR0, srr1 = SPR_SRR1;
|
||||
uint64_t last_pc = env->nip;
|
||||
|
||||
/*
|
||||
* Book E does not play games with certain bits of xSRR1 being MSR save
|
||||
|
|
@ -1144,6 +1179,7 @@ static void powerpc_excp_booke(PowerPCCPU *cpu, int excp)
|
|||
if (!FIELD_EX64_FE(env->msr) || !FIELD_EX64(env->msr, MSR, FP)) {
|
||||
trace_ppc_excp_fp_ignore();
|
||||
powerpc_reset_excp_state(cpu);
|
||||
qemu_plugin_vcpu_exception_cb(env_cpu(env), last_pc);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
|
|
@ -1252,6 +1288,7 @@ static void powerpc_excp_booke(PowerPCCPU *cpu, int excp)
|
|||
env->spr[srr0] = env->nip;
|
||||
env->spr[srr1] = msr;
|
||||
powerpc_set_excp_state(cpu, vector, new_msr);
|
||||
powerpc_do_plugin_vcpu_interrupt_cb(env_cpu(env), excp, last_pc);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1373,6 +1410,7 @@ static void powerpc_excp_books(PowerPCCPU *cpu, int excp)
|
|||
CPUPPCState *env = &cpu->env;
|
||||
target_ulong msr, new_msr, vector;
|
||||
int srr0 = SPR_SRR0, srr1 = SPR_SRR1, lev = -1;
|
||||
uint64_t last_pc = env->nip;
|
||||
|
||||
/* new srr1 value excluding must-be-zero bits */
|
||||
msr = env->msr & ~0x783f0000ULL;
|
||||
|
|
@ -1472,6 +1510,7 @@ static void powerpc_excp_books(PowerPCCPU *cpu, int excp)
|
|||
if (!FIELD_EX64_FE(env->msr) || !FIELD_EX64(env->msr, MSR, FP)) {
|
||||
trace_ppc_excp_fp_ignore();
|
||||
powerpc_reset_excp_state(cpu);
|
||||
qemu_plugin_vcpu_exception_cb(env_cpu(env), last_pc);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
|
|
@ -1516,6 +1555,7 @@ static void powerpc_excp_books(PowerPCCPU *cpu, int excp)
|
|||
if (lev == 1 && books_vhyp_handles_hcall(cpu)) {
|
||||
cpu->vhyp_class->hypercall(cpu->vhyp, cpu);
|
||||
powerpc_reset_excp_state(cpu);
|
||||
qemu_plugin_vcpu_hostcall_cb(env_cpu(env), last_pc);
|
||||
return;
|
||||
}
|
||||
if (env->insns_flags2 & PPC2_ISA310) {
|
||||
|
|
@ -1662,6 +1702,7 @@ static void powerpc_excp_books(PowerPCCPU *cpu, int excp)
|
|||
ppc_excp_apply_ail(cpu, excp, msr, &new_msr, &vector);
|
||||
powerpc_set_excp_state(cpu, vector, new_msr);
|
||||
}
|
||||
powerpc_do_plugin_vcpu_interrupt_cb(env_cpu(env), excp, last_pc);
|
||||
}
|
||||
#else
|
||||
static inline void powerpc_excp_books(PowerPCCPU *cpu, int excp)
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#include "cpu_bits.h"
|
||||
#include "debug.h"
|
||||
#include "pmp.h"
|
||||
#include "qemu/plugin.h"
|
||||
|
||||
int riscv_env_mmu_index(CPURISCVState *env, bool ifetch)
|
||||
{
|
||||
|
|
@ -2175,6 +2176,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
|||
uint64_t hdeleg = async ? env->hideleg : env->hedeleg;
|
||||
const bool prev_virt = env->virt_enabled;
|
||||
const target_ulong prev_priv = env->priv;
|
||||
uint64_t last_pc = env->pc;
|
||||
target_ulong tval = 0;
|
||||
target_ulong tinst = 0;
|
||||
target_ulong htval = 0;
|
||||
|
|
@ -2197,6 +2199,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
|||
case RISCV_EXCP_SEMIHOST:
|
||||
do_common_semihosting(cs);
|
||||
env->pc += 4;
|
||||
qemu_plugin_vcpu_hostcall_cb(cs, last_pc);
|
||||
return;
|
||||
#endif
|
||||
case RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT:
|
||||
|
|
@ -2466,6 +2469,12 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
|||
prev_priv, prev_virt);
|
||||
}
|
||||
|
||||
if (async) {
|
||||
qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
|
||||
} else {
|
||||
qemu_plugin_vcpu_exception_cb(cs, last_pc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Interrupt/exception/trap delivery is asynchronous event and as per
|
||||
* zicfilp spec CPU should clear up the ELP state. No harm in clearing
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include "exec/log.h"
|
||||
#include "accel/tcg/cpu-ldst.h"
|
||||
#include "hw/irq.h"
|
||||
#include "qemu/plugin.h"
|
||||
|
||||
void rx_cpu_unpack_psw(CPURXState *env, uint32_t psw, int rte)
|
||||
{
|
||||
|
|
@ -46,6 +47,7 @@ void rx_cpu_do_interrupt(CPUState *cs)
|
|||
CPURXState *env = cpu_env(cs);
|
||||
int do_irq = cpu_test_interrupt(cs, INT_FLAGS);
|
||||
uint32_t save_psw;
|
||||
uint64_t last_pc = env->pc;
|
||||
|
||||
env->in_sleep = 0;
|
||||
|
||||
|
|
@ -65,6 +67,7 @@ void rx_cpu_do_interrupt(CPUState *cs)
|
|||
env->psw_ipl = 15;
|
||||
cpu_reset_interrupt(cs, CPU_INTERRUPT_FIR);
|
||||
qemu_set_irq(env->ack, env->ack_irq);
|
||||
qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
|
||||
qemu_log_mask(CPU_LOG_INT, "fast interrupt raised\n");
|
||||
} else if (do_irq & CPU_INTERRUPT_HARD) {
|
||||
env->isp -= 4;
|
||||
|
|
@ -75,6 +78,7 @@ void rx_cpu_do_interrupt(CPUState *cs)
|
|||
env->psw_ipl = env->ack_ipl;
|
||||
cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
|
||||
qemu_set_irq(env->ack, env->ack_irq);
|
||||
qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"interrupt 0x%02x raised\n", env->ack_irq);
|
||||
}
|
||||
|
|
@ -92,6 +96,14 @@ void rx_cpu_do_interrupt(CPUState *cs)
|
|||
} else {
|
||||
env->pc = cpu_ldl_data(env, env->intb + (vec & 0xff) * 4);
|
||||
}
|
||||
|
||||
if (vec == 30) {
|
||||
/* Non-maskable interrupt */
|
||||
qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
|
||||
} else {
|
||||
qemu_plugin_vcpu_exception_cb(cs, last_pc);
|
||||
}
|
||||
|
||||
switch (vec) {
|
||||
case 20:
|
||||
expname = "privilege violation";
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include "hw/s390x/s390_flic.h"
|
||||
#include "hw/boards.h"
|
||||
#endif
|
||||
#include "qemu/plugin.h"
|
||||
|
||||
G_NORETURN void tcg_s390_program_interrupt(CPUS390XState *env,
|
||||
uint32_t code, uintptr_t ra)
|
||||
|
|
@ -502,6 +503,7 @@ void s390_cpu_do_interrupt(CPUState *cs)
|
|||
S390CPU *cpu = S390_CPU(cs);
|
||||
CPUS390XState *env = &cpu->env;
|
||||
bool stopped = false;
|
||||
uint64_t last_pc = cpu->env.psw.addr;
|
||||
|
||||
qemu_log_mask(CPU_LOG_INT, "%s: %d at psw=%" PRIx64 ":%" PRIx64 "\n",
|
||||
__func__, cs->exception_index, env->psw.mask, env->psw.addr);
|
||||
|
|
@ -531,21 +533,27 @@ try_deliver:
|
|||
switch (cs->exception_index) {
|
||||
case EXCP_PGM:
|
||||
do_program_interrupt(env);
|
||||
qemu_plugin_vcpu_exception_cb(cs, last_pc);
|
||||
break;
|
||||
case EXCP_SVC:
|
||||
do_svc_interrupt(env);
|
||||
qemu_plugin_vcpu_exception_cb(cs, last_pc);
|
||||
break;
|
||||
case EXCP_EXT:
|
||||
do_ext_interrupt(env);
|
||||
qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
|
||||
break;
|
||||
case EXCP_IO:
|
||||
do_io_interrupt(env);
|
||||
qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
|
||||
break;
|
||||
case EXCP_MCHK:
|
||||
do_mchk_interrupt(env);
|
||||
qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
|
||||
break;
|
||||
case EXCP_RESTART:
|
||||
do_restart_interrupt(env);
|
||||
qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
|
||||
break;
|
||||
case EXCP_STOP:
|
||||
do_stop_interrupt(env);
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include "exec/page-protection.h"
|
||||
#include "exec/target_page.h"
|
||||
#include "exec/log.h"
|
||||
#include "qemu/plugin.h"
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
#include "hw/sh4/sh_intc.h"
|
||||
|
|
@ -60,6 +61,7 @@ void superh_cpu_do_interrupt(CPUState *cs)
|
|||
CPUSH4State *env = cpu_env(cs);
|
||||
int do_irq = cpu_test_interrupt(cs, CPU_INTERRUPT_HARD);
|
||||
int do_exp, irq_vector = cs->exception_index;
|
||||
uint64_t last_pc = env->pc;
|
||||
|
||||
/* prioritize exceptions over interrupts */
|
||||
|
||||
|
|
@ -176,12 +178,14 @@ void superh_cpu_do_interrupt(CPUState *cs)
|
|||
env->pc = env->vbr + 0x100;
|
||||
break;
|
||||
}
|
||||
qemu_plugin_vcpu_exception_cb(cs, last_pc);
|
||||
return;
|
||||
}
|
||||
|
||||
if (do_irq) {
|
||||
env->intevt = irq_vector;
|
||||
env->pc = env->vbr + 0x600;
|
||||
qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include "accel/tcg/cpu-ldst.h"
|
||||
#include "exec/log.h"
|
||||
#include "system/runstate.h"
|
||||
#include "qemu/plugin.h"
|
||||
|
||||
static const char * const excp_names[0x80] = {
|
||||
[TT_TFAULT] = "Instruction Access Fault",
|
||||
|
|
@ -174,4 +175,10 @@ void sparc_cpu_do_interrupt(CPUState *cs)
|
|||
env->qemu_irq_ack(env, intno);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (intno == TT_EXTINT) {
|
||||
qemu_plugin_vcpu_interrupt_cb(cs, env->regwptr[9]);
|
||||
} else {
|
||||
qemu_plugin_vcpu_exception_cb(cs, env->regwptr[9]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include "exec/helper-proto.h"
|
||||
#include "exec/log.h"
|
||||
#include "trace.h"
|
||||
#include "qemu/plugin.h"
|
||||
|
||||
#define DEBUG_PCALL
|
||||
|
||||
|
|
@ -256,6 +257,15 @@ void sparc_cpu_do_interrupt(CPUState *cs)
|
|||
}
|
||||
env->npc = env->pc + 4;
|
||||
cs->exception_index = -1;
|
||||
|
||||
switch (intno) {
|
||||
case TT_EXTINT:
|
||||
case TT_IVEC:
|
||||
qemu_plugin_vcpu_interrupt_cb(cs, tsptr->tpc);
|
||||
break;
|
||||
default:
|
||||
qemu_plugin_vcpu_exception_cb(cs, tsptr->tpc);
|
||||
}
|
||||
}
|
||||
|
||||
trap_state *cpu_tsptr(CPUSPARCState* env)
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include "qemu/host-utils.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "accel/tcg/cpu-ldst.h"
|
||||
#include "qemu/plugin.h"
|
||||
#include <zlib.h> /* for crc32 */
|
||||
|
||||
|
||||
|
|
@ -29,8 +30,11 @@ void raise_exception_sync_internal(CPUTriCoreState *env, uint32_t class, int tin
|
|||
uintptr_t pc, uint32_t fcd_pc)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
uint64_t last_pc;
|
||||
|
||||
/* in case we come from a helper-call we need to restore the PC */
|
||||
cpu_restore_state(cs, pc);
|
||||
last_pc = env->PC;
|
||||
|
||||
/* Tin is loaded into d[15] */
|
||||
env->gpr_d[15] = tin;
|
||||
|
|
@ -90,6 +94,7 @@ void raise_exception_sync_internal(CPUTriCoreState *env, uint32_t class, int tin
|
|||
/* Update PC using the trap vector table */
|
||||
env->PC = env->BTV | (class << 5);
|
||||
|
||||
qemu_plugin_vcpu_exception_cb(cs, last_pc);
|
||||
cpu_loop_exit(cs);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include "exec/helper-proto.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include "qemu/atomic.h"
|
||||
#include "qemu/plugin.h"
|
||||
|
||||
void HELPER(exception)(CPUXtensaState *env, uint32_t excp)
|
||||
{
|
||||
|
|
@ -207,6 +208,8 @@ void xtensa_cpu_do_interrupt(CPUState *cs)
|
|||
CPUXtensaState *env = cpu_env(cs);
|
||||
|
||||
if (cs->exception_index == EXC_IRQ) {
|
||||
uint64_t last_pc = env->pc;
|
||||
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"%s(EXC_IRQ) level = %d, cintlevel = %d, "
|
||||
"pc = %08x, a0 = %08x, ps = %08x, "
|
||||
|
|
@ -218,6 +221,7 @@ void xtensa_cpu_do_interrupt(CPUState *cs)
|
|||
env->sregs[INTSET], env->sregs[INTENABLE],
|
||||
env->sregs[CCOUNT]);
|
||||
handle_interrupt(env);
|
||||
qemu_plugin_vcpu_interrupt_cb(cs, last_pc);
|
||||
}
|
||||
|
||||
switch (cs->exception_index) {
|
||||
|
|
@ -238,9 +242,11 @@ void xtensa_cpu_do_interrupt(CPUState *cs)
|
|||
env->sregs[CCOUNT]);
|
||||
if (env->config->exception_vector[cs->exception_index]) {
|
||||
uint32_t vector;
|
||||
uint64_t last_pc = env->pc;
|
||||
|
||||
vector = env->config->exception_vector[cs->exception_index];
|
||||
env->pc = relocated_vector(env, vector);
|
||||
qemu_plugin_vcpu_exception_cb(cs, last_pc);
|
||||
} else {
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"%s(pc = %08x) bad exception_index: %d\n",
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include "system/memory.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/plugin.h"
|
||||
|
||||
enum {
|
||||
TARGET_SYS_exit = 1,
|
||||
|
|
@ -197,6 +198,7 @@ void HELPER(simcall)(CPUXtensaState *env)
|
|||
CPUState *cs = env_cpu(env);
|
||||
AddressSpace *as = cs->as;
|
||||
uint32_t *regs = env->regs;
|
||||
uint64_t last_pc = env->pc;
|
||||
|
||||
switch (regs[2]) {
|
||||
case TARGET_SYS_exit:
|
||||
|
|
@ -433,4 +435,5 @@ void HELPER(simcall)(CPUXtensaState *env)
|
|||
regs[3] = TARGET_ENOSYS;
|
||||
break;
|
||||
}
|
||||
qemu_plugin_vcpu_hostcall_cb(cs, last_pc);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -272,6 +272,7 @@ try:
|
|||
#
|
||||
generate_yaml("ubuntu", "ubuntu-2404", "aarch64")
|
||||
generate_yaml("ubuntu", "ubuntu-2404", "s390x")
|
||||
generate_yaml("debian", "debian-13", "ppc64le")
|
||||
|
||||
|
||||
sys.exit(0)
|
||||
|
|
|
|||
221
tests/tcg/plugins/discons.c
Normal file
221
tests/tcg/plugins/discons.c
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright (C) 2025, Julian Ganz <neither@nut.email>
|
||||
*
|
||||
* This plugin exercises the discontinuity plugin API and asserts some
|
||||
* of its behaviour regarding reported program counters.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
|
||||
#include <qemu-plugin.h>
|
||||
|
||||
QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
|
||||
|
||||
struct cpu_state {
|
||||
uint64_t last_pc;
|
||||
uint64_t from_pc;
|
||||
uint64_t next_pc;
|
||||
uint64_t has_from;
|
||||
bool has_next;
|
||||
enum qemu_plugin_discon_type next_type;
|
||||
};
|
||||
|
||||
struct insn_data {
|
||||
uint64_t addr;
|
||||
uint64_t next_pc;
|
||||
bool next_valid;
|
||||
};
|
||||
|
||||
static struct qemu_plugin_scoreboard *states;
|
||||
|
||||
static qemu_plugin_u64 last_pc;
|
||||
static qemu_plugin_u64 from_pc;
|
||||
static qemu_plugin_u64 has_from;
|
||||
|
||||
static bool abort_on_mismatch;
|
||||
static bool trace_all_insns;
|
||||
|
||||
static bool addr_eq(uint64_t a, uint64_t b)
|
||||
{
|
||||
if (a == b) {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t a_hw;
|
||||
uint64_t b_hw;
|
||||
if (!qemu_plugin_translate_vaddr(a, &a_hw) ||
|
||||
!qemu_plugin_translate_vaddr(b, &b_hw))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return a_hw == b_hw;
|
||||
}
|
||||
|
||||
static void report_mismatch(const char *pc_name, unsigned int vcpu_index,
|
||||
enum qemu_plugin_discon_type type, uint64_t last,
|
||||
uint64_t expected, uint64_t encountered)
|
||||
{
|
||||
gchar *report;
|
||||
const char *discon_type_name = "unknown";
|
||||
|
||||
if (addr_eq(expected, encountered)) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case QEMU_PLUGIN_DISCON_INTERRUPT:
|
||||
discon_type_name = "interrupt";
|
||||
break;
|
||||
case QEMU_PLUGIN_DISCON_EXCEPTION:
|
||||
discon_type_name = "exception";
|
||||
break;
|
||||
case QEMU_PLUGIN_DISCON_HOSTCALL:
|
||||
discon_type_name = "hostcall";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
report = g_strdup_printf("Discon %s PC mismatch on VCPU %d\n"
|
||||
"Expected: %"PRIx64"\nEncountered: %"
|
||||
PRIx64"\nExecuted Last: %"PRIx64
|
||||
"\nEvent type: %s\n",
|
||||
pc_name, vcpu_index, expected, encountered, last,
|
||||
discon_type_name);
|
||||
if (abort_on_mismatch) {
|
||||
/*
|
||||
* The qemu log infrastructure may lose messages when aborting. Using
|
||||
* fputs directly ensures the final report is visible to developers.
|
||||
*/
|
||||
fputs(report, stderr);
|
||||
g_abort();
|
||||
} else {
|
||||
qemu_plugin_outs(report);
|
||||
}
|
||||
g_free(report);
|
||||
}
|
||||
|
||||
static void vcpu_discon(qemu_plugin_id_t id, unsigned int vcpu_index,
|
||||
enum qemu_plugin_discon_type type, uint64_t from_pc,
|
||||
uint64_t to_pc)
|
||||
{
|
||||
struct cpu_state *state = qemu_plugin_scoreboard_find(states, vcpu_index);
|
||||
|
||||
if (type == QEMU_PLUGIN_DISCON_EXCEPTION &&
|
||||
addr_eq(state->last_pc, from_pc))
|
||||
{
|
||||
/*
|
||||
* For some types of exceptions, insn_exec will be called for the
|
||||
* instruction that caused the exception. This is valid behaviour and
|
||||
* does not need to be reported.
|
||||
*/
|
||||
} else if (state->has_next) {
|
||||
/*
|
||||
* We may encounter discontinuity chains without any instructions
|
||||
* being executed in between.
|
||||
*/
|
||||
report_mismatch("source", vcpu_index, type, state->last_pc,
|
||||
state->next_pc, from_pc);
|
||||
} else if (state->has_from) {
|
||||
report_mismatch("source", vcpu_index, type, state->last_pc,
|
||||
state->from_pc, from_pc);
|
||||
}
|
||||
|
||||
state->has_from = false;
|
||||
|
||||
state->next_pc = to_pc;
|
||||
state->next_type = type;
|
||||
state->has_next = true;
|
||||
}
|
||||
|
||||
static void insn_exec(unsigned int vcpu_index, void *userdata)
|
||||
{
|
||||
struct cpu_state *state = qemu_plugin_scoreboard_find(states, vcpu_index);
|
||||
|
||||
if (state->has_next) {
|
||||
report_mismatch("target", vcpu_index, state->next_type, state->last_pc,
|
||||
state->next_pc, state->last_pc);
|
||||
state->has_next = false;
|
||||
}
|
||||
|
||||
if (trace_all_insns) {
|
||||
g_autoptr(GString) report = g_string_new(NULL);
|
||||
g_string_append_printf(report, "Exec insn at %"PRIx64" on VCPU %d\n",
|
||||
state->last_pc, vcpu_index);
|
||||
qemu_plugin_outs(report->str);
|
||||
}
|
||||
}
|
||||
|
||||
static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
|
||||
{
|
||||
size_t n_insns = qemu_plugin_tb_n_insns(tb);
|
||||
for (size_t i = 0; i < n_insns; i++) {
|
||||
struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, i);
|
||||
uint64_t pc = qemu_plugin_insn_vaddr(insn);
|
||||
uint64_t next_pc = pc + qemu_plugin_insn_size(insn);
|
||||
uint64_t has_next = (i + 1) < n_insns;
|
||||
|
||||
qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu(insn,
|
||||
QEMU_PLUGIN_INLINE_STORE_U64,
|
||||
last_pc, pc);
|
||||
qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu(insn,
|
||||
QEMU_PLUGIN_INLINE_STORE_U64,
|
||||
from_pc, next_pc);
|
||||
qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu(insn,
|
||||
QEMU_PLUGIN_INLINE_STORE_U64,
|
||||
has_from, has_next);
|
||||
qemu_plugin_register_vcpu_insn_exec_cb(insn, insn_exec,
|
||||
QEMU_PLUGIN_CB_NO_REGS, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
|
||||
const qemu_info_t *info,
|
||||
int argc, char **argv)
|
||||
{
|
||||
if (!info->system_emulation) {
|
||||
qemu_plugin_outs("Testing of the disontinuity plugin API is only"
|
||||
" possible in system emulation mode.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set defaults */
|
||||
abort_on_mismatch = true;
|
||||
trace_all_insns = 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], "abort") == 0) {
|
||||
if (!qemu_plugin_bool_parse(tokens[0], tokens[1],
|
||||
&abort_on_mismatch)) {
|
||||
fprintf(stderr, "boolean argument parsing failed: %s\n", opt);
|
||||
return -1;
|
||||
}
|
||||
} else if (g_strcmp0(tokens[0], "trace-all") == 0) {
|
||||
if (!qemu_plugin_bool_parse(tokens[0], tokens[1],
|
||||
&trace_all_insns)) {
|
||||
fprintf(stderr, "boolean argument parsing failed: %s\n", opt);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "option parsing failed: %s\n", opt);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
states = qemu_plugin_scoreboard_new(sizeof(struct cpu_state));
|
||||
last_pc = qemu_plugin_scoreboard_u64_in_struct(states, struct cpu_state,
|
||||
last_pc);
|
||||
from_pc = qemu_plugin_scoreboard_u64_in_struct(states, struct cpu_state,
|
||||
from_pc);
|
||||
has_from = qemu_plugin_scoreboard_u64_in_struct(states, struct cpu_state,
|
||||
has_from);
|
||||
|
||||
qemu_plugin_register_vcpu_discon_cb(id, QEMU_PLUGIN_DISCON_ALL,
|
||||
vcpu_discon);
|
||||
qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
t = []
|
||||
if get_option('plugins')
|
||||
foreach i : ['bb', 'empty', 'inline', 'insn', 'mem', 'reset', 'syscall', 'patch']
|
||||
foreach i : ['bb', 'discons', 'empty', 'inline', 'insn', 'mem', 'reset', 'syscall', 'patch']
|
||||
if host_os == 'windows'
|
||||
t += shared_module(i, files(i + '.c') + '../../../contrib/plugins/win32_linker.c',
|
||||
include_directories: '../../../include/qemu',
|
||||
|
|
|
|||
|
|
@ -24,5 +24,17 @@ EXTRA_RUNS += run-test-mepc-masking
|
|||
run-test-mepc-masking: test-mepc-masking
|
||||
$(call run-test, $<, $(QEMU) $(QEMU_OPTS)$<)
|
||||
|
||||
EXTRA_RUNS += run-plugin-doubletrap
|
||||
run-plugin-doubletrap: doubletrap
|
||||
$(call run-test, $<, \
|
||||
$(QEMU) -plugin ../plugins/libdiscons.so -d plugin -D $<.pout \
|
||||
$(QEMU_OPTS)$<)
|
||||
|
||||
EXTRA_RUNS += run-plugin-interruptedmemory
|
||||
run-plugin-interruptedmemory: interruptedmemory
|
||||
$(call run-test, $<, \
|
||||
$(QEMU) -plugin ../plugins/libdiscons.so -d plugin -D $<.pout \
|
||||
$(QEMU_OPTS)$<)
|
||||
|
||||
# We don't currently support the multiarch system tests
|
||||
undefine MULTIARCH_TESTS
|
||||
|
|
|
|||
73
tests/tcg/riscv64/doubletrap.S
Normal file
73
tests/tcg/riscv64/doubletrap.S
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
.option norvc
|
||||
|
||||
.text
|
||||
.global _start
|
||||
_start:
|
||||
# Set up vectored interrupts
|
||||
lla t0, trap
|
||||
add t0, t0, 1
|
||||
csrw mtvec, t0
|
||||
|
||||
# Enable sw interrupts
|
||||
csrrsi zero, mie, 0x8
|
||||
csrrsi zero, mstatus, 0x8
|
||||
|
||||
# Engage the double trap: we trigger an machine-level software
|
||||
# interrupt, which will trap to an illegal instruction
|
||||
lui t1, 0x02000
|
||||
li t0, 1
|
||||
sw t0, 0(t1)
|
||||
|
||||
# If we still not went out via the software interrupt route after a
|
||||
# short while, we failed the test.
|
||||
lui t0, 0x1
|
||||
0:
|
||||
addi t0, t0, -1
|
||||
bnez t0, 0b
|
||||
j fail
|
||||
|
||||
trap:
|
||||
j illegal_insn # Exceptions
|
||||
j fail # Supervisor software interrupt
|
||||
j fail
|
||||
.insn i CUSTOM_0, 0, x0, x0, 0 # Machine software interrupt
|
||||
j fail
|
||||
j fail # Supervisor timer interrupt
|
||||
j fail
|
||||
j fail # Machine timer interrupt
|
||||
j fail
|
||||
j fail # Supervisor external interrupt
|
||||
j fail
|
||||
j fail # Machine external interrupt
|
||||
j fail
|
||||
j fail # Counter overflow interrupt
|
||||
j fail
|
||||
j fail
|
||||
|
||||
illegal_insn:
|
||||
# Check whether we really got an illegal instruction
|
||||
csrr t0, mcause
|
||||
li t1, 2
|
||||
bne t0, t1, fail
|
||||
li a0, 0
|
||||
j _exit
|
||||
fail:
|
||||
li a0, 1
|
||||
_exit:
|
||||
lla a1, semiargs
|
||||
li t0, 0x20026 # ADP_Stopped_ApplicationExit
|
||||
sd t0, 0(a1)
|
||||
sd a0, 8(a1)
|
||||
li a0, 0x20 # TARGET_SYS_EXIT_EXTENDED
|
||||
|
||||
# Semihosting call sequence
|
||||
.balign 16
|
||||
slli zero, zero, 0x1f
|
||||
ebreak
|
||||
srai zero, zero, 0x7
|
||||
j .
|
||||
|
||||
.data
|
||||
.balign 16
|
||||
semiargs:
|
||||
.space 16
|
||||
97
tests/tcg/riscv64/interruptedmemory.S
Normal file
97
tests/tcg/riscv64/interruptedmemory.S
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
.option norvc
|
||||
|
||||
.text
|
||||
.global _start
|
||||
_start:
|
||||
# Set up trap vector
|
||||
lla t0, trap
|
||||
csrw mtvec, t0
|
||||
|
||||
# Set up timer
|
||||
lui t1, 0x02004
|
||||
sd zero, 0(t1) # MTIMECMP0
|
||||
|
||||
# Enable timer interrupts
|
||||
li t0, 0x80
|
||||
csrrs zero, mie, t0
|
||||
csrrsi zero, mstatus, 0x8
|
||||
|
||||
# Set up UART
|
||||
lui t1, 0x10000
|
||||
li a0, 0x80 # DLAB=1
|
||||
sb a0, 3(t1)
|
||||
li a0, 1 # Full speed
|
||||
sw a0, 0(t1)
|
||||
li a0, 0x03 # 8N1, DLAB=0
|
||||
sb a0, 3(t1)
|
||||
|
||||
# Run test for around 60s
|
||||
call rtc_get
|
||||
li t0, 30
|
||||
slli t0, t0, 30 # Approx. 10e9 ns
|
||||
add t0, t0, a0
|
||||
0:
|
||||
# Tight loop with memory accesses
|
||||
li a1, 1000000
|
||||
la a2, semiargs
|
||||
1:
|
||||
ld a0, 0(a2)
|
||||
sd a0, 0(a2)
|
||||
addi a1, a1, -1
|
||||
bnez a1, 1b
|
||||
|
||||
li a0, '.'
|
||||
call send_byte
|
||||
call rtc_get
|
||||
bltu a0, t0, 0b
|
||||
|
||||
li a0, '\n'
|
||||
call send_byte
|
||||
|
||||
# Exit
|
||||
li a0, 0
|
||||
lla a1, semiargs
|
||||
li t0, 0x20026 # ADP_Stopped_ApplicationExit
|
||||
sd t0, 0(a1)
|
||||
sd a0, 8(a1)
|
||||
li a0, 0x20 # TARGET_SYS_EXIT_EXTENDED
|
||||
|
||||
# Semihosting call sequence
|
||||
.balign 16
|
||||
slli zero, zero, 0x1f
|
||||
ebreak
|
||||
srai zero, zero, 0x7
|
||||
|
||||
j .
|
||||
|
||||
rtc_get:
|
||||
# Get current time from the goldfish RTC
|
||||
lui t3, 0x0101
|
||||
lw a0, 0(t3)
|
||||
lw t3, 4(t3)
|
||||
slli t3, t3, 32
|
||||
add a0, a0, t3
|
||||
ret
|
||||
|
||||
send_byte:
|
||||
# Send a single byte over the serial
|
||||
lui t3, 0x10000
|
||||
lb a1, 5(t3)
|
||||
andi a1, a1, 0x20
|
||||
beqz a1, send_byte
|
||||
sb a0, 0(t3)
|
||||
ret
|
||||
|
||||
.balign 4
|
||||
trap:
|
||||
lui t5, 0x0200c
|
||||
ld t6, -0x8(t5) # MTIME
|
||||
addi t6, t6, 100
|
||||
lui t5, 0x02004
|
||||
sd t6, 0(t5) # MTIMECMP
|
||||
mret
|
||||
|
||||
.data
|
||||
.balign 16
|
||||
semiargs:
|
||||
.space 16
|
||||
Loading…
Add table
Add a link
Reference in a new issue