Merge tag 'pull-10.2-maintainer-260925-1' of https://gitlab.com/stsquad/qemu into staging

September maintainer updates (scripts, semihosting, plugins)

 - new gitlab-failure-analysis script
 - tweak checkpath to ignore license in removed lines
 - refactor semihosting to build once
 - add explicit assert to execlog for coverity
 - new uftrace plugin

# -----BEGIN PGP SIGNATURE-----
#
# iQEzBAABCgAdFiEEZoWumedRZ7yvyN81+9DbCVqeKkQFAmjWWJYACgkQ+9DbCVqe
# KkS1sgf+LsP0jsc1wKhzBhO4WarXXacWCDxK22riJ3aolm+gJ+b0WI4ds18A0e3R
# z/J8VJVxBZ+6Hid+tOCQwfZ+Hb1p9IofzBdZryGUvwguviNdlpEChhXXnoZkicym
# aGcC/jYRkhTx42dKRdZrSzPd3ccipqop9RvGx57bjCSBAEHYNz679p4z91kNR5a9
# UfcCzIQHbBUPZo0F9gQkNnBrjsJQhvF+gXPmmsmBI1pby6gNRQvFshrTQ1C32VpL
# VgXNc9cZ6vaREWlgb6izNjsMP7cYTMH2Ppxty/FyEMg7GTfWRjI6Ec8fJKjPFtKr
# ZbCNNAeJ9uLK6pJfTk2YxYabxx3JuQ==
# =cR9e
# -----END PGP SIGNATURE-----
# gpg: Signature made Fri 26 Sep 2025 02:10:46 AM PDT
# 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-260925-1' of https://gitlab.com/stsquad/qemu: (24 commits)
  contrib/plugins/uftrace: add documentation
  contrib/plugins/uftrace_symbols.py
  contrib/plugins/uftrace: implement x64 support
  contrib/plugins/uftrace: generate additional files for uftrace
  contrib/plugins/uftrace: implement privilege level tracing
  contrib/plugins/uftrace: implement tracing
  contrib/plugins/uftrace: track callstack
  contrib/plugins/uftrace: define cpu operations and implement aarch64
  contrib/plugins/uftrace: skeleton file
  contrib/plugins/execlog: Explicitly check for qemu_plugin_read_register() failure
  semihosting/arm-compat-semi: compile once in system and per target for user mode
  semihosting/arm-compat-semi: remove dependency on cpu.h
  semihosting/arm-compat-semi: eradicate target_long
  semihosting/arm-compat-semi: replace target_ulong
  semihosting/arm-compat-semi: eradicate sizeof(target_ulong)
  include/semihosting/common-semi: extract common_semi API
  target/{arm, riscv}/common-semi-target: eradicate target_ulong
  target/riscv/common-semi-target: remove sizeof(target_ulong)
  semihosting/arm-compat-semi: change common_semi_sys_exit_extended
  semihosting/guestfd: compile once for system/user
  ...

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson
2025-09-26 13:26:30 -07:00
20 changed files with 1540 additions and 150 deletions
+1
View File
@@ -95,6 +95,7 @@ static void insn_check_regs(CPU *cpu)
g_byte_array_set_size(reg->new, 0);
sz = qemu_plugin_read_register(reg->handle, reg->new);
g_assert(sz > 0);
g_assert(sz == reg->last->len);
if (memcmp(reg->last->data, reg->new->data, sz)) {
+2 -1
View File
@@ -1,5 +1,6 @@
contrib_plugins = ['bbv', 'cache', 'cflow', 'drcov', 'execlog', 'hotblocks',
'hotpages', 'howvec', 'hwprofile', 'ips', 'stoptrigger']
'hotpages', 'howvec', 'hwprofile', 'ips', 'stoptrigger',
'uftrace']
if host_os != 'windows'
# lockstep uses socket.h
contrib_plugins += 'lockstep'
File diff suppressed because it is too large Load Diff
+152
View File
@@ -0,0 +1,152 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Create symbols and mapping files for uftrace.
#
# Copyright 2025 Linaro Ltd
# Author: Pierrick Bouvier <pierrick.bouvier@linaro.org>
#
# SPDX-License-Identifier: GPL-2.0-or-later
import argparse
import elftools # pip install pyelftools
import os
from elftools.elf.elffile import ELFFile
from elftools.elf.sections import SymbolTableSection
def elf_func_symbols(elf):
symbol_tables = [(idx, s) for idx, s in enumerate(elf.iter_sections())
if isinstance(s, SymbolTableSection)]
symbols = []
for _, section in symbol_tables:
for _, symbol in enumerate(section.iter_symbols()):
if symbol_size(symbol) == 0:
continue
type = symbol['st_info']['type']
if type == 'STT_FUNC' or type == 'STT_NOTYPE':
symbols.append(symbol)
symbols.sort(key = lambda x: symbol_addr(x))
return symbols
def symbol_size(symbol):
return symbol['st_size']
def symbol_addr(symbol):
addr = symbol['st_value']
# clamp addr to 48 bits, like uftrace entries
return addr & 0xffffffffffff
def symbol_name(symbol):
return symbol.name
class BinaryFile:
def __init__(self, path, map_offset):
self.fullpath = os.path.realpath(path)
self.map_offset = map_offset
with open(path, 'rb') as f:
self.elf = ELFFile(f)
self.symbols = elf_func_symbols(self.elf)
def path(self):
return self.fullpath
def addr_start(self):
return self.map_offset
def addr_end(self):
last_sym = self.symbols[-1]
return symbol_addr(last_sym) + symbol_size(last_sym) + self.map_offset
def generate_symbol_file(self, prefix_symbols):
binary_name = os.path.basename(self.fullpath)
sym_file_path = f'./uftrace.data/{binary_name}.sym'
print(f'{sym_file_path} ({len(self.symbols)} symbols)')
with open(sym_file_path, 'w') as sym_file:
# print hexadecimal addresses on 48 bits
addrx = "0>12x"
for s in self.symbols:
addr = symbol_addr(s)
addr = f'{addr:{addrx}}'
size = f'{symbol_size(s):{addrx}}'
name = symbol_name(s)
if prefix_symbols:
name = f'{binary_name}:{name}'
print(addr, size, 'T', name, file=sym_file)
def parse_parameter(p):
s = p.split(":")
path = s[0]
if len(s) == 1:
return path, 0
if len(s) > 2:
raise ValueError('only one offset can be set')
offset = s[1]
if not offset.startswith('0x'):
err = f'offset "{offset}" is not an hexadecimal constant. '
err += 'It should starts with "0x".'
raise ValueError(err)
offset = int(offset, 16)
return path, offset
def is_from_user_mode(map_file_path):
if os.path.exists(map_file_path):
with open(map_file_path, 'r') as map_file:
if not map_file.readline().startswith('# map stack on'):
return True
return False
def generate_map(binaries):
map_file_path = './uftrace.data/sid-0.map'
if is_from_user_mode(map_file_path):
print(f'do not overwrite {map_file_path} generated from qemu-user')
return
mappings = []
# print hexadecimal addresses on 48 bits
addrx = "0>12x"
mappings += ['# map stack on highest address possible, to prevent uftrace']
mappings += ['# from considering any kernel address']
mappings += ['ffffffffffff-ffffffffffff rw-p 00000000 00:00 0 [stack]']
for b in binaries:
m = f'{b.addr_start():{addrx}}-{b.addr_end():{addrx}}'
m += f' r--p 00000000 00:00 0 {b.path()}'
mappings.append(m)
with open(map_file_path, 'w') as map_file:
print('\n'.join(mappings), file=map_file)
print(f'{map_file_path}')
print('\n'.join(mappings))
def main():
parser = argparse.ArgumentParser(description=
'generate symbol files for uftrace')
parser.add_argument('elf_file', nargs='+',
help='path to an ELF file. '
'Use /path/to/file:0xdeadbeef to add a mapping offset.')
parser.add_argument('--prefix-symbols',
help='prepend binary name to symbols',
action=argparse.BooleanOptionalAction)
args = parser.parse_args()
if not os.path.exists('./uftrace.data'):
os.mkdir('./uftrace.data')
binaries = []
for file in args.elf_file:
path, offset = parse_parameter(file)
b = BinaryFile(path, offset)
binaries.append(b)
binaries.sort(key = lambda b: b.addr_end());
for b in binaries:
b.generate_symbol_file(args.prefix_symbols)
generate_map(binaries)
if __name__ == '__main__':
main()
+199
View File
@@ -816,6 +816,205 @@ This plugin can limit the number of Instructions Per Second that are executed::
The lower the number the more accurate time will be, but the less efficient the plugin.
Defaults to ips/10
Uftrace
.......
``contrib/plugins/uftrace.c``
This plugin generates a binary trace compatible with
`uftrace <https://github.com/namhyung/uftrace>`_.
Plugin supports aarch64 and x64, and works in user and system mode, allowing to
trace a system boot, which is not something possible usually.
In user mode, the memory mapping is directly copied from ``/proc/self/maps`` at
the end of execution. Uftrace should be able to retrieve symbols by itself,
without any additional step.
In system mode, the default memory mapping is empty, and you can generate
one (and associated symbols) using ``contrib/plugins/uftrace_symbols.py``.
Symbols must be present in ELF binaries.
It tracks the call stack (based on frame pointer analysis). Thus, your program
and its dependencies must be compiled using ``-fno-omit-frame-pointer
-mno-omit-leaf-frame-pointer``. In 2024, `Ubuntu and Fedora enabled it by
default again on x64
<https://www.brendangregg.com/blog/2024-03-17/the-return-of-the-frame-pointers.html>`_.
On aarch64, this is less of a problem, as they are usually part of the ABI,
except for leaf functions. That's true for user space applications, but not
necessarily for bare metal code. You can read this `section
<uftrace_build_system_example>` to easily build a system with frame pointers.
When tracing long scenarios (> 1 min), the generated trace can become very long,
making it hard to extract data from it. In this case, a simple solution is to
trace execution while generating a timestamped output log using
``qemu-system-aarch64 ... | ts "%s"``. Then, ``uftrace --time-range=start~end``
can be used to reduce trace for only this part of execution.
Performance wise, overhead compared to normal tcg execution is around x5-x15.
.. list-table:: Uftrace plugin arguments
:widths: 20 80
:header-rows: 1
* - Option
- Description
* - trace-privilege-level=[on|off]
- Generate separate traces for each privilege level (Exception Level +
Security State on aarch64, Rings on x64).
.. list-table:: uftrace_symbols.py arguments
:widths: 20 80
:header-rows: 1
* - Option
- Description
* - elf_file [elf_file ...]
- path to an ELF file. Use /path/to/file:0xdeadbeef to add a mapping offset.
* - --prefix-symbols
- prepend binary name to symbols
Example user trace
++++++++++++++++++
As an example, we can trace qemu itself running git::
$ ./build/qemu-aarch64 -plugin \
build/contrib/plugins/libuftrace.so \
./build/qemu-aarch64 /usr/bin/git --help
# and generate a chrome trace directly
$ uftrace dump --chrome | gzip > ~/qemu_aarch64_git_help.json.gz
For convenience, you can download this trace `qemu_aarch64_git_help.json.gz
<https://fileserver.linaro.org/s/N8X8fnZ5yGRZLsT/download/qemu_aarch64_git_help.json.gz>`_.
Download it and open this trace on https://ui.perfetto.dev/. You can zoom in/out
using :kbd:`W`, :kbd:`A`, :kbd:`S`, :kbd:`D` keys.
Some sequences taken from this trace:
- Loading program and its interpreter
.. image:: https://fileserver.linaro.org/s/fie8JgX76yyL5cq/preview
:height: 200px
- open syscall
.. image:: https://fileserver.linaro.org/s/rsXPTeZZPza4PcE/preview
:height: 200px
- TB creation
.. image:: https://fileserver.linaro.org/s/GXY6NKMw5EeRCew/preview
:height: 200px
It's usually better to use ``uftrace record`` directly. However, tracing
binaries through qemu-user can be convenient when you don't want to recompile
them (``uftrace record`` requires instrumentation), as long as symbols are
present.
Example system trace
++++++++++++++++++++
A full trace example (chrome trace, from instructions below) generated from a
system boot can be found `here
<https://fileserver.linaro.org/s/WsemLboPEzo24nw/download/aarch64_boot.json.gz>`_.
Download it and open this trace on https://ui.perfetto.dev/. You can see code
executed for all privilege levels, and zoom in/out using
:kbd:`W`, :kbd:`A`, :kbd:`S`, :kbd:`D` keys. You can find below some sequences
taken from this trace:
- Two first stages of boot sequence in Arm Trusted Firmware (EL3 and S-EL1)
.. image:: https://fileserver.linaro.org/s/kkxBS552W7nYESX/preview
:height: 200px
- U-boot initialization (until code relocation, after which we can't track it)
.. image:: https://fileserver.linaro.org/s/LKTgsXNZFi5GFNC/preview
:height: 200px
- Stat and open syscalls in kernel
.. image:: https://fileserver.linaro.org/s/dXe4MfraKg2F476/preview
:height: 200px
- Timer interrupt
.. image:: https://fileserver.linaro.org/s/TM5yobYzJtP7P3C/preview
:height: 200px
- Poweroff sequence (from kernel back to firmware, NS-EL2 to EL3)
.. image:: https://fileserver.linaro.org/s/oR2PtyGKJrqnfRf/preview
:height: 200px
Build and run system example
++++++++++++++++++++++++++++
.. _uftrace_build_system_example:
Building a full system image with frame pointers is not trivial.
We provide a `simple way <https://github.com/pbo-linaro/qemu-linux-stack>`_ to
build an aarch64 system, combining Arm Trusted firmware, U-boot, Linux kernel
and debian userland. It's based on containers (``podman`` only) and
``qemu-user-static (binfmt)`` to make sure it's easily reproducible and does not depend
on machine where you build it.
You can follow the exact same instructions for a x64 system, combining edk2,
Linux, and Ubuntu, simply by switching to
`x86_64 <https://github.com/pbo-linaro/qemu-linux-stack/tree/x86_64>`_ branch.
To build the system::
# Install dependencies
$ sudo apt install -y podman qemu-user-static
$ git clone https://github.com/pbo-linaro/qemu-linux-stack
$ cd qemu-linux-stack
$ ./build.sh
# system can be started using:
$ ./run.sh /path/to/qemu-system-aarch64
To generate a uftrace for a system boot from that::
# run true and poweroff the system
$ env INIT=true ./run.sh path/to/qemu-system-aarch64 \
-plugin path/to/contrib/plugins/libuftrace.so,trace-privilege-level=on
# generate symbols and memory mapping
$ path/to/contrib/plugins/uftrace_symbols.py \
--prefix-symbols \
arm-trusted-firmware/build/qemu/debug/bl1/bl1.elf \
arm-trusted-firmware/build/qemu/debug/bl2/bl2.elf \
arm-trusted-firmware/build/qemu/debug/bl31/bl31.elf \
u-boot/u-boot:0x60000000 \
linux/vmlinux
# inspect trace with
$ uftrace replay
Uftrace allows to filter the trace, and dump flamegraphs, or a chrome trace.
This last one is very interesting to see visually the boot process::
$ uftrace dump --chrome > boot.json
# Open your browser, and load boot.json on https://ui.perfetto.dev/.
Long visual chrome traces can't be easily opened, thus, it might be
interesting to generate them around a particular point of execution::
# execute qemu and timestamp output log
$ env INIT=true ./run.sh path/to/qemu-system-aarch64 \
-plugin path/to/contrib/plugins/libuftrace.so,trace-privilege-level=on |&
ts "%s" | tee exec.log
$ cat exec.log | grep 'Run /init'
1753122320 [ 11.834391] Run /init as init process
# init was launched at 1753122320
# generate trace around init execution (2 seconds):
$ uftrace dump --chrome --time-range=1753122320~1753122322 > init.json
Other emulation features
------------------------
+6
View File
@@ -35,5 +35,11 @@
#define COMMON_SEMI_H
void do_common_semihosting(CPUState *cs);
uint64_t common_semi_arg(CPUState *cs, int argno);
void common_semi_set_ret(CPUState *cs, uint64_t ret);
bool is_64bit_semihosting(CPUArchState *env);
bool common_semi_sys_exit_is_extended(CPUState *cs);
uint64_t common_semi_stack_bottom(CPUState *cs);
bool common_semi_has_synccache(CPUArchState *env);
#endif /* COMMON_SEMI_H */
-7
View File
@@ -35,13 +35,6 @@ typedef struct GuestFD {
};
} GuestFD;
/*
* For ARM semihosting, we have a separate structure for routing
* data for the console which is outside the guest fd address space.
*/
extern GuestFD console_in_gf;
extern GuestFD console_out_gf;
/**
* alloc_guestfd:
*
+2
View File
@@ -33,6 +33,8 @@ typedef enum SemihostingTarget {
* Return true if guest code is allowed to make semihosting calls.
*/
bool semihosting_enabled(bool is_user);
bool semihosting_arm_compatible(void);
void semihosting_arm_compatible_init(void);
SemihostingTarget semihosting_get_target(void);
const char *semihosting_get_arg(int i);
+15 -15
View File
@@ -9,7 +9,7 @@
#ifndef SEMIHOSTING_SYSCALLS_H
#define SEMIHOSTING_SYSCALLS_H
#include "exec/cpu-defs.h"
#include "exec/vaddr.h"
#include "gdbstub/syscalls.h"
/*
@@ -24,23 +24,23 @@
typedef struct GuestFD GuestFD;
void semihost_sys_open(CPUState *cs, gdb_syscall_complete_cb complete,
target_ulong fname, target_ulong fname_len,
vaddr fname, uint64_t fname_len,
int gdb_flags, int mode);
void semihost_sys_close(CPUState *cs, gdb_syscall_complete_cb complete,
int fd);
void semihost_sys_read(CPUState *cs, gdb_syscall_complete_cb complete,
int fd, target_ulong buf, target_ulong len);
int fd, vaddr buf, uint64_t len);
void semihost_sys_read_gf(CPUState *cs, gdb_syscall_complete_cb complete,
GuestFD *gf, target_ulong buf, target_ulong len);
GuestFD *gf, vaddr buf, uint64_t len);
void semihost_sys_write(CPUState *cs, gdb_syscall_complete_cb complete,
int fd, target_ulong buf, target_ulong len);
int fd, vaddr buf, uint64_t len);
void semihost_sys_write_gf(CPUState *cs, gdb_syscall_complete_cb complete,
GuestFD *gf, target_ulong buf, target_ulong len);
GuestFD *gf, vaddr buf, uint64_t len);
void semihost_sys_lseek(CPUState *cs, gdb_syscall_complete_cb complete,
int fd, int64_t off, int gdb_whence);
@@ -50,27 +50,27 @@ void semihost_sys_isatty(CPUState *cs, gdb_syscall_complete_cb complete,
void semihost_sys_flen(CPUState *cs, gdb_syscall_complete_cb fstat_cb,
gdb_syscall_complete_cb flen_cb,
int fd, target_ulong fstat_addr);
int fd, vaddr fstat_addr);
void semihost_sys_fstat(CPUState *cs, gdb_syscall_complete_cb complete,
int fd, target_ulong addr);
int fd, vaddr addr);
void semihost_sys_stat(CPUState *cs, gdb_syscall_complete_cb complete,
target_ulong fname, target_ulong fname_len,
target_ulong addr);
vaddr fname, uint64_t fname_len,
vaddr addr);
void semihost_sys_remove(CPUState *cs, gdb_syscall_complete_cb complete,
target_ulong fname, target_ulong fname_len);
vaddr fname, uint64_t fname_len);
void semihost_sys_rename(CPUState *cs, gdb_syscall_complete_cb complete,
target_ulong oname, target_ulong oname_len,
target_ulong nname, target_ulong nname_len);
vaddr oname, uint64_t oname_len,
vaddr nname, uint64_t nname_len);
void semihost_sys_system(CPUState *cs, gdb_syscall_complete_cb complete,
target_ulong cmd, target_ulong cmd_len);
vaddr cmd, uint64_t cmd_len);
void semihost_sys_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete,
target_ulong tv_addr, target_ulong tz_addr);
vaddr tv_addr, vaddr tz_addr);
void semihost_sys_poll_one(CPUState *cs, gdb_syscall_complete_cb complete,
int fd, GIOCondition cond, int timeout);
+2 -1
View File
@@ -1816,7 +1816,8 @@ sub process {
}
# Check SPDX-License-Identifier references a permitted license
if ($rawline =~ m,SPDX-License-Identifier: (.*?)(\*/)?\s*$,) {
if (($rawline =~ m,SPDX-License-Identifier: (.*?)(\*/)?\s*$,) &&
$rawline !~ /^-/) {
$fileinfo->{facts}->{sawspdx} = 1;
&checkspdx($realfile, $1);
}
+117
View File
@@ -0,0 +1,117 @@
#!/usr/bin/env python3
#
# A script to analyse failures in the gitlab pipelines. It requires an
# API key from gitlab with the following permissions:
# - api
# - read_repository
# - read_user
#
import argparse
import gitlab
import os
#
# Arguments
#
class NoneForEmptyStringAction(argparse.Action):
def __call__(self, parser, namespace, value, option_string=None):
if value == '':
setattr(namespace, self.dest, None)
else:
setattr(namespace, self.dest, value)
parser = argparse.ArgumentParser(description="Analyse failed GitLab CI runs.")
parser.add_argument("--gitlab",
default="https://gitlab.com",
help="GitLab instance URL (default: https://gitlab.com).")
parser.add_argument("--id", default=11167699,
type=int,
help="GitLab project id (default: 11167699 for qemu-project/qemu)")
parser.add_argument("--token",
default=os.getenv("GITLAB_TOKEN"),
help="Your personal access token with 'api' scope.")
parser.add_argument("--branch",
type=str,
default="staging",
action=NoneForEmptyStringAction,
help="The name of the branch (default: 'staging')")
parser.add_argument("--status",
type=str,
action=NoneForEmptyStringAction,
default="failed",
help="Filter by branch status (default: 'failed')")
parser.add_argument("--count", type=int,
default=3,
help="The number of failed runs to fetch.")
parser.add_argument("--skip-jobs",
default=False,
action='store_true',
help="Skip dumping the job info")
parser.add_argument("--pipeline", type=int,
nargs="+",
default=None,
help="Explicit pipeline ID(s) to fetch.")
if __name__ == "__main__":
args = parser.parse_args()
gl = gitlab.Gitlab(url=args.gitlab, private_token=args.token)
project = gl.projects.get(args.id)
pipelines_to_process = []
# Use explicit pipeline IDs if provided, otherwise fetch a list
if args.pipeline:
args.count = len(args.pipeline)
for p_id in args.pipeline:
pipelines_to_process.append(project.pipelines.get(p_id))
else:
# Use an iterator to fetch the pipelines
pipe_iter = project.pipelines.list(iterator=True,
status=args.status,
ref=args.branch)
# Check each failed pipeline
pipelines_to_process = [next(pipe_iter) for _ in range(args.count)]
# Check each pipeline
for p in pipelines_to_process:
jobs = p.jobs.list(get_all=True)
failed_jobs = [j for j in jobs if j.status == "failed"]
skipped_jobs = [j for j in jobs if j.status == "skipped"]
manual_jobs = [j for j in jobs if j.status == "manual"]
trs = p.test_report_summary.get()
total = trs.total["count"]
skipped = trs.total["skipped"]
failed = trs.total["failed"]
print(f"{p.status} pipeline {p.id}, total jobs {len(jobs)}, "
f"skipped {len(skipped_jobs)}, "
f"failed {len(failed_jobs)}, ",
f"{total} tests, "
f"{skipped} skipped tests, "
f"{failed} failed tests")
if not args.skip_jobs:
for j in failed_jobs:
print(f" Failed job {j.id}, {j.name}, {j.web_url}")
# It seems we can only extract failing tests from the full
# test report, maybe there is some way to filter it.
if failed > 0:
ftr = p.test_report.get()
failed_suites = [s for s in ftr.test_suites if
s["failed_count"] > 0]
for fs in failed_suites:
name = fs["name"]
tests = fs["test_cases"]
failed_tests = [t for t in tests if t["status"] == 'failed']
for t in failed_tests:
print(f" Failed test {t["classname"]}, {name}, {t["name"]}")
+19
View File
@@ -0,0 +1,19 @@
/*
* Stubs for platforms different from ARM
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "semihosting/semihost.h"
#include <glib.h>
bool semihosting_arm_compatible(void)
{
return false;
}
void semihosting_arm_compatible_init(void)
{
g_assert_not_reached();
}
+46 -17
View File
@@ -100,6 +100,13 @@ static int gdb_open_modeflags[12] = {
GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND,
};
/*
* For ARM semihosting, we have a separate structure for routing
* data for the console which is outside the guest fd address space.
*/
static GuestFD console_in_gf;
static GuestFD console_out_gf;
#ifndef CONFIG_USER_ONLY
/**
@@ -115,7 +122,7 @@ static int gdb_open_modeflags[12] = {
*/
typedef struct LayoutInfo {
target_ulong rambase;
vaddr rambase;
size_t ramsize;
hwaddr heapbase;
hwaddr heaplimit;
@@ -166,8 +173,7 @@ static LayoutInfo common_semi_find_bases(CPUState *cs)
#endif
#include "cpu.h"
#include "common-semi-target.h"
#include "semihosting/common-semi.h"
/*
* Read the input value from the argument block; fail the semihosting
@@ -207,7 +213,7 @@ static LayoutInfo common_semi_find_bases(CPUState *cs)
* global, and we assume that the guest takes care of avoiding any races.
*/
#ifndef CONFIG_USER_ONLY
static target_ulong syscall_err;
static uint64_t syscall_err;
#include "semihosting/uaccess.h"
#endif
@@ -253,8 +259,8 @@ static void common_semi_rw_cb(CPUState *cs, uint64_t ret, int err)
{
/* Recover the original length from the third argument. */
CPUArchState *env G_GNUC_UNUSED = cpu_env(cs);
target_ulong args = common_semi_arg(cs, 1);
target_ulong arg2;
uint64_t args = common_semi_arg(cs, 1);
uint64_t arg2;
GET_ARG(2);
if (err) {
@@ -293,9 +299,9 @@ static void common_semi_seek_cb(CPUState *cs, uint64_t ret, int err)
* is defined by GDB's remote protocol and is not target-specific.)
* We put this on the guest's stack just below SP.
*/
static target_ulong common_semi_flen_buf(CPUState *cs)
static uint64_t common_semi_flen_buf(CPUState *cs)
{
target_ulong sp = common_semi_stack_bottom(cs);
vaddr sp = common_semi_stack_bottom(cs);
return sp - 64;
}
@@ -352,6 +358,25 @@ static const uint8_t featurefile_data[] = {
SH_EXT_EXIT_EXTENDED | SH_EXT_STDOUT_STDERR, /* Feature byte 0 */
};
bool semihosting_arm_compatible(void)
{
return true;
}
void semihosting_arm_compatible_init(void)
{
/* For ARM-compat, the console is in a separate namespace. */
if (use_gdb_syscalls()) {
console_in_gf.type = GuestFDGDB;
console_in_gf.hostfd = 0;
console_out_gf.type = GuestFDGDB;
console_out_gf.hostfd = 2;
} else {
console_in_gf.type = GuestFDConsole;
console_out_gf.type = GuestFDConsole;
}
}
/*
* Do a semihosting call.
*
@@ -363,9 +388,9 @@ static const uint8_t featurefile_data[] = {
void do_common_semihosting(CPUState *cs)
{
CPUArchState *env = cpu_env(cs);
target_ulong args;
target_ulong arg0, arg1, arg2, arg3;
target_ulong ul_ret;
uint64_t args;
uint64_t arg0, arg1, arg2, arg3;
uint64_t ul_ret;
char * s;
int nr;
int64_t elapsed;
@@ -436,7 +461,7 @@ void do_common_semihosting(CPUState *cs)
case TARGET_SYS_WRITEC:
/*
* FIXME: the byte to be written is in a target_ulong slot,
* FIXME: the byte to be written is in a uint64_t slot,
* which means this is wrong for a big-endian guest.
*/
semihost_sys_write_gf(cs, common_semi_dead_cb,
@@ -475,10 +500,13 @@ void do_common_semihosting(CPUState *cs)
break;
case TARGET_SYS_ISERROR:
{
GET_ARG(0);
common_semi_set_ret(cs, (target_long)arg0 < 0);
bool ret = is_64bit_semihosting(env) ?
(int64_t)arg0 < 0 : (int32_t)arg0 < 0;
common_semi_set_ret(cs, ret);
break;
}
case TARGET_SYS_ISTTY:
GET_ARG(0);
semihost_sys_isatty(cs, common_semi_istty_cb, arg0);
@@ -662,7 +690,7 @@ void do_common_semihosting(CPUState *cs)
case TARGET_SYS_HEAPINFO:
{
target_ulong retvals[4];
uint64_t retvals[4];
int i;
#ifdef CONFIG_USER_ONLY
TaskState *ts = get_task_state(cs);
@@ -728,7 +756,8 @@ void do_common_semihosting(CPUState *cs)
{
uint32_t ret;
if (common_semi_sys_exit_extended(cs, nr)) {
if (nr == TARGET_SYS_EXIT_EXTENDED ||
common_semi_sys_exit_is_extended(cs)) {
/*
* The A64 version of SYS_EXIT takes a parameter block,
* so the application-exit type can return a subcode which
@@ -759,7 +788,7 @@ void do_common_semihosting(CPUState *cs)
case TARGET_SYS_ELAPSED:
elapsed = get_clock() - clock_start;
if (sizeof(target_ulong) == 8) {
if (is_64bit_semihosting(env)) {
if (SET_ARG(0, elapsed)) {
goto do_fault;
}
+5 -21
View File
@@ -12,35 +12,20 @@
#include "gdbstub/syscalls.h"
#include "semihosting/semihost.h"
#include "semihosting/guestfd.h"
#ifndef CONFIG_USER_ONLY
#include CONFIG_DEVICES
#endif
static GArray *guestfd_array;
#ifdef CONFIG_ARM_COMPATIBLE_SEMIHOSTING
GuestFD console_in_gf;
GuestFD console_out_gf;
#endif
void qemu_semihosting_guestfd_init(void)
{
/* New entries zero-initialized, i.e. type GuestFDUnused */
guestfd_array = g_array_new(FALSE, TRUE, sizeof(GuestFD));
#ifdef CONFIG_ARM_COMPATIBLE_SEMIHOSTING
/* For ARM-compat, the console is in a separate namespace. */
if (use_gdb_syscalls()) {
console_in_gf.type = GuestFDGDB;
console_in_gf.hostfd = 0;
console_out_gf.type = GuestFDGDB;
console_out_gf.hostfd = 2;
} else {
console_in_gf.type = GuestFDConsole;
console_out_gf.type = GuestFDConsole;
if (semihosting_arm_compatible()) {
semihosting_arm_compatible_init();
return;
}
#else
/* Otherwise, the stdio file descriptors apply. */
/* Out of ARM, the stdio file descriptors apply. */
guestfd_array = g_array_set_size(guestfd_array, 3);
#ifndef CONFIG_USER_ONLY
if (!use_gdb_syscalls()) {
@@ -54,7 +39,6 @@ void qemu_semihosting_guestfd_init(void)
associate_guestfd(0, 0);
associate_guestfd(1, 1);
associate_guestfd(2, 2);
#endif
}
/*
+11 -7
View File
@@ -1,17 +1,21 @@
specific_ss.add(when: 'CONFIG_SEMIHOSTING', if_true: files(
'guestfd.c',
'syscalls.c',
))
common_ss.add(when: 'CONFIG_SEMIHOSTING', if_false: files('stubs-all.c'))
user_ss.add(when: 'CONFIG_SEMIHOSTING', if_true: files('user.c'))
user_ss.add(when: 'CONFIG_SEMIHOSTING', if_true: files(
'user.c',
'guestfd.c'))
system_ss.add(when: 'CONFIG_SEMIHOSTING', if_true: files(
'config.c',
'console.c',
'guestfd.c',
'uaccess.c',
'syscalls.c',
), if_false: files(
'stubs-system.c',
))
system_ss.add(when: 'CONFIG_ARM_COMPATIBLE_SEMIHOSTING',
if_true: files('arm-compat-semi.c'),
if_false: files('arm-compat-semi-stub.c'))
specific_ss.add(when: ['CONFIG_ARM_COMPATIBLE_SEMIHOSTING'],
specific_ss.add(when: ['CONFIG_SEMIHOSTING', 'CONFIG_USER_ONLY'],
if_true: files('syscalls.c'))
specific_ss.add(when: ['CONFIG_ARM_COMPATIBLE_SEMIHOSTING', 'CONFIG_USER_ONLY'],
if_true: files('arm-compat-semi.c'))
+54 -55
View File
@@ -8,7 +8,6 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "cpu.h"
#include "gdbstub/syscalls.h"
#include "semihosting/guestfd.h"
#include "semihosting/syscalls.h"
@@ -23,7 +22,7 @@
/*
* Validate or compute the length of the string (including terminator).
*/
static int validate_strlen(CPUState *cs, target_ulong str, target_ulong tlen)
static int validate_strlen(CPUState *cs, vaddr str, uint64_t tlen)
{
CPUArchState *env G_GNUC_UNUSED = cpu_env(cs);
char c;
@@ -52,7 +51,7 @@ static int validate_strlen(CPUState *cs, target_ulong str, target_ulong tlen)
}
static int validate_lock_user_string(char **pstr, CPUState *cs,
target_ulong tstr, target_ulong tlen)
vaddr tstr, uint64_t tlen)
{
int ret = validate_strlen(cs, tstr, tlen);
CPUArchState *env G_GNUC_UNUSED = cpu_env(cs);
@@ -72,7 +71,7 @@ static int validate_lock_user_string(char **pstr, CPUState *cs,
* big-endian. Until we do something with gdb, also produce the
* same big-endian result from the host.
*/
static int copy_stat_to_user(CPUState *cs, target_ulong addr,
static int copy_stat_to_user(CPUState *cs, vaddr addr,
const struct stat *s)
{
CPUArchState *env G_GNUC_UNUSED = cpu_env(cs);
@@ -129,7 +128,7 @@ static void gdb_open_cb(CPUState *cs, uint64_t ret, int err)
}
static void gdb_open(CPUState *cs, gdb_syscall_complete_cb complete,
target_ulong fname, target_ulong fname_len,
vaddr fname, uint64_t fname_len,
int gdb_flags, int mode)
{
int len = validate_strlen(cs, fname, fname_len);
@@ -140,7 +139,7 @@ static void gdb_open(CPUState *cs, gdb_syscall_complete_cb complete,
gdb_open_complete = complete;
gdb_do_syscall(gdb_open_cb, "open,%s,%x,%x",
(uint64_t)fname, (uint32_t)len,
(vaddr)fname, (uint32_t)len,
(uint32_t)gdb_flags, (uint32_t)mode);
}
@@ -151,17 +150,17 @@ static void gdb_close(CPUState *cs, gdb_syscall_complete_cb complete,
}
static void gdb_read(CPUState *cs, gdb_syscall_complete_cb complete,
GuestFD *gf, target_ulong buf, target_ulong len)
GuestFD *gf, vaddr buf, uint64_t len)
{
gdb_do_syscall(complete, "read,%x,%lx,%lx",
(uint32_t)gf->hostfd, (uint64_t)buf, (uint64_t)len);
(uint32_t)gf->hostfd, (vaddr)buf, (uint64_t)len);
}
static void gdb_write(CPUState *cs, gdb_syscall_complete_cb complete,
GuestFD *gf, target_ulong buf, target_ulong len)
GuestFD *gf, vaddr buf, uint64_t len)
{
gdb_do_syscall(complete, "write,%x,%lx,%lx",
(uint32_t)gf->hostfd, (uint64_t)buf, (uint64_t)len);
(uint32_t)gf->hostfd, (vaddr)buf, (uint64_t)len);
}
static void gdb_lseek(CPUState *cs, gdb_syscall_complete_cb complete,
@@ -178,15 +177,15 @@ static void gdb_isatty(CPUState *cs, gdb_syscall_complete_cb complete,
}
static void gdb_fstat(CPUState *cs, gdb_syscall_complete_cb complete,
GuestFD *gf, target_ulong addr)
GuestFD *gf, vaddr addr)
{
gdb_do_syscall(complete, "fstat,%x,%lx",
(uint32_t)gf->hostfd, (uint64_t)addr);
(uint32_t)gf->hostfd, (vaddr)addr);
}
static void gdb_stat(CPUState *cs, gdb_syscall_complete_cb complete,
target_ulong fname, target_ulong fname_len,
target_ulong addr)
vaddr fname, uint64_t fname_len,
vaddr addr)
{
int len = validate_strlen(cs, fname, fname_len);
if (len < 0) {
@@ -195,11 +194,11 @@ static void gdb_stat(CPUState *cs, gdb_syscall_complete_cb complete,
}
gdb_do_syscall(complete, "stat,%s,%lx",
(uint64_t)fname, (uint32_t)len, (uint64_t)addr);
(vaddr)fname, (uint32_t)len, (vaddr)addr);
}
static void gdb_remove(CPUState *cs, gdb_syscall_complete_cb complete,
target_ulong fname, target_ulong fname_len)
vaddr fname, uint64_t fname_len)
{
int len = validate_strlen(cs, fname, fname_len);
if (len < 0) {
@@ -207,12 +206,12 @@ static void gdb_remove(CPUState *cs, gdb_syscall_complete_cb complete,
return;
}
gdb_do_syscall(complete, "unlink,%s", (uint64_t)fname, (uint32_t)len);
gdb_do_syscall(complete, "unlink,%s", (vaddr)fname, (uint32_t)len);
}
static void gdb_rename(CPUState *cs, gdb_syscall_complete_cb complete,
target_ulong oname, target_ulong oname_len,
target_ulong nname, target_ulong nname_len)
vaddr oname, uint64_t oname_len,
vaddr nname, uint64_t nname_len)
{
int olen, nlen;
@@ -228,12 +227,12 @@ static void gdb_rename(CPUState *cs, gdb_syscall_complete_cb complete,
}
gdb_do_syscall(complete, "rename,%s,%s",
(uint64_t)oname, (uint32_t)olen,
(uint64_t)nname, (uint32_t)nlen);
(vaddr)oname, (uint32_t)olen,
(vaddr)nname, (uint32_t)nlen);
}
static void gdb_system(CPUState *cs, gdb_syscall_complete_cb complete,
target_ulong cmd, target_ulong cmd_len)
vaddr cmd, uint64_t cmd_len)
{
int len = validate_strlen(cs, cmd, cmd_len);
if (len < 0) {
@@ -241,14 +240,14 @@ static void gdb_system(CPUState *cs, gdb_syscall_complete_cb complete,
return;
}
gdb_do_syscall(complete, "system,%s", (uint64_t)cmd, (uint32_t)len);
gdb_do_syscall(complete, "system,%s", (vaddr)cmd, (uint32_t)len);
}
static void gdb_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete,
target_ulong tv_addr, target_ulong tz_addr)
vaddr tv_addr, vaddr tz_addr)
{
gdb_do_syscall(complete, "gettimeofday,%lx,%lx",
(uint64_t)tv_addr, (uint64_t)tz_addr);
(vaddr)tv_addr, (vaddr)tz_addr);
}
/*
@@ -256,7 +255,7 @@ static void gdb_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete,
*/
static void host_open(CPUState *cs, gdb_syscall_complete_cb complete,
target_ulong fname, target_ulong fname_len,
vaddr fname, uint64_t fname_len,
int gdb_flags, int mode)
{
CPUArchState *env G_GNUC_UNUSED = cpu_env(cs);
@@ -316,7 +315,7 @@ static void host_close(CPUState *cs, gdb_syscall_complete_cb complete,
}
static void host_read(CPUState *cs, gdb_syscall_complete_cb complete,
GuestFD *gf, target_ulong buf, target_ulong len)
GuestFD *gf, vaddr buf, uint64_t len)
{
CPUArchState *env G_GNUC_UNUSED = cpu_env(cs);
void *ptr = lock_user(VERIFY_WRITE, buf, len, 0);
@@ -337,7 +336,7 @@ static void host_read(CPUState *cs, gdb_syscall_complete_cb complete,
}
static void host_write(CPUState *cs, gdb_syscall_complete_cb complete,
GuestFD *gf, target_ulong buf, target_ulong len)
GuestFD *gf, vaddr buf, uint64_t len)
{
CPUArchState *env G_GNUC_UNUSED = cpu_env(cs);
void *ptr = lock_user(VERIFY_READ, buf, len, 1);
@@ -395,7 +394,7 @@ static void host_flen(CPUState *cs, gdb_syscall_complete_cb complete,
}
static void host_fstat(CPUState *cs, gdb_syscall_complete_cb complete,
GuestFD *gf, target_ulong addr)
GuestFD *gf, vaddr addr)
{
struct stat buf;
int ret;
@@ -410,8 +409,8 @@ static void host_fstat(CPUState *cs, gdb_syscall_complete_cb complete,
}
static void host_stat(CPUState *cs, gdb_syscall_complete_cb complete,
target_ulong fname, target_ulong fname_len,
target_ulong addr)
vaddr fname, uint64_t fname_len,
vaddr addr)
{
CPUArchState *env G_GNUC_UNUSED = cpu_env(cs);
struct stat buf;
@@ -440,7 +439,7 @@ static void host_stat(CPUState *cs, gdb_syscall_complete_cb complete,
}
static void host_remove(CPUState *cs, gdb_syscall_complete_cb complete,
target_ulong fname, target_ulong fname_len)
vaddr fname, uint64_t fname_len)
{
CPUArchState *env G_GNUC_UNUSED = cpu_env(cs);
char *p;
@@ -458,8 +457,8 @@ static void host_remove(CPUState *cs, gdb_syscall_complete_cb complete,
}
static void host_rename(CPUState *cs, gdb_syscall_complete_cb complete,
target_ulong oname, target_ulong oname_len,
target_ulong nname, target_ulong nname_len)
vaddr oname, uint64_t oname_len,
vaddr nname, uint64_t nname_len)
{
CPUArchState *env G_GNUC_UNUSED = cpu_env(cs);
char *ostr, *nstr;
@@ -484,7 +483,7 @@ static void host_rename(CPUState *cs, gdb_syscall_complete_cb complete,
}
static void host_system(CPUState *cs, gdb_syscall_complete_cb complete,
target_ulong cmd, target_ulong cmd_len)
vaddr cmd, uint64_t cmd_len)
{
CPUArchState *env G_GNUC_UNUSED = cpu_env(cs);
char *p;
@@ -502,7 +501,7 @@ static void host_system(CPUState *cs, gdb_syscall_complete_cb complete,
}
static void host_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete,
target_ulong tv_addr, target_ulong tz_addr)
vaddr tv_addr, vaddr tz_addr)
{
CPUArchState *env G_GNUC_UNUSED = cpu_env(cs);
struct gdb_timeval *p;
@@ -547,10 +546,10 @@ static void host_poll_one(CPUState *cs, gdb_syscall_complete_cb complete,
*/
static void staticfile_read(CPUState *cs, gdb_syscall_complete_cb complete,
GuestFD *gf, target_ulong buf, target_ulong len)
GuestFD *gf, vaddr buf, uint64_t len)
{
CPUArchState *env G_GNUC_UNUSED = cpu_env(cs);
target_ulong rest = gf->staticfile.len - gf->staticfile.off;
uint64_t rest = gf->staticfile.len - gf->staticfile.off;
void *ptr;
if (len > rest) {
@@ -605,7 +604,7 @@ static void staticfile_flen(CPUState *cs, gdb_syscall_complete_cb complete,
*/
static void console_read(CPUState *cs, gdb_syscall_complete_cb complete,
GuestFD *gf, target_ulong buf, target_ulong len)
GuestFD *gf, vaddr buf, uint64_t len)
{
CPUArchState *env G_GNUC_UNUSED = cpu_env(cs);
char *ptr;
@@ -622,7 +621,7 @@ static void console_read(CPUState *cs, gdb_syscall_complete_cb complete,
}
static void console_write(CPUState *cs, gdb_syscall_complete_cb complete,
GuestFD *gf, target_ulong buf, target_ulong len)
GuestFD *gf, vaddr buf, uint64_t len)
{
CPUArchState *env G_GNUC_UNUSED = cpu_env(cs);
char *ptr = lock_user(VERIFY_READ, buf, len, 1);
@@ -638,7 +637,7 @@ static void console_write(CPUState *cs, gdb_syscall_complete_cb complete,
}
static void console_fstat(CPUState *cs, gdb_syscall_complete_cb complete,
GuestFD *gf, target_ulong addr)
GuestFD *gf, vaddr addr)
{
static const struct stat tty_buf = {
.st_mode = 020666, /* S_IFCHR, ugo+rw */
@@ -683,7 +682,7 @@ static void console_poll_one(CPUState *cs, gdb_syscall_complete_cb complete,
*/
void semihost_sys_open(CPUState *cs, gdb_syscall_complete_cb complete,
target_ulong fname, target_ulong fname_len,
vaddr fname, uint64_t fname_len,
int gdb_flags, int mode)
{
if (use_gdb_syscalls()) {
@@ -719,7 +718,7 @@ void semihost_sys_close(CPUState *cs, gdb_syscall_complete_cb complete, int fd)
}
void semihost_sys_read_gf(CPUState *cs, gdb_syscall_complete_cb complete,
GuestFD *gf, target_ulong buf, target_ulong len)
GuestFD *gf, vaddr buf, uint64_t len)
{
/*
* Bound length for 64-bit guests on 32-bit hosts, not overflowing ssize_t.
@@ -748,7 +747,7 @@ void semihost_sys_read_gf(CPUState *cs, gdb_syscall_complete_cb complete,
}
void semihost_sys_read(CPUState *cs, gdb_syscall_complete_cb complete,
int fd, target_ulong buf, target_ulong len)
int fd, vaddr buf, uint64_t len)
{
GuestFD *gf = get_guestfd(fd);
@@ -760,7 +759,7 @@ void semihost_sys_read(CPUState *cs, gdb_syscall_complete_cb complete,
}
void semihost_sys_write_gf(CPUState *cs, gdb_syscall_complete_cb complete,
GuestFD *gf, target_ulong buf, target_ulong len)
GuestFD *gf, vaddr buf, uint64_t len)
{
/*
* Bound length for 64-bit guests on 32-bit hosts, not overflowing ssize_t.
@@ -790,7 +789,7 @@ void semihost_sys_write_gf(CPUState *cs, gdb_syscall_complete_cb complete,
}
void semihost_sys_write(CPUState *cs, gdb_syscall_complete_cb complete,
int fd, target_ulong buf, target_ulong len)
int fd, vaddr buf, uint64_t len)
{
GuestFD *gf = get_guestfd(fd);
@@ -856,7 +855,7 @@ void semihost_sys_isatty(CPUState *cs, gdb_syscall_complete_cb complete, int fd)
void semihost_sys_flen(CPUState *cs, gdb_syscall_complete_cb fstat_cb,
gdb_syscall_complete_cb flen_cb, int fd,
target_ulong fstat_addr)
vaddr fstat_addr)
{
GuestFD *gf = get_guestfd(fd);
@@ -881,7 +880,7 @@ void semihost_sys_flen(CPUState *cs, gdb_syscall_complete_cb fstat_cb,
}
void semihost_sys_fstat(CPUState *cs, gdb_syscall_complete_cb complete,
int fd, target_ulong addr)
int fd, vaddr addr)
{
GuestFD *gf = get_guestfd(fd);
@@ -906,8 +905,8 @@ void semihost_sys_fstat(CPUState *cs, gdb_syscall_complete_cb complete,
}
void semihost_sys_stat(CPUState *cs, gdb_syscall_complete_cb complete,
target_ulong fname, target_ulong fname_len,
target_ulong addr)
vaddr fname, uint64_t fname_len,
vaddr addr)
{
if (use_gdb_syscalls()) {
gdb_stat(cs, complete, fname, fname_len, addr);
@@ -917,7 +916,7 @@ void semihost_sys_stat(CPUState *cs, gdb_syscall_complete_cb complete,
}
void semihost_sys_remove(CPUState *cs, gdb_syscall_complete_cb complete,
target_ulong fname, target_ulong fname_len)
vaddr fname, uint64_t fname_len)
{
if (use_gdb_syscalls()) {
gdb_remove(cs, complete, fname, fname_len);
@@ -927,8 +926,8 @@ void semihost_sys_remove(CPUState *cs, gdb_syscall_complete_cb complete,
}
void semihost_sys_rename(CPUState *cs, gdb_syscall_complete_cb complete,
target_ulong oname, target_ulong oname_len,
target_ulong nname, target_ulong nname_len)
vaddr oname, uint64_t oname_len,
vaddr nname, uint64_t nname_len)
{
if (use_gdb_syscalls()) {
gdb_rename(cs, complete, oname, oname_len, nname, nname_len);
@@ -938,7 +937,7 @@ void semihost_sys_rename(CPUState *cs, gdb_syscall_complete_cb complete,
}
void semihost_sys_system(CPUState *cs, gdb_syscall_complete_cb complete,
target_ulong cmd, target_ulong cmd_len)
vaddr cmd, uint64_t cmd_len)
{
if (use_gdb_syscalls()) {
gdb_system(cs, complete, cmd, cmd_len);
@@ -948,7 +947,7 @@ void semihost_sys_system(CPUState *cs, gdb_syscall_complete_cb complete,
}
void semihost_sys_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete,
target_ulong tv_addr, target_ulong tz_addr)
vaddr tv_addr, vaddr tz_addr)
{
if (use_gdb_syscalls()) {
gdb_gettimeofday(cs, complete, tv_addr, tz_addr);
@@ -7,12 +7,12 @@
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef TARGET_ARM_COMMON_SEMI_TARGET_H
#define TARGET_ARM_COMMON_SEMI_TARGET_H
#include "qemu/osdep.h"
#include "cpu.h"
#include "semihosting/common-semi.h"
#include "target/arm/cpu-qom.h"
static inline target_ulong common_semi_arg(CPUState *cs, int argno)
uint64_t common_semi_arg(CPUState *cs, int argno)
{
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
@@ -23,7 +23,7 @@ static inline target_ulong common_semi_arg(CPUState *cs, int argno)
}
}
static inline void common_semi_set_ret(CPUState *cs, target_ulong ret)
void common_semi_set_ret(CPUState *cs, uint64_t ret)
{
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
@@ -34,27 +34,25 @@ static inline void common_semi_set_ret(CPUState *cs, target_ulong ret)
}
}
static inline bool common_semi_sys_exit_extended(CPUState *cs, int nr)
bool common_semi_sys_exit_is_extended(CPUState *cs)
{
return nr == TARGET_SYS_EXIT_EXTENDED || is_a64(cpu_env(cs));
return is_a64(cpu_env(cs));
}
static inline bool is_64bit_semihosting(CPUArchState *env)
bool is_64bit_semihosting(CPUArchState *env)
{
return is_a64(env);
}
static inline target_ulong common_semi_stack_bottom(CPUState *cs)
uint64_t common_semi_stack_bottom(CPUState *cs)
{
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
return is_a64(env) ? env->xregs[31] : env->regs[13];
}
static inline bool common_semi_has_synccache(CPUArchState *env)
bool common_semi_has_synccache(CPUArchState *env)
{
/* Ok for A64, invalid for A32/T32 */
return is_a64(env);
}
#endif
+4
View File
@@ -28,12 +28,16 @@ arm_user_ss.add(files(
'vfp_fpscr.c',
'el2-stubs.c',
))
arm_user_ss.add(when: 'CONFIG_ARM_COMPATIBLE_SEMIHOSTING',
if_true: files('common-semi-target.c'))
arm_common_system_ss.add(files('cpu.c'))
arm_common_system_ss.add(when: 'TARGET_AARCH64', if_false: files(
'cpu32-stubs.c'))
arm_common_system_ss.add(when: 'CONFIG_KVM', if_false: files('kvm-stub.c'))
arm_common_system_ss.add(when: 'CONFIG_HVF', if_false: files('hvf-stub.c'))
arm_common_system_ss.add(when: 'CONFIG_ARM_COMPATIBLE_SEMIHOSTING',
if_true: files('common-semi-target.c'))
arm_common_system_ss.add(files(
'arch_dump.c',
'arm-powerctl.c',
@@ -8,43 +8,42 @@
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef TARGET_RISCV_COMMON_SEMI_TARGET_H
#define TARGET_RISCV_COMMON_SEMI_TARGET_H
#include "qemu/osdep.h"
#include "cpu.h"
#include "semihosting/common-semi.h"
static inline target_ulong common_semi_arg(CPUState *cs, int argno)
uint64_t common_semi_arg(CPUState *cs, int argno)
{
RISCVCPU *cpu = RISCV_CPU(cs);
CPURISCVState *env = &cpu->env;
return env->gpr[xA0 + argno];
}
static inline void common_semi_set_ret(CPUState *cs, target_ulong ret)
void common_semi_set_ret(CPUState *cs, uint64_t ret)
{
RISCVCPU *cpu = RISCV_CPU(cs);
CPURISCVState *env = &cpu->env;
env->gpr[xA0] = ret;
}
static inline bool common_semi_sys_exit_extended(CPUState *cs, int nr)
{
return (nr == TARGET_SYS_EXIT_EXTENDED || sizeof(target_ulong) == 8);
}
static inline bool is_64bit_semihosting(CPUArchState *env)
bool is_64bit_semihosting(CPUArchState *env)
{
return riscv_cpu_mxl(env) != MXL_RV32;
}
static inline target_ulong common_semi_stack_bottom(CPUState *cs)
bool common_semi_sys_exit_is_extended(CPUState *cs)
{
return is_64bit_semihosting(cpu_env(cs));
}
uint64_t common_semi_stack_bottom(CPUState *cs)
{
RISCVCPU *cpu = RISCV_CPU(cs);
CPURISCVState *env = &cpu->env;
return env->gpr[xSP];
}
static inline bool common_semi_has_synccache(CPUArchState *env)
bool common_semi_has_synccache(CPUArchState *env)
{
return true;
}
#endif
+4
View File
@@ -8,6 +8,10 @@ gen = [
riscv_ss = ss.source_set()
riscv_ss.add(gen)
riscv_ss.add(when: 'CONFIG_ARM_COMPATIBLE_SEMIHOSTING',
if_true: files('common-semi-target.c'))
riscv_ss.add(files(
'cpu.c',
'cpu_helper.c',