Skip to content

Commit

Permalink
Merge branch 'dev' into v9-semantics-by-default
Browse files Browse the repository at this point in the history
  • Loading branch information
arichardson authored Oct 10, 2024
2 parents a10c229 + 6846c33 commit 311e5f5
Show file tree
Hide file tree
Showing 16 changed files with 302 additions and 74 deletions.
6 changes: 4 additions & 2 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ def bootCheriBSDForAllArchitectures(params, String qemuConfig, boolean isDebug)
addBootJobs(bootJobs, params, qemuConfig, architecture, "main")
if (!isDebug) {
// For the non-ASAN build of QEMU we also boot the latest release
addBootJobs(bootJobs, params, qemuConfig, architecture, "releng%252F22.12", "-latest-release")
def latestRelease = cheribsdInfo.getReleasedVersions()[-1]
addBootJobs(bootJobs, params, qemuConfig, architecture, "releng/${latestRelease}", "-latest-release")
}
def targetBranch = env.CHANGE_TARGET ? env.CHANGE_TARGET : env.BRANCH_NAME;
if (targetBranch == 'dev') {
Expand Down Expand Up @@ -106,7 +107,8 @@ def bootCheriBSD(params, String qemuConfig, String stageSuffix, String archSuffi
def compressedDiskImage = "artifacts-${archSuffix}/cheribsd-${archSuffix}.img.xz"
dir (stageSuffix) {
sh "rm -rfv artifacts-${archSuffix}/cheribsd-*.img* artifacts-${archSuffix}/kernel*"
copyArtifacts projectName: "CheriBSD-pipeline/${cheribsdBranch}", filter: "${compressedDiskImage}, ${compressedKernel}",
def jenkinsBranchName = cheribsdBranch.replaceAll('/', '%2F')
copyArtifacts projectName: "CheriBSD-pipeline/${jenkinsBranchName}", filter: "${compressedDiskImage}, ${compressedKernel}",
target: '.', fingerprintArtifacts: false, flatten: false, selector: lastSuccessful()
}
def testExtraArgs = [
Expand Down
165 changes: 165 additions & 0 deletions include/qemu/coroutine-tls.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
/*
* QEMU Thread Local Storage for coroutines
*
* Copyright Red Hat
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
* See the COPYING.LIB file in the top-level directory.
*
* It is forbidden to access Thread Local Storage in coroutines because
* compiler optimizations may cause values to be cached across coroutine
* re-entry. Coroutines can run in more than one thread through the course of
* their life, leading bugs when stale TLS values from the wrong thread are
* used as a result of compiler optimization.
*
* An example is:
*
* ..code-block:: c
* :caption: A coroutine that may see the wrong TLS value
*
* static __thread AioContext *current_aio_context;
* ...
* static void coroutine_fn foo(void)
* {
* aio_notify(current_aio_context);
* qemu_coroutine_yield();
* aio_notify(current_aio_context); // <-- may be stale after yielding!
* }
*
* This header provides macros for safely defining variables in Thread Local
* Storage:
*
* ..code-block:: c
* :caption: A coroutine that safely uses TLS
*
* QEMU_DEFINE_STATIC_CO_TLS(AioContext *, current_aio_context)
* ...
* static void coroutine_fn foo(void)
* {
* aio_notify(get_current_aio_context());
* qemu_coroutine_yield();
* aio_notify(get_current_aio_context()); // <-- safe
* }
*/

#ifndef QEMU_COROUTINE_TLS_H
#define QEMU_COROUTINE_TLS_H

/*
* To stop the compiler from caching TLS values we define accessor functions
* with __attribute__((noinline)) plus asm volatile("") to prevent
* optimizations that override noinline.
*
* The compiler can still analyze noinline code and make optimizations based on
* that knowledge, so an inline asm output operand is used to prevent
* optimizations that make assumptions about the address of the TLS variable.
*
* This is fragile and ultimately needs to be solved by a mechanism that is
* guaranteed to work by the compiler (e.g. stackless coroutines), but for now
* we use this approach to prevent issues.
*/

/**
* QEMU_DECLARE_CO_TLS:
* @type: the variable's C type
* @var: the variable name
*
* Declare an extern variable in Thread Local Storage from a header file:
*
* .. code-block:: c
* :caption: Declaring an extern variable in Thread Local Storage
*
* QEMU_DECLARE_CO_TLS(int, my_count)
* ...
* int c = get_my_count();
* set_my_count(c + 1);
* *get_ptr_my_count() = 0;
*
* This is a coroutine-safe replacement for the __thread keyword and is
* equivalent to the following code:
*
* .. code-block:: c
* :caption: Declaring a TLS variable using __thread
*
* extern __thread int my_count;
* ...
* int c = my_count;
* my_count = c + 1;
* *(&my_count) = 0;
*/
#define QEMU_DECLARE_CO_TLS(type, var) \
__attribute__((noinline)) type get_##var(void); \
__attribute__((noinline)) void set_##var(type v); \
__attribute__((noinline)) type *get_ptr_##var(void);

/**
* QEMU_DEFINE_CO_TLS:
* @type: the variable's C type
* @var: the variable name
*
* Define a variable in Thread Local Storage that was previously declared from
* a header file with QEMU_DECLARE_CO_TLS():
*
* .. code-block:: c
* :caption: Defining a variable in Thread Local Storage
*
* QEMU_DEFINE_CO_TLS(int, my_count)
*
* This is a coroutine-safe replacement for the __thread keyword and is
* equivalent to the following code:
*
* .. code-block:: c
* :caption: Defining a TLS variable using __thread
*
* __thread int my_count;
*/
#define QEMU_DEFINE_CO_TLS(type, var) \
static __thread type co_tls_##var; \
type get_##var(void) { asm volatile(""); return co_tls_##var; } \
void set_##var(type v) { asm volatile(""); co_tls_##var = v; } \
type *get_ptr_##var(void) \
{ type *ptr = &co_tls_##var; asm volatile("" : "+rm" (ptr)); return ptr; }

/**
* QEMU_DEFINE_STATIC_CO_TLS:
* @type: the variable's C type
* @var: the variable name
*
* Define a static variable in Thread Local Storage:
*
* .. code-block:: c
* :caption: Defining a static variable in Thread Local Storage
*
* QEMU_DEFINE_STATIC_CO_TLS(int, my_count)
* ...
* int c = get_my_count();
* set_my_count(c + 1);
* *get_ptr_my_count() = 0;
*
* This is a coroutine-safe replacement for the __thread keyword and is
* equivalent to the following code:
*
* .. code-block:: c
* :caption: Defining a static TLS variable using __thread
*
* static __thread int my_count;
* ...
* int c = my_count;
* my_count = c + 1;
* *(&my_count) = 0;
*/
#define QEMU_DEFINE_STATIC_CO_TLS(type, var) \
static __thread type co_tls_##var; \
static __attribute__((noinline, unused)) \
type get_##var(void) \
{ asm volatile(""); return co_tls_##var; } \
static __attribute__((noinline, unused)) \
void set_##var(type v) \
{ asm volatile(""); co_tls_##var = v; } \
static __attribute__((noinline, unused)) \
type *get_ptr_##var(void) \
{ type *ptr = &co_tls_##var; asm volatile("" : "+rm" (ptr)); return ptr; }

#endif /* QEMU_COROUTINE_TLS_H */
7 changes: 4 additions & 3 deletions include/qemu/rcu.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "qemu/queue.h"
#include "qemu/atomic.h"
#include "qemu/sys_membarrier.h"
#include "qemu/coroutine-tls.h"

#ifdef __cplusplus
extern "C" {
Expand Down Expand Up @@ -68,11 +69,11 @@ struct rcu_reader_data {
QLIST_ENTRY(rcu_reader_data) node;
};

extern __thread struct rcu_reader_data rcu_reader;
QEMU_DECLARE_CO_TLS(struct rcu_reader_data, rcu_reader)

static inline void rcu_read_lock(void)
{
struct rcu_reader_data *p_rcu_reader = &rcu_reader;
struct rcu_reader_data *p_rcu_reader = get_ptr_rcu_reader();
unsigned ctr;

if (p_rcu_reader->depth++ > 0) {
Expand All @@ -88,7 +89,7 @@ static inline void rcu_read_lock(void)

static inline void rcu_read_unlock(void)
{
struct rcu_reader_data *p_rcu_reader = &rcu_reader;
struct rcu_reader_data *p_rcu_reader = get_ptr_rcu_reader();

assert(p_rcu_reader->depth != 0);
if (--p_rcu_reader->depth > 0) {
Expand Down
9 changes: 5 additions & 4 deletions softmmu/cpus.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "monitor/monitor.h"
#include "qemu/coroutine-tls.h"
#include "qapi/error.h"
#include "qapi/qapi-commands-machine.h"
#include "qapi/qapi-commands-misc.h"
Expand Down Expand Up @@ -472,11 +473,11 @@ bool qemu_in_vcpu_thread(void)
return current_cpu && qemu_cpu_is_self(current_cpu);
}

static __thread bool iothread_locked = false;
QEMU_DEFINE_STATIC_CO_TLS(bool, iothread_locked)

bool qemu_mutex_iothread_locked(void)
{
return iothread_locked;
return get_iothread_locked();
}

/*
Expand All @@ -489,13 +490,13 @@ void qemu_mutex_lock_iothread_impl(const char *file, int line)

g_assert(!qemu_mutex_iothread_locked());
bql_lock(&qemu_global_mutex, file, line);
iothread_locked = true;
set_iothread_locked(true);
}

void qemu_mutex_unlock_iothread(void)
{
g_assert(qemu_mutex_iothread_locked());
iothread_locked = false;
set_iothread_locked(false);
qemu_mutex_unlock(&qemu_global_mutex);
}

Expand Down
14 changes: 12 additions & 2 deletions target/arm/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,11 @@ typedef uint64_t AARCH_REG_TYPE;
#define N_BANK_WITH_RESTRICTED 4
#endif

extern const char * const arm32_regnames[16];
#ifdef TARGET_AARCH64
extern const char * const arm64_regnames[32];
#endif

typedef struct CPUARMState {
/* Regs for current mode. */
uint32_t regs[16];
Expand Down Expand Up @@ -3574,6 +3579,7 @@ typedef CPUARMState CPUArchState;
typedef ARMCPU ArchCPU;

#include "exec/cpu-all.h"
#include "exec/log_instr.h"
#include "cpu_cheri.h"
#include "cheri-lazy-capregs.h"

Expand All @@ -3594,11 +3600,15 @@ static inline void arm_set_xreg(CPUARMState *env, int regnum,
#ifdef TARGET_CHERI
update_capreg_to_intval(env, regnum, value);
#else
#ifdef TARGET_AARCH64
if (is_a64(env)) {
env->xregs[regnum] = value;
} else {
env->regs[regnum] = value;
qemu_log_instr_reg(env, arm64_regnames[regnum], value);
return;
}
#endif
env->regs[regnum] = value;
qemu_log_instr_reg(env, arm32_regnames[regnum], value);
#endif
}

Expand Down
11 changes: 9 additions & 2 deletions target/arm/helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -14033,11 +14033,18 @@ void aarch64_sve_change_el(CPUARMState *env, int old_el,
#endif

#ifdef CONFIG_TCG_LOG_INSTR
void HELPER(arm_log_instr)(CPUARMState *env, target_ulong pc, uint32_t opcode)
void HELPER(arm_log_instr)(CPUARMState *env, uint64_t pc, uint32_t opcode,
uint32_t opcode_size)
{
if (qemu_log_instr_enabled(env)) {
qemu_log_instr_asid(env, cpu_get_asid(env, pc));
qemu_log_instr(env, pc, (char *)&opcode, sizeof(opcode));
if (opcode_size == 2) {
uint16_t opcode16 = opcode;
qemu_log_instr(env, pc, (char *)&opcode16, opcode_size);
} else {
tcg_debug_assert(opcode_size == 4);
qemu_log_instr(env, pc, (char *)&opcode, opcode_size);
}
}
}
#endif
2 changes: 1 addition & 1 deletion target/arm/helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -938,7 +938,7 @@ DEF_HELPER_FLAGS_5(neon_sqrdmulh_s, TCG_CALL_NO_RWG,
#endif

#ifdef CONFIG_TCG_LOG_INSTR
DEF_HELPER_FLAGS_3(arm_log_instr, TCG_CALL_NO_WG, void, env, tl, i32)
DEF_HELPER_FLAGS_4(arm_log_instr, TCG_CALL_NO_WG, void, env, i64, i32, i32)
#endif

#ifdef TARGET_CHERI
Expand Down
1 change: 1 addition & 0 deletions target/arm/op_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,7 @@ void HELPER(set_user_reg)(CPUARMState *env, uint32_t regno, uint32_t val)
env->usr_regs[regno - 8] = val;
} else {
env->regs[regno] = val;
qemu_log_instr_reg(env, arm32_regnames[regno], val);
}
}

Expand Down
13 changes: 5 additions & 8 deletions target/arm/translate-a64.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ static inline bool get_sctlr_sa(DisasContext *ctx)
/* Load/store exclusive handling */
static TCGv_i64 cpu_exclusive_high;

static const char *regnames[] = {
const char * const arm64_regnames[32] = {
"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
"x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
"x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
Expand Down Expand Up @@ -169,11 +169,11 @@ void a64_translate_init(void)
_cpu_cursors_do_not_access_directly[i] = tcg_global_mem_new(
cpu_env,
offsetof(CPUARMState, gpcapregs.decompressed[i].cap._cr_cursor),
regnames[i]);
arm64_regnames[i]);
#else
cpu_X[i] = tcg_global_mem_new_i64(cpu_env,
offsetof(CPUARMState, xregs[i]),
regnames[i]);
arm64_regnames[i]);
#endif
}

Expand Down Expand Up @@ -15304,11 +15304,8 @@ static void disas_a64_insn(CPUARMState *env, DisasContext *s)

#if defined(CONFIG_TCG_LOG_INSTR)
if (unlikely(s->base.log_instr_enabled)) {
TCGv pc = tcg_const_tl(s->base.pc_next);
TCGv_i32 opc = tcg_const_i32(insn);
gen_helper_arm_log_instr(cpu_env, pc, opc);
tcg_temp_free(pc);
tcg_temp_free_i32(opc);
gen_helper_arm_log_instr(cpu_env, tcg_constant_i64(s->pc_curr),
tcg_constant_i32(insn), tcg_constant_i32(4));
}

#endif
Expand Down
Loading

0 comments on commit 311e5f5

Please sign in to comment.