Import QEMU upstream snapshot d2e570c

Upstream: https://gitlab.com/qemu-project/qemu.git

Upstream-Commit: d2e570cc0f97b936902a5b1b86b73c0f5998b475
This commit is contained in:
2026-08-31 02:15:30 +02:00
commit cf256aa081
11315 changed files with 3598369 additions and 0 deletions
+79
View File
@@ -0,0 +1,79 @@
#ifndef USER_ABITYPES_H
#define USER_ABITYPES_H
#ifndef CONFIG_USER_ONLY
#error Cannot include this header from system emulation
#endif
#include "exec/cpu-defs.h"
#include "user/tswap-target.h"
#ifdef TARGET_ABI32
#define TARGET_ABI_BITS 32
#else
#define TARGET_ABI_BITS TARGET_LONG_BITS
#endif
#ifdef TARGET_M68K
#define ABI_INT_ALIGNMENT 2
#define ABI_LONG_ALIGNMENT 2
#define ABI_LLONG_ALIGNMENT 2
#endif
#if (defined(TARGET_I386) && !defined(TARGET_X86_64)) \
|| defined(TARGET_SH4) \
|| defined(TARGET_OR1K) \
|| defined(TARGET_MICROBLAZE)
#define ABI_LLONG_ALIGNMENT 4
#endif
#ifndef ABI_SHORT_ALIGNMENT
#define ABI_SHORT_ALIGNMENT 2
#endif
#ifndef ABI_INT_ALIGNMENT
#define ABI_INT_ALIGNMENT 4
#endif
#ifndef ABI_LONG_ALIGNMENT
#define ABI_LONG_ALIGNMENT (TARGET_ABI_BITS / 8)
#endif
#ifndef ABI_LLONG_ALIGNMENT
#define ABI_LLONG_ALIGNMENT 8
#endif
typedef int16_t abi_short __attribute__ ((aligned(ABI_SHORT_ALIGNMENT)));
typedef uint16_t abi_ushort __attribute__((aligned(ABI_SHORT_ALIGNMENT)));
typedef int32_t abi_int __attribute__((aligned(ABI_INT_ALIGNMENT)));
typedef uint32_t abi_uint __attribute__((aligned(ABI_INT_ALIGNMENT)));
typedef int64_t abi_llong __attribute__((aligned(ABI_LLONG_ALIGNMENT)));
typedef uint64_t abi_ullong __attribute__((aligned(ABI_LLONG_ALIGNMENT)));
#ifdef TARGET_ABI32
typedef uint32_t abi_ulong __attribute__((aligned(ABI_LONG_ALIGNMENT)));
typedef int32_t abi_long __attribute__((aligned(ABI_LONG_ALIGNMENT)));
#define TARGET_ABI_FMT_lx "%08x"
#define TARGET_ABI_FMT_ld "%d"
#define TARGET_ABI_FMT_lu "%u"
static inline abi_ulong tswapal(abi_ulong v)
{
return tswap32(v);
}
#else
typedef target_ulong abi_ulong __attribute__((aligned(ABI_LONG_ALIGNMENT)));
typedef target_long abi_long __attribute__((aligned(ABI_LONG_ALIGNMENT)));
#define TARGET_ABI_FMT_lx TARGET_FMT_lx
#define TARGET_ABI_FMT_ld TARGET_FMT_ld
#define TARGET_ABI_FMT_lu TARGET_FMT_lu
/* for consistency, define ABI32 too */
#if TARGET_ABI_BITS == 32
#define TARGET_ABI32 1
#endif
static inline abi_ulong tswapal(abi_ulong v)
{
return tswapl(v);
}
#endif
#endif
+84
View File
@@ -0,0 +1,84 @@
/*
* qemu user cpu loop
*
* Copyright (c) 2003-2008 Fabrice Bellard
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef USER_CPU_LOOP_H
#define USER_CPU_LOOP_H
#include "exec/vaddr.h"
#include "exec/mmu-access-type.h"
#include "accel/tcg/cpu-loop.h"
/**
* adjust_signal_pc:
* @pc: raw pc from the host signal ucontext_t.
* @is_write: host memory operation was write, or read-modify-write.
*
* Alter @pc as required for unwinding. Return the type of the
* guest memory access -- host reads may be for guest execution.
*/
MMUAccessType adjust_signal_pc(uintptr_t *pc, bool is_write);
/**
* handle_sigsegv_accerr_write:
* @cpu: the cpu context
* @old_set: the sigset_t from the signal ucontext_t
* @host_pc: the host pc, adjusted for the signal
* @host_addr: the host address of the fault
*
* Return true if the write fault has been handled, and should be re-tried.
*/
bool handle_sigsegv_accerr_write(CPUState *cpu, sigset_t *old_set,
uintptr_t host_pc, vaddr guest_addr);
/**
* cpu_loop_exit_sigsegv:
* @cpu: the cpu context
* @addr: the guest address of the fault
* @access_type: access was read/write/execute
* @maperr: true for invalid page, false for permission fault
* @ra: host pc for unwinding
*
* Use the TCGCPUOps hook to record cpu state, do guest operating system
* specific things to raise SIGSEGV, and jump to the main cpu loop.
*/
G_NORETURN void cpu_loop_exit_sigsegv(CPUState *cpu, vaddr addr,
MMUAccessType access_type,
bool maperr, uintptr_t ra);
/**
* cpu_loop_exit_sigbus:
* @cpu: the cpu context
* @addr: the guest address of the alignment fault
* @access_type: access was read/write/execute
* @ra: host pc for unwinding
*
* Use the TCGCPUOps hook to record cpu state, do guest operating system
* specific things to raise SIGBUS, and jump to the main cpu loop.
*/
G_NORETURN void cpu_loop_exit_sigbus(CPUState *cpu, vaddr addr,
MMUAccessType access_type,
uintptr_t ra);
G_NORETURN void cpu_loop(CPUArchState *env);
void target_exception_dump(CPUArchState *env, const char *fmt, int code);
#define EXCP_DUMP(env, fmt, code) \
target_exception_dump(env, fmt, code)
#endif
+18
View File
@@ -0,0 +1,18 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Declaration of guest_base.
* Copyright (c) 2003 Fabrice Bellard
*/
#ifndef USER_GUEST_BASE_H
#define USER_GUEST_BASE_H
#ifndef CONFIG_USER_ONLY
#error Cannot include this header from system emulation
#endif
extern uintptr_t guest_base;
extern bool have_guest_base;
#endif
+128
View File
@@ -0,0 +1,128 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* guest <-> host helpers.
*
* Copyright (c) 2003 Fabrice Bellard
*/
#ifndef USER_GUEST_HOST_H
#define USER_GUEST_HOST_H
#include "exec/vaddr.h"
#include "user/guest-base.h"
#include "hw/core/cpu.h"
#include "accel/tcg/cpu-ops.h"
/*
* If non-zero, the guest virtual address space is a contiguous subset
* of the host virtual address space, i.e. '-R reserved_va' is in effect
* either from the command-line or by default. The value is the last
* byte of the guest address space e.g. UINT32_MAX.
*
* If zero, the host and guest virtual address spaces are intermingled.
*/
extern unsigned long reserved_va;
/*
* The last byte of the guest address space.
* If reserved_va is non-zero, guest_addr_max matches.
* If reserved_va is zero, guest_addr_max equals the full guest space.
*/
extern unsigned long guest_addr_max;
/*
* These functions take the guest virtual address as a vaddr,
* and are suitable for use from target-independent code.
*/
static inline vaddr cpu_untagged_addr_vaddr(CPUState *cs, vaddr x)
{
const TCGCPUOps *tcg_ops = cs->cc->tcg_ops;
if (tcg_ops->untagged_addr) {
return tcg_ops->untagged_addr(cs, x);
}
return x;
}
/* All direct uses of g2h and h2g need to go away for usermode softmmu. */
static inline void *g2h_untagged_vaddr(vaddr x)
{
return (void *)((uintptr_t)(x) + guest_base);
}
static inline void *g2h_vaddr(CPUState *cs, vaddr x)
{
return g2h_untagged_vaddr(cpu_untagged_addr_vaddr(cs, x));
}
static inline bool guest_addr_valid_untagged_vaddr(vaddr x)
{
return x <= guest_addr_max;
}
static inline bool guest_range_valid_untagged_vaddr(vaddr start, vaddr len)
{
return len - 1 <= guest_addr_max && start <= guest_addr_max - len + 1;
}
#define h2g_valid(x) \
((uintptr_t)(x) - guest_base <= guest_addr_max)
#define h2g_nocheck(x) ({ \
uintptr_t __ret = (uintptr_t)(x) - guest_base; \
(vaddr)__ret; \
})
#define h2g(x) ({ \
/* Check if given address fits target address space */ \
assert(h2g_valid(x)); \
h2g_nocheck(x); \
})
#ifdef COMPILING_PER_TARGET
#include "exec/abi_ptr.h"
/*
* These functions take the guest virtual address as an abi_ptr. This
* is an important difference from a vaddr for the common case where
* the address is a syscall argument in a variable of type abi_long,
* which may be smaller than the vaddr type. If you pass an address in
* an abi_long to these functions then the value will be converted to
* an unsigned type and then zero extended to give the vaddr. If you
* use the g2h_vaddr() and similar functions which take an argument of
* type vaddr, then the value will be sign-extended, giving the wrong
* answer for addresses above the 2GB mark on 32-bit guests.
*
* Providing these functions with their traditional QEMU semantics is
* less bug-prone than requiring many callsites to remember to cast
* their abi_long variable to an abi_ptr before calling.
*/
static inline void *g2h(CPUState *cs, abi_ptr x)
{
return g2h_vaddr(cs, x);
}
static inline void *g2h_untagged(abi_ptr x)
{
return g2h_untagged_vaddr(x);
}
static inline bool guest_addr_valid_untagged(abi_ptr x)
{
return guest_addr_valid_untagged_vaddr(x);
}
static inline bool guest_range_valid_untagged(abi_ptr start, abi_ptr len)
{
return guest_range_valid_untagged_vaddr(start, len);
}
static inline abi_ptr cpu_untagged_addr(CPUState *cs, abi_ptr x)
{
return cpu_untagged_addr_vaddr(cs, x);
}
#endif
#endif
+12
View File
@@ -0,0 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef USER_MMAP_MIN_ADDR_H
#define USER_MMAP_MIN_ADDR_H
#ifndef CONFIG_USER_ONLY
#error Cannot include this header from system emulation
#endif
extern uintptr_t mmap_min_addr;
#endif
+32
View File
@@ -0,0 +1,32 @@
/*
* MMAP declarations for QEMU user emulation
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef USER_MMAP_H
#define USER_MMAP_H
#include "user/abitypes.h"
/*
* mmap_next_start: The base address for the next mmap without hint,
* increased after each successful map, starting at task_unmapped_base.
* This is an optimization within QEMU and not part of ADDR_COMPAT_LAYOUT.
*/
extern abi_ulong mmap_next_start;
int target_mprotect(abi_ulong start, abi_ulong len, int prot);
abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
int flags, int fd, off_t offset);
int target_munmap(abi_ulong start, abi_ulong len);
abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
abi_ulong new_size, unsigned long flags,
abi_ulong new_addr);
abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size, abi_ulong alignment);
void TSA_NO_TSA mmap_fork_start(void);
void TSA_NO_TSA mmap_fork_end(int child);
#endif
+101
View File
@@ -0,0 +1,101 @@
/*
* QEMU page protection declarations.
*
* Copyright (c) 2003 Fabrice Bellard
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifndef USER_PAGE_PROTECTION_H
#define USER_PAGE_PROTECTION_H
#ifndef CONFIG_USER_ONLY
#error Cannot include this header from system emulation
#endif
#include "exec/vaddr.h"
#include "exec/translation-block.h"
int page_unprotect(CPUState *cpu, tb_page_addr_t address, uintptr_t pc);
int page_get_flags(vaddr address);
/**
* page_set_flags:
* @start: first byte of range
* @last: last byte of range
* @set_flags: flags to set
* @clr_flags: flags to clear
* Context: holding mmap lock
*
* Modify the flags of a page and invalidate the code if necessary.
* The flag PAGE_WRITE_ORG is positioned automatically depending
* on PAGE_WRITE. The mmap_lock should already be held.
*
* For each page, flags = (flags & ~clr_flags) | set_flags.
* If clr_flags includes PAGE_VALID, this indicates a new mapping
* and page_reset_target_data will be called as well.
*/
void page_set_flags(vaddr start, vaddr last, int set_flags, int clr_flags);
void page_reset_target_data(vaddr start, vaddr last);
/**
* page_check_range
* @start: first byte of range
* @len: length of range
* @flags: flags required for each page
*
* Return true if every page in [@start, @start+@len) has @flags set.
* Return false if any page is unmapped. Thus testing flags == 0 is
* equivalent to testing for flags == PAGE_VALID.
*/
bool page_check_range(vaddr start, vaddr last, int flags);
/**
* page_check_range_empty:
* @start: first byte of range
* @last: last byte of range
* Context: holding mmap lock
*
* Return true if the entire range [@start, @last] is unmapped.
* The memory lock must be held so that the caller will can ensure
* the result stays true until a new mapping can be installed.
*/
bool page_check_range_empty(vaddr start, vaddr last);
/**
* page_find_range_empty
* @min: first byte of search range
* @max: last byte of search range
* @len: size of the hole required
* @align: alignment of the hole required (power of 2)
*
* If there is a range [x, x+@len) within [@min, @max] such that
* x % @align == 0, then return x. Otherwise return -1.
* The memory lock must be held, as the caller will want to ensure
* the returned range stays empty until a new mapping can be installed.
*/
vaddr page_find_range_empty(vaddr min, vaddr max, vaddr len, vaddr align);
/**
* page_get_target_data
* @address: guest virtual address
* @size: per-page size
*
* Return @size bytes of out-of-band data to associate
* with the guest page at @address, allocating it if necessary. The
* caller should already have verified that the address is valid.
* The value of @size must be the same for every call.
*
* The memory will be freed when the guest page is deallocated,
* e.g. with the munmap system call.
*/
__attribute__((returns_nonnull))
void *page_get_target_data(vaddr address, size_t size);
typedef int (*walk_memory_regions_fn)(void *, vaddr, vaddr, int);
int walk_memory_regions(void *, walk_memory_regions_fn);
void page_dump(FILE *f);
#endif
+37
View File
@@ -0,0 +1,37 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef USER_PROBE_GUEST_BASE_H
#define USER_PROBE_GUEST_BASE_H
#ifndef CONFIG_USER_ONLY
#error Cannot include this header from system emulation
#endif
#include "exec/vaddr.h"
typedef struct PGBRange {
vaddr lo;
vaddr hi;
} PGBRange;
/**
* probe_guest_base:
* @image_name: the executable being loaded
* @image_range: the fixed addresses within the executable
*
* Creates the initial guest address space in the host memory space.
*
* If @image_range is NULL, then no address in the executable is fixed,
* i.e. it is fully relocatable.
*
* This function will not return if a valid value for guest_base
* cannot be chosen. On return, the executable loader can expect
*
* target_mmap(i->lo, i->hi - i->lo + 1, ...)
*
* to succeed.
*/
void probe_guest_base(const char *image_name, const PGBRange *image_range,
const PGBRange *commpage_range);
#endif
+140
View File
@@ -0,0 +1,140 @@
/*
* safe-syscall.h: prototypes for linux-user signal-race-safe syscalls
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LINUX_USER_SAFE_SYSCALL_H
#define LINUX_USER_SAFE_SYSCALL_H
/**
* safe_syscall:
* @int number: number of system call to make
* ...: arguments to the system call
*
* Call a system call if guest signal not pending.
* This has the same API as the libc syscall() function, except that it
* may return -1 with errno == QEMU_ERESTARTSYS if a signal was pending.
*
* Returns: the system call result, or -1 with an error code in errno
* (Errnos are host errnos; we rely on QEMU_ERESTARTSYS not clashing
* with any of the host errno values.)
*/
/*
* A guide to using safe_syscall() to handle interactions between guest
* syscalls and guest signals:
*
* Guest syscalls come in two flavours:
*
* (1) Non-interruptible syscalls
*
* These are guest syscalls that never get interrupted by signals and
* so never return EINTR. They can be implemented straightforwardly in
* QEMU: just make sure that if the implementation code has to make any
* blocking calls that those calls are retried if they return EINTR.
* It's also OK to implement these with safe_syscall, though it will be
* a little less efficient if a signal is delivered at the 'wrong' moment.
*
* Some non-interruptible syscalls need to be handled using block_signals()
* to block signals for the duration of the syscall. This mainly applies
* to code which needs to modify the data structures used by the
* host_signal_handler() function and the functions it calls, including
* all syscalls which change the thread's signal mask.
*
* (2) Interruptible syscalls
*
* These are guest syscalls that can be interrupted by signals and
* for which we need to either return EINTR or arrange for the guest
* syscall to be restarted. This category includes both syscalls which
* always restart (and in the kernel return -ERESTARTNOINTR), ones
* which only restart if there is no handler (kernel returns -ERESTARTNOHAND
* or -ERESTART_RESTARTBLOCK), and the most common kind which restart
* if the handler was registered with SA_RESTART (kernel returns
* -ERESTARTSYS). System calls which are only interruptible in some
* situations (like 'open') also need to be handled this way.
*
* Here it is important that the host syscall is made
* via this safe_syscall() function, and *not* via the host libc.
* If the host libc is used then the implementation will appear to work
* most of the time, but there will be a race condition where a
* signal could arrive just before we make the host syscall inside libc,
* and then the guest syscall will not correctly be interrupted.
* Instead the implementation of the guest syscall can use the safe_syscall
* function but otherwise just return the result or errno in the usual
* way; the main loop code will take care of restarting the syscall
* if appropriate.
*
* (If the implementation needs to make multiple host syscalls this is
* OK; any which might really block must be via safe_syscall(); for those
* which are only technically blocking (ie which we know in practice won't
* stay in the host kernel indefinitely) it's OK to use libc if necessary.
* You must be able to cope with backing out correctly if some safe_syscall
* you make in the implementation returns either -QEMU_ERESTARTSYS or
* EINTR though.)
*
* block_signals() cannot be used for interruptible syscalls.
*
*
* How and why the safe_syscall implementation works:
*
* The basic setup is that we make the host syscall via a known
* section of host native assembly. If a signal occurs, our signal
* handler checks the interrupted host PC against the address of that
* known section. If the PC is before or at the address of the syscall
* instruction then we change the PC to point at a "return
* -QEMU_ERESTARTSYS" code path instead, and then exit the signal handler
* (causing the safe_syscall() call to immediately return that value).
* Then in the main.c loop if we see this magic return value we adjust
* the guest PC to wind it back to before the system call, and invoke
* the guest signal handler as usual.
*
* This winding-back will happen in two cases:
* (1) signal came in just before we took the host syscall (a race);
* in this case we'll take the guest signal and have another go
* at the syscall afterwards, and this is indistinguishable for the
* guest from the timing having been different such that the guest
* signal really did win the race
* (2) signal came in while the host syscall was blocking, and the
* host kernel decided the syscall should be restarted;
* in this case we want to restart the guest syscall also, and so
* rewinding is the right thing. (Note that "restart" semantics mean
* "first call the signal handler, then reattempt the syscall".)
* The other situation to consider is when a signal came in while the
* host syscall was blocking, and the host kernel decided that the syscall
* should not be restarted; in this case QEMU's host signal handler will
* be invoked with the PC pointing just after the syscall instruction,
* with registers indicating an EINTR return; the special code in the
* handler will not kick in, and we will return EINTR to the guest as
* we should.
*
* Notice that we can leave the host kernel to make the decision for
* us about whether to do a restart of the syscall or not; we do not
* need to check SA_RESTART flags in QEMU or distinguish the various
* kinds of restartability.
*/
/* The core part of this function is implemented in assembly */
long safe_syscall_base(int *pending, long number, ...);
long safe_syscall_set_errno_tail(int value);
/* These are defined by the safe-syscall.inc.S file */
extern char safe_syscall_start[];
extern char safe_syscall_end[];
#define safe_syscall(...) \
safe_syscall_base(&get_task_state(thread_cpu)->signal_pending, \
__VA_ARGS__)
#endif
+44
View File
@@ -0,0 +1,44 @@
/*
* Utility functions to read our own memory map
*
* Copyright (c) 2020 Linaro Ltd
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef SELFMAP_H
#define SELFMAP_H
#include "qemu/interval-tree.h"
typedef struct {
IntervalTreeNode itree;
/* flags */
bool is_read;
bool is_write;
bool is_exec;
bool is_priv;
dev_t dev;
ino_t inode;
uint64_t offset;
const char *path;
} MapInfo;
/**
* read_self_maps:
*
* Read /proc/self/maps and return a tree of MapInfo structures.
*/
IntervalTreeRoot *read_self_maps(void);
/**
* free_self_maps:
* @info: an interval tree
*
* Free a tree of MapInfo structures.
*/
void free_self_maps(IntervalTreeRoot *root);
#endif /* SELFMAP_H */
+25
View File
@@ -0,0 +1,25 @@
/*
* Signal-related declarations.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef USER_SIGNAL_H
#define USER_SIGNAL_H
#ifndef CONFIG_USER_ONLY
#error Cannot include this header from system emulation
#endif
/**
* target_to_host_signal:
* @sig: target signal.
*
* On success, return the host signal between 0 (inclusive) and NSIG
* (exclusive) corresponding to the target signal @sig. Return any other value
* on failure.
*/
int target_to_host_signal(int sig);
extern int host_interrupt_signal;
#endif
+213
View File
@@ -0,0 +1,213 @@
/*
* Generic thunking code to convert data between host and target CPU
*
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef USER_THUNK_H
#define USER_THUNK_H
#ifndef CONFIG_USER_ONLY
#error Cannot include this header from system emulation
#endif
#include "cpu.h"
#include "user/abitypes.h"
/* types enums definitions */
typedef enum argtype {
TYPE_NULL,
TYPE_CHAR,
TYPE_SHORT,
TYPE_INT,
TYPE_LONG,
TYPE_ULONG,
TYPE_PTRVOID, /* pointer on unknown data */
TYPE_LONGLONG,
TYPE_ULONGLONG,
TYPE_PTR,
TYPE_ARRAY,
TYPE_STRUCT,
TYPE_OLDDEVT,
} argtype;
#define MK_PTR(type) TYPE_PTR, type
#define MK_ARRAY(type, size) TYPE_ARRAY, (int)(size), type
#define MK_STRUCT(id) TYPE_STRUCT, id
#define THUNK_TARGET 0
#define THUNK_HOST 1
typedef struct {
/* standard struct handling */
const argtype *field_types;
int nb_fields;
int *field_offsets[2];
/* special handling */
void (*convert[2])(void *dst, const void *src);
void (*print)(void *arg);
int size[2];
int align[2];
const char *name;
} StructEntry;
/* Translation table for bitmasks... */
typedef struct bitmask_transtbl {
unsigned int target_mask;
unsigned int target_bits;
unsigned int host_mask;
unsigned int host_bits;
} bitmask_transtbl;
void thunk_register_struct(int id, const char *name, const argtype *types);
void thunk_register_struct_direct(int id, const char *name,
const StructEntry *se1);
const argtype *thunk_convert(void *dst, const void *src,
const argtype *type_ptr, int to_host);
const argtype *thunk_print(void *arg, const argtype *type_ptr);
extern StructEntry *struct_entries;
int thunk_type_size_array(const argtype *type_ptr, int is_host);
int thunk_type_align_array(const argtype *type_ptr, int is_host);
static inline int thunk_type_size(const argtype *type_ptr, int is_host)
{
int type, size;
const StructEntry *se;
type = *type_ptr;
switch(type) {
case TYPE_CHAR:
return 1;
case TYPE_SHORT:
return 2;
case TYPE_INT:
return 4;
case TYPE_LONGLONG:
case TYPE_ULONGLONG:
return 8;
case TYPE_LONG:
case TYPE_ULONG:
case TYPE_PTRVOID:
case TYPE_PTR:
if (is_host) {
return sizeof(void *);
} else {
return TARGET_ABI_BITS / 8;
}
break;
case TYPE_OLDDEVT:
if (is_host) {
#if defined(HOST_X86_64)
return 8;
#elif defined(HOST_SPARC64)
return 4;
#elif defined(HOST_PPC)
return sizeof(void *);
#else
return 2;
#endif
} else {
#if defined(TARGET_X86_64)
return 8;
#elif defined(TARGET_ALPHA) || defined(TARGET_IA64) || defined(TARGET_MIPS) || \
defined(TARGET_PARISC) || defined(TARGET_SPARC64)
return 4;
#elif defined(TARGET_PPC)
return TARGET_ABI_BITS / 8;
#else
return 2;
#endif
}
break;
case TYPE_ARRAY:
size = type_ptr[1];
return size * thunk_type_size_array(type_ptr + 2, is_host);
case TYPE_STRUCT:
se = struct_entries + type_ptr[1];
return se->size[is_host];
default:
g_assert_not_reached();
}
}
static inline int thunk_type_align(const argtype *type_ptr, int is_host)
{
int type;
const StructEntry *se;
type = *type_ptr;
switch(type) {
case TYPE_CHAR:
return 1;
case TYPE_SHORT:
if (is_host) {
return __alignof__(short);
} else {
return ABI_SHORT_ALIGNMENT;
}
case TYPE_INT:
if (is_host) {
return __alignof__(int);
} else {
return ABI_INT_ALIGNMENT;
}
case TYPE_LONGLONG:
case TYPE_ULONGLONG:
if (is_host) {
return __alignof__(long long);
} else {
return ABI_LLONG_ALIGNMENT;
}
case TYPE_LONG:
case TYPE_ULONG:
case TYPE_PTRVOID:
case TYPE_PTR:
if (is_host) {
return __alignof__(long);
} else {
return ABI_LONG_ALIGNMENT;
}
break;
case TYPE_OLDDEVT:
return thunk_type_size(type_ptr, is_host);
case TYPE_ARRAY:
return thunk_type_align_array(type_ptr + 2, is_host);
case TYPE_STRUCT:
se = struct_entries + type_ptr[1];
return se->align[is_host];
default:
g_assert_not_reached();
}
}
unsigned int target_to_host_bitmask_len(unsigned int target_mask,
const bitmask_transtbl *trans_tbl,
size_t trans_len);
unsigned int host_to_target_bitmask_len(unsigned int host_mask,
const bitmask_transtbl * trans_tbl,
size_t trans_len);
#define target_to_host_bitmask(M, T) \
target_to_host_bitmask_len(M, T, ARRAY_SIZE(T))
#define host_to_target_bitmask(M, T) \
host_to_target_bitmask_len(M, T, ARRAY_SIZE(T))
void thunk_init(unsigned int max_structs);
#endif
+22
View File
@@ -0,0 +1,22 @@
/*
* target-specific swap() definitions
*
* Copyright (c) 2003 Fabrice Bellard
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef USER_TSWAP_H
#define USER_TSWAP_H
#include "exec/cpu-defs.h"
#include "exec/tswap.h"
#if TARGET_LONG_SIZE == 4
#define tswapl(s) tswap32(s)
#define bswaptls(s) bswap32s(s)
#else
#define tswapl(s) tswap64(s)
#define bswaptls(s) bswap64s(s)
#endif
#endif