From 4eff52cd463e5d130a73bd16d81787c36acc0ec7 Mon Sep 17 00:00:00 2001 From: Max Chou Date: Thu, 30 Nov 2023 01:03:57 +0800 Subject: [PATCH 01/65] target/riscv: Add vill check for whole vector register move instructions The ratified version of RISC-V V spec section 16.6 says that `The instructions operate as if EEW=SEW`. So the whole vector register move instructions depend on the vtype register that means the whole vector register move instructions should raise an illegal-instruction exception when vtype.vill=1. Signed-off-by: Max Chou Reviewed-by: Daniel Henrique Barboza Message-ID: <20231129170400.21251-2-max.chou@sifive.com> Signed-off-by: Alistair Francis --- target/riscv/insn_trans/trans_rvv.c.inc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index 78bd363310..114ad87397 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -3631,13 +3631,14 @@ static bool trans_vcompress_vm(DisasContext *s, arg_r *a) } /* - * Whole Vector Register Move Instructions ignore vtype and vl setting. - * Thus, we don't need to check vill bit. (Section 16.6) + * Whole Vector Register Move Instructions depend on vtype register(vsew). + * Thus, we need to check vill bit. (Section 16.6) */ #define GEN_VMV_WHOLE_TRANS(NAME, LEN) \ static bool trans_##NAME(DisasContext *s, arg_##NAME * a) \ { \ if (require_rvv(s) && \ + vext_check_isa_ill(s) && \ QEMU_IS_ALIGNED(a->rd, LEN) && \ QEMU_IS_ALIGNED(a->rs2, LEN)) { \ uint32_t maxsz = (s->cfg_ptr->vlen >> 3) * LEN; \ From 79fc6d38a819cd30e578023a231385f63583eafb Mon Sep 17 00:00:00 2001 From: Max Chou Date: Thu, 30 Nov 2023 01:03:58 +0800 Subject: [PATCH 02/65] target/riscv: The whole vector register move instructions depend on vsew The RISC-V v spec 16.6 section says that the whole vector register move instructions operate as if EEW=SEW. So it should depends on the vsew field of vtype register. Signed-off-by: Max Chou Acked-by: Richard Henderson Message-ID: <20231129170400.21251-3-max.chou@sifive.com> Signed-off-by: Alistair Francis --- target/riscv/insn_trans/trans_rvv.c.inc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index 114ad87397..3871f0ea73 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -3643,8 +3643,7 @@ static bool trans_##NAME(DisasContext *s, arg_##NAME * a) \ QEMU_IS_ALIGNED(a->rs2, LEN)) { \ uint32_t maxsz = (s->cfg_ptr->vlen >> 3) * LEN; \ if (s->vstart_eq_zero) { \ - /* EEW = 8 */ \ - tcg_gen_gvec_mov(MO_8, vreg_ofs(s, a->rd), \ + tcg_gen_gvec_mov(s->sew, vreg_ofs(s, a->rd), \ vreg_ofs(s, a->rs2), maxsz, maxsz); \ mark_vs_dirty(s); \ } else { \ From 564a28bda1b06eb54dc555c0e34403c6f5657a00 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Fri, 8 Dec 2023 17:43:15 +0800 Subject: [PATCH 03/65] target/riscv: Fix th.dcache.cval1 priviledge check According to the specification, the th.dcache.cvall1 can be executed under all priviledges. The specification about xtheadcmo located in, https://github.com/T-head-Semi/thead-extension-spec/blob/master/xtheadcmo/dcache_cval1.adoc Signed-off-by: LIU Zhiwei Reviewed-by: Alistair Francis Reviewed-by: Christoph Muellner Message-ID: <20231208094315.177-1-zhiwei_liu@linux.alibaba.com> Signed-off-by: Alistair Francis --- target/riscv/insn_trans/trans_xthead.c.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/riscv/insn_trans/trans_xthead.c.inc b/target/riscv/insn_trans/trans_xthead.c.inc index 810d76665a..dbb6411239 100644 --- a/target/riscv/insn_trans/trans_xthead.c.inc +++ b/target/riscv/insn_trans/trans_xthead.c.inc @@ -296,7 +296,7 @@ NOP_PRIVCHECK(th_dcache_csw, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS) NOP_PRIVCHECK(th_dcache_cisw, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS) NOP_PRIVCHECK(th_dcache_isw, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS) NOP_PRIVCHECK(th_dcache_cpal1, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS) -NOP_PRIVCHECK(th_dcache_cval1, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS) +NOP_PRIVCHECK(th_dcache_cval1, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MSU) NOP_PRIVCHECK(th_icache_iall, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS) NOP_PRIVCHECK(th_icache_ialls, REQUIRE_XTHEADCMO, REQUIRE_PRIV_MS) From 7767f8b122dc061f9a68802b41b82117e755b03a Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Fri, 15 Dec 2023 10:33:13 +0800 Subject: [PATCH 04/65] target/riscv: Not allow write mstatus_vs without RVV If CPU does not implement the Vector extension, it usually means mstatus vs hardwire to zero. So we should not allow write a non-zero value to this field. Signed-off-by: LIU Zhiwei Reviewed-by: Alistair Francis Message-ID: <20231215023313.1708-1-zhiwei_liu@linux.alibaba.com> Signed-off-by: Alistair Francis --- target/riscv/csr.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index c50a33397c..d8f751a0ae 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -1328,11 +1328,14 @@ static RISCVException write_mstatus(CPURISCVState *env, int csrno, mask = MSTATUS_SIE | MSTATUS_SPIE | MSTATUS_MIE | MSTATUS_MPIE | MSTATUS_SPP | MSTATUS_MPRV | MSTATUS_SUM | MSTATUS_MPP | MSTATUS_MXR | MSTATUS_TVM | MSTATUS_TSR | - MSTATUS_TW | MSTATUS_VS; + MSTATUS_TW; if (riscv_has_ext(env, RVF)) { mask |= MSTATUS_FS; } + if (riscv_has_ext(env, RVV)) { + mask |= MSTATUS_VS; + } if (xl != MXL_RV32 || env->debugger) { if (riscv_has_ext(env, RVH)) { From 6f5bb7d40591386059077060508226b737080d95 Mon Sep 17 00:00:00 2001 From: Ivan Klokov Date: Thu, 23 Nov 2023 12:12:14 +0300 Subject: [PATCH 05/65] target/riscv/pmp: Use hwaddr instead of target_ulong for RV32 The Sv32 page-based virtual-memory scheme described in RISCV privileged spec Section 5.3 supports 34-bit physical addresses for RV32, so the PMP scheme must support addresses wider than XLEN for RV32. However, PMP address register format is still 32 bit wide. Signed-off-by: Ivan Klokov Reviewed-by: Alistair Francis Message-ID: <20231123091214.20312-1-ivan.klokov@syntacore.com> Signed-off-by: Alistair Francis --- target/riscv/pmp.c | 26 ++++++++++++-------------- target/riscv/pmp.h | 8 ++++---- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c index 162e88a90a..dff9512c3f 100644 --- a/target/riscv/pmp.c +++ b/target/riscv/pmp.c @@ -150,8 +150,7 @@ void pmp_unlock_entries(CPURISCVState *env) } } -static void pmp_decode_napot(target_ulong a, target_ulong *sa, - target_ulong *ea) +static void pmp_decode_napot(hwaddr a, hwaddr *sa, hwaddr *ea) { /* * aaaa...aaa0 8-byte NAPOT range @@ -173,8 +172,8 @@ void pmp_update_rule_addr(CPURISCVState *env, uint32_t pmp_index) uint8_t this_cfg = env->pmp_state.pmp[pmp_index].cfg_reg; target_ulong this_addr = env->pmp_state.pmp[pmp_index].addr_reg; target_ulong prev_addr = 0u; - target_ulong sa = 0u; - target_ulong ea = 0u; + hwaddr sa = 0u; + hwaddr ea = 0u; if (pmp_index >= 1u) { prev_addr = env->pmp_state.pmp[pmp_index - 1].addr_reg; @@ -227,8 +226,7 @@ void pmp_update_rule_nums(CPURISCVState *env) } } -static int pmp_is_in_range(CPURISCVState *env, int pmp_index, - target_ulong addr) +static int pmp_is_in_range(CPURISCVState *env, int pmp_index, hwaddr addr) { int result = 0; @@ -305,14 +303,14 @@ static bool pmp_hart_has_privs_default(CPURISCVState *env, pmp_priv_t privs, * Return true if a pmp rule match or default match * Return false if no match */ -bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr, +bool pmp_hart_has_privs(CPURISCVState *env, hwaddr addr, target_ulong size, pmp_priv_t privs, pmp_priv_t *allowed_privs, target_ulong mode) { int i = 0; int pmp_size = 0; - target_ulong s = 0; - target_ulong e = 0; + hwaddr s = 0; + hwaddr e = 0; /* Short cut if no rules */ if (0 == pmp_get_num_rules(env)) { @@ -624,12 +622,12 @@ target_ulong mseccfg_csr_read(CPURISCVState *env) * To avoid this we return a size of 1 (which means no caching) if the PMP * region only covers partial of the TLB page. */ -target_ulong pmp_get_tlb_size(CPURISCVState *env, target_ulong addr) +target_ulong pmp_get_tlb_size(CPURISCVState *env, hwaddr addr) { - target_ulong pmp_sa; - target_ulong pmp_ea; - target_ulong tlb_sa = addr & ~(TARGET_PAGE_SIZE - 1); - target_ulong tlb_ea = tlb_sa + TARGET_PAGE_SIZE - 1; + hwaddr pmp_sa; + hwaddr pmp_ea; + hwaddr tlb_sa = addr & ~(TARGET_PAGE_SIZE - 1); + hwaddr tlb_ea = tlb_sa + TARGET_PAGE_SIZE - 1; int i; /* diff --git a/target/riscv/pmp.h b/target/riscv/pmp.h index 9af8614cd4..f5c10ce85c 100644 --- a/target/riscv/pmp.h +++ b/target/riscv/pmp.h @@ -53,8 +53,8 @@ typedef struct { } pmp_entry_t; typedef struct { - target_ulong sa; - target_ulong ea; + hwaddr sa; + hwaddr ea; } pmp_addr_t; typedef struct { @@ -73,11 +73,11 @@ target_ulong mseccfg_csr_read(CPURISCVState *env); void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index, target_ulong val); target_ulong pmpaddr_csr_read(CPURISCVState *env, uint32_t addr_index); -bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr, +bool pmp_hart_has_privs(CPURISCVState *env, hwaddr addr, target_ulong size, pmp_priv_t privs, pmp_priv_t *allowed_privs, target_ulong mode); -target_ulong pmp_get_tlb_size(CPURISCVState *env, target_ulong addr); +target_ulong pmp_get_tlb_size(CPURISCVState *env, hwaddr addr); void pmp_update_rule_addr(CPURISCVState *env, uint32_t pmp_index); void pmp_update_rule_nums(CPURISCVState *env); uint32_t pmp_get_num_rules(CPURISCVState *env); From 8d326cb88b03b593708262947e9ec30411fb99ab Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 11 Dec 2023 14:07:32 -0300 Subject: [PATCH 06/65] target/riscv/cpu.c: fix machine IDs getters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mvendorid is an uint32 property, mimpid/marchid are uint64 properties. But their getters are returning bools. The reason this went under the radar for this long is because we have no code using the getters. The problem can be seem via the 'qom-get' API though. Launching QEMU with the 'veyron-v1' CPU, a model with: VEYRON_V1_MVENDORID: 0x61f (1567) VEYRON_V1_MIMPID: 0x111 (273) VEYRON_V1_MARCHID: 0x8000000000010000 (9223372036854841344) This is what the API returns when retrieving these properties: (qemu) qom-get /machine/soc0/harts[0] mvendorid true (qemu) qom-get /machine/soc0/harts[0] mimpid true (qemu) qom-get /machine/soc0/harts[0] marchid true After this patch: (qemu) qom-get /machine/soc0/harts[0] mvendorid 1567 (qemu) qom-get /machine/soc0/harts[0] mimpid 273 (qemu) qom-get /machine/soc0/harts[0] marchid 9223372036854841344 Fixes: 1e34150045 ("target/riscv/cpu.c: restrict 'mvendorid' value") Fixes: a1863ad368 ("target/riscv/cpu.c: restrict 'mimpid' value") Fixes: d6a427e2c0 ("target/riscv/cpu.c: restrict 'marchid' value") Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20231211170732.2541368-1-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index b07a76ef6b..53b82cc581 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1570,9 +1570,9 @@ static void cpu_set_mvendorid(Object *obj, Visitor *v, const char *name, static void cpu_get_mvendorid(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - bool value = RISCV_CPU(obj)->cfg.mvendorid; + uint32_t value = RISCV_CPU(obj)->cfg.mvendorid; - visit_type_bool(v, name, &value, errp); + visit_type_uint32(v, name, &value, errp); } static void cpu_set_mimpid(Object *obj, Visitor *v, const char *name, @@ -1599,9 +1599,9 @@ static void cpu_set_mimpid(Object *obj, Visitor *v, const char *name, static void cpu_get_mimpid(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - bool value = RISCV_CPU(obj)->cfg.mimpid; + uint64_t value = RISCV_CPU(obj)->cfg.mimpid; - visit_type_bool(v, name, &value, errp); + visit_type_uint64(v, name, &value, errp); } static void cpu_set_marchid(Object *obj, Visitor *v, const char *name, @@ -1649,9 +1649,9 @@ static void cpu_set_marchid(Object *obj, Visitor *v, const char *name, static void cpu_get_marchid(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - bool value = RISCV_CPU(obj)->cfg.marchid; + uint64_t value = RISCV_CPU(obj)->cfg.marchid; - visit_type_bool(v, name, &value, errp); + visit_type_uint64(v, name, &value, errp); } static void riscv_cpu_class_init(ObjectClass *c, void *data) From 49c211ffca00fdf7c0c29072c224e88527a14838 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Fri, 8 Dec 2023 15:38:31 -0300 Subject: [PATCH 07/65] target/riscv/kvm: change KVM_REG_RISCV_FP_F to u32 KVM_REG_RISCV_FP_F regs have u32 size according to the API, but by using kvm_riscv_reg_id() in RISCV_FP_F_REG() we're returning u64 sizes when running with TARGET_RISCV64. The most likely reason why no one noticed this is because we're not implementing kvm_cpu_synchronize_state() in RISC-V yet. Create a new helper that returns a KVM ID with u32 size and use it in RISCV_FP_F_REG(). Reported-by: Andrew Jones Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Message-ID: <20231208183835.2411523-2-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/kvm/kvm-cpu.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index 117e33cf90..375c8e7f33 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -72,6 +72,11 @@ static uint64_t kvm_riscv_reg_id(CPURISCVState *env, uint64_t type, return id; } +static uint64_t kvm_riscv_reg_id_u32(uint64_t type, uint64_t idx) +{ + return KVM_REG_RISCV | KVM_REG_SIZE_U32 | type | idx; +} + #define RISCV_CORE_REG(env, name) kvm_riscv_reg_id(env, KVM_REG_RISCV_CORE, \ KVM_REG_RISCV_CORE_REG(name)) @@ -81,7 +86,7 @@ static uint64_t kvm_riscv_reg_id(CPURISCVState *env, uint64_t type, #define RISCV_TIMER_REG(env, name) kvm_riscv_reg_id(env, KVM_REG_RISCV_TIMER, \ KVM_REG_RISCV_TIMER_REG(name)) -#define RISCV_FP_F_REG(env, idx) kvm_riscv_reg_id(env, KVM_REG_RISCV_FP_F, idx) +#define RISCV_FP_F_REG(idx) kvm_riscv_reg_id_u32(KVM_REG_RISCV_FP_F, idx) #define RISCV_FP_D_REG(env, idx) kvm_riscv_reg_id(env, KVM_REG_RISCV_FP_D, idx) @@ -586,7 +591,7 @@ static int kvm_riscv_get_regs_fp(CPUState *cs) if (riscv_has_ext(env, RVF)) { uint32_t reg; for (i = 0; i < 32; i++) { - ret = kvm_get_one_reg(cs, RISCV_FP_F_REG(env, i), ®); + ret = kvm_get_one_reg(cs, RISCV_FP_F_REG(i), ®); if (ret) { return ret; } @@ -620,7 +625,7 @@ static int kvm_riscv_put_regs_fp(CPUState *cs) uint32_t reg; for (i = 0; i < 32; i++) { reg = env->fpr[i]; - ret = kvm_set_one_reg(cs, RISCV_FP_F_REG(env, i), ®); + ret = kvm_set_one_reg(cs, RISCV_FP_F_REG(i), ®); if (ret) { return ret; } From 450bd6618fda3d2e2ab02b2fce1c79efd5b66084 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Fri, 8 Dec 2023 15:38:32 -0300 Subject: [PATCH 08/65] target/riscv/kvm: change KVM_REG_RISCV_FP_D to u64 KVM_REG_RISCV_FP_D regs are always u64 size. Using kvm_riscv_reg_id() in RISCV_FP_D_REG() ends up encoding the wrong size if we're running with TARGET_RISCV32. Create a new helper that returns a KVM ID with u64 size and use it with RISCV_FP_D_REG(). Reported-by: Andrew Jones Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Message-ID: <20231208183835.2411523-3-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/kvm/kvm-cpu.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index 375c8e7f33..9370c72f9b 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -77,6 +77,11 @@ static uint64_t kvm_riscv_reg_id_u32(uint64_t type, uint64_t idx) return KVM_REG_RISCV | KVM_REG_SIZE_U32 | type | idx; } +static uint64_t kvm_riscv_reg_id_u64(uint64_t type, uint64_t idx) +{ + return KVM_REG_RISCV | KVM_REG_SIZE_U64 | type | idx; +} + #define RISCV_CORE_REG(env, name) kvm_riscv_reg_id(env, KVM_REG_RISCV_CORE, \ KVM_REG_RISCV_CORE_REG(name)) @@ -88,7 +93,7 @@ static uint64_t kvm_riscv_reg_id_u32(uint64_t type, uint64_t idx) #define RISCV_FP_F_REG(idx) kvm_riscv_reg_id_u32(KVM_REG_RISCV_FP_F, idx) -#define RISCV_FP_D_REG(env, idx) kvm_riscv_reg_id(env, KVM_REG_RISCV_FP_D, idx) +#define RISCV_FP_D_REG(idx) kvm_riscv_reg_id_u64(KVM_REG_RISCV_FP_D, idx) #define KVM_RISCV_GET_CSR(cs, env, csr, reg) \ do { \ @@ -579,7 +584,7 @@ static int kvm_riscv_get_regs_fp(CPUState *cs) if (riscv_has_ext(env, RVD)) { uint64_t reg; for (i = 0; i < 32; i++) { - ret = kvm_get_one_reg(cs, RISCV_FP_D_REG(env, i), ®); + ret = kvm_get_one_reg(cs, RISCV_FP_D_REG(i), ®); if (ret) { return ret; } @@ -613,7 +618,7 @@ static int kvm_riscv_put_regs_fp(CPUState *cs) uint64_t reg; for (i = 0; i < 32; i++) { reg = env->fpr[i]; - ret = kvm_set_one_reg(cs, RISCV_FP_D_REG(env, i), ®); + ret = kvm_set_one_reg(cs, RISCV_FP_D_REG(i), ®); if (ret) { return ret; } From 10f86d1b845087d14b58d65dd2a6e3411d1b6529 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Fri, 8 Dec 2023 15:38:33 -0300 Subject: [PATCH 09/65] target/riscv/kvm: change timer regs size to u64 KVM_REG_RISCV_TIMER regs are always u64 according to the KVM API, but at this moment we'll return u32 regs if we're running a RISCV32 target. Use the kvm_riscv_reg_id_u64() helper in RISCV_TIMER_REG() to fix it. Reported-by: Andrew Jones Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Message-ID: <20231208183835.2411523-4-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/kvm/kvm-cpu.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index 9370c72f9b..b7871b2f8f 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -88,7 +88,7 @@ static uint64_t kvm_riscv_reg_id_u64(uint64_t type, uint64_t idx) #define RISCV_CSR_REG(env, name) kvm_riscv_reg_id(env, KVM_REG_RISCV_CSR, \ KVM_REG_RISCV_CSR_REG(name)) -#define RISCV_TIMER_REG(env, name) kvm_riscv_reg_id(env, KVM_REG_RISCV_TIMER, \ +#define RISCV_TIMER_REG(name) kvm_riscv_reg_id_u64(KVM_REG_RISCV_TIMER, \ KVM_REG_RISCV_TIMER_REG(name)) #define RISCV_FP_F_REG(idx) kvm_riscv_reg_id_u32(KVM_REG_RISCV_FP_F, idx) @@ -111,17 +111,17 @@ static uint64_t kvm_riscv_reg_id_u64(uint64_t type, uint64_t idx) } \ } while (0) -#define KVM_RISCV_GET_TIMER(cs, env, name, reg) \ +#define KVM_RISCV_GET_TIMER(cs, name, reg) \ do { \ - int ret = kvm_get_one_reg(cs, RISCV_TIMER_REG(env, name), ®); \ + int ret = kvm_get_one_reg(cs, RISCV_TIMER_REG(name), ®); \ if (ret) { \ abort(); \ } \ } while (0) -#define KVM_RISCV_SET_TIMER(cs, env, name, reg) \ +#define KVM_RISCV_SET_TIMER(cs, name, reg) \ do { \ - int ret = kvm_set_one_reg(cs, RISCV_TIMER_REG(env, name), ®); \ + int ret = kvm_set_one_reg(cs, RISCV_TIMER_REG(name), ®); \ if (ret) { \ abort(); \ } \ @@ -649,10 +649,10 @@ static void kvm_riscv_get_regs_timer(CPUState *cs) return; } - KVM_RISCV_GET_TIMER(cs, env, time, env->kvm_timer_time); - KVM_RISCV_GET_TIMER(cs, env, compare, env->kvm_timer_compare); - KVM_RISCV_GET_TIMER(cs, env, state, env->kvm_timer_state); - KVM_RISCV_GET_TIMER(cs, env, frequency, env->kvm_timer_frequency); + KVM_RISCV_GET_TIMER(cs, time, env->kvm_timer_time); + KVM_RISCV_GET_TIMER(cs, compare, env->kvm_timer_compare); + KVM_RISCV_GET_TIMER(cs, state, env->kvm_timer_state); + KVM_RISCV_GET_TIMER(cs, frequency, env->kvm_timer_frequency); env->kvm_timer_dirty = true; } @@ -666,8 +666,8 @@ static void kvm_riscv_put_regs_timer(CPUState *cs) return; } - KVM_RISCV_SET_TIMER(cs, env, time, env->kvm_timer_time); - KVM_RISCV_SET_TIMER(cs, env, compare, env->kvm_timer_compare); + KVM_RISCV_SET_TIMER(cs, time, env->kvm_timer_time); + KVM_RISCV_SET_TIMER(cs, compare, env->kvm_timer_compare); /* * To set register of RISCV_TIMER_REG(state) will occur a error from KVM @@ -676,7 +676,7 @@ static void kvm_riscv_put_regs_timer(CPUState *cs) * TODO If KVM changes, adapt here. */ if (env->kvm_timer_state) { - KVM_RISCV_SET_TIMER(cs, env, state, env->kvm_timer_state); + KVM_RISCV_SET_TIMER(cs, state, env->kvm_timer_state); } /* @@ -685,7 +685,7 @@ static void kvm_riscv_put_regs_timer(CPUState *cs) * during the migration. */ if (migration_is_running(migrate_get_current()->state)) { - KVM_RISCV_GET_TIMER(cs, env, frequency, reg); + KVM_RISCV_GET_TIMER(cs, frequency, reg); if (reg != env->kvm_timer_frequency) { error_report("Dst Hosts timer frequency != Src Hosts"); } From f25974f46af7f936d08ed0bae5b80b1c90b78b25 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Fri, 8 Dec 2023 15:38:34 -0300 Subject: [PATCH 10/65] target/riscv/kvm: add RISCV_CONFIG_REG() Create a RISCV_CONFIG_REG() macro, similar to what other regs use, to hide away some of the boilerplate. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Message-ID: <20231208183835.2411523-5-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/kvm/kvm-cpu.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index b7871b2f8f..15573402be 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -88,6 +88,10 @@ static uint64_t kvm_riscv_reg_id_u64(uint64_t type, uint64_t idx) #define RISCV_CSR_REG(env, name) kvm_riscv_reg_id(env, KVM_REG_RISCV_CSR, \ KVM_REG_RISCV_CSR_REG(name)) +#define RISCV_CONFIG_REG(env, name) \ + kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG, \ + KVM_REG_RISCV_CONFIG_REG(name)) + #define RISCV_TIMER_REG(name) kvm_riscv_reg_id_u64(KVM_REG_RISCV_TIMER, \ KVM_REG_RISCV_TIMER_REG(name)) @@ -756,24 +760,21 @@ static void kvm_riscv_init_machine_ids(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) struct kvm_one_reg reg; int ret; - reg.id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG, - KVM_REG_RISCV_CONFIG_REG(mvendorid)); + reg.id = RISCV_CONFIG_REG(env, mvendorid); reg.addr = (uint64_t)&cpu->cfg.mvendorid; ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); if (ret != 0) { error_report("Unable to retrieve mvendorid from host, error %d", ret); } - reg.id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG, - KVM_REG_RISCV_CONFIG_REG(marchid)); + reg.id = RISCV_CONFIG_REG(env, marchid); reg.addr = (uint64_t)&cpu->cfg.marchid; ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); if (ret != 0) { error_report("Unable to retrieve marchid from host, error %d", ret); } - reg.id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG, - KVM_REG_RISCV_CONFIG_REG(mimpid)); + reg.id = RISCV_CONFIG_REG(env, mimpid); reg.addr = (uint64_t)&cpu->cfg.mimpid; ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); if (ret != 0) { @@ -788,8 +789,7 @@ static void kvm_riscv_init_misa_ext_mask(RISCVCPU *cpu, struct kvm_one_reg reg; int ret; - reg.id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG, - KVM_REG_RISCV_CONFIG_REG(isa)); + reg.id = RISCV_CONFIG_REG(env, isa); reg.addr = (uint64_t)&env->misa_ext_mask; ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); @@ -1092,8 +1092,7 @@ static int kvm_vcpu_set_machine_ids(RISCVCPU *cpu, CPUState *cs) uint64_t id; int ret; - id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG, - KVM_REG_RISCV_CONFIG_REG(mvendorid)); + id = RISCV_CONFIG_REG(env, mvendorid); /* * cfg.mvendorid is an uint32 but a target_ulong will * be written. Assign it to a target_ulong var to avoid @@ -1105,15 +1104,13 @@ static int kvm_vcpu_set_machine_ids(RISCVCPU *cpu, CPUState *cs) return ret; } - id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG, - KVM_REG_RISCV_CONFIG_REG(marchid)); + id = RISCV_CONFIG_REG(env, marchid); ret = kvm_set_one_reg(cs, id, &cpu->cfg.marchid); if (ret != 0) { return ret; } - id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG, - KVM_REG_RISCV_CONFIG_REG(mimpid)); + id = RISCV_CONFIG_REG(env, mimpid); ret = kvm_set_one_reg(cs, id, &cpu->cfg.mimpid); return ret; From da14fc74d5965c4c22ed637775959b4d21dca813 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Fri, 8 Dec 2023 15:38:35 -0300 Subject: [PATCH 11/65] target/riscv/kvm: rename riscv_reg_id() to riscv_reg_id_ulong() kvm_riscv_reg_id() returns an id encoded with an ulong size, i.e. an u32 size when running TARGET_RISCV32 and u64 when running TARGET_RISCV64. Rename it to kvm_riscv_reg_id_ulong() to enhance code readability. It'll be in line with the existing kvm_riscv_reg_id_() helpers. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Message-ID: <20231208183835.2411523-6-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/kvm/kvm-cpu.c | 40 ++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index 15573402be..a31df6e273 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -54,7 +54,7 @@ void riscv_kvm_aplic_request(void *opaque, int irq, int level) static bool cap_has_mp_state; -static uint64_t kvm_riscv_reg_id(CPURISCVState *env, uint64_t type, +static uint64_t kvm_riscv_reg_id_ulong(CPURISCVState *env, uint64_t type, uint64_t idx) { uint64_t id = KVM_REG_RISCV | type | idx; @@ -82,15 +82,17 @@ static uint64_t kvm_riscv_reg_id_u64(uint64_t type, uint64_t idx) return KVM_REG_RISCV | KVM_REG_SIZE_U64 | type | idx; } -#define RISCV_CORE_REG(env, name) kvm_riscv_reg_id(env, KVM_REG_RISCV_CORE, \ - KVM_REG_RISCV_CORE_REG(name)) +#define RISCV_CORE_REG(env, name) \ + kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CORE, \ + KVM_REG_RISCV_CORE_REG(name)) -#define RISCV_CSR_REG(env, name) kvm_riscv_reg_id(env, KVM_REG_RISCV_CSR, \ - KVM_REG_RISCV_CSR_REG(name)) +#define RISCV_CSR_REG(env, name) \ + kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CSR, \ + KVM_REG_RISCV_CSR_REG(name)) #define RISCV_CONFIG_REG(env, name) \ - kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG, \ - KVM_REG_RISCV_CONFIG_REG(name)) + kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CONFIG, \ + KVM_REG_RISCV_CONFIG_REG(name)) #define RISCV_TIMER_REG(name) kvm_riscv_reg_id_u64(KVM_REG_RISCV_TIMER, \ KVM_REG_RISCV_TIMER_REG(name)) @@ -216,8 +218,8 @@ static void kvm_riscv_update_cpu_misa_ext(RISCVCPU *cpu, CPUState *cs) /* If we're here we're going to disable the MISA bit */ reg = 0; - id = kvm_riscv_reg_id(env, KVM_REG_RISCV_ISA_EXT, - misa_cfg->kvm_reg_id); + id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_ISA_EXT, + misa_cfg->kvm_reg_id); ret = kvm_set_one_reg(cs, id, ®); if (ret != 0) { /* @@ -378,8 +380,8 @@ static void kvm_riscv_update_cpu_cfg_isa_ext(RISCVCPU *cpu, CPUState *cs) continue; } - id = kvm_riscv_reg_id(env, KVM_REG_RISCV_ISA_EXT, - multi_ext_cfg->kvm_reg_id); + id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_ISA_EXT, + multi_ext_cfg->kvm_reg_id); reg = kvm_cpu_cfg_get(cpu, multi_ext_cfg); ret = kvm_set_one_reg(cs, id, ®); if (ret != 0) { @@ -509,7 +511,7 @@ static int kvm_riscv_get_regs_core(CPUState *cs) env->pc = reg; for (i = 1; i < 32; i++) { - uint64_t id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CORE, i); + uint64_t id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CORE, i); ret = kvm_get_one_reg(cs, id, ®); if (ret) { return ret; @@ -534,7 +536,7 @@ static int kvm_riscv_put_regs_core(CPUState *cs) } for (i = 1; i < 32; i++) { - uint64_t id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CORE, i); + uint64_t id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CORE, i); reg = env->gpr[i]; ret = kvm_set_one_reg(cs, id, ®); if (ret) { @@ -810,8 +812,8 @@ static void kvm_riscv_read_cbomz_blksize(RISCVCPU *cpu, KVMScratchCPU *kvmcpu, struct kvm_one_reg reg; int ret; - reg.id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG, - cbomz_cfg->kvm_reg_id); + reg.id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CONFIG, + cbomz_cfg->kvm_reg_id); reg.addr = (uint64_t)kvmconfig_get_cfg_addr(cpu, cbomz_cfg); ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); if (ret != 0) { @@ -832,8 +834,8 @@ static void kvm_riscv_read_multiext_legacy(RISCVCPU *cpu, KVMCPUConfig *multi_ext_cfg = &kvm_multi_ext_cfgs[i]; struct kvm_one_reg reg; - reg.id = kvm_riscv_reg_id(env, KVM_REG_RISCV_ISA_EXT, - multi_ext_cfg->kvm_reg_id); + reg.id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_ISA_EXT, + multi_ext_cfg->kvm_reg_id); reg.addr = (uint64_t)&val; ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); if (ret != 0) { @@ -924,8 +926,8 @@ static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) for (i = 0; i < ARRAY_SIZE(kvm_multi_ext_cfgs); i++) { multi_ext_cfg = &kvm_multi_ext_cfgs[i]; - reg_id = kvm_riscv_reg_id(&cpu->env, KVM_REG_RISCV_ISA_EXT, - multi_ext_cfg->kvm_reg_id); + reg_id = kvm_riscv_reg_id_ulong(&cpu->env, KVM_REG_RISCV_ISA_EXT, + multi_ext_cfg->kvm_reg_id); reg_search = bsearch(®_id, reglist->reg, reglist->n, sizeof(uint64_t), uint64_cmp); if (!reg_search) { From 4c7f4f4f0516ad1bad45b011235202f5be6899de Mon Sep 17 00:00:00 2001 From: Sunil V L Date: Mon, 18 Dec 2023 20:32:35 +0530 Subject: [PATCH 12/65] hw/arm/virt-acpi-build.c: Migrate fw_cfg creation to common location RISC-V also needs to use the same code to create fw_cfg in DSDT. So, avoid code duplication by moving the code in arm and riscv to a device specific file. Suggested-by: Igor Mammedov Signed-off-by: Sunil V L Reviewed-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Reviewed-by: Andrew Jones Acked-by: Michael S. Tsirkin Message-ID: <20231218150247.466427-2-sunilvl@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/arm/virt-acpi-build.c | 19 ++----------------- hw/nvram/fw_cfg-acpi.c | 23 +++++++++++++++++++++++ hw/nvram/meson.build | 1 + hw/riscv/virt-acpi-build.c | 19 ++----------------- include/hw/nvram/fw_cfg_acpi.h | 15 +++++++++++++++ 5 files changed, 43 insertions(+), 34 deletions(-) create mode 100644 hw/nvram/fw_cfg-acpi.c create mode 100644 include/hw/nvram/fw_cfg_acpi.h diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 5e7cf6c6b3..b6edf9db00 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -35,7 +35,7 @@ #include "target/arm/cpu.h" #include "hw/acpi/acpi-defs.h" #include "hw/acpi/acpi.h" -#include "hw/nvram/fw_cfg.h" +#include "hw/nvram/fw_cfg_acpi.h" #include "hw/acpi/bios-linker-loader.h" #include "hw/acpi/aml-build.h" #include "hw/acpi/utils.h" @@ -94,21 +94,6 @@ static void acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap, aml_append(scope, dev); } -static void acpi_dsdt_add_fw_cfg(Aml *scope, const MemMapEntry *fw_cfg_memmap) -{ - Aml *dev = aml_device("FWCF"); - aml_append(dev, aml_name_decl("_HID", aml_string("QEMU0002"))); - /* device present, functioning, decoding, not shown in UI */ - aml_append(dev, aml_name_decl("_STA", aml_int(0xB))); - aml_append(dev, aml_name_decl("_CCA", aml_int(1))); - - Aml *crs = aml_resource_template(); - aml_append(crs, aml_memory32_fixed(fw_cfg_memmap->base, - fw_cfg_memmap->size, AML_READ_WRITE)); - aml_append(dev, aml_name_decl("_CRS", crs)); - aml_append(scope, dev); -} - static void acpi_dsdt_add_flash(Aml *scope, const MemMapEntry *flash_memmap) { Aml *dev, *crs; @@ -864,7 +849,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) if (vmc->acpi_expose_flash) { acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]); } - acpi_dsdt_add_fw_cfg(scope, &memmap[VIRT_FW_CFG]); + fw_cfg_acpi_dsdt_add(scope, &memmap[VIRT_FW_CFG]); acpi_dsdt_add_virtio(scope, &memmap[VIRT_MMIO], (irqmap[VIRT_MMIO] + ARM_SPI_BASE), NUM_VIRTIO_TRANSPORTS); acpi_dsdt_add_pci(scope, memmap, irqmap[VIRT_PCIE] + ARM_SPI_BASE, vms); diff --git a/hw/nvram/fw_cfg-acpi.c b/hw/nvram/fw_cfg-acpi.c new file mode 100644 index 0000000000..4e48baeaa0 --- /dev/null +++ b/hw/nvram/fw_cfg-acpi.c @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Add fw_cfg device in DSDT + * + */ + +#include "hw/nvram/fw_cfg_acpi.h" +#include "hw/acpi/aml-build.h" + +void fw_cfg_acpi_dsdt_add(Aml *scope, const MemMapEntry *fw_cfg_memmap) +{ + Aml *dev = aml_device("FWCF"); + aml_append(dev, aml_name_decl("_HID", aml_string("QEMU0002"))); + /* device present, functioning, decoding, not shown in UI */ + aml_append(dev, aml_name_decl("_STA", aml_int(0xB))); + aml_append(dev, aml_name_decl("_CCA", aml_int(1))); + + Aml *crs = aml_resource_template(); + aml_append(crs, aml_memory32_fixed(fw_cfg_memmap->base, + fw_cfg_memmap->size, AML_READ_WRITE)); + aml_append(dev, aml_name_decl("_CRS", crs)); + aml_append(scope, dev); +} diff --git a/hw/nvram/meson.build b/hw/nvram/meson.build index 75e415b1a0..4996c72456 100644 --- a/hw/nvram/meson.build +++ b/hw/nvram/meson.build @@ -17,3 +17,4 @@ system_ss.add(when: 'CONFIG_XLNX_EFUSE_ZYNQMP', if_true: files( system_ss.add(when: 'CONFIG_XLNX_BBRAM', if_true: files('xlnx-bbram.c')) specific_ss.add(when: 'CONFIG_PSERIES', if_true: files('spapr_nvram.c')) +specific_ss.add(when: 'CONFIG_ACPI', if_true: files('fw_cfg-acpi.c')) diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c index d3bfaf502e..fc04d1defa 100644 --- a/hw/riscv/virt-acpi-build.c +++ b/hw/riscv/virt-acpi-build.c @@ -28,6 +28,7 @@ #include "hw/acpi/acpi.h" #include "hw/acpi/aml-build.h" #include "hw/acpi/utils.h" +#include "hw/nvram/fw_cfg_acpi.h" #include "qapi/error.h" #include "qemu/error-report.h" #include "sysemu/reset.h" @@ -97,22 +98,6 @@ static void acpi_dsdt_add_cpus(Aml *scope, RISCVVirtState *s) } } -static void acpi_dsdt_add_fw_cfg(Aml *scope, const MemMapEntry *fw_cfg_memmap) -{ - Aml *dev = aml_device("FWCF"); - aml_append(dev, aml_name_decl("_HID", aml_string("QEMU0002"))); - - /* device present, functioning, decoding, not shown in UI */ - aml_append(dev, aml_name_decl("_STA", aml_int(0xB))); - aml_append(dev, aml_name_decl("_CCA", aml_int(1))); - - Aml *crs = aml_resource_template(); - aml_append(crs, aml_memory32_fixed(fw_cfg_memmap->base, - fw_cfg_memmap->size, AML_READ_WRITE)); - aml_append(dev, aml_name_decl("_CRS", crs)); - aml_append(scope, dev); -} - /* RHCT Node[N] starts at offset 56 */ #define RHCT_NODE_ARRAY_OFFSET 56 @@ -226,7 +211,7 @@ static void build_dsdt(GArray *table_data, scope = aml_scope("\\_SB"); acpi_dsdt_add_cpus(scope, s); - acpi_dsdt_add_fw_cfg(scope, &memmap[VIRT_FW_CFG]); + fw_cfg_acpi_dsdt_add(scope, &memmap[VIRT_FW_CFG]); aml_append(dsdt, scope); diff --git a/include/hw/nvram/fw_cfg_acpi.h b/include/hw/nvram/fw_cfg_acpi.h new file mode 100644 index 0000000000..b6553d86fc --- /dev/null +++ b/include/hw/nvram/fw_cfg_acpi.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * ACPI support for fw_cfg + * + */ + +#ifndef FW_CFG_ACPI_H +#define FW_CFG_ACPI_H + +#include "qemu/osdep.h" +#include "exec/hwaddr.h" + +void fw_cfg_acpi_dsdt_add(Aml *scope, const MemMapEntry *fw_cfg_memmap); + +#endif From 57ba8436282940b59d9a069cc01a601bbc8036c5 Mon Sep 17 00:00:00 2001 From: Sunil V L Date: Mon, 18 Dec 2023 20:32:36 +0530 Subject: [PATCH 13/65] hw/arm/virt-acpi-build.c: Migrate virtio creation to common location RISC-V also needs to create the virtio in DSDT in the same way as ARM. So, instead of duplicating the code, move this function to the device specific file which is common across architectures. Suggested-by: Igor Mammedov Signed-off-by: Sunil V L Reviewed-by: Alistair Francis Reviewed-by: Andrew Jones Acked-by: Michael S. Tsirkin Message-ID: <20231218150247.466427-3-sunilvl@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/arm/virt-acpi-build.c | 32 ++++---------------------------- hw/virtio/meson.build | 1 + hw/virtio/virtio-acpi.c | 33 +++++++++++++++++++++++++++++++++ include/hw/virtio/virtio-acpi.h | 16 ++++++++++++++++ 4 files changed, 54 insertions(+), 28 deletions(-) create mode 100644 hw/virtio/virtio-acpi.c create mode 100644 include/hw/virtio/virtio-acpi.h diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index b6edf9db00..a22a2f43a5 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -58,6 +58,7 @@ #include "migration/vmstate.h" #include "hw/acpi/ghes.h" #include "hw/acpi/viot.h" +#include "hw/virtio/virtio-acpi.h" #define ARM_SPI_BASE 32 @@ -118,32 +119,6 @@ static void acpi_dsdt_add_flash(Aml *scope, const MemMapEntry *flash_memmap) aml_append(scope, dev); } -static void acpi_dsdt_add_virtio(Aml *scope, - const MemMapEntry *virtio_mmio_memmap, - uint32_t mmio_irq, int num) -{ - hwaddr base = virtio_mmio_memmap->base; - hwaddr size = virtio_mmio_memmap->size; - int i; - - for (i = 0; i < num; i++) { - uint32_t irq = mmio_irq + i; - Aml *dev = aml_device("VR%02u", i); - aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0005"))); - aml_append(dev, aml_name_decl("_UID", aml_int(i))); - aml_append(dev, aml_name_decl("_CCA", aml_int(1))); - - Aml *crs = aml_resource_template(); - aml_append(crs, aml_memory32_fixed(base, size, AML_READ_WRITE)); - aml_append(crs, - aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, - AML_EXCLUSIVE, &irq, 1)); - aml_append(dev, aml_name_decl("_CRS", crs)); - aml_append(scope, dev); - base += size; - } -} - static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap, uint32_t irq, VirtMachineState *vms) { @@ -850,8 +825,9 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]); } fw_cfg_acpi_dsdt_add(scope, &memmap[VIRT_FW_CFG]); - acpi_dsdt_add_virtio(scope, &memmap[VIRT_MMIO], - (irqmap[VIRT_MMIO] + ARM_SPI_BASE), NUM_VIRTIO_TRANSPORTS); + virtio_acpi_dsdt_add(scope, memmap[VIRT_MMIO].base, memmap[VIRT_MMIO].size, + (irqmap[VIRT_MMIO] + ARM_SPI_BASE), + 0, NUM_VIRTIO_TRANSPORTS); acpi_dsdt_add_pci(scope, memmap, irqmap[VIRT_PCIE] + ARM_SPI_BASE, vms); if (vms->acpi_dev) { build_ged_aml(scope, "\\_SB."GED_DEVICE, diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build index c8c1001451..47baf00366 100644 --- a/hw/virtio/meson.build +++ b/hw/virtio/meson.build @@ -77,3 +77,4 @@ system_ss.add(when: 'CONFIG_VIRTIO', if_false: files('virtio-stub.c')) system_ss.add(files('virtio-hmp-cmds.c')) specific_ss.add_all(when: 'CONFIG_VIRTIO', if_true: specific_virtio_ss) +system_ss.add(when: 'CONFIG_ACPI', if_true: files('virtio-acpi.c')) diff --git a/hw/virtio/virtio-acpi.c b/hw/virtio/virtio-acpi.c new file mode 100644 index 0000000000..e18cb38bdb --- /dev/null +++ b/hw/virtio/virtio-acpi.c @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * virtio ACPI Support + * + */ + +#include "hw/virtio/virtio-acpi.h" +#include "hw/acpi/aml-build.h" + +void virtio_acpi_dsdt_add(Aml *scope, const hwaddr base, const hwaddr size, + uint32_t mmio_irq, long int start_index, int num) +{ + hwaddr virtio_base = base; + uint32_t irq = mmio_irq; + long int i; + + for (i = start_index; i < start_index + num; i++) { + Aml *dev = aml_device("VR%02u", (unsigned)i); + aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0005"))); + aml_append(dev, aml_name_decl("_UID", aml_int(i))); + aml_append(dev, aml_name_decl("_CCA", aml_int(1))); + + Aml *crs = aml_resource_template(); + aml_append(crs, aml_memory32_fixed(virtio_base, size, AML_READ_WRITE)); + aml_append(crs, + aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, + AML_EXCLUSIVE, &irq, 1)); + aml_append(dev, aml_name_decl("_CRS", crs)); + aml_append(scope, dev); + virtio_base += size; + irq++; + } +} diff --git a/include/hw/virtio/virtio-acpi.h b/include/hw/virtio/virtio-acpi.h new file mode 100644 index 0000000000..844e102569 --- /dev/null +++ b/include/hw/virtio/virtio-acpi.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * ACPI support for virtio + */ + +#ifndef VIRTIO_ACPI_H +#define VIRTIO_ACPI_H + +#include "qemu/osdep.h" +#include "exec/hwaddr.h" + +void virtio_acpi_dsdt_add(Aml *scope, const hwaddr virtio_mmio_base, + const hwaddr virtio_mmio_size, uint32_t mmio_irq, + long int start_index, int num); + +#endif From 8199bf48ea1fdb8e491311a0dc28cea30af18c95 Mon Sep 17 00:00:00 2001 From: Sunil V L Date: Mon, 18 Dec 2023 20:32:37 +0530 Subject: [PATCH 14/65] hw/i386/acpi-microvm.c: Use common function to add virtio in DSDT With common function to add virtio in DSDT created now, update microvm code also to use it instead of duplicate code. Suggested-by: Andrew Jones Signed-off-by: Sunil V L Acked-by: Alistair Francis Acked-by: Michael S. Tsirkin Message-ID: <20231218150247.466427-4-sunilvl@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/i386/acpi-microvm.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/hw/i386/acpi-microvm.c b/hw/i386/acpi-microvm.c index 2909a73933..279da6b4aa 100644 --- a/hw/i386/acpi-microvm.c +++ b/hw/i386/acpi-microvm.c @@ -37,6 +37,7 @@ #include "hw/pci/pci.h" #include "hw/pci/pcie_host.h" #include "hw/usb/xhci.h" +#include "hw/virtio/virtio-acpi.h" #include "hw/virtio/virtio-mmio.h" #include "hw/input/i8042.h" @@ -77,19 +78,7 @@ static void acpi_dsdt_add_virtio(Aml *scope, uint32_t irq = mms->virtio_irq_base + index; hwaddr base = VIRTIO_MMIO_BASE + index * 512; hwaddr size = 512; - - Aml *dev = aml_device("VR%02u", (unsigned)index); - aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0005"))); - aml_append(dev, aml_name_decl("_UID", aml_int(index))); - aml_append(dev, aml_name_decl("_CCA", aml_int(1))); - - Aml *crs = aml_resource_template(); - aml_append(crs, aml_memory32_fixed(base, size, AML_READ_WRITE)); - aml_append(crs, - aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, - AML_EXCLUSIVE, &irq, 1)); - aml_append(dev, aml_name_decl("_CRS", crs)); - aml_append(scope, dev); + virtio_acpi_dsdt_add(scope, base, size, irq, index, 1); } } } From 68c8b403c78b8f20acbebba3cdc46320853fe5ca Mon Sep 17 00:00:00 2001 From: Sunil V L Date: Mon, 18 Dec 2023 20:32:38 +0530 Subject: [PATCH 15/65] hw/riscv: virt: Make few IMSIC macros and functions public Some macros and static function related to IMSIC are defined in virt.c. They are required in virt-acpi-build.c. So, make them public. Signed-off-by: Sunil V L Reviewed-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Reviewed-by: Andrew Jones Acked-by: Michael S. Tsirkin Message-ID: <20231218150247.466427-5-sunilvl@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/virt.c | 25 +------------------------ include/hw/riscv/virt.h | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index d2eac24156..9e7629c51c 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -38,7 +38,6 @@ #include "kvm/kvm_riscv.h" #include "hw/intc/riscv_aclint.h" #include "hw/intc/riscv_aplic.h" -#include "hw/intc/riscv_imsic.h" #include "hw/intc/sifive_plic.h" #include "hw/misc/sifive_test.h" #include "hw/platform-bus.h" @@ -54,28 +53,6 @@ #include "hw/acpi/aml-build.h" #include "qapi/qapi-visit-common.h" -/* - * The virt machine physical address space used by some of the devices - * namely ACLINT, PLIC, APLIC, and IMSIC depend on number of Sockets, - * number of CPUs, and number of IMSIC guest files. - * - * Various limits defined by VIRT_SOCKETS_MAX_BITS, VIRT_CPUS_MAX_BITS, - * and VIRT_IRQCHIP_MAX_GUESTS_BITS are tuned for maximum utilization - * of virt machine physical address space. - */ - -#define VIRT_IMSIC_GROUP_MAX_SIZE (1U << IMSIC_MMIO_GROUP_MIN_SHIFT) -#if VIRT_IMSIC_GROUP_MAX_SIZE < \ - IMSIC_GROUP_SIZE(VIRT_CPUS_MAX_BITS, VIRT_IRQCHIP_MAX_GUESTS_BITS) -#error "Can't accommodate single IMSIC group in address space" -#endif - -#define VIRT_IMSIC_MAX_SIZE (VIRT_SOCKETS_MAX * \ - VIRT_IMSIC_GROUP_MAX_SIZE) -#if 0x4000000 < VIRT_IMSIC_MAX_SIZE -#error "Can't accommodate all IMSIC groups in address space" -#endif - /* KVM AIA only supports APLIC MSI. APLIC Wired is always emulated by QEMU. */ static bool virt_use_kvm_aia(RISCVVirtState *s) { @@ -512,7 +489,7 @@ static void create_fdt_socket_plic(RISCVVirtState *s, g_free(plic_cells); } -static uint32_t imsic_num_bits(uint32_t count) +uint32_t imsic_num_bits(uint32_t count) { uint32_t ret = 0; diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h index e5c474b26e..5b03575ed3 100644 --- a/include/hw/riscv/virt.h +++ b/include/hw/riscv/virt.h @@ -23,6 +23,7 @@ #include "hw/riscv/riscv_hart.h" #include "hw/sysbus.h" #include "hw/block/flash.h" +#include "hw/intc/riscv_imsic.h" #define VIRT_CPUS_MAX_BITS 9 #define VIRT_CPUS_MAX (1 << VIRT_CPUS_MAX_BITS) @@ -127,4 +128,28 @@ enum { bool virt_is_acpi_enabled(RISCVVirtState *s); void virt_acpi_setup(RISCVVirtState *vms); +uint32_t imsic_num_bits(uint32_t count); + +/* + * The virt machine physical address space used by some of the devices + * namely ACLINT, PLIC, APLIC, and IMSIC depend on number of Sockets, + * number of CPUs, and number of IMSIC guest files. + * + * Various limits defined by VIRT_SOCKETS_MAX_BITS, VIRT_CPUS_MAX_BITS, + * and VIRT_IRQCHIP_MAX_GUESTS_BITS are tuned for maximum utilization + * of virt machine physical address space. + */ + +#define VIRT_IMSIC_GROUP_MAX_SIZE (1U << IMSIC_MMIO_GROUP_MIN_SHIFT) +#if VIRT_IMSIC_GROUP_MAX_SIZE < \ + IMSIC_GROUP_SIZE(VIRT_CPUS_MAX_BITS, VIRT_IRQCHIP_MAX_GUESTS_BITS) +#error "Can't accomodate single IMSIC group in address space" +#endif + +#define VIRT_IMSIC_MAX_SIZE (VIRT_SOCKETS_MAX * \ + VIRT_IMSIC_GROUP_MAX_SIZE) +#if 0x4000000 < VIRT_IMSIC_MAX_SIZE +#error "Can't accomodate all IMSIC groups in address space" +#endif + #endif From 0efb12b713338e2be713b689d1c9743f7163f85d Mon Sep 17 00:00:00 2001 From: Sunil V L Date: Mon, 18 Dec 2023 20:32:39 +0530 Subject: [PATCH 16/65] hw/riscv/virt-acpi-build.c: Add AIA support in RINTC Update the RINTC structure in MADT with AIA related fields. Signed-off-by: Sunil V L Reviewed-by: Daniel Henrique Barboza Acked-by: Alistair Francis Reviewed-by: Andrew Jones Acked-by: Michael S. Tsirkin Message-ID: <20231218150247.466427-6-sunilvl@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/virt-acpi-build.c | 43 ++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c index fc04d1defa..8f61fd63eb 100644 --- a/hw/riscv/virt-acpi-build.c +++ b/hw/riscv/virt-acpi-build.c @@ -38,6 +38,7 @@ #include "hw/intc/riscv_aclint.h" #define ACPI_BUILD_TABLE_SIZE 0x20000 +#define ACPI_BUILD_INTC_ID(socket, index) ((socket << 24) | (index)) typedef struct AcpiBuildState { /* Copy of table in RAM (for patching) */ @@ -59,17 +60,50 @@ static void acpi_align_size(GArray *blob, unsigned align) static void riscv_acpi_madt_add_rintc(uint32_t uid, const CPUArchIdList *arch_ids, - GArray *entry) + GArray *entry, + RISCVVirtState *s) { + uint8_t guest_index_bits = imsic_num_bits(s->aia_guests + 1); uint64_t hart_id = arch_ids->cpus[uid].arch_id; + uint32_t imsic_size, local_cpu_id, socket_id; + uint64_t imsic_socket_addr, imsic_addr; + MachineState *ms = MACHINE(s); + socket_id = arch_ids->cpus[uid].props.node_id; + local_cpu_id = (arch_ids->cpus[uid].arch_id - + riscv_socket_first_hartid(ms, socket_id)) % + riscv_socket_hart_count(ms, socket_id); + imsic_socket_addr = s->memmap[VIRT_IMSIC_S].base + + (socket_id * VIRT_IMSIC_GROUP_MAX_SIZE); + imsic_size = IMSIC_HART_SIZE(guest_index_bits); + imsic_addr = imsic_socket_addr + local_cpu_id * imsic_size; build_append_int_noprefix(entry, 0x18, 1); /* Type */ - build_append_int_noprefix(entry, 20, 1); /* Length */ + build_append_int_noprefix(entry, 36, 1); /* Length */ build_append_int_noprefix(entry, 1, 1); /* Version */ build_append_int_noprefix(entry, 0, 1); /* Reserved */ build_append_int_noprefix(entry, 0x1, 4); /* Flags */ build_append_int_noprefix(entry, hart_id, 8); /* Hart ID */ build_append_int_noprefix(entry, uid, 4); /* ACPI Processor UID */ + /* External Interrupt Controller ID */ + if (s->aia_type == VIRT_AIA_TYPE_APLIC) { + build_append_int_noprefix(entry, + ACPI_BUILD_INTC_ID( + arch_ids->cpus[uid].props.node_id, + local_cpu_id), + 4); + } else { + build_append_int_noprefix(entry, 0, 4); + } + + if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) { + /* IMSIC Base address */ + build_append_int_noprefix(entry, imsic_addr, 8); + /* IMSIC Size */ + build_append_int_noprefix(entry, imsic_size, 4); + } else { + build_append_int_noprefix(entry, 0, 8); + build_append_int_noprefix(entry, 0, 4); + } } static void acpi_dsdt_add_cpus(Aml *scope, RISCVVirtState *s) @@ -88,7 +122,7 @@ static void acpi_dsdt_add_cpus(Aml *scope, RISCVVirtState *s) aml_int(arch_ids->cpus[i].arch_id))); /* build _MAT object */ - riscv_acpi_madt_add_rintc(i, arch_ids, madt_buf); + riscv_acpi_madt_add_rintc(i, arch_ids, madt_buf, s); aml_append(dev, aml_name_decl("_MAT", aml_buffer(madt_buf->len, (uint8_t *)madt_buf->data))); @@ -227,6 +261,7 @@ static void build_dsdt(GArray *table_data, * 5.2.12 Multiple APIC Description Table (MADT) * REF: https://github.com/riscv-non-isa/riscv-acpi/issues/15 * https://drive.google.com/file/d/1R6k4MshhN3WTT-hwqAquu5nX6xSEqK2l/view + * https://drive.google.com/file/d/1oMGPyOD58JaPgMl1pKasT-VKsIKia7zR/view */ static void build_madt(GArray *table_data, BIOSLinker *linker, @@ -246,7 +281,7 @@ static void build_madt(GArray *table_data, /* RISC-V Local INTC structures per HART */ for (int i = 0; i < arch_ids->len; i++) { - riscv_acpi_madt_add_rintc(i, arch_ids, table_data); + riscv_acpi_madt_add_rintc(i, arch_ids, table_data, s); } acpi_table_end(linker, &table); From 66ac45b75975a64aa3fbcaa038aecfbc11ac8547 Mon Sep 17 00:00:00 2001 From: Sunil V L Date: Mon, 18 Dec 2023 20:32:40 +0530 Subject: [PATCH 17/65] hw/riscv/virt-acpi-build.c: Add IMSIC in the MADT Add IMSIC structure in MADT when IMSIC is configured. Signed-off-by: Sunil V L Reviewed-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Acked-by: Alistair Francis Acked-by: Michael S. Tsirkin Message-ID: <20231218150247.466427-7-sunilvl@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/virt-acpi-build.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c index 8f61fd63eb..32b5795f09 100644 --- a/hw/riscv/virt-acpi-build.c +++ b/hw/riscv/virt-acpi-build.c @@ -270,6 +270,19 @@ static void build_madt(GArray *table_data, MachineClass *mc = MACHINE_GET_CLASS(s); MachineState *ms = MACHINE(s); const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(ms); + uint8_t group_index_bits = imsic_num_bits(riscv_socket_count(ms)); + uint8_t guest_index_bits = imsic_num_bits(s->aia_guests + 1); + uint16_t imsic_max_hart_per_socket = 0; + uint8_t hart_index_bits; + uint8_t socket; + + for (socket = 0; socket < riscv_socket_count(ms); socket++) { + if (imsic_max_hart_per_socket < s->soc[socket].num_harts) { + imsic_max_hart_per_socket = s->soc[socket].num_harts; + } + } + + hart_index_bits = imsic_num_bits(imsic_max_hart_per_socket); AcpiTable table = { .sig = "APIC", .rev = 6, .oem_id = s->oem_id, .oem_table_id = s->oem_table_id }; @@ -284,6 +297,28 @@ static void build_madt(GArray *table_data, riscv_acpi_madt_add_rintc(i, arch_ids, table_data, s); } + /* IMSIC */ + if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) { + /* IMSIC */ + build_append_int_noprefix(table_data, 0x19, 1); /* Type */ + build_append_int_noprefix(table_data, 16, 1); /* Length */ + build_append_int_noprefix(table_data, 1, 1); /* Version */ + build_append_int_noprefix(table_data, 0, 1); /* Reserved */ + build_append_int_noprefix(table_data, 0, 4); /* Flags */ + /* Number of supervisor mode Interrupt Identities */ + build_append_int_noprefix(table_data, VIRT_IRQCHIP_NUM_MSIS, 2); + /* Number of guest mode Interrupt Identities */ + build_append_int_noprefix(table_data, VIRT_IRQCHIP_NUM_MSIS, 2); + /* Guest Index Bits */ + build_append_int_noprefix(table_data, guest_index_bits, 1); + /* Hart Index Bits */ + build_append_int_noprefix(table_data, hart_index_bits, 1); + /* Group Index Bits */ + build_append_int_noprefix(table_data, group_index_bits, 1); + /* Group Index Shift */ + build_append_int_noprefix(table_data, IMSIC_MMIO_GROUP_MIN_SHIFT, 1); + } + acpi_table_end(linker, &table); } From 7d189186f68b2b249c0bd6c84984f3aad2bcd1ca Mon Sep 17 00:00:00 2001 From: Sunil V L Date: Mon, 18 Dec 2023 20:32:41 +0530 Subject: [PATCH 18/65] hw/riscv/virt-acpi-build.c: Add APLIC in the MADT Add APLIC structures for each socket in the MADT when system is configured with APLIC as the external wired interrupt controller. Signed-off-by: Sunil V L Reviewed-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Acked-by: Alistair Francis Acked-by: Michael S. Tsirkin Message-ID: <20231218150247.466427-8-sunilvl@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/virt-acpi-build.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c index 32b5795f09..f50f022dc2 100644 --- a/hw/riscv/virt-acpi-build.c +++ b/hw/riscv/virt-acpi-build.c @@ -274,6 +274,8 @@ static void build_madt(GArray *table_data, uint8_t guest_index_bits = imsic_num_bits(s->aia_guests + 1); uint16_t imsic_max_hart_per_socket = 0; uint8_t hart_index_bits; + uint64_t aplic_addr; + uint32_t gsi_base; uint8_t socket; for (socket = 0; socket < riscv_socket_count(ms); socket++) { @@ -319,6 +321,38 @@ static void build_madt(GArray *table_data, build_append_int_noprefix(table_data, IMSIC_MMIO_GROUP_MIN_SHIFT, 1); } + if (s->aia_type != VIRT_AIA_TYPE_NONE) { + /* APLICs */ + for (socket = 0; socket < riscv_socket_count(ms); socket++) { + aplic_addr = s->memmap[VIRT_APLIC_S].base + + s->memmap[VIRT_APLIC_S].size * socket; + gsi_base = VIRT_IRQCHIP_NUM_SOURCES * socket; + build_append_int_noprefix(table_data, 0x1A, 1); /* Type */ + build_append_int_noprefix(table_data, 36, 1); /* Length */ + build_append_int_noprefix(table_data, 1, 1); /* Version */ + build_append_int_noprefix(table_data, socket, 1); /* APLIC ID */ + build_append_int_noprefix(table_data, 0, 4); /* Flags */ + build_append_int_noprefix(table_data, 0, 8); /* Hardware ID */ + /* Number of IDCs */ + if (s->aia_type == VIRT_AIA_TYPE_APLIC) { + build_append_int_noprefix(table_data, + s->soc[socket].num_harts, + 2); + } else { + build_append_int_noprefix(table_data, 0, 2); + } + /* Total External Interrupt Sources Supported */ + build_append_int_noprefix(table_data, VIRT_IRQCHIP_NUM_SOURCES, 2); + /* Global System Interrupt Base */ + build_append_int_noprefix(table_data, gsi_base, 4); + /* APLIC Address */ + build_append_int_noprefix(table_data, aplic_addr, 8); + /* APLIC size */ + build_append_int_noprefix(table_data, + s->memmap[VIRT_APLIC_S].size, 4); + } + } + acpi_table_end(linker, &table); } From e810a5177c44509e17293d4c7e6cffab8ce197c9 Mon Sep 17 00:00:00 2001 From: Sunil V L Date: Mon, 18 Dec 2023 20:32:42 +0530 Subject: [PATCH 19/65] hw/riscv/virt-acpi-build.c: Add CMO information in RHCT When CMO related extensions like Zicboz, Zicbom and Zicbop are enabled, the block size for those extensions need to be communicated via CMO node in RHCT. Add CMO node in RHCT if any of those CMO extensions are detected. Signed-off-by: Sunil V L Reviewed-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Acked-by: Alistair Francis Acked-by: Michael S. Tsirkin Message-ID: <20231218150247.466427-9-sunilvl@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/virt-acpi-build.c | 64 +++++++++++++++++++++++++++++++++----- 1 file changed, 56 insertions(+), 8 deletions(-) diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c index f50f022dc2..784bbffead 100644 --- a/hw/riscv/virt-acpi-build.c +++ b/hw/riscv/virt-acpi-build.c @@ -140,6 +140,7 @@ static void acpi_dsdt_add_cpus(Aml *scope, RISCVVirtState *s) * 5.2.36 RISC-V Hart Capabilities Table (RHCT) * REF: https://github.com/riscv-non-isa/riscv-acpi/issues/16 * https://drive.google.com/file/d/1nP3nFiH4jkPMp6COOxP6123DCZKR-tia/view + * https://drive.google.com/file/d/1sKbOa8m1UZw1JkquZYe3F1zQBN1xXsaf/view */ static void build_rhct(GArray *table_data, BIOSLinker *linker, @@ -149,8 +150,8 @@ static void build_rhct(GArray *table_data, MachineState *ms = MACHINE(s); const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(ms); size_t len, aligned_len; - uint32_t isa_offset, num_rhct_nodes; - RISCVCPU *cpu; + uint32_t isa_offset, num_rhct_nodes, cmo_offset = 0; + RISCVCPU *cpu = &s->soc[0].harts[0]; char *isa; AcpiTable table = { .sig = "RHCT", .rev = 1, .oem_id = s->oem_id, @@ -166,6 +167,9 @@ static void build_rhct(GArray *table_data, /* ISA + N hart info */ num_rhct_nodes = 1 + ms->smp.cpus; + if (cpu->cfg.ext_zicbom || cpu->cfg.ext_zicboz) { + num_rhct_nodes++; + } /* Number of RHCT nodes*/ build_append_int_noprefix(table_data, num_rhct_nodes, 4); @@ -177,7 +181,6 @@ static void build_rhct(GArray *table_data, isa_offset = table_data->len - table.table_offset; build_append_int_noprefix(table_data, 0, 2); /* Type 0 */ - cpu = &s->soc[0].harts[0]; isa = riscv_isa_string(cpu); len = 8 + strlen(isa) + 1; aligned_len = (len % 2) ? (len + 1) : len; @@ -193,14 +196,59 @@ static void build_rhct(GArray *table_data, build_append_int_noprefix(table_data, 0x0, 1); /* Optional Padding */ } + /* CMO node */ + if (cpu->cfg.ext_zicbom || cpu->cfg.ext_zicboz) { + cmo_offset = table_data->len - table.table_offset; + build_append_int_noprefix(table_data, 1, 2); /* Type */ + build_append_int_noprefix(table_data, 10, 2); /* Length */ + build_append_int_noprefix(table_data, 0x1, 2); /* Revision */ + build_append_int_noprefix(table_data, 0, 1); /* Reserved */ + + /* CBOM block size */ + if (cpu->cfg.cbom_blocksize) { + build_append_int_noprefix(table_data, + __builtin_ctz(cpu->cfg.cbom_blocksize), + 1); + } else { + build_append_int_noprefix(table_data, 0, 1); + } + + /* CBOP block size */ + build_append_int_noprefix(table_data, 0, 1); + + /* CBOZ block size */ + if (cpu->cfg.cboz_blocksize) { + build_append_int_noprefix(table_data, + __builtin_ctz(cpu->cfg.cboz_blocksize), + 1); + } else { + build_append_int_noprefix(table_data, 0, 1); + } + } + /* Hart Info Node */ for (int i = 0; i < arch_ids->len; i++) { + len = 16; + int num_offsets = 1; build_append_int_noprefix(table_data, 0xFFFF, 2); /* Type */ - build_append_int_noprefix(table_data, 16, 2); /* Length */ - build_append_int_noprefix(table_data, 0x1, 2); /* Revision */ - build_append_int_noprefix(table_data, 1, 2); /* Number of offsets */ - build_append_int_noprefix(table_data, i, 4); /* ACPI Processor UID */ - build_append_int_noprefix(table_data, isa_offset, 4); /* Offsets[0] */ + + /* Length */ + if (cmo_offset) { + len += 4; + num_offsets++; + } + + build_append_int_noprefix(table_data, len, 2); + build_append_int_noprefix(table_data, 0x1, 2); /* Revision */ + /* Number of offsets */ + build_append_int_noprefix(table_data, num_offsets, 2); + build_append_int_noprefix(table_data, i, 4); /* ACPI Processor UID */ + + /* Offsets */ + build_append_int_noprefix(table_data, isa_offset, 4); + if (cmo_offset) { + build_append_int_noprefix(table_data, cmo_offset, 4); + } } acpi_table_end(linker, &table); From a52aea263e0f25993e368ee682d96f32aff52499 Mon Sep 17 00:00:00 2001 From: Sunil V L Date: Mon, 18 Dec 2023 20:32:43 +0530 Subject: [PATCH 20/65] hw/riscv/virt-acpi-build.c: Add MMU node in RHCT MMU type information is available via MMU node in RHCT. Add this node in RHCT. Signed-off-by: Sunil V L Reviewed-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Acked-by: Alistair Francis Acked-by: Michael S. Tsirkin Message-ID: <20231218150247.466427-10-sunilvl@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/virt-acpi-build.c | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c index 784bbffead..b7db57b28a 100644 --- a/hw/riscv/virt-acpi-build.c +++ b/hw/riscv/virt-acpi-build.c @@ -152,6 +152,8 @@ static void build_rhct(GArray *table_data, size_t len, aligned_len; uint32_t isa_offset, num_rhct_nodes, cmo_offset = 0; RISCVCPU *cpu = &s->soc[0].harts[0]; + uint32_t mmu_offset = 0; + uint8_t satp_mode_max; char *isa; AcpiTable table = { .sig = "RHCT", .rev = 1, .oem_id = s->oem_id, @@ -171,6 +173,10 @@ static void build_rhct(GArray *table_data, num_rhct_nodes++; } + if (cpu->cfg.satp_mode.supported != 0) { + num_rhct_nodes++; + } + /* Number of RHCT nodes*/ build_append_int_noprefix(table_data, num_rhct_nodes, 4); @@ -226,6 +232,26 @@ static void build_rhct(GArray *table_data, } } + /* MMU node structure */ + if (cpu->cfg.satp_mode.supported != 0) { + satp_mode_max = satp_mode_max_from_map(cpu->cfg.satp_mode.map); + mmu_offset = table_data->len - table.table_offset; + build_append_int_noprefix(table_data, 2, 2); /* Type */ + build_append_int_noprefix(table_data, 8, 2); /* Length */ + build_append_int_noprefix(table_data, 0x1, 2); /* Revision */ + build_append_int_noprefix(table_data, 0, 1); /* Reserved */ + /* MMU Type */ + if (satp_mode_max == VM_1_10_SV57) { + build_append_int_noprefix(table_data, 2, 1); /* Sv57 */ + } else if (satp_mode_max == VM_1_10_SV48) { + build_append_int_noprefix(table_data, 1, 1); /* Sv48 */ + } else if (satp_mode_max == VM_1_10_SV39) { + build_append_int_noprefix(table_data, 0, 1); /* Sv39 */ + } else { + assert(1); + } + } + /* Hart Info Node */ for (int i = 0; i < arch_ids->len; i++) { len = 16; @@ -238,17 +264,25 @@ static void build_rhct(GArray *table_data, num_offsets++; } + if (mmu_offset) { + len += 4; + num_offsets++; + } + build_append_int_noprefix(table_data, len, 2); build_append_int_noprefix(table_data, 0x1, 2); /* Revision */ /* Number of offsets */ build_append_int_noprefix(table_data, num_offsets, 2); build_append_int_noprefix(table_data, i, 4); /* ACPI Processor UID */ - /* Offsets */ build_append_int_noprefix(table_data, isa_offset, 4); if (cmo_offset) { build_append_int_noprefix(table_data, cmo_offset, 4); } + + if (mmu_offset) { + build_append_int_noprefix(table_data, mmu_offset, 4); + } } acpi_table_end(linker, &table); From 8f6a4874887c226b0df35f5b78fa77f197507d96 Mon Sep 17 00:00:00 2001 From: Sunil V L Date: Mon, 18 Dec 2023 20:32:44 +0530 Subject: [PATCH 21/65] hw/pci-host/gpex: Define properties for MMIO ranges ACPI DSDT generator needs information like ECAM range, PIO range, 32-bit and 64-bit PCI MMIO range etc related to the PCI host bridge. Instead of making these values machine specific, create properties for the GPEX host bridge with default value 0. During initialization, the firmware can initialize these properties with correct values for the platform. This basically allows DSDT generator code independent of the machine specific memory map accesses. Suggested-by: Igor Mammedov Signed-off-by: Sunil V L Acked-by: Alistair Francis Acked-by: Michael S. Tsirkin Reviewed-by: Daniel Henrique Barboza Message-ID: <20231218150247.466427-11-sunilvl@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/pci-host/gpex-acpi.c | 13 +++++++++++++ hw/pci-host/gpex.c | 12 ++++++++++++ include/hw/pci-host/gpex.h | 28 ++++++++++++++++++++-------- 3 files changed, 45 insertions(+), 8 deletions(-) diff --git a/hw/pci-host/gpex-acpi.c b/hw/pci-host/gpex-acpi.c index 1092dc3b70..f69413ea2c 100644 --- a/hw/pci-host/gpex-acpi.c +++ b/hw/pci-host/gpex-acpi.c @@ -281,3 +281,16 @@ void acpi_dsdt_add_gpex(Aml *scope, struct GPEXConfig *cfg) crs_range_set_free(&crs_range_set); } + +void acpi_dsdt_add_gpex_host(Aml *scope, uint32_t irq) +{ + bool ambig; + Object *obj = object_resolve_path_type("", TYPE_GPEX_HOST, &ambig); + + if (!obj || ambig) { + return; + } + + GPEX_HOST(obj)->gpex_cfg.irq = irq; + acpi_dsdt_add_gpex(scope, &GPEX_HOST(obj)->gpex_cfg); +} diff --git a/hw/pci-host/gpex.c b/hw/pci-host/gpex.c index e117e47fa7..e9cf455bf5 100644 --- a/hw/pci-host/gpex.c +++ b/hw/pci-host/gpex.c @@ -154,6 +154,18 @@ static Property gpex_host_properties[] = { */ DEFINE_PROP_BOOL("allow-unmapped-accesses", GPEXHost, allow_unmapped_accesses, true), + DEFINE_PROP_UINT64(PCI_HOST_ECAM_BASE, GPEXHost, gpex_cfg.ecam.base, 0), + DEFINE_PROP_SIZE(PCI_HOST_ECAM_SIZE, GPEXHost, gpex_cfg.ecam.size, 0), + DEFINE_PROP_UINT64(PCI_HOST_PIO_BASE, GPEXHost, gpex_cfg.pio.base, 0), + DEFINE_PROP_SIZE(PCI_HOST_PIO_SIZE, GPEXHost, gpex_cfg.pio.size, 0), + DEFINE_PROP_UINT64(PCI_HOST_BELOW_4G_MMIO_BASE, GPEXHost, + gpex_cfg.mmio32.base, 0), + DEFINE_PROP_SIZE(PCI_HOST_BELOW_4G_MMIO_SIZE, GPEXHost, + gpex_cfg.mmio32.size, 0), + DEFINE_PROP_UINT64(PCI_HOST_ABOVE_4G_MMIO_BASE, GPEXHost, + gpex_cfg.mmio64.base, 0), + DEFINE_PROP_SIZE(PCI_HOST_ABOVE_4G_MMIO_SIZE, GPEXHost, + gpex_cfg.mmio64.size, 0), DEFINE_PROP_END_OF_LIST(), }; diff --git a/include/hw/pci-host/gpex.h b/include/hw/pci-host/gpex.h index b0240bd768..dce883573b 100644 --- a/include/hw/pci-host/gpex.h +++ b/include/hw/pci-host/gpex.h @@ -40,6 +40,15 @@ struct GPEXRootState { /*< public >*/ }; +struct GPEXConfig { + MemMapEntry ecam; + MemMapEntry mmio32; + MemMapEntry mmio64; + MemMapEntry pio; + int irq; + PCIBus *bus; +}; + struct GPEXHost { /*< private >*/ PCIExpressHost parent_obj; @@ -55,19 +64,22 @@ struct GPEXHost { int irq_num[GPEX_NUM_IRQS]; bool allow_unmapped_accesses; -}; -struct GPEXConfig { - MemMapEntry ecam; - MemMapEntry mmio32; - MemMapEntry mmio64; - MemMapEntry pio; - int irq; - PCIBus *bus; + struct GPEXConfig gpex_cfg; }; int gpex_set_irq_num(GPEXHost *s, int index, int gsi); void acpi_dsdt_add_gpex(Aml *scope, struct GPEXConfig *cfg); +void acpi_dsdt_add_gpex_host(Aml *scope, uint32_t irq); + +#define PCI_HOST_PIO_BASE "x-pio-base" +#define PCI_HOST_PIO_SIZE "x-pio-size" +#define PCI_HOST_ECAM_BASE "x-ecam-base" +#define PCI_HOST_ECAM_SIZE "x-ecam-size" +#define PCI_HOST_BELOW_4G_MMIO_BASE "x-below-4g-mmio-base" +#define PCI_HOST_BELOW_4G_MMIO_SIZE "x-below-4g-mmio-size" +#define PCI_HOST_ABOVE_4G_MMIO_BASE "x-above-4g-mmio-base" +#define PCI_HOST_ABOVE_4G_MMIO_SIZE "x-above-4g-mmio-size" #endif /* HW_GPEX_H */ From e86e95270e2b10e57c69852778452b54b31e1c19 Mon Sep 17 00:00:00 2001 From: Sunil V L Date: Mon, 18 Dec 2023 20:32:45 +0530 Subject: [PATCH 22/65] hw/riscv/virt: Update GPEX MMIO related properties Update the GPEX host bridge properties related to MMIO ranges with values set for the virt machine. Suggested-by: Igor Mammedov Signed-off-by: Sunil V L Reviewed-by: Alistair Francis Acked-by: Michael S. Tsirkin Message-ID: <20231218150247.466427-12-sunilvl@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/virt.c | 47 ++++++++++++++++++++++++++++------------- include/hw/riscv/virt.h | 1 + 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 9e7629c51c..a7c4c3508e 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -1054,21 +1054,45 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap) } static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem, - hwaddr ecam_base, hwaddr ecam_size, - hwaddr mmio_base, hwaddr mmio_size, - hwaddr high_mmio_base, - hwaddr high_mmio_size, - hwaddr pio_base, - DeviceState *irqchip) + DeviceState *irqchip, + RISCVVirtState *s) { DeviceState *dev; MemoryRegion *ecam_alias, *ecam_reg; MemoryRegion *mmio_alias, *high_mmio_alias, *mmio_reg; + hwaddr ecam_base = s->memmap[VIRT_PCIE_ECAM].base; + hwaddr ecam_size = s->memmap[VIRT_PCIE_ECAM].size; + hwaddr mmio_base = s->memmap[VIRT_PCIE_MMIO].base; + hwaddr mmio_size = s->memmap[VIRT_PCIE_MMIO].size; + hwaddr high_mmio_base = virt_high_pcie_memmap.base; + hwaddr high_mmio_size = virt_high_pcie_memmap.size; + hwaddr pio_base = s->memmap[VIRT_PCIE_PIO].base; + hwaddr pio_size = s->memmap[VIRT_PCIE_PIO].size; qemu_irq irq; int i; dev = qdev_new(TYPE_GPEX_HOST); + /* Set GPEX object properties for the virt machine */ + object_property_set_uint(OBJECT(GPEX_HOST(dev)), PCI_HOST_ECAM_BASE, + ecam_base, NULL); + object_property_set_int(OBJECT(GPEX_HOST(dev)), PCI_HOST_ECAM_SIZE, + ecam_size, NULL); + object_property_set_uint(OBJECT(GPEX_HOST(dev)), + PCI_HOST_BELOW_4G_MMIO_BASE, + mmio_base, NULL); + object_property_set_int(OBJECT(GPEX_HOST(dev)), PCI_HOST_BELOW_4G_MMIO_SIZE, + mmio_size, NULL); + object_property_set_uint(OBJECT(GPEX_HOST(dev)), + PCI_HOST_ABOVE_4G_MMIO_BASE, + high_mmio_base, NULL); + object_property_set_int(OBJECT(GPEX_HOST(dev)), PCI_HOST_ABOVE_4G_MMIO_SIZE, + high_mmio_size, NULL); + object_property_set_uint(OBJECT(GPEX_HOST(dev)), PCI_HOST_PIO_BASE, + pio_base, NULL); + object_property_set_int(OBJECT(GPEX_HOST(dev)), PCI_HOST_PIO_SIZE, + pio_size, NULL); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); ecam_alias = g_new0(MemoryRegion, 1); @@ -1099,6 +1123,7 @@ static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem, gpex_set_irq_num(GPEX_HOST(dev), i, PCIE_IRQ + i); } + GPEX_HOST(dev)->gpex_cfg.bus = PCI_HOST_BRIDGE(GPEX_HOST(dev))->bus; return dev; } @@ -1494,15 +1519,7 @@ static void virt_machine_init(MachineState *machine) qdev_get_gpio_in(virtio_irqchip, VIRTIO_IRQ + i)); } - gpex_pcie_init(system_memory, - memmap[VIRT_PCIE_ECAM].base, - memmap[VIRT_PCIE_ECAM].size, - memmap[VIRT_PCIE_MMIO].base, - memmap[VIRT_PCIE_MMIO].size, - virt_high_pcie_memmap.base, - virt_high_pcie_memmap.size, - memmap[VIRT_PCIE_PIO].base, - pcie_irqchip); + gpex_pcie_init(system_memory, pcie_irqchip, s); create_platform_bus(s, mmio_irqchip); diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h index 5b03575ed3..f89790fd58 100644 --- a/include/hw/riscv/virt.h +++ b/include/hw/riscv/virt.h @@ -61,6 +61,7 @@ struct RISCVVirtState { char *oem_table_id; OnOffAuto acpi; const MemMapEntry *memmap; + struct GPEXHost *gpex_host; }; enum { From 55ecd83b3697d0e4002c1dfde3265ebe6fa887cc Mon Sep 17 00:00:00 2001 From: Sunil V L Date: Mon, 18 Dec 2023 20:32:46 +0530 Subject: [PATCH 23/65] hw/riscv/virt-acpi-build.c: Add IO controllers and devices Add basic IO controllers and devices like PCI, VirtIO and UART in the ACPI namespace. Signed-off-by: Sunil V L Reviewed-by: Daniel Henrique Barboza Acked-by: Alistair Francis Acked-by: Michael S. Tsirkin Message-ID: <20231218150247.466427-13-sunilvl@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/Kconfig | 1 + hw/riscv/virt-acpi-build.c | 79 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 76 insertions(+), 4 deletions(-) diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index b6a5eb4452..a50717be87 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -45,6 +45,7 @@ config RISCV_VIRT select FW_CFG_DMA select PLATFORM_BUS select ACPI + select ACPI_PCI config SHAKTI_C bool diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c index b7db57b28a..536e6b0243 100644 --- a/hw/riscv/virt-acpi-build.c +++ b/hw/riscv/virt-acpi-build.c @@ -27,15 +27,18 @@ #include "hw/acpi/acpi-defs.h" #include "hw/acpi/acpi.h" #include "hw/acpi/aml-build.h" +#include "hw/acpi/pci.h" #include "hw/acpi/utils.h" +#include "hw/intc/riscv_aclint.h" #include "hw/nvram/fw_cfg_acpi.h" +#include "hw/pci-host/gpex.h" +#include "hw/riscv/virt.h" +#include "hw/riscv/numa.h" +#include "hw/virtio/virtio-acpi.h" +#include "migration/vmstate.h" #include "qapi/error.h" #include "qemu/error-report.h" #include "sysemu/reset.h" -#include "migration/vmstate.h" -#include "hw/riscv/virt.h" -#include "hw/riscv/numa.h" -#include "hw/intc/riscv_aclint.h" #define ACPI_BUILD_TABLE_SIZE 0x20000 #define ACPI_BUILD_INTC_ID(socket, index) ((socket << 24) | (index)) @@ -132,6 +135,39 @@ static void acpi_dsdt_add_cpus(Aml *scope, RISCVVirtState *s) } } +static void +acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap, + uint32_t uart_irq) +{ + Aml *dev = aml_device("COM0"); + aml_append(dev, aml_name_decl("_HID", aml_string("PNP0501"))); + aml_append(dev, aml_name_decl("_UID", aml_int(0))); + + Aml *crs = aml_resource_template(); + aml_append(crs, aml_memory32_fixed(uart_memmap->base, + uart_memmap->size, AML_READ_WRITE)); + aml_append(crs, + aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, + AML_EXCLUSIVE, &uart_irq, 1)); + aml_append(dev, aml_name_decl("_CRS", crs)); + + Aml *pkg = aml_package(2); + aml_append(pkg, aml_string("clock-frequency")); + aml_append(pkg, aml_int(3686400)); + + Aml *UUID = aml_touuid("DAFFD814-6EBA-4D8C-8A91-BC9BBF4AA301"); + + Aml *pkg1 = aml_package(1); + aml_append(pkg1, pkg); + + Aml *package = aml_package(2); + aml_append(package, UUID); + aml_append(package, pkg1); + + aml_append(dev, aml_name_decl("_DSD", package)); + aml_append(scope, dev); +} + /* RHCT Node[N] starts at offset 56 */ #define RHCT_NODE_ARRAY_OFFSET 56 @@ -310,6 +346,8 @@ static void build_dsdt(GArray *table_data, RISCVVirtState *s) { Aml *scope, *dsdt; + MachineState *ms = MACHINE(s); + uint8_t socket_count; const MemMapEntry *memmap = s->memmap; AcpiTable table = { .sig = "DSDT", .rev = 2, .oem_id = s->oem_id, .oem_table_id = s->oem_table_id }; @@ -329,6 +367,29 @@ static void build_dsdt(GArray *table_data, fw_cfg_acpi_dsdt_add(scope, &memmap[VIRT_FW_CFG]); + socket_count = riscv_socket_count(ms); + + acpi_dsdt_add_uart(scope, &memmap[VIRT_UART0], UART0_IRQ); + + if (socket_count == 1) { + virtio_acpi_dsdt_add(scope, memmap[VIRT_VIRTIO].base, + memmap[VIRT_VIRTIO].size, + VIRTIO_IRQ, 0, VIRTIO_COUNT); + acpi_dsdt_add_gpex_host(scope, PCIE_IRQ); + } else if (socket_count == 2) { + virtio_acpi_dsdt_add(scope, memmap[VIRT_VIRTIO].base, + memmap[VIRT_VIRTIO].size, + VIRTIO_IRQ + VIRT_IRQCHIP_NUM_SOURCES, 0, + VIRTIO_COUNT); + acpi_dsdt_add_gpex_host(scope, PCIE_IRQ + VIRT_IRQCHIP_NUM_SOURCES); + } else { + virtio_acpi_dsdt_add(scope, memmap[VIRT_VIRTIO].base, + memmap[VIRT_VIRTIO].size, + VIRTIO_IRQ + VIRT_IRQCHIP_NUM_SOURCES, 0, + VIRTIO_COUNT); + acpi_dsdt_add_gpex_host(scope, PCIE_IRQ + VIRT_IRQCHIP_NUM_SOURCES * 2); + } + aml_append(dsdt, scope); /* copy AML table into ACPI tables blob and patch header there */ @@ -465,6 +526,16 @@ static void virt_acpi_build(RISCVVirtState *s, AcpiBuildTables *tables) acpi_add_table(table_offsets, tables_blob); build_rhct(tables_blob, tables->linker, s); + acpi_add_table(table_offsets, tables_blob); + { + AcpiMcfgInfo mcfg = { + .base = s->memmap[VIRT_PCIE_MMIO].base, + .size = s->memmap[VIRT_PCIE_MMIO].size, + }; + build_mcfg(tables_blob, tables->linker, &mcfg, s->oem_id, + s->oem_table_id); + } + /* XSDT is pointed to by RSDP */ xsdt = tables_blob->len; build_xsdt(tables_blob, tables->linker, table_offsets, s->oem_id, From d641da6ed431f497b763a6e6bf30e0b4dc00e0d9 Mon Sep 17 00:00:00 2001 From: Sunil V L Date: Mon, 18 Dec 2023 20:32:47 +0530 Subject: [PATCH 24/65] hw/riscv/virt-acpi-build.c: Add PLIC in MADT Add PLIC structures for each socket in the MADT when system is configured with PLIC as the external interrupt controller. Signed-off-by: Haibo Xu Signed-off-by: Sunil V L Reviewed-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Acked-by: Alistair Francis Acked-by: Michael S. Tsirkin Message-ID: <20231218150247.466427-14-sunilvl@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/virt-acpi-build.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c index 536e6b0243..26c7e4482d 100644 --- a/hw/riscv/virt-acpi-build.c +++ b/hw/riscv/virt-acpi-build.c @@ -94,6 +94,12 @@ static void riscv_acpi_madt_add_rintc(uint32_t uid, arch_ids->cpus[uid].props.node_id, local_cpu_id), 4); + } else if (s->aia_type == VIRT_AIA_TYPE_NONE) { + build_append_int_noprefix(entry, + ACPI_BUILD_INTC_ID( + arch_ids->cpus[uid].props.node_id, + 2 * local_cpu_id + 1), + 4); } else { build_append_int_noprefix(entry, 0, 4); } @@ -494,6 +500,29 @@ static void build_madt(GArray *table_data, build_append_int_noprefix(table_data, s->memmap[VIRT_APLIC_S].size, 4); } + } else { + /* PLICs */ + for (socket = 0; socket < riscv_socket_count(ms); socket++) { + aplic_addr = s->memmap[VIRT_PLIC].base + + s->memmap[VIRT_PLIC].size * socket; + gsi_base = VIRT_IRQCHIP_NUM_SOURCES * socket; + build_append_int_noprefix(table_data, 0x1B, 1); /* Type */ + build_append_int_noprefix(table_data, 36, 1); /* Length */ + build_append_int_noprefix(table_data, 1, 1); /* Version */ + build_append_int_noprefix(table_data, socket, 1); /* PLIC ID */ + build_append_int_noprefix(table_data, 0, 8); /* Hardware ID */ + /* Total External Interrupt Sources Supported */ + build_append_int_noprefix(table_data, + VIRT_IRQCHIP_NUM_SOURCES - 1, 2); + build_append_int_noprefix(table_data, 0, 2); /* Max Priority */ + build_append_int_noprefix(table_data, 0, 4); /* Flags */ + /* PLIC Size */ + build_append_int_noprefix(table_data, s->memmap[VIRT_PLIC].size, 4); + /* PLIC Address */ + build_append_int_noprefix(table_data, aplic_addr, 8); + /* Global System Interrupt Vector Base */ + build_append_int_noprefix(table_data, gsi_base, 4); + } } acpi_table_end(linker, &table); From ca334e10dcd1f0f3a3c08f8dc3f9945d574d0e6b Mon Sep 17 00:00:00 2001 From: Yong-Xuan Wang Date: Mon, 18 Dec 2023 09:05:40 +0000 Subject: [PATCH 25/65] hw/riscv/virt.c: fix the interrupts-extended property format of PLIC The interrupts-extended property of PLIC only has 2 * hart number fields when KVM enabled, copy 4 * hart number fields to fdt will expose some uninitialized value. In this patch, I also refactor the code about the setting of interrupts-extended property of PLIC for improved readability. Signed-off-by: Yong-Xuan Wang Reviewed-by: Jim Shu Reviewed-by: Daniel Henrique Barboza Message-ID: <20231218090543.22353-1-yongxuan.wang@sifive.com> Signed-off-by: Alistair Francis --- hw/riscv/virt.c | 47 +++++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index a7c4c3508e..4194ddcef1 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -437,24 +437,6 @@ static void create_fdt_socket_plic(RISCVVirtState *s, "sifive,plic-1.0.0", "riscv,plic0" }; - if (kvm_enabled()) { - plic_cells = g_new0(uint32_t, s->soc[socket].num_harts * 2); - } else { - plic_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4); - } - - for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) { - if (kvm_enabled()) { - plic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]); - plic_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_S_EXT); - } else { - plic_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandles[cpu]); - plic_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_EXT); - plic_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandles[cpu]); - plic_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_S_EXT); - } - } - plic_phandles[socket] = (*phandle)++; plic_addr = memmap[VIRT_PLIC].base + (memmap[VIRT_PLIC].size * socket); plic_name = g_strdup_printf("/soc/plic@%lx", plic_addr); @@ -467,8 +449,33 @@ static void create_fdt_socket_plic(RISCVVirtState *s, (char **)&plic_compat, ARRAY_SIZE(plic_compat)); qemu_fdt_setprop(ms->fdt, plic_name, "interrupt-controller", NULL, 0); - qemu_fdt_setprop(ms->fdt, plic_name, "interrupts-extended", - plic_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4); + + if (kvm_enabled()) { + plic_cells = g_new0(uint32_t, s->soc[socket].num_harts * 2); + + for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) { + plic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]); + plic_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_S_EXT); + } + + qemu_fdt_setprop(ms->fdt, plic_name, "interrupts-extended", + plic_cells, + s->soc[socket].num_harts * sizeof(uint32_t) * 2); + } else { + plic_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4); + + for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) { + plic_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandles[cpu]); + plic_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_EXT); + plic_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandles[cpu]); + plic_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_S_EXT); + } + + qemu_fdt_setprop(ms->fdt, plic_name, "interrupts-extended", + plic_cells, + s->soc[socket].num_harts * sizeof(uint32_t) * 4); + } + qemu_fdt_setprop_cells(ms->fdt, plic_name, "reg", 0x0, plic_addr, 0x0, memmap[VIRT_PLIC].size); qemu_fdt_setprop_cell(ms->fdt, plic_name, "riscv,ndev", From b52d49e97fc458f90c2e2f8ee79a20208d68682f Mon Sep 17 00:00:00 2001 From: Weiwei Li Date: Thu, 7 Dec 2023 15:32:30 +0000 Subject: [PATCH 26/65] target/riscv: Add support for Zacas extension Add support for amocas.w/d/q instructions which are part of the ratified Zacas extension: https://github.com/riscv/riscv-zacas Signed-off-by: Weiwei Li Signed-off-by: Junqiang Wang Signed-off-by: Rob Bradford Reviewed-by: Daniel Henrique Barboza Message-ID: <20231207153842.32401-2-rbradford@rivosinc.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 2 + target/riscv/cpu_cfg.h | 1 + target/riscv/insn32.decode | 6 + target/riscv/insn_trans/trans_rvzacas.c.inc | 150 ++++++++++++++++++++ target/riscv/tcg/tcg-cpu.c | 5 + target/riscv/translate.c | 1 + 6 files changed, 165 insertions(+) create mode 100644 target/riscv/insn_trans/trans_rvzacas.c.inc diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 53b82cc581..21b0eddf6f 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -87,6 +87,7 @@ const RISCVIsaExtData isa_edata_arr[] = { 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(zmmul, PRIV_VERSION_1_12_0, ext_zmmul), + ISA_EXT_DATA_ENTRY(zacas, PRIV_VERSION_1_12_0, ext_zacas), ISA_EXT_DATA_ENTRY(zawrs, PRIV_VERSION_1_12_0, ext_zawrs), ISA_EXT_DATA_ENTRY(zfa, PRIV_VERSION_1_12_0, ext_zfa), ISA_EXT_DATA_ENTRY(zfbfmin, PRIV_VERSION_1_12_0, ext_zfbfmin), @@ -1297,6 +1298,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("zacas", ext_zacas, false), MULTI_EXT_CFG_BOOL("zawrs", ext_zawrs, true), MULTI_EXT_CFG_BOOL("zfa", ext_zfa, true), MULTI_EXT_CFG_BOOL("zfh", ext_zfh, false), diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h index f4605fb190..d516de4a44 100644 --- a/target/riscv/cpu_cfg.h +++ b/target/riscv/cpu_cfg.h @@ -77,6 +77,7 @@ struct RISCVCPUConfig { bool ext_svnapot; bool ext_svpbmt; bool ext_zdinx; + bool ext_zacas; bool ext_zawrs; bool ext_zfa; bool ext_zfbfmin; diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 33597fe2bb..f22df04cfd 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -1004,3 +1004,9 @@ vgmul_vv 101000 1 ..... 10001 010 ..... 1110111 @r2_vm_1 vsm4k_vi 100001 1 ..... ..... 010 ..... 1110111 @r_vm_1 vsm4r_vv 101000 1 ..... 10000 010 ..... 1110111 @r2_vm_1 vsm4r_vs 101001 1 ..... 10000 010 ..... 1110111 @r2_vm_1 + +# *** RV32 Zacas Standard Extension *** +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 diff --git a/target/riscv/insn_trans/trans_rvzacas.c.inc b/target/riscv/insn_trans/trans_rvzacas.c.inc new file mode 100644 index 0000000000..5d274d4c08 --- /dev/null +++ b/target/riscv/insn_trans/trans_rvzacas.c.inc @@ -0,0 +1,150 @@ +/* + * RISC-V translation routines for the RV64 Zacas Standard Extension. + * + * Copyright (c) 2020-2023 PLCT Lab + * + * 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_ZACAS(ctx) do { \ + if (!ctx->cfg_ptr->ext_zacas) { \ + return false; \ + } \ +} 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); + return gen_cmpxchg(ctx, a, MO_ALIGN | MO_TESL); +} + +static TCGv_i64 get_gpr_pair(DisasContext *ctx, int reg_num) +{ + TCGv_i64 t; + + assert(get_ol(ctx) == MXL_RV32); + + if (reg_num == 0) { + return tcg_constant_i64(0); + } + + t = tcg_temp_new_i64(); + tcg_gen_concat_tl_i64(t, cpu_gpr[reg_num], cpu_gpr[reg_num + 1]); + return t; +} + +static void gen_set_gpr_pair(DisasContext *ctx, int reg_num, TCGv_i64 t) +{ + assert(get_ol(ctx) == MXL_RV32); + + if (reg_num != 0) { +#ifdef TARGET_RISCV32 + tcg_gen_extr_i64_i32(cpu_gpr[reg_num], cpu_gpr[reg_num + 1], t); +#else + tcg_gen_ext32s_i64(cpu_gpr[reg_num], t); + tcg_gen_sari_i64(cpu_gpr[reg_num + 1], t, 32); +#endif + + if (get_xl_max(ctx) == MXL_RV128) { + tcg_gen_sari_tl(cpu_gprh[reg_num], cpu_gpr[reg_num], 63); + tcg_gen_sari_tl(cpu_gprh[reg_num + 1], cpu_gpr[reg_num + 1], 63); + } + } +} + +static bool gen_cmpxchg64(DisasContext *ctx, arg_atomic *a, MemOp mop) +{ + /* + * Encodings with odd numbered registers specified in rs2 and rd are + * reserved. + */ + if ((a->rs2 | a->rd) & 1) { + return false; + } + + TCGv_i64 dest = get_gpr_pair(ctx, a->rd); + TCGv src1 = get_address(ctx, a->rs1, 0); + TCGv_i64 src2 = get_gpr_pair(ctx, a->rs2); + + decode_save_opc(ctx); + tcg_gen_atomic_cmpxchg_i64(dest, src1, dest, src2, ctx->mem_idx, mop); + + gen_set_gpr_pair(ctx, a->rd, dest); + return true; +} + +static bool trans_amocas_d(DisasContext *ctx, arg_amocas_d *a) +{ + REQUIRE_ZACAS(ctx); + switch (get_ol(ctx)) { + case MXL_RV32: + return gen_cmpxchg64(ctx, a, MO_ALIGN | MO_TEUQ); + case MXL_RV64: + case MXL_RV128: + return gen_cmpxchg(ctx, a, MO_ALIGN | MO_TEUQ); + default: + g_assert_not_reached(); + } +} + +static bool trans_amocas_q(DisasContext *ctx, arg_amocas_q *a) +{ + REQUIRE_ZACAS(ctx); + REQUIRE_64BIT(ctx); + + /* + * Encodings with odd numbered registers specified in rs2 and rd are + * reserved. + */ + if ((a->rs2 | a->rd) & 1) { + return false; + } + +#ifdef TARGET_RISCV64 + TCGv_i128 dest = tcg_temp_new_i128(); + TCGv src1 = get_address(ctx, a->rs1, 0); + TCGv_i128 src2 = tcg_temp_new_i128(); + TCGv_i64 src2l = get_gpr(ctx, a->rs2, EXT_NONE); + TCGv_i64 src2h = get_gpr(ctx, a->rs2 == 0 ? 0 : a->rs2 + 1, EXT_NONE); + TCGv_i64 destl = get_gpr(ctx, a->rd, EXT_NONE); + TCGv_i64 desth = get_gpr(ctx, a->rd == 0 ? 0 : a->rd + 1, EXT_NONE); + + tcg_gen_concat_i64_i128(src2, src2l, src2h); + tcg_gen_concat_i64_i128(dest, destl, desth); + decode_save_opc(ctx); + tcg_gen_atomic_cmpxchg_i128(dest, src1, dest, src2, ctx->mem_idx, + (MO_ALIGN | MO_TEUO)); + + tcg_gen_extr_i128_i64(destl, desth, dest); + + if (a->rd != 0) { + gen_set_gpr(ctx, a->rd, destl); + gen_set_gpr(ctx, a->rd + 1, desth); + } +#endif + + return true; +} diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index 8a35683a34..29b5a88931 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -343,6 +343,11 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) return; } + if ((cpu->cfg.ext_zacas) && !riscv_has_ext(env, RVA)) { + error_setg(errp, "Zacas extension requires A extension"); + return; + } + if ((cpu->cfg.ext_zawrs) && !riscv_has_ext(env, RVA)) { error_setg(errp, "Zawrs extension requires A extension"); return; diff --git a/target/riscv/translate.c b/target/riscv/translate.c index f0be79bb16..071fbad7ef 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -1089,6 +1089,7 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc) #include "insn_trans/trans_rvv.c.inc" #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_rvzawrs.c.inc" #include "insn_trans/trans_rvzicbo.c.inc" #include "insn_trans/trans_rvzfa.c.inc" From 6c848c192e5c1b0dfb952f0ba4c361baa2750753 Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Thu, 7 Dec 2023 15:32:31 +0000 Subject: [PATCH 27/65] disas/riscv: Add amocas.[w,d,q] instructions Signed-off-by: Rob Bradford Reviewed-by: Alistair Francis Reviewed-by: Daniel Henrique Barboza Message-ID: <20231207153842.32401-3-rbradford@rivosinc.com> Signed-off-by: Alistair Francis --- disas/riscv.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/disas/riscv.c b/disas/riscv.c index e9458e574b..8a546d5ea5 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -903,6 +903,9 @@ typedef enum { rv_op_vwsll_vv = 872, rv_op_vwsll_vx = 873, rv_op_vwsll_vi = 874, + rv_op_amocas_w = 875, + rv_op_amocas_d = 876, + rv_op_amocas_q = 877, } rv_op; /* register names */ @@ -2090,6 +2093,9 @@ const rv_opcode_data rvi_opcode_data[] = { { "vwsll.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 }, { "vwsll.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 }, { "vwsll.vi", rv_codec_v_i, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 }, + { "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 }, }; /* CSR names */ @@ -2841,6 +2847,9 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa) 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 42: op = rv_op_amocas_w; break; + case 43: op = rv_op_amocas_d; break; + case 44: op = rv_op_amocas_q; 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; From 60db7a03c4de5452c87893c01ff834ae883d34b1 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 20 Dec 2023 20:34:36 +0100 Subject: [PATCH 28/65] docs/system/riscv: document acpi parameter of virt machine Since QEMU v8.0.0 the RISC-V virt machine has a switch to disable ACPI table generation. Add it to the documentation. Fixes: 168b8c29cedb ("hw/riscv/virt: Add a switch to disable ACPI") Signed-off-by: Heinrich Schuchardt Reviewed-by: Daniel Henrique Barboza Reviewed-by: Sunil V L Reviewed-by: Alistair Francis Message-ID: <20231220193436.25909-1-heinrich.schuchardt@canonical.com> Signed-off-by: Alistair Francis --- docs/system/riscv/virt.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/system/riscv/virt.rst b/docs/system/riscv/virt.rst index f5fa7b8b29..9a06f95a34 100644 --- a/docs/system/riscv/virt.rst +++ b/docs/system/riscv/virt.rst @@ -95,6 +95,11 @@ The following machine-specific options are supported: SiFive CLINT. When not specified, this option is assumed to be "off". This option is restricted to the TCG accelerator. +- acpi=[on|off|auto] + + When this option is "on" (which is the default), ACPI tables are generated and + exposed as firmware tables etc/acpi/rsdp and etc/acpi/tables. + - aia=[none|aplic|aplic-imsic] This option allows selecting interrupt controller defined by the AIA From ee557ad53125a0b35906d828d04de9bbd6e11cf8 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 18 Dec 2023 09:53:09 -0300 Subject: [PATCH 29/65] target/riscv: create TYPE_RISCV_VENDOR_CPU We want to add a new CPU type for bare CPUs that will inherit specific traits of the 2 existing types: - it will allow for extensions to be enabled/disabled, like generic CPUs; - it will NOT inherit defaults, like vendor CPUs. We can make this conditions met by adding an explicit type for the existing vendor CPUs and change the existing logic to not imply that "not generic" means vendor CPUs. Let's add the "vendor" CPU type first. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Message-ID: <20231218125334.37184-2-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu-qom.h | 1 + target/riscv/cpu.c | 30 +++++++++++++++++++++--------- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/target/riscv/cpu-qom.h b/target/riscv/cpu-qom.h index 91b3361dec..ca7dd509e3 100644 --- a/target/riscv/cpu-qom.h +++ b/target/riscv/cpu-qom.h @@ -23,6 +23,7 @@ #define TYPE_RISCV_CPU "riscv-cpu" #define TYPE_RISCV_DYNAMIC_CPU "riscv-dynamic-cpu" +#define TYPE_RISCV_VENDOR_CPU "riscv-vendor-cpu" #define RISCV_CPU_TYPE_SUFFIX "-" TYPE_RISCV_CPU #define RISCV_CPU_TYPE_NAME(name) (name RISCV_CPU_TYPE_SUFFIX) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 21b0eddf6f..bf0235305e 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1748,6 +1748,13 @@ char *riscv_isa_string(RISCVCPU *cpu) .instance_init = initfn \ } +#define DEFINE_VENDOR_CPU(type_name, initfn) \ + { \ + .name = type_name, \ + .parent = TYPE_RISCV_VENDOR_CPU, \ + .instance_init = initfn \ + } + static const TypeInfo riscv_cpu_type_infos[] = { { .name = TYPE_RISCV_CPU, @@ -1765,21 +1772,26 @@ static const TypeInfo riscv_cpu_type_infos[] = { .parent = TYPE_RISCV_CPU, .abstract = true, }, + { + .name = TYPE_RISCV_VENDOR_CPU, + .parent = TYPE_RISCV_CPU, + .abstract = true, + }, DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_ANY, riscv_any_cpu_init), DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_MAX, riscv_max_cpu_init), #if defined(TARGET_RISCV32) DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_BASE32, rv32_base_cpu_init), - DEFINE_CPU(TYPE_RISCV_CPU_IBEX, rv32_ibex_cpu_init), - DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E31, rv32_sifive_e_cpu_init), - DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E34, rv32_imafcu_nommu_cpu_init), - DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U34, rv32_sifive_u_cpu_init), + DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_IBEX, rv32_ibex_cpu_init), + DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SIFIVE_E31, rv32_sifive_e_cpu_init), + DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SIFIVE_E34, rv32_imafcu_nommu_cpu_init), + DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SIFIVE_U34, rv32_sifive_u_cpu_init), #elif defined(TARGET_RISCV64) DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_BASE64, rv64_base_cpu_init), - DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E51, rv64_sifive_e_cpu_init), - DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U54, rv64_sifive_u_cpu_init), - DEFINE_CPU(TYPE_RISCV_CPU_SHAKTI_C, rv64_sifive_u_cpu_init), - DEFINE_CPU(TYPE_RISCV_CPU_THEAD_C906, rv64_thead_c906_cpu_init), - DEFINE_CPU(TYPE_RISCV_CPU_VEYRON_V1, rv64_veyron_v1_cpu_init), + DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SIFIVE_E51, rv64_sifive_e_cpu_init), + DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SIFIVE_U54, rv64_sifive_u_cpu_init), + DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SHAKTI_C, rv64_sifive_u_cpu_init), + DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_THEAD_C906, rv64_thead_c906_cpu_init), + DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_VEYRON_V1, rv64_veyron_v1_cpu_init), DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_BASE128, rv128_base_cpu_init), #endif }; From 7fc37962192edfc64aea22130afc2ca8dd15928e Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 18 Dec 2023 09:53:10 -0300 Subject: [PATCH 30/65] target/riscv/tcg: do not use "!generic" CPU checks Our current logic in get/setters of MISA and multi-letter extensions works because we have only 2 CPU types, generic and vendor, and by using "!generic" we're implying that we're talking about vendor CPUs. When adding a third CPU type this logic will break so let's handle it beforehand. In set_misa_ext_cfg() and set_multi_ext_cfg(), check for "vendor" cpu instead of "not generic". The "generic CPU" checks remaining are from riscv_cpu_add_misa_properties() and cpu_add_multi_ext_prop() before applying default values for the extensions. This leaves us with: - vendor CPUs will not allow extension enablement, all other CPUs will; - generic CPUs will inherit default values for extensions, all others won't. And now we can add a new, third CPU type, that will allow extensions to be enabled and will not inherit defaults, without changing the existing logic. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Message-ID: <20231218125334.37184-3-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/tcg/tcg-cpu.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index 29b5a88931..7174abb7f5 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -668,6 +668,11 @@ static bool riscv_cpu_is_generic(Object *cpu_obj) return object_dynamic_cast(cpu_obj, TYPE_RISCV_DYNAMIC_CPU) != NULL; } +static bool riscv_cpu_is_vendor(Object *cpu_obj) +{ + return object_dynamic_cast(cpu_obj, TYPE_RISCV_VENDOR_CPU) != NULL; +} + /* * We'll get here via the following path: * @@ -736,7 +741,7 @@ static void cpu_set_misa_ext_cfg(Object *obj, Visitor *v, const char *name, target_ulong misa_bit = misa_ext_cfg->misa_bit; RISCVCPU *cpu = RISCV_CPU(obj); CPURISCVState *env = &cpu->env; - bool generic_cpu = riscv_cpu_is_generic(obj); + bool vendor_cpu = riscv_cpu_is_vendor(obj); bool prev_val, value; if (!visit_type_bool(v, name, &value, errp)) { @@ -750,7 +755,7 @@ static void cpu_set_misa_ext_cfg(Object *obj, Visitor *v, const char *name, } if (value) { - if (!generic_cpu) { + if (vendor_cpu) { g_autofree char *cpuname = riscv_cpu_get_name(cpu); error_setg(errp, "'%s' CPU does not allow enabling extensions", cpuname); @@ -855,7 +860,7 @@ static void cpu_set_multi_ext_cfg(Object *obj, Visitor *v, const char *name, { const RISCVCPUMultiExtConfig *multi_ext_cfg = opaque; RISCVCPU *cpu = RISCV_CPU(obj); - bool generic_cpu = riscv_cpu_is_generic(obj); + bool vendor_cpu = riscv_cpu_is_vendor(obj); bool prev_val, value; if (!visit_type_bool(v, name, &value, errp)) { @@ -879,7 +884,7 @@ static void cpu_set_multi_ext_cfg(Object *obj, Visitor *v, const char *name, return; } - if (value && !generic_cpu) { + if (value && vendor_cpu) { g_autofree char *cpuname = riscv_cpu_get_name(cpu); error_setg(errp, "'%s' CPU does not allow enabling extensions", cpuname); From fdcefa91a11073eded85cb73cd7715f072d00f98 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 18 Dec 2023 09:53:11 -0300 Subject: [PATCH 31/65] target/riscv/tcg: update priv_ver on user_set extensions We'll add a new bare CPU type that won't have any default priv_ver. This means that the CPU will default to priv_ver = 0, i.e. 1.10.0. At the same we'll allow these CPUs to enable extensions at will, but then, if the extension has a priv_ver newer than 1.10, we'll end up disabling it. Users will then need to manually set priv_ver to something other than 1.10 to enable the extensions they want, which is not ideal. Change the setter() of extensions to allow user enabled extensions to bump the priv_ver of the CPU. This will make it convenient for users to enable extensions for CPUs that doesn't set a default priv_ver. This change does not affect any existing CPU: vendor CPUs does not allow extensions to be enabled, and generic CPUs are already set to priv_ver LATEST. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Message-ID: <20231218125334.37184-4-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/tcg/tcg-cpu.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index 7174abb7f5..e9f980805e 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -114,6 +114,26 @@ static int cpu_cfg_ext_get_min_version(uint32_t ext_offset) g_assert_not_reached(); } +static void cpu_bump_multi_ext_priv_ver(CPURISCVState *env, + uint32_t ext_offset) +{ + int ext_priv_ver; + + if (env->priv_ver == PRIV_VERSION_LATEST) { + return; + } + + ext_priv_ver = cpu_cfg_ext_get_min_version(ext_offset); + + if (env->priv_ver < ext_priv_ver) { + /* + * Note: the 'priv_spec' command line option, if present, + * will take precedence over this priv_ver bump. + */ + env->priv_ver = ext_priv_ver; + } +} + static void cpu_cfg_ext_auto_update(RISCVCPU *cpu, uint32_t ext_offset, bool value) { @@ -762,6 +782,14 @@ static void cpu_set_misa_ext_cfg(Object *obj, Visitor *v, const char *name, return; } + if (misa_bit == RVH && env->priv_ver < PRIV_VERSION_1_12_0) { + /* + * Note: the 'priv_spec' command line option, if present, + * will take precedence over this priv_ver bump. + */ + env->priv_ver = PRIV_VERSION_1_12_0; + } + env->misa_ext |= misa_bit; env->misa_ext_mask |= misa_bit; } else { @@ -891,6 +919,10 @@ static void cpu_set_multi_ext_cfg(Object *obj, Visitor *v, const char *name, return; } + if (value) { + cpu_bump_multi_ext_priv_ver(&cpu->env, multi_ext_cfg->offset); + } + isa_ext_update_enabled(cpu, multi_ext_cfg->offset, value); } From d379c748a30dce4bc6114111a5d6c0acec9c05a7 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 18 Dec 2023 09:53:12 -0300 Subject: [PATCH 32/65] target/riscv: add rv64i CPU We don't have any form of a 'bare bones' CPU. rv64, our default CPUs, comes with a lot of defaults. This is fine for most regular uses but it's not suitable when more control of what is actually loaded in the CPU is required. A bare-bones CPU would be annoying to deal with if not by profile support, a way to load a multitude of extensions with a single flag. Profile support is going to be implemented shortly, so let's add a CPU for it. The new 'rv64i' CPU will have only RVI loaded. It is inspired in the profile specification that dictates, for RVA22U64 [1]: "RVA22U64 Mandatory Base RV64I is the mandatory base ISA for RVA22U64" And so it seems that RV64I is the mandatory base ISA for all profiles listed in [1], making it an ideal CPU to use with profile support. rv64i is a CPU of type TYPE_RISCV_BARE_CPU. It has a mix of features from pre-existent CPUs: - it allows extensions to be enabled, like generic CPUs; - it will not inherit extension defaults, like vendor CPUs. This is the minimum extension set to boot OpenSBI and buildroot using rv64i: ./build/qemu-system-riscv64 -nographic -M virt \ -cpu rv64i,sv39=true,g=true,c=true,s=true,u=true Our minimal riscv,isa in this case will be: # cat /proc/device-tree/cpus/cpu@0/riscv,isa rv64imafdc_zicntr_zicsr_zifencei_zihpm_zca_zcd# [1] https://github.com/riscv/riscv-profiles/blob/main/profiles.adoc Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Message-ID: <20231218125334.37184-5-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu-qom.h | 2 ++ target/riscv/cpu.c | 46 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/target/riscv/cpu-qom.h b/target/riscv/cpu-qom.h index ca7dd509e3..4d1aa54311 100644 --- a/target/riscv/cpu-qom.h +++ b/target/riscv/cpu-qom.h @@ -24,6 +24,7 @@ #define TYPE_RISCV_CPU "riscv-cpu" #define TYPE_RISCV_DYNAMIC_CPU "riscv-dynamic-cpu" #define TYPE_RISCV_VENDOR_CPU "riscv-vendor-cpu" +#define TYPE_RISCV_BARE_CPU "riscv-bare-cpu" #define RISCV_CPU_TYPE_SUFFIX "-" TYPE_RISCV_CPU #define RISCV_CPU_TYPE_NAME(name) (name RISCV_CPU_TYPE_SUFFIX) @@ -33,6 +34,7 @@ #define TYPE_RISCV_CPU_BASE32 RISCV_CPU_TYPE_NAME("rv32") #define TYPE_RISCV_CPU_BASE64 RISCV_CPU_TYPE_NAME("rv64") #define TYPE_RISCV_CPU_BASE128 RISCV_CPU_TYPE_NAME("x-rv128") +#define TYPE_RISCV_CPU_RV64I RISCV_CPU_TYPE_NAME("rv64i") #define TYPE_RISCV_CPU_IBEX RISCV_CPU_TYPE_NAME("lowrisc-ibex") #define TYPE_RISCV_CPU_SHAKTI_C RISCV_CPU_TYPE_NAME("shakti-c") #define TYPE_RISCV_CPU_SIFIVE_E31 RISCV_CPU_TYPE_NAME("sifive-e31") diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index bf0235305e..33d25d12a6 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -371,6 +371,17 @@ static void set_satp_mode_max_supported(RISCVCPU *cpu, /* Set the satp mode to the max supported */ static void set_satp_mode_default_map(RISCVCPU *cpu) { + /* + * Bare CPUs do not default to the max available. + * Users must set a valid satp_mode in the command + * line. + */ + if (object_dynamic_cast(OBJECT(cpu), TYPE_RISCV_BARE_CPU) != NULL) { + warn_report("No satp mode set. Defaulting to 'bare'"); + cpu->cfg.satp_mode.map = (1 << VM_1_10_MBARE); + return; + } + cpu->cfg.satp_mode.map = cpu->cfg.satp_mode.supported; } #endif @@ -553,6 +564,28 @@ static void rv128_base_cpu_init(Object *obj) set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV57); #endif } + +static void rv64i_bare_cpu_init(Object *obj) +{ + CPURISCVState *env = &RISCV_CPU(obj)->env; + riscv_cpu_set_misa(env, MXL_RV64, RVI); + + /* Remove the defaults from the parent class */ + RISCV_CPU(obj)->cfg.ext_zicntr = false; + RISCV_CPU(obj)->cfg.ext_zihpm = false; + + /* Set to QEMU's first supported priv version */ + env->priv_ver = PRIV_VERSION_1_10_0; + + /* + * Support all available satp_mode settings. The default + * value will be set to MBARE if the user doesn't set + * satp_mode manually (see set_satp_mode_default()). + */ +#ifndef CONFIG_USER_ONLY + set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV64); +#endif +} #else static void rv32_base_cpu_init(Object *obj) { @@ -1755,6 +1788,13 @@ char *riscv_isa_string(RISCVCPU *cpu) .instance_init = initfn \ } +#define DEFINE_BARE_CPU(type_name, initfn) \ + { \ + .name = type_name, \ + .parent = TYPE_RISCV_BARE_CPU, \ + .instance_init = initfn \ + } + static const TypeInfo riscv_cpu_type_infos[] = { { .name = TYPE_RISCV_CPU, @@ -1777,6 +1817,11 @@ static const TypeInfo riscv_cpu_type_infos[] = { .parent = TYPE_RISCV_CPU, .abstract = true, }, + { + .name = TYPE_RISCV_BARE_CPU, + .parent = TYPE_RISCV_CPU, + .abstract = true, + }, DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_ANY, riscv_any_cpu_init), DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_MAX, riscv_max_cpu_init), #if defined(TARGET_RISCV32) @@ -1793,6 +1838,7 @@ static const TypeInfo riscv_cpu_type_infos[] = { DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_THEAD_C906, rv64_thead_c906_cpu_init), DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_VEYRON_V1, rv64_veyron_v1_cpu_init), DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_BASE128, rv128_base_cpu_init), + DEFINE_BARE_CPU(TYPE_RISCV_CPU_RV64I, rv64i_bare_cpu_init), #endif }; From cc2bf69a36e05e22a1dca9bf6305ef5e0cad993e Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 18 Dec 2023 09:53:13 -0300 Subject: [PATCH 33/65] target/riscv: add zicbop extension flag QEMU already implements zicbom (Cache Block Management Operations) and zicboz (Cache Block Zero Operations). Commit 59cb29d6a5 ("target/riscv: add Zicbop cbo.prefetch{i, r, m} placeholder") added placeholders for what would be the instructions for zicbop (Cache Block Prefetch Operations), which are now no-ops. The RVA22U64 profile mandates zicbop, which means that applications that run with this profile might expect zicbop to be present in the riscv,isa DT and might behave badly if it's absent. Adding zicbop as an extension will make our future RVA22U64 implementation more in line with what userspace expects and, if/when cache block prefetch operations became relevant to QEMU, we already have the extension flag to turn then on/off as needed. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Message-ID: <20231218125334.37184-6-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/virt.c | 5 +++++ target/riscv/cpu.c | 3 +++ target/riscv/cpu_cfg.h | 2 ++ 3 files changed, 10 insertions(+) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 4194ddcef1..f9fd1341fc 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -250,6 +250,11 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, cpu_ptr->cfg.cboz_blocksize); } + if (cpu_ptr->cfg.ext_zicbop) { + qemu_fdt_setprop_cell(ms->fdt, cpu_name, "riscv,cbop-block-size", + cpu_ptr->cfg.cbop_blocksize); + } + qemu_fdt_setprop_string(ms->fdt, cpu_name, "compatible", "riscv"); qemu_fdt_setprop_string(ms->fdt, cpu_name, "status", "okay"); qemu_fdt_setprop_cell(ms->fdt, cpu_name, "reg", diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 33d25d12a6..ce0a3ded04 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -78,6 +78,7 @@ const uint32_t misa_bits[] = {RVI, RVE, RVM, RVA, RVF, RVD, RVV, */ const RISCVIsaExtData isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(zicbom, PRIV_VERSION_1_12_0, ext_zicbom), + ISA_EXT_DATA_ENTRY(zicbop, PRIV_VERSION_1_12_0, ext_zicbop), ISA_EXT_DATA_ENTRY(zicboz, PRIV_VERSION_1_12_0, ext_zicboz), ISA_EXT_DATA_ENTRY(zicond, PRIV_VERSION_1_12_0, ext_zicond), ISA_EXT_DATA_ENTRY(zicntr, PRIV_VERSION_1_12_0, ext_zicntr), @@ -1375,6 +1376,7 @@ const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = { MULTI_EXT_CFG_BOOL("zhinxmin", ext_zhinxmin, false), MULTI_EXT_CFG_BOOL("zicbom", ext_zicbom, true), + MULTI_EXT_CFG_BOOL("zicbop", ext_zicbop, true), MULTI_EXT_CFG_BOOL("zicboz", ext_zicboz, true), MULTI_EXT_CFG_BOOL("zmmul", ext_zmmul, false), @@ -1509,6 +1511,7 @@ Property riscv_cpu_options[] = { DEFINE_PROP_UINT16("elen", RISCVCPU, cfg.elen, 64), DEFINE_PROP_UINT16("cbom_blocksize", RISCVCPU, cfg.cbom_blocksize, 64), + DEFINE_PROP_UINT16("cbop_blocksize", RISCVCPU, cfg.cbop_blocksize, 64), DEFINE_PROP_UINT16("cboz_blocksize", RISCVCPU, cfg.cboz_blocksize, 64), DEFINE_PROP_END_OF_LIST(), diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h index d516de4a44..2da8ac9582 100644 --- a/target/riscv/cpu_cfg.h +++ b/target/riscv/cpu_cfg.h @@ -65,6 +65,7 @@ struct RISCVCPUConfig { bool ext_zicntr; bool ext_zicsr; bool ext_zicbom; + bool ext_zicbop; bool ext_zicboz; bool ext_zicond; bool ext_zihintntl; @@ -143,6 +144,7 @@ struct RISCVCPUConfig { uint16_t vlen; uint16_t elen; uint16_t cbom_blocksize; + uint16_t cbop_blocksize; uint16_t cboz_blocksize; bool mmu; bool pmp; From 5fe2800b85fc44ffce749fb03c0ace085bd8a7b8 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 18 Dec 2023 09:53:14 -0300 Subject: [PATCH 34/65] target/riscv/tcg: add 'zic64b' support zic64b is defined in the RVA22U64 profile [1] as a named feature for "Cache blocks must be 64 bytes in size, naturally aligned in the address space". It's a fantasy name for 64 bytes cache blocks. The RVA22U64 profile mandates this feature, meaning that applications using this profile expects 64 bytes cache blocks. To make the upcoming RVA22U64 implementation complete, we'll zic64b as a 'named feature', not a regular extension. This means that: - it won't be exposed to users; - it won't be written in riscv,isa. This will be extended to other named extensions in the future, so we're creating some common boilerplate for them as well. zic64b is default to 'true' since we're already using 64 bytes blocks. If any cache block size (cbo{m,p,z}_blocksize) is changed to something different than 64, zic64b is set to 'false'. Our profile implementation will then be able to check the current state of zic64b and take the appropriate action (e.g. throw a warning). [1] https://github.com/riscv/riscv-profiles/releases/download/v1.0/profiles.pdf Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Message-ID: <20231218125334.37184-7-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 6 ++++++ target/riscv/cpu.h | 1 + target/riscv/cpu_cfg.h | 1 + target/riscv/tcg/tcg-cpu.c | 26 ++++++++++++++++++++++++++ 4 files changed, 34 insertions(+) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index ce0a3ded04..29fdd64298 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1443,6 +1443,12 @@ const RISCVCPUMultiExtConfig riscv_cpu_experimental_exts[] = { DEFINE_PROP_END_OF_LIST(), }; +const RISCVCPUMultiExtConfig riscv_cpu_named_features[] = { + MULTI_EXT_CFG_BOOL("zic64b", zic64b, true), + + DEFINE_PROP_END_OF_LIST(), +}; + /* Deprecated entries marked for future removal */ const RISCVCPUMultiExtConfig riscv_cpu_deprecated_exts[] = { MULTI_EXT_CFG_BOOL("Zifencei", ext_zifencei, true), diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 2725528bb5..bfa42a0393 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -765,6 +765,7 @@ typedef struct RISCVCPUMultiExtConfig { extern const RISCVCPUMultiExtConfig riscv_cpu_extensions[]; extern const RISCVCPUMultiExtConfig riscv_cpu_vendor_exts[]; extern const RISCVCPUMultiExtConfig riscv_cpu_experimental_exts[]; +extern const RISCVCPUMultiExtConfig riscv_cpu_named_features[]; extern const RISCVCPUMultiExtConfig riscv_cpu_deprecated_exts[]; extern Property riscv_cpu_options[]; diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h index 2da8ac9582..350ea44e50 100644 --- a/target/riscv/cpu_cfg.h +++ b/target/riscv/cpu_cfg.h @@ -117,6 +117,7 @@ struct RISCVCPUConfig { bool ext_smepmp; bool rvv_ta_all_1s; bool rvv_ma_all_1s; + bool zic64b; uint32_t mvendorid; uint64_t marchid; diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index e9f980805e..f12e0620e5 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -114,6 +114,19 @@ static int cpu_cfg_ext_get_min_version(uint32_t ext_offset) g_assert_not_reached(); } +static bool cpu_cfg_offset_is_named_feat(uint32_t ext_offset) +{ + const RISCVCPUMultiExtConfig *feat; + + for (feat = riscv_cpu_named_features; feat->name != NULL; feat++) { + if (feat->offset == ext_offset) { + return true; + } + } + + return false; +} + static void cpu_bump_multi_ext_priv_ver(CPURISCVState *env, uint32_t ext_offset) { @@ -123,6 +136,10 @@ static void cpu_bump_multi_ext_priv_ver(CPURISCVState *env, return; } + if (cpu_cfg_offset_is_named_feat(ext_offset)) { + return; + } + ext_priv_ver = cpu_cfg_ext_get_min_version(ext_offset); if (env->priv_ver < ext_priv_ver) { @@ -293,6 +310,13 @@ static void riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU *cpu) } } +static void riscv_cpu_update_named_features(RISCVCPU *cpu) +{ + cpu->cfg.zic64b = cpu->cfg.cbom_blocksize == 64 && + cpu->cfg.cbop_blocksize == 64 && + cpu->cfg.cboz_blocksize == 64; +} + /* * Check consistency between chosen extensions while setting * cpu->cfg accordingly. @@ -662,6 +686,8 @@ void riscv_tcg_cpu_finalize_features(RISCVCPU *cpu, Error **errp) return; } + riscv_cpu_update_named_features(cpu); + if (cpu->cfg.ext_smepmp && !cpu->cfg.pmp) { /* * Enhanced PMP should only be available From a88154835ac23e1098b3dabc1142253f034c36a6 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 18 Dec 2023 09:53:15 -0300 Subject: [PATCH 35/65] riscv-qmp-cmds.c: expose named features in cpu_model_expansion Named features (zic64b the sole example at this moment) aren't expose to users, thus we need another way to expose them. Go through each named feature, get its boolean value, do the needed conversions (bool to qbool, qbool to QObject) and add it to output dict. Another adjustment is needed: named features are evaluated during finalize(), so riscv_cpu_finalize_features() needs to be mandatory regardless of whether we have an input dict or not. Otherwise zic64b will always return 'false', which is incorrect: the default values of cache blocksizes ([cbom/cbop/cboz]_blocksize) are set to 64, satisfying the conditions for zic64b. Here's an API usage example after this patch: $ ./build/qemu-system-riscv64 -S -M virt -display none -qmp tcp:localhost:1234,server,wait=off $ ./scripts/qmp/qmp-shell localhost:1234 Welcome to the QMP low-level shell! Connected to QEMU 8.1.50 (QEMU) query-cpu-model-expansion type=full model={"name":"rv64"} {"return": {"model": {"name": "rv64", "props": {... "zic64b": true, ...}}}} zic64b is set to 'true', as expected, since all cache sizes are 64 bytes by default. If we change one of the cache blocksizes, zic64b is returned as 'false': (QEMU) query-cpu-model-expansion type=full model={"name":"rv64","props":{"cbom_blocksize":128}} {"return": {"model": {"name": "rv64", "props": {... "zic64b": false, ...}}}} Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Message-ID: <20231218125334.37184-8-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/riscv-qmp-cmds.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/target/riscv/riscv-qmp-cmds.c b/target/riscv/riscv-qmp-cmds.c index c5551d2cfe..35f2b21163 100644 --- a/target/riscv/riscv-qmp-cmds.c +++ b/target/riscv/riscv-qmp-cmds.c @@ -26,6 +26,7 @@ #include "qapi/error.h" #include "qapi/qapi-commands-machine-target.h" +#include "qapi/qmp/qbool.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qerror.h" #include "qapi/qobject-input-visitor.h" @@ -98,6 +99,22 @@ static void riscv_obj_add_multiext_props(Object *obj, QDict *qdict_out, } } +static void riscv_obj_add_named_feats_qdict(Object *obj, QDict *qdict_out) +{ + const RISCVCPUMultiExtConfig *named_cfg; + RISCVCPU *cpu = RISCV_CPU(obj); + QObject *value; + bool flag_val; + + for (int i = 0; riscv_cpu_named_features[i].name != NULL; i++) { + named_cfg = &riscv_cpu_named_features[i]; + flag_val = isa_ext_is_enabled(cpu, named_cfg->offset); + value = QOBJECT(qbool_from_bool(flag_val)); + + qdict_put_obj(qdict_out, named_cfg->name, value); + } +} + static void riscv_cpuobj_validate_qdict_in(Object *obj, QObject *props, const QDict *qdict_in, Error **errp) @@ -128,11 +145,6 @@ static void riscv_cpuobj_validate_qdict_in(Object *obj, QObject *props, goto err; } - riscv_cpu_finalize_features(RISCV_CPU(obj), &local_err); - if (local_err) { - goto err; - } - visit_end_struct(visitor, NULL); err: @@ -190,6 +202,13 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type, } } + riscv_cpu_finalize_features(RISCV_CPU(obj), &local_err); + if (local_err) { + error_propagate(errp, local_err); + object_unref(obj); + return NULL; + } + expansion_info = g_new0(CpuModelExpansionInfo, 1); expansion_info->model = g_malloc0(sizeof(*expansion_info->model)); expansion_info->model->name = g_strdup(model->name); @@ -199,6 +218,7 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type, riscv_obj_add_multiext_props(obj, qdict_out, riscv_cpu_extensions); riscv_obj_add_multiext_props(obj, qdict_out, riscv_cpu_experimental_exts); riscv_obj_add_multiext_props(obj, qdict_out, riscv_cpu_vendor_exts); + riscv_obj_add_named_feats_qdict(obj, qdict_out); /* Add our CPU boolean options too */ riscv_obj_add_qdict_prop(obj, qdict_out, "mmu"); From 3f3618474a3ecd4799be58cafc34eb36f95657a2 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 18 Dec 2023 09:53:16 -0300 Subject: [PATCH 36/65] target/riscv: add rva22u64 profile definition The rva22U64 profile, described in: https://github.com/riscv/riscv-profiles/blob/main/profiles.adoc#rva22-profiles Contains a set of CPU extensions aimed for 64-bit userspace applications. Enabling this set to be enabled via a single user flag makes it convenient to enable a predictable set of features for the CPU, giving users more predicability when running/testing their workloads. QEMU implements all possible extensions of this profile. All the so called 'synthetic extensions' described in the profile that are cache related are ignored/assumed enabled (Za64rs, Zic64b, Ziccif, Ziccrse, Ziccamoa, Zicclsm) since we do not implement a cache model. An abstraction called RISCVCPUProfile is created to store the profile. 'ext_offsets' contains mandatory extensions that QEMU supports. Same thing with the 'misa_ext' mask. Optional extensions must be enabled manually in the command line if desired. The design here is to use the common target/riscv/cpu.c file to store the profile declaration and export it to the accelerator files. Each accelerator is then responsible to expose it (or not) to users and how to enable the extensions. Next patches will implement the profile for TCG and KVM. Signed-off-by: Daniel Henrique Barboza Acked-by: Alistair Francis Reviewed-by: Andrew Jones Message-ID: <20231218125334.37184-9-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 32 ++++++++++++++++++++++++++++++++ target/riscv/cpu.h | 12 ++++++++++++ 2 files changed, 44 insertions(+) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 29fdd64298..199b581380 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1523,6 +1523,38 @@ Property riscv_cpu_options[] = { DEFINE_PROP_END_OF_LIST(), }; +/* + * RVA22U64 defines some 'named features' or 'synthetic extensions' + * that are cache related: Za64rs, Zic64b, Ziccif, Ziccrse, Ziccamoa + * and Zicclsm. We do not implement caching in QEMU so we'll consider + * all these named features as always enabled. + * + * There's no riscv,isa update for them (nor for zic64b, despite it + * having a cfg offset) at this moment. + */ +static RISCVCPUProfile RVA22U64 = { + .name = "rva22u64", + .misa_ext = RVI | RVM | RVA | RVF | RVD | RVC | RVU, + .ext_offsets = { + CPU_CFG_OFFSET(ext_zicsr), CPU_CFG_OFFSET(ext_zihintpause), + CPU_CFG_OFFSET(ext_zba), CPU_CFG_OFFSET(ext_zbb), + CPU_CFG_OFFSET(ext_zbs), CPU_CFG_OFFSET(ext_zfhmin), + CPU_CFG_OFFSET(ext_zkt), CPU_CFG_OFFSET(ext_zicntr), + CPU_CFG_OFFSET(ext_zihpm), CPU_CFG_OFFSET(ext_zicbom), + CPU_CFG_OFFSET(ext_zicbop), CPU_CFG_OFFSET(ext_zicboz), + + /* mandatory named features for this profile */ + CPU_CFG_OFFSET(zic64b), + + RISCV_PROFILE_EXT_LIST_END + } +}; + +RISCVCPUProfile *riscv_profiles[] = { + &RVA22U64, + NULL, +}; + static Property riscv_cpu_properties[] = { DEFINE_PROP_BOOL("debug", RISCVCPU, cfg.debug, true), diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index bfa42a0393..5af1666dc0 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -76,6 +76,18 @@ const char *riscv_get_misa_ext_description(uint32_t bit); #define CPU_CFG_OFFSET(_prop) offsetof(struct RISCVCPUConfig, _prop) +typedef struct riscv_cpu_profile { + const char *name; + uint32_t misa_ext; + bool enabled; + bool user_set; + const int32_t ext_offsets[]; +} RISCVCPUProfile; + +#define RISCV_PROFILE_EXT_LIST_END -1 + +extern RISCVCPUProfile *riscv_profiles[]; + /* Privileged specification version */ enum { PRIV_VERSION_1_10_0 = 0, From 1a567c5cff36ae3a864fa534bf76711398eba4f1 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 18 Dec 2023 09:53:17 -0300 Subject: [PATCH 37/65] target/riscv/kvm: add 'rva22u64' flag as unavailable KVM does not have the means to support enabling the rva22u64 profile. The main reasons are: - we're missing support for some mandatory rva22u64 extensions in the KVM module; - we can't make promises about enabling a profile since it all depends on host support in the end. We'll revisit this decision in the future if needed. For now mark the 'rva22u64' profile as unavailable when running a KVM CPU: $ qemu-system-riscv64 -machine virt,accel=kvm -cpu rv64,rva22u64=true qemu-system-riscv64: can't apply global rv64-riscv-cpu.rva22u64=true: 'rva22u64' is not available with KVM Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Reviewed-by: LIU Zhiwei Reviewed-by: Andrew Jones Message-ID: <20231218125334.37184-10-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/kvm/kvm-cpu.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index a31df6e273..2c5217102c 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -414,7 +414,7 @@ static void cpu_set_cfg_unavailable(Object *obj, Visitor *v, } if (value) { - error_setg(errp, "extension %s is not available with KVM", + error_setg(errp, "'%s' is not available with KVM", propname); } } @@ -495,6 +495,11 @@ static void kvm_riscv_add_cpu_user_properties(Object *cpu_obj) riscv_cpu_add_kvm_unavail_prop_array(cpu_obj, riscv_cpu_extensions); riscv_cpu_add_kvm_unavail_prop_array(cpu_obj, riscv_cpu_vendor_exts); riscv_cpu_add_kvm_unavail_prop_array(cpu_obj, riscv_cpu_experimental_exts); + + /* We don't have the needed KVM support for profiles */ + for (i = 0; riscv_profiles[i] != NULL; i++) { + riscv_cpu_add_kvm_unavail_prop(cpu_obj, riscv_profiles[i]->name); + } } static int kvm_riscv_get_regs_core(CPUState *cs) From b30ea1677b463fba80daec4e2c6f936e0042cae2 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 18 Dec 2023 09:53:18 -0300 Subject: [PATCH 38/65] target/riscv/tcg: add user flag for profile support The TCG emulation implements all the extensions described in the RVA22U64 profile, both mandatory and optional. The mandatory extensions will be enabled via the profile flag. We'll leave the optional extensions to be enabled by hand. Given that this is the first profile we're implementing in TCG we'll need some ground work first: - all profiles declared in riscv_profiles[] will be exposed to users. TCG is the main accelerator we're considering when adding profile support in QEMU, so for now it's safe to assume that all profiles in riscv_profiles[] will be relevant to TCG; - we'll not support user profile settings for vendor CPUs. The flags will still be exposed but users won't be able to change them; - profile support, albeit available for all non-vendor CPUs, will be based on top of the new 'rv64i' CPU. Setting a profile to 'true' means enable all mandatory extensions of this profile, setting it to 'false' will disable all mandatory profile extensions of the CPU, which will obliterate preset defaults. This is not a problem for a bare CPU like rv64i but it can allow for silly scenarios when using other CPUs. E.g. an user can do "-cpu rv64,rva22u64=false" and have a bunch of default rv64 extensions disabled. The recommended way of using profiles is the rv64i CPU, but users are free to experiment. For now we'll handle multi-letter extensions only. MISA extensions need additional steps that we'll take care later. At this point we can boot a Linux buildroot using rva22u64 using the following options: -cpu rv64i,rva22u64=true,sv39=true,g=true,c=true,s=true Note that being an usermode/application profile we still need to explicitly set 's=true' to enable Supervisor mode to boot Linux. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Message-ID: <20231218125334.37184-11-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/tcg/tcg-cpu.c | 80 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index f12e0620e5..9234254772 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -127,6 +127,19 @@ static bool cpu_cfg_offset_is_named_feat(uint32_t ext_offset) return false; } +static void riscv_cpu_enable_named_feat(RISCVCPU *cpu, uint32_t feat_offset) +{ + switch (feat_offset) { + case CPU_CFG_OFFSET(zic64b): + cpu->cfg.cbom_blocksize = 64; + cpu->cfg.cbop_blocksize = 64; + cpu->cfg.cboz_blocksize = 64; + break; + default: + g_assert_not_reached(); + } +} + static void cpu_bump_multi_ext_priv_ver(CPURISCVState *env, uint32_t ext_offset) { @@ -890,6 +903,71 @@ static void riscv_cpu_add_misa_properties(Object *cpu_obj) } } +static void cpu_set_profile(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + RISCVCPUProfile *profile = opaque; + RISCVCPU *cpu = RISCV_CPU(obj); + bool value; + int i, ext_offset; + + if (riscv_cpu_is_vendor(obj)) { + error_setg(errp, "Profile %s is not available for vendor CPUs", + profile->name); + return; + } + + if (cpu->env.misa_mxl != MXL_RV64) { + error_setg(errp, "Profile %s only available for 64 bit CPUs", + profile->name); + return; + } + + if (!visit_type_bool(v, name, &value, errp)) { + return; + } + + profile->user_set = true; + profile->enabled = value; + + for (i = 0; profile->ext_offsets[i] != RISCV_PROFILE_EXT_LIST_END; i++) { + ext_offset = profile->ext_offsets[i]; + + if (profile->enabled) { + if (cpu_cfg_offset_is_named_feat(ext_offset)) { + riscv_cpu_enable_named_feat(cpu, ext_offset); + } + + cpu_bump_multi_ext_priv_ver(&cpu->env, ext_offset); + } + + g_hash_table_insert(multi_ext_user_opts, + GUINT_TO_POINTER(ext_offset), + (gpointer)profile->enabled); + isa_ext_update_enabled(cpu, ext_offset, profile->enabled); + } +} + +static void cpu_get_profile(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + RISCVCPUProfile *profile = opaque; + bool value = profile->enabled; + + visit_type_bool(v, name, &value, errp); +} + +static void riscv_cpu_add_profiles(Object *cpu_obj) +{ + for (int i = 0; riscv_profiles[i] != NULL; i++) { + const RISCVCPUProfile *profile = riscv_profiles[i]; + + object_property_add(cpu_obj, profile->name, "bool", + cpu_get_profile, cpu_set_profile, + NULL, (void *)profile); + } +} + static bool cpu_ext_is_deprecated(const char *ext_name) { return isupper(ext_name[0]); @@ -1017,6 +1095,8 @@ static void riscv_cpu_add_user_properties(Object *obj) riscv_cpu_add_multiext_prop_array(obj, riscv_cpu_deprecated_exts); + riscv_cpu_add_profiles(obj); + for (Property *prop = riscv_cpu_options; prop && prop->name; prop++) { qdev_property_add_static(DEVICE(obj), prop); } From 21915d16c6fbe857773cc9e10badb3e29cd7194a Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 18 Dec 2023 09:53:19 -0300 Subject: [PATCH 39/65] target/riscv/tcg: add MISA user options hash We already track user choice for multi-letter extensions because we needed to honor user choice when enabling/disabling extensions during realize(). We refrained from adding the same mechanism for MISA extensions since we didn't need it. Profile support requires tne need to check for user choice for MISA extensions, so let's add the corresponding hash now. It works like the existing multi-letter hash (multi_ext_user_opts) but tracking MISA bits options in the cpu_set_misa_ext_cfg() callback. Note that we can't re-use the same hash from multi-letter extensions because that hash uses cpu->cfg offsets as keys, while for MISA extensions we're using MISA bits as keys. After adding the user hash in cpu_set_misa_ext_cfg(), setting default values with object_property_set_bool() in add_misa_properties() will end up marking the user choice hash with them. Set the default value manually to avoid it. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Reviewed-by: LIU Zhiwei Reviewed-by: Andrew Jones Message-ID: <20231218125334.37184-12-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/tcg/tcg-cpu.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index 9234254772..731ec2279e 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -34,6 +34,7 @@ /* Hash that stores user set extensions */ static GHashTable *multi_ext_user_opts; +static GHashTable *misa_ext_user_opts; static bool cpu_cfg_ext_is_user_set(uint32_t ext_offset) { @@ -807,6 +808,10 @@ static void cpu_set_misa_ext_cfg(Object *obj, Visitor *v, const char *name, return; } + g_hash_table_insert(misa_ext_user_opts, + GUINT_TO_POINTER(misa_bit), + (gpointer)value); + prev_val = env->misa_ext & misa_bit; if (value == prev_val) { @@ -878,6 +883,7 @@ static const RISCVCPUMisaExtConfig misa_ext_cfgs[] = { */ static void riscv_cpu_add_misa_properties(Object *cpu_obj) { + CPURISCVState *env = &RISCV_CPU(cpu_obj)->env; bool use_def_vals = riscv_cpu_is_generic(cpu_obj); int i; @@ -898,7 +904,13 @@ static void riscv_cpu_add_misa_properties(Object *cpu_obj) NULL, (void *)misa_cfg); object_property_set_description(cpu_obj, name, desc); if (use_def_vals) { - object_property_set_bool(cpu_obj, name, misa_cfg->enabled, NULL); + if (misa_cfg->enabled) { + env->misa_ext |= bit; + env->misa_ext_mask |= bit; + } else { + env->misa_ext &= ~bit; + env->misa_ext_mask &= ~bit; + } } } } @@ -1147,6 +1159,7 @@ static void tcg_cpu_instance_init(CPUState *cs) RISCVCPU *cpu = RISCV_CPU(cs); Object *obj = OBJECT(cpu); + misa_ext_user_opts = g_hash_table_new(NULL, g_direct_equal); multi_ext_user_opts = g_hash_table_new(NULL, g_direct_equal); riscv_cpu_add_user_properties(obj); From a8c31f935ceb55ab1fa771af44a5f873b65abc77 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 18 Dec 2023 09:53:20 -0300 Subject: [PATCH 40/65] target/riscv/tcg: add riscv_cpu_write_misa_bit() We have two instances of the setting/clearing a MISA bit from env->misa_ext and env->misa_ext_mask pattern. And the next patch will end up adding one more. Create a helper to avoid code repetition. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Reviewed-by: LIU Zhiwei Reviewed-by: Andrew Jones Message-ID: <20231218125334.37184-13-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/tcg/tcg-cpu.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index 731ec2279e..dd8f49b2a6 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -42,6 +42,20 @@ static bool cpu_cfg_ext_is_user_set(uint32_t ext_offset) GUINT_TO_POINTER(ext_offset)); } +static void riscv_cpu_write_misa_bit(RISCVCPU *cpu, uint32_t bit, + bool enabled) +{ + CPURISCVState *env = &cpu->env; + + if (enabled) { + env->misa_ext |= bit; + env->misa_ext_mask |= bit; + } else { + env->misa_ext &= ~bit; + env->misa_ext_mask &= ~bit; + } +} + static void riscv_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb) { @@ -833,13 +847,9 @@ static void cpu_set_misa_ext_cfg(Object *obj, Visitor *v, const char *name, */ env->priv_ver = PRIV_VERSION_1_12_0; } - - env->misa_ext |= misa_bit; - env->misa_ext_mask |= misa_bit; - } else { - env->misa_ext &= ~misa_bit; - env->misa_ext_mask &= ~misa_bit; } + + riscv_cpu_write_misa_bit(cpu, misa_bit, value); } static void cpu_get_misa_ext_cfg(Object *obj, Visitor *v, const char *name, @@ -883,7 +893,6 @@ static const RISCVCPUMisaExtConfig misa_ext_cfgs[] = { */ static void riscv_cpu_add_misa_properties(Object *cpu_obj) { - CPURISCVState *env = &RISCV_CPU(cpu_obj)->env; bool use_def_vals = riscv_cpu_is_generic(cpu_obj); int i; @@ -904,13 +913,8 @@ static void riscv_cpu_add_misa_properties(Object *cpu_obj) NULL, (void *)misa_cfg); object_property_set_description(cpu_obj, name, desc); if (use_def_vals) { - if (misa_cfg->enabled) { - env->misa_ext |= bit; - env->misa_ext_mask |= bit; - } else { - env->misa_ext &= ~bit; - env->misa_ext_mask &= ~bit; - } + riscv_cpu_write_misa_bit(RISCV_CPU(cpu_obj), bit, + misa_cfg->enabled); } } } From 3ba8462c4ca55720239fdc6fa30b9870d22a8814 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 18 Dec 2023 09:53:21 -0300 Subject: [PATCH 41/65] target/riscv/tcg: handle profile MISA bits The profile support is handling multi-letter extensions only. Let's add support for MISA bits as well. We'll go through every known MISA bit. If the profile doesn't declare the bit as mandatory, ignore it. Otherwise, set the bit in env->misa_ext and env->misa_ext_mask. Now that we're setting profile MISA bits, one can use the rv64i CPU to boot Linux using the following options: -cpu rv64i,rva22u64=true,rv39=true,s=true,zifencei=true In the near future, when rva22s64 (where, 's', 'zifencei' and sv39 are mandatory), is implemented, rv64i will be able to boot Linux loading rva22s64 and no additional flags. Signed-off-by: Daniel Henrique Barboza Reviewed-by: LIU Zhiwei Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Message-ID: <20231218125334.37184-14-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/tcg/tcg-cpu.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index dd8f49b2a6..9fba3e8143 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -946,6 +946,27 @@ static void cpu_set_profile(Object *obj, Visitor *v, const char *name, profile->user_set = true; profile->enabled = value; + for (i = 0; misa_bits[i] != 0; i++) { + uint32_t bit = misa_bits[i]; + + if (!(profile->misa_ext & bit)) { + continue; + } + + if (bit == RVI && !profile->enabled) { + /* + * Disabling profiles will not disable the base + * ISA RV64I. + */ + continue; + } + + g_hash_table_insert(misa_ext_user_opts, + GUINT_TO_POINTER(bit), + (gpointer)value); + riscv_cpu_write_misa_bit(cpu, bit, profile->enabled); + } + for (i = 0; profile->ext_offsets[i] != RISCV_PROFILE_EXT_LIST_END; i++) { ext_offset = profile->ext_offsets[i]; From 5187ba5b3067679f4b9c4bb80e16dfdac3bf61fc Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 18 Dec 2023 09:53:22 -0300 Subject: [PATCH 42/65] target/riscv/tcg: add hash table insert helpers Previous patches added several g_hash_table_insert() patterns. Add two helpers, one for each user hash, to make the code cleaner. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Message-ID: <20231218125334.37184-15-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/tcg/tcg-cpu.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index 9fba3e8143..f1eeaa12b9 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -42,6 +42,18 @@ static bool cpu_cfg_ext_is_user_set(uint32_t ext_offset) GUINT_TO_POINTER(ext_offset)); } +static void cpu_cfg_ext_add_user_opt(uint32_t ext_offset, bool value) +{ + g_hash_table_insert(multi_ext_user_opts, GUINT_TO_POINTER(ext_offset), + (gpointer)value); +} + +static void cpu_misa_ext_add_user_opt(uint32_t bit, bool value) +{ + g_hash_table_insert(misa_ext_user_opts, GUINT_TO_POINTER(bit), + (gpointer)value); +} + static void riscv_cpu_write_misa_bit(RISCVCPU *cpu, uint32_t bit, bool enabled) { @@ -822,9 +834,7 @@ static void cpu_set_misa_ext_cfg(Object *obj, Visitor *v, const char *name, return; } - g_hash_table_insert(misa_ext_user_opts, - GUINT_TO_POINTER(misa_bit), - (gpointer)value); + cpu_misa_ext_add_user_opt(misa_bit, value); prev_val = env->misa_ext & misa_bit; @@ -961,9 +971,7 @@ static void cpu_set_profile(Object *obj, Visitor *v, const char *name, continue; } - g_hash_table_insert(misa_ext_user_opts, - GUINT_TO_POINTER(bit), - (gpointer)value); + cpu_misa_ext_add_user_opt(bit, profile->enabled); riscv_cpu_write_misa_bit(cpu, bit, profile->enabled); } @@ -978,9 +986,7 @@ static void cpu_set_profile(Object *obj, Visitor *v, const char *name, cpu_bump_multi_ext_priv_ver(&cpu->env, ext_offset); } - g_hash_table_insert(multi_ext_user_opts, - GUINT_TO_POINTER(ext_offset), - (gpointer)profile->enabled); + cpu_cfg_ext_add_user_opt(ext_offset, profile->enabled); isa_ext_update_enabled(cpu, ext_offset, profile->enabled); } } @@ -1043,9 +1049,7 @@ static void cpu_set_multi_ext_cfg(Object *obj, Visitor *v, const char *name, multi_ext_cfg->name, lower); } - g_hash_table_insert(multi_ext_user_opts, - GUINT_TO_POINTER(multi_ext_cfg->offset), - (gpointer)value); + cpu_cfg_ext_add_user_opt(multi_ext_cfg->offset, value); prev_val = isa_ext_is_enabled(cpu, multi_ext_cfg->offset); From 8b3b3451052cd7a115c9352de1bb8c74ee54a62e Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 18 Dec 2023 09:53:23 -0300 Subject: [PATCH 43/65] target/riscv/tcg: honor user choice for G MISA bits RVG behaves like a profile: a single flag enables a set of bits. Right now we're considering user choice when handling RVG and zicsr/zifencei and ignoring user choice on MISA bits. We'll add user warnings for profiles when the user disables its mandatory extensions in the next patch. We'll do the same thing with RVG now to keep consistency between RVG and profile handling. First and foremost, create a new RVG only helper to avoid clogging riscv_cpu_validate_set_extensions(). We do not want to annoy users with RVG warnings like we did in the past (see 9b9741c38f), thus we'll only warn if RVG was user set and the user disabled a RVG extension in the command line. For every RVG MISA bit (IMAFD), zicsr and zifencei, the logic then becomes: - if enabled, do nothing; - if disabled and not user set, enable it; - if disabled and user set, throw a warning that it's a RVG mandatory extension. This same logic will be used for profiles in the next patch. Note that this is a behavior change, where we would error out if the user disabled either zicsr or zifencei. As long as users are explicitly disabling things in the command line we'll let them have a go at it, at least in this step. We'll error out later in the validation if needed. Other notable changes from the previous RVG code: - use riscv_cpu_write_misa_bit() instead of manually updating both env->misa_ext and env->misa_ext_mask; - set zicsr and zifencei directly. We're already checking if they were user set and priv version will never fail for these extensions, making cpu_cfg_ext_auto_update() redundant. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Message-ID: <20231218125334.37184-16-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/tcg/tcg-cpu.c | 73 +++++++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 25 deletions(-) diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index f1eeaa12b9..d2a42a347b 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -42,6 +42,12 @@ static bool cpu_cfg_ext_is_user_set(uint32_t ext_offset) GUINT_TO_POINTER(ext_offset)); } +static bool cpu_misa_ext_is_user_set(uint32_t misa_bit) +{ + return g_hash_table_contains(misa_ext_user_opts, + GUINT_TO_POINTER(misa_bit)); +} + static void cpu_cfg_ext_add_user_opt(uint32_t ext_offset, bool value) { g_hash_table_insert(multi_ext_user_opts, GUINT_TO_POINTER(ext_offset), @@ -357,6 +363,46 @@ static void riscv_cpu_update_named_features(RISCVCPU *cpu) cpu->cfg.cboz_blocksize == 64; } +static void riscv_cpu_validate_g(RISCVCPU *cpu) +{ + const char *warn_msg = "RVG mandates disabled extension %s"; + uint32_t g_misa_bits[] = {RVI, RVM, RVA, RVF, RVD}; + bool send_warn = cpu_misa_ext_is_user_set(RVG); + + for (int i = 0; i < ARRAY_SIZE(g_misa_bits); i++) { + uint32_t bit = g_misa_bits[i]; + + if (riscv_has_ext(&cpu->env, bit)) { + continue; + } + + if (!cpu_misa_ext_is_user_set(bit)) { + riscv_cpu_write_misa_bit(cpu, bit, true); + continue; + } + + if (send_warn) { + warn_report(warn_msg, riscv_get_misa_ext_name(bit)); + } + } + + if (!cpu->cfg.ext_zicsr) { + if (!cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_zicsr))) { + cpu->cfg.ext_zicsr = true; + } else if (send_warn) { + warn_report(warn_msg, "zicsr"); + } + } + + if (!cpu->cfg.ext_zifencei) { + if (!cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_zifencei))) { + cpu->cfg.ext_zifencei = true; + } else if (send_warn) { + warn_report(warn_msg, "zifencei"); + } + } +} + /* * Check consistency between chosen extensions while setting * cpu->cfg accordingly. @@ -366,31 +412,8 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) CPURISCVState *env = &cpu->env; Error *local_err = NULL; - /* Do some ISA extension error checking */ - if (riscv_has_ext(env, RVG) && - !(riscv_has_ext(env, RVI) && riscv_has_ext(env, RVM) && - riscv_has_ext(env, RVA) && riscv_has_ext(env, RVF) && - riscv_has_ext(env, RVD) && - cpu->cfg.ext_zicsr && cpu->cfg.ext_zifencei)) { - - if (cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_zicsr)) && - !cpu->cfg.ext_zicsr) { - error_setg(errp, "RVG requires Zicsr but user set Zicsr to false"); - return; - } - - if (cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_zifencei)) && - !cpu->cfg.ext_zifencei) { - error_setg(errp, "RVG requires Zifencei but user set " - "Zifencei to false"); - return; - } - - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zicsr), true); - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zifencei), true); - - env->misa_ext |= RVI | RVM | RVA | RVF | RVD; - env->misa_ext_mask |= RVI | RVM | RVA | RVF | RVD; + if (riscv_has_ext(env, RVG)) { + riscv_cpu_validate_g(cpu); } if (riscv_has_ext(env, RVI) && riscv_has_ext(env, RVE)) { From 2af005d6107da71da35299449ee48e2115f1c8db Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 18 Dec 2023 09:53:24 -0300 Subject: [PATCH 44/65] target/riscv/tcg: validate profiles during finalize Enabling a profile and then disabling some of its mandatory extensions is a valid use. It can be useful for debugging and testing. But the common expected use of enabling a profile is to enable all its mandatory extensions. Add an user warning when mandatory extensions from an enabled profile are disabled in the command line. We're also going to disable the profile flag in this case since the profile must include all the mandatory extensions. This flag can be exposed by QMP to indicate the actual profile state after the CPU is realized. After this patch, this will throw warnings: -cpu rv64,rva22u64=true,zihintpause=false,zicbom=false,zicboz=false qemu-system-riscv64: warning: Profile rva22u64 mandates disabled extension zihintpause qemu-system-riscv64: warning: Profile rva22u64 mandates disabled extension zicbom qemu-system-riscv64: warning: Profile rva22u64 mandates disabled extension zicboz Note that the following will NOT throw warnings because the profile is being enabled last, hence all its mandatory extensions will be enabled: -cpu rv64,zihintpause=false,zicbom=false,zicboz=false,rva22u64=true Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Message-ID: <20231218125334.37184-17-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/tcg/tcg-cpu.c | 69 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index d2a42a347b..6c9e2e9a28 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -147,6 +147,26 @@ static int cpu_cfg_ext_get_min_version(uint32_t ext_offset) g_assert_not_reached(); } +static const char *cpu_cfg_ext_get_name(uint32_t ext_offset) +{ + const RISCVCPUMultiExtConfig *feat; + const RISCVIsaExtData *edata; + + for (edata = isa_edata_arr; edata->name != NULL; edata++) { + if (edata->ext_enable_offset == ext_offset) { + return edata->name; + } + } + + for (feat = riscv_cpu_named_features; feat->name != NULL; feat++) { + if (feat->offset == ext_offset) { + return feat->name; + } + } + + g_assert_not_reached(); +} + static bool cpu_cfg_offset_is_named_feat(uint32_t ext_offset) { const RISCVCPUMultiExtConfig *feat; @@ -732,6 +752,54 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) riscv_cpu_disable_priv_spec_isa_exts(cpu); } +static void riscv_cpu_validate_profile(RISCVCPU *cpu, + RISCVCPUProfile *profile) +{ + const char *warn_msg = "Profile %s mandates disabled extension %s"; + bool send_warn = profile->user_set && profile->enabled; + bool profile_impl = true; + int i; + + for (i = 0; misa_bits[i] != 0; i++) { + uint32_t bit = misa_bits[i]; + + if (!(profile->misa_ext & bit)) { + continue; + } + + if (!riscv_has_ext(&cpu->env, bit)) { + profile_impl = false; + + if (send_warn) { + warn_report(warn_msg, profile->name, + riscv_get_misa_ext_name(bit)); + } + } + } + + for (i = 0; profile->ext_offsets[i] != RISCV_PROFILE_EXT_LIST_END; i++) { + int ext_offset = profile->ext_offsets[i]; + + if (!isa_ext_is_enabled(cpu, ext_offset)) { + profile_impl = false; + + if (send_warn) { + warn_report(warn_msg, profile->name, + cpu_cfg_ext_get_name(ext_offset)); + } + } + } + + profile->enabled = profile_impl; +} + +static void riscv_cpu_validate_profiles(RISCVCPU *cpu) +{ + for (int i = 0; riscv_profiles[i] != NULL; i++) { + riscv_cpu_validate_profile(cpu, riscv_profiles[i]); + } +} + void riscv_tcg_cpu_finalize_features(RISCVCPU *cpu, Error **errp) { CPURISCVState *env = &cpu->env; @@ -750,6 +818,7 @@ void riscv_tcg_cpu_finalize_features(RISCVCPU *cpu, Error **errp) } riscv_cpu_update_named_features(cpu); + riscv_cpu_validate_profiles(cpu); if (cpu->cfg.ext_smepmp && !cpu->cfg.pmp) { /* From 6394b67615e1844dd2c0d616f0d2520533e43746 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 18 Dec 2023 09:53:25 -0300 Subject: [PATCH 45/65] riscv-qmp-cmds.c: add profile flags in cpu-model-expansion Expose all profile flags for all CPUs when executing query-cpu-model-expansion. This will allow callers to quickly determine if a certain profile is implemented by a given CPU. This includes vendor CPUs - the fact that they don't have profile user flags doesn't mean that they don't implement the profile. After this change it's possible to quickly determine if our stock CPUs implement the existing rva22u64 profile. Here's a few examples: $ ./build/qemu-system-riscv64 -S -M virt -display none -qmp tcp:localhost:1234,server,wait=off $ ./scripts/qmp/qmp-shell localhost:1234 Welcome to the QMP low-level shell! Connected to QEMU 8.1.50 - As expected, the 'max' CPU implements the rva22u64 profile. (QEMU) query-cpu-model-expansion type=full model={"name":"max"} {"return": {"model": {"name": "rv64", "props": {... "rva22u64": true, ...}}}} - rv64 is missing "zba", "zbb", "zbs", "zkt" and "zfhmin": query-cpu-model-expansion type=full model={"name":"rv64"} {"return": {"model": {"name": "rv64", "props": {... "rva22u64": false, ...}}}} query-cpu-model-expansion type=full model={"name":"rv64", "props":{"zba":true,"zbb":true,"zbs":true,"zkt":true,"zfhmin":true}} {"return": {"model": {"name": "rv64", "props": {... "rva22u64": true, ...}}}} We have no vendor CPUs that supports rva22u64 (veyron-v1 is the closest - it is missing just 'zkt'). In short, aside from the 'max' CPU, we have no CPUs that supports rva22u64 by default. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Message-ID: <20231218125334.37184-18-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/riscv-qmp-cmds.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/target/riscv/riscv-qmp-cmds.c b/target/riscv/riscv-qmp-cmds.c index 35f2b21163..c48b9cfa67 100644 --- a/target/riscv/riscv-qmp-cmds.c +++ b/target/riscv/riscv-qmp-cmds.c @@ -115,6 +115,19 @@ static void riscv_obj_add_named_feats_qdict(Object *obj, QDict *qdict_out) } } +static void riscv_obj_add_profiles_qdict(Object *obj, QDict *qdict_out) +{ + RISCVCPUProfile *profile; + QObject *value; + + for (int i = 0; riscv_profiles[i] != NULL; i++) { + profile = riscv_profiles[i]; + value = QOBJECT(qbool_from_bool(profile->enabled)); + + qdict_put_obj(qdict_out, profile->name, value); + } +} + static void riscv_cpuobj_validate_qdict_in(Object *obj, QObject *props, const QDict *qdict_in, Error **errp) @@ -219,6 +232,7 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type, riscv_obj_add_multiext_props(obj, qdict_out, riscv_cpu_experimental_exts); riscv_obj_add_multiext_props(obj, qdict_out, riscv_cpu_vendor_exts); riscv_obj_add_named_feats_qdict(obj, qdict_out); + riscv_obj_add_profiles_qdict(obj, qdict_out); /* Add our CPU boolean options too */ riscv_obj_add_qdict_prop(obj, qdict_out, "mmu"); From fba92a92e39069d7dc648cba1e561f28b7e91df6 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 18 Dec 2023 09:53:26 -0300 Subject: [PATCH 46/65] target/riscv: add 'rva22u64' CPU This CPU was suggested by Alistair [1] and others during the profile design discussions. It consists of the bare 'rv64i' CPU with rva22u64 enabled by default, like an alias of '-cpu rv64i,rva22u64=true'. Users now have an even easier way of consuming this user-mode profile by doing '-cpu rva22u64'. Extensions can be enabled/disabled at will on top of it. We can boot Linux with this "user-mode" CPU by doing: -cpu rva22u64,sv39=true,s=true,zifencei=true [1] https://lore.kernel.org/qemu-riscv/CAKmqyKP7xzZ9Sx=-Lbx2Ob0qCfB7Z+JO944FQ2TQ+49mqo0q_Q@mail.gmail.com/ Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Message-ID: <20231218125334.37184-19-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu-qom.h | 1 + target/riscv/cpu.c | 17 +++++++++++++++++ target/riscv/tcg/tcg-cpu.c | 9 +++++++++ 3 files changed, 27 insertions(+) diff --git a/target/riscv/cpu-qom.h b/target/riscv/cpu-qom.h index 4d1aa54311..12fe78fc52 100644 --- a/target/riscv/cpu-qom.h +++ b/target/riscv/cpu-qom.h @@ -35,6 +35,7 @@ #define TYPE_RISCV_CPU_BASE64 RISCV_CPU_TYPE_NAME("rv64") #define TYPE_RISCV_CPU_BASE128 RISCV_CPU_TYPE_NAME("x-rv128") #define TYPE_RISCV_CPU_RV64I RISCV_CPU_TYPE_NAME("rv64i") +#define TYPE_RISCV_CPU_RVA22U64 RISCV_CPU_TYPE_NAME("rva22u64") #define TYPE_RISCV_CPU_IBEX RISCV_CPU_TYPE_NAME("lowrisc-ibex") #define TYPE_RISCV_CPU_SHAKTI_C RISCV_CPU_TYPE_NAME("shakti-c") #define TYPE_RISCV_CPU_SIFIVE_E31 RISCV_CPU_TYPE_NAME("sifive-e31") diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 199b581380..cd3c22e92b 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1575,6 +1575,15 @@ static Property riscv_cpu_properties[] = { DEFINE_PROP_END_OF_LIST(), }; +#if defined(TARGET_RISCV64) +static void rva22u64_profile_cpu_init(Object *obj) +{ + rv64i_bare_cpu_init(obj); + + RVA22U64.enabled = true; +} +#endif + static const gchar *riscv_gdb_arch_name(CPUState *cs) { RISCVCPU *cpu = RISCV_CPU(cs); @@ -1836,6 +1845,13 @@ char *riscv_isa_string(RISCVCPU *cpu) .instance_init = initfn \ } +#define DEFINE_PROFILE_CPU(type_name, initfn) \ + { \ + .name = type_name, \ + .parent = TYPE_RISCV_BARE_CPU, \ + .instance_init = initfn \ + } + static const TypeInfo riscv_cpu_type_infos[] = { { .name = TYPE_RISCV_CPU, @@ -1880,6 +1896,7 @@ static const TypeInfo riscv_cpu_type_infos[] = { DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_VEYRON_V1, rv64_veyron_v1_cpu_init), DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_BASE128, rv128_base_cpu_init), DEFINE_BARE_CPU(TYPE_RISCV_CPU_RV64I, rv64i_bare_cpu_init), + DEFINE_PROFILE_CPU(TYPE_RISCV_CPU_RVA22U64, rva22u64_profile_cpu_init), #endif }; diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index 6c9e2e9a28..f2a9558737 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -1100,6 +1100,15 @@ static void riscv_cpu_add_profiles(Object *cpu_obj) object_property_add(cpu_obj, profile->name, "bool", cpu_get_profile, cpu_set_profile, NULL, (void *)profile); + + /* + * CPUs might enable a profile right from the start. + * Enable its mandatory extensions right away in this + * case. + */ + if (profile->enabled) { + object_property_set_bool(cpu_obj, profile->name, true, NULL); + } } } From 48531f5adb2aede5519d072b9bbc27f46994ce2d Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 18 Dec 2023 09:53:27 -0300 Subject: [PATCH 47/65] target/riscv: implement svade 'svade' is a RVA22S64 profile requirement, a profile we're going to add shortly. It is a named feature (i.e. not a formal extension, not defined in riscv,isa DT at this moment) defined in [1] as: "Page-fault exceptions are raised when a page is accessed when A bit is clear, or written when D bit is clear.". As far as the spec goes, 'svade' is one of the two distinct modes of handling PTE_A and PTE_D. The other way, i.e. update PTE_A/PTE_D when they're cleared, is defined by the 'svadu' extension. Checking cpu_helper.c, get_physical_address(), we can verify that QEMU is compliant with that: we will update PTE_A/PTE_D if 'svadu' is enabled, or throw a page-fault exception if 'svadu' isn't enabled. So, as far as we're concerned, 'svade' translates to 'svadu must be disabled'. We'll implement it like 'zic64b': an internal flag that profiles can enable. The flag will not be exposed to users. [1] https://github.com/riscv/riscv-profiles/blob/main/profiles.adoc Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Message-ID: <20231218125334.37184-20-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 1 + target/riscv/cpu_cfg.h | 1 + target/riscv/tcg/tcg-cpu.c | 5 +++++ 3 files changed, 7 insertions(+) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index cd3c22e92b..0ec0d89070 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1444,6 +1444,7 @@ const RISCVCPUMultiExtConfig riscv_cpu_experimental_exts[] = { }; const RISCVCPUMultiExtConfig riscv_cpu_named_features[] = { + MULTI_EXT_CFG_BOOL("svade", svade, true), MULTI_EXT_CFG_BOOL("zic64b", zic64b, true), DEFINE_PROP_END_OF_LIST(), diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h index 350ea44e50..780ae6ef17 100644 --- a/target/riscv/cpu_cfg.h +++ b/target/riscv/cpu_cfg.h @@ -117,6 +117,7 @@ struct RISCVCPUConfig { bool ext_smepmp; bool rvv_ta_all_1s; bool rvv_ma_all_1s; + bool svade; bool zic64b; uint32_t mvendorid; diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index f2a9558737..e90d929ac1 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -188,6 +188,9 @@ static void riscv_cpu_enable_named_feat(RISCVCPU *cpu, uint32_t feat_offset) cpu->cfg.cbop_blocksize = 64; cpu->cfg.cboz_blocksize = 64; break; + case CPU_CFG_OFFSET(svade): + cpu->cfg.ext_svadu = false; + break; default: g_assert_not_reached(); } @@ -381,6 +384,8 @@ static void riscv_cpu_update_named_features(RISCVCPU *cpu) cpu->cfg.zic64b = cpu->cfg.cbom_blocksize == 64 && cpu->cfg.cbop_blocksize == 64 && cpu->cfg.cboz_blocksize == 64; + + cpu->cfg.svade = !cpu->cfg.ext_svadu; } static void riscv_cpu_validate_g(RISCVCPU *cpu) From 1a7d4fcb3fe9d4215b3d6ead362af379a82c1c49 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 18 Dec 2023 09:53:28 -0300 Subject: [PATCH 48/65] target/riscv: add priv ver restriction to profiles Some profiles, like RVA22S64, has a priv_spec requirement. Make this requirement explicit for all profiles. We'll validate this requirement finalize() time and, in case the user chooses an incompatible priv_spec while activating a profile, a warning will be shown. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Message-ID: <20231218125334.37184-21-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 1 + target/riscv/cpu.h | 2 ++ target/riscv/tcg/tcg-cpu.c | 31 +++++++++++++++++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 0ec0d89070..563fd4f722 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1536,6 +1536,7 @@ Property riscv_cpu_options[] = { static RISCVCPUProfile RVA22U64 = { .name = "rva22u64", .misa_ext = RVI | RVM | RVA | RVF | RVD | RVC | RVU, + .priv_spec = RISCV_PROFILE_ATTR_UNUSED, .ext_offsets = { CPU_CFG_OFFSET(ext_zicsr), CPU_CFG_OFFSET(ext_zihintpause), CPU_CFG_OFFSET(ext_zba), CPU_CFG_OFFSET(ext_zbb), diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 5af1666dc0..3d1c347b71 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -81,10 +81,12 @@ typedef struct riscv_cpu_profile { uint32_t misa_ext; bool enabled; bool user_set; + int priv_spec; const int32_t ext_offsets[]; } RISCVCPUProfile; #define RISCV_PROFILE_EXT_LIST_END -1 +#define RISCV_PROFILE_ATTR_UNUSED -1 extern RISCVCPUProfile *riscv_profiles[]; diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index e90d929ac1..41eef87e6e 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -74,6 +74,20 @@ static void riscv_cpu_write_misa_bit(RISCVCPU *cpu, uint32_t bit, } } +static const char *cpu_priv_ver_to_str(int priv_ver) +{ + switch (priv_ver) { + case PRIV_VERSION_1_10_0: + return "v1.10.0"; + case PRIV_VERSION_1_11_0: + return "v1.11.0"; + case PRIV_VERSION_1_12_0: + return "v1.12.0"; + } + + g_assert_not_reached(); +} + static void riscv_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb) { @@ -760,11 +774,24 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) static void riscv_cpu_validate_profile(RISCVCPU *cpu, RISCVCPUProfile *profile) { + CPURISCVState *env = &cpu->env; const char *warn_msg = "Profile %s mandates disabled extension %s"; bool send_warn = profile->user_set && profile->enabled; bool profile_impl = true; int i; + if (profile->priv_spec != RISCV_PROFILE_ATTR_UNUSED && + profile->priv_spec != env->priv_ver) { + profile_impl = false; + + if (send_warn) { + warn_report("Profile %s requires priv spec %s, " + "but priv ver %s was set", profile->name, + cpu_priv_ver_to_str(profile->priv_spec), + cpu_priv_ver_to_str(env->priv_ver)); + } + } + for (i = 0; misa_bits[i] != 0; i++) { uint32_t bit = misa_bits[i]; @@ -1053,6 +1080,10 @@ static void cpu_set_profile(Object *obj, Visitor *v, const char *name, profile->user_set = true; profile->enabled = value; + if (profile->enabled) { + cpu->env.priv_ver = profile->priv_spec; + } + for (i = 0; misa_bits[i] != 0; i++) { uint32_t bit = misa_bits[i]; From ab77a9d5074f87b7ff3df605b26d87c1909d0c01 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 18 Dec 2023 09:53:29 -0300 Subject: [PATCH 49/65] target/riscv/cpu.c: finalize satp_mode earlier Profiles will need to validate satp_mode during their own finalize methods. This will occur inside riscv_tcg_cpu_finalize_features() for TCG. Given that satp_mode does not have any pre-req from the accelerator finalize() method, it's safe to finalize it earlier. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Message-ID: <20231218125334.37184-22-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 563fd4f722..65f69a7dd3 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1054,6 +1054,14 @@ void riscv_cpu_finalize_features(RISCVCPU *cpu, Error **errp) { Error *local_err = NULL; +#ifndef CONFIG_USER_ONLY + riscv_cpu_satp_mode_finalize(cpu, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } +#endif + /* * KVM accel does not have a specialized finalize() * callback because its extensions are validated @@ -1066,14 +1074,6 @@ void riscv_cpu_finalize_features(RISCVCPU *cpu, Error **errp) return; } } - -#ifndef CONFIG_USER_ONLY - riscv_cpu_satp_mode_finalize(cpu, &local_err); - if (local_err != NULL) { - error_propagate(errp, local_err); - return; - } -#endif } static void riscv_cpu_realize(DeviceState *dev, Error **errp) From e7acc1cb934bfada058c726f39548407cfb2a772 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 18 Dec 2023 09:53:30 -0300 Subject: [PATCH 50/65] target/riscv/cpu.c: add riscv_cpu_is_32bit() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Next patch will need to retrieve if a given RISCVCPU is 32 or 64 bit. The existing helper riscv_is_32bit() (hw/riscv/boot.c) will always check the first CPU of a given hart array, not any given CPU. Create a helper to retrieve the info for any given CPU, not the first CPU of the hart array. The helper is using the same 32 bit check that riscv_cpu_satp_mode_finalize() was doing. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-ID: <20231218125334.37184-23-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 7 ++++++- target/riscv/cpu.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 65f69a7dd3..4d1fd7fd48 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -53,6 +53,11 @@ const uint32_t misa_bits[] = {RVI, RVE, RVM, RVA, RVF, RVD, RVV, #define BYTE(x) (x) #endif +bool riscv_cpu_is_32bit(RISCVCPU *cpu) +{ + return riscv_cpu_mxl(&cpu->env) == MXL_RV32; +} + #define ISA_EXT_DATA_ENTRY(_name, _min_ver, _prop) \ {#_name, _min_ver, CPU_CFG_OFFSET(_prop)} @@ -978,7 +983,7 @@ static void riscv_cpu_disas_set_info(CPUState *s, disassemble_info *info) #ifndef CONFIG_USER_ONLY static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp) { - bool rv32 = riscv_cpu_mxl(&cpu->env) == MXL_RV32; + bool rv32 = riscv_cpu_is_32bit(cpu); uint8_t satp_mode_map_max, satp_mode_supported_max; /* The CPU wants the OS to decide which satp mode to use */ diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 3d1c347b71..a0f768e77d 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -693,6 +693,7 @@ void cpu_get_tb_cpu_state(CPURISCVState *env, vaddr *pc, uint64_t *cs_base, uint32_t *pflags); void riscv_cpu_update_mask(CPURISCVState *env); +bool riscv_cpu_is_32bit(RISCVCPU *cpu); RISCVException riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value, From 55398025e7dfe0c8e6455e542980d1fc6157543c Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 18 Dec 2023 09:53:31 -0300 Subject: [PATCH 51/65] target/riscv: add satp_mode profile support 'satp_mode' is a requirement for supervisor profiles like RVA22S64. User-mode/application profiles like RVA22U64 doesn't care. Add 'satp_mode' to the profile description. If a profile requires it, set it during cpu_set_profile(). We'll also check it during finalize() to validate if the running config implements the profile. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Acked-by: Alistair Francis Message-ID: <20231218125334.37184-24-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 1 + target/riscv/cpu.h | 1 + target/riscv/tcg/tcg-cpu.c | 40 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 4d1fd7fd48..1aeb0fee1b 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1542,6 +1542,7 @@ static RISCVCPUProfile RVA22U64 = { .name = "rva22u64", .misa_ext = RVI | RVM | RVA | RVF | RVD | RVC | RVU, .priv_spec = RISCV_PROFILE_ATTR_UNUSED, + .satp_mode = RISCV_PROFILE_ATTR_UNUSED, .ext_offsets = { CPU_CFG_OFFSET(ext_zicsr), CPU_CFG_OFFSET(ext_zihintpause), CPU_CFG_OFFSET(ext_zba), CPU_CFG_OFFSET(ext_zbb), diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index a0f768e77d..136030434e 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -82,6 +82,7 @@ typedef struct riscv_cpu_profile { bool enabled; bool user_set; int priv_spec; + int satp_mode; const int32_t ext_offsets[]; } RISCVCPUProfile; diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index 41eef87e6e..a0a3350e3e 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -771,6 +771,31 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) riscv_cpu_disable_priv_spec_isa_exts(cpu); } +#ifndef CONFIG_USER_ONLY +static bool riscv_cpu_validate_profile_satp(RISCVCPU *cpu, + RISCVCPUProfile *profile, + bool send_warn) +{ + int satp_max = satp_mode_max_from_map(cpu->cfg.satp_mode.supported); + + if (profile->satp_mode > satp_max) { + if (send_warn) { + bool is_32bit = riscv_cpu_is_32bit(cpu); + const char *req_satp = satp_mode_str(profile->satp_mode, is_32bit); + const char *cur_satp = satp_mode_str(satp_max, is_32bit); + + warn_report("Profile %s requires satp mode %s, " + "but satp mode %s was set", profile->name, + req_satp, cur_satp); + } + + return false; + } + + return true; +} +#endif + static void riscv_cpu_validate_profile(RISCVCPU *cpu, RISCVCPUProfile *profile) { @@ -780,6 +805,13 @@ static void riscv_cpu_validate_profile(RISCVCPU *cpu, bool profile_impl = true; int i; +#ifndef CONFIG_USER_ONLY + if (profile->satp_mode != RISCV_PROFILE_ATTR_UNUSED) { + profile_impl = riscv_cpu_validate_profile_satp(cpu, profile, + send_warn); + } +#endif + if (profile->priv_spec != RISCV_PROFILE_ATTR_UNUSED && profile->priv_spec != env->priv_ver) { profile_impl = false; @@ -1084,6 +1116,14 @@ static void cpu_set_profile(Object *obj, Visitor *v, const char *name, cpu->env.priv_ver = profile->priv_spec; } +#ifndef CONFIG_USER_ONLY + if (profile->satp_mode != RISCV_PROFILE_ATTR_UNUSED) { + const char *satp_prop = satp_mode_str(profile->satp_mode, + riscv_cpu_is_32bit(cpu)); + object_property_set_bool(obj, satp_prop, profile->enabled, NULL); + } +#endif + for (i = 0; misa_bits[i] != 0; i++) { uint32_t bit = misa_bits[i]; From 79593ca4b00d01847baa2c710f8a3c1021b96b2f Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 18 Dec 2023 09:53:32 -0300 Subject: [PATCH 52/65] target/riscv: add 'parent' in profile description Certain S-mode profiles, like RVA22S64 and RVA23S64, mandate all the mandatory extensions of their respective U-mode profiles. RVA22S64 includes all mandatory extensions of RVA22U64, and the same happens with RVA23 profiles. Add a 'parent' field to allow profiles to enable other profiles. This will allow us to describe S-mode profiles by specifying their parent U-mode profile, then adding just the S-mode specific extensions. We're naming the field 'parent' to consider the possibility of other uses (e.g. a s-mode profile including a previous s-mode profile) in the future. Suggested-by: Andrew Jones Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Message-ID: <20231218125334.37184-25-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 1 + target/riscv/cpu.h | 1 + target/riscv/tcg/tcg-cpu.c | 14 +++++++++++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 1aeb0fee1b..616b091303 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1539,6 +1539,7 @@ Property riscv_cpu_options[] = { * having a cfg offset) at this moment. */ static RISCVCPUProfile RVA22U64 = { + .parent = NULL, .name = "rva22u64", .misa_ext = RVI | RVM | RVA | RVF | RVD | RVC | RVU, .priv_spec = RISCV_PROFILE_ATTR_UNUSED, diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 136030434e..5f3955c38d 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -77,6 +77,7 @@ const char *riscv_get_misa_ext_description(uint32_t bit); #define CPU_CFG_OFFSET(_prop) offsetof(struct RISCVCPUConfig, _prop) typedef struct riscv_cpu_profile { + struct riscv_cpu_profile *parent; const char *name; uint32_t misa_ext; bool enabled; diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index a0a3350e3e..14133ff665 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -802,7 +802,7 @@ static void riscv_cpu_validate_profile(RISCVCPU *cpu, CPURISCVState *env = &cpu->env; const char *warn_msg = "Profile %s mandates disabled extension %s"; bool send_warn = profile->user_set && profile->enabled; - bool profile_impl = true; + bool parent_enabled, profile_impl = true; int i; #ifndef CONFIG_USER_ONLY @@ -855,6 +855,13 @@ static void riscv_cpu_validate_profile(RISCVCPU *cpu, } profile->enabled = profile_impl; + + if (profile->parent != NULL) { + parent_enabled = object_property_get_bool(OBJECT(cpu), + profile->parent->name, + NULL); + profile->enabled = profile->enabled && parent_enabled; + } } static void riscv_cpu_validate_profiles(RISCVCPU *cpu) @@ -1112,6 +1119,11 @@ static void cpu_set_profile(Object *obj, Visitor *v, const char *name, profile->user_set = true; profile->enabled = value; + if (profile->parent != NULL) { + object_property_set_bool(obj, profile->parent->name, + profile->enabled, NULL); + } + if (profile->enabled) { cpu->env.priv_ver = profile->priv_spec; } From af651969eb23ecf018bcaa8e0761b58425de550c Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 18 Dec 2023 09:53:33 -0300 Subject: [PATCH 53/65] target/riscv: add RVA22S64 profile The RVA22S64 profile consists of the following: - all mandatory extensions of RVA22U64; - priv spec v1.12.0; - satp mode sv39; - Ssccptr, a cache related named feature that we're assuming always enable since we don't implement a cache; - Other named features already implemented: Sstvecd, Sstvala, Sscounterenw; - the new Svade named feature that was recently added. Most of the work is already done, so this patch is enough to implement the profile. After this patch, the 'rva22s64' user flag alone can be used with the rva64i CPU to boot Linux: -cpu rv64i,rva22s64=true This is the /proc/cpuinfo with this profile enabled: # cat /proc/cpuinfo processor : 0 hart : 0 isa : rv64imafdc_zicbom_zicbop_zicboz_zicntr_zicsr_zifencei_zihintpause_zihpm_zfhmin_zca_zcd_zba_zbb_zbs_zkt_svinval_svpbmt mmu : sv39 Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Message-ID: <20231218125334.37184-26-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 616b091303..a8f4081922 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1559,8 +1559,40 @@ static RISCVCPUProfile RVA22U64 = { } }; +/* + * As with RVA22U64, RVA22S64 also defines 'named features'. + * + * Cache related features that we consider enabled since we don't + * implement cache: Ssccptr + * + * Other named features that we already implement: Sstvecd, Sstvala, + * Sscounterenw + * + * Named features that we need to enable: svade + * + * The remaining features/extensions comes from RVA22U64. + */ +static RISCVCPUProfile RVA22S64 = { + .parent = &RVA22U64, + .name = "rva22s64", + .misa_ext = RVS, + .priv_spec = PRIV_VERSION_1_12_0, + .satp_mode = VM_1_10_SV39, + .ext_offsets = { + /* rva22s64 exts */ + CPU_CFG_OFFSET(ext_zifencei), CPU_CFG_OFFSET(ext_svpbmt), + CPU_CFG_OFFSET(ext_svinval), + + /* rva22s64 named features */ + CPU_CFG_OFFSET(svade), + + RISCV_PROFILE_EXT_LIST_END + } +}; + RISCVCPUProfile *riscv_profiles[] = { &RVA22U64, + &RVA22S64, NULL, }; From dfa3c4c57e15912962b7d51c9b4099f46af41991 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 18 Dec 2023 09:53:34 -0300 Subject: [PATCH 54/65] target/riscv: add rva22s64 cpu Add a new profile CPU 'rva22s64' to work as an alias of -cpu rv64i,rva22s64 Like the existing rva22u64 CPU already does with the RVA22U64 profile. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Message-ID: <20231218125334.37184-27-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu-qom.h | 1 + target/riscv/cpu.c | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/target/riscv/cpu-qom.h b/target/riscv/cpu-qom.h index 12fe78fc52..9219c2fcc3 100644 --- a/target/riscv/cpu-qom.h +++ b/target/riscv/cpu-qom.h @@ -36,6 +36,7 @@ #define TYPE_RISCV_CPU_BASE128 RISCV_CPU_TYPE_NAME("x-rv128") #define TYPE_RISCV_CPU_RV64I RISCV_CPU_TYPE_NAME("rv64i") #define TYPE_RISCV_CPU_RVA22U64 RISCV_CPU_TYPE_NAME("rva22u64") +#define TYPE_RISCV_CPU_RVA22S64 RISCV_CPU_TYPE_NAME("rva22s64") #define TYPE_RISCV_CPU_IBEX RISCV_CPU_TYPE_NAME("lowrisc-ibex") #define TYPE_RISCV_CPU_SHAKTI_C RISCV_CPU_TYPE_NAME("shakti-c") #define TYPE_RISCV_CPU_SIFIVE_E31 RISCV_CPU_TYPE_NAME("sifive-e31") diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index a8f4081922..b32681f7f3 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1623,6 +1623,13 @@ static void rva22u64_profile_cpu_init(Object *obj) RVA22U64.enabled = true; } + +static void rva22s64_profile_cpu_init(Object *obj) +{ + rv64i_bare_cpu_init(obj); + + RVA22S64.enabled = true; +} #endif static const gchar *riscv_gdb_arch_name(CPUState *cs) @@ -1938,6 +1945,7 @@ static const TypeInfo riscv_cpu_type_infos[] = { DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_BASE128, rv128_base_cpu_init), DEFINE_BARE_CPU(TYPE_RISCV_CPU_RV64I, rv64i_bare_cpu_init), DEFINE_PROFILE_CPU(TYPE_RISCV_CPU_RVA22U64, rva22u64_profile_cpu_init), + DEFINE_PROFILE_CPU(TYPE_RISCV_CPU_RVA22S64, rva22s64_profile_cpu_init), #endif }; From 871dad3a19c660e17c412b1bc969195f814933c8 Mon Sep 17 00:00:00 2001 From: Yong-Xuan Wang Date: Mon, 18 Dec 2023 09:05:41 +0000 Subject: [PATCH 55/65] target/riscv/kvm.c: remove group setting of KVM AIA if the machine only has 1 socket The emulated AIA within the Linux kernel restores the HART index of the IMSICs according to the configured AIA settings. During this process, the group setting is used only when the machine partitions harts into groups. It's unnecessary to set the group configuration if the machine has only one socket, as its address space might not contain the group shift. Signed-off-by: Yong-Xuan Wang Reviewed-by: Jim Shu Reviewed-by: Daniel Henrique Barboza Message-ID: <20231218090543.22353-2-yongxuan.wang@sifive.com> Signed-off-by: Alistair Francis --- target/riscv/kvm/kvm-cpu.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index 2c5217102c..841756ab9b 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -1390,21 +1390,24 @@ void kvm_riscv_aia_create(MachineState *machine, uint64_t group_shift, exit(1); } - socket_bits = find_last_bit(&socket_count, BITS_PER_LONG) + 1; - ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_CONFIG, - KVM_DEV_RISCV_AIA_CONFIG_GROUP_BITS, - &socket_bits, true, NULL); - if (ret < 0) { - error_report("KVM AIA: failed to set group_bits"); - exit(1); - } - ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_CONFIG, - KVM_DEV_RISCV_AIA_CONFIG_GROUP_SHIFT, - &group_shift, true, NULL); - if (ret < 0) { - error_report("KVM AIA: failed to set group_shift"); - exit(1); + if (socket_count > 1) { + socket_bits = find_last_bit(&socket_count, BITS_PER_LONG) + 1; + ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_CONFIG, + KVM_DEV_RISCV_AIA_CONFIG_GROUP_BITS, + &socket_bits, true, NULL); + if (ret < 0) { + error_report("KVM AIA: failed to set group_bits"); + exit(1); + } + + ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_CONFIG, + KVM_DEV_RISCV_AIA_CONFIG_GROUP_SHIFT, + &group_shift, true, NULL); + if (ret < 0) { + error_report("KVM AIA: failed to set group_shift"); + exit(1); + } } guest_bits = guest_num == 0 ? 0 : From efb91426af6506e7aa8900b9b1ed845039442030 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 18 Dec 2023 17:43:18 -0300 Subject: [PATCH 56/65] linux-headers: Update to Linux v6.7-rc5 We'll add a new RISC-V linux-header file, but first let's update all headers. Headers for 'asm-loongarch' were added in this update. Signed-off-by: Daniel Henrique Barboza Acked-by: Alistair Francis Message-ID: <20231218204321.75757-2-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- include/standard-headers/drm/drm_fourcc.h | 2 + include/standard-headers/linux/pci_regs.h | 24 ++- include/standard-headers/linux/vhost_types.h | 7 + .../standard-headers/linux/virtio_config.h | 5 + include/standard-headers/linux/virtio_pci.h | 11 ++ linux-headers/asm-arm64/kvm.h | 32 ++++ linux-headers/asm-generic/unistd.h | 14 +- linux-headers/asm-loongarch/bitsperlong.h | 1 + linux-headers/asm-loongarch/kvm.h | 108 +++++++++++ linux-headers/asm-loongarch/mman.h | 1 + linux-headers/asm-loongarch/unistd.h | 5 + linux-headers/asm-mips/unistd_n32.h | 4 + linux-headers/asm-mips/unistd_n64.h | 4 + linux-headers/asm-mips/unistd_o32.h | 4 + linux-headers/asm-powerpc/unistd_32.h | 4 + linux-headers/asm-powerpc/unistd_64.h | 4 + linux-headers/asm-riscv/kvm.h | 12 ++ linux-headers/asm-s390/unistd_32.h | 4 + linux-headers/asm-s390/unistd_64.h | 4 + linux-headers/asm-x86/unistd_32.h | 4 + linux-headers/asm-x86/unistd_64.h | 3 + linux-headers/asm-x86/unistd_x32.h | 3 + linux-headers/linux/iommufd.h | 180 +++++++++++++++++- linux-headers/linux/kvm.h | 11 ++ linux-headers/linux/psp-sev.h | 1 + linux-headers/linux/stddef.h | 9 +- linux-headers/linux/userfaultfd.h | 9 +- linux-headers/linux/vfio.h | 47 +++-- linux-headers/linux/vhost.h | 8 + 29 files changed, 498 insertions(+), 27 deletions(-) create mode 100644 linux-headers/asm-loongarch/bitsperlong.h create mode 100644 linux-headers/asm-loongarch/kvm.h create mode 100644 linux-headers/asm-loongarch/mman.h create mode 100644 linux-headers/asm-loongarch/unistd.h diff --git a/include/standard-headers/drm/drm_fourcc.h b/include/standard-headers/drm/drm_fourcc.h index 72279f4d25..3afb70160f 100644 --- a/include/standard-headers/drm/drm_fourcc.h +++ b/include/standard-headers/drm/drm_fourcc.h @@ -322,6 +322,8 @@ extern "C" { * index 1 = Cr:Cb plane, [39:0] Cr1:Cb1:Cr0:Cb0 little endian */ #define DRM_FORMAT_NV15 fourcc_code('N', 'V', '1', '5') /* 2x2 subsampled Cr:Cb plane */ +#define DRM_FORMAT_NV20 fourcc_code('N', 'V', '2', '0') /* 2x1 subsampled Cr:Cb plane */ +#define DRM_FORMAT_NV30 fourcc_code('N', 'V', '3', '0') /* non-subsampled Cr:Cb plane */ /* * 2 plane YCbCr MSB aligned diff --git a/include/standard-headers/linux/pci_regs.h b/include/standard-headers/linux/pci_regs.h index e5f558d964..a39193213f 100644 --- a/include/standard-headers/linux/pci_regs.h +++ b/include/standard-headers/linux/pci_regs.h @@ -80,6 +80,7 @@ #define PCI_HEADER_TYPE_NORMAL 0 #define PCI_HEADER_TYPE_BRIDGE 1 #define PCI_HEADER_TYPE_CARDBUS 2 +#define PCI_HEADER_TYPE_MFD 0x80 /* Multi-Function Device (possible) */ #define PCI_BIST 0x0f /* 8 bits */ #define PCI_BIST_CODE_MASK 0x0f /* Return result */ @@ -637,6 +638,7 @@ #define PCI_EXP_RTCAP 0x1e /* Root Capabilities */ #define PCI_EXP_RTCAP_CRSVIS 0x0001 /* CRS Software Visibility capability */ #define PCI_EXP_RTSTA 0x20 /* Root Status */ +#define PCI_EXP_RTSTA_PME_RQ_ID 0x0000ffff /* PME Requester ID */ #define PCI_EXP_RTSTA_PME 0x00010000 /* PME status */ #define PCI_EXP_RTSTA_PENDING 0x00020000 /* PME pending */ /* @@ -930,12 +932,13 @@ /* Process Address Space ID */ #define PCI_PASID_CAP 0x04 /* PASID feature register */ -#define PCI_PASID_CAP_EXEC 0x02 /* Exec permissions Supported */ -#define PCI_PASID_CAP_PRIV 0x04 /* Privilege Mode Supported */ +#define PCI_PASID_CAP_EXEC 0x0002 /* Exec permissions Supported */ +#define PCI_PASID_CAP_PRIV 0x0004 /* Privilege Mode Supported */ +#define PCI_PASID_CAP_WIDTH 0x1f00 #define PCI_PASID_CTRL 0x06 /* PASID control register */ -#define PCI_PASID_CTRL_ENABLE 0x01 /* Enable bit */ -#define PCI_PASID_CTRL_EXEC 0x02 /* Exec permissions Enable */ -#define PCI_PASID_CTRL_PRIV 0x04 /* Privilege Mode Enable */ +#define PCI_PASID_CTRL_ENABLE 0x0001 /* Enable bit */ +#define PCI_PASID_CTRL_EXEC 0x0002 /* Exec permissions Enable */ +#define PCI_PASID_CTRL_PRIV 0x0004 /* Privilege Mode Enable */ #define PCI_EXT_CAP_PASID_SIZEOF 8 /* Single Root I/O Virtualization */ @@ -975,6 +978,8 @@ #define PCI_LTR_VALUE_MASK 0x000003ff #define PCI_LTR_SCALE_MASK 0x00001c00 #define PCI_LTR_SCALE_SHIFT 10 +#define PCI_LTR_NOSNOOP_VALUE 0x03ff0000 /* Max No-Snoop Latency Value */ +#define PCI_LTR_NOSNOOP_SCALE 0x1c000000 /* Scale for Max Value */ #define PCI_EXT_CAP_LTR_SIZEOF 8 /* Access Control Service */ @@ -1042,9 +1047,16 @@ #define PCI_EXP_DPC_STATUS 0x08 /* DPC Status */ #define PCI_EXP_DPC_STATUS_TRIGGER 0x0001 /* Trigger Status */ #define PCI_EXP_DPC_STATUS_TRIGGER_RSN 0x0006 /* Trigger Reason */ +#define PCI_EXP_DPC_STATUS_TRIGGER_RSN_UNCOR 0x0000 /* Uncorrectable error */ +#define PCI_EXP_DPC_STATUS_TRIGGER_RSN_NFE 0x0002 /* Rcvd ERR_NONFATAL */ +#define PCI_EXP_DPC_STATUS_TRIGGER_RSN_FE 0x0004 /* Rcvd ERR_FATAL */ +#define PCI_EXP_DPC_STATUS_TRIGGER_RSN_IN_EXT 0x0006 /* Reason in Trig Reason Extension field */ #define PCI_EXP_DPC_STATUS_INTERRUPT 0x0008 /* Interrupt Status */ #define PCI_EXP_DPC_RP_BUSY 0x0010 /* Root Port Busy */ #define PCI_EXP_DPC_STATUS_TRIGGER_RSN_EXT 0x0060 /* Trig Reason Extension */ +#define PCI_EXP_DPC_STATUS_TRIGGER_RSN_RP_PIO 0x0000 /* RP PIO error */ +#define PCI_EXP_DPC_STATUS_TRIGGER_RSN_SW_TRIGGER 0x0020 /* DPC SW Trigger bit */ +#define PCI_EXP_DPC_RP_PIO_FEP 0x1f00 /* RP PIO First Err Ptr */ #define PCI_EXP_DPC_SOURCE_ID 0x0A /* DPC Source Identifier */ @@ -1088,6 +1100,8 @@ #define PCI_L1SS_CTL1_LTR_L12_TH_VALUE 0x03ff0000 /* LTR_L1.2_THRESHOLD_Value */ #define PCI_L1SS_CTL1_LTR_L12_TH_SCALE 0xe0000000 /* LTR_L1.2_THRESHOLD_Scale */ #define PCI_L1SS_CTL2 0x0c /* Control 2 Register */ +#define PCI_L1SS_CTL2_T_PWR_ON_SCALE 0x00000003 /* T_POWER_ON Scale */ +#define PCI_L1SS_CTL2_T_PWR_ON_VALUE 0x000000f8 /* T_POWER_ON Value */ /* Designated Vendor-Specific (DVSEC, PCI_EXT_CAP_ID_DVSEC) */ #define PCI_DVSEC_HEADER1 0x4 /* Designated Vendor-Specific Header1 */ diff --git a/include/standard-headers/linux/vhost_types.h b/include/standard-headers/linux/vhost_types.h index 5ad07e134a..fd54044936 100644 --- a/include/standard-headers/linux/vhost_types.h +++ b/include/standard-headers/linux/vhost_types.h @@ -185,5 +185,12 @@ struct vhost_vdpa_iova_range { * DRIVER_OK */ #define VHOST_BACKEND_F_ENABLE_AFTER_DRIVER_OK 0x6 +/* Device may expose the virtqueue's descriptor area, driver area and + * device area to a different group for ASID binding than where its + * buffers may reside. Requires VHOST_BACKEND_F_IOTLB_ASID. + */ +#define VHOST_BACKEND_F_DESC_ASID 0x7 +/* IOTLB don't flush memory mapping across device reset */ +#define VHOST_BACKEND_F_IOTLB_PERSIST 0x8 #endif diff --git a/include/standard-headers/linux/virtio_config.h b/include/standard-headers/linux/virtio_config.h index 8a7d0dc8b0..bfd1ca643e 100644 --- a/include/standard-headers/linux/virtio_config.h +++ b/include/standard-headers/linux/virtio_config.h @@ -103,6 +103,11 @@ */ #define VIRTIO_F_NOTIFICATION_DATA 38 +/* This feature indicates that the driver uses the data provided by the device + * as a virtqueue identifier in available buffer notifications. + */ +#define VIRTIO_F_NOTIF_CONFIG_DATA 39 + /* * This feature indicates that the driver can reset a queue individually. */ diff --git a/include/standard-headers/linux/virtio_pci.h b/include/standard-headers/linux/virtio_pci.h index be912cfc95..b7fdfd0668 100644 --- a/include/standard-headers/linux/virtio_pci.h +++ b/include/standard-headers/linux/virtio_pci.h @@ -166,6 +166,17 @@ struct virtio_pci_common_cfg { uint32_t queue_used_hi; /* read-write */ }; +/* + * Warning: do not use sizeof on this: use offsetofend for + * specific fields you need. + */ +struct virtio_pci_modern_common_cfg { + struct virtio_pci_common_cfg cfg; + + uint16_t queue_notify_data; /* read-write */ + uint16_t queue_reset; /* read-write */ +}; + /* Fields in VIRTIO_PCI_CAP_PCI_CFG: */ struct virtio_pci_cfg_cap { struct virtio_pci_cap cap; diff --git a/linux-headers/asm-arm64/kvm.h b/linux-headers/asm-arm64/kvm.h index 38e5957526..c59ea55cd8 100644 --- a/linux-headers/asm-arm64/kvm.h +++ b/linux-headers/asm-arm64/kvm.h @@ -491,6 +491,38 @@ struct kvm_smccc_filter { #define KVM_HYPERCALL_EXIT_SMC (1U << 0) #define KVM_HYPERCALL_EXIT_16BIT (1U << 1) +/* + * Get feature ID registers userspace writable mask. + * + * From DDI0487J.a, D19.2.66 ("ID_AA64MMFR2_EL1, AArch64 Memory Model + * Feature Register 2"): + * + * "The Feature ID space is defined as the System register space in + * AArch64 with op0==3, op1=={0, 1, 3}, CRn==0, CRm=={0-7}, + * op2=={0-7}." + * + * This covers all currently known R/O registers that indicate + * anything useful feature wise, including the ID registers. + * + * If we ever need to introduce a new range, it will be described as + * such in the range field. + */ +#define KVM_ARM_FEATURE_ID_RANGE_IDX(op0, op1, crn, crm, op2) \ + ({ \ + __u64 __op1 = (op1) & 3; \ + __op1 -= (__op1 == 3); \ + (__op1 << 6 | ((crm) & 7) << 3 | (op2)); \ + }) + +#define KVM_ARM_FEATURE_ID_RANGE 0 +#define KVM_ARM_FEATURE_ID_RANGE_SIZE (3 * 8 * 8) + +struct reg_mask_range { + __u64 addr; /* Pointer to mask array */ + __u32 range; /* Requested range */ + __u32 reserved[13]; +}; + #endif #endif /* __ARM_KVM_H__ */ diff --git a/linux-headers/asm-generic/unistd.h b/linux-headers/asm-generic/unistd.h index abe087c53b..756b013fb8 100644 --- a/linux-headers/asm-generic/unistd.h +++ b/linux-headers/asm-generic/unistd.h @@ -71,7 +71,7 @@ __SYSCALL(__NR_fremovexattr, sys_fremovexattr) #define __NR_getcwd 17 __SYSCALL(__NR_getcwd, sys_getcwd) #define __NR_lookup_dcookie 18 -__SC_COMP(__NR_lookup_dcookie, sys_lookup_dcookie, compat_sys_lookup_dcookie) +__SYSCALL(__NR_lookup_dcookie, sys_ni_syscall) #define __NR_eventfd2 19 __SYSCALL(__NR_eventfd2, sys_eventfd2) #define __NR_epoll_create1 20 @@ -816,15 +816,21 @@ __SYSCALL(__NR_process_mrelease, sys_process_mrelease) __SYSCALL(__NR_futex_waitv, sys_futex_waitv) #define __NR_set_mempolicy_home_node 450 __SYSCALL(__NR_set_mempolicy_home_node, sys_set_mempolicy_home_node) - #define __NR_cachestat 451 __SYSCALL(__NR_cachestat, sys_cachestat) - #define __NR_fchmodat2 452 __SYSCALL(__NR_fchmodat2, sys_fchmodat2) +#define __NR_map_shadow_stack 453 +__SYSCALL(__NR_map_shadow_stack, sys_map_shadow_stack) +#define __NR_futex_wake 454 +__SYSCALL(__NR_futex_wake, sys_futex_wake) +#define __NR_futex_wait 455 +__SYSCALL(__NR_futex_wait, sys_futex_wait) +#define __NR_futex_requeue 456 +__SYSCALL(__NR_futex_requeue, sys_futex_requeue) #undef __NR_syscalls -#define __NR_syscalls 453 +#define __NR_syscalls 457 /* * 32 bit systems traditionally used different diff --git a/linux-headers/asm-loongarch/bitsperlong.h b/linux-headers/asm-loongarch/bitsperlong.h new file mode 100644 index 0000000000..6dc0bb0c13 --- /dev/null +++ b/linux-headers/asm-loongarch/bitsperlong.h @@ -0,0 +1 @@ +#include diff --git a/linux-headers/asm-loongarch/kvm.h b/linux-headers/asm-loongarch/kvm.h new file mode 100644 index 0000000000..c6ad2ee610 --- /dev/null +++ b/linux-headers/asm-loongarch/kvm.h @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited + */ + +#ifndef __UAPI_ASM_LOONGARCH_KVM_H +#define __UAPI_ASM_LOONGARCH_KVM_H + +#include + +/* + * KVM LoongArch specific structures and definitions. + * + * Some parts derived from the x86 version of this file. + */ + +#define __KVM_HAVE_READONLY_MEM + +#define KVM_COALESCED_MMIO_PAGE_OFFSET 1 +#define KVM_DIRTY_LOG_PAGE_OFFSET 64 + +/* + * for KVM_GET_REGS and KVM_SET_REGS + */ +struct kvm_regs { + /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */ + __u64 gpr[32]; + __u64 pc; +}; + +/* + * for KVM_GET_FPU and KVM_SET_FPU + */ +struct kvm_fpu { + __u32 fcsr; + __u64 fcc; /* 8x8 */ + struct kvm_fpureg { + __u64 val64[4]; + } fpr[32]; +}; + +/* + * For LoongArch, we use KVM_SET_ONE_REG and KVM_GET_ONE_REG to access various + * registers. The id field is broken down as follows: + * + * bits[63..52] - As per linux/kvm.h + * bits[51..32] - Must be zero. + * bits[31..16] - Register set. + * + * Register set = 0: GP registers from kvm_regs (see definitions below). + * + * Register set = 1: CSR registers. + * + * Register set = 2: KVM specific registers (see definitions below). + * + * Register set = 3: FPU / SIMD registers (see definitions below). + * + * Other sets registers may be added in the future. Each set would + * have its own identifier in bits[31..16]. + */ + +#define KVM_REG_LOONGARCH_GPR (KVM_REG_LOONGARCH | 0x00000ULL) +#define KVM_REG_LOONGARCH_CSR (KVM_REG_LOONGARCH | 0x10000ULL) +#define KVM_REG_LOONGARCH_KVM (KVM_REG_LOONGARCH | 0x20000ULL) +#define KVM_REG_LOONGARCH_FPSIMD (KVM_REG_LOONGARCH | 0x30000ULL) +#define KVM_REG_LOONGARCH_CPUCFG (KVM_REG_LOONGARCH | 0x40000ULL) +#define KVM_REG_LOONGARCH_MASK (KVM_REG_LOONGARCH | 0x70000ULL) +#define KVM_CSR_IDX_MASK 0x7fff +#define KVM_CPUCFG_IDX_MASK 0x7fff + +/* + * KVM_REG_LOONGARCH_KVM - KVM specific control registers. + */ + +#define KVM_REG_LOONGARCH_COUNTER (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 1) +#define KVM_REG_LOONGARCH_VCPU_RESET (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 2) + +#define LOONGARCH_REG_SHIFT 3 +#define LOONGARCH_REG_64(TYPE, REG) (TYPE | KVM_REG_SIZE_U64 | (REG << LOONGARCH_REG_SHIFT)) +#define KVM_IOC_CSRID(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CSR, REG) +#define KVM_IOC_CPUCFG(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CPUCFG, REG) + +struct kvm_debug_exit_arch { +}; + +/* for KVM_SET_GUEST_DEBUG */ +struct kvm_guest_debug_arch { +}; + +/* definition of registers in kvm_run */ +struct kvm_sync_regs { +}; + +/* dummy definition */ +struct kvm_sregs { +}; + +struct kvm_iocsr_entry { + __u32 addr; + __u32 pad; + __u64 data; +}; + +#define KVM_NR_IRQCHIPS 1 +#define KVM_IRQCHIP_NUM_PINS 64 +#define KVM_MAX_CORES 256 + +#endif /* __UAPI_ASM_LOONGARCH_KVM_H */ diff --git a/linux-headers/asm-loongarch/mman.h b/linux-headers/asm-loongarch/mman.h new file mode 100644 index 0000000000..8eebf89f5a --- /dev/null +++ b/linux-headers/asm-loongarch/mman.h @@ -0,0 +1 @@ +#include diff --git a/linux-headers/asm-loongarch/unistd.h b/linux-headers/asm-loongarch/unistd.h new file mode 100644 index 0000000000..fcb668984f --- /dev/null +++ b/linux-headers/asm-loongarch/unistd.h @@ -0,0 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#define __ARCH_WANT_SYS_CLONE +#define __ARCH_WANT_SYS_CLONE3 + +#include diff --git a/linux-headers/asm-mips/unistd_n32.h b/linux-headers/asm-mips/unistd_n32.h index 46d8500654..994b6f008f 100644 --- a/linux-headers/asm-mips/unistd_n32.h +++ b/linux-headers/asm-mips/unistd_n32.h @@ -381,5 +381,9 @@ #define __NR_set_mempolicy_home_node (__NR_Linux + 450) #define __NR_cachestat (__NR_Linux + 451) #define __NR_fchmodat2 (__NR_Linux + 452) +#define __NR_map_shadow_stack (__NR_Linux + 453) +#define __NR_futex_wake (__NR_Linux + 454) +#define __NR_futex_wait (__NR_Linux + 455) +#define __NR_futex_requeue (__NR_Linux + 456) #endif /* _ASM_UNISTD_N32_H */ diff --git a/linux-headers/asm-mips/unistd_n64.h b/linux-headers/asm-mips/unistd_n64.h index c2f7ac673b..41dcf5877a 100644 --- a/linux-headers/asm-mips/unistd_n64.h +++ b/linux-headers/asm-mips/unistd_n64.h @@ -357,5 +357,9 @@ #define __NR_set_mempolicy_home_node (__NR_Linux + 450) #define __NR_cachestat (__NR_Linux + 451) #define __NR_fchmodat2 (__NR_Linux + 452) +#define __NR_map_shadow_stack (__NR_Linux + 453) +#define __NR_futex_wake (__NR_Linux + 454) +#define __NR_futex_wait (__NR_Linux + 455) +#define __NR_futex_requeue (__NR_Linux + 456) #endif /* _ASM_UNISTD_N64_H */ diff --git a/linux-headers/asm-mips/unistd_o32.h b/linux-headers/asm-mips/unistd_o32.h index 757c68f2ad..ae9d334d96 100644 --- a/linux-headers/asm-mips/unistd_o32.h +++ b/linux-headers/asm-mips/unistd_o32.h @@ -427,5 +427,9 @@ #define __NR_set_mempolicy_home_node (__NR_Linux + 450) #define __NR_cachestat (__NR_Linux + 451) #define __NR_fchmodat2 (__NR_Linux + 452) +#define __NR_map_shadow_stack (__NR_Linux + 453) +#define __NR_futex_wake (__NR_Linux + 454) +#define __NR_futex_wait (__NR_Linux + 455) +#define __NR_futex_requeue (__NR_Linux + 456) #endif /* _ASM_UNISTD_O32_H */ diff --git a/linux-headers/asm-powerpc/unistd_32.h b/linux-headers/asm-powerpc/unistd_32.h index 8ef94bbac1..b9b23d66d7 100644 --- a/linux-headers/asm-powerpc/unistd_32.h +++ b/linux-headers/asm-powerpc/unistd_32.h @@ -434,6 +434,10 @@ #define __NR_set_mempolicy_home_node 450 #define __NR_cachestat 451 #define __NR_fchmodat2 452 +#define __NR_map_shadow_stack 453 +#define __NR_futex_wake 454 +#define __NR_futex_wait 455 +#define __NR_futex_requeue 456 #endif /* _ASM_UNISTD_32_H */ diff --git a/linux-headers/asm-powerpc/unistd_64.h b/linux-headers/asm-powerpc/unistd_64.h index 0e7ee43e88..cbb4b3e8f7 100644 --- a/linux-headers/asm-powerpc/unistd_64.h +++ b/linux-headers/asm-powerpc/unistd_64.h @@ -406,6 +406,10 @@ #define __NR_set_mempolicy_home_node 450 #define __NR_cachestat 451 #define __NR_fchmodat2 452 +#define __NR_map_shadow_stack 453 +#define __NR_futex_wake 454 +#define __NR_futex_wait 455 +#define __NR_futex_requeue 456 #endif /* _ASM_UNISTD_64_H */ diff --git a/linux-headers/asm-riscv/kvm.h b/linux-headers/asm-riscv/kvm.h index 992c5e4071..60d3b21dea 100644 --- a/linux-headers/asm-riscv/kvm.h +++ b/linux-headers/asm-riscv/kvm.h @@ -80,6 +80,7 @@ struct kvm_riscv_csr { unsigned long sip; unsigned long satp; unsigned long scounteren; + unsigned long senvcfg; }; /* AIA CSR registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG */ @@ -93,6 +94,11 @@ struct kvm_riscv_aia_csr { unsigned long iprio2h; }; +/* Smstateen CSR for KVM_GET_ONE_REG and KVM_SET_ONE_REG */ +struct kvm_riscv_smstateen_csr { + unsigned long sstateen0; +}; + /* TIMER registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG */ struct kvm_riscv_timer { __u64 frequency; @@ -131,6 +137,8 @@ enum KVM_RISCV_ISA_EXT_ID { KVM_RISCV_ISA_EXT_ZICSR, KVM_RISCV_ISA_EXT_ZIFENCEI, KVM_RISCV_ISA_EXT_ZIHPM, + KVM_RISCV_ISA_EXT_SMSTATEEN, + KVM_RISCV_ISA_EXT_ZICOND, KVM_RISCV_ISA_EXT_MAX, }; @@ -148,6 +156,7 @@ enum KVM_RISCV_SBI_EXT_ID { KVM_RISCV_SBI_EXT_PMU, KVM_RISCV_SBI_EXT_EXPERIMENTAL, KVM_RISCV_SBI_EXT_VENDOR, + KVM_RISCV_SBI_EXT_DBCN, KVM_RISCV_SBI_EXT_MAX, }; @@ -178,10 +187,13 @@ enum KVM_RISCV_SBI_EXT_ID { #define KVM_REG_RISCV_CSR (0x03 << KVM_REG_RISCV_TYPE_SHIFT) #define KVM_REG_RISCV_CSR_GENERAL (0x0 << KVM_REG_RISCV_SUBTYPE_SHIFT) #define KVM_REG_RISCV_CSR_AIA (0x1 << KVM_REG_RISCV_SUBTYPE_SHIFT) +#define KVM_REG_RISCV_CSR_SMSTATEEN (0x2 << KVM_REG_RISCV_SUBTYPE_SHIFT) #define KVM_REG_RISCV_CSR_REG(name) \ (offsetof(struct kvm_riscv_csr, name) / sizeof(unsigned long)) #define KVM_REG_RISCV_CSR_AIA_REG(name) \ (offsetof(struct kvm_riscv_aia_csr, name) / sizeof(unsigned long)) +#define KVM_REG_RISCV_CSR_SMSTATEEN_REG(name) \ + (offsetof(struct kvm_riscv_smstateen_csr, name) / sizeof(unsigned long)) /* Timer registers are mapped as type 4 */ #define KVM_REG_RISCV_TIMER (0x04 << KVM_REG_RISCV_TYPE_SHIFT) diff --git a/linux-headers/asm-s390/unistd_32.h b/linux-headers/asm-s390/unistd_32.h index 716fa368ca..c093e6d5f9 100644 --- a/linux-headers/asm-s390/unistd_32.h +++ b/linux-headers/asm-s390/unistd_32.h @@ -425,5 +425,9 @@ #define __NR_set_mempolicy_home_node 450 #define __NR_cachestat 451 #define __NR_fchmodat2 452 +#define __NR_map_shadow_stack 453 +#define __NR_futex_wake 454 +#define __NR_futex_wait 455 +#define __NR_futex_requeue 456 #endif /* _ASM_S390_UNISTD_32_H */ diff --git a/linux-headers/asm-s390/unistd_64.h b/linux-headers/asm-s390/unistd_64.h index b2a11b1d13..114c0569a4 100644 --- a/linux-headers/asm-s390/unistd_64.h +++ b/linux-headers/asm-s390/unistd_64.h @@ -373,5 +373,9 @@ #define __NR_set_mempolicy_home_node 450 #define __NR_cachestat 451 #define __NR_fchmodat2 452 +#define __NR_map_shadow_stack 453 +#define __NR_futex_wake 454 +#define __NR_futex_wait 455 +#define __NR_futex_requeue 456 #endif /* _ASM_S390_UNISTD_64_H */ diff --git a/linux-headers/asm-x86/unistd_32.h b/linux-headers/asm-x86/unistd_32.h index d749ad1c24..329649c377 100644 --- a/linux-headers/asm-x86/unistd_32.h +++ b/linux-headers/asm-x86/unistd_32.h @@ -443,6 +443,10 @@ #define __NR_set_mempolicy_home_node 450 #define __NR_cachestat 451 #define __NR_fchmodat2 452 +#define __NR_map_shadow_stack 453 +#define __NR_futex_wake 454 +#define __NR_futex_wait 455 +#define __NR_futex_requeue 456 #endif /* _ASM_UNISTD_32_H */ diff --git a/linux-headers/asm-x86/unistd_64.h b/linux-headers/asm-x86/unistd_64.h index cea67282eb..4583606ce6 100644 --- a/linux-headers/asm-x86/unistd_64.h +++ b/linux-headers/asm-x86/unistd_64.h @@ -366,6 +366,9 @@ #define __NR_cachestat 451 #define __NR_fchmodat2 452 #define __NR_map_shadow_stack 453 +#define __NR_futex_wake 454 +#define __NR_futex_wait 455 +#define __NR_futex_requeue 456 #endif /* _ASM_UNISTD_64_H */ diff --git a/linux-headers/asm-x86/unistd_x32.h b/linux-headers/asm-x86/unistd_x32.h index 5b2e79bf4c..146d74d8e4 100644 --- a/linux-headers/asm-x86/unistd_x32.h +++ b/linux-headers/asm-x86/unistd_x32.h @@ -318,6 +318,9 @@ #define __NR_set_mempolicy_home_node (__X32_SYSCALL_BIT + 450) #define __NR_cachestat (__X32_SYSCALL_BIT + 451) #define __NR_fchmodat2 (__X32_SYSCALL_BIT + 452) +#define __NR_futex_wake (__X32_SYSCALL_BIT + 454) +#define __NR_futex_wait (__X32_SYSCALL_BIT + 455) +#define __NR_futex_requeue (__X32_SYSCALL_BIT + 456) #define __NR_rt_sigaction (__X32_SYSCALL_BIT + 512) #define __NR_rt_sigreturn (__X32_SYSCALL_BIT + 513) #define __NR_ioctl (__X32_SYSCALL_BIT + 514) diff --git a/linux-headers/linux/iommufd.h b/linux-headers/linux/iommufd.h index 218bf7ac98..806d98d09c 100644 --- a/linux-headers/linux/iommufd.h +++ b/linux-headers/linux/iommufd.h @@ -47,6 +47,8 @@ enum { IOMMUFD_CMD_VFIO_IOAS, IOMMUFD_CMD_HWPT_ALLOC, IOMMUFD_CMD_GET_HW_INFO, + IOMMUFD_CMD_HWPT_SET_DIRTY_TRACKING, + IOMMUFD_CMD_HWPT_GET_DIRTY_BITMAP, }; /** @@ -347,20 +349,86 @@ struct iommu_vfio_ioas { }; #define IOMMU_VFIO_IOAS _IO(IOMMUFD_TYPE, IOMMUFD_CMD_VFIO_IOAS) +/** + * enum iommufd_hwpt_alloc_flags - Flags for HWPT allocation + * @IOMMU_HWPT_ALLOC_NEST_PARENT: If set, allocate a HWPT that can serve as + * the parent HWPT in a nesting configuration. + * @IOMMU_HWPT_ALLOC_DIRTY_TRACKING: Dirty tracking support for device IOMMU is + * enforced on device attachment + */ +enum iommufd_hwpt_alloc_flags { + IOMMU_HWPT_ALLOC_NEST_PARENT = 1 << 0, + IOMMU_HWPT_ALLOC_DIRTY_TRACKING = 1 << 1, +}; + +/** + * enum iommu_hwpt_vtd_s1_flags - Intel VT-d stage-1 page table + * entry attributes + * @IOMMU_VTD_S1_SRE: Supervisor request + * @IOMMU_VTD_S1_EAFE: Extended access enable + * @IOMMU_VTD_S1_WPE: Write protect enable + */ +enum iommu_hwpt_vtd_s1_flags { + IOMMU_VTD_S1_SRE = 1 << 0, + IOMMU_VTD_S1_EAFE = 1 << 1, + IOMMU_VTD_S1_WPE = 1 << 2, +}; + +/** + * struct iommu_hwpt_vtd_s1 - Intel VT-d stage-1 page table + * info (IOMMU_HWPT_DATA_VTD_S1) + * @flags: Combination of enum iommu_hwpt_vtd_s1_flags + * @pgtbl_addr: The base address of the stage-1 page table. + * @addr_width: The address width of the stage-1 page table + * @__reserved: Must be 0 + */ +struct iommu_hwpt_vtd_s1 { + __aligned_u64 flags; + __aligned_u64 pgtbl_addr; + __u32 addr_width; + __u32 __reserved; +}; + +/** + * enum iommu_hwpt_data_type - IOMMU HWPT Data Type + * @IOMMU_HWPT_DATA_NONE: no data + * @IOMMU_HWPT_DATA_VTD_S1: Intel VT-d stage-1 page table + */ +enum iommu_hwpt_data_type { + IOMMU_HWPT_DATA_NONE, + IOMMU_HWPT_DATA_VTD_S1, +}; + /** * struct iommu_hwpt_alloc - ioctl(IOMMU_HWPT_ALLOC) * @size: sizeof(struct iommu_hwpt_alloc) - * @flags: Must be 0 + * @flags: Combination of enum iommufd_hwpt_alloc_flags * @dev_id: The device to allocate this HWPT for - * @pt_id: The IOAS to connect this HWPT to + * @pt_id: The IOAS or HWPT to connect this HWPT to * @out_hwpt_id: The ID of the new HWPT * @__reserved: Must be 0 + * @data_type: One of enum iommu_hwpt_data_type + * @data_len: Length of the type specific data + * @data_uptr: User pointer to the type specific data * * Explicitly allocate a hardware page table object. This is the same object * type that is returned by iommufd_device_attach() and represents the * underlying iommu driver's iommu_domain kernel object. * - * A HWPT will be created with the IOVA mappings from the given IOAS. + * A kernel-managed HWPT will be created with the mappings from the given + * IOAS via the @pt_id. The @data_type for this allocation must be set to + * IOMMU_HWPT_DATA_NONE. The HWPT can be allocated as a parent HWPT for a + * nesting configuration by passing IOMMU_HWPT_ALLOC_NEST_PARENT via @flags. + * + * A user-managed nested HWPT will be created from a given parent HWPT via + * @pt_id, in which the parent HWPT must be allocated previously via the + * same ioctl from a given IOAS (@pt_id). In this case, the @data_type + * must be set to a pre-defined type corresponding to an I/O page table + * type supported by the underlying IOMMU hardware. + * + * If the @data_type is set to IOMMU_HWPT_DATA_NONE, @data_len and + * @data_uptr should be zero. Otherwise, both @data_len and @data_uptr + * must be given. */ struct iommu_hwpt_alloc { __u32 size; @@ -369,13 +437,26 @@ struct iommu_hwpt_alloc { __u32 pt_id; __u32 out_hwpt_id; __u32 __reserved; + __u32 data_type; + __u32 data_len; + __aligned_u64 data_uptr; }; #define IOMMU_HWPT_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_HWPT_ALLOC) +/** + * enum iommu_hw_info_vtd_flags - Flags for VT-d hw_info + * @IOMMU_HW_INFO_VTD_ERRATA_772415_SPR17: If set, disallow read-only mappings + * on a nested_parent domain. + * https://www.intel.com/content/www/us/en/content-details/772415/content-details.html + */ +enum iommu_hw_info_vtd_flags { + IOMMU_HW_INFO_VTD_ERRATA_772415_SPR17 = 1 << 0, +}; + /** * struct iommu_hw_info_vtd - Intel VT-d hardware information * - * @flags: Must be 0 + * @flags: Combination of enum iommu_hw_info_vtd_flags * @__reserved: Must be 0 * * @cap_reg: Value of Intel VT-d capability register defined in VT-d spec @@ -404,6 +485,20 @@ enum iommu_hw_info_type { IOMMU_HW_INFO_TYPE_INTEL_VTD, }; +/** + * enum iommufd_hw_capabilities + * @IOMMU_HW_CAP_DIRTY_TRACKING: IOMMU hardware support for dirty tracking + * If available, it means the following APIs + * are supported: + * + * IOMMU_HWPT_GET_DIRTY_BITMAP + * IOMMU_HWPT_SET_DIRTY_TRACKING + * + */ +enum iommufd_hw_capabilities { + IOMMU_HW_CAP_DIRTY_TRACKING = 1 << 0, +}; + /** * struct iommu_hw_info - ioctl(IOMMU_GET_HW_INFO) * @size: sizeof(struct iommu_hw_info) @@ -415,6 +510,8 @@ enum iommu_hw_info_type { * the iommu type specific hardware information data * @out_data_type: Output the iommu hardware info type as defined in the enum * iommu_hw_info_type. + * @out_capabilities: Output the generic iommu capability info type as defined + * in the enum iommu_hw_capabilities. * @__reserved: Must be 0 * * Query an iommu type specific hardware information data from an iommu behind @@ -439,6 +536,81 @@ struct iommu_hw_info { __aligned_u64 data_uptr; __u32 out_data_type; __u32 __reserved; + __aligned_u64 out_capabilities; }; #define IOMMU_GET_HW_INFO _IO(IOMMUFD_TYPE, IOMMUFD_CMD_GET_HW_INFO) + +/* + * enum iommufd_hwpt_set_dirty_tracking_flags - Flags for steering dirty + * tracking + * @IOMMU_HWPT_DIRTY_TRACKING_ENABLE: Enable dirty tracking + */ +enum iommufd_hwpt_set_dirty_tracking_flags { + IOMMU_HWPT_DIRTY_TRACKING_ENABLE = 1, +}; + +/** + * struct iommu_hwpt_set_dirty_tracking - ioctl(IOMMU_HWPT_SET_DIRTY_TRACKING) + * @size: sizeof(struct iommu_hwpt_set_dirty_tracking) + * @flags: Combination of enum iommufd_hwpt_set_dirty_tracking_flags + * @hwpt_id: HW pagetable ID that represents the IOMMU domain + * @__reserved: Must be 0 + * + * Toggle dirty tracking on an HW pagetable. + */ +struct iommu_hwpt_set_dirty_tracking { + __u32 size; + __u32 flags; + __u32 hwpt_id; + __u32 __reserved; +}; +#define IOMMU_HWPT_SET_DIRTY_TRACKING _IO(IOMMUFD_TYPE, \ + IOMMUFD_CMD_HWPT_SET_DIRTY_TRACKING) + +/** + * enum iommufd_hwpt_get_dirty_bitmap_flags - Flags for getting dirty bits + * @IOMMU_HWPT_GET_DIRTY_BITMAP_NO_CLEAR: Just read the PTEs without clearing + * any dirty bits metadata. This flag + * can be passed in the expectation + * where the next operation is an unmap + * of the same IOVA range. + * + */ +enum iommufd_hwpt_get_dirty_bitmap_flags { + IOMMU_HWPT_GET_DIRTY_BITMAP_NO_CLEAR = 1, +}; + +/** + * struct iommu_hwpt_get_dirty_bitmap - ioctl(IOMMU_HWPT_GET_DIRTY_BITMAP) + * @size: sizeof(struct iommu_hwpt_get_dirty_bitmap) + * @hwpt_id: HW pagetable ID that represents the IOMMU domain + * @flags: Combination of enum iommufd_hwpt_get_dirty_bitmap_flags + * @__reserved: Must be 0 + * @iova: base IOVA of the bitmap first bit + * @length: IOVA range size + * @page_size: page size granularity of each bit in the bitmap + * @data: bitmap where to set the dirty bits. The bitmap bits each + * represent a page_size which you deviate from an arbitrary iova. + * + * Checking a given IOVA is dirty: + * + * data[(iova / page_size) / 64] & (1ULL << ((iova / page_size) % 64)) + * + * Walk the IOMMU pagetables for a given IOVA range to return a bitmap + * with the dirty IOVAs. In doing so it will also by default clear any + * dirty bit metadata set in the IOPTE. + */ +struct iommu_hwpt_get_dirty_bitmap { + __u32 size; + __u32 hwpt_id; + __u32 flags; + __u32 __reserved; + __aligned_u64 iova; + __aligned_u64 length; + __aligned_u64 page_size; + __aligned_u64 data; +}; +#define IOMMU_HWPT_GET_DIRTY_BITMAP _IO(IOMMUFD_TYPE, \ + IOMMUFD_CMD_HWPT_GET_DIRTY_BITMAP) + #endif diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index 0d74ee999a..549fea3a97 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -264,6 +264,7 @@ struct kvm_xen_exit { #define KVM_EXIT_RISCV_SBI 35 #define KVM_EXIT_RISCV_CSR 36 #define KVM_EXIT_NOTIFY 37 +#define KVM_EXIT_LOONGARCH_IOCSR 38 /* For KVM_EXIT_INTERNAL_ERROR */ /* Emulate instruction failed. */ @@ -336,6 +337,13 @@ struct kvm_run { __u32 len; __u8 is_write; } mmio; + /* KVM_EXIT_LOONGARCH_IOCSR */ + struct { + __u64 phys_addr; + __u8 data[8]; + __u32 len; + __u8 is_write; + } iocsr_io; /* KVM_EXIT_HYPERCALL */ struct { __u64 nr; @@ -1188,6 +1196,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_COUNTER_OFFSET 227 #define KVM_CAP_ARM_EAGER_SPLIT_CHUNK_SIZE 228 #define KVM_CAP_ARM_SUPPORTED_BLOCK_SIZES 229 +#define KVM_CAP_ARM_SUPPORTED_REG_MASK_RANGES 230 #ifdef KVM_CAP_IRQ_ROUTING @@ -1358,6 +1367,7 @@ struct kvm_dirty_tlb { #define KVM_REG_ARM64 0x6000000000000000ULL #define KVM_REG_MIPS 0x7000000000000000ULL #define KVM_REG_RISCV 0x8000000000000000ULL +#define KVM_REG_LOONGARCH 0x9000000000000000ULL #define KVM_REG_SIZE_SHIFT 52 #define KVM_REG_SIZE_MASK 0x00f0000000000000ULL @@ -1558,6 +1568,7 @@ struct kvm_s390_ucas_mapping { #define KVM_ARM_MTE_COPY_TAGS _IOR(KVMIO, 0xb4, struct kvm_arm_copy_mte_tags) /* Available with KVM_CAP_COUNTER_OFFSET */ #define KVM_ARM_SET_COUNTER_OFFSET _IOW(KVMIO, 0xb5, struct kvm_arm_counter_offset) +#define KVM_ARM_GET_REG_WRITABLE_MASKS _IOR(KVMIO, 0xb6, struct reg_mask_range) /* ioctl for vm fd */ #define KVM_CREATE_DEVICE _IOWR(KVMIO, 0xe0, struct kvm_create_device) diff --git a/linux-headers/linux/psp-sev.h b/linux-headers/linux/psp-sev.h index 12ccb70099..bcb21339ee 100644 --- a/linux-headers/linux/psp-sev.h +++ b/linux-headers/linux/psp-sev.h @@ -68,6 +68,7 @@ typedef enum { SEV_RET_INVALID_PARAM, SEV_RET_RESOURCE_LIMIT, SEV_RET_SECURE_DATA_INVALID, + SEV_RET_INVALID_KEY = 0x27, SEV_RET_MAX, } sev_ret_code; diff --git a/linux-headers/linux/stddef.h b/linux-headers/linux/stddef.h index 9bb07083ac..bf9749dd14 100644 --- a/linux-headers/linux/stddef.h +++ b/linux-headers/linux/stddef.h @@ -27,8 +27,13 @@ union { \ struct { MEMBERS } ATTRS; \ struct TAG { MEMBERS } ATTRS NAME; \ - } + } ATTRS +#ifdef __cplusplus +/* sizeof(struct{}) is 1 in C++, not 0, can't use C version of the macro. */ +#define __DECLARE_FLEX_ARRAY(T, member) \ + T member[0] +#else /** * __DECLARE_FLEX_ARRAY() - Declare a flexible array usable in a union * @@ -49,3 +54,5 @@ #ifndef __counted_by #define __counted_by(m) #endif + +#endif /* _LINUX_STDDEF_H */ diff --git a/linux-headers/linux/userfaultfd.h b/linux-headers/linux/userfaultfd.h index 59978fbaae..953c75feda 100644 --- a/linux-headers/linux/userfaultfd.h +++ b/linux-headers/linux/userfaultfd.h @@ -40,7 +40,8 @@ UFFD_FEATURE_EXACT_ADDRESS | \ UFFD_FEATURE_WP_HUGETLBFS_SHMEM | \ UFFD_FEATURE_WP_UNPOPULATED | \ - UFFD_FEATURE_POISON) + UFFD_FEATURE_POISON | \ + UFFD_FEATURE_WP_ASYNC) #define UFFD_API_IOCTLS \ ((__u64)1 << _UFFDIO_REGISTER | \ (__u64)1 << _UFFDIO_UNREGISTER | \ @@ -216,6 +217,11 @@ struct uffdio_api { * (i.e. empty ptes). This will be the default behavior for shmem * & hugetlbfs, so this flag only affects anonymous memory behavior * when userfault write-protection mode is registered. + * + * UFFD_FEATURE_WP_ASYNC indicates that userfaultfd write-protection + * asynchronous mode is supported in which the write fault is + * automatically resolved and write-protection is un-set. + * It implies UFFD_FEATURE_WP_UNPOPULATED. */ #define UFFD_FEATURE_PAGEFAULT_FLAG_WP (1<<0) #define UFFD_FEATURE_EVENT_FORK (1<<1) @@ -232,6 +238,7 @@ struct uffdio_api { #define UFFD_FEATURE_WP_HUGETLBFS_SHMEM (1<<12) #define UFFD_FEATURE_WP_UNPOPULATED (1<<13) #define UFFD_FEATURE_POISON (1<<14) +#define UFFD_FEATURE_WP_ASYNC (1<<15) __u64 features; __u64 ioctls; diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h index acf72b4999..8e175ece31 100644 --- a/linux-headers/linux/vfio.h +++ b/linux-headers/linux/vfio.h @@ -277,8 +277,8 @@ struct vfio_region_info { #define VFIO_REGION_INFO_FLAG_CAPS (1 << 3) /* Info supports caps */ __u32 index; /* Region index */ __u32 cap_offset; /* Offset within info struct of first cap */ - __u64 size; /* Region size (bytes) */ - __u64 offset; /* Region offset from start of device fd */ + __aligned_u64 size; /* Region size (bytes) */ + __aligned_u64 offset; /* Region offset from start of device fd */ }; #define VFIO_DEVICE_GET_REGION_INFO _IO(VFIO_TYPE, VFIO_BASE + 8) @@ -294,8 +294,8 @@ struct vfio_region_info { #define VFIO_REGION_INFO_CAP_SPARSE_MMAP 1 struct vfio_region_sparse_mmap_area { - __u64 offset; /* Offset of mmap'able area within region */ - __u64 size; /* Size of mmap'able area */ + __aligned_u64 offset; /* Offset of mmap'able area within region */ + __aligned_u64 size; /* Size of mmap'able area */ }; struct vfio_region_info_cap_sparse_mmap { @@ -450,9 +450,9 @@ struct vfio_device_migration_info { VFIO_DEVICE_STATE_V1_RESUMING) __u32 reserved; - __u64 pending_bytes; - __u64 data_offset; - __u64 data_size; + __aligned_u64 pending_bytes; + __aligned_u64 data_offset; + __aligned_u64 data_size; }; /* @@ -476,7 +476,7 @@ struct vfio_device_migration_info { struct vfio_region_info_cap_nvlink2_ssatgt { struct vfio_info_cap_header header; - __u64 tgt; + __aligned_u64 tgt; }; /* @@ -816,7 +816,7 @@ struct vfio_device_gfx_plane_info { __u32 drm_plane_type; /* type of plane: DRM_PLANE_TYPE_* */ /* out */ __u32 drm_format; /* drm format of plane */ - __u64 drm_format_mod; /* tiled mode */ + __aligned_u64 drm_format_mod; /* tiled mode */ __u32 width; /* width of plane */ __u32 height; /* height of plane */ __u32 stride; /* stride of plane */ @@ -829,6 +829,7 @@ struct vfio_device_gfx_plane_info { __u32 region_index; /* region index */ __u32 dmabuf_id; /* dma-buf id */ }; + __u32 reserved; }; #define VFIO_DEVICE_QUERY_GFX_PLANE _IO(VFIO_TYPE, VFIO_BASE + 14) @@ -863,9 +864,10 @@ struct vfio_device_ioeventfd { #define VFIO_DEVICE_IOEVENTFD_32 (1 << 2) /* 4-byte write */ #define VFIO_DEVICE_IOEVENTFD_64 (1 << 3) /* 8-byte write */ #define VFIO_DEVICE_IOEVENTFD_SIZE_MASK (0xf) - __u64 offset; /* device fd offset of write */ - __u64 data; /* data to be written */ + __aligned_u64 offset; /* device fd offset of write */ + __aligned_u64 data; /* data to be written */ __s32 fd; /* -1 for de-assignment */ + __u32 reserved; }; #define VFIO_DEVICE_IOEVENTFD _IO(VFIO_TYPE, VFIO_BASE + 16) @@ -1434,6 +1436,27 @@ struct vfio_device_feature_mig_data_size { #define VFIO_DEVICE_FEATURE_MIG_DATA_SIZE 9 +/** + * Upon VFIO_DEVICE_FEATURE_SET, set or clear the BUS mastering for the device + * based on the operation specified in op flag. + * + * The functionality is incorporated for devices that needs bus master control, + * but the in-band device interface lacks the support. Consequently, it is not + * applicable to PCI devices, as bus master control for PCI devices is managed + * in-band through the configuration space. At present, this feature is supported + * only for CDX devices. + * When the device's BUS MASTER setting is configured as CLEAR, it will result in + * blocking all incoming DMA requests from the device. On the other hand, configuring + * the device's BUS MASTER setting as SET (enable) will grant the device the + * capability to perform DMA to the host memory. + */ +struct vfio_device_feature_bus_master { + __u32 op; +#define VFIO_DEVICE_FEATURE_CLEAR_MASTER 0 /* Clear Bus Master */ +#define VFIO_DEVICE_FEATURE_SET_MASTER 1 /* Set Bus Master */ +}; +#define VFIO_DEVICE_FEATURE_BUS_MASTER 10 + /* -------- API for Type1 VFIO IOMMU -------- */ /** @@ -1449,7 +1472,7 @@ struct vfio_iommu_type1_info { __u32 flags; #define VFIO_IOMMU_INFO_PGSIZES (1 << 0) /* supported page sizes info */ #define VFIO_IOMMU_INFO_CAPS (1 << 1) /* Info supports caps */ - __u64 iova_pgsizes; /* Bitmap of supported page sizes */ + __aligned_u64 iova_pgsizes; /* Bitmap of supported page sizes */ __u32 cap_offset; /* Offset within info struct of first cap */ __u32 pad; }; diff --git a/linux-headers/linux/vhost.h b/linux-headers/linux/vhost.h index f5c48b61ab..649560c685 100644 --- a/linux-headers/linux/vhost.h +++ b/linux-headers/linux/vhost.h @@ -219,4 +219,12 @@ */ #define VHOST_VDPA_RESUME _IO(VHOST_VIRTIO, 0x7E) +/* Get the group for the descriptor table including driver & device areas + * of a virtqueue: read index, write group in num. + * The virtqueue index is stored in the index field of vhost_vring_state. + * The group ID of the descriptor table for this specific virtqueue + * is returned via num field of vhost_vring_state. + */ +#define VHOST_VDPA_GET_VRING_DESC_GROUP _IOWR(VHOST_VIRTIO, 0x7F, \ + struct vhost_vring_state) #endif From 1583ca8aa61e1648d1f340c9a6ae3cd7ba3a82ae Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 18 Dec 2023 17:43:19 -0300 Subject: [PATCH 57/65] linux-headers: riscv: add ptrace.h KVM vector support for RISC-V requires the linux-header ptrace.h. Signed-off-by: Daniel Henrique Barboza Acked-by: Alistair Francis Message-ID: <20231218204321.75757-3-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- linux-headers/asm-riscv/ptrace.h | 132 +++++++++++++++++++++++++++++++ scripts/update-linux-headers.sh | 3 + 2 files changed, 135 insertions(+) create mode 100644 linux-headers/asm-riscv/ptrace.h diff --git a/linux-headers/asm-riscv/ptrace.h b/linux-headers/asm-riscv/ptrace.h new file mode 100644 index 0000000000..1e3166caca --- /dev/null +++ b/linux-headers/asm-riscv/ptrace.h @@ -0,0 +1,132 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (C) 2012 Regents of the University of California + */ + +#ifndef _ASM_RISCV_PTRACE_H +#define _ASM_RISCV_PTRACE_H + +#ifndef __ASSEMBLY__ + +#include + +#define PTRACE_GETFDPIC 33 + +#define PTRACE_GETFDPIC_EXEC 0 +#define PTRACE_GETFDPIC_INTERP 1 + +/* + * User-mode register state for core dumps, ptrace, sigcontext + * + * This decouples struct pt_regs from the userspace ABI. + * struct user_regs_struct must form a prefix of struct pt_regs. + */ +struct user_regs_struct { + unsigned long pc; + unsigned long ra; + unsigned long sp; + unsigned long gp; + unsigned long tp; + unsigned long t0; + unsigned long t1; + unsigned long t2; + unsigned long s0; + unsigned long s1; + unsigned long a0; + unsigned long a1; + unsigned long a2; + unsigned long a3; + unsigned long a4; + unsigned long a5; + unsigned long a6; + unsigned long a7; + unsigned long s2; + unsigned long s3; + unsigned long s4; + unsigned long s5; + unsigned long s6; + unsigned long s7; + unsigned long s8; + unsigned long s9; + unsigned long s10; + unsigned long s11; + unsigned long t3; + unsigned long t4; + unsigned long t5; + unsigned long t6; +}; + +struct __riscv_f_ext_state { + __u32 f[32]; + __u32 fcsr; +}; + +struct __riscv_d_ext_state { + __u64 f[32]; + __u32 fcsr; +}; + +struct __riscv_q_ext_state { + __u64 f[64] __attribute__((aligned(16))); + __u32 fcsr; + /* + * Reserved for expansion of sigcontext structure. Currently zeroed + * upon signal, and must be zero upon sigreturn. + */ + __u32 reserved[3]; +}; + +struct __riscv_ctx_hdr { + __u32 magic; + __u32 size; +}; + +struct __riscv_extra_ext_header { + __u32 __padding[129] __attribute__((aligned(16))); + /* + * Reserved for expansion of sigcontext structure. Currently zeroed + * upon signal, and must be zero upon sigreturn. + */ + __u32 reserved; + struct __riscv_ctx_hdr hdr; +}; + +union __riscv_fp_state { + struct __riscv_f_ext_state f; + struct __riscv_d_ext_state d; + struct __riscv_q_ext_state q; +}; + +struct __riscv_v_ext_state { + unsigned long vstart; + unsigned long vl; + unsigned long vtype; + unsigned long vcsr; + unsigned long vlenb; + void *datap; + /* + * In signal handler, datap will be set a correct user stack offset + * and vector registers will be copied to the address of datap + * pointer. + */ +}; + +struct __riscv_v_regset_state { + unsigned long vstart; + unsigned long vl; + unsigned long vtype; + unsigned long vcsr; + unsigned long vlenb; + char vreg[]; +}; + +/* + * According to spec: The number of bits in a single vector register, + * VLEN >= ELEN, which must be a power of 2, and must be no greater than + * 2^16 = 65536bits = 8192bytes + */ +#define RISCV_MAX_VLENB (8192) + +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_RISCV_PTRACE_H */ diff --git a/scripts/update-linux-headers.sh b/scripts/update-linux-headers.sh index 34295c0fe5..a0006eec6f 100755 --- a/scripts/update-linux-headers.sh +++ b/scripts/update-linux-headers.sh @@ -156,6 +156,9 @@ for arch in $ARCHLIST; do cp_portable "$tmpdir/bootparam.h" \ "$output/include/standard-headers/asm-$arch" fi + if [ $arch = riscv ]; then + cp "$tmpdir/include/asm/ptrace.h" "$output/linux-headers/asm-riscv/" + fi done rm -rf "$output/linux-headers/linux" From 0d71f0a34938a6ac11953ae3dbec40113d2838a1 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 18 Dec 2023 17:43:20 -0300 Subject: [PATCH 58/65] target/riscv/kvm: do PR_RISCV_V_SET_CONTROL during realize() Linux RISC-V vector documentation (Document/arch/riscv/vector.rst) mandates a prctl() in order to allow an userspace thread to use the Vector extension from the host. This is something to be done in realize() time, after init(), when we already decided whether we're using RVV or not. We don't have a realize() callback for KVM yet, so add kvm_cpu_realize() and enable RVV for the thread via PR_RISCV_V_SET_CONTROL. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-ID: <20231218204321.75757-4-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/kvm/kvm-cpu.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index 841756ab9b..d7d6fb1af0 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -18,6 +18,7 @@ #include "qemu/osdep.h" #include +#include #include @@ -47,6 +48,9 @@ #include "sysemu/runstate.h" #include "hw/riscv/numa.h" +#define PR_RISCV_V_SET_CONTROL 69 +#define PR_RISCV_V_VSTATE_CTRL_ON 2 + void riscv_kvm_aplic_request(void *opaque, int irq, int level) { kvm_set_irq(kvm_state, irq, !!level); @@ -1496,11 +1500,36 @@ static void kvm_cpu_instance_init(CPUState *cs) } } +/* + * We'll get here via the following path: + * + * riscv_cpu_realize() + * -> cpu_exec_realizefn() + * -> kvm_cpu_realize() (via accel_cpu_common_realize()) + */ +static bool kvm_cpu_realize(CPUState *cs, Error **errp) +{ + RISCVCPU *cpu = RISCV_CPU(cs); + int ret; + + if (riscv_has_ext(&cpu->env, RVV)) { + ret = prctl(PR_RISCV_V_SET_CONTROL, PR_RISCV_V_VSTATE_CTRL_ON); + if (ret) { + error_setg(errp, "Error in prctl PR_RISCV_V_SET_CONTROL, code: %s", + strerrorname_np(errno)); + return false; + } + } + + return true; +} + static void kvm_cpu_accel_class_init(ObjectClass *oc, void *data) { AccelCPUClass *acc = ACCEL_CPU_CLASS(oc); acc->cpu_instance_init = kvm_cpu_instance_init; + acc->cpu_target_realize = kvm_cpu_realize; } static const TypeInfo kvm_cpu_accel_type_info = { From 3ca78c0689d504366d7c8dc516e7144940aa7c0c Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 18 Dec 2023 17:43:21 -0300 Subject: [PATCH 59/65] target/riscv/kvm: add RVV and Vector CSR regs Add support for RVV and Vector CSR KVM regs vstart, vl and vtype. Support for vregs[] requires KVM side changes and an extra reg (vlenb) and will be added later. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-ID: <20231218204321.75757-5-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/kvm/kvm-cpu.c | 74 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index d7d6fb1af0..680a729cd8 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -105,6 +105,10 @@ static uint64_t kvm_riscv_reg_id_u64(uint64_t type, uint64_t idx) #define RISCV_FP_D_REG(idx) kvm_riscv_reg_id_u64(KVM_REG_RISCV_FP_D, idx) +#define RISCV_VECTOR_CSR_REG(env, name) \ + kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_VECTOR, \ + KVM_REG_RISCV_VECTOR_CSR_REG(name)) + #define KVM_RISCV_GET_CSR(cs, env, csr, reg) \ do { \ int _ret = kvm_get_one_reg(cs, RISCV_CSR_REG(env, csr), ®); \ @@ -158,6 +162,7 @@ static KVMCPUConfig kvm_misa_ext_cfgs[] = { KVM_MISA_CFG(RVH, KVM_RISCV_ISA_EXT_H), KVM_MISA_CFG(RVI, KVM_RISCV_ISA_EXT_I), KVM_MISA_CFG(RVM, KVM_RISCV_ISA_EXT_M), + KVM_MISA_CFG(RVV, KVM_RISCV_ISA_EXT_V), }; static void kvm_cpu_get_misa_ext_cfg(Object *obj, Visitor *v, @@ -709,6 +714,65 @@ static void kvm_riscv_put_regs_timer(CPUState *cs) env->kvm_timer_dirty = false; } +static int kvm_riscv_get_regs_vector(CPUState *cs) +{ + CPURISCVState *env = &RISCV_CPU(cs)->env; + target_ulong reg; + int ret = 0; + + if (!riscv_has_ext(env, RVV)) { + return 0; + } + + ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vstart), ®); + if (ret) { + return ret; + } + env->vstart = reg; + + ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vl), ®); + if (ret) { + return ret; + } + env->vl = reg; + + ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vtype), ®); + if (ret) { + return ret; + } + env->vtype = reg; + + return 0; +} + +static int kvm_riscv_put_regs_vector(CPUState *cs) +{ + CPURISCVState *env = &RISCV_CPU(cs)->env; + target_ulong reg; + int ret = 0; + + if (!riscv_has_ext(env, RVV)) { + return 0; + } + + reg = env->vstart; + ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vstart), ®); + if (ret) { + return ret; + } + + reg = env->vl; + ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vl), ®); + if (ret) { + return ret; + } + + reg = env->vtype; + ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vtype), ®); + + return ret; +} + typedef struct KVMScratchCPU { int kvmfd; int vmfd; @@ -1004,6 +1068,11 @@ int kvm_arch_get_registers(CPUState *cs) return ret; } + ret = kvm_riscv_get_regs_vector(cs); + if (ret) { + return ret; + } + return ret; } @@ -1044,6 +1113,11 @@ int kvm_arch_put_registers(CPUState *cs, int level) return ret; } + ret = kvm_riscv_put_regs_vector(cs); + if (ret) { + return ret; + } + if (KVM_PUT_RESET_STATE == level) { RISCVCPU *cpu = RISCV_CPU(cs); if (cs->cpu_index == 0) { From e0299f71b34cb511257bcb0d2ed698b7c2a42ef4 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 4 Jan 2024 15:15:23 +0800 Subject: [PATCH 60/65] docs/system/riscv: sifive_u: Update S-mode U-Boot image build instructions Currently, the documentation outlines the process for building the S-mode U-Boot image using `make menuconfig` and manual actions within the menuconfig UI. However, this approach is fragile due to Kconfig options potentially changing across different releases. For example, CONFIG_OF_PRIOR_STAGE has been replaced by CONFIG_BOARD since v2022.01 release, and CONFIG_TEXT_BASE has been moved to the 'General setup' menu from the 'Boot options' menu in v2024.01 release. This update aims to make the S-mode U-Boot image build instructions future-proof. It leverages the 'config' script provided in the U-Boot source tree to edit the .config file, followed by a `make olddefconfig`. Validated with U-Boot v2024.01 release. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-ID: <20240104071523.273702-1-bmeng@tinylab.org> Signed-off-by: Alistair Francis --- docs/system/riscv/sifive_u.rst | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/docs/system/riscv/sifive_u.rst b/docs/system/riscv/sifive_u.rst index 7b166567f9..8f55ae8e31 100644 --- a/docs/system/riscv/sifive_u.rst +++ b/docs/system/riscv/sifive_u.rst @@ -210,7 +210,7 @@ command line options with ``qemu-system-riscv32``. Running U-Boot -------------- -U-Boot mainline v2021.07 release is tested at the time of writing. To build a +U-Boot mainline v2024.01 release is tested at the time of writing. To build a U-Boot mainline bootloader that can be booted by the ``sifive_u`` machine, use the sifive_unleashed_defconfig with similar commands as described above for Linux: @@ -325,15 +325,10 @@ configuration of U-Boot: $ export CROSS_COMPILE=riscv64-linux- $ make sifive_unleashed_defconfig - $ make menuconfig - -then manually select the following configuration: - - * Device Tree Control ---> Provider of DTB for DT Control ---> Prior Stage bootloader DTB - -and unselect the following configuration: - - * Library routines ---> Allow access to binman information in the device tree + $ ./scripts/config --enable OF_BOARD + $ ./scripts/config --disable BINMAN_FDT + $ ./scripts/config --disable SPL + $ make olddefconfig This changes U-Boot to use the QEMU generated device tree blob, and bypass running the U-Boot SPL stage. @@ -352,17 +347,13 @@ It's possible to create a 32-bit U-Boot S-mode image as well. $ export CROSS_COMPILE=riscv64-linux- $ make sifive_unleashed_defconfig - $ make menuconfig - -then manually update the following configuration in U-Boot: - - * Device Tree Control ---> Provider of DTB for DT Control ---> Prior Stage bootloader DTB - * RISC-V architecture ---> Base ISA ---> RV32I - * Boot options ---> Boot images ---> Text Base ---> 0x80400000 - -and unselect the following configuration: - - * Library routines ---> Allow access to binman information in the device tree + $ ./scripts/config --disable ARCH_RV64I + $ ./scripts/config --enable ARCH_RV32I + $ ./scripts/config --set-val TEXT_BASE 0x80400000 + $ ./scripts/config --enable OF_BOARD + $ ./scripts/config --disable BINMAN_FDT + $ ./scripts/config --disable SPL + $ make olddefconfig Use the same command line options to boot the 32-bit U-Boot S-mode image: From 2abf0da22cbe7152940a2a90e7a4b7ba70ef04e7 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 2 Jan 2024 22:47:33 +0800 Subject: [PATCH 61/65] roms/opensbi: Upgrade from v1.3.1 to v1.4 Upgrade OpenSBI from v1.3.1 to v1.4 and the pre-built bios images. The v1.4 release includes the following commits: 1a398d9 lib: sbi: Add Zicntr as a HART ISA extension 669089c lib: sbi: Add Zihpm as a HART ISA extension 72b9c8f lib: sbi: Alphabetically sort HART ISA extensions 5359fc6 lib: sbi: Rename hart_pmu_get_allowed_bits() function 976895c lib: sbi: Fix Priv spec version for [m|s]counteren and mcountinhibit CSRs 6053917 lib: sbi: Fix how print gets flags 35ef182 lib: sbi: print not fill '0' when left-aligned 40dac06 lib: sbi: Add '+' flags for print 458fa74 lib: sbi: Add ' ' '\'' flags for print 05cbb6e lib: sbi: implifying the parameters of printi fe08281 lib: sbi: print add 'o' type c6ee5ae lib: sbi: Fix printi 3b6fcdd lib: sbi: Simplify prints cc89fa7 lib: sbi: Fix printc ff43168 lib: sbi: Fix timing of clearing tbuf a73982d lib: sbi: Fix missing '\0' when buffer szie equal 1 ea6533a lib: utils/gpio: Fix RV32 compile error for designware GPIO driver c3b98c6 include: sbi: Add macro definitions for mseccfg CSR 1c099c4 lib: sbi: Add functions to manipulate PMP entries 6c202c5 include: sbi: Add Smepmp specific access flags for PMP entries cbcfc7b lib: sbi: Add smepmp in hart extensions d72f5f1 lib: utils: Add detection of Smepmp from ISA string in FDT 4a42a23 lib: sbi: Grant SU R/W/X permissions to whole memory f3fdd04 lib: sbi: Change the order of PMP initialization 5dd8db5 lib: sbi: Add support for Smepmp 6e44ef6 lib: sbi: Add functions to map/unmap shared memory 0ad8660 lib: sbi: Map/Unmap debug console shared memory buffers 057eb10 lib: utils/gpio: Fix RV32 compile error for designware GPIO driver 0e2111e libfdt: fix SPDX license identifiers e05a9cf lib: sbi: Update system suspend to spec 5e20d25 include: sbi: fix CSR define of mseccfg 44c5151 include: sbi_utils: Remove driver pointer from struct i2c_adapter 14a35b0 lib: utils/regmap: Add generic regmap access library 8e97275 lib: utils/regmap: Add simple FDT based regmap framework f21d8f7 lib: utils/regmap: Add simple FDT based syscon regmap driver 4a344a9 lib: utils/reset: Add syscon based reboot and poweroff c2e6027 lib: utils/reset: Remove SiFive Test reset driver f536e0b gitignore: allow gitignore to ignore most dot file c744ed7 lib: sbi_pmu: Enable noncontigous hpm event and counters 6259b2e lib: utils/fdt: Fix fdt_parse_isa_extensions() implementation f46a564 lib: sbi: Fix typo for finding fixed event counter 94197a8 fw_base.S: Fix assembler error with clang 16+ c104c60 lib: sbi: Add support for smcntrpmf 7aabeee Makefile: Fix grep warning e7e73aa platform: generic: allwinner: correct mhpmevent count ee1f83c lib: sbi_pmu: remove mhpm_count field in hart feature a9cffd6 firmware: payload: test: Change to SBI v2.0 DBCN ecalls b20bd47 lib: sbi: improve the definition of SBI_IPI_EVENT_MAX 664692f lib: sbi_pmu: ensure update hpm counter before starting counting c9a296d platform: generic: allwinner: fix OF process for T-HEAD c9xx pmu 901d3d7 lib: sbi_pmu: keep overflow interrupt of stopped hpm counter disabled cacfba3 platform: Allow platforms to specify the size of tlb fifo 5bd9694 lib: sbi: alloc tlb fifo by sbi_malloc 130e65d lib: sbi: Implement SET_FS_DIRTY() to make sure the mstatus FS dirty is set d1e4dff lib: sbi: Introduce HART index in sbi_scratch e6125c3 lib: sbi: Remove sbi_platform_hart_index/invalid() functions 296e70d lib: sbi: Extend sbi_hartmask to support both hartid and hartindex e632cd7 lib: sbi: Use sbi_scratch_last_hartindex() in remote TLB managment 78c667b lib: sbi: Prefer hartindex over hartid in IPI framework 22d6ff8 lib: sbi: Remove sbi_scratch_last_hartid() macro 112daa2 lib: sbi: Maximize the use of HART index in sbi_domain 9560fb3 include: sbi: Remove sbi_hartmask_for_each_hart() macro b8fb96e include: sbi_domain: Fix permission test macros bff27c1 lib: sbi: Factor-out Smepmp configuration as separate function 5240d31 lib: sbi: Don't clear mseccfg.MML bit in sbi_hart_smepmp_configure() 2b51a9d lib: sbi: Fix pmp_flags for Smepmp read-only shared region 73aea28 lib: sbi: Populate M-only Smepmp entries before setting mseccfg.MML e8bc162 lib: utils/serial: Add shared regions for serial drivers b7e9d34 lib: utils/regmap: Mark syscon region as shared read-write 3669153 platform: generic: thead: fix stale TLB entries for th1520/sg2042 de525ac firmware: Remove ALIGN in .rela.dyn in linker script 2a6d725 firmware: Remove handling of R_RISCV_{32,64} 6ed125a Makefile: Add --exclude-libs ALL to avoid .dynsym e21901d doc: Fix fw_payload.md a125423 lib: utils/serial: Ensure proper allocation of PMP entries for uart8250 d36709f lib: utils: timer/ipi: Update memregion flags for PLMT and PLICSW 8197c2f lib: sbi: fix sbi_domain_get_assigned_hartmask() 9da30f6 lib: utils/fdt: simplify dt_parse_isa_extensions 942aca2 lib: utils: Simplify SET_ISA_EXT_MAP() f831b93 lib: sbi_pmu: check for index overflows d891cae gpio/starfive: redundant readl() call e8114c6 docs: platform: update platform_requirements.md 3632f2b lib: sbi: Add support for mconfigptr ec0559e lib: sbi_misaligned_ldst: Fix handling of C.SWSP and C.SDSP cbdd869 include: sbi: Change spec version to 2.0 5d0ed1b lib: sbi: simplify sanitize_domain() c1a6987 platform: generic: thead: move to thead c9xx header to vendor specific postion 8e941e7 platform: generic: thead: separate implement of T-HEAD c9xx pmu 492d9b1 platform: generic: thead: separate implement of T-HEAD c9xx errata 3e21b96 platform: generic: thead: initialize PMU by default in thead generic platform a140a4e lib: sbi: Correctly limit flushes to a single ASID/VMID 88ae718 platform: generic: thead: improve tlb flush errata 52fd64b platform: Uses hart count as the default size of tlb info 07f2ccd lib: utils/serial: Optimize semihosting_putc implementation fccdf41 firmware: fw_base.S: Fix boot hart status synchronization d1e0f7f utils/reset: Remove fdt_reset_thead 896d2c9 lib: utils/timer: Allow ACLINT MTIMER driver to setup quirks accafb1 lib: utils/timer: mtimer: add separate T-Head C9xx CLINT mtimer compatible 98bc25f lib: utils/ipi: mswi: add separate T-Head C9xx CLINT mswi compatible 5b2f55d lib: sbi: separate the swap operation of domain region 3b03cdd lib: sbi: Add regions merging when sanitizing domain region 2bfdb9e platform: generic: Add Sophgo sg2042 platform support 280f7ae include: sbi: macros for mseccfg.sseed and .useed efcac33 lib: sbi: Add Zkr in hart extensions 6e5b0cf lib: sbi: enable seed access in S-mode 6602e11 lib: sbi: change sbi_hart_features.extensions as an array 3aaed4f lib: sbi: Make console_puts/console_putc interchangeable dc0bb19 lib: utils/serial: remove semihosting_putc 16bb930 lib: sbi: Fix PMP granularity handling in sbi_hart_map_saddr() 574b9c8 lib: sbi_pmu: avoid buffer overflow 791704c lib: utils/irqchip: Avoid redundant writes to APLIC CLRIE register f520256 lib: sbi: Allow relaxed MMIO writes in device ipi_send() callback b70d628 lib: sbi: Allow relaxed MMIO writes in device ipi_clear() callback bd74931 lib: ipi: Adjust Andes PLICSW to single-bit-per-hart scheme 291403f sbi: sbi_pmu: Improve sbi_pmu_init() error handling 090fa99 lib: sbi: Add XAndesPMU in hart extensions a48f2cf sbi: sbi_pmu: Add hw_counter_filter_mode() to pmu device 51ec60c platform: include: andes45: Add PMU related CSR defines effd89a platform: generic: Introduce pmu_init() platform override 1b9e743 platform: andes: Add Andes custom PMU support 2e50c24 platform: andes: Enable Andes PMU for AE350 535c661 platform: rzfive: Enable Andes PMU for RZ/Five 0b3262e lib: utils: fdt_fixup: Allow preserving PMU properties 009ae4e platform: andes: Factor out is_andes() helper 0308f93 lib: utils: fdt_pmu: Make the fdt_pmu_evt_select table global variable e19d419 lib: utils: fdt_pmu: Do not iterate over the fdt_pmu_evt_select table d162009 docs: pmu: Add Andes PMU node example 6b9a849 lib: sbi: Remove xchg/cmpxchg implemented via lr/sc 11bf49b lib: sbi: Fix __atomic_op_bit_ord and comments 8839869 lib: sbi: Replace __atomic_op_bit_ord with __atomic intrinsics 07419ec lib: sbi: Prevent redundant sbi_ipi_process 93da66b lib: sbi_hart: Store PMP granularity as log base 2 ee72517 lib: sbi_pmu: Add PMU snapshot definitions 11a0ba5 lib: sbi_pmu: Fix the counter info function 0696810 firmware: fix section types a25fc74 lib: sbi_hsm: Put the resume_pending hart in the interruptible hart mask 87aa306 platform: recalculate heap size to support new tlb entry number a2e254e lib: sbi: skip wait_for_coldboot when coolboot done 6112d58 lib: utils/fdt: Allow to use reg-names when parsing ACLINT 35cba92 lib: sbi_tlb: Check tlb_range_flush_limit only once per request a894187 lib: sbi_ipi: Do not ignore errors from sbi_ipi_send() 446fa65 lib: sbi_ipi: Process self-IPIs in sbi_ipi_send() 2707250 lib: sbi_ipi: Drop unnecessary ipi_process check 925ce14 lib: sbi: Simplify the initialization of root_hmask in sbi_domain_init 2c8be56 lib: sbi: Improve the code of privilege mode and extensions detection 056fe6f lib: sbi: Refactor the code for enable extensions in menvfg CSR 776770d lib: sbi: Using one array to define the name of extensions 3daac8f lib: sbi: Detect extensions from the ISA string in DT 416ceb3 lib: sbi_tlb: Reduce size of struct sbi_tlb_info 80169b2 platform: generic: Fine tune fw_platform_calculate_heap_size() cdebae2 lib: utils/irqchip: Add shared MMIO region for PLIC in root domain 3284bea lib: sbi: Allow ecall handlers to directly update register state 5a57e8c lib: sbi: Remove the SBI_ETRAP error code 2b80b92 lib: sbi: Do not enter OpenSBI with mseccfg.MML == 1 63e09ad lib: sbi: Fix shift bug in sbi_system_reset ba29293 lib: utils/timer: mtimer: only use regname for aclint bbd065d lib: sbi: Detect Zicntr extension only based on traps a2b255b include: Bump-up version to 1.4 Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-Id: <20240102151153.133896-1-bmeng@tinylab.org> Signed-off-by: Alistair Francis --- .../opensbi-riscv32-generic-fw_dynamic.bin | Bin 135376 -> 267416 bytes .../opensbi-riscv64-generic-fw_dynamic.bin | Bin 138368 -> 270808 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 9a2ba3f2a4d0e1e52c909cd71960410e118ef374..60ca1165c820ff29b984566db22b9453541da19a 100644 GIT binary patch literal 267416 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

Kn$E>?ccR=a(r$DZuoz{Z9LY{alojSBS zO55Faxz~sJvGq|Z*G3q^y+S&_`z6+c7f}xh?=3A4Mtmz47Jy`JE@C-91{iGMO+)_# z(dJKMjAXJ3Xn(^(FYQu6q5jfgX*3r*vyRK7U7uC4sqeqWd*2>)<2`q;=0t$^**?a) z>~lZy1gFtUgAD^XYJ9D)-Fl9peN~rED_`0%kC(J$j%2PS!H(i{+=i5E#X2-7Nn=eT zy-eIG_KdU4h13+8GxqPs!FgcNFUDbYSg3jEljCrU#^Kh-mkL00D%~T&-*=A$-;h-Cnn}U$+?H}(DE&a*3jrZNAke%M^V$mit`{dk%>zW`#|)-0G>Ro%)nuX?-J;1y6al> zmKfEl;^Wg(i>W4PxINS885mI?1)WK^{tV8O581G{k1$&dVQ=4Ns22O;hm0oiT)XgN zwbJt7fr7O0wf#0iE+@5d(HyDX_DyUVS=x={nbr7mzb5oB23!Z68(%hyditjy)6|#r z{Z_A1LN+NAG;?<-{k50 zMv~4nzM~rjHNN5Tca~v}K8U z2>Z*c*g>R`Yi}IMUQYYub6Wy;S4gsP#Jzt~cPs2ey}aL$m-gFgTf!oYNsiHRLHY1W zi;M*mN!A33muQy}A6X0^4|VyymVJ3C=VImQE9IsuN6(j6o<4K2;`;IGqj!$nD`9ZM zfpm-Cp0q33xq5S@pyFc4&cDFhxjO%>_Qh>V!JGSSp*}*V?b{ELA(Ucd28t3NJjn6hYk<@Bgo zduD~q&YZ1!qhZ3LiBYk8Viy@JC#r#kttzYxlW8|17&TK*w}#nLVw(bfq&v%mIK#kX zj@q;7B>6WlHx7+LObo?Nbv^C}3C-AZ&6IV{hspXB z*2Yarc`gE_d7PIhGa%Tq-9(ob|ykH({h#KWg3aTiwLgCC}_ltpiR|xv^eUcj-InG_-KnY<3pp@3EyqPq2x! z`r%)vOD%83$!AIaqrXoqtvU9adngA_7sw}!O$;#(FEWHcA8g)bWzX?>JXZ1yV1n-W>j8g2sjf75+({KZ?qJQ0 zEkau-aOWMFwujQ19+RoTiuU5+1EXbsCf(g~8OP$kHLM*sHGRXOj67P8TfckFSU(5r zbJHff1+iSPE~k8Z2sJ6V$}RSTDeLUN#tVn=ph>00d>HjhcEA2BympNKRk==mcfWsl z9j(Gy_=VLonSKZF4vhHMUSy;j6?u`tDZI;OhA!6`nmxp@igBp8GaA+5CQ;JQ44E?g zI~sxA`y^^W@_j&(dy>~Lr?`E!&wm2HTUnt=(wYcP5Le0(+&4YNItw;u;x^ujlSs!Y zVPn=RQ9w)TNMDJ*2wZM7I}O2+@aOC|&IUa#JeP{k^Q-(Q71zglsTTMygg%THv&~^O zVjUTSSBl>&6i+%Pz$DUQf1!8zKZxH1CUVXX@AfzqN7S3eE5U_5JZq{KaaIEw+S}oa z{ZClKp@>-XVx&tuxStDl4r{0dj-%W|3D1NWH1ItxuJl&dZx#KOuHdWC-iDpjbl6G# z8Jy2Qz)tEqtd7ZV%-QrFe3Dq0(XF2}2brGI2ypMx`G0aJG;=(mKNR|)b$Mtwv>fRiKS`(l z1Ze1xA3o^D(Ytv#+elwdwhCfuhc2uKE_6B8>D$E|%#ML8FW`iB$vCT0d|ToBJzETLx-SA}eFEyk)ufTRQ&8)7I3@ZRPctuD_ zRQD1qINFdYM-7I3J@meKA+?n0Ha-G8rW|mTKjjZ*tkE48B?xq1j2C|qwdAIi;0bUb z^K$SBX}JV_<1zmQ7$c^2obifclTYVx6_Fj(3oM9H3h*fnAxVtp z3UJ_?po2HV8XLOPgcCKD_-!$fEfsj~iA>m{YFIT1to`O$SWCUlhAk`x<@7eY<&!=J z(94Tp+te@v(C%#5hcf|%JOs98acLJ)=YmR_RAcNSbmK(NfkV9Z=@oDv(h7wzKmq?W5}%>}fWn2A9#PD}%v~Eq zt1rl%10#lVg(?gBLb~u|mld}792@pgSI`n+i%Z$Nkd$k`X@Fg=v0b}e)yDnXymQmF zf3HT~V&tuchFuY)6&M++{pmITy`jzVLXSpwzf3l%Uz3wp71Mmg>V;|W;VsTb#1e2+ zV)9_grBSPEX?E7Wx*ojZ4Uvj(4l|l*Ce|{AzJnRKgx?wBEU*?0tk|B%^D}sUZVjt> zV-0J0VGV4*(5{Qfzc~>W)x$9(_S-!f`~5I@kh9-=kFoze3?5EQjJ2&-b-V{ zs{hDpUSGq6EsUeldG8=&zx@}K4q@&0-h>B}{;=|Iz)Wf}#{)2%H!+)dck3S3feJjg z^9;O}EIi0KtJ2CjuU_DR9Bw_Obi_9QjP(wyd7iv~l`(&?;+@ka^7kO+I>G$7ldQwNM;|?los6!qcEXFAaIV#D6r5i0*PBm_a zwzRr>xL9lNLsG3vA2_19Hh2sXtr|P(ldN*cZ{gG4{U@EkWhaCaocGG3dy;F8j!A7Q zB|j_IO^EZ71p4MqXd><{1EIawRMu|WD6AOXrSKj1ek`0g`Wt7#$G4}J{nBIKBFrT1 zDzYgexlN2!xYMc@+j6F1q6{U=4U%bc>~#zMLBN zm)EgBIo4URbhj<_y6H{m1K%?`Dt#Wh^{jrL^|+?hdqzns(c;4t*5%jFy_T;HI>2iC zx|oQCeSB!&!RK^sMk#4i`uq5+=~iVqi-oj0b}$p-<>upfl3Twi-)G7H}~3I#=hGzbrG z1tszDE8h1(vk>pqGh*QwQ+#ARqRL4<3LKYXHmWS(R*Ss>zxhN8@tUE%mr|4NuezM# z*!)k(s1LV9EXM9_9!a;NE_|)jmTW!f(;3;%NKf-)Z7H}}`+**9mReT*jtD8pFIz~M zp+%Tl+ch*jep0;7(BGH&z+~(yj^kB~qa~3ETmBXHTLZo=+K*y32OIo-?Kc}3$HvPp z%cp~w9vNckC@MW7tsz}3U4gcvH14;+1Ye1zKM*+@{=S#fj9neiHn@6Z2x;D3*~x4a zB#>#GFJ_IkoW>vUNZ6toz!%@59N__4L;l>{G)LA?E}?2kSHUyPHzdG8;=t{Je74KnbVu*+LGL9rZz!rLVxuK16q-7`eBhn9g$q?N~@(g&&p$IADnag!H{cy{aajhE*EY>ogj?;(~saHAS#J>qm-k$>e_n9qeph%lQL)s%gIzH0>8)wx=Rn%77dZQA$ z`llbjmhdx1Tqjj;o`eLah*nhda8Qba+T+~IpX%&n$4F#_ew!3=agGMDhDH?7u z{v3IMfUFGbMWj=(L;i(FXK*k(q%1KOJn|S}fn+w$R8qZ^BjwU&p#?lksUF=A+=`1B^+V zFr`-6{X}2{tNV2$;XdPO1|i2ooFWDu!l@N2AW07?Qk6bkl5SN(Q!L@|$64XpAoz!S z@or_e*3 zB~7@EH&~R)W<^NkL)rnW!lG|d+WmLYg}@q(Qg5St#obYG@+Qs|PNb-taDqH<7?{w6 zJ4e-(Wa~K(aG&-4pu2T5H;~?akp%rQ@$KRPq(4R+J|U5RmbAGniHnzKjbB8OY#$?731iY*QW8Qh)Q}4U;phU0ScEIaceXnnXE+Z8jZ#UjR z&acwXwh8xB6_k@SmU5CE>vGyHJl|?JL7KZ-)uy{@>7r~Nl}+!$5JybQ@NEJAB+lZG zT`XS7sy^9$x;VVvXfgy(VBW+yeU!8izq`N+BjKUuTz$l<oZBvru%8=)Mcojk zB?Z3w6~JHMW5!kCl>0RtF>Oc_XxD^4kJ$98<|?b5tH0Q`T%0EHHGyslTa<1FXO8fWIVsN7T* z=s{3fVIM?+$|9Lsf5_Avn?}00r{3_S^Ox0~%_E-)LK!!hEJh|>k?f~Btfy9cf~MzH zFXG%#axdcCXwe3#nA7s<&#bt4rL zUHFezp-pr?P7#Q9_j%NAH+8rOay*GTq;>~jrO*lF{*vl|ct0 zE4;gwko{6E&J@9e>xrG)0@|j>uUgUY2=A^XN{XUbkiO=B-4^(7ch|D$f26j&lyL2T z+avgYch_RtDb}*%YCC!)TFszGexM?gV2$*jsS6wY(I%SJm5I=r1kKMgTX@HFjcqLa zs8B>qW$WmPubJM27ku$6wM#d1UZ5sCKqZ5Ak8DNkz>@|<#KcIpo=uNGrp>;CS}rnM zyd2$=T!_QUUMPLK4c%Kf!7Ue`4KG|QTn28lda-#bhCQGc7Lq4R#!vY3Ii@b)8M2uO z7v4VSA&lpt!Ao3x_!@j=CR=Geuse@uSfQZV1F0XSBaznWPvkWPc=3h#oAiD8x%o2^ zFC$%*HzV<`J{Ekt3~@gnkf~$gI5%eMvMwbNl4-qrwh@9Fu zsfPTk;NlL5tiv9x;k&!BZ^=5j{>%QLUnA>$CJGB%ds_HtrG}68bI-c=YaaSdj$Vyz z?sBTNQn`5-ZK*2@6~BqB`v>;+;x2`6Yu@+`tlrs)d7?EIZhN_~z3SGR2}}H1ynkaq zKjJ840vDZ1^WyD|AF?slv*~{=BJI9PlQx7`Y9!7BS==$vY4-XI8t;oFdZ)k*kwWLL6Lm&lknK*Yq0 zTY=GVqG?|58LsW8W_KTeelobbg@42duoh{rl257+7o!~6xe+&rtk*CC1utbl68FHO zOn~iL2rNeTz3c;X3HP-x(r@K`?O;kH?`!+k zc+Axce`)mF5&+!@4?}jcL^ox9RK~(rND?uqKC34+vsi| zXys(bIPQ+k=&ozgJ2Y#X_c*+{^M(+tI=$n=bLYi+&`;_w-EN;A|G-(W)C5T$NgdJ8 zO~V}Bxf|m7*yix#ZctxgA$JD-45pl#ND;iNZ>YMhc8Mmx-ExXbbA8dl@L*4Gfyq-@THIQuIh!8xEZMMJ(*Lm z8*)l;3P9bQP2Y0zOu>c%xu~3rz57n@lCjpmre%D; z?4V_QWIGH=&%84&BNTC=#MR3=YASy^R}ZJXFBkGklHkpUj7b*Ed`MupVB$mOgyVh? zVjoq&B*C8dP;yjCs=C)9VUwySWNs}MZ)MAj#A=fq1F35B_mIW(!yTdpeQ!CHj(YlH z#ff=D3+A9>;2m%z39Gug4_r5#UkNRk(-vUQHT*MziRf)*i#EFjUK72E_6GIQ$^?d2 z%WHNKM;L5QIGs-P3wNIMmAJ(!TT-Kh#s+Wf=>ZR#jZs4UIq!%++EPJ5HM0|4bJz}x zV4qrEwjs5}GIU~!yAib1sniZHe4+*Lj`mBCJC5g+Xzz~va{R_kTBO~o=C$;`N&OW5 zaKgh9ki=Tz@Yf@WIRUQM2drjx5?KZR*E_Hhg;nU9rmi>_S~%E%TFy1V0?nA{nB3GL zEX`sA!#VFT@2m)Iww1-0H4FC=eda)mD-oQYr~C0E9$7H3S3II8BT_QS=Hc@kX{fTL zaJPf=tacbYt0D6j_jpcU=Z=?L4lnLT=lPOh!^AVb>V?ZV;Z^RLn43QIBvv}c9VdHG z3q$iO65no@HbM-;ZG$Bo}sGpEjXY3&^C$^-6Hj2(KVtm(brbubkLf_`1}}}s)J5*0@)w` zg{;VFTsb{E5w~kkX#7RHHU2=+W6fjzhG#=)!0*mD+Z0#1PhV8#T|h8$&~n`VCy$rh*I6n)40-=w`EIDTTrWYKs-H)>`h zyPww2$)*NvP%>7@zmg3Qy#*X6Vvssg2Xxj;iYTFGuy{+5cCgy7{ZlqdGRD z^Qc}e{CA^T|NmfArCVl9fePBR+Y`i?e>?JzV29v_$?9`}8;N>!-huQ3`i2`1OST}L zakO-IXL?HB%E(JjOaHZp#GeETWUhRQ^i|lOjq7uix;{8wC%&`h{}4 z;?T0WY1_?cS-8yzPUDc;7l8*Np%K9)v=D}#e315Vs2TVM`020{YBH06z~d}0-gy9__R^_hUp6UjLm4Jb#C{G*WM(WLWs@CA;Z#cXQk6T%MXPaU5oXKEG)4*Gna;k5X+^yK_j@40T?p z`NVe)-s_4u*V&Uxp;Z;mT`5E)Nxs(7JCw2h4Rf5Fyj`C2?E#o`jn9cvIwk0&W4{sQ z0NG1HNjk=J7vrPeG>LC^q$jL8RgL~{KfKa4JMo_B9qIj$aLB+NlexldcMhIeQ z=;2qPGp8r)gBffzVqz#Dr`%$wqZDWFh{VB}frpGLN4K9^m!Rdr-w{3gxCD%Jy-E5L zYL@WE_OIY&>YySDyI+spABEkoU&1UA}*cTe_luu;utW_s(Nz#XX4&cPA z6m4&YiB958$DG;uKO2G}X-Wb12=d))OMKI~u2e9JRAB4IADtEDc@o~aVp@Px6#L`% zqO>C03E#+$DO~f@^cp0tmz$R->pIR~`Ldgv_c)|@e#Y5mpyiU@@4p{)K zv%`s759lRNQNEEW-pA))eP>^-h9{|z!)@SAAj-zMcJ(J(JZbpqcKB&f7QXGzfiL#x z7U_C3FhZ7>O4`oQg@LV91Kl8rCq_3&0bVJzL1$U2)iSez-Gy_%59c^s-zrPMhzgY3 zmLuZ0m#)F5=5$WB#wVGHZke`Ue4w`PxR3mekk}bs&G;BZpi9bXcFkTXRSDspfmU>jeY(>yn7Y0mJlRB=`mMWZKO;hQbOqof#!J58B4JPrnhWBih+w?R?1WJU1d8T{z5x0RsuK~R&tmvczCw?^_mgnL8e4NDL6BY7fuB7(ie$|kI-{w#C` zRk(f7J^F@F8Os_%4m&UtH#Qv77%&c%t5}V}1RkD>v2Pp=dK7+*Hh`08HACa*yd0gv ze)~3Y6K+^8m>H_e-c$qVZ`m;ZzgRC`+8w6f9V9Foq+x+GJd9rcU5wrizqxhnL_<(v zpaQGV&@UoTF^~;33@m(35gPxTAvEGS#c$Z>48JLS*6?D)vx-6NvxY&1y%rc1FUCK+ z606q|Fo@CcKJYHWxAwJuNuE3Ev`p?#oKNrF(pMKP7d_4oDd-!T0^Qe#M04RJ5clPx zNi^0KD{<<0T4pA}kB@XmqqDj2ow?#o4e!Nsn)V!>3K}nEwZ9&`RCy{7=EDDtlsE6M%d@Tc>r_Ux3k%o{jXqB2 z=PdZ>OE*Sz<4SnLa?v|h)X}^Yku@IC-W?=Wc$6bNJftHBwGOf4%G|M~De{sD)*|Jx=6XOfdMgq>EfFVZ7~-zyhP$ItyK}OS@UnC!72^bg->NoYCdYK(MOpqV z&BbhtSN7GEcTa&1ZcEiWT(?>SBPefY`rzr(_yDv>JGk+c(_#ef&Qdn=+BYo8ZHG%b zY_J!D7d?N`7FUw8xn*nyQI``Aews0=UUxD{!%f>4_v?PRe`dqiUxFiwgQh6#9!LXs z$dG4k39%vtFUuFZZ8GI|V=`2)Oe-jV%jj#0{t3{bgrvR+EmKFQY6rlNKICUo*^+2i9F@** zk>Sb06i!LnWT~Yo<3)|;>~A;tL`k@Kp(y`v+t=rsq4Z_QetCF0Y=SR@&N6)3pSX>~ z3n{f=^Tri*?iLW|64n(=ETsEQvLE;k9d)JTBaIxq;iELagiF)ORB7zLmOR0uuykK|pHzoVl zl94gKBq@9c9AQtNiLf;67av2G9@KV+DY1T4FT!!qBr>UW&Wd|$9M7oRW}Bq1Z+%7j zdhiJNx?FvExAfNdTj_1_OHRL++6&1JTHNLEpj!CYJ{9Gqj3?c$hP<=!2Enj~MGq5@ z%dAdSaf|XeKV~Gy{2g?`O@iAJ+&QE@+@ZZKJ^P=ac;MK}yK@<7=XbBwa8KL)9VI*V zndD#e@m=;(!@t^P*kN~Qhs6le4x`;Q)`H!IJ8{SE3jYKA7(iwNO92tfZM`Dxu7d|x zh@Nsoj*@lXo&;D(sUEa}&YY*dY0y7t)2@Ed3BySH?pBxYr}etl8TU!MaN(sf@ceMK z&0icN2~$dQQ9M+d3vPhZZ)tVM=u@9N>nD*XVXJ7Xym*FT8_y`V=@}tK?V(xO&yM+<(v6klvyb|6-62C}L49&Kb z(?(k&8^yi1Y4WJa)-OPrrlkd*AHROQu%wi?C>z_umRlJ?qfjZng0}whFh=lEDC<*p z-WHlqs_tupzBhbH?>~Sxr2<-qe{K#_tYIua|IBNdX>AIvvU$0m_In?L`IG&b8or_3 z)k9e9e8r3Zz}j>C2UZVwTxvLQzklrkA-zFaKlf=?c9pQRd(XHhmaOdV_hr7Pc4&j9 zH*1#P=e4UBGSW8`-!IFLk1fnwzP9?n^8Qr^9G_J;bE-Pt$T^-p@v|miG!w?>MtJd| zRyJymZW(7ES<8&cq}a1dD&_rfQL&9zJ*$F`eB3N?yVR}3EprJYMTR(mxCmexUhd4JM zYT{BrSEk@*uIZ72HH8S#X_{#%&mPvn<_mk)9lky}23bG*H<8&E7M*Y3wMX8-m`$x}84}eVfQtkyd7% zx1(X(O+)T+29e!GJL2L3^kMD1yT~(@`$-zX@V~f6F#IE1l1$&`i?E=o_mES^LE6zl zJ)1tGaj4SauH~sYhjyZ^mdqrEsOO0H#5R(o!@FxOplIt4u+C0o>3s(kY}!wwsSWxA ze5Qs+fNu=%nDD2mfnUuY$x=V5j+ylPY2~BxI+Y*oc!RrQOZBlYU)uw#)9*kkeudyy z(19)AEnhnVzlI#xhj&r<6@FkHe$BwIDF+4tx(L7KAK>uo1N?gbKyN@z__g}LP`t~; zueAr%_?3fS*$4Unx(B~@9B}PhzP1Fv3J#pbuS)!?IB<8Tj9V``3(~d|Pr?d16FwmR zDcL6F%#zkn&@jhL?z}D4h>|LlWDe-|b&RiSyOgWoCCBSrr7d;aPDn1A_88x_H_aWr z538+bz3P5{2KsY+U}_QJpNPdx>FY}G_s{+--uY!X;`Qh|bTsE2!k+H$C+4g_=gxVp zogzh${S@P;;ihm}a1me)auoN=Hi`pGW#=3s+Dx+0Af3u-98{Y?vz&4&`B_dmUVfHS&QpGtQ%)^E%PHq2Kg%iCMShl3&Rc$# zQ_e?zmQ${){4A%Ouly{h3|CA2|3OZtvGTK=PVtmeXlI^0S;y>ncCX=`>&Y zSx);8;TURf{~_JwG+0iD%c)LIOU@D5opr)F`JJa=KMccgtz9oSv1_n{rw&ro7z$L^s@<&+;L zKg%f}CO^w5|FZlnr~GjFSx)&8^0S=sAf&0kiE_&SR(_UKew6$yr~E7Ovz+q3lb_|3 z|GoSyr~GL7Sx)&e^0S=sW94T#C43?2bxV;(oEdgDm*LFr``j)u zrYLb4XCM*}MKM`=fsGMn1Gj|EA0n94%>DlJ=ZF1QGqdh+*z8bNv*KCiR32<7f}EA0 zmUNCewav)kM>!;1<+crjzjD(q*d#MAD{^$6#>I+Uqo*Zq52Gop%gFG!cUnmtZDcw(zk@H25>-x zjZKUYpk|x}T~DPHu)3k&EDs54cw=UcdX7;W?oUqC1;0FiQq+f0)*b3ds(Q$xP?2C}|t{fhR zvdoSMZyi$T! z6FgeCli=0&gM;?%BzRLE?;*i&5L~AlPVgJ|gZ=gmCwL?J?DFeh7$bx{osOq zLkV8LWig;@c@a8V=NbiFi7L$IUY8yB_xtMzx{j}+vZHjxLmgeXD;T@Ih2P5~ zO(pnw%=g|5g8yjwkPCOL=g$*#pl;JpM^~;AGro5tpzSq)201eLN`eOKwhV>#))~zC z-e5pqxDBWuyd<9?Xdm66p$>+itM?8BbZj-Co(?O2nxMUPLx(z8?lk6mZ~Z=u#|=Q0 zjtzVTL3`<3BOD%F1!jA16QCbo2h_u{kuN7`cU|Eahk`4|T<DmMM4}jC^S<4p?e3`C^ z;0G~_JDUi83UKULzz-7qUEL~ze~($*xr*Q?0mrTd{Ck2g(XAx-e$3;}l>|QlICd`J z`w6~KcYxq~F_SwF5d0Y6)bq9cUV^`++eh#{==sil1TT|!?^=Ej!RP8m6a0TLn>$An z95LU;-Mg0mAA--)jUxCi%;(Ng1TU6%?^=Er!Q*tUR{-CE8QtmnAHa*`-Mg0GLGY=% zCW3FrobGHQc%i&|*Yev59;@tc&K1ZpFaOd0wNZ{})7@5m8^{j-5`1S7}TMC`8(SPjVWLMF!Bh8%v_f0>k{ z4|2R<#Qx00dO(hL3!4k{$nk9(@Jkw21#)aoMSr&-2Mhd@Mmbv{H$I@otwfHHI$!b-nRkk&xD!Zhx`fPPg$E15YrcO*(+kHe1mhx^U%~odHnk51ls!v z_>dy!$B?V@Buc_&`iB7&1UF^=Fk@;mmn?j;N2yVPD%e!Qa8bf%r40L{bH~9SI(T!- zi7qgbym9N`0Hl!JcsQAp-%^g1qGxC>%JD^M>s#$;efc%nFR0B#9%wg=Uo$RcykpbN zPJWZg_YUJp+|V_LEQwLf+M*QM8~c6ueF=ai7DHtZr@+2qlq+*dDMl7i zOZ4UUvfN+R@24*}U6sDPSWREP_Sl!pjWH(r^5ZmD;M69E#21$0CP)#*-Yi*gnCWR4 zsPljxLZTX+Klt?aP;7%N*%l4&2jvyPcP~wkf$v)A;CO_>qJEcod-5mNOVe#hF~-3u z^edEpB`3W83G^*mSX&|@wlFg?>?7-$>lw4s!c@hGDbT`hw_5)B9HW`}EE6`om?VCQ zA4Ztd?Ob)Z=8fmzM|ux*HWo)5HHDcM$B^Kij>E*A)xgZf4>s zZ9mTAk;D!wRf=!v9^3LY(%9-L4!}>jN*c|yME7Ve-b$mnrAQjh#0TW3k7tA~Y7bcE z4p;O?q{@&o=sT(vG^?CWn%7UPu^(q)b)&| zxaVwXU^KLX{jws3FZiyPA~z)qoB6JaZHREW67ep3sk<5%!{)WCkg9%WeK`5s5;iw@ z2V5kc{Lwok1%sBapI~~K)qeT1Li@GS!^&e5TL%u{`U%bsJXbw&+i-Hl(%~ ztIx3`uf}9Jv&TFXYrL1s$j^;l+>DIC2y>|dHSf136lG21)Q)$WT2mtbQG6+K!>dQa z?eN$mbUCZCt9CQc3HBUGp4e5R7;X{h`U~B!rM!A1^3n5o|C+4ufDE*jyZOh!Q@|wI z9n!0g+s>Krv+0|Xp>z0N*#%S-lWKoY=gK0Wu;-29Gr zh=6cv>IF#ibm$i}Ic-eu!VMEI@0P~O>pYDWD9d{y`~ksx0bV9r7#9$s4 zjB-?!ghif)X(&!gcpa?{*ms`pHePU?V?5UOoRG%5W`wC4nQn*H!J@HSN8};Y*-@hO zWakogeq)=u^Sn3a`UA+s`q-Y@^%jy2skHqE@Rrk^5x(4QE0F<-tsj%q&;iRL^)H=Qg?~Bnx*$1YiBL{@=VU@)jf|^l$W1AUU}412^|`x zHt2A3e3Z8DnPx6Z+fV!*a;90sKWNepxX~OBYmNuaHly}Mc%zW^&E9~sG=jx@zw(78 z^WZbhz-k!=cn8#|mCf*15kvo@SOb^F&rMe!8$R;xLyAje$UO=@g?C%Z z3J9vr?$0U)#()PslC^F`IrG3j7y(f;iUHB^MZvRoFN)qtW_m&wBL3Lr;q|cg0rZ<_ z=0sk`;ds(H4}vFxzG_x#)xvL`Rom0|ObMBuIbAiYA$n0vWz0fgIeEO_#Axd&%1c?k z^rrt@?brQTZO%xs9a0-=-q@Y*Qz(!BwhiNZm7X6j^vv@(4?lXP9-RJoQAO#7BFv|F zip%S1B)pZKpw%SF)`)xQt|NErud8F>2xs<3?T^<%n2$K7q}>JYj^^$spfA$~3#+va zO4*J>wq==`Dsk*P$F7~5D*Tiqo_=)hDLTd2jE=keh#M%eSd zS9L#;b}GFFzHhF3El}I<%wWT6`m^u5A0N=P8;w`QCE3b)09| z2PNz{&fZwc=6N!#t0(zuDobDB74|_7_PUzd7xqpRYp)r}YO{4XCx^2kRxf^m=wHLh zRKPn0={Y_go4&ITQ^DfpWgi*D+WFdWyDBI`_))JG_-2fZnj+RQG#WH|eO2&j>w5^X z(9fo01Q4?hdQPqD#1Sy+_hdMFG}a2ey4rI<(|12$OW2lIHhm)`x!n&qT1GS$Pah=XU0b3; z-?%P|PPuah4lh!`*gA2C@ca5xV*dR{pXLD$I~ z!$ZLrBR+^fXD;J)jLW#Lqgi#`Y@!AfUE`XpI>t4LL6aD-i6l2p)Iqr4zq=Y5L?<(u zd-L1fKmI=J>#FLi>aQMM-KYLtt7)J5n*J5iqz$n4!TJVqPm@d8wuCnWk6dih&f=cK_c5NCb9aAfMxzuw^DKUM z4GjvO-Y+Ql>6=pU)Q_donPY=Wr^iv6eMpVHpB{r6Satg8r@A4*^ewinP-p;-3o)BY zUjFM8Q+ilf(k4^Eu`tu6Ps2v7Fn#{(kmTjRm+-50NN`3ve%+mel(9;Gx=Cj~qWvHX|uvKV4jh>N$-+B$T`!(um8*CV^NU6Q349($mO>fI3 z84^bQ4=pKT;*`D-&p^i+n@((!t<(F%?h9Ykqp#=5_N(;WIDAD9U#-KJ>XNPJ=o@+x zzR&i_QTmD=EY*{({dEp`O!*wEu+OfoZMfLb^$BJ1i(%(FzrsK}IlOQb&n6jY+0*;! z>dQ)}k3~C=)1~%m4yX1*Wg8N@t8(whuS(lD#FSSC?W>B3s0hM7wRLX`JMN=~sz; zZZJk|sFJ2Eq`fec{eIovn|`cen@=?FXn1U~vAwTSdN#Ey2+E{-|`(VPBiAEJzz?UA4 zMQaX0%N`blwP8V9!`@kw8csXp;fsHDw}b9|R-z}Ru5Fc7}3%CgVc&!uOK1*=Ip)w;+=HH?IUv>i6W;`94APaRMd(VW zP1KcUjL5^?W-H^y+ zTc&PZ#NN<}x@FTs<#zPzq{H|QtpClXEQ7H@~=l48HY=?$QH^+p9V0y?m!ugno*DDl=VY5o)|85UYG;f6 zRe)OT?NyCy=}Rj^>sIPs+>d9S*1OM|24T-Q*x+u5RS)I!{^UXU>dwFH4^Aj+9UVn6 zSMSF&#KSjRM^^qyqb05KoK(55GA6v??um*=uovo}k4%q7$lpPumDK7wYUFa4-UQ#M zTeFJB5pCE+*^a-fLZr{Gl}VN3RvxT^KA+T=;kl{X>{eTdZ#LiX85p#9)rby8!w|sTdpuLnNL#f>Ovh}iQ4~4zBd34xMCUlOv6rXhL>eIbl)9O>|IZ0LH(6(>9+w%@nCn|DL z8*(pdz{>DQ)a?&%w$|W_Qgapm{112GIj-N$UZGFnyQ=UVUXI$!|JmRB`&};iOn%VV!1{AJ0{zsxac@Kl~pfD`EB2SFZI< zm=)pa0#6xu!U)C_MsxTPe6yVHKs8bQu!q@{jCD~a_cwimkEh{II$M6iz>`Q&K}4$j zB%;hWXtpt3N_{vbQ=H6L~Ia~qKo`d-!EOOVzJhVK>`imLAFrE0j z0ei#ib*8qjr6ZBez4u;QqT73|N;d>-fo}U|lll36?^d0tu;MO?61P14Hr-Fr+n~H` zb%YrPSsiKn5cMCLW2iHXp+oLS;|H{Tj(UA$=*T-X4|yLvdZ-?@6bW}|wt(wz!1Z6j zQ`Xm*`D^BxqwYw$%zH;idUjSvNYmy|BZp$=pJnMW4>h#LWe%zRJ*F^AfK zIg}OFY%TP)*kpgGj%Js5=DHcGqbvP#ZT8yZYxdqgj{V5?7LF(T1zahvZpeioy831N z_b#v3?G2lxyZndWU-Lf~`sQ=bjiuk4I^M(LnX~1_rjeCD`Aja+&C*89rkXIDq9@Cv zsP`s3S-vG^Q!bbolGGPM%(+#R8f(D`n1_$v~2xelVc!tf0@s(nbFW9i7UyQWPeL!o8$2W#sqs01`h zzzWj+blnf-GMGMnHh3;tz>VrB|CcuRf*Gp4JI3|9AJaYZF7}N??lf=dc+2R1Vtv2E zxEAbeUBAgxa+7A>Ap;NNdqmEgZ8Q=o>oak-d_*IXay~sLqwQnYA$-*pzkkI zbOaX3ObE9hw2HQG}*HbX6^lB)7n8aq8icU4>2 z-!XVZs8n7UvmAB-i$BA7Zu&t))V%bZDK-5cmrRy(Q9m7Udw}VqPop*+l;7=7EPXXn zYJ6*1=71`cZe;zX0W0DD^>032kv0=;e%Dd@wFtUO;g^Rt3+Jm4fhMTb?NdB#MNt#53Q@0bjL5I{q_&^O_z`4U#jS< zm_Jp2Wl`$=3~KF?yr;Q*9Dc5TQ}tA`AiyfVzh0416WSkdC+0|@8Q7tIz<$Z(-X2sv zwY+c-_HtM2EEG0S${C+N9#q{uRNLxaeS5t~J0q@ks;Omr(Ee}!N}?U@gQ^u-Ff#`i<48t1|XupW>f~)eJa_-FOdfx?H@k_1<&tX+KBNe*E7AjYmFI#?n_` z{ox}$XCF8^vw zy9etsLZ|)e7`_IGmh|)RePSQu!Revlm#yEl{oUX>bs?_P*FSGyNtqZE5Q zt8vSbi-*0W)6Pq{9F5veQ*cA=KW@Vf!RZfi-U3e(Bza z)b#*LU;gV?>79$xzejFchOaRO4sZC^;DkttzUvY^JW7H^b>xle|M|(t3i26rs`T+J zX&LRB8|l~0`4XdkOZ%tK-KKpIpL>(iy4-xHm5z+)gU`tQkjhMZCzF*K?VN1H&dFG_ zTNT%R-^@Dt0(`&EOCQIMt>tNWA2>#b{X^wn>K~8V(x9;AKfKt0^+#9eS6=1XzRJ|> zl&oL7yt^;$oBW=9?^E9J(i1z~1xHowPk&gduOizBynP*}n}+oWq2n_jmTE!*Pu{3L zbqCgv!O4R%QB(^2+g3KF3Oub~XRz z@Q;?84u?m{XT$%u;X~`5mF+w!R(ghd-iYyWAKi0aV|Xv@ZxPZsWBBILJGzIKhnO0} z!%S<^f-&2I?I%hnr?1$HDzPaqDwTh%O?>T~*4(JO`>E%k{2^41noucZM){PnFd!7E zh05iluNUVWKD=LP)5`AJ^zK^uj&OZh(#mm_2Uo^y?kCk~bc!jy1C>N+pi)gFsic%> zX8DL8n+9W_;a3~FD%BVst>oPxE2UV(QY=-endObiKY_yC&O5Fu+|VAg;87`N3FSSs zE<-3yvDKW@lYiXP`Mpem-XWngP|Bc~-qk^-6;Fk$CFwkOL-GjJ5|vG9T|=eY(%m0m zP01_0Th-WFHD{JT^gnc;sUeD*_x5v|g{pBVuR`53_$Fx%`huc3^~f2g>3Li3k3)4m76{4Dyzf1^@p zeQQFf?}> z#6l%KQ|~1mwG^{F9KTTFN$R2AFH%0ve=>zWg#8J%`TRuQgLMqd8Wl0Q7ML#?lv!f?G360tz8`N&93&CjgEXcqK;Ms!=9BV)k)*C z@{=rC@D9M;2KF1D%{#2HV`ric4{XHxPx;Fe;&)bht|+G2RmK=^^|Oh}{axZeR)7^? z1y})AfE8c`SOHdm6<`He0aoC@gaQVGL5lNE(z_jgz0GO!>8(ba-D1|qTRa|@M;~V% z5h*PiJ!%YHY~<5!i*r_LrasOaNymDE}~gc}pYpOYx8Xqa?_S(jvN4A5WY@M(CHq>5Qs>oKi<7_+O^;Ddv1R-N|%@9F;P{ zKRTO|eS!{fh(GdCQ_Vwh>GZrOmg+}QEIL?9r{aIbU;ba_NLc(Kyp!WHNF>tM=6TUn zWOLtFUpbE3_P}tTz2L#&HiyM?-xx|c%r1w~=G0qlPNUtn#L`n$D{aAU^jTdVhZ6Jt ziBh>OCZpYc|0q(9n$}FC!=ef$yOZQ*)Db?-V)Xev7H>zKZsF6X5d-1= z$j6u4YIO_Xlu&noi!%&uZ*M~v>_elL2Vxg)rH{!?>urgjE)ly92N<0v+I zEc#TVS5-(6a*{r=B+g!f#@Z2Q7PSuTAIf0XKb5MDll!dxX{*(1QL6*xxF;RN>6%mz z=}fm6-Ca`ZAsso6HYJgcKHlf@8SNtyl;Y{*(S9tRMHX|XkKe03vU)5Q3~2c4yjGLP z=ra{{7F13P!a*BAHw?MzktD4T*Ct9e>}!ZSQZr{8Y$*nErWe80ZH=2Pw$UE@tL zn^9d}eJX+xuS+`F({r-*nNF*#vz&InJ{}D$aYBh)f$A0LQJ0X^wND6TM8LdtRQ&Wj7a~5|Ea|Vz$^Vg%}4DB&W-1ftNJZ=+rw=MMXxZ86$(k zg;aewpjPL$c&vKMB8yX8qkJz_$GivKRFST?z?O$7c~l08e)Ofb_Wt0#5KbpY0ntDo zAQtEg6d66fIP)Z28@YPA%~);F-Rig7=^UR2-BY=6kC0Nbp@@Y>8uh(CkKg2@cHb?E zP`9a}c9|_tm0p-5Z%@gJEI~6}l7FwYUKFn17ZW566Q?CbOyLJlG zCCp(mqC5XsZcX+Qy~DT2XjhNunziZ3fk|p8;?hN{hlt!IuElLqgY*us4>vTgdQ9nh zQBxjc*K^`JV(2?5BKr`x5b%x$5+%t9*GO(MkOYhc#sK4iafkzdFZ{jm_rl)`e=qq@ z1SSBZM+1qH59#=jjt}vDi0?yuAL9EES9>km!bF$1wG+;-P~4qxgK&IAxD=Kz;*cx1 zQM8*pc@8N_Pne2aUW-$5;l_oq1Z5tQpmb5vWwF<1aTvVHoz390czx0n@OQY-#^F9; za{Ik-(ftr)F%>0X#P&M;@Y4EOlE)@W9-G&+C;`2S!tC~9o6~9WBzXPKq(qy+JQ}Ni z{08)Ej|GFA&$dYJ-*nw#JkV3S9hE&VOK)+STxJ@mCgE;w6O?ragb^tXzHE&=SeFsjYqA=C=0TKs~Sx_$5#atOHg76+i%30{8$YPy`eJ z^MScQ4ln~q1D*sX07*asFdWbWj{>nkAD|Zy1f1Kz_&zmgeWk7a_dpA94Y&e)0GtQj z1x^A-fkVJS;5A?uumji%Yyma`)j$_ z7zX?Z7zp$QqJS_!0`AndwSNtK0bB)|fs4R7;52XoXaL>-4gh9 zfR}-#z#_m6EC9^F3&1=e7svvp0V%*FU<@z{hzEuM-)G%%-mE{j0d51_2DlAy8{js; zZGhVVw*hVge`*^TjOUpCKr|2ugaB=LFK`R^3b+n@0$c(v0B3+xKof8TcpcaW>;~$A zZNM*qT3{Wp3a9`Az!IPca00L6`M;rZK^}sgZmq0DB4p;?L00CeL-~)D7BJEX3 z8~6mc1Y7{l0H=T^;0W+Kun*V`)C1dqUjntjI$#x00R(_0fDdp2ML+>CAD9c|05gCz z;7On_-c2&TKMf|J4w8TbU^t)$9tC27K0q%Z2xwi2_hdi|a1FQud;pvW-UUtqM}b4Y zLEtrD7qA1^3Ty#30@XkjPzJmNlmH&U4p@PF;CWy+FcX*#qym$HaX=z45*P;j2p9hvVdto3NQ&61B?RV zfg!+Ppg#}|L;@i|8{Qw>qIU?ub>I`=5^w=H1DpbyfFr=`z&>CbP!HU~bLEc~;rZKw2mwf%OkOZOfq>rc^-?=oagjAXuTL67h`>_MR?Hq zu}mixA==D()$Br#1^9YPiM-ShYZR@1r@XXKUZ+j#>*V#3d18Ge(sVCFnSjKX@jeV# z3dG_#4QK@qD@8v51_Mt5AHeS`z=?NtF9Gx(Zx8S;FbS9qRN)=kHeff<0GtG_0#WE= zL2#?##$&CoeFWCBoRgKM$4XW=7PBgHL@IHe-zu^mYyLV;r&Z}T zue=m@iN)ihC6&^nH7MUY1utkg`Dw%G*eb&NYvMVHNSDWK@%$Lp6MC!NSSYVzrN$}FHM=ZIMHLwr zVF|Wse4r#l6({1Ug>s^)>uCu#t+>R>*+N=oZMJln6sYlgh-Vb*$dzK5jLye>=r|UW z-)BKa3CL?CfF>%%E1tD>DN3QJc%9*$i_7(TIhEAC#N0 z3G28XgwGPDDspK=I7OZ5(tBJkm=}?O8B7Dn&uhdY_{Dltk;SyotFGBsB6L~E-I0Dr zy})Jy@l04~?sIjvYqz=v-z=LwJs-;e z&Kz?2)PAby)k8RSY#I^ddXn|TfSIRUzdYtD6t|*68Dv07enu|ys=2a2tT7v^(VzAt$l78HP7TH|lQ%64$C$z^prtf1gN6S+%l zCa2FsZjqaA{7V)>a|ih;5liF+?aEqp#4T_wk#*P{-qa_RJcgE9Iia+{FjPE+hVVRS)u9XRK2;wV_o z$Lmn?GGSg(XucPmOv`C7(`#&%*2QC3$0Cap2SO7>DVXGk9 z9^|>)SnY4YAmK%2DmDZrJ0>&K93-#J3QK{64i8@uCUXg#tM+I0#y!vN5hx z9b*WK&zU+4#=QED8?)E%cDqphFw!Z))XZ+NxaC_e&iq#AndyWsr%A}l+?kcObZ(EU z&|`GKYRZBUg63~D^FBX!X(C|x<89aH*}1o~ge-RT`YZY*q4 zglnYoc%5!+ zW*-J~sF`Pm-Jivy8j^Lk71+rXn|(=%iL&jD!RzwlMk(2xn2n<>Mwo6bvKVATGK0el z|L#6ygJg3VkO|!ssr>S>e2c?Rjw=@bi{fLXqaOabX!%s>4!p3qH-j?wop zq$4WbY&(xTQpX_fFuJLp3JoYlvCWKzfIp{EE;p=TZAKbFklSuyl}}+3krJzw_!|j$=pbCE00%5-{~(&P>;~|Tn@BJnud4uZMWTKf_}ml z&1=Af55=*VMc=nMyf%}ZW@p_vO%^%}jg|5ec1!R`RL2_%rIs*?B51}JIWHRfJ8j`I zbDxo|O<|`*IptCI9$0zj!Svip5^2v@2O@8=P0hE97e((f-k|8kI&DSQXVqlwCuAx*V)le>ojod=UerOaJz;5tG? zSq)+uC)$Z@aBA?m3=YgJOk@-f^W&bvh?)bPKb?%_foM8Xy^kOaz zVdSye1hdP91{grU=!bY790rT|?)wGI)|7x)^RsblGY+KJQ?MHFL+@LAD{5Cr{#hTt3dD zi>C9*HPH-GJ>LeqVgof>xxFgqVD{5t5{cZ54oS9nHOSKnL{{v6Q3%gs11gAW!yubU zN;DVKdO2(~$a-yNO`KxmLJK76aw6GAc9z78{^B>t6^3#?K`oX{>kZ0diCp$>UPEbi zZBWLCp`rnaL-`&y+l7Z3qjPcBNxGMw+pM+{znf+Q4(ca#S6dWkPKhhQv${dP2dMWt zDgr&E;K>M+P@IH8aF@HN(3RjVOiCP+M90dQE6-)* z^EJn0%&HBS=Q^E!=#4a8@H_1mqqhhx!H8QIU1#UBGiL5)z1cW1aa^+U+)A^6PCew0 zpeXN!M5LVT%&BsCN5137D0Qfo3&-~>hl4)cAj)C37bYlas@ITb_2XQ6Qla}Gnb<4g zd1A^h55X8)lsRC>^v{||!#DlS1A0A-|7iZLh1+4&v{2-SVF$%9JB$Xm%Vihy1v)fa ztVX|`#<1EK+uOGSJAr+`A>agX2KWHD3Va2$0%4x^_GsXav%S3@AdP8cvtf3PugQq_ zc=Q$-;}pG)!+W>3;`a8wKg0PiwYOgY4gebgACL{qT0}^oQZxIgE0RbQ%mOL(js*Gu1r!H)7Jwgw zOV8>S2aS@JJoWbuG<*5^Uh6LphUBmGZ(9=0cjady+@K1b^obe+JiCv1vLB^)pT7Y4 z2P;p_^8Z2IB5M0@w;(=b1y})A;J>8;QBp`CSh?~*tjcpj0`r0u|MibZfil6jfv*t! zg#l7vmEh!7Yxrw|Zy6;84hX&r{G#CJCP;xxf=iR6z!kxdOq2rCLzH~y!Oam|8jA7= z-kK%_<_o?xLki>z{yex@@T=3LK#}0qbSYpLd=+?!;BAP%RPdJ&KOp!d@G`-VBF+lI zW8uF_@W@AWfoj2DkJbg&3qDD&3)Bie5PXZ^dysFP;LYIM1b_Fm6xbp7Zt$Ig$0N>e z!KZ=0CirU)hXf7?J|;RO@Veluzz+$22E0LV`y(NNCei2V1?k9o`Pop z;4O%MOZCr2zJe!$Q~4;(32+Ar?w%uIWKs^XS%>8!N-7K6?`&yiy9yNmf*9&rCy2-^TB%wZU&DQ z+zviaa5uPK@TK7Kg0BEi6ucUIg5b5_lLgOhgl-z1rs2~CUxPSV8vh&(pRM8ZG z=WDoG!;3WBuHkMC_i1>EhA-9dfQFZ8_zDeQrQy{YzFxy?HGGSP*J=1R4d0>RI|cs) zTJ6^Ozoy{_H2ihJ8{i%iJSrk2K*#c!0Jll-_3xmK34UR*E^tP0a?fk{MZshLH`<%v zwcu9-9|nF^<9}W7G4O8@ds(C3p#VtKepEDl3(9Fx+UtXa2hsh!y4HZ`V$2kL0yyPC`Obqo zTkuKeqyQbu<+-j43&rL>xM%IKvRqJ zzan@Y_*KDAgI^bX;6ovS7Qt)5zZSe2d?4bHR&%f5z9#r3aLR-H6X7NZUIc$SCjT?g zHec|~pI{Ctc;cs0pjz-n@Lw-@6#S`tbnb4r+XSESG45-EAA-A6<4^G@zWxiePr(zx zPYZq??is=7B7Hih_|)cm;o9VK!aqvzPrykFIZe2O1&_RnIu$$x>E{T(@fzw;@GS6v z;2!WY!Q;V6M@q8}?s~y zEBGbEzbH7lmo)r};4N^k3Lf1D?LqKFa0;XJCGf8WAKn*zR`7w~6h?7UZlIqEu7?{d zcm?7N6ujjJ=%<3`BR=IJp9^=4;QeFKX9d3$qYI=6?neCSg0BG25qv%PJi&K>&lmhC z&RrpR^B|0Yg4e=bFZg-5bWCN~0e6ewt$4nu6FheV#zw*EKDATjEvOg4=|1(E#{Yoe zbf0=%<9|r-t0-ra;1bfIa!?tr!o4VX)nm9P3chX=#!SHnBK|GGL-5SfD!3k80w|ry za4C#Zo7 z!S4)5eF?q_@pA;<0iG{7xn>RDCisLGpt<0E!FLKC4^Gc%l<#%8O@gn1|3$$|z$uL4 zG<=PDg5dgK^kqE1k^gSQ(F=YhAJ--LQn-nNFUivd=sA$$+u^1Oeg@}e3EqY{W|hOA z;!*rxRB#HT_?Hl$o->I@;kojn;I)WD$K>CFII)6D zzsI~q@M!R1f)4|qE%*+cJ5TU)CX`w52Dn9nHzN)`(^C4|;Q9oA7ye~}SKwR1uM zg5Vd6(cT0vDM5P^JQCb3co^n&KEa;{FA+Q*e2d^aev0c7JQBP~@PXhb1s@K6OYmLm zQD(uV4QNX-N}2aoP5D+!CM8-Z^oP|R!N`c2qA(u=rKMBeg@BTQG(NaKU$3+gz;SP z6!3w9ufThT!GhB@=>@0pX_(->fumY?AE5Hh{0;~WlzzVPetN<&(3a|pK z04u->umY?AE5Hh{0;~WlzzVPetN<&(3a|pK04u->umY?AE5Hh{0;~WlzzVPetN<&( z3a|pK04u->umY?AE5Hh{0;~WlzzVPetN<&(3a|pK04u->umY?AE5Hh{0;~WlzzVPe ztN<&(3a|pK04u->umY?AE5Hh{0;~WlzzVPetN<&(3a|pK04u->umY?AE5Hh{0;~Wl zzzVPetN<&(3a|pK04u->umY?AE5Hh{0;~WlzzVPetN<&(3a|pK04u->umY?AE5Hh{ z0;~WlzzVPetN<&(3a|pK04u->umY?AE5Hh{0;~WlzzVPetN<&(3a|pK04u->umY?A zE5Hh{0;~WlzzVPetN<&(3a|pK04u->umY?AE5Hh{0;~WlzzVPetN<&(3a|pK04u-> zumY?AE5Hh{0;~WlzzVPetN<&(3a|pK04u->umY?AE5Hh{0;~WlzzVPetN<&(3a|pK z04u->umY?AE5Hh{0;~WlzzVPetN<&(3a|pK04u->umY?AE5Hh{0;~WlzzVPetN<&( z3a|pK04u->umY?AE5Hh{0;~WlzzVPetN<&(3a|pK04u->umY?AE5Hh{0;~WlzzVPe ztN<&(3a|pK04u->umY?AE5Hh{0;~WlzzVPetN<&(3a|pK04u->umY?AE5Hh{0;~Wl zzzVPetN<&(3a|pK04u->umY?AE5Hh{0;~WlzzVPetN<&(3a|pK04u->umY?AE5Hh{ z0;~WlzzVPetN<&(3a|pK04u->umY?AE5Hh{0;~WlzzVPetN<&(3a|pK04u->umY?A zE5Hh{0;~WlzzVPetN<&(3a|pK04u->umY?AE5Hh{0;~WlzzVPetN<&(3a|pK04u-> zumY?AE5Hh{0;~WlzzVPetN<&(3a|pK04u->umY?AE5Hh{0;~WlzzVPetN<&(3a|pK z04u->umY?AE5Hh{0;~WlzzVPetN<&(3a|pK04u->umY?AE5Hh{0;~WlzzVPetN<&( z3a|pK04u->umY?AE5Hh{0;~WlzzVPetN<&(3a|pK04u->umY?AE5HhTHw6OP({W{cBg$@3dMJ>Rr6+7udXUc1Hft>Suc-|`wUI-6`( zO%gp)Z;^4K&-Sg7mAp2qZPB+Yu4K3QEG6GAS&6QHLekj89t+sbv&8N!G0+K=LAS8( zhhB@rR^;;fY|g^&L4VS*(Pt_)`;rpBRRJH6a-rMiGI%gU`4;s}$;k2Du40SFW&NWS zd7pgMaqT|AJ$mE5SYk8alBuwkKiV{VOoKczH#51MNTlG~O>9N{?{vj~&h_5+0=}mJ zqs?frIlSLt=J`Dp{4bQPugGFFCzvKCCK~>t6U6UQJh$UJc82egxj6SfW7{?xCnkSGm&kY#;Pzk)_cPCI**B`c99tk1AhgzWTUwPFl>H72}A8TcNu zen$cQ%7+zqC`=#A=~hbUPv@Y~3%K8$q3C@gM1Q&-J@mJSK2`?)NCoe<{s{CRyxD1a zc@vVqKRA|Iz&&t=#&pro**Cdpd(Hr5fG_Az6VQ8q^M1EqBAOXy(EBWe|SGylE#Yr+S}P2P;+IiImesqT%^{H3hg44VUjj z7H53M?XPO&Y{%H)lzXQ{(jz6yAzH$Xv5W2N8D!Ws2St8BBl$~XsL1zzL_uTh@Mihu z17sig5gi>9xrs)R@4L{-v6g=sDEl2JvO8-jyYpZ0&q-~!aLY3g);DEfEma`$r=1BI z1Lipj8tR7TPALNy6Rir}?G00&q?I(H$p6l*D+lyyS$Kw@Izo_v_WH0ImSjAlzRl(N zB1&s0_eGp>HC5otu+D_FgOQ_H#J%`enV;}8qZdfc*EXJiY9C^sXbCFDjdc6)>EzoD6BtLf*g(7(d;joMcL^G7r7K!czp$N;_ z1IY5zbY$5%9rZsD86A!6KLsK3J7*D6?hERa>*sVCf<*NA{^n?P!_nh)ryI^5JAeGr$!|`7*L?l# z&2vAV|Eaa}QqSdqZz35AxgyZZhCmIXr|`%yr5@2i3`Hw>%Al;L(8Ab-^OF6REm=0< z#T75o(-^T~nnp~A@?t}1y_gPT7(3~LD2 zu=L|RYk0h#H3TuzjQj^?7=kqLD~f<$N}8O30wezK$pfVF#Q6UUGO3>b|Cda7ESo2W z%LePuSU-fQXniy_M?Z&((Z^7+`dED&rPXVxx%#YpQdPP~P8&ydb>Dk=xenz?hFwWaXO#a5!Z3F~!P$?J7EKSA?N zQr}u{TNxKO&huQ(F1i04!j4NAS1Z#lnZq5s?rm3+B@pIGhk=&HFk)%+@OKS8@|_or ze6Odx@4yQAkMjHu!hiVjPl0F}=JQX1slmc;V5sn0^4OX+K`oLCs(&SXwcyO6Qz<8w zH@(z|Cf*5E-?p$FZ0tg=Z5I7eHEk0!Vdm4kig%%;HQZk{lp&;vVziv8ef(%Gm)9;W zs&$nFz946k7?=7=K;%;;=*y(y814gh+yZ{R6-M`QUnX6SDXLv>eWf4zr3n62OLn#{ zqa-#$5dgga6a2m_DR7MC!ZLLZYkd%pn+fk7*={KJL42b9!{1T%_O+Bi$-k>C=|Kvh zk^3Bf$CacTZ3sDzdr1+uogIVg?oNn$M%$+Tf44a>5Bf&TLHt*|#`FDJm%3ujmr1s4 zfuAYv(t8QKVQRd{<(JQm?oZ%dCF#DSyHE4*l%DhmFU(; zofDWJ;3>8FNvGTs>K8FD%*fHqIBOxyOZc{bD|qM;nbJQ3)q|Q!ITHcWMF>lGex+0D zb2G{zlu7dkmpbVkEG^54-a#RZdEMT%mcp`vxW8ujB}QZft8cqf)1yv92_q&u=Q7s{ zwA?7S&jP5`h+td-ECuIA_B%Qx2RWtecepeZlnR#z%O!t?b24+Ks1BD%-w5Ry&s@<9 zO@Gt6@Odty7OV?JgK#kie-k7c$&}6b6P=y7M@=& zNRnUfN{x^R&-L(}&XC$b=@DT@*(pKle4P-_`~l)=S4s6_0!{OTAsWrmA({xvRib-@ z&;(W_4bd>wo_t<+rCxc@RiX|RXw<8RXzC9OG(6Chyz44KA%fPS^dTDlpF=dM?*Knj zacP@h7@|n~LZE1aRMdZQm6QbWM1py>Sm%c5+71rURcAtb4Roo~-yatLnGjzJC9lqa z_=gN(@wBDqLBwtKc?jzU_ks8+3!jYyx-_6uuaS=uyH&hgf~1$Q9;q(zLM#ulsek%p zZkhKTv^e!m7pg!uo@1Dq0#)!Eu2l4fD==^o37ugGV?-%NPx=t2hE$To5GP`$d(wRq zQ)QrC>N&O?sEw!h=)!VA zM`p>FmZCD=lJa*XKX3EUr@amI&qG|}FrB=Kz^c>Y|aGWih&*e6=V_Xpt&)9Of#U&4% z_SA4Gq@_->@UfI9y)27Z?1uE8!`hL+mx12;#dveBhm=$2YJF+9WsCJ_A(ws~^Zybtv?7l-+&APjm=7(;bXUM&tw8VUmmr^ey1{6H^VJ%j~n z6kFjNiNqkZe~kgtq)!}+{Agb5>0bkssve||1=%UBqeRH?_wOgkM|F5cDw~|kE<)Ve z4@HLZQHU2iyR8GlclG`*b-wbMBVJzXe-HW1cID^)-g03HjCAL%#WD5^R>bFa|4YTc zIHks6CH<9Vw8kzxmHI||o)}-=^OQC!>YqYvz0VZSQ?O6l7eW{>yXtvrlfLMA(n#Yy zPr+|1gfZoD(3dFOb}x~(3+(`2tLw5rz*sDnu8vNb!;9dAB+^89h*`LeU8PhUFr zO~ZF}*N@(;e)AjM1Y1sc&UCXf{MUtI#&+`j-XbZg-&>1EXj|Ee%8ba!NQcQfKrBi`;gZ{K7WvMzxQnocR;CsZi zeUI|z#D9=~lwsTMC{^MfOOB67NXJ!@8ocH!>qM9%nPs=+zX?SPJ`{BF?=B02q)`4O z6o+STwmj}XmhGM)B)fa>oqjF%V+iFVvw}uhOd(f~gASP+FGH$0 zPfBwzNws9_63Md8_*Dt#6XFsNCaUIbohO<9(~D`Ztk;>fPKEm(uT?&J_uiT+xumY= zEX)IR<6d)PSrYj&9c-k#2kZ}@^e}PGG0YE^wE>9H>(5x0E+@R&$H!4zn}*sJlMI|P zK54hHbmt!ybYt?VNy%YG{)`poq!vE-!aftFu}F|;N(sYozAb25OaYtKi(A2w!u%RR zi>AlIysQT6Q)Y6%Lr4e8d9xh(FhV)Y&)TfY5*CfrI(?j?lR~sAu6bRgSNA*`n*MVQ z_0l$+%DYcX4Qnfl>Y%lRq8SR%3b}002^cq|r?+H;sc%n)nnEn}+faL0&Wk|KDqgRF zdX2MX2h<2(n2%Yy#vxt@IuIg53wV8F@lxEj{AF!-e^RfEJsUeG{y=9M${q=QS3d0HfdQB5BG zsG`fYQmRpqn{sD4PYAF!@*~dMt_%)DgekssLITf9xA;C)9)< z)oWoC1MT5iPS+^fHm5+6)hoA#pr}r zWwm8zq{l`~iMpI*hH`uvgKJ3mZb)`m8+Ak*1znQWTR|Sm(()rivcqZNP(!))u#f`& ze#OF~Ga#K8^k=+v8V*tlsK+_rc+4>!5^~52_8^PN)XlM7h+l0nv9OBMf*idR?B@c- z>aLL#I2}Phtf2RXGGnDc*M9f;g`BC=n^uK3LU!iq#ll}pN4vYJhbSk6T=qSGdB zaTH}U6`eS;W!EP0z{u1V7*)JyY!ySl7d$f7tI3mVo=y%kh4cC|GZM|GDGli}WI~_e z{EcHkkpJ}9tYj?Bb!&posm>-eFF3vE#byRXb%L}@fthVr=-_pu4aj|~*J$x4wlbglh#nUr#hRt=K( zEv;Rd4nz4d%2}Wt%&S_HTv`R=ho3N0slVk)>Iln9E_6J(Cg`%{8`Y(R)&=Jmol7~p zy!oZmI&|j|==VTo@=<@!HiYCNZjE~k6K~7rMhB06iQktqJ?Eg=m5v_dUfLth2tm^= z7w$&)=ayLuO*yPmb*)d%*7eP{PKvQ~-lgmpF2G!@rFK$GB~j6Drg-r?(}8kv(vecWl-9ml2$G`yJXI?1IvPzZ(c5X;itqY zAUWnWi%eEgRs_AO#uX9xHl7Q(B1$sljO_EXysFR@apkSA92V2L!8KavD_uQuv-r<2 z?nbDmU^|9vb@!&Px+IJxIRN3%z&{_Z%1mBXm6jY|m7#)?lRXn@CLJQB463=*bgN$s zm(e2i_8M{+tDu*)J|D9$yFb~I!h)8|-JOUV>k!whvTW!aJgkXatDrbVrC83C59}Dv z{ZuCAL<*V?*?@{RU1dLDXK$6p&5PSmeX`oyTVf5SLyke2^_sK`&o9mVmmzoqlFqU7 z4zc0=d8Q*)cFPL88-{XIn!d5`exHar#A(aY@YCcqJ5QdiGoCIxe*D#bQ8 zZlyz6l%?hFUO-3LXS5CpqVV%8ik&Px`{Cy`ip}_0ji1*ka#%}a*I>WF5Im2XylIh@ z%XB z?HSMYeC=mYZA68exQ#OCfwOxpMicdc>h)%t_P=$sUI|c zY+S$1mR;a*FX>dTij9ju7_Um$njlI1>4lXm&aRmA;(-@c{Q216SJvy?OP;L4b$a~R z%FDP`!D?S8)av~@H7ix0^-SMLYI8Ky=IB#%=#bI4HhZF>HpMVE;O;h(x|~JovXRs! zJVRYJlDdRvsLRF?bvYmEGQrBFJ0?I~_7M4wr9oGm4KyQv)W?pf*HO6uScM-;06y$`W1%YJjD5SiD~#Xl*WQ4M)LnqM=HvZ zT-!DH#wO*?Yra%Mv?FpuHl+;uEhRTy9=xq_-fHXAYvjD|bm;%4;xa>PPK`)->?;!b zXIF$ySyV-boI;ul6JAdK*9Ntn{}TF^u$<_x1FABY7r?(L$1BT&9m0C;^yzOJ-uwoy z*zn5j(lKGh2J5vv7&~(hf;L?1QBJ+va|idCKA;ai$EO%Ve5mNv2dxGhtb;nC?yL;; z|EXoG5XK=4|jlni>%hJgxFE=kvzVsQy zZMfi9q~+S${VZL-fn7N^7FIOjckfvgkb(hrD%$1C;3?L!wtK9;eTP`S%#7d}>Dvq7 zIUb&$gl986ha&m9iAetBM09-1k6SF(sp!15H3rt6Y?lw{dG~Ex|J{eR-1siBrRx!- zKZ9+lcqhbex~s-L`+4h@#@0qlZzAHdM~P}yl;_gsGB8=DNl**&*D;H1~3WFKG@_t#!{@a0PWf>VE^Z(EFA@dfp!v3t|i4`IF|TE&AN^tjZ4uR>pv^$(O>JE+lU^0_sgOB+nQxBc&_BBZJ67JZJ1396Y!=!H)V6awds5JC=Y*~+ zSlgois0^RlD`z(jaG71ca#>w3mMFGgsH6I|FdM8cA8%p%2K!eigYNcZC1O377f(fY z(`S_3m_u<_91ltv;Gt{ECHPX<}wl;D#VsWGiX2Lr2wlf}Vpf#)(OZ2d()r zhTu3~a~q`*)=?pC>Yl9ryPrJSAYAfA!b{Qkh!Na;N_rR|>pt0&g!^Pj%Uux7S* zDJW-A`GEaG8_dqzE{tKH+G+?f`WjRXzH*ZS*=Kd3gI49#>%K}=r|&wLd9JAvxB%+{ z%pU1rzBZb{^FYiMo-JBT?KQ25+(f&E^8fkX`TKI zSVB&KwV)|0K%VKQr!x*Q(lu>V1{NVazr>aUVO5KFG{x1nEoa4+wJn2R={~BR2`#4j zSqtkPv~+dR2iUKFgqms1O3C-;VuD;u#&Nip-&os>bNNlz0I$7#w0~)F z1M~npCBBy%yz3CbY9mW?>C)vwUax(k4BUgFYWy{A)0ETppwK44S|Zr9aQRCDRU%BU?69>m7Km z>eBg*#TJ^qplcshdDrqO$MH&Davrbg(F6lnuETN#uFS>ySnKy-f5`p5z~Y0X+-8}G z7yHYc#Y+Z%x#os-GmNBVJZ+OPuvWbCY>&-U2CGJAm$sh{%N4nj0@)m-NrCqDI&SQ;vf1_7;^eWV6_uu!t8dc@}XLvfc!)a&k7{b^>;*1Fneb z0NR#-Zf|2&+u7|%2Yb?9ZF1ctg1iF*21=uZiTfR6%Wh z7~Y32kU8&$48G<7dU?FZD(baBNgA+*f(=RxX=K;gpjIMM$AFFH8rX$C5$j;>>xXqp z#c%f7`=A{dv<#vf8N|uDkpJ%cZ-woMVR)vkcY16j->x2NBmUQeONvh5IOeDUzN6v$ ztnp4$`v9$B5Du9hJ2?;2!@dQvTMBIpr>s8{29{qiNVXoyj^o^HCZ653 z$uZ#ksNIvEz|X|vxMa8nad~k0oZA~mP;g@_5tm*m`W4CtJ3W+gwsX+VwxL6XX_qV# z_aIKMU(p}1OV(sQmK*rc(~ErBDOnhuN!W^TX|B4!gBZJW`MU* z2KG%+SB$cmGhqKr9}D|teT!h1dI8TTfVa%sliTRvx<2j?Maa$;sqNMtgsm%Cc}mqM zeUq=k$P2q;nA)Y&WvsiX*Q|smu&|UjNeaG)=PR2Il>t8fJ*K=^^$owAuY4x0WyM1L zwBFi1G+zMwJsn*C%1}Q7V=Y*|!Q!0?zA&CKc7sQDf}VNeLAw6!3Xrs%HO<}Tp%Cos zjVt)tZHx6<|NFLe5wYA`W(9zT;k@+P+5CFli)(h)y>x!nSz|-l(c{$%zFBlR<e)F_WYRlcXQ5jw*>@=#c{6(0_j}pNQtOv^wRx@LsUKW zH%_!JUI#mOHyU4plG?K8Uj+$A$X9#`E6GPu%l8&>0-l-TeZz=+Sh;nuVR_v3auJ_k zk-?rJyN7xmWQmq?0m(AC8_1M+vDMg?&zjo0}_FxzgXpQ-VOH5#lI zbm+M!n+#xqSPtu&To_$@k@C?GDVHv30_MvQJWBKue|a(HX>t=4S3th0PGp)6s#UR) z_@9=oTz+=>oEHwf5VT_R3ek%{&4)E+>?@$%{Y$#5ZY{Y{WdK{)dMkMTWC-; zMzCKs_@o|lZg-F9TLfLlBXvTvi} zkQ=`7p!umBZ0D6BTh2Ge;>9bC;kl8HyP`<`uILc#FkA_OTFK_N$WX!V^+ov0_0~u> zIXW_`4b~QE(dJEyc;_|i0Jr5Xa;C2RmC-(k*w?L@P-8rkt$<%SqtUz6CBOTs$|{4s z7IXaFG>3PNf%#rphj$9_Tmv}o!M%phEWFCIWrv%m1IMLjK&Cn2U?GBe{@+=sQ{8O) zzk5Y?<2u^@MJ{d6&7}_(1(eY6jb5wQOso}Ip+`3@jkY_$rq8EE+f8n;e9fX^pKMFm z##g>(=KXS(vXU1#cUrm!oPS)~-(7`!t2GWm<3qxKZT|+(9lds5JOj8h73Sllb+w0W z(_W4_w5161ZrY%3RpTCWcA>Adw$z50lQBcB z7RP$pUNFSfDt8Xsf5qz)h*v<)bV#G}koDM5dxn{bu(KFu4$$n&c6B^%$JVI=jVmcB zaN?;9zl-BC^3MfWSR}>!Uc%g0n1>4aX&-X`t9WVKzp%dxtcY18%BaxJ_%(XaS~6mg zIN0~{=F>b;)<(W7(ayl>50whm0;GRpCJcpn`=`e7L;X{0%!b;m-scy-@$c5!eh2R1 zu}_8M^nwPwQ;cV(SXc6H2^^QpOKXp80pD0{akX-%n4&b?1{qj?WRfqnMYVXZba=0h z$CoJ@SI4Ip1>H*+tDI^>6HoCP=s}YF#^4q4{EG_WHQwH!47!Pu9eA#siTha3%EXiJ zC|kC^@iN(I9w8@?g)nRH(-!=Ej}s(@YY0i{PzJ?DKL(tPEwZmJLVP1wzSiFr!CYsR z{#Yd24SwY80|%|n@2vyFYbgVv2Zq06>3BzCaQPvr+DuUz!yXd?E0YDMorlxjI5O>7 zav|*@*gS|bJ;&Iv%oHp}1=L2c;MM$PU3#muE>AX30 z#0*48H{y-qx#6&%mkZB#gpwuSFPXsx^1kwN-!DtYp8*a=6Au1BIKZXjFX8g7#vJ^z ze8Ri~JiS)6IKW1q?w5A^SJp)asB2tSn@Iy)G(zt0-^C>+(j4WH<|v`WXZiD6WO`S6 z$BWJzBg^cSX7h`;954c=C#^W;z~eX`!Ho^V7_O5FBTW3)cqFli>w3%h*@dnob=brv z@OpvqZtMLK507v#YWAski%i@PJqV1=c*n3>N_={<@ruo0yIDazdfLlHg2l8rhSwA{ z(!ucv(hUp@^w^uomw^w1y(!Dq$7q%fYlF6I6~E)z%zmLQc>0t3y&vY64mF>(Wrr2{ zmoU$QB`r{`u$ff6GofQddlE(_Jeo?*)Ji%huXi8X}H36v@M<+({;afZi|;`oDX&lOo%JiILCJl zjGOcP9C|l{E=SL_9<_3>w2HXz+C|PHN&i<&I1knZ=|TzEG*?lYtST9dd(I!)d%kvT zsd;{m#iXHT^Q|=k%@L4o2ghh$shX5>~^u|tFO2Zyw8n?xQ*UtQzN7!E;Hg)h2lKavr1xiHCN>iwOZU} zpVUBmsJ&4Ief^ceqfJ$z`2FY&#}oLyrpXbF-)r8eipTHO^Q#u(_v$ymXGLi5ULOtI ztI%P1#M$45M_lmD`NxWwt7oJ!YntY1uQpkM1Mnx*!G7EyF8GuYPbrH;Et(QnRtWY@ zb@~!2Uf>LSASLi~;xTvNsdMFTx2>S17W0jA<<325SqOOKhAk9@Yo^5Jlqil^Hq(M z4&kMH4VKOj#N|sK9I9))8bp3D6E=YDNgQsLzoS5w?pX-Dx2UKlPUa(_L*h}tmb=z2 zxf2qYir=sY26&Es534dM{tB#&UCK}HN?oWq>&YgV;iSq<-Gg`)AH+gj`^8Q2b{6&} z;wkysu3r1B4z!)UxC!insc@PDW#rF#6?!KsBftFBDZ77}X8vE&u7WoWrW=QQv5b5L z{Kms?$heGpS4 z>5#4kC4i*`YShxsidq~%oqust6ZnmI$^;w>Wy(+Y)RE&hO)V zg*=rd=cG6NQg;@;XC17|WtbDP#ib2+P{ zBqFt z!^{M`ZBF}B9)9XEZ}^0v6?$3lmHal$wA?84xNY??TKy@-blkYyD8y>M7GjtN@L+jU zkXim>E`XUqL%kWw#8NM1=_OAZ$G~#<2YPolYE@f7j@nP* z?*S{-lZ{&z7oMKQA|3edz z)+G;r%St{)=KLdb3svFo_nz3c^cl!)zmVJ1x`F#S&Luhi`JR|dEf+(MFP4bD(ymG7 zZdyf-kVznst{UOQMxN8l3GAE?6fed5-^26&B{yE_Q(8F9rFcXTtXtmiaJS8UErvIP&LQ+?LVC=+tSN@d*uPj`;>U8h({W4#`GBI7ZiHq8SrPsUv4HA7dW$%0yQI%WZ?LS`OZ1afQ<)F zd=jc6q3Q?MwZK^Xx2xDDHMDjjdfhaL^~078{sM{SMnf>R3{JeN|Bp8hkIjhi#hxd8 zbtJt5d7+vmn8)!!#=|Ody%kQ$N$UE98Z$1#xdn#Xcv+KN(m^Zgp>~t6X68l90ty_!8xAQ z&^skEK2(CmC%exAr+c6`H$u#n4m28O%h`RHZ|;X)STB_P#i9s9r>(Mj8p0W$)}lv zA?J@hKM1mjZ^iO*PV)J2cF=#O@-O0(j zP{A>k5zb*ls<1Qmqf1vZWn!D4)9Z*=Jb1Jih1k*`U?*p?%DC4Wf#kM{6+K9p;SS?Dw-G8 zte(YEEYHf>#s??W!eW-?@tK8zF1&q^LIv|%yMc@+^cn@WSpm%ZK2XmZ;ZM7L8e($ydCcV3@(ZU9buuL+N z{NBZSHC(QERfy{gNntI13+gLGJ;MRLW7Z~Ki|fz7F{8v=gBcZ$cTfGSjX`OEYf>8E z8(Sd^%a6&F|_gXSL$F{|B z0|)W$eYd=`Yb@8+AcB*4)=q?X?APlsM~$B6J9x&oSP$ohVALPc(+`dN_%0Xo8MrYe zLcU9cB(zavfjgEW`IRW327IST3TAvp=(%6p+rhVC;Pvvzy-Q)eY+Z`wyjn)@11t6} zEi&vjA$oTs+LG9sXlOLS-e6s?@=@><4<84sS23(!&-E#%Uh7jz?)L3DRiF*uI6a4J zYn15YpJ=d%V|(SJ>iXIe_(Zx%j9|wvBEH_jcK6D=KnC}2f;_sr$@BL&k=@#hvhw`v z?d;Q(QWrw;GEVlP1kUI>HP*^Vc; zv*o}Gb6U=JL}T9^1xOft?K*Q=&HNgskB?R*c>IkM2OeL5^P)#s`U?4$1f{0+p=OlfC%>=6n zRuC*9m`_kgFr8p3!6bref)NA*2_k|W`$@_Kn+aAEtRPrIFrT1~U^>B6f=L9`1S1Fr z67(a82zFGE^a(Z-tR`4Nu!LYfK^?(#f~f?P2&xH25DX-U2sUSslnJ8g__>-qR}d^A zm`_kgFr8p3!6bref)NA*3HlL41Uvpr(kIwVu$o{6!4iV`1a$<{38oTEBB&-9L9k;s zNsVAL!D@mP1WO3!6Vwq*CzwhwiJ+Qb1i?UpegqN0j%P^v1e*y~6RaRuLNK48j$k^$ zRDwwa)dV951`_lmhzNE(P0}aWOt6|@1;G-6`2=+Y(+Q>$Od_Zz7(ph1Oo~B5kv$#o+9ZJY$jMuu!3L-!F+-`g6RZP z2__L#6O14jNYIZUBG?g0(kIwVu$o{6!4iV`1a$<{38oTEBB&-9K`@Y@A3;R0V>(Hn zU^BsLf)xZy2<8*i5lknTN-&9_nqUOMjtty){||j6=>geuLp|Ux`pC7ok8HmX3kmWBGYO^< zOeUxy7)3CcU;sgepd0sR`E3MS2-Xvj_p8EG1Y-kSCZ)FpXd`K@Gtug24m>2r>lSxF^eRBiKT) zo?s=xQi6p9d4ib)(+DOL)DVm!7)&sLAVbiNd$RmCf-MB=304v;C0Iz1CzwevjbJiC z4Z$da!2|;cG6dbYC(Cam*g~+LU?ss)f`tTmf|&%<2qqKM5R4)iOfY~TL(q+TvivrJ zEd=WcRuU{FSV)j3m`N~=U@}1s!6<^k1Oo^%1l^G&eS$3n>j_p8EG1Y-kSCZ)FpXd` zK@Gtug24m>2r>lS(@FXSTL{(@tRz@Uu#g~6Fq2>!!DNCOf>8wB8KjS-xwdj&ymOy& z9D9=uKZ%Ye$Twae?A9KH8MkSa{5MfZzC0Mo|C$Rv@*QJk+5=|rH+xDhV}573n>k?r za5bD$y)FUIhmOb3TiUWI`<66n&qn**w}2jr_H67=<~H@f4!*sRr|fKn+Hx@z^#@?@ z6<%*|i-J2w_Rm-ZzEVXqz%uqL=g&1TBgd&f*KBDM4@-T|MoUX5Y9jm1naLMn=dgnY zzh++w>|zTV1fLe{LxX)y_L;w~pPnj*Ofr-yi3 z>gRM`s{iw}1o`8;1r1As5xo?j8Nj~d*ycX8S5mV&dhMqwW}Kx^LUrdwc3wx^_=D)k z)=yO}54Lr}jU1KZ?^D;TMpC({Yw%N*TY^ttulvC6270hkjDuQ^5S^+TUaR;HDg()t zXO(`#>vno9GwjU5NI!P)5-i30Il+G%;t@P0%faKJy!`c{FzZ2Bl^Z4H#dEma3kXg( zrnR9~E%$agDvog$T^P`7r^gC*TtN;`*4X%b&0G!lr+QKGe7Ge?_# z6A9mMtT|b8dCry^N^`kpW9`YKLdmAbW)fSUkf!XE!hz>p*8ce23gtutoXRaH2MeoaGUmxW3jdq9I*qNnp#^Bl3ro zZ%ET%6%SNn-J+{YnFQ`7w|If6%(F`#oGR?xm9B94RsR+91b$NYd2&wl>BMP$z2`!j=H_1`&0INkd_#8)9!&z3DR5`WDQ?|#5&!4x4M1IyU zzy`JF2Ke^N&_^e%pTXNF;v_2m$r3pAb_<7c>D{7YH6tq!7bm*AVE4XesK3L#!O)wq zqfl@Q>Xz&?N>k>gz@FvtA^Vlbenw&yl~D5xzuwjH>?KU$(afL4z2EAM8}3!7lkUr& zZoUIv?|E9esb!EGXh(3W`ifN~*g4AQ<%kb$DOO{j3*v8Zj`ZVy>})+J+04_Iq{ z54R`4T^DAWR>|m#2JjMLv0SmAJ)G7D-MQ9h1q}te_$=&8@pIjRF_GnJX3>@l-Oz)b zhFeACthgVqAB0=6W>WZ`DMN4*__3KqaA#F7)Yy(8KD=CjKM!sA83%A5Mc_4}y#fcT zBM(=BK0~OW(^%hyn8t`gtQAm>cp7UvK1WQxy-yJmX$A^2on2 zL!1Iu{En*qqw811=hYr3?esBh})S}j3%v$(j-^?lC!oK zT^%o1csZlU?zPZ%uwUDB^Feb)7@Cn0g7EqB4Q}yc2FqKs5O>WX+5sNXFmFjpr#U!p zrYymH4z(2F1YVwYU9xkldtkzH187H53U~;>7y09`7vopJEu4w*OC@n|r`sIoOH5Ce zCltXAr!uHb&?}W$1g8N__{-EkI9D+DUL#(fWT${gH*K-2s(7*NhI9MWK}_ep4-1bYa5wKl_`YO#cu@_Olr#nAH!`;fO9gwc%}Y_L>fo#< zchw;RY5Z7@T-7fhf^)+IvRk<1>ymMAf&ByVTPArUx>5b|kwS8QO4w68U^=2;WJz;gEmxqcTI60F}#*2;C--ZV!gnrX0EH_{resVphxWvG9OeO7xbuc4CXV3 zIaF92J)J+8jkQRc0v=QYu8No8yaepyR||E7IrYX=nZX}-M2xHY@k4NDMk3Q!44id4 zq$vks&*-^BL*Gt#X~j!RmcxDE%caR+$p-&|yO78GEzW2L&fnc|ELlF`C2#CGh`k1} z-xdyiFT_FE{-Lnp177)YA}xb+zakXr@Te>a;4CpKg@! zoax9)PJ_8?GT9NwI_UCKPqV=Z$)ZMqXZ{J8S@(|Q8P|$gdoY{Rxy5i2U$m#mBm3rO z!DD)4t>89;%YikAigPs&ULBH<_p5I&{=CMZ2WqZ5hihzur-p^G3bzKrW%K)IhI83A z4QBcsUM{^o_Kj9<;wDm=dtPRZ#IKGn5Di~DEpyYlfKf1hhU%*?_`(Fd{*dbPLj zDdS!^XAbiUU-tu-pWpI)>k?%c9;={#ha0Z&JjgRnoP?19`h78++lGHr;U91;jA0?P zWhoxRjtgVhz|a_`B4ZdGoZSZ;_W{SvpH_P3MtD|4M)~UZPY&IHg+sBPWj#V^+>V8h z45xOLe0!VHT&yB>1)SGJd1gcsoCBm@^6-zt>AiHXJVWS4xnV~hMz~>fJfUo+>Huhm z(3T<1N+C_~9>2U~+w){DNXG8rvS5$4947bwR{yCJOa2+hy5z?^`!{*DUoP%TEVzGK zFPuNX&omw~4(*i z^NoL7#7Z%w_Xh5^P-lmm?H`}sxd@sEwE==^xYJ82l!)Sj{MmIc)}dTOLm27m~rt*-gpEhoGV}c1b<#a!SZO19nrV zx&E4#T)hNDmwSRp;-cv*->jH8lZVxZq+JjR0(iHH^@nPke zl7Xz8LsoO%lpn#*9%`*WF0=$J9wP4ELCLlleZc>|zKXuX_4D&O!@g!vM~X(&9~Zfn zrSQJArni9A2jE=RIK1V%aS`hW)aVEJ20=IpvMIhRypWs?gPP>tKPa^T&tY&kpTP5M z;5qm^*lX`}Nc&T=yj;J3P%;U)#x)DKnfc;K0ej9=DinI2;>G$i^l>rb6t7cJ8aROpX%sKU zx3|LHwSGxIe!oFZEz4PE0D6nHU1KehD-73h9oC_mLAd1)LKqF)Nrt{w$SdJmBhue^ z?FNG90b3{BZvyRzjDkb`8{W;wq260j6i^oM)dc@6IO$5b3&pqUDB2L=4nm8;vu>n^ z8hj6Rnpa;O&1kuIyU?U)e6z@e8l|ogo|QTl6-O7<_A82O1m1obFN6=tHsvUmF1F|$ zg!3?lI0-tCv(GHgR3L6yzAtB%jML+r4vamBhPbRASuR&+^^uQ4qSsvDc^{j?GjW_= zCKgt;og!Qs%#$+k22$!S5Z_YF7mmkPnxa}|$ql$QAprCv0Od8z=A9N<-+%qeLw94q z?z23a_em+_lJdnWBez{9!Qb?c8_H`ng+p*&{T8^DGuH&wt7;Q!&R)LMDrr3Z&G}2; zod50|{EeOFA5SBh^3hK^m0_QC!uq!Bshqf6SXpJ88;|7d(Q-are!Iqsdy+qR@+P!W zS~>P^kL8_2@EN++%jNi>Xf4Ow^xHM&ZV%kHEjia~P}OxAf@8a2Hqo`*^i|{`by)27 zSfBXLWviCQy>Rda)rzevBrkT(PboaVJRan!Pne{(EbEDu``+!fm6?%x)EKt4}E&x%pA^#Q5m!nv@aWOF3Vx3 zQSsJ)Lf@C0`yS|lpWL@&tVNb2g4!Bq(2hpjN3;A5+R5na6LNYo;`mwqxSaaAoV6Y9 zGIBkU17kptvLWmq${xcUbG?o-sglTZdGzf9#!o5UBwqM@aIW`#nx(~OqQ4}19 zEJXpU9FMsBzcHcp`E>KqI78P^9OU6#v*+xJW?+%DHOR?g}~#6O03(3JmnXzy1( zS`N3y(9rfHBw+iWiqkC|TZB5lMI`P%22lFbcx2d7k4qitz+>l_AK+jb2H6pjgz&q|O zwy7u9W+}E+ziwb;%;>`oJokmOF{=&#&?4t%-<%Tzq%!*GdjRQ zWX@Jg;FKZU5|zYaI$TCb?}PRSK*lV$zI_7xGH^a|yfWz39^95^S1YH2$Cpan%WFeP zN;ubxvuR~)k6~JN4?PX%TzMGF(JQM^?d)p3Rs&&hf&fade7q|K>z)EMPCn`nOO@fT z_F^lhCHvJB%jmjZxGU~F75_!0uu2F?hJB*3&eX1J78&xho4eKeSmDbPi|u@oI+FPi z1^m{w#d&kaVCZ3wAMDur!v?JqP4(t?D3qI z5Ug8p7SZgg80!i%3s%~;g>ZYyUCvhqe+9$NfSlkII9?%xq;5Rnft#?fboD3T#xGcf;oD-I1$zdR zIx!kKnhM-`*Y3j22;t_!dibjiv7Yp&(ge@&#strRy1h93n_rgU#uLNy9A1VqXN5B8HMkU%rsgSJg2&In zsp|({gdJwdc{Bm;80`Bw-~Oj8l57-ilrwd3N)eZT*;9D`7hA+VJ~pkT&kj#P`RHeT zBg>A{sDs;UvirTMnD3|2|CNwR{rS<)3NumI7lR!K_*(yVt zD;5@l9iaGyqWg9Le4mG|2K+!hHfNlU$AiAX2hQo^JvQ*?b=crG68I|ykg}oN^iV_Ta@cmC~N>*Kkxe-rdZEVesw>m2uI=mG_-CDjG259}mth=EzBo{+7Yw!8va324C z6Sy%Q&dftU1}ECf#T){^SJT}=xJzxWo!3%wSikv~%;x1%_h6(|O4->f>b6a@t=xa^ z!acgz!20b*Tzeb%sRkhD-H?Dz_-}?)i8}kIqy>|z4 zE*0gi=W{Hr_b8C*#__aJUb}Sw2FOj#3!363O>F|QvcVLQ`}e)}o?$cUoX+B zC;hG{PHp*XZLhD6 z)D1`x`^5B#wYB68rF4J!jo(SV>$i`loY(P+QstX{q`f2G@j8ybJ%q#q;%BQ}Bf3m! zpdPo7K?~_p*T(ck8Qi;@T~`$7A5$S~2fXbA2T_Po4vGG5Ur6o<8rrPBvfLX~P~ILh zx9+@x>#TF(-nvV13Gf5F{*!{s{E1}-mk#3I-pZ13FR8G!)%B7{-4>7Yuvjo6qCq-k z*<9Z}tx_7f_LkW9+EUEtPVGU8rI>_>ut#`R~f2T=XPgYnG&fmRRZfW|d+w##*caD_Hi;OJB`(r(;-x0-TN6x{` z!Sflir!8jXj{{fK{}-_b@nzQ5D_f`TR~xi8YeIgrZGNxgEp&^=L8;eGEn=OWA7Q;V z-T0q<1`#s8nZVfaeFA*>9sff#$MeqEBdm$}5tbiYarBMDf2m8PLQ-p~u;Y8uxE^E~ zeUfKNjQS@bi|Yrw97ugSZCwl>^IOW#$@1M16!(vA1^46Q%8Q2ih@vrv-#YHes^1Jh z!?#QA($UB9X4(00?)P70+|odKR%l4xF=|F0_Z~bAaxYO&=dSbQ-r7xZ?-VJ{=t`B> zJ9i(~f1;%kup&1!oW+H>}M;&YZr&1np{ zXwMR1pM^cfL1Eabtd^c*u+8f>ylwG#M`QH<$b4h_Ra*%9)(`x}e>>*?L%DwxL-skM zKYT`ZxwyxpC>j!t_hOv&gPthxewfH6Z@gv3cT@VG^UW{eZ`v;(so@+^G@V3xR+OhKm#Q&^@hgiZV-QJ$Sj4&bAR%?fTw2`5s zb3(aPcF4LIX13VMtZm+C4Y5|Xn-`(gRM(HiUc_XXm*9KG;H>kZc(Yr1i7NBDOnsF{ zb{ZMw3HU3&3^{DoZNzPB9eR691XrhgSltf2${<96W)f{&gWrO;o8PxY2=Nn`N*Vo) zIE&iNhzHfWB_cb`gkO{D;rZP9nYEc0OPdNHDgI`oReT=$8^Mr5aSxG53`&~d=N?uf z9=cNY8(&aQz7q_YzW{?UW`0Gf0^fhm31wWj_Tmkj9k@0-jllmCUe6tV%}b*WOgj; zmA{dag2(t-H0MY6GpHvzeSZMJ8X?S7SQ9*#LOj``zJe%ZJ= zd^XnTxd!>pn!flBN!BLkyY!|d`GMN^Br>=lPt`3%W`;kf4^Go0#z&ODe@=xrrwdo0 z^diyif{Ym_$$by@*~XED`oQ|WjC$yQeLH$zf5~xiRXo?# zgQ6(QPrL4VZ-p%RZUo=Z&V` z$n%*|mUjs&C---yg3KPr2Zbjc&t|^P%@0!_zSBoE=lNAWGwAvtvj&chKfsEF*pF}- zn{X}*5yVMEr>l>C2#(P8$=#8#={Ukz^b3StJm2sa(8^O^XvQvNj#QN3c4?O-_+)Wq z`PWf?;K)I#r0GN3ny&yoe6Ds2u8KRj_9gAXcLmAaZWn5gl(^y$(LZ+S8r+y4dAJatmWmag^ z(WJ=pIB`7TA)MT&cJZRhyxnLb>)gmp`bA$Hf$v8tNF91_)zbz7xvcNY6C$3^t^}pe zzFcAu^G5~THDj+J?#XI#{+eK8ky$vn*z(Su+m<%3HtsfJmU}ebmKXDsug>Co_jeoo zn>P43z;Ath@%kZN+f(`Qmebg%Q} zW0H!?-Z9dpR?`BKgF+4c*l^2s#dbYDQNu0SifnwEj88^|{T=1&oU)uP@U}hyX#qOZ zR_j-D_#+{MuLTrv|A?Z?+8?Jcx0fk`!Ym(b?!K6Ot>S1(Qbc^YvlE}}RziCuBbH>B zOz4l$-s0y=5R-E&Ze^EV;HwcSGF^2X-fO~2@C(J6k9ixxfcCH$kpe(O$>J|1fc5P!G*~=jd z>amZPeV0FD%{hI58#T#%6F1)|*m?TGUNNw1%Z##f^@zuG8KqGyxnsY~bEafQ^XYdK zIdigAnmt|kq+&HCU5Mp(q|f55BH0W_cex}zAin0Pm=(O3dyCYO0|VlDJXw-H`uc_i zrT3(Bd5VWUv|}^Gd3!v>TA2Ai8oy5{PRaPFnaV*{KOx`iQ05_XI%YHdSY4P_^XX#7 z>bLh9L~2tohz8}R(v*CvAX$D)dEU5b55nxEvb?e}&offI;)hF2On0n%9t)}Ex)`l-fPN1UID$2#=OjmXMkma(QUOP?-D9(jZ8N7+63 z&t!-^yD?S^$}Hkv=H;KdG1e?=p~&S=n9IC2QI_}kF4+4i2(Pw$G`h!*mH&MB_>$zf zv*6i&t&dME7FWzaSX{9tf7})?n-qRka(_3?)t{@O?8?4(!?k{EAi{@nu37wJBp@pibTD<8w zN?~J-yN{cMwE#^u4Bf166la!8ZdQ=C516^G7MZ*;8RI?5mnrYa5D&6&sL(&e(pGBn zZe#ABgT02MgjSGw6INSoNze%n@LUu{W`Cfdd8cdfhu z9o_8ve{cC^TJB5-OM6krxAJHFF60cwPJt%Rj;G}(;CaCBD_a0B;3xD&VrAN8D>3^c zh0MYUu)GtwZ`zNzVSWYvhfF{E-Srf=O-0==DU6Dtg-j78$%kjD(<5j)3OvG{)Y=gf zl=}51IkWI6dA9$1+B7#1`d%X zZQoyMwdJuPzc4xhCa#?lbKR&@pB`^g1dr!}iHyGAUp7pl^DuWXOE60hyZqX5W_xMRzUVTquX4VBKWYycs&WFR= zxv@o-5Lg&2w6Ib+lwi+BjihgG1s0AgM~t+ysI_Zcg8Q!Egt?)%(Y;bVyeeTXJnk?b z*bj%ING!vxixXyH~$-rMQ(97uw?o%+%(ZTP+HdVm)h5yax%m0PdLbTE39Cx%|zUFcjvfvyP z>{i8CPsr+E#26>=H_SUAYwy@$J_^19t5d<3fmpK+wBVd_D4OpGu~QzQGqESzN>xY9 zDdYuZSAh3Bc;^jle@o3!GHceO8_5pTY~Qu9BzehAHDZe&DK`TGk!k*_c1i9@57+Ea zK&HXJPw~(01$2+q>mfr(3QOI}jSEh2XP-{UiVMcuSdWQObQc_2<-YXk_2GvMJuecN z1W&+Zxjd8LF2V@qf7HX`&4wfYMH0LHnS`tt1sp>8q~X_Axl@x&J`8O-??RUtxLg;? zG@qfvB29Pi4CQiMsFCdU5Am5IpFP-Ye4ZqHRV2+`zC|hxZt= z!if)uFe0z{!M7emkKN~^#}UGaLm$ry-y_UP0!kCy8HduPV{YZUJi{dyqX&hLHAL(& z5L^t~P?HrdVRUz>;}_tF(bJ(cbo8x!9~;I*jWdjX4t1!Jju`zNO8p+amH(IxrM~rJ7 zN<*1j`G2!vOjJ0-nCMW4k~w1J9ZLPETlwpsv1~2=hcj$h{qUAe?E8+ma;35@?0dKJ z^PjQg7r*BWQ=tT%%l^#~(@v?(%)WgqzxWx8srYSYnD$E0S?pVmnD$F$8`;0!%KzdS z%SXklonfk!pf|IBal}+Bm2GAJd@KL(GnRtlKRd(JAVKG`ZxBq5JL2rX^4D(VpMS=( zvG_G-*se;@+t^nf`_&|sWwWo|%KwS1-*RV|S|#XB>{3TeZBp45_T^jocggy_>m>8+d%q{|-dlu`r$QdSg2|9~?(GioURJM_w5B~Nn)-To>CO-*!Gds@_ zlfP89m7NQ|_AJ(Kt}{%*5_BFr#}U&+sVtw30WW*jl2aVx3{$8Coy|r&V$w=wCUz!x z*t3>x#gWc1&6S|Hun~@!;-s>V*csqm&ssJW&v1rmsRV6iLme^2OJxP@H1MovExEYEGfY_$bRIk2 z5mT;Imd^%*Pm%Qtc7~}?g3e~gI%3)>m6_Nlz^BOi1v$gCSAyQcKIVvNzf|@S8vs5< z)-S*rrb-Fg%#L=%R4bJgu%p1I$oh?PhN(e<-pKknVmd38<*<){M?GuFDt0ObT$P}= zvJX3AYLd#fu|D8Y&ssJY`#9@Us|20T-gEA^NoAW@oced4wd55KbB2kU+Rvj*>_d)y zVx+QM)*U=*swKPF-5Dl#3Hl>eIOiSd+;d<#PI{lISU*>1*!(1DGwb5mFMp}5fMvm_ zreghAXPAN|=#8wx5z|DeEQghWPff-8$(&&d?T6;Jvj1?zq?O9HvG0RVP31NhzwZpw zTnRd#ea{h7oK&`n{TukyR4%XhZ_Y3+m7q=R+m4vxrLtW1E%2$STz2tW&M>W(pg&?) zJ7QWZm1VK3!K0>fTZ;eU3{#>6UBLd?5fd+!ZD!v9kDAJvi{EgDDNBORVPA8^lq;3x zu`9r%rg9sLS2)8|C_!&ympfwGDV1fj%fX|ja$Ad+I>WSAg5JcwOfWgp`Tl|Bi@~SJ z`Ym>btx|$Ev5Or0RV$U{vM+*9k@b7g8Kwpa`Xe^h5z|?zEQ^f=pCaow&l#qx5_ADO z*AY{bRJNI&13pF8Z;mretrBz&8{>$nO)AS{qrs=h`b9g#L`}2vDQ+7Z>4=Gu%Cgx= z@TqB7zX)fT+$HEu>JKsHWWN+8kb)j>I{>g1f9!HbHwB?m6_RR!K0>ers8Lv zVG5R@v)HE{F-?@pHnM*NkDA7PR6NNUrceobGdsZ%lU6F*%8mz*n#L6rk9US?t^}RO z1`|wH_!L<`r}zEU67(kap4j+kou z%X)qQhnmJ^6+6`hH1xwB|IHE0+5VDRU^!3L-^E#PuJ*(3|Je~sQ-8_s-@uusahr;r z-uYYmVYfCDERM9@)?b?RGdR;UF1MIE6T!1*YVL)-^;qy;J7?PZ11V*+cHI=TI{jtF zX6)R(Txzi(tvR&jzZ9A;n@;QpKJrZEy=_3xH{K4B-FzmLi*2Bc4}>f1$J7vd1Gutq=ZgrqLoF?JlizdiR#d#SNGC&JVmK;_&wa`dXp5h@Z;4WY(J?o6E^XE~0tVVE6y z_Xz>&R2?EANi%=TydXG%=)bcT1nUuVD5D;FX~Z=)!n=LT3)%I=({p&$s;gIa@W>gt z>guCAjFFaa>u!6N*kAkS5limg4bc5CwJGoxXJ+W^Yi*Lzr)= ztnkCfq&X6_q>qL6Qx!B!7w@GxtyH?1J)ht+bFam__;D3#^0XP}YZYk7z{>jcwdOC{)SY=a}Fc&RL#ZAkEWZLeiS@d+oG{E=MOwjVG) z^w!q%nNrXGCP5UiM-x2P?zMO_-(FZ-Q6RUOv*IZv5Z%_A#PY4rBD+iyF2uZezc= zcZ>(5(k%9i1ke3@Exxq}oX=RL1fS1-elNCKskDIIm*7>0`7he%Y{nV@ZJV);>|V!l zHcDkV?4AUl^Ls7shxa(6jH`eaIi+PQTOv^Y0IK*&D*cEpPVj8nYk8R2?R<=_fVa(9 z9$R$p7~7;$GrJ?f>&{+_x@d>9F;b=dW6WYdb{r!sm2G4T6MS4sEsq@j$k`a(0c{)O zW_HVisNY9|*u-v1@boOTcrlxukJAtEwsCG`^Y0y}zf@{s^AfxQN-d8TFraN~ zxrN>6IL=8@*+*yqEgdOQqY`y9u6rDfb7a!}%Dq058rM zXJ+r*JH}k8G@rel;FVX(4J*3sY>b6~7RShCv%fozu}CU2v8@R{#iiV%hktW6#=U^H zjd2V6>w~EO3khN~`!hIMDd)}n;(VNyfVYj)#Qt>eIBTWS9JU#ptdw&vYIZix20+`! zxt0CFah#1(**5knI2q>u@KtBje^r9cXTNvE^pjM!iM^EI)eP$AJR2`L>s6}+zmdJ@ zi0h72mP4e0yBOc$^Eoj@8d}x5>RgFoUF52(pM9)%d|3_%-fNd`aNoXzci^Rsihb*Q zL<#10F(jCeT?7dRpKp3?B%kpDTnq^&)kUqp(>ICd8eM*!q*wD^)T-8}el_{9^ub7E za1|_<68iH95lb&I^Q`D=OX6(sx&z6`B@ds#uZ$djM}{mI>33w=by6)gGZ*%d6$hAW z1Al|HPu2(fJ({H75+0|5JCKv2{ezIdcTpzu=Tyj_x?stWs8IjCtKFKlZJ!6pSvpQ_ zeit@H?d?Kl(s2pyZovue!zaMQD&;nneQZ8|nopqo@Y_OnSWXOsodNml(}W!3R~4{I z+4JsYlu`IifikK}@M;!qQKAo1?nzPFD$z>axWS}oLxy{6VMP(F=xMV776gXo4W`?O zwv~5|T2{Cvocr*c%XyvU&*omP?MFmrfIYnc#il1kaqKz8-0)%H!wxkZDzE##6Lmis zR$X5AukTHUJHN$NH|TP75%v4>_zlDAk=Jd*nR;05$ZYkE!>Sio=T~b+Uzh2}q)?&_ zYCP#nq1`TT4!=*xbSswa)F(y3=KG`L<;Wj8+}wR8JU?74VLr@16k9#H{`*dNMtqWw zPyhNJ8CZWiUoDr~`!EMFRDIDNEEGvz^TO$ymI>CD_DFz1#%ohcl2x_Quv@mS?)%u$ z!t!+?U$Pz6`(0QSsf_Ol_MnAVHtGYTWahWY>>2*fr3;Z{n}4JlbmPt3wI4}@)%

I<`NWjxd9-uYhGY4bKEvwr)+g7Cr^v#Ur#g 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 RL2`zim!cs>roX~){U6GO|0e(d delta 68638 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 Date: Wed, 20 Dec 2023 18:32:05 +0300 Subject: [PATCH 62/65] target/riscv: pmp: Ignore writes when RW=01 and MML=0 This patch changes behavior on writing RW=01 to pmpcfg with MML=0. RWX filed is form of collective WARL with the combination of pmpcfg.RW=01 remains reserved for future standard use. According to definition of WARL writing the CSR has no other side effect. But current implementation change architectural state and change system behavior. After writing we will get unreadable-unwriteble region regardless on the previous state. On the other side WARL said that we should read legal value and nothing says about what we should write. Current behavior change system state regardless of whether we read this register or not. Fixes: ac66f2f0 ("target/riscv: pmp: Ignore writes when RW=01") Signed-off-by: Ivan Klokov Reviewed-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-ID: <20231220153205.11072-1-ivan.klokov@syntacore.com> Signed-off-by: Alistair Francis --- target/riscv/pmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c index dff9512c3f..2a76b611a0 100644 --- a/target/riscv/pmp.c +++ b/target/riscv/pmp.c @@ -126,7 +126,7 @@ static bool pmp_write_cfg(CPURISCVState *env, uint32_t pmp_index, uint8_t val) /* If !mseccfg.MML then ignore writes with encoding RW=01 */ if ((val & PMP_WRITE) && !(val & PMP_READ) && !MSECCFG_MML_ISSET(env)) { - val &= ~(PMP_WRITE | PMP_READ); + return false; } env->pmp_state.pmp[pmp_index].cfg_reg = val; pmp_update_rule_addr(env, pmp_index); From 9a7c6da4cd8458c76f619d84542f91d308ecb15f Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Mon, 8 Jan 2024 10:13:26 +1000 Subject: [PATCH 63/65] target/riscv: Assert that the CSR numbers will be correct The CSRs will always be between either CSR_MHPMCOUNTER3 and CSR_MHPMCOUNTER31 or CSR_MHPMCOUNTER3H and CSR_MHPMCOUNTER31H. So although ctr_index can't be negative, Coverity doesn't know this and it isn't obvious to human readers either. Let's add an assert to ensure that Coverity knows the values will be within range. To simplify the code let's also change the RV32 adjustment. Fixes: Coverity CID 1523910 Signed-off-by: Alistair Francis Reviewed-by: Daniel Henrique Barboza Message-ID: <20240108001328.280222-2-alistair.francis@wdc.com> Signed-off-by: Alistair Francis --- target/riscv/csr.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index d8f751a0ae..674ea075a4 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -195,8 +195,11 @@ static RISCVException mctr(CPURISCVState *env, int csrno) if ((riscv_cpu_mxl(env) == MXL_RV32) && csrno >= CSR_MCYCLEH) { /* Offset for RV32 mhpmcounternh counters */ - base_csrno += 0x80; + csrno -= 0x80; } + + g_assert(csrno >= CSR_MHPMCOUNTER3 && csrno <= CSR_MHPMCOUNTER31); + ctr_index = csrno - base_csrno; if ((BIT(ctr_index) & pmu_avail_ctrs >> 3) == 0) { /* The PMU is not enabled or counter is out of range */ From 1525d8aa3a56610e1c72f5dd305ec86ebad41769 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Mon, 8 Jan 2024 10:13:27 +1000 Subject: [PATCH 64/65] target/riscv: Don't adjust vscause for exceptions We have been incorrectly adjusting both the interrupt and exception cause when using the hypervisor extension and trapping to VS-mode. This patch changes the conditional to ensure we only adjust the cause for interrupts and not exceptions. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1708 Signed-off-by: Alistair Francis Reviewed-by: Daniel Henrique Barboza Message-ID: <20240108001328.280222-3-alistair.francis@wdc.com> Signed-off-by: Alistair Francis --- target/riscv/cpu_helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 99d1275729..c7cc7eb423 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -1749,8 +1749,8 @@ void riscv_cpu_do_interrupt(CPUState *cs) * See if we need to adjust cause. Yes if its VS mode interrupt * no if hypervisor has delegated one of hs mode's interrupt */ - if (cause == IRQ_VS_TIMER || cause == IRQ_VS_SOFT || - cause == IRQ_VS_EXT) { + if (async && (cause == IRQ_VS_TIMER || cause == IRQ_VS_SOFT || + cause == IRQ_VS_EXT)) { cause = cause - 1; } write_gva = false; From 71b76da33a1558bcd59100188f5753737ef6fa21 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Mon, 8 Jan 2024 10:13:28 +1000 Subject: [PATCH 65/65] target/riscv: Ensure mideleg is set correctly on reset Bits 10, 6, 2 and 12 of mideleg are read only 1 when the Hypervisor is enabled. We currently only set them on accesses to mideleg, but they aren't correctly set on reset. Let's ensure they are always the correct value. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1617 Signed-off-by: Alistair Francis Reviewed-by: Daniel Henrique Barboza Message-ID: <20240108001328.280222-4-alistair.francis@wdc.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index b32681f7f3..8cbfc7e781 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -931,6 +931,14 @@ static void riscv_cpu_reset_hold(Object *obj) /* mmte is supposed to have pm.current hardwired to 1 */ env->mmte |= (EXT_STATUS_INITIAL | MMTE_M_PM_CURRENT); + /* + * Bits 10, 6, 2 and 12 of mideleg are read only 1 when the Hypervisor + * extension is enabled. + */ + if (riscv_has_ext(env, RVH)) { + env->mideleg |= HS_MODE_INTERRUPTS; + } + /* * Clear mseccfg and unlock all the PMP entries upon reset. * This is allowed as per the priv and smepmp specifications