From 6eab278d389bc3569135773265e0d481d89ef82e Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Tue, 9 Jul 2024 19:36:42 +0800 Subject: [PATCH 01/30] target/riscv: Add zimop extension Zimop extension defines an encoding space for 40 MOPs.The Zimop extension defines 32 MOP instructions named MOP.R.n, where n is an integer between 0 and 31, inclusive. The Zimop extension additionally defines 8 MOP instructions named MOP.RR.n, where n is an integer between 0 and 7. These 40 MOPs initially are defined to simply write zero to x[rd], but are designed to be redefined by later extensions to perform some other action. Signed-off-by: LIU Zhiwei Reviewed-by: Alistair Francis Reviewed-by: Deepak Gupta Message-ID: <20240709113652.1239-2-zhiwei_liu@linux.alibaba.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 2 ++ target/riscv/cpu_cfg.h | 1 + target/riscv/insn32.decode | 11 ++++++ target/riscv/insn_trans/trans_rvzimop.c.inc | 37 +++++++++++++++++++++ target/riscv/translate.c | 1 + 5 files changed, 52 insertions(+) create mode 100644 target/riscv/insn_trans/trans_rvzimop.c.inc diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index c53b0d5b40..ac503826ce 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -113,6 +113,7 @@ const RISCVIsaExtData isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(zihintntl, PRIV_VERSION_1_10_0, ext_zihintntl), ISA_EXT_DATA_ENTRY(zihintpause, PRIV_VERSION_1_10_0, ext_zihintpause), ISA_EXT_DATA_ENTRY(zihpm, PRIV_VERSION_1_12_0, ext_zihpm), + ISA_EXT_DATA_ENTRY(zimop, PRIV_VERSION_1_13_0, ext_zimop), ISA_EXT_DATA_ENTRY(zmmul, PRIV_VERSION_1_12_0, ext_zmmul), ISA_EXT_DATA_ENTRY(za64rs, PRIV_VERSION_1_12_0, has_priv_1_11), ISA_EXT_DATA_ENTRY(zaamo, PRIV_VERSION_1_12_0, ext_zaamo), @@ -1471,6 +1472,7 @@ const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = { MULTI_EXT_CFG_BOOL("zicsr", ext_zicsr, true), MULTI_EXT_CFG_BOOL("zihintntl", ext_zihintntl, true), MULTI_EXT_CFG_BOOL("zihintpause", ext_zihintpause, true), + MULTI_EXT_CFG_BOOL("zimop", ext_zimop, false), MULTI_EXT_CFG_BOOL("zacas", ext_zacas, false), MULTI_EXT_CFG_BOOL("zaamo", ext_zaamo, false), MULTI_EXT_CFG_BOOL("zalrsc", ext_zalrsc, false), diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h index fb7eebde52..9f53512053 100644 --- a/target/riscv/cpu_cfg.h +++ b/target/riscv/cpu_cfg.h @@ -71,6 +71,7 @@ struct RISCVCPUConfig { bool ext_zihintntl; bool ext_zihintpause; bool ext_zihpm; + bool ext_zimop; bool ext_ztso; bool ext_smstateen; bool ext_sstc; diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index f22df04cfd..60da673153 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -38,6 +38,8 @@ %imm_bs 30:2 !function=ex_shift_3 %imm_rnum 20:4 %imm_z6 26:1 15:5 +%imm_mop5 30:1 26:2 20:2 +%imm_mop3 30:1 26:2 # Argument sets: &empty @@ -56,6 +58,8 @@ &r2nfvm vm rd rs1 nf &rnfvm vm rd rs1 rs2 nf &k_aes shamt rs2 rs1 rd +&mop5 imm rd rs1 +&mop3 imm rd rs1 rs2 # Formats 32: @r ....... ..... ..... ... ..... ....... &r %rs2 %rs1 %rd @@ -98,6 +102,9 @@ @k_aes .. ..... ..... ..... ... ..... ....... &k_aes shamt=%imm_bs %rs2 %rs1 %rd @i_aes .. ..... ..... ..... ... ..... ....... &i imm=%imm_rnum %rs1 %rd +@mop5 . . .. .. .... .. ..... ... ..... ....... &mop5 imm=%imm_mop5 %rd %rs1 +@mop3 . . .. .. . ..... ..... ... ..... ....... &mop3 imm=%imm_mop3 %rd %rs1 %rs2 + # Formats 64: @sh5 ....... ..... ..... ... ..... ....... &shift shamt=%sh5 %rs1 %rd @@ -1010,3 +1017,7 @@ amocas_w 00101 . . ..... ..... 010 ..... 0101111 @atom_st amocas_d 00101 . . ..... ..... 011 ..... 0101111 @atom_st # *** RV64 Zacas Standard Extension *** amocas_q 00101 . . ..... ..... 100 ..... 0101111 @atom_st + +# *** Zimop may-be-operation extension *** +mop_r_n 1 . 00 .. 0111 .. ..... 100 ..... 1110011 @mop5 +mop_rr_n 1 . 00 .. 1 ..... ..... 100 ..... 1110011 @mop3 diff --git a/target/riscv/insn_trans/trans_rvzimop.c.inc b/target/riscv/insn_trans/trans_rvzimop.c.inc new file mode 100644 index 0000000000..165aacd2b6 --- /dev/null +++ b/target/riscv/insn_trans/trans_rvzimop.c.inc @@ -0,0 +1,37 @@ +/* + * RISC-V translation routines for May-Be-Operation(zimop). + * + * Copyright (c) 2024 Alibaba Group. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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 . + */ + +#define REQUIRE_ZIMOP(ctx) do { \ + if (!ctx->cfg_ptr->ext_zimop) { \ + return false; \ + } \ +} while (0) + +static bool trans_mop_r_n(DisasContext *ctx, arg_mop_r_n *a) +{ + REQUIRE_ZIMOP(ctx); + gen_set_gpr(ctx, a->rd, ctx->zero); + return true; +} + +static bool trans_mop_rr_n(DisasContext *ctx, arg_mop_rr_n *a) +{ + REQUIRE_ZIMOP(ctx); + gen_set_gpr(ctx, a->rd, ctx->zero); + return true; +} diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 0569224e53..379b68289f 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -1099,6 +1099,7 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc) #include "insn_trans/trans_rvzacas.c.inc" #include "insn_trans/trans_rvzawrs.c.inc" #include "insn_trans/trans_rvzicbo.c.inc" +#include "insn_trans/trans_rvzimop.c.inc" #include "insn_trans/trans_rvzfa.c.inc" #include "insn_trans/trans_rvzfh.c.inc" #include "insn_trans/trans_rvk.c.inc" From d98883d127d0029532601e9ca6832dfcb3ee2ca0 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Tue, 9 Jul 2024 19:36:43 +0800 Subject: [PATCH 02/30] disas/riscv: Support zimop disassemble Signed-off-by: LIU Zhiwei Acked-by: Alistair Francis Reviewed-by: Deepak Gupta Message-ID: <20240709113652.1239-3-zhiwei_liu@linux.alibaba.com> Signed-off-by: Alistair Francis --- disas/riscv.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/disas/riscv.c b/disas/riscv.c index 90d6b26de9..0b82ab2322 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -906,6 +906,46 @@ typedef enum { rv_op_amocas_w = 875, rv_op_amocas_d = 876, rv_op_amocas_q = 877, + rv_mop_r_0 = 878, + rv_mop_r_1 = 879, + rv_mop_r_2 = 880, + rv_mop_r_3 = 881, + rv_mop_r_4 = 882, + rv_mop_r_5 = 883, + rv_mop_r_6 = 884, + rv_mop_r_7 = 885, + rv_mop_r_8 = 886, + rv_mop_r_9 = 887, + rv_mop_r_10 = 888, + rv_mop_r_11 = 889, + rv_mop_r_12 = 890, + rv_mop_r_13 = 891, + rv_mop_r_14 = 892, + rv_mop_r_15 = 893, + rv_mop_r_16 = 894, + rv_mop_r_17 = 895, + rv_mop_r_18 = 896, + rv_mop_r_19 = 897, + rv_mop_r_20 = 898, + rv_mop_r_21 = 899, + rv_mop_r_22 = 900, + rv_mop_r_23 = 901, + rv_mop_r_24 = 902, + rv_mop_r_25 = 903, + rv_mop_r_26 = 904, + rv_mop_r_27 = 905, + rv_mop_r_28 = 906, + rv_mop_r_29 = 907, + rv_mop_r_30 = 908, + rv_mop_r_31 = 909, + rv_mop_rr_0 = 910, + rv_mop_rr_1 = 911, + rv_mop_rr_2 = 912, + rv_mop_rr_3 = 913, + rv_mop_rr_4 = 914, + rv_mop_rr_5 = 915, + rv_mop_rr_6 = 916, + rv_mop_rr_7 = 917, } rv_op; /* register names */ @@ -2096,6 +2136,46 @@ const rv_opcode_data rvi_opcode_data[] = { { "amocas.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, { "amocas.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, { "amocas.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, + { "mop.r.0", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "mop.r.1", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "mop.r.2", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "mop.r.3", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "mop.r.4", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "mop.r.5", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "mop.r.6", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "mop.r.7", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "mop.r.8", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "mop.r.9", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "mop.r.10", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "mop.r.11", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "mop.r.12", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "mop.r.13", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "mop.r.14", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "mop.r.15", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "mop.r.16", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "mop.r.17", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "mop.r.18", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "mop.r.19", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "mop.r.20", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "mop.r.21", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "mop.r.22", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "mop.r.23", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "mop.r.24", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "mop.r.25", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "mop.r.26", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "mop.r.27", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "mop.r.28", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "mop.r.29", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "mop.r.30", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "mop.r.31", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 }, + { "mop.rr.0", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "mop.rr.1", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "mop.rr.2", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "mop.rr.3", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "mop.rr.4", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "mop.rr.5", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "mop.rr.6", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "mop.rr.7", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, }; /* CSR names */ @@ -3855,6 +3935,24 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa) case 1: op = rv_op_csrrw; break; case 2: op = rv_op_csrrs; break; case 3: op = rv_op_csrrc; break; + case 4: + if (dec->cfg->ext_zimop) { + int imm_mop5, imm_mop3; + if ((extract32(inst, 22, 10) & 0b1011001111) + == 0b1000000111) { + imm_mop5 = deposit32(deposit32(extract32(inst, 20, 2), + 2, 2, + extract32(inst, 26, 2)), + 4, 1, extract32(inst, 30, 1)); + op = rv_mop_r_0 + imm_mop5; + } else if ((extract32(inst, 25, 7) & 0b1011001) + == 0b1000001) { + imm_mop3 = deposit32(extract32(inst, 26, 2), + 2, 1, extract32(inst, 30, 1)); + op = rv_mop_rr_0 + imm_mop3; + } + } + break; case 5: op = rv_op_csrrwi; break; case 6: op = rv_op_csrrsi; break; case 7: op = rv_op_csrrci; break; From 197e4d29889453760c74763662e3812d0ec7a645 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Tue, 9 Jul 2024 19:36:44 +0800 Subject: [PATCH 03/30] target/riscv: Add zcmop extension Zcmop defines eight 16-bit MOP instructions named C.MOP.n, where n is an odd integer between 1 and 15, inclusive. C.MOP.n is encoded in the reserved encoding space corresponding to C.LUI xn, 0. Unlike the MOPs defined in the Zimop extension, the C.MOP.n instructions are defined to not write any register. In current implementation, C.MOP.n only has an check function, without any other more behavior. Signed-off-by: LIU Zhiwei Reviewed-by: Alistair Francis Reviewed-by: Deepak Gupta Message-ID: <20240709113652.1239-4-zhiwei_liu@linux.alibaba.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 2 ++ target/riscv/cpu_cfg.h | 1 + target/riscv/insn16.decode | 1 + target/riscv/insn_trans/trans_rvzcmop.c.inc | 29 +++++++++++++++++++++ target/riscv/tcg/tcg-cpu.c | 5 ++++ target/riscv/translate.c | 1 + 6 files changed, 39 insertions(+) create mode 100644 target/riscv/insn_trans/trans_rvzcmop.c.inc diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index ac503826ce..f4f8287a6d 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -131,6 +131,7 @@ const RISCVIsaExtData isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(zcf, PRIV_VERSION_1_12_0, ext_zcf), ISA_EXT_DATA_ENTRY(zcd, PRIV_VERSION_1_12_0, ext_zcd), ISA_EXT_DATA_ENTRY(zce, PRIV_VERSION_1_12_0, ext_zce), + ISA_EXT_DATA_ENTRY(zcmop, PRIV_VERSION_1_13_0, ext_zcmop), ISA_EXT_DATA_ENTRY(zcmp, PRIV_VERSION_1_12_0, ext_zcmp), ISA_EXT_DATA_ENTRY(zcmt, PRIV_VERSION_1_12_0, ext_zcmt), ISA_EXT_DATA_ENTRY(zba, PRIV_VERSION_1_12_0, ext_zba), @@ -1473,6 +1474,7 @@ const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = { MULTI_EXT_CFG_BOOL("zihintntl", ext_zihintntl, true), MULTI_EXT_CFG_BOOL("zihintpause", ext_zihintpause, true), MULTI_EXT_CFG_BOOL("zimop", ext_zimop, false), + MULTI_EXT_CFG_BOOL("zcmop", ext_zcmop, false), MULTI_EXT_CFG_BOOL("zacas", ext_zacas, false), MULTI_EXT_CFG_BOOL("zaamo", ext_zaamo, false), MULTI_EXT_CFG_BOOL("zalrsc", ext_zalrsc, false), diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h index 9f53512053..d85e54b475 100644 --- a/target/riscv/cpu_cfg.h +++ b/target/riscv/cpu_cfg.h @@ -72,6 +72,7 @@ struct RISCVCPUConfig { bool ext_zihintpause; bool ext_zihpm; bool ext_zimop; + bool ext_zcmop; bool ext_ztso; bool ext_smstateen; bool ext_sstc; diff --git a/target/riscv/insn16.decode b/target/riscv/insn16.decode index b96c534e73..3953bcf82d 100644 --- a/target/riscv/insn16.decode +++ b/target/riscv/insn16.decode @@ -140,6 +140,7 @@ sw 110 ... ... .. ... 00 @cs_w addi 000 . ..... ..... 01 @ci addi 010 . ..... ..... 01 @c_li { + c_mop_n 011 0 0 n:3 1 00000 01 illegal 011 0 ----- 00000 01 # c.addi16sp and c.lui, RES nzimm=0 addi 011 . 00010 ..... 01 @c_addi16sp lui 011 . ..... ..... 01 @c_lui diff --git a/target/riscv/insn_trans/trans_rvzcmop.c.inc b/target/riscv/insn_trans/trans_rvzcmop.c.inc new file mode 100644 index 0000000000..7205586508 --- /dev/null +++ b/target/riscv/insn_trans/trans_rvzcmop.c.inc @@ -0,0 +1,29 @@ +/* + * RISC-V translation routines for compressed May-Be-Operation(zcmop). + * + * Copyright (c) 2024 Alibaba Group. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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 . + */ + +#define REQUIRE_ZCMOP(ctx) do { \ + if (!ctx->cfg_ptr->ext_zcmop) { \ + return false; \ + } \ +} while (0) + +static bool trans_c_mop_n(DisasContext *ctx, arg_c_mop_n *a) +{ + REQUIRE_ZCMOP(ctx); + return true; +} diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index ecf366d6c7..b8814ab753 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -549,6 +549,11 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) } } + if (cpu->cfg.ext_zcmop && !cpu->cfg.ext_zca) { + error_setg(errp, "Zcmop extensions require Zca"); + return; + } + if (mcc->misa_mxl_max != MXL_RV32 && cpu->cfg.ext_zcf) { error_setg(errp, "Zcf extension is only relevant to RV32"); return; diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 379b68289f..8a546f4ece 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -1114,6 +1114,7 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc) /* Include the auto-generated decoder for 16 bit insn */ #include "decode-insn16.c.inc" #include "insn_trans/trans_rvzce.c.inc" +#include "insn_trans/trans_rvzcmop.c.inc" /* Include decoders for factored-out extensions */ #include "decode-XVentanaCondOps.c.inc" From 67e98ebad063e8b028466a754578dd8386aaa5f6 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Tue, 9 Jul 2024 19:36:45 +0800 Subject: [PATCH 04/30] disas/riscv: Support zcmop disassemble Although in QEMU disassemble, we usually lift compressed instruction to an normal format when display the instruction name. For C.MOP.n, it is more reasonable to directly display its compressed name, because its behavior can be redefined by later extension. Signed-off-by: LIU Zhiwei Acked-by: Alistair Francis Reviewed-by: Deepak Gupta Message-ID: <20240709113652.1239-5-zhiwei_liu@linux.alibaba.com> Signed-off-by: Alistair Francis --- disas/riscv.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/disas/riscv.c b/disas/riscv.c index 0b82ab2322..d29cb1ff7d 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -946,6 +946,14 @@ typedef enum { rv_mop_rr_5 = 915, rv_mop_rr_6 = 916, rv_mop_rr_7 = 917, + rv_c_mop_1 = 918, + rv_c_mop_3 = 919, + rv_c_mop_5 = 920, + rv_c_mop_7 = 921, + rv_c_mop_9 = 922, + rv_c_mop_11 = 923, + rv_c_mop_13 = 924, + rv_c_mop_15 = 925, } rv_op; /* register names */ @@ -2176,6 +2184,14 @@ const rv_opcode_data rvi_opcode_data[] = { { "mop.rr.5", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, { "mop.rr.6", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, { "mop.rr.7", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 }, + { "c.mop.1", rv_codec_ci_none, rv_fmt_none, NULL, 0, 0, 0 }, + { "c.mop.3", rv_codec_ci_none, rv_fmt_none, NULL, 0, 0, 0 }, + { "c.mop.5", rv_codec_ci_none, rv_fmt_none, NULL, 0, 0, 0 }, + { "c.mop.7", rv_codec_ci_none, rv_fmt_none, NULL, 0, 0, 0 }, + { "c.mop.9", rv_codec_ci_none, rv_fmt_none, NULL, 0, 0, 0 }, + { "c.mop.11", rv_codec_ci_none, rv_fmt_none, NULL, 0, 0, 0 }, + { "c.mop.13", rv_codec_ci_none, rv_fmt_none, NULL, 0, 0, 0 }, + { "c.mop.15", rv_codec_ci_none, rv_fmt_none, NULL, 0, 0, 0 }, }; /* CSR names */ @@ -2532,6 +2548,13 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa) break; case 2: op = rv_op_c_li; break; case 3: + if (dec->cfg->ext_zcmop) { + if ((((inst >> 2) & 0b111111) == 0b100000) && + (((inst >> 11) & 0b11) == 0b0)) { + op = rv_c_mop_1 + ((inst >> 8) & 0b111); + break; + } + } switch ((inst >> 7) & 0b11111) { case 2: op = rv_op_c_addi16sp; break; default: op = rv_op_c_lui; break; From a60ce58fd971bdcbec6ba96ce989fd399ca1f2d7 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Tue, 9 Jul 2024 19:36:46 +0800 Subject: [PATCH 05/30] target/riscv: Support Zama16b extension MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Zama16b is the property that misaligned load/stores/atomics within a naturally aligned 16-byte region are atomic. According to the specification, Zama16b applies only to AMOs, loads and stores defined in the base ISAs, and loads and stores of no more than XLEN bits defined in the F, D, and Q extensions. Thus it should not apply to zacas or RVC instructions. For an instruction in that set, if all accessed bytes lie within 16B granule, the instruction will not raise an exception for reasons of address alignment, and the instruction will give rise to only one memory operation for the purposes of RVWMO—i.e., it will execute atomically. Signed-off-by: LIU Zhiwei Reviewed-by: Alistair Francis Message-ID: <20240709113652.1239-6-zhiwei_liu@linux.alibaba.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 2 ++ target/riscv/cpu_cfg.h | 1 + target/riscv/insn_trans/trans_rva.c.inc | 42 ++++++++++++++----------- target/riscv/insn_trans/trans_rvd.c.inc | 14 +++++++-- target/riscv/insn_trans/trans_rvf.c.inc | 14 +++++++-- target/riscv/insn_trans/trans_rvi.c.inc | 6 ++++ 6 files changed, 57 insertions(+), 22 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index f4f8287a6d..de9c06904f 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -118,6 +118,7 @@ const RISCVIsaExtData isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(za64rs, PRIV_VERSION_1_12_0, has_priv_1_11), ISA_EXT_DATA_ENTRY(zaamo, PRIV_VERSION_1_12_0, ext_zaamo), ISA_EXT_DATA_ENTRY(zacas, PRIV_VERSION_1_12_0, ext_zacas), + ISA_EXT_DATA_ENTRY(zama16b, PRIV_VERSION_1_13_0, ext_zama16b), ISA_EXT_DATA_ENTRY(zalrsc, PRIV_VERSION_1_12_0, ext_zalrsc), ISA_EXT_DATA_ENTRY(zawrs, PRIV_VERSION_1_12_0, ext_zawrs), ISA_EXT_DATA_ENTRY(zfa, PRIV_VERSION_1_12_0, ext_zfa), @@ -1476,6 +1477,7 @@ const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = { MULTI_EXT_CFG_BOOL("zimop", ext_zimop, false), MULTI_EXT_CFG_BOOL("zcmop", ext_zcmop, false), MULTI_EXT_CFG_BOOL("zacas", ext_zacas, false), + MULTI_EXT_CFG_BOOL("zama16b", ext_zama16b, false), MULTI_EXT_CFG_BOOL("zaamo", ext_zaamo, false), MULTI_EXT_CFG_BOOL("zalrsc", ext_zalrsc, false), MULTI_EXT_CFG_BOOL("zawrs", ext_zawrs, true), diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h index d85e54b475..ddbfae37e5 100644 --- a/target/riscv/cpu_cfg.h +++ b/target/riscv/cpu_cfg.h @@ -83,6 +83,7 @@ struct RISCVCPUConfig { bool ext_zdinx; bool ext_zaamo; bool ext_zacas; + bool ext_zama16b; bool ext_zalrsc; bool ext_zawrs; bool ext_zfa; diff --git a/target/riscv/insn_trans/trans_rva.c.inc b/target/riscv/insn_trans/trans_rva.c.inc index 4a9e4591d1..eb080baddd 100644 --- a/target/riscv/insn_trans/trans_rva.c.inc +++ b/target/riscv/insn_trans/trans_rva.c.inc @@ -103,6 +103,12 @@ static bool gen_amo(DisasContext *ctx, arg_atomic *a, TCGv dest = dest_gpr(ctx, a->rd); TCGv src1, src2 = get_gpr(ctx, a->rs2, EXT_NONE); + if (ctx->cfg_ptr->ext_zama16b) { + mop |= MO_ATOM_WITHIN16; + } else { + mop |= MO_ALIGN; + } + decode_save_opc(ctx); src1 = get_address(ctx, a->rs1, 0); func(dest, src1, src2, ctx->mem_idx, mop); @@ -126,55 +132,55 @@ static bool trans_sc_w(DisasContext *ctx, arg_sc_w *a) static bool trans_amoswap_w(DisasContext *ctx, arg_amoswap_w *a) { REQUIRE_A_OR_ZAAMO(ctx); - return gen_amo(ctx, a, &tcg_gen_atomic_xchg_tl, (MO_ALIGN | MO_TESL)); + return gen_amo(ctx, a, &tcg_gen_atomic_xchg_tl, MO_TESL); } static bool trans_amoadd_w(DisasContext *ctx, arg_amoadd_w *a) { REQUIRE_A_OR_ZAAMO(ctx); - return gen_amo(ctx, a, &tcg_gen_atomic_fetch_add_tl, (MO_ALIGN | MO_TESL)); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_add_tl, MO_TESL); } static bool trans_amoxor_w(DisasContext *ctx, arg_amoxor_w *a) { REQUIRE_A_OR_ZAAMO(ctx); - return gen_amo(ctx, a, &tcg_gen_atomic_fetch_xor_tl, (MO_ALIGN | MO_TESL)); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_xor_tl, MO_TESL); } static bool trans_amoand_w(DisasContext *ctx, arg_amoand_w *a) { REQUIRE_A_OR_ZAAMO(ctx); - return gen_amo(ctx, a, &tcg_gen_atomic_fetch_and_tl, (MO_ALIGN | MO_TESL)); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_and_tl, MO_TESL); } static bool trans_amoor_w(DisasContext *ctx, arg_amoor_w *a) { REQUIRE_A_OR_ZAAMO(ctx); - return gen_amo(ctx, a, &tcg_gen_atomic_fetch_or_tl, (MO_ALIGN | MO_TESL)); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_or_tl, MO_TESL); } static bool trans_amomin_w(DisasContext *ctx, arg_amomin_w *a) { REQUIRE_A_OR_ZAAMO(ctx); - return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smin_tl, (MO_ALIGN | MO_TESL)); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smin_tl, MO_TESL); } static bool trans_amomax_w(DisasContext *ctx, arg_amomax_w *a) { REQUIRE_A_OR_ZAAMO(ctx); - return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smax_tl, (MO_ALIGN | MO_TESL)); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smax_tl, MO_TESL); } static bool trans_amominu_w(DisasContext *ctx, arg_amominu_w *a) { REQUIRE_A_OR_ZAAMO(ctx); - return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umin_tl, (MO_ALIGN | MO_TESL)); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umin_tl, MO_TESL); } static bool trans_amomaxu_w(DisasContext *ctx, arg_amomaxu_w *a) { REQUIRE_A_OR_ZAAMO(ctx); - return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, (MO_ALIGN | MO_TESL)); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, MO_TESL); } static bool trans_lr_d(DisasContext *ctx, arg_lr_d *a) @@ -195,61 +201,61 @@ static bool trans_amoswap_d(DisasContext *ctx, arg_amoswap_d *a) { REQUIRE_64BIT(ctx); REQUIRE_A_OR_ZAAMO(ctx); - return gen_amo(ctx, a, &tcg_gen_atomic_xchg_tl, (MO_ALIGN | MO_TEUQ)); + return gen_amo(ctx, a, &tcg_gen_atomic_xchg_tl, MO_TEUQ); } static bool trans_amoadd_d(DisasContext *ctx, arg_amoadd_d *a) { REQUIRE_64BIT(ctx); REQUIRE_A_OR_ZAAMO(ctx); - return gen_amo(ctx, a, &tcg_gen_atomic_fetch_add_tl, (MO_ALIGN | MO_TEUQ)); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_add_tl, MO_TEUQ); } static bool trans_amoxor_d(DisasContext *ctx, arg_amoxor_d *a) { REQUIRE_64BIT(ctx); REQUIRE_A_OR_ZAAMO(ctx); - return gen_amo(ctx, a, &tcg_gen_atomic_fetch_xor_tl, (MO_ALIGN | MO_TEUQ)); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_xor_tl, MO_TEUQ); } static bool trans_amoand_d(DisasContext *ctx, arg_amoand_d *a) { REQUIRE_64BIT(ctx); REQUIRE_A_OR_ZAAMO(ctx); - return gen_amo(ctx, a, &tcg_gen_atomic_fetch_and_tl, (MO_ALIGN | MO_TEUQ)); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_and_tl, MO_TEUQ); } static bool trans_amoor_d(DisasContext *ctx, arg_amoor_d *a) { REQUIRE_64BIT(ctx); REQUIRE_A_OR_ZAAMO(ctx); - return gen_amo(ctx, a, &tcg_gen_atomic_fetch_or_tl, (MO_ALIGN | MO_TEUQ)); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_or_tl, MO_TEUQ); } static bool trans_amomin_d(DisasContext *ctx, arg_amomin_d *a) { REQUIRE_64BIT(ctx); REQUIRE_A_OR_ZAAMO(ctx); - return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smin_tl, (MO_ALIGN | MO_TEUQ)); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smin_tl, MO_TEUQ); } static bool trans_amomax_d(DisasContext *ctx, arg_amomax_d *a) { REQUIRE_64BIT(ctx); REQUIRE_A_OR_ZAAMO(ctx); - return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smax_tl, (MO_ALIGN | MO_TEUQ)); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smax_tl, MO_TEUQ); } static bool trans_amominu_d(DisasContext *ctx, arg_amominu_d *a) { REQUIRE_64BIT(ctx); REQUIRE_A_OR_ZAAMO(ctx); - return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umin_tl, (MO_ALIGN | MO_TEUQ)); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umin_tl, MO_TEUQ); } static bool trans_amomaxu_d(DisasContext *ctx, arg_amomaxu_d *a) { REQUIRE_64BIT(ctx); REQUIRE_A_OR_ZAAMO(ctx); - return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, (MO_ALIGN | MO_TEUQ)); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, MO_TEUQ); } diff --git a/target/riscv/insn_trans/trans_rvd.c.inc b/target/riscv/insn_trans/trans_rvd.c.inc index d9ce9e407f..1f5fac65a2 100644 --- a/target/riscv/insn_trans/trans_rvd.c.inc +++ b/target/riscv/insn_trans/trans_rvd.c.inc @@ -42,13 +42,18 @@ static bool trans_fld(DisasContext *ctx, arg_fld *a) { TCGv addr; + MemOp memop = MO_TEUQ; REQUIRE_FPU; REQUIRE_EXT(ctx, RVD); + if (ctx->cfg_ptr->ext_zama16b && (ctx->cur_insn_len != 2)) { + memop |= MO_ATOM_WITHIN16; + } + decode_save_opc(ctx); addr = get_address(ctx, a->rs1, a->imm); - tcg_gen_qemu_ld_i64(cpu_fpr[a->rd], addr, ctx->mem_idx, MO_TEUQ); + tcg_gen_qemu_ld_i64(cpu_fpr[a->rd], addr, ctx->mem_idx, memop); mark_fs_dirty(ctx); return true; @@ -57,13 +62,18 @@ static bool trans_fld(DisasContext *ctx, arg_fld *a) static bool trans_fsd(DisasContext *ctx, arg_fsd *a) { TCGv addr; + MemOp memop = MO_TEUQ; REQUIRE_FPU; REQUIRE_EXT(ctx, RVD); + if (ctx->cfg_ptr->ext_zama16b && (ctx->cur_insn_len != 2)) { + memop |= MO_ATOM_WITHIN16; + } + decode_save_opc(ctx); addr = get_address(ctx, a->rs1, a->imm); - tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], addr, ctx->mem_idx, MO_TEUQ); + tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], addr, ctx->mem_idx, memop); return true; } diff --git a/target/riscv/insn_trans/trans_rvf.c.inc b/target/riscv/insn_trans/trans_rvf.c.inc index 97a368970b..f771aa1939 100644 --- a/target/riscv/insn_trans/trans_rvf.c.inc +++ b/target/riscv/insn_trans/trans_rvf.c.inc @@ -43,14 +43,19 @@ static bool trans_flw(DisasContext *ctx, arg_flw *a) { TCGv_i64 dest; TCGv addr; + MemOp memop = MO_TEUL; REQUIRE_FPU; REQUIRE_EXT(ctx, RVF); + if (ctx->cfg_ptr->ext_zama16b && (ctx->cur_insn_len != 2)) { + memop |= MO_ATOM_WITHIN16; + } + decode_save_opc(ctx); addr = get_address(ctx, a->rs1, a->imm); dest = cpu_fpr[a->rd]; - tcg_gen_qemu_ld_i64(dest, addr, ctx->mem_idx, MO_TEUL); + tcg_gen_qemu_ld_i64(dest, addr, ctx->mem_idx, memop); gen_nanbox_s(dest, dest); mark_fs_dirty(ctx); @@ -60,13 +65,18 @@ static bool trans_flw(DisasContext *ctx, arg_flw *a) static bool trans_fsw(DisasContext *ctx, arg_fsw *a) { TCGv addr; + MemOp memop = MO_TEUL; REQUIRE_FPU; REQUIRE_EXT(ctx, RVF); + if (ctx->cfg_ptr->ext_zama16b && (ctx->cur_insn_len != 2)) { + memop |= MO_ATOM_WITHIN16; + } + decode_save_opc(ctx); addr = get_address(ctx, a->rs1, a->imm); - tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], addr, ctx->mem_idx, MO_TEUL); + tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], addr, ctx->mem_idx, memop); return true; } diff --git a/target/riscv/insn_trans/trans_rvi.c.inc b/target/riscv/insn_trans/trans_rvi.c.inc index ad40d3e87f..98e3806d5e 100644 --- a/target/riscv/insn_trans/trans_rvi.c.inc +++ b/target/riscv/insn_trans/trans_rvi.c.inc @@ -268,6 +268,9 @@ static bool gen_load(DisasContext *ctx, arg_lb *a, MemOp memop) { bool out; + if (ctx->cfg_ptr->ext_zama16b && (ctx->cur_insn_len != 2)) { + memop |= MO_ATOM_WITHIN16; + } decode_save_opc(ctx); if (get_xl(ctx) == MXL_RV128) { out = gen_load_i128(ctx, a, memop); @@ -366,6 +369,9 @@ static bool gen_store_i128(DisasContext *ctx, arg_sb *a, MemOp memop) static bool gen_store(DisasContext *ctx, arg_sb *a, MemOp memop) { + if (ctx->cfg_ptr->ext_zama16b && (ctx->cur_insn_len != 2)) { + memop |= MO_ATOM_WITHIN16; + } decode_save_opc(ctx); if (get_xl(ctx) == MXL_RV128) { return gen_store_i128(ctx, a, memop); From 24da9cbacacadaf95fbddc11da81ff68d3b1e795 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Tue, 9 Jul 2024 19:36:47 +0800 Subject: [PATCH 06/30] target/riscv: Move gen_amo before implement Zabha Signed-off-by: LIU Zhiwei Acked-by: Alistair Francis Message-ID: <20240709113652.1239-7-zhiwei_liu@linux.alibaba.com> Signed-off-by: Alistair Francis --- target/riscv/insn_trans/trans_rva.c.inc | 21 --------------------- target/riscv/translate.c | 21 +++++++++++++++++++++ 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/target/riscv/insn_trans/trans_rva.c.inc b/target/riscv/insn_trans/trans_rva.c.inc index eb080baddd..39bbf60f3c 100644 --- a/target/riscv/insn_trans/trans_rva.c.inc +++ b/target/riscv/insn_trans/trans_rva.c.inc @@ -96,27 +96,6 @@ static bool gen_sc(DisasContext *ctx, arg_atomic *a, MemOp mop) return true; } -static bool gen_amo(DisasContext *ctx, arg_atomic *a, - void(*func)(TCGv, TCGv, TCGv, TCGArg, MemOp), - MemOp mop) -{ - TCGv dest = dest_gpr(ctx, a->rd); - TCGv src1, src2 = get_gpr(ctx, a->rs2, EXT_NONE); - - if (ctx->cfg_ptr->ext_zama16b) { - mop |= MO_ATOM_WITHIN16; - } else { - mop |= MO_ALIGN; - } - - decode_save_opc(ctx); - src1 = get_address(ctx, a->rs1, 0); - func(dest, src1, src2, ctx->mem_idx, mop); - - gen_set_gpr(ctx, a->rd, dest); - return true; -} - static bool trans_lr_w(DisasContext *ctx, arg_lr_w *a) { REQUIRE_A_OR_ZALRSC(ctx); diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 8a546f4ece..133550d6e2 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -1077,6 +1077,27 @@ static bool gen_unary_per_ol(DisasContext *ctx, arg_r2 *a, DisasExtend ext, return gen_unary(ctx, a, ext, f_tl); } +static bool gen_amo(DisasContext *ctx, arg_atomic *a, + void(*func)(TCGv, TCGv, TCGv, TCGArg, MemOp), + MemOp mop) +{ + TCGv dest = dest_gpr(ctx, a->rd); + TCGv src1, src2 = get_gpr(ctx, a->rs2, EXT_NONE); + + if (ctx->cfg_ptr->ext_zama16b) { + mop |= MO_ATOM_WITHIN16; + } else { + mop |= MO_ALIGN; + } + + decode_save_opc(ctx); + src1 = get_address(ctx, a->rs1, 0); + func(dest, src1, src2, ctx->mem_idx, mop); + + gen_set_gpr(ctx, a->rd, dest); + return true; +} + static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc) { DisasContext *ctx = container_of(dcbase, DisasContext, base); From be4a8db7f304347395b081ae5848bad2f507d0c4 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Tue, 9 Jul 2024 19:36:48 +0800 Subject: [PATCH 07/30] target/riscv: Add AMO instructions for Zabha Signed-off-by: LIU Zhiwei Acked-by: Alistair Francis Message-ID: <20240709113652.1239-8-zhiwei_liu@linux.alibaba.com> Signed-off-by: Alistair Francis --- target/riscv/cpu_cfg.h | 1 + target/riscv/insn32.decode | 20 +++ target/riscv/insn_trans/trans_rvzabha.c.inc | 131 ++++++++++++++++++++ target/riscv/translate.c | 4 +- 4 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 target/riscv/insn_trans/trans_rvzabha.c.inc diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h index ddbfae37e5..120905a254 100644 --- a/target/riscv/cpu_cfg.h +++ b/target/riscv/cpu_cfg.h @@ -84,6 +84,7 @@ struct RISCVCPUConfig { bool ext_zaamo; bool ext_zacas; bool ext_zama16b; + bool ext_zabha; bool ext_zalrsc; bool ext_zawrs; bool ext_zfa; diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 60da673153..3bad6372f2 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -1021,3 +1021,23 @@ amocas_q 00101 . . ..... ..... 100 ..... 0101111 @atom_st # *** Zimop may-be-operation extension *** mop_r_n 1 . 00 .. 0111 .. ..... 100 ..... 1110011 @mop5 mop_rr_n 1 . 00 .. 1 ..... ..... 100 ..... 1110011 @mop3 + +# *** Zabhb Standard Extension *** +amoswap_b 00001 . . ..... ..... 000 ..... 0101111 @atom_st +amoadd_b 00000 . . ..... ..... 000 ..... 0101111 @atom_st +amoxor_b 00100 . . ..... ..... 000 ..... 0101111 @atom_st +amoand_b 01100 . . ..... ..... 000 ..... 0101111 @atom_st +amoor_b 01000 . . ..... ..... 000 ..... 0101111 @atom_st +amomin_b 10000 . . ..... ..... 000 ..... 0101111 @atom_st +amomax_b 10100 . . ..... ..... 000 ..... 0101111 @atom_st +amominu_b 11000 . . ..... ..... 000 ..... 0101111 @atom_st +amomaxu_b 11100 . . ..... ..... 000 ..... 0101111 @atom_st +amoswap_h 00001 . . ..... ..... 001 ..... 0101111 @atom_st +amoadd_h 00000 . . ..... ..... 001 ..... 0101111 @atom_st +amoxor_h 00100 . . ..... ..... 001 ..... 0101111 @atom_st +amoand_h 01100 . . ..... ..... 001 ..... 0101111 @atom_st +amoor_h 01000 . . ..... ..... 001 ..... 0101111 @atom_st +amomin_h 10000 . . ..... ..... 001 ..... 0101111 @atom_st +amomax_h 10100 . . ..... ..... 001 ..... 0101111 @atom_st +amominu_h 11000 . . ..... ..... 001 ..... 0101111 @atom_st +amomaxu_h 11100 . . ..... ..... 001 ..... 0101111 @atom_st diff --git a/target/riscv/insn_trans/trans_rvzabha.c.inc b/target/riscv/insn_trans/trans_rvzabha.c.inc new file mode 100644 index 0000000000..9093a1cfc1 --- /dev/null +++ b/target/riscv/insn_trans/trans_rvzabha.c.inc @@ -0,0 +1,131 @@ +/* + * RISC-V translation routines for the Zabha Standard Extension. + * + * Copyright (c) 2024 Alibaba Group + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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 . + */ + +#define REQUIRE_ZABHA(ctx) do { \ + if (!ctx->cfg_ptr->ext_zabha) { \ + return false; \ + } \ +} while (0) + +static bool trans_amoswap_b(DisasContext *ctx, arg_amoswap_b *a) +{ + REQUIRE_ZABHA(ctx); + return gen_amo(ctx, a, &tcg_gen_atomic_xchg_tl, MO_SB); +} + +static bool trans_amoadd_b(DisasContext *ctx, arg_amoadd_b *a) +{ + REQUIRE_ZABHA(ctx); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_add_tl, MO_SB); +} + +static bool trans_amoxor_b(DisasContext *ctx, arg_amoxor_b *a) +{ + REQUIRE_ZABHA(ctx); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_xor_tl, MO_SB); +} + +static bool trans_amoand_b(DisasContext *ctx, arg_amoand_b *a) +{ + REQUIRE_ZABHA(ctx); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_and_tl, MO_SB); +} + +static bool trans_amoor_b(DisasContext *ctx, arg_amoor_b *a) +{ + REQUIRE_ZABHA(ctx); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_or_tl, MO_SB); +} + +static bool trans_amomin_b(DisasContext *ctx, arg_amomin_b *a) +{ + REQUIRE_ZABHA(ctx); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smin_tl, MO_SB); +} + +static bool trans_amomax_b(DisasContext *ctx, arg_amomax_b *a) +{ + REQUIRE_ZABHA(ctx); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smax_tl, MO_SB); +} + +static bool trans_amominu_b(DisasContext *ctx, arg_amominu_b *a) +{ + REQUIRE_ZABHA(ctx); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umin_tl, MO_SB); +} + +static bool trans_amomaxu_b(DisasContext *ctx, arg_amomaxu_b *a) +{ + REQUIRE_ZABHA(ctx); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, MO_SB); +} + +static bool trans_amoswap_h(DisasContext *ctx, arg_amoswap_h *a) +{ + REQUIRE_ZABHA(ctx); + return gen_amo(ctx, a, &tcg_gen_atomic_xchg_tl, MO_TESW); +} + +static bool trans_amoadd_h(DisasContext *ctx, arg_amoadd_h *a) +{ + REQUIRE_ZABHA(ctx); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_add_tl, MO_TESW); +} + +static bool trans_amoxor_h(DisasContext *ctx, arg_amoxor_h *a) +{ + REQUIRE_ZABHA(ctx); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_xor_tl, MO_TESW); +} + +static bool trans_amoand_h(DisasContext *ctx, arg_amoand_h *a) +{ + REQUIRE_ZABHA(ctx); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_and_tl, MO_TESW); +} + +static bool trans_amoor_h(DisasContext *ctx, arg_amoor_h *a) +{ + REQUIRE_ZABHA(ctx); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_or_tl, MO_TESW); +} + +static bool trans_amomin_h(DisasContext *ctx, arg_amomin_h *a) +{ + REQUIRE_ZABHA(ctx); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smin_tl, MO_TESW); +} + +static bool trans_amomax_h(DisasContext *ctx, arg_amomax_h *a) +{ + REQUIRE_ZABHA(ctx); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smax_tl, MO_TESW); +} + +static bool trans_amominu_h(DisasContext *ctx, arg_amominu_h *a) +{ + REQUIRE_ZABHA(ctx); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umin_tl, MO_TESW); +} + +static bool trans_amomaxu_h(DisasContext *ctx, arg_amomaxu_h *a) +{ + REQUIRE_ZABHA(ctx); + return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, MO_TESW); +} diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 133550d6e2..4a3e786560 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -1083,8 +1083,9 @@ static bool gen_amo(DisasContext *ctx, arg_atomic *a, { TCGv dest = dest_gpr(ctx, a->rd); TCGv src1, src2 = get_gpr(ctx, a->rs2, EXT_NONE); + MemOp size = mop & MO_SIZE; - if (ctx->cfg_ptr->ext_zama16b) { + if (ctx->cfg_ptr->ext_zama16b && size >= MO_32) { mop |= MO_ATOM_WITHIN16; } else { mop |= MO_ALIGN; @@ -1118,6 +1119,7 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc) #include "insn_trans/trans_rvb.c.inc" #include "insn_trans/trans_rvzicond.c.inc" #include "insn_trans/trans_rvzacas.c.inc" +#include "insn_trans/trans_rvzabha.c.inc" #include "insn_trans/trans_rvzawrs.c.inc" #include "insn_trans/trans_rvzicbo.c.inc" #include "insn_trans/trans_rvzimop.c.inc" From 8d07887bcbf13749224bd10b0303f7a79a959edb Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Tue, 9 Jul 2024 19:36:49 +0800 Subject: [PATCH 08/30] target/riscv: Move gen_cmpxchg before adding amocas.[b|h] Signed-off-by: LIU Zhiwei Acked-by: Alistair Francis Message-ID: <20240709113652.1239-9-zhiwei_liu@linux.alibaba.com> Signed-off-by: Alistair Francis --- target/riscv/insn_trans/trans_rvzacas.c.inc | 13 ------------- target/riscv/translate.c | 13 +++++++++++++ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/target/riscv/insn_trans/trans_rvzacas.c.inc b/target/riscv/insn_trans/trans_rvzacas.c.inc index 5d274d4c08..fcced99fc7 100644 --- a/target/riscv/insn_trans/trans_rvzacas.c.inc +++ b/target/riscv/insn_trans/trans_rvzacas.c.inc @@ -22,19 +22,6 @@ } \ } while (0) -static bool gen_cmpxchg(DisasContext *ctx, arg_atomic *a, MemOp mop) -{ - TCGv dest = get_gpr(ctx, a->rd, EXT_NONE); - TCGv src1 = get_address(ctx, a->rs1, 0); - TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE); - - decode_save_opc(ctx); - tcg_gen_atomic_cmpxchg_tl(dest, src1, dest, src2, ctx->mem_idx, mop); - - gen_set_gpr(ctx, a->rd, dest); - return true; -} - static bool trans_amocas_w(DisasContext *ctx, arg_amocas_w *a) { REQUIRE_ZACAS(ctx); diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 4a3e786560..acba90f170 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -1099,6 +1099,19 @@ static bool gen_amo(DisasContext *ctx, arg_atomic *a, return true; } +static bool gen_cmpxchg(DisasContext *ctx, arg_atomic *a, MemOp mop) +{ + TCGv dest = get_gpr(ctx, a->rd, EXT_NONE); + TCGv src1 = get_address(ctx, a->rs1, 0); + TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE); + + decode_save_opc(ctx); + tcg_gen_atomic_cmpxchg_tl(dest, src1, dest, src2, ctx->mem_idx, mop); + + gen_set_gpr(ctx, a->rd, dest); + return true; +} + static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc) { DisasContext *ctx = container_of(dcbase, DisasContext, base); From d34e4066025378dff8d444104100d3b07e127fe6 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Tue, 9 Jul 2024 19:36:50 +0800 Subject: [PATCH 09/30] target/riscv: Add amocas.[b|h] for Zabha Signed-off-by: LIU Zhiwei Reviewed-by: Alistair Francis Message-ID: <20240709113652.1239-10-zhiwei_liu@linux.alibaba.com> Signed-off-by: Alistair Francis --- target/riscv/insn32.decode | 2 ++ target/riscv/insn_trans/trans_rvzabha.c.inc | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 3bad6372f2..c45b8fa1d8 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -1041,3 +1041,5 @@ amomin_h 10000 . . ..... ..... 001 ..... 0101111 @atom_st amomax_h 10100 . . ..... ..... 001 ..... 0101111 @atom_st amominu_h 11000 . . ..... ..... 001 ..... 0101111 @atom_st amomaxu_h 11100 . . ..... ..... 001 ..... 0101111 @atom_st +amocas_b 00101 . . ..... ..... 000 ..... 0101111 @atom_st +amocas_h 00101 . . ..... ..... 001 ..... 0101111 @atom_st diff --git a/target/riscv/insn_trans/trans_rvzabha.c.inc b/target/riscv/insn_trans/trans_rvzabha.c.inc index 9093a1cfc1..ce8edcba62 100644 --- a/target/riscv/insn_trans/trans_rvzabha.c.inc +++ b/target/riscv/insn_trans/trans_rvzabha.c.inc @@ -129,3 +129,17 @@ static bool trans_amomaxu_h(DisasContext *ctx, arg_amomaxu_h *a) REQUIRE_ZABHA(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, MO_TESW); } + +static bool trans_amocas_b(DisasContext *ctx, arg_amocas_b *a) +{ + REQUIRE_ZACAS(ctx); + REQUIRE_ZABHA(ctx); + return gen_cmpxchg(ctx, a, MO_SB); +} + +static bool trans_amocas_h(DisasContext *ctx, arg_amocas_h *a) +{ + REQUIRE_ZACAS(ctx); + REQUIRE_ZABHA(ctx); + return gen_cmpxchg(ctx, a, MO_ALIGN | MO_TESW); +} From 8aebaa2591320619cbd3e75f91f6e088f2c3dcfa Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Tue, 9 Jul 2024 19:36:51 +0800 Subject: [PATCH 10/30] target/riscv: Expose zabha extension as a cpu property Signed-off-by: LIU Zhiwei Reviewed-by: Alistair Francis Message-ID: <20240709113652.1239-11-zhiwei_liu@linux.alibaba.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index de9c06904f..33ef4eb795 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -117,6 +117,7 @@ const RISCVIsaExtData isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(zmmul, PRIV_VERSION_1_12_0, ext_zmmul), ISA_EXT_DATA_ENTRY(za64rs, PRIV_VERSION_1_12_0, has_priv_1_11), ISA_EXT_DATA_ENTRY(zaamo, PRIV_VERSION_1_12_0, ext_zaamo), + ISA_EXT_DATA_ENTRY(zabha, PRIV_VERSION_1_13_0, ext_zabha), ISA_EXT_DATA_ENTRY(zacas, PRIV_VERSION_1_12_0, ext_zacas), ISA_EXT_DATA_ENTRY(zama16b, PRIV_VERSION_1_13_0, ext_zama16b), ISA_EXT_DATA_ENTRY(zalrsc, PRIV_VERSION_1_12_0, ext_zalrsc), @@ -1478,6 +1479,7 @@ const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = { MULTI_EXT_CFG_BOOL("zcmop", ext_zcmop, false), MULTI_EXT_CFG_BOOL("zacas", ext_zacas, false), MULTI_EXT_CFG_BOOL("zama16b", ext_zama16b, false), + MULTI_EXT_CFG_BOOL("zabha", ext_zabha, false), MULTI_EXT_CFG_BOOL("zaamo", ext_zaamo, false), MULTI_EXT_CFG_BOOL("zalrsc", ext_zalrsc, false), MULTI_EXT_CFG_BOOL("zawrs", ext_zawrs, true), From ae4bdcef6fd3166264a47ed6a17cb9870e32306e Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Tue, 9 Jul 2024 19:36:52 +0800 Subject: [PATCH 11/30] disas/riscv: Support zabha disassemble Signed-off-by: LIU Zhiwei Acked-by: Alistair Francis Message-ID: <20240709113652.1239-12-zhiwei_liu@linux.alibaba.com> Signed-off-by: Alistair Francis --- disas/riscv.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/disas/riscv.c b/disas/riscv.c index d29cb1ff7d..c8364c2b07 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -954,6 +954,26 @@ typedef enum { rv_c_mop_11 = 923, rv_c_mop_13 = 924, rv_c_mop_15 = 925, + rv_op_amoswap_b = 926, + rv_op_amoadd_b = 927, + rv_op_amoxor_b = 928, + rv_op_amoor_b = 929, + rv_op_amoand_b = 930, + rv_op_amomin_b = 931, + rv_op_amomax_b = 932, + rv_op_amominu_b = 933, + rv_op_amomaxu_b = 934, + rv_op_amoswap_h = 935, + rv_op_amoadd_h = 936, + rv_op_amoxor_h = 937, + rv_op_amoor_h = 938, + rv_op_amoand_h = 939, + rv_op_amomin_h = 940, + rv_op_amomax_h = 941, + rv_op_amominu_h = 942, + rv_op_amomaxu_h = 943, + rv_op_amocas_b = 944, + rv_op_amocas_h = 945, } rv_op; /* register names */ @@ -2192,6 +2212,26 @@ const rv_opcode_data rvi_opcode_data[] = { { "c.mop.11", rv_codec_ci_none, rv_fmt_none, NULL, 0, 0, 0 }, { "c.mop.13", rv_codec_ci_none, rv_fmt_none, NULL, 0, 0, 0 }, { "c.mop.15", rv_codec_ci_none, rv_fmt_none, NULL, 0, 0, 0 }, + { "amoswap.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, + { "amoadd.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, + { "amoxor.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, + { "amoor.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, + { "amoand.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, + { "amomin.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, + { "amomax.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, + { "amominu.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, + { "amomaxu.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, + { "amoswap.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, + { "amoadd.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, + { "amoxor.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, + { "amoor.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, + { "amoand.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, + { "amomin.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, + { "amomax.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, + { "amominu.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, + { "amomaxu.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, + { "amocas.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, + { "amocas.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, }; /* CSR names */ @@ -2986,9 +3026,13 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa) case 11: switch (((inst >> 24) & 0b11111000) | ((inst >> 12) & 0b00000111)) { + case 0: op = rv_op_amoadd_b; break; + case 1: op = rv_op_amoadd_h; break; case 2: op = rv_op_amoadd_w; break; case 3: op = rv_op_amoadd_d; break; case 4: op = rv_op_amoadd_q; break; + case 8: op = rv_op_amoswap_b; break; + case 9: op = rv_op_amoswap_h; break; case 10: op = rv_op_amoswap_w; break; case 11: op = rv_op_amoswap_d; break; case 12: op = rv_op_amoswap_q; break; @@ -3010,27 +3054,43 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa) case 26: op = rv_op_sc_w; break; case 27: op = rv_op_sc_d; break; case 28: op = rv_op_sc_q; break; + case 32: op = rv_op_amoxor_b; break; + case 33: op = rv_op_amoxor_h; break; case 34: op = rv_op_amoxor_w; break; case 35: op = rv_op_amoxor_d; break; case 36: op = rv_op_amoxor_q; break; + case 40: op = rv_op_amocas_b; break; + case 41: op = rv_op_amocas_h; break; case 42: op = rv_op_amocas_w; break; case 43: op = rv_op_amocas_d; break; case 44: op = rv_op_amocas_q; break; + case 64: op = rv_op_amoor_b; break; + case 65: op = rv_op_amoor_h; break; case 66: op = rv_op_amoor_w; break; case 67: op = rv_op_amoor_d; break; case 68: op = rv_op_amoor_q; break; + case 96: op = rv_op_amoand_b; break; + case 97: op = rv_op_amoand_h; break; case 98: op = rv_op_amoand_w; break; case 99: op = rv_op_amoand_d; break; case 100: op = rv_op_amoand_q; break; + case 128: op = rv_op_amomin_b; break; + case 129: op = rv_op_amomin_h; break; case 130: op = rv_op_amomin_w; break; case 131: op = rv_op_amomin_d; break; case 132: op = rv_op_amomin_q; break; + case 160: op = rv_op_amomax_b; break; + case 161: op = rv_op_amomax_h; break; case 162: op = rv_op_amomax_w; break; case 163: op = rv_op_amomax_d; break; case 164: op = rv_op_amomax_q; break; + case 192: op = rv_op_amominu_b; break; + case 193: op = rv_op_amominu_h; break; case 194: op = rv_op_amominu_w; break; case 195: op = rv_op_amominu_d; break; case 196: op = rv_op_amominu_q; break; + case 224: op = rv_op_amomaxu_b; break; + case 225: op = rv_op_amomaxu_h; break; case 226: op = rv_op_amomaxu_w; break; case 227: op = rv_op_amomaxu_d; break; case 228: op = rv_op_amomaxu_q; break; From 910c18a91738f9b77c5faf66e3534bb10d6e306e Mon Sep 17 00:00:00 2001 From: Jiayi Li Date: Mon, 1 Jul 2024 10:25:53 +0800 Subject: [PATCH 12/30] target/riscv: Validate the mode in write_vstvec Base on the riscv-privileged spec, vstvec substitutes for the usual stvec. Therefore, the encoding of the MODE should also be restricted to 0 and 1. Signed-off-by: Jiayi Li Reviewed-by: Alistair Francis Reviewed-by: LIU Zhiwei Message-ID: <20240701022553.1982-1-lijiayi@eswincomputing.com> Signed-off-by: Alistair Francis --- target/riscv/csr.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 432c59dc66..f9229d92ab 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -3791,7 +3791,12 @@ static RISCVException read_vstvec(CPURISCVState *env, int csrno, static RISCVException write_vstvec(CPURISCVState *env, int csrno, target_ulong val) { - env->vstvec = val; + /* bits [1:0] encode mode; 0 = direct, 1 = vectored, 2 >= reserved */ + if ((val & 3) < 2) { + env->vstvec = val; + } else { + qemu_log_mask(LOG_UNIMP, "CSR_VSTVEC: reserved mode not supported\n"); + } return RISCV_EXCP_NONE; } From 4d46d84ea7fbb694125b95c88e788caf6cd039fa Mon Sep 17 00:00:00 2001 From: Balaji Ravikumar Date: Fri, 5 Jul 2024 17:53:16 +0100 Subject: [PATCH 13/30] disas/riscv: Add decode for Zawrs extension Add disassembly support for these instructions from Zawrs: * wrs.sto * wrs.nto Signed-off-by: Balaji Ravikumar Signed-off-by: Rob Bradford Acked-by: Alistair Francis Message-ID: <20240705165316.127494-1-rbradford@rivosinc.com> Signed-off-by: Alistair Francis --- disas/riscv.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/disas/riscv.c b/disas/riscv.c index c8364c2b07..5965574d87 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -974,6 +974,8 @@ typedef enum { rv_op_amomaxu_h = 943, rv_op_amocas_b = 944, rv_op_amocas_h = 945, + rv_op_wrs_sto = 946, + rv_op_wrs_nto = 947, } rv_op; /* register names */ @@ -2232,6 +2234,8 @@ const rv_opcode_data rvi_opcode_data[] = { { "amomaxu.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, { "amocas.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, { "amocas.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 }, + { "wrs.sto", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 }, + { "wrs.nto", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 }, }; /* CSR names */ @@ -3980,6 +3984,8 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa) case 0: op = rv_op_ecall; break; case 32: op = rv_op_ebreak; break; case 64: op = rv_op_uret; break; + case 416: op = rv_op_wrs_nto; break; + case 928: op = rv_op_wrs_sto; break; } break; case 256: From 3cb9f20499cd7da644387a17a79230f8ffd89993 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 9 Jul 2024 05:54:31 -0300 Subject: [PATCH 14/30] target/riscv/kvm: update KVM regs to Linux 6.10-rc5 Two new regs added: ztso and zacas. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-ID: <20240709085431.455541-1-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/kvm/kvm-cpu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index 1047961fed..f6e3156b8d 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -281,6 +281,7 @@ static KVMCPUConfig kvm_multi_ext_cfgs[] = { KVM_EXT_CFG("zihintntl", ext_zihintntl, KVM_RISCV_ISA_EXT_ZIHINTNTL), KVM_EXT_CFG("zihintpause", ext_zihintpause, KVM_RISCV_ISA_EXT_ZIHINTPAUSE), KVM_EXT_CFG("zihpm", ext_zihpm, KVM_RISCV_ISA_EXT_ZIHPM), + KVM_EXT_CFG("zacas", ext_zacas, KVM_RISCV_ISA_EXT_ZACAS), KVM_EXT_CFG("zfa", ext_zfa, KVM_RISCV_ISA_EXT_ZFA), KVM_EXT_CFG("zfh", ext_zfh, KVM_RISCV_ISA_EXT_ZFH), KVM_EXT_CFG("zfhmin", ext_zfhmin, KVM_RISCV_ISA_EXT_ZFHMIN), @@ -298,6 +299,7 @@ static KVMCPUConfig kvm_multi_ext_cfgs[] = { KVM_EXT_CFG("zksed", ext_zksed, KVM_RISCV_ISA_EXT_ZKSED), KVM_EXT_CFG("zksh", ext_zksh, KVM_RISCV_ISA_EXT_ZKSH), KVM_EXT_CFG("zkt", ext_zkt, KVM_RISCV_ISA_EXT_ZKT), + KVM_EXT_CFG("ztso", ext_ztso, KVM_RISCV_ISA_EXT_ZTSO), KVM_EXT_CFG("zvbb", ext_zvbb, KVM_RISCV_ISA_EXT_ZVBB), KVM_EXT_CFG("zvbc", ext_zvbc, KVM_RISCV_ISA_EXT_ZVBC), KVM_EXT_CFG("zvfh", ext_zvfh, KVM_RISCV_ISA_EXT_ZVFH), From 68c05fb53036f59a55a54c943b713e8ac78fc627 Mon Sep 17 00:00:00 2001 From: Rajnesh Kanwal Date: Thu, 11 Jul 2024 15:31:04 -0700 Subject: [PATCH 15/30] target/riscv: Combine set_mode and set_virt functions. Combining riscv_cpu_set_virt_enabled() and riscv_cpu_set_mode() functions. This is to make complete mode change information available through a single function. This allows to easily differentiate between HS->VS, VS->HS and VS->VS transitions when executing state update codes. For example: One use-case which inspired this change is to update mode-specific instruction and cycle counters which requires information of both prev mode and current mode. Signed-off-by: Rajnesh Kanwal Reviewed-by: Alistair Francis Reviewed-by: Daniel Henrique Barboza Message-ID: <20240711-smcntrpmf_v7-v8-1-b7c38ae7b263@rivosinc.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.h | 2 +- target/riscv/cpu_helper.c | 57 +++++++++++++++++++-------------------- target/riscv/op_helper.c | 17 +++++------- 3 files changed, 35 insertions(+), 41 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 87742047ce..6520e0f5d5 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -567,7 +567,7 @@ void riscv_cpu_set_aia_ireg_rmw_fn(CPURISCVState *env, uint32_t priv, RISCVException smstateen_acc_ok(CPURISCVState *env, int index, uint64_t bit); #endif /* !CONFIG_USER_ONLY */ -void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv); +void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv, bool virt_en); void riscv_translate_init(void); G_NORETURN void riscv_raise_exception(CPURISCVState *env, diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 6709622dd3..10d3fdaed3 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -619,30 +619,6 @@ void riscv_cpu_set_geilen(CPURISCVState *env, target_ulong geilen) env->geilen = geilen; } -/* This function can only be called to set virt when RVH is enabled */ -void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable) -{ - /* Flush the TLB on all virt mode changes. */ - if (env->virt_enabled != enable) { - tlb_flush(env_cpu(env)); - } - - env->virt_enabled = enable; - - if (enable) { - /* - * The guest external interrupts from an interrupt controller are - * delivered only when the Guest/VM is running (i.e. V=1). This means - * any guest external interrupt which is triggered while the Guest/VM - * is not running (i.e. V=0) will be missed on QEMU resulting in guest - * with sluggish response to serial console input and other I/O events. - * - * To solve this, we check and inject interrupt after setting V=1. - */ - riscv_cpu_update_mip(env, 0, 0); - } -} - int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts) { CPURISCVState *env = &cpu->env; @@ -715,7 +691,7 @@ void riscv_cpu_set_aia_ireg_rmw_fn(CPURISCVState *env, uint32_t priv, } } -void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv) +void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv, bool virt_en) { g_assert(newpriv <= PRV_M && newpriv != PRV_RESERVED); @@ -736,6 +712,28 @@ void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv) * preemptive context switch. As a result, do both. */ env->load_res = -1; + + if (riscv_has_ext(env, RVH)) { + /* Flush the TLB on all virt mode changes. */ + if (env->virt_enabled != virt_en) { + tlb_flush(env_cpu(env)); + } + + env->virt_enabled = virt_en; + if (virt_en) { + /* + * The guest external interrupts from an interrupt controller are + * delivered only when the Guest/VM is running (i.e. V=1). This + * means any guest external interrupt which is triggered while the + * Guest/VM is not running (i.e. V=0) will be missed on QEMU + * resulting in guest with sluggish response to serial console + * input and other I/O events. + * + * To solve this, we check and inject interrupt after setting V=1. + */ + riscv_cpu_update_mip(env, 0, 0); + } + } } /* @@ -1648,6 +1646,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) { RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; + bool virt = env->virt_enabled; bool write_gva = false; uint64_t s; @@ -1778,7 +1777,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) htval = env->guest_phys_fault_addr; - riscv_cpu_set_virt_enabled(env, 0); + virt = false; } else { /* Trap into HS mode */ env->hstatus = set_field(env->hstatus, HSTATUS_SPV, false); @@ -1799,7 +1798,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) env->htinst = tinst; env->pc = (env->stvec >> 2 << 2) + ((async && (env->stvec & 3) == 1) ? cause * 4 : 0); - riscv_cpu_set_mode(env, PRV_S); + riscv_cpu_set_mode(env, PRV_S, virt); } else { /* handle the trap in M-mode */ if (riscv_has_ext(env, RVH)) { @@ -1815,7 +1814,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) mtval2 = env->guest_phys_fault_addr; /* Trapping to M mode, virt is disabled */ - riscv_cpu_set_virt_enabled(env, 0); + virt = false; } s = env->mstatus; @@ -1830,7 +1829,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) env->mtinst = tinst; env->pc = (env->mtvec >> 2 << 2) + ((async && (env->mtvec & 3) == 1) ? cause * 4 : 0); - riscv_cpu_set_mode(env, PRV_M); + riscv_cpu_set_mode(env, PRV_M, virt); } /* diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c index 2baf5bc3ca..ec1408ba0f 100644 --- a/target/riscv/op_helper.c +++ b/target/riscv/op_helper.c @@ -264,7 +264,7 @@ void helper_cbo_inval(CPURISCVState *env, target_ulong address) target_ulong helper_sret(CPURISCVState *env) { uint64_t mstatus; - target_ulong prev_priv, prev_virt; + target_ulong prev_priv, prev_virt = env->virt_enabled; if (!(env->priv >= PRV_S)) { riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); @@ -307,11 +307,9 @@ target_ulong helper_sret(CPURISCVState *env) if (prev_virt) { riscv_cpu_swap_hypervisor_regs(env); } - - riscv_cpu_set_virt_enabled(env, prev_virt); } - riscv_cpu_set_mode(env, prev_priv); + riscv_cpu_set_mode(env, prev_priv, prev_virt); return retpc; } @@ -347,16 +345,13 @@ target_ulong helper_mret(CPURISCVState *env) mstatus = set_field(mstatus, MSTATUS_MPRV, 0); } env->mstatus = mstatus; - riscv_cpu_set_mode(env, prev_priv); - if (riscv_has_ext(env, RVH)) { - if (prev_virt) { - riscv_cpu_swap_hypervisor_regs(env); - } - - riscv_cpu_set_virt_enabled(env, prev_virt); + if (riscv_has_ext(env, RVH) && prev_virt) { + riscv_cpu_swap_hypervisor_regs(env); } + riscv_cpu_set_mode(env, prev_priv, prev_virt); + return retpc; } From be470e597708451e6fecb0631728fa759164d03e Mon Sep 17 00:00:00 2001 From: Atish Patra Date: Thu, 11 Jul 2024 15:31:05 -0700 Subject: [PATCH 16/30] target/riscv: Fix the predicate functions for mhpmeventhX CSRs mhpmeventhX CSRs are available for RV32. The predicate function should check that first before checking sscofpmf extension. Fixes: 14664483457b ("target/riscv: Add sscofpmf extension support") Reviewed-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Signed-off-by: Atish Patra Message-ID: <20240711-smcntrpmf_v7-v8-2-b7c38ae7b263@rivosinc.com> Signed-off-by: Alistair Francis --- target/riscv/csr.c | 67 ++++++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 29 deletions(-) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index f9229d92ab..1bcf75f91f 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -227,6 +227,15 @@ static RISCVException sscofpmf(CPURISCVState *env, int csrno) return RISCV_EXCP_NONE; } +static RISCVException sscofpmf_32(CPURISCVState *env, int csrno) +{ + if (riscv_cpu_mxl(env) != MXL_RV32) { + return RISCV_EXCP_ILLEGAL_INST; + } + + return sscofpmf(env, csrno); +} + static RISCVException any(CPURISCVState *env, int csrno) { return RISCV_EXCP_NONE; @@ -5106,91 +5115,91 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_MHPMEVENT31] = { "mhpmevent31", any, read_mhpmevent, write_mhpmevent }, - [CSR_MHPMEVENT3H] = { "mhpmevent3h", sscofpmf, read_mhpmeventh, + [CSR_MHPMEVENT3H] = { "mhpmevent3h", sscofpmf_32, read_mhpmeventh, write_mhpmeventh, .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_MHPMEVENT4H] = { "mhpmevent4h", sscofpmf, read_mhpmeventh, + [CSR_MHPMEVENT4H] = { "mhpmevent4h", sscofpmf_32, read_mhpmeventh, write_mhpmeventh, .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_MHPMEVENT5H] = { "mhpmevent5h", sscofpmf, read_mhpmeventh, + [CSR_MHPMEVENT5H] = { "mhpmevent5h", sscofpmf_32, read_mhpmeventh, write_mhpmeventh, .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_MHPMEVENT6H] = { "mhpmevent6h", sscofpmf, read_mhpmeventh, + [CSR_MHPMEVENT6H] = { "mhpmevent6h", sscofpmf_32, read_mhpmeventh, write_mhpmeventh, .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_MHPMEVENT7H] = { "mhpmevent7h", sscofpmf, read_mhpmeventh, + [CSR_MHPMEVENT7H] = { "mhpmevent7h", sscofpmf_32, read_mhpmeventh, write_mhpmeventh, .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_MHPMEVENT8H] = { "mhpmevent8h", sscofpmf, read_mhpmeventh, + [CSR_MHPMEVENT8H] = { "mhpmevent8h", sscofpmf_32, read_mhpmeventh, write_mhpmeventh, .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_MHPMEVENT9H] = { "mhpmevent9h", sscofpmf, read_mhpmeventh, + [CSR_MHPMEVENT9H] = { "mhpmevent9h", sscofpmf_32, read_mhpmeventh, write_mhpmeventh, .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_MHPMEVENT10H] = { "mhpmevent10h", sscofpmf, read_mhpmeventh, + [CSR_MHPMEVENT10H] = { "mhpmevent10h", sscofpmf_32, read_mhpmeventh, write_mhpmeventh, .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_MHPMEVENT11H] = { "mhpmevent11h", sscofpmf, read_mhpmeventh, + [CSR_MHPMEVENT11H] = { "mhpmevent11h", sscofpmf_32, read_mhpmeventh, write_mhpmeventh, .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_MHPMEVENT12H] = { "mhpmevent12h", sscofpmf, read_mhpmeventh, + [CSR_MHPMEVENT12H] = { "mhpmevent12h", sscofpmf_32, read_mhpmeventh, write_mhpmeventh, .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_MHPMEVENT13H] = { "mhpmevent13h", sscofpmf, read_mhpmeventh, + [CSR_MHPMEVENT13H] = { "mhpmevent13h", sscofpmf_32, read_mhpmeventh, write_mhpmeventh, .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_MHPMEVENT14H] = { "mhpmevent14h", sscofpmf, read_mhpmeventh, + [CSR_MHPMEVENT14H] = { "mhpmevent14h", sscofpmf_32, read_mhpmeventh, write_mhpmeventh, .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_MHPMEVENT15H] = { "mhpmevent15h", sscofpmf, read_mhpmeventh, + [CSR_MHPMEVENT15H] = { "mhpmevent15h", sscofpmf_32, read_mhpmeventh, write_mhpmeventh, .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_MHPMEVENT16H] = { "mhpmevent16h", sscofpmf, read_mhpmeventh, + [CSR_MHPMEVENT16H] = { "mhpmevent16h", sscofpmf_32, read_mhpmeventh, write_mhpmeventh, .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_MHPMEVENT17H] = { "mhpmevent17h", sscofpmf, read_mhpmeventh, + [CSR_MHPMEVENT17H] = { "mhpmevent17h", sscofpmf_32, read_mhpmeventh, write_mhpmeventh, .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_MHPMEVENT18H] = { "mhpmevent18h", sscofpmf, read_mhpmeventh, + [CSR_MHPMEVENT18H] = { "mhpmevent18h", sscofpmf_32, read_mhpmeventh, write_mhpmeventh, .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_MHPMEVENT19H] = { "mhpmevent19h", sscofpmf, read_mhpmeventh, + [CSR_MHPMEVENT19H] = { "mhpmevent19h", sscofpmf_32, read_mhpmeventh, write_mhpmeventh, .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_MHPMEVENT20H] = { "mhpmevent20h", sscofpmf, read_mhpmeventh, + [CSR_MHPMEVENT20H] = { "mhpmevent20h", sscofpmf_32, read_mhpmeventh, write_mhpmeventh, .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_MHPMEVENT21H] = { "mhpmevent21h", sscofpmf, read_mhpmeventh, + [CSR_MHPMEVENT21H] = { "mhpmevent21h", sscofpmf_32, read_mhpmeventh, write_mhpmeventh, .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_MHPMEVENT22H] = { "mhpmevent22h", sscofpmf, read_mhpmeventh, + [CSR_MHPMEVENT22H] = { "mhpmevent22h", sscofpmf_32, read_mhpmeventh, write_mhpmeventh, .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_MHPMEVENT23H] = { "mhpmevent23h", sscofpmf, read_mhpmeventh, + [CSR_MHPMEVENT23H] = { "mhpmevent23h", sscofpmf_32, read_mhpmeventh, write_mhpmeventh, .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_MHPMEVENT24H] = { "mhpmevent24h", sscofpmf, read_mhpmeventh, + [CSR_MHPMEVENT24H] = { "mhpmevent24h", sscofpmf_32, read_mhpmeventh, write_mhpmeventh, .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_MHPMEVENT25H] = { "mhpmevent25h", sscofpmf, read_mhpmeventh, + [CSR_MHPMEVENT25H] = { "mhpmevent25h", sscofpmf_32, read_mhpmeventh, write_mhpmeventh, .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_MHPMEVENT26H] = { "mhpmevent26h", sscofpmf, read_mhpmeventh, + [CSR_MHPMEVENT26H] = { "mhpmevent26h", sscofpmf_32, read_mhpmeventh, write_mhpmeventh, .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_MHPMEVENT27H] = { "mhpmevent27h", sscofpmf, read_mhpmeventh, + [CSR_MHPMEVENT27H] = { "mhpmevent27h", sscofpmf_32, read_mhpmeventh, write_mhpmeventh, .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_MHPMEVENT28H] = { "mhpmevent28h", sscofpmf, read_mhpmeventh, + [CSR_MHPMEVENT28H] = { "mhpmevent28h", sscofpmf_32, read_mhpmeventh, write_mhpmeventh, .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_MHPMEVENT29H] = { "mhpmevent29h", sscofpmf, read_mhpmeventh, + [CSR_MHPMEVENT29H] = { "mhpmevent29h", sscofpmf_32, read_mhpmeventh, write_mhpmeventh, .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_MHPMEVENT30H] = { "mhpmevent30h", sscofpmf, read_mhpmeventh, + [CSR_MHPMEVENT30H] = { "mhpmevent30h", sscofpmf_32, read_mhpmeventh, write_mhpmeventh, .min_priv_ver = PRIV_VERSION_1_12_0 }, - [CSR_MHPMEVENT31H] = { "mhpmevent31h", sscofpmf, read_mhpmeventh, + [CSR_MHPMEVENT31H] = { "mhpmevent31h", sscofpmf_32, read_mhpmeventh, write_mhpmeventh, .min_priv_ver = PRIV_VERSION_1_12_0 }, From 251dccc09af363900436656461151681687e2470 Mon Sep 17 00:00:00 2001 From: Kaiwen Xue Date: Thu, 11 Jul 2024 15:31:06 -0700 Subject: [PATCH 17/30] target/riscv: Add cycle & instret privilege mode filtering properties This adds the properties for ISA extension smcntrpmf. Patches implementing it will follow. Signed-off-by: Kaiwen Xue Reviewed-by: Daniel Henrique Barboza Signed-off-by: Atish Patra Reviewed-by: Alistair Francis Message-ID: <20240711-smcntrpmf_v7-v8-3-b7c38ae7b263@rivosinc.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 1 + target/riscv/cpu_cfg.h | 1 + 2 files changed, 2 insertions(+) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 33ef4eb795..4efe7ee3b0 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -182,6 +182,7 @@ const RISCVIsaExtData isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(zhinx, PRIV_VERSION_1_12_0, ext_zhinx), ISA_EXT_DATA_ENTRY(zhinxmin, PRIV_VERSION_1_12_0, ext_zhinxmin), ISA_EXT_DATA_ENTRY(smaia, PRIV_VERSION_1_12_0, ext_smaia), + ISA_EXT_DATA_ENTRY(smcntrpmf, PRIV_VERSION_1_12_0, ext_smcntrpmf), ISA_EXT_DATA_ENTRY(smepmp, PRIV_VERSION_1_12_0, ext_smepmp), ISA_EXT_DATA_ENTRY(smstateen, PRIV_VERSION_1_12_0, ext_smstateen), ISA_EXT_DATA_ENTRY(ssaia, PRIV_VERSION_1_12_0, ext_ssaia), diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h index 120905a254..8b272fb826 100644 --- a/target/riscv/cpu_cfg.h +++ b/target/riscv/cpu_cfg.h @@ -76,6 +76,7 @@ struct RISCVCPUConfig { bool ext_ztso; bool ext_smstateen; bool ext_sstc; + bool ext_smcntrpmf; bool ext_svadu; bool ext_svinval; bool ext_svnapot; From 6d1e3893cfaeedb47a16edbb766fcc0c7907ab94 Mon Sep 17 00:00:00 2001 From: Kaiwen Xue Date: Thu, 11 Jul 2024 15:31:07 -0700 Subject: [PATCH 18/30] target/riscv: Add cycle & instret privilege mode filtering definitions This adds the definitions for ISA extension smcntrpmf. Signed-off-by: Kaiwen Xue Reviewed-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Signed-off-by: Atish Patra Message-ID: <20240711-smcntrpmf_v7-v8-4-b7c38ae7b263@rivosinc.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.h | 6 ++++++ target/riscv/cpu_bits.h | 29 +++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 6520e0f5d5..980e2154cd 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -362,6 +362,12 @@ struct CPUArchState { uint32_t mcountinhibit; + /* PMU cycle & instret privilege mode filtering */ + target_ulong mcyclecfg; + target_ulong mcyclecfgh; + target_ulong minstretcfg; + target_ulong minstretcfgh; + /* PMU counter state */ PMUCTRState pmu_ctrs[RV_MAX_MHPMCOUNTERS]; diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index c257c5ed7d..5faa817453 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -397,6 +397,10 @@ /* Machine counter-inhibit register */ #define CSR_MCOUNTINHIBIT 0x320 +/* Machine counter configuration registers */ +#define CSR_MCYCLECFG 0x321 +#define CSR_MINSTRETCFG 0x322 + #define CSR_MHPMEVENT3 0x323 #define CSR_MHPMEVENT4 0x324 #define CSR_MHPMEVENT5 0x325 @@ -427,6 +431,9 @@ #define CSR_MHPMEVENT30 0x33e #define CSR_MHPMEVENT31 0x33f +#define CSR_MCYCLECFGH 0x721 +#define CSR_MINSTRETCFGH 0x722 + #define CSR_MHPMEVENT3H 0x723 #define CSR_MHPMEVENT4H 0x724 #define CSR_MHPMEVENT5H 0x725 @@ -884,6 +891,28 @@ typedef enum RISCVException { /* PMU related bits */ #define MIE_LCOFIE (1 << IRQ_PMU_OVF) +#define MCYCLECFG_BIT_MINH BIT_ULL(62) +#define MCYCLECFGH_BIT_MINH BIT(30) +#define MCYCLECFG_BIT_SINH BIT_ULL(61) +#define MCYCLECFGH_BIT_SINH BIT(29) +#define MCYCLECFG_BIT_UINH BIT_ULL(60) +#define MCYCLECFGH_BIT_UINH BIT(28) +#define MCYCLECFG_BIT_VSINH BIT_ULL(59) +#define MCYCLECFGH_BIT_VSINH BIT(27) +#define MCYCLECFG_BIT_VUINH BIT_ULL(58) +#define MCYCLECFGH_BIT_VUINH BIT(26) + +#define MINSTRETCFG_BIT_MINH BIT_ULL(62) +#define MINSTRETCFGH_BIT_MINH BIT(30) +#define MINSTRETCFG_BIT_SINH BIT_ULL(61) +#define MINSTRETCFGH_BIT_SINH BIT(29) +#define MINSTRETCFG_BIT_UINH BIT_ULL(60) +#define MINSTRETCFGH_BIT_UINH BIT(28) +#define MINSTRETCFG_BIT_VSINH BIT_ULL(59) +#define MINSTRETCFGH_BIT_VSINH BIT(27) +#define MINSTRETCFG_BIT_VUINH BIT_ULL(58) +#define MINSTRETCFGH_BIT_VUINH BIT(26) + #define MHPMEVENT_BIT_OF BIT_ULL(63) #define MHPMEVENTH_BIT_OF BIT(31) #define MHPMEVENT_BIT_MINH BIT_ULL(62) From b54a84c15e389a4795022cc7edfe3a7e32dc065d Mon Sep 17 00:00:00 2001 From: Kaiwen Xue Date: Thu, 11 Jul 2024 15:31:08 -0700 Subject: [PATCH 19/30] target/riscv: Add cycle & instret privilege mode filtering support QEMU only calculates dummy cycles and instructions, so there is no actual means to stop the icount in QEMU. Hence this patch merely adds the functionality of accessing the cfg registers, and cause no actual effects on the counting of cycle and instret counters. Signed-off-by: Atish Patra Reviewed-by: Daniel Henrique Barboza Signed-off-by: Kaiwen Xue Acked-by: Alistair Francis Message-ID: <20240711-smcntrpmf_v7-v8-5-b7c38ae7b263@rivosinc.com> Signed-off-by: Alistair Francis --- target/riscv/cpu_bits.h | 12 ++++ target/riscv/csr.c | 138 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 149 insertions(+), 1 deletion(-) diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index 5faa817453..32b068f18a 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -926,6 +926,18 @@ typedef enum RISCVException { #define MHPMEVENT_BIT_VUINH BIT_ULL(58) #define MHPMEVENTH_BIT_VUINH BIT(26) +#define MHPMEVENT_FILTER_MASK (MHPMEVENT_BIT_MINH | \ + MHPMEVENT_BIT_SINH | \ + MHPMEVENT_BIT_UINH | \ + MHPMEVENT_BIT_VSINH | \ + MHPMEVENT_BIT_VUINH) + +#define MHPMEVENTH_FILTER_MASK (MHPMEVENTH_BIT_MINH | \ + MHPMEVENTH_BIT_SINH | \ + MHPMEVENTH_BIT_UINH | \ + MHPMEVENTH_BIT_VSINH | \ + MHPMEVENTH_BIT_VUINH) + #define MHPMEVENT_SSCOF_MASK _ULL(0xFFFF000000000000) #define MHPMEVENT_IDX_MASK 0xFFFFF #define MHPMEVENT_SSCOF_RESVD 16 diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 1bcf75f91f..8831d4f5ec 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -30,7 +30,6 @@ #include "qemu/guest-random.h" #include "qapi/error.h" - /* CSR function table public API */ void riscv_get_csr_ops(int csrno, riscv_csr_operations *ops) { @@ -236,6 +235,24 @@ static RISCVException sscofpmf_32(CPURISCVState *env, int csrno) return sscofpmf(env, csrno); } +static RISCVException smcntrpmf(CPURISCVState *env, int csrno) +{ + if (!riscv_cpu_cfg(env)->ext_smcntrpmf) { + return RISCV_EXCP_ILLEGAL_INST; + } + + return RISCV_EXCP_NONE; +} + +static RISCVException smcntrpmf_32(CPURISCVState *env, int csrno) +{ + if (riscv_cpu_mxl(env) != MXL_RV32) { + return RISCV_EXCP_ILLEGAL_INST; + } + + return smcntrpmf(env, csrno); +} + static RISCVException any(CPURISCVState *env, int csrno) { return RISCV_EXCP_NONE; @@ -830,6 +847,111 @@ static RISCVException read_hpmcounterh(CPURISCVState *env, int csrno, #else /* CONFIG_USER_ONLY */ +static RISCVException read_mcyclecfg(CPURISCVState *env, int csrno, + target_ulong *val) +{ + *val = env->mcyclecfg; + return RISCV_EXCP_NONE; +} + +static RISCVException write_mcyclecfg(CPURISCVState *env, int csrno, + target_ulong val) +{ + uint64_t inh_avail_mask; + + if (riscv_cpu_mxl(env) == MXL_RV32) { + env->mcyclecfg = val; + } else { + /* Set xINH fields if priv mode supported */ + inh_avail_mask = ~MHPMEVENT_FILTER_MASK | MCYCLECFG_BIT_MINH; + inh_avail_mask |= riscv_has_ext(env, RVU) ? MCYCLECFG_BIT_UINH : 0; + inh_avail_mask |= riscv_has_ext(env, RVS) ? MCYCLECFG_BIT_SINH : 0; + inh_avail_mask |= (riscv_has_ext(env, RVH) && + riscv_has_ext(env, RVU)) ? MCYCLECFG_BIT_VUINH : 0; + inh_avail_mask |= (riscv_has_ext(env, RVH) && + riscv_has_ext(env, RVS)) ? MCYCLECFG_BIT_VSINH : 0; + env->mcyclecfg = val & inh_avail_mask; + } + + return RISCV_EXCP_NONE; +} + +static RISCVException read_mcyclecfgh(CPURISCVState *env, int csrno, + target_ulong *val) +{ + *val = env->mcyclecfgh; + return RISCV_EXCP_NONE; +} + +static RISCVException write_mcyclecfgh(CPURISCVState *env, int csrno, + target_ulong val) +{ + target_ulong inh_avail_mask = (target_ulong)(~MHPMEVENTH_FILTER_MASK | + MCYCLECFGH_BIT_MINH); + + /* Set xINH fields if priv mode supported */ + inh_avail_mask |= riscv_has_ext(env, RVU) ? MCYCLECFGH_BIT_UINH : 0; + inh_avail_mask |= riscv_has_ext(env, RVS) ? MCYCLECFGH_BIT_SINH : 0; + inh_avail_mask |= (riscv_has_ext(env, RVH) && + riscv_has_ext(env, RVU)) ? MCYCLECFGH_BIT_VUINH : 0; + inh_avail_mask |= (riscv_has_ext(env, RVH) && + riscv_has_ext(env, RVS)) ? MCYCLECFGH_BIT_VSINH : 0; + + env->mcyclecfgh = val & inh_avail_mask; + return RISCV_EXCP_NONE; +} + +static RISCVException read_minstretcfg(CPURISCVState *env, int csrno, + target_ulong *val) +{ + *val = env->minstretcfg; + return RISCV_EXCP_NONE; +} + +static RISCVException write_minstretcfg(CPURISCVState *env, int csrno, + target_ulong val) +{ + uint64_t inh_avail_mask; + + if (riscv_cpu_mxl(env) == MXL_RV32) { + env->minstretcfg = val; + } else { + inh_avail_mask = ~MHPMEVENT_FILTER_MASK | MINSTRETCFG_BIT_MINH; + inh_avail_mask |= riscv_has_ext(env, RVU) ? MINSTRETCFG_BIT_UINH : 0; + inh_avail_mask |= riscv_has_ext(env, RVS) ? MINSTRETCFG_BIT_SINH : 0; + inh_avail_mask |= (riscv_has_ext(env, RVH) && + riscv_has_ext(env, RVU)) ? MINSTRETCFG_BIT_VUINH : 0; + inh_avail_mask |= (riscv_has_ext(env, RVH) && + riscv_has_ext(env, RVS)) ? MINSTRETCFG_BIT_VSINH : 0; + env->minstretcfg = val & inh_avail_mask; + } + return RISCV_EXCP_NONE; +} + +static RISCVException read_minstretcfgh(CPURISCVState *env, int csrno, + target_ulong *val) +{ + *val = env->minstretcfgh; + return RISCV_EXCP_NONE; +} + +static RISCVException write_minstretcfgh(CPURISCVState *env, int csrno, + target_ulong val) +{ + target_ulong inh_avail_mask = (target_ulong)(~MHPMEVENTH_FILTER_MASK | + MINSTRETCFGH_BIT_MINH); + + inh_avail_mask |= riscv_has_ext(env, RVU) ? MINSTRETCFGH_BIT_UINH : 0; + inh_avail_mask |= riscv_has_ext(env, RVS) ? MINSTRETCFGH_BIT_SINH : 0; + inh_avail_mask |= (riscv_has_ext(env, RVH) && + riscv_has_ext(env, RVU)) ? MINSTRETCFGH_BIT_VUINH : 0; + inh_avail_mask |= (riscv_has_ext(env, RVH) && + riscv_has_ext(env, RVS)) ? MINSTRETCFGH_BIT_VSINH : 0; + + env->minstretcfgh = val & inh_avail_mask; + return RISCV_EXCP_NONE; +} + static RISCVException read_mhpmevent(CPURISCVState *env, int csrno, target_ulong *val) { @@ -5056,6 +5178,13 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { write_mcountinhibit, .min_priv_ver = PRIV_VERSION_1_11_0 }, + [CSR_MCYCLECFG] = { "mcyclecfg", smcntrpmf, read_mcyclecfg, + write_mcyclecfg, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MINSTRETCFG] = { "minstretcfg", smcntrpmf, read_minstretcfg, + write_minstretcfg, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MHPMEVENT3] = { "mhpmevent3", any, read_mhpmevent, write_mhpmevent }, [CSR_MHPMEVENT4] = { "mhpmevent4", any, read_mhpmevent, @@ -5115,6 +5244,13 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_MHPMEVENT31] = { "mhpmevent31", any, read_mhpmevent, write_mhpmevent }, + [CSR_MCYCLECFGH] = { "mcyclecfgh", smcntrpmf_32, read_mcyclecfgh, + write_mcyclecfgh, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MINSTRETCFGH] = { "minstretcfgh", smcntrpmf_32, read_minstretcfgh, + write_minstretcfgh, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_MHPMEVENT3H] = { "mhpmevent3h", sscofpmf_32, read_mhpmeventh, write_mhpmeventh, .min_priv_ver = PRIV_VERSION_1_12_0 }, From 3b31b7baff02b357a6c921b26ae953e04d0cfdbb Mon Sep 17 00:00:00 2001 From: Atish Patra Date: Thu, 11 Jul 2024 15:31:09 -0700 Subject: [PATCH 20/30] target/riscv: Only set INH fields if priv mode is available Currently, the INH fields are set in mhpmevent uncoditionally without checking if a particular priv mode is supported or not. Suggested-by: Alistair Francis Signed-off-by: Atish Patra Acked-by: Alistair Francis Message-ID: <20240711-smcntrpmf_v7-v8-6-b7c38ae7b263@rivosinc.com> Signed-off-by: Alistair Francis --- target/riscv/csr.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 8831d4f5ec..364583dc03 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -967,13 +967,24 @@ static RISCVException write_mhpmevent(CPURISCVState *env, int csrno, { int evt_index = csrno - CSR_MCOUNTINHIBIT; uint64_t mhpmevt_val = val; - - env->mhpmevent_val[evt_index] = val; + uint64_t inh_avail_mask; if (riscv_cpu_mxl(env) == MXL_RV32) { + env->mhpmevent_val[evt_index] = val; mhpmevt_val = mhpmevt_val | ((uint64_t)env->mhpmeventh_val[evt_index] << 32); + } else { + inh_avail_mask = ~MHPMEVENT_FILTER_MASK | MHPMEVENT_BIT_MINH; + inh_avail_mask |= riscv_has_ext(env, RVU) ? MHPMEVENT_BIT_UINH : 0; + inh_avail_mask |= riscv_has_ext(env, RVS) ? MHPMEVENT_BIT_SINH : 0; + inh_avail_mask |= (riscv_has_ext(env, RVH) && + riscv_has_ext(env, RVU)) ? MHPMEVENT_BIT_VUINH : 0; + inh_avail_mask |= (riscv_has_ext(env, RVH) && + riscv_has_ext(env, RVS)) ? MHPMEVENT_BIT_VSINH : 0; + mhpmevt_val = val & inh_avail_mask; + env->mhpmevent_val[evt_index] = mhpmevt_val; } + riscv_pmu_update_event_map(env, mhpmevt_val, evt_index); return RISCV_EXCP_NONE; @@ -993,11 +1004,21 @@ static RISCVException write_mhpmeventh(CPURISCVState *env, int csrno, target_ulong val) { int evt_index = csrno - CSR_MHPMEVENT3H + 3; - uint64_t mhpmevth_val = val; + uint64_t mhpmevth_val; uint64_t mhpmevt_val = env->mhpmevent_val[evt_index]; + target_ulong inh_avail_mask = (target_ulong)(~MHPMEVENTH_FILTER_MASK | + MHPMEVENTH_BIT_MINH); + inh_avail_mask |= riscv_has_ext(env, RVU) ? MHPMEVENTH_BIT_UINH : 0; + inh_avail_mask |= riscv_has_ext(env, RVS) ? MHPMEVENTH_BIT_SINH : 0; + inh_avail_mask |= (riscv_has_ext(env, RVH) && + riscv_has_ext(env, RVU)) ? MHPMEVENTH_BIT_VUINH : 0; + inh_avail_mask |= (riscv_has_ext(env, RVH) && + riscv_has_ext(env, RVS)) ? MHPMEVENTH_BIT_VSINH : 0; + + mhpmevth_val = val & inh_avail_mask; mhpmevt_val = mhpmevt_val | (mhpmevth_val << 32); - env->mhpmeventh_val[evt_index] = val; + env->mhpmeventh_val[evt_index] = mhpmevth_val; riscv_pmu_update_event_map(env, mhpmevt_val, evt_index); From b2d7a7c7e4e30fb5341d38deac968de675f9419c Mon Sep 17 00:00:00 2001 From: Atish Patra Date: Thu, 11 Jul 2024 15:31:10 -0700 Subject: [PATCH 21/30] target/riscv: Implement privilege mode filtering for cycle/instret Privilege mode filtering can also be emulated for cycle/instret by tracking host_ticks/icount during each privilege mode switch. This patch implements that for both cycle/instret and mhpmcounters. The first one requires Smcntrpmf while the other one requires Sscofpmf to be enabled. The cycle/instret are still computed using host ticks when icount is not enabled. Otherwise, they are computed using raw icount which is more accurate in icount mode. Co-Developed-by: Rajnesh Kanwal Signed-off-by: Rajnesh Kanwal Reviewed-by: Daniel Henrique Barboza Acked-by: Alistair Francis Signed-off-by: Atish Patra Message-ID: <20240711-smcntrpmf_v7-v8-7-b7c38ae7b263@rivosinc.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.h | 11 ++++ target/riscv/cpu_helper.c | 9 ++- target/riscv/csr.c | 117 ++++++++++++++++++++++++++------------ target/riscv/pmu.c | 92 ++++++++++++++++++++++++++++++ target/riscv/pmu.h | 2 + 5 files changed, 194 insertions(+), 37 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 980e2154cd..f515ad072b 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -181,6 +181,15 @@ typedef struct PMUCTRState { target_ulong irq_overflow_left; } PMUCTRState; +typedef struct PMUFixedCtrState { + /* Track cycle and icount for each privilege mode */ + uint64_t counter[4]; + uint64_t counter_prev[4]; + /* Track cycle and icount for each privilege mode when V = 1*/ + uint64_t counter_virt[2]; + uint64_t counter_virt_prev[2]; +} PMUFixedCtrState; + struct CPUArchState { target_ulong gpr[32]; target_ulong gprh[32]; /* 64 top bits of the 128-bit registers */ @@ -377,6 +386,8 @@ struct CPUArchState { /* PMU event selector configured values for RV32 */ target_ulong mhpmeventh_val[RV_MAX_MHPMEVENTS]; + PMUFixedCtrState pmu_fixed_ctrs[2]; + target_ulong sscratch; target_ulong mscratch; diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 10d3fdaed3..395a1d9140 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -695,9 +695,14 @@ void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv, bool virt_en) { g_assert(newpriv <= PRV_M && newpriv != PRV_RESERVED); - if (icount_enabled() && newpriv != env->priv) { - riscv_itrigger_update_priv(env); + if (newpriv != env->priv || env->virt_enabled != virt_en) { + if (icount_enabled()) { + riscv_itrigger_update_priv(env); + } + + riscv_pmu_update_fixed_ctrs(env, newpriv, virt_en); } + /* tlb_flush is unnecessary as mode is contained in mmu_idx */ env->priv = newpriv; env->xl = cpu_recompute_xl(env); diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 364583dc03..85d3f0aa3f 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -787,36 +787,16 @@ static RISCVException write_vcsr(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } +#if defined(CONFIG_USER_ONLY) /* User Timers and Counters */ -static target_ulong get_ticks(bool shift, bool instructions) +static target_ulong get_ticks(bool shift) { - int64_t val; - target_ulong result; - -#if !defined(CONFIG_USER_ONLY) - if (icount_enabled()) { - if (instructions) { - val = icount_get_raw(); - } else { - val = icount_get(); - } - } else { - val = cpu_get_host_ticks(); - } -#else - val = cpu_get_host_ticks(); -#endif - - if (shift) { - result = val >> 32; - } else { - result = val; - } + int64_t val = cpu_get_host_ticks(); + target_ulong result = shift ? val >> 32 : val; return result; } -#if defined(CONFIG_USER_ONLY) static RISCVException read_time(CPURISCVState *env, int csrno, target_ulong *val) { @@ -834,14 +814,14 @@ static RISCVException read_timeh(CPURISCVState *env, int csrno, static RISCVException read_hpmcounter(CPURISCVState *env, int csrno, target_ulong *val) { - *val = get_ticks(false, (csrno == CSR_INSTRET)); + *val = get_ticks(false); return RISCV_EXCP_NONE; } static RISCVException read_hpmcounterh(CPURISCVState *env, int csrno, target_ulong *val) { - *val = get_ticks(true, (csrno == CSR_INSTRETH)); + *val = get_ticks(true); return RISCV_EXCP_NONE; } @@ -1025,17 +1005,82 @@ static RISCVException write_mhpmeventh(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } +static target_ulong riscv_pmu_ctr_get_fixed_counters_val(CPURISCVState *env, + int counter_idx, + bool upper_half) +{ + int inst = riscv_pmu_ctr_monitor_instructions(env, counter_idx); + uint64_t *counter_arr_virt = env->pmu_fixed_ctrs[inst].counter_virt; + uint64_t *counter_arr = env->pmu_fixed_ctrs[inst].counter; + target_ulong result = 0; + uint64_t curr_val = 0; + uint64_t cfg_val = 0; + + if (counter_idx == 0) { + cfg_val = upper_half ? ((uint64_t)env->mcyclecfgh << 32) : + env->mcyclecfg; + } else if (counter_idx == 2) { + cfg_val = upper_half ? ((uint64_t)env->minstretcfgh << 32) : + env->minstretcfg; + } else { + cfg_val = upper_half ? + ((uint64_t)env->mhpmeventh_val[counter_idx] << 32) : + env->mhpmevent_val[counter_idx]; + cfg_val &= MHPMEVENT_FILTER_MASK; + } + + if (!cfg_val) { + if (icount_enabled()) { + curr_val = inst ? icount_get_raw() : icount_get(); + } else { + curr_val = cpu_get_host_ticks(); + } + + goto done; + } + + if (!(cfg_val & MCYCLECFG_BIT_MINH)) { + curr_val += counter_arr[PRV_M]; + } + + if (!(cfg_val & MCYCLECFG_BIT_SINH)) { + curr_val += counter_arr[PRV_S]; + } + + if (!(cfg_val & MCYCLECFG_BIT_UINH)) { + curr_val += counter_arr[PRV_U]; + } + + if (!(cfg_val & MCYCLECFG_BIT_VSINH)) { + curr_val += counter_arr_virt[PRV_S]; + } + + if (!(cfg_val & MCYCLECFG_BIT_VUINH)) { + curr_val += counter_arr_virt[PRV_U]; + } + +done: + if (riscv_cpu_mxl(env) == MXL_RV32) { + result = upper_half ? curr_val >> 32 : curr_val; + } else { + result = curr_val; + } + + return result; +} + static RISCVException write_mhpmcounter(CPURISCVState *env, int csrno, target_ulong val) { int ctr_idx = csrno - CSR_MCYCLE; PMUCTRState *counter = &env->pmu_ctrs[ctr_idx]; uint64_t mhpmctr_val = val; - bool instr = riscv_pmu_ctr_monitor_instructions(env, ctr_idx); counter->mhpmcounter_val = val; - if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || instr) { - counter->mhpmcounter_prev = get_ticks(false, instr); + if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || + riscv_pmu_ctr_monitor_instructions(env, ctr_idx)) { + counter->mhpmcounter_prev = riscv_pmu_ctr_get_fixed_counters_val(env, + ctr_idx, false); if (ctr_idx > 2) { if (riscv_cpu_mxl(env) == MXL_RV32) { mhpmctr_val = mhpmctr_val | @@ -1058,12 +1103,13 @@ static RISCVException write_mhpmcounterh(CPURISCVState *env, int csrno, PMUCTRState *counter = &env->pmu_ctrs[ctr_idx]; uint64_t mhpmctr_val = counter->mhpmcounter_val; uint64_t mhpmctrh_val = val; - bool instr = riscv_pmu_ctr_monitor_instructions(env, ctr_idx); counter->mhpmcounterh_val = val; mhpmctr_val = mhpmctr_val | (mhpmctrh_val << 32); - if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || instr) { - counter->mhpmcounterh_prev = get_ticks(true, instr); + if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || + riscv_pmu_ctr_monitor_instructions(env, ctr_idx)) { + counter->mhpmcounterh_prev = riscv_pmu_ctr_get_fixed_counters_val(env, + ctr_idx, true); if (ctr_idx > 2) { riscv_pmu_setup_timer(env, mhpmctr_val, ctr_idx); } @@ -1082,7 +1128,6 @@ static RISCVException riscv_pmu_read_ctr(CPURISCVState *env, target_ulong *val, counter->mhpmcounter_prev; target_ulong ctr_val = upper_half ? counter->mhpmcounterh_val : counter->mhpmcounter_val; - bool instr = riscv_pmu_ctr_monitor_instructions(env, ctr_idx); if (get_field(env->mcountinhibit, BIT(ctr_idx))) { /* @@ -1103,8 +1148,10 @@ static RISCVException riscv_pmu_read_ctr(CPURISCVState *env, target_ulong *val, * The kernel computes the perf delta by subtracting the current value from * the value it initialized previously (ctr_val). */ - if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || instr) { - *val = get_ticks(upper_half, instr) - ctr_prev + ctr_val; + if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || + riscv_pmu_ctr_monitor_instructions(env, ctr_idx)) { + *val = riscv_pmu_ctr_get_fixed_counters_val(env, ctr_idx, upper_half) - + ctr_prev + ctr_val; } else { *val = ctr_val; } diff --git a/target/riscv/pmu.c b/target/riscv/pmu.c index 0e7d58b8a5..ac648cff8d 100644 --- a/target/riscv/pmu.c +++ b/target/riscv/pmu.c @@ -19,6 +19,7 @@ #include "qemu/osdep.h" #include "qemu/log.h" #include "qemu/error-report.h" +#include "qemu/timer.h" #include "cpu.h" #include "pmu.h" #include "sysemu/cpu-timers.h" @@ -176,6 +177,97 @@ static int riscv_pmu_incr_ctr_rv64(RISCVCPU *cpu, uint32_t ctr_idx) return 0; } +/* + * Information needed to update counters: + * new_priv, new_virt: To correctly save starting snapshot for the newly + * started mode. Look at array being indexed with newprv. + * old_priv, old_virt: To correctly select previous snapshot for old priv + * and compute delta. Also to select correct counter + * to inc. Look at arrays being indexed with env->priv. + * + * To avoid the complexity of calling this function, we assume that + * env->priv and env->virt_enabled contain old priv and old virt and + * new priv and new virt values are passed in as arguments. + */ +static void riscv_pmu_icount_update_priv(CPURISCVState *env, + target_ulong newpriv, bool new_virt) +{ + uint64_t *snapshot_prev, *snapshot_new; + uint64_t current_icount; + uint64_t *counter_arr; + uint64_t delta; + + if (icount_enabled()) { + current_icount = icount_get_raw(); + } else { + current_icount = cpu_get_host_ticks(); + } + + if (env->virt_enabled) { + counter_arr = env->pmu_fixed_ctrs[1].counter_virt; + snapshot_prev = env->pmu_fixed_ctrs[1].counter_virt_prev; + } else { + counter_arr = env->pmu_fixed_ctrs[1].counter; + snapshot_prev = env->pmu_fixed_ctrs[1].counter_prev; + } + + if (new_virt) { + snapshot_new = env->pmu_fixed_ctrs[1].counter_virt_prev; + } else { + snapshot_new = env->pmu_fixed_ctrs[1].counter_prev; + } + + /* + * new_priv can be same as env->priv. So we need to calculate + * delta first before updating snapshot_new[new_priv]. + */ + delta = current_icount - snapshot_prev[env->priv]; + snapshot_new[newpriv] = current_icount; + + counter_arr[env->priv] += delta; +} + +static void riscv_pmu_cycle_update_priv(CPURISCVState *env, + target_ulong newpriv, bool new_virt) +{ + uint64_t *snapshot_prev, *snapshot_new; + uint64_t current_ticks; + uint64_t *counter_arr; + uint64_t delta; + + if (icount_enabled()) { + current_ticks = icount_get(); + } else { + current_ticks = cpu_get_host_ticks(); + } + + if (env->virt_enabled) { + counter_arr = env->pmu_fixed_ctrs[0].counter_virt; + snapshot_prev = env->pmu_fixed_ctrs[0].counter_virt_prev; + } else { + counter_arr = env->pmu_fixed_ctrs[0].counter; + snapshot_prev = env->pmu_fixed_ctrs[0].counter_prev; + } + + if (new_virt) { + snapshot_new = env->pmu_fixed_ctrs[0].counter_virt_prev; + } else { + snapshot_new = env->pmu_fixed_ctrs[0].counter_prev; + } + + delta = current_ticks - snapshot_prev[env->priv]; + snapshot_new[newpriv] = current_ticks; + + counter_arr[env->priv] += delta; +} + +void riscv_pmu_update_fixed_ctrs(CPURISCVState *env, target_ulong newpriv, + bool new_virt) +{ + riscv_pmu_cycle_update_priv(env, newpriv, new_virt); + riscv_pmu_icount_update_priv(env, newpriv, new_virt); +} + int riscv_pmu_incr_ctr(RISCVCPU *cpu, enum riscv_pmu_event_idx event_idx) { uint32_t ctr_idx; diff --git a/target/riscv/pmu.h b/target/riscv/pmu.h index 7c0ad661e0..ca40cfeed6 100644 --- a/target/riscv/pmu.h +++ b/target/riscv/pmu.h @@ -34,5 +34,7 @@ int riscv_pmu_incr_ctr(RISCVCPU *cpu, enum riscv_pmu_event_idx event_idx); void riscv_pmu_generate_fdt_node(void *fdt, uint32_t cmask, char *pmu_name); int riscv_pmu_setup_timer(CPURISCVState *env, uint64_t value, uint32_t ctr_idx); +void riscv_pmu_update_fixed_ctrs(CPURISCVState *env, target_ulong newpriv, + bool new_virt); #endif /* RISCV_PMU_H */ From 46023470e014234f3e15ec4497e003550bd7da0d Mon Sep 17 00:00:00 2001 From: Atish Patra Date: Thu, 11 Jul 2024 15:31:11 -0700 Subject: [PATCH 22/30] target/riscv: Save counter values during countinhibit update Currently, if a counter monitoring cycle/instret is stopped via mcountinhibit we just update the state while the value is saved during the next read. This is not accurate as the read may happen many cycles after the counter is stopped. Ideally, the read should return the value saved when the counter is stopped. Thus, save the value of the counter during the inhibit update operation and return that value during the read if corresponding bit in mcountihibit is set. Acked-by: Alistair Francis Reviewed-by: Daniel Henrique Barboza Signed-off-by: Atish Patra Message-ID: <20240711-smcntrpmf_v7-v8-8-b7c38ae7b263@rivosinc.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.h | 1 - target/riscv/csr.c | 34 ++++++++++++++++++++++------------ target/riscv/machine.c | 5 ++--- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index f515ad072b..093c86b8b9 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -176,7 +176,6 @@ typedef struct PMUCTRState { target_ulong mhpmcounter_prev; /* Snapshort value of a counter in RV32 */ target_ulong mhpmcounterh_prev; - bool started; /* Value beyond UINT32_MAX/UINT64_MAX before overflow interrupt trigger */ target_ulong irq_overflow_left; } PMUCTRState; diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 85d3f0aa3f..b7a24f9c60 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -1131,17 +1131,11 @@ static RISCVException riscv_pmu_read_ctr(CPURISCVState *env, target_ulong *val, if (get_field(env->mcountinhibit, BIT(ctr_idx))) { /* - * Counter should not increment if inhibit bit is set. We can't really - * stop the icount counting. Just return the counter value written by - * the supervisor to indicate that counter was not incremented. + * Counter should not increment if inhibit bit is set. Just return the + * current counter value. */ - if (!counter->started) { - *val = ctr_val; - return RISCV_EXCP_NONE; - } else { - /* Mark that the counter has been stopped */ - counter->started = false; - } + *val = ctr_val; + return RISCV_EXCP_NONE; } /* @@ -2183,9 +2177,25 @@ static RISCVException write_mcountinhibit(CPURISCVState *env, int csrno, /* Check if any other counter is also monitoring cycles/instructions */ for (cidx = 0; cidx < RV_MAX_MHPMCOUNTERS; cidx++) { - if (!get_field(env->mcountinhibit, BIT(cidx))) { counter = &env->pmu_ctrs[cidx]; - counter->started = true; + if (get_field(env->mcountinhibit, BIT(cidx)) && (val & BIT(cidx))) { + /* + * Update the counter value for cycle/instret as we can't stop the + * host ticks. But we should show the current value at this moment. + */ + if (riscv_pmu_ctr_monitor_cycles(env, cidx) || + riscv_pmu_ctr_monitor_instructions(env, cidx)) { + counter->mhpmcounter_val = + riscv_pmu_ctr_get_fixed_counters_val(env, cidx, false) - + counter->mhpmcounter_prev + + counter->mhpmcounter_val; + if (riscv_cpu_mxl(env) == MXL_RV32) { + counter->mhpmcounterh_val = + riscv_pmu_ctr_get_fixed_counters_val(env, cidx, true) - + counter->mhpmcounterh_prev + + counter->mhpmcounterh_val; + } + } } } diff --git a/target/riscv/machine.c b/target/riscv/machine.c index 76f2150f78..492c2c6d9d 100644 --- a/target/riscv/machine.c +++ b/target/riscv/machine.c @@ -320,15 +320,14 @@ static bool pmu_needed(void *opaque) static const VMStateDescription vmstate_pmu_ctr_state = { .name = "cpu/pmu", - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .needed = pmu_needed, .fields = (const VMStateField[]) { VMSTATE_UINTTL(mhpmcounter_val, PMUCTRState), VMSTATE_UINTTL(mhpmcounterh_val, PMUCTRState), VMSTATE_UINTTL(mhpmcounter_prev, PMUCTRState), VMSTATE_UINTTL(mhpmcounterh_prev, PMUCTRState), - VMSTATE_BOOL(started, PMUCTRState), VMSTATE_END_OF_LIST() } }; From 8cff74c26dbdfc746d8f0165c233be3d396d4572 Mon Sep 17 00:00:00 2001 From: Atish Patra Date: Thu, 11 Jul 2024 15:31:12 -0700 Subject: [PATCH 23/30] target/riscv: Enforce WARL behavior for scounteren/hcounteren scounteren/hcountern are also WARL registers similar to mcountern. Only set the bits for the available counters during the write to preserve the WARL behavior. Signed-off-by: Atish Patra Reviewed-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-ID: <20240711-smcntrpmf_v7-v8-9-b7c38ae7b263@rivosinc.com> Signed-off-by: Alistair Francis --- target/riscv/csr.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index b7a24f9c60..d6c5b73afd 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -3063,7 +3063,11 @@ static RISCVException read_scounteren(CPURISCVState *env, int csrno, static RISCVException write_scounteren(CPURISCVState *env, int csrno, target_ulong val) { - env->scounteren = val; + RISCVCPU *cpu = env_archcpu(env); + + /* WARL register - disable unavailable counters */ + env->scounteren = val & (cpu->pmu_avail_ctrs | COUNTEREN_CY | COUNTEREN_TM | + COUNTEREN_IR); return RISCV_EXCP_NONE; } @@ -3722,7 +3726,11 @@ static RISCVException read_hcounteren(CPURISCVState *env, int csrno, static RISCVException write_hcounteren(CPURISCVState *env, int csrno, target_ulong val) { - env->hcounteren = val; + RISCVCPU *cpu = env_archcpu(env); + + /* WARL register - disable unavailable counters */ + env->hcounteren = val & (cpu->pmu_avail_ctrs | COUNTEREN_CY | COUNTEREN_TM | + COUNTEREN_IR); return RISCV_EXCP_NONE; } From 22c721c34c1609b5ac53dfc0d34125ec479205a0 Mon Sep 17 00:00:00 2001 From: Rajnesh Kanwal Date: Thu, 11 Jul 2024 15:31:13 -0700 Subject: [PATCH 24/30] target/riscv: Start counters from both mhpmcounter and mcountinhibit Currently we start timer counter from write_mhpmcounter path only without checking for mcountinhibit bit. This changes adds mcountinhibit check and also programs the counter from write_mcountinhibit as well. When a counter is stopped using mcountinhibit we simply update the value of the counter based on current host ticks and save it for future reads. We don't need to disable running timer as pmu_timer_trigger_irq will discard the interrupt if the counter has been inhibited. Signed-off-by: Rajnesh Kanwal Reviewed-by: Daniel Henrique Barboza Message-ID: <20240711-smcntrpmf_v7-v8-10-b7c38ae7b263@rivosinc.com> Signed-off-by: Alistair Francis --- target/riscv/csr.c | 75 ++++++++++++++++++++++++++++++++-------------- target/riscv/pmu.c | 3 +- 2 files changed, 54 insertions(+), 24 deletions(-) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index d6c5b73afd..bb6ac33ac2 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -1077,8 +1077,9 @@ static RISCVException write_mhpmcounter(CPURISCVState *env, int csrno, uint64_t mhpmctr_val = val; counter->mhpmcounter_val = val; - if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || - riscv_pmu_ctr_monitor_instructions(env, ctr_idx)) { + if (!get_field(env->mcountinhibit, BIT(ctr_idx)) && + (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || + riscv_pmu_ctr_monitor_instructions(env, ctr_idx))) { counter->mhpmcounter_prev = riscv_pmu_ctr_get_fixed_counters_val(env, ctr_idx, false); if (ctr_idx > 2) { @@ -1106,8 +1107,9 @@ static RISCVException write_mhpmcounterh(CPURISCVState *env, int csrno, counter->mhpmcounterh_val = val; mhpmctr_val = mhpmctr_val | (mhpmctrh_val << 32); - if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || - riscv_pmu_ctr_monitor_instructions(env, ctr_idx)) { + if (!get_field(env->mcountinhibit, BIT(ctr_idx)) && + (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || + riscv_pmu_ctr_monitor_instructions(env, ctr_idx))) { counter->mhpmcounterh_prev = riscv_pmu_ctr_get_fixed_counters_val(env, ctr_idx, true); if (ctr_idx > 2) { @@ -2170,31 +2172,60 @@ static RISCVException write_mcountinhibit(CPURISCVState *env, int csrno, int cidx; PMUCTRState *counter; RISCVCPU *cpu = env_archcpu(env); + uint32_t present_ctrs = cpu->pmu_avail_ctrs | COUNTEREN_CY | COUNTEREN_IR; + target_ulong updated_ctrs = (env->mcountinhibit ^ val) & present_ctrs; + uint64_t mhpmctr_val, prev_count, curr_count; /* WARL register - disable unavailable counters; TM bit is always 0 */ - env->mcountinhibit = - val & (cpu->pmu_avail_ctrs | COUNTEREN_CY | COUNTEREN_IR); + env->mcountinhibit = val & present_ctrs; /* Check if any other counter is also monitoring cycles/instructions */ for (cidx = 0; cidx < RV_MAX_MHPMCOUNTERS; cidx++) { - counter = &env->pmu_ctrs[cidx]; - if (get_field(env->mcountinhibit, BIT(cidx)) && (val & BIT(cidx))) { - /* - * Update the counter value for cycle/instret as we can't stop the - * host ticks. But we should show the current value at this moment. - */ - if (riscv_pmu_ctr_monitor_cycles(env, cidx) || - riscv_pmu_ctr_monitor_instructions(env, cidx)) { - counter->mhpmcounter_val = - riscv_pmu_ctr_get_fixed_counters_val(env, cidx, false) - - counter->mhpmcounter_prev + - counter->mhpmcounter_val; + if (!(updated_ctrs & BIT(cidx)) || + (!riscv_pmu_ctr_monitor_cycles(env, cidx) && + !riscv_pmu_ctr_monitor_instructions(env, cidx))) { + continue; + } + + counter = &env->pmu_ctrs[cidx]; + + if (!get_field(env->mcountinhibit, BIT(cidx))) { + counter->mhpmcounter_prev = + riscv_pmu_ctr_get_fixed_counters_val(env, cidx, false); + if (riscv_cpu_mxl(env) == MXL_RV32) { + counter->mhpmcounterh_prev = + riscv_pmu_ctr_get_fixed_counters_val(env, cidx, true); + } + + if (cidx > 2) { + mhpmctr_val = counter->mhpmcounter_val; if (riscv_cpu_mxl(env) == MXL_RV32) { - counter->mhpmcounterh_val = - riscv_pmu_ctr_get_fixed_counters_val(env, cidx, true) - - counter->mhpmcounterh_prev + - counter->mhpmcounterh_val; + mhpmctr_val = mhpmctr_val | + ((uint64_t)counter->mhpmcounterh_val << 32); } + riscv_pmu_setup_timer(env, mhpmctr_val, cidx); + } + } else { + curr_count = riscv_pmu_ctr_get_fixed_counters_val(env, cidx, false); + + mhpmctr_val = counter->mhpmcounter_val; + prev_count = counter->mhpmcounter_prev; + if (riscv_cpu_mxl(env) == MXL_RV32) { + uint64_t tmp = + riscv_pmu_ctr_get_fixed_counters_val(env, cidx, true); + + curr_count = curr_count | (tmp << 32); + mhpmctr_val = mhpmctr_val | + ((uint64_t)counter->mhpmcounterh_val << 32); + prev_count = prev_count | + ((uint64_t)counter->mhpmcounterh_prev << 32); + } + + /* Adjust the counter for later reads. */ + mhpmctr_val = curr_count - prev_count + mhpmctr_val; + counter->mhpmcounter_val = mhpmctr_val; + if (riscv_cpu_mxl(env) == MXL_RV32) { + counter->mhpmcounterh_val = mhpmctr_val >> 32; } } } diff --git a/target/riscv/pmu.c b/target/riscv/pmu.c index ac648cff8d..63420d9f36 100644 --- a/target/riscv/pmu.c +++ b/target/riscv/pmu.c @@ -285,8 +285,7 @@ int riscv_pmu_incr_ctr(RISCVCPU *cpu, enum riscv_pmu_event_idx event_idx) } ctr_idx = GPOINTER_TO_UINT(value); - if (!riscv_pmu_counter_enabled(cpu, ctr_idx) || - get_field(env->mcountinhibit, BIT(ctr_idx))) { + if (!riscv_pmu_counter_enabled(cpu, ctr_idx)) { return -1; } From 74112400df659b0edb1da35db5c948313ffeffd0 Mon Sep 17 00:00:00 2001 From: Rajnesh Kanwal Date: Thu, 11 Jul 2024 15:31:14 -0700 Subject: [PATCH 25/30] target/riscv: More accurately model priv mode filtering. In case of programmable counters configured to count inst/cycles we often end-up with counter not incrementing at all from kernel's perspective. For example: - Kernel configures hpm3 to count instructions and sets hpmcounter to -10000 and all modes except U mode are inhibited. - In QEMU we configure a timer to expire after ~10000 instructions. - Problem is, it's often the case that kernel might not even schedule Umode task and we hit the timer callback in QEMU. - In the timer callback we inject the interrupt into kernel, kernel runs the handler and reads hpmcounter3 value. - Given QEMU maintains individual counters to count for each privilege mode, and given umode never ran, the umode counter didn't increment and QEMU returns same value as was programmed by the kernel when starting the counter. - Kernel checks for overflow using previous and current value of the counter and reprograms the counter given there wasn't an overflow as per the counter value. (Which itself is a problem. We have QEMU telling kernel that counter3 overflowed but the counter value returned by QEMU doesn't seem to reflect that.). This change makes sure that timer is reprogrammed from the handler if the counter didn't overflow based on the counter value. Second, this change makes sure that whenever the counter is read, it's value is updated to reflect the latest count. Signed-off-by: Rajnesh Kanwal Reviewed-by: Daniel Henrique Barboza Message-ID: <20240711-smcntrpmf_v7-v8-11-b7c38ae7b263@rivosinc.com> Signed-off-by: Alistair Francis --- target/riscv/csr.c | 5 ++++- target/riscv/pmu.c | 30 +++++++++++++++++++++++++++--- target/riscv/pmu.h | 2 ++ 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index bb6ac33ac2..781ef27eba 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -1039,6 +1039,9 @@ static target_ulong riscv_pmu_ctr_get_fixed_counters_val(CPURISCVState *env, goto done; } + /* Update counter before reading. */ + riscv_pmu_update_fixed_ctrs(env, env->priv, env->virt_enabled); + if (!(cfg_val & MCYCLECFG_BIT_MINH)) { curr_val += counter_arr[PRV_M]; } @@ -1122,7 +1125,7 @@ static RISCVException write_mhpmcounterh(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } -static RISCVException riscv_pmu_read_ctr(CPURISCVState *env, target_ulong *val, +RISCVException riscv_pmu_read_ctr(CPURISCVState *env, target_ulong *val, bool upper_half, uint32_t ctr_idx) { PMUCTRState *counter = &env->pmu_ctrs[ctr_idx]; diff --git a/target/riscv/pmu.c b/target/riscv/pmu.c index 63420d9f36..a4729f6c53 100644 --- a/target/riscv/pmu.c +++ b/target/riscv/pmu.c @@ -425,6 +425,8 @@ static void pmu_timer_trigger_irq(RISCVCPU *cpu, target_ulong *mhpmevent_val; uint64_t of_bit_mask; int64_t irq_trigger_at; + uint64_t curr_ctr_val, curr_ctrh_val; + uint64_t ctr_val; if (evt_idx != RISCV_PMU_EVENT_HW_CPU_CYCLES && evt_idx != RISCV_PMU_EVENT_HW_INSTRUCTIONS) { @@ -454,6 +456,26 @@ static void pmu_timer_trigger_irq(RISCVCPU *cpu, return; } + riscv_pmu_read_ctr(env, (target_ulong *)&curr_ctr_val, false, ctr_idx); + ctr_val = counter->mhpmcounter_val; + if (riscv_cpu_mxl(env) == MXL_RV32) { + riscv_pmu_read_ctr(env, (target_ulong *)&curr_ctrh_val, true, ctr_idx); + curr_ctr_val = curr_ctr_val | (curr_ctrh_val << 32); + ctr_val = ctr_val | + ((uint64_t)counter->mhpmcounterh_val << 32); + } + + /* + * We can not accommodate for inhibited modes when setting up timer. Check + * if the counter has actually overflowed or not by comparing current + * counter value (accommodated for inhibited modes) with software written + * counter value. + */ + if (curr_ctr_val >= ctr_val) { + riscv_pmu_setup_timer(env, curr_ctr_val, ctr_idx); + return; + } + if (cpu->pmu_avail_ctrs & BIT(ctr_idx)) { /* Generate interrupt only if OF bit is clear */ if (!(*mhpmevent_val & of_bit_mask)) { @@ -475,7 +497,7 @@ void riscv_pmu_timer_cb(void *priv) int riscv_pmu_setup_timer(CPURISCVState *env, uint64_t value, uint32_t ctr_idx) { - uint64_t overflow_delta, overflow_at; + uint64_t overflow_delta, overflow_at, curr_ns; int64_t overflow_ns, overflow_left = 0; RISCVCPU *cpu = env_archcpu(env); PMUCTRState *counter = &env->pmu_ctrs[ctr_idx]; @@ -506,8 +528,10 @@ int riscv_pmu_setup_timer(CPURISCVState *env, uint64_t value, uint32_t ctr_idx) } else { return -1; } - overflow_at = (uint64_t)qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + - overflow_ns; + curr_ns = (uint64_t)qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + overflow_at = curr_ns + overflow_ns; + if (overflow_at <= curr_ns) + overflow_at = UINT64_MAX; if (overflow_at > INT64_MAX) { overflow_left += overflow_at - INT64_MAX; diff --git a/target/riscv/pmu.h b/target/riscv/pmu.h index ca40cfeed6..3853d0e262 100644 --- a/target/riscv/pmu.h +++ b/target/riscv/pmu.h @@ -36,5 +36,7 @@ int riscv_pmu_setup_timer(CPURISCVState *env, uint64_t value, uint32_t ctr_idx); void riscv_pmu_update_fixed_ctrs(CPURISCVState *env, target_ulong newpriv, bool new_virt); +RISCVException riscv_pmu_read_ctr(CPURISCVState *env, target_ulong *val, + bool upper_half, uint32_t ctr_idx); #endif /* RISCV_PMU_H */ From dd4c123636dbdabd7dcc4f76c97af90271cd5fb6 Mon Sep 17 00:00:00 2001 From: Atish Patra Date: Thu, 11 Jul 2024 15:31:15 -0700 Subject: [PATCH 26/30] target/riscv: Do not setup pmu timer if OF is disabled The timer is setup function is invoked in both hpmcounter write and mcountinhibit write path. If the OF bit set, the LCOFI interrupt is disabled. There is no benefitting in setting up the qemu timer until LCOFI is cleared to indicate that interrupts can be fired again. Reviewed-by: Daniel Henrique Barboza Signed-off-by: Atish Patra Message-ID: <20240711-smcntrpmf_v7-v8-12-b7c38ae7b263@rivosinc.com> Signed-off-by: Alistair Francis --- target/riscv/pmu.c | 56 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/target/riscv/pmu.c b/target/riscv/pmu.c index a4729f6c53..3cc0b3648c 100644 --- a/target/riscv/pmu.c +++ b/target/riscv/pmu.c @@ -416,14 +416,49 @@ int riscv_pmu_update_event_map(CPURISCVState *env, uint64_t value, return 0; } +static bool pmu_hpmevent_is_of_set(CPURISCVState *env, uint32_t ctr_idx) +{ + target_ulong mhpmevent_val; + uint64_t of_bit_mask; + + if (riscv_cpu_mxl(env) == MXL_RV32) { + mhpmevent_val = env->mhpmeventh_val[ctr_idx]; + of_bit_mask = MHPMEVENTH_BIT_OF; + } else { + mhpmevent_val = env->mhpmevent_val[ctr_idx]; + of_bit_mask = MHPMEVENT_BIT_OF; + } + + return get_field(mhpmevent_val, of_bit_mask); +} + +static bool pmu_hpmevent_set_of_if_clear(CPURISCVState *env, uint32_t ctr_idx) +{ + target_ulong *mhpmevent_val; + uint64_t of_bit_mask; + + if (riscv_cpu_mxl(env) == MXL_RV32) { + mhpmevent_val = &env->mhpmeventh_val[ctr_idx]; + of_bit_mask = MHPMEVENTH_BIT_OF; + } else { + mhpmevent_val = &env->mhpmevent_val[ctr_idx]; + of_bit_mask = MHPMEVENT_BIT_OF; + } + + if (!get_field(*mhpmevent_val, of_bit_mask)) { + *mhpmevent_val |= of_bit_mask; + return true; + } + + return false; +} + static void pmu_timer_trigger_irq(RISCVCPU *cpu, enum riscv_pmu_event_idx evt_idx) { uint32_t ctr_idx; CPURISCVState *env = &cpu->env; PMUCTRState *counter; - target_ulong *mhpmevent_val; - uint64_t of_bit_mask; int64_t irq_trigger_at; uint64_t curr_ctr_val, curr_ctrh_val; uint64_t ctr_val; @@ -439,12 +474,9 @@ static void pmu_timer_trigger_irq(RISCVCPU *cpu, return; } - if (riscv_cpu_mxl(env) == MXL_RV32) { - mhpmevent_val = &env->mhpmeventh_val[ctr_idx]; - of_bit_mask = MHPMEVENTH_BIT_OF; - } else { - mhpmevent_val = &env->mhpmevent_val[ctr_idx]; - of_bit_mask = MHPMEVENT_BIT_OF; + /* Generate interrupt only if OF bit is clear */ + if (pmu_hpmevent_is_of_set(env, ctr_idx)) { + return; } counter = &env->pmu_ctrs[ctr_idx]; @@ -477,9 +509,7 @@ static void pmu_timer_trigger_irq(RISCVCPU *cpu, } if (cpu->pmu_avail_ctrs & BIT(ctr_idx)) { - /* Generate interrupt only if OF bit is clear */ - if (!(*mhpmevent_val & of_bit_mask)) { - *mhpmevent_val |= of_bit_mask; + if (pmu_hpmevent_set_of_if_clear(env, ctr_idx)) { riscv_cpu_update_mip(env, MIP_LCOFIP, BOOL_TO_MASK(1)); } } @@ -502,7 +532,9 @@ int riscv_pmu_setup_timer(CPURISCVState *env, uint64_t value, uint32_t ctr_idx) RISCVCPU *cpu = env_archcpu(env); PMUCTRState *counter = &env->pmu_ctrs[ctr_idx]; - if (!riscv_pmu_counter_valid(cpu, ctr_idx) || !cpu->cfg.ext_sscofpmf) { + /* No need to setup a timer if LCOFI is disabled when OF is set */ + if (!riscv_pmu_counter_valid(cpu, ctr_idx) || !cpu->cfg.ext_sscofpmf || + pmu_hpmevent_is_of_set(env, ctr_idx)) { return -1; } From 6f6592d62ebaffff353bdd27ec4480972695d24b Mon Sep 17 00:00:00 2001 From: Atish Patra Date: Thu, 11 Jul 2024 15:31:16 -0700 Subject: [PATCH 27/30] target/riscv: Expose the Smcntrpmf config Create a new config for Smcntrpmf extension so that it can be enabled/ disabled from the qemu commandline. Signed-off-by: Atish Patra Acked-by: Alistair Francis Message-ID: <20240711-smcntrpmf_v7-v8-13-b7c38ae7b263@rivosinc.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 4efe7ee3b0..a90808a3ba 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1472,6 +1472,7 @@ const char *riscv_get_misa_ext_description(uint32_t bit) const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = { /* Defaults for standard extensions */ MULTI_EXT_CFG_BOOL("sscofpmf", ext_sscofpmf, false), + MULTI_EXT_CFG_BOOL("smcntrpmf", ext_smcntrpmf, false), MULTI_EXT_CFG_BOOL("zifencei", ext_zifencei, true), MULTI_EXT_CFG_BOOL("zicsr", ext_zicsr, true), MULTI_EXT_CFG_BOOL("zihintntl", ext_zihintntl, true), From 38c83e8d3a333b8b377367756a2b6c700c7d0084 Mon Sep 17 00:00:00 2001 From: Yu-Ming Chang Date: Fri, 8 Mar 2024 15:48:03 +0800 Subject: [PATCH 28/30] target/riscv: raise an exception when CSRRS/CSRRC writes a read-only CSR Both CSRRS and CSRRC always read the addressed CSR and cause any read side effects regardless of rs1 and rd fields. Note that if rs1 specifies a register holding a zero value other than x0, the instruction will still attempt to write the unmodified value back to the CSR and will cause any attendant side effects. So if CSRRS or CSRRC tries to write a read-only CSR with rs1 which specifies a register holding a zero value, an illegal instruction exception should be raised. Signed-off-by: Yu-Ming Chang Signed-off-by: Alvin Chang Reviewed-by: Alistair Francis Message-ID: <172100444279.18077.6893072378718059541-0@git.sr.ht> Signed-off-by: Alistair Francis --- target/riscv/cpu.h | 4 +++ target/riscv/csr.c | 57 ++++++++++++++++++++++++++++++++++++---- target/riscv/op_helper.c | 6 ++--- 3 files changed, 58 insertions(+), 9 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 093c86b8b9..1619c3acb6 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -751,6 +751,8 @@ void cpu_get_tb_cpu_state(CPURISCVState *env, vaddr *pc, void riscv_cpu_update_mask(CPURISCVState *env); bool riscv_cpu_is_32bit(RISCVCPU *cpu); +RISCVException riscv_csrr(CPURISCVState *env, int csrno, + target_ulong *ret_value); RISCVException riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value, target_ulong new_value, target_ulong write_mask); @@ -783,6 +785,8 @@ typedef RISCVException (*riscv_csr_op_fn)(CPURISCVState *env, int csrno, target_ulong new_value, target_ulong write_mask); +RISCVException riscv_csrr_i128(CPURISCVState *env, int csrno, + Int128 *ret_value); RISCVException riscv_csrrw_i128(CPURISCVState *env, int csrno, Int128 *ret_value, Int128 new_value, Int128 write_mask); diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 781ef27eba..ea3560342c 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -4624,7 +4624,7 @@ static RISCVException rmw_seed(CPURISCVState *env, int csrno, static inline RISCVException riscv_csrrw_check(CPURISCVState *env, int csrno, - bool write_mask) + bool write) { /* check privileges and return RISCV_EXCP_ILLEGAL_INST if check fails */ bool read_only = get_field(csrno, 0xC00) == 3; @@ -4646,7 +4646,7 @@ static inline RISCVException riscv_csrrw_check(CPURISCVState *env, } /* read / write check */ - if (write_mask && read_only) { + if (write && read_only) { return RISCV_EXCP_ILLEGAL_INST; } @@ -4733,11 +4733,22 @@ static RISCVException riscv_csrrw_do64(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } +RISCVException riscv_csrr(CPURISCVState *env, int csrno, + target_ulong *ret_value) +{ + RISCVException ret = riscv_csrrw_check(env, csrno, false); + if (ret != RISCV_EXCP_NONE) { + return ret; + } + + return riscv_csrrw_do64(env, csrno, ret_value, 0, 0); +} + RISCVException riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value, target_ulong new_value, target_ulong write_mask) { - RISCVException ret = riscv_csrrw_check(env, csrno, write_mask); + RISCVException ret = riscv_csrrw_check(env, csrno, true); if (ret != RISCV_EXCP_NONE) { return ret; } @@ -4785,13 +4796,45 @@ static RISCVException riscv_csrrw_do128(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } +RISCVException riscv_csrr_i128(CPURISCVState *env, int csrno, + Int128 *ret_value) +{ + RISCVException ret; + + ret = riscv_csrrw_check(env, csrno, false); + if (ret != RISCV_EXCP_NONE) { + return ret; + } + + if (csr_ops[csrno].read128) { + return riscv_csrrw_do128(env, csrno, ret_value, + int128_zero(), int128_zero()); + } + + /* + * Fall back to 64-bit version for now, if the 128-bit alternative isn't + * at all defined. + * Note, some CSRs don't need to extend to MXLEN (64 upper bits non + * significant), for those, this fallback is correctly handling the + * accesses + */ + target_ulong old_value; + ret = riscv_csrrw_do64(env, csrno, &old_value, + (target_ulong)0, + (target_ulong)0); + if (ret == RISCV_EXCP_NONE && ret_value) { + *ret_value = int128_make64(old_value); + } + return ret; +} + RISCVException riscv_csrrw_i128(CPURISCVState *env, int csrno, Int128 *ret_value, Int128 new_value, Int128 write_mask) { RISCVException ret; - ret = riscv_csrrw_check(env, csrno, int128_nz(write_mask)); + ret = riscv_csrrw_check(env, csrno, true); if (ret != RISCV_EXCP_NONE) { return ret; } @@ -4830,7 +4873,11 @@ RISCVException riscv_csrrw_debug(CPURISCVState *env, int csrno, #if !defined(CONFIG_USER_ONLY) env->debugger = true; #endif - ret = riscv_csrrw(env, csrno, ret_value, new_value, write_mask); + if (!write_mask) { + ret = riscv_csrr(env, csrno, ret_value); + } else { + ret = riscv_csrrw(env, csrno, ret_value, new_value, write_mask); + } #if !defined(CONFIG_USER_ONLY) env->debugger = false; #endif diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c index ec1408ba0f..25a5263573 100644 --- a/target/riscv/op_helper.c +++ b/target/riscv/op_helper.c @@ -51,7 +51,7 @@ target_ulong helper_csrr(CPURISCVState *env, int csr) } target_ulong val = 0; - RISCVException ret = riscv_csrrw(env, csr, &val, 0, 0); + RISCVException ret = riscv_csrr(env, csr, &val); if (ret != RISCV_EXCP_NONE) { riscv_raise_exception(env, ret, GETPC()); @@ -84,9 +84,7 @@ target_ulong helper_csrrw(CPURISCVState *env, int csr, target_ulong helper_csrr_i128(CPURISCVState *env, int csr) { Int128 rv = int128_zero(); - RISCVException ret = riscv_csrrw_i128(env, csr, &rv, - int128_zero(), - int128_zero()); + RISCVException ret = riscv_csrr_i128(env, csr, &rv); if (ret != RISCV_EXCP_NONE) { riscv_raise_exception(env, ret, GETPC()); From 38facfa84328e4ee5a80f7082a01e10c768ee50a Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 15 Jul 2024 06:04:55 -0300 Subject: [PATCH 29/30] hw/riscv/virt.c: re-insert and deprecate 'riscv,delegate' Commit b1f1e9dcfa renamed 'riscv,delegate' to 'riscv,delegation' since it is the correct name as per dt-bindings, and the absence of the correct name will result in validation fails when dumping the dtb and using dt-validate. But this change has a side-effect: every other firmware available that is AIA capable is using 'riscv,delegate', and it will fault/misbehave if this property isn't present. The property was added back in QEMU 7.0, meaning we have 2 years of firmware development using the wrong property. Re-introducing 'riscv,delegate' while keeping 'riscv,delegation' allows older firmwares to keep booting with the 'virt' machine. 'riscv,delegate' is then marked for future deprecation with its use being discouraged from now on. Cc: Conor Dooley Cc: Anup Patel Fixes: b1f1e9dcfa ("hw/riscv/virt.c: aplic DT: rename prop to 'riscv, delegation'") Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-ID: <20240715090455.145888-1-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- docs/about/deprecated.rst | 11 +++++++++++ hw/riscv/virt.c | 9 +++++++++ 2 files changed, 20 insertions(+) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 20b7a17cf0..88f0f03786 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -479,6 +479,17 @@ versions, aliases will point to newer CPU model versions depending on the machine type, so management software must resolve CPU model aliases before starting a virtual machine. +RISC-V "virt" board "riscv,delegate" DT property (since 9.1) +'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +The "riscv,delegate" DT property was added in QEMU 7.0 as part of +the AIA APLIC support. The property changed name during the review +process in Linux and the correct name ended up being +"riscv,delegation". Changing the DT property name will break all +available firmwares that are using the current (wrong) name. The +property is kept as is in 9.1, together with "riscv,delegation", to +give more time for firmware developers to change their code. + Migration --------- diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index bc0893e087..9981e0f6c9 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -651,6 +651,15 @@ static void create_fdt_one_aplic(RISCVVirtState *s, int socket, qemu_fdt_setprop_cells(ms->fdt, aplic_name, "riscv,delegation", aplic_child_phandle, 0x1, VIRT_IRQCHIP_NUM_SOURCES); + /* + * DEPRECATED_9.1: Compat property kept temporarily + * to allow old firmwares to work with AIA. Do *not* + * use 'riscv,delegate' in new code: use + * 'riscv,delegation' instead. + */ + qemu_fdt_setprop_cells(ms->fdt, aplic_name, "riscv,delegate", + aplic_child_phandle, 0x1, + VIRT_IRQCHIP_NUM_SOURCES); } riscv_socket_fdt_write_id(ms, aplic_name, socket); From daff9f7f7a457f78ce455e6abf19c2a37dfe7630 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 15 Jul 2024 14:15:21 -0300 Subject: [PATCH 30/30] roms/opensbi: Update to v1.5 Update OpenSBI and the pre-built opensbi32 and opensbi64 images to v1.5. The following commits were included in v1.5: 455de67 include: Bump-up version to 1.5 23b7bad lib: sbi: check incoming dbtr shmem address 0e45b63 docs: Fix wrong filename caae2f7 lib: sbi: fwft: return SBI_EINVAL rather than SBI_ERR_INVALID_PARAM e8717d1 lib: sbi: fwft: check feature value to be exactly 1 or 0 ecef14d lib: sbi: implement SBI FWFT extension e9ee967 lib: sbi: fwft: add support for SBI_FWFT_PTE_AD_HW_UPDATING c97a1d5 lib: sbi: fwft: add support for SBI_FWFT_MISALIGNED_EXC_DELEG aa5a859 lib: sbi: add support for firmware features extension 53844c9 lib: sbi: Add support for Svade and Svadu extensions 52dcf35 platform: generic: andes: Add support for RV32 to set up PMA f09f164 platform: generic: andes: Refine Andes PMA related code 7830e98 lib: serial: fix RX path in litex-uart 62e178a lib: utils/reset: Try initializing all reset devices in dt 3a94a32 sbi: sbi_domain_context: Fix trap context for domain context switching a73ff04 lib: utils/reset: Fix fdt_reset to search for more dt nodes b5c984b lib: utils/reset: Skip initialize reset when dt is not enabled 86bbe6c lib: utils/serial: Fix fdt_serial to match more dt nodes 179e00a lib: utils/serial: Skip initialize serial when dt is not enabled b1c7c75 lib: utils/irqchip: Skip initialize irqchip when dt is not enabled 5e3ad7d lib: utils/timer: Skip initialize timer when dt is not enabled c5be0e1 lib: utils/ipi: Skip initialize ipi when dt is not enabled df3db6a lib: utils/fdt: Fix DT property for APLIC delegation d962db2 lib: utils/gpio: respect flag GPIO_FLAG_ACTIVE_LOW ae5ef18 lib: sbi: sse: handle missing writable attributes 858754a lib: utils/irqchip: Add sanity checks in imsic_get_data() and imsic_get_target_file() 96f0a2e firmware: Bring back FW_TEXT_START as an optional parameter e3a30a2 lib: utils/irqchip: Check before initializing imsic 2bed4c1 platform: generic: thead: add Sophgo CV18XX/SG200X series 533067d lib: sbi: Put event after use in sbi_sse_exit() loop ea9cf6a utils/reset: Add SG2042 hwmon MCU support. 1cb792d lib: sbi: simplify inline function in sbi_dtbr.c 7b37da3 lib: sbi: fix return type of sbi_dbtr_shmem_disabled e065c3c lib: sbi: Fixed memory permission check in sbi_dbtr_setup_shmem 7f54527 lib: sbi: fix DBTR_SHMEM_MAKE_PHYS for RV64 744f495 lib: sbi: Removal unnecessary check dbtr_thishart_state_ptr 4953bd7 lib: sbi: fix hart_shmem_base 019a8e6 platform: generic: thead: add Canaan Kendryte K230 33e21c9 platform: generic: thead: separate T-Head PMU Errata 2b93ce0 platform: andes: Change all occurrences of andes45 to andes f68b3ae platform: andes: Rename files with the prefix andes45 17e8291 sbi: sbi_domain_context: Add spinlock for updating domain assigned_harts 1d89a9d lib: sbi: Refine the settings for switching to Virtual Supervisor Mode. 033104d lib: sbi: sse: check handler entry to belong to supervisor mode bd00765 lib: sbi: sse: use PRV_S instead of hardcoded value for mode ce3c82c lib: sbi: sse: call enable callback before sending IPI d528dbf lib: sbi: sse: remove superfluous sbi_list_empty() check 22ff750 lib: sbi: sse: simplify 32bits overflow check 7aa80ea lib: sbi: sse: rename sse_hart_unlock() to sse_enabled_event_unlock() c21c99d lib: sbi: sse: fix typos, comments and spacing errors 7b1ed96 lib: tests: Add test for spinlocks 7bdf41a lib: tests: Add test for atomic_t f6243d9 lib: tests: Add test suite init function d4d2582 firmware: remove FW_TEXT_START 73344d4 lib: utils: check correct value in fdt_node_offset_by_compatible 37e1544 lib: sbi: sse_event_get() may return NULL 68bc031 lib: sbi: Add missing sscrind and sscfg extensions in sbi_hart_ext[] a7c5c2c Makefile: Remove unnecessary dependencies 268feab Makefile: Respect manual changes to .config 29ecda9 sbi: sbi_domain_context: Check privilege spec version before accessing S-mode CSRs 7862c24 lib: sbi: Wakeup non-coldboot HARTs early in the coldboot path beb0cd1 lib: sbi: Simplify wait_for_coldboot() implementation f5375bc platform: generic: allwinner: Optimize current hart scratch access b94396c lib: utils/timer: Optimize current hart scratch access 5c9a735 include: sbi: Support byteorder macros in assembly 06fc453 lib: sbi: Add SSE support for PMU events 09ad214 lib: sbi: Implement SBI SSE extension c8cdf01 lib: sbi: Add support for Supervisor Software Events extension 76d7e9b firmware: remove copy-base relocation 5186da6 platform: generic: allwinner: sun20i-d1: Remove duplicated CSR definitions 3b2f89e docs: writing_tests: Make docs correspond the latest changes f7d0050 lib: sbi: Extend sbi_trap_error() to dump state in a nested trap 5b11f16 lib: sbi: Pass trap context pointer to sbi_ecall_handler() 43d346c lib: sbi: Remove regs parameter from trap irq handling functions d84e7eb lib: sbi: Remove regs paramter of sbi_irqchip_process() f414cf9 lib: sbi: Simplify parameters of sbi_illegal_insn_handler() fea33a9 lib: sbi: Simplify parameters of misaligned and access fault handlers abea949 lib: sbi: Introduce trap context 60ffc15 include: sbi: Add trap_context pointer in struct sbi_scratch ebb697a lib: sbi: Remove sbi_trap_exit() and related code 2e85178 lib: sbi: Remove epc from struct sbi_trap_info 86224ec docs/writing_tests: Update tests paths 5c992a1 lib: tests: Move tests to a separate directory 81e3ba7 lib: sbi: call platform load/store emulators ddf3b64 include: sbi: add emulate_load/store handler to platform ops 4c11265 lib: sbi: abstract out insn decoding to unify mem fault handlers 9221fe5 lib: sbi: change prototype of sbi_misaligned_load/store_handler a17600c lib: sbi: change prototype of sbi_trap_redirect 2471cf2 include: sbi: rename sbi_misaligned_ldst.h to sbi_trap_ldst.h c0a6320 lib: sbi: rename sbi_misaligned_ldst.c to sbi_trap_ldst.c e11025c lib: sbi: Add initial domain context management support 87d8fe7 lib: tests: Add sbi_console test e5f53fd lib: tests: Add a test for sbi_bitmap 874fcef lib: Add SBIUnit testing macros and functions b9e4de0 docs: Add documentation about tests and SBIUnit 526b9ce firmware: fw_base.S: fix _reset_regs 8151105 firmware: fw_base.S: Remove _relocate_lottery 187397f firmware: fw_dynamic.S: Remove _bad_dynamic_info b27b7c6 firmware: fw_base: Simplified setup trap handler fdf5589 firmware: fw_base.S: Simplify address get 748bef1 lib: sbi_misaligned_ldst: Add handling of C.LHU/C.LH and C.SH bc36678 platform: andes: Drop andes_pmu_setup() 6bb6b61 lib: sbi: Add support for smcsrind and smcdeleg 322b598 lib: sbi_hsm: Restor hart state to stop when fails to start 96a35db docs/firmware: document new options for jump and payload firmwares 2cff7f3 platform: Apply relocatable address f056939 firmware: Add relocatable FW_PAYLOAD_FDT_ADDR 7227cdd firmware: Add relocatable FW_JUMP_ADDR and FW_JUMP_FDT_ADDR 741e941 platform: starfive: call starfive_jh7110_inst_init() in pm_reset_init() 3edf044 platform: starfive: return error if needed devices are not present 80ae046 platform: starfive: rename "stf,axp15060-regulator" -> "x-powers,axp15060" 5335340 platform: starfive: remove redundant compatibility check in pmic_ops 4d8569d platform: starfive: get I2C offset address from clocks property 034af1f platform: starfive: correct system clock device tree node 88273fe lib: sbi_pmu: Before using we should ensure PMU init done 46c8c65 docs: move documentation of system suspend test. 8df836d platform: generic: Parse system suspend test from config node. 23e7e48 docs: Add OpenSBI DT configuration guide. 67ce5a7 platform: generic: Add support for specify coldboot harts in DT 9c8b18e firmware: fw_base.S: remove _runtime_offset 4c6b7cb firmware: fw_base.S: Improve loading u32 92e8aff firmware: always create dynsym section d1dad07 Makefile: check for --exclude-libs 4a76f79 Makefile: don't pass -mstrict-align if not supported 21caaa3 fw_base.S: Fix comment errors 1ec353d lib: sbi: Use mask to check the free bit during trigger allocation bb90a9e lib: sbi: Print number of debug triggers found 76a2a15 lib: sbi: Implement SBI debug trigger extension fa87ec9 include: sbi: Add SBI debug trigger extension related defines 97f234f lib: sbi: Introduce the SBI debug triggers extension support 40dac6b lib: sbi: Detect support of debug triggers 2499769 include: sbi: Introduce debug trigger register encodings 20ca19a include: sbi: Add TINFO debug trigger CSR b752099 include: sbi: Introduce common endianess conversion macro Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-ID: <20240715171521.179517-1-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- .../opensbi-riscv32-generic-fw_dynamic.bin | Bin 267416 -> 268312 bytes .../opensbi-riscv64-generic-fw_dynamic.bin | Bin 270808 -> 272504 bytes roms/opensbi | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/pc-bios/opensbi-riscv32-generic-fw_dynamic.bin b/pc-bios/opensbi-riscv32-generic-fw_dynamic.bin index 60ca1165c820ff29b984566db22b9453541da19a..7ec260ff4047d11f7683c9a0b2fed73e1996cd75 100644 GIT binary patch delta 73365 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 cNZ`s=_WyZ?+FC>E`?t>1v*f#E3N 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%0D_%z3c zDT1Mx80Ak`1)=B$jMxTvR0BM=0UqA~$2GuH z8sO;-@T>+np#j#mD&&=8STv zr5vAw5Ysac{2+6S<9@);I2Mo+H5|KLMiUD?laGcBOEHFT~azRPiQcZH#n;|;)%InD-d4mp-uW3J;P z$8k9@^MjcOyP^Jf;+pAT1ao`|$s5P<#tL*S>n+?A4A~qnfcaXE-C)iF$Q;dsx{c#u zH}I9?xB%*|2IfpoZ2z_QQA#-@7`T|@%TOCGQn{$ zFyk?g1>naV2Q)#|<+wSp(1^GHp?1_)2r>&=s9qeWK&Uy#m90=;IgW!o^MuKVLJi@# znHQ=q$K{^Hz<5k10rEpRP6LkRcqv0SqQcs$1^VL6TCYc0?ka=ZcRT8=M6WqRhp z4ycyvHc$k5Xu?MLKw%-1CVDNXTm}($2)-I zIA-dU26!9Cy(b{qIc@^Hi{n6GHiTmVy$kiUo@-WtQOfZ`V8&!ZMUT;O;8-h1oyORX zndd=9%klL%#Ej#`P=h&se2^p`(y!{ud(39Z|4X_`_ ze!!zR-T}*FIWEy5&>R;*ozC$!$gmMF^I#j)c^qGac{0Z-u*-N%Cantn|6N?O0iJ!% z@h)KIFcUfre2HVXCTMUtemNf5#BodD8ji)0GUS+DHd1!t`1%aQo@3!D+6IQv{}4*w zL!sl0g$q&WICcR};8=ye-aL-S0Wah@5O@>EJC-139J>IY=D0cVIgSH>pK-iGUb$E>CD6?BW zvq5Yq$DQ;L!fc$FT+wiJD97wm8OUV`8Z)eZE*;g|!(sT%61 Tghee#k$@t_kb%~CD}4SBw_k;G diff --git a/pc-bios/opensbi-riscv64-generic-fw_dynamic.bin b/pc-bios/opensbi-riscv64-generic-fw_dynamic.bin index bae158d4577341eb3d752ca13cc66149961f8cb4..090c0cf6ac988f811b220c45565eca027fc21d50 100644 GIT binary patch delta 73168 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�^k$*7J*69Maa)8vps9{DXmTwh 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 delta 59449 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