Merge tag 'v9.2.0'

v9.2.0 release
This commit is contained in:
Matt Borgerson
2025-01-03 22:30:04 -07:00
6666 changed files with 569745 additions and 361417 deletions
+33
View File
@@ -0,0 +1,33 @@
/*
* QEMU abi_ptr type definitions
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef EXEC_ABI_PTR_H
#define EXEC_ABI_PTR_H
#include "cpu-param.h"
#if defined(CONFIG_USER_ONLY)
/*
* sparc32plus has 64bit long but 32bit space address
* this can make bad result with g2h() and h2g()
*/
#if TARGET_VIRT_ADDR_SPACE_BITS <= 32
typedef uint32_t abi_ptr;
#define TARGET_ABI_FMT_ptr "%x"
#else
typedef uint64_t abi_ptr;
#define TARGET_ABI_FMT_ptr "%"PRIx64
#endif
#else /* !CONFIG_USER_ONLY */
#include "exec/target_long.h"
typedef target_ulong abi_ptr;
#define TARGET_ABI_FMT_ptr TARGET_FMT_lx
#endif /* !CONFIG_USER_ONLY */
#endif
-2
View File
@@ -19,8 +19,6 @@
* you're one of them.
*/
#include "exec/memory.h"
#ifndef CONFIG_USER_ONLY
/* Get the root memory region. This interface should only be used temporarily
+30
View File
@@ -0,0 +1,30 @@
/*
* QEMU breakpoint & watchpoint definitions
*
* Copyright (c) 2012 SUSE LINUX Products GmbH
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef EXEC_BREAKPOINT_H
#define EXEC_BREAKPOINT_H
#include "qemu/queue.h"
#include "exec/vaddr.h"
#include "exec/memattrs.h"
typedef struct CPUBreakpoint {
vaddr pc;
int flags; /* BP_* */
QTAILQ_ENTRY(CPUBreakpoint) entry;
} CPUBreakpoint;
typedef struct CPUWatchpoint {
vaddr vaddr;
vaddr len;
vaddr hitaddr;
MemTxAttrs hitattrs;
int flags; /* BP_* */
QTAILQ_ENTRY(CPUWatchpoint) entry;
} CPUWatchpoint;
#endif
+38 -1
View File
@@ -23,11 +23,19 @@
#include "qom/object.h"
#define TYPE_CONFIDENTIAL_GUEST_SUPPORT "confidential-guest-support"
OBJECT_DECLARE_SIMPLE_TYPE(ConfidentialGuestSupport, CONFIDENTIAL_GUEST_SUPPORT)
OBJECT_DECLARE_TYPE(ConfidentialGuestSupport,
ConfidentialGuestSupportClass,
CONFIDENTIAL_GUEST_SUPPORT)
struct ConfidentialGuestSupport {
Object parent;
/*
* True if the machine should use guest_memfd for RAM.
*/
bool require_guest_memfd;
/*
* ready: flag set by CGS initialization code once it's ready to
* start executing instructions in a potentially-secure
@@ -55,8 +63,37 @@ struct ConfidentialGuestSupport {
typedef struct ConfidentialGuestSupportClass {
ObjectClass parent;
int (*kvm_init)(ConfidentialGuestSupport *cgs, Error **errp);
int (*kvm_reset)(ConfidentialGuestSupport *cgs, Error **errp);
} ConfidentialGuestSupportClass;
static inline int confidential_guest_kvm_init(ConfidentialGuestSupport *cgs,
Error **errp)
{
ConfidentialGuestSupportClass *klass;
klass = CONFIDENTIAL_GUEST_SUPPORT_GET_CLASS(cgs);
if (klass->kvm_init) {
return klass->kvm_init(cgs, errp);
}
return 0;
}
static inline int confidential_guest_kvm_reset(ConfidentialGuestSupport *cgs,
Error **errp)
{
ConfidentialGuestSupportClass *klass;
klass = CONFIDENTIAL_GUEST_SUPPORT_GET_CLASS(cgs);
if (klass->kvm_reset) {
return klass->kvm_reset(cgs, errp);
}
return 0;
}
#endif /* !CONFIG_USER_ONLY */
#endif /* QEMU_CONFIDENTIAL_GUEST_SUPPORT_H */
+114 -225
View File
@@ -19,18 +19,11 @@
#ifndef CPU_ALL_H
#define CPU_ALL_H
#include "exec/page-protection.h"
#include "exec/cpu-common.h"
#include "exec/memory.h"
#include "qemu/thread.h"
#include "exec/tswap.h"
#include "hw/core/cpu.h"
#include "qemu/rcu.h"
#define EXCP_INTERRUPT 0x10000 /* async interruption */
#define EXCP_HLT 0x10001 /* hlt instruction reached */
#define EXCP_DEBUG 0x10002 /* cpu stopped after a breakpoint or singlestep */
#define EXCP_HALTED 0x10003 /* cpu is halted (waiting for external event) */
#define EXCP_YIELD 0x10004 /* cpu wants to yield timeslice to another */
#define EXCP_ATOMIC 0x10005 /* stop-the-world and emulate atomic */
/* some important defines:
*
@@ -44,79 +37,6 @@
#define BSWAP_NEEDED
#endif
#ifdef BSWAP_NEEDED
static inline uint16_t tswap16(uint16_t s)
{
return bswap16(s);
}
static inline uint32_t tswap32(uint32_t s)
{
return bswap32(s);
}
static inline uint64_t tswap64(uint64_t s)
{
return bswap64(s);
}
static inline void tswap16s(uint16_t *s)
{
*s = bswap16(*s);
}
static inline void tswap32s(uint32_t *s)
{
*s = bswap32(*s);
}
static inline void tswap64s(uint64_t *s)
{
*s = bswap64(*s);
}
#else
static inline uint16_t tswap16(uint16_t s)
{
return s;
}
static inline uint32_t tswap32(uint32_t s)
{
return s;
}
static inline uint64_t tswap64(uint64_t s)
{
return s;
}
static inline void tswap16s(uint16_t *s)
{
}
static inline void tswap32s(uint32_t *s)
{
}
static inline void tswap64s(uint64_t *s)
{
}
#endif
#if TARGET_LONG_SIZE == 4
#define tswapl(s) tswap32(s)
#define tswapls(s) tswap32s((uint32_t *)(s))
#define bswaptls(s) bswap32s(s)
#else
#define tswapl(s) tswap64(s)
#define tswapls(s) tswap64s((uint64_t *)(s))
#define bswaptls(s) bswap64s(s)
#endif
/* Target-endianness CPU memory access functions. These fit into the
* {ld,st}{type}{sign}{size}{endian}_p naming scheme described in bswap.h.
*/
@@ -145,13 +65,16 @@ static inline void tswap64s(uint64_t *s)
/* MMU memory access macros */
#if defined(CONFIG_USER_ONLY)
#include "exec/user/abitypes.h"
#include "user/abitypes.h"
/* On some host systems the guest address space is reserved on the host.
* This allows the guest address space to be offset to a convenient location.
/*
* 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 uintptr_t guest_base;
extern bool have_guest_base;
extern unsigned long reserved_va;
/*
@@ -171,7 +94,7 @@ extern unsigned long reserved_va;
#define GUEST_ADDR_MAX_ \
((MIN_CONST(TARGET_VIRT_ADDR_SPACE_BITS, TARGET_ABI_BITS) <= 32) ? \
UINT32_MAX : ~0ul)
#define GUEST_ADDR_MAX (reserved_va ? reserved_va - 1 : GUEST_ADDR_MAX_)
#define GUEST_ADDR_MAX (reserved_va ? : GUEST_ADDR_MAX_)
#else
@@ -217,57 +140,24 @@ static inline void stl_phys_notdirty(AddressSpace *as, hwaddr addr, uint32_t val
#ifdef TARGET_PAGE_BITS_VARY
# include "exec/page-vary.h"
extern const TargetPageBits target_page;
#ifdef CONFIG_DEBUG_TCG
#define TARGET_PAGE_BITS ({ assert(target_page.decided); target_page.bits; })
#define TARGET_PAGE_MASK ({ assert(target_page.decided); \
(target_long)target_page.mask; })
# ifdef CONFIG_DEBUG_TCG
# define TARGET_PAGE_BITS ({ assert(target_page.decided); \
target_page.bits; })
# define TARGET_PAGE_MASK ({ assert(target_page.decided); \
(target_long)target_page.mask; })
# else
# define TARGET_PAGE_BITS target_page.bits
# define TARGET_PAGE_MASK ((target_long)target_page.mask)
# endif
# define TARGET_PAGE_SIZE (-(int)TARGET_PAGE_MASK)
#else
#define TARGET_PAGE_BITS target_page.bits
#define TARGET_PAGE_MASK ((target_long)target_page.mask)
#endif
#define TARGET_PAGE_SIZE (-(int)TARGET_PAGE_MASK)
#else
#define TARGET_PAGE_BITS_MIN TARGET_PAGE_BITS
#define TARGET_PAGE_SIZE (1 << TARGET_PAGE_BITS)
#define TARGET_PAGE_MASK ((target_long)-1 << TARGET_PAGE_BITS)
# define TARGET_PAGE_BITS_MIN TARGET_PAGE_BITS
# define TARGET_PAGE_SIZE (1 << TARGET_PAGE_BITS)
# define TARGET_PAGE_MASK ((target_long)-1 << TARGET_PAGE_BITS)
#endif
#define TARGET_PAGE_ALIGN(addr) ROUND_UP((addr), TARGET_PAGE_SIZE)
/* same as PROT_xxx */
#define PAGE_READ 0x0001
#define PAGE_WRITE 0x0002
#define PAGE_EXEC 0x0004
#define PAGE_BITS (PAGE_READ | PAGE_WRITE | PAGE_EXEC)
#define PAGE_VALID 0x0008
/*
* Original state of the write flag (used when tracking self-modifying code)
*/
#define PAGE_WRITE_ORG 0x0010
/*
* Invalidate the TLB entry immediately, helpful for s390x
* Low-Address-Protection. Used with PAGE_WRITE in tlb_set_page_with_attrs()
*/
#define PAGE_WRITE_INV 0x0020
/* For use with page_set_flags: page is being replaced; target_data cleared. */
#define PAGE_RESET 0x0040
/* For linux-user, indicates that the page is MAP_ANON. */
#define PAGE_ANON 0x0080
#if defined(CONFIG_BSD) && defined(CONFIG_USER_ONLY)
/* FIXME: Code that sets/uses this is broken and needs to go away. */
#define PAGE_RESERVED 0x0100
#endif
/* Target-specific bits that will be used via page_get_flags(). */
#define PAGE_TARGET_1 0x0200
#define PAGE_TARGET_2 0x0400
/*
* For linux-user, indicates that the page is mapped with the same semantics
* in both guest and host.
*/
#define PAGE_PASSTHROUGH 0x0800
#if defined(CONFIG_USER_ONLY)
void page_dump(FILE *f);
@@ -276,9 +166,60 @@ typedef int (*walk_memory_regions_fn)(void *, target_ulong,
int walk_memory_regions(void *, walk_memory_regions_fn);
int page_get_flags(target_ulong address);
void page_set_flags(target_ulong start, target_ulong end, int flags);
void page_reset_target_data(target_ulong start, target_ulong end);
int page_check_range(target_ulong start, target_ulong len, int flags);
/**
* page_set_flags:
* @start: first byte of range
* @last: last byte of range
* @flags: flags to set
* 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.
*/
void page_set_flags(target_ulong start, target_ulong last, int flags);
void page_reset_target_data(target_ulong start, target_ulong 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(target_ulong start, target_ulong 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(target_ulong start, target_ulong 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.
*/
target_ulong page_find_range_empty(target_ulong min, target_ulong max,
target_ulong len, target_ulong align);
/**
* page_get_target_data(address)
@@ -357,9 +298,13 @@ CPUArchState *cpu_copy(CPUArchState *env);
* be signaled by probe_access_flags().
*/
#define TLB_INVALID_MASK (1 << (TARGET_PAGE_BITS_MIN - 1))
#define TLB_MMIO 0
#define TLB_MMIO (1 << (TARGET_PAGE_BITS_MIN - 2))
#define TLB_WATCHPOINT 0
static inline int cpu_mmu_index(CPUState *cs, bool ifetch)
{
return MMU_USER_IDX;
}
#else
/*
@@ -370,6 +315,9 @@ CPUArchState *cpu_copy(CPUArchState *env);
*
* Use TARGET_PAGE_BITS_MIN so that these bits are constant
* when TARGET_PAGE_BITS_VARY is in effect.
*
* The count, if not the placement of these bits is known
* to tcg/tcg-op-ldst.c, check_max_alignment().
*/
/* Zero if TLB entry is valid. */
#define TLB_INVALID_MASK (1 << (TARGET_PAGE_BITS_MIN - 1))
@@ -378,19 +326,34 @@ CPUArchState *cpu_copy(CPUArchState *env);
#define TLB_NOTDIRTY (1 << (TARGET_PAGE_BITS_MIN - 2))
/* Set if TLB entry is an IO callback. */
#define TLB_MMIO (1 << (TARGET_PAGE_BITS_MIN - 3))
/* Set if TLB entry contains a watchpoint. */
#define TLB_WATCHPOINT (1 << (TARGET_PAGE_BITS_MIN - 4))
/* Set if TLB entry requires byte swap. */
#define TLB_BSWAP (1 << (TARGET_PAGE_BITS_MIN - 5))
/* Set if TLB entry writes ignored. */
#define TLB_DISCARD_WRITE (1 << (TARGET_PAGE_BITS_MIN - 6))
#define TLB_DISCARD_WRITE (1 << (TARGET_PAGE_BITS_MIN - 4))
/* Set if the slow path must be used; more flags in CPUTLBEntryFull. */
#define TLB_FORCE_SLOW (1 << (TARGET_PAGE_BITS_MIN - 5))
/* Use this mask to check interception with an alignment mask
/*
* Use this mask to check interception with an alignment mask
* in a TCG backend.
*/
#define TLB_FLAGS_MASK \
(TLB_INVALID_MASK | TLB_NOTDIRTY | TLB_MMIO \
| TLB_WATCHPOINT | TLB_BSWAP | TLB_DISCARD_WRITE)
| TLB_FORCE_SLOW | TLB_DISCARD_WRITE)
/*
* Flags stored in CPUTLBEntryFull.slow_flags[x].
* TLB_FORCE_SLOW must be set in CPUTLBEntry.addr_idx[x].
*/
/* Set if TLB entry requires byte swap. */
#define TLB_BSWAP (1 << 0)
/* Set if TLB entry contains a watchpoint. */
#define TLB_WATCHPOINT (1 << 1)
/* Set if TLB entry requires aligned accesses. */
#define TLB_CHECK_ALIGNED (1 << 2)
#define TLB_SLOW_FLAGS_MASK (TLB_BSWAP | TLB_WATCHPOINT | TLB_CHECK_ALIGNED)
/* The two sets of flags must not overlap. */
QEMU_BUILD_BUG_ON(TLB_FLAGS_MASK & TLB_SLOW_FLAGS_MASK);
/**
* tlb_hit_page: return true if page aligned @addr is a hit against the
@@ -399,7 +362,7 @@ CPUArchState *cpu_copy(CPUArchState *env);
* @addr: virtual address to test (must be page aligned)
* @tlb_addr: TLB entry address (a CPUTLBEntry addr_read/write/code value)
*/
static inline bool tlb_hit_page(target_ulong tlb_addr, target_ulong addr)
static inline bool tlb_hit_page(uint64_t tlb_addr, vaddr addr)
{
return addr == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK));
}
@@ -410,90 +373,16 @@ static inline bool tlb_hit_page(target_ulong tlb_addr, target_ulong addr)
* @addr: virtual address to test (need not be page aligned)
* @tlb_addr: TLB entry address (a CPUTLBEntry addr_read/write/code value)
*/
static inline bool tlb_hit(target_ulong tlb_addr, target_ulong addr)
static inline bool tlb_hit(uint64_t tlb_addr, vaddr addr)
{
return tlb_hit_page(tlb_addr, addr & TARGET_PAGE_MASK);
}
#ifdef CONFIG_TCG
/* accel/tcg/translate-all.c */
void dump_exec_info(GString *buf);
#endif /* CONFIG_TCG */
#endif /* !CONFIG_USER_ONLY */
/* accel/tcg/cpu-exec.c */
int cpu_exec(CPUState *cpu);
void tcg_exec_realizefn(CPUState *cpu, Error **errp);
void tcg_exec_unrealizefn(CPUState *cpu);
/**
* cpu_set_cpustate_pointers(cpu)
* @cpu: The cpu object
*
* Set the generic pointers in CPUState into the outer object.
*/
static inline void cpu_set_cpustate_pointers(ArchCPU *cpu)
{
cpu->parent_obj.env_ptr = &cpu->env;
cpu->parent_obj.icount_decr_ptr = &cpu->neg.icount_decr;
}
/**
* env_archcpu(env)
* @env: The architecture environment
*
* Return the ArchCPU associated with the environment.
*/
static inline ArchCPU *env_archcpu(CPUArchState *env)
{
return container_of(env, ArchCPU, env);
}
/**
* env_cpu(env)
* @env: The architecture environment
*
* Return the CPUState associated with the environment.
*/
static inline CPUState *env_cpu(CPUArchState *env)
{
return &env_archcpu(env)->parent_obj;
}
/**
* env_neg(env)
* @env: The architecture environment
*
* Return the CPUNegativeOffsetState associated with the environment.
*/
static inline CPUNegativeOffsetState *env_neg(CPUArchState *env)
{
ArchCPU *arch_cpu = container_of(env, ArchCPU, env);
return &arch_cpu->neg;
}
/**
* cpu_neg(cpu)
* @cpu: The generic CPUState
*
* Return the CPUNegativeOffsetState associated with the cpu.
*/
static inline CPUNegativeOffsetState *cpu_neg(CPUState *cpu)
{
ArchCPU *arch_cpu = container_of(cpu, ArchCPU, parent_obj);
return &arch_cpu->neg;
}
/**
* env_tlb(env)
* @env: The architecture environment
*
* Return the CPUTLB state associated with the environment.
*/
static inline CPUTLB *env_tlb(CPUArchState *env)
{
return &env_neg(env)->tlb;
}
/* Validate correct placement of CPUArchState. */
#include "cpu.h"
QEMU_BUILD_BUG_ON(offsetof(ArchCPU, parent_obj) != 0);
QEMU_BUILD_BUG_ON(offsetof(ArchCPU, env) != sizeof(CPUState));
#endif /* CPU_ALL_H */
+140 -27
View File
@@ -1,44 +1,41 @@
/*
* CPU interfaces that are target independent.
*
* Copyright (c) 2003 Fabrice Bellard
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifndef CPU_COMMON_H
#define CPU_COMMON_H
/* CPU interfaces that are target independent. */
#include "exec/vaddr.h"
#ifndef CONFIG_USER_ONLY
#include "exec/hwaddr.h"
#endif
#include "hw/core/cpu.h"
#include "tcg/debug-assert.h"
#include "exec/page-protection.h"
/**
* vaddr:
* Type wide enough to contain any #target_ulong virtual address.
*/
typedef uint64_t vaddr;
#define VADDR_PRId PRId64
#define VADDR_PRIu PRIu64
#define VADDR_PRIo PRIo64
#define VADDR_PRIx PRIx64
#define VADDR_PRIX PRIX64
#define VADDR_MAX UINT64_MAX
#define EXCP_INTERRUPT 0x10000 /* async interruption */
#define EXCP_HLT 0x10001 /* hlt instruction reached */
#define EXCP_DEBUG 0x10002 /* cpu stopped after a breakpoint or singlestep */
#define EXCP_HALTED 0x10003 /* cpu is halted (waiting for external event) */
#define EXCP_YIELD 0x10004 /* cpu wants to yield timeslice to another */
#define EXCP_ATOMIC 0x10005 /* stop-the-world and emulate atomic */
void cpu_exec_init_all(void);
void cpu_exec_step_atomic(CPUState *cpu);
/* Using intptr_t ensures that qemu_*_page_mask is sign-extended even
* when intptr_t is 32-bit and we are aligning a long long.
*/
extern uintptr_t qemu_host_page_size;
extern intptr_t qemu_host_page_mask;
#define HOST_PAGE_ALIGN(addr) ROUND_UP((addr), qemu_host_page_size)
#define REAL_HOST_PAGE_ALIGN(addr) ROUND_UP((addr), qemu_real_host_page_size())
/* The CPU list lock nests outside page_(un)lock or mmap_(un)lock */
extern QemuMutex qemu_cpu_list_lock;
void qemu_init_cpu_list(void);
void cpu_list_lock(void);
void cpu_list_unlock(void);
unsigned int cpu_list_generation_id_get(void);
void tcg_flush_softmmu_tlb(CPUState *cs);
void tcg_flush_jmp_cache(CPUState *cs);
int cpu_get_free_index(void);
void tcg_iommu_init_notifier_list(CPUState *cpu);
void tcg_iommu_free_notifier_list(CPUState *cpu);
@@ -75,6 +72,21 @@ void qemu_ram_remap(ram_addr_t addr, ram_addr_t length);
ram_addr_t qemu_ram_addr_from_host(void *ptr);
ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr);
RAMBlock *qemu_ram_block_by_name(const char *name);
/*
* Translates a host ptr back to a RAMBlock and an offset in that RAMBlock.
*
* @ptr: The host pointer to translate.
* @round_offset: Whether to round the result offset down to a target page
* @offset: Will be set to the offset within the returned RAMBlock.
*
* Returns: RAMBlock (or NULL if not found)
*
* By the time this function returns, the returned pointer is not protected
* by RCU anymore. If the caller is not within an RCU critical section and
* does not hold the BQL, it must have other means of protecting the
* pointer, such as a reference to the memory region that owns the RAMBlock.
*/
RAMBlock *qemu_ram_block_from_host(void *ptr, bool round_offset,
ram_addr_t *offset);
ram_addr_t qemu_ram_block_host_offset(RAMBlock *rb, void *host);
@@ -92,6 +104,7 @@ void qemu_ram_set_uf_zeroable(RAMBlock *rb);
bool qemu_ram_is_migratable(RAMBlock *rb);
void qemu_ram_set_migratable(RAMBlock *rb);
void qemu_ram_unset_migratable(RAMBlock *rb);
bool qemu_ram_is_named_file(RAMBlock *rb);
int qemu_ram_get_fd(RAMBlock *rb);
size_t qemu_ram_pagesize(RAMBlock *block);
@@ -118,6 +131,14 @@ size_t qemu_ram_pagesize_largest(void);
*/
void cpu_address_space_init(CPUState *cpu, int asidx,
const char *prefix, MemoryRegion *mr);
/**
* cpu_address_space_destroy:
* @cpu: CPU for which address space needs to be destroyed
* @asidx: integer index of this address space
*
* Note that with KVM only one address space is supported.
*/
void cpu_address_space_destroy(CPUState *cpu, int asidx);
void cpu_physical_memory_rw(hwaddr addr, void *buf,
hwaddr len, bool is_write);
@@ -131,14 +152,11 @@ static inline void cpu_physical_memory_write(hwaddr addr,
{
cpu_physical_memory_rw(addr, (void *)buf, len, true);
}
void cpu_reloading_memory_map(void);
void *cpu_physical_memory_map(hwaddr addr,
hwaddr *plen,
bool is_write);
void cpu_physical_memory_unmap(void *buffer, hwaddr len,
bool is_write, hwaddr access_len);
void cpu_register_map_client(QEMUBH *bh);
void cpu_unregister_map_client(QEMUBH *bh);
bool cpu_physical_memory_is_io(hwaddr phys_addr);
@@ -155,6 +173,8 @@ typedef int (RAMBlockIterFunc)(RAMBlock *rb, void *opaque);
int qemu_ram_foreach_block(RAMBlockIterFunc func, void *opaque);
int ram_block_discard_range(RAMBlock *rb, uint64_t start, size_t length);
int ram_block_discard_guest_memfd_range(RAMBlock *rb, uint64_t start,
size_t length);
#endif
@@ -163,8 +183,101 @@ int cpu_memory_rw_debug(CPUState *cpu, vaddr addr,
void *ptr, size_t len, bool is_write);
/* vl.c */
extern int singlestep;
void list_cpus(void);
void list_cpus(const char *optarg);
#ifdef CONFIG_TCG
bool tcg_cflags_has(CPUState *cpu, uint32_t flags);
void tcg_cflags_set(CPUState *cpu, uint32_t flags);
/* current cflags for hashing/comparison */
uint32_t curr_cflags(CPUState *cpu);
/**
* cpu_unwind_state_data:
* @cpu: the cpu context
* @host_pc: the host pc within the translation
* @data: output data
*
* Attempt to load the the unwind state for a host pc occurring in
* translated code. If @host_pc is not in translated code, the
* function returns false; otherwise @data is loaded.
* This is the same unwind info as given to restore_state_to_opc.
*/
bool cpu_unwind_state_data(CPUState *cpu, uintptr_t host_pc, uint64_t *data);
/**
* cpu_restore_state:
* @cpu: the cpu context
* @host_pc: the host pc within the translation
* @return: true if state was restored, false otherwise
*
* Attempt to restore the state for a fault occurring in translated
* code. If @host_pc is not in translated code no state is
* restored and the function returns false.
*/
bool cpu_restore_state(CPUState *cpu, uintptr_t host_pc);
G_NORETURN void cpu_loop_exit_noexc(CPUState *cpu);
G_NORETURN void cpu_loop_exit_atomic(CPUState *cpu, uintptr_t pc);
#endif /* CONFIG_TCG */
G_NORETURN void cpu_loop_exit(CPUState *cpu);
G_NORETURN void cpu_loop_exit_restore(CPUState *cpu, uintptr_t pc);
/* accel/tcg/cpu-exec.c */
int cpu_exec(CPUState *cpu);
/**
* env_archcpu(env)
* @env: The architecture environment
*
* Return the ArchCPU associated with the environment.
*/
static inline ArchCPU *env_archcpu(CPUArchState *env)
{
return (void *)env - sizeof(CPUState);
}
/**
* env_cpu_const(env)
* @env: The architecture environment
*
* Return the CPUState associated with the environment.
*/
static inline const CPUState *env_cpu_const(const CPUArchState *env)
{
return (void *)env - sizeof(CPUState);
}
/**
* env_cpu(env)
* @env: The architecture environment
*
* Return the CPUState associated with the environment.
*/
static inline CPUState *env_cpu(CPUArchState *env)
{
return (CPUState *)env_cpu_const(env);
}
#ifndef CONFIG_USER_ONLY
/**
* cpu_mmu_index:
* @env: The cpu environment
* @ifetch: True for code access, false for data access.
*
* Return the core mmu index for the current translation regime.
* This function is used by generic TCG code paths.
*
* The user-only version of this function is inline in cpu-all.h,
* where it always returns MMU_USER_IDX.
*/
static inline int cpu_mmu_index(CPUState *cs, bool ifetch)
{
int ret = cs->cc->mmu_index(cs, ifetch);
tcg_debug_assert(ret >= 0 && ret < NB_MMU_MODES);
return ret;
}
#endif /* !CONFIG_USER_ONLY */
#endif /* CPU_COMMON_H */
+4 -192
View File
@@ -19,7 +19,7 @@
#ifndef CPU_DEFS_H
#define CPU_DEFS_H
#ifndef NEED_CPU_H
#ifndef COMPILING_PER_TARGET
#error cpu.h included from common code
#endif
@@ -36,9 +36,6 @@
#ifndef TARGET_LONG_BITS
# error TARGET_LONG_BITS must be defined in cpu-param.h
#endif
#ifndef NB_MMU_MODES
# error NB_MMU_MODES must be defined in cpu-param.h
#endif
#ifndef TARGET_PHYS_ADDR_SPACE_BITS
# error TARGET_PHYS_ADDR_SPACE_BITS must be defined in cpu-param.h
#endif
@@ -54,40 +51,10 @@
# error TARGET_PAGE_BITS must be defined in cpu-param.h
# endif
#endif
#ifndef TARGET_TB_PCREL
# define TARGET_TB_PCREL 0
#endif
#define TARGET_LONG_SIZE (TARGET_LONG_BITS / 8)
/* target_ulong is the type of a virtual address */
#if TARGET_LONG_SIZE == 4
typedef int32_t target_long;
typedef uint32_t target_ulong;
#define TARGET_FMT_lx "%08x"
#define TARGET_FMT_ld "%d"
#define TARGET_FMT_lu "%u"
#elif TARGET_LONG_SIZE == 8
typedef int64_t target_long;
typedef uint64_t target_ulong;
#define TARGET_FMT_lx "%016" PRIx64
#define TARGET_FMT_ld "%" PRId64
#define TARGET_FMT_lu "%" PRIu64
#else
#error TARGET_LONG_SIZE undefined
#endif
#if !defined(CONFIG_USER_ONLY) && defined(CONFIG_TCG)
/* use a fully associative victim tlb of 8 entries */
#define CPU_VTLB_SIZE 8
#if HOST_LONG_BITS == 32 && TARGET_LONG_BITS == 32
#define CPU_TLB_ENTRY_BITS 4
#else
#define CPU_TLB_ENTRY_BITS 5
#endif
#include "exec/target_long.h"
#if defined(CONFIG_SOFTMMU) && defined(CONFIG_TCG)
#define CPU_TLB_DYN_MIN_BITS 6
#define CPU_TLB_DYN_DEFAULT_BITS 8
@@ -111,161 +78,6 @@ typedef uint64_t target_ulong;
# endif
# endif
/* Minimalized TLB entry for use by TCG fast path. */
typedef struct CPUTLBEntry {
/* bit TARGET_LONG_BITS to TARGET_PAGE_BITS : virtual address
bit TARGET_PAGE_BITS-1..4 : Nonzero for accesses that should not
go directly to ram.
bit 3 : indicates that the entry is invalid
bit 2..0 : zero
*/
union {
struct {
target_ulong addr_read;
target_ulong addr_write;
target_ulong addr_code;
/* Addend to virtual address to get host address. IO accesses
use the corresponding iotlb value. */
uintptr_t addend;
};
/* padding to get a power of two size */
uint8_t dummy[1 << CPU_TLB_ENTRY_BITS];
};
} CPUTLBEntry;
QEMU_BUILD_BUG_ON(sizeof(CPUTLBEntry) != (1 << CPU_TLB_ENTRY_BITS));
/*
* The full TLB entry, which is not accessed by generated TCG code,
* so the layout is not as critical as that of CPUTLBEntry. This is
* also why we don't want to combine the two structs.
*/
typedef struct CPUTLBEntryFull {
/*
* @xlat_section contains:
* - in the lower TARGET_PAGE_BITS, a physical section number
* - with the lower TARGET_PAGE_BITS masked off, an offset which
* must be added to the virtual address to obtain:
* + the ram_addr_t of the target RAM (if the physical section
* number is PHYS_SECTION_NOTDIRTY or PHYS_SECTION_ROM)
* + the offset within the target MemoryRegion (otherwise)
*/
hwaddr xlat_section;
/*
* @phys_addr contains the physical address in the address space
* given by cpu_asidx_from_attrs(cpu, @attrs).
*/
hwaddr phys_addr;
/* @attrs contains the memory transaction attributes for the page. */
MemTxAttrs attrs;
/* @prot contains the complete protections for the page. */
uint8_t prot;
/* @lg_page_size contains the log2 of the page size. */
uint8_t lg_page_size;
/*
* Allow target-specific additions to this structure.
* This may be used to cache items from the guest cpu
* page tables for later use by the implementation.
*/
#ifdef TARGET_PAGE_ENTRY_EXTRA
TARGET_PAGE_ENTRY_EXTRA
#endif
} CPUTLBEntryFull;
/*
* Data elements that are per MMU mode, minus the bits accessed by
* the TCG fast path.
*/
typedef struct CPUTLBDesc {
/*
* Describe a region covering all of the large pages allocated
* into the tlb. When any page within this region is flushed,
* we must flush the entire tlb. The region is matched if
* (addr & large_page_mask) == large_page_addr.
*/
target_ulong large_page_addr;
target_ulong large_page_mask;
/* host time (in ns) at the beginning of the time window */
int64_t window_begin_ns;
/* maximum number of entries observed in the window */
size_t window_max_entries;
size_t n_used_entries;
/* The next index to use in the tlb victim table. */
size_t vindex;
/* The tlb victim table, in two parts. */
CPUTLBEntry vtable[CPU_VTLB_SIZE];
CPUTLBEntryFull vfulltlb[CPU_VTLB_SIZE];
CPUTLBEntryFull *fulltlb;
} CPUTLBDesc;
/*
* Data elements that are per MMU mode, accessed by the fast path.
* The structure is aligned to aid loading the pair with one insn.
*/
typedef struct CPUTLBDescFast {
/* Contains (n_entries - 1) << CPU_TLB_ENTRY_BITS */
uintptr_t mask;
/* The array of tlb entries itself. */
CPUTLBEntry *table;
} CPUTLBDescFast QEMU_ALIGNED(2 * sizeof(void *));
/*
* Data elements that are shared between all MMU modes.
*/
typedef struct CPUTLBCommon {
/* Serialize updates to f.table and d.vtable, and others as noted. */
QemuSpin lock;
/*
* Within dirty, for each bit N, modifications have been made to
* mmu_idx N since the last time that mmu_idx was flushed.
* Protected by tlb_c.lock.
*/
uint16_t dirty;
/*
* Statistics. These are not lock protected, but are read and
* written atomically. This allows the monitor to print a snapshot
* of the stats without interfering with the cpu.
*/
size_t full_flush_count;
size_t part_flush_count;
size_t elide_flush_count;
} CPUTLBCommon;
/*
* The entire softmmu tlb, for all MMU modes.
* The meaning of each of the MMU modes is defined in the target code.
* Since this is placed within CPUNegativeOffsetState, the smallest
* negative offsets are at the end of the struct.
*/
typedef struct CPUTLB {
CPUTLBCommon c;
CPUTLBDesc d[NB_MMU_MODES];
CPUTLBDescFast f[NB_MMU_MODES];
} CPUTLB;
/* This will be used by TCG backends to compute offsets. */
#define TLB_MASK_TABLE_OFS(IDX) \
((int)offsetof(ArchCPU, neg.tlb.f[IDX]) - (int)offsetof(ArchCPU, env))
#else
typedef struct CPUTLB { } CPUTLB;
#endif /* !CONFIG_USER_ONLY && CONFIG_TCG */
/*
* This structure must be placed in ArchCPU immediately
* before CPUArchState, as a field named "neg".
*/
typedef struct CPUNegativeOffsetState {
CPUTLB tlb;
IcountDecr icount_decr;
} CPUNegativeOffsetState;
#endif /* CONFIG_SOFTMMU && CONFIG_TCG */
#endif
+78 -139
View File
@@ -1,5 +1,5 @@
/*
* Software MMU support
* Software MMU support (per-target)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -62,21 +62,18 @@
#ifndef CPU_LDST_H
#define CPU_LDST_H
#ifndef CONFIG_TCG
#error Can only include this header with TCG
#endif
#include "exec/memopidx.h"
#include "exec/abi_ptr.h"
#include "exec/mmu-access-type.h"
#include "qemu/int128.h"
#include "cpu.h"
#if defined(CONFIG_USER_ONLY)
/* sparc32plus has 64bit long but 32bit space address
* this can make bad result with g2h() and h2g()
*/
#if TARGET_VIRT_ADDR_SPACE_BITS <= 32
typedef uint32_t abi_ptr;
#define TARGET_ABI_FMT_ptr "%x"
#else
typedef uint64_t abi_ptr;
#define TARGET_ABI_FMT_ptr "%"PRIx64
#endif
#include "user/guest-base.h"
#ifndef TARGET_TAGGED_ADDRESSES
static inline abi_ptr cpu_untagged_addr(CPUState *cs, abi_ptr x)
@@ -120,10 +117,8 @@ static inline bool guest_range_valid_untagged(abi_ulong start, abi_ulong len)
assert(h2g_valid(x)); \
h2g_nocheck(x); \
})
#else
typedef target_ulong abi_ptr;
#define TARGET_ABI_FMT_ptr TARGET_FMT_lx
#endif
#endif /* CONFIG_USER_ONLY */
uint32_t cpu_ldub_data(CPUArchState *env, abi_ptr ptr);
int cpu_ldsb_data(CPUArchState *env, abi_ptr ptr);
@@ -207,59 +202,47 @@ void cpu_stq_le_mmuidx_ra(CPUArchState *env, abi_ptr ptr, uint64_t val,
int mmu_idx, uintptr_t ra);
uint8_t cpu_ldb_mmu(CPUArchState *env, abi_ptr ptr, MemOpIdx oi, uintptr_t ra);
uint16_t cpu_ldw_be_mmu(CPUArchState *env, abi_ptr ptr,
MemOpIdx oi, uintptr_t ra);
uint32_t cpu_ldl_be_mmu(CPUArchState *env, abi_ptr ptr,
MemOpIdx oi, uintptr_t ra);
uint64_t cpu_ldq_be_mmu(CPUArchState *env, abi_ptr ptr,
MemOpIdx oi, uintptr_t ra);
uint16_t cpu_ldw_le_mmu(CPUArchState *env, abi_ptr ptr,
MemOpIdx oi, uintptr_t ra);
uint32_t cpu_ldl_le_mmu(CPUArchState *env, abi_ptr ptr,
MemOpIdx oi, uintptr_t ra);
uint64_t cpu_ldq_le_mmu(CPUArchState *env, abi_ptr ptr,
MemOpIdx oi, uintptr_t ra);
uint16_t cpu_ldw_mmu(CPUArchState *env, abi_ptr ptr, MemOpIdx oi, uintptr_t ra);
uint32_t cpu_ldl_mmu(CPUArchState *env, abi_ptr ptr, MemOpIdx oi, uintptr_t ra);
uint64_t cpu_ldq_mmu(CPUArchState *env, abi_ptr ptr, MemOpIdx oi, uintptr_t ra);
Int128 cpu_ld16_mmu(CPUArchState *env, abi_ptr addr, MemOpIdx oi, uintptr_t ra);
void cpu_stb_mmu(CPUArchState *env, abi_ptr ptr, uint8_t val,
MemOpIdx oi, uintptr_t ra);
void cpu_stw_be_mmu(CPUArchState *env, abi_ptr ptr, uint16_t val,
MemOpIdx oi, uintptr_t ra);
void cpu_stl_be_mmu(CPUArchState *env, abi_ptr ptr, uint32_t val,
MemOpIdx oi, uintptr_t ra);
void cpu_stq_be_mmu(CPUArchState *env, abi_ptr ptr, uint64_t val,
MemOpIdx oi, uintptr_t ra);
void cpu_stw_le_mmu(CPUArchState *env, abi_ptr ptr, uint16_t val,
MemOpIdx oi, uintptr_t ra);
void cpu_stl_le_mmu(CPUArchState *env, abi_ptr ptr, uint32_t val,
MemOpIdx oi, uintptr_t ra);
void cpu_stq_le_mmu(CPUArchState *env, abi_ptr ptr, uint64_t val,
MemOpIdx oi, uintptr_t ra);
void cpu_stw_mmu(CPUArchState *env, abi_ptr ptr, uint16_t val,
MemOpIdx oi, uintptr_t ra);
void cpu_stl_mmu(CPUArchState *env, abi_ptr ptr, uint32_t val,
MemOpIdx oi, uintptr_t ra);
void cpu_stq_mmu(CPUArchState *env, abi_ptr ptr, uint64_t val,
MemOpIdx oi, uintptr_t ra);
void cpu_st16_mmu(CPUArchState *env, abi_ptr addr, Int128 val,
MemOpIdx oi, uintptr_t ra);
uint32_t cpu_atomic_cmpxchgb_mmu(CPUArchState *env, target_ulong addr,
uint32_t cpu_atomic_cmpxchgb_mmu(CPUArchState *env, abi_ptr addr,
uint32_t cmpv, uint32_t newv,
MemOpIdx oi, uintptr_t retaddr);
uint32_t cpu_atomic_cmpxchgw_le_mmu(CPUArchState *env, target_ulong addr,
uint32_t cpu_atomic_cmpxchgw_le_mmu(CPUArchState *env, abi_ptr addr,
uint32_t cmpv, uint32_t newv,
MemOpIdx oi, uintptr_t retaddr);
uint32_t cpu_atomic_cmpxchgl_le_mmu(CPUArchState *env, target_ulong addr,
uint32_t cpu_atomic_cmpxchgl_le_mmu(CPUArchState *env, abi_ptr addr,
uint32_t cmpv, uint32_t newv,
MemOpIdx oi, uintptr_t retaddr);
uint64_t cpu_atomic_cmpxchgq_le_mmu(CPUArchState *env, target_ulong addr,
uint64_t cpu_atomic_cmpxchgq_le_mmu(CPUArchState *env, abi_ptr addr,
uint64_t cmpv, uint64_t newv,
MemOpIdx oi, uintptr_t retaddr);
uint32_t cpu_atomic_cmpxchgw_be_mmu(CPUArchState *env, target_ulong addr,
uint32_t cpu_atomic_cmpxchgw_be_mmu(CPUArchState *env, abi_ptr addr,
uint32_t cmpv, uint32_t newv,
MemOpIdx oi, uintptr_t retaddr);
uint32_t cpu_atomic_cmpxchgl_be_mmu(CPUArchState *env, target_ulong addr,
uint32_t cpu_atomic_cmpxchgl_be_mmu(CPUArchState *env, abi_ptr addr,
uint32_t cmpv, uint32_t newv,
MemOpIdx oi, uintptr_t retaddr);
uint64_t cpu_atomic_cmpxchgq_be_mmu(CPUArchState *env, target_ulong addr,
uint64_t cpu_atomic_cmpxchgq_be_mmu(CPUArchState *env, abi_ptr addr,
uint64_t cmpv, uint64_t newv,
MemOpIdx oi, uintptr_t retaddr);
#define GEN_ATOMIC_HELPER(NAME, TYPE, SUFFIX) \
TYPE cpu_atomic_ ## NAME ## SUFFIX ## _mmu \
(CPUArchState *env, target_ulong addr, TYPE val, \
#define GEN_ATOMIC_HELPER(NAME, TYPE, SUFFIX) \
TYPE cpu_atomic_ ## NAME ## SUFFIX ## _mmu \
(CPUArchState *env, abi_ptr addr, TYPE val, \
MemOpIdx oi, uintptr_t retaddr);
#ifdef CONFIG_ATOMIC64
@@ -305,78 +288,13 @@ GEN_ATOMIC_HELPER_ALL(xchg)
#undef GEN_ATOMIC_HELPER_ALL
#undef GEN_ATOMIC_HELPER
Int128 cpu_atomic_cmpxchgo_le_mmu(CPUArchState *env, target_ulong addr,
Int128 cpu_atomic_cmpxchgo_le_mmu(CPUArchState *env, abi_ptr addr,
Int128 cmpv, Int128 newv,
MemOpIdx oi, uintptr_t retaddr);
Int128 cpu_atomic_cmpxchgo_be_mmu(CPUArchState *env, target_ulong addr,
Int128 cpu_atomic_cmpxchgo_be_mmu(CPUArchState *env, abi_ptr addr,
Int128 cmpv, Int128 newv,
MemOpIdx oi, uintptr_t retaddr);
Int128 cpu_atomic_ldo_le_mmu(CPUArchState *env, target_ulong addr,
MemOpIdx oi, uintptr_t retaddr);
Int128 cpu_atomic_ldo_be_mmu(CPUArchState *env, target_ulong addr,
MemOpIdx oi, uintptr_t retaddr);
void cpu_atomic_sto_le_mmu(CPUArchState *env, target_ulong addr, Int128 val,
MemOpIdx oi, uintptr_t retaddr);
void cpu_atomic_sto_be_mmu(CPUArchState *env, target_ulong addr, Int128 val,
MemOpIdx oi, uintptr_t retaddr);
#if defined(CONFIG_USER_ONLY)
extern __thread uintptr_t helper_retaddr;
static inline void set_helper_retaddr(uintptr_t ra)
{
helper_retaddr = ra;
/*
* Ensure that this write is visible to the SIGSEGV handler that
* may be invoked due to a subsequent invalid memory operation.
*/
signal_barrier();
}
static inline void clear_helper_retaddr(void)
{
/*
* Ensure that previous memory operations have succeeded before
* removing the data visible to the signal handler.
*/
signal_barrier();
helper_retaddr = 0;
}
#else
/* Needed for TCG_OVERSIZED_GUEST */
#include "tcg/tcg.h"
static inline target_ulong tlb_addr_write(const CPUTLBEntry *entry)
{
#if TCG_OVERSIZED_GUEST
return entry->addr_write;
#else
return qatomic_read(&entry->addr_write);
#endif
}
/* Find the TLB index corresponding to the mmu_idx + address pair. */
static inline uintptr_t tlb_index(CPUArchState *env, uintptr_t mmu_idx,
target_ulong addr)
{
uintptr_t size_mask = env_tlb(env)->f[mmu_idx].mask >> CPU_TLB_ENTRY_BITS;
return (addr >> TARGET_PAGE_BITS) & size_mask;
}
/* Find the TLB entry corresponding to the mmu_idx + address pair. */
static inline CPUTLBEntry *tlb_entry(CPUArchState *env, uintptr_t mmu_idx,
target_ulong addr)
{
return &env_tlb(env)->f[mmu_idx].table[tlb_index(env, mmu_idx, addr)];
}
#endif /* defined(CONFIG_USER_ONLY) */
#if TARGET_BIG_ENDIAN
# define cpu_lduw_data cpu_lduw_be_data
# define cpu_ldsw_data cpu_ldsw_be_data
@@ -390,9 +308,6 @@ static inline CPUTLBEntry *tlb_entry(CPUArchState *env, uintptr_t mmu_idx,
# define cpu_ldsw_mmuidx_ra cpu_ldsw_be_mmuidx_ra
# define cpu_ldl_mmuidx_ra cpu_ldl_be_mmuidx_ra
# define cpu_ldq_mmuidx_ra cpu_ldq_be_mmuidx_ra
# define cpu_ldw_mmu cpu_ldw_be_mmu
# define cpu_ldl_mmu cpu_ldl_be_mmu
# define cpu_ldq_mmu cpu_ldq_be_mmu
# define cpu_stw_data cpu_stw_be_data
# define cpu_stl_data cpu_stl_be_data
# define cpu_stq_data cpu_stq_be_data
@@ -402,9 +317,6 @@ static inline CPUTLBEntry *tlb_entry(CPUArchState *env, uintptr_t mmu_idx,
# define cpu_stw_mmuidx_ra cpu_stw_be_mmuidx_ra
# define cpu_stl_mmuidx_ra cpu_stl_be_mmuidx_ra
# define cpu_stq_mmuidx_ra cpu_stq_be_mmuidx_ra
# define cpu_stw_mmu cpu_stw_be_mmu
# define cpu_stl_mmu cpu_stl_be_mmu
# define cpu_stq_mmu cpu_stq_be_mmu
#else
# define cpu_lduw_data cpu_lduw_le_data
# define cpu_ldsw_data cpu_ldsw_le_data
@@ -418,9 +330,6 @@ static inline CPUTLBEntry *tlb_entry(CPUArchState *env, uintptr_t mmu_idx,
# define cpu_ldsw_mmuidx_ra cpu_ldsw_le_mmuidx_ra
# define cpu_ldl_mmuidx_ra cpu_ldl_le_mmuidx_ra
# define cpu_ldq_mmuidx_ra cpu_ldq_le_mmuidx_ra
# define cpu_ldw_mmu cpu_ldw_le_mmu
# define cpu_ldl_mmu cpu_ldl_le_mmu
# define cpu_ldq_mmu cpu_ldq_le_mmu
# define cpu_stw_data cpu_stw_le_data
# define cpu_stl_data cpu_stl_le_data
# define cpu_stq_data cpu_stq_le_data
@@ -430,27 +339,23 @@ static inline CPUTLBEntry *tlb_entry(CPUArchState *env, uintptr_t mmu_idx,
# define cpu_stw_mmuidx_ra cpu_stw_le_mmuidx_ra
# define cpu_stl_mmuidx_ra cpu_stl_le_mmuidx_ra
# define cpu_stq_mmuidx_ra cpu_stq_le_mmuidx_ra
# define cpu_stw_mmu cpu_stw_le_mmu
# define cpu_stl_mmu cpu_stl_le_mmu
# define cpu_stq_mmu cpu_stq_le_mmu
#endif
uint8_t cpu_ldb_code_mmu(CPUArchState *env, abi_ptr addr,
MemOpIdx oi, uintptr_t ra);
uint16_t cpu_ldw_code_mmu(CPUArchState *env, abi_ptr addr,
MemOpIdx oi, uintptr_t ra);
uint32_t cpu_ldl_code_mmu(CPUArchState *env, abi_ptr addr,
MemOpIdx oi, uintptr_t ra);
uint64_t cpu_ldq_code_mmu(CPUArchState *env, abi_ptr addr,
MemOpIdx oi, uintptr_t ra);
uint32_t cpu_ldub_code(CPUArchState *env, abi_ptr addr);
uint32_t cpu_lduw_code(CPUArchState *env, abi_ptr addr);
uint32_t cpu_ldl_code(CPUArchState *env, abi_ptr addr);
uint64_t cpu_ldq_code(CPUArchState *env, abi_ptr addr);
void cpu_ld_code(CPUArchState *env, abi_ptr addr, size_t len, uint8_t *out);
static inline int cpu_ldsb_code(CPUArchState *env, abi_ptr addr)
{
return (int8_t)cpu_ldub_code(env, addr);
}
static inline int cpu_ldsw_code(CPUArchState *env, abi_ptr addr)
{
return (int16_t)cpu_lduw_code(env, addr);
}
/**
* tlb_vaddr_to_host:
* @env: CPUArchState
@@ -475,4 +380,38 @@ void *tlb_vaddr_to_host(CPUArchState *env, abi_ptr addr,
MMUAccessType access_type, int mmu_idx);
#endif
/*
* For user-only, helpers that use guest to host address translation
* must protect the actual host memory access by recording 'retaddr'
* for the signal handler. This is required for a race condition in
* which another thread unmaps the page between a probe and the
* actual access.
*/
#ifdef CONFIG_USER_ONLY
extern __thread uintptr_t helper_retaddr;
static inline void set_helper_retaddr(uintptr_t ra)
{
helper_retaddr = ra;
/*
* Ensure that this write is visible to the SIGSEGV handler that
* may be invoked due to a subsequent invalid memory operation.
*/
signal_barrier();
}
static inline void clear_helper_retaddr(void)
{
/*
* Ensure that previous memory operations have succeeded before
* removing the data visible to the signal handler.
*/
signal_barrier();
helper_retaddr = 0;
}
#else
#define set_helper_retaddr(ra) do { } while (0)
#define clear_helper_retaddr() do { } while (0)
#endif
#endif /* CPU_LDST_H */
+5 -1
View File
@@ -22,10 +22,14 @@
#include "exec/cpu-common.h"
#ifdef CONFIG_TCG
#if !defined(CONFIG_USER_ONLY)
/* cputlb.c */
void tlb_protect_code(ram_addr_t ram_addr);
void tlb_unprotect_code(ram_addr_t ram_addr);
void tlb_flush_counts(size_t *full, size_t *part, size_t *elide);
#endif
#endif /* CONFIG_TCG */
#endif
+127 -319
View File
File diff suppressed because it is too large Load Diff
+115 -223
View File
@@ -1,220 +1,50 @@
#ifndef GDBSTUB_H
#define GDBSTUB_H
#define DEFAULT_GDBSTUB_PORT "1234"
typedef struct GDBFeature {
const char *xmlname;
const char *xml;
const char *name;
const char * const *regs;
int num_regs;
} GDBFeature;
/* GDB breakpoint/watchpoint types */
#define GDB_BREAKPOINT_SW 0
#define GDB_BREAKPOINT_HW 1
#define GDB_WATCHPOINT_WRITE 2
#define GDB_WATCHPOINT_READ 3
#define GDB_WATCHPOINT_ACCESS 4
typedef struct GDBFeatureBuilder {
GDBFeature *feature;
GPtrArray *xml;
GPtrArray *regs;
int base_reg;
} GDBFeatureBuilder;
/* For gdb file i/o remote protocol open flags. */
#define GDB_O_RDONLY 0
#define GDB_O_WRONLY 1
#define GDB_O_RDWR 2
#define GDB_O_APPEND 8
#define GDB_O_CREAT 0x200
#define GDB_O_TRUNC 0x400
#define GDB_O_EXCL 0x800
/* For gdb file i/o remote protocol errno values */
#define GDB_EPERM 1
#define GDB_ENOENT 2
#define GDB_EINTR 4
#define GDB_EBADF 9
#define GDB_EACCES 13
#define GDB_EFAULT 14
#define GDB_EBUSY 16
#define GDB_EEXIST 17
#define GDB_ENODEV 19
#define GDB_ENOTDIR 20
#define GDB_EISDIR 21
#define GDB_EINVAL 22
#define GDB_ENFILE 23
#define GDB_EMFILE 24
#define GDB_EFBIG 27
#define GDB_ENOSPC 28
#define GDB_ESPIPE 29
#define GDB_EROFS 30
#define GDB_ENAMETOOLONG 91
#define GDB_EUNKNOWN 9999
/* For gdb file i/o remote protocol lseek whence. */
#define GDB_SEEK_SET 0
#define GDB_SEEK_CUR 1
#define GDB_SEEK_END 2
/* For gdb file i/o stat/fstat. */
typedef uint32_t gdb_mode_t;
typedef uint32_t gdb_time_t;
struct gdb_stat {
uint32_t gdb_st_dev; /* device */
uint32_t gdb_st_ino; /* inode */
gdb_mode_t gdb_st_mode; /* protection */
uint32_t gdb_st_nlink; /* number of hard links */
uint32_t gdb_st_uid; /* user ID of owner */
uint32_t gdb_st_gid; /* group ID of owner */
uint32_t gdb_st_rdev; /* device type (if inode device) */
uint64_t gdb_st_size; /* total size, in bytes */
uint64_t gdb_st_blksize; /* blocksize for filesystem I/O */
uint64_t gdb_st_blocks; /* number of blocks allocated */
gdb_time_t gdb_st_atime; /* time of last access */
gdb_time_t gdb_st_mtime; /* time of last modification */
gdb_time_t gdb_st_ctime; /* time of last change */
} QEMU_PACKED;
struct gdb_timeval {
gdb_time_t tv_sec; /* second */
uint64_t tv_usec; /* microsecond */
} QEMU_PACKED;
#ifdef NEED_CPU_H
#include "cpu.h"
typedef void (*gdb_syscall_complete_cb)(CPUState *cpu, uint64_t ret, int err);
/**
* gdb_do_syscall:
* @cb: function to call when the system call has completed
* @fmt: gdb syscall format string
* ...: list of arguments to interpolate into @fmt
*
* Send a GDB syscall request. This function will return immediately;
* the callback function will be called later when the remote system
* call has completed.
*
* @fmt should be in the 'call-id,parameter,parameter...' format documented
* for the F request packet in the GDB remote protocol. A limited set of
* printf-style format specifiers is supported:
* %x - target_ulong argument printed in hex
* %lx - 64-bit argument printed in hex
* %s - string pointer (target_ulong) and length (int) pair
*/
void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...);
/**
* gdb_do_syscallv:
* @cb: function to call when the system call has completed
* @fmt: gdb syscall format string
* @va: arguments to interpolate into @fmt
*
* As gdb_do_syscall, but taking a va_list rather than a variable
* argument list.
*/
void gdb_do_syscallv(gdb_syscall_complete_cb cb, const char *fmt, va_list va);
int use_gdb_syscalls(void);
#ifdef CONFIG_USER_ONLY
/**
* gdb_handlesig: yield control to gdb
* @cpu: CPU
* @sig: if non-zero, the signal number which caused us to stop
*
* This function yields control to gdb, when a user-mode-only target
* needs to stop execution. If @sig is non-zero, then we will send a
* stop packet to tell gdb that we have stopped because of this signal.
*
* This function will block (handling protocol requests from gdb)
* until gdb tells us to continue target execution. When it does
* return, the return value is a signal to deliver to the target,
* or 0 if no signal should be delivered, ie the signal that caused
* us to stop should be ignored.
*/
int gdb_handlesig(CPUState *, int);
void gdb_signalled(CPUArchState *, int);
void gdbserver_fork(CPUState *);
#endif
/* Get or set a register. Returns the size of the register. */
typedef int (*gdb_get_reg_cb)(CPUArchState *env, GByteArray *buf, int reg);
typedef int (*gdb_set_reg_cb)(CPUArchState *env, uint8_t *buf, int reg);
typedef int (*gdb_get_reg_cb)(CPUState *cpu, GByteArray *buf, int reg);
typedef int (*gdb_set_reg_cb)(CPUState *cpu, uint8_t *buf, int reg);
/**
* gdb_init_cpu(): Initialize the CPU for gdbstub.
* @cpu: The CPU to be initialized.
*/
void gdb_init_cpu(CPUState *cpu);
/**
* gdb_register_coprocessor() - register a supplemental set of registers
* @cpu - the CPU associated with registers
* @get_reg - get function (gdb reading)
* @set_reg - set function (gdb modifying)
* @num_regs - number of registers in set
* @xml - xml name of set
* @gpos - non-zero to append to "general" register set at @gpos
*/
void gdb_register_coprocessor(CPUState *cpu,
gdb_get_reg_cb get_reg, gdb_set_reg_cb set_reg,
int num_regs, const char *xml, int g_pos);
/*
* The GDB remote protocol transfers values in target byte order. As
* the gdbstub may be batching up several register values we always
* append to the array.
*/
static inline int gdb_get_reg8(GByteArray *buf, uint8_t val)
{
g_byte_array_append(buf, &val, 1);
return 1;
}
static inline int gdb_get_reg16(GByteArray *buf, uint16_t val)
{
uint16_t to_word = tswap16(val);
g_byte_array_append(buf, (uint8_t *) &to_word, 2);
return 2;
}
static inline int gdb_get_reg32(GByteArray *buf, uint32_t val)
{
uint32_t to_long = tswap32(val);
g_byte_array_append(buf, (uint8_t *) &to_long, 4);
return 4;
}
static inline int gdb_get_reg64(GByteArray *buf, uint64_t val)
{
uint64_t to_quad = tswap64(val);
g_byte_array_append(buf, (uint8_t *) &to_quad, 8);
return 8;
}
static inline int gdb_get_reg128(GByteArray *buf, uint64_t val_hi,
uint64_t val_lo)
{
uint64_t to_quad;
#if TARGET_BIG_ENDIAN
to_quad = tswap64(val_hi);
g_byte_array_append(buf, (uint8_t *) &to_quad, 8);
to_quad = tswap64(val_lo);
g_byte_array_append(buf, (uint8_t *) &to_quad, 8);
#else
to_quad = tswap64(val_lo);
g_byte_array_append(buf, (uint8_t *) &to_quad, 8);
to_quad = tswap64(val_hi);
g_byte_array_append(buf, (uint8_t *) &to_quad, 8);
#endif
return 16;
}
static inline int gdb_get_zeroes(GByteArray *array, size_t len)
{
guint oldlen = array->len;
g_byte_array_set_size(array, oldlen + len);
memset(array->data + oldlen, 0, len);
return len;
}
const GDBFeature *feature, int g_pos);
/**
* gdb_get_reg_ptr: get pointer to start of last element
* @len: length of element
*
* This is a helper function to extract the pointer to the last
* element for additional processing. Some front-ends do additional
* dynamic swapping of the elements based on CPU state.
* gdb_unregister_coprocessor_all() - unregisters supplemental set of registers
* @cpu - the CPU associated with registers
*/
static inline uint8_t * gdb_get_reg_ptr(GByteArray *buf, int len)
{
return buf->data + buf->len - len;
}
#if TARGET_LONG_BITS == 64
#define gdb_get_regl(buf, val) gdb_get_reg64(buf, val)
#define ldtul_p(addr) ldq_p(addr)
#else
#define gdb_get_regl(buf, val) gdb_get_reg32(buf, val)
#define ldtul_p(addr) ldl_p(addr)
#endif
#endif /* NEED_CPU_H */
void gdb_unregister_coprocessor_all(CPUState *cpu);
/**
* gdbserver_start: start the gdb server
@@ -227,26 +57,88 @@ static inline uint8_t * gdb_get_reg_ptr(GByteArray *buf, int len)
int gdbserver_start(const char *port_or_device);
/**
* gdb_exit: exit gdb session, reporting inferior status
* @code: exit code reported
*
* This closes the session and sends a final packet to GDB reporting
* the exit status of the program. It also cleans up any connections
* detritus before returning.
* gdb_feature_builder_init() - Initialize GDBFeatureBuilder.
* @builder: The builder to be initialized.
* @feature: The feature to be filled.
* @name: The name of the feature.
* @xmlname: The name of the XML.
* @base_reg: The base number of the register ID.
*/
void gdb_exit(int code);
void gdb_feature_builder_init(GDBFeatureBuilder *builder, GDBFeature *feature,
const char *name, const char *xmlname,
int base_reg);
/**
* gdb_feature_builder_append_tag() - Append a tag.
* @builder: The builder.
* @format: The format of the tag.
* @...: The values to be formatted.
*/
void G_GNUC_PRINTF(2, 3)
gdb_feature_builder_append_tag(const GDBFeatureBuilder *builder,
const char *format, ...);
/**
* gdb_feature_builder_append_reg() - Append a register.
* @builder: The builder.
* @name: The register's name; it must be unique within a CPU.
* @bitsize: The register's size, in bits.
* @regnum: The offset of the register's number in the feature.
* @type: The type of the register.
* @group: The register group to which this register belongs; it can be NULL.
*/
void gdb_feature_builder_append_reg(const GDBFeatureBuilder *builder,
const char *name,
int bitsize,
int regnum,
const char *type,
const char *group);
/**
* gdb_feature_builder_end() - End building GDBFeature.
* @builder: The builder.
*/
void gdb_feature_builder_end(const GDBFeatureBuilder *builder);
/**
* gdb_find_static_feature() - Find a static feature.
* @xmlname: The name of the XML.
*
* Return: The static feature.
*/
const GDBFeature *gdb_find_static_feature(const char *xmlname);
/**
* gdb_read_register() - Read a register associated with a CPU.
* @cpu: The CPU associated with the register.
* @buf: The buffer that the read register will be appended to.
* @reg: The register's number returned by gdb_find_feature_register().
*
* Return: The number of read bytes.
*/
int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
/**
* typedef GDBRegDesc - a register description from gdbstub
*/
typedef struct {
int gdb_reg;
const char *name;
const char *feature_name;
} GDBRegDesc;
/**
* gdb_get_register_list() - Return list of all registers for CPU
* @cpu: The CPU being searched
*
* Returns a GArray of GDBRegDesc, caller frees array but not the
* const strings.
*/
GArray *gdb_get_register_list(CPUState *cpu);
void gdb_set_stop_cpu(CPUState *cpu);
/**
* gdb_has_xml:
* This is an ugly hack to cope with both new and old gdb.
* If gdb sends qXfer:features:read then assume we're talking to a newish
* gdb that understands target descriptions.
*/
extern bool gdb_has_xml;
/* in gdbstub-xml.c, generated by scripts/feature_to_c.py */
extern const GDBFeature gdb_static_features[];
/* in gdbstub-xml.c, generated by scripts/feature_to_c.sh */
extern const char *const xml_builtin[][2];
#endif
#endif /* GDBSTUB_H */
-94
View File
@@ -1,94 +0,0 @@
#ifndef GEN_ICOUNT_H
#define GEN_ICOUNT_H
#include "exec/exec-all.h"
#include "qemu/timer.h"
/* Helpers for instruction counting code generation. */
static TCGOp *icount_start_insn;
static inline void gen_io_start(void)
{
TCGv_i32 tmp = tcg_const_i32(1);
tcg_gen_st_i32(tmp, cpu_env,
offsetof(ArchCPU, parent_obj.can_do_io) -
offsetof(ArchCPU, env));
tcg_temp_free_i32(tmp);
}
static inline void gen_tb_start(const TranslationBlock *tb)
{
TCGv_i32 count;
if (tb_cflags(tb) & CF_USE_ICOUNT) {
count = tcg_temp_local_new_i32();
} else {
count = tcg_temp_new_i32();
}
tcg_gen_ld_i32(count, cpu_env,
offsetof(ArchCPU, neg.icount_decr.u32) -
offsetof(ArchCPU, env));
if (tb_cflags(tb) & CF_USE_ICOUNT) {
/*
* We emit a sub with a dummy immediate argument. Keep the insn index
* of the sub so that we later (when we know the actual insn count)
* can update the argument with the actual insn count.
*/
tcg_gen_sub_i32(count, count, tcg_constant_i32(0));
icount_start_insn = tcg_last_op();
}
/*
* Emit the check against icount_decr.u32 to see if we should exit
* unless we suppress the check with CF_NOIRQ. If we are using
* icount and have suppressed interruption the higher level code
* should have ensured we don't run more instructions than the
* budget.
*/
if (tb_cflags(tb) & CF_NOIRQ) {
tcg_ctx->exitreq_label = NULL;
} else {
tcg_ctx->exitreq_label = gen_new_label();
tcg_gen_brcondi_i32(TCG_COND_LT, count, 0, tcg_ctx->exitreq_label);
}
if (tb_cflags(tb) & CF_USE_ICOUNT) {
tcg_gen_st16_i32(count, cpu_env,
offsetof(ArchCPU, neg.icount_decr.u16.low) -
offsetof(ArchCPU, env));
/*
* cpu->can_do_io is cleared automatically here at the beginning of
* each translation block. The cost is minimal and only paid for
* -icount, plus it would be very easy to forget doing it in the
* translator. Doing it here means we don't need a gen_io_end() to
* go with gen_io_start().
*/
tcg_gen_st_i32(tcg_constant_i32(0), cpu_env,
offsetof(ArchCPU, parent_obj.can_do_io) -
offsetof(ArchCPU, env));
}
tcg_temp_free_i32(count);
}
static inline void gen_tb_end(const TranslationBlock *tb, int num_insns)
{
if (tb_cflags(tb) & CF_USE_ICOUNT) {
/*
* Update the num_insn immediate parameter now that we know
* the actual insn count.
*/
tcg_set_insn_param(icount_start_insn, 2,
tcgv_i32_arg(tcg_constant_i32(num_insns)));
}
if (tcg_ctx->exitreq_label) {
gen_set_label(tcg_ctx->exitreq_label);
tcg_gen_exit_tb(tb, TB_EXIT_REQUESTED);
}
}
#endif
+14
View File
@@ -0,0 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Helper file for declaring TCG helper functions.
* This one expands generation functions for tcg opcodes.
*/
#ifndef HELPER_GEN_COMMON_H
#define HELPER_GEN_COMMON_H
#define HELPER_H "accel/tcg/tcg-runtime.h"
#include "exec/helper-gen.h.inc"
#undef HELPER_H
#endif /* HELPER_GEN_COMMON_H */
+9 -88
View File
@@ -1,95 +1,16 @@
/* Helper file for declaring TCG helper functions.
This one expands generation functions for tcg opcodes. */
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Helper file for declaring TCG helper functions.
* This one expands generation functions for tcg opcodes.
*/
#ifndef HELPER_GEN_H
#define HELPER_GEN_H
#include "exec/helper-head.h"
#include "exec/helper-gen-common.h"
#define DEF_HELPER_FLAGS_0(name, flags, ret) \
static inline void glue(gen_helper_, name)(dh_retvar_decl0(ret)) \
{ \
tcg_gen_callN(HELPER(name), dh_retvar(ret), 0, NULL); \
}
#define DEF_HELPER_FLAGS_1(name, flags, ret, t1) \
static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \
dh_arg_decl(t1, 1)) \
{ \
TCGTemp *args[1] = { dh_arg(t1, 1) }; \
tcg_gen_callN(HELPER(name), dh_retvar(ret), 1, args); \
}
#define DEF_HELPER_FLAGS_2(name, flags, ret, t1, t2) \
static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \
dh_arg_decl(t1, 1), dh_arg_decl(t2, 2)) \
{ \
TCGTemp *args[2] = { dh_arg(t1, 1), dh_arg(t2, 2) }; \
tcg_gen_callN(HELPER(name), dh_retvar(ret), 2, args); \
}
#define DEF_HELPER_FLAGS_3(name, flags, ret, t1, t2, t3) \
static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \
dh_arg_decl(t1, 1), dh_arg_decl(t2, 2), dh_arg_decl(t3, 3)) \
{ \
TCGTemp *args[3] = { dh_arg(t1, 1), dh_arg(t2, 2), dh_arg(t3, 3) }; \
tcg_gen_callN(HELPER(name), dh_retvar(ret), 3, args); \
}
#define DEF_HELPER_FLAGS_4(name, flags, ret, t1, t2, t3, t4) \
static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \
dh_arg_decl(t1, 1), dh_arg_decl(t2, 2), \
dh_arg_decl(t3, 3), dh_arg_decl(t4, 4)) \
{ \
TCGTemp *args[4] = { dh_arg(t1, 1), dh_arg(t2, 2), \
dh_arg(t3, 3), dh_arg(t4, 4) }; \
tcg_gen_callN(HELPER(name), dh_retvar(ret), 4, args); \
}
#define DEF_HELPER_FLAGS_5(name, flags, ret, t1, t2, t3, t4, t5) \
static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \
dh_arg_decl(t1, 1), dh_arg_decl(t2, 2), dh_arg_decl(t3, 3), \
dh_arg_decl(t4, 4), dh_arg_decl(t5, 5)) \
{ \
TCGTemp *args[5] = { dh_arg(t1, 1), dh_arg(t2, 2), dh_arg(t3, 3), \
dh_arg(t4, 4), dh_arg(t5, 5) }; \
tcg_gen_callN(HELPER(name), dh_retvar(ret), 5, args); \
}
#define DEF_HELPER_FLAGS_6(name, flags, ret, t1, t2, t3, t4, t5, t6) \
static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \
dh_arg_decl(t1, 1), dh_arg_decl(t2, 2), dh_arg_decl(t3, 3), \
dh_arg_decl(t4, 4), dh_arg_decl(t5, 5), dh_arg_decl(t6, 6)) \
{ \
TCGTemp *args[6] = { dh_arg(t1, 1), dh_arg(t2, 2), dh_arg(t3, 3), \
dh_arg(t4, 4), dh_arg(t5, 5), dh_arg(t6, 6) }; \
tcg_gen_callN(HELPER(name), dh_retvar(ret), 6, args); \
}
#define DEF_HELPER_FLAGS_7(name, flags, ret, t1, t2, t3, t4, t5, t6, t7)\
static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \
dh_arg_decl(t1, 1), dh_arg_decl(t2, 2), dh_arg_decl(t3, 3), \
dh_arg_decl(t4, 4), dh_arg_decl(t5, 5), dh_arg_decl(t6, 6), \
dh_arg_decl(t7, 7)) \
{ \
TCGTemp *args[7] = { dh_arg(t1, 1), dh_arg(t2, 2), dh_arg(t3, 3), \
dh_arg(t4, 4), dh_arg(t5, 5), dh_arg(t6, 6), \
dh_arg(t7, 7) }; \
tcg_gen_callN(HELPER(name), dh_retvar(ret), 7, args); \
}
#include "helper.h"
#include "accel/tcg/tcg-runtime.h"
#include "accel/tcg/plugin-helpers.h"
#undef DEF_HELPER_FLAGS_0
#undef DEF_HELPER_FLAGS_1
#undef DEF_HELPER_FLAGS_2
#undef DEF_HELPER_FLAGS_3
#undef DEF_HELPER_FLAGS_4
#undef DEF_HELPER_FLAGS_5
#undef DEF_HELPER_FLAGS_6
#undef DEF_HELPER_FLAGS_7
#undef GEN_HELPER
#define HELPER_H "helper.h"
#include "exec/helper-gen.h.inc"
#undef HELPER_H
#endif /* HELPER_GEN_H */
+110
View File
@@ -0,0 +1,110 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Helper file for declaring TCG helper functions.
* This one expands generation functions for tcg opcodes.
* Define HELPER_H for the header file to be expanded,
* and static inline to change from global file scope.
*/
#include "tcg/tcg.h"
#include "tcg/helper-info.h"
#include "exec/helper-head.h.inc"
#define DEF_HELPER_FLAGS_0(name, flags, ret) \
extern TCGHelperInfo glue(helper_info_, name); \
static inline void glue(gen_helper_, name)(dh_retvar_decl0(ret)) \
{ \
tcg_gen_call0(glue(helper_info_,name).func, \
&glue(helper_info_,name), dh_retvar(ret)); \
}
#define DEF_HELPER_FLAGS_1(name, flags, ret, t1) \
extern TCGHelperInfo glue(helper_info_, name); \
static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \
dh_arg_decl(t1, 1)) \
{ \
tcg_gen_call1(glue(helper_info_,name).func, \
&glue(helper_info_,name), dh_retvar(ret), \
dh_arg(t1, 1)); \
}
#define DEF_HELPER_FLAGS_2(name, flags, ret, t1, t2) \
extern TCGHelperInfo glue(helper_info_, name); \
static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \
dh_arg_decl(t1, 1), dh_arg_decl(t2, 2)) \
{ \
tcg_gen_call2(glue(helper_info_,name).func, \
&glue(helper_info_,name), dh_retvar(ret), \
dh_arg(t1, 1), dh_arg(t2, 2)); \
}
#define DEF_HELPER_FLAGS_3(name, flags, ret, t1, t2, t3) \
extern TCGHelperInfo glue(helper_info_, name); \
static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \
dh_arg_decl(t1, 1), dh_arg_decl(t2, 2), dh_arg_decl(t3, 3)) \
{ \
tcg_gen_call3(glue(helper_info_,name).func, \
&glue(helper_info_,name), dh_retvar(ret), \
dh_arg(t1, 1), dh_arg(t2, 2), dh_arg(t3, 3)); \
}
#define DEF_HELPER_FLAGS_4(name, flags, ret, t1, t2, t3, t4) \
extern TCGHelperInfo glue(helper_info_, name); \
static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \
dh_arg_decl(t1, 1), dh_arg_decl(t2, 2), \
dh_arg_decl(t3, 3), dh_arg_decl(t4, 4)) \
{ \
tcg_gen_call4(glue(helper_info_,name).func, \
&glue(helper_info_,name), dh_retvar(ret), \
dh_arg(t1, 1), dh_arg(t2, 2), \
dh_arg(t3, 3), dh_arg(t4, 4)); \
}
#define DEF_HELPER_FLAGS_5(name, flags, ret, t1, t2, t3, t4, t5) \
extern TCGHelperInfo glue(helper_info_, name); \
static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \
dh_arg_decl(t1, 1), dh_arg_decl(t2, 2), dh_arg_decl(t3, 3), \
dh_arg_decl(t4, 4), dh_arg_decl(t5, 5)) \
{ \
tcg_gen_call5(glue(helper_info_,name).func, \
&glue(helper_info_,name), dh_retvar(ret), \
dh_arg(t1, 1), dh_arg(t2, 2), dh_arg(t3, 3), \
dh_arg(t4, 4), dh_arg(t5, 5)); \
}
#define DEF_HELPER_FLAGS_6(name, flags, ret, t1, t2, t3, t4, t5, t6) \
extern TCGHelperInfo glue(helper_info_, name); \
static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \
dh_arg_decl(t1, 1), dh_arg_decl(t2, 2), dh_arg_decl(t3, 3), \
dh_arg_decl(t4, 4), dh_arg_decl(t5, 5), dh_arg_decl(t6, 6)) \
{ \
tcg_gen_call6(glue(helper_info_,name).func, \
&glue(helper_info_,name), dh_retvar(ret), \
dh_arg(t1, 1), dh_arg(t2, 2), dh_arg(t3, 3), \
dh_arg(t4, 4), dh_arg(t5, 5), dh_arg(t6, 6)); \
}
#define DEF_HELPER_FLAGS_7(name, flags, ret, t1, t2, t3, t4, t5, t6, t7)\
extern TCGHelperInfo glue(helper_info_, name); \
static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \
dh_arg_decl(t1, 1), dh_arg_decl(t2, 2), dh_arg_decl(t3, 3), \
dh_arg_decl(t4, 4), dh_arg_decl(t5, 5), dh_arg_decl(t6, 6), \
dh_arg_decl(t7, 7)) \
{ \
tcg_gen_call7(glue(helper_info_,name).func, \
&glue(helper_info_,name), dh_retvar(ret), \
dh_arg(t1, 1), dh_arg(t2, 2), dh_arg(t3, 3), \
dh_arg(t4, 4), dh_arg(t5, 5), dh_arg(t6, 6), \
dh_arg(t7, 7)); \
}
#include HELPER_H
#undef DEF_HELPER_FLAGS_0
#undef DEF_HELPER_FLAGS_1
#undef DEF_HELPER_FLAGS_2
#undef DEF_HELPER_FLAGS_3
#undef DEF_HELPER_FLAGS_4
#undef DEF_HELPER_FLAGS_5
#undef DEF_HELPER_FLAGS_6
#undef DEF_HELPER_FLAGS_7
@@ -1,23 +1,13 @@
/* Helper file for declaring TCG helper functions.
Used by other helper files.
Targets should use DEF_HELPER_N and DEF_HELPER_FLAGS_N to declare helper
functions. Names should be specified without the helper_ prefix, and
the return and argument types specified. 3 basic types are understood
(i32, i64 and ptr). Additional aliases are provided for convenience and
to match the types used by the C helper implementation.
The target helper.h should be included in all files that use/define
helper functions. THis will ensure that function prototypes are
consistent. In addition it should be included an extra two times for
helper.c, defining:
GEN_HELPER 1 to produce op generation functions (gen_helper_*)
GEN_HELPER 2 to do runtime registration helper functions.
/*
* Helper file for declaring TCG helper functions.
* Used by other helper files.
*/
#ifndef EXEC_HELPER_HEAD_H
#define EXEC_HELPER_HEAD_H
#include "fpu/softfloat-types.h"
#define HELPER(name) glue(helper_, name)
/* Some types that make sense in C, but not for TCG. */
@@ -26,11 +16,13 @@
#define dh_alias_int i32
#define dh_alias_i64 i64
#define dh_alias_s64 i64
#define dh_alias_i128 i128
#define dh_alias_f16 i32
#define dh_alias_f32 i32
#define dh_alias_f64 i64
#define dh_alias_ptr ptr
#define dh_alias_cptr ptr
#define dh_alias_env ptr
#define dh_alias_void void
#define dh_alias_noreturn noreturn
#define dh_alias(t) glue(dh_alias_, t)
@@ -40,16 +32,18 @@
#define dh_ctype_int int
#define dh_ctype_i64 uint64_t
#define dh_ctype_s64 int64_t
#define dh_ctype_i128 Int128
#define dh_ctype_f16 uint32_t
#define dh_ctype_f32 float32
#define dh_ctype_f64 float64
#define dh_ctype_ptr void *
#define dh_ctype_cptr const void *
#define dh_ctype_env CPUArchState *
#define dh_ctype_void void
#define dh_ctype_noreturn G_NORETURN void
#define dh_ctype(t) dh_ctype_##t
#ifdef NEED_CPU_H
#ifdef COMPILING_PER_TARGET
# ifdef TARGET_LONG_BITS
# if TARGET_LONG_BITS == 32
# define dh_alias_tl i32
@@ -60,10 +54,7 @@
# endif
# endif
# define dh_ctype_tl target_ulong
# define dh_alias_env ptr
# define dh_ctype_env CPUArchState *
# define dh_typecode_env dh_typecode_ptr
#endif
#endif /* COMPILING_PER_TARGET */
/* We can't use glue() here because it falls foul of C preprocessor
recursive expansion rules. */
@@ -71,6 +62,7 @@
#define dh_retvar_decl0_noreturn void
#define dh_retvar_decl0_i32 TCGv_i32 retval
#define dh_retvar_decl0_i64 TCGv_i64 retval
#define dh_retval_decl0_i128 TCGv_i128 retval
#define dh_retvar_decl0_ptr TCGv_ptr retval
#define dh_retvar_decl0(t) glue(dh_retvar_decl0_, dh_alias(t))
@@ -78,6 +70,7 @@
#define dh_retvar_decl_noreturn
#define dh_retvar_decl_i32 TCGv_i32 retval,
#define dh_retvar_decl_i64 TCGv_i64 retval,
#define dh_retvar_decl_i128 TCGv_i128 retval,
#define dh_retvar_decl_ptr TCGv_ptr retval,
#define dh_retvar_decl(t) glue(dh_retvar_decl_, dh_alias(t))
@@ -85,6 +78,7 @@
#define dh_retvar_noreturn NULL
#define dh_retvar_i32 tcgv_i32_temp(retval)
#define dh_retvar_i64 tcgv_i64_temp(retval)
#define dh_retvar_i128 tcgv_i128_temp(retval)
#define dh_retvar_ptr tcgv_ptr_temp(retval)
#define dh_retvar(t) glue(dh_retvar_, dh_alias(t))
@@ -95,15 +89,18 @@
#define dh_typecode_i64 4
#define dh_typecode_s64 5
#define dh_typecode_ptr 6
#define dh_typecode_i128 7
#define dh_typecode_int dh_typecode_s32
#define dh_typecode_f16 dh_typecode_i32
#define dh_typecode_f32 dh_typecode_i32
#define dh_typecode_f64 dh_typecode_i64
#define dh_typecode_cptr dh_typecode_ptr
#define dh_typecode_env dh_typecode_ptr
#define dh_typecode(t) dh_typecode_##t
#define dh_callflag_i32 0
#define dh_callflag_i64 0
#define dh_callflag_i128 0
#define dh_callflag_ptr 0
#define dh_callflag_void 0
#define dh_callflag_noreturn TCG_CALL_NO_RETURN
@@ -133,6 +130,6 @@
#define DEF_HELPER_7(name, ret, t1, t2, t3, t4, t5, t6, t7) \
DEF_HELPER_FLAGS_7(name, 0, ret, t1, t2, t3, t4, t5, t6, t7)
/* MAX_OPC_PARAM_IARGS must be set to n if last entry is DEF_HELPER_FLAGS_n. */
/* MAX_CALL_IARGS must be set to n if last entry is DEF_HELPER_FLAGS_n. */
#endif /* EXEC_HELPER_HEAD_H */
+96
View File
@@ -0,0 +1,96 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Helper file for declaring TCG helper functions.
* This one expands info structures for tcg helpers.
* Define HELPER_H for the header file to be expanded.
*/
#include "tcg/tcg.h"
#include "tcg/helper-info.h"
#include "exec/helper-head.h.inc"
/*
* Need one more level of indirection before stringification
* to get all the macros expanded first.
*/
#define str(s) #s
#define DEF_HELPER_FLAGS_0(NAME, FLAGS, RET) \
TCGHelperInfo glue(helper_info_, NAME) = { \
.func = HELPER(NAME), .name = str(NAME), \
.flags = FLAGS | dh_callflag(RET), \
.typemask = dh_typemask(RET, 0) \
};
#define DEF_HELPER_FLAGS_1(NAME, FLAGS, RET, T1) \
TCGHelperInfo glue(helper_info_, NAME) = { \
.func = HELPER(NAME), .name = str(NAME), \
.flags = FLAGS | dh_callflag(RET), \
.typemask = dh_typemask(RET, 0) | dh_typemask(T1, 1) \
};
#define DEF_HELPER_FLAGS_2(NAME, FLAGS, RET, T1, T2) \
TCGHelperInfo glue(helper_info_, NAME) = { \
.func = HELPER(NAME), .name = str(NAME), \
.flags = FLAGS | dh_callflag(RET), \
.typemask = dh_typemask(RET, 0) | dh_typemask(T1, 1) \
| dh_typemask(T2, 2) \
};
#define DEF_HELPER_FLAGS_3(NAME, FLAGS, RET, T1, T2, T3) \
TCGHelperInfo glue(helper_info_, NAME) = { \
.func = HELPER(NAME), .name = str(NAME), \
.flags = FLAGS | dh_callflag(RET), \
.typemask = dh_typemask(RET, 0) | dh_typemask(T1, 1) \
| dh_typemask(T2, 2) | dh_typemask(T3, 3) \
};
#define DEF_HELPER_FLAGS_4(NAME, FLAGS, RET, T1, T2, T3, T4) \
TCGHelperInfo glue(helper_info_, NAME) = { \
.func = HELPER(NAME), .name = str(NAME), \
.flags = FLAGS | dh_callflag(RET), \
.typemask = dh_typemask(RET, 0) | dh_typemask(T1, 1) \
| dh_typemask(T2, 2) | dh_typemask(T3, 3) \
| dh_typemask(T4, 4) \
};
#define DEF_HELPER_FLAGS_5(NAME, FLAGS, RET, T1, T2, T3, T4, T5) \
TCGHelperInfo glue(helper_info_, NAME) = { \
.func = HELPER(NAME), .name = str(NAME), \
.flags = FLAGS | dh_callflag(RET), \
.typemask = dh_typemask(RET, 0) | dh_typemask(T1, 1) \
| dh_typemask(T2, 2) | dh_typemask(T3, 3) \
| dh_typemask(T4, 4) | dh_typemask(T5, 5) \
};
#define DEF_HELPER_FLAGS_6(NAME, FLAGS, RET, T1, T2, T3, T4, T5, T6) \
TCGHelperInfo glue(helper_info_, NAME) = { \
.func = HELPER(NAME), .name = str(NAME), \
.flags = FLAGS | dh_callflag(RET), \
.typemask = dh_typemask(RET, 0) | dh_typemask(T1, 1) \
| dh_typemask(T2, 2) | dh_typemask(T3, 3) \
| dh_typemask(T4, 4) | dh_typemask(T5, 5) \
| dh_typemask(T6, 6) \
};
#define DEF_HELPER_FLAGS_7(NAME, FLAGS, RET, T1, T2, T3, T4, T5, T6, T7) \
TCGHelperInfo glue(helper_info_, NAME) = { \
.func = HELPER(NAME), .name = str(NAME), \
.flags = FLAGS | dh_callflag(RET), \
.typemask = dh_typemask(RET, 0) | dh_typemask(T1, 1) \
| dh_typemask(T2, 2) | dh_typemask(T3, 3) \
| dh_typemask(T4, 4) | dh_typemask(T5, 5) \
| dh_typemask(T6, 6) | dh_typemask(T7, 7) \
};
#include HELPER_H
#undef str
#undef DEF_HELPER_FLAGS_0
#undef DEF_HELPER_FLAGS_1
#undef DEF_HELPER_FLAGS_2
#undef DEF_HELPER_FLAGS_3
#undef DEF_HELPER_FLAGS_4
#undef DEF_HELPER_FLAGS_5
#undef DEF_HELPER_FLAGS_6
#undef DEF_HELPER_FLAGS_7
+16
View File
@@ -0,0 +1,16 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Helper file for declaring TCG helper functions.
* This one expands prototypes for the helper functions.
*/
#ifndef HELPER_PROTO_COMMON_H
#define HELPER_PROTO_COMMON_H
#include "qemu/atomic128.h" /* for HAVE_CMPXCHG128 */
#define HELPER_H "accel/tcg/tcg-runtime.h"
#include "exec/helper-proto.h.inc"
#undef HELPER_H
#endif /* HELPER_PROTO_COMMON_H */
+9 -48
View File
@@ -1,55 +1,16 @@
/* Helper file for declaring TCG helper functions.
This one expands prototypes for the helper functions. */
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Helper file for declaring TCG helper functions.
* This one expands prototypes for the helper functions.
*/
#ifndef HELPER_PROTO_H
#define HELPER_PROTO_H
#include "exec/helper-head.h"
#include "exec/helper-proto-common.h"
#define DEF_HELPER_FLAGS_0(name, flags, ret) \
dh_ctype(ret) HELPER(name) (void);
#define DEF_HELPER_FLAGS_1(name, flags, ret, t1) \
dh_ctype(ret) HELPER(name) (dh_ctype(t1));
#define DEF_HELPER_FLAGS_2(name, flags, ret, t1, t2) \
dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2));
#define DEF_HELPER_FLAGS_3(name, flags, ret, t1, t2, t3) \
dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3));
#define DEF_HELPER_FLAGS_4(name, flags, ret, t1, t2, t3, t4) \
dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), \
dh_ctype(t4));
#define DEF_HELPER_FLAGS_5(name, flags, ret, t1, t2, t3, t4, t5) \
dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), \
dh_ctype(t4), dh_ctype(t5));
#define DEF_HELPER_FLAGS_6(name, flags, ret, t1, t2, t3, t4, t5, t6) \
dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), \
dh_ctype(t4), dh_ctype(t5), dh_ctype(t6));
#define DEF_HELPER_FLAGS_7(name, flags, ret, t1, t2, t3, t4, t5, t6, t7) \
dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), \
dh_ctype(t4), dh_ctype(t5), dh_ctype(t6), \
dh_ctype(t7));
#define IN_HELPER_PROTO
#include "helper.h"
#include "accel/tcg/tcg-runtime.h"
#include "accel/tcg/plugin-helpers.h"
#undef IN_HELPER_PROTO
#undef DEF_HELPER_FLAGS_0
#undef DEF_HELPER_FLAGS_1
#undef DEF_HELPER_FLAGS_2
#undef DEF_HELPER_FLAGS_3
#undef DEF_HELPER_FLAGS_4
#undef DEF_HELPER_FLAGS_5
#undef DEF_HELPER_FLAGS_6
#undef DEF_HELPER_FLAGS_7
#define HELPER_H "helper.h"
#include "exec/helper-proto.h.inc"
#undef HELPER_H
#endif /* HELPER_PROTO_H */
+68
View File
@@ -0,0 +1,68 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Helper file for declaring TCG helper functions.
* This one expands prototypes for the helper functions.
* Define HELPER_H for the header file to be expanded.
*/
#include "exec/helper-head.h.inc"
/*
* Work around an issue with --enable-lto, in which GCC's ipa-split pass
* decides to split out the noreturn code paths that raise an exception,
* taking the __builtin_return_address() along into the new function,
* where it no longer computes a value that returns to TCG generated code.
* Despite the name, the noinline attribute affects splitter, so this
* prevents the optimization in question. Given that helpers should not
* otherwise be called directly, this should not have any other visible effect.
*
* See https://gitlab.com/qemu-project/qemu/-/issues/1454
*/
#define DEF_HELPER_ATTR __attribute__((noinline))
#define DEF_HELPER_FLAGS_0(name, flags, ret) \
dh_ctype(ret) HELPER(name) (void) DEF_HELPER_ATTR;
#define DEF_HELPER_FLAGS_1(name, flags, ret, t1) \
dh_ctype(ret) HELPER(name) (dh_ctype(t1)) DEF_HELPER_ATTR;
#define DEF_HELPER_FLAGS_2(name, flags, ret, t1, t2) \
dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2)) DEF_HELPER_ATTR;
#define DEF_HELPER_FLAGS_3(name, flags, ret, t1, t2, t3) \
dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), \
dh_ctype(t3)) DEF_HELPER_ATTR;
#define DEF_HELPER_FLAGS_4(name, flags, ret, t1, t2, t3, t4) \
dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), \
dh_ctype(t4)) DEF_HELPER_ATTR;
#define DEF_HELPER_FLAGS_5(name, flags, ret, t1, t2, t3, t4, t5) \
dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), \
dh_ctype(t4), dh_ctype(t5)) DEF_HELPER_ATTR;
#define DEF_HELPER_FLAGS_6(name, flags, ret, t1, t2, t3, t4, t5, t6) \
dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), \
dh_ctype(t4), dh_ctype(t5), \
dh_ctype(t6)) DEF_HELPER_ATTR;
#define DEF_HELPER_FLAGS_7(name, flags, ret, t1, t2, t3, t4, t5, t6, t7) \
dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), \
dh_ctype(t4), dh_ctype(t5), dh_ctype(t6), \
dh_ctype(t7)) DEF_HELPER_ATTR;
#define IN_HELPER_PROTO
#include HELPER_H
#undef IN_HELPER_PROTO
#undef DEF_HELPER_FLAGS_0
#undef DEF_HELPER_FLAGS_1
#undef DEF_HELPER_FLAGS_2
#undef DEF_HELPER_FLAGS_3
#undef DEF_HELPER_FLAGS_4
#undef DEF_HELPER_FLAGS_5
#undef DEF_HELPER_FLAGS_6
#undef DEF_HELPER_FLAGS_7
#undef DEF_HELPER_ATTR

Some files were not shown because too many files have changed in this diff Show More