:p
atchew
Login
Hi; here's the first pullreq for arm for 2026. I had a big backlog of code review after the holidays so this is mostly "things that were fairly easy to review and collect up"... -- PMM The following changes since commit 4cfa1ce0365f56832f46ed8a82d8bd954d16be11: Merge tag 'for-upstream' of https://gitlab.com/bonzini/qemu into staging (2026-01-15 11:29:21 +1100) are available in the Git repository at: https://gitlab.com/pm215/qemu.git tags/pull-target-arm-20260115 for you to fetch changes up to 4efed64ffcdb99b977ad0b2129a9c0208456a6c9: target/arm: Rename access_aa64_tid5() to access_tid5() (2026-01-15 15:30:16 +0000) ---------------------------------------------------------------- target-arm queue: * hw/arm/raspi: remove duplicate include * target/arm: Enable FEAT_ASID2 emulation * hw/char/cmsdk-apb-uart.c: log guest_errors for r/w to disabled uart * hw/arm: Re-enable the MAX78000FTHR machine in qemu-system-arm/aarch64 * target/arm/ptw: make granule_protection_check usable without a cpu * hw/arm/omap: Remove omap_badwidth_* functions * hw/arm/smmu: add memory regions as property for an SMMU instance * docs/system/generic-loader: clarify * tests/functional: migrate aspeed_rainier image * target/arm: Correctly handle HCR.TID1 and TID3 traps on v7A CPUs ---------------------------------------------------------------- Alex Bennée (1): tests/functional: migrate aspeed_rainier image Jim MacArthur (4): target/arm: Enable ID_AA64MMFR4_EL1 register target/arm: Allow writes to FNG1, FNG0, A2 target/arm/tcg/cpu64.c: Enable ASID2 for cpu_max tests: Add test for ASID2 and write/read of feature bits Osama Abdelkader (1): hw/arm/raspi: remove duplicate include Peter Maydell (14): hw/sd/omap_mmc: Remove omap_badwidth_* calls hw/i2c/omap_i2c: Remove omap_badwidth_* calls hw/gpio/omap_gpio: Remove omap_badwidth_* calls hw/dma/omap_dma: Remove omap_badwidth_* calls hw/arm/omap1: Remove omap_badwidth_read* calls hw/arm/omap1: Remove omap_badwidth_write* calls hw/arm/omap1: Remove omap_badwidth_* implementations docs/system/generic-loader: Clarify behaviour of cpu-num docs/system/generic-loader: Don't mention QemuOpts implementation detail docs/system/generic-loader: move TODO to source code target/arm: Don't specify ID_PFR1 accessfn twice target/arm: Correctly honour HCR.TID3 for v7A cores target/arm: Correctly trap HCR.TID1 registers in v7A target/arm: Rename access_aa64_tid5() to access_tid5() Philippe Mathieu-Daudé (1): hw/arm: Re-enable the MAX78000FTHR machine in qemu-system-arm/aarch64 Pierrick Bouvier (2): target/arm/ptw: make granule_protection_check usable without a cpu hw/arm/smmu: add memory regions as property for an SMMU instance Tao Tang (1): target/arm: Move ARMSecuritySpace to a common header julia (1): hw/char/cmsdk-apb-uart.c: log guest_errors for r/w to disabled uart docs/system/arm/emulation.rst | 1 + docs/system/generic-loader.rst | 56 ++++---- hw/arm/max78000fthr.c | 3 +- hw/arm/omap1.c | 203 +++++++++++++------------- hw/arm/raspi.c | 1 - hw/arm/sbsa-ref.c | 16 ++- hw/arm/smmu-common.c | 11 ++ hw/arm/virt.c | 13 +- hw/char/cmsdk-apb-uart.c | 8 ++ hw/core/generic-loader.c | 18 +++ hw/dma/omap_dma.c | 7 +- hw/gpio/omap_gpio.c | 7 +- hw/i2c/omap_i2c.c | 7 +- hw/sd/omap_mmc.c | 7 +- include/hw/arm/arm-security.h | 37 +++++ include/hw/arm/omap.h | 10 -- include/hw/arm/smmu-common.h | 4 + include/hw/arm/virt.h | 2 + target/arm/cpu-features.h | 7 + target/arm/cpu-sysregs.h.inc | 1 + target/arm/cpu.h | 59 ++++---- target/arm/helper.c | 211 +++++++++++++++------------- target/arm/internals.h | 5 + target/arm/ptw.c | 57 +++++--- target/arm/tcg/cpu64.c | 4 + tests/functional/arm/test_aspeed_rainier.py | 6 +- tests/tcg/aarch64/system/asid2.c | 76 ++++++++++ 27 files changed, 537 insertions(+), 300 deletions(-) create mode 100644 include/hw/arm/arm-security.h create mode 100644 tests/tcg/aarch64/system/asid2.c
From: Osama Abdelkader <osama.abdelkader@gmail.com> hw/arm/boot.h is included twice Signed-off-by: Osama Abdelkader <osama.abdelkader@gmail.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/raspi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/raspi.c +++ b/hw/arm/raspi.c @@ -XXX,XX +XXX,XX @@ #include "qemu/error-report.h" #include "hw/core/boards.h" #include "hw/core/loader.h" -#include "hw/arm/boot.h" #include "hw/arm/machines-qom.h" #include "qom/object.h" -- 2.47.3
From: Jim MacArthur <jim.macarthur@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Gustavo Romero <gustavo.romero@linaro.org> Signed-off-by: Jim MacArthur <jim.macarthur@linaro.org> [PMM: add entry to v8_user_idregs[] list also] Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu-sysregs.h.inc | 1 + target/arm/helper.c | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/target/arm/cpu-sysregs.h.inc b/target/arm/cpu-sysregs.h.inc index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu-sysregs.h.inc +++ b/target/arm/cpu-sysregs.h.inc @@ -XXX,XX +XXX,XX @@ DEF(ID_AA64MMFR0_EL1, 3, 0, 0, 7, 0) DEF(ID_AA64MMFR1_EL1, 3, 0, 0, 7, 1) DEF(ID_AA64MMFR2_EL1, 3, 0, 0, 7, 2) DEF(ID_AA64MMFR3_EL1, 3, 0, 0, 7, 3) +DEF(ID_AA64MMFR4_EL1, 3, 0, 0, 7, 4) DEF(ID_PFR0_EL1, 3, 0, 0, 1, 0) DEF(ID_PFR1_EL1, 3, 0, 0, 1, 1) DEF(ID_DFR0_EL1, 3, 0, 0, 1, 2) diff --git a/target/arm/helper.c b/target/arm/helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu) .access = PL1_R, .type = ARM_CP_CONST, .accessfn = access_aa64_tid3, .resetvalue = GET_IDREG(isar, ID_AA64MMFR3) }, - { .name = "ID_AA64MMFR4_EL1_RESERVED", .state = ARM_CP_STATE_AA64, + { .name = "ID_AA64MMFR4_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 4, .access = PL1_R, .type = ARM_CP_CONST, .accessfn = access_aa64_tid3, - .resetvalue = 0 }, + .resetvalue = GET_IDREG(isar, ID_AA64MMFR4) }, { .name = "ID_AA64MMFR5_EL1_RESERVED", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 5, .access = PL1_R, .type = ARM_CP_CONST, @@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu) .exported_bits = R_ID_AA64MMFR2_AT_MASK }, { .name = "ID_AA64MMFR3_EL1", .exported_bits = 0 }, + { .name = "ID_AA64MMFR4_EL1", + .exported_bits = 0 }, { .name = "ID_AA64MMFR*_EL1_RESERVED", .is_glob = true }, { .name = "ID_AA64DFR0_EL1", -- 2.47.3
From: Jim MacArthur <jim.macarthur@linaro.org> This just allows read/write of three feature bits. ASID is still ignored. Any writes to TTBR0_EL0 and TTBR1_EL0, including changing the ASID, will still cause a complete flush of the TLB. Signed-off-by: Jim MacArthur <jim.macarthur@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu-features.h | 7 +++++++ target/arm/helper.c | 28 ++++++++++++++++++++++------ target/arm/internals.h | 5 +++++ 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64MMFR3, SDERR, 52, 4) FIELD(ID_AA64MMFR3, ADERR, 56, 4) FIELD(ID_AA64MMFR3, SPEC_FPACC, 60, 4) +FIELD(ID_AA64MMFR4, ASID2, 8, 4) + FIELD(ID_AA64DFR0, DEBUGVER, 0, 4) FIELD(ID_AA64DFR0, TRACEVER, 4, 4) FIELD(ID_AA64DFR0, PMUVER, 8, 4) @@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_aie(const ARMISARegisters *id) return FIELD_EX64_IDREG(id, ID_AA64MMFR3, AIE) != 0; } +static inline bool isar_feature_aa64_asid2(const ARMISARegisters *id) +{ + return FIELD_EX64_IDREG(id, ID_AA64MMFR4, ASID2) != 0; +} + static inline bool isar_feature_aa64_mec(const ARMISARegisters *id) { return FIELD_EX64_IDREG(id, ID_AA64MMFR3, MEC) != 0; diff --git a/target/arm/helper.c b/target/arm/helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -XXX,XX +XXX,XX @@ int alle1_tlbmask(CPUARMState *env) ARMMMUIdxBit_Stage2_S); } +int alle2_tlbmask(void) +{ + return (ARMMMUIdxBit_E20_2 | + ARMMMUIdxBit_E20_2_PAN | + ARMMMUIdxBit_E20_2_GCS | + ARMMMUIdxBit_E20_0 | + ARMMMUIdxBit_E20_0_GCS); +} + static const ARMCPRegInfo cp_reginfo[] = { /* * Define the secure and non-secure FCSE identifier CP registers @@ -XXX,XX +XXX,XX @@ static void vmsa_tcr_ttbr_el2_write(CPUARMState *env, const ARMCPRegInfo *ri, */ if (extract64(raw_read(env, ri) ^ value, 48, 16) && (arm_hcr_el2_eff(env) & HCR_E2H)) { - uint16_t mask = ARMMMUIdxBit_E20_2 | - ARMMMUIdxBit_E20_2_PAN | - ARMMMUIdxBit_E20_2_GCS | - ARMMMUIdxBit_E20_0 | - ARMMMUIdxBit_E20_0_GCS; - tlb_flush_by_mmuidx(env_cpu(env), mask); + tlb_flush_by_mmuidx(env_cpu(env), alle2_tlbmask()); } raw_write(env, ri, value); } @@ -XXX,XX +XXX,XX @@ static void tcr2_el1_write(CPUARMState *env, const ARMCPRegInfo *ri, if (cpu_isar_feature(aa64_aie, cpu)) { valid_mask |= TCR2_AIE; } + if (cpu_isar_feature(aa64_asid2, cpu)) { + valid_mask |= TCR2_FNG1 | TCR2_FNG0 | TCR2_A2; + if (((raw_read(env, ri) ^ value) & TCR2_A2) != 0) { + tlb_flush_by_mmuidx(CPU(cpu), alle1_tlbmask(env)); + } + } value &= valid_mask; raw_write(env, ri, value); } @@ -XXX,XX +XXX,XX @@ static void tcr2_el2_write(CPUARMState *env, const ARMCPRegInfo *ri, if (cpu_isar_feature(aa64_mec, cpu)) { valid_mask |= TCR2_AMEC0 | TCR2_AMEC1; } + if (cpu_isar_feature(aa64_asid2, cpu)) { + valid_mask |= TCR2_FNG1 | TCR2_FNG0 | TCR2_A2; + if (((raw_read(env, ri) ^ value) & TCR2_A2) != 0) { + tlb_flush_by_mmuidx(CPU(cpu), alle2_tlbmask()); + } + } value &= valid_mask; raw_write(env, ri, value); } diff --git a/target/arm/internals.h b/target/arm/internals.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -XXX,XX +XXX,XX @@ uint64_t gt_direct_access_timer_offset(CPUARMState *env, int timeridx); * all EL1" scope; this covers stage 1 and stage 2. */ int alle1_tlbmask(CPUARMState *env); +/* + * Return mask of ARMMMUIdxBit values corresponding to an "invalidate + * all EL2&0" scope. + */ +int alle2_tlbmask(void); /* Set the float_status behaviour to match the Arm defaults */ void arm_set_default_fp_behaviours(float_status *s); -- 2.47.3
From: Jim MacArthur <jim.macarthur@linaro.org> docs/system/arm/emulation.rst: Add ASID2 Reviewed-by: Gustavo Romero <gustavo.romero@linaro.org> Signed-off-by: Jim MacArthur <jim.macarthur@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- docs/system/arm/emulation.rst | 1 + target/arm/tcg/cpu64.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -XXX,XX +XXX,XX @@ the following architecture extensions: - FEAT_AIE (Memory Attribute Index Enhancement) - FEAT_Armv9_Crypto (Armv9 Cryptographic Extension) - FEAT_ASID16 (16 bit ASID) +- FEAT_ASID2 (Concurrent use of two ASIDs) - FEAT_ATS1A (Address Translation operations that ignore stage 1 permissions) - FEAT_BBM at level 2 (Translation table break-before-make levels) - FEAT_BF16 (AArch64 BFloat16 instructions) diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/cpu64.c +++ b/target/arm/tcg/cpu64.c @@ -XXX,XX +XXX,XX @@ void aarch64_max_tcg_initfn(Object *obj) t = FIELD_DP64(t, ID_AA64MMFR3, AIE, 1); /* FEAT_AIE */ SET_IDREG(isar, ID_AA64MMFR3, t); + t = GET_IDREG(isar, ID_AA64MMFR4); + t = FIELD_DP64(t, ID_AA64MMFR4, ASID2, 1); /* FEAT_ASID2 */ + SET_IDREG(isar, ID_AA64MMFR4, t); + t = GET_IDREG(isar, ID_AA64ZFR0); t = FIELD_DP64(t, ID_AA64ZFR0, SVEVER, 2); /* FEAT_SVE2p1 */ t = FIELD_DP64(t, ID_AA64ZFR0, AES, 2); /* FEAT_SVE_PMULL128 */ -- 2.47.3
From: Jim MacArthur <jim.macarthur@linaro.org> Test for presence of ASID2; if it is, check FNG1, FNG0, and A2 are writable, and read value shows the update. If not present, check these read as RES0. Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Signed-off-by: Jim MacArthur <jim.macarthur@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- tests/tcg/aarch64/system/asid2.c | 76 ++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 tests/tcg/aarch64/system/asid2.c diff --git a/tests/tcg/aarch64/system/asid2.c b/tests/tcg/aarch64/system/asid2.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/tcg/aarch64/system/asid2.c @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * + * ASID2 Feature presence and enabled TCR2_EL1 bits test + * + * Copyright (c) 2025 Linaro Ltd + * + */ + +#include <stdint.h> +#include <minilib.h> + +#define ID_AA64MMFR3_EL1 "S3_0_C0_C7_3" +#define ID_AA64MMFR4_EL1 "S3_0_C0_C7_4" +#define TCR2_EL1 "S3_0_C2_C0_3" + +int main() +{ + /* + * Test for presence of ASID2 and three feature bits enabled by it: + * https://developer.arm.com/documentation/109697/2025_09/Feature-descriptions/The-Armv9-5-architecture-extension + * Bits added are FNG1, FNG0, and A2. These should be RES0 if A2 is + * not enabled and read as the written value if A2 is enabled. + */ + + uint64_t out; + uint64_t idreg3; + uint64_t idreg4; + int tcr2_present; + int asid2_present; + + /* Mask is FNG1, FNG0, and A2 */ + const uint64_t feature_mask = (1ULL << 18 | 1ULL << 17 | 1ULL << 16); + const uint64_t in = feature_mask; + + asm("mrs %[idreg3], " ID_AA64MMFR3_EL1 "\n\t" + : [idreg3] "=r" (idreg3)); + + tcr2_present = ((idreg3 & 0xF) != 0); + + if (!tcr2_present) { + ml_printf("TCR2 is not present, cannot perform test"); + return 0; + } + + asm("mrs %[idreg4], " ID_AA64MMFR4_EL1 "\n\t" + : [idreg4] "=r" (idreg4)); + + asid2_present = ((idreg4 & 0xF00) != 0); + + asm("msr " TCR2_EL1 ", %[x0]\n\t" + "mrs %[x1], " TCR2_EL1 "\n\t" + : [x1] "=r" (out) + : [x0] "r" (in)); + + if (asid2_present) { + if ((out & feature_mask) == in) { + ml_printf("OK\n"); + return 0; + } else { + ml_printf("FAIL: ASID2 present, but read value %lx != " + "written value %lx\n", + out & feature_mask, in); + return 1; + } + } else { + if (out == 0) { + ml_printf("TCR2_EL1 reads as RES0 as expected\n"); + return 0; + } else { + ml_printf("FAIL: ASID2, missing but read value %lx != 0\n", + out & feature_mask, in); + return 1; + } + } +} -- 2.47.3
From: julia <midnight@trainwit.ch> I don't want to admit how many hours I spent trying to figure out why nothing was being printed (as the enable-ing code hadn't yet run, even thought it existed). Signed-off-by: julia <midnight@trainwit.ch> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-id: 20251217-cmsdk-uart-disabled-warning2-v1-1-847de48840bc@trainwit.ch Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/char/cmsdk-apb-uart.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hw/char/cmsdk-apb-uart.c b/hw/char/cmsdk-apb-uart.c index XXXXXXX..XXXXXXX 100644 --- a/hw/char/cmsdk-apb-uart.c +++ b/hw/char/cmsdk-apb-uart.c @@ -XXX,XX +XXX,XX @@ static uint64_t uart_read(void *opaque, hwaddr offset, unsigned size) switch (offset) { case A_DATA: r = s->rxbuf; + if (!(s->ctrl & R_CTRL_RX_EN_MASK)) { + qemu_log_mask(LOG_GUEST_ERROR, + "CMSDK APB UART: receive data read with Rx disabled\n"); + } s->state &= ~R_STATE_RXFULL_MASK; cmsdk_apb_uart_update(s); qemu_chr_fe_accept_input(&s->chr); @@ -XXX,XX +XXX,XX @@ static void uart_write(void *opaque, hwaddr offset, uint64_t value, switch (offset) { case A_DATA: s->txbuf = value; + if (!(s->ctrl & R_CTRL_TX_EN_MASK)) { + qemu_log_mask(LOG_GUEST_ERROR, + "CMSDK APB UART: transmit data write with Tx disabled\n"); + } if (s->state & R_STATE_TXFULL_MASK) { /* Buffer already full -- note the overrun and let the * existing pending transmit callback handle the new char. -- 2.47.3
From: Philippe Mathieu-Daudé <philmd@linaro.org> Unfortunately while rebasing the series registering the ARM/Aarch64 machine interfaces and getting it merged as commit 38c5ab40031 ("hw/arm: Filter machine types for qemu-system-arm/aarch64 binaries") we missed the recent addition of the MAX78000FTHR machine in commit 51eb283dd0e. Correct that. The effect is that the machine was accidentally disabled. Cc: qemu-stable@nongnu.org Reported-by: Thomas Huth <thuth@redhat.com> Tested-by: Thomas Huth <thuth@redhat.com> Tested-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-id: 20251218214306.63667-1-philmd@linaro.org Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3248 Fixes: 38c5ab40031 ("hw/arm: Filter machine types for single binary") Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/max78000fthr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/arm/max78000fthr.c b/hw/arm/max78000fthr.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/max78000fthr.c +++ b/hw/arm/max78000fthr.c @@ -XXX,XX +XXX,XX @@ #include "hw/core/qdev-properties.h" #include "hw/core/qdev-clock.h" #include "qemu/error-report.h" +#include "hw/arm/machines-qom.h" #include "hw/arm/max78000_soc.h" #include "hw/arm/boot.h" @@ -XXX,XX +XXX,XX @@ static void max78000_machine_init(MachineClass *mc) mc->valid_cpu_types = valid_cpu_types; } -DEFINE_MACHINE("max78000fthr", max78000_machine_init) +DEFINE_MACHINE_ARM("max78000fthr", max78000_machine_init) -- 2.47.3
From: Tao Tang <tangtao1634@phytium.com.cn> The ARMSecuritySpace enum and its related helpers were defined in the target-specific header target/arm/cpu.h. This prevented common, target-agnostic code like the SMMU model from using these definitions without triggering "cpu.h included from common code" errors. To resolve this, this commit introduces a new, lightweight header, include/hw/arm/arm-security.h, which is safe for inclusion by common code. The following change was made: - The ARMSecuritySpace enum and the arm_space_is_secure() and arm_secure_to_space() helpers have been moved from target/arm/cpu.h to the new hw/arm/arm-security.h header. This refactoring decouples the security state definitions from the core CPU implementation, allowing common hardware models to correctly handle security states without pulling in heavyweight, target-specific headers. Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn> Reviewed-by: Eric Auger <eric.auger@redhat.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-id: 20251216000122.763264-2-pierrick.bouvier@linaro.org Link: https://lists.nongnu.org/archive/html/qemu-arm/2025-09/msg01288.html Signed-off-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- include/hw/arm/arm-security.h | 37 +++++++++++++++++++++++++++++++++++ target/arm/cpu.h | 25 +---------------------- 2 files changed, 38 insertions(+), 24 deletions(-) create mode 100644 include/hw/arm/arm-security.h diff --git a/include/hw/arm/arm-security.h b/include/hw/arm/arm-security.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/include/hw/arm/arm-security.h @@ -XXX,XX +XXX,XX @@ +/* + * ARM security space helpers + * + * Provide ARMSecuritySpace and helpers for code that is not tied to CPU. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_ARM_ARM_SECURITY_H +#define HW_ARM_ARM_SECURITY_H + +/* + * ARM v9 security states. + * The ordering of the enumeration corresponds to the low 2 bits + * of the GPI value, and (except for Root) the concat of NSE:NS. + */ + + typedef enum ARMSecuritySpace { + ARMSS_Secure = 0, + ARMSS_NonSecure = 1, + ARMSS_Root = 2, + ARMSS_Realm = 3, +} ARMSecuritySpace; + +/* Return true if @space is secure, in the pre-v9 sense. */ +static inline bool arm_space_is_secure(ARMSecuritySpace space) +{ + return space == ARMSS_Secure || space == ARMSS_Root; +} + +/* Return the ARMSecuritySpace for @secure, assuming !RME or EL[0-2]. */ +static inline ARMSecuritySpace arm_secure_to_space(bool secure) +{ + return secure ? ARMSS_Secure : ARMSS_NonSecure; +} + +#endif /* HW_ARM_ARM_SECURITY_H */ diff --git a/target/arm/cpu.h b/target/arm/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -XXX,XX +XXX,XX @@ #include "exec/page-protection.h" #include "qapi/qapi-types-common.h" #include "target/arm/multiprocessing.h" +#include "hw/arm/arm-security.h" #include "target/arm/gtimer.h" #include "target/arm/cpu-sysregs.h" #include "target/arm/mmuidx.h" @@ -XXX,XX +XXX,XX @@ static inline int arm_feature(CPUARMState *env, int feature) void arm_cpu_finalize_features(ARMCPU *cpu, Error **errp); -/* - * ARM v9 security states. - * The ordering of the enumeration corresponds to the low 2 bits - * of the GPI value, and (except for Root) the concat of NSE:NS. - */ - -typedef enum ARMSecuritySpace { - ARMSS_Secure = 0, - ARMSS_NonSecure = 1, - ARMSS_Root = 2, - ARMSS_Realm = 3, -} ARMSecuritySpace; - -/* Return true if @space is secure, in the pre-v9 sense. */ -static inline bool arm_space_is_secure(ARMSecuritySpace space) -{ - return space == ARMSS_Secure || space == ARMSS_Root; -} - -/* Return the ARMSecuritySpace for @secure, assuming !RME or EL[0-2]. */ -static inline ARMSecuritySpace arm_secure_to_space(bool secure) -{ - return secure ? ARMSS_Secure : ARMSS_NonSecure; -} #if !defined(CONFIG_USER_ONLY) /** -- 2.47.3
From: Pierrick Bouvier <pierrick.bouvier@linaro.org> By removing cpu details and use a config struct, we can use the same granule_protection_check with other devices, like SMMU. Signed-off-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20251216000122.763264-3-pierrick.bouvier@linaro.org [PMM: avoid local vars in middle of block] Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu.h | 34 +++++++++++++++++++++++++++++ target/arm/ptw.c | 57 ++++++++++++++++++++++++++++++------------------ 2 files changed, 70 insertions(+), 21 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -XXX,XX +XXX,XX @@ void arm_v7m_cpu_do_interrupt(CPUState *cpu); hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr, MemTxAttrs *attrs); + +typedef struct ARMGranuleProtectionConfig { + /* GPCCR_EL3 */ + uint64_t gpccr; + /* GPTBR_EL3 */ + uint64_t gptbr; + /* ID_AA64MMFR0_EL1.PARange */ + uint8_t parange; + /* FEAT_SEL2 */ + bool support_sel2; + /* Address space to access Granule Protection Table */ + AddressSpace *gpt_as; +} ARMGranuleProtectionConfig; + +/** + * arm_granule_protection_check + * @config: granule protection configuration + * @paddress: address accessed + * @pspace: physical address space accessed + * @ss: security state for access + * @fi: fault information in case a fault is detected + * + * Checks if @paddress can be accessed in physical adress space @pspace + * for @ss secure state, following granule protection setup with @config. + * If a fault is detected, @fi is set accordingly. + * See GranuleProtectionCheck() in A-profile manual. + * + * Returns: true if access is authorized, else false. + */ +bool arm_granule_protection_check(ARMGranuleProtectionConfig config, + uint64_t paddress, + ARMSecuritySpace pspace, + ARMSecuritySpace ss, + ARMMMUFaultInfo *fi); #endif /* !CONFIG_USER_ONLY */ int arm_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); diff --git a/target/arm/ptw.c b/target/arm/ptw.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -XXX,XX +XXX,XX @@ static bool regime_translation_disabled(CPUARMState *env, ARMMMUIdx mmu_idx, return (regime_sctlr(env, mmu_idx) & SCTLR_M) == 0; } -static bool granule_protection_check(CPUARMState *env, uint64_t paddress, - ARMSecuritySpace pspace, - ARMSecuritySpace ss, - ARMMMUFaultInfo *fi) +bool arm_granule_protection_check(ARMGranuleProtectionConfig config, + uint64_t paddress, + ARMSecuritySpace pspace, + ARMSecuritySpace ss, + ARMMMUFaultInfo *fi) { MemTxAttrs attrs = { .secure = true, .space = ARMSS_Root, }; - ARMCPU *cpu = env_archcpu(env); - uint64_t gpccr = env->cp15.gpccr_el3; + const uint64_t gpccr = config.gpccr; unsigned pps, pgs, l0gptsz, level = 0; uint64_t tableaddr, pps_mask, align, entry, index; - AddressSpace *as; MemTxResult result; int gpi; - if (!FIELD_EX64(gpccr, GPCCR, GPC)) { - return true; - } + /* + * We assume Granule Protection Check is enabled when + * calling this function (GPCCR.GPC == 1). + */ /* * GPC Priority 1 (R_GMGRR): @@ -XXX,XX +XXX,XX @@ static bool granule_protection_check(CPUARMState *env, uint64_t paddress, * physical address size is invalid. */ pps = FIELD_EX64(gpccr, GPCCR, PPS); - if (pps > FIELD_EX64_IDREG(&cpu->isar, ID_AA64MMFR0, PARANGE)) { + if (pps > config.parange) { goto fault_walk; } pps = pamax_map[pps]; @@ -XXX,XX +XXX,XX @@ static bool granule_protection_check(CPUARMState *env, uint64_t paddress, } /* GPC Priority 4: the base address of GPTBR_EL3 exceeds PPS. */ - tableaddr = env->cp15.gptbr_el3 << 12; + tableaddr = config.gptbr << 12; if (tableaddr & ~pps_mask) { goto fault_size; } @@ -XXX,XX +XXX,XX @@ static bool granule_protection_check(CPUARMState *env, uint64_t paddress, align = MAKE_64BIT_MASK(0, align); tableaddr &= ~align; - as = arm_addressspace(env_cpu(env), attrs); - /* Level 0 lookup. */ index = extract64(paddress, l0gptsz, pps - l0gptsz); tableaddr += index * 8; - entry = address_space_ldq_le(as, tableaddr, attrs, &result); + entry = address_space_ldq_le(config.gpt_as, tableaddr, attrs, &result); if (result != MEMTX_OK) { goto fault_eabt; } @@ -XXX,XX +XXX,XX @@ static bool granule_protection_check(CPUARMState *env, uint64_t paddress, level = 1; index = extract64(paddress, pgs + 4, l0gptsz - pgs - 4); tableaddr += index * 8; - entry = address_space_ldq_le(as, tableaddr, attrs, &result); + entry = address_space_ldq_le(config.gpt_as, tableaddr, attrs, &result); if (result != MEMTX_OK) { goto fault_eabt; } @@ -XXX,XX +XXX,XX @@ static bool granule_protection_check(CPUARMState *env, uint64_t paddress, case 0b1111: /* all access */ return true; case 0b1000: /* secure */ - if (!cpu_isar_feature(aa64_sel2, cpu)) { + if (!config.support_sel2) { goto fault_walk; } /* fall through */ @@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_gpc(CPUARMState *env, S1Translate *ptw, memop, result, fi)) { return true; } - if (!granule_protection_check(env, result->f.phys_addr, - result->f.attrs.space, ptw->in_space, fi)) { - fi->type = ARMFault_GPCFOnOutput; - return true; + + if (FIELD_EX64(env->cp15.gpccr_el3, GPCCR, GPC)) { + ARMCPU *cpu = env_archcpu(env); + MemTxAttrs attrs = { + .secure = true, + .space = ARMSS_Root, + }; + struct ARMGranuleProtectionConfig config = { + .gpccr = env->cp15.gpccr_el3, + .gptbr = env->cp15.gptbr_el3, + .parange = FIELD_EX64_IDREG(&cpu->isar, ID_AA64MMFR0, PARANGE), + .support_sel2 = cpu_isar_feature(aa64_sel2, cpu), + .gpt_as = arm_addressspace(env_cpu(env), attrs) + }; + if (!arm_granule_protection_check(config, result->f.phys_addr, + result->f.attrs.space, ptw->in_space, + fi)) { + fi->type = ARMFault_GPCFOnOutput; + return true; + } } + return false; } -- 2.47.3
The omap_badwidth_read* and omap_badwidth_write* functions are used by various OMAP devices when the guest makes an access to registers with an invalid width; they do two things: - log a GUEST_ERROR for the access - call cpu_physical_memory_read() or cpu_physical_memory_write() with the offset they are passed in The first of these produces an unhelpful log message because the function name that is printed is that of the omap-badwidth_* function, not that of the read or write function of the device that called it; this means you can't tell what device is involved. The second is wrong because the offset is an offset into the device but we use it as an absolute physical address, so we will access whatever is at low memory. That happens to be the boot ROM, so we will ignore a write and return random garbage on a read. This bug has been present since 2011, when we did the conversions to the MemoryRegion APIs, which involved changing all devices from working with absolute physical addresses to working with offsets within their MemoryRegions. We must have missed updating these functions. Replace the uses of these functions in omap_mmc.c with an open-coded call to qemu_log_mask() and RAZ/WI behaviour. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> --- hw/sd/omap_mmc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/hw/sd/omap_mmc.c b/hw/sd/omap_mmc.c index XXXXXXX..XXXXXXX 100644 --- a/hw/sd/omap_mmc.c +++ b/hw/sd/omap_mmc.c @@ -XXX,XX +XXX,XX @@ static uint64_t omap_mmc_read(void *opaque, hwaddr offset, unsigned size) OMAPMMCState *s = opaque; if (size != 2) { - return omap_badwidth_read16(opaque, offset); + qemu_log_mask(LOG_GUEST_ERROR, "%s: read at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, offset, size); + return 0; } switch (offset) { @@ -XXX,XX +XXX,XX @@ static void omap_mmc_write(void *opaque, hwaddr offset, OMAPMMCState *s = opaque; if (size != 2) { - omap_badwidth_write16(opaque, offset, value); + qemu_log_mask(LOG_GUEST_ERROR, "%s: write at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, offset, size); return; } -- 2.47.3
The omap_badwidth_read* and omap_badwidth_write* functions are used by various OMAP devices when the guest makes an access to registers with an invalid width; they do two things: - log a GUEST_ERROR for the access - call cpu_physical_memory_read() or cpu_physical_memory_write() with the offset they are passed in The first of these produces an unhelpful log message because the function name that is printed is that of the omap-badwidth_* function, not that of the read or write function of the device that called it; this means you can't tell what device is involved. The second is wrong because the offset is an offset into the device but we use it as an absolute physical address, so we will access whatever is at low memory. That happens to be the boot ROM, so we will ignore a write and return random garbage on a read. This bug has been present since 2011, when we did the conversions to the MemoryRegion APIs, which involved changing all devices from working with absolute physical addresses to working with offsets within their MemoryRegions. We must have missed updating these functions. Replace the uses of these functions in omap_i2c.c with an open-coded call to qemu_log_mask() and RAZ/WI behaviour. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> --- hw/i2c/omap_i2c.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/hw/i2c/omap_i2c.c b/hw/i2c/omap_i2c.c index XXXXXXX..XXXXXXX 100644 --- a/hw/i2c/omap_i2c.c +++ b/hw/i2c/omap_i2c.c @@ -XXX,XX +XXX,XX @@ static uint64_t omap_i2c_readfn(void *opaque, hwaddr addr, case 2: return omap_i2c_read(opaque, addr); default: - return omap_badwidth_read16(opaque, addr); + qemu_log_mask(LOG_GUEST_ERROR, "%s: read at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); + return 0; } } @@ -XXX,XX +XXX,XX @@ static void omap_i2c_writefn(void *opaque, hwaddr addr, omap_i2c_write(opaque, addr, value); break; default: - omap_badwidth_write16(opaque, addr, value); + qemu_log_mask(LOG_GUEST_ERROR, "%s: write at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); break; } } -- 2.47.3
The omap_badwidth_read* and omap_badwidth_write* functions are used by various OMAP devices when the guest makes an access to registers with an invalid width; they do two things: - log a GUEST_ERROR for the access - call cpu_physical_memory_read() or cpu_physical_memory_write() with the offset they are passed in The first of these produces an unhelpful log message because the function name that is printed is that of the omap-badwidth_* function, not that of the read or write function of the device that called it; this means you can't tell what device is involved. The second is wrong because the offset is an offset into the device but we use it as an absolute physical address, so we will access whatever is at low memory. That happens to be the boot ROM, so we will ignore a write and return random garbage on a read. This bug has been present since 2011, when we did the conversions to the MemoryRegion APIs, which involved changing all devices from working with absolute physical addresses to working with offsets within their MemoryRegions. We must have missed updating these functions. Replace the uses of these functions in omap_gpio.c with an open-coded call to qemu_log_mask() and RAZ/WI behaviour. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> --- hw/gpio/omap_gpio.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/hw/gpio/omap_gpio.c b/hw/gpio/omap_gpio.c index XXXXXXX..XXXXXXX 100644 --- a/hw/gpio/omap_gpio.c +++ b/hw/gpio/omap_gpio.c @@ -XXX,XX +XXX,XX @@ static uint64_t omap_gpio_read(void *opaque, hwaddr addr, int offset = addr & OMAP_MPUI_REG_MASK; if (size != 2) { - return omap_badwidth_read16(opaque, addr); + qemu_log_mask(LOG_GUEST_ERROR, "%s: read at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); + return 0; } switch (offset) { @@ -XXX,XX +XXX,XX @@ static void omap_gpio_write(void *opaque, hwaddr addr, int ln; if (size != 2) { - omap_badwidth_write16(opaque, addr, value); + qemu_log_mask(LOG_GUEST_ERROR, "%s: write at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); return; } -- 2.47.3
The omap_badwidth_read* and omap_badwidth_write* functions are used by various OMAP devices when the guest makes an access to registers with an invalid width; they do two things: - log a GUEST_ERROR for the access - call cpu_physical_memory_read() or cpu_physical_memory_write() with the offset they are passed in The first of these produces an unhelpful log message because the function name that is printed is that of the omap-badwidth_* function, not that of the read or write function of the device that called it; this means you can't tell what device is involved. The second is wrong because the offset is an offset into the device but we use it as an absolute physical address, so we will access whatever is at low memory. That happens to be the boot ROM, so we will ignore a write and return random garbage on a read. This bug has been present since 2011, when we did the conversions to the MemoryRegion APIs, which involved changing all devices from working with absolute physical addresses to working with offsets within their MemoryRegions. We must have missed updating these functions. Replace the uses of these functions in omap_dma.c with an open-coded call to qemu_log_mask() and RAZ/WI behaviour. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> --- hw/dma/omap_dma.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/hw/dma/omap_dma.c b/hw/dma/omap_dma.c index XXXXXXX..XXXXXXX 100644 --- a/hw/dma/omap_dma.c +++ b/hw/dma/omap_dma.c @@ -XXX,XX +XXX,XX @@ static uint64_t omap_dma_read(void *opaque, hwaddr addr, unsigned size) uint16_t ret; if (size != 2) { - return omap_badwidth_read16(opaque, addr); + qemu_log_mask(LOG_GUEST_ERROR, "%s: read at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); + return 0; } switch (addr) { @@ -XXX,XX +XXX,XX @@ static void omap_dma_write(void *opaque, hwaddr addr, int reg, ch; if (size != 2) { - omap_badwidth_write16(opaque, addr, value); + qemu_log_mask(LOG_GUEST_ERROR, "%s: write at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); return; } -- 2.47.3
The omap_badwidth_read* and omap_badwidth_write* functions are used by various OMAP devices when the guest makes an access to registers with an invalid width; they do two things: - log a GUEST_ERROR for the access - call cpu_physical_memory_read() or cpu_physical_memory_write() with the offset they are passed in The first of these produces an unhelpful log message because the function name that is printed is that of the omap-badwidth_* function, not that of the read or write function of the device that called it; this means you can't tell what device is involved. The second is wrong because the offset is an offset into the device but we use it as an absolute physical address, so we will access whatever is at low memory. That happens to be the boot ROM, so we will ignore a write and return random garbage on a read. This bug has been present since 2011, when we did the conversions to the MemoryRegion APIs, which involved changing all devices from working with absolute physical addresses to working with offsets within their MemoryRegions. We must have missed updating these functions. Replace the uses of the omap_badwidth_read* functions in omap1.c with an open-coded call to qemu_log_mask() and RAZ/WI behaviour. We do just the reads here because there are a lot of callsites in omap1.c; the writes will be done in the next commit. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> --- hw/arm/omap1.c | 80 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 60 insertions(+), 20 deletions(-) diff --git a/hw/arm/omap1.c b/hw/arm/omap1.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/omap1.c +++ b/hw/arm/omap1.c @@ -XXX,XX +XXX,XX @@ static uint64_t omap_mpu_timer_read(void *opaque, hwaddr addr, struct omap_mpu_timer_s *s = opaque; if (size != 4) { - return omap_badwidth_read32(opaque, addr); + qemu_log_mask(LOG_GUEST_ERROR, "%s: read at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); + return 0; } switch (addr) { @@ -XXX,XX +XXX,XX @@ static uint64_t omap_wd_timer_read(void *opaque, hwaddr addr, struct omap_watchdog_timer_s *s = opaque; if (size != 2) { - return omap_badwidth_read16(opaque, addr); + qemu_log_mask(LOG_GUEST_ERROR, "%s: read at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); + return 0; } switch (addr) { @@ -XXX,XX +XXX,XX @@ static uint64_t omap_os_timer_read(void *opaque, hwaddr addr, int offset = addr & OMAP_MPUI_REG_MASK; if (size != 4) { - return omap_badwidth_read32(opaque, addr); + qemu_log_mask(LOG_GUEST_ERROR, "%s: read at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); + return 0; } switch (offset) { @@ -XXX,XX +XXX,XX @@ static uint64_t omap_ulpd_pm_read(void *opaque, hwaddr addr, uint16_t ret; if (size != 2) { - return omap_badwidth_read16(opaque, addr); + qemu_log_mask(LOG_GUEST_ERROR, "%s: read at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); + return 0; } switch (addr) { @@ -XXX,XX +XXX,XX @@ static uint64_t omap_pin_cfg_read(void *opaque, hwaddr addr, struct omap_mpu_state_s *s = opaque; if (size != 4) { - return omap_badwidth_read32(opaque, addr); + qemu_log_mask(LOG_GUEST_ERROR, "%s: read at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); + return 0; } switch (addr) { @@ -XXX,XX +XXX,XX @@ static uint64_t omap_id_read(void *opaque, hwaddr addr, struct omap_mpu_state_s *s = opaque; if (size != 4) { - return omap_badwidth_read32(opaque, addr); + qemu_log_mask(LOG_GUEST_ERROR, "%s: read at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); + return 0; } switch (addr) { @@ -XXX,XX +XXX,XX @@ static uint64_t omap_mpui_read(void *opaque, hwaddr addr, struct omap_mpu_state_s *s = opaque; if (size != 4) { - return omap_badwidth_read32(opaque, addr); + qemu_log_mask(LOG_GUEST_ERROR, "%s: read at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); + return 0; } switch (addr) { @@ -XXX,XX +XXX,XX @@ static uint64_t omap_tipb_bridge_read(void *opaque, hwaddr addr, struct omap_tipb_bridge_s *s = opaque; if (size < 2) { - return omap_badwidth_read16(opaque, addr); + qemu_log_mask(LOG_GUEST_ERROR, "%s: read at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); + return 0; } switch (addr) { @@ -XXX,XX +XXX,XX @@ static uint64_t omap_tcmi_read(void *opaque, hwaddr addr, uint32_t ret; if (size != 4) { - return omap_badwidth_read32(opaque, addr); + qemu_log_mask(LOG_GUEST_ERROR, "%s: read at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); + return 0; } switch (addr) { @@ -XXX,XX +XXX,XX @@ static uint64_t omap_dpll_read(void *opaque, hwaddr addr, struct dpll_ctl_s *s = opaque; if (size != 2) { - return omap_badwidth_read16(opaque, addr); + qemu_log_mask(LOG_GUEST_ERROR, "%s: read at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); + return 0; } if (addr == 0x00) /* CTL_REG */ @@ -XXX,XX +XXX,XX @@ static uint64_t omap_clkm_read(void *opaque, hwaddr addr, struct omap_mpu_state_s *s = opaque; if (size != 2) { - return omap_badwidth_read16(opaque, addr); + qemu_log_mask(LOG_GUEST_ERROR, "%s: read at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); + return 0; } switch (addr) { @@ -XXX,XX +XXX,XX @@ static uint64_t omap_clkdsp_read(void *opaque, hwaddr addr, CPUState *cpu = CPU(s->cpu); if (size != 2) { - return omap_badwidth_read16(opaque, addr); + qemu_log_mask(LOG_GUEST_ERROR, "%s: read at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); + return 0; } switch (addr) { @@ -XXX,XX +XXX,XX @@ static uint64_t omap_mpuio_read(void *opaque, hwaddr addr, uint16_t ret; if (size != 2) { - return omap_badwidth_read16(opaque, addr); + qemu_log_mask(LOG_GUEST_ERROR, "%s: read at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); + return 0; } switch (offset) { @@ -XXX,XX +XXX,XX @@ static uint64_t omap_uwire_read(void *opaque, hwaddr addr, unsigned size) int offset = addr & OMAP_MPUI_REG_MASK; if (size != 2) { - return omap_badwidth_read16(opaque, addr); + qemu_log_mask(LOG_GUEST_ERROR, "%s: read at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); + return 0; } switch (offset) { @@ -XXX,XX +XXX,XX @@ static uint64_t omap_pwl_read(void *opaque, hwaddr addr, unsigned size) int offset = addr & OMAP_MPUI_REG_MASK; if (size != 1) { - return omap_badwidth_read8(opaque, addr); + qemu_log_mask(LOG_GUEST_ERROR, "%s: read at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); + return 0; } switch (offset) { @@ -XXX,XX +XXX,XX @@ static uint64_t omap_pwt_read(void *opaque, hwaddr addr, unsigned size) int offset = addr & OMAP_MPUI_REG_MASK; if (size != 1) { - return omap_badwidth_read8(opaque, addr); + qemu_log_mask(LOG_GUEST_ERROR, "%s: read at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); + return 0; } switch (offset) { @@ -XXX,XX +XXX,XX @@ static uint64_t omap_rtc_read(void *opaque, hwaddr addr, unsigned size) uint8_t i; if (size != 1) { - return omap_badwidth_read8(opaque, addr); + qemu_log_mask(LOG_GUEST_ERROR, "%s: read at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); + return 0; } switch (offset) { @@ -XXX,XX +XXX,XX @@ static uint64_t omap_mcbsp_read(void *opaque, hwaddr addr, uint16_t ret; if (size != 2) { - return omap_badwidth_read16(opaque, addr); + qemu_log_mask(LOG_GUEST_ERROR, "%s: read at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); + return 0; } switch (offset) { @@ -XXX,XX +XXX,XX @@ static uint64_t omap_lpg_read(void *opaque, hwaddr addr, unsigned size) int offset = addr & OMAP_MPUI_REG_MASK; if (size != 1) { - return omap_badwidth_read8(opaque, addr); + qemu_log_mask(LOG_GUEST_ERROR, "%s: read at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); + return 0; } switch (offset) { @@ -XXX,XX +XXX,XX @@ static uint64_t omap_mpui_io_read(void *opaque, hwaddr addr, unsigned size) { if (size != 2) { - return omap_badwidth_read16(opaque, addr); + qemu_log_mask(LOG_GUEST_ERROR, "%s: read at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); + return 0; } if (addr == OMAP_MPUI_BASE) /* CMR */ -- 2.47.3
Complete the conversion started in the previous commit by changing all the omap_badwidth_write* calls to open-coded log-and-ignore behaviour. We can delete a FIXME comment about an infinite loop, because that only looped infinitely back before 2011 when the device was still using absolute physical addresses. Now that we are simply logging the error we can clearly see that there's no loop. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> --- hw/arm/omap1.c | 64 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 22 deletions(-) diff --git a/hw/arm/omap1.c b/hw/arm/omap1.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/omap1.c +++ b/hw/arm/omap1.c @@ -XXX,XX +XXX,XX @@ static void omap_mpu_timer_write(void *opaque, hwaddr addr, struct omap_mpu_timer_s *s = opaque; if (size != 4) { - omap_badwidth_write32(opaque, addr, value); + qemu_log_mask(LOG_GUEST_ERROR, "%s: write at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); return; } @@ -XXX,XX +XXX,XX @@ static void omap_wd_timer_write(void *opaque, hwaddr addr, struct omap_watchdog_timer_s *s = opaque; if (size != 2) { - omap_badwidth_write16(opaque, addr, value); + qemu_log_mask(LOG_GUEST_ERROR, "%s: write at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); return; } @@ -XXX,XX +XXX,XX @@ static void omap_os_timer_write(void *opaque, hwaddr addr, int offset = addr & OMAP_MPUI_REG_MASK; if (size != 4) { - omap_badwidth_write32(opaque, addr, value); + qemu_log_mask(LOG_GUEST_ERROR, "%s: write at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); return; } @@ -XXX,XX +XXX,XX @@ static void omap_ulpd_pm_write(void *opaque, hwaddr addr, uint16_t diff; if (size != 2) { - omap_badwidth_write16(opaque, addr, value); + qemu_log_mask(LOG_GUEST_ERROR, "%s: write at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); return; } @@ -XXX,XX +XXX,XX @@ static void omap_pin_cfg_write(void *opaque, hwaddr addr, uint32_t diff; if (size != 4) { - omap_badwidth_write32(opaque, addr, value); + qemu_log_mask(LOG_GUEST_ERROR, "%s: write at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); return; } @@ -XXX,XX +XXX,XX @@ static void omap_id_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { if (size != 4) { - omap_badwidth_write32(opaque, addr, value); + qemu_log_mask(LOG_GUEST_ERROR, "%s: write at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); return; } @@ -XXX,XX +XXX,XX @@ static void omap_mpui_write(void *opaque, hwaddr addr, struct omap_mpu_state_s *s = opaque; if (size != 4) { - omap_badwidth_write32(opaque, addr, value); + qemu_log_mask(LOG_GUEST_ERROR, "%s: write at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); return; } @@ -XXX,XX +XXX,XX @@ static void omap_tipb_bridge_write(void *opaque, hwaddr addr, struct omap_tipb_bridge_s *s = opaque; if (size < 2) { - omap_badwidth_write16(opaque, addr, value); + qemu_log_mask(LOG_GUEST_ERROR, "%s: write at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); return; } @@ -XXX,XX +XXX,XX @@ static void omap_tcmi_write(void *opaque, hwaddr addr, struct omap_mpu_state_s *s = opaque; if (size != 4) { - omap_badwidth_write32(opaque, addr, value); + qemu_log_mask(LOG_GUEST_ERROR, "%s: write at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); return; } @@ -XXX,XX +XXX,XX @@ static void omap_dpll_write(void *opaque, hwaddr addr, int div, mult; if (size != 2) { - omap_badwidth_write16(opaque, addr, value); + qemu_log_mask(LOG_GUEST_ERROR, "%s: write at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); return; } @@ -XXX,XX +XXX,XX @@ static void omap_clkm_write(void *opaque, hwaddr addr, }; if (size != 2) { - omap_badwidth_write16(opaque, addr, value); + qemu_log_mask(LOG_GUEST_ERROR, "%s: write at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); return; } @@ -XXX,XX +XXX,XX @@ static void omap_clkdsp_write(void *opaque, hwaddr addr, uint16_t diff; if (size != 2) { - omap_badwidth_write16(opaque, addr, value); + qemu_log_mask(LOG_GUEST_ERROR, "%s: write at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); return; } @@ -XXX,XX +XXX,XX @@ static void omap_mpuio_write(void *opaque, hwaddr addr, int ln; if (size != 2) { - omap_badwidth_write16(opaque, addr, value); + qemu_log_mask(LOG_GUEST_ERROR, "%s: write at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); return; } @@ -XXX,XX +XXX,XX @@ static void omap_uwire_write(void *opaque, hwaddr addr, int offset = addr & OMAP_MPUI_REG_MASK; if (size != 2) { - omap_badwidth_write16(opaque, addr, value); + qemu_log_mask(LOG_GUEST_ERROR, "%s: write at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); return; } @@ -XXX,XX +XXX,XX @@ static void omap_pwl_write(void *opaque, hwaddr addr, int offset = addr & OMAP_MPUI_REG_MASK; if (size != 1) { - omap_badwidth_write8(opaque, addr, value); + qemu_log_mask(LOG_GUEST_ERROR, "%s: write at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); return; } @@ -XXX,XX +XXX,XX @@ static void omap_pwt_write(void *opaque, hwaddr addr, int offset = addr & OMAP_MPUI_REG_MASK; if (size != 1) { - omap_badwidth_write8(opaque, addr, value); + qemu_log_mask(LOG_GUEST_ERROR, "%s: write at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); return; } @@ -XXX,XX +XXX,XX @@ static void omap_rtc_write(void *opaque, hwaddr addr, time_t ti[2]; if (size != 1) { - omap_badwidth_write8(opaque, addr, value); + qemu_log_mask(LOG_GUEST_ERROR, "%s: write at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); return; } @@ -XXX,XX +XXX,XX @@ static void omap_mcbsp_writew(void *opaque, hwaddr addr, return; } - omap_badwidth_write16(opaque, addr, value); + qemu_log_mask(LOG_GUEST_ERROR, "%s: write at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, 4); } static void omap_mcbsp_write(void *opaque, hwaddr addr, @@ -XXX,XX +XXX,XX @@ static void omap_mcbsp_write(void *opaque, hwaddr addr, omap_mcbsp_writew(opaque, addr, value); break; default: - omap_badwidth_write16(opaque, addr, value); + qemu_log_mask(LOG_GUEST_ERROR, "%s: write at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); } } @@ -XXX,XX +XXX,XX @@ static void omap_lpg_write(void *opaque, hwaddr addr, int offset = addr & OMAP_MPUI_REG_MASK; if (size != 1) { - omap_badwidth_write8(opaque, addr, value); + qemu_log_mask(LOG_GUEST_ERROR, "%s: write at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); return; } @@ -XXX,XX +XXX,XX @@ static uint64_t omap_mpui_io_read(void *opaque, hwaddr addr, static void omap_mpui_io_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - /* FIXME: infinite loop */ - omap_badwidth_write16(opaque, addr, value); + qemu_log_mask(LOG_GUEST_ERROR, "%s: write at offset 0x%" HWADDR_PRIx + " with bad width %d\n", __func__, addr, size); } static const MemoryRegionOps omap_mpui_io_ops = { -- 2.47.3
Now there are no callsites for the omap_badwidth_* family of functions we can remove their implementations. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> --- hw/arm/omap1.c | 59 ------------------------------------------- include/hw/arm/omap.h | 10 -------- 2 files changed, 69 deletions(-) diff --git a/hw/arm/omap1.c b/hw/arm/omap1.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/omap1.c +++ b/hw/arm/omap1.c @@ -XXX,XX +XXX,XX @@ #include "target/arm/cpu-qom.h" #include "trace.h" -static inline void omap_log_badwidth(const char *funcname, hwaddr addr, int sz) -{ - qemu_log_mask(LOG_GUEST_ERROR, "%s: %d-bit register %#08" HWADDR_PRIx "\n", - funcname, 8 * sz, addr); -} - -/* Should signal the TCMI/GPMC */ -uint32_t omap_badwidth_read8(void *opaque, hwaddr addr) -{ - uint8_t ret; - - omap_log_badwidth(__func__, addr, 1); - cpu_physical_memory_read(addr, &ret, 1); - return ret; -} - -void omap_badwidth_write8(void *opaque, hwaddr addr, - uint32_t value) -{ - uint8_t val8 = value; - - omap_log_badwidth(__func__, addr, 1); - cpu_physical_memory_write(addr, &val8, 1); -} - -uint32_t omap_badwidth_read16(void *opaque, hwaddr addr) -{ - uint16_t ret; - - omap_log_badwidth(__func__, addr, 2); - cpu_physical_memory_read(addr, &ret, 2); - return ret; -} - -void omap_badwidth_write16(void *opaque, hwaddr addr, - uint32_t value) -{ - uint16_t val16 = value; - - omap_log_badwidth(__func__, addr, 2); - cpu_physical_memory_write(addr, &val16, 2); -} - -uint32_t omap_badwidth_read32(void *opaque, hwaddr addr) -{ - uint32_t ret; - - omap_log_badwidth(__func__, addr, 4); - cpu_physical_memory_read(addr, &ret, 4); - return ret; -} - -void omap_badwidth_write32(void *opaque, hwaddr addr, - uint32_t value) -{ - omap_log_badwidth(__func__, addr, 4); - cpu_physical_memory_write(addr, &value, 4); -} - /* MPU OS timers */ struct omap_mpu_timer_s { MemoryRegion iomem; diff --git a/include/hw/arm/omap.h b/include/hw/arm/omap.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/arm/omap.h +++ b/include/hw/arm/omap.h @@ -XXX,XX +XXX,XX @@ struct omap_mpu_state_s { struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *sdram, const char *core); -uint32_t omap_badwidth_read8(void *opaque, hwaddr addr); -void omap_badwidth_write8(void *opaque, hwaddr addr, - uint32_t value); -uint32_t omap_badwidth_read16(void *opaque, hwaddr addr); -void omap_badwidth_write16(void *opaque, hwaddr addr, - uint32_t value); -uint32_t omap_badwidth_read32(void *opaque, hwaddr addr); -void omap_badwidth_write32(void *opaque, hwaddr addr, - uint32_t value); - void omap_mpu_wakeup(void *opaque, int irq, int req); #define OMAP_BAD_REG(paddr) \ -- 2.47.3
From: Pierrick Bouvier <pierrick.bouvier@linaro.org> This will be used to access non-secure and secure memory. Secure support and Granule Protection Check (for RME) for SMMU need to access secure memory. As well, it allows to remove usage of global address_space_memory, allowing different SMMU instances to have a specific view of memory. User creatable SMMU are handled as well for virt machine, by setting the memory properties when device is plugged in. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> Reviewed-by: Eric Auger <eric.auger@redhat.com> Message-id: 20260108210453.2280733-1-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/arm/sbsa-ref.c | 16 ++++++++++++---- hw/arm/smmu-common.c | 11 +++++++++++ hw/arm/virt.c | 13 +++++++++++-- include/hw/arm/smmu-common.h | 4 ++++ include/hw/arm/virt.h | 2 ++ 5 files changed, 40 insertions(+), 6 deletions(-) diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/sbsa-ref.c +++ b/hw/arm/sbsa-ref.c @@ -XXX,XX +XXX,XX @@ static void create_xhci(const SBSAMachineState *sms) sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(sms->gic, irq)); } -static void create_smmu(const SBSAMachineState *sms, PCIBus *bus) +static void create_smmu(const SBSAMachineState *sms, PCIBus *bus, + MemoryRegion *sysmem, + MemoryRegion *secure_sysmem) { hwaddr base = sbsa_ref_memmap[SBSA_SMMU].base; int irq = sbsa_ref_irqmap[SBSA_SMMU]; @@ -XXX,XX +XXX,XX @@ static void create_smmu(const SBSAMachineState *sms, PCIBus *bus) object_property_set_str(OBJECT(dev), "stage", "nested", &error_abort); object_property_set_link(OBJECT(dev), "primary-bus", OBJECT(bus), &error_abort); + object_property_set_link(OBJECT(dev), "memory", OBJECT(sysmem), + &error_abort); + object_property_set_link(OBJECT(dev), "secure-memory", OBJECT(secure_sysmem), + &error_abort); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); for (i = 0; i < NUM_SMMU_IRQS; i++) { @@ -XXX,XX +XXX,XX @@ static void create_smmu(const SBSAMachineState *sms, PCIBus *bus) } } -static void create_pcie(SBSAMachineState *sms) +static void create_pcie(SBSAMachineState *sms, + MemoryRegion *sysmem, + MemoryRegion *secure_sysmem) { hwaddr base_ecam = sbsa_ref_memmap[SBSA_PCIE_ECAM].base; hwaddr size_ecam = sbsa_ref_memmap[SBSA_PCIE_ECAM].size; @@ -XXX,XX +XXX,XX @@ static void create_pcie(SBSAMachineState *sms) pci_create_simple(pci->bus, -1, "bochs-display"); - create_smmu(sms, pci->bus); + create_smmu(sms, pci->bus, sysmem, secure_sysmem); } static void *sbsa_ref_dtb(const struct arm_boot_info *binfo, int *fdt_size) @@ -XXX,XX +XXX,XX @@ static void sbsa_ref_init(MachineState *machine) create_xhci(sms); - create_pcie(sms); + create_pcie(sms, sysmem, secure_sysmem); create_secure_ec(secure_sysmem); diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/smmu-common.c +++ b/hw/arm/smmu-common.c @@ -XXX,XX +XXX,XX @@ static void smmu_base_realize(DeviceState *dev, Error **errp) return; } + g_assert(s->memory); + address_space_init(&s->memory_as, s->memory, "smmu-memory-view"); + if (s->secure_memory) { + address_space_init(&s->secure_memory_as, s->secure_memory, + "smmu-secure-memory-view"); + } + /* * We only allow default PCIe Root Complex(pcie.0) or pxb-pcie based extra * root complexes to be associated with SMMU. @@ -XXX,XX +XXX,XX @@ static const Property smmu_dev_properties[] = { DEFINE_PROP_BOOL("smmu_per_bus", SMMUState, smmu_per_bus, false), DEFINE_PROP_LINK("primary-bus", SMMUState, primary_bus, TYPE_PCI_BUS, PCIBus *), + DEFINE_PROP_LINK("memory", SMMUState, memory, + TYPE_MEMORY_REGION, MemoryRegion *), + DEFINE_PROP_LINK("secure-memory", SMMUState, secure_memory, + TYPE_MEMORY_REGION, MemoryRegion *), }; static void smmu_base_class_init(ObjectClass *klass, const void *data) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index XXXXXXX..XXXXXXX 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -XXX,XX +XXX,XX @@ static void create_smmuv3_dev_dtb(VirtMachineState *vms, 0x0, vms->iommu_phandle, 0x0, 0x10000); } -static void create_smmu(const VirtMachineState *vms, - PCIBus *bus) +static void create_smmu(const VirtMachineState *vms, PCIBus *bus) { VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms); int irq = vms->irqmap[VIRT_SMMU]; @@ -XXX,XX +XXX,XX @@ static void create_smmu(const VirtMachineState *vms, } object_property_set_link(OBJECT(dev), "primary-bus", OBJECT(bus), &error_abort); + object_property_set_link(OBJECT(dev), "memory", OBJECT(vms->sysmem), + &error_abort); + object_property_set_link(OBJECT(dev), "secure-memory", OBJECT(vms->secure_sysmem), + &error_abort); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); for (i = 0; i < NUM_SMMU_IRQS; i++) { @@ -XXX,XX +XXX,XX @@ static void create_pcie(VirtMachineState *vms) memory_region_init_alias(ecam_alias, OBJECT(dev), "pcie-ecam", ecam_reg, 0, size_ecam); memory_region_add_subregion(get_system_memory(), base_ecam, ecam_alias); + vms->sysmem = get_system_memory(); /* Map the MMIO window into system address space so as to expose * the section of PCI MMIO space which starts at the same base address @@ -XXX,XX +XXX,XX @@ static void machvirt_init(MachineState *machine) * devices go in at higher priority and take precedence. */ secure_sysmem = g_new(MemoryRegion, 1); + vms->secure_sysmem = secure_sysmem; memory_region_init(secure_sysmem, OBJECT(machine), "secure-memory", UINT64_MAX); memory_region_add_subregion_overlap(secure_sysmem, 0, sysmem, -1); @@ -XXX,XX +XXX,XX @@ static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev, } else if (vms->iommu == VIRT_IOMMU_NONE) { /* The new SMMUv3 device is specific to the PCI bus */ object_property_set_bool(OBJECT(dev), "smmu_per_bus", true, NULL); + object_property_set_link(OBJECT(dev), "memory", + OBJECT(vms->sysmem), NULL); + object_property_set_link(OBJECT(dev), "secure-memory", + OBJECT(vms->secure_sysmem), NULL); } } } diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/arm/smmu-common.h +++ b/include/hw/arm/smmu-common.h @@ -XXX,XX +XXX,XX @@ struct SMMUState { uint8_t bus_num; PCIBus *primary_bus; bool smmu_per_bus; /* SMMU is specific to the primary_bus */ + MemoryRegion *memory; + AddressSpace memory_as; + MemoryRegion *secure_memory; + AddressSpace secure_memory_as; }; struct SMMUBaseClass { diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h @@ -XXX,XX +XXX,XX @@ struct VirtMachineState { bool ns_el2_virt_timer_irq; CXLState cxl_devices_state; bool legacy_smmuv3_present; + MemoryRegion *sysmem; + MemoryRegion *secure_sysmem; }; #define VIRT_ECAM_ID(high) (high ? VIRT_HIGH_PCIE_ECAM : VIRT_PCIE_ECAM) -- 2.47.3
The cpu-num suboption to the generic loader has two effects when it is used with -device loader,file=<file>: * it specifies which CPU to load the data through * it specifies which CPU gets its PC set to the file's entry point Our documentation is not very clear about what happens if you don't pass this suboption. The default is that we pick the first CPU to load the data, but we don't set the PC for any CPU, so the "If not specified, the default is CPU 0" is confusing: it applies for loading but not for the PC setting. Clarify the text to make it clearer that the option has two effects and the default behaviour is different for the two effects. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> --- docs/system/generic-loader.rst | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/docs/system/generic-loader.rst b/docs/system/generic-loader.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/system/generic-loader.rst +++ b/docs/system/generic-loader.rst @@ -XXX,XX +XXX,XX @@ shown below: ``<cpu-num>`` This specifies the CPU that should be used. This is an - optional argument and will cause the CPU's PC to be set to the - memory address where the raw file is loaded or the entry point - specified in the executable format header. This option should only - be used for the boot image. This will also cause the image to be - written to the specified CPU's address space. If not specified, the - default is CPU 0. + optional argument with two effects: + + * this CPU's address space is used to load the data + * this CPU's PC will be set to the address where the raw file is loaded + or the entry point specified in the executable format header + + If this option is not specified, then the data will be loaded via + the address space of the first CPU, and no CPU will have its PC set. + + Since it sets the starting PC, this option should only be used for the boot + image. ``<force-raw>`` Setting 'force-raw=on' forces the file to be treated as a raw image. -- 2.47.3
We currently say "All values are parsed using the standard QemuOpts parsing". This doesn't tell the user anything useful because we don't mention QemuOpts anywhere else in the docs. What we're really trying to tell the user is what we mention afterwards: that the values are decimal, and you need an 0x prefix for hex. How we achieve it is an implementation detail the user doesn't need to know. Drop the explicit mention of QemuOpts; this in passing removes a typo "QemuOps" that we made in one place. Put the informative note more closely associated with the <addr> suboption which is the one that users might most reasonably assume to default to hex. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> --- docs/system/generic-loader.rst | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/docs/system/generic-loader.rst b/docs/system/generic-loader.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/system/generic-loader.rst +++ b/docs/system/generic-loader.rst @@ -XXX,XX +XXX,XX @@ can be done by following the syntax below:: ``<addr>`` The address to store the data in. + Note that as usual with QEMU numeric option values, the default is to + treat the argument as decimal. To specify a value in hex, prefix it + with '0x'. + ``<data>`` The value to be written to the address. The maximum size of the data is 8 bytes. @@ -XXX,XX +XXX,XX @@ can be done by following the syntax below:: The number of the CPU's address space where the data should be loaded. If not specified the address space of the first CPU is used. -All values are parsed using the standard QemuOps parsing. This allows the user -to specify any values in any format supported. By default the values -will be parsed as decimal. To use hex values the user should prefix the number -with a '0x'. An example of loading value 0x8000000e to address 0xfd1a0104 is:: @@ -XXX,XX +XXX,XX @@ can be done by following the syntax below:: ``<addr>`` The value to use as the CPU's PC. + Note that as usual with QEMU numeric option values, the default is to + treat the argument as decimal. To specify a value in hex, prefix it + with '0x'. + ``<cpu-num>`` The number of the CPU whose PC should be set to the specified value. -All values are parsed using the standard QemuOpts parsing. This allows the user -to specify any values in any format supported. By default the values -will be parsed as decimal. To use hex values the user should prefix the number -with a '0x'. - An example of setting CPU 0's PC to 0x8000 is:: -device loader,addr=0x8000,cpu-num=0 @@ -XXX,XX +XXX,XX @@ shown below: The memory address where the file should be loaded. This is required for raw images and ignored for non-raw files. + Note that as usual with QEMU numeric option values, the default is to + treat the argument as decimal. To specify a value in hex, prefix it + with '0x'. + ``<cpu-num>`` This specifies the CPU that should be used. This is an optional argument with two effects: @@ -XXX,XX +XXX,XX @@ shown below: This can be used to load supported executable formats as if they were raw. -All values are parsed using the standard QemuOpts parsing. This allows the user -to specify any values in any format supported. By default the values -will be parsed as decimal. To use hex values the user should prefix the number -with a '0x'. An example of loading an ELF file which CPU0 will boot is shown below:: -- 2.47.3
Currently we have a "Restrictions and ToDos" section at the bottom of the document which notes that there's no way to specify a CPU to load a file through that doesn't also set that CPU's PC. This is written as a developer-facing note. Move this to a TODO comment in the source code, and provide a shorter user-facing statement of the current restriction under the specific sub-option that it applies to. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> --- docs/system/generic-loader.rst | 14 +++----------- hw/core/generic-loader.c | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/docs/system/generic-loader.rst b/docs/system/generic-loader.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/system/generic-loader.rst +++ b/docs/system/generic-loader.rst @@ -XXX,XX +XXX,XX @@ shown below: If this option is not specified, then the data will be loaded via the address space of the first CPU, and no CPU will have its PC set. + Note that there is currently no way to specify the address space to + load the data without also causing that CPU's PC to be set. + Since it sets the starting PC, this option should only be used for the boot image. @@ -XXX,XX +XXX,XX @@ shown below: An example of loading an ELF file which CPU0 will boot is shown below:: -device loader,file=./images/boot.elf,cpu-num=0 - -Restrictions and ToDos -^^^^^^^^^^^^^^^^^^^^^^ - -At the moment it is just assumed that if you specify a cpu-num then -you want to set the PC as well. This might not always be the case. In -future the internal state 'set_pc' (which exists in the generic loader -now) should be exposed to the user so that they can choose if the PC -is set or not. - - diff --git a/hw/core/generic-loader.c b/hw/core/generic-loader.c index XXXXXXX..XXXXXXX 100644 --- a/hw/core/generic-loader.c +++ b/hw/core/generic-loader.c @@ -XXX,XX +XXX,XX @@ * separate backend. */ +/* + * TODO: currently the "load a file" functionality provides no way + * for the user to specify which CPU address space to load the data + * into without also causing that CPU's PC to be set to the start + * address of the file. + * + * We could fix this by having a new suboption set-pc (default: true) + * so the user can say + * -device loader,file=<file>,cpu-num=<cpu-num> + * for the current "use this address space and set the PC" behaviour + * or + * -device loader,file=<file>,cpu-num=<cpu-num>,set-pc=off + * to just pick the address space and not set the PC. + * + * Using set-pc without file= should be handled as an error; otherwise + * it can feed through to what we set s->set_pc to. + */ + #include "qemu/osdep.h" #include "system/dma.h" #include "system/reset.h" -- 2.47.3
From: Alex Bennée <alex.bennee@linaro.org> Cedric has a host for the file which allows us to keep the name. Cc: qemu-stable@nongnu.org Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Cédric Le Goater <clg@redhat.com> Message-id: 20260113135941.3361163-1-alex.bennee@linaro.org Cc: Cédric Le Goater <clg@kaod.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- tests/functional/arm/test_aspeed_rainier.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/functional/arm/test_aspeed_rainier.py b/tests/functional/arm/test_aspeed_rainier.py index XXXXXXX..XXXXXXX 100755 --- a/tests/functional/arm/test_aspeed_rainier.py +++ b/tests/functional/arm/test_aspeed_rainier.py @@ -XXX,XX +XXX,XX @@ class RainierMachine(AspeedTest): - ASSET_RAINIER_EMMC = Asset( - ('https://fileserver.linaro.org/s/B6pJTwWEkzSDi36/download/' - 'mmc-p10bmc-20240617.qcow2'), - 'd523fb478d2b84d5adc5658d08502bc64b1486955683814f89c6137518acd90b') + ASSET_RAINIER_EMMC = Asset('https://kaod.org/qemu/aspeed/rainier/mmc-p10bmc-20240617.qcow2', + 'd523fb478d2b84d5adc5658d08502bc64b1486955683814f89c6137518acd90b') def test_arm_aspeed_emmc_boot(self): self.set_machine('rainier-bmc') -- 2.47.3
In the definition of ID_PFR1 we have an ifdef block; we specify the accessfn once in the common part of the ifdef and once in the not-user-only part, which is redundant but harmless. The accessfn will always return success in user-only mode (because we won't trap to EL2), so specify it only in the not-user-only half of the ifdef, as was probably the intention. This is only cc'd to stable to avoid a textual conflict with the following patch, which is a bug fix. Cc: qemu-stable@nongnu.org Fixes: 0f150c8499e970bd ("target/arm: Constify ID_PFR1 on user emulation") Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20251231170858.254594-2-peter.maydell@linaro.org --- target/arm/helper.c | 1 - 1 file changed, 1 deletion(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu) { .name = "ID_PFR1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 1, .access = PL1_R, .type = ARM_CP_NO_RAW, - .accessfn = access_aa32_tid3, #ifdef CONFIG_USER_ONLY .type = ARM_CP_CONST, .resetvalue = GET_IDREG(isar, ID_PFR1), -- 2.47.3
The HCR.TID3 bit defines that we should trap to the hypervisor for reads to a collection of ID registers. Different architecture versions have defined this differently: * v7A has a set of ID regs that definitely must trap: - ID_PFR{0,1}, ID_DFR0, ID_AFR0, ID_MMFR{0,1,2,3}, ID_ISAR{0,1,2,3,4,5}, MVFR{0,1} and somewhat vaguely says that "there is no requirement" to trap for registers that are reserved in the ID reg space (i.e. which RAZ and might be used for new ID regs in future) * v8A adds to this list: - ID_PFR2 and MVFR2 must trap - ID_MMFR4, ID_MMFR5, ID_ISAR6, ID_DFR1 and reserved registers in the ID reg space must trap if FEAT_FGT is implemented, and it is IMPDEF if they trap if FEAT_FGT is not implemented In QEMU we seem to have attempted to implement this distinction (taking the "we do trap" IMPDEF choice if no FEAT_FGT), with access_aa64_tid3() always trapping on TID3 and access_aa32_tid3() trapping only if ARM_FEATURE_V8 is set. However, we didn't apply these to the right set of registers: we use access_aa32_tid3() on all the 32-bit ID registers *except* ID_PFR2, ID_DFR1, ID_MMFR5 and the RES0 space, which means that for a v7 CPU we don't trap on a lot of registers that we should trap on, and we do trap on various things that the v7A Arm ARM says there is "no requirement" to trap on. Straighten this out by naming the access functions more clearly for their purpose, and documenting this: access_v7_tid3() is only for the fixed set of ID registers that v7A traps on HCR.TID3, and access_tid3() is for any others, including the reserved encoding spaces and any new registers we add in future. AArch32 MVFR2 access is handled differently, in check_hcr_el2_trap; there we already do not trap on TID3 on v7A cores (where MVFR2 doesn't exist), because we in the code-generation function we UNDEF if ARM_FEATURE_V8 is not set, without generating code to call check_hcr_el2_trap. This bug was causing a problem for Xen which (after a recent change to Xen) expects to be able to trap ID_PFR0 on a Cortex-A15. The result of these changes is that our v8A behaviour remains the same, and on v7A we now trap the registers the Arm ARM definitely requires us to trap, and don't trap the reserved space that "there is no requirement" to trap. Cc: qemu-stable@nongnu.org Fixes: 6a4ef4e5d1084c ("target/arm: Honor HCR_EL2.TID3 trapping requirements") Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20251231170858.254594-3-peter.maydell@linaro.org --- target/arm/helper.c | 146 ++++++++++++++++++++++++-------------------- 1 file changed, 81 insertions(+), 65 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo ccsidr2_reginfo[] = { .readfn = ccsidr2_read, .type = ARM_CP_NO_RAW }, }; -static CPAccessResult access_aa64_tid3(CPUARMState *env, const ARMCPRegInfo *ri, - bool isread) +static CPAccessResult access_v7a_tid3(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) { + /* + * Trap on TID3 always. This should be used only for the fixed set of + * registers which are defined to trap on HCR.TID3 in v7A, which is: + * ID_PFR{0,1}, ID_DFR0, ID_AFR0, ID_MMFR{0,1,2,3}, ID_ISAR{0,1,2,3,4,5} + * (MVFR0 and MVFR1 also trap in v7A, but this is not handled via + * this accessfn but in check_hcr_el2_trap.) + * Any other registers in the TID3 trap space should use access_tid3(), + * so that they trap on v8 and above, but not on v7. + */ if ((arm_current_el(env) < 2) && (arm_hcr_el2_eff(env) & HCR_TID3)) { return CP_ACCESS_TRAP_EL2; } @@ -XXX,XX +XXX,XX @@ static CPAccessResult access_aa64_tid3(CPUARMState *env, const ARMCPRegInfo *ri, return CP_ACCESS_OK; } -static CPAccessResult access_aa32_tid3(CPUARMState *env, const ARMCPRegInfo *ri, - bool isread) +static CPAccessResult access_tid3(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) { + /* + * Trap on TID3, if we implement at least v8. For v8 and above + * the ID register space is at least IMPDEF permitted to trap, + * and must trap if FEAT_FGT is implemented. We choose to trap + * always. Use this function for any new registers that should + * trap on TID3. + */ if (arm_feature(env, ARM_FEATURE_V8)) { - return access_aa64_tid3(env, ri, isread); + return access_v7a_tid3(env, ri, isread); } return CP_ACCESS_OK; @@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu) { .name = "ID_PFR0", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 0, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa32_tid3, + .accessfn = access_v7a_tid3, .resetvalue = GET_IDREG(isar, ID_PFR0)}, /* * ID_PFR1 is not a plain ARM_CP_CONST because we don't know @@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu) .resetvalue = GET_IDREG(isar, ID_PFR1), #else .type = ARM_CP_NO_RAW, - .accessfn = access_aa32_tid3, + .accessfn = access_v7a_tid3, .readfn = id_pfr1_read, .writefn = arm_cp_write_ignore #endif @@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu) { .name = "ID_DFR0", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 2, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa32_tid3, + .accessfn = access_v7a_tid3, .resetvalue = GET_IDREG(isar, ID_DFR0)}, { .name = "ID_AFR0", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 3, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa32_tid3, + .accessfn = access_v7a_tid3, .resetvalue = GET_IDREG(isar, ID_AFR0)}, { .name = "ID_MMFR0", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 4, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa32_tid3, + .accessfn = access_v7a_tid3, .resetvalue = GET_IDREG(isar, ID_MMFR0)}, { .name = "ID_MMFR1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 5, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa32_tid3, + .accessfn = access_v7a_tid3, .resetvalue = GET_IDREG(isar, ID_MMFR1)}, { .name = "ID_MMFR2", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 6, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa32_tid3, + .accessfn = access_v7a_tid3, .resetvalue = GET_IDREG(isar, ID_MMFR2)}, { .name = "ID_MMFR3", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 7, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa32_tid3, + .accessfn = access_v7a_tid3, .resetvalue = GET_IDREG(isar, ID_MMFR3)}, { .name = "ID_ISAR0", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 0, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa32_tid3, + .accessfn = access_v7a_tid3, .resetvalue = GET_IDREG(isar, ID_ISAR0)}, { .name = "ID_ISAR1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 1, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa32_tid3, + .accessfn = access_v7a_tid3, .resetvalue = GET_IDREG(isar, ID_ISAR1)}, { .name = "ID_ISAR2", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 2, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa32_tid3, + .accessfn = access_v7a_tid3, .resetvalue = GET_IDREG(isar, ID_ISAR2)}, { .name = "ID_ISAR3", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 3, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa32_tid3, + .accessfn = access_v7a_tid3, .resetvalue = GET_IDREG(isar, ID_ISAR3) }, { .name = "ID_ISAR4", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 4, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa32_tid3, + .accessfn = access_v7a_tid3, .resetvalue = GET_IDREG(isar, ID_ISAR4) }, { .name = "ID_ISAR5", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 5, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa32_tid3, + .accessfn = access_v7a_tid3, .resetvalue = GET_IDREG(isar, ID_ISAR5) }, { .name = "ID_MMFR4", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 6, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa32_tid3, + .accessfn = access_tid3, .resetvalue = GET_IDREG(isar, ID_MMFR4)}, { .name = "ID_ISAR6", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 7, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa32_tid3, + .accessfn = access_tid3, .resetvalue = GET_IDREG(isar, ID_ISAR6) }, }; define_arm_cp_regs(cpu, v6_idregs); @@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu) .resetvalue = GET_IDREG(isar, ID_AA64PFR0) #else .type = ARM_CP_NO_RAW, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .readfn = id_aa64pfr0_read, .writefn = arm_cp_write_ignore #endif @@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu) { .name = "ID_AA64PFR1_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 1, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = GET_IDREG(isar, ID_AA64PFR1)}, { .name = "ID_AA64PFR2_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 2, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = GET_IDREG(isar, ID_AA64PFR2)}, { .name = "ID_AA64PFR3_EL1_RESERVED", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 3, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = 0 }, { .name = "ID_AA64ZFR0_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 4, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = GET_IDREG(isar, ID_AA64ZFR0)}, { .name = "ID_AA64SMFR0_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 5, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = GET_IDREG(isar, ID_AA64SMFR0)}, { .name = "ID_AA64PFR6_EL1_RESERVED", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 6, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = 0 }, { .name = "ID_AA64PFR7_EL1_RESERVED", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 7, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = 0 }, { .name = "ID_AA64DFR0_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 0, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = GET_IDREG(isar, ID_AA64DFR0) }, { .name = "ID_AA64DFR1_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 1, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = GET_IDREG(isar, ID_AA64DFR1) }, { .name = "ID_AA64DFR2_EL1_RESERVED", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 2, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = 0 }, { .name = "ID_AA64DFR3_EL1_RESERVED", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 3, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = 0 }, { .name = "ID_AA64AFR0_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 4, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = GET_IDREG(isar, ID_AA64AFR0) }, { .name = "ID_AA64AFR1_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 5, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = GET_IDREG(isar, ID_AA64AFR1) }, { .name = "ID_AA64AFR2_EL1_RESERVED", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 6, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = 0 }, { .name = "ID_AA64AFR3_EL1_RESERVED", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 7, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = 0 }, { .name = "ID_AA64ISAR0_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 0, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = GET_IDREG(isar, ID_AA64ISAR0)}, { .name = "ID_AA64ISAR1_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 1, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = GET_IDREG(isar, ID_AA64ISAR1)}, { .name = "ID_AA64ISAR2_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 2, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = GET_IDREG(isar, ID_AA64ISAR2)}, { .name = "ID_AA64ISAR3_EL1_RESERVED", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 3, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = 0 }, { .name = "ID_AA64ISAR4_EL1_RESERVED", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 4, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = 0 }, { .name = "ID_AA64ISAR5_EL1_RESERVED", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 5, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = 0 }, { .name = "ID_AA64ISAR6_EL1_RESERVED", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 6, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = 0 }, { .name = "ID_AA64ISAR7_EL1_RESERVED", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 7, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = 0 }, { .name = "ID_AA64MMFR0_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 0, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = GET_IDREG(isar, ID_AA64MMFR0)}, { .name = "ID_AA64MMFR1_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 1, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = GET_IDREG(isar, ID_AA64MMFR1) }, { .name = "ID_AA64MMFR2_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 2, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = GET_IDREG(isar, ID_AA64MMFR2) }, { .name = "ID_AA64MMFR3_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 3, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = GET_IDREG(isar, ID_AA64MMFR3) }, { .name = "ID_AA64MMFR4_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 4, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = GET_IDREG(isar, ID_AA64MMFR4) }, { .name = "ID_AA64MMFR5_EL1_RESERVED", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 5, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = 0 }, { .name = "ID_AA64MMFR6_EL1_RESERVED", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 6, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = 0 }, { .name = "ID_AA64MMFR7_EL1_RESERVED", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 7, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = 0 }, { .name = "MVFR0_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 0, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = cpu->isar.mvfr0 }, { .name = "MVFR1_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 1, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = cpu->isar.mvfr1 }, { .name = "MVFR2_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 2, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = cpu->isar.mvfr2 }, /* * "0, c0, c3, {0,1,2}" are the encodings corresponding to @@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu) { .name = "RES_0_C0_C3_0", .state = ARM_CP_STATE_AA32, .cp = 15, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 0, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = 0 }, { .name = "RES_0_C0_C3_1", .state = ARM_CP_STATE_AA32, .cp = 15, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 1, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = 0 }, { .name = "RES_0_C0_C3_2", .state = ARM_CP_STATE_AA32, .cp = 15, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 2, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = 0 }, /* * Other encodings in "0, c0, c3, ..." are STATE_BOTH because @@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu) { .name = "RES_0_C0_C3_3", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 3, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = 0 }, { .name = "ID_PFR2", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 4, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = GET_IDREG(isar, ID_PFR2)}, { .name = "ID_DFR1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 5, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = GET_IDREG(isar, ID_DFR1)}, { .name = "ID_MMFR5", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 6, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = GET_IDREG(isar, ID_MMFR5)}, { .name = "RES_0_C0_C3_7", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 7, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = 0 }, }; #ifdef CONFIG_USER_ONLY @@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu) .state = ARM_CP_STATE_AA32, .cp = 15, .opc1 = 0, .crn = 0, .crm = i, .opc2 = CP_ANY, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid3, + .accessfn = access_tid3, .resetvalue = 0 }; define_one_arm_cp_reg(cpu, &v8_aa32_raz_idregs); } -- 2.47.3
In v7A HCR.TID1 is defined to trap for TCMTR, TLBTR, REVIDR and AIDR. We incorrectly use an accessfn for REVIDR and AIDR that only traps on v8A cores. Fix this by collapsing access_aa64_tid1() and access_aa32_tid1() together and never doing a check for v8 vs v7. The accessfn is also used for SMIDR_EL1, which is fine as this register is AArch64 only. Cc: qemu-stable@nongnu.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20251231170858.254594-4-peter.maydell@linaro.org --- target/arm/helper.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -XXX,XX +XXX,XX @@ static uint64_t isr_read(CPUARMState *env, const ARMCPRegInfo *ri) return ret; } -static CPAccessResult access_aa64_tid1(CPUARMState *env, const ARMCPRegInfo *ri, - bool isread) +static CPAccessResult access_tid1(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) { if (arm_current_el(env) == 1 && (arm_hcr_el2_eff(env) & HCR_TID1)) { return CP_ACCESS_TRAP_EL2; @@ -XXX,XX +XXX,XX @@ static CPAccessResult access_aa64_tid1(CPUARMState *env, const ARMCPRegInfo *ri, return CP_ACCESS_OK; } -static CPAccessResult access_aa32_tid1(CPUARMState *env, const ARMCPRegInfo *ri, - bool isread) -{ - if (arm_feature(env, ARM_FEATURE_V8)) { - return access_aa64_tid1(env, ri, isread); - } - - return CP_ACCESS_OK; -} - static const ARMCPRegInfo v7_cp_reginfo[] = { /* the old v6 WFI, UNPREDICTABLE in v7 but we choose to NOP */ { .name = "NOP", .cp = 15, .crn = 7, .crm = 0, .opc1 = 0, .opc2 = 4, @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo v7_cp_reginfo[] = { { .name = "AIDR", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 1, .crn = 0, .crm = 0, .opc2 = 7, .access = PL1_R, .type = ARM_CP_CONST, - .accessfn = access_aa64_tid1, + .accessfn = access_tid1, .fgt = FGT_AIDR_EL1, .resetvalue = 0 }, /* @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo sme_reginfo[] = { .writefn = smcr_write, .raw_writefn = raw_write }, { .name = "SMIDR_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 1, .crn = 0, .crm = 0, .opc2 = 6, - .access = PL1_R, .accessfn = access_aa64_tid1, + .access = PL1_R, .accessfn = access_tid1, /* * IMPLEMENTOR = 0 (software) * REVISION = 0 (implementation defined) @@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu) { .name = "REVIDR_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 0, .opc2 = 6, .access = PL1_R, - .accessfn = access_aa64_tid1, + .accessfn = access_tid1, .fgt = FGT_REVIDR_EL1, .type = ARM_CP_CONST, .resetvalue = cpu->revidr }, }; @@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu) { .name = "TCMTR", .cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 2, .access = PL1_R, - .accessfn = access_aa32_tid1, + .accessfn = access_tid1, .type = ARM_CP_CONST, .resetvalue = 0 }, }; /* TLBTR is specific to VMSA */ @@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu) .name = "TLBTR", .cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 3, .access = PL1_R, - .accessfn = access_aa32_tid1, + .accessfn = access_tid1, .type = ARM_CP_CONST, .resetvalue = 0, }; /* MPUIR is specific to PMSA V6+ */ -- 2.47.3
There is no equivalent access_aa32_tid5() (HCR_EL2.TID5 only exists starting from v8); rename access_aa64_tid5() to access_tid5() to line up with the naming we now have for the TID1 and TID3 check functions. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20251231170858.254594-5-peter.maydell@linaro.org --- target/arm/helper.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo dcpodp_reg[] = { .accessfn = aa64_cacheop_poc_access, .writefn = dccvap_writefn }, }; -static CPAccessResult access_aa64_tid5(CPUARMState *env, const ARMCPRegInfo *ri, - bool isread) +static CPAccessResult access_tid5(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) { if ((arm_current_el(env) < 2) && (arm_hcr_el2_eff(env) & HCR_TID5)) { return CP_ACCESS_TRAP_EL2; @@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu) ARMCPRegInfo gmid_reginfo = { .name = "GMID_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 1, .crn = 0, .crm = 0, .opc2 = 4, - .access = PL1_R, .accessfn = access_aa64_tid5, + .access = PL1_R, .accessfn = access_tid5, .type = ARM_CP_CONST, .resetvalue = cpu->gm_blocksize, }; define_one_arm_cp_reg(cpu, &gmid_reginfo); -- 2.47.3
v3->v4: Windows headers define an INT type which clashed with an enum value name in arm_gicv3_its.c... The following changes since commit eae587e8e3694b1aceab23239493fb4c7e1a80f5: Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2021-09-13' into staging (2021-09-13 11:00:30 +0100) are available in the Git repository at: https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20210913-3 for you to fetch changes up to 28e987a7e7edaa3ca7feeac65edca26145df8814: hw/arm/mps2.c: Mark internal-only I2C buses as 'full' (2021-09-13 21:01:08 +0100) ---------------------------------------------------------------- target-arm queue: * mark MPS2/MPS3 board-internal i2c buses as 'full' so that command line user-created devices are not plugged into them * Take an exception if PSTATE.IL is set * Support an emulated ITS in the virt board * Add support for kudo-bmc board * Probe for KVM_CAP_ARM_VM_IPA_SIZE when creating scratch VM * cadence_uart: Fix clock handling issues that prevented u-boot from running ---------------------------------------------------------------- Bin Meng (6): hw/misc: zynq_slcr: Correctly compute output clocks in the reset exit phase hw/char: cadence_uart: Disable transmit when input clock is disabled hw/char: cadence_uart: Move clock/reset check to uart_can_receive() hw/char: cadence_uart: Convert to memop_with_attrs() ops hw/char: cadence_uart: Ignore access when unclocked or in reset for uart_{read, write}() hw/char: cadence_uart: Log a guest error when device is unclocked or in reset Chris Rauer (1): hw/arm: Add support for kudo-bmc board. Marc Zyngier (1): hw/arm/virt: KVM: Probe for KVM_CAP_ARM_VM_IPA_SIZE when creating scratch VM Peter Maydell (5): target/arm: Take an exception if PSTATE.IL is set qdev: Support marking individual buses as 'full' hw/arm/mps2-tz.c: Add extra data parameter to MakeDevFn hw/arm/mps2-tz.c: Mark internal-only I2C buses as 'full' hw/arm/mps2.c: Mark internal-only I2C buses as 'full' Richard Henderson (1): target/arm: Merge disas_a64_insn into aarch64_tr_translate_insn Shashi Mallela (9): hw/intc: GICv3 ITS initial framework hw/intc: GICv3 ITS register definitions added hw/intc: GICv3 ITS command queue framework hw/intc: GICv3 ITS Command processing hw/intc: GICv3 ITS Feature enablement hw/intc: GICv3 redistributor ITS processing tests/data/acpi/virt: Add IORT files for ITS hw/arm/virt: add ITS support in virt GIC tests/data/acpi/virt: Update IORT files for ITS docs/system/arm/nuvoton.rst | 1 + hw/intc/gicv3_internal.h | 188 ++++- include/hw/arm/virt.h | 2 + include/hw/intc/arm_gicv3_common.h | 13 + include/hw/intc/arm_gicv3_its_common.h | 32 +- include/hw/qdev-core.h | 24 + target/arm/cpu.h | 1 + target/arm/kvm_arm.h | 4 +- target/arm/syndrome.h | 5 + target/arm/translate.h | 2 + hw/arm/mps2-tz.c | 92 ++- hw/arm/mps2.c | 12 +- hw/arm/npcm7xx_boards.c | 34 + hw/arm/virt.c | 29 +- hw/char/cadence_uart.c | 61 +- hw/intc/arm_gicv3.c | 14 + hw/intc/arm_gicv3_common.c | 13 + hw/intc/arm_gicv3_cpuif.c | 7 +- hw/intc/arm_gicv3_dist.c | 5 +- hw/intc/arm_gicv3_its.c | 1322 ++++++++++++++++++++++++++++++++ hw/intc/arm_gicv3_its_common.c | 7 +- hw/intc/arm_gicv3_its_kvm.c | 2 +- hw/intc/arm_gicv3_redist.c | 153 +++- hw/misc/zynq_slcr.c | 31 +- softmmu/qdev-monitor.c | 7 +- target/arm/helper-a64.c | 1 + target/arm/helper.c | 8 + target/arm/kvm.c | 7 +- target/arm/translate-a64.c | 255 +++--- target/arm/translate.c | 21 + hw/intc/meson.build | 1 + tests/data/acpi/virt/IORT | Bin 0 -> 124 bytes tests/data/acpi/virt/IORT.memhp | Bin 0 -> 124 bytes tests/data/acpi/virt/IORT.numamem | Bin 0 -> 124 bytes tests/data/acpi/virt/IORT.pxb | Bin 0 -> 124 bytes 35 files changed, 2144 insertions(+), 210 deletions(-) create mode 100644 hw/intc/arm_gicv3_its.c create mode 100644 tests/data/acpi/virt/IORT create mode 100644 tests/data/acpi/virt/IORT.memhp create mode 100644 tests/data/acpi/virt/IORT.numamem create mode 100644 tests/data/acpi/virt/IORT.pxb