mirror of https://github.com/xemu-project/xemu.git
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:
commit
8b6269c8ec
23
.travis.yml
23
.travis.yml
|
@ -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'.
|
||||
|
|
|
@ -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
|
||||
=====
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
23
tcg/tcg-op.c
23
tcg/tcg-op.c
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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" |
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
;;
|
||||
|
|
|
@ -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=...: "
|
||||
|
|
Loading…
Reference in New Issue