Testing and plugin updates:

- fix pauth TCG tests
  - tweak away rcutorture failures
  - various Travis updates
  - relax iotest size check a little
  - fix for -trace/-D clash
  - fix cross compile detection for tcg tests
  - document plugin query lifetime
  - fix missing break in plugin core
  - fix some plugin warnings
  - better progressive instruction decode
  - avoid trampling vaddr in plugins
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCgAdFiEEZoWumedRZ7yvyN81+9DbCVqeKkQFAl5VgeQACgkQ+9DbCVqe
 KkTZxQf9GSTivhKCQuBIHO/g22uEXeoqrVRAvn/43F5p8f+Y23JcO9ej1ScDfyvk
 ZvYwL39SzCEVakiJnoYw/AR38DQhE5OsRLwvaAUXapPG4QsLlSu1XB9JltZMbM92
 yAjfnyH/90OijNrMhjncD2uikVgo37gqygRP8v9ztegoc/U/4QWLqVgqGXvcbcTT
 A4g0DCfWfxdOl4kVMYRLXODBjYkZCLtflU32Q+VX4Jem/LPDZNw9zbVB0tUC6iTg
 VDMO//ARK5HeDv1yRuN34wmUPLRVWYvMpjlFk2yLfX6Z/BuMz0VrN6FBptA2P67x
 Bn4ooyjiGeiJ9sKG5ra1HMbm2nJ+Xg==
 =ncn4
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/stsquad/tags/pull-testing-and-plugins-250220-1' into staging

Testing and plugin updates:

 - fix pauth TCG tests
 - tweak away rcutorture failures
 - various Travis updates
 - relax iotest size check a little
 - fix for -trace/-D clash
 - fix cross compile detection for tcg tests
 - document plugin query lifetime
 - fix missing break in plugin core
 - fix some plugin warnings
 - better progressive instruction decode
 - avoid trampling vaddr in plugins

# gpg: Signature made Tue 25 Feb 2020 20:21:56 GMT
# gpg:                using RSA key 6685AE99E75167BCAFC8DF35FBD0DB095A9E2A44
# gpg: Good signature from "Alex Bennée (Master Work Key) <alex.bennee@linaro.org>" [full]
# Primary key fingerprint: 6685 AE99 E751 67BC AFC8  DF35 FBD0 DB09 5A9E 2A44

* remotes/stsquad/tags/pull-testing-and-plugins-250220-1:
  tests/tcg: take into account expected clashes pauth-4
  tests/tcg: fix typo in configure.sh test for v8.3
  tcg: save vaddr temp for plugin usage
  tests/tcg: give debug builds a little bit longer
  tests/plugins: make howvec clean-up after itself.
  target/riscv: progressively load the instruction during decode
  qemu/bitops.h: Add extract8 and extract16
  tests/plugin: prevent uninitialized warning
  plugins/core: add missing break in cb_to_tcg_flags
  docs/devel: document query handle lifetimes
  tracing: only allow -trace to override -D if set
  tests/iotests: be a little more forgiving on the size test
  travis.yml: single-thread build-tcg stages
  travis.yml: Fix Travis YAML configuration warnings
  travis.yml: Test the s390-ccw build, too
  tests/rcutorture: mild documenting refactor of update thread
  tests/rcutorture: better document locking of stats
  tests/rcutorture: update usage hint
  tests/tcg: include a skip runner for pauth3 with plugins

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2020-02-27 17:12:31 +00:00
commit 8b6269c8ec
17 changed files with 235 additions and 97 deletions

View file

@ -1,6 +1,7 @@
# The current Travis default is a VM based 16.04 Xenial on GCE
# Additional builds with specific requirements for a full VM need to
# be added as additional matrix: entries later on
os: linux
dist: xenial
language: c
compiler:
@ -113,7 +114,7 @@ after_script:
- if command -v ccache ; then ccache --show-stats ; fi
matrix:
jobs:
include:
- name: "GCC static (user)"
env:
@ -297,8 +298,7 @@ matrix:
- CONFIG="--target-list=x86_64-softmmu"
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
language: python
python:
- "3.5"
python: 3.5
- name: "GCC Python 3.6 (x86_64-softmmu)"
@ -306,8 +306,7 @@ matrix:
- CONFIG="--target-list=x86_64-softmmu"
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
language: python
python:
- "3.6"
python: 3.6
# Acceptance (Functional) tests
@ -401,7 +400,7 @@ matrix:
- name: "GCC check-tcg (some-softmmu)"
env:
- CONFIG="--enable-debug-tcg --target-list=xtensa-softmmu,arm-softmmu,aarch64-softmmu,alpha-softmmu"
- TEST_BUILD_CMD="make -j${JOBS} build-tcg"
- TEST_BUILD_CMD="make build-tcg"
- TEST_CMD="make check-tcg"
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug-tcg"
@ -410,7 +409,7 @@ matrix:
- name: "GCC plugins check-tcg (some-softmmu)"
env:
- CONFIG="--enable-plugins --enable-debug-tcg --target-list=xtensa-softmmu,arm-softmmu,aarch64-softmmu,alpha-softmmu"
- TEST_BUILD_CMD="make -j${JOBS} build-tcg"
- TEST_BUILD_CMD="make build-tcg"
- TEST_CMD="make check-tcg"
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-debug-tcg"
@ -509,6 +508,16 @@ matrix:
env:
- TEST_CMD="make check check-tcg V=1"
- CONFIG="--disable-containers --target-list=${MAIN_SOFTMMU_TARGETS},s390x-linux-user"
script:
- ( cd ${SRC_DIR} ; git submodule update --init roms/SLOF )
- BUILD_RC=0 && make -j${JOBS} || BUILD_RC=$?
- |
if [ "$BUILD_RC" -eq 0 ] ; then
mv pc-bios/s390-ccw/*.img pc-bios/ ;
${TEST_CMD} ;
else
$(exit $BUILD_RC);
fi
# Release builds
# The make-release script expect a QEMU version, so our tag must start with a 'v'.

View file

@ -51,8 +51,17 @@ about how QEMU's translation works to the plugins. While there are
conceptions such as translation time and translation blocks the
details are opaque to plugins. The plugin is able to query select
details of instructions and system configuration only through the
exported *qemu_plugin* functions. The types used to describe
instructions and events are opaque to the plugins themselves.
exported *qemu_plugin* functions.
Query Handle Lifetime
---------------------
Each callback provides an opaque anonymous information handle which
can usually be further queried to find out information about a
translation, instruction or operation. The handles themselves are only
valid during the lifetime of the callback so it is important that any
information that is needed is extracted during the callback and saved
by the plugin.
Usage
=====

View file

@ -301,6 +301,44 @@ static inline uint32_t extract32(uint32_t value, int start, int length)
return (value >> start) & (~0U >> (32 - length));
}
/**
* extract8:
* @value: the value to extract the bit field from
* @start: the lowest bit in the bit field (numbered from 0)
* @length: the length of the bit field
*
* Extract from the 8 bit input @value the bit field specified by the
* @start and @length parameters, and return it. The bit field must
* lie entirely within the 8 bit word. It is valid to request that
* all 8 bits are returned (ie @length 8 and @start 0).
*
* Returns: the value of the bit field extracted from the input value.
*/
static inline uint8_t extract8(uint8_t value, int start, int length)
{
assert(start >= 0 && length > 0 && length <= 8 - start);
return extract32(value, start, length);
}
/**
* extract16:
* @value: the value to extract the bit field from
* @start: the lowest bit in the bit field (numbered from 0)
* @length: the length of the bit field
*
* Extract from the 16 bit input @value the bit field specified by the
* @start and @length parameters, and return it. The bit field must
* lie entirely within the 16 bit word. It is valid to request that
* all 16 bits are returned (ie @length 16 and @start 0).
*
* Returns: the value of the bit field extracted from the input value.
*/
static inline uint16_t extract16(uint16_t value, int start, int length)
{
assert(start >= 0 && length > 0 && length <= 16 - start);
return extract32(value, start, length);
}
/**
* extract64:
* @value: the value to extract the bit field from

View file

@ -286,6 +286,7 @@ static inline uint32_t cb_to_tcg_flags(enum qemu_plugin_cb_flags flags)
switch (flags) {
case QEMU_PLUGIN_CB_RW_REGS:
ret = 0;
break;
case QEMU_PLUGIN_CB_R_REGS:
ret = TCG_CALL_NO_WG;
break;

View file

@ -344,8 +344,8 @@ enum {
#define GET_C_LW_IMM(inst) ((extract32(inst, 6, 1) << 2) \
| (extract32(inst, 10, 3) << 3) \
| (extract32(inst, 5, 1) << 6))
#define GET_C_LD_IMM(inst) ((extract32(inst, 10, 3) << 3) \
| (extract32(inst, 5, 2) << 6))
#define GET_C_LD_IMM(inst) ((extract16(inst, 10, 3) << 3) \
| (extract16(inst, 5, 2) << 6))
#define GET_C_J_IMM(inst) ((extract32(inst, 3, 3) << 1) \
| (extract32(inst, 11, 1) << 4) \
| (extract32(inst, 2, 1) << 5) \
@ -363,7 +363,7 @@ enum {
#define GET_C_RD(inst) GET_RD(inst)
#define GET_C_RS1(inst) GET_RD(inst)
#define GET_C_RS2(inst) extract32(inst, 2, 5)
#define GET_C_RS1S(inst) (8 + extract32(inst, 7, 3))
#define GET_C_RS2S(inst) (8 + extract32(inst, 2, 3))
#define GET_C_RS1S(inst) (8 + extract16(inst, 7, 3))
#define GET_C_RS2S(inst) (8 + extract16(inst, 2, 3))
#endif

View file

@ -44,7 +44,6 @@ typedef struct DisasContext {
/* pc_succ_insn points to the instruction following base.pc_next */
target_ulong pc_succ_insn;
target_ulong priv_ver;
uint32_t opcode;
uint32_t mstatus_fs;
uint32_t misa;
uint32_t mem_idx;
@ -492,45 +491,45 @@ static void gen_set_rm(DisasContext *ctx, int rm)
tcg_temp_free_i32(t0);
}
static void decode_RV32_64C0(DisasContext *ctx)
static void decode_RV32_64C0(DisasContext *ctx, uint16_t opcode)
{
uint8_t funct3 = extract32(ctx->opcode, 13, 3);
uint8_t rd_rs2 = GET_C_RS2S(ctx->opcode);
uint8_t rs1s = GET_C_RS1S(ctx->opcode);
uint8_t funct3 = extract16(opcode, 13, 3);
uint8_t rd_rs2 = GET_C_RS2S(opcode);
uint8_t rs1s = GET_C_RS1S(opcode);
switch (funct3) {
case 3:
#if defined(TARGET_RISCV64)
/* C.LD(RV64/128) -> ld rd', offset[7:3](rs1')*/
gen_load_c(ctx, OPC_RISC_LD, rd_rs2, rs1s,
GET_C_LD_IMM(ctx->opcode));
GET_C_LD_IMM(opcode));
#else
/* C.FLW (RV32) -> flw rd', offset[6:2](rs1')*/
gen_fp_load(ctx, OPC_RISC_FLW, rd_rs2, rs1s,
GET_C_LW_IMM(ctx->opcode));
GET_C_LW_IMM(opcode));
#endif
break;
case 7:
#if defined(TARGET_RISCV64)
/* C.SD (RV64/128) -> sd rs2', offset[7:3](rs1')*/
gen_store_c(ctx, OPC_RISC_SD, rs1s, rd_rs2,
GET_C_LD_IMM(ctx->opcode));
GET_C_LD_IMM(opcode));
#else
/* C.FSW (RV32) -> fsw rs2', offset[6:2](rs1')*/
gen_fp_store(ctx, OPC_RISC_FSW, rs1s, rd_rs2,
GET_C_LW_IMM(ctx->opcode));
GET_C_LW_IMM(opcode));
#endif
break;
}
}
static void decode_RV32_64C(DisasContext *ctx)
static void decode_RV32_64C(DisasContext *ctx, uint16_t opcode)
{
uint8_t op = extract32(ctx->opcode, 0, 2);
uint8_t op = extract16(opcode, 0, 2);
switch (op) {
case 0:
decode_RV32_64C0(ctx);
decode_RV32_64C0(ctx, opcode);
break;
}
}
@ -709,22 +708,25 @@ static bool gen_shift(DisasContext *ctx, arg_r *a,
/* Include the auto-generated decoder for 16 bit insn */
#include "decode_insn16.inc.c"
static void decode_opc(DisasContext *ctx)
static void decode_opc(CPURISCVState *env, DisasContext *ctx, uint16_t opcode)
{
/* check for compressed insn */
if (extract32(ctx->opcode, 0, 2) != 3) {
if (extract16(opcode, 0, 2) != 3) {
if (!has_ext(ctx, RVC)) {
gen_exception_illegal(ctx);
} else {
ctx->pc_succ_insn = ctx->base.pc_next + 2;
if (!decode_insn16(ctx, ctx->opcode)) {
if (!decode_insn16(ctx, opcode)) {
/* fall back to old decoder */
decode_RV32_64C(ctx);
decode_RV32_64C(ctx, opcode);
}
}
} else {
uint32_t opcode32 = opcode;
opcode32 = deposit32(opcode32, 16, 16,
translator_lduw(env, ctx->base.pc_next + 2));
ctx->pc_succ_insn = ctx->base.pc_next + 4;
if (!decode_insn32(ctx, ctx->opcode)) {
if (!decode_insn32(ctx, opcode32)) {
gen_exception_illegal(ctx);
}
}
@ -776,9 +778,9 @@ static void riscv_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
{
DisasContext *ctx = container_of(dcbase, DisasContext, base);
CPURISCVState *env = cpu->env_ptr;
uint16_t opcode16 = translator_lduw(env, ctx->base.pc_next);
ctx->opcode = translator_ldl(env, ctx->base.pc_next);
decode_opc(ctx);
decode_opc(env, ctx, opcode16);
ctx->base.pc_next = ctx->pc_succ_insn;
if (ctx->base.is_jmp == DISAS_NEXT) {

View file

@ -2794,13 +2794,26 @@ static void tcg_gen_req_mo(TCGBar type)
}
}
static inline TCGv plugin_prep_mem_callbacks(TCGv vaddr)
{
#ifdef CONFIG_PLUGIN
if (tcg_ctx->plugin_insn != NULL) {
/* Save a copy of the vaddr for use after a load. */
TCGv temp = tcg_temp_new();
tcg_gen_mov_tl(temp, vaddr);
return temp;
}
#endif
return vaddr;
}
static inline void plugin_gen_mem_callbacks(TCGv vaddr, uint16_t info)
{
#ifdef CONFIG_PLUGIN
if (tcg_ctx->plugin_insn == NULL) {
return;
if (tcg_ctx->plugin_insn != NULL) {
plugin_gen_empty_mem_callback(vaddr, info);
tcg_temp_free(vaddr);
}
plugin_gen_empty_mem_callback(vaddr, info);
#endif
}
@ -2822,6 +2835,7 @@ void tcg_gen_qemu_ld_i32(TCGv_i32 val, TCGv addr, TCGArg idx, MemOp memop)
}
}
addr = plugin_prep_mem_callbacks(addr);
gen_ldst_i32(INDEX_op_qemu_ld_i32, val, addr, memop, idx);
plugin_gen_mem_callbacks(addr, info);
@ -2868,6 +2882,7 @@ void tcg_gen_qemu_st_i32(TCGv_i32 val, TCGv addr, TCGArg idx, MemOp memop)
memop &= ~MO_BSWAP;
}
addr = plugin_prep_mem_callbacks(addr);
gen_ldst_i32(INDEX_op_qemu_st_i32, val, addr, memop, idx);
plugin_gen_mem_callbacks(addr, info);
@ -2905,6 +2920,7 @@ void tcg_gen_qemu_ld_i64(TCGv_i64 val, TCGv addr, TCGArg idx, MemOp memop)
}
}
addr = plugin_prep_mem_callbacks(addr);
gen_ldst_i64(INDEX_op_qemu_ld_i64, val, addr, memop, idx);
plugin_gen_mem_callbacks(addr, info);
@ -2967,6 +2983,7 @@ void tcg_gen_qemu_st_i64(TCGv_i64 val, TCGv addr, TCGArg idx, MemOp memop)
memop &= ~MO_BSWAP;
}
addr = plugin_prep_mem_callbacks(addr);
gen_ldst_i64(INDEX_op_qemu_st_i64, val, addr, memop, idx);
plugin_gen_mem_callbacks(addr, info);

View file

@ -22,9 +22,9 @@ static bool do_inline;
static void plugin_exit(qemu_plugin_id_t id, void *p)
{
g_autofree gchar *out;
out = g_strdup_printf("bb's: %" PRIu64", insns: %" PRIu64 "\n",
bb_count, insn_count);
g_autofree gchar *out = g_strdup_printf(
"bb's: %" PRIu64", insns: %" PRIu64 "\n",
bb_count, insn_count);
qemu_plugin_outs(out);
}

View file

@ -163,6 +163,13 @@ static gint cmp_exec_count(gconstpointer a, gconstpointer b)
return ea->count > eb->count ? -1 : 1;
}
static void free_record(gpointer data)
{
InsnExecCount *rec = (InsnExecCount *) data;
g_free(rec->insn);
g_free(rec);
}
static void plugin_exit(qemu_plugin_id_t id, void *p)
{
g_autoptr(GString) report = g_string_new("Instruction Classes:\n");
@ -195,30 +202,31 @@ static void plugin_exit(qemu_plugin_id_t id, void *p)
counts = g_hash_table_get_values(insns);
if (counts && g_list_next(counts)) {
GList *it;
g_string_append_printf(report,"Individual Instructions:\n");
counts = g_list_sort(counts, cmp_exec_count);
it = g_list_sort(counts, cmp_exec_count);
for (i = 0; i < limit && it->next; i++, it = it->next) {
InsnExecCount *rec = (InsnExecCount *) it->data;
g_string_append_printf(report, "Instr: %-24s\t(%ld hits)\t(op=%#08x/%s)\n",
for (i = 0; i < limit && g_list_next(counts);
i++, counts = g_list_next(counts)) {
InsnExecCount *rec = (InsnExecCount *) counts->data;
g_string_append_printf(report,
"Instr: %-24s\t(%ld hits)\t(op=%#08x/%s)\n",
rec->insn,
rec->count,
rec->opcode,
rec->class ?
rec->class->class : "un-categorised");
}
g_list_free(it);
g_list_free(counts);
}
g_hash_table_destroy(insns);
qemu_plugin_outs(report->str);
}
static void plugin_init(void)
{
insns = g_hash_table_new(NULL, g_direct_equal);
insns = g_hash_table_new_full(NULL, g_direct_equal, NULL, &free_record);
}
static void vcpu_insn_exec_before(unsigned int cpu_index, void *udata)

View file

@ -44,8 +44,7 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
static void plugin_exit(qemu_plugin_id_t id, void *p)
{
g_autofree gchar *out;
out = g_strdup_printf("insns: %" PRIu64 "\n", insn_count);
g_autofree gchar *out = g_strdup_printf("insns: %" PRIu64 "\n", insn_count);
qemu_plugin_outs(out);
}

View file

@ -125,9 +125,9 @@ $QEMU_IO -c "write -P 0xcc $offset $data_size" "json:{\
sizeB=$($QEMU_IMG info --output=json "$TEST_IMG" |
sed -n '/"actual-size":/ s/[^0-9]//gp')
if [ $sizeA -le $sizeB ]
if [ $sizeA -lt $sizeB ]
then
echo "Compression ERROR"
echo "Compression ERROR ($sizeA < $sizeB)"
fi
$QEMU_IMG check --output=json "$TEST_IMG" |

View file

@ -65,8 +65,6 @@
#include "qemu/rcu.h"
#include "qemu/thread.h"
long long n_reads = 0LL;
long n_updates = 0L;
int nthreadsrunning;
#define GOFLAG_INIT 0
@ -78,11 +76,20 @@ static volatile int goflag = GOFLAG_INIT;
#define RCU_READ_RUN 1000
#define NR_THREADS 100
static QemuMutex counts_mutex;
static QemuThread threads[NR_THREADS];
static struct rcu_reader_data *data[NR_THREADS];
static int n_threads;
/*
* Statistical counts
*
* These are the sum of local counters at the end of a run.
* Updates are protected by a mutex.
*/
static QemuMutex counts_mutex;
long long n_reads = 0LL;
long n_updates = 0L;
static void create_thread(void *(*func)(void *))
{
if (n_threads >= NR_THREADS) {
@ -223,15 +230,15 @@ static void uperftest(int nupdaters, int duration)
#define RCU_STRESS_PIPE_LEN 10
struct rcu_stress {
int pipe_count;
int age; /* how many update cycles while not rcu_stress_current */
int mbtest;
};
struct rcu_stress rcu_stress_array[RCU_STRESS_PIPE_LEN] = { { 0 } };
struct rcu_stress *rcu_stress_current;
int rcu_stress_idx;
int n_mberror;
/* Updates protected by counts_mutex */
long long rcu_stress_count[RCU_STRESS_PIPE_LEN + 1];
@ -253,7 +260,7 @@ static void *rcu_read_stress_test(void *arg)
while (goflag == GOFLAG_RUN) {
rcu_read_lock();
p = atomic_rcu_read(&rcu_stress_current);
if (p->mbtest == 0) {
if (atomic_read(&p->mbtest) == 0) {
n_mberror++;
}
rcu_read_lock();
@ -261,7 +268,7 @@ static void *rcu_read_stress_test(void *arg)
garbage++;
}
rcu_read_unlock();
pc = p->pipe_count;
pc = atomic_read(&p->age);
rcu_read_unlock();
if ((pc > RCU_STRESS_PIPE_LEN) || (pc < 0)) {
pc = RCU_STRESS_PIPE_LEN;
@ -280,32 +287,52 @@ static void *rcu_read_stress_test(void *arg)
return NULL;
}
/*
* Stress Test Updater
*
* The updater cycles around updating rcu_stress_current to point at
* one of the rcu_stress_array_entries and resets it's age. It
* then increments the age of all the other entries. The age
* will be read under an rcu_read_lock() and distribution of values
* calculated. The final result gives an indication of how many
* previously current rcu_stress entries are in flight until the RCU
* cycle complete.
*/
static void *rcu_update_stress_test(void *arg)
{
int i;
struct rcu_stress *p;
int i, rcu_stress_idx = 0;
struct rcu_stress *cp = atomic_read(&rcu_stress_current);
rcu_register_thread();
*(struct rcu_reader_data **)arg = &rcu_reader;
while (goflag == GOFLAG_INIT) {
g_usleep(1000);
}
while (goflag == GOFLAG_RUN) {
i = rcu_stress_idx + 1;
if (i >= RCU_STRESS_PIPE_LEN) {
i = 0;
struct rcu_stress *p;
rcu_stress_idx++;
if (rcu_stress_idx >= RCU_STRESS_PIPE_LEN) {
rcu_stress_idx = 0;
}
p = &rcu_stress_array[i];
p->mbtest = 0;
p = &rcu_stress_array[rcu_stress_idx];
/* catching up with ourselves would be a bug */
assert(p != cp);
atomic_set(&p->mbtest, 0);
smp_mb();
p->pipe_count = 0;
p->mbtest = 1;
atomic_set(&p->age, 0);
atomic_set(&p->mbtest, 1);
atomic_rcu_set(&rcu_stress_current, p);
rcu_stress_idx = i;
cp = p;
/*
* New RCU structure is now live, update pipe counts on old
* ones.
*/
for (i = 0; i < RCU_STRESS_PIPE_LEN; i++) {
if (i != rcu_stress_idx) {
rcu_stress_array[i].pipe_count++;
atomic_set(&rcu_stress_array[i].age,
rcu_stress_array[i].age + 1);
}
}
synchronize_rcu();
@ -338,7 +365,7 @@ static void stresstest(int nreaders, int duration)
int i;
rcu_stress_current = &rcu_stress_array[0];
rcu_stress_current->pipe_count = 0;
rcu_stress_current->age = 0;
rcu_stress_current->mbtest = 1;
for (i = 0; i < nreaders; i++) {
create_thread(rcu_read_stress_test);
@ -368,7 +395,7 @@ static void gtest_stress(int nreaders, int duration)
int i;
rcu_stress_current = &rcu_stress_array[0];
rcu_stress_current->pipe_count = 0;
rcu_stress_current->age = 0;
rcu_stress_current->mbtest = 1;
for (i = 0; i < nreaders; i++) {
create_thread(rcu_read_stress_test);
@ -413,7 +440,8 @@ static void gtest_stress_10_5(void)
static void usage(int argc, char *argv[])
{
fprintf(stderr, "Usage: %s [nreaders [ perf | stress ] ]\n", argv[0]);
fprintf(stderr, "Usage: %s [nreaders [ [r|u]perf | stress [duration]]\n",
argv[0]);
exit(-1);
}

View file

@ -79,7 +79,7 @@ QEMU_OPTS=
# If TCG debugging is enabled things are a lot slower
ifeq ($(CONFIG_DEBUG_TCG),y)
TIMEOUT=45
TIMEOUT=60
else
TIMEOUT=15
endif
@ -137,7 +137,7 @@ PLUGINS=$(notdir $(wildcard $(PLUGIN_DIR)/*.so))
$(foreach p,$(PLUGINS), \
$(foreach t,$(TESTS),\
$(eval run-plugin-$(t)-with-$(p): $t $p) \
$(eval run-plugin-$(t)-with-$(p): TIMEOUT=30) \
$(eval run-plugin-$(t)-with-$(p): TIMEOUT=60) \
$(eval RUN_TESTS+=run-plugin-$(t)-with-$(p))))
endif

View file

@ -70,4 +70,6 @@ pauth-3:
$(call skip-test, "BUILD of $@", "missing compiler support")
run-pauth-3:
$(call skip-test, "RUN of pauth-3", "not built")
run-plugin-pauth-3-with-%:
$(call skip-test, "RUN of pauth-3 ($*)", "not built")
endif

View file

@ -1,25 +1,45 @@
#include <stdint.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#define TESTS 1000
int main()
{
uintptr_t x, y;
int i, count = 0;
float perc;
void *base = malloc(TESTS);
asm("mov %0, lr\n\t"
"pacia %0, sp\n\t" /* sigill if pauth not supported */
"eor %0, %0, #4\n\t" /* corrupt single bit */
"mov %1, %0\n\t"
"autia %1, sp\n\t" /* validate corrupted pointer */
"xpaci %0\n\t" /* strip pac from corrupted pointer */
: "=r"(x), "=r"(y));
for (i = 0; i < TESTS; i++) {
uintptr_t in, x, y;
/*
* Once stripped, the corrupted pointer is of the form 0x0000...wxyz.
* We expect the autia to indicate failure, producing a pointer of the
* form 0x000e....wxyz. Use xpaci and != for the test, rather than
* extracting explicit bits from the top, because the location of the
* error code "e" depends on the configuration of virtual memory.
*/
assert(x != y);
return 0;
in = i + (uintptr_t) base;
asm("mov %0, %[in]\n\t"
"pacia %0, sp\n\t" /* sigill if pauth not supported */
"eor %0, %0, #4\n\t" /* corrupt single bit */
"mov %1, %0\n\t"
"autia %1, sp\n\t" /* validate corrupted pointer */
"xpaci %0\n\t" /* strip pac from corrupted pointer */
: /* out */ "=r"(x), "=r"(y)
: /* in */ [in] "r" (in)
: /* clobbers */);
/*
* Once stripped, the corrupted pointer is of the form 0x0000...wxyz.
* We expect the autia to indicate failure, producing a pointer of the
* form 0x000e....wxyz. Use xpaci and != for the test, rather than
* extracting explicit bits from the top, because the location of the
* error code "e" depends on the configuration of virtual memory.
*/
if (x != y) {
count++;
}
}
perc = (float) count / (float) TESTS;
printf("Checks Passed: %0.2f%%", perc * 100.0);
assert(perc > 0.95);
return 0;
}

View file

@ -228,7 +228,7 @@ for target in $target_list; do
echo "CROSS_CC_HAS_SVE=y" >> $config_target_mak
fi
if do_compiler "$target_compiler" $target_compiler_cflags \
-march=-march=armv8.3-a -o $TMPE $TMPC; then
-march=armv8.3-a -o $TMPE $TMPC; then
echo "CROSS_CC_HAS_ARMV8_3=y" >> $config_target_mak
fi
;;

View file

@ -226,10 +226,15 @@ void trace_init_file(const char *file)
#ifdef CONFIG_TRACE_SIMPLE
st_set_trace_file(file);
#elif defined CONFIG_TRACE_LOG
/* If both the simple and the log backends are enabled, "--trace file"
* only applies to the simple backend; use "-D" for the log backend.
/*
* If both the simple and the log backends are enabled, "--trace file"
* only applies to the simple backend; use "-D" for the log
* backend. However we should only override -D if we actually have
* something to override it with.
*/
qemu_set_log_filename(file, &error_fatal);
if (file) {
qemu_set_log_filename(file, &error_fatal);
}
#else
if (file) {
fprintf(stderr, "error: --trace file=...: "