From b15bdc965106a10dbac2e50dc598ee7fd926ff14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 3 Apr 2023 16:12:29 +0100 Subject: [PATCH 1/4] target/arm: Fix non-TCG build failure by inlining pauth_ptr_mask() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit aarch64_gdb_get_pauth_reg() -- although disabled since commit 5787d17a42 ("target/arm: Don't advertise aarch64-pauth.xml to gdb") is still compiled in. It calls pauth_ptr_mask() which is located in target/arm/tcg/pauth_helper.c, a TCG specific helper. To avoid a linking error when TCG is not enabled: Undefined symbols for architecture arm64: "_pauth_ptr_mask", referenced from: _aarch64_gdb_get_pauth_reg in target_arm_gdbstub64.c.o ld: symbol(s) not found for architecture arm64 clang: error: linker command failed with exit code 1 (use -v to see invocation) - Inline pauth_ptr_mask() in aarch64_gdb_get_pauth_reg() (this is the single user), - Rename pauth_ptr_mask_internal() as pauth_ptr_mask() and inline it in "internals.h", Fixes: e995d5cce4 ("target/arm: Implement gdbstub pauth extension") Suggested-by: Richard Henderson Reviewed-by: Fabiano Rosas Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-id: 20230328212516.29592-1-philmd@linaro.org [PMM: reinstated doc comment] Signed-off-by: Peter Maydell --- target/arm/gdbstub64.c | 7 +++++-- target/arm/internals.h | 15 ++++++++++----- target/arm/tcg/pauth_helper.c | 18 +----------------- 3 files changed, 16 insertions(+), 24 deletions(-) diff --git a/target/arm/gdbstub64.c b/target/arm/gdbstub64.c index ec1e07f139..c1f7e8c934 100644 --- a/target/arm/gdbstub64.c +++ b/target/arm/gdbstub64.c @@ -230,8 +230,11 @@ int aarch64_gdb_get_pauth_reg(CPUARMState *env, GByteArray *buf, int reg) { bool is_data = !(reg & 1); bool is_high = reg & 2; - uint64_t mask = pauth_ptr_mask(env, -is_high, is_data); - return gdb_get_reg64(buf, mask); + ARMMMUIdx mmu_idx = arm_stage1_mmu_idx(env); + ARMVAParameters param; + + param = aa64_va_parameters(env, -is_high, mmu_idx, is_data); + return gdb_get_reg64(buf, pauth_ptr_mask(param)); } default: return 0; diff --git a/target/arm/internals.h b/target/arm/internals.h index 673519a24a..c2c70d5918 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1391,13 +1391,18 @@ bool arm_generate_debug_exceptions(CPUARMState *env); /** * pauth_ptr_mask: - * @env: cpu context - * @ptr: selects between TTBR0 and TTBR1 - * @data: selects between TBI and TBID + * @param: parameters defining the MMU setup * - * Return a mask of the bits of @ptr that contain the authentication code. + * Return a mask of the address bits that contain the authentication code, + * given the MMU config defined by @param. */ -uint64_t pauth_ptr_mask(CPUARMState *env, uint64_t ptr, bool data); +static inline uint64_t pauth_ptr_mask(ARMVAParameters param) +{ + int bot_pac_bit = 64 - param.tsz; + int top_pac_bit = 64 - 8 * param.tbi; + + return MAKE_64BIT_MASK(bot_pac_bit, top_pac_bit - bot_pac_bit); +} /* Add the cpreg definitions for debug related system registers */ void define_debug_regs(ARMCPU *cpu); diff --git a/target/arm/tcg/pauth_helper.c b/target/arm/tcg/pauth_helper.c index 20f347332d..de067fa716 100644 --- a/target/arm/tcg/pauth_helper.c +++ b/target/arm/tcg/pauth_helper.c @@ -339,17 +339,9 @@ static uint64_t pauth_addpac(CPUARMState *env, uint64_t ptr, uint64_t modifier, return pac | ext | ptr; } -static uint64_t pauth_ptr_mask_internal(ARMVAParameters param) -{ - int bot_pac_bit = 64 - param.tsz; - int top_pac_bit = 64 - 8 * param.tbi; - - return MAKE_64BIT_MASK(bot_pac_bit, top_pac_bit - bot_pac_bit); -} - static uint64_t pauth_original_ptr(uint64_t ptr, ARMVAParameters param) { - uint64_t mask = pauth_ptr_mask_internal(param); + uint64_t mask = pauth_ptr_mask(param); /* Note that bit 55 is used whether or not the regime has 2 ranges. */ if (extract64(ptr, 55, 1)) { @@ -359,14 +351,6 @@ static uint64_t pauth_original_ptr(uint64_t ptr, ARMVAParameters param) } } -uint64_t pauth_ptr_mask(CPUARMState *env, uint64_t ptr, bool data) -{ - ARMMMUIdx mmu_idx = arm_stage1_mmu_idx(env); - ARMVAParameters param = aa64_va_parameters(env, ptr, mmu_idx, data); - - return pauth_ptr_mask_internal(param); -} - static uint64_t pauth_auth(CPUARMState *env, uint64_t ptr, uint64_t modifier, ARMPACKey *key, bool data, int keynumber) { From 12148d442ec3f4386c8624ffcf44c61a8b344018 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 3 Apr 2023 16:12:30 +0100 Subject: [PATCH 2/4] hw/arm: do not free machine->fdt in arm_load_dtb() At this moment, arm_load_dtb() can free machine->fdt when binfo->dtb_filename is NULL. If there's no 'dtb_filename', 'fdt' will be retrieved by binfo->get_dtb(). If get_dtb() returns machine->fdt, as is the case of machvirt_dtb() from hw/arm/virt.c, fdt now has a pointer to machine->fdt. And, in that case, the existing g_free(fdt) at the end of arm_load_dtb() will make machine->fdt point to an invalid memory region. Since monitor command 'dumpdtb' was introduced a couple of releases ago, running it with any ARM machine that uses arm_load_dtb() will crash QEMU. Let's enable all arm_load_dtb() callers to use dumpdtb properly. Instead of freeing 'fdt', assign it back to ms->fdt. Cc: Peter Maydell Cc: qemu-arm@nongnu.org Fixes: bf353ad55590f ("qmp/hmp, device_tree.c: introduce dumpdtb") Reported-by: Markus Armbruster Signed-off-by: Daniel Henrique Barboza Signed-off-by: Markus Armbruster Reviewed-by: Daniel Henrique Barboza Message-id: 20230328165935.1512846-1-armbru@redhat.com Signed-off-by: Peter Maydell --- hw/arm/boot.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hw/arm/boot.c b/hw/arm/boot.c index 50e5141116..54f6a3e0b3 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -689,7 +689,10 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo, qemu_register_reset_nosnapshotload(qemu_fdt_randomize_seeds, rom_ptr_for_as(as, addr, size)); - g_free(fdt); + if (fdt != ms->fdt) { + g_free(ms->fdt); + ms->fdt = fdt; + } return size; From 782781e85decfd85a6d9b064be741fb30d4fd307 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 3 Apr 2023 16:12:30 +0100 Subject: [PATCH 3/4] target/arm: Fix generated code for cpreg reads when HSTR is active In commit 049edada we added some code to handle HSTR_EL2 traps, which we did as an inline "conditionally branch over a gen_exception_insn()". Unfortunately this fails to take account of the fact that gen_exception_insn() will set s->base.is_jmp to DISAS_NORETURN. That means that at the end of the TB we won't generate the necessary code to handle the "branched over the trap and continued normal execution" codepath. The result is that the TCG main loop thinks that we stopped execution of the TB due to a situation that only happens when icount is enabled, and hits an assertion. Explicitly set is_jmp back to DISAS_NEXT so we generate the correct code for when execution continues past this insn. Note that this only happens for cpreg reads; writes will call gen_lookup_tb() which generates a valid end-of-TB. Fixes: 049edada ("target/arm: Make HSTR_EL2 traps take priority over UNDEF-at-EL1") Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1551 Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20230330101900.2320380-1-peter.maydell@linaro.org --- target/arm/tcg/translate.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c index 2cb9368b1b..3c8401e908 100644 --- a/target/arm/tcg/translate.c +++ b/target/arm/tcg/translate.c @@ -4623,6 +4623,12 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64, tcg_gen_brcondi_i32(TCG_COND_EQ, t, 0, over.label); gen_exception_insn(s, 0, EXCP_UDEF, syndrome); + /* + * gen_exception_insn() will set is_jmp to DISAS_NORETURN, + * but since we're conditionally branching over it, we want + * to assume continue-to-next-instruction. + */ + s->base.is_jmp = DISAS_NEXT; set_disas_label(s, over); } } From a0eaa126af3c5a43937a22c58cfb9bb36e4a5001 Mon Sep 17 00:00:00 2001 From: Chris Rauer Date: Mon, 3 Apr 2023 16:12:30 +0100 Subject: [PATCH 4/4] hw/ssi: Fix Linux driver init issue with xilinx_spi The problem is that the Linux driver expects the master transaction inhibit bit(R_SPICR_MTI) to be set during driver initialization so that it can detect the fifo size but QEMU defaults it to zero out of reset. The datasheet indicates this bit is active on reset. See page 25, SPI Control Register section: https://www.xilinx.com/content/dam/xilinx/support/documents/ip_documentation/axi_quad_spi/v3_2/pg153-axi-quad-spi.pdf Signed-off-by: Chris Rauer Message-id: 20230323182811.2641044-1-crauer@google.com Reviewed-by: Edgar E. Iglesias Signed-off-by: Peter Maydell --- hw/ssi/xilinx_spi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/ssi/xilinx_spi.c b/hw/ssi/xilinx_spi.c index 552927622f..d4de2e7aab 100644 --- a/hw/ssi/xilinx_spi.c +++ b/hw/ssi/xilinx_spi.c @@ -156,6 +156,7 @@ static void xlx_spi_do_reset(XilinxSPI *s) txfifo_reset(s); s->regs[R_SPISSR] = ~0; + s->regs[R_SPICR] = R_SPICR_MTI; xlx_spi_update_irq(s); xlx_spi_update_cs(s); }