From 5e21b1317f900a574d85e0890ba156078964ba2c Mon Sep 17 00:00:00 2001 From: Dmitry Frolov Date: Fri, 28 Jun 2024 15:39:10 +0300 Subject: [PATCH 1/8] hw/loongarch/boot.c: fix out-of-bound reading memcpy() is trying to READ 512 bytes from memory, pointed by info->kernel_cmdline, which was (presumable) allocated by g_strdup(""); Found with ASAN, making check with enabled sanitizers. Signed-off-by: Dmitry Frolov Reviewed-by: Song Gao Message-Id: <20240628123910.577740-1-frolov@swemel.ru> Signed-off-by: Song Gao --- hw/loongarch/boot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c index b8e1aa18d5..cb668703bd 100644 --- a/hw/loongarch/boot.c +++ b/hw/loongarch/boot.c @@ -163,7 +163,7 @@ static void init_cmdline(struct loongarch_boot_info *info, void *p, void *start) info->a0 = 1; info->a1 = cmdline_addr; - memcpy(p, info->kernel_cmdline, COMMAND_LINE_SIZE); + g_strlcpy(p, info->kernel_cmdline, COMMAND_LINE_SIZE); } static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr) From 0aca736433dcb56f365fe8a18ed1b969ca247304 Mon Sep 17 00:00:00 2001 From: Xianglai Li Date: Mon, 24 Jun 2024 11:23:00 +0800 Subject: [PATCH 2/8] hw/loongarch: Change the tpm support by default Add devices that support tpm by default, Fixed incomplete tpm acpi table information. Signed-off-by: Xianglai Li Reviewed-by: Song Gao Message-Id: <20240624032300.999157-1-lixianglai@loongson.cn> Signed-off-by: Song Gao --- hw/loongarch/Kconfig | 1 + hw/loongarch/acpi-build.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig index 90a0dba9d5..89be737726 100644 --- a/hw/loongarch/Kconfig +++ b/hw/loongarch/Kconfig @@ -8,6 +8,7 @@ config LOONGARCH_VIRT imply VIRTIO_VGA imply PCI_DEVICES imply NVDIMM + imply TPM_TIS_SYSBUS select SERIAL select VIRTIO_PCI select PLATFORM_BUS diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c index af45ce526d..72bfc35ae6 100644 --- a/hw/loongarch/acpi-build.c +++ b/hw/loongarch/acpi-build.c @@ -646,6 +646,9 @@ void loongarch_acpi_setup(LoongArchVirtMachineState *lvms) build_state, tables.rsdp, ACPI_BUILD_RSDP_FILE); + fw_cfg_add_file(lvms->fw_cfg, ACPI_BUILD_TPMLOG_FILE, tables.tcpalog->data, + acpi_data_len(tables.tcpalog)); + qemu_register_reset(acpi_build_reset, build_state); acpi_build_reset(build_state); vmstate_register(NULL, 0, &vmstate_acpi_build, build_state); From 5efbc384c6dee9f4960e5ef05be84af370cef6bb Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 12 Jun 2024 11:36:37 +0800 Subject: [PATCH 3/8] hw/loongarch/virt: Remove unused assignment There is abuse usage about local variable gap. Remove duplicated assignment and solve Coverity reported error. Resolves: Coverity CID 1546441 Fixes: 3cc451cbce ("hw/loongarch: Refine fwcfg memory map") Signed-off-by: Bibo Mao Reviewed-by: Song Gao Message-Id: <20240612033637.167787-1-maobibo@loongson.cn> Signed-off-by: Song Gao --- hw/loongarch/virt.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c index 8be2d2ff6a..e592b1b6b7 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -1054,7 +1054,6 @@ static void fw_cfg_add_memory(MachineState *ms) memmap_add_entry(base, gap, 1); size -= gap; base = VIRT_HIGHMEM_BASE; - gap = ram_size - VIRT_LOWMEM_SIZE; } if (size) { @@ -1067,17 +1066,17 @@ static void fw_cfg_add_memory(MachineState *ms) } /* add fw_cfg memory map of other nodes */ - size = ram_size - numa_info[0].node_mem; - gap = VIRT_LOWMEM_BASE + VIRT_LOWMEM_SIZE; - if (base < gap && (base + size) > gap) { + if (numa_info[0].node_mem < gap && ram_size > gap) { /* * memory map for the maining nodes splited into two part - * lowram: [base, +(gap - base)) - * highram: [VIRT_HIGHMEM_BASE, +(size - (gap - base))) + * lowram: [base, +(gap - numa_info[0].node_mem)) + * highram: [VIRT_HIGHMEM_BASE, +(ram_size - gap)) */ - memmap_add_entry(base, gap - base, 1); - size -= gap - base; + memmap_add_entry(base, gap - numa_info[0].node_mem, 1); + size = ram_size - gap; base = VIRT_HIGHMEM_BASE; + } else { + size = ram_size - numa_info[0].node_mem; } if (size) From 36ff178716054d36ca2a61cdf3452514bd95220b Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Thu, 27 Jun 2024 05:13:28 +0100 Subject: [PATCH 4/8] MAINTAINERS: Add myself as a reviewer of LoongArch virt machine I would like to be informed on changes made to the LoongArch virt machine. I'm fairly familiar with Loongson-3 series platform hardware and doing firmwre (U-Boot) development as hobbyist on LoongArch virt platform, so I believe I can give positive review input to changes on that machine. Signed-off-by: Jiaxun Yang Reviewed-by: Song Gao Message-Id: <20240627-ipi-fixes-v1-2-9b061dc28a3a@flygoat.com> Signed-off-by: Song Gao --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 6725913c8b..41bece23c1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1240,6 +1240,7 @@ LoongArch Machines ------------------ Virt M: Song Gao +R: Jiaxun Yang S: Maintained F: docs/system/loongarch/virt.rst F: configs/targets/loongarch64-softmmu.mak From d38e31ef740d102020d1b14b5a2becd4336b462d Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Fri, 7 Jun 2024 11:50:16 +0800 Subject: [PATCH 5/8] target/loongarch/kvm: Add software breakpoint support With KVM virtualization, debug exception is injected to guest kernel rather than host for normal break intruction. Here hypercall instruction with special code is used for sw breakpoint usage, and detailed instruction comes from kvm kernel with user API KVM_REG_LOONGARCH_DEBUG_INST. Now only software breakpoint is supported, and it is allowed to insert/remove software breakpoint. We can debug guest kernel with gdb method after kernel is loaded, hardware breakpoint will be added in later. Signed-off-by: Bibo Mao Reviewed-by: Song Gao Tested-by: Song Gao Message-Id: <20240607035016.2975799-1-maobibo@loongson.cn> Signed-off-by: Song Gao --- configs/targets/loongarch64-softmmu.mak | 1 + target/loongarch/kvm/kvm.c | 76 +++++++++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/configs/targets/loongarch64-softmmu.mak b/configs/targets/loongarch64-softmmu.mak index 84beb19b90..65b65e0c34 100644 --- a/configs/targets/loongarch64-softmmu.mak +++ b/configs/targets/loongarch64-softmmu.mak @@ -1,5 +1,6 @@ TARGET_ARCH=loongarch64 TARGET_BASE_ARCH=loongarch +TARGET_KVM_HAVE_GUEST_DEBUG=y TARGET_SUPPORTS_MTTCG=y TARGET_XML_FILES= gdb-xml/loongarch-base32.xml gdb-xml/loongarch-base64.xml gdb-xml/loongarch-fpu.xml # all boards require libfdt diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c index 8e6e27c8bf..e1be6a6959 100644 --- a/target/loongarch/kvm/kvm.c +++ b/target/loongarch/kvm/kvm.c @@ -28,6 +28,7 @@ #include "trace.h" static bool cap_has_mp_state; +static unsigned int brk_insn; const KVMCapabilityInfo kvm_arch_required_capabilities[] = { KVM_CAP_LAST_INFO }; @@ -664,7 +665,14 @@ static void kvm_loongarch_vm_stage_change(void *opaque, bool running, int kvm_arch_init_vcpu(CPUState *cs) { + uint64_t val; + qemu_add_vm_change_state_handler(kvm_loongarch_vm_stage_change, cs); + + if (!kvm_get_one_reg(cs, KVM_REG_LOONGARCH_DEBUG_INST, &val)) { + brk_insn = val; + } + return 0; } @@ -739,6 +747,67 @@ bool kvm_arch_stop_on_emulation_error(CPUState *cs) return true; } +void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg) +{ + if (kvm_sw_breakpoints_active(cpu)) { + dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP; + } +} + +int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) +{ + if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0) || + cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&brk_insn, 4, 1)) { + error_report("%s failed", __func__); + return -EINVAL; + } + return 0; +} + +int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) +{ + static uint32_t brk; + + if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&brk, 4, 0) || + brk != brk_insn || + cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 1)) { + error_report("%s failed", __func__); + return -EINVAL; + } + return 0; +} + +int kvm_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type) +{ + return -ENOSYS; +} + +int kvm_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type) +{ + return -ENOSYS; +} + +void kvm_arch_remove_all_hw_breakpoints(void) +{ +} + +static bool kvm_loongarch_handle_debug(CPUState *cs, struct kvm_run *run) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + + kvm_cpu_synchronize_state(cs); + if (cs->singlestep_enabled) { + return true; + } + + if (kvm_find_sw_breakpoint(cs, env->pc)) { + return true; + } + + return false; +} + int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) { int ret = 0; @@ -757,6 +826,13 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) run->iocsr_io.len, run->iocsr_io.is_write); break; + + case KVM_EXIT_DEBUG: + if (kvm_loongarch_handle_debug(cs, run)) { + ret = EXCP_DEBUG; + } + break; + default: ret = -1; warn_report("KVM: unknown exit reason %d", run->exit_reason); From 785875874da1f419c09016b0fcea5e756caaa00c Mon Sep 17 00:00:00 2001 From: Feiyang Chen Date: Fri, 28 Jun 2024 13:33:57 +1000 Subject: [PATCH 6/8] target/loongarch: Remove avail_64 in trans_srai_w() and simplify it Since srai.w is a valid instruction on la32, remove the avail_64 check and simplify trans_srai_w(). Fixes: c0c0461e3a06 ("target/loongarch: Add avail_64 to check la64-only instructions") Reviewed-by: Richard Henderson Signed-off-by: Feiyang Chen Message-Id: <20240628033357.50027-1-chris.chenfeiyang@gmail.com> Signed-off-by: Song Gao --- target/loongarch/tcg/insn_trans/trans_shift.c.inc | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/target/loongarch/tcg/insn_trans/trans_shift.c.inc b/target/loongarch/tcg/insn_trans/trans_shift.c.inc index 2f4bd6ff28..377307785a 100644 --- a/target/loongarch/tcg/insn_trans/trans_shift.c.inc +++ b/target/loongarch/tcg/insn_trans/trans_shift.c.inc @@ -67,19 +67,9 @@ static void gen_rotr_d(TCGv dest, TCGv src1, TCGv src2) tcg_gen_rotr_tl(dest, src1, t0); } -static bool trans_srai_w(DisasContext *ctx, arg_srai_w *a) +static void gen_sari_w(TCGv dest, TCGv src1, target_long imm) { - TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE); - TCGv src1 = gpr_src(ctx, a->rj, EXT_ZERO); - - if (!avail_64(ctx)) { - return false; - } - - tcg_gen_sextract_tl(dest, src1, a->imm, 32 - a->imm); - gen_set_gpr(a->rd, dest, EXT_NONE); - - return true; + tcg_gen_sextract_tl(dest, src1, imm, 32 - imm); } TRANS(sll_w, ALL, gen_rrr, EXT_ZERO, EXT_NONE, EXT_SIGN, gen_sll_w) @@ -94,6 +84,7 @@ TRANS(slli_w, ALL, gen_rri_c, EXT_NONE, EXT_SIGN, tcg_gen_shli_tl) TRANS(slli_d, 64, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_shli_tl) TRANS(srli_w, ALL, gen_rri_c, EXT_ZERO, EXT_SIGN, tcg_gen_shri_tl) TRANS(srli_d, 64, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_shri_tl) +TRANS(srai_w, ALL, gen_rri_c, EXT_NONE, EXT_NONE, gen_sari_w) TRANS(srai_d, 64, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_sari_tl) TRANS(rotri_w, 64, gen_rri_v, EXT_NONE, EXT_NONE, gen_rotr_w) TRANS(rotri_d, 64, gen_rri_c, EXT_NONE, EXT_NONE, tcg_gen_rotri_tl) From bba1c36da0589b4179c16e0895256ca731023f2c Mon Sep 17 00:00:00 2001 From: Song Gao Date: Fri, 5 Jul 2024 10:18:38 +0800 Subject: [PATCH 7/8] target/loongarch: Set CSR_PRCFG1 and CSR_PRCFG2 values We set the value of register CSR_PRCFG3, but left out CSR_PRCFG1 and CSR_PRCFG2. Set CSR_PRCFG1 and CSR_PRCFG2 according to the default values of the physical machine. Signed-off-by: Song Gao Reviewed-by: Bibo Mao Message-Id: <20240705021839.1004374-1-gaosong@loongson.cn> --- target/loongarch/cpu.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index 69f9ad7711..61af018eec 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -457,6 +457,18 @@ static void loongarch_la464_initfn(Object *obj) env->cpucfg[20] = data; env->CSR_ASID = FIELD_DP64(0, CSR_ASID, ASIDBITS, 0xa); + + env->CSR_PRCFG1 = FIELD_DP64(env->CSR_PRCFG1, CSR_PRCFG1, SAVE_NUM, 8); + env->CSR_PRCFG1 = FIELD_DP64(env->CSR_PRCFG1, CSR_PRCFG1, TIMER_BITS, 0x2f); + env->CSR_PRCFG1 = FIELD_DP64(env->CSR_PRCFG1, CSR_PRCFG1, VSMAX, 7); + + env->CSR_PRCFG2 = 0x3ffff000; + + env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, TLB_TYPE, 2); + env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, MTLB_ENTRY, 63); + env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_WAYS, 7); + env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_SETS, 8); + loongarch_cpu_post_init(obj); } @@ -538,11 +550,6 @@ static void loongarch_cpu_reset_hold(Object *obj, ResetType type) env->CSR_MERRCTL = FIELD_DP64(env->CSR_MERRCTL, CSR_MERRCTL, ISMERR, 0); env->CSR_TID = cs->cpu_index; - env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, TLB_TYPE, 2); - env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, MTLB_ENTRY, 63); - env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_WAYS, 7); - env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_SETS, 8); - for (n = 0; n < 4; n++) { env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV0, 0); env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV1, 0); From 3ef4b21a5c767ff0b15047e709762abef490ad07 Mon Sep 17 00:00:00 2001 From: Song Gao Date: Fri, 5 Jul 2024 10:18:39 +0800 Subject: [PATCH 8/8] target/loongarch: Fix cpu_reset set wrong CSR_CRMD After cpu_reset, DATF in CSR_CRMD is 0, DATM is 0. See the manual[1] 6.4. [1]: https://github.com/loongson/LoongArch-Documentation/releases/download/2023.04.20/LoongArch-Vol1-v1.10-EN.pdf Signed-off-by: Song Gao Reviewed-by: Bibo Mao Message-Id: <20240705021839.1004374-2-gaosong@loongson.cn> --- target/loongarch/cpu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index 61af018eec..5e85b9dbef 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -523,13 +523,13 @@ static void loongarch_cpu_reset_hold(Object *obj, ResetType type) env->fcsr0 = 0x0; int n; - /* Set csr registers value after reset */ + /* Set csr registers value after reset, see the manual 6.4. */ env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PLV, 0); env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, IE, 0); env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DA, 1); env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PG, 0); - env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DATF, 1); - env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DATM, 1); + env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DATF, 0); + env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DATM, 0); env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, FPE, 0); env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, SXE, 0);