From 4d2b2e766a5a60afdfa85652a328c967c248d47f Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Wed, 14 Jun 2023 12:00:32 +0200 Subject: [PATCH 0001/1353] target/tricore: Introduce ISA 1.6.2 feature we also introduce the tc37x CPU that implements that ISA version. Acked-by: Richard Henderson Signed-off-by: Bastian Koppelmann Message-Id: <20230614100039.1337971-2-kbastian@mail.uni-paderborn.de> --- target/tricore/cpu.c | 13 +++++++++++++ target/tricore/cpu.h | 1 + 2 files changed, 14 insertions(+) diff --git a/target/tricore/cpu.c b/target/tricore/cpu.c index 7fa113fed2..f15169bd1b 100644 --- a/target/tricore/cpu.c +++ b/target/tricore/cpu.c @@ -104,6 +104,10 @@ static void tricore_cpu_realizefn(DeviceState *dev, Error **errp) } /* Some features automatically imply others */ + if (tricore_feature(env, TRICORE_FEATURE_162)) { + set_feature(env, TRICORE_FEATURE_161); + } + if (tricore_feature(env, TRICORE_FEATURE_161)) { set_feature(env, TRICORE_FEATURE_16); } @@ -164,6 +168,14 @@ static void tc27x_initfn(Object *obj) set_feature(&cpu->env, TRICORE_FEATURE_161); } +static void tc37x_initfn(Object *obj) +{ + TriCoreCPU *cpu = TRICORE_CPU(obj); + + set_feature(&cpu->env, TRICORE_FEATURE_162); +} + + #include "hw/core/sysemu-cpu-ops.h" static const struct SysemuCPUOps tricore_sysemu_ops = { @@ -226,6 +238,7 @@ static const TypeInfo tricore_cpu_type_infos[] = { DEFINE_TRICORE_CPU_TYPE("tc1796", tc1796_initfn), DEFINE_TRICORE_CPU_TYPE("tc1797", tc1797_initfn), DEFINE_TRICORE_CPU_TYPE("tc27x", tc27x_initfn), + DEFINE_TRICORE_CPU_TYPE("tc37x", tc37x_initfn), }; DEFINE_TYPES(tricore_cpu_type_infos) diff --git a/target/tricore/cpu.h b/target/tricore/cpu.h index d98a3fb671..041fc0b6e5 100644 --- a/target/tricore/cpu.h +++ b/target/tricore/cpu.h @@ -273,6 +273,7 @@ enum tricore_features { TRICORE_FEATURE_131, TRICORE_FEATURE_16, TRICORE_FEATURE_161, + TRICORE_FEATURE_162, }; static inline int tricore_feature(CPUTriCoreState *env, int feature) From fd6f446a5e34f160cbdc9bb300d326cec0eca6c6 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Wed, 14 Jun 2023 12:00:33 +0200 Subject: [PATCH 0002/1353] target/tricore: Add popcnt.w insn reported in https://gitlab.com/qemu-project/qemu/-/issues/1667 Reviewed-by: Richard Henderson Signed-off-by: Bastian Koppelmann Message-Id: <20230614100039.1337971-3-kbastian@mail.uni-paderborn.de> --- target/tricore/translate.c | 7 +++++++ target/tricore/tricore-opcodes.h | 1 + 2 files changed, 8 insertions(+) diff --git a/target/tricore/translate.c b/target/tricore/translate.c index cd33a1dcdd..26b284bcec 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -6197,6 +6197,13 @@ static void decode_rr_divide(DisasContext *ctx) generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } break; + case OPC2_32_RR_POPCNT_W: + if (has_feature(ctx, TRICORE_FEATURE_162)) { + tcg_gen_ctpop_tl(cpu_gpr_d[r3], cpu_gpr_d[r1]); + } else { + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); + } + break; case OPC2_32_RR_DIV: if (has_feature(ctx, TRICORE_FEATURE_16)) { GEN_HELPER_RR(divide, cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1], diff --git a/target/tricore/tricore-opcodes.h b/target/tricore/tricore-opcodes.h index f7135f183d..59aa39a7a5 100644 --- a/target/tricore/tricore-opcodes.h +++ b/target/tricore/tricore-opcodes.h @@ -1133,6 +1133,7 @@ enum { OPC2_32_RR_PARITY = 0x02, OPC2_32_RR_UNPACK = 0x08, OPC2_32_RR_CRC32 = 0x03, + OPC2_32_RR_POPCNT_W = 0x22, /* 1.6.2 only */ OPC2_32_RR_DIV = 0x20, OPC2_32_RR_DIV_U = 0x21, OPC2_32_RR_MUL_F = 0x04, From 73f874d9fe67bc0395d629d4d1ce083f61605ba5 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Wed, 14 Jun 2023 12:00:34 +0200 Subject: [PATCH 0003/1353] target/tricore: Add LHA insn reported in https://gitlab.com/qemu-project/qemu/-/issues/1667 Reviewed-by: Richard Henderson Signed-off-by: Bastian Koppelmann Message-Id: <20230614100039.1337971-4-kbastian@mail.uni-paderborn.de> --- target/tricore/translate.c | 14 ++++++++++++-- target/tricore/tricore-opcodes.h | 9 ++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/target/tricore/translate.c b/target/tricore/translate.c index 26b284bcec..898557d22a 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -7931,7 +7931,7 @@ static void decode_sys_interrupts(DisasContext *ctx) static void decode_32Bit_opc(DisasContext *ctx) { - int op1; + int op1, op2; int32_t r1, r2, r3; int32_t address, const16; int8_t b, const4; @@ -7982,9 +7982,19 @@ static void decode_32Bit_opc(DisasContext *ctx) tcg_gen_qemu_ld_tl(cpu_gpr_d[r1], temp, ctx->mem_idx, MO_LEUW); tcg_gen_shli_tl(cpu_gpr_d[r1], cpu_gpr_d[r1], 16); break; - case OPC1_32_ABS_LEA: + case OPCM_32_ABS_LEA_LHA: address = MASK_OP_ABS_OFF18(ctx->opcode); r1 = MASK_OP_ABS_S1D(ctx->opcode); + + if (has_feature(ctx, TRICORE_FEATURE_162)) { + op2 = MASK_OP_ABS_OP2(ctx->opcode); + if (op2 == OPC2_32_ABS_LHA) { + tcg_gen_movi_tl(cpu_gpr_a[r1], address << 14); + break; + } + /* otherwise translate regular LEA */ + } + tcg_gen_movi_tl(cpu_gpr_a[r1], EA_ABS_FORMAT(address)); break; /* ABSB-format */ diff --git a/target/tricore/tricore-opcodes.h b/target/tricore/tricore-opcodes.h index 59aa39a7a5..9fab4bd75c 100644 --- a/target/tricore/tricore-opcodes.h +++ b/target/tricore/tricore-opcodes.h @@ -430,7 +430,7 @@ enum { OPCM_32_ABS_STOREB_H = 0x25, OPC1_32_ABS_STOREQ = 0x65, OPC1_32_ABS_LD_Q = 0x45, - OPC1_32_ABS_LEA = 0xc5, + OPCM_32_ABS_LEA_LHA = 0xc5, /* ABSB Format */ OPC1_32_ABSB_ST_T = 0xd5, /* B Format */ @@ -592,6 +592,13 @@ enum { OPC2_32_ABS_ST_B = 0x00, OPC2_32_ABS_ST_H = 0x02, }; + +/* OPCM_32_ABS_LEA_LHA */ +enum { + OPC2_32_ABS_LEA = 0x00, + OPC2_32_ABS_LHA = 0x01, +}; + /* * Bit Format */ From dc0b4368be92d85fc9fb2d48922149759c1f7804 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Wed, 14 Jun 2023 12:00:35 +0200 Subject: [PATCH 0004/1353] target/tricore: Add crc32l.w insn reported in https://gitlab.com/qemu-project/qemu/-/issues/1667 Reviewed-by: Richard Henderson Signed-off-by: Bastian Koppelmann Message-Id: <20230614100039.1337971-5-kbastian@mail.uni-paderborn.de> --- target/tricore/helper.h | 3 ++- target/tricore/op_helper.c | 10 +++++++++- target/tricore/translate.c | 12 ++++++++++-- target/tricore/tricore-opcodes.h | 3 ++- 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/target/tricore/helper.h b/target/tricore/helper.h index b64780c37d..24da5e97c0 100644 --- a/target/tricore/helper.h +++ b/target/tricore/helper.h @@ -131,7 +131,8 @@ DEF_HELPER_FLAGS_5(mul_h, TCG_CALL_NO_RWG_SE, i64, i32, i32, i32, i32, i32) DEF_HELPER_FLAGS_5(mulm_h, TCG_CALL_NO_RWG_SE, i64, i32, i32, i32, i32, i32) DEF_HELPER_FLAGS_5(mulr_h, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32, i32, i32) /* crc32 */ -DEF_HELPER_FLAGS_2(crc32, TCG_CALL_NO_RWG_SE, i32, i32, i32) +DEF_HELPER_FLAGS_2(crc32_be, TCG_CALL_NO_RWG_SE, i32, i32, i32) +DEF_HELPER_FLAGS_2(crc32_le, TCG_CALL_NO_RWG_SE, i32, i32, i32) /* CSA */ DEF_HELPER_2(call, void, env, i32) DEF_HELPER_1(ret, void, env) diff --git a/target/tricore/op_helper.c b/target/tricore/op_helper.c index 54f54811d9..8ce404cb93 100644 --- a/target/tricore/op_helper.c +++ b/target/tricore/op_helper.c @@ -2284,7 +2284,7 @@ uint32_t helper_mulr_h(uint32_t arg00, uint32_t arg01, return (result1 & 0xffff0000) | (result0 >> 16); } -uint32_t helper_crc32(uint32_t arg0, uint32_t arg1) +uint32_t helper_crc32_be(uint32_t arg0, uint32_t arg1) { uint8_t buf[4]; stl_be_p(buf, arg0); @@ -2292,6 +2292,14 @@ uint32_t helper_crc32(uint32_t arg0, uint32_t arg1) return crc32(arg1, buf, 4); } +uint32_t helper_crc32_le(uint32_t arg0, uint32_t arg1) +{ + uint8_t buf[4]; + stl_le_p(buf, arg0); + + return crc32(arg1, buf, 4); +} + /* context save area (CSA) related helpers */ static int cdc_increment(target_ulong *psw) diff --git a/target/tricore/translate.c b/target/tricore/translate.c index 898557d22a..250de80de5 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -6190,13 +6190,21 @@ static void decode_rr_divide(DisasContext *ctx) CHECK_REG_PAIR(r3); gen_unpack(cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1]); break; - case OPC2_32_RR_CRC32: + case OPC2_32_RR_CRC32: /* CRC32B.W in 1.6.2 */ if (has_feature(ctx, TRICORE_FEATURE_161)) { - gen_helper_crc32(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]); + gen_helper_crc32_be(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]); } else { generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } break; + case OPC2_32_RR_CRC32L_W: + if (has_feature(ctx, TRICORE_FEATURE_162)) { + gen_helper_crc32_le(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]); + } else { + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); + } + break; + case OPC2_32_RR_POPCNT_W: if (has_feature(ctx, TRICORE_FEATURE_162)) { tcg_gen_ctpop_tl(cpu_gpr_d[r3], cpu_gpr_d[r1]); diff --git a/target/tricore/tricore-opcodes.h b/target/tricore/tricore-opcodes.h index 9fab4bd75c..be07f82ec1 100644 --- a/target/tricore/tricore-opcodes.h +++ b/target/tricore/tricore-opcodes.h @@ -1139,7 +1139,8 @@ enum { OPC2_32_RR_DVINIT_U = 0x0a, OPC2_32_RR_PARITY = 0x02, OPC2_32_RR_UNPACK = 0x08, - OPC2_32_RR_CRC32 = 0x03, + OPC2_32_RR_CRC32 = 0x03, /* CRC32B.W in 1.6.2 */ + OPC2_32_RR_CRC32L_W = 0x07, /* 1.6.2 only */ OPC2_32_RR_POPCNT_W = 0x22, /* 1.6.2 only */ OPC2_32_RR_DIV = 0x20, OPC2_32_RR_DIV_U = 0x21, From 0eaafe33d03447f36ff152010836d501ba68c710 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Wed, 14 Jun 2023 12:00:36 +0200 Subject: [PATCH 0005/1353] target/tricore: Add crc32.b insn reported in https://gitlab.com/qemu-project/qemu/-/issues/1667 Reviewed-by: Richard Henderson Signed-off-by: Bastian Koppelmann Message-Id: <20230614100039.1337971-6-kbastian@mail.uni-paderborn.de> --- target/tricore/helper.h | 1 + target/tricore/op_helper.c | 8 ++++++++ target/tricore/translate.c | 7 +++++++ target/tricore/tricore-opcodes.h | 1 + 4 files changed, 17 insertions(+) diff --git a/target/tricore/helper.h b/target/tricore/helper.h index 24da5e97c0..a10576e09e 100644 --- a/target/tricore/helper.h +++ b/target/tricore/helper.h @@ -131,6 +131,7 @@ DEF_HELPER_FLAGS_5(mul_h, TCG_CALL_NO_RWG_SE, i64, i32, i32, i32, i32, i32) DEF_HELPER_FLAGS_5(mulm_h, TCG_CALL_NO_RWG_SE, i64, i32, i32, i32, i32, i32) DEF_HELPER_FLAGS_5(mulr_h, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32, i32, i32) /* crc32 */ +DEF_HELPER_FLAGS_2(crc32b, TCG_CALL_NO_RWG_SE, i32, i32, i32) DEF_HELPER_FLAGS_2(crc32_be, TCG_CALL_NO_RWG_SE, i32, i32, i32) DEF_HELPER_FLAGS_2(crc32_le, TCG_CALL_NO_RWG_SE, i32, i32, i32) /* CSA */ diff --git a/target/tricore/op_helper.c b/target/tricore/op_helper.c index 8ce404cb93..b6ef1462e4 100644 --- a/target/tricore/op_helper.c +++ b/target/tricore/op_helper.c @@ -2284,6 +2284,14 @@ uint32_t helper_mulr_h(uint32_t arg00, uint32_t arg01, return (result1 & 0xffff0000) | (result0 >> 16); } +uint32_t helper_crc32b(uint32_t arg0, uint32_t arg1) +{ + uint8_t buf[1] = { arg0 & 0xff }; + + return crc32(arg1, buf, 1); +} + + uint32_t helper_crc32_be(uint32_t arg0, uint32_t arg1) { uint8_t buf[4]; diff --git a/target/tricore/translate.c b/target/tricore/translate.c index 250de80de5..85526ef4db 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -6190,6 +6190,13 @@ static void decode_rr_divide(DisasContext *ctx) CHECK_REG_PAIR(r3); gen_unpack(cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1]); break; + case OPC2_32_RR_CRC32_B: + if (has_feature(ctx, TRICORE_FEATURE_162)) { + gen_helper_crc32b(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]); + } else { + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); + } + break; case OPC2_32_RR_CRC32: /* CRC32B.W in 1.6.2 */ if (has_feature(ctx, TRICORE_FEATURE_161)) { gen_helper_crc32_be(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]); diff --git a/target/tricore/tricore-opcodes.h b/target/tricore/tricore-opcodes.h index be07f82ec1..27f80e1702 100644 --- a/target/tricore/tricore-opcodes.h +++ b/target/tricore/tricore-opcodes.h @@ -1140,6 +1140,7 @@ enum { OPC2_32_RR_PARITY = 0x02, OPC2_32_RR_UNPACK = 0x08, OPC2_32_RR_CRC32 = 0x03, /* CRC32B.W in 1.6.2 */ + OPC2_32_RR_CRC32_B = 0x06, /* 1.6.2 only */ OPC2_32_RR_CRC32L_W = 0x07, /* 1.6.2 only */ OPC2_32_RR_POPCNT_W = 0x22, /* 1.6.2 only */ OPC2_32_RR_DIV = 0x20, From 4e3377bb5abe8914eec0650730536d5d48e22008 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Wed, 14 Jun 2023 12:00:37 +0200 Subject: [PATCH 0006/1353] target/tricore: Add shuffle insn this is based on code by volumit (https://github.com/volumit/qemu/). Reported in https://gitlab.com/qemu-project/qemu/-/issues/1667 and https://gitlab.com/qemu-project/qemu/-/issues/1452. Reviewed-by: Richard Henderson Signed-off-by: Bastian Koppelmann Message-Id: <20230614100039.1337971-7-kbastian@mail.uni-paderborn.de> --- target/tricore/helper.h | 1 + target/tricore/op_helper.c | 36 ++++++++++++++++++++++++++++++++ target/tricore/translate.c | 8 +++++++ target/tricore/tricore-opcodes.h | 1 + 4 files changed, 46 insertions(+) diff --git a/target/tricore/helper.h b/target/tricore/helper.h index a10576e09e..31d71eac7a 100644 --- a/target/tricore/helper.h +++ b/target/tricore/helper.h @@ -134,6 +134,7 @@ DEF_HELPER_FLAGS_5(mulr_h, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32, i32, i32) DEF_HELPER_FLAGS_2(crc32b, TCG_CALL_NO_RWG_SE, i32, i32, i32) DEF_HELPER_FLAGS_2(crc32_be, TCG_CALL_NO_RWG_SE, i32, i32, i32) DEF_HELPER_FLAGS_2(crc32_le, TCG_CALL_NO_RWG_SE, i32, i32, i32) +DEF_HELPER_FLAGS_2(shuffle, TCG_CALL_NO_RWG_SE, i32, i32, i32) /* CSA */ DEF_HELPER_2(call, void, env, i32) DEF_HELPER_1(ret, void, env) diff --git a/target/tricore/op_helper.c b/target/tricore/op_helper.c index b6ef1462e4..026e15f3e0 100644 --- a/target/tricore/op_helper.c +++ b/target/tricore/op_helper.c @@ -2308,6 +2308,42 @@ uint32_t helper_crc32_le(uint32_t arg0, uint32_t arg1) return crc32(arg1, buf, 4); } +uint32_t helper_shuffle(uint32_t arg0, uint32_t arg1) +{ + uint32_t resb; + uint32_t byte_select; + uint32_t res = 0; + + byte_select = arg1 & 0x3; + resb = extract32(arg0, byte_select * 8, 8); + res |= resb << 0; + + byte_select = (arg1 >> 2) & 0x3; + resb = extract32(arg0, byte_select * 8, 8); + res |= resb << 8; + + byte_select = (arg1 >> 4) & 0x3; + resb = extract32(arg0, byte_select * 8, 8); + res |= resb << 16; + + byte_select = (arg1 >> 6) & 0x3; + resb = extract32(arg0, byte_select * 8, 8); + res |= resb << 24; + + if (arg1 & 0x100) { + /* Assign the correct nibble position. */ + res = ((res & 0xf0f0f0f0) >> 4) + | ((res & 0x0f0f0f0f) << 4); + /* Assign the correct bit position. */ + res = ((res & 0x88888888) >> 3) + | ((res & 0x44444444) >> 1) + | ((res & 0x22222222) << 1) + | ((res & 0x11111111) << 3); + } + + return res; +} + /* context save area (CSA) related helpers */ static int cdc_increment(target_ulong *psw) diff --git a/target/tricore/translate.c b/target/tricore/translate.c index 85526ef4db..a4c60e8ae2 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -5011,6 +5011,14 @@ static void decode_rc_logical_shift(DisasContext *ctx) case OPC2_32_RC_XOR: tcg_gen_xori_tl(cpu_gpr_d[r2], cpu_gpr_d[r1], const9); break; + case OPC2_32_RC_SHUFFLE: + if (has_feature(ctx, TRICORE_FEATURE_162)) { + TCGv temp = tcg_constant_i32(const9); + gen_helper_shuffle(cpu_gpr_d[r2], cpu_gpr_d[r1], temp); + } else { + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); + } + break; default: generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } diff --git a/target/tricore/tricore-opcodes.h b/target/tricore/tricore-opcodes.h index 27f80e1702..af63926731 100644 --- a/target/tricore/tricore-opcodes.h +++ b/target/tricore/tricore-opcodes.h @@ -885,6 +885,7 @@ enum { OPC2_32_RC_SHAS = 0x02, OPC2_32_RC_XNOR = 0x0d, OPC2_32_RC_XOR = 0x0c, + OPC2_32_RC_SHUFFLE = 0x07, /* v1.6.2 only */ }; /* OPCM_32_RC_ACCUMULATOR */ enum { From 3b5d136db6484f2b625fb98cce4fd8b7ac26e348 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Wed, 14 Jun 2023 12:00:38 +0200 Subject: [PATCH 0007/1353] target/tricore: Implement SYCSCALL insn Reviewed-by: Richard Henderson Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1452 Signed-off-by: Bastian Koppelmann Message-Id: <20230614100039.1337971-8-kbastian@mail.uni-paderborn.de> --- target/tricore/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/tricore/translate.c b/target/tricore/translate.c index a4c60e8ae2..f01000efd4 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -5236,7 +5236,7 @@ static void decode_rc_serviceroutine(DisasContext *ctx) gen_helper_1arg(bisr, const9); break; case OPC2_32_RC_SYSCALL: - /* TODO: Add exception generation */ + generate_trap(ctx, TRAPC_SYSCALL, const9 & 0xff); break; default: generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); From 0b9f9b63c2d1e26cfe4e593f384898837c7c941f Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Wed, 14 Jun 2023 12:00:39 +0200 Subject: [PATCH 0008/1353] target/tricore: Add DISABLE insn variant this variant saves the 'IE' bit to a 'd' register. The 'IE' bitfield changed from ISA version 1.6.1, so we add icr_ie_offset to DisasContext as with the other DISABLE insn. Reviewed-by: Richard Henderson Signed-off-by: Bastian Koppelmann Message-Id: <20230614100039.1337971-9-kbastian@mail.uni-paderborn.de> --- target/tricore/translate.c | 11 ++++++++++- target/tricore/tricore-opcodes.h | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/target/tricore/translate.c b/target/tricore/translate.c index f01000efd4..6712d98f6e 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -75,7 +75,7 @@ typedef struct DisasContext { int mem_idx; uint32_t hflags, saved_hflags; uint64_t features; - uint32_t icr_ie_mask; + uint32_t icr_ie_mask, icr_ie_offset; } DisasContext; static int has_feature(DisasContext *ctx, int feature) @@ -7883,6 +7883,13 @@ static void decode_sys_interrupts(DisasContext *ctx) case OPC2_32_SYS_DISABLE: tcg_gen_andi_tl(cpu_ICR, cpu_ICR, ~ctx->icr_ie_mask); break; + case OPC2_32_SYS_DISABLE_D: + if (has_feature(ctx, TRICORE_FEATURE_16)) { + tcg_gen_extract_tl(cpu_gpr_d[r1], cpu_ICR, ctx->icr_ie_offset, 1); + tcg_gen_andi_tl(cpu_ICR, cpu_ICR, ~ctx->icr_ie_mask); + } else { + generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); + } case OPC2_32_SYS_DSYNC: break; case OPC2_32_SYS_ENABLE: @@ -8302,8 +8309,10 @@ static void tricore_tr_init_disas_context(DisasContextBase *dcbase, ctx->features = env->features; if (has_feature(ctx, TRICORE_FEATURE_161)) { ctx->icr_ie_mask = R_ICR_IE_161_MASK; + ctx->icr_ie_offset = R_ICR_IE_161_SHIFT; } else { ctx->icr_ie_mask = R_ICR_IE_13_MASK; + ctx->icr_ie_offset = R_ICR_IE_13_SHIFT; } } diff --git a/target/tricore/tricore-opcodes.h b/target/tricore/tricore-opcodes.h index af63926731..bc62b73173 100644 --- a/target/tricore/tricore-opcodes.h +++ b/target/tricore/tricore-opcodes.h @@ -1467,6 +1467,7 @@ enum { enum { OPC2_32_SYS_DEBUG = 0x04, OPC2_32_SYS_DISABLE = 0x0d, + OPC2_32_SYS_DISABLE_D = 0x0f, /* 1.6 up */ OPC2_32_SYS_DSYNC = 0x12, OPC2_32_SYS_ENABLE = 0x0c, OPC2_32_SYS_ISYNC = 0x13, From d34b092cab606a47a0d76edde45aab7100bb2435 Mon Sep 17 00:00:00 2001 From: Siqi Chen Date: Mon, 12 Jun 2023 13:32:42 +0200 Subject: [PATCH 0009/1353] target/tricore: Fix out-of-bounds index in imask instruction When translating "imask" instruction of Tricore architecture, QEMU did not check whether the register index was out of bounds, resulting in a global-buffer-overflow. Reviewed-by: Bastian Koppelmann Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1698 Reported-by: Siqi Chen Signed-off-by: Siqi Chen Signed-off-by: Bastian Koppelmann Message-Id: <20230612065633.149152-1-coc.cyqh@gmail.com> Message-Id: <20230612113245.56667-2-kbastian@mail.uni-paderborn.de> --- target/tricore/translate.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target/tricore/translate.c b/target/tricore/translate.c index 6712d98f6e..74faad4794 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -5339,6 +5339,7 @@ static void decode_rcrw_insert(DisasContext *ctx) switch (op2) { case OPC2_32_RCRW_IMASK: + CHECK_REG_PAIR(r4); tcg_gen_andi_tl(temp, cpu_gpr_d[r3], 0x1f); tcg_gen_movi_tl(temp2, (1 << width) - 1); tcg_gen_shl_tl(cpu_gpr_d[r4 + 1], temp2, temp); From 5434557ffc5b46f178ccf325517db2b1f5e2c037 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Mon, 12 Jun 2023 13:32:43 +0200 Subject: [PATCH 0010/1353] target/tricore: Correctly fix saving PSW.CDE to CSA on call we don't want to save PSW.CDC to the CSA, but PSW.CDE must be saved. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1699 Signed-off-by: Bastian Koppelmann Message-Id: <20230612113245.56667-3-kbastian@mail.uni-paderborn.de> --- target/tricore/op_helper.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/target/tricore/op_helper.c b/target/tricore/op_helper.c index 026e15f3e0..9a7a26b171 100644 --- a/target/tricore/op_helper.c +++ b/target/tricore/op_helper.c @@ -2499,7 +2499,12 @@ void helper_call(CPUTriCoreState *env, uint32_t next_pc) } /* PSW.CDE = 1;*/ psw |= MASK_PSW_CDE; - psw_write(env, psw); + /* + * we need to save PSW.CDE and not PSW.CDC into the CSAs. psw already + * contains the CDC from cdc_increment(), so we cannot call psw_write() + * here. + */ + env->PSW |= MASK_PSW_CDE; /* tmp_FCX = FCX; */ tmp_FCX = env->FCX; From 6991777ec4b2a344d47bddec62744bedd9883d78 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Mon, 12 Jun 2023 13:32:44 +0200 Subject: [PATCH 0011/1353] target/tricore: Add CHECK_REG_PAIR() for insn accessing 64 bit regs some insns were not checking if an even index was used to access a 64 bit register. In the worst case that could lead to a buffer overflow as reported in https://gitlab.com/qemu-project/qemu/-/issues/1698. Reported-by: Siqi Chen Signed-off-by: Bastian Koppelmann Message-Id: <20230612113245.56667-4-kbastian@mail.uni-paderborn.de> --- target/tricore/translate.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/target/tricore/translate.c b/target/tricore/translate.c index 74faad4794..d1b319e374 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -309,6 +309,7 @@ static void gen_cmpswap(DisasContext *ctx, int reg, TCGv ea) { TCGv temp = tcg_temp_new(); TCGv temp2 = tcg_temp_new(); + CHECK_REG_PAIR(reg); tcg_gen_qemu_ld_tl(temp, ea, ctx->mem_idx, MO_LEUL); tcg_gen_movcond_tl(TCG_COND_EQ, temp2, cpu_gpr_d[reg+1], temp, cpu_gpr_d[reg], temp); @@ -321,7 +322,7 @@ static void gen_swapmsk(DisasContext *ctx, int reg, TCGv ea) TCGv temp = tcg_temp_new(); TCGv temp2 = tcg_temp_new(); TCGv temp3 = tcg_temp_new(); - + CHECK_REG_PAIR(reg); tcg_gen_qemu_ld_tl(temp, ea, ctx->mem_idx, MO_LEUL); tcg_gen_and_tl(temp2, cpu_gpr_d[reg], cpu_gpr_d[reg+1]); tcg_gen_andc_tl(temp3, temp, cpu_gpr_d[reg+1]); @@ -3219,6 +3220,7 @@ static void decode_src_opc(DisasContext *ctx, int op1) break; case OPC1_16_SRC_MOV_E: if (has_feature(ctx, TRICORE_FEATURE_16)) { + CHECK_REG_PAIR(r1); tcg_gen_movi_tl(cpu_gpr_d[r1], const4); tcg_gen_sari_tl(cpu_gpr_d[r1+1], cpu_gpr_d[r1], 31); } else { @@ -6180,6 +6182,7 @@ static void decode_rr_divide(DisasContext *ctx) tcg_gen_sari_tl(cpu_gpr_d[r3+1], cpu_gpr_d[r1], 31); break; case OPC2_32_RR_DVINIT_U: + CHECK_REG_PAIR(r3); /* overflow = (D[b] == 0) */ tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_PSW_V, cpu_gpr_d[r2], 0); tcg_gen_shli_tl(cpu_PSW_V, cpu_PSW_V, 31); @@ -6230,6 +6233,7 @@ static void decode_rr_divide(DisasContext *ctx) break; case OPC2_32_RR_DIV: if (has_feature(ctx, TRICORE_FEATURE_16)) { + CHECK_REG_PAIR(r3); GEN_HELPER_RR(divide, cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2]); } else { @@ -6238,6 +6242,7 @@ static void decode_rr_divide(DisasContext *ctx) break; case OPC2_32_RR_DIV_U: if (has_feature(ctx, TRICORE_FEATURE_16)) { + CHECK_REG_PAIR(r3); GEN_HELPER_RR(divide_u, cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r1], cpu_gpr_d[r2]); } else { @@ -6764,6 +6769,8 @@ static void decode_rrr2_msub(DisasContext *ctx) cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r2]); break; case OPC2_32_RRR2_MSUB_U_64: + CHECK_REG_PAIR(r4); + CHECK_REG_PAIR(r3); gen_msubu64_d(cpu_gpr_d[r4], cpu_gpr_d[r4+1], cpu_gpr_d[r1], cpu_gpr_d[r3], cpu_gpr_d[r3+1], cpu_gpr_d[r2]); break; @@ -7847,7 +7854,7 @@ static void decode_rrrw_extract_insert(DisasContext *ctx) break; case OPC2_32_RRRW_IMASK: temp2 = tcg_temp_new(); - + CHECK_REG_PAIR(r4); tcg_gen_andi_tl(temp, cpu_gpr_d[r3], 0x1f); tcg_gen_movi_tl(temp2, (1 << width) - 1); tcg_gen_shl_tl(temp2, temp2, temp); From 82736612e75b84f51d8f3529cb35fa3835de5741 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Mon, 12 Jun 2023 13:32:45 +0200 Subject: [PATCH 0012/1353] target/tricore: Fix helper_ret() not correctly restoring PSW We are always taking the TRICORE_FEATURE_13 branch as every CPU has TRICORE_FEATURE_13. For CPUs with ISA > 1.3 we have to take the else branch. We fix this by inverting the condition. We check for TRICORE_FEATURE_131, which every CPU except TRICORE_FEATURE_13 CPUs have. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1700 Signed-off-by: Bastian Koppelmann Message-Id: <20230612113245.56667-5-kbastian@mail.uni-paderborn.de> --- target/tricore/op_helper.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target/tricore/op_helper.c b/target/tricore/op_helper.c index 9a7a26b171..821a4b67cb 100644 --- a/target/tricore/op_helper.c +++ b/target/tricore/op_helper.c @@ -2584,12 +2584,12 @@ void helper_ret(CPUTriCoreState *env) /* PCXI = new_PCXI; */ env->PCXI = new_PCXI; - if (tricore_feature(env, TRICORE_FEATURE_13)) { - /* PSW = new_PSW */ - psw_write(env, new_PSW); - } else { + if (tricore_feature(env, TRICORE_FEATURE_131)) { /* PSW = {new_PSW[31:26], PSW[25:24], new_PSW[23:0]}; */ psw_write(env, (new_PSW & ~(0x3000000)) + (psw & (0x3000000))); + } else { /* TRICORE_FEATURE_13 only */ + /* PSW = new_PSW */ + psw_write(env, new_PSW); } } From 8da70480f59b4fd423918ac756747c1e35f6f53a Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Wed, 21 Jun 2023 16:22:55 +0200 Subject: [PATCH 0013/1353] target/tricore: Fix RR_JLI clobbering reg A[11] if A[r1] == A[11], then we would overwrite the destination address of the jump with the return address. Reported-by: Richard Henderson Reviewed-by: Richard Henderson Signed-off-by: Bastian Koppelmann Message-Id: <20230621142302.1648383-2-kbastian@mail.uni-paderborn.de> --- target/tricore/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/tricore/translate.c b/target/tricore/translate.c index d1b319e374..cca52c75b2 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -6064,8 +6064,8 @@ static void decode_rr_idirect(DisasContext *ctx) tcg_gen_andi_tl(cpu_PC, cpu_gpr_a[r1], ~0x1); break; case OPC2_32_RR_JLI: - tcg_gen_movi_tl(cpu_gpr_a[11], ctx->pc_succ_insn); tcg_gen_andi_tl(cpu_PC, cpu_gpr_a[r1], ~0x1); + tcg_gen_movi_tl(cpu_gpr_a[11], ctx->pc_succ_insn); break; case OPC2_32_RR_CALLI: gen_helper_1arg(call, ctx->pc_succ_insn); From 1706e04f6e807431b460b4109ab65bb469adc53a Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Wed, 21 Jun 2023 16:22:56 +0200 Subject: [PATCH 0014/1353] target/tricore: Introduce DISAS_TARGET_EXIT this replaces all calls to tcg_gen_exit_tb() and moves them to tricore_tb_stop(). Reviewed-by: Richard Henderson Signed-off-by: Bastian Koppelmann Message-Id: <20230621142302.1648383-3-kbastian@mail.uni-paderborn.de> --- target/tricore/translate.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/target/tricore/translate.c b/target/tricore/translate.c index cca52c75b2..ef74e9f234 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -37,6 +37,7 @@ #include "exec/helper-info.c.inc" #undef HELPER_H +#define DISAS_EXIT DISAS_TARGET_0 /* * TCG registers @@ -2836,6 +2837,7 @@ static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) gen_save_pc(dest); tcg_gen_lookup_and_goto_ptr(); } + ctx->base.is_jmp = DISAS_NORETURN; } static void generate_trap(DisasContext *ctx, int class, int tin) @@ -2896,8 +2898,7 @@ static void gen_fret(DisasContext *ctx) tcg_gen_qemu_ld_tl(cpu_gpr_a[11], cpu_gpr_a[10], ctx->mem_idx, MO_LESL); tcg_gen_addi_tl(cpu_gpr_a[10], cpu_gpr_a[10], 4); tcg_gen_mov_tl(cpu_PC, temp); - tcg_gen_exit_tb(NULL, 0); - ctx->base.is_jmp = DISAS_NORETURN; + ctx->base.is_jmp = DISAS_EXIT; } static void gen_compute_branch(DisasContext *ctx, uint32_t opc, int r1, @@ -2996,12 +2997,12 @@ static void gen_compute_branch(DisasContext *ctx, uint32_t opc, int r1, /* SR-format jumps */ case OPC1_16_SR_JI: tcg_gen_andi_tl(cpu_PC, cpu_gpr_a[r1], 0xfffffffe); - tcg_gen_exit_tb(NULL, 0); + ctx->base.is_jmp = DISAS_EXIT; break; case OPC2_32_SYS_RET: case OPC2_16_SR_RET: gen_helper_ret(cpu_env); - tcg_gen_exit_tb(NULL, 0); + ctx->base.is_jmp = DISAS_EXIT; break; /* B-format */ case OPC1_32_B_CALLA: @@ -3153,7 +3154,6 @@ static void gen_compute_branch(DisasContext *ctx, uint32_t opc, int r1, default: generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } - ctx->base.is_jmp = DISAS_NORETURN; } @@ -3495,8 +3495,7 @@ static void decode_sr_system(DisasContext *ctx) break; case OPC2_16_SR_RFE: gen_helper_rfe(cpu_env); - tcg_gen_exit_tb(NULL, 0); - ctx->base.is_jmp = DISAS_NORETURN; + ctx->base.is_jmp = DISAS_EXIT; break; case OPC2_16_SR_DEBUG: /* raise EXCP_DEBUG */ @@ -6078,8 +6077,7 @@ static void decode_rr_idirect(DisasContext *ctx) default: generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } - tcg_gen_exit_tb(NULL, 0); - ctx->base.is_jmp = DISAS_NORETURN; + ctx->base.is_jmp = DISAS_EXIT; } static void decode_rr_divide(DisasContext *ctx) @@ -7915,8 +7913,7 @@ static void decode_sys_interrupts(DisasContext *ctx) break; case OPC2_32_SYS_RFE: gen_helper_rfe(cpu_env); - tcg_gen_exit_tb(NULL, 0); - ctx->base.is_jmp = DISAS_NORETURN; + ctx->base.is_jmp = DISAS_EXIT; break; case OPC2_32_SYS_RFM: if ((ctx->hflags & TRICORE_HFLAG_KUU) == TRICORE_HFLAG_SM) { @@ -7928,8 +7925,7 @@ static void decode_sys_interrupts(DisasContext *ctx) tcg_gen_brcondi_tl(TCG_COND_NE, tmp, 1, l1); gen_helper_rfm(cpu_env); gen_set_label(l1); - tcg_gen_exit_tb(NULL, 0); - ctx->base.is_jmp = DISAS_NORETURN; + ctx->base.is_jmp = DISAS_EXIT; } else { /* generate privilege trap */ } @@ -8391,6 +8387,9 @@ static void tricore_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) case DISAS_TOO_MANY: gen_goto_tb(ctx, 0, ctx->base.pc_next); break; + case DISAS_EXIT: + tcg_gen_exit_tb(NULL, 0); + break; case DISAS_NORETURN: break; default: From 2dbd73bf17f4c6bf016709d995ea46477cb6133c Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Wed, 21 Jun 2023 16:22:57 +0200 Subject: [PATCH 0015/1353] target/tricore: ENABLE exit to main-loop so we can recognize exceptions after re-enabling interrupts. Reviewed-by: Richard Henderson Reported-by: Richard Henderson Signed-off-by: Bastian Koppelmann Message-Id: <20230621142302.1648383-4-kbastian@mail.uni-paderborn.de> --- target/tricore/translate.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target/tricore/translate.c b/target/tricore/translate.c index ef74e9f234..98e2767d21 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -38,6 +38,7 @@ #undef HELPER_H #define DISAS_EXIT DISAS_TARGET_0 +#define DISAS_EXIT_UPDATE DISAS_TARGET_1 /* * TCG registers @@ -7900,6 +7901,7 @@ static void decode_sys_interrupts(DisasContext *ctx) break; case OPC2_32_SYS_ENABLE: tcg_gen_ori_tl(cpu_ICR, cpu_ICR, ctx->icr_ie_mask); + ctx->base.is_jmp = DISAS_EXIT_UPDATE; break; case OPC2_32_SYS_ISYNC: break; @@ -8387,6 +8389,9 @@ static void tricore_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) case DISAS_TOO_MANY: gen_goto_tb(ctx, 0, ctx->base.pc_next); break; + case DISAS_EXIT_UPDATE: + gen_save_pc(ctx->base.pc_next); + /* fall through */ case DISAS_EXIT: tcg_gen_exit_tb(NULL, 0); break; From d8f466af7cad3a997c3f9d0396f2a63826fee239 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Wed, 21 Jun 2023 16:22:58 +0200 Subject: [PATCH 0016/1353] target/tricore: Indirect jump insns use tcg_gen_lookup_and_goto_ptr() Reviewed-by: Richard Henderson Signed-off-by: Bastian Koppelmann Message-Id: <20230621142302.1648383-5-kbastian@mail.uni-paderborn.de> --- target/tricore/translate.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/target/tricore/translate.c b/target/tricore/translate.c index 98e2767d21..fb6f0caa24 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -39,6 +39,7 @@ #define DISAS_EXIT DISAS_TARGET_0 #define DISAS_EXIT_UPDATE DISAS_TARGET_1 +#define DISAS_JUMP DISAS_TARGET_2 /* * TCG registers @@ -6077,8 +6078,9 @@ static void decode_rr_idirect(DisasContext *ctx) break; default: generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); + return; } - ctx->base.is_jmp = DISAS_EXIT; + ctx->base.is_jmp = DISAS_JUMP; } static void decode_rr_divide(DisasContext *ctx) @@ -8395,6 +8397,9 @@ static void tricore_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) case DISAS_EXIT: tcg_gen_exit_tb(NULL, 0); break; + case DISAS_JUMP: + tcg_gen_lookup_and_goto_ptr(); + break; case DISAS_NORETURN: break; default: From 878d1b6a90173d61859f1b5083266d2bbc3db17c Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Wed, 21 Jun 2023 16:22:59 +0200 Subject: [PATCH 0017/1353] target/tricore: Introduce priv tb flag Reviewed-by: Richard Henderson Signed-off-by: Bastian Koppelmann Message-Id: <20230621142302.1648383-6-kbastian@mail.uni-paderborn.de> --- target/tricore/cpu.h | 17 ++++++++++++----- target/tricore/translate.c | 14 ++++++++------ 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/target/tricore/cpu.h b/target/tricore/cpu.h index 041fc0b6e5..257fcf3cee 100644 --- a/target/tricore/cpu.h +++ b/target/tricore/cpu.h @@ -263,10 +263,11 @@ void icr_set_ie(CPUTriCoreState *env, uint32_t val); #define MASK_DBGSR_PEVT 0x40 #define MASK_DBGSR_EVTSRC 0x1f00 -#define TRICORE_HFLAG_KUU 0x3 -#define TRICORE_HFLAG_UM0 0x00002 /* user mode-0 flag */ -#define TRICORE_HFLAG_UM1 0x00001 /* user mode-1 flag */ -#define TRICORE_HFLAG_SM 0x00000 /* kernel mode flag */ +enum tricore_priv_levels { + TRICORE_PRIV_UM0 = 0x0, /* user mode-0 flag */ + TRICORE_PRIV_UM1 = 0x1, /* user mode-1 flag */ + TRICORE_PRIV_SM = 0x2, /* kernel mode flag */ +}; enum tricore_features { TRICORE_FEATURE_13, @@ -378,15 +379,21 @@ static inline int cpu_mmu_index(CPUTriCoreState *env, bool ifetch) #include "exec/cpu-all.h" +FIELD(TB_FLAGS, PRIV, 0, 2) + void cpu_state_reset(CPUTriCoreState *s); void tricore_tcg_init(void); static inline void cpu_get_tb_cpu_state(CPUTriCoreState *env, target_ulong *pc, target_ulong *cs_base, uint32_t *flags) { + uint32_t new_flags = 0; *pc = env->PC; *cs_base = 0; - *flags = 0; + + new_flags |= FIELD_DP32(new_flags, TB_FLAGS, PRIV, + extract32(env->PSW, 10, 2)); + *flags = new_flags; } #define TRICORE_CPU_TYPE_SUFFIX "-" TYPE_TRICORE_CPU diff --git a/target/tricore/translate.c b/target/tricore/translate.c index fb6f0caa24..6932a54663 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -76,7 +76,7 @@ typedef struct DisasContext { uint32_t opcode; /* Routine used to access memory */ int mem_idx; - uint32_t hflags, saved_hflags; + int priv; uint64_t features; uint32_t icr_ie_mask, icr_ie_offset; } DisasContext; @@ -378,7 +378,7 @@ static inline void gen_mfcr(DisasContext *ctx, TCGv ret, int32_t offset) static inline void gen_mtcr(DisasContext *ctx, TCGv r1, int32_t offset) { - if ((ctx->hflags & TRICORE_HFLAG_KUU) == TRICORE_HFLAG_SM) { + if (ctx->priv == TRICORE_PRIV_SM) { /* since we're caching PSW make this a special case */ if (offset == 0xfe04) { gen_helper_psw_write(cpu_env, r1); @@ -7920,7 +7920,7 @@ static void decode_sys_interrupts(DisasContext *ctx) ctx->base.is_jmp = DISAS_EXIT; break; case OPC2_32_SYS_RFM: - if ((ctx->hflags & TRICORE_HFLAG_KUU) == TRICORE_HFLAG_SM) { + if (ctx->priv == TRICORE_PRIV_SM) { tmp = tcg_temp_new(); l1 = gen_new_label(); @@ -7942,8 +7942,7 @@ static void decode_sys_interrupts(DisasContext *ctx) break; case OPC2_32_SYS_RESTORE: if (has_feature(ctx, TRICORE_FEATURE_16)) { - if ((ctx->hflags & TRICORE_HFLAG_KUU) == TRICORE_HFLAG_SM || - (ctx->hflags & TRICORE_HFLAG_KUU) == TRICORE_HFLAG_UM1) { + if (ctx->priv == TRICORE_PRIV_SM || ctx->priv == TRICORE_PRIV_UM1) { tcg_gen_deposit_tl(cpu_ICR, cpu_ICR, cpu_gpr_d[r1], 8, 1); } /* else raise privilege trap */ } else { @@ -8313,7 +8312,10 @@ static void tricore_tr_init_disas_context(DisasContextBase *dcbase, DisasContext *ctx = container_of(dcbase, DisasContext, base); CPUTriCoreState *env = cs->env_ptr; ctx->mem_idx = cpu_mmu_index(env, false); - ctx->hflags = (uint32_t)ctx->base.tb->flags; + + uint32_t tb_flags = (uint32_t)ctx->base.tb->flags; + ctx->priv = FIELD_EX32(tb_flags, TB_FLAGS, PRIV); + ctx->features = env->features; if (has_feature(ctx, TRICORE_FEATURE_161)) { ctx->icr_ie_mask = R_ICR_IE_161_MASK; From 57b9c589b621b40f3a81662ad1aa960ab6a60497 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Wed, 21 Jun 2023 16:23:00 +0200 Subject: [PATCH 0018/1353] target/tricore: Implement privilege level for all insns Reviewed-by: Richard Henderson Signed-off-by: Bastian Koppelmann Message-Id: <20230621142302.1648383-7-kbastian@mail.uni-paderborn.de> --- target/tricore/translate.c | 43 +++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/target/tricore/translate.c b/target/tricore/translate.c index 6932a54663..82b61e912e 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -388,7 +388,7 @@ static inline void gen_mtcr(DisasContext *ctx, TCGv r1, } } } else { - /* generate privilege trap */ + generate_trap(ctx, TRAPC_PROT, TIN1_PRIV); } } @@ -3375,7 +3375,11 @@ static void decode_sc_opc(DisasContext *ctx, int op1) tcg_gen_andi_tl(cpu_gpr_d[15], cpu_gpr_d[15], const16); break; case OPC1_16_SC_BISR: - gen_helper_1arg(bisr, const16 & 0xff); + if (ctx->priv == TRICORE_PRIV_SM) { + gen_helper_1arg(bisr, const16 & 0xff); + } else { + generate_trap(ctx, TRAPC_PROT, TIN1_PRIV); + } break; case OPC1_16_SC_LD_A: gen_offset_ld(ctx, cpu_gpr_a[15], cpu_gpr_a[10], const16 * 4, MO_LESL); @@ -5236,7 +5240,11 @@ static void decode_rc_serviceroutine(DisasContext *ctx) switch (op2) { case OPC2_32_RC_BISR: - gen_helper_1arg(bisr, const9); + if (ctx->priv == TRICORE_PRIV_SM) { + gen_helper_1arg(bisr, const9); + } else { + generate_trap(ctx, TRAPC_PROT, TIN1_PRIV); + } break; case OPC2_32_RC_SYSCALL: generate_trap(ctx, TRAPC_SYSCALL, const9 & 0xff); @@ -7890,20 +7898,33 @@ static void decode_sys_interrupts(DisasContext *ctx) /* raise EXCP_DEBUG */ break; case OPC2_32_SYS_DISABLE: - tcg_gen_andi_tl(cpu_ICR, cpu_ICR, ~ctx->icr_ie_mask); + if (ctx->priv == TRICORE_PRIV_SM || ctx->priv == TRICORE_PRIV_UM1) { + tcg_gen_andi_tl(cpu_ICR, cpu_ICR, ~ctx->icr_ie_mask); + } else { + generate_trap(ctx, TRAPC_PROT, TIN1_PRIV); + } break; case OPC2_32_SYS_DISABLE_D: if (has_feature(ctx, TRICORE_FEATURE_16)) { - tcg_gen_extract_tl(cpu_gpr_d[r1], cpu_ICR, ctx->icr_ie_offset, 1); - tcg_gen_andi_tl(cpu_ICR, cpu_ICR, ~ctx->icr_ie_mask); + if (ctx->priv == TRICORE_PRIV_SM || ctx->priv == TRICORE_PRIV_UM1) { + tcg_gen_extract_tl(cpu_gpr_d[r1], cpu_ICR, + ctx->icr_ie_offset, 1); + tcg_gen_andi_tl(cpu_ICR, cpu_ICR, ~ctx->icr_ie_mask); + } else { + generate_trap(ctx, TRAPC_PROT, TIN1_PRIV); + } } else { generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } case OPC2_32_SYS_DSYNC: break; case OPC2_32_SYS_ENABLE: - tcg_gen_ori_tl(cpu_ICR, cpu_ICR, ctx->icr_ie_mask); - ctx->base.is_jmp = DISAS_EXIT_UPDATE; + if (ctx->priv == TRICORE_PRIV_SM || ctx->priv == TRICORE_PRIV_UM1) { + tcg_gen_ori_tl(cpu_ICR, cpu_ICR, ctx->icr_ie_mask); + ctx->base.is_jmp = DISAS_EXIT_UPDATE; + } else { + generate_trap(ctx, TRAPC_PROT, TIN1_PRIV); + } break; case OPC2_32_SYS_ISYNC: break; @@ -7931,7 +7952,7 @@ static void decode_sys_interrupts(DisasContext *ctx) gen_set_label(l1); ctx->base.is_jmp = DISAS_EXIT; } else { - /* generate privilege trap */ + generate_trap(ctx, TRAPC_PROT, TIN1_PRIV); } break; case OPC2_32_SYS_RSLCX: @@ -7944,7 +7965,9 @@ static void decode_sys_interrupts(DisasContext *ctx) if (has_feature(ctx, TRICORE_FEATURE_16)) { if (ctx->priv == TRICORE_PRIV_SM || ctx->priv == TRICORE_PRIV_UM1) { tcg_gen_deposit_tl(cpu_ICR, cpu_ICR, cpu_gpr_d[r1], 8, 1); - } /* else raise privilege trap */ + } else { + generate_trap(ctx, TRAPC_PROT, TIN1_PRIV); + } } else { generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC); } From 19a18edd8860064d3dbe71bc5315347bcfeb4c24 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Wed, 21 Jun 2023 16:23:01 +0200 Subject: [PATCH 0019/1353] target/tricore: Honour privilege changes on PSW write the CPU can change the privilege level by writing the corresponding bits in PSW. If this happens all instructions after this 'mtcr' in the TB are translated with the wrong privilege level. So we have to exit to the cpu_loop() and start translating again with the new privilege level. Reviewed-by: Richard Henderson Signed-off-by: Bastian Koppelmann Message-Id: <20230621142302.1648383-8-kbastian@mail.uni-paderborn.de> --- target/tricore/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/tricore/translate.c b/target/tricore/translate.c index 82b61e912e..9e408f44ec 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -334,7 +334,6 @@ static void gen_swapmsk(DisasContext *ctx, int reg, TCGv ea) tcg_gen_mov_tl(cpu_gpr_d[reg], temp); } - /* We generate loads and store to core special function register (csfr) through the function gen_mfcr and gen_mtcr. To handle access permissions, we use 3 makros R, A and E, which allow read-only, all and endinit protected access. @@ -382,6 +381,7 @@ static inline void gen_mtcr(DisasContext *ctx, TCGv r1, /* since we're caching PSW make this a special case */ if (offset == 0xfe04) { gen_helper_psw_write(cpu_env, r1); + ctx->base.is_jmp = DISAS_EXIT_UPDATE; } else { switch (offset) { #include "csfr.h.inc" From a9c37abdff65a07d0191123a21d318c4d8cc7f33 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Wed, 21 Jun 2023 16:23:02 +0200 Subject: [PATCH 0020/1353] target/tricore: Fix ICR.IE offset in RESTORE insn from ISA v1.6.1 onwards the bit position of ICR.IE changed. ctx->icr_ie_offset contains the correct value for the ISA version used by the vCPU. We also need to exit this tb here, as we might have enabled interrupts. Reviewed-by: Richard Henderson Signed-off-by: Bastian Koppelmann Message-Id: <20230621142302.1648383-9-kbastian@mail.uni-paderborn.de> --- target/tricore/translate.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/target/tricore/translate.c b/target/tricore/translate.c index 9e408f44ec..2f32463d4d 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -7964,7 +7964,9 @@ static void decode_sys_interrupts(DisasContext *ctx) case OPC2_32_SYS_RESTORE: if (has_feature(ctx, TRICORE_FEATURE_16)) { if (ctx->priv == TRICORE_PRIV_SM || ctx->priv == TRICORE_PRIV_UM1) { - tcg_gen_deposit_tl(cpu_ICR, cpu_ICR, cpu_gpr_d[r1], 8, 1); + tcg_gen_deposit_tl(cpu_ICR, cpu_ICR, cpu_gpr_d[r1], + ctx->icr_ie_offset, 1); + ctx->base.is_jmp = DISAS_EXIT_UPDATE; } else { generate_trap(ctx, TRAPC_PROT, TIN1_PRIV); } From 26fcbf00226115bc58cf5bf3c6d3aa24d5d9b01c Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 21 Jun 2023 09:53:30 +0100 Subject: [PATCH 0021/1353] q800: fix up minor spacing issues in hw_compat_q800 GlobalProperty array MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ensure there is a space before the final closing brace for all global properties. Signed-off-by: Mark Cave-Ayland Reviewed-by: Laurent Vivier Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230621085353.113233-2-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/m68k/q800.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 68f0cd8cac..dda57c60bf 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -719,14 +719,14 @@ static void q800_init(MachineState *machine) } static GlobalProperty hw_compat_q800[] = { - { "scsi-hd", "quirk_mode_page_vendor_specific_apple", "on"}, + { "scsi-hd", "quirk_mode_page_vendor_specific_apple", "on" }, { "scsi-hd", "vendor", " SEAGATE" }, { "scsi-hd", "product", " ST225N" }, { "scsi-hd", "ver", "1.0 " }, - { "scsi-cd", "quirk_mode_page_apple_vendor", "on"}, - { "scsi-cd", "quirk_mode_sense_rom_use_dbd", "on"}, - { "scsi-cd", "quirk_mode_page_vendor_specific_apple", "on"}, - { "scsi-cd", "quirk_mode_page_truncated", "on"}, + { "scsi-cd", "quirk_mode_page_apple_vendor", "on" }, + { "scsi-cd", "quirk_mode_sense_rom_use_dbd", "on" }, + { "scsi-cd", "quirk_mode_page_vendor_specific_apple", "on" }, + { "scsi-cd", "quirk_mode_page_truncated", "on" }, { "scsi-cd", "vendor", "MATSHITA" }, { "scsi-cd", "product", "CD-ROM CR-8005" }, { "scsi-cd", "ver", "1.0k" }, From cbba124319812657975ba0bcd17dbf6793494884 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 21 Jun 2023 09:53:31 +0100 Subject: [PATCH 0022/1353] q800: add missing space after parent object in GLUEState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This brings GLUEState in line with our current QOM guidelines. Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Laurent Vivier Message-Id: <20230621085353.113233-3-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/m68k/q800.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index dda57c60bf..465c510c18 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -100,6 +100,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(GLUEState, GLUE) struct GLUEState { SysBusDevice parent_obj; + M68kCPU *cpu; uint8_t ipr; uint8_t auxmode; From a8019229c489a51508099d38ec54e035dee94234 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 21 Jun 2023 09:53:32 +0100 Subject: [PATCH 0023/1353] q800: introduce Q800MachineState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This provides an overall container and owner for Machine-related objects such as MemoryRegions. Signed-off-by: Mark Cave-Ayland Reviewed-by: Laurent Vivier Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230621085353.113233-4-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- MAINTAINERS | 1 + hw/m68k/q800.c | 2 ++ include/hw/m68k/q800.h | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 include/hw/m68k/q800.h diff --git a/MAINTAINERS b/MAINTAINERS index 88b5a7ee0a..748a66fbaa 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1236,6 +1236,7 @@ F: include/hw/misc/mac_via.h F: include/hw/nubus/* F: include/hw/display/macfb.h F: include/hw/block/swim.h +F: include/hw/m68k/q800.h virt M: Laurent Vivier diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 465c510c18..c0256c8a90 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -38,6 +38,7 @@ #include "standard-headers/asm-m68k/bootinfo.h" #include "standard-headers/asm-m68k/bootinfo-mac.h" #include "bootinfo.h" +#include "hw/m68k/q800.h" #include "hw/misc/mac_via.h" #include "hw/input/adb.h" #include "hw/nubus/mac-nubus-bridge.h" @@ -749,6 +750,7 @@ static void q800_machine_class_init(ObjectClass *oc, void *data) static const TypeInfo q800_machine_typeinfo = { .name = MACHINE_TYPE_NAME("q800"), .parent = TYPE_MACHINE, + .instance_size = sizeof(Q800MachineState), .class_init = q800_machine_class_init, }; diff --git a/include/hw/m68k/q800.h b/include/hw/m68k/q800.h new file mode 100644 index 0000000000..f3bc17aa1b --- /dev/null +++ b/include/hw/m68k/q800.h @@ -0,0 +1,40 @@ +/* + * QEMU Motorla 680x0 Macintosh hardware System Emulator + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HW_Q800_H +#define HW_Q800_H + +#include "hw/boards.h" +#include "qom/object.h" + +/* + * The main Q800 machine + */ + +struct Q800MachineState { + MachineState parent_obj; +}; + +#define TYPE_Q800_MACHINE MACHINE_TYPE_NAME("q800") +OBJECT_DECLARE_SIMPLE_TYPE(Q800MachineState, Q800_MACHINE) + +#endif From 1a514d3a8a9b058701f0b8693067e44b08e924f2 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 21 Jun 2023 09:53:33 +0100 Subject: [PATCH 0024/1353] q800: rename q800_init() to q800_machine_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will enable us later to distinguish between QOM initialisation and machine initialisation. Signed-off-by: Mark Cave-Ayland Reviewed-by: Laurent Vivier Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230621085353.113233-5-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/m68k/q800.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index c0256c8a90..062a3c6c76 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -362,7 +362,7 @@ static uint8_t fake_mac_rom[] = { 0x60, 0xFE /* bras [self] */ }; -static void q800_init(MachineState *machine) +static void q800_machine_init(MachineState *machine) { M68kCPU *cpu = NULL; int linux_boot; @@ -738,8 +738,9 @@ static const size_t hw_compat_q800_len = G_N_ELEMENTS(hw_compat_q800); static void q800_machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); + mc->desc = "Macintosh Quadra 800"; - mc->init = q800_init; + mc->init = q800_machine_init; mc->default_cpu_type = M68K_CPU_TYPE_NAME("m68040"); mc->max_cpus = 1; mc->block_default_type = IF_SCSI; From 36e2e338b34e9ac6b86102ef81571277613903e2 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 21 Jun 2023 09:53:34 +0100 Subject: [PATCH 0025/1353] q800: move CPU object into Q800MachineState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also change the instantiation of the CPU to use object_initialize_child() followed by a separate realisation. Restrict valid CPU types to m68040. Signed-off-by: Mark Cave-Ayland Reviewed-by: Laurent Vivier Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230621085353.113233-6-mark.cave-ayland@ilande.co.uk> [lv: update commit message] Signed-off-by: Laurent Vivier --- hw/m68k/q800.c | 18 +++++++++++++----- include/hw/m68k/q800.h | 3 +++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 062a3c6c76..2b651de3c1 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -364,7 +364,7 @@ static uint8_t fake_mac_rom[] = { static void q800_machine_init(MachineState *machine) { - M68kCPU *cpu = NULL; + Q800MachineState *m = Q800_MACHINE(machine); int linux_boot; int32_t kernel_size; uint64_t elf_entry; @@ -407,8 +407,9 @@ static void q800_machine_init(MachineState *machine) } /* init CPUs */ - cpu = M68K_CPU(cpu_create(machine->cpu_type)); - qemu_register_reset(main_cpu_reset, cpu); + object_initialize_child(OBJECT(machine), "cpu", &m->cpu, machine->cpu_type); + qdev_realize(DEVICE(&m->cpu), NULL, &error_fatal); + qemu_register_reset(main_cpu_reset, &m->cpu); /* RAM */ memory_region_add_subregion(get_system_memory(), 0, machine->ram); @@ -430,7 +431,8 @@ static void q800_machine_init(MachineState *machine) /* IRQ Glue */ glue = qdev_new(TYPE_GLUE); - object_property_set_link(OBJECT(glue), "cpu", OBJECT(cpu), &error_abort); + object_property_set_link(OBJECT(glue), "cpu", OBJECT(&m->cpu), + &error_abort); sysbus_realize_and_unref(SYS_BUS_DEVICE(glue), &error_fatal); /* VIA 1 */ @@ -605,7 +607,7 @@ static void q800_machine_init(MachineState *machine) macfb_mode = (NUBUS_MACFB(dev)->macfb).mode; - cs = CPU(cpu); + cs = CPU(&m->cpu); if (linux_boot) { uint64_t high; void *param_blob, *param_ptr, *param_rng_seed; @@ -735,6 +737,11 @@ static GlobalProperty hw_compat_q800[] = { }; static const size_t hw_compat_q800_len = G_N_ELEMENTS(hw_compat_q800); +static const char *q800_machine_valid_cpu_types[] = { + M68K_CPU_TYPE_NAME("m68040"), + NULL +}; + static void q800_machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -742,6 +749,7 @@ static void q800_machine_class_init(ObjectClass *oc, void *data) mc->desc = "Macintosh Quadra 800"; mc->init = q800_machine_init; mc->default_cpu_type = M68K_CPU_TYPE_NAME("m68040"); + mc->valid_cpu_types = q800_machine_valid_cpu_types; mc->max_cpus = 1; mc->block_default_type = IF_SCSI; mc->default_ram_id = "m68k_mac.ram"; diff --git a/include/hw/m68k/q800.h b/include/hw/m68k/q800.h index f3bc17aa1b..4cb1a51dfe 100644 --- a/include/hw/m68k/q800.h +++ b/include/hw/m68k/q800.h @@ -25,6 +25,7 @@ #include "hw/boards.h" #include "qom/object.h" +#include "target/m68k/cpu-qom.h" /* * The main Q800 machine @@ -32,6 +33,8 @@ struct Q800MachineState { MachineState parent_obj; + + M68kCPU cpu; }; #define TYPE_Q800_MACHINE MACHINE_TYPE_NAME("q800") From 0b9b41fb8b4879d4dd3d2ce0a13493541c2d8d66 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 21 Jun 2023 09:53:35 +0100 Subject: [PATCH 0026/1353] q800: move ROM memory region to Q800MachineState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Laurent Vivier Message-Id: <20230621085353.113233-7-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/m68k/q800.c | 13 +++++-------- include/hw/m68k/q800.h | 2 ++ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 2b651de3c1..9f9668c2b4 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -372,7 +372,6 @@ static void q800_machine_init(MachineState *machine) int bios_size; ram_addr_t initrd_base; int32_t initrd_size; - MemoryRegion *rom; MemoryRegion *io; MemoryRegion *dp8393x_prom = g_new(MemoryRegion, 1); uint8_t *prom; @@ -646,11 +645,10 @@ static void q800_machine_init(MachineState *machine) BOOTINFO1(param_ptr, BI_MAC_VROW, macfb_mode->stride); BOOTINFO1(param_ptr, BI_MAC_SCCBASE, SCC_BASE); - rom = g_malloc(sizeof(*rom)); - memory_region_init_ram_ptr(rom, NULL, "m68k_fake_mac.rom", + memory_region_init_ram_ptr(&m->rom, NULL, "m68k_fake_mac.rom", sizeof(fake_mac_rom), fake_mac_rom); - memory_region_set_readonly(rom, true); - memory_region_add_subregion(get_system_memory(), MACROM_ADDR, rom); + memory_region_set_readonly(&m->rom, true); + memory_region_add_subregion(get_system_memory(), MACROM_ADDR, &m->rom); if (kernel_cmdline) { BOOTINFOSTR(param_ptr, BI_COMMAND_LINE, @@ -692,11 +690,10 @@ static void q800_machine_init(MachineState *machine) } else { uint8_t *ptr; /* allocate and load BIOS */ - rom = g_malloc(sizeof(*rom)); - memory_region_init_rom(rom, NULL, "m68k_mac.rom", MACROM_SIZE, + memory_region_init_rom(&m->rom, NULL, "m68k_mac.rom", MACROM_SIZE, &error_abort); filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); - memory_region_add_subregion(get_system_memory(), MACROM_ADDR, rom); + memory_region_add_subregion(get_system_memory(), MACROM_ADDR, &m->rom); /* Load MacROM binary */ if (filename) { diff --git a/include/hw/m68k/q800.h b/include/hw/m68k/q800.h index 4cb1a51dfe..d1f1ae4b88 100644 --- a/include/hw/m68k/q800.h +++ b/include/hw/m68k/q800.h @@ -26,6 +26,7 @@ #include "hw/boards.h" #include "qom/object.h" #include "target/m68k/cpu-qom.h" +#include "exec/memory.h" /* * The main Q800 machine @@ -35,6 +36,7 @@ struct Q800MachineState { MachineState parent_obj; M68kCPU cpu; + MemoryRegion rom; }; #define TYPE_Q800_MACHINE MACHINE_TYPE_NAME("q800") From 8e0932802f5fd6d8c5c12080d144f01b09863c3c Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 21 Jun 2023 09:53:36 +0100 Subject: [PATCH 0027/1353] q800: move GLUE device into separate q800-glue.c file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will allow the q800-glue.h header to be included separately so that the GLUE device can be referenced externally. Signed-off-by: Mark Cave-Ayland Reviewed-by: Laurent Vivier Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230621085353.113233-8-mark.cave-ayland@ilande.co.uk> [lv: update comment] Signed-off-by: Laurent Vivier --- MAINTAINERS | 2 + hw/m68k/meson.build | 2 +- hw/m68k/q800-glue.c | 252 ++++++++++++++++++++++++++++++++++++ hw/m68k/q800.c | 238 +--------------------------------- include/hw/m68k/q800-glue.h | 50 +++++++ 5 files changed, 306 insertions(+), 238 deletions(-) create mode 100644 hw/m68k/q800-glue.c create mode 100644 include/hw/m68k/q800-glue.h diff --git a/MAINTAINERS b/MAINTAINERS index 748a66fbaa..7f323cd2eb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1225,6 +1225,7 @@ q800 M: Laurent Vivier S: Maintained F: hw/m68k/q800.c +F: hw/m68k/q800-glue.c F: hw/misc/mac_via.c F: hw/nubus/* F: hw/display/macfb.c @@ -1237,6 +1238,7 @@ F: include/hw/nubus/* F: include/hw/display/macfb.h F: include/hw/block/swim.h F: include/hw/m68k/q800.h +F: include/hw/m68k/q800-glue.h virt M: Laurent Vivier diff --git a/hw/m68k/meson.build b/hw/m68k/meson.build index 31248641d3..84bc68fa4e 100644 --- a/hw/m68k/meson.build +++ b/hw/m68k/meson.build @@ -2,7 +2,7 @@ m68k_ss = ss.source_set() m68k_ss.add(when: 'CONFIG_AN5206', if_true: files('an5206.c', 'mcf5206.c')) m68k_ss.add(when: 'CONFIG_MCF5208', if_true: files('mcf5208.c', 'mcf_intc.c')) m68k_ss.add(when: 'CONFIG_NEXTCUBE', if_true: files('next-kbd.c', 'next-cube.c')) -m68k_ss.add(when: 'CONFIG_Q800', if_true: files('q800.c')) +m68k_ss.add(when: 'CONFIG_Q800', if_true: files('q800.c', 'q800-glue.c')) m68k_ss.add(when: 'CONFIG_M68K_VIRT', if_true: files('virt.c')) hw_arch += {'m68k': m68k_ss} diff --git a/hw/m68k/q800-glue.c b/hw/m68k/q800-glue.c new file mode 100644 index 0000000000..e81f9438f1 --- /dev/null +++ b/hw/m68k/q800-glue.c @@ -0,0 +1,252 @@ +/* + * QEMU q800 logic GLUE (General Logic Unit) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "hw/m68k/q800-glue.h" +#include "hw/boards.h" +#include "hw/irq.h" +#include "hw/nmi.h" +#include "hw/qdev-properties.h" +#include "migration/vmstate.h" + +/* + * The GLUE (General Logic Unit) is an Apple custom integrated circuit chip + * that performs a variety of functions (RAM management, clock generation, ...). + * The GLUE chip receives interrupt requests from various devices, + * assign priority to each, and asserts one or more interrupt line to the + * CPU. + */ + +/* + * The GLUE logic on the Quadra 800 supports 2 different IRQ routing modes + * controlled from the VIA1 auxmode GPIO (port B bit 6) which are documented + * in NetBSD as follows: + * + * A/UX mode (Linux, NetBSD, auxmode GPIO low) + * + * Level 0: Spurious: ignored + * Level 1: Software + * Level 2: VIA2 (except ethernet, sound) + * Level 3: Ethernet + * Level 4: Serial (SCC) + * Level 5: Sound + * Level 6: VIA1 + * Level 7: NMIs: parity errors, RESET button, YANCC error + * + * Classic mode (default: used by MacOS, A/UX 3.0.1, auxmode GPIO high) + * + * Level 0: Spurious: ignored + * Level 1: VIA1 (clock, ADB) + * Level 2: VIA2 (NuBus, SCSI) + * Level 3: + * Level 4: Serial (SCC) + * Level 5: + * Level 6: + * Level 7: Non-maskable: parity errors, RESET button + * + * Note that despite references to A/UX mode in Linux and NetBSD, at least + * A/UX 3.0.1 still uses Classic mode. + */ + +static void GLUE_set_irq(void *opaque, int irq, int level) +{ + GLUEState *s = opaque; + int i; + + if (s->auxmode) { + /* Classic mode */ + switch (irq) { + case GLUE_IRQ_IN_VIA1: + irq = 0; + break; + + case GLUE_IRQ_IN_VIA2: + irq = 1; + break; + + case GLUE_IRQ_IN_SONIC: + /* Route to VIA2 instead */ + qemu_set_irq(s->irqs[GLUE_IRQ_NUBUS_9], level); + return; + + case GLUE_IRQ_IN_ESCC: + irq = 3; + break; + + case GLUE_IRQ_IN_NMI: + irq = 6; + break; + + default: + g_assert_not_reached(); + } + } else { + /* A/UX mode */ + switch (irq) { + case GLUE_IRQ_IN_VIA1: + irq = 5; + break; + + case GLUE_IRQ_IN_VIA2: + irq = 1; + break; + + case GLUE_IRQ_IN_SONIC: + irq = 2; + break; + + case GLUE_IRQ_IN_ESCC: + irq = 3; + break; + + case GLUE_IRQ_IN_NMI: + irq = 6; + break; + + default: + g_assert_not_reached(); + } + } + + if (level) { + s->ipr |= 1 << irq; + } else { + s->ipr &= ~(1 << irq); + } + + for (i = 7; i >= 0; i--) { + if ((s->ipr >> i) & 1) { + m68k_set_irq_level(s->cpu, i + 1, i + 25); + return; + } + } + m68k_set_irq_level(s->cpu, 0, 0); +} + +static void glue_auxmode_set_irq(void *opaque, int irq, int level) +{ + GLUEState *s = GLUE(opaque); + + s->auxmode = level; +} + +static void glue_nmi(NMIState *n, int cpu_index, Error **errp) +{ + GLUEState *s = GLUE(n); + + /* Hold NMI active for 100ms */ + GLUE_set_irq(s, GLUE_IRQ_IN_NMI, 1); + timer_mod(s->nmi_release, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 100); +} + +static void glue_nmi_release(void *opaque) +{ + GLUEState *s = GLUE(opaque); + + GLUE_set_irq(s, GLUE_IRQ_IN_NMI, 0); +} + +static void glue_reset(DeviceState *dev) +{ + GLUEState *s = GLUE(dev); + + s->ipr = 0; + s->auxmode = 0; + + timer_del(s->nmi_release); +} + +static const VMStateDescription vmstate_glue = { + .name = "q800-glue", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT8(ipr, GLUEState), + VMSTATE_UINT8(auxmode, GLUEState), + VMSTATE_TIMER_PTR(nmi_release, GLUEState), + VMSTATE_END_OF_LIST(), + }, +}; + +/* + * If the m68k CPU implemented its inbound irq lines as GPIO lines + * rather than via the m68k_set_irq_level() function we would not need + * this cpu link property and could instead provide outbound IRQ lines + * that the board could wire up to the CPU. + */ +static Property glue_properties[] = { + DEFINE_PROP_LINK("cpu", GLUEState, cpu, TYPE_M68K_CPU, M68kCPU *), + DEFINE_PROP_END_OF_LIST(), +}; + +static void glue_finalize(Object *obj) +{ + GLUEState *s = GLUE(obj); + + timer_free(s->nmi_release); +} + +static void glue_init(Object *obj) +{ + DeviceState *dev = DEVICE(obj); + GLUEState *s = GLUE(dev); + + qdev_init_gpio_in(dev, GLUE_set_irq, 8); + qdev_init_gpio_in_named(dev, glue_auxmode_set_irq, "auxmode", 1); + + qdev_init_gpio_out(dev, s->irqs, 1); + + /* NMI release timer */ + s->nmi_release = timer_new_ms(QEMU_CLOCK_VIRTUAL, glue_nmi_release, s); +} + +static void glue_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + NMIClass *nc = NMI_CLASS(klass); + + dc->vmsd = &vmstate_glue; + dc->reset = glue_reset; + device_class_set_props(dc, glue_properties); + nc->nmi_monitor_handler = glue_nmi; +} + +static const TypeInfo glue_info = { + .name = TYPE_GLUE, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(GLUEState), + .instance_init = glue_init, + .instance_finalize = glue_finalize, + .class_init = glue_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_NMI }, + { } + }, +}; + +static void glue_register_types(void) +{ + type_register_static(&glue_info); +} + +type_init(glue_register_types) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 9f9668c2b4..9f9de2ebaf 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -28,7 +28,6 @@ #include "cpu.h" #include "hw/boards.h" #include "hw/or-irq.h" -#include "hw/nmi.h" #include "elf.h" #include "hw/loader.h" #include "ui/console.h" @@ -39,6 +38,7 @@ #include "standard-headers/asm-m68k/bootinfo-mac.h" #include "bootinfo.h" #include "hw/m68k/q800.h" +#include "hw/m68k/q800-glue.h" #include "hw/misc/mac_via.h" #include "hw/input/adb.h" #include "hw/nubus/mac-nubus-bridge.h" @@ -88,241 +88,6 @@ #define Q800_NUBUS_SLOTS_AVAILABLE (BIT(0x9) | BIT(0xc) | BIT(0xd) | \ BIT(0xe)) -/* - * The GLUE (General Logic Unit) is an Apple custom integrated circuit chip - * that performs a variety of functions (RAM management, clock generation, ...). - * The GLUE chip receives interrupt requests from various devices, - * assign priority to each, and asserts one or more interrupt line to the - * CPU. - */ - -#define TYPE_GLUE "q800-glue" -OBJECT_DECLARE_SIMPLE_TYPE(GLUEState, GLUE) - -struct GLUEState { - SysBusDevice parent_obj; - - M68kCPU *cpu; - uint8_t ipr; - uint8_t auxmode; - qemu_irq irqs[1]; - QEMUTimer *nmi_release; -}; - -#define GLUE_IRQ_IN_VIA1 0 -#define GLUE_IRQ_IN_VIA2 1 -#define GLUE_IRQ_IN_SONIC 2 -#define GLUE_IRQ_IN_ESCC 3 -#define GLUE_IRQ_IN_NMI 4 - -#define GLUE_IRQ_NUBUS_9 0 - -/* - * The GLUE logic on the Quadra 800 supports 2 different IRQ routing modes - * controlled from the VIA1 auxmode GPIO (port B bit 6) which are documented - * in NetBSD as follows: - * - * A/UX mode (Linux, NetBSD, auxmode GPIO low) - * - * Level 0: Spurious: ignored - * Level 1: Software - * Level 2: VIA2 (except ethernet, sound) - * Level 3: Ethernet - * Level 4: Serial (SCC) - * Level 5: Sound - * Level 6: VIA1 - * Level 7: NMIs: parity errors, RESET button, YANCC error - * - * Classic mode (default: used by MacOS, A/UX 3.0.1, auxmode GPIO high) - * - * Level 0: Spurious: ignored - * Level 1: VIA1 (clock, ADB) - * Level 2: VIA2 (NuBus, SCSI) - * Level 3: - * Level 4: Serial (SCC) - * Level 5: - * Level 6: - * Level 7: Non-maskable: parity errors, RESET button - * - * Note that despite references to A/UX mode in Linux and NetBSD, at least - * A/UX 3.0.1 still uses Classic mode. - */ - -static void GLUE_set_irq(void *opaque, int irq, int level) -{ - GLUEState *s = opaque; - int i; - - if (s->auxmode) { - /* Classic mode */ - switch (irq) { - case GLUE_IRQ_IN_VIA1: - irq = 0; - break; - - case GLUE_IRQ_IN_VIA2: - irq = 1; - break; - - case GLUE_IRQ_IN_SONIC: - /* Route to VIA2 instead */ - qemu_set_irq(s->irqs[GLUE_IRQ_NUBUS_9], level); - return; - - case GLUE_IRQ_IN_ESCC: - irq = 3; - break; - - case GLUE_IRQ_IN_NMI: - irq = 6; - break; - - default: - g_assert_not_reached(); - } - } else { - /* A/UX mode */ - switch (irq) { - case GLUE_IRQ_IN_VIA1: - irq = 5; - break; - - case GLUE_IRQ_IN_VIA2: - irq = 1; - break; - - case GLUE_IRQ_IN_SONIC: - irq = 2; - break; - - case GLUE_IRQ_IN_ESCC: - irq = 3; - break; - - case GLUE_IRQ_IN_NMI: - irq = 6; - break; - - default: - g_assert_not_reached(); - } - } - - if (level) { - s->ipr |= 1 << irq; - } else { - s->ipr &= ~(1 << irq); - } - - for (i = 7; i >= 0; i--) { - if ((s->ipr >> i) & 1) { - m68k_set_irq_level(s->cpu, i + 1, i + 25); - return; - } - } - m68k_set_irq_level(s->cpu, 0, 0); -} - -static void glue_auxmode_set_irq(void *opaque, int irq, int level) -{ - GLUEState *s = GLUE(opaque); - - s->auxmode = level; -} - -static void glue_nmi(NMIState *n, int cpu_index, Error **errp) -{ - GLUEState *s = GLUE(n); - - /* Hold NMI active for 100ms */ - GLUE_set_irq(s, GLUE_IRQ_IN_NMI, 1); - timer_mod(s->nmi_release, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 100); -} - -static void glue_nmi_release(void *opaque) -{ - GLUEState *s = GLUE(opaque); - - GLUE_set_irq(s, GLUE_IRQ_IN_NMI, 0); -} - -static void glue_reset(DeviceState *dev) -{ - GLUEState *s = GLUE(dev); - - s->ipr = 0; - s->auxmode = 0; - - timer_del(s->nmi_release); -} - -static const VMStateDescription vmstate_glue = { - .name = "q800-glue", - .version_id = 0, - .minimum_version_id = 0, - .fields = (VMStateField[]) { - VMSTATE_UINT8(ipr, GLUEState), - VMSTATE_UINT8(auxmode, GLUEState), - VMSTATE_TIMER_PTR(nmi_release, GLUEState), - VMSTATE_END_OF_LIST(), - }, -}; - -/* - * If the m68k CPU implemented its inbound irq lines as GPIO lines - * rather than via the m68k_set_irq_level() function we would not need - * this cpu link property and could instead provide outbound IRQ lines - * that the board could wire up to the CPU. - */ -static Property glue_properties[] = { - DEFINE_PROP_LINK("cpu", GLUEState, cpu, TYPE_M68K_CPU, M68kCPU *), - DEFINE_PROP_END_OF_LIST(), -}; - -static void glue_finalize(Object *obj) -{ - GLUEState *s = GLUE(obj); - - timer_free(s->nmi_release); -} - -static void glue_init(Object *obj) -{ - DeviceState *dev = DEVICE(obj); - GLUEState *s = GLUE(dev); - - qdev_init_gpio_in(dev, GLUE_set_irq, 8); - qdev_init_gpio_in_named(dev, glue_auxmode_set_irq, "auxmode", 1); - - qdev_init_gpio_out(dev, s->irqs, 1); - - /* NMI release timer */ - s->nmi_release = timer_new_ms(QEMU_CLOCK_VIRTUAL, glue_nmi_release, s); -} - -static void glue_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - NMIClass *nc = NMI_CLASS(klass); - - dc->vmsd = &vmstate_glue; - dc->reset = glue_reset; - device_class_set_props(dc, glue_properties); - nc->nmi_monitor_handler = glue_nmi; -} - -static const TypeInfo glue_info = { - .name = TYPE_GLUE, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(GLUEState), - .instance_init = glue_init, - .instance_finalize = glue_finalize, - .class_init = glue_class_init, - .interfaces = (InterfaceInfo[]) { - { TYPE_NMI }, - { } - }, -}; static void main_cpu_reset(void *opaque) { @@ -763,7 +528,6 @@ static const TypeInfo q800_machine_typeinfo = { static void q800_machine_register_types(void) { type_register_static(&q800_machine_typeinfo); - type_register_static(&glue_info); } type_init(q800_machine_register_types) diff --git a/include/hw/m68k/q800-glue.h b/include/hw/m68k/q800-glue.h new file mode 100644 index 0000000000..a35efc1c53 --- /dev/null +++ b/include/hw/m68k/q800-glue.h @@ -0,0 +1,50 @@ +/* + * QEMU q800 logic GLUE (General Logic Unit) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HW_Q800_GLUE_H +#define HW_Q800_GLUE_H + +#include "qemu/osdep.h" +#include "hw/sysbus.h" + +#define TYPE_GLUE "q800-glue" +OBJECT_DECLARE_SIMPLE_TYPE(GLUEState, GLUE) + +struct GLUEState { + SysBusDevice parent_obj; + + M68kCPU *cpu; + uint8_t ipr; + uint8_t auxmode; + qemu_irq irqs[1]; + QEMUTimer *nmi_release; +}; + +#define GLUE_IRQ_IN_VIA1 0 +#define GLUE_IRQ_IN_VIA2 1 +#define GLUE_IRQ_IN_SONIC 2 +#define GLUE_IRQ_IN_ESCC 3 +#define GLUE_IRQ_IN_NMI 4 + +#define GLUE_IRQ_NUBUS_9 0 + +#endif From 101b4764c7312dff04db8bf277eda875f7c00fa3 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 21 Jun 2023 09:53:37 +0100 Subject: [PATCH 0028/1353] q800-glue.c: switch TypeInfo registration to use DEFINE_TYPES() macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The use of the DEFINE_TYPES() macro will soon be recommended over the use of calling type_init() directly. Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230621085353.113233-9-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/m68k/q800-glue.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/hw/m68k/q800-glue.c b/hw/m68k/q800-glue.c index e81f9438f1..34c4f0e987 100644 --- a/hw/m68k/q800-glue.c +++ b/hw/m68k/q800-glue.c @@ -231,22 +231,19 @@ static void glue_class_init(ObjectClass *klass, void *data) nc->nmi_monitor_handler = glue_nmi; } -static const TypeInfo glue_info = { - .name = TYPE_GLUE, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(GLUEState), - .instance_init = glue_init, - .instance_finalize = glue_finalize, - .class_init = glue_class_init, - .interfaces = (InterfaceInfo[]) { - { TYPE_NMI }, - { } +static const TypeInfo glue_info_types[] = { + { + .name = TYPE_GLUE, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(GLUEState), + .instance_init = glue_init, + .instance_finalize = glue_finalize, + .class_init = glue_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_NMI }, + { } + }, }, }; -static void glue_register_types(void) -{ - type_register_static(&glue_info); -} - -type_init(glue_register_types) +DEFINE_TYPES(glue_info_types) From 1ecc6ec1ffbf5c209233be137f04344ec4eac6b5 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 21 Jun 2023 09:53:38 +0100 Subject: [PATCH 0029/1353] q800: move GLUE device to Q800MachineState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also change the instantiation of the GLUE device to use object_initialize_child(). Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Laurent Vivier Message-Id: <20230621085353.113233-10-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/m68k/q800.c | 24 ++++++++++++++---------- include/hw/m68k/q800.h | 2 ++ 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 9f9de2ebaf..505e50d4af 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -158,7 +158,6 @@ static void q800_machine_init(MachineState *machine) SysBusDevice *sysbus; BusState *adb_bus; NubusBus *nubus; - DeviceState *glue; DriveInfo *dinfo; uint8_t rng_seed[32]; @@ -194,10 +193,10 @@ static void q800_machine_init(MachineState *machine) } /* IRQ Glue */ - glue = qdev_new(TYPE_GLUE); - object_property_set_link(OBJECT(glue), "cpu", OBJECT(&m->cpu), + object_initialize_child(OBJECT(machine), "glue", &m->glue, TYPE_GLUE); + object_property_set_link(OBJECT(&m->glue), "cpu", OBJECT(&m->cpu), &error_abort); - sysbus_realize_and_unref(SYS_BUS_DEVICE(glue), &error_fatal); + sysbus_realize(SYS_BUS_DEVICE(&m->glue), &error_fatal); /* VIA 1 */ via1_dev = qdev_new(TYPE_MOS6522_Q800_VIA1); @@ -208,10 +207,12 @@ static void q800_machine_init(MachineState *machine) sysbus = SYS_BUS_DEVICE(via1_dev); sysbus_realize_and_unref(sysbus, &error_fatal); sysbus_mmio_map(sysbus, 1, VIA_BASE); - sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(glue, GLUE_IRQ_IN_VIA1)); + sysbus_connect_irq(sysbus, 0, + qdev_get_gpio_in(DEVICE(&m->glue), GLUE_IRQ_IN_VIA1)); /* A/UX mode */ qdev_connect_gpio_out(via1_dev, 0, - qdev_get_gpio_in_named(glue, "auxmode", 0)); + qdev_get_gpio_in_named(DEVICE(&m->glue), + "auxmode", 0)); adb_bus = qdev_get_child_bus(via1_dev, "adb.0"); dev = qdev_new(TYPE_ADB_KEYBOARD); @@ -224,7 +225,8 @@ static void q800_machine_init(MachineState *machine) sysbus = SYS_BUS_DEVICE(via2_dev); sysbus_realize_and_unref(sysbus, &error_fatal); sysbus_mmio_map(sysbus, 1, VIA_BASE + VIA_SIZE); - sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(glue, GLUE_IRQ_IN_VIA2)); + sysbus_connect_irq(sysbus, 0, + qdev_get_gpio_in(DEVICE(&m->glue), GLUE_IRQ_IN_VIA2)); /* MACSONIC */ @@ -257,7 +259,8 @@ static void q800_machine_init(MachineState *machine) sysbus = SYS_BUS_DEVICE(dev); sysbus_realize_and_unref(sysbus, &error_fatal); sysbus_mmio_map(sysbus, 0, SONIC_BASE); - sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(glue, GLUE_IRQ_IN_SONIC)); + sysbus_connect_irq(sysbus, 0, + qdev_get_gpio_in(DEVICE(&m->glue), GLUE_IRQ_IN_SONIC)); memory_region_init_rom(dp8393x_prom, NULL, "dp8393x-q800.prom", SONIC_PROM_SIZE, &error_fatal); @@ -294,7 +297,8 @@ static void q800_machine_init(MachineState *machine) sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(escc_orgate, 0)); sysbus_connect_irq(sysbus, 1, qdev_get_gpio_in(escc_orgate, 1)); qdev_connect_gpio_out(escc_orgate, 0, - qdev_get_gpio_in(glue, GLUE_IRQ_IN_ESCC)); + qdev_get_gpio_in(DEVICE(&m->glue), + GLUE_IRQ_IN_ESCC)); sysbus_mmio_map(sysbus, 0, SCC_BASE); /* SCSI */ @@ -349,7 +353,7 @@ static void q800_machine_init(MachineState *machine) * Since the framebuffer in slot 0x9 uses a separate IRQ, wire the unused * IRQ via GLUE for use by SONIC Ethernet in classic mode */ - qdev_connect_gpio_out(glue, GLUE_IRQ_NUBUS_9, + qdev_connect_gpio_out(DEVICE(&m->glue), GLUE_IRQ_NUBUS_9, qdev_get_gpio_in_named(via2_dev, "nubus-irq", VIA2_NUBUS_IRQ_9)); diff --git a/include/hw/m68k/q800.h b/include/hw/m68k/q800.h index d1f1ae4b88..fda42e0a1c 100644 --- a/include/hw/m68k/q800.h +++ b/include/hw/m68k/q800.h @@ -27,6 +27,7 @@ #include "qom/object.h" #include "target/m68k/cpu-qom.h" #include "exec/memory.h" +#include "hw/m68k/q800-glue.h" /* * The main Q800 machine @@ -37,6 +38,7 @@ struct Q800MachineState { M68kCPU cpu; MemoryRegion rom; + GLUEState glue; }; #define TYPE_Q800_MACHINE MACHINE_TYPE_NAME("q800") From 7527c52fd0472dbe06cc1f2f3b7979e202995ea2 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 21 Jun 2023 09:53:39 +0100 Subject: [PATCH 0030/1353] q800: introduce mac-io container memory region MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move all devices from the IO region to within the container in preparation for updating the IO aliasing mechanism. Signed-off-by: Mark Cave-Ayland Reviewed-by: Laurent Vivier Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230621085353.113233-11-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/m68k/q800.c | 6 ++++++ include/hw/m68k/q800.h | 1 + 2 files changed, 7 insertions(+) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 505e50d4af..359bdf3443 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -177,6 +177,12 @@ static void q800_machine_init(MachineState *machine) /* RAM */ memory_region_add_subregion(get_system_memory(), 0, machine->ram); + /* + * Create container for all IO devices + */ + memory_region_init(&m->macio, OBJECT(machine), "mac-io", IO_SLICE); + memory_region_add_subregion(get_system_memory(), IO_BASE, &m->macio); + /* * Memory from IO_BASE to IO_BASE + IO_SLICE is repeated * from IO_BASE + IO_SLICE to IO_BASE + IO_SIZE diff --git a/include/hw/m68k/q800.h b/include/hw/m68k/q800.h index fda42e0a1c..17067dfad7 100644 --- a/include/hw/m68k/q800.h +++ b/include/hw/m68k/q800.h @@ -39,6 +39,7 @@ struct Q800MachineState { M68kCPU cpu; MemoryRegion rom; GLUEState glue; + MemoryRegion macio; }; #define TYPE_Q800_MACHINE MACHINE_TYPE_NAME("q800") From f18a2886328d92c617a08692157d2b3f68477548 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 21 Jun 2023 09:53:40 +0100 Subject: [PATCH 0031/1353] q800: reimplement mac-io region aliasing using IO memory region The current use of aliased memory regions causes us 2 problems: firstly the output of "info qom-tree" is absolutely huge and difficult to read, and secondly we have already reached the internal limit for memory regions as adding any new memory region into the mac-io region causes QEMU to assert with "phys_section_add: Assertion `map->sections_nb < TARGET_PAGE_SIZE' failed". Implement the mac-io region aliasing using a single IO memory region that applies IO_SLICE_MASK representing the maximum size of the aliased region and then forwarding the access to the existing mac-io memory region using the address space API. Signed-off-by: Mark Cave-Ayland Reviewed-by: Laurent Vivier Message-Id: <20230621085353.113233-12-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/m68k/q800.c | 100 +++++++++++++++++++++++++++++++++-------- include/hw/m68k/q800.h | 1 + 2 files changed, 82 insertions(+), 19 deletions(-) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 359bdf3443..51b8d8ec3c 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -59,6 +59,7 @@ #define IO_BASE 0x50000000 #define IO_SLICE 0x00040000 +#define IO_SLICE_MASK (IO_SLICE - 1) #define IO_SIZE 0x04000000 #define VIA_BASE (IO_BASE + 0x00000) @@ -127,6 +128,68 @@ static uint8_t fake_mac_rom[] = { 0x60, 0xFE /* bras [self] */ }; +static MemTxResult macio_alias_read(void *opaque, hwaddr addr, uint64_t *data, + unsigned size, MemTxAttrs attrs) +{ + MemTxResult r; + uint32_t val; + + addr &= IO_SLICE_MASK; + addr |= IO_BASE; + + switch (size) { + case 4: + val = address_space_ldl_be(&address_space_memory, addr, attrs, &r); + break; + case 2: + val = address_space_lduw_be(&address_space_memory, addr, attrs, &r); + break; + case 1: + val = address_space_ldub(&address_space_memory, addr, attrs, &r); + break; + default: + g_assert_not_reached(); + } + + *data = val; + return r; +} + +static MemTxResult macio_alias_write(void *opaque, hwaddr addr, uint64_t value, + unsigned size, MemTxAttrs attrs) +{ + MemTxResult r; + + addr &= IO_SLICE_MASK; + addr |= IO_BASE; + + switch (size) { + case 4: + address_space_stl_be(&address_space_memory, addr, value, attrs, &r); + break; + case 2: + address_space_stw_be(&address_space_memory, addr, value, attrs, &r); + break; + case 1: + address_space_stb(&address_space_memory, addr, value, attrs, &r); + break; + default: + g_assert_not_reached(); + } + + return r; +} + +static const MemoryRegionOps macio_alias_ops = { + .read_with_attrs = macio_alias_read, + .write_with_attrs = macio_alias_write, + .endianness = DEVICE_BIG_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 4, + }, +}; + static void q800_machine_init(MachineState *machine) { Q800MachineState *m = Q800_MACHINE(machine); @@ -137,10 +200,8 @@ static void q800_machine_init(MachineState *machine) int bios_size; ram_addr_t initrd_base; int32_t initrd_size; - MemoryRegion *io; MemoryRegion *dp8393x_prom = g_new(MemoryRegion, 1); uint8_t *prom; - const int io_slice_nb = (IO_SIZE / IO_SLICE) - 1; int i, checksum; MacFbMode *macfb_mode; ram_addr_t ram_size = machine->ram_size; @@ -187,16 +248,10 @@ static void q800_machine_init(MachineState *machine) * Memory from IO_BASE to IO_BASE + IO_SLICE is repeated * from IO_BASE + IO_SLICE to IO_BASE + IO_SIZE */ - io = g_new(MemoryRegion, io_slice_nb); - for (i = 0; i < io_slice_nb; i++) { - char *name = g_strdup_printf("mac_m68k.io[%d]", i + 1); - - memory_region_init_alias(&io[i], NULL, name, get_system_memory(), - IO_BASE, IO_SLICE); - memory_region_add_subregion(get_system_memory(), - IO_BASE + (i + 1) * IO_SLICE, &io[i]); - g_free(name); - } + memory_region_init_io(&m->macio_alias, OBJECT(machine), &macio_alias_ops, + &m->macio, "mac-io.alias", IO_SIZE - IO_SLICE); + memory_region_add_subregion(get_system_memory(), IO_BASE + IO_SLICE, + &m->macio_alias); /* IRQ Glue */ object_initialize_child(OBJECT(machine), "glue", &m->glue, TYPE_GLUE); @@ -212,7 +267,8 @@ static void q800_machine_init(MachineState *machine) } sysbus = SYS_BUS_DEVICE(via1_dev); sysbus_realize_and_unref(sysbus, &error_fatal); - sysbus_mmio_map(sysbus, 1, VIA_BASE); + memory_region_add_subregion(&m->macio, VIA_BASE - IO_BASE, + sysbus_mmio_get_region(sysbus, 1)); sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(DEVICE(&m->glue), GLUE_IRQ_IN_VIA1)); /* A/UX mode */ @@ -230,7 +286,8 @@ static void q800_machine_init(MachineState *machine) via2_dev = qdev_new(TYPE_MOS6522_Q800_VIA2); sysbus = SYS_BUS_DEVICE(via2_dev); sysbus_realize_and_unref(sysbus, &error_fatal); - sysbus_mmio_map(sysbus, 1, VIA_BASE + VIA_SIZE); + memory_region_add_subregion(&m->macio, VIA_BASE - IO_BASE + VIA_SIZE, + sysbus_mmio_get_region(sysbus, 1)); sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(DEVICE(&m->glue), GLUE_IRQ_IN_VIA2)); @@ -264,7 +321,8 @@ static void q800_machine_init(MachineState *machine) OBJECT(get_system_memory()), &error_abort); sysbus = SYS_BUS_DEVICE(dev); sysbus_realize_and_unref(sysbus, &error_fatal); - sysbus_mmio_map(sysbus, 0, SONIC_BASE); + memory_region_add_subregion(&m->macio, SONIC_BASE - IO_BASE, + sysbus_mmio_get_region(sysbus, 0)); sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(DEVICE(&m->glue), GLUE_IRQ_IN_SONIC)); @@ -305,7 +363,8 @@ static void q800_machine_init(MachineState *machine) qdev_connect_gpio_out(escc_orgate, 0, qdev_get_gpio_in(DEVICE(&m->glue), GLUE_IRQ_IN_ESCC)); - sysbus_mmio_map(sysbus, 0, SCC_BASE); + memory_region_add_subregion(&m->macio, SCC_BASE - IO_BASE, + sysbus_mmio_get_region(sysbus, 0)); /* SCSI */ @@ -325,8 +384,10 @@ static void q800_machine_init(MachineState *machine) VIA2_IRQ_SCSI_BIT))); sysbus_connect_irq(sysbus, 1, qemu_irq_invert(qdev_get_gpio_in(via2_dev, VIA2_IRQ_SCSI_DATA_BIT))); - sysbus_mmio_map(sysbus, 0, ESP_BASE); - sysbus_mmio_map(sysbus, 1, ESP_PDMA); + memory_region_add_subregion(&m->macio, ESP_BASE - IO_BASE, + sysbus_mmio_get_region(sysbus, 0)); + memory_region_add_subregion(&m->macio, ESP_PDMA - IO_BASE, + sysbus_mmio_get_region(sysbus, 1)); scsi_bus_legacy_handle_cmdline(&esp->bus); @@ -334,7 +395,8 @@ static void q800_machine_init(MachineState *machine) dev = qdev_new(TYPE_SWIM); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, SWIM_BASE); + memory_region_add_subregion(&m->macio, SWIM_BASE - IO_BASE, + sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0)); /* NuBus */ diff --git a/include/hw/m68k/q800.h b/include/hw/m68k/q800.h index 17067dfad7..1ed38bf0b1 100644 --- a/include/hw/m68k/q800.h +++ b/include/hw/m68k/q800.h @@ -40,6 +40,7 @@ struct Q800MachineState { MemoryRegion rom; GLUEState glue; MemoryRegion macio; + MemoryRegion macio_alias; }; #define TYPE_Q800_MACHINE MACHINE_TYPE_NAME("q800") From 6d32c0643f263da92d24af4c87c86ea2c0f7f251 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 21 Jun 2023 09:53:41 +0100 Subject: [PATCH 0032/1353] q800: move VIA1 device to Q800MachineState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also change the instantiation of the VIA1 device to use object_initialize_child(). Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Laurent Vivier Message-Id: <20230621085353.113233-13-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/m68k/q800.c | 16 +++++++++------- include/hw/m68k/q800.h | 2 ++ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 51b8d8ec3c..fccdad5f3c 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -212,7 +212,7 @@ static void q800_machine_init(MachineState *machine) hwaddr parameters_base; CPUState *cs; DeviceState *dev; - DeviceState *via1_dev, *via2_dev; + DeviceState *via2_dev; DeviceState *escc_orgate; SysBusESPState *sysbus_esp; ESPState *esp; @@ -260,23 +260,25 @@ static void q800_machine_init(MachineState *machine) sysbus_realize(SYS_BUS_DEVICE(&m->glue), &error_fatal); /* VIA 1 */ - via1_dev = qdev_new(TYPE_MOS6522_Q800_VIA1); + object_initialize_child(OBJECT(machine), "via1", &m->via1, + TYPE_MOS6522_Q800_VIA1); dinfo = drive_get(IF_MTD, 0, 0); if (dinfo) { - qdev_prop_set_drive(via1_dev, "drive", blk_by_legacy_dinfo(dinfo)); + qdev_prop_set_drive(DEVICE(&m->via1), "drive", + blk_by_legacy_dinfo(dinfo)); } - sysbus = SYS_BUS_DEVICE(via1_dev); - sysbus_realize_and_unref(sysbus, &error_fatal); + sysbus = SYS_BUS_DEVICE(&m->via1); + sysbus_realize(sysbus, &error_fatal); memory_region_add_subregion(&m->macio, VIA_BASE - IO_BASE, sysbus_mmio_get_region(sysbus, 1)); sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(DEVICE(&m->glue), GLUE_IRQ_IN_VIA1)); /* A/UX mode */ - qdev_connect_gpio_out(via1_dev, 0, + qdev_connect_gpio_out(DEVICE(&m->via1), 0, qdev_get_gpio_in_named(DEVICE(&m->glue), "auxmode", 0)); - adb_bus = qdev_get_child_bus(via1_dev, "adb.0"); + adb_bus = qdev_get_child_bus(DEVICE(&m->via1), "adb.0"); dev = qdev_new(TYPE_ADB_KEYBOARD); qdev_realize_and_unref(dev, adb_bus, &error_fatal); dev = qdev_new(TYPE_ADB_MOUSE); diff --git a/include/hw/m68k/q800.h b/include/hw/m68k/q800.h index 1ed38bf0b1..5cf66d08a0 100644 --- a/include/hw/m68k/q800.h +++ b/include/hw/m68k/q800.h @@ -28,6 +28,7 @@ #include "target/m68k/cpu-qom.h" #include "exec/memory.h" #include "hw/m68k/q800-glue.h" +#include "hw/misc/mac_via.h" /* * The main Q800 machine @@ -39,6 +40,7 @@ struct Q800MachineState { M68kCPU cpu; MemoryRegion rom; GLUEState glue; + MOS6522Q800VIA1State via1; MemoryRegion macio; MemoryRegion macio_alias; }; From d7942e166ae2da7f70a55365470177d9e71cca3f Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 21 Jun 2023 09:53:42 +0100 Subject: [PATCH 0033/1353] q800: move VIA2 device to Q800MachineState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also change the instantiation of the VIA2 device to use object_initialize_child(). Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Laurent Vivier Message-Id: <20230621085353.113233-14-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/m68k/q800.c | 27 ++++++++++++++++----------- include/hw/m68k/q800.h | 1 + 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index fccdad5f3c..988b4981b8 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -212,7 +212,6 @@ static void q800_machine_init(MachineState *machine) hwaddr parameters_base; CPUState *cs; DeviceState *dev; - DeviceState *via2_dev; DeviceState *escc_orgate; SysBusESPState *sysbus_esp; ESPState *esp; @@ -285,9 +284,10 @@ static void q800_machine_init(MachineState *machine) qdev_realize_and_unref(dev, adb_bus, &error_fatal); /* VIA 2 */ - via2_dev = qdev_new(TYPE_MOS6522_Q800_VIA2); - sysbus = SYS_BUS_DEVICE(via2_dev); - sysbus_realize_and_unref(sysbus, &error_fatal); + object_initialize_child(OBJECT(machine), "via2", &m->via2, + TYPE_MOS6522_Q800_VIA2); + sysbus = SYS_BUS_DEVICE(&m->via2); + sysbus_realize(sysbus, &error_fatal); memory_region_add_subregion(&m->macio, VIA_BASE - IO_BASE + VIA_SIZE, sysbus_mmio_get_region(sysbus, 1)); sysbus_connect_irq(sysbus, 0, @@ -382,10 +382,14 @@ static void q800_machine_init(MachineState *machine) sysbus = SYS_BUS_DEVICE(dev); sysbus_realize_and_unref(sysbus, &error_fatal); /* SCSI and SCSI data IRQs are negative edge triggered */ - sysbus_connect_irq(sysbus, 0, qemu_irq_invert(qdev_get_gpio_in(via2_dev, - VIA2_IRQ_SCSI_BIT))); - sysbus_connect_irq(sysbus, 1, qemu_irq_invert(qdev_get_gpio_in(via2_dev, - VIA2_IRQ_SCSI_DATA_BIT))); + sysbus_connect_irq(sysbus, 0, + qemu_irq_invert( + qdev_get_gpio_in(DEVICE(&m->via2), + VIA2_IRQ_SCSI_BIT))); + sysbus_connect_irq(sysbus, 1, + qemu_irq_invert( + qdev_get_gpio_in(DEVICE(&m->via2), + VIA2_IRQ_SCSI_DATA_BIT))); memory_region_add_subregion(&m->macio, ESP_BASE - IO_BASE, sysbus_mmio_get_region(sysbus, 0)); memory_region_add_subregion(&m->macio, ESP_PDMA - IO_BASE, @@ -411,11 +415,12 @@ static void q800_machine_init(MachineState *machine) sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, NUBUS_SLOT_BASE + MAC_NUBUS_FIRST_SLOT * NUBUS_SLOT_SIZE); qdev_connect_gpio_out(dev, 9, - qdev_get_gpio_in_named(via2_dev, "nubus-irq", + qdev_get_gpio_in_named(DEVICE(&m->via2), "nubus-irq", VIA2_NUBUS_IRQ_INTVIDEO)); for (i = 1; i < VIA2_NUBUS_IRQ_NB; i++) { qdev_connect_gpio_out(dev, 9 + i, - qdev_get_gpio_in_named(via2_dev, "nubus-irq", + qdev_get_gpio_in_named(DEVICE(&m->via2), + "nubus-irq", VIA2_NUBUS_IRQ_9 + i)); } @@ -424,7 +429,7 @@ static void q800_machine_init(MachineState *machine) * IRQ via GLUE for use by SONIC Ethernet in classic mode */ qdev_connect_gpio_out(DEVICE(&m->glue), GLUE_IRQ_NUBUS_9, - qdev_get_gpio_in_named(via2_dev, "nubus-irq", + qdev_get_gpio_in_named(DEVICE(&m->via2), "nubus-irq", VIA2_NUBUS_IRQ_9)); nubus = &NUBUS_BRIDGE(dev)->bus; diff --git a/include/hw/m68k/q800.h b/include/hw/m68k/q800.h index 5cf66d08a0..06c771635b 100644 --- a/include/hw/m68k/q800.h +++ b/include/hw/m68k/q800.h @@ -41,6 +41,7 @@ struct Q800MachineState { MemoryRegion rom; GLUEState glue; MOS6522Q800VIA1State via1; + MOS6522Q800VIA2State via2; MemoryRegion macio; MemoryRegion macio_alias; }; From 2db48d0364f9bbc0d22370fc26debfaa4adca31f Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 21 Jun 2023 09:53:43 +0100 Subject: [PATCH 0034/1353] hw/net/dp8393x.c: move TYPE_DP8393X and dp8393xState into dp8393x.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is to enable them to be used outside of dp8393x.c. Signed-off-by: Mark Cave-Ayland CC: Jason Wang Reviewed-by: Laurent Vivier Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230621085353.113233-15-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/net/dp8393x.c | 32 +-------------------- include/hw/net/dp8393x.h | 60 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 31 deletions(-) create mode 100644 include/hw/net/dp8393x.h diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c index 45b954e46c..a596f7fbc6 100644 --- a/hw/net/dp8393x.c +++ b/hw/net/dp8393x.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "hw/irq.h" #include "hw/qdev-properties.h" +#include "hw/net/dp8393x.h" #include "hw/sysbus.h" #include "migration/vmstate.h" #include "net/net.h" @@ -85,7 +86,6 @@ static const char *reg_names[] = { #define SONIC_MPT 0x2e #define SONIC_MDT 0x2f #define SONIC_DCR2 0x3f -#define SONIC_REG_COUNT 0x40 #define SONIC_CR_HTX 0x0001 #define SONIC_CR_TXP 0x0002 @@ -139,36 +139,6 @@ static const char *reg_names[] = { #define SONIC_DESC_EOL 0x0001 #define SONIC_DESC_ADDR 0xFFFE -#define TYPE_DP8393X "dp8393x" -OBJECT_DECLARE_SIMPLE_TYPE(dp8393xState, DP8393X) - -struct dp8393xState { - SysBusDevice parent_obj; - - /* Hardware */ - uint8_t it_shift; - bool big_endian; - bool last_rba_is_full; - qemu_irq irq; - int irq_level; - QEMUTimer *watchdog; - int64_t wt_last_update; - NICConf conf; - NICState *nic; - MemoryRegion mmio; - - /* Registers */ - uint16_t cam[16][3]; - uint16_t regs[SONIC_REG_COUNT]; - - /* Temporaries */ - uint8_t tx_buffer[0x10000]; - int loopback_packet; - - /* Memory access */ - MemoryRegion *dma_mr; - AddressSpace as; -}; /* * Accessor functions for values which are formed by diff --git a/include/hw/net/dp8393x.h b/include/hw/net/dp8393x.h new file mode 100644 index 0000000000..4a3f7478be --- /dev/null +++ b/include/hw/net/dp8393x.h @@ -0,0 +1,60 @@ +/* + * QEMU NS SONIC DP8393x netcard + * + * Copyright (c) 2008-2009 Herve Poussineau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#ifndef HW_NET_DP8393X_H +#define HW_NET_DP8393X_H + +#include "hw/sysbus.h" +#include "net/net.h" +#include "exec/memory.h" + +#define SONIC_REG_COUNT 0x40 + +#define TYPE_DP8393X "dp8393x" +OBJECT_DECLARE_SIMPLE_TYPE(dp8393xState, DP8393X) + +struct dp8393xState { + SysBusDevice parent_obj; + + /* Hardware */ + uint8_t it_shift; + bool big_endian; + bool last_rba_is_full; + qemu_irq irq; + int irq_level; + QEMUTimer *watchdog; + int64_t wt_last_update; + NICConf conf; + NICState *nic; + MemoryRegion mmio; + + /* Registers */ + uint16_t cam[16][3]; + uint16_t regs[SONIC_REG_COUNT]; + + /* Temporaries */ + uint8_t tx_buffer[0x10000]; + int loopback_packet; + + /* Memory access */ + MemoryRegion *dma_mr; + AddressSpace as; +}; + +#endif From 804ae67ee6fc3ff5a6c82edba7ed4cbdd33de091 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 21 Jun 2023 09:53:44 +0100 Subject: [PATCH 0035/1353] q800: move dp8393x device to Q800MachineState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also change the instantiation of the dp8393x device to use object_initialize_child(). Signed-off-by: Mark Cave-Ayland CC: Jason Wang Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Laurent Vivier Message-Id: <20230621085353.113233-16-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/m68k/q800.c | 6 ++++-- include/hw/m68k/q800.h | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 988b4981b8..13806613fa 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -315,14 +315,16 @@ static void q800_machine_init(MachineState *machine) nd_table[0].macaddr.a[1] = 0x00; nd_table[0].macaddr.a[2] = 0x07; - dev = qdev_new("dp8393x"); + object_initialize_child(OBJECT(machine), "dp8393x", &m->dp8393x, + TYPE_DP8393X); + dev = DEVICE(&m->dp8393x); qdev_set_nic_properties(dev, &nd_table[0]); qdev_prop_set_uint8(dev, "it_shift", 2); qdev_prop_set_bit(dev, "big_endian", true); object_property_set_link(OBJECT(dev), "dma_mr", OBJECT(get_system_memory()), &error_abort); sysbus = SYS_BUS_DEVICE(dev); - sysbus_realize_and_unref(sysbus, &error_fatal); + sysbus_realize(sysbus, &error_fatal); memory_region_add_subregion(&m->macio, SONIC_BASE - IO_BASE, sysbus_mmio_get_region(sysbus, 0)); sysbus_connect_irq(sysbus, 0, diff --git a/include/hw/m68k/q800.h b/include/hw/m68k/q800.h index 06c771635b..d11bc020ed 100644 --- a/include/hw/m68k/q800.h +++ b/include/hw/m68k/q800.h @@ -29,6 +29,7 @@ #include "exec/memory.h" #include "hw/m68k/q800-glue.h" #include "hw/misc/mac_via.h" +#include "hw/net/dp8393x.h" /* * The main Q800 machine @@ -42,6 +43,7 @@ struct Q800MachineState { GLUEState glue; MOS6522Q800VIA1State via1; MOS6522Q800VIA2State via2; + dp8393xState dp8393x; MemoryRegion macio; MemoryRegion macio_alias; }; From 836126c77326d9a7b629063c9caa9deff3a26aed Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 21 Jun 2023 09:53:45 +0100 Subject: [PATCH 0036/1353] q800: move ESCC device to Q800MachineState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also change the instantiation of the ESCC device to use object_initialize_child(). Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Laurent Vivier Message-Id: <20230621085353.113233-17-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/m68k/q800.c | 6 ++++-- include/hw/m68k/q800.h | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 13806613fa..8bf94b2511 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -346,7 +346,9 @@ static void q800_machine_init(MachineState *machine) /* SCC */ - dev = qdev_new(TYPE_ESCC); + object_initialize_child(OBJECT(machine), "escc", &m->escc, + TYPE_ESCC); + dev = DEVICE(&m->escc); qdev_prop_set_uint32(dev, "disabled", 0); qdev_prop_set_uint32(dev, "frequency", MAC_CLOCK); qdev_prop_set_uint32(dev, "it_shift", 1); @@ -356,7 +358,7 @@ static void q800_machine_init(MachineState *machine) qdev_prop_set_uint32(dev, "chnBtype", 0); qdev_prop_set_uint32(dev, "chnAtype", 0); sysbus = SYS_BUS_DEVICE(dev); - sysbus_realize_and_unref(sysbus, &error_fatal); + sysbus_realize(sysbus, &error_fatal); /* Logically OR both its IRQs together */ escc_orgate = DEVICE(object_new(TYPE_OR_IRQ)); diff --git a/include/hw/m68k/q800.h b/include/hw/m68k/q800.h index d11bc020ed..9e76a3fe7c 100644 --- a/include/hw/m68k/q800.h +++ b/include/hw/m68k/q800.h @@ -30,6 +30,7 @@ #include "hw/m68k/q800-glue.h" #include "hw/misc/mac_via.h" #include "hw/net/dp8393x.h" +#include "hw/char/escc.h" /* * The main Q800 machine @@ -44,6 +45,7 @@ struct Q800MachineState { MOS6522Q800VIA1State via1; MOS6522Q800VIA2State via2; dp8393xState dp8393x; + ESCCState escc; MemoryRegion macio; MemoryRegion macio_alias; }; From 1a7a3f004cb9a4913b2a5eb8b1c8dd178db3bee9 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 21 Jun 2023 09:53:46 +0100 Subject: [PATCH 0037/1353] q800: move escc_orgate device to Q800MachineState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also change the instantiation of the escc_orgate device to use object_initialize_child(). Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Laurent Vivier Message-Id: <20230621085353.113233-18-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/m68k/q800.c | 16 +++++++++------- include/hw/m68k/q800.h | 2 ++ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 8bf94b2511..c6314c6bf9 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -212,7 +212,6 @@ static void q800_machine_init(MachineState *machine) hwaddr parameters_base; CPUState *cs; DeviceState *dev; - DeviceState *escc_orgate; SysBusESPState *sysbus_esp; ESPState *esp; SysBusDevice *sysbus; @@ -361,12 +360,15 @@ static void q800_machine_init(MachineState *machine) sysbus_realize(sysbus, &error_fatal); /* Logically OR both its IRQs together */ - escc_orgate = DEVICE(object_new(TYPE_OR_IRQ)); - object_property_set_int(OBJECT(escc_orgate), "num-lines", 2, &error_fatal); - qdev_realize_and_unref(escc_orgate, NULL, &error_fatal); - sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(escc_orgate, 0)); - sysbus_connect_irq(sysbus, 1, qdev_get_gpio_in(escc_orgate, 1)); - qdev_connect_gpio_out(escc_orgate, 0, + object_initialize_child(OBJECT(machine), "escc_orgate", &m->escc_orgate, + TYPE_OR_IRQ); + object_property_set_int(OBJECT(&m->escc_orgate), "num-lines", 2, + &error_fatal); + dev = DEVICE(&m->escc_orgate); + qdev_realize(dev, NULL, &error_fatal); + sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(dev, 0)); + sysbus_connect_irq(sysbus, 1, qdev_get_gpio_in(dev, 1)); + qdev_connect_gpio_out(dev, 0, qdev_get_gpio_in(DEVICE(&m->glue), GLUE_IRQ_IN_ESCC)); memory_region_add_subregion(&m->macio, SCC_BASE - IO_BASE, diff --git a/include/hw/m68k/q800.h b/include/hw/m68k/q800.h index 9e76a3fe7c..36e1bd8e4e 100644 --- a/include/hw/m68k/q800.h +++ b/include/hw/m68k/q800.h @@ -31,6 +31,7 @@ #include "hw/misc/mac_via.h" #include "hw/net/dp8393x.h" #include "hw/char/escc.h" +#include "hw/or-irq.h" /* * The main Q800 machine @@ -46,6 +47,7 @@ struct Q800MachineState { MOS6522Q800VIA2State via2; dp8393xState dp8393x; ESCCState escc; + OrIRQState escc_orgate; MemoryRegion macio; MemoryRegion macio_alias; }; From e78d17ca7d1dbfbe0a312e1ed40694d1485c763b Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 21 Jun 2023 09:53:47 +0100 Subject: [PATCH 0038/1353] q800: move ESP device to Q800MachineState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also change the instantiation of the ESP device to use object_initialize_child(). Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Laurent Vivier Message-Id: <20230621085353.113233-19-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/m68k/q800.c | 9 +++++---- include/hw/m68k/q800.h | 2 ++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index c6314c6bf9..9da46f4456 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -376,8 +376,9 @@ static void q800_machine_init(MachineState *machine) /* SCSI */ - dev = qdev_new(TYPE_SYSBUS_ESP); - sysbus_esp = SYSBUS_ESP(dev); + object_initialize_child(OBJECT(machine), "esp", &m->esp, + TYPE_SYSBUS_ESP); + sysbus_esp = SYSBUS_ESP(&m->esp); esp = &sysbus_esp->esp; esp->dma_memory_read = NULL; esp->dma_memory_write = NULL; @@ -385,8 +386,8 @@ static void q800_machine_init(MachineState *machine) sysbus_esp->it_shift = 4; esp->dma_enabled = 1; - sysbus = SYS_BUS_DEVICE(dev); - sysbus_realize_and_unref(sysbus, &error_fatal); + sysbus = SYS_BUS_DEVICE(&m->esp); + sysbus_realize(sysbus, &error_fatal); /* SCSI and SCSI data IRQs are negative edge triggered */ sysbus_connect_irq(sysbus, 0, qemu_irq_invert( diff --git a/include/hw/m68k/q800.h b/include/hw/m68k/q800.h index 36e1bd8e4e..8f23e0c4c6 100644 --- a/include/hw/m68k/q800.h +++ b/include/hw/m68k/q800.h @@ -32,6 +32,7 @@ #include "hw/net/dp8393x.h" #include "hw/char/escc.h" #include "hw/or-irq.h" +#include "hw/scsi/esp.h" /* * The main Q800 machine @@ -48,6 +49,7 @@ struct Q800MachineState { dp8393xState dp8393x; ESCCState escc; OrIRQState escc_orgate; + SysBusESPState esp; MemoryRegion macio; MemoryRegion macio_alias; }; From 01f35a4f1cfa34a998d0bc11dbdefa7dd26d2c7b Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 21 Jun 2023 09:53:48 +0100 Subject: [PATCH 0039/1353] q800: move SWIM device to Q800MachineState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also change the instantiation of the SWIM device to use object_initialize_child(). Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Laurent Vivier Message-Id: <20230621085353.113233-20-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/m68k/q800.c | 8 +++++--- include/hw/m68k/q800.h | 2 ++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 9da46f4456..50fc7de9a2 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -406,10 +406,12 @@ static void q800_machine_init(MachineState *machine) /* SWIM floppy controller */ - dev = qdev_new(TYPE_SWIM); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + object_initialize_child(OBJECT(machine), "swim", &m->swim, + TYPE_SWIM); + sysbus = SYS_BUS_DEVICE(&m->swim); + sysbus_realize(sysbus, &error_fatal); memory_region_add_subregion(&m->macio, SWIM_BASE - IO_BASE, - sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0)); + sysbus_mmio_get_region(sysbus, 0)); /* NuBus */ diff --git a/include/hw/m68k/q800.h b/include/hw/m68k/q800.h index 8f23e0c4c6..06e095ae29 100644 --- a/include/hw/m68k/q800.h +++ b/include/hw/m68k/q800.h @@ -33,6 +33,7 @@ #include "hw/char/escc.h" #include "hw/or-irq.h" #include "hw/scsi/esp.h" +#include "hw/block/swim.h" /* * The main Q800 machine @@ -50,6 +51,7 @@ struct Q800MachineState { ESCCState escc; OrIRQState escc_orgate; SysBusESPState esp; + Swim swim; MemoryRegion macio; MemoryRegion macio_alias; }; From 36df1c5a635c11e5514ac561ed90a9c459cdbff2 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 21 Jun 2023 09:53:49 +0100 Subject: [PATCH 0040/1353] q800: move mac-nubus-bridge device to Q800MachineState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also change the instantiation of the mac-nubus-bridge device to use object_initialize_child() and map the Nubus address space using memory_region_add_subregion() instead of sysbus_mmio_map(). Signed-off-by: Mark Cave-Ayland Reviewed-by: Laurent Vivier Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230621085353.113233-21-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/m68k/q800.c | 21 ++++++++++++++------- include/hw/m68k/q800.h | 2 ++ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 50fc7de9a2..b22651931a 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -415,14 +415,21 @@ static void q800_machine_init(MachineState *machine) /* NuBus */ - dev = qdev_new(TYPE_MAC_NUBUS_BRIDGE); - qdev_prop_set_uint32(dev, "slot-available-mask", + object_initialize_child(OBJECT(machine), "mac-nubus-bridge", + &m->mac_nubus_bridge, + TYPE_MAC_NUBUS_BRIDGE); + sysbus = SYS_BUS_DEVICE(&m->mac_nubus_bridge); + dev = DEVICE(&m->mac_nubus_bridge); + qdev_prop_set_uint32(DEVICE(&m->mac_nubus_bridge), "slot-available-mask", Q800_NUBUS_SLOTS_AVAILABLE); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, - MAC_NUBUS_FIRST_SLOT * NUBUS_SUPER_SLOT_SIZE); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, NUBUS_SLOT_BASE + - MAC_NUBUS_FIRST_SLOT * NUBUS_SLOT_SIZE); + sysbus_realize(sysbus, &error_fatal); + memory_region_add_subregion(get_system_memory(), + MAC_NUBUS_FIRST_SLOT * NUBUS_SUPER_SLOT_SIZE, + sysbus_mmio_get_region(sysbus, 0)); + memory_region_add_subregion(get_system_memory(), + NUBUS_SLOT_BASE + + MAC_NUBUS_FIRST_SLOT * NUBUS_SLOT_SIZE, + sysbus_mmio_get_region(sysbus, 1)); qdev_connect_gpio_out(dev, 9, qdev_get_gpio_in_named(DEVICE(&m->via2), "nubus-irq", VIA2_NUBUS_IRQ_INTVIDEO)); diff --git a/include/hw/m68k/q800.h b/include/hw/m68k/q800.h index 06e095ae29..8f2c572a81 100644 --- a/include/hw/m68k/q800.h +++ b/include/hw/m68k/q800.h @@ -34,6 +34,7 @@ #include "hw/or-irq.h" #include "hw/scsi/esp.h" #include "hw/block/swim.h" +#include "hw/nubus/mac-nubus-bridge.h" /* * The main Q800 machine @@ -52,6 +53,7 @@ struct Q800MachineState { OrIRQState escc_orgate; SysBusESPState esp; Swim swim; + MacNubusBridge mac_nubus_bridge; MemoryRegion macio; MemoryRegion macio_alias; }; From 464085e8f6776a0ca5a2677cf8b93b25c8a94da4 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 21 Jun 2023 09:53:50 +0100 Subject: [PATCH 0041/1353] q800: don't access Nubus bus directly from the mac-nubus-bridge device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead use the qdev_get_child_bus() function which is intended for this exact purpose. Signed-off-by: Mark Cave-Ayland Reviewed-by: Laurent Vivier Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230621085353.113233-22-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/m68k/q800.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index b22651931a..a32e6fbf8d 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -448,7 +448,7 @@ static void q800_machine_init(MachineState *machine) qdev_get_gpio_in_named(DEVICE(&m->via2), "nubus-irq", VIA2_NUBUS_IRQ_9)); - nubus = &NUBUS_BRIDGE(dev)->bus; + nubus = NUBUS_BUS(qdev_get_child_bus(dev, "nubus-bus.0")); /* framebuffer in nubus slot #9 */ From 7a1f3acb3f41a6bc896c1d7d1749336c21eb8cee Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 21 Jun 2023 09:53:51 +0100 Subject: [PATCH 0042/1353] q800: move macfb device to Q800MachineState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also change the instantiation of the macfb device to use object_initialize_child(). Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Laurent Vivier Message-Id: <20230621085353.113233-23-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/m68k/q800.c | 6 ++++-- include/hw/m68k/q800.h | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index a32e6fbf8d..b770b71d54 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -452,7 +452,9 @@ static void q800_machine_init(MachineState *machine) /* framebuffer in nubus slot #9 */ - dev = qdev_new(TYPE_NUBUS_MACFB); + object_initialize_child(OBJECT(machine), "macfb", &m->macfb, + TYPE_NUBUS_MACFB); + dev = DEVICE(&m->macfb); qdev_prop_set_uint32(dev, "slot", 9); qdev_prop_set_uint32(dev, "width", graphic_width); qdev_prop_set_uint32(dev, "height", graphic_height); @@ -462,7 +464,7 @@ static void q800_machine_init(MachineState *machine) } else { qdev_prop_set_uint8(dev, "display", MACFB_DISPLAY_VGA); } - qdev_realize_and_unref(dev, BUS(nubus), &error_fatal); + qdev_realize(dev, BUS(nubus), &error_fatal); macfb_mode = (NUBUS_MACFB(dev)->macfb).mode; diff --git a/include/hw/m68k/q800.h b/include/hw/m68k/q800.h index 8f2c572a81..b3d77f1cba 100644 --- a/include/hw/m68k/q800.h +++ b/include/hw/m68k/q800.h @@ -35,6 +35,7 @@ #include "hw/scsi/esp.h" #include "hw/block/swim.h" #include "hw/nubus/mac-nubus-bridge.h" +#include "hw/display/macfb.h" /* * The main Q800 machine @@ -54,6 +55,7 @@ struct Q800MachineState { SysBusESPState esp; Swim swim; MacNubusBridge mac_nubus_bridge; + MacfbNubusState macfb; MemoryRegion macio; MemoryRegion macio_alias; }; From ce47d531c33c35eca985f2dffc340c09433690fa Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 21 Jun 2023 09:53:52 +0100 Subject: [PATCH 0043/1353] mac_via: fix rtc command decoding from PRAM addresses 0x0 to 0xf A comparison between the rtc command table included in the comment and the code itself shows that the decoding for PRAM addresses 0x0 to 0xf is being done on the raw command, and not the shifted version held in value. Signed-off-by: Mark Cave-Ayland Reviewed-by: Laurent Vivier Message-Id: <20230621085353.113233-24-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/misc/mac_via.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/misc/mac_via.c b/hw/misc/mac_via.c index 076d18e5fd..85c2e65856 100644 --- a/hw/misc/mac_via.c +++ b/hw/misc/mac_via.c @@ -399,7 +399,7 @@ static int via1_rtc_compact_cmd(uint8_t value) } else if ((value & 0x1c) == 0x08) { /* RAM address 0x10 to 0x13 */ return read | (REG_PRAM_ADDR + 0x10 + (value & 0x03)); - } else if ((value & 0x43) == 0x41) { + } else if ((value & 0x10) == 0x10) { /* RAM address 0x00 to 0x0f */ return read | (REG_PRAM_ADDR + (value & 0x0f)); } From 532009054b45d75a3cf7ba9c31921add669d290d Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 21 Jun 2023 09:53:53 +0100 Subject: [PATCH 0044/1353] mac_via: fix rtc command decoding for the PRAM seconds registers Analysis of the MacOS toolbox ROM code shows that on startup it attempts 2 separate reads of the seconds registers with commands 0x9d...0x91 followed by 0x8d..0x81 without resetting the command to its initial value. The PRAM seconds value is only accepted when the values of the 2 separate reads match. From this we conclude that bit 4 of the rtc command is not decoded or we don't care about its value when reading the PRAM seconds registers. Implement this decoding change so that both reads return successfully which allows the MacOS toolbox ROM to correctly set the date/time. Signed-off-by: Mark Cave-Ayland Reviewed-by: Laurent Vivier Message-Id: <20230621085353.113233-25-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- hw/misc/mac_via.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/hw/misc/mac_via.c b/hw/misc/mac_via.c index 85c2e65856..0787a0268d 100644 --- a/hw/misc/mac_via.c +++ b/hw/misc/mac_via.c @@ -362,10 +362,10 @@ static void pram_update(MOS6522Q800VIA1State *v1s) * * Command byte Register addressed by the command * - * z0000001 Seconds register 0 (lowest-order byte) - * z0000101 Seconds register 1 - * z0001001 Seconds register 2 - * z0001101 Seconds register 3 (highest-order byte) + * z00x0001 Seconds register 0 (lowest-order byte) + * z00x0101 Seconds register 1 + * z00x1001 Seconds register 2 + * z00x1101 Seconds register 3 (highest-order byte) * 00110001 Test register (write-only) * 00110101 Write-Protect Register (write-only) * z010aa01 RAM address 100aa ($10-$13) (first 20 bytes only) @@ -373,6 +373,7 @@ static void pram_update(MOS6522Q800VIA1State *v1s) * z0111aaa Extended memory designator and sector number * * For a read request, z=1, for a write z=0 + * The letter x indicates don't care * The letter a indicates bits whose value depend on what parameter * RAM byte you want to address */ @@ -389,7 +390,7 @@ static int via1_rtc_compact_cmd(uint8_t value) } if ((value & 0x03) == 0x01) { value >>= 2; - if ((value & 0x1c) == 0) { + if ((value & 0x18) == 0) { /* seconds registers */ return read | (REG_0 + (value & 0x03)); } else if ((value == 0x0c) && !read) { From 14180d6221502bd4b9d96fa5f1065e7cda4bcf00 Mon Sep 17 00:00:00 2001 From: Ira Weiny Date: Fri, 26 May 2023 18:00:07 +0100 Subject: [PATCH 0045/1353] bswap: Add the ability to store to an unaligned 24 bit field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CXL has 24 bit unaligned fields which need to be stored to. CXL is specified as little endian. Define st24_le_p() and the supporting functions to store such a field from a 32 bit host native value. The use of b, w, l, q as the size specifier is limiting. So "24" was used for the size part of the function name. Reviewed-by: Fan Ni Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Ira Weiny Signed-off-by: Jonathan Cameron Message-Id: <20230526170010.574-2-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- docs/devel/loads-stores.rst | 2 ++ include/qemu/bswap.h | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/docs/devel/loads-stores.rst b/docs/devel/loads-stores.rst index d2cefc77a2..dab6dfa0ac 100644 --- a/docs/devel/loads-stores.rst +++ b/docs/devel/loads-stores.rst @@ -36,6 +36,7 @@ store: ``st{size}_{endian}_p(ptr, val)`` ``size`` - ``b`` : 8 bits - ``w`` : 16 bits + - ``24`` : 24 bits - ``l`` : 32 bits - ``q`` : 64 bits @@ -65,6 +66,7 @@ of size ``sz`` bytes. Regexes for git grep - ``\`` - ``\`` + - ``\`` - ``\`` - ``\`` diff --git a/include/qemu/bswap.h b/include/qemu/bswap.h index 15a78c0db5..933a66ee87 100644 --- a/include/qemu/bswap.h +++ b/include/qemu/bswap.h @@ -8,11 +8,23 @@ #undef bswap64 #define bswap64(_x) __builtin_bswap64(_x) +static inline uint32_t bswap24(uint32_t x) +{ + return (((x & 0x000000ffU) << 16) | + ((x & 0x0000ff00U) << 0) | + ((x & 0x00ff0000U) >> 16)); +} + static inline void bswap16s(uint16_t *s) { *s = __builtin_bswap16(*s); } +static inline void bswap24s(uint32_t *s) +{ + *s = bswap24(*s & 0x00ffffffU); +} + static inline void bswap32s(uint32_t *s) { *s = __builtin_bswap32(*s); @@ -26,11 +38,13 @@ static inline void bswap64s(uint64_t *s) #if HOST_BIG_ENDIAN #define be_bswap(v, size) (v) #define le_bswap(v, size) glue(__builtin_bswap, size)(v) +#define le_bswap24(v) bswap24(v) #define be_bswaps(v, size) #define le_bswaps(p, size) \ do { *p = glue(__builtin_bswap, size)(*p); } while (0) #else #define le_bswap(v, size) (v) +#define le_bswap24(v) (v) #define be_bswap(v, size) glue(__builtin_bswap, size)(v) #define le_bswaps(v, size) #define be_bswaps(p, size) \ @@ -176,6 +190,7 @@ CPU_CONVERT(le, 64, uint64_t) * size is: * b: 8 bits * w: 16 bits + * 24: 24 bits * l: 32 bits * q: 64 bits * @@ -248,6 +263,11 @@ static inline void stw_he_p(void *ptr, uint16_t v) __builtin_memcpy(ptr, &v, sizeof(v)); } +static inline void st24_he_p(void *ptr, uint32_t v) +{ + __builtin_memcpy(ptr, &v, 3); +} + static inline int ldl_he_p(const void *ptr) { int32_t r; @@ -297,6 +317,11 @@ static inline void stw_le_p(void *ptr, uint16_t v) stw_he_p(ptr, le_bswap(v, 16)); } +static inline void st24_le_p(void *ptr, uint32_t v) +{ + st24_he_p(ptr, le_bswap24(v)); +} + static inline void stl_le_p(void *ptr, uint32_t v) { stl_he_p(ptr, le_bswap(v, 32)); From 9547754f40ee5c5e3d1dbed0fbc972caacd075e8 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Fri, 26 May 2023 18:00:08 +0100 Subject: [PATCH 0046/1353] hw/cxl: QMP based poison injection support Inject poison using QMP command cxl-inject-poison to add an entry to the poison list. For now, the poison is not returned CXL.mem reads, but only via the mailbox command Get Poison List. So a normal memory read to an address that is on the poison list will not yet result in a synchronous exception (and similar for partial cacheline writes). That is left for a future patch. See CXL rev 3.0, sec 8.2.9.8.4.1 Get Poison list (Opcode 4300h) Kernel patches to use this interface here: https://lore.kernel.org/linux-cxl/cover.1665606782.git.alison.schofield@intel.com/ To inject poison using QMP (telnet to the QMP port) { "execute": "qmp_capabilities" } { "execute": "cxl-inject-poison", "arguments": { "path": "/machine/peripheral/cxl-pmem0", "start": 2048, "length": 256 } } Adjusted to select a device on your machine. Note that the poison list supported is kept short enough to avoid the complexity of state machine that is needed to handle the MORE flag. Reviewed-by: Fan Ni Reviewed-by: Ira Weiny Acked-by: Markus Armbruster Signed-off-by: Jonathan Cameron Message-Id: <20230526170010.574-3-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-mailbox-utils.c | 90 +++++++++++++++++++++++++++++++++++++ hw/mem/cxl_type3.c | 56 +++++++++++++++++++++++ hw/mem/cxl_type3_stubs.c | 6 +++ include/hw/cxl/cxl.h | 1 + include/hw/cxl/cxl_device.h | 20 +++++++++ qapi/cxl.json | 21 +++++++++ 6 files changed, 194 insertions(+) diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c index 702e16ca20..1f74b26ea2 100644 --- a/hw/cxl/cxl-mailbox-utils.c +++ b/hw/cxl/cxl-mailbox-utils.c @@ -62,6 +62,8 @@ enum { #define GET_PARTITION_INFO 0x0 #define GET_LSA 0x2 #define SET_LSA 0x3 + MEDIA_AND_POISON = 0x43, + #define GET_POISON_LIST 0x0 }; /* 8.2.8.4.5.1 Command Return Codes */ @@ -295,6 +297,10 @@ static CXLRetCode cmd_identify_memory_device(struct cxl_cmd *cmd, stq_le_p(&id->persistent_capacity, cxl_dstate->pmem_size / CXL_CAPACITY_MULTIPLIER); stq_le_p(&id->volatile_capacity, cxl_dstate->vmem_size / CXL_CAPACITY_MULTIPLIER); stl_le_p(&id->lsa_size, cvc->get_lsa_size(ct3d)); + /* 256 poison records */ + st24_le_p(id->poison_list_max_mer, 256); + /* No limit - so limited by main poison record limit */ + stw_le_p(&id->inject_poison_limit, 0); *len = sizeof(*id); return CXL_MBOX_SUCCESS; @@ -384,6 +390,88 @@ static CXLRetCode cmd_ccls_set_lsa(struct cxl_cmd *cmd, return CXL_MBOX_SUCCESS; } +/* + * This is very inefficient, but good enough for now! + * Also the payload will always fit, so no need to handle the MORE flag and + * make this stateful. We may want to allow longer poison lists to aid + * testing that kernel functionality. + */ +static CXLRetCode cmd_media_get_poison_list(struct cxl_cmd *cmd, + CXLDeviceState *cxl_dstate, + uint16_t *len) +{ + struct get_poison_list_pl { + uint64_t pa; + uint64_t length; + } QEMU_PACKED; + + struct get_poison_list_out_pl { + uint8_t flags; + uint8_t rsvd1; + uint64_t overflow_timestamp; + uint16_t count; + uint8_t rsvd2[0x14]; + struct { + uint64_t addr; + uint32_t length; + uint32_t resv; + } QEMU_PACKED records[]; + } QEMU_PACKED; + + struct get_poison_list_pl *in = (void *)cmd->payload; + struct get_poison_list_out_pl *out = (void *)cmd->payload; + CXLType3Dev *ct3d = container_of(cxl_dstate, CXLType3Dev, cxl_dstate); + uint16_t record_count = 0, i = 0; + uint64_t query_start, query_length; + CXLPoisonList *poison_list = &ct3d->poison_list; + CXLPoison *ent; + uint16_t out_pl_len; + + query_start = ldq_le_p(&in->pa); + /* 64 byte alignemnt required */ + if (query_start & 0x3f) { + return CXL_MBOX_INVALID_INPUT; + } + query_length = ldq_le_p(&in->length) * CXL_CACHE_LINE_SIZE; + + QLIST_FOREACH(ent, poison_list, node) { + /* Check for no overlap */ + if (ent->start >= query_start + query_length || + ent->start + ent->length <= query_start) { + continue; + } + record_count++; + } + out_pl_len = sizeof(*out) + record_count * sizeof(out->records[0]); + assert(out_pl_len <= CXL_MAILBOX_MAX_PAYLOAD_SIZE); + + memset(out, 0, out_pl_len); + QLIST_FOREACH(ent, poison_list, node) { + uint64_t start, stop; + + /* Check for no overlap */ + if (ent->start >= query_start + query_length || + ent->start + ent->length <= query_start) { + continue; + } + + /* Deal with overlap */ + start = MAX(ROUND_DOWN(ent->start, 64ull), query_start); + stop = MIN(ROUND_DOWN(ent->start, 64ull) + ent->length, + query_start + query_length); + stq_le_p(&out->records[i].addr, start | (ent->type & 0x7)); + stl_le_p(&out->records[i].length, (stop - start) / CXL_CACHE_LINE_SIZE); + i++; + } + if (ct3d->poison_list_overflowed) { + out->flags = (1 << 1); + stq_le_p(&out->overflow_timestamp, ct3d->poison_list_overflow_ts); + } + stw_le_p(&out->count, record_count); + *len = out_pl_len; + return CXL_MBOX_SUCCESS; +} + #define IMMEDIATE_CONFIG_CHANGE (1 << 1) #define IMMEDIATE_DATA_CHANGE (1 << 2) #define IMMEDIATE_POLICY_CHANGE (1 << 3) @@ -411,6 +499,8 @@ static struct cxl_cmd cxl_cmd_set[256][256] = { [CCLS][GET_LSA] = { "CCLS_GET_LSA", cmd_ccls_get_lsa, 8, 0 }, [CCLS][SET_LSA] = { "CCLS_SET_LSA", cmd_ccls_set_lsa, ~0, IMMEDIATE_CONFIG_CHANGE | IMMEDIATE_DATA_CHANGE }, + [MEDIA_AND_POISON][GET_POISON_LIST] = { "MEDIA_AND_POISON_GET_POISON_LIST", + cmd_media_get_poison_list, 16, 0 }, }; void cxl_process_mailbox(CXLDeviceState *cxl_dstate) diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c index 2adacbd01b..ab600735eb 100644 --- a/hw/mem/cxl_type3.c +++ b/hw/mem/cxl_type3.c @@ -947,6 +947,62 @@ static void set_lsa(CXLType3Dev *ct3d, const void *buf, uint64_t size, */ } +void cxl_set_poison_list_overflowed(CXLType3Dev *ct3d) +{ + ct3d->poison_list_overflowed = true; + ct3d->poison_list_overflow_ts = + cxl_device_get_timestamp(&ct3d->cxl_dstate); +} + +void qmp_cxl_inject_poison(const char *path, uint64_t start, uint64_t length, + Error **errp) +{ + Object *obj = object_resolve_path(path, NULL); + CXLType3Dev *ct3d; + CXLPoison *p; + + if (length % 64) { + error_setg(errp, "Poison injection must be in multiples of 64 bytes"); + return; + } + if (start % 64) { + error_setg(errp, "Poison start address must be 64 byte aligned"); + return; + } + if (!obj) { + error_setg(errp, "Unable to resolve path"); + return; + } + if (!object_dynamic_cast(obj, TYPE_CXL_TYPE3)) { + error_setg(errp, "Path does not point to a CXL type 3 device"); + return; + } + + ct3d = CXL_TYPE3(obj); + + QLIST_FOREACH(p, &ct3d->poison_list, node) { + if (((start >= p->start) && (start < p->start + p->length)) || + ((start + length > p->start) && + (start + length <= p->start + p->length))) { + error_setg(errp, "Overlap with existing poisoned region not supported"); + return; + } + } + + if (ct3d->poison_list_cnt == CXL_POISON_LIST_LIMIT) { + cxl_set_poison_list_overflowed(ct3d); + return; + } + + p = g_new0(CXLPoison, 1); + p->length = length; + p->start = start; + p->type = CXL_POISON_TYPE_INTERNAL; /* Different from injected via the mbox */ + + QLIST_INSERT_HEAD(&ct3d->poison_list, p, node); + ct3d->poison_list_cnt++; +} + /* For uncorrectable errors include support for multiple header recording */ void qmp_cxl_inject_uncorrectable_errors(const char *path, CXLUncorErrorRecordList *errors, diff --git a/hw/mem/cxl_type3_stubs.c b/hw/mem/cxl_type3_stubs.c index d574c58f9a..fd1166a610 100644 --- a/hw/mem/cxl_type3_stubs.c +++ b/hw/mem/cxl_type3_stubs.c @@ -3,6 +3,12 @@ #include "qapi/error.h" #include "qapi/qapi-commands-cxl.h" +void qmp_cxl_inject_poison(const char *path, uint64_t start, uint64_t length, + Error **errp) +{ + error_setg(errp, "CXL Type 3 support is not compiled in"); +} + void qmp_cxl_inject_uncorrectable_errors(const char *path, CXLUncorErrorRecordList *errors, Error **errp) diff --git a/include/hw/cxl/cxl.h b/include/hw/cxl/cxl.h index c453983e83..56c9e7676e 100644 --- a/include/hw/cxl/cxl.h +++ b/include/hw/cxl/cxl.h @@ -18,6 +18,7 @@ #include "cxl_component.h" #include "cxl_device.h" +#define CXL_CACHE_LINE_SIZE 64 #define CXL_COMPONENT_REG_BAR_IDX 0 #define CXL_DEVICE_REG_BAR_IDX 2 diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h index 02befda0f6..32c234ea91 100644 --- a/include/hw/cxl/cxl_device.h +++ b/include/hw/cxl/cxl_device.h @@ -242,6 +242,18 @@ typedef struct CXLError { typedef QTAILQ_HEAD(, CXLError) CXLErrorList; +typedef struct CXLPoison { + uint64_t start, length; + uint8_t type; +#define CXL_POISON_TYPE_EXTERNAL 0x1 +#define CXL_POISON_TYPE_INTERNAL 0x2 +#define CXL_POISON_TYPE_INJECTED 0x3 + QLIST_ENTRY(CXLPoison) node; +} CXLPoison; + +typedef QLIST_HEAD(, CXLPoison) CXLPoisonList; +#define CXL_POISON_LIST_LIMIT 256 + struct CXLType3Dev { /* Private */ PCIDevice parent_obj; @@ -264,6 +276,12 @@ struct CXLType3Dev { /* Error injection */ CXLErrorList error_list; + + /* Poison Injection - cache */ + CXLPoisonList poison_list; + unsigned int poison_list_cnt; + bool poison_list_overflowed; + uint64_t poison_list_overflow_ts; }; #define TYPE_CXL_TYPE3 "cxl-type3" @@ -289,4 +307,6 @@ MemTxResult cxl_type3_write(PCIDevice *d, hwaddr host_addr, uint64_t data, uint64_t cxl_device_get_timestamp(CXLDeviceState *cxlds); +void cxl_set_poison_list_overflowed(CXLType3Dev *ct3d); + #endif diff --git a/qapi/cxl.json b/qapi/cxl.json index b21c9b4c1c..ed1c7eea3a 100644 --- a/qapi/cxl.json +++ b/qapi/cxl.json @@ -5,6 +5,27 @@ # = CXL devices ## +## +# @cxl-inject-poison: +# +# Poison records indicate that a CXL memory device knows that a +# particular memory region may be corrupted. This may be because of +# locally detected errors (e.g. ECC failure) or poisoned writes +# received from other components in the system. This injection +# mechanism enables testing of the OS handling of poison records which +# may be queried via the CXL mailbox. +# +# @path: CXL type 3 device canonical QOM path +# +# @start: Start address; must be 64 byte aligned. +# +# @length: Length of poison to inject; must be a multiple of 64 bytes. +# +# Since: 8.1 +## +{ 'command': 'cxl-inject-poison', + 'data': { 'path': 'str', 'start': 'uint64', 'length': 'size' }} + ## # @CxlUncorErrorType: # From ff04b207a0525b3f77b6352ce3a2e610b11ea34f Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Fri, 26 May 2023 18:00:09 +0100 Subject: [PATCH 0047/1353] hw/cxl: Add poison injection via the mailbox. Very simple implementation to allow testing of corresponding kernel code. Note that for now we track each 64 byte section independently. Whilst a valid implementation choice, it may make sense to fuse entries so as to prove out more complex corners of the kernel code. Reviewed-by: Ira Weiny Reviewed-by: Fan Ni Signed-off-by: Jonathan Cameron Message-Id: <20230526170010.574-4-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-mailbox-utils.c | 42 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c index 1f74b26ea2..6c476ad7f4 100644 --- a/hw/cxl/cxl-mailbox-utils.c +++ b/hw/cxl/cxl-mailbox-utils.c @@ -64,6 +64,7 @@ enum { #define SET_LSA 0x3 MEDIA_AND_POISON = 0x43, #define GET_POISON_LIST 0x0 + #define INJECT_POISON 0x1 }; /* 8.2.8.4.5.1 Command Return Codes */ @@ -472,6 +473,45 @@ static CXLRetCode cmd_media_get_poison_list(struct cxl_cmd *cmd, return CXL_MBOX_SUCCESS; } +static CXLRetCode cmd_media_inject_poison(struct cxl_cmd *cmd, + CXLDeviceState *cxl_dstate, + uint16_t *len_unused) +{ + CXLType3Dev *ct3d = container_of(cxl_dstate, CXLType3Dev, cxl_dstate); + CXLPoisonList *poison_list = &ct3d->poison_list; + CXLPoison *ent; + struct inject_poison_pl { + uint64_t dpa; + }; + struct inject_poison_pl *in = (void *)cmd->payload; + uint64_t dpa = ldq_le_p(&in->dpa); + CXLPoison *p; + + QLIST_FOREACH(ent, poison_list, node) { + if (dpa >= ent->start && + dpa + CXL_CACHE_LINE_SIZE <= ent->start + ent->length) { + return CXL_MBOX_SUCCESS; + } + } + + if (ct3d->poison_list_cnt == CXL_POISON_LIST_LIMIT) { + return CXL_MBOX_INJECT_POISON_LIMIT; + } + p = g_new0(CXLPoison, 1); + + p->length = CXL_CACHE_LINE_SIZE; + p->start = dpa; + p->type = CXL_POISON_TYPE_INJECTED; + + /* + * Possible todo: Merge with existing entry if next to it and if same type + */ + QLIST_INSERT_HEAD(poison_list, p, node); + ct3d->poison_list_cnt++; + + return CXL_MBOX_SUCCESS; +} + #define IMMEDIATE_CONFIG_CHANGE (1 << 1) #define IMMEDIATE_DATA_CHANGE (1 << 2) #define IMMEDIATE_POLICY_CHANGE (1 << 3) @@ -501,6 +541,8 @@ static struct cxl_cmd cxl_cmd_set[256][256] = { ~0, IMMEDIATE_CONFIG_CHANGE | IMMEDIATE_DATA_CHANGE }, [MEDIA_AND_POISON][GET_POISON_LIST] = { "MEDIA_AND_POISON_GET_POISON_LIST", cmd_media_get_poison_list, 16, 0 }, + [MEDIA_AND_POISON][INJECT_POISON] = { "MEDIA_AND_POISON_INJECT_POISON", + cmd_media_inject_poison, 8, 0 }, }; void cxl_process_mailbox(CXLDeviceState *cxl_dstate) From 6bda41a69bdcee8ff7dcf75df2f9647ce55908ab Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Fri, 26 May 2023 18:00:10 +0100 Subject: [PATCH 0048/1353] hw/cxl: Add clear poison mailbox command support. Current implementation is very simple so many of the corner cases do not exist (e.g. fragmenting larger poison list entries) Reviewed-by: Fan Ni Reviewed-by: Ira Weiny Signed-off-by: Jonathan Cameron Message-Id: <20230526170010.574-5-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-mailbox-utils.c | 82 +++++++++++++++++++++++++++++++++++++ hw/mem/cxl_type3.c | 37 +++++++++++++++++ include/hw/cxl/cxl_device.h | 1 + 3 files changed, 120 insertions(+) diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c index 6c476ad7f4..e3401b6be8 100644 --- a/hw/cxl/cxl-mailbox-utils.c +++ b/hw/cxl/cxl-mailbox-utils.c @@ -65,6 +65,7 @@ enum { MEDIA_AND_POISON = 0x43, #define GET_POISON_LIST 0x0 #define INJECT_POISON 0x1 + #define CLEAR_POISON 0x2 }; /* 8.2.8.4.5.1 Command Return Codes */ @@ -512,6 +513,85 @@ static CXLRetCode cmd_media_inject_poison(struct cxl_cmd *cmd, return CXL_MBOX_SUCCESS; } +static CXLRetCode cmd_media_clear_poison(struct cxl_cmd *cmd, + CXLDeviceState *cxl_dstate, + uint16_t *len_unused) +{ + CXLType3Dev *ct3d = container_of(cxl_dstate, CXLType3Dev, cxl_dstate); + CXLPoisonList *poison_list = &ct3d->poison_list; + CXLType3Class *cvc = CXL_TYPE3_GET_CLASS(ct3d); + struct clear_poison_pl { + uint64_t dpa; + uint8_t data[64]; + }; + CXLPoison *ent; + uint64_t dpa; + + struct clear_poison_pl *in = (void *)cmd->payload; + + dpa = ldq_le_p(&in->dpa); + if (dpa + CXL_CACHE_LINE_SIZE > cxl_dstate->mem_size) { + return CXL_MBOX_INVALID_PA; + } + + /* Clearing a region with no poison is not an error so always do so */ + if (cvc->set_cacheline) { + if (!cvc->set_cacheline(ct3d, dpa, in->data)) { + return CXL_MBOX_INTERNAL_ERROR; + } + } + + QLIST_FOREACH(ent, poison_list, node) { + /* + * Test for contained in entry. Simpler than general case + * as clearing 64 bytes and entries 64 byte aligned + */ + if ((dpa >= ent->start) && (dpa < ent->start + ent->length)) { + break; + } + } + if (!ent) { + return CXL_MBOX_SUCCESS; + } + + QLIST_REMOVE(ent, node); + ct3d->poison_list_cnt--; + + if (dpa > ent->start) { + CXLPoison *frag; + /* Cannot overflow as replacing existing entry */ + + frag = g_new0(CXLPoison, 1); + + frag->start = ent->start; + frag->length = dpa - ent->start; + frag->type = ent->type; + + QLIST_INSERT_HEAD(poison_list, frag, node); + ct3d->poison_list_cnt++; + } + + if (dpa + CXL_CACHE_LINE_SIZE < ent->start + ent->length) { + CXLPoison *frag; + + if (ct3d->poison_list_cnt == CXL_POISON_LIST_LIMIT) { + cxl_set_poison_list_overflowed(ct3d); + } else { + frag = g_new0(CXLPoison, 1); + + frag->start = dpa + CXL_CACHE_LINE_SIZE; + frag->length = ent->start + ent->length - frag->start; + frag->type = ent->type; + QLIST_INSERT_HEAD(poison_list, frag, node); + ct3d->poison_list_cnt++; + } + } + /* Any fragments have been added, free original entry */ + g_free(ent); + + return CXL_MBOX_SUCCESS; +} + #define IMMEDIATE_CONFIG_CHANGE (1 << 1) #define IMMEDIATE_DATA_CHANGE (1 << 2) #define IMMEDIATE_POLICY_CHANGE (1 << 3) @@ -543,6 +623,8 @@ static struct cxl_cmd cxl_cmd_set[256][256] = { cmd_media_get_poison_list, 16, 0 }, [MEDIA_AND_POISON][INJECT_POISON] = { "MEDIA_AND_POISON_INJECT_POISON", cmd_media_inject_poison, 8, 0 }, + [MEDIA_AND_POISON][CLEAR_POISON] = { "MEDIA_AND_POISON_CLEAR_POISON", + cmd_media_clear_poison, 72, 0 }, }; void cxl_process_mailbox(CXLDeviceState *cxl_dstate) diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c index ab600735eb..d751803188 100644 --- a/hw/mem/cxl_type3.c +++ b/hw/mem/cxl_type3.c @@ -947,6 +947,42 @@ static void set_lsa(CXLType3Dev *ct3d, const void *buf, uint64_t size, */ } +static bool set_cacheline(CXLType3Dev *ct3d, uint64_t dpa_offset, uint8_t *data) +{ + MemoryRegion *vmr = NULL, *pmr = NULL; + AddressSpace *as; + + if (ct3d->hostvmem) { + vmr = host_memory_backend_get_memory(ct3d->hostvmem); + } + if (ct3d->hostpmem) { + pmr = host_memory_backend_get_memory(ct3d->hostpmem); + } + + if (!vmr && !pmr) { + return false; + } + + if (dpa_offset + CXL_CACHE_LINE_SIZE > ct3d->cxl_dstate.mem_size) { + return false; + } + + if (vmr) { + if (dpa_offset < memory_region_size(vmr)) { + as = &ct3d->hostvmem_as; + } else { + as = &ct3d->hostpmem_as; + dpa_offset -= memory_region_size(vmr); + } + } else { + as = &ct3d->hostpmem_as; + } + + address_space_write(as, dpa_offset, MEMTXATTRS_UNSPECIFIED, &data, + CXL_CACHE_LINE_SIZE); + return true; +} + void cxl_set_poison_list_overflowed(CXLType3Dev *ct3d) { ct3d->poison_list_overflowed = true; @@ -1168,6 +1204,7 @@ static void ct3_class_init(ObjectClass *oc, void *data) cvc->get_lsa_size = get_lsa_size; cvc->get_lsa = get_lsa; cvc->set_lsa = set_lsa; + cvc->set_cacheline = set_cacheline; } static const TypeInfo ct3d_info = { diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h index 32c234ea91..73328a52cf 100644 --- a/include/hw/cxl/cxl_device.h +++ b/include/hw/cxl/cxl_device.h @@ -298,6 +298,7 @@ struct CXLType3Class { uint64_t offset); void (*set_lsa)(CXLType3Dev *ct3d, const void *buf, uint64_t size, uint64_t offset); + bool (*set_cacheline)(CXLType3Dev *ct3d, uint64_t dpa_offset, uint8_t *data); }; MemTxResult cxl_type3_read(PCIDevice *d, hwaddr host_addr, uint64_t *data, From d7b84ddc3b99ae4dcac052a03817aeeab9d12514 Mon Sep 17 00:00:00 2001 From: Ira Weiny Date: Tue, 30 May 2023 14:35:57 +0100 Subject: [PATCH 0049/1353] hw/cxl/events: Add event status register The device status register block was defined. However, there were no individual registers nor any data wired up. Define the event status register [CXL 3.0; 8.2.8.3.1] as part of the device status register block. Wire up the register and initialize the event status for each log. To support CXL 3.0 the version of the device status register block needs to be 2. Change the macro to allow for setting the version. Signed-off-by: Ira Weiny Reviewed-by: Fan Ni Signed-off-by: Jonathan Cameron Message-Id: <20230530133603.16934-2-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-device-utils.c | 43 ++++++++++++++++++++++++++++++++----- include/hw/cxl/cxl_device.h | 23 +++++++++++++++++--- include/hw/cxl/cxl_events.h | 28 ++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 8 deletions(-) create mode 100644 include/hw/cxl/cxl_events.h diff --git a/hw/cxl/cxl-device-utils.c b/hw/cxl/cxl-device-utils.c index 86e1cea8ce..517f06d869 100644 --- a/hw/cxl/cxl-device-utils.c +++ b/hw/cxl/cxl-device-utils.c @@ -41,7 +41,20 @@ static uint64_t caps_reg_read(void *opaque, hwaddr offset, unsigned size) static uint64_t dev_reg_read(void *opaque, hwaddr offset, unsigned size) { - return 0; + CXLDeviceState *cxl_dstate = opaque; + + switch (size) { + case 1: + return cxl_dstate->dev_reg_state[offset]; + case 2: + return cxl_dstate->dev_reg_state16[offset / size]; + case 4: + return cxl_dstate->dev_reg_state32[offset / size]; + case 8: + return cxl_dstate->dev_reg_state64[offset / size]; + default: + g_assert_not_reached(); + } } static uint64_t mailbox_reg_read(void *opaque, hwaddr offset, unsigned size) @@ -236,7 +249,27 @@ void cxl_device_register_block_init(Object *obj, CXLDeviceState *cxl_dstate) &cxl_dstate->memory_device); } -static void device_reg_init_common(CXLDeviceState *cxl_dstate) { } +void cxl_event_set_status(CXLDeviceState *cxl_dstate, CXLEventLogType log_type, + bool available) +{ + if (available) { + cxl_dstate->event_status |= (1 << log_type); + } else { + cxl_dstate->event_status &= ~(1 << log_type); + } + + ARRAY_FIELD_DP64(cxl_dstate->dev_reg_state64, CXL_DEV_EVENT_STATUS, + EVENT_STATUS, cxl_dstate->event_status); +} + +static void device_reg_init_common(CXLDeviceState *cxl_dstate) +{ + CXLEventLogType log; + + for (log = 0; log < CXL_EVENT_TYPE_MAX; log++) { + cxl_event_set_status(cxl_dstate, log, false); + } +} static void mailbox_reg_init_common(CXLDeviceState *cxl_dstate) { @@ -258,13 +291,13 @@ void cxl_device_register_init_common(CXLDeviceState *cxl_dstate) ARRAY_FIELD_DP64(cap_hdrs, CXL_DEV_CAP_ARRAY, CAP_VERSION, 1); ARRAY_FIELD_DP64(cap_hdrs, CXL_DEV_CAP_ARRAY, CAP_COUNT, cap_count); - cxl_device_cap_init(cxl_dstate, DEVICE_STATUS, 1); + cxl_device_cap_init(cxl_dstate, DEVICE_STATUS, 1, 2); device_reg_init_common(cxl_dstate); - cxl_device_cap_init(cxl_dstate, MAILBOX, 2); + cxl_device_cap_init(cxl_dstate, MAILBOX, 2, 1); mailbox_reg_init_common(cxl_dstate); - cxl_device_cap_init(cxl_dstate, MEMORY_DEVICE, 0x4000); + cxl_device_cap_init(cxl_dstate, MEMORY_DEVICE, 0x4000, 1); memdev_reg_init_common(cxl_dstate); cxl_initialize_mailbox(cxl_dstate); diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h index 73328a52cf..16993f7098 100644 --- a/include/hw/cxl/cxl_device.h +++ b/include/hw/cxl/cxl_device.h @@ -13,6 +13,7 @@ #include "hw/cxl/cxl_component.h" #include "hw/pci/pci_device.h" #include "hw/register.h" +#include "hw/cxl/cxl_events.h" /* * The following is how a CXL device's Memory Device registers are laid out. @@ -86,7 +87,16 @@ typedef struct cxl_device_state { MemoryRegion device_registers; /* mmio for device capabilities array - 8.2.8.2 */ - MemoryRegion device; + struct { + MemoryRegion device; + union { + uint8_t dev_reg_state[CXL_DEVICE_STATUS_REGISTERS_LENGTH]; + uint16_t dev_reg_state16[CXL_DEVICE_STATUS_REGISTERS_LENGTH / 2]; + uint32_t dev_reg_state32[CXL_DEVICE_STATUS_REGISTERS_LENGTH / 4]; + uint64_t dev_reg_state64[CXL_DEVICE_STATUS_REGISTERS_LENGTH / 8]; + }; + uint64_t event_status; + }; MemoryRegion memory_device; struct { MemoryRegion caps; @@ -141,6 +151,9 @@ REG64(CXL_DEV_CAP_ARRAY, 0) /* Documented as 128 bit register but 64 byte access FIELD(CXL_DEV_CAP_ARRAY, CAP_VERSION, 16, 8) FIELD(CXL_DEV_CAP_ARRAY, CAP_COUNT, 32, 16) +void cxl_event_set_status(CXLDeviceState *cxl_dstate, CXLEventLogType log_type, + bool available); + /* * Helper macro to initialize capability headers for CXL devices. * @@ -175,7 +188,7 @@ CXL_DEVICE_CAPABILITY_HEADER_REGISTER(MEMORY_DEVICE, void cxl_initialize_mailbox(CXLDeviceState *cxl_dstate); void cxl_process_mailbox(CXLDeviceState *cxl_dstate); -#define cxl_device_cap_init(dstate, reg, cap_id) \ +#define cxl_device_cap_init(dstate, reg, cap_id, ver) \ do { \ uint32_t *cap_hdrs = dstate->caps_reg_state32; \ int which = R_CXL_DEV_##reg##_CAP_HDR0; \ @@ -183,7 +196,7 @@ void cxl_process_mailbox(CXLDeviceState *cxl_dstate); FIELD_DP32(cap_hdrs[which], CXL_DEV_##reg##_CAP_HDR0, \ CAP_ID, cap_id); \ cap_hdrs[which] = FIELD_DP32( \ - cap_hdrs[which], CXL_DEV_##reg##_CAP_HDR0, CAP_VERSION, 1); \ + cap_hdrs[which], CXL_DEV_##reg##_CAP_HDR0, CAP_VERSION, ver); \ cap_hdrs[which + 1] = \ FIELD_DP32(cap_hdrs[which + 1], CXL_DEV_##reg##_CAP_HDR1, \ CAP_OFFSET, CXL_##reg##_REGISTERS_OFFSET); \ @@ -192,6 +205,10 @@ void cxl_process_mailbox(CXLDeviceState *cxl_dstate); CAP_LENGTH, CXL_##reg##_REGISTERS_LENGTH); \ } while (0) +/* CXL 3.0 8.2.8.3.1 Event Status Register */ +REG64(CXL_DEV_EVENT_STATUS, 0) + FIELD(CXL_DEV_EVENT_STATUS, EVENT_STATUS, 0, 32) + /* CXL 2.0 8.2.8.4.3 Mailbox Capabilities Register */ REG32(CXL_DEV_MAILBOX_CAP, 0) FIELD(CXL_DEV_MAILBOX_CAP, PAYLOAD_SIZE, 0, 5) diff --git a/include/hw/cxl/cxl_events.h b/include/hw/cxl/cxl_events.h new file mode 100644 index 0000000000..aeb3b0590e --- /dev/null +++ b/include/hw/cxl/cxl_events.h @@ -0,0 +1,28 @@ +/* + * QEMU CXL Events + * + * Copyright (c) 2022 Intel + * + * This work is licensed under the terms of the GNU GPL, version 2. See the + * COPYING file in the top-level directory. + */ + +#ifndef CXL_EVENTS_H +#define CXL_EVENTS_H + +/* + * CXL rev 3.0 section 8.2.9.2.2; Table 8-49 + * + * Define these as the bit position for the event status register for ease of + * setting the status. + */ +typedef enum CXLEventLogType { + CXL_EVENT_TYPE_INFO = 0, + CXL_EVENT_TYPE_WARN = 1, + CXL_EVENT_TYPE_FAIL = 2, + CXL_EVENT_TYPE_FATAL = 3, + CXL_EVENT_TYPE_DYNAMIC_CAP = 4, + CXL_EVENT_TYPE_MAX +} CXLEventLogType; + +#endif /* CXL_EVENTS_H */ From 2f6b8c8f420d90579b29a96f46630e241dd2c1cc Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Tue, 30 May 2023 14:35:58 +0100 Subject: [PATCH 0050/1353] hw/cxl: Move CXLRetCode definition to cxl_device.h Following patches will need access to the mailbox return code type so move it to the header. Reviewed-by: Ira Weiny Reviewed-by: Fan Ni Signed-off-by: Jonathan Cameron Message-Id: <20230530133603.16934-3-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-mailbox-utils.c | 28 ---------------------------- include/hw/cxl/cxl_device.h | 28 ++++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c index e3401b6be8..d7e114aaae 100644 --- a/hw/cxl/cxl-mailbox-utils.c +++ b/hw/cxl/cxl-mailbox-utils.c @@ -68,34 +68,6 @@ enum { #define CLEAR_POISON 0x2 }; -/* 8.2.8.4.5.1 Command Return Codes */ -typedef enum { - CXL_MBOX_SUCCESS = 0x0, - CXL_MBOX_BG_STARTED = 0x1, - CXL_MBOX_INVALID_INPUT = 0x2, - CXL_MBOX_UNSUPPORTED = 0x3, - CXL_MBOX_INTERNAL_ERROR = 0x4, - CXL_MBOX_RETRY_REQUIRED = 0x5, - CXL_MBOX_BUSY = 0x6, - CXL_MBOX_MEDIA_DISABLED = 0x7, - CXL_MBOX_FW_XFER_IN_PROGRESS = 0x8, - CXL_MBOX_FW_XFER_OUT_OF_ORDER = 0x9, - CXL_MBOX_FW_AUTH_FAILED = 0xa, - CXL_MBOX_FW_INVALID_SLOT = 0xb, - CXL_MBOX_FW_ROLLEDBACK = 0xc, - CXL_MBOX_FW_REST_REQD = 0xd, - CXL_MBOX_INVALID_HANDLE = 0xe, - CXL_MBOX_INVALID_PA = 0xf, - CXL_MBOX_INJECT_POISON_LIMIT = 0x10, - CXL_MBOX_PERMANENT_MEDIA_FAILURE = 0x11, - CXL_MBOX_ABORTED = 0x12, - CXL_MBOX_INVALID_SECURITY_STATE = 0x13, - CXL_MBOX_INCORRECT_PASSPHRASE = 0x14, - CXL_MBOX_UNSUPPORTED_MAILBOX = 0x15, - CXL_MBOX_INVALID_PAYLOAD_LENGTH = 0x16, - CXL_MBOX_MAX = 0x17 -} CXLRetCode; - struct cxl_cmd; typedef CXLRetCode (*opcode_handler)(struct cxl_cmd *cmd, CXLDeviceState *cxl_dstate, uint16_t *len); diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h index 16993f7098..9f8ee85f8a 100644 --- a/include/hw/cxl/cxl_device.h +++ b/include/hw/cxl/cxl_device.h @@ -83,6 +83,34 @@ (CXL_DEVICE_CAP_REG_SIZE + CXL_DEVICE_STATUS_REGISTERS_LENGTH + \ CXL_MAILBOX_REGISTERS_LENGTH + CXL_MEMORY_DEVICE_REGISTERS_LENGTH) +/* 8.2.8.4.5.1 Command Return Codes */ +typedef enum { + CXL_MBOX_SUCCESS = 0x0, + CXL_MBOX_BG_STARTED = 0x1, + CXL_MBOX_INVALID_INPUT = 0x2, + CXL_MBOX_UNSUPPORTED = 0x3, + CXL_MBOX_INTERNAL_ERROR = 0x4, + CXL_MBOX_RETRY_REQUIRED = 0x5, + CXL_MBOX_BUSY = 0x6, + CXL_MBOX_MEDIA_DISABLED = 0x7, + CXL_MBOX_FW_XFER_IN_PROGRESS = 0x8, + CXL_MBOX_FW_XFER_OUT_OF_ORDER = 0x9, + CXL_MBOX_FW_AUTH_FAILED = 0xa, + CXL_MBOX_FW_INVALID_SLOT = 0xb, + CXL_MBOX_FW_ROLLEDBACK = 0xc, + CXL_MBOX_FW_REST_REQD = 0xd, + CXL_MBOX_INVALID_HANDLE = 0xe, + CXL_MBOX_INVALID_PA = 0xf, + CXL_MBOX_INJECT_POISON_LIMIT = 0x10, + CXL_MBOX_PERMANENT_MEDIA_FAILURE = 0x11, + CXL_MBOX_ABORTED = 0x12, + CXL_MBOX_INVALID_SECURITY_STATE = 0x13, + CXL_MBOX_INCORRECT_PASSPHRASE = 0x14, + CXL_MBOX_UNSUPPORTED_MAILBOX = 0x15, + CXL_MBOX_INVALID_PAYLOAD_LENGTH = 0x16, + CXL_MBOX_MAX = 0x17 +} CXLRetCode; + typedef struct cxl_device_state { MemoryRegion device_registers; From 22d7e3be0714f39bae43bd0c05f6e6d149a47b13 Mon Sep 17 00:00:00 2001 From: Ira Weiny Date: Tue, 30 May 2023 14:35:59 +0100 Subject: [PATCH 0051/1353] hw/cxl/events: Wire up get/clear event mailbox commands CXL testing is benefited from an artificial event log injection mechanism. Add an event log infrastructure to insert, get, and clear events from the various logs available on a device. Replace the stubbed out CXL Get/Clear Event mailbox commands with commands that operate on the new infrastructure. Signed-off-by: Ira Weiny Reviewed-by: Fan Ni Signed-off-by: Jonathan Cameron Message-Id: <20230530133603.16934-4-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-events.c | 217 ++++++++++++++++++++++++++++++++++++ hw/cxl/cxl-mailbox-utils.c | 40 ++++++- hw/cxl/meson.build | 1 + hw/mem/cxl_type3.c | 1 + include/hw/cxl/cxl_device.h | 25 +++++ include/hw/cxl/cxl_events.h | 55 +++++++++ 6 files changed, 337 insertions(+), 2 deletions(-) create mode 100644 hw/cxl/cxl-events.c diff --git a/hw/cxl/cxl-events.c b/hw/cxl/cxl-events.c new file mode 100644 index 0000000000..5da1b76b97 --- /dev/null +++ b/hw/cxl/cxl-events.c @@ -0,0 +1,217 @@ +/* + * CXL Event processing + * + * Copyright(C) 2023 Intel Corporation. + * + * This work is licensed under the terms of the GNU GPL, version 2. See the + * COPYING file in the top-level directory. + */ + +#include + +#include "qemu/osdep.h" +#include "qemu/bswap.h" +#include "qemu/typedefs.h" +#include "qemu/error-report.h" +#include "hw/cxl/cxl.h" +#include "hw/cxl/cxl_events.h" + +/* Artificial limit on the number of events a log can hold */ +#define CXL_TEST_EVENT_OVERFLOW 8 + +static void reset_overflow(CXLEventLog *log) +{ + log->overflow_err_count = 0; + log->first_overflow_timestamp = 0; + log->last_overflow_timestamp = 0; +} + +void cxl_event_init(CXLDeviceState *cxlds) +{ + CXLEventLog *log; + int i; + + for (i = 0; i < CXL_EVENT_TYPE_MAX; i++) { + log = &cxlds->event_logs[i]; + log->next_handle = 1; + log->overflow_err_count = 0; + log->first_overflow_timestamp = 0; + log->last_overflow_timestamp = 0; + qemu_mutex_init(&log->lock); + QSIMPLEQ_INIT(&log->events); + } +} + +static CXLEvent *cxl_event_get_head(CXLEventLog *log) +{ + return QSIMPLEQ_FIRST(&log->events); +} + +static CXLEvent *cxl_event_get_next(CXLEvent *entry) +{ + return QSIMPLEQ_NEXT(entry, node); +} + +static int cxl_event_count(CXLEventLog *log) +{ + CXLEvent *event; + int rc = 0; + + QSIMPLEQ_FOREACH(event, &log->events, node) { + rc++; + } + + return rc; +} + +static bool cxl_event_empty(CXLEventLog *log) +{ + return QSIMPLEQ_EMPTY(&log->events); +} + +static void cxl_event_delete_head(CXLDeviceState *cxlds, + CXLEventLogType log_type, + CXLEventLog *log) +{ + CXLEvent *entry = cxl_event_get_head(log); + + reset_overflow(log); + QSIMPLEQ_REMOVE_HEAD(&log->events, node); + if (cxl_event_empty(log)) { + cxl_event_set_status(cxlds, log_type, false); + } + g_free(entry); +} + +/* + * return true if an interrupt should be generated as a result + * of inserting this event. + */ +bool cxl_event_insert(CXLDeviceState *cxlds, CXLEventLogType log_type, + CXLEventRecordRaw *event) +{ + uint64_t time; + CXLEventLog *log; + CXLEvent *entry; + + if (log_type >= CXL_EVENT_TYPE_MAX) { + return false; + } + + time = cxl_device_get_timestamp(cxlds); + + log = &cxlds->event_logs[log_type]; + + QEMU_LOCK_GUARD(&log->lock); + + if (cxl_event_count(log) >= CXL_TEST_EVENT_OVERFLOW) { + if (log->overflow_err_count == 0) { + log->first_overflow_timestamp = time; + } + log->overflow_err_count++; + log->last_overflow_timestamp = time; + return false; + } + + entry = g_new0(CXLEvent, 1); + + memcpy(&entry->data, event, sizeof(*event)); + + entry->data.hdr.handle = cpu_to_le16(log->next_handle); + log->next_handle++; + /* 0 handle is never valid */ + if (log->next_handle == 0) { + log->next_handle++; + } + entry->data.hdr.timestamp = cpu_to_le64(time); + + QSIMPLEQ_INSERT_TAIL(&log->events, entry, node); + cxl_event_set_status(cxlds, log_type, true); + + /* Count went from 0 to 1 */ + return cxl_event_count(log) == 1; +} + +CXLRetCode cxl_event_get_records(CXLDeviceState *cxlds, CXLGetEventPayload *pl, + uint8_t log_type, int max_recs, + uint16_t *len) +{ + CXLEventLog *log; + CXLEvent *entry; + uint16_t nr; + + if (log_type >= CXL_EVENT_TYPE_MAX) { + return CXL_MBOX_INVALID_INPUT; + } + + log = &cxlds->event_logs[log_type]; + + QEMU_LOCK_GUARD(&log->lock); + + entry = cxl_event_get_head(log); + for (nr = 0; entry && nr < max_recs; nr++) { + memcpy(&pl->records[nr], &entry->data, CXL_EVENT_RECORD_SIZE); + entry = cxl_event_get_next(entry); + } + + if (!cxl_event_empty(log)) { + pl->flags |= CXL_GET_EVENT_FLAG_MORE_RECORDS; + } + + if (log->overflow_err_count) { + pl->flags |= CXL_GET_EVENT_FLAG_OVERFLOW; + pl->overflow_err_count = cpu_to_le16(log->overflow_err_count); + pl->first_overflow_timestamp = cpu_to_le64(log->first_overflow_timestamp); + pl->last_overflow_timestamp = cpu_to_le64(log->last_overflow_timestamp); + } + + pl->record_count = cpu_to_le16(nr); + *len = CXL_EVENT_PAYLOAD_HDR_SIZE + (CXL_EVENT_RECORD_SIZE * nr); + + return CXL_MBOX_SUCCESS; +} + +CXLRetCode cxl_event_clear_records(CXLDeviceState *cxlds, CXLClearEventPayload *pl) +{ + CXLEventLog *log; + uint8_t log_type; + CXLEvent *entry; + int nr; + + log_type = pl->event_log; + + if (log_type >= CXL_EVENT_TYPE_MAX) { + return CXL_MBOX_INVALID_INPUT; + } + + log = &cxlds->event_logs[log_type]; + + QEMU_LOCK_GUARD(&log->lock); + /* + * Must itterate the queue twice. + * "The device shall verify the event record handles specified in the input + * payload are in temporal order. If the device detects an older event + * record that will not be cleared when Clear Event Records is executed, + * the device shall return the Invalid Handle return code and shall not + * clear any of the specified event records." + * -- CXL 3.0 8.2.9.2.3 + */ + entry = cxl_event_get_head(log); + for (nr = 0; entry && nr < pl->nr_recs; nr++) { + uint16_t handle = pl->handle[nr]; + + /* NOTE: Both handles are little endian. */ + if (handle == 0 || entry->data.hdr.handle != handle) { + return CXL_MBOX_INVALID_INPUT; + } + entry = cxl_event_get_next(entry); + } + + entry = cxl_event_get_head(log); + for (nr = 0; entry && nr < pl->nr_recs; nr++) { + cxl_event_delete_head(cxlds, log_type, log); + entry = cxl_event_get_head(log); + } + + return CXL_MBOX_SUCCESS; +} diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c index d7e114aaae..3f46538048 100644 --- a/hw/cxl/cxl-mailbox-utils.c +++ b/hw/cxl/cxl-mailbox-utils.c @@ -9,6 +9,7 @@ #include "qemu/osdep.h" #include "hw/cxl/cxl.h" +#include "hw/cxl/cxl_events.h" #include "hw/pci/pci.h" #include "qemu/cutils.h" #include "qemu/log.h" @@ -95,11 +96,46 @@ struct cxl_cmd { return CXL_MBOX_SUCCESS; \ } -DEFINE_MAILBOX_HANDLER_ZEROED(events_get_records, 0x20); -DEFINE_MAILBOX_HANDLER_NOP(events_clear_records); DEFINE_MAILBOX_HANDLER_ZEROED(events_get_interrupt_policy, 4); DEFINE_MAILBOX_HANDLER_NOP(events_set_interrupt_policy); +static CXLRetCode cmd_events_get_records(struct cxl_cmd *cmd, + CXLDeviceState *cxlds, + uint16_t *len) +{ + CXLGetEventPayload *pl; + uint8_t log_type; + int max_recs; + + if (cmd->in < sizeof(log_type)) { + return CXL_MBOX_INVALID_INPUT; + } + + log_type = *((uint8_t *)cmd->payload); + + pl = (CXLGetEventPayload *)cmd->payload; + memset(pl, 0, sizeof(*pl)); + + max_recs = (cxlds->payload_size - CXL_EVENT_PAYLOAD_HDR_SIZE) / + CXL_EVENT_RECORD_SIZE; + if (max_recs > 0xFFFF) { + max_recs = 0xFFFF; + } + + return cxl_event_get_records(cxlds, pl, log_type, max_recs, len); +} + +static CXLRetCode cmd_events_clear_records(struct cxl_cmd *cmd, + CXLDeviceState *cxlds, + uint16_t *len) +{ + CXLClearEventPayload *pl; + + pl = (CXLClearEventPayload *)cmd->payload; + *len = 0; + return cxl_event_clear_records(cxlds, pl); +} + /* 8.2.9.2.1 */ static CXLRetCode cmd_firmware_update_get_info(struct cxl_cmd *cmd, CXLDeviceState *cxl_dstate, diff --git a/hw/cxl/meson.build b/hw/cxl/meson.build index 1f9aa2ea1f..e261ff3881 100644 --- a/hw/cxl/meson.build +++ b/hw/cxl/meson.build @@ -5,6 +5,7 @@ system_ss.add(when: 'CONFIG_CXL', 'cxl-mailbox-utils.c', 'cxl-host.c', 'cxl-cdat.c', + 'cxl-events.c', ), if_false: files( 'cxl-host-stubs.c', diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c index d751803188..ec5a384885 100644 --- a/hw/mem/cxl_type3.c +++ b/hw/mem/cxl_type3.c @@ -724,6 +724,7 @@ static void ct3_realize(PCIDevice *pci_dev, Error **errp) goto err_release_cdat; } + cxl_event_init(&ct3d->cxl_dstate); return; err_release_cdat: diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h index 9f8ee85f8a..d3aec1bc0e 100644 --- a/include/hw/cxl/cxl_device.h +++ b/include/hw/cxl/cxl_device.h @@ -111,6 +111,20 @@ typedef enum { CXL_MBOX_MAX = 0x17 } CXLRetCode; +typedef struct CXLEvent { + CXLEventRecordRaw data; + QSIMPLEQ_ENTRY(CXLEvent) node; +} CXLEvent; + +typedef struct CXLEventLog { + uint16_t next_handle; + uint16_t overflow_err_count; + uint64_t first_overflow_timestamp; + uint64_t last_overflow_timestamp; + QemuMutex lock; + QSIMPLEQ_HEAD(, CXLEvent) events; +} CXLEventLog; + typedef struct cxl_device_state { MemoryRegion device_registers; @@ -161,6 +175,8 @@ typedef struct cxl_device_state { uint64_t mem_size; uint64_t pmem_size; uint64_t vmem_size; + + CXLEventLog event_logs[CXL_EVENT_TYPE_MAX]; } CXLDeviceState; /* Initialize the register block for a device */ @@ -353,6 +369,15 @@ MemTxResult cxl_type3_write(PCIDevice *d, hwaddr host_addr, uint64_t data, uint64_t cxl_device_get_timestamp(CXLDeviceState *cxlds); +void cxl_event_init(CXLDeviceState *cxlds); +bool cxl_event_insert(CXLDeviceState *cxlds, CXLEventLogType log_type, + CXLEventRecordRaw *event); +CXLRetCode cxl_event_get_records(CXLDeviceState *cxlds, CXLGetEventPayload *pl, + uint8_t log_type, int max_recs, + uint16_t *len); +CXLRetCode cxl_event_clear_records(CXLDeviceState *cxlds, + CXLClearEventPayload *pl); + void cxl_set_poison_list_overflowed(CXLType3Dev *ct3d); #endif diff --git a/include/hw/cxl/cxl_events.h b/include/hw/cxl/cxl_events.h index aeb3b0590e..d4aaa894f1 100644 --- a/include/hw/cxl/cxl_events.h +++ b/include/hw/cxl/cxl_events.h @@ -10,6 +10,8 @@ #ifndef CXL_EVENTS_H #define CXL_EVENTS_H +#include "qemu/uuid.h" + /* * CXL rev 3.0 section 8.2.9.2.2; Table 8-49 * @@ -25,4 +27,57 @@ typedef enum CXLEventLogType { CXL_EVENT_TYPE_MAX } CXLEventLogType; +/* + * Common Event Record Format + * CXL rev 3.0 section 8.2.9.2.1; Table 8-42 + */ +#define CXL_EVENT_REC_HDR_RES_LEN 0xf +typedef struct CXLEventRecordHdr { + QemuUUID id; + uint8_t length; + uint8_t flags[3]; + uint16_t handle; + uint16_t related_handle; + uint64_t timestamp; + uint8_t maint_op_class; + uint8_t reserved[CXL_EVENT_REC_HDR_RES_LEN]; +} QEMU_PACKED CXLEventRecordHdr; + +#define CXL_EVENT_RECORD_DATA_LENGTH 0x50 +typedef struct CXLEventRecordRaw { + CXLEventRecordHdr hdr; + uint8_t data[CXL_EVENT_RECORD_DATA_LENGTH]; +} QEMU_PACKED CXLEventRecordRaw; +#define CXL_EVENT_RECORD_SIZE (sizeof(CXLEventRecordRaw)) + +/* + * Get Event Records output payload + * CXL rev 3.0 section 8.2.9.2.2; Table 8-50 + */ +#define CXL_GET_EVENT_FLAG_OVERFLOW BIT(0) +#define CXL_GET_EVENT_FLAG_MORE_RECORDS BIT(1) +typedef struct CXLGetEventPayload { + uint8_t flags; + uint8_t reserved1; + uint16_t overflow_err_count; + uint64_t first_overflow_timestamp; + uint64_t last_overflow_timestamp; + uint16_t record_count; + uint8_t reserved2[0xa]; + CXLEventRecordRaw records[]; +} QEMU_PACKED CXLGetEventPayload; +#define CXL_EVENT_PAYLOAD_HDR_SIZE (sizeof(CXLGetEventPayload)) + +/* + * Clear Event Records input payload + * CXL rev 3.0 section 8.2.9.2.3; Table 8-51 + */ +typedef struct CXLClearEventPayload { + uint8_t event_log; /* CXLEventLogType */ + uint8_t clear_flags; + uint8_t nr_recs; + uint8_t reserved[3]; + uint16_t handle[]; +} CXLClearEventPayload; + #endif /* CXL_EVENTS_H */ From 6676bb973ba53d60886b06213ec98fbd736d66a1 Mon Sep 17 00:00:00 2001 From: Ira Weiny Date: Tue, 30 May 2023 14:36:00 +0100 Subject: [PATCH 0052/1353] hw/cxl/events: Add event interrupt support Replace the stubbed out CXL Get/Set Event interrupt policy mailbox commands. Enable those commands to control interrupts for each of the event log types. Skip the standard input mailbox length on the Set command due to DCD being optional. Perform the checks separately. Signed-off-by: Ira Weiny Reviewed-by: Fan Ni Reviewed-by: Davidlohr Bueso Signed-off-by: Jonathan Cameron Message-Id: <20230530133603.16934-5-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-events.c | 33 ++++++++++- hw/cxl/cxl-mailbox-utils.c | 106 +++++++++++++++++++++++++++++------- hw/mem/cxl_type3.c | 4 +- include/hw/cxl/cxl_device.h | 6 +- include/hw/cxl/cxl_events.h | 23 ++++++++ 5 files changed, 147 insertions(+), 25 deletions(-) diff --git a/hw/cxl/cxl-events.c b/hw/cxl/cxl-events.c index 5da1b76b97..d161d57456 100644 --- a/hw/cxl/cxl-events.c +++ b/hw/cxl/cxl-events.c @@ -13,6 +13,8 @@ #include "qemu/bswap.h" #include "qemu/typedefs.h" #include "qemu/error-report.h" +#include "hw/pci/msi.h" +#include "hw/pci/msix.h" #include "hw/cxl/cxl.h" #include "hw/cxl/cxl_events.h" @@ -26,7 +28,7 @@ static void reset_overflow(CXLEventLog *log) log->last_overflow_timestamp = 0; } -void cxl_event_init(CXLDeviceState *cxlds) +void cxl_event_init(CXLDeviceState *cxlds, int start_msg_num) { CXLEventLog *log; int i; @@ -37,9 +39,16 @@ void cxl_event_init(CXLDeviceState *cxlds) log->overflow_err_count = 0; log->first_overflow_timestamp = 0; log->last_overflow_timestamp = 0; + log->irq_enabled = false; + log->irq_vec = start_msg_num++; qemu_mutex_init(&log->lock); QSIMPLEQ_INIT(&log->events); } + + /* Override -- Dynamic Capacity uses the same vector as info */ + cxlds->event_logs[CXL_EVENT_TYPE_DYNAMIC_CAP].irq_vec = + cxlds->event_logs[CXL_EVENT_TYPE_INFO].irq_vec; + } static CXLEvent *cxl_event_get_head(CXLEventLog *log) @@ -215,3 +224,25 @@ CXLRetCode cxl_event_clear_records(CXLDeviceState *cxlds, CXLClearEventPayload * return CXL_MBOX_SUCCESS; } + +void cxl_event_irq_assert(CXLType3Dev *ct3d) +{ + CXLDeviceState *cxlds = &ct3d->cxl_dstate; + PCIDevice *pdev = &ct3d->parent_obj; + int i; + + for (i = 0; i < CXL_EVENT_TYPE_MAX; i++) { + CXLEventLog *log = &cxlds->event_logs[i]; + + if (!log->irq_enabled || cxl_event_empty(log)) { + continue; + } + + /* Notifies interrupt, legacy IRQ is not supported */ + if (msix_enabled(pdev)) { + msix_notify(pdev, log->irq_vec); + } else if (msi_enabled(pdev)) { + msi_notify(pdev, log->irq_vec); + } + } +} diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c index 3f46538048..02f9b5a870 100644 --- a/hw/cxl/cxl-mailbox-utils.c +++ b/hw/cxl/cxl-mailbox-utils.c @@ -80,25 +80,6 @@ struct cxl_cmd { uint8_t *payload; }; -#define DEFINE_MAILBOX_HANDLER_ZEROED(name, size) \ - uint16_t __zero##name = size; \ - static CXLRetCode cmd_##name(struct cxl_cmd *cmd, \ - CXLDeviceState *cxl_dstate, uint16_t *len) \ - { \ - *len = __zero##name; \ - memset(cmd->payload, 0, *len); \ - return CXL_MBOX_SUCCESS; \ - } -#define DEFINE_MAILBOX_HANDLER_NOP(name) \ - static CXLRetCode cmd_##name(struct cxl_cmd *cmd, \ - CXLDeviceState *cxl_dstate, uint16_t *len) \ - { \ - return CXL_MBOX_SUCCESS; \ - } - -DEFINE_MAILBOX_HANDLER_ZEROED(events_get_interrupt_policy, 4); -DEFINE_MAILBOX_HANDLER_NOP(events_set_interrupt_policy); - static CXLRetCode cmd_events_get_records(struct cxl_cmd *cmd, CXLDeviceState *cxlds, uint16_t *len) @@ -136,6 +117,88 @@ static CXLRetCode cmd_events_clear_records(struct cxl_cmd *cmd, return cxl_event_clear_records(cxlds, pl); } +static CXLRetCode cmd_events_get_interrupt_policy(struct cxl_cmd *cmd, + CXLDeviceState *cxlds, + uint16_t *len) +{ + CXLEventInterruptPolicy *policy; + CXLEventLog *log; + + policy = (CXLEventInterruptPolicy *)cmd->payload; + memset(policy, 0, sizeof(*policy)); + + log = &cxlds->event_logs[CXL_EVENT_TYPE_INFO]; + if (log->irq_enabled) { + policy->info_settings = CXL_EVENT_INT_SETTING(log->irq_vec); + } + + log = &cxlds->event_logs[CXL_EVENT_TYPE_WARN]; + if (log->irq_enabled) { + policy->warn_settings = CXL_EVENT_INT_SETTING(log->irq_vec); + } + + log = &cxlds->event_logs[CXL_EVENT_TYPE_FAIL]; + if (log->irq_enabled) { + policy->failure_settings = CXL_EVENT_INT_SETTING(log->irq_vec); + } + + log = &cxlds->event_logs[CXL_EVENT_TYPE_FATAL]; + if (log->irq_enabled) { + policy->fatal_settings = CXL_EVENT_INT_SETTING(log->irq_vec); + } + + log = &cxlds->event_logs[CXL_EVENT_TYPE_DYNAMIC_CAP]; + if (log->irq_enabled) { + /* Dynamic Capacity borrows the same vector as info */ + policy->dyn_cap_settings = CXL_INT_MSI_MSIX; + } + + *len = sizeof(*policy); + return CXL_MBOX_SUCCESS; +} + +static CXLRetCode cmd_events_set_interrupt_policy(struct cxl_cmd *cmd, + CXLDeviceState *cxlds, + uint16_t *len) +{ + CXLEventInterruptPolicy *policy; + CXLEventLog *log; + + if (*len < CXL_EVENT_INT_SETTING_MIN_LEN) { + return CXL_MBOX_INVALID_PAYLOAD_LENGTH; + } + + policy = (CXLEventInterruptPolicy *)cmd->payload; + + log = &cxlds->event_logs[CXL_EVENT_TYPE_INFO]; + log->irq_enabled = (policy->info_settings & CXL_EVENT_INT_MODE_MASK) == + CXL_INT_MSI_MSIX; + + log = &cxlds->event_logs[CXL_EVENT_TYPE_WARN]; + log->irq_enabled = (policy->warn_settings & CXL_EVENT_INT_MODE_MASK) == + CXL_INT_MSI_MSIX; + + log = &cxlds->event_logs[CXL_EVENT_TYPE_FAIL]; + log->irq_enabled = (policy->failure_settings & CXL_EVENT_INT_MODE_MASK) == + CXL_INT_MSI_MSIX; + + log = &cxlds->event_logs[CXL_EVENT_TYPE_FATAL]; + log->irq_enabled = (policy->fatal_settings & CXL_EVENT_INT_MODE_MASK) == + CXL_INT_MSI_MSIX; + + /* DCD is optional */ + if (*len < sizeof(*policy)) { + return CXL_MBOX_SUCCESS; + } + + log = &cxlds->event_logs[CXL_EVENT_TYPE_DYNAMIC_CAP]; + log->irq_enabled = (policy->dyn_cap_settings & CXL_EVENT_INT_MODE_MASK) == + CXL_INT_MSI_MSIX; + + *len = sizeof(*policy); + return CXL_MBOX_SUCCESS; +} + /* 8.2.9.2.1 */ static CXLRetCode cmd_firmware_update_get_info(struct cxl_cmd *cmd, CXLDeviceState *cxl_dstate, @@ -611,9 +674,10 @@ static struct cxl_cmd cxl_cmd_set[256][256] = { [EVENTS][CLEAR_RECORDS] = { "EVENTS_CLEAR_RECORDS", cmd_events_clear_records, ~0, IMMEDIATE_LOG_CHANGE }, [EVENTS][GET_INTERRUPT_POLICY] = { "EVENTS_GET_INTERRUPT_POLICY", - cmd_events_get_interrupt_policy, 0, 0 }, + cmd_events_get_interrupt_policy, 0, 0 }, [EVENTS][SET_INTERRUPT_POLICY] = { "EVENTS_SET_INTERRUPT_POLICY", - cmd_events_set_interrupt_policy, 4, IMMEDIATE_CONFIG_CHANGE }, + cmd_events_set_interrupt_policy, + ~0, IMMEDIATE_CONFIG_CHANGE }, [FIRMWARE_UPDATE][GET_INFO] = { "FIRMWARE_UPDATE_GET_INFO", cmd_firmware_update_get_info, 0, 0 }, [TIMESTAMP][GET] = { "TIMESTAMP_GET", cmd_timestamp_get, 0, 0 }, diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c index ec5a384885..c9e347f42b 100644 --- a/hw/mem/cxl_type3.c +++ b/hw/mem/cxl_type3.c @@ -659,7 +659,7 @@ static void ct3_realize(PCIDevice *pci_dev, Error **errp) ComponentRegisters *regs = &cxl_cstate->crb; MemoryRegion *mr = ®s->component_registers; uint8_t *pci_conf = pci_dev->config; - unsigned short msix_num = 1; + unsigned short msix_num = 6; int i, rc; QTAILQ_INIT(&ct3d->error_list); @@ -723,8 +723,8 @@ static void ct3_realize(PCIDevice *pci_dev, Error **errp) if (rc) { goto err_release_cdat; } + cxl_event_init(&ct3d->cxl_dstate, 2); - cxl_event_init(&ct3d->cxl_dstate); return; err_release_cdat: diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h index d3aec1bc0e..1978730fba 100644 --- a/include/hw/cxl/cxl_device.h +++ b/include/hw/cxl/cxl_device.h @@ -121,6 +121,8 @@ typedef struct CXLEventLog { uint16_t overflow_err_count; uint64_t first_overflow_timestamp; uint64_t last_overflow_timestamp; + bool irq_enabled; + int irq_vec; QemuMutex lock; QSIMPLEQ_HEAD(, CXLEvent) events; } CXLEventLog; @@ -369,7 +371,7 @@ MemTxResult cxl_type3_write(PCIDevice *d, hwaddr host_addr, uint64_t data, uint64_t cxl_device_get_timestamp(CXLDeviceState *cxlds); -void cxl_event_init(CXLDeviceState *cxlds); +void cxl_event_init(CXLDeviceState *cxlds, int start_msg_num); bool cxl_event_insert(CXLDeviceState *cxlds, CXLEventLogType log_type, CXLEventRecordRaw *event); CXLRetCode cxl_event_get_records(CXLDeviceState *cxlds, CXLGetEventPayload *pl, @@ -378,6 +380,8 @@ CXLRetCode cxl_event_get_records(CXLDeviceState *cxlds, CXLGetEventPayload *pl, CXLRetCode cxl_event_clear_records(CXLDeviceState *cxlds, CXLClearEventPayload *pl); +void cxl_event_irq_assert(CXLType3Dev *ct3d); + void cxl_set_poison_list_overflowed(CXLType3Dev *ct3d); #endif diff --git a/include/hw/cxl/cxl_events.h b/include/hw/cxl/cxl_events.h index d4aaa894f1..4bf8b7aa08 100644 --- a/include/hw/cxl/cxl_events.h +++ b/include/hw/cxl/cxl_events.h @@ -80,4 +80,27 @@ typedef struct CXLClearEventPayload { uint16_t handle[]; } CXLClearEventPayload; +/** + * Event Interrupt Policy + * + * CXL rev 3.0 section 8.2.9.2.4; Table 8-52 + */ +typedef enum CXLEventIntMode { + CXL_INT_NONE = 0x00, + CXL_INT_MSI_MSIX = 0x01, + CXL_INT_FW = 0x02, + CXL_INT_RES = 0x03, +} CXLEventIntMode; +#define CXL_EVENT_INT_MODE_MASK 0x3 +#define CXL_EVENT_INT_SETTING(vector) ((((uint8_t)vector & 0xf) << 4) | CXL_INT_MSI_MSIX) +typedef struct CXLEventInterruptPolicy { + uint8_t info_settings; + uint8_t warn_settings; + uint8_t failure_settings; + uint8_t fatal_settings; + uint8_t dyn_cap_settings; +} QEMU_PACKED CXLEventInterruptPolicy; +/* DCD is optional but other fields are not */ +#define CXL_EVENT_INT_SETTING_MIN_LEN 4 + #endif /* CXL_EVENTS_H */ From ea9b6d647f2f4708708d19ba1cb17d332d3eff06 Mon Sep 17 00:00:00 2001 From: Ira Weiny Date: Tue, 30 May 2023 14:36:01 +0100 Subject: [PATCH 0053/1353] hw/cxl/events: Add injection of General Media Events To facilitate testing provide a QMP command to inject a general media event. The event can be added to the log specified. Signed-off-by: Ira Weiny Reviewed-by: Fan Ni Acked-by: Markus Armbruster Signed-off-by: Jonathan Cameron Message-Id: <20230530133603.16934-6-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/mem/cxl_type3.c | 111 ++++++++++++++++++++++++++++++++++++ hw/mem/cxl_type3_stubs.c | 10 ++++ include/hw/cxl/cxl_events.h | 20 +++++++ qapi/cxl.json | 74 ++++++++++++++++++++++++ 4 files changed, 215 insertions(+) diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c index c9e347f42b..b1618779d2 100644 --- a/hw/mem/cxl_type3.c +++ b/hw/mem/cxl_type3.c @@ -1181,6 +1181,117 @@ void qmp_cxl_inject_correctable_error(const char *path, CxlCorErrorType type, pcie_aer_inject_error(PCI_DEVICE(obj), &err); } +static void cxl_assign_event_header(CXLEventRecordHdr *hdr, + const QemuUUID *uuid, uint32_t flags, + uint8_t length, uint64_t timestamp) +{ + st24_le_p(&hdr->flags, flags); + hdr->length = length; + memcpy(&hdr->id, uuid, sizeof(hdr->id)); + stq_le_p(&hdr->timestamp, timestamp); +} + +static const QemuUUID gen_media_uuid = { + .data = UUID(0xfbcd0a77, 0xc260, 0x417f, + 0x85, 0xa9, 0x08, 0x8b, 0x16, 0x21, 0xeb, 0xa6), +}; + +#define CXL_GMER_VALID_CHANNEL BIT(0) +#define CXL_GMER_VALID_RANK BIT(1) +#define CXL_GMER_VALID_DEVICE BIT(2) +#define CXL_GMER_VALID_COMPONENT BIT(3) + +static int ct3d_qmp_cxl_event_log_enc(CxlEventLog log) +{ + switch (log) { + case CXL_EVENT_LOG_INFORMATIONAL: + return CXL_EVENT_TYPE_INFO; + case CXL_EVENT_LOG_WARNING: + return CXL_EVENT_TYPE_WARN; + case CXL_EVENT_LOG_FAILURE: + return CXL_EVENT_TYPE_FAIL; + case CXL_EVENT_LOG_FATAL: + return CXL_EVENT_TYPE_FATAL; +/* DCD not yet supported */ + default: + return -EINVAL; + } +} +/* Component ID is device specific. Define this as a string. */ +void qmp_cxl_inject_general_media_event(const char *path, CxlEventLog log, + uint8_t flags, uint64_t dpa, + uint8_t descriptor, uint8_t type, + uint8_t transaction_type, + bool has_channel, uint8_t channel, + bool has_rank, uint8_t rank, + bool has_device, uint32_t device, + const char *component_id, + Error **errp) +{ + Object *obj = object_resolve_path(path, NULL); + CXLEventGenMedia gem; + CXLEventRecordHdr *hdr = &gem.hdr; + CXLDeviceState *cxlds; + CXLType3Dev *ct3d; + uint16_t valid_flags = 0; + uint8_t enc_log; + int rc; + + if (!obj) { + error_setg(errp, "Unable to resolve path"); + return; + } + if (!object_dynamic_cast(obj, TYPE_CXL_TYPE3)) { + error_setg(errp, "Path does not point to a CXL type 3 device"); + return; + } + ct3d = CXL_TYPE3(obj); + cxlds = &ct3d->cxl_dstate; + + rc = ct3d_qmp_cxl_event_log_enc(log); + if (rc < 0) { + error_setg(errp, "Unhandled error log type"); + return; + } + enc_log = rc; + + memset(&gem, 0, sizeof(gem)); + cxl_assign_event_header(hdr, &gen_media_uuid, flags, sizeof(gem), + cxl_device_get_timestamp(&ct3d->cxl_dstate)); + + stq_le_p(&gem.phys_addr, dpa); + gem.descriptor = descriptor; + gem.type = type; + gem.transaction_type = transaction_type; + + if (has_channel) { + gem.channel = channel; + valid_flags |= CXL_GMER_VALID_CHANNEL; + } + + if (has_rank) { + gem.rank = rank; + valid_flags |= CXL_GMER_VALID_RANK; + } + + if (has_device) { + st24_le_p(gem.device, device); + valid_flags |= CXL_GMER_VALID_DEVICE; + } + + if (component_id) { + strncpy((char *)gem.component_id, component_id, + sizeof(gem.component_id) - 1); + valid_flags |= CXL_GMER_VALID_COMPONENT; + } + + stw_le_p(&gem.validity_flags, valid_flags); + + if (cxl_event_insert(cxlds, enc_log, (CXLEventRecordRaw *)&gem)) { + cxl_event_irq_assert(ct3d); + } +} + static void ct3_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/mem/cxl_type3_stubs.c b/hw/mem/cxl_type3_stubs.c index fd1166a610..4dfbdf9268 100644 --- a/hw/mem/cxl_type3_stubs.c +++ b/hw/mem/cxl_type3_stubs.c @@ -3,6 +3,16 @@ #include "qapi/error.h" #include "qapi/qapi-commands-cxl.h" +void qmp_cxl_inject_general_media_event(const char *path, CxlEventLog log, + uint8_t flags, uint64_t dpa, + uint8_t descriptor, uint8_t type, + uint8_t transaction_type, + bool has_channel, uint8_t channel, + bool has_rank, uint8_t rank, + bool has_device, uint32_t device, + const char *component_id, + Error **errp) {} + void qmp_cxl_inject_poison(const char *path, uint64_t start, uint64_t length, Error **errp) { diff --git a/include/hw/cxl/cxl_events.h b/include/hw/cxl/cxl_events.h index 4bf8b7aa08..b189193f4c 100644 --- a/include/hw/cxl/cxl_events.h +++ b/include/hw/cxl/cxl_events.h @@ -103,4 +103,24 @@ typedef struct CXLEventInterruptPolicy { /* DCD is optional but other fields are not */ #define CXL_EVENT_INT_SETTING_MIN_LEN 4 +/* + * General Media Event Record + * CXL rev 3.0 Section 8.2.9.2.1.1; Table 8-43 + */ +#define CXL_EVENT_GEN_MED_COMP_ID_SIZE 0x10 +#define CXL_EVENT_GEN_MED_RES_SIZE 0x2e +typedef struct CXLEventGenMedia { + CXLEventRecordHdr hdr; + uint64_t phys_addr; + uint8_t descriptor; + uint8_t type; + uint8_t transaction_type; + uint16_t validity_flags; + uint8_t channel; + uint8_t rank; + uint8_t device[3]; + uint8_t component_id[CXL_EVENT_GEN_MED_COMP_ID_SIZE]; + uint8_t reserved[CXL_EVENT_GEN_MED_RES_SIZE]; +} QEMU_PACKED CXLEventGenMedia; + #endif /* CXL_EVENTS_H */ diff --git a/qapi/cxl.json b/qapi/cxl.json index ed1c7eea3a..d509430844 100644 --- a/qapi/cxl.json +++ b/qapi/cxl.json @@ -5,6 +5,80 @@ # = CXL devices ## +## +# @CxlEventLog: +# +# CXL has a number of separate event logs for different types of +# events. Each such event log is handled and signaled independently. +# +# @informational: Information Event Log +# +# @warning: Warning Event Log +# +# @failure: Failure Event Log +# +# @fatal: Fatal Event Log +# +# Since: 8.1 +## +{ 'enum': 'CxlEventLog', + 'data': ['informational', + 'warning', + 'failure', + 'fatal'] + } + +## +# @cxl-inject-general-media-event: +# +# Inject an event record for a General Media Event (CXL r3.0 +# 8.2.9.2.1.1). This event type is reported via one of the event logs +# specified via the log parameter. +# +# @path: CXL type 3 device canonical QOM path +# +# @log: event log to add the event to +# +# @flags: Event Record Flags. See CXL r3.0 Table 8-42 Common Event +# Record Format, Event Record Flags for subfield definitions. +# +# @dpa: Device Physical Address (relative to @path device). Note +# lower bits include some flags. See CXL r3.0 Table 8-43 General +# Media Event Record, Physical Address. +# +# @descriptor: Memory Event Descriptor with additional memory event +# information. See CXL r3.0 Table 8-43 General Media Event +# Record, Memory Event Descriptor for bit definitions. +# +# @type: Type of memory event that occurred. See CXL r3.0 Table 8-43 +# General Media Event Record, Memory Event Type for possible +# values. +# +# @transaction-type: Type of first transaction that caused the event +# to occur. See CXL r3.0 Table 8-43 General Media Event Record, +# Transaction Type for possible values. +# +# @channel: The channel of the memory event location. A channel is an +# interface that can be independently accessed for a transaction. +# +# @rank: The rank of the memory event location. A rank is a set of +# memory devices on a channel that together execute a transaction. +# +# @device: Bitmask that represents all devices in the rank associated +# with the memory event location. +# +# @component-id: Device specific component identifier for the event. +# May describe a field replaceable sub-component of the device. +# +# Since: 8.1 +## +{ 'command': 'cxl-inject-general-media-event', + 'data': { 'path': 'str', 'log': 'CxlEventLog', 'flags': 'uint8', + 'dpa': 'uint64', 'descriptor': 'uint8', + 'type': 'uint8', 'transaction-type': 'uint8', + '*channel': 'uint8', '*rank': 'uint8', + '*device': 'uint32', '*component-id': 'str' } } + ## # @cxl-inject-poison: # From b90a324eda7113b62b558aad43e2166eb52567d2 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Tue, 30 May 2023 14:36:02 +0100 Subject: [PATCH 0054/1353] hw/cxl/events: Add injection of DRAM events Defined in CXL r3.0 8.2.9.2.1.2 DRAM Event Record, this event provides information related to DRAM devices. Example injection command in QMP: { "execute": "cxl-inject-dram-event", "arguments": { "path": "/machine/peripheral/cxl-mem0", "log": "informational", "flags": 1, "dpa": 1000, "descriptor": 3, "type": 3, "transaction-type": 192, "channel": 3, "rank": 17, "nibble-mask": 37421234, "bank-group": 7, "bank": 11, "row": 2, "column": 77, "correction-mask": [33, 44, 55,66] }} Acked-by: Markus Armbruster Reviewed-by: Fan Ni Reviewed-by: Ira Weiny Signed-off-by: Jonathan Cameron Message-Id: <20230530133603.16934-7-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/mem/cxl_type3.c | 116 ++++++++++++++++++++++++++++++++++++ hw/mem/cxl_type3_stubs.c | 13 ++++ include/hw/cxl/cxl_events.h | 23 +++++++ qapi/cxl.json | 61 +++++++++++++++++++ 4 files changed, 213 insertions(+) diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c index b1618779d2..3c07b1b7a3 100644 --- a/hw/mem/cxl_type3.c +++ b/hw/mem/cxl_type3.c @@ -1196,6 +1196,11 @@ static const QemuUUID gen_media_uuid = { 0x85, 0xa9, 0x08, 0x8b, 0x16, 0x21, 0xeb, 0xa6), }; +static const QemuUUID dram_uuid = { + .data = UUID(0x601dcbb3, 0x9c06, 0x4eab, 0xb8, 0xaf, + 0x4e, 0x9b, 0xfb, 0x5c, 0x96, 0x24), +}; + #define CXL_GMER_VALID_CHANNEL BIT(0) #define CXL_GMER_VALID_RANK BIT(1) #define CXL_GMER_VALID_DEVICE BIT(2) @@ -1292,6 +1297,117 @@ void qmp_cxl_inject_general_media_event(const char *path, CxlEventLog log, } } +#define CXL_DRAM_VALID_CHANNEL BIT(0) +#define CXL_DRAM_VALID_RANK BIT(1) +#define CXL_DRAM_VALID_NIBBLE_MASK BIT(2) +#define CXL_DRAM_VALID_BANK_GROUP BIT(3) +#define CXL_DRAM_VALID_BANK BIT(4) +#define CXL_DRAM_VALID_ROW BIT(5) +#define CXL_DRAM_VALID_COLUMN BIT(6) +#define CXL_DRAM_VALID_CORRECTION_MASK BIT(7) + +void qmp_cxl_inject_dram_event(const char *path, CxlEventLog log, uint8_t flags, + uint64_t dpa, uint8_t descriptor, + uint8_t type, uint8_t transaction_type, + bool has_channel, uint8_t channel, + bool has_rank, uint8_t rank, + bool has_nibble_mask, uint32_t nibble_mask, + bool has_bank_group, uint8_t bank_group, + bool has_bank, uint8_t bank, + bool has_row, uint32_t row, + bool has_column, uint16_t column, + bool has_correction_mask, uint64List *correction_mask, + Error **errp) +{ + Object *obj = object_resolve_path(path, NULL); + CXLEventDram dram; + CXLEventRecordHdr *hdr = &dram.hdr; + CXLDeviceState *cxlds; + CXLType3Dev *ct3d; + uint16_t valid_flags = 0; + uint8_t enc_log; + int rc; + + if (!obj) { + error_setg(errp, "Unable to resolve path"); + return; + } + if (!object_dynamic_cast(obj, TYPE_CXL_TYPE3)) { + error_setg(errp, "Path does not point to a CXL type 3 device"); + return; + } + ct3d = CXL_TYPE3(obj); + cxlds = &ct3d->cxl_dstate; + + rc = ct3d_qmp_cxl_event_log_enc(log); + if (rc < 0) { + error_setg(errp, "Unhandled error log type"); + return; + } + enc_log = rc; + + memset(&dram, 0, sizeof(dram)); + cxl_assign_event_header(hdr, &dram_uuid, flags, sizeof(dram), + cxl_device_get_timestamp(&ct3d->cxl_dstate)); + stq_le_p(&dram.phys_addr, dpa); + dram.descriptor = descriptor; + dram.type = type; + dram.transaction_type = transaction_type; + + if (has_channel) { + dram.channel = channel; + valid_flags |= CXL_DRAM_VALID_CHANNEL; + } + + if (has_rank) { + dram.rank = rank; + valid_flags |= CXL_DRAM_VALID_RANK; + } + + if (has_nibble_mask) { + st24_le_p(dram.nibble_mask, nibble_mask); + valid_flags |= CXL_DRAM_VALID_NIBBLE_MASK; + } + + if (has_bank_group) { + dram.bank_group = bank_group; + valid_flags |= CXL_DRAM_VALID_BANK_GROUP; + } + + if (has_bank) { + dram.bank = bank; + valid_flags |= CXL_DRAM_VALID_BANK; + } + + if (has_row) { + st24_le_p(dram.row, row); + valid_flags |= CXL_DRAM_VALID_ROW; + } + + if (has_column) { + stw_le_p(&dram.column, column); + valid_flags |= CXL_DRAM_VALID_COLUMN; + } + + if (has_correction_mask) { + int count = 0; + while (correction_mask && count < 4) { + stq_le_p(&dram.correction_mask[count], + correction_mask->value); + count++; + correction_mask = correction_mask->next; + } + valid_flags |= CXL_DRAM_VALID_CORRECTION_MASK; + } + + stw_le_p(&dram.validity_flags, valid_flags); + + if (cxl_event_insert(cxlds, enc_log, (CXLEventRecordRaw *)&dram)) { + cxl_event_irq_assert(ct3d); + } + return; +} + static void ct3_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/mem/cxl_type3_stubs.c b/hw/mem/cxl_type3_stubs.c index 4dfbdf9268..e904c5d089 100644 --- a/hw/mem/cxl_type3_stubs.c +++ b/hw/mem/cxl_type3_stubs.c @@ -13,6 +13,19 @@ void qmp_cxl_inject_general_media_event(const char *path, CxlEventLog log, const char *component_id, Error **errp) {} +void qmp_cxl_inject_dram_event(const char *path, CxlEventLog log, uint8_t flags, + uint64_t dpa, uint8_t descriptor, + uint8_t type, uint8_t transaction_type, + bool has_channel, uint8_t channel, + bool has_rank, uint8_t rank, + bool has_nibble_mask, uint32_t nibble_mask, + bool has_bank_group, uint8_t bank_group, + bool has_bank, uint8_t bank, + bool has_row, uint32_t row, + bool has_column, uint16_t column, + bool has_correction_mask, uint64List *correction_mask, + Error **errp) {} + void qmp_cxl_inject_poison(const char *path, uint64_t start, uint64_t length, Error **errp) { diff --git a/include/hw/cxl/cxl_events.h b/include/hw/cxl/cxl_events.h index b189193f4c..a39e30d973 100644 --- a/include/hw/cxl/cxl_events.h +++ b/include/hw/cxl/cxl_events.h @@ -123,4 +123,27 @@ typedef struct CXLEventGenMedia { uint8_t reserved[CXL_EVENT_GEN_MED_RES_SIZE]; } QEMU_PACKED CXLEventGenMedia; +/* + * DRAM Event Record + * CXL Rev 3.0 Section 8.2.9.2.1.2: Table 8-44 + * All fields little endian. + */ +typedef struct CXLEventDram { + CXLEventRecordHdr hdr; + uint64_t phys_addr; + uint8_t descriptor; + uint8_t type; + uint8_t transaction_type; + uint16_t validity_flags; + uint8_t channel; + uint8_t rank; + uint8_t nibble_mask[3]; + uint8_t bank_group; + uint8_t bank; + uint8_t row[3]; + uint16_t column; + uint64_t correction_mask[4]; + uint8_t reserved[0x17]; +} QEMU_PACKED CXLEventDram; + #endif /* CXL_EVENTS_H */ diff --git a/qapi/cxl.json b/qapi/cxl.json index d509430844..2ad310387c 100644 --- a/qapi/cxl.json +++ b/qapi/cxl.json @@ -79,6 +79,67 @@ '*channel': 'uint8', '*rank': 'uint8', '*device': 'uint32', '*component-id': 'str' } } +## +# @cxl-inject-dram-event: +# +# Inject an event record for a DRAM Event (CXL r3.0 8.2.9.2.1.2). +# This event type is reported via one of the event logs specified via +# the log parameter. +# +# @path: CXL type 3 device canonical QOM path +# +# @log: Event log to add the event to +# +# @flags: Event Record Flags. See CXL r3.0 Table 8-42 Common Event +# Record Format, Event Record Flags for subfield definitions. +# +# @dpa: Device Physical Address (relative to @path device). Note +# lower bits include some flags. See CXL r3.0 Table 8-44 DRAM +# Event Record, Physical Address. +# +# @descriptor: Memory Event Descriptor with additional memory event +# information. See CXL r3.0 Table 8-44 DRAM Event Record, Memory +# Event Descriptor for bit definitions. +# +# @type: Type of memory event that occurred. See CXL r3.0 Table 8-44 +# DRAM Event Record, Memory Event Type for possible values. +# +# @transaction-type: Type of first transaction that caused the event +# to occur. See CXL r3.0 Table 8-44 DRAM Event Record, +# Transaction Type for possible values. +# +# @channel: The channel of the memory event location. A channel is an +# interface that can be independently accessed for a transaction. +# +# @rank: The rank of the memory event location. A rank is a set of +# memory devices on a channel that together execute a transaction. +# +# @nibble-mask: Identifies one or more nibbles that the error affects +# +# @bank-group: Bank group of the memory event location, incorporating +# a number of Banks. +# +# @bank: Bank of the memory event location. A single bank is accessed +# per read or write of the memory. +# +# @row: Row address within the DRAM. +# +# @column: Column address within the DRAM. +# +# @correction-mask: Bits within each nibble. Used in order of bits +# set in the nibble-mask. Up to 4 nibbles may be covered. +# +# Since: 8.1 +## +{ 'command': 'cxl-inject-dram-event', + 'data': { 'path': 'str', 'log': 'CxlEventLog', 'flags': 'uint8', + 'dpa': 'uint64', 'descriptor': 'uint8', + 'type': 'uint8', 'transaction-type': 'uint8', + '*channel': 'uint8', '*rank': 'uint8', '*nibble-mask': 'uint32', + '*bank-group': 'uint8', '*bank': 'uint8', '*row': 'uint32', + '*column': 'uint16', '*correction-mask': [ 'uint64' ] + }} + ## # @cxl-inject-poison: # From bafe03083255da3a053144b77a5fbc7dbf9494f3 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Tue, 30 May 2023 14:36:03 +0100 Subject: [PATCH 0055/1353] hw/cxl/events: Add injection of Memory Module Events These events include a copy of the device health information at the time of the event. Actually using the emulated device health would require a lot of controls to manipulate that state. Given the aim of this injection code is to just test the flows when events occur, inject the contents of the device health state as well. Future work may add more sophisticate device health emulation including direct generation of these records when events occur (such as a temperature threshold being crossed). That does not reduce the usefulness of this more basic generation of the events. Acked-by: Markus Armbruster Reviewed-by: Fan Ni Reviewed-by: Ira Weiny Signed-off-by: Jonathan Cameron Message-Id: <20230530133603.16934-8-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/mem/cxl_type3.c | 62 +++++++++++++++++++++++++++++++++++++ hw/mem/cxl_type3_stubs.c | 12 +++++++ include/hw/cxl/cxl_events.h | 19 ++++++++++++ qapi/cxl.json | 53 +++++++++++++++++++++++++++++++ 4 files changed, 146 insertions(+) diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c index 3c07b1b7a3..4e314748d3 100644 --- a/hw/mem/cxl_type3.c +++ b/hw/mem/cxl_type3.c @@ -1201,6 +1201,11 @@ static const QemuUUID dram_uuid = { 0x4e, 0x9b, 0xfb, 0x5c, 0x96, 0x24), }; +static const QemuUUID memory_module_uuid = { + .data = UUID(0xfe927475, 0xdd59, 0x4339, 0xa5, 0x86, + 0x79, 0xba, 0xb1, 0x13, 0xb7, 0x74), +}; + #define CXL_GMER_VALID_CHANNEL BIT(0) #define CXL_GMER_VALID_RANK BIT(1) #define CXL_GMER_VALID_DEVICE BIT(2) @@ -1408,6 +1413,63 @@ void qmp_cxl_inject_dram_event(const char *path, CxlEventLog log, uint8_t flags, return; } +void qmp_cxl_inject_memory_module_event(const char *path, CxlEventLog log, + uint8_t flags, uint8_t type, + uint8_t health_status, + uint8_t media_status, + uint8_t additional_status, + uint8_t life_used, + int16_t temperature, + uint32_t dirty_shutdown_count, + uint32_t corrected_volatile_error_count, + uint32_t corrected_persistent_error_count, + Error **errp) +{ + Object *obj = object_resolve_path(path, NULL); + CXLEventMemoryModule module; + CXLEventRecordHdr *hdr = &module.hdr; + CXLDeviceState *cxlds; + CXLType3Dev *ct3d; + uint8_t enc_log; + int rc; + + if (!obj) { + error_setg(errp, "Unable to resolve path"); + return; + } + if (!object_dynamic_cast(obj, TYPE_CXL_TYPE3)) { + error_setg(errp, "Path does not point to a CXL type 3 device"); + return; + } + ct3d = CXL_TYPE3(obj); + cxlds = &ct3d->cxl_dstate; + + rc = ct3d_qmp_cxl_event_log_enc(log); + if (rc < 0) { + error_setg(errp, "Unhandled error log type"); + return; + } + enc_log = rc; + + memset(&module, 0, sizeof(module)); + cxl_assign_event_header(hdr, &memory_module_uuid, flags, sizeof(module), + cxl_device_get_timestamp(&ct3d->cxl_dstate)); + + module.type = type; + module.health_status = health_status; + module.media_status = media_status; + module.additional_status = additional_status; + module.life_used = life_used; + stw_le_p(&module.temperature, temperature); + stl_le_p(&module.dirty_shutdown_count, dirty_shutdown_count); + stl_le_p(&module.corrected_volatile_error_count, corrected_volatile_error_count); + stl_le_p(&module.corrected_persistent_error_count, corrected_persistent_error_count); + + if (cxl_event_insert(cxlds, enc_log, (CXLEventRecordRaw *)&module)) { + cxl_event_irq_assert(ct3d); + } +} + static void ct3_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/mem/cxl_type3_stubs.c b/hw/mem/cxl_type3_stubs.c index e904c5d089..f3e4a9fa72 100644 --- a/hw/mem/cxl_type3_stubs.c +++ b/hw/mem/cxl_type3_stubs.c @@ -26,6 +26,18 @@ void qmp_cxl_inject_dram_event(const char *path, CxlEventLog log, uint8_t flags, bool has_correction_mask, uint64List *correction_mask, Error **errp) {} +void qmp_cxl_inject_memory_module_event(const char *path, CxlEventLog log, + uint8_t flags, uint8_t type, + uint8_t health_status, + uint8_t media_status, + uint8_t additional_status, + uint8_t life_used, + int16_t temperature, + uint32_t dirty_shutdown_count, + uint32_t corrected_volatile_error_count, + uint32_t corrected_persistent_error_count, + Error **errp) {} + void qmp_cxl_inject_poison(const char *path, uint64_t start, uint64_t length, Error **errp) { diff --git a/include/hw/cxl/cxl_events.h b/include/hw/cxl/cxl_events.h index a39e30d973..089ba2091f 100644 --- a/include/hw/cxl/cxl_events.h +++ b/include/hw/cxl/cxl_events.h @@ -146,4 +146,23 @@ typedef struct CXLEventDram { uint8_t reserved[0x17]; } QEMU_PACKED CXLEventDram; +/* + * Memory Module Event Record + * CXL Rev 3.0 Section 8.2.9.2.1.3: Table 8-45 + * All fields little endian. + */ +typedef struct CXLEventMemoryModule { + CXLEventRecordHdr hdr; + uint8_t type; + uint8_t health_status; + uint8_t media_status; + uint8_t additional_status; + uint8_t life_used; + int16_t temperature; + uint32_t dirty_shutdown_count; + uint32_t corrected_volatile_error_count; + uint32_t corrected_persistent_error_count; + uint8_t reserved[0x3d]; +} QEMU_PACKED CXLEventMemoryModule; + #endif /* CXL_EVENTS_H */ diff --git a/qapi/cxl.json b/qapi/cxl.json index 2ad310387c..d5b5293eb5 100644 --- a/qapi/cxl.json +++ b/qapi/cxl.json @@ -140,6 +140,59 @@ '*column': 'uint16', '*correction-mask': [ 'uint64' ] }} +## +# @cxl-inject-memory-module-event: +# +# Inject an event record for a Memory Module Event (CXL r3.0 +# 8.2.9.2.1.3). This event includes a copy of the Device Health +# info at the time of the event. +# +# @path: CXL type 3 device canonical QOM path +# +# @log: Event Log to add the event to +# +# @flags: Event Record Flags. See CXL r3.0 Table 8-42 Common Event +# Record Format, Event Record Flags for subfield definitions. +# +# @type: Device Event Type. See CXL r3.0 Table 8-45 Memory Module +# Event Record for bit definitions for bit definiions. +# +# @health-status: Overall health summary bitmap. See CXL r3.0 Table +# 8-100 Get Health Info Output Payload, Health Status for bit +# definitions. +# +# @media-status: Overall media health summary. See CXL r3.0 Table +# 8-100 Get Health Info Output Payload, Media Status for bit +# definitions. +# +# @additional-status: See CXL r3.0 Table 8-100 Get Health Info Output +# Payload, Additional Status for subfield definitions. +# +# @life-used: Percentage (0-100) of factory expected life span. +# +# @temperature: Device temperature in degrees Celsius. +# +# @dirty-shutdown-count: Number of times the device has been unable +# to determine whether data loss may have occurred. +# +# @corrected-volatile-error-count: Total number of correctable errors +# in volatile memory. +# +# @corrected-persistent-error-count: Total number of correctable +# errors in persistent memory +# +# Since: 8.1 +## +{ 'command': 'cxl-inject-memory-module-event', + 'data': { 'path': 'str', 'log': 'CxlEventLog', 'flags' : 'uint8', + 'type': 'uint8', 'health-status': 'uint8', + 'media-status': 'uint8', 'additional-status': 'uint8', + 'life-used': 'uint8', 'temperature' : 'int16', + 'dirty-shutdown-count': 'uint32', + 'corrected-volatile-error-count': 'uint32', + 'corrected-persistent-error-count': 'uint32' + }} + ## # @cxl-inject-poison: # From 5c33f9783ace0b5e077060b220978d94fecb3e81 Mon Sep 17 00:00:00 2001 From: Gowrishankar Muthukrishnan Date: Tue, 16 May 2023 14:01:39 +0530 Subject: [PATCH 0056/1353] cryptodev-vhost-user: add asymmetric crypto support Add asymmetric crypto support in vhost_user backend. Signed-off-by: Gowrishankar Muthukrishnan Message-Id: <20230516083139.2349744-1-gmuthukrishn@marvell.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- backends/cryptodev-vhost-user.c | 9 ++-- hw/virtio/vhost-user.c | 75 +++++++++++++++++++++++++++------ 2 files changed, 66 insertions(+), 18 deletions(-) diff --git a/backends/cryptodev-vhost-user.c b/backends/cryptodev-vhost-user.c index b1d9eb735f..c3283ba84a 100644 --- a/backends/cryptodev-vhost-user.c +++ b/backends/cryptodev-vhost-user.c @@ -232,9 +232,9 @@ static void cryptodev_vhost_user_init( backend->conf.max_auth_key_len = VHOST_USER_MAX_AUTH_KEY_LEN; } -static int64_t cryptodev_vhost_user_sym_create_session( +static int64_t cryptodev_vhost_user_crypto_create_session( CryptoDevBackend *backend, - CryptoDevBackendSymSessionInfo *sess_info, + CryptoDevBackendSessionInfo *sess_info, uint32_t queue_index, Error **errp) { CryptoDevBackendClient *cc = @@ -266,18 +266,17 @@ static int cryptodev_vhost_user_create_session( void *opaque) { uint32_t op_code = sess_info->op_code; - CryptoDevBackendSymSessionInfo *sym_sess_info; int64_t ret; Error *local_error = NULL; int status; switch (op_code) { case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION: + case VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION: case VIRTIO_CRYPTO_HASH_CREATE_SESSION: case VIRTIO_CRYPTO_MAC_CREATE_SESSION: case VIRTIO_CRYPTO_AEAD_CREATE_SESSION: - sym_sess_info = &sess_info->u.sym_sess_info; - ret = cryptodev_vhost_user_sym_create_session(backend, sym_sess_info, + ret = cryptodev_vhost_user_crypto_create_session(backend, sess_info, queue_index, &local_error); break; diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 74a2a28663..2ad75a7964 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -11,6 +11,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "hw/virtio/vhost.h" +#include "hw/virtio/virtio-crypto.h" #include "hw/virtio/vhost-user.h" #include "hw/virtio/vhost-backend.h" #include "hw/virtio/virtio.h" @@ -163,13 +164,24 @@ typedef struct VhostUserConfig { #define VHOST_CRYPTO_SYM_HMAC_MAX_KEY_LEN 512 #define VHOST_CRYPTO_SYM_CIPHER_MAX_KEY_LEN 64 +#define VHOST_CRYPTO_ASYM_MAX_KEY_LEN 1024 typedef struct VhostUserCryptoSession { + uint64_t op_code; + union { + struct { + CryptoDevBackendSymSessionInfo session_setup_data; + uint8_t key[VHOST_CRYPTO_SYM_CIPHER_MAX_KEY_LEN]; + uint8_t auth_key[VHOST_CRYPTO_SYM_HMAC_MAX_KEY_LEN]; + } sym; + struct { + CryptoDevBackendAsymSessionInfo session_setup_data; + uint8_t key[VHOST_CRYPTO_ASYM_MAX_KEY_LEN]; + } asym; + } u; + /* session id for success, -1 on errors */ int64_t session_id; - CryptoDevBackendSymSessionInfo session_setup_data; - uint8_t key[VHOST_CRYPTO_SYM_CIPHER_MAX_KEY_LEN]; - uint8_t auth_key[VHOST_CRYPTO_SYM_HMAC_MAX_KEY_LEN]; } VhostUserCryptoSession; static VhostUserConfig c __attribute__ ((unused)); @@ -2357,7 +2369,7 @@ static int vhost_user_crypto_create_session(struct vhost_dev *dev, int ret; bool crypto_session = virtio_has_feature(dev->protocol_features, VHOST_USER_PROTOCOL_F_CRYPTO_SESSION); - CryptoDevBackendSymSessionInfo *sess_info = session_info; + CryptoDevBackendSessionInfo *backend_info = session_info; VhostUserMsg msg = { .hdr.request = VHOST_USER_CREATE_CRYPTO_SESSION, .hdr.flags = VHOST_USER_VERSION, @@ -2371,16 +2383,53 @@ static int vhost_user_crypto_create_session(struct vhost_dev *dev, return -ENOTSUP; } - memcpy(&msg.payload.session.session_setup_data, sess_info, - sizeof(CryptoDevBackendSymSessionInfo)); - if (sess_info->key_len) { - memcpy(&msg.payload.session.key, sess_info->cipher_key, - sess_info->key_len); - } - if (sess_info->auth_key_len > 0) { - memcpy(&msg.payload.session.auth_key, sess_info->auth_key, - sess_info->auth_key_len); + if (backend_info->op_code == VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION) { + CryptoDevBackendAsymSessionInfo *sess = &backend_info->u.asym_sess_info; + size_t keylen; + + memcpy(&msg.payload.session.u.asym.session_setup_data, sess, + sizeof(CryptoDevBackendAsymSessionInfo)); + if (sess->keylen) { + keylen = sizeof(msg.payload.session.u.asym.key); + if (sess->keylen > keylen) { + error_report("Unsupported asymmetric key size"); + return -ENOTSUP; + } + + memcpy(&msg.payload.session.u.asym.key, sess->key, + sess->keylen); + } + } else { + CryptoDevBackendSymSessionInfo *sess = &backend_info->u.sym_sess_info; + size_t keylen; + + memcpy(&msg.payload.session.u.sym.session_setup_data, sess, + sizeof(CryptoDevBackendSymSessionInfo)); + if (sess->key_len) { + keylen = sizeof(msg.payload.session.u.sym.key); + if (sess->key_len > keylen) { + error_report("Unsupported cipher key size"); + return -ENOTSUP; + } + + memcpy(&msg.payload.session.u.sym.key, sess->cipher_key, + sess->key_len); + } + + if (sess->auth_key_len > 0) { + keylen = sizeof(msg.payload.session.u.sym.auth_key); + if (sess->auth_key_len > keylen) { + error_report("Unsupported auth key size"); + return -ENOTSUP; + } + + memcpy(&msg.payload.session.u.sym.auth_key, sess->auth_key, + sess->auth_key_len); + } } + + msg.payload.session.op_code = backend_info->op_code; + msg.payload.session.session_id = backend_info->session_id; ret = vhost_user_write(dev, &msg, NULL, 0); if (ret < 0) { error_report("vhost_user_write() return %d, create session failed", From b3b408ffb9291e887029051a522a2c968a816d22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 24 May 2023 11:37:35 +0200 Subject: [PATCH 0057/1353] softmmu: Introduce qemu_target_page_mask() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since TARGET_PAGE_MASK is poisoned in target-agnostic code, introduce the qemu_target_page_mask() helper to get this value from target-agnostic code at runtime. Reviewed-by: Thomas Huth Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20230524093744.88442-2-philmd@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Alex Bennée --- include/exec/target_page.h | 1 + softmmu/physmem.c | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/include/exec/target_page.h b/include/exec/target_page.h index bbf37aea17..98ffbb5c23 100644 --- a/include/exec/target_page.h +++ b/include/exec/target_page.h @@ -15,6 +15,7 @@ #define EXEC_TARGET_PAGE_H size_t qemu_target_page_size(void); +int qemu_target_page_mask(void); int qemu_target_page_bits(void); int qemu_target_page_bits_min(void); diff --git a/softmmu/physmem.c b/softmmu/physmem.c index 6bdd944fe8..bda475a719 100644 --- a/softmmu/physmem.c +++ b/softmmu/physmem.c @@ -3359,6 +3359,11 @@ size_t qemu_target_page_size(void) return TARGET_PAGE_SIZE; } +int qemu_target_page_mask(void) +{ + return TARGET_PAGE_MASK; +} + int qemu_target_page_bits(void) { return TARGET_PAGE_BITS; From 8f691f1cb76f0591874e91eb18569a150bb3cfe0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 24 May 2023 11:37:36 +0200 Subject: [PATCH 0058/1353] hw/scsi: Introduce VHOST_SCSI_COMMON symbol in Kconfig MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of adding 'vhost-scsi-common.c' twice (for VHOST_SCSI and VHOST_USER_SCSI), have it depend on VHOST_SCSI_COMMON, selected by both symbols. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Reviewed-by: Richard Henderson Message-Id: <20230524093744.88442-3-philmd@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Alex Bennée --- hw/scsi/Kconfig | 6 ++++++ hw/scsi/meson.build | 6 ++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/hw/scsi/Kconfig b/hw/scsi/Kconfig index e7b34dc8e2..1feab84c4c 100644 --- a/hw/scsi/Kconfig +++ b/hw/scsi/Kconfig @@ -48,13 +48,19 @@ config VIRTIO_SCSI depends on VIRTIO select SCSI +config VHOST_SCSI_COMMON + bool + depends on VIRTIO + config VHOST_SCSI bool default y + select VHOST_SCSI_COMMON depends on VIRTIO && VHOST_KERNEL config VHOST_USER_SCSI bool # Only PCI devices are provided for now default y if VIRTIO_PCI + select VHOST_SCSI_COMMON depends on VIRTIO && VHOST_USER && LINUX diff --git a/hw/scsi/meson.build b/hw/scsi/meson.build index 7a1e7f13f0..2a005420d2 100644 --- a/hw/scsi/meson.build +++ b/hw/scsi/meson.build @@ -17,8 +17,10 @@ specific_scsi_ss = ss.source_set() virtio_scsi_ss = ss.source_set() virtio_scsi_ss.add(files('virtio-scsi.c', 'virtio-scsi-dataplane.c')) -virtio_scsi_ss.add(when: 'CONFIG_VHOST_SCSI', if_true: files('vhost-scsi-common.c', 'vhost-scsi.c')) -virtio_scsi_ss.add(when: 'CONFIG_VHOST_USER_SCSI', if_true: files('vhost-scsi-common.c', 'vhost-user-scsi.c')) + +virtio_scsi_ss.add(when: 'CONFIG_VHOST_SCSI_COMMON', if_true: files('vhost-scsi-common.c')) +virtio_scsi_ss.add(when: 'CONFIG_VHOST_SCSI', if_true: files('vhost-scsi.c')) +virtio_scsi_ss.add(when: 'CONFIG_VHOST_USER_SCSI', if_true: files('vhost-user-scsi.c')) specific_scsi_ss.add_all(when: 'CONFIG_VIRTIO_SCSI', if_true: virtio_scsi_ss) specific_scsi_ss.add(when: 'CONFIG_SPAPR_VSCSI', if_true: files('spapr_vscsi.c')) From 04ca164ad3fc5309732e482534410a36b4713b11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 24 May 2023 11:37:37 +0200 Subject: [PATCH 0059/1353] hw/scsi: Rearrange meson.build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We will modify this file shortly. Re-arrange it slightly first, declaring source sets first. No logical change. Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20230524093744.88442-4-philmd@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Thomas Huth Reviewed-by: Alex Bennée --- hw/scsi/meson.build | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/scsi/meson.build b/hw/scsi/meson.build index 2a005420d2..d9b5673c14 100644 --- a/hw/scsi/meson.build +++ b/hw/scsi/meson.build @@ -1,4 +1,7 @@ scsi_ss = ss.source_set() +specific_scsi_ss = ss.source_set() +virtio_scsi_ss = ss.source_set() + scsi_ss.add(files( 'emulation.c', 'scsi-bus.c', @@ -11,18 +14,15 @@ scsi_ss.add(when: 'CONFIG_LSI_SCSI_PCI', if_true: files('lsi53c895a.c')) scsi_ss.add(when: 'CONFIG_MEGASAS_SCSI_PCI', if_true: files('megasas.c')) scsi_ss.add(when: 'CONFIG_MPTSAS_SCSI_PCI', if_true: files('mptsas.c', 'mptconfig.c', 'mptendian.c')) scsi_ss.add(when: 'CONFIG_VMW_PVSCSI_SCSI_PCI', if_true: files('vmw_pvscsi.c')) -system_ss.add_all(when: 'CONFIG_SCSI', if_true: scsi_ss) -specific_scsi_ss = ss.source_set() - -virtio_scsi_ss = ss.source_set() virtio_scsi_ss.add(files('virtio-scsi.c', 'virtio-scsi-dataplane.c')) - virtio_scsi_ss.add(when: 'CONFIG_VHOST_SCSI_COMMON', if_true: files('vhost-scsi-common.c')) virtio_scsi_ss.add(when: 'CONFIG_VHOST_SCSI', if_true: files('vhost-scsi.c')) virtio_scsi_ss.add(when: 'CONFIG_VHOST_USER_SCSI', if_true: files('vhost-user-scsi.c')) + specific_scsi_ss.add_all(when: 'CONFIG_VIRTIO_SCSI', if_true: virtio_scsi_ss) specific_scsi_ss.add(when: 'CONFIG_SPAPR_VSCSI', if_true: files('spapr_vscsi.c')) +system_ss.add_all(when: 'CONFIG_SCSI', if_true: scsi_ss) specific_ss.add_all(when: 'CONFIG_SCSI', if_true: specific_scsi_ss) From 5268f5f5224ed67de63e0b91b05e410a97dbb976 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 24 May 2023 11:37:38 +0200 Subject: [PATCH 0060/1353] hw/scsi: Rename target-specific source set as 'specific_virtio_scsi_ss' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Following the SCSI variable named '[specific_]scsi_ss', rename the target-specific VirtIO/SCSI set prefixed with 'specific_'. This will help when adding target-agnostic VirtIO/SCSI set in few commits. No logical change. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20230524093744.88442-5-philmd@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Thomas Huth --- hw/scsi/meson.build | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/scsi/meson.build b/hw/scsi/meson.build index d9b5673c14..43746700be 100644 --- a/hw/scsi/meson.build +++ b/hw/scsi/meson.build @@ -1,6 +1,6 @@ scsi_ss = ss.source_set() specific_scsi_ss = ss.source_set() -virtio_scsi_ss = ss.source_set() +specific_virtio_scsi_ss = ss.source_set() scsi_ss.add(files( 'emulation.c', @@ -15,12 +15,12 @@ scsi_ss.add(when: 'CONFIG_MEGASAS_SCSI_PCI', if_true: files('megasas.c')) scsi_ss.add(when: 'CONFIG_MPTSAS_SCSI_PCI', if_true: files('mptsas.c', 'mptconfig.c', 'mptendian.c')) scsi_ss.add(when: 'CONFIG_VMW_PVSCSI_SCSI_PCI', if_true: files('vmw_pvscsi.c')) -virtio_scsi_ss.add(files('virtio-scsi.c', 'virtio-scsi-dataplane.c')) -virtio_scsi_ss.add(when: 'CONFIG_VHOST_SCSI_COMMON', if_true: files('vhost-scsi-common.c')) -virtio_scsi_ss.add(when: 'CONFIG_VHOST_SCSI', if_true: files('vhost-scsi.c')) -virtio_scsi_ss.add(when: 'CONFIG_VHOST_USER_SCSI', if_true: files('vhost-user-scsi.c')) +specific_virtio_scsi_ss.add(files('virtio-scsi.c', 'virtio-scsi-dataplane.c')) +specific_virtio_scsi_ss.add(when: 'CONFIG_VHOST_SCSI_COMMON', if_true: files('vhost-scsi-common.c')) +specific_virtio_scsi_ss.add(when: 'CONFIG_VHOST_SCSI', if_true: files('vhost-scsi.c')) +specific_virtio_scsi_ss.add(when: 'CONFIG_VHOST_USER_SCSI', if_true: files('vhost-user-scsi.c')) -specific_scsi_ss.add_all(when: 'CONFIG_VIRTIO_SCSI', if_true: virtio_scsi_ss) +specific_scsi_ss.add_all(when: 'CONFIG_VIRTIO_SCSI', if_true: specific_virtio_scsi_ss) specific_scsi_ss.add(when: 'CONFIG_SPAPR_VSCSI', if_true: files('spapr_vscsi.c')) From 6df956299a751c1eff03a8ea791a0182a688a7cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 24 May 2023 11:37:39 +0200 Subject: [PATCH 0061/1353] hw/virtio: Introduce VHOST_VSOCK_COMMON symbol in Kconfig MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of adding 'vhost-vsock-common.c' twice (for VHOST_VSOCK and VHOST_USER_VSOCK), have it depend on VHOST_VSOCK_COMMON, selected by both symbols. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Message-Id: <20230524093744.88442-6-philmd@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Alex Bennée Reviewed-by: Stefano Garzarella --- hw/virtio/Kconfig | 6 ++++++ hw/virtio/meson.build | 5 +++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/hw/virtio/Kconfig b/hw/virtio/Kconfig index 89e9e426d8..de7a35429a 100644 --- a/hw/virtio/Kconfig +++ b/hw/virtio/Kconfig @@ -56,14 +56,20 @@ config VIRTIO_MEM depends on VIRTIO_MEM_SUPPORTED select MEM_DEVICE +config VHOST_VSOCK_COMMON + bool + depends on VIRTIO + config VHOST_VSOCK bool default y + select VHOST_VSOCK_COMMON depends on VIRTIO && VHOST_KERNEL config VHOST_USER_VSOCK bool default y + select VHOST_VSOCK_COMMON depends on VIRTIO && VHOST_USER config VHOST_USER_I2C diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build index e83c37fffd..a6ea5beae7 100644 --- a/hw/virtio/meson.build +++ b/hw/virtio/meson.build @@ -23,8 +23,9 @@ specific_virtio_ss.add(when: 'CONFIG_VIRTIO_BALLOON', if_true: files('virtio-bal specific_virtio_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: files('virtio-crypto.c')) specific_virtio_ss.add(when: 'CONFIG_VHOST_USER_FS', if_true: files('vhost-user-fs.c')) specific_virtio_ss.add(when: 'CONFIG_VIRTIO_PMEM', if_true: files('virtio-pmem.c')) -specific_virtio_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock.c', 'vhost-vsock-common.c')) -specific_virtio_ss.add(when: 'CONFIG_VHOST_USER_VSOCK', if_true: files('vhost-user-vsock.c', 'vhost-vsock-common.c')) +specific_virtio_ss.add(when: 'CONFIG_VHOST_VSOCK_COMMON', if_true: files('vhost-vsock-common.c')) +specific_virtio_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock.c')) +specific_virtio_ss.add(when: 'CONFIG_VHOST_USER_VSOCK', if_true: files('vhost-user-vsock.c')) specific_virtio_ss.add(when: 'CONFIG_VIRTIO_RNG', if_true: files('virtio-rng.c')) specific_virtio_ss.add(when: 'CONFIG_VIRTIO_IOMMU', if_true: files('virtio-iommu.c')) specific_virtio_ss.add(when: 'CONFIG_VIRTIO_MEM', if_true: files('virtio-mem.c')) From 21e6435066bd3818969b520b69415ba62a85cd24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 24 May 2023 11:37:40 +0200 Subject: [PATCH 0062/1353] hw/virtio/virtio-mem: Use qemu_ram_get_fd() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid accessing RAMBlock internals, use the provided qemu_ram_get_fd() getter to get the file descriptor. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: David Hildenbrand Reviewed-by: Richard Henderson Message-Id: <20230524093744.88442-7-philmd@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Alex Bennée --- hw/virtio/virtio-mem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c index 538b695c29..74e63bd47a 100644 --- a/hw/virtio/virtio-mem.c +++ b/hw/virtio/virtio-mem.c @@ -135,7 +135,7 @@ static bool virtio_mem_has_shared_zeropage(RAMBlock *rb) * anonymous RAM. In any other case, reading unplugged *can* populate a * fresh page, consuming actual memory. */ - return !qemu_ram_is_shared(rb) && rb->fd < 0 && + return !qemu_ram_is_shared(rb) && qemu_ram_get_fd(rb) < 0 && qemu_ram_pagesize(rb) == qemu_real_host_page_size(); } #endif /* VIRTIO_MEM_HAS_LEGACY_GUESTS */ From a64da64ac671e81f3bae0fbf4e99fe7f8b65b668 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 24 May 2023 11:37:41 +0200 Subject: [PATCH 0063/1353] hw/virtio/vhost-vsock: Include missing 'virtio/virtio-bus.h' header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of having "virtio/virtio-bus.h" implicitly included, explicitly include it, to avoid when rearranging headers: hw/virtio/vhost-vsock-common.c: In function ‘vhost_vsock_common_start’: hw/virtio/vhost-vsock-common.c:51:5: error: unknown type name ‘VirtioBusClass’; did you mean ‘VirtioDeviceClass’? 51 | VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); | ^~~~~~~~~~~~~~ | VirtioDeviceClass hw/virtio/vhost-vsock-common.c:51:25: error: implicit declaration of function ‘VIRTIO_BUS_GET_CLASS’; did you mean ‘VIRTIO_DEVICE_CLASS’? [-Werror=implicit-function-declaration] 51 | VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); | ^~~~~~~~~~~~~~~~~~~~ | VIRTIO_DEVICE_CLASS Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Message-Id: <20230524093744.88442-8-philmd@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Alex Bennée Reviewed-by: Stefano Garzarella --- hw/virtio/vhost-vsock-common.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/virtio/vhost-vsock-common.c b/hw/virtio/vhost-vsock-common.c index d2b5519d5a..e89af9b329 100644 --- a/hw/virtio/vhost-vsock-common.c +++ b/hw/virtio/vhost-vsock-common.c @@ -11,6 +11,7 @@ #include "qemu/osdep.h" #include "standard-headers/linux/virtio_vsock.h" #include "qapi/error.h" +#include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio-access.h" #include "qemu/error-report.h" #include "hw/qdev-properties.h" From e414ed2c47da70381a66846cf9353f7612daa4b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 24 May 2023 11:37:42 +0200 Subject: [PATCH 0064/1353] hw/virtio/virtio-iommu: Use target-agnostic qemu_target_page_mask() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to have virtio-iommu.c become target-agnostic, we need to avoid using TARGET_PAGE_MASK. Get it with the qemu_target_page_mask() helper. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Eric Auger Message-Id: <20230524093744.88442-9-philmd@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Alex Bennée --- hw/virtio/virtio-iommu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c index 1cd258135d..85905a9e3d 100644 --- a/hw/virtio/virtio-iommu.c +++ b/hw/virtio/virtio-iommu.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "qemu/log.h" #include "qemu/iov.h" +#include "exec/target_page.h" #include "hw/qdev-properties.h" #include "hw/virtio/virtio.h" #include "sysemu/kvm.h" @@ -1164,7 +1165,7 @@ static void virtio_iommu_device_realize(DeviceState *dev, Error **errp) * in vfio realize */ s->config.bypass = s->boot_bypass; - s->config.page_size_mask = TARGET_PAGE_MASK; + s->config.page_size_mask = qemu_target_page_mask(); s->config.input_range.end = UINT64_MAX; s->config.domain_range.end = UINT32_MAX; s->config.probe_size = VIOMMU_PROBE_SIZE; From 4ee4667ded5841ff9278d4e4a4c765a3220023bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 24 May 2023 11:37:43 +0200 Subject: [PATCH 0065/1353] hw/virtio: Remove unnecessary 'virtio-access.h' header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit None of these files use the VirtIO Load/Store API declared by "hw/virtio/virtio-access.h". This header probably crept in via copy/pasting, remove it. Note, "virtio-access.h" is target-specific, so any file including it also become tainted as target-specific. Signed-off-by: Philippe Mathieu-Daudé Acked-by: Richard Henderson Tested-by: Thomas Huth Message-Id: <20230524093744.88442-10-philmd@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Alex Bennée --- hw/block/dataplane/virtio-blk.c | 1 - hw/s390x/virtio-ccw.c | 1 - hw/scsi/vhost-scsi.c | 1 - hw/scsi/vhost-user-scsi.c | 1 - hw/scsi/virtio-scsi-dataplane.c | 1 - hw/virtio/vdpa-dev.c | 1 - hw/virtio/vhost-vdpa.c | 1 - hw/virtio/vhost-vsock-common.c | 1 - hw/virtio/vhost.c | 1 - hw/virtio/virtio-crypto.c | 1 - hw/virtio/virtio-iommu.c | 1 - hw/virtio/virtio-mem.c | 1 - 12 files changed, 12 deletions(-) diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c index b90456c08c..c227b39408 100644 --- a/hw/block/dataplane/virtio-blk.c +++ b/hw/block/dataplane/virtio-blk.c @@ -19,7 +19,6 @@ #include "qemu/main-loop.h" #include "qemu/thread.h" #include "qemu/error-report.h" -#include "hw/virtio/virtio-access.h" #include "hw/virtio/virtio-blk.h" #include "virtio-blk.h" #include "block/aio.h" diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index f44de1a8c1..17c548b84f 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -22,7 +22,6 @@ #include "qemu/error-report.h" #include "qemu/log.h" #include "qemu/module.h" -#include "hw/virtio/virtio-access.h" #include "hw/virtio/virtio-bus.h" #include "hw/s390x/adapter.h" #include "hw/s390x/s390_flic.h" diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c index 6a0fd0dfb1..443f67daa4 100644 --- a/hw/scsi/vhost-scsi.c +++ b/hw/scsi/vhost-scsi.c @@ -26,7 +26,6 @@ #include "hw/virtio/vhost.h" #include "hw/virtio/virtio-scsi.h" #include "hw/virtio/virtio-bus.h" -#include "hw/virtio/virtio-access.h" #include "hw/fw-path-provider.h" #include "hw/qdev-properties.h" #include "qemu/cutils.h" diff --git a/hw/scsi/vhost-user-scsi.c b/hw/scsi/vhost-user-scsi.c index b7a71a802c..ee99b19e7a 100644 --- a/hw/scsi/vhost-user-scsi.c +++ b/hw/scsi/vhost-user-scsi.c @@ -26,7 +26,6 @@ #include "hw/virtio/vhost-backend.h" #include "hw/virtio/vhost-user-scsi.h" #include "hw/virtio/virtio.h" -#include "hw/virtio/virtio-access.h" #include "chardev/char-fe.h" #include "sysemu/sysemu.h" diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c index d55de4c8ca..1e684beebe 100644 --- a/hw/scsi/virtio-scsi-dataplane.c +++ b/hw/scsi/virtio-scsi-dataplane.c @@ -19,7 +19,6 @@ #include "hw/scsi/scsi.h" #include "scsi/constants.h" #include "hw/virtio/virtio-bus.h" -#include "hw/virtio/virtio-access.h" /* Context: QEMU global mutex held */ void virtio_scsi_dataplane_setup(VirtIOSCSI *s, Error **errp) diff --git a/hw/virtio/vdpa-dev.c b/hw/virtio/vdpa-dev.c index 01b41eb0f1..e08e830006 100644 --- a/hw/virtio/vdpa-dev.c +++ b/hw/virtio/vdpa-dev.c @@ -25,7 +25,6 @@ #include "hw/virtio/vhost.h" #include "hw/virtio/virtio.h" #include "hw/virtio/virtio-bus.h" -#include "hw/virtio/virtio-access.h" #include "hw/virtio/vdpa-dev.h" #include "sysemu/sysemu.h" #include "sysemu/runstate.h" diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c index b3094e8a8b..3c575a9a6e 100644 --- a/hw/virtio/vhost-vdpa.c +++ b/hw/virtio/vhost-vdpa.c @@ -26,7 +26,6 @@ #include "cpu.h" #include "trace.h" #include "qapi/error.h" -#include "hw/virtio/virtio-access.h" /* * Return one past the end of the end of section. Be careful with uint64_t diff --git a/hw/virtio/vhost-vsock-common.c b/hw/virtio/vhost-vsock-common.c index e89af9b329..321262f6b3 100644 --- a/hw/virtio/vhost-vsock-common.c +++ b/hw/virtio/vhost-vsock-common.c @@ -12,7 +12,6 @@ #include "standard-headers/linux/virtio_vsock.h" #include "qapi/error.h" #include "hw/virtio/virtio-bus.h" -#include "hw/virtio/virtio-access.h" #include "qemu/error-report.h" #include "hw/qdev-properties.h" #include "hw/virtio/vhost.h" diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 23da579ce2..7f3c727777 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -23,7 +23,6 @@ #include "qemu/log.h" #include "standard-headers/linux/vhost_types.h" #include "hw/virtio/virtio-bus.h" -#include "hw/virtio/virtio-access.h" #include "migration/blocker.h" #include "migration/qemu-file-types.h" #include "sysemu/dma.h" diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c index c729a1f79e..a6d7e1e8ec 100644 --- a/hw/virtio/virtio-crypto.c +++ b/hw/virtio/virtio-crypto.c @@ -21,7 +21,6 @@ #include "hw/virtio/virtio.h" #include "hw/virtio/virtio-crypto.h" #include "hw/qdev-properties.h" -#include "hw/virtio/virtio-access.h" #include "standard-headers/linux/virtio_ids.h" #include "sysemu/cryptodev-vhost.h" diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c index 85905a9e3d..1bbad23f4a 100644 --- a/hw/virtio/virtio-iommu.c +++ b/hw/virtio/virtio-iommu.c @@ -32,7 +32,6 @@ #include "standard-headers/linux/virtio_ids.h" #include "hw/virtio/virtio-bus.h" -#include "hw/virtio/virtio-access.h" #include "hw/virtio/virtio-iommu.h" #include "hw/pci/pci_bus.h" #include "hw/pci/pci.h" diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c index 74e63bd47a..12ea58d5ad 100644 --- a/hw/virtio/virtio-mem.c +++ b/hw/virtio/virtio-mem.c @@ -20,7 +20,6 @@ #include "sysemu/reset.h" #include "hw/virtio/virtio.h" #include "hw/virtio/virtio-bus.h" -#include "hw/virtio/virtio-access.h" #include "hw/virtio/virtio-mem.h" #include "qapi/error.h" #include "qapi/visitor.h" From 7a0903f7ea8ac7e5b3191c9a2cfd1751b153f48c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 24 May 2023 11:37:44 +0200 Subject: [PATCH 0066/1353] hw/virtio: Build various target-agnostic objects just once MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous commit remove the unnecessary "virtio-access.h" header. These files no longer have target-specific dependency. Move them to the generic 'softmmu_ss' source set. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Message-Id: <20230524093744.88442-11-philmd@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/block/dataplane/meson.build | 2 +- hw/scsi/meson.build | 10 +++++++--- hw/virtio/meson.build | 11 ++++++----- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/hw/block/dataplane/meson.build b/hw/block/dataplane/meson.build index 78d7ac1a11..025b3b061b 100644 --- a/hw/block/dataplane/meson.build +++ b/hw/block/dataplane/meson.build @@ -1,2 +1,2 @@ -specific_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio-blk.c')) +system_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio-blk.c')) specific_ss.add(when: 'CONFIG_XEN_BUS', if_true: files('xen-block.c')) diff --git a/hw/scsi/meson.build b/hw/scsi/meson.build index 43746700be..bb7d289aa0 100644 --- a/hw/scsi/meson.build +++ b/hw/scsi/meson.build @@ -1,5 +1,6 @@ scsi_ss = ss.source_set() specific_scsi_ss = ss.source_set() +virtio_scsi_ss = ss.source_set() specific_virtio_scsi_ss = ss.source_set() scsi_ss.add(files( @@ -15,12 +16,15 @@ scsi_ss.add(when: 'CONFIG_MEGASAS_SCSI_PCI', if_true: files('megasas.c')) scsi_ss.add(when: 'CONFIG_MPTSAS_SCSI_PCI', if_true: files('mptsas.c', 'mptconfig.c', 'mptendian.c')) scsi_ss.add(when: 'CONFIG_VMW_PVSCSI_SCSI_PCI', if_true: files('vmw_pvscsi.c')) -specific_virtio_scsi_ss.add(files('virtio-scsi.c', 'virtio-scsi-dataplane.c')) +virtio_scsi_ss.add(files('virtio-scsi-dataplane.c')) +virtio_scsi_ss.add(when: 'CONFIG_VHOST_SCSI', if_true: files('vhost-scsi.c')) +virtio_scsi_ss.add(when: 'CONFIG_VHOST_USER_SCSI', if_true: files('vhost-user-scsi.c')) + +specific_virtio_scsi_ss.add(files('virtio-scsi.c')) specific_virtio_scsi_ss.add(when: 'CONFIG_VHOST_SCSI_COMMON', if_true: files('vhost-scsi-common.c')) -specific_virtio_scsi_ss.add(when: 'CONFIG_VHOST_SCSI', if_true: files('vhost-scsi.c')) -specific_virtio_scsi_ss.add(when: 'CONFIG_VHOST_USER_SCSI', if_true: files('vhost-user-scsi.c')) specific_scsi_ss.add_all(when: 'CONFIG_VIRTIO_SCSI', if_true: specific_virtio_scsi_ss) +scsi_ss.add_all(when: 'CONFIG_VIRTIO_SCSI', if_true: virtio_scsi_ss) specific_scsi_ss.add(when: 'CONFIG_SPAPR_VSCSI', if_true: files('spapr_vscsi.c')) diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build index a6ea5beae7..f32b22f61b 100644 --- a/hw/virtio/meson.build +++ b/hw/virtio/meson.build @@ -2,13 +2,18 @@ softmmu_virtio_ss = ss.source_set() softmmu_virtio_ss.add(files('virtio-bus.c')) softmmu_virtio_ss.add(when: 'CONFIG_VIRTIO_PCI', if_true: files('virtio-pci.c')) softmmu_virtio_ss.add(when: 'CONFIG_VIRTIO_MMIO', if_true: files('virtio-mmio.c')) +softmmu_virtio_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: files('virtio-crypto.c')) +softmmu_virtio_ss.add(when: 'CONFIG_VHOST_VSOCK_COMMON', if_true: files('vhost-vsock-common.c')) +softmmu_virtio_ss.add(when: 'CONFIG_VIRTIO_IOMMU', if_true: files('virtio-iommu.c')) +softmmu_virtio_ss.add(when: 'CONFIG_VHOST_VDPA_DEV', if_true: files('vdpa-dev.c')) specific_virtio_ss = ss.source_set() specific_virtio_ss.add(files('virtio.c')) specific_virtio_ss.add(files('virtio-config-io.c', 'virtio-qmp.c')) if have_vhost - specific_virtio_ss.add(files('vhost.c', 'vhost-backend.c', 'vhost-iova-tree.c')) + softmmu_virtio_ss.add(files('vhost.c')) + specific_virtio_ss.add(files('vhost-backend.c', 'vhost-iova-tree.c')) if have_vhost_user specific_virtio_ss.add(files('vhost-user.c')) endif @@ -20,20 +25,16 @@ else endif specific_virtio_ss.add(when: 'CONFIG_VIRTIO_BALLOON', if_true: files('virtio-balloon.c')) -specific_virtio_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: files('virtio-crypto.c')) specific_virtio_ss.add(when: 'CONFIG_VHOST_USER_FS', if_true: files('vhost-user-fs.c')) specific_virtio_ss.add(when: 'CONFIG_VIRTIO_PMEM', if_true: files('virtio-pmem.c')) -specific_virtio_ss.add(when: 'CONFIG_VHOST_VSOCK_COMMON', if_true: files('vhost-vsock-common.c')) specific_virtio_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock.c')) specific_virtio_ss.add(when: 'CONFIG_VHOST_USER_VSOCK', if_true: files('vhost-user-vsock.c')) specific_virtio_ss.add(when: 'CONFIG_VIRTIO_RNG', if_true: files('virtio-rng.c')) -specific_virtio_ss.add(when: 'CONFIG_VIRTIO_IOMMU', if_true: files('virtio-iommu.c')) specific_virtio_ss.add(when: 'CONFIG_VIRTIO_MEM', if_true: files('virtio-mem.c')) specific_virtio_ss.add(when: 'CONFIG_VHOST_USER_I2C', if_true: files('vhost-user-i2c.c')) specific_virtio_ss.add(when: 'CONFIG_VHOST_USER_RNG', if_true: files('vhost-user-rng.c')) specific_virtio_ss.add(when: 'CONFIG_VHOST_USER_GPIO', if_true: files('vhost-user-gpio.c')) specific_virtio_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_GPIO'], if_true: files('vhost-user-gpio-pci.c')) -specific_virtio_ss.add(when: 'CONFIG_VHOST_VDPA_DEV', if_true: files('vdpa-dev.c')) virtio_pci_ss = ss.source_set() virtio_pci_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock-pci.c')) From 1e3ffb34f764f8ac4c003b2b2e6a775b2b073a16 Mon Sep 17 00:00:00 2001 From: Prasad Pandit Date: Mon, 29 May 2023 17:13:32 +0530 Subject: [PATCH 0067/1353] vhost: release memory_listener object in error path vhost_dev_start function does not release memory_listener object in case of an error. This may crash the guest when vhost is unable to set memory table: stack trace of thread 125653: Program terminated with signal SIGSEGV, Segmentation fault #0 memory_listener_register (qemu-kvm + 0x6cda0f) #1 vhost_dev_start (qemu-kvm + 0x699301) #2 vhost_net_start (qemu-kvm + 0x45b03f) #3 virtio_net_set_status (qemu-kvm + 0x665672) #4 qmp_set_link (qemu-kvm + 0x548fd5) #5 net_vhost_user_event (qemu-kvm + 0x552c45) #6 tcp_chr_connect (qemu-kvm + 0x88d473) #7 tcp_chr_new_client (qemu-kvm + 0x88cf83) #8 tcp_chr_accept (qemu-kvm + 0x88b429) #9 qio_net_listener_channel_func (qemu-kvm + 0x7ac07c) #10 g_main_context_dispatch (libglib-2.0.so.0 + 0x54e2f) Release memory_listener objects in the error path. Signed-off-by: Prasad Pandit Message-Id: <20230529114333.31686-2-ppandit@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Peter Xu Fixes: c471ad0e9b ("vhost_net: device IOTLB support") Cc: qemu-stable@nongnu.org Acked-by: Jason Wang --- hw/virtio/vhost.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 7f3c727777..7e1f556994 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -2003,6 +2003,9 @@ fail_vq: } fail_mem: + if (vhost_dev_has_iommu(hdev)) { + memory_listener_unregister(&hdev->iommu_listener); + } fail_features: vdev->vhost_started = false; hdev->started = false; From 77ece20ba04582d94c345ac0107ddff2fd18d27a Mon Sep 17 00:00:00 2001 From: Prasad Pandit Date: Mon, 29 May 2023 17:13:33 +0530 Subject: [PATCH 0068/1353] vhost: release virtqueue objects in error path vhost_dev_start function does not release virtqueue objects when event_notifier_init() function fails. Release virtqueue objects and log a message about function failure. Signed-off-by: Prasad Pandit Message-Id: <20230529114333.31686-3-ppandit@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Fixes: f9a09ca3ea ("vhost: add support for configure interrupt") Reviewed-by: Peter Xu Cc: qemu-stable@nongnu.org Acked-by: Jason Wang --- hw/virtio/vhost.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 7e1f556994..fb7abc9769 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -1941,7 +1941,8 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings) r = event_notifier_init( &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier, 0); if (r < 0) { - return r; + VHOST_OPS_DEBUG(r, "event_notifier_init failed"); + goto fail_vq; } event_notifier_test_and_clear( &hdev->vqs[VHOST_QUEUE_NUM_CONFIG_INR].masked_config_notifier); From 8eb85fb5ac60bfb6ee4c729cc087078d490670c4 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Mon, 22 May 2023 23:17:40 +0300 Subject: [PATCH 0069/1353] pci: ROM preallocation for incoming migration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On incoming migration we have the following sequence to load option ROM: 1. On device realize we do normal load ROM from the file 2. Than, on incoming migration we rewrite ROM from the incoming RAM block. If sizes mismatch we fail, like this: Size mismatch: 0000:00:03.0/virtio-net-pci.rom: 0x40000 != 0x80000: Invalid argument This is not ideal when we migrate to updated distribution: we have to keep old ROM files in new distribution and be careful around romfile property to load correct ROM file. Which is loaded actually just to allocate the ROM with correct length. Note, that romsize property doesn't really help: if we try to specify it when default romfile is larger, it fails with something like: romfile "efi-virtio.rom" (160768 bytes) is too large for ROM size 65536 Let's just ignore ROM file when romsize is specified and we are in incoming migration state. In other words, we need only to preallocate ROM of specified size, local ROM file is unrelated. This way: If romsize was specified on source, we just use same commandline as on source, and migration will work independently of local ROM files on target. If romsize was not specified on source (and we have mismatching local ROM file on target host), we have to specify romsize on target to match source romsize. romfile parameter may be kept same as on source or may be dropped, the file is not loaded anyway. As a bonus we avoid extra reading from ROM file on target. Note: when we don't have romsize parameter on source command line and need it for target, it may be calculated as aligned up to power of two size of ROM file on source (if we know, which file is it) or, alternatively it may be retrieved from source QEMU by QMP qom-get command, like { "execute": "qom-get", "arguments": { "path": "/machine/peripheral/CARD_ID/virtio-net-pci.rom[0]", "property": "size" } } Note: we have extra initialization of size variable to zero in pci_add_option_rom to avoid false-positive "error: ‘size’ may be used uninitialized" Suggested-by: Michael S. Tsirkin Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: David Hildenbrand Reviewed-by: Juan Quintela Message-Id: <20230522201740.88960-2-vsementsov@yandex-team.ru> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 79 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 46 insertions(+), 33 deletions(-) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index bf38905b7d..e2eb4c3b4a 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -36,6 +36,7 @@ #include "migration/vmstate.h" #include "net/net.h" #include "sysemu/numa.h" +#include "sysemu/runstate.h" #include "sysemu/sysemu.h" #include "hw/loader.h" #include "qemu/error-report.h" @@ -2308,12 +2309,18 @@ static void pci_patch_ids(PCIDevice *pdev, uint8_t *ptr, uint32_t size) static void pci_add_option_rom(PCIDevice *pdev, bool is_default_rom, Error **errp) { - int64_t size; + int64_t size = 0; g_autofree char *path = NULL; - void *ptr; char name[32]; const VMStateDescription *vmsd; + /* + * In case of incoming migration ROM will come with migration stream, no + * reason to load the file. Neither we want to fail if local ROM file + * mismatches with specified romsize. + */ + bool load_file = !runstate_check(RUN_STATE_INMIGRATE); + if (!pdev->romfile || !strlen(pdev->romfile)) { return; } @@ -2343,32 +2350,35 @@ static void pci_add_option_rom(PCIDevice *pdev, bool is_default_rom, return; } - path = qemu_find_file(QEMU_FILE_TYPE_BIOS, pdev->romfile); - if (path == NULL) { - path = g_strdup(pdev->romfile); - } + if (load_file || pdev->romsize == -1) { + path = qemu_find_file(QEMU_FILE_TYPE_BIOS, pdev->romfile); + if (path == NULL) { + path = g_strdup(pdev->romfile); + } - size = get_image_size(path); - if (size < 0) { - error_setg(errp, "failed to find romfile \"%s\"", pdev->romfile); - return; - } else if (size == 0) { - error_setg(errp, "romfile \"%s\" is empty", pdev->romfile); - return; - } else if (size > 2 * GiB) { - error_setg(errp, "romfile \"%s\" too large (size cannot exceed 2 GiB)", - pdev->romfile); - return; - } - if (pdev->romsize != -1) { - if (size > pdev->romsize) { - error_setg(errp, "romfile \"%s\" (%u bytes) " - "is too large for ROM size %u", - pdev->romfile, (uint32_t)size, pdev->romsize); + size = get_image_size(path); + if (size < 0) { + error_setg(errp, "failed to find romfile \"%s\"", pdev->romfile); + return; + } else if (size == 0) { + error_setg(errp, "romfile \"%s\" is empty", pdev->romfile); + return; + } else if (size > 2 * GiB) { + error_setg(errp, + "romfile \"%s\" too large (size cannot exceed 2 GiB)", + pdev->romfile); return; } - } else { - pdev->romsize = pow2ceil(size); + if (pdev->romsize != -1) { + if (size > pdev->romsize) { + error_setg(errp, "romfile \"%s\" (%u bytes) " + "is too large for ROM size %u", + pdev->romfile, (uint32_t)size, pdev->romsize); + return; + } + } else { + pdev->romsize = pow2ceil(size); + } } vmsd = qdev_get_vmsd(DEVICE(pdev)); @@ -2379,15 +2389,18 @@ static void pci_add_option_rom(PCIDevice *pdev, bool is_default_rom, memory_region_init_rom(&pdev->rom, OBJECT(pdev), name, pdev->romsize, &error_fatal); - ptr = memory_region_get_ram_ptr(&pdev->rom); - if (load_image_size(path, ptr, size) < 0) { - error_setg(errp, "failed to load romfile \"%s\"", pdev->romfile); - return; - } + if (load_file) { + void *ptr = memory_region_get_ram_ptr(&pdev->rom); - if (is_default_rom) { - /* Only the default rom images will be patched (if needed). */ - pci_patch_ids(pdev, ptr, size); + if (load_image_size(path, ptr, size) < 0) { + error_setg(errp, "failed to load romfile \"%s\"", pdev->romfile); + return; + } + + if (is_default_rom) { + /* Only the default rom images will be patched (if needed). */ + pci_patch_ids(pdev, ptr, size); + } } pci_register_bar(pdev, PCI_ROM_SLOT, 0, &pdev->rom); From 25c893037b89ddd4e42927a2a9b524dbbc0c34a3 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 23 May 2023 20:30:36 +0200 Subject: [PATCH 0070/1353] virtio-mem: Simplify bitmap handling and virtio_mem_set_block_state() Let's separate plug and unplug handling to prepare for future changes and make the code a bit easier to read -- working on block states (plugged/unplugged) instead of on a bitmap. Cc: "Michael S. Tsirkin" Cc: Gavin Shan Signed-off-by: David Hildenbrand Message-Id: <20230523183036.517957-1-david@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-mem.c | 112 +++++++++++++++++++++++------------------ 1 file changed, 64 insertions(+), 48 deletions(-) diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c index 12ea58d5ad..ec0ae32589 100644 --- a/hw/virtio/virtio-mem.c +++ b/hw/virtio/virtio-mem.c @@ -398,33 +398,46 @@ static void virtio_mem_notify_unplug_all(VirtIOMEM *vmem) } } -static bool virtio_mem_test_bitmap(const VirtIOMEM *vmem, uint64_t start_gpa, - uint64_t size, bool plugged) +static bool virtio_mem_is_range_plugged(const VirtIOMEM *vmem, + uint64_t start_gpa, uint64_t size) { const unsigned long first_bit = (start_gpa - vmem->addr) / vmem->block_size; const unsigned long last_bit = first_bit + (size / vmem->block_size) - 1; unsigned long found_bit; /* We fake a shorter bitmap to avoid searching too far. */ - if (plugged) { - found_bit = find_next_zero_bit(vmem->bitmap, last_bit + 1, first_bit); - } else { - found_bit = find_next_bit(vmem->bitmap, last_bit + 1, first_bit); - } + found_bit = find_next_zero_bit(vmem->bitmap, last_bit + 1, first_bit); return found_bit > last_bit; } -static void virtio_mem_set_bitmap(VirtIOMEM *vmem, uint64_t start_gpa, - uint64_t size, bool plugged) +static bool virtio_mem_is_range_unplugged(const VirtIOMEM *vmem, + uint64_t start_gpa, uint64_t size) +{ + const unsigned long first_bit = (start_gpa - vmem->addr) / vmem->block_size; + const unsigned long last_bit = first_bit + (size / vmem->block_size) - 1; + unsigned long found_bit; + + /* We fake a shorter bitmap to avoid searching too far. */ + found_bit = find_next_bit(vmem->bitmap, last_bit + 1, first_bit); + return found_bit > last_bit; +} + +static void virtio_mem_set_range_plugged(VirtIOMEM *vmem, uint64_t start_gpa, + uint64_t size) { const unsigned long bit = (start_gpa - vmem->addr) / vmem->block_size; const unsigned long nbits = size / vmem->block_size; - if (plugged) { - bitmap_set(vmem->bitmap, bit, nbits); - } else { - bitmap_clear(vmem->bitmap, bit, nbits); - } + bitmap_set(vmem->bitmap, bit, nbits); +} + +static void virtio_mem_set_range_unplugged(VirtIOMEM *vmem, uint64_t start_gpa, + uint64_t size) +{ + const unsigned long bit = (start_gpa - vmem->addr) / vmem->block_size; + const unsigned long nbits = size / vmem->block_size; + + bitmap_clear(vmem->bitmap, bit, nbits); } static void virtio_mem_send_response(VirtIOMEM *vmem, VirtQueueElement *elem, @@ -474,6 +487,7 @@ static int virtio_mem_set_block_state(VirtIOMEM *vmem, uint64_t start_gpa, { const uint64_t offset = start_gpa - vmem->addr; RAMBlock *rb = vmem->memdev->mr.ram_block; + int ret = 0; if (virtio_mem_is_busy()) { return -EBUSY; @@ -484,42 +498,43 @@ static int virtio_mem_set_block_state(VirtIOMEM *vmem, uint64_t start_gpa, return -EBUSY; } virtio_mem_notify_unplug(vmem, offset, size); - } else { - int ret = 0; + virtio_mem_set_range_unplugged(vmem, start_gpa, size); + return 0; + } - if (vmem->prealloc) { - void *area = memory_region_get_ram_ptr(&vmem->memdev->mr) + offset; - int fd = memory_region_get_fd(&vmem->memdev->mr); - Error *local_err = NULL; + if (vmem->prealloc) { + void *area = memory_region_get_ram_ptr(&vmem->memdev->mr) + offset; + int fd = memory_region_get_fd(&vmem->memdev->mr); + Error *local_err = NULL; - qemu_prealloc_mem(fd, area, size, 1, NULL, &local_err); - if (local_err) { - static bool warned; + qemu_prealloc_mem(fd, area, size, 1, NULL, &local_err); + if (local_err) { + static bool warned; - /* - * Warn only once, we don't want to fill the log with these - * warnings. - */ - if (!warned) { - warn_report_err(local_err); - warned = true; - } else { - error_free(local_err); - } - ret = -EBUSY; + /* + * Warn only once, we don't want to fill the log with these + * warnings. + */ + if (!warned) { + warn_report_err(local_err); + warned = true; + } else { + error_free(local_err); } - } - if (!ret) { - ret = virtio_mem_notify_plug(vmem, offset, size); - } - - if (ret) { - /* Could be preallocation or a notifier populated memory. */ - ram_block_discard_range(vmem->memdev->mr.ram_block, offset, size); - return -EBUSY; + ret = -EBUSY; } } - virtio_mem_set_bitmap(vmem, start_gpa, size, plug); + + if (!ret) { + ret = virtio_mem_notify_plug(vmem, offset, size); + } + if (ret) { + /* Could be preallocation or a notifier populated memory. */ + ram_block_discard_range(vmem->memdev->mr.ram_block, offset, size); + return -EBUSY; + } + + virtio_mem_set_range_plugged(vmem, start_gpa, size); return 0; } @@ -538,7 +553,8 @@ static int virtio_mem_state_change_request(VirtIOMEM *vmem, uint64_t gpa, } /* test if really all blocks are in the opposite state */ - if (!virtio_mem_test_bitmap(vmem, gpa, size, !plug)) { + if ((plug && !virtio_mem_is_range_unplugged(vmem, gpa, size)) || + (!plug && !virtio_mem_is_range_plugged(vmem, gpa, size))) { return VIRTIO_MEM_RESP_ERROR; } @@ -651,9 +667,9 @@ static void virtio_mem_state_request(VirtIOMEM *vmem, VirtQueueElement *elem, return; } - if (virtio_mem_test_bitmap(vmem, gpa, size, true)) { + if (virtio_mem_is_range_plugged(vmem, gpa, size)) { resp.u.state.state = cpu_to_le16(VIRTIO_MEM_STATE_PLUGGED); - } else if (virtio_mem_test_bitmap(vmem, gpa, size, false)) { + } else if (virtio_mem_is_range_unplugged(vmem, gpa, size)) { resp.u.state.state = cpu_to_le16(VIRTIO_MEM_STATE_UNPLUGGED); } else { resp.u.state.state = cpu_to_le16(VIRTIO_MEM_STATE_MIXED); @@ -1372,7 +1388,7 @@ static bool virtio_mem_rdm_is_populated(const RamDiscardManager *rdm, return false; } - return virtio_mem_test_bitmap(vmem, start_gpa, end_gpa - start_gpa, true); + return virtio_mem_is_range_plugged(vmem, start_gpa, end_gpa - start_gpa); } struct VirtIOMEMReplayData { From 0f2bb0bf38b04e9dfdc32ce5c762dd317f5a4c5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= Date: Fri, 26 May 2023 17:31:42 +0200 Subject: [PATCH 0071/1353] vdpa: return errno in vhost_vdpa_get_vring_group error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need to tell in the caller, as some errors are expected in a normal workflow. In particular, parent drivers in recent kernels with VHOST_BACKEND_F_IOTLB_ASID may not support vring groups. In that case, -ENOTSUP is returned. This is the case of vp_vdpa in Linux 6.2. Next patches in this series will use that information to know if it must abort or not. Also, next patches return properly an errp instead of printing with error_report. Reviewed-by: Stefano Garzarella Acked-by: Jason Wang Signed-off-by: Eugenio Pérez Message-Id: <20230526153143.470745-2-eperezma@redhat.com> Tested-by: Lei Yang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- net/vhost-vdpa.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index 37cdc84562..3fb833fe76 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -362,6 +362,14 @@ static NetClientInfo net_vhost_vdpa_info = { .check_peer_type = vhost_vdpa_check_peer_type, }; +/** + * Get vring virtqueue group + * + * @device_fd vdpa device fd + * @vq_index Virtqueue index + * + * Return -errno in case of error, or vq group if success. + */ static int64_t vhost_vdpa_get_vring_group(int device_fd, unsigned vq_index) { struct vhost_vring_state state = { @@ -370,6 +378,7 @@ static int64_t vhost_vdpa_get_vring_group(int device_fd, unsigned vq_index) int r = ioctl(device_fd, VHOST_VDPA_GET_VRING_GROUP, &state); if (unlikely(r < 0)) { + r = -errno; error_report("Cannot get VQ %u group: %s", vq_index, g_strerror(errno)); return r; From 152128d646973ed298d41dafd7a5bccff43336c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= Date: Fri, 26 May 2023 17:31:43 +0200 Subject: [PATCH 0072/1353] vdpa: move CVQ isolation check to net_init_vhost_vdpa MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Evaluating it at start time instead of initialization time may make the guest capable of dynamically adding or removing migration blockers. Also, moving to initialization reduces the number of ioctls in the migration, reducing failure possibilities. As a drawback we need to check for CVQ isolation twice: one time with no MQ negotiated and another one acking it, as long as the device supports it. This is because Vring ASID / group management is based on vq indexes, but we don't know the index of CVQ before negotiating MQ. Signed-off-by: Eugenio Pérez Message-Id: <20230526153143.470745-3-eperezma@redhat.com> Tested-by: Lei Yang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang --- net/vhost-vdpa.c | 157 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 113 insertions(+), 44 deletions(-) diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index 3fb833fe76..46778d5313 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -43,6 +43,10 @@ typedef struct VhostVDPAState { /* The device always have SVQ enabled */ bool always_svq; + + /* The device can isolate CVQ in its own ASID */ + bool cvq_isolated; + bool started; } VhostVDPAState; @@ -362,15 +366,8 @@ static NetClientInfo net_vhost_vdpa_info = { .check_peer_type = vhost_vdpa_check_peer_type, }; -/** - * Get vring virtqueue group - * - * @device_fd vdpa device fd - * @vq_index Virtqueue index - * - * Return -errno in case of error, or vq group if success. - */ -static int64_t vhost_vdpa_get_vring_group(int device_fd, unsigned vq_index) +static int64_t vhost_vdpa_get_vring_group(int device_fd, unsigned vq_index, + Error **errp) { struct vhost_vring_state state = { .index = vq_index, @@ -379,8 +376,7 @@ static int64_t vhost_vdpa_get_vring_group(int device_fd, unsigned vq_index) if (unlikely(r < 0)) { r = -errno; - error_report("Cannot get VQ %u group: %s", vq_index, - g_strerror(errno)); + error_setg_errno(errp, errno, "Cannot get VQ %u group", vq_index); return r; } @@ -480,9 +476,9 @@ static int vhost_vdpa_net_cvq_start(NetClientState *nc) { VhostVDPAState *s, *s0; struct vhost_vdpa *v; - uint64_t backend_features; int64_t cvq_group; - int cvq_index, r; + int r; + Error *err = NULL; assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); @@ -502,40 +498,21 @@ static int vhost_vdpa_net_cvq_start(NetClientState *nc) /* * If we early return in these cases SVQ will not be enabled. The migration * will be blocked as long as vhost-vdpa backends will not offer _F_LOG. - * - * Calling VHOST_GET_BACKEND_FEATURES as they are not available in v->dev - * yet. */ - r = ioctl(v->device_fd, VHOST_GET_BACKEND_FEATURES, &backend_features); - if (unlikely(r < 0)) { - error_report("Cannot get vdpa backend_features: %s(%d)", - g_strerror(errno), errno); - return -1; - } - if (!(backend_features & BIT_ULL(VHOST_BACKEND_F_IOTLB_ASID)) || - !vhost_vdpa_net_valid_svq_features(v->dev->features, NULL)) { + if (!vhost_vdpa_net_valid_svq_features(v->dev->features, NULL)) { return 0; } - /* - * Check if all the virtqueues of the virtio device are in a different vq - * than the last vq. VQ group of last group passed in cvq_group. - */ - cvq_index = v->dev->vq_index_end - 1; - cvq_group = vhost_vdpa_get_vring_group(v->device_fd, cvq_index); - if (unlikely(cvq_group < 0)) { - return cvq_group; + if (!s->cvq_isolated) { + return 0; } - for (int i = 0; i < cvq_index; ++i) { - int64_t group = vhost_vdpa_get_vring_group(v->device_fd, i); - if (unlikely(group < 0)) { - return group; - } - - if (group == cvq_group) { - return 0; - } + cvq_group = vhost_vdpa_get_vring_group(v->device_fd, + v->dev->vq_index_end - 1, + &err); + if (unlikely(cvq_group < 0)) { + error_report_err(err); + return cvq_group; } r = vhost_vdpa_set_address_space_id(v, cvq_group, VHOST_VDPA_NET_CVQ_ASID); @@ -799,6 +776,87 @@ static const VhostShadowVirtqueueOps vhost_vdpa_net_svq_ops = { .avail_handler = vhost_vdpa_net_handle_ctrl_avail, }; +/** + * Probe if CVQ is isolated + * + * @device_fd The vdpa device fd + * @features Features offered by the device. + * @cvq_index The control vq pair index + * + * Returns <0 in case of failure, 0 if false and 1 if true. + */ +static int vhost_vdpa_probe_cvq_isolation(int device_fd, uint64_t features, + int cvq_index, Error **errp) +{ + uint64_t backend_features; + int64_t cvq_group; + uint8_t status = VIRTIO_CONFIG_S_ACKNOWLEDGE | + VIRTIO_CONFIG_S_DRIVER | + VIRTIO_CONFIG_S_FEATURES_OK; + int r; + + ERRP_GUARD(); + + r = ioctl(device_fd, VHOST_GET_BACKEND_FEATURES, &backend_features); + if (unlikely(r < 0)) { + error_setg_errno(errp, errno, "Cannot get vdpa backend_features"); + return r; + } + + if (!(backend_features & BIT_ULL(VHOST_BACKEND_F_IOTLB_ASID))) { + return 0; + } + + r = ioctl(device_fd, VHOST_SET_FEATURES, &features); + if (unlikely(r)) { + error_setg_errno(errp, errno, "Cannot set features"); + } + + r = ioctl(device_fd, VHOST_VDPA_SET_STATUS, &status); + if (unlikely(r)) { + error_setg_errno(errp, -r, "Cannot set device features"); + goto out; + } + + cvq_group = vhost_vdpa_get_vring_group(device_fd, cvq_index, errp); + if (unlikely(cvq_group < 0)) { + if (cvq_group != -ENOTSUP) { + r = cvq_group; + goto out; + } + + /* + * The kernel report VHOST_BACKEND_F_IOTLB_ASID if the vdpa frontend + * support ASID even if the parent driver does not. The CVQ cannot be + * isolated in this case. + */ + error_free(*errp); + *errp = NULL; + r = 0; + goto out; + } + + for (int i = 0; i < cvq_index; ++i) { + int64_t group = vhost_vdpa_get_vring_group(device_fd, i, errp); + if (unlikely(group < 0)) { + r = group; + goto out; + } + + if (group == (int64_t)cvq_group) { + r = 0; + goto out; + } + } + + r = 1; + +out: + status = 0; + ioctl(device_fd, VHOST_VDPA_SET_STATUS, &status); + return r; +} + static NetClientState *net_vhost_vdpa_init(NetClientState *peer, const char *device, const char *name, @@ -808,16 +866,26 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, bool is_datapath, bool svq, struct vhost_vdpa_iova_range iova_range, - uint64_t features) + uint64_t features, + Error **errp) { NetClientState *nc = NULL; VhostVDPAState *s; int ret = 0; assert(name); + int cvq_isolated; + if (is_datapath) { nc = qemu_new_net_client(&net_vhost_vdpa_info, peer, device, name); } else { + cvq_isolated = vhost_vdpa_probe_cvq_isolation(vdpa_device_fd, features, + queue_pair_index * 2, + errp); + if (unlikely(cvq_isolated < 0)) { + return NULL; + } + nc = qemu_new_net_control_client(&net_vhost_vdpa_cvq_info, peer, device, name); } @@ -844,6 +912,7 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, s->vhost_vdpa.shadow_vq_ops = &vhost_vdpa_net_svq_ops; s->vhost_vdpa.shadow_vq_ops_opaque = s; + s->cvq_isolated = cvq_isolated; /* * TODO: We cannot migrate devices with CVQ as there is no way to set @@ -972,7 +1041,7 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, for (i = 0; i < queue_pairs; i++) { ncs[i] = net_vhost_vdpa_init(peer, TYPE_VHOST_VDPA, name, vdpa_device_fd, i, 2, true, opts->x_svq, - iova_range, features); + iova_range, features, errp); if (!ncs[i]) goto err; } @@ -980,7 +1049,7 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name, if (has_cvq) { nc = net_vhost_vdpa_init(peer, TYPE_VHOST_VDPA, name, vdpa_device_fd, i, 1, false, - opts->x_svq, iova_range, features); + opts->x_svq, iova_range, features, errp); if (!nc) goto err; } From a1f85cff902f3260d85c74ec11d4c4b182cead80 Mon Sep 17 00:00:00 2001 From: zhenwei pi Date: Wed, 3 May 2023 19:54:37 +0800 Subject: [PATCH 0073/1353] cryptodev: fix memory leak during stats query object_get_canonical_path already returns newly allocated memory, this means no additional g_strdup required. Remove g_strdup to avoid memory leak. Fixes: Coverity CID 1508074 Fixes: f2b901098 ("cryptodev: Support query-stats QMP command") Cc: Peter Maydell Signed-off-by: zhenwei pi Message-Id: <20230503115437.262469-1-pizhenwei@bytedance.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- backends/cryptodev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/cryptodev.c b/backends/cryptodev.c index 94ca393cee..7d29517843 100644 --- a/backends/cryptodev.c +++ b/backends/cryptodev.c @@ -522,7 +522,7 @@ static int cryptodev_backend_stats_query(Object *obj, void *data) entry = g_new0(StatsResult, 1); entry->provider = STATS_PROVIDER_CRYPTODEV; - entry->qom_path = g_strdup(object_get_canonical_path(obj)); + entry->qom_path = object_get_canonical_path(obj); entry->stats = stats_list; QAPI_LIST_PREPEND(*stats_results, entry); From b9f335c24705883391ea52035c9b2229e6992eee Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Jun 2023 11:15:43 +0100 Subject: [PATCH 0074/1353] target/arm: Add isar_feature_aa64_rme MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the missing field for ID_AA64PFR0, and the predicate. Disable it if EL3 is forced off by the board or command-line. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20230620124418.805717-2-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.c | 4 ++++ target/arm/cpu.h | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 353fc48567..842e1b53ee 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1989,6 +1989,10 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) cpu->isar.id_dfr0 = FIELD_DP32(cpu->isar.id_dfr0, ID_DFR0, COPSDBG, 0); cpu->isar.id_aa64pfr0 = FIELD_DP64(cpu->isar.id_aa64pfr0, ID_AA64PFR0, EL3, 0); + + /* Disable the realm management extension, which requires EL3. */ + cpu->isar.id_aa64pfr0 = FIELD_DP64(cpu->isar.id_aa64pfr0, + ID_AA64PFR0, RME, 0); } if (!cpu->has_el2) { diff --git a/target/arm/cpu.h b/target/arm/cpu.h index af0119addf..c84ec2752f 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -2195,6 +2195,7 @@ FIELD(ID_AA64PFR0, SEL2, 36, 4) FIELD(ID_AA64PFR0, MPAM, 40, 4) FIELD(ID_AA64PFR0, AMU, 44, 4) FIELD(ID_AA64PFR0, DIT, 48, 4) +FIELD(ID_AA64PFR0, RME, 52, 4) FIELD(ID_AA64PFR0, CSV2, 56, 4) FIELD(ID_AA64PFR0, CSV3, 60, 4) @@ -3814,6 +3815,11 @@ static inline bool isar_feature_aa64_sel2(const ARMISARegisters *id) return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, SEL2) != 0; } +static inline bool isar_feature_aa64_rme(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, RME) != 0; +} + static inline bool isar_feature_aa64_vh(const ARMISARegisters *id) { return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, VH) != 0; From aa3cc42c016116615b80359ab4dd8a934339aec5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Jun 2023 11:15:43 +0100 Subject: [PATCH 0075/1353] target/arm: Update SCR and HCR for RME Define the missing SCR and HCR bits, allow SCR_NSE and {SCR,HCR}_GPF to be set, and invalidate TLBs when NSE changes. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20230620124418.805717-3-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.h | 5 +++-- target/arm/helper.c | 10 ++++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index c84ec2752f..318d1033b8 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -1655,7 +1655,7 @@ static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask) #define HCR_TERR (1ULL << 36) #define HCR_TEA (1ULL << 37) #define HCR_MIOCNCE (1ULL << 38) -/* RES0 bit 39 */ +#define HCR_TME (1ULL << 39) #define HCR_APK (1ULL << 40) #define HCR_API (1ULL << 41) #define HCR_NV (1ULL << 42) @@ -1664,7 +1664,7 @@ static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask) #define HCR_NV2 (1ULL << 45) #define HCR_FWB (1ULL << 46) #define HCR_FIEN (1ULL << 47) -/* RES0 bit 48 */ +#define HCR_GPF (1ULL << 48) #define HCR_TID4 (1ULL << 49) #define HCR_TICAB (1ULL << 50) #define HCR_AMVOFFEN (1ULL << 51) @@ -1729,6 +1729,7 @@ static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask) #define SCR_TRNDR (1ULL << 40) #define SCR_ENTP2 (1ULL << 41) #define SCR_GPF (1ULL << 48) +#define SCR_NSE (1ULL << 62) #define HSTR_TTEE (1 << 16) #define HSTR_TJDBX (1 << 17) diff --git a/target/arm/helper.c b/target/arm/helper.c index d4bee43bd0..d2f0d9226e 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -1874,6 +1874,9 @@ static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) if (cpu_isar_feature(aa64_fgt, cpu)) { valid_mask |= SCR_FGTEN; } + if (cpu_isar_feature(aa64_rme, cpu)) { + valid_mask |= SCR_NSE | SCR_GPF; + } } else { valid_mask &= ~(SCR_RW | SCR_ST); if (cpu_isar_feature(aa32_ras, cpu)) { @@ -1903,10 +1906,10 @@ static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) env->cp15.scr_el3 = value; /* - * If SCR_EL3.NS changes, i.e. arm_is_secure_below_el3, then + * If SCR_EL3.{NS,NSE} changes, i.e. change of security state, * we must invalidate all TLBs below EL3. */ - if (changed & SCR_NS) { + if (changed & (SCR_NS | SCR_NSE)) { tlb_flush_by_mmuidx(env_cpu(env), (ARMMMUIdxBit_E10_0 | ARMMMUIdxBit_E20_0 | ARMMMUIdxBit_E10_1 | @@ -5654,6 +5657,9 @@ static void do_hcr_write(CPUARMState *env, uint64_t value, uint64_t valid_mask) if (cpu_isar_feature(aa64_fwb, cpu)) { valid_mask |= HCR_FWB; } + if (cpu_isar_feature(aa64_rme, cpu)) { + valid_mask |= HCR_GPF; + } } if (cpu_isar_feature(any_evt, cpu)) { From 87bfbfe7e595372251037c28223919659a294fd3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Jun 2023 11:15:43 +0100 Subject: [PATCH 0076/1353] target/arm: SCR_EL3.NS may be RES1 With RME, SEL2 must also be present to support secure state. The NS bit is RES1 if SEL2 is not present. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20230620124418.805717-4-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/target/arm/helper.c b/target/arm/helper.c index d2f0d9226e..9132d4de6a 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -1855,6 +1855,9 @@ static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) } if (cpu_isar_feature(aa64_sel2, cpu)) { valid_mask |= SCR_EEL2; + } else if (cpu_isar_feature(aa64_rme, cpu)) { + /* With RME and without SEL2, NS is RES1 (R_GSWWH, I_DJJQJ). */ + value |= SCR_NS; } if (cpu_isar_feature(aa64_mte, cpu)) { valid_mask |= SCR_ATA; From ef1febe758c893dfc2164c5324bbbe5ba4916413 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Jun 2023 11:15:44 +0100 Subject: [PATCH 0077/1353] target/arm: Add RME cpregs This includes GPCCR, GPTBR, MFAR, the TLB flush insns PAALL, PAALLOS, RPALOS, RPAOS, and the cache flush insns CIPAPA and CIGDPAPA. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20230620124418.805717-5-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.h | 19 ++++++++++ target/arm/helper.c | 84 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 318d1033b8..c9c87b515d 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -541,6 +541,11 @@ typedef struct CPUArchState { uint64_t fgt_read[2]; /* HFGRTR, HDFGRTR */ uint64_t fgt_write[2]; /* HFGWTR, HDFGWTR */ uint64_t fgt_exec[1]; /* HFGITR */ + + /* RME registers */ + uint64_t gpccr_el3; + uint64_t gptbr_el3; + uint64_t mfar_el3; } cp15; struct { @@ -1055,6 +1060,7 @@ struct ArchCPU { uint64_t reset_cbar; uint32_t reset_auxcr; bool reset_hivecs; + uint8_t reset_l0gptsz; /* * Intermediate values used during property parsing. @@ -2341,6 +2347,19 @@ FIELD(MVFR1, SIMDFMAC, 28, 4) FIELD(MVFR2, SIMDMISC, 0, 4) FIELD(MVFR2, FPMISC, 4, 4) +FIELD(GPCCR, PPS, 0, 3) +FIELD(GPCCR, IRGN, 8, 2) +FIELD(GPCCR, ORGN, 10, 2) +FIELD(GPCCR, SH, 12, 2) +FIELD(GPCCR, PGS, 14, 2) +FIELD(GPCCR, GPC, 16, 1) +FIELD(GPCCR, GPCP, 17, 1) +FIELD(GPCCR, L0GPTSZ, 20, 4) + +FIELD(MFAR, FPA, 12, 40) +FIELD(MFAR, NSE, 62, 1) +FIELD(MFAR, NS, 63, 1) + QEMU_BUILD_BUG_ON(ARRAY_SIZE(((ARMCPU *)0)->ccsidr) <= R_V7M_CSSELR_INDEX_MASK); /* If adding a feature bit which corresponds to a Linux ELF diff --git a/target/arm/helper.c b/target/arm/helper.c index 9132d4de6a..006447dde8 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6910,6 +6910,83 @@ static const ARMCPRegInfo sme_reginfo[] = { .access = PL2_RW, .accessfn = access_esm, .type = ARM_CP_CONST, .resetvalue = 0 }, }; + +static void tlbi_aa64_paall_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + CPUState *cs = env_cpu(env); + + tlb_flush(cs); +} + +static void gpccr_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + /* L0GPTSZ is RO; other bits not mentioned are RES0. */ + uint64_t rw_mask = R_GPCCR_PPS_MASK | R_GPCCR_IRGN_MASK | + R_GPCCR_ORGN_MASK | R_GPCCR_SH_MASK | R_GPCCR_PGS_MASK | + R_GPCCR_GPC_MASK | R_GPCCR_GPCP_MASK; + + env->cp15.gpccr_el3 = (value & rw_mask) | (env->cp15.gpccr_el3 & ~rw_mask); +} + +static void gpccr_reset(CPUARMState *env, const ARMCPRegInfo *ri) +{ + env->cp15.gpccr_el3 = FIELD_DP64(0, GPCCR, L0GPTSZ, + env_archcpu(env)->reset_l0gptsz); +} + +static void tlbi_aa64_paallos_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + CPUState *cs = env_cpu(env); + + tlb_flush_all_cpus_synced(cs); +} + +static const ARMCPRegInfo rme_reginfo[] = { + { .name = "GPCCR_EL3", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 6, .crn = 2, .crm = 1, .opc2 = 6, + .access = PL3_RW, .writefn = gpccr_write, .resetfn = gpccr_reset, + .fieldoffset = offsetof(CPUARMState, cp15.gpccr_el3) }, + { .name = "GPTBR_EL3", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 6, .crn = 2, .crm = 1, .opc2 = 4, + .access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.gptbr_el3) }, + { .name = "MFAR_EL3", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 6, .crn = 6, .crm = 0, .opc2 = 5, + .access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.mfar_el3) }, + { .name = "TLBI_PAALL", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 7, .opc2 = 4, + .access = PL3_W, .type = ARM_CP_NO_RAW, + .writefn = tlbi_aa64_paall_write }, + { .name = "TLBI_PAALLOS", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 1, .opc2 = 4, + .access = PL3_W, .type = ARM_CP_NO_RAW, + .writefn = tlbi_aa64_paallos_write }, + /* + * QEMU does not have a way to invalidate by physical address, thus + * invalidating a range of physical addresses is accomplished by + * flushing all tlb entries in the outer sharable domain, + * just like PAALLOS. + */ + { .name = "TLBI_RPALOS", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 4, .opc2 = 7, + .access = PL3_W, .type = ARM_CP_NO_RAW, + .writefn = tlbi_aa64_paallos_write }, + { .name = "TLBI_RPAOS", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 6, .crn = 8, .crm = 4, .opc2 = 3, + .access = PL3_W, .type = ARM_CP_NO_RAW, + .writefn = tlbi_aa64_paallos_write }, + { .name = "DC_CIPAPA", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 6, .crn = 7, .crm = 14, .opc2 = 1, + .access = PL3_W, .type = ARM_CP_NOP }, +}; + +static const ARMCPRegInfo rme_mte_reginfo[] = { + { .name = "DC_CIGDPAPA", .state = ARM_CP_STATE_AA64, + .opc0 = 1, .opc1 = 6, .crn = 7, .crm = 14, .opc2 = 5, + .access = PL3_W, .type = ARM_CP_NOP }, +}; #endif /* TARGET_AARCH64 */ static void define_pmu_regs(ARMCPU *cpu) @@ -9130,6 +9207,13 @@ void register_cp_regs_for_features(ARMCPU *cpu) if (cpu_isar_feature(aa64_fgt, cpu)) { define_arm_cp_regs(cpu, fgt_reginfo); } + + if (cpu_isar_feature(aa64_rme, cpu)) { + define_arm_cp_regs(cpu, rme_reginfo); + if (cpu_isar_feature(aa64_mte, cpu)) { + define_arm_cp_regs(cpu, rme_mte_reginfo); + } + } #endif if (cpu_isar_feature(any_predinv, cpu)) { From 5d28ac0cf7a5cd91f03da658edd6e934c5a431bd Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Jun 2023 11:15:44 +0100 Subject: [PATCH 0078/1353] target/arm: Introduce ARMSecuritySpace Introduce both the enumeration and functions to retrieve the current state, and state outside of EL3. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20230620124418.805717-6-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.h | 89 ++++++++++++++++++++++++++++++++++----------- target/arm/helper.c | 60 ++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+), 22 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index c9c87b515d..125e53b83f 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -2414,25 +2414,53 @@ static inline int arm_feature(CPUARMState *env, int feature) void arm_cpu_finalize_features(ARMCPU *cpu, Error **errp); -#if !defined(CONFIG_USER_ONLY) /* + * ARM v9 security states. + * The ordering of the enumeration corresponds to the low 2 bits + * of the GPI value, and (except for Root) the concat of NSE:NS. + */ + +typedef enum ARMSecuritySpace { + ARMSS_Secure = 0, + ARMSS_NonSecure = 1, + ARMSS_Root = 2, + ARMSS_Realm = 3, +} ARMSecuritySpace; + +/* Return true if @space is secure, in the pre-v9 sense. */ +static inline bool arm_space_is_secure(ARMSecuritySpace space) +{ + return space == ARMSS_Secure || space == ARMSS_Root; +} + +/* Return the ARMSecuritySpace for @secure, assuming !RME or EL[0-2]. */ +static inline ARMSecuritySpace arm_secure_to_space(bool secure) +{ + return secure ? ARMSS_Secure : ARMSS_NonSecure; +} + +#if !defined(CONFIG_USER_ONLY) +/** + * arm_security_space_below_el3: + * @env: cpu context + * + * Return the security space of exception levels below EL3, following + * an exception return to those levels. Unlike arm_security_space, + * this doesn't care about the current EL. + */ +ARMSecuritySpace arm_security_space_below_el3(CPUARMState *env); + +/** + * arm_is_secure_below_el3: + * @env: cpu context + * * Return true if exception levels below EL3 are in secure state, - * or would be following an exception return to that level. - * Unlike arm_is_secure() (which is always a question about the - * _current_ state of the CPU) this doesn't care about the current - * EL or mode. + * or would be following an exception return to those levels. */ static inline bool arm_is_secure_below_el3(CPUARMState *env) { - assert(!arm_feature(env, ARM_FEATURE_M)); - if (arm_feature(env, ARM_FEATURE_EL3)) { - return !(env->cp15.scr_el3 & SCR_NS); - } else { - /* If EL3 is not supported then the secure state is implementation - * defined, in which case QEMU defaults to non-secure. - */ - return false; - } + ARMSecuritySpace ss = arm_security_space_below_el3(env); + return ss == ARMSS_Secure; } /* Return true if the CPU is AArch64 EL3 or AArch32 Mon */ @@ -2452,16 +2480,23 @@ static inline bool arm_is_el3_or_mon(CPUARMState *env) return false; } -/* Return true if the processor is in secure state */ +/** + * arm_security_space: + * @env: cpu context + * + * Return the current security space of the cpu. + */ +ARMSecuritySpace arm_security_space(CPUARMState *env); + +/** + * arm_is_secure: + * @env: cpu context + * + * Return true if the processor is in secure state. + */ static inline bool arm_is_secure(CPUARMState *env) { - if (arm_feature(env, ARM_FEATURE_M)) { - return env->v7m.secure; - } - if (arm_is_el3_or_mon(env)) { - return true; - } - return arm_is_secure_below_el3(env); + return arm_space_is_secure(arm_security_space(env)); } /* @@ -2480,11 +2515,21 @@ static inline bool arm_is_el2_enabled(CPUARMState *env) } #else +static inline ARMSecuritySpace arm_security_space_below_el3(CPUARMState *env) +{ + return ARMSS_NonSecure; +} + static inline bool arm_is_secure_below_el3(CPUARMState *env) { return false; } +static inline ARMSecuritySpace arm_security_space(CPUARMState *env) +{ + return ARMSS_NonSecure; +} + static inline bool arm_is_secure(CPUARMState *env) { return false; diff --git a/target/arm/helper.c b/target/arm/helper.c index 006447dde8..f68923d73b 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -12136,3 +12136,63 @@ void aarch64_sve_change_el(CPUARMState *env, int old_el, } } #endif + +#ifndef CONFIG_USER_ONLY +ARMSecuritySpace arm_security_space(CPUARMState *env) +{ + if (arm_feature(env, ARM_FEATURE_M)) { + return arm_secure_to_space(env->v7m.secure); + } + + /* + * If EL3 is not supported then the secure state is implementation + * defined, in which case QEMU defaults to non-secure. + */ + if (!arm_feature(env, ARM_FEATURE_EL3)) { + return ARMSS_NonSecure; + } + + /* Check for AArch64 EL3 or AArch32 Mon. */ + if (is_a64(env)) { + if (extract32(env->pstate, 2, 2) == 3) { + if (cpu_isar_feature(aa64_rme, env_archcpu(env))) { + return ARMSS_Root; + } else { + return ARMSS_Secure; + } + } + } else { + if ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_MON) { + return ARMSS_Secure; + } + } + + return arm_security_space_below_el3(env); +} + +ARMSecuritySpace arm_security_space_below_el3(CPUARMState *env) +{ + assert(!arm_feature(env, ARM_FEATURE_M)); + + /* + * If EL3 is not supported then the secure state is implementation + * defined, in which case QEMU defaults to non-secure. + */ + if (!arm_feature(env, ARM_FEATURE_EL3)) { + return ARMSS_NonSecure; + } + + /* + * Note NSE cannot be set without RME, and NSE & !NS is Reserved. + * Ignoring NSE when !NS retains consistency without having to + * modify other predicates. + */ + if (!(env->cp15.scr_el3 & SCR_NS)) { + return ARMSS_Secure; + } else if (env->cp15.scr_el3 & SCR_NSE) { + return ARMSS_Realm; + } else { + return ARMSS_NonSecure; + } +} +#endif /* !CONFIG_USER_ONLY */ From 4d6e1c6495f483e8c48526189c4c6984b44365fc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Jun 2023 11:15:44 +0100 Subject: [PATCH 0079/1353] include/exec/memattrs: Add two bits of space to MemTxAttrs We will need 2 bits to represent ARMSecurityState. Do not attempt to replace or widen secure, even though it logically overlaps the new field -- there are uses within e.g. hw/block/pflash_cfi01.c, which don't know anything specific about ARM. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20230620124418.805717-7-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- include/exec/memattrs.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/include/exec/memattrs.h b/include/exec/memattrs.h index 9fb98bc1ef..d04170aa27 100644 --- a/include/exec/memattrs.h +++ b/include/exec/memattrs.h @@ -29,10 +29,17 @@ typedef struct MemTxAttrs { * "didn't specify" if necessary. */ unsigned int unspecified:1; - /* ARM/AMBA: TrustZone Secure access + /* + * ARM/AMBA: TrustZone Secure access * x86: System Management Mode access */ unsigned int secure:1; + /* + * ARM: ArmSecuritySpace. This partially overlaps secure, but it is + * easier to have both fields to assist code that does not understand + * ARMv9 RME, or no specific knowledge of ARM at all (e.g. pflash). + */ + unsigned int space:2; /* Memory access is usermode (unprivileged) */ unsigned int user:1; /* From d38fa9670d14331fc766dfc15b2bc6628d0149d0 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Jun 2023 11:15:45 +0100 Subject: [PATCH 0080/1353] target/arm: Adjust the order of Phys and Stage2 ARMMMUIdx It will be helpful to have ARMMMUIdx_Phys_* to be in the same relative order as ARMSecuritySpace enumerators. This requires the adjustment to the nstable check. While there, check for being in secure state rather than rely on clearing the low bit making no change to non-secure state. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20230620124418.805717-8-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.h | 12 ++++++------ target/arm/ptw.c | 12 +++++------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 125e53b83f..b338619775 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -2860,18 +2860,18 @@ typedef enum ARMMMUIdx { ARMMMUIdx_E2 = 6 | ARM_MMU_IDX_A, ARMMMUIdx_E3 = 7 | ARM_MMU_IDX_A, - /* TLBs with 1-1 mapping to the physical address spaces. */ - ARMMMUIdx_Phys_NS = 8 | ARM_MMU_IDX_A, - ARMMMUIdx_Phys_S = 9 | ARM_MMU_IDX_A, - /* * Used for second stage of an S12 page table walk, or for descriptor * loads during first stage of an S1 page table walk. Note that both * are in use simultaneously for SecureEL2: the security state for * the S2 ptw is selected by the NS bit from the S1 ptw. */ - ARMMMUIdx_Stage2 = 10 | ARM_MMU_IDX_A, - ARMMMUIdx_Stage2_S = 11 | ARM_MMU_IDX_A, + ARMMMUIdx_Stage2_S = 8 | ARM_MMU_IDX_A, + ARMMMUIdx_Stage2 = 9 | ARM_MMU_IDX_A, + + /* TLBs with 1-1 mapping to the physical address spaces. */ + ARMMMUIdx_Phys_S = 10 | ARM_MMU_IDX_A, + ARMMMUIdx_Phys_NS = 11 | ARM_MMU_IDX_A, /* * These are not allocated TLBs and are used only for AT system diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 37bcb17a9e..3f3517f70b 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -1449,16 +1449,14 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw, descaddr |= (address >> (stride * (4 - level))) & indexmask; descaddr &= ~7ULL; nstable = !regime_is_stage2(mmu_idx) && extract32(tableattrs, 4, 1); - if (nstable) { + if (nstable && ptw->in_secure) { /* * Stage2_S -> Stage2 or Phys_S -> Phys_NS - * Assert that the non-secure idx are even, and relative order. + * Assert the relative order of the secure/non-secure indexes. */ - QEMU_BUILD_BUG_ON((ARMMMUIdx_Phys_NS & 1) != 0); - QEMU_BUILD_BUG_ON((ARMMMUIdx_Stage2 & 1) != 0); - QEMU_BUILD_BUG_ON(ARMMMUIdx_Phys_NS + 1 != ARMMMUIdx_Phys_S); - QEMU_BUILD_BUG_ON(ARMMMUIdx_Stage2 + 1 != ARMMMUIdx_Stage2_S); - ptw->in_ptw_idx &= ~1; + QEMU_BUILD_BUG_ON(ARMMMUIdx_Phys_S + 1 != ARMMMUIdx_Phys_NS); + QEMU_BUILD_BUG_ON(ARMMMUIdx_Stage2_S + 1 != ARMMMUIdx_Stage2); + ptw->in_ptw_idx += 1; ptw->in_secure = false; } if (!S1_ptw_translate(env, ptw, descaddr, fi)) { From bb5cc2c860c4d359e107ede2464dfe5cd297f16b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Jun 2023 11:15:45 +0100 Subject: [PATCH 0081/1353] target/arm: Introduce ARMMMUIdx_Phys_{Realm,Root} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With FEAT_RME, there are four physical address spaces. For now, just define the symbols, and mention them in the same spots as the other Phys indexes in ptw.c. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20230620124418.805717-9-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.h | 23 +++++++++++++++++++++-- target/arm/ptw.c | 10 ++++++++-- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index b338619775..590216b855 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -2870,8 +2870,10 @@ typedef enum ARMMMUIdx { ARMMMUIdx_Stage2 = 9 | ARM_MMU_IDX_A, /* TLBs with 1-1 mapping to the physical address spaces. */ - ARMMMUIdx_Phys_S = 10 | ARM_MMU_IDX_A, - ARMMMUIdx_Phys_NS = 11 | ARM_MMU_IDX_A, + ARMMMUIdx_Phys_S = 10 | ARM_MMU_IDX_A, + ARMMMUIdx_Phys_NS = 11 | ARM_MMU_IDX_A, + ARMMMUIdx_Phys_Root = 12 | ARM_MMU_IDX_A, + ARMMMUIdx_Phys_Realm = 13 | ARM_MMU_IDX_A, /* * These are not allocated TLBs and are used only for AT system @@ -2935,6 +2937,23 @@ typedef enum ARMASIdx { ARMASIdx_TagS = 3, } ARMASIdx; +static inline ARMMMUIdx arm_space_to_phys(ARMSecuritySpace space) +{ + /* Assert the relative order of the physical mmu indexes. */ + QEMU_BUILD_BUG_ON(ARMSS_Secure != 0); + QEMU_BUILD_BUG_ON(ARMMMUIdx_Phys_NS != ARMMMUIdx_Phys_S + ARMSS_NonSecure); + QEMU_BUILD_BUG_ON(ARMMMUIdx_Phys_Root != ARMMMUIdx_Phys_S + ARMSS_Root); + QEMU_BUILD_BUG_ON(ARMMMUIdx_Phys_Realm != ARMMMUIdx_Phys_S + ARMSS_Realm); + + return ARMMMUIdx_Phys_S + space; +} + +static inline ARMSecuritySpace arm_phys_to_space(ARMMMUIdx idx) +{ + assert(idx >= ARMMMUIdx_Phys_S && idx <= ARMMMUIdx_Phys_Realm); + return idx - ARMMMUIdx_Phys_S; +} + static inline bool arm_v7m_csselr_razwi(ARMCPU *cpu) { /* If all the CLIDR.Ctypem bits are 0 there are no caches, and diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 3f3517f70b..a742bc1826 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -215,8 +215,10 @@ static bool regime_translation_disabled(CPUARMState *env, ARMMMUIdx mmu_idx, case ARMMMUIdx_E3: break; - case ARMMMUIdx_Phys_NS: case ARMMMUIdx_Phys_S: + case ARMMMUIdx_Phys_NS: + case ARMMMUIdx_Phys_Root: + case ARMMMUIdx_Phys_Realm: /* No translation for physical address spaces. */ return true; @@ -2672,8 +2674,10 @@ static bool get_phys_addr_disabled(CPUARMState *env, target_ulong address, switch (mmu_idx) { case ARMMMUIdx_Stage2: case ARMMMUIdx_Stage2_S: - case ARMMMUIdx_Phys_NS: case ARMMMUIdx_Phys_S: + case ARMMMUIdx_Phys_NS: + case ARMMMUIdx_Phys_Root: + case ARMMMUIdx_Phys_Realm: break; default: @@ -2861,6 +2865,8 @@ static bool get_phys_addr_with_struct(CPUARMState *env, S1Translate *ptw, switch (mmu_idx) { case ARMMMUIdx_Phys_S: case ARMMMUIdx_Phys_NS: + case ARMMMUIdx_Phys_Root: + case ARMMMUIdx_Phys_Realm: /* Checking Phys early avoids special casing later vs regime_el. */ return get_phys_addr_disabled(env, address, access_type, mmu_idx, is_secure, result, fi); From 86a438b462406c7944be1fea8b027604e85253ff Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Jun 2023 11:15:45 +0100 Subject: [PATCH 0082/1353] target/arm: Remove __attribute__((nonnull)) from ptw.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was added in 7e98e21c098 as part of a reorg in which one of the argument had been legally NULL, and this caught actual instances. Now that the reorg is complete, this serves little purpose. Reviewed-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson Message-id: 20230620124418.805717-10-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/ptw.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/target/arm/ptw.c b/target/arm/ptw.c index a742bc1826..f7cbb984f9 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -34,15 +34,13 @@ typedef struct S1Translate { static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw, uint64_t address, MMUAccessType access_type, bool s1_is_el0, - GetPhysAddrResult *result, ARMMMUFaultInfo *fi) - __attribute__((nonnull)); + GetPhysAddrResult *result, ARMMMUFaultInfo *fi); static bool get_phys_addr_with_struct(CPUARMState *env, S1Translate *ptw, target_ulong address, MMUAccessType access_type, GetPhysAddrResult *result, - ARMMMUFaultInfo *fi) - __attribute__((nonnull)); + ARMMMUFaultInfo *fi); /* This mapping is common between ID_AA64MMFR0.PARANGE and TCR_ELx.{I}PS. */ static const uint8_t pamax_map[] = { From 90c6629393e0d7121c84033b3aa886fd0662a1c7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Jun 2023 11:15:45 +0100 Subject: [PATCH 0083/1353] target/arm: Pipe ARMSecuritySpace through ptw.c Add input and output space members to S1Translate. Set and adjust them in S1_ptw_translate, and the various points at which we drop secure state. Initialize the space in get_phys_addr; for now leave get_phys_addr_with_secure considering only secure vs non-secure spaces. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20230620124418.805717-11-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/ptw.c | 86 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 71 insertions(+), 15 deletions(-) diff --git a/target/arm/ptw.c b/target/arm/ptw.c index f7cbb984f9..e1e7c9a3d2 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -21,11 +21,13 @@ typedef struct S1Translate { ARMMMUIdx in_mmu_idx; ARMMMUIdx in_ptw_idx; + ARMSecuritySpace in_space; bool in_secure; bool in_debug; bool out_secure; bool out_rw; bool out_be; + ARMSecuritySpace out_space; hwaddr out_virt; hwaddr out_phys; void *out_host; @@ -249,6 +251,7 @@ static bool S2_attrs_are_device(uint64_t hcr, uint8_t attrs) static bool S1_ptw_translate(CPUARMState *env, S1Translate *ptw, hwaddr addr, ARMMMUFaultInfo *fi) { + ARMSecuritySpace space = ptw->in_space; bool is_secure = ptw->in_secure; ARMMMUIdx mmu_idx = ptw->in_mmu_idx; ARMMMUIdx s2_mmu_idx = ptw->in_ptw_idx; @@ -266,6 +269,9 @@ static bool S1_ptw_translate(CPUARMState *env, S1Translate *ptw, .in_mmu_idx = s2_mmu_idx, .in_ptw_idx = ptw_idx_for_stage_2(env, s2_mmu_idx), .in_secure = s2_mmu_idx == ARMMMUIdx_Stage2_S, + .in_space = (s2_mmu_idx == ARMMMUIdx_Stage2_S ? ARMSS_Secure + : space == ARMSS_Realm ? ARMSS_Realm + : ARMSS_NonSecure), .in_debug = true, }; GetPhysAddrResult s2 = { }; @@ -277,11 +283,15 @@ static bool S1_ptw_translate(CPUARMState *env, S1Translate *ptw, ptw->out_phys = s2.f.phys_addr; pte_attrs = s2.cacheattrs.attrs; ptw->out_secure = s2.f.attrs.secure; + ptw->out_space = s2.f.attrs.space; } else { /* Regime is physical. */ ptw->out_phys = addr; pte_attrs = 0; ptw->out_secure = s2_mmu_idx == ARMMMUIdx_Phys_S; + ptw->out_space = (s2_mmu_idx == ARMMMUIdx_Phys_S ? ARMSS_Secure + : space == ARMSS_Realm ? ARMSS_Realm + : ARMSS_NonSecure); } ptw->out_host = NULL; ptw->out_rw = false; @@ -303,6 +313,7 @@ static bool S1_ptw_translate(CPUARMState *env, S1Translate *ptw, ptw->out_rw = full->prot & PAGE_WRITE; pte_attrs = full->pte_attrs; ptw->out_secure = full->attrs.secure; + ptw->out_space = full->attrs.space; #else g_assert_not_reached(); #endif @@ -355,7 +366,10 @@ static uint32_t arm_ldl_ptw(CPUARMState *env, S1Translate *ptw, } } else { /* Page tables are in MMIO. */ - MemTxAttrs attrs = { .secure = ptw->out_secure }; + MemTxAttrs attrs = { + .secure = ptw->out_secure, + .space = ptw->out_space, + }; AddressSpace *as = arm_addressspace(cs, attrs); MemTxResult result = MEMTX_OK; @@ -398,7 +412,10 @@ static uint64_t arm_ldq_ptw(CPUARMState *env, S1Translate *ptw, #endif } else { /* Page tables are in MMIO. */ - MemTxAttrs attrs = { .secure = ptw->out_secure }; + MemTxAttrs attrs = { + .secure = ptw->out_secure, + .space = ptw->out_space, + }; AddressSpace *as = arm_addressspace(cs, attrs); MemTxResult result = MEMTX_OK; @@ -909,6 +926,7 @@ static bool get_phys_addr_v6(CPUARMState *env, S1Translate *ptw, * regime, because the attribute will already be non-secure. */ result->f.attrs.secure = false; + result->f.attrs.space = ARMSS_NonSecure; } result->f.phys_addr = phys_addr; return false; @@ -1616,6 +1634,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw, * regime, because the attribute will already be non-secure. */ result->f.attrs.secure = false; + result->f.attrs.space = ARMSS_NonSecure; } if (regime_is_stage2(mmu_idx)) { @@ -2400,6 +2419,7 @@ static bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address, */ if (sattrs.ns) { result->f.attrs.secure = false; + result->f.attrs.space = ARMSS_NonSecure; } else if (!secure) { /* * NS access to S memory must fault. @@ -2750,6 +2770,7 @@ static bool get_phys_addr_twostage(CPUARMState *env, S1Translate *ptw, bool is_secure = ptw->in_secure; bool ret, ipa_secure; ARMCacheAttrs cacheattrs1; + ARMSecuritySpace ipa_space; bool is_el0; uint64_t hcr; @@ -2762,10 +2783,12 @@ static bool get_phys_addr_twostage(CPUARMState *env, S1Translate *ptw, ipa = result->f.phys_addr; ipa_secure = result->f.attrs.secure; + ipa_space = result->f.attrs.space; is_el0 = ptw->in_mmu_idx == ARMMMUIdx_Stage1_E0; ptw->in_mmu_idx = ipa_secure ? ARMMMUIdx_Stage2_S : ARMMMUIdx_Stage2; ptw->in_secure = ipa_secure; + ptw->in_space = ipa_space; ptw->in_ptw_idx = ptw_idx_for_stage_2(env, ptw->in_mmu_idx); /* @@ -2854,11 +2877,12 @@ static bool get_phys_addr_with_struct(CPUARMState *env, S1Translate *ptw, ARMMMUIdx s1_mmu_idx; /* - * The page table entries may downgrade secure to non-secure, but - * cannot upgrade an non-secure translation regime's attributes - * to secure. + * The page table entries may downgrade Secure to NonSecure, but + * cannot upgrade a NonSecure translation regime's attributes + * to Secure or Realm. */ result->f.attrs.secure = is_secure; + result->f.attrs.space = ptw->in_space; switch (mmu_idx) { case ARMMMUIdx_Phys_S: @@ -2910,7 +2934,7 @@ static bool get_phys_addr_with_struct(CPUARMState *env, S1Translate *ptw, default: /* Single stage uses physical for ptw. */ - ptw->in_ptw_idx = is_secure ? ARMMMUIdx_Phys_S : ARMMMUIdx_Phys_NS; + ptw->in_ptw_idx = arm_space_to_phys(ptw->in_space); break; } @@ -2985,6 +3009,7 @@ bool get_phys_addr_with_secure(CPUARMState *env, target_ulong address, S1Translate ptw = { .in_mmu_idx = mmu_idx, .in_secure = is_secure, + .in_space = arm_secure_to_space(is_secure), }; return get_phys_addr_with_struct(env, &ptw, address, access_type, result, fi); @@ -2994,7 +3019,10 @@ bool get_phys_addr(CPUARMState *env, target_ulong address, MMUAccessType access_type, ARMMMUIdx mmu_idx, GetPhysAddrResult *result, ARMMMUFaultInfo *fi) { - bool is_secure; + S1Translate ptw = { + .in_mmu_idx = mmu_idx, + }; + ARMSecuritySpace ss; switch (mmu_idx) { case ARMMMUIdx_E10_0: @@ -3007,30 +3035,55 @@ bool get_phys_addr(CPUARMState *env, target_ulong address, case ARMMMUIdx_Stage1_E1: case ARMMMUIdx_Stage1_E1_PAN: case ARMMMUIdx_E2: - is_secure = arm_is_secure_below_el3(env); + ss = arm_security_space_below_el3(env); break; case ARMMMUIdx_Stage2: + /* + * For Secure EL2, we need this index to be NonSecure; + * otherwise this will already be NonSecure or Realm. + */ + ss = arm_security_space_below_el3(env); + if (ss == ARMSS_Secure) { + ss = ARMSS_NonSecure; + } + break; case ARMMMUIdx_Phys_NS: case ARMMMUIdx_MPrivNegPri: case ARMMMUIdx_MUserNegPri: case ARMMMUIdx_MPriv: case ARMMMUIdx_MUser: - is_secure = false; + ss = ARMSS_NonSecure; break; - case ARMMMUIdx_E3: case ARMMMUIdx_Stage2_S: case ARMMMUIdx_Phys_S: case ARMMMUIdx_MSPrivNegPri: case ARMMMUIdx_MSUserNegPri: case ARMMMUIdx_MSPriv: case ARMMMUIdx_MSUser: - is_secure = true; + ss = ARMSS_Secure; + break; + case ARMMMUIdx_E3: + if (arm_feature(env, ARM_FEATURE_AARCH64) && + cpu_isar_feature(aa64_rme, env_archcpu(env))) { + ss = ARMSS_Root; + } else { + ss = ARMSS_Secure; + } + break; + case ARMMMUIdx_Phys_Root: + ss = ARMSS_Root; + break; + case ARMMMUIdx_Phys_Realm: + ss = ARMSS_Realm; break; default: g_assert_not_reached(); } - return get_phys_addr_with_secure(env, address, access_type, mmu_idx, - is_secure, result, fi); + + ptw.in_space = ss; + ptw.in_secure = arm_space_is_secure(ss); + return get_phys_addr_with_struct(env, &ptw, address, access_type, + result, fi); } hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr, @@ -3038,9 +3091,12 @@ hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr, { ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; + ARMMMUIdx mmu_idx = arm_mmu_idx(env); + ARMSecuritySpace ss = arm_security_space(env); S1Translate ptw = { - .in_mmu_idx = arm_mmu_idx(env), - .in_secure = arm_is_secure(env), + .in_mmu_idx = mmu_idx, + .in_space = ss, + .in_secure = arm_space_is_secure(ss), .in_debug = true, }; GetPhysAddrResult res = {}; From 26d19945944b4878fa84667487a5c4fe38df960a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Jun 2023 11:15:46 +0100 Subject: [PATCH 0084/1353] target/arm: NSTable is RES0 for the RME EL3 regime Test in_space instead of in_secure so that we don't switch out of Root space. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20230620124418.805717-12-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/ptw.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/target/arm/ptw.c b/target/arm/ptw.c index e1e7c9a3d2..ea0ad56f13 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -1275,7 +1275,6 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw, { ARMCPU *cpu = env_archcpu(env); ARMMMUIdx mmu_idx = ptw->in_mmu_idx; - bool is_secure = ptw->in_secure; int32_t level; ARMVAParameters param; uint64_t ttbr; @@ -1291,7 +1290,6 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw, uint64_t descaddrmask; bool aarch64 = arm_el_is_aa64(env, el); uint64_t descriptor, new_descriptor; - bool nstable; /* TODO: This code does not support shareability levels. */ if (aarch64) { @@ -1453,21 +1451,21 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw, descaddrmask = MAKE_64BIT_MASK(0, 40); } descaddrmask &= ~indexmask_grainsize; - - /* - * Secure stage 1 accesses start with the page table in secure memory and - * can be downgraded to non-secure at any step. Non-secure accesses - * remain non-secure. We implement this by just ORing in the NSTable/NS - * bits at each step. - * Stage 2 never gets this kind of downgrade. - */ - tableattrs = is_secure ? 0 : (1 << 4); + tableattrs = 0; next_level: descaddr |= (address >> (stride * (4 - level))) & indexmask; descaddr &= ~7ULL; - nstable = !regime_is_stage2(mmu_idx) && extract32(tableattrs, 4, 1); - if (nstable && ptw->in_secure) { + + /* + * Process the NSTable bit from the previous level. This changes + * the table address space and the output space from Secure to + * NonSecure. With RME, the EL3 translation regime does not change + * from Root to NonSecure. + */ + if (ptw->in_space == ARMSS_Secure + && !regime_is_stage2(mmu_idx) + && extract32(tableattrs, 4, 1)) { /* * Stage2_S -> Stage2 or Phys_S -> Phys_NS * Assert the relative order of the secure/non-secure indexes. @@ -1476,7 +1474,9 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw, QEMU_BUILD_BUG_ON(ARMMMUIdx_Stage2_S + 1 != ARMMMUIdx_Stage2); ptw->in_ptw_idx += 1; ptw->in_secure = false; + ptw->in_space = ARMSS_NonSecure; } + if (!S1_ptw_translate(env, ptw, descaddr, fi)) { goto do_fault; } @@ -1579,7 +1579,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw, */ attrs = new_descriptor & (MAKE_64BIT_MASK(2, 10) | MAKE_64BIT_MASK(50, 14)); if (!regime_is_stage2(mmu_idx)) { - attrs |= nstable << 5; /* NS */ + attrs |= !ptw->in_secure << 5; /* NS */ if (!param.hpd) { attrs |= extract64(tableattrs, 0, 2) << 53; /* XN, PXN */ /* From 2f1ff4e7b9f30cc73e32bcb8e85fbe80a8925db1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Jun 2023 11:15:46 +0100 Subject: [PATCH 0085/1353] target/arm: Handle Block and Page bits for security space With Realm security state, bit 55 of a block or page descriptor during the stage2 walk becomes the NS bit; during the stage1 walk the bit 5 NS bit is RES0. With Root security state, bit 11 of the block or page descriptor during the stage1 walk becomes the NSE bit. Rather than collecting an NS bit and applying it later, compute the output pa space from the input pa space and unconditionally assign. This means that we no longer need to adjust the output space earlier for the NSTable bit. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20230620124418.805717-13-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/ptw.c | 89 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 73 insertions(+), 16 deletions(-) diff --git a/target/arm/ptw.c b/target/arm/ptw.c index ea0ad56f13..bbae432861 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -990,12 +990,14 @@ static int get_S2prot(CPUARMState *env, int s2ap, int xn, bool s1_is_el0) * @mmu_idx: MMU index indicating required translation regime * @is_aa64: TRUE if AArch64 * @ap: The 2-bit simple AP (AP[2:1]) - * @ns: NS (non-secure) bit * @xn: XN (execute-never) bit * @pxn: PXN (privileged execute-never) bit + * @in_pa: The original input pa space + * @out_pa: The output pa space, modified by NSTable, NS, and NSE */ static int get_S1prot(CPUARMState *env, ARMMMUIdx mmu_idx, bool is_aa64, - int ap, int ns, int xn, int pxn) + int ap, int xn, int pxn, + ARMSecuritySpace in_pa, ARMSecuritySpace out_pa) { ARMCPU *cpu = env_archcpu(env); bool is_user = regime_is_user(env, mmu_idx); @@ -1028,7 +1030,8 @@ static int get_S1prot(CPUARMState *env, ARMMMUIdx mmu_idx, bool is_aa64, } } - if (ns && arm_is_secure(env) && (env->cp15.scr_el3 & SCR_SIF)) { + if (out_pa == ARMSS_NonSecure && in_pa == ARMSS_Secure && + (env->cp15.scr_el3 & SCR_SIF)) { return prot_rw; } @@ -1285,11 +1288,12 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw, int32_t stride; int addrsize, inputsize, outputsize; uint64_t tcr = regime_tcr(env, mmu_idx); - int ap, ns, xn, pxn; + int ap, xn, pxn; uint32_t el = regime_el(env, mmu_idx); uint64_t descaddrmask; bool aarch64 = arm_el_is_aa64(env, el); uint64_t descriptor, new_descriptor; + ARMSecuritySpace out_space; /* TODO: This code does not support shareability levels. */ if (aarch64) { @@ -1592,15 +1596,75 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw, } ap = extract32(attrs, 6, 2); + out_space = ptw->in_space; if (regime_is_stage2(mmu_idx)) { - ns = mmu_idx == ARMMMUIdx_Stage2; + /* + * R_GYNXY: For stage2 in Realm security state, bit 55 is NS. + * The bit remains ignored for other security states. + */ + if (out_space == ARMSS_Realm && extract64(attrs, 55, 1)) { + out_space = ARMSS_NonSecure; + } xn = extract64(attrs, 53, 2); result->f.prot = get_S2prot(env, ap, xn, s1_is_el0); } else { - ns = extract32(attrs, 5, 1); + int nse, ns = extract32(attrs, 5, 1); + switch (out_space) { + case ARMSS_Root: + /* + * R_GVZML: Bit 11 becomes the NSE field in the EL3 regime. + * R_XTYPW: NSE and NS together select the output pa space. + */ + nse = extract32(attrs, 11, 1); + out_space = (nse << 1) | ns; + if (out_space == ARMSS_Secure && + !cpu_isar_feature(aa64_sel2, cpu)) { + out_space = ARMSS_NonSecure; + } + break; + case ARMSS_Secure: + if (ns) { + out_space = ARMSS_NonSecure; + } + break; + case ARMSS_Realm: + switch (mmu_idx) { + case ARMMMUIdx_Stage1_E0: + case ARMMMUIdx_Stage1_E1: + case ARMMMUIdx_Stage1_E1_PAN: + /* I_CZPRF: For Realm EL1&0 stage1, NS bit is RES0. */ + break; + case ARMMMUIdx_E2: + case ARMMMUIdx_E20_0: + case ARMMMUIdx_E20_2: + case ARMMMUIdx_E20_2_PAN: + /* + * R_LYKFZ, R_WGRZN: For Realm EL2 and EL2&1, + * NS changes the output to non-secure space. + */ + if (ns) { + out_space = ARMSS_NonSecure; + } + break; + default: + g_assert_not_reached(); + } + break; + case ARMSS_NonSecure: + /* R_QRMFF: For NonSecure state, the NS bit is RES0. */ + break; + default: + g_assert_not_reached(); + } xn = extract64(attrs, 54, 1); pxn = extract64(attrs, 53, 1); - result->f.prot = get_S1prot(env, mmu_idx, aarch64, ap, ns, xn, pxn); + + /* + * Note that we modified ptw->in_space earlier for NSTable, but + * result->f.attrs retains a copy of the original security space. + */ + result->f.prot = get_S1prot(env, mmu_idx, aarch64, ap, xn, pxn, + result->f.attrs.space, out_space); } if (!(result->f.prot & (1 << access_type))) { @@ -1627,15 +1691,8 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw, } } - if (ns) { - /* - * The NS bit will (as required by the architecture) have no effect if - * the CPU doesn't support TZ or this is a non-secure translation - * regime, because the attribute will already be non-secure. - */ - result->f.attrs.secure = false; - result->f.attrs.space = ARMSS_NonSecure; - } + result->f.attrs.space = out_space; + result->f.attrs.secure = arm_space_is_secure(out_space); if (regime_is_stage2(mmu_idx)) { result->cacheattrs.is_s2_format = true; From 4a7d7702cdfa776567535e55bdfb0a25f9c73d6f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Jun 2023 11:15:46 +0100 Subject: [PATCH 0086/1353] target/arm: Handle no-execute for Realm and Root regimes While Root and Realm may read and write data from other spaces, neither may execute from other pa spaces. This happens for Stage1 EL3, EL2, EL2&0, and Stage2 EL1&0. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20230620124418.805717-14-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/ptw.c | 52 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/target/arm/ptw.c b/target/arm/ptw.c index bbae432861..45271d666b 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -943,7 +943,7 @@ do_fault: * @xn: XN (execute-never) bits * @s1_is_el0: true if this is S2 of an S1+2 walk for EL0 */ -static int get_S2prot(CPUARMState *env, int s2ap, int xn, bool s1_is_el0) +static int get_S2prot_noexecute(int s2ap) { int prot = 0; @@ -953,6 +953,12 @@ static int get_S2prot(CPUARMState *env, int s2ap, int xn, bool s1_is_el0) if (s2ap & 2) { prot |= PAGE_WRITE; } + return prot; +} + +static int get_S2prot(CPUARMState *env, int s2ap, int xn, bool s1_is_el0) +{ + int prot = get_S2prot_noexecute(s2ap); if (cpu_isar_feature(any_tts2uxn, env_archcpu(env))) { switch (xn) { @@ -1030,9 +1036,39 @@ static int get_S1prot(CPUARMState *env, ARMMMUIdx mmu_idx, bool is_aa64, } } - if (out_pa == ARMSS_NonSecure && in_pa == ARMSS_Secure && - (env->cp15.scr_el3 & SCR_SIF)) { - return prot_rw; + if (in_pa != out_pa) { + switch (in_pa) { + case ARMSS_Root: + /* + * R_ZWRVD: permission fault for insn fetched from non-Root, + * I_WWBFB: SIF has no effect in EL3. + */ + return prot_rw; + case ARMSS_Realm: + /* + * R_PKTDS: permission fault for insn fetched from non-Realm, + * for Realm EL2 or EL2&0. The corresponding fault for EL1&0 + * happens during any stage2 translation. + */ + switch (mmu_idx) { + case ARMMMUIdx_E2: + case ARMMMUIdx_E20_0: + case ARMMMUIdx_E20_2: + case ARMMMUIdx_E20_2_PAN: + return prot_rw; + default: + break; + } + break; + case ARMSS_Secure: + if (env->cp15.scr_el3 & SCR_SIF) { + return prot_rw; + } + break; + default: + /* Input NonSecure must have output NonSecure. */ + g_assert_not_reached(); + } } /* TODO have_wxn should be replaced with @@ -1601,12 +1637,16 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw, /* * R_GYNXY: For stage2 in Realm security state, bit 55 is NS. * The bit remains ignored for other security states. + * R_YMCSL: Executing an insn fetched from non-Realm causes + * a stage2 permission fault. */ if (out_space == ARMSS_Realm && extract64(attrs, 55, 1)) { out_space = ARMSS_NonSecure; + result->f.prot = get_S2prot_noexecute(ap); + } else { + xn = extract64(attrs, 53, 2); + result->f.prot = get_S2prot(env, ap, xn, s1_is_el0); } - xn = extract64(attrs, 53, 2); - result->f.prot = get_S2prot(env, ap, xn, s1_is_el0); } else { int nse, ns = extract32(attrs, 5, 1); switch (out_space) { From fe4a5472ccd62a6d10fa4b4f518a5dc707e62efd Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Jun 2023 11:15:47 +0100 Subject: [PATCH 0087/1353] target/arm: Use get_phys_addr_with_struct in S1_ptw_translate Do not provide a fast-path for physical addresses, as those will need to be validated for GPC. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20230620124418.805717-15-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/ptw.c | 44 +++++++++++++++++--------------------------- 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 45271d666b..6d5e4855a3 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -264,37 +264,27 @@ static bool S1_ptw_translate(CPUARMState *env, S1Translate *ptw, * From gdbstub, do not use softmmu so that we don't modify the * state of the cpu at all, including softmmu tlb contents. */ - if (regime_is_stage2(s2_mmu_idx)) { - S1Translate s2ptw = { - .in_mmu_idx = s2_mmu_idx, - .in_ptw_idx = ptw_idx_for_stage_2(env, s2_mmu_idx), - .in_secure = s2_mmu_idx == ARMMMUIdx_Stage2_S, - .in_space = (s2_mmu_idx == ARMMMUIdx_Stage2_S ? ARMSS_Secure - : space == ARMSS_Realm ? ARMSS_Realm - : ARMSS_NonSecure), - .in_debug = true, - }; - GetPhysAddrResult s2 = { }; + S1Translate s2ptw = { + .in_mmu_idx = s2_mmu_idx, + .in_ptw_idx = ptw_idx_for_stage_2(env, s2_mmu_idx), + .in_secure = s2_mmu_idx == ARMMMUIdx_Stage2_S, + .in_space = (s2_mmu_idx == ARMMMUIdx_Stage2_S ? ARMSS_Secure + : space == ARMSS_Realm ? ARMSS_Realm + : ARMSS_NonSecure), + .in_debug = true, + }; + GetPhysAddrResult s2 = { }; - if (get_phys_addr_lpae(env, &s2ptw, addr, MMU_DATA_LOAD, - false, &s2, fi)) { - goto fail; - } - ptw->out_phys = s2.f.phys_addr; - pte_attrs = s2.cacheattrs.attrs; - ptw->out_secure = s2.f.attrs.secure; - ptw->out_space = s2.f.attrs.space; - } else { - /* Regime is physical. */ - ptw->out_phys = addr; - pte_attrs = 0; - ptw->out_secure = s2_mmu_idx == ARMMMUIdx_Phys_S; - ptw->out_space = (s2_mmu_idx == ARMMMUIdx_Phys_S ? ARMSS_Secure - : space == ARMSS_Realm ? ARMSS_Realm - : ARMSS_NonSecure); + if (get_phys_addr_with_struct(env, &s2ptw, addr, + MMU_DATA_LOAD, &s2, fi)) { + goto fail; } + ptw->out_phys = s2.f.phys_addr; + pte_attrs = s2.cacheattrs.attrs; ptw->out_host = NULL; ptw->out_rw = false; + ptw->out_secure = s2.f.attrs.secure; + ptw->out_space = s2.f.attrs.space; } else { #ifdef CONFIG_TCG CPUTLBEntryFull *full; From 7c19b2d6d9c67910812da976c968500a1d6eb170 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Jun 2023 11:15:47 +0100 Subject: [PATCH 0088/1353] target/arm: Move s1_is_el0 into S1Translate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of passing this to get_phys_addr_lpae, stash it in the S1Translate structure. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20230620124418.805717-16-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/ptw.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 6d5e4855a3..558b4b731b 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -24,6 +24,12 @@ typedef struct S1Translate { ARMSecuritySpace in_space; bool in_secure; bool in_debug; + /* + * If this is stage 2 of a stage 1+2 page table walk, then this must + * be true if stage 1 is an EL0 access; otherwise this is ignored. + * Stage 2 is indicated by in_mmu_idx set to ARMMMUIdx_Stage2{,_S}. + */ + bool in_s1_is_el0; bool out_secure; bool out_rw; bool out_be; @@ -34,8 +40,7 @@ typedef struct S1Translate { } S1Translate; static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw, - uint64_t address, - MMUAccessType access_type, bool s1_is_el0, + uint64_t address, MMUAccessType access_type, GetPhysAddrResult *result, ARMMMUFaultInfo *fi); static bool get_phys_addr_with_struct(CPUARMState *env, S1Translate *ptw, @@ -1289,17 +1294,12 @@ static int check_s2_mmu_setup(ARMCPU *cpu, bool is_aa64, uint64_t tcr, * @ptw: Current and next stage parameters for the walk. * @address: virtual address to get physical address for * @access_type: MMU_DATA_LOAD, MMU_DATA_STORE or MMU_INST_FETCH - * @s1_is_el0: if @ptw->in_mmu_idx is ARMMMUIdx_Stage2 - * (so this is a stage 2 page table walk), - * must be true if this is stage 2 of a stage 1+2 - * walk for an EL0 access. If @mmu_idx is anything else, - * @s1_is_el0 is ignored. * @result: set on translation success, * @fi: set to fault info if the translation fails */ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw, uint64_t address, - MMUAccessType access_type, bool s1_is_el0, + MMUAccessType access_type, GetPhysAddrResult *result, ARMMMUFaultInfo *fi) { ARMCPU *cpu = env_archcpu(env); @@ -1635,7 +1635,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw, result->f.prot = get_S2prot_noexecute(ap); } else { xn = extract64(attrs, 53, 2); - result->f.prot = get_S2prot(env, ap, xn, s1_is_el0); + result->f.prot = get_S2prot(env, ap, xn, ptw->in_s1_is_el0); } } else { int nse, ns = extract32(attrs, 5, 1); @@ -2858,7 +2858,6 @@ static bool get_phys_addr_twostage(CPUARMState *env, S1Translate *ptw, bool ret, ipa_secure; ARMCacheAttrs cacheattrs1; ARMSecuritySpace ipa_space; - bool is_el0; uint64_t hcr; ret = get_phys_addr_with_struct(env, ptw, address, access_type, result, fi); @@ -2872,7 +2871,7 @@ static bool get_phys_addr_twostage(CPUARMState *env, S1Translate *ptw, ipa_secure = result->f.attrs.secure; ipa_space = result->f.attrs.space; - is_el0 = ptw->in_mmu_idx == ARMMMUIdx_Stage1_E0; + ptw->in_s1_is_el0 = ptw->in_mmu_idx == ARMMMUIdx_Stage1_E0; ptw->in_mmu_idx = ipa_secure ? ARMMMUIdx_Stage2_S : ARMMMUIdx_Stage2; ptw->in_secure = ipa_secure; ptw->in_space = ipa_space; @@ -2891,8 +2890,7 @@ static bool get_phys_addr_twostage(CPUARMState *env, S1Translate *ptw, ret = get_phys_addr_pmsav8(env, ipa, access_type, ptw->in_mmu_idx, is_secure, result, fi); } else { - ret = get_phys_addr_lpae(env, ptw, ipa, access_type, - is_el0, result, fi); + ret = get_phys_addr_lpae(env, ptw, ipa, access_type, result, fi); } fi->s2addr = ipa; @@ -3078,8 +3076,7 @@ static bool get_phys_addr_with_struct(CPUARMState *env, S1Translate *ptw, } if (regime_using_lpae_format(env, mmu_idx)) { - return get_phys_addr_lpae(env, ptw, address, access_type, false, - result, fi); + return get_phys_addr_lpae(env, ptw, address, access_type, result, fi); } else if (arm_feature(env, ARM_FEATURE_V7) || regime_sctlr(env, mmu_idx) & SCTLR_XP) { return get_phys_addr_v6(env, ptw, address, access_type, result, fi); From a5c7765202f3afcc1e0bf4ae87a89bffcfb50b33 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Jun 2023 11:15:47 +0100 Subject: [PATCH 0089/1353] target/arm: Use get_phys_addr_with_struct for stage2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes a bug in which we failed to initialize the result attributes properly after the memset. Reviewed-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson Message-id: 20230620124418.805717-17-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/ptw.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 558b4b731b..7c4526e2da 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -39,10 +39,6 @@ typedef struct S1Translate { void *out_host; } S1Translate; -static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw, - uint64_t address, MMUAccessType access_type, - GetPhysAddrResult *result, ARMMMUFaultInfo *fi); - static bool get_phys_addr_with_struct(CPUARMState *env, S1Translate *ptw, target_ulong address, MMUAccessType access_type, @@ -2886,12 +2882,7 @@ static bool get_phys_addr_twostage(CPUARMState *env, S1Translate *ptw, cacheattrs1 = result->cacheattrs; memset(result, 0, sizeof(*result)); - if (arm_feature(env, ARM_FEATURE_PMSA)) { - ret = get_phys_addr_pmsav8(env, ipa, access_type, - ptw->in_mmu_idx, is_secure, result, fi); - } else { - ret = get_phys_addr_lpae(env, ptw, ipa, access_type, result, fi); - } + ret = get_phys_addr_with_struct(env, ptw, ipa, access_type, result, fi); fi->s2addr = ipa; /* Combine the S1 and S2 perms. */ From f65a9bc7197a0cc7f4546631e3ad82945a36270f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Jun 2023 11:15:47 +0100 Subject: [PATCH 0090/1353] target/arm: Add GPC syndrome The function takes the fields as filled in by the Arm ARM pseudocode for TakeGPCException. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20230620124418.805717-18-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/syndrome.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h index d27d1bc31f..62254d0e51 100644 --- a/target/arm/syndrome.h +++ b/target/arm/syndrome.h @@ -50,6 +50,7 @@ enum arm_exception_class { EC_SVEACCESSTRAP = 0x19, EC_ERETTRAP = 0x1a, EC_SMETRAP = 0x1d, + EC_GPC = 0x1e, EC_INSNABORT = 0x20, EC_INSNABORT_SAME_EL = 0x21, EC_PCALIGNMENT = 0x22, @@ -247,6 +248,15 @@ static inline uint32_t syn_bxjtrap(int cv, int cond, int rm) (cv << 24) | (cond << 20) | rm; } +static inline uint32_t syn_gpc(int s2ptw, int ind, int gpcsc, + int cm, int s1ptw, int wnr, int fsc) +{ + /* TODO: FEAT_NV2 adds VNCR */ + return (EC_GPC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (s2ptw << 21) + | (ind << 20) | (gpcsc << 14) | (cm << 8) | (s1ptw << 7) + | (wnr << 6) | fsc; +} + static inline uint32_t syn_insn_abort(int same_el, int ea, int s1ptw, int fsc) { return (EC_INSNABORT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT) From 11b76fda0adcf84055863c42f8f6cebe3eef8ca0 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Jun 2023 11:15:48 +0100 Subject: [PATCH 0091/1353] target/arm: Implement GPC exceptions Handle GPC Fault types in arm_deliver_fault, reporting as either a GPC exception at EL3, or falling through to insn or data aborts at various exception levels. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20230620124418.805717-19-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.h | 1 + target/arm/helper.c | 5 ++ target/arm/internals.h | 27 +++++++++++ target/arm/tcg/tlb_helper.c | 96 +++++++++++++++++++++++++++++++++++-- 4 files changed, 126 insertions(+), 3 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 590216b855..11c3850ad9 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -57,6 +57,7 @@ #define EXCP_UNALIGNED 22 /* v7M UNALIGNED UsageFault */ #define EXCP_DIVBYZERO 23 /* v7M DIVBYZERO UsageFault */ #define EXCP_VSERR 24 +#define EXCP_GPC 25 /* v9 Granule Protection Check Fault */ /* NB: add new EXCP_ defines to the array in arm_log_exception() too */ #define ARMV7M_EXCP_RESET 1 diff --git a/target/arm/helper.c b/target/arm/helper.c index f68923d73b..323cadd3c8 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -10184,6 +10184,7 @@ void arm_log_exception(CPUState *cs) [EXCP_UNALIGNED] = "v7M UNALIGNED UsageFault", [EXCP_DIVBYZERO] = "v7M DIVBYZERO UsageFault", [EXCP_VSERR] = "Virtual SERR", + [EXCP_GPC] = "Granule Protection Check", }; if (idx >= 0 && idx < ARRAY_SIZE(excnames)) { @@ -10915,6 +10916,10 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs) } switch (cs->exception_index) { + case EXCP_GPC: + qemu_log_mask(CPU_LOG_INT, "...with MFAR 0x%" PRIx64 "\n", + env->cp15.mfar_el3); + /* fall through */ case EXCP_PREFETCH_ABORT: case EXCP_DATA_ABORT: /* diff --git a/target/arm/internals.h b/target/arm/internals.h index e3029bdc37..0f01bc32a8 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -358,14 +358,27 @@ typedef enum ARMFaultType { ARMFault_ICacheMaint, ARMFault_QEMU_NSCExec, /* v8M: NS executing in S&NSC memory */ ARMFault_QEMU_SFault, /* v8M: SecureFault INVTRAN, INVEP or AUVIOL */ + ARMFault_GPCFOnWalk, + ARMFault_GPCFOnOutput, } ARMFaultType; +typedef enum ARMGPCF { + GPCF_None, + GPCF_AddressSize, + GPCF_Walk, + GPCF_EABT, + GPCF_Fail, +} ARMGPCF; + /** * ARMMMUFaultInfo: Information describing an ARM MMU Fault * @type: Type of fault + * @gpcf: Subtype of ARMFault_GPCFOn{Walk,Output}. * @level: Table walk level (for translation, access flag and permission faults) * @domain: Domain of the fault address (for non-LPAE CPUs only) * @s2addr: Address that caused a fault at stage 2 + * @paddr: physical address that caused a fault for gpc + * @paddr_space: physical address space that caused a fault for gpc * @stage2: True if we faulted at stage 2 * @s1ptw: True if we faulted at stage 2 while doing a stage 1 page-table walk * @s1ns: True if we faulted on a non-secure IPA while in secure state @@ -374,7 +387,10 @@ typedef enum ARMFaultType { typedef struct ARMMMUFaultInfo ARMMMUFaultInfo; struct ARMMMUFaultInfo { ARMFaultType type; + ARMGPCF gpcf; target_ulong s2addr; + target_ulong paddr; + ARMSecuritySpace paddr_space; int level; int domain; bool stage2; @@ -548,6 +564,17 @@ static inline uint32_t arm_fi_to_lfsc(ARMMMUFaultInfo *fi) case ARMFault_Exclusive: fsc = 0x35; break; + case ARMFault_GPCFOnWalk: + assert(fi->level >= -1 && fi->level <= 3); + if (fi->level < 0) { + fsc = 0b100011; + } else { + fsc = 0b100100 | fi->level; + } + break; + case ARMFault_GPCFOnOutput: + fsc = 0b101000; + break; default: /* Other faults can't occur in a context that requires a * long-format status code. diff --git a/target/arm/tcg/tlb_helper.c b/target/arm/tcg/tlb_helper.c index 8df36c2cbf..b22b2a4c6e 100644 --- a/target/arm/tcg/tlb_helper.c +++ b/target/arm/tcg/tlb_helper.c @@ -107,17 +107,106 @@ static uint32_t compute_fsr_fsc(CPUARMState *env, ARMMMUFaultInfo *fi, return fsr; } +static bool report_as_gpc_exception(ARMCPU *cpu, int current_el, + ARMMMUFaultInfo *fi) +{ + bool ret; + + switch (fi->gpcf) { + case GPCF_None: + return false; + case GPCF_AddressSize: + case GPCF_Walk: + case GPCF_EABT: + /* R_PYTGX: GPT faults are reported as GPC. */ + ret = true; + break; + case GPCF_Fail: + /* + * R_BLYPM: A GPF at EL3 is reported as insn or data abort. + * R_VBZMW, R_LXHQR: A GPF at EL[0-2] is reported as a GPC + * if SCR_EL3.GPF is set, otherwise an insn or data abort. + */ + ret = (cpu->env.cp15.scr_el3 & SCR_GPF) && current_el != 3; + break; + default: + g_assert_not_reached(); + } + + assert(cpu_isar_feature(aa64_rme, cpu)); + assert(fi->type == ARMFault_GPCFOnWalk || + fi->type == ARMFault_GPCFOnOutput); + if (fi->gpcf == GPCF_AddressSize) { + assert(fi->level == 0); + } else { + assert(fi->level >= 0 && fi->level <= 1); + } + + return ret; +} + +static unsigned encode_gpcsc(ARMMMUFaultInfo *fi) +{ + static uint8_t const gpcsc[] = { + [GPCF_AddressSize] = 0b000000, + [GPCF_Walk] = 0b000100, + [GPCF_Fail] = 0b001100, + [GPCF_EABT] = 0b010100, + }; + + /* Note that we've validated fi->gpcf and fi->level above. */ + return gpcsc[fi->gpcf] | fi->level; +} + static G_NORETURN void arm_deliver_fault(ARMCPU *cpu, vaddr addr, MMUAccessType access_type, int mmu_idx, ARMMMUFaultInfo *fi) { CPUARMState *env = &cpu->env; - int target_el; + int target_el = exception_target_el(env); + int current_el = arm_current_el(env); bool same_el; uint32_t syn, exc, fsr, fsc; - target_el = exception_target_el(env); + if (report_as_gpc_exception(cpu, current_el, fi)) { + target_el = 3; + + fsr = compute_fsr_fsc(env, fi, target_el, mmu_idx, &fsc); + + syn = syn_gpc(fi->stage2 && fi->type == ARMFault_GPCFOnWalk, + access_type == MMU_INST_FETCH, + encode_gpcsc(fi), 0, fi->s1ptw, + access_type == MMU_DATA_STORE, fsc); + + env->cp15.mfar_el3 = fi->paddr; + switch (fi->paddr_space) { + case ARMSS_Secure: + break; + case ARMSS_NonSecure: + env->cp15.mfar_el3 |= R_MFAR_NS_MASK; + break; + case ARMSS_Root: + env->cp15.mfar_el3 |= R_MFAR_NSE_MASK; + break; + case ARMSS_Realm: + env->cp15.mfar_el3 |= R_MFAR_NSE_MASK | R_MFAR_NS_MASK; + break; + default: + g_assert_not_reached(); + } + + exc = EXCP_GPC; + goto do_raise; + } + + /* If SCR_EL3.GPF is unset, GPF may still be routed to EL2. */ + if (fi->gpcf == GPCF_Fail && target_el < 2) { + if (arm_hcr_el2_eff(env) & HCR_GPF) { + target_el = 2; + } + } + if (fi->stage2) { target_el = 2; env->cp15.hpfar_el2 = extract64(fi->s2addr, 12, 47) << 4; @@ -125,8 +214,8 @@ void arm_deliver_fault(ARMCPU *cpu, vaddr addr, env->cp15.hpfar_el2 |= HPFAR_NS; } } - same_el = (arm_current_el(env) == target_el); + same_el = current_el == target_el; fsr = compute_fsr_fsc(env, fi, target_el, mmu_idx, &fsc); if (access_type == MMU_INST_FETCH) { @@ -143,6 +232,7 @@ void arm_deliver_fault(ARMCPU *cpu, vaddr addr, exc = EXCP_DATA_ABORT; } + do_raise: env->exception.vaddress = addr; env->exception.fsr = fsr; raise_exception(env, exc, syn, target_el); From 46f38c975f0a077a8f82081cc81a7cbd4f78f946 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Jun 2023 11:15:48 +0100 Subject: [PATCH 0092/1353] target/arm: Implement the granule protection check Place the check at the end of get_phys_addr_with_struct, so that we check all physical results. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20230620124418.805717-20-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/ptw.c | 249 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 232 insertions(+), 17 deletions(-) diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 7c4526e2da..6015121b99 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -39,11 +39,17 @@ typedef struct S1Translate { void *out_host; } S1Translate; -static bool get_phys_addr_with_struct(CPUARMState *env, S1Translate *ptw, - target_ulong address, - MMUAccessType access_type, - GetPhysAddrResult *result, - ARMMMUFaultInfo *fi); +static bool get_phys_addr_nogpc(CPUARMState *env, S1Translate *ptw, + target_ulong address, + MMUAccessType access_type, + GetPhysAddrResult *result, + ARMMMUFaultInfo *fi); + +static bool get_phys_addr_gpc(CPUARMState *env, S1Translate *ptw, + target_ulong address, + MMUAccessType access_type, + GetPhysAddrResult *result, + ARMMMUFaultInfo *fi); /* This mapping is common between ID_AA64MMFR0.PARANGE and TCR_ELx.{I}PS. */ static const uint8_t pamax_map[] = { @@ -230,6 +236,197 @@ static bool regime_translation_disabled(CPUARMState *env, ARMMMUIdx mmu_idx, return (regime_sctlr(env, mmu_idx) & SCTLR_M) == 0; } +static bool granule_protection_check(CPUARMState *env, uint64_t paddress, + ARMSecuritySpace pspace, + ARMMMUFaultInfo *fi) +{ + MemTxAttrs attrs = { + .secure = true, + .space = ARMSS_Root, + }; + ARMCPU *cpu = env_archcpu(env); + uint64_t gpccr = env->cp15.gpccr_el3; + unsigned pps, pgs, l0gptsz, level = 0; + uint64_t tableaddr, pps_mask, align, entry, index; + AddressSpace *as; + MemTxResult result; + int gpi; + + if (!FIELD_EX64(gpccr, GPCCR, GPC)) { + return true; + } + + /* + * GPC Priority 1 (R_GMGRR): + * R_JWCSM: If the configuration of GPCCR_EL3 is invalid, + * the access fails as GPT walk fault at level 0. + */ + + /* + * Configuration of PPS to a value exceeding the implemented + * physical address size is invalid. + */ + pps = FIELD_EX64(gpccr, GPCCR, PPS); + if (pps > FIELD_EX64(cpu->isar.id_aa64mmfr0, ID_AA64MMFR0, PARANGE)) { + goto fault_walk; + } + pps = pamax_map[pps]; + pps_mask = MAKE_64BIT_MASK(0, pps); + + switch (FIELD_EX64(gpccr, GPCCR, SH)) { + case 0b10: /* outer shareable */ + break; + case 0b00: /* non-shareable */ + case 0b11: /* inner shareable */ + /* Inner and Outer non-cacheable requires Outer shareable. */ + if (FIELD_EX64(gpccr, GPCCR, ORGN) == 0 && + FIELD_EX64(gpccr, GPCCR, IRGN) == 0) { + goto fault_walk; + } + break; + default: /* reserved */ + goto fault_walk; + } + + switch (FIELD_EX64(gpccr, GPCCR, PGS)) { + case 0b00: /* 4KB */ + pgs = 12; + break; + case 0b01: /* 64KB */ + pgs = 16; + break; + case 0b10: /* 16KB */ + pgs = 14; + break; + default: /* reserved */ + goto fault_walk; + } + + /* Note this field is read-only and fixed at reset. */ + l0gptsz = 30 + FIELD_EX64(gpccr, GPCCR, L0GPTSZ); + + /* + * GPC Priority 2: Secure, Realm or Root address exceeds PPS. + * R_CPDSB: A NonSecure physical address input exceeding PPS + * does not experience any fault. + */ + if (paddress & ~pps_mask) { + if (pspace == ARMSS_NonSecure) { + return true; + } + goto fault_size; + } + + /* GPC Priority 3: the base address of GPTBR_EL3 exceeds PPS. */ + tableaddr = env->cp15.gptbr_el3 << 12; + if (tableaddr & ~pps_mask) { + goto fault_size; + } + + /* + * BADDR is aligned per a function of PPS and L0GPTSZ. + * These bits of GPTBR_EL3 are RES0, but are not a configuration error, + * unlike the RES0 bits of the GPT entries (R_XNKFZ). + */ + align = MAX(pps - l0gptsz + 3, 12); + align = MAKE_64BIT_MASK(0, align); + tableaddr &= ~align; + + as = arm_addressspace(env_cpu(env), attrs); + + /* Level 0 lookup. */ + index = extract64(paddress, l0gptsz, pps - l0gptsz); + tableaddr += index * 8; + entry = address_space_ldq_le(as, tableaddr, attrs, &result); + if (result != MEMTX_OK) { + goto fault_eabt; + } + + switch (extract32(entry, 0, 4)) { + case 1: /* block descriptor */ + if (entry >> 8) { + goto fault_walk; /* RES0 bits not 0 */ + } + gpi = extract32(entry, 4, 4); + goto found; + case 3: /* table descriptor */ + tableaddr = entry & ~0xf; + align = MAX(l0gptsz - pgs - 1, 12); + align = MAKE_64BIT_MASK(0, align); + if (tableaddr & (~pps_mask | align)) { + goto fault_walk; /* RES0 bits not 0 */ + } + break; + default: /* invalid */ + goto fault_walk; + } + + /* Level 1 lookup */ + level = 1; + index = extract64(paddress, pgs + 4, l0gptsz - pgs - 4); + tableaddr += index * 8; + entry = address_space_ldq_le(as, tableaddr, attrs, &result); + if (result != MEMTX_OK) { + goto fault_eabt; + } + + switch (extract32(entry, 0, 4)) { + case 1: /* contiguous descriptor */ + if (entry >> 10) { + goto fault_walk; /* RES0 bits not 0 */ + } + /* + * Because the softmmu tlb only works on units of TARGET_PAGE_SIZE, + * and because we cannot invalidate by pa, and thus will always + * flush entire tlbs, we don't actually care about the range here + * and can simply extract the GPI as the result. + */ + if (extract32(entry, 8, 2) == 0) { + goto fault_walk; /* reserved contig */ + } + gpi = extract32(entry, 4, 4); + break; + default: + index = extract64(paddress, pgs, 4); + gpi = extract64(entry, index * 4, 4); + break; + } + + found: + switch (gpi) { + case 0b0000: /* no access */ + break; + case 0b1111: /* all access */ + return true; + case 0b1000: + case 0b1001: + case 0b1010: + case 0b1011: + if (pspace == (gpi & 3)) { + return true; + } + break; + default: + goto fault_walk; /* reserved */ + } + + fi->gpcf = GPCF_Fail; + goto fault_common; + fault_eabt: + fi->gpcf = GPCF_EABT; + goto fault_common; + fault_size: + fi->gpcf = GPCF_AddressSize; + goto fault_common; + fault_walk: + fi->gpcf = GPCF_Walk; + fault_common: + fi->level = level; + fi->paddr = paddress; + fi->paddr_space = pspace; + return false; +} + static bool S2_attrs_are_device(uint64_t hcr, uint8_t attrs) { /* @@ -276,10 +473,10 @@ static bool S1_ptw_translate(CPUARMState *env, S1Translate *ptw, }; GetPhysAddrResult s2 = { }; - if (get_phys_addr_with_struct(env, &s2ptw, addr, - MMU_DATA_LOAD, &s2, fi)) { + if (get_phys_addr_gpc(env, &s2ptw, addr, MMU_DATA_LOAD, &s2, fi)) { goto fail; } + ptw->out_phys = s2.f.phys_addr; pte_attrs = s2.cacheattrs.attrs; ptw->out_host = NULL; @@ -332,6 +529,9 @@ static bool S1_ptw_translate(CPUARMState *env, S1Translate *ptw, fail: assert(fi->type != ARMFault_None); + if (fi->type == ARMFault_GPCFOnOutput) { + fi->type = ARMFault_GPCFOnWalk; + } fi->s2addr = addr; fi->stage2 = true; fi->s1ptw = true; @@ -2769,7 +2969,7 @@ static bool get_phys_addr_disabled(CPUARMState *env, target_ulong address, ARMMMUFaultInfo *fi) { uint8_t memattr = 0x00; /* Device nGnRnE */ - uint8_t shareability = 0; /* non-sharable */ + uint8_t shareability = 0; /* non-shareable */ int r_el; switch (mmu_idx) { @@ -2828,7 +3028,7 @@ static bool get_phys_addr_disabled(CPUARMState *env, target_ulong address, } else { memattr = 0x44; /* Normal, NC, No */ } - shareability = 2; /* outer sharable */ + shareability = 2; /* outer shareable */ } result->cacheattrs.is_s2_format = false; break; @@ -2856,7 +3056,7 @@ static bool get_phys_addr_twostage(CPUARMState *env, S1Translate *ptw, ARMSecuritySpace ipa_space; uint64_t hcr; - ret = get_phys_addr_with_struct(env, ptw, address, access_type, result, fi); + ret = get_phys_addr_nogpc(env, ptw, address, access_type, result, fi); /* If S1 fails, return early. */ if (ret) { @@ -2882,7 +3082,7 @@ static bool get_phys_addr_twostage(CPUARMState *env, S1Translate *ptw, cacheattrs1 = result->cacheattrs; memset(result, 0, sizeof(*result)); - ret = get_phys_addr_with_struct(env, ptw, ipa, access_type, result, fi); + ret = get_phys_addr_nogpc(env, ptw, ipa, access_type, result, fi); fi->s2addr = ipa; /* Combine the S1 and S2 perms. */ @@ -2942,7 +3142,7 @@ static bool get_phys_addr_twostage(CPUARMState *env, S1Translate *ptw, return false; } -static bool get_phys_addr_with_struct(CPUARMState *env, S1Translate *ptw, +static bool get_phys_addr_nogpc(CPUARMState *env, S1Translate *ptw, target_ulong address, MMUAccessType access_type, GetPhysAddrResult *result, @@ -3076,6 +3276,23 @@ static bool get_phys_addr_with_struct(CPUARMState *env, S1Translate *ptw, } } +static bool get_phys_addr_gpc(CPUARMState *env, S1Translate *ptw, + target_ulong address, + MMUAccessType access_type, + GetPhysAddrResult *result, + ARMMMUFaultInfo *fi) +{ + if (get_phys_addr_nogpc(env, ptw, address, access_type, result, fi)) { + return true; + } + if (!granule_protection_check(env, result->f.phys_addr, + result->f.attrs.space, fi)) { + fi->type = ARMFault_GPCFOnOutput; + return true; + } + return false; +} + bool get_phys_addr_with_secure(CPUARMState *env, target_ulong address, MMUAccessType access_type, ARMMMUIdx mmu_idx, bool is_secure, GetPhysAddrResult *result, @@ -3086,8 +3303,7 @@ bool get_phys_addr_with_secure(CPUARMState *env, target_ulong address, .in_secure = is_secure, .in_space = arm_secure_to_space(is_secure), }; - return get_phys_addr_with_struct(env, &ptw, address, access_type, - result, fi); + return get_phys_addr_gpc(env, &ptw, address, access_type, result, fi); } bool get_phys_addr(CPUARMState *env, target_ulong address, @@ -3157,8 +3373,7 @@ bool get_phys_addr(CPUARMState *env, target_ulong address, ptw.in_space = ss; ptw.in_secure = arm_space_is_secure(ss); - return get_phys_addr_with_struct(env, &ptw, address, access_type, - result, fi); + return get_phys_addr_gpc(env, &ptw, address, access_type, result, fi); } hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr, @@ -3178,7 +3393,7 @@ hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr, ARMMMUFaultInfo fi = {}; bool ret; - ret = get_phys_addr_with_struct(env, &ptw, addr, MMU_DATA_LOAD, &res, &fi); + ret = get_phys_addr_gpc(env, &ptw, addr, MMU_DATA_LOAD, &res, &fi); *attrs = res.f.attrs; if (ret) { From a834d5474e24a279ffc16558c34d4536e84fe09d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Jun 2023 11:15:48 +0100 Subject: [PATCH 0093/1353] target/arm: Add cpu properties for enabling FEAT_RME Add an x-rme cpu property to enable FEAT_RME. Add an x-l0gptsz property to set GPCCR_EL3.L0GPTSZ, for testing various possible configurations. We're not currently completely sure whether FEAT_RME will be OK to enable purely as a CPU-level property, or if it will need board co-operation, so we're making these experimental x- properties, so that the people developing the system level software for RME can try to start using this and let us know how it goes. The command line syntax for enabling this will change in future, without backwards-compatibility. Signed-off-by: Richard Henderson Message-id: 20230620124418.805717-21-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/tcg/cpu64.c | 53 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c index 2976f94ae4..6fec2d8a57 100644 --- a/target/arm/tcg/cpu64.c +++ b/target/arm/tcg/cpu64.c @@ -142,6 +142,56 @@ static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name, cpu->sve_max_vq = max_vq; } +static bool cpu_arm_get_rme(Object *obj, Error **errp) +{ + ARMCPU *cpu = ARM_CPU(obj); + return cpu_isar_feature(aa64_rme, cpu); +} + +static void cpu_arm_set_rme(Object *obj, bool value, Error **errp) +{ + ARMCPU *cpu = ARM_CPU(obj); + uint64_t t; + + t = cpu->isar.id_aa64pfr0; + t = FIELD_DP64(t, ID_AA64PFR0, RME, value); + cpu->isar.id_aa64pfr0 = t; +} + +static void cpu_max_set_l0gptsz(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + ARMCPU *cpu = ARM_CPU(obj); + uint32_t value; + + if (!visit_type_uint32(v, name, &value, errp)) { + return; + } + + /* Encode the value for the GPCCR_EL3 field. */ + switch (value) { + case 30: + case 34: + case 36: + case 39: + cpu->reset_l0gptsz = value - 30; + break; + default: + error_setg(errp, "invalid value for l0gptsz"); + error_append_hint(errp, "valid values are 30, 34, 36, 39\n"); + break; + } +} + +static void cpu_max_get_l0gptsz(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + ARMCPU *cpu = ARM_CPU(obj); + uint32_t value = cpu->reset_l0gptsz + 30; + + visit_type_uint32(v, name, &value, errp); +} + static Property arm_cpu_lpa2_property = DEFINE_PROP_BOOL("lpa2", ARMCPU, prop_lpa2, true); @@ -700,6 +750,9 @@ void aarch64_max_tcg_initfn(Object *obj) aarch64_add_sme_properties(obj); object_property_add(obj, "sve-max-vq", "uint32", cpu_max_get_sve_max_vq, cpu_max_set_sve_max_vq, NULL, NULL); + object_property_add_bool(obj, "x-rme", cpu_arm_get_rme, cpu_arm_set_rme); + object_property_add(obj, "x-l0gptsz", "uint32", cpu_max_get_l0gptsz, + cpu_max_set_l0gptsz, NULL, NULL); qdev_property_add_static(DEVICE(obj), &arm_cpu_lpa2_property); } From 57223a4c24d58493d1eade8c1b38fd707f845d5e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 22 Jun 2023 16:30:46 +0200 Subject: [PATCH 0094/1353] docs/system/arm: Document FEAT_RME MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Richard Henderson Reviewed-by: Alex Bennée Message-id: 20230622143046.1578160-1-richard.henderson@linaro.org [PMM: fixed typo; note experimental status in emulation.rst too] Signed-off-by: Peter Maydell --- docs/system/arm/cpu-features.rst | 23 +++++++++++++++++++++++ docs/system/arm/emulation.rst | 1 + 2 files changed, 24 insertions(+) diff --git a/docs/system/arm/cpu-features.rst b/docs/system/arm/cpu-features.rst index f4524b6d3e..6bb88a40c7 100644 --- a/docs/system/arm/cpu-features.rst +++ b/docs/system/arm/cpu-features.rst @@ -435,3 +435,26 @@ As with ``sve-default-vector-length``, if the default length is larger than the maximum vector length enabled, the actual vector length will be reduced. If this property is set to ``-1`` then the default vector length is set to the maximum possible length. + +RME CPU Properties +================== + +The status of RME support with QEMU is experimental. At this time we +only support RME within the CPU proper, not within the SMMU or GIC. +The feature is enabled by the CPU property ``x-rme``, with the ``x-`` +prefix present as a reminder of the experimental status, and defaults off. + +The method for enabling RME will change in some future QEMU release +without notice or backward compatibility. + +RME Level 0 GPT Size Property +----------------------------- + +To aid firmware developers in testing different possible CPU +configurations, ``x-l0gptsz=S`` may be used to specify the value +to encode into ``GPCCR_EL3.L0GPTSZ``, a read-only field that +specifies the size of the Level 0 Granule Protection Table. +Legal values for ``S`` are 30, 34, 36, and 39; the default is 30. + +As with ``x-rme``, the ``x-l0gptsz`` property may be renamed or +removed in some future QEMU release. diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index ecbbd63adf..bdafc68819 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -66,6 +66,7 @@ the following architecture extensions: - FEAT_RAS (Reliability, availability, and serviceability) - FEAT_RASv1p1 (RAS Extension v1.1) - FEAT_RDM (Advanced SIMD rounding double multiply accumulate instructions) +- FEAT_RME (Realm Management Extension) (NB: support status in QEMU is experimental) - FEAT_RNG (Random number generator) - FEAT_S2FWB (Stage 2 forced Write-Back) - FEAT_SB (Speculation Barrier) From b0438861efe1dfbdfdd9fa1d9aa05100d37ea8ee Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 22 Jun 2023 14:08:23 +0100 Subject: [PATCH 0095/1353] host-utils: Avoid using __builtin_subcll on buggy versions of Apple Clang MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We use __builtin_subcll() to do a 64-bit subtract with borrow-in and borrow-out when the host compiler supports it. Unfortunately some versions of Apple Clang have a bug in their implementation of this intrinsic which means it returns the wrong value. The effect is that a QEMU built with the affected compiler will hang when emulating x86 or m68k float80 division. The upstream LLVM issue is: https://github.com/llvm/llvm-project/issues/55253 The commit that introduced the bug apparently never made it into an upstream LLVM release without the subsequent fix https://github.com/llvm/llvm-project/commit/fffb6e6afdbaba563189c1f715058ed401fbc88d but unfortunately it did make it into Apple Clang 14.0, as shipped in Xcode 14.3 (14.2 is reported to be OK). The Apple bug number is FB12210478. Add ifdefs to avoid use of __builtin_subcll() on Apple Clang version 14 or greater. There is not currently a version of Apple Clang which has the bug fix -- when one appears we should be able to add an upper bound to the ifdef condition so we can start using the builtin again. We make the lower bound a conservative "any Apple clang with major version 14 or greater" because the consequences of incorrectly disabling the builtin when it would work are pretty small and the consequences of not disabling it when we should are pretty bad. Many thanks to those users who both reported this bug and also did a lot of work in identifying the root cause; in particular to Daniel Bertalan and osy. Cc: qemu-stable@nongnu.org Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1631 Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1659 Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Daniel P. Berrangé Tested-by: Daniel Bertalan Tested-by: Tested-By: Solra Bizna Message-id: 20230622130823.1631719-1-peter.maydell@linaro.org --- include/qemu/compiler.h | 13 +++++++++++++ include/qemu/host-utils.h | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/include/qemu/compiler.h b/include/qemu/compiler.h index c2f49df1f9..a309f90c76 100644 --- a/include/qemu/compiler.h +++ b/include/qemu/compiler.h @@ -184,4 +184,17 @@ #define QEMU_DISABLE_CFI #endif +/* + * Apple clang version 14 has a bug in its __builtin_subcll(); define + * BUILTIN_SUBCLL_BROKEN for the offending versions so we can avoid it. + * When a version of Apple clang which has this bug fixed is released + * we can add an upper bound to this check. + * See https://gitlab.com/qemu-project/qemu/-/issues/1631 + * and https://gitlab.com/qemu-project/qemu/-/issues/1659 for details. + * The bug never made it into any upstream LLVM releases, only Apple ones. + */ +#if defined(__apple_build_version__) && __clang_major__ >= 14 +#define BUILTIN_SUBCLL_BROKEN +#endif + #endif /* COMPILER_H */ diff --git a/include/qemu/host-utils.h b/include/qemu/host-utils.h index d3b4dce6a9..011618373e 100644 --- a/include/qemu/host-utils.h +++ b/include/qemu/host-utils.h @@ -649,7 +649,7 @@ static inline uint64_t uadd64_carry(uint64_t x, uint64_t y, bool *pcarry) */ static inline uint64_t usub64_borrow(uint64_t x, uint64_t y, bool *pborrow) { -#if __has_builtin(__builtin_subcll) +#if __has_builtin(__builtin_subcll) && !defined(BUILTIN_SUBCLL_BROKEN) unsigned long long b = *pborrow; x = __builtin_subcll(x, y, b, &b); *pborrow = b & 1; From 4315f7c6147431a69a02613fbdf9964d68f87a27 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Jun 2023 16:02:16 +0200 Subject: [PATCH 0096/1353] target/arm: Restructure has_vfp_d32 test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One cannot test for feature aa32_simd_r32 without first testing if AArch32 mode is supported at all. This leads to qemu-system-aarch64: ARM CPUs must have both VFP-D32 and Neon or neither for Apple M1 cpus. We already have a check for ARMv8-A never setting vfp-d32 true, so restructure the code so that AArch64 avoids the test entirely. Reported-by: Mads Ynddal Signed-off-by: Richard Henderson Tested-by: Philippe Mathieu-Daudé Tested-by: Mads Ynddal Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Reviewed-by: Mads Ynddal Message-id: 20230619140216.402530-1-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 842e1b53ee..a1e77698ba 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1402,25 +1402,27 @@ void arm_cpu_post_init(Object *obj) * KVM does not currently allow us to lie to the guest about its * ID/feature registers, so the guest always sees what the host has. */ - if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64) - ? cpu_isar_feature(aa64_fp_simd, cpu) - : cpu_isar_feature(aa32_vfp, cpu)) { - cpu->has_vfp = true; - if (!kvm_enabled()) { - qdev_property_add_static(DEVICE(obj), &arm_cpu_has_vfp_property); + if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { + if (cpu_isar_feature(aa64_fp_simd, cpu)) { + cpu->has_vfp = true; + cpu->has_vfp_d32 = true; + if (tcg_enabled() || qtest_enabled()) { + qdev_property_add_static(DEVICE(obj), + &arm_cpu_has_vfp_property); + } } - } - - if (cpu->has_vfp && cpu_isar_feature(aa32_simd_r32, cpu)) { - cpu->has_vfp_d32 = true; - if (!kvm_enabled()) { + } else if (cpu_isar_feature(aa32_vfp, cpu)) { + cpu->has_vfp = true; + if (cpu_isar_feature(aa32_simd_r32, cpu)) { + cpu->has_vfp_d32 = true; /* * The permitted values of the SIMDReg bits [3:0] on * Armv8-A are either 0b0000 and 0b0010. On such CPUs, * make sure that has_vfp_d32 can not be set to false. */ - if (!(arm_feature(&cpu->env, ARM_FEATURE_V8) && - !arm_feature(&cpu->env, ARM_FEATURE_M))) { + if ((tcg_enabled() || qtest_enabled()) + && !(arm_feature(&cpu->env, ARM_FEATURE_V8) + && !arm_feature(&cpu->env, ARM_FEATURE_M))) { qdev_property_add_static(DEVICE(obj), &arm_cpu_has_vfp_d32_property); } From 9fe2b4a2899507bc66122840f060fab74b5dd161 Mon Sep 17 00:00:00 2001 From: Shashi Mallela Date: Mon, 19 Jun 2023 19:09:13 +0200 Subject: [PATCH 0097/1353] hw/arm/sbsa-ref: add ITS support in SBSA GIC Create ITS as part of SBSA platform GIC initialization. GIC ITS information is in DeviceTree so TF-A can pass it to EDK2. Bumping platform version to 0.2 as this is important hardware change. Signed-off-by: Shashi Mallela Signed-off-by: Marcin Juszkiewicz Message-id: 20230619170913.517373-2-marcin.juszkiewicz@linaro.org Co-authored-by: Marcin Juszkiewicz Signed-off-by: Marcin Juszkiewicz Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- docs/system/arm/sbsa.rst | 14 ++++++++++++++ hw/arm/sbsa-ref.c | 33 ++++++++++++++++++++++++++++++--- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/docs/system/arm/sbsa.rst b/docs/system/arm/sbsa.rst index f571fe645e..a8e0b530a2 100644 --- a/docs/system/arm/sbsa.rst +++ b/docs/system/arm/sbsa.rst @@ -46,6 +46,9 @@ to be a complete compliant DT. It currently reports: - platform version - GIC addresses +Platform version +'''''''''''''''' + The platform version is only for informing platform firmware about what kind of ``sbsa-ref`` board it is running on. It is neither a QEMU versioned machine type nor a reflection of the level of the @@ -54,3 +57,14 @@ SBSA/SystemReady SR support provided. The ``machine-version-major`` value is updated when changes breaking fw compatibility are introduced. The ``machine-version-minor`` value is updated when features are added that don't break fw compatibility. + +Platform version changes: + +0.0 + Devicetree holds information about CPUs, memory and platform version. + +0.1 + GIC information is present in devicetree. + +0.2 + GIC ITS information is present in devicetree. diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c index de21200ff9..0639f97dd5 100644 --- a/hw/arm/sbsa-ref.c +++ b/hw/arm/sbsa-ref.c @@ -65,6 +65,7 @@ enum { SBSA_CPUPERIPHS, SBSA_GIC_DIST, SBSA_GIC_REDIST, + SBSA_GIC_ITS, SBSA_SECURE_EC, SBSA_GWDT_WS0, SBSA_GWDT_REFRESH, @@ -108,6 +109,7 @@ static const MemMapEntry sbsa_ref_memmap[] = { [SBSA_CPUPERIPHS] = { 0x40000000, 0x00040000 }, [SBSA_GIC_DIST] = { 0x40060000, 0x00010000 }, [SBSA_GIC_REDIST] = { 0x40080000, 0x04000000 }, + [SBSA_GIC_ITS] = { 0x44081000, 0x00020000 }, [SBSA_SECURE_EC] = { 0x50000000, 0x00001000 }, [SBSA_GWDT_REFRESH] = { 0x50010000, 0x00001000 }, [SBSA_GWDT_CONTROL] = { 0x50011000, 0x00001000 }, @@ -181,8 +183,15 @@ static void sbsa_fdt_add_gic_node(SBSAMachineState *sms) 2, sbsa_ref_memmap[SBSA_GIC_REDIST].base, 2, sbsa_ref_memmap[SBSA_GIC_REDIST].size); + nodename = g_strdup_printf("/intc/its"); + qemu_fdt_add_subnode(sms->fdt, nodename); + qemu_fdt_setprop_sized_cells(sms->fdt, nodename, "reg", + 2, sbsa_ref_memmap[SBSA_GIC_ITS].base, + 2, sbsa_ref_memmap[SBSA_GIC_ITS].size); + g_free(nodename); } + /* * Firmware on this machine only uses ACPI table to load OS, these limited * device tree nodes are just to let firmware know the info which varies from @@ -219,7 +228,7 @@ static void create_fdt(SBSAMachineState *sms) * fw compatibility. */ qemu_fdt_setprop_cell(fdt, "/", "machine-version-major", 0); - qemu_fdt_setprop_cell(fdt, "/", "machine-version-minor", 1); + qemu_fdt_setprop_cell(fdt, "/", "machine-version-minor", 2); if (ms->numa_state->have_numa_distance) { int size = nb_numa_nodes * nb_numa_nodes * 3 * sizeof(uint32_t); @@ -409,7 +418,20 @@ static void create_secure_ram(SBSAMachineState *sms, memory_region_add_subregion(secure_sysmem, base, secram); } -static void create_gic(SBSAMachineState *sms) +static void create_its(SBSAMachineState *sms) +{ + const char *itsclass = its_class_name(); + DeviceState *dev; + + dev = qdev_new(itsclass); + + object_property_set_link(OBJECT(dev), "parent-gicv3", OBJECT(sms->gic), + &error_abort); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, sbsa_ref_memmap[SBSA_GIC_ITS].base); +} + +static void create_gic(SBSAMachineState *sms, MemoryRegion *mem) { unsigned int smp_cpus = MACHINE(sms)->smp.cpus; SysBusDevice *gicbusdev; @@ -436,6 +458,10 @@ static void create_gic(SBSAMachineState *sms) qdev_prop_set_uint32(sms->gic, "len-redist-region-count", 1); qdev_prop_set_uint32(sms->gic, "redist-region-count[0]", redist0_count); + object_property_set_link(OBJECT(sms->gic), "sysmem", + OBJECT(mem), &error_fatal); + qdev_prop_set_bit(sms->gic, "has-lpi", true); + gicbusdev = SYS_BUS_DEVICE(sms->gic); sysbus_realize_and_unref(gicbusdev, &error_fatal); sysbus_mmio_map(gicbusdev, 0, sbsa_ref_memmap[SBSA_GIC_DIST].base); @@ -482,6 +508,7 @@ static void create_gic(SBSAMachineState *sms) sysbus_connect_irq(gicbusdev, i + 3 * smp_cpus, qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ)); } + create_its(sms); } static void create_uart(const SBSAMachineState *sms, int uart, @@ -788,7 +815,7 @@ static void sbsa_ref_init(MachineState *machine) create_secure_ram(sms, secure_sysmem); - create_gic(sms); + create_gic(sms, sysmem); create_uart(sms, SBSA_UART, sysmem, serial_hd(0)); create_uart(sms, SBSA_SECURE_UART, secure_sysmem, serial_hd(1)); From 7c347c7333d9c6651b0d0f985e7d919dc3aba607 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 20 Jun 2023 15:46:59 +0200 Subject: [PATCH 0098/1353] target/arm: Fix sve predicate store, 8 <= VQ <= 15 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Brown bag time: store instead of load results in uninitialized temp. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1704 Reported-by: Mark Rutland Tested-by: Alex Bennée Signed-off-by: Richard Henderson Message-id: 20230620134659.817559-1-richard.henderson@linaro.org Fixes: e6dd5e782be ("target/arm: Use tcg_gen_qemu_{ld, st}_i128 in gen_sve_{ld, st}r") Tested-by: Alex Bennée Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/tcg/translate-sve.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c index ff050626e6..225d358922 100644 --- a/target/arm/tcg/translate-sve.c +++ b/target/arm/tcg/translate-sve.c @@ -4329,7 +4329,7 @@ void gen_sve_str(DisasContext *s, TCGv_ptr base, int vofs, /* Predicate register stores can be any multiple of 2. */ if (len_remain >= 8) { t0 = tcg_temp_new_i64(); - tcg_gen_st_i64(t0, base, vofs + len_align); + tcg_gen_ld_i64(t0, base, vofs + len_align); tcg_gen_qemu_st_i64(t0, clean_addr, midx, MO_LEUQ | MO_ATOM_NONE); len_remain -= 8; len_align += 8; From 497fad38979c16b6412388927401e577eba43d26 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 20 Jun 2023 17:20:24 +0100 Subject: [PATCH 0099/1353] pc-bios/keymaps: Use the official xkb name for Arabic layout, not the legacy synonym MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The xkb official name for the Arabic keyboard layout is 'ara'. However xkb has for at least the past 15 years also permitted it to be named via the legacy synonym 'ar'. In xkeyboard-config 2.39 this synoynm was removed, which breaks compilation of QEMU: FAILED: pc-bios/keymaps/ar /home/fred/qemu-git/src/qemu/build-full/qemu-keymap -f pc-bios/keymaps/ar -l ar xkbcommon: ERROR: Couldn't find file "symbols/ar" in include paths xkbcommon: ERROR: 1 include paths searched: xkbcommon: ERROR: /usr/share/X11/xkb xkbcommon: ERROR: 3 include paths could not be added: xkbcommon: ERROR: /home/fred/.config/xkb xkbcommon: ERROR: /home/fred/.xkb xkbcommon: ERROR: /etc/xkb xkbcommon: ERROR: Abandoning symbols file "(unnamed)" xkbcommon: ERROR: Failed to compile xkb_symbols xkbcommon: ERROR: Failed to compile keymap The upstream xkeyboard-config change removing the compat mapping is: https://gitlab.freedesktop.org/xkeyboard-config/xkeyboard-config/-/commit/470ad2cd8fea84d7210377161d86b31999bb5ea6 Make QEMU always ask for the 'ara' xkb layout, which should work on both older and newer xkeyboard-config. We leave the QEMU name for this keyboard layout as 'ar'; it is not the only one where our name for it deviates from the xkb standard name. Cc: qemu-stable@nongnu.org Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Message-id: 20230620162024.1132013-1-peter.maydell@linaro.org Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1709 --- pc-bios/keymaps/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pc-bios/keymaps/meson.build b/pc-bios/keymaps/meson.build index bff3083313..0bd8ce0077 100644 --- a/pc-bios/keymaps/meson.build +++ b/pc-bios/keymaps/meson.build @@ -1,5 +1,5 @@ keymaps = { - 'ar': '-l ar', + 'ar': '-l ara', 'bepo': '-l fr -v dvorak', 'cz': '-l cz', 'da': '-l dk', From 50ba97e928b44ff5bc731c9ffe68d86acbe44639 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Fri, 23 Jun 2023 08:24:30 +0200 Subject: [PATCH 0100/1353] target/hppa: Fix OS reboot issues When the OS triggers a reboot, the reset helper function sends a qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET) together with an EXCP_HLT exception to halt the CPUs. So, at reboot when initializing the CPUs again, make sure to set all instruction pointers to the firmware entry point, disable any interrupts, disable data and instruction translations, enable PSW_Q bit and tell qemu to unhalt (halted=0) the CPUs again. This fixes the various reboot issues which were seen when rebooting a Linux VM, including the case where even the monarch CPU has been virtually halted from the OS (e.g. via "chcpu -d 0" inside the Linux VM). Signed-off-by: Helge Deller --- hw/hppa/machine.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index b00a91ecfe..9facef7f14 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -418,10 +418,16 @@ static void hppa_machine_reset(MachineState *ms, ShutdownCause reason) /* Start all CPUs at the firmware entry point. * Monarch CPU will initialize firmware, secondary CPUs - * will enter a small idle look and wait for rendevouz. */ + * will enter a small idle loop and wait for rendevouz. */ for (i = 0; i < smp_cpus; i++) { - cpu_set_pc(CPU(cpu[i]), firmware_entry); + CPUState *cs = CPU(cpu[i]); + + cpu_set_pc(cs, firmware_entry); + cpu[i]->env.psw = PSW_Q; cpu[i]->env.gr[5] = CPU_HPA + i * 0x1000; + + cs->exception_index = -1; + cs->halted = 0; } /* already initialized by machine_hppa_init()? */ From 069d296669448b9eef72c6332ae84af962d9582c Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sat, 24 Jun 2023 00:28:44 +0200 Subject: [PATCH 0101/1353] target/hppa: Provide qemu version via fw_cfg to firmware Give current QEMU version string to SeaBIOS-hppa via fw_cfg interface so that the firmware can show the QEMU version in the boot menu info. Signed-off-by: Helge Deller --- hw/hppa/machine.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index 9facef7f14..866e11d208 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -122,6 +122,7 @@ static FWCfgState *create_fw_cfg(MachineState *ms) { FWCfgState *fw_cfg; uint64_t val; + const char qemu_version[] = QEMU_VERSION; fw_cfg = fw_cfg_init_mem(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4); fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, ms->smp.cpus); @@ -147,6 +148,10 @@ static FWCfgState *create_fw_cfg(MachineState *ms) fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, ms->boot_config.order[0]); qemu_register_boot_set(fw_cfg_boot_set, fw_cfg); + fw_cfg_add_file(fw_cfg, "/etc/qemu-version", + g_memdup(qemu_version, sizeof(qemu_version)), + sizeof(qemu_version)); + return fw_cfg; } From 34ec3aea54368a92b62a55c656335885ba8c65ef Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sat, 24 Jun 2023 11:45:52 +0200 Subject: [PATCH 0102/1353] target/hppa: Update to SeaBIOS-hppa version 8 Update SeaBIOS-hppa to version 8. Fixes: - boot of HP-UX with SMP, and - reboot of Linux and HP-UX with SMP Enhancements: - show qemu version in boot menu - adds exit menu entry in boot menu to quit emulation - allow to trace PCD_CHASSIS codes & machine run status Signed-off-by: Helge Deller --- pc-bios/hppa-firmware.img | Bin 719376 -> 720216 bytes roms/seabios-hppa | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/pc-bios/hppa-firmware.img b/pc-bios/hppa-firmware.img index e7660b0458b78b101c7ed2dc17595e94438ffeb8..0fa3808f163ea60766272188a634d9296f2b5be4 100644 GIT binary patch delta 356358 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%0DfVbJAcdm$Zdy@RS`RP{y8 zcne1ME6%7USdRN-GxYY!>M?eHhTcBuH6Oj7AqVzl^FZs>C__%{i*IaS zol#fR(Kk;2HbdX+W83IACc`9@P=G0p3_k&E4%-)I)EB_!khwj>UqA#v$kPnHt#aO0 zJ~l(zs@w#1wL?abutl>GUU?_u89{W1U+$KnFUZ9MjQ=e|Z=Q5|XH?D57v%Z_%&eLr z&9fo_!0(R?eF={9wwd2&G!bo_s%4oonhN0TEbB>zzIQkQpu3jA%|fi`B>}bAn;|Q8 z70Ccii!x-Tt|Ap6+mg{rG{B2ej=z_oZz4_um|ZtR-$KkHFlR&vTMj@@-Hf&Z<^Y^1 z%Fvha<^pUC%FtWzLb5H%XfJzi6^np!k7lq5D-}xs3QuHo60i*5+?I@I1*`yQyE3D* zfK>qbYcskCSPKw0BST;F+X&F?afZI;w*}x}a)zw=Rcr^a9L$h4zlvP|FKF*&^bigE zfCg1$#0l6BFl$(b-kRSA$Y_`GoKTJeq?KfF^>6iCCjriXnxU_fJqGC2DMMc*`->eQ zW`o#qkv39?(}#^6GWubZT2-fSY$o^Q)+p?RZm5~O4RehwC+b)(z!e{Oti7MinL6*b|EE8 z>DxP#MY0AtE%8Tr#Uat&8-LW0%nky&Lp(epv!j4`rEhK~^K8wBdgO6lX+$3HjlAvn z%;&t3cYZmurvTO!Skg<ILR$sw$;Om+E=))RcJU4nS zvlE~Bh3MVUnY_Mm%@W)}k*s9)L$|cHp(lIRwhdzTT*BDfz z$rwup286Pk^05sg8WkWPYx1%6Cz>1(rgvex`oJSO8PEcWbnofLBjjpMKr0E+x3;^( z`&iW}V00+r`3Bxc)XV5jn@?R4pw2`R*72(>PYO`EMWr86Y5ycZ)ihf{$=wa2vcs63aKZ-siI*dLI zzHo*D{ZCjh;=>)^Sf{j&3X=oB^1}1(?cAjd+lcrg1H({o>xZGpaC#ZP*+DG6EFTu~ zEbP3au4>#ETAw8K#z18^!UMUxvVIsxFNYCj*}x~TytK<2=XRrt4M zV5cf5*No=_pJlnq$ANY)gQ9^ywF;!mvEiA( zG%Zj%E7=+eObL|EO1|@Q(mzl-tGFNoODixIYoO~}gaGW?9M~g}FRq8Ownv?*9muz7 zH#`T@$Ug&RcS1I-XZH>44L)B#*^o#GYZXWbV}msi(f0>ogH_@3T(2(z`5idlkHeTN z8?Yj}VYWL{nCSk2DK#ZS6!&|p8(xVaH-3~jW?QGpfz#0zH@r@+-Mm$6g98OO_+j8% zwaJ5mXuK{^t?B_jsex*U02YF&Kls0r`0DUn#fDq0VbZIC>ab=cQ0IbgprWQRP?gPd z>RYV@8XAG#@AuPc6ZEb>AnBuT#y0ikGrCsg)R(c%q|;&7Yz>Rm`@+A5qYCVeWnZ}Q zsfsP#7jw$*Z7>#SL62iw^nk4u>d#=g78lzREV!BSF>{0yt&LB`!rwgj)p~-jD5q7J zyQ!ZZe>kKz^<(^qvW>*gC}B*50NFRrdN;N$`9`Zo(3&5LZD%UKv(fmcHd<8v>4{>K zRq#~h3|z(7P*kl=i)W^F?4ZQ*t4SM!W~O!Sq{Q;h+E?pw=ej9I=~%wuv1ucEx=r|h z7p+fW7C)z~A`0{C+2na@I}adxx$J(xeec-k}QBsRat zOb(Bj#?4He%LQn1f0}+HKs|tALDO{K#}~jnY?|)-_yhFYJWY3S*s9L?P17A5Zp^ol zSS$-J3QYVw?YaaPDSfjH%~yGhUQR$V7wpfWCf&tz6i4 zd!_+-a-f^aOG|~CDw=1LI;ebRRZ_>4|Ggj8Z}-e+blzyt22PvVP)9jH?{=QqL`PxN z+9b=ZH4|vr+APu1O)UiqK9f~b=bQr+)hmn6J>ri9a@EW7(@`(CH5D0>F7-vE3mH1} zGY&8n6A$`S7*lbA7^lHS_$q`GTVxH?(ITKj1G0wbXfROy^;yGplnAuHPSz+Lbp={f zZppomfP6TZiC*Iovz4H%$^#~A7;_|w}+HJI%u2_v3gdBt~Lt9 zRo~4D)ln=^qf4{GbTp6~_uAs}{I`t*;t$Nt=5*%Jq`+x7s*vrA-p+3;>r7GCY~E6F zXi_Lkm{XTSnNluQ7;(EE+5YJN4s|Iv9x^(#7S(5S(sVcsf;ZIJwV_4-Y+Kv2v+JPY z;SCw~!1a$9XEV0L3EdA2Wy!#KuP|Gn9!P!i;5;-SCrIHB?bqsMLp&gSg?Fkb=+ ze0{de7^LU!Ts|8!23a}|oH`{}nJrU>vfAJa`E|BFy=SH0wRtu#aFli=-BKK z3=+P6uqp5@-<(kD{vB*J4&}(?{1bdR4Lh(o%|OuK=*YL^@C>|uH)V$hIo!X;>LXLt zJytX3@DSmVc2EJvaG@!IX~{WC4rlZFYdZ@k;@F zMfv7%vVP=S*`myeWj`Cqte<`~hlAviZ;b%md*$$U-6KC%2WXa-6Hm%7az^6tK@3=j zc^A%+X5E95Af}&maoIyBwapVtniKeKW z1VnyhM=N%h=4m;D!KRe8@&_7~o-;&80YJ+RQO6K>W;iXziC6R)E!v> z={7xAUkTz8#G0hCV_20KmdgsG-@MzoJXfDH(%$fhTz%C?7J6Pa_~&v|JN9v)1;;~j zpG74()`KO#D>_%7CdvVmi{JX^b_L&Yqt4gO%QyQ}F4ugj{VjafvC+9bkb~L@F4y&H zl&jAGsqpCiTzv+}ES%!V?a2&~voZa~aJ=i!@Ou*dQ>Y?c03Bb-eL*OlScq0_ zZ0<;u;&CHNvEln_E-Tpy9Qb0%^MnPxA@DVPKX)wHPBgF?b0=fSK4BY!Qm>b5K|?Yn z;yF1eHyLidQi10qqvYT_T0WF6EvuRPA{3oC0T<;&ceumJDN3%DCX}I!${U=(22$hP zsS;NWN~AT4&dmTk$@>L5&dbe2qdQ?^$<$YJGf|!=Y&CTQGcg>WurZfWH8WcgFppku zoSPX%z??w!m?r6EQ(1R2ce+Hx^|S6za%TwWqA}X=RrbzwDNd$>wsvdh5QO2tWMKAm zrE^2vB6c!0DlmJR(zy}FpA#qKlix=J!SmXJ7rKbtJ(26;k>mZ~UAR20-w)n%YL`Yb zhI9g3@Wn2TF$}l)KAP&gXrZFNKlOKMg8t~_J&rABmUR)grfis8^KBSAxw#Vup_O2@WB+%DQ>%<=}=w;dErdv%yTrsr#&f(@q9A1~_eC4J_*t z%ujNhdV~2MJU*CT3ppJSL3{C$Qw-Oqw#DFQnfx&H)XH}ds#Iuvex1)LyeIZl1*aYr zc(@8y)If%v@`T+-SV3D7DunQXn{e8IFw;r=AP*?l$ zk!&_$yM&OG`@!9i?awShh>tA_A+MN&c}sSS;Sv&xkOT3-u?WG^oCJj+sG4tZ4@|F2 zi4wvo@$q`WabUvLOxPdW6&znl^+$}7n%~44Rk?>OJl)a|j23hHYbY@6ZrvKMJ#7s( z=%1gEpjN0lVXdR{_@2Um#a9C*Ft7PY`}+?=Cu^Sdb#vM zUMm8b3%47X*IEE;;`Et$GM$nG*6%#Zlj+nap^7a&uNgX@v+c*A@B1r{yK-mSqk}qg zT>N*`n6u9X(T|FhqqZlT#^=!yIy(|w4-csH_04;hcJ0>f>g=@(rgZVzb@+?CXo51f zmtkx2x(cX?YmbtZylw*6c)DE5ixE&)vH9k8q+J)pE-jDSel3Q>u(KoCv(y~wn@8{G z?8mfYH`ck)Em^DPaT;dEs0FGcw@UJS%~befP!B^3sH@ z4M4ls@}>$~B*443^X$U*91S?b`$LyIuI6Pj?xUcu-I~YO8B9OP*Wd!Lq;tfzev4bZ4x-fW@71MGe$FGoOcfJ|p@YbMoebVoH1gU|;9FdGzDoIW>khp4-CS;uBbLP17`3y>m}+OTj+@ z>sR7+W~cMcy*JQ^8|=+DqRqeakS%t>3d(`+{4*l=Jo(Po5Wb`NRls*%zBaNT9zDc! zi?x=V{I$=M4#amdj9b=nu)dHL)(JKG&pBftg6|Muu`F&5-`3Ed8_gN#d4A7l&UikT zA!2#}=a);wPZh{?zcGgw37nsY=ak>)@O}W(T09?$o5Sk?OlviQadYH)020>xG>5kX z2$OU6oMg}QsPl8=osBr~xP0cwD;seUIP6fPz^^5|=tI(51tFy4)Pg`%q|x0NvgAo7Jws<&A77Bg;!Hz?oOK)J{gW|FeSiUa6goto53L&6QG&tJ!}FUh_z4hMkP8 z;hzPEE5#UDg{$C%S8N9(JMu>XcP(@icQCRZEedXVrFJl~I;#sls+3}6g|326E2S9M z%dZstt@x$UbEG;Vf*TE9{*2SG_y z3)H|$!Bz+|oG4JkD+PlP6t}!UjTAvHv>RS~jIiFO0=1)8@-;@8?J7|FdL>_DlyBWG zPzQOVe2r1Qy}CdhS}DjVL)H|ilPd)o<+@J`RI68T8)IzPqd?WBdL_3p$~eCQwa_cM zjZvOlSD-Galw_3iHx{U_NAr)c8V`hH+TiNGRkfN1?pz6;MVP}HLPV; zD^M%El3N*NpTPy{kxEHM*?&`kdZJR2QMytJ)a#XkjB=T?K>g4wxP?)!>{6h9c19MEmox84+fVC{Q0&N-jcBqum86ofW;tZHe}Wt>rZfxk7P?3)-WO7s>*K z%pDh$71E8so;E0JzAcn}OZh})p{cMXMD&xEWqk^{ZlPcI(qUVn#+j&o-^-}a3uPCx zOy1$U$WJF3dsHdpy2Pb?D9yJNa$rUm2T*r?VMlLt@h1vpTe3`Uh^x5bt8uOM(i8A) z8=-}gPv+a!2#u#A8kTa5YnZ9Q-$4G$2TuA|*JR~I-aqKCYI?#r-ONwa^n`JgO`U~> zC&d0O$HKDzYI?%B+>=_O=?SaHe%F4sa8wi8JsHD;-Q0pbx{pm9AN0_dTPMLJPNmOl z7(Yzg%_xk^LDTWL-`uK-yC1(iM7Xr4@+p{zf#%k56E4Tbv&B46`k=+MGPj}UaGN3b zuOg(jW{$vECOcY&EuFABJ;vM?Fb3F2=eIA~B zCYj+EX#hxFy({LPCW;=3hO)AS=4n+t*?6QALJZHDvnxZQ5OQFrIS1yn`JPf+!Vpq4 z*_@Avlt|GNfsnBQ<~fxitq@Q940B;Up;MyRZq_s}!sIL{2IJOB@z*q zw>9snf@j&1I}(ZzE&6lwUZms7ez7V5fXaQ z{7YqsFG6}gGFOfxTa?09W>rD!yP6~yDvsw++ z_Ns~uyNZ^5b*&H^E3M&D7n@byOn;SAJi`VyMOdO-WuK}<)+Wo!8)nr;mc3+Ie~Ild z8}RcavLM^R)9^F1Pd)NnC(j{yIe1QYvk$#EJ?tRAN$LM3(xf|p)#w0TtC5ds#Avfm z1X{#3-2n`Ry52vUecr&T_Vd3=l93An{l?B!2AxFEqD*tO zA0Vg=?I4mIB4XQ_tNns7cTj%>Z9ZeJ_GhK!GL%tl-*CU$NRZTlgS8Rz;&b>ARFdn-JeA+sgqHbVNAhsQ#yF^?A+ zD#)|pM0h+yq`|Mdijb?O@ZJc~8own>HxX1XEW97A4wW9Vg2hKa{Q5d6;ioKy>m>)! zDvHK5L*=@@4uWb$JlF!p0iG2$DXr`K$+lo_b4*IEpB1)HhFlxVEr}r;w-|SOLJl&%8y)#y;*%>=8^xihR<&tZo9}$wXvPGs zI|)9%e|TfOn-AvS7z92?R>Rt7&{S^lyP+!XYv5t5CPy3Aevf#cf=|;)wSpz&;MucYHpFA|8nk{DyWq2eHpJ+$B1;Zs{#JUKCK3x z^`Z7~JB=qc^kZ=ywrSjU(XUmFe?ima%$AJvb5F-El2>@Cwh<9_`O5v-dp49_Xit6vY*u=gpa<)^;Q~>L4L52x(`*?+5t2yZ2|B`k*0AN*Dvgzc~*-O z5DrqIL6a5nGR}<+Lp9xX;pJ|z*;+?o<`)x-a6gpF`aSdHb;R-BV5^nw~DO@u(-O{*-uB3DUhzZxY z8Pl?=ym!l-{$QWvY(pk~@6E>Zs(^ee2CNsZ&Z~-=e=CNG-&$i{wHi<&r}rWo&(n|c zRp;Bs^H43yXMJF7l(=dh571VxV}d|tvw3n@uk0CsK85q@a!4sN1H8R*o}An(Ysd+= zICxv%HqHxVyoG@|$~hnJU zX#JE6V|CZhzr_TXH3fLqXa0v$55jmN@Yx#kZwrc0_+g4mPv#rza!r=G`C)hx9wMtf zRnCKSe%%7b#Lqelv7Zp@JXKyLafgc3ec0JUOcr82H}QZ0vgz=OQR``S7=d*VH zGQW=y^gi3{^9zHd?M__yjQmYo7%YEhEi}vDbf_cvjxAmp0jzW0p}qhj+Bs0! zD2F;ySa~^T$3+fx6cAcEP}Qambua*&GkFFW#Y!6P-Qf z3pNFR`WPMR1{i)E)FyKr>PCHIm6pHxrbB&IqNL^LzbX&CjeGNs`wRo=U5C0wNO&K_ zoxQiONcI|@dILBgRw7T(IeNat8Gy35eTC0u&eq=N4bJY~=k3m+d_E4I?AM$t@m%e1 zJln&ZWq7{X70;>KPUjkc7QX_le9gImgaH)T>wMKK5aHb95y(F1e9ar)$+_JVZdvWz zjb~lYUgsMO7d_{kZ+ZC#Irn?{_c{-eUz3OrI*)k->?52fJWN>!ojla5D?Q=7;NhA5 z#Q7ecB{k{0oEJU($z{%~9{$Zf&YK?ooT|=SUjF^g4?X6KY zm!9X0M$Y?Qo_o&kJ>faeI)B2m7?IJ!`N+$2-}%_XQ}0>lUkqnX%x>y@B0Q+z>MvnV zwJHkyBds&)LZ8M?RXQs<8JAJwRI6hIy?C3iR-FIJsp`X6?fB#uEs9g+(L>Y8I-tFD z&Z+9-mc)+fj}J>IaT&yrjvYGrD{{B%H3Sk$q)^2%XFt| z5-0~4{<{Wt^_99NcN=UQ>Qw#F9eu=^Q?8FweK8D48jEUrqXMDRgfm0|@%>+%s)d|M ztixq^C=sH{Dtqyui#tRg72r9if$JGO*IiQ$>(vSFiw&&?ynBO`)NCT@5MphKF`X zXeQDcCb^oCcG*MwU1))%P4;tzlXf4^?Q>kb_wJ+1c(#vsalb^uJ9cyR;)j5Ru(HfG z&_ftI)-}Q-aQLQ+3zi~~_qL1I#0dZXYpyg;_?#5ibWeE2Fc(jh3ICXA7ccA-{+=CO zE>C#wBv+{?Tx)XH#mg{7Aiuh6y@$|zm20af{H6V_-JbBoORoK%@K$fTj(Wo9E_I#p zgh#h?UGjv#vch#k!ZDH@9vb5M2(|7`HU@=0ja@joiS(CoD6w{PeJleWcg-_OTz8}b za=oF4-SsId2Nvi9XHJ=}xb9*T;Z8O^lPj)wT^;RHF$+I$`%Jdr?gca2UqmgbyszPXgk(Ps3t;&Vc9Gq~iLRWL&(B=VG;( zXL9h2^lz~3EC8Vvd5Z@FQicso-rYcNGx@eTpZld*BduM^0w(#wO2 zcL{}g690SgZUM}bI{S+E2%rmh>|ya@tXn~ z1Jr+5{FZ=FfE}*l{Q{Z*#I7zrAb`Vte%Im(0rXAt2NfR_5TIIk&*c+R&J&x>S&k*LVeis^^(g&d`t zwRo{Sn`*;%Eq>Wd4;Twgm@qc2Rh;Wqcdt!(>0Mltake-&LW&V||CHjH9x^>2m@=~^ zW2?)L`W4Sa!$J0fF*&9<-NQItXG|AH61x@@TRp_pI?)icyKv(>FBMqjK}q;sGA1@w(K2e@G1wAqBrPwibtj@w4M~XJTWqI2=6> zc4%>0WK?l@C<-_m&wY!E!`tu~WwY@_aRh5poT+x2Qj9k*(VfJZK&Zd6xC?Udt`pCF z8W-zZyTAV;@bocDQ9gSFeIN&dRf(etc?rj(A=F*9x}&AFD^feTlki2AS~I3( zDMhNBNaE4u5l@QT_oq|=%4u7^>ocq{Z7Wh=lxkiJ=ktnG8=v{{;7%)xRJ#X6&n{Ba z1=LChQ)Xit4W{GyMYt6Y5|QXvKi`Lt?dyuvLFmy%N7rgaY63xAEuK6FKfn&mQnP$ z1Jy(EsN+Sd3OW|zB^FiYbxal`siCK2atbV>DVtA)6KO$YdhBfl^PY9&PvWIR*)!RyZ{y6Tqw(x~%aMF%AO86`zmTd+RV zW;S1!SW%QkxA_!D=`NW?$34$UY|B_TBua=-ieK}vx zl|7YhuV|07J&E^Ck!1ba_EXVTPi#ANnXMutd@_cWkxF&QXe%=});z z(QttwhjX~3B4MYBBy6zg)cMUG1S*A&@2 z#1lHv*3w;#HqR=uNtY+xLy;|B(gdLmpB5!~guc;*lKvqSnWT4={ot_fE0Vq`MNz&s zN`C5dK?R-o9JOc&8o}4C%U}5lALguGG=TH@GKBQ4%VP>f1Hc4~Zf4|LMI900*K733 z(9u&F(nb|^l*#}j`W6*+Y$p{1?ebY^mdFbFKXfLSH6Cq z(_WBUpy1K5Ktrp4XlO0%nl*D$yP`&PeNePt|E8zB5yqffF?v*?IwSg@&40QK!`*rG zO|0}kE`uEL)B7KnA(aJNQHuxfT!u6`a!AsgZ7xFwNo7h7T=q6DLtm;v27WW8RyJ7m zw@_>4;Bg=<0ObN0T%j&QoW$1?-h;tqXbtcUE7z860GvqvW+{ixGwJm68l3$XEsxF`Vm769a^^u$PudKw+*gJveA ztX+Q~bl4AC>8_Ag2c>iAIi&K!iZe%FKZDdcE>MrsZyzIxn6= zA3&(>S)e9tNC2HM>zIemLMb!Vq7UR!7qVkPBSqSm-*c&15M$cEty`Y?z}QHGaF*^* zfuZ0Fm+EnazU>Ef%pBbp^3}EJ&Je6i8s<{dzyZ||JYjUH<2;)8xdq2br|jmPAiT9E zcYsL~^;Au6uei!7?RBZcJks~w(!-F?w_@DU4io3etxAsMO0>`2bgBK^g8z$j z3-%L1H!mxwUKGepz4?KXdBCL((z6rBhcq7TQhRvRu$eR2J;Z+k*gUKJqi?ay+0=y# z()7&x-wHQVbR`q0x|fCa+}78nHV5zjKKJF&3m|?LgwjRZxH|r>rS>*kCvcg zK!AOixvH%z%PpdtOATUsqf7N&J+P613+di^8Z7mcMKK8l!*0?2f|T9Qv0-Vy+rd?t#~BbNM7 zKBKpCnmB_9XjY^H_Rkk{Iiq z5;le(xXug0Fi!@gC?&&CLd=W|rKJ45?~M(H-YXeM*4a8MUpVqaJTO%BA>!c8CA~Zm zuh1ELiB9HRuf8SSsNsDfl(+inQrLpudfusCLkl*Y1W5X>{Me7i2u**NtsV#Fhhs2${C5r7j3L6Q z@+-{`OWfAJ87d7O-AMhbPW3gCJ^_hKsIS2-Q254u{ks6DF{1tg*mlU6>rM#2fABC} zAGDn6F5N1nr-oh8H=HVK^-s6J+6%dn4l{nbh3?0xW zoob;6AX`=3NTO$Whiy)oKM5PlXED@0Os4@A&{EdNsX9#5A{oy7UyN>t!?WInI#pix z&!LY_UJ5GKPx>3PA@r+mR3L-jd*oE<^gZe){WO3yW28N86hISiKMjBmQTl18e!r&l z)3j=oSOtTa{L$_hQ4<>tcdGOR*=IkR3zdB|Fz^jQ@dljw4WM2%14Rwyw%GLg(W&aL zAtX0IlGzuh_u%hBoR*!t1%SGa8*;K0hk9G8F2{tf;SM-G zgmH@Ub5Obck+G3_wtVp;3~Qe`)VHAE=Xl8i0MtpP4B9f#55Luw6z11$E5h6T>VVgR zpmaC$cJ|>O=Ixz@8GNOo4z+-MyWM;RZ1*0%0$B9(Zqzvk-kH>B6mpN-P7cJ1@d{4ChPt{6FLk}U&!I+o$Sd9CNK{9! zsz~(2-h{RXhweD7(mrsg>@3B|_uY~$MADtMR>BNWG7{f{j}L zBg#f751n^zf1ui4N7hi-)v~a5}sW#IKXw%qEO!(uHoG1!@PX z64wl%hbNZSMGm!=Czi!-!CL1qaw&T83JDrJ> zA26X9O4>O7%czkVzx4(qGULBuC5InPIrXCB8p&nQcj!|G7dC#oApVYn_j}5K-ENiR zcoTFqi4dPr=s1pftb|7mamcYH`b5#o94F9dWkB9J#&Lq<4jqwbq8?HFEsxT{jx8r5N$86H!M;$NAu)y>m z%XEE)D}>li`dYY2(^!7+j{k=pjGV}xWu zZO$YdT&2_n5^6gJv+X>7pi2x6@ldLEar6Y?_he$?roMYdkhb)(9wnD{yMqK zKgcIQ9<|ItwZBh=+N@66eJ|HQ$0w>X}g=Qx^?e>wOMhB}&|O6Ue2 z81D!mfy*riL(ALzZfv53FI3-V*nd$tTe1OA9rY<{#!CxT7TzCRjwk62l#X|*{s+dQ zjF&u9^*{WA5J_ZBdIWzMkn^4IF8rIaFCr?){w<;tut)mJLbU-J$%U&6)hbAc;Z{uf z<=;_mqnD0{m~-J$4mE#p1#L_A(!MYq#-Q>wJ-xIg3AaF4wr6Qej)ZJ9`Ie>brBSHjx8lJvY0}ajQZ?~h&|+yEG$1>u^Z3$w(D~Y?-7(X3P4f|P~{4M=mwy1k^S8oE?g}&wEw5>Zd6Cz%dE&$zSU+* z1e#j~fGs?cee~&Wr3Ma7K+4}O^sH?mIRRE$C?gZKJbSX#AR|)+6bk4a|QZhe>E%hQCoIu9m95S8}U=3pe7~ zFtJqs`cWMHq~Rk=)pHPK&3Tdy@&6<2J)o;9w#WZ7wJz3Qg&ST$Ks7owQm?Mh` zG{3JxZAZAjttB{s*t9L!4s8zF0@RKisR8taKozrFwa=1guTyIg`1ac3+|li-JQeB= zoP=JXpdBT`np(Vt`>F^g_A-*QHyF-auH_n-a4yZ zi*>#F!AB~lUn0vB(y_@EYKk(H;kQXo(HaB5%GDI1Af&N!HPtcsZmX+q_}dc~kjFPd zO}`tLCw6u4tqR#1QbxxZu{hPQiNs}Y`R*Z-8~3SD-6VOsmCO-!l5NJ_n5HmCM5c|y zDpaIo`^?G~X-c*TuHdUs(N3>f7aOS1$4j)mBy_J(^&zAIT$YM+@}(cIP}k9Ntr{{> ztxyehCRwXI)wDv%TbNwz${c%dg~~uo>2>``YgC~h8_hA4dV<31Vk>?}frj{F%E@QM zjH8LT(;{Dm%mTH0U$v~_j~F{%cHQoS-bsN(KK_s(ieI)Zt?!A7VodF@~-%be#{1a)fVL)++`wp zVNt_5I!gvuv4#1`!pNRK>HoGM8Eg*SR>AT{xsF%GxV#DNS6953Y4gVcy@yR`S?J&I z_182Rf2#IZyx=pGTV50?8e28htnwQ2?dqgi6!qTXoN~C{@XO z4Y5WLkJnmx_h4x(<^1ot0WD7#TQ8T^dUDgj=a=Yn5GRrHTfjy1rJq z4OR*RH{Nz$MWDUN|A>~qeXSa2YndsY`dmehWtsrgew?m7LV4C%#O1;VN94S#LhZ9s z`_)SAe~nNhbc)yyl03V%g0V$;RaFmMN2xJZcG|hUn?aRPQ$ij9)Yn?Bx`g< zk`x(RwZ|%wRLd5U@b!)@B=vKOwEv?bPKrES^*u!bt1IF7ydrgYF+CNtWM2_{UJvx_<`U z?@Q9FcGCM+y_ie}-5=-~Efpy>*9F}&Vb_`*HX!JhCq;S-ZEee{)G%*yV4WVj52Xg( z)k5xqO|CjryNUM%-OrE|9&RT+6RMqExrz6Pu=B?T-A_oqEIZ#5|C?|ASjjhwNx@Z3_kEI4Ucr{y-xsR={PscjK1sUIPU3<`G|nDS(0!-2h=}Fw ziQlE;npoYSd#9ABwoB}^hy{?S;BwH-^KTU{t7>6%(^YC)H3d{Tw_(tIONd;-4?%Y^ zMe4|eP>K}mB6hxoPN99Y?V?bj={BEEW0l9lB8<7(2o zLDw&mB(rX~yMD2fa5k}VLDxr;bg$mx0*EuJK12xhebtY3yeWZgL6_`=7<25N==#*| ziAYoZdeFrKPgVCVo9?@su9Nfqt2x&_5Ol4PoEPn!YeFg<*Er}}PEtgSowQsNu~irl z9gb_Pn_*ngC0#zEt)1~|mtQw1D35tn#8fLu$w$sGz=9b@Q2oUUiK(A-MJ1mbc`sk6 zMIH;Pe@l^-c9DOFBwCjlRNqSy57`2uFZKP^wB|u|UeXTQ#m!B1AXL{i!Jv|f zOXLwdNj|`AZ9m-jaZs_1rJ`2YNt?79s>Vfn`*bP{D%qFQ{;%JHpxWjDeNoDG0c16o z)*gWIRs+ni&qUHGWHr9^{-C7-iY;u_saJ2wfc63O?uov%davn(gDBxE{kCI(dz`J(IC`HE`gn}0Ri(4dm3T6Bt? ztso>(_&m3W20mZ1cXUD3XVG4N;CS#ndmOP-ndvb{;M0w&-rX|e ziH|8F4L_fJ72+7+H{bm^RnP-kwqWYJkTpRM|6@;dEXXIpz7~> z-uQ{(!7)M;-B5N+vd#jp)i(!+2>uzeMl25wfvC0XJb8OiKS0=HsMs*Lkl01nnD`5c zLF@8-;%t$X#CYQa_XlMPWR-pPzF=Ev3@Ixav6Z&62$X$QEUGQs^~NX$)i%v3bTBrU zAcZj3SlOzjwh6jnV6rYYD9a;uXxcI3nO}YhBWN~wL&x+8L@mA^(q@P!VZ)LvKqn#eIHatWV3D?g#hV~eq8Bjw0cxm=J;1;ku3 zUoC&$9-QjyGfOH~UTKzh2|I}#TM;|Z{ABq}3Wc_>U(T5oRevmedz6;1kW<(7!pm0* zq35=juhLr+#Ba+kU#;Wttl!V#vYL@bY~6y^!c4Y14nV#rvV0-L!={#x7vi^2!6iny zKBRIK2E#W6%4fvdFn9vpiEf0PuZ&D$i^K zUiMnE%gXhR^U>JIk_Bj{1BJOH-aW~SJ>s?Nax-7giXUJRdiBa6h2Se%QOB186kn&CkfLp@=7y>ll z9Rz?}?{vVeBu4$M+cP$zw8Th^t`jGOb;oKrv@@^JJf0Z!2~XHn+@CR}i+U^||0k^l ziYOo|Gh;n-UR)0V$u$tyD>3RbAu3Cirttt`r2;(RshSrwAwm_}ZWdh#NF!_~ggw0m-5)a&dvYV>jbrqFh(K~<6HgrwdAsCg6c7Ku?O z1lp&HCM;UE6!48cfOo6H2?cZJ0-hA`el@qT5n=ozIx*@Lo5(L!R>e2)CMJjg5h+nG zqaw{ol!yQWI2X{nYIp`-w#Q?x9A*w6kDfJNN7hlLvqfhv0>_gap z-Jckh&xV_DIaH0E_ZBXVGm4l(iMsL!)@IYA={0P6CSSv*7e3Tdm)2Gvtu08mAS7e3 zJBK7j^{oSNl+cxs%jQ}0Z)()z9Sx;_QDI^f_gtxl>)mY)l_EZ3IAJKW=M)!_DTGM? z&3`2_pHMW&a6ge(^~rT8Y$EV-!csT5Aw<>_Zs28bn@d*%5}wS&D5jgLVU5rf2HOc0 z4ud-YZg&_w3h?k0VSse9&^J6?5+l!gg}yL*nsC%%cATMJuCQ~sjn~}zB}PqyTl@@% z+ds+mmc#8MfDasQ-vfNBs{^;`oL$kshNm{i-^lZe%~4SsjL>kDSoQCQ-umh9*^J~( zN)=%T9*gB&I(MGbVA zj04~{OWinXHb8+>n+=)*zt_}8m5^tlJ79BN4Ycwq*In8sc2OoKF{)6wRy$m`kaLs6 z^;Uo?hwB3X_c>f~+31j8M(f@IaQ^>0;*aJ%d*5TMWvomiBXH|INaVMKcB1A z1}Ntz)JG1t{{#5m;dV)LcHz_vI^IloVw5}qGxBEEsKa;*|Bv`AdKlv#hGFG4^}90o%H z20IL<0!+56e)zalU4E~rx~B+uu4ag{@GK>ih7A7jDP4wNG59ucP2fw?R<$JeT8HaR z0Gl1IXy3Ef;i?sW_j1?B6 z4djqbAhAqurP0~&Zgc9kAIzOj-CFBT!|ye2#QQLL9@2HITAk=^68%MD6!-Dcdm+-K zbJYWh-lRZLV&oSo;Etl4FL5YM#i2AWMNmfa$S;@#G%vL$43S?7ROU<=BEMo9(tM5M zL?XZLWjPVsNT4PPhbBf6c@YgJ=}tzE^S(^bj@czm^iP6}ZqntvpAtUS^{SfI#OiY1 z@4#Jj+UP$3WOTS()?6-IT)q`9D1o%IPV}EIrBSNHh zSM&Wr9=;E%T}qgj^^p52$H|)GF99m0gx9moFnC0E&NK68pe&}#~iMM$!Ske0!A1!lrU$862=TA%$cD; zLh5Og2+i=qO31U&;kp`tj&7Ulk-eHLztU6x4cBHkA8oE-TgbV|sp>9(9RT&jdcy7@ z?ALXzT9<5fim*q)@s%7)n@=o{|m6C-~W4wVjv*T{9;;cy1vp8%QxZ5j5l zW1iL8+}@~Vo?-OBFsBEG{W=8b=c{!(r|ZP8)af@ka&?har*K+0T-hAMqX8mqj`9vq zxZkSM^k!C-!kJ@+x3H@e-X0)}eN@OvANWNx;g^9f@^@!e5uQ)3?i`MylSfEjm)e96 zA`Ea$<9A(<-)l@Gd@OlJJG^EXRlhd#HdfxMdd*pcowL2)`@;O3{%sNE^-H4WgKqlQQH%V}kWQAN6233%^h5zLRV#blrO%BxB*> z$E8}R#C`ZM(0hclhS3sGbiA1{T>gkTB;=rl7EBN=MSn)lPaVBo0{BiVT9~n{facHy zzN*UkS%(>ePWT_fY^cqw4zrIsbuDI{DRw~fI-q%Ri@0i;?KT4L!jRTX)`FuWzARaaYoRjZcX)WGtDIL1V8W||x-O^_+San7~9Bl?{< zw?;)hNN+NdrY1C^Kex%G$`fH zhWmC?u?qqW*#wdngPuiW$**Ay_PJOHtJe4`_aypDWDVg5I8WNjB^0P7N(sGNrM#3* zrrarATEvX;xwr#KweBXRGs%qGi{cTWds0^^AT|2CM#Tgg2`BOu31Q+Pa12zXSDYgUB?GP)Mn1R5)rGVTk|*M9K;41i*ttRS<3w z01pzij}X`^&?aI`7NQ=(`c!nW;l6hw#J|JZ;^_;4HeAQ0J8cv*k*KF= zrlwMR>9kQyN1~XHP;T;Q_#z#tZ4-F7qEeanyC=^e1HC%xUs9~?9t4{57P0O=<%=Ot ze0vZdeg%5!OB#LH3ufxq^7Enmyd6ioHti0-ssDz|H-s+)xI%>WbJU-r9C~szjTc>4 zfQCe9p=gnDS~DWU3DWVWWe}kOqbE>P(GrT7Ty|CXHCp%)2}vTnjG-cY^gQ@S7mD;F zFybjsP;P_P&NQD2lPWN?a!;uy(<;J>fynlf&Lf(b=Hs4iFszoMZz60K;6oyG&*)tO zyiJ4-6un{pN{4|pv>Z9wi!Kz1d+N3jGkUpk= z#c?*e4kqHqqE8dvhNSqh=nI5Tc;S&3OV+2ZXOtV;-!NR$#qFeT&nPfb*ZZxvhNJ&u zRGmomMhE_63%Cs*Kivw-as^ zfT@XUhlo+$XIT@u0~>_>zTgrx`@0`dVc&w5`;N=G6;6Mhl^nOV>nF*3gr znPVCd>I;C(G3kW103vftXF`t1{HrZ3Z!Q3f=FfNW~Qqk5=esw(>;br)Pd2GBEr!M8OsY-t?x^&S3 zBXwyjd592Z7{QlQmormH|Iq$KBC#$wq3Z(tUbjJhw(!&7ekf7611}l>kUB*kNMuZ~ zC{0NdN(>lj^HZl_vU<2pTbw#2-;RfGNu8SM#4A(vMLaSjuiuk8&B5RPed;u%)n%g= zq)xXI5D#uM5ig_65ig?*ahjLPkB+SgNtZDJ>E1|99jK){ZAmw}@Ub%7~<$s||^C;r7x6TZd5p5RqJr@vObYT3*T?-x^}rt~+A z`j1FY?$#r@$S}hP)Q14|iopZKR5SlLa}P-AnIL295u!l8)5Q!A45a1dlHFK(e{3VL zO+Pln2PWD`oN8?IAv!36<9eGwVCbhr>ytZ>VuaYj z%GP6R6d&NFRScDRiUNyIUT(nh2$sB)qQr2n*N}W;1>sMh9BY*V-=SOqS~OD(pQ+_k2Aou+l8*vS3n>xmBJ?pF9Zal z!u976n1-o1CXw~`5h?|kN`#40eNOPGxcR*8iJ8>@OXQEs>BY}-cpwZDH`Oji@|2M$ zi;yAv-*Gq9sF{Pc2wM}Q(`4Znx0l48gzh5CR_Ww%_W{l#Ocer$h-@H~3-CMi$ft0vzzwLu8y;*ahwg2kh8J%KT|g$zx*@9pXVAiHT!an zD!^M)&Bx5}H(}6WIy~ppg#&eJAcyMH9~1r0=?3^J;VA(I8ho}E;4cBj0ni7oGX#W!W$^O$R_3sR5o%|U{#=fO0y0rD~x8LQOdOzs+j!TjuiYA3O|TmV$1ixv`(YD zTIdd53w;4J)10|9`kY@WR(L|@(^NfII4lV)xrRd-PL^pPJrPM3U2p^`3zS`xO$N+tn! z)v+IKI+qzqL;6fZd1^7Y2a%@Oboo_{pe= z=>a$Zn9Y`=Mn;;=>C+xwj zGSLPz7M0y45#S0-A9}!i)=hi=2ALvFyFJ`CWg21r8b*ZCp-{Xo)INy3RVM#jdmEGb=CJO-Oz4slvN z`(a6@pEO1}jgyRkq>ryr#U*z7NlBkV+VzBNU3@#qyX<7CgjfaRW&G*zE zK4s>>ic96cgE*JXu$ySf+%2Lmmh~$CGfLrw8_$wf`2lr^|I7aq%$)=oa(eiPpw-6j zE(M5_ACrNy=N34fGen{1U=d@6btQAo5}eI^JQ$-f&DO3%jaslmR!W&kW>{feGW+HQB>pa1Q^KzCXx`2P?<^aceR@a*p!ffirXPxW(FnCNXlZcOgH>l+BGm)Sa1mL zn3AgHE3Q&+CoQr7Pcn0aMOf!tm|~Z9X3(Vx zLSSL8;SR_=Cif{a%ao}!SL6E|?vjr{vpSh4Jx3##+Q`ppBM;fg-)bYzS=>5DIaJ4M z0zC5he7T`IGq{APE($cYD0I$ouvB2tbU``@bj$<_RUWyI2%qeAC1ic5Q-3ksXPMVsKfy`t*u!uQ9-*=%by_$hD_-LI<)rErrCt)v&)11GxK7-8 zZDN0&n9p=pm>wiCAex&$8m>0kS$5)U4%6wn%nG|+A3Nw`jox63C|*oc+FV=2y_W0i z5^tv-pmv2SUz%p-(*`@>o|=G~iJ$FGJ9g$1|3VxLZ@EgtDF86Pp!Gf5J8&QO(yC33=WkN-d-fz$K>j}SR; zS#6i+Z6aI^C1|@_cX29SoNvo_AVsHNwu}8@7b`v>=vj>{bk_(QO{W$#Jxe-VSLp+y zuZ012fWTw$8sFW)ms^@5ZT4V0ZJCo+EjGg33H7Ytcdm;`sB7C`8AV*%`rFns`-G*k zuCnidT2DJ_trW`IgytM){w0&Tu8)z&lix2TNrahm%9_)4eN`C7mY2V*r+RbnDmwFd z3mvr4zgv75;jd}FJMl`o`RLE{(xeKci=?XPx@8=yS`x?~l+rA+YExH^beHiG?GmFM zyB4Y;Zkg4iyqVN(L?e7FmtuAz-eUu!O1H&bWMTL}Ke8O$1|G0GJ)4MXjg z)a9c&Y5I{Fo>x!G*BFcULwT^QSi9%8W)a|jlQb6Y4K83>%mw`gt@(`143Gn?m8icQ z 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

&93x-sa>C{NP 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
2{R%Fmzj@O$<;D&444OK%0>0#qESY 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 &Km%hgJ;AoRPJ-iP~{9zjJi6Gb&dl)6Ou@ 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 Date: Wed, 31 May 2023 11:23:09 +1000 Subject: [PATCH 0103/1353] target/ppc: gdbstub init spr gdb_id for all CPUs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make sure each CPU gets its state set up for gdb, not just the ones before PowerPCCPUClass has had its gdb state set up. Signed-off-by: Nicholas Piggin Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Cédric Le Goater --- target/ppc/gdbstub.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/target/ppc/gdbstub.c b/target/ppc/gdbstub.c index 63c9abe4f1..ca39efdc35 100644 --- a/target/ppc/gdbstub.c +++ b/target/ppc/gdbstub.c @@ -327,6 +327,25 @@ void ppc_gdb_gen_spr_xml(PowerPCCPU *cpu) unsigned int num_regs = 0; int i; + for (i = 0; i < ARRAY_SIZE(env->spr_cb); i++) { + ppc_spr_t *spr = &env->spr_cb[i]; + + if (!spr->name) { + continue; + } + + /* + * GDB identifies registers based on the order they are + * presented in the XML. These ids will not match QEMU's + * representation (which follows the PowerISA). + * + * Store the position of the current register description so + * we can make the correspondence later. + */ + spr->gdb_id = num_regs; + num_regs++; + } + if (pcc->gdb_spr_xml) { return; } @@ -348,17 +367,6 @@ void ppc_gdb_gen_spr_xml(PowerPCCPU *cpu) g_string_append_printf(xml, " bitsize=\"%d\"", TARGET_LONG_BITS); g_string_append(xml, " group=\"spr\"/>"); - - /* - * GDB identifies registers based on the order they are - * presented in the XML. These ids will not match QEMU's - * representation (which follows the PowerISA). - * - * Store the position of the current register description so - * we can make the correspondence later. - */ - spr->gdb_id = num_regs; - num_regs++; } g_string_append(xml, ""); From b08e8a837ec91fc8dd84aa487876b9f244fc2677 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Tue, 20 Jun 2023 09:06:36 +0930 Subject: [PATCH 0104/1353] ppc/pnv/pci: Clean up error messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The phb error macros add a newline for you, so remove the second one to avoid double whitespace. Signed-off-by: Joel Stanley Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Cédric Le Goater Signed-off-by: Cédric Le Goater --- hw/pci-host/pnv_phb4.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c index 542f9e2932..6232cbeee1 100644 --- a/hw/pci-host/pnv_phb4.c +++ b/hw/pci-host/pnv_phb4.c @@ -133,13 +133,13 @@ static void pnv_phb4_rc_config_write(PnvPHB4 *phb, unsigned off, PCIDevice *pdev; if (size != 4) { - phb_error(phb, "rc_config_write invalid size %d\n", size); + phb_error(phb, "rc_config_write invalid size %d", size); return; } pdev = pci_find_device(pci->bus, 0, 0); if (!pdev) { - phb_error(phb, "rc_config_write device not found\n"); + phb_error(phb, "rc_config_write device not found"); return; } @@ -155,13 +155,13 @@ static uint64_t pnv_phb4_rc_config_read(PnvPHB4 *phb, unsigned off, uint64_t val; if (size != 4) { - phb_error(phb, "rc_config_read invalid size %d\n", size); + phb_error(phb, "rc_config_read invalid size %d", size); return ~0ull; } pdev = pci_find_device(pci->bus, 0, 0); if (!pdev) { - phb_error(phb, "rc_config_read device not found\n"); + phb_error(phb, "rc_config_read device not found"); return ~0ull; } @@ -1039,19 +1039,19 @@ static void pnv_pec_stk_nest_xscom_write(void *opaque, hwaddr addr, if (phb->nest_regs[PEC_NEST_STK_BAR_EN] & (PEC_NEST_STK_BAR_EN_MMIO0 | PEC_NEST_STK_BAR_EN_MMIO1)) { - phb_pec_error(pec, "Changing enabled BAR unsupported\n"); + phb_pec_error(pec, "Changing enabled BAR unsupported"); } phb->nest_regs[reg] = val & 0xffffffffff000000ull; break; case PEC_NEST_STK_PHB_REGS_BAR: if (phb->nest_regs[PEC_NEST_STK_BAR_EN] & PEC_NEST_STK_BAR_EN_PHB) { - phb_pec_error(pec, "Changing enabled BAR unsupported\n"); + phb_pec_error(pec, "Changing enabled BAR unsupported"); } phb->nest_regs[reg] = val & 0xffffffffffc00000ull; break; case PEC_NEST_STK_INT_BAR: if (phb->nest_regs[PEC_NEST_STK_BAR_EN] & PEC_NEST_STK_BAR_EN_INT) { - phb_pec_error(pec, "Changing enabled BAR unsupported\n"); + phb_pec_error(pec, "Changing enabled BAR unsupported"); } phb->nest_regs[reg] = val & 0xfffffff000000000ull; break; From 602b88ec8a204cc44821217c0ceff5a395cf820b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Tue, 20 Jun 2023 07:59:03 +0200 Subject: [PATCH 0105/1353] MAINTAINERS: Add reviewers for PowerNV baremetal emulation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fred and Nick have been hacking baremetal POWER systems (OPAL) for many years. They use and modify the QEMU models regularly. Add them as PowerNV reviewers. Cc: Frédéric Barrat Cc: Nicholas Piggin Signed-off-by: Cédric Le Goater Acked-by: Frederic Barrat Reviewed-by: Richard Henderson Reviewed-by: Nicholas Piggin Signed-off-by: Cédric Le Goater --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 7f323cd2eb..06c746370c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1451,6 +1451,8 @@ F: tests/avocado/ppc_pseries.py PowerNV (Non-Virtualized) M: Cédric Le Goater +R: Frédéric Barrat +R: Nicholas Piggin L: qemu-ppc@nongnu.org S: Odd Fixes F: docs/system/ppc/powernv.rst From 58fc20f0e384177e78346630cdf8c72f538d167e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Tue, 20 Jun 2023 07:59:04 +0200 Subject: [PATCH 0106/1353] MAINTAINERS: Add reviewer for PowerPC TCG CPUs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nick has great knowledge of the PowerPC CPUs, software and hardware. Add him as a reviewer on CPU TCG modeling. Cc: Nicholas Piggin Signed-off-by: Cédric Le Goater Reviewed-by: Richard Henderson Reviewed-by: Nicholas Piggin Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Cédric Le Goater --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 06c746370c..eeb071efdb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -302,6 +302,7 @@ M: Daniel Henrique Barboza R: Cédric Le Goater R: David Gibson R: Greg Kurz +R: Nicholas Piggin L: qemu-ppc@nongnu.org S: Odd Fixes F: target/ppc/ From 4901a34d26a686d41647d34b04a4e0c6ea81bd6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Tue, 20 Jun 2023 07:59:05 +0200 Subject: [PATCH 0107/1353] MAINTAINERS: Add reviewer for XIVE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fred discusses frequently with the IBM HW designers, he is fluent in XIVE logic, add him as a reviewer. Cc: Frédéric Barrat Signed-off-by: Cédric Le Goater Acked-by: Frederic Barrat Reviewed-by: Richard Henderson Signed-off-by: Cédric Le Goater --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index eeb071efdb..e07746ac7d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2448,6 +2448,7 @@ T: git https://github.com/philmd/qemu.git fw_cfg-next XIVE M: Cédric Le Goater +R: Frédéric Barrat L: qemu-ppc@nongnu.org S: Odd Fixes F: hw/*/*xive* From 9df480db3bb89152821a74b28c8fb385956702a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Tue, 20 Jun 2023 07:59:06 +0200 Subject: [PATCH 0108/1353] ppc/prep: Report an error when run with KVM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 'prep' machine never supported KVM. This piece of code was probably inherited from another model. Cc: Hervé Poussineau Signed-off-by: Cédric Le Goater Reviewed-by: Richard Henderson Signed-off-by: Cédric Le Goater --- hw/ppc/prep.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c index 33bf232f8b..d9231c7317 100644 --- a/hw/ppc/prep.c +++ b/hw/ppc/prep.c @@ -45,7 +45,6 @@ #include "trace.h" #include "elf.h" #include "qemu/units.h" -#include "kvm_ppc.h" /* SMP is not enabled, for now */ #define MAX_CPUS 1 @@ -245,6 +244,12 @@ static void ibm_40p_init(MachineState *machine) long kernel_size = 0, initrd_size = 0; char boot_device; + if (kvm_enabled()) { + error_report("machine %s does not support the KVM accelerator", + MACHINE_GET_CLASS(machine)->name); + exit(EXIT_FAILURE); + } + /* init CPU */ cpu = POWERPC_CPU(cpu_create(machine->cpu_type)); env = &cpu->env; @@ -392,18 +397,7 @@ static void ibm_40p_init(MachineState *machine) fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_HEIGHT, graphic_height); fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_DEPTH, graphic_depth); - fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_IS_KVM, kvm_enabled()); - if (kvm_enabled()) { - uint8_t *hypercall; - - fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, kvmppc_get_tbfreq()); - hypercall = g_malloc(16); - kvmppc_get_hypercall(env, hypercall, 16); - fw_cfg_add_bytes(fw_cfg, FW_CFG_PPC_KVM_HC, hypercall, 16); - fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_KVM_PID, getpid()); - } else { - fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, NANOSECONDS_PER_SECOND); - } + fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, NANOSECONDS_PER_SECOND); fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, boot_device); qemu_register_boot_set(fw_cfg_boot_set, fw_cfg); From 74b2fd630761b3e3fe39a5314fcec04829060502 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Tue, 20 Jun 2023 07:59:09 +0200 Subject: [PATCH 0109/1353] ppc/bamboo: Report an error when run with KVM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 'bamboo' machine was used as a KVM platform in the early days (~2008). It clearly doesn't support it anymore. Signed-off-by: Cédric Le Goater Reviewed-by: Richard Henderson Signed-off-by: Cédric Le Goater --- hw/ppc/ppc440_bamboo.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/hw/ppc/ppc440_bamboo.c b/hw/ppc/ppc440_bamboo.c index f969fa3c29..f061b8cf3b 100644 --- a/hw/ppc/ppc440_bamboo.c +++ b/hw/ppc/ppc440_bamboo.c @@ -19,7 +19,6 @@ #include "hw/pci/pci.h" #include "hw/boards.h" #include "sysemu/kvm.h" -#include "kvm_ppc.h" #include "sysemu/device_tree.h" #include "hw/loader.h" #include "elf.h" @@ -97,16 +96,6 @@ static int bamboo_load_device_tree(MachineState *machine, fprintf(stderr, "couldn't set /chosen/bootargs\n"); } - /* - * Copy data from the host device tree into the guest. Since the guest can - * directly access the timebase without host involvement, we must expose - * the correct frequencies. - */ - if (kvm_enabled()) { - tb_freq = kvmppc_get_tbfreq(); - clock_freq = kvmppc_get_clockfreq(); - } - qemu_fdt_setprop_cell(fdt, "/cpus/cpu@0", "clock-frequency", clock_freq); qemu_fdt_setprop_cell(fdt, "/cpus/cpu@0", "timebase-frequency", @@ -175,6 +164,12 @@ static void bamboo_init(MachineState *machine) int success; int i; + if (kvm_enabled()) { + error_report("machine %s does not support the KVM accelerator", + MACHINE_GET_CLASS(machine)->name); + exit(EXIT_FAILURE); + } + cpu = POWERPC_CPU(cpu_create(machine->cpu_type)); env = &cpu->env; From 518f72ec4bb395647921d5091d85c7335c3968ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Tue, 20 Jun 2023 07:59:10 +0200 Subject: [PATCH 0110/1353] ppc/pnv: Rephrase error when run with KVM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Cédric Le Goater Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Cédric Le Goater --- hw/ppc/pnv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 590fc64b32..fc083173f3 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -799,7 +799,8 @@ static void pnv_init(MachineState *machine) DeviceState *dev; if (kvm_enabled()) { - error_report("The powernv machine does not work with KVM acceleration"); + error_report("machine %s does not support the KVM accelerator", + mc->name); exit(EXIT_FAILURE); } From c4550e6e9824c3fb5ee980cc8c9b175b8baf3d1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Tue, 20 Jun 2023 07:59:11 +0200 Subject: [PATCH 0111/1353] target/ppc: Fix timer register accessors when !KVM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the Timer Control and Timer Status registers are modified, avoid calling the KVM backend when not available Signed-off-by: Cédric Le Goater --- target/ppc/kvm.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index a7f2de9d10..a8a935e267 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -1728,6 +1728,10 @@ int kvmppc_or_tsr_bits(PowerPCCPU *cpu, uint32_t tsr_bits) .addr = (uintptr_t) &bits, }; + if (!kvm_enabled()) { + return 0; + } + return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); } @@ -1741,6 +1745,10 @@ int kvmppc_clear_tsr_bits(PowerPCCPU *cpu, uint32_t tsr_bits) .addr = (uintptr_t) &bits, }; + if (!kvm_enabled()) { + return 0; + } + return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); } @@ -1755,6 +1763,10 @@ int kvmppc_set_tcr(PowerPCCPU *cpu) .addr = (uintptr_t) &tcr, }; + if (!kvm_enabled()) { + return 0; + } + return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); } From cb2f6c3d69ea5b5bdc37c8330266ab67db629fc5 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 20 Jun 2023 20:57:34 +1000 Subject: [PATCH 0112/1353] ppc/spapr: H_ENTER_NESTED should restore host XER ca field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix missing env->ca restore when going from L2 back to the host. Fixes: 120f738a467 ("spapr: implement nested-hv capability for the virtual hypervisor") Reviewed-by: Harsh Prateek Bora Signed-off-by: Nicholas Piggin Signed-off-by: Cédric Le Goater --- hw/ppc/spapr_hcall.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index b904755575..0582b524d1 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -1773,6 +1773,7 @@ out_restore_l1: env->cfar = spapr_cpu->nested_host_state->cfar; env->xer = spapr_cpu->nested_host_state->xer; env->so = spapr_cpu->nested_host_state->so; + env->ca = spapr_cpu->nested_host_state->ca; env->ov = spapr_cpu->nested_host_state->ov; env->ov32 = spapr_cpu->nested_host_state->ov32; env->ca32 = spapr_cpu->nested_host_state->ca32; From c709e8eacd5578f84c0dffbfe65a743a281d1d46 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 20 Jun 2023 20:57:35 +1000 Subject: [PATCH 0113/1353] ppc/spapr: Add a nested state struct MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than use a copy of CPUPPCState to store the host state while the environment has been switched to the L2, use a new struct for this purpose. Have helper functions to save and load this host state. Reviewed-by: Harsh Prateek Bora Signed-off-by: Nicholas Piggin Signed-off-by: Cédric Le Goater --- hw/ppc/spapr_hcall.c | 150 ++++++++++++++++++++++++-------- include/hw/ppc/spapr_cpu_core.h | 5 +- 2 files changed, 115 insertions(+), 40 deletions(-) diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 0582b524d1..d5b8d54692 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -1546,6 +1546,112 @@ static target_ulong h_copy_tofrom_guest(PowerPCCPU *cpu, return H_FUNCTION; } +struct nested_ppc_state { + uint64_t gpr[32]; + uint64_t lr; + uint64_t ctr; + uint64_t cfar; + uint64_t msr; + uint64_t nip; + uint32_t cr; + + uint64_t xer; + + uint64_t lpcr; + uint64_t lpidr; + uint64_t pidr; + uint64_t pcr; + uint64_t dpdes; + uint64_t hfscr; + uint64_t srr0; + uint64_t srr1; + uint64_t sprg0; + uint64_t sprg1; + uint64_t sprg2; + uint64_t sprg3; + uint64_t ppr; + + int64_t tb_offset; +}; + +static void nested_save_state(struct nested_ppc_state *save, PowerPCCPU *cpu) +{ + CPUPPCState *env = &cpu->env; + + memcpy(save->gpr, env->gpr, sizeof(save->gpr)); + + save->lr = env->lr; + save->ctr = env->ctr; + save->cfar = env->cfar; + save->msr = env->msr; + save->nip = env->nip; + + save->cr = ppc_get_cr(env); + save->xer = cpu_read_xer(env); + + save->lpcr = env->spr[SPR_LPCR]; + save->lpidr = env->spr[SPR_LPIDR]; + save->pcr = env->spr[SPR_PCR]; + save->dpdes = env->spr[SPR_DPDES]; + save->hfscr = env->spr[SPR_HFSCR]; + save->srr0 = env->spr[SPR_SRR0]; + save->srr1 = env->spr[SPR_SRR1]; + save->sprg0 = env->spr[SPR_SPRG0]; + save->sprg1 = env->spr[SPR_SPRG1]; + save->sprg2 = env->spr[SPR_SPRG2]; + save->sprg3 = env->spr[SPR_SPRG3]; + save->pidr = env->spr[SPR_BOOKS_PID]; + save->ppr = env->spr[SPR_PPR]; + + save->tb_offset = env->tb_env->tb_offset; +} + +static void nested_load_state(PowerPCCPU *cpu, struct nested_ppc_state *load) +{ + CPUState *cs = CPU(cpu); + CPUPPCState *env = &cpu->env; + + memcpy(env->gpr, load->gpr, sizeof(env->gpr)); + + env->lr = load->lr; + env->ctr = load->ctr; + env->cfar = load->cfar; + env->msr = load->msr; + env->nip = load->nip; + + ppc_set_cr(env, load->cr); + cpu_write_xer(env, load->xer); + + env->spr[SPR_LPCR] = load->lpcr; + env->spr[SPR_LPIDR] = load->lpidr; + env->spr[SPR_PCR] = load->pcr; + env->spr[SPR_DPDES] = load->dpdes; + env->spr[SPR_HFSCR] = load->hfscr; + env->spr[SPR_SRR0] = load->srr0; + env->spr[SPR_SRR1] = load->srr1; + env->spr[SPR_SPRG0] = load->sprg0; + env->spr[SPR_SPRG1] = load->sprg1; + env->spr[SPR_SPRG2] = load->sprg2; + env->spr[SPR_SPRG3] = load->sprg3; + env->spr[SPR_BOOKS_PID] = load->pidr; + env->spr[SPR_PPR] = load->ppr; + + env->tb_env->tb_offset = load->tb_offset; + + /* + * MSR updated, compute hflags and possible interrupts. + */ + hreg_compute_hflags(env); + ppc_maybe_interrupt(env); + + /* + * Nested HV does not tag TLB entries between L1 and L2, so must + * flush on transition. + */ + tlb_flush(cs); + env->reserve_addr = -1; /* Reset the reservation */ +} + /* * When this handler returns, the environment is switched to the L2 guest * and TCG begins running that. spapr_exit_nested() performs the switch from @@ -1593,12 +1699,14 @@ static target_ulong h_enter_nested(PowerPCCPU *cpu, return H_PARAMETER; } - spapr_cpu->nested_host_state = g_try_new(CPUPPCState, 1); + spapr_cpu->nested_host_state = g_try_new(struct nested_ppc_state, 1); if (!spapr_cpu->nested_host_state) { return H_NO_MEM; } - memcpy(spapr_cpu->nested_host_state, env, sizeof(CPUPPCState)); + assert(env->spr[SPR_LPIDR] == 0); + assert(env->spr[SPR_DPDES] == 0); + nested_save_state(spapr_cpu->nested_host_state, cpu); len = sizeof(*regs); regs = address_space_map(CPU(cpu)->as, regs_ptr, &len, false, @@ -1639,7 +1747,6 @@ static target_ulong h_enter_nested(PowerPCCPU *cpu, env->spr[SPR_DPDES] = hv_state.dpdes; env->spr[SPR_HFSCR] = hv_state.hfscr; hdec = hv_state.hdec_expiry - now; - spapr_cpu->nested_tb_offset = hv_state.tb_offset; /* TCG does not implement DAWR*, CIABR, PURR, SPURR, IC, VTB, HEIR SPRs*/ env->spr[SPR_SRR0] = hv_state.srr0; env->spr[SPR_SRR1] = hv_state.srr1; @@ -1665,7 +1772,7 @@ static target_ulong h_enter_nested(PowerPCCPU *cpu, * and it's not obviously worth a new data structure to do it. */ - env->tb_env->tb_offset += spapr_cpu->nested_tb_offset; + env->tb_env->tb_offset += hv_state.tb_offset; spapr_cpu->in_nested = true; hreg_compute_hflags(env); @@ -1684,7 +1791,6 @@ static target_ulong h_enter_nested(PowerPCCPU *cpu, void spapr_exit_nested(PowerPCCPU *cpu, int excp) { - CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu); target_ulong r3_return = env->excp_vectors[excp]; /* hcall return value */ @@ -1766,34 +1872,8 @@ void spapr_exit_nested(PowerPCCPU *cpu, int excp) address_space_unmap(CPU(cpu)->as, regs, len, len, true); out_restore_l1: - memcpy(env->gpr, spapr_cpu->nested_host_state->gpr, sizeof(env->gpr)); - env->lr = spapr_cpu->nested_host_state->lr; - env->ctr = spapr_cpu->nested_host_state->ctr; - memcpy(env->crf, spapr_cpu->nested_host_state->crf, sizeof(env->crf)); - env->cfar = spapr_cpu->nested_host_state->cfar; - env->xer = spapr_cpu->nested_host_state->xer; - env->so = spapr_cpu->nested_host_state->so; - env->ca = spapr_cpu->nested_host_state->ca; - env->ov = spapr_cpu->nested_host_state->ov; - env->ov32 = spapr_cpu->nested_host_state->ov32; - env->ca32 = spapr_cpu->nested_host_state->ca32; - env->msr = spapr_cpu->nested_host_state->msr; - env->nip = spapr_cpu->nested_host_state->nip; - assert(env->spr[SPR_LPIDR] != 0); - env->spr[SPR_LPCR] = spapr_cpu->nested_host_state->spr[SPR_LPCR]; - env->spr[SPR_LPIDR] = spapr_cpu->nested_host_state->spr[SPR_LPIDR]; - env->spr[SPR_PCR] = spapr_cpu->nested_host_state->spr[SPR_PCR]; - env->spr[SPR_DPDES] = 0; - env->spr[SPR_HFSCR] = spapr_cpu->nested_host_state->spr[SPR_HFSCR]; - env->spr[SPR_SRR0] = spapr_cpu->nested_host_state->spr[SPR_SRR0]; - env->spr[SPR_SRR1] = spapr_cpu->nested_host_state->spr[SPR_SRR1]; - env->spr[SPR_SPRG0] = spapr_cpu->nested_host_state->spr[SPR_SPRG0]; - env->spr[SPR_SPRG1] = spapr_cpu->nested_host_state->spr[SPR_SPRG1]; - env->spr[SPR_SPRG2] = spapr_cpu->nested_host_state->spr[SPR_SPRG2]; - env->spr[SPR_SPRG3] = spapr_cpu->nested_host_state->spr[SPR_SPRG3]; - env->spr[SPR_BOOKS_PID] = spapr_cpu->nested_host_state->spr[SPR_BOOKS_PID]; - env->spr[SPR_PPR] = spapr_cpu->nested_host_state->spr[SPR_PPR]; + nested_load_state(cpu, spapr_cpu->nested_host_state); /* * Return the interrupt vector address from H_ENTER_NESTED to the L1 @@ -1801,14 +1881,8 @@ out_restore_l1: */ env->gpr[3] = r3_return; - env->tb_env->tb_offset -= spapr_cpu->nested_tb_offset; spapr_cpu->in_nested = false; - hreg_compute_hflags(env); - ppc_maybe_interrupt(env); - tlb_flush(cs); - env->reserve_addr = -1; /* Reset the reservation */ - g_free(spapr_cpu->nested_host_state); spapr_cpu->nested_host_state = NULL; } diff --git a/include/hw/ppc/spapr_cpu_core.h b/include/hw/ppc/spapr_cpu_core.h index b560514560..69a52e39b8 100644 --- a/include/hw/ppc/spapr_cpu_core.h +++ b/include/hw/ppc/spapr_cpu_core.h @@ -41,6 +41,8 @@ void spapr_cpu_set_entry_state(PowerPCCPU *cpu, target_ulong nip, target_ulong r1, target_ulong r3, target_ulong r4); +struct nested_ppc_state; + typedef struct SpaprCpuState { uint64_t vpa_addr; uint64_t slb_shadow_addr, slb_shadow_size; @@ -51,8 +53,7 @@ typedef struct SpaprCpuState { /* Fields for nested-HV support */ bool in_nested; /* true while the L2 is executing */ - CPUPPCState *nested_host_state; /* holds the L1 state while L2 executes */ - int64_t nested_tb_offset; /* L1->L2 TB offset */ + struct nested_ppc_state *nested_host_state; /* holds the L1 state while L2 executes */ } SpaprCpuState; static inline SpaprCpuState *spapr_cpu_state(PowerPCCPU *cpu) From cb4e61a33b7585642a8a7ff9e5b3b78599bcc582 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 20 Jun 2023 20:57:36 +1000 Subject: [PATCH 0114/1353] ppc/spapr: load and store l2 state with helper functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Arguably this is just shuffling around register accesses, but one nice thing it does is allow the exit to save away the L2 state then switch the environment to the L1 before copying L2 data back to the L1, which logically flows more naturally and simplifies the error paths. Reviewed-by: Harsh Prateek Bora Signed-off-by: Nicholas Piggin Signed-off-by: Cédric Le Goater --- hw/ppc/spapr_hcall.c | 164 ++++++++++++++++++++++--------------------- 1 file changed, 85 insertions(+), 79 deletions(-) diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index d5b8d54692..54ad83a3e6 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -1663,9 +1663,9 @@ static target_ulong h_enter_nested(PowerPCCPU *cpu, target_ulong *args) { PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); - CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu); + struct nested_ppc_state l2_state; target_ulong hv_ptr = args[0]; target_ulong regs_ptr = args[1]; target_ulong hdec, now = cpu_ppc_load_tbl(env); @@ -1699,6 +1699,10 @@ static target_ulong h_enter_nested(PowerPCCPU *cpu, return H_PARAMETER; } + if (hv_state.lpid == 0) { + return H_PARAMETER; + } + spapr_cpu->nested_host_state = g_try_new(struct nested_ppc_state, 1); if (!spapr_cpu->nested_host_state) { return H_NO_MEM; @@ -1717,46 +1721,49 @@ static target_ulong h_enter_nested(PowerPCCPU *cpu, return H_P2; } - len = sizeof(env->gpr); + len = sizeof(l2_state.gpr); assert(len == sizeof(regs->gpr)); - memcpy(env->gpr, regs->gpr, len); + memcpy(l2_state.gpr, regs->gpr, len); - env->lr = regs->link; - env->ctr = regs->ctr; - cpu_write_xer(env, regs->xer); - ppc_set_cr(env, regs->ccr); - - env->msr = regs->msr; - env->nip = regs->nip; + l2_state.lr = regs->link; + l2_state.ctr = regs->ctr; + l2_state.xer = regs->xer; + l2_state.cr = regs->ccr; + l2_state.msr = regs->msr; + l2_state.nip = regs->nip; address_space_unmap(CPU(cpu)->as, regs, len, len, false); - env->cfar = hv_state.cfar; - - assert(env->spr[SPR_LPIDR] == 0); - env->spr[SPR_LPIDR] = hv_state.lpid; + l2_state.cfar = hv_state.cfar; + l2_state.lpidr = hv_state.lpid; lpcr_mask = LPCR_DPFD | LPCR_ILE | LPCR_AIL | LPCR_LD | LPCR_MER; lpcr = (env->spr[SPR_LPCR] & ~lpcr_mask) | (hv_state.lpcr & lpcr_mask); lpcr |= LPCR_HR | LPCR_UPRT | LPCR_GTSE | LPCR_HVICE | LPCR_HDICE; lpcr &= ~LPCR_LPES0; - env->spr[SPR_LPCR] = lpcr & pcc->lpcr_mask; + l2_state.lpcr = lpcr & pcc->lpcr_mask; - env->spr[SPR_PCR] = hv_state.pcr; + l2_state.pcr = hv_state.pcr; /* hv_state.amor is not used */ - env->spr[SPR_DPDES] = hv_state.dpdes; - env->spr[SPR_HFSCR] = hv_state.hfscr; - hdec = hv_state.hdec_expiry - now; + l2_state.dpdes = hv_state.dpdes; + l2_state.hfscr = hv_state.hfscr; /* TCG does not implement DAWR*, CIABR, PURR, SPURR, IC, VTB, HEIR SPRs*/ - env->spr[SPR_SRR0] = hv_state.srr0; - env->spr[SPR_SRR1] = hv_state.srr1; - env->spr[SPR_SPRG0] = hv_state.sprg[0]; - env->spr[SPR_SPRG1] = hv_state.sprg[1]; - env->spr[SPR_SPRG2] = hv_state.sprg[2]; - env->spr[SPR_SPRG3] = hv_state.sprg[3]; - env->spr[SPR_BOOKS_PID] = hv_state.pidr; - env->spr[SPR_PPR] = hv_state.ppr; + l2_state.srr0 = hv_state.srr0; + l2_state.srr1 = hv_state.srr1; + l2_state.sprg0 = hv_state.sprg[0]; + l2_state.sprg1 = hv_state.sprg[1]; + l2_state.sprg2 = hv_state.sprg[2]; + l2_state.sprg3 = hv_state.sprg[3]; + l2_state.pidr = hv_state.pidr; + l2_state.ppr = hv_state.ppr; + l2_state.tb_offset = env->tb_env->tb_offset + hv_state.tb_offset; + /* + * Switch to the nested guest environment and start the "hdec" timer. + */ + nested_load_state(cpu, &l2_state); + + hdec = hv_state.hdec_expiry - now; cpu_ppc_hdecr_init(env); cpu_ppc_store_hdecr(env, hdec); @@ -1772,14 +1779,8 @@ static target_ulong h_enter_nested(PowerPCCPU *cpu, * and it's not obviously worth a new data structure to do it. */ - env->tb_env->tb_offset += hv_state.tb_offset; spapr_cpu->in_nested = true; - hreg_compute_hflags(env); - ppc_maybe_interrupt(env); - tlb_flush(cs); - env->reserve_addr = -1; /* Reset the reservation */ - /* * The spapr hcall helper sets env->gpr[3] to the return value, but at * this point the L1 is not returning from the hcall but rather we @@ -1793,49 +1794,69 @@ void spapr_exit_nested(PowerPCCPU *cpu, int excp) { CPUPPCState *env = &cpu->env; SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu); - target_ulong r3_return = env->excp_vectors[excp]; /* hcall return value */ + struct nested_ppc_state l2_state; target_ulong hv_ptr = spapr_cpu->nested_host_state->gpr[4]; target_ulong regs_ptr = spapr_cpu->nested_host_state->gpr[5]; + target_ulong hsrr0, hsrr1, hdar, asdr, hdsisr; struct kvmppc_hv_guest_state *hvstate; struct kvmppc_pt_regs *regs; hwaddr len; assert(spapr_cpu->in_nested); + nested_save_state(&l2_state, cpu); + hsrr0 = env->spr[SPR_HSRR0]; + hsrr1 = env->spr[SPR_HSRR1]; + hdar = env->spr[SPR_HDAR]; + hdsisr = env->spr[SPR_HDSISR]; + asdr = env->spr[SPR_ASDR]; + + /* + * Switch back to the host environment (including for any error). + */ + assert(env->spr[SPR_LPIDR] != 0); + nested_load_state(cpu, spapr_cpu->nested_host_state); + env->gpr[3] = env->excp_vectors[excp]; /* hcall return value */ + cpu_ppc_hdecr_exit(env); + spapr_cpu->in_nested = false; + + g_free(spapr_cpu->nested_host_state); + spapr_cpu->nested_host_state = NULL; + len = sizeof(*hvstate); hvstate = address_space_map(CPU(cpu)->as, hv_ptr, &len, true, MEMTXATTRS_UNSPECIFIED); if (len != sizeof(*hvstate)) { address_space_unmap(CPU(cpu)->as, hvstate, len, 0, true); - r3_return = H_PARAMETER; - goto out_restore_l1; + env->gpr[3] = H_PARAMETER; + return; } - hvstate->cfar = env->cfar; - hvstate->lpcr = env->spr[SPR_LPCR]; - hvstate->pcr = env->spr[SPR_PCR]; - hvstate->dpdes = env->spr[SPR_DPDES]; - hvstate->hfscr = env->spr[SPR_HFSCR]; + hvstate->cfar = l2_state.cfar; + hvstate->lpcr = l2_state.lpcr; + hvstate->pcr = l2_state.pcr; + hvstate->dpdes = l2_state.dpdes; + hvstate->hfscr = l2_state.hfscr; if (excp == POWERPC_EXCP_HDSI) { - hvstate->hdar = env->spr[SPR_HDAR]; - hvstate->hdsisr = env->spr[SPR_HDSISR]; - hvstate->asdr = env->spr[SPR_ASDR]; + hvstate->hdar = hdar; + hvstate->hdsisr = hdsisr; + hvstate->asdr = asdr; } else if (excp == POWERPC_EXCP_HISI) { - hvstate->asdr = env->spr[SPR_ASDR]; + hvstate->asdr = asdr; } /* HEIR should be implemented for HV mode and saved here. */ - hvstate->srr0 = env->spr[SPR_SRR0]; - hvstate->srr1 = env->spr[SPR_SRR1]; - hvstate->sprg[0] = env->spr[SPR_SPRG0]; - hvstate->sprg[1] = env->spr[SPR_SPRG1]; - hvstate->sprg[2] = env->spr[SPR_SPRG2]; - hvstate->sprg[3] = env->spr[SPR_SPRG3]; - hvstate->pidr = env->spr[SPR_BOOKS_PID]; - hvstate->ppr = env->spr[SPR_PPR]; + hvstate->srr0 = l2_state.srr0; + hvstate->srr1 = l2_state.srr1; + hvstate->sprg[0] = l2_state.sprg0; + hvstate->sprg[1] = l2_state.sprg1; + hvstate->sprg[2] = l2_state.sprg2; + hvstate->sprg[3] = l2_state.sprg3; + hvstate->pidr = l2_state.pidr; + hvstate->ppr = l2_state.ppr; /* Is it okay to specify write length larger than actual data written? */ address_space_unmap(CPU(cpu)->as, hvstate, len, len, true); @@ -1845,46 +1866,31 @@ void spapr_exit_nested(PowerPCCPU *cpu, int excp) MEMTXATTRS_UNSPECIFIED); if (!regs || len != sizeof(*regs)) { address_space_unmap(CPU(cpu)->as, regs, len, 0, true); - r3_return = H_P2; - goto out_restore_l1; + env->gpr[3] = H_P2; + return; } len = sizeof(env->gpr); assert(len == sizeof(regs->gpr)); - memcpy(regs->gpr, env->gpr, len); + memcpy(regs->gpr, l2_state.gpr, len); - regs->link = env->lr; - regs->ctr = env->ctr; - regs->xer = cpu_read_xer(env); - regs->ccr = ppc_get_cr(env); + regs->link = l2_state.lr; + regs->ctr = l2_state.ctr; + regs->xer = l2_state.xer; + regs->ccr = l2_state.cr; if (excp == POWERPC_EXCP_MCHECK || excp == POWERPC_EXCP_RESET || excp == POWERPC_EXCP_SYSCALL) { - regs->nip = env->spr[SPR_SRR0]; - regs->msr = env->spr[SPR_SRR1] & env->msr_mask; + regs->nip = l2_state.srr0; + regs->msr = l2_state.srr1 & env->msr_mask; } else { - regs->nip = env->spr[SPR_HSRR0]; - regs->msr = env->spr[SPR_HSRR1] & env->msr_mask; + regs->nip = hsrr0; + regs->msr = hsrr1 & env->msr_mask; } /* Is it okay to specify write length larger than actual data written? */ address_space_unmap(CPU(cpu)->as, regs, len, len, true); - -out_restore_l1: - assert(env->spr[SPR_LPIDR] != 0); - nested_load_state(cpu, spapr_cpu->nested_host_state); - - /* - * Return the interrupt vector address from H_ENTER_NESTED to the L1 - * (or error code). - */ - env->gpr[3] = r3_return; - - spapr_cpu->in_nested = false; - - g_free(spapr_cpu->nested_host_state); - spapr_cpu->nested_host_state = NULL; } static void hypercall_register_nested(void) From 6b8a05373bf142fe5fd3839c3675da005bfc9b49 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 20 Jun 2023 20:57:37 +1000 Subject: [PATCH 0115/1353] ppc/spapr: Move spapr nested HV to a new file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create spapr_nested.c for most of the nested HV implementation. Signed-off-by: Nicholas Piggin Reviewed-by: Harsh Prateek Bora Signed-off-by: Cédric Le Goater --- hw/ppc/meson.build | 1 + hw/ppc/spapr.c | 1 + hw/ppc/spapr_hcall.c | 416 +--------------------------------- hw/ppc/spapr_nested.c | 395 ++++++++++++++++++++++++++++++++ include/hw/ppc/spapr.h | 62 ----- include/hw/ppc/spapr_nested.h | 102 +++++++++ 6 files changed, 501 insertions(+), 476 deletions(-) create mode 100644 hw/ppc/spapr_nested.c create mode 100644 include/hw/ppc/spapr_nested.h diff --git a/hw/ppc/meson.build b/hw/ppc/meson.build index c927337da0..a313d4b964 100644 --- a/hw/ppc/meson.build +++ b/hw/ppc/meson.build @@ -15,6 +15,7 @@ ppc_ss.add(when: 'CONFIG_PSERIES', if_true: files( 'spapr_vio.c', 'spapr_events.c', 'spapr_hcall.c', + 'spapr_nested.c', 'spapr_iommu.c', 'spapr_rtas.c', 'spapr_pci.c', diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index dcb7f1c70a..e55905a1f0 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -61,6 +61,7 @@ #include "hw/ppc/fdt.h" #include "hw/ppc/spapr.h" +#include "hw/ppc/spapr_nested.h" #include "hw/ppc/spapr_vio.h" #include "hw/ppc/vof.h" #include "hw/qdev-properties.h" diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 54ad83a3e6..002ea0b7c1 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -13,6 +13,7 @@ #include "hw/ppc/ppc.h" #include "hw/ppc/spapr.h" #include "hw/ppc/spapr_cpu_core.h" +#include "hw/ppc/spapr_nested.h" #include "mmu-hash64.h" #include "cpu-models.h" #include "trace.h" @@ -1498,430 +1499,17 @@ target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode, } #ifdef CONFIG_TCG -#define PRTS_MASK 0x1f - -static target_ulong h_set_ptbl(PowerPCCPU *cpu, - SpaprMachineState *spapr, - target_ulong opcode, - target_ulong *args) -{ - target_ulong ptcr = args[0]; - - if (!spapr_get_cap(spapr, SPAPR_CAP_NESTED_KVM_HV)) { - return H_FUNCTION; - } - - if ((ptcr & PRTS_MASK) + 12 - 4 > 12) { - return H_PARAMETER; - } - - spapr->nested_ptcr = ptcr; /* Save new partition table */ - - return H_SUCCESS; -} - -static target_ulong h_tlb_invalidate(PowerPCCPU *cpu, - SpaprMachineState *spapr, - target_ulong opcode, - target_ulong *args) -{ - /* - * The spapr virtual hypervisor nested HV implementation retains no L2 - * translation state except for TLB. And the TLB is always invalidated - * across L1<->L2 transitions, so nothing is required here. - */ - - return H_SUCCESS; -} - -static target_ulong h_copy_tofrom_guest(PowerPCCPU *cpu, - SpaprMachineState *spapr, - target_ulong opcode, - target_ulong *args) -{ - /* - * This HCALL is not required, L1 KVM will take a slow path and walk the - * page tables manually to do the data copy. - */ - return H_FUNCTION; -} - -struct nested_ppc_state { - uint64_t gpr[32]; - uint64_t lr; - uint64_t ctr; - uint64_t cfar; - uint64_t msr; - uint64_t nip; - uint32_t cr; - - uint64_t xer; - - uint64_t lpcr; - uint64_t lpidr; - uint64_t pidr; - uint64_t pcr; - uint64_t dpdes; - uint64_t hfscr; - uint64_t srr0; - uint64_t srr1; - uint64_t sprg0; - uint64_t sprg1; - uint64_t sprg2; - uint64_t sprg3; - uint64_t ppr; - - int64_t tb_offset; -}; - -static void nested_save_state(struct nested_ppc_state *save, PowerPCCPU *cpu) -{ - CPUPPCState *env = &cpu->env; - - memcpy(save->gpr, env->gpr, sizeof(save->gpr)); - - save->lr = env->lr; - save->ctr = env->ctr; - save->cfar = env->cfar; - save->msr = env->msr; - save->nip = env->nip; - - save->cr = ppc_get_cr(env); - save->xer = cpu_read_xer(env); - - save->lpcr = env->spr[SPR_LPCR]; - save->lpidr = env->spr[SPR_LPIDR]; - save->pcr = env->spr[SPR_PCR]; - save->dpdes = env->spr[SPR_DPDES]; - save->hfscr = env->spr[SPR_HFSCR]; - save->srr0 = env->spr[SPR_SRR0]; - save->srr1 = env->spr[SPR_SRR1]; - save->sprg0 = env->spr[SPR_SPRG0]; - save->sprg1 = env->spr[SPR_SPRG1]; - save->sprg2 = env->spr[SPR_SPRG2]; - save->sprg3 = env->spr[SPR_SPRG3]; - save->pidr = env->spr[SPR_BOOKS_PID]; - save->ppr = env->spr[SPR_PPR]; - - save->tb_offset = env->tb_env->tb_offset; -} - -static void nested_load_state(PowerPCCPU *cpu, struct nested_ppc_state *load) -{ - CPUState *cs = CPU(cpu); - CPUPPCState *env = &cpu->env; - - memcpy(env->gpr, load->gpr, sizeof(env->gpr)); - - env->lr = load->lr; - env->ctr = load->ctr; - env->cfar = load->cfar; - env->msr = load->msr; - env->nip = load->nip; - - ppc_set_cr(env, load->cr); - cpu_write_xer(env, load->xer); - - env->spr[SPR_LPCR] = load->lpcr; - env->spr[SPR_LPIDR] = load->lpidr; - env->spr[SPR_PCR] = load->pcr; - env->spr[SPR_DPDES] = load->dpdes; - env->spr[SPR_HFSCR] = load->hfscr; - env->spr[SPR_SRR0] = load->srr0; - env->spr[SPR_SRR1] = load->srr1; - env->spr[SPR_SPRG0] = load->sprg0; - env->spr[SPR_SPRG1] = load->sprg1; - env->spr[SPR_SPRG2] = load->sprg2; - env->spr[SPR_SPRG3] = load->sprg3; - env->spr[SPR_BOOKS_PID] = load->pidr; - env->spr[SPR_PPR] = load->ppr; - - env->tb_env->tb_offset = load->tb_offset; - - /* - * MSR updated, compute hflags and possible interrupts. - */ - hreg_compute_hflags(env); - ppc_maybe_interrupt(env); - - /* - * Nested HV does not tag TLB entries between L1 and L2, so must - * flush on transition. - */ - tlb_flush(cs); - env->reserve_addr = -1; /* Reset the reservation */ -} - -/* - * When this handler returns, the environment is switched to the L2 guest - * and TCG begins running that. spapr_exit_nested() performs the switch from - * L2 back to L1 and returns from the H_ENTER_NESTED hcall. - */ -static target_ulong h_enter_nested(PowerPCCPU *cpu, - SpaprMachineState *spapr, - target_ulong opcode, - target_ulong *args) -{ - PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); - CPUPPCState *env = &cpu->env; - SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu); - struct nested_ppc_state l2_state; - target_ulong hv_ptr = args[0]; - target_ulong regs_ptr = args[1]; - target_ulong hdec, now = cpu_ppc_load_tbl(env); - target_ulong lpcr, lpcr_mask; - struct kvmppc_hv_guest_state *hvstate; - struct kvmppc_hv_guest_state hv_state; - struct kvmppc_pt_regs *regs; - hwaddr len; - - if (spapr->nested_ptcr == 0) { - return H_NOT_AVAILABLE; - } - - len = sizeof(*hvstate); - hvstate = address_space_map(CPU(cpu)->as, hv_ptr, &len, false, - MEMTXATTRS_UNSPECIFIED); - if (len != sizeof(*hvstate)) { - address_space_unmap(CPU(cpu)->as, hvstate, len, 0, false); - return H_PARAMETER; - } - - memcpy(&hv_state, hvstate, len); - - address_space_unmap(CPU(cpu)->as, hvstate, len, len, false); - - /* - * We accept versions 1 and 2. Version 2 fields are unused because TCG - * does not implement DAWR*. - */ - if (hv_state.version > HV_GUEST_STATE_VERSION) { - return H_PARAMETER; - } - - if (hv_state.lpid == 0) { - return H_PARAMETER; - } - - spapr_cpu->nested_host_state = g_try_new(struct nested_ppc_state, 1); - if (!spapr_cpu->nested_host_state) { - return H_NO_MEM; - } - - assert(env->spr[SPR_LPIDR] == 0); - assert(env->spr[SPR_DPDES] == 0); - nested_save_state(spapr_cpu->nested_host_state, cpu); - - len = sizeof(*regs); - regs = address_space_map(CPU(cpu)->as, regs_ptr, &len, false, - MEMTXATTRS_UNSPECIFIED); - if (!regs || len != sizeof(*regs)) { - address_space_unmap(CPU(cpu)->as, regs, len, 0, false); - g_free(spapr_cpu->nested_host_state); - return H_P2; - } - - len = sizeof(l2_state.gpr); - assert(len == sizeof(regs->gpr)); - memcpy(l2_state.gpr, regs->gpr, len); - - l2_state.lr = regs->link; - l2_state.ctr = regs->ctr; - l2_state.xer = regs->xer; - l2_state.cr = regs->ccr; - l2_state.msr = regs->msr; - l2_state.nip = regs->nip; - - address_space_unmap(CPU(cpu)->as, regs, len, len, false); - - l2_state.cfar = hv_state.cfar; - l2_state.lpidr = hv_state.lpid; - - lpcr_mask = LPCR_DPFD | LPCR_ILE | LPCR_AIL | LPCR_LD | LPCR_MER; - lpcr = (env->spr[SPR_LPCR] & ~lpcr_mask) | (hv_state.lpcr & lpcr_mask); - lpcr |= LPCR_HR | LPCR_UPRT | LPCR_GTSE | LPCR_HVICE | LPCR_HDICE; - lpcr &= ~LPCR_LPES0; - l2_state.lpcr = lpcr & pcc->lpcr_mask; - - l2_state.pcr = hv_state.pcr; - /* hv_state.amor is not used */ - l2_state.dpdes = hv_state.dpdes; - l2_state.hfscr = hv_state.hfscr; - /* TCG does not implement DAWR*, CIABR, PURR, SPURR, IC, VTB, HEIR SPRs*/ - l2_state.srr0 = hv_state.srr0; - l2_state.srr1 = hv_state.srr1; - l2_state.sprg0 = hv_state.sprg[0]; - l2_state.sprg1 = hv_state.sprg[1]; - l2_state.sprg2 = hv_state.sprg[2]; - l2_state.sprg3 = hv_state.sprg[3]; - l2_state.pidr = hv_state.pidr; - l2_state.ppr = hv_state.ppr; - l2_state.tb_offset = env->tb_env->tb_offset + hv_state.tb_offset; - - /* - * Switch to the nested guest environment and start the "hdec" timer. - */ - nested_load_state(cpu, &l2_state); - - hdec = hv_state.hdec_expiry - now; - cpu_ppc_hdecr_init(env); - cpu_ppc_store_hdecr(env, hdec); - - /* - * The hv_state.vcpu_token is not needed. It is used by the KVM - * implementation to remember which L2 vCPU last ran on which physical - * CPU so as to invalidate process scope translations if it is moved - * between physical CPUs. For now TLBs are always flushed on L1<->L2 - * transitions so this is not a problem. - * - * Could validate that the same vcpu_token does not attempt to run on - * different L1 vCPUs at the same time, but that would be a L1 KVM bug - * and it's not obviously worth a new data structure to do it. - */ - - spapr_cpu->in_nested = true; - - /* - * The spapr hcall helper sets env->gpr[3] to the return value, but at - * this point the L1 is not returning from the hcall but rather we - * start running the L2, so r3 must not be clobbered, so return env->gpr[3] - * to leave it unchanged. - */ - return env->gpr[3]; -} - -void spapr_exit_nested(PowerPCCPU *cpu, int excp) -{ - CPUPPCState *env = &cpu->env; - SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu); - struct nested_ppc_state l2_state; - target_ulong hv_ptr = spapr_cpu->nested_host_state->gpr[4]; - target_ulong regs_ptr = spapr_cpu->nested_host_state->gpr[5]; - target_ulong hsrr0, hsrr1, hdar, asdr, hdsisr; - struct kvmppc_hv_guest_state *hvstate; - struct kvmppc_pt_regs *regs; - hwaddr len; - - assert(spapr_cpu->in_nested); - - nested_save_state(&l2_state, cpu); - hsrr0 = env->spr[SPR_HSRR0]; - hsrr1 = env->spr[SPR_HSRR1]; - hdar = env->spr[SPR_HDAR]; - hdsisr = env->spr[SPR_HDSISR]; - asdr = env->spr[SPR_ASDR]; - - /* - * Switch back to the host environment (including for any error). - */ - assert(env->spr[SPR_LPIDR] != 0); - nested_load_state(cpu, spapr_cpu->nested_host_state); - env->gpr[3] = env->excp_vectors[excp]; /* hcall return value */ - - cpu_ppc_hdecr_exit(env); - - spapr_cpu->in_nested = false; - - g_free(spapr_cpu->nested_host_state); - spapr_cpu->nested_host_state = NULL; - - len = sizeof(*hvstate); - hvstate = address_space_map(CPU(cpu)->as, hv_ptr, &len, true, - MEMTXATTRS_UNSPECIFIED); - if (len != sizeof(*hvstate)) { - address_space_unmap(CPU(cpu)->as, hvstate, len, 0, true); - env->gpr[3] = H_PARAMETER; - return; - } - - hvstate->cfar = l2_state.cfar; - hvstate->lpcr = l2_state.lpcr; - hvstate->pcr = l2_state.pcr; - hvstate->dpdes = l2_state.dpdes; - hvstate->hfscr = l2_state.hfscr; - - if (excp == POWERPC_EXCP_HDSI) { - hvstate->hdar = hdar; - hvstate->hdsisr = hdsisr; - hvstate->asdr = asdr; - } else if (excp == POWERPC_EXCP_HISI) { - hvstate->asdr = asdr; - } - - /* HEIR should be implemented for HV mode and saved here. */ - hvstate->srr0 = l2_state.srr0; - hvstate->srr1 = l2_state.srr1; - hvstate->sprg[0] = l2_state.sprg0; - hvstate->sprg[1] = l2_state.sprg1; - hvstate->sprg[2] = l2_state.sprg2; - hvstate->sprg[3] = l2_state.sprg3; - hvstate->pidr = l2_state.pidr; - hvstate->ppr = l2_state.ppr; - - /* Is it okay to specify write length larger than actual data written? */ - address_space_unmap(CPU(cpu)->as, hvstate, len, len, true); - - len = sizeof(*regs); - regs = address_space_map(CPU(cpu)->as, regs_ptr, &len, true, - MEMTXATTRS_UNSPECIFIED); - if (!regs || len != sizeof(*regs)) { - address_space_unmap(CPU(cpu)->as, regs, len, 0, true); - env->gpr[3] = H_P2; - return; - } - - len = sizeof(env->gpr); - assert(len == sizeof(regs->gpr)); - memcpy(regs->gpr, l2_state.gpr, len); - - regs->link = l2_state.lr; - regs->ctr = l2_state.ctr; - regs->xer = l2_state.xer; - regs->ccr = l2_state.cr; - - if (excp == POWERPC_EXCP_MCHECK || - excp == POWERPC_EXCP_RESET || - excp == POWERPC_EXCP_SYSCALL) { - regs->nip = l2_state.srr0; - regs->msr = l2_state.srr1 & env->msr_mask; - } else { - regs->nip = hsrr0; - regs->msr = hsrr1 & env->msr_mask; - } - - /* Is it okay to specify write length larger than actual data written? */ - address_space_unmap(CPU(cpu)->as, regs, len, len, true); -} - -static void hypercall_register_nested(void) -{ - spapr_register_hypercall(KVMPPC_H_SET_PARTITION_TABLE, h_set_ptbl); - spapr_register_hypercall(KVMPPC_H_ENTER_NESTED, h_enter_nested); - spapr_register_hypercall(KVMPPC_H_TLB_INVALIDATE, h_tlb_invalidate); - spapr_register_hypercall(KVMPPC_H_COPY_TOFROM_GUEST, h_copy_tofrom_guest); -} - static void hypercall_register_softmmu(void) { /* DO NOTHING */ } #else -void spapr_exit_nested(PowerPCCPU *cpu, int excp) -{ - g_assert_not_reached(); -} - static target_ulong h_softmmu(PowerPCCPU *cpu, SpaprMachineState *spapr, target_ulong opcode, target_ulong *args) { g_assert_not_reached(); } -static void hypercall_register_nested(void) -{ - /* DO NOTHING */ -} - static void hypercall_register_softmmu(void) { /* hcall-pft */ @@ -1991,7 +1579,7 @@ static void hypercall_register_types(void) spapr_register_hypercall(KVMPPC_H_UPDATE_DT, h_update_dt); - hypercall_register_nested(); + spapr_register_nested(); } type_init(hypercall_register_types) diff --git a/hw/ppc/spapr_nested.c b/hw/ppc/spapr_nested.c new file mode 100644 index 0000000000..121aa96ddc --- /dev/null +++ b/hw/ppc/spapr_nested.c @@ -0,0 +1,395 @@ +#include "qemu/osdep.h" +#include "qemu/cutils.h" +#include "exec/exec-all.h" +#include "helper_regs.h" +#include "hw/ppc/ppc.h" +#include "hw/ppc/spapr.h" +#include "hw/ppc/spapr_cpu_core.h" +#include "hw/ppc/spapr_nested.h" + +#ifdef CONFIG_TCG +#define PRTS_MASK 0x1f + +static target_ulong h_set_ptbl(PowerPCCPU *cpu, + SpaprMachineState *spapr, + target_ulong opcode, + target_ulong *args) +{ + target_ulong ptcr = args[0]; + + if (!spapr_get_cap(spapr, SPAPR_CAP_NESTED_KVM_HV)) { + return H_FUNCTION; + } + + if ((ptcr & PRTS_MASK) + 12 - 4 > 12) { + return H_PARAMETER; + } + + spapr->nested_ptcr = ptcr; /* Save new partition table */ + + return H_SUCCESS; +} + +static target_ulong h_tlb_invalidate(PowerPCCPU *cpu, + SpaprMachineState *spapr, + target_ulong opcode, + target_ulong *args) +{ + /* + * The spapr virtual hypervisor nested HV implementation retains no L2 + * translation state except for TLB. And the TLB is always invalidated + * across L1<->L2 transitions, so nothing is required here. + */ + + return H_SUCCESS; +} + +static target_ulong h_copy_tofrom_guest(PowerPCCPU *cpu, + SpaprMachineState *spapr, + target_ulong opcode, + target_ulong *args) +{ + /* + * This HCALL is not required, L1 KVM will take a slow path and walk the + * page tables manually to do the data copy. + */ + return H_FUNCTION; +} + +static void nested_save_state(struct nested_ppc_state *save, PowerPCCPU *cpu) +{ + CPUPPCState *env = &cpu->env; + + memcpy(save->gpr, env->gpr, sizeof(save->gpr)); + + save->lr = env->lr; + save->ctr = env->ctr; + save->cfar = env->cfar; + save->msr = env->msr; + save->nip = env->nip; + + save->cr = ppc_get_cr(env); + save->xer = cpu_read_xer(env); + + save->lpcr = env->spr[SPR_LPCR]; + save->lpidr = env->spr[SPR_LPIDR]; + save->pcr = env->spr[SPR_PCR]; + save->dpdes = env->spr[SPR_DPDES]; + save->hfscr = env->spr[SPR_HFSCR]; + save->srr0 = env->spr[SPR_SRR0]; + save->srr1 = env->spr[SPR_SRR1]; + save->sprg0 = env->spr[SPR_SPRG0]; + save->sprg1 = env->spr[SPR_SPRG1]; + save->sprg2 = env->spr[SPR_SPRG2]; + save->sprg3 = env->spr[SPR_SPRG3]; + save->pidr = env->spr[SPR_BOOKS_PID]; + save->ppr = env->spr[SPR_PPR]; + + save->tb_offset = env->tb_env->tb_offset; +} + +static void nested_load_state(PowerPCCPU *cpu, struct nested_ppc_state *load) +{ + CPUState *cs = CPU(cpu); + CPUPPCState *env = &cpu->env; + + memcpy(env->gpr, load->gpr, sizeof(env->gpr)); + + env->lr = load->lr; + env->ctr = load->ctr; + env->cfar = load->cfar; + env->msr = load->msr; + env->nip = load->nip; + + ppc_set_cr(env, load->cr); + cpu_write_xer(env, load->xer); + + env->spr[SPR_LPCR] = load->lpcr; + env->spr[SPR_LPIDR] = load->lpidr; + env->spr[SPR_PCR] = load->pcr; + env->spr[SPR_DPDES] = load->dpdes; + env->spr[SPR_HFSCR] = load->hfscr; + env->spr[SPR_SRR0] = load->srr0; + env->spr[SPR_SRR1] = load->srr1; + env->spr[SPR_SPRG0] = load->sprg0; + env->spr[SPR_SPRG1] = load->sprg1; + env->spr[SPR_SPRG2] = load->sprg2; + env->spr[SPR_SPRG3] = load->sprg3; + env->spr[SPR_BOOKS_PID] = load->pidr; + env->spr[SPR_PPR] = load->ppr; + + env->tb_env->tb_offset = load->tb_offset; + + /* + * MSR updated, compute hflags and possible interrupts. + */ + hreg_compute_hflags(env); + ppc_maybe_interrupt(env); + + /* + * Nested HV does not tag TLB entries between L1 and L2, so must + * flush on transition. + */ + tlb_flush(cs); + env->reserve_addr = -1; /* Reset the reservation */ +} + +/* + * When this handler returns, the environment is switched to the L2 guest + * and TCG begins running that. spapr_exit_nested() performs the switch from + * L2 back to L1 and returns from the H_ENTER_NESTED hcall. + */ +static target_ulong h_enter_nested(PowerPCCPU *cpu, + SpaprMachineState *spapr, + target_ulong opcode, + target_ulong *args) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); + CPUPPCState *env = &cpu->env; + SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu); + struct nested_ppc_state l2_state; + target_ulong hv_ptr = args[0]; + target_ulong regs_ptr = args[1]; + target_ulong hdec, now = cpu_ppc_load_tbl(env); + target_ulong lpcr, lpcr_mask; + struct kvmppc_hv_guest_state *hvstate; + struct kvmppc_hv_guest_state hv_state; + struct kvmppc_pt_regs *regs; + hwaddr len; + + if (spapr->nested_ptcr == 0) { + return H_NOT_AVAILABLE; + } + + len = sizeof(*hvstate); + hvstate = address_space_map(CPU(cpu)->as, hv_ptr, &len, false, + MEMTXATTRS_UNSPECIFIED); + if (len != sizeof(*hvstate)) { + address_space_unmap(CPU(cpu)->as, hvstate, len, 0, false); + return H_PARAMETER; + } + + memcpy(&hv_state, hvstate, len); + + address_space_unmap(CPU(cpu)->as, hvstate, len, len, false); + + /* + * We accept versions 1 and 2. Version 2 fields are unused because TCG + * does not implement DAWR*. + */ + if (hv_state.version > HV_GUEST_STATE_VERSION) { + return H_PARAMETER; + } + + if (hv_state.lpid == 0) { + return H_PARAMETER; + } + + spapr_cpu->nested_host_state = g_try_new(struct nested_ppc_state, 1); + if (!spapr_cpu->nested_host_state) { + return H_NO_MEM; + } + + assert(env->spr[SPR_LPIDR] == 0); + assert(env->spr[SPR_DPDES] == 0); + nested_save_state(spapr_cpu->nested_host_state, cpu); + + len = sizeof(*regs); + regs = address_space_map(CPU(cpu)->as, regs_ptr, &len, false, + MEMTXATTRS_UNSPECIFIED); + if (!regs || len != sizeof(*regs)) { + address_space_unmap(CPU(cpu)->as, regs, len, 0, false); + g_free(spapr_cpu->nested_host_state); + return H_P2; + } + + len = sizeof(l2_state.gpr); + assert(len == sizeof(regs->gpr)); + memcpy(l2_state.gpr, regs->gpr, len); + + l2_state.lr = regs->link; + l2_state.ctr = regs->ctr; + l2_state.xer = regs->xer; + l2_state.cr = regs->ccr; + l2_state.msr = regs->msr; + l2_state.nip = regs->nip; + + address_space_unmap(CPU(cpu)->as, regs, len, len, false); + + l2_state.cfar = hv_state.cfar; + l2_state.lpidr = hv_state.lpid; + + lpcr_mask = LPCR_DPFD | LPCR_ILE | LPCR_AIL | LPCR_LD | LPCR_MER; + lpcr = (env->spr[SPR_LPCR] & ~lpcr_mask) | (hv_state.lpcr & lpcr_mask); + lpcr |= LPCR_HR | LPCR_UPRT | LPCR_GTSE | LPCR_HVICE | LPCR_HDICE; + lpcr &= ~LPCR_LPES0; + l2_state.lpcr = lpcr & pcc->lpcr_mask; + + l2_state.pcr = hv_state.pcr; + /* hv_state.amor is not used */ + l2_state.dpdes = hv_state.dpdes; + l2_state.hfscr = hv_state.hfscr; + /* TCG does not implement DAWR*, CIABR, PURR, SPURR, IC, VTB, HEIR SPRs*/ + l2_state.srr0 = hv_state.srr0; + l2_state.srr1 = hv_state.srr1; + l2_state.sprg0 = hv_state.sprg[0]; + l2_state.sprg1 = hv_state.sprg[1]; + l2_state.sprg2 = hv_state.sprg[2]; + l2_state.sprg3 = hv_state.sprg[3]; + l2_state.pidr = hv_state.pidr; + l2_state.ppr = hv_state.ppr; + l2_state.tb_offset = env->tb_env->tb_offset + hv_state.tb_offset; + + /* + * Switch to the nested guest environment and start the "hdec" timer. + */ + nested_load_state(cpu, &l2_state); + + hdec = hv_state.hdec_expiry - now; + cpu_ppc_hdecr_init(env); + cpu_ppc_store_hdecr(env, hdec); + + /* + * The hv_state.vcpu_token is not needed. It is used by the KVM + * implementation to remember which L2 vCPU last ran on which physical + * CPU so as to invalidate process scope translations if it is moved + * between physical CPUs. For now TLBs are always flushed on L1<->L2 + * transitions so this is not a problem. + * + * Could validate that the same vcpu_token does not attempt to run on + * different L1 vCPUs at the same time, but that would be a L1 KVM bug + * and it's not obviously worth a new data structure to do it. + */ + + spapr_cpu->in_nested = true; + + /* + * The spapr hcall helper sets env->gpr[3] to the return value, but at + * this point the L1 is not returning from the hcall but rather we + * start running the L2, so r3 must not be clobbered, so return env->gpr[3] + * to leave it unchanged. + */ + return env->gpr[3]; +} + +void spapr_exit_nested(PowerPCCPU *cpu, int excp) +{ + CPUPPCState *env = &cpu->env; + SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu); + struct nested_ppc_state l2_state; + target_ulong hv_ptr = spapr_cpu->nested_host_state->gpr[4]; + target_ulong regs_ptr = spapr_cpu->nested_host_state->gpr[5]; + target_ulong hsrr0, hsrr1, hdar, asdr, hdsisr; + struct kvmppc_hv_guest_state *hvstate; + struct kvmppc_pt_regs *regs; + hwaddr len; + + assert(spapr_cpu->in_nested); + + nested_save_state(&l2_state, cpu); + hsrr0 = env->spr[SPR_HSRR0]; + hsrr1 = env->spr[SPR_HSRR1]; + hdar = env->spr[SPR_HDAR]; + hdsisr = env->spr[SPR_HDSISR]; + asdr = env->spr[SPR_ASDR]; + + /* + * Switch back to the host environment (including for any error). + */ + assert(env->spr[SPR_LPIDR] != 0); + nested_load_state(cpu, spapr_cpu->nested_host_state); + env->gpr[3] = env->excp_vectors[excp]; /* hcall return value */ + + cpu_ppc_hdecr_exit(env); + + spapr_cpu->in_nested = false; + + g_free(spapr_cpu->nested_host_state); + spapr_cpu->nested_host_state = NULL; + + len = sizeof(*hvstate); + hvstate = address_space_map(CPU(cpu)->as, hv_ptr, &len, true, + MEMTXATTRS_UNSPECIFIED); + if (len != sizeof(*hvstate)) { + address_space_unmap(CPU(cpu)->as, hvstate, len, 0, true); + env->gpr[3] = H_PARAMETER; + return; + } + + hvstate->cfar = l2_state.cfar; + hvstate->lpcr = l2_state.lpcr; + hvstate->pcr = l2_state.pcr; + hvstate->dpdes = l2_state.dpdes; + hvstate->hfscr = l2_state.hfscr; + + if (excp == POWERPC_EXCP_HDSI) { + hvstate->hdar = hdar; + hvstate->hdsisr = hdsisr; + hvstate->asdr = asdr; + } else if (excp == POWERPC_EXCP_HISI) { + hvstate->asdr = asdr; + } + + /* HEIR should be implemented for HV mode and saved here. */ + hvstate->srr0 = l2_state.srr0; + hvstate->srr1 = l2_state.srr1; + hvstate->sprg[0] = l2_state.sprg0; + hvstate->sprg[1] = l2_state.sprg1; + hvstate->sprg[2] = l2_state.sprg2; + hvstate->sprg[3] = l2_state.sprg3; + hvstate->pidr = l2_state.pidr; + hvstate->ppr = l2_state.ppr; + + /* Is it okay to specify write length larger than actual data written? */ + address_space_unmap(CPU(cpu)->as, hvstate, len, len, true); + + len = sizeof(*regs); + regs = address_space_map(CPU(cpu)->as, regs_ptr, &len, true, + MEMTXATTRS_UNSPECIFIED); + if (!regs || len != sizeof(*regs)) { + address_space_unmap(CPU(cpu)->as, regs, len, 0, true); + env->gpr[3] = H_P2; + return; + } + + len = sizeof(env->gpr); + assert(len == sizeof(regs->gpr)); + memcpy(regs->gpr, l2_state.gpr, len); + + regs->link = l2_state.lr; + regs->ctr = l2_state.ctr; + regs->xer = l2_state.xer; + regs->ccr = l2_state.cr; + + if (excp == POWERPC_EXCP_MCHECK || + excp == POWERPC_EXCP_RESET || + excp == POWERPC_EXCP_SYSCALL) { + regs->nip = l2_state.srr0; + regs->msr = l2_state.srr1 & env->msr_mask; + } else { + regs->nip = hsrr0; + regs->msr = hsrr1 & env->msr_mask; + } + + /* Is it okay to specify write length larger than actual data written? */ + address_space_unmap(CPU(cpu)->as, regs, len, len, true); +} + +void spapr_register_nested(void) +{ + spapr_register_hypercall(KVMPPC_H_SET_PARTITION_TABLE, h_set_ptbl); + spapr_register_hypercall(KVMPPC_H_ENTER_NESTED, h_enter_nested); + spapr_register_hypercall(KVMPPC_H_TLB_INVALIDATE, h_tlb_invalidate); + spapr_register_hypercall(KVMPPC_H_COPY_TOFROM_GUEST, h_copy_tofrom_guest); +} +#else +void spapr_exit_nested(PowerPCCPU *cpu, int excp) +{ + g_assert_not_reached(); +} + +void spapr_register_nested(void) +{ + /* DO NOTHING */ +} +#endif diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index bd5a6c4780..538b2dfb89 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -621,66 +621,6 @@ struct SpaprMachineState { #define SVM_H_TPM_COMM 0xEF10 #define SVM_HCALL_MAX SVM_H_TPM_COMM -/* - * Register state for entering a nested guest with H_ENTER_NESTED. - * New member must be added at the end. - */ -struct kvmppc_hv_guest_state { - uint64_t version; /* version of this structure layout, must be first */ - uint32_t lpid; - uint32_t vcpu_token; - /* These registers are hypervisor privileged (at least for writing) */ - uint64_t lpcr; - uint64_t pcr; - uint64_t amor; - uint64_t dpdes; - uint64_t hfscr; - int64_t tb_offset; - uint64_t dawr0; - uint64_t dawrx0; - uint64_t ciabr; - uint64_t hdec_expiry; - uint64_t purr; - uint64_t spurr; - uint64_t ic; - uint64_t vtb; - uint64_t hdar; - uint64_t hdsisr; - uint64_t heir; - uint64_t asdr; - /* These are OS privileged but need to be set late in guest entry */ - uint64_t srr0; - uint64_t srr1; - uint64_t sprg[4]; - uint64_t pidr; - uint64_t cfar; - uint64_t ppr; - /* Version 1 ends here */ - uint64_t dawr1; - uint64_t dawrx1; - /* Version 2 ends here */ -}; - -/* Latest version of hv_guest_state structure */ -#define HV_GUEST_STATE_VERSION 2 - -/* Linux 64-bit powerpc pt_regs struct, used by nested HV */ -struct kvmppc_pt_regs { - uint64_t gpr[32]; - uint64_t nip; - uint64_t msr; - uint64_t orig_gpr3; /* Used for restarting system calls */ - uint64_t ctr; - uint64_t link; - uint64_t xer; - uint64_t ccr; - uint64_t softe; /* Soft enabled/disabled */ - uint64_t trap; /* Reason for being here */ - uint64_t dar; /* Fault registers */ - uint64_t dsisr; /* on 4xx/Book-E used for ESR */ - uint64_t result; /* Result of a system call */ -}; - typedef struct SpaprDeviceTreeUpdateHeader { uint32_t version_id; } SpaprDeviceTreeUpdateHeader; @@ -698,8 +638,6 @@ void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn); target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode, target_ulong *args); -void spapr_exit_nested(PowerPCCPU *cpu, int excp); - target_ulong softmmu_resize_hpt_prepare(PowerPCCPU *cpu, SpaprMachineState *spapr, target_ulong shift); target_ulong softmmu_resize_hpt_commit(PowerPCCPU *cpu, SpaprMachineState *spapr, diff --git a/include/hw/ppc/spapr_nested.h b/include/hw/ppc/spapr_nested.h new file mode 100644 index 0000000000..d383486476 --- /dev/null +++ b/include/hw/ppc/spapr_nested.h @@ -0,0 +1,102 @@ +#ifndef HW_SPAPR_NESTED_H +#define HW_SPAPR_NESTED_H + +#include "qemu/osdep.h" +#include "target/ppc/cpu.h" + +/* + * Register state for entering a nested guest with H_ENTER_NESTED. + * New member must be added at the end. + */ +struct kvmppc_hv_guest_state { + uint64_t version; /* version of this structure layout, must be first */ + uint32_t lpid; + uint32_t vcpu_token; + /* These registers are hypervisor privileged (at least for writing) */ + uint64_t lpcr; + uint64_t pcr; + uint64_t amor; + uint64_t dpdes; + uint64_t hfscr; + int64_t tb_offset; + uint64_t dawr0; + uint64_t dawrx0; + uint64_t ciabr; + uint64_t hdec_expiry; + uint64_t purr; + uint64_t spurr; + uint64_t ic; + uint64_t vtb; + uint64_t hdar; + uint64_t hdsisr; + uint64_t heir; + uint64_t asdr; + /* These are OS privileged but need to be set late in guest entry */ + uint64_t srr0; + uint64_t srr1; + uint64_t sprg[4]; + uint64_t pidr; + uint64_t cfar; + uint64_t ppr; + /* Version 1 ends here */ + uint64_t dawr1; + uint64_t dawrx1; + /* Version 2 ends here */ +}; + +/* Latest version of hv_guest_state structure */ +#define HV_GUEST_STATE_VERSION 2 + +/* Linux 64-bit powerpc pt_regs struct, used by nested HV */ +struct kvmppc_pt_regs { + uint64_t gpr[32]; + uint64_t nip; + uint64_t msr; + uint64_t orig_gpr3; /* Used for restarting system calls */ + uint64_t ctr; + uint64_t link; + uint64_t xer; + uint64_t ccr; + uint64_t softe; /* Soft enabled/disabled */ + uint64_t trap; /* Reason for being here */ + uint64_t dar; /* Fault registers */ + uint64_t dsisr; /* on 4xx/Book-E used for ESR */ + uint64_t result; /* Result of a system call */ +}; + +/* + * nested_ppc_state is used to save the host CPU state before switching it to + * the guest CPU state, to be restored on H_ENTER_NESTED exit. + */ +struct nested_ppc_state { + uint64_t gpr[32]; + uint64_t lr; + uint64_t ctr; + uint64_t cfar; + uint64_t msr; + uint64_t nip; + uint32_t cr; + + uint64_t xer; + + uint64_t lpcr; + uint64_t lpidr; + uint64_t pidr; + uint64_t pcr; + uint64_t dpdes; + uint64_t hfscr; + uint64_t srr0; + uint64_t srr1; + uint64_t sprg0; + uint64_t sprg1; + uint64_t sprg2; + uint64_t sprg3; + uint64_t ppr; + + int64_t tb_offset; +}; + +void spapr_register_nested(void); +void spapr_exit_nested(PowerPCCPU *cpu, int excp); + +#endif /* HW_SPAPR_NESTED_H */ From 888050cf519eb5995424cf415f4f8f269de96824 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 20 Jun 2023 23:10:41 +1000 Subject: [PATCH 0116/1353] target/ppc: Fix instruction loading endianness in alignment interrupt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit powerpc ifetch endianness depends on MSR[LE] so it has to byteswap after cpu_ldl_code(). This corrects DSISR bits in alignment interrupts when running in little endian mode. Reviewed-by: Fabiano Rosas Signed-off-by: Nicholas Piggin Signed-off-by: Cédric Le Goater --- target/ppc/excp_helper.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 12d8a7257b..a2801f6e6b 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -133,6 +133,26 @@ static void dump_hcall(CPUPPCState *env) env->nip); } +#ifdef CONFIG_TCG +/* Return true iff byteswap is needed to load instruction */ +static inline bool insn_need_byteswap(CPUArchState *env) +{ + /* SYSTEM builds TARGET_BIG_ENDIAN. Need to swap when MSR[LE] is set */ + return !!(env->msr & ((target_ulong)1 << MSR_LE)); +} + +static uint32_t ppc_ldl_code(CPUArchState *env, hwaddr addr) +{ + uint32_t insn = cpu_ldl_code(env, addr); + + if (insn_need_byteswap(env)) { + insn = bswap32(insn); + } + + return insn; +} +#endif + static void ppc_excp_debug_sw_tlb(CPUPPCState *env, int excp) { const char *es; @@ -3104,7 +3124,7 @@ void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, /* Restore state and reload the insn we executed, for filling in DSISR. */ cpu_restore_state(cs, retaddr); - insn = cpu_ldl_code(env, env->nip); + insn = ppc_ldl_code(env, env->nip); switch (env->mmu_model) { case POWERPC_MMU_SOFT_4xx: From 74574c3845a046174993092cdc3c03f481dc2cf3 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 20 Jun 2023 23:10:42 +1000 Subject: [PATCH 0117/1353] target/ppc: Change partition-scope translate interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than always performing partition scope page table translation with access type of 0 (MMU_DATA_LOAD), pass through the processor access type which first initiated the translation sequence. Process- scoped page table loads are then set to MMU_DATA_LOAD access type in the xlate function. This will allow more information to be passed to the exception handler in the next patch. Signed-off-by: Nicholas Piggin Signed-off-by: Cédric Le Goater --- target/ppc/mmu-radix64.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c index 031efda0df..1fc1ba3ecf 100644 --- a/target/ppc/mmu-radix64.c +++ b/target/ppc/mmu-radix64.c @@ -380,6 +380,14 @@ static int ppc_radix64_partition_scoped_xlate(PowerPCCPU *cpu, hwaddr pte_addr; uint64_t pte; + if (pde_addr) { + /* + * Translation of process-scoped tables/directories is performed as + * a read-access. + */ + access_type = MMU_DATA_LOAD; + } + qemu_log_mask(CPU_LOG_MMU, "%s for %s @0x%"VADDR_PRIx " mmu_idx %u 0x%"HWADDR_PRIx"\n", __func__, access_str(access_type), @@ -477,10 +485,10 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, * is only used to translate the effective addresses of the * process table entries. */ - ret = ppc_radix64_partition_scoped_xlate(cpu, 0, eaddr, prtbe_addr, - pate, &h_raddr, &h_prot, - &h_page_size, true, - /* mmu_idx is 5 because we're translating from hypervisor scope */ + /* mmu_idx is 5 because we're translating from hypervisor scope */ + ret = ppc_radix64_partition_scoped_xlate(cpu, access_type, eaddr, + prtbe_addr, pate, &h_raddr, + &h_prot, &h_page_size, true, 5, guest_visible); if (ret) { return ret; @@ -519,11 +527,11 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, * translation */ do { - ret = ppc_radix64_partition_scoped_xlate(cpu, 0, eaddr, pte_addr, - pate, &h_raddr, &h_prot, - &h_page_size, true, /* mmu_idx is 5 because we're translating from hypervisor scope */ - 5, guest_visible); + ret = ppc_radix64_partition_scoped_xlate(cpu, access_type, eaddr, + pte_addr, pate, &h_raddr, + &h_prot, &h_page_size, + true, 5, guest_visible); if (ret) { return ret; } From 5a5d3b23cb281d99ee6dd74afa41864428e35241 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 20 Jun 2023 23:10:43 +1000 Subject: [PATCH 0118/1353] target/ppc: Add SRR1 prefix indication to interrupt handlers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ISA v3.1 introduced prefix instructions. Among the changes, various synchronous interrupts report whether they were caused by a prefix instruction in (H)SRR1. The case of instruction fetch that causes an HDSI due to access of a process-scoped table faulting on the partition scoped translation is the tricky one. As with ISIs and HISIs, this does not try to set the prefix bit because there is no instruction image to be loaded. The HDSI needs the originating access type to be passed through to the handler to distinguish this from HDSIs that fault translating process scoped tables originating from a load or store instruction (in that case the prefix bit should be provided). Reviewed-by: Fabiano Rosas Signed-off-by: Nicholas Piggin [ clg: checkpatch issues ] Signed-off-by: Cédric Le Goater --- target/ppc/excp_helper.c | 73 +++++++++++++++++++++++++++++++++++++++- target/ppc/mmu-radix64.c | 14 ++++++-- 2 files changed, 83 insertions(+), 4 deletions(-) diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index a2801f6e6b..847f8a33be 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -28,6 +28,7 @@ #include "trace.h" #ifdef CONFIG_TCG +#include "sysemu/tcg.h" #include "exec/helper-proto.h" #include "exec/cpu_ldst.h" #endif @@ -141,7 +142,7 @@ static inline bool insn_need_byteswap(CPUArchState *env) return !!(env->msr & ((target_ulong)1 << MSR_LE)); } -static uint32_t ppc_ldl_code(CPUArchState *env, hwaddr addr) +static uint32_t ppc_ldl_code(CPUArchState *env, abi_ptr addr) { uint32_t insn = cpu_ldl_code(env, addr); @@ -1348,6 +1349,72 @@ static bool books_vhyp_handles_hv_excp(PowerPCCPU *cpu) return false; } +#ifdef CONFIG_TCG +static bool is_prefix_insn(CPUPPCState *env, uint32_t insn) +{ + if (!(env->insns_flags2 & PPC2_ISA310)) { + return false; + } + return ((insn & 0xfc000000) == 0x04000000); +} + +static bool is_prefix_insn_excp(PowerPCCPU *cpu, int excp) +{ + CPUPPCState *env = &cpu->env; + + if (!tcg_enabled()) { + /* + * This does not load instructions and set the prefix bit correctly + * for injected interrupts with KVM. That may have to be discovered + * and set by the KVM layer before injecting. + */ + return false; + } + + switch (excp) { + case POWERPC_EXCP_HDSI: + /* HDSI PRTABLE_FAULT has the originating access type in error_code */ + if ((env->spr[SPR_HDSISR] & DSISR_PRTABLE_FAULT) && + (env->error_code == MMU_INST_FETCH)) { + /* + * Fetch failed due to partition scope translation, so prefix + * indication is not relevant (and attempting to load the + * instruction at NIP would cause recursive faults with the same + * translation). + */ + break; + } + /* fall through */ + case POWERPC_EXCP_MCHECK: + case POWERPC_EXCP_DSI: + case POWERPC_EXCP_DSEG: + case POWERPC_EXCP_ALIGN: + case POWERPC_EXCP_PROGRAM: + case POWERPC_EXCP_FPU: + case POWERPC_EXCP_TRACE: + case POWERPC_EXCP_HV_EMU: + case POWERPC_EXCP_VPU: + case POWERPC_EXCP_VSXU: + case POWERPC_EXCP_FU: + case POWERPC_EXCP_HV_FU: { + uint32_t insn = ppc_ldl_code(env, env->nip); + if (is_prefix_insn(env, insn)) { + return true; + } + break; + } + default: + break; + } + return false; +} +#else +static bool is_prefix_insn_excp(PowerPCCPU *cpu, int excp) +{ + return false; +} +#endif + static void powerpc_excp_books(PowerPCCPU *cpu, int excp) { CPUState *cs = CPU(cpu); @@ -1395,6 +1462,10 @@ static void powerpc_excp_books(PowerPCCPU *cpu, int excp) vector |= env->excp_prefix; + if (is_prefix_insn_excp(cpu, excp)) { + msr |= PPC_BIT(34); + } + switch (excp) { case POWERPC_EXCP_MCHECK: /* Machine check exception */ if (!FIELD_EX64(env->msr, MSR, ME)) { diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c index 1fc1ba3ecf..920084bd8f 100644 --- a/target/ppc/mmu-radix64.c +++ b/target/ppc/mmu-radix64.c @@ -145,6 +145,13 @@ static void ppc_radix64_raise_hsi(PowerPCCPU *cpu, MMUAccessType access_type, CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; + env->error_code = 0; + if (cause & DSISR_PRTABLE_FAULT) { + /* HDSI PRTABLE_FAULT gets the originating access type in error_code */ + env->error_code = access_type; + access_type = MMU_DATA_LOAD; + } + qemu_log_mask(CPU_LOG_MMU, "%s for %s @0x%"VADDR_PRIx" 0x%" HWADDR_PRIx" cause %08x\n", __func__, access_str(access_type), @@ -166,7 +173,6 @@ static void ppc_radix64_raise_hsi(PowerPCCPU *cpu, MMUAccessType access_type, env->spr[SPR_HDSISR] = cause; env->spr[SPR_HDAR] = eaddr; env->spr[SPR_ASDR] = g_raddr; - env->error_code = 0; break; default: g_assert_not_reached(); @@ -369,13 +375,14 @@ static bool validate_pate(PowerPCCPU *cpu, uint64_t lpid, ppc_v3_pate_t *pate) } static int ppc_radix64_partition_scoped_xlate(PowerPCCPU *cpu, - MMUAccessType access_type, + MMUAccessType orig_access_type, vaddr eaddr, hwaddr g_raddr, ppc_v3_pate_t pate, hwaddr *h_raddr, int *h_prot, int *h_page_size, bool pde_addr, int mmu_idx, bool guest_visible) { + MMUAccessType access_type = orig_access_type; int fault_cause = 0; hwaddr pte_addr; uint64_t pte; @@ -404,7 +411,8 @@ static int ppc_radix64_partition_scoped_xlate(PowerPCCPU *cpu, fault_cause |= DSISR_PRTABLE_FAULT; } if (guest_visible) { - ppc_radix64_raise_hsi(cpu, access_type, eaddr, g_raddr, fault_cause); + ppc_radix64_raise_hsi(cpu, orig_access_type, + eaddr, g_raddr, fault_cause); } return 1; } From a3c020d85ea721fc2a57b28f305a532b2c388f7c Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 20 Jun 2023 23:10:44 +1000 Subject: [PATCH 0119/1353] target/ppc: Implement HEIR SPR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hypervisor emulation assistance interrupt modifies HEIR to contain the value of the instruction which caused the exception. Only TCG raises HEAI interrupts so this can be made TCG-only. Signed-off-by: Nicholas Piggin Signed-off-by: Cédric Le Goater --- target/ppc/cpu.h | 1 + target/ppc/cpu_init.c | 23 +++++++++++++++++++++++ target/ppc/excp_helper.c | 17 ++++++++++++++++- 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 0ee2adc105..054edf3c80 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -1647,6 +1647,7 @@ void ppc_compat_add_property(Object *obj, const char *name, #define SPR_HMER (0x150) #define SPR_HMEER (0x151) #define SPR_PCR (0x152) +#define SPR_HEIR (0x153) #define SPR_BOOKE_LPIDR (0x152) #define SPR_BOOKE_TCR (0x154) #define SPR_BOOKE_TLB0PS (0x158) diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index 7bce421a7c..dccc064053 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -1630,6 +1630,7 @@ static void register_8xx_sprs(CPUPPCState *env) * HSRR0 => SPR 314 (Power 2.04 hypv) * HSRR1 => SPR 315 (Power 2.04 hypv) * LPIDR => SPR 317 (970) + * HEIR => SPR 339 (Power 2.05 hypv) (64-bit reg from 3.1) * EPR => SPR 702 (Power 2.04 emb) * perf => 768-783 (Power 2.04) * perf => 784-799 (Power 2.04) @@ -5523,6 +5524,24 @@ static void register_power6_common_sprs(CPUPPCState *env) 0x00000000); } +static void register_HEIR32_spr(CPUPPCState *env) +{ + spr_register_hv(env, SPR_HEIR, "HEIR", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic32, + 0x00000000); +} + +static void register_HEIR64_spr(CPUPPCState *env) +{ + spr_register_hv(env, SPR_HEIR, "HEIR", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +} + static void register_power8_tce_address_control_sprs(CPUPPCState *env) { spr_register_kvm(env, SPR_TAR, "TAR", @@ -5951,6 +5970,7 @@ static void init_proc_POWER7(CPUPPCState *env) register_power5p_ear_sprs(env); register_power5p_tb_sprs(env); register_power6_common_sprs(env); + register_HEIR32_spr(env); register_power6_dbg_sprs(env); register_power7_book4_sprs(env); @@ -6073,6 +6093,7 @@ static void init_proc_POWER8(CPUPPCState *env) register_power5p_ear_sprs(env); register_power5p_tb_sprs(env); register_power6_common_sprs(env); + register_HEIR32_spr(env); register_power6_dbg_sprs(env); register_power8_tce_address_control_sprs(env); register_power8_ids_sprs(env); @@ -6235,6 +6256,7 @@ static void init_proc_POWER9(CPUPPCState *env) register_power5p_ear_sprs(env); register_power5p_tb_sprs(env); register_power6_common_sprs(env); + register_HEIR32_spr(env); register_power6_dbg_sprs(env); register_power8_tce_address_control_sprs(env); register_power8_ids_sprs(env); @@ -6427,6 +6449,7 @@ static void init_proc_POWER10(CPUPPCState *env) register_power5p_ear_sprs(env); register_power5p_tb_sprs(env); register_power6_common_sprs(env); + register_HEIR64_spr(env); register_power6_dbg_sprs(env); register_power8_tce_address_control_sprs(env); register_power8_ids_sprs(env); diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 847f8a33be..2a0070cf43 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -1642,13 +1642,28 @@ static void powerpc_excp_books(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */ case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */ case POWERPC_EXCP_SDOOR_HV: /* Hypervisor Doorbell interrupt */ - case POWERPC_EXCP_HV_EMU: case POWERPC_EXCP_HVIRT: /* Hypervisor virtualization */ srr0 = SPR_HSRR0; srr1 = SPR_HSRR1; new_msr |= (target_ulong)MSR_HVB; new_msr |= env->msr & ((target_ulong)1 << MSR_RI); break; +#ifdef CONFIG_TCG + case POWERPC_EXCP_HV_EMU: { + uint32_t insn = ppc_ldl_code(env, env->nip); + env->spr[SPR_HEIR] = insn; + if (is_prefix_insn(env, insn)) { + uint32_t insn2 = ppc_ldl_code(env, env->nip + 4); + env->spr[SPR_HEIR] <<= 32; + env->spr[SPR_HEIR] |= insn2; + } + srr0 = SPR_HSRR0; + srr1 = SPR_HSRR1; + new_msr |= (target_ulong)MSR_HVB; + new_msr |= env->msr & ((target_ulong)1 << MSR_RI); + break; + } +#endif case POWERPC_EXCP_VPU: /* Vector unavailable exception */ case POWERPC_EXCP_VSXU: /* VSX unavailable exception */ case POWERPC_EXCP_FU: /* Facility unavailable exception */ From eb701f30120d899bdaa202c3cbd9219055fccae0 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 20 Jun 2023 23:13:21 +1000 Subject: [PATCH 0120/1353] target/ppc: Add ISA v3.1 LEV indication in SRR1 for system call interrupts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit System call interrupts in ISA v3.1 CPUs add a LEV indication in SRR1 that corresponds with the LEV field of the instruction that caused the interrupt. Signed-off-by: Nicholas Piggin Reviewed-by: Harsh Prateek Bora Signed-off-by: Cédric Le Goater --- target/ppc/excp_helper.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 2a0070cf43..8e2fec3551 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -1591,6 +1591,10 @@ static void powerpc_excp_books(PowerPCCPU *cpu, int excp) vhc->hypercall(cpu->vhyp, cpu); return; } + if (env->insns_flags2 & PPC2_ISA310) { + /* ISAv3.1 puts LEV into SRR1 */ + msr |= lev << 20; + } if (lev == 1) { new_msr |= (target_ulong)MSR_HVB; } From 488aad116651f9838767fd53d5660e6702925c14 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 20 Jun 2023 23:15:23 +1000 Subject: [PATCH 0121/1353] target/ppc: Better CTRL SPR implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CTRL register is able to write the bit in the RUN field, which gets reflected into the TS field which is read-only and contains the state of the RUN field for all threads in the core. TCG does not implement SMT, so the correct implementation just requires mirroring the RUN bit into the first bit of the TS field. Signed-off-by: Nicholas Piggin Signed-off-by: Cédric Le Goater --- target/ppc/translate.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/target/ppc/translate.c b/target/ppc/translate.c index b591f2e496..1ade063616 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -418,7 +418,14 @@ void spr_write_generic32(DisasContext *ctx, int sprn, int gprn) void spr_write_CTRL(DisasContext *ctx, int sprn, int gprn) { - spr_write_generic32(ctx, sprn, gprn); + /* This does not implement >1 thread */ + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + tcg_gen_extract_tl(t0, cpu_gpr[gprn], 0, 1); /* Extract RUN field */ + tcg_gen_shli_tl(t1, t0, 8); /* Duplicate the bit in TS */ + tcg_gen_or_tl(t1, t1, t0); + gen_store_spr(sprn, t1); + spr_store_dump_spr(sprn); /* * SPR_CTRL writes must force a new translation block, From 984eda58f20763ffb56b7aff34ad60bdeb118eb1 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Wed, 21 Jun 2023 21:09:38 +1000 Subject: [PATCH 0122/1353] target/ppc: Fix sc instruction handling of LEV field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The top bits of the LEV field of the sc instruction are to be treated as as a reserved field rather than a reserved value, meaning LEV is effectively the bottom bit. LEV=0xF should be treated as LEV=1 and be a hypercall, for example. This changes the instruction execution to just set lev from the low bit of the field. Processors which don't support the LEV field will continue to ignore it. ISA v3.1 defines LEV to be 2 bits, in order to add the 'sc 2' ultracall instruction. TCG does not support Ultravisor, so don't worry about that bit. Suggested-by: "Harsh Prateek Bora" Signed-off-by: Nicholas Piggin Reviewed-by: Harsh Prateek Bora Signed-off-by: Cédric Le Goater --- target/ppc/translate.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 1ade063616..8f74a864e4 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -4429,7 +4429,12 @@ static void gen_sc(DisasContext *ctx) { uint32_t lev; - lev = (ctx->opcode >> 5) & 0x7F; + /* + * LEV is a 7-bit field, but the top 6 bits are treated as a reserved + * field (i.e., ignored). ISA v3.1 changes that to 5 bits, but that is + * for Ultravisor which TCG does not support, so just ignore the top 6. + */ + lev = (ctx->opcode >> 5) & 0x1; gen_exception_err(ctx, POWERPC_SYSCALL, lev); } From b769d4c8f4c67e794444a6376b849db2caeeff3e Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Thu, 22 Jun 2023 19:33:51 +1000 Subject: [PATCH 0123/1353] target/ppc: Add initial flags and helpers for SMT support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TGC SMT emulation needs to know whether it is running with SMT siblings, to be able to iterate over siblings in a core, and to serialise threads to access per-core shared SPRs. Add infrastructure to do these things. For now the sibling iteration and serialisation are implemented in a simple but inefficient way. SMT shared state and sibling access is not too common, and SMT configurations are mainly useful to test system code, so performance is not to critical. Signed-off-by: Nicholas Piggin Reviewed-by: Cédric Le Goater [ clg: fix build breakage with clang ] Signed-off-by: Cédric Le Goater --- target/ppc/cpu.h | 9 +++++++++ target/ppc/cpu_init.c | 5 +++++ target/ppc/translate.c | 22 ++++++++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 054edf3c80..4138a25801 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -672,6 +672,8 @@ enum { POWERPC_FLAG_TM = 0x00100000, /* Has SCV (ISA 3.00) */ POWERPC_FLAG_SCV = 0x00200000, + /* Has >1 thread per core */ + POWERPC_FLAG_SMT = 0x00400000, }; /* @@ -1268,6 +1270,13 @@ struct CPUArchState { uint64_t pmu_base_time; }; +#define _CORE_ID(cs) \ + (POWERPC_CPU(cs)->env.spr_cb[SPR_PIR].default_value & ~(cs->nr_threads - 1)) + +#define THREAD_SIBLING_FOREACH(cs, cs_sibling) \ + CPU_FOREACH(cs_sibling) \ + if (_CORE_ID(cs) == _CORE_ID(cs_sibling)) + #define SET_FIT_PERIOD(a_, b_, c_, d_) \ do { \ env->fit_period[0] = (a_); \ diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index dccc064053..aeff71d063 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -6755,6 +6755,7 @@ static void ppc_cpu_realize(DeviceState *dev, Error **errp) { CPUState *cs = CPU(dev); PowerPCCPU *cpu = POWERPC_CPU(dev); + CPUPPCState *env = &cpu->env; PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); Error *local_err = NULL; @@ -6786,6 +6787,10 @@ static void ppc_cpu_realize(DeviceState *dev, Error **errp) pcc->parent_realize(dev, errp); + if (env_cpu(env)->nr_threads > 1) { + env->flags |= POWERPC_FLAG_SMT; + } + return; unrealize: diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 8f74a864e4..7d8877b3dc 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -234,6 +234,28 @@ struct opc_handler_t { void (*handler)(DisasContext *ctx); }; +static inline bool gen_serialize(DisasContext *ctx) +{ + if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { + /* Restart with exclusive lock. */ + gen_helper_exit_atomic(cpu_env); + ctx->base.is_jmp = DISAS_NORETURN; + return false; + } + return true; +} + +#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) +static inline bool gen_serialize_core(DisasContext *ctx) +{ + if (ctx->flags & POWERPC_FLAG_SMT) { + return gen_serialize(ctx); + } + + return true; +} +#endif + /* SPR load/store helpers */ static inline void gen_load_spr(TCGv t, int reg) { From c5d98a7b3d455204e24212cb769dec8f490e4e1c Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Thu, 22 Jun 2023 19:33:52 +1000 Subject: [PATCH 0124/1353] target/ppc: Add support for SMT CTRL register MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A relatively simple case to begin with, CTRL is a SMT shared register where reads and writes need to synchronise against state changes by other threads in the core. Atomic serialisation operations are used to achieve this. Signed-off-by: Nicholas Piggin Reviewed-by: Cédric Le Goater Signed-off-by: Cédric Le Goater --- target/ppc/helper.h | 2 ++ target/ppc/misc_helper.c | 25 +++++++++++++++++++++++++ target/ppc/translate.c | 18 +++++++++++++++++- 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/target/ppc/helper.h b/target/ppc/helper.h index 38efbc351c..fda40b8a60 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -704,6 +704,8 @@ DEF_HELPER_3(store_dcr, void, env, tl, tl) DEF_HELPER_2(load_dump_spr, void, env, i32) DEF_HELPER_2(store_dump_spr, void, env, i32) +DEF_HELPER_3(spr_write_CTRL, void, env, i32, tl) + DEF_HELPER_4(fscr_facility_check, void, env, i32, i32, i32) DEF_HELPER_4(msr_facility_check, void, env, i32, i32, i32) DEF_HELPER_FLAGS_1(load_tbl, TCG_CALL_NO_RWG, tl, env) diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c index 40ddc5c08c..a058eb24cd 100644 --- a/target/ppc/misc_helper.c +++ b/target/ppc/misc_helper.c @@ -43,6 +43,31 @@ void helper_store_dump_spr(CPUPPCState *env, uint32_t sprn) env->spr[sprn]); } +void helper_spr_write_CTRL(CPUPPCState *env, uint32_t sprn, + target_ulong val) +{ + CPUState *cs = env_cpu(env); + CPUState *ccs; + uint32_t run = val & 1; + uint32_t ts, ts_mask; + + assert(sprn == SPR_CTRL); + + env->spr[sprn] &= ~1U; + env->spr[sprn] |= run; + + ts_mask = ~(1U << (8 + env->spr[SPR_TIR])); + ts = run << (8 + env->spr[SPR_TIR]); + + THREAD_SIBLING_FOREACH(cs, ccs) { + CPUPPCState *cenv = &POWERPC_CPU(ccs)->env; + + cenv->spr[sprn] &= ts_mask; + cenv->spr[sprn] |= ts; + } +} + + #ifdef TARGET_PPC64 static void raise_hv_fu_exception(CPUPPCState *env, uint32_t bit, const char *caller, uint32_t cause, diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 7d8877b3dc..c321a39027 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -438,7 +438,7 @@ void spr_write_generic32(DisasContext *ctx, int sprn, int gprn) #endif } -void spr_write_CTRL(DisasContext *ctx, int sprn, int gprn) +static void spr_write_CTRL_ST(DisasContext *ctx, int sprn, int gprn) { /* This does not implement >1 thread */ TCGv t0 = tcg_temp_new(); @@ -447,6 +447,22 @@ void spr_write_CTRL(DisasContext *ctx, int sprn, int gprn) tcg_gen_shli_tl(t1, t0, 8); /* Duplicate the bit in TS */ tcg_gen_or_tl(t1, t1, t0); gen_store_spr(sprn, t1); +} + +void spr_write_CTRL(DisasContext *ctx, int sprn, int gprn) +{ + if (!(ctx->flags & POWERPC_FLAG_SMT)) { + spr_write_CTRL_ST(ctx, sprn, gprn); + goto out; + } + + if (!gen_serialize(ctx)) { + return; + } + + gen_helper_spr_write_CTRL(cpu_env, tcg_constant_i32(sprn), + cpu_gpr[gprn]); +out: spr_store_dump_spr(sprn); /* From d24e80b2ae3e061a200178d679711b5538479a72 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Thu, 22 Jun 2023 19:33:53 +1000 Subject: [PATCH 0125/1353] target/ppc: Add msgsnd/p and DPDES SMT support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Doorbells in SMT need to coordinate msgsnd/msgclr and DPDES access from multiple threads that affect the same state. Signed-off-by: Nicholas Piggin Reviewed-by: Cédric Le Goater Signed-off-by: Cédric Le Goater --- hw/ppc/ppc.c | 6 ++++++ include/hw/ppc/ppc.h | 1 + target/ppc/excp_helper.c | 30 ++++++++++++++++++++++----- target/ppc/misc_helper.c | 44 ++++++++++++++++++++++++++++++++++------ target/ppc/translate.c | 8 ++++++++ 5 files changed, 78 insertions(+), 11 deletions(-) diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c index 1b1220c423..82e4408c5c 100644 --- a/hw/ppc/ppc.c +++ b/hw/ppc/ppc.c @@ -1436,6 +1436,12 @@ int ppc_cpu_pir(PowerPCCPU *cpu) return env->spr_cb[SPR_PIR].default_value; } +int ppc_cpu_tir(PowerPCCPU *cpu) +{ + CPUPPCState *env = &cpu->env; + return env->spr_cb[SPR_TIR].default_value; +} + PowerPCCPU *ppc_get_vcpu_by_pir(int pir) { CPUState *cs; diff --git a/include/hw/ppc/ppc.h b/include/hw/ppc/ppc.h index 02af03ada2..e095c002dc 100644 --- a/include/hw/ppc/ppc.h +++ b/include/hw/ppc/ppc.h @@ -6,6 +6,7 @@ void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level); PowerPCCPU *ppc_get_vcpu_by_pir(int pir); int ppc_cpu_pir(PowerPCCPU *cpu); +int ppc_cpu_tir(PowerPCCPU *cpu); /* PowerPC hardware exceptions management helpers */ typedef void (*clk_setup_cb)(void *opaque, uint32_t freq); diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 8e2fec3551..2158390e27 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -3186,22 +3186,42 @@ void helper_book3s_msgclrp(CPUPPCState *env, target_ulong rb) } /* - * sends a message to other threads that are on the same + * sends a message to another thread on the same * multi-threaded processor */ void helper_book3s_msgsndp(CPUPPCState *env, target_ulong rb) { - int pir = env->spr_cb[SPR_PIR].default_value; + CPUState *cs = env_cpu(env); + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUState *ccs; + uint32_t nr_threads = cs->nr_threads; + int ttir = rb & PPC_BITMASK(57, 63); helper_hfscr_facility_check(env, HFSCR_MSGP, "msgsndp", HFSCR_IC_MSGP); - if (!dbell_type_server(rb)) { + if (!dbell_type_server(rb) || ttir >= nr_threads) { return; } - /* TODO: TCG supports only one thread */ + if (nr_threads == 1) { + ppc_set_irq(cpu, PPC_INTERRUPT_DOORBELL, 1); + return; + } - book3s_msgsnd_common(pir, PPC_INTERRUPT_DOORBELL); + /* Does iothread need to be locked for walking CPU list? */ + qemu_mutex_lock_iothread(); + THREAD_SIBLING_FOREACH(cs, ccs) { + PowerPCCPU *ccpu = POWERPC_CPU(ccs); + uint32_t thread_id = ppc_cpu_tir(ccpu); + + if (ttir == thread_id) { + ppc_set_irq(ccpu, PPC_INTERRUPT_DOORBELL, 1); + qemu_mutex_unlock_iothread(); + return; + } + } + + g_assert_not_reached(); } #endif /* TARGET_PPC64 */ diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c index a058eb24cd..1f1af21f33 100644 --- a/target/ppc/misc_helper.c +++ b/target/ppc/misc_helper.c @@ -184,32 +184,64 @@ void helper_store_pcr(CPUPPCState *env, target_ulong value) */ target_ulong helper_load_dpdes(CPUPPCState *env) { + CPUState *cs = env_cpu(env); + CPUState *ccs; + uint32_t nr_threads = cs->nr_threads; target_ulong dpdes = 0; helper_hfscr_facility_check(env, HFSCR_MSGP, "load DPDES", HFSCR_IC_MSGP); - /* TODO: TCG supports only one thread */ - if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) { - dpdes = 1; + if (nr_threads == 1) { + if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) { + dpdes = 1; + } + return dpdes; } + qemu_mutex_lock_iothread(); + THREAD_SIBLING_FOREACH(cs, ccs) { + PowerPCCPU *ccpu = POWERPC_CPU(ccs); + CPUPPCState *cenv = &ccpu->env; + uint32_t thread_id = ppc_cpu_tir(ccpu); + + if (cenv->pending_interrupts & PPC_INTERRUPT_DOORBELL) { + dpdes |= (0x1 << thread_id); + } + } + qemu_mutex_unlock_iothread(); + return dpdes; } void helper_store_dpdes(CPUPPCState *env, target_ulong val) { PowerPCCPU *cpu = env_archcpu(env); + CPUState *cs = env_cpu(env); + CPUState *ccs; + uint32_t nr_threads = cs->nr_threads; helper_hfscr_facility_check(env, HFSCR_MSGP, "store DPDES", HFSCR_IC_MSGP); - /* TODO: TCG supports only one thread */ - if (val & ~0x1) { + if (val & ~(nr_threads - 1)) { qemu_log_mask(LOG_GUEST_ERROR, "Invalid DPDES register value " TARGET_FMT_lx"\n", val); + val &= (nr_threads - 1); /* Ignore the invalid bits */ + } + + if (nr_threads == 1) { + ppc_set_irq(cpu, PPC_INTERRUPT_DOORBELL, val & 0x1); return; } - ppc_set_irq(cpu, PPC_INTERRUPT_DOORBELL, val & 0x1); + /* Does iothread need to be locked for walking CPU list? */ + qemu_mutex_lock_iothread(); + THREAD_SIBLING_FOREACH(cs, ccs) { + PowerPCCPU *ccpu = POWERPC_CPU(ccs); + uint32_t thread_id = ppc_cpu_tir(ccpu); + + ppc_set_irq(cpu, PPC_INTERRUPT_DOORBELL, val & (0x1 << thread_id)); + } + qemu_mutex_unlock_iothread(); } #endif /* defined(TARGET_PPC64) */ diff --git a/target/ppc/translate.c b/target/ppc/translate.c index c321a39027..372ee600b2 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -815,11 +815,19 @@ void spr_write_pcr(DisasContext *ctx, int sprn, int gprn) /* DPDES */ void spr_read_dpdes(DisasContext *ctx, int gprn, int sprn) { + if (!gen_serialize_core(ctx)) { + return; + } + gen_helper_load_dpdes(cpu_gpr[gprn], cpu_env); } void spr_write_dpdes(DisasContext *ctx, int sprn, int gprn) { + if (!gen_serialize_core(ctx)) { + return; + } + gen_helper_store_dpdes(cpu_env, cpu_gpr[gprn]); } #endif From 516cd737330a9b4d90a66136ebf738c4653b4e78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 22 Jun 2023 19:33:54 +1000 Subject: [PATCH 0126/1353] hw/ppc/spapr: Test whether TCG is enabled with tcg_enabled() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Although the PPC target only supports the TCG and KVM accelerators, QEMU supports more. We can not assume that '!kvm == tcg', so test for the correct accelerator. This also eases code review, because here we don't care about KVM, we really want to test for TCG. Reviewed-by: Greg Kurz Reviewed-by: Harsh Prateek Bora Reviewed-by: Cédric Le Goater Reviewed-by: David Gibson Signed-off-by: Philippe Mathieu-Daudé [np: Fix changelog typo noticed by Zoltan] Signed-off-by: Nicholas Piggin Signed-off-by: Cédric Le Goater --- hw/ppc/spapr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index e55905a1f0..8e7d497f25 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -2525,7 +2525,7 @@ static void spapr_set_vsmt_mode(SpaprMachineState *spapr, Error **errp) int ret; unsigned int smp_threads = ms->smp.threads; - if (!kvm_enabled() && (smp_threads > 1)) { + if (tcg_enabled() && (smp_threads > 1)) { error_setg(errp, "TCG cannot support more than 1 thread/core " "on a pseries machine"); return; From dc5e072188ea622071bab47c4f899817d6ef1295 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Thu, 22 Jun 2023 19:33:55 +1000 Subject: [PATCH 0127/1353] spapr: TCG allow up to 8-thread SMT on POWER8 and newer CPUs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PPC TCG supports SMT CPU configurations for non-hypervisor state, so permit POWER8-10 pseries machines to enable SMT. This requires PIR and TIR be set, because that's how sibling thread matching is done by TCG. spapr's nested-HV capability does not currently coexist with SMT, so that combination is prohibited (interestingly somewhat analogous to LPAR-per-core mode on real hardware which also does not support KVM). Signed-off-by: Nicholas Piggin Reviewed-by: Cédric Le Goater [ clg: Also test smp_threads when checking for POWER8 CPU and above ] Signed-off-by: Cédric Le Goater --- hw/ppc/spapr.c | 17 +++++++++++++---- hw/ppc/spapr_caps.c | 14 ++++++++++++++ hw/ppc/spapr_cpu_core.c | 7 +++++-- 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 8e7d497f25..54dbfd7fe9 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -2525,10 +2525,19 @@ static void spapr_set_vsmt_mode(SpaprMachineState *spapr, Error **errp) int ret; unsigned int smp_threads = ms->smp.threads; - if (tcg_enabled() && (smp_threads > 1)) { - error_setg(errp, "TCG cannot support more than 1 thread/core " - "on a pseries machine"); - return; + if (tcg_enabled()) { + if (smp_threads > 1 && + !ppc_type_check_compat(ms->cpu_type, CPU_POWERPC_LOGICAL_2_07, 0, + spapr->max_compat_pvr)) { + error_setg(errp, "TCG only supports SMT on POWER8 or newer CPUs"); + return; + } + + if (smp_threads > 8) { + error_setg(errp, "TCG cannot support more than 8 threads/core " + "on a pseries machine"); + return; + } } if (!is_power_of_2(smp_threads)) { error_setg(errp, "Cannot support %d threads/core on a pseries " diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c index 3fd45a6dec..5a0755d34f 100644 --- a/hw/ppc/spapr_caps.c +++ b/hw/ppc/spapr_caps.c @@ -473,6 +473,20 @@ static void cap_nested_kvm_hv_apply(SpaprMachineState *spapr, error_append_hint(errp, "Try appending -machine cap-nested-hv=off\n"); } + } else if (tcg_enabled()) { + MachineState *ms = MACHINE(spapr); + unsigned int smp_threads = ms->smp.threads; + + /* + * Nested-HV vCPU env state to L2, so SMT-shared SPR updates, for + * example, do not necessarily update the correct SPR value on sibling + * threads that are in a different guest/host context. + */ + if (smp_threads > 1) { + error_setg(errp, "TCG does not support nested-HV with SMT"); + error_append_hint(errp, "Try appending -machine cap-nested-hv=off " + "or use threads=1 with -smp\n"); + } } } diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index 9b88dd549a..a4e3c2fadd 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -255,7 +255,7 @@ static void spapr_cpu_core_unrealize(DeviceState *dev) } static bool spapr_realize_vcpu(PowerPCCPU *cpu, SpaprMachineState *spapr, - SpaprCpuCore *sc, Error **errp) + SpaprCpuCore *sc, int thread_index, Error **errp) { CPUPPCState *env = &cpu->env; CPUState *cs = CPU(cpu); @@ -267,6 +267,9 @@ static bool spapr_realize_vcpu(PowerPCCPU *cpu, SpaprMachineState *spapr, cpu_ppc_set_vhyp(cpu, PPC_VIRTUAL_HYPERVISOR(spapr)); kvmppc_set_papr(cpu); + env->spr_cb[SPR_PIR].default_value = cs->cpu_index; + env->spr_cb[SPR_TIR].default_value = thread_index; + /* Set time-base frequency to 512 MHz. vhyp must be set first. */ cpu_ppc_tb_init(env, SPAPR_TIMEBASE_FREQ); @@ -337,7 +340,7 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp) for (i = 0; i < cc->nr_threads; i++) { sc->threads[i] = spapr_create_vcpu(sc, i, errp); if (!sc->threads[i] || - !spapr_realize_vcpu(sc->threads[i], spapr, sc, errp)) { + !spapr_realize_vcpu(sc->threads[i], spapr, sc, i, errp)) { spapr_cpu_core_unrealize(dev); return; } From 8f4c627b2f1479c15822ab2123ff4bdd63c24417 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Thu, 22 Jun 2023 19:33:56 +1000 Subject: [PATCH 0128/1353] tests/avocado: boot ppc64 pseries to Linux VFS mount MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This machine can boot Linux to VFS mount, so don't stop in early boot. Signed-off-by: Nicholas Piggin Reviewed-by: Cédric Le Goater Signed-off-by: Cédric Le Goater --- tests/avocado/ppc_pseries.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/avocado/ppc_pseries.py b/tests/avocado/ppc_pseries.py index d8b04dc3ea..a152cf222e 100644 --- a/tests/avocado/ppc_pseries.py +++ b/tests/avocado/ppc_pseries.py @@ -31,5 +31,5 @@ class pseriesMachine(QemuSystemTest): self.vm.add_args('-kernel', kernel_path, '-append', kernel_command_line) self.vm.launch() - console_pattern = 'Kernel command line: %s' % kernel_command_line + console_pattern = 'VFS: Cannot open root device' wait_for_console_pattern(self, console_pattern, self.panic_message) From 242e8b4dca60574a81c92ba4b8bcb538550c6cfc Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Thu, 22 Jun 2023 19:33:57 +1000 Subject: [PATCH 0129/1353] tests/avocado: Add ppc64 pseries multiprocessor boot tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add mult-thread/core/socket Linux boot tests that ensure the right topology comes up. Of particular note is a SMT test, which is a new capability for TCG. Signed-off-by: Nicholas Piggin Reviewed-by: Cédric Le Goater Signed-off-by: Cédric Le Goater --- tests/avocado/ppc_pseries.py | 60 +++++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 5 deletions(-) diff --git a/tests/avocado/ppc_pseries.py b/tests/avocado/ppc_pseries.py index a152cf222e..ff42c770f2 100644 --- a/tests/avocado/ppc_pseries.py +++ b/tests/avocado/ppc_pseries.py @@ -14,12 +14,9 @@ class pseriesMachine(QemuSystemTest): timeout = 90 KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 ' panic_message = 'Kernel panic - not syncing' + good_message = 'VFS: Cannot open root device' - def test_ppc64_pseries(self): - """ - :avocado: tags=arch:ppc64 - :avocado: tags=machine:pseries - """ + def do_test_ppc64_linux_boot(self): kernel_url = ('https://archives.fedoraproject.org/pub/archive' '/fedora-secondary/releases/29/Everything/ppc64le/os' '/ppc/ppc64/vmlinuz') @@ -31,5 +28,58 @@ class pseriesMachine(QemuSystemTest): self.vm.add_args('-kernel', kernel_path, '-append', kernel_command_line) self.vm.launch() + + def test_ppc64_linux_boot(self): + """ + :avocado: tags=arch:ppc64 + :avocado: tags=machine:pseries + """ + + self.do_test_ppc64_linux_boot() console_pattern = 'VFS: Cannot open root device' wait_for_console_pattern(self, console_pattern, self.panic_message) + + def test_ppc64_linux_smp_boot(self): + """ + :avocado: tags=arch:ppc64 + :avocado: tags=machine:pseries + """ + + self.vm.add_args('-smp', '4') + self.do_test_ppc64_linux_boot() + console_pattern = 'smp: Brought up 1 node, 4 CPUs' + wait_for_console_pattern(self, console_pattern, self.panic_message) + wait_for_console_pattern(self, self.good_message, self.panic_message) + + def test_ppc64_linux_smt_boot(self): + """ + :avocado: tags=arch:ppc64 + :avocado: tags=machine:pseries + """ + + self.vm.add_args('-smp', '4,threads=4') + self.do_test_ppc64_linux_boot() + console_pattern = 'CPU maps initialized for 4 threads per core' + wait_for_console_pattern(self, console_pattern, self.panic_message) + console_pattern = 'smp: Brought up 1 node, 4 CPUs' + wait_for_console_pattern(self, console_pattern, self.panic_message) + wait_for_console_pattern(self, self.good_message, self.panic_message) + + def test_ppc64_linux_big_boot(self): + """ + :avocado: tags=arch:ppc64 + :avocado: tags=machine:pseries + """ + + self.vm.add_args('-smp', '16,threads=4,cores=2,sockets=2') + self.vm.add_args('-m', '512M', + '-object', 'memory-backend-ram,size=256M,id=m0', + '-object', 'memory-backend-ram,size=256M,id=m1') + self.vm.add_args('-numa', 'node,nodeid=0,memdev=m0') + self.vm.add_args('-numa', 'node,nodeid=1,memdev=m1') + self.do_test_ppc64_linux_boot() + console_pattern = 'CPU maps initialized for 4 threads per core' + wait_for_console_pattern(self, console_pattern, self.panic_message) + console_pattern = 'smp: Brought up 2 nodes, 16 CPUs' + wait_for_console_pattern(self, console_pattern, self.panic_message) + wait_for_console_pattern(self, self.good_message, self.panic_message) From 2a24e6e394c0badefd1c6b1ecf571f3663236300 Mon Sep 17 00:00:00 2001 From: Frederic Barrat Date: Thu, 22 Jun 2023 18:25:26 +0200 Subject: [PATCH 0130/1353] pnv/xive2: Add a get_config() method on the presenter class MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The presenters for xive on P9 and P10 are mostly similar but the behavior can be tuned through a few CQ registers. This patch adds a "get_config" method, which will allow to access that config from the presenter in a later patch. For now, just define the config for the TIMA version. Signed-off-by: Frederic Barrat Reviewed-by: Cédric Le Goater Signed-off-by: Cédric Le Goater --- hw/intc/pnv_xive.c | 11 +++++++++++ hw/intc/pnv_xive2.c | 12 ++++++++++++ hw/intc/spapr_xive.c | 16 ++++++++++++++++ hw/intc/xive.c | 7 +++++++ include/hw/ppc/xive.h | 3 +++ 5 files changed, 49 insertions(+) diff --git a/hw/intc/pnv_xive.c b/hw/intc/pnv_xive.c index 622f9d28b7..e536b3ec26 100644 --- a/hw/intc/pnv_xive.c +++ b/hw/intc/pnv_xive.c @@ -479,6 +479,16 @@ static int pnv_xive_match_nvt(XivePresenter *xptr, uint8_t format, return count; } +static uint32_t pnv_xive_presenter_get_config(XivePresenter *xptr) +{ + uint32_t cfg = 0; + + /* TIMA GEN1 is all P9 knows */ + cfg |= XIVE_PRESENTER_GEN1_TIMA_OS; + + return cfg; +} + static uint8_t pnv_xive_get_block_id(XiveRouter *xrtr) { return pnv_xive_block_id(PNV_XIVE(xrtr)); @@ -1991,6 +2001,7 @@ static void pnv_xive_class_init(ObjectClass *klass, void *data) xnc->notify = pnv_xive_notify; xpc->match_nvt = pnv_xive_match_nvt; + xpc->get_config = pnv_xive_presenter_get_config; }; static const TypeInfo pnv_xive_info = { diff --git a/hw/intc/pnv_xive2.c b/hw/intc/pnv_xive2.c index ec1edeb385..59534f6843 100644 --- a/hw/intc/pnv_xive2.c +++ b/hw/intc/pnv_xive2.c @@ -501,6 +501,17 @@ static int pnv_xive2_match_nvt(XivePresenter *xptr, uint8_t format, return count; } +static uint32_t pnv_xive2_presenter_get_config(XivePresenter *xptr) +{ + PnvXive2 *xive = PNV_XIVE2(xptr); + uint32_t cfg = 0; + + if (xive->cq_regs[CQ_XIVE_CFG >> 3] & CQ_XIVE_CFG_GEN1_TIMA_OS) { + cfg |= XIVE_PRESENTER_GEN1_TIMA_OS; + } + return cfg; +} + static uint8_t pnv_xive2_get_block_id(Xive2Router *xrtr) { return pnv_xive2_block_id(PNV_XIVE2(xrtr)); @@ -1987,6 +1998,7 @@ static void pnv_xive2_class_init(ObjectClass *klass, void *data) xnc->notify = pnv_xive2_notify; xpc->match_nvt = pnv_xive2_match_nvt; + xpc->get_config = pnv_xive2_presenter_get_config; }; static const TypeInfo pnv_xive2_info = { diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c index dc641cc604..8bcab2846c 100644 --- a/hw/intc/spapr_xive.c +++ b/hw/intc/spapr_xive.c @@ -475,6 +475,21 @@ static int spapr_xive_match_nvt(XivePresenter *xptr, uint8_t format, return count; } +static uint32_t spapr_xive_presenter_get_config(XivePresenter *xptr) +{ + uint32_t cfg = 0; + + /* + * Let's claim GEN1 TIMA format. If running with KVM on P10, the + * correct answer is deep in the hardware and not accessible to + * us. But it shouldn't matter as it only affects the presenter + * as seen by a guest OS. + */ + cfg |= XIVE_PRESENTER_GEN1_TIMA_OS; + + return cfg; +} + static uint8_t spapr_xive_get_block_id(XiveRouter *xrtr) { return SPAPR_XIVE_BLOCK_ID; @@ -832,6 +847,7 @@ static void spapr_xive_class_init(ObjectClass *klass, void *data) sicc->post_load = spapr_xive_post_load; xpc->match_nvt = spapr_xive_match_nvt; + xpc->get_config = spapr_xive_presenter_get_config; xpc->in_kernel = spapr_xive_in_kernel_xptr; } diff --git a/hw/intc/xive.c b/hw/intc/xive.c index 5204c14b87..34a868b185 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -461,6 +461,13 @@ static void xive_tm_push_os_ctx(XivePresenter *xptr, XiveTCTX *tctx, } } +static __attribute__((unused)) uint32_t xive_presenter_get_config(XivePresenter *xptr) +{ + XivePresenterClass *xpc = XIVE_PRESENTER_GET_CLASS(xptr); + + return xpc->get_config(xptr); +} + /* * Define a mapping of "special" operations depending on the TIMA page * offset and the size of the operation. diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h index f7eea4ca81..3dfb06e002 100644 --- a/include/hw/ppc/xive.h +++ b/include/hw/ppc/xive.h @@ -430,6 +430,8 @@ typedef struct XivePresenterClass XivePresenterClass; DECLARE_CLASS_CHECKERS(XivePresenterClass, XIVE_PRESENTER, TYPE_XIVE_PRESENTER) +#define XIVE_PRESENTER_GEN1_TIMA_OS 0x1 + struct XivePresenterClass { InterfaceClass parent; int (*match_nvt)(XivePresenter *xptr, uint8_t format, @@ -437,6 +439,7 @@ struct XivePresenterClass { bool cam_ignore, uint8_t priority, uint32_t logic_serv, XiveTCTXMatch *match); bool (*in_kernel)(const XivePresenter *xptr); + uint32_t (*get_config)(XivePresenter *xptr); }; int xive_presenter_tctx_match(XivePresenter *xptr, XiveTCTX *tctx, From 177835304b39b6ed6a7c51fd19263ac10995dbec Mon Sep 17 00:00:00 2001 From: Frederic Barrat Date: Thu, 22 Jun 2023 18:25:27 +0200 Subject: [PATCH 0131/1353] pnv/xive2: Check TIMA special ops against a dedicated array for P10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Accessing the TIMA from some specific ring/offset combination can trigger a special operation, with or without side effects. It is implemented in qemu with an array of special operations to compare accesses against. Since the presenter on P10 is pretty similar to P9, we had the full array defined for P9 and we just had a special case for P10 to treat one access differently. With a recent change, 6f2cbd133d4 ("pnv/xive2: Handle TIMA access through all ports"), we now ignore some of the bits of the TIMA address, but that patch managed to botch the detection of the special case for P10. To clean that up, this patch introduces a full array of special ops to be used for P10. The code to detect a special access is common with P9, only the array of operations differs. The presenter can pick the correct array of special ops based on its configuration introduced in a previous patch. Fixes: Coverity CID 1512997, 1512998 Fixes: 6f2cbd133d4 ("pnv/xive2: Handle TIMA access through all ports") Signed-off-by: Frederic Barrat Reviewed-by: Cédric Le Goater Signed-off-by: Cédric Le Goater --- hw/intc/pnv_xive2.c | 32 ---------------------------- hw/intc/xive.c | 52 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 43 insertions(+), 41 deletions(-) diff --git a/hw/intc/pnv_xive2.c b/hw/intc/pnv_xive2.c index 59534f6843..ed438a20ed 100644 --- a/hw/intc/pnv_xive2.c +++ b/hw/intc/pnv_xive2.c @@ -1656,17 +1656,6 @@ static const MemoryRegionOps pnv_xive2_ic_tm_indirect_ops = { /* * TIMA ops */ - -/* - * Special TIMA offsets to handle accesses in a POWER10 way. - * - * Only the CAM line updates done by the hypervisor should be handled - * specifically. - */ -#define HV_PAGE_OFFSET (XIVE_TM_HV_PAGE << TM_SHIFT) -#define HV_PUSH_OS_CTX_OFFSET (HV_PAGE_OFFSET | (TM_QW1_OS + TM_WORD2)) -#define HV_PULL_OS_CTX_OFFSET (HV_PAGE_OFFSET | TM_SPC_PULL_OS_CTX) - static void pnv_xive2_tm_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { @@ -1674,18 +1663,7 @@ static void pnv_xive2_tm_write(void *opaque, hwaddr offset, PnvXive2 *xive = pnv_xive2_tm_get_xive(cpu); XiveTCTX *tctx = XIVE_TCTX(pnv_cpu_state(cpu)->intc); XivePresenter *xptr = XIVE_PRESENTER(xive); - bool gen1_tima_os = - xive->cq_regs[CQ_XIVE_CFG >> 3] & CQ_XIVE_CFG_GEN1_TIMA_OS; - offset &= TM_ADDRESS_MASK; - - /* TODO: should we switch the TM ops table instead ? */ - if (!gen1_tima_os && offset == HV_PUSH_OS_CTX_OFFSET) { - xive2_tm_push_os_ctx(xptr, tctx, offset, value, size); - return; - } - - /* Other TM ops are the same as XIVE1 */ xive_tctx_tm_write(xptr, tctx, offset, value, size); } @@ -1695,17 +1673,7 @@ static uint64_t pnv_xive2_tm_read(void *opaque, hwaddr offset, unsigned size) PnvXive2 *xive = pnv_xive2_tm_get_xive(cpu); XiveTCTX *tctx = XIVE_TCTX(pnv_cpu_state(cpu)->intc); XivePresenter *xptr = XIVE_PRESENTER(xive); - bool gen1_tima_os = - xive->cq_regs[CQ_XIVE_CFG >> 3] & CQ_XIVE_CFG_GEN1_TIMA_OS; - offset &= TM_ADDRESS_MASK; - - /* TODO: should we switch the TM ops table instead ? */ - if (!gen1_tima_os && offset == HV_PULL_OS_CTX_OFFSET) { - return xive2_tm_pull_os_ctx(xptr, tctx, offset, size); - } - - /* Other TM ops are the same as XIVE1 */ return xive_tctx_tm_read(xptr, tctx, offset, size); } diff --git a/hw/intc/xive.c b/hw/intc/xive.c index 34a868b185..84c079b034 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -20,6 +20,7 @@ #include "monitor/monitor.h" #include "hw/irq.h" #include "hw/ppc/xive.h" +#include "hw/ppc/xive2.h" #include "hw/ppc/xive_regs.h" #include "trace.h" @@ -461,7 +462,7 @@ static void xive_tm_push_os_ctx(XivePresenter *xptr, XiveTCTX *tctx, } } -static __attribute__((unused)) uint32_t xive_presenter_get_config(XivePresenter *xptr) +static uint32_t xive_presenter_get_config(XivePresenter *xptr) { XivePresenterClass *xpc = XIVE_PRESENTER_GET_CLASS(xptr); @@ -504,14 +505,47 @@ static const XiveTmOp xive_tm_operations[] = { { XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 8, NULL, xive_tm_pull_pool_ctx }, }; -static const XiveTmOp *xive_tm_find_op(hwaddr offset, unsigned size, bool write) +static const XiveTmOp xive2_tm_operations[] = { + /* + * MMIOs below 2K : raw values and special operations without side + * effects + */ + { XIVE_TM_OS_PAGE, TM_QW1_OS + TM_CPPR, 1, xive_tm_set_os_cppr, NULL }, + { XIVE_TM_HV_PAGE, TM_QW1_OS + TM_WORD2, 4, xive2_tm_push_os_ctx, NULL }, + { XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_CPPR, 1, xive_tm_set_hv_cppr, NULL }, + { XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, xive_tm_vt_push, NULL }, + { XIVE_TM_HV_PAGE, TM_QW3_HV_PHYS + TM_WORD2, 1, NULL, xive_tm_vt_poll }, + + /* MMIOs above 2K : special operations with side effects */ + { XIVE_TM_OS_PAGE, TM_SPC_ACK_OS_REG, 2, NULL, xive_tm_ack_os_reg }, + { XIVE_TM_OS_PAGE, TM_SPC_SET_OS_PENDING, 1, xive_tm_set_os_pending, NULL }, + { XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 4, NULL, xive2_tm_pull_os_ctx }, + { XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 8, NULL, xive2_tm_pull_os_ctx }, + { XIVE_TM_HV_PAGE, TM_SPC_ACK_HV_REG, 2, NULL, xive_tm_ack_hv_reg }, + { XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 4, NULL, xive_tm_pull_pool_ctx }, + { XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 8, NULL, xive_tm_pull_pool_ctx }, +}; + +static const XiveTmOp *xive_tm_find_op(XivePresenter *xptr, hwaddr offset, + unsigned size, bool write) { uint8_t page_offset = (offset >> TM_SHIFT) & 0x3; uint32_t op_offset = offset & TM_ADDRESS_MASK; - int i; + const XiveTmOp *tm_ops; + int i, tm_ops_count; + uint32_t cfg; - for (i = 0; i < ARRAY_SIZE(xive_tm_operations); i++) { - const XiveTmOp *xto = &xive_tm_operations[i]; + cfg = xive_presenter_get_config(xptr); + if (cfg & XIVE_PRESENTER_GEN1_TIMA_OS) { + tm_ops = xive_tm_operations; + tm_ops_count = ARRAY_SIZE(xive_tm_operations); + } else { + tm_ops = xive2_tm_operations; + tm_ops_count = ARRAY_SIZE(xive2_tm_operations); + } + + for (i = 0; i < tm_ops_count; i++) { + const XiveTmOp *xto = &tm_ops[i]; /* Accesses done from a more privileged TIMA page is allowed */ if (xto->page_offset >= page_offset && @@ -542,7 +576,7 @@ void xive_tctx_tm_write(XivePresenter *xptr, XiveTCTX *tctx, hwaddr offset, * First, check for special operations in the 2K region */ if (offset & TM_SPECIAL_OP) { - xto = xive_tm_find_op(offset, size, true); + xto = xive_tm_find_op(tctx->xptr, offset, size, true); if (!xto) { qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid write access at TIMA " "@%"HWADDR_PRIx"\n", offset); @@ -555,7 +589,7 @@ void xive_tctx_tm_write(XivePresenter *xptr, XiveTCTX *tctx, hwaddr offset, /* * Then, for special operations in the region below 2K. */ - xto = xive_tm_find_op(offset, size, true); + xto = xive_tm_find_op(tctx->xptr, offset, size, true); if (xto) { xto->write_handler(xptr, tctx, offset, value, size); return; @@ -581,7 +615,7 @@ uint64_t xive_tctx_tm_read(XivePresenter *xptr, XiveTCTX *tctx, hwaddr offset, * First, check for special operations in the 2K region */ if (offset & TM_SPECIAL_OP) { - xto = xive_tm_find_op(offset, size, false); + xto = xive_tm_find_op(tctx->xptr, offset, size, false); if (!xto) { qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid read access to TIMA" "@%"HWADDR_PRIx"\n", offset); @@ -594,7 +628,7 @@ uint64_t xive_tctx_tm_read(XivePresenter *xptr, XiveTCTX *tctx, hwaddr offset, /* * Then, for special operations in the region below 2K. */ - xto = xive_tm_find_op(offset, size, false); + xto = xive_tm_find_op(tctx->xptr, offset, size, false); if (xto) { ret = xto->read_handler(xptr, tctx, offset, size); goto out; From 5eb63b88d0ac259c2f49e62b6dcc6527a5caf255 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Fri, 23 Jun 2023 22:21:35 +1000 Subject: [PATCH 0132/1353] tests/avocado: ppc test VOF bios Linux boot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VOF is the new lightweight fast pseries bios. Add a Linux boot test using VOF. More tests could be moved to use VOF becasue it's much faster, but just dip one toe in the water first here. SLOF should continue to be tested too. Signed-off-by: Nicholas Piggin Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Cédric Le Goater --- tests/avocado/ppc_pseries.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/avocado/ppc_pseries.py b/tests/avocado/ppc_pseries.py index ff42c770f2..a8311e6555 100644 --- a/tests/avocado/ppc_pseries.py +++ b/tests/avocado/ppc_pseries.py @@ -29,6 +29,17 @@ class pseriesMachine(QemuSystemTest): '-append', kernel_command_line) self.vm.launch() + def test_ppc64_vof_linux_boot(self): + """ + :avocado: tags=arch:ppc64 + :avocado: tags=machine:pseries + """ + + self.vm.add_args('-machine', 'x-vof=on') + self.do_test_ppc64_linux_boot() + console_pattern = 'VFS: Cannot open root device' + wait_for_console_pattern(self, console_pattern, self.panic_message) + def test_ppc64_linux_boot(self): """ :avocado: tags=arch:ppc64 From ac9fd9b6981cdcc0da9d7de1409cb435a0fd2abf Mon Sep 17 00:00:00 2001 From: Milan Zamazal Date: Wed, 21 Jun 2023 12:17:09 +0200 Subject: [PATCH 0133/1353] tests/qtest: Fix a comment typo in vhost-user-test.c Signed-off-by: Milan Zamazal Reviewed-by: Thomas Huth Message-Id: <20230621101710.297975-4-mzamazal@redhat.com> Signed-off-by: Thomas Huth --- tests/qtest/vhost-user-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/qtest/vhost-user-test.c b/tests/qtest/vhost-user-test.c index e4f95b2858..dfb8003597 100644 --- a/tests/qtest/vhost-user-test.c +++ b/tests/qtest/vhost-user-test.c @@ -281,7 +281,7 @@ static void read_guest_mem_server(QTestState *qts, TestServer *s) /* iterate all regions */ for (i = 0; i < s->fds_num; i++) { - /* We'll check only the region statring at 0x0*/ + /* We'll check only the region starting at 0x0 */ if (s->memory.regions[i].guest_phys_addr != 0x0) { continue; } From d4c7a56539d0bdb6fccf60af94d528613cbc7c4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 8 Jun 2023 17:40:14 +0100 Subject: [PATCH 0134/1353] gitlab: centralize the container tag name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We use a fixed container tag of 'latest' so that contributors' forks don't end up with an ever growing number of containers as they work on throwaway feature branches. This fixed tag causes problems running CI upstream in stable staging branches, however, because the stable staging branch will publish old container content that clashes with that needed by primary staging branch. This makes it impossible to reliably run CI pipelines in parallel in upstream for different staging branches. This introduces $QEMU_CI_CONTAINER_TAG global variable as a way to change which tag container publishing uses. Initially it can be set by contributors as a git push option if they want to override the default use of 'latest' eg git push gitlab -o ci.variable=QEMU_CONTAINER_TAG=fish this is useful if contributors need to run pipelines for different branches concurrently in their forks. Reviewed-by: Michael Tokarev Reviewed-by: Richard Henderson Signed-off-by: Daniel P. Berrangé Message-Id: <20230608164018.2520330-2-berrange@redhat.com> Signed-off-by: Thomas Huth --- .gitlab-ci.d/base.yml | 6 ++++++ .gitlab-ci.d/buildtest-template.yml | 4 ++-- .gitlab-ci.d/buildtest.yml | 4 ++-- .gitlab-ci.d/container-template.yml | 3 ++- .gitlab-ci.d/crossbuild-template.yml | 6 +++--- .gitlab-ci.d/static_checks.yml | 4 ++-- docs/devel/ci-jobs.rst.inc | 5 +++++ 7 files changed, 22 insertions(+), 10 deletions(-) diff --git a/.gitlab-ci.d/base.yml b/.gitlab-ci.d/base.yml index 2fbb58d2a3..fba9d31cc6 100644 --- a/.gitlab-ci.d/base.yml +++ b/.gitlab-ci.d/base.yml @@ -1,4 +1,10 @@ +variables: + # On stable branches this needs changing. Should also be + # overridden per pipeline if running pipelines concurrently + # for different branches in contributor forks. + QEMU_CI_CONTAINER_TAG: latest + # The order of rules defined here is critically important. # They are evaluated in order and first match wins. # diff --git a/.gitlab-ci.d/buildtest-template.yml b/.gitlab-ci.d/buildtest-template.yml index 76ff1dfcb6..5da61f4277 100644 --- a/.gitlab-ci.d/buildtest-template.yml +++ b/.gitlab-ci.d/buildtest-template.yml @@ -1,7 +1,7 @@ .native_build_job_template: extends: .base_job_template stage: build - image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest + image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:$QEMU_CI_CONTAINER_TAG before_script: - JOBS=$(expr $(nproc) + 1) script: @@ -40,7 +40,7 @@ .common_test_job_template: extends: .base_job_template stage: test - image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest + image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:$QEMU_CI_CONTAINER_TAG script: - scripts/git-submodule.sh update roms/SLOF - meson subprojects download $(cd build/subprojects && echo *) diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml index 1922caf536..aa833b62ca 100644 --- a/.gitlab-ci.d/buildtest.yml +++ b/.gitlab-ci.d/buildtest.yml @@ -532,7 +532,7 @@ build-without-defaults: build-libvhost-user: extends: .base_job_template stage: build - image: $CI_REGISTRY_IMAGE/qemu/fedora:latest + image: $CI_REGISTRY_IMAGE/qemu/fedora:$QEMU_CI_CONTAINER_TAG needs: job: amd64-fedora-container script: @@ -572,7 +572,7 @@ build-tools-and-docs-debian: # of what topic branch they're currently using pages: extends: .base_job_template - image: $CI_REGISTRY_IMAGE/qemu/debian-amd64:latest + image: $CI_REGISTRY_IMAGE/qemu/debian-amd64:$QEMU_CI_CONTAINER_TAG stage: test needs: - job: build-tools-and-docs-debian diff --git a/.gitlab-ci.d/container-template.yml b/.gitlab-ci.d/container-template.yml index 77aa839e9e..4eec72f383 100644 --- a/.gitlab-ci.d/container-template.yml +++ b/.gitlab-ci.d/container-template.yml @@ -5,7 +5,8 @@ services: - docker:dind before_script: - - export TAG="$CI_REGISTRY_IMAGE/qemu/$NAME:latest" + - export TAG="$CI_REGISTRY_IMAGE/qemu/$NAME:$QEMU_CI_CONTAINER_TAG" + # Always ':latest' because we always use upstream as a common cache source - export COMMON_TAG="$CI_REGISTRY/qemu-project/qemu/qemu/$NAME:latest" - docker login $CI_REGISTRY -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" - until docker info; do sleep 1; done diff --git a/.gitlab-ci.d/crossbuild-template.yml b/.gitlab-ci.d/crossbuild-template.yml index 4f93b9e4e5..6efb0d2a54 100644 --- a/.gitlab-ci.d/crossbuild-template.yml +++ b/.gitlab-ci.d/crossbuild-template.yml @@ -1,7 +1,7 @@ .cross_system_build_job: extends: .base_job_template stage: build - image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest + image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:$QEMU_CI_CONTAINER_TAG timeout: 80m script: - mkdir build @@ -27,7 +27,7 @@ .cross_accel_build_job: extends: .base_job_template stage: build - image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest + image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:$QEMU_CI_CONTAINER_TAG timeout: 30m script: - mkdir build @@ -39,7 +39,7 @@ .cross_user_build_job: extends: .base_job_template stage: build - image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest + image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:$QEMU_CI_CONTAINER_TAG script: - mkdir build - cd build diff --git a/.gitlab-ci.d/static_checks.yml b/.gitlab-ci.d/static_checks.yml index b4cbdbce2a..ad9f426a52 100644 --- a/.gitlab-ci.d/static_checks.yml +++ b/.gitlab-ci.d/static_checks.yml @@ -26,7 +26,7 @@ check-dco: check-python-minreqs: extends: .base_job_template stage: test - image: $CI_REGISTRY_IMAGE/qemu/python:latest + image: $CI_REGISTRY_IMAGE/qemu/python:$QEMU_CI_CONTAINER_TAG script: - make -C python check-minreqs variables: @@ -37,7 +37,7 @@ check-python-minreqs: check-python-tox: extends: .base_job_template stage: test - image: $CI_REGISTRY_IMAGE/qemu/python:latest + image: $CI_REGISTRY_IMAGE/qemu/python:$QEMU_CI_CONTAINER_TAG script: - make -C python check-tox variables: diff --git a/docs/devel/ci-jobs.rst.inc b/docs/devel/ci-jobs.rst.inc index 1f28fec0d0..f72537853b 100644 --- a/docs/devel/ci-jobs.rst.inc +++ b/docs/devel/ci-jobs.rst.inc @@ -70,6 +70,11 @@ in a handful of namespaces repository CI settings, or as git push variables, to influence which jobs get run in a pipeline + * QEMU_CI_CONTAINER_TAG - the tag used to publish containers + in stage 1, for use by build jobs in stage 2. Defaults to + 'latest', but if running pipelines for different branches + concurrently, it should be overridden per pipeline. + * nnn - other misc variables not falling into the above categories, or using different names for historical reasons and not yet converted. From 1ddd2ff9cd873dd7d634a0b6296e91c6583b47e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 8 Jun 2023 17:40:15 +0100 Subject: [PATCH 0135/1353] gitlab: allow overriding name of the upstream repository MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CI rules have special logic for what happens in upstream. To enable contributors who modify CI rules to test this logic, however, they need to be able to override which repo is considered upstream. This introduces the 'QEMU_CI_UPSTREAM' variable git push gitlab -o ci.variable=QEMU_CI_UPSTREAM=berrange to make it look as if my namespace is the actual upstream. Namespace in this context refers to the path fragment in gitlab URLs that is above the repository. Typically this will be the contributor's gitlab login name. Reviewed-by: Richard Henderson Reviewed-by: Michael Tokarev Signed-off-by: Daniel P. Berrangé Message-Id: <20230608164018.2520330-3-berrange@redhat.com> Reviewed-by: Thomas Huth Signed-off-by: Thomas Huth --- .gitlab-ci.d/base.yml | 19 ++++++++++++------- docs/devel/ci-jobs.rst.inc | 6 ++++++ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/.gitlab-ci.d/base.yml b/.gitlab-ci.d/base.yml index fba9d31cc6..a1d734267a 100644 --- a/.gitlab-ci.d/base.yml +++ b/.gitlab-ci.d/base.yml @@ -5,6 +5,11 @@ variables: # for different branches in contributor forks. QEMU_CI_CONTAINER_TAG: latest + # For purposes of CI rules, upstream is the gitlab.com/qemu-project + # namespace. When testing CI, it might be usefult to override this + # to point to a fork repo + QEMU_CI_UPSTREAM: qemu-project + # The order of rules defined here is critically important. # They are evaluated in order and first match wins. # @@ -30,23 +35,23 @@ variables: when: never # Publishing jobs should only run on the default branch in upstream - - if: '$QEMU_JOB_PUBLISH == "1" && $CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH' + - if: '$QEMU_JOB_PUBLISH == "1" && $CI_PROJECT_NAMESPACE == $QEMU_CI_UPSTREAM && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH' when: never # Non-publishing jobs should only run on staging branches in upstream - - if: '$QEMU_JOB_PUBLISH != "1" && $CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH !~ /staging/' + - if: '$QEMU_JOB_PUBLISH != "1" && $CI_PROJECT_NAMESPACE == $QEMU_CI_UPSTREAM && $CI_COMMIT_BRANCH !~ /staging/' when: never # Jobs only intended for forks should always be skipped on upstream - - if: '$QEMU_JOB_ONLY_FORKS == "1" && $CI_PROJECT_NAMESPACE == "qemu-project"' + - if: '$QEMU_JOB_ONLY_FORKS == "1" && $CI_PROJECT_NAMESPACE == $QEMU_CI_UPSTREAM' when: never # Forks don't get pipelines unless QEMU_CI=1 or QEMU_CI=2 is set - - if: '$QEMU_CI != "1" && $QEMU_CI != "2" && $CI_PROJECT_NAMESPACE != "qemu-project"' + - if: '$QEMU_CI != "1" && $QEMU_CI != "2" && $CI_PROJECT_NAMESPACE != $QEMU_CI_UPSTREAM' when: never # Avocado jobs don't run in forks unless $QEMU_CI_AVOCADO_TESTING is set - - if: '$QEMU_JOB_AVOCADO && $QEMU_CI_AVOCADO_TESTING != "1" && $CI_PROJECT_NAMESPACE != "qemu-project"' + - if: '$QEMU_JOB_AVOCADO && $QEMU_CI_AVOCADO_TESTING != "1" && $CI_PROJECT_NAMESPACE != $QEMU_CI_UPSTREAM' when: never @@ -66,7 +71,7 @@ variables: allow_failure: true # Avocado jobs can be manually start in forks if $QEMU_CI_AVOCADO_TESTING is unset - - if: '$QEMU_JOB_AVOCADO && $CI_PROJECT_NAMESPACE != "qemu-project"' + - if: '$QEMU_JOB_AVOCADO && $CI_PROJECT_NAMESPACE != $QEMU_CI_UPSTREAM' when: manual allow_failure: true @@ -78,7 +83,7 @@ variables: # Forks pipeline jobs don't start automatically unless # QEMU_CI=2 is set - - if: '$QEMU_CI != "2" && $CI_PROJECT_NAMESPACE != "qemu-project"' + - if: '$QEMU_CI != "2" && $CI_PROJECT_NAMESPACE != $QEMU_CI_UPSTREAM' when: manual # Jobs can run if any jobs they depend on were successful diff --git a/docs/devel/ci-jobs.rst.inc b/docs/devel/ci-jobs.rst.inc index f72537853b..3f6802d51e 100644 --- a/docs/devel/ci-jobs.rst.inc +++ b/docs/devel/ci-jobs.rst.inc @@ -75,6 +75,12 @@ in a handful of namespaces 'latest', but if running pipelines for different branches concurrently, it should be overridden per pipeline. + * QEMU_CI_UPSTREAM - gitlab namespace that is considered to be + the 'upstream'. This defaults to 'qemu-project'. Contributors + may choose to override this if they are modifying rules in + base.yml and need to validate how they will operate when in + an upstream context, as opposed to their fork context. + * nnn - other misc variables not falling into the above categories, or using different names for historical reasons and not yet converted. From e28112d00703abd136e2411d23931f4f891c9244 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 8 Jun 2023 17:40:16 +0100 Subject: [PATCH 0136/1353] gitlab: stable staging branches publish containers in a separate tag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the stable staging branches publish containers under the 'latest' tag they will clash with containers published on the primary staging branch, as well as with each other. This introduces logic that overrides the container tag when jobs run against the stable staging branches. The CI_COMMIT_REF_SLUG variable we use expands to the git branch name, but with most special characters removed, such that it is valid as a docker tag name. eg 'staging-8.0' will get a slug of 'staging-8-0' Reviewed-by: Richard Henderson Reviewed-by: Michael Tokarev Signed-off-by: Daniel P. Berrangé Message-Id: <20230608164018.2520330-4-berrange@redhat.com> Signed-off-by: Thomas Huth --- .gitlab-ci.d/base.yml | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.d/base.yml b/.gitlab-ci.d/base.yml index a1d734267a..f379c182a7 100644 --- a/.gitlab-ci.d/base.yml +++ b/.gitlab-ci.d/base.yml @@ -1,7 +1,7 @@ variables: - # On stable branches this needs changing. Should also be - # overridden per pipeline if running pipelines concurrently + # On stable branches this is changed by later rules. Should also + # be overridden per pipeline if running pipelines concurrently # for different branches in contributor forks. QEMU_CI_CONTAINER_TAG: latest @@ -16,6 +16,9 @@ variables: # Thus we group them into a number of stages, ordered from # most restrictive to least restrictive # +# For pipelines running for stable "staging-X.Y" branches +# we must override QEMU_CI_CONTAINER_TAG +# .base_job_template: variables: # Each script line from will be in a collapsible section in the job output @@ -61,11 +64,23 @@ variables: ############################################################# # Optional jobs should not be run unless manually triggered + - if: '$QEMU_JOB_OPTIONAL && $CI_PROJECT_NAMESPACE == $QEMU_CI_UPSTREAM && $CI_COMMIT_BRANCH =~ /staging-[[:digit:]]+\.[[:digit:]]/' + when: manual + allow_failure: true + variables: + QEMU_CI_CONTAINER_TAG: $CI_COMMIT_REF_SLUG + - if: '$QEMU_JOB_OPTIONAL' when: manual allow_failure: true # Skipped jobs should not be run unless manually triggered + - if: '$QEMU_JOB_SKIPPED && $CI_PROJECT_NAMESPACE == $QEMU_CI_UPSTREAM && $CI_COMMIT_BRANCH =~ /staging-[[:digit:]]+\.[[:digit:]]/' + when: manual + allow_failure: true + variables: + QEMU_CI_CONTAINER_TAG: $CI_COMMIT_REF_SLUG + - if: '$QEMU_JOB_SKIPPED' when: manual allow_failure: true @@ -87,4 +102,9 @@ variables: when: manual # Jobs can run if any jobs they depend on were successful + - if: '$QEMU_JOB_SKIPPED && $CI_PROJECT_NAMESPACE == $QEMU_CI_UPSTREAM && $CI_COMMIT_BRANCH =~ /staging-[[:digit:]]+\.[[:digit:]]/' + when: on_success + variables: + QEMU_CI_CONTAINER_TAG: $CI_COMMIT_REF_SLUG + - when: on_success From a77ef83cf8f2a7deeb23357fc6f005695a56a81c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 8 Jun 2023 17:40:17 +0100 Subject: [PATCH 0137/1353] gitlab: avoid extra pipelines for tags and stable branches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In upstream context we only run pipelines on staging branches, and limited publishing jobs on the default branch. We don't want to run pipelines on stable branches, or tags, because the content will have already been tested on a staging branch before getting pushed. Reviewed-by: Richard Henderson Reviewed-by: Michael Tokarev Signed-off-by: Daniel P. Berrangé Message-Id: <20230608164018.2520330-5-berrange@redhat.com> Signed-off-by: Thomas Huth --- .gitlab-ci.d/base.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.gitlab-ci.d/base.yml b/.gitlab-ci.d/base.yml index f379c182a7..999149852e 100644 --- a/.gitlab-ci.d/base.yml +++ b/.gitlab-ci.d/base.yml @@ -33,6 +33,14 @@ variables: # want jobs to run ############################################################# + # Never run jobs upstream on stable branch, staging branch jobs already ran + - if: '$CI_PROJECT_NAMESPACE == $QEMU_CI_UPSTREAM && $CI_COMMIT_BRANCH =~ /^stable-/' + when: never + + # Never run jobs upstream on tags, staging branch jobs already ran + - if: '$CI_PROJECT_NAMESPACE == $QEMU_CI_UPSTREAM && $CI_COMMIT_TAG' + when: never + # Cirrus jobs can't run unless the creds / target repo are set - if: '$QEMU_JOB_CIRRUS && ($CIRRUS_GITHUB_REPO == null || $CIRRUS_API_TOKEN == null)' when: never From 49ac76c2a0ef4a49a4d259fff28829c0a7ce8458 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 8 Jun 2023 17:40:18 +0100 Subject: [PATCH 0138/1353] gitlab: support disabling job auto-run in upstream MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In forks QEMU_CI=1 can be used to create a pipeline but not auto-run any jobs. In upstream jobs always auto-run, which is equiv of QEMU_CI=2. This supports setting QEMU_CI=1 in upstream, to disable job auto-run. This can be used to preserve CI minutes if repushing a branch to staging with a specific fix that only needs testing in limited scenarios. Signed-off-by: Daniel P. Berrangé Message-Id: <20230608164018.2520330-6-berrange@redhat.com> Reviewed-by: Richard Henderson Signed-off-by: Thomas Huth --- .gitlab-ci.d/base.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.gitlab-ci.d/base.yml b/.gitlab-ci.d/base.yml index 999149852e..188a770799 100644 --- a/.gitlab-ci.d/base.yml +++ b/.gitlab-ci.d/base.yml @@ -109,6 +109,16 @@ variables: - if: '$QEMU_CI != "2" && $CI_PROJECT_NAMESPACE != $QEMU_CI_UPSTREAM' when: manual + # Upstream pipeline jobs start automatically unless told not to + # by setting QEMU_CI=1 + - if: '$QEMU_CI == "1" && $CI_PROJECT_NAMESPACE == $QEMU_CI_UPSTREAM && $CI_COMMIT_BRANCH =~ /staging-[[:digit:]]+\.[[:digit:]]/' + when: manual + variables: + QEMU_CI_CONTAINER_TAG: $CI_COMMIT_REF_SLUG + + - if: '$QEMU_CI == "1" && $CI_PROJECT_NAMESPACE == $QEMU_CI_UPSTREAM' + when: manual + # Jobs can run if any jobs they depend on were successful - if: '$QEMU_JOB_SKIPPED && $CI_PROJECT_NAMESPACE == $QEMU_CI_UPSTREAM && $CI_COMMIT_BRANCH =~ /staging-[[:digit:]]+\.[[:digit:]]/' when: on_success From a3fcbb47901cbf6e99ad68539867ae69ec3b605a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 20 Jun 2023 17:37:19 +0200 Subject: [PATCH 0139/1353] gitlab-ci: grab msys2 meson-logs as artifacts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename build directory to "build", like most other CI builds. Signed-off-by: Marc-André Lureau Message-Id: <20230620153720.514882-2-marcandre.lureau@redhat.com> Signed-off-by: Thomas Huth --- .gitlab-ci.d/windows.yml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.d/windows.yml b/.gitlab-ci.d/windows.yml index 472bacd2e2..d45794463a 100644 --- a/.gitlab-ci.d/windows.yml +++ b/.gitlab-ci.d/windows.yml @@ -11,6 +11,11 @@ needs: [] stage: build timeout: 80m + artifacts: + name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG" + expire_in: 7 days + paths: + - build/meson-logs/testlog.txt before_script: - If ( !(Test-Path -Path msys64\var\cache ) ) { mkdir msys64\var\cache @@ -65,8 +70,8 @@ msys2-64bit: - $env:CHERE_INVOKING = 'yes' # Preserve the current working directory - $env:MSYSTEM = 'MINGW64' # Start a 64-bit MinGW environment - $env:MSYS = 'winsymlinks:native' # Enable native Windows symlink - - mkdir output - - cd output + - mkdir build + - cd build # Note: do not remove "--without-default-devices"! # commit 9f8e6cad65a6 ("gitlab-ci: Speed up the msys2-64bit job by using --without-default-devices" # changed to compile QEMU with the --without-default-devices switch @@ -115,8 +120,8 @@ msys2-32bit: - $env:CHERE_INVOKING = 'yes' # Preserve the current working directory - $env:MSYSTEM = 'MINGW32' # Start a 32-bit MinGW environment - $env:MSYS = 'winsymlinks:native' # Enable native Windows symlink - - mkdir output - - cd output + - mkdir build + - cd build - ..\msys64\usr\bin\bash -lc '../configure --target-list=ppc64-softmmu --enable-fdt=system' - ..\msys64\usr\bin\bash -lc 'make' From 81a12315ade028ae356e8f2e264344b537a9715b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 20 Jun 2023 17:37:20 +0200 Subject: [PATCH 0140/1353] gitlab-ci: add msys2 meson test to junit report MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marc-André Lureau Message-Id: <20230620153720.514882-3-marcandre.lureau@redhat.com> Signed-off-by: Thomas Huth --- .gitlab-ci.d/windows.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitlab-ci.d/windows.yml b/.gitlab-ci.d/windows.yml index d45794463a..f889a468b5 100644 --- a/.gitlab-ci.d/windows.yml +++ b/.gitlab-ci.d/windows.yml @@ -16,6 +16,8 @@ expire_in: 7 days paths: - build/meson-logs/testlog.txt + reports: + junit: "build/meson-logs/testlog.junit.xml" before_script: - If ( !(Test-Path -Path msys64\var\cache ) ) { mkdir msys64\var\cache From b197ea8636a18b0e2968b00c3a392bfc641b51a0 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 22 Jun 2023 13:41:32 +0200 Subject: [PATCH 0141/1353] tests/qtest/cxl-test: Clean up temporary directories after testing It's good style to clean up temporary directories when they are not needed anymore. Message-Id: <20230622114132.372898-1-thuth@redhat.com> Acked-by: Jonathan Cameron Signed-off-by: Thomas Huth --- tests/qtest/cxl-test.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/qtest/cxl-test.c b/tests/qtest/cxl-test.c index edcad4a0ce..a600331843 100644 --- a/tests/qtest/cxl-test.c +++ b/tests/qtest/cxl-test.c @@ -124,6 +124,7 @@ static void cxl_t3d_deprecated(void) qtest_start(cmdline->str); qtest_end(); + rmdir(tmpfs); } static void cxl_t3d_persistent(void) @@ -138,6 +139,7 @@ static void cxl_t3d_persistent(void) qtest_start(cmdline->str); qtest_end(); + rmdir(tmpfs); } static void cxl_t3d_volatile(void) From 6c5f893d1771edc49fe6d3f8580be19a42b3b118 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 23 May 2023 17:56:33 +0200 Subject: [PATCH 0142/1353] build: further refine build.ninja rules In commit b0fcc6fc7fc1 ("build: rebuild build.ninja using "meson setup --reconfigure"", 2023-05-19) I changed the build.ninja rule in the Makefile to use "meson setup" so that the Makefile would pick up a changed path to the meson binary. However, there was a reason why build.ninja was rebuilt using $(NINJA) itself. Namely, ninja has its own cache of file modification times, and if it does not know about the modification that was done outside its control, it will *also* try to regenerate build.ninja. This can be simply by running "make" on a fresh tree immediately after "configure"; that will trigger an unnecessary meson run. So, apply a refinement to the rule in order to cover both cases: - track the meson binary that was used (and that is embedded in build.ninja's reconfigure rules); to do this, write build.ninja.stamp right after executing meson successfully - if it changed, force usage of "$(MESON) setup --reconfigure" to update the path in the reconfigure rule - if it didn't change, use "$(NINJA) build.ninja" just like before commit b0fcc6fc7fc1. Reported-by: Mark Cave-Ayland Tested-by: Mark Cave-Ayland Signed-off-by: Paolo Bonzini --- Makefile | 17 +++++++++++++---- configure | 1 + 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index b22bf6fba1..804a5681e0 100644 --- a/Makefile +++ b/Makefile @@ -83,16 +83,17 @@ config-host.mak: $(SRC_PATH)/configure $(SRC_PATH)/scripts/meson-buildoptions.sh @if test -f meson-private/coredata.dat; then \ ./config.status --skip-meson; \ else \ - ./config.status && touch build.ninja.stamp; \ + ./config.status; \ fi # 2. meson.stamp exists if meson has run at least once (so ninja reconfigure # works), but otherwise never needs to be updated + meson-private/coredata.dat: meson.stamp meson.stamp: config-host.mak @touch meson.stamp -# 3. ensure generated build files are up-to-date +# 3. ensure meson-generated build files are up-to-date ifneq ($(NINJA),) Makefile.ninja: build.ninja @@ -106,11 +107,19 @@ Makefile.ninja: build.ninja endif ifneq ($(MESON),) -# A separate rule is needed for Makefile dependencies to avoid -n +# The path to meson always points to pyvenv/bin/meson, but the absolute +# paths could change. In that case, force a regeneration of build.ninja. +# Note that this invocation of $(NINJA), just like when Make rebuilds +# Makefiles, does not include -n. build.ninja: build.ninja.stamp $(build-files): build.ninja.stamp: meson.stamp $(build-files) - $(MESON) setup --reconfigure $(SRC_PATH) && touch $@ + @if test "$$(cat build.ninja.stamp)" = "$(MESON)" && test -n "$(NINJA)"; then \ + $(NINJA) build.ninja; \ + else \ + echo "$(MESON) setup --reconfigure $(SRC_PATH)"; \ + $(MESON) setup --reconfigure $(SRC_PATH); \ + fi && echo "$(MESON)" > $@ Makefile.mtest: build.ninja scripts/mtest2make.py $(MESON) introspect --targets --tests --benchmarks | $(PYTHON) scripts/mtest2make.py > $@ diff --git a/configure b/configure index 01a53576a7..86363a7e50 100755 --- a/configure +++ b/configure @@ -1895,6 +1895,7 @@ if test "$skip_meson" = no; then if test "$?" -ne 0 ; then error_exit "meson setup failed" fi + echo "$meson" > build.ninja.stamp else if test -f meson-private/cmd_line.txt; then # Adjust old command line options that were removed From a0488cd0444101765744b8ea848fa4af7a2e850c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 6 Jun 2023 15:49:13 +0200 Subject: [PATCH 0143/1353] hw/remote/proxy: Remove dubious 'event_notifier-posix.c' include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit event_notifier-posix.c is registered in meson's util_ss[] source set, which is built as libqemuutil.a.p library. Both tools and system emulation binaries are linked with qemuutil, so there is no point in including this source file. Introduced in commit bd36adb8df ("multi-process: create IOHUB object to handle irq"). Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20230606134913.93724-1-philmd@linaro.org> Signed-off-by: Paolo Bonzini --- hw/remote/proxy.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/remote/proxy.c b/hw/remote/proxy.c index 1c7786b52c..2052d721e5 100644 --- a/hw/remote/proxy.c +++ b/hw/remote/proxy.c @@ -22,7 +22,6 @@ #include "qom/object.h" #include "qemu/event_notifier.h" #include "sysemu/kvm.h" -#include "util/event_notifier-posix.c" static void probe_pci_info(PCIDevice *dev, Error **errp); static void proxy_device_reset(DeviceState *dev); From a494fdb715832000ee9047a549a35aacfea8175e Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Tue, 9 May 2023 10:27:37 +1000 Subject: [PATCH 0144/1353] numa: Validate cluster and NUMA node boundary if required MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For some architectures like ARM64, multiple CPUs in one cluster can be associated with different NUMA nodes, which is irregular configuration because we shouldn't have this in baremetal environment. The irregular configuration causes Linux guest to misbehave, as the following warning messages indicate. -smp 6,maxcpus=6,sockets=2,clusters=1,cores=3,threads=1 \ -numa node,nodeid=0,cpus=0-1,memdev=ram0 \ -numa node,nodeid=1,cpus=2-3,memdev=ram1 \ -numa node,nodeid=2,cpus=4-5,memdev=ram2 \ ------------[ cut here ]------------ WARNING: CPU: 0 PID: 1 at kernel/sched/topology.c:2271 build_sched_domains+0x284/0x910 Modules linked in: CPU: 0 PID: 1 Comm: swapper/0 Not tainted 5.14.0-268.el9.aarch64 #1 pstate: 00400005 (nzcv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : build_sched_domains+0x284/0x910 lr : build_sched_domains+0x184/0x910 sp : ffff80000804bd50 x29: ffff80000804bd50 x28: 0000000000000002 x27: 0000000000000000 x26: ffff800009cf9a80 x25: 0000000000000000 x24: ffff800009cbf840 x23: ffff000080325000 x22: ffff0000005df800 x21: ffff80000a4ce508 x20: 0000000000000000 x19: ffff000080324440 x18: 0000000000000014 x17: 00000000388925c0 x16: 000000005386a066 x15: 000000009c10cc2e x14: 00000000000001c0 x13: 0000000000000001 x12: ffff00007fffb1a0 x11: ffff00007fffb180 x10: ffff80000a4ce508 x9 : 0000000000000041 x8 : ffff80000a4ce500 x7 : ffff80000a4cf920 x6 : 0000000000000001 x5 : 0000000000000001 x4 : 0000000000000007 x3 : 0000000000000002 x2 : 0000000000001000 x1 : ffff80000a4cf928 x0 : 0000000000000001 Call trace: build_sched_domains+0x284/0x910 sched_init_domains+0xac/0xe0 sched_init_smp+0x48/0xc8 kernel_init_freeable+0x140/0x1ac kernel_init+0x28/0x140 ret_from_fork+0x10/0x20 Improve the situation to warn when multiple CPUs in one cluster have been associated with different NUMA nodes. However, one NUMA node is allowed to be associated with different clusters. Signed-off-by: Gavin Shan Acked-by: Philippe Mathieu-Daudé Acked-by: Igor Mammedov Message-Id: <20230509002739.18388-2-gshan@redhat.com> Signed-off-by: Paolo Bonzini --- hw/core/machine.c | 42 ++++++++++++++++++++++++++++++++++++++++++ include/hw/boards.h | 1 + 2 files changed, 43 insertions(+) diff --git a/hw/core/machine.c b/hw/core/machine.c index 1000406211..46f8f9a2b0 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -1262,6 +1262,45 @@ static void machine_numa_finish_cpu_init(MachineState *machine) g_string_free(s, true); } +static void validate_cpu_cluster_to_numa_boundary(MachineState *ms) +{ + MachineClass *mc = MACHINE_GET_CLASS(ms); + NumaState *state = ms->numa_state; + const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms); + const CPUArchId *cpus = possible_cpus->cpus; + int i, j; + + if (state->num_nodes <= 1 || possible_cpus->len <= 1) { + return; + } + + /* + * The Linux scheduling domain can't be parsed when the multiple CPUs + * in one cluster have been associated with different NUMA nodes. However, + * it's fine to associate one NUMA node with CPUs in different clusters. + */ + for (i = 0; i < possible_cpus->len; i++) { + for (j = i + 1; j < possible_cpus->len; j++) { + if (cpus[i].props.has_socket_id && + cpus[i].props.has_cluster_id && + cpus[i].props.has_node_id && + cpus[j].props.has_socket_id && + cpus[j].props.has_cluster_id && + cpus[j].props.has_node_id && + cpus[i].props.socket_id == cpus[j].props.socket_id && + cpus[i].props.cluster_id == cpus[j].props.cluster_id && + cpus[i].props.node_id != cpus[j].props.node_id) { + warn_report("CPU-%d and CPU-%d in socket-%" PRId64 "-cluster-%" PRId64 + " have been associated with node-%" PRId64 " and node-%" PRId64 + " respectively. It can cause OSes like Linux to" + " misbehave", i, j, cpus[i].props.socket_id, + cpus[i].props.cluster_id, cpus[i].props.node_id, + cpus[j].props.node_id); + } + } + } +} + MemoryRegion *machine_consume_memdev(MachineState *machine, HostMemoryBackend *backend) { @@ -1355,6 +1394,9 @@ void machine_run_board_init(MachineState *machine, const char *mem_path, Error * numa_complete_configuration(machine); if (machine->numa_state->num_nodes) { machine_numa_finish_cpu_init(machine); + if (machine_class->cpu_cluster_has_numa_boundary) { + validate_cpu_cluster_to_numa_boundary(machine); + } } } diff --git a/include/hw/boards.h b/include/hw/boards.h index a385010909..6b267c21ce 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -274,6 +274,7 @@ struct MachineClass { bool nvdimm_supported; bool numa_mem_supported; bool auto_enable_numa; + bool cpu_cluster_has_numa_boundary; SMPCompatProps smp_props; const char *default_ram_id; From fecff672351ace5e39adf7dbcf7a8ee748b201cb Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Tue, 9 May 2023 10:27:38 +1000 Subject: [PATCH 0145/1353] hw/arm: Validate cluster and NUMA node boundary There are two ARM machines where NUMA is aware: 'virt' and 'sbsa-ref'. Both of them are required to follow cluster-NUMA-node boundary. To enable the validation to warn about the irregular configuration where multiple CPUs in one cluster have been associated with different NUMA nodes. Signed-off-by: Gavin Shan Acked-by: Igor Mammedov Message-Id: <20230509002739.18388-3-gshan@redhat.com> Signed-off-by: Paolo Bonzini --- hw/arm/sbsa-ref.c | 2 ++ hw/arm/virt.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c index 0639f97dd5..b774d80291 100644 --- a/hw/arm/sbsa-ref.c +++ b/hw/arm/sbsa-ref.c @@ -910,6 +910,8 @@ static void sbsa_ref_class_init(ObjectClass *oc, void *data) mc->possible_cpu_arch_ids = sbsa_ref_possible_cpu_arch_ids; mc->cpu_index_to_instance_props = sbsa_ref_cpu_index_to_props; mc->get_default_cpu_node_id = sbsa_ref_get_default_cpu_node_id; + /* platform instead of architectural choice */ + mc->cpu_cluster_has_numa_boundary = true; } static const TypeInfo sbsa_ref_info = { diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 9b9f7d9c68..3937e30477 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -3033,6 +3033,8 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) mc->smp_props.clusters_supported = true; mc->auto_enable_numa_with_memhp = true; mc->auto_enable_numa_with_memdev = true; + /* platform instead of architectural choice */ + mc->cpu_cluster_has_numa_boundary = true; mc->default_ram_id = "mach-virt.ram"; mc->default_nic = "virtio-net-pci"; From 3d9981cde964ea80f9c58072ddbb4df8b5a7183a Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Tue, 9 May 2023 10:27:39 +1000 Subject: [PATCH 0146/1353] hw/riscv: Validate cluster and NUMA node boundary There are two RISCV machines where NUMA is aware: 'virt' and 'spike'. Both of them are required to follow cluster-NUMA-node boundary. To enable the validation to warn about the irregular configuration where multiple CPUs in one cluster has been associated with multiple NUMA nodes. Signed-off-by: Gavin Shan Reviewed-by: Daniel Henrique Barboza Acked-by: Igor Mammedov Acked-by: Alistair Francis Message-Id: <20230509002739.18388-4-gshan@redhat.com> Signed-off-by: Paolo Bonzini --- hw/riscv/spike.c | 2 ++ hw/riscv/virt.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index 2c5546560a..81f7e53aed 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -354,6 +354,8 @@ static void spike_machine_class_init(ObjectClass *oc, void *data) mc->cpu_index_to_instance_props = riscv_numa_cpu_index_to_props; mc->get_default_cpu_node_id = riscv_numa_get_default_cpu_node_id; mc->numa_mem_supported = true; + /* platform instead of architectural choice */ + mc->cpu_cluster_has_numa_boundary = true; mc->default_ram_id = "riscv.spike.ram"; object_class_property_add_str(oc, "signature", NULL, spike_set_signature); object_class_property_set_description(oc, "signature", diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 95708d890e..ed4c27487e 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -1669,6 +1669,8 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) mc->cpu_index_to_instance_props = riscv_numa_cpu_index_to_props; mc->get_default_cpu_node_id = riscv_numa_get_default_cpu_node_id; mc->numa_mem_supported = true; + /* platform instead of architectural choice */ + mc->cpu_cluster_has_numa_boundary = true; mc->default_ram_id = "riscv_virt_board.ram"; assert(!mc->get_hotplug_handler); mc->get_hotplug_handler = virt_machine_get_hotplug_handler; From 3b6f485275ae95a81eec589d2773b86ca9ddec4d Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Sun, 18 Jun 2023 23:24:40 +0200 Subject: [PATCH 0147/1353] kvm: reuse per-vcpu stats fd to avoid vcpu interruption A regression has been detected in latency testing of KVM guests. More specifically, it was observed that the cyclictest numbers inside of an isolated vcpu (running on isolated pcpu) are: Where a maximum of 50us is acceptable. The implementation of KVM_GET_STATS_FD uses run_on_cpu to query per vcpu statistics, which interrupts the vcpu (and is unnecessary). To fix this, open the per vcpu stats fd on vcpu initialization, and read from that fd from QEMU's main thread. Signed-off-by: Marcelo Tosatti Signed-off-by: Paolo Bonzini --- accel/kvm/kvm-all.c | 30 +++++++++++++++--------------- include/hw/core/cpu.h | 1 + 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index 7679f397ae..9aa898db14 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -450,6 +450,8 @@ int kvm_init_vcpu(CPUState *cpu, Error **errp) "kvm_init_vcpu: kvm_arch_init_vcpu failed (%lu)", kvm_arch_vcpu_id(cpu)); } + cpu->kvm_vcpu_stats_fd = kvm_vcpu_ioctl(cpu, KVM_GET_STATS_FD, NULL); + err: return ret; } @@ -4007,7 +4009,7 @@ static StatsDescriptors *find_stats_descriptors(StatsTarget target, int stats_fd /* Read stats header */ kvm_stats_header = &descriptors->kvm_stats_header; - ret = read(stats_fd, kvm_stats_header, sizeof(*kvm_stats_header)); + ret = pread(stats_fd, kvm_stats_header, sizeof(*kvm_stats_header), 0); if (ret != sizeof(*kvm_stats_header)) { error_setg(errp, "KVM stats: failed to read stats header: " "expected %zu actual %zu", @@ -4038,7 +4040,8 @@ static StatsDescriptors *find_stats_descriptors(StatsTarget target, int stats_fd } static void query_stats(StatsResultList **result, StatsTarget target, - strList *names, int stats_fd, Error **errp) + strList *names, int stats_fd, CPUState *cpu, + Error **errp) { struct kvm_stats_desc *kvm_stats_desc; struct kvm_stats_header *kvm_stats_header; @@ -4096,7 +4099,7 @@ static void query_stats(StatsResultList **result, StatsTarget target, break; case STATS_TARGET_VCPU: add_stats_entry(result, STATS_PROVIDER_KVM, - current_cpu->parent_obj.canonical_path, + cpu->parent_obj.canonical_path, stats_list); break; default: @@ -4133,10 +4136,9 @@ static void query_stats_schema(StatsSchemaList **result, StatsTarget target, add_stats_schema(result, STATS_PROVIDER_KVM, target, stats_list); } -static void query_stats_vcpu(CPUState *cpu, run_on_cpu_data data) +static void query_stats_vcpu(CPUState *cpu, StatsArgs *kvm_stats_args) { - StatsArgs *kvm_stats_args = (StatsArgs *) data.host_ptr; - int stats_fd = kvm_vcpu_ioctl(cpu, KVM_GET_STATS_FD, NULL); + int stats_fd = cpu->kvm_vcpu_stats_fd; Error *local_err = NULL; if (stats_fd == -1) { @@ -4145,14 +4147,13 @@ static void query_stats_vcpu(CPUState *cpu, run_on_cpu_data data) return; } query_stats(kvm_stats_args->result.stats, STATS_TARGET_VCPU, - kvm_stats_args->names, stats_fd, kvm_stats_args->errp); - close(stats_fd); + kvm_stats_args->names, stats_fd, cpu, + kvm_stats_args->errp); } -static void query_stats_schema_vcpu(CPUState *cpu, run_on_cpu_data data) +static void query_stats_schema_vcpu(CPUState *cpu, StatsArgs *kvm_stats_args) { - StatsArgs *kvm_stats_args = (StatsArgs *) data.host_ptr; - int stats_fd = kvm_vcpu_ioctl(cpu, KVM_GET_STATS_FD, NULL); + int stats_fd = cpu->kvm_vcpu_stats_fd; Error *local_err = NULL; if (stats_fd == -1) { @@ -4162,7 +4163,6 @@ static void query_stats_schema_vcpu(CPUState *cpu, run_on_cpu_data data) } query_stats_schema(kvm_stats_args->result.schema, STATS_TARGET_VCPU, stats_fd, kvm_stats_args->errp); - close(stats_fd); } static void query_stats_cb(StatsResultList **result, StatsTarget target, @@ -4180,7 +4180,7 @@ static void query_stats_cb(StatsResultList **result, StatsTarget target, error_setg_errno(errp, errno, "KVM stats: ioctl failed"); return; } - query_stats(result, target, names, stats_fd, errp); + query_stats(result, target, names, stats_fd, NULL, errp); close(stats_fd); break; } @@ -4194,7 +4194,7 @@ static void query_stats_cb(StatsResultList **result, StatsTarget target, if (!apply_str_list_filter(cpu->parent_obj.canonical_path, targets)) { continue; } - run_on_cpu(cpu, query_stats_vcpu, RUN_ON_CPU_HOST_PTR(&stats_args)); + query_stats_vcpu(cpu, &stats_args); } break; } @@ -4220,6 +4220,6 @@ void query_stats_schemas_cb(StatsSchemaList **result, Error **errp) if (first_cpu) { stats_args.result.schema = result; stats_args.errp = errp; - run_on_cpu(first_cpu, query_stats_schema_vcpu, RUN_ON_CPU_HOST_PTR(&stats_args)); + query_stats_schema_vcpu(first_cpu, &stats_args); } } diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 4871ad85f0..3b765beb9b 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -402,6 +402,7 @@ struct CPUState { struct kvm_dirty_gfn *kvm_dirty_gfns; uint32_t kvm_fetch_index; uint64_t dirty_pages; + int kvm_vcpu_stats_fd; /* Use by accel-block: CPU is executing an ioctl() */ QemuLockCnt in_ioctl_lock; From 4d714d1a0bf1fca9576ee53a1a5dfa3fd5ddae99 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 16 Jun 2023 23:57:30 +0200 Subject: [PATCH 0148/1353] target/i386: fix INVD vmexit Due to a typo or perhaps a brain fart, the INVD vmexit was never generated. Fix it (but not that fixing just the typo would break both INVD and WBINVD, due to a case of two wrongs making a right). Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- target/i386/tcg/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index 08c4cab73f..0de068d4b7 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -6119,7 +6119,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) case 0x108: /* invd */ case 0x109: /* wbinvd */ if (check_cpl0(s)) { - gen_svm_check_intercept(s, (b & 2) ? SVM_EXIT_INVD : SVM_EXIT_WBINVD); + gen_svm_check_intercept(s, (b & 1) ? SVM_EXIT_WBINVD : SVM_EXIT_INVD); /* nothing to do */ } break; From 8afce497e42bb279bcbc1637ecd30b70fc001947 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sat, 17 Jun 2023 00:01:58 +0200 Subject: [PATCH 0149/1353] target/i386: TCG supports 3DNow! prefetch(w) The AMD prefetch(w) instructions have not been deprecated together with the rest of 3DNow!, and in fact are even supported by newer Intel processor. Mark them as supported by TCG, as it supports all of 3DNow!. Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 1242bd541a..ff3dcd02dc 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -647,7 +647,8 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT | CPUID_EXT2_PDPE1GB | \ TCG_EXT2_X86_64_FEATURES) #define TCG_EXT3_FEATURES (CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM | \ - CPUID_EXT3_CR8LEG | CPUID_EXT3_ABM | CPUID_EXT3_SSE4A) + CPUID_EXT3_CR8LEG | CPUID_EXT3_ABM | CPUID_EXT3_SSE4A | \ + CPUID_EXT3_3DNOWPREFETCH) #define TCG_EXT4_FEATURES 0 #define TCG_SVM_FEATURES (CPUID_SVM_NPT | CPUID_SVM_VGIF | \ CPUID_SVM_SVME_ADDR_CHK) From 691925e5a3215caa6096f56070734b95054f800b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sat, 17 Jun 2023 00:05:38 +0200 Subject: [PATCH 0150/1353] target/i386: TCG supports RDSEED TCG implements RDSEED, and in fact uses qcrypto_random_bytes which is secure enough to match hardware behavior. Expose it to guests. Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index ff3dcd02dc..fc4246223d 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -657,11 +657,10 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ADX | \ CPUID_7_0_EBX_PCOMMIT | CPUID_7_0_EBX_CLFLUSHOPT | \ CPUID_7_0_EBX_CLWB | CPUID_7_0_EBX_MPX | CPUID_7_0_EBX_FSGSBASE | \ - CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_AVX2) + CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_RDSEED) /* missing: CPUID_7_0_EBX_HLE - CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM, - CPUID_7_0_EBX_RDSEED */ + CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM */ #define TCG_7_0_ECX_FEATURES (CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU | \ /* CPUID_7_0_ECX_OSPKE is dynamic */ \ CPUID_7_0_ECX_LA57 | CPUID_7_0_ECX_PKS | CPUID_7_0_ECX_VAES) From f9e0dbae7844738f2b7d8bdead7be506a8c7646d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 21 Jun 2023 00:43:22 +0200 Subject: [PATCH 0151/1353] target/i386: do not accept RDSEED if CPUID bit absent Suggested-by: Richard Henderson Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- target/i386/tcg/translate.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index 0de068d4b7..4ef45bbd71 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -3925,12 +3925,20 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) break; case 7: /* RDSEED */ + if (mod != 3 || + (s->prefix & (PREFIX_LOCK | PREFIX_REPZ | PREFIX_REPNZ)) || + !(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_RDSEED)) { + goto illegal_op; + } + goto do_rdrand; + case 6: /* RDRAND */ if (mod != 3 || (s->prefix & (PREFIX_LOCK | PREFIX_REPZ | PREFIX_REPNZ)) || !(s->cpuid_ext_features & CPUID_EXT_RDRAND)) { goto illegal_op; } + do_rdrand: translator_io_start(&s->base); gen_helper_rdrand(s->T0, cpu_env); rm = (modrm & 7) | REX_B(s); From 1420dd6a19cfbdf444af5622797d5d95a24d9461 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sat, 17 Jun 2023 01:59:35 +0200 Subject: [PATCH 0152/1353] target/i386: TCG supports XSAVEERPTR XSAVEERPTR is actually a fix for an errata; TCG does not have the issue. Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index fc4246223d..bce0cb73e8 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -678,6 +678,8 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, #define TCG_SGX_12_0_EBX_FEATURES 0 #define TCG_SGX_12_1_EAX_FEATURES 0 +#define TCG_8000_0008_EBX CPUID_8000_0008_EBX_XSAVEERPTR + FeatureWordInfo feature_word_info[FEATURE_WORDS] = { [FEAT_1_EDX] = { .type = CPUID_FEATURE_WORD, @@ -939,7 +941,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { "amd-psfd", NULL, NULL, NULL, }, .cpuid = { .eax = 0x80000008, .reg = R_EBX, }, - .tcg_features = 0, + .tcg_features = TCG_8000_0008_EBX, .unmigratable_flags = 0, }, [FEAT_8000_0021_EAX] = { From 431c51e9d48faecbd2dd3ffc49b1636f280bfe8d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 16 Jun 2023 23:58:25 +0200 Subject: [PATCH 0153/1353] target/i386: TCG supports WBNOINVD WBNOINVD is the same as INVD or WBINVD as far as TCG is concerned, since there is no cache in TCG and therefore no invalidation side effect in WBNOINVD. With respect to SVM emulation, processors that do not support WBNOINVD will ignore the prefix and treat it as WBINVD, while those that support it will generate exactly the same vmexit. Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 3 ++- target/i386/tcg/translate.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index bce0cb73e8..695e01582b 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -678,7 +678,8 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, #define TCG_SGX_12_0_EBX_FEATURES 0 #define TCG_SGX_12_1_EAX_FEATURES 0 -#define TCG_8000_0008_EBX CPUID_8000_0008_EBX_XSAVEERPTR +#define TCG_8000_0008_EBX (CPUID_8000_0008_EBX_XSAVEERPTR | \ + CPUID_8000_0008_EBX_WBNOINVD) FeatureWordInfo feature_word_info[FEATURE_WORDS] = { [FEAT_1_EDX] = { diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index 4ef45bbd71..b2e2dccb84 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -6125,7 +6125,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) break; case 0x108: /* invd */ - case 0x109: /* wbinvd */ + case 0x109: /* wbinvd; wbnoinvd with REPZ prefix */ if (check_cpl0(s)) { gen_svm_check_intercept(s, (b & 1) ? SVM_EXIT_WBINVD : SVM_EXIT_INVD); /* nothing to do */ From fd5dcb1ccd660e47fb9f74043a16539631f53386 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 19 Jun 2023 15:41:42 +0200 Subject: [PATCH 0154/1353] target/i386: Intel only supports SYSCALL/SYSRET in long mode Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 4 ++++ target/i386/tcg/translate.c | 9 ++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 695e01582b..978d24b5ec 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -6238,6 +6238,10 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, *ecx |= 1 << 1; /* CmpLegacy bit */ } } + if (tcg_enabled() && env->cpuid_vendor1 == CPUID_VENDOR_INTEL_1 && + !(env->hflags & HF_LMA_MASK)) { + *edx &= ~CPUID_EXT2_SYSCALL; + } break; case 0x80000002: case 0x80000003: diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index b2e2dccb84..ed4016f554 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -5692,7 +5692,10 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) break; #ifdef TARGET_X86_64 case 0x105: /* syscall */ - /* XXX: is it usable in real mode ? */ + /* For Intel SYSCALL is only valid in long mode */ + if (!LMA(s) && env->cpuid_vendor1 == CPUID_VENDOR_INTEL_1) { + goto illegal_op; + } gen_update_cc_op(s); gen_update_eip_cur(s); gen_helper_syscall(cpu_env, cur_insn_len_i32(s)); @@ -5702,6 +5705,10 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) gen_eob_worker(s, false, true); break; case 0x107: /* sysret */ + /* For Intel SYSRET is only valid in long mode */ + if (!LMA(s) && env->cpuid_vendor1 == CPUID_VENDOR_INTEL_1) { + goto illegal_op; + } if (!PE(s)) { gen_exception_gpf(s); } else { From 75a02adf81911c14ec51b11a8ecd6c8aabcbd049 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 19 Jun 2023 15:41:42 +0200 Subject: [PATCH 0155/1353] target/i386: AMD only supports SYSENTER/SYSEXIT in 32-bit mode Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- target/i386/tcg/translate.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index ed4016f554..a20b5af71e 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -5669,9 +5669,10 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) s->base.is_jmp = DISAS_NORETURN; break; case 0x134: /* sysenter */ - /* For Intel SYSENTER is valid on 64-bit */ - if (CODE64(s) && env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1) + /* For AMD SYSENTER is not valid in long mode */ + if (LMA(s) && env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1) { goto illegal_op; + } if (!PE(s)) { gen_exception_gpf(s); } else { @@ -5680,9 +5681,10 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) } break; case 0x135: /* sysexit */ - /* For Intel SYSEXIT is valid on 64-bit */ - if (CODE64(s) && env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1) + /* For AMD SYSEXIT is not valid in long mode */ + if (LMA(s) && env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1) { goto illegal_op; + } if (!PE(s)) { gen_exception_gpf(s); } else { From 53b9b4cc9fb956279c6494bfa7d7ea61f07bb214 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 19 Jun 2023 15:29:12 +0200 Subject: [PATCH 0156/1353] target/i386: sysret and sysexit are privileged Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- target/i386/tcg/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index a20b5af71e..66800392bb 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -5685,7 +5685,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) if (LMA(s) && env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1) { goto illegal_op; } - if (!PE(s)) { + if (!PE(s) || CPL(s) != 0) { gen_exception_gpf(s); } else { gen_helper_sysexit(cpu_env, tcg_constant_i32(dflag - 1)); @@ -5711,7 +5711,7 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) if (!LMA(s) && env->cpuid_vendor1 == CPUID_VENDOR_INTEL_1) { goto illegal_op; } - if (!PE(s)) { + if (!PE(s) || CPL(s) != 0) { gen_exception_gpf(s); } else { gen_helper_sysret(cpu_env, tcg_constant_i32(dflag - 1)); From 6750485bf42a9917a29487aec899687669104e07 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 21 Jun 2023 00:47:31 +0200 Subject: [PATCH 0157/1353] target/i386: implement RDPID in TCG RDPID corresponds to a RDMSR(TSC_AUX); however, it is unprivileged so for user-mode emulation we must provide the value that the kernel places in the MSR. For Linux, it is a combination of the current CPU and the current NUMA node, both of which can be retrieved with getcpu(2). Also try sched_getcpu(), which might be there on the BSDs. If there is no portable way to retrieve the current CPU id from userspace, return 0. RDTSCP is reimplemented as RDTSC + RDPID ECX; the differences in terms of serializability are not relevant to QEMU. Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- meson.build | 2 ++ target/i386/cpu.c | 10 +++++++++- target/i386/helper.h | 2 +- target/i386/tcg/misc_helper.c | 21 +++++++++++++++------ target/i386/tcg/translate.c | 24 +++++++++++++++++++----- 5 files changed, 46 insertions(+), 13 deletions(-) diff --git a/meson.build b/meson.build index 6ef78ea278..3e3d38badb 100644 --- a/meson.build +++ b/meson.build @@ -2232,6 +2232,8 @@ config_host_data.set('CONFIG_CLOCK_ADJTIME', cc.has_function('clock_adjtime')) config_host_data.set('CONFIG_DUP3', cc.has_function('dup3')) config_host_data.set('CONFIG_FALLOCATE', cc.has_function('fallocate')) config_host_data.set('CONFIG_POSIX_FALLOCATE', cc.has_function('posix_fallocate')) +config_host_data.set('CONFIG_GETCPU', cc.has_function('getcpu', prefix: gnu_source_prefix)) +config_host_data.set('CONFIG_SCHED_GETCPU', cc.has_function('sched_getcpu', prefix: '#include ')) # Note that we need to specify prefix: here to avoid incorrectly # thinking that Windows has posix_memalign() config_host_data.set('CONFIG_POSIX_MEMALIGN', cc.has_function('posix_memalign', prefix: '#include ')) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 978d24b5ec..4d52e612ac 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -661,9 +661,17 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, /* missing: CPUID_7_0_EBX_HLE CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM */ + +#if defined CONFIG_SOFTMMU || defined CONFIG_LINUX +#define TCG_7_0_ECX_RDPID CPUID_7_0_ECX_RDPID +#else +#define TCG_7_0_ECX_RDPID 0 +#endif #define TCG_7_0_ECX_FEATURES (CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU | \ /* CPUID_7_0_ECX_OSPKE is dynamic */ \ - CPUID_7_0_ECX_LA57 | CPUID_7_0_ECX_PKS | CPUID_7_0_ECX_VAES) + CPUID_7_0_ECX_LA57 | CPUID_7_0_ECX_PKS | CPUID_7_0_ECX_VAES | \ + TCG_7_0_ECX_RDPID) + #define TCG_7_0_EDX_FEATURES CPUID_7_0_EDX_FSRM #define TCG_7_1_EAX_FEATURES (CPUID_7_1_EAX_FZRM | CPUID_7_1_EAX_FSRS | \ CPUID_7_1_EAX_FSRC) diff --git a/target/i386/helper.h b/target/i386/helper.h index 48609c210b..c93c1d6c8f 100644 --- a/target/i386/helper.h +++ b/target/i386/helper.h @@ -69,8 +69,8 @@ DEF_HELPER_2(into, void, env, int) DEF_HELPER_FLAGS_1(single_step, TCG_CALL_NO_WG, noreturn, env) DEF_HELPER_1(rechecking_single_step, void, env) DEF_HELPER_1(cpuid, void, env) +DEF_HELPER_FLAGS_1(rdpid, TCG_CALL_NO_WG, tl, env) DEF_HELPER_1(rdtsc, void, env) -DEF_HELPER_1(rdtscp, void, env) DEF_HELPER_FLAGS_1(rdpmc, TCG_CALL_NO_WG, noreturn, env) #ifndef CONFIG_USER_ONLY diff --git a/target/i386/tcg/misc_helper.c b/target/i386/tcg/misc_helper.c index 5f7a3061ca..868f36ab7f 100644 --- a/target/i386/tcg/misc_helper.c +++ b/target/i386/tcg/misc_helper.c @@ -75,12 +75,6 @@ void helper_rdtsc(CPUX86State *env) env->regs[R_EDX] = (uint32_t)(val >> 32); } -void helper_rdtscp(CPUX86State *env) -{ - helper_rdtsc(env); - env->regs[R_ECX] = (uint32_t)(env->tsc_aux); -} - G_NORETURN void helper_rdpmc(CPUX86State *env) { if (((env->cr[4] & CR4_PCE_MASK) == 0 ) && @@ -137,3 +131,18 @@ void helper_wrpkru(CPUX86State *env, uint32_t ecx, uint64_t val) env->pkru = val; tlb_flush(cs); } + +target_ulong HELPER(rdpid)(CPUX86State *env) +{ +#if defined CONFIG_SOFTMMU + return env->tsc_aux; +#elif defined CONFIG_LINUX && defined CONFIG_GETCPU + unsigned cpu, node; + getcpu(&cpu, &node); + return (node << 12) | (cpu & 0xfff); +#elif defined CONFIG_SCHED_GETCPU + return sched_getcpu(); +#else + return 0; +#endif +} diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index 66800392bb..a6c2424133 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -3924,13 +3924,25 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) gen_cmpxchg8b(s, env, modrm); break; - case 7: /* RDSEED */ + case 7: /* RDSEED, RDPID with f3 prefix */ if (mod != 3 || - (s->prefix & (PREFIX_LOCK | PREFIX_REPZ | PREFIX_REPNZ)) || - !(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_RDSEED)) { + (s->prefix & (PREFIX_LOCK | PREFIX_REPNZ))) { goto illegal_op; } - goto do_rdrand; + if (s->prefix & PREFIX_REPZ) { + if (!(s->cpuid_ext_features & CPUID_7_0_ECX_RDPID)) { + goto illegal_op; + } + gen_helper_rdpid(s->T0, cpu_env); + rm = (modrm & 7) | REX_B(s); + gen_op_mov_reg_v(s, dflag, rm, s->T0); + break; + } else { + if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_RDSEED)) { + goto illegal_op; + } + goto do_rdrand; + } case 6: /* RDRAND */ if (mod != 3 || @@ -6125,7 +6137,9 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) gen_update_cc_op(s); gen_update_eip_cur(s); translator_io_start(&s->base); - gen_helper_rdtscp(cpu_env); + gen_helper_rdtsc(cpu_env); + gen_helper_rdpid(s->T0, cpu_env); + gen_op_mov_reg_v(s, dflag, R_ECX, s->T0); break; default: From 63fd8ef080351357c0cb0644ed63fd3e2a8833a8 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sat, 17 Jun 2023 01:01:29 +0200 Subject: [PATCH 0158/1353] target/i386: implement SYSCALL/SYSRET in 32-bit emulators AMD supports both 32-bit and 64-bit SYSCALL/SYSRET, but the TCG only exposes it for 64-bit targets. For system emulation just reuse the helper; for user-mode emulation the ABI is the same as "int $80". The BSDs does not support any fast system call mechanism in 32-bit mode so add to bsd-user the same stub that FreeBSD has for 64-bit compatibility mode. Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- bsd-user/i386/target_arch_cpu.h | 4 ++++ linux-user/i386/cpu_loop.c | 9 +++++---- target/i386/cpu.c | 4 ++-- target/i386/helper.h | 2 -- target/i386/tcg/seg_helper.c | 7 +++++-- target/i386/tcg/sysemu/seg_helper.c | 7 ++++--- target/i386/tcg/translate.c | 2 -- target/i386/tcg/user/seg_helper.c | 2 -- 8 files changed, 20 insertions(+), 17 deletions(-) diff --git a/bsd-user/i386/target_arch_cpu.h b/bsd-user/i386/target_arch_cpu.h index d792dc720f..9bf2c4244b 100644 --- a/bsd-user/i386/target_arch_cpu.h +++ b/bsd-user/i386/target_arch_cpu.h @@ -164,6 +164,10 @@ static inline void target_cpu_loop(CPUX86State *env) } break; + case EXCP_SYSCALL: + /* doesn't do anything */ + break; + case EXCP_INTERRUPT: /* just indicate that signals should be handled asap */ break; diff --git a/linux-user/i386/cpu_loop.c b/linux-user/i386/cpu_loop.c index 2d0918a93f..9eeda551ea 100644 --- a/linux-user/i386/cpu_loop.c +++ b/linux-user/i386/cpu_loop.c @@ -211,6 +211,9 @@ void cpu_loop(CPUX86State *env) switch(trapnr) { case 0x80: +#ifndef TARGET_X86_64 + case EXCP_SYSCALL: +#endif /* linux syscall from int $0x80 */ ret = do_syscall(env, env->regs[R_EAX], @@ -227,9 +230,9 @@ void cpu_loop(CPUX86State *env) env->regs[R_EAX] = ret; } break; -#ifndef TARGET_ABI32 +#ifdef TARGET_X86_64 case EXCP_SYSCALL: - /* linux syscall from syscall instruction */ + /* linux syscall from syscall instruction. */ ret = do_syscall(env, env->regs[R_EAX], env->regs[R_EDI], @@ -245,8 +248,6 @@ void cpu_loop(CPUX86State *env) env->regs[R_EAX] = ret; } break; -#endif -#ifdef TARGET_X86_64 case EXCP_VSYSCALL: emulate_vsyscall(env); break; diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 4d52e612ac..c0fb6b3ad9 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -637,7 +637,7 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, CPUID_EXT_X2APIC, CPUID_EXT_TSC_DEADLINE_TIMER */ #ifdef TARGET_X86_64 -#define TCG_EXT2_X86_64_FEATURES (CPUID_EXT2_SYSCALL | CPUID_EXT2_LM) +#define TCG_EXT2_X86_64_FEATURES CPUID_EXT2_LM #else #define TCG_EXT2_X86_64_FEATURES 0 #endif @@ -645,7 +645,7 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, #define TCG_EXT2_FEATURES ((TCG_FEATURES & CPUID_EXT2_AMD_ALIASES) | \ CPUID_EXT2_NX | CPUID_EXT2_MMXEXT | CPUID_EXT2_RDTSCP | \ CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT | CPUID_EXT2_PDPE1GB | \ - TCG_EXT2_X86_64_FEATURES) + CPUID_EXT2_SYSCALL | TCG_EXT2_X86_64_FEATURES) #define TCG_EXT3_FEATURES (CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM | \ CPUID_EXT3_CR8LEG | CPUID_EXT3_ABM | CPUID_EXT3_SSE4A | \ CPUID_EXT3_3DNOWPREFETCH) diff --git a/target/i386/helper.h b/target/i386/helper.h index c93c1d6c8f..ac2b04abd6 100644 --- a/target/i386/helper.h +++ b/target/i386/helper.h @@ -51,10 +51,8 @@ DEF_HELPER_FLAGS_2(get_dr, TCG_CALL_NO_WG, tl, env, int) DEF_HELPER_1(sysenter, void, env) DEF_HELPER_2(sysexit, void, env, int) -#ifdef TARGET_X86_64 DEF_HELPER_2(syscall, void, env, int) DEF_HELPER_2(sysret, void, env, int) -#endif DEF_HELPER_FLAGS_2(pause, TCG_CALL_NO_WG, noreturn, env, int) DEF_HELPER_FLAGS_3(raise_interrupt, TCG_CALL_NO_WG, noreturn, env, int, int) DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_WG, noreturn, env, int) diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c index 03b58e94a2..e8d19c65fd 100644 --- a/target/i386/tcg/seg_helper.c +++ b/target/i386/tcg/seg_helper.c @@ -977,6 +977,7 @@ static void do_interrupt64(CPUX86State *env, int intno, int is_int, e2); env->eip = offset; } +#endif /* TARGET_X86_64 */ void helper_sysret(CPUX86State *env, int dflag) { @@ -990,6 +991,7 @@ void helper_sysret(CPUX86State *env, int dflag) raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC()); } selector = (env->star >> 48) & 0xffff; +#ifdef TARGET_X86_64 if (env->hflags & HF_LMA_MASK) { cpu_load_eflags(env, (uint32_t)(env->regs[11]), TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | @@ -1015,7 +1017,9 @@ void helper_sysret(CPUX86State *env, int dflag) DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | (3 << DESC_DPL_SHIFT) | DESC_W_MASK | DESC_A_MASK); - } else { + } else +#endif + { env->eflags |= IF_MASK; cpu_x86_load_seg_cache(env, R_CS, selector | 3, 0, 0xffffffff, @@ -1030,7 +1034,6 @@ void helper_sysret(CPUX86State *env, int dflag) DESC_W_MASK | DESC_A_MASK); } } -#endif /* TARGET_X86_64 */ /* real mode interrupt */ static void do_interrupt_real(CPUX86State *env, int intno, int is_int, diff --git a/target/i386/tcg/sysemu/seg_helper.c b/target/i386/tcg/sysemu/seg_helper.c index 2c9bd007ad..1cb5a0db45 100644 --- a/target/i386/tcg/sysemu/seg_helper.c +++ b/target/i386/tcg/sysemu/seg_helper.c @@ -26,7 +26,6 @@ #include "tcg/helper-tcg.h" #include "../seg_helper.h" -#ifdef TARGET_X86_64 void helper_syscall(CPUX86State *env, int next_eip_addend) { int selector; @@ -35,6 +34,7 @@ void helper_syscall(CPUX86State *env, int next_eip_addend) raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC()); } selector = (env->star >> 32) & 0xffff; +#ifdef TARGET_X86_64 if (env->hflags & HF_LMA_MASK) { int code64; @@ -61,7 +61,9 @@ void helper_syscall(CPUX86State *env, int next_eip_addend) } else { env->eip = env->cstar; } - } else { + } else +#endif + { env->regs[R_ECX] = (uint32_t)(env->eip + next_eip_addend); env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK); @@ -78,7 +80,6 @@ void helper_syscall(CPUX86State *env, int next_eip_addend) env->eip = (uint32_t)env->star; } } -#endif /* TARGET_X86_64 */ void handle_even_inj(CPUX86State *env, int intno, int is_int, int error_code, int is_hw, int rm) diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index a6c2424133..28cb3fb7f4 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -5704,7 +5704,6 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) s->base.is_jmp = DISAS_EOB_ONLY; } break; -#ifdef TARGET_X86_64 case 0x105: /* syscall */ /* For Intel SYSCALL is only valid in long mode */ if (!LMA(s) && env->cpuid_vendor1 == CPUID_VENDOR_INTEL_1) { @@ -5738,7 +5737,6 @@ static bool disas_insn(DisasContext *s, CPUState *cpu) gen_eob_worker(s, false, true); } break; -#endif case 0x1a2: /* cpuid */ gen_update_cc_op(s); gen_update_eip_cur(s); diff --git a/target/i386/tcg/user/seg_helper.c b/target/i386/tcg/user/seg_helper.c index 67481b0aa8..c45f2ac2ba 100644 --- a/target/i386/tcg/user/seg_helper.c +++ b/target/i386/tcg/user/seg_helper.c @@ -26,7 +26,6 @@ #include "tcg/helper-tcg.h" #include "tcg/seg_helper.h" -#ifdef TARGET_X86_64 void helper_syscall(CPUX86State *env, int next_eip_addend) { CPUState *cs = env_cpu(env); @@ -36,7 +35,6 @@ void helper_syscall(CPUX86State *env, int next_eip_addend) env->exception_next_eip = env->eip + next_eip_addend; cpu_loop_exit(cs); } -#endif /* TARGET_X86_64 */ /* * fake user mode interrupt. is_int is TRUE if coming from the int From 8edddaa23d75c57e093d99bf098a39f8cbd227c7 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sun, 18 Jun 2023 23:10:39 +0200 Subject: [PATCH 0159/1353] git-submodule.sh: allow running in validate mode without previous update The call to git-submodule.sh done in configure may happen without a previous checkout of the roms/SLOF submodule, or even without a previous run of the script. So, handle creating a .git-submodule-status file even in validate mode. If git is absent, ensure that all passed directories exists (because you should be in a fresh untar and will not have stale arguments to git-submodule.sh) but do no other checks. If git is present, ensure that .git-submodule-status contains an entry for all submodules passed on the command line. With this change, "ignore" mode is not needed anymore. Reported-by: Nina Schoetterl-Glausch Fixes: b11f9bd96f4 ("configure: move SLOF submodule handling to pc-bios/s390-ccw", 2023-06-06) Signed-off-by: Paolo Bonzini --- configure | 2 +- scripts/git-submodule.sh | 73 ++++++++++++++++++++++------------------ 2 files changed, 42 insertions(+), 33 deletions(-) diff --git a/configure b/configure index 86363a7e50..2b41c49c0d 100755 --- a/configure +++ b/configure @@ -758,7 +758,7 @@ done if ! test -e "$source_path/.git" then - git_submodules_action="ignore" + git_submodules_action="validate" fi # test for any invalid configuration combinations diff --git a/scripts/git-submodule.sh b/scripts/git-submodule.sh index 11fad2137c..335f7f5fdf 100755 --- a/scripts/git-submodule.sh +++ b/scripts/git-submodule.sh @@ -9,13 +9,22 @@ command=$1 shift maybe_modules="$@" -# if not running in a git checkout, do nothing -test "$command" = "ignore" && exit 0 - +test -z "$maybe_modules" && exit 0 test -z "$GIT" && GIT=$(command -v git) cd "$(dirname "$0")/.." +no_git_error= +if ! test -e ".git"; then + no_git_error='no git checkout exists' +elif test -z "$GIT"; then + no_git_error='git binary not found' +fi + +is_git() { + test -z "$no_git_error" +} + update_error() { echo "$0: $*" echo @@ -34,7 +43,7 @@ update_error() { } validate_error() { - if test "$1" = "validate"; then + if is_git && test "$1" = "validate"; then echo "GIT submodules checkout is out of date, and submodules" echo "configured for validate only. Please run" echo " scripts/git-submodule.sh update $maybe_modules" @@ -51,42 +60,42 @@ check_updated() { test "$CURSTATUS" = "$OLDSTATUS" } -if test -n "$maybe_modules" && ! test -e ".git" -then - echo "$0: unexpectedly called with submodules but no git checkout exists" - exit 1 +if is_git; then + test -e $substat || touch $substat + modules="" + for m in $maybe_modules + do + $GIT submodule status $m 1> /dev/null 2>&1 + if test $? = 0 + then + modules="$modules $m" + grep $m $substat > /dev/null 2>&1 || $GIT submodule status $module >> $substat + else + echo "warn: ignoring non-existent submodule $m" + fi + done +else + modules=$maybe_modules fi -if test -n "$maybe_modules" && test -z "$GIT" -then - echo "$0: unexpectedly called with submodules but git binary not found" - exit 1 -fi - -modules="" -for m in $maybe_modules -do - $GIT submodule status $m 1> /dev/null 2>&1 - if test $? = 0 - then - modules="$modules $m" - else - echo "warn: ignoring non-existent submodule $m" - fi -done - case "$command" in status|validate) - test -f "$substat" || validate_error "$command" - test -z "$maybe_modules" && exit 0 for module in $modules; do - check_updated $module || validate_error "$command" + if is_git; then + check_updated $module || validate_error "$command" + elif ! (set xyz "$module"/* && test -e "$2"); then + # The directory does not exist or it contains no files + echo "$0: sources not available for $module and $no_git_error" + validate_error "$command" + fi done - exit 0 ;; + update) - test -e $substat || touch $substat - test -z "$maybe_modules" && exit 0 + is_git || { + echo "$0: unexpectedly called with submodules but $no_git_error" + exit 1 + } $GIT submodule update --init $modules 1>/dev/null test $? -ne 0 && update_error "failed to update modules" From 42b1b9d7db48e72b10760869de20070b4afb6c2c Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Wed, 7 Jun 2023 22:01:25 +0200 Subject: [PATCH 0160/1353] hw/acpi: Fix PM control register access On pegasos2 which has ACPI as part of VT8231 south bridge the board firmware writes PM control register by accessing the second byte so addr will be 1. This wasn't handled correctly and the write went to addr 0 instead. Remove the acpi_pm1_cnt_write() function which is used only once and does not take addr into account and handle non-zero address in acpi_pm_cnt_{read|write}. This fixes ACPI shutdown with pegasos2 firmware. The issue below is possibly related to the same memory core bug. Link: https://gitlab.com/qemu-project/qemu/-/issues/360 Reviewed-by: Igor Mammedov Signed-off-by: BALATON Zoltan Message-Id: <20230607200125.A9988746377@zero.eik.bme.hu> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/acpi/core.c | 56 +++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/hw/acpi/core.c b/hw/acpi/core.c index 6da275c599..00b1e79a30 100644 --- a/hw/acpi/core.c +++ b/hw/acpi/core.c @@ -551,8 +551,35 @@ void acpi_pm_tmr_reset(ACPIREGS *ar) } /* ACPI PM1aCNT */ -static void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val) +void acpi_pm1_cnt_update(ACPIREGS *ar, + bool sci_enable, bool sci_disable) { + /* ACPI specs 3.0, 4.7.2.5 */ + if (ar->pm1.cnt.acpi_only) { + return; + } + + if (sci_enable) { + ar->pm1.cnt.cnt |= ACPI_BITMASK_SCI_ENABLE; + } else if (sci_disable) { + ar->pm1.cnt.cnt &= ~ACPI_BITMASK_SCI_ENABLE; + } +} + +static uint64_t acpi_pm_cnt_read(void *opaque, hwaddr addr, unsigned width) +{ + ACPIREGS *ar = opaque; + return ar->pm1.cnt.cnt >> addr * 8; +} + +static void acpi_pm_cnt_write(void *opaque, hwaddr addr, uint64_t val, + unsigned width) +{ + ACPIREGS *ar = opaque; + + if (addr == 1) { + val = val << 8 | (ar->pm1.cnt.cnt & 0xff); + } ar->pm1.cnt.cnt = val & ~(ACPI_BITMASK_SLEEP_ENABLE); if (val & ACPI_BITMASK_SLEEP_ENABLE) { @@ -575,33 +602,6 @@ static void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val) } } -void acpi_pm1_cnt_update(ACPIREGS *ar, - bool sci_enable, bool sci_disable) -{ - /* ACPI specs 3.0, 4.7.2.5 */ - if (ar->pm1.cnt.acpi_only) { - return; - } - - if (sci_enable) { - ar->pm1.cnt.cnt |= ACPI_BITMASK_SCI_ENABLE; - } else if (sci_disable) { - ar->pm1.cnt.cnt &= ~ACPI_BITMASK_SCI_ENABLE; - } -} - -static uint64_t acpi_pm_cnt_read(void *opaque, hwaddr addr, unsigned width) -{ - ACPIREGS *ar = opaque; - return ar->pm1.cnt.cnt; -} - -static void acpi_pm_cnt_write(void *opaque, hwaddr addr, uint64_t val, - unsigned width) -{ - acpi_pm1_cnt_write(opaque, val); -} - static const MemoryRegionOps acpi_pm_cnt_ops = { .read = acpi_pm_cnt_read, .write = acpi_pm_cnt_write, From bf376f3020dfd7bcb2c4158b4ffa85c04d44f56d Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Wed, 7 Jun 2023 15:57:16 -0500 Subject: [PATCH 0161/1353] hw/i386/pc: Default to use SMBIOS 3.0 for newer machine models MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, pc-q35 and pc-i44fx machine models are default to use SMBIOS 2.8 (32-bit entry point). Since SMBIOS 3.0 (64-bit entry point) is now fully supported since QEMU 7.0, default to use SMBIOS 3.0 for newer machine models. This is necessary to avoid the following message when launching a VM with large number of vcpus. "SMBIOS 2.1 table length 66822 exceeds 65535" Signed-off-by: Suravee Suthikulpanit Message-Id: <20230607205717.737749-2-suravee.suthikulpanit@amd.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Daniel P. Berrangé Reviewed-by: Igor Mammedov --- hw/i386/pc.c | 4 +++- hw/i386/pc_piix.c | 5 +++++ hw/i386/pc_q35.c | 5 +++++ include/hw/i386/pc.h | 1 + tests/qtest/bios-tables-test-allowed-diff.h | 1 + 5 files changed, 15 insertions(+), 1 deletion(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index fc52772fdd..8d37567e08 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1856,6 +1856,7 @@ static void pc_machine_set_max_fw_size(Object *obj, Visitor *v, static void pc_machine_initfn(Object *obj) { PCMachineState *pcms = PC_MACHINE(obj); + PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); #ifdef CONFIG_VMPORT pcms->vmport = ON_OFF_AUTO_AUTO; @@ -1863,7 +1864,7 @@ static void pc_machine_initfn(Object *obj) pcms->vmport = ON_OFF_AUTO_OFF; #endif /* CONFIG_VMPORT */ pcms->max_ram_below_4g = 0; /* use default */ - pcms->smbios_entry_point_type = SMBIOS_ENTRY_POINT_TYPE_32; + pcms->smbios_entry_point_type = pcmc->default_smbios_ep_type; /* acpi build is enabled by default if machine supports it */ pcms->acpi_build_enabled = PC_MACHINE_GET_CLASS(pcms)->has_acpi_build; @@ -1975,6 +1976,7 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) mc->nvdimm_supported = true; mc->smp_props.dies_supported = true; mc->default_ram_id = "pc.ram"; + pcmc->default_smbios_ep_type = SMBIOS_ENTRY_POINT_TYPE_64; object_class_property_add(oc, PC_MACHINE_MAX_RAM_BELOW_4G, "size", pc_machine_get_max_ram_below_4g, pc_machine_set_max_ram_below_4g, diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 44146e6ff5..f9947fbc10 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -506,11 +506,16 @@ DEFINE_I440FX_MACHINE(v8_1, "pc-i440fx-8.1", NULL, static void pc_i440fx_8_0_machine_options(MachineClass *m) { + PCMachineClass *pcmc = PC_MACHINE_CLASS(m); + pc_i440fx_8_1_machine_options(m); m->alias = NULL; m->is_default = false; compat_props_add(m->compat_props, hw_compat_8_0, hw_compat_8_0_len); compat_props_add(m->compat_props, pc_compat_8_0, pc_compat_8_0_len); + + /* For pc-i44fx-8.0 and older, use SMBIOS 2.8 by default */ + pcmc->default_smbios_ep_type = SMBIOS_ENTRY_POINT_TYPE_32; } DEFINE_I440FX_MACHINE(v8_0, "pc-i440fx-8.0", NULL, diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index a9a59ed42b..cf68b80974 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -387,10 +387,15 @@ DEFINE_Q35_MACHINE(v8_1, "pc-q35-8.1", NULL, static void pc_q35_8_0_machine_options(MachineClass *m) { + PCMachineClass *pcmc = PC_MACHINE_CLASS(m); + pc_q35_8_1_machine_options(m); m->alias = NULL; compat_props_add(m->compat_props, hw_compat_8_0, hw_compat_8_0_len); compat_props_add(m->compat_props, pc_compat_8_0, pc_compat_8_0_len); + + /* For pc-q35-8.0 and older, use SMBIOS 2.8 by default */ + pcmc->default_smbios_ep_type = SMBIOS_ENTRY_POINT_TYPE_32; } DEFINE_Q35_MACHINE(v8_0, "pc-q35-8.0", NULL, diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index c661e9cc80..6eec0fc51d 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -110,6 +110,7 @@ struct PCMachineClass { bool smbios_defaults; bool smbios_legacy_mode; bool smbios_uuid_encoded; + SmbiosEntryPointType default_smbios_ep_type; /* RAM / address space compat: */ bool gigabyte_align; diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523c8b..81148a604f 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,2 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/q35/SSDT.dimmpxm", From c85cad8105e647e6aae1b0d8405c49d91994b158 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 26 Jun 2023 05:54:41 -0400 Subject: [PATCH 0162/1353] tests/data/acpi: update after SMBIOS 2.0 change Switching to SMBIOS3.0 by default shifts some addresses, so we get this change in tests/data/acpi/q35/SSDT.dimmpxm : @@ -389,6 +389,6 @@ } } - Name (MEMA, 0x07FFE000) + Name (MEMA, 0x07FFF000) } update the expected file to match. Signed-off-by: Michael S. Tsirkin --- tests/data/acpi/q35/SSDT.dimmpxm | Bin 1815 -> 1815 bytes tests/qtest/bios-tables-test-allowed-diff.h | 1 - 2 files changed, 1 deletion(-) diff --git a/tests/data/acpi/q35/SSDT.dimmpxm b/tests/data/acpi/q35/SSDT.dimmpxm index 9ea4e0d0ceaa8a5cbd706afb6d49de853fafe654..70f133412f5e0aa128ab210245a8de7304eeb843 100644 GIT binary patch delta 23 ecmbQvH=U0wIM^jboSlJzanD9BE_UVz|JeaVy9Ofw delta 23 ecmbQvH=U0wIM^jboSlJzam_|9E_UV*|JeaVTLvQl diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index 81148a604f..dfb8523c8b 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1,2 +1 @@ /* List of comma-separated changed AML files to ignore */ -"tests/data/acpi/q35/SSDT.dimmpxm", From e0001297eb2f8569e950e55dbda8ad686e4155fb Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Wed, 7 Jun 2023 15:57:17 -0500 Subject: [PATCH 0163/1353] pc: q35: Bump max_cpus to 1024 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since KVM_MAX_VCPUS is currently defined to 1024 for x86 as shown in arch/x86/include/asm/kvm_host.h, update QEMU limits to the same number. In case KVM could not support the specified number of vcpus, QEMU would return the following error message: qemu-system-x86_64: kvm_init_vcpu: kvm_get_vcpu failed (xxx): Invalid argument Also, keep max_cpus at 288 for machine version 8.0 and older. Cc: Igor Mammedov Cc: Daniel P. Berrangé Cc: Michael S. Tsirkin Cc: Julia Suvorova Reviewed-by: Igor Mammedov Signed-off-by: Suravee Suthikulpanit Message-Id: <20230607205717.737749-3-suravee.suthikulpanit@amd.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Daniel P. Berrangé --- hw/i386/pc_q35.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index cf68b80974..11a7084ea1 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -368,12 +368,12 @@ static void pc_q35_machine_options(MachineClass *m) m->default_nic = "e1000e"; m->default_kernel_irqchip_split = false; m->no_floppy = 1; + m->max_cpus = 1024; m->no_parallel = !module_object_class_by_name(TYPE_ISA_PARALLEL); machine_class_allow_dynamic_sysbus_dev(m, TYPE_AMD_IOMMU_DEVICE); machine_class_allow_dynamic_sysbus_dev(m, TYPE_INTEL_IOMMU_DEVICE); machine_class_allow_dynamic_sysbus_dev(m, TYPE_RAMFB_DEVICE); machine_class_allow_dynamic_sysbus_dev(m, TYPE_VMBUS_BRIDGE); - m->max_cpus = 288; } static void pc_q35_8_1_machine_options(MachineClass *m) @@ -396,6 +396,7 @@ static void pc_q35_8_0_machine_options(MachineClass *m) /* For pc-q35-8.0 and older, use SMBIOS 2.8 by default */ pcmc->default_smbios_ep_type = SMBIOS_ENTRY_POINT_TYPE_32; + m->max_cpus = 288; } DEFINE_Q35_MACHINE(v8_0, "pc-q35-8.0", NULL, From 8bc0049eadafb984d305c847cedff550b58e5fc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= Date: Fri, 2 Jun 2023 16:38:52 +0200 Subject: [PATCH 0164/1353] vdpa: do not block migration if device has cvq and x-svq=on MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was a mistake to forbid in all cases, as SVQ is already able to send all the CVQ messages before start forwarding data vqs. It actually caused a regression, making impossible to migrate device previously migratable. Fixes: 36e4647247f2 ("vdpa: add vhost_vdpa_net_valid_svq_features") Signed-off-by: Eugenio Pérez Message-Id: <20230602143854.1879091-2-eperezma@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Tested-by: Lei Yang --- net/vhost-vdpa.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index 46778d5313..4345f1e6de 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -915,13 +915,16 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, s->cvq_isolated = cvq_isolated; /* - * TODO: We cannot migrate devices with CVQ as there is no way to set - * the device state (MAC, MQ, etc) before starting the datapath. + * TODO: We cannot migrate devices with CVQ and no x-svq enabled as + * there is no way to set the device state (MAC, MQ, etc) before + * starting the datapath. * * Migration blocker ownership now belongs to s->vhost_vdpa. */ - error_setg(&s->vhost_vdpa.migration_blocker, - "net vdpa cannot migrate with CVQ feature"); + if (!svq) { + error_setg(&s->vhost_vdpa.migration_blocker, + "net vdpa cannot migrate with CVQ feature"); + } } ret = vhost_vdpa_add(nc, (void *)&s->vhost_vdpa, queue_pair_index, nvqs); if (ret) { From 915bf6ccd7a5c9b6cbea7a72f153597d1b98834f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= Date: Fri, 2 Jun 2023 16:38:53 +0200 Subject: [PATCH 0165/1353] vdpa: reorder vhost_vdpa_net_cvq_cmd_page_len function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need to call it from resource cleanup context, as munmap needs the size of the mappings. Signed-off-by: Eugenio Pérez Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230602143854.1879091-3-eperezma@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- net/vhost-vdpa.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index 4345f1e6de..e425fabc34 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -120,6 +120,22 @@ VHostNetState *vhost_vdpa_get_vhost_net(NetClientState *nc) return s->vhost_net; } +static size_t vhost_vdpa_net_cvq_cmd_len(void) +{ + /* + * MAC_TABLE_SET is the ctrl command that produces the longer out buffer. + * In buffer is always 1 byte, so it should fit here + */ + return sizeof(struct virtio_net_ctrl_hdr) + + 2 * sizeof(struct virtio_net_ctrl_mac) + + MAC_TABLE_ENTRIES * ETH_ALEN; +} + +static size_t vhost_vdpa_net_cvq_cmd_page_len(void) +{ + return ROUND_UP(vhost_vdpa_net_cvq_cmd_len(), qemu_real_host_page_size()); +} + static bool vhost_vdpa_net_valid_svq_features(uint64_t features, Error **errp) { uint64_t invalid_dev_features = @@ -427,22 +443,6 @@ static void vhost_vdpa_cvq_unmap_buf(struct vhost_vdpa *v, void *addr) vhost_iova_tree_remove(tree, *map); } -static size_t vhost_vdpa_net_cvq_cmd_len(void) -{ - /* - * MAC_TABLE_SET is the ctrl command that produces the longer out buffer. - * In buffer is always 1 byte, so it should fit here - */ - return sizeof(struct virtio_net_ctrl_hdr) + - 2 * sizeof(struct virtio_net_ctrl_mac) + - MAC_TABLE_ENTRIES * ETH_ALEN; -} - -static size_t vhost_vdpa_net_cvq_cmd_page_len(void) -{ - return ROUND_UP(vhost_vdpa_net_cvq_cmd_len(), qemu_real_host_page_size()); -} - /** Map CVQ buffer. */ static int vhost_vdpa_cvq_map_buf(struct vhost_vdpa *v, void *buf, size_t size, bool write) From babf8b87127ae809b31b3c0a117dcbc91aaf9aba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= Date: Fri, 2 Jun 2023 16:38:54 +0200 Subject: [PATCH 0166/1353] vdpa: map shadow vrings with MAP_SHARED MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The vdpa devices that use va addresses neeeds these maps shared. Otherwise, vhost_vdpa checks will refuse to accept the maps. The mmap call will always return a page aligned address, so removing the qemu_memalign call. Keeping the ROUND_UP for the size as we still need to DMA-map them in full. Not applying fixes tag as it never worked with va devices. Signed-off-by: Eugenio Pérez Message-Id: <20230602143854.1879091-4-eperezma@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-shadow-virtqueue.c | 18 +++++++++--------- net/vhost-vdpa.c | 16 ++++++++-------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c index bd7c12b6d3..1b1d85306c 100644 --- a/hw/virtio/vhost-shadow-virtqueue.c +++ b/hw/virtio/vhost-shadow-virtqueue.c @@ -649,7 +649,7 @@ void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd) void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev, VirtQueue *vq, VhostIOVATree *iova_tree) { - size_t desc_size, driver_size, device_size; + size_t desc_size; event_notifier_set_handler(&svq->hdev_call, vhost_svq_handle_call); svq->next_guest_avail_elem = NULL; @@ -662,14 +662,14 @@ void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev, svq->vring.num = virtio_queue_get_num(vdev, virtio_get_queue_index(vq)); svq->num_free = svq->vring.num; - driver_size = vhost_svq_driver_area_size(svq); - device_size = vhost_svq_device_area_size(svq); - svq->vring.desc = qemu_memalign(qemu_real_host_page_size(), driver_size); + svq->vring.desc = mmap(NULL, vhost_svq_driver_area_size(svq), + PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, + -1, 0); desc_size = sizeof(vring_desc_t) * svq->vring.num; svq->vring.avail = (void *)((char *)svq->vring.desc + desc_size); - memset(svq->vring.desc, 0, driver_size); - svq->vring.used = qemu_memalign(qemu_real_host_page_size(), device_size); - memset(svq->vring.used, 0, device_size); + svq->vring.used = mmap(NULL, vhost_svq_device_area_size(svq), + PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, + -1, 0); svq->desc_state = g_new0(SVQDescState, svq->vring.num); svq->desc_next = g_new0(uint16_t, svq->vring.num); for (unsigned i = 0; i < svq->vring.num - 1; i++) { @@ -712,8 +712,8 @@ void vhost_svq_stop(VhostShadowVirtqueue *svq) svq->vq = NULL; g_free(svq->desc_next); g_free(svq->desc_state); - qemu_vfree(svq->vring.desc); - qemu_vfree(svq->vring.used); + munmap(svq->vring.desc, vhost_svq_driver_area_size(svq)); + munmap(svq->vring.used, vhost_svq_device_area_size(svq)); event_notifier_set_handler(&svq->hdev_call, NULL); } diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index e425fabc34..8840ca2ea4 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -205,8 +205,8 @@ static void vhost_vdpa_cleanup(NetClientState *nc) { VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); - qemu_vfree(s->cvq_cmd_out_buffer); - qemu_vfree(s->status); + munmap(s->cvq_cmd_out_buffer, vhost_vdpa_net_cvq_cmd_page_len()); + munmap(s->status, vhost_vdpa_net_cvq_cmd_page_len()); if (s->vhost_net) { vhost_net_cleanup(s->vhost_net); g_free(s->vhost_net); @@ -903,12 +903,12 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, vhost_vdpa_net_valid_svq_features(features, &s->vhost_vdpa.migration_blocker); } else if (!is_datapath) { - s->cvq_cmd_out_buffer = qemu_memalign(qemu_real_host_page_size(), - vhost_vdpa_net_cvq_cmd_page_len()); - memset(s->cvq_cmd_out_buffer, 0, vhost_vdpa_net_cvq_cmd_page_len()); - s->status = qemu_memalign(qemu_real_host_page_size(), - vhost_vdpa_net_cvq_cmd_page_len()); - memset(s->status, 0, vhost_vdpa_net_cvq_cmd_page_len()); + s->cvq_cmd_out_buffer = mmap(NULL, vhost_vdpa_net_cvq_cmd_page_len(), + PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); + s->status = mmap(NULL, vhost_vdpa_net_cvq_cmd_page_len(), + PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, + -1, 0); s->vhost_vdpa.shadow_vq_ops = &vhost_vdpa_net_svq_ops; s->vhost_vdpa.shadow_vq_ops_opaque = s; From 0a47810b09909a432b705e89e0cb5f9c1109465f Mon Sep 17 00:00:00 2001 From: Hawkins Jiawei Date: Fri, 2 Jun 2023 19:52:13 +0800 Subject: [PATCH 0167/1353] include/hw/virtio: make some VirtIODevice const MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The VirtIODevice structure is not modified in virtio_vdev_has_feature(). Therefore, make it const to allow this function to accept const variables. Signed-off-by: Hawkins Jiawei Reviewed-by: Eugenio Pérez Martin Message-Id: <16c0561b921310a32c240a4fb6e8cee3ffee16fe.1685704856.git.yin31149@gmail.com> Tested-by: Lei Yang Reviewed-by: Eugenio Pérez Tested-by: Eugenio Pérez Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- include/hw/virtio/virtio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index af86ed7249..0492d26900 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -402,7 +402,7 @@ static inline bool virtio_has_feature(uint64_t features, unsigned int fbit) return !!(features & (1ULL << fbit)); } -static inline bool virtio_vdev_has_feature(VirtIODevice *vdev, +static inline bool virtio_vdev_has_feature(const VirtIODevice *vdev, unsigned int fbit) { return virtio_has_feature(vdev->guest_features, fbit); From 02d3bf099ba071f37145cfcc34d088e8f839072f Mon Sep 17 00:00:00 2001 From: Hawkins Jiawei Date: Fri, 2 Jun 2023 19:52:14 +0800 Subject: [PATCH 0168/1353] vdpa: reuse virtio_vdev_has_feature() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can use virtio_vdev_has_feature() instead of manually accessing the features. Signed-off-by: Hawkins Jiawei Acked-by: Eugenio Pérez Message-Id: Tested-by: Lei Yang Reviewed-by: Eugenio Pérez Tested-by: Eugenio Pérez Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- net/vhost-vdpa.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index 8840ca2ea4..c3ef0139a6 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -629,8 +629,7 @@ static ssize_t vhost_vdpa_net_load_cmd(VhostVDPAState *s, uint8_t class, static int vhost_vdpa_net_load_mac(VhostVDPAState *s, const VirtIONet *n) { - uint64_t features = n->parent_obj.guest_features; - if (features & BIT_ULL(VIRTIO_NET_F_CTRL_MAC_ADDR)) { + if (virtio_vdev_has_feature(&n->parent_obj, VIRTIO_NET_F_CTRL_MAC_ADDR)) { ssize_t dev_written = vhost_vdpa_net_load_cmd(s, VIRTIO_NET_CTRL_MAC, VIRTIO_NET_CTRL_MAC_ADDR_SET, n->mac, sizeof(n->mac)); @@ -648,10 +647,9 @@ static int vhost_vdpa_net_load_mq(VhostVDPAState *s, const VirtIONet *n) { struct virtio_net_ctrl_mq mq; - uint64_t features = n->parent_obj.guest_features; ssize_t dev_written; - if (!(features & BIT_ULL(VIRTIO_NET_F_MQ))) { + if (!virtio_vdev_has_feature(&n->parent_obj, VIRTIO_NET_F_MQ)) { return 0; } From 705e89cfaafc54491482742a756cf661b48608d2 Mon Sep 17 00:00:00 2001 From: Hawkins Jiawei Date: Fri, 2 Jun 2023 19:52:15 +0800 Subject: [PATCH 0169/1353] hw/net/virtio-net: make some VirtIONet const MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The VirtIONet structure is not modified in virtio_net_supported_guest_offloads(). Therefore, make it const to allow this function to accept const variables. Signed-off-by: Hawkins Jiawei Reviewed-by: Eugenio Pérez Message-Id: <489b09c3998ac09b9135e57a7dd8c56a4be8cdf9.1685704856.git.yin31149@gmail.com> Tested-by: Lei Yang Reviewed-by: Eugenio Pérez Tested-by: Eugenio Pérez Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/net/virtio-net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 6df6b7329d..7b27dad6c4 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -874,7 +874,7 @@ static uint64_t virtio_net_guest_offloads_by_features(uint32_t features) return guest_offloads_mask & features; } -static inline uint64_t virtio_net_supported_guest_offloads(VirtIONet *n) +static inline uint64_t virtio_net_supported_guest_offloads(const VirtIONet *n) { VirtIODevice *vdev = VIRTIO_DEVICE(n); return virtio_net_guest_offloads_by_features(vdev->guest_features); From 0b545b1e42fc61f64071c7dd6f3ce1650f328007 Mon Sep 17 00:00:00 2001 From: Hawkins Jiawei Date: Fri, 2 Jun 2023 19:52:16 +0800 Subject: [PATCH 0170/1353] virtio-net: expose virtio_net_supported_guest_offloads() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To support restoring offloads state in vdpa, it is necessary to expose the function virtio_net_supported_guest_offloads(). According to VirtIO standard, "Upon feature negotiation corresponding offload gets enabled to preserve backward compatibility.". Therefore, QEMU uses this function to get the device supported offloads. This allows QEMU to know the device's defaults and skip the control message sending if these defaults align with the driver's configuration. Note that the device's defaults can mismatch the driver's configuration only at live migration. Signed-off-by: Hawkins Jiawei Message-Id: <43679506f3f039a7aa2bdd5b49785107b5dfd7d4.1685704856.git.yin31149@gmail.com> Tested-by: Lei Yang Reviewed-by: Eugenio Pérez Tested-by: Eugenio Pérez Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/net/virtio-net.c | 2 +- include/hw/virtio/virtio-net.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 7b27dad6c4..7e8897a8bc 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -874,7 +874,7 @@ static uint64_t virtio_net_guest_offloads_by_features(uint32_t features) return guest_offloads_mask & features; } -static inline uint64_t virtio_net_supported_guest_offloads(const VirtIONet *n) +uint64_t virtio_net_supported_guest_offloads(const VirtIONet *n) { VirtIODevice *vdev = VIRTIO_DEVICE(n); return virtio_net_guest_offloads_by_features(vdev->guest_features); diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h index ef234ffe7e..5f5dcb4572 100644 --- a/include/hw/virtio/virtio-net.h +++ b/include/hw/virtio/virtio-net.h @@ -227,5 +227,6 @@ size_t virtio_net_handle_ctrl_iov(VirtIODevice *vdev, unsigned out_num); void virtio_net_set_netclient_name(VirtIONet *n, const char *name, const char *type); +uint64_t virtio_net_supported_guest_offloads(const VirtIONet *n); #endif From 0b58d3686a07f505d02edc28cfaf272a4768481c Mon Sep 17 00:00:00 2001 From: Hawkins Jiawei Date: Fri, 2 Jun 2023 19:52:17 +0800 Subject: [PATCH 0171/1353] vdpa: Add vhost_vdpa_net_load_offloads() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch introduces vhost_vdpa_net_load_offloads() to restore offloads state at device's startup. Signed-off-by: Hawkins Jiawei Message-Id: <7e2b5cad9c48c917df53d80dec27dbfeb513e1a3.1685704856.git.yin31149@gmail.com> Tested-by: Lei Yang Reviewed-by: Eugenio Pérez Tested-by: Eugenio Pérez Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- net/vhost-vdpa.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index c3ef0139a6..99d0445d90 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -664,6 +664,44 @@ static int vhost_vdpa_net_load_mq(VhostVDPAState *s, return *s->status != VIRTIO_NET_OK; } +static int vhost_vdpa_net_load_offloads(VhostVDPAState *s, + const VirtIONet *n) +{ + uint64_t offloads; + ssize_t dev_written; + + if (!virtio_vdev_has_feature(&n->parent_obj, + VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) { + return 0; + } + + if (n->curr_guest_offloads == virtio_net_supported_guest_offloads(n)) { + /* + * According to VirtIO standard, "Upon feature negotiation + * corresponding offload gets enabled to preserve + * backward compatibility.". + * + * Therefore, there is no need to send this CVQ command if the + * driver also enables all supported offloads, which aligns with + * the device's defaults. + * + * Note that the device's defaults can mismatch the driver's + * configuration only at live migration. + */ + return 0; + } + + offloads = cpu_to_le64(n->curr_guest_offloads); + dev_written = vhost_vdpa_net_load_cmd(s, VIRTIO_NET_CTRL_GUEST_OFFLOADS, + VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET, + &offloads, sizeof(offloads)); + if (unlikely(dev_written < 0)) { + return dev_written; + } + + return *s->status != VIRTIO_NET_OK; +} + static int vhost_vdpa_net_load(NetClientState *nc) { VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); @@ -686,6 +724,10 @@ static int vhost_vdpa_net_load(NetClientState *nc) if (unlikely(r)) { return r; } + r = vhost_vdpa_net_load_offloads(s, n); + if (unlikely(r)) { + return r; + } return 0; } From 4b4a1378b951930628398b3c67ccb036bdf6f012 Mon Sep 17 00:00:00 2001 From: Hawkins Jiawei Date: Fri, 2 Jun 2023 19:52:18 +0800 Subject: [PATCH 0172/1353] vdpa: Allow VIRTIO_NET_F_CTRL_GUEST_OFFLOADS in SVQ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable SVQ with VIRTIO_NET_F_CTRL_GUEST_OFFLOADS feature. Signed-off-by: Hawkins Jiawei Acked-by: Jason Wang Message-Id: <778d642ecae6deed8a218b0e6232e4d7bb96b439.1685704856.git.yin31149@gmail.com> Tested-by: Lei Yang Reviewed-by: Eugenio Pérez Tested-by: Eugenio Pérez Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- net/vhost-vdpa.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index 99d0445d90..49221937a1 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -89,6 +89,7 @@ const int vdpa_feature_bits[] = { static const uint64_t vdpa_svq_device_features = BIT_ULL(VIRTIO_NET_F_CSUM) | BIT_ULL(VIRTIO_NET_F_GUEST_CSUM) | + BIT_ULL(VIRTIO_NET_F_CTRL_GUEST_OFFLOADS) | BIT_ULL(VIRTIO_NET_F_MTU) | BIT_ULL(VIRTIO_NET_F_MAC) | BIT_ULL(VIRTIO_NET_F_GUEST_TSO4) | From 92099aa4e9a3bb6856c290afaf41c76f9e3dd9fd Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Fri, 2 Jun 2023 18:27:35 +0200 Subject: [PATCH 0173/1353] vhost: fix vhost_dev_enable_notifiers() error case MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit in vhost_dev_enable_notifiers(), if virtio_bus_set_host_notifier(true) fails, we call vhost_dev_disable_notifiers() that executes virtio_bus_set_host_notifier(false) on all queues, even on queues that have failed to be initialized. This triggers a core dump in memory_region_del_eventfd(): virtio_bus_set_host_notifier: unable to init event notifier: Too many open files (-24) vhost VQ 1 notifier binding failed: 24 .../softmmu/memory.c:2611: memory_region_del_eventfd: Assertion `i != mr->ioeventfd_nb' failed. Fix the problem by providing to vhost_dev_disable_notifiers() the number of queues to disable. Fixes: 8771589b6f81 ("vhost: simplify vhost_dev_enable_notifiers") Cc: longpeng2@huawei.com Signed-off-by: Laurent Vivier Message-Id: <20230602162735.3670785-1-lvivier@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Philippe Mathieu-Daudé --- hw/virtio/vhost.c | 65 ++++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index fb7abc9769..d116c2d6a1 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -1530,6 +1530,40 @@ void vhost_dev_cleanup(struct vhost_dev *hdev) memset(hdev, 0, sizeof(struct vhost_dev)); } +static void vhost_dev_disable_notifiers_nvqs(struct vhost_dev *hdev, + VirtIODevice *vdev, + unsigned int nvqs) +{ + BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); + int i, r; + + /* + * Batch all the host notifiers in a single transaction to avoid + * quadratic time complexity in address_space_update_ioeventfds(). + */ + memory_region_transaction_begin(); + + for (i = 0; i < nvqs; ++i) { + r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), hdev->vq_index + i, + false); + if (r < 0) { + error_report("vhost VQ %d notifier cleanup failed: %d", i, -r); + } + assert(r >= 0); + } + + /* + * The transaction expects the ioeventfds to be open when it + * commits. Do it now, before the cleanup loop. + */ + memory_region_transaction_commit(); + + for (i = 0; i < nvqs; ++i) { + virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), hdev->vq_index + i); + } + virtio_device_release_ioeventfd(vdev); +} + /* Stop processing guest IO notifications in qemu. * Start processing them in vhost in kernel. */ @@ -1559,7 +1593,7 @@ int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev) if (r < 0) { error_report("vhost VQ %d notifier binding failed: %d", i, -r); memory_region_transaction_commit(); - vhost_dev_disable_notifiers(hdev, vdev); + vhost_dev_disable_notifiers_nvqs(hdev, vdev, i); return r; } } @@ -1576,34 +1610,7 @@ int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev) */ void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev) { - BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); - int i, r; - - /* - * Batch all the host notifiers in a single transaction to avoid - * quadratic time complexity in address_space_update_ioeventfds(). - */ - memory_region_transaction_begin(); - - for (i = 0; i < hdev->nvqs; ++i) { - r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), hdev->vq_index + i, - false); - if (r < 0) { - error_report("vhost VQ %d notifier cleanup failed: %d", i, -r); - } - assert (r >= 0); - } - - /* - * The transaction expects the ioeventfds to be open when it - * commits. Do it now, before the cleanup loop. - */ - memory_region_transaction_commit(); - - for (i = 0; i < hdev->nvqs; ++i) { - virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), hdev->vq_index + i); - } - virtio_device_release_ioeventfd(vdev); + vhost_dev_disable_notifiers_nvqs(hdev, vdev, hdev->nvqs); } /* Test and clear event pending status. From 51e84244a7799172f4239482199e9b4bdcd23172 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= Date: Fri, 2 Jun 2023 19:33:28 +0200 Subject: [PATCH 0174/1353] vdpa: mask _F_CTRL_GUEST_OFFLOADS for vhost vdpa devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QEMU does not emulate it so it must be disabled as long as the backend does not support it. Signed-off-by: Eugenio Pérez Message-Id: <20230602173328.1917385-1-eperezma@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang Tested-by: Lei Yang --- net/vhost-vdpa.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index 49221937a1..75352efa39 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -58,6 +58,7 @@ const int vdpa_feature_bits[] = { VIRTIO_F_VERSION_1, VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GUEST_CSUM, + VIRTIO_NET_F_CTRL_GUEST_OFFLOADS, VIRTIO_NET_F_GSO, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6, From d45243bcfc61a3c34f96a4fc34bffcb9929daba0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= Date: Fri, 2 Jun 2023 19:34:51 +0200 Subject: [PATCH 0175/1353] vdpa: fix not using CVQ buffer in case of error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug introducing when refactoring. Otherway, the guest never received the used buffer. Fixes: be4278b65fc1 ("vdpa: extract vhost_vdpa_net_cvq_add from vhost_vdpa_net_handle_ctrl_avail") Signed-off-by: Eugenio Pérez Message-Id: <20230602173451.1917999-1-eperezma@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang Tested-by: Lei Yang --- net/vhost-vdpa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index 75352efa39..9e92b3558c 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -794,7 +794,7 @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq, } if (*s->status != VIRTIO_NET_OK) { - return VIRTIO_NET_ERR; + goto out; } status = VIRTIO_NET_ERR; From abe10037b129615f3da80f6d7c4acc3a0ec48afa Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Fri, 9 Jun 2023 11:41:07 -0500 Subject: [PATCH 0176/1353] hw/i386/pc: Clean up pc_machine_initfn To use the newly introduced PC machine class local variable. Suggested-by: Igor Mammedov Signed-off-by: Suravee Suthikulpanit Message-Id: <20230609164107.23404-1-suravee.suthikulpanit@amd.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 8d37567e08..f01d7de5ad 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1867,7 +1867,7 @@ static void pc_machine_initfn(Object *obj) pcms->smbios_entry_point_type = pcmc->default_smbios_ep_type; /* acpi build is enabled by default if machine supports it */ - pcms->acpi_build_enabled = PC_MACHINE_GET_CLASS(pcms)->has_acpi_build; + pcms->acpi_build_enabled = pcmc->has_acpi_build; pcms->smbus_enabled = true; pcms->sata_enabled = true; pcms->i8042_enabled = true; From 535a3d9a32a9e37487984c16af0167bb3c3a2025 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Sun, 11 Jun 2023 15:39:24 -0400 Subject: [PATCH 0177/1353] virtio-scsi: avoid dangling host notifier in ->ioeventfd_stop() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit virtio_scsi_dataplane_stop() calls blk_drain_all(), which invokes ->drained_begin()/->drained_end() after we've already detached the host notifier. virtio_scsi_drained_end() currently attaches the host notifier again and leaves it dangling after dataplane has stopped. This results in the following assertion failure because virtio_scsi_defer_to_dataplane() is called from the IOThread instead of the main loop thread: qemu-system-x86_64: ../softmmu/memory.c:1111: memory_region_transaction_commit: Assertion `qemu_mutex_iothread_locked()' failed. Buglink: https://gitlab.com/qemu-project/qemu/-/issues/1680 Reported-by: Jean-Louis Dupond Signed-off-by: Stefan Hajnoczi Message-Id: <20230611193924.2444914-1-stefanha@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/scsi/virtio-scsi.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 9c8ef0aaa6..45b95ea070 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -1125,7 +1125,16 @@ static void virtio_scsi_drained_begin(SCSIBus *bus) uint32_t total_queues = VIRTIO_SCSI_VQ_NUM_FIXED + s->parent_obj.conf.num_queues; - if (!s->dataplane_started) { + /* + * Drain is called when stopping dataplane but the host notifier has + * already been detached. Detaching multiple times is a no-op if nothing + * else is using the monitoring same file descriptor, but avoid it just in + * case. + * + * Also, don't detach if dataplane has not even been started yet because + * the host notifier isn't attached. + */ + if (s->dataplane_stopping || !s->dataplane_started) { return; } @@ -1143,7 +1152,14 @@ static void virtio_scsi_drained_end(SCSIBus *bus) uint32_t total_queues = VIRTIO_SCSI_VQ_NUM_FIXED + s->parent_obj.conf.num_queues; - if (!s->dataplane_started) { + /* + * Drain is called when stopping dataplane. Keep the host notifier detached + * so it's not left dangling after dataplane is stopped. + * + * Also, don't attach if dataplane has not even been started yet. We're not + * ready. + */ + if (s->dataplane_stopping || !s->dataplane_started) { return; } From f8ed3648b5b9c0cd77397ae4404f3e9e4be8a426 Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Tue, 13 Jun 2023 11:08:48 +0300 Subject: [PATCH 0178/1353] vhost-user: fully use new backend/frontend naming MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Slave/master nomenclature was replaced with backend/frontend in commit 1fc19b65279a ("vhost-user: Adopt new backend naming") This patch replaces all remaining uses of master and slave in the codebase. Signed-off-by: Emmanouil Pitsidianakis Message-Id: <20230613080849.2115347-1-manos.pitsidianakis@linaro.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Marc-André Lureau --- block/export/vhost-user-blk-server.c | 2 +- contrib/vhost-user-blk/vhost-user-blk.c | 2 +- hw/block/vhost-user-blk.c | 2 +- hw/display/vhost-user-gpu.c | 2 +- hw/input/vhost-user-input.c | 2 +- hw/net/virtio-net.c | 4 +- hw/virtio/vdpa-dev.c | 2 +- hw/virtio/vhost-user.c | 52 +++++++++++----------- hw/virtio/virtio-qmp.c | 2 +- include/hw/virtio/vhost-backend.h | 2 +- subprojects/libvhost-user/libvhost-user.c | 54 +++++++++++------------ subprojects/libvhost-user/libvhost-user.h | 20 +++++---- 12 files changed, 74 insertions(+), 72 deletions(-) diff --git a/block/export/vhost-user-blk-server.c b/block/export/vhost-user-blk-server.c index 81b59761e3..f7b5073605 100644 --- a/block/export/vhost-user-blk-server.c +++ b/block/export/vhost-user-blk-server.c @@ -167,7 +167,7 @@ vu_blk_set_config(VuDev *vu_dev, const uint8_t *data, uint8_t wce; /* don't support live migration */ - if (flags != VHOST_SET_CONFIG_TYPE_MASTER) { + if (flags != VHOST_SET_CONFIG_TYPE_FRONTEND) { return -EINVAL; } diff --git a/contrib/vhost-user-blk/vhost-user-blk.c b/contrib/vhost-user-blk/vhost-user-blk.c index 7941694e53..89e5f11a64 100644 --- a/contrib/vhost-user-blk/vhost-user-blk.c +++ b/contrib/vhost-user-blk/vhost-user-blk.c @@ -421,7 +421,7 @@ vub_set_config(VuDev *vu_dev, const uint8_t *data, int fd; /* don't support live migration */ - if (flags != VHOST_SET_CONFIG_TYPE_MASTER) { + if (flags != VHOST_SET_CONFIG_TYPE_FRONTEND) { return -1; } diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c index aff4d2b8cb..eecf3f7a81 100644 --- a/hw/block/vhost-user-blk.c +++ b/hw/block/vhost-user-blk.c @@ -81,7 +81,7 @@ static void vhost_user_blk_set_config(VirtIODevice *vdev, const uint8_t *config) ret = vhost_dev_set_config(&s->dev, &blkcfg->wce, offsetof(struct virtio_blk_config, wce), sizeof(blkcfg->wce), - VHOST_SET_CONFIG_TYPE_MASTER); + VHOST_SET_CONFIG_TYPE_FRONTEND); if (ret) { error_report("set device config space failed"); return; diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c index 1386e869e5..15f9d99d09 100644 --- a/hw/display/vhost-user-gpu.c +++ b/hw/display/vhost-user-gpu.c @@ -452,7 +452,7 @@ vhost_user_gpu_set_config(VirtIODevice *vdev, ret = vhost_dev_set_config(&g->vhost->dev, config_data, 0, sizeof(struct virtio_gpu_config), - VHOST_SET_CONFIG_TYPE_MASTER); + VHOST_SET_CONFIG_TYPE_FRONTEND); if (ret) { error_report("vhost-user-gpu: set device config space failed"); return; diff --git a/hw/input/vhost-user-input.c b/hw/input/vhost-user-input.c index 1352e372ff..4ee3542106 100644 --- a/hw/input/vhost-user-input.c +++ b/hw/input/vhost-user-input.c @@ -69,7 +69,7 @@ static void vhost_input_set_config(VirtIODevice *vdev, ret = vhost_dev_set_config(&vhi->vhost->dev, config_data, 0, sizeof(virtio_input_config), - VHOST_SET_CONFIG_TYPE_MASTER); + VHOST_SET_CONFIG_TYPE_FRONTEND); if (ret) { error_report("vhost-user-input: set device config space failed"); return; diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 7e8897a8bc..aa421a908a 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -211,7 +211,7 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config) if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) { vhost_net_set_config(get_vhost_net(nc->peer), (uint8_t *)&netcfg, 0, n->config_size, - VHOST_SET_CONFIG_TYPE_MASTER); + VHOST_SET_CONFIG_TYPE_FRONTEND); } } @@ -3733,7 +3733,7 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) struct virtio_net_config netcfg = {}; memcpy(&netcfg.mac, &n->nic_conf.macaddr, ETH_ALEN); vhost_net_set_config(get_vhost_net(nc->peer), - (uint8_t *)&netcfg, 0, ETH_ALEN, VHOST_SET_CONFIG_TYPE_MASTER); + (uint8_t *)&netcfg, 0, ETH_ALEN, VHOST_SET_CONFIG_TYPE_FRONTEND); } QTAILQ_INIT(&n->rsc_chains); n->qdev = dev; diff --git a/hw/virtio/vdpa-dev.c b/hw/virtio/vdpa-dev.c index e08e830006..363b625243 100644 --- a/hw/virtio/vdpa-dev.c +++ b/hw/virtio/vdpa-dev.c @@ -203,7 +203,7 @@ vhost_vdpa_device_set_config(VirtIODevice *vdev, const uint8_t *config) int ret; ret = vhost_dev_set_config(&s->dev, s->config, 0, s->config_size, - VHOST_SET_CONFIG_TYPE_MASTER); + VHOST_SET_CONFIG_TYPE_FRONTEND); if (ret) { error_report("set device config space failed"); return; diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 2ad75a7964..c4e0cbd702 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -124,13 +124,13 @@ typedef enum VhostUserRequest { VHOST_USER_MAX } VhostUserRequest; -typedef enum VhostUserSlaveRequest { +typedef enum VhostUserBackendRequest { VHOST_USER_BACKEND_NONE = 0, VHOST_USER_BACKEND_IOTLB_MSG = 1, VHOST_USER_BACKEND_CONFIG_CHANGE_MSG = 2, VHOST_USER_BACKEND_VRING_HOST_NOTIFIER_MSG = 3, VHOST_USER_BACKEND_MAX -} VhostUserSlaveRequest; +} VhostUserBackendRequest; typedef struct VhostUserMemoryRegion { uint64_t guest_phys_addr; @@ -245,8 +245,8 @@ struct vhost_user { struct vhost_dev *dev; /* Shared between vhost devs of the same virtio device */ VhostUserState *user; - QIOChannel *slave_ioc; - GSource *slave_src; + QIOChannel *backend_ioc; + GSource *backend_src; NotifierWithReturn postcopy_notifier; struct PostCopyFD postcopy_fd; uint64_t postcopy_client_bases[VHOST_USER_MAX_RAM_SLOTS]; @@ -1495,7 +1495,7 @@ static int vhost_user_reset_device(struct vhost_dev *dev) return vhost_user_write(dev, &msg, NULL, 0); } -static int vhost_user_slave_handle_config_change(struct vhost_dev *dev) +static int vhost_user_backend_handle_config_change(struct vhost_dev *dev) { if (!dev->config_ops || !dev->config_ops->vhost_dev_config_notifier) { return -ENOSYS; @@ -1532,7 +1532,7 @@ static VhostUserHostNotifier *fetch_or_create_notifier(VhostUserState *u, return n; } -static int vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev, +static int vhost_user_backend_handle_vring_host_notifier(struct vhost_dev *dev, VhostUserVringArea *area, int fd) { @@ -1594,16 +1594,16 @@ static int vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev, return 0; } -static void close_slave_channel(struct vhost_user *u) +static void close_backend_channel(struct vhost_user *u) { - g_source_destroy(u->slave_src); - g_source_unref(u->slave_src); - u->slave_src = NULL; - object_unref(OBJECT(u->slave_ioc)); - u->slave_ioc = NULL; + g_source_destroy(u->backend_src); + g_source_unref(u->backend_src); + u->backend_src = NULL; + object_unref(OBJECT(u->backend_ioc)); + u->backend_ioc = NULL; } -static gboolean slave_read(QIOChannel *ioc, GIOCondition condition, +static gboolean backend_read(QIOChannel *ioc, GIOCondition condition, gpointer opaque) { struct vhost_dev *dev = opaque; @@ -1645,10 +1645,10 @@ static gboolean slave_read(QIOChannel *ioc, GIOCondition condition, ret = vhost_backend_handle_iotlb_msg(dev, &payload.iotlb); break; case VHOST_USER_BACKEND_CONFIG_CHANGE_MSG: - ret = vhost_user_slave_handle_config_change(dev); + ret = vhost_user_backend_handle_config_change(dev); break; case VHOST_USER_BACKEND_VRING_HOST_NOTIFIER_MSG: - ret = vhost_user_slave_handle_vring_host_notifier(dev, &payload.area, + ret = vhost_user_backend_handle_vring_host_notifier(dev, &payload.area, fd ? fd[0] : -1); break; default: @@ -1684,7 +1684,7 @@ static gboolean slave_read(QIOChannel *ioc, GIOCondition condition, goto fdcleanup; err: - close_slave_channel(u); + close_backend_channel(u); rc = G_SOURCE_REMOVE; fdcleanup: @@ -1696,7 +1696,7 @@ fdcleanup: return rc; } -static int vhost_setup_slave_channel(struct vhost_dev *dev) +static int vhost_setup_backend_channel(struct vhost_dev *dev) { VhostUserMsg msg = { .hdr.request = VHOST_USER_SET_BACKEND_REQ_FD, @@ -1725,10 +1725,10 @@ static int vhost_setup_slave_channel(struct vhost_dev *dev) error_report_err(local_err); return -ECONNREFUSED; } - u->slave_ioc = ioc; - u->slave_src = qio_channel_add_watch_source(u->slave_ioc, + u->backend_ioc = ioc; + u->backend_src = qio_channel_add_watch_source(u->backend_ioc, G_IO_IN | G_IO_HUP, - slave_read, dev, NULL, NULL); + backend_read, dev, NULL, NULL); if (reply_supported) { msg.hdr.flags |= VHOST_USER_NEED_REPLY_MASK; @@ -1746,7 +1746,7 @@ static int vhost_setup_slave_channel(struct vhost_dev *dev) out: close(sv[1]); if (ret) { - close_slave_channel(u); + close_backend_channel(u); } return ret; @@ -2072,7 +2072,7 @@ static int vhost_user_backend_init(struct vhost_dev *dev, void *opaque, virtio_has_feature(dev->protocol_features, VHOST_USER_PROTOCOL_F_REPLY_ACK))) { error_setg(errp, "IOMMU support requires reply-ack and " - "slave-req protocol features."); + "backend-req protocol features."); return -EINVAL; } @@ -2108,7 +2108,7 @@ static int vhost_user_backend_init(struct vhost_dev *dev, void *opaque, } if (dev->vq_index == 0) { - err = vhost_setup_slave_channel(dev); + err = vhost_setup_backend_channel(dev); if (err < 0) { error_setg_errno(errp, EPROTO, "vhost_backend_init failed"); return -EPROTO; @@ -2138,8 +2138,8 @@ static int vhost_user_backend_cleanup(struct vhost_dev *dev) close(u->postcopy_fd.fd); u->postcopy_fd.handler = NULL; } - if (u->slave_ioc) { - close_slave_channel(u); + if (u->backend_ioc) { + close_backend_channel(u); } g_free(u->region_rb); u->region_rb = NULL; @@ -2235,7 +2235,7 @@ static int vhost_user_net_set_mtu(struct vhost_dev *dev, uint16_t mtu) return ret; } - /* If reply_ack supported, slave has to ack specified MTU is valid */ + /* If reply_ack supported, backend has to ack specified MTU is valid */ if (reply_supported) { return process_message_reply(dev, &msg); } diff --git a/hw/virtio/virtio-qmp.c b/hw/virtio/virtio-qmp.c index 3528fc628d..3d32dbec8d 100644 --- a/hw/virtio/virtio-qmp.c +++ b/hw/virtio/virtio-qmp.c @@ -117,7 +117,7 @@ static const qmp_virtio_feature_map_t vhost_user_protocol_map[] = { "VHOST_USER_PROTOCOL_F_CONFIG: Vhost-user messaging for virtio " "device configuration space supported"), FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_BACKEND_SEND_FD, \ - "VHOST_USER_PROTOCOL_F_BACKEND_SEND_FD: Slave fd communication " + "VHOST_USER_PROTOCOL_F_BACKEND_SEND_FD: Backend fd communication " "channel supported"), FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_HOST_NOTIFIER, \ "VHOST_USER_PROTOCOL_F_HOST_NOTIFIER: Host notifiers for specified " diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h index ec3fbae58d..31a251a9f5 100644 --- a/include/hw/virtio/vhost-backend.h +++ b/include/hw/virtio/vhost-backend.h @@ -22,7 +22,7 @@ typedef enum VhostBackendType { } VhostBackendType; typedef enum VhostSetConfigType { - VHOST_SET_CONFIG_TYPE_MASTER = 0, + VHOST_SET_CONFIG_TYPE_FRONTEND = 0, VHOST_SET_CONFIG_TYPE_MIGRATION = 1, } VhostSetConfigType; diff --git a/subprojects/libvhost-user/libvhost-user.c b/subprojects/libvhost-user/libvhost-user.c index 8fb61e2df2..0469a50101 100644 --- a/subprojects/libvhost-user/libvhost-user.c +++ b/subprojects/libvhost-user/libvhost-user.c @@ -421,8 +421,8 @@ vu_send_reply(VuDev *dev, int conn_fd, VhostUserMsg *vmsg) } /* - * Processes a reply on the slave channel. - * Entered with slave_mutex held and releases it before exit. + * Processes a reply on the backend channel. + * Entered with backend_mutex held and releases it before exit. * Returns true on success. */ static bool @@ -436,7 +436,7 @@ vu_process_message_reply(VuDev *dev, const VhostUserMsg *vmsg) goto out; } - if (!vu_message_read_default(dev, dev->slave_fd, &msg_reply)) { + if (!vu_message_read_default(dev, dev->backend_fd, &msg_reply)) { goto out; } @@ -449,7 +449,7 @@ vu_process_message_reply(VuDev *dev, const VhostUserMsg *vmsg) result = msg_reply.payload.u64 == 0; out: - pthread_mutex_unlock(&dev->slave_mutex); + pthread_mutex_unlock(&dev->backend_mutex); return result; } @@ -1393,13 +1393,13 @@ bool vu_set_queue_host_notifier(VuDev *dev, VuVirtq *vq, int fd, return false; } - pthread_mutex_lock(&dev->slave_mutex); - if (!vu_message_write(dev, dev->slave_fd, &vmsg)) { - pthread_mutex_unlock(&dev->slave_mutex); + pthread_mutex_lock(&dev->backend_mutex); + if (!vu_message_write(dev, dev->backend_fd, &vmsg)) { + pthread_mutex_unlock(&dev->backend_mutex); return false; } - /* Also unlocks the slave_mutex */ + /* Also unlocks the backend_mutex */ return vu_process_message_reply(dev, &vmsg); } @@ -1463,7 +1463,7 @@ vu_get_protocol_features_exec(VuDev *dev, VhostUserMsg *vmsg) * a device implementation can return it in its callback * (get_protocol_features) if it wants to use this for * simulation, but it is otherwise not desirable (if even - * implemented by the master.) + * implemented by the frontend.) */ uint64_t features = 1ULL << VHOST_USER_PROTOCOL_F_MQ | 1ULL << VHOST_USER_PROTOCOL_F_LOG_SHMFD | @@ -1508,7 +1508,7 @@ vu_set_protocol_features_exec(VuDev *dev, VhostUserMsg *vmsg) * of the other features are required. * Theoretically, one could use only kick messages, or do them without * having F_REPLY_ACK, but too many (possibly pending) messages on the - * socket will eventually cause the master to hang, to avoid this in + * socket will eventually cause the frontend to hang, to avoid this in * scenarios where not desired enforce that the settings are in a way * that actually enables the simulation case. */ @@ -1550,18 +1550,18 @@ vu_set_vring_enable_exec(VuDev *dev, VhostUserMsg *vmsg) } static bool -vu_set_slave_req_fd(VuDev *dev, VhostUserMsg *vmsg) +vu_set_backend_req_fd(VuDev *dev, VhostUserMsg *vmsg) { if (vmsg->fd_num != 1) { - vu_panic(dev, "Invalid slave_req_fd message (%d fd's)", vmsg->fd_num); + vu_panic(dev, "Invalid backend_req_fd message (%d fd's)", vmsg->fd_num); return false; } - if (dev->slave_fd != -1) { - close(dev->slave_fd); + if (dev->backend_fd != -1) { + close(dev->backend_fd); } - dev->slave_fd = vmsg->fds[0]; - DPRINT("Got slave_fd: %d\n", vmsg->fds[0]); + dev->backend_fd = vmsg->fds[0]; + DPRINT("Got backend_fd: %d\n", vmsg->fds[0]); return false; } @@ -1577,7 +1577,7 @@ vu_get_config(VuDev *dev, VhostUserMsg *vmsg) } if (ret) { - /* resize to zero to indicate an error to master */ + /* resize to zero to indicate an error to frontend */ vmsg->size = 0; } @@ -1917,7 +1917,7 @@ vu_process_message(VuDev *dev, VhostUserMsg *vmsg) case VHOST_USER_SET_VRING_ENABLE: return vu_set_vring_enable_exec(dev, vmsg); case VHOST_USER_SET_BACKEND_REQ_FD: - return vu_set_slave_req_fd(dev, vmsg); + return vu_set_backend_req_fd(dev, vmsg); case VHOST_USER_GET_CONFIG: return vu_get_config(dev, vmsg); case VHOST_USER_SET_CONFIG: @@ -2038,11 +2038,11 @@ vu_deinit(VuDev *dev) } vu_close_log(dev); - if (dev->slave_fd != -1) { - close(dev->slave_fd); - dev->slave_fd = -1; + if (dev->backend_fd != -1) { + close(dev->backend_fd); + dev->backend_fd = -1; } - pthread_mutex_destroy(&dev->slave_mutex); + pthread_mutex_destroy(&dev->backend_mutex); if (dev->sock != -1) { close(dev->sock); @@ -2080,8 +2080,8 @@ vu_init(VuDev *dev, dev->remove_watch = remove_watch; dev->iface = iface; dev->log_call_fd = -1; - pthread_mutex_init(&dev->slave_mutex, NULL); - dev->slave_fd = -1; + pthread_mutex_init(&dev->backend_mutex, NULL); + dev->backend_fd = -1; dev->max_queues = max_queues; dev->vq = malloc(max_queues * sizeof(dev->vq[0])); @@ -2439,9 +2439,9 @@ static void _vu_queue_notify(VuDev *dev, VuVirtq *vq, bool sync) vmsg.flags |= VHOST_USER_NEED_REPLY_MASK; } - vu_message_write(dev, dev->slave_fd, &vmsg); + vu_message_write(dev, dev->backend_fd, &vmsg); if (ack) { - vu_message_read_default(dev, dev->slave_fd, &vmsg); + vu_message_read_default(dev, dev->backend_fd, &vmsg); } return; } @@ -2468,7 +2468,7 @@ void vu_config_change_msg(VuDev *dev) .flags = VHOST_USER_VERSION, }; - vu_message_write(dev, dev->slave_fd, &vmsg); + vu_message_write(dev, dev->backend_fd, &vmsg); } static inline void diff --git a/subprojects/libvhost-user/libvhost-user.h b/subprojects/libvhost-user/libvhost-user.h index 49208cceaa..708370c5f5 100644 --- a/subprojects/libvhost-user/libvhost-user.h +++ b/subprojects/libvhost-user/libvhost-user.h @@ -39,7 +39,7 @@ #define VHOST_USER_HDR_SIZE offsetof(VhostUserMsg, payload.u64) typedef enum VhostSetConfigType { - VHOST_SET_CONFIG_TYPE_MASTER = 0, + VHOST_SET_CONFIG_TYPE_FRONTEND = 0, VHOST_SET_CONFIG_TYPE_MIGRATION = 1, } VhostSetConfigType; @@ -112,7 +112,7 @@ typedef enum VhostUserRequest { VHOST_USER_MAX } VhostUserRequest; -typedef enum VhostUserSlaveRequest { +typedef enum VhostUserBackendRequest { VHOST_USER_BACKEND_NONE = 0, VHOST_USER_BACKEND_IOTLB_MSG = 1, VHOST_USER_BACKEND_CONFIG_CHANGE_MSG = 2, @@ -120,7 +120,7 @@ typedef enum VhostUserSlaveRequest { VHOST_USER_BACKEND_VRING_CALL = 4, VHOST_USER_BACKEND_VRING_ERR = 5, VHOST_USER_BACKEND_MAX -} VhostUserSlaveRequest; +} VhostUserBackendRequest; typedef struct VhostUserMemoryRegion { uint64_t guest_phys_addr; @@ -296,8 +296,10 @@ typedef struct VuVirtqInflight { * Zero value indicates a vm reset happened. */ uint16_t version; - /* The size of VuDescStateSplit array. It's equal to the virtqueue - * size. Slave could get it from queue size field of VhostUserInflight. */ + /* + * The size of VuDescStateSplit array. It's equal to the virtqueue size. + * Backend could get it from queue size field of VhostUserInflight. + */ uint16_t desc_num; /* The head of list that track the last batch of used descriptors. */ @@ -384,9 +386,9 @@ struct VuDev { VuVirtq *vq; VuDevInflightInfo inflight_info; int log_call_fd; - /* Must be held while using slave_fd */ - pthread_mutex_t slave_mutex; - int slave_fd; + /* Must be held while using backend_fd */ + pthread_mutex_t backend_mutex; + int backend_fd; uint64_t log_size; uint8_t *log_table; uint64_t features; @@ -445,7 +447,7 @@ typedef struct VuVirtqElement { * vu_init: * @dev: a VuDev context * @max_queues: maximum number of virtqueues - * @socket: the socket connected to vhost-user master + * @socket: the socket connected to vhost-user frontend * @panic: a panic callback * @set_watch: a set_watch callback * @remove_watch: a remove_watch callback From e80c1e4c7d057fe5c96db588e651b934757a912e Mon Sep 17 00:00:00 2001 From: Zhenzhong Duan Date: Thu, 15 Jun 2023 11:26:24 +0800 Subject: [PATCH 0179/1353] intel_iommu: Fix a potential issue in VFIO dirty page sync Peter Xu found a potential issue: "The other thing is when I am looking at the new code I found that we actually extended the replay() to be used also in dirty tracking of vfio, in vfio_sync_dirty_bitmap(). For that maybe it's already broken if unmap_all() because afaiu log_sync() can be called in migration thread anytime during DMA so I think it means the device is prone to DMA with the IOMMU pgtable quickly erased and rebuilt here, which means the DMA could fail unexpectedly. Copy Alex, Kirti and Neo." Fix it by replacing the unmap_all() to only evacuate the iova tree (keeping all host mappings untouched, IOW, don't notify UNMAP), and do a full resync in page walk which will notify all existing mappings as MAP. This way we don't interrupt with any existing mapping if there is (e.g. for the dirty sync case), meanwhile we keep sync too to latest (for moving a vfio device into an existing iommu group). Suggested-by: Peter Xu Signed-off-by: Zhenzhong Duan Reviewed-by: Peter Xu Message-Id: <20230615032626.314476-2-zhenzhong.duan@intel.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/intel_iommu.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 94d52f4205..34af12f392 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -3825,13 +3825,10 @@ static void vtd_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n) IntelIOMMUState *s = vtd_as->iommu_state; uint8_t bus_n = pci_bus_num(vtd_as->bus); VTDContextEntry ce; + DMAMap map = { .iova = 0, .size = HWADDR_MAX }; - /* - * The replay can be triggered by either a invalidation or a newly - * created entry. No matter what, we release existing mappings - * (it means flushing caches for UNMAP-only registers). - */ - vtd_address_space_unmap(vtd_as, n); + /* replay is protected by BQL, page walk will re-setup it safely */ + iova_tree_remove(vtd_as->iova_tree, map); if (vtd_dev_to_context_entry(s, bus_n, vtd_as->devfn, &ce) == 0) { trace_vtd_replay_ce_valid(s->root_scalable ? "scalable mode" : From ce735ff03349eeac9efe59c118d78f088a151ec4 Mon Sep 17 00:00:00 2001 From: Zhenzhong Duan Date: Thu, 15 Jun 2023 11:26:25 +0800 Subject: [PATCH 0180/1353] intel_iommu: Fix flag check in replay Replay doesn't notify registered notifiers but the one passed to it. So it's meaningless to check the registered notifier's synthetic flag. There is no issue currently as all replay use cases have MAP flag set, but let's be robust. Signed-off-by: Zhenzhong Duan Reviewed-by: Peter Xu Message-Id: <20230615032626.314476-3-zhenzhong.duan@intel.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/intel_iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 34af12f392..f046f85913 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -3837,7 +3837,7 @@ static void vtd_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n) PCI_FUNC(vtd_as->devfn), vtd_get_domain_id(s, &ce, vtd_as->pasid), ce.hi, ce.lo); - if (vtd_as_has_map_notifier(vtd_as)) { + if (n->notifier_flags & IOMMU_NOTIFIER_MAP) { /* This is required only for MAP typed notifiers */ vtd_page_walk_info info = { .hook_fn = vtd_replay_hook, From ebe1504e10f771f4fc5d005a6d1ed3f30e3ad428 Mon Sep 17 00:00:00 2001 From: Zhenzhong Duan Date: Thu, 15 Jun 2023 11:26:26 +0800 Subject: [PATCH 0181/1353] intel_iommu: Fix address space unmap During address space unmap, corresponding IOVA tree entries are also removed. But DMAMap is set beyond notifier's scope by 1, so in theory there is possibility to remove a continuous entry above the notifier's scope but falling in adjacent notifier's scope. There is no issue currently as no use cases allocate notifiers continuously, but let's be robust. Signed-off-by: Zhenzhong Duan Reviewed-by: Peter Xu Message-Id: <20230615032626.314476-4-zhenzhong.duan@intel.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/intel_iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index f046f85913..dcc334060c 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -3791,7 +3791,7 @@ static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n) n->start, size); map.iova = n->start; - map.size = size; + map.size = size - 1; /* Inclusive */ iova_tree_remove(as->iova_tree, map); } From 0e994668d00c9ca760817a4ae802a7bed0e29596 Mon Sep 17 00:00:00 2001 From: Ani Sinha Date: Mon, 19 Jun 2023 09:45:01 +0530 Subject: [PATCH 0182/1353] vhost_net: add an assertion for TAP client backends An assertion was missing for tap vhost backends that enforces a non-null reference from get_vhost_net(). Both vhost-net-user and vhost-net-vdpa enforces this. Enforce the same for tap. Unit tests pass with this change. Signed-off-by: Ani Sinha Message-Id: <20230619041501.111655-1-anisinha@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Laurent Vivier --- hw/net/vhost_net.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index c4eecc6f36..6db23ca323 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -507,6 +507,7 @@ VHostNetState *get_vhost_net(NetClientState *nc) switch (nc->info->type) { case NET_CLIENT_DRIVER_TAP: vhost_net = tap_get_vhost_net(nc); + assert(vhost_net); break; #ifdef CONFIG_VHOST_NET_USER case NET_CLIENT_DRIVER_VHOST_USER: From a0d7215e339b61c7d7a7b3fcf754954d80d93eb8 Mon Sep 17 00:00:00 2001 From: Ani Sinha Date: Mon, 19 Jun 2023 12:22:09 +0530 Subject: [PATCH 0183/1353] vhost-vdpa: do not cleanup the vdpa/vhost-net structures if peer nic is present When a peer nic is still attached to the vdpa backend, it is too early to free up the vhost-net and vdpa structures. If these structures are freed here, then QEMU crashes when the guest is being shut down. The following call chain would result in an assertion failure since the pointer returned from vhost_vdpa_get_vhost_net() would be NULL: do_vm_stop() -> vm_state_notify() -> virtio_set_status() -> virtio_net_vhost_status() -> get_vhost_net(). Therefore, we defer freeing up the structures until at guest shutdown time when qemu_cleanup() calls net_cleanup() which then calls qemu_del_net_client() which would eventually call vhost_vdpa_cleanup() again to free up the structures. This time, the loop in net_cleanup() ensures that vhost_vdpa_cleanup() will be called one last time when all the peer nics are detached and freed. All unit tests pass with this change. CC: imammedo@redhat.com CC: jusual@redhat.com CC: mst@redhat.com Fixes: CVE-2023-3301 Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2128929 Signed-off-by: Ani Sinha Message-Id: <20230619065209.442185-1-anisinha@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- net/vhost-vdpa.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index 9e92b3558c..e19ab063fa 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -207,6 +207,14 @@ static void vhost_vdpa_cleanup(NetClientState *nc) { VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); + /* + * If a peer NIC is attached, do not cleanup anything. + * Cleanup will happen as a part of qemu_cleanup() -> net_cleanup() + * when the guest is shutting down. + */ + if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_NIC) { + return; + } munmap(s->cvq_cmd_out_buffer, vhost_vdpa_net_cvq_cmd_page_len()); munmap(s->status, vhost_vdpa_net_cvq_cmd_page_len()); if (s->vhost_net) { From 732d548732edda90f3cfe0f7dceee64861f07b25 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Wed, 21 Jun 2023 15:56:22 +0200 Subject: [PATCH 0184/1353] accel: Replace target_ulong in tlb_*() Replaces target_ulong with vaddr for guest virtual addresses in tlb_*() functions and auxilliary structs. Signed-off-by: Anton Johansson Reviewed-by: Richard Henderson Message-Id: <20230621135633.1649-2-anjo@rev.ng> Signed-off-by: Richard Henderson --- accel/stubs/tcg-stub.c | 2 +- accel/tcg/cputlb.c | 177 +++++++++++++++++------------------ accel/tcg/tb-maint.c | 2 +- include/exec/cpu-defs.h | 4 +- include/exec/exec-all.h | 79 ++++++++-------- include/qemu/plugin-memory.h | 2 +- 6 files changed, 131 insertions(+), 135 deletions(-) diff --git a/accel/stubs/tcg-stub.c b/accel/stubs/tcg-stub.c index 813695b402..0998e601ad 100644 --- a/accel/stubs/tcg-stub.c +++ b/accel/stubs/tcg-stub.c @@ -18,7 +18,7 @@ void tb_flush(CPUState *cpu) { } -void tlb_set_dirty(CPUState *cpu, target_ulong vaddr) +void tlb_set_dirty(CPUState *cpu, vaddr vaddr) { } diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 14ce97c33b..5caeccb52d 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -427,7 +427,7 @@ void tlb_flush_all_cpus_synced(CPUState *src_cpu) } static bool tlb_hit_page_mask_anyprot(CPUTLBEntry *tlb_entry, - target_ulong page, target_ulong mask) + vaddr page, vaddr mask) { page &= mask; mask &= TARGET_PAGE_MASK | TLB_INVALID_MASK; @@ -437,8 +437,7 @@ static bool tlb_hit_page_mask_anyprot(CPUTLBEntry *tlb_entry, page == (tlb_entry->addr_code & mask)); } -static inline bool tlb_hit_page_anyprot(CPUTLBEntry *tlb_entry, - target_ulong page) +static inline bool tlb_hit_page_anyprot(CPUTLBEntry *tlb_entry, vaddr page) { return tlb_hit_page_mask_anyprot(tlb_entry, page, -1); } @@ -454,8 +453,8 @@ static inline bool tlb_entry_is_empty(const CPUTLBEntry *te) /* Called with tlb_c.lock held */ static bool tlb_flush_entry_mask_locked(CPUTLBEntry *tlb_entry, - target_ulong page, - target_ulong mask) + vaddr page, + vaddr mask) { if (tlb_hit_page_mask_anyprot(tlb_entry, page, mask)) { memset(tlb_entry, -1, sizeof(*tlb_entry)); @@ -464,16 +463,15 @@ static bool tlb_flush_entry_mask_locked(CPUTLBEntry *tlb_entry, return false; } -static inline bool tlb_flush_entry_locked(CPUTLBEntry *tlb_entry, - target_ulong page) +static inline bool tlb_flush_entry_locked(CPUTLBEntry *tlb_entry, vaddr page) { return tlb_flush_entry_mask_locked(tlb_entry, page, -1); } /* Called with tlb_c.lock held */ static void tlb_flush_vtlb_page_mask_locked(CPUArchState *env, int mmu_idx, - target_ulong page, - target_ulong mask) + vaddr page, + vaddr mask) { CPUTLBDesc *d = &env_tlb(env)->d[mmu_idx]; int k; @@ -487,21 +485,20 @@ static void tlb_flush_vtlb_page_mask_locked(CPUArchState *env, int mmu_idx, } static inline void tlb_flush_vtlb_page_locked(CPUArchState *env, int mmu_idx, - target_ulong page) + vaddr page) { tlb_flush_vtlb_page_mask_locked(env, mmu_idx, page, -1); } -static void tlb_flush_page_locked(CPUArchState *env, int midx, - target_ulong page) +static void tlb_flush_page_locked(CPUArchState *env, int midx, vaddr page) { - target_ulong lp_addr = env_tlb(env)->d[midx].large_page_addr; - target_ulong lp_mask = env_tlb(env)->d[midx].large_page_mask; + vaddr lp_addr = env_tlb(env)->d[midx].large_page_addr; + vaddr lp_mask = env_tlb(env)->d[midx].large_page_mask; /* Check if we need to flush due to large pages. */ if ((page & lp_mask) == lp_addr) { - tlb_debug("forcing full flush midx %d (" - TARGET_FMT_lx "/" TARGET_FMT_lx ")\n", + tlb_debug("forcing full flush midx %d (%" + VADDR_PRIx "/%" VADDR_PRIx ")\n", midx, lp_addr, lp_mask); tlb_flush_one_mmuidx_locked(env, midx, get_clock_realtime()); } else { @@ -522,7 +519,7 @@ static void tlb_flush_page_locked(CPUArchState *env, int midx, * at @addr from the tlbs indicated by @idxmap from @cpu. */ static void tlb_flush_page_by_mmuidx_async_0(CPUState *cpu, - target_ulong addr, + vaddr addr, uint16_t idxmap) { CPUArchState *env = cpu->env_ptr; @@ -530,7 +527,7 @@ static void tlb_flush_page_by_mmuidx_async_0(CPUState *cpu, assert_cpu_is_self(cpu); - tlb_debug("page addr:" TARGET_FMT_lx " mmu_map:0x%x\n", addr, idxmap); + tlb_debug("page addr: %" VADDR_PRIx " mmu_map:0x%x\n", addr, idxmap); qemu_spin_lock(&env_tlb(env)->c.lock); for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { @@ -561,15 +558,15 @@ static void tlb_flush_page_by_mmuidx_async_0(CPUState *cpu, static void tlb_flush_page_by_mmuidx_async_1(CPUState *cpu, run_on_cpu_data data) { - target_ulong addr_and_idxmap = (target_ulong) data.target_ptr; - target_ulong addr = addr_and_idxmap & TARGET_PAGE_MASK; + vaddr addr_and_idxmap = data.target_ptr; + vaddr addr = addr_and_idxmap & TARGET_PAGE_MASK; uint16_t idxmap = addr_and_idxmap & ~TARGET_PAGE_MASK; tlb_flush_page_by_mmuidx_async_0(cpu, addr, idxmap); } typedef struct { - target_ulong addr; + vaddr addr; uint16_t idxmap; } TLBFlushPageByMMUIdxData; @@ -592,9 +589,9 @@ static void tlb_flush_page_by_mmuidx_async_2(CPUState *cpu, g_free(d); } -void tlb_flush_page_by_mmuidx(CPUState *cpu, target_ulong addr, uint16_t idxmap) +void tlb_flush_page_by_mmuidx(CPUState *cpu, vaddr addr, uint16_t idxmap) { - tlb_debug("addr: "TARGET_FMT_lx" mmu_idx:%" PRIx16 "\n", addr, idxmap); + tlb_debug("addr: %" VADDR_PRIx " mmu_idx:%" PRIx16 "\n", addr, idxmap); /* This should already be page aligned */ addr &= TARGET_PAGE_MASK; @@ -620,15 +617,15 @@ void tlb_flush_page_by_mmuidx(CPUState *cpu, target_ulong addr, uint16_t idxmap) } } -void tlb_flush_page(CPUState *cpu, target_ulong addr) +void tlb_flush_page(CPUState *cpu, vaddr addr) { tlb_flush_page_by_mmuidx(cpu, addr, ALL_MMUIDX_BITS); } -void tlb_flush_page_by_mmuidx_all_cpus(CPUState *src_cpu, target_ulong addr, +void tlb_flush_page_by_mmuidx_all_cpus(CPUState *src_cpu, vaddr addr, uint16_t idxmap) { - tlb_debug("addr: "TARGET_FMT_lx" mmu_idx:%"PRIx16"\n", addr, idxmap); + tlb_debug("addr: %" VADDR_PRIx " mmu_idx:%"PRIx16"\n", addr, idxmap); /* This should already be page aligned */ addr &= TARGET_PAGE_MASK; @@ -660,16 +657,16 @@ void tlb_flush_page_by_mmuidx_all_cpus(CPUState *src_cpu, target_ulong addr, tlb_flush_page_by_mmuidx_async_0(src_cpu, addr, idxmap); } -void tlb_flush_page_all_cpus(CPUState *src, target_ulong addr) +void tlb_flush_page_all_cpus(CPUState *src, vaddr addr) { tlb_flush_page_by_mmuidx_all_cpus(src, addr, ALL_MMUIDX_BITS); } void tlb_flush_page_by_mmuidx_all_cpus_synced(CPUState *src_cpu, - target_ulong addr, + vaddr addr, uint16_t idxmap) { - tlb_debug("addr: "TARGET_FMT_lx" mmu_idx:%"PRIx16"\n", addr, idxmap); + tlb_debug("addr: %" VADDR_PRIx " mmu_idx:%"PRIx16"\n", addr, idxmap); /* This should already be page aligned */ addr &= TARGET_PAGE_MASK; @@ -706,18 +703,18 @@ void tlb_flush_page_by_mmuidx_all_cpus_synced(CPUState *src_cpu, } } -void tlb_flush_page_all_cpus_synced(CPUState *src, target_ulong addr) +void tlb_flush_page_all_cpus_synced(CPUState *src, vaddr addr) { tlb_flush_page_by_mmuidx_all_cpus_synced(src, addr, ALL_MMUIDX_BITS); } static void tlb_flush_range_locked(CPUArchState *env, int midx, - target_ulong addr, target_ulong len, + vaddr addr, vaddr len, unsigned bits) { CPUTLBDesc *d = &env_tlb(env)->d[midx]; CPUTLBDescFast *f = &env_tlb(env)->f[midx]; - target_ulong mask = MAKE_64BIT_MASK(0, bits); + vaddr mask = MAKE_64BIT_MASK(0, bits); /* * If @bits is smaller than the tlb size, there may be multiple entries @@ -731,7 +728,7 @@ static void tlb_flush_range_locked(CPUArchState *env, int midx, */ if (mask < f->mask || len > f->mask) { tlb_debug("forcing full flush midx %d (" - TARGET_FMT_lx "/" TARGET_FMT_lx "+" TARGET_FMT_lx ")\n", + "%" VADDR_PRIx "/%" VADDR_PRIx "+%" VADDR_PRIx ")\n", midx, addr, mask, len); tlb_flush_one_mmuidx_locked(env, midx, get_clock_realtime()); return; @@ -744,14 +741,14 @@ static void tlb_flush_range_locked(CPUArchState *env, int midx, */ if (((addr + len - 1) & d->large_page_mask) == d->large_page_addr) { tlb_debug("forcing full flush midx %d (" - TARGET_FMT_lx "/" TARGET_FMT_lx ")\n", + "%" VADDR_PRIx "/%" VADDR_PRIx ")\n", midx, d->large_page_addr, d->large_page_mask); tlb_flush_one_mmuidx_locked(env, midx, get_clock_realtime()); return; } - for (target_ulong i = 0; i < len; i += TARGET_PAGE_SIZE) { - target_ulong page = addr + i; + for (vaddr i = 0; i < len; i += TARGET_PAGE_SIZE) { + vaddr page = addr + i; CPUTLBEntry *entry = tlb_entry(env, midx, page); if (tlb_flush_entry_mask_locked(entry, page, mask)) { @@ -762,8 +759,8 @@ static void tlb_flush_range_locked(CPUArchState *env, int midx, } typedef struct { - target_ulong addr; - target_ulong len; + vaddr addr; + vaddr len; uint16_t idxmap; uint16_t bits; } TLBFlushRangeData; @@ -776,7 +773,7 @@ static void tlb_flush_range_by_mmuidx_async_0(CPUState *cpu, assert_cpu_is_self(cpu); - tlb_debug("range:" TARGET_FMT_lx "/%u+" TARGET_FMT_lx " mmu_map:0x%x\n", + tlb_debug("range: %" VADDR_PRIx "/%u+%" VADDR_PRIx " mmu_map:0x%x\n", d.addr, d.bits, d.len, d.idxmap); qemu_spin_lock(&env_tlb(env)->c.lock); @@ -801,7 +798,7 @@ static void tlb_flush_range_by_mmuidx_async_0(CPUState *cpu, * overlap the flushed pages, which includes the previous. */ d.addr -= TARGET_PAGE_SIZE; - for (target_ulong i = 0, n = d.len / TARGET_PAGE_SIZE + 1; i < n; i++) { + for (vaddr i = 0, n = d.len / TARGET_PAGE_SIZE + 1; i < n; i++) { tb_jmp_cache_clear_page(cpu, d.addr); d.addr += TARGET_PAGE_SIZE; } @@ -815,8 +812,8 @@ static void tlb_flush_range_by_mmuidx_async_1(CPUState *cpu, g_free(d); } -void tlb_flush_range_by_mmuidx(CPUState *cpu, target_ulong addr, - target_ulong len, uint16_t idxmap, +void tlb_flush_range_by_mmuidx(CPUState *cpu, vaddr addr, + vaddr len, uint16_t idxmap, unsigned bits) { TLBFlushRangeData d; @@ -851,14 +848,14 @@ void tlb_flush_range_by_mmuidx(CPUState *cpu, target_ulong addr, } } -void tlb_flush_page_bits_by_mmuidx(CPUState *cpu, target_ulong addr, +void tlb_flush_page_bits_by_mmuidx(CPUState *cpu, vaddr addr, uint16_t idxmap, unsigned bits) { tlb_flush_range_by_mmuidx(cpu, addr, TARGET_PAGE_SIZE, idxmap, bits); } void tlb_flush_range_by_mmuidx_all_cpus(CPUState *src_cpu, - target_ulong addr, target_ulong len, + vaddr addr, vaddr len, uint16_t idxmap, unsigned bits) { TLBFlushRangeData d; @@ -898,16 +895,16 @@ void tlb_flush_range_by_mmuidx_all_cpus(CPUState *src_cpu, } void tlb_flush_page_bits_by_mmuidx_all_cpus(CPUState *src_cpu, - target_ulong addr, - uint16_t idxmap, unsigned bits) + vaddr addr, uint16_t idxmap, + unsigned bits) { tlb_flush_range_by_mmuidx_all_cpus(src_cpu, addr, TARGET_PAGE_SIZE, idxmap, bits); } void tlb_flush_range_by_mmuidx_all_cpus_synced(CPUState *src_cpu, - target_ulong addr, - target_ulong len, + vaddr addr, + vaddr len, uint16_t idxmap, unsigned bits) { @@ -949,7 +946,7 @@ void tlb_flush_range_by_mmuidx_all_cpus_synced(CPUState *src_cpu, } void tlb_flush_page_bits_by_mmuidx_all_cpus_synced(CPUState *src_cpu, - target_ulong addr, + vaddr addr, uint16_t idxmap, unsigned bits) { @@ -1055,32 +1052,32 @@ void tlb_reset_dirty(CPUState *cpu, ram_addr_t start1, ram_addr_t length) /* Called with tlb_c.lock held */ static inline void tlb_set_dirty1_locked(CPUTLBEntry *tlb_entry, - target_ulong vaddr) + vaddr addr) { - if (tlb_entry->addr_write == (vaddr | TLB_NOTDIRTY)) { - tlb_entry->addr_write = vaddr; + if (tlb_entry->addr_write == (addr | TLB_NOTDIRTY)) { + tlb_entry->addr_write = addr; } } /* update the TLB corresponding to virtual page vaddr so that it is no longer dirty */ -void tlb_set_dirty(CPUState *cpu, target_ulong vaddr) +void tlb_set_dirty(CPUState *cpu, vaddr addr) { CPUArchState *env = cpu->env_ptr; int mmu_idx; assert_cpu_is_self(cpu); - vaddr &= TARGET_PAGE_MASK; + addr &= TARGET_PAGE_MASK; qemu_spin_lock(&env_tlb(env)->c.lock); for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { - tlb_set_dirty1_locked(tlb_entry(env, mmu_idx, vaddr), vaddr); + tlb_set_dirty1_locked(tlb_entry(env, mmu_idx, addr), addr); } for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { int k; for (k = 0; k < CPU_VTLB_SIZE; k++) { - tlb_set_dirty1_locked(&env_tlb(env)->d[mmu_idx].vtable[k], vaddr); + tlb_set_dirty1_locked(&env_tlb(env)->d[mmu_idx].vtable[k], addr); } } qemu_spin_unlock(&env_tlb(env)->c.lock); @@ -1089,20 +1086,20 @@ void tlb_set_dirty(CPUState *cpu, target_ulong vaddr) /* Our TLB does not support large pages, so remember the area covered by large pages and trigger a full TLB flush if these are invalidated. */ static void tlb_add_large_page(CPUArchState *env, int mmu_idx, - target_ulong vaddr, target_ulong size) + vaddr addr, uint64_t size) { - target_ulong lp_addr = env_tlb(env)->d[mmu_idx].large_page_addr; - target_ulong lp_mask = ~(size - 1); + vaddr lp_addr = env_tlb(env)->d[mmu_idx].large_page_addr; + vaddr lp_mask = ~(size - 1); - if (lp_addr == (target_ulong)-1) { + if (lp_addr == (vaddr)-1) { /* No previous large page. */ - lp_addr = vaddr; + lp_addr = addr; } else { /* Extend the existing region to include the new page. This is a compromise between unnecessary flushes and the cost of maintaining a full variable size TLB. */ lp_mask &= env_tlb(env)->d[mmu_idx].large_page_mask; - while (((lp_addr ^ vaddr) & lp_mask) != 0) { + while (((lp_addr ^ addr) & lp_mask) != 0) { lp_mask <<= 1; } } @@ -1119,19 +1116,19 @@ static void tlb_add_large_page(CPUArchState *env, int mmu_idx, * critical section. */ void tlb_set_page_full(CPUState *cpu, int mmu_idx, - target_ulong vaddr, CPUTLBEntryFull *full) + vaddr addr, CPUTLBEntryFull *full) { CPUArchState *env = cpu->env_ptr; CPUTLB *tlb = env_tlb(env); CPUTLBDesc *desc = &tlb->d[mmu_idx]; MemoryRegionSection *section; unsigned int index; - target_ulong address; - target_ulong write_address; + vaddr address; + vaddr write_address; uintptr_t addend; CPUTLBEntry *te, tn; hwaddr iotlb, xlat, sz, paddr_page; - target_ulong vaddr_page; + vaddr addr_page; int asidx, wp_flags, prot; bool is_ram, is_romd; @@ -1141,9 +1138,9 @@ void tlb_set_page_full(CPUState *cpu, int mmu_idx, sz = TARGET_PAGE_SIZE; } else { sz = (hwaddr)1 << full->lg_page_size; - tlb_add_large_page(env, mmu_idx, vaddr, sz); + tlb_add_large_page(env, mmu_idx, addr, sz); } - vaddr_page = vaddr & TARGET_PAGE_MASK; + addr_page = addr & TARGET_PAGE_MASK; paddr_page = full->phys_addr & TARGET_PAGE_MASK; prot = full->prot; @@ -1152,11 +1149,11 @@ void tlb_set_page_full(CPUState *cpu, int mmu_idx, &xlat, &sz, full->attrs, &prot); assert(sz >= TARGET_PAGE_SIZE); - tlb_debug("vaddr=" TARGET_FMT_lx " paddr=0x" HWADDR_FMT_plx + tlb_debug("vaddr=%" VADDR_PRIx " paddr=0x" HWADDR_FMT_plx " prot=%x idx=%d\n", - vaddr, full->phys_addr, prot, mmu_idx); + addr, full->phys_addr, prot, mmu_idx); - address = vaddr_page; + address = addr_page; if (full->lg_page_size < TARGET_PAGE_BITS) { /* Repeat the MMU check and TLB fill on every access. */ address |= TLB_INVALID_MASK; @@ -1204,11 +1201,11 @@ void tlb_set_page_full(CPUState *cpu, int mmu_idx, } } - wp_flags = cpu_watchpoint_address_matches(cpu, vaddr_page, + wp_flags = cpu_watchpoint_address_matches(cpu, addr_page, TARGET_PAGE_SIZE); - index = tlb_index(env, mmu_idx, vaddr_page); - te = tlb_entry(env, mmu_idx, vaddr_page); + index = tlb_index(env, mmu_idx, addr_page); + te = tlb_entry(env, mmu_idx, addr_page); /* * Hold the TLB lock for the rest of the function. We could acquire/release @@ -1223,13 +1220,13 @@ void tlb_set_page_full(CPUState *cpu, int mmu_idx, tlb->c.dirty |= 1 << mmu_idx; /* Make sure there's no cached translation for the new page. */ - tlb_flush_vtlb_page_locked(env, mmu_idx, vaddr_page); + tlb_flush_vtlb_page_locked(env, mmu_idx, addr_page); /* * Only evict the old entry to the victim tlb if it's for a * different page; otherwise just overwrite the stale data. */ - if (!tlb_hit_page_anyprot(te, vaddr_page) && !tlb_entry_is_empty(te)) { + if (!tlb_hit_page_anyprot(te, addr_page) && !tlb_entry_is_empty(te)) { unsigned vidx = desc->vindex++ % CPU_VTLB_SIZE; CPUTLBEntry *tv = &desc->vtable[vidx]; @@ -1253,11 +1250,11 @@ void tlb_set_page_full(CPUState *cpu, int mmu_idx, * vaddr we add back in io_readx()/io_writex()/get_page_addr_code(). */ desc->fulltlb[index] = *full; - desc->fulltlb[index].xlat_section = iotlb - vaddr_page; + desc->fulltlb[index].xlat_section = iotlb - addr_page; desc->fulltlb[index].phys_addr = paddr_page; /* Now calculate the new entry */ - tn.addend = addend - vaddr_page; + tn.addend = addend - addr_page; if (prot & PAGE_READ) { tn.addr_read = address; if (wp_flags & BP_MEM_READ) { @@ -1289,9 +1286,9 @@ void tlb_set_page_full(CPUState *cpu, int mmu_idx, qemu_spin_unlock(&tlb->c.lock); } -void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr, +void tlb_set_page_with_attrs(CPUState *cpu, vaddr addr, hwaddr paddr, MemTxAttrs attrs, int prot, - int mmu_idx, target_ulong size) + int mmu_idx, uint64_t size) { CPUTLBEntryFull full = { .phys_addr = paddr, @@ -1301,14 +1298,14 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr, }; assert(is_power_of_2(size)); - tlb_set_page_full(cpu, mmu_idx, vaddr, &full); + tlb_set_page_full(cpu, mmu_idx, addr, &full); } -void tlb_set_page(CPUState *cpu, target_ulong vaddr, +void tlb_set_page(CPUState *cpu, vaddr addr, hwaddr paddr, int prot, - int mmu_idx, target_ulong size) + int mmu_idx, uint64_t size) { - tlb_set_page_with_attrs(cpu, vaddr, paddr, MEMTXATTRS_UNSPECIFIED, + tlb_set_page_with_attrs(cpu, addr, paddr, MEMTXATTRS_UNSPECIFIED, prot, mmu_idx, size); } @@ -1317,7 +1314,7 @@ void tlb_set_page(CPUState *cpu, target_ulong vaddr, * caller's prior references to the TLB table (e.g. CPUTLBEntry pointers) must * be discarded and looked up again (e.g. via tlb_entry()). */ -static void tlb_fill(CPUState *cpu, target_ulong addr, int size, +static void tlb_fill(CPUState *cpu, vaddr addr, int size, MMUAccessType access_type, int mmu_idx, uintptr_t retaddr) { bool ok; @@ -1357,7 +1354,7 @@ static inline void cpu_transaction_failed(CPUState *cpu, hwaddr physaddr, } static uint64_t io_readx(CPUArchState *env, CPUTLBEntryFull *full, - int mmu_idx, target_ulong addr, uintptr_t retaddr, + int mmu_idx, vaddr addr, uintptr_t retaddr, MMUAccessType access_type, MemOp op) { CPUState *cpu = env_cpu(env); @@ -1407,7 +1404,7 @@ static void save_iotlb_data(CPUState *cs, MemoryRegionSection *section, } static void io_writex(CPUArchState *env, CPUTLBEntryFull *full, - int mmu_idx, uint64_t val, target_ulong addr, + int mmu_idx, uint64_t val, vaddr addr, uintptr_t retaddr, MemOp op) { CPUState *cpu = env_cpu(env); @@ -1449,7 +1446,7 @@ static void io_writex(CPUArchState *env, CPUTLBEntryFull *full, /* Return true if ADDR is present in the victim tlb, and has been copied back to the main tlb. */ static bool victim_tlb_hit(CPUArchState *env, size_t mmu_idx, size_t index, - MMUAccessType access_type, target_ulong page) + MMUAccessType access_type, vaddr page) { size_t vidx; @@ -1691,13 +1688,13 @@ tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, target_ulong addr, * from the same thread (which a mem callback will be) this is safe. */ -bool tlb_plugin_lookup(CPUState *cpu, target_ulong addr, int mmu_idx, +bool tlb_plugin_lookup(CPUState *cpu, vaddr addr, int mmu_idx, bool is_store, struct qemu_plugin_hwaddr *data) { CPUArchState *env = cpu->env_ptr; CPUTLBEntry *tlbe = tlb_entry(env, mmu_idx, addr); uintptr_t index = tlb_index(env, mmu_idx, addr); - target_ulong tlb_addr = is_store ? tlb_addr_write(tlbe) : tlbe->addr_read; + vaddr tlb_addr = is_store ? tlb_addr_write(tlbe) : tlbe->addr_read; if (likely(tlb_hit(tlb_addr, addr))) { /* We must have an iotlb entry for MMIO */ diff --git a/accel/tcg/tb-maint.c b/accel/tcg/tb-maint.c index 892eecda2d..3541419845 100644 --- a/accel/tcg/tb-maint.c +++ b/accel/tcg/tb-maint.c @@ -98,7 +98,7 @@ static void tb_remove_all(void) /* Call with mmap_lock held. */ static void tb_record(TranslationBlock *tb, PageDesc *p1, PageDesc *p2) { - target_ulong addr; + vaddr addr; int flags; assert_memory_lock(); diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h index 4cb77c8dec..e6a079402e 100644 --- a/include/exec/cpu-defs.h +++ b/include/exec/cpu-defs.h @@ -147,8 +147,8 @@ typedef struct CPUTLBDesc { * 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; + vaddr large_page_addr; + vaddr 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 */ diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 698943d58f..f5508e242b 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -94,7 +94,7 @@ void tlb_destroy(CPUState *cpu); * Flush one page from the TLB of the specified CPU, for all * MMU indexes. */ -void tlb_flush_page(CPUState *cpu, target_ulong addr); +void tlb_flush_page(CPUState *cpu, vaddr addr); /** * tlb_flush_page_all_cpus: * @cpu: src CPU of the flush @@ -103,7 +103,7 @@ void tlb_flush_page(CPUState *cpu, target_ulong addr); * Flush one page from the TLB of the specified CPU, for all * MMU indexes. */ -void tlb_flush_page_all_cpus(CPUState *src, target_ulong addr); +void tlb_flush_page_all_cpus(CPUState *src, vaddr addr); /** * tlb_flush_page_all_cpus_synced: * @cpu: src CPU of the flush @@ -115,7 +115,7 @@ void tlb_flush_page_all_cpus(CPUState *src, target_ulong addr); * the source vCPUs safe work is complete. This will depend on when * the guests translation ends the TB. */ -void tlb_flush_page_all_cpus_synced(CPUState *src, target_ulong addr); +void tlb_flush_page_all_cpus_synced(CPUState *src, vaddr addr); /** * tlb_flush: * @cpu: CPU whose TLB should be flushed @@ -150,7 +150,7 @@ void tlb_flush_all_cpus_synced(CPUState *src_cpu); * Flush one page from the TLB of the specified CPU, for the specified * MMU indexes. */ -void tlb_flush_page_by_mmuidx(CPUState *cpu, target_ulong addr, +void tlb_flush_page_by_mmuidx(CPUState *cpu, vaddr addr, uint16_t idxmap); /** * tlb_flush_page_by_mmuidx_all_cpus: @@ -161,7 +161,7 @@ void tlb_flush_page_by_mmuidx(CPUState *cpu, target_ulong addr, * Flush one page from the TLB of all CPUs, for the specified * MMU indexes. */ -void tlb_flush_page_by_mmuidx_all_cpus(CPUState *cpu, target_ulong addr, +void tlb_flush_page_by_mmuidx_all_cpus(CPUState *cpu, vaddr addr, uint16_t idxmap); /** * tlb_flush_page_by_mmuidx_all_cpus_synced: @@ -175,7 +175,7 @@ void tlb_flush_page_by_mmuidx_all_cpus(CPUState *cpu, target_ulong addr, * complete once the source vCPUs safe work is complete. This will * depend on when the guests translation ends the TB. */ -void tlb_flush_page_by_mmuidx_all_cpus_synced(CPUState *cpu, target_ulong addr, +void tlb_flush_page_by_mmuidx_all_cpus_synced(CPUState *cpu, vaddr addr, uint16_t idxmap); /** * tlb_flush_by_mmuidx: @@ -218,14 +218,14 @@ void tlb_flush_by_mmuidx_all_cpus_synced(CPUState *cpu, uint16_t idxmap); * * Similar to tlb_flush_page_mask, but with a bitmap of indexes. */ -void tlb_flush_page_bits_by_mmuidx(CPUState *cpu, target_ulong addr, +void tlb_flush_page_bits_by_mmuidx(CPUState *cpu, vaddr addr, uint16_t idxmap, unsigned bits); /* Similarly, with broadcast and syncing. */ -void tlb_flush_page_bits_by_mmuidx_all_cpus(CPUState *cpu, target_ulong addr, +void tlb_flush_page_bits_by_mmuidx_all_cpus(CPUState *cpu, vaddr addr, uint16_t idxmap, unsigned bits); void tlb_flush_page_bits_by_mmuidx_all_cpus_synced - (CPUState *cpu, target_ulong addr, uint16_t idxmap, unsigned bits); + (CPUState *cpu, vaddr addr, uint16_t idxmap, unsigned bits); /** * tlb_flush_range_by_mmuidx @@ -238,17 +238,17 @@ void tlb_flush_page_bits_by_mmuidx_all_cpus_synced * For each mmuidx in @idxmap, flush all pages within [@addr,@addr+@len), * comparing only the low @bits worth of each virtual page. */ -void tlb_flush_range_by_mmuidx(CPUState *cpu, target_ulong addr, - target_ulong len, uint16_t idxmap, +void tlb_flush_range_by_mmuidx(CPUState *cpu, vaddr addr, + vaddr len, uint16_t idxmap, unsigned bits); /* Similarly, with broadcast and syncing. */ -void tlb_flush_range_by_mmuidx_all_cpus(CPUState *cpu, target_ulong addr, - target_ulong len, uint16_t idxmap, +void tlb_flush_range_by_mmuidx_all_cpus(CPUState *cpu, vaddr addr, + vaddr len, uint16_t idxmap, unsigned bits); void tlb_flush_range_by_mmuidx_all_cpus_synced(CPUState *cpu, - target_ulong addr, - target_ulong len, + vaddr addr, + vaddr len, uint16_t idxmap, unsigned bits); @@ -256,7 +256,7 @@ void tlb_flush_range_by_mmuidx_all_cpus_synced(CPUState *cpu, * tlb_set_page_full: * @cpu: CPU context * @mmu_idx: mmu index of the tlb to modify - * @vaddr: virtual address of the entry to add + * @addr: virtual address of the entry to add * @full: the details of the tlb entry * * Add an entry to @cpu tlb index @mmu_idx. All of the fields of @@ -271,13 +271,13 @@ void tlb_flush_range_by_mmuidx_all_cpus_synced(CPUState *cpu, * single TARGET_PAGE_SIZE region is mapped; @full->lg_page_size is only * used by tlb_flush_page. */ -void tlb_set_page_full(CPUState *cpu, int mmu_idx, target_ulong vaddr, +void tlb_set_page_full(CPUState *cpu, int mmu_idx, vaddr addr, CPUTLBEntryFull *full); /** * tlb_set_page_with_attrs: * @cpu: CPU to add this TLB entry for - * @vaddr: virtual address of page to add entry for + * @addr: virtual address of page to add entry for * @paddr: physical address of the page * @attrs: memory transaction attributes * @prot: access permissions (PAGE_READ/PAGE_WRITE/PAGE_EXEC bits) @@ -285,7 +285,7 @@ void tlb_set_page_full(CPUState *cpu, int mmu_idx, target_ulong vaddr, * @size: size of the page in bytes * * Add an entry to this CPU's TLB (a mapping from virtual address - * @vaddr to physical address @paddr) with the specified memory + * @addr to physical address @paddr) with the specified memory * transaction attributes. This is generally called by the target CPU * specific code after it has been called through the tlb_fill() * entry point and performed a successful page table walk to find @@ -296,18 +296,18 @@ void tlb_set_page_full(CPUState *cpu, int mmu_idx, target_ulong vaddr, * single TARGET_PAGE_SIZE region is mapped; the supplied @size is only * used by tlb_flush_page. */ -void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr, +void tlb_set_page_with_attrs(CPUState *cpu, vaddr addr, hwaddr paddr, MemTxAttrs attrs, - int prot, int mmu_idx, target_ulong size); + int prot, int mmu_idx, vaddr size); /* tlb_set_page: * * This function is equivalent to calling tlb_set_page_with_attrs() * with an @attrs argument of MEMTXATTRS_UNSPECIFIED. It's provided * as a convenience for CPUs which don't use memory transaction attributes. */ -void tlb_set_page(CPUState *cpu, target_ulong vaddr, +void tlb_set_page(CPUState *cpu, vaddr addr, hwaddr paddr, int prot, - int mmu_idx, target_ulong size); + int mmu_idx, vaddr size); #else static inline void tlb_init(CPUState *cpu) { @@ -315,14 +315,13 @@ static inline void tlb_init(CPUState *cpu) static inline void tlb_destroy(CPUState *cpu) { } -static inline void tlb_flush_page(CPUState *cpu, target_ulong addr) +static inline void tlb_flush_page(CPUState *cpu, vaddr addr) { } -static inline void tlb_flush_page_all_cpus(CPUState *src, target_ulong addr) +static inline void tlb_flush_page_all_cpus(CPUState *src, vaddr addr) { } -static inline void tlb_flush_page_all_cpus_synced(CPUState *src, - target_ulong addr) +static inline void tlb_flush_page_all_cpus_synced(CPUState *src, vaddr addr) { } static inline void tlb_flush(CPUState *cpu) @@ -335,7 +334,7 @@ static inline void tlb_flush_all_cpus_synced(CPUState *src_cpu) { } static inline void tlb_flush_page_by_mmuidx(CPUState *cpu, - target_ulong addr, uint16_t idxmap) + vaddr addr, uint16_t idxmap) { } @@ -343,12 +342,12 @@ static inline void tlb_flush_by_mmuidx(CPUState *cpu, uint16_t idxmap) { } static inline void tlb_flush_page_by_mmuidx_all_cpus(CPUState *cpu, - target_ulong addr, + vaddr addr, uint16_t idxmap) { } static inline void tlb_flush_page_by_mmuidx_all_cpus_synced(CPUState *cpu, - target_ulong addr, + vaddr addr, uint16_t idxmap) { } @@ -361,37 +360,37 @@ static inline void tlb_flush_by_mmuidx_all_cpus_synced(CPUState *cpu, { } static inline void tlb_flush_page_bits_by_mmuidx(CPUState *cpu, - target_ulong addr, + vaddr addr, uint16_t idxmap, unsigned bits) { } static inline void tlb_flush_page_bits_by_mmuidx_all_cpus(CPUState *cpu, - target_ulong addr, + vaddr addr, uint16_t idxmap, unsigned bits) { } static inline void -tlb_flush_page_bits_by_mmuidx_all_cpus_synced(CPUState *cpu, target_ulong addr, +tlb_flush_page_bits_by_mmuidx_all_cpus_synced(CPUState *cpu, vaddr addr, uint16_t idxmap, unsigned bits) { } -static inline void tlb_flush_range_by_mmuidx(CPUState *cpu, target_ulong addr, - target_ulong len, uint16_t idxmap, +static inline void tlb_flush_range_by_mmuidx(CPUState *cpu, vaddr addr, + vaddr len, uint16_t idxmap, unsigned bits) { } static inline void tlb_flush_range_by_mmuidx_all_cpus(CPUState *cpu, - target_ulong addr, - target_ulong len, + vaddr addr, + vaddr len, uint16_t idxmap, unsigned bits) { } static inline void tlb_flush_range_by_mmuidx_all_cpus_synced(CPUState *cpu, - target_ulong addr, - target_long len, + vaddr addr, + vaddr len, uint16_t idxmap, unsigned bits) { @@ -663,7 +662,7 @@ static inline void mmap_lock(void) {} static inline void mmap_unlock(void) {} void tlb_reset_dirty(CPUState *cpu, ram_addr_t start1, ram_addr_t length); -void tlb_set_dirty(CPUState *cpu, target_ulong vaddr); +void tlb_set_dirty(CPUState *cpu, vaddr addr); MemoryRegionSection * address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr addr, diff --git a/include/qemu/plugin-memory.h b/include/qemu/plugin-memory.h index 6fd539022a..43165f2452 100644 --- a/include/qemu/plugin-memory.h +++ b/include/qemu/plugin-memory.h @@ -37,7 +37,7 @@ struct qemu_plugin_hwaddr { * It would only fail if not called from an instrumented memory access * which would be an abuse of the API. */ -bool tlb_plugin_lookup(CPUState *cpu, target_ulong addr, int mmu_idx, +bool tlb_plugin_lookup(CPUState *cpu, vaddr addr, int mmu_idx, bool is_store, struct qemu_plugin_hwaddr *data); #endif /* PLUGIN_MEMORY_H */ From 256d11f9ba23c74db75d50b24e3357d583d7885b Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Wed, 21 Jun 2023 15:56:23 +0200 Subject: [PATCH 0185/1353] accel/tcg/translate-all.c: Widen pc and cs_base Signed-off-by: Anton Johansson Reviewed-by: Richard Henderson Message-Id: <20230621135633.1649-3-anjo@rev.ng> Signed-off-by: Richard Henderson --- accel/tcg/internal.h | 6 +++--- accel/tcg/translate-all.c | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/accel/tcg/internal.h b/accel/tcg/internal.h index 65380ccb42..91f308bdfa 100644 --- a/accel/tcg/internal.h +++ b/accel/tcg/internal.h @@ -42,8 +42,8 @@ void tb_invalidate_phys_range_fast(ram_addr_t ram_addr, G_NORETURN void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr); #endif /* CONFIG_SOFTMMU */ -TranslationBlock *tb_gen_code(CPUState *cpu, target_ulong pc, - target_ulong cs_base, uint32_t flags, +TranslationBlock *tb_gen_code(CPUState *cpu, vaddr pc, + uint64_t cs_base, uint32_t flags, int cflags); void page_init(void); void tb_htable_init(void); @@ -55,7 +55,7 @@ void cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb, uintptr_t host_pc); /* Return the current PC from CPU, which may be cached in TB. */ -static inline target_ulong log_pc(CPUState *cpu, const TranslationBlock *tb) +static inline vaddr log_pc(CPUState *cpu, const TranslationBlock *tb) { if (tb_cflags(tb) & CF_PCREL) { return cpu->cc->get_pc(cpu); diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index c4d081f5ad..03caf62459 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -274,7 +274,7 @@ void page_init(void) * Return the size of the generated code, or negative on error. */ static int setjmp_gen_code(CPUArchState *env, TranslationBlock *tb, - target_ulong pc, void *host_pc, + vaddr pc, void *host_pc, int *max_insns, int64_t *ti) { int ret = sigsetjmp(tcg_ctx->jmp_trans, 0); @@ -302,7 +302,7 @@ static int setjmp_gen_code(CPUArchState *env, TranslationBlock *tb, /* Called with mmap_lock held for user mode emulation. */ TranslationBlock *tb_gen_code(CPUState *cpu, - target_ulong pc, target_ulong cs_base, + vaddr pc, uint64_t cs_base, uint32_t flags, int cflags) { CPUArchState *env = cpu->env_ptr; @@ -634,10 +634,10 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr) cpu->cflags_next_tb = curr_cflags(cpu) | CF_MEMI_ONLY | CF_LAST_IO | n; if (qemu_loglevel_mask(CPU_LOG_EXEC)) { - target_ulong pc = log_pc(cpu, tb); + vaddr pc = log_pc(cpu, tb); if (qemu_log_in_addr_range(pc)) { - qemu_log("cpu_io_recompile: rewound execution of TB to " - TARGET_FMT_lx "\n", pc); + qemu_log("cpu_io_recompile: rewound execution of TB to %" + VADDR_PRIx "\n", pc); } } From bb5de52524c6c4b7da5623c5b19d9d6dc8405aa0 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Wed, 21 Jun 2023 15:56:24 +0200 Subject: [PATCH 0186/1353] target: Widen pc/cs_base in cpu_get_tb_cpu_state Signed-off-by: Anton Johansson Reviewed-by: Richard Henderson Message-Id: <20230621135633.1649-4-anjo@rev.ng> Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 9 ++++++--- accel/tcg/translate-all.c | 3 ++- target/alpha/cpu.h | 4 ++-- target/arm/cpu.h | 4 ++-- target/arm/helper.c | 4 ++-- target/avr/cpu.h | 4 ++-- target/cris/cpu.h | 4 ++-- target/hexagon/cpu.h | 4 ++-- target/hppa/cpu.h | 5 ++--- target/i386/cpu.h | 4 ++-- target/loongarch/cpu.h | 6 ++---- target/m68k/cpu.h | 4 ++-- target/microblaze/cpu.h | 4 ++-- target/mips/cpu.h | 4 ++-- target/nios2/cpu.h | 4 ++-- target/openrisc/cpu.h | 5 ++--- target/ppc/cpu.h | 8 ++++---- target/ppc/helper_regs.c | 4 ++-- target/riscv/cpu.h | 4 ++-- target/riscv/cpu_helper.c | 4 ++-- target/rx/cpu.h | 4 ++-- target/s390x/cpu.h | 4 ++-- target/sh4/cpu.h | 4 ++-- target/sparc/cpu.h | 4 ++-- target/tricore/cpu.h | 4 ++-- target/xtensa/cpu.h | 4 ++-- 26 files changed, 58 insertions(+), 58 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 179847b294..4d952a6cc2 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -408,7 +408,8 @@ const void *HELPER(lookup_tb_ptr)(CPUArchState *env) { CPUState *cpu = env_cpu(env); TranslationBlock *tb; - target_ulong cs_base, pc; + vaddr pc; + uint64_t cs_base; uint32_t flags, cflags; cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags); @@ -529,7 +530,8 @@ void cpu_exec_step_atomic(CPUState *cpu) { CPUArchState *env = cpu->env_ptr; TranslationBlock *tb; - target_ulong cs_base, pc; + vaddr pc; + uint64_t cs_base; uint32_t flags, cflags; int tb_exit; @@ -942,7 +944,8 @@ cpu_exec_loop(CPUState *cpu, SyncClocks *sc) while (!cpu_handle_interrupt(cpu, &last_tb)) { TranslationBlock *tb; - target_ulong cs_base, pc; + vaddr pc; + uint64_t cs_base; uint32_t flags, cflags; cpu_get_tb_cpu_state(cpu->env_ptr, &pc, &cs_base, &flags); diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 03caf62459..03c49baf1c 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -580,7 +580,8 @@ void tb_check_watchpoint(CPUState *cpu, uintptr_t retaddr) /* The exception probably happened in a helper. The CPU state should have been saved before calling it. Fetch the PC from there. */ CPUArchState *env = cpu->env_ptr; - target_ulong pc, cs_base; + vaddr pc; + uint64_t cs_base; tb_page_addr_t addr; uint32_t flags; diff --git a/target/alpha/cpu.h b/target/alpha/cpu.h index 5e67304d81..fcd20bfd3a 100644 --- a/target/alpha/cpu.h +++ b/target/alpha/cpu.h @@ -462,8 +462,8 @@ void alpha_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, MemTxResult response, uintptr_t retaddr); #endif -static inline void cpu_get_tb_cpu_state(CPUAlphaState *env, target_ulong *pc, - target_ulong *cs_base, uint32_t *pflags) +static inline void cpu_get_tb_cpu_state(CPUAlphaState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *pflags) { *pc = env->pc; *cs_base = 0; diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 11c3850ad9..00e675f58f 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -3220,8 +3220,8 @@ static inline bool arm_cpu_bswap_data(CPUARMState *env) } #endif -void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc, - target_ulong *cs_base, uint32_t *flags); +void cpu_get_tb_cpu_state(CPUARMState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *flags); enum { QEMU_PSCI_CONDUIT_DISABLED = 0, diff --git a/target/arm/helper.c b/target/arm/helper.c index 323cadd3c8..d08c058e42 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -11945,8 +11945,8 @@ static bool mve_no_pred(CPUARMState *env) return true; } -void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc, - target_ulong *cs_base, uint32_t *pflags) +void cpu_get_tb_cpu_state(CPUARMState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *pflags) { CPUARMTBFlags flags; diff --git a/target/avr/cpu.h b/target/avr/cpu.h index f19dd72926..7225174668 100644 --- a/target/avr/cpu.h +++ b/target/avr/cpu.h @@ -190,8 +190,8 @@ enum { TB_FLAGS_SKIP = 2, }; -static inline void cpu_get_tb_cpu_state(CPUAVRState *env, target_ulong *pc, - target_ulong *cs_base, uint32_t *pflags) +static inline void cpu_get_tb_cpu_state(CPUAVRState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *pflags) { uint32_t flags = 0; diff --git a/target/cris/cpu.h b/target/cris/cpu.h index 71fa1f96e0..8e37c6e50d 100644 --- a/target/cris/cpu.h +++ b/target/cris/cpu.h @@ -266,8 +266,8 @@ static inline int cpu_mmu_index (CPUCRISState *env, bool ifetch) #include "exec/cpu-all.h" -static inline void cpu_get_tb_cpu_state(CPUCRISState *env, target_ulong *pc, - target_ulong *cs_base, uint32_t *flags) +static inline void cpu_get_tb_cpu_state(CPUCRISState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *flags) { *pc = env->pc; *cs_base = 0; diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index bfcb1057dd..daef5c3f00 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -153,8 +153,8 @@ struct ArchCPU { FIELD(TB_FLAGS, IS_TIGHT_LOOP, 0, 1) -static inline void cpu_get_tb_cpu_state(CPUHexagonState *env, target_ulong *pc, - target_ulong *cs_base, uint32_t *flags) +static inline void cpu_get_tb_cpu_state(CPUHexagonState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *flags) { uint32_t hex_flags = 0; *pc = env->gpr[HEX_REG_PC]; diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h index b595ef25a9..7373177b55 100644 --- a/target/hppa/cpu.h +++ b/target/hppa/cpu.h @@ -268,9 +268,8 @@ static inline target_ulong hppa_form_gva(CPUHPPAState *env, uint64_t spc, #define TB_FLAG_PRIV_SHIFT 8 #define TB_FLAG_UNALIGN 0x400 -static inline void cpu_get_tb_cpu_state(CPUHPPAState *env, target_ulong *pc, - target_ulong *cs_base, - uint32_t *pflags) +static inline void cpu_get_tb_cpu_state(CPUHPPAState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *pflags) { uint32_t flags = env->psw_n * PSW_N; diff --git a/target/i386/cpu.h b/target/i386/cpu.h index cd047e0410..2c9b0d2ebc 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -2275,8 +2275,8 @@ static inline int cpu_mmu_index_kernel(CPUX86State *env) #include "hw/i386/apic.h" #endif -static inline void cpu_get_tb_cpu_state(CPUX86State *env, target_ulong *pc, - target_ulong *cs_base, uint32_t *flags) +static inline void cpu_get_tb_cpu_state(CPUX86State *env, vaddr *pc, + uint64_t *cs_base, uint32_t *flags) { *cs_base = env->segs[R_CS].base; *pc = *cs_base + env->eip; diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h index b23f38c3d5..ed04027af1 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -427,10 +427,8 @@ static inline int cpu_mmu_index(CPULoongArchState *env, bool ifetch) #define HW_FLAGS_EUEN_FPE 0x04 #define HW_FLAGS_EUEN_SXE 0x08 -static inline void cpu_get_tb_cpu_state(CPULoongArchState *env, - target_ulong *pc, - target_ulong *cs_base, - uint32_t *flags) +static inline void cpu_get_tb_cpu_state(CPULoongArchState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *flags) { *pc = env->pc; *cs_base = 0; diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h index 048d5aae2b..cf70282717 100644 --- a/target/m68k/cpu.h +++ b/target/m68k/cpu.h @@ -601,8 +601,8 @@ void m68k_cpu_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr, #define TB_FLAGS_TRACE 16 #define TB_FLAGS_TRACE_BIT (1 << TB_FLAGS_TRACE) -static inline void cpu_get_tb_cpu_state(CPUM68KState *env, target_ulong *pc, - target_ulong *cs_base, uint32_t *flags) +static inline void cpu_get_tb_cpu_state(CPUM68KState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *flags) { *pc = env->pc; *cs_base = 0; diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index 88324d0bc1..3525de144c 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -401,8 +401,8 @@ void mb_tcg_init(void); /* Ensure there is no overlap between the two masks. */ QEMU_BUILD_BUG_ON(MSR_TB_MASK & IFLAGS_TB_MASK); -static inline void cpu_get_tb_cpu_state(CPUMBState *env, target_ulong *pc, - target_ulong *cs_base, uint32_t *flags) +static inline void cpu_get_tb_cpu_state(CPUMBState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *flags) { *pc = env->pc; *flags = (env->iflags & IFLAGS_TB_MASK) | (env->msr & MSR_TB_MASK); diff --git a/target/mips/cpu.h b/target/mips/cpu.h index 142c55af47..a3bc646976 100644 --- a/target/mips/cpu.h +++ b/target/mips/cpu.h @@ -1313,8 +1313,8 @@ void itc_reconfigure(struct MIPSITUState *tag); /* helper.c */ target_ulong exception_resume_pc(CPUMIPSState *env); -static inline void cpu_get_tb_cpu_state(CPUMIPSState *env, target_ulong *pc, - target_ulong *cs_base, uint32_t *flags) +static inline void cpu_get_tb_cpu_state(CPUMIPSState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *flags) { *pc = env->active_tc.PC; *cs_base = 0; diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h index 20042c4332..477a3161fd 100644 --- a/target/nios2/cpu.h +++ b/target/nios2/cpu.h @@ -302,8 +302,8 @@ FIELD(TBFLAGS, CRS0, 0, 1) /* Set if CRS == 0. */ FIELD(TBFLAGS, U, 1, 1) /* Overlaps CR_STATUS_U */ FIELD(TBFLAGS, R0_0, 2, 1) /* Set if R0 == 0. */ -static inline void cpu_get_tb_cpu_state(CPUNios2State *env, target_ulong *pc, - target_ulong *cs_base, uint32_t *flags) +static inline void cpu_get_tb_cpu_state(CPUNios2State *env, vaddr *pc, + uint64_t *cs_base, uint32_t *flags) { unsigned crs = FIELD_EX32(env->ctrl[CR_STATUS], CR_STATUS, CRS); diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h index f16e8b3274..92c38f54c2 100644 --- a/target/openrisc/cpu.h +++ b/target/openrisc/cpu.h @@ -367,9 +367,8 @@ static inline void cpu_set_gpr(CPUOpenRISCState *env, int i, uint32_t val) env->shadow_gpr[0][i] = val; } -static inline void cpu_get_tb_cpu_state(CPUOpenRISCState *env, - target_ulong *pc, - target_ulong *cs_base, uint32_t *flags) +static inline void cpu_get_tb_cpu_state(CPUOpenRISCState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *flags) { *pc = env->pc; *cs_base = 0; diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 4138a25801..94497aa115 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -2508,11 +2508,11 @@ void cpu_write_xer(CPUPPCState *env, target_ulong xer); #define is_book3s_arch2x(ctx) (!!((ctx)->insns_flags & PPC_SEGMENT_64B)) #ifdef CONFIG_DEBUG_TCG -void cpu_get_tb_cpu_state(CPUPPCState *env, target_ulong *pc, - target_ulong *cs_base, uint32_t *flags); +void cpu_get_tb_cpu_state(CPUPPCState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *flags); #else -static inline void cpu_get_tb_cpu_state(CPUPPCState *env, target_ulong *pc, - target_ulong *cs_base, uint32_t *flags) +static inline void cpu_get_tb_cpu_state(CPUPPCState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *flags) { *pc = env->nip; *cs_base = 0; diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c index e27f4a75a4..f380342d4d 100644 --- a/target/ppc/helper_regs.c +++ b/target/ppc/helper_regs.c @@ -218,8 +218,8 @@ void hreg_update_pmu_hflags(CPUPPCState *env) } #ifdef CONFIG_DEBUG_TCG -void cpu_get_tb_cpu_state(CPUPPCState *env, target_ulong *pc, - target_ulong *cs_base, uint32_t *flags) +void cpu_get_tb_cpu_state(CPUPPCState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *flags) { uint32_t hflags_current = env->hflags; uint32_t hflags_rebuilt; diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index e3e08d315f..7bff1d47f6 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -587,8 +587,8 @@ static inline uint32_t vext_get_vlmax(RISCVCPU *cpu, target_ulong vtype) return cpu->cfg.vlen >> (sew + 3 - lmul); } -void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc, - target_ulong *cs_base, uint32_t *pflags); +void cpu_get_tb_cpu_state(CPURISCVState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *pflags); void riscv_cpu_update_mask(CPURISCVState *env); diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 90cef9856d..a944f25694 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -61,8 +61,8 @@ int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch) #endif } -void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc, - target_ulong *cs_base, uint32_t *pflags) +void cpu_get_tb_cpu_state(CPURISCVState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *pflags) { CPUState *cs = env_cpu(env); RISCVCPU *cpu = RISCV_CPU(cs); diff --git a/target/rx/cpu.h b/target/rx/cpu.h index 555d230f24..7f03ffcfed 100644 --- a/target/rx/cpu.h +++ b/target/rx/cpu.h @@ -143,8 +143,8 @@ void rx_cpu_unpack_psw(CPURXState *env, uint32_t psw, int rte); #define RX_CPU_IRQ 0 #define RX_CPU_FIR 1 -static inline void cpu_get_tb_cpu_state(CPURXState *env, target_ulong *pc, - target_ulong *cs_base, uint32_t *flags) +static inline void cpu_get_tb_cpu_state(CPURXState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *flags) { *pc = env->pc; *cs_base = 0; diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index f130c29f83..eb5b65b7d3 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -378,8 +378,8 @@ static inline int cpu_mmu_index(CPUS390XState *env, bool ifetch) #endif } -static inline void cpu_get_tb_cpu_state(CPUS390XState* env, target_ulong *pc, - target_ulong *cs_base, uint32_t *flags) +static inline void cpu_get_tb_cpu_state(CPUS390XState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *flags) { if (env->psw.addr & 1) { /* diff --git a/target/sh4/cpu.h b/target/sh4/cpu.h index 02bfd612ea..1399d3840f 100644 --- a/target/sh4/cpu.h +++ b/target/sh4/cpu.h @@ -368,8 +368,8 @@ static inline void cpu_write_sr(CPUSH4State *env, target_ulong sr) env->sr = sr & ~((1u << SR_M) | (1u << SR_Q) | (1u << SR_T)); } -static inline void cpu_get_tb_cpu_state(CPUSH4State *env, target_ulong *pc, - target_ulong *cs_base, uint32_t *flags) +static inline void cpu_get_tb_cpu_state(CPUSH4State *env, vaddr *pc, + uint64_t *cs_base, uint32_t *flags) { *pc = env->pc; /* For a gUSA region, notice the end of the region. */ diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h index 3d090e8278..95d2d0da71 100644 --- a/target/sparc/cpu.h +++ b/target/sparc/cpu.h @@ -762,8 +762,8 @@ trap_state* cpu_tsptr(CPUSPARCState* env); #define TB_FLAG_HYPER (1 << 7) #define TB_FLAG_ASI_SHIFT 24 -static inline void cpu_get_tb_cpu_state(CPUSPARCState *env, target_ulong *pc, - target_ulong *cs_base, uint32_t *pflags) +static inline void cpu_get_tb_cpu_state(CPUSPARCState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *pflags) { uint32_t flags; *pc = env->pc; diff --git a/target/tricore/cpu.h b/target/tricore/cpu.h index 257fcf3cee..a50b91cc36 100644 --- a/target/tricore/cpu.h +++ b/target/tricore/cpu.h @@ -384,8 +384,8 @@ FIELD(TB_FLAGS, PRIV, 0, 2) void cpu_state_reset(CPUTriCoreState *s); void tricore_tcg_init(void); -static inline void cpu_get_tb_cpu_state(CPUTriCoreState *env, target_ulong *pc, - target_ulong *cs_base, uint32_t *flags) +static inline void cpu_get_tb_cpu_state(CPUTriCoreState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *flags) { uint32_t new_flags = 0; *pc = env->PC; diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h index b7a54711a6..87fe992ba6 100644 --- a/target/xtensa/cpu.h +++ b/target/xtensa/cpu.h @@ -727,8 +727,8 @@ static inline int cpu_mmu_index(CPUXtensaState *env, bool ifetch) #include "exec/cpu-all.h" -static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, target_ulong *pc, - target_ulong *cs_base, uint32_t *flags) +static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *flags) { *pc = env->pc; *cs_base = 0; From 9e39de980fdf0dbb083a5c78b71bf2c1bdfa0499 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Wed, 21 Jun 2023 15:56:25 +0200 Subject: [PATCH 0187/1353] accel/tcg/cputlb.c: Widen CPUTLBEntry access functions Signed-off-by: Anton Johansson Reviewed-by: Richard Henderson Message-Id: <20230621135633.1649-5-anjo@rev.ng> Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 8 ++++---- include/exec/cpu_ldst.h | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 5caeccb52d..ac990a1526 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -1453,7 +1453,7 @@ static bool victim_tlb_hit(CPUArchState *env, size_t mmu_idx, size_t index, assert_cpu_is_self(env_cpu(env)); for (vidx = 0; vidx < CPU_VTLB_SIZE; ++vidx) { CPUTLBEntry *vtlb = &env_tlb(env)->d[mmu_idx].vtable[vidx]; - target_ulong cmp = tlb_read_idx(vtlb, access_type); + uint64_t cmp = tlb_read_idx(vtlb, access_type); if (cmp == page) { /* Found entry in victim tlb, swap tlb and iotlb. */ @@ -1507,7 +1507,7 @@ static int probe_access_internal(CPUArchState *env, target_ulong addr, { uintptr_t index = tlb_index(env, mmu_idx, addr); CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr); - target_ulong tlb_addr = tlb_read_idx(entry, access_type); + uint64_t tlb_addr = tlb_read_idx(entry, access_type); target_ulong page_addr = addr & TARGET_PAGE_MASK; int flags = TLB_FLAGS_MASK; @@ -1694,7 +1694,7 @@ bool tlb_plugin_lookup(CPUState *cpu, vaddr addr, int mmu_idx, CPUArchState *env = cpu->env_ptr; CPUTLBEntry *tlbe = tlb_entry(env, mmu_idx, addr); uintptr_t index = tlb_index(env, mmu_idx, addr); - vaddr tlb_addr = is_store ? tlb_addr_write(tlbe) : tlbe->addr_read; + uint64_t tlb_addr = is_store ? tlb_addr_write(tlbe) : tlbe->addr_read; if (likely(tlb_hit(tlb_addr, addr))) { /* We must have an iotlb entry for MMIO */ @@ -1759,7 +1759,7 @@ static bool mmu_lookup1(CPUArchState *env, MMULookupPageData *data, target_ulong addr = data->addr; uintptr_t index = tlb_index(env, mmu_idx, addr); CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr); - target_ulong tlb_addr = tlb_read_idx(entry, access_type); + uint64_t tlb_addr = tlb_read_idx(entry, access_type); bool maybe_resized = false; /* If the TLB entry is for a different page, reload and try again. */ diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h index 896f305ff3..645476f0e5 100644 --- a/include/exec/cpu_ldst.h +++ b/include/exec/cpu_ldst.h @@ -328,8 +328,8 @@ static inline void clear_helper_retaddr(void) #include "tcg/oversized-guest.h" -static inline target_ulong tlb_read_idx(const CPUTLBEntry *entry, - MMUAccessType access_type) +static inline uint64_t tlb_read_idx(const CPUTLBEntry *entry, + MMUAccessType access_type) { /* Do not rearrange the CPUTLBEntry structure members. */ QEMU_BUILD_BUG_ON(offsetof(CPUTLBEntry, addr_read) != @@ -355,14 +355,14 @@ static inline target_ulong tlb_read_idx(const CPUTLBEntry *entry, #endif } -static inline target_ulong tlb_addr_write(const CPUTLBEntry *entry) +static inline uint64_t tlb_addr_write(const CPUTLBEntry *entry) { return tlb_read_idx(entry, MMU_DATA_STORE); } /* 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) + vaddr addr) { uintptr_t size_mask = env_tlb(env)->f[mmu_idx].mask >> CPU_TLB_ENTRY_BITS; @@ -371,7 +371,7 @@ static inline uintptr_t tlb_index(CPUArchState *env, uintptr_t mmu_idx, /* 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) + vaddr addr) { return &env_tlb(env)->f[mmu_idx].table[tlb_index(env, mmu_idx, addr)]; } From fb2c53cb710e3f3a4c6d4bb6f2465295e216b835 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Wed, 21 Jun 2023 15:56:26 +0200 Subject: [PATCH 0188/1353] accel/tcg/cputlb.c: Widen addr in MMULookupPageData Functions accessing MMULookupPageData are also updated. Signed-off-by: Anton Johansson Reviewed-by: Richard Henderson Message-Id: <20230621135633.1649-6-anjo@rev.ng> Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index ac990a1526..cc53d0fb64 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -1729,7 +1729,7 @@ bool tlb_plugin_lookup(CPUState *cpu, vaddr addr, int mmu_idx, typedef struct MMULookupPageData { CPUTLBEntryFull *full; void *haddr; - target_ulong addr; + vaddr addr; int flags; int size; } MMULookupPageData; @@ -1756,7 +1756,7 @@ typedef struct MMULookupLocals { static bool mmu_lookup1(CPUArchState *env, MMULookupPageData *data, int mmu_idx, MMUAccessType access_type, uintptr_t ra) { - target_ulong addr = data->addr; + vaddr addr = data->addr; uintptr_t index = tlb_index(env, mmu_idx, addr); CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr); uint64_t tlb_addr = tlb_read_idx(entry, access_type); @@ -1796,7 +1796,7 @@ static void mmu_watch_or_dirty(CPUArchState *env, MMULookupPageData *data, MMUAccessType access_type, uintptr_t ra) { CPUTLBEntryFull *full = data->full; - target_ulong addr = data->addr; + vaddr addr = data->addr; int flags = data->flags; int size = data->size; @@ -1827,7 +1827,7 @@ static void mmu_watch_or_dirty(CPUArchState *env, MMULookupPageData *data, * Resolve the translation for the page(s) beginning at @addr, for MemOp.size * bytes. Return true if the lookup crosses a page boundary. */ -static bool mmu_lookup(CPUArchState *env, target_ulong addr, MemOpIdx oi, +static bool mmu_lookup(CPUArchState *env, vaddr addr, MemOpIdx oi, uintptr_t ra, MMUAccessType type, MMULookupLocals *l) { unsigned a_bits; @@ -2024,7 +2024,7 @@ static uint64_t do_ld_mmio_beN(CPUArchState *env, MMULookupPageData *p, MMUAccessType type, uintptr_t ra) { CPUTLBEntryFull *full = p->full; - target_ulong addr = p->addr; + vaddr addr = p->addr; int i, size = p->size; QEMU_IOTHREAD_LOCK_GUARD(); @@ -2333,7 +2333,7 @@ static uint64_t do_ld_8(CPUArchState *env, MMULookupPageData *p, int mmu_idx, return ret; } -static uint8_t do_ld1_mmu(CPUArchState *env, target_ulong addr, MemOpIdx oi, +static uint8_t do_ld1_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, uintptr_t ra, MMUAccessType access_type) { MMULookupLocals l; @@ -2352,7 +2352,7 @@ tcg_target_ulong helper_ldub_mmu(CPUArchState *env, uint64_t addr, return do_ld1_mmu(env, addr, oi, retaddr, MMU_DATA_LOAD); } -static uint16_t do_ld2_mmu(CPUArchState *env, target_ulong addr, MemOpIdx oi, +static uint16_t do_ld2_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, uintptr_t ra, MMUAccessType access_type) { MMULookupLocals l; @@ -2383,7 +2383,7 @@ tcg_target_ulong helper_lduw_mmu(CPUArchState *env, uint64_t addr, return do_ld2_mmu(env, addr, oi, retaddr, MMU_DATA_LOAD); } -static uint32_t do_ld4_mmu(CPUArchState *env, target_ulong addr, MemOpIdx oi, +static uint32_t do_ld4_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, uintptr_t ra, MMUAccessType access_type) { MMULookupLocals l; @@ -2410,7 +2410,7 @@ tcg_target_ulong helper_ldul_mmu(CPUArchState *env, uint64_t addr, return do_ld4_mmu(env, addr, oi, retaddr, MMU_DATA_LOAD); } -static uint64_t do_ld8_mmu(CPUArchState *env, target_ulong addr, MemOpIdx oi, +static uint64_t do_ld8_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, uintptr_t ra, MMUAccessType access_type) { MMULookupLocals l; @@ -2460,7 +2460,7 @@ tcg_target_ulong helper_ldsl_mmu(CPUArchState *env, uint64_t addr, return (int32_t)helper_ldul_mmu(env, addr, oi, retaddr); } -static Int128 do_ld16_mmu(CPUArchState *env, target_ulong addr, +static Int128 do_ld16_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, uintptr_t ra) { MMULookupLocals l; @@ -2617,7 +2617,7 @@ static uint64_t do_st_mmio_leN(CPUArchState *env, MMULookupPageData *p, uint64_t val_le, int mmu_idx, uintptr_t ra) { CPUTLBEntryFull *full = p->full; - target_ulong addr = p->addr; + vaddr addr = p->addr; int i, size = p->size; QEMU_IOTHREAD_LOCK_GUARD(); @@ -2808,7 +2808,7 @@ void helper_stb_mmu(CPUArchState *env, uint64_t addr, uint32_t val, do_st_1(env, &l.page[0], val, l.mmu_idx, ra); } -static void do_st2_mmu(CPUArchState *env, target_ulong addr, uint16_t val, +static void do_st2_mmu(CPUArchState *env, vaddr addr, uint16_t val, MemOpIdx oi, uintptr_t ra) { MMULookupLocals l; @@ -2837,7 +2837,7 @@ void helper_stw_mmu(CPUArchState *env, uint64_t addr, uint32_t val, do_st2_mmu(env, addr, val, oi, retaddr); } -static void do_st4_mmu(CPUArchState *env, target_ulong addr, uint32_t val, +static void do_st4_mmu(CPUArchState *env, vaddr addr, uint32_t val, MemOpIdx oi, uintptr_t ra) { MMULookupLocals l; @@ -2864,7 +2864,7 @@ void helper_stl_mmu(CPUArchState *env, uint64_t addr, uint32_t val, do_st4_mmu(env, addr, val, oi, retaddr); } -static void do_st8_mmu(CPUArchState *env, target_ulong addr, uint64_t val, +static void do_st8_mmu(CPUArchState *env, vaddr addr, uint64_t val, MemOpIdx oi, uintptr_t ra) { MMULookupLocals l; @@ -2891,7 +2891,7 @@ void helper_stq_mmu(CPUArchState *env, uint64_t addr, uint64_t val, do_st8_mmu(env, addr, val, oi, retaddr); } -static void do_st16_mmu(CPUArchState *env, target_ulong addr, Int128 val, +static void do_st16_mmu(CPUArchState *env, vaddr addr, Int128 val, MemOpIdx oi, uintptr_t ra) { MMULookupLocals l; From f0a08b0913befbd400c16fb444612b6d034a2c53 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Wed, 21 Jun 2023 15:56:27 +0200 Subject: [PATCH 0189/1353] accel/tcg/cpu-exec.c: Widen pc to vaddr Signed-off-by: Anton Johansson Reviewed-by: Richard Henderson Message-Id: <20230621135633.1649-7-anjo@rev.ng> Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 4d952a6cc2..ba1890a373 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -169,8 +169,8 @@ uint32_t curr_cflags(CPUState *cpu) } struct tb_desc { - target_ulong pc; - target_ulong cs_base; + vaddr pc; + uint64_t cs_base; CPUArchState *env; tb_page_addr_t page_addr0; uint32_t flags; @@ -193,7 +193,7 @@ static bool tb_lookup_cmp(const void *p, const void *d) return true; } else { tb_page_addr_t phys_page1; - target_ulong virt_page1; + vaddr virt_page1; /* * We know that the first page matched, and an otherwise valid TB @@ -214,8 +214,8 @@ static bool tb_lookup_cmp(const void *p, const void *d) return false; } -static TranslationBlock *tb_htable_lookup(CPUState *cpu, target_ulong pc, - target_ulong cs_base, uint32_t flags, +static TranslationBlock *tb_htable_lookup(CPUState *cpu, vaddr pc, + uint64_t cs_base, uint32_t flags, uint32_t cflags) { tb_page_addr_t phys_pc; @@ -238,9 +238,9 @@ static TranslationBlock *tb_htable_lookup(CPUState *cpu, target_ulong pc, } /* Might cause an exception, so have a longjmp destination ready */ -static inline TranslationBlock *tb_lookup(CPUState *cpu, target_ulong pc, - target_ulong cs_base, - uint32_t flags, uint32_t cflags) +static inline TranslationBlock *tb_lookup(CPUState *cpu, vaddr pc, + uint64_t cs_base, uint32_t flags, + uint32_t cflags) { TranslationBlock *tb; CPUJumpCache *jc; @@ -292,13 +292,13 @@ static inline TranslationBlock *tb_lookup(CPUState *cpu, target_ulong pc, return tb; } -static void log_cpu_exec(target_ulong pc, CPUState *cpu, +static void log_cpu_exec(vaddr pc, CPUState *cpu, const TranslationBlock *tb) { if (qemu_log_in_addr_range(pc)) { qemu_log_mask(CPU_LOG_EXEC, "Trace %d: %p [%08" PRIx64 - "/" TARGET_FMT_lx "/%08x/%08x] %s\n", + "/%" VADDR_PRIx "/%08x/%08x] %s\n", cpu->cpu_index, tb->tc.ptr, tb->cs_base, pc, tb->flags, tb->cflags, lookup_symbol(pc)); @@ -323,7 +323,7 @@ static void log_cpu_exec(target_ulong pc, CPUState *cpu, } } -static bool check_for_breakpoints_slow(CPUState *cpu, target_ulong pc, +static bool check_for_breakpoints_slow(CPUState *cpu, vaddr pc, uint32_t *cflags) { CPUBreakpoint *bp; @@ -389,7 +389,7 @@ static bool check_for_breakpoints_slow(CPUState *cpu, target_ulong pc, return false; } -static inline bool check_for_breakpoints(CPUState *cpu, target_ulong pc, +static inline bool check_for_breakpoints(CPUState *cpu, vaddr pc, uint32_t *cflags) { return unlikely(!QTAILQ_EMPTY(&cpu->breakpoints)) && @@ -485,10 +485,10 @@ cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit) cc->set_pc(cpu, last_tb->pc); } if (qemu_loglevel_mask(CPU_LOG_EXEC)) { - target_ulong pc = log_pc(cpu, last_tb); + vaddr pc = log_pc(cpu, last_tb); if (qemu_log_in_addr_range(pc)) { - qemu_log("Stopped execution of TB chain before %p [" - TARGET_FMT_lx "] %s\n", + qemu_log("Stopped execution of TB chain before %p [%" + VADDR_PRIx "] %s\n", last_tb->tc.ptr, pc, lookup_symbol(pc)); } } @@ -882,8 +882,8 @@ static inline bool cpu_handle_interrupt(CPUState *cpu, } static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb, - target_ulong pc, - TranslationBlock **last_tb, int *tb_exit) + vaddr pc, TranslationBlock **last_tb, + int *tb_exit) { int32_t insns_left; From 06f3831c08ac0d36ce3d0b1f2deaa8ec1e1d8d7e Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Wed, 21 Jun 2023 15:56:28 +0200 Subject: [PATCH 0190/1353] accel/tcg: Widen pc to vaddr in CPUJumpCache Related functions dealing with the jump cache are also updated. Signed-off-by: Anton Johansson Reviewed-by: Richard Henderson Message-Id: <20230621135633.1649-8-anjo@rev.ng> Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 2 +- accel/tcg/tb-hash.h | 12 ++++++------ accel/tcg/tb-jmp-cache.h | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index cc53d0fb64..bdf400f6e6 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -99,7 +99,7 @@ static void tlb_window_reset(CPUTLBDesc *desc, int64_t ns, desc->window_max_entries = max_entries; } -static void tb_jmp_cache_clear_page(CPUState *cpu, target_ulong page_addr) +static void tb_jmp_cache_clear_page(CPUState *cpu, vaddr page_addr) { CPUJumpCache *jc = cpu->tb_jmp_cache; int i, i0; diff --git a/accel/tcg/tb-hash.h b/accel/tcg/tb-hash.h index 2ba2193731..a0c61f25cd 100644 --- a/accel/tcg/tb-hash.h +++ b/accel/tcg/tb-hash.h @@ -35,16 +35,16 @@ #define TB_JMP_ADDR_MASK (TB_JMP_PAGE_SIZE - 1) #define TB_JMP_PAGE_MASK (TB_JMP_CACHE_SIZE - TB_JMP_PAGE_SIZE) -static inline unsigned int tb_jmp_cache_hash_page(target_ulong pc) +static inline unsigned int tb_jmp_cache_hash_page(vaddr pc) { - target_ulong tmp; + vaddr tmp; tmp = pc ^ (pc >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS)); return (tmp >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS)) & TB_JMP_PAGE_MASK; } -static inline unsigned int tb_jmp_cache_hash_func(target_ulong pc) +static inline unsigned int tb_jmp_cache_hash_func(vaddr pc) { - target_ulong tmp; + vaddr tmp; tmp = pc ^ (pc >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS)); return (((tmp >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS)) & TB_JMP_PAGE_MASK) | (tmp & TB_JMP_ADDR_MASK)); @@ -53,7 +53,7 @@ static inline unsigned int tb_jmp_cache_hash_func(target_ulong pc) #else /* In user-mode we can get better hashing because we do not have a TLB */ -static inline unsigned int tb_jmp_cache_hash_func(target_ulong pc) +static inline unsigned int tb_jmp_cache_hash_func(vaddr pc) { return (pc ^ (pc >> TB_JMP_CACHE_BITS)) & (TB_JMP_CACHE_SIZE - 1); } @@ -61,7 +61,7 @@ static inline unsigned int tb_jmp_cache_hash_func(target_ulong pc) #endif /* CONFIG_SOFTMMU */ static inline -uint32_t tb_hash_func(tb_page_addr_t phys_pc, target_ulong pc, +uint32_t tb_hash_func(tb_page_addr_t phys_pc, vaddr pc, uint32_t flags, uint64_t flags2, uint32_t cf_mask) { return qemu_xxhash8(phys_pc, pc, flags2, flags, cf_mask); diff --git a/accel/tcg/tb-jmp-cache.h b/accel/tcg/tb-jmp-cache.h index bee87eb840..bb424c8a05 100644 --- a/accel/tcg/tb-jmp-cache.h +++ b/accel/tcg/tb-jmp-cache.h @@ -21,7 +21,7 @@ struct CPUJumpCache { struct rcu_head rcu; struct { TranslationBlock *tb; - target_ulong pc; + vaddr pc; } array[TB_JMP_CACHE_SIZE]; }; From 4f8f41272eec57105e82dbb5761354ef0da9f7b0 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Wed, 21 Jun 2023 15:56:29 +0200 Subject: [PATCH 0191/1353] accel: Replace target_ulong with vaddr in probe_*() Functions for probing memory accesses (and functions that call these) are updated to take a vaddr for guest virtual addresses over target_ulong. Signed-off-by: Anton Johansson Reviewed-by: Richard Henderson Message-Id: <20230621135633.1649-9-anjo@rev.ng> Signed-off-by: Richard Henderson --- accel/stubs/tcg-stub.c | 4 ++-- accel/tcg/cputlb.c | 12 ++++++------ accel/tcg/user-exec.c | 8 ++++---- include/exec/exec-all.h | 14 +++++++------- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/accel/stubs/tcg-stub.c b/accel/stubs/tcg-stub.c index 0998e601ad..a9e7a2d5b4 100644 --- a/accel/stubs/tcg-stub.c +++ b/accel/stubs/tcg-stub.c @@ -26,14 +26,14 @@ void tcg_flush_jmp_cache(CPUState *cpu) { } -int probe_access_flags(CPUArchState *env, target_ulong addr, int size, +int probe_access_flags(CPUArchState *env, vaddr addr, int size, MMUAccessType access_type, int mmu_idx, bool nonfault, void **phost, uintptr_t retaddr) { g_assert_not_reached(); } -void *probe_access(CPUArchState *env, target_ulong addr, int size, +void *probe_access(CPUArchState *env, vaddr addr, int size, MMUAccessType access_type, int mmu_idx, uintptr_t retaddr) { /* Handled by hardware accelerator. */ diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index bdf400f6e6..d873e58a5d 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -1499,7 +1499,7 @@ static void notdirty_write(CPUState *cpu, vaddr mem_vaddr, unsigned size, } } -static int probe_access_internal(CPUArchState *env, target_ulong addr, +static int probe_access_internal(CPUArchState *env, vaddr addr, int fault_size, MMUAccessType access_type, int mmu_idx, bool nonfault, void **phost, CPUTLBEntryFull **pfull, @@ -1508,7 +1508,7 @@ static int probe_access_internal(CPUArchState *env, target_ulong addr, uintptr_t index = tlb_index(env, mmu_idx, addr); CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr); uint64_t tlb_addr = tlb_read_idx(entry, access_type); - target_ulong page_addr = addr & TARGET_PAGE_MASK; + vaddr page_addr = addr & TARGET_PAGE_MASK; int flags = TLB_FLAGS_MASK; if (!tlb_hit_page(tlb_addr, page_addr)) { @@ -1551,7 +1551,7 @@ static int probe_access_internal(CPUArchState *env, target_ulong addr, return flags; } -int probe_access_full(CPUArchState *env, target_ulong addr, int size, +int probe_access_full(CPUArchState *env, vaddr addr, int size, MMUAccessType access_type, int mmu_idx, bool nonfault, void **phost, CPUTLBEntryFull **pfull, uintptr_t retaddr) @@ -1568,7 +1568,7 @@ int probe_access_full(CPUArchState *env, target_ulong addr, int size, return flags; } -int probe_access_flags(CPUArchState *env, target_ulong addr, int size, +int probe_access_flags(CPUArchState *env, vaddr addr, int size, MMUAccessType access_type, int mmu_idx, bool nonfault, void **phost, uintptr_t retaddr) { @@ -1589,7 +1589,7 @@ int probe_access_flags(CPUArchState *env, target_ulong addr, int size, return flags; } -void *probe_access(CPUArchState *env, target_ulong addr, int size, +void *probe_access(CPUArchState *env, vaddr addr, int size, MMUAccessType access_type, int mmu_idx, uintptr_t retaddr) { CPUTLBEntryFull *full; @@ -1648,7 +1648,7 @@ void *tlb_vaddr_to_host(CPUArchState *env, abi_ptr addr, * NOTE: This function will trigger an exception if the page is * not executable. */ -tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, target_ulong addr, +tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, vaddr addr, void **hostp) { CPUTLBEntryFull *full; diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index dc8d6b5d40..d71e26a7b5 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -721,7 +721,7 @@ int page_unprotect(target_ulong address, uintptr_t pc) return current_tb_invalidated ? 2 : 1; } -static int probe_access_internal(CPUArchState *env, target_ulong addr, +static int probe_access_internal(CPUArchState *env, vaddr addr, int fault_size, MMUAccessType access_type, bool nonfault, uintptr_t ra) { @@ -759,7 +759,7 @@ static int probe_access_internal(CPUArchState *env, target_ulong addr, cpu_loop_exit_sigsegv(env_cpu(env), addr, access_type, maperr, ra); } -int probe_access_flags(CPUArchState *env, target_ulong addr, int size, +int probe_access_flags(CPUArchState *env, vaddr addr, int size, MMUAccessType access_type, int mmu_idx, bool nonfault, void **phost, uintptr_t ra) { @@ -771,7 +771,7 @@ int probe_access_flags(CPUArchState *env, target_ulong addr, int size, return flags; } -void *probe_access(CPUArchState *env, target_ulong addr, int size, +void *probe_access(CPUArchState *env, vaddr addr, int size, MMUAccessType access_type, int mmu_idx, uintptr_t ra) { int flags; @@ -783,7 +783,7 @@ void *probe_access(CPUArchState *env, target_ulong addr, int size, return size ? g2h(env_cpu(env), addr) : NULL; } -tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, target_ulong addr, +tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, vaddr addr, void **hostp) { int flags; diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index f5508e242b..cc1c3556f6 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -413,16 +413,16 @@ static inline void tlb_flush_range_by_mmuidx_all_cpus_synced(CPUState *cpu, * Finally, return the host address for a page that is backed by RAM, * or NULL if the page requires I/O. */ -void *probe_access(CPUArchState *env, target_ulong addr, int size, +void *probe_access(CPUArchState *env, vaddr addr, int size, MMUAccessType access_type, int mmu_idx, uintptr_t retaddr); -static inline void *probe_write(CPUArchState *env, target_ulong addr, int size, +static inline void *probe_write(CPUArchState *env, vaddr addr, int size, int mmu_idx, uintptr_t retaddr) { return probe_access(env, addr, size, MMU_DATA_STORE, mmu_idx, retaddr); } -static inline void *probe_read(CPUArchState *env, target_ulong addr, int size, +static inline void *probe_read(CPUArchState *env, vaddr addr, int size, int mmu_idx, uintptr_t retaddr) { return probe_access(env, addr, size, MMU_DATA_LOAD, mmu_idx, retaddr); @@ -447,7 +447,7 @@ static inline void *probe_read(CPUArchState *env, target_ulong addr, int size, * Do handle clean pages, so exclude TLB_NOTDIRY from the returned flags. * For simplicity, all "mmio-like" flags are folded to TLB_MMIO. */ -int probe_access_flags(CPUArchState *env, target_ulong addr, int size, +int probe_access_flags(CPUArchState *env, vaddr addr, int size, MMUAccessType access_type, int mmu_idx, bool nonfault, void **phost, uintptr_t retaddr); @@ -460,7 +460,7 @@ int probe_access_flags(CPUArchState *env, target_ulong addr, int size, * and must be consumed or copied immediately, before any further * access or changes to TLB @mmu_idx. */ -int probe_access_full(CPUArchState *env, target_ulong addr, int size, +int probe_access_full(CPUArchState *env, vaddr addr, int size, MMUAccessType access_type, int mmu_idx, bool nonfault, void **phost, CPUTLBEntryFull **pfull, uintptr_t retaddr); @@ -581,7 +581,7 @@ struct MemoryRegionSection *iotlb_to_section(CPUState *cpu, * * Note: this function can trigger an exception. */ -tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, target_ulong addr, +tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, vaddr addr, void **hostp); /** @@ -596,7 +596,7 @@ tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, target_ulong addr, * Note: this function can trigger an exception. */ static inline tb_page_addr_t get_page_addr_code(CPUArchState *env, - target_ulong addr) + vaddr addr) { return get_page_addr_code_hostp(env, addr, NULL); } From b0326eb99917d99a37c8cd9d479a2e9b04659076 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Wed, 21 Jun 2023 15:56:30 +0200 Subject: [PATCH 0192/1353] accel/tcg: Replace target_ulong with vaddr in *_mmu_lookup() Update atomic_mmu_lookup() and cpu_mmu_lookup() to take the guest virtual address as a vaddr instead of a target_ulong. Signed-off-by: Anton Johansson Reviewed-by: Richard Henderson Message-Id: <20230621135633.1649-10-anjo@rev.ng> Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 6 +++--- accel/tcg/user-exec.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index d873e58a5d..e02cfc550e 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -1898,15 +1898,15 @@ static bool mmu_lookup(CPUArchState *env, vaddr addr, MemOpIdx oi, * Probe for an atomic operation. Do not allow unaligned operations, * or io operations to proceed. Return the host address. */ -static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr, - MemOpIdx oi, int size, uintptr_t retaddr) +static void *atomic_mmu_lookup(CPUArchState *env, vaddr addr, MemOpIdx oi, + int size, uintptr_t retaddr) { uintptr_t mmu_idx = get_mmuidx(oi); MemOp mop = get_memop(oi); int a_bits = get_alignment_bits(mop); uintptr_t index; CPUTLBEntry *tlbe; - target_ulong tlb_addr; + vaddr tlb_addr; void *hostaddr; CPUTLBEntryFull *full; diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index d71e26a7b5..f8b16d6ab8 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -889,7 +889,7 @@ void page_reset_target_data(target_ulong start, target_ulong last) { } /* The softmmu versions of these helpers are in cputlb.c. */ -static void *cpu_mmu_lookup(CPUArchState *env, abi_ptr addr, +static void *cpu_mmu_lookup(CPUArchState *env, vaddr addr, MemOp mop, uintptr_t ra, MMUAccessType type) { int a_bits = get_alignment_bits(mop); @@ -1324,8 +1324,8 @@ uint64_t cpu_ldq_code_mmu(CPUArchState *env, abi_ptr addr, /* * Do not allow unaligned operations to proceed. Return the host address. */ -static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr, - MemOpIdx oi, int size, uintptr_t retaddr) +static void *atomic_mmu_lookup(CPUArchState *env, vaddr addr, MemOpIdx oi, + int size, uintptr_t retaddr) { MemOp mop = get_memop(oi); int a_bits = get_alignment_bits(mop); From b1c09220b4cef17632495bfbb9a1355ce3eb301c Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Wed, 21 Jun 2023 15:56:31 +0200 Subject: [PATCH 0193/1353] accel/tcg: Replace target_ulong with vaddr in translator_*() Use vaddr for guest virtual address in translator_use_goto_tb() and translator_loop(). Signed-off-by: Anton Johansson Reviewed-by: Richard Henderson Message-Id: <20230621135633.1649-11-anjo@rev.ng> Signed-off-by: Richard Henderson --- accel/tcg/translator.c | 10 +++++----- include/exec/translator.h | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index 918a455e73..0fd9efceba 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -117,7 +117,7 @@ static void gen_tb_end(const TranslationBlock *tb, uint32_t cflags, } } -bool translator_use_goto_tb(DisasContextBase *db, target_ulong dest) +bool translator_use_goto_tb(DisasContextBase *db, vaddr dest) { /* Suppress goto_tb if requested. */ if (tb_cflags(db->tb) & CF_NO_GOTO_TB) { @@ -129,8 +129,8 @@ bool translator_use_goto_tb(DisasContextBase *db, target_ulong dest) } void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns, - target_ulong pc, void *host_pc, - const TranslatorOps *ops, DisasContextBase *db) + vaddr pc, void *host_pc, const TranslatorOps *ops, + DisasContextBase *db) { uint32_t cflags = tb_cflags(tb); TCGOp *icount_start_insn; @@ -235,10 +235,10 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns, } static void *translator_access(CPUArchState *env, DisasContextBase *db, - target_ulong pc, size_t len) + vaddr pc, size_t len) { void *host; - target_ulong base, end; + vaddr base, end; TranslationBlock *tb; tb = db->tb; diff --git a/include/exec/translator.h b/include/exec/translator.h index 224ae14aa7..a53d3243d4 100644 --- a/include/exec/translator.h +++ b/include/exec/translator.h @@ -142,8 +142,8 @@ typedef struct TranslatorOps { * - When too many instructions have been translated. */ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns, - target_ulong pc, void *host_pc, - const TranslatorOps *ops, DisasContextBase *db); + vaddr pc, void *host_pc, const TranslatorOps *ops, + DisasContextBase *db); /** * translator_use_goto_tb @@ -153,7 +153,7 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns, * Return true if goto_tb is allowed between the current TB * and the destination PC. */ -bool translator_use_goto_tb(DisasContextBase *db, target_ulong dest); +bool translator_use_goto_tb(DisasContextBase *db, vaddr dest); /** * translator_io_start From c814c892e5e7f55eb5184e4aaf3bfa918070fbb1 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Wed, 21 Jun 2023 15:56:33 +0200 Subject: [PATCH 0194/1353] cpu: Replace target_ulong with hwaddr in tb_invalidate_phys_addr() Signed-off-by: Anton Johansson Reviewed-by: Richard Henderson Message-Id: <20230621135633.1649-13-anjo@rev.ng> Signed-off-by: Richard Henderson --- cpu.c | 2 +- include/exec/exec-all.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cpu.c b/cpu.c index 65ebaf8159..1c948d1161 100644 --- a/cpu.c +++ b/cpu.c @@ -293,7 +293,7 @@ void list_cpus(void) } #if defined(CONFIG_USER_ONLY) -void tb_invalidate_phys_addr(target_ulong addr) +void tb_invalidate_phys_addr(hwaddr addr) { mmap_lock(); tb_invalidate_phys_page(addr); diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index cc1c3556f6..200c27eadf 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -526,7 +526,7 @@ uint32_t curr_cflags(CPUState *cpu); /* TranslationBlock invalidate API */ #if defined(CONFIG_USER_ONLY) -void tb_invalidate_phys_addr(target_ulong addr); +void tb_invalidate_phys_addr(hwaddr addr); #else void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr, MemTxAttrs attrs); #endif From 1d3daf95254d998b91445c48de875796df3b0998 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 23 May 2023 14:11:07 +0100 Subject: [PATCH 0195/1353] softfloat: use QEMU_FLATTEN to avoid mistaken isra inlining MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Balton discovered that asserts for the extract/deposit calls had a significant impact on a lame benchmark on qemu-ppc. Replicating with: ./qemu-ppc64 ~/lsrc/tests/lame.git-svn/builds/ppc64/frontend/lame \ -h pts-trondheim-3.wav pts-trondheim-3.mp3 showed up the pack/unpack routines not eliding the assert checks as it should have done causing them to prominently figure in the profile:  11.44%  qemu-ppc64  qemu-ppc64               [.] unpack_raw64.isra.0  11.03%  qemu-ppc64  qemu-ppc64               [.] parts64_uncanon_normal   8.26%  qemu-ppc64  qemu-ppc64               [.] helper_compute_fprf_float64   6.75%  qemu-ppc64  qemu-ppc64               [.] do_float_check_status   5.34%  qemu-ppc64  qemu-ppc64               [.] parts64_muladd   4.75%  qemu-ppc64  qemu-ppc64               [.] pack_raw64.isra.0   4.38%  qemu-ppc64  qemu-ppc64               [.] parts64_canonicalize   3.62%  qemu-ppc64  qemu-ppc64               [.] float64r32_round_pack_canonical After this patch the same test runs 31 seconds faster with a profile where the generated code dominates more: + 14.12% 0.00% qemu-ppc64 [unknown] [.] 0x0000004000619420 + 13.30% 0.00% qemu-ppc64 [unknown] [.] 0x0000004000616850 + 12.58% 12.19% qemu-ppc64 qemu-ppc64 [.] parts64_uncanon_normal + 10.62% 0.00% qemu-ppc64 [unknown] [.] 0x000000400061bf70 + 9.91% 9.73% qemu-ppc64 qemu-ppc64 [.] helper_compute_fprf_float64 + 7.84% 7.82% qemu-ppc64 qemu-ppc64 [.] do_float_check_status + 6.47% 5.78% qemu-ppc64 qemu-ppc64 [.] parts64_canonicalize.constprop.0 + 6.46% 0.00% qemu-ppc64 [unknown] [.] 0x0000004000620130 + 6.42% 0.00% qemu-ppc64 [unknown] [.] 0x0000004000619400 + 6.17% 6.04% qemu-ppc64 qemu-ppc64 [.] parts64_muladd + 5.85% 0.00% qemu-ppc64 [unknown] [.] 0x00000040006167e0 + 5.74% 0.00% qemu-ppc64 [unknown] [.] 0x0000b693fcffffd3 + 5.45% 4.78% qemu-ppc64 qemu-ppc64 [.] float64r32_round_pack_canonical Suggested-by: Richard Henderson Message-Id: [AJB: Patchified rth's suggestion] Signed-off-by: Alex Bennée Cc: BALATON Zoltan Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Tested-by: BALATON Zoltan Message-Id: <20230523131107.3680641-1-alex.bennee@linaro.org> Signed-off-by: Richard Henderson --- fpu/softfloat.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 108f9cb224..42e6c188b4 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -593,27 +593,27 @@ static void unpack_raw64(FloatParts64 *r, const FloatFmt *fmt, uint64_t raw) }; } -static inline void float16_unpack_raw(FloatParts64 *p, float16 f) +static void QEMU_FLATTEN float16_unpack_raw(FloatParts64 *p, float16 f) { unpack_raw64(p, &float16_params, f); } -static inline void bfloat16_unpack_raw(FloatParts64 *p, bfloat16 f) +static void QEMU_FLATTEN bfloat16_unpack_raw(FloatParts64 *p, bfloat16 f) { unpack_raw64(p, &bfloat16_params, f); } -static inline void float32_unpack_raw(FloatParts64 *p, float32 f) +static void QEMU_FLATTEN float32_unpack_raw(FloatParts64 *p, float32 f) { unpack_raw64(p, &float32_params, f); } -static inline void float64_unpack_raw(FloatParts64 *p, float64 f) +static void QEMU_FLATTEN float64_unpack_raw(FloatParts64 *p, float64 f) { unpack_raw64(p, &float64_params, f); } -static void floatx80_unpack_raw(FloatParts128 *p, floatx80 f) +static void QEMU_FLATTEN floatx80_unpack_raw(FloatParts128 *p, floatx80 f) { *p = (FloatParts128) { .cls = float_class_unclassified, @@ -623,7 +623,7 @@ static void floatx80_unpack_raw(FloatParts128 *p, floatx80 f) }; } -static void float128_unpack_raw(FloatParts128 *p, float128 f) +static void QEMU_FLATTEN float128_unpack_raw(FloatParts128 *p, float128 f) { const int f_size = float128_params.frac_size - 64; const int e_size = float128_params.exp_size; @@ -650,27 +650,27 @@ static uint64_t pack_raw64(const FloatParts64 *p, const FloatFmt *fmt) return ret; } -static inline float16 float16_pack_raw(const FloatParts64 *p) +static float16 QEMU_FLATTEN float16_pack_raw(const FloatParts64 *p) { return make_float16(pack_raw64(p, &float16_params)); } -static inline bfloat16 bfloat16_pack_raw(const FloatParts64 *p) +static bfloat16 QEMU_FLATTEN bfloat16_pack_raw(const FloatParts64 *p) { return pack_raw64(p, &bfloat16_params); } -static inline float32 float32_pack_raw(const FloatParts64 *p) +static float32 QEMU_FLATTEN float32_pack_raw(const FloatParts64 *p) { return make_float32(pack_raw64(p, &float32_params)); } -static inline float64 float64_pack_raw(const FloatParts64 *p) +static float64 QEMU_FLATTEN float64_pack_raw(const FloatParts64 *p) { return make_float64(pack_raw64(p, &float64_params)); } -static float128 float128_pack_raw(const FloatParts128 *p) +static float128 QEMU_FLATTEN float128_pack_raw(const FloatParts128 *p) { const int f_size = float128_params.frac_size - 64; const int e_size = float128_params.exp_size; From ea185a557bc97868f3729060ea1cd003dbd971d1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 10 Jun 2023 10:19:59 -0700 Subject: [PATCH 0196/1353] tests/plugin: Remove duplicate insn log from libinsn.so This is a perfectly natural occurrence for x86 "rep movb", where the "rep" prefix forms a counted loop of the one insn. During the tests/tcg/multiarch/memory test, this logging is triggered over 350000 times. Within the context of cross-i386-tci build, which is already slow by nature, the logging is sufficient to push the test into timeout. Signed-off-by: Richard Henderson --- tests/plugin/insn.c | 9 +-------- tests/tcg/i386/Makefile.softmmu-target | 9 --------- tests/tcg/i386/Makefile.target | 6 ------ tests/tcg/x86_64/Makefile.softmmu-target | 9 --------- 4 files changed, 1 insertion(+), 32 deletions(-) diff --git a/tests/plugin/insn.c b/tests/plugin/insn.c index cd5ea5d4ae..9bd6e44f73 100644 --- a/tests/plugin/insn.c +++ b/tests/plugin/insn.c @@ -19,7 +19,6 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; #define MAX_CPUS 8 /* lets not go nuts */ typedef struct { - uint64_t last_pc; uint64_t insn_count; } InstructionCount; @@ -51,13 +50,7 @@ static void vcpu_insn_exec_before(unsigned int cpu_index, void *udata) { unsigned int i = cpu_index % MAX_CPUS; InstructionCount *c = &counts[i]; - uint64_t this_pc = GPOINTER_TO_UINT(udata); - if (this_pc == c->last_pc) { - g_autofree gchar *out = g_strdup_printf("detected repeat execution @ 0x%" - PRIx64 "\n", this_pc); - qemu_plugin_outs(out); - } - c->last_pc = this_pc; + c->insn_count++; } diff --git a/tests/tcg/i386/Makefile.softmmu-target b/tests/tcg/i386/Makefile.softmmu-target index ed922d59c8..5266f2335a 100644 --- a/tests/tcg/i386/Makefile.softmmu-target +++ b/tests/tcg/i386/Makefile.softmmu-target @@ -33,14 +33,5 @@ EXTRA_RUNS+=$(MULTIARCH_RUNS) memory: CFLAGS+=-DCHECK_UNALIGNED=1 -# non-inline runs will trigger the duplicate instruction heuristics in libinsn.so -run-plugin-%-with-libinsn.so: - $(call run-test, $@, \ - $(QEMU) -monitor none -display none \ - -chardev file$(COMMA)path=$@.out$(COMMA)id=output \ - -plugin ../../plugin/libinsn.so$(COMMA)inline=on \ - -d plugin -D $*-with-libinsn.so.pout \ - $(QEMU_OPTS) $*) - # Running QEMU_OPTS+=-device isa-debugcon,chardev=output -device isa-debug-exit,iobase=0xf4,iosize=0x4 -kernel diff --git a/tests/tcg/i386/Makefile.target b/tests/tcg/i386/Makefile.target index 821822ed0c..f2ee7a4db7 100644 --- a/tests/tcg/i386/Makefile.target +++ b/tests/tcg/i386/Makefile.target @@ -63,12 +63,6 @@ else SKIP_I386_TESTS+=test-i386-fprem endif -# non-inline runs will trigger the duplicate instruction heuristics in libinsn.so -run-plugin-%-with-libinsn.so: - $(call run-test, $@, $(QEMU) $(QEMU_OPTS) \ - -plugin ../../plugin/libinsn.so$(COMMA)inline=on \ - -d plugin -D $*-with-libinsn.so.pout $*) - # Update TESTS I386_TESTS:=$(filter-out $(SKIP_I386_TESTS), $(ALL_X86_TESTS)) TESTS=$(MULTIARCH_TESTS) $(I386_TESTS) diff --git a/tests/tcg/x86_64/Makefile.softmmu-target b/tests/tcg/x86_64/Makefile.softmmu-target index 7207fee94c..1bd763f2e6 100644 --- a/tests/tcg/x86_64/Makefile.softmmu-target +++ b/tests/tcg/x86_64/Makefile.softmmu-target @@ -33,14 +33,5 @@ EXTRA_RUNS+=$(MULTIARCH_RUNS) memory: CFLAGS+=-DCHECK_UNALIGNED=1 -# non-inline runs will trigger the duplicate instruction heuristics in libinsn.so -run-plugin-%-with-libinsn.so: - $(call run-test, $@, \ - $(QEMU) -monitor none -display none \ - -chardev file$(COMMA)path=$@.out$(COMMA)id=output \ - -plugin ../../plugin/libinsn.so$(COMMA)inline=on \ - -d plugin -D $*-with-libinsn.so.pout \ - $(QEMU_OPTS) $*) - # Running QEMU_OPTS+=-device isa-debugcon,chardev=output -device isa-debug-exit,iobase=0xf4,iosize=0x4 -kernel From 1b65b4f54c7f7d07b5d35fac5f7de3e75f5f21a0 Mon Sep 17 00:00:00 2001 From: Fei Wu Date: Wed, 7 Jun 2023 20:24:02 +0800 Subject: [PATCH 0197/1353] accel/tcg: remove CONFIG_PROFILER MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TBStats will be introduced to replace CONFIG_PROFILER totally, here remove all CONFIG_PROFILER related stuffs first. Signed-off-by: Vanderson M. do Rosario Signed-off-by: Alex Bennée Signed-off-by: Fei Wu Reviewed-by: Richard Henderson Message-Id: <20230607122411.3394702-2-fei2.wu@intel.com> Signed-off-by: Richard Henderson --- accel/tcg/monitor.c | 31 ----- accel/tcg/tcg-accel-ops.c | 10 -- accel/tcg/translate-all.c | 33 ------ hmp-commands-info.hx | 15 --- include/qemu/timer.h | 9 -- include/tcg/tcg.h | 26 ----- meson.build | 2 - meson_options.txt | 2 - qapi/machine.json | 18 --- scripts/meson-buildoptions.sh | 3 - softmmu/runstate.c | 9 -- tcg/tcg.c | 214 ---------------------------------- tests/qtest/qmp-cmd-test.c | 3 - 13 files changed, 375 deletions(-) diff --git a/accel/tcg/monitor.c b/accel/tcg/monitor.c index f171bc6f5e..d48de23999 100644 --- a/accel/tcg/monitor.c +++ b/accel/tcg/monitor.c @@ -81,37 +81,6 @@ HumanReadableText *qmp_x_query_opcount(Error **errp) return human_readable_text_from_str(buf); } -#ifdef CONFIG_PROFILER - -int64_t dev_time; - -HumanReadableText *qmp_x_query_profile(Error **errp) -{ - g_autoptr(GString) buf = g_string_new(""); - static int64_t last_cpu_exec_time; - int64_t cpu_exec_time; - int64_t delta; - - cpu_exec_time = tcg_cpu_exec_time(); - delta = cpu_exec_time - last_cpu_exec_time; - - g_string_append_printf(buf, "async time %" PRId64 " (%0.3f)\n", - dev_time, dev_time / (double)NANOSECONDS_PER_SECOND); - g_string_append_printf(buf, "qemu time %" PRId64 " (%0.3f)\n", - delta, delta / (double)NANOSECONDS_PER_SECOND); - last_cpu_exec_time = cpu_exec_time; - dev_time = 0; - - return human_readable_text_from_str(buf); -} -#else -HumanReadableText *qmp_x_query_profile(Error **errp) -{ - error_setg(errp, "Internal profiler not compiled"); - return NULL; -} -#endif - static void hmp_tcg_register(void) { monitor_register_hmp_info_hrt("jit", qmp_x_query_jit); diff --git a/accel/tcg/tcg-accel-ops.c b/accel/tcg/tcg-accel-ops.c index 58c8e64096..3973591508 100644 --- a/accel/tcg/tcg-accel-ops.c +++ b/accel/tcg/tcg-accel-ops.c @@ -70,20 +70,10 @@ void tcg_cpus_destroy(CPUState *cpu) int tcg_cpus_exec(CPUState *cpu) { int ret; -#ifdef CONFIG_PROFILER - int64_t ti; -#endif assert(tcg_enabled()); -#ifdef CONFIG_PROFILER - ti = profile_getclock(); -#endif cpu_exec_start(cpu); ret = cpu_exec(cpu); cpu_exec_end(cpu); -#ifdef CONFIG_PROFILER - qatomic_set(&tcg_ctx->prof.cpu_exec_time, - tcg_ctx->prof.cpu_exec_time + profile_getclock() - ti); -#endif return ret; } diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 03c49baf1c..d3d4fbc1a4 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -202,10 +202,6 @@ void cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb, uintptr_t host_pc) { uint64_t data[TARGET_INSN_START_WORDS]; -#ifdef CONFIG_PROFILER - TCGProfile *prof = &tcg_ctx->prof; - int64_t ti = profile_getclock(); -#endif int insns_left = cpu_unwind_data_from_tb(tb, host_pc, data); if (insns_left < 0) { @@ -222,12 +218,6 @@ void cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb, } cpu->cc->tcg_ops->restore_state_to_opc(cpu, tb, data); - -#ifdef CONFIG_PROFILER - qatomic_set(&prof->restore_time, - prof->restore_time + profile_getclock() - ti); - qatomic_set(&prof->restore_count, prof->restore_count + 1); -#endif } bool cpu_restore_state(CPUState *cpu, uintptr_t host_pc) @@ -290,13 +280,6 @@ static int setjmp_gen_code(CPUArchState *env, TranslationBlock *tb, tcg_ctx->cpu = NULL; *max_insns = tb->icount; -#ifdef CONFIG_PROFILER - qatomic_set(&tcg_ctx->prof.tb_count, tcg_ctx->prof.tb_count + 1); - qatomic_set(&tcg_ctx->prof.interm_time, - tcg_ctx->prof.interm_time + profile_getclock() - *ti); - *ti = profile_getclock(); -#endif - return tcg_gen_code(tcg_ctx, tb, pc); } @@ -310,9 +293,6 @@ TranslationBlock *tb_gen_code(CPUState *cpu, tb_page_addr_t phys_pc; tcg_insn_unit *gen_code_buf; int gen_code_size, search_size, max_insns; -#ifdef CONFIG_PROFILER - TCGProfile *prof = &tcg_ctx->prof; -#endif int64_t ti; void *host_pc; @@ -371,12 +351,6 @@ TranslationBlock *tb_gen_code(CPUState *cpu, tb_overflow: -#ifdef CONFIG_PROFILER - /* includes aborted translations because of exceptions */ - qatomic_set(&prof->tb_count1, prof->tb_count1 + 1); - ti = profile_getclock(); -#endif - trace_translate_block(tb, pc, tb->tc.ptr); gen_code_size = setjmp_gen_code(env, tb, pc, host_pc, &max_insns, &ti); @@ -431,13 +405,6 @@ TranslationBlock *tb_gen_code(CPUState *cpu, */ perf_report_code(pc, tb, tcg_splitwx_to_rx(gen_code_buf)); -#ifdef CONFIG_PROFILER - qatomic_set(&prof->code_time, prof->code_time + profile_getclock() - ti); - qatomic_set(&prof->code_in_len, prof->code_in_len + tb->size); - qatomic_set(&prof->code_out_len, prof->code_out_len + gen_code_size); - qatomic_set(&prof->search_out_len, prof->search_out_len + search_size); -#endif - if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM) && qemu_log_in_addr_range(pc)) { FILE *logfile = qemu_log_trylock(); diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx index 47d63d26db..f5b37eb74a 100644 --- a/hmp-commands-info.hx +++ b/hmp-commands-info.hx @@ -360,21 +360,6 @@ SRST Show host USB devices. ERST -#if defined(CONFIG_TCG) - { - .name = "profile", - .args_type = "", - .params = "", - .help = "show profiling information", - .cmd_info_hrt = qmp_x_query_profile, - }, -#endif - -SRST - ``info profile`` - Show profiling information. -ERST - { .name = "capture", .args_type = "", diff --git a/include/qemu/timer.h b/include/qemu/timer.h index ee071e07d1..9a91cb1248 100644 --- a/include/qemu/timer.h +++ b/include/qemu/timer.h @@ -989,13 +989,4 @@ static inline int64_t cpu_get_host_ticks(void) } #endif -#ifdef CONFIG_PROFILER -static inline int64_t profile_getclock(void) -{ - return get_clock(); -} - -extern int64_t dev_time; -#endif - #endif diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index a498f31967..95541e9474 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -478,27 +478,6 @@ static inline TCGRegSet output_pref(const TCGOp *op, unsigned i) return i < ARRAY_SIZE(op->output_pref) ? op->output_pref[i] : 0; } -typedef struct TCGProfile { - int64_t cpu_exec_time; - int64_t tb_count1; - int64_t tb_count; - int64_t op_count; /* total insn count */ - int op_count_max; /* max insn per TB */ - int temp_count_max; - int64_t temp_count; - int64_t del_op_count; - int64_t code_in_len; - int64_t code_out_len; - int64_t search_out_len; - int64_t interm_time; - int64_t code_time; - int64_t la_time; - int64_t opt_time; - int64_t restore_count; - int64_t restore_time; - int64_t table_op_count[NB_OPS]; -} TCGProfile; - struct TCGContext { uint8_t *pool_cur, *pool_end; TCGPool *pool_first, *pool_current, *pool_first_large; @@ -528,10 +507,6 @@ struct TCGContext { tcg_insn_unit *code_buf; /* pointer for start of tb */ tcg_insn_unit *code_ptr; /* pointer for running end of tb */ -#ifdef CONFIG_PROFILER - TCGProfile prof; -#endif - #ifdef CONFIG_DEBUG_TCG int goto_tb_issue_mask; const TCGOpcode *vecop_list; @@ -871,7 +846,6 @@ static inline TCGv_ptr tcg_temp_new_ptr(void) return temp_tcgv_ptr(t); } -int64_t tcg_cpu_exec_time(void); void tcg_dump_info(GString *buf); void tcg_dump_op_count(GString *buf); diff --git a/meson.build b/meson.build index 3e3d38badb..b409788832 100644 --- a/meson.build +++ b/meson.build @@ -2121,7 +2121,6 @@ if numa.found() dependencies: numa)) endif config_host_data.set('CONFIG_OPENGL', opengl.found()) -config_host_data.set('CONFIG_PROFILER', get_option('profiler')) config_host_data.set('CONFIG_RBD', rbd.found()) config_host_data.set('CONFIG_RDMA', rdma.found()) config_host_data.set('CONFIG_SAFESTACK', get_option('safe_stack')) @@ -4087,7 +4086,6 @@ if 'objc' in all_languages summary_info += {'QEMU_OBJCFLAGS': ' '.join(qemu_common_flags)} endif summary_info += {'QEMU_LDFLAGS': ' '.join(qemu_ldflags)} -summary_info += {'profiler': get_option('profiler')} summary_info += {'link-time optimization (LTO)': get_option('b_lto')} summary_info += {'PIE': get_option('b_pie')} summary_info += {'static build': get_option('prefer_static')} diff --git a/meson_options.txt b/meson_options.txt index 90237389e2..bbb5c7e886 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -345,8 +345,6 @@ option('qom_cast_debug', type: 'boolean', value: true, option('gprof', type: 'boolean', value: false, description: 'QEMU profiling with gprof', deprecated: true) -option('profiler', type: 'boolean', value: false, - description: 'profiler support') option('slirp_smbd', type : 'feature', value : 'auto', description: 'use smbd (at path --smbd=*) in slirp networking') diff --git a/qapi/machine.json b/qapi/machine.json index 37660d8f2a..a08b6576ca 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -1575,24 +1575,6 @@ 'if': 'CONFIG_TCG', 'features': [ 'unstable' ] } -## -# @x-query-profile: -# -# Query TCG profiling information -# -# Features: -# -# @unstable: This command is meant for debugging. -# -# Returns: profile information -# -# Since: 6.2 -## -{ 'command': 'x-query-profile', - 'returns': 'HumanReadableText', - 'if': 'CONFIG_TCG', - 'features': [ 'unstable' ] } - ## # @x-query-ramblock: # diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index 5714fd93d9..7dd5709ef4 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -39,7 +39,6 @@ meson_options_help() { printf "%s\n" ' jemalloc/system/tcmalloc)' printf "%s\n" ' --enable-module-upgrades try to load modules from alternate paths for' printf "%s\n" ' upgrades' - printf "%s\n" ' --enable-profiler profiler support' printf "%s\n" ' --enable-rng-none dummy RNG, avoid using /dev/(u)random and' printf "%s\n" ' getrandom()' printf "%s\n" ' --enable-safe-stack SafeStack Stack Smash Protection (requires' @@ -401,8 +400,6 @@ _meson_option_parse() { --with-pkgversion=*) quote_sh "-Dpkgversion=$2" ;; --enable-png) printf "%s" -Dpng=enabled ;; --disable-png) printf "%s" -Dpng=disabled ;; - --enable-profiler) printf "%s" -Dprofiler=true ;; - --disable-profiler) printf "%s" -Dprofiler=false ;; --enable-pvrdma) printf "%s" -Dpvrdma=enabled ;; --disable-pvrdma) printf "%s" -Dpvrdma=disabled ;; --enable-qcow1) printf "%s" -Dqcow1=enabled ;; diff --git a/softmmu/runstate.c b/softmmu/runstate.c index 1957caf73f..a9fbcf4862 100644 --- a/softmmu/runstate.c +++ b/softmmu/runstate.c @@ -727,18 +727,9 @@ static bool main_loop_should_exit(int *status) int qemu_main_loop(void) { int status = EXIT_SUCCESS; -#ifdef CONFIG_PROFILER - int64_t ti; -#endif while (!main_loop_should_exit(&status)) { -#ifdef CONFIG_PROFILER - ti = profile_getclock(); -#endif main_loop_wait(false); -#ifdef CONFIG_PROFILER - dev_time += profile_getclock() - ti; -#endif } return status; diff --git a/tcg/tcg.c b/tcg/tcg.c index 3fcd0d9f32..a0628fe424 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -3033,10 +3033,6 @@ void tcg_op_remove(TCGContext *s, TCGOp *op) QTAILQ_REMOVE(&s->ops, op, link); QTAILQ_INSERT_TAIL(&s->free_ops, op, link); s->nb_ops--; - -#ifdef CONFIG_PROFILER - qatomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1); -#endif } void tcg_remove_ops_after(TCGOp *op) @@ -5906,143 +5902,16 @@ static void tcg_out_st_helper_args(TCGContext *s, const TCGLabelQemuLdst *ldst, tcg_out_helper_load_common_args(s, ldst, parm, info, next_arg); } -#ifdef CONFIG_PROFILER - -/* avoid copy/paste errors */ -#define PROF_ADD(to, from, field) \ - do { \ - (to)->field += qatomic_read(&((from)->field)); \ - } while (0) - -#define PROF_MAX(to, from, field) \ - do { \ - typeof((from)->field) val__ = qatomic_read(&((from)->field)); \ - if (val__ > (to)->field) { \ - (to)->field = val__; \ - } \ - } while (0) - -/* Pass in a zero'ed @prof */ -static inline -void tcg_profile_snapshot(TCGProfile *prof, bool counters, bool table) -{ - unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs); - unsigned int i; - - for (i = 0; i < n_ctxs; i++) { - TCGContext *s = qatomic_read(&tcg_ctxs[i]); - const TCGProfile *orig = &s->prof; - - if (counters) { - PROF_ADD(prof, orig, cpu_exec_time); - PROF_ADD(prof, orig, tb_count1); - PROF_ADD(prof, orig, tb_count); - PROF_ADD(prof, orig, op_count); - PROF_MAX(prof, orig, op_count_max); - PROF_ADD(prof, orig, temp_count); - PROF_MAX(prof, orig, temp_count_max); - PROF_ADD(prof, orig, del_op_count); - PROF_ADD(prof, orig, code_in_len); - PROF_ADD(prof, orig, code_out_len); - PROF_ADD(prof, orig, search_out_len); - PROF_ADD(prof, orig, interm_time); - PROF_ADD(prof, orig, code_time); - PROF_ADD(prof, orig, la_time); - PROF_ADD(prof, orig, opt_time); - PROF_ADD(prof, orig, restore_count); - PROF_ADD(prof, orig, restore_time); - } - if (table) { - int i; - - for (i = 0; i < NB_OPS; i++) { - PROF_ADD(prof, orig, table_op_count[i]); - } - } - } -} - -#undef PROF_ADD -#undef PROF_MAX - -static void tcg_profile_snapshot_counters(TCGProfile *prof) -{ - tcg_profile_snapshot(prof, true, false); -} - -static void tcg_profile_snapshot_table(TCGProfile *prof) -{ - tcg_profile_snapshot(prof, false, true); -} - -void tcg_dump_op_count(GString *buf) -{ - TCGProfile prof = {}; - int i; - - tcg_profile_snapshot_table(&prof); - for (i = 0; i < NB_OPS; i++) { - g_string_append_printf(buf, "%s %" PRId64 "\n", tcg_op_defs[i].name, - prof.table_op_count[i]); - } -} - -int64_t tcg_cpu_exec_time(void) -{ - unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs); - unsigned int i; - int64_t ret = 0; - - for (i = 0; i < n_ctxs; i++) { - const TCGContext *s = qatomic_read(&tcg_ctxs[i]); - const TCGProfile *prof = &s->prof; - - ret += qatomic_read(&prof->cpu_exec_time); - } - return ret; -} -#else void tcg_dump_op_count(GString *buf) { g_string_append_printf(buf, "[TCG profiler not compiled]\n"); } -int64_t tcg_cpu_exec_time(void) -{ - error_report("%s: TCG profiler not compiled", __func__); - exit(EXIT_FAILURE); -} -#endif - - int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start) { -#ifdef CONFIG_PROFILER - TCGProfile *prof = &s->prof; -#endif int i, start_words, num_insns; TCGOp *op; -#ifdef CONFIG_PROFILER - { - int n = 0; - - QTAILQ_FOREACH(op, &s->ops, link) { - n++; - } - qatomic_set(&prof->op_count, prof->op_count + n); - if (n > prof->op_count_max) { - qatomic_set(&prof->op_count_max, n); - } - - n = s->nb_temps; - qatomic_set(&prof->temp_count, prof->temp_count + n); - if (n > prof->temp_count_max) { - qatomic_set(&prof->temp_count_max, n); - } - } -#endif - if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP) && qemu_log_in_addr_range(pc_start))) { FILE *logfile = qemu_log_trylock(); @@ -6071,17 +5940,8 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start) } #endif -#ifdef CONFIG_PROFILER - qatomic_set(&prof->opt_time, prof->opt_time - profile_getclock()); -#endif - tcg_optimize(s); -#ifdef CONFIG_PROFILER - qatomic_set(&prof->opt_time, prof->opt_time + profile_getclock()); - qatomic_set(&prof->la_time, prof->la_time - profile_getclock()); -#endif - reachable_code_pass(s); liveness_pass_0(s); liveness_pass_1(s); @@ -6105,10 +5965,6 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start) } } -#ifdef CONFIG_PROFILER - qatomic_set(&prof->la_time, prof->la_time + profile_getclock()); -#endif - if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT) && qemu_log_in_addr_range(pc_start))) { FILE *logfile = qemu_log_trylock(); @@ -6151,10 +6007,6 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start) QTAILQ_FOREACH(op, &s->ops, link) { TCGOpcode opc = op->opc; -#ifdef CONFIG_PROFILER - qatomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1); -#endif - switch (opc) { case INDEX_op_mov_i32: case INDEX_op_mov_i64: @@ -6249,76 +6101,10 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start) return tcg_current_code_size(s); } -#ifdef CONFIG_PROFILER -void tcg_dump_info(GString *buf) -{ - TCGProfile prof = {}; - const TCGProfile *s; - int64_t tb_count; - int64_t tb_div_count; - int64_t tot; - - tcg_profile_snapshot_counters(&prof); - s = &prof; - tb_count = s->tb_count; - tb_div_count = tb_count ? tb_count : 1; - tot = s->interm_time + s->code_time; - - g_string_append_printf(buf, "JIT cycles %" PRId64 - " (%0.3f s at 2.4 GHz)\n", - tot, tot / 2.4e9); - g_string_append_printf(buf, "translated TBs %" PRId64 - " (aborted=%" PRId64 " %0.1f%%)\n", - tb_count, s->tb_count1 - tb_count, - (double)(s->tb_count1 - s->tb_count) - / (s->tb_count1 ? s->tb_count1 : 1) * 100.0); - g_string_append_printf(buf, "avg ops/TB %0.1f max=%d\n", - (double)s->op_count / tb_div_count, s->op_count_max); - g_string_append_printf(buf, "deleted ops/TB %0.2f\n", - (double)s->del_op_count / tb_div_count); - g_string_append_printf(buf, "avg temps/TB %0.2f max=%d\n", - (double)s->temp_count / tb_div_count, - s->temp_count_max); - g_string_append_printf(buf, "avg host code/TB %0.1f\n", - (double)s->code_out_len / tb_div_count); - g_string_append_printf(buf, "avg search data/TB %0.1f\n", - (double)s->search_out_len / tb_div_count); - - g_string_append_printf(buf, "cycles/op %0.1f\n", - s->op_count ? (double)tot / s->op_count : 0); - g_string_append_printf(buf, "cycles/in byte %0.1f\n", - s->code_in_len ? (double)tot / s->code_in_len : 0); - g_string_append_printf(buf, "cycles/out byte %0.1f\n", - s->code_out_len ? (double)tot / s->code_out_len : 0); - g_string_append_printf(buf, "cycles/search byte %0.1f\n", - s->search_out_len ? - (double)tot / s->search_out_len : 0); - if (tot == 0) { - tot = 1; - } - g_string_append_printf(buf, " gen_interm time %0.1f%%\n", - (double)s->interm_time / tot * 100.0); - g_string_append_printf(buf, " gen_code time %0.1f%%\n", - (double)s->code_time / tot * 100.0); - g_string_append_printf(buf, "optim./code time %0.1f%%\n", - (double)s->opt_time / (s->code_time ? - s->code_time : 1) - * 100.0); - g_string_append_printf(buf, "liveness/code time %0.1f%%\n", - (double)s->la_time / (s->code_time ? - s->code_time : 1) * 100.0); - g_string_append_printf(buf, "cpu_restore count %" PRId64 "\n", - s->restore_count); - g_string_append_printf(buf, " avg cycles %0.1f\n", - s->restore_count ? - (double)s->restore_time / s->restore_count : 0); -} -#else void tcg_dump_info(GString *buf) { g_string_append_printf(buf, "[TCG profiler not compiled]\n"); } -#endif #ifdef ELF_HOST_MACHINE /* In order to use this feature, the backend needs to do three things: diff --git a/tests/qtest/qmp-cmd-test.c b/tests/qtest/qmp-cmd-test.c index a58de48d2a..73a670e8fa 100644 --- a/tests/qtest/qmp-cmd-test.c +++ b/tests/qtest/qmp-cmd-test.c @@ -46,9 +46,6 @@ static int query_error_class(const char *cmd) { "query-balloon", ERROR_CLASS_DEVICE_NOT_ACTIVE }, { "query-hotpluggable-cpus", ERROR_CLASS_GENERIC_ERROR }, { "query-vm-generation-id", ERROR_CLASS_GENERIC_ERROR }, -#ifndef CONFIG_PROFILER - { "x-query-profile", ERROR_CLASS_GENERIC_ERROR }, -#endif /* Only valid with a USB bus added */ { "x-query-usb", ERROR_CLASS_GENERIC_ERROR }, /* Only valid with accel=tcg */ From 70bfde9a7de7fa3495d9e2bd7142cb1bc656484e Mon Sep 17 00:00:00 2001 From: Max Chou Date: Fri, 23 Jun 2023 00:16:24 +0800 Subject: [PATCH 0198/1353] tcg: Fix temporary variable in tcg_gen_gvec_andcs The 5th parameter of tcg_gen_gvec_2s should be replaced by the temporary tmp variable in the tcg_gen_gvec_andcs function. Reviewed-by: Daniel Henrique Barboza Signed-off-by: Max Chou Message-Id: <20230622161646.32005-9-max.chou@sifive.com> Signed-off-by: Richard Henderson --- tcg/tcg-op-gvec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcg/tcg-op-gvec.c b/tcg/tcg-op-gvec.c index 95a588d6d2..a062239804 100644 --- a/tcg/tcg-op-gvec.c +++ b/tcg/tcg-op-gvec.c @@ -2774,7 +2774,7 @@ void tcg_gen_gvec_andcs(unsigned vece, uint32_t dofs, uint32_t aofs, TCGv_i64 tmp = tcg_temp_ebb_new_i64(); tcg_gen_dup_i64(vece, tmp, c); - tcg_gen_gvec_2s(dofs, aofs, oprsz, maxsz, c, &g); + tcg_gen_gvec_2s(dofs, aofs, oprsz, maxsz, tmp, &g); tcg_temp_free_i64(tmp); } From f6ff4923b92ceefbe5650c3e90ccdcc57dc60fb7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Jun 2023 11:08:41 +0200 Subject: [PATCH 0199/1353] target/microblaze: Define TCG_GUEST_DEFAULT_MO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The microblaze architecture does not reorder instructions. While there is an MBAR wait-for-data-access instruction, this concerns synchronizing with DMA. This should have been defined when enabling MTTCG. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Edgar E. Iglesias Fixes: d449561b130 ("configure: microblaze: Enable mttcg") Signed-off-by: Richard Henderson --- target/microblaze/cpu.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index 3525de144c..a7b040abd4 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -24,6 +24,9 @@ #include "exec/cpu-defs.h" #include "qemu/cpu-float.h" +/* MicroBlaze is always in-order. */ +#define TCG_GUEST_DEFAULT_MO TCG_MO_ALL + typedef struct CPUArchState CPUMBState; #if !defined(CONFIG_USER_ONLY) #include "mmu.h" From c914d46d0a645e7c633292146f4e38c945d4f847 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 18 Feb 2021 16:47:35 +0000 Subject: [PATCH 0200/1353] tcg: Do not elide memory barriers for !CF_PARALLEL in system mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The virtio devices require proper memory ordering between the vcpus and the iothreads. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/tcg-op.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index c07de5d9f8..7aadb37756 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -102,7 +102,19 @@ void tcg_gen_br(TCGLabel *l) void tcg_gen_mb(TCGBar mb_type) { - if (tcg_ctx->gen_tb->cflags & CF_PARALLEL) { +#ifdef CONFIG_USER_ONLY + bool parallel = tcg_ctx->gen_tb->cflags & CF_PARALLEL; +#else + /* + * It is tempting to elide the barrier in a uniprocessor context. + * However, even with a single cpu we have i/o threads running in + * parallel, and lack of memory order can result in e.g. virtio + * queue entries being read incorrectly. + */ + bool parallel = true; +#endif + + if (parallel) { tcg_gen_op1(INDEX_op_mb, mb_type); } } From f86e8f3d138de112d66ec28792e0fd303bf129ca Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 3 Mar 2022 15:57:10 +0000 Subject: [PATCH 0201/1353] tcg: Add host memory barriers to cpu_ldst.h interfaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bring the helpers into line with the rest of tcg in respecting guest memory ordering. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 10 ++++++++++ accel/tcg/internal.h | 34 ++++++++++++++++++++++++++++++++++ accel/tcg/user-exec.c | 10 ++++++++++ 3 files changed, 54 insertions(+) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index e02cfc550e..5666a8e23a 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -2339,6 +2339,7 @@ static uint8_t do_ld1_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, MMULookupLocals l; bool crosspage; + cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); crosspage = mmu_lookup(env, addr, oi, ra, access_type, &l); tcg_debug_assert(!crosspage); @@ -2360,6 +2361,7 @@ static uint16_t do_ld2_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, uint16_t ret; uint8_t a, b; + cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); crosspage = mmu_lookup(env, addr, oi, ra, access_type, &l); if (likely(!crosspage)) { return do_ld_2(env, &l.page[0], l.mmu_idx, access_type, l.memop, ra); @@ -2390,6 +2392,7 @@ static uint32_t do_ld4_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, bool crosspage; uint32_t ret; + cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); crosspage = mmu_lookup(env, addr, oi, ra, access_type, &l); if (likely(!crosspage)) { return do_ld_4(env, &l.page[0], l.mmu_idx, access_type, l.memop, ra); @@ -2417,6 +2420,7 @@ static uint64_t do_ld8_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, bool crosspage; uint64_t ret; + cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); crosspage = mmu_lookup(env, addr, oi, ra, access_type, &l); if (likely(!crosspage)) { return do_ld_8(env, &l.page[0], l.mmu_idx, access_type, l.memop, ra); @@ -2469,6 +2473,7 @@ static Int128 do_ld16_mmu(CPUArchState *env, vaddr addr, Int128 ret; int first; + cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); crosspage = mmu_lookup(env, addr, oi, ra, MMU_DATA_LOAD, &l); if (likely(!crosspage)) { /* Perform the load host endian. */ @@ -2802,6 +2807,7 @@ void helper_stb_mmu(CPUArchState *env, uint64_t addr, uint32_t val, bool crosspage; tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_8); + cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); crosspage = mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE, &l); tcg_debug_assert(!crosspage); @@ -2815,6 +2821,7 @@ static void do_st2_mmu(CPUArchState *env, vaddr addr, uint16_t val, bool crosspage; uint8_t a, b; + cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); crosspage = mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE, &l); if (likely(!crosspage)) { do_st_2(env, &l.page[0], val, l.mmu_idx, l.memop, ra); @@ -2843,6 +2850,7 @@ static void do_st4_mmu(CPUArchState *env, vaddr addr, uint32_t val, MMULookupLocals l; bool crosspage; + cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); crosspage = mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE, &l); if (likely(!crosspage)) { do_st_4(env, &l.page[0], val, l.mmu_idx, l.memop, ra); @@ -2870,6 +2878,7 @@ static void do_st8_mmu(CPUArchState *env, vaddr addr, uint64_t val, MMULookupLocals l; bool crosspage; + cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); crosspage = mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE, &l); if (likely(!crosspage)) { do_st_8(env, &l.page[0], val, l.mmu_idx, l.memop, ra); @@ -2899,6 +2908,7 @@ static void do_st16_mmu(CPUArchState *env, vaddr addr, Int128 val, uint64_t a, b; int first; + cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); crosspage = mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE, &l); if (likely(!crosspage)) { /* Swap to host endian if necessary, then store. */ diff --git a/accel/tcg/internal.h b/accel/tcg/internal.h index 91f308bdfa..650c3ac53f 100644 --- a/accel/tcg/internal.h +++ b/accel/tcg/internal.h @@ -78,4 +78,38 @@ extern int64_t max_advance; extern bool one_insn_per_tb; +/** + * tcg_req_mo: + * @type: TCGBar + * + * Filter @type to the barrier that is required for the guest + * memory ordering vs the host memory ordering. A non-zero + * result indicates that some barrier is required. + * + * If TCG_GUEST_DEFAULT_MO is not defined, assume that the + * guest requires strict ordering. + * + * This is a macro so that it's constant even without optimization. + */ +#ifdef TCG_GUEST_DEFAULT_MO +# define tcg_req_mo(type) \ + ((type) & TCG_GUEST_DEFAULT_MO & ~TCG_TARGET_DEFAULT_MO) +#else +# define tcg_req_mo(type) ((type) & ~TCG_TARGET_DEFAULT_MO) +#endif + +/** + * cpu_req_mo: + * @type: TCGBar + * + * If tcg_req_mo indicates a barrier for @type is required + * for the guest memory model, issue a host memory barrier. + */ +#define cpu_req_mo(type) \ + do { \ + if (tcg_req_mo(type)) { \ + smp_mb(); \ + } \ + } while (0) + #endif /* ACCEL_TCG_INTERNAL_H */ diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index f8b16d6ab8..8fbcbf9771 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -914,6 +914,7 @@ static uint8_t do_ld1_mmu(CPUArchState *env, abi_ptr addr, uint8_t ret; tcg_debug_assert((mop & MO_SIZE) == MO_8); + cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); haddr = cpu_mmu_lookup(env, addr, mop, ra, MMU_DATA_LOAD); ret = ldub_p(haddr); clear_helper_retaddr(); @@ -947,6 +948,7 @@ static uint16_t do_ld2_mmu(CPUArchState *env, abi_ptr addr, uint16_t ret; tcg_debug_assert((mop & MO_SIZE) == MO_16); + cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); haddr = cpu_mmu_lookup(env, addr, mop, ra, MMU_DATA_LOAD); ret = load_atom_2(env, ra, haddr, mop); clear_helper_retaddr(); @@ -984,6 +986,7 @@ static uint32_t do_ld4_mmu(CPUArchState *env, abi_ptr addr, uint32_t ret; tcg_debug_assert((mop & MO_SIZE) == MO_32); + cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); haddr = cpu_mmu_lookup(env, addr, mop, ra, MMU_DATA_LOAD); ret = load_atom_4(env, ra, haddr, mop); clear_helper_retaddr(); @@ -1021,6 +1024,7 @@ static uint64_t do_ld8_mmu(CPUArchState *env, abi_ptr addr, uint64_t ret; tcg_debug_assert((mop & MO_SIZE) == MO_64); + cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); haddr = cpu_mmu_lookup(env, addr, mop, ra, MMU_DATA_LOAD); ret = load_atom_8(env, ra, haddr, mop); clear_helper_retaddr(); @@ -1052,6 +1056,7 @@ static Int128 do_ld16_mmu(CPUArchState *env, abi_ptr addr, Int128 ret; tcg_debug_assert((mop & MO_SIZE) == MO_128); + cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); haddr = cpu_mmu_lookup(env, addr, mop, ra, MMU_DATA_LOAD); ret = load_atom_16(env, ra, haddr, mop); clear_helper_retaddr(); @@ -1087,6 +1092,7 @@ static void do_st1_mmu(CPUArchState *env, abi_ptr addr, uint8_t val, void *haddr; tcg_debug_assert((mop & MO_SIZE) == MO_8); + cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); haddr = cpu_mmu_lookup(env, addr, mop, ra, MMU_DATA_STORE); stb_p(haddr, val); clear_helper_retaddr(); @@ -1111,6 +1117,7 @@ static void do_st2_mmu(CPUArchState *env, abi_ptr addr, uint16_t val, void *haddr; tcg_debug_assert((mop & MO_SIZE) == MO_16); + cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); haddr = cpu_mmu_lookup(env, addr, mop, ra, MMU_DATA_STORE); if (mop & MO_BSWAP) { @@ -1139,6 +1146,7 @@ static void do_st4_mmu(CPUArchState *env, abi_ptr addr, uint32_t val, void *haddr; tcg_debug_assert((mop & MO_SIZE) == MO_32); + cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); haddr = cpu_mmu_lookup(env, addr, mop, ra, MMU_DATA_STORE); if (mop & MO_BSWAP) { @@ -1167,6 +1175,7 @@ static void do_st8_mmu(CPUArchState *env, abi_ptr addr, uint64_t val, void *haddr; tcg_debug_assert((mop & MO_SIZE) == MO_64); + cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); haddr = cpu_mmu_lookup(env, addr, mop, ra, MMU_DATA_STORE); if (mop & MO_BSWAP) { @@ -1195,6 +1204,7 @@ static void do_st16_mmu(CPUArchState *env, abi_ptr addr, Int128 val, void *haddr; tcg_debug_assert((mop & MO_SIZE) == MO_128); + cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); haddr = cpu_mmu_lookup(env, addr, mop, ra, MMU_DATA_STORE); if (mop & MO_BSWAP) { From 97e1576957c28a5fbcc810f92643e52069cc49b7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 3 Mar 2022 15:57:27 +0000 Subject: [PATCH 0202/1353] accel/tcg: Remove check_tcg_memory_orders_compatible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We now issue host memory barriers to match the guest memory order. Continue to disable MTTCG only if the guest has not been ported. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- accel/tcg/tcg-all.c | 39 ++++++++++----------------------------- 1 file changed, 10 insertions(+), 29 deletions(-) diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c index 02af6a2891..03dfd67e9e 100644 --- a/accel/tcg/tcg-all.c +++ b/accel/tcg/tcg-all.c @@ -64,37 +64,23 @@ DECLARE_INSTANCE_CHECKER(TCGState, TCG_STATE, * they can set the appropriate CONFIG flags in ${target}-softmmu.mak * * Once a guest architecture has been converted to the new primitives - * there are two remaining limitations to check. - * - * - The guest can't be oversized (e.g. 64 bit guest on 32 bit host) - * - The host must have a stronger memory order than the guest - * - * It may be possible in future to support strong guests on weak hosts - * but that will require tagging all load/stores in a guest with their - * implicit memory order requirements which would likely slow things - * down a lot. + * there is one remaining limitation to check: + * - The guest can't be oversized (e.g. 64 bit guest on 32 bit host) */ -static bool check_tcg_memory_orders_compatible(void) -{ -#if defined(TCG_GUEST_DEFAULT_MO) && defined(TCG_TARGET_DEFAULT_MO) - return (TCG_GUEST_DEFAULT_MO & ~TCG_TARGET_DEFAULT_MO) == 0; -#else - return false; -#endif -} - static bool default_mttcg_enabled(void) { if (icount_enabled() || TCG_OVERSIZED_GUEST) { return false; - } else { -#ifdef TARGET_SUPPORTS_MTTCG - return check_tcg_memory_orders_compatible(); -#else - return false; -#endif } +#ifdef TARGET_SUPPORTS_MTTCG +# ifndef TCG_GUEST_DEFAULT_MO +# error "TARGET_SUPPORTS_MTTCG without TCG_GUEST_DEFAULT_MO" +# endif + return true; +#else + return false; +#endif } static void tcg_accel_instance_init(Object *obj) @@ -162,11 +148,6 @@ static void tcg_set_thread(Object *obj, const char *value, Error **errp) warn_report("Guest not yet converted to MTTCG - " "you may get unexpected results"); #endif - if (!check_tcg_memory_orders_compatible()) { - warn_report("Guest expects a stronger memory ordering " - "than the host provides"); - error_printf("This may cause strange/hard to debug errors\n"); - } s->mttcg_enabled = true; } } else if (strcmp(value, "single") == 0) { From 58e8f1f616d117aed6283690419dc16f53b7a202 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Feb 2023 19:17:52 -1000 Subject: [PATCH 0203/1353] accel/tcg: Store some tlb flags in CPUTLBEntryFull MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have run out of bits we can use within the CPUTLBEntry comparators, as TLB_FLAGS_MASK cannot overlap alignment. Store slow_flags[] in CPUTLBEntryFull, and merge with the flags from the comparator. A new TLB_FORCE_SLOW bit is set within the comparator as an indication that the slow path must be used. Move TLB_BSWAP to TLB_SLOW_FLAGS_MASK. Since we are out of bits, we cannot create a new bit without moving an old one. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 98 ++++++++++++++++++++++++----------------- include/exec/cpu-all.h | 21 +++++++-- include/exec/cpu-defs.h | 6 +++ include/hw/core/cpu.h | 1 + 4 files changed, 82 insertions(+), 44 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 5666a8e23a..3671846744 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -1107,6 +1107,24 @@ static void tlb_add_large_page(CPUArchState *env, int mmu_idx, env_tlb(env)->d[mmu_idx].large_page_mask = lp_mask; } +static inline void tlb_set_compare(CPUTLBEntryFull *full, CPUTLBEntry *ent, + target_ulong address, int flags, + MMUAccessType access_type, bool enable) +{ + if (enable) { + address |= flags & TLB_FLAGS_MASK; + flags &= TLB_SLOW_FLAGS_MASK; + if (flags) { + address |= TLB_FORCE_SLOW; + } + } else { + address = -1; + flags = 0; + } + ent->addr_idx[access_type] = address; + full->slow_flags[access_type] = flags; +} + /* * Add a new TLB entry. At most one entry for a given virtual address * is permitted. Only a single TARGET_PAGE_SIZE region is mapped, the @@ -1122,9 +1140,7 @@ void tlb_set_page_full(CPUState *cpu, int mmu_idx, CPUTLB *tlb = env_tlb(env); CPUTLBDesc *desc = &tlb->d[mmu_idx]; MemoryRegionSection *section; - unsigned int index; - vaddr address; - vaddr write_address; + unsigned int index, read_flags, write_flags; uintptr_t addend; CPUTLBEntry *te, tn; hwaddr iotlb, xlat, sz, paddr_page; @@ -1153,13 +1169,13 @@ void tlb_set_page_full(CPUState *cpu, int mmu_idx, " prot=%x idx=%d\n", addr, full->phys_addr, prot, mmu_idx); - address = addr_page; + read_flags = 0; if (full->lg_page_size < TARGET_PAGE_BITS) { /* Repeat the MMU check and TLB fill on every access. */ - address |= TLB_INVALID_MASK; + read_flags |= TLB_INVALID_MASK; } if (full->attrs.byte_swap) { - address |= TLB_BSWAP; + read_flags |= TLB_BSWAP; } is_ram = memory_region_is_ram(section->mr); @@ -1173,7 +1189,7 @@ void tlb_set_page_full(CPUState *cpu, int mmu_idx, addend = 0; } - write_address = address; + write_flags = read_flags; if (is_ram) { iotlb = memory_region_get_ram_addr(section->mr) + xlat; /* @@ -1182,9 +1198,9 @@ void tlb_set_page_full(CPUState *cpu, int mmu_idx, */ if (prot & PAGE_WRITE) { if (section->readonly) { - write_address |= TLB_DISCARD_WRITE; + write_flags |= TLB_DISCARD_WRITE; } else if (cpu_physical_memory_is_clean(iotlb)) { - write_address |= TLB_NOTDIRTY; + write_flags |= TLB_NOTDIRTY; } } } else { @@ -1195,9 +1211,9 @@ void tlb_set_page_full(CPUState *cpu, int mmu_idx, * Reads to romd devices go through the ram_ptr found above, * but of course reads to I/O must go through MMIO. */ - write_address |= TLB_MMIO; + write_flags |= TLB_MMIO; if (!is_romd) { - address = write_address; + read_flags = write_flags; } } @@ -1242,7 +1258,7 @@ void tlb_set_page_full(CPUState *cpu, int mmu_idx, * TARGET_PAGE_BITS, and either * + the ram_addr_t of the page base of the target RAM (RAM) * + the offset within section->mr of the page base (I/O, ROMD) - * We subtract the vaddr_page (which is page aligned and thus won't + * We subtract addr_page (which is page aligned and thus won't * disturb the low bits) to give an offset which can be added to the * (non-page-aligned) vaddr of the eventual memory access to get * the MemoryRegion offset for the access. Note that the vaddr we @@ -1250,36 +1266,30 @@ void tlb_set_page_full(CPUState *cpu, int mmu_idx, * vaddr we add back in io_readx()/io_writex()/get_page_addr_code(). */ desc->fulltlb[index] = *full; - desc->fulltlb[index].xlat_section = iotlb - addr_page; - desc->fulltlb[index].phys_addr = paddr_page; + full = &desc->fulltlb[index]; + full->xlat_section = iotlb - addr_page; + full->phys_addr = paddr_page; /* Now calculate the new entry */ tn.addend = addend - addr_page; - if (prot & PAGE_READ) { - tn.addr_read = address; - if (wp_flags & BP_MEM_READ) { - tn.addr_read |= TLB_WATCHPOINT; - } - } else { - tn.addr_read = -1; - } - if (prot & PAGE_EXEC) { - tn.addr_code = address; - } else { - tn.addr_code = -1; - } + tlb_set_compare(full, &tn, addr_page, read_flags, + MMU_INST_FETCH, prot & PAGE_EXEC); - tn.addr_write = -1; - if (prot & PAGE_WRITE) { - tn.addr_write = write_address; - if (prot & PAGE_WRITE_INV) { - tn.addr_write |= TLB_INVALID_MASK; - } - if (wp_flags & BP_MEM_WRITE) { - tn.addr_write |= TLB_WATCHPOINT; - } + if (wp_flags & BP_MEM_READ) { + read_flags |= TLB_WATCHPOINT; } + tlb_set_compare(full, &tn, addr_page, read_flags, + MMU_DATA_LOAD, prot & PAGE_READ); + + if (prot & PAGE_WRITE_INV) { + write_flags |= TLB_INVALID_MASK; + } + if (wp_flags & BP_MEM_WRITE) { + write_flags |= TLB_WATCHPOINT; + } + tlb_set_compare(full, &tn, addr_page, write_flags, + MMU_DATA_STORE, prot & PAGE_WRITE); copy_tlb_helper_locked(te, &tn); tlb_n_used_entries_inc(env, mmu_idx); @@ -1509,7 +1519,8 @@ static int probe_access_internal(CPUArchState *env, vaddr addr, CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr); uint64_t tlb_addr = tlb_read_idx(entry, access_type); vaddr page_addr = addr & TARGET_PAGE_MASK; - int flags = TLB_FLAGS_MASK; + int flags = TLB_FLAGS_MASK & ~TLB_FORCE_SLOW; + CPUTLBEntryFull *full; if (!tlb_hit_page(tlb_addr, page_addr)) { if (!victim_tlb_hit(env, mmu_idx, index, access_type, page_addr)) { @@ -1538,7 +1549,8 @@ static int probe_access_internal(CPUArchState *env, vaddr addr, } flags &= tlb_addr; - *pfull = &env_tlb(env)->d[mmu_idx].fulltlb[index]; + *pfull = full = &env_tlb(env)->d[mmu_idx].fulltlb[index]; + flags |= full->slow_flags[access_type]; /* Fold all "mmio-like" bits into TLB_MMIO. This is not RAM. */ if (unlikely(flags & ~(TLB_WATCHPOINT | TLB_NOTDIRTY))) { @@ -1761,6 +1773,8 @@ static bool mmu_lookup1(CPUArchState *env, MMULookupPageData *data, CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr); uint64_t tlb_addr = tlb_read_idx(entry, access_type); bool maybe_resized = false; + CPUTLBEntryFull *full; + int flags; /* If the TLB entry is for a different page, reload and try again. */ if (!tlb_hit(tlb_addr, addr)) { @@ -1774,8 +1788,12 @@ static bool mmu_lookup1(CPUArchState *env, MMULookupPageData *data, tlb_addr = tlb_read_idx(entry, access_type) & ~TLB_INVALID_MASK; } - data->flags = tlb_addr & TLB_FLAGS_MASK; - data->full = &env_tlb(env)->d[mmu_idx].fulltlb[index]; + full = &env_tlb(env)->d[mmu_idx].fulltlb[index]; + flags = tlb_addr & (TLB_FLAGS_MASK & ~TLB_FORCE_SLOW); + flags |= full->slow_flags[access_type]; + + data->full = full; + data->flags = flags; /* Compute haddr speculatively; depending on flags it might be invalid. */ data->haddr = (void *)((uintptr_t)addr + entry->addend); diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 09bf4c0cc6..4422f4bb07 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -327,17 +327,30 @@ CPUArchState *cpu_copy(CPUArchState *env); #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 the slow path must be used; more flags in CPUTLBEntryFull. */ +#define TLB_FORCE_SLOW (1 << (TARGET_PAGE_BITS_MIN - 5)) /* Set if TLB entry writes ignored. */ #define TLB_DISCARD_WRITE (1 << (TARGET_PAGE_BITS_MIN - 6)) -/* 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_WATCHPOINT | 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) + +#define TLB_SLOW_FLAGS_MASK TLB_BSWAP + +/* 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 diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h index e6a079402e..fb4c8d480f 100644 --- a/include/exec/cpu-defs.h +++ b/include/exec/cpu-defs.h @@ -124,6 +124,12 @@ typedef struct CPUTLBEntryFull { /* @lg_page_size contains the log2 of the page size. */ uint8_t lg_page_size; + /* + * Additional tlb flags for use by the slow path. If non-zero, + * the corresponding CPUTLBEntry comparator must have TLB_FORCE_SLOW. + */ + uint8_t slow_flags[MMU_ACCESS_COUNT]; + /* * Allow target-specific additions to this structure. * This may be used to cache items from the guest cpu diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 3b765beb9b..eda0230a02 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -84,6 +84,7 @@ typedef enum MMUAccessType { MMU_DATA_LOAD = 0, MMU_DATA_STORE = 1, MMU_INST_FETCH = 2 +#define MMU_ACCESS_COUNT 3 } MMUAccessType; typedef struct CPUWatchpoint CPUWatchpoint; From 187ba6945345cedf2f343fcc33e5616186aebe9d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Feb 2023 23:09:43 -1000 Subject: [PATCH 0204/1353] accel/tcg: Move TLB_WATCHPOINT to TLB_SLOW_FLAGS_MASK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This frees up one bit of the primary tlb flags without impacting the TLB_NOTDIRTY logic. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 18 ++++++++++++++---- include/exec/cpu-all.h | 8 ++++---- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 3671846744..5b51eff5a4 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -1981,7 +1981,7 @@ static void *atomic_mmu_lookup(CPUArchState *env, vaddr addr, MemOpIdx oi, */ goto stop_the_world; } - /* Collect TLB_WATCHPOINT for read. */ + /* Collect tlb flags for read. */ tlb_addr |= tlbe->addr_read; /* Notice an IO access or a needs-MMU-lookup access */ @@ -1998,9 +1998,19 @@ static void *atomic_mmu_lookup(CPUArchState *env, vaddr addr, MemOpIdx oi, notdirty_write(env_cpu(env), addr, size, full, retaddr); } - if (unlikely(tlb_addr & TLB_WATCHPOINT)) { - cpu_check_watchpoint(env_cpu(env), addr, size, full->attrs, - BP_MEM_READ | BP_MEM_WRITE, retaddr); + if (unlikely(tlb_addr & TLB_FORCE_SLOW)) { + int wp_flags = 0; + + if (full->slow_flags[MMU_DATA_STORE] & TLB_WATCHPOINT) { + wp_flags |= BP_MEM_WRITE; + } + if (full->slow_flags[MMU_DATA_LOAD] & TLB_WATCHPOINT) { + wp_flags |= BP_MEM_READ; + } + if (wp_flags) { + cpu_check_watchpoint(env_cpu(env), addr, size, + full->attrs, wp_flags, retaddr); + } } return hostaddr; diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 4422f4bb07..b5618613cc 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -325,8 +325,6 @@ 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 the slow path must be used; more flags in CPUTLBEntryFull. */ #define TLB_FORCE_SLOW (1 << (TARGET_PAGE_BITS_MIN - 5)) /* Set if TLB entry writes ignored. */ @@ -338,7 +336,7 @@ CPUArchState *cpu_copy(CPUArchState *env); */ #define TLB_FLAGS_MASK \ (TLB_INVALID_MASK | TLB_NOTDIRTY | TLB_MMIO \ - | TLB_WATCHPOINT | TLB_FORCE_SLOW | TLB_DISCARD_WRITE) + | TLB_FORCE_SLOW | TLB_DISCARD_WRITE) /* * Flags stored in CPUTLBEntryFull.slow_flags[x]. @@ -346,8 +344,10 @@ CPUArchState *cpu_copy(CPUArchState *env); */ /* Set if TLB entry requires byte swap. */ #define TLB_BSWAP (1 << 0) +/* Set if TLB entry contains a watchpoint. */ +#define TLB_WATCHPOINT (1 << 1) -#define TLB_SLOW_FLAGS_MASK TLB_BSWAP +#define TLB_SLOW_FLAGS_MASK (TLB_BSWAP | TLB_WATCHPOINT) /* The two sets of flags must not overlap. */ QEMU_BUILD_BUG_ON(TLB_FLAGS_MASK & TLB_SLOW_FLAGS_MASK); From a0eaae08c7c6a59c185cf646b02f4167b2ac6ec0 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 21 Jun 2023 12:27:27 +0200 Subject: [PATCH 0205/1353] accel/tcg: Renumber TLB_DISCARD_WRITE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move to fill a hole in the set of bits. Reduce the total number of tlb bits by 1. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- include/exec/cpu-all.h | 4 ++-- tcg/tcg-op-ldst.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index b5618613cc..8018ce783e 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -325,10 +325,10 @@ 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 writes ignored. */ +#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)) -/* Set if TLB entry writes ignored. */ -#define TLB_DISCARD_WRITE (1 << (TARGET_PAGE_BITS_MIN - 6)) /* * Use this mask to check interception with an alignment mask diff --git a/tcg/tcg-op-ldst.c b/tcg/tcg-op-ldst.c index a4f51bfb6e..0fcc1618e5 100644 --- a/tcg/tcg-op-ldst.c +++ b/tcg/tcg-op-ldst.c @@ -39,7 +39,7 @@ static void check_max_alignment(unsigned a_bits) * The requested alignment cannot overlap the TLB flags. * FIXME: Must keep the count up-to-date with "exec/cpu-all.h". */ - tcg_debug_assert(a_bits + 6 <= tcg_ctx->page_bits); + tcg_debug_assert(a_bits + 5 <= tcg_ctx->page_bits); #endif } From 67f85346ca9305d9fb3254ceff735ceaadeb0911 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 27 Jun 2023 16:14:06 +1000 Subject: [PATCH 0206/1353] icount: don't adjust virtual time backwards after warp The icount-based QEMU_CLOCK_VIRTUAL runs ahead of the RT clock at times. When warping, it is possible it is still ahead at the end of the warp, which causes icount adaptive mode to adjust it backward. This can result in the machine observing time going backwards. Prevent this by clamping adaptive adjustment to 0 at minimum. Signed-off-by: Nicholas Piggin Message-ID: <20230627061406.241847-1-npiggin@gmail.com> Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini --- softmmu/icount.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/softmmu/icount.c b/softmmu/icount.c index 4504433e16..a5cef9c60a 100644 --- a/softmmu/icount.c +++ b/softmmu/icount.c @@ -259,11 +259,16 @@ static void icount_warp_rt(void) warp_delta = clock - timers_state.vm_clock_warp_start; if (icount_enabled() == 2) { /* - * In adaptive mode, do not let QEMU_CLOCK_VIRTUAL run too - * far ahead of real time. + * In adaptive mode, do not let QEMU_CLOCK_VIRTUAL run too far + * ahead of real time (it might already be ahead so careful not + * to go backwards). */ int64_t cur_icount = icount_get_locked(); int64_t delta = clock - cur_icount; + + if (delta < 0) { + delta = 0; + } warp_delta = MIN(warp_delta, delta); } qatomic_set_i64(&timers_state.qemu_icount_bias, From 333e7599a0d723801235f675719008ce43db93e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Sun, 19 Mar 2023 15:10:17 +0400 Subject: [PATCH 0207/1353] ui: return NULL when getting cursor without a console MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VNC may try to get the current cursor even when there are no consoles and crashes. Simple reproducer is qemu with -nodefaults. Fixes: (again) https://gitlab.com/qemu-project/qemu/-/issues/1548 Fixes: commit 385ac97f8 ("ui: keep current cursor with QemuConsole") Signed-off-by: Marc-André Lureau Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230428154807.2143652-1-marcandre.lureau@redhat.com> --- ui/console.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/console.c b/ui/console.c index e173731e20..7461446e71 100644 --- a/ui/console.c +++ b/ui/console.c @@ -2306,7 +2306,7 @@ QEMUCursor *qemu_console_get_cursor(QemuConsole *con) if (con == NULL) { con = active_console; } - return con->cursor; + return con ? con->cursor : NULL; } bool qemu_console_is_visible(QemuConsole *con) From 72cbcead969de5b34709ac706a3881636010b6f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 18 Apr 2023 11:32:37 +0400 Subject: [PATCH 0208/1353] egl: no need to lookup EGL functions manually MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit libepoxy handles loading the function pointer and dispatching the call, so you don't have to worry about it. Signed-off-by: Marc-André Lureau Message-Id: <20230515132455.1025608-1-marcandre.lureau@redhat.com> --- ui/egl-helpers.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ui/egl-helpers.c b/ui/egl-helpers.c index 4203163ace..60385c1f48 100644 --- a/ui/egl-helpers.c +++ b/ui/egl-helpers.c @@ -439,10 +439,8 @@ static EGLDisplay qemu_egl_get_display(EGLNativeDisplayType native, /* In practise any EGL 1.5 implementation would support the EXT extension */ if (epoxy_has_egl_extension(NULL, "EGL_EXT_platform_base")) { - PFNEGLGETPLATFORMDISPLAYEXTPROC getPlatformDisplayEXT = - (void *) eglGetProcAddress("eglGetPlatformDisplayEXT"); - if (getPlatformDisplayEXT && platform != 0) { - dpy = getPlatformDisplayEXT(platform, native, NULL); + if (platform != 0) { + dpy = eglGetPlatformDisplayEXT(platform, native, NULL); } } From 176e3783f2ab1476cdfd18a12bd2cfbe42e6b573 Mon Sep 17 00:00:00 2001 From: Antonio Caggiano Date: Mon, 12 Jun 2023 11:19:59 +0200 Subject: [PATCH 0209/1353] ui/sdl2: OpenGL window context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When OpenGL is enabled, create only the OpenGL context, ignoring the SDL renderer as it is unused anyway. Signed-off-by: Antonio Caggiano Reviewed-by: Marc-André Lureau Message-Id: <20230612091959.2983-1-quic_acaggian@quicinc.com> --- ui/sdl2.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/ui/sdl2.c b/ui/sdl2.c index 9d703200bf..0d91b555e3 100644 --- a/ui/sdl2.c +++ b/ui/sdl2.c @@ -113,11 +113,11 @@ void sdl2_window_create(struct sdl2_console *scon) SDL_SetHint(SDL_HINT_RENDER_DRIVER, driver); SDL_SetHint(SDL_HINT_RENDER_BATCHING, "1"); - } - scon->real_renderer = SDL_CreateRenderer(scon->real_window, -1, 0); - if (scon->opengl) { scon->winctx = SDL_GL_CreateContext(scon->real_window); + } else { + /* The SDL renderer is only used by sdl2-2D, when OpenGL is disabled */ + scon->real_renderer = SDL_CreateRenderer(scon->real_window, -1, 0); } sdl_update_caption(scon); } @@ -128,10 +128,14 @@ void sdl2_window_destroy(struct sdl2_console *scon) return; } - SDL_GL_DeleteContext(scon->winctx); - scon->winctx = NULL; - SDL_DestroyRenderer(scon->real_renderer); - scon->real_renderer = NULL; + if (scon->winctx) { + SDL_GL_DeleteContext(scon->winctx); + scon->winctx = NULL; + } + if (scon->real_renderer) { + SDL_DestroyRenderer(scon->real_renderer); + scon->real_renderer = NULL; + } SDL_DestroyWindow(scon->real_window); scon->real_window = NULL; } From b097b80bc919fca5f45663c20722e57792a093ea Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Mon, 12 Jun 2023 10:13:58 +0800 Subject: [PATCH 0210/1353] virtio-gpu: Optimize 2D resource data transfer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The following points sometimes can reduce much data to copy: 1. When width matches, we can transfer data with one call of iov_to_buf(). 2. Only the required height need to transfer, not whole image. Signed-off-by: Keqian Zhu Reviewed-by: Marc-André Lureau Message-Id: <20230612021358.25068-1-zhukeqian1@huawei.com> --- hw/display/virtio-gpu.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 66cddd94d9..af31018ab0 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -438,11 +438,11 @@ static void virtio_gpu_transfer_to_host_2d(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd) { struct virtio_gpu_simple_resource *res; - int h; + int h, bpp; uint32_t src_offset, dst_offset, stride; - int bpp; pixman_format_code_t format; struct virtio_gpu_transfer_to_host_2d t2d; + void *img_data; VIRTIO_GPU_FILL_CMD(t2d); virtio_gpu_t2d_bswap(&t2d); @@ -471,23 +471,23 @@ static void virtio_gpu_transfer_to_host_2d(VirtIOGPU *g, format = pixman_image_get_format(res->image); bpp = DIV_ROUND_UP(PIXMAN_FORMAT_BPP(format), 8); stride = pixman_image_get_stride(res->image); + img_data = pixman_image_get_data(res->image); - if (t2d.offset || t2d.r.x || t2d.r.y || - t2d.r.width != pixman_image_get_width(res->image)) { - void *img_data = pixman_image_get_data(res->image); + if (t2d.r.x || t2d.r.width != pixman_image_get_width(res->image)) { for (h = 0; h < t2d.r.height; h++) { src_offset = t2d.offset + stride * h; dst_offset = (t2d.r.y + h) * stride + (t2d.r.x * bpp); iov_to_buf(res->iov, res->iov_cnt, src_offset, - (uint8_t *)img_data - + dst_offset, t2d.r.width * bpp); + (uint8_t *)img_data + dst_offset, + t2d.r.width * bpp); } } else { - iov_to_buf(res->iov, res->iov_cnt, 0, - pixman_image_get_data(res->image), - pixman_image_get_stride(res->image) - * pixman_image_get_height(res->image)); + src_offset = t2d.offset; + dst_offset = t2d.r.y * stride + t2d.r.x * bpp; + iov_to_buf(res->iov, res->iov_cnt, src_offset, + (uint8_t *)img_data + dst_offset, + stride * t2d.r.height); } } From 1e0c544673f43cb7ed97020cb9b3b1a915811bac Mon Sep 17 00:00:00 2001 From: Zhang Huasen Date: Thu, 15 Jun 2023 18:35:00 +0800 Subject: [PATCH 0211/1353] chardev/char-win-stdio: Support VT sequences on Windows 11 host MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the monitor or the serial port use STDIO as backend on Windows 11 host, e.g. -nographic options is used, the monitor or the guest Linux do not response to arrow keys. When Windows creates a console, ENABLE_VIRTUAL_PROCESS_INPUT is disabled by default. Arrow keys cannot be retrieved by ReadFile or ReadConsoleInput functions. Add ENABLE_VIRTUAL_PROCESS_INPUT to the flag which is passed to SetConsoleMode, when opening stdio console. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1674 Signed-off-by: Zhang Huasen Reviewed-by: Marc-André Lureau Message-Id: --- chardev/char-win-stdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chardev/char-win-stdio.c b/chardev/char-win-stdio.c index eb830eabd9..1a18999e78 100644 --- a/chardev/char-win-stdio.c +++ b/chardev/char-win-stdio.c @@ -190,7 +190,7 @@ static void qemu_chr_open_stdio(Chardev *chr, } } - dwMode |= ENABLE_LINE_INPUT; + dwMode |= ENABLE_LINE_INPUT | ENABLE_VIRTUAL_TERMINAL_INPUT; if (is_console) { /* set the terminal in raw mode */ From b6596785987d0174d6f413b7a5b695de6aa14483 Mon Sep 17 00:00:00 2001 From: Bilal Elmoussaoui Date: Mon, 19 Jun 2023 11:53:36 +0200 Subject: [PATCH 0212/1353] ui/touch: Move event handling to a common helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To share code between the GTK and DBus UI bakcends see the next commit for details Signed-off-by: Bilal Elmoussaoui Reviewed-by: Marc-André Lureau Message-Id: <20230619095337.9899-2-belmouss@redhat.com> --- include/ui/console.h | 15 ++++++++++ ui/console.c | 65 ++++++++++++++++++++++++++++++++++++++++++++ ui/gtk.c | 61 ++++------------------------------------- 3 files changed, 85 insertions(+), 56 deletions(-) diff --git a/include/ui/console.h b/include/ui/console.h index ae5ec466c1..2093e2a3ba 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -5,6 +5,7 @@ #include "qom/object.h" #include "qemu/notify.h" #include "qapi/qapi-types-ui.h" +#include "ui/input.h" #ifdef CONFIG_OPENGL # include @@ -95,6 +96,20 @@ bool kbd_put_qcode_console(QemuConsole *s, int qcode, bool ctrl); void kbd_put_string_console(QemuConsole *s, const char *str, int len); void kbd_put_keysym(int keysym); +/* Touch devices */ +typedef struct touch_slot { + int x; + int y; + int tracking_id; +} touch_slot; + +void console_handle_touch_event(QemuConsole *con, + struct touch_slot touch_slots[INPUT_EVENT_SLOTS_MAX], + uint64_t num_slot, + int width, int height, + double x, double y, + InputMultiTouchType type, + Error **errp); /* consoles */ #define TYPE_QEMU_CONSOLE "qemu-console" diff --git a/ui/console.c b/ui/console.c index 7461446e71..cfaa43e970 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1635,6 +1635,71 @@ static bool console_compatible_with(QemuConsole *con, return true; } +void console_handle_touch_event(QemuConsole *con, + struct touch_slot touch_slots[INPUT_EVENT_SLOTS_MAX], + uint64_t num_slot, + int width, int height, + double x, double y, + InputMultiTouchType type, + Error **errp) +{ + struct touch_slot *slot; + bool needs_sync = false; + int update; + int i; + + if (num_slot >= INPUT_EVENT_SLOTS_MAX) { + error_setg(errp, + "Unexpected touch slot number: % " PRId64" >= %d", + num_slot, INPUT_EVENT_SLOTS_MAX); + return; + } + + slot = &touch_slots[num_slot]; + slot->x = x; + slot->y = y; + + if (type == INPUT_MULTI_TOUCH_TYPE_BEGIN) { + slot->tracking_id = num_slot; + } + + for (i = 0; i < INPUT_EVENT_SLOTS_MAX; ++i) { + if (i == num_slot) { + update = type; + } else { + update = INPUT_MULTI_TOUCH_TYPE_UPDATE; + } + + slot = &touch_slots[i]; + + if (slot->tracking_id == -1) { + continue; + } + + if (update == INPUT_MULTI_TOUCH_TYPE_END) { + slot->tracking_id = -1; + qemu_input_queue_mtt(con, update, i, slot->tracking_id); + needs_sync = true; + } else { + qemu_input_queue_mtt(con, update, i, slot->tracking_id); + qemu_input_queue_btn(con, INPUT_BUTTON_TOUCH, true); + qemu_input_queue_mtt_abs(con, + INPUT_AXIS_X, (int) slot->x, + 0, width, + i, slot->tracking_id); + qemu_input_queue_mtt_abs(con, + INPUT_AXIS_Y, (int) slot->y, + 0, height, + i, slot->tracking_id); + needs_sync = true; + } + } + + if (needs_sync) { + qemu_input_event_sync(); + } +} + void qemu_console_set_display_gl_ctx(QemuConsole *con, DisplayGLCtx *gl) { /* display has opengl support */ diff --git a/ui/gtk.c b/ui/gtk.c index e50f950f2b..e09e164482 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -130,11 +130,6 @@ typedef struct VCChardev VCChardev; DECLARE_INSTANCE_CHECKER(VCChardev, VC_CHARDEV, TYPE_CHARDEV_VC) -struct touch_slot { - int x; - int y; - int tracking_id; -}; static struct touch_slot touch_slots[INPUT_EVENT_SLOTS_MAX]; bool gtk_use_gl_area; @@ -1068,27 +1063,12 @@ static gboolean gd_touch_event(GtkWidget *widget, GdkEventTouch *touch, void *opaque) { VirtualConsole *vc = opaque; - struct touch_slot *slot; uint64_t num_slot = GPOINTER_TO_UINT(touch->sequence); - bool needs_sync = false; - int update; int type = -1; - int i; - - if (num_slot >= INPUT_EVENT_SLOTS_MAX) { - warn_report("gtk: unexpected touch slot number: % " PRId64" >= %d\n", - num_slot, INPUT_EVENT_SLOTS_MAX); - return FALSE; - } - - slot = &touch_slots[num_slot]; - slot->x = touch->x; - slot->y = touch->y; switch (touch->type) { case GDK_TOUCH_BEGIN: type = INPUT_MULTI_TOUCH_TYPE_BEGIN; - slot->tracking_id = num_slot; break; case GDK_TOUCH_UPDATE: type = INPUT_MULTI_TOUCH_TYPE_UPDATE; @@ -1099,44 +1079,13 @@ static gboolean gd_touch_event(GtkWidget *widget, GdkEventTouch *touch, break; default: warn_report("gtk: unexpected touch event type\n"); + return FALSE; } - for (i = 0; i < INPUT_EVENT_SLOTS_MAX; ++i) { - if (i == num_slot) { - update = type; - } else { - update = INPUT_MULTI_TOUCH_TYPE_UPDATE; - } - - slot = &touch_slots[i]; - - if (slot->tracking_id == -1) { - continue; - } - - if (update == INPUT_MULTI_TOUCH_TYPE_END) { - slot->tracking_id = -1; - qemu_input_queue_mtt(vc->gfx.dcl.con, update, i, slot->tracking_id); - needs_sync = true; - } else { - qemu_input_queue_mtt(vc->gfx.dcl.con, update, i, slot->tracking_id); - qemu_input_queue_btn(vc->gfx.dcl.con, INPUT_BUTTON_TOUCH, true); - qemu_input_queue_mtt_abs(vc->gfx.dcl.con, - INPUT_AXIS_X, (int) slot->x, - 0, surface_width(vc->gfx.ds), - i, slot->tracking_id); - qemu_input_queue_mtt_abs(vc->gfx.dcl.con, - INPUT_AXIS_Y, (int) slot->y, - 0, surface_height(vc->gfx.ds), - i, slot->tracking_id); - needs_sync = true; - } - } - - if (needs_sync) { - qemu_input_event_sync(); - } - + console_handle_touch_event(vc->gfx.dcl.con, touch_slots, + num_slot, surface_width(vc->gfx.ds), + surface_height(vc->gfx.ds), touch->x, + touch->y, type, &error_warn); return TRUE; } From de9f844ce27ef8540bb9e8b4dd2c159b676d78a5 Mon Sep 17 00:00:00 2001 From: Bilal Elmoussaoui Date: Mon, 19 Jun 2023 11:53:37 +0200 Subject: [PATCH 0213/1353] ui/dbus: Expose a touch device interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So that clients making use of the DBus backend could send touch events through the new org.qemu.Display1.Touch interface Signed-off-by: Bilal Elmoussaoui Reviewed-by: Marc-André Lureau Message-Id: <20230619095337.9899-3-belmouss@redhat.com> --- ui/dbus-console.c | 59 +++++++++++++++++++++++++++++++++++++++++++- ui/dbus-display1.xml | 45 +++++++++++++++++++++++++++++++-- ui/trace-events | 1 + 3 files changed, 102 insertions(+), 3 deletions(-) diff --git a/ui/dbus-console.c b/ui/dbus-console.c index f77bc49d2e..bc97614fec 100644 --- a/ui/dbus-console.c +++ b/ui/dbus-console.c @@ -32,6 +32,8 @@ #include "dbus.h" +static struct touch_slot touch_slots[INPUT_EVENT_SLOTS_MAX]; + struct _DBusDisplayConsole { GDBusObjectSkeleton parent_instance; DisplayChangeListener dcl; @@ -44,6 +46,7 @@ struct _DBusDisplayConsole { QKbdState *kbd; QemuDBusDisplay1Mouse *iface_mouse; + QemuDBusDisplay1MultiTouch *iface_touch; gboolean last_set; guint last_x; guint last_y; @@ -345,6 +348,46 @@ dbus_mouse_rel_motion(DBusDisplayConsole *ddc, return DBUS_METHOD_INVOCATION_HANDLED; } +static gboolean +dbus_touch_send_event(DBusDisplayConsole *ddc, + GDBusMethodInvocation *invocation, + guint kind, uint64_t num_slot, + double x, double y) +{ + Error *error = NULL; + int width, height; + trace_dbus_touch_send_event(kind, num_slot, x, y); + + if (kind != INPUT_MULTI_TOUCH_TYPE_BEGIN && + kind != INPUT_MULTI_TOUCH_TYPE_UPDATE && + kind != INPUT_MULTI_TOUCH_TYPE_CANCEL && + kind != INPUT_MULTI_TOUCH_TYPE_END) + { + g_dbus_method_invocation_return_error( + invocation, DBUS_DISPLAY_ERROR, + DBUS_DISPLAY_ERROR_INVALID, + "Invalid touch event kind"); + return DBUS_METHOD_INVOCATION_HANDLED; + } + width = qemu_console_get_width(ddc->dcl.con, 0); + height = qemu_console_get_height(ddc->dcl.con, 0); + + console_handle_touch_event(ddc->dcl.con, touch_slots, + num_slot, width, height, + x, y, kind, &error); + if (error != NULL) { + g_dbus_method_invocation_return_error( + invocation, DBUS_DISPLAY_ERROR, + DBUS_DISPLAY_ERROR_INVALID, + error_get_pretty(error), NULL); + error_free(error); + } else { + qemu_dbus_display1_multi_touch_complete_send_event(ddc->iface_touch, + invocation); + } + return DBUS_METHOD_INVOCATION_HANDLED; +} + static gboolean dbus_mouse_set_pos(DBusDisplayConsole *ddc, GDBusMethodInvocation *invocation, @@ -440,7 +483,7 @@ dbus_display_console_new(DBusDisplay *display, QemuConsole *con) g_autofree char *label = NULL; char device_addr[256] = ""; DBusDisplayConsole *ddc; - int idx; + int idx, i; assert(display); assert(con); @@ -495,6 +538,20 @@ dbus_display_console_new(DBusDisplay *display, QemuConsole *con) g_dbus_object_skeleton_add_interface(G_DBUS_OBJECT_SKELETON(ddc), G_DBUS_INTERFACE_SKELETON(ddc->iface_mouse)); + ddc->iface_touch = qemu_dbus_display1_multi_touch_skeleton_new(); + g_object_connect(ddc->iface_touch, + "swapped-signal::handle-send-event", dbus_touch_send_event, ddc, + NULL); + qemu_dbus_display1_multi_touch_set_max_slots(ddc->iface_touch, + INPUT_EVENT_SLOTS_MAX); + g_dbus_object_skeleton_add_interface(G_DBUS_OBJECT_SKELETON(ddc), + G_DBUS_INTERFACE_SKELETON(ddc->iface_touch)); + + for (i = 0; i < INPUT_EVENT_SLOTS_MAX; i++) { + struct touch_slot *slot = &touch_slots[i]; + slot->tracking_id = -1; + } + register_displaychangelistener(&ddc->dcl); ddc->mouse_mode_notifier.notify = dbus_mouse_mode_change; qemu_add_mouse_mode_change_notifier(&ddc->mouse_mode_notifier); diff --git a/ui/dbus-display1.xml b/ui/dbus-display1.xml index c3b2293376..cc0c9b68bf 100644 --- a/ui/dbus-display1.xml +++ b/ui/dbus-display1.xml @@ -39,8 +39,9 @@ "Text" (see :dbus:prop:`Type` and other properties). Interactions with a console may be done with - :dbus:iface:`org.qemu.Display1.Keyboard` and - :dbus:iface:`org.qemu.Display1.Mouse` interfaces when available. + :dbus:iface:`org.qemu.Display1.Keyboard`, + :dbus:iface:`org.qemu.Display1.Mouse` and + :dbus:iface:`org.qemu.Display1.MultiTouch` interfaces when available. --> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -760,7 +782,13 @@ The current handler, if any, will be replaced. --> + + + + + + + + + + + + @@ -171,7 +200,8 @@ + + + + + + + + From 09b4c198b80c3f5c9c051bc8d8935668cdd206e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 6 Jun 2023 15:56:46 +0400 Subject: [PATCH 0227/1353] console/win32: allocate shareable display surface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce qemu_win32_map_alloc() and qemu_win32_map_free() to allocate shared memory mapping. The handle can be used to share the mapping with another process. Teach qemu_create_displaysurface() to allocate shared memory. Following patches will introduce other places for shared memory allocation. Other patches for -display dbus will share the memory when possible with the client, to avoid expensive memory copy between the processes. Signed-off-by: Marc-André Lureau Message-Id: <20230606115658.677673-10-marcandre.lureau@redhat.com> --- include/sysemu/os-win32.h | 3 ++ include/ui/console.h | 8 ++++++ ui/console.c | 59 ++++++++++++++++++++++++++++++++++----- ui/qemu-pixman.c | 1 + ui/trace-events | 2 +- util/oslib-win32.c | 33 ++++++++++++++++++++++ util/trace-events | 4 +++ 7 files changed, 102 insertions(+), 8 deletions(-) diff --git a/include/sysemu/os-win32.h b/include/sysemu/os-win32.h index 65f6c9ea57..91aa0d7ec0 100644 --- a/include/sysemu/os-win32.h +++ b/include/sysemu/os-win32.h @@ -263,6 +263,9 @@ EXCEPTION_DISPOSITION win32_close_exception_handler(struct _EXCEPTION_RECORD*, void*, struct _CONTEXT*, void*); +void *qemu_win32_map_alloc(size_t size, HANDLE *h, Error **errp); +void qemu_win32_map_free(void *ptr, HANDLE h, Error **errp); + #ifdef __cplusplus } #endif diff --git a/include/ui/console.h b/include/ui/console.h index 2093e2a3ba..2ab0c7112a 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -143,6 +143,10 @@ typedef struct DisplaySurface { GLenum gltype; GLuint texture; #endif +#ifdef WIN32 + HANDLE handle; + uint32_t handle_offset; +#endif } DisplaySurface; typedef struct QemuUIInfo { @@ -329,6 +333,10 @@ DisplaySurface *qemu_create_displaysurface_from(int width, int height, DisplaySurface *qemu_create_displaysurface_pixman(pixman_image_t *image); DisplaySurface *qemu_create_placeholder_surface(int w, int h, const char *msg); +#ifdef WIN32 +void qemu_displaysurface_win32_set_handle(DisplaySurface *surface, + HANDLE h, uint32_t offset); +#endif PixelFormat qemu_default_pixelformat(int bpp); DisplaySurface *qemu_create_displaysurface(int width, int height); diff --git a/ui/console.c b/ui/console.c index cfaa43e970..4957110723 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1513,18 +1513,59 @@ static QemuConsole *new_console(DisplayState *ds, console_type_t console_type, return s; } +#ifdef WIN32 +void qemu_displaysurface_win32_set_handle(DisplaySurface *surface, + HANDLE h, uint32_t offset) +{ + assert(!surface->handle); + + surface->handle = h; + surface->handle_offset = offset; +} + +static void +win32_pixman_image_destroy(pixman_image_t *image, void *data) +{ + DisplaySurface *surface = data; + + if (!surface->handle) { + return; + } + + assert(surface->handle_offset == 0); + + qemu_win32_map_free( + pixman_image_get_data(surface->image), + surface->handle, + &error_warn + ); +} +#endif + DisplaySurface *qemu_create_displaysurface(int width, int height) { - DisplaySurface *surface = g_new0(DisplaySurface, 1); + DisplaySurface *surface; + void *bits = NULL; +#ifdef WIN32 + HANDLE handle = NULL; +#endif - trace_displaysurface_create(surface, width, height); - surface->format = PIXMAN_x8r8g8b8; - surface->image = pixman_image_create_bits(surface->format, - width, height, - NULL, width * 4); - assert(surface->image != NULL); + trace_displaysurface_create(width, height); + +#ifdef WIN32 + bits = qemu_win32_map_alloc(width * height * 4, &handle, &error_abort); +#endif + + surface = qemu_create_displaysurface_from( + width, height, + PIXMAN_x8r8g8b8, + width * 4, bits + ); surface->flags = QEMU_ALLOCATED_FLAG; +#ifdef WIN32 + qemu_displaysurface_win32_set_handle(surface, handle, 0); +#endif return surface; } @@ -1540,6 +1581,10 @@ DisplaySurface *qemu_create_displaysurface_from(int width, int height, width, height, (void *)data, linesize); assert(surface->image != NULL); +#ifdef WIN32 + pixman_image_set_destroy_function(surface->image, + win32_pixman_image_destroy, surface); +#endif return surface; } diff --git a/ui/qemu-pixman.c b/ui/qemu-pixman.c index 3ab7e2e958..e4f024a85e 100644 --- a/ui/qemu-pixman.c +++ b/ui/qemu-pixman.c @@ -6,6 +6,7 @@ #include "qemu/osdep.h" #include "ui/console.h" #include "standard-headers/drm/drm_fourcc.h" +#include "trace.h" PixelFormat qemu_pixelformat_from_pixman(pixman_format_code_t format) { diff --git a/ui/trace-events b/ui/trace-events index 138a09cc03..a71895c479 100644 --- a/ui/trace-events +++ b/ui/trace-events @@ -9,7 +9,7 @@ console_putchar_unhandled(int ch) "unhandled escape character '%c'" console_txt_new(int w, int h) "%dx%d" console_select(int nr) "%d" console_refresh(int interval) "interval %d ms" -displaysurface_create(void *display_surface, int w, int h) "surface=%p, %dx%d" +displaysurface_create(int w, int h) "%dx%d" displaysurface_create_from(void *display_surface, int w, int h, uint32_t format) "surface=%p, %dx%d, format 0x%x" displaysurface_create_pixman(void *display_surface) "surface=%p" displaysurface_free(void *display_surface) "surface=%p" diff --git a/util/oslib-win32.c b/util/oslib-win32.c index fafbab80b4..429542face 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -835,3 +835,36 @@ int qemu_msync(void *addr, size_t length, int fd) */ return qemu_fdatasync(fd); } + +void *qemu_win32_map_alloc(size_t size, HANDLE *h, Error **errp) +{ + void *bits; + + trace_win32_map_alloc(size); + + *h = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, + size, NULL); + if (*h == NULL) { + error_setg_win32(errp, GetLastError(), "Failed to CreateFileMapping"); + return NULL; + } + + bits = MapViewOfFile(*h, FILE_MAP_ALL_ACCESS, 0, 0, size); + if (bits == NULL) { + error_setg_win32(errp, GetLastError(), "Failed to MapViewOfFile"); + CloseHandle(*h); + return NULL; + } + + return bits; +} + +void qemu_win32_map_free(void *ptr, HANDLE h, Error **errp) +{ + trace_win32_map_free(ptr, h); + + if (UnmapViewOfFile(ptr) == 0) { + error_setg_win32(errp, GetLastError(), "Failed to UnmapViewOfFile"); + } + CloseHandle(h); +} diff --git a/util/trace-events b/util/trace-events index 3f7e766683..49a4962e18 100644 --- a/util/trace-events +++ b/util/trace-events @@ -52,6 +52,10 @@ qemu_anon_ram_alloc(size_t size, void *ptr) "size %zu ptr %p" qemu_vfree(void *ptr) "ptr %p" qemu_anon_ram_free(void *ptr, size_t size) "ptr %p size %zu" +# oslib-win32.c +win32_map_alloc(size_t size) "size:%zd" +win32_map_free(void *ptr, void *h) "ptr:%p handle:%p" + # hbitmap.c hbitmap_iter_skip_words(const void *hb, void *hbi, uint64_t pos, unsigned long cur) "hb %p hbi %p pos %"PRId64" cur 0x%lx" hbitmap_reset(void *hb, uint64_t start, uint64_t count, uint64_t sbit, uint64_t ebit) "hb %p items %"PRIu64",%"PRIu64" bits %"PRIu64"..%"PRIu64 From 9462ff4695aa0d086fd63f7f2efafe5a05f2a243 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 6 Jun 2023 15:56:47 +0400 Subject: [PATCH 0228/1353] virtio-gpu/win32: allocate shareable 2d resources/images MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allocate pixman bits for scanouts with qemu_win32_map_alloc() so we can set a shareable handle on the associated display surface. Note: when bits are provided to pixman_image_create_bits(), you must also give the rowstride (the argument is ignored when bits is NULL) Signed-off-by: Marc-André Lureau Message-Id: <20230606115658.677673-11-marcandre.lureau@redhat.com> --- hw/display/virtio-gpu.c | 46 +++++++++++++++++++++++++++++++--- include/hw/virtio/virtio-gpu.h | 3 +++ 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 1f8a5b16c6..347e17d490 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -258,6 +258,16 @@ static uint32_t calc_image_hostmem(pixman_format_code_t pformat, return height * stride; } +#ifdef WIN32 +static void +win32_pixman_image_destroy(pixman_image_t *image, void *data) +{ + HANDLE handle = data; + + qemu_win32_map_free(pixman_image_get_data(image), handle, &error_warn); +} +#endif + static void virtio_gpu_resource_create_2d(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd) { @@ -304,12 +314,27 @@ static void virtio_gpu_resource_create_2d(VirtIOGPU *g, res->hostmem = calc_image_hostmem(pformat, c2d.width, c2d.height); if (res->hostmem + g->hostmem < g->conf_max_hostmem) { + void *bits = NULL; +#ifdef WIN32 + bits = qemu_win32_map_alloc(res->hostmem, &res->handle, &error_warn); + if (!bits) { + goto end; + } +#endif res->image = pixman_image_create_bits(pformat, c2d.width, c2d.height, - NULL, 0); + bits, res->hostmem / c2d.height); +#ifdef WIN32 + if (res->image) { + pixman_image_set_destroy_function(res->image, win32_pixman_image_destroy, res->handle); + } +#endif } +#ifdef WIN32 +end: +#endif if (!res->image) { qemu_log_mask(LOG_GUEST_ERROR, "%s: resource creation failed %d %d %d\n", @@ -685,6 +710,9 @@ static void virtio_gpu_do_set_scanout(VirtIOGPU *g, *error = VIRTIO_GPU_RESP_ERR_UNSPEC; return; } +#ifdef WIN32 + qemu_displaysurface_win32_set_handle(scanout->ds, res->handle, fb->offset); +#endif pixman_image_unref(rect); dpy_gfx_replace_surface(g->parent_obj.scanout[scanout_id].con, @@ -1228,6 +1256,7 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size, struct virtio_gpu_simple_resource *res; struct virtio_gpu_scanout *scanout; uint32_t resource_id, pformat; + void *bits = NULL; int i; g->hostmem = 0; @@ -1252,15 +1281,23 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size, g_free(res); return -EINVAL; } + + res->hostmem = calc_image_hostmem(pformat, res->width, res->height); +#ifdef WIN32 + bits = qemu_win32_map_alloc(res->hostmem, &res->handle, &error_warn); + if (!bits) { + g_free(res); + return -EINVAL; + } +#endif res->image = pixman_image_create_bits(pformat, res->width, res->height, - NULL, 0); + bits, res->hostmem / res->height); if (!res->image) { g_free(res); return -EINVAL; } - res->hostmem = calc_image_hostmem(pformat, res->width, res->height); res->addrs = g_new(uint64_t, res->iov_cnt); res->iov = g_new(struct iovec, res->iov_cnt); @@ -1321,6 +1358,9 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size, if (!scanout->ds) { return -EINVAL; } +#ifdef WIN32 + qemu_displaysurface_win32_set_handle(scanout->ds, res->handle, 0); +#endif dpy_gfx_replace_surface(scanout->con, scanout->ds); dpy_gfx_update_full(scanout->con); diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 2e28507efe..7a5f8056ea 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -48,6 +48,9 @@ struct virtio_gpu_simple_resource { unsigned int iov_cnt; uint32_t scanout_bitmask; pixman_image_t *image; +#ifdef WIN32 + HANDLE handle; +#endif uint64_t hostmem; uint64_t blob_size; From 48dddba1763b2134e81ae6765b19184fd907f142 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 6 Jun 2023 15:56:48 +0400 Subject: [PATCH 0229/1353] ui/dbus: use shared memory when possible on win32 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the display surface has an associated HANDLE, we can duplicate it to the client process and let it map the memory to avoid expensive copies. Introduce two new win32-specific methods ScanoutMap and UpdateMap. The first is used to inform the listener about the a shared map availability, and the second for display updates. Signed-off-by: Marc-André Lureau Message-Id: <20230606115658.677673-12-marcandre.lureau@redhat.com> --- ui/dbus-display1.xml | 48 ++++++++++++- ui/dbus-listener.c | 165 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 208 insertions(+), 5 deletions(-) diff --git a/ui/dbus-display1.xml b/ui/dbus-display1.xml index 06e8779c04..7233286b28 100644 --- a/ui/dbus-display1.xml +++ b/ui/dbus-display1.xml @@ -370,9 +370,7 @@ - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index 556419f159..822f2a72e5 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -726,8 +726,18 @@ static void loongarch_cpu_class_init(ObjectClass *c, void *data) #endif } +static gchar *loongarch32_gdb_arch_name(CPUState *cs) +{ + return g_strdup("loongarch32"); +} + static void loongarch32_cpu_class_init(ObjectClass *c, void *data) { + CPUClass *cc = CPU_CLASS(c); + + cc->gdb_num_core_regs = 35; + cc->gdb_core_xml_file = "loongarch-base32.xml"; + cc->gdb_arch_name = loongarch32_gdb_arch_name; } static gchar *loongarch64_gdb_arch_name(CPUState *cs) diff --git a/target/loongarch/gdbstub.c b/target/loongarch/gdbstub.c index 0752fff924..a462e25737 100644 --- a/target/loongarch/gdbstub.c +++ b/target/loongarch/gdbstub.c @@ -34,16 +34,25 @@ int loongarch_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) { LoongArchCPU *cpu = LOONGARCH_CPU(cs); CPULoongArchState *env = &cpu->env; + uint64_t val; if (0 <= n && n < 32) { - return gdb_get_regl(mem_buf, env->gpr[n]); + val = env->gpr[n]; } else if (n == 32) { /* orig_a0 */ - return gdb_get_regl(mem_buf, 0); + val = 0; } else if (n == 33) { - return gdb_get_regl(mem_buf, env->pc); + val = env->pc; } else if (n == 34) { - return gdb_get_regl(mem_buf, env->CSR_BADV); + val = env->CSR_BADV; + } + + if (0 <= n && n <= 34) { + if (is_la64(env)) { + return gdb_get_reg64(mem_buf, val); + } else { + return gdb_get_reg32(mem_buf, val); + } } return 0; } @@ -52,15 +61,24 @@ int loongarch_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) { LoongArchCPU *cpu = LOONGARCH_CPU(cs); CPULoongArchState *env = &cpu->env; - target_ulong tmp = ldtul_p(mem_buf); + target_ulong tmp; + int read_length; int length = 0; + if (is_la64(env)) { + tmp = ldq_p(mem_buf); + read_length = 8; + } else { + tmp = ldl_p(mem_buf); + read_length = 4; + } + if (0 <= n && n < 32) { env->gpr[n] = tmp; - length = sizeof(target_ulong); + length = read_length; } else if (n == 33) { env->pc = tmp; - length = sizeof(target_ulong); + length = read_length; } return length; } From e70bb6fb9afd0c560b3200b569d9d47239448c30 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Tue, 22 Aug 2023 09:13:47 +0200 Subject: [PATCH 1176/1353] target/loongarch: Support LoongArch32 TLB entry The TLB entry of LA32 lacks NR, NX and RPLV and they are hardwired to zero in LoongArch32. Signed-off-by: Jiajie Chen Reviewed-by: Richard Henderson Signed-off-by: Song Gao Message-ID: <20230822032724.1353391-2-gaosong@loongson.cn> Message-Id: <20230822071405.35386-2-philmd@linaro.org> --- target/loongarch/cpu-csr.h | 9 +++++---- target/loongarch/tlb_helper.c | 17 ++++++++++++----- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/target/loongarch/cpu-csr.h b/target/loongarch/cpu-csr.h index f8f24032cb..48ed2e0632 100644 --- a/target/loongarch/cpu-csr.h +++ b/target/loongarch/cpu-csr.h @@ -66,10 +66,11 @@ FIELD(TLBENTRY, D, 1, 1) FIELD(TLBENTRY, PLV, 2, 2) FIELD(TLBENTRY, MAT, 4, 2) FIELD(TLBENTRY, G, 6, 1) -FIELD(TLBENTRY, PPN, 12, 36) -FIELD(TLBENTRY, NR, 61, 1) -FIELD(TLBENTRY, NX, 62, 1) -FIELD(TLBENTRY, RPLV, 63, 1) +FIELD(TLBENTRY_32, PPN, 8, 24) +FIELD(TLBENTRY_64, PPN, 12, 36) +FIELD(TLBENTRY_64, NR, 61, 1) +FIELD(TLBENTRY_64, NX, 62, 1) +FIELD(TLBENTRY_64, RPLV, 63, 1) #define LOONGARCH_CSR_ASID 0x18 /* Address space identifier */ FIELD(CSR_ASID, ASID, 0, 10) diff --git a/target/loongarch/tlb_helper.c b/target/loongarch/tlb_helper.c index 6e00190547..cef10e2257 100644 --- a/target/loongarch/tlb_helper.c +++ b/target/loongarch/tlb_helper.c @@ -48,10 +48,17 @@ static int loongarch_map_tlb_entry(CPULoongArchState *env, hwaddr *physical, tlb_v = FIELD_EX64(tlb_entry, TLBENTRY, V); tlb_d = FIELD_EX64(tlb_entry, TLBENTRY, D); tlb_plv = FIELD_EX64(tlb_entry, TLBENTRY, PLV); - tlb_ppn = FIELD_EX64(tlb_entry, TLBENTRY, PPN); - tlb_nx = FIELD_EX64(tlb_entry, TLBENTRY, NX); - tlb_nr = FIELD_EX64(tlb_entry, TLBENTRY, NR); - tlb_rplv = FIELD_EX64(tlb_entry, TLBENTRY, RPLV); + if (is_la64(env)) { + tlb_ppn = FIELD_EX64(tlb_entry, TLBENTRY_64, PPN); + tlb_nx = FIELD_EX64(tlb_entry, TLBENTRY_64, NX); + tlb_nr = FIELD_EX64(tlb_entry, TLBENTRY_64, NR); + tlb_rplv = FIELD_EX64(tlb_entry, TLBENTRY_64, RPLV); + } else { + tlb_ppn = FIELD_EX64(tlb_entry, TLBENTRY_32, PPN); + tlb_nx = 0; + tlb_nr = 0; + tlb_rplv = 0; + } /* Check access rights */ if (!tlb_v) { @@ -79,7 +86,7 @@ static int loongarch_map_tlb_entry(CPULoongArchState *env, hwaddr *physical, * tlb_entry contains ppn[47:12] while 16KiB ppn is [47:15] * need adjust. */ - *physical = (tlb_ppn << R_TLBENTRY_PPN_SHIFT) | + *physical = (tlb_ppn << R_TLBENTRY_64_PPN_SHIFT) | (address & MAKE_64BIT_MASK(0, tlb_ps)); *prot = PAGE_READ; if (tlb_d) { From eece5764092063f3f7a091a8b42935e9cb1a37ff Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Tue, 22 Aug 2023 09:13:48 +0200 Subject: [PATCH 1177/1353] target/loongarch: Support LoongArch32 DMW LA32 uses a different encoding for CSR.DMW and a new direct mapping mechanism. Signed-off-by: Jiajie Chen Reviewed-by: Richard Henderson Signed-off-by: Song Gao Message-ID: <20230822032724.1353391-3-gaosong@loongson.cn> Message-Id: <20230822071405.35386-3-philmd@linaro.org> --- target/loongarch/cpu-csr.h | 7 +++---- target/loongarch/tlb_helper.c | 26 +++++++++++++++++++++++--- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/target/loongarch/cpu-csr.h b/target/loongarch/cpu-csr.h index 48ed2e0632..b93f99a9ef 100644 --- a/target/loongarch/cpu-csr.h +++ b/target/loongarch/cpu-csr.h @@ -188,10 +188,9 @@ FIELD(CSR_DMW, PLV1, 1, 1) FIELD(CSR_DMW, PLV2, 2, 1) FIELD(CSR_DMW, PLV3, 3, 1) FIELD(CSR_DMW, MAT, 4, 2) -FIELD(CSR_DMW, VSEG, 60, 4) - -#define dmw_va2pa(va) \ - (va & MAKE_64BIT_MASK(0, TARGET_VIRT_ADDR_SPACE_BITS)) +FIELD(CSR_DMW_32, PSEG, 25, 3) +FIELD(CSR_DMW_32, VSEG, 29, 3) +FIELD(CSR_DMW_64, VSEG, 60, 4) /* Debug CSRs */ #define LOONGARCH_CSR_DBG 0x500 /* debug config */ diff --git a/target/loongarch/tlb_helper.c b/target/loongarch/tlb_helper.c index cef10e2257..1f8e7911c7 100644 --- a/target/loongarch/tlb_helper.c +++ b/target/loongarch/tlb_helper.c @@ -173,6 +173,18 @@ static int loongarch_map_address(CPULoongArchState *env, hwaddr *physical, return TLBRET_NOMATCH; } +static hwaddr dmw_va2pa(CPULoongArchState *env, target_ulong va, + target_ulong dmw) +{ + if (is_la64(env)) { + return va & TARGET_VIRT_MASK; + } else { + uint32_t pseg = FIELD_EX32(dmw, CSR_DMW_32, PSEG); + return (va & MAKE_64BIT_MASK(0, R_CSR_DMW_32_VSEG_SHIFT)) | \ + (pseg << R_CSR_DMW_32_VSEG_SHIFT); + } +} + static int get_physical_address(CPULoongArchState *env, hwaddr *physical, int *prot, target_ulong address, MMUAccessType access_type, int mmu_idx) @@ -192,12 +204,20 @@ static int get_physical_address(CPULoongArchState *env, hwaddr *physical, } plv = kernel_mode | (user_mode << R_CSR_DMW_PLV3_SHIFT); - base_v = address >> R_CSR_DMW_VSEG_SHIFT; + if (is_la64(env)) { + base_v = address >> R_CSR_DMW_64_VSEG_SHIFT; + } else { + base_v = address >> R_CSR_DMW_32_VSEG_SHIFT; + } /* Check direct map window */ for (int i = 0; i < 4; i++) { - base_c = FIELD_EX64(env->CSR_DMW[i], CSR_DMW, VSEG); + if (is_la64(env)) { + base_c = FIELD_EX64(env->CSR_DMW[i], CSR_DMW_64, VSEG); + } else { + base_c = FIELD_EX64(env->CSR_DMW[i], CSR_DMW_32, VSEG); + } if ((plv & env->CSR_DMW[i]) && (base_c == base_v)) { - *physical = dmw_va2pa(address); + *physical = dmw_va2pa(env, address, env->CSR_DMW[i]); *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; return TLBRET_MATCH; } From 50fffcc49b0e68f53de5c1eaf21ec07819540d5a Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Tue, 22 Aug 2023 09:13:49 +0200 Subject: [PATCH 1178/1353] target/loongarch: Support LoongArch32 VPPN VPPN of TLBEHI/TLBREHI is limited to 19 bits in LA32. Signed-off-by: Jiajie Chen Reviewed-by: Richard Henderson Signed-off-by: Song Gao Message-ID: <20230822032724.1353391-4-gaosong@loongson.cn> Message-Id: <20230822071405.35386-4-philmd@linaro.org> --- target/loongarch/cpu-csr.h | 6 ++++-- target/loongarch/tlb_helper.c | 23 ++++++++++++++++++----- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/target/loongarch/cpu-csr.h b/target/loongarch/cpu-csr.h index b93f99a9ef..c59d7a9fcb 100644 --- a/target/loongarch/cpu-csr.h +++ b/target/loongarch/cpu-csr.h @@ -57,7 +57,8 @@ FIELD(CSR_TLBIDX, PS, 24, 6) FIELD(CSR_TLBIDX, NE, 31, 1) #define LOONGARCH_CSR_TLBEHI 0x11 /* TLB EntryHi */ -FIELD(CSR_TLBEHI, VPPN, 13, 35) +FIELD(CSR_TLBEHI_32, VPPN, 13, 19) +FIELD(CSR_TLBEHI_64, VPPN, 13, 35) #define LOONGARCH_CSR_TLBELO0 0x12 /* TLB EntryLo0 */ #define LOONGARCH_CSR_TLBELO1 0x13 /* TLB EntryLo1 */ @@ -164,7 +165,8 @@ FIELD(CSR_TLBRERA, PC, 2, 62) #define LOONGARCH_CSR_TLBRELO1 0x8d /* TLB refill entrylo1 */ #define LOONGARCH_CSR_TLBREHI 0x8e /* TLB refill entryhi */ FIELD(CSR_TLBREHI, PS, 0, 6) -FIELD(CSR_TLBREHI, VPPN, 13, 35) +FIELD(CSR_TLBREHI_32, VPPN, 13, 19) +FIELD(CSR_TLBREHI_64, VPPN, 13, 35) #define LOONGARCH_CSR_TLBRPRMD 0x8f /* TLB refill mode info */ FIELD(CSR_TLBRPRMD, PPLV, 0, 2) FIELD(CSR_TLBRPRMD, PIE, 2, 1) diff --git a/target/loongarch/tlb_helper.c b/target/loongarch/tlb_helper.c index 1f8e7911c7..c8b8b0497f 100644 --- a/target/loongarch/tlb_helper.c +++ b/target/loongarch/tlb_helper.c @@ -300,8 +300,13 @@ static void raise_mmu_exception(CPULoongArchState *env, target_ulong address, if (tlb_error == TLBRET_NOMATCH) { env->CSR_TLBRBADV = address; - env->CSR_TLBREHI = FIELD_DP64(env->CSR_TLBREHI, CSR_TLBREHI, VPPN, - extract64(address, 13, 35)); + if (is_la64(env)) { + env->CSR_TLBREHI = FIELD_DP64(env->CSR_TLBREHI, CSR_TLBREHI_64, + VPPN, extract64(address, 13, 35)); + } else { + env->CSR_TLBREHI = FIELD_DP64(env->CSR_TLBREHI, CSR_TLBREHI_32, + VPPN, extract64(address, 13, 19)); + } } else { if (!FIELD_EX64(env->CSR_DBG, CSR_DBG, DST)) { env->CSR_BADV = address; @@ -366,12 +371,20 @@ static void fill_tlb_entry(CPULoongArchState *env, int index) if (FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) { csr_ps = FIELD_EX64(env->CSR_TLBREHI, CSR_TLBREHI, PS); - csr_vppn = FIELD_EX64(env->CSR_TLBREHI, CSR_TLBREHI, VPPN); + if (is_la64(env)) { + csr_vppn = FIELD_EX64(env->CSR_TLBREHI, CSR_TLBREHI_64, VPPN); + } else { + csr_vppn = FIELD_EX64(env->CSR_TLBREHI, CSR_TLBREHI_32, VPPN); + } lo0 = env->CSR_TLBRELO0; lo1 = env->CSR_TLBRELO1; } else { csr_ps = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, PS); - csr_vppn = FIELD_EX64(env->CSR_TLBEHI, CSR_TLBEHI, VPPN); + if (is_la64(env)) { + csr_vppn = FIELD_EX64(env->CSR_TLBEHI, CSR_TLBEHI_64, VPPN); + } else { + csr_vppn = FIELD_EX64(env->CSR_TLBEHI, CSR_TLBEHI_32, VPPN); + } lo0 = env->CSR_TLBELO0; lo1 = env->CSR_TLBELO1; } @@ -491,7 +504,7 @@ void helper_tlbfill(CPULoongArchState *env) if (pagesize == stlb_ps) { /* Only write into STLB bits [47:13] */ - address = entryhi & ~MAKE_64BIT_MASK(0, R_CSR_TLBEHI_VPPN_SHIFT); + address = entryhi & ~MAKE_64BIT_MASK(0, R_CSR_TLBEHI_64_VPPN_SHIFT); /* Choose one set ramdomly */ set = get_random_tlb(0, 7); From 3966582099b0c94b45a2ea0fd8afb0dcac8ad292 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Tue, 22 Aug 2023 09:13:50 +0200 Subject: [PATCH 1179/1353] target/loongarch: Add LA64 & VA32 to DisasContext Add LA64 and VA32(32-bit Virtual Address) to DisasContext to allow the translator to reject doubleword instructions in LA32 mode for example. Signed-off-by: Jiajie Chen Reviewed-by: Richard Henderson Signed-off-by: Song Gao Message-ID: <20230822032724.1353391-5-gaosong@loongson.cn> Message-Id: <20230822071405.35386-5-philmd@linaro.org> --- target/loongarch/cpu.h | 13 +++++++++++++ target/loongarch/translate.c | 3 +++ target/loongarch/translate.h | 2 ++ 3 files changed, 18 insertions(+) diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h index b8af491041..72109095e4 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -432,6 +432,17 @@ static inline bool is_la64(CPULoongArchState *env) return FIELD_EX32(env->cpucfg[1], CPUCFG1, ARCH) == CPUCFG1_ARCH_LA64; } +static inline bool is_va32(CPULoongArchState *env) +{ + /* VA32 if !LA64 or VA32L[1-3] */ + bool va32 = !is_la64(env); + uint64_t plv = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PLV); + if (plv >= 1 && (FIELD_EX64(env->CSR_MISC, CSR_MISC, VA32) & (1 << plv))) { + va32 = true; + } + return va32; +} + /* * LoongArch CPUs hardware flags. */ @@ -439,6 +450,7 @@ static inline bool is_la64(CPULoongArchState *env) #define HW_FLAGS_CRMD_PG R_CSR_CRMD_PG_MASK /* 0x10 */ #define HW_FLAGS_EUEN_FPE 0x04 #define HW_FLAGS_EUEN_SXE 0x08 +#define HW_FLAGS_VA32 0x20 static inline void cpu_get_tb_cpu_state(CPULoongArchState *env, vaddr *pc, uint64_t *cs_base, uint32_t *flags) @@ -448,6 +460,7 @@ static inline void cpu_get_tb_cpu_state(CPULoongArchState *env, vaddr *pc, *flags = env->CSR_CRMD & (R_CSR_CRMD_PLV_MASK | R_CSR_CRMD_PG_MASK); *flags |= FIELD_EX64(env->CSR_EUEN, CSR_EUEN, FPE) * HW_FLAGS_EUEN_FPE; *flags |= FIELD_EX64(env->CSR_EUEN, CSR_EUEN, SXE) * HW_FLAGS_EUEN_SXE; + *flags |= is_va32(env) * HW_FLAGS_VA32; } void loongarch_cpu_list(void); diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index 3146a2d4ac..ac847745df 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -119,6 +119,9 @@ static void loongarch_tr_init_disas_context(DisasContextBase *dcbase, ctx->vl = LSX_LEN; } + ctx->la64 = is_la64(env); + ctx->va32 = (ctx->base.tb->flags & HW_FLAGS_VA32) != 0; + ctx->zero = tcg_constant_tl(0); } diff --git a/target/loongarch/translate.h b/target/loongarch/translate.h index 7f60090580..b6fa5df82d 100644 --- a/target/loongarch/translate.h +++ b/target/loongarch/translate.h @@ -33,6 +33,8 @@ typedef struct DisasContext { uint16_t plv; int vl; /* Vector length */ TCGv zero; + bool la64; /* LoongArch64 mode */ + bool va32; /* 32-bit virtual address */ } DisasContext; void generate_exception(DisasContext *ctx, int excp); From 34423c01941928974f4854bc23a949789154fee7 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Tue, 22 Aug 2023 09:13:51 +0200 Subject: [PATCH 1180/1353] target/loongarch: Extract make_address_x() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jiajie Chen Co-authored-by: Richard Henderson Reviewed-by: Richard Henderson Signed-off-by: Song Gao Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20230822032724.1353391-6-gaosong@loongson.cn> [PMD: Extract helper from bigger patch] Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20230822071405.35386-6-philmd@linaro.org> --- .../loongarch/insn_trans/trans_fmemory.c.inc | 18 ++++++------------ target/loongarch/insn_trans/trans_lsx.c.inc | 6 ++---- target/loongarch/insn_trans/trans_memory.c.inc | 6 ++---- target/loongarch/translate.c | 12 ++++++++++++ 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/target/loongarch/insn_trans/trans_fmemory.c.inc b/target/loongarch/insn_trans/trans_fmemory.c.inc index 91c09fb6d9..88ad209338 100644 --- a/target/loongarch/insn_trans/trans_fmemory.c.inc +++ b/target/loongarch/insn_trans/trans_fmemory.c.inc @@ -57,8 +57,7 @@ static bool gen_floadx(DisasContext *ctx, arg_frr *a, MemOp mop) CHECK_FPE; - addr = tcg_temp_new(); - tcg_gen_add_tl(addr, src1, src2); + addr = make_address_x(ctx, src1, src2); tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, mop); maybe_nanbox_load(dest, mop); set_fpr(a->fd, dest); @@ -75,8 +74,7 @@ static bool gen_fstorex(DisasContext *ctx, arg_frr *a, MemOp mop) CHECK_FPE; - addr = tcg_temp_new(); - tcg_gen_add_tl(addr, src1, src2); + addr = make_address_x(ctx, src1, src2); tcg_gen_qemu_st_tl(src3, addr, ctx->mem_idx, mop); return true; @@ -91,9 +89,8 @@ static bool gen_fload_gt(DisasContext *ctx, arg_frr *a, MemOp mop) CHECK_FPE; - addr = tcg_temp_new(); gen_helper_asrtgt_d(cpu_env, src1, src2); - tcg_gen_add_tl(addr, src1, src2); + addr = make_address_x(ctx, src1, src2); tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, mop); maybe_nanbox_load(dest, mop); set_fpr(a->fd, dest); @@ -110,9 +107,8 @@ static bool gen_fstore_gt(DisasContext *ctx, arg_frr *a, MemOp mop) CHECK_FPE; - addr = tcg_temp_new(); gen_helper_asrtgt_d(cpu_env, src1, src2); - tcg_gen_add_tl(addr, src1, src2); + addr = make_address_x(ctx, src1, src2); tcg_gen_qemu_st_tl(src3, addr, ctx->mem_idx, mop); return true; @@ -127,9 +123,8 @@ static bool gen_fload_le(DisasContext *ctx, arg_frr *a, MemOp mop) CHECK_FPE; - addr = tcg_temp_new(); gen_helper_asrtle_d(cpu_env, src1, src2); - tcg_gen_add_tl(addr, src1, src2); + addr = make_address_x(ctx, src1, src2); tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, mop); maybe_nanbox_load(dest, mop); set_fpr(a->fd, dest); @@ -146,9 +141,8 @@ static bool gen_fstore_le(DisasContext *ctx, arg_frr *a, MemOp mop) CHECK_FPE; - addr = tcg_temp_new(); gen_helper_asrtle_d(cpu_env, src1, src2); - tcg_gen_add_tl(addr, src1, src2); + addr = make_address_x(ctx, src1, src2); tcg_gen_qemu_st_tl(src3, addr, ctx->mem_idx, mop); return true; diff --git a/target/loongarch/insn_trans/trans_lsx.c.inc b/target/loongarch/insn_trans/trans_lsx.c.inc index 68779daff6..875cb7d51d 100644 --- a/target/loongarch/insn_trans/trans_lsx.c.inc +++ b/target/loongarch/insn_trans/trans_lsx.c.inc @@ -4315,14 +4315,13 @@ static bool trans_vldx(DisasContext *ctx, arg_vrr *a) CHECK_SXE; - addr = tcg_temp_new(); src1 = gpr_src(ctx, a->rj, EXT_NONE); src2 = gpr_src(ctx, a->rk, EXT_NONE); val = tcg_temp_new_i128(); rl = tcg_temp_new_i64(); rh = tcg_temp_new_i64(); - tcg_gen_add_tl(addr, src1, src2); + addr = make_address_x(ctx, src1, src2); tcg_gen_qemu_ld_i128(val, addr, ctx->mem_idx, MO_128 | MO_TE); tcg_gen_extr_i128_i64(rl, rh, val); set_vreg64(rh, a->vd, 1); @@ -4339,14 +4338,13 @@ static bool trans_vstx(DisasContext *ctx, arg_vrr *a) CHECK_SXE; - addr = tcg_temp_new(); src1 = gpr_src(ctx, a->rj, EXT_NONE); src2 = gpr_src(ctx, a->rk, EXT_NONE); val = tcg_temp_new_i128(); ah = tcg_temp_new_i64(); al = tcg_temp_new_i64(); - tcg_gen_add_tl(addr, src1, src2); + addr = make_address_x(ctx, src1, src2); get_vreg64(ah, a->vd, 1); get_vreg64(al, a->vd, 0); tcg_gen_concat_i64_i128(val, al, ah); diff --git a/target/loongarch/insn_trans/trans_memory.c.inc b/target/loongarch/insn_trans/trans_memory.c.inc index 75cfdf59ad..ccebd0a4e0 100644 --- a/target/loongarch/insn_trans/trans_memory.c.inc +++ b/target/loongarch/insn_trans/trans_memory.c.inc @@ -39,9 +39,8 @@ static bool gen_loadx(DisasContext *ctx, arg_rrr *a, MemOp mop) TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); - TCGv addr = tcg_temp_new(); + TCGv addr = make_address_x(ctx, src1, src2); - tcg_gen_add_tl(addr, src1, src2); tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, mop); gen_set_gpr(a->rd, dest, EXT_NONE); @@ -53,9 +52,8 @@ static bool gen_storex(DisasContext *ctx, arg_rrr *a, MemOp mop) TCGv data = gpr_src(ctx, a->rd, EXT_NONE); TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); - TCGv addr = tcg_temp_new(); + TCGv addr = make_address_x(ctx, src1, src2); - tcg_gen_add_tl(addr, src1, src2); tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, mop); return true; diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index ac847745df..a68a979a55 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -208,6 +208,18 @@ static void set_fpr(int reg_num, TCGv val) offsetof(CPULoongArchState, fpr[reg_num].vreg.D(0))); } +static TCGv make_address_x(DisasContext *ctx, TCGv base, TCGv addend) +{ + TCGv temp = NULL; + + if (addend) { + temp = tcg_temp_new(); + tcg_gen_add_tl(temp, base, addend); + base = temp; + } + return base; +} + #include "decode-insns.c.inc" #include "insn_trans/trans_arith.c.inc" #include "insn_trans/trans_shift.c.inc" From c5af6628f4be5d30800233e59ba3842ca19a12e6 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Tue, 22 Aug 2023 09:13:52 +0200 Subject: [PATCH 1181/1353] target/loongarch: Extract make_address_i() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jiajie Chen Co-authored-by: Richard Henderson Reviewed-by: Richard Henderson Signed-off-by: Song Gao Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20230822032724.1353391-6-gaosong@loongson.cn> [PMD: Extract helper from bigger patch] Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20230822071405.35386-7-philmd@linaro.org> --- .../loongarch/insn_trans/trans_atomic.c.inc | 5 +-- .../loongarch/insn_trans/trans_branch.c.inc | 3 +- .../loongarch/insn_trans/trans_fmemory.c.inc | 12 ++----- target/loongarch/insn_trans/trans_lsx.c.inc | 32 +++++-------------- .../loongarch/insn_trans/trans_memory.c.inc | 28 +++++----------- target/loongarch/translate.c | 6 ++++ 6 files changed, 29 insertions(+), 57 deletions(-) diff --git a/target/loongarch/insn_trans/trans_atomic.c.inc b/target/loongarch/insn_trans/trans_atomic.c.inc index 612709f2a7..fbc081448d 100644 --- a/target/loongarch/insn_trans/trans_atomic.c.inc +++ b/target/loongarch/insn_trans/trans_atomic.c.inc @@ -7,9 +7,8 @@ static bool gen_ll(DisasContext *ctx, arg_rr_i *a, MemOp mop) { TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); - TCGv t0 = tcg_temp_new(); + TCGv t0 = make_address_i(ctx, src1, a->imm); - tcg_gen_addi_tl(t0, src1, a->imm); tcg_gen_qemu_ld_i64(dest, t0, ctx->mem_idx, mop); tcg_gen_st_tl(t0, cpu_env, offsetof(CPULoongArchState, lladdr)); tcg_gen_st_tl(dest, cpu_env, offsetof(CPULoongArchState, llval)); @@ -62,6 +61,8 @@ static bool gen_am(DisasContext *ctx, arg_rrr *a, return false; } + addr = make_address_i(ctx, addr, 0); + func(dest, addr, val, ctx->mem_idx, mop); gen_set_gpr(a->rd, dest, EXT_NONE); diff --git a/target/loongarch/insn_trans/trans_branch.c.inc b/target/loongarch/insn_trans/trans_branch.c.inc index a860f7e733..3ad34bcc05 100644 --- a/target/loongarch/insn_trans/trans_branch.c.inc +++ b/target/loongarch/insn_trans/trans_branch.c.inc @@ -23,7 +23,8 @@ static bool trans_jirl(DisasContext *ctx, arg_jirl *a) TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); - tcg_gen_addi_tl(cpu_pc, src1, a->imm); + TCGv addr = make_address_i(ctx, src1, a->imm); + tcg_gen_mov_tl(cpu_pc, addr); tcg_gen_movi_tl(dest, ctx->base.pc_next + 4); gen_set_gpr(a->rd, dest, EXT_NONE); tcg_gen_lookup_and_goto_ptr(); diff --git a/target/loongarch/insn_trans/trans_fmemory.c.inc b/target/loongarch/insn_trans/trans_fmemory.c.inc index 88ad209338..bd3aba2c49 100644 --- a/target/loongarch/insn_trans/trans_fmemory.c.inc +++ b/target/loongarch/insn_trans/trans_fmemory.c.inc @@ -17,11 +17,7 @@ static bool gen_fload_i(DisasContext *ctx, arg_fr_i *a, MemOp mop) CHECK_FPE; - if (a->imm) { - TCGv temp = tcg_temp_new(); - tcg_gen_addi_tl(temp, addr, a->imm); - addr = temp; - } + addr = make_address_i(ctx, addr, a->imm); tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, mop); maybe_nanbox_load(dest, mop); @@ -37,11 +33,7 @@ static bool gen_fstore_i(DisasContext *ctx, arg_fr_i *a, MemOp mop) CHECK_FPE; - if (a->imm) { - TCGv temp = tcg_temp_new(); - tcg_gen_addi_tl(temp, addr, a->imm); - addr = temp; - } + addr = make_address_i(ctx, addr, a->imm); tcg_gen_qemu_st_tl(src, addr, ctx->mem_idx, mop); diff --git a/target/loongarch/insn_trans/trans_lsx.c.inc b/target/loongarch/insn_trans/trans_lsx.c.inc index 875cb7d51d..50153d6d0b 100644 --- a/target/loongarch/insn_trans/trans_lsx.c.inc +++ b/target/loongarch/insn_trans/trans_lsx.c.inc @@ -4255,7 +4255,7 @@ TRANS(vextrins_d, gen_vv_i, gen_helper_vextrins_d) static bool trans_vld(DisasContext *ctx, arg_vr_i *a) { - TCGv addr, temp; + TCGv addr; TCGv_i64 rl, rh; TCGv_i128 val; @@ -4266,11 +4266,7 @@ static bool trans_vld(DisasContext *ctx, arg_vr_i *a) rl = tcg_temp_new_i64(); rh = tcg_temp_new_i64(); - if (a->imm) { - temp = tcg_temp_new(); - tcg_gen_addi_tl(temp, addr, a->imm); - addr = temp; - } + addr = make_address_i(ctx, addr, a->imm); tcg_gen_qemu_ld_i128(val, addr, ctx->mem_idx, MO_128 | MO_TE); tcg_gen_extr_i128_i64(rl, rh, val); @@ -4282,7 +4278,7 @@ static bool trans_vld(DisasContext *ctx, arg_vr_i *a) static bool trans_vst(DisasContext *ctx, arg_vr_i *a) { - TCGv addr, temp; + TCGv addr; TCGv_i128 val; TCGv_i64 ah, al; @@ -4293,11 +4289,7 @@ static bool trans_vst(DisasContext *ctx, arg_vr_i *a) ah = tcg_temp_new_i64(); al = tcg_temp_new_i64(); - if (a->imm) { - temp = tcg_temp_new(); - tcg_gen_addi_tl(temp, addr, a->imm); - addr = temp; - } + addr = make_address_i(ctx, addr, a->imm); get_vreg64(ah, a->vd, 1); get_vreg64(al, a->vd, 0); @@ -4356,7 +4348,7 @@ static bool trans_vstx(DisasContext *ctx, arg_vrr *a) #define VLDREPL(NAME, MO) \ static bool trans_## NAME (DisasContext *ctx, arg_vr_i *a) \ { \ - TCGv addr, temp; \ + TCGv addr; \ TCGv_i64 val; \ \ CHECK_SXE; \ @@ -4364,11 +4356,7 @@ static bool trans_## NAME (DisasContext *ctx, arg_vr_i *a) \ addr = gpr_src(ctx, a->rj, EXT_NONE); \ val = tcg_temp_new_i64(); \ \ - if (a->imm) { \ - temp = tcg_temp_new(); \ - tcg_gen_addi_tl(temp, addr, a->imm); \ - addr = temp; \ - } \ + addr = make_address_i(ctx, addr, a->imm); \ \ tcg_gen_qemu_ld_i64(val, addr, ctx->mem_idx, MO); \ tcg_gen_gvec_dup_i64(MO, vec_full_offset(a->vd), 16, ctx->vl/8, val); \ @@ -4384,7 +4372,7 @@ VLDREPL(vldrepl_d, MO_64) #define VSTELM(NAME, MO, E) \ static bool trans_## NAME (DisasContext *ctx, arg_vr_ii *a) \ { \ - TCGv addr, temp; \ + TCGv addr; \ TCGv_i64 val; \ \ CHECK_SXE; \ @@ -4392,11 +4380,7 @@ static bool trans_## NAME (DisasContext *ctx, arg_vr_ii *a) \ addr = gpr_src(ctx, a->rj, EXT_NONE); \ val = tcg_temp_new_i64(); \ \ - if (a->imm) { \ - temp = tcg_temp_new(); \ - tcg_gen_addi_tl(temp, addr, a->imm); \ - addr = temp; \ - } \ + addr = make_address_i(ctx, addr, a->imm); \ \ tcg_gen_ld_i64(val, cpu_env, \ offsetof(CPULoongArchState, fpr[a->vd].vreg.E(a->imm2))); \ diff --git a/target/loongarch/insn_trans/trans_memory.c.inc b/target/loongarch/insn_trans/trans_memory.c.inc index ccebd0a4e0..88953f0ab0 100644 --- a/target/loongarch/insn_trans/trans_memory.c.inc +++ b/target/loongarch/insn_trans/trans_memory.c.inc @@ -8,11 +8,7 @@ static bool gen_load(DisasContext *ctx, arg_rr_i *a, MemOp mop) TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); - if (a->imm) { - TCGv temp = tcg_temp_new(); - tcg_gen_addi_tl(temp, addr, a->imm); - addr = temp; - } + addr = make_address_i(ctx, addr, a->imm); tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, mop); gen_set_gpr(a->rd, dest, EXT_NONE); @@ -24,11 +20,7 @@ static bool gen_store(DisasContext *ctx, arg_rr_i *a, MemOp mop) TCGv data = gpr_src(ctx, a->rd, EXT_NONE); TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); - if (a->imm) { - TCGv temp = tcg_temp_new(); - tcg_gen_addi_tl(temp, addr, a->imm); - addr = temp; - } + addr = make_address_i(ctx, addr, a->imm); tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, mop); return true; @@ -66,6 +58,7 @@ static bool gen_load_gt(DisasContext *ctx, arg_rrr *a, MemOp mop) TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); gen_helper_asrtgt_d(cpu_env, src1, src2); + src1 = make_address_i(ctx, src1, 0); tcg_gen_qemu_ld_tl(dest, src1, ctx->mem_idx, mop); gen_set_gpr(a->rd, dest, EXT_NONE); @@ -79,6 +72,7 @@ static bool gen_load_le(DisasContext *ctx, arg_rrr *a, MemOp mop) TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); gen_helper_asrtle_d(cpu_env, src1, src2); + src1 = make_address_i(ctx, src1, 0); tcg_gen_qemu_ld_tl(dest, src1, ctx->mem_idx, mop); gen_set_gpr(a->rd, dest, EXT_NONE); @@ -92,6 +86,7 @@ static bool gen_store_gt(DisasContext *ctx, arg_rrr *a, MemOp mop) TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); gen_helper_asrtgt_d(cpu_env, src1, src2); + src1 = make_address_i(ctx, src1, 0); tcg_gen_qemu_st_tl(data, src1, ctx->mem_idx, mop); return true; @@ -104,6 +99,7 @@ static bool gen_store_le(DisasContext *ctx, arg_rrr *a, MemOp mop) TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); gen_helper_asrtle_d(cpu_env, src1, src2); + src1 = make_address_i(ctx, src1, 0); tcg_gen_qemu_st_tl(data, src1, ctx->mem_idx, mop); return true; @@ -131,11 +127,7 @@ static bool gen_ldptr(DisasContext *ctx, arg_rr_i *a, MemOp mop) TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); - if (a->imm) { - TCGv temp = tcg_temp_new(); - tcg_gen_addi_tl(temp, addr, a->imm); - addr = temp; - } + addr = make_address_i(ctx, addr, a->imm); tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, mop); gen_set_gpr(a->rd, dest, EXT_NONE); @@ -147,11 +139,7 @@ static bool gen_stptr(DisasContext *ctx, arg_rr_i *a, MemOp mop) TCGv data = gpr_src(ctx, a->rd, EXT_NONE); TCGv addr = gpr_src(ctx, a->rj, EXT_NONE); - if (a->imm) { - TCGv temp = tcg_temp_new(); - tcg_gen_addi_tl(temp, addr, a->imm); - addr = temp; - } + addr = make_address_i(ctx, addr, a->imm); tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, mop); return true; diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index a68a979a55..acc54d7587 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -220,6 +220,12 @@ static TCGv make_address_x(DisasContext *ctx, TCGv base, TCGv addend) return base; } +static TCGv make_address_i(DisasContext *ctx, TCGv base, target_long ofs) +{ + TCGv addend = ofs ? tcg_constant_tl(ofs) : NULL; + return make_address_x(ctx, base, addend); +} + #include "decode-insns.c.inc" #include "insn_trans/trans_arith.c.inc" #include "insn_trans/trans_shift.c.inc" From 5a7ce25d0db050b8ddd62dc91c56f4af46e9cf3c Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Tue, 22 Aug 2023 09:13:53 +0200 Subject: [PATCH 1182/1353] target/loongarch: Extract make_address_pc() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jiajie Chen Reviewed-by: Richard Henderson Signed-off-by: Song Gao Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20230822032724.1353391-7-gaosong@loongson.cn> [PMD: Extract helper from bigger patch] Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20230822071405.35386-8-philmd@linaro.org> --- target/loongarch/insn_trans/trans_arith.c.inc | 2 +- target/loongarch/insn_trans/trans_branch.c.inc | 4 ++-- target/loongarch/translate.c | 5 +++++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/target/loongarch/insn_trans/trans_arith.c.inc b/target/loongarch/insn_trans/trans_arith.c.inc index 43d6cf261d..2aea4e41d5 100644 --- a/target/loongarch/insn_trans/trans_arith.c.inc +++ b/target/loongarch/insn_trans/trans_arith.c.inc @@ -72,7 +72,7 @@ static bool gen_pc(DisasContext *ctx, arg_r_i *a, target_ulong (*func)(target_ulong, int)) { TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); - target_ulong addr = func(ctx->base.pc_next, a->imm); + target_ulong addr = make_address_pc(ctx, func(ctx->base.pc_next, a->imm)); tcg_gen_movi_tl(dest, addr); gen_set_gpr(a->rd, dest, EXT_NONE); diff --git a/target/loongarch/insn_trans/trans_branch.c.inc b/target/loongarch/insn_trans/trans_branch.c.inc index 3ad34bcc05..2e35572cea 100644 --- a/target/loongarch/insn_trans/trans_branch.c.inc +++ b/target/loongarch/insn_trans/trans_branch.c.inc @@ -12,7 +12,7 @@ static bool trans_b(DisasContext *ctx, arg_b *a) static bool trans_bl(DisasContext *ctx, arg_bl *a) { - tcg_gen_movi_tl(cpu_gpr[1], ctx->base.pc_next + 4); + tcg_gen_movi_tl(cpu_gpr[1], make_address_pc(ctx, ctx->base.pc_next + 4)); gen_goto_tb(ctx, 0, ctx->base.pc_next + a->offs); ctx->base.is_jmp = DISAS_NORETURN; return true; @@ -25,7 +25,7 @@ static bool trans_jirl(DisasContext *ctx, arg_jirl *a) TCGv addr = make_address_i(ctx, src1, a->imm); tcg_gen_mov_tl(cpu_pc, addr); - tcg_gen_movi_tl(dest, ctx->base.pc_next + 4); + tcg_gen_movi_tl(dest, make_address_pc(ctx, ctx->base.pc_next + 4)); gen_set_gpr(a->rd, dest, EXT_NONE); tcg_gen_lookup_and_goto_ptr(); ctx->base.is_jmp = DISAS_NORETURN; diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index acc54d7587..8b26555a27 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -226,6 +226,11 @@ static TCGv make_address_i(DisasContext *ctx, TCGv base, target_long ofs) return make_address_x(ctx, base, addend); } +static uint64_t make_address_pc(DisasContext *ctx, uint64_t addr) +{ + return addr; +} + #include "decode-insns.c.inc" #include "insn_trans/trans_arith.c.inc" #include "insn_trans/trans_shift.c.inc" From 2f6478ffad1770a474460b7692588bae7f031da3 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Tue, 22 Aug 2023 09:13:54 +0200 Subject: [PATCH 1183/1353] target/loongarch: Extract set_pc() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jiajie Chen Co-authored-by: Richard Henderson Reviewed-by: Richard Henderson Signed-off-by: Song Gao Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20230822032724.1353391-6-gaosong@loongson.cn> [PMD: Extract helper from bigger patch] Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20230822071405.35386-9-philmd@linaro.org> --- target/loongarch/cpu.c | 16 ++++++++-------- target/loongarch/cpu.h | 5 +++++ target/loongarch/gdbstub.c | 2 +- target/loongarch/op_helper.c | 4 ++-- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index 822f2a72e5..67eb6c3135 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -81,7 +81,7 @@ static void loongarch_cpu_set_pc(CPUState *cs, vaddr value) LoongArchCPU *cpu = LOONGARCH_CPU(cs); CPULoongArchState *env = &cpu->env; - env->pc = value; + set_pc(env, value); } static vaddr loongarch_cpu_get_pc(CPUState *cs) @@ -168,7 +168,7 @@ static void loongarch_cpu_do_interrupt(CPUState *cs) set_DERA: env->CSR_DERA = env->pc; env->CSR_DBG = FIELD_DP64(env->CSR_DBG, CSR_DBG, DST, 1); - env->pc = env->CSR_EENTRY + 0x480; + set_pc(env, env->CSR_EENTRY + 0x480); break; case EXCCODE_INT: if (FIELD_EX64(env->CSR_DBG, CSR_DBG, DST)) { @@ -249,7 +249,8 @@ static void loongarch_cpu_do_interrupt(CPUState *cs) /* Find the highest-priority interrupt. */ vector = 31 - clz32(pending); - env->pc = env->CSR_EENTRY + (EXCCODE_EXTERNAL_INT + vector) * vec_size; + set_pc(env, env->CSR_EENTRY + \ + (EXCCODE_EXTERNAL_INT + vector) * vec_size); qemu_log_mask(CPU_LOG_INT, "%s: PC " TARGET_FMT_lx " ERA " TARGET_FMT_lx " cause %d\n" " A " TARGET_FMT_lx " D " @@ -260,10 +261,9 @@ static void loongarch_cpu_do_interrupt(CPUState *cs) env->CSR_ECFG, env->CSR_ESTAT); } else { if (tlbfill) { - env->pc = env->CSR_TLBRENTRY; + set_pc(env, env->CSR_TLBRENTRY); } else { - env->pc = env->CSR_EENTRY; - env->pc += EXCODE_MCODE(cause) * vec_size; + set_pc(env, env->CSR_EENTRY + EXCODE_MCODE(cause) * vec_size); } qemu_log_mask(CPU_LOG_INT, "%s: PC " TARGET_FMT_lx " ERA " TARGET_FMT_lx @@ -324,7 +324,7 @@ static void loongarch_cpu_synchronize_from_tb(CPUState *cs, CPULoongArchState *env = &cpu->env; tcg_debug_assert(!(cs->tcg_cflags & CF_PCREL)); - env->pc = tb->pc; + set_pc(env, tb->pc); } static void loongarch_restore_state_to_opc(CPUState *cs, @@ -334,7 +334,7 @@ static void loongarch_restore_state_to_opc(CPUState *cs, LoongArchCPU *cpu = LOONGARCH_CPU(cs); CPULoongArchState *env = &cpu->env; - env->pc = data[0]; + set_pc(env, data[0]); } #endif /* CONFIG_TCG */ diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h index 72109095e4..e1562695e8 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -443,6 +443,11 @@ static inline bool is_va32(CPULoongArchState *env) return va32; } +static inline void set_pc(CPULoongArchState *env, uint64_t value) +{ + env->pc = value; +} + /* * LoongArch CPUs hardware flags. */ diff --git a/target/loongarch/gdbstub.c b/target/loongarch/gdbstub.c index a462e25737..e20b20f99b 100644 --- a/target/loongarch/gdbstub.c +++ b/target/loongarch/gdbstub.c @@ -77,7 +77,7 @@ int loongarch_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) env->gpr[n] = tmp; length = read_length; } else if (n == 33) { - env->pc = tmp; + set_pc(env, tmp); length = read_length; } return length; diff --git a/target/loongarch/op_helper.c b/target/loongarch/op_helper.c index 60335a05e2..cf84f20aba 100644 --- a/target/loongarch/op_helper.c +++ b/target/loongarch/op_helper.c @@ -114,14 +114,14 @@ void helper_ertn(CPULoongArchState *env) env->CSR_TLBRERA = FIELD_DP64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR, 0); env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DA, 0); env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PG, 1); - env->pc = env->CSR_TLBRERA; + set_pc(env, env->CSR_TLBRERA); qemu_log_mask(CPU_LOG_INT, "%s: TLBRERA " TARGET_FMT_lx "\n", __func__, env->CSR_TLBRERA); } else { csr_pplv = FIELD_EX64(env->CSR_PRMD, CSR_PRMD, PPLV); csr_pie = FIELD_EX64(env->CSR_PRMD, CSR_PRMD, PIE); - env->pc = env->CSR_ERA; + set_pc(env, env->CSR_ERA); qemu_log_mask(CPU_LOG_INT, "%s: ERA " TARGET_FMT_lx "\n", __func__, env->CSR_ERA); } From 7033c0e6dd36cd2bfa9a323c3a51ecb0b55903fc Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Tue, 22 Aug 2023 09:13:55 +0200 Subject: [PATCH 1184/1353] target/loongarch: Truncate high 32 bits of address in VA32 mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When running in VA32 mode(!LA64 or VA32L[1-3] matching PLV), virtual address is truncated to 32 bits before address mapping. Signed-off-by: Jiajie Chen Co-authored-by: Richard Henderson Reviewed-by: Richard Henderson Signed-off-by: Song Gao Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20230822032724.1353391-6-gaosong@loongson.cn> Message-Id: <20230822071405.35386-10-philmd@linaro.org> --- target/loongarch/cpu.h | 6 +++++- target/loongarch/translate.c | 16 +++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h index e1562695e8..25a0ef7e41 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -445,7 +445,11 @@ static inline bool is_va32(CPULoongArchState *env) static inline void set_pc(CPULoongArchState *env, uint64_t value) { - env->pc = value; + if (is_va32(env)) { + env->pc = (uint32_t)value; + } else { + env->pc = value; + } } /* diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index 8b26555a27..9a23ec786d 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -86,6 +86,10 @@ void generate_exception(DisasContext *ctx, int excp) static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) { + if (ctx->va32) { + dest = (uint32_t) dest; + } + if (translator_use_goto_tb(&ctx->base, dest)) { tcg_gen_goto_tb(n); tcg_gen_movi_tl(cpu_pc, dest); @@ -212,11 +216,17 @@ static TCGv make_address_x(DisasContext *ctx, TCGv base, TCGv addend) { TCGv temp = NULL; - if (addend) { + if (addend || ctx->va32) { temp = tcg_temp_new(); + } + if (addend) { tcg_gen_add_tl(temp, base, addend); base = temp; } + if (ctx->va32) { + tcg_gen_ext32u_tl(temp, base); + base = temp; + } return base; } @@ -262,6 +272,10 @@ static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) } ctx->base.pc_next += 4; + + if (ctx->va32) { + ctx->base.pc_next = (uint32_t)ctx->base.pc_next; + } } static void loongarch_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) From 6496269d7e0b7f0d42499d7e4dde19c8b6c759c9 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Tue, 22 Aug 2023 09:19:50 +0200 Subject: [PATCH 1185/1353] target/loongarch: Sign extend results in VA32 mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In VA32 mode, BL, JIRL and PC* instructions should sign-extend the low 32 bit result to 64 bits. Signed-off-by: Jiajie Chen Reviewed-by: Richard Henderson Signed-off-by: Song Gao Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20230822032724.1353391-7-gaosong@loongson.cn> Message-Id: <20230822071959.35620-1-philmd@linaro.org> --- target/loongarch/translate.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index 9a23ec786d..de7c1c5d1f 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -238,6 +238,9 @@ static TCGv make_address_i(DisasContext *ctx, TCGv base, target_long ofs) static uint64_t make_address_pc(DisasContext *ctx, uint64_t addr) { + if (ctx->va32) { + addr = (int32_t)addr; + } return addr; } From ec3a951891b00b2382bca29266c28f7ed021b0e5 Mon Sep 17 00:00:00 2001 From: Song Gao Date: Tue, 22 Aug 2023 09:19:51 +0200 Subject: [PATCH 1186/1353] target/loongarch: Add a check parameter to the TRANS macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The default check parmeter is ALL. Suggested-by: Richard Henderson Signed-off-by: Song Gao Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-ID: <20230822032724.1353391-8-gaosong@loongson.cn> Message-Id: <20230822071959.35620-2-philmd@linaro.org> --- target/loongarch/insn_trans/trans_arith.c.inc | 84 +- .../loongarch/insn_trans/trans_atomic.c.inc | 80 +- target/loongarch/insn_trans/trans_bit.c.inc | 56 +- .../loongarch/insn_trans/trans_branch.c.inc | 20 +- target/loongarch/insn_trans/trans_extra.c.inc | 16 +- .../loongarch/insn_trans/trans_farith.c.inc | 72 +- target/loongarch/insn_trans/trans_fcnv.c.inc | 56 +- .../loongarch/insn_trans/trans_fmemory.c.inc | 32 +- target/loongarch/insn_trans/trans_fmov.c.inc | 16 +- target/loongarch/insn_trans/trans_lsx.c.inc | 1236 ++++++++--------- .../loongarch/insn_trans/trans_memory.c.inc | 84 +- .../insn_trans/trans_privileged.c.inc | 16 +- target/loongarch/insn_trans/trans_shift.c.inc | 30 +- target/loongarch/translate.h | 6 +- 14 files changed, 903 insertions(+), 901 deletions(-) diff --git a/target/loongarch/insn_trans/trans_arith.c.inc b/target/loongarch/insn_trans/trans_arith.c.inc index 2aea4e41d5..d7f69a7553 100644 --- a/target/loongarch/insn_trans/trans_arith.c.inc +++ b/target/loongarch/insn_trans/trans_arith.c.inc @@ -248,45 +248,45 @@ static bool trans_addu16i_d(DisasContext *ctx, arg_addu16i_d *a) return true; } -TRANS(add_w, gen_rrr, EXT_NONE, EXT_NONE, EXT_SIGN, tcg_gen_add_tl) -TRANS(add_d, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_add_tl) -TRANS(sub_w, gen_rrr, EXT_NONE, EXT_NONE, EXT_SIGN, tcg_gen_sub_tl) -TRANS(sub_d, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_sub_tl) -TRANS(and, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_and_tl) -TRANS(or, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_or_tl) -TRANS(xor, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_xor_tl) -TRANS(nor, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_nor_tl) -TRANS(andn, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_andc_tl) -TRANS(orn, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_orc_tl) -TRANS(slt, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_slt) -TRANS(sltu, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_sltu) -TRANS(mul_w, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_SIGN, tcg_gen_mul_tl) -TRANS(mul_d, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_mul_tl) -TRANS(mulh_w, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_NONE, gen_mulh_w) -TRANS(mulh_wu, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_NONE, gen_mulh_w) -TRANS(mulh_d, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_mulh_d) -TRANS(mulh_du, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_mulh_du) -TRANS(mulw_d_w, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_NONE, tcg_gen_mul_tl) -TRANS(mulw_d_wu, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_NONE, tcg_gen_mul_tl) -TRANS(div_w, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_SIGN, gen_div_w) -TRANS(mod_w, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_SIGN, gen_rem_w) -TRANS(div_wu, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_SIGN, gen_div_du) -TRANS(mod_wu, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_SIGN, gen_rem_du) -TRANS(div_d, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_div_d) -TRANS(mod_d, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_rem_d) -TRANS(div_du, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_div_du) -TRANS(mod_du, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_rem_du) -TRANS(slti, gen_rri_v, EXT_NONE, EXT_NONE, gen_slt) -TRANS(sltui, gen_rri_v, EXT_NONE, EXT_NONE, gen_sltu) -TRANS(addi_w, gen_rri_c, EXT_NONE, EXT_SIGN, tcg_gen_addi_tl) -TRANS(addi_d, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_addi_tl) -TRANS(alsl_w, gen_rrr_sa, EXT_NONE, EXT_SIGN, gen_alsl) -TRANS(alsl_wu, gen_rrr_sa, EXT_NONE, EXT_ZERO, gen_alsl) -TRANS(alsl_d, gen_rrr_sa, EXT_NONE, EXT_NONE, gen_alsl) -TRANS(pcaddi, gen_pc, gen_pcaddi) -TRANS(pcalau12i, gen_pc, gen_pcalau12i) -TRANS(pcaddu12i, gen_pc, gen_pcaddu12i) -TRANS(pcaddu18i, gen_pc, gen_pcaddu18i) -TRANS(andi, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_andi_tl) -TRANS(ori, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_ori_tl) -TRANS(xori, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_xori_tl) +TRANS(add_w, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_SIGN, tcg_gen_add_tl) +TRANS(add_d, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_add_tl) +TRANS(sub_w, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_SIGN, tcg_gen_sub_tl) +TRANS(sub_d, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_sub_tl) +TRANS(and, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_and_tl) +TRANS(or, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_or_tl) +TRANS(xor, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_xor_tl) +TRANS(nor, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_nor_tl) +TRANS(andn, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_andc_tl) +TRANS(orn, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_orc_tl) +TRANS(slt, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_slt) +TRANS(sltu, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_sltu) +TRANS(mul_w, ALL, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_SIGN, tcg_gen_mul_tl) +TRANS(mul_d, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_mul_tl) +TRANS(mulh_w, ALL, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_NONE, gen_mulh_w) +TRANS(mulh_wu, ALL, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_NONE, gen_mulh_w) +TRANS(mulh_d, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_mulh_d) +TRANS(mulh_du, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_mulh_du) +TRANS(mulw_d_w, ALL, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_NONE, tcg_gen_mul_tl) +TRANS(mulw_d_wu, ALL, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_NONE, tcg_gen_mul_tl) +TRANS(div_w, ALL, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_SIGN, gen_div_w) +TRANS(mod_w, ALL, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_SIGN, gen_rem_w) +TRANS(div_wu, ALL, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_SIGN, gen_div_du) +TRANS(mod_wu, ALL, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_SIGN, gen_rem_du) +TRANS(div_d, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_div_d) +TRANS(mod_d, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_rem_d) +TRANS(div_du, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_div_du) +TRANS(mod_du, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_rem_du) +TRANS(slti, ALL, gen_rri_v, EXT_NONE, EXT_NONE, gen_slt) +TRANS(sltui, ALL, gen_rri_v, EXT_NONE, EXT_NONE, gen_sltu) +TRANS(addi_w, ALL, gen_rri_c, EXT_NONE, EXT_SIGN, tcg_gen_addi_tl) +TRANS(addi_d, ALL, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_addi_tl) +TRANS(alsl_w, ALL, gen_rrr_sa, EXT_NONE, EXT_SIGN, gen_alsl) +TRANS(alsl_wu, ALL, gen_rrr_sa, EXT_NONE, EXT_ZERO, gen_alsl) +TRANS(alsl_d, ALL, gen_rrr_sa, EXT_NONE, EXT_NONE, gen_alsl) +TRANS(pcaddi, ALL, gen_pc, gen_pcaddi) +TRANS(pcalau12i, ALL, gen_pc, gen_pcalau12i) +TRANS(pcaddu12i, ALL, gen_pc, gen_pcaddu12i) +TRANS(pcaddu18i, ALL, gen_pc, gen_pcaddu18i) +TRANS(andi, ALL, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_andi_tl) +TRANS(ori, ALL, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_ori_tl) +TRANS(xori, ALL, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_xori_tl) diff --git a/target/loongarch/insn_trans/trans_atomic.c.inc b/target/loongarch/insn_trans/trans_atomic.c.inc index fbc081448d..0a02f0dbf3 100644 --- a/target/loongarch/insn_trans/trans_atomic.c.inc +++ b/target/loongarch/insn_trans/trans_atomic.c.inc @@ -69,43 +69,43 @@ static bool gen_am(DisasContext *ctx, arg_rrr *a, return true; } -TRANS(ll_w, gen_ll, MO_TESL) -TRANS(sc_w, gen_sc, MO_TESL) -TRANS(ll_d, gen_ll, MO_TEUQ) -TRANS(sc_d, gen_sc, MO_TEUQ) -TRANS(amswap_w, gen_am, tcg_gen_atomic_xchg_tl, MO_TESL) -TRANS(amswap_d, gen_am, tcg_gen_atomic_xchg_tl, MO_TEUQ) -TRANS(amadd_w, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TESL) -TRANS(amadd_d, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TEUQ) -TRANS(amand_w, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TESL) -TRANS(amand_d, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TEUQ) -TRANS(amor_w, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TESL) -TRANS(amor_d, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TEUQ) -TRANS(amxor_w, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TESL) -TRANS(amxor_d, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TEUQ) -TRANS(ammax_w, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TESL) -TRANS(ammax_d, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TEUQ) -TRANS(ammin_w, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TESL) -TRANS(ammin_d, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TEUQ) -TRANS(ammax_wu, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TESL) -TRANS(ammax_du, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TEUQ) -TRANS(ammin_wu, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TESL) -TRANS(ammin_du, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TEUQ) -TRANS(amswap_db_w, gen_am, tcg_gen_atomic_xchg_tl, MO_TESL) -TRANS(amswap_db_d, gen_am, tcg_gen_atomic_xchg_tl, MO_TEUQ) -TRANS(amadd_db_w, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TESL) -TRANS(amadd_db_d, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TEUQ) -TRANS(amand_db_w, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TESL) -TRANS(amand_db_d, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TEUQ) -TRANS(amor_db_w, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TESL) -TRANS(amor_db_d, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TEUQ) -TRANS(amxor_db_w, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TESL) -TRANS(amxor_db_d, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TEUQ) -TRANS(ammax_db_w, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TESL) -TRANS(ammax_db_d, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TEUQ) -TRANS(ammin_db_w, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TESL) -TRANS(ammin_db_d, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TEUQ) -TRANS(ammax_db_wu, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TESL) -TRANS(ammax_db_du, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TEUQ) -TRANS(ammin_db_wu, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TESL) -TRANS(ammin_db_du, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TEUQ) +TRANS(ll_w, ALL, gen_ll, MO_TESL) +TRANS(sc_w, ALL, gen_sc, MO_TESL) +TRANS(ll_d, ALL, gen_ll, MO_TEUQ) +TRANS(sc_d, ALL, gen_sc, MO_TEUQ) +TRANS(amswap_w, ALL, gen_am, tcg_gen_atomic_xchg_tl, MO_TESL) +TRANS(amswap_d, ALL, gen_am, tcg_gen_atomic_xchg_tl, MO_TEUQ) +TRANS(amadd_w, ALL, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TESL) +TRANS(amadd_d, ALL, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TEUQ) +TRANS(amand_w, ALL, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TESL) +TRANS(amand_d, ALL, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TEUQ) +TRANS(amor_w, ALL, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TESL) +TRANS(amor_d, ALL, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TEUQ) +TRANS(amxor_w, ALL, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TESL) +TRANS(amxor_d, ALL, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TEUQ) +TRANS(ammax_w, ALL, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TESL) +TRANS(ammax_d, ALL, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TEUQ) +TRANS(ammin_w, ALL, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TESL) +TRANS(ammin_d, ALL, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TEUQ) +TRANS(ammax_wu, ALL, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TESL) +TRANS(ammax_du, ALL, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TEUQ) +TRANS(ammin_wu, ALL, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TESL) +TRANS(ammin_du, ALL, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TEUQ) +TRANS(amswap_db_w, ALL, gen_am, tcg_gen_atomic_xchg_tl, MO_TESL) +TRANS(amswap_db_d, ALL, gen_am, tcg_gen_atomic_xchg_tl, MO_TEUQ) +TRANS(amadd_db_w, ALL, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TESL) +TRANS(amadd_db_d, ALL, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TEUQ) +TRANS(amand_db_w, ALL, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TESL) +TRANS(amand_db_d, ALL, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TEUQ) +TRANS(amor_db_w, ALL, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TESL) +TRANS(amor_db_d, ALL, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TEUQ) +TRANS(amxor_db_w, ALL, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TESL) +TRANS(amxor_db_d, ALL, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TEUQ) +TRANS(ammax_db_w, ALL, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TESL) +TRANS(ammax_db_d, ALL, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TEUQ) +TRANS(ammin_db_w, ALL, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TESL) +TRANS(ammin_db_d, ALL, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TEUQ) +TRANS(ammax_db_wu, ALL, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TESL) +TRANS(ammax_db_du, ALL, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TEUQ) +TRANS(ammin_db_wu, ALL, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TESL) +TRANS(ammin_db_du, ALL, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TEUQ) diff --git a/target/loongarch/insn_trans/trans_bit.c.inc b/target/loongarch/insn_trans/trans_bit.c.inc index 25b4d7858b..d2a7ac28f7 100644 --- a/target/loongarch/insn_trans/trans_bit.c.inc +++ b/target/loongarch/insn_trans/trans_bit.c.inc @@ -178,31 +178,31 @@ static void gen_masknez(TCGv dest, TCGv src1, TCGv src2) tcg_gen_movcond_tl(TCG_COND_NE, dest, src2, zero, zero, src1); } -TRANS(ext_w_h, gen_rr, EXT_NONE, EXT_NONE, tcg_gen_ext16s_tl) -TRANS(ext_w_b, gen_rr, EXT_NONE, EXT_NONE, tcg_gen_ext8s_tl) -TRANS(clo_w, gen_rr, EXT_NONE, EXT_NONE, gen_clo_w) -TRANS(clz_w, gen_rr, EXT_ZERO, EXT_NONE, gen_clz_w) -TRANS(cto_w, gen_rr, EXT_NONE, EXT_NONE, gen_cto_w) -TRANS(ctz_w, gen_rr, EXT_NONE, EXT_NONE, gen_ctz_w) -TRANS(clo_d, gen_rr, EXT_NONE, EXT_NONE, gen_clo_d) -TRANS(clz_d, gen_rr, EXT_NONE, EXT_NONE, gen_clz_d) -TRANS(cto_d, gen_rr, EXT_NONE, EXT_NONE, gen_cto_d) -TRANS(ctz_d, gen_rr, EXT_NONE, EXT_NONE, gen_ctz_d) -TRANS(revb_2h, gen_rr, EXT_NONE, EXT_SIGN, gen_revb_2h) -TRANS(revb_4h, gen_rr, EXT_NONE, EXT_NONE, gen_revb_4h) -TRANS(revb_2w, gen_rr, EXT_NONE, EXT_NONE, gen_revb_2w) -TRANS(revb_d, gen_rr, EXT_NONE, EXT_NONE, tcg_gen_bswap64_i64) -TRANS(revh_2w, gen_rr, EXT_NONE, EXT_NONE, gen_revh_2w) -TRANS(revh_d, gen_rr, EXT_NONE, EXT_NONE, gen_revh_d) -TRANS(bitrev_4b, gen_rr, EXT_ZERO, EXT_SIGN, gen_helper_bitswap) -TRANS(bitrev_8b, gen_rr, EXT_NONE, EXT_NONE, gen_helper_bitswap) -TRANS(bitrev_w, gen_rr, EXT_NONE, EXT_SIGN, gen_helper_bitrev_w) -TRANS(bitrev_d, gen_rr, EXT_NONE, EXT_NONE, gen_helper_bitrev_d) -TRANS(maskeqz, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_maskeqz) -TRANS(masknez, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_masknez) -TRANS(bytepick_w, gen_rrr_sa, EXT_NONE, EXT_NONE, gen_bytepick_w) -TRANS(bytepick_d, gen_rrr_sa, EXT_NONE, EXT_NONE, gen_bytepick_d) -TRANS(bstrins_w, gen_bstrins, EXT_SIGN) -TRANS(bstrins_d, gen_bstrins, EXT_NONE) -TRANS(bstrpick_w, gen_bstrpick, EXT_SIGN) -TRANS(bstrpick_d, gen_bstrpick, EXT_NONE) +TRANS(ext_w_h, ALL, gen_rr, EXT_NONE, EXT_NONE, tcg_gen_ext16s_tl) +TRANS(ext_w_b, ALL, gen_rr, EXT_NONE, EXT_NONE, tcg_gen_ext8s_tl) +TRANS(clo_w, ALL, gen_rr, EXT_NONE, EXT_NONE, gen_clo_w) +TRANS(clz_w, ALL, gen_rr, EXT_ZERO, EXT_NONE, gen_clz_w) +TRANS(cto_w, ALL, gen_rr, EXT_NONE, EXT_NONE, gen_cto_w) +TRANS(ctz_w, ALL, gen_rr, EXT_NONE, EXT_NONE, gen_ctz_w) +TRANS(clo_d, ALL, gen_rr, EXT_NONE, EXT_NONE, gen_clo_d) +TRANS(clz_d, ALL, gen_rr, EXT_NONE, EXT_NONE, gen_clz_d) +TRANS(cto_d, ALL, gen_rr, EXT_NONE, EXT_NONE, gen_cto_d) +TRANS(ctz_d, ALL, gen_rr, EXT_NONE, EXT_NONE, gen_ctz_d) +TRANS(revb_2h, ALL, gen_rr, EXT_NONE, EXT_SIGN, gen_revb_2h) +TRANS(revb_4h, ALL, gen_rr, EXT_NONE, EXT_NONE, gen_revb_4h) +TRANS(revb_2w, ALL, gen_rr, EXT_NONE, EXT_NONE, gen_revb_2w) +TRANS(revb_d, ALL, gen_rr, EXT_NONE, EXT_NONE, tcg_gen_bswap64_i64) +TRANS(revh_2w, ALL, gen_rr, EXT_NONE, EXT_NONE, gen_revh_2w) +TRANS(revh_d, ALL, gen_rr, EXT_NONE, EXT_NONE, gen_revh_d) +TRANS(bitrev_4b, ALL, gen_rr, EXT_ZERO, EXT_SIGN, gen_helper_bitswap) +TRANS(bitrev_8b, ALL, gen_rr, EXT_NONE, EXT_NONE, gen_helper_bitswap) +TRANS(bitrev_w, ALL, gen_rr, EXT_NONE, EXT_SIGN, gen_helper_bitrev_w) +TRANS(bitrev_d, ALL, gen_rr, EXT_NONE, EXT_NONE, gen_helper_bitrev_d) +TRANS(maskeqz, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_maskeqz) +TRANS(masknez, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_masknez) +TRANS(bytepick_w, ALL, gen_rrr_sa, EXT_NONE, EXT_NONE, gen_bytepick_w) +TRANS(bytepick_d, ALL, gen_rrr_sa, EXT_NONE, EXT_NONE, gen_bytepick_d) +TRANS(bstrins_w, ALL, gen_bstrins, EXT_SIGN) +TRANS(bstrins_d, ALL, gen_bstrins, EXT_NONE) +TRANS(bstrpick_w, ALL, gen_bstrpick, EXT_SIGN) +TRANS(bstrpick_d, ALL, gen_bstrpick, EXT_NONE) diff --git a/target/loongarch/insn_trans/trans_branch.c.inc b/target/loongarch/insn_trans/trans_branch.c.inc index 2e35572cea..50f7eb640a 100644 --- a/target/loongarch/insn_trans/trans_branch.c.inc +++ b/target/loongarch/insn_trans/trans_branch.c.inc @@ -72,13 +72,13 @@ static bool gen_cz_bc(DisasContext *ctx, arg_c_offs *a, TCGCond cond) return true; } -TRANS(beq, gen_rr_bc, TCG_COND_EQ) -TRANS(bne, gen_rr_bc, TCG_COND_NE) -TRANS(blt, gen_rr_bc, TCG_COND_LT) -TRANS(bge, gen_rr_bc, TCG_COND_GE) -TRANS(bltu, gen_rr_bc, TCG_COND_LTU) -TRANS(bgeu, gen_rr_bc, TCG_COND_GEU) -TRANS(beqz, gen_rz_bc, TCG_COND_EQ) -TRANS(bnez, gen_rz_bc, TCG_COND_NE) -TRANS(bceqz, gen_cz_bc, TCG_COND_EQ) -TRANS(bcnez, gen_cz_bc, TCG_COND_NE) +TRANS(beq, ALL, gen_rr_bc, TCG_COND_EQ) +TRANS(bne, ALL, gen_rr_bc, TCG_COND_NE) +TRANS(blt, ALL, gen_rr_bc, TCG_COND_LT) +TRANS(bge, ALL, gen_rr_bc, TCG_COND_GE) +TRANS(bltu, ALL, gen_rr_bc, TCG_COND_LTU) +TRANS(bgeu, ALL, gen_rr_bc, TCG_COND_GEU) +TRANS(beqz, ALL, gen_rz_bc, TCG_COND_EQ) +TRANS(bnez, ALL, gen_rz_bc, TCG_COND_NE) +TRANS(bceqz, ALL, gen_cz_bc, TCG_COND_EQ) +TRANS(bcnez, ALL, gen_cz_bc, TCG_COND_NE) diff --git a/target/loongarch/insn_trans/trans_extra.c.inc b/target/loongarch/insn_trans/trans_extra.c.inc index 06f4de4515..b354ca0f86 100644 --- a/target/loongarch/insn_trans/trans_extra.c.inc +++ b/target/loongarch/insn_trans/trans_extra.c.inc @@ -89,11 +89,11 @@ static bool gen_crc(DisasContext *ctx, arg_rrr *a, return true; } -TRANS(crc_w_b_w, gen_crc, gen_helper_crc32, tcg_constant_tl(1)) -TRANS(crc_w_h_w, gen_crc, gen_helper_crc32, tcg_constant_tl(2)) -TRANS(crc_w_w_w, gen_crc, gen_helper_crc32, tcg_constant_tl(4)) -TRANS(crc_w_d_w, gen_crc, gen_helper_crc32, tcg_constant_tl(8)) -TRANS(crcc_w_b_w, gen_crc, gen_helper_crc32c, tcg_constant_tl(1)) -TRANS(crcc_w_h_w, gen_crc, gen_helper_crc32c, tcg_constant_tl(2)) -TRANS(crcc_w_w_w, gen_crc, gen_helper_crc32c, tcg_constant_tl(4)) -TRANS(crcc_w_d_w, gen_crc, gen_helper_crc32c, tcg_constant_tl(8)) +TRANS(crc_w_b_w, ALL, gen_crc, gen_helper_crc32, tcg_constant_tl(1)) +TRANS(crc_w_h_w, ALL, gen_crc, gen_helper_crc32, tcg_constant_tl(2)) +TRANS(crc_w_w_w, ALL, gen_crc, gen_helper_crc32, tcg_constant_tl(4)) +TRANS(crc_w_d_w, ALL, gen_crc, gen_helper_crc32, tcg_constant_tl(8)) +TRANS(crcc_w_b_w, ALL, gen_crc, gen_helper_crc32c, tcg_constant_tl(1)) +TRANS(crcc_w_h_w, ALL, gen_crc, gen_helper_crc32c, tcg_constant_tl(2)) +TRANS(crcc_w_w_w, ALL, gen_crc, gen_helper_crc32c, tcg_constant_tl(4)) +TRANS(crcc_w_d_w, ALL, gen_crc, gen_helper_crc32c, tcg_constant_tl(8)) diff --git a/target/loongarch/insn_trans/trans_farith.c.inc b/target/loongarch/insn_trans/trans_farith.c.inc index 21ea47308b..b1a1dc7b01 100644 --- a/target/loongarch/insn_trans/trans_farith.c.inc +++ b/target/loongarch/insn_trans/trans_farith.c.inc @@ -143,41 +143,41 @@ static bool trans_fneg_d(DisasContext *ctx, arg_fneg_d *a) return true; } -TRANS(fadd_s, gen_fff, gen_helper_fadd_s) -TRANS(fadd_d, gen_fff, gen_helper_fadd_d) -TRANS(fsub_s, gen_fff, gen_helper_fsub_s) -TRANS(fsub_d, gen_fff, gen_helper_fsub_d) -TRANS(fmul_s, gen_fff, gen_helper_fmul_s) -TRANS(fmul_d, gen_fff, gen_helper_fmul_d) -TRANS(fdiv_s, gen_fff, gen_helper_fdiv_s) -TRANS(fdiv_d, gen_fff, gen_helper_fdiv_d) -TRANS(fmax_s, gen_fff, gen_helper_fmax_s) -TRANS(fmax_d, gen_fff, gen_helper_fmax_d) -TRANS(fmin_s, gen_fff, gen_helper_fmin_s) -TRANS(fmin_d, gen_fff, gen_helper_fmin_d) -TRANS(fmaxa_s, gen_fff, gen_helper_fmaxa_s) -TRANS(fmaxa_d, gen_fff, gen_helper_fmaxa_d) -TRANS(fmina_s, gen_fff, gen_helper_fmina_s) -TRANS(fmina_d, gen_fff, gen_helper_fmina_d) -TRANS(fscaleb_s, gen_fff, gen_helper_fscaleb_s) -TRANS(fscaleb_d, gen_fff, gen_helper_fscaleb_d) -TRANS(fsqrt_s, gen_ff, gen_helper_fsqrt_s) -TRANS(fsqrt_d, gen_ff, gen_helper_fsqrt_d) -TRANS(frecip_s, gen_ff, gen_helper_frecip_s) -TRANS(frecip_d, gen_ff, gen_helper_frecip_d) -TRANS(frsqrt_s, gen_ff, gen_helper_frsqrt_s) -TRANS(frsqrt_d, gen_ff, gen_helper_frsqrt_d) -TRANS(flogb_s, gen_ff, gen_helper_flogb_s) -TRANS(flogb_d, gen_ff, gen_helper_flogb_d) -TRANS(fclass_s, gen_ff, gen_helper_fclass_s) -TRANS(fclass_d, gen_ff, gen_helper_fclass_d) -TRANS(fmadd_s, gen_muladd, gen_helper_fmuladd_s, 0) -TRANS(fmadd_d, gen_muladd, gen_helper_fmuladd_d, 0) -TRANS(fmsub_s, gen_muladd, gen_helper_fmuladd_s, float_muladd_negate_c) -TRANS(fmsub_d, gen_muladd, gen_helper_fmuladd_d, float_muladd_negate_c) -TRANS(fnmadd_s, gen_muladd, gen_helper_fmuladd_s, float_muladd_negate_result) -TRANS(fnmadd_d, gen_muladd, gen_helper_fmuladd_d, float_muladd_negate_result) -TRANS(fnmsub_s, gen_muladd, gen_helper_fmuladd_s, +TRANS(fadd_s, ALL, gen_fff, gen_helper_fadd_s) +TRANS(fadd_d, ALL, gen_fff, gen_helper_fadd_d) +TRANS(fsub_s, ALL, gen_fff, gen_helper_fsub_s) +TRANS(fsub_d, ALL, gen_fff, gen_helper_fsub_d) +TRANS(fmul_s, ALL, gen_fff, gen_helper_fmul_s) +TRANS(fmul_d, ALL, gen_fff, gen_helper_fmul_d) +TRANS(fdiv_s, ALL, gen_fff, gen_helper_fdiv_s) +TRANS(fdiv_d, ALL, gen_fff, gen_helper_fdiv_d) +TRANS(fmax_s, ALL, gen_fff, gen_helper_fmax_s) +TRANS(fmax_d, ALL, gen_fff, gen_helper_fmax_d) +TRANS(fmin_s, ALL, gen_fff, gen_helper_fmin_s) +TRANS(fmin_d, ALL, gen_fff, gen_helper_fmin_d) +TRANS(fmaxa_s, ALL, gen_fff, gen_helper_fmaxa_s) +TRANS(fmaxa_d, ALL, gen_fff, gen_helper_fmaxa_d) +TRANS(fmina_s, ALL, gen_fff, gen_helper_fmina_s) +TRANS(fmina_d, ALL, gen_fff, gen_helper_fmina_d) +TRANS(fscaleb_s, ALL, gen_fff, gen_helper_fscaleb_s) +TRANS(fscaleb_d, ALL, gen_fff, gen_helper_fscaleb_d) +TRANS(fsqrt_s, ALL, gen_ff, gen_helper_fsqrt_s) +TRANS(fsqrt_d, ALL, gen_ff, gen_helper_fsqrt_d) +TRANS(frecip_s, ALL, gen_ff, gen_helper_frecip_s) +TRANS(frecip_d, ALL, gen_ff, gen_helper_frecip_d) +TRANS(frsqrt_s, ALL, gen_ff, gen_helper_frsqrt_s) +TRANS(frsqrt_d, ALL, gen_ff, gen_helper_frsqrt_d) +TRANS(flogb_s, ALL, gen_ff, gen_helper_flogb_s) +TRANS(flogb_d, ALL, gen_ff, gen_helper_flogb_d) +TRANS(fclass_s, ALL, gen_ff, gen_helper_fclass_s) +TRANS(fclass_d, ALL, gen_ff, gen_helper_fclass_d) +TRANS(fmadd_s, ALL, gen_muladd, gen_helper_fmuladd_s, 0) +TRANS(fmadd_d, ALL, gen_muladd, gen_helper_fmuladd_d, 0) +TRANS(fmsub_s, ALL, gen_muladd, gen_helper_fmuladd_s, float_muladd_negate_c) +TRANS(fmsub_d, ALL, gen_muladd, gen_helper_fmuladd_d, float_muladd_negate_c) +TRANS(fnmadd_s, ALL, gen_muladd, gen_helper_fmuladd_s, float_muladd_negate_result) +TRANS(fnmadd_d, ALL, gen_muladd, gen_helper_fmuladd_d, float_muladd_negate_result) +TRANS(fnmsub_s, ALL, gen_muladd, gen_helper_fmuladd_s, float_muladd_negate_c | float_muladd_negate_result) -TRANS(fnmsub_d, gen_muladd, gen_helper_fmuladd_d, +TRANS(fnmsub_d, ALL, gen_muladd, gen_helper_fmuladd_d, float_muladd_negate_c | float_muladd_negate_result) diff --git a/target/loongarch/insn_trans/trans_fcnv.c.inc b/target/loongarch/insn_trans/trans_fcnv.c.inc index c1c6918ad1..329a2d6872 100644 --- a/target/loongarch/insn_trans/trans_fcnv.c.inc +++ b/target/loongarch/insn_trans/trans_fcnv.c.inc @@ -3,31 +3,31 @@ * Copyright (c) 2021 Loongson Technology Corporation Limited */ -TRANS(fcvt_s_d, gen_ff, gen_helper_fcvt_s_d) -TRANS(fcvt_d_s, gen_ff, gen_helper_fcvt_d_s) -TRANS(ftintrm_w_s, gen_ff, gen_helper_ftintrm_w_s) -TRANS(ftintrm_w_d, gen_ff, gen_helper_ftintrm_w_d) -TRANS(ftintrm_l_s, gen_ff, gen_helper_ftintrm_l_s) -TRANS(ftintrm_l_d, gen_ff, gen_helper_ftintrm_l_d) -TRANS(ftintrp_w_s, gen_ff, gen_helper_ftintrp_w_s) -TRANS(ftintrp_w_d, gen_ff, gen_helper_ftintrp_w_d) -TRANS(ftintrp_l_s, gen_ff, gen_helper_ftintrp_l_s) -TRANS(ftintrp_l_d, gen_ff, gen_helper_ftintrp_l_d) -TRANS(ftintrz_w_s, gen_ff, gen_helper_ftintrz_w_s) -TRANS(ftintrz_w_d, gen_ff, gen_helper_ftintrz_w_d) -TRANS(ftintrz_l_s, gen_ff, gen_helper_ftintrz_l_s) -TRANS(ftintrz_l_d, gen_ff, gen_helper_ftintrz_l_d) -TRANS(ftintrne_w_s, gen_ff, gen_helper_ftintrne_w_s) -TRANS(ftintrne_w_d, gen_ff, gen_helper_ftintrne_w_d) -TRANS(ftintrne_l_s, gen_ff, gen_helper_ftintrne_l_s) -TRANS(ftintrne_l_d, gen_ff, gen_helper_ftintrne_l_d) -TRANS(ftint_w_s, gen_ff, gen_helper_ftint_w_s) -TRANS(ftint_w_d, gen_ff, gen_helper_ftint_w_d) -TRANS(ftint_l_s, gen_ff, gen_helper_ftint_l_s) -TRANS(ftint_l_d, gen_ff, gen_helper_ftint_l_d) -TRANS(ffint_s_w, gen_ff, gen_helper_ffint_s_w) -TRANS(ffint_s_l, gen_ff, gen_helper_ffint_s_l) -TRANS(ffint_d_w, gen_ff, gen_helper_ffint_d_w) -TRANS(ffint_d_l, gen_ff, gen_helper_ffint_d_l) -TRANS(frint_s, gen_ff, gen_helper_frint_s) -TRANS(frint_d, gen_ff, gen_helper_frint_d) +TRANS(fcvt_s_d, ALL, gen_ff, gen_helper_fcvt_s_d) +TRANS(fcvt_d_s, ALL, gen_ff, gen_helper_fcvt_d_s) +TRANS(ftintrm_w_s, ALL, gen_ff, gen_helper_ftintrm_w_s) +TRANS(ftintrm_w_d, ALL, gen_ff, gen_helper_ftintrm_w_d) +TRANS(ftintrm_l_s, ALL, gen_ff, gen_helper_ftintrm_l_s) +TRANS(ftintrm_l_d, ALL, gen_ff, gen_helper_ftintrm_l_d) +TRANS(ftintrp_w_s, ALL, gen_ff, gen_helper_ftintrp_w_s) +TRANS(ftintrp_w_d, ALL, gen_ff, gen_helper_ftintrp_w_d) +TRANS(ftintrp_l_s, ALL, gen_ff, gen_helper_ftintrp_l_s) +TRANS(ftintrp_l_d, ALL, gen_ff, gen_helper_ftintrp_l_d) +TRANS(ftintrz_w_s, ALL, gen_ff, gen_helper_ftintrz_w_s) +TRANS(ftintrz_w_d, ALL, gen_ff, gen_helper_ftintrz_w_d) +TRANS(ftintrz_l_s, ALL, gen_ff, gen_helper_ftintrz_l_s) +TRANS(ftintrz_l_d, ALL, gen_ff, gen_helper_ftintrz_l_d) +TRANS(ftintrne_w_s, ALL, gen_ff, gen_helper_ftintrne_w_s) +TRANS(ftintrne_w_d, ALL, gen_ff, gen_helper_ftintrne_w_d) +TRANS(ftintrne_l_s, ALL, gen_ff, gen_helper_ftintrne_l_s) +TRANS(ftintrne_l_d, ALL, gen_ff, gen_helper_ftintrne_l_d) +TRANS(ftint_w_s, ALL, gen_ff, gen_helper_ftint_w_s) +TRANS(ftint_w_d, ALL, gen_ff, gen_helper_ftint_w_d) +TRANS(ftint_l_s, ALL, gen_ff, gen_helper_ftint_l_s) +TRANS(ftint_l_d, ALL, gen_ff, gen_helper_ftint_l_d) +TRANS(ffint_s_w, ALL, gen_ff, gen_helper_ffint_s_w) +TRANS(ffint_s_l, ALL, gen_ff, gen_helper_ffint_s_l) +TRANS(ffint_d_w, ALL, gen_ff, gen_helper_ffint_d_w) +TRANS(ffint_d_l, ALL, gen_ff, gen_helper_ffint_d_l) +TRANS(frint_s, ALL, gen_ff, gen_helper_frint_s) +TRANS(frint_d, ALL, gen_ff, gen_helper_frint_d) diff --git a/target/loongarch/insn_trans/trans_fmemory.c.inc b/target/loongarch/insn_trans/trans_fmemory.c.inc index bd3aba2c49..8e3b4522c9 100644 --- a/target/loongarch/insn_trans/trans_fmemory.c.inc +++ b/target/loongarch/insn_trans/trans_fmemory.c.inc @@ -140,19 +140,19 @@ static bool gen_fstore_le(DisasContext *ctx, arg_frr *a, MemOp mop) return true; } -TRANS(fld_s, gen_fload_i, MO_TEUL) -TRANS(fst_s, gen_fstore_i, MO_TEUL) -TRANS(fld_d, gen_fload_i, MO_TEUQ) -TRANS(fst_d, gen_fstore_i, MO_TEUQ) -TRANS(fldx_s, gen_floadx, MO_TEUL) -TRANS(fldx_d, gen_floadx, MO_TEUQ) -TRANS(fstx_s, gen_fstorex, MO_TEUL) -TRANS(fstx_d, gen_fstorex, MO_TEUQ) -TRANS(fldgt_s, gen_fload_gt, MO_TEUL) -TRANS(fldgt_d, gen_fload_gt, MO_TEUQ) -TRANS(fldle_s, gen_fload_le, MO_TEUL) -TRANS(fldle_d, gen_fload_le, MO_TEUQ) -TRANS(fstgt_s, gen_fstore_gt, MO_TEUL) -TRANS(fstgt_d, gen_fstore_gt, MO_TEUQ) -TRANS(fstle_s, gen_fstore_le, MO_TEUL) -TRANS(fstle_d, gen_fstore_le, MO_TEUQ) +TRANS(fld_s, ALL, gen_fload_i, MO_TEUL) +TRANS(fst_s, ALL, gen_fstore_i, MO_TEUL) +TRANS(fld_d, ALL, gen_fload_i, MO_TEUQ) +TRANS(fst_d, ALL, gen_fstore_i, MO_TEUQ) +TRANS(fldx_s, ALL, gen_floadx, MO_TEUL) +TRANS(fldx_d, ALL, gen_floadx, MO_TEUQ) +TRANS(fstx_s, ALL, gen_fstorex, MO_TEUL) +TRANS(fstx_d, ALL, gen_fstorex, MO_TEUQ) +TRANS(fldgt_s, ALL, gen_fload_gt, MO_TEUL) +TRANS(fldgt_d, ALL, gen_fload_gt, MO_TEUQ) +TRANS(fldle_s, ALL, gen_fload_le, MO_TEUL) +TRANS(fldle_d, ALL, gen_fload_le, MO_TEUQ) +TRANS(fstgt_s, ALL, gen_fstore_gt, MO_TEUL) +TRANS(fstgt_d, ALL, gen_fstore_gt, MO_TEUQ) +TRANS(fstle_s, ALL, gen_fstore_le, MO_TEUL) +TRANS(fstle_d, ALL, gen_fstore_le, MO_TEUQ) diff --git a/target/loongarch/insn_trans/trans_fmov.c.inc b/target/loongarch/insn_trans/trans_fmov.c.inc index 5af0dd1b66..aa7fea67b5 100644 --- a/target/loongarch/insn_trans/trans_fmov.c.inc +++ b/target/loongarch/insn_trans/trans_fmov.c.inc @@ -178,11 +178,11 @@ static bool trans_movcf2gr(DisasContext *ctx, arg_movcf2gr *a) return true; } -TRANS(fmov_s, gen_f2f, tcg_gen_mov_tl, true) -TRANS(fmov_d, gen_f2f, tcg_gen_mov_tl, false) -TRANS(movgr2fr_w, gen_r2f, gen_movgr2fr_w) -TRANS(movgr2fr_d, gen_r2f, tcg_gen_mov_tl) -TRANS(movgr2frh_w, gen_r2f, gen_movgr2frh_w) -TRANS(movfr2gr_s, gen_f2r, tcg_gen_ext32s_tl) -TRANS(movfr2gr_d, gen_f2r, tcg_gen_mov_tl) -TRANS(movfrh2gr_s, gen_f2r, gen_movfrh2gr_s) +TRANS(fmov_s, ALL, gen_f2f, tcg_gen_mov_tl, true) +TRANS(fmov_d, ALL, gen_f2f, tcg_gen_mov_tl, false) +TRANS(movgr2fr_w, ALL, gen_r2f, gen_movgr2fr_w) +TRANS(movgr2fr_d, ALL, gen_r2f, tcg_gen_mov_tl) +TRANS(movgr2frh_w, ALL, gen_r2f, gen_movgr2frh_w) +TRANS(movfr2gr_s, ALL, gen_f2r, tcg_gen_ext32s_tl) +TRANS(movfr2gr_d, ALL, gen_f2r, tcg_gen_mov_tl) +TRANS(movfrh2gr_s, ALL, gen_f2r, gen_movfrh2gr_s) diff --git a/target/loongarch/insn_trans/trans_lsx.c.inc b/target/loongarch/insn_trans/trans_lsx.c.inc index 50153d6d0b..45e0e738ad 100644 --- a/target/loongarch/insn_trans/trans_lsx.c.inc +++ b/target/loongarch/insn_trans/trans_lsx.c.inc @@ -135,10 +135,10 @@ static bool gvec_subi(DisasContext *ctx, arg_vv_i *a, MemOp mop) return true; } -TRANS(vadd_b, gvec_vvv, MO_8, tcg_gen_gvec_add) -TRANS(vadd_h, gvec_vvv, MO_16, tcg_gen_gvec_add) -TRANS(vadd_w, gvec_vvv, MO_32, tcg_gen_gvec_add) -TRANS(vadd_d, gvec_vvv, MO_64, tcg_gen_gvec_add) +TRANS(vadd_b, ALL, gvec_vvv, MO_8, tcg_gen_gvec_add) +TRANS(vadd_h, ALL, gvec_vvv, MO_16, tcg_gen_gvec_add) +TRANS(vadd_w, ALL, gvec_vvv, MO_32, tcg_gen_gvec_add) +TRANS(vadd_d, ALL, gvec_vvv, MO_64, tcg_gen_gvec_add) #define VADDSUB_Q(NAME) \ static bool trans_v## NAME ##_q(DisasContext *ctx, arg_vvv *a) \ @@ -170,58 +170,58 @@ static bool trans_v## NAME ##_q(DisasContext *ctx, arg_vvv *a) \ VADDSUB_Q(add) VADDSUB_Q(sub) -TRANS(vsub_b, gvec_vvv, MO_8, tcg_gen_gvec_sub) -TRANS(vsub_h, gvec_vvv, MO_16, tcg_gen_gvec_sub) -TRANS(vsub_w, gvec_vvv, MO_32, tcg_gen_gvec_sub) -TRANS(vsub_d, gvec_vvv, MO_64, tcg_gen_gvec_sub) +TRANS(vsub_b, ALL, gvec_vvv, MO_8, tcg_gen_gvec_sub) +TRANS(vsub_h, ALL, gvec_vvv, MO_16, tcg_gen_gvec_sub) +TRANS(vsub_w, ALL, gvec_vvv, MO_32, tcg_gen_gvec_sub) +TRANS(vsub_d, ALL, gvec_vvv, MO_64, tcg_gen_gvec_sub) -TRANS(vaddi_bu, gvec_vv_i, MO_8, tcg_gen_gvec_addi) -TRANS(vaddi_hu, gvec_vv_i, MO_16, tcg_gen_gvec_addi) -TRANS(vaddi_wu, gvec_vv_i, MO_32, tcg_gen_gvec_addi) -TRANS(vaddi_du, gvec_vv_i, MO_64, tcg_gen_gvec_addi) -TRANS(vsubi_bu, gvec_subi, MO_8) -TRANS(vsubi_hu, gvec_subi, MO_16) -TRANS(vsubi_wu, gvec_subi, MO_32) -TRANS(vsubi_du, gvec_subi, MO_64) +TRANS(vaddi_bu, ALL, gvec_vv_i, MO_8, tcg_gen_gvec_addi) +TRANS(vaddi_hu, ALL, gvec_vv_i, MO_16, tcg_gen_gvec_addi) +TRANS(vaddi_wu, ALL, gvec_vv_i, MO_32, tcg_gen_gvec_addi) +TRANS(vaddi_du, ALL, gvec_vv_i, MO_64, tcg_gen_gvec_addi) +TRANS(vsubi_bu, ALL, gvec_subi, MO_8) +TRANS(vsubi_hu, ALL, gvec_subi, MO_16) +TRANS(vsubi_wu, ALL, gvec_subi, MO_32) +TRANS(vsubi_du, ALL, gvec_subi, MO_64) -TRANS(vneg_b, gvec_vv, MO_8, tcg_gen_gvec_neg) -TRANS(vneg_h, gvec_vv, MO_16, tcg_gen_gvec_neg) -TRANS(vneg_w, gvec_vv, MO_32, tcg_gen_gvec_neg) -TRANS(vneg_d, gvec_vv, MO_64, tcg_gen_gvec_neg) +TRANS(vneg_b, ALL, gvec_vv, MO_8, tcg_gen_gvec_neg) +TRANS(vneg_h, ALL, gvec_vv, MO_16, tcg_gen_gvec_neg) +TRANS(vneg_w, ALL, gvec_vv, MO_32, tcg_gen_gvec_neg) +TRANS(vneg_d, ALL, gvec_vv, MO_64, tcg_gen_gvec_neg) -TRANS(vsadd_b, gvec_vvv, MO_8, tcg_gen_gvec_ssadd) -TRANS(vsadd_h, gvec_vvv, MO_16, tcg_gen_gvec_ssadd) -TRANS(vsadd_w, gvec_vvv, MO_32, tcg_gen_gvec_ssadd) -TRANS(vsadd_d, gvec_vvv, MO_64, tcg_gen_gvec_ssadd) -TRANS(vsadd_bu, gvec_vvv, MO_8, tcg_gen_gvec_usadd) -TRANS(vsadd_hu, gvec_vvv, MO_16, tcg_gen_gvec_usadd) -TRANS(vsadd_wu, gvec_vvv, MO_32, tcg_gen_gvec_usadd) -TRANS(vsadd_du, gvec_vvv, MO_64, tcg_gen_gvec_usadd) -TRANS(vssub_b, gvec_vvv, MO_8, tcg_gen_gvec_sssub) -TRANS(vssub_h, gvec_vvv, MO_16, tcg_gen_gvec_sssub) -TRANS(vssub_w, gvec_vvv, MO_32, tcg_gen_gvec_sssub) -TRANS(vssub_d, gvec_vvv, MO_64, tcg_gen_gvec_sssub) -TRANS(vssub_bu, gvec_vvv, MO_8, tcg_gen_gvec_ussub) -TRANS(vssub_hu, gvec_vvv, MO_16, tcg_gen_gvec_ussub) -TRANS(vssub_wu, gvec_vvv, MO_32, tcg_gen_gvec_ussub) -TRANS(vssub_du, gvec_vvv, MO_64, tcg_gen_gvec_ussub) +TRANS(vsadd_b, ALL, gvec_vvv, MO_8, tcg_gen_gvec_ssadd) +TRANS(vsadd_h, ALL, gvec_vvv, MO_16, tcg_gen_gvec_ssadd) +TRANS(vsadd_w, ALL, gvec_vvv, MO_32, tcg_gen_gvec_ssadd) +TRANS(vsadd_d, ALL, gvec_vvv, MO_64, tcg_gen_gvec_ssadd) +TRANS(vsadd_bu, ALL, gvec_vvv, MO_8, tcg_gen_gvec_usadd) +TRANS(vsadd_hu, ALL, gvec_vvv, MO_16, tcg_gen_gvec_usadd) +TRANS(vsadd_wu, ALL, gvec_vvv, MO_32, tcg_gen_gvec_usadd) +TRANS(vsadd_du, ALL, gvec_vvv, MO_64, tcg_gen_gvec_usadd) +TRANS(vssub_b, ALL, gvec_vvv, MO_8, tcg_gen_gvec_sssub) +TRANS(vssub_h, ALL, gvec_vvv, MO_16, tcg_gen_gvec_sssub) +TRANS(vssub_w, ALL, gvec_vvv, MO_32, tcg_gen_gvec_sssub) +TRANS(vssub_d, ALL, gvec_vvv, MO_64, tcg_gen_gvec_sssub) +TRANS(vssub_bu, ALL, gvec_vvv, MO_8, tcg_gen_gvec_ussub) +TRANS(vssub_hu, ALL, gvec_vvv, MO_16, tcg_gen_gvec_ussub) +TRANS(vssub_wu, ALL, gvec_vvv, MO_32, tcg_gen_gvec_ussub) +TRANS(vssub_du, ALL, gvec_vvv, MO_64, tcg_gen_gvec_ussub) -TRANS(vhaddw_h_b, gen_vvv, gen_helper_vhaddw_h_b) -TRANS(vhaddw_w_h, gen_vvv, gen_helper_vhaddw_w_h) -TRANS(vhaddw_d_w, gen_vvv, gen_helper_vhaddw_d_w) -TRANS(vhaddw_q_d, gen_vvv, gen_helper_vhaddw_q_d) -TRANS(vhaddw_hu_bu, gen_vvv, gen_helper_vhaddw_hu_bu) -TRANS(vhaddw_wu_hu, gen_vvv, gen_helper_vhaddw_wu_hu) -TRANS(vhaddw_du_wu, gen_vvv, gen_helper_vhaddw_du_wu) -TRANS(vhaddw_qu_du, gen_vvv, gen_helper_vhaddw_qu_du) -TRANS(vhsubw_h_b, gen_vvv, gen_helper_vhsubw_h_b) -TRANS(vhsubw_w_h, gen_vvv, gen_helper_vhsubw_w_h) -TRANS(vhsubw_d_w, gen_vvv, gen_helper_vhsubw_d_w) -TRANS(vhsubw_q_d, gen_vvv, gen_helper_vhsubw_q_d) -TRANS(vhsubw_hu_bu, gen_vvv, gen_helper_vhsubw_hu_bu) -TRANS(vhsubw_wu_hu, gen_vvv, gen_helper_vhsubw_wu_hu) -TRANS(vhsubw_du_wu, gen_vvv, gen_helper_vhsubw_du_wu) -TRANS(vhsubw_qu_du, gen_vvv, gen_helper_vhsubw_qu_du) +TRANS(vhaddw_h_b, ALL, gen_vvv, gen_helper_vhaddw_h_b) +TRANS(vhaddw_w_h, ALL, gen_vvv, gen_helper_vhaddw_w_h) +TRANS(vhaddw_d_w, ALL, gen_vvv, gen_helper_vhaddw_d_w) +TRANS(vhaddw_q_d, ALL, gen_vvv, gen_helper_vhaddw_q_d) +TRANS(vhaddw_hu_bu, ALL, gen_vvv, gen_helper_vhaddw_hu_bu) +TRANS(vhaddw_wu_hu, ALL, gen_vvv, gen_helper_vhaddw_wu_hu) +TRANS(vhaddw_du_wu, ALL, gen_vvv, gen_helper_vhaddw_du_wu) +TRANS(vhaddw_qu_du, ALL, gen_vvv, gen_helper_vhaddw_qu_du) +TRANS(vhsubw_h_b, ALL, gen_vvv, gen_helper_vhsubw_h_b) +TRANS(vhsubw_w_h, ALL, gen_vvv, gen_helper_vhsubw_w_h) +TRANS(vhsubw_d_w, ALL, gen_vvv, gen_helper_vhsubw_d_w) +TRANS(vhsubw_q_d, ALL, gen_vvv, gen_helper_vhsubw_q_d) +TRANS(vhsubw_hu_bu, ALL, gen_vvv, gen_helper_vhsubw_hu_bu) +TRANS(vhsubw_wu_hu, ALL, gen_vvv, gen_helper_vhsubw_wu_hu) +TRANS(vhsubw_du_wu, ALL, gen_vvv, gen_helper_vhsubw_du_wu) +TRANS(vhsubw_qu_du, ALL, gen_vvv, gen_helper_vhsubw_qu_du) static void gen_vaddwev_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -301,10 +301,10 @@ static void do_vaddwev_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vaddwev_h_b, gvec_vvv, MO_8, do_vaddwev_s) -TRANS(vaddwev_w_h, gvec_vvv, MO_16, do_vaddwev_s) -TRANS(vaddwev_d_w, gvec_vvv, MO_32, do_vaddwev_s) -TRANS(vaddwev_q_d, gvec_vvv, MO_64, do_vaddwev_s) +TRANS(vaddwev_h_b, ALL, gvec_vvv, MO_8, do_vaddwev_s) +TRANS(vaddwev_w_h, ALL, gvec_vvv, MO_16, do_vaddwev_s) +TRANS(vaddwev_d_w, ALL, gvec_vvv, MO_32, do_vaddwev_s) +TRANS(vaddwev_q_d, ALL, gvec_vvv, MO_64, do_vaddwev_s) static void gen_vaddwod_w_h(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) { @@ -380,10 +380,10 @@ static void do_vaddwod_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vaddwod_h_b, gvec_vvv, MO_8, do_vaddwod_s) -TRANS(vaddwod_w_h, gvec_vvv, MO_16, do_vaddwod_s) -TRANS(vaddwod_d_w, gvec_vvv, MO_32, do_vaddwod_s) -TRANS(vaddwod_q_d, gvec_vvv, MO_64, do_vaddwod_s) +TRANS(vaddwod_h_b, ALL, gvec_vvv, MO_8, do_vaddwod_s) +TRANS(vaddwod_w_h, ALL, gvec_vvv, MO_16, do_vaddwod_s) +TRANS(vaddwod_d_w, ALL, gvec_vvv, MO_32, do_vaddwod_s) +TRANS(vaddwod_q_d, ALL, gvec_vvv, MO_64, do_vaddwod_s) static void gen_vsubwev_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -463,10 +463,10 @@ static void do_vsubwev_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vsubwev_h_b, gvec_vvv, MO_8, do_vsubwev_s) -TRANS(vsubwev_w_h, gvec_vvv, MO_16, do_vsubwev_s) -TRANS(vsubwev_d_w, gvec_vvv, MO_32, do_vsubwev_s) -TRANS(vsubwev_q_d, gvec_vvv, MO_64, do_vsubwev_s) +TRANS(vsubwev_h_b, ALL, gvec_vvv, MO_8, do_vsubwev_s) +TRANS(vsubwev_w_h, ALL, gvec_vvv, MO_16, do_vsubwev_s) +TRANS(vsubwev_d_w, ALL, gvec_vvv, MO_32, do_vsubwev_s) +TRANS(vsubwev_q_d, ALL, gvec_vvv, MO_64, do_vsubwev_s) static void gen_vsubwod_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -542,10 +542,10 @@ static void do_vsubwod_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vsubwod_h_b, gvec_vvv, MO_8, do_vsubwod_s) -TRANS(vsubwod_w_h, gvec_vvv, MO_16, do_vsubwod_s) -TRANS(vsubwod_d_w, gvec_vvv, MO_32, do_vsubwod_s) -TRANS(vsubwod_q_d, gvec_vvv, MO_64, do_vsubwod_s) +TRANS(vsubwod_h_b, ALL, gvec_vvv, MO_8, do_vsubwod_s) +TRANS(vsubwod_w_h, ALL, gvec_vvv, MO_16, do_vsubwod_s) +TRANS(vsubwod_d_w, ALL, gvec_vvv, MO_32, do_vsubwod_s) +TRANS(vsubwod_q_d, ALL, gvec_vvv, MO_64, do_vsubwod_s) static void gen_vaddwev_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -617,10 +617,10 @@ static void do_vaddwev_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vaddwev_h_bu, gvec_vvv, MO_8, do_vaddwev_u) -TRANS(vaddwev_w_hu, gvec_vvv, MO_16, do_vaddwev_u) -TRANS(vaddwev_d_wu, gvec_vvv, MO_32, do_vaddwev_u) -TRANS(vaddwev_q_du, gvec_vvv, MO_64, do_vaddwev_u) +TRANS(vaddwev_h_bu, ALL, gvec_vvv, MO_8, do_vaddwev_u) +TRANS(vaddwev_w_hu, ALL, gvec_vvv, MO_16, do_vaddwev_u) +TRANS(vaddwev_d_wu, ALL, gvec_vvv, MO_32, do_vaddwev_u) +TRANS(vaddwev_q_du, ALL, gvec_vvv, MO_64, do_vaddwev_u) static void gen_vaddwod_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -696,10 +696,10 @@ static void do_vaddwod_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vaddwod_h_bu, gvec_vvv, MO_8, do_vaddwod_u) -TRANS(vaddwod_w_hu, gvec_vvv, MO_16, do_vaddwod_u) -TRANS(vaddwod_d_wu, gvec_vvv, MO_32, do_vaddwod_u) -TRANS(vaddwod_q_du, gvec_vvv, MO_64, do_vaddwod_u) +TRANS(vaddwod_h_bu, ALL, gvec_vvv, MO_8, do_vaddwod_u) +TRANS(vaddwod_w_hu, ALL, gvec_vvv, MO_16, do_vaddwod_u) +TRANS(vaddwod_d_wu, ALL, gvec_vvv, MO_32, do_vaddwod_u) +TRANS(vaddwod_q_du, ALL, gvec_vvv, MO_64, do_vaddwod_u) static void gen_vsubwev_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -771,10 +771,10 @@ static void do_vsubwev_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vsubwev_h_bu, gvec_vvv, MO_8, do_vsubwev_u) -TRANS(vsubwev_w_hu, gvec_vvv, MO_16, do_vsubwev_u) -TRANS(vsubwev_d_wu, gvec_vvv, MO_32, do_vsubwev_u) -TRANS(vsubwev_q_du, gvec_vvv, MO_64, do_vsubwev_u) +TRANS(vsubwev_h_bu, ALL, gvec_vvv, MO_8, do_vsubwev_u) +TRANS(vsubwev_w_hu, ALL, gvec_vvv, MO_16, do_vsubwev_u) +TRANS(vsubwev_d_wu, ALL, gvec_vvv, MO_32, do_vsubwev_u) +TRANS(vsubwev_q_du, ALL, gvec_vvv, MO_64, do_vsubwev_u) static void gen_vsubwod_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -850,10 +850,10 @@ static void do_vsubwod_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vsubwod_h_bu, gvec_vvv, MO_8, do_vsubwod_u) -TRANS(vsubwod_w_hu, gvec_vvv, MO_16, do_vsubwod_u) -TRANS(vsubwod_d_wu, gvec_vvv, MO_32, do_vsubwod_u) -TRANS(vsubwod_q_du, gvec_vvv, MO_64, do_vsubwod_u) +TRANS(vsubwod_h_bu, ALL, gvec_vvv, MO_8, do_vsubwod_u) +TRANS(vsubwod_w_hu, ALL, gvec_vvv, MO_16, do_vsubwod_u) +TRANS(vsubwod_d_wu, ALL, gvec_vvv, MO_32, do_vsubwod_u) +TRANS(vsubwod_q_du, ALL, gvec_vvv, MO_64, do_vsubwod_u) static void gen_vaddwev_u_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -933,10 +933,10 @@ static void do_vaddwev_u_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vaddwev_h_bu_b, gvec_vvv, MO_8, do_vaddwev_u_s) -TRANS(vaddwev_w_hu_h, gvec_vvv, MO_16, do_vaddwev_u_s) -TRANS(vaddwev_d_wu_w, gvec_vvv, MO_32, do_vaddwev_u_s) -TRANS(vaddwev_q_du_d, gvec_vvv, MO_64, do_vaddwev_u_s) +TRANS(vaddwev_h_bu_b, ALL, gvec_vvv, MO_8, do_vaddwev_u_s) +TRANS(vaddwev_w_hu_h, ALL, gvec_vvv, MO_16, do_vaddwev_u_s) +TRANS(vaddwev_d_wu_w, ALL, gvec_vvv, MO_32, do_vaddwev_u_s) +TRANS(vaddwev_q_du_d, ALL, gvec_vvv, MO_64, do_vaddwev_u_s) static void gen_vaddwod_u_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -1013,10 +1013,10 @@ static void do_vaddwod_u_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vaddwod_h_bu_b, gvec_vvv, MO_8, do_vaddwod_u_s) -TRANS(vaddwod_w_hu_h, gvec_vvv, MO_16, do_vaddwod_u_s) -TRANS(vaddwod_d_wu_w, gvec_vvv, MO_32, do_vaddwod_u_s) -TRANS(vaddwod_q_du_d, gvec_vvv, MO_64, do_vaddwod_u_s) +TRANS(vaddwod_h_bu_b, ALL, gvec_vvv, MO_8, do_vaddwod_u_s) +TRANS(vaddwod_w_hu_h, ALL, gvec_vvv, MO_16, do_vaddwod_u_s) +TRANS(vaddwod_d_wu_w, ALL, gvec_vvv, MO_32, do_vaddwod_u_s) +TRANS(vaddwod_q_du_d, ALL, gvec_vvv, MO_64, do_vaddwod_u_s) static void do_vavg(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b, void (*gen_shr_vec)(unsigned, TCGv_vec, @@ -1125,14 +1125,14 @@ static void do_vavg_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vavg_b, gvec_vvv, MO_8, do_vavg_s) -TRANS(vavg_h, gvec_vvv, MO_16, do_vavg_s) -TRANS(vavg_w, gvec_vvv, MO_32, do_vavg_s) -TRANS(vavg_d, gvec_vvv, MO_64, do_vavg_s) -TRANS(vavg_bu, gvec_vvv, MO_8, do_vavg_u) -TRANS(vavg_hu, gvec_vvv, MO_16, do_vavg_u) -TRANS(vavg_wu, gvec_vvv, MO_32, do_vavg_u) -TRANS(vavg_du, gvec_vvv, MO_64, do_vavg_u) +TRANS(vavg_b, ALL, gvec_vvv, MO_8, do_vavg_s) +TRANS(vavg_h, ALL, gvec_vvv, MO_16, do_vavg_s) +TRANS(vavg_w, ALL, gvec_vvv, MO_32, do_vavg_s) +TRANS(vavg_d, ALL, gvec_vvv, MO_64, do_vavg_s) +TRANS(vavg_bu, ALL, gvec_vvv, MO_8, do_vavg_u) +TRANS(vavg_hu, ALL, gvec_vvv, MO_16, do_vavg_u) +TRANS(vavg_wu, ALL, gvec_vvv, MO_32, do_vavg_u) +TRANS(vavg_du, ALL, gvec_vvv, MO_64, do_vavg_u) static void do_vavgr_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) @@ -1206,14 +1206,14 @@ static void do_vavgr_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vavgr_b, gvec_vvv, MO_8, do_vavgr_s) -TRANS(vavgr_h, gvec_vvv, MO_16, do_vavgr_s) -TRANS(vavgr_w, gvec_vvv, MO_32, do_vavgr_s) -TRANS(vavgr_d, gvec_vvv, MO_64, do_vavgr_s) -TRANS(vavgr_bu, gvec_vvv, MO_8, do_vavgr_u) -TRANS(vavgr_hu, gvec_vvv, MO_16, do_vavgr_u) -TRANS(vavgr_wu, gvec_vvv, MO_32, do_vavgr_u) -TRANS(vavgr_du, gvec_vvv, MO_64, do_vavgr_u) +TRANS(vavgr_b, ALL, gvec_vvv, MO_8, do_vavgr_s) +TRANS(vavgr_h, ALL, gvec_vvv, MO_16, do_vavgr_s) +TRANS(vavgr_w, ALL, gvec_vvv, MO_32, do_vavgr_s) +TRANS(vavgr_d, ALL, gvec_vvv, MO_64, do_vavgr_s) +TRANS(vavgr_bu, ALL, gvec_vvv, MO_8, do_vavgr_u) +TRANS(vavgr_hu, ALL, gvec_vvv, MO_16, do_vavgr_u) +TRANS(vavgr_wu, ALL, gvec_vvv, MO_32, do_vavgr_u) +TRANS(vavgr_du, ALL, gvec_vvv, MO_64, do_vavgr_u) static void gen_vabsd_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -1301,14 +1301,14 @@ static void do_vabsd_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vabsd_b, gvec_vvv, MO_8, do_vabsd_s) -TRANS(vabsd_h, gvec_vvv, MO_16, do_vabsd_s) -TRANS(vabsd_w, gvec_vvv, MO_32, do_vabsd_s) -TRANS(vabsd_d, gvec_vvv, MO_64, do_vabsd_s) -TRANS(vabsd_bu, gvec_vvv, MO_8, do_vabsd_u) -TRANS(vabsd_hu, gvec_vvv, MO_16, do_vabsd_u) -TRANS(vabsd_wu, gvec_vvv, MO_32, do_vabsd_u) -TRANS(vabsd_du, gvec_vvv, MO_64, do_vabsd_u) +TRANS(vabsd_b, ALL, gvec_vvv, MO_8, do_vabsd_s) +TRANS(vabsd_h, ALL, gvec_vvv, MO_16, do_vabsd_s) +TRANS(vabsd_w, ALL, gvec_vvv, MO_32, do_vabsd_s) +TRANS(vabsd_d, ALL, gvec_vvv, MO_64, do_vabsd_s) +TRANS(vabsd_bu, ALL, gvec_vvv, MO_8, do_vabsd_u) +TRANS(vabsd_hu, ALL, gvec_vvv, MO_16, do_vabsd_u) +TRANS(vabsd_wu, ALL, gvec_vvv, MO_32, do_vabsd_u) +TRANS(vabsd_du, ALL, gvec_vvv, MO_64, do_vabsd_u) static void gen_vadda(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -1358,28 +1358,28 @@ static void do_vadda(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vadda_b, gvec_vvv, MO_8, do_vadda) -TRANS(vadda_h, gvec_vvv, MO_16, do_vadda) -TRANS(vadda_w, gvec_vvv, MO_32, do_vadda) -TRANS(vadda_d, gvec_vvv, MO_64, do_vadda) +TRANS(vadda_b, ALL, gvec_vvv, MO_8, do_vadda) +TRANS(vadda_h, ALL, gvec_vvv, MO_16, do_vadda) +TRANS(vadda_w, ALL, gvec_vvv, MO_32, do_vadda) +TRANS(vadda_d, ALL, gvec_vvv, MO_64, do_vadda) -TRANS(vmax_b, gvec_vvv, MO_8, tcg_gen_gvec_smax) -TRANS(vmax_h, gvec_vvv, MO_16, tcg_gen_gvec_smax) -TRANS(vmax_w, gvec_vvv, MO_32, tcg_gen_gvec_smax) -TRANS(vmax_d, gvec_vvv, MO_64, tcg_gen_gvec_smax) -TRANS(vmax_bu, gvec_vvv, MO_8, tcg_gen_gvec_umax) -TRANS(vmax_hu, gvec_vvv, MO_16, tcg_gen_gvec_umax) -TRANS(vmax_wu, gvec_vvv, MO_32, tcg_gen_gvec_umax) -TRANS(vmax_du, gvec_vvv, MO_64, tcg_gen_gvec_umax) +TRANS(vmax_b, ALL, gvec_vvv, MO_8, tcg_gen_gvec_smax) +TRANS(vmax_h, ALL, gvec_vvv, MO_16, tcg_gen_gvec_smax) +TRANS(vmax_w, ALL, gvec_vvv, MO_32, tcg_gen_gvec_smax) +TRANS(vmax_d, ALL, gvec_vvv, MO_64, tcg_gen_gvec_smax) +TRANS(vmax_bu, ALL, gvec_vvv, MO_8, tcg_gen_gvec_umax) +TRANS(vmax_hu, ALL, gvec_vvv, MO_16, tcg_gen_gvec_umax) +TRANS(vmax_wu, ALL, gvec_vvv, MO_32, tcg_gen_gvec_umax) +TRANS(vmax_du, ALL, gvec_vvv, MO_64, tcg_gen_gvec_umax) -TRANS(vmin_b, gvec_vvv, MO_8, tcg_gen_gvec_smin) -TRANS(vmin_h, gvec_vvv, MO_16, tcg_gen_gvec_smin) -TRANS(vmin_w, gvec_vvv, MO_32, tcg_gen_gvec_smin) -TRANS(vmin_d, gvec_vvv, MO_64, tcg_gen_gvec_smin) -TRANS(vmin_bu, gvec_vvv, MO_8, tcg_gen_gvec_umin) -TRANS(vmin_hu, gvec_vvv, MO_16, tcg_gen_gvec_umin) -TRANS(vmin_wu, gvec_vvv, MO_32, tcg_gen_gvec_umin) -TRANS(vmin_du, gvec_vvv, MO_64, tcg_gen_gvec_umin) +TRANS(vmin_b, ALL, gvec_vvv, MO_8, tcg_gen_gvec_smin) +TRANS(vmin_h, ALL, gvec_vvv, MO_16, tcg_gen_gvec_smin) +TRANS(vmin_w, ALL, gvec_vvv, MO_32, tcg_gen_gvec_smin) +TRANS(vmin_d, ALL, gvec_vvv, MO_64, tcg_gen_gvec_smin) +TRANS(vmin_bu, ALL, gvec_vvv, MO_8, tcg_gen_gvec_umin) +TRANS(vmin_hu, ALL, gvec_vvv, MO_16, tcg_gen_gvec_umin) +TRANS(vmin_wu, ALL, gvec_vvv, MO_32, tcg_gen_gvec_umin) +TRANS(vmin_du, ALL, gvec_vvv, MO_64, tcg_gen_gvec_umin) static void gen_vmini_s(unsigned vece, TCGv_vec t, TCGv_vec a, int64_t imm) { @@ -1473,14 +1473,14 @@ static void do_vmini_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_2i(vd_ofs, vj_ofs, oprsz, maxsz, imm, &op[vece]); } -TRANS(vmini_b, gvec_vv_i, MO_8, do_vmini_s) -TRANS(vmini_h, gvec_vv_i, MO_16, do_vmini_s) -TRANS(vmini_w, gvec_vv_i, MO_32, do_vmini_s) -TRANS(vmini_d, gvec_vv_i, MO_64, do_vmini_s) -TRANS(vmini_bu, gvec_vv_i, MO_8, do_vmini_u) -TRANS(vmini_hu, gvec_vv_i, MO_16, do_vmini_u) -TRANS(vmini_wu, gvec_vv_i, MO_32, do_vmini_u) -TRANS(vmini_du, gvec_vv_i, MO_64, do_vmini_u) +TRANS(vmini_b, ALL, gvec_vv_i, MO_8, do_vmini_s) +TRANS(vmini_h, ALL, gvec_vv_i, MO_16, do_vmini_s) +TRANS(vmini_w, ALL, gvec_vv_i, MO_32, do_vmini_s) +TRANS(vmini_d, ALL, gvec_vv_i, MO_64, do_vmini_s) +TRANS(vmini_bu, ALL, gvec_vv_i, MO_8, do_vmini_u) +TRANS(vmini_hu, ALL, gvec_vv_i, MO_16, do_vmini_u) +TRANS(vmini_wu, ALL, gvec_vv_i, MO_32, do_vmini_u) +TRANS(vmini_du, ALL, gvec_vv_i, MO_64, do_vmini_u) static void do_vmaxi_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, int64_t imm, uint32_t oprsz, uint32_t maxsz) @@ -1554,19 +1554,19 @@ static void do_vmaxi_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_2i(vd_ofs, vj_ofs, oprsz, maxsz, imm, &op[vece]); } -TRANS(vmaxi_b, gvec_vv_i, MO_8, do_vmaxi_s) -TRANS(vmaxi_h, gvec_vv_i, MO_16, do_vmaxi_s) -TRANS(vmaxi_w, gvec_vv_i, MO_32, do_vmaxi_s) -TRANS(vmaxi_d, gvec_vv_i, MO_64, do_vmaxi_s) -TRANS(vmaxi_bu, gvec_vv_i, MO_8, do_vmaxi_u) -TRANS(vmaxi_hu, gvec_vv_i, MO_16, do_vmaxi_u) -TRANS(vmaxi_wu, gvec_vv_i, MO_32, do_vmaxi_u) -TRANS(vmaxi_du, gvec_vv_i, MO_64, do_vmaxi_u) +TRANS(vmaxi_b, ALL, gvec_vv_i, MO_8, do_vmaxi_s) +TRANS(vmaxi_h, ALL, gvec_vv_i, MO_16, do_vmaxi_s) +TRANS(vmaxi_w, ALL, gvec_vv_i, MO_32, do_vmaxi_s) +TRANS(vmaxi_d, ALL, gvec_vv_i, MO_64, do_vmaxi_s) +TRANS(vmaxi_bu, ALL, gvec_vv_i, MO_8, do_vmaxi_u) +TRANS(vmaxi_hu, ALL, gvec_vv_i, MO_16, do_vmaxi_u) +TRANS(vmaxi_wu, ALL, gvec_vv_i, MO_32, do_vmaxi_u) +TRANS(vmaxi_du, ALL, gvec_vv_i, MO_64, do_vmaxi_u) -TRANS(vmul_b, gvec_vvv, MO_8, tcg_gen_gvec_mul) -TRANS(vmul_h, gvec_vvv, MO_16, tcg_gen_gvec_mul) -TRANS(vmul_w, gvec_vvv, MO_32, tcg_gen_gvec_mul) -TRANS(vmul_d, gvec_vvv, MO_64, tcg_gen_gvec_mul) +TRANS(vmul_b, ALL, gvec_vvv, MO_8, tcg_gen_gvec_mul) +TRANS(vmul_h, ALL, gvec_vvv, MO_16, tcg_gen_gvec_mul) +TRANS(vmul_w, ALL, gvec_vvv, MO_32, tcg_gen_gvec_mul) +TRANS(vmul_d, ALL, gvec_vvv, MO_64, tcg_gen_gvec_mul) static void gen_vmuh_w(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) { @@ -1607,10 +1607,10 @@ static void do_vmuh_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vmuh_b, gvec_vvv, MO_8, do_vmuh_s) -TRANS(vmuh_h, gvec_vvv, MO_16, do_vmuh_s) -TRANS(vmuh_w, gvec_vvv, MO_32, do_vmuh_s) -TRANS(vmuh_d, gvec_vvv, MO_64, do_vmuh_s) +TRANS(vmuh_b, ALL, gvec_vvv, MO_8, do_vmuh_s) +TRANS(vmuh_h, ALL, gvec_vvv, MO_16, do_vmuh_s) +TRANS(vmuh_w, ALL, gvec_vvv, MO_32, do_vmuh_s) +TRANS(vmuh_d, ALL, gvec_vvv, MO_64, do_vmuh_s) static void gen_vmuh_wu(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) { @@ -1651,10 +1651,10 @@ static void do_vmuh_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vmuh_bu, gvec_vvv, MO_8, do_vmuh_u) -TRANS(vmuh_hu, gvec_vvv, MO_16, do_vmuh_u) -TRANS(vmuh_wu, gvec_vvv, MO_32, do_vmuh_u) -TRANS(vmuh_du, gvec_vvv, MO_64, do_vmuh_u) +TRANS(vmuh_bu, ALL, gvec_vvv, MO_8, do_vmuh_u) +TRANS(vmuh_hu, ALL, gvec_vvv, MO_16, do_vmuh_u) +TRANS(vmuh_wu, ALL, gvec_vvv, MO_32, do_vmuh_u) +TRANS(vmuh_du, ALL, gvec_vvv, MO_64, do_vmuh_u) static void gen_vmulwev_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -1724,9 +1724,9 @@ static void do_vmulwev_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vmulwev_h_b, gvec_vvv, MO_8, do_vmulwev_s) -TRANS(vmulwev_w_h, gvec_vvv, MO_16, do_vmulwev_s) -TRANS(vmulwev_d_w, gvec_vvv, MO_32, do_vmulwev_s) +TRANS(vmulwev_h_b, ALL, gvec_vvv, MO_8, do_vmulwev_s) +TRANS(vmulwev_w_h, ALL, gvec_vvv, MO_16, do_vmulwev_s) +TRANS(vmulwev_d_w, ALL, gvec_vvv, MO_32, do_vmulwev_s) static void tcg_gen_mulus2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2) @@ -1828,9 +1828,9 @@ static void do_vmulwod_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vmulwod_h_b, gvec_vvv, MO_8, do_vmulwod_s) -TRANS(vmulwod_w_h, gvec_vvv, MO_16, do_vmulwod_s) -TRANS(vmulwod_d_w, gvec_vvv, MO_32, do_vmulwod_s) +TRANS(vmulwod_h_b, ALL, gvec_vvv, MO_8, do_vmulwod_s) +TRANS(vmulwod_w_h, ALL, gvec_vvv, MO_16, do_vmulwod_s) +TRANS(vmulwod_d_w, ALL, gvec_vvv, MO_32, do_vmulwod_s) static void gen_vmulwev_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -1898,9 +1898,9 @@ static void do_vmulwev_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vmulwev_h_bu, gvec_vvv, MO_8, do_vmulwev_u) -TRANS(vmulwev_w_hu, gvec_vvv, MO_16, do_vmulwev_u) -TRANS(vmulwev_d_wu, gvec_vvv, MO_32, do_vmulwev_u) +TRANS(vmulwev_h_bu, ALL, gvec_vvv, MO_8, do_vmulwev_u) +TRANS(vmulwev_w_hu, ALL, gvec_vvv, MO_16, do_vmulwev_u) +TRANS(vmulwev_d_wu, ALL, gvec_vvv, MO_32, do_vmulwev_u) static void gen_vmulwod_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -1968,9 +1968,9 @@ static void do_vmulwod_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vmulwod_h_bu, gvec_vvv, MO_8, do_vmulwod_u) -TRANS(vmulwod_w_hu, gvec_vvv, MO_16, do_vmulwod_u) -TRANS(vmulwod_d_wu, gvec_vvv, MO_32, do_vmulwod_u) +TRANS(vmulwod_h_bu, ALL, gvec_vvv, MO_8, do_vmulwod_u) +TRANS(vmulwod_w_hu, ALL, gvec_vvv, MO_16, do_vmulwod_u) +TRANS(vmulwod_d_wu, ALL, gvec_vvv, MO_32, do_vmulwod_u) static void gen_vmulwev_u_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -2040,9 +2040,9 @@ static void do_vmulwev_u_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vmulwev_h_bu_b, gvec_vvv, MO_8, do_vmulwev_u_s) -TRANS(vmulwev_w_hu_h, gvec_vvv, MO_16, do_vmulwev_u_s) -TRANS(vmulwev_d_wu_w, gvec_vvv, MO_32, do_vmulwev_u_s) +TRANS(vmulwev_h_bu_b, ALL, gvec_vvv, MO_8, do_vmulwev_u_s) +TRANS(vmulwev_w_hu_h, ALL, gvec_vvv, MO_16, do_vmulwev_u_s) +TRANS(vmulwev_d_wu_w, ALL, gvec_vvv, MO_32, do_vmulwev_u_s) static void gen_vmulwod_u_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -2109,9 +2109,9 @@ static void do_vmulwod_u_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vmulwod_h_bu_b, gvec_vvv, MO_8, do_vmulwod_u_s) -TRANS(vmulwod_w_hu_h, gvec_vvv, MO_16, do_vmulwod_u_s) -TRANS(vmulwod_d_wu_w, gvec_vvv, MO_32, do_vmulwod_u_s) +TRANS(vmulwod_h_bu_b, ALL, gvec_vvv, MO_8, do_vmulwod_u_s) +TRANS(vmulwod_w_hu_h, ALL, gvec_vvv, MO_16, do_vmulwod_u_s) +TRANS(vmulwod_d_wu_w, ALL, gvec_vvv, MO_32, do_vmulwod_u_s) static void gen_vmadd(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -2182,10 +2182,10 @@ static void do_vmadd(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vmadd_b, gvec_vvv, MO_8, do_vmadd) -TRANS(vmadd_h, gvec_vvv, MO_16, do_vmadd) -TRANS(vmadd_w, gvec_vvv, MO_32, do_vmadd) -TRANS(vmadd_d, gvec_vvv, MO_64, do_vmadd) +TRANS(vmadd_b, ALL, gvec_vvv, MO_8, do_vmadd) +TRANS(vmadd_h, ALL, gvec_vvv, MO_16, do_vmadd) +TRANS(vmadd_w, ALL, gvec_vvv, MO_32, do_vmadd) +TRANS(vmadd_d, ALL, gvec_vvv, MO_64, do_vmadd) static void gen_vmsub(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -2256,10 +2256,10 @@ static void do_vmsub(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vmsub_b, gvec_vvv, MO_8, do_vmsub) -TRANS(vmsub_h, gvec_vvv, MO_16, do_vmsub) -TRANS(vmsub_w, gvec_vvv, MO_32, do_vmsub) -TRANS(vmsub_d, gvec_vvv, MO_64, do_vmsub) +TRANS(vmsub_b, ALL, gvec_vvv, MO_8, do_vmsub) +TRANS(vmsub_h, ALL, gvec_vvv, MO_16, do_vmsub) +TRANS(vmsub_w, ALL, gvec_vvv, MO_32, do_vmsub) +TRANS(vmsub_d, ALL, gvec_vvv, MO_64, do_vmsub) static void gen_vmaddwev_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -2331,9 +2331,9 @@ static void do_vmaddwev_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vmaddwev_h_b, gvec_vvv, MO_8, do_vmaddwev_s) -TRANS(vmaddwev_w_h, gvec_vvv, MO_16, do_vmaddwev_s) -TRANS(vmaddwev_d_w, gvec_vvv, MO_32, do_vmaddwev_s) +TRANS(vmaddwev_h_b, ALL, gvec_vvv, MO_8, do_vmaddwev_s) +TRANS(vmaddwev_w_h, ALL, gvec_vvv, MO_16, do_vmaddwev_s) +TRANS(vmaddwev_d_w, ALL, gvec_vvv, MO_32, do_vmaddwev_s) #define VMADD_Q(NAME, FN, idx1, idx2) \ static bool trans_## NAME (DisasContext *ctx, arg_vvv *a) \ @@ -2435,9 +2435,9 @@ static void do_vmaddwod_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vmaddwod_h_b, gvec_vvv, MO_8, do_vmaddwod_s) -TRANS(vmaddwod_w_h, gvec_vvv, MO_16, do_vmaddwod_s) -TRANS(vmaddwod_d_w, gvec_vvv, MO_32, do_vmaddwod_s) +TRANS(vmaddwod_h_b, ALL, gvec_vvv, MO_8, do_vmaddwod_s) +TRANS(vmaddwod_w_h, ALL, gvec_vvv, MO_16, do_vmaddwod_s) +TRANS(vmaddwod_d_w, ALL, gvec_vvv, MO_32, do_vmaddwod_s) static void gen_vmaddwev_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -2505,9 +2505,9 @@ static void do_vmaddwev_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vmaddwev_h_bu, gvec_vvv, MO_8, do_vmaddwev_u) -TRANS(vmaddwev_w_hu, gvec_vvv, MO_16, do_vmaddwev_u) -TRANS(vmaddwev_d_wu, gvec_vvv, MO_32, do_vmaddwev_u) +TRANS(vmaddwev_h_bu, ALL, gvec_vvv, MO_8, do_vmaddwev_u) +TRANS(vmaddwev_w_hu, ALL, gvec_vvv, MO_16, do_vmaddwev_u) +TRANS(vmaddwev_d_wu, ALL, gvec_vvv, MO_32, do_vmaddwev_u) static void gen_vmaddwod_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -2576,9 +2576,9 @@ static void do_vmaddwod_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vmaddwod_h_bu, gvec_vvv, MO_8, do_vmaddwod_u) -TRANS(vmaddwod_w_hu, gvec_vvv, MO_16, do_vmaddwod_u) -TRANS(vmaddwod_d_wu, gvec_vvv, MO_32, do_vmaddwod_u) +TRANS(vmaddwod_h_bu, ALL, gvec_vvv, MO_8, do_vmaddwod_u) +TRANS(vmaddwod_w_hu, ALL, gvec_vvv, MO_16, do_vmaddwod_u) +TRANS(vmaddwod_d_wu, ALL, gvec_vvv, MO_32, do_vmaddwod_u) static void gen_vmaddwev_u_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -2649,9 +2649,9 @@ static void do_vmaddwev_u_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vmaddwev_h_bu_b, gvec_vvv, MO_8, do_vmaddwev_u_s) -TRANS(vmaddwev_w_hu_h, gvec_vvv, MO_16, do_vmaddwev_u_s) -TRANS(vmaddwev_d_wu_w, gvec_vvv, MO_32, do_vmaddwev_u_s) +TRANS(vmaddwev_h_bu_b, ALL, gvec_vvv, MO_8, do_vmaddwev_u_s) +TRANS(vmaddwev_w_hu_h, ALL, gvec_vvv, MO_16, do_vmaddwev_u_s) +TRANS(vmaddwev_d_wu_w, ALL, gvec_vvv, MO_32, do_vmaddwev_u_s) static void gen_vmaddwod_u_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -2721,26 +2721,26 @@ static void do_vmaddwod_u_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vmaddwod_h_bu_b, gvec_vvv, MO_8, do_vmaddwod_u_s) -TRANS(vmaddwod_w_hu_h, gvec_vvv, MO_16, do_vmaddwod_u_s) -TRANS(vmaddwod_d_wu_w, gvec_vvv, MO_32, do_vmaddwod_u_s) +TRANS(vmaddwod_h_bu_b, ALL, gvec_vvv, MO_8, do_vmaddwod_u_s) +TRANS(vmaddwod_w_hu_h, ALL, gvec_vvv, MO_16, do_vmaddwod_u_s) +TRANS(vmaddwod_d_wu_w, ALL, gvec_vvv, MO_32, do_vmaddwod_u_s) -TRANS(vdiv_b, gen_vvv, gen_helper_vdiv_b) -TRANS(vdiv_h, gen_vvv, gen_helper_vdiv_h) -TRANS(vdiv_w, gen_vvv, gen_helper_vdiv_w) -TRANS(vdiv_d, gen_vvv, gen_helper_vdiv_d) -TRANS(vdiv_bu, gen_vvv, gen_helper_vdiv_bu) -TRANS(vdiv_hu, gen_vvv, gen_helper_vdiv_hu) -TRANS(vdiv_wu, gen_vvv, gen_helper_vdiv_wu) -TRANS(vdiv_du, gen_vvv, gen_helper_vdiv_du) -TRANS(vmod_b, gen_vvv, gen_helper_vmod_b) -TRANS(vmod_h, gen_vvv, gen_helper_vmod_h) -TRANS(vmod_w, gen_vvv, gen_helper_vmod_w) -TRANS(vmod_d, gen_vvv, gen_helper_vmod_d) -TRANS(vmod_bu, gen_vvv, gen_helper_vmod_bu) -TRANS(vmod_hu, gen_vvv, gen_helper_vmod_hu) -TRANS(vmod_wu, gen_vvv, gen_helper_vmod_wu) -TRANS(vmod_du, gen_vvv, gen_helper_vmod_du) +TRANS(vdiv_b, ALL, gen_vvv, gen_helper_vdiv_b) +TRANS(vdiv_h, ALL, gen_vvv, gen_helper_vdiv_h) +TRANS(vdiv_w, ALL, gen_vvv, gen_helper_vdiv_w) +TRANS(vdiv_d, ALL, gen_vvv, gen_helper_vdiv_d) +TRANS(vdiv_bu, ALL, gen_vvv, gen_helper_vdiv_bu) +TRANS(vdiv_hu, ALL, gen_vvv, gen_helper_vdiv_hu) +TRANS(vdiv_wu, ALL, gen_vvv, gen_helper_vdiv_wu) +TRANS(vdiv_du, ALL, gen_vvv, gen_helper_vdiv_du) +TRANS(vmod_b, ALL, gen_vvv, gen_helper_vmod_b) +TRANS(vmod_h, ALL, gen_vvv, gen_helper_vmod_h) +TRANS(vmod_w, ALL, gen_vvv, gen_helper_vmod_w) +TRANS(vmod_d, ALL, gen_vvv, gen_helper_vmod_d) +TRANS(vmod_bu, ALL, gen_vvv, gen_helper_vmod_bu) +TRANS(vmod_hu, ALL, gen_vvv, gen_helper_vmod_hu) +TRANS(vmod_wu, ALL, gen_vvv, gen_helper_vmod_wu) +TRANS(vmod_du, ALL, gen_vvv, gen_helper_vmod_du) static void gen_vsat_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec max) { @@ -2789,10 +2789,10 @@ static void do_vsat_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_constant_i64((1ll<< imm) -1), &op[vece]); } -TRANS(vsat_b, gvec_vv_i, MO_8, do_vsat_s) -TRANS(vsat_h, gvec_vv_i, MO_16, do_vsat_s) -TRANS(vsat_w, gvec_vv_i, MO_32, do_vsat_s) -TRANS(vsat_d, gvec_vv_i, MO_64, do_vsat_s) +TRANS(vsat_b, ALL, gvec_vv_i, MO_8, do_vsat_s) +TRANS(vsat_h, ALL, gvec_vv_i, MO_16, do_vsat_s) +TRANS(vsat_w, ALL, gvec_vv_i, MO_32, do_vsat_s) +TRANS(vsat_d, ALL, gvec_vv_i, MO_64, do_vsat_s) static void gen_vsat_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec max) { @@ -2838,19 +2838,19 @@ static void do_vsat_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_constant_i64(max), &op[vece]); } -TRANS(vsat_bu, gvec_vv_i, MO_8, do_vsat_u) -TRANS(vsat_hu, gvec_vv_i, MO_16, do_vsat_u) -TRANS(vsat_wu, gvec_vv_i, MO_32, do_vsat_u) -TRANS(vsat_du, gvec_vv_i, MO_64, do_vsat_u) +TRANS(vsat_bu, ALL, gvec_vv_i, MO_8, do_vsat_u) +TRANS(vsat_hu, ALL, gvec_vv_i, MO_16, do_vsat_u) +TRANS(vsat_wu, ALL, gvec_vv_i, MO_32, do_vsat_u) +TRANS(vsat_du, ALL, gvec_vv_i, MO_64, do_vsat_u) -TRANS(vexth_h_b, gen_vv, gen_helper_vexth_h_b) -TRANS(vexth_w_h, gen_vv, gen_helper_vexth_w_h) -TRANS(vexth_d_w, gen_vv, gen_helper_vexth_d_w) -TRANS(vexth_q_d, gen_vv, gen_helper_vexth_q_d) -TRANS(vexth_hu_bu, gen_vv, gen_helper_vexth_hu_bu) -TRANS(vexth_wu_hu, gen_vv, gen_helper_vexth_wu_hu) -TRANS(vexth_du_wu, gen_vv, gen_helper_vexth_du_wu) -TRANS(vexth_qu_du, gen_vv, gen_helper_vexth_qu_du) +TRANS(vexth_h_b, ALL, gen_vv, gen_helper_vexth_h_b) +TRANS(vexth_w_h, ALL, gen_vv, gen_helper_vexth_w_h) +TRANS(vexth_d_w, ALL, gen_vv, gen_helper_vexth_d_w) +TRANS(vexth_q_d, ALL, gen_vv, gen_helper_vexth_q_d) +TRANS(vexth_hu_bu, ALL, gen_vv, gen_helper_vexth_hu_bu) +TRANS(vexth_wu_hu, ALL, gen_vv, gen_helper_vexth_wu_hu) +TRANS(vexth_du_wu, ALL, gen_vv, gen_helper_vexth_du_wu) +TRANS(vexth_qu_du, ALL, gen_vv, gen_helper_vexth_qu_du) static void gen_vsigncov(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -2900,17 +2900,17 @@ static void do_vsigncov(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vsigncov_b, gvec_vvv, MO_8, do_vsigncov) -TRANS(vsigncov_h, gvec_vvv, MO_16, do_vsigncov) -TRANS(vsigncov_w, gvec_vvv, MO_32, do_vsigncov) -TRANS(vsigncov_d, gvec_vvv, MO_64, do_vsigncov) +TRANS(vsigncov_b, ALL, gvec_vvv, MO_8, do_vsigncov) +TRANS(vsigncov_h, ALL, gvec_vvv, MO_16, do_vsigncov) +TRANS(vsigncov_w, ALL, gvec_vvv, MO_32, do_vsigncov) +TRANS(vsigncov_d, ALL, gvec_vvv, MO_64, do_vsigncov) -TRANS(vmskltz_b, gen_vv, gen_helper_vmskltz_b) -TRANS(vmskltz_h, gen_vv, gen_helper_vmskltz_h) -TRANS(vmskltz_w, gen_vv, gen_helper_vmskltz_w) -TRANS(vmskltz_d, gen_vv, gen_helper_vmskltz_d) -TRANS(vmskgez_b, gen_vv, gen_helper_vmskgez_b) -TRANS(vmsknz_b, gen_vv, gen_helper_vmsknz_b) +TRANS(vmskltz_b, ALL, gen_vv, gen_helper_vmskltz_b) +TRANS(vmskltz_h, ALL, gen_vv, gen_helper_vmskltz_h) +TRANS(vmskltz_w, ALL, gen_vv, gen_helper_vmskltz_w) +TRANS(vmskltz_d, ALL, gen_vv, gen_helper_vmskltz_d) +TRANS(vmskgez_b, ALL, gen_vv, gen_helper_vmskgez_b) +TRANS(vmsknz_b, ALL, gen_vv, gen_helper_vmsknz_b) #define EXPAND_BYTE(bit) ((uint64_t)(bit ? 0xff : 0)) @@ -3049,10 +3049,10 @@ static bool trans_vldi(DisasContext *ctx, arg_vldi *a) return true; } -TRANS(vand_v, gvec_vvv, MO_64, tcg_gen_gvec_and) -TRANS(vor_v, gvec_vvv, MO_64, tcg_gen_gvec_or) -TRANS(vxor_v, gvec_vvv, MO_64, tcg_gen_gvec_xor) -TRANS(vnor_v, gvec_vvv, MO_64, tcg_gen_gvec_nor) +TRANS(vand_v, ALL, gvec_vvv, MO_64, tcg_gen_gvec_and) +TRANS(vor_v, ALL, gvec_vvv, MO_64, tcg_gen_gvec_or) +TRANS(vxor_v, ALL, gvec_vvv, MO_64, tcg_gen_gvec_xor) +TRANS(vnor_v, ALL, gvec_vvv, MO_64, tcg_gen_gvec_nor) static bool trans_vandn_v(DisasContext *ctx, arg_vvv *a) { @@ -3067,10 +3067,10 @@ static bool trans_vandn_v(DisasContext *ctx, arg_vvv *a) tcg_gen_gvec_andc(MO_64, vd_ofs, vk_ofs, vj_ofs, 16, ctx->vl/8); return true; } -TRANS(vorn_v, gvec_vvv, MO_64, tcg_gen_gvec_orc) -TRANS(vandi_b, gvec_vv_i, MO_8, tcg_gen_gvec_andi) -TRANS(vori_b, gvec_vv_i, MO_8, tcg_gen_gvec_ori) -TRANS(vxori_b, gvec_vv_i, MO_8, tcg_gen_gvec_xori) +TRANS(vorn_v, ALL, gvec_vvv, MO_64, tcg_gen_gvec_orc) +TRANS(vandi_b, ALL, gvec_vv_i, MO_8, tcg_gen_gvec_andi) +TRANS(vori_b, ALL, gvec_vv_i, MO_8, tcg_gen_gvec_ori) +TRANS(vxori_b, ALL, gvec_vv_i, MO_8, tcg_gen_gvec_xori) static void gen_vnori(unsigned vece, TCGv_vec t, TCGv_vec a, int64_t imm) { @@ -3103,176 +3103,176 @@ static void do_vnori_b(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_2i(vd_ofs, vj_ofs, oprsz, maxsz, imm, &op); } -TRANS(vnori_b, gvec_vv_i, MO_8, do_vnori_b) +TRANS(vnori_b, ALL, gvec_vv_i, MO_8, do_vnori_b) -TRANS(vsll_b, gvec_vvv, MO_8, tcg_gen_gvec_shlv) -TRANS(vsll_h, gvec_vvv, MO_16, tcg_gen_gvec_shlv) -TRANS(vsll_w, gvec_vvv, MO_32, tcg_gen_gvec_shlv) -TRANS(vsll_d, gvec_vvv, MO_64, tcg_gen_gvec_shlv) -TRANS(vslli_b, gvec_vv_i, MO_8, tcg_gen_gvec_shli) -TRANS(vslli_h, gvec_vv_i, MO_16, tcg_gen_gvec_shli) -TRANS(vslli_w, gvec_vv_i, MO_32, tcg_gen_gvec_shli) -TRANS(vslli_d, gvec_vv_i, MO_64, tcg_gen_gvec_shli) +TRANS(vsll_b, ALL, gvec_vvv, MO_8, tcg_gen_gvec_shlv) +TRANS(vsll_h, ALL, gvec_vvv, MO_16, tcg_gen_gvec_shlv) +TRANS(vsll_w, ALL, gvec_vvv, MO_32, tcg_gen_gvec_shlv) +TRANS(vsll_d, ALL, gvec_vvv, MO_64, tcg_gen_gvec_shlv) +TRANS(vslli_b, ALL, gvec_vv_i, MO_8, tcg_gen_gvec_shli) +TRANS(vslli_h, ALL, gvec_vv_i, MO_16, tcg_gen_gvec_shli) +TRANS(vslli_w, ALL, gvec_vv_i, MO_32, tcg_gen_gvec_shli) +TRANS(vslli_d, ALL, gvec_vv_i, MO_64, tcg_gen_gvec_shli) -TRANS(vsrl_b, gvec_vvv, MO_8, tcg_gen_gvec_shrv) -TRANS(vsrl_h, gvec_vvv, MO_16, tcg_gen_gvec_shrv) -TRANS(vsrl_w, gvec_vvv, MO_32, tcg_gen_gvec_shrv) -TRANS(vsrl_d, gvec_vvv, MO_64, tcg_gen_gvec_shrv) -TRANS(vsrli_b, gvec_vv_i, MO_8, tcg_gen_gvec_shri) -TRANS(vsrli_h, gvec_vv_i, MO_16, tcg_gen_gvec_shri) -TRANS(vsrli_w, gvec_vv_i, MO_32, tcg_gen_gvec_shri) -TRANS(vsrli_d, gvec_vv_i, MO_64, tcg_gen_gvec_shri) +TRANS(vsrl_b, ALL, gvec_vvv, MO_8, tcg_gen_gvec_shrv) +TRANS(vsrl_h, ALL, gvec_vvv, MO_16, tcg_gen_gvec_shrv) +TRANS(vsrl_w, ALL, gvec_vvv, MO_32, tcg_gen_gvec_shrv) +TRANS(vsrl_d, ALL, gvec_vvv, MO_64, tcg_gen_gvec_shrv) +TRANS(vsrli_b, ALL, gvec_vv_i, MO_8, tcg_gen_gvec_shri) +TRANS(vsrli_h, ALL, gvec_vv_i, MO_16, tcg_gen_gvec_shri) +TRANS(vsrli_w, ALL, gvec_vv_i, MO_32, tcg_gen_gvec_shri) +TRANS(vsrli_d, ALL, gvec_vv_i, MO_64, tcg_gen_gvec_shri) -TRANS(vsra_b, gvec_vvv, MO_8, tcg_gen_gvec_sarv) -TRANS(vsra_h, gvec_vvv, MO_16, tcg_gen_gvec_sarv) -TRANS(vsra_w, gvec_vvv, MO_32, tcg_gen_gvec_sarv) -TRANS(vsra_d, gvec_vvv, MO_64, tcg_gen_gvec_sarv) -TRANS(vsrai_b, gvec_vv_i, MO_8, tcg_gen_gvec_sari) -TRANS(vsrai_h, gvec_vv_i, MO_16, tcg_gen_gvec_sari) -TRANS(vsrai_w, gvec_vv_i, MO_32, tcg_gen_gvec_sari) -TRANS(vsrai_d, gvec_vv_i, MO_64, tcg_gen_gvec_sari) +TRANS(vsra_b, ALL, gvec_vvv, MO_8, tcg_gen_gvec_sarv) +TRANS(vsra_h, ALL, gvec_vvv, MO_16, tcg_gen_gvec_sarv) +TRANS(vsra_w, ALL, gvec_vvv, MO_32, tcg_gen_gvec_sarv) +TRANS(vsra_d, ALL, gvec_vvv, MO_64, tcg_gen_gvec_sarv) +TRANS(vsrai_b, ALL, gvec_vv_i, MO_8, tcg_gen_gvec_sari) +TRANS(vsrai_h, ALL, gvec_vv_i, MO_16, tcg_gen_gvec_sari) +TRANS(vsrai_w, ALL, gvec_vv_i, MO_32, tcg_gen_gvec_sari) +TRANS(vsrai_d, ALL, gvec_vv_i, MO_64, tcg_gen_gvec_sari) -TRANS(vrotr_b, gvec_vvv, MO_8, tcg_gen_gvec_rotrv) -TRANS(vrotr_h, gvec_vvv, MO_16, tcg_gen_gvec_rotrv) -TRANS(vrotr_w, gvec_vvv, MO_32, tcg_gen_gvec_rotrv) -TRANS(vrotr_d, gvec_vvv, MO_64, tcg_gen_gvec_rotrv) -TRANS(vrotri_b, gvec_vv_i, MO_8, tcg_gen_gvec_rotri) -TRANS(vrotri_h, gvec_vv_i, MO_16, tcg_gen_gvec_rotri) -TRANS(vrotri_w, gvec_vv_i, MO_32, tcg_gen_gvec_rotri) -TRANS(vrotri_d, gvec_vv_i, MO_64, tcg_gen_gvec_rotri) +TRANS(vrotr_b, ALL, gvec_vvv, MO_8, tcg_gen_gvec_rotrv) +TRANS(vrotr_h, ALL, gvec_vvv, MO_16, tcg_gen_gvec_rotrv) +TRANS(vrotr_w, ALL, gvec_vvv, MO_32, tcg_gen_gvec_rotrv) +TRANS(vrotr_d, ALL, gvec_vvv, MO_64, tcg_gen_gvec_rotrv) +TRANS(vrotri_b, ALL, gvec_vv_i, MO_8, tcg_gen_gvec_rotri) +TRANS(vrotri_h, ALL, gvec_vv_i, MO_16, tcg_gen_gvec_rotri) +TRANS(vrotri_w, ALL, gvec_vv_i, MO_32, tcg_gen_gvec_rotri) +TRANS(vrotri_d, ALL, gvec_vv_i, MO_64, tcg_gen_gvec_rotri) -TRANS(vsllwil_h_b, gen_vv_i, gen_helper_vsllwil_h_b) -TRANS(vsllwil_w_h, gen_vv_i, gen_helper_vsllwil_w_h) -TRANS(vsllwil_d_w, gen_vv_i, gen_helper_vsllwil_d_w) -TRANS(vextl_q_d, gen_vv, gen_helper_vextl_q_d) -TRANS(vsllwil_hu_bu, gen_vv_i, gen_helper_vsllwil_hu_bu) -TRANS(vsllwil_wu_hu, gen_vv_i, gen_helper_vsllwil_wu_hu) -TRANS(vsllwil_du_wu, gen_vv_i, gen_helper_vsllwil_du_wu) -TRANS(vextl_qu_du, gen_vv, gen_helper_vextl_qu_du) +TRANS(vsllwil_h_b, ALL, gen_vv_i, gen_helper_vsllwil_h_b) +TRANS(vsllwil_w_h, ALL, gen_vv_i, gen_helper_vsllwil_w_h) +TRANS(vsllwil_d_w, ALL, gen_vv_i, gen_helper_vsllwil_d_w) +TRANS(vextl_q_d, ALL, gen_vv, gen_helper_vextl_q_d) +TRANS(vsllwil_hu_bu, ALL, gen_vv_i, gen_helper_vsllwil_hu_bu) +TRANS(vsllwil_wu_hu, ALL, gen_vv_i, gen_helper_vsllwil_wu_hu) +TRANS(vsllwil_du_wu, ALL, gen_vv_i, gen_helper_vsllwil_du_wu) +TRANS(vextl_qu_du, ALL, gen_vv, gen_helper_vextl_qu_du) -TRANS(vsrlr_b, gen_vvv, gen_helper_vsrlr_b) -TRANS(vsrlr_h, gen_vvv, gen_helper_vsrlr_h) -TRANS(vsrlr_w, gen_vvv, gen_helper_vsrlr_w) -TRANS(vsrlr_d, gen_vvv, gen_helper_vsrlr_d) -TRANS(vsrlri_b, gen_vv_i, gen_helper_vsrlri_b) -TRANS(vsrlri_h, gen_vv_i, gen_helper_vsrlri_h) -TRANS(vsrlri_w, gen_vv_i, gen_helper_vsrlri_w) -TRANS(vsrlri_d, gen_vv_i, gen_helper_vsrlri_d) +TRANS(vsrlr_b, ALL, gen_vvv, gen_helper_vsrlr_b) +TRANS(vsrlr_h, ALL, gen_vvv, gen_helper_vsrlr_h) +TRANS(vsrlr_w, ALL, gen_vvv, gen_helper_vsrlr_w) +TRANS(vsrlr_d, ALL, gen_vvv, gen_helper_vsrlr_d) +TRANS(vsrlri_b, ALL, gen_vv_i, gen_helper_vsrlri_b) +TRANS(vsrlri_h, ALL, gen_vv_i, gen_helper_vsrlri_h) +TRANS(vsrlri_w, ALL, gen_vv_i, gen_helper_vsrlri_w) +TRANS(vsrlri_d, ALL, gen_vv_i, gen_helper_vsrlri_d) -TRANS(vsrar_b, gen_vvv, gen_helper_vsrar_b) -TRANS(vsrar_h, gen_vvv, gen_helper_vsrar_h) -TRANS(vsrar_w, gen_vvv, gen_helper_vsrar_w) -TRANS(vsrar_d, gen_vvv, gen_helper_vsrar_d) -TRANS(vsrari_b, gen_vv_i, gen_helper_vsrari_b) -TRANS(vsrari_h, gen_vv_i, gen_helper_vsrari_h) -TRANS(vsrari_w, gen_vv_i, gen_helper_vsrari_w) -TRANS(vsrari_d, gen_vv_i, gen_helper_vsrari_d) +TRANS(vsrar_b, ALL, gen_vvv, gen_helper_vsrar_b) +TRANS(vsrar_h, ALL, gen_vvv, gen_helper_vsrar_h) +TRANS(vsrar_w, ALL, gen_vvv, gen_helper_vsrar_w) +TRANS(vsrar_d, ALL, gen_vvv, gen_helper_vsrar_d) +TRANS(vsrari_b, ALL, gen_vv_i, gen_helper_vsrari_b) +TRANS(vsrari_h, ALL, gen_vv_i, gen_helper_vsrari_h) +TRANS(vsrari_w, ALL, gen_vv_i, gen_helper_vsrari_w) +TRANS(vsrari_d, ALL, gen_vv_i, gen_helper_vsrari_d) -TRANS(vsrln_b_h, gen_vvv, gen_helper_vsrln_b_h) -TRANS(vsrln_h_w, gen_vvv, gen_helper_vsrln_h_w) -TRANS(vsrln_w_d, gen_vvv, gen_helper_vsrln_w_d) -TRANS(vsran_b_h, gen_vvv, gen_helper_vsran_b_h) -TRANS(vsran_h_w, gen_vvv, gen_helper_vsran_h_w) -TRANS(vsran_w_d, gen_vvv, gen_helper_vsran_w_d) +TRANS(vsrln_b_h, ALL, gen_vvv, gen_helper_vsrln_b_h) +TRANS(vsrln_h_w, ALL, gen_vvv, gen_helper_vsrln_h_w) +TRANS(vsrln_w_d, ALL, gen_vvv, gen_helper_vsrln_w_d) +TRANS(vsran_b_h, ALL, gen_vvv, gen_helper_vsran_b_h) +TRANS(vsran_h_w, ALL, gen_vvv, gen_helper_vsran_h_w) +TRANS(vsran_w_d, ALL, gen_vvv, gen_helper_vsran_w_d) -TRANS(vsrlni_b_h, gen_vv_i, gen_helper_vsrlni_b_h) -TRANS(vsrlni_h_w, gen_vv_i, gen_helper_vsrlni_h_w) -TRANS(vsrlni_w_d, gen_vv_i, gen_helper_vsrlni_w_d) -TRANS(vsrlni_d_q, gen_vv_i, gen_helper_vsrlni_d_q) -TRANS(vsrani_b_h, gen_vv_i, gen_helper_vsrani_b_h) -TRANS(vsrani_h_w, gen_vv_i, gen_helper_vsrani_h_w) -TRANS(vsrani_w_d, gen_vv_i, gen_helper_vsrani_w_d) -TRANS(vsrani_d_q, gen_vv_i, gen_helper_vsrani_d_q) +TRANS(vsrlni_b_h, ALL, gen_vv_i, gen_helper_vsrlni_b_h) +TRANS(vsrlni_h_w, ALL, gen_vv_i, gen_helper_vsrlni_h_w) +TRANS(vsrlni_w_d, ALL, gen_vv_i, gen_helper_vsrlni_w_d) +TRANS(vsrlni_d_q, ALL, gen_vv_i, gen_helper_vsrlni_d_q) +TRANS(vsrani_b_h, ALL, gen_vv_i, gen_helper_vsrani_b_h) +TRANS(vsrani_h_w, ALL, gen_vv_i, gen_helper_vsrani_h_w) +TRANS(vsrani_w_d, ALL, gen_vv_i, gen_helper_vsrani_w_d) +TRANS(vsrani_d_q, ALL, gen_vv_i, gen_helper_vsrani_d_q) -TRANS(vsrlrn_b_h, gen_vvv, gen_helper_vsrlrn_b_h) -TRANS(vsrlrn_h_w, gen_vvv, gen_helper_vsrlrn_h_w) -TRANS(vsrlrn_w_d, gen_vvv, gen_helper_vsrlrn_w_d) -TRANS(vsrarn_b_h, gen_vvv, gen_helper_vsrarn_b_h) -TRANS(vsrarn_h_w, gen_vvv, gen_helper_vsrarn_h_w) -TRANS(vsrarn_w_d, gen_vvv, gen_helper_vsrarn_w_d) +TRANS(vsrlrn_b_h, ALL, gen_vvv, gen_helper_vsrlrn_b_h) +TRANS(vsrlrn_h_w, ALL, gen_vvv, gen_helper_vsrlrn_h_w) +TRANS(vsrlrn_w_d, ALL, gen_vvv, gen_helper_vsrlrn_w_d) +TRANS(vsrarn_b_h, ALL, gen_vvv, gen_helper_vsrarn_b_h) +TRANS(vsrarn_h_w, ALL, gen_vvv, gen_helper_vsrarn_h_w) +TRANS(vsrarn_w_d, ALL, gen_vvv, gen_helper_vsrarn_w_d) -TRANS(vsrlrni_b_h, gen_vv_i, gen_helper_vsrlrni_b_h) -TRANS(vsrlrni_h_w, gen_vv_i, gen_helper_vsrlrni_h_w) -TRANS(vsrlrni_w_d, gen_vv_i, gen_helper_vsrlrni_w_d) -TRANS(vsrlrni_d_q, gen_vv_i, gen_helper_vsrlrni_d_q) -TRANS(vsrarni_b_h, gen_vv_i, gen_helper_vsrarni_b_h) -TRANS(vsrarni_h_w, gen_vv_i, gen_helper_vsrarni_h_w) -TRANS(vsrarni_w_d, gen_vv_i, gen_helper_vsrarni_w_d) -TRANS(vsrarni_d_q, gen_vv_i, gen_helper_vsrarni_d_q) +TRANS(vsrlrni_b_h, ALL, gen_vv_i, gen_helper_vsrlrni_b_h) +TRANS(vsrlrni_h_w, ALL, gen_vv_i, gen_helper_vsrlrni_h_w) +TRANS(vsrlrni_w_d, ALL, gen_vv_i, gen_helper_vsrlrni_w_d) +TRANS(vsrlrni_d_q, ALL, gen_vv_i, gen_helper_vsrlrni_d_q) +TRANS(vsrarni_b_h, ALL, gen_vv_i, gen_helper_vsrarni_b_h) +TRANS(vsrarni_h_w, ALL, gen_vv_i, gen_helper_vsrarni_h_w) +TRANS(vsrarni_w_d, ALL, gen_vv_i, gen_helper_vsrarni_w_d) +TRANS(vsrarni_d_q, ALL, gen_vv_i, gen_helper_vsrarni_d_q) -TRANS(vssrln_b_h, gen_vvv, gen_helper_vssrln_b_h) -TRANS(vssrln_h_w, gen_vvv, gen_helper_vssrln_h_w) -TRANS(vssrln_w_d, gen_vvv, gen_helper_vssrln_w_d) -TRANS(vssran_b_h, gen_vvv, gen_helper_vssran_b_h) -TRANS(vssran_h_w, gen_vvv, gen_helper_vssran_h_w) -TRANS(vssran_w_d, gen_vvv, gen_helper_vssran_w_d) -TRANS(vssrln_bu_h, gen_vvv, gen_helper_vssrln_bu_h) -TRANS(vssrln_hu_w, gen_vvv, gen_helper_vssrln_hu_w) -TRANS(vssrln_wu_d, gen_vvv, gen_helper_vssrln_wu_d) -TRANS(vssran_bu_h, gen_vvv, gen_helper_vssran_bu_h) -TRANS(vssran_hu_w, gen_vvv, gen_helper_vssran_hu_w) -TRANS(vssran_wu_d, gen_vvv, gen_helper_vssran_wu_d) +TRANS(vssrln_b_h, ALL, gen_vvv, gen_helper_vssrln_b_h) +TRANS(vssrln_h_w, ALL, gen_vvv, gen_helper_vssrln_h_w) +TRANS(vssrln_w_d, ALL, gen_vvv, gen_helper_vssrln_w_d) +TRANS(vssran_b_h, ALL, gen_vvv, gen_helper_vssran_b_h) +TRANS(vssran_h_w, ALL, gen_vvv, gen_helper_vssran_h_w) +TRANS(vssran_w_d, ALL, gen_vvv, gen_helper_vssran_w_d) +TRANS(vssrln_bu_h, ALL, gen_vvv, gen_helper_vssrln_bu_h) +TRANS(vssrln_hu_w, ALL, gen_vvv, gen_helper_vssrln_hu_w) +TRANS(vssrln_wu_d, ALL, gen_vvv, gen_helper_vssrln_wu_d) +TRANS(vssran_bu_h, ALL, gen_vvv, gen_helper_vssran_bu_h) +TRANS(vssran_hu_w, ALL, gen_vvv, gen_helper_vssran_hu_w) +TRANS(vssran_wu_d, ALL, gen_vvv, gen_helper_vssran_wu_d) -TRANS(vssrlni_b_h, gen_vv_i, gen_helper_vssrlni_b_h) -TRANS(vssrlni_h_w, gen_vv_i, gen_helper_vssrlni_h_w) -TRANS(vssrlni_w_d, gen_vv_i, gen_helper_vssrlni_w_d) -TRANS(vssrlni_d_q, gen_vv_i, gen_helper_vssrlni_d_q) -TRANS(vssrani_b_h, gen_vv_i, gen_helper_vssrani_b_h) -TRANS(vssrani_h_w, gen_vv_i, gen_helper_vssrani_h_w) -TRANS(vssrani_w_d, gen_vv_i, gen_helper_vssrani_w_d) -TRANS(vssrani_d_q, gen_vv_i, gen_helper_vssrani_d_q) -TRANS(vssrlni_bu_h, gen_vv_i, gen_helper_vssrlni_bu_h) -TRANS(vssrlni_hu_w, gen_vv_i, gen_helper_vssrlni_hu_w) -TRANS(vssrlni_wu_d, gen_vv_i, gen_helper_vssrlni_wu_d) -TRANS(vssrlni_du_q, gen_vv_i, gen_helper_vssrlni_du_q) -TRANS(vssrani_bu_h, gen_vv_i, gen_helper_vssrani_bu_h) -TRANS(vssrani_hu_w, gen_vv_i, gen_helper_vssrani_hu_w) -TRANS(vssrani_wu_d, gen_vv_i, gen_helper_vssrani_wu_d) -TRANS(vssrani_du_q, gen_vv_i, gen_helper_vssrani_du_q) +TRANS(vssrlni_b_h, ALL, gen_vv_i, gen_helper_vssrlni_b_h) +TRANS(vssrlni_h_w, ALL, gen_vv_i, gen_helper_vssrlni_h_w) +TRANS(vssrlni_w_d, ALL, gen_vv_i, gen_helper_vssrlni_w_d) +TRANS(vssrlni_d_q, ALL, gen_vv_i, gen_helper_vssrlni_d_q) +TRANS(vssrani_b_h, ALL, gen_vv_i, gen_helper_vssrani_b_h) +TRANS(vssrani_h_w, ALL, gen_vv_i, gen_helper_vssrani_h_w) +TRANS(vssrani_w_d, ALL, gen_vv_i, gen_helper_vssrani_w_d) +TRANS(vssrani_d_q, ALL, gen_vv_i, gen_helper_vssrani_d_q) +TRANS(vssrlni_bu_h, ALL, gen_vv_i, gen_helper_vssrlni_bu_h) +TRANS(vssrlni_hu_w, ALL, gen_vv_i, gen_helper_vssrlni_hu_w) +TRANS(vssrlni_wu_d, ALL, gen_vv_i, gen_helper_vssrlni_wu_d) +TRANS(vssrlni_du_q, ALL, gen_vv_i, gen_helper_vssrlni_du_q) +TRANS(vssrani_bu_h, ALL, gen_vv_i, gen_helper_vssrani_bu_h) +TRANS(vssrani_hu_w, ALL, gen_vv_i, gen_helper_vssrani_hu_w) +TRANS(vssrani_wu_d, ALL, gen_vv_i, gen_helper_vssrani_wu_d) +TRANS(vssrani_du_q, ALL, gen_vv_i, gen_helper_vssrani_du_q) -TRANS(vssrlrn_b_h, gen_vvv, gen_helper_vssrlrn_b_h) -TRANS(vssrlrn_h_w, gen_vvv, gen_helper_vssrlrn_h_w) -TRANS(vssrlrn_w_d, gen_vvv, gen_helper_vssrlrn_w_d) -TRANS(vssrarn_b_h, gen_vvv, gen_helper_vssrarn_b_h) -TRANS(vssrarn_h_w, gen_vvv, gen_helper_vssrarn_h_w) -TRANS(vssrarn_w_d, gen_vvv, gen_helper_vssrarn_w_d) -TRANS(vssrlrn_bu_h, gen_vvv, gen_helper_vssrlrn_bu_h) -TRANS(vssrlrn_hu_w, gen_vvv, gen_helper_vssrlrn_hu_w) -TRANS(vssrlrn_wu_d, gen_vvv, gen_helper_vssrlrn_wu_d) -TRANS(vssrarn_bu_h, gen_vvv, gen_helper_vssrarn_bu_h) -TRANS(vssrarn_hu_w, gen_vvv, gen_helper_vssrarn_hu_w) -TRANS(vssrarn_wu_d, gen_vvv, gen_helper_vssrarn_wu_d) +TRANS(vssrlrn_b_h, ALL, gen_vvv, gen_helper_vssrlrn_b_h) +TRANS(vssrlrn_h_w, ALL, gen_vvv, gen_helper_vssrlrn_h_w) +TRANS(vssrlrn_w_d, ALL, gen_vvv, gen_helper_vssrlrn_w_d) +TRANS(vssrarn_b_h, ALL, gen_vvv, gen_helper_vssrarn_b_h) +TRANS(vssrarn_h_w, ALL, gen_vvv, gen_helper_vssrarn_h_w) +TRANS(vssrarn_w_d, ALL, gen_vvv, gen_helper_vssrarn_w_d) +TRANS(vssrlrn_bu_h, ALL, gen_vvv, gen_helper_vssrlrn_bu_h) +TRANS(vssrlrn_hu_w, ALL, gen_vvv, gen_helper_vssrlrn_hu_w) +TRANS(vssrlrn_wu_d, ALL, gen_vvv, gen_helper_vssrlrn_wu_d) +TRANS(vssrarn_bu_h, ALL, gen_vvv, gen_helper_vssrarn_bu_h) +TRANS(vssrarn_hu_w, ALL, gen_vvv, gen_helper_vssrarn_hu_w) +TRANS(vssrarn_wu_d, ALL, gen_vvv, gen_helper_vssrarn_wu_d) -TRANS(vssrlrni_b_h, gen_vv_i, gen_helper_vssrlrni_b_h) -TRANS(vssrlrni_h_w, gen_vv_i, gen_helper_vssrlrni_h_w) -TRANS(vssrlrni_w_d, gen_vv_i, gen_helper_vssrlrni_w_d) -TRANS(vssrlrni_d_q, gen_vv_i, gen_helper_vssrlrni_d_q) -TRANS(vssrarni_b_h, gen_vv_i, gen_helper_vssrarni_b_h) -TRANS(vssrarni_h_w, gen_vv_i, gen_helper_vssrarni_h_w) -TRANS(vssrarni_w_d, gen_vv_i, gen_helper_vssrarni_w_d) -TRANS(vssrarni_d_q, gen_vv_i, gen_helper_vssrarni_d_q) -TRANS(vssrlrni_bu_h, gen_vv_i, gen_helper_vssrlrni_bu_h) -TRANS(vssrlrni_hu_w, gen_vv_i, gen_helper_vssrlrni_hu_w) -TRANS(vssrlrni_wu_d, gen_vv_i, gen_helper_vssrlrni_wu_d) -TRANS(vssrlrni_du_q, gen_vv_i, gen_helper_vssrlrni_du_q) -TRANS(vssrarni_bu_h, gen_vv_i, gen_helper_vssrarni_bu_h) -TRANS(vssrarni_hu_w, gen_vv_i, gen_helper_vssrarni_hu_w) -TRANS(vssrarni_wu_d, gen_vv_i, gen_helper_vssrarni_wu_d) -TRANS(vssrarni_du_q, gen_vv_i, gen_helper_vssrarni_du_q) +TRANS(vssrlrni_b_h, ALL, gen_vv_i, gen_helper_vssrlrni_b_h) +TRANS(vssrlrni_h_w, ALL, gen_vv_i, gen_helper_vssrlrni_h_w) +TRANS(vssrlrni_w_d, ALL, gen_vv_i, gen_helper_vssrlrni_w_d) +TRANS(vssrlrni_d_q, ALL, gen_vv_i, gen_helper_vssrlrni_d_q) +TRANS(vssrarni_b_h, ALL, gen_vv_i, gen_helper_vssrarni_b_h) +TRANS(vssrarni_h_w, ALL, gen_vv_i, gen_helper_vssrarni_h_w) +TRANS(vssrarni_w_d, ALL, gen_vv_i, gen_helper_vssrarni_w_d) +TRANS(vssrarni_d_q, ALL, gen_vv_i, gen_helper_vssrarni_d_q) +TRANS(vssrlrni_bu_h, ALL, gen_vv_i, gen_helper_vssrlrni_bu_h) +TRANS(vssrlrni_hu_w, ALL, gen_vv_i, gen_helper_vssrlrni_hu_w) +TRANS(vssrlrni_wu_d, ALL, gen_vv_i, gen_helper_vssrlrni_wu_d) +TRANS(vssrlrni_du_q, ALL, gen_vv_i, gen_helper_vssrlrni_du_q) +TRANS(vssrarni_bu_h, ALL, gen_vv_i, gen_helper_vssrarni_bu_h) +TRANS(vssrarni_hu_w, ALL, gen_vv_i, gen_helper_vssrarni_hu_w) +TRANS(vssrarni_wu_d, ALL, gen_vv_i, gen_helper_vssrarni_wu_d) +TRANS(vssrarni_du_q, ALL, gen_vv_i, gen_helper_vssrarni_du_q) -TRANS(vclo_b, gen_vv, gen_helper_vclo_b) -TRANS(vclo_h, gen_vv, gen_helper_vclo_h) -TRANS(vclo_w, gen_vv, gen_helper_vclo_w) -TRANS(vclo_d, gen_vv, gen_helper_vclo_d) -TRANS(vclz_b, gen_vv, gen_helper_vclz_b) -TRANS(vclz_h, gen_vv, gen_helper_vclz_h) -TRANS(vclz_w, gen_vv, gen_helper_vclz_w) -TRANS(vclz_d, gen_vv, gen_helper_vclz_d) +TRANS(vclo_b, ALL, gen_vv, gen_helper_vclo_b) +TRANS(vclo_h, ALL, gen_vv, gen_helper_vclo_h) +TRANS(vclo_w, ALL, gen_vv, gen_helper_vclo_w) +TRANS(vclo_d, ALL, gen_vv, gen_helper_vclo_d) +TRANS(vclz_b, ALL, gen_vv, gen_helper_vclz_b) +TRANS(vclz_h, ALL, gen_vv, gen_helper_vclz_h) +TRANS(vclz_w, ALL, gen_vv, gen_helper_vclz_w) +TRANS(vclz_d, ALL, gen_vv, gen_helper_vclz_d) -TRANS(vpcnt_b, gen_vv, gen_helper_vpcnt_b) -TRANS(vpcnt_h, gen_vv, gen_helper_vpcnt_h) -TRANS(vpcnt_w, gen_vv, gen_helper_vpcnt_w) -TRANS(vpcnt_d, gen_vv, gen_helper_vpcnt_d) +TRANS(vpcnt_b, ALL, gen_vv, gen_helper_vpcnt_b) +TRANS(vpcnt_h, ALL, gen_vv, gen_helper_vpcnt_h) +TRANS(vpcnt_w, ALL, gen_vv, gen_helper_vpcnt_w) +TRANS(vpcnt_d, ALL, gen_vv, gen_helper_vpcnt_d) static void do_vbit(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b, void (*func)(unsigned, TCGv_vec, TCGv_vec, TCGv_vec)) @@ -3340,10 +3340,10 @@ static void do_vbitclr(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vbitclr_b, gvec_vvv, MO_8, do_vbitclr) -TRANS(vbitclr_h, gvec_vvv, MO_16, do_vbitclr) -TRANS(vbitclr_w, gvec_vvv, MO_32, do_vbitclr) -TRANS(vbitclr_d, gvec_vvv, MO_64, do_vbitclr) +TRANS(vbitclr_b, ALL, gvec_vvv, MO_8, do_vbitclr) +TRANS(vbitclr_h, ALL, gvec_vvv, MO_16, do_vbitclr) +TRANS(vbitclr_w, ALL, gvec_vvv, MO_32, do_vbitclr) +TRANS(vbitclr_d, ALL, gvec_vvv, MO_64, do_vbitclr) static void do_vbiti(unsigned vece, TCGv_vec t, TCGv_vec a, int64_t imm, void (*func)(unsigned, TCGv_vec, TCGv_vec, TCGv_vec)) @@ -3410,10 +3410,10 @@ static void do_vbitclri(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_2i(vd_ofs, vj_ofs, oprsz, maxsz, imm, &op[vece]); } -TRANS(vbitclri_b, gvec_vv_i, MO_8, do_vbitclri) -TRANS(vbitclri_h, gvec_vv_i, MO_16, do_vbitclri) -TRANS(vbitclri_w, gvec_vv_i, MO_32, do_vbitclri) -TRANS(vbitclri_d, gvec_vv_i, MO_64, do_vbitclri) +TRANS(vbitclri_b, ALL, gvec_vv_i, MO_8, do_vbitclri) +TRANS(vbitclri_h, ALL, gvec_vv_i, MO_16, do_vbitclri) +TRANS(vbitclri_w, ALL, gvec_vv_i, MO_32, do_vbitclri) +TRANS(vbitclri_d, ALL, gvec_vv_i, MO_64, do_vbitclri) static void do_vbitset(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) @@ -3451,10 +3451,10 @@ static void do_vbitset(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vbitset_b, gvec_vvv, MO_8, do_vbitset) -TRANS(vbitset_h, gvec_vvv, MO_16, do_vbitset) -TRANS(vbitset_w, gvec_vvv, MO_32, do_vbitset) -TRANS(vbitset_d, gvec_vvv, MO_64, do_vbitset) +TRANS(vbitset_b, ALL, gvec_vvv, MO_8, do_vbitset) +TRANS(vbitset_h, ALL, gvec_vvv, MO_16, do_vbitset) +TRANS(vbitset_w, ALL, gvec_vvv, MO_32, do_vbitset) +TRANS(vbitset_d, ALL, gvec_vvv, MO_64, do_vbitset) static void do_vbitseti(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, int64_t imm, uint32_t oprsz, uint32_t maxsz) @@ -3492,10 +3492,10 @@ static void do_vbitseti(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_2i(vd_ofs, vj_ofs, oprsz, maxsz, imm, &op[vece]); } -TRANS(vbitseti_b, gvec_vv_i, MO_8, do_vbitseti) -TRANS(vbitseti_h, gvec_vv_i, MO_16, do_vbitseti) -TRANS(vbitseti_w, gvec_vv_i, MO_32, do_vbitseti) -TRANS(vbitseti_d, gvec_vv_i, MO_64, do_vbitseti) +TRANS(vbitseti_b, ALL, gvec_vv_i, MO_8, do_vbitseti) +TRANS(vbitseti_h, ALL, gvec_vv_i, MO_16, do_vbitseti) +TRANS(vbitseti_w, ALL, gvec_vv_i, MO_32, do_vbitseti) +TRANS(vbitseti_d, ALL, gvec_vv_i, MO_64, do_vbitseti) static void do_vbitrev(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) @@ -3533,10 +3533,10 @@ static void do_vbitrev(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vbitrev_b, gvec_vvv, MO_8, do_vbitrev) -TRANS(vbitrev_h, gvec_vvv, MO_16, do_vbitrev) -TRANS(vbitrev_w, gvec_vvv, MO_32, do_vbitrev) -TRANS(vbitrev_d, gvec_vvv, MO_64, do_vbitrev) +TRANS(vbitrev_b, ALL, gvec_vvv, MO_8, do_vbitrev) +TRANS(vbitrev_h, ALL, gvec_vvv, MO_16, do_vbitrev) +TRANS(vbitrev_w, ALL, gvec_vvv, MO_32, do_vbitrev) +TRANS(vbitrev_d, ALL, gvec_vvv, MO_64, do_vbitrev) static void do_vbitrevi(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, int64_t imm, uint32_t oprsz, uint32_t maxsz) @@ -3574,112 +3574,112 @@ static void do_vbitrevi(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_2i(vd_ofs, vj_ofs, oprsz, maxsz, imm, &op[vece]); } -TRANS(vbitrevi_b, gvec_vv_i, MO_8, do_vbitrevi) -TRANS(vbitrevi_h, gvec_vv_i, MO_16, do_vbitrevi) -TRANS(vbitrevi_w, gvec_vv_i, MO_32, do_vbitrevi) -TRANS(vbitrevi_d, gvec_vv_i, MO_64, do_vbitrevi) +TRANS(vbitrevi_b, ALL, gvec_vv_i, MO_8, do_vbitrevi) +TRANS(vbitrevi_h, ALL, gvec_vv_i, MO_16, do_vbitrevi) +TRANS(vbitrevi_w, ALL, gvec_vv_i, MO_32, do_vbitrevi) +TRANS(vbitrevi_d, ALL, gvec_vv_i, MO_64, do_vbitrevi) -TRANS(vfrstp_b, gen_vvv, gen_helper_vfrstp_b) -TRANS(vfrstp_h, gen_vvv, gen_helper_vfrstp_h) -TRANS(vfrstpi_b, gen_vv_i, gen_helper_vfrstpi_b) -TRANS(vfrstpi_h, gen_vv_i, gen_helper_vfrstpi_h) +TRANS(vfrstp_b, ALL, gen_vvv, gen_helper_vfrstp_b) +TRANS(vfrstp_h, ALL, gen_vvv, gen_helper_vfrstp_h) +TRANS(vfrstpi_b, ALL, gen_vv_i, gen_helper_vfrstpi_b) +TRANS(vfrstpi_h, ALL, gen_vv_i, gen_helper_vfrstpi_h) -TRANS(vfadd_s, gen_vvv, gen_helper_vfadd_s) -TRANS(vfadd_d, gen_vvv, gen_helper_vfadd_d) -TRANS(vfsub_s, gen_vvv, gen_helper_vfsub_s) -TRANS(vfsub_d, gen_vvv, gen_helper_vfsub_d) -TRANS(vfmul_s, gen_vvv, gen_helper_vfmul_s) -TRANS(vfmul_d, gen_vvv, gen_helper_vfmul_d) -TRANS(vfdiv_s, gen_vvv, gen_helper_vfdiv_s) -TRANS(vfdiv_d, gen_vvv, gen_helper_vfdiv_d) +TRANS(vfadd_s, ALL, gen_vvv, gen_helper_vfadd_s) +TRANS(vfadd_d, ALL, gen_vvv, gen_helper_vfadd_d) +TRANS(vfsub_s, ALL, gen_vvv, gen_helper_vfsub_s) +TRANS(vfsub_d, ALL, gen_vvv, gen_helper_vfsub_d) +TRANS(vfmul_s, ALL, gen_vvv, gen_helper_vfmul_s) +TRANS(vfmul_d, ALL, gen_vvv, gen_helper_vfmul_d) +TRANS(vfdiv_s, ALL, gen_vvv, gen_helper_vfdiv_s) +TRANS(vfdiv_d, ALL, gen_vvv, gen_helper_vfdiv_d) -TRANS(vfmadd_s, gen_vvvv, gen_helper_vfmadd_s) -TRANS(vfmadd_d, gen_vvvv, gen_helper_vfmadd_d) -TRANS(vfmsub_s, gen_vvvv, gen_helper_vfmsub_s) -TRANS(vfmsub_d, gen_vvvv, gen_helper_vfmsub_d) -TRANS(vfnmadd_s, gen_vvvv, gen_helper_vfnmadd_s) -TRANS(vfnmadd_d, gen_vvvv, gen_helper_vfnmadd_d) -TRANS(vfnmsub_s, gen_vvvv, gen_helper_vfnmsub_s) -TRANS(vfnmsub_d, gen_vvvv, gen_helper_vfnmsub_d) +TRANS(vfmadd_s, ALL, gen_vvvv, gen_helper_vfmadd_s) +TRANS(vfmadd_d, ALL, gen_vvvv, gen_helper_vfmadd_d) +TRANS(vfmsub_s, ALL, gen_vvvv, gen_helper_vfmsub_s) +TRANS(vfmsub_d, ALL, gen_vvvv, gen_helper_vfmsub_d) +TRANS(vfnmadd_s, ALL, gen_vvvv, gen_helper_vfnmadd_s) +TRANS(vfnmadd_d, ALL, gen_vvvv, gen_helper_vfnmadd_d) +TRANS(vfnmsub_s, ALL, gen_vvvv, gen_helper_vfnmsub_s) +TRANS(vfnmsub_d, ALL, gen_vvvv, gen_helper_vfnmsub_d) -TRANS(vfmax_s, gen_vvv, gen_helper_vfmax_s) -TRANS(vfmax_d, gen_vvv, gen_helper_vfmax_d) -TRANS(vfmin_s, gen_vvv, gen_helper_vfmin_s) -TRANS(vfmin_d, gen_vvv, gen_helper_vfmin_d) +TRANS(vfmax_s, ALL, gen_vvv, gen_helper_vfmax_s) +TRANS(vfmax_d, ALL, gen_vvv, gen_helper_vfmax_d) +TRANS(vfmin_s, ALL, gen_vvv, gen_helper_vfmin_s) +TRANS(vfmin_d, ALL, gen_vvv, gen_helper_vfmin_d) -TRANS(vfmaxa_s, gen_vvv, gen_helper_vfmaxa_s) -TRANS(vfmaxa_d, gen_vvv, gen_helper_vfmaxa_d) -TRANS(vfmina_s, gen_vvv, gen_helper_vfmina_s) -TRANS(vfmina_d, gen_vvv, gen_helper_vfmina_d) +TRANS(vfmaxa_s, ALL, gen_vvv, gen_helper_vfmaxa_s) +TRANS(vfmaxa_d, ALL, gen_vvv, gen_helper_vfmaxa_d) +TRANS(vfmina_s, ALL, gen_vvv, gen_helper_vfmina_s) +TRANS(vfmina_d, ALL, gen_vvv, gen_helper_vfmina_d) -TRANS(vflogb_s, gen_vv, gen_helper_vflogb_s) -TRANS(vflogb_d, gen_vv, gen_helper_vflogb_d) +TRANS(vflogb_s, ALL, gen_vv, gen_helper_vflogb_s) +TRANS(vflogb_d, ALL, gen_vv, gen_helper_vflogb_d) -TRANS(vfclass_s, gen_vv, gen_helper_vfclass_s) -TRANS(vfclass_d, gen_vv, gen_helper_vfclass_d) +TRANS(vfclass_s, ALL, gen_vv, gen_helper_vfclass_s) +TRANS(vfclass_d, ALL, gen_vv, gen_helper_vfclass_d) -TRANS(vfsqrt_s, gen_vv, gen_helper_vfsqrt_s) -TRANS(vfsqrt_d, gen_vv, gen_helper_vfsqrt_d) -TRANS(vfrecip_s, gen_vv, gen_helper_vfrecip_s) -TRANS(vfrecip_d, gen_vv, gen_helper_vfrecip_d) -TRANS(vfrsqrt_s, gen_vv, gen_helper_vfrsqrt_s) -TRANS(vfrsqrt_d, gen_vv, gen_helper_vfrsqrt_d) +TRANS(vfsqrt_s, ALL, gen_vv, gen_helper_vfsqrt_s) +TRANS(vfsqrt_d, ALL, gen_vv, gen_helper_vfsqrt_d) +TRANS(vfrecip_s, ALL, gen_vv, gen_helper_vfrecip_s) +TRANS(vfrecip_d, ALL, gen_vv, gen_helper_vfrecip_d) +TRANS(vfrsqrt_s, ALL, gen_vv, gen_helper_vfrsqrt_s) +TRANS(vfrsqrt_d, ALL, gen_vv, gen_helper_vfrsqrt_d) -TRANS(vfcvtl_s_h, gen_vv, gen_helper_vfcvtl_s_h) -TRANS(vfcvth_s_h, gen_vv, gen_helper_vfcvth_s_h) -TRANS(vfcvtl_d_s, gen_vv, gen_helper_vfcvtl_d_s) -TRANS(vfcvth_d_s, gen_vv, gen_helper_vfcvth_d_s) -TRANS(vfcvt_h_s, gen_vvv, gen_helper_vfcvt_h_s) -TRANS(vfcvt_s_d, gen_vvv, gen_helper_vfcvt_s_d) +TRANS(vfcvtl_s_h, ALL, gen_vv, gen_helper_vfcvtl_s_h) +TRANS(vfcvth_s_h, ALL, gen_vv, gen_helper_vfcvth_s_h) +TRANS(vfcvtl_d_s, ALL, gen_vv, gen_helper_vfcvtl_d_s) +TRANS(vfcvth_d_s, ALL, gen_vv, gen_helper_vfcvth_d_s) +TRANS(vfcvt_h_s, ALL, gen_vvv, gen_helper_vfcvt_h_s) +TRANS(vfcvt_s_d, ALL, gen_vvv, gen_helper_vfcvt_s_d) -TRANS(vfrintrne_s, gen_vv, gen_helper_vfrintrne_s) -TRANS(vfrintrne_d, gen_vv, gen_helper_vfrintrne_d) -TRANS(vfrintrz_s, gen_vv, gen_helper_vfrintrz_s) -TRANS(vfrintrz_d, gen_vv, gen_helper_vfrintrz_d) -TRANS(vfrintrp_s, gen_vv, gen_helper_vfrintrp_s) -TRANS(vfrintrp_d, gen_vv, gen_helper_vfrintrp_d) -TRANS(vfrintrm_s, gen_vv, gen_helper_vfrintrm_s) -TRANS(vfrintrm_d, gen_vv, gen_helper_vfrintrm_d) -TRANS(vfrint_s, gen_vv, gen_helper_vfrint_s) -TRANS(vfrint_d, gen_vv, gen_helper_vfrint_d) +TRANS(vfrintrne_s, ALL, gen_vv, gen_helper_vfrintrne_s) +TRANS(vfrintrne_d, ALL, gen_vv, gen_helper_vfrintrne_d) +TRANS(vfrintrz_s, ALL, gen_vv, gen_helper_vfrintrz_s) +TRANS(vfrintrz_d, ALL, gen_vv, gen_helper_vfrintrz_d) +TRANS(vfrintrp_s, ALL, gen_vv, gen_helper_vfrintrp_s) +TRANS(vfrintrp_d, ALL, gen_vv, gen_helper_vfrintrp_d) +TRANS(vfrintrm_s, ALL, gen_vv, gen_helper_vfrintrm_s) +TRANS(vfrintrm_d, ALL, gen_vv, gen_helper_vfrintrm_d) +TRANS(vfrint_s, ALL, gen_vv, gen_helper_vfrint_s) +TRANS(vfrint_d, ALL, gen_vv, gen_helper_vfrint_d) -TRANS(vftintrne_w_s, gen_vv, gen_helper_vftintrne_w_s) -TRANS(vftintrne_l_d, gen_vv, gen_helper_vftintrne_l_d) -TRANS(vftintrz_w_s, gen_vv, gen_helper_vftintrz_w_s) -TRANS(vftintrz_l_d, gen_vv, gen_helper_vftintrz_l_d) -TRANS(vftintrp_w_s, gen_vv, gen_helper_vftintrp_w_s) -TRANS(vftintrp_l_d, gen_vv, gen_helper_vftintrp_l_d) -TRANS(vftintrm_w_s, gen_vv, gen_helper_vftintrm_w_s) -TRANS(vftintrm_l_d, gen_vv, gen_helper_vftintrm_l_d) -TRANS(vftint_w_s, gen_vv, gen_helper_vftint_w_s) -TRANS(vftint_l_d, gen_vv, gen_helper_vftint_l_d) -TRANS(vftintrz_wu_s, gen_vv, gen_helper_vftintrz_wu_s) -TRANS(vftintrz_lu_d, gen_vv, gen_helper_vftintrz_lu_d) -TRANS(vftint_wu_s, gen_vv, gen_helper_vftint_wu_s) -TRANS(vftint_lu_d, gen_vv, gen_helper_vftint_lu_d) -TRANS(vftintrne_w_d, gen_vvv, gen_helper_vftintrne_w_d) -TRANS(vftintrz_w_d, gen_vvv, gen_helper_vftintrz_w_d) -TRANS(vftintrp_w_d, gen_vvv, gen_helper_vftintrp_w_d) -TRANS(vftintrm_w_d, gen_vvv, gen_helper_vftintrm_w_d) -TRANS(vftint_w_d, gen_vvv, gen_helper_vftint_w_d) -TRANS(vftintrnel_l_s, gen_vv, gen_helper_vftintrnel_l_s) -TRANS(vftintrneh_l_s, gen_vv, gen_helper_vftintrneh_l_s) -TRANS(vftintrzl_l_s, gen_vv, gen_helper_vftintrzl_l_s) -TRANS(vftintrzh_l_s, gen_vv, gen_helper_vftintrzh_l_s) -TRANS(vftintrpl_l_s, gen_vv, gen_helper_vftintrpl_l_s) -TRANS(vftintrph_l_s, gen_vv, gen_helper_vftintrph_l_s) -TRANS(vftintrml_l_s, gen_vv, gen_helper_vftintrml_l_s) -TRANS(vftintrmh_l_s, gen_vv, gen_helper_vftintrmh_l_s) -TRANS(vftintl_l_s, gen_vv, gen_helper_vftintl_l_s) -TRANS(vftinth_l_s, gen_vv, gen_helper_vftinth_l_s) +TRANS(vftintrne_w_s, ALL, gen_vv, gen_helper_vftintrne_w_s) +TRANS(vftintrne_l_d, ALL, gen_vv, gen_helper_vftintrne_l_d) +TRANS(vftintrz_w_s, ALL, gen_vv, gen_helper_vftintrz_w_s) +TRANS(vftintrz_l_d, ALL, gen_vv, gen_helper_vftintrz_l_d) +TRANS(vftintrp_w_s, ALL, gen_vv, gen_helper_vftintrp_w_s) +TRANS(vftintrp_l_d, ALL, gen_vv, gen_helper_vftintrp_l_d) +TRANS(vftintrm_w_s, ALL, gen_vv, gen_helper_vftintrm_w_s) +TRANS(vftintrm_l_d, ALL, gen_vv, gen_helper_vftintrm_l_d) +TRANS(vftint_w_s, ALL, gen_vv, gen_helper_vftint_w_s) +TRANS(vftint_l_d, ALL, gen_vv, gen_helper_vftint_l_d) +TRANS(vftintrz_wu_s, ALL, gen_vv, gen_helper_vftintrz_wu_s) +TRANS(vftintrz_lu_d, ALL, gen_vv, gen_helper_vftintrz_lu_d) +TRANS(vftint_wu_s, ALL, gen_vv, gen_helper_vftint_wu_s) +TRANS(vftint_lu_d, ALL, gen_vv, gen_helper_vftint_lu_d) +TRANS(vftintrne_w_d, ALL, gen_vvv, gen_helper_vftintrne_w_d) +TRANS(vftintrz_w_d, ALL, gen_vvv, gen_helper_vftintrz_w_d) +TRANS(vftintrp_w_d, ALL, gen_vvv, gen_helper_vftintrp_w_d) +TRANS(vftintrm_w_d, ALL, gen_vvv, gen_helper_vftintrm_w_d) +TRANS(vftint_w_d, ALL, gen_vvv, gen_helper_vftint_w_d) +TRANS(vftintrnel_l_s, ALL, gen_vv, gen_helper_vftintrnel_l_s) +TRANS(vftintrneh_l_s, ALL, gen_vv, gen_helper_vftintrneh_l_s) +TRANS(vftintrzl_l_s, ALL, gen_vv, gen_helper_vftintrzl_l_s) +TRANS(vftintrzh_l_s, ALL, gen_vv, gen_helper_vftintrzh_l_s) +TRANS(vftintrpl_l_s, ALL, gen_vv, gen_helper_vftintrpl_l_s) +TRANS(vftintrph_l_s, ALL, gen_vv, gen_helper_vftintrph_l_s) +TRANS(vftintrml_l_s, ALL, gen_vv, gen_helper_vftintrml_l_s) +TRANS(vftintrmh_l_s, ALL, gen_vv, gen_helper_vftintrmh_l_s) +TRANS(vftintl_l_s, ALL, gen_vv, gen_helper_vftintl_l_s) +TRANS(vftinth_l_s, ALL, gen_vv, gen_helper_vftinth_l_s) -TRANS(vffint_s_w, gen_vv, gen_helper_vffint_s_w) -TRANS(vffint_d_l, gen_vv, gen_helper_vffint_d_l) -TRANS(vffint_s_wu, gen_vv, gen_helper_vffint_s_wu) -TRANS(vffint_d_lu, gen_vv, gen_helper_vffint_d_lu) -TRANS(vffintl_d_w, gen_vv, gen_helper_vffintl_d_w) -TRANS(vffinth_d_w, gen_vv, gen_helper_vffinth_d_w) -TRANS(vffint_s_l, gen_vvv, gen_helper_vffint_s_l) +TRANS(vffint_s_w, ALL, gen_vv, gen_helper_vffint_s_w) +TRANS(vffint_d_l, ALL, gen_vv, gen_helper_vffint_d_l) +TRANS(vffint_s_wu, ALL, gen_vv, gen_helper_vffint_s_wu) +TRANS(vffint_d_lu, ALL, gen_vv, gen_helper_vffint_d_lu) +TRANS(vffintl_d_w, ALL, gen_vv, gen_helper_vffintl_d_w) +TRANS(vffinth_d_w, ALL, gen_vv, gen_helper_vffinth_d_w) +TRANS(vffint_s_l, ALL, gen_vvv, gen_helper_vffint_s_l) static bool do_cmp(DisasContext *ctx, arg_vvv *a, MemOp mop, TCGCond cond) { @@ -3823,48 +3823,48 @@ static bool do_## NAME ##_u(DisasContext *ctx, arg_vv_i *a, MemOp mop) \ DO_CMPI_U(vslei) DO_CMPI_U(vslti) -TRANS(vseq_b, do_cmp, MO_8, TCG_COND_EQ) -TRANS(vseq_h, do_cmp, MO_16, TCG_COND_EQ) -TRANS(vseq_w, do_cmp, MO_32, TCG_COND_EQ) -TRANS(vseq_d, do_cmp, MO_64, TCG_COND_EQ) -TRANS(vseqi_b, do_vseqi_s, MO_8) -TRANS(vseqi_h, do_vseqi_s, MO_16) -TRANS(vseqi_w, do_vseqi_s, MO_32) -TRANS(vseqi_d, do_vseqi_s, MO_64) +TRANS(vseq_b, ALL, do_cmp, MO_8, TCG_COND_EQ) +TRANS(vseq_h, ALL, do_cmp, MO_16, TCG_COND_EQ) +TRANS(vseq_w, ALL, do_cmp, MO_32, TCG_COND_EQ) +TRANS(vseq_d, ALL, do_cmp, MO_64, TCG_COND_EQ) +TRANS(vseqi_b, ALL, do_vseqi_s, MO_8) +TRANS(vseqi_h, ALL, do_vseqi_s, MO_16) +TRANS(vseqi_w, ALL, do_vseqi_s, MO_32) +TRANS(vseqi_d, ALL, do_vseqi_s, MO_64) -TRANS(vsle_b, do_cmp, MO_8, TCG_COND_LE) -TRANS(vsle_h, do_cmp, MO_16, TCG_COND_LE) -TRANS(vsle_w, do_cmp, MO_32, TCG_COND_LE) -TRANS(vsle_d, do_cmp, MO_64, TCG_COND_LE) -TRANS(vslei_b, do_vslei_s, MO_8) -TRANS(vslei_h, do_vslei_s, MO_16) -TRANS(vslei_w, do_vslei_s, MO_32) -TRANS(vslei_d, do_vslei_s, MO_64) -TRANS(vsle_bu, do_cmp, MO_8, TCG_COND_LEU) -TRANS(vsle_hu, do_cmp, MO_16, TCG_COND_LEU) -TRANS(vsle_wu, do_cmp, MO_32, TCG_COND_LEU) -TRANS(vsle_du, do_cmp, MO_64, TCG_COND_LEU) -TRANS(vslei_bu, do_vslei_u, MO_8) -TRANS(vslei_hu, do_vslei_u, MO_16) -TRANS(vslei_wu, do_vslei_u, MO_32) -TRANS(vslei_du, do_vslei_u, MO_64) +TRANS(vsle_b, ALL, do_cmp, MO_8, TCG_COND_LE) +TRANS(vsle_h, ALL, do_cmp, MO_16, TCG_COND_LE) +TRANS(vsle_w, ALL, do_cmp, MO_32, TCG_COND_LE) +TRANS(vsle_d, ALL, do_cmp, MO_64, TCG_COND_LE) +TRANS(vslei_b, ALL, do_vslei_s, MO_8) +TRANS(vslei_h, ALL, do_vslei_s, MO_16) +TRANS(vslei_w, ALL, do_vslei_s, MO_32) +TRANS(vslei_d, ALL, do_vslei_s, MO_64) +TRANS(vsle_bu, ALL, do_cmp, MO_8, TCG_COND_LEU) +TRANS(vsle_hu, ALL, do_cmp, MO_16, TCG_COND_LEU) +TRANS(vsle_wu, ALL, do_cmp, MO_32, TCG_COND_LEU) +TRANS(vsle_du, ALL, do_cmp, MO_64, TCG_COND_LEU) +TRANS(vslei_bu, ALL, do_vslei_u, MO_8) +TRANS(vslei_hu, ALL, do_vslei_u, MO_16) +TRANS(vslei_wu, ALL, do_vslei_u, MO_32) +TRANS(vslei_du, ALL, do_vslei_u, MO_64) -TRANS(vslt_b, do_cmp, MO_8, TCG_COND_LT) -TRANS(vslt_h, do_cmp, MO_16, TCG_COND_LT) -TRANS(vslt_w, do_cmp, MO_32, TCG_COND_LT) -TRANS(vslt_d, do_cmp, MO_64, TCG_COND_LT) -TRANS(vslti_b, do_vslti_s, MO_8) -TRANS(vslti_h, do_vslti_s, MO_16) -TRANS(vslti_w, do_vslti_s, MO_32) -TRANS(vslti_d, do_vslti_s, MO_64) -TRANS(vslt_bu, do_cmp, MO_8, TCG_COND_LTU) -TRANS(vslt_hu, do_cmp, MO_16, TCG_COND_LTU) -TRANS(vslt_wu, do_cmp, MO_32, TCG_COND_LTU) -TRANS(vslt_du, do_cmp, MO_64, TCG_COND_LTU) -TRANS(vslti_bu, do_vslti_u, MO_8) -TRANS(vslti_hu, do_vslti_u, MO_16) -TRANS(vslti_wu, do_vslti_u, MO_32) -TRANS(vslti_du, do_vslti_u, MO_64) +TRANS(vslt_b, ALL, do_cmp, MO_8, TCG_COND_LT) +TRANS(vslt_h, ALL, do_cmp, MO_16, TCG_COND_LT) +TRANS(vslt_w, ALL, do_cmp, MO_32, TCG_COND_LT) +TRANS(vslt_d, ALL, do_cmp, MO_64, TCG_COND_LT) +TRANS(vslti_b, ALL, do_vslti_s, MO_8) +TRANS(vslti_h, ALL, do_vslti_s, MO_16) +TRANS(vslti_w, ALL, do_vslti_s, MO_32) +TRANS(vslti_d, ALL, do_vslti_s, MO_64) +TRANS(vslt_bu, ALL, do_cmp, MO_8, TCG_COND_LTU) +TRANS(vslt_hu, ALL, do_cmp, MO_16, TCG_COND_LTU) +TRANS(vslt_wu, ALL, do_cmp, MO_32, TCG_COND_LTU) +TRANS(vslt_du, ALL, do_cmp, MO_64, TCG_COND_LTU) +TRANS(vslti_bu, ALL, do_vslti_u, MO_8) +TRANS(vslti_hu, ALL, do_vslti_u, MO_16) +TRANS(vslti_wu, ALL, do_vslti_u, MO_32) +TRANS(vslti_du, ALL, do_vslti_u, MO_64) static bool trans_vfcmp_cond_s(DisasContext *ctx, arg_vvv_fcond *a) { @@ -3952,14 +3952,14 @@ static bool trans_## NAME (DisasContext *ctx, arg_cv *a) \ VSET(vseteqz_v, TCG_COND_EQ) VSET(vsetnez_v, TCG_COND_NE) -TRANS(vsetanyeqz_b, gen_cv, gen_helper_vsetanyeqz_b) -TRANS(vsetanyeqz_h, gen_cv, gen_helper_vsetanyeqz_h) -TRANS(vsetanyeqz_w, gen_cv, gen_helper_vsetanyeqz_w) -TRANS(vsetanyeqz_d, gen_cv, gen_helper_vsetanyeqz_d) -TRANS(vsetallnez_b, gen_cv, gen_helper_vsetallnez_b) -TRANS(vsetallnez_h, gen_cv, gen_helper_vsetallnez_h) -TRANS(vsetallnez_w, gen_cv, gen_helper_vsetallnez_w) -TRANS(vsetallnez_d, gen_cv, gen_helper_vsetallnez_d) +TRANS(vsetanyeqz_b, ALL, gen_cv, gen_helper_vsetanyeqz_b) +TRANS(vsetanyeqz_h, ALL, gen_cv, gen_helper_vsetanyeqz_h) +TRANS(vsetanyeqz_w, ALL, gen_cv, gen_helper_vsetanyeqz_w) +TRANS(vsetanyeqz_d, ALL, gen_cv, gen_helper_vsetanyeqz_d) +TRANS(vsetallnez_b, ALL, gen_cv, gen_helper_vsetallnez_b) +TRANS(vsetallnez_h, ALL, gen_cv, gen_helper_vsetallnez_h) +TRANS(vsetallnez_w, ALL, gen_cv, gen_helper_vsetallnez_w) +TRANS(vsetallnez_d, ALL, gen_cv, gen_helper_vsetallnez_d) static bool trans_vinsgr2vr_b(DisasContext *ctx, arg_vr_i *a) { @@ -4079,10 +4079,10 @@ static bool gvec_dup(DisasContext *ctx, arg_vr *a, MemOp mop) return true; } -TRANS(vreplgr2vr_b, gvec_dup, MO_8) -TRANS(vreplgr2vr_h, gvec_dup, MO_16) -TRANS(vreplgr2vr_w, gvec_dup, MO_32) -TRANS(vreplgr2vr_d, gvec_dup, MO_64) +TRANS(vreplgr2vr_b, ALL, gvec_dup, MO_8) +TRANS(vreplgr2vr_h, ALL, gvec_dup, MO_16) +TRANS(vreplgr2vr_w, ALL, gvec_dup, MO_32) +TRANS(vreplgr2vr_d, ALL, gvec_dup, MO_64) static bool trans_vreplvei_b(DisasContext *ctx, arg_vv_i *a) { @@ -4145,10 +4145,10 @@ static bool gen_vreplve(DisasContext *ctx, arg_vvr *a, int vece, int bit, return true; } -TRANS(vreplve_b, gen_vreplve, MO_8, 8, tcg_gen_ld8u_i64) -TRANS(vreplve_h, gen_vreplve, MO_16, 16, tcg_gen_ld16u_i64) -TRANS(vreplve_w, gen_vreplve, MO_32, 32, tcg_gen_ld32u_i64) -TRANS(vreplve_d, gen_vreplve, MO_64, 64, tcg_gen_ld_i64) +TRANS(vreplve_b, ALL, gen_vreplve, MO_8, 8, tcg_gen_ld8u_i64) +TRANS(vreplve_h, ALL, gen_vreplve, MO_16, 16, tcg_gen_ld16u_i64) +TRANS(vreplve_w, ALL, gen_vreplve, MO_32, 32, tcg_gen_ld32u_i64) +TRANS(vreplve_d, ALL, gen_vreplve, MO_64, 64, tcg_gen_ld_i64) static bool trans_vbsll_v(DisasContext *ctx, arg_vv_i *a) { @@ -4210,48 +4210,48 @@ static bool trans_vbsrl_v(DisasContext *ctx, arg_vv_i *a) return true; } -TRANS(vpackev_b, gen_vvv, gen_helper_vpackev_b) -TRANS(vpackev_h, gen_vvv, gen_helper_vpackev_h) -TRANS(vpackev_w, gen_vvv, gen_helper_vpackev_w) -TRANS(vpackev_d, gen_vvv, gen_helper_vpackev_d) -TRANS(vpackod_b, gen_vvv, gen_helper_vpackod_b) -TRANS(vpackod_h, gen_vvv, gen_helper_vpackod_h) -TRANS(vpackod_w, gen_vvv, gen_helper_vpackod_w) -TRANS(vpackod_d, gen_vvv, gen_helper_vpackod_d) +TRANS(vpackev_b, ALL, gen_vvv, gen_helper_vpackev_b) +TRANS(vpackev_h, ALL, gen_vvv, gen_helper_vpackev_h) +TRANS(vpackev_w, ALL, gen_vvv, gen_helper_vpackev_w) +TRANS(vpackev_d, ALL, gen_vvv, gen_helper_vpackev_d) +TRANS(vpackod_b, ALL, gen_vvv, gen_helper_vpackod_b) +TRANS(vpackod_h, ALL, gen_vvv, gen_helper_vpackod_h) +TRANS(vpackod_w, ALL, gen_vvv, gen_helper_vpackod_w) +TRANS(vpackod_d, ALL, gen_vvv, gen_helper_vpackod_d) -TRANS(vpickev_b, gen_vvv, gen_helper_vpickev_b) -TRANS(vpickev_h, gen_vvv, gen_helper_vpickev_h) -TRANS(vpickev_w, gen_vvv, gen_helper_vpickev_w) -TRANS(vpickev_d, gen_vvv, gen_helper_vpickev_d) -TRANS(vpickod_b, gen_vvv, gen_helper_vpickod_b) -TRANS(vpickod_h, gen_vvv, gen_helper_vpickod_h) -TRANS(vpickod_w, gen_vvv, gen_helper_vpickod_w) -TRANS(vpickod_d, gen_vvv, gen_helper_vpickod_d) +TRANS(vpickev_b, ALL, gen_vvv, gen_helper_vpickev_b) +TRANS(vpickev_h, ALL, gen_vvv, gen_helper_vpickev_h) +TRANS(vpickev_w, ALL, gen_vvv, gen_helper_vpickev_w) +TRANS(vpickev_d, ALL, gen_vvv, gen_helper_vpickev_d) +TRANS(vpickod_b, ALL, gen_vvv, gen_helper_vpickod_b) +TRANS(vpickod_h, ALL, gen_vvv, gen_helper_vpickod_h) +TRANS(vpickod_w, ALL, gen_vvv, gen_helper_vpickod_w) +TRANS(vpickod_d, ALL, gen_vvv, gen_helper_vpickod_d) -TRANS(vilvl_b, gen_vvv, gen_helper_vilvl_b) -TRANS(vilvl_h, gen_vvv, gen_helper_vilvl_h) -TRANS(vilvl_w, gen_vvv, gen_helper_vilvl_w) -TRANS(vilvl_d, gen_vvv, gen_helper_vilvl_d) -TRANS(vilvh_b, gen_vvv, gen_helper_vilvh_b) -TRANS(vilvh_h, gen_vvv, gen_helper_vilvh_h) -TRANS(vilvh_w, gen_vvv, gen_helper_vilvh_w) -TRANS(vilvh_d, gen_vvv, gen_helper_vilvh_d) +TRANS(vilvl_b, ALL, gen_vvv, gen_helper_vilvl_b) +TRANS(vilvl_h, ALL, gen_vvv, gen_helper_vilvl_h) +TRANS(vilvl_w, ALL, gen_vvv, gen_helper_vilvl_w) +TRANS(vilvl_d, ALL, gen_vvv, gen_helper_vilvl_d) +TRANS(vilvh_b, ALL, gen_vvv, gen_helper_vilvh_b) +TRANS(vilvh_h, ALL, gen_vvv, gen_helper_vilvh_h) +TRANS(vilvh_w, ALL, gen_vvv, gen_helper_vilvh_w) +TRANS(vilvh_d, ALL, gen_vvv, gen_helper_vilvh_d) -TRANS(vshuf_b, gen_vvvv, gen_helper_vshuf_b) -TRANS(vshuf_h, gen_vvv, gen_helper_vshuf_h) -TRANS(vshuf_w, gen_vvv, gen_helper_vshuf_w) -TRANS(vshuf_d, gen_vvv, gen_helper_vshuf_d) -TRANS(vshuf4i_b, gen_vv_i, gen_helper_vshuf4i_b) -TRANS(vshuf4i_h, gen_vv_i, gen_helper_vshuf4i_h) -TRANS(vshuf4i_w, gen_vv_i, gen_helper_vshuf4i_w) -TRANS(vshuf4i_d, gen_vv_i, gen_helper_vshuf4i_d) +TRANS(vshuf_b, ALL, gen_vvvv, gen_helper_vshuf_b) +TRANS(vshuf_h, ALL, gen_vvv, gen_helper_vshuf_h) +TRANS(vshuf_w, ALL, gen_vvv, gen_helper_vshuf_w) +TRANS(vshuf_d, ALL, gen_vvv, gen_helper_vshuf_d) +TRANS(vshuf4i_b, ALL, gen_vv_i, gen_helper_vshuf4i_b) +TRANS(vshuf4i_h, ALL, gen_vv_i, gen_helper_vshuf4i_h) +TRANS(vshuf4i_w, ALL, gen_vv_i, gen_helper_vshuf4i_w) +TRANS(vshuf4i_d, ALL, gen_vv_i, gen_helper_vshuf4i_d) -TRANS(vpermi_w, gen_vv_i, gen_helper_vpermi_w) +TRANS(vpermi_w, ALL, gen_vv_i, gen_helper_vpermi_w) -TRANS(vextrins_b, gen_vv_i, gen_helper_vextrins_b) -TRANS(vextrins_h, gen_vv_i, gen_helper_vextrins_h) -TRANS(vextrins_w, gen_vv_i, gen_helper_vextrins_w) -TRANS(vextrins_d, gen_vv_i, gen_helper_vextrins_d) +TRANS(vextrins_b, ALL, gen_vv_i, gen_helper_vextrins_b) +TRANS(vextrins_h, ALL, gen_vv_i, gen_helper_vextrins_h) +TRANS(vextrins_w, ALL, gen_vv_i, gen_helper_vextrins_w) +TRANS(vextrins_d, ALL, gen_vv_i, gen_helper_vextrins_d) static bool trans_vld(DisasContext *ctx, arg_vr_i *a) { diff --git a/target/loongarch/insn_trans/trans_memory.c.inc b/target/loongarch/insn_trans/trans_memory.c.inc index 88953f0ab0..ad6a4b006d 100644 --- a/target/loongarch/insn_trans/trans_memory.c.inc +++ b/target/loongarch/insn_trans/trans_memory.c.inc @@ -145,45 +145,45 @@ static bool gen_stptr(DisasContext *ctx, arg_rr_i *a, MemOp mop) return true; } -TRANS(ld_b, gen_load, MO_SB) -TRANS(ld_h, gen_load, MO_TESW) -TRANS(ld_w, gen_load, MO_TESL) -TRANS(ld_d, gen_load, MO_TEUQ) -TRANS(st_b, gen_store, MO_UB) -TRANS(st_h, gen_store, MO_TEUW) -TRANS(st_w, gen_store, MO_TEUL) -TRANS(st_d, gen_store, MO_TEUQ) -TRANS(ld_bu, gen_load, MO_UB) -TRANS(ld_hu, gen_load, MO_TEUW) -TRANS(ld_wu, gen_load, MO_TEUL) -TRANS(ldx_b, gen_loadx, MO_SB) -TRANS(ldx_h, gen_loadx, MO_TESW) -TRANS(ldx_w, gen_loadx, MO_TESL) -TRANS(ldx_d, gen_loadx, MO_TEUQ) -TRANS(stx_b, gen_storex, MO_UB) -TRANS(stx_h, gen_storex, MO_TEUW) -TRANS(stx_w, gen_storex, MO_TEUL) -TRANS(stx_d, gen_storex, MO_TEUQ) -TRANS(ldx_bu, gen_loadx, MO_UB) -TRANS(ldx_hu, gen_loadx, MO_TEUW) -TRANS(ldx_wu, gen_loadx, MO_TEUL) -TRANS(ldptr_w, gen_ldptr, MO_TESL) -TRANS(stptr_w, gen_stptr, MO_TEUL) -TRANS(ldptr_d, gen_ldptr, MO_TEUQ) -TRANS(stptr_d, gen_stptr, MO_TEUQ) -TRANS(ldgt_b, gen_load_gt, MO_SB) -TRANS(ldgt_h, gen_load_gt, MO_TESW) -TRANS(ldgt_w, gen_load_gt, MO_TESL) -TRANS(ldgt_d, gen_load_gt, MO_TEUQ) -TRANS(ldle_b, gen_load_le, MO_SB) -TRANS(ldle_h, gen_load_le, MO_TESW) -TRANS(ldle_w, gen_load_le, MO_TESL) -TRANS(ldle_d, gen_load_le, MO_TEUQ) -TRANS(stgt_b, gen_store_gt, MO_UB) -TRANS(stgt_h, gen_store_gt, MO_TEUW) -TRANS(stgt_w, gen_store_gt, MO_TEUL) -TRANS(stgt_d, gen_store_gt, MO_TEUQ) -TRANS(stle_b, gen_store_le, MO_UB) -TRANS(stle_h, gen_store_le, MO_TEUW) -TRANS(stle_w, gen_store_le, MO_TEUL) -TRANS(stle_d, gen_store_le, MO_TEUQ) +TRANS(ld_b, ALL, gen_load, MO_SB) +TRANS(ld_h, ALL, gen_load, MO_TESW) +TRANS(ld_w, ALL, gen_load, MO_TESL) +TRANS(ld_d, ALL, gen_load, MO_TEUQ) +TRANS(st_b, ALL, gen_store, MO_UB) +TRANS(st_h, ALL, gen_store, MO_TEUW) +TRANS(st_w, ALL, gen_store, MO_TEUL) +TRANS(st_d, ALL, gen_store, MO_TEUQ) +TRANS(ld_bu, ALL, gen_load, MO_UB) +TRANS(ld_hu, ALL, gen_load, MO_TEUW) +TRANS(ld_wu, ALL, gen_load, MO_TEUL) +TRANS(ldx_b, ALL, gen_loadx, MO_SB) +TRANS(ldx_h, ALL, gen_loadx, MO_TESW) +TRANS(ldx_w, ALL, gen_loadx, MO_TESL) +TRANS(ldx_d, ALL, gen_loadx, MO_TEUQ) +TRANS(stx_b, ALL, gen_storex, MO_UB) +TRANS(stx_h, ALL, gen_storex, MO_TEUW) +TRANS(stx_w, ALL, gen_storex, MO_TEUL) +TRANS(stx_d, ALL, gen_storex, MO_TEUQ) +TRANS(ldx_bu, ALL, gen_loadx, MO_UB) +TRANS(ldx_hu, ALL, gen_loadx, MO_TEUW) +TRANS(ldx_wu, ALL, gen_loadx, MO_TEUL) +TRANS(ldptr_w, ALL, gen_ldptr, MO_TESL) +TRANS(stptr_w, ALL, gen_stptr, MO_TEUL) +TRANS(ldptr_d, ALL, gen_ldptr, MO_TEUQ) +TRANS(stptr_d, ALL, gen_stptr, MO_TEUQ) +TRANS(ldgt_b, ALL, gen_load_gt, MO_SB) +TRANS(ldgt_h, ALL, gen_load_gt, MO_TESW) +TRANS(ldgt_w, ALL, gen_load_gt, MO_TESL) +TRANS(ldgt_d, ALL, gen_load_gt, MO_TEUQ) +TRANS(ldle_b, ALL, gen_load_le, MO_SB) +TRANS(ldle_h, ALL, gen_load_le, MO_TESW) +TRANS(ldle_w, ALL, gen_load_le, MO_TESL) +TRANS(ldle_d, ALL, gen_load_le, MO_TEUQ) +TRANS(stgt_b, ALL, gen_store_gt, MO_UB) +TRANS(stgt_h, ALL, gen_store_gt, MO_TEUW) +TRANS(stgt_w, ALL, gen_store_gt, MO_TEUL) +TRANS(stgt_d, ALL, gen_store_gt, MO_TEUQ) +TRANS(stle_b, ALL, gen_store_le, MO_UB) +TRANS(stle_h, ALL, gen_store_le, MO_TEUW) +TRANS(stle_w, ALL, gen_store_le, MO_TEUL) +TRANS(stle_d, ALL, gen_store_le, MO_TEUQ) diff --git a/target/loongarch/insn_trans/trans_privileged.c.inc b/target/loongarch/insn_trans/trans_privileged.c.inc index 9c9de090f0..684ff547a7 100644 --- a/target/loongarch/insn_trans/trans_privileged.c.inc +++ b/target/loongarch/insn_trans/trans_privileged.c.inc @@ -312,14 +312,14 @@ static bool gen_iocsrwr(DisasContext *ctx, arg_rr *a, return true; } -TRANS(iocsrrd_b, gen_iocsrrd, gen_helper_iocsrrd_b) -TRANS(iocsrrd_h, gen_iocsrrd, gen_helper_iocsrrd_h) -TRANS(iocsrrd_w, gen_iocsrrd, gen_helper_iocsrrd_w) -TRANS(iocsrrd_d, gen_iocsrrd, gen_helper_iocsrrd_d) -TRANS(iocsrwr_b, gen_iocsrwr, gen_helper_iocsrwr_b) -TRANS(iocsrwr_h, gen_iocsrwr, gen_helper_iocsrwr_h) -TRANS(iocsrwr_w, gen_iocsrwr, gen_helper_iocsrwr_w) -TRANS(iocsrwr_d, gen_iocsrwr, gen_helper_iocsrwr_d) +TRANS(iocsrrd_b, ALL, gen_iocsrrd, gen_helper_iocsrrd_b) +TRANS(iocsrrd_h, ALL, gen_iocsrrd, gen_helper_iocsrrd_h) +TRANS(iocsrrd_w, ALL, gen_iocsrrd, gen_helper_iocsrrd_w) +TRANS(iocsrrd_d, ALL, gen_iocsrrd, gen_helper_iocsrrd_d) +TRANS(iocsrwr_b, ALL, gen_iocsrwr, gen_helper_iocsrwr_b) +TRANS(iocsrwr_h, ALL, gen_iocsrwr, gen_helper_iocsrwr_h) +TRANS(iocsrwr_w, ALL, gen_iocsrwr, gen_helper_iocsrwr_w) +TRANS(iocsrwr_d, ALL, gen_iocsrwr, gen_helper_iocsrwr_d) static void check_mmu_idx(DisasContext *ctx) { diff --git a/target/loongarch/insn_trans/trans_shift.c.inc b/target/loongarch/insn_trans/trans_shift.c.inc index bf5428a2ba..849759b94b 100644 --- a/target/loongarch/insn_trans/trans_shift.c.inc +++ b/target/loongarch/insn_trans/trans_shift.c.inc @@ -78,18 +78,18 @@ static bool trans_srai_w(DisasContext *ctx, arg_srai_w *a) return true; } -TRANS(sll_w, gen_rrr, EXT_ZERO, EXT_NONE, EXT_SIGN, gen_sll_w) -TRANS(srl_w, gen_rrr, EXT_ZERO, EXT_NONE, EXT_SIGN, gen_srl_w) -TRANS(sra_w, gen_rrr, EXT_SIGN, EXT_NONE, EXT_SIGN, gen_sra_w) -TRANS(sll_d, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_sll_d) -TRANS(srl_d, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_srl_d) -TRANS(sra_d, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_sra_d) -TRANS(rotr_w, gen_rrr, EXT_ZERO, EXT_NONE, EXT_SIGN, gen_rotr_w) -TRANS(rotr_d, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_rotr_d) -TRANS(slli_w, gen_rri_c, EXT_NONE, EXT_SIGN, tcg_gen_shli_tl) -TRANS(slli_d, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_shli_tl) -TRANS(srli_w, gen_rri_c, EXT_ZERO, EXT_SIGN, tcg_gen_shri_tl) -TRANS(srli_d, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_shri_tl) -TRANS(srai_d, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_sari_tl) -TRANS(rotri_w, gen_rri_v, EXT_NONE, EXT_NONE, gen_rotr_w) -TRANS(rotri_d, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_rotri_tl) +TRANS(sll_w, ALL, gen_rrr, EXT_ZERO, EXT_NONE, EXT_SIGN, gen_sll_w) +TRANS(srl_w, ALL, gen_rrr, EXT_ZERO, EXT_NONE, EXT_SIGN, gen_srl_w) +TRANS(sra_w, ALL, gen_rrr, EXT_SIGN, EXT_NONE, EXT_SIGN, gen_sra_w) +TRANS(sll_d, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_sll_d) +TRANS(srl_d, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_srl_d) +TRANS(sra_d, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_sra_d) +TRANS(rotr_w, ALL, gen_rrr, EXT_ZERO, EXT_NONE, EXT_SIGN, gen_rotr_w) +TRANS(rotr_d, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_rotr_d) +TRANS(slli_w, ALL, gen_rri_c, EXT_NONE, EXT_SIGN, tcg_gen_shli_tl) +TRANS(slli_d, ALL, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_shli_tl) +TRANS(srli_w, ALL, gen_rri_c, EXT_ZERO, EXT_SIGN, tcg_gen_shri_tl) +TRANS(srli_d, ALL, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_shri_tl) +TRANS(srai_d, ALL, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_sari_tl) +TRANS(rotri_w, ALL, gen_rri_v, EXT_NONE, EXT_NONE, gen_rotr_w) +TRANS(rotri_d, ALL, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_rotri_tl) diff --git a/target/loongarch/translate.h b/target/loongarch/translate.h index b6fa5df82d..3c5c746f30 100644 --- a/target/loongarch/translate.h +++ b/target/loongarch/translate.h @@ -10,9 +10,11 @@ #include "exec/translator.h" -#define TRANS(NAME, FUNC, ...) \ +#define TRANS(NAME, AVAIL, FUNC, ...) \ static bool trans_##NAME(DisasContext *ctx, arg_##NAME * a) \ - { return FUNC(ctx, a, __VA_ARGS__); } + { return avail_##AVAIL(ctx) && FUNC(ctx, a, __VA_ARGS__); } + +#define avail_ALL(C) true /* * If an operation is being performed on less than TARGET_LONG_BITS, From c0c0461e3a06c8e854b8666a2610b1b619d0d1f8 Mon Sep 17 00:00:00 2001 From: Song Gao Date: Tue, 22 Aug 2023 09:19:52 +0200 Subject: [PATCH 1187/1353] target/loongarch: Add avail_64 to check la64-only instructions The la32 instructions listed in Table 2 at https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html#overview-of-basic-integer-instructions Co-authored-by: Jiajie Chen Signed-off-by: Song Gao Reviewed-by: Richard Henderson Message-ID: <20230822032724.1353391-9-gaosong@loongson.cn> Message-Id: <20230822071959.35620-3-philmd@linaro.org> --- target/loongarch/insn_trans/trans_arith.c.inc | 42 ++++++---- .../loongarch/insn_trans/trans_atomic.c.inc | 76 +++++++++---------- target/loongarch/insn_trans/trans_bit.c.inc | 28 +++---- .../loongarch/insn_trans/trans_branch.c.inc | 4 +- target/loongarch/insn_trans/trans_extra.c.inc | 24 ++++-- target/loongarch/insn_trans/trans_fmov.c.inc | 4 +- .../loongarch/insn_trans/trans_memory.c.inc | 68 ++++++++--------- target/loongarch/insn_trans/trans_shift.c.inc | 24 +++--- target/loongarch/translate.c | 2 + target/loongarch/translate.h | 3 + 10 files changed, 152 insertions(+), 123 deletions(-) diff --git a/target/loongarch/insn_trans/trans_arith.c.inc b/target/loongarch/insn_trans/trans_arith.c.inc index d7f69a7553..2be057e932 100644 --- a/target/loongarch/insn_trans/trans_arith.c.inc +++ b/target/loongarch/insn_trans/trans_arith.c.inc @@ -199,6 +199,10 @@ static bool trans_lu32i_d(DisasContext *ctx, arg_lu32i_d *a) TCGv src1 = gpr_src(ctx, a->rd, EXT_NONE); TCGv src2 = tcg_constant_tl(a->imm); + if (!avail_64(ctx)) { + return false; + } + tcg_gen_deposit_tl(dest, src1, src2, 32, 32); gen_set_gpr(a->rd, dest, EXT_NONE); @@ -211,6 +215,10 @@ static bool trans_lu52i_d(DisasContext *ctx, arg_lu52i_d *a) TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); TCGv src2 = tcg_constant_tl(a->imm); + if (!avail_64(ctx)) { + return false; + } + tcg_gen_deposit_tl(dest, src1, src2, 52, 12); gen_set_gpr(a->rd, dest, EXT_NONE); @@ -242,6 +250,10 @@ static bool trans_addu16i_d(DisasContext *ctx, arg_addu16i_d *a) TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + if (!avail_64(ctx)) { + return false; + } + tcg_gen_addi_tl(dest, src1, a->imm << 16); gen_set_gpr(a->rd, dest, EXT_NONE); @@ -249,9 +261,9 @@ static bool trans_addu16i_d(DisasContext *ctx, arg_addu16i_d *a) } TRANS(add_w, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_SIGN, tcg_gen_add_tl) -TRANS(add_d, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_add_tl) +TRANS(add_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_add_tl) TRANS(sub_w, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_SIGN, tcg_gen_sub_tl) -TRANS(sub_d, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_sub_tl) +TRANS(sub_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_sub_tl) TRANS(and, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_and_tl) TRANS(or, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_or_tl) TRANS(xor, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_xor_tl) @@ -261,32 +273,32 @@ TRANS(orn, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_orc_tl) TRANS(slt, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_slt) TRANS(sltu, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_sltu) TRANS(mul_w, ALL, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_SIGN, tcg_gen_mul_tl) -TRANS(mul_d, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_mul_tl) +TRANS(mul_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, tcg_gen_mul_tl) TRANS(mulh_w, ALL, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_NONE, gen_mulh_w) TRANS(mulh_wu, ALL, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_NONE, gen_mulh_w) -TRANS(mulh_d, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_mulh_d) -TRANS(mulh_du, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_mulh_du) -TRANS(mulw_d_w, ALL, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_NONE, tcg_gen_mul_tl) -TRANS(mulw_d_wu, ALL, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_NONE, tcg_gen_mul_tl) +TRANS(mulh_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_mulh_d) +TRANS(mulh_du, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_mulh_du) +TRANS(mulw_d_w, 64, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_NONE, tcg_gen_mul_tl) +TRANS(mulw_d_wu, 64, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_NONE, tcg_gen_mul_tl) TRANS(div_w, ALL, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_SIGN, gen_div_w) TRANS(mod_w, ALL, gen_rrr, EXT_SIGN, EXT_SIGN, EXT_SIGN, gen_rem_w) TRANS(div_wu, ALL, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_SIGN, gen_div_du) TRANS(mod_wu, ALL, gen_rrr, EXT_ZERO, EXT_ZERO, EXT_SIGN, gen_rem_du) -TRANS(div_d, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_div_d) -TRANS(mod_d, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_rem_d) -TRANS(div_du, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_div_du) -TRANS(mod_du, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_rem_du) +TRANS(div_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_div_d) +TRANS(mod_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_rem_d) +TRANS(div_du, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_div_du) +TRANS(mod_du, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_rem_du) TRANS(slti, ALL, gen_rri_v, EXT_NONE, EXT_NONE, gen_slt) TRANS(sltui, ALL, gen_rri_v, EXT_NONE, EXT_NONE, gen_sltu) TRANS(addi_w, ALL, gen_rri_c, EXT_NONE, EXT_SIGN, tcg_gen_addi_tl) -TRANS(addi_d, ALL, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_addi_tl) +TRANS(addi_d, 64, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_addi_tl) TRANS(alsl_w, ALL, gen_rrr_sa, EXT_NONE, EXT_SIGN, gen_alsl) -TRANS(alsl_wu, ALL, gen_rrr_sa, EXT_NONE, EXT_ZERO, gen_alsl) -TRANS(alsl_d, ALL, gen_rrr_sa, EXT_NONE, EXT_NONE, gen_alsl) +TRANS(alsl_wu, 64, gen_rrr_sa, EXT_NONE, EXT_ZERO, gen_alsl) +TRANS(alsl_d, 64, gen_rrr_sa, EXT_NONE, EXT_NONE, gen_alsl) TRANS(pcaddi, ALL, gen_pc, gen_pcaddi) TRANS(pcalau12i, ALL, gen_pc, gen_pcalau12i) TRANS(pcaddu12i, ALL, gen_pc, gen_pcaddu12i) -TRANS(pcaddu18i, ALL, gen_pc, gen_pcaddu18i) +TRANS(pcaddu18i, 64, gen_pc, gen_pcaddu18i) TRANS(andi, ALL, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_andi_tl) TRANS(ori, ALL, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_ori_tl) TRANS(xori, ALL, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_xori_tl) diff --git a/target/loongarch/insn_trans/trans_atomic.c.inc b/target/loongarch/insn_trans/trans_atomic.c.inc index 0a02f0dbf3..194818d74d 100644 --- a/target/loongarch/insn_trans/trans_atomic.c.inc +++ b/target/loongarch/insn_trans/trans_atomic.c.inc @@ -71,41 +71,41 @@ static bool gen_am(DisasContext *ctx, arg_rrr *a, TRANS(ll_w, ALL, gen_ll, MO_TESL) TRANS(sc_w, ALL, gen_sc, MO_TESL) -TRANS(ll_d, ALL, gen_ll, MO_TEUQ) -TRANS(sc_d, ALL, gen_sc, MO_TEUQ) -TRANS(amswap_w, ALL, gen_am, tcg_gen_atomic_xchg_tl, MO_TESL) -TRANS(amswap_d, ALL, gen_am, tcg_gen_atomic_xchg_tl, MO_TEUQ) -TRANS(amadd_w, ALL, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TESL) -TRANS(amadd_d, ALL, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TEUQ) -TRANS(amand_w, ALL, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TESL) -TRANS(amand_d, ALL, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TEUQ) -TRANS(amor_w, ALL, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TESL) -TRANS(amor_d, ALL, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TEUQ) -TRANS(amxor_w, ALL, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TESL) -TRANS(amxor_d, ALL, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TEUQ) -TRANS(ammax_w, ALL, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TESL) -TRANS(ammax_d, ALL, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TEUQ) -TRANS(ammin_w, ALL, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TESL) -TRANS(ammin_d, ALL, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TEUQ) -TRANS(ammax_wu, ALL, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TESL) -TRANS(ammax_du, ALL, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TEUQ) -TRANS(ammin_wu, ALL, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TESL) -TRANS(ammin_du, ALL, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TEUQ) -TRANS(amswap_db_w, ALL, gen_am, tcg_gen_atomic_xchg_tl, MO_TESL) -TRANS(amswap_db_d, ALL, gen_am, tcg_gen_atomic_xchg_tl, MO_TEUQ) -TRANS(amadd_db_w, ALL, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TESL) -TRANS(amadd_db_d, ALL, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TEUQ) -TRANS(amand_db_w, ALL, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TESL) -TRANS(amand_db_d, ALL, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TEUQ) -TRANS(amor_db_w, ALL, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TESL) -TRANS(amor_db_d, ALL, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TEUQ) -TRANS(amxor_db_w, ALL, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TESL) -TRANS(amxor_db_d, ALL, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TEUQ) -TRANS(ammax_db_w, ALL, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TESL) -TRANS(ammax_db_d, ALL, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TEUQ) -TRANS(ammin_db_w, ALL, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TESL) -TRANS(ammin_db_d, ALL, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TEUQ) -TRANS(ammax_db_wu, ALL, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TESL) -TRANS(ammax_db_du, ALL, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TEUQ) -TRANS(ammin_db_wu, ALL, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TESL) -TRANS(ammin_db_du, ALL, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TEUQ) +TRANS(ll_d, 64, gen_ll, MO_TEUQ) +TRANS(sc_d, 64, gen_sc, MO_TEUQ) +TRANS(amswap_w, 64, gen_am, tcg_gen_atomic_xchg_tl, MO_TESL) +TRANS(amswap_d, 64, gen_am, tcg_gen_atomic_xchg_tl, MO_TEUQ) +TRANS(amadd_w, 64, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TESL) +TRANS(amadd_d, 64, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TEUQ) +TRANS(amand_w, 64, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TESL) +TRANS(amand_d, 64, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TEUQ) +TRANS(amor_w, 64, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TESL) +TRANS(amor_d, 64, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TEUQ) +TRANS(amxor_w, 64, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TESL) +TRANS(amxor_d, 64, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TEUQ) +TRANS(ammax_w, 64, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TESL) +TRANS(ammax_d, 64, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TEUQ) +TRANS(ammin_w, 64, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TESL) +TRANS(ammin_d, 64, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TEUQ) +TRANS(ammax_wu, 64, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TESL) +TRANS(ammax_du, 64, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TEUQ) +TRANS(ammin_wu, 64, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TESL) +TRANS(ammin_du, 64, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TEUQ) +TRANS(amswap_db_w, 64, gen_am, tcg_gen_atomic_xchg_tl, MO_TESL) +TRANS(amswap_db_d, 64, gen_am, tcg_gen_atomic_xchg_tl, MO_TEUQ) +TRANS(amadd_db_w, 64, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TESL) +TRANS(amadd_db_d, 64, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TEUQ) +TRANS(amand_db_w, 64, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TESL) +TRANS(amand_db_d, 64, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TEUQ) +TRANS(amor_db_w, 64, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TESL) +TRANS(amor_db_d, 64, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TEUQ) +TRANS(amxor_db_w, 64, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TESL) +TRANS(amxor_db_d, 64, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TEUQ) +TRANS(ammax_db_w, 64, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TESL) +TRANS(ammax_db_d, 64, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TEUQ) +TRANS(ammin_db_w, 64, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TESL) +TRANS(ammin_db_d, 64, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TEUQ) +TRANS(ammax_db_wu, 64, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TESL) +TRANS(ammax_db_du, 64, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TEUQ) +TRANS(ammin_db_wu, 64, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TESL) +TRANS(ammin_db_du, 64, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TEUQ) diff --git a/target/loongarch/insn_trans/trans_bit.c.inc b/target/loongarch/insn_trans/trans_bit.c.inc index d2a7ac28f7..ee5fa003ce 100644 --- a/target/loongarch/insn_trans/trans_bit.c.inc +++ b/target/loongarch/insn_trans/trans_bit.c.inc @@ -184,25 +184,25 @@ TRANS(clo_w, ALL, gen_rr, EXT_NONE, EXT_NONE, gen_clo_w) TRANS(clz_w, ALL, gen_rr, EXT_ZERO, EXT_NONE, gen_clz_w) TRANS(cto_w, ALL, gen_rr, EXT_NONE, EXT_NONE, gen_cto_w) TRANS(ctz_w, ALL, gen_rr, EXT_NONE, EXT_NONE, gen_ctz_w) -TRANS(clo_d, ALL, gen_rr, EXT_NONE, EXT_NONE, gen_clo_d) -TRANS(clz_d, ALL, gen_rr, EXT_NONE, EXT_NONE, gen_clz_d) -TRANS(cto_d, ALL, gen_rr, EXT_NONE, EXT_NONE, gen_cto_d) -TRANS(ctz_d, ALL, gen_rr, EXT_NONE, EXT_NONE, gen_ctz_d) +TRANS(clo_d, 64, gen_rr, EXT_NONE, EXT_NONE, gen_clo_d) +TRANS(clz_d, 64, gen_rr, EXT_NONE, EXT_NONE, gen_clz_d) +TRANS(cto_d, 64, gen_rr, EXT_NONE, EXT_NONE, gen_cto_d) +TRANS(ctz_d, 64, gen_rr, EXT_NONE, EXT_NONE, gen_ctz_d) TRANS(revb_2h, ALL, gen_rr, EXT_NONE, EXT_SIGN, gen_revb_2h) -TRANS(revb_4h, ALL, gen_rr, EXT_NONE, EXT_NONE, gen_revb_4h) -TRANS(revb_2w, ALL, gen_rr, EXT_NONE, EXT_NONE, gen_revb_2w) -TRANS(revb_d, ALL, gen_rr, EXT_NONE, EXT_NONE, tcg_gen_bswap64_i64) -TRANS(revh_2w, ALL, gen_rr, EXT_NONE, EXT_NONE, gen_revh_2w) -TRANS(revh_d, ALL, gen_rr, EXT_NONE, EXT_NONE, gen_revh_d) +TRANS(revb_4h, 64, gen_rr, EXT_NONE, EXT_NONE, gen_revb_4h) +TRANS(revb_2w, 64, gen_rr, EXT_NONE, EXT_NONE, gen_revb_2w) +TRANS(revb_d, 64, gen_rr, EXT_NONE, EXT_NONE, tcg_gen_bswap64_i64) +TRANS(revh_2w, 64, gen_rr, EXT_NONE, EXT_NONE, gen_revh_2w) +TRANS(revh_d, 64, gen_rr, EXT_NONE, EXT_NONE, gen_revh_d) TRANS(bitrev_4b, ALL, gen_rr, EXT_ZERO, EXT_SIGN, gen_helper_bitswap) -TRANS(bitrev_8b, ALL, gen_rr, EXT_NONE, EXT_NONE, gen_helper_bitswap) +TRANS(bitrev_8b, 64, gen_rr, EXT_NONE, EXT_NONE, gen_helper_bitswap) TRANS(bitrev_w, ALL, gen_rr, EXT_NONE, EXT_SIGN, gen_helper_bitrev_w) -TRANS(bitrev_d, ALL, gen_rr, EXT_NONE, EXT_NONE, gen_helper_bitrev_d) +TRANS(bitrev_d, 64, gen_rr, EXT_NONE, EXT_NONE, gen_helper_bitrev_d) TRANS(maskeqz, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_maskeqz) TRANS(masknez, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_masknez) TRANS(bytepick_w, ALL, gen_rrr_sa, EXT_NONE, EXT_NONE, gen_bytepick_w) -TRANS(bytepick_d, ALL, gen_rrr_sa, EXT_NONE, EXT_NONE, gen_bytepick_d) +TRANS(bytepick_d, 64, gen_rrr_sa, EXT_NONE, EXT_NONE, gen_bytepick_d) TRANS(bstrins_w, ALL, gen_bstrins, EXT_SIGN) -TRANS(bstrins_d, ALL, gen_bstrins, EXT_NONE) +TRANS(bstrins_d, 64, gen_bstrins, EXT_NONE) TRANS(bstrpick_w, ALL, gen_bstrpick, EXT_SIGN) -TRANS(bstrpick_d, ALL, gen_bstrpick, EXT_NONE) +TRANS(bstrpick_d, 64, gen_bstrpick, EXT_NONE) diff --git a/target/loongarch/insn_trans/trans_branch.c.inc b/target/loongarch/insn_trans/trans_branch.c.inc index 50f7eb640a..a4fd2092e5 100644 --- a/target/loongarch/insn_trans/trans_branch.c.inc +++ b/target/loongarch/insn_trans/trans_branch.c.inc @@ -80,5 +80,5 @@ TRANS(bltu, ALL, gen_rr_bc, TCG_COND_LTU) TRANS(bgeu, ALL, gen_rr_bc, TCG_COND_GEU) TRANS(beqz, ALL, gen_rz_bc, TCG_COND_EQ) TRANS(bnez, ALL, gen_rz_bc, TCG_COND_NE) -TRANS(bceqz, ALL, gen_cz_bc, TCG_COND_EQ) -TRANS(bcnez, ALL, gen_cz_bc, TCG_COND_NE) +TRANS(bceqz, 64, gen_cz_bc, TCG_COND_EQ) +TRANS(bcnez, 64, gen_cz_bc, TCG_COND_NE) diff --git a/target/loongarch/insn_trans/trans_extra.c.inc b/target/loongarch/insn_trans/trans_extra.c.inc index b354ca0f86..dd5d02e88c 100644 --- a/target/loongarch/insn_trans/trans_extra.c.inc +++ b/target/loongarch/insn_trans/trans_extra.c.inc @@ -20,6 +20,10 @@ static bool trans_asrtle_d(DisasContext *ctx, arg_asrtle_d * a) TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); + if (!avail_64(ctx)) { + return false; + } + gen_helper_asrtle_d(cpu_env, src1, src2); return true; } @@ -29,6 +33,10 @@ static bool trans_asrtgt_d(DisasContext *ctx, arg_asrtgt_d * a) TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); TCGv src2 = gpr_src(ctx, a->rk, EXT_NONE); + if (!avail_64(ctx)) { + return false; + } + gen_helper_asrtgt_d(cpu_env, src1, src2); return true; } @@ -89,11 +97,11 @@ static bool gen_crc(DisasContext *ctx, arg_rrr *a, return true; } -TRANS(crc_w_b_w, ALL, gen_crc, gen_helper_crc32, tcg_constant_tl(1)) -TRANS(crc_w_h_w, ALL, gen_crc, gen_helper_crc32, tcg_constant_tl(2)) -TRANS(crc_w_w_w, ALL, gen_crc, gen_helper_crc32, tcg_constant_tl(4)) -TRANS(crc_w_d_w, ALL, gen_crc, gen_helper_crc32, tcg_constant_tl(8)) -TRANS(crcc_w_b_w, ALL, gen_crc, gen_helper_crc32c, tcg_constant_tl(1)) -TRANS(crcc_w_h_w, ALL, gen_crc, gen_helper_crc32c, tcg_constant_tl(2)) -TRANS(crcc_w_w_w, ALL, gen_crc, gen_helper_crc32c, tcg_constant_tl(4)) -TRANS(crcc_w_d_w, ALL, gen_crc, gen_helper_crc32c, tcg_constant_tl(8)) +TRANS(crc_w_b_w, 64, gen_crc, gen_helper_crc32, tcg_constant_tl(1)) +TRANS(crc_w_h_w, 64, gen_crc, gen_helper_crc32, tcg_constant_tl(2)) +TRANS(crc_w_w_w, 64, gen_crc, gen_helper_crc32, tcg_constant_tl(4)) +TRANS(crc_w_d_w, 64, gen_crc, gen_helper_crc32, tcg_constant_tl(8)) +TRANS(crcc_w_b_w, 64, gen_crc, gen_helper_crc32c, tcg_constant_tl(1)) +TRANS(crcc_w_h_w, 64, gen_crc, gen_helper_crc32c, tcg_constant_tl(2)) +TRANS(crcc_w_w_w, 64, gen_crc, gen_helper_crc32c, tcg_constant_tl(4)) +TRANS(crcc_w_d_w, 64, gen_crc, gen_helper_crc32c, tcg_constant_tl(8)) diff --git a/target/loongarch/insn_trans/trans_fmov.c.inc b/target/loongarch/insn_trans/trans_fmov.c.inc index aa7fea67b5..385bbb7929 100644 --- a/target/loongarch/insn_trans/trans_fmov.c.inc +++ b/target/loongarch/insn_trans/trans_fmov.c.inc @@ -181,8 +181,8 @@ static bool trans_movcf2gr(DisasContext *ctx, arg_movcf2gr *a) TRANS(fmov_s, ALL, gen_f2f, tcg_gen_mov_tl, true) TRANS(fmov_d, ALL, gen_f2f, tcg_gen_mov_tl, false) TRANS(movgr2fr_w, ALL, gen_r2f, gen_movgr2fr_w) -TRANS(movgr2fr_d, ALL, gen_r2f, tcg_gen_mov_tl) +TRANS(movgr2fr_d, 64, gen_r2f, tcg_gen_mov_tl) TRANS(movgr2frh_w, ALL, gen_r2f, gen_movgr2frh_w) TRANS(movfr2gr_s, ALL, gen_f2r, tcg_gen_ext32s_tl) -TRANS(movfr2gr_d, ALL, gen_f2r, tcg_gen_mov_tl) +TRANS(movfr2gr_d, 64, gen_f2r, tcg_gen_mov_tl) TRANS(movfrh2gr_s, ALL, gen_f2r, gen_movfrh2gr_s) diff --git a/target/loongarch/insn_trans/trans_memory.c.inc b/target/loongarch/insn_trans/trans_memory.c.inc index ad6a4b006d..d9d062235a 100644 --- a/target/loongarch/insn_trans/trans_memory.c.inc +++ b/target/loongarch/insn_trans/trans_memory.c.inc @@ -148,42 +148,42 @@ static bool gen_stptr(DisasContext *ctx, arg_rr_i *a, MemOp mop) TRANS(ld_b, ALL, gen_load, MO_SB) TRANS(ld_h, ALL, gen_load, MO_TESW) TRANS(ld_w, ALL, gen_load, MO_TESL) -TRANS(ld_d, ALL, gen_load, MO_TEUQ) +TRANS(ld_d, 64, gen_load, MO_TEUQ) TRANS(st_b, ALL, gen_store, MO_UB) TRANS(st_h, ALL, gen_store, MO_TEUW) TRANS(st_w, ALL, gen_store, MO_TEUL) -TRANS(st_d, ALL, gen_store, MO_TEUQ) +TRANS(st_d, 64, gen_store, MO_TEUQ) TRANS(ld_bu, ALL, gen_load, MO_UB) TRANS(ld_hu, ALL, gen_load, MO_TEUW) -TRANS(ld_wu, ALL, gen_load, MO_TEUL) -TRANS(ldx_b, ALL, gen_loadx, MO_SB) -TRANS(ldx_h, ALL, gen_loadx, MO_TESW) -TRANS(ldx_w, ALL, gen_loadx, MO_TESL) -TRANS(ldx_d, ALL, gen_loadx, MO_TEUQ) -TRANS(stx_b, ALL, gen_storex, MO_UB) -TRANS(stx_h, ALL, gen_storex, MO_TEUW) -TRANS(stx_w, ALL, gen_storex, MO_TEUL) -TRANS(stx_d, ALL, gen_storex, MO_TEUQ) -TRANS(ldx_bu, ALL, gen_loadx, MO_UB) -TRANS(ldx_hu, ALL, gen_loadx, MO_TEUW) -TRANS(ldx_wu, ALL, gen_loadx, MO_TEUL) -TRANS(ldptr_w, ALL, gen_ldptr, MO_TESL) -TRANS(stptr_w, ALL, gen_stptr, MO_TEUL) -TRANS(ldptr_d, ALL, gen_ldptr, MO_TEUQ) -TRANS(stptr_d, ALL, gen_stptr, MO_TEUQ) -TRANS(ldgt_b, ALL, gen_load_gt, MO_SB) -TRANS(ldgt_h, ALL, gen_load_gt, MO_TESW) -TRANS(ldgt_w, ALL, gen_load_gt, MO_TESL) -TRANS(ldgt_d, ALL, gen_load_gt, MO_TEUQ) -TRANS(ldle_b, ALL, gen_load_le, MO_SB) -TRANS(ldle_h, ALL, gen_load_le, MO_TESW) -TRANS(ldle_w, ALL, gen_load_le, MO_TESL) -TRANS(ldle_d, ALL, gen_load_le, MO_TEUQ) -TRANS(stgt_b, ALL, gen_store_gt, MO_UB) -TRANS(stgt_h, ALL, gen_store_gt, MO_TEUW) -TRANS(stgt_w, ALL, gen_store_gt, MO_TEUL) -TRANS(stgt_d, ALL, gen_store_gt, MO_TEUQ) -TRANS(stle_b, ALL, gen_store_le, MO_UB) -TRANS(stle_h, ALL, gen_store_le, MO_TEUW) -TRANS(stle_w, ALL, gen_store_le, MO_TEUL) -TRANS(stle_d, ALL, gen_store_le, MO_TEUQ) +TRANS(ld_wu, 64, gen_load, MO_TEUL) +TRANS(ldx_b, 64, gen_loadx, MO_SB) +TRANS(ldx_h, 64, gen_loadx, MO_TESW) +TRANS(ldx_w, 64, gen_loadx, MO_TESL) +TRANS(ldx_d, 64, gen_loadx, MO_TEUQ) +TRANS(stx_b, 64, gen_storex, MO_UB) +TRANS(stx_h, 64, gen_storex, MO_TEUW) +TRANS(stx_w, 64, gen_storex, MO_TEUL) +TRANS(stx_d, 64, gen_storex, MO_TEUQ) +TRANS(ldx_bu, 64, gen_loadx, MO_UB) +TRANS(ldx_hu, 64, gen_loadx, MO_TEUW) +TRANS(ldx_wu, 64, gen_loadx, MO_TEUL) +TRANS(ldptr_w, 64, gen_ldptr, MO_TESL) +TRANS(stptr_w, 64, gen_stptr, MO_TEUL) +TRANS(ldptr_d, 64, gen_ldptr, MO_TEUQ) +TRANS(stptr_d, 64, gen_stptr, MO_TEUQ) +TRANS(ldgt_b, 64, gen_load_gt, MO_SB) +TRANS(ldgt_h, 64, gen_load_gt, MO_TESW) +TRANS(ldgt_w, 64, gen_load_gt, MO_TESL) +TRANS(ldgt_d, 64, gen_load_gt, MO_TEUQ) +TRANS(ldle_b, 64, gen_load_le, MO_SB) +TRANS(ldle_h, 64, gen_load_le, MO_TESW) +TRANS(ldle_w, 64, gen_load_le, MO_TESL) +TRANS(ldle_d, 64, gen_load_le, MO_TEUQ) +TRANS(stgt_b, 64, gen_store_gt, MO_UB) +TRANS(stgt_h, 64, gen_store_gt, MO_TEUW) +TRANS(stgt_w, 64, gen_store_gt, MO_TEUL) +TRANS(stgt_d, 64, gen_store_gt, MO_TEUQ) +TRANS(stle_b, 64, gen_store_le, MO_UB) +TRANS(stle_h, 64, gen_store_le, MO_TEUW) +TRANS(stle_w, 64, gen_store_le, MO_TEUL) +TRANS(stle_d, 64, gen_store_le, MO_TEUQ) diff --git a/target/loongarch/insn_trans/trans_shift.c.inc b/target/loongarch/insn_trans/trans_shift.c.inc index 849759b94b..2f4bd6ff28 100644 --- a/target/loongarch/insn_trans/trans_shift.c.inc +++ b/target/loongarch/insn_trans/trans_shift.c.inc @@ -72,6 +72,10 @@ static bool trans_srai_w(DisasContext *ctx, arg_srai_w *a) TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); TCGv src1 = gpr_src(ctx, a->rj, EXT_ZERO); + if (!avail_64(ctx)) { + return false; + } + tcg_gen_sextract_tl(dest, src1, a->imm, 32 - a->imm); gen_set_gpr(a->rd, dest, EXT_NONE); @@ -81,15 +85,15 @@ static bool trans_srai_w(DisasContext *ctx, arg_srai_w *a) TRANS(sll_w, ALL, gen_rrr, EXT_ZERO, EXT_NONE, EXT_SIGN, gen_sll_w) TRANS(srl_w, ALL, gen_rrr, EXT_ZERO, EXT_NONE, EXT_SIGN, gen_srl_w) TRANS(sra_w, ALL, gen_rrr, EXT_SIGN, EXT_NONE, EXT_SIGN, gen_sra_w) -TRANS(sll_d, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_sll_d) -TRANS(srl_d, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_srl_d) -TRANS(sra_d, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_sra_d) -TRANS(rotr_w, ALL, gen_rrr, EXT_ZERO, EXT_NONE, EXT_SIGN, gen_rotr_w) -TRANS(rotr_d, ALL, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_rotr_d) +TRANS(sll_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_sll_d) +TRANS(srl_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_srl_d) +TRANS(sra_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_sra_d) +TRANS(rotr_w, 64, gen_rrr, EXT_ZERO, EXT_NONE, EXT_SIGN, gen_rotr_w) +TRANS(rotr_d, 64, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_rotr_d) TRANS(slli_w, ALL, gen_rri_c, EXT_NONE, EXT_SIGN, tcg_gen_shli_tl) -TRANS(slli_d, ALL, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_shli_tl) +TRANS(slli_d, 64, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_shli_tl) TRANS(srli_w, ALL, gen_rri_c, EXT_ZERO, EXT_SIGN, tcg_gen_shri_tl) -TRANS(srli_d, ALL, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_shri_tl) -TRANS(srai_d, ALL, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_sari_tl) -TRANS(rotri_w, ALL, gen_rri_v, EXT_NONE, EXT_NONE, gen_rotr_w) -TRANS(rotri_d, ALL, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_rotri_tl) +TRANS(srli_d, 64, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_shri_tl) +TRANS(srai_d, 64, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_sari_tl) +TRANS(rotri_w, 64, gen_rri_v, EXT_NONE, EXT_NONE, gen_rotr_w) +TRANS(rotri_d, 64, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_rotri_tl) diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index de7c1c5d1f..6967e12fc3 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -127,6 +127,8 @@ static void loongarch_tr_init_disas_context(DisasContextBase *dcbase, ctx->va32 = (ctx->base.tb->flags & HW_FLAGS_VA32) != 0; ctx->zero = tcg_constant_tl(0); + + ctx->cpucfg1 = env->cpucfg[1]; } static void loongarch_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) diff --git a/target/loongarch/translate.h b/target/loongarch/translate.h index 3c5c746f30..1342446242 100644 --- a/target/loongarch/translate.h +++ b/target/loongarch/translate.h @@ -15,6 +15,8 @@ { return avail_##AVAIL(ctx) && FUNC(ctx, a, __VA_ARGS__); } #define avail_ALL(C) true +#define avail_64(C) (FIELD_EX32((C)->cpucfg1, CPUCFG1, ARCH) == \ + CPUCFG1_ARCH_LA64) /* * If an operation is being performed on less than TARGET_LONG_BITS, @@ -37,6 +39,7 @@ typedef struct DisasContext { TCGv zero; bool la64; /* LoongArch64 mode */ bool va32; /* 32-bit virtual address */ + uint32_t cpucfg1; } DisasContext; void generate_exception(DisasContext *ctx, int excp); From bb8710cf0a637c4af189675f234639ce9e90a27d Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Tue, 22 Aug 2023 09:19:53 +0200 Subject: [PATCH 1188/1353] target/loongarch: Add LoongArch32 cpu la132 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add LoongArch32 cpu la132. Due to lack of public documentation of la132, it is currently a synthetic LoongArch32 cpu model. Details need to be added in the future. Signed-off-by: Jiajie Chen Signed-off-by: Song Gao Acked-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20230822032724.1353391-10-gaosong@loongson.cn> Message-Id: <20230822071959.35620-4-philmd@linaro.org> --- target/loongarch/cpu.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index 67eb6c3135..d3c3e0d8a1 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -440,6 +440,35 @@ static void loongarch_la464_initfn(Object *obj) env->CSR_ASID = FIELD_DP64(0, CSR_ASID, ASIDBITS, 0xa); } +static void loongarch_la132_initfn(Object *obj) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(obj); + CPULoongArchState *env = &cpu->env; + + int i; + + for (i = 0; i < 21; i++) { + env->cpucfg[i] = 0x0; + } + + cpu->dtb_compatible = "loongarch,Loongson-1C103"; + env->cpucfg[0] = 0x148042; /* PRID */ + + uint32_t data = 0; + data = FIELD_DP32(data, CPUCFG1, ARCH, 1); /* LA32 */ + data = FIELD_DP32(data, CPUCFG1, PGMMU, 1); + data = FIELD_DP32(data, CPUCFG1, IOCSR, 1); + data = FIELD_DP32(data, CPUCFG1, PALEN, 0x1f); /* 32 bits */ + data = FIELD_DP32(data, CPUCFG1, VALEN, 0x1f); /* 32 bits */ + data = FIELD_DP32(data, CPUCFG1, UAL, 1); + data = FIELD_DP32(data, CPUCFG1, RI, 0); + data = FIELD_DP32(data, CPUCFG1, EP, 0); + data = FIELD_DP32(data, CPUCFG1, RPLV, 0); + data = FIELD_DP32(data, CPUCFG1, HP, 1); + data = FIELD_DP32(data, CPUCFG1, IOCSR_BRD, 1); + env->cpucfg[1] = data; +} + static void loongarch_cpu_list_entry(gpointer data, gpointer user_data) { const char *typename = object_class_get_name(OBJECT_CLASS(data)); @@ -787,6 +816,7 @@ static const TypeInfo loongarch_cpu_type_infos[] = { .class_init = loongarch64_cpu_class_init, }, DEFINE_LOONGARCH_CPU_TYPE(64, "la464", loongarch_la464_initfn), + DEFINE_LOONGARCH_CPU_TYPE(32, "la132", loongarch_la132_initfn), }; DEFINE_TYPES(loongarch_cpu_type_infos) From 3055122ff6d5d96e5394f495de3d512f1d6e94cf Mon Sep 17 00:00:00 2001 From: Song Gao Date: Tue, 22 Aug 2023 09:19:54 +0200 Subject: [PATCH 1189/1353] hw/loongarch: Remove restriction of la464 cores in the virt machine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow virt machine to be used with la132 instead of la464. Co-authored-by: Jiajie Chen Signed-off-by: Song Gao Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20230822032724.1353391-11-gaosong@loongson.cn> Message-Id: <20230822071959.35620-5-philmd@linaro.org> --- hw/loongarch/virt.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c index e19b042ce8..af15bf5aaa 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -798,11 +798,6 @@ static void loongarch_init(MachineState *machine) cpu_model = LOONGARCH_CPU_TYPE_NAME("la464"); } - if (!strstr(cpu_model, "la464")) { - error_report("LoongArch/TCG needs cpu type la464"); - exit(1); - } - if (ram_size < 1 * GiB) { error_report("ram_size must be greater than 1G."); exit(1); From 95e2ca240739fc1a917102710d79a09f055f4d79 Mon Sep 17 00:00:00 2001 From: Song Gao Date: Tue, 22 Aug 2023 09:19:55 +0200 Subject: [PATCH 1190/1353] target/loongarch: Add avail_FP/FP_SP/FP_DP to check fpu instructions Signed-off-by: Song Gao Acked-by: Richard Henderson Message-ID: <20230822032724.1353391-12-gaosong@loongson.cn> Message-Id: <20230822071959.35620-6-philmd@linaro.org> --- .../loongarch/insn_trans/trans_farith.c.inc | 96 ++++++++++++------- target/loongarch/insn_trans/trans_fcmp.c.inc | 8 ++ target/loongarch/insn_trans/trans_fcnv.c.inc | 56 +++++------ .../loongarch/insn_trans/trans_fmemory.c.inc | 32 +++---- target/loongarch/insn_trans/trans_fmov.c.inc | 48 ++++++++-- target/loongarch/translate.c | 1 + target/loongarch/translate.h | 4 + 7 files changed, 159 insertions(+), 86 deletions(-) diff --git a/target/loongarch/insn_trans/trans_farith.c.inc b/target/loongarch/insn_trans/trans_farith.c.inc index b1a1dc7b01..a7ced99fd3 100644 --- a/target/loongarch/insn_trans/trans_farith.c.inc +++ b/target/loongarch/insn_trans/trans_farith.c.inc @@ -67,6 +67,10 @@ static bool trans_fcopysign_s(DisasContext *ctx, arg_fcopysign_s *a) TCGv src1 = get_fpr(ctx, a->fk); TCGv src2 = get_fpr(ctx, a->fj); + if (!avail_FP_SP(ctx)) { + return false; + } + CHECK_FPE; tcg_gen_deposit_i64(dest, src1, src2, 0, 31); @@ -81,6 +85,10 @@ static bool trans_fcopysign_d(DisasContext *ctx, arg_fcopysign_d *a) TCGv src1 = get_fpr(ctx, a->fk); TCGv src2 = get_fpr(ctx, a->fj); + if (!avail_FP_DP(ctx)) { + return false; + } + CHECK_FPE; tcg_gen_deposit_i64(dest, src1, src2, 0, 63); @@ -94,6 +102,10 @@ static bool trans_fabs_s(DisasContext *ctx, arg_fabs_s *a) TCGv dest = get_fpr(ctx, a->fd); TCGv src = get_fpr(ctx, a->fj); + if (!avail_FP_SP(ctx)) { + return false; + } + CHECK_FPE; tcg_gen_andi_i64(dest, src, MAKE_64BIT_MASK(0, 31)); @@ -108,6 +120,10 @@ static bool trans_fabs_d(DisasContext *ctx, arg_fabs_d *a) TCGv dest = get_fpr(ctx, a->fd); TCGv src = get_fpr(ctx, a->fj); + if (!avail_FP_DP(ctx)) { + return false; + } + CHECK_FPE; tcg_gen_andi_i64(dest, src, MAKE_64BIT_MASK(0, 63)); @@ -121,6 +137,10 @@ static bool trans_fneg_s(DisasContext *ctx, arg_fneg_s *a) TCGv dest = get_fpr(ctx, a->fd); TCGv src = get_fpr(ctx, a->fj); + if (!avail_FP_SP(ctx)) { + return false; + } + CHECK_FPE; tcg_gen_xori_i64(dest, src, 0x80000000); @@ -135,6 +155,10 @@ static bool trans_fneg_d(DisasContext *ctx, arg_fneg_d *a) TCGv dest = get_fpr(ctx, a->fd); TCGv src = get_fpr(ctx, a->fj); + if (!avail_FP_DP(ctx)) { + return false; + } + CHECK_FPE; tcg_gen_xori_i64(dest, src, 0x8000000000000000LL); @@ -143,41 +167,41 @@ static bool trans_fneg_d(DisasContext *ctx, arg_fneg_d *a) return true; } -TRANS(fadd_s, ALL, gen_fff, gen_helper_fadd_s) -TRANS(fadd_d, ALL, gen_fff, gen_helper_fadd_d) -TRANS(fsub_s, ALL, gen_fff, gen_helper_fsub_s) -TRANS(fsub_d, ALL, gen_fff, gen_helper_fsub_d) -TRANS(fmul_s, ALL, gen_fff, gen_helper_fmul_s) -TRANS(fmul_d, ALL, gen_fff, gen_helper_fmul_d) -TRANS(fdiv_s, ALL, gen_fff, gen_helper_fdiv_s) -TRANS(fdiv_d, ALL, gen_fff, gen_helper_fdiv_d) -TRANS(fmax_s, ALL, gen_fff, gen_helper_fmax_s) -TRANS(fmax_d, ALL, gen_fff, gen_helper_fmax_d) -TRANS(fmin_s, ALL, gen_fff, gen_helper_fmin_s) -TRANS(fmin_d, ALL, gen_fff, gen_helper_fmin_d) -TRANS(fmaxa_s, ALL, gen_fff, gen_helper_fmaxa_s) -TRANS(fmaxa_d, ALL, gen_fff, gen_helper_fmaxa_d) -TRANS(fmina_s, ALL, gen_fff, gen_helper_fmina_s) -TRANS(fmina_d, ALL, gen_fff, gen_helper_fmina_d) -TRANS(fscaleb_s, ALL, gen_fff, gen_helper_fscaleb_s) -TRANS(fscaleb_d, ALL, gen_fff, gen_helper_fscaleb_d) -TRANS(fsqrt_s, ALL, gen_ff, gen_helper_fsqrt_s) -TRANS(fsqrt_d, ALL, gen_ff, gen_helper_fsqrt_d) -TRANS(frecip_s, ALL, gen_ff, gen_helper_frecip_s) -TRANS(frecip_d, ALL, gen_ff, gen_helper_frecip_d) -TRANS(frsqrt_s, ALL, gen_ff, gen_helper_frsqrt_s) -TRANS(frsqrt_d, ALL, gen_ff, gen_helper_frsqrt_d) -TRANS(flogb_s, ALL, gen_ff, gen_helper_flogb_s) -TRANS(flogb_d, ALL, gen_ff, gen_helper_flogb_d) -TRANS(fclass_s, ALL, gen_ff, gen_helper_fclass_s) -TRANS(fclass_d, ALL, gen_ff, gen_helper_fclass_d) -TRANS(fmadd_s, ALL, gen_muladd, gen_helper_fmuladd_s, 0) -TRANS(fmadd_d, ALL, gen_muladd, gen_helper_fmuladd_d, 0) -TRANS(fmsub_s, ALL, gen_muladd, gen_helper_fmuladd_s, float_muladd_negate_c) -TRANS(fmsub_d, ALL, gen_muladd, gen_helper_fmuladd_d, float_muladd_negate_c) -TRANS(fnmadd_s, ALL, gen_muladd, gen_helper_fmuladd_s, float_muladd_negate_result) -TRANS(fnmadd_d, ALL, gen_muladd, gen_helper_fmuladd_d, float_muladd_negate_result) -TRANS(fnmsub_s, ALL, gen_muladd, gen_helper_fmuladd_s, +TRANS(fadd_s, FP_SP, gen_fff, gen_helper_fadd_s) +TRANS(fadd_d, FP_DP, gen_fff, gen_helper_fadd_d) +TRANS(fsub_s, FP_SP, gen_fff, gen_helper_fsub_s) +TRANS(fsub_d, FP_DP, gen_fff, gen_helper_fsub_d) +TRANS(fmul_s, FP_SP, gen_fff, gen_helper_fmul_s) +TRANS(fmul_d, FP_DP, gen_fff, gen_helper_fmul_d) +TRANS(fdiv_s, FP_SP, gen_fff, gen_helper_fdiv_s) +TRANS(fdiv_d, FP_DP, gen_fff, gen_helper_fdiv_d) +TRANS(fmax_s, FP_SP, gen_fff, gen_helper_fmax_s) +TRANS(fmax_d, FP_DP, gen_fff, gen_helper_fmax_d) +TRANS(fmin_s, FP_SP, gen_fff, gen_helper_fmin_s) +TRANS(fmin_d, FP_DP, gen_fff, gen_helper_fmin_d) +TRANS(fmaxa_s, FP_SP, gen_fff, gen_helper_fmaxa_s) +TRANS(fmaxa_d, FP_DP, gen_fff, gen_helper_fmaxa_d) +TRANS(fmina_s, FP_SP, gen_fff, gen_helper_fmina_s) +TRANS(fmina_d, FP_DP, gen_fff, gen_helper_fmina_d) +TRANS(fscaleb_s, FP_SP, gen_fff, gen_helper_fscaleb_s) +TRANS(fscaleb_d, FP_DP, gen_fff, gen_helper_fscaleb_d) +TRANS(fsqrt_s, FP_SP, gen_ff, gen_helper_fsqrt_s) +TRANS(fsqrt_d, FP_DP, gen_ff, gen_helper_fsqrt_d) +TRANS(frecip_s, FP_SP, gen_ff, gen_helper_frecip_s) +TRANS(frecip_d, FP_DP, gen_ff, gen_helper_frecip_d) +TRANS(frsqrt_s, FP_SP, gen_ff, gen_helper_frsqrt_s) +TRANS(frsqrt_d, FP_DP, gen_ff, gen_helper_frsqrt_d) +TRANS(flogb_s, FP_SP, gen_ff, gen_helper_flogb_s) +TRANS(flogb_d, FP_DP, gen_ff, gen_helper_flogb_d) +TRANS(fclass_s, FP_SP, gen_ff, gen_helper_fclass_s) +TRANS(fclass_d, FP_DP, gen_ff, gen_helper_fclass_d) +TRANS(fmadd_s, FP_SP, gen_muladd, gen_helper_fmuladd_s, 0) +TRANS(fmadd_d, FP_DP, gen_muladd, gen_helper_fmuladd_d, 0) +TRANS(fmsub_s, FP_SP, gen_muladd, gen_helper_fmuladd_s, float_muladd_negate_c) +TRANS(fmsub_d, FP_DP, gen_muladd, gen_helper_fmuladd_d, float_muladd_negate_c) +TRANS(fnmadd_s, FP_SP, gen_muladd, gen_helper_fmuladd_s, float_muladd_negate_result) +TRANS(fnmadd_d, FP_DP, gen_muladd, gen_helper_fmuladd_d, float_muladd_negate_result) +TRANS(fnmsub_s, FP_SP, gen_muladd, gen_helper_fmuladd_s, float_muladd_negate_c | float_muladd_negate_result) -TRANS(fnmsub_d, ALL, gen_muladd, gen_helper_fmuladd_d, +TRANS(fnmsub_d, FP_DP, gen_muladd, gen_helper_fmuladd_d, float_muladd_negate_c | float_muladd_negate_result) diff --git a/target/loongarch/insn_trans/trans_fcmp.c.inc b/target/loongarch/insn_trans/trans_fcmp.c.inc index a78868dbc4..43d5866a67 100644 --- a/target/loongarch/insn_trans/trans_fcmp.c.inc +++ b/target/loongarch/insn_trans/trans_fcmp.c.inc @@ -29,6 +29,10 @@ static bool trans_fcmp_cond_s(DisasContext *ctx, arg_fcmp_cond_s *a) uint32_t flags; void (*fn)(TCGv, TCGv_env, TCGv, TCGv, TCGv_i32); + if (!avail_FP_SP(ctx)) { + return false; + } + CHECK_FPE; var = tcg_temp_new(); @@ -49,6 +53,10 @@ static bool trans_fcmp_cond_d(DisasContext *ctx, arg_fcmp_cond_d *a) uint32_t flags; void (*fn)(TCGv, TCGv_env, TCGv, TCGv, TCGv_i32); + if (!avail_FP_DP(ctx)) { + return false; + } + CHECK_FPE; var = tcg_temp_new(); diff --git a/target/loongarch/insn_trans/trans_fcnv.c.inc b/target/loongarch/insn_trans/trans_fcnv.c.inc index 329a2d6872..833c059d6d 100644 --- a/target/loongarch/insn_trans/trans_fcnv.c.inc +++ b/target/loongarch/insn_trans/trans_fcnv.c.inc @@ -3,31 +3,31 @@ * Copyright (c) 2021 Loongson Technology Corporation Limited */ -TRANS(fcvt_s_d, ALL, gen_ff, gen_helper_fcvt_s_d) -TRANS(fcvt_d_s, ALL, gen_ff, gen_helper_fcvt_d_s) -TRANS(ftintrm_w_s, ALL, gen_ff, gen_helper_ftintrm_w_s) -TRANS(ftintrm_w_d, ALL, gen_ff, gen_helper_ftintrm_w_d) -TRANS(ftintrm_l_s, ALL, gen_ff, gen_helper_ftintrm_l_s) -TRANS(ftintrm_l_d, ALL, gen_ff, gen_helper_ftintrm_l_d) -TRANS(ftintrp_w_s, ALL, gen_ff, gen_helper_ftintrp_w_s) -TRANS(ftintrp_w_d, ALL, gen_ff, gen_helper_ftintrp_w_d) -TRANS(ftintrp_l_s, ALL, gen_ff, gen_helper_ftintrp_l_s) -TRANS(ftintrp_l_d, ALL, gen_ff, gen_helper_ftintrp_l_d) -TRANS(ftintrz_w_s, ALL, gen_ff, gen_helper_ftintrz_w_s) -TRANS(ftintrz_w_d, ALL, gen_ff, gen_helper_ftintrz_w_d) -TRANS(ftintrz_l_s, ALL, gen_ff, gen_helper_ftintrz_l_s) -TRANS(ftintrz_l_d, ALL, gen_ff, gen_helper_ftintrz_l_d) -TRANS(ftintrne_w_s, ALL, gen_ff, gen_helper_ftintrne_w_s) -TRANS(ftintrne_w_d, ALL, gen_ff, gen_helper_ftintrne_w_d) -TRANS(ftintrne_l_s, ALL, gen_ff, gen_helper_ftintrne_l_s) -TRANS(ftintrne_l_d, ALL, gen_ff, gen_helper_ftintrne_l_d) -TRANS(ftint_w_s, ALL, gen_ff, gen_helper_ftint_w_s) -TRANS(ftint_w_d, ALL, gen_ff, gen_helper_ftint_w_d) -TRANS(ftint_l_s, ALL, gen_ff, gen_helper_ftint_l_s) -TRANS(ftint_l_d, ALL, gen_ff, gen_helper_ftint_l_d) -TRANS(ffint_s_w, ALL, gen_ff, gen_helper_ffint_s_w) -TRANS(ffint_s_l, ALL, gen_ff, gen_helper_ffint_s_l) -TRANS(ffint_d_w, ALL, gen_ff, gen_helper_ffint_d_w) -TRANS(ffint_d_l, ALL, gen_ff, gen_helper_ffint_d_l) -TRANS(frint_s, ALL, gen_ff, gen_helper_frint_s) -TRANS(frint_d, ALL, gen_ff, gen_helper_frint_d) +TRANS(fcvt_s_d, FP_DP, gen_ff, gen_helper_fcvt_s_d) +TRANS(fcvt_d_s, FP_DP, gen_ff, gen_helper_fcvt_d_s) +TRANS(ftintrm_w_s, FP_SP, gen_ff, gen_helper_ftintrm_w_s) +TRANS(ftintrm_w_d, FP_DP, gen_ff, gen_helper_ftintrm_w_d) +TRANS(ftintrm_l_s, FP_SP, gen_ff, gen_helper_ftintrm_l_s) +TRANS(ftintrm_l_d, FP_DP, gen_ff, gen_helper_ftintrm_l_d) +TRANS(ftintrp_w_s, FP_SP, gen_ff, gen_helper_ftintrp_w_s) +TRANS(ftintrp_w_d, FP_DP, gen_ff, gen_helper_ftintrp_w_d) +TRANS(ftintrp_l_s, FP_SP, gen_ff, gen_helper_ftintrp_l_s) +TRANS(ftintrp_l_d, FP_DP, gen_ff, gen_helper_ftintrp_l_d) +TRANS(ftintrz_w_s, FP_SP, gen_ff, gen_helper_ftintrz_w_s) +TRANS(ftintrz_w_d, FP_DP, gen_ff, gen_helper_ftintrz_w_d) +TRANS(ftintrz_l_s, FP_SP, gen_ff, gen_helper_ftintrz_l_s) +TRANS(ftintrz_l_d, FP_DP, gen_ff, gen_helper_ftintrz_l_d) +TRANS(ftintrne_w_s, FP_SP, gen_ff, gen_helper_ftintrne_w_s) +TRANS(ftintrne_w_d, FP_DP, gen_ff, gen_helper_ftintrne_w_d) +TRANS(ftintrne_l_s, FP_SP, gen_ff, gen_helper_ftintrne_l_s) +TRANS(ftintrne_l_d, FP_DP, gen_ff, gen_helper_ftintrne_l_d) +TRANS(ftint_w_s, FP_SP, gen_ff, gen_helper_ftint_w_s) +TRANS(ftint_w_d, FP_DP, gen_ff, gen_helper_ftint_w_d) +TRANS(ftint_l_s, FP_SP, gen_ff, gen_helper_ftint_l_s) +TRANS(ftint_l_d, FP_DP, gen_ff, gen_helper_ftint_l_d) +TRANS(ffint_s_w, FP_SP, gen_ff, gen_helper_ffint_s_w) +TRANS(ffint_s_l, FP_SP, gen_ff, gen_helper_ffint_s_l) +TRANS(ffint_d_w, FP_DP, gen_ff, gen_helper_ffint_d_w) +TRANS(ffint_d_l, FP_DP, gen_ff, gen_helper_ffint_d_l) +TRANS(frint_s, FP_SP, gen_ff, gen_helper_frint_s) +TRANS(frint_d, FP_DP, gen_ff, gen_helper_frint_d) diff --git a/target/loongarch/insn_trans/trans_fmemory.c.inc b/target/loongarch/insn_trans/trans_fmemory.c.inc index 8e3b4522c9..5ddb8a473b 100644 --- a/target/loongarch/insn_trans/trans_fmemory.c.inc +++ b/target/loongarch/insn_trans/trans_fmemory.c.inc @@ -140,19 +140,19 @@ static bool gen_fstore_le(DisasContext *ctx, arg_frr *a, MemOp mop) return true; } -TRANS(fld_s, ALL, gen_fload_i, MO_TEUL) -TRANS(fst_s, ALL, gen_fstore_i, MO_TEUL) -TRANS(fld_d, ALL, gen_fload_i, MO_TEUQ) -TRANS(fst_d, ALL, gen_fstore_i, MO_TEUQ) -TRANS(fldx_s, ALL, gen_floadx, MO_TEUL) -TRANS(fldx_d, ALL, gen_floadx, MO_TEUQ) -TRANS(fstx_s, ALL, gen_fstorex, MO_TEUL) -TRANS(fstx_d, ALL, gen_fstorex, MO_TEUQ) -TRANS(fldgt_s, ALL, gen_fload_gt, MO_TEUL) -TRANS(fldgt_d, ALL, gen_fload_gt, MO_TEUQ) -TRANS(fldle_s, ALL, gen_fload_le, MO_TEUL) -TRANS(fldle_d, ALL, gen_fload_le, MO_TEUQ) -TRANS(fstgt_s, ALL, gen_fstore_gt, MO_TEUL) -TRANS(fstgt_d, ALL, gen_fstore_gt, MO_TEUQ) -TRANS(fstle_s, ALL, gen_fstore_le, MO_TEUL) -TRANS(fstle_d, ALL, gen_fstore_le, MO_TEUQ) +TRANS(fld_s, FP_SP, gen_fload_i, MO_TEUL) +TRANS(fst_s, FP_SP, gen_fstore_i, MO_TEUL) +TRANS(fld_d, FP_DP, gen_fload_i, MO_TEUQ) +TRANS(fst_d, FP_DP, gen_fstore_i, MO_TEUQ) +TRANS(fldx_s, FP_SP, gen_floadx, MO_TEUL) +TRANS(fldx_d, FP_DP, gen_floadx, MO_TEUQ) +TRANS(fstx_s, FP_SP, gen_fstorex, MO_TEUL) +TRANS(fstx_d, FP_DP, gen_fstorex, MO_TEUQ) +TRANS(fldgt_s, FP_SP, gen_fload_gt, MO_TEUL) +TRANS(fldgt_d, FP_DP, gen_fload_gt, MO_TEUQ) +TRANS(fldle_s, FP_SP, gen_fload_le, MO_TEUL) +TRANS(fldle_d, FP_DP, gen_fload_le, MO_TEUQ) +TRANS(fstgt_s, FP_SP, gen_fstore_gt, MO_TEUL) +TRANS(fstgt_d, FP_DP, gen_fstore_gt, MO_TEUQ) +TRANS(fstle_s, FP_SP, gen_fstore_le, MO_TEUL) +TRANS(fstle_d, FP_DP, gen_fstore_le, MO_TEUQ) diff --git a/target/loongarch/insn_trans/trans_fmov.c.inc b/target/loongarch/insn_trans/trans_fmov.c.inc index 385bbb7929..928e127820 100644 --- a/target/loongarch/insn_trans/trans_fmov.c.inc +++ b/target/loongarch/insn_trans/trans_fmov.c.inc @@ -15,6 +15,10 @@ static bool trans_fsel(DisasContext *ctx, arg_fsel *a) TCGv src2 = get_fpr(ctx, a->fk); TCGv cond; + if (!avail_FP(ctx)) { + return false; + } + CHECK_FPE; cond = tcg_temp_new(); @@ -48,6 +52,10 @@ static bool gen_r2f(DisasContext *ctx, arg_fr *a, TCGv src = gpr_src(ctx, a->rj, EXT_NONE); TCGv dest = get_fpr(ctx, a->fd); + if (!avail_FP(ctx)) { + return false; + } + CHECK_FPE; func(dest, src); @@ -62,6 +70,10 @@ static bool gen_f2r(DisasContext *ctx, arg_rf *a, TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); TCGv src = get_fpr(ctx, a->fj); + if (!avail_FP(ctx)) { + return false; + } + CHECK_FPE; func(dest, src); @@ -75,6 +87,10 @@ static bool trans_movgr2fcsr(DisasContext *ctx, arg_movgr2fcsr *a) uint32_t mask = fcsr_mask[a->fcsrd]; TCGv Rj = gpr_src(ctx, a->rj, EXT_NONE); + if (!avail_FP(ctx)) { + return false; + } + CHECK_FPE; if (mask == UINT32_MAX) { @@ -105,6 +121,10 @@ static bool trans_movfcsr2gr(DisasContext *ctx, arg_movfcsr2gr *a) { TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + if (!avail_FP(ctx)) { + return false; + } + CHECK_FPE; tcg_gen_ld32u_i64(dest, cpu_env, offsetof(CPULoongArchState, fcsr0)); @@ -134,6 +154,10 @@ static bool trans_movfr2cf(DisasContext *ctx, arg_movfr2cf *a) TCGv t0; TCGv src = get_fpr(ctx, a->fj); + if (!avail_FP(ctx)) { + return false; + } + CHECK_FPE; t0 = tcg_temp_new(); @@ -147,6 +171,10 @@ static bool trans_movcf2fr(DisasContext *ctx, arg_movcf2fr *a) { TCGv dest = get_fpr(ctx, a->fd); + if (!avail_FP(ctx)) { + return false; + } + CHECK_FPE; tcg_gen_ld8u_tl(dest, cpu_env, @@ -160,6 +188,10 @@ static bool trans_movgr2cf(DisasContext *ctx, arg_movgr2cf *a) { TCGv t0; + if (!avail_FP(ctx)) { + return false; + } + CHECK_FPE; t0 = tcg_temp_new(); @@ -171,6 +203,10 @@ static bool trans_movgr2cf(DisasContext *ctx, arg_movgr2cf *a) static bool trans_movcf2gr(DisasContext *ctx, arg_movcf2gr *a) { + if (!avail_FP(ctx)) { + return false; + } + CHECK_FPE; tcg_gen_ld8u_tl(gpr_dst(ctx, a->rd, EXT_NONE), cpu_env, @@ -178,11 +214,11 @@ static bool trans_movcf2gr(DisasContext *ctx, arg_movcf2gr *a) return true; } -TRANS(fmov_s, ALL, gen_f2f, tcg_gen_mov_tl, true) -TRANS(fmov_d, ALL, gen_f2f, tcg_gen_mov_tl, false) -TRANS(movgr2fr_w, ALL, gen_r2f, gen_movgr2fr_w) +TRANS(fmov_s, FP_SP, gen_f2f, tcg_gen_mov_tl, true) +TRANS(fmov_d, FP_DP, gen_f2f, tcg_gen_mov_tl, false) +TRANS(movgr2fr_w, FP_SP, gen_r2f, gen_movgr2fr_w) TRANS(movgr2fr_d, 64, gen_r2f, tcg_gen_mov_tl) -TRANS(movgr2frh_w, ALL, gen_r2f, gen_movgr2frh_w) -TRANS(movfr2gr_s, ALL, gen_f2r, tcg_gen_ext32s_tl) +TRANS(movgr2frh_w, FP_DP, gen_r2f, gen_movgr2frh_w) +TRANS(movfr2gr_s, FP_SP, gen_f2r, tcg_gen_ext32s_tl) TRANS(movfr2gr_d, 64, gen_f2r, tcg_gen_mov_tl) -TRANS(movfrh2gr_s, ALL, gen_f2r, gen_movfrh2gr_s) +TRANS(movfrh2gr_s, FP_DP, gen_f2r, gen_movfrh2gr_s) diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index 6967e12fc3..fd393ed76d 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -129,6 +129,7 @@ static void loongarch_tr_init_disas_context(DisasContextBase *dcbase, ctx->zero = tcg_constant_tl(0); ctx->cpucfg1 = env->cpucfg[1]; + ctx->cpucfg2 = env->cpucfg[2]; } static void loongarch_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) diff --git a/target/loongarch/translate.h b/target/loongarch/translate.h index 1342446242..0f244cd83b 100644 --- a/target/loongarch/translate.h +++ b/target/loongarch/translate.h @@ -17,6 +17,9 @@ #define avail_ALL(C) true #define avail_64(C) (FIELD_EX32((C)->cpucfg1, CPUCFG1, ARCH) == \ CPUCFG1_ARCH_LA64) +#define avail_FP(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, FP)) +#define avail_FP_SP(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, FP_SP)) +#define avail_FP_DP(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, FP_DP)) /* * If an operation is being performed on less than TARGET_LONG_BITS, @@ -40,6 +43,7 @@ typedef struct DisasContext { bool la64; /* LoongArch64 mode */ bool va32; /* 32-bit virtual address */ uint32_t cpucfg1; + uint32_t cpucfg2; } DisasContext; void generate_exception(DisasContext *ctx, int excp); From 70c8d5eaaaf1b39b13af942a359d35a3aedd0803 Mon Sep 17 00:00:00 2001 From: Song Gao Date: Tue, 22 Aug 2023 09:19:56 +0200 Subject: [PATCH 1191/1353] target/loongarch: Add avail_LSPW to check LSPW instructions Signed-off-by: Song Gao Reviewed-by: Richard Henderson Message-ID: <20230822032724.1353391-13-gaosong@loongson.cn> Message-Id: <20230822071959.35620-7-philmd@linaro.org> --- target/loongarch/insn_trans/trans_privileged.c.inc | 8 ++++++++ target/loongarch/translate.h | 1 + 2 files changed, 9 insertions(+) diff --git a/target/loongarch/insn_trans/trans_privileged.c.inc b/target/loongarch/insn_trans/trans_privileged.c.inc index 684ff547a7..099cd871f0 100644 --- a/target/loongarch/insn_trans/trans_privileged.c.inc +++ b/target/loongarch/insn_trans/trans_privileged.c.inc @@ -437,6 +437,10 @@ static bool trans_ldpte(DisasContext *ctx, arg_ldpte *a) TCGv_i32 mem_idx = tcg_constant_i32(ctx->mem_idx); TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE); + if (!avail_LSPW(ctx)) { + return true; + } + if (check_plv(ctx)) { return false; } @@ -450,6 +454,10 @@ static bool trans_lddir(DisasContext *ctx, arg_lddir *a) TCGv src = gpr_src(ctx, a->rj, EXT_NONE); TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); + if (!avail_LSPW(ctx)) { + return true; + } + if (check_plv(ctx)) { return false; } diff --git a/target/loongarch/translate.h b/target/loongarch/translate.h index 0f244cd83b..f0d7b82932 100644 --- a/target/loongarch/translate.h +++ b/target/loongarch/translate.h @@ -20,6 +20,7 @@ #define avail_FP(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, FP)) #define avail_FP_SP(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, FP_SP)) #define avail_FP_DP(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, FP_DP)) +#define avail_LSPW(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, LSPW)) /* * If an operation is being performed on less than TARGET_LONG_BITS, From b139ddf1e944e395def788193232088cd6caf946 Mon Sep 17 00:00:00 2001 From: Song Gao Date: Tue, 22 Aug 2023 09:19:57 +0200 Subject: [PATCH 1192/1353] target/loongarch: Add avail_LAM to check atomic instructions Signed-off-by: Song Gao Reviewed-by: Richard Henderson Message-ID: <20230822032724.1353391-14-gaosong@loongson.cn> Message-Id: <20230822071959.35620-8-philmd@linaro.org> --- .../loongarch/insn_trans/trans_atomic.c.inc | 72 +++++++++---------- target/loongarch/translate.h | 1 + 2 files changed, 37 insertions(+), 36 deletions(-) diff --git a/target/loongarch/insn_trans/trans_atomic.c.inc b/target/loongarch/insn_trans/trans_atomic.c.inc index 194818d74d..40085190f6 100644 --- a/target/loongarch/insn_trans/trans_atomic.c.inc +++ b/target/loongarch/insn_trans/trans_atomic.c.inc @@ -73,39 +73,39 @@ TRANS(ll_w, ALL, gen_ll, MO_TESL) TRANS(sc_w, ALL, gen_sc, MO_TESL) TRANS(ll_d, 64, gen_ll, MO_TEUQ) TRANS(sc_d, 64, gen_sc, MO_TEUQ) -TRANS(amswap_w, 64, gen_am, tcg_gen_atomic_xchg_tl, MO_TESL) -TRANS(amswap_d, 64, gen_am, tcg_gen_atomic_xchg_tl, MO_TEUQ) -TRANS(amadd_w, 64, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TESL) -TRANS(amadd_d, 64, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TEUQ) -TRANS(amand_w, 64, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TESL) -TRANS(amand_d, 64, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TEUQ) -TRANS(amor_w, 64, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TESL) -TRANS(amor_d, 64, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TEUQ) -TRANS(amxor_w, 64, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TESL) -TRANS(amxor_d, 64, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TEUQ) -TRANS(ammax_w, 64, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TESL) -TRANS(ammax_d, 64, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TEUQ) -TRANS(ammin_w, 64, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TESL) -TRANS(ammin_d, 64, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TEUQ) -TRANS(ammax_wu, 64, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TESL) -TRANS(ammax_du, 64, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TEUQ) -TRANS(ammin_wu, 64, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TESL) -TRANS(ammin_du, 64, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TEUQ) -TRANS(amswap_db_w, 64, gen_am, tcg_gen_atomic_xchg_tl, MO_TESL) -TRANS(amswap_db_d, 64, gen_am, tcg_gen_atomic_xchg_tl, MO_TEUQ) -TRANS(amadd_db_w, 64, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TESL) -TRANS(amadd_db_d, 64, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TEUQ) -TRANS(amand_db_w, 64, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TESL) -TRANS(amand_db_d, 64, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TEUQ) -TRANS(amor_db_w, 64, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TESL) -TRANS(amor_db_d, 64, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TEUQ) -TRANS(amxor_db_w, 64, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TESL) -TRANS(amxor_db_d, 64, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TEUQ) -TRANS(ammax_db_w, 64, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TESL) -TRANS(ammax_db_d, 64, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TEUQ) -TRANS(ammin_db_w, 64, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TESL) -TRANS(ammin_db_d, 64, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TEUQ) -TRANS(ammax_db_wu, 64, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TESL) -TRANS(ammax_db_du, 64, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TEUQ) -TRANS(ammin_db_wu, 64, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TESL) -TRANS(ammin_db_du, 64, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TEUQ) +TRANS(amswap_w, LAM, gen_am, tcg_gen_atomic_xchg_tl, MO_TESL) +TRANS(amswap_d, LAM, gen_am, tcg_gen_atomic_xchg_tl, MO_TEUQ) +TRANS(amadd_w, LAM, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TESL) +TRANS(amadd_d, LAM, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TEUQ) +TRANS(amand_w, LAM, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TESL) +TRANS(amand_d, LAM, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TEUQ) +TRANS(amor_w, LAM, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TESL) +TRANS(amor_d, LAM, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TEUQ) +TRANS(amxor_w, LAM, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TESL) +TRANS(amxor_d, LAM, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TEUQ) +TRANS(ammax_w, LAM, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TESL) +TRANS(ammax_d, LAM, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TEUQ) +TRANS(ammin_w, LAM, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TESL) +TRANS(ammin_d, LAM, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TEUQ) +TRANS(ammax_wu, LAM, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TESL) +TRANS(ammax_du, LAM, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TEUQ) +TRANS(ammin_wu, LAM, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TESL) +TRANS(ammin_du, LAM, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TEUQ) +TRANS(amswap_db_w, LAM, gen_am, tcg_gen_atomic_xchg_tl, MO_TESL) +TRANS(amswap_db_d, LAM, gen_am, tcg_gen_atomic_xchg_tl, MO_TEUQ) +TRANS(amadd_db_w, LAM, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TESL) +TRANS(amadd_db_d, LAM, gen_am, tcg_gen_atomic_fetch_add_tl, MO_TEUQ) +TRANS(amand_db_w, LAM, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TESL) +TRANS(amand_db_d, LAM, gen_am, tcg_gen_atomic_fetch_and_tl, MO_TEUQ) +TRANS(amor_db_w, LAM, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TESL) +TRANS(amor_db_d, LAM, gen_am, tcg_gen_atomic_fetch_or_tl, MO_TEUQ) +TRANS(amxor_db_w, LAM, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TESL) +TRANS(amxor_db_d, LAM, gen_am, tcg_gen_atomic_fetch_xor_tl, MO_TEUQ) +TRANS(ammax_db_w, LAM, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TESL) +TRANS(ammax_db_d, LAM, gen_am, tcg_gen_atomic_fetch_smax_tl, MO_TEUQ) +TRANS(ammin_db_w, LAM, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TESL) +TRANS(ammin_db_d, LAM, gen_am, tcg_gen_atomic_fetch_smin_tl, MO_TEUQ) +TRANS(ammax_db_wu, LAM, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TESL) +TRANS(ammax_db_du, LAM, gen_am, tcg_gen_atomic_fetch_umax_tl, MO_TEUQ) +TRANS(ammin_db_wu, LAM, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TESL) +TRANS(ammin_db_du, LAM, gen_am, tcg_gen_atomic_fetch_umin_tl, MO_TEUQ) diff --git a/target/loongarch/translate.h b/target/loongarch/translate.h index f0d7b82932..faf4ce87f9 100644 --- a/target/loongarch/translate.h +++ b/target/loongarch/translate.h @@ -21,6 +21,7 @@ #define avail_FP_SP(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, FP_SP)) #define avail_FP_DP(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, FP_DP)) #define avail_LSPW(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, LSPW)) +#define avail_LAM(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, LAM)) /* * If an operation is being performed on less than TARGET_LONG_BITS, From ebf288b410a38316dd6d6d15a9453222fff13d92 Mon Sep 17 00:00:00 2001 From: Song Gao Date: Tue, 22 Aug 2023 09:30:26 +0200 Subject: [PATCH 1193/1353] target/loongarch: Add avail_LSX to check LSX instructions Signed-off-by: Song Gao Reviewed-by: Richard Henderson Message-ID: <20230822032724.1353391-15-gaosong@loongson.cn> Message-Id: <20230822073026.35776-1-philmd@linaro.org> --- target/loongarch/insn_trans/trans_lsx.c.inc | 1396 +++++++++++-------- target/loongarch/translate.h | 2 + 2 files changed, 780 insertions(+), 618 deletions(-) diff --git a/target/loongarch/insn_trans/trans_lsx.c.inc b/target/loongarch/insn_trans/trans_lsx.c.inc index 45e0e738ad..5fbf2718f7 100644 --- a/target/loongarch/insn_trans/trans_lsx.c.inc +++ b/target/loongarch/insn_trans/trans_lsx.c.inc @@ -135,16 +135,20 @@ static bool gvec_subi(DisasContext *ctx, arg_vv_i *a, MemOp mop) return true; } -TRANS(vadd_b, ALL, gvec_vvv, MO_8, tcg_gen_gvec_add) -TRANS(vadd_h, ALL, gvec_vvv, MO_16, tcg_gen_gvec_add) -TRANS(vadd_w, ALL, gvec_vvv, MO_32, tcg_gen_gvec_add) -TRANS(vadd_d, ALL, gvec_vvv, MO_64, tcg_gen_gvec_add) +TRANS(vadd_b, LSX, gvec_vvv, MO_8, tcg_gen_gvec_add) +TRANS(vadd_h, LSX, gvec_vvv, MO_16, tcg_gen_gvec_add) +TRANS(vadd_w, LSX, gvec_vvv, MO_32, tcg_gen_gvec_add) +TRANS(vadd_d, LSX, gvec_vvv, MO_64, tcg_gen_gvec_add) #define VADDSUB_Q(NAME) \ static bool trans_v## NAME ##_q(DisasContext *ctx, arg_vvv *a) \ { \ TCGv_i64 rh, rl, ah, al, bh, bl; \ \ + if (!avail_LSX(ctx)) { \ + return false; \ + } \ + \ CHECK_SXE; \ \ rh = tcg_temp_new_i64(); \ @@ -170,58 +174,58 @@ static bool trans_v## NAME ##_q(DisasContext *ctx, arg_vvv *a) \ VADDSUB_Q(add) VADDSUB_Q(sub) -TRANS(vsub_b, ALL, gvec_vvv, MO_8, tcg_gen_gvec_sub) -TRANS(vsub_h, ALL, gvec_vvv, MO_16, tcg_gen_gvec_sub) -TRANS(vsub_w, ALL, gvec_vvv, MO_32, tcg_gen_gvec_sub) -TRANS(vsub_d, ALL, gvec_vvv, MO_64, tcg_gen_gvec_sub) +TRANS(vsub_b, LSX, gvec_vvv, MO_8, tcg_gen_gvec_sub) +TRANS(vsub_h, LSX, gvec_vvv, MO_16, tcg_gen_gvec_sub) +TRANS(vsub_w, LSX, gvec_vvv, MO_32, tcg_gen_gvec_sub) +TRANS(vsub_d, LSX, gvec_vvv, MO_64, tcg_gen_gvec_sub) -TRANS(vaddi_bu, ALL, gvec_vv_i, MO_8, tcg_gen_gvec_addi) -TRANS(vaddi_hu, ALL, gvec_vv_i, MO_16, tcg_gen_gvec_addi) -TRANS(vaddi_wu, ALL, gvec_vv_i, MO_32, tcg_gen_gvec_addi) -TRANS(vaddi_du, ALL, gvec_vv_i, MO_64, tcg_gen_gvec_addi) -TRANS(vsubi_bu, ALL, gvec_subi, MO_8) -TRANS(vsubi_hu, ALL, gvec_subi, MO_16) -TRANS(vsubi_wu, ALL, gvec_subi, MO_32) -TRANS(vsubi_du, ALL, gvec_subi, MO_64) +TRANS(vaddi_bu, LSX, gvec_vv_i, MO_8, tcg_gen_gvec_addi) +TRANS(vaddi_hu, LSX, gvec_vv_i, MO_16, tcg_gen_gvec_addi) +TRANS(vaddi_wu, LSX, gvec_vv_i, MO_32, tcg_gen_gvec_addi) +TRANS(vaddi_du, LSX, gvec_vv_i, MO_64, tcg_gen_gvec_addi) +TRANS(vsubi_bu, LSX, gvec_subi, MO_8) +TRANS(vsubi_hu, LSX, gvec_subi, MO_16) +TRANS(vsubi_wu, LSX, gvec_subi, MO_32) +TRANS(vsubi_du, LSX, gvec_subi, MO_64) -TRANS(vneg_b, ALL, gvec_vv, MO_8, tcg_gen_gvec_neg) -TRANS(vneg_h, ALL, gvec_vv, MO_16, tcg_gen_gvec_neg) -TRANS(vneg_w, ALL, gvec_vv, MO_32, tcg_gen_gvec_neg) -TRANS(vneg_d, ALL, gvec_vv, MO_64, tcg_gen_gvec_neg) +TRANS(vneg_b, LSX, gvec_vv, MO_8, tcg_gen_gvec_neg) +TRANS(vneg_h, LSX, gvec_vv, MO_16, tcg_gen_gvec_neg) +TRANS(vneg_w, LSX, gvec_vv, MO_32, tcg_gen_gvec_neg) +TRANS(vneg_d, LSX, gvec_vv, MO_64, tcg_gen_gvec_neg) -TRANS(vsadd_b, ALL, gvec_vvv, MO_8, tcg_gen_gvec_ssadd) -TRANS(vsadd_h, ALL, gvec_vvv, MO_16, tcg_gen_gvec_ssadd) -TRANS(vsadd_w, ALL, gvec_vvv, MO_32, tcg_gen_gvec_ssadd) -TRANS(vsadd_d, ALL, gvec_vvv, MO_64, tcg_gen_gvec_ssadd) -TRANS(vsadd_bu, ALL, gvec_vvv, MO_8, tcg_gen_gvec_usadd) -TRANS(vsadd_hu, ALL, gvec_vvv, MO_16, tcg_gen_gvec_usadd) -TRANS(vsadd_wu, ALL, gvec_vvv, MO_32, tcg_gen_gvec_usadd) -TRANS(vsadd_du, ALL, gvec_vvv, MO_64, tcg_gen_gvec_usadd) -TRANS(vssub_b, ALL, gvec_vvv, MO_8, tcg_gen_gvec_sssub) -TRANS(vssub_h, ALL, gvec_vvv, MO_16, tcg_gen_gvec_sssub) -TRANS(vssub_w, ALL, gvec_vvv, MO_32, tcg_gen_gvec_sssub) -TRANS(vssub_d, ALL, gvec_vvv, MO_64, tcg_gen_gvec_sssub) -TRANS(vssub_bu, ALL, gvec_vvv, MO_8, tcg_gen_gvec_ussub) -TRANS(vssub_hu, ALL, gvec_vvv, MO_16, tcg_gen_gvec_ussub) -TRANS(vssub_wu, ALL, gvec_vvv, MO_32, tcg_gen_gvec_ussub) -TRANS(vssub_du, ALL, gvec_vvv, MO_64, tcg_gen_gvec_ussub) +TRANS(vsadd_b, LSX, gvec_vvv, MO_8, tcg_gen_gvec_ssadd) +TRANS(vsadd_h, LSX, gvec_vvv, MO_16, tcg_gen_gvec_ssadd) +TRANS(vsadd_w, LSX, gvec_vvv, MO_32, tcg_gen_gvec_ssadd) +TRANS(vsadd_d, LSX, gvec_vvv, MO_64, tcg_gen_gvec_ssadd) +TRANS(vsadd_bu, LSX, gvec_vvv, MO_8, tcg_gen_gvec_usadd) +TRANS(vsadd_hu, LSX, gvec_vvv, MO_16, tcg_gen_gvec_usadd) +TRANS(vsadd_wu, LSX, gvec_vvv, MO_32, tcg_gen_gvec_usadd) +TRANS(vsadd_du, LSX, gvec_vvv, MO_64, tcg_gen_gvec_usadd) +TRANS(vssub_b, LSX, gvec_vvv, MO_8, tcg_gen_gvec_sssub) +TRANS(vssub_h, LSX, gvec_vvv, MO_16, tcg_gen_gvec_sssub) +TRANS(vssub_w, LSX, gvec_vvv, MO_32, tcg_gen_gvec_sssub) +TRANS(vssub_d, LSX, gvec_vvv, MO_64, tcg_gen_gvec_sssub) +TRANS(vssub_bu, LSX, gvec_vvv, MO_8, tcg_gen_gvec_ussub) +TRANS(vssub_hu, LSX, gvec_vvv, MO_16, tcg_gen_gvec_ussub) +TRANS(vssub_wu, LSX, gvec_vvv, MO_32, tcg_gen_gvec_ussub) +TRANS(vssub_du, LSX, gvec_vvv, MO_64, tcg_gen_gvec_ussub) -TRANS(vhaddw_h_b, ALL, gen_vvv, gen_helper_vhaddw_h_b) -TRANS(vhaddw_w_h, ALL, gen_vvv, gen_helper_vhaddw_w_h) -TRANS(vhaddw_d_w, ALL, gen_vvv, gen_helper_vhaddw_d_w) -TRANS(vhaddw_q_d, ALL, gen_vvv, gen_helper_vhaddw_q_d) -TRANS(vhaddw_hu_bu, ALL, gen_vvv, gen_helper_vhaddw_hu_bu) -TRANS(vhaddw_wu_hu, ALL, gen_vvv, gen_helper_vhaddw_wu_hu) -TRANS(vhaddw_du_wu, ALL, gen_vvv, gen_helper_vhaddw_du_wu) -TRANS(vhaddw_qu_du, ALL, gen_vvv, gen_helper_vhaddw_qu_du) -TRANS(vhsubw_h_b, ALL, gen_vvv, gen_helper_vhsubw_h_b) -TRANS(vhsubw_w_h, ALL, gen_vvv, gen_helper_vhsubw_w_h) -TRANS(vhsubw_d_w, ALL, gen_vvv, gen_helper_vhsubw_d_w) -TRANS(vhsubw_q_d, ALL, gen_vvv, gen_helper_vhsubw_q_d) -TRANS(vhsubw_hu_bu, ALL, gen_vvv, gen_helper_vhsubw_hu_bu) -TRANS(vhsubw_wu_hu, ALL, gen_vvv, gen_helper_vhsubw_wu_hu) -TRANS(vhsubw_du_wu, ALL, gen_vvv, gen_helper_vhsubw_du_wu) -TRANS(vhsubw_qu_du, ALL, gen_vvv, gen_helper_vhsubw_qu_du) +TRANS(vhaddw_h_b, LSX, gen_vvv, gen_helper_vhaddw_h_b) +TRANS(vhaddw_w_h, LSX, gen_vvv, gen_helper_vhaddw_w_h) +TRANS(vhaddw_d_w, LSX, gen_vvv, gen_helper_vhaddw_d_w) +TRANS(vhaddw_q_d, LSX, gen_vvv, gen_helper_vhaddw_q_d) +TRANS(vhaddw_hu_bu, LSX, gen_vvv, gen_helper_vhaddw_hu_bu) +TRANS(vhaddw_wu_hu, LSX, gen_vvv, gen_helper_vhaddw_wu_hu) +TRANS(vhaddw_du_wu, LSX, gen_vvv, gen_helper_vhaddw_du_wu) +TRANS(vhaddw_qu_du, LSX, gen_vvv, gen_helper_vhaddw_qu_du) +TRANS(vhsubw_h_b, LSX, gen_vvv, gen_helper_vhsubw_h_b) +TRANS(vhsubw_w_h, LSX, gen_vvv, gen_helper_vhsubw_w_h) +TRANS(vhsubw_d_w, LSX, gen_vvv, gen_helper_vhsubw_d_w) +TRANS(vhsubw_q_d, LSX, gen_vvv, gen_helper_vhsubw_q_d) +TRANS(vhsubw_hu_bu, LSX, gen_vvv, gen_helper_vhsubw_hu_bu) +TRANS(vhsubw_wu_hu, LSX, gen_vvv, gen_helper_vhsubw_wu_hu) +TRANS(vhsubw_du_wu, LSX, gen_vvv, gen_helper_vhsubw_du_wu) +TRANS(vhsubw_qu_du, LSX, gen_vvv, gen_helper_vhsubw_qu_du) static void gen_vaddwev_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -301,10 +305,10 @@ static void do_vaddwev_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vaddwev_h_b, ALL, gvec_vvv, MO_8, do_vaddwev_s) -TRANS(vaddwev_w_h, ALL, gvec_vvv, MO_16, do_vaddwev_s) -TRANS(vaddwev_d_w, ALL, gvec_vvv, MO_32, do_vaddwev_s) -TRANS(vaddwev_q_d, ALL, gvec_vvv, MO_64, do_vaddwev_s) +TRANS(vaddwev_h_b, LSX, gvec_vvv, MO_8, do_vaddwev_s) +TRANS(vaddwev_w_h, LSX, gvec_vvv, MO_16, do_vaddwev_s) +TRANS(vaddwev_d_w, LSX, gvec_vvv, MO_32, do_vaddwev_s) +TRANS(vaddwev_q_d, LSX, gvec_vvv, MO_64, do_vaddwev_s) static void gen_vaddwod_w_h(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) { @@ -380,10 +384,10 @@ static void do_vaddwod_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vaddwod_h_b, ALL, gvec_vvv, MO_8, do_vaddwod_s) -TRANS(vaddwod_w_h, ALL, gvec_vvv, MO_16, do_vaddwod_s) -TRANS(vaddwod_d_w, ALL, gvec_vvv, MO_32, do_vaddwod_s) -TRANS(vaddwod_q_d, ALL, gvec_vvv, MO_64, do_vaddwod_s) +TRANS(vaddwod_h_b, LSX, gvec_vvv, MO_8, do_vaddwod_s) +TRANS(vaddwod_w_h, LSX, gvec_vvv, MO_16, do_vaddwod_s) +TRANS(vaddwod_d_w, LSX, gvec_vvv, MO_32, do_vaddwod_s) +TRANS(vaddwod_q_d, LSX, gvec_vvv, MO_64, do_vaddwod_s) static void gen_vsubwev_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -463,10 +467,10 @@ static void do_vsubwev_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vsubwev_h_b, ALL, gvec_vvv, MO_8, do_vsubwev_s) -TRANS(vsubwev_w_h, ALL, gvec_vvv, MO_16, do_vsubwev_s) -TRANS(vsubwev_d_w, ALL, gvec_vvv, MO_32, do_vsubwev_s) -TRANS(vsubwev_q_d, ALL, gvec_vvv, MO_64, do_vsubwev_s) +TRANS(vsubwev_h_b, LSX, gvec_vvv, MO_8, do_vsubwev_s) +TRANS(vsubwev_w_h, LSX, gvec_vvv, MO_16, do_vsubwev_s) +TRANS(vsubwev_d_w, LSX, gvec_vvv, MO_32, do_vsubwev_s) +TRANS(vsubwev_q_d, LSX, gvec_vvv, MO_64, do_vsubwev_s) static void gen_vsubwod_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -542,10 +546,10 @@ static void do_vsubwod_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vsubwod_h_b, ALL, gvec_vvv, MO_8, do_vsubwod_s) -TRANS(vsubwod_w_h, ALL, gvec_vvv, MO_16, do_vsubwod_s) -TRANS(vsubwod_d_w, ALL, gvec_vvv, MO_32, do_vsubwod_s) -TRANS(vsubwod_q_d, ALL, gvec_vvv, MO_64, do_vsubwod_s) +TRANS(vsubwod_h_b, LSX, gvec_vvv, MO_8, do_vsubwod_s) +TRANS(vsubwod_w_h, LSX, gvec_vvv, MO_16, do_vsubwod_s) +TRANS(vsubwod_d_w, LSX, gvec_vvv, MO_32, do_vsubwod_s) +TRANS(vsubwod_q_d, LSX, gvec_vvv, MO_64, do_vsubwod_s) static void gen_vaddwev_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -617,10 +621,10 @@ static void do_vaddwev_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vaddwev_h_bu, ALL, gvec_vvv, MO_8, do_vaddwev_u) -TRANS(vaddwev_w_hu, ALL, gvec_vvv, MO_16, do_vaddwev_u) -TRANS(vaddwev_d_wu, ALL, gvec_vvv, MO_32, do_vaddwev_u) -TRANS(vaddwev_q_du, ALL, gvec_vvv, MO_64, do_vaddwev_u) +TRANS(vaddwev_h_bu, LSX, gvec_vvv, MO_8, do_vaddwev_u) +TRANS(vaddwev_w_hu, LSX, gvec_vvv, MO_16, do_vaddwev_u) +TRANS(vaddwev_d_wu, LSX, gvec_vvv, MO_32, do_vaddwev_u) +TRANS(vaddwev_q_du, LSX, gvec_vvv, MO_64, do_vaddwev_u) static void gen_vaddwod_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -696,10 +700,10 @@ static void do_vaddwod_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vaddwod_h_bu, ALL, gvec_vvv, MO_8, do_vaddwod_u) -TRANS(vaddwod_w_hu, ALL, gvec_vvv, MO_16, do_vaddwod_u) -TRANS(vaddwod_d_wu, ALL, gvec_vvv, MO_32, do_vaddwod_u) -TRANS(vaddwod_q_du, ALL, gvec_vvv, MO_64, do_vaddwod_u) +TRANS(vaddwod_h_bu, LSX, gvec_vvv, MO_8, do_vaddwod_u) +TRANS(vaddwod_w_hu, LSX, gvec_vvv, MO_16, do_vaddwod_u) +TRANS(vaddwod_d_wu, LSX, gvec_vvv, MO_32, do_vaddwod_u) +TRANS(vaddwod_q_du, LSX, gvec_vvv, MO_64, do_vaddwod_u) static void gen_vsubwev_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -771,10 +775,10 @@ static void do_vsubwev_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vsubwev_h_bu, ALL, gvec_vvv, MO_8, do_vsubwev_u) -TRANS(vsubwev_w_hu, ALL, gvec_vvv, MO_16, do_vsubwev_u) -TRANS(vsubwev_d_wu, ALL, gvec_vvv, MO_32, do_vsubwev_u) -TRANS(vsubwev_q_du, ALL, gvec_vvv, MO_64, do_vsubwev_u) +TRANS(vsubwev_h_bu, LSX, gvec_vvv, MO_8, do_vsubwev_u) +TRANS(vsubwev_w_hu, LSX, gvec_vvv, MO_16, do_vsubwev_u) +TRANS(vsubwev_d_wu, LSX, gvec_vvv, MO_32, do_vsubwev_u) +TRANS(vsubwev_q_du, LSX, gvec_vvv, MO_64, do_vsubwev_u) static void gen_vsubwod_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -850,10 +854,10 @@ static void do_vsubwod_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vsubwod_h_bu, ALL, gvec_vvv, MO_8, do_vsubwod_u) -TRANS(vsubwod_w_hu, ALL, gvec_vvv, MO_16, do_vsubwod_u) -TRANS(vsubwod_d_wu, ALL, gvec_vvv, MO_32, do_vsubwod_u) -TRANS(vsubwod_q_du, ALL, gvec_vvv, MO_64, do_vsubwod_u) +TRANS(vsubwod_h_bu, LSX, gvec_vvv, MO_8, do_vsubwod_u) +TRANS(vsubwod_w_hu, LSX, gvec_vvv, MO_16, do_vsubwod_u) +TRANS(vsubwod_d_wu, LSX, gvec_vvv, MO_32, do_vsubwod_u) +TRANS(vsubwod_q_du, LSX, gvec_vvv, MO_64, do_vsubwod_u) static void gen_vaddwev_u_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -933,10 +937,10 @@ static void do_vaddwev_u_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vaddwev_h_bu_b, ALL, gvec_vvv, MO_8, do_vaddwev_u_s) -TRANS(vaddwev_w_hu_h, ALL, gvec_vvv, MO_16, do_vaddwev_u_s) -TRANS(vaddwev_d_wu_w, ALL, gvec_vvv, MO_32, do_vaddwev_u_s) -TRANS(vaddwev_q_du_d, ALL, gvec_vvv, MO_64, do_vaddwev_u_s) +TRANS(vaddwev_h_bu_b, LSX, gvec_vvv, MO_8, do_vaddwev_u_s) +TRANS(vaddwev_w_hu_h, LSX, gvec_vvv, MO_16, do_vaddwev_u_s) +TRANS(vaddwev_d_wu_w, LSX, gvec_vvv, MO_32, do_vaddwev_u_s) +TRANS(vaddwev_q_du_d, LSX, gvec_vvv, MO_64, do_vaddwev_u_s) static void gen_vaddwod_u_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -1013,10 +1017,10 @@ static void do_vaddwod_u_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vaddwod_h_bu_b, ALL, gvec_vvv, MO_8, do_vaddwod_u_s) -TRANS(vaddwod_w_hu_h, ALL, gvec_vvv, MO_16, do_vaddwod_u_s) -TRANS(vaddwod_d_wu_w, ALL, gvec_vvv, MO_32, do_vaddwod_u_s) -TRANS(vaddwod_q_du_d, ALL, gvec_vvv, MO_64, do_vaddwod_u_s) +TRANS(vaddwod_h_bu_b, LSX, gvec_vvv, MO_8, do_vaddwod_u_s) +TRANS(vaddwod_w_hu_h, LSX, gvec_vvv, MO_16, do_vaddwod_u_s) +TRANS(vaddwod_d_wu_w, LSX, gvec_vvv, MO_32, do_vaddwod_u_s) +TRANS(vaddwod_q_du_d, LSX, gvec_vvv, MO_64, do_vaddwod_u_s) static void do_vavg(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b, void (*gen_shr_vec)(unsigned, TCGv_vec, @@ -1125,14 +1129,14 @@ static void do_vavg_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vavg_b, ALL, gvec_vvv, MO_8, do_vavg_s) -TRANS(vavg_h, ALL, gvec_vvv, MO_16, do_vavg_s) -TRANS(vavg_w, ALL, gvec_vvv, MO_32, do_vavg_s) -TRANS(vavg_d, ALL, gvec_vvv, MO_64, do_vavg_s) -TRANS(vavg_bu, ALL, gvec_vvv, MO_8, do_vavg_u) -TRANS(vavg_hu, ALL, gvec_vvv, MO_16, do_vavg_u) -TRANS(vavg_wu, ALL, gvec_vvv, MO_32, do_vavg_u) -TRANS(vavg_du, ALL, gvec_vvv, MO_64, do_vavg_u) +TRANS(vavg_b, LSX, gvec_vvv, MO_8, do_vavg_s) +TRANS(vavg_h, LSX, gvec_vvv, MO_16, do_vavg_s) +TRANS(vavg_w, LSX, gvec_vvv, MO_32, do_vavg_s) +TRANS(vavg_d, LSX, gvec_vvv, MO_64, do_vavg_s) +TRANS(vavg_bu, LSX, gvec_vvv, MO_8, do_vavg_u) +TRANS(vavg_hu, LSX, gvec_vvv, MO_16, do_vavg_u) +TRANS(vavg_wu, LSX, gvec_vvv, MO_32, do_vavg_u) +TRANS(vavg_du, LSX, gvec_vvv, MO_64, do_vavg_u) static void do_vavgr_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) @@ -1206,14 +1210,14 @@ static void do_vavgr_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vavgr_b, ALL, gvec_vvv, MO_8, do_vavgr_s) -TRANS(vavgr_h, ALL, gvec_vvv, MO_16, do_vavgr_s) -TRANS(vavgr_w, ALL, gvec_vvv, MO_32, do_vavgr_s) -TRANS(vavgr_d, ALL, gvec_vvv, MO_64, do_vavgr_s) -TRANS(vavgr_bu, ALL, gvec_vvv, MO_8, do_vavgr_u) -TRANS(vavgr_hu, ALL, gvec_vvv, MO_16, do_vavgr_u) -TRANS(vavgr_wu, ALL, gvec_vvv, MO_32, do_vavgr_u) -TRANS(vavgr_du, ALL, gvec_vvv, MO_64, do_vavgr_u) +TRANS(vavgr_b, LSX, gvec_vvv, MO_8, do_vavgr_s) +TRANS(vavgr_h, LSX, gvec_vvv, MO_16, do_vavgr_s) +TRANS(vavgr_w, LSX, gvec_vvv, MO_32, do_vavgr_s) +TRANS(vavgr_d, LSX, gvec_vvv, MO_64, do_vavgr_s) +TRANS(vavgr_bu, LSX, gvec_vvv, MO_8, do_vavgr_u) +TRANS(vavgr_hu, LSX, gvec_vvv, MO_16, do_vavgr_u) +TRANS(vavgr_wu, LSX, gvec_vvv, MO_32, do_vavgr_u) +TRANS(vavgr_du, LSX, gvec_vvv, MO_64, do_vavgr_u) static void gen_vabsd_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -1301,14 +1305,14 @@ static void do_vabsd_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vabsd_b, ALL, gvec_vvv, MO_8, do_vabsd_s) -TRANS(vabsd_h, ALL, gvec_vvv, MO_16, do_vabsd_s) -TRANS(vabsd_w, ALL, gvec_vvv, MO_32, do_vabsd_s) -TRANS(vabsd_d, ALL, gvec_vvv, MO_64, do_vabsd_s) -TRANS(vabsd_bu, ALL, gvec_vvv, MO_8, do_vabsd_u) -TRANS(vabsd_hu, ALL, gvec_vvv, MO_16, do_vabsd_u) -TRANS(vabsd_wu, ALL, gvec_vvv, MO_32, do_vabsd_u) -TRANS(vabsd_du, ALL, gvec_vvv, MO_64, do_vabsd_u) +TRANS(vabsd_b, LSX, gvec_vvv, MO_8, do_vabsd_s) +TRANS(vabsd_h, LSX, gvec_vvv, MO_16, do_vabsd_s) +TRANS(vabsd_w, LSX, gvec_vvv, MO_32, do_vabsd_s) +TRANS(vabsd_d, LSX, gvec_vvv, MO_64, do_vabsd_s) +TRANS(vabsd_bu, LSX, gvec_vvv, MO_8, do_vabsd_u) +TRANS(vabsd_hu, LSX, gvec_vvv, MO_16, do_vabsd_u) +TRANS(vabsd_wu, LSX, gvec_vvv, MO_32, do_vabsd_u) +TRANS(vabsd_du, LSX, gvec_vvv, MO_64, do_vabsd_u) static void gen_vadda(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -1358,28 +1362,28 @@ static void do_vadda(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vadda_b, ALL, gvec_vvv, MO_8, do_vadda) -TRANS(vadda_h, ALL, gvec_vvv, MO_16, do_vadda) -TRANS(vadda_w, ALL, gvec_vvv, MO_32, do_vadda) -TRANS(vadda_d, ALL, gvec_vvv, MO_64, do_vadda) +TRANS(vadda_b, LSX, gvec_vvv, MO_8, do_vadda) +TRANS(vadda_h, LSX, gvec_vvv, MO_16, do_vadda) +TRANS(vadda_w, LSX, gvec_vvv, MO_32, do_vadda) +TRANS(vadda_d, LSX, gvec_vvv, MO_64, do_vadda) -TRANS(vmax_b, ALL, gvec_vvv, MO_8, tcg_gen_gvec_smax) -TRANS(vmax_h, ALL, gvec_vvv, MO_16, tcg_gen_gvec_smax) -TRANS(vmax_w, ALL, gvec_vvv, MO_32, tcg_gen_gvec_smax) -TRANS(vmax_d, ALL, gvec_vvv, MO_64, tcg_gen_gvec_smax) -TRANS(vmax_bu, ALL, gvec_vvv, MO_8, tcg_gen_gvec_umax) -TRANS(vmax_hu, ALL, gvec_vvv, MO_16, tcg_gen_gvec_umax) -TRANS(vmax_wu, ALL, gvec_vvv, MO_32, tcg_gen_gvec_umax) -TRANS(vmax_du, ALL, gvec_vvv, MO_64, tcg_gen_gvec_umax) +TRANS(vmax_b, LSX, gvec_vvv, MO_8, tcg_gen_gvec_smax) +TRANS(vmax_h, LSX, gvec_vvv, MO_16, tcg_gen_gvec_smax) +TRANS(vmax_w, LSX, gvec_vvv, MO_32, tcg_gen_gvec_smax) +TRANS(vmax_d, LSX, gvec_vvv, MO_64, tcg_gen_gvec_smax) +TRANS(vmax_bu, LSX, gvec_vvv, MO_8, tcg_gen_gvec_umax) +TRANS(vmax_hu, LSX, gvec_vvv, MO_16, tcg_gen_gvec_umax) +TRANS(vmax_wu, LSX, gvec_vvv, MO_32, tcg_gen_gvec_umax) +TRANS(vmax_du, LSX, gvec_vvv, MO_64, tcg_gen_gvec_umax) -TRANS(vmin_b, ALL, gvec_vvv, MO_8, tcg_gen_gvec_smin) -TRANS(vmin_h, ALL, gvec_vvv, MO_16, tcg_gen_gvec_smin) -TRANS(vmin_w, ALL, gvec_vvv, MO_32, tcg_gen_gvec_smin) -TRANS(vmin_d, ALL, gvec_vvv, MO_64, tcg_gen_gvec_smin) -TRANS(vmin_bu, ALL, gvec_vvv, MO_8, tcg_gen_gvec_umin) -TRANS(vmin_hu, ALL, gvec_vvv, MO_16, tcg_gen_gvec_umin) -TRANS(vmin_wu, ALL, gvec_vvv, MO_32, tcg_gen_gvec_umin) -TRANS(vmin_du, ALL, gvec_vvv, MO_64, tcg_gen_gvec_umin) +TRANS(vmin_b, LSX, gvec_vvv, MO_8, tcg_gen_gvec_smin) +TRANS(vmin_h, LSX, gvec_vvv, MO_16, tcg_gen_gvec_smin) +TRANS(vmin_w, LSX, gvec_vvv, MO_32, tcg_gen_gvec_smin) +TRANS(vmin_d, LSX, gvec_vvv, MO_64, tcg_gen_gvec_smin) +TRANS(vmin_bu, LSX, gvec_vvv, MO_8, tcg_gen_gvec_umin) +TRANS(vmin_hu, LSX, gvec_vvv, MO_16, tcg_gen_gvec_umin) +TRANS(vmin_wu, LSX, gvec_vvv, MO_32, tcg_gen_gvec_umin) +TRANS(vmin_du, LSX, gvec_vvv, MO_64, tcg_gen_gvec_umin) static void gen_vmini_s(unsigned vece, TCGv_vec t, TCGv_vec a, int64_t imm) { @@ -1473,14 +1477,14 @@ static void do_vmini_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_2i(vd_ofs, vj_ofs, oprsz, maxsz, imm, &op[vece]); } -TRANS(vmini_b, ALL, gvec_vv_i, MO_8, do_vmini_s) -TRANS(vmini_h, ALL, gvec_vv_i, MO_16, do_vmini_s) -TRANS(vmini_w, ALL, gvec_vv_i, MO_32, do_vmini_s) -TRANS(vmini_d, ALL, gvec_vv_i, MO_64, do_vmini_s) -TRANS(vmini_bu, ALL, gvec_vv_i, MO_8, do_vmini_u) -TRANS(vmini_hu, ALL, gvec_vv_i, MO_16, do_vmini_u) -TRANS(vmini_wu, ALL, gvec_vv_i, MO_32, do_vmini_u) -TRANS(vmini_du, ALL, gvec_vv_i, MO_64, do_vmini_u) +TRANS(vmini_b, LSX, gvec_vv_i, MO_8, do_vmini_s) +TRANS(vmini_h, LSX, gvec_vv_i, MO_16, do_vmini_s) +TRANS(vmini_w, LSX, gvec_vv_i, MO_32, do_vmini_s) +TRANS(vmini_d, LSX, gvec_vv_i, MO_64, do_vmini_s) +TRANS(vmini_bu, LSX, gvec_vv_i, MO_8, do_vmini_u) +TRANS(vmini_hu, LSX, gvec_vv_i, MO_16, do_vmini_u) +TRANS(vmini_wu, LSX, gvec_vv_i, MO_32, do_vmini_u) +TRANS(vmini_du, LSX, gvec_vv_i, MO_64, do_vmini_u) static void do_vmaxi_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, int64_t imm, uint32_t oprsz, uint32_t maxsz) @@ -1554,19 +1558,19 @@ static void do_vmaxi_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_2i(vd_ofs, vj_ofs, oprsz, maxsz, imm, &op[vece]); } -TRANS(vmaxi_b, ALL, gvec_vv_i, MO_8, do_vmaxi_s) -TRANS(vmaxi_h, ALL, gvec_vv_i, MO_16, do_vmaxi_s) -TRANS(vmaxi_w, ALL, gvec_vv_i, MO_32, do_vmaxi_s) -TRANS(vmaxi_d, ALL, gvec_vv_i, MO_64, do_vmaxi_s) -TRANS(vmaxi_bu, ALL, gvec_vv_i, MO_8, do_vmaxi_u) -TRANS(vmaxi_hu, ALL, gvec_vv_i, MO_16, do_vmaxi_u) -TRANS(vmaxi_wu, ALL, gvec_vv_i, MO_32, do_vmaxi_u) -TRANS(vmaxi_du, ALL, gvec_vv_i, MO_64, do_vmaxi_u) +TRANS(vmaxi_b, LSX, gvec_vv_i, MO_8, do_vmaxi_s) +TRANS(vmaxi_h, LSX, gvec_vv_i, MO_16, do_vmaxi_s) +TRANS(vmaxi_w, LSX, gvec_vv_i, MO_32, do_vmaxi_s) +TRANS(vmaxi_d, LSX, gvec_vv_i, MO_64, do_vmaxi_s) +TRANS(vmaxi_bu, LSX, gvec_vv_i, MO_8, do_vmaxi_u) +TRANS(vmaxi_hu, LSX, gvec_vv_i, MO_16, do_vmaxi_u) +TRANS(vmaxi_wu, LSX, gvec_vv_i, MO_32, do_vmaxi_u) +TRANS(vmaxi_du, LSX, gvec_vv_i, MO_64, do_vmaxi_u) -TRANS(vmul_b, ALL, gvec_vvv, MO_8, tcg_gen_gvec_mul) -TRANS(vmul_h, ALL, gvec_vvv, MO_16, tcg_gen_gvec_mul) -TRANS(vmul_w, ALL, gvec_vvv, MO_32, tcg_gen_gvec_mul) -TRANS(vmul_d, ALL, gvec_vvv, MO_64, tcg_gen_gvec_mul) +TRANS(vmul_b, LSX, gvec_vvv, MO_8, tcg_gen_gvec_mul) +TRANS(vmul_h, LSX, gvec_vvv, MO_16, tcg_gen_gvec_mul) +TRANS(vmul_w, LSX, gvec_vvv, MO_32, tcg_gen_gvec_mul) +TRANS(vmul_d, LSX, gvec_vvv, MO_64, tcg_gen_gvec_mul) static void gen_vmuh_w(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) { @@ -1607,10 +1611,10 @@ static void do_vmuh_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vmuh_b, ALL, gvec_vvv, MO_8, do_vmuh_s) -TRANS(vmuh_h, ALL, gvec_vvv, MO_16, do_vmuh_s) -TRANS(vmuh_w, ALL, gvec_vvv, MO_32, do_vmuh_s) -TRANS(vmuh_d, ALL, gvec_vvv, MO_64, do_vmuh_s) +TRANS(vmuh_b, LSX, gvec_vvv, MO_8, do_vmuh_s) +TRANS(vmuh_h, LSX, gvec_vvv, MO_16, do_vmuh_s) +TRANS(vmuh_w, LSX, gvec_vvv, MO_32, do_vmuh_s) +TRANS(vmuh_d, LSX, gvec_vvv, MO_64, do_vmuh_s) static void gen_vmuh_wu(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) { @@ -1651,10 +1655,10 @@ static void do_vmuh_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vmuh_bu, ALL, gvec_vvv, MO_8, do_vmuh_u) -TRANS(vmuh_hu, ALL, gvec_vvv, MO_16, do_vmuh_u) -TRANS(vmuh_wu, ALL, gvec_vvv, MO_32, do_vmuh_u) -TRANS(vmuh_du, ALL, gvec_vvv, MO_64, do_vmuh_u) +TRANS(vmuh_bu, LSX, gvec_vvv, MO_8, do_vmuh_u) +TRANS(vmuh_hu, LSX, gvec_vvv, MO_16, do_vmuh_u) +TRANS(vmuh_wu, LSX, gvec_vvv, MO_32, do_vmuh_u) +TRANS(vmuh_du, LSX, gvec_vvv, MO_64, do_vmuh_u) static void gen_vmulwev_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -1724,9 +1728,9 @@ static void do_vmulwev_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vmulwev_h_b, ALL, gvec_vvv, MO_8, do_vmulwev_s) -TRANS(vmulwev_w_h, ALL, gvec_vvv, MO_16, do_vmulwev_s) -TRANS(vmulwev_d_w, ALL, gvec_vvv, MO_32, do_vmulwev_s) +TRANS(vmulwev_h_b, LSX, gvec_vvv, MO_8, do_vmulwev_s) +TRANS(vmulwev_w_h, LSX, gvec_vvv, MO_16, do_vmulwev_s) +TRANS(vmulwev_d_w, LSX, gvec_vvv, MO_32, do_vmulwev_s) static void tcg_gen_mulus2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2) @@ -1739,6 +1743,10 @@ static bool trans_## NAME (DisasContext *ctx, arg_vvv *a) \ { \ TCGv_i64 rh, rl, arg1, arg2; \ \ + if (!avail_LSX(ctx)) { \ + return false; \ + } \ + \ rh = tcg_temp_new_i64(); \ rl = tcg_temp_new_i64(); \ arg1 = tcg_temp_new_i64(); \ @@ -1828,9 +1836,9 @@ static void do_vmulwod_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vmulwod_h_b, ALL, gvec_vvv, MO_8, do_vmulwod_s) -TRANS(vmulwod_w_h, ALL, gvec_vvv, MO_16, do_vmulwod_s) -TRANS(vmulwod_d_w, ALL, gvec_vvv, MO_32, do_vmulwod_s) +TRANS(vmulwod_h_b, LSX, gvec_vvv, MO_8, do_vmulwod_s) +TRANS(vmulwod_w_h, LSX, gvec_vvv, MO_16, do_vmulwod_s) +TRANS(vmulwod_d_w, LSX, gvec_vvv, MO_32, do_vmulwod_s) static void gen_vmulwev_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -1898,9 +1906,9 @@ static void do_vmulwev_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vmulwev_h_bu, ALL, gvec_vvv, MO_8, do_vmulwev_u) -TRANS(vmulwev_w_hu, ALL, gvec_vvv, MO_16, do_vmulwev_u) -TRANS(vmulwev_d_wu, ALL, gvec_vvv, MO_32, do_vmulwev_u) +TRANS(vmulwev_h_bu, LSX, gvec_vvv, MO_8, do_vmulwev_u) +TRANS(vmulwev_w_hu, LSX, gvec_vvv, MO_16, do_vmulwev_u) +TRANS(vmulwev_d_wu, LSX, gvec_vvv, MO_32, do_vmulwev_u) static void gen_vmulwod_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -1968,9 +1976,9 @@ static void do_vmulwod_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vmulwod_h_bu, ALL, gvec_vvv, MO_8, do_vmulwod_u) -TRANS(vmulwod_w_hu, ALL, gvec_vvv, MO_16, do_vmulwod_u) -TRANS(vmulwod_d_wu, ALL, gvec_vvv, MO_32, do_vmulwod_u) +TRANS(vmulwod_h_bu, LSX, gvec_vvv, MO_8, do_vmulwod_u) +TRANS(vmulwod_w_hu, LSX, gvec_vvv, MO_16, do_vmulwod_u) +TRANS(vmulwod_d_wu, LSX, gvec_vvv, MO_32, do_vmulwod_u) static void gen_vmulwev_u_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -2040,9 +2048,9 @@ static void do_vmulwev_u_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vmulwev_h_bu_b, ALL, gvec_vvv, MO_8, do_vmulwev_u_s) -TRANS(vmulwev_w_hu_h, ALL, gvec_vvv, MO_16, do_vmulwev_u_s) -TRANS(vmulwev_d_wu_w, ALL, gvec_vvv, MO_32, do_vmulwev_u_s) +TRANS(vmulwev_h_bu_b, LSX, gvec_vvv, MO_8, do_vmulwev_u_s) +TRANS(vmulwev_w_hu_h, LSX, gvec_vvv, MO_16, do_vmulwev_u_s) +TRANS(vmulwev_d_wu_w, LSX, gvec_vvv, MO_32, do_vmulwev_u_s) static void gen_vmulwod_u_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -2109,9 +2117,9 @@ static void do_vmulwod_u_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vmulwod_h_bu_b, ALL, gvec_vvv, MO_8, do_vmulwod_u_s) -TRANS(vmulwod_w_hu_h, ALL, gvec_vvv, MO_16, do_vmulwod_u_s) -TRANS(vmulwod_d_wu_w, ALL, gvec_vvv, MO_32, do_vmulwod_u_s) +TRANS(vmulwod_h_bu_b, LSX, gvec_vvv, MO_8, do_vmulwod_u_s) +TRANS(vmulwod_w_hu_h, LSX, gvec_vvv, MO_16, do_vmulwod_u_s) +TRANS(vmulwod_d_wu_w, LSX, gvec_vvv, MO_32, do_vmulwod_u_s) static void gen_vmadd(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -2182,10 +2190,10 @@ static void do_vmadd(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vmadd_b, ALL, gvec_vvv, MO_8, do_vmadd) -TRANS(vmadd_h, ALL, gvec_vvv, MO_16, do_vmadd) -TRANS(vmadd_w, ALL, gvec_vvv, MO_32, do_vmadd) -TRANS(vmadd_d, ALL, gvec_vvv, MO_64, do_vmadd) +TRANS(vmadd_b, LSX, gvec_vvv, MO_8, do_vmadd) +TRANS(vmadd_h, LSX, gvec_vvv, MO_16, do_vmadd) +TRANS(vmadd_w, LSX, gvec_vvv, MO_32, do_vmadd) +TRANS(vmadd_d, LSX, gvec_vvv, MO_64, do_vmadd) static void gen_vmsub(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -2256,10 +2264,10 @@ static void do_vmsub(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vmsub_b, ALL, gvec_vvv, MO_8, do_vmsub) -TRANS(vmsub_h, ALL, gvec_vvv, MO_16, do_vmsub) -TRANS(vmsub_w, ALL, gvec_vvv, MO_32, do_vmsub) -TRANS(vmsub_d, ALL, gvec_vvv, MO_64, do_vmsub) +TRANS(vmsub_b, LSX, gvec_vvv, MO_8, do_vmsub) +TRANS(vmsub_h, LSX, gvec_vvv, MO_16, do_vmsub) +TRANS(vmsub_w, LSX, gvec_vvv, MO_32, do_vmsub) +TRANS(vmsub_d, LSX, gvec_vvv, MO_64, do_vmsub) static void gen_vmaddwev_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -2331,15 +2339,19 @@ static void do_vmaddwev_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vmaddwev_h_b, ALL, gvec_vvv, MO_8, do_vmaddwev_s) -TRANS(vmaddwev_w_h, ALL, gvec_vvv, MO_16, do_vmaddwev_s) -TRANS(vmaddwev_d_w, ALL, gvec_vvv, MO_32, do_vmaddwev_s) +TRANS(vmaddwev_h_b, LSX, gvec_vvv, MO_8, do_vmaddwev_s) +TRANS(vmaddwev_w_h, LSX, gvec_vvv, MO_16, do_vmaddwev_s) +TRANS(vmaddwev_d_w, LSX, gvec_vvv, MO_32, do_vmaddwev_s) #define VMADD_Q(NAME, FN, idx1, idx2) \ static bool trans_## NAME (DisasContext *ctx, arg_vvv *a) \ { \ TCGv_i64 rh, rl, arg1, arg2, th, tl; \ \ + if (!avail_LSX(ctx)) { \ + return false; \ + } \ + \ rh = tcg_temp_new_i64(); \ rl = tcg_temp_new_i64(); \ arg1 = tcg_temp_new_i64(); \ @@ -2435,9 +2447,9 @@ static void do_vmaddwod_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vmaddwod_h_b, ALL, gvec_vvv, MO_8, do_vmaddwod_s) -TRANS(vmaddwod_w_h, ALL, gvec_vvv, MO_16, do_vmaddwod_s) -TRANS(vmaddwod_d_w, ALL, gvec_vvv, MO_32, do_vmaddwod_s) +TRANS(vmaddwod_h_b, LSX, gvec_vvv, MO_8, do_vmaddwod_s) +TRANS(vmaddwod_w_h, LSX, gvec_vvv, MO_16, do_vmaddwod_s) +TRANS(vmaddwod_d_w, LSX, gvec_vvv, MO_32, do_vmaddwod_s) static void gen_vmaddwev_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -2505,9 +2517,9 @@ static void do_vmaddwev_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vmaddwev_h_bu, ALL, gvec_vvv, MO_8, do_vmaddwev_u) -TRANS(vmaddwev_w_hu, ALL, gvec_vvv, MO_16, do_vmaddwev_u) -TRANS(vmaddwev_d_wu, ALL, gvec_vvv, MO_32, do_vmaddwev_u) +TRANS(vmaddwev_h_bu, LSX, gvec_vvv, MO_8, do_vmaddwev_u) +TRANS(vmaddwev_w_hu, LSX, gvec_vvv, MO_16, do_vmaddwev_u) +TRANS(vmaddwev_d_wu, LSX, gvec_vvv, MO_32, do_vmaddwev_u) static void gen_vmaddwod_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -2576,9 +2588,9 @@ static void do_vmaddwod_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vmaddwod_h_bu, ALL, gvec_vvv, MO_8, do_vmaddwod_u) -TRANS(vmaddwod_w_hu, ALL, gvec_vvv, MO_16, do_vmaddwod_u) -TRANS(vmaddwod_d_wu, ALL, gvec_vvv, MO_32, do_vmaddwod_u) +TRANS(vmaddwod_h_bu, LSX, gvec_vvv, MO_8, do_vmaddwod_u) +TRANS(vmaddwod_w_hu, LSX, gvec_vvv, MO_16, do_vmaddwod_u) +TRANS(vmaddwod_d_wu, LSX, gvec_vvv, MO_32, do_vmaddwod_u) static void gen_vmaddwev_u_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -2649,9 +2661,9 @@ static void do_vmaddwev_u_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vmaddwev_h_bu_b, ALL, gvec_vvv, MO_8, do_vmaddwev_u_s) -TRANS(vmaddwev_w_hu_h, ALL, gvec_vvv, MO_16, do_vmaddwev_u_s) -TRANS(vmaddwev_d_wu_w, ALL, gvec_vvv, MO_32, do_vmaddwev_u_s) +TRANS(vmaddwev_h_bu_b, LSX, gvec_vvv, MO_8, do_vmaddwev_u_s) +TRANS(vmaddwev_w_hu_h, LSX, gvec_vvv, MO_16, do_vmaddwev_u_s) +TRANS(vmaddwev_d_wu_w, LSX, gvec_vvv, MO_32, do_vmaddwev_u_s) static void gen_vmaddwod_u_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -2721,26 +2733,26 @@ static void do_vmaddwod_u_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vmaddwod_h_bu_b, ALL, gvec_vvv, MO_8, do_vmaddwod_u_s) -TRANS(vmaddwod_w_hu_h, ALL, gvec_vvv, MO_16, do_vmaddwod_u_s) -TRANS(vmaddwod_d_wu_w, ALL, gvec_vvv, MO_32, do_vmaddwod_u_s) +TRANS(vmaddwod_h_bu_b, LSX, gvec_vvv, MO_8, do_vmaddwod_u_s) +TRANS(vmaddwod_w_hu_h, LSX, gvec_vvv, MO_16, do_vmaddwod_u_s) +TRANS(vmaddwod_d_wu_w, LSX, gvec_vvv, MO_32, do_vmaddwod_u_s) -TRANS(vdiv_b, ALL, gen_vvv, gen_helper_vdiv_b) -TRANS(vdiv_h, ALL, gen_vvv, gen_helper_vdiv_h) -TRANS(vdiv_w, ALL, gen_vvv, gen_helper_vdiv_w) -TRANS(vdiv_d, ALL, gen_vvv, gen_helper_vdiv_d) -TRANS(vdiv_bu, ALL, gen_vvv, gen_helper_vdiv_bu) -TRANS(vdiv_hu, ALL, gen_vvv, gen_helper_vdiv_hu) -TRANS(vdiv_wu, ALL, gen_vvv, gen_helper_vdiv_wu) -TRANS(vdiv_du, ALL, gen_vvv, gen_helper_vdiv_du) -TRANS(vmod_b, ALL, gen_vvv, gen_helper_vmod_b) -TRANS(vmod_h, ALL, gen_vvv, gen_helper_vmod_h) -TRANS(vmod_w, ALL, gen_vvv, gen_helper_vmod_w) -TRANS(vmod_d, ALL, gen_vvv, gen_helper_vmod_d) -TRANS(vmod_bu, ALL, gen_vvv, gen_helper_vmod_bu) -TRANS(vmod_hu, ALL, gen_vvv, gen_helper_vmod_hu) -TRANS(vmod_wu, ALL, gen_vvv, gen_helper_vmod_wu) -TRANS(vmod_du, ALL, gen_vvv, gen_helper_vmod_du) +TRANS(vdiv_b, LSX, gen_vvv, gen_helper_vdiv_b) +TRANS(vdiv_h, LSX, gen_vvv, gen_helper_vdiv_h) +TRANS(vdiv_w, LSX, gen_vvv, gen_helper_vdiv_w) +TRANS(vdiv_d, LSX, gen_vvv, gen_helper_vdiv_d) +TRANS(vdiv_bu, LSX, gen_vvv, gen_helper_vdiv_bu) +TRANS(vdiv_hu, LSX, gen_vvv, gen_helper_vdiv_hu) +TRANS(vdiv_wu, LSX, gen_vvv, gen_helper_vdiv_wu) +TRANS(vdiv_du, LSX, gen_vvv, gen_helper_vdiv_du) +TRANS(vmod_b, LSX, gen_vvv, gen_helper_vmod_b) +TRANS(vmod_h, LSX, gen_vvv, gen_helper_vmod_h) +TRANS(vmod_w, LSX, gen_vvv, gen_helper_vmod_w) +TRANS(vmod_d, LSX, gen_vvv, gen_helper_vmod_d) +TRANS(vmod_bu, LSX, gen_vvv, gen_helper_vmod_bu) +TRANS(vmod_hu, LSX, gen_vvv, gen_helper_vmod_hu) +TRANS(vmod_wu, LSX, gen_vvv, gen_helper_vmod_wu) +TRANS(vmod_du, LSX, gen_vvv, gen_helper_vmod_du) static void gen_vsat_s(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec max) { @@ -2789,10 +2801,10 @@ static void do_vsat_s(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_constant_i64((1ll<< imm) -1), &op[vece]); } -TRANS(vsat_b, ALL, gvec_vv_i, MO_8, do_vsat_s) -TRANS(vsat_h, ALL, gvec_vv_i, MO_16, do_vsat_s) -TRANS(vsat_w, ALL, gvec_vv_i, MO_32, do_vsat_s) -TRANS(vsat_d, ALL, gvec_vv_i, MO_64, do_vsat_s) +TRANS(vsat_b, LSX, gvec_vv_i, MO_8, do_vsat_s) +TRANS(vsat_h, LSX, gvec_vv_i, MO_16, do_vsat_s) +TRANS(vsat_w, LSX, gvec_vv_i, MO_32, do_vsat_s) +TRANS(vsat_d, LSX, gvec_vv_i, MO_64, do_vsat_s) static void gen_vsat_u(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec max) { @@ -2838,19 +2850,19 @@ static void do_vsat_u(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_constant_i64(max), &op[vece]); } -TRANS(vsat_bu, ALL, gvec_vv_i, MO_8, do_vsat_u) -TRANS(vsat_hu, ALL, gvec_vv_i, MO_16, do_vsat_u) -TRANS(vsat_wu, ALL, gvec_vv_i, MO_32, do_vsat_u) -TRANS(vsat_du, ALL, gvec_vv_i, MO_64, do_vsat_u) +TRANS(vsat_bu, LSX, gvec_vv_i, MO_8, do_vsat_u) +TRANS(vsat_hu, LSX, gvec_vv_i, MO_16, do_vsat_u) +TRANS(vsat_wu, LSX, gvec_vv_i, MO_32, do_vsat_u) +TRANS(vsat_du, LSX, gvec_vv_i, MO_64, do_vsat_u) -TRANS(vexth_h_b, ALL, gen_vv, gen_helper_vexth_h_b) -TRANS(vexth_w_h, ALL, gen_vv, gen_helper_vexth_w_h) -TRANS(vexth_d_w, ALL, gen_vv, gen_helper_vexth_d_w) -TRANS(vexth_q_d, ALL, gen_vv, gen_helper_vexth_q_d) -TRANS(vexth_hu_bu, ALL, gen_vv, gen_helper_vexth_hu_bu) -TRANS(vexth_wu_hu, ALL, gen_vv, gen_helper_vexth_wu_hu) -TRANS(vexth_du_wu, ALL, gen_vv, gen_helper_vexth_du_wu) -TRANS(vexth_qu_du, ALL, gen_vv, gen_helper_vexth_qu_du) +TRANS(vexth_h_b, LSX, gen_vv, gen_helper_vexth_h_b) +TRANS(vexth_w_h, LSX, gen_vv, gen_helper_vexth_w_h) +TRANS(vexth_d_w, LSX, gen_vv, gen_helper_vexth_d_w) +TRANS(vexth_q_d, LSX, gen_vv, gen_helper_vexth_q_d) +TRANS(vexth_hu_bu, LSX, gen_vv, gen_helper_vexth_hu_bu) +TRANS(vexth_wu_hu, LSX, gen_vv, gen_helper_vexth_wu_hu) +TRANS(vexth_du_wu, LSX, gen_vv, gen_helper_vexth_du_wu) +TRANS(vexth_qu_du, LSX, gen_vv, gen_helper_vexth_qu_du) static void gen_vsigncov(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) { @@ -2900,17 +2912,17 @@ static void do_vsigncov(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vsigncov_b, ALL, gvec_vvv, MO_8, do_vsigncov) -TRANS(vsigncov_h, ALL, gvec_vvv, MO_16, do_vsigncov) -TRANS(vsigncov_w, ALL, gvec_vvv, MO_32, do_vsigncov) -TRANS(vsigncov_d, ALL, gvec_vvv, MO_64, do_vsigncov) +TRANS(vsigncov_b, LSX, gvec_vvv, MO_8, do_vsigncov) +TRANS(vsigncov_h, LSX, gvec_vvv, MO_16, do_vsigncov) +TRANS(vsigncov_w, LSX, gvec_vvv, MO_32, do_vsigncov) +TRANS(vsigncov_d, LSX, gvec_vvv, MO_64, do_vsigncov) -TRANS(vmskltz_b, ALL, gen_vv, gen_helper_vmskltz_b) -TRANS(vmskltz_h, ALL, gen_vv, gen_helper_vmskltz_h) -TRANS(vmskltz_w, ALL, gen_vv, gen_helper_vmskltz_w) -TRANS(vmskltz_d, ALL, gen_vv, gen_helper_vmskltz_d) -TRANS(vmskgez_b, ALL, gen_vv, gen_helper_vmskgez_b) -TRANS(vmsknz_b, ALL, gen_vv, gen_helper_vmsknz_b) +TRANS(vmskltz_b, LSX, gen_vv, gen_helper_vmskltz_b) +TRANS(vmskltz_h, LSX, gen_vv, gen_helper_vmskltz_h) +TRANS(vmskltz_w, LSX, gen_vv, gen_helper_vmskltz_w) +TRANS(vmskltz_d, LSX, gen_vv, gen_helper_vmskltz_d) +TRANS(vmskgez_b, LSX, gen_vv, gen_helper_vmskgez_b) +TRANS(vmsknz_b, LSX, gen_vv, gen_helper_vmsknz_b) #define EXPAND_BYTE(bit) ((uint64_t)(bit ? 0xff : 0)) @@ -3032,6 +3044,11 @@ static bool trans_vldi(DisasContext *ctx, arg_vldi *a) { int sel, vece; uint64_t value; + + if (!avail_LSX(ctx)) { + return false; + } + CHECK_SXE; sel = (a->imm >> 12) & 0x1; @@ -3049,15 +3066,19 @@ static bool trans_vldi(DisasContext *ctx, arg_vldi *a) return true; } -TRANS(vand_v, ALL, gvec_vvv, MO_64, tcg_gen_gvec_and) -TRANS(vor_v, ALL, gvec_vvv, MO_64, tcg_gen_gvec_or) -TRANS(vxor_v, ALL, gvec_vvv, MO_64, tcg_gen_gvec_xor) -TRANS(vnor_v, ALL, gvec_vvv, MO_64, tcg_gen_gvec_nor) +TRANS(vand_v, LSX, gvec_vvv, MO_64, tcg_gen_gvec_and) +TRANS(vor_v, LSX, gvec_vvv, MO_64, tcg_gen_gvec_or) +TRANS(vxor_v, LSX, gvec_vvv, MO_64, tcg_gen_gvec_xor) +TRANS(vnor_v, LSX, gvec_vvv, MO_64, tcg_gen_gvec_nor) static bool trans_vandn_v(DisasContext *ctx, arg_vvv *a) { uint32_t vd_ofs, vj_ofs, vk_ofs; + if (!avail_LSX(ctx)) { + return false; + } + CHECK_SXE; vd_ofs = vec_full_offset(a->vd); @@ -3067,10 +3088,10 @@ static bool trans_vandn_v(DisasContext *ctx, arg_vvv *a) tcg_gen_gvec_andc(MO_64, vd_ofs, vk_ofs, vj_ofs, 16, ctx->vl/8); return true; } -TRANS(vorn_v, ALL, gvec_vvv, MO_64, tcg_gen_gvec_orc) -TRANS(vandi_b, ALL, gvec_vv_i, MO_8, tcg_gen_gvec_andi) -TRANS(vori_b, ALL, gvec_vv_i, MO_8, tcg_gen_gvec_ori) -TRANS(vxori_b, ALL, gvec_vv_i, MO_8, tcg_gen_gvec_xori) +TRANS(vorn_v, LSX, gvec_vvv, MO_64, tcg_gen_gvec_orc) +TRANS(vandi_b, LSX, gvec_vv_i, MO_8, tcg_gen_gvec_andi) +TRANS(vori_b, LSX, gvec_vv_i, MO_8, tcg_gen_gvec_ori) +TRANS(vxori_b, LSX, gvec_vv_i, MO_8, tcg_gen_gvec_xori) static void gen_vnori(unsigned vece, TCGv_vec t, TCGv_vec a, int64_t imm) { @@ -3103,176 +3124,176 @@ static void do_vnori_b(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_2i(vd_ofs, vj_ofs, oprsz, maxsz, imm, &op); } -TRANS(vnori_b, ALL, gvec_vv_i, MO_8, do_vnori_b) +TRANS(vnori_b, LSX, gvec_vv_i, MO_8, do_vnori_b) -TRANS(vsll_b, ALL, gvec_vvv, MO_8, tcg_gen_gvec_shlv) -TRANS(vsll_h, ALL, gvec_vvv, MO_16, tcg_gen_gvec_shlv) -TRANS(vsll_w, ALL, gvec_vvv, MO_32, tcg_gen_gvec_shlv) -TRANS(vsll_d, ALL, gvec_vvv, MO_64, tcg_gen_gvec_shlv) -TRANS(vslli_b, ALL, gvec_vv_i, MO_8, tcg_gen_gvec_shli) -TRANS(vslli_h, ALL, gvec_vv_i, MO_16, tcg_gen_gvec_shli) -TRANS(vslli_w, ALL, gvec_vv_i, MO_32, tcg_gen_gvec_shli) -TRANS(vslli_d, ALL, gvec_vv_i, MO_64, tcg_gen_gvec_shli) +TRANS(vsll_b, LSX, gvec_vvv, MO_8, tcg_gen_gvec_shlv) +TRANS(vsll_h, LSX, gvec_vvv, MO_16, tcg_gen_gvec_shlv) +TRANS(vsll_w, LSX, gvec_vvv, MO_32, tcg_gen_gvec_shlv) +TRANS(vsll_d, LSX, gvec_vvv, MO_64, tcg_gen_gvec_shlv) +TRANS(vslli_b, LSX, gvec_vv_i, MO_8, tcg_gen_gvec_shli) +TRANS(vslli_h, LSX, gvec_vv_i, MO_16, tcg_gen_gvec_shli) +TRANS(vslli_w, LSX, gvec_vv_i, MO_32, tcg_gen_gvec_shli) +TRANS(vslli_d, LSX, gvec_vv_i, MO_64, tcg_gen_gvec_shli) -TRANS(vsrl_b, ALL, gvec_vvv, MO_8, tcg_gen_gvec_shrv) -TRANS(vsrl_h, ALL, gvec_vvv, MO_16, tcg_gen_gvec_shrv) -TRANS(vsrl_w, ALL, gvec_vvv, MO_32, tcg_gen_gvec_shrv) -TRANS(vsrl_d, ALL, gvec_vvv, MO_64, tcg_gen_gvec_shrv) -TRANS(vsrli_b, ALL, gvec_vv_i, MO_8, tcg_gen_gvec_shri) -TRANS(vsrli_h, ALL, gvec_vv_i, MO_16, tcg_gen_gvec_shri) -TRANS(vsrli_w, ALL, gvec_vv_i, MO_32, tcg_gen_gvec_shri) -TRANS(vsrli_d, ALL, gvec_vv_i, MO_64, tcg_gen_gvec_shri) +TRANS(vsrl_b, LSX, gvec_vvv, MO_8, tcg_gen_gvec_shrv) +TRANS(vsrl_h, LSX, gvec_vvv, MO_16, tcg_gen_gvec_shrv) +TRANS(vsrl_w, LSX, gvec_vvv, MO_32, tcg_gen_gvec_shrv) +TRANS(vsrl_d, LSX, gvec_vvv, MO_64, tcg_gen_gvec_shrv) +TRANS(vsrli_b, LSX, gvec_vv_i, MO_8, tcg_gen_gvec_shri) +TRANS(vsrli_h, LSX, gvec_vv_i, MO_16, tcg_gen_gvec_shri) +TRANS(vsrli_w, LSX, gvec_vv_i, MO_32, tcg_gen_gvec_shri) +TRANS(vsrli_d, LSX, gvec_vv_i, MO_64, tcg_gen_gvec_shri) -TRANS(vsra_b, ALL, gvec_vvv, MO_8, tcg_gen_gvec_sarv) -TRANS(vsra_h, ALL, gvec_vvv, MO_16, tcg_gen_gvec_sarv) -TRANS(vsra_w, ALL, gvec_vvv, MO_32, tcg_gen_gvec_sarv) -TRANS(vsra_d, ALL, gvec_vvv, MO_64, tcg_gen_gvec_sarv) -TRANS(vsrai_b, ALL, gvec_vv_i, MO_8, tcg_gen_gvec_sari) -TRANS(vsrai_h, ALL, gvec_vv_i, MO_16, tcg_gen_gvec_sari) -TRANS(vsrai_w, ALL, gvec_vv_i, MO_32, tcg_gen_gvec_sari) -TRANS(vsrai_d, ALL, gvec_vv_i, MO_64, tcg_gen_gvec_sari) +TRANS(vsra_b, LSX, gvec_vvv, MO_8, tcg_gen_gvec_sarv) +TRANS(vsra_h, LSX, gvec_vvv, MO_16, tcg_gen_gvec_sarv) +TRANS(vsra_w, LSX, gvec_vvv, MO_32, tcg_gen_gvec_sarv) +TRANS(vsra_d, LSX, gvec_vvv, MO_64, tcg_gen_gvec_sarv) +TRANS(vsrai_b, LSX, gvec_vv_i, MO_8, tcg_gen_gvec_sari) +TRANS(vsrai_h, LSX, gvec_vv_i, MO_16, tcg_gen_gvec_sari) +TRANS(vsrai_w, LSX, gvec_vv_i, MO_32, tcg_gen_gvec_sari) +TRANS(vsrai_d, LSX, gvec_vv_i, MO_64, tcg_gen_gvec_sari) -TRANS(vrotr_b, ALL, gvec_vvv, MO_8, tcg_gen_gvec_rotrv) -TRANS(vrotr_h, ALL, gvec_vvv, MO_16, tcg_gen_gvec_rotrv) -TRANS(vrotr_w, ALL, gvec_vvv, MO_32, tcg_gen_gvec_rotrv) -TRANS(vrotr_d, ALL, gvec_vvv, MO_64, tcg_gen_gvec_rotrv) -TRANS(vrotri_b, ALL, gvec_vv_i, MO_8, tcg_gen_gvec_rotri) -TRANS(vrotri_h, ALL, gvec_vv_i, MO_16, tcg_gen_gvec_rotri) -TRANS(vrotri_w, ALL, gvec_vv_i, MO_32, tcg_gen_gvec_rotri) -TRANS(vrotri_d, ALL, gvec_vv_i, MO_64, tcg_gen_gvec_rotri) +TRANS(vrotr_b, LSX, gvec_vvv, MO_8, tcg_gen_gvec_rotrv) +TRANS(vrotr_h, LSX, gvec_vvv, MO_16, tcg_gen_gvec_rotrv) +TRANS(vrotr_w, LSX, gvec_vvv, MO_32, tcg_gen_gvec_rotrv) +TRANS(vrotr_d, LSX, gvec_vvv, MO_64, tcg_gen_gvec_rotrv) +TRANS(vrotri_b, LSX, gvec_vv_i, MO_8, tcg_gen_gvec_rotri) +TRANS(vrotri_h, LSX, gvec_vv_i, MO_16, tcg_gen_gvec_rotri) +TRANS(vrotri_w, LSX, gvec_vv_i, MO_32, tcg_gen_gvec_rotri) +TRANS(vrotri_d, LSX, gvec_vv_i, MO_64, tcg_gen_gvec_rotri) -TRANS(vsllwil_h_b, ALL, gen_vv_i, gen_helper_vsllwil_h_b) -TRANS(vsllwil_w_h, ALL, gen_vv_i, gen_helper_vsllwil_w_h) -TRANS(vsllwil_d_w, ALL, gen_vv_i, gen_helper_vsllwil_d_w) -TRANS(vextl_q_d, ALL, gen_vv, gen_helper_vextl_q_d) -TRANS(vsllwil_hu_bu, ALL, gen_vv_i, gen_helper_vsllwil_hu_bu) -TRANS(vsllwil_wu_hu, ALL, gen_vv_i, gen_helper_vsllwil_wu_hu) -TRANS(vsllwil_du_wu, ALL, gen_vv_i, gen_helper_vsllwil_du_wu) -TRANS(vextl_qu_du, ALL, gen_vv, gen_helper_vextl_qu_du) +TRANS(vsllwil_h_b, LSX, gen_vv_i, gen_helper_vsllwil_h_b) +TRANS(vsllwil_w_h, LSX, gen_vv_i, gen_helper_vsllwil_w_h) +TRANS(vsllwil_d_w, LSX, gen_vv_i, gen_helper_vsllwil_d_w) +TRANS(vextl_q_d, LSX, gen_vv, gen_helper_vextl_q_d) +TRANS(vsllwil_hu_bu, LSX, gen_vv_i, gen_helper_vsllwil_hu_bu) +TRANS(vsllwil_wu_hu, LSX, gen_vv_i, gen_helper_vsllwil_wu_hu) +TRANS(vsllwil_du_wu, LSX, gen_vv_i, gen_helper_vsllwil_du_wu) +TRANS(vextl_qu_du, LSX, gen_vv, gen_helper_vextl_qu_du) -TRANS(vsrlr_b, ALL, gen_vvv, gen_helper_vsrlr_b) -TRANS(vsrlr_h, ALL, gen_vvv, gen_helper_vsrlr_h) -TRANS(vsrlr_w, ALL, gen_vvv, gen_helper_vsrlr_w) -TRANS(vsrlr_d, ALL, gen_vvv, gen_helper_vsrlr_d) -TRANS(vsrlri_b, ALL, gen_vv_i, gen_helper_vsrlri_b) -TRANS(vsrlri_h, ALL, gen_vv_i, gen_helper_vsrlri_h) -TRANS(vsrlri_w, ALL, gen_vv_i, gen_helper_vsrlri_w) -TRANS(vsrlri_d, ALL, gen_vv_i, gen_helper_vsrlri_d) +TRANS(vsrlr_b, LSX, gen_vvv, gen_helper_vsrlr_b) +TRANS(vsrlr_h, LSX, gen_vvv, gen_helper_vsrlr_h) +TRANS(vsrlr_w, LSX, gen_vvv, gen_helper_vsrlr_w) +TRANS(vsrlr_d, LSX, gen_vvv, gen_helper_vsrlr_d) +TRANS(vsrlri_b, LSX, gen_vv_i, gen_helper_vsrlri_b) +TRANS(vsrlri_h, LSX, gen_vv_i, gen_helper_vsrlri_h) +TRANS(vsrlri_w, LSX, gen_vv_i, gen_helper_vsrlri_w) +TRANS(vsrlri_d, LSX, gen_vv_i, gen_helper_vsrlri_d) -TRANS(vsrar_b, ALL, gen_vvv, gen_helper_vsrar_b) -TRANS(vsrar_h, ALL, gen_vvv, gen_helper_vsrar_h) -TRANS(vsrar_w, ALL, gen_vvv, gen_helper_vsrar_w) -TRANS(vsrar_d, ALL, gen_vvv, gen_helper_vsrar_d) -TRANS(vsrari_b, ALL, gen_vv_i, gen_helper_vsrari_b) -TRANS(vsrari_h, ALL, gen_vv_i, gen_helper_vsrari_h) -TRANS(vsrari_w, ALL, gen_vv_i, gen_helper_vsrari_w) -TRANS(vsrari_d, ALL, gen_vv_i, gen_helper_vsrari_d) +TRANS(vsrar_b, LSX, gen_vvv, gen_helper_vsrar_b) +TRANS(vsrar_h, LSX, gen_vvv, gen_helper_vsrar_h) +TRANS(vsrar_w, LSX, gen_vvv, gen_helper_vsrar_w) +TRANS(vsrar_d, LSX, gen_vvv, gen_helper_vsrar_d) +TRANS(vsrari_b, LSX, gen_vv_i, gen_helper_vsrari_b) +TRANS(vsrari_h, LSX, gen_vv_i, gen_helper_vsrari_h) +TRANS(vsrari_w, LSX, gen_vv_i, gen_helper_vsrari_w) +TRANS(vsrari_d, LSX, gen_vv_i, gen_helper_vsrari_d) -TRANS(vsrln_b_h, ALL, gen_vvv, gen_helper_vsrln_b_h) -TRANS(vsrln_h_w, ALL, gen_vvv, gen_helper_vsrln_h_w) -TRANS(vsrln_w_d, ALL, gen_vvv, gen_helper_vsrln_w_d) -TRANS(vsran_b_h, ALL, gen_vvv, gen_helper_vsran_b_h) -TRANS(vsran_h_w, ALL, gen_vvv, gen_helper_vsran_h_w) -TRANS(vsran_w_d, ALL, gen_vvv, gen_helper_vsran_w_d) +TRANS(vsrln_b_h, LSX, gen_vvv, gen_helper_vsrln_b_h) +TRANS(vsrln_h_w, LSX, gen_vvv, gen_helper_vsrln_h_w) +TRANS(vsrln_w_d, LSX, gen_vvv, gen_helper_vsrln_w_d) +TRANS(vsran_b_h, LSX, gen_vvv, gen_helper_vsran_b_h) +TRANS(vsran_h_w, LSX, gen_vvv, gen_helper_vsran_h_w) +TRANS(vsran_w_d, LSX, gen_vvv, gen_helper_vsran_w_d) -TRANS(vsrlni_b_h, ALL, gen_vv_i, gen_helper_vsrlni_b_h) -TRANS(vsrlni_h_w, ALL, gen_vv_i, gen_helper_vsrlni_h_w) -TRANS(vsrlni_w_d, ALL, gen_vv_i, gen_helper_vsrlni_w_d) -TRANS(vsrlni_d_q, ALL, gen_vv_i, gen_helper_vsrlni_d_q) -TRANS(vsrani_b_h, ALL, gen_vv_i, gen_helper_vsrani_b_h) -TRANS(vsrani_h_w, ALL, gen_vv_i, gen_helper_vsrani_h_w) -TRANS(vsrani_w_d, ALL, gen_vv_i, gen_helper_vsrani_w_d) -TRANS(vsrani_d_q, ALL, gen_vv_i, gen_helper_vsrani_d_q) +TRANS(vsrlni_b_h, LSX, gen_vv_i, gen_helper_vsrlni_b_h) +TRANS(vsrlni_h_w, LSX, gen_vv_i, gen_helper_vsrlni_h_w) +TRANS(vsrlni_w_d, LSX, gen_vv_i, gen_helper_vsrlni_w_d) +TRANS(vsrlni_d_q, LSX, gen_vv_i, gen_helper_vsrlni_d_q) +TRANS(vsrani_b_h, LSX, gen_vv_i, gen_helper_vsrani_b_h) +TRANS(vsrani_h_w, LSX, gen_vv_i, gen_helper_vsrani_h_w) +TRANS(vsrani_w_d, LSX, gen_vv_i, gen_helper_vsrani_w_d) +TRANS(vsrani_d_q, LSX, gen_vv_i, gen_helper_vsrani_d_q) -TRANS(vsrlrn_b_h, ALL, gen_vvv, gen_helper_vsrlrn_b_h) -TRANS(vsrlrn_h_w, ALL, gen_vvv, gen_helper_vsrlrn_h_w) -TRANS(vsrlrn_w_d, ALL, gen_vvv, gen_helper_vsrlrn_w_d) -TRANS(vsrarn_b_h, ALL, gen_vvv, gen_helper_vsrarn_b_h) -TRANS(vsrarn_h_w, ALL, gen_vvv, gen_helper_vsrarn_h_w) -TRANS(vsrarn_w_d, ALL, gen_vvv, gen_helper_vsrarn_w_d) +TRANS(vsrlrn_b_h, LSX, gen_vvv, gen_helper_vsrlrn_b_h) +TRANS(vsrlrn_h_w, LSX, gen_vvv, gen_helper_vsrlrn_h_w) +TRANS(vsrlrn_w_d, LSX, gen_vvv, gen_helper_vsrlrn_w_d) +TRANS(vsrarn_b_h, LSX, gen_vvv, gen_helper_vsrarn_b_h) +TRANS(vsrarn_h_w, LSX, gen_vvv, gen_helper_vsrarn_h_w) +TRANS(vsrarn_w_d, LSX, gen_vvv, gen_helper_vsrarn_w_d) -TRANS(vsrlrni_b_h, ALL, gen_vv_i, gen_helper_vsrlrni_b_h) -TRANS(vsrlrni_h_w, ALL, gen_vv_i, gen_helper_vsrlrni_h_w) -TRANS(vsrlrni_w_d, ALL, gen_vv_i, gen_helper_vsrlrni_w_d) -TRANS(vsrlrni_d_q, ALL, gen_vv_i, gen_helper_vsrlrni_d_q) -TRANS(vsrarni_b_h, ALL, gen_vv_i, gen_helper_vsrarni_b_h) -TRANS(vsrarni_h_w, ALL, gen_vv_i, gen_helper_vsrarni_h_w) -TRANS(vsrarni_w_d, ALL, gen_vv_i, gen_helper_vsrarni_w_d) -TRANS(vsrarni_d_q, ALL, gen_vv_i, gen_helper_vsrarni_d_q) +TRANS(vsrlrni_b_h, LSX, gen_vv_i, gen_helper_vsrlrni_b_h) +TRANS(vsrlrni_h_w, LSX, gen_vv_i, gen_helper_vsrlrni_h_w) +TRANS(vsrlrni_w_d, LSX, gen_vv_i, gen_helper_vsrlrni_w_d) +TRANS(vsrlrni_d_q, LSX, gen_vv_i, gen_helper_vsrlrni_d_q) +TRANS(vsrarni_b_h, LSX, gen_vv_i, gen_helper_vsrarni_b_h) +TRANS(vsrarni_h_w, LSX, gen_vv_i, gen_helper_vsrarni_h_w) +TRANS(vsrarni_w_d, LSX, gen_vv_i, gen_helper_vsrarni_w_d) +TRANS(vsrarni_d_q, LSX, gen_vv_i, gen_helper_vsrarni_d_q) -TRANS(vssrln_b_h, ALL, gen_vvv, gen_helper_vssrln_b_h) -TRANS(vssrln_h_w, ALL, gen_vvv, gen_helper_vssrln_h_w) -TRANS(vssrln_w_d, ALL, gen_vvv, gen_helper_vssrln_w_d) -TRANS(vssran_b_h, ALL, gen_vvv, gen_helper_vssran_b_h) -TRANS(vssran_h_w, ALL, gen_vvv, gen_helper_vssran_h_w) -TRANS(vssran_w_d, ALL, gen_vvv, gen_helper_vssran_w_d) -TRANS(vssrln_bu_h, ALL, gen_vvv, gen_helper_vssrln_bu_h) -TRANS(vssrln_hu_w, ALL, gen_vvv, gen_helper_vssrln_hu_w) -TRANS(vssrln_wu_d, ALL, gen_vvv, gen_helper_vssrln_wu_d) -TRANS(vssran_bu_h, ALL, gen_vvv, gen_helper_vssran_bu_h) -TRANS(vssran_hu_w, ALL, gen_vvv, gen_helper_vssran_hu_w) -TRANS(vssran_wu_d, ALL, gen_vvv, gen_helper_vssran_wu_d) +TRANS(vssrln_b_h, LSX, gen_vvv, gen_helper_vssrln_b_h) +TRANS(vssrln_h_w, LSX, gen_vvv, gen_helper_vssrln_h_w) +TRANS(vssrln_w_d, LSX, gen_vvv, gen_helper_vssrln_w_d) +TRANS(vssran_b_h, LSX, gen_vvv, gen_helper_vssran_b_h) +TRANS(vssran_h_w, LSX, gen_vvv, gen_helper_vssran_h_w) +TRANS(vssran_w_d, LSX, gen_vvv, gen_helper_vssran_w_d) +TRANS(vssrln_bu_h, LSX, gen_vvv, gen_helper_vssrln_bu_h) +TRANS(vssrln_hu_w, LSX, gen_vvv, gen_helper_vssrln_hu_w) +TRANS(vssrln_wu_d, LSX, gen_vvv, gen_helper_vssrln_wu_d) +TRANS(vssran_bu_h, LSX, gen_vvv, gen_helper_vssran_bu_h) +TRANS(vssran_hu_w, LSX, gen_vvv, gen_helper_vssran_hu_w) +TRANS(vssran_wu_d, LSX, gen_vvv, gen_helper_vssran_wu_d) -TRANS(vssrlni_b_h, ALL, gen_vv_i, gen_helper_vssrlni_b_h) -TRANS(vssrlni_h_w, ALL, gen_vv_i, gen_helper_vssrlni_h_w) -TRANS(vssrlni_w_d, ALL, gen_vv_i, gen_helper_vssrlni_w_d) -TRANS(vssrlni_d_q, ALL, gen_vv_i, gen_helper_vssrlni_d_q) -TRANS(vssrani_b_h, ALL, gen_vv_i, gen_helper_vssrani_b_h) -TRANS(vssrani_h_w, ALL, gen_vv_i, gen_helper_vssrani_h_w) -TRANS(vssrani_w_d, ALL, gen_vv_i, gen_helper_vssrani_w_d) -TRANS(vssrani_d_q, ALL, gen_vv_i, gen_helper_vssrani_d_q) -TRANS(vssrlni_bu_h, ALL, gen_vv_i, gen_helper_vssrlni_bu_h) -TRANS(vssrlni_hu_w, ALL, gen_vv_i, gen_helper_vssrlni_hu_w) -TRANS(vssrlni_wu_d, ALL, gen_vv_i, gen_helper_vssrlni_wu_d) -TRANS(vssrlni_du_q, ALL, gen_vv_i, gen_helper_vssrlni_du_q) -TRANS(vssrani_bu_h, ALL, gen_vv_i, gen_helper_vssrani_bu_h) -TRANS(vssrani_hu_w, ALL, gen_vv_i, gen_helper_vssrani_hu_w) -TRANS(vssrani_wu_d, ALL, gen_vv_i, gen_helper_vssrani_wu_d) -TRANS(vssrani_du_q, ALL, gen_vv_i, gen_helper_vssrani_du_q) +TRANS(vssrlni_b_h, LSX, gen_vv_i, gen_helper_vssrlni_b_h) +TRANS(vssrlni_h_w, LSX, gen_vv_i, gen_helper_vssrlni_h_w) +TRANS(vssrlni_w_d, LSX, gen_vv_i, gen_helper_vssrlni_w_d) +TRANS(vssrlni_d_q, LSX, gen_vv_i, gen_helper_vssrlni_d_q) +TRANS(vssrani_b_h, LSX, gen_vv_i, gen_helper_vssrani_b_h) +TRANS(vssrani_h_w, LSX, gen_vv_i, gen_helper_vssrani_h_w) +TRANS(vssrani_w_d, LSX, gen_vv_i, gen_helper_vssrani_w_d) +TRANS(vssrani_d_q, LSX, gen_vv_i, gen_helper_vssrani_d_q) +TRANS(vssrlni_bu_h, LSX, gen_vv_i, gen_helper_vssrlni_bu_h) +TRANS(vssrlni_hu_w, LSX, gen_vv_i, gen_helper_vssrlni_hu_w) +TRANS(vssrlni_wu_d, LSX, gen_vv_i, gen_helper_vssrlni_wu_d) +TRANS(vssrlni_du_q, LSX, gen_vv_i, gen_helper_vssrlni_du_q) +TRANS(vssrani_bu_h, LSX, gen_vv_i, gen_helper_vssrani_bu_h) +TRANS(vssrani_hu_w, LSX, gen_vv_i, gen_helper_vssrani_hu_w) +TRANS(vssrani_wu_d, LSX, gen_vv_i, gen_helper_vssrani_wu_d) +TRANS(vssrani_du_q, LSX, gen_vv_i, gen_helper_vssrani_du_q) -TRANS(vssrlrn_b_h, ALL, gen_vvv, gen_helper_vssrlrn_b_h) -TRANS(vssrlrn_h_w, ALL, gen_vvv, gen_helper_vssrlrn_h_w) -TRANS(vssrlrn_w_d, ALL, gen_vvv, gen_helper_vssrlrn_w_d) -TRANS(vssrarn_b_h, ALL, gen_vvv, gen_helper_vssrarn_b_h) -TRANS(vssrarn_h_w, ALL, gen_vvv, gen_helper_vssrarn_h_w) -TRANS(vssrarn_w_d, ALL, gen_vvv, gen_helper_vssrarn_w_d) -TRANS(vssrlrn_bu_h, ALL, gen_vvv, gen_helper_vssrlrn_bu_h) -TRANS(vssrlrn_hu_w, ALL, gen_vvv, gen_helper_vssrlrn_hu_w) -TRANS(vssrlrn_wu_d, ALL, gen_vvv, gen_helper_vssrlrn_wu_d) -TRANS(vssrarn_bu_h, ALL, gen_vvv, gen_helper_vssrarn_bu_h) -TRANS(vssrarn_hu_w, ALL, gen_vvv, gen_helper_vssrarn_hu_w) -TRANS(vssrarn_wu_d, ALL, gen_vvv, gen_helper_vssrarn_wu_d) +TRANS(vssrlrn_b_h, LSX, gen_vvv, gen_helper_vssrlrn_b_h) +TRANS(vssrlrn_h_w, LSX, gen_vvv, gen_helper_vssrlrn_h_w) +TRANS(vssrlrn_w_d, LSX, gen_vvv, gen_helper_vssrlrn_w_d) +TRANS(vssrarn_b_h, LSX, gen_vvv, gen_helper_vssrarn_b_h) +TRANS(vssrarn_h_w, LSX, gen_vvv, gen_helper_vssrarn_h_w) +TRANS(vssrarn_w_d, LSX, gen_vvv, gen_helper_vssrarn_w_d) +TRANS(vssrlrn_bu_h, LSX, gen_vvv, gen_helper_vssrlrn_bu_h) +TRANS(vssrlrn_hu_w, LSX, gen_vvv, gen_helper_vssrlrn_hu_w) +TRANS(vssrlrn_wu_d, LSX, gen_vvv, gen_helper_vssrlrn_wu_d) +TRANS(vssrarn_bu_h, LSX, gen_vvv, gen_helper_vssrarn_bu_h) +TRANS(vssrarn_hu_w, LSX, gen_vvv, gen_helper_vssrarn_hu_w) +TRANS(vssrarn_wu_d, LSX, gen_vvv, gen_helper_vssrarn_wu_d) -TRANS(vssrlrni_b_h, ALL, gen_vv_i, gen_helper_vssrlrni_b_h) -TRANS(vssrlrni_h_w, ALL, gen_vv_i, gen_helper_vssrlrni_h_w) -TRANS(vssrlrni_w_d, ALL, gen_vv_i, gen_helper_vssrlrni_w_d) -TRANS(vssrlrni_d_q, ALL, gen_vv_i, gen_helper_vssrlrni_d_q) -TRANS(vssrarni_b_h, ALL, gen_vv_i, gen_helper_vssrarni_b_h) -TRANS(vssrarni_h_w, ALL, gen_vv_i, gen_helper_vssrarni_h_w) -TRANS(vssrarni_w_d, ALL, gen_vv_i, gen_helper_vssrarni_w_d) -TRANS(vssrarni_d_q, ALL, gen_vv_i, gen_helper_vssrarni_d_q) -TRANS(vssrlrni_bu_h, ALL, gen_vv_i, gen_helper_vssrlrni_bu_h) -TRANS(vssrlrni_hu_w, ALL, gen_vv_i, gen_helper_vssrlrni_hu_w) -TRANS(vssrlrni_wu_d, ALL, gen_vv_i, gen_helper_vssrlrni_wu_d) -TRANS(vssrlrni_du_q, ALL, gen_vv_i, gen_helper_vssrlrni_du_q) -TRANS(vssrarni_bu_h, ALL, gen_vv_i, gen_helper_vssrarni_bu_h) -TRANS(vssrarni_hu_w, ALL, gen_vv_i, gen_helper_vssrarni_hu_w) -TRANS(vssrarni_wu_d, ALL, gen_vv_i, gen_helper_vssrarni_wu_d) -TRANS(vssrarni_du_q, ALL, gen_vv_i, gen_helper_vssrarni_du_q) +TRANS(vssrlrni_b_h, LSX, gen_vv_i, gen_helper_vssrlrni_b_h) +TRANS(vssrlrni_h_w, LSX, gen_vv_i, gen_helper_vssrlrni_h_w) +TRANS(vssrlrni_w_d, LSX, gen_vv_i, gen_helper_vssrlrni_w_d) +TRANS(vssrlrni_d_q, LSX, gen_vv_i, gen_helper_vssrlrni_d_q) +TRANS(vssrarni_b_h, LSX, gen_vv_i, gen_helper_vssrarni_b_h) +TRANS(vssrarni_h_w, LSX, gen_vv_i, gen_helper_vssrarni_h_w) +TRANS(vssrarni_w_d, LSX, gen_vv_i, gen_helper_vssrarni_w_d) +TRANS(vssrarni_d_q, LSX, gen_vv_i, gen_helper_vssrarni_d_q) +TRANS(vssrlrni_bu_h, LSX, gen_vv_i, gen_helper_vssrlrni_bu_h) +TRANS(vssrlrni_hu_w, LSX, gen_vv_i, gen_helper_vssrlrni_hu_w) +TRANS(vssrlrni_wu_d, LSX, gen_vv_i, gen_helper_vssrlrni_wu_d) +TRANS(vssrlrni_du_q, LSX, gen_vv_i, gen_helper_vssrlrni_du_q) +TRANS(vssrarni_bu_h, LSX, gen_vv_i, gen_helper_vssrarni_bu_h) +TRANS(vssrarni_hu_w, LSX, gen_vv_i, gen_helper_vssrarni_hu_w) +TRANS(vssrarni_wu_d, LSX, gen_vv_i, gen_helper_vssrarni_wu_d) +TRANS(vssrarni_du_q, LSX, gen_vv_i, gen_helper_vssrarni_du_q) -TRANS(vclo_b, ALL, gen_vv, gen_helper_vclo_b) -TRANS(vclo_h, ALL, gen_vv, gen_helper_vclo_h) -TRANS(vclo_w, ALL, gen_vv, gen_helper_vclo_w) -TRANS(vclo_d, ALL, gen_vv, gen_helper_vclo_d) -TRANS(vclz_b, ALL, gen_vv, gen_helper_vclz_b) -TRANS(vclz_h, ALL, gen_vv, gen_helper_vclz_h) -TRANS(vclz_w, ALL, gen_vv, gen_helper_vclz_w) -TRANS(vclz_d, ALL, gen_vv, gen_helper_vclz_d) +TRANS(vclo_b, LSX, gen_vv, gen_helper_vclo_b) +TRANS(vclo_h, LSX, gen_vv, gen_helper_vclo_h) +TRANS(vclo_w, LSX, gen_vv, gen_helper_vclo_w) +TRANS(vclo_d, LSX, gen_vv, gen_helper_vclo_d) +TRANS(vclz_b, LSX, gen_vv, gen_helper_vclz_b) +TRANS(vclz_h, LSX, gen_vv, gen_helper_vclz_h) +TRANS(vclz_w, LSX, gen_vv, gen_helper_vclz_w) +TRANS(vclz_d, LSX, gen_vv, gen_helper_vclz_d) -TRANS(vpcnt_b, ALL, gen_vv, gen_helper_vpcnt_b) -TRANS(vpcnt_h, ALL, gen_vv, gen_helper_vpcnt_h) -TRANS(vpcnt_w, ALL, gen_vv, gen_helper_vpcnt_w) -TRANS(vpcnt_d, ALL, gen_vv, gen_helper_vpcnt_d) +TRANS(vpcnt_b, LSX, gen_vv, gen_helper_vpcnt_b) +TRANS(vpcnt_h, LSX, gen_vv, gen_helper_vpcnt_h) +TRANS(vpcnt_w, LSX, gen_vv, gen_helper_vpcnt_w) +TRANS(vpcnt_d, LSX, gen_vv, gen_helper_vpcnt_d) static void do_vbit(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b, void (*func)(unsigned, TCGv_vec, TCGv_vec, TCGv_vec)) @@ -3340,10 +3361,10 @@ static void do_vbitclr(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vbitclr_b, ALL, gvec_vvv, MO_8, do_vbitclr) -TRANS(vbitclr_h, ALL, gvec_vvv, MO_16, do_vbitclr) -TRANS(vbitclr_w, ALL, gvec_vvv, MO_32, do_vbitclr) -TRANS(vbitclr_d, ALL, gvec_vvv, MO_64, do_vbitclr) +TRANS(vbitclr_b, LSX, gvec_vvv, MO_8, do_vbitclr) +TRANS(vbitclr_h, LSX, gvec_vvv, MO_16, do_vbitclr) +TRANS(vbitclr_w, LSX, gvec_vvv, MO_32, do_vbitclr) +TRANS(vbitclr_d, LSX, gvec_vvv, MO_64, do_vbitclr) static void do_vbiti(unsigned vece, TCGv_vec t, TCGv_vec a, int64_t imm, void (*func)(unsigned, TCGv_vec, TCGv_vec, TCGv_vec)) @@ -3410,10 +3431,10 @@ static void do_vbitclri(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_2i(vd_ofs, vj_ofs, oprsz, maxsz, imm, &op[vece]); } -TRANS(vbitclri_b, ALL, gvec_vv_i, MO_8, do_vbitclri) -TRANS(vbitclri_h, ALL, gvec_vv_i, MO_16, do_vbitclri) -TRANS(vbitclri_w, ALL, gvec_vv_i, MO_32, do_vbitclri) -TRANS(vbitclri_d, ALL, gvec_vv_i, MO_64, do_vbitclri) +TRANS(vbitclri_b, LSX, gvec_vv_i, MO_8, do_vbitclri) +TRANS(vbitclri_h, LSX, gvec_vv_i, MO_16, do_vbitclri) +TRANS(vbitclri_w, LSX, gvec_vv_i, MO_32, do_vbitclri) +TRANS(vbitclri_d, LSX, gvec_vv_i, MO_64, do_vbitclri) static void do_vbitset(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) @@ -3451,10 +3472,10 @@ static void do_vbitset(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vbitset_b, ALL, gvec_vvv, MO_8, do_vbitset) -TRANS(vbitset_h, ALL, gvec_vvv, MO_16, do_vbitset) -TRANS(vbitset_w, ALL, gvec_vvv, MO_32, do_vbitset) -TRANS(vbitset_d, ALL, gvec_vvv, MO_64, do_vbitset) +TRANS(vbitset_b, LSX, gvec_vvv, MO_8, do_vbitset) +TRANS(vbitset_h, LSX, gvec_vvv, MO_16, do_vbitset) +TRANS(vbitset_w, LSX, gvec_vvv, MO_32, do_vbitset) +TRANS(vbitset_d, LSX, gvec_vvv, MO_64, do_vbitset) static void do_vbitseti(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, int64_t imm, uint32_t oprsz, uint32_t maxsz) @@ -3492,10 +3513,10 @@ static void do_vbitseti(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_2i(vd_ofs, vj_ofs, oprsz, maxsz, imm, &op[vece]); } -TRANS(vbitseti_b, ALL, gvec_vv_i, MO_8, do_vbitseti) -TRANS(vbitseti_h, ALL, gvec_vv_i, MO_16, do_vbitseti) -TRANS(vbitseti_w, ALL, gvec_vv_i, MO_32, do_vbitseti) -TRANS(vbitseti_d, ALL, gvec_vv_i, MO_64, do_vbitseti) +TRANS(vbitseti_b, LSX, gvec_vv_i, MO_8, do_vbitseti) +TRANS(vbitseti_h, LSX, gvec_vv_i, MO_16, do_vbitseti) +TRANS(vbitseti_w, LSX, gvec_vv_i, MO_32, do_vbitseti) +TRANS(vbitseti_d, LSX, gvec_vv_i, MO_64, do_vbitseti) static void do_vbitrev(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, uint32_t vk_ofs, uint32_t oprsz, uint32_t maxsz) @@ -3533,10 +3554,10 @@ static void do_vbitrev(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_3(vd_ofs, vj_ofs, vk_ofs, oprsz, maxsz, &op[vece]); } -TRANS(vbitrev_b, ALL, gvec_vvv, MO_8, do_vbitrev) -TRANS(vbitrev_h, ALL, gvec_vvv, MO_16, do_vbitrev) -TRANS(vbitrev_w, ALL, gvec_vvv, MO_32, do_vbitrev) -TRANS(vbitrev_d, ALL, gvec_vvv, MO_64, do_vbitrev) +TRANS(vbitrev_b, LSX, gvec_vvv, MO_8, do_vbitrev) +TRANS(vbitrev_h, LSX, gvec_vvv, MO_16, do_vbitrev) +TRANS(vbitrev_w, LSX, gvec_vvv, MO_32, do_vbitrev) +TRANS(vbitrev_d, LSX, gvec_vvv, MO_64, do_vbitrev) static void do_vbitrevi(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, int64_t imm, uint32_t oprsz, uint32_t maxsz) @@ -3574,112 +3595,112 @@ static void do_vbitrevi(unsigned vece, uint32_t vd_ofs, uint32_t vj_ofs, tcg_gen_gvec_2i(vd_ofs, vj_ofs, oprsz, maxsz, imm, &op[vece]); } -TRANS(vbitrevi_b, ALL, gvec_vv_i, MO_8, do_vbitrevi) -TRANS(vbitrevi_h, ALL, gvec_vv_i, MO_16, do_vbitrevi) -TRANS(vbitrevi_w, ALL, gvec_vv_i, MO_32, do_vbitrevi) -TRANS(vbitrevi_d, ALL, gvec_vv_i, MO_64, do_vbitrevi) +TRANS(vbitrevi_b, LSX, gvec_vv_i, MO_8, do_vbitrevi) +TRANS(vbitrevi_h, LSX, gvec_vv_i, MO_16, do_vbitrevi) +TRANS(vbitrevi_w, LSX, gvec_vv_i, MO_32, do_vbitrevi) +TRANS(vbitrevi_d, LSX, gvec_vv_i, MO_64, do_vbitrevi) -TRANS(vfrstp_b, ALL, gen_vvv, gen_helper_vfrstp_b) -TRANS(vfrstp_h, ALL, gen_vvv, gen_helper_vfrstp_h) -TRANS(vfrstpi_b, ALL, gen_vv_i, gen_helper_vfrstpi_b) -TRANS(vfrstpi_h, ALL, gen_vv_i, gen_helper_vfrstpi_h) +TRANS(vfrstp_b, LSX, gen_vvv, gen_helper_vfrstp_b) +TRANS(vfrstp_h, LSX, gen_vvv, gen_helper_vfrstp_h) +TRANS(vfrstpi_b, LSX, gen_vv_i, gen_helper_vfrstpi_b) +TRANS(vfrstpi_h, LSX, gen_vv_i, gen_helper_vfrstpi_h) -TRANS(vfadd_s, ALL, gen_vvv, gen_helper_vfadd_s) -TRANS(vfadd_d, ALL, gen_vvv, gen_helper_vfadd_d) -TRANS(vfsub_s, ALL, gen_vvv, gen_helper_vfsub_s) -TRANS(vfsub_d, ALL, gen_vvv, gen_helper_vfsub_d) -TRANS(vfmul_s, ALL, gen_vvv, gen_helper_vfmul_s) -TRANS(vfmul_d, ALL, gen_vvv, gen_helper_vfmul_d) -TRANS(vfdiv_s, ALL, gen_vvv, gen_helper_vfdiv_s) -TRANS(vfdiv_d, ALL, gen_vvv, gen_helper_vfdiv_d) +TRANS(vfadd_s, LSX, gen_vvv, gen_helper_vfadd_s) +TRANS(vfadd_d, LSX, gen_vvv, gen_helper_vfadd_d) +TRANS(vfsub_s, LSX, gen_vvv, gen_helper_vfsub_s) +TRANS(vfsub_d, LSX, gen_vvv, gen_helper_vfsub_d) +TRANS(vfmul_s, LSX, gen_vvv, gen_helper_vfmul_s) +TRANS(vfmul_d, LSX, gen_vvv, gen_helper_vfmul_d) +TRANS(vfdiv_s, LSX, gen_vvv, gen_helper_vfdiv_s) +TRANS(vfdiv_d, LSX, gen_vvv, gen_helper_vfdiv_d) -TRANS(vfmadd_s, ALL, gen_vvvv, gen_helper_vfmadd_s) -TRANS(vfmadd_d, ALL, gen_vvvv, gen_helper_vfmadd_d) -TRANS(vfmsub_s, ALL, gen_vvvv, gen_helper_vfmsub_s) -TRANS(vfmsub_d, ALL, gen_vvvv, gen_helper_vfmsub_d) -TRANS(vfnmadd_s, ALL, gen_vvvv, gen_helper_vfnmadd_s) -TRANS(vfnmadd_d, ALL, gen_vvvv, gen_helper_vfnmadd_d) -TRANS(vfnmsub_s, ALL, gen_vvvv, gen_helper_vfnmsub_s) -TRANS(vfnmsub_d, ALL, gen_vvvv, gen_helper_vfnmsub_d) +TRANS(vfmadd_s, LSX, gen_vvvv, gen_helper_vfmadd_s) +TRANS(vfmadd_d, LSX, gen_vvvv, gen_helper_vfmadd_d) +TRANS(vfmsub_s, LSX, gen_vvvv, gen_helper_vfmsub_s) +TRANS(vfmsub_d, LSX, gen_vvvv, gen_helper_vfmsub_d) +TRANS(vfnmadd_s, LSX, gen_vvvv, gen_helper_vfnmadd_s) +TRANS(vfnmadd_d, LSX, gen_vvvv, gen_helper_vfnmadd_d) +TRANS(vfnmsub_s, LSX, gen_vvvv, gen_helper_vfnmsub_s) +TRANS(vfnmsub_d, LSX, gen_vvvv, gen_helper_vfnmsub_d) -TRANS(vfmax_s, ALL, gen_vvv, gen_helper_vfmax_s) -TRANS(vfmax_d, ALL, gen_vvv, gen_helper_vfmax_d) -TRANS(vfmin_s, ALL, gen_vvv, gen_helper_vfmin_s) -TRANS(vfmin_d, ALL, gen_vvv, gen_helper_vfmin_d) +TRANS(vfmax_s, LSX, gen_vvv, gen_helper_vfmax_s) +TRANS(vfmax_d, LSX, gen_vvv, gen_helper_vfmax_d) +TRANS(vfmin_s, LSX, gen_vvv, gen_helper_vfmin_s) +TRANS(vfmin_d, LSX, gen_vvv, gen_helper_vfmin_d) -TRANS(vfmaxa_s, ALL, gen_vvv, gen_helper_vfmaxa_s) -TRANS(vfmaxa_d, ALL, gen_vvv, gen_helper_vfmaxa_d) -TRANS(vfmina_s, ALL, gen_vvv, gen_helper_vfmina_s) -TRANS(vfmina_d, ALL, gen_vvv, gen_helper_vfmina_d) +TRANS(vfmaxa_s, LSX, gen_vvv, gen_helper_vfmaxa_s) +TRANS(vfmaxa_d, LSX, gen_vvv, gen_helper_vfmaxa_d) +TRANS(vfmina_s, LSX, gen_vvv, gen_helper_vfmina_s) +TRANS(vfmina_d, LSX, gen_vvv, gen_helper_vfmina_d) -TRANS(vflogb_s, ALL, gen_vv, gen_helper_vflogb_s) -TRANS(vflogb_d, ALL, gen_vv, gen_helper_vflogb_d) +TRANS(vflogb_s, LSX, gen_vv, gen_helper_vflogb_s) +TRANS(vflogb_d, LSX, gen_vv, gen_helper_vflogb_d) -TRANS(vfclass_s, ALL, gen_vv, gen_helper_vfclass_s) -TRANS(vfclass_d, ALL, gen_vv, gen_helper_vfclass_d) +TRANS(vfclass_s, LSX, gen_vv, gen_helper_vfclass_s) +TRANS(vfclass_d, LSX, gen_vv, gen_helper_vfclass_d) -TRANS(vfsqrt_s, ALL, gen_vv, gen_helper_vfsqrt_s) -TRANS(vfsqrt_d, ALL, gen_vv, gen_helper_vfsqrt_d) -TRANS(vfrecip_s, ALL, gen_vv, gen_helper_vfrecip_s) -TRANS(vfrecip_d, ALL, gen_vv, gen_helper_vfrecip_d) -TRANS(vfrsqrt_s, ALL, gen_vv, gen_helper_vfrsqrt_s) -TRANS(vfrsqrt_d, ALL, gen_vv, gen_helper_vfrsqrt_d) +TRANS(vfsqrt_s, LSX, gen_vv, gen_helper_vfsqrt_s) +TRANS(vfsqrt_d, LSX, gen_vv, gen_helper_vfsqrt_d) +TRANS(vfrecip_s, LSX, gen_vv, gen_helper_vfrecip_s) +TRANS(vfrecip_d, LSX, gen_vv, gen_helper_vfrecip_d) +TRANS(vfrsqrt_s, LSX, gen_vv, gen_helper_vfrsqrt_s) +TRANS(vfrsqrt_d, LSX, gen_vv, gen_helper_vfrsqrt_d) -TRANS(vfcvtl_s_h, ALL, gen_vv, gen_helper_vfcvtl_s_h) -TRANS(vfcvth_s_h, ALL, gen_vv, gen_helper_vfcvth_s_h) -TRANS(vfcvtl_d_s, ALL, gen_vv, gen_helper_vfcvtl_d_s) -TRANS(vfcvth_d_s, ALL, gen_vv, gen_helper_vfcvth_d_s) -TRANS(vfcvt_h_s, ALL, gen_vvv, gen_helper_vfcvt_h_s) -TRANS(vfcvt_s_d, ALL, gen_vvv, gen_helper_vfcvt_s_d) +TRANS(vfcvtl_s_h, LSX, gen_vv, gen_helper_vfcvtl_s_h) +TRANS(vfcvth_s_h, LSX, gen_vv, gen_helper_vfcvth_s_h) +TRANS(vfcvtl_d_s, LSX, gen_vv, gen_helper_vfcvtl_d_s) +TRANS(vfcvth_d_s, LSX, gen_vv, gen_helper_vfcvth_d_s) +TRANS(vfcvt_h_s, LSX, gen_vvv, gen_helper_vfcvt_h_s) +TRANS(vfcvt_s_d, LSX, gen_vvv, gen_helper_vfcvt_s_d) -TRANS(vfrintrne_s, ALL, gen_vv, gen_helper_vfrintrne_s) -TRANS(vfrintrne_d, ALL, gen_vv, gen_helper_vfrintrne_d) -TRANS(vfrintrz_s, ALL, gen_vv, gen_helper_vfrintrz_s) -TRANS(vfrintrz_d, ALL, gen_vv, gen_helper_vfrintrz_d) -TRANS(vfrintrp_s, ALL, gen_vv, gen_helper_vfrintrp_s) -TRANS(vfrintrp_d, ALL, gen_vv, gen_helper_vfrintrp_d) -TRANS(vfrintrm_s, ALL, gen_vv, gen_helper_vfrintrm_s) -TRANS(vfrintrm_d, ALL, gen_vv, gen_helper_vfrintrm_d) -TRANS(vfrint_s, ALL, gen_vv, gen_helper_vfrint_s) -TRANS(vfrint_d, ALL, gen_vv, gen_helper_vfrint_d) +TRANS(vfrintrne_s, LSX, gen_vv, gen_helper_vfrintrne_s) +TRANS(vfrintrne_d, LSX, gen_vv, gen_helper_vfrintrne_d) +TRANS(vfrintrz_s, LSX, gen_vv, gen_helper_vfrintrz_s) +TRANS(vfrintrz_d, LSX, gen_vv, gen_helper_vfrintrz_d) +TRANS(vfrintrp_s, LSX, gen_vv, gen_helper_vfrintrp_s) +TRANS(vfrintrp_d, LSX, gen_vv, gen_helper_vfrintrp_d) +TRANS(vfrintrm_s, LSX, gen_vv, gen_helper_vfrintrm_s) +TRANS(vfrintrm_d, LSX, gen_vv, gen_helper_vfrintrm_d) +TRANS(vfrint_s, LSX, gen_vv, gen_helper_vfrint_s) +TRANS(vfrint_d, LSX, gen_vv, gen_helper_vfrint_d) -TRANS(vftintrne_w_s, ALL, gen_vv, gen_helper_vftintrne_w_s) -TRANS(vftintrne_l_d, ALL, gen_vv, gen_helper_vftintrne_l_d) -TRANS(vftintrz_w_s, ALL, gen_vv, gen_helper_vftintrz_w_s) -TRANS(vftintrz_l_d, ALL, gen_vv, gen_helper_vftintrz_l_d) -TRANS(vftintrp_w_s, ALL, gen_vv, gen_helper_vftintrp_w_s) -TRANS(vftintrp_l_d, ALL, gen_vv, gen_helper_vftintrp_l_d) -TRANS(vftintrm_w_s, ALL, gen_vv, gen_helper_vftintrm_w_s) -TRANS(vftintrm_l_d, ALL, gen_vv, gen_helper_vftintrm_l_d) -TRANS(vftint_w_s, ALL, gen_vv, gen_helper_vftint_w_s) -TRANS(vftint_l_d, ALL, gen_vv, gen_helper_vftint_l_d) -TRANS(vftintrz_wu_s, ALL, gen_vv, gen_helper_vftintrz_wu_s) -TRANS(vftintrz_lu_d, ALL, gen_vv, gen_helper_vftintrz_lu_d) -TRANS(vftint_wu_s, ALL, gen_vv, gen_helper_vftint_wu_s) -TRANS(vftint_lu_d, ALL, gen_vv, gen_helper_vftint_lu_d) -TRANS(vftintrne_w_d, ALL, gen_vvv, gen_helper_vftintrne_w_d) -TRANS(vftintrz_w_d, ALL, gen_vvv, gen_helper_vftintrz_w_d) -TRANS(vftintrp_w_d, ALL, gen_vvv, gen_helper_vftintrp_w_d) -TRANS(vftintrm_w_d, ALL, gen_vvv, gen_helper_vftintrm_w_d) -TRANS(vftint_w_d, ALL, gen_vvv, gen_helper_vftint_w_d) -TRANS(vftintrnel_l_s, ALL, gen_vv, gen_helper_vftintrnel_l_s) -TRANS(vftintrneh_l_s, ALL, gen_vv, gen_helper_vftintrneh_l_s) -TRANS(vftintrzl_l_s, ALL, gen_vv, gen_helper_vftintrzl_l_s) -TRANS(vftintrzh_l_s, ALL, gen_vv, gen_helper_vftintrzh_l_s) -TRANS(vftintrpl_l_s, ALL, gen_vv, gen_helper_vftintrpl_l_s) -TRANS(vftintrph_l_s, ALL, gen_vv, gen_helper_vftintrph_l_s) -TRANS(vftintrml_l_s, ALL, gen_vv, gen_helper_vftintrml_l_s) -TRANS(vftintrmh_l_s, ALL, gen_vv, gen_helper_vftintrmh_l_s) -TRANS(vftintl_l_s, ALL, gen_vv, gen_helper_vftintl_l_s) -TRANS(vftinth_l_s, ALL, gen_vv, gen_helper_vftinth_l_s) +TRANS(vftintrne_w_s, LSX, gen_vv, gen_helper_vftintrne_w_s) +TRANS(vftintrne_l_d, LSX, gen_vv, gen_helper_vftintrne_l_d) +TRANS(vftintrz_w_s, LSX, gen_vv, gen_helper_vftintrz_w_s) +TRANS(vftintrz_l_d, LSX, gen_vv, gen_helper_vftintrz_l_d) +TRANS(vftintrp_w_s, LSX, gen_vv, gen_helper_vftintrp_w_s) +TRANS(vftintrp_l_d, LSX, gen_vv, gen_helper_vftintrp_l_d) +TRANS(vftintrm_w_s, LSX, gen_vv, gen_helper_vftintrm_w_s) +TRANS(vftintrm_l_d, LSX, gen_vv, gen_helper_vftintrm_l_d) +TRANS(vftint_w_s, LSX, gen_vv, gen_helper_vftint_w_s) +TRANS(vftint_l_d, LSX, gen_vv, gen_helper_vftint_l_d) +TRANS(vftintrz_wu_s, LSX, gen_vv, gen_helper_vftintrz_wu_s) +TRANS(vftintrz_lu_d, LSX, gen_vv, gen_helper_vftintrz_lu_d) +TRANS(vftint_wu_s, LSX, gen_vv, gen_helper_vftint_wu_s) +TRANS(vftint_lu_d, LSX, gen_vv, gen_helper_vftint_lu_d) +TRANS(vftintrne_w_d, LSX, gen_vvv, gen_helper_vftintrne_w_d) +TRANS(vftintrz_w_d, LSX, gen_vvv, gen_helper_vftintrz_w_d) +TRANS(vftintrp_w_d, LSX, gen_vvv, gen_helper_vftintrp_w_d) +TRANS(vftintrm_w_d, LSX, gen_vvv, gen_helper_vftintrm_w_d) +TRANS(vftint_w_d, LSX, gen_vvv, gen_helper_vftint_w_d) +TRANS(vftintrnel_l_s, LSX, gen_vv, gen_helper_vftintrnel_l_s) +TRANS(vftintrneh_l_s, LSX, gen_vv, gen_helper_vftintrneh_l_s) +TRANS(vftintrzl_l_s, LSX, gen_vv, gen_helper_vftintrzl_l_s) +TRANS(vftintrzh_l_s, LSX, gen_vv, gen_helper_vftintrzh_l_s) +TRANS(vftintrpl_l_s, LSX, gen_vv, gen_helper_vftintrpl_l_s) +TRANS(vftintrph_l_s, LSX, gen_vv, gen_helper_vftintrph_l_s) +TRANS(vftintrml_l_s, LSX, gen_vv, gen_helper_vftintrml_l_s) +TRANS(vftintrmh_l_s, LSX, gen_vv, gen_helper_vftintrmh_l_s) +TRANS(vftintl_l_s, LSX, gen_vv, gen_helper_vftintl_l_s) +TRANS(vftinth_l_s, LSX, gen_vv, gen_helper_vftinth_l_s) -TRANS(vffint_s_w, ALL, gen_vv, gen_helper_vffint_s_w) -TRANS(vffint_d_l, ALL, gen_vv, gen_helper_vffint_d_l) -TRANS(vffint_s_wu, ALL, gen_vv, gen_helper_vffint_s_wu) -TRANS(vffint_d_lu, ALL, gen_vv, gen_helper_vffint_d_lu) -TRANS(vffintl_d_w, ALL, gen_vv, gen_helper_vffintl_d_w) -TRANS(vffinth_d_w, ALL, gen_vv, gen_helper_vffinth_d_w) -TRANS(vffint_s_l, ALL, gen_vvv, gen_helper_vffint_s_l) +TRANS(vffint_s_w, LSX, gen_vv, gen_helper_vffint_s_w) +TRANS(vffint_d_l, LSX, gen_vv, gen_helper_vffint_d_l) +TRANS(vffint_s_wu, LSX, gen_vv, gen_helper_vffint_s_wu) +TRANS(vffint_d_lu, LSX, gen_vv, gen_helper_vffint_d_lu) +TRANS(vffintl_d_w, LSX, gen_vv, gen_helper_vffintl_d_w) +TRANS(vffinth_d_w, LSX, gen_vv, gen_helper_vffinth_d_w) +TRANS(vffint_s_l, LSX, gen_vvv, gen_helper_vffint_s_l) static bool do_cmp(DisasContext *ctx, arg_vvv *a, MemOp mop, TCGCond cond) { @@ -3823,48 +3844,48 @@ static bool do_## NAME ##_u(DisasContext *ctx, arg_vv_i *a, MemOp mop) \ DO_CMPI_U(vslei) DO_CMPI_U(vslti) -TRANS(vseq_b, ALL, do_cmp, MO_8, TCG_COND_EQ) -TRANS(vseq_h, ALL, do_cmp, MO_16, TCG_COND_EQ) -TRANS(vseq_w, ALL, do_cmp, MO_32, TCG_COND_EQ) -TRANS(vseq_d, ALL, do_cmp, MO_64, TCG_COND_EQ) -TRANS(vseqi_b, ALL, do_vseqi_s, MO_8) -TRANS(vseqi_h, ALL, do_vseqi_s, MO_16) -TRANS(vseqi_w, ALL, do_vseqi_s, MO_32) -TRANS(vseqi_d, ALL, do_vseqi_s, MO_64) +TRANS(vseq_b, LSX, do_cmp, MO_8, TCG_COND_EQ) +TRANS(vseq_h, LSX, do_cmp, MO_16, TCG_COND_EQ) +TRANS(vseq_w, LSX, do_cmp, MO_32, TCG_COND_EQ) +TRANS(vseq_d, LSX, do_cmp, MO_64, TCG_COND_EQ) +TRANS(vseqi_b, LSX, do_vseqi_s, MO_8) +TRANS(vseqi_h, LSX, do_vseqi_s, MO_16) +TRANS(vseqi_w, LSX, do_vseqi_s, MO_32) +TRANS(vseqi_d, LSX, do_vseqi_s, MO_64) -TRANS(vsle_b, ALL, do_cmp, MO_8, TCG_COND_LE) -TRANS(vsle_h, ALL, do_cmp, MO_16, TCG_COND_LE) -TRANS(vsle_w, ALL, do_cmp, MO_32, TCG_COND_LE) -TRANS(vsle_d, ALL, do_cmp, MO_64, TCG_COND_LE) -TRANS(vslei_b, ALL, do_vslei_s, MO_8) -TRANS(vslei_h, ALL, do_vslei_s, MO_16) -TRANS(vslei_w, ALL, do_vslei_s, MO_32) -TRANS(vslei_d, ALL, do_vslei_s, MO_64) -TRANS(vsle_bu, ALL, do_cmp, MO_8, TCG_COND_LEU) -TRANS(vsle_hu, ALL, do_cmp, MO_16, TCG_COND_LEU) -TRANS(vsle_wu, ALL, do_cmp, MO_32, TCG_COND_LEU) -TRANS(vsle_du, ALL, do_cmp, MO_64, TCG_COND_LEU) -TRANS(vslei_bu, ALL, do_vslei_u, MO_8) -TRANS(vslei_hu, ALL, do_vslei_u, MO_16) -TRANS(vslei_wu, ALL, do_vslei_u, MO_32) -TRANS(vslei_du, ALL, do_vslei_u, MO_64) +TRANS(vsle_b, LSX, do_cmp, MO_8, TCG_COND_LE) +TRANS(vsle_h, LSX, do_cmp, MO_16, TCG_COND_LE) +TRANS(vsle_w, LSX, do_cmp, MO_32, TCG_COND_LE) +TRANS(vsle_d, LSX, do_cmp, MO_64, TCG_COND_LE) +TRANS(vslei_b, LSX, do_vslei_s, MO_8) +TRANS(vslei_h, LSX, do_vslei_s, MO_16) +TRANS(vslei_w, LSX, do_vslei_s, MO_32) +TRANS(vslei_d, LSX, do_vslei_s, MO_64) +TRANS(vsle_bu, LSX, do_cmp, MO_8, TCG_COND_LEU) +TRANS(vsle_hu, LSX, do_cmp, MO_16, TCG_COND_LEU) +TRANS(vsle_wu, LSX, do_cmp, MO_32, TCG_COND_LEU) +TRANS(vsle_du, LSX, do_cmp, MO_64, TCG_COND_LEU) +TRANS(vslei_bu, LSX, do_vslei_u, MO_8) +TRANS(vslei_hu, LSX, do_vslei_u, MO_16) +TRANS(vslei_wu, LSX, do_vslei_u, MO_32) +TRANS(vslei_du, LSX, do_vslei_u, MO_64) -TRANS(vslt_b, ALL, do_cmp, MO_8, TCG_COND_LT) -TRANS(vslt_h, ALL, do_cmp, MO_16, TCG_COND_LT) -TRANS(vslt_w, ALL, do_cmp, MO_32, TCG_COND_LT) -TRANS(vslt_d, ALL, do_cmp, MO_64, TCG_COND_LT) -TRANS(vslti_b, ALL, do_vslti_s, MO_8) -TRANS(vslti_h, ALL, do_vslti_s, MO_16) -TRANS(vslti_w, ALL, do_vslti_s, MO_32) -TRANS(vslti_d, ALL, do_vslti_s, MO_64) -TRANS(vslt_bu, ALL, do_cmp, MO_8, TCG_COND_LTU) -TRANS(vslt_hu, ALL, do_cmp, MO_16, TCG_COND_LTU) -TRANS(vslt_wu, ALL, do_cmp, MO_32, TCG_COND_LTU) -TRANS(vslt_du, ALL, do_cmp, MO_64, TCG_COND_LTU) -TRANS(vslti_bu, ALL, do_vslti_u, MO_8) -TRANS(vslti_hu, ALL, do_vslti_u, MO_16) -TRANS(vslti_wu, ALL, do_vslti_u, MO_32) -TRANS(vslti_du, ALL, do_vslti_u, MO_64) +TRANS(vslt_b, LSX, do_cmp, MO_8, TCG_COND_LT) +TRANS(vslt_h, LSX, do_cmp, MO_16, TCG_COND_LT) +TRANS(vslt_w, LSX, do_cmp, MO_32, TCG_COND_LT) +TRANS(vslt_d, LSX, do_cmp, MO_64, TCG_COND_LT) +TRANS(vslti_b, LSX, do_vslti_s, MO_8) +TRANS(vslti_h, LSX, do_vslti_s, MO_16) +TRANS(vslti_w, LSX, do_vslti_s, MO_32) +TRANS(vslti_d, LSX, do_vslti_s, MO_64) +TRANS(vslt_bu, LSX, do_cmp, MO_8, TCG_COND_LTU) +TRANS(vslt_hu, LSX, do_cmp, MO_16, TCG_COND_LTU) +TRANS(vslt_wu, LSX, do_cmp, MO_32, TCG_COND_LTU) +TRANS(vslt_du, LSX, do_cmp, MO_64, TCG_COND_LTU) +TRANS(vslti_bu, LSX, do_vslti_u, MO_8) +TRANS(vslti_hu, LSX, do_vslti_u, MO_16) +TRANS(vslti_wu, LSX, do_vslti_u, MO_32) +TRANS(vslti_du, LSX, do_vslti_u, MO_64) static bool trans_vfcmp_cond_s(DisasContext *ctx, arg_vvv_fcond *a) { @@ -3874,6 +3895,10 @@ static bool trans_vfcmp_cond_s(DisasContext *ctx, arg_vvv_fcond *a) TCGv_i32 vj = tcg_constant_i32(a->vj); TCGv_i32 vk = tcg_constant_i32(a->vk); + if (!avail_LSX(ctx)) { + return false; + } + CHECK_SXE; fn = (a->fcond & 1 ? gen_helper_vfcmp_s_s : gen_helper_vfcmp_c_s); @@ -3891,6 +3916,12 @@ static bool trans_vfcmp_cond_d(DisasContext *ctx, arg_vvv_fcond *a) TCGv_i32 vj = tcg_constant_i32(a->vj); TCGv_i32 vk = tcg_constant_i32(a->vk); + if (!avail_LSX(ctx)) { + return false; + } + + CHECK_SXE; + fn = (a->fcond & 1 ? gen_helper_vfcmp_s_d : gen_helper_vfcmp_c_d); flags = get_fcmp_flags(a->fcond >> 1); fn(cpu_env, vd, vj, vk, tcg_constant_i32(flags)); @@ -3900,6 +3931,10 @@ static bool trans_vfcmp_cond_d(DisasContext *ctx, arg_vvv_fcond *a) static bool trans_vbitsel_v(DisasContext *ctx, arg_vvvv *a) { + if (!avail_LSX(ctx)) { + return false; + } + CHECK_SXE; tcg_gen_gvec_bitsel(MO_64, vec_full_offset(a->vd), vec_full_offset(a->va), @@ -3922,6 +3957,10 @@ static bool trans_vbitseli_b(DisasContext *ctx, arg_vv_i *a) .load_dest = true }; + if (!avail_LSX(ctx)) { + return false; + } + CHECK_SXE; tcg_gen_gvec_2i(vec_full_offset(a->vd), vec_full_offset(a->vj), @@ -3941,6 +3980,10 @@ static bool trans_## NAME (DisasContext *ctx, arg_cv *a) \ get_vreg64(ah, a->vj, 1); \ get_vreg64(al, a->vj, 0); \ \ + if (!avail_LSX(ctx)) { \ + return false; \ + } \ + \ CHECK_SXE; \ tcg_gen_or_i64(t1, al, ah); \ tcg_gen_setcondi_i64(COND, t1, t1, 0); \ @@ -3952,18 +3995,23 @@ static bool trans_## NAME (DisasContext *ctx, arg_cv *a) \ VSET(vseteqz_v, TCG_COND_EQ) VSET(vsetnez_v, TCG_COND_NE) -TRANS(vsetanyeqz_b, ALL, gen_cv, gen_helper_vsetanyeqz_b) -TRANS(vsetanyeqz_h, ALL, gen_cv, gen_helper_vsetanyeqz_h) -TRANS(vsetanyeqz_w, ALL, gen_cv, gen_helper_vsetanyeqz_w) -TRANS(vsetanyeqz_d, ALL, gen_cv, gen_helper_vsetanyeqz_d) -TRANS(vsetallnez_b, ALL, gen_cv, gen_helper_vsetallnez_b) -TRANS(vsetallnez_h, ALL, gen_cv, gen_helper_vsetallnez_h) -TRANS(vsetallnez_w, ALL, gen_cv, gen_helper_vsetallnez_w) -TRANS(vsetallnez_d, ALL, gen_cv, gen_helper_vsetallnez_d) +TRANS(vsetanyeqz_b, LSX, gen_cv, gen_helper_vsetanyeqz_b) +TRANS(vsetanyeqz_h, LSX, gen_cv, gen_helper_vsetanyeqz_h) +TRANS(vsetanyeqz_w, LSX, gen_cv, gen_helper_vsetanyeqz_w) +TRANS(vsetanyeqz_d, LSX, gen_cv, gen_helper_vsetanyeqz_d) +TRANS(vsetallnez_b, LSX, gen_cv, gen_helper_vsetallnez_b) +TRANS(vsetallnez_h, LSX, gen_cv, gen_helper_vsetallnez_h) +TRANS(vsetallnez_w, LSX, gen_cv, gen_helper_vsetallnez_w) +TRANS(vsetallnez_d, LSX, gen_cv, gen_helper_vsetallnez_d) static bool trans_vinsgr2vr_b(DisasContext *ctx, arg_vr_i *a) { TCGv src = gpr_src(ctx, a->rj, EXT_NONE); + + if (!avail_LSX(ctx)) { + return false; + } + CHECK_SXE; tcg_gen_st8_i64(src, cpu_env, offsetof(CPULoongArchState, fpr[a->vd].vreg.B(a->imm))); @@ -3973,6 +4021,11 @@ static bool trans_vinsgr2vr_b(DisasContext *ctx, arg_vr_i *a) static bool trans_vinsgr2vr_h(DisasContext *ctx, arg_vr_i *a) { TCGv src = gpr_src(ctx, a->rj, EXT_NONE); + + if (!avail_LSX(ctx)) { + return false; + } + CHECK_SXE; tcg_gen_st16_i64(src, cpu_env, offsetof(CPULoongArchState, fpr[a->vd].vreg.H(a->imm))); @@ -3982,6 +4035,11 @@ static bool trans_vinsgr2vr_h(DisasContext *ctx, arg_vr_i *a) static bool trans_vinsgr2vr_w(DisasContext *ctx, arg_vr_i *a) { TCGv src = gpr_src(ctx, a->rj, EXT_NONE); + + if (!avail_LSX(ctx)) { + return false; + } + CHECK_SXE; tcg_gen_st32_i64(src, cpu_env, offsetof(CPULoongArchState, fpr[a->vd].vreg.W(a->imm))); @@ -3991,6 +4049,11 @@ static bool trans_vinsgr2vr_w(DisasContext *ctx, arg_vr_i *a) static bool trans_vinsgr2vr_d(DisasContext *ctx, arg_vr_i *a) { TCGv src = gpr_src(ctx, a->rj, EXT_NONE); + + if (!avail_LSX(ctx)) { + return false; + } + CHECK_SXE; tcg_gen_st_i64(src, cpu_env, offsetof(CPULoongArchState, fpr[a->vd].vreg.D(a->imm))); @@ -4000,6 +4063,11 @@ static bool trans_vinsgr2vr_d(DisasContext *ctx, arg_vr_i *a) static bool trans_vpickve2gr_b(DisasContext *ctx, arg_rv_i *a) { TCGv dst = gpr_dst(ctx, a->rd, EXT_NONE); + + if (!avail_LSX(ctx)) { + return false; + } + CHECK_SXE; tcg_gen_ld8s_i64(dst, cpu_env, offsetof(CPULoongArchState, fpr[a->vj].vreg.B(a->imm))); @@ -4009,6 +4077,11 @@ static bool trans_vpickve2gr_b(DisasContext *ctx, arg_rv_i *a) static bool trans_vpickve2gr_h(DisasContext *ctx, arg_rv_i *a) { TCGv dst = gpr_dst(ctx, a->rd, EXT_NONE); + + if (!avail_LSX(ctx)) { + return false; + } + CHECK_SXE; tcg_gen_ld16s_i64(dst, cpu_env, offsetof(CPULoongArchState, fpr[a->vj].vreg.H(a->imm))); @@ -4018,6 +4091,11 @@ static bool trans_vpickve2gr_h(DisasContext *ctx, arg_rv_i *a) static bool trans_vpickve2gr_w(DisasContext *ctx, arg_rv_i *a) { TCGv dst = gpr_dst(ctx, a->rd, EXT_NONE); + + if (!avail_LSX(ctx)) { + return false; + } + CHECK_SXE; tcg_gen_ld32s_i64(dst, cpu_env, offsetof(CPULoongArchState, fpr[a->vj].vreg.W(a->imm))); @@ -4027,6 +4105,11 @@ static bool trans_vpickve2gr_w(DisasContext *ctx, arg_rv_i *a) static bool trans_vpickve2gr_d(DisasContext *ctx, arg_rv_i *a) { TCGv dst = gpr_dst(ctx, a->rd, EXT_NONE); + + if (!avail_LSX(ctx)) { + return false; + } + CHECK_SXE; tcg_gen_ld_i64(dst, cpu_env, offsetof(CPULoongArchState, fpr[a->vj].vreg.D(a->imm))); @@ -4036,6 +4119,11 @@ static bool trans_vpickve2gr_d(DisasContext *ctx, arg_rv_i *a) static bool trans_vpickve2gr_bu(DisasContext *ctx, arg_rv_i *a) { TCGv dst = gpr_dst(ctx, a->rd, EXT_NONE); + + if (!avail_LSX(ctx)) { + return false; + } + CHECK_SXE; tcg_gen_ld8u_i64(dst, cpu_env, offsetof(CPULoongArchState, fpr[a->vj].vreg.B(a->imm))); @@ -4045,6 +4133,11 @@ static bool trans_vpickve2gr_bu(DisasContext *ctx, arg_rv_i *a) static bool trans_vpickve2gr_hu(DisasContext *ctx, arg_rv_i *a) { TCGv dst = gpr_dst(ctx, a->rd, EXT_NONE); + + if (!avail_LSX(ctx)) { + return false; + } + CHECK_SXE; tcg_gen_ld16u_i64(dst, cpu_env, offsetof(CPULoongArchState, fpr[a->vj].vreg.H(a->imm))); @@ -4054,6 +4147,11 @@ static bool trans_vpickve2gr_hu(DisasContext *ctx, arg_rv_i *a) static bool trans_vpickve2gr_wu(DisasContext *ctx, arg_rv_i *a) { TCGv dst = gpr_dst(ctx, a->rd, EXT_NONE); + + if (!avail_LSX(ctx)) { + return false; + } + CHECK_SXE; tcg_gen_ld32u_i64(dst, cpu_env, offsetof(CPULoongArchState, fpr[a->vj].vreg.W(a->imm))); @@ -4063,6 +4161,11 @@ static bool trans_vpickve2gr_wu(DisasContext *ctx, arg_rv_i *a) static bool trans_vpickve2gr_du(DisasContext *ctx, arg_rv_i *a) { TCGv dst = gpr_dst(ctx, a->rd, EXT_NONE); + + if (!avail_LSX(ctx)) { + return false; + } + CHECK_SXE; tcg_gen_ld_i64(dst, cpu_env, offsetof(CPULoongArchState, fpr[a->vj].vreg.D(a->imm))); @@ -4072,6 +4175,11 @@ static bool trans_vpickve2gr_du(DisasContext *ctx, arg_rv_i *a) static bool gvec_dup(DisasContext *ctx, arg_vr *a, MemOp mop) { TCGv src = gpr_src(ctx, a->rj, EXT_NONE); + + if (!avail_LSX(ctx)) { + return false; + } + CHECK_SXE; tcg_gen_gvec_dup_i64(mop, vec_full_offset(a->vd), @@ -4079,13 +4187,17 @@ static bool gvec_dup(DisasContext *ctx, arg_vr *a, MemOp mop) return true; } -TRANS(vreplgr2vr_b, ALL, gvec_dup, MO_8) -TRANS(vreplgr2vr_h, ALL, gvec_dup, MO_16) -TRANS(vreplgr2vr_w, ALL, gvec_dup, MO_32) -TRANS(vreplgr2vr_d, ALL, gvec_dup, MO_64) +TRANS(vreplgr2vr_b, LSX, gvec_dup, MO_8) +TRANS(vreplgr2vr_h, LSX, gvec_dup, MO_16) +TRANS(vreplgr2vr_w, LSX, gvec_dup, MO_32) +TRANS(vreplgr2vr_d, LSX, gvec_dup, MO_64) static bool trans_vreplvei_b(DisasContext *ctx, arg_vv_i *a) { + if (!avail_LSX(ctx)) { + return false; + } + CHECK_SXE; tcg_gen_gvec_dup_mem(MO_8,vec_full_offset(a->vd), offsetof(CPULoongArchState, @@ -4096,6 +4208,10 @@ static bool trans_vreplvei_b(DisasContext *ctx, arg_vv_i *a) static bool trans_vreplvei_h(DisasContext *ctx, arg_vv_i *a) { + if (!avail_LSX(ctx)) { + return false; + } + CHECK_SXE; tcg_gen_gvec_dup_mem(MO_16, vec_full_offset(a->vd), offsetof(CPULoongArchState, @@ -4105,6 +4221,10 @@ static bool trans_vreplvei_h(DisasContext *ctx, arg_vv_i *a) } static bool trans_vreplvei_w(DisasContext *ctx, arg_vv_i *a) { + if (!avail_LSX(ctx)) { + return false; + } + CHECK_SXE; tcg_gen_gvec_dup_mem(MO_32, vec_full_offset(a->vd), offsetof(CPULoongArchState, @@ -4114,6 +4234,10 @@ static bool trans_vreplvei_w(DisasContext *ctx, arg_vv_i *a) } static bool trans_vreplvei_d(DisasContext *ctx, arg_vv_i *a) { + if (!avail_LSX(ctx)) { + return false; + } + CHECK_SXE; tcg_gen_gvec_dup_mem(MO_64, vec_full_offset(a->vd), offsetof(CPULoongArchState, @@ -4129,6 +4253,10 @@ static bool gen_vreplve(DisasContext *ctx, arg_vvr *a, int vece, int bit, TCGv_ptr t1 = tcg_temp_new_ptr(); TCGv_i64 t2 = tcg_temp_new_i64(); + if (!avail_LSX(ctx)) { + return false; + } + CHECK_SXE; tcg_gen_andi_i64(t0, gpr_src(ctx, a->rk, EXT_NONE), (LSX_LEN/bit) -1); @@ -4145,16 +4273,20 @@ static bool gen_vreplve(DisasContext *ctx, arg_vvr *a, int vece, int bit, return true; } -TRANS(vreplve_b, ALL, gen_vreplve, MO_8, 8, tcg_gen_ld8u_i64) -TRANS(vreplve_h, ALL, gen_vreplve, MO_16, 16, tcg_gen_ld16u_i64) -TRANS(vreplve_w, ALL, gen_vreplve, MO_32, 32, tcg_gen_ld32u_i64) -TRANS(vreplve_d, ALL, gen_vreplve, MO_64, 64, tcg_gen_ld_i64) +TRANS(vreplve_b, LSX, gen_vreplve, MO_8, 8, tcg_gen_ld8u_i64) +TRANS(vreplve_h, LSX, gen_vreplve, MO_16, 16, tcg_gen_ld16u_i64) +TRANS(vreplve_w, LSX, gen_vreplve, MO_32, 32, tcg_gen_ld32u_i64) +TRANS(vreplve_d, LSX, gen_vreplve, MO_64, 64, tcg_gen_ld_i64) static bool trans_vbsll_v(DisasContext *ctx, arg_vv_i *a) { int ofs; TCGv_i64 desthigh, destlow, high, low; + if (!avail_LSX(ctx)) { + return false; + } + CHECK_SXE; desthigh = tcg_temp_new_i64(); @@ -4185,6 +4317,10 @@ static bool trans_vbsrl_v(DisasContext *ctx, arg_vv_i *a) TCGv_i64 desthigh, destlow, high, low; int ofs; + if (!avail_LSX(ctx)) { + return false; + } + CHECK_SXE; desthigh = tcg_temp_new_i64(); @@ -4210,48 +4346,48 @@ static bool trans_vbsrl_v(DisasContext *ctx, arg_vv_i *a) return true; } -TRANS(vpackev_b, ALL, gen_vvv, gen_helper_vpackev_b) -TRANS(vpackev_h, ALL, gen_vvv, gen_helper_vpackev_h) -TRANS(vpackev_w, ALL, gen_vvv, gen_helper_vpackev_w) -TRANS(vpackev_d, ALL, gen_vvv, gen_helper_vpackev_d) -TRANS(vpackod_b, ALL, gen_vvv, gen_helper_vpackod_b) -TRANS(vpackod_h, ALL, gen_vvv, gen_helper_vpackod_h) -TRANS(vpackod_w, ALL, gen_vvv, gen_helper_vpackod_w) -TRANS(vpackod_d, ALL, gen_vvv, gen_helper_vpackod_d) +TRANS(vpackev_b, LSX, gen_vvv, gen_helper_vpackev_b) +TRANS(vpackev_h, LSX, gen_vvv, gen_helper_vpackev_h) +TRANS(vpackev_w, LSX, gen_vvv, gen_helper_vpackev_w) +TRANS(vpackev_d, LSX, gen_vvv, gen_helper_vpackev_d) +TRANS(vpackod_b, LSX, gen_vvv, gen_helper_vpackod_b) +TRANS(vpackod_h, LSX, gen_vvv, gen_helper_vpackod_h) +TRANS(vpackod_w, LSX, gen_vvv, gen_helper_vpackod_w) +TRANS(vpackod_d, LSX, gen_vvv, gen_helper_vpackod_d) -TRANS(vpickev_b, ALL, gen_vvv, gen_helper_vpickev_b) -TRANS(vpickev_h, ALL, gen_vvv, gen_helper_vpickev_h) -TRANS(vpickev_w, ALL, gen_vvv, gen_helper_vpickev_w) -TRANS(vpickev_d, ALL, gen_vvv, gen_helper_vpickev_d) -TRANS(vpickod_b, ALL, gen_vvv, gen_helper_vpickod_b) -TRANS(vpickod_h, ALL, gen_vvv, gen_helper_vpickod_h) -TRANS(vpickod_w, ALL, gen_vvv, gen_helper_vpickod_w) -TRANS(vpickod_d, ALL, gen_vvv, gen_helper_vpickod_d) +TRANS(vpickev_b, LSX, gen_vvv, gen_helper_vpickev_b) +TRANS(vpickev_h, LSX, gen_vvv, gen_helper_vpickev_h) +TRANS(vpickev_w, LSX, gen_vvv, gen_helper_vpickev_w) +TRANS(vpickev_d, LSX, gen_vvv, gen_helper_vpickev_d) +TRANS(vpickod_b, LSX, gen_vvv, gen_helper_vpickod_b) +TRANS(vpickod_h, LSX, gen_vvv, gen_helper_vpickod_h) +TRANS(vpickod_w, LSX, gen_vvv, gen_helper_vpickod_w) +TRANS(vpickod_d, LSX, gen_vvv, gen_helper_vpickod_d) -TRANS(vilvl_b, ALL, gen_vvv, gen_helper_vilvl_b) -TRANS(vilvl_h, ALL, gen_vvv, gen_helper_vilvl_h) -TRANS(vilvl_w, ALL, gen_vvv, gen_helper_vilvl_w) -TRANS(vilvl_d, ALL, gen_vvv, gen_helper_vilvl_d) -TRANS(vilvh_b, ALL, gen_vvv, gen_helper_vilvh_b) -TRANS(vilvh_h, ALL, gen_vvv, gen_helper_vilvh_h) -TRANS(vilvh_w, ALL, gen_vvv, gen_helper_vilvh_w) -TRANS(vilvh_d, ALL, gen_vvv, gen_helper_vilvh_d) +TRANS(vilvl_b, LSX, gen_vvv, gen_helper_vilvl_b) +TRANS(vilvl_h, LSX, gen_vvv, gen_helper_vilvl_h) +TRANS(vilvl_w, LSX, gen_vvv, gen_helper_vilvl_w) +TRANS(vilvl_d, LSX, gen_vvv, gen_helper_vilvl_d) +TRANS(vilvh_b, LSX, gen_vvv, gen_helper_vilvh_b) +TRANS(vilvh_h, LSX, gen_vvv, gen_helper_vilvh_h) +TRANS(vilvh_w, LSX, gen_vvv, gen_helper_vilvh_w) +TRANS(vilvh_d, LSX, gen_vvv, gen_helper_vilvh_d) -TRANS(vshuf_b, ALL, gen_vvvv, gen_helper_vshuf_b) -TRANS(vshuf_h, ALL, gen_vvv, gen_helper_vshuf_h) -TRANS(vshuf_w, ALL, gen_vvv, gen_helper_vshuf_w) -TRANS(vshuf_d, ALL, gen_vvv, gen_helper_vshuf_d) -TRANS(vshuf4i_b, ALL, gen_vv_i, gen_helper_vshuf4i_b) -TRANS(vshuf4i_h, ALL, gen_vv_i, gen_helper_vshuf4i_h) -TRANS(vshuf4i_w, ALL, gen_vv_i, gen_helper_vshuf4i_w) -TRANS(vshuf4i_d, ALL, gen_vv_i, gen_helper_vshuf4i_d) +TRANS(vshuf_b, LSX, gen_vvvv, gen_helper_vshuf_b) +TRANS(vshuf_h, LSX, gen_vvv, gen_helper_vshuf_h) +TRANS(vshuf_w, LSX, gen_vvv, gen_helper_vshuf_w) +TRANS(vshuf_d, LSX, gen_vvv, gen_helper_vshuf_d) +TRANS(vshuf4i_b, LSX, gen_vv_i, gen_helper_vshuf4i_b) +TRANS(vshuf4i_h, LSX, gen_vv_i, gen_helper_vshuf4i_h) +TRANS(vshuf4i_w, LSX, gen_vv_i, gen_helper_vshuf4i_w) +TRANS(vshuf4i_d, LSX, gen_vv_i, gen_helper_vshuf4i_d) -TRANS(vpermi_w, ALL, gen_vv_i, gen_helper_vpermi_w) +TRANS(vpermi_w, LSX, gen_vv_i, gen_helper_vpermi_w) -TRANS(vextrins_b, ALL, gen_vv_i, gen_helper_vextrins_b) -TRANS(vextrins_h, ALL, gen_vv_i, gen_helper_vextrins_h) -TRANS(vextrins_w, ALL, gen_vv_i, gen_helper_vextrins_w) -TRANS(vextrins_d, ALL, gen_vv_i, gen_helper_vextrins_d) +TRANS(vextrins_b, LSX, gen_vv_i, gen_helper_vextrins_b) +TRANS(vextrins_h, LSX, gen_vv_i, gen_helper_vextrins_h) +TRANS(vextrins_w, LSX, gen_vv_i, gen_helper_vextrins_w) +TRANS(vextrins_d, LSX, gen_vv_i, gen_helper_vextrins_d) static bool trans_vld(DisasContext *ctx, arg_vr_i *a) { @@ -4259,6 +4395,10 @@ static bool trans_vld(DisasContext *ctx, arg_vr_i *a) TCGv_i64 rl, rh; TCGv_i128 val; + if (!avail_LSX(ctx)) { + return false; + } + CHECK_SXE; addr = gpr_src(ctx, a->rj, EXT_NONE); @@ -4282,6 +4422,10 @@ static bool trans_vst(DisasContext *ctx, arg_vr_i *a) TCGv_i128 val; TCGv_i64 ah, al; + if (!avail_LSX(ctx)) { + return false; + } + CHECK_SXE; addr = gpr_src(ctx, a->rj, EXT_NONE); @@ -4305,6 +4449,10 @@ static bool trans_vldx(DisasContext *ctx, arg_vrr *a) TCGv_i64 rl, rh; TCGv_i128 val; + if (!avail_LSX(ctx)) { + return false; + } + CHECK_SXE; src1 = gpr_src(ctx, a->rj, EXT_NONE); @@ -4328,6 +4476,10 @@ static bool trans_vstx(DisasContext *ctx, arg_vrr *a) TCGv_i64 ah, al; TCGv_i128 val; + if (!avail_LSX(ctx)) { + return false; + } + CHECK_SXE; src1 = gpr_src(ctx, a->rj, EXT_NONE); @@ -4351,6 +4503,10 @@ static bool trans_## NAME (DisasContext *ctx, arg_vr_i *a) \ TCGv addr; \ TCGv_i64 val; \ \ + if (!avail_LSX(ctx)) { \ + return false; \ + } \ + \ CHECK_SXE; \ \ addr = gpr_src(ctx, a->rj, EXT_NONE); \ @@ -4375,6 +4531,10 @@ static bool trans_## NAME (DisasContext *ctx, arg_vr_ii *a) \ TCGv addr; \ TCGv_i64 val; \ \ + if (!avail_LSX(ctx)) { \ + return false; \ + } \ + \ CHECK_SXE; \ \ addr = gpr_src(ctx, a->rj, EXT_NONE); \ diff --git a/target/loongarch/translate.h b/target/loongarch/translate.h index faf4ce87f9..db46e9aa0f 100644 --- a/target/loongarch/translate.h +++ b/target/loongarch/translate.h @@ -22,6 +22,8 @@ #define avail_FP_DP(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, FP_DP)) #define avail_LSPW(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, LSPW)) #define avail_LAM(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, LAM)) +#define avail_LSX(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, LSX)) + /* * If an operation is being performed on less than TARGET_LONG_BITS, From a380c6f11fd9f1ca96f204c4ae26c79e483ede8a Mon Sep 17 00:00:00 2001 From: Song Gao Date: Tue, 22 Aug 2023 09:22:19 +0200 Subject: [PATCH 1194/1353] target/loongarch: Add avail_IOCSR to check iocsr instructions Signed-off-by: Song Gao Reviewed-by: Richard Henderson Message-ID: <20230822032724.1353391-16-gaosong@loongson.cn> Message-Id: <20230822072219.35719-1-philmd@linaro.org> --- .../loongarch/insn_trans/trans_privileged.c.inc | 16 ++++++++-------- target/loongarch/translate.h | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/target/loongarch/insn_trans/trans_privileged.c.inc b/target/loongarch/insn_trans/trans_privileged.c.inc index 099cd871f0..4cb701b4b5 100644 --- a/target/loongarch/insn_trans/trans_privileged.c.inc +++ b/target/loongarch/insn_trans/trans_privileged.c.inc @@ -312,14 +312,14 @@ static bool gen_iocsrwr(DisasContext *ctx, arg_rr *a, return true; } -TRANS(iocsrrd_b, ALL, gen_iocsrrd, gen_helper_iocsrrd_b) -TRANS(iocsrrd_h, ALL, gen_iocsrrd, gen_helper_iocsrrd_h) -TRANS(iocsrrd_w, ALL, gen_iocsrrd, gen_helper_iocsrrd_w) -TRANS(iocsrrd_d, ALL, gen_iocsrrd, gen_helper_iocsrrd_d) -TRANS(iocsrwr_b, ALL, gen_iocsrwr, gen_helper_iocsrwr_b) -TRANS(iocsrwr_h, ALL, gen_iocsrwr, gen_helper_iocsrwr_h) -TRANS(iocsrwr_w, ALL, gen_iocsrwr, gen_helper_iocsrwr_w) -TRANS(iocsrwr_d, ALL, gen_iocsrwr, gen_helper_iocsrwr_d) +TRANS(iocsrrd_b, IOCSR, gen_iocsrrd, gen_helper_iocsrrd_b) +TRANS(iocsrrd_h, IOCSR, gen_iocsrrd, gen_helper_iocsrrd_h) +TRANS(iocsrrd_w, IOCSR, gen_iocsrrd, gen_helper_iocsrrd_w) +TRANS(iocsrrd_d, IOCSR, gen_iocsrrd, gen_helper_iocsrrd_d) +TRANS(iocsrwr_b, IOCSR, gen_iocsrwr, gen_helper_iocsrwr_b) +TRANS(iocsrwr_h, IOCSR, gen_iocsrwr, gen_helper_iocsrwr_h) +TRANS(iocsrwr_w, IOCSR, gen_iocsrwr, gen_helper_iocsrwr_w) +TRANS(iocsrwr_d, IOCSR, gen_iocsrwr, gen_helper_iocsrwr_d) static void check_mmu_idx(DisasContext *ctx) { diff --git a/target/loongarch/translate.h b/target/loongarch/translate.h index db46e9aa0f..89b49a859e 100644 --- a/target/loongarch/translate.h +++ b/target/loongarch/translate.h @@ -23,7 +23,7 @@ #define avail_LSPW(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, LSPW)) #define avail_LAM(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, LAM)) #define avail_LSX(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, LSX)) - +#define avail_IOCSR(C) (FIELD_EX32((C)->cpucfg1, CPUCFG1, IOCSR)) /* * If an operation is being performed on less than TARGET_LONG_BITS, From 14f21f673a01cf3efa22a70256947fb9b6bbfdfa Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Thu, 24 Aug 2023 08:50:07 +0800 Subject: [PATCH 1195/1353] target/loongarch: cpu: Implement get_arch_id callback Implement the callback for getting the architecture-dependent CPU ID, the cpu ID is physical id described in ACPI MADT table, this will be used for cpu hotplug. Signed-off-by: Bibo Mao Reviewed-by: Song Gao Message-Id: <20230824005007.2000525-1-maobibo@loongson.cn> Signed-off-by: Song Gao --- hw/loongarch/virt.c | 2 ++ target/loongarch/cpu.c | 8 ++++++++ target/loongarch/cpu.h | 1 + 3 files changed, 11 insertions(+) diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c index af15bf5aaa..2629128aed 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -810,6 +810,8 @@ static void loongarch_init(MachineState *machine) cpu = cpu_create(machine->cpu_type); cpu->cpu_index = i; machine->possible_cpus->cpus[i].cpu = OBJECT(cpu); + lacpu = LOONGARCH_CPU(cpu); + lacpu->phy_id = machine->possible_cpus->cpus[i].arch_id; } fdt_add_cpu_nodes(lams); diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index d3c3e0d8a1..27fc6e1f33 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -722,6 +722,13 @@ static struct TCGCPUOps loongarch_tcg_ops = { static const struct SysemuCPUOps loongarch_sysemu_ops = { .get_phys_page_debug = loongarch_cpu_get_phys_page_debug, }; + +static int64_t loongarch_cpu_get_arch_id(CPUState *cs) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + + return cpu->phy_id; +} #endif static void loongarch_cpu_class_init(ObjectClass *c, void *data) @@ -742,6 +749,7 @@ static void loongarch_cpu_class_init(ObjectClass *c, void *data) cc->set_pc = loongarch_cpu_set_pc; cc->get_pc = loongarch_cpu_get_pc; #ifndef CONFIG_USER_ONLY + cc->get_arch_id = loongarch_cpu_get_arch_id; dc->vmsd = &vmstate_loongarch_cpu; cc->sysemu_ops = &loongarch_sysemu_ops; #endif diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h index 25a0ef7e41..4d7201995a 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -376,6 +376,7 @@ struct ArchCPU { CPUNegativeOffsetState neg; CPULoongArchState env; QEMUTimer timer; + uint32_t phy_id; /* 'compatible' string for this CPU for Linux device trees */ const char *dtb_compatible; From 2948c1fb6b8d806d92394ec358e6ed727e946df9 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Fri, 7 Jul 2023 17:15:57 +0800 Subject: [PATCH 1196/1353] hw/intc/loongarch_pch: fix edge triggered irq handling For edge triggered irq, qemu_irq_pulse is used to inject irq. It will set irq with high level and low level soon to simluate pulse irq. For edge triggered irq, irq is injected and set as pending at rising level, do not clear irq at lowering level. LoongArch pch interrupt will clear irq for lowering level irq, there will be problem. ACPI ged deivce is edge-triggered irq, it is used for cpu/memory hotplug. This patch fixes memory hotplug issue on LoongArch virt machine. Signed-off-by: Bibo Mao Reviewed-by: Song Gao Message-Id: <20230707091557.1474790-1-maobibo@loongson.cn> Signed-off-by: Song Gao --- hw/intc/loongarch_pch_pic.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c index 9208fc4460..6aa4cadfa4 100644 --- a/hw/intc/loongarch_pch_pic.c +++ b/hw/intc/loongarch_pch_pic.c @@ -30,7 +30,11 @@ static void pch_pic_update_irq(LoongArchPCHPIC *s, uint64_t mask, int level) qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 1); } } else { - val = mask & s->intisr; + /* + * intirr means requested pending irq + * do not clear pending irq for edge-triggered on lowering edge + */ + val = mask & s->intisr & ~s->intirr; if (val) { irq = ctz64(val); s->intisr &= ~MAKE_64BIT_MASK(irq, 1); @@ -51,6 +55,7 @@ static void pch_pic_irq_handler(void *opaque, int irq, int level) /* Edge triggered */ if (level) { if ((s->last_intirr & mask) == 0) { + /* marked pending on a rising edge */ s->intirr |= mask; } s->last_intirr |= mask; From 17ffe331a923c9015887917b27212ab39ff1d8ea Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Tue, 8 Aug 2023 13:42:47 +0800 Subject: [PATCH 1197/1353] target/loongarch: Split fcc register to fcc0-7 in gdbstub Since GDB 13.1(GDB commit ea3352172), GDB LoongArch changed to use fcc0-7 instead of fcc register. This commit partially reverts commit 2f149c759 (`target/loongarch: Update gdb_set_fpu() and gdb_get_fpu()`) to match the behavior of GDB. Note that it is a breaking change for GDB 13.0 or earlier, but it is also required for GDB 13.1 or later to work. Signed-off-by: Jiajie Chen Acked-by: Song Gao Message-Id: <20230808054315.3391465-1-c@jia.je> Signed-off-by: Song Gao --- gdb-xml/loongarch-fpu.xml | 9 ++++++++- target/loongarch/gdbstub.c | 16 +++++++--------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/gdb-xml/loongarch-fpu.xml b/gdb-xml/loongarch-fpu.xml index 78e42cf5dd..e81e3382e7 100644 --- a/gdb-xml/loongarch-fpu.xml +++ b/gdb-xml/loongarch-fpu.xml @@ -45,6 +45,13 @@ - + + + + + + + + diff --git a/target/loongarch/gdbstub.c b/target/loongarch/gdbstub.c index e20b20f99b..b09804b62f 100644 --- a/target/loongarch/gdbstub.c +++ b/target/loongarch/gdbstub.c @@ -88,10 +88,9 @@ static int loongarch_gdb_get_fpu(CPULoongArchState *env, { if (0 <= n && n < 32) { return gdb_get_reg64(mem_buf, env->fpr[n].vreg.D(0)); - } else if (n == 32) { - uint64_t val = read_fcc(env); - return gdb_get_reg64(mem_buf, val); - } else if (n == 33) { + } else if (32 <= n && n < 40) { + return gdb_get_reg8(mem_buf, env->cf[n - 32]); + } else if (n == 40) { return gdb_get_reg32(mem_buf, env->fcsr0); } return 0; @@ -105,11 +104,10 @@ static int loongarch_gdb_set_fpu(CPULoongArchState *env, if (0 <= n && n < 32) { env->fpr[n].vreg.D(0) = ldq_p(mem_buf); length = 8; - } else if (n == 32) { - uint64_t val = ldq_p(mem_buf); - write_fcc(env, val); - length = 8; - } else if (n == 33) { + } else if (32 <= n && n < 40) { + env->cf[n - 32] = ldub_p(mem_buf); + length = 1; + } else if (n == 40) { env->fcsr0 = ldl_p(mem_buf); length = 4; } From 3f6bec4a9f7c159d32d49f6df5c2c3d587b953b9 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Sun, 20 Aug 2023 18:56:59 +0800 Subject: [PATCH 1198/1353] hw/loongarch: Fix ACPI processor id off-by-one error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In hw/acpi/aml-build.c:build_pptt() function, the code assumes that the ACPI processor id equals to the cpu index, for example if we have 8 cpus, then the ACPI processor id should be in range 0-7. However, in hw/loongarch/acpi-build.c:build_madt() function we broke the assumption. If we have 8 cpus again, the ACPI processor id in MADT table would be in range 1-8. It violates the following description taken from ACPI spec 6.4 table 5.138: If the processor structure represents an actual processor, this field must match the value of ACPI processor ID field in the processor’s entry in the MADT. It will break the latest Linux 6.5-rc6 with the following error message: ACPI PPTT: PPTT table found, but unable to locate core 7 (8) Invalid BIOS PPTT Here 7 is the last cpu index, 8 is the ACPI processor id learned from MADT. With this patch, Linux can properly detect SMT threads when "-smp 8,sockets=1,cores=4,threads=2" is passed: Thread(s) per core: 2 Core(s) per socket: 2 Socket(s): 2 The detection of number of sockets is still wrong, but that is out of scope of the commit. Signed-off-by: Jiajie Chen Reviewed-by: Bibo Mao Message-Id: <20230820105658.99123-2-c@jia.je> Signed-off-by: Song Gao --- hw/loongarch/acpi-build.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c index 0b62c3a2f7..ae292fc543 100644 --- a/hw/loongarch/acpi-build.c +++ b/hw/loongarch/acpi-build.c @@ -127,7 +127,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, LoongArchMachineState *lams) build_append_int_noprefix(table_data, 17, 1); /* Type */ build_append_int_noprefix(table_data, 15, 1); /* Length */ build_append_int_noprefix(table_data, 1, 1); /* Version */ - build_append_int_noprefix(table_data, i + 1, 4); /* ACPI Processor ID */ + build_append_int_noprefix(table_data, i, 4); /* ACPI Processor ID */ build_append_int_noprefix(table_data, arch_id, 4); /* Core ID */ build_append_int_noprefix(table_data, 1, 4); /* Flags */ } From b67be03e3ac9d20a258f24dcaf1b61c91c1306f5 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Mon, 7 Aug 2023 17:56:58 +0200 Subject: [PATCH 1199/1353] accel/kvm: Widen pc/saved_insn for kvm_sw_breakpoint Widens the pc and saved_insn fields of kvm_sw_breakpoint from target_ulong to vaddr. The pc argument of kvm_find_sw_breakpoint is also widened to match. Signed-off-by: Anton Johansson Reviewed-by: Richard Henderson Message-Id: <20230807155706.9580-2-anjo@rev.ng> Signed-off-by: Richard Henderson --- accel/kvm/kvm-all.c | 3 +-- include/sysemu/kvm.h | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index d07f1ecbd3..2ba7521695 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -3309,8 +3309,7 @@ bool kvm_arm_supports_user_irq(void) } #ifdef KVM_CAP_SET_GUEST_DEBUG -struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *cpu, - target_ulong pc) +struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *cpu, vaddr pc) { struct kvm_sw_breakpoint *bp; diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index ccaf55caf7..407fe183cc 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -413,14 +413,14 @@ struct kvm_guest_debug; struct kvm_debug_exit_arch; struct kvm_sw_breakpoint { - target_ulong pc; - target_ulong saved_insn; + vaddr pc; + vaddr saved_insn; int use_count; QTAILQ_ENTRY(kvm_sw_breakpoint) entry; }; struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *cpu, - target_ulong pc); + vaddr pc); int kvm_sw_breakpoints_active(CPUState *cpu); From fcfe761680e2a94f64a20914c0df9462ec31b113 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Mon, 7 Aug 2023 17:56:59 +0200 Subject: [PATCH 1200/1353] accel/hvf: Widen pc/saved_insn for hvf_sw_breakpoint Widens the pc and saved_insn fields of hvf_sw_breakpoint from target_ulong to vaddr. Other hvf_* functions accessing hvf_sw_breakpoint are also widened to match. Signed-off-by: Anton Johansson Reviewed-by: Richard Henderson Message-Id: <20230807155706.9580-3-anjo@rev.ng> Signed-off-by: Richard Henderson --- accel/hvf/hvf-accel-ops.c | 4 ++-- accel/hvf/hvf-all.c | 2 +- include/sysemu/hvf.h | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/accel/hvf/hvf-accel-ops.c b/accel/hvf/hvf-accel-ops.c index a44cf1c144..3c94c79747 100644 --- a/accel/hvf/hvf-accel-ops.c +++ b/accel/hvf/hvf-accel-ops.c @@ -474,7 +474,7 @@ static void hvf_start_vcpu_thread(CPUState *cpu) cpu, QEMU_THREAD_JOINABLE); } -static int hvf_insert_breakpoint(CPUState *cpu, int type, hwaddr addr, hwaddr len) +static int hvf_insert_breakpoint(CPUState *cpu, int type, vaddr addr, vaddr len) { struct hvf_sw_breakpoint *bp; int err; @@ -512,7 +512,7 @@ static int hvf_insert_breakpoint(CPUState *cpu, int type, hwaddr addr, hwaddr le return 0; } -static int hvf_remove_breakpoint(CPUState *cpu, int type, hwaddr addr, hwaddr len) +static int hvf_remove_breakpoint(CPUState *cpu, int type, vaddr addr, vaddr len) { struct hvf_sw_breakpoint *bp; int err; diff --git a/accel/hvf/hvf-all.c b/accel/hvf/hvf-all.c index 4920787af6..db05b81be5 100644 --- a/accel/hvf/hvf-all.c +++ b/accel/hvf/hvf-all.c @@ -51,7 +51,7 @@ void assert_hvf_ok(hv_return_t ret) abort(); } -struct hvf_sw_breakpoint *hvf_find_sw_breakpoint(CPUState *cpu, target_ulong pc) +struct hvf_sw_breakpoint *hvf_find_sw_breakpoint(CPUState *cpu, vaddr pc) { struct hvf_sw_breakpoint *bp; diff --git a/include/sysemu/hvf.h b/include/sysemu/hvf.h index 70549b9158..4cbae87ced 100644 --- a/include/sysemu/hvf.h +++ b/include/sysemu/hvf.h @@ -39,14 +39,14 @@ DECLARE_INSTANCE_CHECKER(HVFState, HVF_STATE, #ifdef NEED_CPU_H struct hvf_sw_breakpoint { - target_ulong pc; - target_ulong saved_insn; + vaddr pc; + vaddr saved_insn; int use_count; QTAILQ_ENTRY(hvf_sw_breakpoint) entry; }; struct hvf_sw_breakpoint *hvf_find_sw_breakpoint(CPUState *cpu, - target_ulong pc); + vaddr pc); int hvf_sw_breakpoints_active(CPUState *cpu); int hvf_arch_insert_sw_breakpoint(CPUState *cpu, struct hvf_sw_breakpoint *bp); From b8a6eb1862a96b1c51518df2562804a39eccd97b Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Mon, 7 Aug 2023 17:57:00 +0200 Subject: [PATCH 1201/1353] sysemu/kvm: Use vaddr for kvm_arch_[insert|remove]_hw_breakpoint Changes the signature of the target-defined functions for inserting/removing kvm hw breakpoints. The address and length arguments are now of vaddr type, which both matches the type used internally in accel/kvm/kvm-all.c and makes the api target-agnostic. Signed-off-by: Anton Johansson Reviewed-by: Richard Henderson Message-Id: <20230807155706.9580-4-anjo@rev.ng> Signed-off-by: Richard Henderson --- include/sysemu/kvm.h | 6 ++---- target/arm/kvm64.c | 6 ++---- target/i386/kvm/kvm.c | 8 +++----- target/ppc/kvm.c | 13 ++++++------- target/s390x/kvm/kvm.c | 6 ++---- 5 files changed, 15 insertions(+), 24 deletions(-) diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index 407fe183cc..ebdca41052 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -428,10 +428,8 @@ int kvm_arch_insert_sw_breakpoint(CPUState *cpu, struct kvm_sw_breakpoint *bp); int kvm_arch_remove_sw_breakpoint(CPUState *cpu, struct kvm_sw_breakpoint *bp); -int kvm_arch_insert_hw_breakpoint(target_ulong addr, - target_ulong len, int type); -int kvm_arch_remove_hw_breakpoint(target_ulong addr, - target_ulong len, int type); +int kvm_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type); +int kvm_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type); void kvm_arch_remove_all_hw_breakpoints(void); void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg); diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c index 94bbd9661f..4d904a1d11 100644 --- a/target/arm/kvm64.c +++ b/target/arm/kvm64.c @@ -49,8 +49,7 @@ void kvm_arm_init_debug(KVMState *s) return; } -int kvm_arch_insert_hw_breakpoint(target_ulong addr, - target_ulong len, int type) +int kvm_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type) { switch (type) { case GDB_BREAKPOINT_HW: @@ -65,8 +64,7 @@ int kvm_arch_insert_hw_breakpoint(target_ulong addr, } } -int kvm_arch_remove_hw_breakpoint(target_ulong addr, - target_ulong len, int type) +int kvm_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type) { switch (type) { case GDB_BREAKPOINT_HW: diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index b45ce20fd8..639a242ad8 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -5000,7 +5000,7 @@ MemTxAttrs kvm_arch_post_run(CPUState *cpu, struct kvm_run *run) kvm_rate_limit_on_bus_lock(); } -#ifdef CONFIG_XEN_EMU +#ifdef CONFIG_XEN_EMU /* * If the callback is asserted as a GSI (or PCI INTx) then check if * vcpu_info->evtchn_upcall_pending has been cleared, and deassert @@ -5161,8 +5161,7 @@ static int find_hw_breakpoint(target_ulong addr, int len, int type) return -1; } -int kvm_arch_insert_hw_breakpoint(target_ulong addr, - target_ulong len, int type) +int kvm_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type) { switch (type) { case GDB_BREAKPOINT_HW: @@ -5202,8 +5201,7 @@ int kvm_arch_insert_hw_breakpoint(target_ulong addr, return 0; } -int kvm_arch_remove_hw_breakpoint(target_ulong addr, - target_ulong len, int type) +int kvm_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type) { int n; diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index dc1182cd37..7698501743 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -1449,15 +1449,15 @@ static int find_hw_watchpoint(target_ulong addr, int *flag) return -1; } -int kvm_arch_insert_hw_breakpoint(target_ulong addr, - target_ulong len, int type) +int kvm_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type) { - if ((nb_hw_breakpoint + nb_hw_watchpoint) >= ARRAY_SIZE(hw_debug_points)) { + const unsigned breakpoint_index = nb_hw_breakpoint + nb_hw_watchpoint; + if (breakpoint_index >= ARRAY_SIZE(hw_debug_points)) { return -ENOBUFS; } - hw_debug_points[nb_hw_breakpoint + nb_hw_watchpoint].addr = addr; - hw_debug_points[nb_hw_breakpoint + nb_hw_watchpoint].type = type; + hw_debug_points[breakpoint_index].addr = addr; + hw_debug_points[breakpoint_index].type = type; switch (type) { case GDB_BREAKPOINT_HW: @@ -1493,8 +1493,7 @@ int kvm_arch_insert_hw_breakpoint(target_ulong addr, return 0; } -int kvm_arch_remove_hw_breakpoint(target_ulong addr, - target_ulong len, int type) +int kvm_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type) { int n; diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c index c413eca74c..852fbd0df7 100644 --- a/target/s390x/kvm/kvm.c +++ b/target/s390x/kvm/kvm.c @@ -990,8 +990,7 @@ static int insert_hw_breakpoint(target_ulong addr, int len, int type) return 0; } -int kvm_arch_insert_hw_breakpoint(target_ulong addr, - target_ulong len, int type) +int kvm_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type) { switch (type) { case GDB_BREAKPOINT_HW: @@ -1009,8 +1008,7 @@ int kvm_arch_insert_hw_breakpoint(target_ulong addr, return insert_hw_breakpoint(addr, len, type); } -int kvm_arch_remove_hw_breakpoint(target_ulong addr, - target_ulong len, int type) +int kvm_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type) { int size; struct kvm_hw_breakpoint *bp = find_hw_breakpoint(addr, len, type); From d447a624d0cffb28836e776687a861cd27d06d2f Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Mon, 7 Aug 2023 17:57:01 +0200 Subject: [PATCH 1202/1353] sysemu/hvf: Use vaddr for hvf_arch_[insert|remove]_hw_breakpoint Changes the signature of the target-defined functions for inserting/removing hvf hw breakpoints. The address and length arguments are now of vaddr type, which both matches the type used internally in accel/hvf/hvf-all.c and makes the api target-agnostic. Signed-off-by: Anton Johansson Reviewed-by: Richard Henderson Message-Id: <20230807155706.9580-5-anjo@rev.ng> Signed-off-by: Richard Henderson --- include/sysemu/hvf.h | 6 ++---- target/arm/hvf/hvf.c | 4 ++-- target/i386/hvf/hvf.c | 4 ++-- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/include/sysemu/hvf.h b/include/sysemu/hvf.h index 4cbae87ced..4037cd6a73 100644 --- a/include/sysemu/hvf.h +++ b/include/sysemu/hvf.h @@ -51,10 +51,8 @@ int hvf_sw_breakpoints_active(CPUState *cpu); int hvf_arch_insert_sw_breakpoint(CPUState *cpu, struct hvf_sw_breakpoint *bp); int hvf_arch_remove_sw_breakpoint(CPUState *cpu, struct hvf_sw_breakpoint *bp); -int hvf_arch_insert_hw_breakpoint(target_ulong addr, target_ulong len, - int type); -int hvf_arch_remove_hw_breakpoint(target_ulong addr, target_ulong len, - int type); +int hvf_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type); +int hvf_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type); void hvf_arch_remove_all_hw_breakpoints(void); /* diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index 8fce64bbf6..486f90be1d 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -2063,7 +2063,7 @@ int hvf_arch_remove_sw_breakpoint(CPUState *cpu, struct hvf_sw_breakpoint *bp) return 0; } -int hvf_arch_insert_hw_breakpoint(target_ulong addr, target_ulong len, int type) +int hvf_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type) { switch (type) { case GDB_BREAKPOINT_HW: @@ -2077,7 +2077,7 @@ int hvf_arch_insert_hw_breakpoint(target_ulong addr, target_ulong len, int type) } } -int hvf_arch_remove_hw_breakpoint(target_ulong addr, target_ulong len, int type) +int hvf_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type) { switch (type) { case GDB_BREAKPOINT_HW: diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index b9cbcc02a8..cb2cd0b02f 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -690,12 +690,12 @@ int hvf_arch_remove_sw_breakpoint(CPUState *cpu, struct hvf_sw_breakpoint *bp) return -ENOSYS; } -int hvf_arch_insert_hw_breakpoint(target_ulong addr, target_ulong len, int type) +int hvf_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type) { return -ENOSYS; } -int hvf_arch_remove_hw_breakpoint(target_ulong addr, target_ulong len, int type) +int hvf_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type) { return -ENOSYS; } From 022b9bcedef9b6123d287345e424cc8fc8475dca Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Mon, 7 Aug 2023 17:57:02 +0200 Subject: [PATCH 1203/1353] include/exec: Replace target_ulong with abi_ptr in cpu_[st|ld]*() Changes the address type of the guest memory read/write functions from target_ulong to abi_ptr. (abi_ptr is currently typedef'd to target_ulong but that will change in a following commit.) This will reduce the coupling between accel/ and target/. Note: Function pointers that point to cpu_[st|ld]*() in target/riscv and target/rx are also updated in this commit. Signed-off-by: Anton Johansson Reviewed-by: Richard Henderson Message-Id: <20230807155706.9580-6-anjo@rev.ng> Signed-off-by: Richard Henderson --- accel/tcg/atomic_template.h | 16 ++++++++-------- accel/tcg/cputlb.c | 10 +++++----- include/exec/cpu_ldst.h | 24 ++++++++++++------------ target/riscv/vector_helper.c | 2 +- target/rx/op_helper.c | 6 +++--- 5 files changed, 29 insertions(+), 29 deletions(-) diff --git a/accel/tcg/atomic_template.h b/accel/tcg/atomic_template.h index e312acd16d..84c08b1425 100644 --- a/accel/tcg/atomic_template.h +++ b/accel/tcg/atomic_template.h @@ -69,7 +69,7 @@ # define END _le #endif -ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, +ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, abi_ptr addr, ABI_TYPE cmpv, ABI_TYPE newv, MemOpIdx oi, uintptr_t retaddr) { @@ -87,7 +87,7 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, } #if DATA_SIZE < 16 -ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val, +ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, abi_ptr addr, ABI_TYPE val, MemOpIdx oi, uintptr_t retaddr) { DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, retaddr); @@ -100,7 +100,7 @@ ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val, } #define GEN_ATOMIC_HELPER(X) \ -ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ +ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, abi_ptr addr, \ ABI_TYPE val, MemOpIdx oi, uintptr_t retaddr) \ { \ DATA_TYPE *haddr, ret; \ @@ -131,7 +131,7 @@ GEN_ATOMIC_HELPER(xor_fetch) * of CF_PARALLEL's value, we'll trace just a read and a write. */ #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \ -ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ +ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, abi_ptr addr, \ ABI_TYPE xval, MemOpIdx oi, uintptr_t retaddr) \ { \ XDATA_TYPE *haddr, cmp, old, new, val = xval; \ @@ -172,7 +172,7 @@ GEN_ATOMIC_HELPER_FN(umax_fetch, MAX, DATA_TYPE, new) # define END _be #endif -ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, +ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, abi_ptr addr, ABI_TYPE cmpv, ABI_TYPE newv, MemOpIdx oi, uintptr_t retaddr) { @@ -190,7 +190,7 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, } #if DATA_SIZE < 16 -ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val, +ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, abi_ptr addr, ABI_TYPE val, MemOpIdx oi, uintptr_t retaddr) { DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, retaddr); @@ -203,7 +203,7 @@ ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val, } #define GEN_ATOMIC_HELPER(X) \ -ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ +ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, abi_ptr addr, \ ABI_TYPE val, MemOpIdx oi, uintptr_t retaddr) \ { \ DATA_TYPE *haddr, ret; \ @@ -231,7 +231,7 @@ GEN_ATOMIC_HELPER(xor_fetch) * of CF_PARALLEL's value, we'll trace just a read and a write. */ #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \ -ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ +ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, abi_ptr addr, \ ABI_TYPE xval, MemOpIdx oi, uintptr_t retaddr) \ { \ XDATA_TYPE *haddr, ldo, ldn, old, new, val = xval; \ diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index d68fa6867c..11095c4f5f 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -3133,14 +3133,14 @@ static void plugin_store_cb(CPUArchState *env, abi_ptr addr, MemOpIdx oi) qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W); } -void cpu_stb_mmu(CPUArchState *env, target_ulong addr, uint8_t val, +void cpu_stb_mmu(CPUArchState *env, abi_ptr addr, uint8_t val, MemOpIdx oi, uintptr_t retaddr) { helper_stb_mmu(env, addr, val, oi, retaddr); plugin_store_cb(env, addr, oi); } -void cpu_stw_mmu(CPUArchState *env, target_ulong addr, uint16_t val, +void cpu_stw_mmu(CPUArchState *env, abi_ptr addr, uint16_t val, MemOpIdx oi, uintptr_t retaddr) { tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16); @@ -3148,7 +3148,7 @@ void cpu_stw_mmu(CPUArchState *env, target_ulong addr, uint16_t val, plugin_store_cb(env, addr, oi); } -void cpu_stl_mmu(CPUArchState *env, target_ulong addr, uint32_t val, +void cpu_stl_mmu(CPUArchState *env, abi_ptr addr, uint32_t val, MemOpIdx oi, uintptr_t retaddr) { tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32); @@ -3156,7 +3156,7 @@ void cpu_stl_mmu(CPUArchState *env, target_ulong addr, uint32_t val, plugin_store_cb(env, addr, oi); } -void cpu_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val, +void cpu_stq_mmu(CPUArchState *env, abi_ptr addr, uint64_t val, MemOpIdx oi, uintptr_t retaddr) { tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64); @@ -3164,7 +3164,7 @@ void cpu_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val, plugin_store_cb(env, addr, oi); } -void cpu_st16_mmu(CPUArchState *env, target_ulong addr, Int128 val, +void cpu_st16_mmu(CPUArchState *env, abi_ptr addr, Int128 val, MemOpIdx oi, uintptr_t retaddr) { tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128); diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h index 645476f0e5..da10ba1433 100644 --- a/include/exec/cpu_ldst.h +++ b/include/exec/cpu_ldst.h @@ -223,31 +223,31 @@ void cpu_stq_mmu(CPUArchState *env, abi_ptr ptr, uint64_t val, 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 @@ -293,10 +293,10 @@ 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); diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 4d06754826..bf7e0029a1 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -235,7 +235,7 @@ static inline int vext_elem_mask(void *v0, int index) } /* elements operations for load and store */ -typedef void vext_ldst_elem_fn(CPURISCVState *env, target_ulong addr, +typedef void vext_ldst_elem_fn(CPURISCVState *env, abi_ptr addr, uint32_t idx, void *vd, uintptr_t retaddr); #define GEN_VEXT_LD_ELEM(NAME, ETYPE, H, LDSUF) \ diff --git a/target/rx/op_helper.c b/target/rx/op_helper.c index dc0092ca99..691a12b2be 100644 --- a/target/rx/op_helper.c +++ b/target/rx/op_helper.c @@ -216,19 +216,19 @@ void helper_scmpu(CPURXState *env) } static uint32_t (* const cpu_ldufn[])(CPUArchState *env, - target_ulong ptr, + abi_ptr ptr, uintptr_t retaddr) = { cpu_ldub_data_ra, cpu_lduw_data_ra, cpu_ldl_data_ra, }; static uint32_t (* const cpu_ldfn[])(CPUArchState *env, - target_ulong ptr, + abi_ptr ptr, uintptr_t retaddr) = { cpu_ldub_data_ra, cpu_lduw_data_ra, cpu_ldl_data_ra, }; static void (* const cpu_stfn[])(CPUArchState *env, - target_ulong ptr, + abi_ptr ptr, uint32_t val, uintptr_t retaddr) = { cpu_stb_data_ra, cpu_stw_data_ra, cpu_stl_data_ra, From fc15bfb6a6bda8d4d01f1383579d385acae17c0f Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Mon, 7 Aug 2023 17:57:03 +0200 Subject: [PATCH 1204/1353] include/exec: typedef abi_ptr to vaddr in softmmu In system mode, abi_ptr is primarily used for representing addresses when accessing guest memory with cpu_[st|ld]*(). Widening it from target_ulong to vaddr reduces the target dependence of these functions and is step towards building accel/ once for system mode. Signed-off-by: Anton Johansson Reviewed-by: Richard Henderson Message-Id: <20230807155706.9580-7-anjo@rev.ng> Signed-off-by: Richard Henderson --- include/exec/cpu_ldst.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h index da10ba1433..f3ce4eb1d0 100644 --- a/include/exec/cpu_ldst.h +++ b/include/exec/cpu_ldst.h @@ -121,8 +121,8 @@ static inline bool guest_range_valid_untagged(abi_ulong start, abi_ulong len) h2g_nocheck(x); \ }) #else -typedef target_ulong abi_ptr; -#define TARGET_ABI_FMT_ptr TARGET_FMT_lx +typedef vaddr abi_ptr; +#define TARGET_ABI_FMT_ptr "%016" VADDR_PRIx #endif uint32_t cpu_ldub_data(CPUArchState *env, abi_ptr ptr); From c78edb563942ce80c9c6c03b07397725b006b625 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Mon, 7 Aug 2023 17:57:04 +0200 Subject: [PATCH 1205/1353] include/exec: Widen tlb_hit/tlb_hit_page() tlb_addr is changed from target_ulong to uint64_t to match the type of a CPUTLBEntry value, and the addressed is changed to vaddr. Signed-off-by: Anton Johansson Reviewed-by: Richard Henderson Message-Id: <20230807155706.9580-8-anjo@rev.ng> Signed-off-by: Richard Henderson --- include/exec/cpu-all.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 94f44f1f59..c2c62160c6 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -397,7 +397,7 @@ QEMU_BUILD_BUG_ON(TLB_FLAGS_MASK & TLB_SLOW_FLAGS_MASK); * @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)); } @@ -408,7 +408,7 @@ 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); } From d712b116385e262329e323d02de79998f18191a8 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Mon, 7 Aug 2023 17:57:05 +0200 Subject: [PATCH 1206/1353] accel/tcg: Widen address arg in tlb_compare_set() Signed-off-by: Anton Johansson Reviewed-by: Richard Henderson Message-Id: <20230807155706.9580-9-anjo@rev.ng> Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 11095c4f5f..bd2cf4b0be 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -1108,7 +1108,7 @@ static void tlb_add_large_page(CPUArchState *env, int mmu_idx, } static inline void tlb_set_compare(CPUTLBEntryFull *full, CPUTLBEntry *ent, - target_ulong address, int flags, + vaddr address, int flags, MMUAccessType access_type, bool enable) { if (enable) { From e79f81421b78c4329d54a895b96d74a88d055968 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Mon, 7 Aug 2023 17:57:06 +0200 Subject: [PATCH 1207/1353] accel/tcg: Update run_on_cpu_data static assert As we are now using vaddr for representing guest addresses, update the static assert to check that vaddr fits in the run_on_cpu_data union. Signed-off-by: Anton Johansson Reviewed-by: Richard Henderson Message-Id: <20230807155706.9580-10-anjo@rev.ng> Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index bd2cf4b0be..c643d66190 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -74,8 +74,9 @@ } while (0) /* run_on_cpu_data.target_ptr should always be big enough for a - * target_ulong even on 32 bit builds */ -QEMU_BUILD_BUG_ON(sizeof(target_ulong) > sizeof(run_on_cpu_data)); + * vaddr even on 32 bit builds + */ +QEMU_BUILD_BUG_ON(sizeof(vaddr) > sizeof(run_on_cpu_data)); /* We currently can't handle more than 16 bits in the MMUIDX bitmask. */ From 64919f710f3547e59e56089e91e4cbe0c623a6af Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 5 Aug 2023 17:36:02 -0700 Subject: [PATCH 1208/1353] target/m68k: Use tcg_gen_deposit_i32 in gen_partset_reg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/m68k/translate.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/target/m68k/translate.c b/target/m68k/translate.c index e07161d76f..d08e823b6c 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -697,19 +697,12 @@ static inline int ext_opsize(int ext, int pos) */ static void gen_partset_reg(int opsize, TCGv reg, TCGv val) { - TCGv tmp; switch (opsize) { case OS_BYTE: - tcg_gen_andi_i32(reg, reg, 0xffffff00); - tmp = tcg_temp_new(); - tcg_gen_ext8u_i32(tmp, val); - tcg_gen_or_i32(reg, reg, tmp); + tcg_gen_deposit_i32(reg, reg, val, 0, 8); break; case OS_WORD: - tcg_gen_andi_i32(reg, reg, 0xffff0000); - tmp = tcg_temp_new(); - tcg_gen_ext16u_i32(tmp, val); - tcg_gen_or_i32(reg, reg, tmp); + tcg_gen_deposit_i32(reg, reg, val, 0, 16); break; case OS_LONG: case OS_SINGLE: From 36df88c0405aafa747d3ee04c3d96f81827841f7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 13 Aug 2023 10:42:54 -0700 Subject: [PATCH 1209/1353] tcg/i386: Drop BYTEH deposits for 64-bit It is more useful to allow low-part deposits into all registers than to restrict allocation for high-byte deposits. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- tcg/i386/tcg-target-con-set.h | 2 +- tcg/i386/tcg-target-con-str.h | 1 - tcg/i386/tcg-target.c.inc | 7 +++---- tcg/i386/tcg-target.h | 4 ++-- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/tcg/i386/tcg-target-con-set.h b/tcg/i386/tcg-target-con-set.h index 5ea3a292f0..3949d49538 100644 --- a/tcg/i386/tcg-target-con-set.h +++ b/tcg/i386/tcg-target-con-set.h @@ -33,7 +33,7 @@ C_O1_I1(r, q) C_O1_I1(r, r) C_O1_I1(x, r) C_O1_I1(x, x) -C_O1_I2(Q, 0, Q) +C_O1_I2(q, 0, q) C_O1_I2(q, r, re) C_O1_I2(r, 0, ci) C_O1_I2(r, 0, r) diff --git a/tcg/i386/tcg-target-con-str.h b/tcg/i386/tcg-target-con-str.h index 24e6bcb80d..95a30e58cd 100644 --- a/tcg/i386/tcg-target-con-str.h +++ b/tcg/i386/tcg-target-con-str.h @@ -19,7 +19,6 @@ REGS('D', 1u << TCG_REG_EDI) REGS('r', ALL_GENERAL_REGS) REGS('x', ALL_VECTOR_REGS) REGS('q', ALL_BYTEL_REGS) /* regs that can be used as a byte operand */ -REGS('Q', ALL_BYTEH_REGS) /* regs with a second byte (e.g. %ah) */ REGS('L', ALL_GENERAL_REGS & ~SOFTMMU_RESERVE_REGS) /* qemu_ld/st */ REGS('s', ALL_BYTEL_REGS & ~SOFTMMU_RESERVE_REGS) /* qemu_st8_i32 data */ diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index a6b2eae995..ba40dd0f4d 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -144,7 +144,6 @@ static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot) # define TCG_REG_L1 TCG_REG_EDX #endif -#define ALL_BYTEH_REGS 0x0000000fu #if TCG_TARGET_REG_BITS == 64 # define ALL_GENERAL_REGS 0x0000ffffu # define ALL_VECTOR_REGS 0xffff0000u @@ -152,7 +151,7 @@ static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot) #else # define ALL_GENERAL_REGS 0x000000ffu # define ALL_VECTOR_REGS 0x00ff0000u -# define ALL_BYTEL_REGS ALL_BYTEH_REGS +# define ALL_BYTEL_REGS 0x0000000fu #endif #ifdef CONFIG_SOFTMMU # define SOFTMMU_RESERVE_REGS ((1 << TCG_REG_L0) | (1 << TCG_REG_L1)) @@ -2752,7 +2751,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, if (args[3] == 0 && args[4] == 8) { /* load bits 0..7 */ tcg_out_modrm(s, OPC_MOVB_EvGv | P_REXB_R | P_REXB_RM, a2, a0); - } else if (args[3] == 8 && args[4] == 8) { + } else if (TCG_TARGET_REG_BITS == 32 && args[3] == 8 && args[4] == 8) { /* load bits 8..15 */ tcg_out_modrm(s, OPC_MOVB_EvGv, a2, a0 + 4); } else if (args[3] == 0 && args[4] == 16) { @@ -3312,7 +3311,7 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) case INDEX_op_deposit_i32: case INDEX_op_deposit_i64: - return C_O1_I2(Q, 0, Q); + return C_O1_I2(q, 0, q); case INDEX_op_setcond_i32: case INDEX_op_setcond_i64: diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h index 2a2e3fffa8..30cce01ca4 100644 --- a/tcg/i386/tcg-target.h +++ b/tcg/i386/tcg-target.h @@ -227,8 +227,8 @@ typedef enum { #define TCG_TARGET_HAS_cmpsel_vec -1 #define TCG_TARGET_deposit_i32_valid(ofs, len) \ - (((ofs) == 0 && (len) == 8) || ((ofs) == 8 && (len) == 8) || \ - ((ofs) == 0 && (len) == 16)) + (((ofs) == 0 && ((len) == 8 || (len) == 16)) || \ + (TCG_TARGET_REG_BITS == 32 && (ofs) == 8 && (len) == 8)) #define TCG_TARGET_deposit_i64_valid TCG_TARGET_deposit_i32_valid /* Check for the possibility of high-byte extraction and, for 64-bit, From 8f7a840d7df92ecbf78802e54eee52e82aa55383 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 13 Aug 2023 11:03:05 -0700 Subject: [PATCH 1210/1353] tcg: Fold deposit with zero to and MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Inserting a zero into a value, or inserting a value into zero at offset 0 may be implemented with AND. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- tcg/optimize.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tcg/optimize.c b/tcg/optimize.c index d2156367a3..bbd9bb64c6 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -1279,6 +1279,8 @@ static bool fold_ctpop(OptContext *ctx, TCGOp *op) static bool fold_deposit(OptContext *ctx, TCGOp *op) { + TCGOpcode and_opc; + if (arg_is_const(op->args[1]) && arg_is_const(op->args[2])) { uint64_t t1 = arg_info(op->args[1])->val; uint64_t t2 = arg_info(op->args[2])->val; @@ -1287,6 +1289,41 @@ static bool fold_deposit(OptContext *ctx, TCGOp *op) return tcg_opt_gen_movi(ctx, op, op->args[0], t1); } + switch (ctx->type) { + case TCG_TYPE_I32: + and_opc = INDEX_op_and_i32; + break; + case TCG_TYPE_I64: + and_opc = INDEX_op_and_i64; + break; + default: + g_assert_not_reached(); + } + + /* Inserting a value into zero at offset 0. */ + if (arg_is_const(op->args[1]) + && arg_info(op->args[1])->val == 0 + && op->args[3] == 0) { + uint64_t mask = MAKE_64BIT_MASK(0, op->args[4]); + + op->opc = and_opc; + op->args[1] = op->args[2]; + op->args[2] = temp_arg(tcg_constant_internal(ctx->type, mask)); + ctx->z_mask = mask & arg_info(op->args[1])->z_mask; + return false; + } + + /* Inserting zero into a value. */ + if (arg_is_const(op->args[2]) + && arg_info(op->args[2])->val == 0) { + uint64_t mask = deposit64(-1, op->args[3], op->args[4], 0); + + op->opc = and_opc; + op->args[2] = temp_arg(tcg_constant_internal(ctx->type, mask)); + ctx->z_mask = mask & arg_info(op->args[1])->z_mask; + return false; + } + ctx->z_mask = deposit64(arg_info(op->args[1])->z_mask, op->args[3], op->args[4], arg_info(op->args[2])->z_mask); From 73f97f0aa34c1da9946b399ae92e7b65c51627b1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 13 Aug 2023 11:49:27 -0700 Subject: [PATCH 1211/1353] tcg/i386: Allow immediate as input to deposit_* We can use MOVB and MOVW with an immediate just as easily as with a register input. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- tcg/i386/tcg-target-con-set.h | 2 +- tcg/i386/tcg-target.c.inc | 26 ++++++++++++++++++++++---- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/tcg/i386/tcg-target-con-set.h b/tcg/i386/tcg-target-con-set.h index 3949d49538..7d00a7dde8 100644 --- a/tcg/i386/tcg-target-con-set.h +++ b/tcg/i386/tcg-target-con-set.h @@ -33,7 +33,7 @@ C_O1_I1(r, q) C_O1_I1(r, r) C_O1_I1(x, r) C_O1_I1(x, x) -C_O1_I2(q, 0, q) +C_O1_I2(q, 0, qi) C_O1_I2(q, r, re) C_O1_I2(r, 0, ci) C_O1_I2(r, 0, r) diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index ba40dd0f4d..3045b56002 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -276,6 +276,7 @@ static bool tcg_target_const_match(int64_t val, TCGType type, int ct) #define OPC_MOVL_GvEv (0x8b) /* loads, more or less */ #define OPC_MOVB_EvIz (0xc6) #define OPC_MOVL_EvIz (0xc7) +#define OPC_MOVB_Ib (0xb0) #define OPC_MOVL_Iv (0xb8) #define OPC_MOVBE_GyMy (0xf0 | P_EXT38) #define OPC_MOVBE_MyGy (0xf1 | P_EXT38) @@ -2750,13 +2751,30 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, OP_32_64(deposit): if (args[3] == 0 && args[4] == 8) { /* load bits 0..7 */ - tcg_out_modrm(s, OPC_MOVB_EvGv | P_REXB_R | P_REXB_RM, a2, a0); + if (const_a2) { + tcg_out_opc(s, OPC_MOVB_Ib | P_REXB_RM | LOWREGMASK(a0), + 0, a0, 0); + tcg_out8(s, a2); + } else { + tcg_out_modrm(s, OPC_MOVB_EvGv | P_REXB_R | P_REXB_RM, a2, a0); + } } else if (TCG_TARGET_REG_BITS == 32 && args[3] == 8 && args[4] == 8) { /* load bits 8..15 */ - tcg_out_modrm(s, OPC_MOVB_EvGv, a2, a0 + 4); + if (const_a2) { + tcg_out8(s, OPC_MOVB_Ib + a0 + 4); + tcg_out8(s, a2); + } else { + tcg_out_modrm(s, OPC_MOVB_EvGv, a2, a0 + 4); + } } else if (args[3] == 0 && args[4] == 16) { /* load bits 0..15 */ - tcg_out_modrm(s, OPC_MOVL_EvGv | P_DATA16, a2, a0); + if (const_a2) { + tcg_out_opc(s, OPC_MOVL_Iv | P_DATA16 | LOWREGMASK(a0), + 0, a0, 0); + tcg_out16(s, a2); + } else { + tcg_out_modrm(s, OPC_MOVL_EvGv | P_DATA16, a2, a0); + } } else { g_assert_not_reached(); } @@ -3311,7 +3329,7 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) case INDEX_op_deposit_i32: case INDEX_op_deposit_i64: - return C_O1_I2(q, 0, q); + return C_O1_I2(q, 0, qi); case INDEX_op_setcond_i32: case INDEX_op_setcond_i64: From bb9d7ee83e7279d71dae5dfba4d149abbf2c3b59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 22 Aug 2023 18:28:47 +0200 Subject: [PATCH 1212/1353] docs/devel/tcg-ops: Bury mentions of trunc_shr_i64_i32() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 609ad70562 ("tcg: Split trunc_shr_i32 opcode into extr[lh]_i64_i32") remove trunc_shr_i64_i32(). Update the backend documentation. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20230822162847.71206-1-philmd@linaro.org> Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index 6a166c5665..53695e1623 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -882,14 +882,15 @@ sub2_i32, brcond2_i32). On a 64 bit target, the values are transferred between 32 and 64-bit registers using the following ops: -- trunc_shr_i64_i32 +- extrl_i64_i32 +- extrh_i64_i32 - ext_i32_i64 - extu_i32_i64 They ensure that the values are correctly truncated or extended when moved from a 32-bit to a 64-bit register or vice-versa. Note that the -trunc_shr_i64_i32 is an optional op. It is not necessary to implement -it if all the following conditions are met: +extrl_i64_i32 and extrh_i64_i32 are optional ops. It is not necessary +to implement them if all the following conditions are met: - 64-bit registers can hold 32-bit values - 32-bit values in a 64-bit register do not need to stay zero or From 13d885b0ad4ada4d216b0341de5ae4a9ce3f5abb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 22 Aug 2023 10:51:10 -0700 Subject: [PATCH 1213/1353] tcg: Unify TCG_TARGET_HAS_extr[lh]_i64_i32 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the separate defines with TCG_TARGET_HAS_extr_i64_i32, so that the two parts of backend-specific type changing cannot be out of sync. Reported-by: Philippe Mathieu-Daudé Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson Message-id: <20230822175127.1173698-1-richard.henderson@linaro.org> --- include/tcg/tcg-opc.h | 4 ++-- include/tcg/tcg.h | 3 +-- tcg/aarch64/tcg-target.h | 3 +-- tcg/i386/tcg-target.h | 3 +-- tcg/loongarch64/tcg-target.h | 3 +-- tcg/mips/tcg-target.h | 3 +-- tcg/ppc/tcg-target.h | 3 +-- tcg/riscv/tcg-target.h | 3 +-- tcg/s390x/tcg-target.h | 3 +-- tcg/sparc64/tcg-target.h | 3 +-- tcg/tcg-op.c | 4 ++-- tcg/tcg.c | 3 +-- tcg/tci/tcg-target.h | 3 +-- 13 files changed, 15 insertions(+), 26 deletions(-) diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index acfa5ba753..c64dfe558c 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -152,10 +152,10 @@ DEF(extract2_i64, 1, 2, 1, IMPL64 | IMPL(TCG_TARGET_HAS_extract2_i64)) DEF(ext_i32_i64, 1, 1, 0, IMPL64) DEF(extu_i32_i64, 1, 1, 0, IMPL64) DEF(extrl_i64_i32, 1, 1, 0, - IMPL(TCG_TARGET_HAS_extrl_i64_i32) + IMPL(TCG_TARGET_HAS_extr_i64_i32) | (TCG_TARGET_REG_BITS == 32 ? TCG_OPF_NOT_PRESENT : 0)) DEF(extrh_i64_i32, 1, 1, 0, - IMPL(TCG_TARGET_HAS_extrh_i64_i32) + IMPL(TCG_TARGET_HAS_extr_i64_i32) | (TCG_TARGET_REG_BITS == 32 ? TCG_OPF_NOT_PRESENT : 0)) DEF(brcond_i64, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_COND_BRANCH | IMPL64) diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index 0875971719..ea7e55eeb8 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -68,8 +68,7 @@ typedef uint64_t TCGRegSet; #if TCG_TARGET_REG_BITS == 32 /* Turn some undef macros into false macros. */ -#define TCG_TARGET_HAS_extrl_i64_i32 0 -#define TCG_TARGET_HAS_extrh_i64_i32 0 +#define TCG_TARGET_HAS_extr_i64_i32 0 #define TCG_TARGET_HAS_div_i64 0 #define TCG_TARGET_HAS_rem_i64 0 #define TCG_TARGET_HAS_div2_i64 0 diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h index ce64de06e5..12765cc281 100644 --- a/tcg/aarch64/tcg-target.h +++ b/tcg/aarch64/tcg-target.h @@ -92,8 +92,7 @@ typedef enum { #define TCG_TARGET_HAS_muls2_i32 0 #define TCG_TARGET_HAS_muluh_i32 0 #define TCG_TARGET_HAS_mulsh_i32 0 -#define TCG_TARGET_HAS_extrl_i64_i32 0 -#define TCG_TARGET_HAS_extrh_i64_i32 0 +#define TCG_TARGET_HAS_extr_i64_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_div_i64 1 diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h index 30cce01ca4..32dd795259 100644 --- a/tcg/i386/tcg-target.h +++ b/tcg/i386/tcg-target.h @@ -159,8 +159,7 @@ typedef enum { #if TCG_TARGET_REG_BITS == 64 /* Keep 32-bit values zero-extended in a register. */ -#define TCG_TARGET_HAS_extrl_i64_i32 1 -#define TCG_TARGET_HAS_extrh_i64_i32 1 +#define TCG_TARGET_HAS_extr_i64_i32 1 #define TCG_TARGET_HAS_div2_i64 1 #define TCG_TARGET_HAS_rot_i64 1 #define TCG_TARGET_HAS_ext8s_i64 1 diff --git a/tcg/loongarch64/tcg-target.h b/tcg/loongarch64/tcg-target.h index 26f1aab780..c94e0c6044 100644 --- a/tcg/loongarch64/tcg-target.h +++ b/tcg/loongarch64/tcg-target.h @@ -130,8 +130,7 @@ typedef enum { #define TCG_TARGET_HAS_extract_i64 1 #define TCG_TARGET_HAS_sextract_i64 0 #define TCG_TARGET_HAS_extract2_i64 0 -#define TCG_TARGET_HAS_extrl_i64_i32 1 -#define TCG_TARGET_HAS_extrh_i64_i32 1 +#define TCG_TARGET_HAS_extr_i64_i32 1 #define TCG_TARGET_HAS_ext8s_i64 1 #define TCG_TARGET_HAS_ext16s_i64 1 #define TCG_TARGET_HAS_ext32s_i64 1 diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h index dd2efa795c..bdfa25bef4 100644 --- a/tcg/mips/tcg-target.h +++ b/tcg/mips/tcg-target.h @@ -132,8 +132,7 @@ extern bool use_mips32r2_instructions; #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_add2_i32 0 #define TCG_TARGET_HAS_sub2_i32 0 -#define TCG_TARGET_HAS_extrl_i64_i32 1 -#define TCG_TARGET_HAS_extrh_i64_i32 1 +#define TCG_TARGET_HAS_extr_i64_i32 1 #define TCG_TARGET_HAS_div_i64 1 #define TCG_TARGET_HAS_rem_i64 1 #define TCG_TARGET_HAS_not_i64 1 diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h index 9a41fab8cc..37b54e6aeb 100644 --- a/tcg/ppc/tcg-target.h +++ b/tcg/ppc/tcg-target.h @@ -106,8 +106,7 @@ typedef enum { #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_add2_i32 0 #define TCG_TARGET_HAS_sub2_i32 0 -#define TCG_TARGET_HAS_extrl_i64_i32 0 -#define TCG_TARGET_HAS_extrh_i64_i32 0 +#define TCG_TARGET_HAS_extr_i64_i32 0 #define TCG_TARGET_HAS_div_i64 1 #define TCG_TARGET_HAS_rem_i64 have_isa_3_00 #define TCG_TARGET_HAS_rot_i64 1 diff --git a/tcg/riscv/tcg-target.h b/tcg/riscv/tcg-target.h index e1d8110ee4..6cbd226ca9 100644 --- a/tcg/riscv/tcg-target.h +++ b/tcg/riscv/tcg-target.h @@ -131,8 +131,7 @@ extern bool have_zbb; #define TCG_TARGET_HAS_extract_i64 0 #define TCG_TARGET_HAS_sextract_i64 0 #define TCG_TARGET_HAS_extract2_i64 0 -#define TCG_TARGET_HAS_extrl_i64_i32 1 -#define TCG_TARGET_HAS_extrh_i64_i32 1 +#define TCG_TARGET_HAS_extr_i64_i32 1 #define TCG_TARGET_HAS_ext8s_i64 1 #define TCG_TARGET_HAS_ext16s_i64 1 #define TCG_TARGET_HAS_ext32s_i64 1 diff --git a/tcg/s390x/tcg-target.h b/tcg/s390x/tcg-target.h index 9a405003b9..2edc2056ba 100644 --- a/tcg/s390x/tcg-target.h +++ b/tcg/s390x/tcg-target.h @@ -102,8 +102,7 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_muls2_i32 0 #define TCG_TARGET_HAS_muluh_i32 0 #define TCG_TARGET_HAS_mulsh_i32 0 -#define TCG_TARGET_HAS_extrl_i64_i32 0 -#define TCG_TARGET_HAS_extrh_i64_i32 0 +#define TCG_TARGET_HAS_extr_i64_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_div2_i64 1 diff --git a/tcg/sparc64/tcg-target.h b/tcg/sparc64/tcg-target.h index d454278811..682e6f1613 100644 --- a/tcg/sparc64/tcg-target.h +++ b/tcg/sparc64/tcg-target.h @@ -114,8 +114,7 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_mulsh_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 -#define TCG_TARGET_HAS_extrl_i64_i32 1 -#define TCG_TARGET_HAS_extrh_i64_i32 1 +#define TCG_TARGET_HAS_extr_i64_i32 1 #define TCG_TARGET_HAS_div_i64 1 #define TCG_TARGET_HAS_rem_i64 0 #define TCG_TARGET_HAS_rot_i64 0 diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 7aadb37756..68b93a3d4b 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -2681,7 +2681,7 @@ void tcg_gen_extrl_i64_i32(TCGv_i32 ret, TCGv_i64 arg) { if (TCG_TARGET_REG_BITS == 32) { tcg_gen_mov_i32(ret, TCGV_LOW(arg)); - } else if (TCG_TARGET_HAS_extrl_i64_i32) { + } else if (TCG_TARGET_HAS_extr_i64_i32) { tcg_gen_op2(INDEX_op_extrl_i64_i32, tcgv_i32_arg(ret), tcgv_i64_arg(arg)); } else { @@ -2693,7 +2693,7 @@ void tcg_gen_extrh_i64_i32(TCGv_i32 ret, TCGv_i64 arg) { if (TCG_TARGET_REG_BITS == 32) { tcg_gen_mov_i32(ret, TCGV_HIGH(arg)); - } else if (TCG_TARGET_HAS_extrh_i64_i32) { + } else if (TCG_TARGET_HAS_extr_i64_i32) { tcg_gen_op2(INDEX_op_extrh_i64_i32, tcgv_i32_arg(ret), tcgv_i64_arg(arg)); } else { diff --git a/tcg/tcg.c b/tcg/tcg.c index ddfe9a96cb..a23348824b 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -2000,9 +2000,8 @@ bool tcg_op_supported(TCGOpcode op) case INDEX_op_extract2_i64: return TCG_TARGET_HAS_extract2_i64; case INDEX_op_extrl_i64_i32: - return TCG_TARGET_HAS_extrl_i64_i32; case INDEX_op_extrh_i64_i32: - return TCG_TARGET_HAS_extrh_i64_i32; + return TCG_TARGET_HAS_extr_i64_i32; case INDEX_op_ext8s_i64: return TCG_TARGET_HAS_ext8s_i64; case INDEX_op_ext16s_i64: diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h index 37ee10c959..d33185fb36 100644 --- a/tcg/tci/tcg-target.h +++ b/tcg/tci/tcg-target.h @@ -76,8 +76,7 @@ #define TCG_TARGET_HAS_qemu_st8_i32 0 #if TCG_TARGET_REG_BITS == 64 -#define TCG_TARGET_HAS_extrl_i64_i32 0 -#define TCG_TARGET_HAS_extrh_i64_i32 0 +#define TCG_TARGET_HAS_extr_i64_i32 0 #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 From 3635502dd00bcfee3a6ab790d950c2fc4ace607b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 4 Aug 2023 23:24:04 +0000 Subject: [PATCH 1214/1353] tcg: Introduce negsetcond opcodes Introduce a new opcode for negative setcond. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 6 ++++++ include/tcg/tcg-op-common.h | 4 ++++ include/tcg/tcg-op.h | 2 ++ include/tcg/tcg-opc.h | 2 ++ include/tcg/tcg.h | 1 + tcg/aarch64/tcg-target.h | 2 ++ tcg/arm/tcg-target.h | 1 + tcg/i386/tcg-target.h | 2 ++ tcg/loongarch64/tcg-target.h | 3 +++ tcg/mips/tcg-target.h | 2 ++ tcg/optimize.c | 41 +++++++++++++++++++++++++++++++++++- tcg/ppc/tcg-target.h | 2 ++ tcg/riscv/tcg-target.h | 2 ++ tcg/s390x/tcg-target.h | 2 ++ tcg/sparc64/tcg-target.h | 2 ++ tcg/tcg-op.c | 36 +++++++++++++++++++++++++++++++ tcg/tcg.c | 6 ++++++ tcg/tci/tcg-target.h | 2 ++ 18 files changed, 117 insertions(+), 1 deletion(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index 53695e1623..9e2a931d85 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -498,6 +498,12 @@ Conditional moves | | Set *dest* to 1 if (*t1* *cond* *t2*) is true, otherwise set to 0. + * - negsetcond_i32/i64 *dest*, *t1*, *t2*, *cond* + + - | *dest* = -(*t1* *cond* *t2*) + | + | Set *dest* to -1 if (*t1* *cond* *t2*) is true, otherwise set to 0. + * - movcond_i32/i64 *dest*, *c1*, *c2*, *v1*, *v2*, *cond* - | *dest* = (*c1* *cond* *c2* ? *v1* : *v2*) diff --git a/include/tcg/tcg-op-common.h b/include/tcg/tcg-op-common.h index be382bbf77..a53b15933b 100644 --- a/include/tcg/tcg-op-common.h +++ b/include/tcg/tcg-op-common.h @@ -344,6 +344,8 @@ void tcg_gen_setcond_i32(TCGCond cond, TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2); void tcg_gen_setcondi_i32(TCGCond cond, TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2); +void tcg_gen_negsetcond_i32(TCGCond cond, TCGv_i32 ret, + TCGv_i32 arg1, TCGv_i32 arg2); void tcg_gen_movcond_i32(TCGCond cond, TCGv_i32 ret, TCGv_i32 c1, TCGv_i32 c2, TCGv_i32 v1, TCGv_i32 v2); void tcg_gen_add2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 al, @@ -540,6 +542,8 @@ void tcg_gen_setcond_i64(TCGCond cond, TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2); void tcg_gen_setcondi_i64(TCGCond cond, TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2); +void tcg_gen_negsetcond_i64(TCGCond cond, TCGv_i64 ret, + TCGv_i64 arg1, TCGv_i64 arg2); void tcg_gen_movcond_i64(TCGCond cond, TCGv_i64 ret, TCGv_i64 c1, TCGv_i64 c2, TCGv_i64 v1, TCGv_i64 v2); void tcg_gen_add2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 al, diff --git a/include/tcg/tcg-op.h b/include/tcg/tcg-op.h index d63683c47b..80cfcf8104 100644 --- a/include/tcg/tcg-op.h +++ b/include/tcg/tcg-op.h @@ -200,6 +200,7 @@ DEF_ATOMIC2(tcg_gen_atomic_umax_fetch, i64) #define tcg_gen_brcondi_tl tcg_gen_brcondi_i64 #define tcg_gen_setcond_tl tcg_gen_setcond_i64 #define tcg_gen_setcondi_tl tcg_gen_setcondi_i64 +#define tcg_gen_negsetcond_tl tcg_gen_negsetcond_i64 #define tcg_gen_mul_tl tcg_gen_mul_i64 #define tcg_gen_muli_tl tcg_gen_muli_i64 #define tcg_gen_div_tl tcg_gen_div_i64 @@ -317,6 +318,7 @@ DEF_ATOMIC2(tcg_gen_atomic_umax_fetch, i64) #define tcg_gen_brcondi_tl tcg_gen_brcondi_i32 #define tcg_gen_setcond_tl tcg_gen_setcond_i32 #define tcg_gen_setcondi_tl tcg_gen_setcondi_i32 +#define tcg_gen_negsetcond_tl tcg_gen_negsetcond_i32 #define tcg_gen_mul_tl tcg_gen_mul_i32 #define tcg_gen_muli_tl tcg_gen_muli_i32 #define tcg_gen_div_tl tcg_gen_div_i32 diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index c64dfe558c..6eff3d9106 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -46,6 +46,7 @@ DEF(mb, 0, 0, 1, 0) DEF(mov_i32, 1, 1, 0, TCG_OPF_NOT_PRESENT) DEF(setcond_i32, 1, 2, 1, 0) +DEF(negsetcond_i32, 1, 2, 1, IMPL(TCG_TARGET_HAS_negsetcond_i32)) DEF(movcond_i32, 1, 4, 1, IMPL(TCG_TARGET_HAS_movcond_i32)) /* load/store */ DEF(ld8u_i32, 1, 1, 1, 0) @@ -111,6 +112,7 @@ DEF(ctpop_i32, 1, 1, 0, IMPL(TCG_TARGET_HAS_ctpop_i32)) DEF(mov_i64, 1, 1, 0, TCG_OPF_64BIT | TCG_OPF_NOT_PRESENT) DEF(setcond_i64, 1, 2, 1, IMPL64) +DEF(negsetcond_i64, 1, 2, 1, IMPL64 | IMPL(TCG_TARGET_HAS_negsetcond_i64)) DEF(movcond_i64, 1, 4, 1, IMPL64 | IMPL(TCG_TARGET_HAS_movcond_i64)) /* load/store */ DEF(ld8u_i64, 1, 1, 1, IMPL64) diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index ea7e55eeb8..61d7c81b44 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -97,6 +97,7 @@ typedef uint64_t TCGRegSet; #define TCG_TARGET_HAS_sextract_i64 0 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_movcond_i64 0 +#define TCG_TARGET_HAS_negsetcond_i64 0 #define TCG_TARGET_HAS_add2_i64 0 #define TCG_TARGET_HAS_sub2_i64 0 #define TCG_TARGET_HAS_mulu2_i64 0 diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h index 12765cc281..bfa3e5aae9 100644 --- a/tcg/aarch64/tcg-target.h +++ b/tcg/aarch64/tcg-target.h @@ -86,6 +86,7 @@ typedef enum { #define TCG_TARGET_HAS_sextract_i32 1 #define TCG_TARGET_HAS_extract2_i32 1 #define TCG_TARGET_HAS_movcond_i32 1 +#define TCG_TARGET_HAS_negsetcond_i32 0 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_mulu2_i32 0 @@ -122,6 +123,7 @@ typedef enum { #define TCG_TARGET_HAS_sextract_i64 1 #define TCG_TARGET_HAS_extract2_i64 1 #define TCG_TARGET_HAS_movcond_i64 1 +#define TCG_TARGET_HAS_negsetcond_i64 0 #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 #define TCG_TARGET_HAS_mulu2_i64 0 diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h index c649db72a6..ad66f11574 100644 --- a/tcg/arm/tcg-target.h +++ b/tcg/arm/tcg-target.h @@ -116,6 +116,7 @@ extern bool use_neon_instructions; #define TCG_TARGET_HAS_sextract_i32 use_armv7_instructions #define TCG_TARGET_HAS_extract2_i32 1 #define TCG_TARGET_HAS_movcond_i32 1 +#define TCG_TARGET_HAS_negsetcond_i32 0 #define TCG_TARGET_HAS_mulu2_i32 1 #define TCG_TARGET_HAS_muls2_i32 1 #define TCG_TARGET_HAS_muluh_i32 0 diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h index 32dd795259..ebc0b1a6ce 100644 --- a/tcg/i386/tcg-target.h +++ b/tcg/i386/tcg-target.h @@ -150,6 +150,7 @@ typedef enum { #define TCG_TARGET_HAS_sextract_i32 1 #define TCG_TARGET_HAS_extract2_i32 1 #define TCG_TARGET_HAS_movcond_i32 1 +#define TCG_TARGET_HAS_negsetcond_i32 0 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_mulu2_i32 1 @@ -186,6 +187,7 @@ typedef enum { #define TCG_TARGET_HAS_sextract_i64 0 #define TCG_TARGET_HAS_extract2_i64 1 #define TCG_TARGET_HAS_movcond_i64 1 +#define TCG_TARGET_HAS_negsetcond_i64 0 #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 #define TCG_TARGET_HAS_mulu2_i64 1 diff --git a/tcg/loongarch64/tcg-target.h b/tcg/loongarch64/tcg-target.h index c94e0c6044..559be67186 100644 --- a/tcg/loongarch64/tcg-target.h +++ b/tcg/loongarch64/tcg-target.h @@ -86,6 +86,7 @@ typedef enum { /* optional instructions */ #define TCG_TARGET_HAS_movcond_i32 1 +#define TCG_TARGET_HAS_negsetcond_i32 0 #define TCG_TARGET_HAS_div_i32 1 #define TCG_TARGET_HAS_rem_i32 1 #define TCG_TARGET_HAS_div2_i32 0 @@ -122,6 +123,7 @@ typedef enum { /* 64-bit operations */ #define TCG_TARGET_HAS_movcond_i64 1 +#define TCG_TARGET_HAS_negsetcond_i64 0 #define TCG_TARGET_HAS_div_i64 1 #define TCG_TARGET_HAS_rem_i64 1 #define TCG_TARGET_HAS_div2_i64 0 @@ -156,6 +158,7 @@ typedef enum { #define TCG_TARGET_HAS_muls2_i64 0 #define TCG_TARGET_HAS_muluh_i64 1 #define TCG_TARGET_HAS_mulsh_i64 1 + #define TCG_TARGET_HAS_qemu_ldst_i128 0 #define TCG_TARGET_DEFAULT_MO (0) diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h index bdfa25bef4..c0576f66d7 100644 --- a/tcg/mips/tcg-target.h +++ b/tcg/mips/tcg-target.h @@ -128,6 +128,7 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_HAS_muluh_i32 1 #define TCG_TARGET_HAS_mulsh_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 +#define TCG_TARGET_HAS_negsetcond_i32 0 #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_add2_i32 0 @@ -149,6 +150,7 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_HAS_mulsh_i64 1 #define TCG_TARGET_HAS_ext32s_i64 1 #define TCG_TARGET_HAS_ext32u_i64 1 +#define TCG_TARGET_HAS_negsetcond_i64 0 #endif /* optional instructions detected at runtime */ diff --git a/tcg/optimize.c b/tcg/optimize.c index bbd9bb64c6..3013eb04e6 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -1567,14 +1567,22 @@ static bool fold_movcond(OptContext *ctx, TCGOp *op) if (arg_is_const(op->args[3]) && arg_is_const(op->args[4])) { uint64_t tv = arg_info(op->args[3])->val; uint64_t fv = arg_info(op->args[4])->val; - TCGOpcode opc; + TCGOpcode opc, negopc = 0; switch (ctx->type) { case TCG_TYPE_I32: opc = INDEX_op_setcond_i32; + if (TCG_TARGET_HAS_negsetcond_i32) { + negopc = INDEX_op_negsetcond_i32; + } + tv = (int32_t)tv; + fv = (int32_t)fv; break; case TCG_TYPE_I64: opc = INDEX_op_setcond_i64; + if (TCG_TARGET_HAS_negsetcond_i64) { + negopc = INDEX_op_negsetcond_i64; + } break; default: g_assert_not_reached(); @@ -1586,6 +1594,14 @@ static bool fold_movcond(OptContext *ctx, TCGOp *op) } else if (fv == 1 && tv == 0) { op->opc = opc; op->args[3] = tcg_invert_cond(cond); + } else if (negopc) { + if (tv == -1 && fv == 0) { + op->opc = negopc; + op->args[3] = cond; + } else if (fv == -1 && tv == 0) { + op->opc = negopc; + op->args[3] = tcg_invert_cond(cond); + } } } return false; @@ -1796,6 +1812,26 @@ static bool fold_setcond(OptContext *ctx, TCGOp *op) return false; } +static bool fold_negsetcond(OptContext *ctx, TCGOp *op) +{ + TCGCond cond = op->args[3]; + int i; + + if (swap_commutative(op->args[0], &op->args[1], &op->args[2])) { + op->args[3] = cond = tcg_swap_cond(cond); + } + + i = do_constant_folding_cond(ctx->type, op->args[1], op->args[2], cond); + if (i >= 0) { + return tcg_opt_gen_movi(ctx, op, op->args[0], -i); + } + + /* Value is {0,-1} so all bits are repetitions of the sign. */ + ctx->s_mask = -1; + return false; +} + + static bool fold_setcond2(OptContext *ctx, TCGOp *op) { TCGCond cond = op->args[5]; @@ -2253,6 +2289,9 @@ void tcg_optimize(TCGContext *s) CASE_OP_32_64(setcond): done = fold_setcond(&ctx, op); break; + CASE_OP_32_64(negsetcond): + done = fold_negsetcond(&ctx, op); + break; case INDEX_op_setcond2_i32: done = fold_setcond2(&ctx, op); break; diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h index 37b54e6aeb..a2ca0b44ce 100644 --- a/tcg/ppc/tcg-target.h +++ b/tcg/ppc/tcg-target.h @@ -97,6 +97,7 @@ typedef enum { #define TCG_TARGET_HAS_sextract_i32 0 #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_movcond_i32 1 +#define TCG_TARGET_HAS_negsetcond_i32 0 #define TCG_TARGET_HAS_mulu2_i32 0 #define TCG_TARGET_HAS_muls2_i32 0 #define TCG_TARGET_HAS_muluh_i32 1 @@ -134,6 +135,7 @@ typedef enum { #define TCG_TARGET_HAS_sextract_i64 0 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_movcond_i64 1 +#define TCG_TARGET_HAS_negsetcond_i64 0 #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 #define TCG_TARGET_HAS_mulu2_i64 0 diff --git a/tcg/riscv/tcg-target.h b/tcg/riscv/tcg-target.h index 6cbd226ca9..0efb3fc0b8 100644 --- a/tcg/riscv/tcg-target.h +++ b/tcg/riscv/tcg-target.h @@ -88,6 +88,7 @@ extern bool have_zbb; /* optional instructions */ #define TCG_TARGET_HAS_movcond_i32 1 +#define TCG_TARGET_HAS_negsetcond_i32 0 #define TCG_TARGET_HAS_div_i32 1 #define TCG_TARGET_HAS_rem_i32 1 #define TCG_TARGET_HAS_div2_i32 0 @@ -123,6 +124,7 @@ extern bool have_zbb; #define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_movcond_i64 1 +#define TCG_TARGET_HAS_negsetcond_i64 0 #define TCG_TARGET_HAS_div_i64 1 #define TCG_TARGET_HAS_rem_i64 1 #define TCG_TARGET_HAS_div2_i64 0 diff --git a/tcg/s390x/tcg-target.h b/tcg/s390x/tcg-target.h index 2edc2056ba..123a4b1645 100644 --- a/tcg/s390x/tcg-target.h +++ b/tcg/s390x/tcg-target.h @@ -96,6 +96,7 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_sextract_i32 0 #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_movcond_i32 1 +#define TCG_TARGET_HAS_negsetcond_i32 0 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_mulu2_i32 0 @@ -131,6 +132,7 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_sextract_i64 0 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_movcond_i64 1 +#define TCG_TARGET_HAS_negsetcond_i64 0 #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 #define TCG_TARGET_HAS_mulu2_i64 1 diff --git a/tcg/sparc64/tcg-target.h b/tcg/sparc64/tcg-target.h index 682e6f1613..79889db760 100644 --- a/tcg/sparc64/tcg-target.h +++ b/tcg/sparc64/tcg-target.h @@ -106,6 +106,7 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_sextract_i32 0 #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_movcond_i32 1 +#define TCG_TARGET_HAS_negsetcond_i32 0 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_mulu2_i32 1 @@ -142,6 +143,7 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_sextract_i64 0 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_movcond_i64 1 +#define TCG_TARGET_HAS_negsetcond_i64 0 #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 #define TCG_TARGET_HAS_mulu2_i64 0 diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 68b93a3d4b..a954004cff 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -276,6 +276,21 @@ void tcg_gen_setcondi_i32(TCGCond cond, TCGv_i32 ret, tcg_gen_setcond_i32(cond, ret, arg1, tcg_constant_i32(arg2)); } +void tcg_gen_negsetcond_i32(TCGCond cond, TCGv_i32 ret, + TCGv_i32 arg1, TCGv_i32 arg2) +{ + if (cond == TCG_COND_ALWAYS) { + tcg_gen_movi_i32(ret, -1); + } else if (cond == TCG_COND_NEVER) { + tcg_gen_movi_i32(ret, 0); + } else if (TCG_TARGET_HAS_negsetcond_i32) { + tcg_gen_op4i_i32(INDEX_op_negsetcond_i32, ret, arg1, arg2, cond); + } else { + tcg_gen_setcond_i32(cond, ret, arg1, arg2); + tcg_gen_neg_i32(ret, ret); + } +} + void tcg_gen_muli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) { if (arg2 == 0) { @@ -1567,6 +1582,27 @@ void tcg_gen_setcondi_i64(TCGCond cond, TCGv_i64 ret, } } +void tcg_gen_negsetcond_i64(TCGCond cond, TCGv_i64 ret, + TCGv_i64 arg1, TCGv_i64 arg2) +{ + if (cond == TCG_COND_ALWAYS) { + tcg_gen_movi_i64(ret, -1); + } else if (cond == TCG_COND_NEVER) { + tcg_gen_movi_i64(ret, 0); + } else if (TCG_TARGET_HAS_negsetcond_i64) { + tcg_gen_op4i_i64(INDEX_op_negsetcond_i64, ret, arg1, arg2, cond); + } else if (TCG_TARGET_REG_BITS == 32) { + tcg_gen_op6i_i32(INDEX_op_setcond2_i32, TCGV_LOW(ret), + TCGV_LOW(arg1), TCGV_HIGH(arg1), + TCGV_LOW(arg2), TCGV_HIGH(arg2), cond); + tcg_gen_neg_i32(TCGV_LOW(ret), TCGV_LOW(ret)); + tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_LOW(ret)); + } else { + tcg_gen_setcond_i64(cond, ret, arg1, arg2); + tcg_gen_neg_i64(ret, ret); + } +} + void tcg_gen_muli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) { if (arg2 == 0) { diff --git a/tcg/tcg.c b/tcg/tcg.c index a23348824b..620dbe08da 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1879,6 +1879,8 @@ bool tcg_op_supported(TCGOpcode op) case INDEX_op_sar_i32: return true; + case INDEX_op_negsetcond_i32: + return TCG_TARGET_HAS_negsetcond_i32; case INDEX_op_movcond_i32: return TCG_TARGET_HAS_movcond_i32; case INDEX_op_div_i32: @@ -1977,6 +1979,8 @@ bool tcg_op_supported(TCGOpcode op) case INDEX_op_extu_i32_i64: return TCG_TARGET_REG_BITS == 64; + case INDEX_op_negsetcond_i64: + return TCG_TARGET_HAS_negsetcond_i64; case INDEX_op_movcond_i64: return TCG_TARGET_HAS_movcond_i64; case INDEX_op_div_i64: @@ -2509,11 +2513,13 @@ static void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs) switch (c) { case INDEX_op_brcond_i32: case INDEX_op_setcond_i32: + case INDEX_op_negsetcond_i32: case INDEX_op_movcond_i32: case INDEX_op_brcond2_i32: case INDEX_op_setcond2_i32: case INDEX_op_brcond_i64: case INDEX_op_setcond_i64: + case INDEX_op_negsetcond_i64: case INDEX_op_movcond_i64: case INDEX_op_cmp_vec: case INDEX_op_cmpsel_vec: diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h index d33185fb36..91ca33b616 100644 --- a/tcg/tci/tcg-target.h +++ b/tcg/tci/tcg-target.h @@ -70,6 +70,7 @@ #define TCG_TARGET_HAS_orc_i32 1 #define TCG_TARGET_HAS_rot_i32 1 #define TCG_TARGET_HAS_movcond_i32 1 +#define TCG_TARGET_HAS_negsetcond_i32 0 #define TCG_TARGET_HAS_muls2_i32 1 #define TCG_TARGET_HAS_muluh_i32 0 #define TCG_TARGET_HAS_mulsh_i32 0 @@ -104,6 +105,7 @@ #define TCG_TARGET_HAS_orc_i64 1 #define TCG_TARGET_HAS_rot_i64 1 #define TCG_TARGET_HAS_movcond_i64 1 +#define TCG_TARGET_HAS_negsetcond_i64 0 #define TCG_TARGET_HAS_muls2_i64 1 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 From 4a8838705660a72bcb35ef6ba271769fb1c8ab02 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 4 Aug 2023 23:29:53 +0000 Subject: [PATCH 1215/1353] tcg: Use tcg_gen_negsetcond_* MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- tcg/tcg-op-gvec.c | 6 ++---- tcg/tcg-op.c | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/tcg/tcg-op-gvec.c b/tcg/tcg-op-gvec.c index a062239804..e260a07c61 100644 --- a/tcg/tcg-op-gvec.c +++ b/tcg/tcg-op-gvec.c @@ -3692,8 +3692,7 @@ static void expand_cmp_i32(uint32_t dofs, uint32_t aofs, uint32_t bofs, for (i = 0; i < oprsz; i += 4) { tcg_gen_ld_i32(t0, cpu_env, aofs + i); tcg_gen_ld_i32(t1, cpu_env, bofs + i); - tcg_gen_setcond_i32(cond, t0, t0, t1); - tcg_gen_neg_i32(t0, t0); + tcg_gen_negsetcond_i32(cond, t0, t0, t1); tcg_gen_st_i32(t0, cpu_env, dofs + i); } tcg_temp_free_i32(t1); @@ -3710,8 +3709,7 @@ static void expand_cmp_i64(uint32_t dofs, uint32_t aofs, uint32_t bofs, for (i = 0; i < oprsz; i += 8) { tcg_gen_ld_i64(t0, cpu_env, aofs + i); tcg_gen_ld_i64(t1, cpu_env, bofs + i); - tcg_gen_setcond_i64(cond, t0, t0, t1); - tcg_gen_neg_i64(t0, t0); + tcg_gen_negsetcond_i64(cond, t0, t0, t1); tcg_gen_st_i64(t0, cpu_env, dofs + i); } tcg_temp_free_i64(t1); diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index a954004cff..b59a50a5a9 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -863,8 +863,7 @@ void tcg_gen_movcond_i32(TCGCond cond, TCGv_i32 ret, TCGv_i32 c1, } else { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); TCGv_i32 t1 = tcg_temp_ebb_new_i32(); - tcg_gen_setcond_i32(cond, t0, c1, c2); - tcg_gen_neg_i32(t0, t0); + tcg_gen_negsetcond_i32(cond, t0, c1, c2); tcg_gen_and_i32(t1, v1, t0); tcg_gen_andc_i32(ret, v2, t0); tcg_gen_or_i32(ret, ret, t1); @@ -2563,8 +2562,7 @@ void tcg_gen_movcond_i64(TCGCond cond, TCGv_i64 ret, TCGv_i64 c1, } else { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); TCGv_i64 t1 = tcg_temp_ebb_new_i64(); - tcg_gen_setcond_i64(cond, t0, c1, c2); - tcg_gen_neg_i64(t0, t0); + tcg_gen_negsetcond_i64(cond, t0, c1, c2); tcg_gen_and_i64(t1, v1, t0); tcg_gen_andc_i64(ret, v2, t0); tcg_gen_or_i64(ret, ret, t1); From d55a3211e24d7b918b1b0bcb8a89aafb524c2b14 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 4 Aug 2023 23:40:42 +0000 Subject: [PATCH 1216/1353] target/alpha: Use tcg_gen_movcond_i64 in gen_fold_mzero The setcond + neg + and sequence is a complex method of performing a conditional move. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/alpha/translate.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/target/alpha/translate.c b/target/alpha/translate.c index 846f3d8091..0839182a1f 100644 --- a/target/alpha/translate.c +++ b/target/alpha/translate.c @@ -517,10 +517,9 @@ static void gen_fold_mzero(TCGCond cond, TCGv dest, TCGv src) case TCG_COND_GE: case TCG_COND_LT: - /* For >= or <, map -0.0 to +0.0 via comparison and mask. */ - tcg_gen_setcondi_i64(TCG_COND_NE, dest, src, mzero); - tcg_gen_neg_i64(dest, dest); - tcg_gen_and_i64(dest, dest, src); + /* For >= or <, map -0.0 to +0.0. */ + tcg_gen_movcond_i64(TCG_COND_NE, dest, src, tcg_constant_i64(mzero), + src, tcg_constant_i64(0)); break; default: From a1264259902039ad4427f6c912d453f7d3763059 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 4 Aug 2023 23:58:29 +0000 Subject: [PATCH 1217/1353] target/arm: Use tcg_gen_negsetcond_* Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/arm/tcg/translate-a64.c | 22 +++++++++------------- target/arm/tcg/translate.c | 12 ++++-------- 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index 5fa1257d32..da686cc953 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -4935,9 +4935,12 @@ static void disas_cond_select(DisasContext *s, uint32_t insn) if (rn == 31 && rm == 31 && (else_inc ^ else_inv)) { /* CSET & CSETM. */ - tcg_gen_setcond_i64(tcg_invert_cond(c.cond), tcg_rd, c.value, zero); if (else_inv) { - tcg_gen_neg_i64(tcg_rd, tcg_rd); + tcg_gen_negsetcond_i64(tcg_invert_cond(c.cond), + tcg_rd, c.value, zero); + } else { + tcg_gen_setcond_i64(tcg_invert_cond(c.cond), + tcg_rd, c.value, zero); } } else { TCGv_i64 t_true = cpu_reg(s, rn); @@ -8670,13 +8673,10 @@ static void handle_3same_64(DisasContext *s, int opcode, bool u, } break; case 0x6: /* CMGT, CMHI */ - /* 64 bit integer comparison, result = test ? (2^64 - 1) : 0. - * We implement this using setcond (test) and then negating. - */ cond = u ? TCG_COND_GTU : TCG_COND_GT; do_cmop: - tcg_gen_setcond_i64(cond, tcg_rd, tcg_rn, tcg_rm); - tcg_gen_neg_i64(tcg_rd, tcg_rd); + /* 64 bit integer comparison, result = test ? -1 : 0. */ + tcg_gen_negsetcond_i64(cond, tcg_rd, tcg_rn, tcg_rm); break; case 0x7: /* CMGE, CMHS */ cond = u ? TCG_COND_GEU : TCG_COND_GE; @@ -9265,14 +9265,10 @@ static void handle_2misc_64(DisasContext *s, int opcode, bool u, } break; case 0xa: /* CMLT */ - /* 64 bit integer comparison against zero, result is - * test ? (2^64 - 1) : 0. We implement via setcond(!test) and - * subtracting 1. - */ cond = TCG_COND_LT; do_cmop: - tcg_gen_setcondi_i64(cond, tcg_rd, tcg_rn, 0); - tcg_gen_neg_i64(tcg_rd, tcg_rd); + /* 64 bit integer comparison against zero, result is test ? -1 : 0. */ + tcg_gen_negsetcond_i64(cond, tcg_rd, tcg_rn, tcg_constant_i64(0)); break; case 0x8: /* CMGT, CMGE */ cond = u ? TCG_COND_GE : TCG_COND_GT; diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c index 39541ecdf0..38ad8dd4bd 100644 --- a/target/arm/tcg/translate.c +++ b/target/arm/tcg/translate.c @@ -2946,13 +2946,11 @@ void gen_gvec_sqrdmlsh_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, #define GEN_CMP0(NAME, COND) \ static void gen_##NAME##0_i32(TCGv_i32 d, TCGv_i32 a) \ { \ - tcg_gen_setcondi_i32(COND, d, a, 0); \ - tcg_gen_neg_i32(d, d); \ + tcg_gen_negsetcond_i32(COND, d, a, tcg_constant_i32(0)); \ } \ static void gen_##NAME##0_i64(TCGv_i64 d, TCGv_i64 a) \ { \ - tcg_gen_setcondi_i64(COND, d, a, 0); \ - tcg_gen_neg_i64(d, d); \ + tcg_gen_negsetcond_i64(COND, d, a, tcg_constant_i64(0)); \ } \ static void gen_##NAME##0_vec(unsigned vece, TCGv_vec d, TCGv_vec a) \ { \ @@ -3863,15 +3861,13 @@ void gen_gvec_mls(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, static void gen_cmtst_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b) { tcg_gen_and_i32(d, a, b); - tcg_gen_setcondi_i32(TCG_COND_NE, d, d, 0); - tcg_gen_neg_i32(d, d); + tcg_gen_negsetcond_i32(TCG_COND_NE, d, d, tcg_constant_i32(0)); } void gen_cmtst_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b) { tcg_gen_and_i64(d, a, b); - tcg_gen_setcondi_i64(TCG_COND_NE, d, d, 0); - tcg_gen_neg_i64(d, d); + tcg_gen_negsetcond_i64(TCG_COND_NE, d, d, tcg_constant_i64(0)); } static void gen_cmtst_vec(unsigned vece, TCGv_vec d, TCGv_vec a, TCGv_vec b) From 27f9af76e11441c498aedf34cb08d0a148fc71f1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 5 Aug 2023 00:07:59 +0000 Subject: [PATCH 1218/1353] target/m68k: Use tcg_gen_negsetcond_* MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/m68k/translate.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/target/m68k/translate.c b/target/m68k/translate.c index d08e823b6c..15b3701b8f 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -1350,8 +1350,7 @@ static void gen_cc_cond(DisasCompare *c, DisasContext *s, int cond) case 14: /* GT (!(Z || (N ^ V))) */ case 15: /* LE (Z || (N ^ V)) */ c->v1 = tmp = tcg_temp_new(); - tcg_gen_setcond_i32(TCG_COND_EQ, tmp, QREG_CC_Z, c->v2); - tcg_gen_neg_i32(tmp, tmp); + tcg_gen_negsetcond_i32(TCG_COND_EQ, tmp, QREG_CC_Z, c->v2); tmp2 = tcg_temp_new(); tcg_gen_xor_i32(tmp2, QREG_CC_N, QREG_CC_V); tcg_gen_or_i32(tmp, tmp, tmp2); @@ -1430,9 +1429,8 @@ DISAS_INSN(scc) gen_cc_cond(&c, s, cond); tmp = tcg_temp_new(); - tcg_gen_setcond_i32(c.tcond, tmp, c.v1, c.v2); + tcg_gen_negsetcond_i32(c.tcond, tmp, c.v1, c.v2); - tcg_gen_neg_i32(tmp, tmp); DEST_EA(env, insn, OS_BYTE, tmp, NULL); } @@ -2764,13 +2762,14 @@ DISAS_INSN(mull) tcg_gen_muls2_i32(QREG_CC_N, QREG_CC_V, src1, DREG(ext, 12)); /* QREG_CC_V is -(QREG_CC_V != (QREG_CC_N >> 31)) */ tcg_gen_sari_i32(QREG_CC_Z, QREG_CC_N, 31); - tcg_gen_setcond_i32(TCG_COND_NE, QREG_CC_V, QREG_CC_V, QREG_CC_Z); + tcg_gen_negsetcond_i32(TCG_COND_NE, QREG_CC_V, + QREG_CC_V, QREG_CC_Z); } else { tcg_gen_mulu2_i32(QREG_CC_N, QREG_CC_V, src1, DREG(ext, 12)); /* QREG_CC_V is -(QREG_CC_V != 0), use QREG_CC_C as 0 */ - tcg_gen_setcond_i32(TCG_COND_NE, QREG_CC_V, QREG_CC_V, QREG_CC_C); + tcg_gen_negsetcond_i32(TCG_COND_NE, QREG_CC_V, + QREG_CC_V, QREG_CC_C); } - tcg_gen_neg_i32(QREG_CC_V, QREG_CC_V); tcg_gen_mov_i32(DREG(ext, 12), QREG_CC_N); tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N); @@ -3339,14 +3338,13 @@ static inline void shift_im(DisasContext *s, uint16_t insn, int opsize) if (!logical && m68k_feature(s->env, M68K_FEATURE_M68K)) { /* if shift count >= bits, V is (reg != 0) */ if (count >= bits) { - tcg_gen_setcond_i32(TCG_COND_NE, QREG_CC_V, reg, QREG_CC_V); + tcg_gen_negsetcond_i32(TCG_COND_NE, QREG_CC_V, reg, QREG_CC_V); } else { TCGv t0 = tcg_temp_new(); tcg_gen_sari_i32(QREG_CC_V, reg, bits - 1); tcg_gen_sari_i32(t0, reg, bits - count - 1); - tcg_gen_setcond_i32(TCG_COND_NE, QREG_CC_V, QREG_CC_V, t0); + tcg_gen_negsetcond_i32(TCG_COND_NE, QREG_CC_V, QREG_CC_V, t0); } - tcg_gen_neg_i32(QREG_CC_V, QREG_CC_V); } } else { tcg_gen_shri_i32(QREG_CC_C, reg, count - 1); @@ -3430,9 +3428,8 @@ static inline void shift_reg(DisasContext *s, uint16_t insn, int opsize) /* Ignore the bits below the sign bit. */ tcg_gen_andi_i64(t64, t64, -1ULL << (bits - 1)); /* If any bits remain set, we have overflow. */ - tcg_gen_setcondi_i64(TCG_COND_NE, t64, t64, 0); + tcg_gen_negsetcond_i64(TCG_COND_NE, t64, t64, tcg_constant_i64(0)); tcg_gen_extrl_i64_i32(QREG_CC_V, t64); - tcg_gen_neg_i32(QREG_CC_V, QREG_CC_V); } } else { tcg_gen_shli_i64(t64, t64, 32); @@ -5311,9 +5308,8 @@ DISAS_INSN(fscc) gen_fcc_cond(&c, s, cond); tmp = tcg_temp_new(); - tcg_gen_setcond_i32(c.tcond, tmp, c.v1, c.v2); + tcg_gen_negsetcond_i32(c.tcond, tmp, c.v1, c.v2); - tcg_gen_neg_i32(tmp, tmp); DEST_EA(env, insn, OS_BYTE, tmp, NULL); } From cfe158875b81df65771d8bfabf6f9a18a9c4307a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 5 Aug 2023 00:15:06 +0000 Subject: [PATCH 1219/1353] target/openrisc: Use tcg_gen_negsetcond_* MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/openrisc/translate.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index a86360d4f5..7c6f80daf1 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -253,9 +253,8 @@ static void gen_mul(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) tcg_gen_muls2_tl(dest, cpu_sr_ov, srca, srcb); tcg_gen_sari_tl(t0, dest, TARGET_LONG_BITS - 1); - tcg_gen_setcond_tl(TCG_COND_NE, cpu_sr_ov, cpu_sr_ov, t0); + tcg_gen_negsetcond_tl(TCG_COND_NE, cpu_sr_ov, cpu_sr_ov, t0); - tcg_gen_neg_tl(cpu_sr_ov, cpu_sr_ov); gen_ove_ov(dc); } @@ -309,9 +308,8 @@ static void gen_muld(DisasContext *dc, TCGv srca, TCGv srcb) tcg_gen_muls2_i64(cpu_mac, high, t1, t2); tcg_gen_sari_i64(t1, cpu_mac, 63); - tcg_gen_setcond_i64(TCG_COND_NE, t1, t1, high); + tcg_gen_negsetcond_i64(TCG_COND_NE, t1, t1, high); tcg_gen_trunc_i64_tl(cpu_sr_ov, t1); - tcg_gen_neg_tl(cpu_sr_ov, cpu_sr_ov); gen_ove_ov(dc); } From 253d110dba77769e1f2919d066c53dfd65942dc3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 5 Aug 2023 00:22:26 +0000 Subject: [PATCH 1220/1353] target/ppc: Use tcg_gen_negsetcond_* Tested-by: Nicholas Piggin Reviewed-by: Nicholas Piggin Reviewed-by: Daniel Henrique Barboza Signed-off-by: Richard Henderson --- target/ppc/translate/fixedpoint-impl.c.inc | 6 ++++-- target/ppc/translate/vmx-impl.c.inc | 8 +++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/target/ppc/translate/fixedpoint-impl.c.inc b/target/ppc/translate/fixedpoint-impl.c.inc index f47f1a50e8..4ce02fd3a4 100644 --- a/target/ppc/translate/fixedpoint-impl.c.inc +++ b/target/ppc/translate/fixedpoint-impl.c.inc @@ -342,12 +342,14 @@ static bool do_set_bool_cond(DisasContext *ctx, arg_X_bi *a, bool neg, bool rev) uint32_t mask = 0x08 >> (a->bi & 0x03); TCGCond cond = rev ? TCG_COND_EQ : TCG_COND_NE; TCGv temp = tcg_temp_new(); + TCGv zero = tcg_constant_tl(0); tcg_gen_extu_i32_tl(temp, cpu_crf[a->bi >> 2]); tcg_gen_andi_tl(temp, temp, mask); - tcg_gen_setcondi_tl(cond, cpu_gpr[a->rt], temp, 0); if (neg) { - tcg_gen_neg_tl(cpu_gpr[a->rt], cpu_gpr[a->rt]); + tcg_gen_negsetcond_tl(cond, cpu_gpr[a->rt], temp, zero); + } else { + tcg_gen_setcond_tl(cond, cpu_gpr[a->rt], temp, zero); } return true; } diff --git a/target/ppc/translate/vmx-impl.c.inc b/target/ppc/translate/vmx-impl.c.inc index c8712dd7d8..6d7669aabd 100644 --- a/target/ppc/translate/vmx-impl.c.inc +++ b/target/ppc/translate/vmx-impl.c.inc @@ -1341,8 +1341,7 @@ static bool trans_VCMPEQUQ(DisasContext *ctx, arg_VC *a) tcg_gen_xor_i64(t1, t0, t1); tcg_gen_or_i64(t1, t1, t2); - tcg_gen_setcondi_i64(TCG_COND_EQ, t1, t1, 0); - tcg_gen_neg_i64(t1, t1); + tcg_gen_negsetcond_i64(TCG_COND_EQ, t1, t1, tcg_constant_i64(0)); set_avr64(a->vrt, t1, true); set_avr64(a->vrt, t1, false); @@ -1365,15 +1364,14 @@ static bool do_vcmpgtq(DisasContext *ctx, arg_VC *a, bool sign) get_avr64(t0, a->vra, false); get_avr64(t1, a->vrb, false); - tcg_gen_setcond_i64(TCG_COND_GTU, t2, t0, t1); + tcg_gen_negsetcond_i64(TCG_COND_GTU, t2, t0, t1); get_avr64(t0, a->vra, true); get_avr64(t1, a->vrb, true); tcg_gen_movcond_i64(TCG_COND_EQ, t2, t0, t1, t2, tcg_constant_i64(0)); - tcg_gen_setcond_i64(sign ? TCG_COND_GT : TCG_COND_GTU, t1, t0, t1); + tcg_gen_negsetcond_i64(sign ? TCG_COND_GT : TCG_COND_GTU, t1, t0, t1); tcg_gen_or_i64(t1, t1, t2); - tcg_gen_neg_i64(t1, t1); set_avr64(a->vrt, t1, true); set_avr64(a->vrt, t1, false); From e3ebbade58aae114c0d61a7365ea54b36f07f2fb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 5 Aug 2023 00:31:29 +0000 Subject: [PATCH 1221/1353] target/sparc: Use tcg_gen_movcond_i64 in gen_edge The setcond + neg + or sequence is a complex method of performing a conditional move. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/sparc/translate.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/target/sparc/translate.c b/target/sparc/translate.c index bd877a5e4a..fa80a91161 100644 --- a/target/sparc/translate.c +++ b/target/sparc/translate.c @@ -2916,7 +2916,7 @@ static void gen_edge(DisasContext *dc, TCGv dst, TCGv s1, TCGv s2, tcg_gen_shr_tl(lo1, tcg_constant_tl(tabl), lo1); tcg_gen_shr_tl(lo2, tcg_constant_tl(tabr), lo2); - tcg_gen_andi_tl(dst, lo1, omask); + tcg_gen_andi_tl(lo1, lo1, omask); tcg_gen_andi_tl(lo2, lo2, omask); amask = -8; @@ -2926,18 +2926,9 @@ static void gen_edge(DisasContext *dc, TCGv dst, TCGv s1, TCGv s2, tcg_gen_andi_tl(s1, s1, amask); tcg_gen_andi_tl(s2, s2, amask); - /* We want to compute - dst = (s1 == s2 ? lo1 : lo1 & lo2). - We've already done dst = lo1, so this reduces to - dst &= (s1 == s2 ? -1 : lo2) - Which we perform by - lo2 |= -(s1 == s2) - dst &= lo2 - */ - tcg_gen_setcond_tl(TCG_COND_EQ, lo1, s1, s2); - tcg_gen_neg_tl(lo1, lo1); - tcg_gen_or_tl(lo2, lo2, lo1); - tcg_gen_and_tl(dst, dst, lo2); + /* Compute dst = (s1 == s2 ? lo1 : lo1 & lo2). */ + tcg_gen_and_tl(lo2, lo2, lo1); + tcg_gen_movcond_tl(TCG_COND_EQ, dst, s1, s2, lo1, lo2); } static void gen_alignaddr(TCGv dst, TCGv s1, TCGv s2, bool left) From b0a433be48c120fdc2be676216a240a316f3613e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 5 Aug 2023 00:38:57 +0000 Subject: [PATCH 1222/1353] target/tricore: Replace gen_cond_w with tcg_gen_negsetcond_tl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Bastian Koppelmann Signed-off-by: Richard Henderson --- target/tricore/translate.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/target/tricore/translate.c b/target/tricore/translate.c index 1947733870..6ae5ccbf72 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -2680,13 +2680,6 @@ gen_accumulating_condi(int cond, TCGv ret, TCGv r1, int32_t con, gen_accumulating_cond(cond, ret, r1, temp, op); } -/* ret = (r1 cond r2) ? 0xFFFFFFFF ? 0x00000000;*/ -static inline void gen_cond_w(TCGCond cond, TCGv ret, TCGv r1, TCGv r2) -{ - tcg_gen_setcond_tl(cond, ret, r1, r2); - tcg_gen_neg_tl(ret, ret); -} - static inline void gen_eqany_bi(TCGv ret, TCGv r1, int32_t con) { TCGv b0 = tcg_temp_new(); @@ -5692,7 +5685,8 @@ static void decode_rr_accumulator(DisasContext *ctx) gen_helper_eq_h(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]); break; case OPC2_32_RR_EQ_W: - gen_cond_w(TCG_COND_EQ, cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]); + tcg_gen_negsetcond_tl(TCG_COND_EQ, cpu_gpr_d[r3], + cpu_gpr_d[r1], cpu_gpr_d[r2]); break; case OPC2_32_RR_EQANY_B: gen_helper_eqany_b(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]); @@ -5729,10 +5723,12 @@ static void decode_rr_accumulator(DisasContext *ctx) gen_helper_lt_hu(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]); break; case OPC2_32_RR_LT_W: - gen_cond_w(TCG_COND_LT, cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]); + tcg_gen_negsetcond_tl(TCG_COND_LT, cpu_gpr_d[r3], + cpu_gpr_d[r1], cpu_gpr_d[r2]); break; case OPC2_32_RR_LT_WU: - gen_cond_w(TCG_COND_LTU, cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2]); + tcg_gen_negsetcond_tl(TCG_COND_LTU, cpu_gpr_d[r3], + cpu_gpr_d[r1], cpu_gpr_d[r2]); break; case OPC2_32_RR_MAX: tcg_gen_movcond_tl(TCG_COND_GT, cpu_gpr_d[r3], cpu_gpr_d[r1], From cba10bb3c8875f428821608f9dfb860a97a63aa1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 5 Aug 2023 01:55:23 +0000 Subject: [PATCH 1223/1353] tcg/ppc: Implement negsetcond_* In the general case we simply negate. However with isel we may load -1 instead of 1 with no extra effort. Consolidate EQ0 and NE0 logic. Replace the NE0 zero-extension with inversion+negation of EQ0, which is never worse and may eliminate one insn. Provide a special case for -EQ0. Reviewed-by: Daniel Henrique Barboza Signed-off-by: Richard Henderson --- tcg/ppc/tcg-target.c.inc | 127 ++++++++++++++++++++++++--------------- tcg/ppc/tcg-target.h | 4 +- 2 files changed, 82 insertions(+), 49 deletions(-) diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 511e14b180..10448aa0e6 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -1548,8 +1548,20 @@ static void tcg_out_cmp(TCGContext *s, int cond, TCGArg arg1, TCGArg arg2, } static void tcg_out_setcond_eq0(TCGContext *s, TCGType type, - TCGReg dst, TCGReg src) + TCGReg dst, TCGReg src, bool neg) { + if (neg && (TCG_TARGET_REG_BITS == 32 || type == TCG_TYPE_I64)) { + /* + * X != 0 implies X + -1 generates a carry. + * RT = (~X + X) + CA + * = -1 + CA + * = CA ? 0 : -1 + */ + tcg_out32(s, ADDIC | TAI(TCG_REG_R0, src, -1)); + tcg_out32(s, SUBFE | TAB(dst, src, src)); + return; + } + if (type == TCG_TYPE_I32) { tcg_out32(s, CNTLZW | RS(src) | RA(dst)); tcg_out_shri32(s, dst, dst, 5); @@ -1557,18 +1569,28 @@ static void tcg_out_setcond_eq0(TCGContext *s, TCGType type, tcg_out32(s, CNTLZD | RS(src) | RA(dst)); tcg_out_shri64(s, dst, dst, 6); } + if (neg) { + tcg_out32(s, NEG | RT(dst) | RA(dst)); + } } -static void tcg_out_setcond_ne0(TCGContext *s, TCGReg dst, TCGReg src) +static void tcg_out_setcond_ne0(TCGContext *s, TCGType type, + TCGReg dst, TCGReg src, bool neg) { - /* X != 0 implies X + -1 generates a carry. Extra addition - trickery means: R = X-1 + ~X + C = X-1 + (-X+1) + C = C. */ - if (dst != src) { - tcg_out32(s, ADDIC | TAI(dst, src, -1)); - tcg_out32(s, SUBFE | TAB(dst, dst, src)); - } else { + if (!neg && (TCG_TARGET_REG_BITS == 32 || type == TCG_TYPE_I64)) { + /* + * X != 0 implies X + -1 generates a carry. Extra addition + * trickery means: R = X-1 + ~X + C = X-1 + (-X+1) + C = C. + */ tcg_out32(s, ADDIC | TAI(TCG_REG_R0, src, -1)); tcg_out32(s, SUBFE | TAB(dst, TCG_REG_R0, src)); + return; + } + tcg_out_setcond_eq0(s, type, dst, src, false); + if (neg) { + tcg_out32(s, ADDI | TAI(dst, dst, -1)); + } else { + tcg_out_xori32(s, dst, dst, 1); } } @@ -1590,9 +1612,10 @@ static TCGReg tcg_gen_setcond_xor(TCGContext *s, TCGReg arg1, TCGArg arg2, static void tcg_out_setcond(TCGContext *s, TCGType type, TCGCond cond, TCGArg arg0, TCGArg arg1, TCGArg arg2, - int const_arg2) + int const_arg2, bool neg) { - int crop, sh; + int sh; + bool inv; tcg_debug_assert(TCG_TARGET_REG_BITS == 64 || type == TCG_TYPE_I32); @@ -1605,14 +1628,10 @@ static void tcg_out_setcond(TCGContext *s, TCGType type, TCGCond cond, if (arg2 == 0) { switch (cond) { case TCG_COND_EQ: - tcg_out_setcond_eq0(s, type, arg0, arg1); + tcg_out_setcond_eq0(s, type, arg0, arg1, neg); return; case TCG_COND_NE: - if (TCG_TARGET_REG_BITS == 64 && type == TCG_TYPE_I32) { - tcg_out_ext32u(s, TCG_REG_R0, arg1); - arg1 = TCG_REG_R0; - } - tcg_out_setcond_ne0(s, arg0, arg1); + tcg_out_setcond_ne0(s, type, arg0, arg1, neg); return; case TCG_COND_GE: tcg_out32(s, NOR | SAB(arg1, arg0, arg1)); @@ -1621,9 +1640,17 @@ static void tcg_out_setcond(TCGContext *s, TCGType type, TCGCond cond, case TCG_COND_LT: /* Extract the sign bit. */ if (type == TCG_TYPE_I32) { - tcg_out_shri32(s, arg0, arg1, 31); + if (neg) { + tcg_out_sari32(s, arg0, arg1, 31); + } else { + tcg_out_shri32(s, arg0, arg1, 31); + } } else { - tcg_out_shri64(s, arg0, arg1, 63); + if (neg) { + tcg_out_sari64(s, arg0, arg1, 63); + } else { + tcg_out_shri64(s, arg0, arg1, 63); + } } return; default: @@ -1641,7 +1668,7 @@ static void tcg_out_setcond(TCGContext *s, TCGType type, TCGCond cond, isel = tcg_to_isel[cond]; - tcg_out_movi(s, type, arg0, 1); + tcg_out_movi(s, type, arg0, neg ? -1 : 1); if (isel & 1) { /* arg0 = (bc ? 0 : 1) */ tab = TAB(arg0, 0, arg0); @@ -1655,51 +1682,47 @@ static void tcg_out_setcond(TCGContext *s, TCGType type, TCGCond cond, return; } + inv = false; switch (cond) { case TCG_COND_EQ: arg1 = tcg_gen_setcond_xor(s, arg1, arg2, const_arg2); - tcg_out_setcond_eq0(s, type, arg0, arg1); - return; + tcg_out_setcond_eq0(s, type, arg0, arg1, neg); + break; case TCG_COND_NE: arg1 = tcg_gen_setcond_xor(s, arg1, arg2, const_arg2); - /* Discard the high bits only once, rather than both inputs. */ - if (TCG_TARGET_REG_BITS == 64 && type == TCG_TYPE_I32) { - tcg_out_ext32u(s, TCG_REG_R0, arg1); - arg1 = TCG_REG_R0; - } - tcg_out_setcond_ne0(s, arg0, arg1); - return; + tcg_out_setcond_ne0(s, type, arg0, arg1, neg); + break; + case TCG_COND_LE: + case TCG_COND_LEU: + inv = true; + /* fall through */ case TCG_COND_GT: case TCG_COND_GTU: - sh = 30; - crop = 0; - goto crtest; - - case TCG_COND_LT: - case TCG_COND_LTU: - sh = 29; - crop = 0; + sh = 30; /* CR7 CR_GT */ goto crtest; case TCG_COND_GE: case TCG_COND_GEU: - sh = 31; - crop = CRNOR | BT(7, CR_EQ) | BA(7, CR_LT) | BB(7, CR_LT); + inv = true; + /* fall through */ + case TCG_COND_LT: + case TCG_COND_LTU: + sh = 29; /* CR7 CR_LT */ goto crtest; - case TCG_COND_LE: - case TCG_COND_LEU: - sh = 31; - crop = CRNOR | BT(7, CR_EQ) | BA(7, CR_GT) | BB(7, CR_GT); crtest: tcg_out_cmp(s, cond, arg1, arg2, const_arg2, 7, type); - if (crop) { - tcg_out32(s, crop); - } tcg_out32(s, MFOCRF | RT(TCG_REG_R0) | FXM(7)); tcg_out_rlw(s, RLWINM, arg0, TCG_REG_R0, sh, 31, 31); + if (neg && inv) { + tcg_out32(s, ADDI | TAI(arg0, arg0, -1)); + } else if (neg) { + tcg_out32(s, NEG | RT(arg0) | RA(arg0)); + } else if (inv) { + tcg_out_xori32(s, arg0, arg0, 1); + } break; default: @@ -2982,11 +3005,19 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, case INDEX_op_setcond_i32: tcg_out_setcond(s, TCG_TYPE_I32, args[3], args[0], args[1], args[2], - const_args[2]); + const_args[2], false); break; case INDEX_op_setcond_i64: tcg_out_setcond(s, TCG_TYPE_I64, args[3], args[0], args[1], args[2], - const_args[2]); + const_args[2], false); + break; + case INDEX_op_negsetcond_i32: + tcg_out_setcond(s, TCG_TYPE_I32, args[3], args[0], args[1], args[2], + const_args[2], true); + break; + case INDEX_op_negsetcond_i64: + tcg_out_setcond(s, TCG_TYPE_I64, args[3], args[0], args[1], args[2], + const_args[2], true); break; case INDEX_op_setcond2_i32: tcg_out_setcond2(s, args, const_args); @@ -3724,6 +3755,7 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) case INDEX_op_rotl_i32: case INDEX_op_rotr_i32: case INDEX_op_setcond_i32: + case INDEX_op_negsetcond_i32: case INDEX_op_and_i64: case INDEX_op_andc_i64: case INDEX_op_shl_i64: @@ -3732,6 +3764,7 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) case INDEX_op_rotl_i64: case INDEX_op_rotr_i64: case INDEX_op_setcond_i64: + case INDEX_op_negsetcond_i64: return C_O1_I2(r, r, ri); case INDEX_op_mul_i32: diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h index a2ca0b44ce..8bfb14998e 100644 --- a/tcg/ppc/tcg-target.h +++ b/tcg/ppc/tcg-target.h @@ -97,7 +97,7 @@ typedef enum { #define TCG_TARGET_HAS_sextract_i32 0 #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_movcond_i32 1 -#define TCG_TARGET_HAS_negsetcond_i32 0 +#define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_mulu2_i32 0 #define TCG_TARGET_HAS_muls2_i32 0 #define TCG_TARGET_HAS_muluh_i32 1 @@ -135,7 +135,7 @@ typedef enum { #define TCG_TARGET_HAS_sextract_i64 0 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_movcond_i64 1 -#define TCG_TARGET_HAS_negsetcond_i64 0 +#define TCG_TARGET_HAS_negsetcond_i64 1 #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 #define TCG_TARGET_HAS_mulu2_i64 0 From 72fa954a6321734b2d7875af7741e23e84601a5b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 5 Aug 2023 02:04:56 +0000 Subject: [PATCH 1224/1353] tcg/ppc: Use the Set Boolean Extension The SETBC family of instructions requires exactly two insns for all comparisions, saving 0-3 insns per (neg)setcond. Tested-by: Nicholas Piggin Reviewed-by: Daniel Henrique Barboza Signed-off-by: Richard Henderson --- tcg/ppc/tcg-target.c.inc | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 10448aa0e6..090f11e71c 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -447,6 +447,11 @@ static bool tcg_target_const_match(int64_t val, TCGType type, int ct) #define TW XO31( 4) #define TRAP (TW | TO(31)) +#define SETBC XO31(384) /* v3.10 */ +#define SETBCR XO31(416) /* v3.10 */ +#define SETNBC XO31(448) /* v3.10 */ +#define SETNBCR XO31(480) /* v3.10 */ + #define NOP ORI /* ori 0,0,0 */ #define LVX XO31(103) @@ -1624,6 +1629,23 @@ static void tcg_out_setcond(TCGContext *s, TCGType type, TCGCond cond, arg2 = (uint32_t)arg2; } + /* With SETBC/SETBCR, we can always implement with 2 insns. */ + if (have_isa_3_10) { + tcg_insn_unit bi, opc; + + tcg_out_cmp(s, cond, arg1, arg2, const_arg2, 7, type); + + /* Re-use tcg_to_bc for BI and BO_COND_{TRUE,FALSE}. */ + bi = tcg_to_bc[cond] & (0x1f << 16); + if (tcg_to_bc[cond] & BO(8)) { + opc = neg ? SETNBC : SETBC; + } else { + opc = neg ? SETNBCR : SETBCR; + } + tcg_out32(s, opc | RT(arg0) | bi); + return; + } + /* Handle common and trivial cases before handling anything else. */ if (arg2 == 0) { switch (cond) { From f58a7dea0f0652779e1525f072ef45bf99dbfd72 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 5 Aug 2023 14:27:12 +0000 Subject: [PATCH 1225/1353] tcg/aarch64: Implement negsetcond_* Trivial, as aarch64 has an instruction for this: CSETM. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 12 ++++++++++++ tcg/aarch64/tcg-target.h | 4 ++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 35ca80cd56..7d8d114c9e 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2262,6 +2262,16 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCG_REG_XZR, tcg_invert_cond(args[3])); break; + case INDEX_op_negsetcond_i32: + a2 = (int32_t)a2; + /* FALLTHRU */ + case INDEX_op_negsetcond_i64: + tcg_out_cmp(s, ext, a1, a2, c2); + /* Use CSETM alias of CSINV Wd, WZR, WZR, invert(cond). */ + tcg_out_insn(s, 3506, CSINV, ext, a0, TCG_REG_XZR, + TCG_REG_XZR, tcg_invert_cond(args[3])); + break; + case INDEX_op_movcond_i32: a2 = (int32_t)a2; /* FALLTHRU */ @@ -2868,6 +2878,8 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) case INDEX_op_sub_i64: case INDEX_op_setcond_i32: case INDEX_op_setcond_i64: + case INDEX_op_negsetcond_i32: + case INDEX_op_negsetcond_i64: return C_O1_I2(r, r, rA); case INDEX_op_mul_i32: diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h index bfa3e5aae9..98727ea53b 100644 --- a/tcg/aarch64/tcg-target.h +++ b/tcg/aarch64/tcg-target.h @@ -86,7 +86,7 @@ typedef enum { #define TCG_TARGET_HAS_sextract_i32 1 #define TCG_TARGET_HAS_extract2_i32 1 #define TCG_TARGET_HAS_movcond_i32 1 -#define TCG_TARGET_HAS_negsetcond_i32 0 +#define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_mulu2_i32 0 @@ -123,7 +123,7 @@ typedef enum { #define TCG_TARGET_HAS_sextract_i64 1 #define TCG_TARGET_HAS_extract2_i64 1 #define TCG_TARGET_HAS_movcond_i64 1 -#define TCG_TARGET_HAS_negsetcond_i64 0 +#define TCG_TARGET_HAS_negsetcond_i64 1 #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 #define TCG_TARGET_HAS_mulu2_i64 0 From fe06b8973385c9421b2988239cadb9d091cdc628 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 5 Aug 2023 14:32:57 +0000 Subject: [PATCH 1226/1353] tcg/arm: Implement negsetcond_i32 Trivial, as we simply need to load a different constant in the conditional move. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- tcg/arm/tcg-target.c.inc | 9 +++++++++ tcg/arm/tcg-target.h | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 83e286088f..162df38c73 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1975,6 +1975,14 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out_dat_imm(s, tcg_cond_to_arm_cond[tcg_invert_cond(args[3])], ARITH_MOV, args[0], 0, 0); break; + case INDEX_op_negsetcond_i32: + tcg_out_dat_rIN(s, COND_AL, ARITH_CMP, ARITH_CMN, 0, + args[1], args[2], const_args[2]); + tcg_out_dat_imm(s, tcg_cond_to_arm_cond[args[3]], + ARITH_MVN, args[0], 0, 0); + tcg_out_dat_imm(s, tcg_cond_to_arm_cond[tcg_invert_cond(args[3])], + ARITH_MOV, args[0], 0, 0); + break; case INDEX_op_brcond2_i32: c = tcg_out_cmp2(s, args, const_args); @@ -2112,6 +2120,7 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) case INDEX_op_add_i32: case INDEX_op_sub_i32: case INDEX_op_setcond_i32: + case INDEX_op_negsetcond_i32: return C_O1_I2(r, r, rIN); case INDEX_op_and_i32: diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h index ad66f11574..311a985209 100644 --- a/tcg/arm/tcg-target.h +++ b/tcg/arm/tcg-target.h @@ -116,7 +116,7 @@ extern bool use_neon_instructions; #define TCG_TARGET_HAS_sextract_i32 use_armv7_instructions #define TCG_TARGET_HAS_extract2_i32 1 #define TCG_TARGET_HAS_movcond_i32 1 -#define TCG_TARGET_HAS_negsetcond_i32 0 +#define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_mulu2_i32 1 #define TCG_TARGET_HAS_muls2_i32 1 #define TCG_TARGET_HAS_muluh_i32 0 From 41e4c0a9ad2b10fc14896447361225b410eb112e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 5 Aug 2023 18:16:32 +0000 Subject: [PATCH 1227/1353] tcg/riscv: Implement negsetcond_* Reviewed-by: Daniel Henrique Barboza Signed-off-by: Richard Henderson --- tcg/riscv/tcg-target.c.inc | 45 ++++++++++++++++++++++++++++++++++++++ tcg/riscv/tcg-target.h | 4 ++-- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index eeaeb6b6e3..232b616af3 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -936,6 +936,44 @@ static void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGReg ret, } } +static void tcg_out_negsetcond(TCGContext *s, TCGCond cond, TCGReg ret, + TCGReg arg1, tcg_target_long arg2, bool c2) +{ + int tmpflags; + TCGReg tmp; + + /* For LT/GE comparison against 0, replicate the sign bit. */ + if (c2 && arg2 == 0) { + switch (cond) { + case TCG_COND_GE: + tcg_out_opc_imm(s, OPC_XORI, ret, arg1, -1); + arg1 = ret; + /* fall through */ + case TCG_COND_LT: + tcg_out_opc_imm(s, OPC_SRAI, ret, arg1, TCG_TARGET_REG_BITS - 1); + return; + default: + break; + } + } + + tmpflags = tcg_out_setcond_int(s, cond, ret, arg1, arg2, c2); + tmp = tmpflags & ~SETCOND_FLAGS; + + /* If intermediate result is zero/non-zero: test != 0. */ + if (tmpflags & SETCOND_NEZ) { + tcg_out_opc_reg(s, OPC_SLTU, ret, TCG_REG_ZERO, tmp); + tmp = ret; + } + + /* Produce the 0/-1 result. */ + if (tmpflags & SETCOND_INV) { + tcg_out_opc_imm(s, OPC_ADDI, ret, tmp, -1); + } else { + tcg_out_opc_reg(s, OPC_SUB, ret, TCG_REG_ZERO, tmp); + } +} + static void tcg_out_movcond_zicond(TCGContext *s, TCGReg ret, TCGReg test_ne, int val1, bool c_val1, int val2, bool c_val2) @@ -1782,6 +1820,11 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out_setcond(s, args[3], a0, a1, a2, c2); break; + case INDEX_op_negsetcond_i32: + case INDEX_op_negsetcond_i64: + tcg_out_negsetcond(s, args[3], a0, a1, a2, c2); + break; + case INDEX_op_movcond_i32: case INDEX_op_movcond_i64: tcg_out_movcond(s, args[5], a0, a1, a2, c2, @@ -1910,6 +1953,8 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) case INDEX_op_xor_i64: case INDEX_op_setcond_i32: case INDEX_op_setcond_i64: + case INDEX_op_negsetcond_i32: + case INDEX_op_negsetcond_i64: return C_O1_I2(r, r, rI); case INDEX_op_andc_i32: diff --git a/tcg/riscv/tcg-target.h b/tcg/riscv/tcg-target.h index 0efb3fc0b8..c1132d178f 100644 --- a/tcg/riscv/tcg-target.h +++ b/tcg/riscv/tcg-target.h @@ -88,7 +88,7 @@ extern bool have_zbb; /* optional instructions */ #define TCG_TARGET_HAS_movcond_i32 1 -#define TCG_TARGET_HAS_negsetcond_i32 0 +#define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_div_i32 1 #define TCG_TARGET_HAS_rem_i32 1 #define TCG_TARGET_HAS_div2_i32 0 @@ -124,7 +124,7 @@ extern bool have_zbb; #define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_movcond_i64 1 -#define TCG_TARGET_HAS_negsetcond_i64 0 +#define TCG_TARGET_HAS_negsetcond_i64 1 #define TCG_TARGET_HAS_div_i64 1 #define TCG_TARGET_HAS_rem_i64 1 #define TCG_TARGET_HAS_div2_i64 0 From 128c7d51942fed5bf09ad835ef2dd9b57946ada3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 5 Aug 2023 18:55:54 +0000 Subject: [PATCH 1228/1353] tcg/s390x: Implement negsetcond_* Signed-off-by: Richard Henderson --- tcg/s390x/tcg-target.c.inc | 78 +++++++++++++++++++++++++------------- tcg/s390x/tcg-target.h | 4 +- 2 files changed, 54 insertions(+), 28 deletions(-) diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index a94f7908d6..ecd8aaf2a1 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -1266,7 +1266,8 @@ static int tgen_cmp(TCGContext *s, TCGType type, TCGCond c, TCGReg r1, } static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond, - TCGReg dest, TCGReg c1, TCGArg c2, int c2const) + TCGReg dest, TCGReg c1, TCGArg c2, + bool c2const, bool neg) { int cc; @@ -1275,11 +1276,27 @@ static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond, /* Emit: d = 0, d = (cc ? 1 : d). */ cc = tgen_cmp(s, type, cond, c1, c2, c2const, false); tcg_out_movi(s, TCG_TYPE_I64, dest, 0); - tcg_out_insn(s, RIEg, LOCGHI, dest, 1, cc); + tcg_out_insn(s, RIEg, LOCGHI, dest, neg ? -1 : 1, cc); return; } - restart: + switch (cond) { + case TCG_COND_GEU: + case TCG_COND_LTU: + case TCG_COND_LT: + case TCG_COND_GE: + /* Swap operands so that we can use LEU/GTU/GT/LE. */ + if (!c2const) { + TCGReg t = c1; + c1 = c2; + c2 = t; + cond = tcg_swap_cond(cond); + } + break; + default: + break; + } + switch (cond) { case TCG_COND_NE: /* X != 0 is X > 0. */ @@ -1292,11 +1309,20 @@ static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond, case TCG_COND_GTU: case TCG_COND_GT: - /* The result of a compare has CC=2 for GT and CC=3 unused. - ADD LOGICAL WITH CARRY considers (CC & 2) the carry bit. */ + /* + * The result of a compare has CC=2 for GT and CC=3 unused. + * ADD LOGICAL WITH CARRY considers (CC & 2) the carry bit. + */ tgen_cmp(s, type, cond, c1, c2, c2const, true); tcg_out_movi(s, type, dest, 0); tcg_out_insn(s, RRE, ALCGR, dest, dest); + if (neg) { + if (type == TCG_TYPE_I32) { + tcg_out_insn(s, RR, LCR, dest, dest); + } else { + tcg_out_insn(s, RRE, LCGR, dest, dest); + } + } return; case TCG_COND_EQ: @@ -1310,27 +1336,17 @@ static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond, case TCG_COND_LEU: case TCG_COND_LE: - /* As above, but we're looking for borrow, or !carry. - The second insn computes d - d - borrow, or -1 for true - and 0 for false. So we must mask to 1 bit afterward. */ + /* + * As above, but we're looking for borrow, or !carry. + * The second insn computes d - d - borrow, or -1 for true + * and 0 for false. So we must mask to 1 bit afterward. + */ tgen_cmp(s, type, cond, c1, c2, c2const, true); tcg_out_insn(s, RRE, SLBGR, dest, dest); - tgen_andi(s, type, dest, 1); - return; - - case TCG_COND_GEU: - case TCG_COND_LTU: - case TCG_COND_LT: - case TCG_COND_GE: - /* Swap operands so that we can use LEU/GTU/GT/LE. */ - if (!c2const) { - TCGReg t = c1; - c1 = c2; - c2 = t; - cond = tcg_swap_cond(cond); - goto restart; + if (!neg) { + tgen_andi(s, type, dest, 1); } - break; + return; default: g_assert_not_reached(); @@ -1339,7 +1355,7 @@ static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond, cc = tgen_cmp(s, type, cond, c1, c2, c2const, false); /* Emit: d = 0, t = 1, d = (cc ? t : d). */ tcg_out_movi(s, TCG_TYPE_I64, dest, 0); - tcg_out_movi(s, TCG_TYPE_I64, TCG_TMP0, 1); + tcg_out_movi(s, TCG_TYPE_I64, TCG_TMP0, neg ? -1 : 1); tcg_out_insn(s, RRFc, LOCGR, dest, TCG_TMP0, cc); } @@ -2288,7 +2304,11 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, break; case INDEX_op_setcond_i32: tgen_setcond(s, TCG_TYPE_I32, args[3], args[0], args[1], - args[2], const_args[2]); + args[2], const_args[2], false); + break; + case INDEX_op_negsetcond_i32: + tgen_setcond(s, TCG_TYPE_I32, args[3], args[0], args[1], + args[2], const_args[2], true); break; case INDEX_op_movcond_i32: tgen_movcond(s, TCG_TYPE_I32, args[5], args[0], args[1], @@ -2566,7 +2586,11 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, break; case INDEX_op_setcond_i64: tgen_setcond(s, TCG_TYPE_I64, args[3], args[0], args[1], - args[2], const_args[2]); + args[2], const_args[2], false); + break; + case INDEX_op_negsetcond_i64: + tgen_setcond(s, TCG_TYPE_I64, args[3], args[0], args[1], + args[2], const_args[2], true); break; case INDEX_op_movcond_i64: tgen_movcond(s, TCG_TYPE_I64, args[5], args[0], args[1], @@ -3109,8 +3133,10 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) case INDEX_op_rotr_i32: case INDEX_op_rotr_i64: case INDEX_op_setcond_i32: + case INDEX_op_negsetcond_i32: return C_O1_I2(r, r, ri); case INDEX_op_setcond_i64: + case INDEX_op_negsetcond_i64: return C_O1_I2(r, r, rA); case INDEX_op_clz_i64: diff --git a/tcg/s390x/tcg-target.h b/tcg/s390x/tcg-target.h index 123a4b1645..50e12ef9d6 100644 --- a/tcg/s390x/tcg-target.h +++ b/tcg/s390x/tcg-target.h @@ -96,7 +96,7 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_sextract_i32 0 #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_movcond_i32 1 -#define TCG_TARGET_HAS_negsetcond_i32 0 +#define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_mulu2_i32 0 @@ -132,7 +132,7 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_sextract_i64 0 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_movcond_i64 1 -#define TCG_TARGET_HAS_negsetcond_i64 0 +#define TCG_TARGET_HAS_negsetcond_i64 1 #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 #define TCG_TARGET_HAS_mulu2_i64 1 From a0fdd7c91c220ea9240643b155f9f5bdc4a2e2a1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 5 Aug 2023 13:57:32 -0700 Subject: [PATCH 1229/1353] tcg/sparc64: Implement negsetcond_* Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- tcg/sparc64/tcg-target.c.inc | 40 +++++++++++++++++++++++++++--------- tcg/sparc64/tcg-target.h | 4 ++-- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index ffcb879211..f2a346a1bd 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -720,7 +720,7 @@ static void tcg_out_movcond_i64(TCGContext *s, TCGCond cond, TCGReg ret, } static void tcg_out_setcond_i32(TCGContext *s, TCGCond cond, TCGReg ret, - TCGReg c1, int32_t c2, int c2const) + TCGReg c1, int32_t c2, int c2const, bool neg) { /* For 32-bit comparisons, we can play games with ADDC/SUBC. */ switch (cond) { @@ -760,22 +760,34 @@ static void tcg_out_setcond_i32(TCGContext *s, TCGCond cond, TCGReg ret, default: tcg_out_cmp(s, c1, c2, c2const); tcg_out_movi_s13(s, ret, 0); - tcg_out_movcc(s, cond, MOVCC_ICC, ret, 1, 1); + tcg_out_movcc(s, cond, MOVCC_ICC, ret, neg ? -1 : 1, 1); return; } tcg_out_cmp(s, c1, c2, c2const); if (cond == TCG_COND_LTU) { - tcg_out_arithi(s, ret, TCG_REG_G0, 0, ARITH_ADDC); + if (neg) { + /* 0 - 0 - C = -C = (C ? -1 : 0) */ + tcg_out_arithi(s, ret, TCG_REG_G0, 0, ARITH_SUBC); + } else { + /* 0 + 0 + C = C = (C ? 1 : 0) */ + tcg_out_arithi(s, ret, TCG_REG_G0, 0, ARITH_ADDC); + } } else { - tcg_out_arithi(s, ret, TCG_REG_G0, -1, ARITH_SUBC); + if (neg) { + /* 0 + -1 + C = C - 1 = (C ? 0 : -1) */ + tcg_out_arithi(s, ret, TCG_REG_G0, -1, ARITH_ADDC); + } else { + /* 0 - -1 - C = 1 - C = (C ? 0 : 1) */ + tcg_out_arithi(s, ret, TCG_REG_G0, -1, ARITH_SUBC); + } } } static void tcg_out_setcond_i64(TCGContext *s, TCGCond cond, TCGReg ret, - TCGReg c1, int32_t c2, int c2const) + TCGReg c1, int32_t c2, int c2const, bool neg) { - if (use_vis3_instructions) { + if (use_vis3_instructions && !neg) { switch (cond) { case TCG_COND_NE: if (c2 != 0) { @@ -796,11 +808,11 @@ static void tcg_out_setcond_i64(TCGContext *s, TCGCond cond, TCGReg ret, if the input does not overlap the output. */ if (c2 == 0 && !is_unsigned_cond(cond) && c1 != ret) { tcg_out_movi_s13(s, ret, 0); - tcg_out_movr(s, cond, ret, c1, 1, 1); + tcg_out_movr(s, cond, ret, c1, neg ? -1 : 1, 1); } else { tcg_out_cmp(s, c1, c2, c2const); tcg_out_movi_s13(s, ret, 0); - tcg_out_movcc(s, cond, MOVCC_XCC, ret, 1, 1); + tcg_out_movcc(s, cond, MOVCC_XCC, ret, neg ? -1 : 1, 1); } } @@ -1355,7 +1367,10 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out_brcond_i32(s, a2, a0, a1, const_args[1], arg_label(args[3])); break; case INDEX_op_setcond_i32: - tcg_out_setcond_i32(s, args[3], a0, a1, a2, c2); + tcg_out_setcond_i32(s, args[3], a0, a1, a2, c2, false); + break; + case INDEX_op_negsetcond_i32: + tcg_out_setcond_i32(s, args[3], a0, a1, a2, c2, true); break; case INDEX_op_movcond_i32: tcg_out_movcond_i32(s, args[5], a0, a1, a2, c2, args[3], const_args[3]); @@ -1437,7 +1452,10 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out_brcond_i64(s, a2, a0, a1, const_args[1], arg_label(args[3])); break; case INDEX_op_setcond_i64: - tcg_out_setcond_i64(s, args[3], a0, a1, a2, c2); + tcg_out_setcond_i64(s, args[3], a0, a1, a2, c2, false); + break; + case INDEX_op_negsetcond_i64: + tcg_out_setcond_i64(s, args[3], a0, a1, a2, c2, true); break; case INDEX_op_movcond_i64: tcg_out_movcond_i64(s, args[5], a0, a1, a2, c2, args[3], const_args[3]); @@ -1564,6 +1582,8 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) case INDEX_op_sar_i64: case INDEX_op_setcond_i32: case INDEX_op_setcond_i64: + case INDEX_op_negsetcond_i32: + case INDEX_op_negsetcond_i64: return C_O1_I2(r, rZ, rJ); case INDEX_op_brcond_i32: diff --git a/tcg/sparc64/tcg-target.h b/tcg/sparc64/tcg-target.h index 79889db760..3d41c9659b 100644 --- a/tcg/sparc64/tcg-target.h +++ b/tcg/sparc64/tcg-target.h @@ -106,7 +106,7 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_sextract_i32 0 #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_movcond_i32 1 -#define TCG_TARGET_HAS_negsetcond_i32 0 +#define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_mulu2_i32 1 @@ -143,7 +143,7 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_sextract_i64 0 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_movcond_i64 1 -#define TCG_TARGET_HAS_negsetcond_i64 0 +#define TCG_TARGET_HAS_negsetcond_i64 1 #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 #define TCG_TARGET_HAS_mulu2_i64 0 From c359ce756db4fd8ba27a390780e3013b479ae537 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 5 Aug 2023 14:48:27 -0700 Subject: [PATCH 1230/1353] tcg/i386: Merge tcg_out_brcond{32,64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pass a rexw parameter instead of duplicating the functions. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- tcg/i386/tcg-target.c.inc | 110 +++++++++++++++++--------------------- 1 file changed, 49 insertions(+), 61 deletions(-) diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 3045b56002..33f66ba204 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -1436,99 +1436,89 @@ static void tcg_out_cmp(TCGContext *s, TCGArg arg1, TCGArg arg2, } } -static void tcg_out_brcond32(TCGContext *s, TCGCond cond, - TCGArg arg1, TCGArg arg2, int const_arg2, - TCGLabel *label, int small) +static void tcg_out_brcond(TCGContext *s, int rexw, TCGCond cond, + TCGArg arg1, TCGArg arg2, int const_arg2, + TCGLabel *label, bool small) { - tcg_out_cmp(s, arg1, arg2, const_arg2, 0); + tcg_out_cmp(s, arg1, arg2, const_arg2, rexw); tcg_out_jxx(s, tcg_cond_to_jcc[cond], label, small); } -#if TCG_TARGET_REG_BITS == 64 -static void tcg_out_brcond64(TCGContext *s, TCGCond cond, - TCGArg arg1, TCGArg arg2, int const_arg2, - TCGLabel *label, int small) -{ - tcg_out_cmp(s, arg1, arg2, const_arg2, P_REXW); - tcg_out_jxx(s, tcg_cond_to_jcc[cond], label, small); -} -#else -/* XXX: we implement it at the target level to avoid having to - handle cross basic blocks temporaries */ +#if TCG_TARGET_REG_BITS == 32 static void tcg_out_brcond2(TCGContext *s, const TCGArg *args, - const int *const_args, int small) + const int *const_args, bool small) { TCGLabel *label_next = gen_new_label(); TCGLabel *label_this = arg_label(args[5]); switch(args[4]) { case TCG_COND_EQ: - tcg_out_brcond32(s, TCG_COND_NE, args[0], args[2], const_args[2], - label_next, 1); - tcg_out_brcond32(s, TCG_COND_EQ, args[1], args[3], const_args[3], - label_this, small); + tcg_out_brcond(s, 0, TCG_COND_NE, args[0], args[2], const_args[2], + label_next, 1); + tcg_out_brcond(s, 0, TCG_COND_EQ, args[1], args[3], const_args[3], + label_this, small); break; case TCG_COND_NE: - tcg_out_brcond32(s, TCG_COND_NE, args[0], args[2], const_args[2], - label_this, small); - tcg_out_brcond32(s, TCG_COND_NE, args[1], args[3], const_args[3], - label_this, small); + tcg_out_brcond(s, 0, TCG_COND_NE, args[0], args[2], const_args[2], + label_this, small); + tcg_out_brcond(s, 0, TCG_COND_NE, args[1], args[3], const_args[3], + label_this, small); break; case TCG_COND_LT: - tcg_out_brcond32(s, TCG_COND_LT, args[1], args[3], const_args[3], - label_this, small); + tcg_out_brcond(s, 0, TCG_COND_LT, args[1], args[3], const_args[3], + label_this, small); tcg_out_jxx(s, JCC_JNE, label_next, 1); - tcg_out_brcond32(s, TCG_COND_LTU, args[0], args[2], const_args[2], - label_this, small); + tcg_out_brcond(s, 0, TCG_COND_LTU, args[0], args[2], const_args[2], + label_this, small); break; case TCG_COND_LE: - tcg_out_brcond32(s, TCG_COND_LT, args[1], args[3], const_args[3], - label_this, small); + tcg_out_brcond(s, 0, TCG_COND_LT, args[1], args[3], const_args[3], + label_this, small); tcg_out_jxx(s, JCC_JNE, label_next, 1); - tcg_out_brcond32(s, TCG_COND_LEU, args[0], args[2], const_args[2], - label_this, small); + tcg_out_brcond(s, 0, TCG_COND_LEU, args[0], args[2], const_args[2], + label_this, small); break; case TCG_COND_GT: - tcg_out_brcond32(s, TCG_COND_GT, args[1], args[3], const_args[3], - label_this, small); + tcg_out_brcond(s, 0, TCG_COND_GT, args[1], args[3], const_args[3], + label_this, small); tcg_out_jxx(s, JCC_JNE, label_next, 1); - tcg_out_brcond32(s, TCG_COND_GTU, args[0], args[2], const_args[2], - label_this, small); + tcg_out_brcond(s, 0, TCG_COND_GTU, args[0], args[2], const_args[2], + label_this, small); break; case TCG_COND_GE: - tcg_out_brcond32(s, TCG_COND_GT, args[1], args[3], const_args[3], - label_this, small); + tcg_out_brcond(s, 0, TCG_COND_GT, args[1], args[3], const_args[3], + label_this, small); tcg_out_jxx(s, JCC_JNE, label_next, 1); - tcg_out_brcond32(s, TCG_COND_GEU, args[0], args[2], const_args[2], - label_this, small); + tcg_out_brcond(s, 0, TCG_COND_GEU, args[0], args[2], const_args[2], + label_this, small); break; case TCG_COND_LTU: - tcg_out_brcond32(s, TCG_COND_LTU, args[1], args[3], const_args[3], - label_this, small); + tcg_out_brcond(s, 0, TCG_COND_LTU, args[1], args[3], const_args[3], + label_this, small); tcg_out_jxx(s, JCC_JNE, label_next, 1); - tcg_out_brcond32(s, TCG_COND_LTU, args[0], args[2], const_args[2], - label_this, small); + tcg_out_brcond(s, 0, TCG_COND_LTU, args[0], args[2], const_args[2], + label_this, small); break; case TCG_COND_LEU: - tcg_out_brcond32(s, TCG_COND_LTU, args[1], args[3], const_args[3], - label_this, small); + tcg_out_brcond(s, 0, TCG_COND_LTU, args[1], args[3], const_args[3], + label_this, small); tcg_out_jxx(s, JCC_JNE, label_next, 1); - tcg_out_brcond32(s, TCG_COND_LEU, args[0], args[2], const_args[2], - label_this, small); + tcg_out_brcond(s, 0, TCG_COND_LEU, args[0], args[2], const_args[2], + label_this, small); break; case TCG_COND_GTU: - tcg_out_brcond32(s, TCG_COND_GTU, args[1], args[3], const_args[3], - label_this, small); + tcg_out_brcond(s, 0, TCG_COND_GTU, args[1], args[3], const_args[3], + label_this, small); tcg_out_jxx(s, JCC_JNE, label_next, 1); - tcg_out_brcond32(s, TCG_COND_GTU, args[0], args[2], const_args[2], - label_this, small); + tcg_out_brcond(s, 0, TCG_COND_GTU, args[0], args[2], const_args[2], + label_this, small); break; case TCG_COND_GEU: - tcg_out_brcond32(s, TCG_COND_GTU, args[1], args[3], const_args[3], - label_this, small); + tcg_out_brcond(s, 0, TCG_COND_GTU, args[1], args[3], const_args[3], + label_this, small); tcg_out_jxx(s, JCC_JNE, label_next, 1); - tcg_out_brcond32(s, TCG_COND_GEU, args[0], args[2], const_args[2], - label_this, small); + tcg_out_brcond(s, 0, TCG_COND_GEU, args[0], args[2], const_args[2], + label_this, small); break; default: g_assert_not_reached(); @@ -2574,8 +2564,9 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out_modrm(s, OPC_POPCNT + rexw, a0, a1); break; - case INDEX_op_brcond_i32: - tcg_out_brcond32(s, a2, a0, a1, const_args[1], arg_label(args[3]), 0); + OP_32_64(brcond): + tcg_out_brcond(s, rexw, a2, a0, a1, const_args[1], + arg_label(args[3]), 0); break; case INDEX_op_setcond_i32: tcg_out_setcond32(s, args[3], a0, a1, a2, const_a2); @@ -2730,9 +2721,6 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, } break; - case INDEX_op_brcond_i64: - tcg_out_brcond64(s, a2, a0, a1, const_args[1], arg_label(args[3]), 0); - break; case INDEX_op_setcond_i64: tcg_out_setcond64(s, args[3], a0, a1, a2, const_a2); break; From 7ba99a1c762d46e08a5adf68f71f9d4ab621a094 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 5 Aug 2023 14:59:16 -0700 Subject: [PATCH 1231/1353] tcg/i386: Merge tcg_out_setcond{32,64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pass a rexw parameter instead of duplicating the functions. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- tcg/i386/tcg-target.c.inc | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 33f66ba204..010432d3a9 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -1527,23 +1527,16 @@ static void tcg_out_brcond2(TCGContext *s, const TCGArg *args, } #endif -static void tcg_out_setcond32(TCGContext *s, TCGCond cond, TCGArg dest, - TCGArg arg1, TCGArg arg2, int const_arg2) +static void tcg_out_setcond(TCGContext *s, int rexw, TCGCond cond, + TCGArg dest, TCGArg arg1, TCGArg arg2, + int const_arg2) { - tcg_out_cmp(s, arg1, arg2, const_arg2, 0); + tcg_out_cmp(s, arg1, arg2, const_arg2, rexw); tcg_out_modrm(s, OPC_SETCC | tcg_cond_to_jcc[cond], 0, dest); tcg_out_ext8u(s, dest, dest); } -#if TCG_TARGET_REG_BITS == 64 -static void tcg_out_setcond64(TCGContext *s, TCGCond cond, TCGArg dest, - TCGArg arg1, TCGArg arg2, int const_arg2) -{ - tcg_out_cmp(s, arg1, arg2, const_arg2, P_REXW); - tcg_out_modrm(s, OPC_SETCC | tcg_cond_to_jcc[cond], 0, dest); - tcg_out_ext8u(s, dest, dest); -} -#else +#if TCG_TARGET_REG_BITS == 32 static void tcg_out_setcond2(TCGContext *s, const TCGArg *args, const int *const_args) { @@ -2568,8 +2561,8 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out_brcond(s, rexw, a2, a0, a1, const_args[1], arg_label(args[3]), 0); break; - case INDEX_op_setcond_i32: - tcg_out_setcond32(s, args[3], a0, a1, a2, const_a2); + OP_32_64(setcond): + tcg_out_setcond(s, rexw, args[3], a0, a1, a2, const_a2); break; case INDEX_op_movcond_i32: tcg_out_movcond32(s, args[5], a0, a1, a2, const_a2, args[3]); @@ -2721,9 +2714,6 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, } break; - case INDEX_op_setcond_i64: - tcg_out_setcond64(s, args[3], a0, a1, a2, const_a2); - break; case INDEX_op_movcond_i64: tcg_out_movcond64(s, args[5], a0, a1, a2, const_a2, args[3]); break; From 78ddf0dc75229865ba637cfffd53cc605cc33ca1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 5 Aug 2023 15:02:35 -0700 Subject: [PATCH 1232/1353] tcg/i386: Merge tcg_out_movcond{32,64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pass a rexw parameter instead of duplicating the functions. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- tcg/i386/tcg-target.c.inc | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 010432d3a9..1542afd94d 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -1593,24 +1593,14 @@ static void tcg_out_cmov(TCGContext *s, TCGCond cond, int rexw, } } -static void tcg_out_movcond32(TCGContext *s, TCGCond cond, TCGReg dest, - TCGReg c1, TCGArg c2, int const_c2, - TCGReg v1) +static void tcg_out_movcond(TCGContext *s, int rexw, TCGCond cond, + TCGReg dest, TCGReg c1, TCGArg c2, int const_c2, + TCGReg v1) { - tcg_out_cmp(s, c1, c2, const_c2, 0); - tcg_out_cmov(s, cond, 0, dest, v1); + tcg_out_cmp(s, c1, c2, const_c2, rexw); + tcg_out_cmov(s, cond, rexw, dest, v1); } -#if TCG_TARGET_REG_BITS == 64 -static void tcg_out_movcond64(TCGContext *s, TCGCond cond, TCGReg dest, - TCGReg c1, TCGArg c2, int const_c2, - TCGReg v1) -{ - tcg_out_cmp(s, c1, c2, const_c2, P_REXW); - tcg_out_cmov(s, cond, P_REXW, dest, v1); -} -#endif - static void tcg_out_ctz(TCGContext *s, int rexw, TCGReg dest, TCGReg arg1, TCGArg arg2, bool const_a2) { @@ -2564,8 +2554,8 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, OP_32_64(setcond): tcg_out_setcond(s, rexw, args[3], a0, a1, a2, const_a2); break; - case INDEX_op_movcond_i32: - tcg_out_movcond32(s, args[5], a0, a1, a2, const_a2, args[3]); + OP_32_64(movcond): + tcg_out_movcond(s, rexw, args[5], a0, a1, a2, const_a2, args[3]); break; OP_32_64(bswap16): @@ -2714,10 +2704,6 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, } break; - case INDEX_op_movcond_i64: - tcg_out_movcond64(s, args[5], a0, a1, a2, const_a2, args[3]); - break; - case INDEX_op_bswap64_i64: tcg_out_bswap64(s, a0); break; From 6950f68b62e4913513a40b574de0219b7ae15b9f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 5 Aug 2023 15:43:23 -0700 Subject: [PATCH 1233/1353] tcg/i386: Use CMP+SBB in tcg_out_setcond Use the carry bit to optimize some forms of setcond. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- tcg/i386/tcg-target.c.inc | 50 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 1542afd94d..4d7b745a52 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -1531,6 +1531,56 @@ static void tcg_out_setcond(TCGContext *s, int rexw, TCGCond cond, TCGArg dest, TCGArg arg1, TCGArg arg2, int const_arg2) { + bool inv = false; + + switch (cond) { + case TCG_COND_NE: + inv = true; + /* fall through */ + case TCG_COND_EQ: + /* If arg2 is 0, convert to LTU/GEU vs 1. */ + if (const_arg2 && arg2 == 0) { + arg2 = 1; + goto do_ltu; + } + break; + + case TCG_COND_LEU: + inv = true; + /* fall through */ + case TCG_COND_GTU: + /* If arg2 is a register, swap for LTU/GEU. */ + if (!const_arg2) { + TCGReg t = arg1; + arg1 = arg2; + arg2 = t; + goto do_ltu; + } + break; + + case TCG_COND_GEU: + inv = true; + /* fall through */ + case TCG_COND_LTU: + do_ltu: + /* + * Relying on the carry bit, use SBB to produce -1 if LTU, 0 if GEU. + * We can then use NEG or INC to produce the desired result. + * This is always smaller than the SETCC expansion. + */ + tcg_out_cmp(s, arg1, arg2, const_arg2, rexw); + tgen_arithr(s, ARITH_SBB, dest, dest); /* T:-1 F:0 */ + if (inv) { + tgen_arithi(s, ARITH_ADD, dest, 1, 0); /* T:0 F:1 */ + } else { + tcg_out_modrm(s, OPC_GRP3_Ev, EXT3_NEG, dest); /* T:1 F:0 */ + } + return; + + default: + break; + } + tcg_out_cmp(s, arg1, arg2, const_arg2, rexw); tcg_out_modrm(s, OPC_SETCC | tcg_cond_to_jcc[cond], 0, dest); tcg_out_ext8u(s, dest, dest); From 96658acafd9ade24d00526e46cc073ed8fcf2111 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 5 Aug 2023 15:51:30 -0700 Subject: [PATCH 1234/1353] tcg/i386: Clear dest first in tcg_out_setcond if possible Using XOR first is both smaller and more efficient, though cannot be applied if it clobbers an input. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- tcg/i386/tcg-target.c.inc | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 4d7b745a52..3f3c114efd 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -1532,6 +1532,7 @@ static void tcg_out_setcond(TCGContext *s, int rexw, TCGCond cond, int const_arg2) { bool inv = false; + bool cleared; switch (cond) { case TCG_COND_NE: @@ -1581,9 +1582,23 @@ static void tcg_out_setcond(TCGContext *s, int rexw, TCGCond cond, break; } + /* + * If dest does not overlap the inputs, clearing it first is preferred. + * The XOR breaks any false dependency for the low-byte write to dest, + * and is also one byte smaller than MOVZBL. + */ + cleared = false; + if (dest != arg1 && (const_arg2 || dest != arg2)) { + tgen_arithr(s, ARITH_XOR, dest, dest); + cleared = true; + } + tcg_out_cmp(s, arg1, arg2, const_arg2, rexw); tcg_out_modrm(s, OPC_SETCC | tcg_cond_to_jcc[cond], 0, dest); - tcg_out_ext8u(s, dest, dest); + + if (!cleared) { + tcg_out_ext8u(s, dest, dest); + } } #if TCG_TARGET_REG_BITS == 32 From e91f015b62d72158c4f69a5b1cbf87fba4599ba1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 5 Aug 2023 16:07:34 -0700 Subject: [PATCH 1235/1353] tcg/i386: Use shift in tcg_out_setcond For LT/GE vs zero, shift down the sign bit. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- tcg/i386/tcg-target.c.inc | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 3f3c114efd..16e830051d 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -1578,6 +1578,21 @@ static void tcg_out_setcond(TCGContext *s, int rexw, TCGCond cond, } return; + case TCG_COND_GE: + inv = true; + /* fall through */ + case TCG_COND_LT: + /* If arg2 is 0, extract the sign bit. */ + if (const_arg2 && arg2 == 0) { + tcg_out_mov(s, rexw ? TCG_TYPE_I64 : TCG_TYPE_I32, dest, arg1); + if (inv) { + tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_NOT, dest); + } + tcg_out_shifti(s, SHIFT_SHR + rexw, dest, rexw ? 63 : 31); + return; + } + break; + default: break; } From 95bf306e3a058a38f5adb27be2ac598134b159d9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 5 Aug 2023 16:58:43 -0700 Subject: [PATCH 1236/1353] tcg/i386: Implement negsetcond_* Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- tcg/i386/tcg-target.c.inc | 32 ++++++++++++++++++++++++-------- tcg/i386/tcg-target.h | 4 ++-- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 16e830051d..0c3d1e4cef 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -1529,7 +1529,7 @@ static void tcg_out_brcond2(TCGContext *s, const TCGArg *args, static void tcg_out_setcond(TCGContext *s, int rexw, TCGCond cond, TCGArg dest, TCGArg arg1, TCGArg arg2, - int const_arg2) + int const_arg2, bool neg) { bool inv = false; bool cleared; @@ -1570,11 +1570,18 @@ static void tcg_out_setcond(TCGContext *s, int rexw, TCGCond cond, * This is always smaller than the SETCC expansion. */ tcg_out_cmp(s, arg1, arg2, const_arg2, rexw); - tgen_arithr(s, ARITH_SBB, dest, dest); /* T:-1 F:0 */ - if (inv) { - tgen_arithi(s, ARITH_ADD, dest, 1, 0); /* T:0 F:1 */ - } else { - tcg_out_modrm(s, OPC_GRP3_Ev, EXT3_NEG, dest); /* T:1 F:0 */ + + /* X - X - C = -C = (C ? -1 : 0) */ + tgen_arithr(s, ARITH_SBB + (neg ? rexw : 0), dest, dest); + if (inv && neg) { + /* ~(C ? -1 : 0) = (C ? 0 : -1) */ + tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_NOT, dest); + } else if (inv) { + /* (C ? -1 : 0) + 1 = (C ? 0 : 1) */ + tgen_arithi(s, ARITH_ADD, dest, 1, 0); + } else if (!neg) { + /* -(C ? -1 : 0) = (C ? 1 : 0) */ + tcg_out_modrm(s, OPC_GRP3_Ev, EXT3_NEG, dest); } return; @@ -1588,7 +1595,8 @@ static void tcg_out_setcond(TCGContext *s, int rexw, TCGCond cond, if (inv) { tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_NOT, dest); } - tcg_out_shifti(s, SHIFT_SHR + rexw, dest, rexw ? 63 : 31); + tcg_out_shifti(s, (neg ? SHIFT_SAR : SHIFT_SHR) + rexw, + dest, rexw ? 63 : 31); return; } break; @@ -1614,6 +1622,9 @@ static void tcg_out_setcond(TCGContext *s, int rexw, TCGCond cond, if (!cleared) { tcg_out_ext8u(s, dest, dest); } + if (neg) { + tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_NEG, dest); + } } #if TCG_TARGET_REG_BITS == 32 @@ -2632,7 +2643,10 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, arg_label(args[3]), 0); break; OP_32_64(setcond): - tcg_out_setcond(s, rexw, args[3], a0, a1, a2, const_a2); + tcg_out_setcond(s, rexw, args[3], a0, a1, a2, const_a2, false); + break; + OP_32_64(negsetcond): + tcg_out_setcond(s, rexw, args[3], a0, a1, a2, const_a2, true); break; OP_32_64(movcond): tcg_out_movcond(s, rexw, args[5], a0, a1, a2, const_a2, args[3]); @@ -3377,6 +3391,8 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) case INDEX_op_setcond_i32: case INDEX_op_setcond_i64: + case INDEX_op_negsetcond_i32: + case INDEX_op_negsetcond_i64: return C_O1_I2(q, r, re); case INDEX_op_movcond_i32: diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h index ebc0b1a6ce..8417ea4899 100644 --- a/tcg/i386/tcg-target.h +++ b/tcg/i386/tcg-target.h @@ -150,7 +150,7 @@ typedef enum { #define TCG_TARGET_HAS_sextract_i32 1 #define TCG_TARGET_HAS_extract2_i32 1 #define TCG_TARGET_HAS_movcond_i32 1 -#define TCG_TARGET_HAS_negsetcond_i32 0 +#define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_mulu2_i32 1 @@ -187,7 +187,7 @@ typedef enum { #define TCG_TARGET_HAS_sextract_i64 0 #define TCG_TARGET_HAS_extract2_i64 1 #define TCG_TARGET_HAS_movcond_i64 1 -#define TCG_TARGET_HAS_negsetcond_i64 0 +#define TCG_TARGET_HAS_negsetcond_i64 1 #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 #define TCG_TARGET_HAS_mulu2_i64 1 From 4de5a76a923e1afab28bfbf9d19b67368bf98fb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 23 Aug 2023 16:55:35 +0200 Subject: [PATCH 1237/1353] tcg/tcg-op: Document bswap16_i32() byte pattern MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20230823145542.79633-2-philmd@linaro.org> Signed-off-by: Richard Henderson --- tcg/tcg-op.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index b59a50a5a9..fc3a0ab7fc 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -1035,6 +1035,14 @@ void tcg_gen_ext16u_i32(TCGv_i32 ret, TCGv_i32 arg) } } +/* + * bswap16_i32: 16-bit byte swap on the low bits of a 32-bit value. + * + * Byte pattern: xxab -> yyba + * + * With TCG_BSWAP_IZ, x == zero, else undefined. + * With TCG_BSWAP_OZ, y == zero, with TCG_BSWAP_OS y == sign, else undefined. + */ void tcg_gen_bswap16_i32(TCGv_i32 ret, TCGv_i32 arg, int flags) { /* Only one extension flag may be present. */ @@ -1046,22 +1054,25 @@ void tcg_gen_bswap16_i32(TCGv_i32 ret, TCGv_i32 arg, int flags) TCGv_i32 t0 = tcg_temp_ebb_new_i32(); TCGv_i32 t1 = tcg_temp_ebb_new_i32(); - tcg_gen_shri_i32(t0, arg, 8); + /* arg = ..ab (IZ) xxab (!IZ) */ + tcg_gen_shri_i32(t0, arg, 8); /* t0 = ...a (IZ) .xxa (!IZ) */ if (!(flags & TCG_BSWAP_IZ)) { - tcg_gen_ext8u_i32(t0, t0); + tcg_gen_ext8u_i32(t0, t0); /* t0 = ...a */ } if (flags & TCG_BSWAP_OS) { - tcg_gen_shli_i32(t1, arg, 24); - tcg_gen_sari_i32(t1, t1, 16); + tcg_gen_shli_i32(t1, arg, 24); /* t1 = b... */ + tcg_gen_sari_i32(t1, t1, 16); /* t1 = ssb. */ } else if (flags & TCG_BSWAP_OZ) { - tcg_gen_ext8u_i32(t1, arg); - tcg_gen_shli_i32(t1, t1, 8); + tcg_gen_ext8u_i32(t1, arg); /* t1 = ...b */ + tcg_gen_shli_i32(t1, t1, 8); /* t1 = ..b. */ } else { - tcg_gen_shli_i32(t1, arg, 8); + tcg_gen_shli_i32(t1, arg, 8); /* t1 = xab. */ } - tcg_gen_or_i32(ret, t0, t1); + tcg_gen_or_i32(ret, t0, t1); /* ret = ..ba (OZ) */ + /* = ssba (OS) */ + /* = xaba (no flag) */ tcg_temp_free_i32(t0); tcg_temp_free_i32(t1); } From 8b078800ab23c38e07a11dffbd88a988a6633152 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 23 Aug 2023 16:55:36 +0200 Subject: [PATCH 1238/1353] tcg/tcg-op: Document bswap16_i64() byte pattern MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20230823145542.79633-3-philmd@linaro.org> Signed-off-by: Richard Henderson --- tcg/tcg-op.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index fc3a0ab7fc..88c7c60ffe 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -1767,6 +1767,14 @@ void tcg_gen_ext32u_i64(TCGv_i64 ret, TCGv_i64 arg) } } +/* + * bswap16_i64: 16-bit byte swap on the low bits of a 64-bit value. + * + * Byte pattern: xxxxxxxxab -> yyyyyyyyba + * + * With TCG_BSWAP_IZ, x == zero, else undefined. + * With TCG_BSWAP_OZ, y == zero, with TCG_BSWAP_OS y == sign, else undefined. + */ void tcg_gen_bswap16_i64(TCGv_i64 ret, TCGv_i64 arg, int flags) { /* Only one extension flag may be present. */ @@ -1785,22 +1793,25 @@ void tcg_gen_bswap16_i64(TCGv_i64 ret, TCGv_i64 arg, int flags) TCGv_i64 t0 = tcg_temp_ebb_new_i64(); TCGv_i64 t1 = tcg_temp_ebb_new_i64(); - tcg_gen_shri_i64(t0, arg, 8); + /* arg = ......ab or xxxxxxab */ + tcg_gen_shri_i64(t0, arg, 8); /* t0 = .......a or .xxxxxxa */ if (!(flags & TCG_BSWAP_IZ)) { - tcg_gen_ext8u_i64(t0, t0); + tcg_gen_ext8u_i64(t0, t0); /* t0 = .......a */ } if (flags & TCG_BSWAP_OS) { - tcg_gen_shli_i64(t1, arg, 56); - tcg_gen_sari_i64(t1, t1, 48); + tcg_gen_shli_i64(t1, arg, 56); /* t1 = b....... */ + tcg_gen_sari_i64(t1, t1, 48); /* t1 = ssssssb. */ } else if (flags & TCG_BSWAP_OZ) { - tcg_gen_ext8u_i64(t1, arg); - tcg_gen_shli_i64(t1, t1, 8); + tcg_gen_ext8u_i64(t1, arg); /* t1 = .......b */ + tcg_gen_shli_i64(t1, t1, 8); /* t1 = ......b. */ } else { - tcg_gen_shli_i64(t1, arg, 8); + tcg_gen_shli_i64(t1, arg, 8); /* t1 = xxxxxab. */ } - tcg_gen_or_i64(ret, t0, t1); + tcg_gen_or_i64(ret, t0, t1); /* ret = ......ba (OZ) */ + /* ssssssba (OS) */ + /* xxxxxaba (no flag) */ tcg_temp_free_i64(t0); tcg_temp_free_i64(t1); } From 9296455697dbc423f0ca201f75d4e44bfcb68a5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 23 Aug 2023 16:55:37 +0200 Subject: [PATCH 1239/1353] tcg/tcg-op: Document bswap32_i32() byte pattern MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20230823145542.79633-4-philmd@linaro.org> Signed-off-by: Richard Henderson --- tcg/tcg-op.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 88c7c60ffe..ed0ab218a1 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -1078,6 +1078,11 @@ void tcg_gen_bswap16_i32(TCGv_i32 ret, TCGv_i32 arg, int flags) } } +/* + * bswap32_i32: 32-bit byte swap on a 32-bit value. + * + * Byte pattern: abcd -> dcba + */ void tcg_gen_bswap32_i32(TCGv_i32 ret, TCGv_i32 arg) { if (TCG_TARGET_HAS_bswap32_i32) { From 9c40621584622078dcf47bb9add9a05925105130 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 23 Aug 2023 16:55:38 +0200 Subject: [PATCH 1240/1353] tcg/tcg-op: Document bswap32_i64() byte pattern MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20230823145542.79633-5-philmd@linaro.org> Signed-off-by: Richard Henderson --- tcg/tcg-op.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index ed0ab218a1..b56ae748b8 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -1822,6 +1822,14 @@ void tcg_gen_bswap16_i64(TCGv_i64 ret, TCGv_i64 arg, int flags) } } +/* + * bswap32_i64: 32-bit byte swap on the low bits of a 64-bit value. + * + * Byte pattern: xxxxabcd -> yyyydcba + * + * With TCG_BSWAP_IZ, x == zero, else undefined. + * With TCG_BSWAP_OZ, y == zero, with TCG_BSWAP_OS y == sign, else undefined. + */ void tcg_gen_bswap32_i64(TCGv_i64 ret, TCGv_i64 arg, int flags) { /* Only one extension flag may be present. */ @@ -1855,7 +1863,8 @@ void tcg_gen_bswap32_i64(TCGv_i64 ret, TCGv_i64 arg, int flags) } else { tcg_gen_shri_i64(t1, t1, 32); /* t1 = ....dc.. */ } - tcg_gen_or_i64(ret, t0, t1); /* ret = ssssdcba */ + tcg_gen_or_i64(ret, t0, t1); /* ret = ssssdcba (OS) */ + /* ....dcba (else) */ tcg_temp_free_i64(t0); tcg_temp_free_i64(t1); From 95180e750b16ab21556b1073c3051a848911093a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 23 Aug 2023 16:55:39 +0200 Subject: [PATCH 1241/1353] tcg/tcg-op: Document bswap64_i64() byte pattern MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20230823145542.79633-6-philmd@linaro.org> Signed-off-by: Richard Henderson --- tcg/tcg-op.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index b56ae748b8..22c682c28e 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -1871,6 +1871,11 @@ void tcg_gen_bswap32_i64(TCGv_i64 ret, TCGv_i64 arg, int flags) } } +/* + * bswap64_i64: 64-bit byte swap on a 64-bit value. + * + * Byte pattern: abcdefgh -> hgfedcba + */ void tcg_gen_bswap64_i64(TCGv_i64 ret, TCGv_i64 arg) { if (TCG_TARGET_REG_BITS == 32) { From b8976aa5fe65e335af2eb5243a67d3b7fcd5442e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 23 Aug 2023 16:55:40 +0200 Subject: [PATCH 1242/1353] tcg/tcg-op: Document hswap_i32/64() byte pattern MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document hswap_i32() and hswap_i64(), added in commit 46be8425ff ("tcg: Implement tcg_gen_{h,w}swap_{i32,i64}"). Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20230823145542.79633-7-philmd@linaro.org> Signed-off-by: Richard Henderson --- tcg/tcg-op.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 22c682c28e..58572526b7 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -1108,6 +1108,11 @@ void tcg_gen_bswap32_i32(TCGv_i32 ret, TCGv_i32 arg) } } +/* + * hswap_i32: Swap 16-bit halfwords within a 32-bit value. + * + * Byte pattern: abcd -> cdab + */ void tcg_gen_hswap_i32(TCGv_i32 ret, TCGv_i32 arg) { /* Swapping 2 16-bit elements is a rotate. */ @@ -1921,19 +1926,25 @@ void tcg_gen_bswap64_i64(TCGv_i64 ret, TCGv_i64 arg) } } +/* + * hswap_i64: Swap 16-bit halfwords within a 64-bit value. + * See also include/qemu/bitops.h, hswap64. + * + * Byte pattern: abcdefgh -> ghefcdab + */ void tcg_gen_hswap_i64(TCGv_i64 ret, TCGv_i64 arg) { uint64_t m = 0x0000ffff0000ffffull; TCGv_i64 t0 = tcg_temp_ebb_new_i64(); TCGv_i64 t1 = tcg_temp_ebb_new_i64(); - /* See include/qemu/bitops.h, hswap64. */ - tcg_gen_rotli_i64(t1, arg, 32); - tcg_gen_andi_i64(t0, t1, m); - tcg_gen_shli_i64(t0, t0, 16); - tcg_gen_shri_i64(t1, t1, 16); - tcg_gen_andi_i64(t1, t1, m); - tcg_gen_or_i64(ret, t0, t1); + /* arg = abcdefgh */ + tcg_gen_rotli_i64(t1, arg, 32); /* t1 = efghabcd */ + tcg_gen_andi_i64(t0, t1, m); /* t0 = ..gh..cd */ + tcg_gen_shli_i64(t0, t0, 16); /* t0 = gh..cd.. */ + tcg_gen_shri_i64(t1, t1, 16); /* t1 = ..efghab */ + tcg_gen_andi_i64(t1, t1, m); /* t1 = ..ef..ab */ + tcg_gen_or_i64(ret, t0, t1); /* ret = ghefcdab */ tcg_temp_free_i64(t0); tcg_temp_free_i64(t1); From ad262fb56bd8b04a992f20c598286587080eb3c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 23 Aug 2023 16:55:41 +0200 Subject: [PATCH 1243/1353] tcg/tcg-op: Document wswap_i64() byte pattern MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document wswap_i64(), added in commit 46be8425ff ("tcg: Implement tcg_gen_{h,w}swap_{i32,i64}"). Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20230823145542.79633-8-philmd@linaro.org> Signed-off-by: Richard Henderson --- tcg/tcg-op.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 58572526b7..02a8cadcc0 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -1950,6 +1950,11 @@ void tcg_gen_hswap_i64(TCGv_i64 ret, TCGv_i64 arg) tcg_temp_free_i64(t1); } +/* + * wswap_i64: Swap 32-bit words within a 64-bit value. + * + * Byte pattern: abcdefgh -> efghabcd + */ void tcg_gen_wswap_i64(TCGv_i64 ret, TCGv_i64 arg) { /* Swapping 2 32-bit elements is a rotate. */ From 277561638f482f54f6e18f8206429cdc62294179 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 23 Aug 2023 16:55:42 +0200 Subject: [PATCH 1244/1353] target/cris: Fix a typo in gen_swapr() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20230823145542.79633-9-philmd@linaro.org> Signed-off-by: Richard Henderson --- target/cris/translate.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/target/cris/translate.c b/target/cris/translate.c index 0b3d724281..42103b5558 100644 --- a/target/cris/translate.c +++ b/target/cris/translate.c @@ -411,15 +411,17 @@ static inline void t_gen_swapw(TCGv d, TCGv s) tcg_gen_or_tl(d, d, t); } -/* Reverse the within each byte. - T0 = (((T0 << 7) & 0x80808080) | - ((T0 << 5) & 0x40404040) | - ((T0 << 3) & 0x20202020) | - ((T0 << 1) & 0x10101010) | - ((T0 >> 1) & 0x08080808) | - ((T0 >> 3) & 0x04040404) | - ((T0 >> 5) & 0x02020202) | - ((T0 >> 7) & 0x01010101)); +/* + * Reverse the bits within each byte. + * + * T0 = ((T0 << 7) & 0x80808080) + * | ((T0 << 5) & 0x40404040) + * | ((T0 << 3) & 0x20202020) + * | ((T0 << 1) & 0x10101010) + * | ((T0 >> 1) & 0x08080808) + * | ((T0 >> 3) & 0x04040404) + * | ((T0 >> 5) & 0x02020202) + * | ((T0 >> 7) & 0x01010101); */ static void t_gen_swapr(TCGv d, TCGv s) { From b08caa6d50d45debfb67822a3c667e12a29ba437 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 23 Aug 2023 15:17:40 +0100 Subject: [PATCH 1245/1353] docs/devel/tcg-ops: fix missing newlines in "Host vector operations" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This unintentionally causes the mov_vec, ld_vec and st_vec operations to appear on the same line. Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230823141740.35974-1-mark.cave-ayland@ilande.co.uk> Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index 9e2a931d85..8ae59ea02b 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -718,7 +718,9 @@ E.g. VECL = 1 -> 64 << 1 -> v128, and VECE = 2 -> 1 << 2 -> i32. .. list-table:: * - mov_vec *v0*, *v1* + ld_vec *v0*, *t1* + st_vec *v0*, *t1* - | Move, load and store. From 4daad8d9d6b9d426beb8ce505d2164ba36ea3168 Mon Sep 17 00:00:00 2001 From: Michael Tokarev Date: Wed, 23 Aug 2023 09:53:16 +0300 Subject: [PATCH 1246/1353] tcg: spelling fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Acked-by: Alex Bennée Signed-off-by: Michael Tokarev Message-Id: <20230823065335.1919380-4-mjt@tls.msk.ru> Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 2 +- tcg/arm/tcg-target.c.inc | 10 ++++++---- tcg/riscv/tcg-target.c.inc | 4 ++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 7d8d114c9e..0931a69448 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -3098,7 +3098,7 @@ static void tcg_target_qemu_prologue(TCGContext *s) #if !defined(CONFIG_SOFTMMU) /* * Note that XZR cannot be encoded in the address base register slot, - * as that actaully encodes SP. Depending on the guest, we may need + * as that actually encodes SP. Depending on the guest, we may need * to zero-extend the guest address via the address index register slot, * therefore we need to load even a zero guest base into a register. */ diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 162df38c73..acb5f23b54 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1216,9 +1216,11 @@ static TCGCond tcg_out_cmp2(TCGContext *s, const TCGArg *args, case TCG_COND_LEU: case TCG_COND_GTU: case TCG_COND_GEU: - /* We perform a conditional comparision. If the high half is - equal, then overwrite the flags with the comparison of the - low half. The resulting flags cover the whole. */ + /* + * We perform a conditional comparison. If the high half is + * equal, then overwrite the flags with the comparison of the + * low half. The resulting flags cover the whole. + */ tcg_out_dat_rI(s, COND_AL, ARITH_CMP, 0, ah, bh, const_bh); tcg_out_dat_rI(s, COND_EQ, ARITH_CMP, 0, al, bl, const_bl); return cond; @@ -1250,7 +1252,7 @@ static TCGCond tcg_out_cmp2(TCGContext *s, const TCGArg *args, /* * Note that TCGReg references Q-registers. - * Q-regno = 2 * D-regno, so shift left by 1 whlie inserting. + * Q-regno = 2 * D-regno, so shift left by 1 while inserting. */ static uint32_t encode_vd(TCGReg rd) { diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 232b616af3..9be81c1b7b 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -69,7 +69,7 @@ static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { static const int tcg_target_reg_alloc_order[] = { /* Call saved registers */ - /* TCG_REG_S0 reservered for TCG_AREG0 */ + /* TCG_REG_S0 reserved for TCG_AREG0 */ TCG_REG_S1, TCG_REG_S2, TCG_REG_S3, @@ -260,7 +260,7 @@ typedef enum { /* Zba: Bit manipulation extension, address generation */ OPC_ADD_UW = 0x0800003b, - /* Zbb: Bit manipulation extension, basic bit manipulaton */ + /* Zbb: Bit manipulation extension, basic bit manipulation */ OPC_ANDN = 0x40007033, OPC_CLZ = 0x60001013, OPC_CLZW = 0x6000101b, From c400b6ed877213ad3d87d0e27f260401a9194c7c Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Mon, 7 Aug 2023 11:17:59 +0200 Subject: [PATCH 1247/1353] target/hppa: Add missing PL1 and PL2 privilege levels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hppa CPU has 4 privilege levels (0-3). Mention the missing PL1 and PL2 levels, although the Linux kernel uses only 0 (KERNEL) and 3 (USER). Not sure about HP-UX. Signed-off-by: Helge Deller Reviewed-by: Philippe Mathieu-Daudé --- target/hppa/cpu.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h index 75c5c0ccf7..6c5b0e67c8 100644 --- a/target/hppa/cpu.h +++ b/target/hppa/cpu.h @@ -31,8 +31,11 @@ #define TCG_GUEST_DEFAULT_MO TCG_MO_ALL #define MMU_KERNEL_IDX 0 +#define MMU_PL1_IDX 1 +#define MMU_PL2_IDX 2 #define MMU_USER_IDX 3 #define MMU_PHYS_IDX 4 + #define TARGET_INSN_START_EXTRA_WORDS 1 /* Hardware exceptions, interrupts, faults, and traps. */ From c01e5dfb9a5b7a4c044e5da8840b6bc1175e5839 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Mon, 7 Aug 2023 11:32:09 +0200 Subject: [PATCH 1248/1353] target/hppa: Add privilege to MMU index conversion helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add two macros which convert privilege level to/from MMU index: - PRIV_TO_MMU_IDX(priv) returns the MMU index for the given privilege level - MMU_IDX_TO_PRIV(mmu_idx) returns the corresponding privilege level for this MMU index The introduction of those macros make the code easier to read and will help to improve performance in follow-up patch. Signed-off-by: Helge Deller Reviewed-by: Philippe Mathieu-Daudé --- target/hppa/cpu.h | 5 ++++- target/hppa/translate.c | 9 +++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h index 6c5b0e67c8..50b513f0ea 100644 --- a/target/hppa/cpu.h +++ b/target/hppa/cpu.h @@ -36,6 +36,9 @@ #define MMU_USER_IDX 3 #define MMU_PHYS_IDX 4 +#define PRIV_TO_MMU_IDX(priv) (priv) +#define MMU_IDX_TO_PRIV(mmu_idx) (mmu_idx) + #define TARGET_INSN_START_EXTRA_WORDS 1 /* Hardware exceptions, interrupts, faults, and traps. */ @@ -236,7 +239,7 @@ static inline int cpu_mmu_index(CPUHPPAState *env, bool ifetch) return MMU_USER_IDX; #else if (env->psw & (ifetch ? PSW_C : PSW_D)) { - return env->iaoq_f & 3; + return PRIV_TO_MMU_IDX(env->iaoq_f & 3); } return MMU_PHYS_IDX; /* mmu disabled */ #endif diff --git a/target/hppa/translate.c b/target/hppa/translate.c index d66fcb3e6a..e3af668252 100644 --- a/target/hppa/translate.c +++ b/target/hppa/translate.c @@ -4057,14 +4057,15 @@ static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) ctx->tb_flags = ctx->base.tb->flags; #ifdef CONFIG_USER_ONLY - ctx->privilege = MMU_USER_IDX; + ctx->privilege = MMU_IDX_TO_PRIV(MMU_USER_IDX); ctx->mmu_idx = MMU_USER_IDX; - ctx->iaoq_f = ctx->base.pc_first | MMU_USER_IDX; - ctx->iaoq_b = ctx->base.tb->cs_base | MMU_USER_IDX; + ctx->iaoq_f = ctx->base.pc_first | ctx->privilege; + ctx->iaoq_b = ctx->base.tb->cs_base | ctx->privilege; ctx->unalign = (ctx->tb_flags & TB_FLAG_UNALIGN ? MO_UNALN : MO_ALIGN); #else ctx->privilege = (ctx->tb_flags >> TB_FLAG_PRIV_SHIFT) & 3; - ctx->mmu_idx = (ctx->tb_flags & PSW_D ? ctx->privilege : MMU_PHYS_IDX); + ctx->mmu_idx = (ctx->tb_flags & PSW_D ? + PRIV_TO_MMU_IDX(ctx->privilege) : MMU_PHYS_IDX); /* Recover the IAOQ values from the GVA + PRIV. */ uint64_t cs_base = ctx->base.tb->cs_base; From 88b7ad10dd7cecfb5977f99175fe62ac2c511290 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Mon, 7 Aug 2023 11:42:11 +0200 Subject: [PATCH 1249/1353] target/hppa: Do not use hardcoded value for tlb_flush_*() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid using hardcoded values when calling the tlb_flush*() functions. Instead, define and use HPPA_MMU_FLUSH_MASK (keeping the current behavior, which doesn't flush the physical address MMU). Signed-off-by: Helge Deller Reviewed-by: Philippe Mathieu-Daudé --- target/hppa/cpu.h | 5 +++++ target/hppa/helper.c | 2 +- target/hppa/mem_helper.c | 7 +++---- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h index 50b513f0ea..6623712644 100644 --- a/target/hppa/cpu.h +++ b/target/hppa/cpu.h @@ -41,6 +41,11 @@ #define TARGET_INSN_START_EXTRA_WORDS 1 +/* No need to flush MMU_PHYS_IDX */ +#define HPPA_MMU_FLUSH_MASK \ + (1 << MMU_KERNEL_IDX | 1 << MMU_PL1_IDX | \ + 1 << MMU_PL2_IDX | 1 << MMU_USER_IDX) + /* Hardware exceptions, interrupts, faults, and traps. */ #define EXCP_HPMC 1 /* high priority machine check */ #define EXCP_POWER_FAIL 2 diff --git a/target/hppa/helper.c b/target/hppa/helper.c index 74b8747083..a8d3f456ee 100644 --- a/target/hppa/helper.c +++ b/target/hppa/helper.c @@ -71,7 +71,7 @@ void cpu_hppa_put_psw(CPUHPPAState *env, target_ureg psw) /* If PSW_P changes, it affects how we translate addresses. */ if ((psw ^ old_psw) & PSW_P) { #ifndef CONFIG_USER_ONLY - tlb_flush_by_mmuidx(env_cpu(env), 0xf); + tlb_flush_by_mmuidx(env_cpu(env), HPPA_MMU_FLUSH_MASK); #endif } } diff --git a/target/hppa/mem_helper.c b/target/hppa/mem_helper.c index 5046cc8f9d..6f04c101dd 100644 --- a/target/hppa/mem_helper.c +++ b/target/hppa/mem_helper.c @@ -50,8 +50,7 @@ static void hppa_flush_tlb_ent(CPUHPPAState *env, hppa_tlb_entry *ent) trace_hppa_tlb_flush_ent(env, ent, ent->va_b, ent->va_e, ent->pa); for (i = 0; i < n; ++i, addr += TARGET_PAGE_SIZE) { - /* Do not flush MMU_PHYS_IDX. */ - tlb_flush_page_by_mmuidx(cs, addr, 0xf); + tlb_flush_page_by_mmuidx(cs, addr, HPPA_MMU_FLUSH_MASK); } memset(ent, 0, sizeof(*ent)); @@ -335,13 +334,13 @@ void HELPER(ptlbe)(CPUHPPAState *env) { trace_hppa_tlb_ptlbe(env); memset(env->tlb, 0, sizeof(env->tlb)); - tlb_flush_by_mmuidx(env_cpu(env), 0xf); + tlb_flush_by_mmuidx(env_cpu(env), HPPA_MMU_FLUSH_MASK); } void cpu_hppa_change_prot_id(CPUHPPAState *env) { if (env->psw & PSW_P) { - tlb_flush_by_mmuidx(env_cpu(env), 0xf); + tlb_flush_by_mmuidx(env_cpu(env), HPPA_MMU_FLUSH_MASK); } } From 3d066afc68d469b2c7cbabf62d32421eef478a66 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Mon, 7 Aug 2023 11:52:39 +0200 Subject: [PATCH 1250/1353] target/hppa: Use privilege helper in hppa_get_physical_address() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert hppa_get_physical_address() to use the privilege helper macro. Signed-off-by: Helge Deller Reviewed-by: Philippe Mathieu-Daudé --- target/hppa/mem_helper.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/target/hppa/mem_helper.c b/target/hppa/mem_helper.c index 6f04c101dd..46c3dcaf15 100644 --- a/target/hppa/mem_helper.c +++ b/target/hppa/mem_helper.c @@ -73,7 +73,7 @@ int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx, int type, hwaddr *pphys, int *pprot) { hwaddr phys; - int prot, r_prot, w_prot, x_prot; + int prot, r_prot, w_prot, x_prot, priv; hppa_tlb_entry *ent; int ret = -1; @@ -97,9 +97,10 @@ int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx, phys = ent->pa + (addr & ~TARGET_PAGE_MASK); /* Map TLB access_rights field to QEMU protection. */ - r_prot = (mmu_idx <= ent->ar_pl1) * PAGE_READ; - w_prot = (mmu_idx <= ent->ar_pl2) * PAGE_WRITE; - x_prot = (ent->ar_pl2 <= mmu_idx && mmu_idx <= ent->ar_pl1) * PAGE_EXEC; + priv = MMU_IDX_TO_PRIV(mmu_idx); + r_prot = (priv <= ent->ar_pl1) * PAGE_READ; + w_prot = (priv <= ent->ar_pl2) * PAGE_WRITE; + x_prot = (ent->ar_pl2 <= priv && priv <= ent->ar_pl1) * PAGE_EXEC; switch (ent->ar_type) { case 0: /* read-only: data page */ prot = r_prot; From 2ad04500543094bc83f5f13dbb099000f010e008 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Mon, 7 Aug 2023 12:14:36 +0200 Subject: [PATCH 1251/1353] target/hppa: Switch to use MMU indices 11-15 The MMU indices 9-15 will use shorter assembler instructions when run on a x86-64 host. So, switch over to those to get smaller code and maybe minimally faster emulation. Signed-off-by: Helge Deller --- target/hppa/cpu.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h index 6623712644..fa13694dab 100644 --- a/target/hppa/cpu.h +++ b/target/hppa/cpu.h @@ -30,14 +30,14 @@ basis. It's probably easier to fall back to a strong memory model. */ #define TCG_GUEST_DEFAULT_MO TCG_MO_ALL -#define MMU_KERNEL_IDX 0 -#define MMU_PL1_IDX 1 -#define MMU_PL2_IDX 2 -#define MMU_USER_IDX 3 -#define MMU_PHYS_IDX 4 +#define MMU_KERNEL_IDX 11 +#define MMU_PL1_IDX 12 +#define MMU_PL2_IDX 13 +#define MMU_USER_IDX 14 +#define MMU_PHYS_IDX 15 -#define PRIV_TO_MMU_IDX(priv) (priv) -#define MMU_IDX_TO_PRIV(mmu_idx) (mmu_idx) +#define PRIV_TO_MMU_IDX(priv) (MMU_KERNEL_IDX + (priv)) +#define MMU_IDX_TO_PRIV(mmu_idx) ((mmu_idx) - MMU_KERNEL_IDX) #define TARGET_INSN_START_EXTRA_WORDS 1 From a3d3de8e1d4aff1343066e351020de9a6294c102 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 9 Aug 2023 10:13:43 +0200 Subject: [PATCH 1252/1353] configure: fix and complete detection of tricore tools The tricore tools are not detected when they are installed in the host system, only if they are taken from an external container. For this reason the build-tricore-softmmu job was not running the TCG tests. In addition the container provides all tools, not just as/ld/gcc, so there is no need to special case tricore. Signed-off-by: Paolo Bonzini --- configure | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/configure b/configure index 133f4e3235..f2bd8858d6 100755 --- a/configure +++ b/configure @@ -1271,6 +1271,7 @@ fi : ${cross_prefix_sh4="sh4-linux-gnu-"} : ${cross_prefix_sparc64="sparc64-linux-gnu-"} : ${cross_prefix_sparc="$cross_prefix_sparc64"} +: ${cross_prefix_tricore="tricore-"} : ${cross_prefix_x86_64="x86_64-linux-gnu-"} : ${cross_cc_aarch64_be="$cross_cc_aarch64"} @@ -1458,10 +1459,6 @@ probe_target_compiler() { tricore) container_image=debian-tricore-cross container_cross_prefix=tricore- - container_cross_as=tricore-as - container_cross_ld=tricore-ld - container_cross_cc=tricore-gcc - break ;; x86_64) container_image=debian-amd64-cross From 87f77f58d897314f0726374ce8f9cdf44ccd9c5b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 8 Aug 2023 16:02:57 +0200 Subject: [PATCH 1253/1353] dockerfiles: bump tricore cross compiler container to Debian 11 With the release of version 12 on June 10, 2023, Debian 10 is not supported anymore. Modify the cross compiler container to build on a newer version. Signed-off-by: Paolo Bonzini --- tests/docker/dockerfiles/debian-tricore-cross.docker | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/docker/dockerfiles/debian-tricore-cross.docker b/tests/docker/dockerfiles/debian-tricore-cross.docker index 269bfa8d42..5bd1963fb5 100644 --- a/tests/docker/dockerfiles/debian-tricore-cross.docker +++ b/tests/docker/dockerfiles/debian-tricore-cross.docker @@ -9,7 +9,7 @@ # # SPDX-License-Identifier: GPL-2.0-or-later # -FROM docker.io/library/debian:buster-slim +FROM docker.io/library/debian:11-slim MAINTAINER Philippe Mathieu-Daudé From 67b9a83daf384f3dc24e83f22da40e34da49021d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 8 Aug 2023 13:25:09 +0200 Subject: [PATCH 1254/1353] python: mkvenv: tweak the matching of --diagnose to depspecs Move the matching between the "absent" array and dep_specs[0] inside the loop, preparing for the possibility of having multiple canaries among the installed packages. Signed-off-by: Paolo Bonzini --- python/scripts/mkvenv.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python/scripts/mkvenv.py b/python/scripts/mkvenv.py index a47f1eaf5d..399659b22f 100644 --- a/python/scripts/mkvenv.py +++ b/python/scripts/mkvenv.py @@ -806,6 +806,7 @@ def _do_ensure( """ absent = [] present = [] + canary = None for spec in dep_specs: matcher = distlib.version.LegacyMatcher(spec) ver = _get_version(matcher.name) @@ -817,6 +818,8 @@ def _do_ensure( or not matcher.match(distlib.version.LegacyVersion(ver)) ): absent.append(spec) + if spec == dep_specs[0]: + canary = prog else: logger.info("found %s %s", matcher.name, ver) present.append(matcher.name) @@ -839,7 +842,7 @@ def _do_ensure( absent[0], online, wheels_dir, - prog if absent[0] == dep_specs[0] else None, + canary, ) return None From 0f1ec0705b92b79e5e5f69bed236639dae67d312 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 8 Aug 2023 09:47:25 +0200 Subject: [PATCH 1255/1353] python: mkvenv: introduce TOML-like representation of dependencies We would like to place all Python dependencies in the same file, so that we can add more information without having long and complex command lines. The plan is to have a TOML file with one entry per package, for example [avocado] avocado-framework = { accepted = "(>=88.1, <93.0)", installed = "88.1", canary = "avocado" } Each TOML section will thus be a dictionary of dictionaries. Modify mkvenv.py's workhorse function, _do_ensure, to already operate on such a data structure. The "ensure" subcommand is modified to separate the depspec into a name and a version part, and use the result (plus the --diagnose argument) to build a dictionary for each command line argument. Signed-off-by: Paolo Bonzini --- python/scripts/mkvenv.py | 77 +++++++++++++++++++++++++++++++--------- 1 file changed, 61 insertions(+), 16 deletions(-) diff --git a/python/scripts/mkvenv.py b/python/scripts/mkvenv.py index 399659b22f..96f506d7e2 100644 --- a/python/scripts/mkvenv.py +++ b/python/scripts/mkvenv.py @@ -46,6 +46,9 @@ options: """ +# The duplication between importlib and pkg_resources does not help +# pylint: disable=too-many-lines + # Copyright (C) 2022-2023 Red Hat, Inc. # # Authors: @@ -69,6 +72,7 @@ import sysconfig from types import SimpleNamespace from typing import ( Any, + Dict, Iterator, Optional, Sequence, @@ -786,43 +790,67 @@ def pip_install( ) +def _make_version_constraint(info: Dict[str, str], install: bool) -> str: + """ + Construct the version constraint part of a PEP 508 dependency + specification (for example '>=0.61.5') from the accepted and + installed keys of the provided dictionary. + + :param info: A dictionary corresponding to a TOML key-value list. + :param install: True generates install constraints, False generates + presence constraints + """ + if install and "installed" in info: + return "==" + info["installed"] + + dep_spec = info.get("accepted", "") + dep_spec = dep_spec.strip() + # Double check that they didn't just use a version number + if dep_spec and dep_spec[0] not in "!~><=(": + raise Ouch( + "invalid dependency specifier " + dep_spec + " in dependency file" + ) + + return dep_spec + + def _do_ensure( - dep_specs: Sequence[str], + group: Dict[str, Dict[str, str]], online: bool = False, wheels_dir: Optional[Union[str, Path]] = None, - prog: Optional[str] = None, ) -> Optional[Tuple[str, bool]]: """ - Use pip to ensure we have the package specified by @dep_specs. + Use pip to ensure we have the packages specified in @group. - If the package is already installed, do nothing. If online and + If the packages are already installed, do nothing. If online and wheels_dir are both provided, prefer packages found in wheels_dir first before connecting to PyPI. - :param dep_specs: - PEP 508 dependency specifications. e.g. ['meson>=0.61.5']. + :param group: A dictionary of dictionaries, corresponding to a + section in a pythondeps.toml file. :param online: If True, fall back to PyPI. :param wheels_dir: If specified, search this path for packages. """ absent = [] present = [] canary = None - for spec in dep_specs: - matcher = distlib.version.LegacyMatcher(spec) - ver = _get_version(matcher.name) + for name, info in group.items(): + constraint = _make_version_constraint(info, False) + matcher = distlib.version.LegacyMatcher(name + constraint) + ver = _get_version(name) if ( ver is None # Always pass installed package to pip, so that they can be # updated if the requested version changes - or not _is_system_package(matcher.name) + or not _is_system_package(name) or not matcher.match(distlib.version.LegacyVersion(ver)) ): - absent.append(spec) - if spec == dep_specs[0]: - canary = prog + absent.append(name + _make_version_constraint(info, True)) + if len(absent) == 1: + canary = info.get("canary", None) else: - logger.info("found %s %s", matcher.name, ver) - present.append(matcher.name) + logger.info("found %s %s", name, ver) + present.append(name) if present: generate_console_scripts(present) @@ -875,7 +903,24 @@ def ensure( if not HAVE_DISTLIB: raise Ouch("a usable distlib could not be found, please install it") - result = _do_ensure(dep_specs, online, wheels_dir, prog) + # Convert the depspecs to a dictionary, as if they came + # from a section in a pythondeps.toml file + group: Dict[str, Dict[str, str]] = {} + for spec in dep_specs: + name = distlib.version.LegacyMatcher(spec).name + group[name] = {} + + spec = spec.strip() + pos = len(name) + ver = spec[pos:].strip() + if ver: + group[name]["accepted"] = ver + + if prog: + group[name]["canary"] = prog + prog = None + + result = _do_ensure(group, online, wheels_dir) if result: # Well, that's not good. if result[1]: From 71ed611cd47d961e1897721d7d002ffb498221d4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 8 Aug 2023 10:03:42 +0200 Subject: [PATCH 1256/1353] python: mkvenv: add ensuregroup command Introduce a new subcommand that retrieves the packages to be installed from a TOML file. This allows being more flexible in using the system version of a package, while at the same time using a known-good version when installing the package. This is important for packages that sometimes have backwards-incompatible changes or that depend on specific versions of their dependencies. Compared to JSON, TOML is more human readable and easier to edit. A parser is available in 3.11 but also available as a small (12k) package for older versions, tomli. While tomli is bundled with pip, this is only true of recent versions of pip. Of all the supported OSes pretty much only FreeBSD has a recent enough version of pip while staying on Python <3.11. So we cannot use the same trick that is in place for distlib. Signed-off-by: Paolo Bonzini --- python/scripts/mkvenv.py | 126 ++++++++++++++++++++++++++++++++++++++- python/setup.cfg | 6 ++ pythondeps.toml | 17 ++++++ 3 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 pythondeps.toml diff --git a/python/scripts/mkvenv.py b/python/scripts/mkvenv.py index 96f506d7e2..02bcd9a8c9 100644 --- a/python/scripts/mkvenv.py +++ b/python/scripts/mkvenv.py @@ -14,6 +14,8 @@ Commands: post_init post-venv initialization ensure Ensure that the specified package is installed. + ensuregroup + Ensure that the specified package group is installed. -------------------------------------------------- @@ -44,6 +46,19 @@ options: --online Install packages from PyPI, if necessary. --dir DIR Path to vendored packages where we may install from. +-------------------------------------------------- + +usage: mkvenv ensuregroup [-h] [--online] [--dir DIR] file group... + +positional arguments: + file pointer to a TOML file + group section name in the TOML file + +options: + -h, --help show this help message and exit + --online Install packages from PyPI, if necessary. + --dir DIR Path to vendored packages where we may install from. + """ # The duplication between importlib and pkg_resources does not help @@ -99,6 +114,18 @@ except ImportError: except ImportError: HAVE_DISTLIB = False +# Try to load tomllib, with a fallback to tomli. +# HAVE_TOMLLIB is checked below, just-in-time, so that mkvenv does not fail +# outside the venv or before a potential call to ensurepip in checkpip(). +HAVE_TOMLLIB = True +try: + import tomllib +except ImportError: + try: + import tomli as tomllib + except ImportError: + HAVE_TOMLLIB = False + # Do not add any mandatory dependencies from outside the stdlib: # This script *must* be usable standalone! @@ -837,6 +864,7 @@ def _do_ensure( for name, info in group.items(): constraint = _make_version_constraint(info, False) matcher = distlib.version.LegacyMatcher(name + constraint) + print(f"mkvenv: checking for {matcher}", file=sys.stderr) ver = _get_version(name) if ( ver is None @@ -898,7 +926,6 @@ def ensure( be presented to the user. e.g., 'sphinx-build' can be used as a bellwether for the presence of 'sphinx'. """ - print(f"mkvenv: checking for {', '.join(dep_specs)}", file=sys.stderr) if not HAVE_DISTLIB: raise Ouch("a usable distlib could not be found, please install it") @@ -928,6 +955,64 @@ def ensure( raise SystemExit(f"\n{result[0]}\n\n") +def _parse_groups(file: str) -> Dict[str, Dict[str, Any]]: + if not HAVE_TOMLLIB: + if sys.version_info < (3, 11): + raise Ouch("found no usable tomli, please install it") + + raise Ouch( + "Python >=3.11 does not have tomllib... what have you done!?" + ) + + try: + # Use loads() to support both tomli v1.2.x (Ubuntu 22.04, + # Debian bullseye-backports) and v2.0.x + with open(file, "r", encoding="ascii") as depfile: + contents = depfile.read() + return tomllib.loads(contents) # type: ignore + except tomllib.TOMLDecodeError as exc: + raise Ouch(f"parsing {file} failed: {exc}") from exc + + +def ensure_group( + file: str, + groups: Sequence[str], + online: bool = False, + wheels_dir: Optional[Union[str, Path]] = None, +) -> None: + """ + Use pip to ensure we have the package specified by @dep_specs. + + If the package is already installed, do nothing. If online and + wheels_dir are both provided, prefer packages found in wheels_dir + first before connecting to PyPI. + + :param dep_specs: + PEP 508 dependency specifications. e.g. ['meson>=0.61.5']. + :param online: If True, fall back to PyPI. + :param wheels_dir: If specified, search this path for packages. + """ + + if not HAVE_DISTLIB: + raise Ouch("found no usable distlib, please install it") + + parsed_deps = _parse_groups(file) + + to_install: Dict[str, Dict[str, str]] = {} + for group in groups: + try: + to_install.update(parsed_deps[group]) + except KeyError as exc: + raise Ouch(f"group {group} not defined") from exc + + result = _do_ensure(to_install, online, wheels_dir) + if result: + # Well, that's not good. + if result[1]: + raise Ouch(result[0]) + raise SystemExit(f"\n{result[0]}\n\n") + + def post_venv_setup() -> None: """ This is intended to be run *inside the venv* after it is created. @@ -955,6 +1040,37 @@ def _add_post_init_subcommand(subparsers: Any) -> None: subparsers.add_parser("post_init", help="post-venv initialization") +def _add_ensuregroup_subcommand(subparsers: Any) -> None: + subparser = subparsers.add_parser( + "ensuregroup", + help="Ensure that the specified package group is installed.", + ) + subparser.add_argument( + "--online", + action="store_true", + help="Install packages from PyPI, if necessary.", + ) + subparser.add_argument( + "--dir", + type=str, + action="store", + help="Path to vendored packages where we may install from.", + ) + subparser.add_argument( + "file", + type=str, + action="store", + help=("Path to a TOML file describing package groups"), + ) + subparser.add_argument( + "group", + type=str, + action="store", + help="One or more package group names", + nargs="+", + ) + + def _add_ensure_subcommand(subparsers: Any) -> None: subparser = subparsers.add_parser( "ensure", help="Ensure that the specified package is installed." @@ -1012,6 +1128,7 @@ def main() -> int: _add_create_subcommand(subparsers) _add_post_init_subcommand(subparsers) _add_ensure_subcommand(subparsers) + _add_ensuregroup_subcommand(subparsers) args = parser.parse_args() try: @@ -1030,6 +1147,13 @@ def main() -> int: wheels_dir=args.dir, prog=args.diagnose, ) + if args.command == "ensuregroup": + ensure_group( + file=args.file, + groups=args.group, + online=args.online, + wheels_dir=args.dir, + ) logger.debug("mkvenv.py %s: exiting", args.command) except Ouch as exc: print("\n*** Ouch! ***\n", file=sys.stderr) diff --git a/python/setup.cfg b/python/setup.cfg index 5d7e95f5d2..e74b58a8c2 100644 --- a/python/setup.cfg +++ b/python/setup.cfg @@ -94,6 +94,12 @@ allow_subclassing_any = True [mypy-fuse] ignore_missing_imports = True +[mypy-tomli] +ignore_missing_imports = True + +[mypy-tomllib] +ignore_missing_imports = True + [mypy-urwid] ignore_missing_imports = True diff --git a/pythondeps.toml b/pythondeps.toml new file mode 100644 index 0000000000..362f63ff2c --- /dev/null +++ b/pythondeps.toml @@ -0,0 +1,17 @@ +# This file describes Python package requirements to be +# installed in the pyvenv Python virtual environment. +# +# Packages are placed in groups, which are installed using +# the ensuregroup subcommand of python/scripts/mkvenv.py. +# Each group forms a TOML section and each entry in the +# section is a TOML key-value list describing a package. +# All fields are optional; valid fields are: +# +# - accepted: accepted versions when using a system package +# - installed: fixed version to install in the virtual environment +# if a system package is not found; if not specified, +# the minimum and maximum +# - canary: if specified, use this program name to present more +# precise error diagnostics to the user. For example, +# 'sphinx-build' can be used as a bellwether for the +# presence of 'sphinx' in the system. From dcb8541b0b726e18af7bb32acc6eea383d3b75af Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 8 Aug 2023 15:31:22 +0200 Subject: [PATCH 1257/1353] lcitool: bump libvirt-ci submodule and regenerate This brings in a newer version of the pipewire mapping, so rename it. Python 3.9 and 3.10 do not seem to work in OpenSUSE LEAP 15.5 (weird, because 3.9 persisted from 15.3 to 15.4) so bump the Python runtime version to 3.11. Signed-off-by: Paolo Bonzini --- .../dockerfiles/debian-amd64-cross.docker | 2 +- .../dockerfiles/debian-arm64-cross.docker | 2 +- .../dockerfiles/debian-armel-cross.docker | 2 +- .../dockerfiles/debian-armhf-cross.docker | 2 +- .../dockerfiles/debian-mips64el-cross.docker | 2 +- .../dockerfiles/debian-mipsel-cross.docker | 2 +- .../dockerfiles/debian-ppc64el-cross.docker | 2 +- .../dockerfiles/debian-riscv64-cross.docker | 2 +- .../dockerfiles/debian-s390x-cross.docker | 2 +- .../dockerfiles/fedora-win32-cross.docker | 2 +- .../dockerfiles/fedora-win64-cross.docker | 2 +- tests/docker/dockerfiles/opensuse-leap.docker | 22 +++++++++---------- tests/lcitool/libvirt-ci | 2 +- tests/lcitool/mappings.yml | 12 +++++----- tests/lcitool/projects/qemu.yml | 2 +- tests/lcitool/targets/opensuse-leap-15.yml | 4 ++-- 16 files changed, 32 insertions(+), 32 deletions(-) diff --git a/tests/docker/dockerfiles/debian-amd64-cross.docker b/tests/docker/dockerfiles/debian-amd64-cross.docker index b7bdc01243..b9871f9c8c 100644 --- a/tests/docker/dockerfiles/debian-amd64-cross.docker +++ b/tests/docker/dockerfiles/debian-amd64-cross.docker @@ -1,6 +1,6 @@ # THIS FILE WAS AUTO-GENERATED # -# $ lcitool dockerfile --layers all --cross x86_64 debian-11 qemu +# $ lcitool dockerfile --layers all --cross-arch x86_64 debian-11 qemu # # https://gitlab.com/libvirt/libvirt-ci diff --git a/tests/docker/dockerfiles/debian-arm64-cross.docker b/tests/docker/dockerfiles/debian-arm64-cross.docker index 68165c2f23..3504c771a7 100644 --- a/tests/docker/dockerfiles/debian-arm64-cross.docker +++ b/tests/docker/dockerfiles/debian-arm64-cross.docker @@ -1,6 +1,6 @@ # THIS FILE WAS AUTO-GENERATED # -# $ lcitool dockerfile --layers all --cross aarch64 debian-11 qemu +# $ lcitool dockerfile --layers all --cross-arch aarch64 debian-11 qemu # # https://gitlab.com/libvirt/libvirt-ci diff --git a/tests/docker/dockerfiles/debian-armel-cross.docker b/tests/docker/dockerfiles/debian-armel-cross.docker index 2fb65308c7..6d11c9510f 100644 --- a/tests/docker/dockerfiles/debian-armel-cross.docker +++ b/tests/docker/dockerfiles/debian-armel-cross.docker @@ -1,6 +1,6 @@ # THIS FILE WAS AUTO-GENERATED # -# $ lcitool dockerfile --layers all --cross armv6l debian-11 qemu +# $ lcitool dockerfile --layers all --cross-arch armv6l debian-11 qemu # # https://gitlab.com/libvirt/libvirt-ci diff --git a/tests/docker/dockerfiles/debian-armhf-cross.docker b/tests/docker/dockerfiles/debian-armhf-cross.docker index df77ccb57b..37ae575cf7 100644 --- a/tests/docker/dockerfiles/debian-armhf-cross.docker +++ b/tests/docker/dockerfiles/debian-armhf-cross.docker @@ -1,6 +1,6 @@ # THIS FILE WAS AUTO-GENERATED # -# $ lcitool dockerfile --layers all --cross armv7l debian-11 qemu +# $ lcitool dockerfile --layers all --cross-arch armv7l debian-11 qemu # # https://gitlab.com/libvirt/libvirt-ci diff --git a/tests/docker/dockerfiles/debian-mips64el-cross.docker b/tests/docker/dockerfiles/debian-mips64el-cross.docker index 63a3d7aa3b..26ed730165 100644 --- a/tests/docker/dockerfiles/debian-mips64el-cross.docker +++ b/tests/docker/dockerfiles/debian-mips64el-cross.docker @@ -1,6 +1,6 @@ # THIS FILE WAS AUTO-GENERATED # -# $ lcitool dockerfile --layers all --cross mips64el debian-11 qemu +# $ lcitool dockerfile --layers all --cross-arch mips64el debian-11 qemu # # https://gitlab.com/libvirt/libvirt-ci diff --git a/tests/docker/dockerfiles/debian-mipsel-cross.docker b/tests/docker/dockerfiles/debian-mipsel-cross.docker index ac87bbb095..ade2f37ed1 100644 --- a/tests/docker/dockerfiles/debian-mipsel-cross.docker +++ b/tests/docker/dockerfiles/debian-mipsel-cross.docker @@ -1,6 +1,6 @@ # THIS FILE WAS AUTO-GENERATED # -# $ lcitool dockerfile --layers all --cross mipsel debian-11 qemu +# $ lcitool dockerfile --layers all --cross-arch mipsel debian-11 qemu # # https://gitlab.com/libvirt/libvirt-ci diff --git a/tests/docker/dockerfiles/debian-ppc64el-cross.docker b/tests/docker/dockerfiles/debian-ppc64el-cross.docker index def11f1693..08dcffa0a8 100644 --- a/tests/docker/dockerfiles/debian-ppc64el-cross.docker +++ b/tests/docker/dockerfiles/debian-ppc64el-cross.docker @@ -1,6 +1,6 @@ # THIS FILE WAS AUTO-GENERATED # -# $ lcitool dockerfile --layers all --cross ppc64le debian-11 qemu +# $ lcitool dockerfile --layers all --cross-arch ppc64le debian-11 qemu # # https://gitlab.com/libvirt/libvirt-ci diff --git a/tests/docker/dockerfiles/debian-riscv64-cross.docker b/tests/docker/dockerfiles/debian-riscv64-cross.docker index a2d879ee1f..a26637ec4f 100644 --- a/tests/docker/dockerfiles/debian-riscv64-cross.docker +++ b/tests/docker/dockerfiles/debian-riscv64-cross.docker @@ -1,6 +1,6 @@ # THIS FILE WAS AUTO-GENERATED # -# $ lcitool dockerfile --layers all --cross riscv64 debian-sid qemu-minimal +# $ lcitool dockerfile --layers all --cross-arch riscv64 debian-sid qemu-minimal # # https://gitlab.com/libvirt/libvirt-ci diff --git a/tests/docker/dockerfiles/debian-s390x-cross.docker b/tests/docker/dockerfiles/debian-s390x-cross.docker index 80028e1eea..48a2c10fdb 100644 --- a/tests/docker/dockerfiles/debian-s390x-cross.docker +++ b/tests/docker/dockerfiles/debian-s390x-cross.docker @@ -1,6 +1,6 @@ # THIS FILE WAS AUTO-GENERATED # -# $ lcitool dockerfile --layers all --cross s390x debian-11 qemu +# $ lcitool dockerfile --layers all --cross-arch s390x debian-11 qemu # # https://gitlab.com/libvirt/libvirt-ci diff --git a/tests/docker/dockerfiles/fedora-win32-cross.docker b/tests/docker/dockerfiles/fedora-win32-cross.docker index e3dfd68bed..afa988574f 100644 --- a/tests/docker/dockerfiles/fedora-win32-cross.docker +++ b/tests/docker/dockerfiles/fedora-win32-cross.docker @@ -1,6 +1,6 @@ # THIS FILE WAS AUTO-GENERATED # -# $ lcitool dockerfile --layers all --cross mingw32 fedora-38 qemu +# $ lcitool dockerfile --layers all --cross-arch mingw32 fedora-38 qemu # # https://gitlab.com/libvirt/libvirt-ci diff --git a/tests/docker/dockerfiles/fedora-win64-cross.docker b/tests/docker/dockerfiles/fedora-win64-cross.docker index 0e15c9643a..cf93a0ca60 100644 --- a/tests/docker/dockerfiles/fedora-win64-cross.docker +++ b/tests/docker/dockerfiles/fedora-win64-cross.docker @@ -1,6 +1,6 @@ # THIS FILE WAS AUTO-GENERATED # -# $ lcitool dockerfile --layers all --cross mingw64 fedora-38 qemu +# $ lcitool dockerfile --layers all --cross-arch mingw64 fedora-38 qemu # # https://gitlab.com/libvirt/libvirt-ci diff --git a/tests/docker/dockerfiles/opensuse-leap.docker b/tests/docker/dockerfiles/opensuse-leap.docker index 37c83e5e4e..fef8d5a2e4 100644 --- a/tests/docker/dockerfiles/opensuse-leap.docker +++ b/tests/docker/dockerfiles/opensuse-leap.docker @@ -4,7 +4,7 @@ # # https://gitlab.com/libvirt/libvirt-ci -FROM registry.opensuse.org/opensuse/leap:15.4 +FROM registry.opensuse.org/opensuse/leap:15.5 RUN zypper update -y && \ zypper install -y \ @@ -90,9 +90,9 @@ RUN zypper update -y && \ pcre-devel-static \ pipewire-devel \ pkgconfig \ - python39-base \ - python39-pip \ - python39-setuptools \ + python311-base \ + python311-pip \ + python311-setuptools \ rdma-core-devel \ sed \ snappy-devel \ @@ -125,18 +125,18 @@ RUN zypper update -y && \ ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/g++ && \ ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc -RUN /usr/bin/pip3.9 install \ - PyYAML \ - meson==0.63.2 \ - pillow \ - sphinx \ - sphinx-rtd-theme +RUN /usr/bin/pip3.11 install \ + PyYAML \ + meson==0.63.2 \ + pillow \ + sphinx \ + sphinx-rtd-theme ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" ENV LANG "en_US.UTF-8" ENV MAKE "/usr/bin/make" ENV NINJA "/usr/bin/ninja" -ENV PYTHON "/usr/bin/python3.9" +ENV PYTHON "/usr/bin/python3.11" # As a final step configure the user (if env is defined) ARG USER ARG UID diff --git a/tests/lcitool/libvirt-ci b/tests/lcitool/libvirt-ci index 9bff3b763b..bbd55b4d18 160000 --- a/tests/lcitool/libvirt-ci +++ b/tests/lcitool/libvirt-ci @@ -1 +1 @@ -Subproject commit 9bff3b763b5531a1490e238bfbf77306dc3a6dbb +Subproject commit bbd55b4d18cce8f89b5167675e434a6941315634 diff --git a/tests/lcitool/mappings.yml b/tests/lcitool/mappings.yml index 454963f07b..3c554099ed 100644 --- a/tests/lcitool/mappings.yml +++ b/tests/lcitool/mappings.yml @@ -9,7 +9,7 @@ mappings: python3: CentOSStream8: python38 - OpenSUSELeap15: python39-base + OpenSUSELeap15: python311-base python3-PyYAML: CentOSStream8: python38-PyYAML @@ -17,7 +17,7 @@ mappings: python3-devel: CentOSStream8: python38-devel - OpenSUSELeap15: python39-devel + OpenSUSELeap15: python311-devel python3-docutils: CentOSStream8: @@ -37,7 +37,7 @@ mappings: python3-pip: CentOSStream8: python38-pip - OpenSUSELeap15: python39-pip + OpenSUSELeap15: python311-pip python3-pillow: CentOSStream8: @@ -49,7 +49,7 @@ mappings: python3-setuptools: CentOSStream8: python38-setuptools - OpenSUSELeap15: python39-setuptools + OpenSUSELeap15: python311-setuptools python3-sphinx: CentOSStream8: @@ -61,11 +61,11 @@ mappings: python3-venv: CentOSStream8: python38 - OpenSUSELeap15: python39-base + OpenSUSELeap15: python311-base python3-wheel: CentOSStream8: python38-wheel - OpenSUSELeap15: python39-pip + OpenSUSELeap15: python311-pip pypi_mappings: # Request more recent version diff --git a/tests/lcitool/projects/qemu.yml b/tests/lcitool/projects/qemu.yml index d452a891ee..2d31cf792a 100644 --- a/tests/lcitool/projects/qemu.yml +++ b/tests/lcitool/projects/qemu.yml @@ -85,7 +85,7 @@ packages: - pam - pcre-static - pixman - - pipewire + - libpipewire-dev - pkg-config - pulseaudio - python3 diff --git a/tests/lcitool/targets/opensuse-leap-15.yml b/tests/lcitool/targets/opensuse-leap-15.yml index 683016e007..c2d87f6cb4 100644 --- a/tests/lcitool/targets/opensuse-leap-15.yml +++ b/tests/lcitool/targets/opensuse-leap-15.yml @@ -1,3 +1,3 @@ paths: - pip3: /usr/bin/pip3.9 - python: /usr/bin/python3.9 + pip3: /usr/bin/pip3.11 + python: /usr/bin/python3.11 From 7c3fb52bcdaef85b15a91b3ca4d1516f9d9b5402 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 8 Aug 2023 20:28:25 +0200 Subject: [PATCH 1258/1353] configure: never use PyPI for Meson Since there is a vendored copy, there is no point in choosing online operation. Signed-off-by: Paolo Bonzini --- configure | 6 ------ 1 file changed, 6 deletions(-) diff --git a/configure b/configure index f2bd8858d6..f13f0662b9 100755 --- a/configure +++ b/configure @@ -1018,13 +1018,7 @@ fi python="$python -B" mkvenv="$python ${source_path}/python/scripts/mkvenv.py" -mkvenv_flags="" -if test "$download" = "enabled" ; then - mkvenv_flags="--online" -fi - if ! $mkvenv ensure \ - $mkvenv_flags \ --dir "${source_path}/python/wheels" \ --diagnose "meson" \ "meson>=0.63.0" ; From edc2107895007d621fe474d58bcb99036c8e55d2 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 8 Aug 2023 20:19:43 +0200 Subject: [PATCH 1259/1353] python: use vendored tomli Debian only introduced tomli in the bookworm release. Use a vendored wheel to avoid requiring a package that is only in bullseye-backports and is also absent in Ubuntu 20.04. While at it, fix an issue in the vendor.py scripts which does not add a newline after each package and hash. Signed-off-by: Paolo Bonzini --- configure | 6 ++++++ python/scripts/vendor.py | 5 ++++- python/wheels/tomli-2.0.1-py3-none-any.whl | Bin 0 -> 12757 bytes 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 python/wheels/tomli-2.0.1-py3-none-any.whl diff --git a/configure b/configure index f13f0662b9..347153702c 100755 --- a/configure +++ b/configure @@ -1018,6 +1018,12 @@ fi python="$python -B" mkvenv="$python ${source_path}/python/scripts/mkvenv.py" +# Finish preparing the virtual environment using vendored .whl files + +if $python -c 'import sys; sys.exit(sys.version_info >= (3,11))'; then + $mkvenv ensure --dir "${source_path}/python/wheels" \ + 'tomli>=1.2.0' || exit 1 +fi if ! $mkvenv ensure \ --dir "${source_path}/python/wheels" \ --diagnose "meson" \ diff --git a/python/scripts/vendor.py b/python/scripts/vendor.py index 34486a51f4..7627487117 100755 --- a/python/scripts/vendor.py +++ b/python/scripts/vendor.py @@ -43,13 +43,16 @@ def main() -> int: packages = { "meson==0.63.3": "d677b809c4895dcbaac9bf6c43703fcb3609a4b24c6057c78f828590049cf43a", + + "tomli==2.0.1": + "939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", } vendor_dir = Path(__file__, "..", "..", "wheels").resolve() with tempfile.NamedTemporaryFile(mode="w", encoding="utf-8") as file: for dep_spec, checksum in packages.items(): - file.write(f"{dep_spec} --hash=sha256:{checksum}") + print(f"{dep_spec} --hash=sha256:{checksum}", file=file) file.flush() cli_args = [ diff --git a/python/wheels/tomli-2.0.1-py3-none-any.whl b/python/wheels/tomli-2.0.1-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..29670b98d16e2bc770d4fea718582e1dc0dd8aca GIT binary patch literal 12757 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

;mAt+>gV7*{n<(t#6)oNmB+~P1uzZMb~^P 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 Date: Tue, 8 Aug 2023 11:23:48 +0200 Subject: [PATCH 1260/1353] configure: switch to ensuregroup Using the new ensuregroup command, the desired versions of meson and sphinx can be placed in pythondeps.toml rather than configure. The meson.install entry in pythondeps.toml matches the version that is found in python/wheels. This ensures that mkvenv.py uses the bundled wheel even if PyPI is enabled; thus not introducing warnings or errors from versions that are more recent than the one used in CI. The sphinx entries match what is shipped in Fedora 38. It's the last release that has support for older versions of Python (sphinx 6.0 requires Python 3.8) and especially docutils (of which sphinx 6.0 requires version 0.18). This is important because Ubuntu 20.04 has docutils 0.14 and Debian 11 has docutils 0.16. "mkvenv.py ensure" is only used to bootstrap tomli. Signed-off-by: Paolo Bonzini --- configure | 14 ++++---------- pythondeps.toml | 8 ++++++++ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/configure b/configure index 347153702c..e4d42d640e 100755 --- a/configure +++ b/configure @@ -1024,13 +1024,8 @@ if $python -c 'import sys; sys.exit(sys.version_info >= (3,11))'; then $mkvenv ensure --dir "${source_path}/python/wheels" \ 'tomli>=1.2.0' || exit 1 fi -if ! $mkvenv ensure \ - --dir "${source_path}/python/wheels" \ - --diagnose "meson" \ - "meson>=0.63.0" ; -then - exit 1 -fi +$mkvenv ensuregroup --dir "${source_path}/python/wheels" \ + ${source_path}/pythondeps.toml meson || exit 1 # At this point, we expect Meson to be installed and available. # We expect mkvenv or pip to have created pyvenv/bin/meson for us. @@ -1047,10 +1042,9 @@ if test "$download" = "enabled" -a "$docs" = "enabled" ; then fi if test "$docs" != "disabled" ; then - if ! $mkvenv ensure \ + if ! $mkvenv ensuregroup \ $mkvenv_flags \ - --diagnose "sphinx-build" \ - "sphinx>=1.6.0" "sphinx-rtd-theme>=0.5.0"; + ${source_path}/pythondeps.toml docs; then if test "$docs" = "enabled" ; then exit 1 diff --git a/pythondeps.toml b/pythondeps.toml index 362f63ff2c..6be31dba30 100644 --- a/pythondeps.toml +++ b/pythondeps.toml @@ -15,3 +15,11 @@ # precise error diagnostics to the user. For example, # 'sphinx-build' can be used as a bellwether for the # presence of 'sphinx' in the system. + +[meson] +# The install key should match the version in python/wheels/ +meson = { accepted = ">=0.63.0", installed = "0.63.3", canary = "meson" } + +[docs] +sphinx = { accepted = ">=1.6", installed = "5.3.0", canary = "sphinx-build" } +sphinx_rtd_theme = { accepted = ">=0.5", installed = "1.1.1" } From c03f57fd5bf72588a05750f14202f63be7ddbd0c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 8 Aug 2023 11:28:08 +0200 Subject: [PATCH 1261/1353] Revert "tests: Use separate virtual environment for avocado" This reverts commit e8e4298feadae7924cf7600bb3bcc5b0a8d7cbe9. ensuregroup allows to specify both the acceptable versions of avocado, and a locked version to be used when avocado is not installed as a system pacakge. This lets us install avocado in pyvenv/ using "mkvenv.py" and reuse the distro package on Fedora and CentOS Stream (the only distros where it's available). ensuregroup's usage of "(>=..., <=...)" constraints when evaluating the distro package, and "==" constraints when installing it from PyPI, makes it possible to avoid conflicts between the known-good version and a package plugins included in the distro. This is because package plugins have "==" constraints on the version that is included in the distro, and, using "pip install avocado==88.1" on a venv that includes system packages will result in an error: avocado-framework-plugin-varianter-yaml-to-mux 98.0 requires avocado-framework==98.0, but you have avocado-framework 88.1 which is incompatible. avocado-framework-plugin-result-html 98.0 requires avocado-framework==98.0, but you have avocado-framework 88.1 which is incompatible. But at the same time, if the venv does not include a system distribution of avocado then we can install a known-good version and stick to LTS releases. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1663 Signed-off-by: Paolo Bonzini --- .gitlab-ci.d/buildtest.yml | 6 +++--- docs/devel/acpi-bits.rst | 6 +++--- docs/devel/testing.rst | 14 +++++++------- python/scripts/mkvenv.py | 13 +++++-------- pythondeps.toml | 7 +++++++ .../org.centos/stream/8/x86_64/test-avocado | 4 ++-- scripts/device-crash-test | 2 +- tests/Makefile.include | 19 ++++++++----------- tests/requirements.txt | 6 ------ tests/vm/Makefile.include | 2 +- 10 files changed, 37 insertions(+), 42 deletions(-) delete mode 100644 tests/requirements.txt diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml index 77dc83a6be..aee9101507 100644 --- a/.gitlab-ci.d/buildtest.yml +++ b/.gitlab-ci.d/buildtest.yml @@ -103,7 +103,7 @@ crash-test-debian: script: - cd build - make NINJA=":" check-venv - - tests/venv/bin/python3 scripts/device-crash-test -q --tcg-only ./qemu-system-i386 + - pyvenv/bin/python3 scripts/device-crash-test -q --tcg-only ./qemu-system-i386 build-system-fedora: extends: @@ -146,8 +146,8 @@ crash-test-fedora: script: - cd build - make NINJA=":" check-venv - - tests/venv/bin/python3 scripts/device-crash-test -q ./qemu-system-ppc - - tests/venv/bin/python3 scripts/device-crash-test -q ./qemu-system-riscv32 + - pyvenv/bin/python3 scripts/device-crash-test -q ./qemu-system-ppc + - pyvenv/bin/python3 scripts/device-crash-test -q ./qemu-system-riscv32 build-system-centos: extends: diff --git a/docs/devel/acpi-bits.rst b/docs/devel/acpi-bits.rst index 22e2580200..9677b0098f 100644 --- a/docs/devel/acpi-bits.rst +++ b/docs/devel/acpi-bits.rst @@ -61,19 +61,19 @@ Under ``tests/avocado/`` as the root we have: :: $ make check-venv (needed only the first time to create the venv) - $ ./tests/venv/bin/avocado run -t acpi tests/avocado + $ ./pyvenv/bin/avocado run -t acpi tests/avocado The above will run all acpi avocado tests including this one. In order to run the individual tests, perform the following: :: - $ ./tests/venv/bin/avocado run tests/avocado/acpi-bits.py --tap - + $ ./pyvenv/bin/avocado run tests/avocado/acpi-bits.py --tap - The above will produce output in tap format. You can omit "--tap -" in the end and it will produce output like the following: :: - $ ./tests/venv/bin/avocado run tests/avocado/acpi-bits.py + $ ./pyvenv/bin/avocado run tests/avocado/acpi-bits.py Fetching asset from tests/avocado/acpi-bits.py:AcpiBitsTest.test_acpi_smbios_bits JOB ID : eab225724da7b64c012c65705dc2fa14ab1defef JOB LOG : /home/anisinha/avocado/job-results/job-2022-10-10T17.58-eab2257/job.log diff --git a/docs/devel/testing.rst b/docs/devel/testing.rst index b6ad21bed1..5d1fc0aa95 100644 --- a/docs/devel/testing.rst +++ b/docs/devel/testing.rst @@ -894,9 +894,9 @@ You can run the avocado tests simply by executing: make check-avocado -This involves the automatic creation of Python virtual environment -within the build tree (at ``tests/venv``) which will have all the -right dependencies, and will save tests results also within the +This involves the automatic installation, from PyPI, of all the +necessary avocado-framework dependencies into the QEMU venv within the +build tree (at ``./pyvenv``). Test results are also saved within the build tree (at ``tests/results``). Note: the build environment must be using a Python 3 stack, and have @@ -953,7 +953,7 @@ may be invoked by running: .. code:: - tests/venv/bin/avocado run $OPTION1 $OPTION2 tests/avocado/ + pyvenv/bin/avocado run $OPTION1 $OPTION2 tests/avocado/ Note that if ``make check-avocado`` was not executed before, it is possible to create the Python virtual environment with the dependencies @@ -968,20 +968,20 @@ a test file. To run tests from a single file within the build tree, use: .. code:: - tests/venv/bin/avocado run tests/avocado/$TESTFILE + pyvenv/bin/avocado run tests/avocado/$TESTFILE To run a single test within a test file, use: .. code:: - tests/venv/bin/avocado run tests/avocado/$TESTFILE:$TESTCLASS.$TESTNAME + pyvenv/bin/avocado run tests/avocado/$TESTFILE:$TESTCLASS.$TESTNAME Valid test names are visible in the output from any previous execution of Avocado or ``make check-avocado``, and can also be queried using: .. code:: - tests/venv/bin/avocado list tests/avocado + pyvenv/bin/avocado list tests/avocado Manual Installation ~~~~~~~~~~~~~~~~~~~ diff --git a/python/scripts/mkvenv.py b/python/scripts/mkvenv.py index 02bcd9a8c9..4f2349fbb6 100644 --- a/python/scripts/mkvenv.py +++ b/python/scripts/mkvenv.py @@ -964,14 +964,11 @@ def _parse_groups(file: str) -> Dict[str, Dict[str, Any]]: "Python >=3.11 does not have tomllib... what have you done!?" ) - try: - # Use loads() to support both tomli v1.2.x (Ubuntu 22.04, - # Debian bullseye-backports) and v2.0.x - with open(file, "r", encoding="ascii") as depfile: - contents = depfile.read() - return tomllib.loads(contents) # type: ignore - except tomllib.TOMLDecodeError as exc: - raise Ouch(f"parsing {file} failed: {exc}") from exc + # Use loads() to support both tomli v1.2.x (Ubuntu 22.04, + # Debian bullseye-backports) and v2.0.x + with open(file, "r", encoding="ascii") as depfile: + contents = depfile.read() + return tomllib.loads(contents) # type: ignore def ensure_group( diff --git a/pythondeps.toml b/pythondeps.toml index 6be31dba30..0a35ebcf9f 100644 --- a/pythondeps.toml +++ b/pythondeps.toml @@ -23,3 +23,10 @@ meson = { accepted = ">=0.63.0", installed = "0.63.3", canary = "meson" } [docs] sphinx = { accepted = ">=1.6", installed = "5.3.0", canary = "sphinx-build" } sphinx_rtd_theme = { accepted = ">=0.5", installed = "1.1.1" } + +[avocado] +# Note that qemu.git/python/ is always implicitly installed. +# Prefer an LTS version when updating the accepted versions of +# avocado-framework, for example right now the limit is 92.x. +avocado-framework = { accepted = "(>=88.1, <93.0)", installed = "88.1", canary = "avocado" } +pycdlib = { accepted = ">=1.11.0" } diff --git a/scripts/ci/org.centos/stream/8/x86_64/test-avocado b/scripts/ci/org.centos/stream/8/x86_64/test-avocado index e0443fc8ae..73e7a1a312 100755 --- a/scripts/ci/org.centos/stream/8/x86_64/test-avocado +++ b/scripts/ci/org.centos/stream/8/x86_64/test-avocado @@ -4,7 +4,7 @@ # KVM and x86_64, or tests that are generic enough to be valid for all # targets. Such a test list can be generated with: # -# ./tests/venv/bin/avocado list --filter-by-tags-include-empty \ +# ./pyvenv/bin/avocado list --filter-by-tags-include-empty \ # --filter-by-tags-include-empty-key -t accel:kvm,arch:x86_64 \ # tests/avocado/ # @@ -22,7 +22,7 @@ # - tests/avocado/virtio_check_params.py:VirtioMaxSegSettingsCheck.test_machine_types # make get-vm-images -./tests/venv/bin/avocado run \ +./pyvenv/bin/avocado run \ --job-results-dir=tests/results/ \ tests/avocado/boot_linux.py:BootLinuxX8664.test_pc_i440fx_kvm \ tests/avocado/boot_linux.py:BootLinuxX8664.test_pc_q35_kvm \ diff --git a/scripts/device-crash-test b/scripts/device-crash-test index b74d887331..353aa575d7 100755 --- a/scripts/device-crash-test +++ b/scripts/device-crash-test @@ -43,7 +43,7 @@ except ModuleNotFoundError as exc: print(f"Module '{exc.name}' not found.") print(" Try 'make check-venv' from your build directory,") print(" and then one way to run this script is like so:") - print(f' > $builddir/tests/venv/bin/python3 "{path}"') + print(f' > $builddir/pyvenv/bin/python3 "{path}"') sys.exit(1) logger = logging.getLogger('device-crash-test') diff --git a/tests/Makefile.include b/tests/Makefile.include index 9422ddaece..985cda7a94 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -89,10 +89,8 @@ distclean-tcg: $(DISTCLEAN_TCG_TARGET_RULES) # Build up our target list from the filtered list of ninja targets TARGETS=$(patsubst libqemu-%.fa, %, $(filter libqemu-%.fa, $(ninja-targets))) -TESTS_VENV_DIR=$(BUILD_DIR)/tests/venv -TESTS_VENV_REQ=$(SRC_PATH)/tests/requirements.txt +TESTS_VENV_TOKEN=$(BUILD_DIR)/pyvenv/tests.group TESTS_RESULTS_DIR=$(BUILD_DIR)/tests/results -TESTS_PYTHON=$(TESTS_VENV_DIR)/bin/python3 ifndef AVOCADO_TESTS AVOCADO_TESTS=tests/avocado endif @@ -108,20 +106,19 @@ else endif quiet-venv-pip = $(quiet-@)$(call quiet-command-run, \ - $(TESTS_PYTHON) -m pip -q --disable-pip-version-check $1, \ + $(PYTHON) -m pip -q --disable-pip-version-check $1, \ "VENVPIP","$1") -$(TESTS_VENV_DIR): $(TESTS_VENV_REQ) - $(call quiet-command, $(PYTHON) -m venv $@, VENV, $@) +$(TESTS_VENV_TOKEN): $(SRC_PATH)/pythondeps.toml $(call quiet-venv-pip,install -e "$(SRC_PATH)/python/") - $(call quiet-venv-pip,install -r $(TESTS_VENV_REQ)) + $(PYTHON) python/scripts/mkvenv.py ensuregroup --online $< avocado $(call quiet-command, touch $@) $(TESTS_RESULTS_DIR): $(call quiet-command, mkdir -p $@, \ MKDIR, $@) -check-venv: $(TESTS_VENV_DIR) +check-venv: $(TESTS_VENV_TOKEN) FEDORA_31_ARCHES_TARGETS=$(patsubst %-softmmu,%, $(filter %-softmmu,$(TARGETS))) FEDORA_31_ARCHES_CANDIDATES=$(patsubst ppc64,ppc64le,$(FEDORA_31_ARCHES_TARGETS)) @@ -131,7 +128,7 @@ FEDORA_31_DOWNLOAD=$(filter $(FEDORA_31_ARCHES),$(FEDORA_31_ARCHES_CANDIDATES)) # download one specific Fedora 31 image get-vm-image-fedora-31-%: check-venv $(call quiet-command, \ - $(TESTS_PYTHON) -m avocado vmimage get \ + $(PYTHON) -m avocado vmimage get \ --distro=fedora --distro-version=31 --arch=$*, \ "AVOCADO", "Downloading avocado tests VM image for $*") @@ -140,7 +137,7 @@ get-vm-images: check-venv $(patsubst %,get-vm-image-fedora-31-%, $(FEDORA_31_DOW check-avocado: check-venv $(TESTS_RESULTS_DIR) get-vm-images $(call quiet-command, \ - $(TESTS_PYTHON) -m avocado \ + $(PYTHON) -m avocado \ --show=$(AVOCADO_SHOW) run --job-results-dir=$(TESTS_RESULTS_DIR) \ $(if $(AVOCADO_TAGS),, --filter-by-tags-include-empty \ --filter-by-tags-include-empty-key) \ @@ -163,7 +160,7 @@ check: check-build: run-ninja check-clean: - rm -rf $(TESTS_VENV_DIR) $(TESTS_RESULTS_DIR) + rm -rf $(TESTS_RESULTS_DIR) clean: check-clean clean-tcg distclean: distclean-tcg diff --git a/tests/requirements.txt b/tests/requirements.txt deleted file mode 100644 index 0ba561b6bd..0000000000 --- a/tests/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -# Add Python module requirements, one per line, to be installed -# in the tests/venv Python virtual environment. For more info, -# refer to: https://pip.pypa.io/en/stable/user_guide/#id1 -# Note that qemu.git/python/ is always implicitly installed. -avocado-framework==88.1 -pycdlib==1.11.0 diff --git a/tests/vm/Makefile.include b/tests/vm/Makefile.include index c2a8ca1c17..f0f5d32fb0 100644 --- a/tests/vm/Makefile.include +++ b/tests/vm/Makefile.include @@ -5,7 +5,7 @@ ifeq ($(realpath $(SRC_PATH)),$(realpath .)) VM_PYTHON = PYTHONPATH=$(SRC_PATH)/python /usr/bin/env python3 VM_VENV = else -VM_PYTHON = $(TESTS_PYTHON) +VM_PYTHON = $(PYTHON) VM_VENV = check-venv endif From 7ace219303e28cc67852e1d193437cd1f367b5c8 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 8 Aug 2023 23:35:47 +0200 Subject: [PATCH 1262/1353] tests/docker: add python3-tomli dependency to containers Instead of having CI pick tomli from the vendored wheel at configure time, place it in the containers. Signed-off-by: Paolo Bonzini --- .gitlab-ci.d/cirrus/freebsd-13.vars | 2 +- .gitlab-ci.d/cirrus/macos-12.vars | 2 +- tests/docker/dockerfiles/centos8.docker | 3 ++- .../dockerfiles/debian-all-test-cross.docker | 7 ++++++- .../docker/dockerfiles/debian-amd64-cross.docker | 4 ++++ tests/docker/dockerfiles/debian-amd64.docker | 4 ++++ .../docker/dockerfiles/debian-arm64-cross.docker | 4 ++++ .../docker/dockerfiles/debian-armel-cross.docker | 4 ++++ .../docker/dockerfiles/debian-armhf-cross.docker | 4 ++++ .../dockerfiles/debian-hexagon-cross.docker | 6 +++++- .../dockerfiles/debian-mips64el-cross.docker | 4 ++++ .../dockerfiles/debian-mipsel-cross.docker | 4 ++++ .../dockerfiles/debian-ppc64el-cross.docker | 4 ++++ .../docker/dockerfiles/debian-s390x-cross.docker | 4 ++++ .../dockerfiles/debian-tricore-cross.docker | 2 ++ .../docker/dockerfiles/fedora-i386-cross.docker | 1 + tests/docker/dockerfiles/ubuntu2004.docker | 4 +++- tests/docker/dockerfiles/ubuntu2204.docker | 1 + tests/lcitool/mappings.yml | 16 ++++++++++++++++ tests/lcitool/projects/qemu.yml | 1 + tests/vm/generated/freebsd.json | 1 + 21 files changed, 76 insertions(+), 6 deletions(-) diff --git a/.gitlab-ci.d/cirrus/freebsd-13.vars b/.gitlab-ci.d/cirrus/freebsd-13.vars index facb649f5b..3785afca36 100644 --- a/.gitlab-ci.d/cirrus/freebsd-13.vars +++ b/.gitlab-ci.d/cirrus/freebsd-13.vars @@ -11,6 +11,6 @@ MAKE='/usr/local/bin/gmake' NINJA='/usr/local/bin/ninja' PACKAGING_COMMAND='pkg' PIP3='/usr/local/bin/pip-3.8' -PKGS='alsa-lib bash bison bzip2 ca_root_nss capstone4 ccache cmocka ctags curl cyrus-sasl dbus diffutils dtc flex fusefs-libs3 gettext git glib gmake gnutls gsed gtk3 json-c libepoxy libffi libgcrypt libjpeg-turbo libnfs libslirp libspice-server libssh libtasn1 llvm lzo2 meson mtools ncurses nettle ninja opencv pixman pkgconf png py39-numpy py39-pillow py39-pip py39-sphinx py39-sphinx_rtd_theme py39-yaml python3 rpm2cpio sdl2 sdl2_image snappy sndio socat spice-protocol tesseract usbredir virglrenderer vte3 xorriso zstd' +PKGS='alsa-lib bash bison bzip2 ca_root_nss capstone4 ccache cmocka ctags curl cyrus-sasl dbus diffutils dtc flex fusefs-libs3 gettext git glib gmake gnutls gsed gtk3 json-c libepoxy libffi libgcrypt libjpeg-turbo libnfs libslirp libspice-server libssh libtasn1 llvm lzo2 meson mtools ncurses nettle ninja opencv pixman pkgconf png py39-numpy py39-pillow py39-pip py39-sphinx py39-sphinx_rtd_theme py39-tomli py39-yaml python3 rpm2cpio sdl2 sdl2_image snappy sndio socat spice-protocol tesseract usbredir virglrenderer vte3 xorriso zstd' PYPI_PKGS='' PYTHON='/usr/local/bin/python3' diff --git a/.gitlab-ci.d/cirrus/macos-12.vars b/.gitlab-ci.d/cirrus/macos-12.vars index ceb294e153..80eadaab29 100644 --- a/.gitlab-ci.d/cirrus/macos-12.vars +++ b/.gitlab-ci.d/cirrus/macos-12.vars @@ -12,5 +12,5 @@ NINJA='/opt/homebrew/bin/ninja' PACKAGING_COMMAND='brew' PIP3='/opt/homebrew/bin/pip3' PKGS='bash bc bison bzip2 capstone ccache cmocka ctags curl dbus diffutils dtc flex gcovr gettext git glib gnu-sed gnutls gtk+3 jemalloc jpeg-turbo json-c libepoxy libffi libgcrypt libiscsi libnfs libpng libslirp libssh libtasn1 libusb llvm lzo make meson mtools ncurses nettle ninja pixman pkg-config python3 rpm2cpio sdl2 sdl2_image snappy socat sparse spice-protocol tesseract usbredir vde vte3 xorriso zlib zstd' -PYPI_PKGS='PyYAML numpy pillow sphinx sphinx-rtd-theme' +PYPI_PKGS='PyYAML numpy pillow sphinx sphinx-rtd-theme tomli' PYTHON='/opt/homebrew/bin/python3' diff --git a/tests/docker/dockerfiles/centos8.docker b/tests/docker/dockerfiles/centos8.docker index da7dc818fb..fc1830966f 100644 --- a/tests/docker/dockerfiles/centos8.docker +++ b/tests/docker/dockerfiles/centos8.docker @@ -133,7 +133,8 @@ RUN /usr/bin/pip3.8 install \ meson==0.63.2 \ pillow \ sphinx \ - sphinx-rtd-theme + sphinx-rtd-theme \ + tomli ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" ENV LANG "en_US.UTF-8" diff --git a/tests/docker/dockerfiles/debian-all-test-cross.docker b/tests/docker/dockerfiles/debian-all-test-cross.docker index f9f401544a..54e957d5e7 100644 --- a/tests/docker/dockerfiles/debian-all-test-cross.docker +++ b/tests/docker/dockerfiles/debian-all-test-cross.docker @@ -58,7 +58,12 @@ RUN DEBIAN_FRONTEND=noninteractive eatmydata \ libc6-dev-sh4-cross \ gcc-sparc64-linux-gnu \ libc6-dev-sparc64-cross \ - python3-venv + python3-pip \ + python3-setuptools \ + python3-venv \ + python3-wheel + +RUN /usr/bin/pip3 install tomli ENV QEMU_CONFIGURE_OPTS --disable-system --disable-docs --disable-tools ENV DEF_TARGET_LIST aarch64-linux-user,alpha-linux-user,arm-linux-user,hppa-linux-user,i386-linux-user,m68k-linux-user,mips-linux-user,mips64-linux-user,mips64el-linux-user,mipsel-linux-user,ppc-linux-user,ppc64-linux-user,ppc64le-linux-user,riscv64-linux-user,s390x-linux-user,sh4-linux-user,sparc64-linux-user diff --git a/tests/docker/dockerfiles/debian-amd64-cross.docker b/tests/docker/dockerfiles/debian-amd64-cross.docker index b9871f9c8c..b66b9cc191 100644 --- a/tests/docker/dockerfiles/debian-amd64-cross.docker +++ b/tests/docker/dockerfiles/debian-amd64-cross.docker @@ -47,9 +47,11 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ python3-opencv \ python3-pillow \ python3-pip \ + python3-setuptools \ python3-sphinx \ python3-sphinx-rtd-theme \ python3-venv \ + python3-wheel \ python3-yaml \ rpm2cpio \ sed \ @@ -65,6 +67,8 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ dpkg-reconfigure locales +RUN /usr/bin/pip3 install tomli + ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" ENV LANG "en_US.UTF-8" ENV MAKE "/usr/bin/make" diff --git a/tests/docker/dockerfiles/debian-amd64.docker b/tests/docker/dockerfiles/debian-amd64.docker index 6d2fa38e3e..02262bc70e 100644 --- a/tests/docker/dockerfiles/debian-amd64.docker +++ b/tests/docker/dockerfiles/debian-amd64.docker @@ -115,9 +115,11 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ python3-opencv \ python3-pillow \ python3-pip \ + python3-setuptools \ python3-sphinx \ python3-sphinx-rtd-theme \ python3-venv \ + python3-wheel \ python3-yaml \ rpm2cpio \ sed \ @@ -143,6 +145,8 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/g++ && \ ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc +RUN /usr/bin/pip3 install tomli + ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" ENV LANG "en_US.UTF-8" ENV MAKE "/usr/bin/make" diff --git a/tests/docker/dockerfiles/debian-arm64-cross.docker b/tests/docker/dockerfiles/debian-arm64-cross.docker index 3504c771a7..a0a968b8c6 100644 --- a/tests/docker/dockerfiles/debian-arm64-cross.docker +++ b/tests/docker/dockerfiles/debian-arm64-cross.docker @@ -47,9 +47,11 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ python3-opencv \ python3-pillow \ python3-pip \ + python3-setuptools \ python3-sphinx \ python3-sphinx-rtd-theme \ python3-venv \ + python3-wheel \ python3-yaml \ rpm2cpio \ sed \ @@ -65,6 +67,8 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ dpkg-reconfigure locales +RUN /usr/bin/pip3 install tomli + ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" ENV LANG "en_US.UTF-8" ENV MAKE "/usr/bin/make" diff --git a/tests/docker/dockerfiles/debian-armel-cross.docker b/tests/docker/dockerfiles/debian-armel-cross.docker index 6d11c9510f..f1fc34a28a 100644 --- a/tests/docker/dockerfiles/debian-armel-cross.docker +++ b/tests/docker/dockerfiles/debian-armel-cross.docker @@ -47,9 +47,11 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ python3-opencv \ python3-pillow \ python3-pip \ + python3-setuptools \ python3-sphinx \ python3-sphinx-rtd-theme \ python3-venv \ + python3-wheel \ python3-yaml \ rpm2cpio \ sed \ @@ -65,6 +67,8 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ dpkg-reconfigure locales +RUN /usr/bin/pip3 install tomli + ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" ENV LANG "en_US.UTF-8" ENV MAKE "/usr/bin/make" diff --git a/tests/docker/dockerfiles/debian-armhf-cross.docker b/tests/docker/dockerfiles/debian-armhf-cross.docker index 37ae575cf7..a278578211 100644 --- a/tests/docker/dockerfiles/debian-armhf-cross.docker +++ b/tests/docker/dockerfiles/debian-armhf-cross.docker @@ -47,9 +47,11 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ python3-opencv \ python3-pillow \ python3-pip \ + python3-setuptools \ python3-sphinx \ python3-sphinx-rtd-theme \ python3-venv \ + python3-wheel \ python3-yaml \ rpm2cpio \ sed \ @@ -65,6 +67,8 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ dpkg-reconfigure locales +RUN /usr/bin/pip3 install tomli + ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" ENV LANG "en_US.UTF-8" ENV MAKE "/usr/bin/make" diff --git a/tests/docker/dockerfiles/debian-hexagon-cross.docker b/tests/docker/dockerfiles/debian-hexagon-cross.docker index c2cfb6a5d0..153fc7cfb3 100644 --- a/tests/docker/dockerfiles/debian-hexagon-cross.docker +++ b/tests/docker/dockerfiles/debian-hexagon-cross.docker @@ -21,11 +21,15 @@ RUN apt-get update && \ flex \ git \ ninja-build \ - python3-venv && \ + python3-pip \ + python3-setuptools \ + python3-venv \ + python3-wheel && \ # Install QEMU build deps for use in CI DEBIAN_FRONTEND=noninteractive eatmydata \ apt build-dep -yy --arch-only qemu +RUN /usr/bin/pip3 install tomli ENV TOOLCHAIN_INSTALL /opt ENV TOOLCHAIN_RELEASE 16.0.0 diff --git a/tests/docker/dockerfiles/debian-mips64el-cross.docker b/tests/docker/dockerfiles/debian-mips64el-cross.docker index 26ed730165..17d3e01ecc 100644 --- a/tests/docker/dockerfiles/debian-mips64el-cross.docker +++ b/tests/docker/dockerfiles/debian-mips64el-cross.docker @@ -47,9 +47,11 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ python3-opencv \ python3-pillow \ python3-pip \ + python3-setuptools \ python3-sphinx \ python3-sphinx-rtd-theme \ python3-venv \ + python3-wheel \ python3-yaml \ rpm2cpio \ sed \ @@ -65,6 +67,8 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ dpkg-reconfigure locales +RUN /usr/bin/pip3 install tomli + ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" ENV LANG "en_US.UTF-8" ENV MAKE "/usr/bin/make" diff --git a/tests/docker/dockerfiles/debian-mipsel-cross.docker b/tests/docker/dockerfiles/debian-mipsel-cross.docker index ade2f37ed1..5fcd641f15 100644 --- a/tests/docker/dockerfiles/debian-mipsel-cross.docker +++ b/tests/docker/dockerfiles/debian-mipsel-cross.docker @@ -47,9 +47,11 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ python3-opencv \ python3-pillow \ python3-pip \ + python3-setuptools \ python3-sphinx \ python3-sphinx-rtd-theme \ python3-venv \ + python3-wheel \ python3-yaml \ rpm2cpio \ sed \ @@ -65,6 +67,8 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ dpkg-reconfigure locales +RUN /usr/bin/pip3 install tomli + ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" ENV LANG "en_US.UTF-8" ENV MAKE "/usr/bin/make" diff --git a/tests/docker/dockerfiles/debian-ppc64el-cross.docker b/tests/docker/dockerfiles/debian-ppc64el-cross.docker index 08dcffa0a8..30e5efa986 100644 --- a/tests/docker/dockerfiles/debian-ppc64el-cross.docker +++ b/tests/docker/dockerfiles/debian-ppc64el-cross.docker @@ -47,9 +47,11 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ python3-opencv \ python3-pillow \ python3-pip \ + python3-setuptools \ python3-sphinx \ python3-sphinx-rtd-theme \ python3-venv \ + python3-wheel \ python3-yaml \ rpm2cpio \ sed \ @@ -65,6 +67,8 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ dpkg-reconfigure locales +RUN /usr/bin/pip3 install tomli + ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" ENV LANG "en_US.UTF-8" ENV MAKE "/usr/bin/make" diff --git a/tests/docker/dockerfiles/debian-s390x-cross.docker b/tests/docker/dockerfiles/debian-s390x-cross.docker index 48a2c10fdb..ee6db7b526 100644 --- a/tests/docker/dockerfiles/debian-s390x-cross.docker +++ b/tests/docker/dockerfiles/debian-s390x-cross.docker @@ -47,9 +47,11 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ python3-opencv \ python3-pillow \ python3-pip \ + python3-setuptools \ python3-sphinx \ python3-sphinx-rtd-theme \ python3-venv \ + python3-wheel \ python3-yaml \ rpm2cpio \ sed \ @@ -65,6 +67,8 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \ dpkg-reconfigure locales +RUN /usr/bin/pip3 install tomli + ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" ENV LANG "en_US.UTF-8" ENV MAKE "/usr/bin/make" diff --git a/tests/docker/dockerfiles/debian-tricore-cross.docker b/tests/docker/dockerfiles/debian-tricore-cross.docker index 5bd1963fb5..c597f8e16b 100644 --- a/tests/docker/dockerfiles/debian-tricore-cross.docker +++ b/tests/docker/dockerfiles/debian-tricore-cross.docker @@ -36,6 +36,8 @@ RUN apt update && \ python3-wheel \ python3-venv +RUN /usr/bin/pip3 install tomli + RUN curl -#SL https://github.com/bkoppelmann/package_940/releases/download/tricore-toolchain-9.40/tricore-toolchain-9.4.0.tar.gz \ | tar -xzC /usr/local/ diff --git a/tests/docker/dockerfiles/fedora-i386-cross.docker b/tests/docker/dockerfiles/fedora-i386-cross.docker index 14c1fb2c93..b59a9115c4 100644 --- a/tests/docker/dockerfiles/fedora-i386-cross.docker +++ b/tests/docker/dockerfiles/fedora-i386-cross.docker @@ -24,6 +24,7 @@ ENV PACKAGES \ nettle-devel.i686 \ pcre-devel.i686 \ pixman-devel.i686 \ + python3-tomli \ sysprof-capture-devel.i686 \ zlib-devel.i686 diff --git a/tests/docker/dockerfiles/ubuntu2004.docker b/tests/docker/dockerfiles/ubuntu2004.docker index 8f864d19e6..4180cd8674 100644 --- a/tests/docker/dockerfiles/ubuntu2004.docker +++ b/tests/docker/dockerfiles/ubuntu2004.docker @@ -141,7 +141,9 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/g++ && \ ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc -RUN /usr/bin/pip3 install meson==0.63.2 +RUN /usr/bin/pip3 install \ + meson==0.63.2 \ + tomli ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" ENV LANG "en_US.UTF-8" diff --git a/tests/docker/dockerfiles/ubuntu2204.docker b/tests/docker/dockerfiles/ubuntu2204.docker index 8f939870ae..88493f00f6 100644 --- a/tests/docker/dockerfiles/ubuntu2204.docker +++ b/tests/docker/dockerfiles/ubuntu2204.docker @@ -117,6 +117,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ python3-pip \ python3-sphinx \ python3-sphinx-rtd-theme \ + python3-tomli \ python3-venv \ python3-yaml \ rpm2cpio \ diff --git a/tests/lcitool/mappings.yml b/tests/lcitool/mappings.yml index 3c554099ed..0b908882f1 100644 --- a/tests/lcitool/mappings.yml +++ b/tests/lcitool/mappings.yml @@ -59,6 +59,15 @@ mappings: CentOSStream8: OpenSUSELeap15: + python3-tomli: + # test using tomllib + apk: + Fedora: + Debian12: + OpenSUSELeap15: + # Not available for Python 3.8 + CentOSStream8: + python3-venv: CentOSStream8: python38 OpenSUSELeap15: python311-base @@ -75,3 +84,10 @@ pypi_mappings: # Drop packages that need devel headers python3-numpy: OpenSUSELeap15: + + # see above + python3-tomli: + apk: + Fedora: + Debian12: + OpenSUSELeap15: diff --git a/tests/lcitool/projects/qemu.yml b/tests/lcitool/projects/qemu.yml index 2d31cf792a..584f78cb7f 100644 --- a/tests/lcitool/projects/qemu.yml +++ b/tests/lcitool/projects/qemu.yml @@ -96,6 +96,7 @@ packages: - python3-pip - python3-sphinx - python3-sphinx-rtd-theme + - python3-tomli - python3-venv - rpm2cpio - sdl2 diff --git a/tests/vm/generated/freebsd.json b/tests/vm/generated/freebsd.json index 7c435cf23e..2d5895ebed 100644 --- a/tests/vm/generated/freebsd.json +++ b/tests/vm/generated/freebsd.json @@ -56,6 +56,7 @@ "py39-pip", "py39-sphinx", "py39-sphinx_rtd_theme", + "py39-tomli", "py39-yaml", "python3", "rpm2cpio", From 33cc88261c352445d31599054653d759f20531c1 Mon Sep 17 00:00:00 2001 From: Ake Koomsin Date: Mon, 7 Aug 2023 18:33:40 +0900 Subject: [PATCH 1263/1353] target/i386: add support for VMX_SECONDARY_EXEC_ENABLE_USER_WAIT_PAUSE Current QEMU can expose waitpkg to guests when it is available. However, VMX_SECONDARY_EXEC_ENABLE_USER_WAIT_PAUSE is still not recognized and masked by QEMU. This can lead to an unexpected situation when a L1 hypervisor wants to expose waitpkg to a L2 guest. The L1 hypervisor can assume that VMX_SECONDARY_EXEC_ENABLE_USER_WAIT_PAUSE exists as waitpkg is available. The L1 hypervisor then can accidentally expose waitpkg to the L2 guest. This will cause invalid opcode exception in the L2 guest when it executes waitpkg related instructions. This patch adds VMX_SECONDARY_EXEC_ENABLE_USER_WAIT_PAUSE support, and sets up dependency between the bit and CPUID_7_0_ECX_WAITPKG. QEMU should not expose waitpkg feature if VMX_SECONDARY_EXEC_ENABLE_USER_WAIT_PAUSE is not available to avoid unexpected invalid opcode exception in L2 guests. Signed-off-by: Ake Koomsin Message-ID: <20230807093339.32091-2-ake@igel.co.jp> Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 6 +++++- target/i386/cpu.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 97ad229d8b..00f913b638 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -1228,7 +1228,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { "vmx-invpcid-exit", "vmx-vmfunc", "vmx-shadow-vmcs", "vmx-encls-exit", "vmx-rdseed-exit", "vmx-pml", NULL, NULL, "vmx-xsaves", NULL, NULL, NULL, - NULL, "vmx-tsc-scaling", NULL, NULL, + NULL, "vmx-tsc-scaling", "vmx-enable-user-wait-pause", NULL, NULL, NULL, NULL, NULL, }, .msr = { @@ -1545,6 +1545,10 @@ static FeatureDep feature_dependencies[] = { .from = { FEAT_8000_0001_ECX, CPUID_EXT3_SVM }, .to = { FEAT_SVM, ~0ull }, }, + { + .from = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_ENABLE_USER_WAIT_PAUSE }, + .to = { FEAT_7_0_ECX, CPUID_7_0_ECX_WAITPKG }, + }, }; typedef struct X86RegisterInfo32 { diff --git a/target/i386/cpu.h b/target/i386/cpu.h index e0771a1043..a6000e93bd 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1111,6 +1111,7 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, #define VMX_SECONDARY_EXEC_ENABLE_PML 0x00020000 #define VMX_SECONDARY_EXEC_XSAVES 0x00100000 #define VMX_SECONDARY_EXEC_TSC_SCALING 0x02000000 +#define VMX_SECONDARY_EXEC_ENABLE_USER_WAIT_PAUSE 0x04000000 #define VMX_PIN_BASED_EXT_INTR_MASK 0x00000001 #define VMX_PIN_BASED_NMI_EXITING 0x00000008 From a04f33727cea092dc71be32745e8964f62fb8104 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 7 Aug 2023 11:22:08 +0200 Subject: [PATCH 1264/1353] configure: fix container_hosts misspellings and duplications container_hosts is matched against $cpu, so it must contain QEMU canonical architecture names, not Debian architecture names. Also do not set $container_hosts inside the loop, since it is already set before. Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- configure | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/configure b/configure index e4d42d640e..08bf24b689 100755 --- a/configure +++ b/configure @@ -1352,7 +1352,7 @@ probe_target_compiler() { sh4) container_hosts=x86_64 ;; sparc64) container_hosts=x86_64 ;; tricore) container_hosts=x86_64 ;; - x86_64) container_hosts="aarch64 ppc64el x86_64" ;; + x86_64) container_hosts="aarch64 ppc64le x86_64" ;; xtensa*) container_hosts=x86_64 ;; esac @@ -1459,7 +1459,6 @@ probe_target_compiler() { container_cross_prefix=x86_64-linux-gnu- ;; xtensa*) - container_hosts=x86_64 container_image=debian-xtensa-cross # default to the dc232b cpu From 29a8238510df27080b0ffa92c58400412ce19daa Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 7 Aug 2023 14:17:43 +0200 Subject: [PATCH 1265/1353] configure: remove unnecessary mkdir -p It is already included in the symlink shell function. Signed-off-by: Paolo Bonzini --- configure | 1 - 1 file changed, 1 deletion(-) diff --git a/configure b/configure index 08bf24b689..b9bd008592 100755 --- a/configure +++ b/configure @@ -1775,7 +1775,6 @@ fi for target in $target_list; do target_dir="$target" target_name=$(echo $target | cut -d '-' -f 1)$EXESUF - mkdir -p "$target_dir" case $target in *-user) symlink "../qemu-$target_name" "$target_dir/qemu-$target_name" ;; *) symlink "../qemu-system-$target_name" "$target_dir/qemu-system-$target_name" ;; From 935f1dd8181b757e6eff83522d85b0a2b84c27c5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 18 Aug 2023 10:57:34 -0700 Subject: [PATCH 1266/1353] bsd-user: Remove ELF_START_MMAP and image_info.start_mmap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The start_mmap value is write-only. Remove the field and the defines that populated it. Signed-off-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230818175736.144194-2-richard.henderson@linaro.org> Reviewed-by: Warner Losh Signed-off-by: Warner Losh --- bsd-user/arm/target_arch_elf.h | 1 - bsd-user/elfload.c | 1 - bsd-user/i386/target_arch_elf.h | 1 - bsd-user/qemu.h | 1 - bsd-user/x86_64/target_arch_elf.h | 1 - 5 files changed, 5 deletions(-) diff --git a/bsd-user/arm/target_arch_elf.h b/bsd-user/arm/target_arch_elf.h index 935bce347f..b1c0fd2b32 100644 --- a/bsd-user/arm/target_arch_elf.h +++ b/bsd-user/arm/target_arch_elf.h @@ -20,7 +20,6 @@ #ifndef TARGET_ARCH_ELF_H #define TARGET_ARCH_ELF_H -#define ELF_START_MMAP 0x80000000 #define ELF_ET_DYN_LOAD_ADDR 0x500000 #define elf_check_arch(x) ((x) == EM_ARM) diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c index 1f650bdde8..38a3439d2c 100644 --- a/bsd-user/elfload.c +++ b/bsd-user/elfload.c @@ -738,7 +738,6 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs, /* OK, This is the point of no return */ info->end_data = 0; info->end_code = 0; - info->start_mmap = (abi_ulong)ELF_START_MMAP; info->mmap = 0; elf_entry = (abi_ulong) elf_ex.e_entry; diff --git a/bsd-user/i386/target_arch_elf.h b/bsd-user/i386/target_arch_elf.h index cbcd1f08e2..4ac27b02e7 100644 --- a/bsd-user/i386/target_arch_elf.h +++ b/bsd-user/i386/target_arch_elf.h @@ -20,7 +20,6 @@ #ifndef TARGET_ARCH_ELF_H #define TARGET_ARCH_ELF_H -#define ELF_START_MMAP 0x80000000 #define ELF_ET_DYN_LOAD_ADDR 0x01001000 #define elf_check_arch(x) (((x) == EM_386) || ((x) == EM_486)) diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index 8f2d6a3c78..178114b423 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -52,7 +52,6 @@ struct image_info { abi_ulong end_data; abi_ulong start_brk; abi_ulong brk; - abi_ulong start_mmap; abi_ulong mmap; abi_ulong rss; abi_ulong start_stack; diff --git a/bsd-user/x86_64/target_arch_elf.h b/bsd-user/x86_64/target_arch_elf.h index b244711888..e51c2faf08 100644 --- a/bsd-user/x86_64/target_arch_elf.h +++ b/bsd-user/x86_64/target_arch_elf.h @@ -20,7 +20,6 @@ #ifndef TARGET_ARCH_ELF_H #define TARGET_ARCH_ELF_H -#define ELF_START_MMAP 0x2aaaaab000ULL #define ELF_ET_DYN_LOAD_ADDR 0x01021000 #define elf_check_arch(x) (((x) == ELF_ARCH)) From 7db1873664dcba22820981ad105b0d30bcd509b8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 18 Aug 2023 10:57:35 -0700 Subject: [PATCH 1267/1353] bsd-user: Remove image_info.mmap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This value is unused. Signed-off-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230818175736.144194-3-richard.henderson@linaro.org> Reviewed-by: Warner Losh Signed-off-by: Warner Losh --- bsd-user/elfload.c | 1 - bsd-user/qemu.h | 1 - 2 files changed, 2 deletions(-) diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c index 38a3439d2c..2d39e59258 100644 --- a/bsd-user/elfload.c +++ b/bsd-user/elfload.c @@ -738,7 +738,6 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs, /* OK, This is the point of no return */ info->end_data = 0; info->end_code = 0; - info->mmap = 0; elf_entry = (abi_ulong) elf_ex.e_entry; /* XXX Join this with PT_INTERP search? */ diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index 178114b423..898fe3e8b3 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -52,7 +52,6 @@ struct image_info { abi_ulong end_data; abi_ulong start_brk; abi_ulong brk; - abi_ulong mmap; abi_ulong rss; abi_ulong start_stack; abi_ulong entry; From 4436e2ff6cae585f4863fa59a3ad77dd3c54ac63 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 18 Aug 2023 10:57:36 -0700 Subject: [PATCH 1268/1353] bsd-user: Remove image_info.start_brk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This has the same value is image_info.brk, which is also logged, and is otherwise unused. Signed-off-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230818175736.144194-4-richard.henderson@linaro.org> Reviewed-by: Warner Losh Signed-off-by: Warner Losh --- bsd-user/elfload.c | 2 +- bsd-user/main.c | 2 -- bsd-user/qemu.h | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c index 2d39e59258..baf2f63d2f 100644 --- a/bsd-user/elfload.c +++ b/bsd-user/elfload.c @@ -811,7 +811,7 @@ int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs, bprm->stringp, &elf_ex, load_addr, et_dyn_addr, interp_load_addr, info); info->load_addr = reloc_func_desc; - info->start_brk = info->brk = elf_brk; + info->brk = elf_brk; info->start_stack = bprm->p; info->load_bias = 0; diff --git a/bsd-user/main.c b/bsd-user/main.c index 381bb18df8..f913cb55a7 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -553,8 +553,6 @@ int main(int argc, char **argv) fprintf(f, "page layout changed following binary load\n"); page_dump(f); - fprintf(f, "start_brk 0x" TARGET_ABI_FMT_lx "\n", - info->start_brk); fprintf(f, "end_code 0x" TARGET_ABI_FMT_lx "\n", info->end_code); fprintf(f, "start_code 0x" TARGET_ABI_FMT_lx "\n", diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index 898fe3e8b3..61501c321b 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -50,7 +50,6 @@ struct image_info { abi_ulong end_code; abi_ulong start_data; abi_ulong end_data; - abi_ulong start_brk; abi_ulong brk; abi_ulong rss; abi_ulong start_stack; From 25e2cfbb8e621a4a726040427f14dca68f78bd1b Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Sun, 13 Aug 2023 10:41:22 +0200 Subject: [PATCH 1269/1353] bsd-user: Move _WANT_FREEBSD macros to include/qemu/osdep.h move _WANT_FREEBSD macros from bsd-user/freebsd/os-syscall.c to include/qemu/osdep.h in order to pull some struct defintions needed later in the build. Signed-off-by: Warner Losh Signed-off-by: Karim Taha Acked-by: Richard Henderson --- bsd-user/freebsd/os-syscall.c | 11 ----------- include/qemu/osdep.h | 13 +++++++++++++ 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index de36c4b71c..2224a280ea 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -17,17 +17,6 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ - -/* - * We need the FreeBSD "legacy" definitions. Rust needs the FreeBSD 11 system - * calls since it doesn't use libc at all, so we have to emulate that despite - * FreeBSD 11 being EOL'd. - */ -#define _WANT_FREEBSD11_STAT -#define _WANT_FREEBSD11_STATFS -#define _WANT_FREEBSD11_DIRENT -#define _WANT_KERNEL_ERRNO -#define _WANT_SEMUN #include "qemu/osdep.h" #include "qemu/cutils.h" #include "qemu/path.h" diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index 21ef8f1699..2cae135280 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -88,6 +88,19 @@ QEMU_EXTERN_C int daemon(int, int); #define __USE_MINGW_ANSI_STDIO 1 #endif +/* + * We need the FreeBSD "legacy" definitions. Rust needs the FreeBSD 11 system + * calls since it doesn't use libc at all, so we have to emulate that despite + * FreeBSD 11 being EOL'd. + */ +#ifdef __FreeBSD__ +#define _WANT_FREEBSD11_STAT +#define _WANT_FREEBSD11_STATFS +#define _WANT_FREEBSD11_DIRENT +#define _WANT_KERNEL_ERRNO +#define _WANT_SEMUN +#endif + #include #include #include From 15b950ecd16ecc6e9a1f21e1f9f185ee61a5a1d5 Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Sun, 13 Aug 2023 10:41:23 +0200 Subject: [PATCH 1270/1353] bsd-user: Disable clang warnings Implement PRAGMA_DISABLE_PACKED_WARNING and PRAGMA_REENABLE_PACKED_WARNING macros in include/qemu/compiler.h. Signed-off-by: Kyle Evans Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- include/qemu/compiler.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/include/qemu/compiler.h b/include/qemu/compiler.h index a309f90c76..b037442518 100644 --- a/include/qemu/compiler.h +++ b/include/qemu/compiler.h @@ -22,6 +22,36 @@ #define QEMU_EXTERN_C extern #endif +/* + * Tricky points: + * - Use __builtin_choose_expr to avoid type promotion from ?:, + * - Invalid sizes result in a compile time error stemming from + * the fact that abort has no parameters. + * - It's easier to use the endian-specific unaligned load/store + * functions than host-endian unaligned load/store plus tswapN. + * - The pragmas are necessary only to silence a clang false-positive + * warning: see https://bugs.llvm.org/show_bug.cgi?id=39113 . + * - We have to disable -Wpragmas warnings to avoid a complaint about + * an unknown warning type from older compilers that don't know about + * -Waddress-of-packed-member. + * - gcc has bugs in its _Pragma() support in some versions, eg + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83256 -- so we only + * include the warning-suppression pragmas for clang + */ +#ifdef __clang__ +#define PRAGMA_DISABLE_PACKED_WARNING \ + _Pragma("GCC diagnostic push"); \ + _Pragma("GCC diagnostic ignored \"-Wpragmas\""); \ + _Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\"") + +#define PRAGMA_REENABLE_PACKED_WARNING \ + _Pragma("GCC diagnostic pop") + +#else +#define PRAGMA_DISABLE_PACKED_WARNING +#define PRAGMA_REENABLE_PACKED_WARNING +#endif + #if defined(_WIN32) && (defined(__x86_64__) || defined(__i386__)) # define QEMU_PACKED __attribute__((gcc_struct, packed)) #else From 6538c682db9c2b34fbffc22e111a4bcd8f4b02de Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Sun, 13 Aug 2023 10:41:24 +0200 Subject: [PATCH 1271/1353] bsd-user; Update the definitions of __put_user and __get_user macros Use __builtin_choose_expr to avoid type promotion from ?: in __put_user_e and __get_user_e macros. Copied from linux-user/qemu.h, originally by Blue Swirl. Signed-off-by: Warner Losh Signed-off-by: Karim Taha Reviewed-by: Richard Henderson --- bsd-user/qemu.h | 81 ++++++++++++++++++++--------------------------- bsd-user/signal.c | 5 +-- 2 files changed, 35 insertions(+), 51 deletions(-) diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index 61501c321b..ca791e18b2 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -272,50 +272,37 @@ static inline bool access_ok(int type, abi_ulong addr, abi_ulong size) * These are usually used to access struct data members once the struct has been * locked - usually with lock_user_struct(). */ -#define __put_user(x, hptr)\ -({\ - int size = sizeof(*hptr);\ - switch (size) {\ - case 1:\ - *(uint8_t *)(hptr) = (uint8_t)(typeof(*hptr))(x);\ - break;\ - case 2:\ - *(uint16_t *)(hptr) = tswap16((typeof(*hptr))(x));\ - break;\ - case 4:\ - *(uint32_t *)(hptr) = tswap32((typeof(*hptr))(x));\ - break;\ - case 8:\ - *(uint64_t *)(hptr) = tswap64((typeof(*hptr))(x));\ - break;\ - default:\ - abort();\ - } \ - 0;\ -}) +#define __put_user_e(x, hptr, e) \ + do { \ + PRAGMA_DISABLE_PACKED_WARNING; \ + (__builtin_choose_expr(sizeof(*(hptr)) == 1, stb_p, \ + __builtin_choose_expr(sizeof(*(hptr)) == 2, stw_##e##_p, \ + __builtin_choose_expr(sizeof(*(hptr)) == 4, stl_##e##_p, \ + __builtin_choose_expr(sizeof(*(hptr)) == 8, stq_##e##_p, abort)))) \ + ((hptr), (x)), (void)0); \ + PRAGMA_REENABLE_PACKED_WARNING; \ + } while (0) -#define __get_user(x, hptr) \ -({\ - int size = sizeof(*hptr);\ - switch (size) {\ - case 1:\ - x = (typeof(*hptr))*(uint8_t *)(hptr);\ - break;\ - case 2:\ - x = (typeof(*hptr))tswap16(*(uint16_t *)(hptr));\ - break;\ - case 4:\ - x = (typeof(*hptr))tswap32(*(uint32_t *)(hptr));\ - break;\ - case 8:\ - x = (typeof(*hptr))tswap64(*(uint64_t *)(hptr));\ - break;\ - default:\ - x = 0;\ - abort();\ - } \ - 0;\ -}) +#define __get_user_e(x, hptr, e) \ + do { \ + PRAGMA_DISABLE_PACKED_WARNING; \ + ((x) = (typeof(*hptr))( \ + __builtin_choose_expr(sizeof(*(hptr)) == 1, ldub_p, \ + __builtin_choose_expr(sizeof(*(hptr)) == 2, lduw_##e##_p, \ + __builtin_choose_expr(sizeof(*(hptr)) == 4, ldl_##e##_p, \ + __builtin_choose_expr(sizeof(*(hptr)) == 8, ldq_##e##_p, abort)))) \ + (hptr)), (void)0); \ + PRAGMA_REENABLE_PACKED_WARNING; \ + } while (0) + + +#if TARGET_BIG_ENDIAN +# define __put_user(x, hptr) __put_user_e(x, hptr, be) +# define __get_user(x, hptr) __get_user_e(x, hptr, be) +#else +# define __put_user(x, hptr) __put_user_e(x, hptr, le) +# define __get_user(x, hptr) __get_user_e(x, hptr, le) +#endif /* * put_user()/get_user() take a guest address and check access @@ -328,10 +315,10 @@ static inline bool access_ok(int type, abi_ulong addr, abi_ulong size) ({ \ abi_ulong __gaddr = (gaddr); \ target_type *__hptr; \ - abi_long __ret; \ + abi_long __ret = 0; \ __hptr = lock_user(VERIFY_WRITE, __gaddr, sizeof(target_type), 0); \ if (__hptr) { \ - __ret = __put_user((x), __hptr); \ + __put_user((x), __hptr); \ unlock_user(__hptr, __gaddr, sizeof(target_type)); \ } else \ __ret = -TARGET_EFAULT; \ @@ -342,10 +329,10 @@ static inline bool access_ok(int type, abi_ulong addr, abi_ulong size) ({ \ abi_ulong __gaddr = (gaddr); \ target_type *__hptr; \ - abi_long __ret; \ + abi_long __ret = 0; \ __hptr = lock_user(VERIFY_READ, __gaddr, sizeof(target_type), 1); \ if (__hptr) { \ - __ret = __get_user((x), __hptr); \ + __get_user((x), __hptr); \ unlock_user(__hptr, __gaddr, 0); \ } else { \ (x) = 0; \ diff --git a/bsd-user/signal.c b/bsd-user/signal.c index f4e078ee1d..4db85a3485 100644 --- a/bsd-user/signal.c +++ b/bsd-user/signal.c @@ -787,10 +787,7 @@ static int reset_signal_mask(target_ucontext_t *ucontext) TaskState *ts = (TaskState *)thread_cpu->opaque; for (i = 0; i < TARGET_NSIG_WORDS; i++) { - if (__get_user(target_set.__bits[i], - &ucontext->uc_sigmask.__bits[i])) { - return -TARGET_EFAULT; - } + __get_user(target_set.__bits[i], &ucontext->uc_sigmask.__bits[i]); } target_to_host_sigset_internal(&blocked, &target_set); ts->signal_mask = blocked; From 9b4a902d3164b60ea732cca7405fcd2d083b784e Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Sun, 13 Aug 2023 10:41:25 +0200 Subject: [PATCH 1272/1353] bsd-user: Declarations of h2t and t2h conversion functions. Declarations of functions that convert between host and target structs. Co-authored-by: Michal Meloun Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/freebsd/qemu-os.h | 50 ++++++++++++++++++++++++++++++++++++++ bsd-user/qemu.h | 1 + 2 files changed, 51 insertions(+) create mode 100644 bsd-user/freebsd/qemu-os.h diff --git a/bsd-user/freebsd/qemu-os.h b/bsd-user/freebsd/qemu-os.h new file mode 100644 index 0000000000..12adc50928 --- /dev/null +++ b/bsd-user/freebsd/qemu-os.h @@ -0,0 +1,50 @@ +/* + * FreeBSD conversion extern declarations + * + * Copyright (c) 2013 Stacey D. Son + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef QEMU_OS_H +#define QEMU_OS_H + +/* qemu/osdep.h pulls in the rest */ + +#include +#include +#include +#include +#include +#include +#include + +struct freebsd11_stat; + +/* os-stat.c */ +abi_long h2t_freebsd11_stat(abi_ulong target_addr, + struct freebsd11_stat *host_st); +abi_long h2t_freebsd11_nstat(abi_ulong target_addr, + struct freebsd11_stat *host_st); +abi_long t2h_freebsd_fhandle(fhandle_t *host_fh, abi_ulong target_addr); +abi_long h2t_freebsd_fhandle(abi_ulong target_addr, fhandle_t *host_fh); +abi_long h2t_freebsd11_statfs(abi_ulong target_addr, + struct freebsd11_statfs *host_statfs); +abi_long target_to_host_fcntl_cmd(int cmd); +abi_long h2t_freebsd_stat(abi_ulong target_addr, + struct stat *host_st); +abi_long h2t_freebsd_statfs(abi_ulong target_addr, + struct statfs *host_statfs); + +#endif /* QEMU_OS_H */ diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index ca791e18b2..4cfd5c6337 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -38,6 +38,7 @@ extern char **environ; #include "exec/gdbstub.h" #include "qemu/clang-tsa.h" +#include "qemu-os.h" /* * This struct is used to hold certain information about the image. Basically, * it replicates in user space what would be certain task_struct fields in the From 40f5e2983407e51e00e0fc82ff59c1ed55001530 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Sun, 13 Aug 2023 10:41:26 +0200 Subject: [PATCH 1273/1353] bsd-user: Add struct target_freebsd11_stat to bsd-user/syscall_defs Signed-off-by: Stacey Son Signed-off-by: Karim Taha Acked-by: Richard Henderson Singed-off-by: Warner Losh --- bsd-user/syscall_defs.h | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h index aedfbf2d7d..56198cc6a0 100644 --- a/bsd-user/syscall_defs.h +++ b/bsd-user/syscall_defs.h @@ -179,6 +179,39 @@ struct target_freebsd__wrusage { struct target_freebsd_rusage wru_children; }; +/* + * sys/stat.h + */ +struct target_freebsd11_stat { + uint32_t st_dev; /* inode's device */ + uint32_t st_ino; /* inode's number */ + int16_t st_mode; /* inode protection mode */ + int16_t st_nlink; /* number of hard links */ + uint32_t st_uid; /* user ID of the file's owner */ + uint32_t st_gid; /* group ID of the file's group */ + uint32_t st_rdev; /* device type */ + struct target_freebsd_timespec st_atim; /* time last accessed */ + struct target_freebsd_timespec st_mtim; /* time last data modification */ + struct target_freebsd_timespec st_ctim; /* time last file status change */ + int64_t st_size; /* file size, in bytes */ + int64_t st_blocks; /* blocks allocated for file */ + uint32_t st_blksize; /* optimal blocksize for I/O */ + uint32_t st_flags; /* user defined flags for file */ + uint32_t st_gen; /* file generation number */ + int32_t st_lspare; + struct target_freebsd_timespec st_birthtim; /* time of file creation */ + /* + * Explicitly pad st_birthtim to 16 bytes so that the size of + * struct stat is backwards compatible. We use bitfields instead + * of an array of chars so that this doesn't require a C99 compiler + * to compile if the size of the padding is 0. We use 2 bitfields + * to cover up to 64 bits on 32-bit machines. We assume that + * CHAR_BIT is 8... + */ + unsigned int:(8 / 2) * (16 - (int)sizeof(struct target_freebsd_timespec)); + unsigned int:(8 / 2) * (16 - (int)sizeof(struct target_freebsd_timespec)); +} __packed; + #define safe_syscall0(type, name) \ type safe_##name(void) \ { \ From ad805a77592a1765515c70be225ec3097c954e5c Mon Sep 17 00:00:00 2001 From: Michal Meloun Date: Sun, 13 Aug 2023 10:41:27 +0200 Subject: [PATCH 1274/1353] bsd-user: Add struct target_stat to bsd-user/syscall_defs.h Signed-off-by: Michal Meloun Signed-off-by: Karim Taha Acked-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/syscall_defs.h | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h index 56198cc6a0..bd04b30a56 100644 --- a/bsd-user/syscall_defs.h +++ b/bsd-user/syscall_defs.h @@ -212,6 +212,44 @@ struct target_freebsd11_stat { unsigned int:(8 / 2) * (16 - (int)sizeof(struct target_freebsd_timespec)); } __packed; +#if defined(__i386__) +#define TARGET_HAS_STAT_TIME_T_EXT 1 +#endif + +struct target_stat { + uint64_t st_dev; /* inode's device */ + uint64_t st_ino; /* inode's number */ + uint64_t st_nlink; /* number of hard links */ + int16_t st_mode; /* inode protection mode */ + int16_t st_padding0; + uint32_t st_uid; /* user ID of the file's owner */ + uint32_t st_gid; /* group ID of the file's group */ + int32_t st_padding1; + uint64_t st_rdev; /* device type */ +#ifdef TARGET_HAS_STAT_TIME_T_EXT + int32_t st_atim_ext; +#endif + struct target_freebsd_timespec st_atim; /* time of last access */ +#ifdef TARGET_HAS_STAT_TIME_T_EXT + int32_t st_mtim_ext; +#endif + struct target_freebsd_timespec st_mtim; /* time of last data modification */ +#ifdef TARGET_HAS_STAT_TIME_T_EXT + int32_t st_ctim_ext; +#endif + struct target_freebsd_timespec st_ctim;/* time of last file status change */ +#ifdef TARGET_HAS_STAT_TIME_T_EXT + int32_t st_btim_ext; +#endif + struct target_freebsd_timespec st_birthtim; /* time of file creation */ + int64_t st_size; /* file size, in bytes */ + int64_t st_blocks; /* blocks allocated for file */ + uint32_t st_blksize; /* optimal blocksize for I/O */ + uint32_t st_flags; /* user defined flags for file */ + uint64_t st_gen; /* file generation number */ + uint64_t st_spare[10]; +}; + #define safe_syscall0(type, name) \ type safe_##name(void) \ { \ From 1de075a0f6c6aa0ab54cef4fae902d4c0e95effa Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Sun, 13 Aug 2023 10:41:28 +0200 Subject: [PATCH 1275/1353] bsd-user: Add structs target_freebsd11_{nstat,statfs} Add structs target_freebsd11_nstat and target_freebsd11_statfs to bsd-user/syscall_defs.h Signed-off-by: Stacey Son Signed-off-by: Karim Taha Acked-by: Richard Henderson --- bsd-user/syscall_defs.h | 64 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h index bd04b30a56..51d8ff0dd8 100644 --- a/bsd-user/syscall_defs.h +++ b/bsd-user/syscall_defs.h @@ -250,6 +250,70 @@ struct target_stat { uint64_t st_spare[10]; }; + +/* struct nstat is the same as stat above but without the st_lspare field */ +struct target_freebsd11_nstat { + uint32_t st_dev; /* inode's device */ + uint32_t st_ino; /* inode's number */ + int16_t st_mode; /* inode protection mode */ + int16_t st_nlink; /* number of hard links */ + uint32_t st_uid; /* user ID of the file's owner */ + uint32_t st_gid; /* group ID of the file's group */ + uint32_t st_rdev; /* device type */ + struct target_freebsd_timespec st_atim; /* time last accessed */ + struct target_freebsd_timespec st_mtim; /* time last data modification */ + struct target_freebsd_timespec st_ctim; /* time last file status change */ + int64_t st_size; /* file size, in bytes */ + int64_t st_blocks; /* blocks allocated for file */ + uint32_t st_blksize; /* optimal blocksize for I/O */ + uint32_t st_flags; /* user defined flags for file */ + uint32_t st_gen; /* file generation number */ + struct target_freebsd_timespec st_birthtim; /* time of file creation */ + /* + * Explicitly pad st_birthtim to 16 bytes so that the size of + * struct stat is backwards compatible. We use bitfields instead + * of an array of chars so that this doesn't require a C99 compiler + * to compile if the size of the padding is 0. We use 2 bitfields + * to cover up to 64 bits on 32-bit machines. We assume that + * CHAR_BIT is 8... + */ + unsigned int:(8 / 2) * (16 - (int)sizeof(struct target_freebsd_timespec)); + unsigned int:(8 / 2) * (16 - (int)sizeof(struct target_freebsd_timespec)); +} __packed; + +/* + * sys/mount.h + */ + +/* filesystem id type */ +typedef struct target_freebsd_fsid { int32_t val[2]; } target_freebsd_fsid_t; + +/* filesystem statistics */ +struct target_freebsd11_statfs { + uint32_t f_version; /* structure version number */ + uint32_t f_type; /* type of filesystem */ + uint64_t f_flags; /* copy of mount exported flags */ + uint64_t f_bsize; /* filesystem fragment size */ + uint64_t f_iosize; /* optimal transfer block size */ + uint64_t f_blocks; /* total data blocks in filesystem */ + uint64_t f_bfree; /* free blocks in filesystem */ + int64_t f_bavail; /* free blocks avail to non-superuser */ + uint64_t f_files; /* total file nodes in filesystem */ + int64_t f_ffree; /* free nodes avail to non-superuser */ + uint64_t f_syncwrites; /* count of sync writes since mount */ + uint64_t f_asyncwrites; /* count of async writes since mount */ + uint64_t f_syncreads; /* count of sync reads since mount */ + uint64_t f_asyncreads; /* count of async reads since mount */ + uint64_t f_spare[10]; /* unused spare */ + uint32_t f_namemax; /* maximum filename length */ + uint32_t f_owner; /* user that mounted the filesystem */ + target_freebsd_fsid_t f_fsid; /* filesystem id */ + char f_charspare[80]; /* spare string space */ + char f_fstypename[16]; /* filesys type name */ + char f_mntfromname[88]; /* mount filesystem */ + char f_mntonname[88]; /* dir on which mounted*/ +}; + #define safe_syscall0(type, name) \ type safe_##name(void) \ { \ From 25efcda41f107f124019f338ae929a694ec6191e Mon Sep 17 00:00:00 2001 From: Michal Meloun Date: Sun, 13 Aug 2023 10:41:29 +0200 Subject: [PATCH 1276/1353] bsd-user: Add struct target_statfs Add struct target_statfs to bsd-user/syscall_defs.h Signed-off-by: Michal Meloun Signed-off-by: Karim Taha Acked-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/syscall_defs.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h index 51d8ff0dd8..499a80f8bf 100644 --- a/bsd-user/syscall_defs.h +++ b/bsd-user/syscall_defs.h @@ -314,6 +314,31 @@ struct target_freebsd11_statfs { char f_mntonname[88]; /* dir on which mounted*/ }; +struct target_statfs { + uint32_t f_version; /* structure version number */ + uint32_t f_type; /* type of filesystem */ + uint64_t f_flags; /* copy of mount exported flags */ + uint64_t f_bsize; /* filesystem fragment size */ + uint64_t f_iosize; /* optimal transfer block size */ + uint64_t f_blocks; /* total data blocks in filesystem */ + uint64_t f_bfree; /* free blocks in filesystem */ + int64_t f_bavail; /* free blocks avail to non-superuser */ + uint64_t f_files; /* total file nodes in filesystem */ + int64_t f_ffree; /* free nodes avail to non-superuser */ + uint64_t f_syncwrites; /* count of sync writes since mount */ + uint64_t f_asyncwrites; /* count of async writes since mount */ + uint64_t f_syncreads; /* count of sync reads since mount */ + uint64_t f_asyncreads; /* count of async reads since mount */ + uint64_t f_spare[10]; /* unused spare */ + uint32_t f_namemax; /* maximum filename length */ + uint32_t f_owner; /* user that mounted the filesystem */ + target_freebsd_fsid_t f_fsid; /* filesystem id */ + char f_charspare[80]; /* spare string space */ + char f_fstypename[16]; /* filesystem type name */ + char f_mntfromname[1024]; /* mounted filesystem */ + char f_mntonname[1024]; /* directory on which mounted */ +}; + #define safe_syscall0(type, name) \ type safe_##name(void) \ { \ From 54d07b44aa534277d72fa570498bd379c06d9a40 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Sun, 13 Aug 2023 10:41:30 +0200 Subject: [PATCH 1277/1353] bsd-user: Add struct target_freebsd_fhandle and fcntl flags Add struct target_freebsd_fhandle and fcntl flags to bsd-user/syscall_defs.h Signed-off-by: Stacey Son Signed-off-by: Karim Taha Acked-by: Richard Henderson Reviewed-by: Warner Losh Signed-off-by: Warner Losh --- bsd-user/syscall_defs.h | 51 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h index 499a80f8bf..96ae90b063 100644 --- a/bsd-user/syscall_defs.h +++ b/bsd-user/syscall_defs.h @@ -339,6 +339,57 @@ struct target_statfs { char f_mntonname[1024]; /* directory on which mounted */ }; +/* File identifier. These are unique per filesystem on a single machine. */ +#define TARGET_MAXFIDSZ 16 + +struct target_freebsd_fid { + uint16_t fid_len; /* len of data in bytes */ + uint16_t fid_data0; /* force longword align */ + char fid_data[TARGET_MAXFIDSZ]; /* data (variable len) */ +}; + +/* Generic file handle */ +struct target_freebsd_fhandle { + target_freebsd_fsid_t fh_fsid; /* Filesystem id of mount point */ + struct target_freebsd_fid fh_fid; /* Filesys specific id */ +}; +typedef struct target_freebsd_fhandle target_freebsd_fhandle_t; + +/* + * sys/fcntl.h + */ +#define TARGET_F_DUPFD 0 +#define TARGET_F_GETFD 1 +#define TARGET_F_SETFD 2 +#define TARGET_F_GETFL 3 +#define TARGET_F_SETFL 4 +#define TARGET_F_GETOWN 5 +#define TARGET_F_SETOWN 6 +#define TARGET_F_OGETLK 7 +#define TARGET_F_OSETLK 8 +#define TARGET_F_OSETLKW 9 +#define TARGET_F_DUP2FD 10 +#define TARGET_F_GETLK 11 +#define TARGET_F_SETLK 12 +#define TARGET_F_SETLKW 13 +#define TARGET_F_SETLK_REMOTE 14 +#define TARGET_F_READAHEAD 15 +#define TARGET_F_RDAHEAD 16 +#define TARGET_F_DUPFD_CLOEXEC 17 +#define TARGET_F_DUP2FD_CLOEXEC 18 +/* FreeBSD-specific */ +#define TARGET_F_ADD_SEALS 19 +#define TARGET_F_GET_SEALS 20 + +struct target_freebsd_flock { + int64_t l_start; + int64_t l_len; + int32_t l_pid; + int16_t l_type; + int16_t l_whence; + int32_t l_sysid; +} QEMU_PACKED; + #define safe_syscall0(type, name) \ type safe_##name(void) \ { \ From 243c725fe7489b15aa441a20b0298035481da2f9 Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Sat, 19 Aug 2023 20:23:27 -0600 Subject: [PATCH 1278/1353] bsd-user: Define safe_fcntl macro in bsd-user/syscall_defs.h Signed-off-by: Kyle Evans Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/syscall_defs.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h index 96ae90b063..c6699c9943 100644 --- a/bsd-user/syscall_defs.h +++ b/bsd-user/syscall_defs.h @@ -437,6 +437,8 @@ type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ return safe_syscall(SYS_##name, arg1, arg2, arg3, arg4, arg5, arg6); \ } +#define safe_fcntl(...) safe_syscall(SYS_fcntl, __VA_ARGS__) + /* So far all target and host bitmasks are the same */ #undef target_to_host_bitmask #define target_to_host_bitmask(x, tbl) (x) From a0c20b1b36576042d1c2789f92b42043f48409c4 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Sun, 13 Aug 2023 10:41:32 +0200 Subject: [PATCH 1279/1353] bsd-user: Rename target_freebsd_time_t to target_time_t This is necessary for future code using target_time_t, in bsd-user/syscall_defs. Signed-off-by: Warner Losh Signed-off-by: Karim Taha Reviewed-by: Richard Henderson --- bsd-user/syscall_defs.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h index c6699c9943..9c90616baa 100644 --- a/bsd-user/syscall_defs.h +++ b/bsd-user/syscall_defs.h @@ -45,9 +45,9 @@ * */ #if (!defined(TARGET_I386)) -typedef int64_t target_freebsd_time_t; +typedef int64_t target_time_t; #else -typedef int32_t target_freebsd_time_t; +typedef int32_t target_time_t; #endif struct target_iovec { @@ -102,7 +102,7 @@ typedef abi_long target_freebsd_suseconds_t; /* compare to sys/timespec.h */ struct target_freebsd_timespec { - target_freebsd_time_t tv_sec; /* seconds */ + target_time_t tv_sec; /* seconds */ abi_long tv_nsec; /* and nanoseconds */ #if !defined(TARGET_I386) && TARGET_ABI_BITS == 32 abi_long _pad; @@ -120,7 +120,7 @@ struct target_freebsd__umtx_time { }; struct target_freebsd_timeval { - target_freebsd_time_t tv_sec; /* seconds */ + target_time_t tv_sec; /* seconds */ target_freebsd_suseconds_t tv_usec;/* and microseconds */ #if !defined(TARGET_I386) && TARGET_ABI_BITS == 32 abi_long _pad; From 86547e577bdfe55f32778a052b82227599233067 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Sun, 13 Aug 2023 10:41:33 +0200 Subject: [PATCH 1280/1353] bsd-user: Implement h2t_freebsd11_stat h2t_freebsd_nstat Implement the stat conversion functions: h2t_freebsd11_stat h2t_freebsd_nstat Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/freebsd/os-stat.c | 94 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 bsd-user/freebsd/os-stat.c diff --git a/bsd-user/freebsd/os-stat.c b/bsd-user/freebsd/os-stat.c new file mode 100644 index 0000000000..8c73f7402c --- /dev/null +++ b/bsd-user/freebsd/os-stat.c @@ -0,0 +1,94 @@ +/* + * FreeBSD stat related conversion routines + * + * Copyright (c) 2013 Stacey D. Son + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ +#include "qemu/osdep.h" + +#include "qemu.h" + +/* + * stat conversion + */ +abi_long h2t_freebsd11_stat(abi_ulong target_addr, + struct freebsd11_stat *host_st) +{ + struct target_freebsd11_stat *target_st; + + if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0)) { + return -TARGET_EFAULT; + } + memset(target_st, 0, sizeof(*target_st)); + __put_user(host_st->st_dev, &target_st->st_dev); + __put_user(host_st->st_ino, &target_st->st_ino); + __put_user(host_st->st_mode, &target_st->st_mode); + __put_user(host_st->st_nlink, &target_st->st_nlink); + __put_user(host_st->st_uid, &target_st->st_uid); + __put_user(host_st->st_gid, &target_st->st_gid); + __put_user(host_st->st_rdev, &target_st->st_rdev); + __put_user(host_st->st_atim.tv_sec, &target_st->st_atim.tv_sec); + __put_user(host_st->st_atim.tv_nsec, &target_st->st_atim.tv_nsec); + __put_user(host_st->st_mtim.tv_sec, &target_st->st_mtim.tv_sec); + __put_user(host_st->st_mtim.tv_nsec, &target_st->st_mtim.tv_nsec); + __put_user(host_st->st_ctim.tv_sec, &target_st->st_ctim.tv_sec); + __put_user(host_st->st_ctim.tv_nsec, &target_st->st_ctim.tv_nsec); + __put_user(host_st->st_size, &target_st->st_size); + __put_user(host_st->st_blocks, &target_st->st_blocks); + __put_user(host_st->st_blksize, &target_st->st_blksize); + __put_user(host_st->st_flags, &target_st->st_flags); + __put_user(host_st->st_gen, &target_st->st_gen); + /* st_lspare not used */ + __put_user(host_st->st_birthtim.tv_sec, &target_st->st_birthtim.tv_sec); + __put_user(host_st->st_birthtim.tv_nsec, &target_st->st_birthtim.tv_nsec); + unlock_user_struct(target_st, target_addr, 1); + + return 0; +} + +abi_long h2t_freebsd11_nstat(abi_ulong target_addr, + struct freebsd11_stat *host_st) +{ + struct target_freebsd11_nstat *target_st; + + if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0)) { + return -TARGET_EFAULT; + } + memset(target_st, 0, sizeof(*target_st)); + __put_user(host_st->st_dev, &target_st->st_dev); + __put_user(host_st->st_ino, &target_st->st_ino); + __put_user(host_st->st_mode, &target_st->st_mode); + __put_user(host_st->st_nlink, &target_st->st_nlink); + __put_user(host_st->st_uid, &target_st->st_uid); + __put_user(host_st->st_gid, &target_st->st_gid); + __put_user(host_st->st_rdev, &target_st->st_rdev); + __put_user(host_st->st_atim.tv_sec, &target_st->st_atim.tv_sec); + __put_user(host_st->st_atim.tv_nsec, &target_st->st_atim.tv_nsec); + __put_user(host_st->st_mtim.tv_sec, &target_st->st_mtim.tv_sec); + __put_user(host_st->st_mtim.tv_nsec, &target_st->st_mtim.tv_nsec); + __put_user(host_st->st_ctim.tv_sec, &target_st->st_ctim.tv_sec); + __put_user(host_st->st_ctim.tv_nsec, &target_st->st_ctim.tv_nsec); + __put_user(host_st->st_size, &target_st->st_size); + __put_user(host_st->st_blocks, &target_st->st_blocks); + __put_user(host_st->st_blksize, &target_st->st_blksize); + __put_user(host_st->st_flags, &target_st->st_flags); + __put_user(host_st->st_gen, &target_st->st_gen); + __put_user(host_st->st_birthtim.tv_sec, &target_st->st_birthtim.tv_sec); + __put_user(host_st->st_birthtim.tv_nsec, &target_st->st_birthtim.tv_nsec); + unlock_user_struct(target_st, target_addr, 1); + + return 0; +} + From f2bc92aaf3d2944fd41073ed3bfb5addf9ee96e7 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Sun, 13 Aug 2023 10:41:34 +0200 Subject: [PATCH 1281/1353] bsd-user: Implement h2t_freebsd_fhandle t2h_freebsd_fhandle Implement the stat conversion functions: h2t_freebsd_fhandle t2h_freebsd_fhandle Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/freebsd/os-stat.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/bsd-user/freebsd/os-stat.c b/bsd-user/freebsd/os-stat.c index 8c73f7402c..6716cee3e2 100644 --- a/bsd-user/freebsd/os-stat.c +++ b/bsd-user/freebsd/os-stat.c @@ -92,3 +92,40 @@ abi_long h2t_freebsd11_nstat(abi_ulong target_addr, return 0; } +/* + * file handle conversion + */ +abi_long t2h_freebsd_fhandle(fhandle_t *host_fh, abi_ulong target_addr) +{ + target_freebsd_fhandle_t *target_fh; + + if (!lock_user_struct(VERIFY_READ, target_fh, target_addr, 1)) { + return -TARGET_EFAULT; + } + __get_user(host_fh->fh_fsid.val[0], &target_fh->fh_fsid.val[0]); + __get_user(host_fh->fh_fsid.val[1], &target_fh->fh_fsid.val[0]); + __get_user(host_fh->fh_fid.fid_len, &target_fh->fh_fid.fid_len); + /* u_short fid_data0; */ + memcpy(host_fh->fh_fid.fid_data, target_fh->fh_fid.fid_data, + TARGET_MAXFIDSZ); + unlock_user_struct(target_fh, target_addr, 0); + return 0; +} + +abi_long h2t_freebsd_fhandle(abi_ulong target_addr, fhandle_t *host_fh) +{ + target_freebsd_fhandle_t *target_fh; + + if (!lock_user_struct(VERIFY_WRITE, target_fh, target_addr, 0)) { + return -TARGET_EFAULT; + } + __put_user(host_fh->fh_fsid.val[0], &target_fh->fh_fsid.val[0]); + __put_user(host_fh->fh_fsid.val[1], &target_fh->fh_fsid.val[0]); + __put_user(host_fh->fh_fid.fid_len, &target_fh->fh_fid.fid_len); + /* u_short fid_data0; */ + memcpy(target_fh->fh_fid.fid_data, host_fh->fh_fid.fid_data, + TARGET_MAXFIDSZ); + unlock_user_struct(target_fh, target_addr, 1); + return 0; +} + From 5aa88f962cac2e93f222c48c92a14d685aaf00e7 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Sun, 13 Aug 2023 10:41:35 +0200 Subject: [PATCH 1282/1353] bsd-user: Implement h2t_freebds11_statfs Implement the stat conversion functions: h2t_freebds11_statfs Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/freebsd/os-stat.c | 41 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/bsd-user/freebsd/os-stat.c b/bsd-user/freebsd/os-stat.c index 6716cee3e2..9eb01bf664 100644 --- a/bsd-user/freebsd/os-stat.c +++ b/bsd-user/freebsd/os-stat.c @@ -129,3 +129,44 @@ abi_long h2t_freebsd_fhandle(abi_ulong target_addr, fhandle_t *host_fh) return 0; } +/* + * file system stat + */ +abi_long h2t_freebsd11_statfs(abi_ulong target_addr, + struct freebsd11_statfs *host_statfs) +{ + struct target_freebsd11_statfs *target_statfs; + + if (!lock_user_struct(VERIFY_WRITE, target_statfs, target_addr, 0)) { + return -TARGET_EFAULT; + } + __put_user(host_statfs->f_version, &target_statfs->f_version); + __put_user(host_statfs->f_type, &target_statfs->f_type); + __put_user(host_statfs->f_flags, &target_statfs->f_flags); + __put_user(host_statfs->f_bsize, &target_statfs->f_bsize); + __put_user(host_statfs->f_iosize, &target_statfs->f_iosize); + __put_user(host_statfs->f_blocks, &target_statfs->f_blocks); + __put_user(host_statfs->f_bfree, &target_statfs->f_bfree); + __put_user(host_statfs->f_bavail, &target_statfs->f_bavail); + __put_user(host_statfs->f_files, &target_statfs->f_files); + __put_user(host_statfs->f_ffree, &target_statfs->f_ffree); + __put_user(host_statfs->f_syncwrites, &target_statfs->f_syncwrites); + __put_user(host_statfs->f_asyncwrites, &target_statfs->f_asyncwrites); + __put_user(host_statfs->f_syncreads, &target_statfs->f_syncreads); + __put_user(host_statfs->f_asyncreads, &target_statfs->f_asyncreads); + /* uint64_t f_spare[10]; */ + __put_user(host_statfs->f_namemax, &target_statfs->f_namemax); + __put_user(host_statfs->f_owner, &target_statfs->f_owner); + __put_user(host_statfs->f_fsid.val[0], &target_statfs->f_fsid.val[0]); + __put_user(host_statfs->f_fsid.val[1], &target_statfs->f_fsid.val[1]); + /* char f_charspace[80]; */ + strncpy(target_statfs->f_fstypename, host_statfs->f_fstypename, + sizeof(target_statfs->f_fstypename)); + strncpy(target_statfs->f_mntfromname, host_statfs->f_mntfromname, + sizeof(target_statfs->f_mntfromname)); + strncpy(target_statfs->f_mntonname, host_statfs->f_mntonname, + sizeof(target_statfs->f_mntonname)); + unlock_user_struct(target_statfs, target_addr, 1); + return 0; +} + From 584d6fce65bd80335795d80c0e9bf1062ef3c4f6 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Sun, 13 Aug 2023 10:41:36 +0200 Subject: [PATCH 1283/1353] bsd-user: Implement target_to_host_fcntl_cmd Implement the stat conversion functions: target_to_host_fcntl_cmd Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/freebsd/os-stat.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/bsd-user/freebsd/os-stat.c b/bsd-user/freebsd/os-stat.c index 9eb01bf664..2ce235d5da 100644 --- a/bsd-user/freebsd/os-stat.c +++ b/bsd-user/freebsd/os-stat.c @@ -170,3 +170,11 @@ abi_long h2t_freebsd11_statfs(abi_ulong target_addr, return 0; } +/* + * fcntl cmd conversion + */ +abi_long target_to_host_fcntl_cmd(int cmd) +{ + return cmd; +} + From f9d5a35fbbfeb534e748fc79df7f3f85b83c695a Mon Sep 17 00:00:00 2001 From: Michal Meloun Date: Sun, 13 Aug 2023 10:41:37 +0200 Subject: [PATCH 1284/1353] bsd-uesr: Implement h2t_freebsd_stat and h2t_freebsd_statfs functions They are the 64-bit variants of h2t_freebsd11_stat and h2t_freebsd11_statfs, respectively Signed-off-by: Michal Meloun Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/freebsd/os-stat.c | 82 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/bsd-user/freebsd/os-stat.c b/bsd-user/freebsd/os-stat.c index 2ce235d5da..f0f9e609c3 100644 --- a/bsd-user/freebsd/os-stat.c +++ b/bsd-user/freebsd/os-stat.c @@ -58,6 +58,50 @@ abi_long h2t_freebsd11_stat(abi_ulong target_addr, return 0; } +abi_long h2t_freebsd_stat(abi_ulong target_addr, + struct stat *host_st) +{ + struct target_stat *target_st; + + if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0)) { + return -TARGET_EFAULT; + } + memset(target_st, 0, sizeof(*target_st)); + __put_user(host_st->st_dev, &target_st->st_dev); + __put_user(host_st->st_ino, &target_st->st_ino); + __put_user(host_st->st_nlink, &target_st->st_nlink); + __put_user(host_st->st_mode, &target_st->st_mode); + __put_user(host_st->st_uid, &target_st->st_uid); + __put_user(host_st->st_gid, &target_st->st_gid); + __put_user(host_st->st_rdev, &target_st->st_rdev); + __put_user(host_st->st_atim.tv_sec, &target_st->st_atim.tv_sec); + __put_user(host_st->st_atim.tv_nsec, &target_st->st_atim.tv_nsec); +#ifdef TARGET_HAS_STAT_TIME_T_EXT +/* __put_user(host_st->st_mtim_ext, &target_st->st_mtim_ext); XXX */ +#endif + __put_user(host_st->st_mtim.tv_sec, &target_st->st_mtim.tv_sec); + __put_user(host_st->st_mtim.tv_nsec, &target_st->st_mtim.tv_nsec); +#ifdef TARGET_HAS_STAT_TIME_T_EXT +/* __put_user(host_st->st_ctim_ext, &target_st->st_ctim_ext); XXX */ +#endif + __put_user(host_st->st_ctim.tv_sec, &target_st->st_ctim.tv_sec); + __put_user(host_st->st_ctim.tv_nsec, &target_st->st_ctim.tv_nsec); +#ifdef TARGET_HAS_STAT_TIME_T_EXT +/* __put_user(host_st->st_birthtim_ext, &target_st->st_birthtim_ext); XXX */ +#endif + __put_user(host_st->st_birthtim.tv_sec, &target_st->st_birthtim.tv_sec); + __put_user(host_st->st_birthtim.tv_nsec, &target_st->st_birthtim.tv_nsec); + + __put_user(host_st->st_size, &target_st->st_size); + __put_user(host_st->st_blocks, &target_st->st_blocks); + __put_user(host_st->st_blksize, &target_st->st_blksize); + __put_user(host_st->st_flags, &target_st->st_flags); + __put_user(host_st->st_gen, &target_st->st_gen); + unlock_user_struct(target_st, target_addr, 1); + + return 0; +} + abi_long h2t_freebsd11_nstat(abi_ulong target_addr, struct freebsd11_stat *host_st) { @@ -170,6 +214,44 @@ abi_long h2t_freebsd11_statfs(abi_ulong target_addr, return 0; } +abi_long h2t_freebsd_statfs(abi_ulong target_addr, + struct statfs *host_statfs) +{ + struct target_statfs *target_statfs; + + if (!lock_user_struct(VERIFY_WRITE, target_statfs, target_addr, 0)) { + return -TARGET_EFAULT; + } + __put_user(host_statfs->f_version, &target_statfs->f_version); + __put_user(host_statfs->f_type, &target_statfs->f_type); + __put_user(host_statfs->f_flags, &target_statfs->f_flags); + __put_user(host_statfs->f_bsize, &target_statfs->f_bsize); + __put_user(host_statfs->f_iosize, &target_statfs->f_iosize); + __put_user(host_statfs->f_blocks, &target_statfs->f_blocks); + __put_user(host_statfs->f_bfree, &target_statfs->f_bfree); + __put_user(host_statfs->f_bavail, &target_statfs->f_bavail); + __put_user(host_statfs->f_files, &target_statfs->f_files); + __put_user(host_statfs->f_ffree, &target_statfs->f_ffree); + __put_user(host_statfs->f_syncwrites, &target_statfs->f_syncwrites); + __put_user(host_statfs->f_asyncwrites, &target_statfs->f_asyncwrites); + __put_user(host_statfs->f_syncreads, &target_statfs->f_syncreads); + __put_user(host_statfs->f_asyncreads, &target_statfs->f_asyncreads); + /* uint64_t f_spare[10]; */ + __put_user(host_statfs->f_namemax, &target_statfs->f_namemax); + __put_user(host_statfs->f_owner, &target_statfs->f_owner); + __put_user(host_statfs->f_fsid.val[0], &target_statfs->f_fsid.val[0]); + __put_user(host_statfs->f_fsid.val[1], &target_statfs->f_fsid.val[1]); + /* char f_charspace[80]; */ + strncpy(target_statfs->f_fstypename, host_statfs->f_fstypename, + sizeof(target_statfs->f_fstypename)); + strncpy(target_statfs->f_mntfromname, host_statfs->f_mntfromname, + sizeof(target_statfs->f_mntfromname)); + strncpy(target_statfs->f_mntonname, host_statfs->f_mntonname, + sizeof(target_statfs->f_mntonname)); + unlock_user_struct(target_statfs, target_addr, 1); + return 0; +} + /* * fcntl cmd conversion */ From bf14f13d8be8f572fa169a866d3244fa4a1988ac Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Sun, 13 Aug 2023 10:41:38 +0200 Subject: [PATCH 1285/1353] bsd-user: Implement stat related syscalls Implement the following syscalls: stat(2) lstat(2) fstat(2) fstatat(2) nstat nfstat nlstat Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/freebsd/os-stat.h | 130 +++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 bsd-user/freebsd/os-stat.h diff --git a/bsd-user/freebsd/os-stat.h b/bsd-user/freebsd/os-stat.h new file mode 100644 index 0000000000..f8f99b4a72 --- /dev/null +++ b/bsd-user/freebsd/os-stat.h @@ -0,0 +1,130 @@ +/* + * stat related system call shims and definitions + * + * Copyright (c) 2013 Stacey D. Son + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef BSD_USER_FREEBSD_OS_STAT_H +#define BSD_USER_FREEBSD_OS_STAT_H + +/* stat(2) */ +static inline abi_long do_freebsd11_stat(abi_long arg1, abi_long arg2) +{ + abi_long ret; + void *p; + struct freebsd11_stat st; + + LOCK_PATH(p, arg1); + ret = get_errno(freebsd11_stat(path(p), &st)); + UNLOCK_PATH(p, arg1); + if (!is_error(ret)) { + ret = h2t_freebsd11_stat(arg2, &st); + } + return ret; +} + +/* lstat(2) */ +static inline abi_long do_freebsd11_lstat(abi_long arg1, abi_long arg2) +{ + abi_long ret; + void *p; + struct freebsd11_stat st; + + LOCK_PATH(p, arg1); + ret = get_errno(freebsd11_lstat(path(p), &st)); + UNLOCK_PATH(p, arg1); + if (!is_error(ret)) { + ret = h2t_freebsd11_stat(arg2, &st); + } + return ret; +} + +/* fstat(2) */ +static inline abi_long do_freebsd_fstat(abi_long arg1, abi_long arg2) +{ + abi_long ret; + struct stat st; + + ret = get_errno(fstat(arg1, &st)); + if (!is_error(ret)) { + ret = h2t_freebsd_stat(arg2, &st); + } + return ret; +} + +/* fstatat(2) */ +static inline abi_long do_freebsd_fstatat(abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4) +{ + abi_long ret; + void *p; + struct stat st; + + LOCK_PATH(p, arg2); + ret = get_errno(fstatat(arg1, p, &st, arg4)); + UNLOCK_PATH(p, arg2); + if (!is_error(ret) && arg3) { + ret = h2t_freebsd_stat(arg3, &st); + } + return ret; +} + +/* undocummented nstat(char *path, struct nstat *ub) syscall */ +static abi_long do_freebsd11_nstat(abi_long arg1, abi_long arg2) +{ + abi_long ret; + void *p; + struct freebsd11_stat st; + + LOCK_PATH(p, arg1); + ret = get_errno(freebsd11_nstat(path(p), &st)); + UNLOCK_PATH(p, arg1); + if (!is_error(ret)) { + ret = h2t_freebsd11_nstat(arg2, &st); + } + return ret; +} + +/* undocummented nfstat(int fd, struct nstat *sb) syscall */ +static abi_long do_freebsd11_nfstat(abi_long arg1, abi_long arg2) +{ + abi_long ret; + struct freebsd11_stat st; + + ret = get_errno(freebsd11_nfstat(arg1, &st)); + if (!is_error(ret)) { + ret = h2t_freebsd11_nstat(arg2, &st); + } + return ret; +} + +/* undocummented nlstat(char *path, struct nstat *ub) syscall */ +static abi_long do_freebsd11_nlstat(abi_long arg1, abi_long arg2) +{ + abi_long ret; + void *p; + struct freebsd11_stat st; + + LOCK_PATH(p, arg1); + ret = get_errno(freebsd11_nlstat(path(p), &st)); + UNLOCK_PATH(p, arg1); + if (!is_error(ret)) { + ret = h2t_freebsd11_nstat(arg2, &st); + } + return ret; +} + +#endif /* BSD_USER_FREEBSD_OS_STAT_H */ From db8ee08f0a88ae04ee6b684690a3d53f862e7ea3 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Sun, 13 Aug 2023 10:41:39 +0200 Subject: [PATCH 1286/1353] bsd-user: Implement statfh related syscalls Implement the following syscalls: getfh(2) lgetfh(2) fhopen(2) fhstat(2) fhstatfs(2) Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/freebsd/os-stat.h | 83 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/bsd-user/freebsd/os-stat.h b/bsd-user/freebsd/os-stat.h index f8f99b4a72..935663c071 100644 --- a/bsd-user/freebsd/os-stat.h +++ b/bsd-user/freebsd/os-stat.h @@ -127,4 +127,87 @@ static abi_long do_freebsd11_nlstat(abi_long arg1, abi_long arg2) return ret; } +/* getfh(2) */ +static abi_long do_freebsd_getfh(abi_long arg1, abi_long arg2) +{ + abi_long ret; + void *p; + fhandle_t host_fh; + + LOCK_PATH(p, arg1); + ret = get_errno(getfh(path(p), &host_fh)); + UNLOCK_PATH(p, arg1); + if (is_error(ret)) { + return ret; + } + return h2t_freebsd_fhandle(arg2, &host_fh); +} + +/* lgetfh(2) */ +static inline abi_long do_freebsd_lgetfh(abi_long arg1, abi_long arg2) +{ + abi_long ret; + void *p; + fhandle_t host_fh; + + LOCK_PATH(p, arg1); + ret = get_errno(lgetfh(path(p), &host_fh)); + UNLOCK_PATH(p, arg1); + if (is_error(ret)) { + return ret; + } + return h2t_freebsd_fhandle(arg2, &host_fh); +} + +/* fhopen(2) */ +static inline abi_long do_freebsd_fhopen(abi_long arg1, abi_long arg2) +{ + abi_long ret; + fhandle_t host_fh; + + ret = t2h_freebsd_fhandle(&host_fh, arg1); + if (is_error(ret)) { + return ret; + } + + return get_errno(fhopen(&host_fh, arg2)); +} + +/* fhstat(2) */ +static inline abi_long do_freebsd_fhstat(abi_long arg1, abi_long arg2) +{ + abi_long ret; + fhandle_t host_fh; + struct stat host_sb; + + ret = t2h_freebsd_fhandle(&host_fh, arg1); + if (is_error(ret)) { + return ret; + } + ret = get_errno(fhstat(&host_fh, &host_sb)); + if (is_error(ret)) { + return ret; + } + return h2t_freebsd_stat(arg2, &host_sb); +} + +/* fhstatfs(2) */ +static inline abi_long do_freebsd_fhstatfs(abi_ulong target_fhp_addr, + abi_ulong target_stfs_addr) +{ + abi_long ret; + fhandle_t host_fh; + struct statfs host_stfs; + + ret = t2h_freebsd_fhandle(&host_fh, target_fhp_addr); + if (is_error(ret)) { + return ret; + } + ret = get_errno(fhstatfs(&host_fh, &host_stfs)); + if (is_error(ret)) { + return ret; + } + return h2t_freebsd_statfs(target_stfs_addr, &host_stfs); +} + #endif /* BSD_USER_FREEBSD_OS_STAT_H */ From 191fe50d5dc8f26e0049d62e92d192d410520fab Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Sun, 13 Aug 2023 10:41:40 +0200 Subject: [PATCH 1287/1353] bsd-user: Implement statfs related syscalls Implement the following syscalls: statfs(2) fstatfs(2) getfsstat(2) Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/freebsd/os-stat.h | 69 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/bsd-user/freebsd/os-stat.h b/bsd-user/freebsd/os-stat.h index 935663c071..9492c93c55 100644 --- a/bsd-user/freebsd/os-stat.h +++ b/bsd-user/freebsd/os-stat.h @@ -210,4 +210,73 @@ static inline abi_long do_freebsd_fhstatfs(abi_ulong target_fhp_addr, return h2t_freebsd_statfs(target_stfs_addr, &host_stfs); } +/* statfs(2) */ +static inline abi_long do_freebsd_statfs(abi_long arg1, abi_long arg2) +{ + abi_long ret; + void *p; + struct statfs host_stfs; + + LOCK_PATH(p, arg1); + ret = get_errno(statfs(path(p), &host_stfs)); + UNLOCK_PATH(p, arg1); + if (is_error(ret)) { + return ret; + } + + return h2t_freebsd_statfs(arg2, &host_stfs); +} + +/* fstatfs(2) */ +static inline abi_long do_freebsd_fstatfs(abi_long fd, abi_ulong target_addr) +{ + abi_long ret; + struct statfs host_stfs; + + ret = get_errno(fstatfs(fd, &host_stfs)); + if (is_error(ret)) { + return ret; + } + + return h2t_freebsd_statfs(target_addr, &host_stfs); +} + +/* getfsstat(2) */ +static inline abi_long do_freebsd_getfsstat(abi_ulong target_addr, + abi_long bufsize, abi_long flags) +{ + abi_long ret; + struct statfs *host_stfs; + int count; + long host_bufsize; + + count = bufsize / sizeof(struct target_statfs); + + /* if user buffer is NULL then return number of mounted FS's */ + if (target_addr == 0 || count == 0) { + return get_errno(freebsd11_getfsstat(NULL, 0, flags)); + } + + /* XXX check count to be reasonable */ + host_bufsize = sizeof(struct statfs) * count; + host_stfs = alloca(host_bufsize); + if (!host_stfs) { + return -TARGET_EINVAL; + } + + ret = count = get_errno(getfsstat(host_stfs, host_bufsize, flags)); + if (is_error(ret)) { + return ret; + } + + while (count--) { + if (h2t_freebsd_statfs((target_addr + + (count * sizeof(struct target_statfs))), + &host_stfs[count])) { + return -TARGET_EFAULT; + } + } + return ret; +} + #endif /* BSD_USER_FREEBSD_OS_STAT_H */ From 213444529de083d1cbd1ef2391a1323207182f93 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Sun, 13 Aug 2023 10:41:41 +0200 Subject: [PATCH 1288/1353] bsd-user: Implement getdents related syscalls Implement the following syscalls: getdents(2) getdirecentries(2) Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/freebsd/os-stat.h | 72 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/bsd-user/freebsd/os-stat.h b/bsd-user/freebsd/os-stat.h index 9492c93c55..7dc41cd0bf 100644 --- a/bsd-user/freebsd/os-stat.h +++ b/bsd-user/freebsd/os-stat.h @@ -279,4 +279,76 @@ static inline abi_long do_freebsd_getfsstat(abi_ulong target_addr, return ret; } +/* getdents(2) */ +static inline abi_long do_freebsd11_getdents(abi_long arg1, + abi_ulong arg2, abi_long nbytes) +{ + abi_long ret; + struct freebsd11_dirent *dirp; + + dirp = lock_user(VERIFY_WRITE, arg2, nbytes, 0); + if (dirp == NULL) { + return -TARGET_EFAULT; + } + ret = get_errno(freebsd11_getdents(arg1, (char *)dirp, nbytes)); + if (!is_error(ret)) { + struct freebsd11_dirent *de; + int len = ret; + int reclen; + + de = dirp; + while (len > 0) { + reclen = de->d_reclen; + if (reclen > len) { + return -TARGET_EFAULT; + } + de->d_reclen = tswap16(reclen); + de->d_fileno = tswap32(de->d_fileno); + len -= reclen; + } + } + return ret; +} + +/* getdirecentries(2) */ +static inline abi_long do_freebsd_getdirentries(abi_long arg1, + abi_ulong arg2, abi_long nbytes, abi_ulong arg4) +{ + abi_long ret; + struct dirent *dirp; + long basep; + + dirp = lock_user(VERIFY_WRITE, arg2, nbytes, 0); + if (dirp == NULL) { + return -TARGET_EFAULT; + } + ret = get_errno(getdirentries(arg1, (char *)dirp, nbytes, &basep)); + if (!is_error(ret)) { + struct dirent *de; + int len = ret; + int reclen; + + de = dirp; + while (len > 0) { + reclen = de->d_reclen; + if (reclen > len) { + return -TARGET_EFAULT; + } + de->d_fileno = tswap64(de->d_fileno); + de->d_off = tswap64(de->d_off); + de->d_reclen = tswap16(de->d_reclen); + de->d_namlen = tswap16(de->d_namlen); + len -= reclen; + de = (struct dirent *)((void *)de + reclen); + } + } + unlock_user(dirp, arg2, ret); + if (arg4) { + if (put_user(basep, arg4, abi_ulong)) { + return -TARGET_EFAULT; + } + } + return ret; +} + #endif /* BSD_USER_FREEBSD_OS_STAT_H */ From c0023204cb05f330c51432fdcae8929413ff6d73 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Sun, 13 Aug 2023 10:41:42 +0200 Subject: [PATCH 1289/1353] bsd-user: Implement stat related syscalls Implement the following syscalls: fcntl(2) Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/freebsd/os-stat.h | 74 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/bsd-user/freebsd/os-stat.h b/bsd-user/freebsd/os-stat.h index 7dc41cd0bf..5d9323c7d1 100644 --- a/bsd-user/freebsd/os-stat.h +++ b/bsd-user/freebsd/os-stat.h @@ -351,4 +351,78 @@ static inline abi_long do_freebsd_getdirentries(abi_long arg1, return ret; } +/* fcntl(2) */ +static inline abi_long do_freebsd_fcntl(abi_long arg1, abi_long arg2, + abi_ulong arg3) +{ + abi_long ret; + int host_cmd; + struct flock fl; + struct target_freebsd_flock *target_fl; + + host_cmd = target_to_host_fcntl_cmd(arg2); + if (host_cmd < 0) { + return host_cmd; + } + switch (arg2) { + case TARGET_F_GETLK: + if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) { + return -TARGET_EFAULT; + } + __get_user(fl.l_type, &target_fl->l_type); + __get_user(fl.l_whence, &target_fl->l_whence); + __get_user(fl.l_start, &target_fl->l_start); + __get_user(fl.l_len, &target_fl->l_len); + __get_user(fl.l_pid, &target_fl->l_pid); + __get_user(fl.l_sysid, &target_fl->l_sysid); + unlock_user_struct(target_fl, arg3, 0); + ret = get_errno(safe_fcntl(arg1, host_cmd, &fl)); + if (!is_error(ret)) { + if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0)) { + return -TARGET_EFAULT; + } + __put_user(fl.l_type, &target_fl->l_type); + __put_user(fl.l_whence, &target_fl->l_whence); + __put_user(fl.l_start, &target_fl->l_start); + __put_user(fl.l_len, &target_fl->l_len); + __put_user(fl.l_pid, &target_fl->l_pid); + __put_user(fl.l_sysid, &target_fl->l_sysid); + unlock_user_struct(target_fl, arg3, 1); + } + break; + + case TARGET_F_SETLK: + case TARGET_F_SETLKW: + if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) { + return -TARGET_EFAULT; + } + __get_user(fl.l_type, &target_fl->l_type); + __get_user(fl.l_whence, &target_fl->l_whence); + __get_user(fl.l_start, &target_fl->l_start); + __get_user(fl.l_len, &target_fl->l_len); + __get_user(fl.l_pid, &target_fl->l_pid); + __get_user(fl.l_sysid, &target_fl->l_sysid); + unlock_user_struct(target_fl, arg3, 0); + ret = get_errno(safe_fcntl(arg1, host_cmd, &fl)); + break; + + case TARGET_F_DUPFD: + case TARGET_F_DUP2FD: + case TARGET_F_GETOWN: + case TARGET_F_SETOWN: + case TARGET_F_GETFD: + case TARGET_F_SETFD: + case TARGET_F_GETFL: + case TARGET_F_SETFL: + case TARGET_F_READAHEAD: + case TARGET_F_RDAHEAD: + case TARGET_F_ADD_SEALS: + case TARGET_F_GET_SEALS: + default: + ret = get_errno(safe_fcntl(arg1, host_cmd, arg3)); + break; + } + return ret; +} + #endif /* BSD_USER_FREEBSD_OS_STAT_H */ From b443297793ef696f282e470775dc89815758fb24 Mon Sep 17 00:00:00 2001 From: Michal Meloun Date: Sun, 13 Aug 2023 10:41:43 +0200 Subject: [PATCH 1290/1353] bsd-user: Implement freebsd11 stat related syscalls Rename the following syscalls to the freebsd11 variant: do_freebsd_lstat -> do_freebsd11_lstat do_freebsd_stat -> do_freebsd11_stat Co-authored-by: Stacey Son Signed-off-by: Stacey Son Signed-off-by: Michal Meloun Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/freebsd/os-stat.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bsd-user/freebsd/os-stat.h b/bsd-user/freebsd/os-stat.h index 5d9323c7d1..aef55c8bb5 100644 --- a/bsd-user/freebsd/os-stat.h +++ b/bsd-user/freebsd/os-stat.h @@ -20,6 +20,11 @@ #ifndef BSD_USER_FREEBSD_OS_STAT_H #define BSD_USER_FREEBSD_OS_STAT_H +int freebsd11_stat(const char *path, struct freebsd11_stat *stat); +__sym_compat(stat, freebsd11_stat, FBSD_1.0); +int freebsd11_lstat(const char *path, struct freebsd11_stat *stat); +__sym_compat(lstat, freebsd11_lstat, FBSD_1.0); + /* stat(2) */ static inline abi_long do_freebsd11_stat(abi_long arg1, abi_long arg2) { From 33d730684efbe9f9343a07a6f4259e322d22f63e Mon Sep 17 00:00:00 2001 From: Michal Meloun Date: Sun, 13 Aug 2023 10:41:44 +0200 Subject: [PATCH 1291/1353] bsd-user: Implement freebsd11 fstat and fhstat related syscalls Implement the freebsd11 variant of the following syscalls: fstat(2) fstatat(2) fhstat(2) fhstatfs(2) Co-authored-by: Stacey Son Signed-off-by: Stacey Son Signed-off-by: Michal Meloun Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/freebsd/os-stat.h | 78 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/bsd-user/freebsd/os-stat.h b/bsd-user/freebsd/os-stat.h index aef55c8bb5..2e0c7245df 100644 --- a/bsd-user/freebsd/os-stat.h +++ b/bsd-user/freebsd/os-stat.h @@ -24,6 +24,17 @@ int freebsd11_stat(const char *path, struct freebsd11_stat *stat); __sym_compat(stat, freebsd11_stat, FBSD_1.0); int freebsd11_lstat(const char *path, struct freebsd11_stat *stat); __sym_compat(lstat, freebsd11_lstat, FBSD_1.0); +int freebsd11_fstat(int fd, struct freebsd11_stat *stat); +__sym_compat(fstat, freebsd11_fstat, FBSD_1.0); +int freebsd11_fstatat(int fd, const char *path, struct freebsd11_stat *stat, + int flag); +__sym_compat(fstatat, freebsd11_fstatat, FBSD_1.1); + +int freebsd11_fhstat(const fhandle_t *fhandle, struct freebsd11_stat *stat); +__sym_compat(fhstat, freebsd11_fhstat, FBSD_1.0); +int freebsd11_fhstatfs(const fhandle_t *fhandle, struct freebsd11_statfs * buf); +__sym_compat(fhstatfs, freebsd11_fhstatfs, FBSD_1.0); +int freebsd11_statfs(const char *path, struct freebsd11_statfs *buf); /* stat(2) */ static inline abi_long do_freebsd11_stat(abi_long arg1, abi_long arg2) @@ -57,6 +68,19 @@ static inline abi_long do_freebsd11_lstat(abi_long arg1, abi_long arg2) return ret; } +/* fstat(2) */ +static inline abi_long do_freebsd11_fstat(abi_long arg1, abi_long arg2) +{ + abi_long ret; + struct freebsd11_stat st; + + ret = get_errno(freebsd11_fstat(arg1, &st)); + if (!is_error(ret)) { + ret = h2t_freebsd11_stat(arg2, &st); + } + return ret; +} + /* fstat(2) */ static inline abi_long do_freebsd_fstat(abi_long arg1, abi_long arg2) { @@ -70,6 +94,23 @@ static inline abi_long do_freebsd_fstat(abi_long arg1, abi_long arg2) return ret; } +/* fstatat(2) */ +static inline abi_long do_freebsd11_fstatat(abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4) +{ + abi_long ret; + void *p; + struct freebsd11_stat st; + + LOCK_PATH(p, arg2); + ret = get_errno(freebsd11_fstatat(arg1, p, &st, arg4)); + UNLOCK_PATH(p, arg2); + if (!is_error(ret) && arg3) { + ret = h2t_freebsd11_stat(arg3, &st); + } + return ret; +} + /* fstatat(2) */ static inline abi_long do_freebsd_fstatat(abi_long arg1, abi_long arg2, abi_long arg3, abi_long arg4) @@ -178,6 +219,24 @@ static inline abi_long do_freebsd_fhopen(abi_long arg1, abi_long arg2) return get_errno(fhopen(&host_fh, arg2)); } +/* fhstat(2) */ +static inline abi_long do_freebsd11_fhstat(abi_long arg1, abi_long arg2) +{ + abi_long ret; + fhandle_t host_fh; + struct freebsd11_stat host_sb; + + ret = t2h_freebsd_fhandle(&host_fh, arg1); + if (is_error(ret)) { + return ret; + } + ret = get_errno(freebsd11_fhstat(&host_fh, &host_sb)); + if (is_error(ret)) { + return ret; + } + return h2t_freebsd11_stat(arg2, &host_sb); +} + /* fhstat(2) */ static inline abi_long do_freebsd_fhstat(abi_long arg1, abi_long arg2) { @@ -196,6 +255,25 @@ static inline abi_long do_freebsd_fhstat(abi_long arg1, abi_long arg2) return h2t_freebsd_stat(arg2, &host_sb); } +/* fhstatfs(2) */ +static inline abi_long do_freebsd11_fhstatfs(abi_ulong target_fhp_addr, + abi_ulong target_stfs_addr) +{ + abi_long ret; + fhandle_t host_fh; + struct freebsd11_statfs host_stfs; + + ret = t2h_freebsd_fhandle(&host_fh, target_fhp_addr); + if (is_error(ret)) { + return ret; + } + ret = get_errno(freebsd11_fhstatfs(&host_fh, &host_stfs)); + if (is_error(ret)) { + return ret; + } + return h2t_freebsd11_statfs(target_stfs_addr, &host_stfs); +} + /* fhstatfs(2) */ static inline abi_long do_freebsd_fhstatfs(abi_ulong target_fhp_addr, abi_ulong target_stfs_addr) From 196da9d3d3f1ab142473a6b2f714720ba1b29a33 Mon Sep 17 00:00:00 2001 From: Michal Meloun Date: Sun, 13 Aug 2023 10:41:45 +0200 Subject: [PATCH 1292/1353] bsd-user: Implement freebsd11 statfs related syscalls Implement the freebsd11 variant of the following syscalls: statfs(2) fstatfs(2) getfsstat(2) Co-authored-by: Stacey Son Signed-off-by: Stacey Son Signed-off-by: Michal Meloun Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/freebsd/os-stat.h | 75 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/bsd-user/freebsd/os-stat.h b/bsd-user/freebsd/os-stat.h index 2e0c7245df..04a61fabd1 100644 --- a/bsd-user/freebsd/os-stat.h +++ b/bsd-user/freebsd/os-stat.h @@ -32,9 +32,15 @@ __sym_compat(fstatat, freebsd11_fstatat, FBSD_1.1); int freebsd11_fhstat(const fhandle_t *fhandle, struct freebsd11_stat *stat); __sym_compat(fhstat, freebsd11_fhstat, FBSD_1.0); +int freebsd11_getfsstat(struct freebsd11_statfs *buf, long bufsize, int mode); +__sym_compat(getfsstat, freebsd11_getfsstat, FBSD_1.0); int freebsd11_fhstatfs(const fhandle_t *fhandle, struct freebsd11_statfs * buf); __sym_compat(fhstatfs, freebsd11_fhstatfs, FBSD_1.0); int freebsd11_statfs(const char *path, struct freebsd11_statfs *buf); +__sym_compat(statfs, freebsd11_statfs, FBSD_1.0); +int freebsd11_fstatfs(int fd, struct freebsd11_statfs *buf); +__sym_compat(fstatfs, freebsd11_fstatfs, FBSD_1.0); + /* stat(2) */ static inline abi_long do_freebsd11_stat(abi_long arg1, abi_long arg2) @@ -293,6 +299,23 @@ static inline abi_long do_freebsd_fhstatfs(abi_ulong target_fhp_addr, return h2t_freebsd_statfs(target_stfs_addr, &host_stfs); } +/* statfs(2) */ +static inline abi_long do_freebsd11_statfs(abi_long arg1, abi_long arg2) +{ + abi_long ret; + void *p; + struct freebsd11_statfs host_stfs; + + LOCK_PATH(p, arg1); + ret = get_errno(freebsd11_statfs(path(p), &host_stfs)); + UNLOCK_PATH(p, arg1); + if (is_error(ret)) { + return ret; + } + + return h2t_freebsd11_statfs(arg2, &host_stfs); +} + /* statfs(2) */ static inline abi_long do_freebsd_statfs(abi_long arg1, abi_long arg2) { @@ -310,6 +333,20 @@ static inline abi_long do_freebsd_statfs(abi_long arg1, abi_long arg2) return h2t_freebsd_statfs(arg2, &host_stfs); } +/* fstatfs(2) */ +static inline abi_long do_freebsd11_fstatfs(abi_long fd, abi_ulong target_addr) +{ + abi_long ret; + struct freebsd11_statfs host_stfs; + + ret = get_errno(freebsd11_fstatfs(fd, &host_stfs)); + if (is_error(ret)) { + return ret; + } + + return h2t_freebsd11_statfs(target_addr, &host_stfs); +} + /* fstatfs(2) */ static inline abi_long do_freebsd_fstatfs(abi_long fd, abi_ulong target_addr) { @@ -324,6 +361,44 @@ static inline abi_long do_freebsd_fstatfs(abi_long fd, abi_ulong target_addr) return h2t_freebsd_statfs(target_addr, &host_stfs); } +/* getfsstat(2) */ +static inline abi_long do_freebsd11_getfsstat(abi_ulong target_addr, + abi_long bufsize, abi_long flags) +{ + abi_long ret; + struct freebsd11_statfs *host_stfs; + int count; + long host_bufsize; + + count = bufsize / sizeof(struct target_freebsd11_statfs); + + /* if user buffer is NULL then return number of mounted FS's */ + if (target_addr == 0 || count == 0) { + return get_errno(freebsd11_getfsstat(NULL, 0, flags)); + } + + /* XXX check count to be reasonable */ + host_bufsize = sizeof(struct freebsd11_statfs) * count; + host_stfs = alloca(host_bufsize); + if (!host_stfs) { + return -TARGET_EINVAL; + } + + ret = count = get_errno(freebsd11_getfsstat(host_stfs, host_bufsize, flags)); + if (is_error(ret)) { + return ret; + } + + while (count--) { + if (h2t_freebsd11_statfs((target_addr + + (count * sizeof(struct target_freebsd11_statfs))), + &host_stfs[count])) { + return -TARGET_EFAULT; + } + } + return ret; +} + /* getfsstat(2) */ static inline abi_long do_freebsd_getfsstat(abi_ulong target_addr, abi_long bufsize, abi_long flags) From 91a98c9bbcfba2a9f278a0811676cd2f8000481c Mon Sep 17 00:00:00 2001 From: Michal Meloun Date: Sun, 13 Aug 2023 10:41:46 +0200 Subject: [PATCH 1293/1353] bsd-user: Implement freebsd11 getdirents related syscalls Implement the freebsd11 variant of the following syscalls: getdirentries(2) Co-authored-by: Stacey Son Signed-off-by: Stacey Son Signed-off-by: Michal Meloun Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/freebsd/os-stat.h | 44 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/bsd-user/freebsd/os-stat.h b/bsd-user/freebsd/os-stat.h index 04a61fabd1..26909af455 100644 --- a/bsd-user/freebsd/os-stat.h +++ b/bsd-user/freebsd/os-stat.h @@ -41,6 +41,11 @@ __sym_compat(statfs, freebsd11_statfs, FBSD_1.0); int freebsd11_fstatfs(int fd, struct freebsd11_statfs *buf); __sym_compat(fstatfs, freebsd11_fstatfs, FBSD_1.0); +ssize_t freebsd11_getdirentries(int fd, char *buf, size_t nbytes, off_t *basep); +__sym_compat(getdirentries, freebsd11_getdirentries, FBSD_1.0); +ssize_t freebsd11_getdents(int fd, char *buf, size_t nbytes); +__sym_compat(getdents, freebsd11_getdents, FBSD_1.0); + /* stat(2) */ static inline abi_long do_freebsd11_stat(abi_long arg1, abi_long arg2) @@ -468,6 +473,45 @@ static inline abi_long do_freebsd11_getdents(abi_long arg1, return ret; } +/* getdirecentries(2) */ +static inline abi_long do_freebsd11_getdirentries(abi_long arg1, + abi_ulong arg2, abi_long nbytes, abi_ulong arg4) +{ + abi_long ret; + struct freebsd11_dirent *dirp; + long basep; + + dirp = lock_user(VERIFY_WRITE, arg2, nbytes, 0); + if (dirp == NULL) { + return -TARGET_EFAULT; + } + ret = get_errno(freebsd11_getdirentries(arg1, (char *)dirp, nbytes, &basep)); + if (!is_error(ret)) { + struct freebsd11_dirent *de; + int len = ret; + int reclen; + + de = dirp; + while (len > 0) { + reclen = de->d_reclen; + if (reclen > len) { + return -TARGET_EFAULT; + } + de->d_reclen = tswap16(reclen); + de->d_fileno = tswap32(de->d_fileno); + len -= reclen; + de = (struct freebsd11_dirent *)((void *)de + reclen); + } + } + unlock_user(dirp, arg2, ret); + if (arg4) { + if (put_user(basep, arg4, abi_ulong)) { + return -TARGET_EFAULT; + } + } + return ret; +} + /* getdirecentries(2) */ static inline abi_long do_freebsd_getdirentries(abi_long arg1, abi_ulong arg2, abi_long nbytes, abi_ulong arg4) From 292f00c05bfa62a020eee5eb1d8c0983e8483b33 Mon Sep 17 00:00:00 2001 From: Michal Meloun Date: Sun, 13 Aug 2023 10:41:47 +0200 Subject: [PATCH 1294/1353] bsd-user: Implement freebsd11 netbsd stat related syscalls Forward declaration of the nstat syscalls: nstat nlstat nfstat Co-authored-by: Stacey Son Signed-off-by: Stacey Son Signed-off-by: Michal Meloun Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/freebsd/os-stat.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/bsd-user/freebsd/os-stat.h b/bsd-user/freebsd/os-stat.h index 26909af455..e31b2aab9e 100644 --- a/bsd-user/freebsd/os-stat.h +++ b/bsd-user/freebsd/os-stat.h @@ -46,6 +46,13 @@ __sym_compat(getdirentries, freebsd11_getdirentries, FBSD_1.0); ssize_t freebsd11_getdents(int fd, char *buf, size_t nbytes); __sym_compat(getdents, freebsd11_getdents, FBSD_1.0); +/* undocumented nstat system calls */ +int freebsd11_nstat(const char *path, struct freebsd11_stat *sb); +__sym_compat(nstat, freebsd11_nstat, FBSD_1.0); +int freebsd11_nlstat(const char *path, struct freebsd11_stat *sb); +__sym_compat(nlstat, freebsd11_nlstat, FBSD_1.0); +int freebsd11_nfstat(int fd, struct freebsd11_stat *sb); +__sym_compat(nfstat, freebsd11_nfstat, FBSD_1.0); /* stat(2) */ static inline abi_long do_freebsd11_stat(abi_long arg1, abi_long arg2) From 292bfd0f512aa71fcc8f7e2f6ce2aa40a5a825ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Urankar?= Date: Sun, 13 Aug 2023 10:41:48 +0200 Subject: [PATCH 1295/1353] bsd-user: Implement do_freebsd_realpathat syscall MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mikaël Urankar Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/freebsd/os-stat.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/bsd-user/freebsd/os-stat.h b/bsd-user/freebsd/os-stat.h index e31b2aab9e..b20e270774 100644 --- a/bsd-user/freebsd/os-stat.h +++ b/bsd-user/freebsd/os-stat.h @@ -634,4 +634,30 @@ static inline abi_long do_freebsd_fcntl(abi_long arg1, abi_long arg2, return ret; } +#if defined(__FreeBSD_version) && __FreeBSD_version >= 1300080 +extern int __realpathat(int fd, const char *path, char *buf, size_t size, + int flags); +/* https://svnweb.freebsd.org/base?view=revision&revision=358172 */ +/* no man page */ +static inline abi_long do_freebsd_realpathat(abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + abi_long ret; + void *p, *b; + + LOCK_PATH(p, arg2); + b = lock_user(VERIFY_WRITE, arg3, arg4, 0); + if (b == NULL) { + UNLOCK_PATH(p, arg2); + return -TARGET_EFAULT; + } + + ret = get_errno(__realpathat(arg1, p, b, arg4, arg5)); + UNLOCK_PATH(p, arg2); + unlock_user(b, arg3, ret); + + return ret; +} +#endif + #endif /* BSD_USER_FREEBSD_OS_STAT_H */ From c97c1f3a9f4d4a5bebf88c844b9b3fc07c4296e3 Mon Sep 17 00:00:00 2001 From: Karim Taha Date: Sun, 13 Aug 2023 10:41:49 +0200 Subject: [PATCH 1296/1353] bsd-user: Add os-stat.c to the build Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/freebsd/meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/bsd-user/freebsd/meson.build b/bsd-user/freebsd/meson.build index f87c788e84..f2f047cca3 100644 --- a/bsd-user/freebsd/meson.build +++ b/bsd-user/freebsd/meson.build @@ -1,4 +1,5 @@ bsd_user_ss.add(files( + 'os-stat.c', 'os-sys.c', 'os-syscall.c', )) From e800e6c541b4088a52f4c0129eb4cbbf8a0ea9fb Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Sun, 13 Aug 2023 10:41:50 +0200 Subject: [PATCH 1297/1353] bsd-user: Add glue for the freebsd11_stat syscalls Add glue to call the freebsd11_stat syscalls to the freebsd_syscall: freebsd11_stat freebsd11_lstat freebsd11_fstat freebsd11_fstatat freebsd11_nstat, freebsd11_nfstat, freebsd11_nlstat fstatat fstat Signed-off-by: Warner Losh Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/freebsd/os-syscall.c | 42 +++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index 2224a280ea..ade47a0d2f 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -36,6 +36,9 @@ #include "bsd-file.h" #include "bsd-proc.h" +/* *BSD dependent syscall shims */ +#include "os-stat.h" + /* I/O */ safe_syscall3(int, open, const char *, path, int, flags, mode_t, mode); safe_syscall4(int, openat, int, fd, const char *, path, int, flags, mode_t, @@ -482,6 +485,45 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, ret = do_bsd_undelete(arg1); break; + /* + * stat system calls + */ + case TARGET_FREEBSD_NR_freebsd11_stat: /* stat(2) */ + ret = do_freebsd11_stat(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_freebsd11_lstat: /* lstat(2) */ + ret = do_freebsd11_lstat(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_freebsd11_fstat: /* fstat(2) */ + ret = do_freebsd11_fstat(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_fstat: /* fstat(2) */ + ret = do_freebsd_fstat(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_freebsd11_fstatat: /* fstatat(2) */ + ret = do_freebsd11_fstatat(arg1, arg2, arg3, arg4); + break; + + case TARGET_FREEBSD_NR_fstatat: /* fstatat(2) */ + ret = do_freebsd_fstatat(arg1, arg2, arg3, arg4); + break; + + case TARGET_FREEBSD_NR_freebsd11_nstat: /* undocumented */ + ret = do_freebsd11_nstat(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_freebsd11_nfstat: /* undocumented */ + ret = do_freebsd11_nfstat(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_freebsd11_nlstat: /* undocumented */ + ret = do_freebsd11_nlstat(arg1, arg2); + break; + /* * sys{ctl, arch, call} */ From 6fe97c6cf7969bcf809a89ecabc30acf10b77735 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Sun, 13 Aug 2023 10:41:51 +0200 Subject: [PATCH 1298/1353] bsd-user: Add glue for getfh and related syscalls Add glue to call the following syscalls to the freebsd_syscall: getfh lgetfh fhopen freebsd11_fhstat freebsd11_fhstatfs fhstat fhstatfs Signed-off-by: Warner Losh Signed-off-by: Karim Taha Reviewed-by: Richard Henderson --- bsd-user/freebsd/os-syscall.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index ade47a0d2f..73616a5be0 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -524,6 +524,34 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, ret = do_freebsd11_nlstat(arg1, arg2); break; + case TARGET_FREEBSD_NR_getfh: /* getfh(2) */ + ret = do_freebsd_getfh(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_lgetfh: /* lgetfh(2) */ + ret = do_freebsd_lgetfh(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_fhopen: /* fhopen(2) */ + ret = do_freebsd_fhopen(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_freebsd11_fhstat: /* fhstat(2) */ + ret = do_freebsd11_fhstat(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_fhstat: /* fhstat(2) */ + ret = do_freebsd_fhstat(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_freebsd11_fhstatfs: /* fhstatfs(2) */ + ret = do_freebsd11_fhstatfs(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_fhstatfs: /* fhstatfs(2) */ + ret = do_freebsd_fhstatfs(arg1, arg2); + break; + /* * sys{ctl, arch, call} */ From d7e9a545084ba1ded8fe864697db174cc3e6ebe2 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Sun, 13 Aug 2023 10:41:52 +0200 Subject: [PATCH 1299/1353] bsd-user: Add glue for statfs related system calls Add glue to call the following syscalls to the freebsd_syscall: freebsd11_statfs statfs freebsd11_fstatfs fstatfs freebsd11_getfsstat getfsstat Signed-off-by: Warner Losh Signed-off-by: Karim Taha Reviewed-by: Richard Henderson --- bsd-user/freebsd/os-syscall.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index 73616a5be0..916a754bf8 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -552,6 +552,30 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, ret = do_freebsd_fhstatfs(arg1, arg2); break; + case TARGET_FREEBSD_NR_freebsd11_statfs: /* statfs(2) */ + ret = do_freebsd11_statfs(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_statfs: /* statfs(2) */ + ret = do_freebsd_statfs(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_freebsd11_fstatfs: /* fstatfs(2) */ + ret = do_freebsd11_fstatfs(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_fstatfs: /* fstatfs(2) */ + ret = do_freebsd_fstatfs(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_freebsd11_getfsstat: /* getfsstat(2) */ + ret = do_freebsd11_getfsstat(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_getfsstat: /* getfsstat(2) */ + ret = do_freebsd_getfsstat(arg1, arg2, arg3); + break; + /* * sys{ctl, arch, call} */ From 97a3c571147c3b62a79a994ebd85769419e630c2 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Sun, 13 Aug 2023 10:41:53 +0200 Subject: [PATCH 1300/1353] bsd-user: Add getdents and fcntl related system calls Add glue to call the following syscalls to the freebsd_syscall: freebsd11_getdents getdirentries freebsd11_getdirentries fcntl Signed-off-by: Warner Losh Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/freebsd/os-syscall.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index 916a754bf8..e9b1b663af 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -576,6 +576,22 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, ret = do_freebsd_getfsstat(arg1, arg2, arg3); break; + case TARGET_FREEBSD_NR_freebsd11_getdents: /* getdents(2) */ + ret = do_freebsd11_getdents(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_getdirentries: /* getdirentries(2) */ + ret = do_freebsd_getdirentries(arg1, arg2, arg3, arg4); + break; + + case TARGET_FREEBSD_NR_freebsd11_getdirentries: /* getdirentries(2) */ + ret = do_freebsd11_getdirentries(arg1, arg2, arg3, arg4); + break; + case TARGET_FREEBSD_NR_fcntl: /* fcntl(2) */ + ret = do_freebsd_fcntl(arg1, arg2, arg3); + break; + + /* * sys{ctl, arch, call} */ From f51e7c41acb4b17d28fc74f9f10df50a4a65fbcc Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Sat, 19 Aug 2023 22:54:19 -0600 Subject: [PATCH 1301/1353] bsd-user: Add missing break after do_bsd_preadv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without it, we'd call preadv, then write with weird parameters, which is clearly not ideal... Signed-off-by: Warner Losh Reviewed-by: Philippe Mathieu-Daudé Fixes: 770d8abae7 ("bsd-user/bsd-file.h: Meat of the write system calls") Reviewed-by: Richard Henderson Message-Id: <20230820045419.89691-1-imp@bsdimp.com> --- bsd-user/freebsd/os-syscall.c | 1 + 1 file changed, 1 insertion(+) diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c index e9b1b663af..fa60df529e 100644 --- a/bsd-user/freebsd/os-syscall.c +++ b/bsd-user/freebsd/os-syscall.c @@ -240,6 +240,7 @@ static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_FREEBSD_NR_preadv: /* preadv(2) */ ret = do_bsd_preadv(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6); + break; case TARGET_FREEBSD_NR_write: /* write(2) */ ret = do_bsd_write(arg1, arg2, arg3); From 58b4def2a28b38d7c5d49e99beb31e45936b1096 Mon Sep 17 00:00:00 2001 From: "alloc.young" Date: Fri, 25 Aug 2023 10:31:20 +0800 Subject: [PATCH 1302/1353] softmmu: Fix dirtylimit memory leak Fix memory leak in hmp_info_vcpu_dirty_limit,use g_autoptr to handle memory deallocation. Signed-off-by: alloc.young Reviewed-by: Hyman Huang Message-Id: Signed-off-by: Hyman Huang --- softmmu/dirtylimit.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/softmmu/dirtylimit.c b/softmmu/dirtylimit.c index 3c275ee55b..e3ff53b8fc 100644 --- a/softmmu/dirtylimit.c +++ b/softmmu/dirtylimit.c @@ -653,7 +653,8 @@ struct DirtyLimitInfoList *qmp_query_vcpu_dirty_limit(Error **errp) void hmp_info_vcpu_dirty_limit(Monitor *mon, const QDict *qdict) { - DirtyLimitInfoList *limit, *head, *info = NULL; + DirtyLimitInfoList *info; + g_autoptr(DirtyLimitInfoList) head = NULL; Error *err = NULL; if (!dirtylimit_in_service()) { @@ -661,20 +662,17 @@ void hmp_info_vcpu_dirty_limit(Monitor *mon, const QDict *qdict) return; } - info = qmp_query_vcpu_dirty_limit(&err); + head = qmp_query_vcpu_dirty_limit(&err); if (err) { hmp_handle_error(mon, err); return; } - head = info; - for (limit = head; limit != NULL; limit = limit->next) { + for (info = head; info != NULL; info = info->next) { monitor_printf(mon, "vcpu[%"PRIi64"], limit rate %"PRIi64 " (MB/s)," " current rate %"PRIi64 " (MB/s)\n", - limit->value->cpu_index, - limit->value->limit_rate, - limit->value->current_rate); + info->value->cpu_index, + info->value->limit_rate, + info->value->current_rate); } - - g_free(info); } From 19b14cea453b7429a06922fe96e55e6b32fe718a Mon Sep 17 00:00:00 2001 From: "alloc.young" Date: Fri, 25 Aug 2023 10:32:51 +0800 Subject: [PATCH 1303/1353] softmmu/dirtylimit: Convert free to g_free MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert free to g_free to match g_new and g_malloc functions. Fixes: cc2b33eab0 ("softmmu/dirtylimit: Implement vCPU dirtyrate calculation periodically") Fixes: baa609832e ("softmmu/dirtylimit: Implement virtual CPU throttle") Signed-off-by: alloc.young Reviewed-by: Hyman Huang Reviewed-by: Philippe Mathieu-Daudé Message-Id: Signed-off-by: Hyman Huang --- softmmu/dirtylimit.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/softmmu/dirtylimit.c b/softmmu/dirtylimit.c index e3ff53b8fc..fa959d7743 100644 --- a/softmmu/dirtylimit.c +++ b/softmmu/dirtylimit.c @@ -100,7 +100,7 @@ static void vcpu_dirty_rate_stat_collect(void) stat.rates[i].dirty_rate; } - free(stat.rates); + g_free(stat.rates); } static void *vcpu_dirty_rate_stat_thread(void *opaque) @@ -171,10 +171,10 @@ void vcpu_dirty_rate_stat_initialize(void) void vcpu_dirty_rate_stat_finalize(void) { - free(vcpu_dirty_rate_stat->stat.rates); + g_free(vcpu_dirty_rate_stat->stat.rates); vcpu_dirty_rate_stat->stat.rates = NULL; - free(vcpu_dirty_rate_stat); + g_free(vcpu_dirty_rate_stat); vcpu_dirty_rate_stat = NULL; } @@ -220,10 +220,10 @@ void dirtylimit_state_initialize(void) void dirtylimit_state_finalize(void) { - free(dirtylimit_state->states); + g_free(dirtylimit_state->states); dirtylimit_state->states = NULL; - free(dirtylimit_state); + g_free(dirtylimit_state); dirtylimit_state = NULL; trace_dirtylimit_state_finalize(); From 3eb82637fbf8c0471990b59e6733fd4beb1f9939 Mon Sep 17 00:00:00 2001 From: Andrei Gudkov Date: Mon, 28 Aug 2023 20:55:57 +0800 Subject: [PATCH 1304/1353] migration/dirtyrate: Fix precision losses and g_usleep overshoot Signed-off-by: Andrei Gudkov Reviewed-by: Hyman Huang Message-Id: <8ddb0d40d143f77aab8f602bd494e01e5fa01614.1691161009.git.gudkov.andrei@huawei.com> Signed-off-by: Hyman Huang --- migration/dirtyrate.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c index 84f1b0fb20..bccb3515e3 100644 --- a/migration/dirtyrate.c +++ b/migration/dirtyrate.c @@ -57,6 +57,8 @@ static int64_t dirty_stat_wait(int64_t msec, int64_t initial_time) msec = current_time - initial_time; } else { g_usleep((msec + initial_time - current_time) * 1000); + /* g_usleep may overshoot */ + msec = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) - initial_time; } return msec; @@ -77,9 +79,13 @@ static int64_t do_calculate_dirtyrate(DirtyPageRecord dirty_pages, { uint64_t increased_dirty_pages = dirty_pages.end_pages - dirty_pages.start_pages; - uint64_t memory_size_MiB = qemu_target_pages_to_MiB(increased_dirty_pages); - return memory_size_MiB * 1000 / calc_time_ms; + /* + * multiply by 1000ms/s _before_ converting down to megabytes + * to avoid losing precision + */ + return qemu_target_pages_to_MiB(increased_dirty_pages * 1000) / + calc_time_ms; } void global_dirty_log_change(unsigned int flag, bool start) From 86e4f93d827d3c1efd00cd8a906e38a2c0f2b5bc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 25 Aug 2023 14:06:58 -0700 Subject: [PATCH 1305/1353] softmmu: Assert data in bounds in iotlb_to_section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Acked-by: Alex Bennée Suggested-by: Alex Bennée Signed-off-by: Richard Henderson --- softmmu/physmem.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/softmmu/physmem.c b/softmmu/physmem.c index 3df73542e1..7597dc1c39 100644 --- a/softmmu/physmem.c +++ b/softmmu/physmem.c @@ -2413,9 +2413,15 @@ MemoryRegionSection *iotlb_to_section(CPUState *cpu, int asidx = cpu_asidx_from_attrs(cpu, attrs); CPUAddressSpace *cpuas = &cpu->cpu_ases[asidx]; AddressSpaceDispatch *d = qatomic_rcu_read(&cpuas->memory_dispatch); - MemoryRegionSection *sections = d->map.sections; + int section_index = index & ~TARGET_PAGE_MASK; + MemoryRegionSection *ret; - return §ions[index & ~TARGET_PAGE_MASK]; + assert(section_index < d->map.sections_nb); + ret = d->map.sections + section_index; + assert(ret->mr); + assert(ret->mr->ops); + + return ret; } static void io_mem_init(void) From 0d58c660689f6da1e3feff8a997014003d928b3b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 25 Aug 2023 16:13:17 -0700 Subject: [PATCH 1306/1353] softmmu: Use async_run_on_cpu in tcg_commit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After system startup, run the update to memory_dispatch and the tlb_flush on the cpu. This eliminates a race, wherein a running cpu sees the memory_dispatch change but has not yet seen the tlb_flush. Since the update now happens on the cpu, we need not use qatomic_rcu_read to protect the read of memory_dispatch. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1826 Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1834 Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1846 Tested-by: Alex Bennée Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec-common.c | 30 ---------------------------- include/exec/cpu-common.h | 1 - softmmu/physmem.c | 40 +++++++++++++++++++++++++++---------- 3 files changed, 29 insertions(+), 42 deletions(-) diff --git a/accel/tcg/cpu-exec-common.c b/accel/tcg/cpu-exec-common.c index 9a5fabf625..7e35d7f4b5 100644 --- a/accel/tcg/cpu-exec-common.c +++ b/accel/tcg/cpu-exec-common.c @@ -33,36 +33,6 @@ void cpu_loop_exit_noexc(CPUState *cpu) cpu_loop_exit(cpu); } -#if defined(CONFIG_SOFTMMU) -void cpu_reloading_memory_map(void) -{ - if (qemu_in_vcpu_thread() && current_cpu->running) { - /* The guest can in theory prolong the RCU critical section as long - * as it feels like. The major problem with this is that because it - * can do multiple reconfigurations of the memory map within the - * critical section, we could potentially accumulate an unbounded - * collection of memory data structures awaiting reclamation. - * - * Because the only thing we're currently protecting with RCU is the - * memory data structures, it's sufficient to break the critical section - * in this callback, which we know will get called every time the - * memory map is rearranged. - * - * (If we add anything else in the system that uses RCU to protect - * its data structures, we will need to implement some other mechanism - * to force TCG CPUs to exit the critical section, at which point this - * part of this callback might become unnecessary.) - * - * This pair matches cpu_exec's rcu_read_lock()/rcu_read_unlock(), which - * only protects cpu->as->dispatch. Since we know our caller is about - * to reload it, it's safe to split the critical section. - */ - rcu_read_unlock(); - rcu_read_lock(); - } -} -#endif - void cpu_loop_exit(CPUState *cpu) { /* Undo the setting in cpu_tb_exec. */ diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index 87dc9a752c..41788c0bdd 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -133,7 +133,6 @@ 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); diff --git a/softmmu/physmem.c b/softmmu/physmem.c index 7597dc1c39..18277ddd67 100644 --- a/softmmu/physmem.c +++ b/softmmu/physmem.c @@ -680,8 +680,7 @@ address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr orig_addr, IOMMUTLBEntry iotlb; int iommu_idx; hwaddr addr = orig_addr; - AddressSpaceDispatch *d = - qatomic_rcu_read(&cpu->cpu_ases[asidx].memory_dispatch); + AddressSpaceDispatch *d = cpu->cpu_ases[asidx].memory_dispatch; for (;;) { section = address_space_translate_internal(d, addr, &addr, plen, false); @@ -2412,7 +2411,7 @@ MemoryRegionSection *iotlb_to_section(CPUState *cpu, { int asidx = cpu_asidx_from_attrs(cpu, attrs); CPUAddressSpace *cpuas = &cpu->cpu_ases[asidx]; - AddressSpaceDispatch *d = qatomic_rcu_read(&cpuas->memory_dispatch); + AddressSpaceDispatch *d = cpuas->memory_dispatch; int section_index = index & ~TARGET_PAGE_MASK; MemoryRegionSection *ret; @@ -2487,23 +2486,42 @@ static void tcg_log_global_after_sync(MemoryListener *listener) } } +static void tcg_commit_cpu(CPUState *cpu, run_on_cpu_data data) +{ + CPUAddressSpace *cpuas = data.host_ptr; + + cpuas->memory_dispatch = address_space_to_dispatch(cpuas->as); + tlb_flush(cpu); +} + static void tcg_commit(MemoryListener *listener) { CPUAddressSpace *cpuas; - AddressSpaceDispatch *d; + CPUState *cpu; assert(tcg_enabled()); /* since each CPU stores ram addresses in its TLB cache, we must reset the modified entries */ cpuas = container_of(listener, CPUAddressSpace, tcg_as_listener); - cpu_reloading_memory_map(); - /* The CPU and TLB are protected by the iothread lock. - * We reload the dispatch pointer now because cpu_reloading_memory_map() - * may have split the RCU critical section. + cpu = cpuas->cpu; + + /* + * Defer changes to as->memory_dispatch until the cpu is quiescent. + * Otherwise we race between (1) other cpu threads and (2) ongoing + * i/o for the current cpu thread, with data cached by mmu_lookup(). + * + * In addition, queueing the work function will kick the cpu back to + * the main loop, which will end the RCU critical section and reclaim + * the memory data structures. + * + * That said, the listener is also called during realize, before + * all of the tcg machinery for run-on is initialized: thus halt_cond. */ - d = address_space_to_dispatch(cpuas->as); - qatomic_rcu_set(&cpuas->memory_dispatch, d); - tlb_flush(cpuas->cpu); + if (cpu->halt_cond) { + async_run_on_cpu(cpu, tcg_commit_cpu, RUN_ON_CPU_HOST_PTR(cpuas)); + } else { + tcg_commit_cpu(cpu, RUN_ON_CPU_HOST_PTR(cpuas)); + } } static void memory_map_init(void) From 77fafcb50046f6c683f3cab9df975fdab43e1a68 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 28 Aug 2023 12:15:35 -0700 Subject: [PATCH 1307/1353] tcg: Remove vecop_list check from tcg_gen_not_vec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The not pattern is always available via generic expansion. See debug block in tcg_can_emit_vecop_list. Fixes: 11978f6f58 ("tcg: Fix expansion of INDEX_op_not_vec") Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/tcg-op-vec.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tcg/tcg-op-vec.c b/tcg/tcg-op-vec.c index ad8ee08a7e..094298bb27 100644 --- a/tcg/tcg-op-vec.c +++ b/tcg/tcg-op-vec.c @@ -391,12 +391,11 @@ static bool do_op2(unsigned vece, TCGv_vec r, TCGv_vec a, TCGOpcode opc) void tcg_gen_not_vec(unsigned vece, TCGv_vec r, TCGv_vec a) { - const TCGOpcode *hold_list = tcg_swap_vecop_list(NULL); - - if (!TCG_TARGET_HAS_not_vec || !do_op2(vece, r, a, INDEX_op_not_vec)) { + if (TCG_TARGET_HAS_not_vec) { + vec_gen_op2(INDEX_op_not_vec, 0, r, a); + } else { tcg_gen_xor_vec(0, r, a, tcg_constant_vec_matching(r, 0, -1)); } - tcg_swap_vecop_list(hold_list); } void tcg_gen_neg_vec(unsigned vece, TCGv_vec r, TCGv_vec a) From dad2f2f5afbaf58d6056f31dfd4b9edd0854b8ab Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 22 Aug 2023 11:02:00 -0700 Subject: [PATCH 1308/1353] tcg/sparc64: Disable TCG_TARGET_HAS_extr_i64_i32 Since a59a29312660 ("tcg/sparc64: Remove sparc32plus constraints") we no longer distinguish registers with 32 vs 64 bits. Therefore we can remove support for the backend-specific type change opcodes. Signed-off-by: Richard Henderson --- tcg/sparc64/tcg-target.c.inc | 11 ----------- tcg/sparc64/tcg-target.h | 2 +- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index f2a346a1bd..81a08bb6c5 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -529,11 +529,6 @@ static void tcg_out_extu_i32_i64(TCGContext *s, TCGReg rd, TCGReg rs) tcg_out_ext32u(s, rd, rs); } -static void tcg_out_extrl_i64_i32(TCGContext *s, TCGReg rd, TCGReg rs) -{ - tcg_out_mov(s, TCG_TYPE_I32, rd, rs); -} - static bool tcg_out_xchg(TCGContext *s, TCGType type, TCGReg r1, TCGReg r2) { return false; @@ -1444,9 +1439,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, case INDEX_op_divu_i64: c = ARITH_UDIVX; goto gen_arith; - case INDEX_op_extrh_i64_i32: - tcg_out_arithi(s, a0, a1, 32, SHIFT_SRLX); - break; case INDEX_op_brcond_i64: tcg_out_brcond_i64(s, a2, a0, a1, const_args[1], arg_label(args[3])); @@ -1501,7 +1493,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, case INDEX_op_ext32u_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: - case INDEX_op_extrl_i64_i32: default: g_assert_not_reached(); } @@ -1533,8 +1524,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op) case INDEX_op_ext32u_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: - case INDEX_op_extrl_i64_i32: - case INDEX_op_extrh_i64_i32: case INDEX_op_qemu_ld_a32_i32: case INDEX_op_qemu_ld_a64_i32: case INDEX_op_qemu_ld_a32_i64: diff --git a/tcg/sparc64/tcg-target.h b/tcg/sparc64/tcg-target.h index 3d41c9659b..5cfc4b4679 100644 --- a/tcg/sparc64/tcg-target.h +++ b/tcg/sparc64/tcg-target.h @@ -115,7 +115,7 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_mulsh_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 -#define TCG_TARGET_HAS_extr_i64_i32 1 +#define TCG_TARGET_HAS_extr_i64_i32 0 #define TCG_TARGET_HAS_div_i64 1 #define TCG_TARGET_HAS_rem_i64 0 #define TCG_TARGET_HAS_rot_i64 0 From 669fd6151337fdc81e34f7eb4940ba2f20d89957 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 29 Aug 2023 11:29:09 -0700 Subject: [PATCH 1309/1353] Revert "include/exec: typedef abi_ptr to vaddr in softmmu" This reverts commit fc15bfb6a6bda8d4d01f1383579d385acae17c0f. This patch caused a regression for tricore-softmmu, ./tests/tcg/tricore-softmmu/test_boot_to_main.c.tst. Reported-by: Bastian Koppelmann Signed-off-by: Richard Henderson --- include/exec/cpu_ldst.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h index f3ce4eb1d0..da10ba1433 100644 --- a/include/exec/cpu_ldst.h +++ b/include/exec/cpu_ldst.h @@ -121,8 +121,8 @@ static inline bool guest_range_valid_untagged(abi_ulong start, abi_ulong len) h2g_nocheck(x); \ }) #else -typedef vaddr abi_ptr; -#define TARGET_ABI_FMT_ptr "%016" VADDR_PRIx +typedef target_ulong abi_ptr; +#define TARGET_ABI_FMT_ptr TARGET_FMT_lx #endif uint32_t cpu_ldub_data(CPUArchState *env, abi_ptr ptr); From f187609f27b261702a17f79d20bf252ee0d4f9cd Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Mon, 31 Jul 2023 17:33:38 -0300 Subject: [PATCH 1310/1353] block-migration: Ensure we don't crash during migration cleanup We can fail the blk_insert_bs() at init_blk_migration(), leaving the BlkMigDevState without a dirty_bitmap and BlockDriverState. Account for the possibly missing elements when doing cleanup. Fix the following crashes: Thread 1 "qemu-system-x86" received signal SIGSEGV, Segmentation fault. 0x0000555555ec83ef in bdrv_release_dirty_bitmap (bitmap=0x0) at ../block/dirty-bitmap.c:359 359 BlockDriverState *bs = bitmap->bs; #0 0x0000555555ec83ef in bdrv_release_dirty_bitmap (bitmap=0x0) at ../block/dirty-bitmap.c:359 #1 0x0000555555bba331 in unset_dirty_tracking () at ../migration/block.c:371 #2 0x0000555555bbad98 in block_migration_cleanup_bmds () at ../migration/block.c:681 Thread 1 "qemu-system-x86" received signal SIGSEGV, Segmentation fault. 0x0000555555e971ff in bdrv_op_unblock (bs=0x0, op=BLOCK_OP_TYPE_BACKUP_SOURCE, reason=0x0) at ../block.c:7073 7073 QLIST_FOREACH_SAFE(blocker, &bs->op_blockers[op], list, next) { #0 0x0000555555e971ff in bdrv_op_unblock (bs=0x0, op=BLOCK_OP_TYPE_BACKUP_SOURCE, reason=0x0) at ../block.c:7073 #1 0x0000555555e9734a in bdrv_op_unblock_all (bs=0x0, reason=0x0) at ../block.c:7095 #2 0x0000555555bbae13 in block_migration_cleanup_bmds () at ../migration/block.c:690 Signed-off-by: Fabiano Rosas Message-id: 20230731203338.27581-1-farosas@suse.de Signed-off-by: Stefan Hajnoczi --- migration/block.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/migration/block.c b/migration/block.c index b9580a6c7e..86c2256a2b 100644 --- a/migration/block.c +++ b/migration/block.c @@ -368,7 +368,9 @@ static void unset_dirty_tracking(void) BlkMigDevState *bmds; QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) { - bdrv_release_dirty_bitmap(bmds->dirty_bitmap); + if (bmds->dirty_bitmap) { + bdrv_release_dirty_bitmap(bmds->dirty_bitmap); + } } } @@ -676,13 +678,18 @@ static int64_t get_remaining_dirty(void) static void block_migration_cleanup_bmds(void) { BlkMigDevState *bmds; + BlockDriverState *bs; AioContext *ctx; unset_dirty_tracking(); while ((bmds = QSIMPLEQ_FIRST(&block_mig_state.bmds_list)) != NULL) { QSIMPLEQ_REMOVE_HEAD(&block_mig_state.bmds_list, entry); - bdrv_op_unblock_all(blk_bs(bmds->blk), bmds->blocker); + + bs = blk_bs(bmds->blk); + if (bs) { + bdrv_op_unblock_all(bs, bmds->blocker); + } error_free(bmds->blocker); /* Save ctx, because bmds->blk can disappear during blk_unref. */ From c54483b6f45a0c84e230728a1a9e7adf90345e15 Mon Sep 17 00:00:00 2001 From: Andrey Drobyshev Date: Tue, 11 Jul 2023 20:25:51 +0300 Subject: [PATCH 1311/1353] block: add subcluster_size field to BlockDriverInfo This is going to be used in the subsequent commit as requests alignment (in particular, during copy-on-read). This value only makes sense for the formats which support subclusters (currently QCOW2 only). If this field isn't set by driver's own bdrv_get_info() implementation, we simply set it equal to the cluster size thus treating each cluster as having a single subcluster. Reviewed-by: Eric Blake Reviewed-by: Denis V. Lunev Signed-off-by: Andrey Drobyshev Reviewed-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Stefan Hajnoczi Message-ID: <20230711172553.234055-2-andrey.drobyshev@virtuozzo.com> --- block.c | 7 +++++++ block/qcow2.c | 1 + include/block/block-common.h | 5 +++++ 3 files changed, 13 insertions(+) diff --git a/block.c b/block.c index a307c151a8..0af890f647 100644 --- a/block.c +++ b/block.c @@ -6480,6 +6480,13 @@ int coroutine_fn bdrv_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) } memset(bdi, 0, sizeof(*bdi)); ret = drv->bdrv_co_get_info(bs, bdi); + if (bdi->subcluster_size == 0) { + /* + * If the driver left this unset, subclusters are not supported. + * Then it is safe to treat each cluster as having only one subcluster. + */ + bdi->subcluster_size = bdi->cluster_size; + } if (ret < 0) { return ret; } diff --git a/block/qcow2.c b/block/qcow2.c index c51388e99d..b48cd9ce63 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -5197,6 +5197,7 @@ qcow2_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) { BDRVQcow2State *s = bs->opaque; bdi->cluster_size = s->cluster_size; + bdi->subcluster_size = s->subcluster_size; bdi->vm_state_offset = qcow2_vm_state_offset(s); bdi->is_dirty = s->incompatible_features & QCOW2_INCOMPAT_DIRTY; return 0; diff --git a/include/block/block-common.h b/include/block/block-common.h index e15395f2cb..df5ffc8d09 100644 --- a/include/block/block-common.h +++ b/include/block/block-common.h @@ -132,6 +132,11 @@ typedef struct BlockZoneWps { typedef struct BlockDriverInfo { /* in bytes, 0 if irrelevant */ int cluster_size; + /* + * A fraction of cluster_size, if supported (currently QCOW2 only); if + * disabled or unsupported, set equal to cluster_size. + */ + int subcluster_size; /* offset at which the VM state can be saved (0 if not possible) */ int64_t vm_state_offset; bool is_dirty; From fc6b211f920a68f4c9c8db91ccc35ca95fe6683a Mon Sep 17 00:00:00 2001 From: Andrey Drobyshev Date: Tue, 11 Jul 2023 20:25:52 +0300 Subject: [PATCH 1312/1353] block/io: align requests to subcluster_size When target image is using subclusters, and we align the request during copy-on-read, it makes sense to align to subcluster_size rather than cluster_size. Otherwise we end up with unnecessary allocations. This commit renames bdrv_round_to_clusters() to bdrv_round_to_subclusters() and utilizes subcluster_size field of BlockDriverInfo to make necessary alignments. It affects copy-on-read as well as mirror job (which is using bdrv_round_to_clusters()). This change also fixes the following bug with failing assert (covered by the test in the subsequent commit): qemu-img create -f qcow2 base.qcow2 64K qemu-img create -f qcow2 -o extended_l2=on,backing_file=base.qcow2,backing_fmt=qcow2 img.qcow2 64K qemu-io -c "write -P 0xaa 0 2K" img.qcow2 qemu-io -C -c "read -P 0x00 2K 62K" img.qcow2 qemu-io: ../block/io.c:1236: bdrv_co_do_copy_on_readv: Assertion `skip_bytes < pnum' failed. Reviewed-by: Eric Blake Reviewed-by: Denis V. Lunev Signed-off-by: Andrey Drobyshev Reviewed-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Stefan Hajnoczi Message-ID: <20230711172553.234055-3-andrey.drobyshev@virtuozzo.com> --- block/io.c | 50 ++++++++++++++++++++-------------------- block/mirror.c | 8 +++---- include/block/block-io.h | 8 +++---- 3 files changed, 33 insertions(+), 33 deletions(-) diff --git a/block/io.c b/block/io.c index 055fcf7438..76e7df18d8 100644 --- a/block/io.c +++ b/block/io.c @@ -728,21 +728,21 @@ BdrvTrackedRequest *coroutine_fn bdrv_co_get_self_request(BlockDriverState *bs) } /** - * Round a region to cluster boundaries + * Round a region to subcluster (if supported) or cluster boundaries */ void coroutine_fn GRAPH_RDLOCK -bdrv_round_to_clusters(BlockDriverState *bs, int64_t offset, int64_t bytes, - int64_t *cluster_offset, int64_t *cluster_bytes) +bdrv_round_to_subclusters(BlockDriverState *bs, int64_t offset, int64_t bytes, + int64_t *align_offset, int64_t *align_bytes) { BlockDriverInfo bdi; IO_CODE(); - if (bdrv_co_get_info(bs, &bdi) < 0 || bdi.cluster_size == 0) { - *cluster_offset = offset; - *cluster_bytes = bytes; + if (bdrv_co_get_info(bs, &bdi) < 0 || bdi.subcluster_size == 0) { + *align_offset = offset; + *align_bytes = bytes; } else { - int64_t c = bdi.cluster_size; - *cluster_offset = QEMU_ALIGN_DOWN(offset, c); - *cluster_bytes = QEMU_ALIGN_UP(offset - *cluster_offset + bytes, c); + int64_t c = bdi.subcluster_size; + *align_offset = QEMU_ALIGN_DOWN(offset, c); + *align_bytes = QEMU_ALIGN_UP(offset - *align_offset + bytes, c); } } @@ -1168,8 +1168,8 @@ bdrv_co_do_copy_on_readv(BdrvChild *child, int64_t offset, int64_t bytes, void *bounce_buffer = NULL; BlockDriver *drv = bs->drv; - int64_t cluster_offset; - int64_t cluster_bytes; + int64_t align_offset; + int64_t align_bytes; int64_t skip_bytes; int ret; int max_transfer = MIN_NON_ZERO(bs->bl.max_transfer, @@ -1203,28 +1203,28 @@ bdrv_co_do_copy_on_readv(BdrvChild *child, int64_t offset, int64_t bytes, * BDRV_REQUEST_MAX_BYTES (even when the original read did not), which * is one reason we loop rather than doing it all at once. */ - bdrv_round_to_clusters(bs, offset, bytes, &cluster_offset, &cluster_bytes); - skip_bytes = offset - cluster_offset; + bdrv_round_to_subclusters(bs, offset, bytes, &align_offset, &align_bytes); + skip_bytes = offset - align_offset; trace_bdrv_co_do_copy_on_readv(bs, offset, bytes, - cluster_offset, cluster_bytes); + align_offset, align_bytes); - while (cluster_bytes) { + while (align_bytes) { int64_t pnum; if (skip_write) { ret = 1; /* "already allocated", so nothing will be copied */ - pnum = MIN(cluster_bytes, max_transfer); + pnum = MIN(align_bytes, max_transfer); } else { - ret = bdrv_is_allocated(bs, cluster_offset, - MIN(cluster_bytes, max_transfer), &pnum); + ret = bdrv_is_allocated(bs, align_offset, + MIN(align_bytes, max_transfer), &pnum); if (ret < 0) { /* * Safe to treat errors in querying allocation as if * unallocated; we'll probably fail again soon on the * read, but at least that will set a decent errno. */ - pnum = MIN(cluster_bytes, max_transfer); + pnum = MIN(align_bytes, max_transfer); } /* Stop at EOF if the image ends in the middle of the cluster */ @@ -1242,7 +1242,7 @@ bdrv_co_do_copy_on_readv(BdrvChild *child, int64_t offset, int64_t bytes, /* Must copy-on-read; use the bounce buffer */ pnum = MIN(pnum, MAX_BOUNCE_BUFFER); if (!bounce_buffer) { - int64_t max_we_need = MAX(pnum, cluster_bytes - pnum); + int64_t max_we_need = MAX(pnum, align_bytes - pnum); int64_t max_allowed = MIN(max_transfer, MAX_BOUNCE_BUFFER); int64_t bounce_buffer_len = MIN(max_we_need, max_allowed); @@ -1254,7 +1254,7 @@ bdrv_co_do_copy_on_readv(BdrvChild *child, int64_t offset, int64_t bytes, } qemu_iovec_init_buf(&local_qiov, bounce_buffer, pnum); - ret = bdrv_driver_preadv(bs, cluster_offset, pnum, + ret = bdrv_driver_preadv(bs, align_offset, pnum, &local_qiov, 0, 0); if (ret < 0) { goto err; @@ -1266,13 +1266,13 @@ bdrv_co_do_copy_on_readv(BdrvChild *child, int64_t offset, int64_t bytes, /* FIXME: Should we (perhaps conditionally) be setting * BDRV_REQ_MAY_UNMAP, if it will allow for a sparser copy * that still correctly reads as zero? */ - ret = bdrv_co_do_pwrite_zeroes(bs, cluster_offset, pnum, + ret = bdrv_co_do_pwrite_zeroes(bs, align_offset, pnum, BDRV_REQ_WRITE_UNCHANGED); } else { /* This does not change the data on the disk, it is not * necessary to flush even in cache=writethrough mode. */ - ret = bdrv_driver_pwritev(bs, cluster_offset, pnum, + ret = bdrv_driver_pwritev(bs, align_offset, pnum, &local_qiov, 0, BDRV_REQ_WRITE_UNCHANGED); } @@ -1301,8 +1301,8 @@ bdrv_co_do_copy_on_readv(BdrvChild *child, int64_t offset, int64_t bytes, } } - cluster_offset += pnum; - cluster_bytes -= pnum; + align_offset += pnum; + align_bytes -= pnum; progress += pnum - skip_bytes; skip_bytes = 0; } diff --git a/block/mirror.c b/block/mirror.c index d3cacd1708..e213a892db 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -283,8 +283,8 @@ static int coroutine_fn mirror_cow_align(MirrorBlockJob *s, int64_t *offset, need_cow |= !test_bit((*offset + *bytes - 1) / s->granularity, s->cow_bitmap); if (need_cow) { - bdrv_round_to_clusters(blk_bs(s->target), *offset, *bytes, - &align_offset, &align_bytes); + bdrv_round_to_subclusters(blk_bs(s->target), *offset, *bytes, + &align_offset, &align_bytes); } if (align_bytes > max_bytes) { @@ -576,8 +576,8 @@ static void coroutine_fn mirror_iteration(MirrorBlockJob *s) int64_t target_offset; int64_t target_bytes; WITH_GRAPH_RDLOCK_GUARD() { - bdrv_round_to_clusters(blk_bs(s->target), offset, io_bytes, - &target_offset, &target_bytes); + bdrv_round_to_subclusters(blk_bs(s->target), offset, io_bytes, + &target_offset, &target_bytes); } if (target_offset == offset && target_bytes == io_bytes) { diff --git a/include/block/block-io.h b/include/block/block-io.h index 4415506e40..6db48f2d35 100644 --- a/include/block/block-io.h +++ b/include/block/block-io.h @@ -189,10 +189,10 @@ bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi); ImageInfoSpecific *bdrv_get_specific_info(BlockDriverState *bs, Error **errp); BlockStatsSpecific *bdrv_get_specific_stats(BlockDriverState *bs); -void bdrv_round_to_clusters(BlockDriverState *bs, - int64_t offset, int64_t bytes, - int64_t *cluster_offset, - int64_t *cluster_bytes); +void bdrv_round_to_subclusters(BlockDriverState *bs, + int64_t offset, int64_t bytes, + int64_t *cluster_offset, + int64_t *cluster_bytes); void bdrv_get_backing_filename(BlockDriverState *bs, char *filename, int filename_size); From e2f938265e0aa8486303d260f3cb13d5bb9e9d6a Mon Sep 17 00:00:00 2001 From: Andrey Drobyshev Date: Tue, 11 Jul 2023 20:25:53 +0300 Subject: [PATCH 1313/1353] tests/qemu-iotests/197: add testcase for CoR with subclusters Add testcase which checks that allocations during copy-on-read are performed on the subcluster basis when subclusters are enabled in target image. This testcase also triggers the following assert with previous commit not being applied, so we check that as well: qemu-io: ../block/io.c:1236: bdrv_co_do_copy_on_readv: Assertion `skip_bytes < pnum' failed. Reviewed-by: Eric Blake Reviewed-by: Denis V. Lunev Signed-off-by: Andrey Drobyshev Reviewed-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Stefan Hajnoczi Message-ID: <20230711172553.234055-4-andrey.drobyshev@virtuozzo.com> --- tests/qemu-iotests/197 | 29 +++++++++++++++++++++++++++++ tests/qemu-iotests/197.out | 24 ++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/tests/qemu-iotests/197 b/tests/qemu-iotests/197 index a2547bc280..f07a9da136 100755 --- a/tests/qemu-iotests/197 +++ b/tests/qemu-iotests/197 @@ -122,6 +122,35 @@ $QEMU_IO -f qcow2 -C -c 'read 0 1024' "$TEST_WRAP" | _filter_qemu_io $QEMU_IO -f qcow2 -c map "$TEST_WRAP" _check_test_img +echo +echo '=== Copy-on-read with subclusters ===' +echo + +# Create base and top images 64K (1 cluster) each. Make subclusters enabled +# for the top image +_make_test_img 64K +IMGPROTO=file IMGFMT=qcow2 TEST_IMG_FILE="$TEST_WRAP" \ + _make_test_img --no-opts -o extended_l2=true -F "$IMGFMT" -b "$TEST_IMG" \ + 64K | _filter_img_create + +$QEMU_IO -c "write -P 0xaa 0 64k" "$TEST_IMG" | _filter_qemu_io + +# Allocate individual subclusters in the top image, and not the whole cluster +$QEMU_IO -c "write -P 0xbb 28K 2K" -c "write -P 0xcc 34K 2K" "$TEST_WRAP" \ + | _filter_qemu_io + +# Only 2 subclusters should be allocated in the top image at this point +$QEMU_IMG map "$TEST_WRAP" | _filter_qemu_img_map + +# Actual copy-on-read operation +$QEMU_IO -C -c "read -P 0xaa 30K 4K" "$TEST_WRAP" | _filter_qemu_io + +# And here we should have 4 subclusters allocated right in the middle of the +# top image. Make sure the whole cluster remains unallocated +$QEMU_IMG map "$TEST_WRAP" | _filter_qemu_img_map + +_check_test_img + # success, all done echo '*** done' status=0 diff --git a/tests/qemu-iotests/197.out b/tests/qemu-iotests/197.out index ad414c3b0e..8f34a30afe 100644 --- a/tests/qemu-iotests/197.out +++ b/tests/qemu-iotests/197.out @@ -31,4 +31,28 @@ read 1024/1024 bytes at offset 0 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) 1 KiB (0x400) bytes allocated at offset 0 bytes (0x0) No errors were found on the image. + +=== Copy-on-read with subclusters === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=65536 +Formatting 'TEST_DIR/t.wrap.IMGFMT', fmt=IMGFMT size=65536 backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT +wrote 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 2048/2048 bytes at offset 28672 +2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 2048/2048 bytes at offset 34816 +2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Offset Length File +0 0x7000 TEST_DIR/t.IMGFMT +0x7000 0x800 TEST_DIR/t.wrap.IMGFMT +0x7800 0x1000 TEST_DIR/t.IMGFMT +0x8800 0x800 TEST_DIR/t.wrap.IMGFMT +0x9000 0x7000 TEST_DIR/t.IMGFMT +read 4096/4096 bytes at offset 30720 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Offset Length File +0 0x7000 TEST_DIR/t.IMGFMT +0x7000 0x2000 TEST_DIR/t.wrap.IMGFMT +0x9000 0x7000 TEST_DIR/t.IMGFMT +No errors were found on the image. *** done From 87ec6f55af38e29be5b2b65a8acf84da73e06d06 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 26 Apr 2023 17:26:39 -0400 Subject: [PATCH 1314/1353] aio-posix: zero out io_uring sqe user_data liburing does not clear sqe->user_data. We must do it ourselves to avoid undefined behavior in process_cqe() when user_data is used. Note that fdmon-io_uring is currently disabled, so this is a latent bug that does not affect users. Let's merge this fix now to make it easier to enable fdmon-io_uring in the future (and I'm working on that). Signed-off-by: Stefan Hajnoczi Message-ID: <20230426212639.82310-1-stefanha@redhat.com> --- util/fdmon-io_uring.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/util/fdmon-io_uring.c b/util/fdmon-io_uring.c index 17ec18b7bd..16054c5ede 100644 --- a/util/fdmon-io_uring.c +++ b/util/fdmon-io_uring.c @@ -184,6 +184,7 @@ static void add_poll_remove_sqe(AioContext *ctx, AioHandler *node) #else io_uring_prep_poll_remove(sqe, node); #endif + io_uring_sqe_set_data(sqe, NULL); } /* Add a timeout that self-cancels when another cqe becomes ready */ @@ -197,6 +198,7 @@ static void add_timeout_sqe(AioContext *ctx, int64_t ns) sqe = get_sqe(ctx); io_uring_prep_timeout(sqe, &ts, 1, 0); + io_uring_sqe_set_data(sqe, NULL); } /* Add sqes from ctx->submit_list for submission */ From 2f7350cd43ebda0011c9cf191c621eed1439bcf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Tue, 29 Aug 2023 17:15:17 +0100 Subject: [PATCH 1315/1353] gitlab: enable ccache for many build jobs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `ccache` tool can be very effective at reducing compilation times when re-running pipelines with only minor changes each time. For example a fresh 'build-system-fedora' job will typically take 20 minutes on the gitlab.com shared runners. With ccache this is reduced to as little as 6 minutes. Normally meson would auto-detect existance of ccache in $PATH and use it automatically, but the way we wrap meson from configure breaks this, as we're passing in an config file with explicitly set compiler paths. Thus we need to add $CCACHE_WRAPPERSPATH to the front of $PATH. For unknown reasons if doing this in msys though, gcc becomes unable to invoke 'cc1' when run from meson. For msys we thus set CC='ccache gcc' before invoking 'configure' instead. A second problem with msys is that cache misses are incredibly expensive, so enabling ccache massively slows down the build when the cache isn't well populated. This is suspected to be a result of the cost of spawning processes under the msys architecture. To deal with this we set CCACHE_DEPEND=1 which enables ccache's 'depend_only' strategy. This avoids extra spawning of the pre-processor during cache misses, with the downside that is it less likely ccache will find a cache hit after semantically benign compiler flag changes. This is the lesser of two evils, as otherwise we can't use ccache at all under msys and remain inside the job time limit. If people are finding ccache to hurt their pipelines, it can be disabled by setting the 'CCACHE_DISABLE=1' env variable against their gitlab fork CI settings. Signed-off-by: Daniel P. Berrangé Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20230804111054.281802-2-berrange@redhat.com> Signed-off-by: Alex Bennée Message-Id: <20230829161528.2707696-2-alex.bennee@linaro.org> --- .gitlab-ci.d/buildtest-template.yml | 11 ++++++++ .gitlab-ci.d/crossbuild-template.yml | 26 +++++++++++++++++++ .gitlab-ci.d/windows.yml | 13 ++++++++-- docs/devel/ci-jobs.rst.inc | 7 +++++ .../dockerfiles/debian-hexagon-cross.docker | 9 ++++++- 5 files changed, 63 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.d/buildtest-template.yml b/.gitlab-ci.d/buildtest-template.yml index f3e39b7eb1..4fbfeb6667 100644 --- a/.gitlab-ci.d/buildtest-template.yml +++ b/.gitlab-ci.d/buildtest-template.yml @@ -2,11 +2,21 @@ extends: .base_job_template stage: build image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:$QEMU_CI_CONTAINER_TAG + cache: + paths: + - ccache + key: "$CI_JOB_NAME" + when: always before_script: - JOBS=$(expr $(nproc) + 1) script: + - export CCACHE_BASEDIR="$(pwd)" + - export CCACHE_DIR="$CCACHE_BASEDIR/ccache" + - export CCACHE_MAXSIZE="500M" + - export PATH="$CCACHE_WRAPPERSDIR:$PATH" - mkdir build - cd build + - ccache --zero-stats - ../configure --enable-werror --disable-docs --enable-fdt=system ${TARGETS:+--target-list="$TARGETS"} $CONFIGURE_ARGS || @@ -20,6 +30,7 @@ then make -j"$JOBS" $MAKE_CHECK_ARGS ; fi + - ccache --show-stats # We jump some hoops in common_test_job_template to avoid # rebuilding all the object files we skip in the artifacts diff --git a/.gitlab-ci.d/crossbuild-template.yml b/.gitlab-ci.d/crossbuild-template.yml index d97611053b..3e5f4d9cd8 100644 --- a/.gitlab-ci.d/crossbuild-template.yml +++ b/.gitlab-ci.d/crossbuild-template.yml @@ -2,10 +2,20 @@ extends: .base_job_template stage: build image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:$QEMU_CI_CONTAINER_TAG + cache: + paths: + - ccache + key: "$CI_JOB_NAME" + when: always timeout: 80m script: + - export CCACHE_BASEDIR="$(pwd)" + - export CCACHE_DIR="$CCACHE_BASEDIR/ccache" + - export CCACHE_MAXSIZE="500M" + - export PATH="$CCACHE_WRAPPERSDIR:$PATH" - mkdir build - cd build + - ccache --zero-stats - ../configure --enable-werror --disable-docs --enable-fdt=system --disable-user $QEMU_CONFIGURE_OPTS $EXTRA_CONFIGURE_OPTS --target-list-exclude="arm-softmmu cris-softmmu @@ -18,6 +28,7 @@ version="$(git describe --match v[0-9]* 2>/dev/null || git rev-parse --short HEAD)"; mv -v qemu-setup*.exe qemu-setup-${version}.exe; fi + - ccache --show-stats # Job to cross-build specific accelerators. # @@ -29,7 +40,15 @@ stage: build image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:$QEMU_CI_CONTAINER_TAG timeout: 30m + cache: + paths: + - ccache/ + key: "$CI_JOB_NAME" script: + - export CCACHE_BASEDIR="$(pwd)" + - export CCACHE_DIR="$CCACHE_BASEDIR/ccache" + - export CCACHE_MAXSIZE="500M" + - export PATH="$CCACHE_WRAPPERSDIR:$PATH" - mkdir build - cd build - ../configure --enable-werror --disable-docs $QEMU_CONFIGURE_OPTS @@ -40,7 +59,14 @@ extends: .base_job_template stage: build image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:$QEMU_CI_CONTAINER_TAG + cache: + paths: + - ccache/ + key: "$CI_JOB_NAME" script: + - export CCACHE_BASEDIR="$(pwd)" + - export CCACHE_DIR="$CCACHE_BASEDIR/ccache" + - export CCACHE_MAXSIZE="500M" - mkdir build - cd build - ../configure --enable-werror --disable-docs $QEMU_CONFIGURE_OPTS diff --git a/.gitlab-ci.d/windows.yml b/.gitlab-ci.d/windows.yml index cd7622a761..12a987cd71 100644 --- a/.gitlab-ci.d/windows.yml +++ b/.gitlab-ci.d/windows.yml @@ -5,13 +5,14 @@ - windows - windows-1809 cache: - key: "${CI_JOB_NAME}-cache" + key: "$CI_JOB_NAME" paths: - msys64/var/cache + - ccache when: always needs: [] stage: build - timeout: 80m + timeout: 100m variables: # This feature doesn't (currently) work with PowerShell, it stops # the echo'ing of commands being run and doesn't show any timing @@ -72,6 +73,7 @@ bison diffutils flex git grep make sed $MINGW_TARGET-capstone + $MINGW_TARGET-ccache $MINGW_TARGET-curl $MINGW_TARGET-cyrus-sasl $MINGW_TARGET-dtc @@ -101,11 +103,18 @@ - Write-Output "Running build at $(Get-Date -Format u)" - $env:CHERE_INVOKING = 'yes' # Preserve the current working directory - $env:MSYS = 'winsymlinks:native' # Enable native Windows symlink + - $env:CCACHE_BASEDIR = "$env:CI_PROJECT_DIR" + - $env:CCACHE_DIR = "$env:CCACHE_BASEDIR/ccache" + - $env:CCACHE_MAXSIZE = "500M" + - $env:CCACHE_DEPEND = 1 # cache misses are too expensive with preprocessor mode + - $env:CC = "ccache gcc" - mkdir build - cd build + - ..\msys64\usr\bin\bash -lc "ccache --zero-stats" - ..\msys64\usr\bin\bash -lc "../configure --enable-fdt=system $CONFIGURE_ARGS" - ..\msys64\usr\bin\bash -lc "make" - ..\msys64\usr\bin\bash -lc "make check MTESTARGS='$TEST_ARGS' || { cat meson-logs/testlog.txt; exit 1; } ;" + - ..\msys64\usr\bin\bash -lc "ccache --show-stats" - Write-Output "Finished build at $(Get-Date -Format u)" msys2-64bit: diff --git a/docs/devel/ci-jobs.rst.inc b/docs/devel/ci-jobs.rst.inc index 3f6802d51e..4c39cdb2d9 100644 --- a/docs/devel/ci-jobs.rst.inc +++ b/docs/devel/ci-jobs.rst.inc @@ -188,3 +188,10 @@ If you've got access to a CentOS Stream 8 x86_64 host that can be used as a gitlab-CI runner, you can set this variable to enable the tests that require this kind of host. The runner should be tagged with both "centos_stream_8" and "x86_64". + +CCACHE_DISABLE +~~~~~~~~~~~~~~ +The jobs are configured to use "ccache" by default since this typically +reduces compilation time, at the cost of increased storage. If the +use of "ccache" is suspected to be hurting the overall job execution +time, setting the "CCACHE_DISABLE=1" env variable to disable it. diff --git a/tests/docker/dockerfiles/debian-hexagon-cross.docker b/tests/docker/dockerfiles/debian-hexagon-cross.docker index 153fc7cfb3..7c38d7c9e4 100644 --- a/tests/docker/dockerfiles/debian-hexagon-cross.docker +++ b/tests/docker/dockerfiles/debian-hexagon-cross.docker @@ -15,6 +15,7 @@ RUN apt-get update && \ # Install common build utilities apt-get install -y --no-install-recommends \ curl \ + ccache \ xz-utils \ ca-certificates \ bison \ @@ -27,7 +28,12 @@ RUN apt-get update && \ python3-wheel && \ # Install QEMU build deps for use in CI DEBIAN_FRONTEND=noninteractive eatmydata \ - apt build-dep -yy --arch-only qemu + apt build-dep -yy --arch-only qemu && \ + mkdir -p /usr/libexec/ccache-wrappers && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/c++ && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/g++ && \ + ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc RUN /usr/bin/pip3 install tomli @@ -35,6 +41,7 @@ ENV TOOLCHAIN_INSTALL /opt ENV TOOLCHAIN_RELEASE 16.0.0 ENV TOOLCHAIN_BASENAME "clang+llvm-${TOOLCHAIN_RELEASE}-cross-hexagon-unknown-linux-musl" ENV TOOLCHAIN_URL https://codelinaro.jfrog.io/artifactory/codelinaro-toolchain-for-hexagon/v${TOOLCHAIN_RELEASE}/${TOOLCHAIN_BASENAME}.tar.xz +ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers" RUN curl -#SL "$TOOLCHAIN_URL" | tar -xJC "$TOOLCHAIN_INSTALL" ENV PATH $PATH:${TOOLCHAIN_INSTALL}/${TOOLCHAIN_BASENAME}/x86_64-linux-gnu/bin From 6445c2cace9f284e8326510c01d6d83c2bef12da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 29 Aug 2023 17:15:18 +0100 Subject: [PATCH 1316/1353] tests/docker: cleanup non-verbose output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Even with --quiet docker will spam the sha256 to the console. Avoid this by redirecting stdout. While we are at it fix the name we echo which was broken during 0b1a649047 (tests/docker: use direct RUNC call to build containers). Reviewed-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Alex Bennée Message-Id: <20230829161528.2707696-3-alex.bennee@linaro.org> --- tests/docker/Makefile.include | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include index 142e8605ee..dfabafab92 100644 --- a/tests/docker/Makefile.include +++ b/tests/docker/Makefile.include @@ -46,9 +46,9 @@ docker-image-%: $(DOCKER_FILES_DIR)/%.docker --build-arg BUILDKIT_INLINE_CACHE=1 \ $(if $(NOUSER),, \ --build-arg USER=$(USER) \ - --build-arg UID=$(UID)) \ - -t qemu/$* - < $<, \ - "BUILD", $1) + --build-arg UID=$(UID)) \ + -t qemu/$* - < $< $(if $V,,> /dev/null),\ + "BUILD", $*) # Special rule for debootstraped binfmt linux-user images docker-binfmt-image-debian-%: $(DOCKER_FILES_DIR)/debian-bootstrap.docker From bb16cb45192b344c8bd5e3c2f423b96fb438ed29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 29 Aug 2023 17:15:19 +0100 Subject: [PATCH 1317/1353] tests/tcg: remove quoting for info output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This avoids ugly multi-line wrapping for the test on non V=1 builds. Acked-by: Richard Henderson Signed-off-by: Alex Bennée Message-Id: <20230829161528.2707696-4-alex.bennee@linaro.org> --- tests/tcg/aarch64/Makefile.target | 2 +- tests/tcg/multiarch/system/Makefile.softmmu-target | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target index 681dfa077c..b77bbd9b3c 100644 --- a/tests/tcg/aarch64/Makefile.target +++ b/tests/tcg/aarch64/Makefile.target @@ -14,7 +14,7 @@ AARCH64_TESTS=fcvt pcalign-a64 lse2-fault fcvt: LDFLAGS+=-lm run-fcvt: fcvt - $(call run-test,$<,$(QEMU) $<, "$< on $(TARGET_NAME)") + $(call run-test,$<,$(QEMU) $<) $(call diff-out,$<,$(AARCH64_SRC)/fcvt.ref) config-cc.mak: Makefile diff --git a/tests/tcg/multiarch/system/Makefile.softmmu-target b/tests/tcg/multiarch/system/Makefile.softmmu-target index 7ba9053375..a051d689d7 100644 --- a/tests/tcg/multiarch/system/Makefile.softmmu-target +++ b/tests/tcg/multiarch/system/Makefile.softmmu-target @@ -37,10 +37,10 @@ run-gdbstub-untimely-packet: hello --qemu $(QEMU) \ --bin $< --qargs \ "-monitor none -display none -chardev file$(COMMA)path=untimely-packet.out$(COMMA)id=output $(QEMU_OPTS)", \ - "softmmu gdbstub untimely packets") + softmmu gdbstub untimely packets) $(call quiet-command, \ (! grep -Fq 'Packet instead of Ack, ignoring it' untimely-packet.gdb.err), \ - "GREP", "file untimely-packet.gdb.err") + "GREP", file untimely-packet.gdb.err) else run-gdbstub-%: $(call skip-test, "gdbstub test $*", "no guest arch support") From 4b77429adbecf970d0ebb7213b99b82771b6368f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 29 Aug 2023 17:15:20 +0100 Subject: [PATCH 1318/1353] docs/style: permit inline loop variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I've already wasted enough of my time debugging aliased variables in deeply nested loops. While not scattering variable declarations around is a good aim I think we can make an exception for stuff used inside a loop. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Stefan Hajnoczi Acked-by: Markus Armbruster Reviewed-by: Thomas Huth Reviewed-by: Richard Henderson Signed-off-by: Alex Bennée Message-Id: <20230829161528.2707696-5-alex.bennee@linaro.org> --- docs/devel/style.rst | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/devel/style.rst b/docs/devel/style.rst index 3cfcdeb9cd..2f68b50079 100644 --- a/docs/devel/style.rst +++ b/docs/devel/style.rst @@ -204,7 +204,14 @@ Declarations Mixed declarations (interleaving statements and declarations within blocks) are generally not allowed; declarations should be at the beginning -of blocks. +of blocks. To avoid accidental re-use it is permissible to declare +loop variables inside for loops: + +.. code-block:: c + + for (int i = 0; i < ARRAY_SIZE(thing); i++) { + /* do something loopy */ + } Every now and then, an exception is made for declarations inside a #ifdef or #ifndef block: if the code looks nicer, such declarations can From e05a4beaecc346346c1fa7d5c1d13941dc609c80 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 29 Aug 2023 17:15:21 +0100 Subject: [PATCH 1319/1353] .gitlab-ci.d/cirrus.yml: Update FreeBSD to v13.2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The FreeBSD CI job started to fail due to linking problems ... time to update to the latest version to get this fixed. Signed-off-by: Thomas Huth Reviewed-by: Daniel P. Berrangé Message-Id: <20230823144533.230477-1-thuth@redhat.com> Signed-off-by: Alex Bennée Message-Id: <20230829161528.2707696-6-alex.bennee@linaro.org> --- .gitlab-ci.d/cirrus.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.d/cirrus.yml b/.gitlab-ci.d/cirrus.yml index 1507c928e5..41d64d6680 100644 --- a/.gitlab-ci.d/cirrus.yml +++ b/.gitlab-ci.d/cirrus.yml @@ -50,7 +50,7 @@ x64-freebsd-13-build: NAME: freebsd-13 CIRRUS_VM_INSTANCE_TYPE: freebsd_instance CIRRUS_VM_IMAGE_SELECTOR: image_family - CIRRUS_VM_IMAGE_NAME: freebsd-13-1 + CIRRUS_VM_IMAGE_NAME: freebsd-13-2 CIRRUS_VM_CPUS: 8 CIRRUS_VM_RAM: 8G UPDATE_COMMAND: pkg update; pkg upgrade -y From d84842be6c53c03c9498101b509a25961ed5856f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 29 Aug 2023 17:15:22 +0100 Subject: [PATCH 1320/1353] tests: remove test-gdbstub.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This isn't directly called by our CI and because it doesn't run via our run-test.py script does things slightly differently. Lets remove it as we have plenty of working in-tree tests now for various aspects of gdbstub. Reviewed-by: Richard Henderson Signed-off-by: Alex Bennée Message-Id: <20230829161528.2707696-7-alex.bennee@linaro.org> --- tests/guest-debug/test-gdbstub.py | 177 ------------------------------ 1 file changed, 177 deletions(-) delete mode 100644 tests/guest-debug/test-gdbstub.py diff --git a/tests/guest-debug/test-gdbstub.py b/tests/guest-debug/test-gdbstub.py deleted file mode 100644 index 98a5df4d42..0000000000 --- a/tests/guest-debug/test-gdbstub.py +++ /dev/null @@ -1,177 +0,0 @@ -# -# This script needs to be run on startup -# qemu -kernel ${KERNEL} -s -S -# and then: -# gdb ${KERNEL}.vmlinux -x ${QEMU_SRC}/tests/guest-debug/test-gdbstub.py - -import gdb - -failcount = 0 - - -def report(cond, msg): - "Report success/fail of test" - if cond: - print ("PASS: %s" % (msg)) - else: - print ("FAIL: %s" % (msg)) - global failcount - failcount += 1 - - -def check_step(): - "Step an instruction, check it moved." - start_pc = gdb.parse_and_eval('$pc') - gdb.execute("si") - end_pc = gdb.parse_and_eval('$pc') - - return not (start_pc == end_pc) - - -def check_break(sym_name): - "Setup breakpoint, continue and check we stopped." - sym, ok = gdb.lookup_symbol(sym_name) - bp = gdb.Breakpoint(sym_name) - - gdb.execute("c") - - # hopefully we came back - end_pc = gdb.parse_and_eval('$pc') - print ("%s == %s %d" % (end_pc, sym.value(), bp.hit_count)) - bp.delete() - - # can we test we hit bp? - return end_pc == sym.value() - - -# We need to do hbreak manually as the python interface doesn't export it -def check_hbreak(sym_name): - "Setup hardware breakpoint, continue and check we stopped." - sym, ok = gdb.lookup_symbol(sym_name) - gdb.execute("hbreak %s" % (sym_name)) - gdb.execute("c") - - # hopefully we came back - end_pc = gdb.parse_and_eval('$pc') - print ("%s == %s" % (end_pc, sym.value())) - - if end_pc == sym.value(): - gdb.execute("d 1") - return True - else: - return False - - -class WatchPoint(gdb.Breakpoint): - - def get_wpstr(self, sym_name): - "Setup sym and wp_str for given symbol." - self.sym, ok = gdb.lookup_symbol(sym_name) - wp_addr = gdb.parse_and_eval(sym_name).address - self.wp_str = '*(%(type)s)(&%(address)s)' % dict( - type = wp_addr.type, address = sym_name) - - return(self.wp_str) - - def __init__(self, sym_name, type): - wp_str = self.get_wpstr(sym_name) - super(WatchPoint, self).__init__(wp_str, gdb.BP_WATCHPOINT, type) - - def stop(self): - end_pc = gdb.parse_and_eval('$pc') - print ("HIT WP @ %s" % (end_pc)) - return True - - -def do_one_watch(sym, wtype, text): - - wp = WatchPoint(sym, wtype) - gdb.execute("c") - report_str = "%s for %s (%s)" % (text, sym, wp.sym.value()) - - if wp.hit_count > 0: - report(True, report_str) - wp.delete() - else: - report(False, report_str) - - -def check_watches(sym_name): - "Watch a symbol for any access." - - # Should hit for any read - do_one_watch(sym_name, gdb.WP_ACCESS, "awatch") - - # Again should hit for reads - do_one_watch(sym_name, gdb.WP_READ, "rwatch") - - # Finally when it is written - do_one_watch(sym_name, gdb.WP_WRITE, "watch") - - -class CatchBreakpoint(gdb.Breakpoint): - def __init__(self, sym_name): - super(CatchBreakpoint, self).__init__(sym_name) - self.sym, ok = gdb.lookup_symbol(sym_name) - - def stop(self): - end_pc = gdb.parse_and_eval('$pc') - print ("CB: %s == %s" % (end_pc, self.sym.value())) - if end_pc == self.sym.value(): - report(False, "Hit final catchpoint") - - -def run_test(): - "Run through the tests one by one" - - print ("Checking we can step the first few instructions") - step_ok = 0 - for i in range(3): - if check_step(): - step_ok += 1 - - report(step_ok == 3, "single step in boot code") - - print ("Checking HW breakpoint works") - break_ok = check_hbreak("kernel_init") - report(break_ok, "hbreak @ kernel_init") - - # Can't set this up until we are in the kernel proper - # if we make it to run_init_process we've over-run and - # one of the tests failed - print ("Setup catch-all for run_init_process") - cbp = CatchBreakpoint("run_init_process") - cpb2 = CatchBreakpoint("try_to_run_init_process") - - print ("Checking Normal breakpoint works") - break_ok = check_break("wait_for_completion") - report(break_ok, "break @ wait_for_completion") - - print ("Checking watchpoint works") - check_watches("system_state") - -# -# This runs as the script it sourced (via -x) -# - -try: - print ("Connecting to remote") - gdb.execute("target remote localhost:1234") - - # These are not very useful in scripts - gdb.execute("set pagination off") - gdb.execute("set confirm off") - - # Run the actual tests - run_test() - -except: - print ("GDB Exception: %s" % (sys.exc_info()[0])) - failcount += 1 - import code - code.InteractiveConsole(locals=globals()).interact() - raise - -# Finally kill the inferior and exit gdb with a count of failures -gdb.execute("kill") -exit(failcount) From a8fea70f656416b2ed7d388fbcc7cc6cda126a82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 29 Aug 2023 17:15:23 +0100 Subject: [PATCH 1321/1353] tests/tcg: clean-up gdb confirm/pagination settings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can do this all in the run-test.py script so remove the extraneous bits from the individual tests which got copied from the original non-CI gdb tests. Acked-by: Ilya Leoshkevich Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Alex Bennée Message-Id: <20230829161528.2707696-8-alex.bennee@linaro.org> --- tests/guest-debug/run-test.py | 2 ++ tests/tcg/aarch64/gdbstub/test-sve-ioctl.py | 3 --- tests/tcg/aarch64/gdbstub/test-sve.py | 3 --- tests/tcg/multiarch/gdbstub/memory.py | 3 --- tests/tcg/multiarch/gdbstub/sha1.py | 4 ---- tests/tcg/multiarch/gdbstub/test-proc-mappings.py | 4 ---- tests/tcg/multiarch/gdbstub/test-qxfer-auxv-read.py | 4 ---- tests/tcg/multiarch/gdbstub/test-thread-breakpoint.py | 4 ---- tests/tcg/s390x/gdbstub/test-signals-s390x.py | 4 ---- tests/tcg/s390x/gdbstub/test-svc.py | 4 ---- 10 files changed, 2 insertions(+), 33 deletions(-) diff --git a/tests/guest-debug/run-test.py b/tests/guest-debug/run-test.py index a032e01f79..b13b27d4b1 100755 --- a/tests/guest-debug/run-test.py +++ b/tests/guest-debug/run-test.py @@ -83,6 +83,8 @@ if __name__ == '__main__': gdb_cmd += " %s" % (args.gdb_args) # run quietly and ignore .gdbinit gdb_cmd += " -q -n -batch" + # disable pagination + gdb_cmd += " -ex 'set pagination off'" # disable prompts in case of crash gdb_cmd += " -ex 'set confirm off'" # connect to remote diff --git a/tests/tcg/aarch64/gdbstub/test-sve-ioctl.py b/tests/tcg/aarch64/gdbstub/test-sve-ioctl.py index b9ef169c1a..ee8d467e59 100644 --- a/tests/tcg/aarch64/gdbstub/test-sve-ioctl.py +++ b/tests/tcg/aarch64/gdbstub/test-sve-ioctl.py @@ -76,9 +76,6 @@ except (gdb.error, AttributeError): exit(0) try: - # These are not very useful in scripts - gdb.execute("set pagination off") - # Run the actual tests run_test() except: diff --git a/tests/tcg/aarch64/gdbstub/test-sve.py b/tests/tcg/aarch64/gdbstub/test-sve.py index ef57c7412c..afd8ece98d 100644 --- a/tests/tcg/aarch64/gdbstub/test-sve.py +++ b/tests/tcg/aarch64/gdbstub/test-sve.py @@ -66,9 +66,6 @@ except (gdb.error, AttributeError): exit(0) try: - # These are not very useful in scripts - gdb.execute("set pagination off") - # Run the actual tests run_test() except: diff --git a/tests/tcg/multiarch/gdbstub/memory.py b/tests/tcg/multiarch/gdbstub/memory.py index 67864ad902..dd25e72281 100644 --- a/tests/tcg/multiarch/gdbstub/memory.py +++ b/tests/tcg/multiarch/gdbstub/memory.py @@ -115,9 +115,6 @@ if gdb.parse_and_eval('$pc') == 0: exit(0) try: - # These are not very useful in scripts - gdb.execute("set pagination off") - # Run the actual tests run_test() except (gdb.error): diff --git a/tests/tcg/multiarch/gdbstub/sha1.py b/tests/tcg/multiarch/gdbstub/sha1.py index 423b720e6d..416728415f 100644 --- a/tests/tcg/multiarch/gdbstub/sha1.py +++ b/tests/tcg/multiarch/gdbstub/sha1.py @@ -73,10 +73,6 @@ if gdb.parse_and_eval('$pc') == 0: exit(0) try: - # These are not very useful in scripts - gdb.execute("set pagination off") - gdb.execute("set confirm off") - # Run the actual tests run_test() except (gdb.error): diff --git a/tests/tcg/multiarch/gdbstub/test-proc-mappings.py b/tests/tcg/multiarch/gdbstub/test-proc-mappings.py index 5e3e5a2fb7..04ec61d219 100644 --- a/tests/tcg/multiarch/gdbstub/test-proc-mappings.py +++ b/tests/tcg/multiarch/gdbstub/test-proc-mappings.py @@ -51,10 +51,6 @@ def main(): exit(0) try: - # These are not very useful in scripts - gdb.execute("set pagination off") - gdb.execute("set confirm off") - # Run the actual tests run_test() except gdb.error: diff --git a/tests/tcg/multiarch/gdbstub/test-qxfer-auxv-read.py b/tests/tcg/multiarch/gdbstub/test-qxfer-auxv-read.py index d91e8fdf19..926fa962b7 100644 --- a/tests/tcg/multiarch/gdbstub/test-qxfer-auxv-read.py +++ b/tests/tcg/multiarch/gdbstub/test-qxfer-auxv-read.py @@ -42,10 +42,6 @@ if gdb.parse_and_eval('$pc') == 0: exit(0) try: - # These are not very useful in scripts - gdb.execute("set pagination off") - gdb.execute("set confirm off") - # Run the actual tests run_test() except (gdb.error): diff --git a/tests/tcg/multiarch/gdbstub/test-thread-breakpoint.py b/tests/tcg/multiarch/gdbstub/test-thread-breakpoint.py index 798d508bc7..e57d2a8db8 100644 --- a/tests/tcg/multiarch/gdbstub/test-thread-breakpoint.py +++ b/tests/tcg/multiarch/gdbstub/test-thread-breakpoint.py @@ -45,10 +45,6 @@ if gdb.parse_and_eval('$pc') == 0: exit(0) try: - # These are not very useful in scripts - gdb.execute("set pagination off") - gdb.execute("set confirm off") - # Run the actual tests run_test() except (gdb.error): diff --git a/tests/tcg/s390x/gdbstub/test-signals-s390x.py b/tests/tcg/s390x/gdbstub/test-signals-s390x.py index 80a284b475..ca2bbc0b03 100644 --- a/tests/tcg/s390x/gdbstub/test-signals-s390x.py +++ b/tests/tcg/s390x/gdbstub/test-signals-s390x.py @@ -61,10 +61,6 @@ if gdb.parse_and_eval("$pc") == 0: exit(0) try: - # These are not very useful in scripts - gdb.execute("set pagination off") - gdb.execute("set confirm off") - # Run the actual tests run_test() except (gdb.error): diff --git a/tests/tcg/s390x/gdbstub/test-svc.py b/tests/tcg/s390x/gdbstub/test-svc.py index 18fad3f163..804705fede 100644 --- a/tests/tcg/s390x/gdbstub/test-svc.py +++ b/tests/tcg/s390x/gdbstub/test-svc.py @@ -49,10 +49,6 @@ def main(): exit(0) try: - # These are not very useful in scripts - gdb.execute("set pagination off") - gdb.execute("set confirm off") - # Run the actual tests run_test() except gdb.error: From 761e3c10881b5f521b19b713cf8d16c72c47affb Mon Sep 17 00:00:00 2001 From: Matheus Branco Borella Date: Tue, 29 Aug 2023 17:15:24 +0100 Subject: [PATCH 1322/1353] gdbstub: fixes cases where wrong threads were reported to GDB on SIGINT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fix is implemented by having the vCont handler set the value of `gdbserver_state.c_cpu` if any threads are to be resumed. The specific CPU picked is arbitrarily from the ones to be resumed, but it should be okay, as all GDB cares about is that it is a resumed thread. Signed-off-by: Matheus Branco Borella Message-Id: <20230804182633.47300-2-dark.ryu.550@gmail.com> [AJB: style and whitespace fixes] Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1725 Signed-off-by: Alex Bennée Message-Id: <20230829161528.2707696-9-alex.bennee@linaro.org> --- gdbstub/gdbstub.c | 29 ++++++ tests/tcg/multiarch/gdbstub/interrupt.py | 97 +++++++++++++++++++ .../multiarch/system/Makefile.softmmu-target | 12 ++- tests/tcg/multiarch/system/interrupt.c | 28 ++++++ 4 files changed, 164 insertions(+), 2 deletions(-) create mode 100644 tests/tcg/multiarch/gdbstub/interrupt.py create mode 100644 tests/tcg/multiarch/system/interrupt.c diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c index 5f28d5cf57..e7d48fa0d4 100644 --- a/gdbstub/gdbstub.c +++ b/gdbstub/gdbstub.c @@ -597,6 +597,15 @@ static int gdb_handle_vcont(const char *p) * or incorrect parameters passed. */ res = 0; + + /* + * target_count and last_target keep track of how many CPUs we are going to + * step or resume, and a pointer to the state structure of one of them, + * respectivelly + */ + int target_count = 0; + CPUState *last_target = NULL; + while (*p) { if (*p++ != ';') { return -ENOTSUP; @@ -637,6 +646,9 @@ static int gdb_handle_vcont(const char *p) while (cpu) { if (newstates[cpu->cpu_index] == 1) { newstates[cpu->cpu_index] = cur_action; + + target_count++; + last_target = cpu; } cpu = gdb_next_attached_cpu(cpu); @@ -654,6 +666,9 @@ static int gdb_handle_vcont(const char *p) while (cpu) { if (newstates[cpu->cpu_index] == 1) { newstates[cpu->cpu_index] = cur_action; + + target_count++; + last_target = cpu; } cpu = gdb_next_cpu_in_process(cpu); @@ -671,11 +686,25 @@ static int gdb_handle_vcont(const char *p) /* only use if no previous match occourred */ if (newstates[cpu->cpu_index] == 1) { newstates[cpu->cpu_index] = cur_action; + + target_count++; + last_target = cpu; } break; } } + /* + * if we're about to resume a specific set of CPUs/threads, make it so that + * in case execution gets interrupted, we can send GDB a stop reply with a + * correct value. it doesn't really matter which CPU we tell GDB the signal + * happened in (VM pauses stop all of them anyway), so long as it is one of + * the ones we resumed/single stepped here. + */ + if (target_count > 0) { + gdbserver_state.c_cpu = last_target; + } + gdbserver_state.signal = signal; gdb_continue_partial(newstates); return res; diff --git a/tests/tcg/multiarch/gdbstub/interrupt.py b/tests/tcg/multiarch/gdbstub/interrupt.py new file mode 100644 index 0000000000..e222ac94c5 --- /dev/null +++ b/tests/tcg/multiarch/gdbstub/interrupt.py @@ -0,0 +1,97 @@ +from __future__ import print_function +# +# Test some of the softmmu debug features with the multiarch memory +# test. It is a port of the original vmlinux focused test case but +# using the "memory" test instead. +# +# This is launched via tests/guest-debug/run-test.py +# + +import gdb +import sys + +failcount = 0 + + +def report(cond, msg): + "Report success/fail of test" + if cond: + print("PASS: %s" % (msg)) + else: + print("FAIL: %s" % (msg)) + global failcount + failcount += 1 + + +def check_interrupt(thread): + """ + Check that, if thread is resumed, we go back to the same thread when the + program gets interrupted. + """ + + # Switch to the thread we're going to be running the test in. + print("thread ", thread.num) + gdb.execute("thr %d" % thread.num) + + # Enter the loop() function on this thread. + # + # While there are cleaner ways to do this, we want to minimize the number of + # side effects on the gdbstub's internal state, since those may mask bugs. + # Ideally, there should be no difference between what we're doing here and + # the program reaching the loop() function on its own. + # + # For this to be safe, we only need the prologue of loop() to not have + # instructions that may have problems with what we're doing here. We don't + # have to worry about anything else, as this function never returns. + gdb.execute("set $pc = loop") + + # Continue and then interrupt the task. + gdb.post_event(lambda: gdb.execute("interrupt")) + gdb.execute("c") + + # Check whether the thread we're in after the interruption is the same we + # ran continue from. + return (thread.num == gdb.selected_thread().num) + + +def run_test(): + """ + Test if interrupting the code always lands us on the same thread when + running with scheduler-lock enabled. + """ + + gdb.execute("set scheduler-locking on") + for thread in gdb.selected_inferior().threads(): + report(check_interrupt(thread), + "thread %d resumes correctly on interrupt" % thread.num) + + +# +# This runs as the script it sourced (via -x, via run-test.py) +# +try: + inferior = gdb.selected_inferior() + arch = inferior.architecture() + print("ATTACHED: %s" % arch.name()) +except (gdb.error, AttributeError): + print("SKIPPING (not connected)", file=sys.stderr) + exit(0) + +if gdb.parse_and_eval('$pc') == 0: + print("SKIP: PC not set") + exit(0) +if len(gdb.selected_inferior().threads()) == 1: + print("SKIP: set to run on a single thread") + exit(0) + +try: + # Run the actual tests + run_test() +except (gdb.error): + print("GDB Exception: %s" % (sys.exc_info()[0])) + failcount += 1 + pass + +# Finally kill the inferior and exit gdb with a count of failures +gdb.execute("kill") +exit(failcount) diff --git a/tests/tcg/multiarch/system/Makefile.softmmu-target b/tests/tcg/multiarch/system/Makefile.softmmu-target index a051d689d7..90810a32b2 100644 --- a/tests/tcg/multiarch/system/Makefile.softmmu-target +++ b/tests/tcg/multiarch/system/Makefile.softmmu-target @@ -27,7 +27,15 @@ run-gdbstub-memory: memory "-monitor none -display none -chardev file$(COMMA)path=$<.out$(COMMA)id=output $(QEMU_OPTS)" \ --bin $< --test $(MULTIARCH_SRC)/gdbstub/memory.py, \ softmmu gdbstub support) - +run-gdbstub-interrupt: interrupt + $(call run-test, $@, $(GDB_SCRIPT) \ + --gdb $(HAVE_GDB_BIN) \ + --qemu $(QEMU) \ + --output $<.gdb.out \ + --qargs \ + "-smp 2 -monitor none -display none -chardev file$(COMMA)path=$<.out$(COMMA)id=output $(QEMU_OPTS)" \ + --bin $< --test $(MULTIARCH_SRC)/gdbstub/interrupt.py, \ + softmmu gdbstub support) run-gdbstub-untimely-packet: hello $(call run-test, $@, $(GDB_SCRIPT) \ --gdb $(HAVE_GDB_BIN) \ @@ -50,4 +58,4 @@ run-gdbstub-%: $(call skip-test, "gdbstub test $*", "need working gdb") endif -MULTIARCH_RUNS += run-gdbstub-memory run-gdbstub-untimely-packet +MULTIARCH_RUNS += run-gdbstub-memory run-gdbstub-interrupt run-gdbstub-untimely-packet diff --git a/tests/tcg/multiarch/system/interrupt.c b/tests/tcg/multiarch/system/interrupt.c new file mode 100644 index 0000000000..98d4f2eff9 --- /dev/null +++ b/tests/tcg/multiarch/system/interrupt.c @@ -0,0 +1,28 @@ +/* + * External interruption test. This test is structured in such a way that it + * passes the cases that require it to exit, but we can make it enter an + * infinite loop from GDB. + * + * We don't have the benefit of libc, just builtin C primitives and + * whatever is in minilib. + */ + +#include + +void loop(void) +{ + do { + /* + * Loop forever. Just make sure the condition is always a constant + * expression, so that this loop is not UB, as per the C + * standard. + */ + } while (1); +} + +int main(void) +{ + return 0; +} + + From 5b030993dba1bbb841431506c0919c7a7bef986c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 29 Aug 2023 17:15:25 +0100 Subject: [PATCH 1323/1353] gdbstub: remove unused user_ctx field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was always NULL so drop it. Reviewed-by: Philippe Mathieu-Daudé Acked-by: Ilya Leoshkevich Signed-off-by: Alex Bennée Message-Id: <20230829161528.2707696-10-alex.bennee@linaro.org> --- gdbstub/gdbstub.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c index e7d48fa0d4..8e9bc17e07 100644 --- a/gdbstub/gdbstub.c +++ b/gdbstub/gdbstub.c @@ -836,7 +836,7 @@ static inline int startswith(const char *string, const char *pattern) return !strncmp(string, pattern, strlen(pattern)); } -static int process_string_cmd(void *user_ctx, const char *data, +static int process_string_cmd(const char *data, const GdbCmdParseEntry *cmds, int num_cmds) { int i; @@ -863,7 +863,7 @@ static int process_string_cmd(void *user_ctx, const char *data, } gdbserver_state.allow_stop_reply = cmd->allow_stop_reply; - cmd->handler(params, user_ctx); + cmd->handler(params, NULL); return 0; } @@ -881,7 +881,7 @@ static void run_cmd_parser(const char *data, const GdbCmdParseEntry *cmd) /* In case there was an error during the command parsing we must * send a NULL packet to indicate the command is not supported */ - if (process_string_cmd(NULL, data, cmd, 1)) { + if (process_string_cmd(data, cmd, 1)) { gdb_put_packet(""); } } @@ -1394,7 +1394,7 @@ static void handle_v_commands(GArray *params, void *user_ctx) return; } - if (process_string_cmd(NULL, get_param(params, 0)->data, + if (process_string_cmd(get_param(params, 0)->data, gdb_v_commands_table, ARRAY_SIZE(gdb_v_commands_table))) { gdb_put_packet(""); @@ -1738,13 +1738,13 @@ static void handle_gen_query(GArray *params, void *user_ctx) return; } - if (!process_string_cmd(NULL, get_param(params, 0)->data, + if (!process_string_cmd(get_param(params, 0)->data, gdb_gen_query_set_common_table, ARRAY_SIZE(gdb_gen_query_set_common_table))) { return; } - if (process_string_cmd(NULL, get_param(params, 0)->data, + if (process_string_cmd(get_param(params, 0)->data, gdb_gen_query_table, ARRAY_SIZE(gdb_gen_query_table))) { gdb_put_packet(""); @@ -1757,13 +1757,13 @@ static void handle_gen_set(GArray *params, void *user_ctx) return; } - if (!process_string_cmd(NULL, get_param(params, 0)->data, + if (!process_string_cmd(get_param(params, 0)->data, gdb_gen_query_set_common_table, ARRAY_SIZE(gdb_gen_query_set_common_table))) { return; } - if (process_string_cmd(NULL, get_param(params, 0)->data, + if (process_string_cmd(get_param(params, 0)->data, gdb_gen_set_table, ARRAY_SIZE(gdb_gen_set_table))) { gdb_put_packet(""); From 56e534bd116afda6f7b9ef96691549373c64040d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 29 Aug 2023 17:15:26 +0100 Subject: [PATCH 1324/1353] gdbstub: refactor get_feature_xml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Try to bring up the code to more modern standards by: - use dynamic GString built xml over a fixed buffer - use autofree to save on explicit g_free() calls - don't hand hack strstr to find the delimiter - fix up style of xml_builtin and invert loop Reviewed-by: Richard Henderson Signed-off-by: Alex Bennée Message-Id: <20230829161528.2707696-11-alex.bennee@linaro.org> --- gdbstub/gdbstub.c | 87 +++++++++++++++++++++++---------------------- gdbstub/internals.h | 2 +- 2 files changed, 46 insertions(+), 43 deletions(-) diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c index 8e9bc17e07..729e54139a 100644 --- a/gdbstub/gdbstub.c +++ b/gdbstub/gdbstub.c @@ -354,64 +354,67 @@ static CPUState *gdb_get_cpu(uint32_t pid, uint32_t tid) static const char *get_feature_xml(const char *p, const char **newp, GDBProcess *process) { - size_t len; - int i; - const char *name; CPUState *cpu = gdb_get_first_cpu_in_process(process); CPUClass *cc = CPU_GET_CLASS(cpu); + size_t len; - len = 0; - while (p[len] && p[len] != ':') - len++; - *newp = p + len; + /* + * qXfer:features:read:ANNEX:OFFSET,LENGTH' + * ^p ^newp + */ + char *term = strchr(p, ':'); + *newp = term + 1; + len = term - p; - name = NULL; + /* Is it the main target xml? */ if (strncmp(p, "target.xml", len) == 0) { - char *buf = process->target_xml; - const size_t buf_sz = sizeof(process->target_xml); - - /* Generate the XML description for this CPU. */ - if (!buf[0]) { + if (!process->target_xml) { GDBRegisterState *r; + GString *xml = g_string_new(""); + + g_string_append(xml, + "" + ""); - pstrcat(buf, buf_sz, - "" - "" - ""); if (cc->gdb_arch_name) { - gchar *arch = cc->gdb_arch_name(cpu); - pstrcat(buf, buf_sz, ""); - pstrcat(buf, buf_sz, arch); - pstrcat(buf, buf_sz, ""); - g_free(arch); + g_autofree gchar *arch = cc->gdb_arch_name(cpu); + g_string_append_printf(xml, + "%s", + arch); } - pstrcat(buf, buf_sz, "gdb_core_xml_file); - pstrcat(buf, buf_sz, "\"/>"); + g_string_append(xml, "gdb_core_xml_file); + g_string_append(xml, "\"/>"); for (r = cpu->gdb_regs; r; r = r->next) { - pstrcat(buf, buf_sz, "xml); - pstrcat(buf, buf_sz, "\"/>"); + g_string_append(xml, "xml); + g_string_append(xml, "\"/>"); } - pstrcat(buf, buf_sz, ""); - } - return buf; - } - if (cc->gdb_get_dynamic_xml) { - char *xmlname = g_strndup(p, len); - const char *xml = cc->gdb_get_dynamic_xml(cpu, xmlname); + g_string_append(xml, ""); - g_free(xmlname); + process->target_xml = g_string_free(xml, false); + return process->target_xml; + } + } + /* Is it dynamically generated by the target? */ + if (cc->gdb_get_dynamic_xml) { + g_autofree char *xmlname = g_strndup(p, len); + const char *xml = cc->gdb_get_dynamic_xml(cpu, xmlname); if (xml) { return xml; } } - for (i = 0; ; i++) { - name = xml_builtin[i][0]; - if (!name || (strncmp(name, p, len) == 0 && strlen(name) == len)) - break; + /* Is it one of the encoded gdb-xml/ files? */ + for (int i = 0; xml_builtin[i][0]; i++) { + const char *name = xml_builtin[i][0]; + if ((strncmp(name, p, len) == 0) && + strlen(name) == len) { + return xml_builtin[i][1]; + } } - return name ? xml_builtin[i][1] : NULL; + + /* failed */ + return NULL; } static int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg) @@ -2245,6 +2248,6 @@ void gdb_create_default_process(GDBState *s) process = &s->processes[s->process_num - 1]; process->pid = pid; process->attached = false; - process->target_xml[0] = '\0'; + process->target_xml = NULL; } diff --git a/gdbstub/internals.h b/gdbstub/internals.h index f2b46cce41..4876ebd74f 100644 --- a/gdbstub/internals.h +++ b/gdbstub/internals.h @@ -33,7 +33,7 @@ typedef struct GDBProcess { uint32_t pid; bool attached; - char target_xml[1024]; + char *target_xml; } GDBProcess; enum RSState { From d0e5fa849db4d729e0607ef597cb31eac79532a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 29 Aug 2023 17:15:27 +0100 Subject: [PATCH 1325/1353] gdbstub: replace global gdb_has_xml with a function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Try and make the self reported global hack a little less hackish by providing a query function instead. As gdb_has_xml was always set if we negotiated XML we can now use the presence of ->target_xml as the test instead. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Alex Bennée Message-Id: <20230829161528.2707696-12-alex.bennee@linaro.org> --- gdbstub/gdbstub.c | 12 +++++++----- gdbstub/internals.h | 1 + gdbstub/softmmu.c | 1 - gdbstub/user.c | 1 - include/exec/gdbstub.h | 10 +++++----- target/arm/gdbstub.c | 8 ++++---- target/ppc/gdbstub.c | 4 ++-- 7 files changed, 19 insertions(+), 18 deletions(-) diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c index 729e54139a..fdebfe25ea 100644 --- a/gdbstub/gdbstub.c +++ b/gdbstub/gdbstub.c @@ -75,8 +75,6 @@ void gdb_init_gdbserver_state(void) gdbserver_state.sstep_flags &= gdbserver_state.supported_sstep_flags; } -bool gdb_has_xml; - /* writes 2*len+1 bytes in buf */ void gdb_memtohex(GString *buf, const uint8_t *mem, int len) { @@ -351,6 +349,11 @@ static CPUState *gdb_get_cpu(uint32_t pid, uint32_t tid) } } +bool gdb_has_xml(void) +{ + return !!gdb_get_cpu_process(gdbserver_state.g_cpu)->target_xml; +} + static const char *get_feature_xml(const char *p, const char **newp, GDBProcess *process) { @@ -1084,7 +1087,7 @@ static void handle_set_reg(GArray *params, void *user_ctx) { int reg_size; - if (!gdb_has_xml) { + if (!gdb_get_cpu_process(gdbserver_state.g_cpu)->target_xml) { gdb_put_packet(""); return; } @@ -1105,7 +1108,7 @@ static void handle_get_reg(GArray *params, void *user_ctx) { int reg_size; - if (!gdb_has_xml) { + if (!gdb_get_cpu_process(gdbserver_state.g_cpu)->target_xml) { gdb_put_packet(""); return; } @@ -1572,7 +1575,6 @@ static void handle_query_xfer_features(GArray *params, void *user_ctx) return; } - gdb_has_xml = true; p = get_param(params, 0)->data; xml = get_feature_xml(p, &p, process); if (!xml) { diff --git a/gdbstub/internals.h b/gdbstub/internals.h index 4876ebd74f..fee243081f 100644 --- a/gdbstub/internals.h +++ b/gdbstub/internals.h @@ -33,6 +33,7 @@ typedef struct GDBProcess { uint32_t pid; bool attached; + /* If gdb sends qXfer:features:read:target.xml this will be populated */ char *target_xml; } GDBProcess; diff --git a/gdbstub/softmmu.c b/gdbstub/softmmu.c index f509b7285d..9f0b8b5497 100644 --- a/gdbstub/softmmu.c +++ b/gdbstub/softmmu.c @@ -97,7 +97,6 @@ static void gdb_chr_event(void *opaque, QEMUChrEvent event) vm_stop(RUN_STATE_PAUSED); replay_gdb_attached(); - gdb_has_xml = false; break; default: break; diff --git a/gdbstub/user.c b/gdbstub/user.c index 5b375be1d9..7ab6e5d975 100644 --- a/gdbstub/user.c +++ b/gdbstub/user.c @@ -198,7 +198,6 @@ static void gdb_accept_init(int fd) gdbserver_state.c_cpu = gdb_first_attached_cpu(); gdbserver_state.g_cpu = gdbserver_state.c_cpu; gdbserver_user_state.fd = fd; - gdb_has_xml = false; } static bool gdb_accept_socket(int gdb_fd) diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h index 7d743fe1e9..0ee39cfdd1 100644 --- a/include/exec/gdbstub.h +++ b/include/exec/gdbstub.h @@ -31,12 +31,12 @@ int gdbserver_start(const char *port_or_device); 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. + * gdb_has_xml() - report of gdb supports modern target descriptions + * + * This will report true if the gdb negotiated qXfer:features:read + * target descriptions. */ -extern bool gdb_has_xml; +bool gdb_has_xml(void); /* in gdbstub-xml.c, generated by scripts/feature_to_c.sh */ extern const char *const xml_builtin[][2]; diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c index f421c5d041..8fc8351df7 100644 --- a/target/arm/gdbstub.c +++ b/target/arm/gdbstub.c @@ -48,7 +48,7 @@ int arm_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) } if (n < 24) { /* FPA registers. */ - if (gdb_has_xml) { + if (gdb_has_xml()) { return 0; } return gdb_get_zeroes(mem_buf, 12); @@ -56,7 +56,7 @@ int arm_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) switch (n) { case 24: /* FPA status register. */ - if (gdb_has_xml) { + if (gdb_has_xml()) { return 0; } return gdb_get_reg32(mem_buf, 0); @@ -102,7 +102,7 @@ int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) } if (n < 24) { /* 16-23 */ /* FPA registers (ignored). */ - if (gdb_has_xml) { + if (gdb_has_xml()) { return 0; } return 12; @@ -110,7 +110,7 @@ int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) switch (n) { case 24: /* FPA status register (ignored). */ - if (gdb_has_xml) { + if (gdb_has_xml()) { return 0; } return 4; diff --git a/target/ppc/gdbstub.c b/target/ppc/gdbstub.c index ca39efdc35..2ad11510bf 100644 --- a/target/ppc/gdbstub.c +++ b/target/ppc/gdbstub.c @@ -56,7 +56,7 @@ static int ppc_gdb_register_len(int n) return sizeof(target_ulong); case 32 ... 63: /* fprs */ - if (gdb_has_xml) { + if (gdb_has_xml()) { return 0; } return 8; @@ -76,7 +76,7 @@ static int ppc_gdb_register_len(int n) return sizeof(target_ulong); case 70: /* fpscr */ - if (gdb_has_xml) { + if (gdb_has_xml()) { return 0; } return sizeof(target_ulong); From 8dd7a4b3487ab93ff8fddc5f818942ff39d4550f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 29 Aug 2023 17:15:28 +0100 Subject: [PATCH 1326/1353] gdbstub: move comment for gdb_register_coprocessor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use proper kdoc style comments for this API function. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Alex Bennée Message-Id: <20230829161528.2707696-13-alex.bennee@linaro.org> --- gdbstub/gdbstub.c | 6 ------ include/exec/gdbstub.h | 10 ++++++++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c index fdebfe25ea..349d348c7b 100644 --- a/gdbstub/gdbstub.c +++ b/gdbstub/gdbstub.c @@ -456,12 +456,6 @@ static int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg) return 0; } -/* Register a supplemental set of CPU registers. If g_pos is nonzero it - specifies the first register number and these registers are included in - a standard "g" packet. Direction is relative to gdb, i.e. get_reg is - gdb reading a CPU register, and set_reg is gdb modifying a CPU register. - */ - 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) diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h index 0ee39cfdd1..16a139043f 100644 --- a/include/exec/gdbstub.h +++ b/include/exec/gdbstub.h @@ -14,6 +14,16 @@ /* 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); + +/** + * 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); From 8a45962be33d4f7449567f8b9e07c724733ca303 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Wed, 30 Aug 2023 08:44:01 -0600 Subject: [PATCH 1327/1353] bsd-user: Move PRAGMA_DISABLE_PACKED_WARNING etc to qemu.h For the moment, move PRAGMA_DISABLE_PACKED_WARNING and PRAGMA_ENABLE_PACKED_WARNING back to bsd-user/qemu.h. Of course, these should be in compiler.h, but that interferes with too many things at the moment, so take one step back to unbreak clang linux-user builds first. Use the exact same version that's in linux-user/qemu.h since that's what should be in compiler.h. Signed-off-by: Warner Losh Reviewed-by: Peter Maydell --- bsd-user/qemu.h | 27 +++++++++++++++++++++++++++ include/qemu/compiler.h | 30 ------------------------------ 2 files changed, 27 insertions(+), 30 deletions(-) diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index 4cfd5c6337..d3158bc2ed 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -273,6 +273,33 @@ static inline bool access_ok(int type, abi_ulong addr, abi_ulong size) * These are usually used to access struct data members once the struct has been * locked - usually with lock_user_struct(). */ + +/* + * Tricky points: + * - Use __builtin_choose_expr to avoid type promotion from ?:, + * - Invalid sizes result in a compile time error stemming from + * the fact that abort has no parameters. + * - It's easier to use the endian-specific unaligned load/store + * functions than host-endian unaligned load/store plus tswapN. + * - The pragmas are necessary only to silence a clang false-positive + * warning: see https://bugs.llvm.org/show_bug.cgi?id=39113 . + * - gcc has bugs in its _Pragma() support in some versions, eg + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83256 -- so we only + * include the warning-suppression pragmas for clang + */ +#if defined(__clang__) && __has_warning("-Waddress-of-packed-member") +#define PRAGMA_DISABLE_PACKED_WARNING \ + _Pragma("GCC diagnostic push"); \ + _Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\"") + +#define PRAGMA_REENABLE_PACKED_WARNING \ + _Pragma("GCC diagnostic pop") + +#else +#define PRAGMA_DISABLE_PACKED_WARNING +#define PRAGMA_REENABLE_PACKED_WARNING +#endif + #define __put_user_e(x, hptr, e) \ do { \ PRAGMA_DISABLE_PACKED_WARNING; \ diff --git a/include/qemu/compiler.h b/include/qemu/compiler.h index b037442518..a309f90c76 100644 --- a/include/qemu/compiler.h +++ b/include/qemu/compiler.h @@ -22,36 +22,6 @@ #define QEMU_EXTERN_C extern #endif -/* - * Tricky points: - * - Use __builtin_choose_expr to avoid type promotion from ?:, - * - Invalid sizes result in a compile time error stemming from - * the fact that abort has no parameters. - * - It's easier to use the endian-specific unaligned load/store - * functions than host-endian unaligned load/store plus tswapN. - * - The pragmas are necessary only to silence a clang false-positive - * warning: see https://bugs.llvm.org/show_bug.cgi?id=39113 . - * - We have to disable -Wpragmas warnings to avoid a complaint about - * an unknown warning type from older compilers that don't know about - * -Waddress-of-packed-member. - * - gcc has bugs in its _Pragma() support in some versions, eg - * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83256 -- so we only - * include the warning-suppression pragmas for clang - */ -#ifdef __clang__ -#define PRAGMA_DISABLE_PACKED_WARNING \ - _Pragma("GCC diagnostic push"); \ - _Pragma("GCC diagnostic ignored \"-Wpragmas\""); \ - _Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\"") - -#define PRAGMA_REENABLE_PACKED_WARNING \ - _Pragma("GCC diagnostic pop") - -#else -#define PRAGMA_DISABLE_PACKED_WARNING -#define PRAGMA_REENABLE_PACKED_WARNING -#endif - #if defined(_WIN32) && (defined(__x86_64__) || defined(__i386__)) # define QEMU_PACKED __attribute__((gcc_struct, packed)) #else From 0c8ab1cddd6c1bf4e3722fcea111e614c22dcc09 Mon Sep 17 00:00:00 2001 From: Oleksandr Tyshchenko Date: Tue, 29 Aug 2023 21:35:17 -0700 Subject: [PATCH 1328/1353] xen_arm: Create virtio-mmio devices during initialization In order to use virtio backends we need to allocate virtio-mmio parameters (irq and base) and register corresponding buses. Use the constants defined in public header arch-arm.h to be aligned with the toolstack. So the number of current supported virtio-mmio devices is 10. For the interrupts triggering use already existing on Arm device-model hypercall. The toolstack should then insert the same amount of device nodes into guest device-tree. Signed-off-by: Oleksandr Tyshchenko Signed-off-by: Vikram Garhwal Reviewed-by: Stefano Stabellini Signed-off-by: Stefano Stabellini --- hw/arm/xen_arm.c | 35 +++++++++++++++++++++++++++++++++++ include/hw/xen/xen_native.h | 16 ++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/hw/arm/xen_arm.c b/hw/arm/xen_arm.c index 1d3e6d481a..7393b37355 100644 --- a/hw/arm/xen_arm.c +++ b/hw/arm/xen_arm.c @@ -26,6 +26,7 @@ #include "qapi/qapi-commands-migration.h" #include "qapi/visitor.h" #include "hw/boards.h" +#include "hw/irq.h" #include "hw/sysbus.h" #include "sysemu/block-backend.h" #include "sysemu/tpm_backend.h" @@ -59,6 +60,38 @@ struct XenArmState { } cfg; }; +/* + * VIRTIO_MMIO_DEV_SIZE is imported from tools/libs/light/libxl_arm.c under Xen + * repository. + * + * Origin: git://xenbits.xen.org/xen.git 2128143c114c + */ +#define VIRTIO_MMIO_DEV_SIZE 0x200 + +#define NR_VIRTIO_MMIO_DEVICES \ + (GUEST_VIRTIO_MMIO_SPI_LAST - GUEST_VIRTIO_MMIO_SPI_FIRST) + +static void xen_set_irq(void *opaque, int irq, int level) +{ + xendevicemodel_set_irq_level(xen_dmod, xen_domid, irq, level); +} + +static void xen_create_virtio_mmio_devices(XenArmState *xam) +{ + int i; + + for (i = 0; i < NR_VIRTIO_MMIO_DEVICES; i++) { + hwaddr base = GUEST_VIRTIO_MMIO_BASE + i * VIRTIO_MMIO_DEV_SIZE; + qemu_irq irq = qemu_allocate_irq(xen_set_irq, NULL, + GUEST_VIRTIO_MMIO_SPI_FIRST + i); + + sysbus_create_simple("virtio-mmio", base, irq); + + DPRINTF("Created virtio-mmio device %d: irq %d base 0x%lx\n", + i, GUEST_VIRTIO_MMIO_SPI_FIRST + i, base); + } +} + void arch_handle_ioreq(XenIOState *state, ioreq_t *req) { hw_error("Invalid ioreq type 0x%x\n", req->type); @@ -110,6 +143,8 @@ static void xen_arm_init(MachineState *machine) xen_register_ioreq(xam->state, machine->smp.cpus, &xen_memory_listener); + xen_create_virtio_mmio_devices(xam); + #ifdef CONFIG_TPM if (xam->cfg.tpm_base_addr) { xen_enable_tpm(xam); diff --git a/include/hw/xen/xen_native.h b/include/hw/xen/xen_native.h index 4dce905fde..a4b1aa9e5d 100644 --- a/include/hw/xen/xen_native.h +++ b/include/hw/xen/xen_native.h @@ -523,4 +523,20 @@ static inline int xen_set_ioreq_server_state(domid_t dom, enable); } +#if CONFIG_XEN_CTRL_INTERFACE_VERSION <= 41500 +static inline int xendevicemodel_set_irq_level(xendevicemodel_handle *dmod, + domid_t domid, uint32_t irq, + unsigned int level) +{ + return 0; +} +#endif + +#if CONFIG_XEN_CTRL_INTERFACE_VERSION <= 41700 +#define GUEST_VIRTIO_MMIO_BASE xen_mk_ullong(0x02000000) +#define GUEST_VIRTIO_MMIO_SIZE xen_mk_ullong(0x00100000) +#define GUEST_VIRTIO_MMIO_SPI_FIRST 33 +#define GUEST_VIRTIO_MMIO_SPI_LAST 43 +#endif + #endif /* QEMU_HW_XEN_NATIVE_H */ From 560142190bc347fdd4511a795bdcff768799519d Mon Sep 17 00:00:00 2001 From: Oleksandr Tyshchenko Date: Tue, 29 Aug 2023 21:35:18 -0700 Subject: [PATCH 1329/1353] xen_arm: Initialize RAM and add hi/low memory regions In order to use virtio backends we need to initialize RAM for the xen-mapcache (which is responsible for mapping guest memory using foreign mapping) to work. Calculate and add hi/low memory regions based on machine->ram_size. Use the constants defined in public header arch-arm.h to be aligned with the xen toolstack. While using this machine, the toolstack should then pass real ram_size using "-m" arg. If "-m" is not given, create a QEMU machine without IOREQ and other emulated devices like TPM and VIRTIO. This is done to keep this QEMU machine usable for /etc/init.d/xencommons. Signed-off-by: Oleksandr Tyshchenko Signed-off-by: Vikram Garhwal Reviewed-by: Stefano Stabellini Signed-off-by: Stefano Stabellini --- hw/arm/xen_arm.c | 45 +++++++++++++++++++++++++++++++++++++ include/hw/xen/xen_native.h | 8 +++++++ 2 files changed, 53 insertions(+) diff --git a/hw/arm/xen_arm.c b/hw/arm/xen_arm.c index 7393b37355..f83b983ec5 100644 --- a/hw/arm/xen_arm.c +++ b/hw/arm/xen_arm.c @@ -60,6 +60,8 @@ struct XenArmState { } cfg; }; +static MemoryRegion ram_lo, ram_hi; + /* * VIRTIO_MMIO_DEV_SIZE is imported from tools/libs/light/libxl_arm.c under Xen * repository. @@ -92,6 +94,39 @@ static void xen_create_virtio_mmio_devices(XenArmState *xam) } } +static void xen_init_ram(MachineState *machine) +{ + MemoryRegion *sysmem = get_system_memory(); + ram_addr_t block_len, ram_size[GUEST_RAM_BANKS]; + + if (machine->ram_size <= GUEST_RAM0_SIZE) { + ram_size[0] = machine->ram_size; + ram_size[1] = 0; + block_len = GUEST_RAM0_BASE + ram_size[0]; + } else { + ram_size[0] = GUEST_RAM0_SIZE; + ram_size[1] = machine->ram_size - GUEST_RAM0_SIZE; + block_len = GUEST_RAM1_BASE + ram_size[1]; + } + + memory_region_init_ram(&ram_memory, NULL, "xen.ram", block_len, + &error_fatal); + + memory_region_init_alias(&ram_lo, NULL, "xen.ram.lo", &ram_memory, + GUEST_RAM0_BASE, ram_size[0]); + memory_region_add_subregion(sysmem, GUEST_RAM0_BASE, &ram_lo); + DPRINTF("Initialized region xen.ram.lo: base 0x%llx size 0x%lx\n", + GUEST_RAM0_BASE, ram_size[0]); + + if (ram_size[1] > 0) { + memory_region_init_alias(&ram_hi, NULL, "xen.ram.hi", &ram_memory, + GUEST_RAM1_BASE, ram_size[1]); + memory_region_add_subregion(sysmem, GUEST_RAM1_BASE, &ram_hi); + DPRINTF("Initialized region xen.ram.hi: base 0x%llx size 0x%lx\n", + GUEST_RAM1_BASE, ram_size[1]); + } +} + void arch_handle_ioreq(XenIOState *state, ioreq_t *req) { hw_error("Invalid ioreq type 0x%x\n", req->type); @@ -141,6 +176,14 @@ static void xen_arm_init(MachineState *machine) xam->state = g_new0(XenIOState, 1); + if (machine->ram_size == 0) { + DPRINTF("ram_size not specified. QEMU machine started without IOREQ" + "(no emulated devices including Virtio)\n"); + return; + } + + xen_init_ram(machine); + xen_register_ioreq(xam->state, machine->smp.cpus, &xen_memory_listener); xen_create_virtio_mmio_devices(xam); @@ -188,6 +231,8 @@ static void xen_arm_machine_class_init(ObjectClass *oc, void *data) mc->init = xen_arm_init; mc->max_cpus = 1; mc->default_machine_opts = "accel=xen"; + /* Set explicitly here to make sure that real ram_size is passed */ + mc->default_ram_size = 0; #ifdef CONFIG_TPM object_class_property_add(oc, "tpm-base-addr", "uint64_t", diff --git a/include/hw/xen/xen_native.h b/include/hw/xen/xen_native.h index a4b1aa9e5d..5d2718261f 100644 --- a/include/hw/xen/xen_native.h +++ b/include/hw/xen/xen_native.h @@ -539,4 +539,12 @@ static inline int xendevicemodel_set_irq_level(xendevicemodel_handle *dmod, #define GUEST_VIRTIO_MMIO_SPI_LAST 43 #endif +#if defined(__i386__) || defined(__x86_64__) +#define GUEST_RAM_BANKS 2 +#define GUEST_RAM0_BASE 0x40000000ULL /* 3GB of low RAM @ 1GB */ +#define GUEST_RAM0_SIZE 0xc0000000ULL +#define GUEST_RAM1_BASE 0x0200000000ULL /* 1016GB of RAM @ 8GB */ +#define GUEST_RAM1_SIZE 0xfe00000000ULL +#endif + #endif /* QEMU_HW_XEN_NATIVE_H */ From ae4acc696f34bf0cb8865521c16ff378b19915b3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 31 Aug 2023 09:45:14 +0100 Subject: [PATCH 1330/1353] target/arm: Reduce dcz_blocksize to uint8_t MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This value is only 4 bits wide. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20230811214031.171020-2-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index cdf8600b96..a1e604366b 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -1074,7 +1074,8 @@ struct ArchCPU { bool prop_lpa2; /* DCZ blocksize, in log_2(words), ie low 4 bits of DCZID_EL0 */ - uint32_t dcz_blocksize; + uint8_t dcz_blocksize; + uint64_t rvbar_prop; /* Property/input signals. */ /* Configurable aspects of GIC cpu interface (which is part of the CPU) */ From 851ec6eba56d0153574c042bff05a3d0f235a00e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 31 Aug 2023 09:45:14 +0100 Subject: [PATCH 1331/1353] target/arm: Allow cpu to configure GM blocksize Previously we hard-coded the blocksize with GMID_EL1_BS. But the value we choose for -cpu max does not match the value that cortex-a710 uses. Mirror the way we handle dcz_blocksize. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20230811214031.171020-3-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.h | 2 ++ target/arm/helper.c | 11 +++++--- target/arm/internals.h | 6 ----- target/arm/tcg/cpu64.c | 1 + target/arm/tcg/mte_helper.c | 46 ++++++++++++++++++++++------------ target/arm/tcg/translate-a64.c | 5 ++-- target/arm/tcg/translate.h | 2 ++ 7 files changed, 45 insertions(+), 28 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index a1e604366b..278cc135c2 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -1075,6 +1075,8 @@ struct ArchCPU { /* DCZ blocksize, in log_2(words), ie low 4 bits of DCZID_EL0 */ uint8_t dcz_blocksize; + /* GM blocksize, in log_2(words), ie low 4 bits of GMID_EL0 */ + uint8_t gm_blocksize; uint64_t rvbar_prop; /* Property/input signals. */ diff --git a/target/arm/helper.c b/target/arm/helper.c index 85291d5b8e..4dfc51de35 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -7748,10 +7748,6 @@ static const ARMCPRegInfo mte_reginfo[] = { .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 6, .access = PL1_RW, .accessfn = access_mte, .fieldoffset = offsetof(CPUARMState, cp15.gcr_el1) }, - { .name = "GMID_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 1, .crn = 0, .crm = 0, .opc2 = 4, - .access = PL1_R, .accessfn = access_aa64_tid5, - .type = ARM_CP_CONST, .resetvalue = GMID_EL1_BS }, { .name = "TCO", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 4, .crm = 2, .opc2 = 7, .type = ARM_CP_NO_RAW, @@ -9342,6 +9338,13 @@ void register_cp_regs_for_features(ARMCPU *cpu) * then define only a RAZ/WI version of PSTATE.TCO. */ if (cpu_isar_feature(aa64_mte, cpu)) { + ARMCPRegInfo gmid_reginfo = { + .name = "GMID_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 1, .crn = 0, .crm = 0, .opc2 = 4, + .access = PL1_R, .accessfn = access_aa64_tid5, + .type = ARM_CP_CONST, .resetvalue = cpu->gm_blocksize, + }; + define_one_arm_cp_reg(cpu, &gmid_reginfo); define_arm_cp_regs(cpu, mte_reginfo); define_arm_cp_regs(cpu, mte_el0_cacheop_reginfo); } else if (cpu_isar_feature(aa64_mte_insn_reg, cpu)) { diff --git a/target/arm/internals.h b/target/arm/internals.h index cf13bb94f5..5f5393b25c 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1246,12 +1246,6 @@ void arm_log_exception(CPUState *cs); #endif /* !CONFIG_USER_ONLY */ -/* - * The log2 of the words in the tag block, for GMID_EL1.BS. - * The is the maximum, 256 bytes, which manipulates 64-bits of tags. - */ -#define GMID_EL1_BS 6 - /* * SVE predicates are 1/8 the size of SVE vectors, and cannot use * the same simd_desc() encoding due to restrictions on size. diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c index 8019f00bc3..4cd73779c8 100644 --- a/target/arm/tcg/cpu64.c +++ b/target/arm/tcg/cpu64.c @@ -868,6 +868,7 @@ void aarch64_max_tcg_initfn(Object *obj) cpu->ctr = 0x80038003; /* 32 byte I and D cacheline size, VIPT icache */ cpu->dcz_blocksize = 7; /* 512 bytes */ #endif + cpu->gm_blocksize = 6; /* 256 bytes */ cpu->sve_vq.supported = MAKE_64BIT_MASK(0, ARM_MAX_VQ); cpu->sme_vq.supported = SVE_VQ_POW2_MAP; diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c index 9c64def081..3640c6e57f 100644 --- a/target/arm/tcg/mte_helper.c +++ b/target/arm/tcg/mte_helper.c @@ -421,46 +421,54 @@ void HELPER(st2g_stub)(CPUARMState *env, uint64_t ptr) } } -#define LDGM_STGM_SIZE (4 << GMID_EL1_BS) - uint64_t HELPER(ldgm)(CPUARMState *env, uint64_t ptr) { int mmu_idx = cpu_mmu_index(env, false); uintptr_t ra = GETPC(); + int gm_bs = env_archcpu(env)->gm_blocksize; + int gm_bs_bytes = 4 << gm_bs; void *tag_mem; - ptr = QEMU_ALIGN_DOWN(ptr, LDGM_STGM_SIZE); + ptr = QEMU_ALIGN_DOWN(ptr, gm_bs_bytes); /* Trap if accessing an invalid page. */ tag_mem = allocation_tag_mem(env, mmu_idx, ptr, MMU_DATA_LOAD, - LDGM_STGM_SIZE, MMU_DATA_LOAD, - LDGM_STGM_SIZE / (2 * TAG_GRANULE), ra); + gm_bs_bytes, MMU_DATA_LOAD, + gm_bs_bytes / (2 * TAG_GRANULE), ra); /* The tag is squashed to zero if the page does not support tags. */ if (!tag_mem) { return 0; } - QEMU_BUILD_BUG_ON(GMID_EL1_BS != 6); /* - * We are loading 64-bits worth of tags. The ordering of elements - * within the word corresponds to a 64-bit little-endian operation. + * The ordering of elements within the word corresponds to + * a little-endian operation. */ - return ldq_le_p(tag_mem); + switch (gm_bs) { + case 6: + /* 256 bytes -> 16 tags -> 64 result bits */ + return ldq_le_p(tag_mem); + default: + /* cpu configured with unsupported gm blocksize. */ + g_assert_not_reached(); + } } void HELPER(stgm)(CPUARMState *env, uint64_t ptr, uint64_t val) { int mmu_idx = cpu_mmu_index(env, false); uintptr_t ra = GETPC(); + int gm_bs = env_archcpu(env)->gm_blocksize; + int gm_bs_bytes = 4 << gm_bs; void *tag_mem; - ptr = QEMU_ALIGN_DOWN(ptr, LDGM_STGM_SIZE); + ptr = QEMU_ALIGN_DOWN(ptr, gm_bs_bytes); /* Trap if accessing an invalid page. */ tag_mem = allocation_tag_mem(env, mmu_idx, ptr, MMU_DATA_STORE, - LDGM_STGM_SIZE, MMU_DATA_LOAD, - LDGM_STGM_SIZE / (2 * TAG_GRANULE), ra); + gm_bs_bytes, MMU_DATA_LOAD, + gm_bs_bytes / (2 * TAG_GRANULE), ra); /* * Tag store only happens if the page support tags, @@ -470,12 +478,18 @@ void HELPER(stgm)(CPUARMState *env, uint64_t ptr, uint64_t val) return; } - QEMU_BUILD_BUG_ON(GMID_EL1_BS != 6); /* - * We are storing 64-bits worth of tags. The ordering of elements - * within the word corresponds to a 64-bit little-endian operation. + * The ordering of elements within the word corresponds to + * a little-endian operation. */ - stq_le_p(tag_mem, val); + switch (gm_bs) { + case 6: + stq_le_p(tag_mem, val); + break; + default: + /* cpu configured with unsupported gm blocksize. */ + g_assert_not_reached(); + } } void HELPER(stzgm_tags)(CPUARMState *env, uint64_t ptr, uint64_t val) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index da686cc953..0b77c92437 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -3786,7 +3786,7 @@ static bool trans_STGM(DisasContext *s, arg_ldst_tag *a) gen_helper_stgm(cpu_env, addr, tcg_rt); } else { MMUAccessType acc = MMU_DATA_STORE; - int size = 4 << GMID_EL1_BS; + int size = 4 << s->gm_blocksize; clean_addr = clean_data_tbi(s, addr); tcg_gen_andi_i64(clean_addr, clean_addr, -size); @@ -3818,7 +3818,7 @@ static bool trans_LDGM(DisasContext *s, arg_ldst_tag *a) gen_helper_ldgm(tcg_rt, cpu_env, addr); } else { MMUAccessType acc = MMU_DATA_LOAD; - int size = 4 << GMID_EL1_BS; + int size = 4 << s->gm_blocksize; clean_addr = clean_data_tbi(s, addr); tcg_gen_andi_i64(clean_addr, clean_addr, -size); @@ -13896,6 +13896,7 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase, dc->cp_regs = arm_cpu->cp_regs; dc->features = env->features; dc->dcz_blocksize = arm_cpu->dcz_blocksize; + dc->gm_blocksize = arm_cpu->gm_blocksize; #ifdef CONFIG_USER_ONLY /* In sve_probe_page, we assume TBI is enabled. */ diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h index d1cacff0b2..f748ba6f39 100644 --- a/target/arm/tcg/translate.h +++ b/target/arm/tcg/translate.h @@ -151,6 +151,8 @@ typedef struct DisasContext { int8_t btype; /* A copy of cpu->dcz_blocksize. */ uint8_t dcz_blocksize; + /* A copy of cpu->gm_blocksize. */ + uint8_t gm_blocksize; /* True if this page is guarded. */ bool guarded_page; /* Bottom two bits of XScale c15_cpar coprocessor access control reg */ From 7134cb07b749b669c25526c044b19204686f4663 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 31 Aug 2023 09:45:14 +0100 Subject: [PATCH 1332/1353] target/arm: Support more GM blocksizes Support all of the easy GM block sizes. Use direct memory operations, since the pointers are aligned. While BS=2 (16 bytes, 1 tag) is a legal setting, that requires an atomic store of one nibble. This is not difficult, but there is also no point in supporting it until required. Note that cortex-a710 sets GM blocksize to match its cacheline size of 64 bytes. I expect many implementations will also match the cacheline, which makes 16 bytes very unlikely. Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20230811214031.171020-4-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.c | 18 +++++++++--- target/arm/tcg/mte_helper.c | 56 +++++++++++++++++++++++++++++++------ 2 files changed, 62 insertions(+), 12 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index d906d2b1ca..fe73fd8af7 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -2056,16 +2056,26 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) ID_PFR1, VIRTUALIZATION, 0); } + if (cpu_isar_feature(aa64_mte, cpu)) { + /* + * The architectural range of GM blocksize is 2-6, however qemu + * doesn't support blocksize of 2 (see HELPER(ldgm)). + */ + if (tcg_enabled()) { + assert(cpu->gm_blocksize >= 3 && cpu->gm_blocksize <= 6); + } + #ifndef CONFIG_USER_ONLY - if (cpu->tag_memory == NULL && cpu_isar_feature(aa64_mte, cpu)) { /* * Disable the MTE feature bits if we do not have tag-memory * provided by the machine. */ - cpu->isar.id_aa64pfr1 = - FIELD_DP64(cpu->isar.id_aa64pfr1, ID_AA64PFR1, MTE, 0); - } + if (cpu->tag_memory == NULL) { + cpu->isar.id_aa64pfr1 = + FIELD_DP64(cpu->isar.id_aa64pfr1, ID_AA64PFR1, MTE, 0); + } #endif + } if (tcg_enabled()) { /* diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c index 3640c6e57f..b23d11563a 100644 --- a/target/arm/tcg/mte_helper.c +++ b/target/arm/tcg/mte_helper.c @@ -428,6 +428,8 @@ uint64_t HELPER(ldgm)(CPUARMState *env, uint64_t ptr) int gm_bs = env_archcpu(env)->gm_blocksize; int gm_bs_bytes = 4 << gm_bs; void *tag_mem; + uint64_t ret; + int shift; ptr = QEMU_ALIGN_DOWN(ptr, gm_bs_bytes); @@ -443,16 +445,41 @@ uint64_t HELPER(ldgm)(CPUARMState *env, uint64_t ptr) /* * The ordering of elements within the word corresponds to - * a little-endian operation. + * a little-endian operation. Computation of shift comes from + * + * index = address + * data = tag + * + * Because of the alignment of ptr above, BS=6 has shift=0. + * All memory operations are aligned. Defer support for BS=2, + * requiring insertion or extraction of a nibble, until we + * support a cpu that requires it. */ switch (gm_bs) { + case 3: + /* 32 bytes -> 2 tags -> 8 result bits */ + ret = *(uint8_t *)tag_mem; + break; + case 4: + /* 64 bytes -> 4 tags -> 16 result bits */ + ret = cpu_to_le16(*(uint16_t *)tag_mem); + break; + case 5: + /* 128 bytes -> 8 tags -> 32 result bits */ + ret = cpu_to_le32(*(uint32_t *)tag_mem); + break; case 6: /* 256 bytes -> 16 tags -> 64 result bits */ - return ldq_le_p(tag_mem); + return cpu_to_le64(*(uint64_t *)tag_mem); default: - /* cpu configured with unsupported gm blocksize. */ + /* + * CPU configured with unsupported/invalid gm blocksize. + * This is detected early in arm_cpu_realizefn. + */ g_assert_not_reached(); } + shift = extract64(ptr, LOG2_TAG_GRANULE, 4) * 4; + return ret << shift; } void HELPER(stgm)(CPUARMState *env, uint64_t ptr, uint64_t val) @@ -462,6 +489,7 @@ void HELPER(stgm)(CPUARMState *env, uint64_t ptr, uint64_t val) int gm_bs = env_archcpu(env)->gm_blocksize; int gm_bs_bytes = 4 << gm_bs; void *tag_mem; + int shift; ptr = QEMU_ALIGN_DOWN(ptr, gm_bs_bytes); @@ -478,13 +506,25 @@ void HELPER(stgm)(CPUARMState *env, uint64_t ptr, uint64_t val) return; } - /* - * The ordering of elements within the word corresponds to - * a little-endian operation. - */ + /* See LDGM for comments on BS and on shift. */ + shift = extract64(ptr, LOG2_TAG_GRANULE, 4) * 4; + val >>= shift; switch (gm_bs) { + case 3: + /* 32 bytes -> 2 tags -> 8 result bits */ + *(uint8_t *)tag_mem = val; + break; + case 4: + /* 64 bytes -> 4 tags -> 16 result bits */ + *(uint16_t *)tag_mem = cpu_to_le16(val); + break; + case 5: + /* 128 bytes -> 8 tags -> 32 result bits */ + *(uint32_t *)tag_mem = cpu_to_le32(val); + break; case 6: - stq_le_p(tag_mem, val); + /* 256 bytes -> 16 tags -> 64 result bits */ + *(uint64_t *)tag_mem = cpu_to_le64(val); break; default: /* cpu configured with unsupported gm blocksize. */ From cd305b5f311d6ecea6cf487f3ec78b84bcd60d63 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 31 Aug 2023 09:45:15 +0100 Subject: [PATCH 1333/1353] target/arm: When tag memory is not present, set MTE=1 When the cpu support MTE, but the system does not, reduce cpu support to user instructions at EL0 instead of completely disabling MTE. If we encounter a cpu implementation which does something else, we can revisit this setting. Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20230811214031.171020-5-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index fe73fd8af7..23901121ac 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -2067,12 +2067,13 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) #ifndef CONFIG_USER_ONLY /* - * Disable the MTE feature bits if we do not have tag-memory - * provided by the machine. + * If we do not have tag-memory provided by the machine, + * reduce MTE support to instructions enabled at EL0. + * This matches Cortex-A710 BROADCASTMTE input being LOW. */ if (cpu->tag_memory == NULL) { cpu->isar.id_aa64pfr1 = - FIELD_DP64(cpu->isar.id_aa64pfr1, ID_AA64PFR1, MTE, 0); + FIELD_DP64(cpu->isar.id_aa64pfr1, ID_AA64PFR1, MTE, 1); } #endif } From d8100822d6988cf7837aa780eaa24de6752b1c59 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 31 Aug 2023 09:45:15 +0100 Subject: [PATCH 1334/1353] target/arm: Introduce make_ccsidr64 Do not hard-code the constants for Neoverse V1. Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20230811214031.171020-6-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/tcg/cpu64.c | 48 ++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c index 4cd73779c8..00f39d42a8 100644 --- a/target/arm/tcg/cpu64.c +++ b/target/arm/tcg/cpu64.c @@ -24,9 +24,36 @@ #include "qemu/module.h" #include "qapi/visitor.h" #include "hw/qdev-properties.h" +#include "qemu/units.h" #include "internals.h" #include "cpregs.h" +static uint64_t make_ccsidr64(unsigned assoc, unsigned linesize, + unsigned cachesize) +{ + unsigned lg_linesize = ctz32(linesize); + unsigned sets; + + /* + * The 64-bit CCSIDR_EL1 format is: + * [55:32] number of sets - 1 + * [23:3] associativity - 1 + * [2:0] log2(linesize) - 4 + * so 0 == 16 bytes, 1 == 32 bytes, 2 == 64 bytes, etc + */ + assert(assoc != 0); + assert(is_power_of_2(linesize)); + assert(lg_linesize >= 4 && lg_linesize <= 7 + 4); + + /* sets * associativity * linesize == cachesize. */ + sets = cachesize / (assoc * linesize); + assert(cachesize % (assoc * linesize) == 0); + + return ((uint64_t)(sets - 1) << 32) + | ((assoc - 1) << 3) + | (lg_linesize - 4); +} + static void aarch64_a35_initfn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); @@ -651,26 +678,15 @@ static void aarch64_neoverse_v1_initfn(Object *obj) * The Neoverse-V1 r1p2 TRM lists 32-bit format CCSIDR_EL1 values, * but also says it implements CCIDX, which means they should be * 64-bit format. So we here use values which are based on the textual - * information in chapter 2 of the TRM (and on the fact that - * sets * associativity * linesize == cachesize). - * - * The 64-bit CCSIDR_EL1 format is: - * [55:32] number of sets - 1 - * [23:3] associativity - 1 - * [2:0] log2(linesize) - 4 - * so 0 == 16 bytes, 1 == 32 bytes, 2 == 64 bytes, etc - * - * L1: 4-way set associative 64-byte line size, total size 64K, - * so sets is 256. + * information in chapter 2 of the TRM: * + * L1: 4-way set associative 64-byte line size, total size 64K. * L2: 8-way set associative, 64 byte line size, either 512K or 1MB. - * We pick 1MB, so this has 2048 sets. - * * L3: No L3 (this matches the CLIDR_EL1 value). */ - cpu->ccsidr[0] = 0x000000ff0000001aull; /* 64KB L1 dcache */ - cpu->ccsidr[1] = 0x000000ff0000001aull; /* 64KB L1 icache */ - cpu->ccsidr[2] = 0x000007ff0000003aull; /* 1MB L2 cache */ + cpu->ccsidr[0] = make_ccsidr64(4, 64, 64 * KiB); /* L1 dcache */ + cpu->ccsidr[1] = cpu->ccsidr[0]; /* L1 icache */ + cpu->ccsidr[2] = make_ccsidr64(8, 64, 1 * MiB); /* L2 cache */ /* From 3.2.115 SCTLR_EL3 */ cpu->reset_sctlr = 0x30c50838; From 6d482423fcecb34056013268fa552b1ce2efcfeb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 31 Aug 2023 09:45:15 +0100 Subject: [PATCH 1335/1353] target/arm: Apply access checks to neoverse-n1 special registers Access to many of the special registers is enabled or disabled by ACTLR_EL[23], which we implement as constant 0, which means that all writes outside EL3 should trap. Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20230811214031.171020-7-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpregs.h | 2 ++ target/arm/helper.c | 4 ++-- target/arm/tcg/cpu64.c | 46 +++++++++++++++++++++++++++++++++--------- 3 files changed, 41 insertions(+), 11 deletions(-) diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h index 14785686f6..f1293d16c0 100644 --- a/target/arm/cpregs.h +++ b/target/arm/cpregs.h @@ -1077,4 +1077,6 @@ static inline void define_cortex_a72_a57_a53_cp_reginfo(ARMCPU *cpu) { } void define_cortex_a72_a57_a53_cp_reginfo(ARMCPU *cpu); #endif +CPAccessResult access_tvm_trvm(CPUARMState *, const ARMCPRegInfo *, bool); + #endif /* TARGET_ARM_CPREGS_H */ diff --git a/target/arm/helper.c b/target/arm/helper.c index 4dfc51de35..e3f5a7d2bd 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -319,8 +319,8 @@ static CPAccessResult access_tpm(CPUARMState *env, const ARMCPRegInfo *ri, } /* Check for traps from EL1 due to HCR_EL2.TVM and HCR_EL2.TRVM. */ -static CPAccessResult access_tvm_trvm(CPUARMState *env, const ARMCPRegInfo *ri, - bool isread) +CPAccessResult access_tvm_trvm(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) { if (arm_current_el(env) == 1) { uint64_t trap = isread ? HCR_TRVM : HCR_TVM; diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c index 00f39d42a8..bc3db798f0 100644 --- a/target/arm/tcg/cpu64.c +++ b/target/arm/tcg/cpu64.c @@ -463,10 +463,30 @@ static void aarch64_a64fx_initfn(Object *obj) /* TODO: Add A64FX specific HPC extension registers */ } +static CPAccessResult access_actlr_w(CPUARMState *env, const ARMCPRegInfo *r, + bool read) +{ + if (!read) { + int el = arm_current_el(env); + + /* Because ACTLR_EL2 is constant 0, writes below EL2 trap to EL2. */ + if (el < 2 && arm_is_el2_enabled(env)) { + return CP_ACCESS_TRAP_EL2; + } + /* Because ACTLR_EL3 is constant 0, writes below EL3 trap to EL3. */ + if (el < 3 && arm_feature(env, ARM_FEATURE_EL3)) { + return CP_ACCESS_TRAP_EL3; + } + } + return CP_ACCESS_OK; +} + static const ARMCPRegInfo neoverse_n1_cp_reginfo[] = { { .name = "ATCR_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 15, .crm = 7, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0, + /* Traps and enables are the same as for TCR_EL1. */ + .accessfn = access_tvm_trvm, .fgt = FGT_TCR_EL1, }, { .name = "ATCR_EL2", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 4, .crn = 15, .crm = 7, .opc2 = 0, .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, @@ -481,13 +501,16 @@ static const ARMCPRegInfo neoverse_n1_cp_reginfo[] = { .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, { .name = "CPUACTLR_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 15, .crm = 1, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0, + .accessfn = access_actlr_w }, { .name = "CPUACTLR2_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 15, .crm = 1, .opc2 = 1, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0, + .accessfn = access_actlr_w }, { .name = "CPUACTLR3_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 15, .crm = 1, .opc2 = 2, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0, + .accessfn = access_actlr_w }, /* * Report CPUCFR_EL1.SCU as 1, as we do not implement the DSU * (and in particular its system registers). @@ -497,7 +520,8 @@ static const ARMCPRegInfo neoverse_n1_cp_reginfo[] = { .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 4 }, { .name = "CPUECTLR_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 15, .crm = 1, .opc2 = 4, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0x961563010 }, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0x961563010, + .accessfn = access_actlr_w }, { .name = "CPUPCR_EL3", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 6, .crn = 15, .crm = 8, .opc2 = 1, .access = PL3_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, @@ -512,16 +536,20 @@ static const ARMCPRegInfo neoverse_n1_cp_reginfo[] = { .access = PL3_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, { .name = "CPUPWRCTLR_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 15, .crm = 2, .opc2 = 7, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0, + .accessfn = access_actlr_w }, { .name = "ERXPFGCDN_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 15, .crm = 2, .opc2 = 2, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0, + .accessfn = access_actlr_w }, { .name = "ERXPFGCTL_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 15, .crm = 2, .opc2 = 1, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0, + .accessfn = access_actlr_w }, { .name = "ERXPFGF_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 15, .crm = 2, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0, + .accessfn = access_actlr_w }, }; static void define_neoverse_n1_cp_reginfo(ARMCPU *cpu) From 87da10b45ce50b55c0306862a511c77243b1b065 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 31 Aug 2023 09:45:15 +0100 Subject: [PATCH 1336/1353] target/arm: Apply access checks to neoverse-v1 special registers There is only one additional EL1 register modeled, which also needs to use access_actlr_w. Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20230811214031.171020-8-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/tcg/cpu64.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c index bc3db798f0..b0cac05be6 100644 --- a/target/arm/tcg/cpu64.c +++ b/target/arm/tcg/cpu64.c @@ -560,7 +560,8 @@ static void define_neoverse_n1_cp_reginfo(ARMCPU *cpu) static const ARMCPRegInfo neoverse_v1_cp_reginfo[] = { { .name = "CPUECTLR2_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 15, .crm = 1, .opc2 = 5, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0, + .accessfn = access_actlr_w }, { .name = "CPUPPMCR_EL3", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 6, .crn = 15, .crm = 2, .opc2 = 0, .access = PL3_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, From 3d5f45ec895b278bfc442a436eebefab598f416a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 31 Aug 2023 09:45:16 +0100 Subject: [PATCH 1337/1353] target/arm: Suppress FEAT_TRBE (Trace Buffer Extension) Like FEAT_TRF (Self-hosted Trace Extension), suppress tracing external to the cpu, which is out of scope for QEMU. Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20230811214031.171020-10-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 23901121ac..17540300fe 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -2088,6 +2088,9 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) /* FEAT_SPE (Statistical Profiling Extension) */ cpu->isar.id_aa64dfr0 = FIELD_DP64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, PMSVER, 0); + /* FEAT_TRBE (Trace Buffer Extension) */ + cpu->isar.id_aa64dfr0 = + FIELD_DP64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, TRACEBUFFER, 0); /* FEAT_TRF (Self-hosted Trace Extension) */ cpu->isar.id_aa64dfr0 = FIELD_DP64(cpu->isar.id_aa64dfr0, ID_AA64DFR0, TRACEFILT, 0); From df9a391757c7fc5a6c88f6d32b82d6f2f860bd1d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 31 Aug 2023 09:45:16 +0100 Subject: [PATCH 1338/1353] target/arm: Implement FEAT_HPDS2 as a no-op This feature allows the operating system to set TCR_ELx.HWU* to allow the implementation to use the PBHA bits from the block and page descriptors for for IMPLEMENTATION DEFINED purposes. Since QEMU has no need to use these bits, we may simply ignore them. Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20230811214031.171020-11-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- docs/system/arm/emulation.rst | 1 + target/arm/tcg/cpu32.c | 2 +- target/arm/tcg/cpu64.c | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index bdafc68819..2012bbf7c7 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -40,6 +40,7 @@ the following architecture extensions: - FEAT_HAFDBS (Hardware management of the access flag and dirty bit state) - FEAT_HCX (Support for the HCRX_EL2 register) - FEAT_HPDS (Hierarchical permission disables) +- FEAT_HPDS2 (Translation table page-based hardware attributes) - FEAT_I8MM (AArch64 Int8 matrix multiplication instructions) - FEAT_IDST (ID space trap handling) - FEAT_IESB (Implicit error synchronization event) diff --git a/target/arm/tcg/cpu32.c b/target/arm/tcg/cpu32.c index 47d2e8e781..1f918ff537 100644 --- a/target/arm/tcg/cpu32.c +++ b/target/arm/tcg/cpu32.c @@ -62,7 +62,7 @@ void aa32_max_features(ARMCPU *cpu) cpu->isar.id_mmfr3 = t; t = cpu->isar.id_mmfr4; - t = FIELD_DP32(t, ID_MMFR4, HPDS, 1); /* FEAT_AA32HPD */ + t = FIELD_DP32(t, ID_MMFR4, HPDS, 2); /* FEAT_HPDS2 */ t = FIELD_DP32(t, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */ t = FIELD_DP32(t, ID_MMFR4, CNP, 1); /* FEAT_TTCNP */ t = FIELD_DP32(t, ID_MMFR4, XNX, 1); /* FEAT_XNX */ diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c index b0cac05be6..11e406d960 100644 --- a/target/arm/tcg/cpu64.c +++ b/target/arm/tcg/cpu64.c @@ -852,7 +852,7 @@ void aarch64_max_tcg_initfn(Object *obj) t = FIELD_DP64(t, ID_AA64MMFR1, HAFDBS, 2); /* FEAT_HAFDBS */ t = FIELD_DP64(t, ID_AA64MMFR1, VMIDBITS, 2); /* FEAT_VMID16 */ t = FIELD_DP64(t, ID_AA64MMFR1, VH, 1); /* FEAT_VHE */ - t = FIELD_DP64(t, ID_AA64MMFR1, HPDS, 1); /* FEAT_HPDS */ + t = FIELD_DP64(t, ID_AA64MMFR1, HPDS, 2); /* FEAT_HPDS2 */ t = FIELD_DP64(t, ID_AA64MMFR1, LO, 1); /* FEAT_LOR */ t = FIELD_DP64(t, ID_AA64MMFR1, PAN, 3); /* FEAT_PAN3 */ t = FIELD_DP64(t, ID_AA64MMFR1, XNX, 1); /* FEAT_XNX */ From 9e771a2fc68d98c5719b877e008d1dca64e6896e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Thu, 31 Aug 2023 09:45:16 +0100 Subject: [PATCH 1339/1353] target/arm: properly document FEAT_CRC32 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a mandatory feature for Armv8.1 architectures but we don't state the feature clearly in our emulation list. Also include FEAT_CRC32 comment in aarch64_max_tcg_initfn for ease of grepping. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Alex Bennée Message-id: 20230824075406.1515566-1-alex.bennee@linaro.org Cc: qemu-stable@nongnu.org Message-Id: <20230222110104.3996971-1-alex.bennee@linaro.org> [PMM: pluralize 'instructions' in docs] Signed-off-by: Peter Maydell --- docs/system/arm/emulation.rst | 1 + target/arm/tcg/cpu64.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index 2012bbf7c7..2e6a7c8961 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -14,6 +14,7 @@ the following architecture extensions: - FEAT_BBM at level 2 (Translation table break-before-make levels) - FEAT_BF16 (AArch64 BFloat16 instructions) - FEAT_BTI (Branch Target Identification) +- FEAT_CRC32 (CRC32 instructions) - FEAT_CSV2 (Cache speculation variant 2) - FEAT_CSV2_1p1 (Cache speculation variant 2, version 1.1) - FEAT_CSV2_1p2 (Cache speculation variant 2, version 1.2) diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c index 11e406d960..0f8972950d 100644 --- a/target/arm/tcg/cpu64.c +++ b/target/arm/tcg/cpu64.c @@ -788,7 +788,7 @@ void aarch64_max_tcg_initfn(Object *obj) t = FIELD_DP64(t, ID_AA64ISAR0, AES, 2); /* FEAT_PMULL */ t = FIELD_DP64(t, ID_AA64ISAR0, SHA1, 1); /* FEAT_SHA1 */ t = FIELD_DP64(t, ID_AA64ISAR0, SHA2, 2); /* FEAT_SHA512 */ - t = FIELD_DP64(t, ID_AA64ISAR0, CRC32, 1); + t = FIELD_DP64(t, ID_AA64ISAR0, CRC32, 1); /* FEAT_CRC32 */ t = FIELD_DP64(t, ID_AA64ISAR0, ATOMIC, 2); /* FEAT_LSE */ t = FIELD_DP64(t, ID_AA64ISAR0, RDM, 1); /* FEAT_RDM */ t = FIELD_DP64(t, ID_AA64ISAR0, SHA3, 1); /* FEAT_SHA3 */ From 6f97cfd8e0e081c9f5e4ee27984b239912b911b9 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Dubois Date: Thu, 31 Aug 2023 09:45:16 +0100 Subject: [PATCH 1340/1353] Remove i.MX7 IOMUX GPR device from i.MX6UL i.MX7 IOMUX GPR device is not equivalent to i.MX6UL IOMUXC GPR device. In particular, register 22 is not present on i.MX6UL and this is actualy The only register that is really emulated in the i.MX7 IOMUX GPR device. Note: The i.MX6UL code is actually also implementing the IOMUX GPR device as an unimplemented device at the same bus adress and the 2 instantiations were actualy colliding. So we go back to the unimplemented device for now. Signed-off-by: Jean-Christophe Dubois Message-id: 48681bf51ee97646479bb261bee19abebbc8074e.1692964892.git.jcd@tribudubois.net Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/fsl-imx6ul.c | 11 ----------- include/hw/arm/fsl-imx6ul.h | 2 -- 2 files changed, 13 deletions(-) diff --git a/hw/arm/fsl-imx6ul.c b/hw/arm/fsl-imx6ul.c index 2189dcbb72..0fdd2782ba 100644 --- a/hw/arm/fsl-imx6ul.c +++ b/hw/arm/fsl-imx6ul.c @@ -63,11 +63,6 @@ static void fsl_imx6ul_init(Object *obj) */ object_initialize_child(obj, "snvs", &s->snvs, TYPE_IMX7_SNVS); - /* - * GPR - */ - object_initialize_child(obj, "gpr", &s->gpr, TYPE_IMX7_GPR); - /* * GPIOs 1 to 5 */ @@ -537,12 +532,6 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) FSL_IMX6UL_WDOGn_IRQ[i])); } - /* - * GPR - */ - sysbus_realize(SYS_BUS_DEVICE(&s->gpr), &error_abort); - sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpr), 0, FSL_IMX6UL_IOMUXC_GPR_ADDR); - /* * SDMA */ diff --git a/include/hw/arm/fsl-imx6ul.h b/include/hw/arm/fsl-imx6ul.h index 9ee15ae38d..3bec6bb3fb 100644 --- a/include/hw/arm/fsl-imx6ul.h +++ b/include/hw/arm/fsl-imx6ul.h @@ -22,7 +22,6 @@ #include "hw/misc/imx6ul_ccm.h" #include "hw/misc/imx6_src.h" #include "hw/misc/imx7_snvs.h" -#include "hw/misc/imx7_gpr.h" #include "hw/intc/imx_gpcv2.h" #include "hw/watchdog/wdt_imx2.h" #include "hw/gpio/imx_gpio.h" @@ -74,7 +73,6 @@ struct FslIMX6ULState { IMX6SRCState src; IMX7SNVSState snvs; IMXGPCv2State gpcv2; - IMX7GPRState gpr; IMXSPIState spi[FSL_IMX6UL_NUM_ECSPIS]; IMXI2CState i2c[FSL_IMX6UL_NUM_I2CS]; IMXSerialState uart[FSL_IMX6UL_NUM_UARTS]; From 0cd4926b855c491c88facaa0abeaf910f7d6ff01 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Dubois Date: Thu, 31 Aug 2023 09:45:16 +0100 Subject: [PATCH 1341/1353] Refactor i.MX6UL processor code * Add Addr and size definition for most i.MX6UL devices in i.MX6UL header file. * Use those newly defined named constants whenever possible. * Standardize the way we init a familly of unimplemented devices - SAI - PWM - CAN * Add/rework few comments Signed-off-by: Jean-Christophe Dubois Message-id: d579043fbd4e4b490370783fda43fc02c8e9be75.1692964892.git.jcd@tribudubois.net Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/fsl-imx6ul.c | 147 ++++++++++++++++++++++----------- include/hw/arm/fsl-imx6ul.h | 156 +++++++++++++++++++++++++++++++----- 2 files changed, 232 insertions(+), 71 deletions(-) diff --git a/hw/arm/fsl-imx6ul.c b/hw/arm/fsl-imx6ul.c index 0fdd2782ba..06a32aff64 100644 --- a/hw/arm/fsl-imx6ul.c +++ b/hw/arm/fsl-imx6ul.c @@ -64,7 +64,7 @@ static void fsl_imx6ul_init(Object *obj) object_initialize_child(obj, "snvs", &s->snvs, TYPE_IMX7_SNVS); /* - * GPIOs 1 to 5 + * GPIOs */ for (i = 0; i < FSL_IMX6UL_NUM_GPIOS; i++) { snprintf(name, NAME_SIZE, "gpio%d", i); @@ -72,7 +72,7 @@ static void fsl_imx6ul_init(Object *obj) } /* - * GPT 1, 2 + * GPTs */ for (i = 0; i < FSL_IMX6UL_NUM_GPTS; i++) { snprintf(name, NAME_SIZE, "gpt%d", i); @@ -80,7 +80,7 @@ static void fsl_imx6ul_init(Object *obj) } /* - * EPIT 1, 2 + * EPITs */ for (i = 0; i < FSL_IMX6UL_NUM_EPITS; i++) { snprintf(name, NAME_SIZE, "epit%d", i + 1); @@ -88,7 +88,7 @@ static void fsl_imx6ul_init(Object *obj) } /* - * eCSPI + * eCSPIs */ for (i = 0; i < FSL_IMX6UL_NUM_ECSPIS; i++) { snprintf(name, NAME_SIZE, "spi%d", i + 1); @@ -96,7 +96,7 @@ static void fsl_imx6ul_init(Object *obj) } /* - * I2C + * I2Cs */ for (i = 0; i < FSL_IMX6UL_NUM_I2CS; i++) { snprintf(name, NAME_SIZE, "i2c%d", i + 1); @@ -104,7 +104,7 @@ static void fsl_imx6ul_init(Object *obj) } /* - * UART + * UARTs */ for (i = 0; i < FSL_IMX6UL_NUM_UARTS; i++) { snprintf(name, NAME_SIZE, "uart%d", i); @@ -112,25 +112,31 @@ static void fsl_imx6ul_init(Object *obj) } /* - * Ethernet + * Ethernets */ for (i = 0; i < FSL_IMX6UL_NUM_ETHS; i++) { snprintf(name, NAME_SIZE, "eth%d", i); object_initialize_child(obj, name, &s->eth[i], TYPE_IMX_ENET); } - /* USB */ + /* + * USB PHYs + */ for (i = 0; i < FSL_IMX6UL_NUM_USB_PHYS; i++) { snprintf(name, NAME_SIZE, "usbphy%d", i); object_initialize_child(obj, name, &s->usbphy[i], TYPE_IMX_USBPHY); } + + /* + * USBs + */ for (i = 0; i < FSL_IMX6UL_NUM_USBS; i++) { snprintf(name, NAME_SIZE, "usb%d", i); object_initialize_child(obj, name, &s->usb[i], TYPE_CHIPIDEA); } /* - * SDHCI + * SDHCIs */ for (i = 0; i < FSL_IMX6UL_NUM_USDHCS; i++) { snprintf(name, NAME_SIZE, "usdhc%d", i); @@ -138,7 +144,7 @@ static void fsl_imx6ul_init(Object *obj) } /* - * Watchdog + * Watchdogs */ for (i = 0; i < FSL_IMX6UL_NUM_WDTS; i++) { snprintf(name, NAME_SIZE, "wdt%d", i); @@ -184,10 +190,10 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) * A7MPCORE DAP */ create_unimplemented_device("a7mpcore-dap", FSL_IMX6UL_A7MPCORE_DAP_ADDR, - 0x100000); + FSL_IMX6UL_A7MPCORE_DAP_SIZE); /* - * GPT 1, 2 + * GPTs */ for (i = 0; i < FSL_IMX6UL_NUM_GPTS; i++) { static const hwaddr FSL_IMX6UL_GPTn_ADDR[FSL_IMX6UL_NUM_GPTS] = { @@ -212,7 +218,7 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) } /* - * EPIT 1, 2 + * EPITs */ for (i = 0; i < FSL_IMX6UL_NUM_EPITS; i++) { static const hwaddr FSL_IMX6UL_EPITn_ADDR[FSL_IMX6UL_NUM_EPITS] = { @@ -237,7 +243,7 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) } /* - * GPIO + * GPIOs */ for (i = 0; i < FSL_IMX6UL_NUM_GPIOS; i++) { static const hwaddr FSL_IMX6UL_GPIOn_ADDR[FSL_IMX6UL_NUM_GPIOS] = { @@ -279,17 +285,12 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) } /* - * IOMUXC and IOMUXC_GPR + * IOMUXC */ - for (i = 0; i < 1; i++) { - static const hwaddr FSL_IMX6UL_IOMUXCn_ADDR[FSL_IMX6UL_NUM_IOMUXCS] = { - FSL_IMX6UL_IOMUXC_ADDR, - FSL_IMX6UL_IOMUXC_GPR_ADDR, - }; - - snprintf(name, NAME_SIZE, "iomuxc%d", i); - create_unimplemented_device(name, FSL_IMX6UL_IOMUXCn_ADDR[i], 0x4000); - } + create_unimplemented_device("iomuxc", FSL_IMX6UL_IOMUXC_ADDR, + FSL_IMX6UL_IOMUXC_SIZE); + create_unimplemented_device("iomuxc_gpr", FSL_IMX6UL_IOMUXC_GPR_ADDR, + FSL_IMX6UL_IOMUXC_GPR_SIZE); /* * CCM @@ -309,7 +310,9 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) sysbus_realize(SYS_BUS_DEVICE(&s->gpcv2), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpcv2), 0, FSL_IMX6UL_GPC_ADDR); - /* Initialize all ECSPI */ + /* + * ECSPIs + */ for (i = 0; i < FSL_IMX6UL_NUM_ECSPIS; i++) { static const hwaddr FSL_IMX6UL_SPIn_ADDR[FSL_IMX6UL_NUM_ECSPIS] = { FSL_IMX6UL_ECSPI1_ADDR, @@ -337,7 +340,7 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) } /* - * I2C + * I2Cs */ for (i = 0; i < FSL_IMX6UL_NUM_I2CS; i++) { static const hwaddr FSL_IMX6UL_I2Cn_ADDR[FSL_IMX6UL_NUM_I2CS] = { @@ -363,7 +366,7 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) } /* - * UART + * UARTs */ for (i = 0; i < FSL_IMX6UL_NUM_UARTS; i++) { static const hwaddr FSL_IMX6UL_UARTn_ADDR[FSL_IMX6UL_NUM_UARTS] = { @@ -401,7 +404,7 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) } /* - * Ethernet + * Ethernets * * We must use two loops since phy_connected affects the other interface * and we have to set all properties before calling sysbus_realize(). @@ -454,28 +457,45 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) FSL_IMX6UL_ENETn_TIMER_IRQ[i])); } - /* USB */ + /* + * USB PHYs + */ for (i = 0; i < FSL_IMX6UL_NUM_USB_PHYS; i++) { + static const hwaddr + FSL_IMX6UL_USB_PHYn_ADDR[FSL_IMX6UL_NUM_USB_PHYS] = { + FSL_IMX6UL_USBPHY1_ADDR, + FSL_IMX6UL_USBPHY2_ADDR, + }; + sysbus_realize(SYS_BUS_DEVICE(&s->usbphy[i]), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->usbphy[i]), 0, - FSL_IMX6UL_USBPHY1_ADDR + i * 0x1000); + FSL_IMX6UL_USB_PHYn_ADDR[i]); } + /* + * USBs + */ for (i = 0; i < FSL_IMX6UL_NUM_USBS; i++) { + static const hwaddr FSL_IMX6UL_USB02_USBn_ADDR[FSL_IMX6UL_NUM_USBS] = { + FSL_IMX6UL_USBO2_USB1_ADDR, + FSL_IMX6UL_USBO2_USB2_ADDR, + }; + static const int FSL_IMX6UL_USBn_IRQ[] = { FSL_IMX6UL_USB1_IRQ, FSL_IMX6UL_USB2_IRQ, }; + sysbus_realize(SYS_BUS_DEVICE(&s->usb[i]), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->usb[i]), 0, - FSL_IMX6UL_USBO2_USB_ADDR + i * 0x200); + FSL_IMX6UL_USB02_USBn_ADDR[i]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->usb[i]), 0, qdev_get_gpio_in(DEVICE(&s->a7mpcore), FSL_IMX6UL_USBn_IRQ[i])); } /* - * USDHC + * USDHCs */ for (i = 0; i < FSL_IMX6UL_NUM_USDHCS; i++) { static const hwaddr FSL_IMX6UL_USDHCn_ADDR[FSL_IMX6UL_NUM_USDHCS] = { @@ -507,7 +527,7 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) sysbus_mmio_map(SYS_BUS_DEVICE(&s->snvs), 0, FSL_IMX6UL_SNVS_HP_ADDR); /* - * Watchdog + * Watchdogs */ for (i = 0; i < FSL_IMX6UL_NUM_WDTS; i++) { static const hwaddr FSL_IMX6UL_WDOGn_ADDR[FSL_IMX6UL_NUM_WDTS] = { @@ -515,6 +535,7 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) FSL_IMX6UL_WDOG2_ADDR, FSL_IMX6UL_WDOG3_ADDR, }; + static const int FSL_IMX6UL_WDOGn_IRQ[FSL_IMX6UL_NUM_WDTS] = { FSL_IMX6UL_WDOG1_IRQ, FSL_IMX6UL_WDOG2_IRQ, @@ -535,33 +556,59 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) /* * SDMA */ - create_unimplemented_device("sdma", FSL_IMX6UL_SDMA_ADDR, 0x4000); + create_unimplemented_device("sdma", FSL_IMX6UL_SDMA_ADDR, + FSL_IMX6UL_SDMA_SIZE); /* - * SAI (Audio SSI (Synchronous Serial Interface)) + * SAIs (Audio SSI (Synchronous Serial Interface)) */ - create_unimplemented_device("sai1", FSL_IMX6UL_SAI1_ADDR, 0x4000); - create_unimplemented_device("sai2", FSL_IMX6UL_SAI2_ADDR, 0x4000); - create_unimplemented_device("sai3", FSL_IMX6UL_SAI3_ADDR, 0x4000); + for (i = 0; i < FSL_IMX6UL_NUM_SAIS; i++) { + static const hwaddr FSL_IMX6UL_SAIn_ADDR[FSL_IMX6UL_NUM_SAIS] = { + FSL_IMX6UL_SAI1_ADDR, + FSL_IMX6UL_SAI2_ADDR, + FSL_IMX6UL_SAI3_ADDR, + }; + + snprintf(name, NAME_SIZE, "sai%d", i); + create_unimplemented_device(name, FSL_IMX6UL_SAIn_ADDR[i], + FSL_IMX6UL_SAIn_SIZE); + } /* - * PWM + * PWMs */ - create_unimplemented_device("pwm1", FSL_IMX6UL_PWM1_ADDR, 0x4000); - create_unimplemented_device("pwm2", FSL_IMX6UL_PWM2_ADDR, 0x4000); - create_unimplemented_device("pwm3", FSL_IMX6UL_PWM3_ADDR, 0x4000); - create_unimplemented_device("pwm4", FSL_IMX6UL_PWM4_ADDR, 0x4000); + for (i = 0; i < FSL_IMX6UL_NUM_PWMS; i++) { + static const hwaddr FSL_IMX6UL_PWMn_ADDR[FSL_IMX6UL_NUM_PWMS] = { + FSL_IMX6UL_PWM1_ADDR, + FSL_IMX6UL_PWM2_ADDR, + FSL_IMX6UL_PWM3_ADDR, + FSL_IMX6UL_PWM4_ADDR, + }; + + snprintf(name, NAME_SIZE, "pwm%d", i); + create_unimplemented_device(name, FSL_IMX6UL_PWMn_ADDR[i], + FSL_IMX6UL_PWMn_SIZE); + } /* * Audio ASRC (asynchronous sample rate converter) */ - create_unimplemented_device("asrc", FSL_IMX6UL_ASRC_ADDR, 0x4000); + create_unimplemented_device("asrc", FSL_IMX6UL_ASRC_ADDR, + FSL_IMX6UL_ASRC_SIZE); /* - * CAN + * CANs */ - create_unimplemented_device("can1", FSL_IMX6UL_CAN1_ADDR, 0x4000); - create_unimplemented_device("can2", FSL_IMX6UL_CAN2_ADDR, 0x4000); + for (i = 0; i < FSL_IMX6UL_NUM_CANS; i++) { + static const hwaddr FSL_IMX6UL_CANn_ADDR[FSL_IMX6UL_NUM_CANS] = { + FSL_IMX6UL_CAN1_ADDR, + FSL_IMX6UL_CAN2_ADDR, + }; + + snprintf(name, NAME_SIZE, "can%d", i); + create_unimplemented_device(name, FSL_IMX6UL_CANn_ADDR[i], + FSL_IMX6UL_CANn_SIZE); + } /* * APHB_DMA @@ -579,13 +626,15 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) }; snprintf(name, NAME_SIZE, "adc%d", i); - create_unimplemented_device(name, FSL_IMX6UL_ADCn_ADDR[i], 0x4000); + create_unimplemented_device(name, FSL_IMX6UL_ADCn_ADDR[i], + FSL_IMX6UL_ADCn_SIZE); } /* * LCD */ - create_unimplemented_device("lcdif", FSL_IMX6UL_LCDIF_ADDR, 0x4000); + create_unimplemented_device("lcdif", FSL_IMX6UL_LCDIF_ADDR, + FSL_IMX6UL_LCDIF_SIZE); /* * ROM memory diff --git a/include/hw/arm/fsl-imx6ul.h b/include/hw/arm/fsl-imx6ul.h index 3bec6bb3fb..f7bf684b42 100644 --- a/include/hw/arm/fsl-imx6ul.h +++ b/include/hw/arm/fsl-imx6ul.h @@ -37,6 +37,7 @@ #include "exec/memory.h" #include "cpu.h" #include "qom/object.h" +#include "qemu/units.h" #define TYPE_FSL_IMX6UL "fsl-imx6ul" OBJECT_DECLARE_SIMPLE_TYPE(FslIMX6ULState, FSL_IMX6UL) @@ -57,6 +58,9 @@ enum FslIMX6ULConfiguration { FSL_IMX6UL_NUM_ADCS = 2, FSL_IMX6UL_NUM_USB_PHYS = 2, FSL_IMX6UL_NUM_USBS = 2, + FSL_IMX6UL_NUM_SAIS = 3, + FSL_IMX6UL_NUM_CANS = 2, + FSL_IMX6UL_NUM_PWMS = 4, }; struct FslIMX6ULState { @@ -92,119 +96,227 @@ struct FslIMX6ULState { enum FslIMX6ULMemoryMap { FSL_IMX6UL_MMDC_ADDR = 0x80000000, - FSL_IMX6UL_MMDC_SIZE = 2 * 1024 * 1024 * 1024UL, + FSL_IMX6UL_MMDC_SIZE = (2 * GiB), FSL_IMX6UL_QSPI1_MEM_ADDR = 0x60000000, - FSL_IMX6UL_EIM_ALIAS_ADDR = 0x58000000, - FSL_IMX6UL_EIM_CS_ADDR = 0x50000000, - FSL_IMX6UL_AES_ENCRYPT_ADDR = 0x10000000, - FSL_IMX6UL_QSPI1_RX_ADDR = 0x0C000000, + FSL_IMX6UL_QSPI1_MEM_SIZE = (256 * MiB), - /* AIPS-2 */ + FSL_IMX6UL_EIM_ALIAS_ADDR = 0x58000000, + FSL_IMX6UL_EIM_ALIAS_SIZE = (128 * MiB), + + FSL_IMX6UL_EIM_CS_ADDR = 0x50000000, + FSL_IMX6UL_EIM_CS_SIZE = (128 * MiB), + + FSL_IMX6UL_AES_ENCRYPT_ADDR = 0x10000000, + FSL_IMX6UL_AES_ENCRYPT_SIZE = (1 * MiB), + + FSL_IMX6UL_QSPI1_RX_ADDR = 0x0C000000, + FSL_IMX6UL_QSPI1_RX_SIZE = (32 * MiB), + + /* AIPS-2 Begin */ FSL_IMX6UL_UART6_ADDR = 0x021FC000, + FSL_IMX6UL_I2C4_ADDR = 0x021F8000, + FSL_IMX6UL_UART5_ADDR = 0x021F4000, FSL_IMX6UL_UART4_ADDR = 0x021F0000, FSL_IMX6UL_UART3_ADDR = 0x021EC000, FSL_IMX6UL_UART2_ADDR = 0x021E8000, + FSL_IMX6UL_WDOG3_ADDR = 0x021E4000, + FSL_IMX6UL_QSPI_ADDR = 0x021E0000, + FSL_IMX6UL_QSPI_SIZE = 0x500, + FSL_IMX6UL_SYS_CNT_CTRL_ADDR = 0x021DC000, + FSL_IMX6UL_SYS_CNT_CTRL_SIZE = (16 * KiB), + FSL_IMX6UL_SYS_CNT_CMP_ADDR = 0x021D8000, + FSL_IMX6UL_SYS_CNT_CMP_SIZE = (16 * KiB), + FSL_IMX6UL_SYS_CNT_RD_ADDR = 0x021D4000, + FSL_IMX6UL_SYS_CNT_RD_SIZE = (16 * KiB), + FSL_IMX6UL_TZASC_ADDR = 0x021D0000, + FSL_IMX6UL_TZASC_SIZE = (16 * KiB), + FSL_IMX6UL_PXP_ADDR = 0x021CC000, + FSL_IMX6UL_PXP_SIZE = (16 * KiB), + FSL_IMX6UL_LCDIF_ADDR = 0x021C8000, + FSL_IMX6UL_LCDIF_SIZE = 0x100, + FSL_IMX6UL_CSI_ADDR = 0x021C4000, + FSL_IMX6UL_CSI_SIZE = 0x100, + FSL_IMX6UL_CSU_ADDR = 0x021C0000, + FSL_IMX6UL_CSU_SIZE = (16 * KiB), + FSL_IMX6UL_OCOTP_CTRL_ADDR = 0x021BC000, + FSL_IMX6UL_OCOTP_CTRL_SIZE = (4 * KiB), + FSL_IMX6UL_EIM_ADDR = 0x021B8000, + FSL_IMX6UL_EIM_SIZE = 0x100, + FSL_IMX6UL_SIM2_ADDR = 0x021B4000, + FSL_IMX6UL_MMDC_CFG_ADDR = 0x021B0000, + FSL_IMX6UL_MMDC_CFG_SIZE = (4 * KiB), + FSL_IMX6UL_ROMCP_ADDR = 0x021AC000, + FSL_IMX6UL_ROMCP_SIZE = 0x300, + FSL_IMX6UL_I2C3_ADDR = 0x021A8000, FSL_IMX6UL_I2C2_ADDR = 0x021A4000, FSL_IMX6UL_I2C1_ADDR = 0x021A0000, + FSL_IMX6UL_ADC2_ADDR = 0x0219C000, FSL_IMX6UL_ADC1_ADDR = 0x02198000, + FSL_IMX6UL_ADCn_SIZE = 0x100, + FSL_IMX6UL_USDHC2_ADDR = 0x02194000, FSL_IMX6UL_USDHC1_ADDR = 0x02190000, - FSL_IMX6UL_SIM1_ADDR = 0x0218C000, - FSL_IMX6UL_ENET1_ADDR = 0x02188000, - FSL_IMX6UL_USBO2_USBMISC_ADDR = 0x02184800, - FSL_IMX6UL_USBO2_USB_ADDR = 0x02184000, - FSL_IMX6UL_USBO2_PL301_ADDR = 0x02180000, - FSL_IMX6UL_AIPS2_CFG_ADDR = 0x0217C000, - FSL_IMX6UL_CAAM_ADDR = 0x02140000, - FSL_IMX6UL_A7MPCORE_DAP_ADDR = 0x02100000, - /* AIPS-1 */ + FSL_IMX6UL_SIM1_ADDR = 0x0218C000, + FSL_IMX6UL_SIMn_SIZE = (16 * KiB), + + FSL_IMX6UL_ENET1_ADDR = 0x02188000, + + FSL_IMX6UL_USBO2_USBMISC_ADDR = 0x02184800, + FSL_IMX6UL_USBO2_USB1_ADDR = 0x02184000, + FSL_IMX6UL_USBO2_USB2_ADDR = 0x02184200, + + FSL_IMX6UL_USBO2_PL301_ADDR = 0x02180000, + FSL_IMX6UL_USBO2_PL301_SIZE = (16 * KiB), + + FSL_IMX6UL_AIPS2_CFG_ADDR = 0x0217C000, + FSL_IMX6UL_AIPS2_CFG_SIZE = 0x100, + + FSL_IMX6UL_CAAM_ADDR = 0x02140000, + FSL_IMX6UL_CAAM_SIZE = (16 * KiB), + + FSL_IMX6UL_A7MPCORE_DAP_ADDR = 0x02100000, + FSL_IMX6UL_A7MPCORE_DAP_SIZE = (4 * KiB), + /* AIPS-2 End */ + + /* AIPS-1 Begin */ FSL_IMX6UL_PWM8_ADDR = 0x020FC000, FSL_IMX6UL_PWM7_ADDR = 0x020F8000, FSL_IMX6UL_PWM6_ADDR = 0x020F4000, FSL_IMX6UL_PWM5_ADDR = 0x020F0000, + FSL_IMX6UL_SDMA_ADDR = 0x020EC000, + FSL_IMX6UL_SDMA_SIZE = 0x300, + FSL_IMX6UL_GPT2_ADDR = 0x020E8000, + FSL_IMX6UL_IOMUXC_GPR_ADDR = 0x020E4000, + FSL_IMX6UL_IOMUXC_GPR_SIZE = 0x40, + FSL_IMX6UL_IOMUXC_ADDR = 0x020E0000, + FSL_IMX6UL_IOMUXC_SIZE = 0x700, + FSL_IMX6UL_GPC_ADDR = 0x020DC000, + FSL_IMX6UL_SRC_ADDR = 0x020D8000, + FSL_IMX6UL_EPIT2_ADDR = 0x020D4000, FSL_IMX6UL_EPIT1_ADDR = 0x020D0000, + FSL_IMX6UL_SNVS_HP_ADDR = 0x020CC000, + FSL_IMX6UL_USBPHY2_ADDR = 0x020CA000, - FSL_IMX6UL_USBPHY2_SIZE = (4 * 1024), FSL_IMX6UL_USBPHY1_ADDR = 0x020C9000, - FSL_IMX6UL_USBPHY1_SIZE = (4 * 1024), + FSL_IMX6UL_ANALOG_ADDR = 0x020C8000, + FSL_IMX6UL_ANALOG_SIZE = 0x300, + FSL_IMX6UL_CCM_ADDR = 0x020C4000, + FSL_IMX6UL_WDOG2_ADDR = 0x020C0000, FSL_IMX6UL_WDOG1_ADDR = 0x020BC000, + FSL_IMX6UL_KPP_ADDR = 0x020B8000, + FSL_IMX6UL_KPP_SIZE = 0x10, + FSL_IMX6UL_ENET2_ADDR = 0x020B4000, + FSL_IMX6UL_SNVS_LP_ADDR = 0x020B0000, + FSL_IMX6UL_SNVS_LP_SIZE = (16 * KiB), + FSL_IMX6UL_GPIO5_ADDR = 0x020AC000, FSL_IMX6UL_GPIO4_ADDR = 0x020A8000, FSL_IMX6UL_GPIO3_ADDR = 0x020A4000, FSL_IMX6UL_GPIO2_ADDR = 0x020A0000, FSL_IMX6UL_GPIO1_ADDR = 0x0209C000, + FSL_IMX6UL_GPT1_ADDR = 0x02098000, + FSL_IMX6UL_CAN2_ADDR = 0x02094000, FSL_IMX6UL_CAN1_ADDR = 0x02090000, + FSL_IMX6UL_CANn_SIZE = (4 * KiB), + FSL_IMX6UL_PWM4_ADDR = 0x0208C000, FSL_IMX6UL_PWM3_ADDR = 0x02088000, FSL_IMX6UL_PWM2_ADDR = 0x02084000, FSL_IMX6UL_PWM1_ADDR = 0x02080000, + FSL_IMX6UL_PWMn_SIZE = 0x20, + FSL_IMX6UL_AIPS1_CFG_ADDR = 0x0207C000, + FSL_IMX6UL_AIPS1_CFG_SIZE = (16 * KiB), + FSL_IMX6UL_BEE_ADDR = 0x02044000, + FSL_IMX6UL_BEE_SIZE = (16 * KiB), + FSL_IMX6UL_TOUCH_CTRL_ADDR = 0x02040000, + FSL_IMX6UL_TOUCH_CTRL_SIZE = 0x100, + FSL_IMX6UL_SPBA_ADDR = 0x0203C000, + FSL_IMX6UL_SPBA_SIZE = 0x100, + FSL_IMX6UL_ASRC_ADDR = 0x02034000, + FSL_IMX6UL_ASRC_SIZE = 0x100, + FSL_IMX6UL_SAI3_ADDR = 0x02030000, FSL_IMX6UL_SAI2_ADDR = 0x0202C000, FSL_IMX6UL_SAI1_ADDR = 0x02028000, + FSL_IMX6UL_SAIn_SIZE = 0x200, + FSL_IMX6UL_UART8_ADDR = 0x02024000, FSL_IMX6UL_UART1_ADDR = 0x02020000, FSL_IMX6UL_UART7_ADDR = 0x02018000, + FSL_IMX6UL_ECSPI4_ADDR = 0x02014000, FSL_IMX6UL_ECSPI3_ADDR = 0x02010000, FSL_IMX6UL_ECSPI2_ADDR = 0x0200C000, FSL_IMX6UL_ECSPI1_ADDR = 0x02008000, + FSL_IMX6UL_SPDIF_ADDR = 0x02004000, + FSL_IMX6UL_SPDIF_SIZE = 0x100, + /* AIPS-1 End */ + + FSL_IMX6UL_BCH_ADDR = 0x01808000, + FSL_IMX6UL_BCH_SIZE = 0x200, + + FSL_IMX6UL_GPMI_ADDR = 0x01806000, + FSL_IMX6UL_GPMI_SIZE = 0x200, FSL_IMX6UL_APBH_DMA_ADDR = 0x01804000, - FSL_IMX6UL_APBH_DMA_SIZE = (32 * 1024), + FSL_IMX6UL_APBH_DMA_SIZE = (4 * KiB), FSL_IMX6UL_A7MPCORE_ADDR = 0x00A00000, FSL_IMX6UL_OCRAM_ALIAS_ADDR = 0x00920000, - FSL_IMX6UL_OCRAM_ALIAS_SIZE = 0x00060000, + FSL_IMX6UL_OCRAM_ALIAS_SIZE = (384 * KiB), + FSL_IMX6UL_OCRAM_MEM_ADDR = 0x00900000, - FSL_IMX6UL_OCRAM_MEM_SIZE = 0x00020000, + FSL_IMX6UL_OCRAM_MEM_SIZE = (128 * KiB), + FSL_IMX6UL_CAAM_MEM_ADDR = 0x00100000, - FSL_IMX6UL_CAAM_MEM_SIZE = 0x00008000, + FSL_IMX6UL_CAAM_MEM_SIZE = (32 * KiB), + FSL_IMX6UL_ROM_ADDR = 0x00000000, - FSL_IMX6UL_ROM_SIZE = 0x00018000, + FSL_IMX6UL_ROM_SIZE = (96 * KiB), }; enum FslIMX6ULIRQs { From f6020845e20d1cc033770bbff8c1d92855d2bba5 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Dubois Date: Thu, 31 Aug 2023 09:45:16 +0100 Subject: [PATCH 1342/1353] Add i.MX6UL missing devices. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add TZASC as unimplemented device. - Allow bare metal application to access this (unimplemented) device * Add CSU as unimplemented device. - Allow bare metal application to access this (unimplemented) device * Add 4 missing PWM devices Signed-off-by: Jean-Christophe Dubois Reviewed-by: Philippe Mathieu-Daudé Message-id: 59e4dc56e14eccfefd379275ec19048dff9c10b3.1692964892.git.jcd@tribudubois.net Signed-off-by: Peter Maydell --- hw/arm/fsl-imx6ul.c | 16 ++++++++++++++++ include/hw/arm/fsl-imx6ul.h | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/hw/arm/fsl-imx6ul.c b/hw/arm/fsl-imx6ul.c index 06a32aff64..e37b69a5e1 100644 --- a/hw/arm/fsl-imx6ul.c +++ b/hw/arm/fsl-imx6ul.c @@ -583,6 +583,10 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) FSL_IMX6UL_PWM2_ADDR, FSL_IMX6UL_PWM3_ADDR, FSL_IMX6UL_PWM4_ADDR, + FSL_IMX6UL_PWM5_ADDR, + FSL_IMX6UL_PWM6_ADDR, + FSL_IMX6UL_PWM7_ADDR, + FSL_IMX6UL_PWM8_ADDR, }; snprintf(name, NAME_SIZE, "pwm%d", i); @@ -636,6 +640,18 @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp) create_unimplemented_device("lcdif", FSL_IMX6UL_LCDIF_ADDR, FSL_IMX6UL_LCDIF_SIZE); + /* + * CSU + */ + create_unimplemented_device("csu", FSL_IMX6UL_CSU_ADDR, + FSL_IMX6UL_CSU_SIZE); + + /* + * TZASC + */ + create_unimplemented_device("tzasc", FSL_IMX6UL_TZASC_ADDR, + FSL_IMX6UL_TZASC_SIZE); + /* * ROM memory */ diff --git a/include/hw/arm/fsl-imx6ul.h b/include/hw/arm/fsl-imx6ul.h index f7bf684b42..63012628ff 100644 --- a/include/hw/arm/fsl-imx6ul.h +++ b/include/hw/arm/fsl-imx6ul.h @@ -60,7 +60,7 @@ enum FslIMX6ULConfiguration { FSL_IMX6UL_NUM_USBS = 2, FSL_IMX6UL_NUM_SAIS = 3, FSL_IMX6UL_NUM_CANS = 2, - FSL_IMX6UL_NUM_PWMS = 4, + FSL_IMX6UL_NUM_PWMS = 8, }; struct FslIMX6ULState { From 45b8b34dfacb14503d6f8692fa450f81175328e6 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Dubois Date: Thu, 31 Aug 2023 09:45:17 +0100 Subject: [PATCH 1343/1353] Refactor i.MX7 processor code * Add Addr and size definition for all i.MX7 devices in i.MX7 header file. * Use those newly defined named constants whenever possible. * Standardize the way we init a familly of unimplemented devices - SAI - PWM - CAN * Add/rework few comments Signed-off-by: Jean-Christophe Dubois Message-id: 59e195d33e4d486a8d131392acd46633c8c10ed7.1692964892.git.jcd@tribudubois.net Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/fsl-imx7.c | 130 ++++++++++----- include/hw/arm/fsl-imx7.h | 330 ++++++++++++++++++++++++++++---------- 2 files changed, 335 insertions(+), 125 deletions(-) diff --git a/hw/arm/fsl-imx7.c b/hw/arm/fsl-imx7.c index 9e41d4b677..e976053539 100644 --- a/hw/arm/fsl-imx7.c +++ b/hw/arm/fsl-imx7.c @@ -36,6 +36,9 @@ static void fsl_imx7_init(Object *obj) char name[NAME_SIZE]; int i; + /* + * CPUs + */ for (i = 0; i < MIN(ms->smp.cpus, FSL_IMX7_NUM_CPUS); i++) { snprintf(name, NAME_SIZE, "cpu%d", i); object_initialize_child(obj, name, &s->cpu[i], @@ -49,7 +52,7 @@ static void fsl_imx7_init(Object *obj) TYPE_A15MPCORE_PRIV); /* - * GPIOs 1 to 7 + * GPIOs */ for (i = 0; i < FSL_IMX7_NUM_GPIOS; i++) { snprintf(name, NAME_SIZE, "gpio%d", i); @@ -57,7 +60,7 @@ static void fsl_imx7_init(Object *obj) } /* - * GPT1, 2, 3, 4 + * GPTs */ for (i = 0; i < FSL_IMX7_NUM_GPTS; i++) { snprintf(name, NAME_SIZE, "gpt%d", i); @@ -79,19 +82,24 @@ static void fsl_imx7_init(Object *obj) */ object_initialize_child(obj, "gpcv2", &s->gpcv2, TYPE_IMX_GPCV2); + /* + * ECSPIs + */ for (i = 0; i < FSL_IMX7_NUM_ECSPIS; i++) { snprintf(name, NAME_SIZE, "spi%d", i + 1); object_initialize_child(obj, name, &s->spi[i], TYPE_IMX_SPI); } - + /* + * I2Cs + */ for (i = 0; i < FSL_IMX7_NUM_I2CS; i++) { snprintf(name, NAME_SIZE, "i2c%d", i + 1); object_initialize_child(obj, name, &s->i2c[i], TYPE_IMX_I2C); } /* - * UART + * UARTs */ for (i = 0; i < FSL_IMX7_NUM_UARTS; i++) { snprintf(name, NAME_SIZE, "uart%d", i); @@ -99,7 +107,7 @@ static void fsl_imx7_init(Object *obj) } /* - * Ethernet + * Ethernets */ for (i = 0; i < FSL_IMX7_NUM_ETHS; i++) { snprintf(name, NAME_SIZE, "eth%d", i); @@ -107,7 +115,7 @@ static void fsl_imx7_init(Object *obj) } /* - * SDHCI + * SDHCIs */ for (i = 0; i < FSL_IMX7_NUM_USDHCS; i++) { snprintf(name, NAME_SIZE, "usdhc%d", i); @@ -120,7 +128,7 @@ static void fsl_imx7_init(Object *obj) object_initialize_child(obj, "snvs", &s->snvs, TYPE_IMX7_SNVS); /* - * Watchdog + * Watchdogs */ for (i = 0; i < FSL_IMX7_NUM_WDTS; i++) { snprintf(name, NAME_SIZE, "wdt%d", i); @@ -132,8 +140,14 @@ static void fsl_imx7_init(Object *obj) */ object_initialize_child(obj, "gpr", &s->gpr, TYPE_IMX7_GPR); + /* + * PCIE + */ object_initialize_child(obj, "pcie", &s->pcie, TYPE_DESIGNWARE_PCIE_HOST); + /* + * USBs + */ for (i = 0; i < FSL_IMX7_NUM_USBS; i++) { snprintf(name, NAME_SIZE, "usb%d", i); object_initialize_child(obj, name, &s->usb[i], TYPE_CHIPIDEA); @@ -156,6 +170,9 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) return; } + /* + * CPUs + */ for (i = 0; i < smp_cpus; i++) { o = OBJECT(&s->cpu[i]); @@ -206,10 +223,10 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) * A7MPCORE DAP */ create_unimplemented_device("a7mpcore-dap", FSL_IMX7_A7MPCORE_DAP_ADDR, - 0x100000); + FSL_IMX7_A7MPCORE_DAP_SIZE); /* - * GPT1, 2, 3, 4 + * GPTs */ for (i = 0; i < FSL_IMX7_NUM_GPTS; i++) { static const hwaddr FSL_IMX7_GPTn_ADDR[FSL_IMX7_NUM_GPTS] = { @@ -234,6 +251,9 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) FSL_IMX7_GPTn_IRQ[i])); } + /* + * GPIOs + */ for (i = 0; i < FSL_IMX7_NUM_GPIOS; i++) { static const hwaddr FSL_IMX7_GPIOn_ADDR[FSL_IMX7_NUM_GPIOS] = { FSL_IMX7_GPIO1_ADDR, @@ -281,16 +301,10 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) /* * IOMUXC and IOMUXC_LPSR */ - for (i = 0; i < FSL_IMX7_NUM_IOMUXCS; i++) { - static const hwaddr FSL_IMX7_IOMUXCn_ADDR[FSL_IMX7_NUM_IOMUXCS] = { - FSL_IMX7_IOMUXC_ADDR, - FSL_IMX7_IOMUXC_LPSR_ADDR, - }; - - snprintf(name, NAME_SIZE, "iomuxc%d", i); - create_unimplemented_device(name, FSL_IMX7_IOMUXCn_ADDR[i], - FSL_IMX7_IOMUXCn_SIZE); - } + create_unimplemented_device("iomuxc", FSL_IMX7_IOMUXC_ADDR, + FSL_IMX7_IOMUXC_SIZE); + create_unimplemented_device("iomuxc_lspr", FSL_IMX7_IOMUXC_LPSR_ADDR, + FSL_IMX7_IOMUXC_LPSR_SIZE); /* * CCM @@ -310,7 +324,9 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) sysbus_realize(SYS_BUS_DEVICE(&s->gpcv2), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpcv2), 0, FSL_IMX7_GPC_ADDR); - /* Initialize all ECSPI */ + /* + * ECSPIs + */ for (i = 0; i < FSL_IMX7_NUM_ECSPIS; i++) { static const hwaddr FSL_IMX7_SPIn_ADDR[FSL_IMX7_NUM_ECSPIS] = { FSL_IMX7_ECSPI1_ADDR, @@ -335,6 +351,9 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) FSL_IMX7_SPIn_IRQ[i])); } + /* + * I2Cs + */ for (i = 0; i < FSL_IMX7_NUM_I2CS; i++) { static const hwaddr FSL_IMX7_I2Cn_ADDR[FSL_IMX7_NUM_I2CS] = { FSL_IMX7_I2C1_ADDR, @@ -359,7 +378,7 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) } /* - * UART + * UARTs */ for (i = 0; i < FSL_IMX7_NUM_UARTS; i++) { static const hwaddr FSL_IMX7_UARTn_ADDR[FSL_IMX7_NUM_UARTS] = { @@ -394,7 +413,7 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) } /* - * Ethernet + * Ethernets * * We must use two loops since phy_connected affects the other interface * and we have to set all properties before calling sysbus_realize(). @@ -434,7 +453,7 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) } /* - * USDHC + * USDHCs */ for (i = 0; i < FSL_IMX7_NUM_USDHCS; i++) { static const hwaddr FSL_IMX7_USDHCn_ADDR[FSL_IMX7_NUM_USDHCS] = { @@ -464,7 +483,7 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) * SNVS */ sysbus_realize(SYS_BUS_DEVICE(&s->snvs), &error_abort); - sysbus_mmio_map(SYS_BUS_DEVICE(&s->snvs), 0, FSL_IMX7_SNVS_ADDR); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->snvs), 0, FSL_IMX7_SNVS_HP_ADDR); /* * SRC @@ -472,7 +491,7 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) create_unimplemented_device("src", FSL_IMX7_SRC_ADDR, FSL_IMX7_SRC_SIZE); /* - * Watchdog + * Watchdogs */ for (i = 0; i < FSL_IMX7_NUM_WDTS; i++) { static const hwaddr FSL_IMX7_WDOGn_ADDR[FSL_IMX7_NUM_WDTS] = { @@ -509,25 +528,49 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) create_unimplemented_device("caam", FSL_IMX7_CAAM_ADDR, FSL_IMX7_CAAM_SIZE); /* - * PWM + * PWMs */ - create_unimplemented_device("pwm1", FSL_IMX7_PWM1_ADDR, FSL_IMX7_PWMn_SIZE); - create_unimplemented_device("pwm2", FSL_IMX7_PWM2_ADDR, FSL_IMX7_PWMn_SIZE); - create_unimplemented_device("pwm3", FSL_IMX7_PWM3_ADDR, FSL_IMX7_PWMn_SIZE); - create_unimplemented_device("pwm4", FSL_IMX7_PWM4_ADDR, FSL_IMX7_PWMn_SIZE); + for (i = 0; i < FSL_IMX7_NUM_PWMS; i++) { + static const hwaddr FSL_IMX7_PWMn_ADDR[FSL_IMX7_NUM_PWMS] = { + FSL_IMX7_PWM1_ADDR, + FSL_IMX7_PWM2_ADDR, + FSL_IMX7_PWM3_ADDR, + FSL_IMX7_PWM4_ADDR, + }; + + snprintf(name, NAME_SIZE, "pwm%d", i); + create_unimplemented_device(name, FSL_IMX7_PWMn_ADDR[i], + FSL_IMX7_PWMn_SIZE); + } /* - * CAN + * CANs */ - create_unimplemented_device("can1", FSL_IMX7_CAN1_ADDR, FSL_IMX7_CANn_SIZE); - create_unimplemented_device("can2", FSL_IMX7_CAN2_ADDR, FSL_IMX7_CANn_SIZE); + for (i = 0; i < FSL_IMX7_NUM_CANS; i++) { + static const hwaddr FSL_IMX7_CANn_ADDR[FSL_IMX7_NUM_CANS] = { + FSL_IMX7_CAN1_ADDR, + FSL_IMX7_CAN2_ADDR, + }; + + snprintf(name, NAME_SIZE, "can%d", i); + create_unimplemented_device(name, FSL_IMX7_CANn_ADDR[i], + FSL_IMX7_CANn_SIZE); + } /* - * SAI (Audio SSI (Synchronous Serial Interface)) + * SAIs (Audio SSI (Synchronous Serial Interface)) */ - create_unimplemented_device("sai1", FSL_IMX7_SAI1_ADDR, FSL_IMX7_SAIn_SIZE); - create_unimplemented_device("sai2", FSL_IMX7_SAI2_ADDR, FSL_IMX7_SAIn_SIZE); - create_unimplemented_device("sai2", FSL_IMX7_SAI3_ADDR, FSL_IMX7_SAIn_SIZE); + for (i = 0; i < FSL_IMX7_NUM_SAIS; i++) { + static const hwaddr FSL_IMX7_SAIn_ADDR[FSL_IMX7_NUM_SAIS] = { + FSL_IMX7_SAI1_ADDR, + FSL_IMX7_SAI2_ADDR, + FSL_IMX7_SAI3_ADDR, + }; + + snprintf(name, NAME_SIZE, "sai%d", i); + create_unimplemented_device(name, FSL_IMX7_SAIn_ADDR[i], + FSL_IMX7_SAIn_SIZE); + } /* * OCOTP @@ -535,9 +578,15 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) create_unimplemented_device("ocotp", FSL_IMX7_OCOTP_ADDR, FSL_IMX7_OCOTP_SIZE); + /* + * GPR + */ sysbus_realize(SYS_BUS_DEVICE(&s->gpr), &error_abort); - sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpr), 0, FSL_IMX7_GPR_ADDR); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpr), 0, FSL_IMX7_IOMUXC_GPR_ADDR); + /* + * PCIE + */ sysbus_realize(SYS_BUS_DEVICE(&s->pcie), &error_abort); sysbus_mmio_map(SYS_BUS_DEVICE(&s->pcie), 0, FSL_IMX7_PCIE_REG_ADDR); @@ -550,7 +599,9 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) irq = qdev_get_gpio_in(DEVICE(&s->a7mpcore), FSL_IMX7_PCI_INTD_IRQ); sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 3, irq); - + /* + * USBs + */ for (i = 0; i < FSL_IMX7_NUM_USBS; i++) { static const hwaddr FSL_IMX7_USBMISCn_ADDR[FSL_IMX7_NUM_USBS] = { FSL_IMX7_USBMISC1_ADDR, @@ -612,6 +663,7 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) */ create_unimplemented_device("pcie-phy", FSL_IMX7_PCIE_PHY_ADDR, FSL_IMX7_PCIE_PHY_SIZE); + } static Property fsl_imx7_properties[] = { diff --git a/include/hw/arm/fsl-imx7.h b/include/hw/arm/fsl-imx7.h index fcce6421c8..06b2c5e4ac 100644 --- a/include/hw/arm/fsl-imx7.h +++ b/include/hw/arm/fsl-imx7.h @@ -25,7 +25,6 @@ #include "hw/misc/imx7_ccm.h" #include "hw/misc/imx7_snvs.h" #include "hw/misc/imx7_gpr.h" -#include "hw/misc/imx6_src.h" #include "hw/watchdog/wdt_imx2.h" #include "hw/gpio/imx_gpio.h" #include "hw/char/imx_serial.h" @@ -39,6 +38,7 @@ #include "hw/usb/chipidea.h" #include "cpu.h" #include "qom/object.h" +#include "qemu/units.h" #define TYPE_FSL_IMX7 "fsl-imx7" OBJECT_DECLARE_SIMPLE_TYPE(FslIMX7State, FSL_IMX7) @@ -57,6 +57,9 @@ enum FslIMX7Configuration { FSL_IMX7_NUM_ECSPIS = 4, FSL_IMX7_NUM_USBS = 3, FSL_IMX7_NUM_ADCS = 2, + FSL_IMX7_NUM_SAIS = 3, + FSL_IMX7_NUM_CANS = 2, + FSL_IMX7_NUM_PWMS = 4, }; struct FslIMX7State { @@ -87,80 +90,106 @@ struct FslIMX7State { enum FslIMX7MemoryMap { FSL_IMX7_MMDC_ADDR = 0x80000000, - FSL_IMX7_MMDC_SIZE = 2 * 1024 * 1024 * 1024UL, + FSL_IMX7_MMDC_SIZE = (2 * GiB), - FSL_IMX7_GPIO1_ADDR = 0x30200000, - FSL_IMX7_GPIO2_ADDR = 0x30210000, - FSL_IMX7_GPIO3_ADDR = 0x30220000, - FSL_IMX7_GPIO4_ADDR = 0x30230000, - FSL_IMX7_GPIO5_ADDR = 0x30240000, - FSL_IMX7_GPIO6_ADDR = 0x30250000, - FSL_IMX7_GPIO7_ADDR = 0x30260000, + FSL_IMX7_QSPI1_MEM_ADDR = 0x60000000, + FSL_IMX7_QSPI1_MEM_SIZE = (256 * MiB), - FSL_IMX7_IOMUXC_LPSR_GPR_ADDR = 0x30270000, + FSL_IMX7_PCIE1_MEM_ADDR = 0x40000000, + FSL_IMX7_PCIE1_MEM_SIZE = (256 * MiB), - FSL_IMX7_WDOG1_ADDR = 0x30280000, - FSL_IMX7_WDOG2_ADDR = 0x30290000, - FSL_IMX7_WDOG3_ADDR = 0x302A0000, - FSL_IMX7_WDOG4_ADDR = 0x302B0000, + FSL_IMX7_QSPI1_RX_BUF_ADDR = 0x34000000, + FSL_IMX7_QSPI1_RX_BUF_SIZE = (32 * MiB), - FSL_IMX7_IOMUXC_LPSR_ADDR = 0x302C0000, + /* PCIe Peripherals */ + FSL_IMX7_PCIE_REG_ADDR = 0x33800000, - FSL_IMX7_GPT1_ADDR = 0x302D0000, - FSL_IMX7_GPT2_ADDR = 0x302E0000, - FSL_IMX7_GPT3_ADDR = 0x302F0000, - FSL_IMX7_GPT4_ADDR = 0x30300000, + /* MMAP Peripherals */ + FSL_IMX7_DMA_APBH_ADDR = 0x33000000, + FSL_IMX7_DMA_APBH_SIZE = 0x8000, - FSL_IMX7_IOMUXC_ADDR = 0x30330000, - FSL_IMX7_IOMUXC_GPR_ADDR = 0x30340000, - FSL_IMX7_IOMUXCn_SIZE = 0x1000, + /* GPV configuration */ + FSL_IMX7_GPV6_ADDR = 0x32600000, + FSL_IMX7_GPV5_ADDR = 0x32500000, + FSL_IMX7_GPV4_ADDR = 0x32400000, + FSL_IMX7_GPV3_ADDR = 0x32300000, + FSL_IMX7_GPV2_ADDR = 0x32200000, + FSL_IMX7_GPV1_ADDR = 0x32100000, + FSL_IMX7_GPV0_ADDR = 0x32000000, + FSL_IMX7_GPVn_SIZE = (1 * MiB), - FSL_IMX7_OCOTP_ADDR = 0x30350000, - FSL_IMX7_OCOTP_SIZE = 0x10000, + /* Arm Peripherals */ + FSL_IMX7_A7MPCORE_ADDR = 0x31000000, - FSL_IMX7_ANALOG_ADDR = 0x30360000, - FSL_IMX7_SNVS_ADDR = 0x30370000, - FSL_IMX7_CCM_ADDR = 0x30380000, + /* AIPS-3 Begin */ - FSL_IMX7_SRC_ADDR = 0x30390000, - FSL_IMX7_SRC_SIZE = 0x1000, + FSL_IMX7_ENET2_ADDR = 0x30BF0000, + FSL_IMX7_ENET1_ADDR = 0x30BE0000, - FSL_IMX7_ADC1_ADDR = 0x30610000, - FSL_IMX7_ADC2_ADDR = 0x30620000, - FSL_IMX7_ADCn_SIZE = 0x1000, + FSL_IMX7_SDMA_ADDR = 0x30BD0000, + FSL_IMX7_SDMA_SIZE = (4 * KiB), - FSL_IMX7_PWM1_ADDR = 0x30660000, - FSL_IMX7_PWM2_ADDR = 0x30670000, - FSL_IMX7_PWM3_ADDR = 0x30680000, - FSL_IMX7_PWM4_ADDR = 0x30690000, - FSL_IMX7_PWMn_SIZE = 0x10000, + FSL_IMX7_EIM_ADDR = 0x30BC0000, + FSL_IMX7_EIM_SIZE = (4 * KiB), - FSL_IMX7_PCIE_PHY_ADDR = 0x306D0000, - FSL_IMX7_PCIE_PHY_SIZE = 0x10000, + FSL_IMX7_QSPI_ADDR = 0x30BB0000, + FSL_IMX7_QSPI_SIZE = 0x8000, - FSL_IMX7_GPC_ADDR = 0x303A0000, + FSL_IMX7_SIM2_ADDR = 0x30BA0000, + FSL_IMX7_SIM1_ADDR = 0x30B90000, + FSL_IMX7_SIMn_SIZE = (4 * KiB), + + FSL_IMX7_USDHC3_ADDR = 0x30B60000, + FSL_IMX7_USDHC2_ADDR = 0x30B50000, + FSL_IMX7_USDHC1_ADDR = 0x30B40000, + + FSL_IMX7_USB3_ADDR = 0x30B30000, + FSL_IMX7_USBMISC3_ADDR = 0x30B30200, + FSL_IMX7_USB2_ADDR = 0x30B20000, + FSL_IMX7_USBMISC2_ADDR = 0x30B20200, + FSL_IMX7_USB1_ADDR = 0x30B10000, + FSL_IMX7_USBMISC1_ADDR = 0x30B10200, + FSL_IMX7_USBMISCn_SIZE = 0x200, + + FSL_IMX7_USB_PL301_ADDR = 0x30AD0000, + FSL_IMX7_USB_PL301_SIZE = (64 * KiB), + + FSL_IMX7_SEMAPHORE_HS_ADDR = 0x30AC0000, + FSL_IMX7_SEMAPHORE_HS_SIZE = (64 * KiB), + + FSL_IMX7_MUB_ADDR = 0x30AB0000, + FSL_IMX7_MUA_ADDR = 0x30AA0000, + FSL_IMX7_MUn_SIZE = (KiB), + + FSL_IMX7_UART7_ADDR = 0x30A90000, + FSL_IMX7_UART6_ADDR = 0x30A80000, + FSL_IMX7_UART5_ADDR = 0x30A70000, + FSL_IMX7_UART4_ADDR = 0x30A60000, + + FSL_IMX7_I2C4_ADDR = 0x30A50000, + FSL_IMX7_I2C3_ADDR = 0x30A40000, + FSL_IMX7_I2C2_ADDR = 0x30A30000, + FSL_IMX7_I2C1_ADDR = 0x30A20000, + + FSL_IMX7_CAN2_ADDR = 0x30A10000, + FSL_IMX7_CAN1_ADDR = 0x30A00000, + FSL_IMX7_CANn_SIZE = (4 * KiB), + + FSL_IMX7_AIPS3_CONF_ADDR = 0x309F0000, + FSL_IMX7_AIPS3_CONF_SIZE = (64 * KiB), FSL_IMX7_CAAM_ADDR = 0x30900000, - FSL_IMX7_CAAM_SIZE = 0x40000, + FSL_IMX7_CAAM_SIZE = (256 * KiB), - FSL_IMX7_CAN1_ADDR = 0x30A00000, - FSL_IMX7_CAN2_ADDR = 0x30A10000, - FSL_IMX7_CANn_SIZE = 0x10000, + FSL_IMX7_SPBA_ADDR = 0x308F0000, + FSL_IMX7_SPBA_SIZE = (4 * KiB), - FSL_IMX7_I2C1_ADDR = 0x30A20000, - FSL_IMX7_I2C2_ADDR = 0x30A30000, - FSL_IMX7_I2C3_ADDR = 0x30A40000, - FSL_IMX7_I2C4_ADDR = 0x30A50000, + FSL_IMX7_SAI3_ADDR = 0x308C0000, + FSL_IMX7_SAI2_ADDR = 0x308B0000, + FSL_IMX7_SAI1_ADDR = 0x308A0000, + FSL_IMX7_SAIn_SIZE = (4 * KiB), - FSL_IMX7_ECSPI1_ADDR = 0x30820000, - FSL_IMX7_ECSPI2_ADDR = 0x30830000, - FSL_IMX7_ECSPI3_ADDR = 0x30840000, - FSL_IMX7_ECSPI4_ADDR = 0x30630000, - - FSL_IMX7_LCDIF_ADDR = 0x30730000, - FSL_IMX7_LCDIF_SIZE = 0x1000, - - FSL_IMX7_UART1_ADDR = 0x30860000, + FSL_IMX7_UART3_ADDR = 0x30880000, /* * Some versions of the reference manual claim that UART2 is @ * 0x30870000, but experiments with HW + DT files in upstream @@ -168,45 +197,174 @@ enum FslIMX7MemoryMap { * actually located @ 0x30890000 */ FSL_IMX7_UART2_ADDR = 0x30890000, - FSL_IMX7_UART3_ADDR = 0x30880000, - FSL_IMX7_UART4_ADDR = 0x30A60000, - FSL_IMX7_UART5_ADDR = 0x30A70000, - FSL_IMX7_UART6_ADDR = 0x30A80000, - FSL_IMX7_UART7_ADDR = 0x30A90000, + FSL_IMX7_UART1_ADDR = 0x30860000, - FSL_IMX7_SAI1_ADDR = 0x308A0000, - FSL_IMX7_SAI2_ADDR = 0x308B0000, - FSL_IMX7_SAI3_ADDR = 0x308C0000, - FSL_IMX7_SAIn_SIZE = 0x10000, + FSL_IMX7_ECSPI3_ADDR = 0x30840000, + FSL_IMX7_ECSPI2_ADDR = 0x30830000, + FSL_IMX7_ECSPI1_ADDR = 0x30820000, + FSL_IMX7_ECSPIn_SIZE = (4 * KiB), - FSL_IMX7_ENET1_ADDR = 0x30BE0000, - FSL_IMX7_ENET2_ADDR = 0x30BF0000, + /* AIPS-3 End */ - FSL_IMX7_USB1_ADDR = 0x30B10000, - FSL_IMX7_USBMISC1_ADDR = 0x30B10200, - FSL_IMX7_USB2_ADDR = 0x30B20000, - FSL_IMX7_USBMISC2_ADDR = 0x30B20200, - FSL_IMX7_USB3_ADDR = 0x30B30000, - FSL_IMX7_USBMISC3_ADDR = 0x30B30200, - FSL_IMX7_USBMISCn_SIZE = 0x200, + /* AIPS-2 Begin */ - FSL_IMX7_USDHC1_ADDR = 0x30B40000, - FSL_IMX7_USDHC2_ADDR = 0x30B50000, - FSL_IMX7_USDHC3_ADDR = 0x30B60000, + FSL_IMX7_AXI_DEBUG_MON_ADDR = 0x307E0000, + FSL_IMX7_AXI_DEBUG_MON_SIZE = (64 * KiB), - FSL_IMX7_SDMA_ADDR = 0x30BD0000, - FSL_IMX7_SDMA_SIZE = 0x1000, + FSL_IMX7_PERFMON2_ADDR = 0x307D0000, + FSL_IMX7_PERFMON1_ADDR = 0x307C0000, + FSL_IMX7_PERFMONn_SIZE = (64 * KiB), + + FSL_IMX7_DDRC_ADDR = 0x307A0000, + FSL_IMX7_DDRC_SIZE = (4 * KiB), + + FSL_IMX7_DDRC_PHY_ADDR = 0x30790000, + FSL_IMX7_DDRC_PHY_SIZE = (4 * KiB), + + FSL_IMX7_TZASC_ADDR = 0x30780000, + FSL_IMX7_TZASC_SIZE = (64 * KiB), + + FSL_IMX7_MIPI_DSI_ADDR = 0x30760000, + FSL_IMX7_MIPI_DSI_SIZE = (4 * KiB), + + FSL_IMX7_MIPI_CSI_ADDR = 0x30750000, + FSL_IMX7_MIPI_CSI_SIZE = 0x4000, + + FSL_IMX7_LCDIF_ADDR = 0x30730000, + FSL_IMX7_LCDIF_SIZE = 0x8000, + + FSL_IMX7_CSI_ADDR = 0x30710000, + FSL_IMX7_CSI_SIZE = (4 * KiB), + + FSL_IMX7_PXP_ADDR = 0x30700000, + FSL_IMX7_PXP_SIZE = 0x4000, + + FSL_IMX7_EPDC_ADDR = 0x306F0000, + FSL_IMX7_EPDC_SIZE = (4 * KiB), + + FSL_IMX7_PCIE_PHY_ADDR = 0x306D0000, + FSL_IMX7_PCIE_PHY_SIZE = (4 * KiB), + + FSL_IMX7_SYSCNT_CTRL_ADDR = 0x306C0000, + FSL_IMX7_SYSCNT_CMP_ADDR = 0x306B0000, + FSL_IMX7_SYSCNT_RD_ADDR = 0x306A0000, + + FSL_IMX7_PWM4_ADDR = 0x30690000, + FSL_IMX7_PWM3_ADDR = 0x30680000, + FSL_IMX7_PWM2_ADDR = 0x30670000, + FSL_IMX7_PWM1_ADDR = 0x30660000, + FSL_IMX7_PWMn_SIZE = (4 * KiB), + + FSL_IMX7_FlEXTIMER2_ADDR = 0x30650000, + FSL_IMX7_FlEXTIMER1_ADDR = 0x30640000, + FSL_IMX7_FLEXTIMERn_SIZE = (4 * KiB), + + FSL_IMX7_ECSPI4_ADDR = 0x30630000, + + FSL_IMX7_ADC2_ADDR = 0x30620000, + FSL_IMX7_ADC1_ADDR = 0x30610000, + FSL_IMX7_ADCn_SIZE = (4 * KiB), + + FSL_IMX7_AIPS2_CONF_ADDR = 0x305F0000, + FSL_IMX7_AIPS2_CONF_SIZE = (64 * KiB), + + /* AIPS-2 End */ + + /* AIPS-1 Begin */ + + FSL_IMX7_CSU_ADDR = 0x303E0000, + FSL_IMX7_CSU_SIZE = (64 * KiB), + + FSL_IMX7_RDC_ADDR = 0x303D0000, + FSL_IMX7_RDC_SIZE = (4 * KiB), + + FSL_IMX7_SEMAPHORE2_ADDR = 0x303C0000, + FSL_IMX7_SEMAPHORE1_ADDR = 0x303B0000, + FSL_IMX7_SEMAPHOREn_SIZE = (4 * KiB), + + FSL_IMX7_GPC_ADDR = 0x303A0000, + + FSL_IMX7_SRC_ADDR = 0x30390000, + FSL_IMX7_SRC_SIZE = (4 * KiB), + + FSL_IMX7_CCM_ADDR = 0x30380000, + + FSL_IMX7_SNVS_HP_ADDR = 0x30370000, + + FSL_IMX7_ANALOG_ADDR = 0x30360000, + + FSL_IMX7_OCOTP_ADDR = 0x30350000, + FSL_IMX7_OCOTP_SIZE = 0x10000, + + FSL_IMX7_IOMUXC_GPR_ADDR = 0x30340000, + FSL_IMX7_IOMUXC_GPR_SIZE = (4 * KiB), + + FSL_IMX7_IOMUXC_ADDR = 0x30330000, + FSL_IMX7_IOMUXC_SIZE = (4 * KiB), + + FSL_IMX7_KPP_ADDR = 0x30320000, + FSL_IMX7_KPP_SIZE = (4 * KiB), + + FSL_IMX7_ROMCP_ADDR = 0x30310000, + FSL_IMX7_ROMCP_SIZE = (4 * KiB), + + FSL_IMX7_GPT4_ADDR = 0x30300000, + FSL_IMX7_GPT3_ADDR = 0x302F0000, + FSL_IMX7_GPT2_ADDR = 0x302E0000, + FSL_IMX7_GPT1_ADDR = 0x302D0000, + + FSL_IMX7_IOMUXC_LPSR_ADDR = 0x302C0000, + FSL_IMX7_IOMUXC_LPSR_SIZE = (4 * KiB), + + FSL_IMX7_WDOG4_ADDR = 0x302B0000, + FSL_IMX7_WDOG3_ADDR = 0x302A0000, + FSL_IMX7_WDOG2_ADDR = 0x30290000, + FSL_IMX7_WDOG1_ADDR = 0x30280000, + + FSL_IMX7_IOMUXC_LPSR_GPR_ADDR = 0x30270000, + + FSL_IMX7_GPIO7_ADDR = 0x30260000, + FSL_IMX7_GPIO6_ADDR = 0x30250000, + FSL_IMX7_GPIO5_ADDR = 0x30240000, + FSL_IMX7_GPIO4_ADDR = 0x30230000, + FSL_IMX7_GPIO3_ADDR = 0x30220000, + FSL_IMX7_GPIO2_ADDR = 0x30210000, + FSL_IMX7_GPIO1_ADDR = 0x30200000, + + FSL_IMX7_AIPS1_CONF_ADDR = 0x301F0000, + FSL_IMX7_AIPS1_CONF_SIZE = (64 * KiB), - FSL_IMX7_A7MPCORE_ADDR = 0x31000000, FSL_IMX7_A7MPCORE_DAP_ADDR = 0x30000000, + FSL_IMX7_A7MPCORE_DAP_SIZE = (1 * MiB), - FSL_IMX7_PCIE_REG_ADDR = 0x33800000, - FSL_IMX7_PCIE_REG_SIZE = 16 * 1024, + /* AIPS-1 End */ - FSL_IMX7_GPR_ADDR = 0x30340000, + FSL_IMX7_EIM_CS0_ADDR = 0x28000000, + FSL_IMX7_EIM_CS0_SIZE = (128 * MiB), - FSL_IMX7_DMA_APBH_ADDR = 0x33000000, - FSL_IMX7_DMA_APBH_SIZE = 0x2000, + FSL_IMX7_OCRAM_PXP_ADDR = 0x00940000, + FSL_IMX7_OCRAM_PXP_SIZE = (32 * KiB), + + FSL_IMX7_OCRAM_EPDC_ADDR = 0x00920000, + FSL_IMX7_OCRAM_EPDC_SIZE = (128 * KiB), + + FSL_IMX7_OCRAM_MEM_ADDR = 0x00900000, + FSL_IMX7_OCRAM_MEM_SIZE = (128 * KiB), + + FSL_IMX7_TCMU_ADDR = 0x00800000, + FSL_IMX7_TCMU_SIZE = (32 * KiB), + + FSL_IMX7_TCML_ADDR = 0x007F8000, + FSL_IMX7_TCML_SIZE = (32 * KiB), + + FSL_IMX7_OCRAM_S_ADDR = 0x00180000, + FSL_IMX7_OCRAM_S_SIZE = (32 * KiB), + + FSL_IMX7_CAAM_MEM_ADDR = 0x00100000, + FSL_IMX7_CAAM_MEM_SIZE = (32 * KiB), + + FSL_IMX7_ROM_ADDR = 0x00000000, + FSL_IMX7_ROM_SIZE = (96 * KiB), }; enum FslIMX7IRQs { From 736988a040b58b7021445580634d4d2d35a4a6cc Mon Sep 17 00:00:00 2001 From: Jean-Christophe Dubois Date: Thu, 31 Aug 2023 09:45:17 +0100 Subject: [PATCH 1344/1353] Add i.MX7 missing TZ devices and memory regions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add TZASC as unimplemented device. - Allow bare metal application to access this (unimplemented) device * Add CSU as unimplemented device. - Allow bare metal application to access this (unimplemented) device * Add various memory segments - OCRAM - OCRAM EPDC - OCRAM PXP - OCRAM S - ROM - CAAM Signed-off-by: Jean-Christophe Dubois Reviewed-by: Philippe Mathieu-Daudé Message-id: f887a3483996ba06d40bd62ffdfb0ecf68621987.1692964892.git.jcd@tribudubois.net Signed-off-by: Peter Maydell --- hw/arm/fsl-imx7.c | 63 +++++++++++++++++++++++++++++++++++++++ include/hw/arm/fsl-imx7.h | 7 +++++ 2 files changed, 70 insertions(+) diff --git a/hw/arm/fsl-imx7.c b/hw/arm/fsl-imx7.c index e976053539..97e982bf06 100644 --- a/hw/arm/fsl-imx7.c +++ b/hw/arm/fsl-imx7.c @@ -664,6 +664,69 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) create_unimplemented_device("pcie-phy", FSL_IMX7_PCIE_PHY_ADDR, FSL_IMX7_PCIE_PHY_SIZE); + /* + * CSU + */ + create_unimplemented_device("csu", FSL_IMX7_CSU_ADDR, + FSL_IMX7_CSU_SIZE); + + /* + * TZASC + */ + create_unimplemented_device("tzasc", FSL_IMX7_TZASC_ADDR, + FSL_IMX7_TZASC_SIZE); + + /* + * OCRAM memory + */ + memory_region_init_ram(&s->ocram, NULL, "imx7.ocram", + FSL_IMX7_OCRAM_MEM_SIZE, + &error_abort); + memory_region_add_subregion(get_system_memory(), FSL_IMX7_OCRAM_MEM_ADDR, + &s->ocram); + + /* + * OCRAM EPDC memory + */ + memory_region_init_ram(&s->ocram_epdc, NULL, "imx7.ocram_epdc", + FSL_IMX7_OCRAM_EPDC_SIZE, + &error_abort); + memory_region_add_subregion(get_system_memory(), FSL_IMX7_OCRAM_EPDC_ADDR, + &s->ocram_epdc); + + /* + * OCRAM PXP memory + */ + memory_region_init_ram(&s->ocram_pxp, NULL, "imx7.ocram_pxp", + FSL_IMX7_OCRAM_PXP_SIZE, + &error_abort); + memory_region_add_subregion(get_system_memory(), FSL_IMX7_OCRAM_PXP_ADDR, + &s->ocram_pxp); + + /* + * OCRAM_S memory + */ + memory_region_init_ram(&s->ocram_s, NULL, "imx7.ocram_s", + FSL_IMX7_OCRAM_S_SIZE, + &error_abort); + memory_region_add_subregion(get_system_memory(), FSL_IMX7_OCRAM_S_ADDR, + &s->ocram_s); + + /* + * ROM memory + */ + memory_region_init_rom(&s->rom, OBJECT(dev), "imx7.rom", + FSL_IMX7_ROM_SIZE, &error_abort); + memory_region_add_subregion(get_system_memory(), FSL_IMX7_ROM_ADDR, + &s->rom); + + /* + * CAAM memory + */ + memory_region_init_rom(&s->caam, OBJECT(dev), "imx7.caam", + FSL_IMX7_CAAM_MEM_SIZE, &error_abort); + memory_region_add_subregion(get_system_memory(), FSL_IMX7_CAAM_MEM_ADDR, + &s->caam); } static Property fsl_imx7_properties[] = { diff --git a/include/hw/arm/fsl-imx7.h b/include/hw/arm/fsl-imx7.h index 06b2c5e4ac..01e15004d7 100644 --- a/include/hw/arm/fsl-imx7.h +++ b/include/hw/arm/fsl-imx7.h @@ -84,6 +84,13 @@ struct FslIMX7State { IMX7GPRState gpr; ChipideaState usb[FSL_IMX7_NUM_USBS]; DesignwarePCIEHost pcie; + MemoryRegion rom; + MemoryRegion caam; + MemoryRegion ocram; + MemoryRegion ocram_epdc; + MemoryRegion ocram_pxp; + MemoryRegion ocram_s; + uint32_t phy_num[FSL_IMX7_NUM_ETHS]; bool phy_connected[FSL_IMX7_NUM_ETHS]; }; From 12517bc978e62ce19df0160ad2ef229169a567b2 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Dubois Date: Thu, 31 Aug 2023 09:45:17 +0100 Subject: [PATCH 1345/1353] Add i.MX7 SRC device implementation The SRC device is normally used to start the secondary CPU. When running Linux directly, QEMU is emulating a PSCI interface that UBOOT is installing at boot time and therefore the fact that the SRC device is unimplemented is hidden as Qemu respond directly to PSCI requets without using the SRC device. But if you try to run a more bare metal application (maybe uboot itself), then it is not possible to start the secondary CPU as the SRC is an unimplemented device. This patch adds the ability to start the secondary CPU through the SRC device so that you can use this feature in bare metal applications. Signed-off-by: Jean-Christophe Dubois Reviewed-by: Peter Maydell Message-id: ce9a0162defd2acee5dc7f8a674743de0cded569.1692964892.git.jcd@tribudubois.net Signed-off-by: Peter Maydell --- hw/arm/fsl-imx7.c | 8 +- hw/misc/imx7_src.c | 276 +++++++++++++++++++++++++++++++++++++ hw/misc/meson.build | 1 + hw/misc/trace-events | 4 + include/hw/arm/fsl-imx7.h | 3 +- include/hw/misc/imx7_src.h | 66 +++++++++ 6 files changed, 356 insertions(+), 2 deletions(-) create mode 100644 hw/misc/imx7_src.c create mode 100644 include/hw/misc/imx7_src.h diff --git a/hw/arm/fsl-imx7.c b/hw/arm/fsl-imx7.c index 97e982bf06..474cfdc87c 100644 --- a/hw/arm/fsl-imx7.c +++ b/hw/arm/fsl-imx7.c @@ -82,6 +82,11 @@ static void fsl_imx7_init(Object *obj) */ object_initialize_child(obj, "gpcv2", &s->gpcv2, TYPE_IMX_GPCV2); + /* + * SRC + */ + object_initialize_child(obj, "src", &s->src, TYPE_IMX7_SRC); + /* * ECSPIs */ @@ -488,7 +493,8 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp) /* * SRC */ - create_unimplemented_device("src", FSL_IMX7_SRC_ADDR, FSL_IMX7_SRC_SIZE); + sysbus_realize(SYS_BUS_DEVICE(&s->src), &error_abort); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->src), 0, FSL_IMX7_SRC_ADDR); /* * Watchdogs diff --git a/hw/misc/imx7_src.c b/hw/misc/imx7_src.c new file mode 100644 index 0000000000..983251e86f --- /dev/null +++ b/hw/misc/imx7_src.c @@ -0,0 +1,276 @@ +/* + * IMX7 System Reset Controller + * + * Copyright (c) 2023 Jean-Christophe Dubois + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "hw/misc/imx7_src.h" +#include "migration/vmstate.h" +#include "qemu/bitops.h" +#include "qemu/log.h" +#include "qemu/main-loop.h" +#include "qemu/module.h" +#include "target/arm/arm-powerctl.h" +#include "hw/core/cpu.h" +#include "hw/registerfields.h" + +#include "trace.h" + +static const char *imx7_src_reg_name(uint32_t reg) +{ + static char unknown[20]; + + switch (reg) { + case SRC_SCR: + return "SRC_SCR"; + case SRC_A7RCR0: + return "SRC_A7RCR0"; + case SRC_A7RCR1: + return "SRC_A7RCR1"; + case SRC_M4RCR: + return "SRC_M4RCR"; + case SRC_ERCR: + return "SRC_ERCR"; + case SRC_HSICPHY_RCR: + return "SRC_HSICPHY_RCR"; + case SRC_USBOPHY1_RCR: + return "SRC_USBOPHY1_RCR"; + case SRC_USBOPHY2_RCR: + return "SRC_USBOPHY2_RCR"; + case SRC_PCIEPHY_RCR: + return "SRC_PCIEPHY_RCR"; + case SRC_SBMR1: + return "SRC_SBMR1"; + case SRC_SRSR: + return "SRC_SRSR"; + case SRC_SISR: + return "SRC_SISR"; + case SRC_SIMR: + return "SRC_SIMR"; + case SRC_SBMR2: + return "SRC_SBMR2"; + case SRC_GPR1: + return "SRC_GPR1"; + case SRC_GPR2: + return "SRC_GPR2"; + case SRC_GPR3: + return "SRC_GPR3"; + case SRC_GPR4: + return "SRC_GPR4"; + case SRC_GPR5: + return "SRC_GPR5"; + case SRC_GPR6: + return "SRC_GPR6"; + case SRC_GPR7: + return "SRC_GPR7"; + case SRC_GPR8: + return "SRC_GPR8"; + case SRC_GPR9: + return "SRC_GPR9"; + case SRC_GPR10: + return "SRC_GPR10"; + default: + sprintf(unknown, "%u ?", reg); + return unknown; + } +} + +static const VMStateDescription vmstate_imx7_src = { + .name = TYPE_IMX7_SRC, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, IMX7SRCState, SRC_MAX), + VMSTATE_END_OF_LIST() + }, +}; + +static void imx7_src_reset(DeviceState *dev) +{ + IMX7SRCState *s = IMX7_SRC(dev); + + memset(s->regs, 0, sizeof(s->regs)); + + /* Set reset values */ + s->regs[SRC_SCR] = 0xA0; + s->regs[SRC_SRSR] = 0x1; + s->regs[SRC_SIMR] = 0x1F; +} + +static uint64_t imx7_src_read(void *opaque, hwaddr offset, unsigned size) +{ + uint32_t value = 0; + IMX7SRCState *s = (IMX7SRCState *)opaque; + uint32_t index = offset >> 2; + + if (index < SRC_MAX) { + value = s->regs[index]; + } else { + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" + HWADDR_PRIx "\n", TYPE_IMX7_SRC, __func__, offset); + } + + trace_imx7_src_read(imx7_src_reg_name(index), value); + + return value; +} + + +/* + * The reset is asynchronous so we need to defer clearing the reset + * bit until the work is completed. + */ + +struct SRCSCRResetInfo { + IMX7SRCState *s; + uint32_t reset_bit; +}; + +static void imx7_clear_reset_bit(CPUState *cpu, run_on_cpu_data data) +{ + struct SRCSCRResetInfo *ri = data.host_ptr; + IMX7SRCState *s = ri->s; + + assert(qemu_mutex_iothread_locked()); + + s->regs[SRC_A7RCR0] = deposit32(s->regs[SRC_A7RCR0], ri->reset_bit, 1, 0); + + trace_imx7_src_write(imx7_src_reg_name(SRC_A7RCR0), s->regs[SRC_A7RCR0]); + + g_free(ri); +} + +static void imx7_defer_clear_reset_bit(uint32_t cpuid, + IMX7SRCState *s, + uint32_t reset_shift) +{ + struct SRCSCRResetInfo *ri; + CPUState *cpu = arm_get_cpu_by_id(cpuid); + + if (!cpu) { + return; + } + + ri = g_new(struct SRCSCRResetInfo, 1); + ri->s = s; + ri->reset_bit = reset_shift; + + async_run_on_cpu(cpu, imx7_clear_reset_bit, RUN_ON_CPU_HOST_PTR(ri)); +} + + +static void imx7_src_write(void *opaque, hwaddr offset, uint64_t value, + unsigned size) +{ + IMX7SRCState *s = (IMX7SRCState *)opaque; + uint32_t index = offset >> 2; + long unsigned int change_mask; + uint32_t current_value = value; + + if (index >= SRC_MAX) { + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" + HWADDR_PRIx "\n", TYPE_IMX7_SRC, __func__, offset); + return; + } + + trace_imx7_src_write(imx7_src_reg_name(SRC_A7RCR0), s->regs[SRC_A7RCR0]); + + change_mask = s->regs[index] ^ (uint32_t)current_value; + + switch (index) { + case SRC_A7RCR0: + if (FIELD_EX32(change_mask, CORE0, RST)) { + arm_reset_cpu(0); + imx7_defer_clear_reset_bit(0, s, R_CORE0_RST_SHIFT); + } + if (FIELD_EX32(change_mask, CORE1, RST)) { + arm_reset_cpu(1); + imx7_defer_clear_reset_bit(1, s, R_CORE1_RST_SHIFT); + } + s->regs[index] = current_value; + break; + case SRC_A7RCR1: + /* + * On real hardware when the system reset controller starts a + * secondary CPU it runs through some boot ROM code which reads + * the SRC_GPRX registers controlling the start address and branches + * to it. + * Here we are taking a short cut and branching directly to the + * requested address (we don't want to run the boot ROM code inside + * QEMU) + */ + if (FIELD_EX32(change_mask, CORE1, ENABLE)) { + if (FIELD_EX32(current_value, CORE1, ENABLE)) { + /* CORE 1 is brought up */ + arm_set_cpu_on(1, s->regs[SRC_GPR3], s->regs[SRC_GPR4], + 3, false); + } else { + /* CORE 1 is shut down */ + arm_set_cpu_off(1); + } + /* We clear the reset bits as the processor changed state */ + imx7_defer_clear_reset_bit(1, s, R_CORE1_RST_SHIFT); + clear_bit(R_CORE1_RST_SHIFT, &change_mask); + } + s->regs[index] = current_value; + break; + default: + s->regs[index] = current_value; + break; + } +} + +static const struct MemoryRegionOps imx7_src_ops = { + .read = imx7_src_read, + .write = imx7_src_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + /* + * Our device would not work correctly if the guest was doing + * unaligned access. This might not be a limitation on the real + * device but in practice there is no reason for a guest to access + * this device unaligned. + */ + .min_access_size = 4, + .max_access_size = 4, + .unaligned = false, + }, +}; + +static void imx7_src_realize(DeviceState *dev, Error **errp) +{ + IMX7SRCState *s = IMX7_SRC(dev); + + memory_region_init_io(&s->iomem, OBJECT(dev), &imx7_src_ops, s, + TYPE_IMX7_SRC, 0x1000); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); +} + +static void imx7_src_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = imx7_src_realize; + dc->reset = imx7_src_reset; + dc->vmsd = &vmstate_imx7_src; + dc->desc = "i.MX6 System Reset Controller"; +} + +static const TypeInfo imx7_src_info = { + .name = TYPE_IMX7_SRC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IMX7SRCState), + .class_init = imx7_src_class_init, +}; + +static void imx7_src_register_types(void) +{ + type_register_static(&imx7_src_info); +} + +type_init(imx7_src_register_types) diff --git a/hw/misc/meson.build b/hw/misc/meson.build index 892f8b91c5..d9a370c1de 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -60,6 +60,7 @@ system_ss.add(when: 'CONFIG_IMX', if_true: files( 'imx6_src.c', 'imx6ul_ccm.c', 'imx7_ccm.c', + 'imx7_src.c', 'imx7_gpr.c', 'imx7_snvs.c', 'imx_ccm.c', diff --git a/hw/misc/trace-events b/hw/misc/trace-events index 4d1a0e17af..e8b2be14c0 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -199,6 +199,10 @@ ccm_clock_freq(uint32_t clock, uint32_t freq) "(Clock = %d) = %d" ccm_read_reg(const char *reg_name, uint32_t value) "reg[%s] <= 0x%" PRIx32 ccm_write_reg(const char *reg_name, uint32_t value) "reg[%s] => 0x%" PRIx32 +# imx7_src.c +imx7_src_read(const char *reg_name, uint32_t value) "reg[%s] => 0x%" PRIx32 +imx7_src_write(const char *reg_name, uint32_t value) "reg[%s] <= 0x%" PRIx32 + # iotkit-sysinfo.c iotkit_sysinfo_read(uint64_t offset, uint64_t data, unsigned size) "IoTKit SysInfo read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" iotkit_sysinfo_write(uint64_t offset, uint64_t data, unsigned size) "IoTKit SysInfo write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" diff --git a/include/hw/arm/fsl-imx7.h b/include/hw/arm/fsl-imx7.h index 01e15004d7..2cbfc6b2b2 100644 --- a/include/hw/arm/fsl-imx7.h +++ b/include/hw/arm/fsl-imx7.h @@ -25,6 +25,7 @@ #include "hw/misc/imx7_ccm.h" #include "hw/misc/imx7_snvs.h" #include "hw/misc/imx7_gpr.h" +#include "hw/misc/imx7_src.h" #include "hw/watchdog/wdt_imx2.h" #include "hw/gpio/imx_gpio.h" #include "hw/char/imx_serial.h" @@ -74,6 +75,7 @@ struct FslIMX7State { IMX7CCMState ccm; IMX7AnalogState analog; IMX7SNVSState snvs; + IMX7SRCState src; IMXGPCv2State gpcv2; IMXSPIState spi[FSL_IMX7_NUM_ECSPIS]; IMXI2CState i2c[FSL_IMX7_NUM_I2CS]; @@ -292,7 +294,6 @@ enum FslIMX7MemoryMap { FSL_IMX7_GPC_ADDR = 0x303A0000, FSL_IMX7_SRC_ADDR = 0x30390000, - FSL_IMX7_SRC_SIZE = (4 * KiB), FSL_IMX7_CCM_ADDR = 0x30380000, diff --git a/include/hw/misc/imx7_src.h b/include/hw/misc/imx7_src.h new file mode 100644 index 0000000000..b4b97dcb1c --- /dev/null +++ b/include/hw/misc/imx7_src.h @@ -0,0 +1,66 @@ +/* + * IMX7 System Reset Controller + * + * Copyright (C) 2023 Jean-Christophe Dubois + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef IMX7_SRC_H +#define IMX7_SRC_H + +#include "hw/sysbus.h" +#include "qemu/bitops.h" +#include "qom/object.h" + +#define SRC_SCR 0 +#define SRC_A7RCR0 1 +#define SRC_A7RCR1 2 +#define SRC_M4RCR 3 +#define SRC_ERCR 5 +#define SRC_HSICPHY_RCR 7 +#define SRC_USBOPHY1_RCR 8 +#define SRC_USBOPHY2_RCR 9 +#define SRC_MPIPHY_RCR 10 +#define SRC_PCIEPHY_RCR 11 +#define SRC_SBMR1 22 +#define SRC_SRSR 23 +#define SRC_SISR 26 +#define SRC_SIMR 27 +#define SRC_SBMR2 28 +#define SRC_GPR1 29 +#define SRC_GPR2 30 +#define SRC_GPR3 31 +#define SRC_GPR4 32 +#define SRC_GPR5 33 +#define SRC_GPR6 34 +#define SRC_GPR7 35 +#define SRC_GPR8 36 +#define SRC_GPR9 37 +#define SRC_GPR10 38 +#define SRC_MAX 39 + +/* SRC_A7SCR1 */ +#define R_CORE1_ENABLE_SHIFT 1 +#define R_CORE1_ENABLE_LENGTH 1 +/* SRC_A7SCR0 */ +#define R_CORE1_RST_SHIFT 5 +#define R_CORE1_RST_LENGTH 1 +#define R_CORE0_RST_SHIFT 4 +#define R_CORE0_RST_LENGTH 1 + +#define TYPE_IMX7_SRC "imx7.src" +OBJECT_DECLARE_SIMPLE_TYPE(IMX7SRCState, IMX7_SRC) + +struct IMX7SRCState { + /* */ + SysBusDevice parent_obj; + + /* */ + MemoryRegion iomem; + + uint32_t regs[SRC_MAX]; +}; + +#endif /* IMX7_SRC_H */ From 35aa6715ddcd9748bae5bc01563331e8eae8d7cf Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 31 Aug 2023 09:45:17 +0100 Subject: [PATCH 1346/1353] target/arm: Catch illegal-exception-return from EL3 with bad NSE/NS The architecture requires (R_TYTWB) that an attempt to return from EL3 when SCR_EL3.{NSE,NS} are {1,0} is an illegal exception return. (This enforces that the CPU can't ever be executing below EL3 with the NSE,NS bits indicating an invalid security state.) We were missing this check; add it. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20230807150618.101357-1-peter.maydell@linaro.org --- target/arm/tcg/helper-a64.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/target/arm/tcg/helper-a64.c b/target/arm/tcg/helper-a64.c index 1c9370f07b..0cf56f6dc4 100644 --- a/target/arm/tcg/helper-a64.c +++ b/target/arm/tcg/helper-a64.c @@ -780,6 +780,15 @@ void HELPER(exception_return)(CPUARMState *env, uint64_t new_pc) spsr &= ~PSTATE_SS; } + /* + * FEAT_RME forbids return from EL3 with an invalid security state. + * We don't need an explicit check for FEAT_RME here because we enforce + * in scr_write() that you can't set the NSE bit without it. + */ + if (cur_el == 3 && (env->cp15.scr_el3 & (SCR_NS | SCR_NSE)) == SCR_NSE) { + goto illegal_return; + } + new_el = el_from_spsr(spsr); if (new_el == -1) { goto illegal_return; From 7038b6e4e71d9fb3a234e00da31c222d3e97dd5c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 31 Aug 2023 09:45:17 +0100 Subject: [PATCH 1347/1353] hw/rtc/m48t59: Use 64-bit arithmetic in set_alarm() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the m48t59 device we almost always use 64-bit arithmetic when dealing with time_t deltas. The one exception is in set_alarm(), which currently uses a plain 'int' to hold the difference between two time_t values. Switch to int64_t instead to avoid any possible overflow issues. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé --- hw/rtc/m48t59.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/rtc/m48t59.c b/hw/rtc/m48t59.c index ec3e56e84f..2e2c849985 100644 --- a/hw/rtc/m48t59.c +++ b/hw/rtc/m48t59.c @@ -133,7 +133,7 @@ static void alarm_cb (void *opaque) static void set_alarm(M48t59State *NVRAM) { - int diff; + int64_t diff; if (NVRAM->alrm_timer != NULL) { timer_del(NVRAM->alrm_timer); diff = qemu_timedate_diff(&NVRAM->alarm) - NVRAM->time_offset; From 279695a4a4472c41d8764317e4fae04d93ee2b42 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 31 Aug 2023 09:45:18 +0100 Subject: [PATCH 1348/1353] hw/rtc/twl92230: Use int64_t for sec_offset and alm_sec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the twl92230 device, use int64_t for the two state fields sec_offset and alm_sec, because we set these to values that are either time_t or differences between two time_t values. These fields aren't saved in vmstate anywhere, so we can safely widen them. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé --- hw/rtc/twl92230.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/rtc/twl92230.c b/hw/rtc/twl92230.c index d8534dad94..64c61c3dae 100644 --- a/hw/rtc/twl92230.c +++ b/hw/rtc/twl92230.c @@ -65,8 +65,8 @@ struct MenelausState { struct tm tm; struct tm new; struct tm alm; - int sec_offset; - int alm_sec; + int64_t sec_offset; + int64_t alm_sec; int next_comp; } rtc; uint16_t rtc_next_vmstate; From c0a63857282afebaeed606a3dca803bb3bfb6aa3 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 31 Aug 2023 09:45:18 +0100 Subject: [PATCH 1349/1353] hw/rtc/aspeed_rtc: Use 64-bit offset for holding time_t difference MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the aspeed_rtc device we store a difference between two time_t values in an 'int'. This is not really correct when time_t could be 64 bits. Enlarge the field to 'int64_t'. This is a migration compatibility break for the aspeed boards. While we are changing the vmstate, remove the accidental duplicate of the offset field. Signed-off-by: Peter Maydell Reviewed-by: Cédric Le Goater --- hw/rtc/aspeed_rtc.c | 5 ++--- include/hw/rtc/aspeed_rtc.h | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/hw/rtc/aspeed_rtc.c b/hw/rtc/aspeed_rtc.c index f6da7b666d..fa861e2d49 100644 --- a/hw/rtc/aspeed_rtc.c +++ b/hw/rtc/aspeed_rtc.c @@ -136,11 +136,10 @@ static const MemoryRegionOps aspeed_rtc_ops = { static const VMStateDescription vmstate_aspeed_rtc = { .name = TYPE_ASPEED_RTC, - .version_id = 1, + .version_id = 2, .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(reg, AspeedRtcState, 0x18), - VMSTATE_INT32(offset, AspeedRtcState), - VMSTATE_INT32(offset, AspeedRtcState), + VMSTATE_INT64(offset, AspeedRtcState), VMSTATE_END_OF_LIST() } }; diff --git a/include/hw/rtc/aspeed_rtc.h b/include/hw/rtc/aspeed_rtc.h index df61e46059..596dfebb46 100644 --- a/include/hw/rtc/aspeed_rtc.h +++ b/include/hw/rtc/aspeed_rtc.h @@ -18,7 +18,7 @@ struct AspeedRtcState { qemu_irq irq; uint32_t reg[0x18]; - int offset; + int64_t offset; }; From 5ec008a2bd7e928d41d2a158120223311742d860 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 31 Aug 2023 09:45:18 +0100 Subject: [PATCH 1350/1353] rtc: Use time_t for passing and returning time offsets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The functions qemu_get_timedate() and qemu_timedate_diff() take and return a time offset as an integer. Coverity points out that means that when an RTC device implementation holds an offset as a time_t, as the m48t59 does, the time_t will get truncated. (CID 1507157, 1517772). The functions work with time_t internally, so make them use that type in their APIs. Note that this won't help any Y2038 issues where either the device model itself is keeping the offset in a 32-bit integer, or where the hardware under emulation has Y2038 or other rollover problems. If we missed any cases of the former then hopefully Coverity will warn us about them since after this patch we'd be truncating a time_t in assignments from qemu_timedate_diff().) Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé --- include/sysemu/rtc.h | 4 ++-- softmmu/rtc.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/sysemu/rtc.h b/include/sysemu/rtc.h index 159702b45b..0fc8ad6fdf 100644 --- a/include/sysemu/rtc.h +++ b/include/sysemu/rtc.h @@ -42,7 +42,7 @@ * The behaviour of the clock whose value this function returns will * depend on the -rtc command line option passed by the user. */ -void qemu_get_timedate(struct tm *tm, int offset); +void qemu_get_timedate(struct tm *tm, time_t offset); /** * qemu_timedate_diff: Return difference between a struct tm and the RTC @@ -53,6 +53,6 @@ void qemu_get_timedate(struct tm *tm, int offset); * a timestamp one hour further ahead than the current RTC time * then this function will return 3600. */ -int qemu_timedate_diff(struct tm *tm); +time_t qemu_timedate_diff(struct tm *tm); #endif diff --git a/softmmu/rtc.c b/softmmu/rtc.c index 4b2bf75dd6..4904581abe 100644 --- a/softmmu/rtc.c +++ b/softmmu/rtc.c @@ -68,7 +68,7 @@ static time_t qemu_ref_timedate(QEMUClockType clock) return value; } -void qemu_get_timedate(struct tm *tm, int offset) +void qemu_get_timedate(struct tm *tm, time_t offset) { time_t ti = qemu_ref_timedate(rtc_clock); @@ -85,7 +85,7 @@ void qemu_get_timedate(struct tm *tm, int offset) } } -int qemu_timedate_diff(struct tm *tm) +time_t qemu_timedate_diff(struct tm *tm) { time_t seconds; From b8f7959f28c4f36496bc0a694fa28bf5078152c5 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 24 Jul 2023 18:43:33 +0100 Subject: [PATCH 1351/1353] target/arm: Do all "ARM_FEATURE_X implies Y" checks in post_init Where architecturally one ARM_FEATURE_X flag implies another ARM_FEATURE_Y, we allow the CPU init function to only set X, and then set Y for it. Currently we do this in two places -- we set a few flags in arm_cpu_post_init() because we need them to decide which properties to create on the CPU object, and then we do the rest in arm_cpu_realizefn(). However, this is fragile, because it's easy to add a new property and not notice that this means that an X-implies-Y check now has to move from realize to post-init. As a specific example, the pmsav7-dregion property is conditional on ARM_FEATURE_PMSA && ARM_FEATURE_V7, which means it won't appear on the Cortex-M33 and -M55, because they set ARM_FEATURE_V8 and rely on V8-implies-V7, which doesn't happen until the realizefn. Move all of these X-implies-Y checks into a new function, which we call at the top of arm_cpu_post_init(), so the feature bits are available at that point. This does now give us the reverse issue, that if there's a feature bit which is enabled or disabled by the setting of a property then then X-implies-Y features that are dependent on that property need to be in realize, not in this new function. But the only one of those is the "EL3 implies VBAR" which is already in the right place, so putting things this way round seems better to me. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20230724174335.2150499-2-peter.maydell@linaro.org --- target/arm/cpu.c | 179 +++++++++++++++++++++++++---------------------- 1 file changed, 97 insertions(+), 82 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 17540300fe..0bb0585441 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1356,17 +1356,108 @@ unsigned int gt_cntfrq_period_ns(ARMCPU *cpu) NANOSECONDS_PER_SECOND / cpu->gt_cntfrq_hz : 1; } +static void arm_cpu_propagate_feature_implications(ARMCPU *cpu) +{ + CPUARMState *env = &cpu->env; + bool no_aa32 = false; + + /* + * Some features automatically imply others: set the feature + * bits explicitly for these cases. + */ + + if (arm_feature(env, ARM_FEATURE_M)) { + set_feature(env, ARM_FEATURE_PMSA); + } + + if (arm_feature(env, ARM_FEATURE_V8)) { + if (arm_feature(env, ARM_FEATURE_M)) { + set_feature(env, ARM_FEATURE_V7); + } else { + set_feature(env, ARM_FEATURE_V7VE); + } + } + + /* + * There exist AArch64 cpus without AArch32 support. When KVM + * queries ID_ISAR0_EL1 on such a host, the value is UNKNOWN. + * Similarly, we cannot check ID_AA64PFR0 without AArch64 support. + * As a general principle, we also do not make ID register + * consistency checks anywhere unless using TCG, because only + * for TCG would a consistency-check failure be a QEMU bug. + */ + if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { + no_aa32 = !cpu_isar_feature(aa64_aa32, cpu); + } + + if (arm_feature(env, ARM_FEATURE_V7VE)) { + /* + * v7 Virtualization Extensions. In real hardware this implies + * EL2 and also the presence of the Security Extensions. + * For QEMU, for backwards-compatibility we implement some + * CPUs or CPU configs which have no actual EL2 or EL3 but do + * include the various other features that V7VE implies. + * Presence of EL2 itself is ARM_FEATURE_EL2, and of the + * Security Extensions is ARM_FEATURE_EL3. + */ + assert(!tcg_enabled() || no_aa32 || + cpu_isar_feature(aa32_arm_div, cpu)); + set_feature(env, ARM_FEATURE_LPAE); + set_feature(env, ARM_FEATURE_V7); + } + if (arm_feature(env, ARM_FEATURE_V7)) { + set_feature(env, ARM_FEATURE_VAPA); + set_feature(env, ARM_FEATURE_THUMB2); + set_feature(env, ARM_FEATURE_MPIDR); + if (!arm_feature(env, ARM_FEATURE_M)) { + set_feature(env, ARM_FEATURE_V6K); + } else { + set_feature(env, ARM_FEATURE_V6); + } + + /* + * Always define VBAR for V7 CPUs even if it doesn't exist in + * non-EL3 configs. This is needed by some legacy boards. + */ + set_feature(env, ARM_FEATURE_VBAR); + } + if (arm_feature(env, ARM_FEATURE_V6K)) { + set_feature(env, ARM_FEATURE_V6); + set_feature(env, ARM_FEATURE_MVFR); + } + if (arm_feature(env, ARM_FEATURE_V6)) { + set_feature(env, ARM_FEATURE_V5); + if (!arm_feature(env, ARM_FEATURE_M)) { + assert(!tcg_enabled() || no_aa32 || + cpu_isar_feature(aa32_jazelle, cpu)); + set_feature(env, ARM_FEATURE_AUXCR); + } + } + if (arm_feature(env, ARM_FEATURE_V5)) { + set_feature(env, ARM_FEATURE_V4T); + } + if (arm_feature(env, ARM_FEATURE_LPAE)) { + set_feature(env, ARM_FEATURE_V7MP); + } + if (arm_feature(env, ARM_FEATURE_CBAR_RO)) { + set_feature(env, ARM_FEATURE_CBAR); + } + if (arm_feature(env, ARM_FEATURE_THUMB2) && + !arm_feature(env, ARM_FEATURE_M)) { + set_feature(env, ARM_FEATURE_THUMB_DSP); + } +} + void arm_cpu_post_init(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); - /* M profile implies PMSA. We have to do this here rather than - * in realize with the other feature-implication checks because - * we look at the PMSA bit to see if we should add some properties. + /* + * Some features imply others. Figure this out now, because we + * are going to look at the feature bits in deciding which + * properties to add. */ - if (arm_feature(&cpu->env, ARM_FEATURE_M)) { - set_feature(&cpu->env, ARM_FEATURE_PMSA); - } + arm_cpu_propagate_feature_implications(cpu); if (arm_feature(&cpu->env, ARM_FEATURE_CBAR) || arm_feature(&cpu->env, ARM_FEATURE_CBAR_RO)) { @@ -1588,7 +1679,6 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) CPUARMState *env = &cpu->env; int pagebits; Error *local_err = NULL; - bool no_aa32 = false; /* Use pc-relative instructions in system-mode */ #ifndef CONFIG_USER_ONLY @@ -1869,81 +1959,6 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) cpu->isar.id_isar3 = u; } - /* Some features automatically imply others: */ - if (arm_feature(env, ARM_FEATURE_V8)) { - if (arm_feature(env, ARM_FEATURE_M)) { - set_feature(env, ARM_FEATURE_V7); - } else { - set_feature(env, ARM_FEATURE_V7VE); - } - } - - /* - * There exist AArch64 cpus without AArch32 support. When KVM - * queries ID_ISAR0_EL1 on such a host, the value is UNKNOWN. - * Similarly, we cannot check ID_AA64PFR0 without AArch64 support. - * As a general principle, we also do not make ID register - * consistency checks anywhere unless using TCG, because only - * for TCG would a consistency-check failure be a QEMU bug. - */ - if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { - no_aa32 = !cpu_isar_feature(aa64_aa32, cpu); - } - - if (arm_feature(env, ARM_FEATURE_V7VE)) { - /* v7 Virtualization Extensions. In real hardware this implies - * EL2 and also the presence of the Security Extensions. - * For QEMU, for backwards-compatibility we implement some - * CPUs or CPU configs which have no actual EL2 or EL3 but do - * include the various other features that V7VE implies. - * Presence of EL2 itself is ARM_FEATURE_EL2, and of the - * Security Extensions is ARM_FEATURE_EL3. - */ - assert(!tcg_enabled() || no_aa32 || - cpu_isar_feature(aa32_arm_div, cpu)); - set_feature(env, ARM_FEATURE_LPAE); - set_feature(env, ARM_FEATURE_V7); - } - if (arm_feature(env, ARM_FEATURE_V7)) { - set_feature(env, ARM_FEATURE_VAPA); - set_feature(env, ARM_FEATURE_THUMB2); - set_feature(env, ARM_FEATURE_MPIDR); - if (!arm_feature(env, ARM_FEATURE_M)) { - set_feature(env, ARM_FEATURE_V6K); - } else { - set_feature(env, ARM_FEATURE_V6); - } - - /* Always define VBAR for V7 CPUs even if it doesn't exist in - * non-EL3 configs. This is needed by some legacy boards. - */ - set_feature(env, ARM_FEATURE_VBAR); - } - if (arm_feature(env, ARM_FEATURE_V6K)) { - set_feature(env, ARM_FEATURE_V6); - set_feature(env, ARM_FEATURE_MVFR); - } - if (arm_feature(env, ARM_FEATURE_V6)) { - set_feature(env, ARM_FEATURE_V5); - if (!arm_feature(env, ARM_FEATURE_M)) { - assert(!tcg_enabled() || no_aa32 || - cpu_isar_feature(aa32_jazelle, cpu)); - set_feature(env, ARM_FEATURE_AUXCR); - } - } - if (arm_feature(env, ARM_FEATURE_V5)) { - set_feature(env, ARM_FEATURE_V4T); - } - if (arm_feature(env, ARM_FEATURE_LPAE)) { - set_feature(env, ARM_FEATURE_V7MP); - } - if (arm_feature(env, ARM_FEATURE_CBAR_RO)) { - set_feature(env, ARM_FEATURE_CBAR); - } - if (arm_feature(env, ARM_FEATURE_THUMB2) && - !arm_feature(env, ARM_FEATURE_M)) { - set_feature(env, ARM_FEATURE_THUMB_DSP); - } /* * We rely on no XScale CPU having VFP so we can use the same bits in the From cb0929bb1344d095c9e7980e3803562b8b3cd604 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 24 Jul 2023 18:43:34 +0100 Subject: [PATCH 1352/1353] hw/arm/armv7m: Add mpu-ns-regions and mpu-s-regions properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit M-profile CPUs generally allow configuration of the number of MPU regions that they have. We don't currently model this, so our implementations of some of the board models provide CPUs with the wrong number of regions. RTOSes like Zephyr that hardcode the expected number of regions may therefore not run on the model if they are set up to run on real hardware. Add properties mpu-ns-regions and mpu-s-regions to the ARMV7M object, matching the ability of hardware to configure the number of Secure and NonSecure regions separately. Our actual CPU implementation doesn't currently support that, and it happens that none of the MPS boards we model set the number of regions differently for Secure vs NonSecure, so we provide an interface to the boards and SoCs that won't need to change if we ever do add that functionality in future, but make it an error to configure the two properties to different values. (The property name on the CPU is the somewhat misnamed-for-M-profile "pmsav7-dregion", so we don't follow that naming convention for the properties here. The TRM doesn't say what the CPU configuration variable names are, so we pick something, and follow the lowercase convention we already have for properties here.) Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Message-id: 20230724174335.2150499-3-peter.maydell@linaro.org --- hw/arm/armv7m.c | 21 +++++++++++++++++++++ include/hw/arm/armv7m.h | 8 ++++++++ 2 files changed, 29 insertions(+) diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c index 50a9507c0b..bf173b10b8 100644 --- a/hw/arm/armv7m.c +++ b/hw/arm/armv7m.c @@ -334,6 +334,25 @@ static void armv7m_realize(DeviceState *dev, Error **errp) } } + /* + * Real M-profile hardware can be configured with a different number of + * MPU regions for Secure vs NonSecure. QEMU's CPU implementation doesn't + * support that yet, so catch attempts to select that. + */ + if (arm_feature(&s->cpu->env, ARM_FEATURE_M_SECURITY) && + s->mpu_ns_regions != s->mpu_s_regions) { + error_setg(errp, + "mpu-ns-regions and mpu-s-regions properties must have the same value"); + return; + } + if (s->mpu_ns_regions != UINT_MAX && + object_property_find(OBJECT(s->cpu), "pmsav7-dregion")) { + if (!object_property_set_uint(OBJECT(s->cpu), "pmsav7-dregion", + s->mpu_ns_regions, errp)) { + return; + } + } + /* * Tell the CPU where the NVIC is; it will fail realize if it doesn't * have one. Similarly, tell the NVIC where its CPU is. @@ -530,6 +549,8 @@ static Property armv7m_properties[] = { false), DEFINE_PROP_BOOL("vfp", ARMv7MState, vfp, true), DEFINE_PROP_BOOL("dsp", ARMv7MState, dsp, true), + DEFINE_PROP_UINT32("mpu-ns-regions", ARMv7MState, mpu_ns_regions, UINT_MAX), + DEFINE_PROP_UINT32("mpu-s-regions", ARMv7MState, mpu_s_regions, UINT_MAX), DEFINE_PROP_END_OF_LIST(), }; diff --git a/include/hw/arm/armv7m.h b/include/hw/arm/armv7m.h index b7ba0ff409..e2cebbd15c 100644 --- a/include/hw/arm/armv7m.h +++ b/include/hw/arm/armv7m.h @@ -52,6 +52,12 @@ OBJECT_DECLARE_SIMPLE_TYPE(ARMv7MState, ARMV7M) * + Property "vfp": enable VFP (forwarded to CPU object) * + Property "dsp": enable DSP (forwarded to CPU object) * + Property "enable-bitband": expose bitbanded IO + * + Property "mpu-ns-regions": number of Non-Secure MPU regions (forwarded + * to CPU object pmsav7-dregion property; default is whatever the default + * for the CPU is) + * + Property "mpu-s-regions": number of Secure MPU regions (default is + * whatever the default for the CPU is; must currently be set to the same + * value as mpu-ns-regions if the CPU implements the Security Extension) * + Clock input "refclk" is the external reference clock for the systick timers * + Clock input "cpuclk" is the main CPU clock */ @@ -95,6 +101,8 @@ struct ARMv7MState { Object *idau; uint32_t init_svtor; uint32_t init_nsvtor; + uint32_t mpu_ns_regions; + uint32_t mpu_s_regions; bool enable_bitband; bool start_powered_off; bool vfp; From e73b8bb8a3e9a162f70e9ffbf922d4fafc96bbfb Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 24 Jul 2023 18:43:35 +0100 Subject: [PATCH 1353/1353] hw/arm: Set number of MPU regions correctly for an505, an521, an524 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The IoTKit, SSE200 and SSE300 all default to 8 MPU regions. The MPS2/MPS3 FPGA images don't override these except in the case of AN547, which uses 16 MPU regions. Define properties on the ARMSSE object for the MPU regions (using the same names as the documented RTL configuration settings, and following the pattern we already have for this device of using all-caps names as the RTL does), and set them in the board code. We don't actually need to override the default except on AN547, but it's simpler code to have the board code set them always rather than tracking which board subtypes want to set them to a non-default value separately from what that value is. Tho overall effect is that for mps2-an505, mps2-an521 and mps3-an524 we now correctly use 8 MPU regions, while mps3-an547 stays at its current 16 regions. It's possible some guest code wrongly depended on the previous incorrectly modeled number of memory regions. (Such guest code should ideally check the number of regions via the MPU_TYPE register.) The old behaviour can be obtained with additional -global arguments to QEMU: For mps2-an521 and mps2-an524: -global sse-200.CPU0_MPU_NS=16 -global sse-200.CPU0_MPU_S=16 -global sse-200.CPU1_MPU_NS=16 -global sse-200.CPU1_MPU_S=16 For mps2-an505: -global sse-200.CPU0_MPU_NS=16 -global sse-200.CPU0_MPU_S=16 NB that the way the implementation allows this use of -global is slightly fragile: if the board code explicitly sets the properties on the sse-200 object, this overrides the -global command line option. So we rely on: - the boards that need fixing all happen to use the SSE defaults - we can write the board code to only set the property if it is different from the default, rather than having all boards explicitly set the property - the board that does need to use a non-default value happens to need to set it to the same value (16) we previously used This works, but there are some kinds of refactoring of the mps2-tz.c code that would break the support for -global here. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1772 Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20230724174335.2150499-4-peter.maydell@linaro.org --- hw/arm/armsse.c | 16 ++++++++++++++++ hw/arm/mps2-tz.c | 29 +++++++++++++++++++++++++++++ include/hw/arm/armsse.h | 5 +++++ 3 files changed, 50 insertions(+) diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c index 0202bad787..11cd08b6c1 100644 --- a/hw/arm/armsse.c +++ b/hw/arm/armsse.c @@ -85,6 +85,8 @@ static Property iotkit_properties[] = { DEFINE_PROP_UINT32("init-svtor", ARMSSE, init_svtor, 0x10000000), DEFINE_PROP_BOOL("CPU0_FPU", ARMSSE, cpu_fpu[0], true), DEFINE_PROP_BOOL("CPU0_DSP", ARMSSE, cpu_dsp[0], true), + DEFINE_PROP_UINT32("CPU0_MPU_NS", ARMSSE, cpu_mpu_ns[0], 8), + DEFINE_PROP_UINT32("CPU0_MPU_S", ARMSSE, cpu_mpu_s[0], 8), DEFINE_PROP_END_OF_LIST() }; @@ -98,6 +100,10 @@ static Property sse200_properties[] = { DEFINE_PROP_BOOL("CPU0_DSP", ARMSSE, cpu_dsp[0], false), DEFINE_PROP_BOOL("CPU1_FPU", ARMSSE, cpu_fpu[1], true), DEFINE_PROP_BOOL("CPU1_DSP", ARMSSE, cpu_dsp[1], true), + DEFINE_PROP_UINT32("CPU0_MPU_NS", ARMSSE, cpu_mpu_ns[0], 8), + DEFINE_PROP_UINT32("CPU0_MPU_S", ARMSSE, cpu_mpu_s[0], 8), + DEFINE_PROP_UINT32("CPU1_MPU_NS", ARMSSE, cpu_mpu_ns[1], 8), + DEFINE_PROP_UINT32("CPU1_MPU_S", ARMSSE, cpu_mpu_s[1], 8), DEFINE_PROP_END_OF_LIST() }; @@ -109,6 +115,8 @@ static Property sse300_properties[] = { DEFINE_PROP_UINT32("init-svtor", ARMSSE, init_svtor, 0x10000000), DEFINE_PROP_BOOL("CPU0_FPU", ARMSSE, cpu_fpu[0], true), DEFINE_PROP_BOOL("CPU0_DSP", ARMSSE, cpu_dsp[0], true), + DEFINE_PROP_UINT32("CPU0_MPU_NS", ARMSSE, cpu_mpu_ns[0], 8), + DEFINE_PROP_UINT32("CPU0_MPU_S", ARMSSE, cpu_mpu_s[0], 8), DEFINE_PROP_END_OF_LIST() }; @@ -1029,6 +1037,14 @@ static void armsse_realize(DeviceState *dev, Error **errp) return; } } + if (!object_property_set_uint(cpuobj, "mpu-ns-regions", + s->cpu_mpu_ns[i], errp)) { + return; + } + if (!object_property_set_uint(cpuobj, "mpu-s-regions", + s->cpu_mpu_s[i], errp)) { + return; + } if (i > 0) { memory_region_add_subregion_overlap(&s->cpu_container[i], 0, diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c index 5873107302..eae3639da2 100644 --- a/hw/arm/mps2-tz.c +++ b/hw/arm/mps2-tz.c @@ -124,6 +124,10 @@ struct MPS2TZMachineClass { int uart_overflow_irq; /* number of the combined UART overflow IRQ */ uint32_t init_svtor; /* init-svtor setting for SSE */ uint32_t sram_addr_width; /* SRAM_ADDR_WIDTH setting for SSE */ + uint32_t cpu0_mpu_ns; /* CPU0_MPU_NS setting for SSE */ + uint32_t cpu0_mpu_s; /* CPU0_MPU_S setting for SSE */ + uint32_t cpu1_mpu_ns; /* CPU1_MPU_NS setting for SSE */ + uint32_t cpu1_mpu_s; /* CPU1_MPU_S setting for SSE */ const RAMInfo *raminfo; const char *armsse_type; uint32_t boot_ram_size; /* size of ram at address 0; 0 == find in raminfo */ @@ -183,6 +187,9 @@ OBJECT_DECLARE_TYPE(MPS2TZMachineState, MPS2TZMachineClass, MPS2TZ_MACHINE) #define MPS3_DDR_SIZE (2 * GiB) #endif +/* For cpu{0,1}_mpu_{ns,s}, means "leave at SSE's default value" */ +#define MPU_REGION_DEFAULT UINT32_MAX + static const uint32_t an505_oscclk[] = { 40000000, 24580000, @@ -828,6 +835,20 @@ static void mps2tz_common_init(MachineState *machine) OBJECT(system_memory), &error_abort); qdev_prop_set_uint32(iotkitdev, "EXP_NUMIRQ", mmc->numirq); qdev_prop_set_uint32(iotkitdev, "init-svtor", mmc->init_svtor); + if (mmc->cpu0_mpu_ns != MPU_REGION_DEFAULT) { + qdev_prop_set_uint32(iotkitdev, "CPU0_MPU_NS", mmc->cpu0_mpu_ns); + } + if (mmc->cpu0_mpu_s != MPU_REGION_DEFAULT) { + qdev_prop_set_uint32(iotkitdev, "CPU0_MPU_S", mmc->cpu0_mpu_s); + } + if (object_property_find(OBJECT(iotkitdev), "CPU1_MPU_NS")) { + if (mmc->cpu1_mpu_ns != MPU_REGION_DEFAULT) { + qdev_prop_set_uint32(iotkitdev, "CPU1_MPU_NS", mmc->cpu1_mpu_ns); + } + if (mmc->cpu1_mpu_s != MPU_REGION_DEFAULT) { + qdev_prop_set_uint32(iotkitdev, "CPU1_MPU_S", mmc->cpu1_mpu_s); + } + } qdev_prop_set_uint32(iotkitdev, "SRAM_ADDR_WIDTH", mmc->sram_addr_width); qdev_connect_clock_in(iotkitdev, "MAINCLK", mms->sysclk); qdev_connect_clock_in(iotkitdev, "S32KCLK", mms->s32kclk); @@ -1256,10 +1277,17 @@ static void mps2tz_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); IDAUInterfaceClass *iic = IDAU_INTERFACE_CLASS(oc); + MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_CLASS(oc); mc->init = mps2tz_common_init; mc->reset = mps2_machine_reset; iic->check = mps2_tz_idau_check; + + /* Most machines leave these at the SSE defaults */ + mmc->cpu0_mpu_ns = MPU_REGION_DEFAULT; + mmc->cpu0_mpu_s = MPU_REGION_DEFAULT; + mmc->cpu1_mpu_ns = MPU_REGION_DEFAULT; + mmc->cpu1_mpu_s = MPU_REGION_DEFAULT; } static void mps2tz_set_default_ram_info(MPS2TZMachineClass *mmc) @@ -1396,6 +1424,7 @@ static void mps3tz_an547_class_init(ObjectClass *oc, void *data) mmc->numirq = 96; mmc->uart_overflow_irq = 48; mmc->init_svtor = 0x00000000; + mmc->cpu0_mpu_s = mmc->cpu0_mpu_ns = 16; mmc->sram_addr_width = 21; mmc->raminfo = an547_raminfo; mmc->armsse_type = TYPE_SSE300; diff --git a/include/hw/arm/armsse.h b/include/hw/arm/armsse.h index cd0931d0a0..88b3b759c5 100644 --- a/include/hw/arm/armsse.h +++ b/include/hw/arm/armsse.h @@ -56,6 +56,9 @@ * (matching the hardware) is that for CPU0 in an IoTKit and CPU1 in an * SSE-200 both are present; CPU0 in an SSE-200 has neither. * Since the IoTKit has only one CPU, it does not have the CPU1_* properties. + * + QOM properties "CPU0_MPU_NS", "CPU0_MPU_S", "CPU1_MPU_NS" and "CPU1_MPU_S" + * which set the number of MPU regions on the CPUs. If there is only one + * CPU the CPU1 properties are not present. * + Named GPIO inputs "EXP_IRQ" 0..n are the expansion interrupts for CPU 0, * which are wired to its NVIC lines 32 .. n+32 * + Named GPIO inputs "EXP_CPU1_IRQ" 0..n are the expansion interrupts for @@ -221,6 +224,8 @@ struct ARMSSE { uint32_t exp_numirq; uint32_t sram_addr_width; uint32_t init_svtor; + uint32_t cpu_mpu_ns[SSE_MAX_CPUS]; + uint32_t cpu_mpu_s[SSE_MAX_CPUS]; bool cpu_fpu[SSE_MAX_CPUS]; bool cpu_dsp[SSE_MAX_CPUS]; };

Tv|dEj+< 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�Q(n`eL48ogtbSfu{@R1Q51~c85J`>gV{1kKx@y#(spJ5@7);8^z9M^P1sZ z$V1=-eq^Q5JCBF0gbg%%*rW6U?>=H@2`43ToQE5PZzOVo6C&`R{f9)pAVTxyl#vK1 zIq;s-T_SgQpbO=UP0$RVa}M3chw~lw1Zh4@P|hN{Lk{=k89uZsX9MA7iPYlZ7~v4B zO66)5X^nPKmKL_$)Yp{IjMxw0w%icX(Y72GosDumdH9vU@hhWT8#JsWL6-W;HQ@o; zBjTh|vYcCvmK;%+kRo5ZY4lkb1P=ul`CPt0S}(}i8KFd`<+!V~QNBdNc9{CJ zyj3*fP@oab2~CCU4#>(Zb;N^&Zi1+mmP-8F)Q>97qTb#n$_d~CLE8!FQiW6+7)7ee z%0p{3;q_wV2^R9}HEm?ky8To`&A&z4_9s(@T2iX?qp42{W%Q+487JMJaq|5cC##Hf zMp4hnRDm&D8Ebu7NgByL5$ljxF}SO&t6X4+sn3WM;|om8On_|4giUQugoebjOs0G8 zkk(CegM|^-XDcgAWNQVaB^^0KVZB%dtOqP>`i+>>?d>&f+dHNnuej%XC$G~hl?5sn zw?@~W4VZeOXu}hkauboMSEgS-c2>(AH#D1A6^7Gtaq(ginB3`p21(yQ@%yaW)K-L(}SDgQSr)dp*;Kju&yx@=I4@@=3Nq%No^=KtcJ|b+CcVX;n zJ#3ESw1K?reRwZn2QVD@arFe7_(j4QU?}7G3bNcp9Fz2L5wL;#%<Y-cDk+)x_%+|^$1%KtpPHuHG=IUp2)Q0SU?9OifQchn>3&=L4T233@ z(8S{c#lIb;YR$DY60gj~B_(p2@qVa6)o8gRE~i;_5i)${4asQ+&*~X*G;3y88~)QN zK#3sOCMO;H5E4f^jjUxfrkmt6m%`P3?XRuQ4vUZizK9t+DPJRkLY~_nBLXKvXC8J2 zwb|P7D>wwJ3}Y&)F(pEQ;~A$XcS}eIX={`ZS)XvOCAo@?Ki^k|<7cakE(w&eC);tEGAebm%ec(i zL8u;%%XRP7V@ranhvVb>%lP>IGCsM#j8CjG!V_JoEfTUFeWi@NnDH8qaXe17x1#V= z7Ma$`ptFF07S27A?Pw_2I}~<98WVZUNOZ+lIiBsPB`G&!#`EPKBKQYN1ZVpYp;VVvGZ=lY(pxjcD!U8 zpQ!eZ90`q2R0jrSZqIDvQzZkrw}0)XY~vA%N*ouHI|;N$Qt)THlkM@xi8Qv0+S@YQ z7*oS;@-m%+dKK40J*s6Joyl2QvzU}#!E^R-w8`jPTXMz-^PTCvT1L!7^vdYm1{^2U z_pQh_chzY_-jUt2^}C_GOI2R|E>^y>9C*w&bR`(Mhc&7}w*FNJ@oNk5D^*Bv zh2Pa6a5h{2lv-9PVI_TQMS~ z44}5MlcMYdXv^