1
ARM pullreq; contains some patches that arrived while I
1
The following changes since commit 55ef0b702bc2c90c3c4ed97f97676d8f139e5ca1:
2
was on holiday, plus the series I sent off before going
3
away, which got reviewed while I was away.
4
2
5
thanks
3
Merge remote-tracking branch 'remotes/lvivier-gitlab/tags/linux-user-for-7.0-pull-request' into staging (2022-02-07 10:48:25 +0000)
6
-- PMM
7
4
5
are available in the Git repository at:
8
6
9
The following changes since commit c077a998eb3fcae2d048e3baeb5bc592d30fddde:
7
https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20220208
10
8
11
Merge remote-tracking branch 'remotes/riku/tags/pull-linux-user-20170531' into staging (2017-06-01 15:50:40 +0100)
9
for you to fetch changes up to 4fd1ebb10593087d45d2f56f7f3d13447d24802c:
12
10
13
are available in the git repository at:
11
hw/sensor: Add lsm303dlhc magnetometer device (2022-02-08 10:56:29 +0000)
14
15
git://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20170601
16
17
for you to fetch changes up to cdc58be430b0bdeaef282e2e70f8135ae531616d:
18
19
hw/arm/virt: fdt: generate distance-map when needed (2017-06-01 17:27:07 +0100)
20
12
21
----------------------------------------------------------------
13
----------------------------------------------------------------
22
target-arm queue:
14
target-arm queue:
23
* virt: numa: provide ACPI distance info when needed
15
* Fix handling of SVE ZCR_LEN when using VHE
24
* aspeed: fix i2c controller bugs
16
* xlnx-zynqmp: 'Or' the QSPI / QSPI DMA IRQs
25
* aspeed: add temperature sensor device
17
* Don't ever enable PSCI when booting guest in EL3
26
* M profile: support MPU
18
* Adhere to SMCCC 1.3 section 5.2
27
* gicv3: fix mishandling of BPR1, VBPR1
19
* highbank: Fix issues with booting SMP
28
* load_uboot_image: don't assume a full header read
20
* midway: Fix issues booting at all
29
* libvixl: Correct build failures on NetBSD
21
* boot: Drop existing dtb /psci node rather than retaining it
22
* versal-virt: Always call arm_load_kernel()
23
* force flag recalculation when messing with DAIF
24
* hw/timer/armv7m_systick: Update clock source before enabling timer
25
* hw/arm/smmuv3: Fix device reset
26
* hw/intc/arm_gicv3_its: refactorings and minor bug fixes
27
* hw/sensor: Add lsm303dlhc magnetometer device
30
28
31
----------------------------------------------------------------
29
----------------------------------------------------------------
32
Andrew Jones (3):
30
Alex Bennée (1):
33
load_uboot_image: don't assume a full header read
31
arm: force flag recalculation when messing with DAIF
34
hw/arm/virt-acpi-build: build SLIT when needed
35
hw/arm/virt: fdt: generate distance-map when needed
36
32
37
Cédric Le Goater (6):
33
Edgar E. Iglesias (1):
38
aspeed/i2c: improve command handling
34
hw/arm: versal-virt: Always call arm_load_kernel()
39
aspeed/i2c: handle LAST command under the RX command
40
aspeed/i2c: introduce a state machine
41
aspeed: add some I2C devices to the Aspeed machines
42
hw/misc: add a TMP42{1,2,3} device model
43
aspeed: add a temp sensor device on I2C bus 3
44
35
45
Kamil Rytarowski (1):
36
Eric Auger (1):
46
libvixl: Correct build failures on NetBSD
37
hw/arm/smmuv3: Fix device reset
47
38
48
Michael Davidsaver (4):
39
Francisco Iglesias (1):
49
armv7m: Improve "-d mmu" tracing for PMSAv7 MPU
40
hw/arm/xlnx-zynqmp: 'Or' the QSPI / QSPI DMA IRQs
50
armv7m: Implement M profile default memory map
51
armv7m: Classify faults as MemManage or BusFault
52
arm: add MPU support to M profile CPUs
53
41
54
Peter Maydell (12):
42
Kevin Townsend (1):
55
hw/intc/arm_gicv3_cpuif: Fix reset value for VMCR_EL2.VBPR1
43
hw/sensor: Add lsm303dlhc magnetometer device
56
hw/intc/arm_gicv3_cpuif: Don't let BPR be set below its minimum
57
hw/intc/arm_gicv3_cpuif: Fix priority masking for NS BPR1
58
arm: Use the mmu_idx we're passed in arm_cpu_do_unaligned_access()
59
arm: Add support for M profile CPUs having different MMU index semantics
60
arm: Use different ARMMMUIdx values for M profile
61
arm: Clean up handling of no-MPU PMSA CPUs
62
arm: Don't clear ARM_FEATURE_PMSA for no-mpu configs
63
arm: Don't let no-MPU PMSA cores write to SCTLR.M
64
arm: Remove unnecessary check on cpu->pmsav7_dregion
65
arm: All M profile cores are PMSA
66
arm: Implement HFNMIENA support for M profile MPU
67
44
68
Wei Huang (1):
45
Peter Maydell (29):
69
target/arm: clear PMUVER field of AA64DFR0 when vPMU=off
46
target/arm: make psci-conduit settable after realize
47
cpu.c: Make start-powered-off settable after realize
48
hw/arm/boot: Support setting psci-conduit based on guest EL
49
hw/arm: imx: Don't enable PSCI conduit when booting guest in EL3
50
hw/arm: allwinner: Don't enable PSCI conduit when booting guest in EL3
51
hw/arm/xlnx-zcu102: Don't enable PSCI conduit when booting guest in EL3
52
hw/arm/versal: Let boot.c handle PSCI enablement
53
hw/arm/virt: Let boot.c handle PSCI enablement
54
hw/arm: highbank: For EL3 guests, don't enable PSCI, start all cores
55
arm: tcg: Adhere to SMCCC 1.3 section 5.2
56
hw/arm/highbank: Drop use of secure_board_setup
57
hw/arm/boot: Prevent setting both psci_conduit and secure_board_setup
58
hw/arm/boot: Don't write secondary boot stub if using PSCI
59
hw/arm/highbank: Drop unused secondary boot stub code
60
hw/arm/boot: Drop nb_cpus field from arm_boot_info
61
hw/arm/boot: Drop existing dtb /psci node rather than retaining it
62
hw/intc/arm_gicv3_its: Use address_space_map() to access command queue packets
63
hw/intc/arm_gicv3_its: Keep DTEs as a struct, not a raw uint64_t
64
hw/intc/arm_gicv3_its: Pass DTEntry to update_dte()
65
hw/intc/arm_gicv3_its: Keep CTEs as a struct, not a raw uint64_t
66
hw/intc/arm_gicv3_its: Pass CTEntry to update_cte()
67
hw/intc/arm_gicv3_its: Fix address calculation in get_ite() and update_ite()
68
hw/intc/arm_gicv3_its: Avoid nested ifs in get_ite()
69
hw/intc/arm_gicv3_its: Pass ITE values back from get_ite() via a struct
70
hw/intc/arm_gicv3_its: Make update_ite() use ITEntry
71
hw/intc/arm_gicv3_its: Drop TableDesc and CmdQDesc valid fields
72
hw/intc/arm_gicv3_its: In MAPC with V=0, don't check rdbase field
73
hw/intc/arm_gicv3_its: Don't allow intid 1023 in MAPI/MAPTI
74
hw/intc/arm_gicv3_its: Split error checks
70
75
71
disas/libvixl/Makefile.objs | 3 +
76
Richard Henderson (4):
72
hw/misc/Makefile.objs | 1 +
77
target/arm: Fix sve_zcr_len_for_el for VHE mode running
73
target/arm/cpu.h | 118 ++++++++++--
78
target/arm: Tidy sve_exception_el for CPACR_EL1 access
74
target/arm/translate.h | 2 +-
79
target/arm: Fix {fp, sve}_exception_el for VHE mode running
75
hw/arm/aspeed.c | 36 ++++
80
target/arm: Use CPTR_TFP with CPTR_EL3 in fp_exception_el
76
hw/arm/virt-acpi-build.c | 4 +
77
hw/arm/virt.c | 21 +++
78
hw/core/loader.c | 3 +-
79
hw/i2c/aspeed_i2c.c | 65 ++++++-
80
hw/intc/arm_gicv3_cpuif.c | 50 ++++-
81
hw/intc/armv7m_nvic.c | 104 +++++++++++
82
hw/misc/tmp421.c | 401 ++++++++++++++++++++++++++++++++++++++++
83
target/arm/cpu.c | 28 ++-
84
target/arm/helper.c | 338 ++++++++++++++++++++++-----------
85
target/arm/machine.c | 7 +-
86
target/arm/op_helper.c | 3 +-
87
target/arm/translate-a64.c | 18 +-
88
target/arm/translate.c | 14 +-
89
default-configs/arm-softmmu.mak | 1 +
90
19 files changed, 1060 insertions(+), 157 deletions(-)
91
create mode 100644 hw/misc/tmp421.c
92
81
82
Richard Petri (1):
83
hw/timer/armv7m_systick: Update clock source before enabling timer
84
85
hw/intc/gicv3_internal.h | 23 +-
86
include/hw/arm/boot.h | 14 +-
87
include/hw/arm/xlnx-versal.h | 1 -
88
include/hw/arm/xlnx-zynqmp.h | 2 +
89
include/hw/intc/arm_gicv3_its_common.h | 2 -
90
cpu.c | 22 +-
91
hw/arm/allwinner-h3.c | 9 +-
92
hw/arm/aspeed.c | 1 -
93
hw/arm/boot.c | 107 ++++-
94
hw/arm/exynos4_boards.c | 1 -
95
hw/arm/fsl-imx6ul.c | 2 -
96
hw/arm/fsl-imx7.c | 8 +-
97
hw/arm/highbank.c | 72 +---
98
hw/arm/imx25_pdk.c | 3 +-
99
hw/arm/kzm.c | 1 -
100
hw/arm/mcimx6ul-evk.c | 2 +-
101
hw/arm/mcimx7d-sabre.c | 2 +-
102
hw/arm/npcm7xx.c | 3 -
103
hw/arm/orangepi.c | 5 +-
104
hw/arm/raspi.c | 1 -
105
hw/arm/realview.c | 1 -
106
hw/arm/sabrelite.c | 1 -
107
hw/arm/sbsa-ref.c | 1 -
108
hw/arm/smmuv3.c | 6 +
109
hw/arm/vexpress.c | 1 -
110
hw/arm/virt.c | 13 +-
111
hw/arm/xilinx_zynq.c | 1 -
112
hw/arm/xlnx-versal-virt.c | 17 +-
113
hw/arm/xlnx-versal.c | 5 +-
114
hw/arm/xlnx-zcu102.c | 1 +
115
hw/arm/xlnx-zynqmp.c | 25 +-
116
hw/intc/arm_gicv3_its.c | 696 +++++++++++++++------------------
117
hw/sensor/lsm303dlhc_mag.c | 556 ++++++++++++++++++++++++++
118
hw/timer/armv7m_systick.c | 8 +-
119
target/arm/cpu.c | 6 +-
120
target/arm/helper-a64.c | 2 +
121
target/arm/helper.c | 118 ++++--
122
target/arm/psci.c | 35 +-
123
tests/qtest/lsm303dlhc-mag-test.c | 148 +++++++
124
hw/sensor/Kconfig | 4 +
125
hw/sensor/meson.build | 1 +
126
tests/qtest/meson.build | 1 +
127
42 files changed, 1308 insertions(+), 620 deletions(-)
128
create mode 100644 hw/sensor/lsm303dlhc_mag.c
129
create mode 100644 tests/qtest/lsm303dlhc-mag-test.c
130
diff view generated by jsdifflib
1
From: Michael Davidsaver <mdavidsaver@gmail.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
Add support for the M profile default memory map which is used
3
When HCR_EL2.{E2H,TGE} == '11', ZCR_EL1 is unused.
4
if the MPU is not present or disabled.
5
4
6
The main differences in behaviour from implementing this
5
Reported-by: Zenghui Yu <yuzenghui@huawei.com>
7
correctly are that we set the PAGE_EXEC attribute on
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
the right regions of memory, such that device regions
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
are not executable.
8
Reviewed-by: Zenghui Yu <yuzenghui@huawei.com>
10
9
Message-id: 20220127063428.30212-2-richard.henderson@linaro.org
11
Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
12
Message-id: 1493122030-32191-10-git-send-email-peter.maydell@linaro.org
13
[PMM: rephrased comment and commit message; don't mark
14
the flash memory region as not-writable; list all
15
the cases in the default map explicitly rather than
16
using a 'default' case for the non-executable regions]
17
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
18
---
11
---
19
target/arm/helper.c | 41 ++++++++++++++++++++++++++++++++---------
12
target/arm/helper.c | 3 ++-
20
1 file changed, 32 insertions(+), 9 deletions(-)
13
1 file changed, 2 insertions(+), 1 deletion(-)
21
14
22
diff --git a/target/arm/helper.c b/target/arm/helper.c
15
diff --git a/target/arm/helper.c b/target/arm/helper.c
23
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
24
--- a/target/arm/helper.c
17
--- a/target/arm/helper.c
25
+++ b/target/arm/helper.c
18
+++ b/target/arm/helper.c
26
@@ -XXX,XX +XXX,XX @@ static inline void get_phys_addr_pmsav7_default(CPUARMState *env,
19
@@ -XXX,XX +XXX,XX @@ uint32_t sve_zcr_len_for_el(CPUARMState *env, int el)
27
ARMMMUIdx mmu_idx,
20
ARMCPU *cpu = env_archcpu(env);
28
int32_t address, int *prot)
21
uint32_t zcr_len = cpu->sve_max_vq - 1;
29
{
22
30
- *prot = PAGE_READ | PAGE_WRITE;
23
- if (el <= 1) {
31
- switch (address) {
24
+ if (el <= 1 &&
32
- case 0xF0000000 ... 0xFFFFFFFF:
25
+ (arm_hcr_el2_eff(env) & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE)) {
33
- if (regime_sctlr(env, mmu_idx) & SCTLR_V) { /* hivecs execing is ok */
26
zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[1]);
34
+ if (!arm_feature(env, ARM_FEATURE_M)) {
35
+ *prot = PAGE_READ | PAGE_WRITE;
36
+ switch (address) {
37
+ case 0xF0000000 ... 0xFFFFFFFF:
38
+ if (regime_sctlr(env, mmu_idx) & SCTLR_V) {
39
+ /* hivecs execing is ok */
40
+ *prot |= PAGE_EXEC;
41
+ }
42
+ break;
43
+ case 0x00000000 ... 0x7FFFFFFF:
44
*prot |= PAGE_EXEC;
45
+ break;
46
+ }
47
+ } else {
48
+ /* Default system address map for M profile cores.
49
+ * The architecture specifies which regions are execute-never;
50
+ * at the MPU level no other checks are defined.
51
+ */
52
+ switch (address) {
53
+ case 0x00000000 ... 0x1fffffff: /* ROM */
54
+ case 0x20000000 ... 0x3fffffff: /* SRAM */
55
+ case 0x60000000 ... 0x7fffffff: /* RAM */
56
+ case 0x80000000 ... 0x9fffffff: /* RAM */
57
+ *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
58
+ break;
59
+ case 0x40000000 ... 0x5fffffff: /* Peripheral */
60
+ case 0xa0000000 ... 0xbfffffff: /* Device */
61
+ case 0xc0000000 ... 0xdfffffff: /* Device */
62
+ case 0xe0000000 ... 0xffffffff: /* System */
63
+ *prot = PAGE_READ | PAGE_WRITE;
64
+ break;
65
+ default:
66
+ g_assert_not_reached();
67
}
68
- break;
69
- case 0x00000000 ... 0x7FFFFFFF:
70
- *prot |= PAGE_EXEC;
71
- break;
72
}
27
}
73
-
28
if (el <= 2 && arm_feature(env, ARM_FEATURE_EL2)) {
74
}
75
76
static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address,
77
--
29
--
78
2.7.4
30
2.25.1
79
31
80
32
diff view generated by jsdifflib
1
From: Michael Davidsaver <mdavidsaver@gmail.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
General logic is that operations stopped by the MPU are MemManage,
3
Extract entire fields for ZEN and FPEN, rather than testing specific bits.
4
and those which go through the MPU and are caught by the unassigned
4
This makes it easier to follow the code versus the ARM spec.
5
handle are BusFault. Distinguish these by looking at the
6
exception.fsr values, and set the CFSR bits and (if appropriate)
7
fill in the BFAR or MMFAR with the exception address.
8
5
9
Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
10
Message-id: 1493122030-32191-12-git-send-email-peter.maydell@linaro.org
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
11
[PMM: i-side faults do not set BFAR/MMFAR, only d-side;
8
Reviewed-by: Zenghui Yu <yuzenghui@huawei.com>
12
added some CPU_LOG_INT logging]
9
Message-id: 20220127063428.30212-3-richard.henderson@linaro.org
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
15
---
11
---
16
target/arm/helper.c | 45 ++++++++++++++++++++++++++++++++++++++++++---
12
target/arm/helper.c | 36 +++++++++++++++++-------------------
17
1 file changed, 42 insertions(+), 3 deletions(-)
13
1 file changed, 17 insertions(+), 19 deletions(-)
18
14
19
diff --git a/target/arm/helper.c b/target/arm/helper.c
15
diff --git a/target/arm/helper.c b/target/arm/helper.c
20
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
21
--- a/target/arm/helper.c
17
--- a/target/arm/helper.c
22
+++ b/target/arm/helper.c
18
+++ b/target/arm/helper.c
23
@@ -XXX,XX +XXX,XX @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
19
@@ -XXX,XX +XXX,XX @@ int sve_exception_el(CPUARMState *env, int el)
24
break;
20
uint64_t hcr_el2 = arm_hcr_el2_eff(env);
25
case EXCP_PREFETCH_ABORT:
21
26
case EXCP_DATA_ABORT:
22
if (el <= 1 && (hcr_el2 & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE)) {
27
- /* TODO: if we implemented the MPU registers, this is where we
23
- bool disabled = false;
28
- * should set the MMFAR, etc from exception.fsr and exception.vaddress.
24
-
29
+ /* Note that for M profile we don't have a guest facing FSR, but
25
- /* The CPACR.ZEN controls traps to EL1:
30
+ * the env->exception.fsr will be populated by the code that
26
- * 0, 2 : trap EL0 and EL1 accesses
31
+ * raises the fault, in the A profile short-descriptor format.
27
- * 1 : trap only EL0 accesses
32
*/
28
- * 3 : trap no accesses
33
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM);
29
- */
34
+ switch (env->exception.fsr & 0xf) {
30
- if (!extract32(env->cp15.cpacr_el1, 16, 1)) {
35
+ case 0x8: /* External Abort */
31
- disabled = true;
36
+ switch (cs->exception_index) {
32
- } else if (!extract32(env->cp15.cpacr_el1, 17, 1)) {
37
+ case EXCP_PREFETCH_ABORT:
33
- disabled = el == 0;
38
+ env->v7m.cfsr |= R_V7M_CFSR_PRECISERR_MASK;
34
- }
39
+ qemu_log_mask(CPU_LOG_INT, "...with CFSR.PRECISERR\n");
35
- if (disabled) {
40
+ break;
36
+ /* Check CPACR.ZEN. */
41
+ case EXCP_DATA_ABORT:
37
+ switch (extract32(env->cp15.cpacr_el1, 16, 2)) {
42
+ env->v7m.cfsr |=
38
+ case 1:
43
+ (R_V7M_CFSR_IBUSERR_MASK | R_V7M_CFSR_BFARVALID_MASK);
39
+ if (el != 0) {
44
+ env->v7m.bfar = env->exception.vaddress;
45
+ qemu_log_mask(CPU_LOG_INT,
46
+ "...with CFSR.IBUSERR and BFAR 0x%x\n",
47
+ env->v7m.bfar);
48
+ break;
40
+ break;
49
+ }
41
+ }
50
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_BUS);
42
+ /* fall through */
51
+ break;
43
+ case 0:
52
+ default:
44
+ case 2:
53
+ /* All other FSR values are either MPU faults or "can't happen
45
/* route_to_el2 */
54
+ * for M profile" cases.
46
return hcr_el2 & HCR_TGE ? 2 : 1;
55
+ */
47
}
56
+ switch (cs->exception_index) {
48
57
+ case EXCP_PREFETCH_ABORT:
49
/* Check CPACR.FPEN. */
58
+ env->v7m.cfsr |= R_V7M_CFSR_IACCVIOL_MASK;
50
- if (!extract32(env->cp15.cpacr_el1, 20, 1)) {
59
+ qemu_log_mask(CPU_LOG_INT, "...with CFSR.IACCVIOL\n");
51
- disabled = true;
60
+ break;
52
- } else if (!extract32(env->cp15.cpacr_el1, 21, 1)) {
61
+ case EXCP_DATA_ABORT:
53
- disabled = el == 0;
62
+ env->v7m.cfsr |=
54
- }
63
+ (R_V7M_CFSR_DACCVIOL_MASK | R_V7M_CFSR_MMARVALID_MASK);
55
- if (disabled) {
64
+ env->v7m.mmfar = env->exception.vaddress;
56
+ switch (extract32(env->cp15.cpacr_el1, 20, 2)) {
65
+ qemu_log_mask(CPU_LOG_INT,
57
+ case 1:
66
+ "...with CFSR.DACCVIOL and MMFAR 0x%x\n",
58
+ if (el != 0) {
67
+ env->v7m.mmfar);
68
+ break;
59
+ break;
69
+ }
60
+ }
70
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM);
61
+ /* fall through */
71
+ break;
62
+ case 0:
72
+ }
63
+ case 2:
73
break;
64
return 0;
74
case EXCP_BKPT:
65
}
75
if (semihosting_enabled()) {
66
}
76
--
67
--
77
2.7.4
68
2.25.1
78
69
79
70
diff view generated by jsdifflib
1
Implement HFNMIENA support for the M profile MPU. This bit controls
1
From: Richard Henderson <richard.henderson@linaro.org>
2
whether the MPU is treated as enabled when executing at execution
3
priorities of less than zero (in NMI, HardFault or with the FAULTMASK
4
bit set).
5
2
6
Doing this requires us to use a different MMU index for "running
3
When HCR_EL2.E2H is set, the format of CPTR_EL2 changes to
7
at execution priority < 0", because we will have different
4
look more like CPACR_EL1, with ZEN and FPEN fields instead
8
access permissions for that case versus the normal case.
5
of TZ and TFP fields.
9
6
7
Reported-by: Zenghui Yu <yuzenghui@huawei.com>
8
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Message-id: 20220127063428.30212-4-richard.henderson@linaro.org
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Message-id: 1493122030-32191-14-git-send-email-peter.maydell@linaro.org
12
---
12
---
13
target/arm/cpu.h | 24 +++++++++++++++++++++++-
13
target/arm/helper.c | 77 +++++++++++++++++++++++++++++++++++----------
14
target/arm/helper.c | 18 +++++++++++++++++-
14
1 file changed, 60 insertions(+), 17 deletions(-)
15
target/arm/translate.c | 1 +
16
3 files changed, 41 insertions(+), 2 deletions(-)
17
15
18
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
19
index XXXXXXX..XXXXXXX 100644
20
--- a/target/arm/cpu.h
21
+++ b/target/arm/cpu.h
22
@@ -XXX,XX +XXX,XX @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx,
23
* for the accesses done as part of a stage 1 page table walk, rather than
24
* having to walk the stage 2 page table over and over.)
25
*
26
+ * R profile CPUs have an MPU, but can use the same set of MMU indexes
27
+ * as A profile. They only need to distinguish NS EL0 and NS EL1 (and
28
+ * NS EL2 if we ever model a Cortex-R52).
29
+ *
30
+ * M profile CPUs are rather different as they do not have a true MMU.
31
+ * They have the following different MMU indexes:
32
+ * User
33
+ * Privileged
34
+ * Execution priority negative (this is like privileged, but the
35
+ * MPU HFNMIENA bit means that it may have different access permission
36
+ * check results to normal privileged code, so can't share a TLB).
37
+ *
38
* The ARMMMUIdx and the mmu index value used by the core QEMU TLB code
39
* are not quite the same -- different CPU types (most notably M profile
40
* vs A/R profile) would like to use MMU indexes with different semantics,
41
@@ -XXX,XX +XXX,XX @@ typedef enum ARMMMUIdx {
42
ARMMMUIdx_S2NS = 6 | ARM_MMU_IDX_A,
43
ARMMMUIdx_MUser = 0 | ARM_MMU_IDX_M,
44
ARMMMUIdx_MPriv = 1 | ARM_MMU_IDX_M,
45
+ ARMMMUIdx_MNegPri = 2 | ARM_MMU_IDX_M,
46
/* Indexes below here don't have TLBs and are used only for AT system
47
* instructions or for the first stage of an S12 page table walk.
48
*/
49
@@ -XXX,XX +XXX,XX @@ typedef enum ARMMMUIdxBit {
50
ARMMMUIdxBit_S2NS = 1 << 6,
51
ARMMMUIdxBit_MUser = 1 << 0,
52
ARMMMUIdxBit_MPriv = 1 << 1,
53
+ ARMMMUIdxBit_MNegPri = 1 << 2,
54
} ARMMMUIdxBit;
55
56
#define MMU_USER_IDX 0
57
@@ -XXX,XX +XXX,XX @@ static inline int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx)
58
case ARM_MMU_IDX_A:
59
return mmu_idx & 3;
60
case ARM_MMU_IDX_M:
61
- return mmu_idx & 1;
62
+ return mmu_idx == ARMMMUIdx_MUser ? 0 : 1;
63
default:
64
g_assert_not_reached();
65
}
66
@@ -XXX,XX +XXX,XX @@ static inline int cpu_mmu_index(CPUARMState *env, bool ifetch)
67
if (arm_feature(env, ARM_FEATURE_M)) {
68
ARMMMUIdx mmu_idx = el == 0 ? ARMMMUIdx_MUser : ARMMMUIdx_MPriv;
69
70
+ /* Execution priority is negative if FAULTMASK is set or
71
+ * we're in a HardFault or NMI handler.
72
+ */
73
+ if ((env->v7m.exception > 0 && env->v7m.exception <= 3)
74
+ || env->daif & PSTATE_F) {
75
+ return arm_to_core_mmu_idx(ARMMMUIdx_MNegPri);
76
+ }
77
+
78
return arm_to_core_mmu_idx(mmu_idx);
79
}
80
81
diff --git a/target/arm/helper.c b/target/arm/helper.c
16
diff --git a/target/arm/helper.c b/target/arm/helper.c
82
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
83
--- a/target/arm/helper.c
18
--- a/target/arm/helper.c
84
+++ b/target/arm/helper.c
19
+++ b/target/arm/helper.c
85
@@ -XXX,XX +XXX,XX @@ static inline uint32_t regime_el(CPUARMState *env, ARMMMUIdx mmu_idx)
20
@@ -XXX,XX +XXX,XX @@ int sve_exception_el(CPUARMState *env, int el)
86
case ARMMMUIdx_S1NSE0:
21
}
87
case ARMMMUIdx_S1NSE1:
22
}
88
case ARMMMUIdx_MPriv:
23
89
+ case ARMMMUIdx_MNegPri:
24
- /* CPTR_EL2. Since TZ and TFP are positive,
90
case ARMMMUIdx_MUser:
25
- * they will be zero when EL2 is not present.
91
return 1;
26
+ /*
92
default:
27
+ * CPTR_EL2 changes format with HCR_EL2.E2H (regardless of TGE).
93
@@ -XXX,XX +XXX,XX @@ static inline bool regime_is_secure(CPUARMState *env, ARMMMUIdx mmu_idx)
28
*/
94
case ARMMMUIdx_S1E2:
29
- if (el <= 2 && arm_is_el2_enabled(env)) {
95
case ARMMMUIdx_S2NS:
30
- if (env->cp15.cptr_el[2] & CPTR_TZ) {
96
case ARMMMUIdx_MPriv:
31
- return 2;
97
+ case ARMMMUIdx_MNegPri:
32
- }
98
case ARMMMUIdx_MUser:
33
- if (env->cp15.cptr_el[2] & CPTR_TFP) {
99
return false;
34
- return 0;
100
case ARMMMUIdx_S1E3:
35
+ if (el <= 2) {
101
@@ -XXX,XX +XXX,XX @@ static inline bool regime_translation_disabled(CPUARMState *env,
36
+ if (hcr_el2 & HCR_E2H) {
102
ARMMMUIdx mmu_idx)
37
+ /* Check CPTR_EL2.ZEN. */
38
+ switch (extract32(env->cp15.cptr_el[2], 16, 2)) {
39
+ case 1:
40
+ if (el != 0 || !(hcr_el2 & HCR_TGE)) {
41
+ break;
42
+ }
43
+ /* fall through */
44
+ case 0:
45
+ case 2:
46
+ return 2;
47
+ }
48
+
49
+ /* Check CPTR_EL2.FPEN. */
50
+ switch (extract32(env->cp15.cptr_el[2], 20, 2)) {
51
+ case 1:
52
+ if (el == 2 || !(hcr_el2 & HCR_TGE)) {
53
+ break;
54
+ }
55
+ /* fall through */
56
+ case 0:
57
+ case 2:
58
+ return 0;
59
+ }
60
+ } else if (arm_is_el2_enabled(env)) {
61
+ if (env->cp15.cptr_el[2] & CPTR_TZ) {
62
+ return 2;
63
+ }
64
+ if (env->cp15.cptr_el[2] & CPTR_TFP) {
65
+ return 0;
66
+ }
67
}
68
}
69
70
@@ -XXX,XX +XXX,XX @@ uint32_t HELPER(crc32c)(uint32_t acc, uint32_t val, uint32_t bytes)
71
int fp_exception_el(CPUARMState *env, int cur_el)
103
{
72
{
104
if (arm_feature(env, ARM_FEATURE_M)) {
73
#ifndef CONFIG_USER_ONLY
105
- return !(env->v7m.mpu_ctrl & R_V7M_MPU_CTRL_ENABLE_MASK);
74
+ uint64_t hcr_el2;
106
+ switch (env->v7m.mpu_ctrl &
75
+
107
+ (R_V7M_MPU_CTRL_ENABLE_MASK | R_V7M_MPU_CTRL_HFNMIENA_MASK)) {
76
/* CPACR and the CPTR registers don't exist before v6, so FP is
108
+ case R_V7M_MPU_CTRL_ENABLE_MASK:
77
* always accessible
109
+ /* Enabled, but not for HardFault and NMI */
78
*/
110
+ return mmu_idx == ARMMMUIdx_MNegPri;
79
@@ -XXX,XX +XXX,XX @@ int fp_exception_el(CPUARMState *env, int cur_el)
111
+ case R_V7M_MPU_CTRL_ENABLE_MASK | R_V7M_MPU_CTRL_HFNMIENA_MASK:
80
return 0;
112
+ /* Enabled for all cases */
81
}
113
+ return false;
82
114
+ case 0:
83
+ hcr_el2 = arm_hcr_el2_eff(env);
115
+ default:
84
+
116
+ /* HFNMIENA set and ENABLE clear is UNPREDICTABLE, but
85
/* The CPACR controls traps to EL1, or PL1 if we're 32 bit:
117
+ * we warned about that in armv7m_nvic.c when the guest set it.
86
* 0, 2 : trap EL0 and EL1/PL1 accesses
118
+ */
87
* 1 : trap only EL0 accesses
119
+ return true;
88
* 3 : trap no accesses
89
* This register is ignored if E2H+TGE are both set.
90
*/
91
- if ((arm_hcr_el2_eff(env) & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE)) {
92
+ if ((hcr_el2 & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE)) {
93
int fpen = extract32(env->cp15.cpacr_el1, 20, 2);
94
95
switch (fpen) {
96
@@ -XXX,XX +XXX,XX @@ int fp_exception_el(CPUARMState *env, int cur_el)
97
}
98
}
99
100
- /* For the CPTR registers we don't need to guard with an ARM_FEATURE
101
- * check because zero bits in the registers mean "don't trap".
102
+ /*
103
+ * CPTR_EL2 is present in v7VE or v8, and changes format
104
+ * with HCR_EL2.E2H (regardless of TGE).
105
*/
106
-
107
- /* CPTR_EL2 : present in v7VE or v8 */
108
- if (cur_el <= 2 && extract32(env->cp15.cptr_el[2], 10, 1)
109
- && arm_is_el2_enabled(env)) {
110
- /* Trap FP ops at EL2, NS-EL1 or NS-EL0 to EL2 */
111
- return 2;
112
+ if (cur_el <= 2) {
113
+ if (hcr_el2 & HCR_E2H) {
114
+ /* Check CPTR_EL2.FPEN. */
115
+ switch (extract32(env->cp15.cptr_el[2], 20, 2)) {
116
+ case 1:
117
+ if (cur_el != 0 || !(hcr_el2 & HCR_TGE)) {
118
+ break;
119
+ }
120
+ /* fall through */
121
+ case 0:
122
+ case 2:
123
+ return 2;
124
+ }
125
+ } else if (arm_is_el2_enabled(env)) {
126
+ if (env->cp15.cptr_el[2] & CPTR_TFP) {
127
+ return 2;
128
+ }
120
+ }
129
+ }
121
}
130
}
122
131
123
if (mmu_idx == ARMMMUIdx_S2NS) {
132
/* CPTR_EL3 : present in v8 */
124
diff --git a/target/arm/translate.c b/target/arm/translate.c
125
index XXXXXXX..XXXXXXX 100644
126
--- a/target/arm/translate.c
127
+++ b/target/arm/translate.c
128
@@ -XXX,XX +XXX,XX @@ static inline int get_a32_user_mem_index(DisasContext *s)
129
return arm_to_core_mmu_idx(ARMMMUIdx_S1SE0);
130
case ARMMMUIdx_MUser:
131
case ARMMMUIdx_MPriv:
132
+ case ARMMMUIdx_MNegPri:
133
return arm_to_core_mmu_idx(ARMMMUIdx_MUser);
134
case ARMMMUIdx_S2NS:
135
default:
136
--
133
--
137
2.7.4
134
2.25.1
138
135
139
136
diff view generated by jsdifflib
1
From: Michael Davidsaver <mdavidsaver@gmail.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
Improve the "-d mmu" tracing for the PMSAv7 MPU translation
3
Use the named bit rather than a bare extract32.
4
process as an aid in debugging guest MPU configurations:
5
* fix a missing newline for a guest-error log
6
* report the region number with guest-error or unimp
7
logs of bad region register values
8
* add a log message for the overall result of the lookup
9
* print "0x" prefix for hex values
10
4
11
Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
5
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
12
Reviewed-by: Alistair Francis <alistair.francis@xilinx.com>
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
13
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
7
Reviewed-by: Zenghui Yu <yuzenghui@huawei.com>
14
Message-id: 1493122030-32191-9-git-send-email-peter.maydell@linaro.org
8
Message-id: 20220127063428.30212-5-richard.henderson@linaro.org
15
[PMM: a little tidyup, report region number in all messages
16
rather than just one]
17
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
18
---
10
---
19
target/arm/helper.c | 39 +++++++++++++++++++++++++++------------
11
target/arm/helper.c | 2 +-
20
1 file changed, 27 insertions(+), 12 deletions(-)
12
1 file changed, 1 insertion(+), 1 deletion(-)
21
13
22
diff --git a/target/arm/helper.c b/target/arm/helper.c
14
diff --git a/target/arm/helper.c b/target/arm/helper.c
23
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
24
--- a/target/arm/helper.c
16
--- a/target/arm/helper.c
25
+++ b/target/arm/helper.c
17
+++ b/target/arm/helper.c
26
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address,
18
@@ -XXX,XX +XXX,XX @@ int fp_exception_el(CPUARMState *env, int cur_el)
27
}
28
29
if (!rsize) {
30
- qemu_log_mask(LOG_GUEST_ERROR, "DRSR.Rsize field can not be 0");
31
+ qemu_log_mask(LOG_GUEST_ERROR,
32
+ "DRSR[%d]: Rsize field cannot be 0\n", n);
33
continue;
34
}
35
rsize++;
36
rmask = (1ull << rsize) - 1;
37
38
if (base & rmask) {
39
- qemu_log_mask(LOG_GUEST_ERROR, "DRBAR %" PRIx32 " misaligned "
40
- "to DRSR region size, mask = %" PRIx32,
41
- base, rmask);
42
+ qemu_log_mask(LOG_GUEST_ERROR,
43
+ "DRBAR[%d]: 0x%" PRIx32 " misaligned "
44
+ "to DRSR region size, mask = 0x%" PRIx32 "\n",
45
+ n, base, rmask);
46
continue;
47
}
48
49
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address,
50
}
51
}
52
if (rsize < TARGET_PAGE_BITS) {
53
- qemu_log_mask(LOG_UNIMP, "No support for MPU (sub)region"
54
+ qemu_log_mask(LOG_UNIMP,
55
+ "DRSR[%d]: No support for MPU (sub)region "
56
"alignment of %" PRIu32 " bits. Minimum is %d\n",
57
- rsize, TARGET_PAGE_BITS);
58
+ n, rsize, TARGET_PAGE_BITS);
59
continue;
60
}
61
if (srdis) {
62
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address,
63
break;
64
default:
65
qemu_log_mask(LOG_GUEST_ERROR,
66
- "Bad value for AP bits in DRACR %"
67
- PRIx32 "\n", ap);
68
+ "DRACR[%d]: Bad value for AP bits: 0x%"
69
+ PRIx32 "\n", n, ap);
70
}
71
} else { /* Priv. mode AP bits decoding */
72
switch (ap) {
73
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address,
74
break;
75
default:
76
qemu_log_mask(LOG_GUEST_ERROR,
77
- "Bad value for AP bits in DRACR %"
78
- PRIx32 "\n", ap);
79
+ "DRACR[%d]: Bad value for AP bits: 0x%"
80
+ PRIx32 "\n", n, ap);
81
}
82
}
83
84
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr(CPUARMState *env, target_ulong address,
85
*/
86
if (arm_feature(env, ARM_FEATURE_PMSA) &&
87
arm_feature(env, ARM_FEATURE_V7)) {
88
+ bool ret;
89
*page_size = TARGET_PAGE_SIZE;
90
- return get_phys_addr_pmsav7(env, address, access_type, mmu_idx,
91
- phys_ptr, prot, fsr);
92
+ ret = get_phys_addr_pmsav7(env, address, access_type, mmu_idx,
93
+ phys_ptr, prot, fsr);
94
+ qemu_log_mask(CPU_LOG_MMU, "PMSAv7 MPU lookup for %s at 0x%08" PRIx32
95
+ " mmu_idx %u -> %s (prot %c%c%c)\n",
96
+ access_type == 1 ? "reading" :
97
+ (access_type == 2 ? "writing" : "execute"),
98
+ (uint32_t)address, mmu_idx,
99
+ ret ? "Miss" : "Hit",
100
+ *prot & PAGE_READ ? 'r' : '-',
101
+ *prot & PAGE_WRITE ? 'w' : '-',
102
+ *prot & PAGE_EXEC ? 'x' : '-');
103
+
104
+ return ret;
105
}
19
}
106
20
107
if (regime_translation_disabled(env, mmu_idx)) {
21
/* CPTR_EL3 : present in v8 */
22
- if (extract32(env->cp15.cptr_el[3], 10, 1)) {
23
+ if (env->cp15.cptr_el[3] & CPTR_TFP) {
24
/* Trap all FP ops to EL3 */
25
return 3;
26
}
108
--
27
--
109
2.7.4
28
2.25.1
110
29
111
30
diff view generated by jsdifflib
1
From: Cédric Le Goater <clg@kaod.org>
1
From: Francisco Iglesias <francisco.iglesias@xilinx.com>
2
2
3
Today, the LAST command is handled with the STOP command but this is
3
'Or' the IRQs coming from the QSPI and QSPI DMA models. This is done for
4
incorrect. Also nack the I2C bus when a LAST is issued.
4
avoiding the situation where one of the models incorrectly deasserts an
5
interrupt asserted from the other model (which will result in that the IRQ
6
is lost and will not reach guest SW).
5
7
6
Signed-off-by: Cédric Le Goater <clg@kaod.org>
8
Signed-off-by: Francisco Iglesias <francisco.iglesias@xilinx.com>
7
Message-id: 1494827476-1487-3-git-send-email-clg@kaod.org
9
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
10
Reviewed-by: Luc Michel <luc@lmichel.fr>
11
Message-id: 20220203151742.1457-1-francisco.iglesias@xilinx.com
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
13
---
10
hw/i2c/aspeed_i2c.c | 9 ++++++---
14
include/hw/arm/xlnx-zynqmp.h | 2 ++
11
1 file changed, 6 insertions(+), 3 deletions(-)
15
hw/arm/xlnx-zynqmp.c | 14 ++++++++++++--
16
2 files changed, 14 insertions(+), 2 deletions(-)
12
17
13
diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
18
diff --git a/include/hw/arm/xlnx-zynqmp.h b/include/hw/arm/xlnx-zynqmp.h
14
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
15
--- a/hw/i2c/aspeed_i2c.c
20
--- a/include/hw/arm/xlnx-zynqmp.h
16
+++ b/hw/i2c/aspeed_i2c.c
21
+++ b/include/hw/arm/xlnx-zynqmp.h
17
@@ -XXX,XX +XXX,XX @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value)
22
@@ -XXX,XX +XXX,XX @@
18
bus->cmd &= ~I2CD_M_TX_CMD;
23
#include "hw/dma/xlnx_csu_dma.h"
24
#include "hw/nvram/xlnx-bbram.h"
25
#include "hw/nvram/xlnx-zynqmp-efuse.h"
26
+#include "hw/or-irq.h"
27
28
#define TYPE_XLNX_ZYNQMP "xlnx-zynqmp"
29
OBJECT_DECLARE_SIMPLE_TYPE(XlnxZynqMPState, XLNX_ZYNQMP)
30
@@ -XXX,XX +XXX,XX @@ struct XlnxZynqMPState {
31
XlnxZDMA gdma[XLNX_ZYNQMP_NUM_GDMA_CH];
32
XlnxZDMA adma[XLNX_ZYNQMP_NUM_ADMA_CH];
33
XlnxCSUDMA qspi_dma;
34
+ qemu_or_irq qspi_irq_orgate;
35
36
char *boot_cpu;
37
ARMCPU *boot_cpu_ptr;
38
diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
39
index XXXXXXX..XXXXXXX 100644
40
--- a/hw/arm/xlnx-zynqmp.c
41
+++ b/hw/arm/xlnx-zynqmp.c
42
@@ -XXX,XX +XXX,XX @@
43
#define LQSPI_ADDR 0xc0000000
44
#define QSPI_IRQ 15
45
#define QSPI_DMA_ADDR 0xff0f0800
46
+#define NUM_QSPI_IRQ_LINES 2
47
48
#define DP_ADDR 0xfd4a0000
49
#define DP_IRQ 113
50
@@ -XXX,XX +XXX,XX @@ static void xlnx_zynqmp_init(Object *obj)
19
}
51
}
20
52
21
- if (bus->cmd & I2CD_M_RX_CMD) {
53
object_initialize_child(obj, "qspi-dma", &s->qspi_dma, TYPE_XLNX_CSU_DMA);
22
+ if (bus->cmd & (I2CD_M_RX_CMD | I2CD_M_S_RX_CMD_LAST)) {
54
+ object_initialize_child(obj, "qspi-irq-orgate",
23
int ret = i2c_recv(bus->bus);
55
+ &s->qspi_irq_orgate, TYPE_OR_IRQ);
24
if (ret < 0) {
56
}
25
qemu_log_mask(LOG_GUEST_ERROR, "%s: read failed\n", __func__);
57
26
@@ -XXX,XX +XXX,XX @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value)
58
static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
27
bus->intr_status |= I2CD_INTR_RX_DONE;
59
@@ -XXX,XX +XXX,XX @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
28
}
60
gic_spi[adma_ch_intr[i]]);
29
bus->buf = (ret & I2CD_BYTE_BUF_RX_MASK) << I2CD_BYTE_BUF_RX_SHIFT;
30
- bus->cmd &= ~I2CD_M_RX_CMD;
31
+ if (bus->cmd & I2CD_M_S_RX_CMD_LAST) {
32
+ i2c_nack(bus->bus);
33
+ }
34
+ bus->cmd &= ~(I2CD_M_RX_CMD | I2CD_M_S_RX_CMD_LAST);
35
}
61
}
36
62
37
- if (bus->cmd & (I2CD_M_STOP_CMD | I2CD_M_S_RX_CMD_LAST)) {
63
+ object_property_set_int(OBJECT(&s->qspi_irq_orgate),
38
+ if (bus->cmd & I2CD_M_STOP_CMD) {
64
+ "num-lines", NUM_QSPI_IRQ_LINES, &error_fatal);
39
if (!i2c_bus_busy(bus->bus)) {
65
+ qdev_realize(DEVICE(&s->qspi_irq_orgate), NULL, &error_fatal);
40
bus->intr_status |= I2CD_INTR_ABNORMAL;
66
+ qdev_connect_gpio_out(DEVICE(&s->qspi_irq_orgate), 0, gic_spi[QSPI_IRQ]);
41
} else {
67
+
68
if (!object_property_set_link(OBJECT(&s->qspi_dma), "dma",
69
OBJECT(system_memory), errp)) {
70
return;
71
@@ -XXX,XX +XXX,XX @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
72
}
73
74
sysbus_mmio_map(SYS_BUS_DEVICE(&s->qspi_dma), 0, QSPI_DMA_ADDR);
75
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->qspi_dma), 0, gic_spi[QSPI_IRQ]);
76
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->qspi_dma), 0,
77
+ qdev_get_gpio_in(DEVICE(&s->qspi_irq_orgate), 0));
78
79
if (!object_property_set_link(OBJECT(&s->qspi), "stream-connected-dma",
80
OBJECT(&s->qspi_dma), errp)) {
81
@@ -XXX,XX +XXX,XX @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
82
}
83
sysbus_mmio_map(SYS_BUS_DEVICE(&s->qspi), 0, QSPI_ADDR);
84
sysbus_mmio_map(SYS_BUS_DEVICE(&s->qspi), 1, LQSPI_ADDR);
85
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->qspi), 0, gic_spi[QSPI_IRQ]);
86
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->qspi), 0,
87
+ qdev_get_gpio_in(DEVICE(&s->qspi_irq_orgate), 1));
88
89
for (i = 0; i < XLNX_ZYNQMP_NUM_QSPI_BUS; i++) {
90
g_autofree gchar *bus_name = g_strdup_printf("qspi%d", i);
42
--
91
--
43
2.7.4
92
2.25.1
44
93
45
94
diff view generated by jsdifflib
1
All M profile CPUs are PMSA, so set the feature bit.
1
We want to allow the psci-conduit property to be set after realize,
2
(We haven't actually implemented the M profile MPU register
2
because the parts of the code which are best placed to decide if it's
3
interface yet, but setting this feature bit gives us closer
3
OK to enable QEMU's builtin PSCI emulation (the board code and the
4
to correct behaviour for the MPU-disabled case.)
4
arm_load_kernel() function are distant from the code which creates
5
and realizes CPUs (typically inside an SoC object's init and realize
6
method) and run afterwards.
7
8
Since the DEFINE_PROP_* macros don't have support for creating
9
properties which can be changed after realize, change the property to
10
be created with object_property_add_uint32_ptr(), which is what we
11
already use in this function for creating settable-after-realize
12
properties like init-svtor and init-nsvtor.
13
14
Note that it doesn't conceptually make sense to change the setting of
15
the property after the machine has been completely initialized,
16
beacuse this would mean that the behaviour of the machine when first
17
started would differ from its behaviour when the system is
18
subsequently reset. (It would also require the underlying state to
19
be migrated, which we don't do.)
5
20
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
21
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
22
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 1493122030-32191-11-git-send-email-peter.maydell@linaro.org
23
Tested-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
24
Tested-by: Cédric Le Goater <clg@kaod.org>
25
Message-id: 20220127154639.2090164-2-peter.maydell@linaro.org
9
---
26
---
10
target/arm/cpu.c | 8 ++++++++
27
target/arm/cpu.c | 6 +++++-
11
1 file changed, 8 insertions(+)
28
1 file changed, 5 insertions(+), 1 deletion(-)
12
29
13
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
30
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
14
index XXXXXXX..XXXXXXX 100644
31
index XXXXXXX..XXXXXXX 100644
15
--- a/target/arm/cpu.c
32
--- a/target/arm/cpu.c
16
+++ b/target/arm/cpu.c
33
+++ b/target/arm/cpu.c
17
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_post_init(Object *obj)
34
@@ -XXX,XX +XXX,XX @@ void arm_cpu_post_init(Object *obj)
18
{
35
OBJ_PROP_FLAG_READWRITE);
19
ARMCPU *cpu = ARM_CPU(obj);
36
}
20
37
21
+ /* M profile implies PMSA. We have to do this here rather than
38
+ /* Not DEFINE_PROP_UINT32: we want this to be settable after realize */
22
+ * in realize with the other feature-implication checks because
39
+ object_property_add_uint32_ptr(obj, "psci-conduit",
23
+ * we look at the PMSA bit to see if we should add some properties.
40
+ &cpu->psci_conduit,
24
+ */
41
+ OBJ_PROP_FLAG_READWRITE);
25
+ if (arm_feature(&cpu->env, ARM_FEATURE_M)) {
26
+ set_feature(&cpu->env, ARM_FEATURE_PMSA);
27
+ }
28
+
42
+
29
if (arm_feature(&cpu->env, ARM_FEATURE_CBAR) ||
43
qdev_property_add_static(DEVICE(obj), &arm_cpu_cfgend_property);
30
arm_feature(&cpu->env, ARM_FEATURE_CBAR_RO)) {
44
31
qdev_property_add_static(DEVICE(obj), &arm_cpu_reset_cbar_property,
45
if (arm_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER)) {
46
@@ -XXX,XX +XXX,XX @@ static ObjectClass *arm_cpu_class_by_name(const char *cpu_model)
47
}
48
49
static Property arm_cpu_properties[] = {
50
- DEFINE_PROP_UINT32("psci-conduit", ARMCPU, psci_conduit, 0),
51
DEFINE_PROP_UINT64("midr", ARMCPU, midr, 0),
52
DEFINE_PROP_UINT64("mp-affinity", ARMCPU,
53
mp_affinity, ARM64_AFFINITY_INVALID),
32
--
54
--
33
2.7.4
55
2.25.1
34
56
35
57
diff view generated by jsdifflib
1
From: Cédric Le Goater <clg@kaod.org>
1
The CPU object's start-powered-off property is currently only
2
settable before the CPU object is realized. For arm machines this is
3
awkward, because we would like to decide whether the CPU should be
4
powered-off based on how we are booting the guest code, which is
5
something done in the machine model code and in common code called by
6
the machine model, which runs much later and in completely different
7
parts of the codebase from the SoC object code that is responsible
8
for creating and realizing the CPU objects.
2
9
3
Let's add an RTC to the palmetto BMC and a LM75 temperature sensor to
10
Allow start-powered-off to be set after realize. Since this isn't
4
the AST2500 EVB to start with.
11
something that's supported by the DEFINE_PROP_* macros, we have to
12
switch the property definition to use the
13
object_class_property_add_bool() function.
5
14
6
Signed-off-by: Cédric Le Goater <clg@kaod.org>
15
Note that it doesn't conceptually make sense to change the setting of
7
Message-id: 1494827476-1487-5-git-send-email-clg@kaod.org
16
the property after the machine has been completely initialized,
17
beacuse this would mean that the behaviour of the machine when first
18
started would differ from its behaviour when the system is
19
subsequently reset. (It would also require the underlying state to
20
be migrated, which we don't do.)
21
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
22
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
23
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
24
Tested-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
25
Tested-by: Cédric Le Goater <clg@kaod.org>
26
Message-id: 20220127154639.2090164-3-peter.maydell@linaro.org
10
---
27
---
11
hw/arm/aspeed.c | 27 +++++++++++++++++++++++++++
28
cpu.c | 22 +++++++++++++++++++++-
12
1 file changed, 27 insertions(+)
29
1 file changed, 21 insertions(+), 1 deletion(-)
13
30
14
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
31
diff --git a/cpu.c b/cpu.c
15
index XXXXXXX..XXXXXXX 100644
32
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/arm/aspeed.c
33
--- a/cpu.c
17
+++ b/hw/arm/aspeed.c
34
+++ b/cpu.c
18
@@ -XXX,XX +XXX,XX @@ typedef struct AspeedBoardConfig {
35
@@ -XXX,XX +XXX,XX @@ static Property cpu_common_props[] = {
19
const char *fmc_model;
36
DEFINE_PROP_LINK("memory", CPUState, memory, TYPE_MEMORY_REGION,
20
const char *spi_model;
37
MemoryRegion *),
21
uint32_t num_cs;
38
#endif
22
+ void (*i2c_init)(AspeedBoardState *bmc);
39
- DEFINE_PROP_BOOL("start-powered-off", CPUState, start_powered_off, false),
23
} AspeedBoardConfig;
40
DEFINE_PROP_END_OF_LIST(),
24
41
};
25
enum {
42
26
@@ -XXX,XX +XXX,XX @@ enum {
43
+static bool cpu_get_start_powered_off(Object *obj, Error **errp)
27
SCU_AST2500_HW_STRAP_ACPI_ENABLE | \
28
SCU_HW_STRAP_SPI_MODE(SCU_HW_STRAP_SPI_MASTER))
29
30
+static void palmetto_bmc_i2c_init(AspeedBoardState *bmc);
31
+static void ast2500_evb_i2c_init(AspeedBoardState *bmc);
32
+
33
static const AspeedBoardConfig aspeed_boards[] = {
34
[PALMETTO_BMC] = {
35
.soc_name = "ast2400-a1",
36
@@ -XXX,XX +XXX,XX @@ static const AspeedBoardConfig aspeed_boards[] = {
37
.fmc_model = "n25q256a",
38
.spi_model = "mx25l25635e",
39
.num_cs = 1,
40
+ .i2c_init = palmetto_bmc_i2c_init,
41
},
42
[AST2500_EVB] = {
43
.soc_name = "ast2500-a1",
44
@@ -XXX,XX +XXX,XX @@ static const AspeedBoardConfig aspeed_boards[] = {
45
.fmc_model = "n25q256a",
46
.spi_model = "mx25l25635e",
47
.num_cs = 1,
48
+ .i2c_init = ast2500_evb_i2c_init,
49
},
50
[ROMULUS_BMC] = {
51
.soc_name = "ast2500-a1",
52
@@ -XXX,XX +XXX,XX @@ static void aspeed_board_init(MachineState *machine,
53
aspeed_board_binfo.ram_size = ram_size;
54
aspeed_board_binfo.loader_start = sc->info->sdram_base;
55
56
+ if (cfg->i2c_init) {
57
+ cfg->i2c_init(bmc);
58
+ }
59
+
60
arm_load_kernel(ARM_CPU(first_cpu), &aspeed_board_binfo);
61
}
62
63
+static void palmetto_bmc_i2c_init(AspeedBoardState *bmc)
64
+{
44
+{
65
+ AspeedSoCState *soc = &bmc->soc;
45
+ CPUState *cpu = CPU(obj);
66
+
46
+ return cpu->start_powered_off;
67
+ /* The palmetto platform expects a ds3231 RTC but a ds1338 is
68
+ * enough to provide basic RTC features. Alarms will be missing */
69
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 0), "ds1338", 0x68);
70
+}
47
+}
71
+
48
+
72
static void palmetto_bmc_init(MachineState *machine)
49
+static void cpu_set_start_powered_off(Object *obj, bool value, Error **errp)
73
{
74
aspeed_board_init(machine, &aspeed_boards[PALMETTO_BMC]);
75
@@ -XXX,XX +XXX,XX @@ static const TypeInfo palmetto_bmc_type = {
76
.class_init = palmetto_bmc_class_init,
77
};
78
79
+static void ast2500_evb_i2c_init(AspeedBoardState *bmc)
80
+{
50
+{
81
+ AspeedSoCState *soc = &bmc->soc;
51
+ CPUState *cpu = CPU(obj);
82
+
52
+ cpu->start_powered_off = value;
83
+ /* The AST2500 EVB expects a LM75 but a TMP105 is compatible */
84
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 7), "tmp105", 0x4d);
85
+}
53
+}
86
+
54
+
87
static void ast2500_evb_init(MachineState *machine)
55
void cpu_class_init_props(DeviceClass *dc)
88
{
56
{
89
aspeed_board_init(machine, &aspeed_boards[AST2500_EVB]);
57
+ ObjectClass *oc = OBJECT_CLASS(dc);
58
+
59
device_class_set_props(dc, cpu_common_props);
60
+ /*
61
+ * We can't use DEFINE_PROP_BOOL in the Property array for this
62
+ * property, because we want this to be settable after realize.
63
+ */
64
+ object_class_property_add_bool(oc, "start-powered-off",
65
+ cpu_get_start_powered_off,
66
+ cpu_set_start_powered_off);
67
}
68
69
void cpu_exec_initfn(CPUState *cpu)
90
--
70
--
91
2.7.4
71
2.25.1
92
72
93
73
diff view generated by jsdifflib
1
If the CPU is a PMSA config with no MPU implemented, then the
1
Currently we expect board code to set the psci-conduit property on
2
SCTLR.M bit should be RAZ/WI, so that the guest can never
2
CPUs and ensure that secondary CPUs are created with the
3
turn on the non-existent MPU.
3
start-powered-off property set to false, if the board wishes to use
4
QEMU's builtin PSCI emulation. This worked OK for the virt board
5
where we first wanted to use it, because the virt board directly
6
creates its CPUs and is in a reasonable position to set those
7
properties. For other boards which model real hardware and use a
8
separate SoC object, however, it is more awkward. Most PSCI-using
9
boards just set the psci-conduit board unconditionally.
10
11
This was never strictly speaking correct (because you would not be
12
able to run EL3 guest firmware that itself provided the PSCI
13
interface, as the QEMU implementation would overrule it), but mostly
14
worked in practice because for non-PSCI SMC calls QEMU would emulate
15
the SMC instruction as normal (by trapping to guest EL3). However,
16
we would like to make our PSCI emulation follow the part of the SMCC
17
specification that mandates that SMC calls with unknown function
18
identifiers return a failure code, which means that all SMC calls
19
will be handled by the PSCI code and the "emulate as normal" path
20
will no longer be taken.
21
22
We tried to implement that in commit 9fcd15b9193e81
23
("arm: tcg: Adhere to SMCCC 1.3 section 5.2"), but this
24
regressed attempts to run EL3 guest code on the affected boards:
25
* mcimx6ul-evk, mcimx7d-sabre, orangepi, xlnx-zcu102
26
* for the case only of EL3 code loaded via -kernel (and
27
not via -bios or -pflash), virt and xlnx-versal-virt
28
so for the 7.0 release we reverted it (in commit 4825eaae4fdd56f).
29
30
This commit provides a mechanism that boards can use to arrange that
31
psci-conduit is set if running guest code at a low enough EL but not
32
if it would be running at the same EL that the conduit implies that
33
the QEMU PSCI implementation is using. (Later commits will convert
34
individual board models to use this mechanism.)
35
36
We do this by moving the setting of the psci-conduit and
37
start-powered-off properties to arm_load_kernel(). Boards which want
38
to potentially use emulated PSCI must set a psci_conduit field in the
39
arm_boot_info struct to the type of conduit they want to use (SMC or
40
HVC); arm_load_kernel() will then set the CPUs up accordingly if it
41
is not going to start the guest code at the same or higher EL as the
42
fake QEMU firmware would be at.
43
44
Board/SoC code which uses this mechanism should no longer set the CPU
45
psci-conduit property directly. It should only set the
46
start-powered-off property for secondaries if EL3 guest firmware
47
running bare metal expects that rather than the alternative "all CPUs
48
start executing the firmware at once".
49
50
Note that when calculating whether we are going to run guest
51
code at EL3, we ignore the setting of arm_boot_info::secure_board_setup,
52
which might cause us to run a stub bit of guest code at EL3 which
53
does some board-specific setup before dropping to EL2 or EL1 to
54
run the guest kernel. This is OK because only one board that
55
enables PSCI sets secure_board_setup (the highbank board), and
56
the stub code it writes will behave the same way whether the
57
one SMC call it makes is handled by "emulate the SMC" or by
58
"PSCI default returns an error code". So we can leave that stub
59
code in place until after we've changed the PSCI default behaviour;
60
at that point we will remove it.
4
61
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
62
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Alistair Francis <alistair.francis@xilinx.com>
63
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
64
Tested-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
8
Message-id: 1493122030-32191-7-git-send-email-peter.maydell@linaro.org
65
Tested-by: Cédric Le Goater <clg@kaod.org>
66
Message-id: 20220127154639.2090164-4-peter.maydell@linaro.org
9
---
67
---
10
target/arm/helper.c | 5 +++++
68
include/hw/arm/boot.h | 10 +++++++++
11
1 file changed, 5 insertions(+)
69
hw/arm/boot.c | 50 +++++++++++++++++++++++++++++++++++++++++++
70
2 files changed, 60 insertions(+)
12
71
13
diff --git a/target/arm/helper.c b/target/arm/helper.c
72
diff --git a/include/hw/arm/boot.h b/include/hw/arm/boot.h
14
index XXXXXXX..XXXXXXX 100644
73
index XXXXXXX..XXXXXXX 100644
15
--- a/target/arm/helper.c
74
--- a/include/hw/arm/boot.h
16
+++ b/target/arm/helper.c
75
+++ b/include/hw/arm/boot.h
17
@@ -XXX,XX +XXX,XX @@ static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri,
76
@@ -XXX,XX +XXX,XX @@ struct arm_boot_info {
18
return;
77
* the user it should implement this hook.
78
*/
79
void (*modify_dtb)(const struct arm_boot_info *info, void *fdt);
80
+ /*
81
+ * If a board wants to use the QEMU emulated-firmware PSCI support,
82
+ * it should set this to QEMU_PSCI_CONDUIT_HVC or QEMU_PSCI_CONDUIT_SMC
83
+ * as appropriate. arm_load_kernel() will set the psci-conduit and
84
+ * start-powered-off properties on the CPUs accordingly.
85
+ * Note that if the guest image is started at the same exception level
86
+ * as the conduit specifies calls should go to (eg guest firmware booted
87
+ * to EL3) then PSCI will not be enabled.
88
+ */
89
+ int psci_conduit;
90
/* Used internally by arm_boot.c */
91
int is_linux;
92
hwaddr initrd_start;
93
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
94
index XXXXXXX..XXXXXXX 100644
95
--- a/hw/arm/boot.c
96
+++ b/hw/arm/boot.c
97
@@ -XXX,XX +XXX,XX @@ void arm_load_kernel(ARMCPU *cpu, MachineState *ms, struct arm_boot_info *info)
98
{
99
CPUState *cs;
100
AddressSpace *as = arm_boot_address_space(cpu, info);
101
+ int boot_el;
102
+ CPUARMState *env = &cpu->env;
103
104
/*
105
* CPU objects (unlike devices) are not automatically reset on system
106
@@ -XXX,XX +XXX,XX @@ void arm_load_kernel(ARMCPU *cpu, MachineState *ms, struct arm_boot_info *info)
107
arm_setup_direct_kernel_boot(cpu, info);
19
}
108
}
20
109
21
+ if (arm_feature(env, ARM_FEATURE_PMSA) && !cpu->has_mpu) {
110
+ /*
22
+ /* M bit is RAZ/WI for PMSA with no MPU implemented */
111
+ * Disable the PSCI conduit if it is set up to target the same
23
+ value &= ~SCTLR_M;
112
+ * or a lower EL than the one we're going to start the guest code in.
113
+ * This logic needs to agree with the code in do_cpu_reset() which
114
+ * decides whether we're going to boot the guest in the highest
115
+ * supported exception level or in a lower one.
116
+ */
117
+
118
+ /* Boot into highest supported EL ... */
119
+ if (arm_feature(env, ARM_FEATURE_EL3)) {
120
+ boot_el = 3;
121
+ } else if (arm_feature(env, ARM_FEATURE_EL2)) {
122
+ boot_el = 2;
123
+ } else {
124
+ boot_el = 1;
125
+ }
126
+ /* ...except that if we're booting Linux we adjust the EL we boot into */
127
+ if (info->is_linux && !info->secure_boot) {
128
+ boot_el = arm_feature(env, ARM_FEATURE_EL2) ? 2 : 1;
24
+ }
129
+ }
25
+
130
+
26
raw_write(env, ri, value);
131
+ if ((info->psci_conduit == QEMU_PSCI_CONDUIT_HVC && boot_el >= 2) ||
27
/* ??? Lots of these bits are not implemented. */
132
+ (info->psci_conduit == QEMU_PSCI_CONDUIT_SMC && boot_el == 3)) {
28
/* This may enable/disable the MMU, so do a TLB flush. */
133
+ info->psci_conduit = QEMU_PSCI_CONDUIT_DISABLED;
134
+ }
135
+
136
+ if (info->psci_conduit != QEMU_PSCI_CONDUIT_DISABLED) {
137
+ for (cs = first_cpu; cs; cs = CPU_NEXT(cs)) {
138
+ Object *cpuobj = OBJECT(cs);
139
+
140
+ object_property_set_int(cpuobj, "psci-conduit", info->psci_conduit,
141
+ &error_abort);
142
+ /*
143
+ * Secondary CPUs start in PSCI powered-down state. Like the
144
+ * code in do_cpu_reset(), we assume first_cpu is the primary
145
+ * CPU.
146
+ */
147
+ if (cs != first_cpu) {
148
+ object_property_set_bool(cpuobj, "start-powered-off", true,
149
+ &error_abort);
150
+ }
151
+ }
152
+ }
153
+
154
+ /*
155
+ * arm_load_dtb() may add a PSCI node so it must be called after we have
156
+ * decided whether to enable PSCI and set the psci-conduit CPU properties.
157
+ */
158
if (!info->skip_dtb_autoload && have_dtb(info)) {
159
if (arm_load_dtb(info->dtb_start, info, info->dtb_limit, as, ms) < 0) {
160
exit(1);
29
--
161
--
30
2.7.4
162
2.25.1
31
163
32
164
diff view generated by jsdifflib
New patch
1
Change the iMX-SoC based boards to use the new boot.c functionality
2
to allow us to enable psci-conduit only if the guest is being booted
3
in EL1 or EL2, so that if the user runs guest EL3 firmware code our
4
PSCI emulation doesn't get in its way.
1
5
6
To do this we stop setting the psci-conduit property on the CPU
7
objects in the SoC code, and instead set the psci_conduit field in
8
the arm_boot_info struct to tell the common boot loader code that
9
we'd like PSCI if the guest is starting at an EL that it makes
10
sense with.
11
12
This affects the mcimx6ul-evk and mcimx7d-sabre boards.
13
14
Note that for the mcimx7d board, this means that when running guest
15
code at EL3 there is currently no way to power on the secondary CPUs,
16
because we do not currently have a model of the system reset
17
controller module which should be used to do that for the imx7 SoC,
18
only for the imx6 SoC. (Previously EL3 code which knew it was
19
running on QEMU could use a PSCI call to do this.) This doesn't
20
affect the imx6ul-evk board because it is uniprocessor.
21
22
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
23
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
24
Tested-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
25
Tested-by: Cédric Le Goater <clg@kaod.org>
26
Acked-by: Richard Henderson <richard.henderson@linaro.org>
27
Message-id: 20220127154639.2090164-5-peter.maydell@linaro.org
28
---
29
hw/arm/fsl-imx6ul.c | 2 --
30
hw/arm/fsl-imx7.c | 8 ++++----
31
hw/arm/mcimx6ul-evk.c | 1 +
32
hw/arm/mcimx7d-sabre.c | 1 +
33
4 files changed, 6 insertions(+), 6 deletions(-)
34
35
diff --git a/hw/arm/fsl-imx6ul.c b/hw/arm/fsl-imx6ul.c
36
index XXXXXXX..XXXXXXX 100644
37
--- a/hw/arm/fsl-imx6ul.c
38
+++ b/hw/arm/fsl-imx6ul.c
39
@@ -XXX,XX +XXX,XX @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp)
40
return;
41
}
42
43
- object_property_set_int(OBJECT(&s->cpu), "psci-conduit",
44
- QEMU_PSCI_CONDUIT_SMC, &error_abort);
45
qdev_realize(DEVICE(&s->cpu), NULL, &error_abort);
46
47
/*
48
diff --git a/hw/arm/fsl-imx7.c b/hw/arm/fsl-imx7.c
49
index XXXXXXX..XXXXXXX 100644
50
--- a/hw/arm/fsl-imx7.c
51
+++ b/hw/arm/fsl-imx7.c
52
@@ -XXX,XX +XXX,XX @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)
53
for (i = 0; i < smp_cpus; i++) {
54
o = OBJECT(&s->cpu[i]);
55
56
- object_property_set_int(o, "psci-conduit", QEMU_PSCI_CONDUIT_SMC,
57
- &error_abort);
58
-
59
/* On uniprocessor, the CBAR is set to 0 */
60
if (smp_cpus > 1) {
61
object_property_set_int(o, "reset-cbar", FSL_IMX7_A7MPCORE_ADDR,
62
@@ -XXX,XX +XXX,XX @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)
63
}
64
65
if (i) {
66
- /* Secondary CPUs start in PSCI powered-down state */
67
+ /*
68
+ * Secondary CPUs start in powered-down state (and can be
69
+ * powered up via the SRC system reset controller)
70
+ */
71
object_property_set_bool(o, "start-powered-off", true,
72
&error_abort);
73
}
74
diff --git a/hw/arm/mcimx6ul-evk.c b/hw/arm/mcimx6ul-evk.c
75
index XXXXXXX..XXXXXXX 100644
76
--- a/hw/arm/mcimx6ul-evk.c
77
+++ b/hw/arm/mcimx6ul-evk.c
78
@@ -XXX,XX +XXX,XX @@ static void mcimx6ul_evk_init(MachineState *machine)
79
.board_id = -1,
80
.ram_size = machine->ram_size,
81
.nb_cpus = machine->smp.cpus,
82
+ .psci_conduit = QEMU_PSCI_CONDUIT_SMC,
83
};
84
85
s = FSL_IMX6UL(object_new(TYPE_FSL_IMX6UL));
86
diff --git a/hw/arm/mcimx7d-sabre.c b/hw/arm/mcimx7d-sabre.c
87
index XXXXXXX..XXXXXXX 100644
88
--- a/hw/arm/mcimx7d-sabre.c
89
+++ b/hw/arm/mcimx7d-sabre.c
90
@@ -XXX,XX +XXX,XX @@ static void mcimx7d_sabre_init(MachineState *machine)
91
.board_id = -1,
92
.ram_size = machine->ram_size,
93
.nb_cpus = machine->smp.cpus,
94
+ .psci_conduit = QEMU_PSCI_CONDUIT_SMC,
95
};
96
97
s = FSL_IMX7(object_new(TYPE_FSL_IMX7));
98
--
99
2.25.1
100
101
diff view generated by jsdifflib
1
We were setting the VBPR1 field of VMCR_EL2 to icv_min_vbpr()
1
Change the allwinner-h3 based board to use the new boot.c
2
on reset, but this is not correct. The field should reset to
2
functionality to allow us to enable psci-conduit only if the guest is
3
the minimum value of ICV_BPR0_EL1 plus one.
3
being booted in EL1 or EL2, so that if the user runs guest EL3
4
firmware code our PSCI emulation doesn't get in its way.
5
6
To do this we stop setting the psci-conduit property on the CPU
7
objects in the SoC code, and instead set the psci_conduit field in
8
the arm_boot_info struct to tell the common boot loader code that
9
we'd like PSCI if the guest is starting at an EL that it makes sense
10
with.
11
12
This affects the orangepi-pc board.
13
14
This commit leaves the secondary CPUs in the powered-down state if
15
the guest is booting at EL3, which is the same behaviour as before
16
this commit. The secondaries can no longer be started by that EL3
17
code making a PSCI call but can still be started via the CPU
18
Configuration Module registers (which we model in
19
hw/misc/allwinner-cpucfg.c).
4
20
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
21
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
22
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 1493226792-3237-2-git-send-email-peter.maydell@linaro.org
23
Reviewed-by: Niek Linnenbank <nieklinnenbank@gmail.com>
24
Tested-by: Cédric Le Goater <clg@kaod.org>
25
Tested-by: Niek Linnenbank <nieklinnenbank@gmail.com>
26
Message-id: 20220127154639.2090164-6-peter.maydell@linaro.org
8
---
27
---
9
hw/intc/arm_gicv3_cpuif.c | 2 +-
28
hw/arm/allwinner-h3.c | 9 ++++-----
10
1 file changed, 1 insertion(+), 1 deletion(-)
29
hw/arm/orangepi.c | 1 +
30
2 files changed, 5 insertions(+), 5 deletions(-)
11
31
12
diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
32
diff --git a/hw/arm/allwinner-h3.c b/hw/arm/allwinner-h3.c
13
index XXXXXXX..XXXXXXX 100644
33
index XXXXXXX..XXXXXXX 100644
14
--- a/hw/intc/arm_gicv3_cpuif.c
34
--- a/hw/arm/allwinner-h3.c
15
+++ b/hw/intc/arm_gicv3_cpuif.c
35
+++ b/hw/arm/allwinner-h3.c
16
@@ -XXX,XX +XXX,XX @@ static void icc_reset(CPUARMState *env, const ARMCPRegInfo *ri)
36
@@ -XXX,XX +XXX,XX @@ static void allwinner_h3_realize(DeviceState *dev, Error **errp)
17
cs->ich_hcr_el2 = 0;
37
/* CPUs */
18
memset(cs->ich_lr_el2, 0, sizeof(cs->ich_lr_el2));
38
for (i = 0; i < AW_H3_NUM_CPUS; i++) {
19
cs->ich_vmcr_el2 = ICH_VMCR_EL2_VFIQEN |
39
20
- (icv_min_vbpr(cs) << ICH_VMCR_EL2_VBPR1_SHIFT) |
40
- /* Provide Power State Coordination Interface */
21
+ ((icv_min_vbpr(cs) + 1) << ICH_VMCR_EL2_VBPR1_SHIFT) |
41
- qdev_prop_set_int32(DEVICE(&s->cpus[i]), "psci-conduit",
22
(icv_min_vbpr(cs) << ICH_VMCR_EL2_VBPR0_SHIFT);
42
- QEMU_PSCI_CONDUIT_SMC);
43
-
44
- /* Disable secondary CPUs */
45
+ /*
46
+ * Disable secondary CPUs. Guest EL3 firmware will start
47
+ * them via CPU reset control registers.
48
+ */
49
qdev_prop_set_bit(DEVICE(&s->cpus[i]), "start-powered-off",
50
i > 0);
51
52
diff --git a/hw/arm/orangepi.c b/hw/arm/orangepi.c
53
index XXXXXXX..XXXXXXX 100644
54
--- a/hw/arm/orangepi.c
55
+++ b/hw/arm/orangepi.c
56
@@ -XXX,XX +XXX,XX @@ static void orangepi_init(MachineState *machine)
57
}
58
orangepi_binfo.loader_start = h3->memmap[AW_H3_DEV_SDRAM];
59
orangepi_binfo.ram_size = machine->ram_size;
60
+ orangepi_binfo.psci_conduit = QEMU_PSCI_CONDUIT_SMC;
61
arm_load_kernel(ARM_CPU(first_cpu), machine, &orangepi_binfo);
23
}
62
}
24
63
25
--
64
--
26
2.7.4
65
2.25.1
27
66
28
67
diff view generated by jsdifflib
New patch
1
Change the Xilinx ZynqMP-based board xlnx-zcu102 to use the new
2
boot.c functionality to allow us to enable psci-conduit only if
3
the guest is being booted in EL1 or EL2, so that if the user runs
4
guest EL3 firmware code our PSCI emulation doesn't get in its
5
way.
1
6
7
To do this we stop setting the psci-conduit property on the CPU
8
objects in the SoC code, and instead set the psci_conduit field in
9
the arm_boot_info struct to tell the common boot loader code that
10
we'd like PSCI if the guest is starting at an EL that it makes
11
sense with.
12
13
Note that this means that EL3 guest code will have no way
14
to power on secondary cores, because we don't model any
15
kind of power controller that does that on this SoC.
16
17
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
18
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
19
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
20
Reviewed-by: Niek Linnenbank <nieklinnenbank@gmail.com>
21
Tested-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
22
Tested-by: Cédric Le Goater <clg@kaod.org>
23
Tested-by: Niek Linnenbank <nieklinnenbank@gmail.com>
24
Acked-by: Richard Henderson <richard.henderson@linaro.org>
25
Message-id: 20220127154639.2090164-7-peter.maydell@linaro.org
26
---
27
hw/arm/xlnx-zcu102.c | 1 +
28
hw/arm/xlnx-zynqmp.c | 11 ++++++-----
29
2 files changed, 7 insertions(+), 5 deletions(-)
30
31
diff --git a/hw/arm/xlnx-zcu102.c b/hw/arm/xlnx-zcu102.c
32
index XXXXXXX..XXXXXXX 100644
33
--- a/hw/arm/xlnx-zcu102.c
34
+++ b/hw/arm/xlnx-zcu102.c
35
@@ -XXX,XX +XXX,XX @@ static void xlnx_zcu102_init(MachineState *machine)
36
s->binfo.ram_size = ram_size;
37
s->binfo.loader_start = 0;
38
s->binfo.modify_dtb = zcu102_modify_dtb;
39
+ s->binfo.psci_conduit = QEMU_PSCI_CONDUIT_SMC;
40
arm_load_kernel(s->soc.boot_cpu_ptr, machine, &s->binfo);
41
}
42
43
diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
44
index XXXXXXX..XXXXXXX 100644
45
--- a/hw/arm/xlnx-zynqmp.c
46
+++ b/hw/arm/xlnx-zynqmp.c
47
@@ -XXX,XX +XXX,XX @@ static void xlnx_zynqmp_create_rpu(MachineState *ms, XlnxZynqMPState *s,
48
49
name = object_get_canonical_path_component(OBJECT(&s->rpu_cpu[i]));
50
if (strcmp(name, boot_cpu)) {
51
- /* Secondary CPUs start in PSCI powered-down state */
52
+ /*
53
+ * Secondary CPUs start in powered-down state.
54
+ */
55
object_property_set_bool(OBJECT(&s->rpu_cpu[i]),
56
"start-powered-off", true, &error_abort);
57
} else {
58
@@ -XXX,XX +XXX,XX @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
59
for (i = 0; i < num_apus; i++) {
60
const char *name;
61
62
- object_property_set_int(OBJECT(&s->apu_cpu[i]), "psci-conduit",
63
- QEMU_PSCI_CONDUIT_SMC, &error_abort);
64
-
65
name = object_get_canonical_path_component(OBJECT(&s->apu_cpu[i]));
66
if (strcmp(name, boot_cpu)) {
67
- /* Secondary CPUs start in PSCI powered-down state */
68
+ /*
69
+ * Secondary CPUs start in powered-down state.
70
+ */
71
object_property_set_bool(OBJECT(&s->apu_cpu[i]),
72
"start-powered-off", true, &error_abort);
73
} else {
74
--
75
2.25.1
76
77
diff view generated by jsdifflib
New patch
1
Instead of setting the CPU psci-conduit and start-powered-off
2
properties in the xlnx-versal-virt board code, set the arm_boot_info
3
psci_conduit field so that the boot.c code can do it.
1
4
5
This will fix a corner case where we were incorrectly enabling PSCI
6
emulation when booting guest code into EL3 because it was an ELF file
7
passed to -kernel. (EL3 guest code started via -bios, -pflash, or
8
the generic loader was already being run with PSCI emulation
9
disabled.)
10
11
Note that EL3 guest code has no way to turn on the secondary CPUs
12
because there's no emulated power controller, but this was already
13
true for EL3 guest code run via -bios, -pflash, or the generic
14
loader.
15
16
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
17
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
18
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
19
Reviewed-by: Niek Linnenbank <nieklinnenbank@gmail.com>
20
Tested-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
21
Tested-by: Cédric Le Goater <clg@kaod.org>
22
Tested-by: Niek Linnenbank <nieklinnenbank@gmail.com>
23
Message-id: 20220127154639.2090164-8-peter.maydell@linaro.org
24
---
25
include/hw/arm/xlnx-versal.h | 1 -
26
hw/arm/xlnx-versal-virt.c | 6 ++++--
27
hw/arm/xlnx-versal.c | 5 +----
28
3 files changed, 5 insertions(+), 7 deletions(-)
29
30
diff --git a/include/hw/arm/xlnx-versal.h b/include/hw/arm/xlnx-versal.h
31
index XXXXXXX..XXXXXXX 100644
32
--- a/include/hw/arm/xlnx-versal.h
33
+++ b/include/hw/arm/xlnx-versal.h
34
@@ -XXX,XX +XXX,XX @@ struct Versal {
35
36
struct {
37
MemoryRegion *mr_ddr;
38
- uint32_t psci_conduit;
39
} cfg;
40
};
41
42
diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c
43
index XXXXXXX..XXXXXXX 100644
44
--- a/hw/arm/xlnx-versal-virt.c
45
+++ b/hw/arm/xlnx-versal-virt.c
46
@@ -XXX,XX +XXX,XX @@ static void versal_virt_init(MachineState *machine)
47
* When loading an OS, we turn on QEMU's PSCI implementation with SMC
48
* as the PSCI conduit. When there's no -kernel, we assume the user
49
* provides EL3 firmware to handle PSCI.
50
+ *
51
+ * Even if the user provides a kernel filename, arm_load_kernel()
52
+ * may suppress PSCI if it's going to boot that guest code at EL3.
53
*/
54
if (machine->kernel_filename) {
55
psci_conduit = QEMU_PSCI_CONDUIT_SMC;
56
@@ -XXX,XX +XXX,XX @@ static void versal_virt_init(MachineState *machine)
57
TYPE_XLNX_VERSAL);
58
object_property_set_link(OBJECT(&s->soc), "ddr", OBJECT(machine->ram),
59
&error_abort);
60
- object_property_set_int(OBJECT(&s->soc), "psci-conduit", psci_conduit,
61
- &error_abort);
62
sysbus_realize(SYS_BUS_DEVICE(&s->soc), &error_fatal);
63
64
fdt_create(s);
65
@@ -XXX,XX +XXX,XX @@ static void versal_virt_init(MachineState *machine)
66
s->binfo.loader_start = 0x0;
67
s->binfo.get_dtb = versal_virt_get_dtb;
68
s->binfo.modify_dtb = versal_virt_modify_dtb;
69
+ s->binfo.psci_conduit = psci_conduit;
70
if (machine->kernel_filename) {
71
arm_load_kernel(&s->soc.fpd.apu.cpu[0], machine, &s->binfo);
72
} else {
73
diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c
74
index XXXXXXX..XXXXXXX 100644
75
--- a/hw/arm/xlnx-versal.c
76
+++ b/hw/arm/xlnx-versal.c
77
@@ -XXX,XX +XXX,XX @@ static void versal_create_apu_cpus(Versal *s)
78
object_initialize_child(OBJECT(s), "apu-cpu[*]", &s->fpd.apu.cpu[i],
79
XLNX_VERSAL_ACPU_TYPE);
80
obj = OBJECT(&s->fpd.apu.cpu[i]);
81
- object_property_set_int(obj, "psci-conduit", s->cfg.psci_conduit,
82
- &error_abort);
83
if (i) {
84
- /* Secondary CPUs start in PSCI powered-down state */
85
+ /* Secondary CPUs start in powered-down state */
86
object_property_set_bool(obj, "start-powered-off", true,
87
&error_abort);
88
}
89
@@ -XXX,XX +XXX,XX @@ static void versal_init(Object *obj)
90
static Property versal_properties[] = {
91
DEFINE_PROP_LINK("ddr", Versal, cfg.mr_ddr, TYPE_MEMORY_REGION,
92
MemoryRegion *),
93
- DEFINE_PROP_UINT32("psci-conduit", Versal, cfg.psci_conduit, 0),
94
DEFINE_PROP_END_OF_LIST()
95
};
96
97
--
98
2.25.1
99
100
diff view generated by jsdifflib
1
From: Andrew Jones <drjones@redhat.com>
1
Instead of setting the CPU psci-conduit and start-powered-off
2
properties in the virt board code, set the arm_boot_info psci_conduit
3
field so that the boot.c code can do it.
2
4
3
This is based on patch Shannon Zhao originally posted.
5
This will fix a corner case where we were incorrectly enabling PSCI
6
emulation when booting guest code into EL3 because it was an ELF file
7
passed to -kernel or to the generic loader. (EL3 guest code started
8
via -bios or -pflash was already being run with PSCI emulation
9
disabled.)
4
10
5
Cc: Shannon Zhao <zhaoshenglong@huawei.com>
6
Signed-off-by: Andrew Jones <drjones@redhat.com>
7
Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org>
8
Message-id: 20170529173751.3443-3-drjones@redhat.com
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
13
Reviewed-by: Niek Linnenbank <nieklinnenbank@gmail.com>
14
Tested-by: Cédric Le Goater <clg@kaod.org>
15
Tested-by: Niek Linnenbank <nieklinnenbank@gmail.com>
16
Message-id: 20220127154639.2090164-9-peter.maydell@linaro.org
10
---
17
---
11
hw/arm/virt.c | 21 +++++++++++++++++++++
18
hw/arm/virt.c | 12 +-----------
12
1 file changed, 21 insertions(+)
19
1 file changed, 1 insertion(+), 11 deletions(-)
13
20
14
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
21
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
15
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/arm/virt.c
23
--- a/hw/arm/virt.c
17
+++ b/hw/arm/virt.c
24
+++ b/hw/arm/virt.c
18
@@ -XXX,XX +XXX,XX @@ static void create_fdt(VirtMachineState *vms)
25
@@ -XXX,XX +XXX,XX @@ static void machvirt_init(MachineState *machine)
19
"clk24mhz");
26
object_property_set_bool(cpuobj, "has_el2", false, NULL);
20
qemu_fdt_setprop_cell(fdt, "/apb-pclk", "phandle", vms->clock_phandle);
27
}
21
28
22
+ if (have_numa_distance) {
29
- if (vms->psci_conduit != QEMU_PSCI_CONDUIT_DISABLED) {
23
+ int size = nb_numa_nodes * nb_numa_nodes * 3 * sizeof(uint32_t);
30
- object_property_set_int(cpuobj, "psci-conduit", vms->psci_conduit,
24
+ uint32_t *matrix = g_malloc0(size);
31
- NULL);
25
+ int idx, i, j;
32
-
26
+
33
- /* Secondary CPUs start in PSCI powered-down state */
27
+ for (i = 0; i < nb_numa_nodes; i++) {
34
- if (n > 0) {
28
+ for (j = 0; j < nb_numa_nodes; j++) {
35
- object_property_set_bool(cpuobj, "start-powered-off", true,
29
+ idx = (i * nb_numa_nodes + j) * 3;
36
- NULL);
30
+ matrix[idx + 0] = cpu_to_be32(i);
37
- }
31
+ matrix[idx + 1] = cpu_to_be32(j);
38
- }
32
+ matrix[idx + 2] = cpu_to_be32(numa_info[i].distance[j]);
39
-
33
+ }
40
if (vmc->kvm_no_adjvtime &&
34
+ }
41
object_property_find(cpuobj, "kvm-no-adjvtime")) {
35
+
42
object_property_set_bool(cpuobj, "kvm-no-adjvtime", true, NULL);
36
+ qemu_fdt_add_subnode(fdt, "/distance-map");
43
@@ -XXX,XX +XXX,XX @@ static void machvirt_init(MachineState *machine)
37
+ qemu_fdt_setprop_string(fdt, "/distance-map", "compatible",
44
vms->bootinfo.get_dtb = machvirt_dtb;
38
+ "numa-distance-map-v1");
45
vms->bootinfo.skip_dtb_autoload = true;
39
+ qemu_fdt_setprop(fdt, "/distance-map", "distance-matrix",
46
vms->bootinfo.firmware_loaded = firmware_loaded;
40
+ matrix, size);
47
+ vms->bootinfo.psci_conduit = vms->psci_conduit;
41
+ g_free(matrix);
48
arm_load_kernel(ARM_CPU(first_cpu), machine, &vms->bootinfo);
42
+ }
49
43
}
50
vms->machine_done.notify = virt_machine_done;
44
45
static void fdt_add_psci_node(const VirtMachineState *vms)
46
--
51
--
47
2.7.4
52
2.25.1
48
53
49
54
diff view generated by jsdifflib
New patch
1
Change the highbank/midway boards to use the new boot.c functionality
2
to allow us to enable psci-conduit only if the guest is being booted
3
in EL1 or EL2, so that if the user runs guest EL3 firmware code our
4
PSCI emulation doesn't get in its way.
1
5
6
To do this we stop setting the psci-conduit and start-powered-off
7
properties on the CPU objects in the board code, and instead set the
8
psci_conduit field in the arm_boot_info struct to tell the common
9
boot loader code that we'd like PSCI if the guest is starting at an
10
EL that it makes sense with (in which case it will set these
11
properties).
12
13
This means that when running guest code at EL3, all the cores
14
will start execution at once on poweron. This matches the
15
real hardware behaviour. (A brief description of the hardware
16
boot process is in the u-boot documentation for these boards:
17
https://u-boot.readthedocs.io/en/latest/board/highbank/highbank.html#boot-process
18
-- in theory one might run the 'a9boot'/'a15boot' secure monitor
19
code in QEMU, though we probably don't emulate enough for that.)
20
21
This affects the highbank and midway boards.
22
23
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
24
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
25
Reviewed-by: Niek Linnenbank <nieklinnenbank@gmail.com>
26
Tested-by: Cédric Le Goater <clg@kaod.org>
27
Tested-by: Niek Linnenbank <nieklinnenbank@gmail.com>
28
Message-id: 20220127154639.2090164-10-peter.maydell@linaro.org
29
---
30
hw/arm/highbank.c | 7 +------
31
1 file changed, 1 insertion(+), 6 deletions(-)
32
33
diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c
34
index XXXXXXX..XXXXXXX 100644
35
--- a/hw/arm/highbank.c
36
+++ b/hw/arm/highbank.c
37
@@ -XXX,XX +XXX,XX @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
38
object_property_set_int(cpuobj, "psci-conduit", QEMU_PSCI_CONDUIT_SMC,
39
&error_abort);
40
41
- if (n) {
42
- /* Secondary CPUs start in PSCI powered-down state */
43
- object_property_set_bool(cpuobj, "start-powered-off", true,
44
- &error_abort);
45
- }
46
-
47
if (object_property_find(cpuobj, "reset-cbar")) {
48
object_property_set_int(cpuobj, "reset-cbar", MPCORE_PERIPHBASE,
49
&error_abort);
50
@@ -XXX,XX +XXX,XX @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
51
highbank_binfo.board_setup_addr = BOARD_SETUP_ADDR;
52
highbank_binfo.write_board_setup = hb_write_board_setup;
53
highbank_binfo.secure_board_setup = true;
54
+ highbank_binfo.psci_conduit = QEMU_PSCI_CONDUIT_SMC;
55
56
arm_load_kernel(ARM_CPU(first_cpu), machine, &highbank_binfo);
57
}
58
--
59
2.25.1
60
61
diff view generated by jsdifflib
1
From: Wei Huang <wei@redhat.com>
1
The SMCCC 1.3 spec section 5.2 says
2
2
3
The PMUv3 driver of linux kernel (in arch/arm64/kernel/perf_event.c)
3
The Unknown SMC Function Identifier is a sign-extended value of (-1)
4
relies on the PMUVER field of id_aa64dfr0_el1 to decide if PMU support
4
that is returned in the R0, W0 or X0 registers. An implementation must
5
is present or not. This patch clears the PMUVER field under TCG mode
5
return this error code when it receives:
6
when vPMU=off. Without it, PMUv3 will init insider guest VMs even
7
with vPMU=off. This patch also removes a redundant line inside the
8
if-statement.
9
6
10
Signed-off-by: Wei Huang <wei@redhat.com>
7
* An SMC or HVC call with an unknown Function Identifier
11
Message-id: 1495123889-32301-1-git-send-email-wei@redhat.com
8
* An SMC or HVC call for a removed Function Identifier
9
* An SMC64/HVC64 call from AArch32 state
10
11
To comply with these statements, let's always return -1 when we encounter
12
an unknown HVC or SMC call.
13
14
[PMM:
15
This is a reinstatement of commit 9fcd15b9193e819b, previously
16
reverted in commit 4825eaae4fdd56fba0f; we can do this now that we
17
have arranged for all the affected board models to not enable the
18
PSCI emulation if they are running guest code at EL3. This avoids
19
the regressions that caused us to revert the change for 7.0.]
20
21
Signed-off-by: Alexander Graf <agraf@csgraf.de>
22
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
23
Reviewed-by: Niek Linnenbank <nieklinnenbank@gmail.com>
24
Tested-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
25
Tested-by: Cédric Le Goater <clg@kaod.org>
26
Tested-by: Niek Linnenbank <nieklinnenbank@gmail.com>
12
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
27
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
28
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
---
29
---
15
target/arm/cpu.c | 2 +-
30
target/arm/psci.c | 35 ++++++-----------------------------
16
1 file changed, 1 insertion(+), 1 deletion(-)
31
1 file changed, 6 insertions(+), 29 deletions(-)
17
32
18
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
33
diff --git a/target/arm/psci.c b/target/arm/psci.c
19
index XXXXXXX..XXXXXXX 100644
34
index XXXXXXX..XXXXXXX 100644
20
--- a/target/arm/cpu.c
35
--- a/target/arm/psci.c
21
+++ b/target/arm/cpu.c
36
+++ b/target/arm/psci.c
22
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
37
@@ -XXX,XX +XXX,XX @@
38
39
bool arm_is_psci_call(ARMCPU *cpu, int excp_type)
40
{
41
- /* Return true if the r0/x0 value indicates a PSCI call and
42
- * the exception type matches the configured PSCI conduit. This is
43
- * called before the SMC/HVC instruction is executed, to decide whether
44
- * we should treat it as a PSCI call or with the architecturally
45
+ /*
46
+ * Return true if the exception type matches the configured PSCI conduit.
47
+ * This is called before the SMC/HVC instruction is executed, to decide
48
+ * whether we should treat it as a PSCI call or with the architecturally
49
* defined behaviour for an SMC or HVC (which might be UNDEF or trap
50
* to EL2 or to EL3).
51
*/
52
- CPUARMState *env = &cpu->env;
53
- uint64_t param = is_a64(env) ? env->xregs[0] : env->regs[0];
54
55
switch (excp_type) {
56
case EXCP_HVC:
57
@@ -XXX,XX +XXX,XX @@ bool arm_is_psci_call(ARMCPU *cpu, int excp_type)
58
return false;
23
}
59
}
24
60
25
if (!cpu->has_pmu) {
61
- switch (param) {
26
- cpu->has_pmu = false;
62
- case QEMU_PSCI_0_2_FN_PSCI_VERSION:
27
unset_feature(env, ARM_FEATURE_PMU);
63
- case QEMU_PSCI_0_2_FN_MIGRATE_INFO_TYPE:
28
+ cpu->id_aa64dfr0 &= ~0xf00;
64
- case QEMU_PSCI_0_2_FN_AFFINITY_INFO:
65
- case QEMU_PSCI_0_2_FN64_AFFINITY_INFO:
66
- case QEMU_PSCI_0_2_FN_SYSTEM_RESET:
67
- case QEMU_PSCI_0_2_FN_SYSTEM_OFF:
68
- case QEMU_PSCI_0_1_FN_CPU_ON:
69
- case QEMU_PSCI_0_2_FN_CPU_ON:
70
- case QEMU_PSCI_0_2_FN64_CPU_ON:
71
- case QEMU_PSCI_0_1_FN_CPU_OFF:
72
- case QEMU_PSCI_0_2_FN_CPU_OFF:
73
- case QEMU_PSCI_0_1_FN_CPU_SUSPEND:
74
- case QEMU_PSCI_0_2_FN_CPU_SUSPEND:
75
- case QEMU_PSCI_0_2_FN64_CPU_SUSPEND:
76
- case QEMU_PSCI_0_1_FN_MIGRATE:
77
- case QEMU_PSCI_0_2_FN_MIGRATE:
78
- return true;
79
- default:
80
- return false;
81
- }
82
+ return true;
83
}
84
85
void arm_handle_psci_call(ARMCPU *cpu)
86
@@ -XXX,XX +XXX,XX @@ void arm_handle_psci_call(ARMCPU *cpu)
87
break;
88
case QEMU_PSCI_0_1_FN_MIGRATE:
89
case QEMU_PSCI_0_2_FN_MIGRATE:
90
+ default:
91
ret = QEMU_PSCI_RET_NOT_SUPPORTED;
92
break;
93
- default:
94
- g_assert_not_reached();
29
}
95
}
30
96
31
if (!arm_feature(env, ARM_FEATURE_EL2)) {
97
err:
32
--
98
--
33
2.7.4
99
2.25.1
34
100
35
101
diff view generated by jsdifflib
New patch
1
Guest code on highbank may make non-PSCI SMC calls in order to
2
enable/disable the L2x0 cache controller (see the Linux kernel's
3
arch/arm/mach-highbank/highbank.c highbank_l2c310_write_sec()
4
function). The ABI for this is documented in kernel commit
5
8e56130dcb as being borrowed from the OMAP44xx ROM. The OMAP44xx TRM
6
documents this function ID as having no return value and potentially
7
trashing all guest registers except SP and PC. For QEMU's purposes
8
(where our L2x0 model is a stub and enabling or disabling it doesn't
9
affect the guest behaviour) a simple "do nothing" SMC is fine.
1
10
11
We currently implement this NOP behaviour using a little bit of
12
Secure code we run before jumping to the guest kernel, which is
13
written by arm_write_secure_board_setup_dummy_smc(). The code sets
14
up a set of Secure vectors where the SMC entry point returns without
15
doing anything.
16
17
Now that the PSCI SMC emulation handles all SMC calls (setting r0 to
18
an error code if the input r0 function identifier is not recognized),
19
we can use that default behaviour as sufficient for the highbank
20
cache controller call. (Because the guest code assumes r0 has no
21
interesting value on exit it doesn't matter that we set it to the
22
error code). We can therefore delete the highbank board code that
23
sets secure_board_setup to true and writes the secure-code bootstub.
24
25
(Note that because the OMAP44xx ABI puts function-identifiers in
26
r12 and PSCI uses r0, we only avoid a clash because Linux's code
27
happens to put the function-identifier in both registers. But this
28
is true also when the kernel is running on real firmware that
29
implements both ABIs as far as I can see.)
30
31
This change fixes in passing booting on the 'midway' board model,
32
which has been completely broken since we added support for Hyp
33
mode to the Cortex-A15 CPU. When we did that boot.c was made to
34
start running the guest code in Hyp mode; this includes the
35
board_setup hook, which instantly UNDEFs because the NSACR is
36
not accessible from Hyp. (Put another way, we never made the
37
secure_board_setup hook support cope with Hyp mode.)
38
39
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
40
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
41
Reviewed-by: Niek Linnenbank <nieklinnenbank@gmail.com>
42
Tested-by: Cédric Le Goater <clg@kaod.org>
43
Tested-by: Niek Linnenbank <nieklinnenbank@gmail.com>
44
Message-id: 20220127154639.2090164-12-peter.maydell@linaro.org
45
---
46
hw/arm/highbank.c | 8 --------
47
1 file changed, 8 deletions(-)
48
49
diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c
50
index XXXXXXX..XXXXXXX 100644
51
--- a/hw/arm/highbank.c
52
+++ b/hw/arm/highbank.c
53
@@ -XXX,XX +XXX,XX @@
54
55
/* Board init. */
56
57
-static void hb_write_board_setup(ARMCPU *cpu,
58
- const struct arm_boot_info *info)
59
-{
60
- arm_write_secure_board_setup_dummy_smc(cpu, info, MVBAR_ADDR);
61
-}
62
-
63
static void hb_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info)
64
{
65
int n;
66
@@ -XXX,XX +XXX,XX @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
67
highbank_binfo.write_secondary_boot = hb_write_secondary;
68
highbank_binfo.secondary_cpu_reset_hook = hb_reset_secondary;
69
highbank_binfo.board_setup_addr = BOARD_SETUP_ADDR;
70
- highbank_binfo.write_board_setup = hb_write_board_setup;
71
- highbank_binfo.secure_board_setup = true;
72
highbank_binfo.psci_conduit = QEMU_PSCI_CONDUIT_SMC;
73
74
arm_load_kernel(ARM_CPU(first_cpu), machine, &highbank_binfo);
75
--
76
2.25.1
77
78
diff view generated by jsdifflib
New patch
1
Now that we have dealt with the one special case (highbank) that needed
2
to set both psci_conduit and secure_board_setup, we don't need to
3
allow that combination any more. It doesn't make sense in general,
4
so use an assertion to ensure we don't add new boards that do it
5
by accident without thinking through the consequences.
1
6
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
9
Reviewed-by: Niek Linnenbank <nieklinnenbank@gmail.com>
10
Tested-by: Cédric Le Goater <clg@kaod.org>
11
Tested-by: Niek Linnenbank <nieklinnenbank@gmail.com>
12
Message-id: 20220127154639.2090164-13-peter.maydell@linaro.org
13
---
14
hw/arm/boot.c | 10 ++++++++++
15
1 file changed, 10 insertions(+)
16
17
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/hw/arm/boot.c
20
+++ b/hw/arm/boot.c
21
@@ -XXX,XX +XXX,XX @@ void arm_load_kernel(ARMCPU *cpu, MachineState *ms, struct arm_boot_info *info)
22
* supported exception level or in a lower one.
23
*/
24
25
+ /*
26
+ * If PSCI is enabled, then SMC calls all go to the PSCI handler and
27
+ * are never emulated to trap into guest code. It therefore does not
28
+ * make sense for the board to have a setup code fragment that runs
29
+ * in Secure, because this will probably need to itself issue an SMC of some
30
+ * kind as part of its operation.
31
+ */
32
+ assert(info->psci_conduit == QEMU_PSCI_CONDUIT_DISABLED ||
33
+ !info->secure_board_setup);
34
+
35
/* Boot into highest supported EL ... */
36
if (arm_feature(env, ARM_FEATURE_EL3)) {
37
boot_el = 3;
38
--
39
2.25.1
40
41
diff view generated by jsdifflib
1
icc_bpr_write() was not enforcing that writing a value below the
1
If we're using PSCI emulation to start secondary CPUs, there is no
2
minimum for the BPR should behave as if the BPR was set to the
2
point in writing the "secondary boot" stub code, because it will
3
minimum value. This doesn't make a difference for the secure
3
never be used -- secondary CPUs start powered-off, and when powered
4
BPRs (since we define the minimum for the QEMU implementation
4
on are set to begin execution at the address specified by the guest's
5
as zero) but did mean we were allowing the NS BPR1 to be set to
5
power-on PSCI call, not at the stub.
6
0 when 1 should be the lowest value.
6
7
Move the call to the hook that writes the secondary boot stub code so
8
that we can do it only if we're starting a Linux kernel and not using
9
PSCI.
10
11
(None of the users of the hook care about the ordering of its call
12
relative to anything else: they only use it to write a rom blob to
13
guest memory.)
7
14
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
16
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
Message-id: 1493226792-3237-3-git-send-email-peter.maydell@linaro.org
17
Reviewed-by: Niek Linnenbank <nieklinnenbank@gmail.com>
18
Tested-by: Cédric Le Goater <clg@kaod.org>
19
Tested-by: Niek Linnenbank <nieklinnenbank@gmail.com>
20
Message-id: 20220127154639.2090164-14-peter.maydell@linaro.org
11
---
21
---
12
hw/intc/arm_gicv3_cpuif.c | 6 ++++++
22
include/hw/arm/boot.h | 3 +++
13
1 file changed, 6 insertions(+)
23
hw/arm/boot.c | 35 ++++++++++++++++++++++++-----------
24
2 files changed, 27 insertions(+), 11 deletions(-)
14
25
15
diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
26
diff --git a/include/hw/arm/boot.h b/include/hw/arm/boot.h
16
index XXXXXXX..XXXXXXX 100644
27
index XXXXXXX..XXXXXXX 100644
17
--- a/hw/intc/arm_gicv3_cpuif.c
28
--- a/include/hw/arm/boot.h
18
+++ b/hw/intc/arm_gicv3_cpuif.c
29
+++ b/include/hw/arm/boot.h
19
@@ -XXX,XX +XXX,XX @@ static void icc_bpr_write(CPUARMState *env, const ARMCPRegInfo *ri,
30
@@ -XXX,XX +XXX,XX @@ struct arm_boot_info {
20
{
31
* boot loader/boot ROM code, and secondary_cpu_reset_hook() should
21
GICv3CPUState *cs = icc_cs_from_env(env);
32
* perform any necessary CPU reset handling and set the PC for the
22
int grp = (ri->crm == 8) ? GICV3_G0 : GICV3_G1;
33
* secondary CPUs to point at this boot blob.
23
+ uint64_t minval;
34
+ *
24
35
+ * These hooks won't be called if secondary CPUs are booting via
25
if (icv_access(env, grp == GICV3_G0 ? HCR_FMO : HCR_IMO)) {
36
+ * emulated PSCI (see psci_conduit below).
26
icv_bpr_write(env, ri, value);
37
*/
27
@@ -XXX,XX +XXX,XX @@ static void icc_bpr_write(CPUARMState *env, const ARMCPRegInfo *ri,
38
void (*write_secondary_boot)(ARMCPU *cpu,
28
return;
39
const struct arm_boot_info *info);
40
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
41
index XXXXXXX..XXXXXXX 100644
42
--- a/hw/arm/boot.c
43
+++ b/hw/arm/boot.c
44
@@ -XXX,XX +XXX,XX @@ static void do_cpu_reset(void *opaque)
45
set_kernel_args(info, as);
46
}
47
}
48
- } else {
49
+ } else if (info->secondary_cpu_reset_hook) {
50
info->secondary_cpu_reset_hook(cpu, info);
51
}
52
}
53
@@ -XXX,XX +XXX,XX @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu,
54
elf_machine = EM_ARM;
29
}
55
}
30
56
31
+ minval = (grp == GICV3_G1NS) ? GIC_MIN_BPR_NS : GIC_MIN_BPR;
57
- if (!info->secondary_cpu_reset_hook) {
32
+ if (value < minval) {
58
- info->secondary_cpu_reset_hook = default_reset_secondary;
33
+ value = minval;
59
- }
60
- if (!info->write_secondary_boot) {
61
- info->write_secondary_boot = default_write_secondary;
62
- }
63
-
64
if (info->nb_cpus == 0)
65
info->nb_cpus = 1;
66
67
@@ -XXX,XX +XXX,XX @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu,
68
write_bootloader("bootloader", info->loader_start,
69
primary_loader, fixupcontext, as);
70
71
- if (info->nb_cpus > 1) {
72
- info->write_secondary_boot(cpu, info);
73
- }
74
if (info->write_board_setup) {
75
info->write_board_setup(cpu, info);
76
}
77
@@ -XXX,XX +XXX,XX @@ void arm_load_kernel(ARMCPU *cpu, MachineState *ms, struct arm_boot_info *info)
78
}
79
}
80
81
+ if (info->psci_conduit == QEMU_PSCI_CONDUIT_DISABLED &&
82
+ info->is_linux && info->nb_cpus > 1) {
83
+ /*
84
+ * We're booting Linux but not using PSCI, so for SMP we need
85
+ * to write a custom secondary CPU boot loader stub, and arrange
86
+ * for the secondary CPU reset to make the accompanying initialization.
87
+ */
88
+ if (!info->secondary_cpu_reset_hook) {
89
+ info->secondary_cpu_reset_hook = default_reset_secondary;
90
+ }
91
+ if (!info->write_secondary_boot) {
92
+ info->write_secondary_boot = default_write_secondary;
93
+ }
94
+ info->write_secondary_boot(cpu, info);
95
+ } else {
96
+ /*
97
+ * No secondary boot stub; don't use the reset hook that would
98
+ * have set the CPU up to call it
99
+ */
100
+ info->write_secondary_boot = NULL;
101
+ info->secondary_cpu_reset_hook = NULL;
34
+ }
102
+ }
35
+
103
+
36
cs->icc_bpr[grp] = value & 7;
104
/*
37
gicv3_cpuif_update(cs);
105
* arm_load_dtb() may add a PSCI node so it must be called after we have
38
}
106
* decided whether to enable PSCI and set the psci-conduit CPU properties.
39
--
107
--
40
2.7.4
108
2.25.1
41
109
42
110
diff view generated by jsdifflib
New patch
1
The highbank and midway board code includes boot-stub code for
2
handling secondary CPU boot which keeps the secondaries in a pen
3
until the primary writes to a known location with the address they
4
should jump to.
1
5
6
This code is never used, because the boards enable QEMU's PSCI
7
emulation, so secondary CPUs are kept powered off until the PSCI call
8
which turns them on, and then start execution from the address given
9
by the guest in that PSCI call. Delete the unreachable code.
10
11
(The code was wrong for midway in any case -- on the Cortex-A15 the
12
GIC CPU interface registers are at a different offset from PERIPHBASE
13
compared to the Cortex-A9, and the code baked-in the offsets for
14
highbank's A9.)
15
16
Note that this commit implicitly depends on the preceding "Don't
17
write secondary boot stub if using PSCI" commit -- the default
18
secondary-boot stub code overlaps with one of the highbank-specific
19
bootcode rom blobs, so we must suppress the secondary-boot
20
stub code entirely, not merely replace the highbank-specific
21
version with the default.
22
23
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
24
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
25
Reviewed-by: Niek Linnenbank <nieklinnenbank@gmail.com>
26
Tested-by: Cédric Le Goater <clg@kaod.org>
27
Tested-by: Niek Linnenbank <nieklinnenbank@gmail.com>
28
Message-id: 20220127154639.2090164-15-peter.maydell@linaro.org
29
---
30
hw/arm/highbank.c | 56 -----------------------------------------------
31
1 file changed, 56 deletions(-)
32
33
diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c
34
index XXXXXXX..XXXXXXX 100644
35
--- a/hw/arm/highbank.c
36
+++ b/hw/arm/highbank.c
37
@@ -XXX,XX +XXX,XX @@
38
39
/* Board init. */
40
41
-static void hb_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info)
42
-{
43
- int n;
44
- uint32_t smpboot[] = {
45
- 0xee100fb0, /* mrc p15, 0, r0, c0, c0, 5 - read current core id */
46
- 0xe210000f, /* ands r0, r0, #0x0f */
47
- 0xe3a03040, /* mov r3, #0x40 - jump address is 0x40 + 0x10 * core id */
48
- 0xe0830200, /* add r0, r3, r0, lsl #4 */
49
- 0xe59f2024, /* ldr r2, privbase */
50
- 0xe3a01001, /* mov r1, #1 */
51
- 0xe5821100, /* str r1, [r2, #256] - set GICC_CTLR.Enable */
52
- 0xe3a010ff, /* mov r1, #0xff */
53
- 0xe5821104, /* str r1, [r2, #260] - set GICC_PMR.Priority to 0xff */
54
- 0xf57ff04f, /* dsb */
55
- 0xe320f003, /* wfi */
56
- 0xe5901000, /* ldr r1, [r0] */
57
- 0xe1110001, /* tst r1, r1 */
58
- 0x0afffffb, /* beq <wfi> */
59
- 0xe12fff11, /* bx r1 */
60
- MPCORE_PERIPHBASE /* privbase: MPCore peripheral base address. */
61
- };
62
- for (n = 0; n < ARRAY_SIZE(smpboot); n++) {
63
- smpboot[n] = tswap32(smpboot[n]);
64
- }
65
- rom_add_blob_fixed_as("smpboot", smpboot, sizeof(smpboot), SMP_BOOT_ADDR,
66
- arm_boot_address_space(cpu, info));
67
-}
68
-
69
-static void hb_reset_secondary(ARMCPU *cpu, const struct arm_boot_info *info)
70
-{
71
- CPUARMState *env = &cpu->env;
72
-
73
- switch (info->nb_cpus) {
74
- case 4:
75
- address_space_stl_notdirty(&address_space_memory,
76
- SMP_BOOT_REG + 0x30, 0,
77
- MEMTXATTRS_UNSPECIFIED, NULL);
78
- /* fallthrough */
79
- case 3:
80
- address_space_stl_notdirty(&address_space_memory,
81
- SMP_BOOT_REG + 0x20, 0,
82
- MEMTXATTRS_UNSPECIFIED, NULL);
83
- /* fallthrough */
84
- case 2:
85
- address_space_stl_notdirty(&address_space_memory,
86
- SMP_BOOT_REG + 0x10, 0,
87
- MEMTXATTRS_UNSPECIFIED, NULL);
88
- env->regs[15] = SMP_BOOT_ADDR;
89
- break;
90
- default:
91
- break;
92
- }
93
-}
94
-
95
#define NUM_REGS 0x200
96
static void hb_regs_write(void *opaque, hwaddr offset,
97
uint64_t value, unsigned size)
98
@@ -XXX,XX +XXX,XX @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
99
highbank_binfo.board_id = -1;
100
highbank_binfo.nb_cpus = smp_cpus;
101
highbank_binfo.loader_start = 0;
102
- highbank_binfo.write_secondary_boot = hb_write_secondary;
103
- highbank_binfo.secondary_cpu_reset_hook = hb_reset_secondary;
104
highbank_binfo.board_setup_addr = BOARD_SETUP_ADDR;
105
highbank_binfo.psci_conduit = QEMU_PSCI_CONDUIT_SMC;
106
107
--
108
2.25.1
109
110
diff view generated by jsdifflib
1
From: Cédric Le Goater <clg@kaod.org>
1
We use the arm_boot_info::nb_cpus field in only one place, and that
2
2
place can easily get the number of CPUs locally rather than relying
3
Temperatures can be changed from the monitor with :
3
on the board code to have set the field correctly. (At least one
4
4
board, xlnx-versal-virt, does not set the field despite having more
5
    (qemu) qom-set /machine/unattached/device[2] temperature0 12000
5
than one CPU.)
6
6
7
Signed-off-by: Cédric Le Goater <clg@kaod.org>
8
Message-id: 1494827476-1487-7-git-send-email-clg@kaod.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
9
Reviewed-by: Niek Linnenbank <nieklinnenbank@gmail.com>
10
Tested-by: Cédric Le Goater <clg@kaod.org>
11
Tested-by: Niek Linnenbank <nieklinnenbank@gmail.com>
12
Message-id: 20220127154639.2090164-16-peter.maydell@linaro.org
11
---
13
---
12
hw/arm/aspeed.c | 9 +++++++++
14
include/hw/arm/boot.h | 1 -
13
1 file changed, 9 insertions(+)
15
hw/arm/aspeed.c | 1 -
14
16
hw/arm/boot.c | 7 +++----
17
hw/arm/exynos4_boards.c | 1 -
18
hw/arm/highbank.c | 1 -
19
hw/arm/imx25_pdk.c | 3 +--
20
hw/arm/kzm.c | 1 -
21
hw/arm/mcimx6ul-evk.c | 1 -
22
hw/arm/mcimx7d-sabre.c | 1 -
23
hw/arm/npcm7xx.c | 3 ---
24
hw/arm/orangepi.c | 4 +---
25
hw/arm/raspi.c | 1 -
26
hw/arm/realview.c | 1 -
27
hw/arm/sabrelite.c | 1 -
28
hw/arm/sbsa-ref.c | 1 -
29
hw/arm/vexpress.c | 1 -
30
hw/arm/virt.c | 1 -
31
hw/arm/xilinx_zynq.c | 1 -
32
18 files changed, 5 insertions(+), 26 deletions(-)
33
34
diff --git a/include/hw/arm/boot.h b/include/hw/arm/boot.h
35
index XXXXXXX..XXXXXXX 100644
36
--- a/include/hw/arm/boot.h
37
+++ b/include/hw/arm/boot.h
38
@@ -XXX,XX +XXX,XX @@ struct arm_boot_info {
39
hwaddr smp_loader_start;
40
hwaddr smp_bootreg_addr;
41
hwaddr gic_cpu_if_addr;
42
- int nb_cpus;
43
int board_id;
44
/* ARM machines that support the ARM Security Extensions use this field to
45
* control whether Linux is booted as secure(true) or non-secure(false).
15
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
46
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
16
index XXXXXXX..XXXXXXX 100644
47
index XXXXXXX..XXXXXXX 100644
17
--- a/hw/arm/aspeed.c
48
--- a/hw/arm/aspeed.c
18
+++ b/hw/arm/aspeed.c
49
+++ b/hw/arm/aspeed.c
19
@@ -XXX,XX +XXX,XX @@ static void aspeed_board_init(MachineState *machine,
50
@@ -XXX,XX +XXX,XX @@ static void aspeed_machine_init(MachineState *machine)
20
static void palmetto_bmc_i2c_init(AspeedBoardState *bmc)
51
52
aspeed_board_binfo.ram_size = machine->ram_size;
53
aspeed_board_binfo.loader_start = sc->memmap[ASPEED_DEV_SDRAM];
54
- aspeed_board_binfo.nb_cpus = sc->num_cpus;
55
56
if (amc->i2c_init) {
57
amc->i2c_init(bmc);
58
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
59
index XXXXXXX..XXXXXXX 100644
60
--- a/hw/arm/boot.c
61
+++ b/hw/arm/boot.c
62
@@ -XXX,XX +XXX,XX @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu,
63
elf_machine = EM_ARM;
64
}
65
66
- if (info->nb_cpus == 0)
67
- info->nb_cpus = 1;
68
-
69
/* Assume that raw images are linux kernels, and ELF images are not. */
70
kernel_size = arm_load_elf(info, &elf_entry, &image_low_addr,
71
&image_high_addr, elf_machine, as);
72
@@ -XXX,XX +XXX,XX @@ void arm_load_kernel(ARMCPU *cpu, MachineState *ms, struct arm_boot_info *info)
73
AddressSpace *as = arm_boot_address_space(cpu, info);
74
int boot_el;
75
CPUARMState *env = &cpu->env;
76
+ int nb_cpus = 0;
77
78
/*
79
* CPU objects (unlike devices) are not automatically reset on system
80
@@ -XXX,XX +XXX,XX @@ void arm_load_kernel(ARMCPU *cpu, MachineState *ms, struct arm_boot_info *info)
81
*/
82
for (cs = first_cpu; cs; cs = CPU_NEXT(cs)) {
83
qemu_register_reset(do_cpu_reset, ARM_CPU(cs));
84
+ nb_cpus++;
85
}
86
87
/*
88
@@ -XXX,XX +XXX,XX @@ void arm_load_kernel(ARMCPU *cpu, MachineState *ms, struct arm_boot_info *info)
89
}
90
91
if (info->psci_conduit == QEMU_PSCI_CONDUIT_DISABLED &&
92
- info->is_linux && info->nb_cpus > 1) {
93
+ info->is_linux && nb_cpus > 1) {
94
/*
95
* We're booting Linux but not using PSCI, so for SMP we need
96
* to write a custom secondary CPU boot loader stub, and arrange
97
diff --git a/hw/arm/exynos4_boards.c b/hw/arm/exynos4_boards.c
98
index XXXXXXX..XXXXXXX 100644
99
--- a/hw/arm/exynos4_boards.c
100
+++ b/hw/arm/exynos4_boards.c
101
@@ -XXX,XX +XXX,XX @@ static unsigned long exynos4_board_ram_size[EXYNOS4_NUM_OF_BOARDS] = {
102
static struct arm_boot_info exynos4_board_binfo = {
103
.loader_start = EXYNOS4210_BASE_BOOT_ADDR,
104
.smp_loader_start = EXYNOS4210_SMP_BOOT_ADDR,
105
- .nb_cpus = EXYNOS4210_NCPUS,
106
.write_secondary_boot = exynos4210_write_secondary,
107
};
108
109
diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c
110
index XXXXXXX..XXXXXXX 100644
111
--- a/hw/arm/highbank.c
112
+++ b/hw/arm/highbank.c
113
@@ -XXX,XX +XXX,XX @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
114
* clear that the value is meaningless.
115
*/
116
highbank_binfo.board_id = -1;
117
- highbank_binfo.nb_cpus = smp_cpus;
118
highbank_binfo.loader_start = 0;
119
highbank_binfo.board_setup_addr = BOARD_SETUP_ADDR;
120
highbank_binfo.psci_conduit = QEMU_PSCI_CONDUIT_SMC;
121
diff --git a/hw/arm/imx25_pdk.c b/hw/arm/imx25_pdk.c
122
index XXXXXXX..XXXXXXX 100644
123
--- a/hw/arm/imx25_pdk.c
124
+++ b/hw/arm/imx25_pdk.c
125
@@ -XXX,XX +XXX,XX @@ static void imx25_pdk_init(MachineState *machine)
126
127
imx25_pdk_binfo.ram_size = machine->ram_size;
128
imx25_pdk_binfo.loader_start = FSL_IMX25_SDRAM0_ADDR;
129
- imx25_pdk_binfo.board_id = 1771,
130
- imx25_pdk_binfo.nb_cpus = 1;
131
+ imx25_pdk_binfo.board_id = 1771;
132
133
for (i = 0; i < FSL_IMX25_NUM_ESDHCS; i++) {
134
BusState *bus;
135
diff --git a/hw/arm/kzm.c b/hw/arm/kzm.c
136
index XXXXXXX..XXXXXXX 100644
137
--- a/hw/arm/kzm.c
138
+++ b/hw/arm/kzm.c
139
@@ -XXX,XX +XXX,XX @@ static void kzm_init(MachineState *machine)
140
}
141
142
kzm_binfo.ram_size = machine->ram_size;
143
- kzm_binfo.nb_cpus = 1;
144
145
if (!qtest_enabled()) {
146
arm_load_kernel(&s->soc.cpu, machine, &kzm_binfo);
147
diff --git a/hw/arm/mcimx6ul-evk.c b/hw/arm/mcimx6ul-evk.c
148
index XXXXXXX..XXXXXXX 100644
149
--- a/hw/arm/mcimx6ul-evk.c
150
+++ b/hw/arm/mcimx6ul-evk.c
151
@@ -XXX,XX +XXX,XX @@ static void mcimx6ul_evk_init(MachineState *machine)
152
.loader_start = FSL_IMX6UL_MMDC_ADDR,
153
.board_id = -1,
154
.ram_size = machine->ram_size,
155
- .nb_cpus = machine->smp.cpus,
156
.psci_conduit = QEMU_PSCI_CONDUIT_SMC,
157
};
158
159
diff --git a/hw/arm/mcimx7d-sabre.c b/hw/arm/mcimx7d-sabre.c
160
index XXXXXXX..XXXXXXX 100644
161
--- a/hw/arm/mcimx7d-sabre.c
162
+++ b/hw/arm/mcimx7d-sabre.c
163
@@ -XXX,XX +XXX,XX @@ static void mcimx7d_sabre_init(MachineState *machine)
164
.loader_start = FSL_IMX7_MMDC_ADDR,
165
.board_id = -1,
166
.ram_size = machine->ram_size,
167
- .nb_cpus = machine->smp.cpus,
168
.psci_conduit = QEMU_PSCI_CONDUIT_SMC,
169
};
170
171
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
172
index XXXXXXX..XXXXXXX 100644
173
--- a/hw/arm/npcm7xx.c
174
+++ b/hw/arm/npcm7xx.c
175
@@ -XXX,XX +XXX,XX @@ static struct arm_boot_info npcm7xx_binfo = {
176
177
void npcm7xx_load_kernel(MachineState *machine, NPCM7xxState *soc)
21
{
178
{
22
AspeedSoCState *soc = &bmc->soc;
179
- NPCM7xxClass *sc = NPCM7XX_GET_CLASS(soc);
23
+ DeviceState *dev;
180
-
24
181
npcm7xx_binfo.ram_size = machine->ram_size;
25
/* The palmetto platform expects a ds3231 RTC but a ds1338 is
182
- npcm7xx_binfo.nb_cpus = sc->num_cpus;
26
* enough to provide basic RTC features. Alarms will be missing */
183
27
i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 0), "ds1338", 0x68);
184
arm_load_kernel(&soc->cpu[0], machine, &npcm7xx_binfo);
28
+
29
+ /* add a TMP423 temperature sensor */
30
+ dev = i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 2),
31
+ "tmp423", 0x4c);
32
+ object_property_set_int(OBJECT(dev), 31000, "temperature0", &error_abort);
33
+ object_property_set_int(OBJECT(dev), 28000, "temperature1", &error_abort);
34
+ object_property_set_int(OBJECT(dev), 20000, "temperature2", &error_abort);
35
+ object_property_set_int(OBJECT(dev), 110000, "temperature3", &error_abort);
36
}
185
}
37
186
diff --git a/hw/arm/orangepi.c b/hw/arm/orangepi.c
38
static void palmetto_bmc_init(MachineState *machine)
187
index XXXXXXX..XXXXXXX 100644
188
--- a/hw/arm/orangepi.c
189
+++ b/hw/arm/orangepi.c
190
@@ -XXX,XX +XXX,XX @@
191
#include "hw/qdev-properties.h"
192
#include "hw/arm/allwinner-h3.h"
193
194
-static struct arm_boot_info orangepi_binfo = {
195
- .nb_cpus = AW_H3_NUM_CPUS,
196
-};
197
+static struct arm_boot_info orangepi_binfo;
198
199
static void orangepi_init(MachineState *machine)
200
{
201
diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c
202
index XXXXXXX..XXXXXXX 100644
203
--- a/hw/arm/raspi.c
204
+++ b/hw/arm/raspi.c
205
@@ -XXX,XX +XXX,XX @@ static void setup_boot(MachineState *machine, RaspiProcessorId processor_id,
206
207
s->binfo.board_id = MACH_TYPE_BCM2708;
208
s->binfo.ram_size = ram_size;
209
- s->binfo.nb_cpus = machine->smp.cpus;
210
211
if (processor_id <= PROCESSOR_ID_BCM2836) {
212
/*
213
diff --git a/hw/arm/realview.c b/hw/arm/realview.c
214
index XXXXXXX..XXXXXXX 100644
215
--- a/hw/arm/realview.c
216
+++ b/hw/arm/realview.c
217
@@ -XXX,XX +XXX,XX @@ static void realview_init(MachineState *machine,
218
memory_region_add_subregion(sysmem, SMP_BOOT_ADDR, ram_hack);
219
220
realview_binfo.ram_size = ram_size;
221
- realview_binfo.nb_cpus = smp_cpus;
222
realview_binfo.board_id = realview_board_id[board_type];
223
realview_binfo.loader_start = (board_type == BOARD_PB_A8 ? 0x70000000 : 0);
224
arm_load_kernel(ARM_CPU(first_cpu), machine, &realview_binfo);
225
diff --git a/hw/arm/sabrelite.c b/hw/arm/sabrelite.c
226
index XXXXXXX..XXXXXXX 100644
227
--- a/hw/arm/sabrelite.c
228
+++ b/hw/arm/sabrelite.c
229
@@ -XXX,XX +XXX,XX @@ static void sabrelite_init(MachineState *machine)
230
}
231
232
sabrelite_binfo.ram_size = machine->ram_size;
233
- sabrelite_binfo.nb_cpus = machine->smp.cpus;
234
sabrelite_binfo.secure_boot = true;
235
sabrelite_binfo.write_secondary_boot = sabrelite_write_secondary;
236
sabrelite_binfo.secondary_cpu_reset_hook = sabrelite_reset_secondary;
237
diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c
238
index XXXXXXX..XXXXXXX 100644
239
--- a/hw/arm/sbsa-ref.c
240
+++ b/hw/arm/sbsa-ref.c
241
@@ -XXX,XX +XXX,XX @@ static void sbsa_ref_init(MachineState *machine)
242
create_secure_ec(secure_sysmem);
243
244
sms->bootinfo.ram_size = machine->ram_size;
245
- sms->bootinfo.nb_cpus = smp_cpus;
246
sms->bootinfo.board_id = -1;
247
sms->bootinfo.loader_start = sbsa_ref_memmap[SBSA_MEM].base;
248
sms->bootinfo.get_dtb = sbsa_ref_dtb;
249
diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c
250
index XXXXXXX..XXXXXXX 100644
251
--- a/hw/arm/vexpress.c
252
+++ b/hw/arm/vexpress.c
253
@@ -XXX,XX +XXX,XX @@ static void vexpress_common_init(MachineState *machine)
254
}
255
256
daughterboard->bootinfo.ram_size = machine->ram_size;
257
- daughterboard->bootinfo.nb_cpus = machine->smp.cpus;
258
daughterboard->bootinfo.board_id = VEXPRESS_BOARD_ID;
259
daughterboard->bootinfo.loader_start = daughterboard->loader_start;
260
daughterboard->bootinfo.smp_loader_start = map[VE_SRAM];
261
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
262
index XXXXXXX..XXXXXXX 100644
263
--- a/hw/arm/virt.c
264
+++ b/hw/arm/virt.c
265
@@ -XXX,XX +XXX,XX @@ static void machvirt_init(MachineState *machine)
266
}
267
268
vms->bootinfo.ram_size = machine->ram_size;
269
- vms->bootinfo.nb_cpus = smp_cpus;
270
vms->bootinfo.board_id = -1;
271
vms->bootinfo.loader_start = vms->memmap[VIRT_MEM].base;
272
vms->bootinfo.get_dtb = machvirt_dtb;
273
diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c
274
index XXXXXXX..XXXXXXX 100644
275
--- a/hw/arm/xilinx_zynq.c
276
+++ b/hw/arm/xilinx_zynq.c
277
@@ -XXX,XX +XXX,XX @@ static void zynq_init(MachineState *machine)
278
sysbus_mmio_map(busdev, 0, 0xF8007000);
279
280
zynq_binfo.ram_size = machine->ram_size;
281
- zynq_binfo.nb_cpus = 1;
282
zynq_binfo.board_id = 0xd32;
283
zynq_binfo.loader_start = 0;
284
zynq_binfo.board_setup_addr = BOARD_SETUP_ADDR;
39
--
285
--
40
2.7.4
286
2.25.1
41
287
42
288
diff view generated by jsdifflib
1
Fix the handling of QOM properties for PMSA CPUs with no MPU:
1
If we're using PSCI emulation, we add a /psci node to the device tree
2
we pass to the guest. At the moment, if the dtb already has a /psci
3
node in it, we retain it, rather than replacing it. (This behaviour
4
was added in commit c39770cd637765 in 2018.)
2
5
3
Allow no-MPU to be specified by either:
6
This is a problem if the existing node doesn't match our PSCI
4
* has-mpu = false
7
emulation. In particular, it might specify the wrong method (HVC vs
5
* pmsav7_dregion = 0
8
SMC), or wrong function IDs for cpu_suspend/cpu_off/etc, in which
6
and make setting one imply the other. Don't clear the PMSA
9
case the guest will not get the behaviour it wants when it makes PSCI
7
feature bit in this situation.
10
calls.
11
12
An example of this is trying to boot the highbank or midway board
13
models using the device tree supplied in the kernel sources: this
14
device tree includes a /psci node that specifies function IDs that
15
don't match the (PSCI 0.2 compliant) IDs that QEMU uses. The dtb
16
cpu_suspend function ID happens to match the PSCI 0.2 cpu_off ID, so
17
the guest hangs after booting when the kernel tries to idle the CPU
18
and instead it gets turned off.
19
20
Instead of retaining an existing /psci node, delete it entirely
21
and replace it with a node whose properties match QEMU's PSCI
22
emulation behaviour. This matches the way we handle /memory nodes,
23
where we also delete any existing nodes and write in ones that
24
match the way QEMU is going to behave.
8
25
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
26
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Reviewed-by: Alistair Francis <alistair.francis@xilinx.com>
27
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
11
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
28
Reviewed-by: Niek Linnenbank <nieklinnenbank@gmail.com>
12
Message-id: 1493122030-32191-6-git-send-email-peter.maydell@linaro.org
29
Tested-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
30
Tested-by: Cédric Le Goater <clg@kaod.org>
31
Tested-by: Niek Linnenbank <nieklinnenbank@gmail.com>
32
Message-id: 20220127154639.2090164-17-peter.maydell@linaro.org
13
---
33
---
14
target/arm/cpu.c | 8 +++++++-
34
hw/arm/boot.c | 7 ++++---
15
1 file changed, 7 insertions(+), 1 deletion(-)
35
1 file changed, 4 insertions(+), 3 deletions(-)
16
36
17
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
37
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
18
index XXXXXXX..XXXXXXX 100644
38
index XXXXXXX..XXXXXXX 100644
19
--- a/target/arm/cpu.c
39
--- a/hw/arm/boot.c
20
+++ b/target/arm/cpu.c
40
+++ b/hw/arm/boot.c
21
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
41
@@ -XXX,XX +XXX,XX @@ static void fdt_add_psci_node(void *fdt)
22
cpu->id_pfr1 &= ~0xf000;
23
}
42
}
24
43
25
+ /* MPU can be configured out of a PMSA CPU either by setting has-mpu
44
/*
26
+ * to false or by setting pmsav7-dregion to 0.
45
- * If /psci node is present in provided DTB, assume that no fixup
27
+ */
46
- * is necessary and all PSCI configuration should be taken as-is
28
if (!cpu->has_mpu) {
47
+ * A pre-existing /psci node might specify function ID values
29
- unset_feature(env, ARM_FEATURE_PMSA);
48
+ * that don't match QEMU's PSCI implementation. Delete the whole
30
+ cpu->pmsav7_dregion = 0;
49
+ * node and put our own in instead.
31
+ }
50
*/
32
+ if (cpu->pmsav7_dregion == 0) {
51
rc = fdt_path_offset(fdt, "/psci");
33
+ cpu->has_mpu = false;
52
if (rc >= 0) {
53
- return;
54
+ qemu_fdt_nop_node(fdt, "/psci");
34
}
55
}
35
56
36
if (arm_feature(env, ARM_FEATURE_PMSA) &&
57
qemu_fdt_add_subnode(fdt, "/psci");
37
--
58
--
38
2.7.4
59
2.25.1
39
60
40
61
diff view generated by jsdifflib
1
From: Kamil Rytarowski <n54@gmx.com>
1
From: "Edgar E. Iglesias" <edgar.iglesias@xilinx.com>
2
2
3
Ensure that C99 macros are defined regardless of the inclusion order of
3
Always call arm_load_kernel() regardless of kernel_filename being
4
headers in vixl. This is required at least on NetBSD.
4
set. This is needed because arm_load_kernel() sets up reset for
5
the CPUs.
5
6
6
The vixl/globals.h headers defines __STDC_CONSTANT_MACROS and must be
7
Fixes: 6f16da53ff (hw/arm: versal: Add a virtual Xilinx Versal board)
7
included before other system headers.
8
Reported-by: Peter Maydell <peter.maydell@linaro.org>
8
9
Signed-off-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
9
This file defines unconditionally the following macros, without altering
10
Message-id: 20220130110313.4045351-2-edgar.iglesias@gmail.com
10
the original sources:
11
- __STDC_CONSTANT_MACROS
12
- __STDC_LIMIT_MACROS
13
- __STDC_FORMAT_MACROS
14
15
Signed-off-by: Kamil Rytarowski <n54@gmx.com>
16
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
17
Message-id: 20170514051820.15985-1-n54@gmx.com
18
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
11
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
19
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
20
---
13
---
21
disas/libvixl/Makefile.objs | 3 +++
14
hw/arm/xlnx-versal-virt.c | 11 ++---------
22
1 file changed, 3 insertions(+)
15
1 file changed, 2 insertions(+), 9 deletions(-)
23
16
24
diff --git a/disas/libvixl/Makefile.objs b/disas/libvixl/Makefile.objs
17
diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c
25
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
26
--- a/disas/libvixl/Makefile.objs
19
--- a/hw/arm/xlnx-versal-virt.c
27
+++ b/disas/libvixl/Makefile.objs
20
+++ b/hw/arm/xlnx-versal-virt.c
28
@@ -XXX,XX +XXX,XX @@ libvixl_OBJS = vixl/utils.o \
21
@@ -XXX,XX +XXX,XX @@ static void versal_virt_init(MachineState *machine)
29
# The -Wno-sign-compare is needed only for gcc 4.6, which complains about
22
s->binfo.get_dtb = versal_virt_get_dtb;
30
# some signed-unsigned equality comparisons which later gcc versions do not.
23
s->binfo.modify_dtb = versal_virt_modify_dtb;
31
$(addprefix $(obj)/,$(libvixl_OBJS)): QEMU_CFLAGS := -I$(SRC_PATH)/disas/libvixl $(QEMU_CFLAGS) -Wno-sign-compare
24
s->binfo.psci_conduit = psci_conduit;
32
+# Ensure that C99 macros are defined regardless of the inclusion order of
25
- if (machine->kernel_filename) {
33
+# headers in vixl. This is required at least on NetBSD.
26
- arm_load_kernel(&s->soc.fpd.apu.cpu[0], machine, &s->binfo);
34
+$(addprefix $(obj)/,$(libvixl_OBJS)): QEMU_CFLAGS += -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS -D__STDC_FORMAT_MACROS
27
- } else {
35
28
- AddressSpace *as = arm_boot_address_space(&s->soc.fpd.apu.cpu[0],
36
common-obj-$(CONFIG_ARM_A64_DIS) += $(libvixl_OBJS)
29
- &s->binfo);
30
+ if (!machine->kernel_filename) {
31
/* Some boot-loaders (e.g u-boot) don't like blobs at address 0 (NULL).
32
* Offset things by 4K. */
33
s->binfo.loader_start = 0x1000;
34
s->binfo.dtb_limit = 0x1000000;
35
- if (arm_load_dtb(s->binfo.loader_start,
36
- &s->binfo, s->binfo.dtb_limit, as, machine) < 0) {
37
- exit(EXIT_FAILURE);
38
- }
39
}
40
+ arm_load_kernel(&s->soc.fpd.apu.cpu[0], machine, &s->binfo);
41
42
for (i = 0; i < XLNX_VERSAL_NUM_OSPI_FLASH; i++) {
43
BusState *spi_bus;
37
--
44
--
38
2.7.4
45
2.25.1
39
46
40
47
diff view generated by jsdifflib
1
From: Cédric Le Goater <clg@kaod.org>
1
From: Alex Bennée <alex.bennee@linaro.org>
2
2
3
The Aspeed I2C controller maintains a state machine in the command
3
The recently introduced debug tests in kvm-unit-tests exposed an error
4
register, which is mostly used for debug.
4
in our handling of singlestep cause by stale hflags. This is caught by
5
--enable-debug-tcg when running the tests.
5
6
6
Let's start adding a few states to handle abnormal STOP
7
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
7
commands. Today, the model uses the busy status of the bus as a
8
Reported-by: Andrew Jones <drjones@redhat.com>
8
condition to do so but it is not precise enough.
9
Tested-by: Andrew Jones <drjones@redhat.com>
9
10
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
Also remove the ABNORMAL bit for failing TX commands. This is
11
Message-id: 20220202122353.457084-1-alex.bennee@linaro.org
11
incorrect with respect to the specs.
12
13
Signed-off-by: Cédric Le Goater <clg@kaod.org>
14
Message-id: 1494827476-1487-4-git-send-email-clg@kaod.org
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
---
13
---
17
hw/i2c/aspeed_i2c.c | 36 +++++++++++++++++++++++++++++++++---
14
target/arm/helper-a64.c | 2 ++
18
1 file changed, 33 insertions(+), 3 deletions(-)
15
1 file changed, 2 insertions(+)
19
16
20
diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
17
diff --git a/target/arm/helper-a64.c b/target/arm/helper-a64.c
21
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
22
--- a/hw/i2c/aspeed_i2c.c
19
--- a/target/arm/helper-a64.c
23
+++ b/hw/i2c/aspeed_i2c.c
20
+++ b/target/arm/helper-a64.c
24
@@ -XXX,XX +XXX,XX @@ static uint64_t aspeed_i2c_bus_read(void *opaque, hwaddr offset,
21
@@ -XXX,XX +XXX,XX @@ void HELPER(msr_i_daifset)(CPUARMState *env, uint32_t imm)
25
}
22
{
23
daif_check(env, 0x1e, imm, GETPC());
24
env->daif |= (imm << 6) & PSTATE_DAIF;
25
+ arm_rebuild_hflags(env);
26
}
26
}
27
27
28
+static void aspeed_i2c_set_state(AspeedI2CBus *bus, uint8_t state)
28
void HELPER(msr_i_daifclear)(CPUARMState *env, uint32_t imm)
29
+{
30
+ bus->cmd &= ~(I2CD_TX_STATE_MASK << I2CD_TX_STATE_SHIFT);
31
+ bus->cmd |= (state & I2CD_TX_STATE_MASK) << I2CD_TX_STATE_SHIFT;
32
+}
33
+
34
+static uint8_t aspeed_i2c_get_state(AspeedI2CBus *bus)
35
+{
36
+ return (bus->cmd >> I2CD_TX_STATE_SHIFT) & I2CD_TX_STATE_MASK;
37
+}
38
+
39
+/*
40
+ * The state machine needs some refinement. It is only used to track
41
+ * invalid STOP commands for the moment.
42
+ */
43
static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value)
44
{
29
{
45
bus->cmd &= ~0xFFFF;
30
daif_check(env, 0x1f, imm, GETPC());
46
@@ -XXX,XX +XXX,XX @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value)
31
env->daif &= ~((imm << 6) & PSTATE_DAIF);
47
bus->intr_status = 0;
32
+ arm_rebuild_hflags(env);
48
49
if (bus->cmd & I2CD_M_START_CMD) {
50
+ uint8_t state = aspeed_i2c_get_state(bus) & I2CD_MACTIVE ?
51
+ I2CD_MSTARTR : I2CD_MSTART;
52
+
53
+ aspeed_i2c_set_state(bus, state);
54
+
55
if (i2c_start_transfer(bus->bus, extract32(bus->buf, 1, 7),
56
extract32(bus->buf, 0, 1))) {
57
bus->intr_status |= I2CD_INTR_TX_NAK;
58
@@ -XXX,XX +XXX,XX @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value)
59
if (!i2c_bus_busy(bus->bus)) {
60
return;
61
}
62
+ aspeed_i2c_set_state(bus, I2CD_MACTIVE);
63
}
64
65
if (bus->cmd & I2CD_M_TX_CMD) {
66
+ aspeed_i2c_set_state(bus, I2CD_MTXD);
67
if (i2c_send(bus->bus, bus->buf)) {
68
- bus->intr_status |= (I2CD_INTR_TX_NAK | I2CD_INTR_ABNORMAL);
69
+ bus->intr_status |= (I2CD_INTR_TX_NAK);
70
i2c_end_transfer(bus->bus);
71
} else {
72
bus->intr_status |= I2CD_INTR_TX_ACK;
73
}
74
bus->cmd &= ~I2CD_M_TX_CMD;
75
+ aspeed_i2c_set_state(bus, I2CD_MACTIVE);
76
}
77
78
if (bus->cmd & (I2CD_M_RX_CMD | I2CD_M_S_RX_CMD_LAST)) {
79
- int ret = i2c_recv(bus->bus);
80
+ int ret;
81
+
82
+ aspeed_i2c_set_state(bus, I2CD_MRXD);
83
+ ret = i2c_recv(bus->bus);
84
if (ret < 0) {
85
qemu_log_mask(LOG_GUEST_ERROR, "%s: read failed\n", __func__);
86
ret = 0xff;
87
@@ -XXX,XX +XXX,XX @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value)
88
i2c_nack(bus->bus);
89
}
90
bus->cmd &= ~(I2CD_M_RX_CMD | I2CD_M_S_RX_CMD_LAST);
91
+ aspeed_i2c_set_state(bus, I2CD_MACTIVE);
92
}
93
94
if (bus->cmd & I2CD_M_STOP_CMD) {
95
- if (!i2c_bus_busy(bus->bus)) {
96
+ if (!(aspeed_i2c_get_state(bus) & I2CD_MACTIVE)) {
97
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: abnormal stop\n", __func__);
98
bus->intr_status |= I2CD_INTR_ABNORMAL;
99
} else {
100
+ aspeed_i2c_set_state(bus, I2CD_MSTOP);
101
i2c_end_transfer(bus->bus);
102
bus->intr_status |= I2CD_INTR_NORMAL_STOP;
103
}
104
bus->cmd &= ~I2CD_M_STOP_CMD;
105
+ aspeed_i2c_set_state(bus, I2CD_IDLE);
106
}
107
}
33
}
108
34
35
/* Convert a softfloat float_relation_ (as returned by
109
--
36
--
110
2.7.4
37
2.25.1
111
38
112
39
diff view generated by jsdifflib
1
From: Michael Davidsaver <mdavidsaver@gmail.com>
1
From: Richard Petri <git@rpls.de>
2
2
3
The M series MPU is almost the same as the already implemented R
3
Starting the SysTick timer and changing the clock source a the same time
4
profile MPU (v7 PMSA). So all we need to implement here is the MPU
4
will result in an error, if the previous clock period was zero. For exmaple,
5
register interface in the system register space.
5
on the mps2-tz platforms, no refclk is present. Right after reset, the
6
configured ptimer period is zero, and trying to enabling it will turn it off
7
right away. E.g., code running on the platform setting
6
8
7
This implementation has the same restriction as the R profile MPU
9
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk;
8
that it doesn't permit regions to be sized down smaller than 1K.
9
10
10
We also do not yet implement support for MPU_CTRL.HFNMIENA; this
11
should change the clock source and enable the timer on real hardware, but
11
bit should if zero disable use of the MPU when running HardFault,
12
resulted in an error in qemu.
12
NMI or with FAULTMASK set to 1 (ie at an execution priority of
13
less than zero) -- if the MPU is enabled we don't treat these
14
cases any differently.
15
13
16
Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
14
Signed-off-by: Richard Petri <git@rpls.de>
17
Message-id: 1493122030-32191-13-git-send-email-peter.maydell@linaro.org
15
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
18
[PMM: Keep all the bits in mpu_ctrl field, rather than
16
Message-id: 20220201192650.289584-1-git@rpls.de
19
using SCTLR bits for them; drop broken HFNMIENA support;
20
various cleanup]
21
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
17
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
22
---
18
---
23
target/arm/cpu.h | 6 +++
19
hw/timer/armv7m_systick.c | 8 ++++----
24
hw/intc/armv7m_nvic.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++
20
1 file changed, 4 insertions(+), 4 deletions(-)
25
target/arm/helper.c | 25 +++++++++++-
26
target/arm/machine.c | 5 ++-
27
4 files changed, 137 insertions(+), 3 deletions(-)
28
21
29
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
22
diff --git a/hw/timer/armv7m_systick.c b/hw/timer/armv7m_systick.c
30
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
31
--- a/target/arm/cpu.h
24
--- a/hw/timer/armv7m_systick.c
32
+++ b/target/arm/cpu.h
25
+++ b/hw/timer/armv7m_systick.c
33
@@ -XXX,XX +XXX,XX @@ typedef struct CPUARMState {
26
@@ -XXX,XX +XXX,XX @@ static MemTxResult systick_write(void *opaque, hwaddr addr,
34
uint32_t dfsr; /* Debug Fault Status Register */
27
s->control &= 0xfffffff8;
35
uint32_t mmfar; /* MemManage Fault Address */
28
s->control |= value & 7;
36
uint32_t bfar; /* BusFault Address */
29
37
+ unsigned mpu_ctrl; /* MPU_CTRL (some bits kept in sctlr_el[1]) */
30
+ if ((oldval ^ value) & SYSTICK_CLKSOURCE) {
38
int exception;
31
+ systick_set_period_from_clock(s);
39
} v7m;
40
41
@@ -XXX,XX +XXX,XX @@ FIELD(V7M_DFSR, DWTTRAP, 2, 1)
42
FIELD(V7M_DFSR, VCATCH, 3, 1)
43
FIELD(V7M_DFSR, EXTERNAL, 4, 1)
44
45
+/* v7M MPU_CTRL bits */
46
+FIELD(V7M_MPU_CTRL, ENABLE, 0, 1)
47
+FIELD(V7M_MPU_CTRL, HFNMIENA, 1, 1)
48
+FIELD(V7M_MPU_CTRL, PRIVDEFENA, 2, 1)
49
+
50
/* If adding a feature bit which corresponds to a Linux ELF
51
* HWCAP bit, remember to update the feature-bit-to-hwcap
52
* mapping in linux-user/elfload.c:get_elf_hwcap().
53
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
54
index XXXXXXX..XXXXXXX 100644
55
--- a/hw/intc/armv7m_nvic.c
56
+++ b/hw/intc/armv7m_nvic.c
57
@@ -XXX,XX +XXX,XX @@
58
#include "hw/arm/arm.h"
59
#include "hw/arm/armv7m_nvic.h"
60
#include "target/arm/cpu.h"
61
+#include "exec/exec-all.h"
62
#include "qemu/log.h"
63
#include "trace.h"
64
65
@@ -XXX,XX +XXX,XX @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset)
66
case 0xd70: /* ISAR4. */
67
return 0x01310102;
68
/* TODO: Implement debug registers. */
69
+ case 0xd90: /* MPU_TYPE */
70
+ /* Unified MPU; if the MPU is not present this value is zero */
71
+ return cpu->pmsav7_dregion << 8;
72
+ break;
73
+ case 0xd94: /* MPU_CTRL */
74
+ return cpu->env.v7m.mpu_ctrl;
75
+ case 0xd98: /* MPU_RNR */
76
+ return cpu->env.cp15.c6_rgnr;
77
+ case 0xd9c: /* MPU_RBAR */
78
+ case 0xda4: /* MPU_RBAR_A1 */
79
+ case 0xdac: /* MPU_RBAR_A2 */
80
+ case 0xdb4: /* MPU_RBAR_A3 */
81
+ {
82
+ int region = cpu->env.cp15.c6_rgnr;
83
+
84
+ if (region >= cpu->pmsav7_dregion) {
85
+ return 0;
86
+ }
87
+ return (cpu->env.pmsav7.drbar[region] & 0x1f) | (region & 0xf);
88
+ }
89
+ case 0xda0: /* MPU_RASR */
90
+ case 0xda8: /* MPU_RASR_A1 */
91
+ case 0xdb0: /* MPU_RASR_A2 */
92
+ case 0xdb8: /* MPU_RASR_A3 */
93
+ {
94
+ int region = cpu->env.cp15.c6_rgnr;
95
+
96
+ if (region >= cpu->pmsav7_dregion) {
97
+ return 0;
98
+ }
99
+ return ((cpu->env.pmsav7.dracr[region] & 0xffff) << 16) |
100
+ (cpu->env.pmsav7.drsr[region] & 0xffff);
101
+ }
102
default:
103
qemu_log_mask(LOG_GUEST_ERROR, "NVIC: Bad read offset 0x%x\n", offset);
104
return 0;
105
@@ -XXX,XX +XXX,XX @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value)
106
qemu_log_mask(LOG_UNIMP,
107
"NVIC: Aux fault status registers unimplemented\n");
108
break;
109
+ case 0xd90: /* MPU_TYPE */
110
+ return; /* RO */
111
+ case 0xd94: /* MPU_CTRL */
112
+ if ((value &
113
+ (R_V7M_MPU_CTRL_HFNMIENA_MASK | R_V7M_MPU_CTRL_ENABLE_MASK))
114
+ == R_V7M_MPU_CTRL_HFNMIENA_MASK) {
115
+ qemu_log_mask(LOG_GUEST_ERROR, "MPU_CTRL: HFNMIENA and !ENABLE is "
116
+ "UNPREDICTABLE\n");
117
+ }
118
+ cpu->env.v7m.mpu_ctrl = value & (R_V7M_MPU_CTRL_ENABLE_MASK |
119
+ R_V7M_MPU_CTRL_HFNMIENA_MASK |
120
+ R_V7M_MPU_CTRL_PRIVDEFENA_MASK);
121
+ tlb_flush(CPU(cpu));
122
+ break;
123
+ case 0xd98: /* MPU_RNR */
124
+ if (value >= cpu->pmsav7_dregion) {
125
+ qemu_log_mask(LOG_GUEST_ERROR, "MPU region out of range %"
126
+ PRIu32 "/%" PRIu32 "\n",
127
+ value, cpu->pmsav7_dregion);
128
+ } else {
129
+ cpu->env.cp15.c6_rgnr = value;
130
+ }
131
+ break;
132
+ case 0xd9c: /* MPU_RBAR */
133
+ case 0xda4: /* MPU_RBAR_A1 */
134
+ case 0xdac: /* MPU_RBAR_A2 */
135
+ case 0xdb4: /* MPU_RBAR_A3 */
136
+ {
137
+ int region;
138
+
139
+ if (value & (1 << 4)) {
140
+ /* VALID bit means use the region number specified in this
141
+ * value and also update MPU_RNR.REGION with that value.
142
+ */
143
+ region = extract32(value, 0, 4);
144
+ if (region >= cpu->pmsav7_dregion) {
145
+ qemu_log_mask(LOG_GUEST_ERROR,
146
+ "MPU region out of range %u/%" PRIu32 "\n",
147
+ region, cpu->pmsav7_dregion);
148
+ return;
149
+ }
150
+ cpu->env.cp15.c6_rgnr = region;
151
+ } else {
152
+ region = cpu->env.cp15.c6_rgnr;
153
+ }
32
+ }
154
+
33
+
155
+ if (region >= cpu->pmsav7_dregion) {
34
if ((oldval ^ value) & SYSTICK_ENABLE) {
156
+ return;
35
if (value & SYSTICK_ENABLE) {
157
+ }
36
ptimer_run(s->ptimer, 0);
158
+
37
@@ -XXX,XX +XXX,XX @@ static MemTxResult systick_write(void *opaque, hwaddr addr,
159
+ cpu->env.pmsav7.drbar[region] = value & ~0x1f;
38
ptimer_stop(s->ptimer);
160
+ tlb_flush(CPU(cpu));
39
}
161
+ break;
162
+ }
163
+ case 0xda0: /* MPU_RASR */
164
+ case 0xda8: /* MPU_RASR_A1 */
165
+ case 0xdb0: /* MPU_RASR_A2 */
166
+ case 0xdb8: /* MPU_RASR_A3 */
167
+ {
168
+ int region = cpu->env.cp15.c6_rgnr;
169
+
170
+ if (region >= cpu->pmsav7_dregion) {
171
+ return;
172
+ }
173
+
174
+ cpu->env.pmsav7.drsr[region] = value & 0xff3f;
175
+ cpu->env.pmsav7.dracr[region] = (value >> 16) & 0x173f;
176
+ tlb_flush(CPU(cpu));
177
+ break;
178
+ }
179
case 0xf00: /* Software Triggered Interrupt Register */
180
{
181
/* user mode can only write to STIR if CCR.USERSETMPEND permits it */
182
diff --git a/target/arm/helper.c b/target/arm/helper.c
183
index XXXXXXX..XXXXXXX 100644
184
--- a/target/arm/helper.c
185
+++ b/target/arm/helper.c
186
@@ -XXX,XX +XXX,XX @@ static inline uint32_t regime_sctlr(CPUARMState *env, ARMMMUIdx mmu_idx)
187
static inline bool regime_translation_disabled(CPUARMState *env,
188
ARMMMUIdx mmu_idx)
189
{
190
+ if (arm_feature(env, ARM_FEATURE_M)) {
191
+ return !(env->v7m.mpu_ctrl & R_V7M_MPU_CTRL_ENABLE_MASK);
192
+ }
193
+
194
if (mmu_idx == ARMMMUIdx_S2NS) {
195
return (env->cp15.hcr_el2 & HCR_VM) == 0;
196
}
197
@@ -XXX,XX +XXX,XX @@ static inline void get_phys_addr_pmsav7_default(CPUARMState *env,
198
}
199
}
200
201
+static bool pmsav7_use_background_region(ARMCPU *cpu,
202
+ ARMMMUIdx mmu_idx, bool is_user)
203
+{
204
+ /* Return true if we should use the default memory map as a
205
+ * "background" region if there are no hits against any MPU regions.
206
+ */
207
+ CPUARMState *env = &cpu->env;
208
+
209
+ if (is_user) {
210
+ return false;
211
+ }
212
+
213
+ if (arm_feature(env, ARM_FEATURE_M)) {
214
+ return env->v7m.mpu_ctrl & R_V7M_MPU_CTRL_PRIVDEFENA_MASK;
215
+ } else {
216
+ return regime_sctlr(env, mmu_idx) & SCTLR_BR;
217
+ }
218
+}
219
+
220
static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address,
221
int access_type, ARMMMUIdx mmu_idx,
222
hwaddr *phys_ptr, int *prot, uint32_t *fsr)
223
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address,
224
}
40
}
225
41
-
226
if (n == -1) { /* no hits */
42
- if ((oldval ^ value) & SYSTICK_CLKSOURCE) {
227
- if (is_user || !(regime_sctlr(env, mmu_idx) & SCTLR_BR)) {
43
- systick_set_period_from_clock(s);
228
+ if (!pmsav7_use_background_region(cpu, mmu_idx, is_user)) {
44
- }
229
/* background fault */
45
ptimer_transaction_commit(s->ptimer);
230
*fsr = 0;
46
break;
231
return true;
232
diff --git a/target/arm/machine.c b/target/arm/machine.c
233
index XXXXXXX..XXXXXXX 100644
234
--- a/target/arm/machine.c
235
+++ b/target/arm/machine.c
236
@@ -XXX,XX +XXX,XX @@ static bool m_needed(void *opaque)
237
238
static const VMStateDescription vmstate_m = {
239
.name = "cpu/m",
240
- .version_id = 3,
241
- .minimum_version_id = 3,
242
+ .version_id = 4,
243
+ .minimum_version_id = 4,
244
.needed = m_needed,
245
.fields = (VMStateField[]) {
246
VMSTATE_UINT32(env.v7m.vecbase, ARMCPU),
247
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_m = {
248
VMSTATE_UINT32(env.v7m.dfsr, ARMCPU),
249
VMSTATE_UINT32(env.v7m.mmfar, ARMCPU),
250
VMSTATE_UINT32(env.v7m.bfar, ARMCPU),
251
+ VMSTATE_UINT32(env.v7m.mpu_ctrl, ARMCPU),
252
VMSTATE_INT32(env.v7m.exception, ARMCPU),
253
VMSTATE_END_OF_LIST()
254
}
47
}
255
--
48
--
256
2.7.4
49
2.25.1
257
50
258
51
diff view generated by jsdifflib
1
From: Cédric Le Goater <clg@kaod.org>
1
From: Eric Auger <eric.auger@redhat.com>
2
2
3
Multiple I2C commands can be fired simultaneously and the controller
3
We currently miss a bunch of register resets in the device reset
4
execute the commands following these priorities:
4
function. This sometimes prevents the guest from rebooting after
5
a system_reset (with virtio-blk-pci). For instance, we may get
6
the following errors:
5
7
6
(1) Master Start Command
8
invalid STE
7
(2) Master Transmit Command
9
smmuv3-iommu-memory-region-0-0 translation failed for iova=0x13a9d2000(SMMU_EVT_C_BAD_STE)
8
(3) Slave Transmit Command or Master Receive Command
10
Invalid read at addr 0x13A9D2000, size 2, region '(null)', reason: rejected
9
(4) Master Stop Command
11
invalid STE
12
smmuv3-iommu-memory-region-0-0 translation failed for iova=0x13a9d2000(SMMU_EVT_C_BAD_STE)
13
Invalid write at addr 0x13A9D2000, size 2, region '(null)', reason: rejected
14
invalid STE
10
15
11
The current code is incorrect with respect to the above sequence and
16
Signed-off-by: Eric Auger <eric.auger@redhat.com>
12
needs to be reworked to handle each individual command.
17
Message-id: 20220202111602.627429-1-eric.auger@redhat.com
13
18
Fixes: 10a83cb988 ("hw/arm/smmuv3: Skeleton")
14
Signed-off-by: Cédric Le Goater <clg@kaod.org>
19
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
15
Message-id: 1494827476-1487-2-git-send-email-clg@kaod.org
16
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
20
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
17
---
21
---
18
hw/i2c/aspeed_i2c.c | 24 ++++++++++++++++++------
22
hw/arm/smmuv3.c | 6 ++++++
19
1 file changed, 18 insertions(+), 6 deletions(-)
23
1 file changed, 6 insertions(+)
20
24
21
diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
25
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
22
index XXXXXXX..XXXXXXX 100644
26
index XXXXXXX..XXXXXXX 100644
23
--- a/hw/i2c/aspeed_i2c.c
27
--- a/hw/arm/smmuv3.c
24
+++ b/hw/i2c/aspeed_i2c.c
28
+++ b/hw/arm/smmuv3.c
25
@@ -XXX,XX +XXX,XX @@ static uint64_t aspeed_i2c_bus_read(void *opaque, hwaddr offset,
29
@@ -XXX,XX +XXX,XX @@ static void smmuv3_init_regs(SMMUv3State *s)
26
30
s->features = 0;
27
static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value)
31
s->sid_split = 0;
28
{
32
s->aidr = 0x1;
29
+ bus->cmd &= ~0xFFFF;
33
+ s->cr[0] = 0;
30
bus->cmd |= value & 0xFFFF;
34
+ s->cr0ack = 0;
31
bus->intr_status = 0;
35
+ s->irq_ctrl = 0;
32
36
+ s->gerror = 0;
33
@@ -XXX,XX +XXX,XX @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value)
37
+ s->gerrorn = 0;
34
bus->intr_status |= I2CD_INTR_TX_ACK;
38
+ s->statusr = 0;
35
}
36
37
- } else if (bus->cmd & I2CD_M_TX_CMD) {
38
+ /* START command is also a TX command, as the slave address is
39
+ * sent on the bus */
40
+ bus->cmd &= ~(I2CD_M_START_CMD | I2CD_M_TX_CMD);
41
+
42
+ /* No slave found */
43
+ if (!i2c_bus_busy(bus->bus)) {
44
+ return;
45
+ }
46
+ }
47
+
48
+ if (bus->cmd & I2CD_M_TX_CMD) {
49
if (i2c_send(bus->bus, bus->buf)) {
50
bus->intr_status |= (I2CD_INTR_TX_NAK | I2CD_INTR_ABNORMAL);
51
i2c_end_transfer(bus->bus);
52
} else {
53
bus->intr_status |= I2CD_INTR_TX_ACK;
54
}
55
+ bus->cmd &= ~I2CD_M_TX_CMD;
56
+ }
57
58
- } else if (bus->cmd & I2CD_M_RX_CMD) {
59
+ if (bus->cmd & I2CD_M_RX_CMD) {
60
int ret = i2c_recv(bus->bus);
61
if (ret < 0) {
62
qemu_log_mask(LOG_GUEST_ERROR, "%s: read failed\n", __func__);
63
@@ -XXX,XX +XXX,XX @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value)
64
bus->intr_status |= I2CD_INTR_RX_DONE;
65
}
66
bus->buf = (ret & I2CD_BYTE_BUF_RX_MASK) << I2CD_BYTE_BUF_RX_SHIFT;
67
+ bus->cmd &= ~I2CD_M_RX_CMD;
68
}
69
70
if (bus->cmd & (I2CD_M_STOP_CMD | I2CD_M_S_RX_CMD_LAST)) {
71
@@ -XXX,XX +XXX,XX @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value)
72
i2c_end_transfer(bus->bus);
73
bus->intr_status |= I2CD_INTR_NORMAL_STOP;
74
}
75
+ bus->cmd &= ~I2CD_M_STOP_CMD;
76
}
77
-
78
- /* command is handled, reset it and check for interrupts */
79
- bus->cmd &= ~0xFFFF;
80
- aspeed_i2c_bus_raise_interrupt(bus);
81
}
39
}
82
40
83
static void aspeed_i2c_bus_write(void *opaque, hwaddr offset,
41
static int smmu_get_ste(SMMUv3State *s, dma_addr_t addr, STE *buf,
84
@@ -XXX,XX +XXX,XX @@ static void aspeed_i2c_bus_write(void *opaque, hwaddr offset,
85
}
86
87
aspeed_i2c_bus_handle_cmd(bus, value);
88
+ aspeed_i2c_bus_raise_interrupt(bus);
89
break;
90
91
default:
92
--
42
--
93
2.7.4
43
2.25.1
94
44
95
45
diff view generated by jsdifflib
New patch
1
1
Currently the ITS accesses each 8-byte doubleword in a 4-doubleword
2
command packet with a separate address_space_ldq_le() call. This is
3
awkward because the individual command processing functions have
4
ended up with code to handle "load more doublewords out of the
5
packet", which is both unwieldy and also a potential source of bugs
6
because it's not obvious when looking at a line that pulls a field
7
out of the 'value' variable which of the 4 doublewords that variable
8
currently holds.
9
10
Switch to using address_space_map() to map the whole command packet
11
at once and fish the four doublewords out of it. Then each process_*
12
function can start with a few lines of code that extract the fields
13
it cares about.
14
15
This requires us to split out the guts of process_its_cmd() into a
16
new do_process_its_cmd(), because we were previously overloading the
17
value and offset arguments as a backdoor way to directly pass the
18
devid and eventid from a write to GITS_TRANSLATER. The new
19
do_process_its_cmd() takes those arguments directly, and
20
process_its_cmd() is just a wrapper that does the "read fields from
21
command packet" part.
22
23
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
24
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
25
Message-id: 20220201193207.2771604-2-peter.maydell@linaro.org
26
---
27
hw/intc/gicv3_internal.h | 4 +-
28
hw/intc/arm_gicv3_its.c | 208 +++++++++++----------------------------
29
2 files changed, 62 insertions(+), 150 deletions(-)
30
31
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
32
index XXXXXXX..XXXXXXX 100644
33
--- a/hw/intc/gicv3_internal.h
34
+++ b/hw/intc/gicv3_internal.h
35
@@ -XXX,XX +XXX,XX @@ FIELD(GITS_TYPER, CIL, 36, 1)
36
#define LPI_CTE_ENABLED TABLE_ENTRY_VALID_MASK
37
#define LPI_PRIORITY_MASK 0xfc
38
39
-#define GITS_CMDQ_ENTRY_SIZE 32
40
-#define NUM_BYTES_IN_DW 8
41
+#define GITS_CMDQ_ENTRY_WORDS 4
42
+#define GITS_CMDQ_ENTRY_SIZE (GITS_CMDQ_ENTRY_WORDS * sizeof(uint64_t))
43
44
#define CMD_MASK 0xff
45
46
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
47
index XXXXXXX..XXXXXXX 100644
48
--- a/hw/intc/arm_gicv3_its.c
49
+++ b/hw/intc/arm_gicv3_its.c
50
@@ -XXX,XX +XXX,XX @@ static uint64_t get_dte(GICv3ITSState *s, uint32_t devid, MemTxResult *res)
51
* 3. handling of ITS CLEAR command
52
* 4. handling of ITS DISCARD command
53
*/
54
-static ItsCmdResult process_its_cmd(GICv3ITSState *s, uint64_t value,
55
- uint32_t offset, ItsCmdType cmd)
56
+static ItsCmdResult do_process_its_cmd(GICv3ITSState *s, uint32_t devid,
57
+ uint32_t eventid, ItsCmdType cmd)
58
{
59
- AddressSpace *as = &s->gicv3->dma_as;
60
- uint32_t devid, eventid;
61
MemTxResult res = MEMTX_OK;
62
bool dte_valid;
63
uint64_t dte = 0;
64
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_its_cmd(GICv3ITSState *s, uint64_t value,
65
bool cte_valid = false;
66
uint64_t rdbase;
67
68
- if (cmd == NONE) {
69
- devid = offset;
70
- } else {
71
- devid = ((value & DEVID_MASK) >> DEVID_SHIFT);
72
-
73
- offset += NUM_BYTES_IN_DW;
74
- value = address_space_ldq_le(as, s->cq.base_addr + offset,
75
- MEMTXATTRS_UNSPECIFIED, &res);
76
- }
77
-
78
- if (res != MEMTX_OK) {
79
- return CMD_STALL;
80
- }
81
-
82
- eventid = (value & EVENTID_MASK);
83
-
84
if (devid >= s->dt.num_entries) {
85
qemu_log_mask(LOG_GUEST_ERROR,
86
"%s: invalid command attributes: devid %d>=%d",
87
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_its_cmd(GICv3ITSState *s, uint64_t value,
88
}
89
return CMD_CONTINUE;
90
}
91
-
92
-static ItsCmdResult process_mapti(GICv3ITSState *s, uint64_t value,
93
- uint32_t offset, bool ignore_pInt)
94
+static ItsCmdResult process_its_cmd(GICv3ITSState *s, const uint64_t *cmdpkt,
95
+ ItsCmdType cmd)
96
+{
97
+ uint32_t devid, eventid;
98
+
99
+ devid = (cmdpkt[0] & DEVID_MASK) >> DEVID_SHIFT;
100
+ eventid = cmdpkt[1] & EVENTID_MASK;
101
+ return do_process_its_cmd(s, devid, eventid, cmd);
102
+}
103
+
104
+static ItsCmdResult process_mapti(GICv3ITSState *s, const uint64_t *cmdpkt,
105
+ bool ignore_pInt)
106
{
107
- AddressSpace *as = &s->gicv3->dma_as;
108
uint32_t devid, eventid;
109
uint32_t pIntid = 0;
110
uint64_t num_eventids;
111
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_mapti(GICv3ITSState *s, uint64_t value,
112
uint64_t dte = 0;
113
IteEntry ite = {};
114
115
- devid = ((value & DEVID_MASK) >> DEVID_SHIFT);
116
- offset += NUM_BYTES_IN_DW;
117
- value = address_space_ldq_le(as, s->cq.base_addr + offset,
118
- MEMTXATTRS_UNSPECIFIED, &res);
119
-
120
- if (res != MEMTX_OK) {
121
- return CMD_STALL;
122
- }
123
-
124
- eventid = (value & EVENTID_MASK);
125
+ devid = (cmdpkt[0] & DEVID_MASK) >> DEVID_SHIFT;
126
+ eventid = cmdpkt[1] & EVENTID_MASK;
127
128
if (ignore_pInt) {
129
pIntid = eventid;
130
} else {
131
- pIntid = ((value & pINTID_MASK) >> pINTID_SHIFT);
132
+ pIntid = (cmdpkt[1] & pINTID_MASK) >> pINTID_SHIFT;
133
}
134
135
- offset += NUM_BYTES_IN_DW;
136
- value = address_space_ldq_le(as, s->cq.base_addr + offset,
137
- MEMTXATTRS_UNSPECIFIED, &res);
138
-
139
- if (res != MEMTX_OK) {
140
- return CMD_STALL;
141
- }
142
-
143
- icid = value & ICID_MASK;
144
+ icid = cmdpkt[2] & ICID_MASK;
145
146
if (devid >= s->dt.num_entries) {
147
qemu_log_mask(LOG_GUEST_ERROR,
148
@@ -XXX,XX +XXX,XX @@ static bool update_cte(GICv3ITSState *s, uint16_t icid, bool valid,
149
return res == MEMTX_OK;
150
}
151
152
-static ItsCmdResult process_mapc(GICv3ITSState *s, uint32_t offset)
153
+static ItsCmdResult process_mapc(GICv3ITSState *s, const uint64_t *cmdpkt)
154
{
155
- AddressSpace *as = &s->gicv3->dma_as;
156
uint16_t icid;
157
uint64_t rdbase;
158
bool valid;
159
- MemTxResult res = MEMTX_OK;
160
- uint64_t value;
161
162
- offset += NUM_BYTES_IN_DW;
163
- offset += NUM_BYTES_IN_DW;
164
+ icid = cmdpkt[2] & ICID_MASK;
165
166
- value = address_space_ldq_le(as, s->cq.base_addr + offset,
167
- MEMTXATTRS_UNSPECIFIED, &res);
168
-
169
- if (res != MEMTX_OK) {
170
- return CMD_STALL;
171
- }
172
-
173
- icid = value & ICID_MASK;
174
-
175
- rdbase = (value & R_MAPC_RDBASE_MASK) >> R_MAPC_RDBASE_SHIFT;
176
+ rdbase = (cmdpkt[2] & R_MAPC_RDBASE_MASK) >> R_MAPC_RDBASE_SHIFT;
177
rdbase &= RDBASE_PROCNUM_MASK;
178
179
- valid = (value & CMD_FIELD_VALID_MASK);
180
+ valid = cmdpkt[2] & CMD_FIELD_VALID_MASK;
181
182
if ((icid >= s->ct.num_entries) || (rdbase >= s->gicv3->num_cpu)) {
183
qemu_log_mask(LOG_GUEST_ERROR,
184
@@ -XXX,XX +XXX,XX @@ static bool update_dte(GICv3ITSState *s, uint32_t devid, bool valid,
185
return res == MEMTX_OK;
186
}
187
188
-static ItsCmdResult process_mapd(GICv3ITSState *s, uint64_t value,
189
- uint32_t offset)
190
+static ItsCmdResult process_mapd(GICv3ITSState *s, const uint64_t *cmdpkt)
191
{
192
- AddressSpace *as = &s->gicv3->dma_as;
193
uint32_t devid;
194
uint8_t size;
195
uint64_t itt_addr;
196
bool valid;
197
- MemTxResult res = MEMTX_OK;
198
199
- devid = ((value & DEVID_MASK) >> DEVID_SHIFT);
200
-
201
- offset += NUM_BYTES_IN_DW;
202
- value = address_space_ldq_le(as, s->cq.base_addr + offset,
203
- MEMTXATTRS_UNSPECIFIED, &res);
204
-
205
- if (res != MEMTX_OK) {
206
- return CMD_STALL;
207
- }
208
-
209
- size = (value & SIZE_MASK);
210
-
211
- offset += NUM_BYTES_IN_DW;
212
- value = address_space_ldq_le(as, s->cq.base_addr + offset,
213
- MEMTXATTRS_UNSPECIFIED, &res);
214
-
215
- if (res != MEMTX_OK) {
216
- return CMD_STALL;
217
- }
218
-
219
- itt_addr = (value & ITTADDR_MASK) >> ITTADDR_SHIFT;
220
-
221
- valid = (value & CMD_FIELD_VALID_MASK);
222
+ devid = (cmdpkt[0] & DEVID_MASK) >> DEVID_SHIFT;
223
+ size = cmdpkt[1] & SIZE_MASK;
224
+ itt_addr = (cmdpkt[2] & ITTADDR_MASK) >> ITTADDR_SHIFT;
225
+ valid = cmdpkt[2] & CMD_FIELD_VALID_MASK;
226
227
if ((devid >= s->dt.num_entries) ||
228
(size > FIELD_EX64(s->typer, GITS_TYPER, IDBITS))) {
229
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_mapd(GICv3ITSState *s, uint64_t value,
230
return update_dte(s, devid, valid, size, itt_addr) ? CMD_CONTINUE : CMD_STALL;
231
}
232
233
-static ItsCmdResult process_movall(GICv3ITSState *s, uint64_t value,
234
- uint32_t offset)
235
+static ItsCmdResult process_movall(GICv3ITSState *s, const uint64_t *cmdpkt)
236
{
237
- AddressSpace *as = &s->gicv3->dma_as;
238
- MemTxResult res = MEMTX_OK;
239
uint64_t rd1, rd2;
240
241
- /* No fields in dwords 0 or 1 */
242
- offset += NUM_BYTES_IN_DW;
243
- offset += NUM_BYTES_IN_DW;
244
- value = address_space_ldq_le(as, s->cq.base_addr + offset,
245
- MEMTXATTRS_UNSPECIFIED, &res);
246
- if (res != MEMTX_OK) {
247
- return CMD_STALL;
248
- }
249
+ rd1 = FIELD_EX64(cmdpkt[2], MOVALL_2, RDBASE1);
250
+ rd2 = FIELD_EX64(cmdpkt[3], MOVALL_3, RDBASE2);
251
252
- rd1 = FIELD_EX64(value, MOVALL_2, RDBASE1);
253
if (rd1 >= s->gicv3->num_cpu) {
254
qemu_log_mask(LOG_GUEST_ERROR,
255
"%s: RDBASE1 %" PRId64
256
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_movall(GICv3ITSState *s, uint64_t value,
257
__func__, rd1, s->gicv3->num_cpu);
258
return CMD_CONTINUE;
259
}
260
-
261
- offset += NUM_BYTES_IN_DW;
262
- value = address_space_ldq_le(as, s->cq.base_addr + offset,
263
- MEMTXATTRS_UNSPECIFIED, &res);
264
- if (res != MEMTX_OK) {
265
- return CMD_STALL;
266
- }
267
-
268
- rd2 = FIELD_EX64(value, MOVALL_3, RDBASE2);
269
if (rd2 >= s->gicv3->num_cpu) {
270
qemu_log_mask(LOG_GUEST_ERROR,
271
"%s: RDBASE2 %" PRId64
272
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_movall(GICv3ITSState *s, uint64_t value,
273
return CMD_CONTINUE;
274
}
275
276
-static ItsCmdResult process_movi(GICv3ITSState *s, uint64_t value,
277
- uint32_t offset)
278
+static ItsCmdResult process_movi(GICv3ITSState *s, const uint64_t *cmdpkt)
279
{
280
- AddressSpace *as = &s->gicv3->dma_as;
281
MemTxResult res = MEMTX_OK;
282
uint32_t devid, eventid, intid;
283
uint16_t old_icid, new_icid;
284
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_movi(GICv3ITSState *s, uint64_t value,
285
uint64_t num_eventids;
286
IteEntry ite = {};
287
288
- devid = FIELD_EX64(value, MOVI_0, DEVICEID);
289
-
290
- offset += NUM_BYTES_IN_DW;
291
- value = address_space_ldq_le(as, s->cq.base_addr + offset,
292
- MEMTXATTRS_UNSPECIFIED, &res);
293
- if (res != MEMTX_OK) {
294
- return CMD_STALL;
295
- }
296
- eventid = FIELD_EX64(value, MOVI_1, EVENTID);
297
-
298
- offset += NUM_BYTES_IN_DW;
299
- value = address_space_ldq_le(as, s->cq.base_addr + offset,
300
- MEMTXATTRS_UNSPECIFIED, &res);
301
- if (res != MEMTX_OK) {
302
- return CMD_STALL;
303
- }
304
- new_icid = FIELD_EX64(value, MOVI_2, ICID);
305
+ devid = FIELD_EX64(cmdpkt[0], MOVI_0, DEVICEID);
306
+ eventid = FIELD_EX64(cmdpkt[1], MOVI_1, EVENTID);
307
+ new_icid = FIELD_EX64(cmdpkt[2], MOVI_2, ICID);
308
309
if (devid >= s->dt.num_entries) {
310
qemu_log_mask(LOG_GUEST_ERROR,
311
@@ -XXX,XX +XXX,XX @@ static void process_cmdq(GICv3ITSState *s)
312
uint32_t wr_offset = 0;
313
uint32_t rd_offset = 0;
314
uint32_t cq_offset = 0;
315
- uint64_t data;
316
AddressSpace *as = &s->gicv3->dma_as;
317
- MemTxResult res = MEMTX_OK;
318
uint8_t cmd;
319
int i;
320
321
@@ -XXX,XX +XXX,XX @@ static void process_cmdq(GICv3ITSState *s)
322
323
while (wr_offset != rd_offset) {
324
ItsCmdResult result = CMD_CONTINUE;
325
+ void *hostmem;
326
+ hwaddr buflen;
327
+ uint64_t cmdpkt[GITS_CMDQ_ENTRY_WORDS];
328
329
cq_offset = (rd_offset * GITS_CMDQ_ENTRY_SIZE);
330
- data = address_space_ldq_le(as, s->cq.base_addr + cq_offset,
331
- MEMTXATTRS_UNSPECIFIED, &res);
332
- if (res != MEMTX_OK) {
333
+
334
+ buflen = GITS_CMDQ_ENTRY_SIZE;
335
+ hostmem = address_space_map(as, s->cq.base_addr + cq_offset,
336
+ &buflen, false, MEMTXATTRS_UNSPECIFIED);
337
+ if (!hostmem || buflen != GITS_CMDQ_ENTRY_SIZE) {
338
+ if (hostmem) {
339
+ address_space_unmap(as, hostmem, buflen, false, 0);
340
+ }
341
s->creadr = FIELD_DP64(s->creadr, GITS_CREADR, STALLED, 1);
342
qemu_log_mask(LOG_GUEST_ERROR,
343
"%s: could not read command at 0x%" PRIx64 "\n",
344
__func__, s->cq.base_addr + cq_offset);
345
break;
346
}
347
+ for (i = 0; i < ARRAY_SIZE(cmdpkt); i++) {
348
+ cmdpkt[i] = ldq_le_p(hostmem + i * sizeof(uint64_t));
349
+ }
350
+ address_space_unmap(as, hostmem, buflen, false, 0);
351
352
- cmd = (data & CMD_MASK);
353
+ cmd = cmdpkt[0] & CMD_MASK;
354
355
trace_gicv3_its_process_command(rd_offset, cmd);
356
357
switch (cmd) {
358
case GITS_CMD_INT:
359
- result = process_its_cmd(s, data, cq_offset, INTERRUPT);
360
+ result = process_its_cmd(s, cmdpkt, INTERRUPT);
361
break;
362
case GITS_CMD_CLEAR:
363
- result = process_its_cmd(s, data, cq_offset, CLEAR);
364
+ result = process_its_cmd(s, cmdpkt, CLEAR);
365
break;
366
case GITS_CMD_SYNC:
367
/*
368
@@ -XXX,XX +XXX,XX @@ static void process_cmdq(GICv3ITSState *s)
369
*/
370
break;
371
case GITS_CMD_MAPD:
372
- result = process_mapd(s, data, cq_offset);
373
+ result = process_mapd(s, cmdpkt);
374
break;
375
case GITS_CMD_MAPC:
376
- result = process_mapc(s, cq_offset);
377
+ result = process_mapc(s, cmdpkt);
378
break;
379
case GITS_CMD_MAPTI:
380
- result = process_mapti(s, data, cq_offset, false);
381
+ result = process_mapti(s, cmdpkt, false);
382
break;
383
case GITS_CMD_MAPI:
384
- result = process_mapti(s, data, cq_offset, true);
385
+ result = process_mapti(s, cmdpkt, true);
386
break;
387
case GITS_CMD_DISCARD:
388
- result = process_its_cmd(s, data, cq_offset, DISCARD);
389
+ result = process_its_cmd(s, cmdpkt, DISCARD);
390
break;
391
case GITS_CMD_INV:
392
case GITS_CMD_INVALL:
393
@@ -XXX,XX +XXX,XX @@ static void process_cmdq(GICv3ITSState *s)
394
}
395
break;
396
case GITS_CMD_MOVI:
397
- result = process_movi(s, data, cq_offset);
398
+ result = process_movi(s, cmdpkt);
399
break;
400
case GITS_CMD_MOVALL:
401
- result = process_movall(s, data, cq_offset);
402
+ result = process_movall(s, cmdpkt);
403
break;
404
default:
405
break;
406
@@ -XXX,XX +XXX,XX @@ static MemTxResult gicv3_its_translation_write(void *opaque, hwaddr offset,
407
{
408
GICv3ITSState *s = (GICv3ITSState *)opaque;
409
bool result = true;
410
- uint32_t devid = 0;
411
412
trace_gicv3_its_translation_write(offset, data, size, attrs.requester_id);
413
414
switch (offset) {
415
case GITS_TRANSLATER:
416
if (s->ctlr & R_GITS_CTLR_ENABLED_MASK) {
417
- devid = attrs.requester_id;
418
- result = process_its_cmd(s, data, devid, NONE);
419
+ result = do_process_its_cmd(s, attrs.requester_id, data, NONE);
420
}
421
break;
422
default:
423
--
424
2.25.1
425
426
diff view generated by jsdifflib
New patch
1
1
In the ITS, a DTE is an entry in the device table, which contains
2
multiple fields. Currently the function get_dte() which reads one
3
entry from the device table returns it as a raw 64-bit integer,
4
which we then pass around in that form, only extracting fields
5
from it as we need them.
6
7
Create a real C struct with the same fields as the DTE, and
8
populate it in get_dte(), so that that function and update_dte()
9
are the only ones that need to care about the in-guest-memory
10
format of the DTE.
11
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
14
Message-id: 20220201193207.2771604-3-peter.maydell@linaro.org
15
---
16
hw/intc/arm_gicv3_its.c | 111 ++++++++++++++++++++--------------------
17
1 file changed, 56 insertions(+), 55 deletions(-)
18
19
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/hw/intc/arm_gicv3_its.c
22
+++ b/hw/intc/arm_gicv3_its.c
23
@@ -XXX,XX +XXX,XX @@ typedef struct {
24
uint64_t itel;
25
} IteEntry;
26
27
+typedef struct DTEntry {
28
+ bool valid;
29
+ unsigned size;
30
+ uint64_t ittaddr;
31
+} DTEntry;
32
+
33
/*
34
* The ITS spec permits a range of CONSTRAINED UNPREDICTABLE options
35
* if a command parameter is not correct. These include both "stall
36
@@ -XXX,XX +XXX,XX @@ static bool get_cte(GICv3ITSState *s, uint16_t icid, uint64_t *cte,
37
return FIELD_EX64(*cte, CTE, VALID);
38
}
39
40
-static bool update_ite(GICv3ITSState *s, uint32_t eventid, uint64_t dte,
41
+static bool update_ite(GICv3ITSState *s, uint32_t eventid, const DTEntry *dte,
42
IteEntry ite)
43
{
44
AddressSpace *as = &s->gicv3->dma_as;
45
- uint64_t itt_addr;
46
MemTxResult res = MEMTX_OK;
47
48
- itt_addr = FIELD_EX64(dte, DTE, ITTADDR);
49
- itt_addr <<= ITTADDR_SHIFT; /* 256 byte aligned */
50
-
51
- address_space_stq_le(as, itt_addr + (eventid * (sizeof(uint64_t) +
52
+ address_space_stq_le(as, dte->ittaddr + (eventid * (sizeof(uint64_t) +
53
sizeof(uint32_t))), ite.itel, MEMTXATTRS_UNSPECIFIED,
54
&res);
55
56
if (res == MEMTX_OK) {
57
- address_space_stl_le(as, itt_addr + (eventid * (sizeof(uint64_t) +
58
+ address_space_stl_le(as, dte->ittaddr + (eventid * (sizeof(uint64_t) +
59
sizeof(uint32_t))) + sizeof(uint32_t), ite.iteh,
60
MEMTXATTRS_UNSPECIFIED, &res);
61
}
62
@@ -XXX,XX +XXX,XX @@ static bool update_ite(GICv3ITSState *s, uint32_t eventid, uint64_t dte,
63
}
64
}
65
66
-static bool get_ite(GICv3ITSState *s, uint32_t eventid, uint64_t dte,
67
+static bool get_ite(GICv3ITSState *s, uint32_t eventid, const DTEntry *dte,
68
uint16_t *icid, uint32_t *pIntid, MemTxResult *res)
69
{
70
AddressSpace *as = &s->gicv3->dma_as;
71
- uint64_t itt_addr;
72
bool status = false;
73
IteEntry ite = {};
74
75
- itt_addr = FIELD_EX64(dte, DTE, ITTADDR);
76
- itt_addr <<= ITTADDR_SHIFT; /* 256 byte aligned */
77
-
78
- ite.itel = address_space_ldq_le(as, itt_addr +
79
+ ite.itel = address_space_ldq_le(as, dte->ittaddr +
80
(eventid * (sizeof(uint64_t) +
81
sizeof(uint32_t))), MEMTXATTRS_UNSPECIFIED,
82
res);
83
84
if (*res == MEMTX_OK) {
85
- ite.iteh = address_space_ldl_le(as, itt_addr +
86
+ ite.iteh = address_space_ldl_le(as, dte->ittaddr +
87
(eventid * (sizeof(uint64_t) +
88
sizeof(uint32_t))) + sizeof(uint32_t),
89
MEMTXATTRS_UNSPECIFIED, res);
90
@@ -XXX,XX +XXX,XX @@ static bool get_ite(GICv3ITSState *s, uint32_t eventid, uint64_t dte,
91
return status;
92
}
93
94
-static uint64_t get_dte(GICv3ITSState *s, uint32_t devid, MemTxResult *res)
95
+/*
96
+ * Read the Device Table entry at index @devid. On success (including
97
+ * successfully determining that there is no valid DTE for this index),
98
+ * we return MEMTX_OK and populate the DTEntry struct accordingly.
99
+ * If there is an error reading memory then we return the error code.
100
+ */
101
+static MemTxResult get_dte(GICv3ITSState *s, uint32_t devid, DTEntry *dte)
102
{
103
+ MemTxResult res = MEMTX_OK;
104
AddressSpace *as = &s->gicv3->dma_as;
105
- uint64_t entry_addr = table_entry_addr(s, &s->dt, devid, res);
106
+ uint64_t entry_addr = table_entry_addr(s, &s->dt, devid, &res);
107
+ uint64_t dteval;
108
109
if (entry_addr == -1) {
110
- return 0; /* a DTE entry with the Valid bit clear */
111
+ /* No L2 table entry, i.e. no valid DTE, or a memory error */
112
+ dte->valid = false;
113
+ return res;
114
}
115
- return address_space_ldq_le(as, entry_addr, MEMTXATTRS_UNSPECIFIED, res);
116
+ dteval = address_space_ldq_le(as, entry_addr, MEMTXATTRS_UNSPECIFIED, &res);
117
+ if (res != MEMTX_OK) {
118
+ return res;
119
+ }
120
+ dte->valid = FIELD_EX64(dteval, DTE, VALID);
121
+ dte->size = FIELD_EX64(dteval, DTE, SIZE);
122
+ /* DTE word field stores bits [51:8] of the ITT address */
123
+ dte->ittaddr = FIELD_EX64(dteval, DTE, ITTADDR) << ITTADDR_SHIFT;
124
+ return MEMTX_OK;
125
}
126
127
/*
128
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult do_process_its_cmd(GICv3ITSState *s, uint32_t devid,
129
uint32_t eventid, ItsCmdType cmd)
130
{
131
MemTxResult res = MEMTX_OK;
132
- bool dte_valid;
133
- uint64_t dte = 0;
134
uint64_t num_eventids;
135
uint16_t icid = 0;
136
uint32_t pIntid = 0;
137
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult do_process_its_cmd(GICv3ITSState *s, uint32_t devid,
138
uint64_t cte = 0;
139
bool cte_valid = false;
140
uint64_t rdbase;
141
+ DTEntry dte;
142
143
if (devid >= s->dt.num_entries) {
144
qemu_log_mask(LOG_GUEST_ERROR,
145
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult do_process_its_cmd(GICv3ITSState *s, uint32_t devid,
146
return CMD_CONTINUE;
147
}
148
149
- dte = get_dte(s, devid, &res);
150
-
151
- if (res != MEMTX_OK) {
152
+ if (get_dte(s, devid, &dte) != MEMTX_OK) {
153
return CMD_STALL;
154
}
155
- dte_valid = FIELD_EX64(dte, DTE, VALID);
156
-
157
- if (!dte_valid) {
158
+ if (!dte.valid) {
159
qemu_log_mask(LOG_GUEST_ERROR,
160
"%s: invalid command attributes: "
161
- "invalid dte: %"PRIx64" for %d\n",
162
- __func__, dte, devid);
163
+ "invalid dte for %d\n", __func__, devid);
164
return CMD_CONTINUE;
165
}
166
167
- num_eventids = 1ULL << (FIELD_EX64(dte, DTE, SIZE) + 1);
168
-
169
+ num_eventids = 1ULL << (dte.size + 1);
170
if (eventid >= num_eventids) {
171
qemu_log_mask(LOG_GUEST_ERROR,
172
"%s: invalid command attributes: eventid %d >= %"
173
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult do_process_its_cmd(GICv3ITSState *s, uint32_t devid,
174
return CMD_CONTINUE;
175
}
176
177
- ite_valid = get_ite(s, eventid, dte, &icid, &pIntid, &res);
178
+ ite_valid = get_ite(s, eventid, &dte, &icid, &pIntid, &res);
179
if (res != MEMTX_OK) {
180
return CMD_STALL;
181
}
182
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult do_process_its_cmd(GICv3ITSState *s, uint32_t devid,
183
if (cmd == DISCARD) {
184
IteEntry ite = {};
185
/* remove mapping from interrupt translation table */
186
- return update_ite(s, eventid, dte, ite) ? CMD_CONTINUE : CMD_STALL;
187
+ return update_ite(s, eventid, &dte, ite) ? CMD_CONTINUE : CMD_STALL;
188
}
189
return CMD_CONTINUE;
190
}
191
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_mapti(GICv3ITSState *s, const uint64_t *cmdpkt,
192
uint32_t pIntid = 0;
193
uint64_t num_eventids;
194
uint32_t num_intids;
195
- bool dte_valid;
196
- MemTxResult res = MEMTX_OK;
197
uint16_t icid = 0;
198
- uint64_t dte = 0;
199
IteEntry ite = {};
200
+ DTEntry dte;
201
202
devid = (cmdpkt[0] & DEVID_MASK) >> DEVID_SHIFT;
203
eventid = cmdpkt[1] & EVENTID_MASK;
204
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_mapti(GICv3ITSState *s, const uint64_t *cmdpkt,
205
return CMD_CONTINUE;
206
}
207
208
- dte = get_dte(s, devid, &res);
209
-
210
- if (res != MEMTX_OK) {
211
+ if (get_dte(s, devid, &dte) != MEMTX_OK) {
212
return CMD_STALL;
213
}
214
- dte_valid = FIELD_EX64(dte, DTE, VALID);
215
- num_eventids = 1ULL << (FIELD_EX64(dte, DTE, SIZE) + 1);
216
+ num_eventids = 1ULL << (dte.size + 1);
217
num_intids = 1ULL << (GICD_TYPER_IDBITS + 1);
218
219
if ((icid >= s->ct.num_entries)
220
- || !dte_valid || (eventid >= num_eventids) ||
221
+ || !dte.valid || (eventid >= num_eventids) ||
222
(((pIntid < GICV3_LPI_INTID_START) || (pIntid >= num_intids)) &&
223
(pIntid != INTID_SPURIOUS))) {
224
qemu_log_mask(LOG_GUEST_ERROR,
225
"%s: invalid command attributes "
226
"icid %d or eventid %d or pIntid %d or"
227
"unmapped dte %d\n", __func__, icid, eventid,
228
- pIntid, dte_valid);
229
+ pIntid, dte.valid);
230
/*
231
* in this implementation, in case of error
232
* we ignore this command and move onto the next
233
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_mapti(GICv3ITSState *s, const uint64_t *cmdpkt,
234
}
235
236
/* add ite entry to interrupt translation table */
237
- ite.itel = FIELD_DP64(ite.itel, ITE_L, VALID, dte_valid);
238
+ ite.itel = FIELD_DP64(ite.itel, ITE_L, VALID, true);
239
ite.itel = FIELD_DP64(ite.itel, ITE_L, INTTYPE, ITE_INTTYPE_PHYSICAL);
240
ite.itel = FIELD_DP64(ite.itel, ITE_L, INTID, pIntid);
241
ite.itel = FIELD_DP64(ite.itel, ITE_L, DOORBELL, INTID_SPURIOUS);
242
ite.iteh = FIELD_DP32(ite.iteh, ITE_H, ICID, icid);
243
244
- return update_ite(s, eventid, dte, ite) ? CMD_CONTINUE : CMD_STALL;
245
+ return update_ite(s, eventid, &dte, ite) ? CMD_CONTINUE : CMD_STALL;
246
}
247
248
static bool update_cte(GICv3ITSState *s, uint16_t icid, bool valid,
249
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_movi(GICv3ITSState *s, const uint64_t *cmdpkt)
250
uint16_t old_icid, new_icid;
251
uint64_t old_cte, new_cte;
252
uint64_t old_rdbase, new_rdbase;
253
- uint64_t dte;
254
- bool dte_valid, ite_valid, cte_valid;
255
+ bool ite_valid, cte_valid;
256
uint64_t num_eventids;
257
IteEntry ite = {};
258
+ DTEntry dte;
259
260
devid = FIELD_EX64(cmdpkt[0], MOVI_0, DEVICEID);
261
eventid = FIELD_EX64(cmdpkt[1], MOVI_1, EVENTID);
262
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_movi(GICv3ITSState *s, const uint64_t *cmdpkt)
263
__func__, devid, s->dt.num_entries);
264
return CMD_CONTINUE;
265
}
266
- dte = get_dte(s, devid, &res);
267
- if (res != MEMTX_OK) {
268
+ if (get_dte(s, devid, &dte) != MEMTX_OK) {
269
return CMD_STALL;
270
}
271
272
- dte_valid = FIELD_EX64(dte, DTE, VALID);
273
- if (!dte_valid) {
274
+ if (!dte.valid) {
275
qemu_log_mask(LOG_GUEST_ERROR,
276
"%s: invalid command attributes: "
277
- "invalid dte: %"PRIx64" for %d\n",
278
- __func__, dte, devid);
279
+ "invalid dte for %d\n", __func__, devid);
280
return CMD_CONTINUE;
281
}
282
283
- num_eventids = 1ULL << (FIELD_EX64(dte, DTE, SIZE) + 1);
284
+ num_eventids = 1ULL << (dte.size + 1);
285
if (eventid >= num_eventids) {
286
qemu_log_mask(LOG_GUEST_ERROR,
287
"%s: invalid command attributes: eventid %d >= %"
288
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_movi(GICv3ITSState *s, const uint64_t *cmdpkt)
289
return CMD_CONTINUE;
290
}
291
292
- ite_valid = get_ite(s, eventid, dte, &old_icid, &intid, &res);
293
+ ite_valid = get_ite(s, eventid, &dte, &old_icid, &intid, &res);
294
if (res != MEMTX_OK) {
295
return CMD_STALL;
296
}
297
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_movi(GICv3ITSState *s, const uint64_t *cmdpkt)
298
ite.itel = FIELD_DP64(ite.itel, ITE_L, INTID, intid);
299
ite.itel = FIELD_DP64(ite.itel, ITE_L, DOORBELL, INTID_SPURIOUS);
300
ite.iteh = FIELD_DP32(ite.iteh, ITE_H, ICID, new_icid);
301
- return update_ite(s, eventid, dte, ite) ? CMD_CONTINUE : CMD_STALL;
302
+ return update_ite(s, eventid, &dte, ite) ? CMD_CONTINUE : CMD_STALL;
303
}
304
305
/*
306
--
307
2.25.1
308
309
diff view generated by jsdifflib
1
When we calculate the mask to use to get the group priority from
1
Make update_dte() take a DTEntry struct rather than all the fields of
2
an interrupt priority, the way that NS BPR1 is handled differs
2
the new DTE as separate arguments.
3
from how BPR0 and S BPR1 work -- a BPR1 value of 1 means
4
the group priority is in bits [7:1], whereas for BPR0 and S BPR1
5
this is indicated by a 0 BPR value.
6
7
Subtract 1 from the BPR value before creating the mask if
8
we're using the NS BPR value, for both hardware and virtual
9
interrupts, as the GICv3 pseudocode does, and fix the comments
10
accordingly.
11
3
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
14
Message-id: 1493226792-3237-4-git-send-email-peter.maydell@linaro.org
6
Message-id: 20220201193207.2771604-4-peter.maydell@linaro.org
15
---
7
---
16
hw/intc/arm_gicv3_cpuif.c | 42 ++++++++++++++++++++++++++++++++++++++----
8
hw/intc/arm_gicv3_its.c | 35 ++++++++++++++++++-----------------
17
1 file changed, 38 insertions(+), 4 deletions(-)
9
1 file changed, 18 insertions(+), 17 deletions(-)
18
10
19
diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
11
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
20
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
21
--- a/hw/intc/arm_gicv3_cpuif.c
13
--- a/hw/intc/arm_gicv3_its.c
22
+++ b/hw/intc/arm_gicv3_cpuif.c
14
+++ b/hw/intc/arm_gicv3_its.c
23
@@ -XXX,XX +XXX,XX @@ static uint32_t icv_gprio_mask(GICv3CPUState *cs, int group)
15
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_mapc(GICv3ITSState *s, const uint64_t *cmdpkt)
16
return update_cte(s, icid, valid, rdbase) ? CMD_CONTINUE : CMD_STALL;
17
}
18
19
-static bool update_dte(GICv3ITSState *s, uint32_t devid, bool valid,
20
- uint8_t size, uint64_t itt_addr)
21
+/*
22
+ * Update the Device Table entry for @devid to @dte. Returns true
23
+ * on success, false if there was a memory access error.
24
+ */
25
+static bool update_dte(GICv3ITSState *s, uint32_t devid, const DTEntry *dte)
24
{
26
{
25
/* Return a mask word which clears the subpriority bits from
27
AddressSpace *as = &s->gicv3->dma_as;
26
* a priority value for a virtual interrupt in the specified group.
28
uint64_t entry_addr;
27
- * This depends on the VBPR value:
29
- uint64_t dte = 0;
28
+ * This depends on the VBPR value.
30
+ uint64_t dteval = 0;
29
+ * If using VBPR0 then:
31
MemTxResult res = MEMTX_OK;
30
* a BPR of 0 means the group priority bits are [7:1];
32
31
* a BPR of 1 means they are [7:2], and so on down to
33
if (s->dt.valid) {
32
* a BPR of 7 meaning no group priority bits at all.
34
- if (valid) {
33
+ * If using VBPR1 then:
35
+ if (dte->valid) {
34
+ * a BPR of 0 is impossible (the minimum value is 1)
36
/* add mapping entry to device table */
35
+ * a BPR of 1 means the group priority bits are [7:1];
37
- dte = FIELD_DP64(dte, DTE, VALID, 1);
36
+ * a BPR of 2 means they are [7:2], and so on down to
38
- dte = FIELD_DP64(dte, DTE, SIZE, size);
37
+ * a BPR of 7 meaning the group priority is [7].
39
- dte = FIELD_DP64(dte, DTE, ITTADDR, itt_addr);
38
+ *
40
+ dteval = FIELD_DP64(dteval, DTE, VALID, 1);
39
* Which BPR to use depends on the group of the interrupt and
41
+ dteval = FIELD_DP64(dteval, DTE, SIZE, dte->size);
40
* the current ICH_VMCR_EL2.VCBPR settings.
42
+ dteval = FIELD_DP64(dteval, DTE, ITTADDR, dte->ittaddr);
41
+ *
43
}
42
+ * This corresponds to the VGroupBits() pseudocode.
44
} else {
43
*/
45
return true;
44
+ int bpr;
46
@@ -XXX,XX +XXX,XX @@ static bool update_dte(GICv3ITSState *s, uint32_t devid, bool valid,
45
+
47
/* No L2 table for this index: discard write and continue */
46
if (group == GICV3_G1NS && cs->ich_vmcr_el2 & ICH_VMCR_EL2_VCBPR) {
48
return true;
47
group = GICV3_G0;
48
}
49
}
49
50
- address_space_stq_le(as, entry_addr, dte, MEMTXATTRS_UNSPECIFIED, &res);
50
- return ~0U << (read_vbpr(cs, group) + 1);
51
+ address_space_stq_le(as, entry_addr, dteval, MEMTXATTRS_UNSPECIFIED, &res);
51
+ bpr = read_vbpr(cs, group);
52
return res == MEMTX_OK;
52
+ if (group == GICV3_G1NS) {
53
+ assert(bpr > 0);
54
+ bpr--;
55
+ }
56
+
57
+ return ~0U << (bpr + 1);
58
}
53
}
59
54
60
static bool icv_hppi_can_preempt(GICv3CPUState *cs, uint64_t lr)
55
static ItsCmdResult process_mapd(GICv3ITSState *s, const uint64_t *cmdpkt)
61
@@ -XXX,XX +XXX,XX @@ static uint32_t icc_gprio_mask(GICv3CPUState *cs, int group)
62
{
56
{
63
/* Return a mask word which clears the subpriority bits from
57
uint32_t devid;
64
* a priority value for an interrupt in the specified group.
58
- uint8_t size;
65
- * This depends on the BPR value:
59
- uint64_t itt_addr;
66
+ * This depends on the BPR value. For CBPR0 (S or NS):
60
- bool valid;
67
* a BPR of 0 means the group priority bits are [7:1];
61
+ DTEntry dte;
68
* a BPR of 1 means they are [7:2], and so on down to
62
69
* a BPR of 7 meaning no group priority bits at all.
63
devid = (cmdpkt[0] & DEVID_MASK) >> DEVID_SHIFT;
70
+ * For CBPR1 NS:
64
- size = cmdpkt[1] & SIZE_MASK;
71
+ * a BPR of 0 is impossible (the minimum value is 1)
65
- itt_addr = (cmdpkt[2] & ITTADDR_MASK) >> ITTADDR_SHIFT;
72
+ * a BPR of 1 means the group priority bits are [7:1];
66
- valid = cmdpkt[2] & CMD_FIELD_VALID_MASK;
73
+ * a BPR of 2 means they are [7:2], and so on down to
67
+ dte.size = cmdpkt[1] & SIZE_MASK;
74
+ * a BPR of 7 meaning the group priority is [7].
68
+ dte.ittaddr = (cmdpkt[2] & ITTADDR_MASK) >> ITTADDR_SHIFT;
75
+ *
69
+ dte.valid = cmdpkt[2] & CMD_FIELD_VALID_MASK;
76
* Which BPR to use depends on the group of the interrupt and
70
77
* the current ICC_CTLR.CBPR settings.
71
if ((devid >= s->dt.num_entries) ||
78
+ *
72
- (size > FIELD_EX64(s->typer, GITS_TYPER, IDBITS))) {
79
+ * This corresponds to the GroupBits() pseudocode.
73
+ (dte.size > FIELD_EX64(s->typer, GITS_TYPER, IDBITS))) {
80
*/
74
qemu_log_mask(LOG_GUEST_ERROR,
81
+ int bpr;
75
"ITS MAPD: invalid device table attributes "
82
+
76
- "devid %d or size %d\n", devid, size);
83
if ((group == GICV3_G1 && cs->icc_ctlr_el1[GICV3_S] & ICC_CTLR_EL1_CBPR) ||
77
+ "devid %d or size %d\n", devid, dte.size);
84
(group == GICV3_G1NS &&
78
/*
85
cs->icc_ctlr_el1[GICV3_NS] & ICC_CTLR_EL1_CBPR)) {
79
* in this implementation, in case of error
86
group = GICV3_G0;
80
* we ignore this command and move onto the next
81
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_mapd(GICv3ITSState *s, const uint64_t *cmdpkt)
82
return CMD_CONTINUE;
87
}
83
}
88
84
89
- return ~0U << ((cs->icc_bpr[group] & 7) + 1);
85
- return update_dte(s, devid, valid, size, itt_addr) ? CMD_CONTINUE : CMD_STALL;
90
+ bpr = cs->icc_bpr[group] & 7;
86
+ return update_dte(s, devid, &dte) ? CMD_CONTINUE : CMD_STALL;
91
+
92
+ if (group == GICV3_G1NS) {
93
+ assert(bpr > 0);
94
+ bpr--;
95
+ }
96
+
97
+ return ~0U << (bpr + 1);
98
}
87
}
99
88
100
static bool icc_no_enabled_hppi(GICv3CPUState *cs)
89
static ItsCmdResult process_movall(GICv3ITSState *s, const uint64_t *cmdpkt)
101
--
90
--
102
2.7.4
91
2.25.1
103
92
104
93
diff view generated by jsdifflib
New patch
1
1
In the ITS, a CTE is an entry in the collection table, which contains
2
multiple fields. Currently the function get_cte() which reads one
3
entry from the device table returns a success/failure boolean and
4
passes back the raw 64-bit integer CTE value via a pointer argument.
5
We then extract fields from the CTE as we need them.
6
7
Create a real C struct with the same fields as the CTE, and
8
populate it in get_cte(), so that that function and update_cte()
9
are the only ones which need to care about the in-guest-memory
10
format of the CTE.
11
12
This brings get_cte()'s API into line with get_dte().
13
14
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
16
Message-id: 20220201193207.2771604-5-peter.maydell@linaro.org
17
---
18
hw/intc/arm_gicv3_its.c | 96 ++++++++++++++++++++++-------------------
19
1 file changed, 52 insertions(+), 44 deletions(-)
20
21
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
22
index XXXXXXX..XXXXXXX 100644
23
--- a/hw/intc/arm_gicv3_its.c
24
+++ b/hw/intc/arm_gicv3_its.c
25
@@ -XXX,XX +XXX,XX @@ typedef struct DTEntry {
26
uint64_t ittaddr;
27
} DTEntry;
28
29
+typedef struct CTEntry {
30
+ bool valid;
31
+ uint32_t rdbase;
32
+} CTEntry;
33
+
34
/*
35
* The ITS spec permits a range of CONSTRAINED UNPREDICTABLE options
36
* if a command parameter is not correct. These include both "stall
37
@@ -XXX,XX +XXX,XX @@ static uint64_t table_entry_addr(GICv3ITSState *s, TableDesc *td,
38
return (l2 & ((1ULL << 51) - 1)) + (idx % num_l2_entries) * td->entry_sz;
39
}
40
41
-static bool get_cte(GICv3ITSState *s, uint16_t icid, uint64_t *cte,
42
- MemTxResult *res)
43
+/*
44
+ * Read the Collection Table entry at index @icid. On success (including
45
+ * successfully determining that there is no valid CTE for this index),
46
+ * we return MEMTX_OK and populate the CTEntry struct @cte accordingly.
47
+ * If there is an error reading memory then we return the error code.
48
+ */
49
+static MemTxResult get_cte(GICv3ITSState *s, uint16_t icid, CTEntry *cte)
50
{
51
AddressSpace *as = &s->gicv3->dma_as;
52
- uint64_t entry_addr = table_entry_addr(s, &s->ct, icid, res);
53
+ MemTxResult res = MEMTX_OK;
54
+ uint64_t entry_addr = table_entry_addr(s, &s->ct, icid, &res);
55
+ uint64_t cteval;
56
57
if (entry_addr == -1) {
58
- return false; /* not valid */
59
+ /* No L2 table entry, i.e. no valid CTE, or a memory error */
60
+ cte->valid = false;
61
+ return res;
62
}
63
64
- *cte = address_space_ldq_le(as, entry_addr, MEMTXATTRS_UNSPECIFIED, res);
65
- return FIELD_EX64(*cte, CTE, VALID);
66
+ cteval = address_space_ldq_le(as, entry_addr, MEMTXATTRS_UNSPECIFIED, &res);
67
+ if (res != MEMTX_OK) {
68
+ return res;
69
+ }
70
+ cte->valid = FIELD_EX64(cteval, CTE, VALID);
71
+ cte->rdbase = FIELD_EX64(cteval, CTE, RDBASE);
72
+ return MEMTX_OK;
73
}
74
75
static bool update_ite(GICv3ITSState *s, uint32_t eventid, const DTEntry *dte,
76
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult do_process_its_cmd(GICv3ITSState *s, uint32_t devid,
77
uint16_t icid = 0;
78
uint32_t pIntid = 0;
79
bool ite_valid = false;
80
- uint64_t cte = 0;
81
- bool cte_valid = false;
82
- uint64_t rdbase;
83
DTEntry dte;
84
+ CTEntry cte;
85
86
if (devid >= s->dt.num_entries) {
87
qemu_log_mask(LOG_GUEST_ERROR,
88
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult do_process_its_cmd(GICv3ITSState *s, uint32_t devid,
89
return CMD_CONTINUE;
90
}
91
92
- cte_valid = get_cte(s, icid, &cte, &res);
93
- if (res != MEMTX_OK) {
94
+ if (get_cte(s, icid, &cte) != MEMTX_OK) {
95
return CMD_STALL;
96
}
97
- if (!cte_valid) {
98
+ if (!cte.valid) {
99
qemu_log_mask(LOG_GUEST_ERROR,
100
- "%s: invalid command attributes: "
101
- "invalid cte: %"PRIx64"\n",
102
- __func__, cte);
103
+ "%s: invalid command attributes: invalid CTE\n",
104
+ __func__);
105
return CMD_CONTINUE;
106
}
107
108
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult do_process_its_cmd(GICv3ITSState *s, uint32_t devid,
109
* Current implementation only supports rdbase == procnum
110
* Hence rdbase physical address is ignored
111
*/
112
- rdbase = FIELD_EX64(cte, CTE, RDBASE);
113
-
114
- if (rdbase >= s->gicv3->num_cpu) {
115
+ if (cte.rdbase >= s->gicv3->num_cpu) {
116
return CMD_CONTINUE;
117
}
118
119
if ((cmd == CLEAR) || (cmd == DISCARD)) {
120
- gicv3_redist_process_lpi(&s->gicv3->cpu[rdbase], pIntid, 0);
121
+ gicv3_redist_process_lpi(&s->gicv3->cpu[cte.rdbase], pIntid, 0);
122
} else {
123
- gicv3_redist_process_lpi(&s->gicv3->cpu[rdbase], pIntid, 1);
124
+ gicv3_redist_process_lpi(&s->gicv3->cpu[cte.rdbase], pIntid, 1);
125
}
126
127
if (cmd == DISCARD) {
128
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_movi(GICv3ITSState *s, const uint64_t *cmdpkt)
129
MemTxResult res = MEMTX_OK;
130
uint32_t devid, eventid, intid;
131
uint16_t old_icid, new_icid;
132
- uint64_t old_cte, new_cte;
133
- uint64_t old_rdbase, new_rdbase;
134
- bool ite_valid, cte_valid;
135
+ bool ite_valid;
136
uint64_t num_eventids;
137
IteEntry ite = {};
138
DTEntry dte;
139
+ CTEntry old_cte, new_cte;
140
141
devid = FIELD_EX64(cmdpkt[0], MOVI_0, DEVICEID);
142
eventid = FIELD_EX64(cmdpkt[1], MOVI_1, EVENTID);
143
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_movi(GICv3ITSState *s, const uint64_t *cmdpkt)
144
return CMD_CONTINUE;
145
}
146
147
- cte_valid = get_cte(s, old_icid, &old_cte, &res);
148
- if (res != MEMTX_OK) {
149
+ if (get_cte(s, old_icid, &old_cte) != MEMTX_OK) {
150
return CMD_STALL;
151
}
152
- if (!cte_valid) {
153
+ if (!old_cte.valid) {
154
qemu_log_mask(LOG_GUEST_ERROR,
155
"%s: invalid command attributes: "
156
- "invalid cte: %"PRIx64"\n",
157
- __func__, old_cte);
158
+ "invalid CTE for old ICID 0x%x\n",
159
+ __func__, old_icid);
160
return CMD_CONTINUE;
161
}
162
163
- cte_valid = get_cte(s, new_icid, &new_cte, &res);
164
- if (res != MEMTX_OK) {
165
+ if (get_cte(s, new_icid, &new_cte) != MEMTX_OK) {
166
return CMD_STALL;
167
}
168
- if (!cte_valid) {
169
+ if (!new_cte.valid) {
170
qemu_log_mask(LOG_GUEST_ERROR,
171
"%s: invalid command attributes: "
172
- "invalid cte: %"PRIx64"\n",
173
- __func__, new_cte);
174
+ "invalid CTE for new ICID 0x%x\n",
175
+ __func__, new_icid);
176
return CMD_CONTINUE;
177
}
178
179
- old_rdbase = FIELD_EX64(old_cte, CTE, RDBASE);
180
- if (old_rdbase >= s->gicv3->num_cpu) {
181
+ if (old_cte.rdbase >= s->gicv3->num_cpu) {
182
qemu_log_mask(LOG_GUEST_ERROR,
183
- "%s: CTE has invalid rdbase 0x%"PRIx64"\n",
184
- __func__, old_rdbase);
185
+ "%s: CTE has invalid rdbase 0x%x\n",
186
+ __func__, old_cte.rdbase);
187
return CMD_CONTINUE;
188
}
189
190
- new_rdbase = FIELD_EX64(new_cte, CTE, RDBASE);
191
- if (new_rdbase >= s->gicv3->num_cpu) {
192
+ if (new_cte.rdbase >= s->gicv3->num_cpu) {
193
qemu_log_mask(LOG_GUEST_ERROR,
194
- "%s: CTE has invalid rdbase 0x%"PRIx64"\n",
195
- __func__, new_rdbase);
196
+ "%s: CTE has invalid rdbase 0x%x\n",
197
+ __func__, new_cte.rdbase);
198
return CMD_CONTINUE;
199
}
200
201
- if (old_rdbase != new_rdbase) {
202
+ if (old_cte.rdbase != new_cte.rdbase) {
203
/* Move the LPI from the old redistributor to the new one */
204
- gicv3_redist_mov_lpi(&s->gicv3->cpu[old_rdbase],
205
- &s->gicv3->cpu[new_rdbase],
206
+ gicv3_redist_mov_lpi(&s->gicv3->cpu[old_cte.rdbase],
207
+ &s->gicv3->cpu[new_cte.rdbase],
208
intid);
209
}
210
211
--
212
2.25.1
213
214
diff view generated by jsdifflib
1
ARM CPUs come in two flavours:
1
Make update_cte() take a CTEntry struct rather than all the fields
2
* proper MMU ("VMSA")
2
of the new CTE as separate arguments.
3
* only an MPU ("PMSA")
4
For PMSA, the MPU may be implemented, or not (in which case there
5
is default "always acts the same" behaviour, but it isn't guest
6
programmable).
7
3
8
QEMU is a bit confused about how we indicate this: we have an
4
This brings it into line with the update_dte() API.
9
ARM_FEATURE_MPU, but it's not clear whether this indicates
10
"PMSA, not VMSA" or "PMSA and MPU present" , and sometimes we
11
use it for one purpose and sometimes the other.
12
13
Currently trying to implement a PMSA-without-MPU core won't
14
work correctly because we turn off the ARM_FEATURE_MPU bit
15
and then a lot of things which should still exist get
16
turned off too.
17
18
As the first step in cleaning this up, rename the feature
19
bit to ARM_FEATURE_PMSA, which indicates a PMSA CPU (with
20
or without MPU).
21
5
22
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
23
Reviewed-by: Alistair Francis <alistair.francis@xilinx.com>
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
24
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
Message-id: 20220201193207.2771604-6-peter.maydell@linaro.org
25
Message-id: 1493122030-32191-5-git-send-email-peter.maydell@linaro.org
26
---
9
---
27
target/arm/cpu.h | 2 +-
10
hw/intc/arm_gicv3_its.c | 32 +++++++++++++++++---------------
28
target/arm/cpu.c | 12 ++++++------
11
1 file changed, 17 insertions(+), 15 deletions(-)
29
target/arm/helper.c | 12 ++++++------
30
target/arm/machine.c | 2 +-
31
4 files changed, 14 insertions(+), 14 deletions(-)
32
12
33
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
13
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
34
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
35
--- a/target/arm/cpu.h
15
--- a/hw/intc/arm_gicv3_its.c
36
+++ b/target/arm/cpu.h
16
+++ b/hw/intc/arm_gicv3_its.c
37
@@ -XXX,XX +XXX,XX @@ enum arm_features {
17
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_mapti(GICv3ITSState *s, const uint64_t *cmdpkt,
38
ARM_FEATURE_V6K,
18
return update_ite(s, eventid, &dte, ite) ? CMD_CONTINUE : CMD_STALL;
39
ARM_FEATURE_V7,
19
}
40
ARM_FEATURE_THUMB2,
20
41
- ARM_FEATURE_MPU, /* Only has Memory Protection Unit, not full MMU. */
21
-static bool update_cte(GICv3ITSState *s, uint16_t icid, bool valid,
42
+ ARM_FEATURE_PMSA, /* no MMU; may have Memory Protection Unit */
22
- uint64_t rdbase)
43
ARM_FEATURE_VFP3,
23
+/*
44
ARM_FEATURE_VFP_FP16,
24
+ * Update the Collection Table entry for @icid to @cte. Returns true
45
ARM_FEATURE_NEON,
25
+ * on success, false if there was a memory access error.
46
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
26
+ */
47
index XXXXXXX..XXXXXXX 100644
27
+static bool update_cte(GICv3ITSState *s, uint16_t icid, const CTEntry *cte)
48
--- a/target/arm/cpu.c
28
{
49
+++ b/target/arm/cpu.c
29
AddressSpace *as = &s->gicv3->dma_as;
50
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_post_init(Object *obj)
30
uint64_t entry_addr;
51
&error_abort);
31
- uint64_t cte = 0;
32
+ uint64_t cteval = 0;
33
MemTxResult res = MEMTX_OK;
34
35
if (!s->ct.valid) {
36
return true;
52
}
37
}
53
38
54
- if (arm_feature(&cpu->env, ARM_FEATURE_MPU)) {
39
- if (valid) {
55
+ if (arm_feature(&cpu->env, ARM_FEATURE_PMSA)) {
40
+ if (cte->valid) {
56
qdev_property_add_static(DEVICE(obj), &arm_cpu_has_mpu_property,
41
/* add mapping entry to collection table */
57
&error_abort);
42
- cte = FIELD_DP64(cte, CTE, VALID, 1);
58
if (arm_feature(&cpu->env, ARM_FEATURE_V7)) {
43
- cte = FIELD_DP64(cte, CTE, RDBASE, rdbase);
59
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
44
+ cteval = FIELD_DP64(cteval, CTE, VALID, 1);
60
45
+ cteval = FIELD_DP64(cteval, CTE, RDBASE, cte->rdbase);
61
if (arm_feature(env, ARM_FEATURE_V7) &&
62
!arm_feature(env, ARM_FEATURE_M) &&
63
- !arm_feature(env, ARM_FEATURE_MPU)) {
64
+ !arm_feature(env, ARM_FEATURE_PMSA)) {
65
/* v7VMSA drops support for the old ARMv5 tiny pages, so we
66
* can use 4K pages.
67
*/
68
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
69
}
46
}
70
47
71
if (!cpu->has_mpu) {
48
entry_addr = table_entry_addr(s, &s->ct, icid, &res);
72
- unset_feature(env, ARM_FEATURE_MPU);
49
@@ -XXX,XX +XXX,XX @@ static bool update_cte(GICv3ITSState *s, uint16_t icid, bool valid,
73
+ unset_feature(env, ARM_FEATURE_PMSA);
50
return true;
74
}
51
}
75
52
76
- if (arm_feature(env, ARM_FEATURE_MPU) &&
53
- address_space_stq_le(as, entry_addr, cte, MEMTXATTRS_UNSPECIFIED, &res);
77
+ if (arm_feature(env, ARM_FEATURE_PMSA) &&
54
+ address_space_stq_le(as, entry_addr, cteval, MEMTXATTRS_UNSPECIFIED, &res);
78
arm_feature(env, ARM_FEATURE_V7)) {
55
return res == MEMTX_OK;
79
uint32_t nr = cpu->pmsav7_dregion;
56
}
80
57
81
@@ -XXX,XX +XXX,XX @@ static void arm946_initfn(Object *obj)
58
static ItsCmdResult process_mapc(GICv3ITSState *s, const uint64_t *cmdpkt)
82
83
cpu->dtb_compatible = "arm,arm946";
84
set_feature(&cpu->env, ARM_FEATURE_V5);
85
- set_feature(&cpu->env, ARM_FEATURE_MPU);
86
+ set_feature(&cpu->env, ARM_FEATURE_PMSA);
87
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
88
cpu->midr = 0x41059461;
89
cpu->ctr = 0x0f004006;
90
@@ -XXX,XX +XXX,XX @@ static void cortex_r5_initfn(Object *obj)
91
set_feature(&cpu->env, ARM_FEATURE_THUMB_DIV);
92
set_feature(&cpu->env, ARM_FEATURE_ARM_DIV);
93
set_feature(&cpu->env, ARM_FEATURE_V7MP);
94
- set_feature(&cpu->env, ARM_FEATURE_MPU);
95
+ set_feature(&cpu->env, ARM_FEATURE_PMSA);
96
cpu->midr = 0x411fc153; /* r1p3 */
97
cpu->id_pfr0 = 0x0131;
98
cpu->id_pfr1 = 0x001;
99
diff --git a/target/arm/helper.c b/target/arm/helper.c
100
index XXXXXXX..XXXXXXX 100644
101
--- a/target/arm/helper.c
102
+++ b/target/arm/helper.c
103
@@ -XXX,XX +XXX,XX @@ static void contextidr_write(CPUARMState *env, const ARMCPRegInfo *ri,
104
{
59
{
105
ARMCPU *cpu = arm_env_get_cpu(env);
60
uint16_t icid;
106
61
- uint64_t rdbase;
107
- if (raw_read(env, ri) != value && !arm_feature(env, ARM_FEATURE_MPU)
62
- bool valid;
108
+ if (raw_read(env, ri) != value && !arm_feature(env, ARM_FEATURE_PMSA)
63
+ CTEntry cte;
109
&& !extended_addresses_enabled(env)) {
64
110
/* For VMSA (when not using the LPAE long descriptor page table
65
icid = cmdpkt[2] & ICID_MASK;
111
* format) this register includes the ASID, so do a TLB flush.
66
112
@@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu)
67
- rdbase = (cmdpkt[2] & R_MAPC_RDBASE_MASK) >> R_MAPC_RDBASE_SHIFT;
113
define_arm_cp_regs(cpu, v6k_cp_reginfo);
68
- rdbase &= RDBASE_PROCNUM_MASK;
69
+ cte.rdbase = (cmdpkt[2] & R_MAPC_RDBASE_MASK) >> R_MAPC_RDBASE_SHIFT;
70
+ cte.rdbase &= RDBASE_PROCNUM_MASK;
71
72
- valid = cmdpkt[2] & CMD_FIELD_VALID_MASK;
73
+ cte.valid = cmdpkt[2] & CMD_FIELD_VALID_MASK;
74
75
- if ((icid >= s->ct.num_entries) || (rdbase >= s->gicv3->num_cpu)) {
76
+ if ((icid >= s->ct.num_entries) || (cte.rdbase >= s->gicv3->num_cpu)) {
77
qemu_log_mask(LOG_GUEST_ERROR,
78
"ITS MAPC: invalid collection table attributes "
79
- "icid %d rdbase %" PRIu64 "\n", icid, rdbase);
80
+ "icid %d rdbase %u\n", icid, cte.rdbase);
81
/*
82
* in this implementation, in case of error
83
* we ignore this command and move onto the next
84
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_mapc(GICv3ITSState *s, const uint64_t *cmdpkt)
85
return CMD_CONTINUE;
114
}
86
}
115
if (arm_feature(env, ARM_FEATURE_V7MP) &&
87
116
- !arm_feature(env, ARM_FEATURE_MPU)) {
88
- return update_cte(s, icid, valid, rdbase) ? CMD_CONTINUE : CMD_STALL;
117
+ !arm_feature(env, ARM_FEATURE_PMSA)) {
89
+ return update_cte(s, icid, &cte) ? CMD_CONTINUE : CMD_STALL;
118
define_arm_cp_regs(cpu, v7mp_cp_reginfo);
119
}
120
if (arm_feature(env, ARM_FEATURE_V7)) {
121
@@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu)
122
}
123
}
124
125
- if (arm_feature(env, ARM_FEATURE_MPU)) {
126
+ if (arm_feature(env, ARM_FEATURE_PMSA)) {
127
if (arm_feature(env, ARM_FEATURE_V6)) {
128
/* PMSAv6 not implemented */
129
assert(arm_feature(env, ARM_FEATURE_V7));
130
@@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu)
131
define_arm_cp_regs(cpu, id_pre_v8_midr_cp_reginfo);
132
}
133
define_arm_cp_regs(cpu, id_cp_reginfo);
134
- if (!arm_feature(env, ARM_FEATURE_MPU)) {
135
+ if (!arm_feature(env, ARM_FEATURE_PMSA)) {
136
define_one_arm_cp_reg(cpu, &id_tlbtr_reginfo);
137
} else if (arm_feature(env, ARM_FEATURE_V7)) {
138
define_one_arm_cp_reg(cpu, &id_mpuir_reginfo);
139
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr(CPUARMState *env, target_ulong address,
140
/* pmsav7 has special handling for when MPU is disabled so call it before
141
* the common MMU/MPU disabled check below.
142
*/
143
- if (arm_feature(env, ARM_FEATURE_MPU) &&
144
+ if (arm_feature(env, ARM_FEATURE_PMSA) &&
145
arm_feature(env, ARM_FEATURE_V7)) {
146
*page_size = TARGET_PAGE_SIZE;
147
return get_phys_addr_pmsav7(env, address, access_type, mmu_idx,
148
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr(CPUARMState *env, target_ulong address,
149
return 0;
150
}
151
152
- if (arm_feature(env, ARM_FEATURE_MPU)) {
153
+ if (arm_feature(env, ARM_FEATURE_PMSA)) {
154
/* Pre-v7 MPU */
155
*page_size = TARGET_PAGE_SIZE;
156
return get_phys_addr_pmsav5(env, address, access_type, mmu_idx,
157
diff --git a/target/arm/machine.c b/target/arm/machine.c
158
index XXXXXXX..XXXXXXX 100644
159
--- a/target/arm/machine.c
160
+++ b/target/arm/machine.c
161
@@ -XXX,XX +XXX,XX @@ static bool pmsav7_needed(void *opaque)
162
ARMCPU *cpu = opaque;
163
CPUARMState *env = &cpu->env;
164
165
- return arm_feature(env, ARM_FEATURE_MPU) &&
166
+ return arm_feature(env, ARM_FEATURE_PMSA) &&
167
arm_feature(env, ARM_FEATURE_V7);
168
}
90
}
169
91
92
/*
170
--
93
--
171
2.7.4
94
2.25.1
172
95
173
96
diff view generated by jsdifflib
New patch
1
In get_ite() and update_ite() we work with a 12-byte in-guest-memory
2
table entry, which we intend to handle as an 8-byte value followed by
3
a 4-byte value. Unfortunately the calculation of the address of the
4
4-byte value is wrong, because we write it as:
1
5
6
table_base_address + (index * entrysize) + 4
7
(obfuscated by the way the expression has been written)
8
9
when it should be + 8. This bug meant that we overwrote the top
10
bytes of the 8-byte value with the 4-byte value. There are no
11
guest-visible effects because the top half of the 8-byte value
12
contains only the doorbell interrupt field, which is used only in
13
GICv4, and the two bugs in the "write ITE" and "read ITE" codepaths
14
cancel each other out.
15
16
We can't simply change the calculation, because this would break
17
migration of a (TCG) guest from the old version of QEMU which had
18
in-guest-memory interrupt tables written using the buggy version of
19
update_ite(). We must also at the same time change the layout of the
20
fields within the ITE_L and ITE_H values so that the in-memory
21
locations of the fields we care about (VALID, INTTYPE, INTID and
22
ICID) stay the same.
23
24
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
25
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
26
Message-id: 20220201193207.2771604-7-peter.maydell@linaro.org
27
---
28
hw/intc/gicv3_internal.h | 19 ++++++++++---------
29
hw/intc/arm_gicv3_its.c | 28 +++++++++++-----------------
30
2 files changed, 21 insertions(+), 26 deletions(-)
31
32
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
33
index XXXXXXX..XXXXXXX 100644
34
--- a/hw/intc/gicv3_internal.h
35
+++ b/hw/intc/gicv3_internal.h
36
@@ -XXX,XX +XXX,XX @@ FIELD(MOVI_2, ICID, 0, 16)
37
* 12 bytes Interrupt translation Table Entry size
38
* as per Table 5.3 in GICv3 spec
39
* ITE Lower 8 Bytes
40
- * Bits: | 49 ... 26 | 25 ... 2 | 1 | 0 |
41
- * Values: | Doorbell | IntNum | IntType | Valid |
42
+ * Bits: | 63 ... 48 | 47 ... 32 | 31 ... 26 | 25 ... 2 | 1 | 0 |
43
+ * Values: | vPEID | ICID | unused | IntNum | IntType | Valid |
44
* ITE Higher 4 Bytes
45
- * Bits: | 31 ... 16 | 15 ...0 |
46
- * Values: | vPEID | ICID |
47
- * (When Doorbell is unused, as it always is in GICv3, it is 1023)
48
+ * Bits: | 31 ... 25 | 24 ... 0 |
49
+ * Values: | unused | Doorbell |
50
+ * (When Doorbell is unused, as it always is for INTYPE_PHYSICAL,
51
+ * the value of that field in memory cannot be relied upon -- older
52
+ * versions of QEMU did not correctly write to that memory.)
53
*/
54
#define ITS_ITT_ENTRY_SIZE 0xC
55
56
FIELD(ITE_L, VALID, 0, 1)
57
FIELD(ITE_L, INTTYPE, 1, 1)
58
FIELD(ITE_L, INTID, 2, 24)
59
-FIELD(ITE_L, DOORBELL, 26, 24)
60
-
61
-FIELD(ITE_H, ICID, 0, 16)
62
-FIELD(ITE_H, VPEID, 16, 16)
63
+FIELD(ITE_L, ICID, 32, 16)
64
+FIELD(ITE_L, VPEID, 48, 16)
65
+FIELD(ITE_H, DOORBELL, 0, 24)
66
67
/* Possible values for ITE_L INTTYPE */
68
#define ITE_INTTYPE_VIRTUAL 0
69
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
70
index XXXXXXX..XXXXXXX 100644
71
--- a/hw/intc/arm_gicv3_its.c
72
+++ b/hw/intc/arm_gicv3_its.c
73
@@ -XXX,XX +XXX,XX @@ static bool update_ite(GICv3ITSState *s, uint32_t eventid, const DTEntry *dte,
74
{
75
AddressSpace *as = &s->gicv3->dma_as;
76
MemTxResult res = MEMTX_OK;
77
+ hwaddr iteaddr = dte->ittaddr + eventid * ITS_ITT_ENTRY_SIZE;
78
79
- address_space_stq_le(as, dte->ittaddr + (eventid * (sizeof(uint64_t) +
80
- sizeof(uint32_t))), ite.itel, MEMTXATTRS_UNSPECIFIED,
81
- &res);
82
+ address_space_stq_le(as, iteaddr, ite.itel, MEMTXATTRS_UNSPECIFIED, &res);
83
84
if (res == MEMTX_OK) {
85
- address_space_stl_le(as, dte->ittaddr + (eventid * (sizeof(uint64_t) +
86
- sizeof(uint32_t))) + sizeof(uint32_t), ite.iteh,
87
+ address_space_stl_le(as, iteaddr + 8, ite.iteh,
88
MEMTXATTRS_UNSPECIFIED, &res);
89
}
90
if (res != MEMTX_OK) {
91
@@ -XXX,XX +XXX,XX @@ static bool get_ite(GICv3ITSState *s, uint32_t eventid, const DTEntry *dte,
92
AddressSpace *as = &s->gicv3->dma_as;
93
bool status = false;
94
IteEntry ite = {};
95
+ hwaddr iteaddr = dte->ittaddr + eventid * ITS_ITT_ENTRY_SIZE;
96
97
- ite.itel = address_space_ldq_le(as, dte->ittaddr +
98
- (eventid * (sizeof(uint64_t) +
99
- sizeof(uint32_t))), MEMTXATTRS_UNSPECIFIED,
100
- res);
101
+ ite.itel = address_space_ldq_le(as, iteaddr, MEMTXATTRS_UNSPECIFIED, res);
102
103
if (*res == MEMTX_OK) {
104
- ite.iteh = address_space_ldl_le(as, dte->ittaddr +
105
- (eventid * (sizeof(uint64_t) +
106
- sizeof(uint32_t))) + sizeof(uint32_t),
107
+ ite.iteh = address_space_ldl_le(as, iteaddr + 8,
108
MEMTXATTRS_UNSPECIFIED, res);
109
110
if (*res == MEMTX_OK) {
111
@@ -XXX,XX +XXX,XX @@ static bool get_ite(GICv3ITSState *s, uint32_t eventid, const DTEntry *dte,
112
int inttype = FIELD_EX64(ite.itel, ITE_L, INTTYPE);
113
if (inttype == ITE_INTTYPE_PHYSICAL) {
114
*pIntid = FIELD_EX64(ite.itel, ITE_L, INTID);
115
- *icid = FIELD_EX32(ite.iteh, ITE_H, ICID);
116
+ *icid = FIELD_EX64(ite.itel, ITE_L, ICID);
117
status = true;
118
}
119
}
120
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_mapti(GICv3ITSState *s, const uint64_t *cmdpkt,
121
ite.itel = FIELD_DP64(ite.itel, ITE_L, VALID, true);
122
ite.itel = FIELD_DP64(ite.itel, ITE_L, INTTYPE, ITE_INTTYPE_PHYSICAL);
123
ite.itel = FIELD_DP64(ite.itel, ITE_L, INTID, pIntid);
124
- ite.itel = FIELD_DP64(ite.itel, ITE_L, DOORBELL, INTID_SPURIOUS);
125
- ite.iteh = FIELD_DP32(ite.iteh, ITE_H, ICID, icid);
126
+ ite.itel = FIELD_DP64(ite.itel, ITE_L, ICID, icid);
127
+ ite.iteh = FIELD_DP32(ite.iteh, ITE_H, DOORBELL, INTID_SPURIOUS);
128
129
return update_ite(s, eventid, &dte, ite) ? CMD_CONTINUE : CMD_STALL;
130
}
131
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_movi(GICv3ITSState *s, const uint64_t *cmdpkt)
132
ite.itel = FIELD_DP64(ite.itel, ITE_L, VALID, 1);
133
ite.itel = FIELD_DP64(ite.itel, ITE_L, INTTYPE, ITE_INTTYPE_PHYSICAL);
134
ite.itel = FIELD_DP64(ite.itel, ITE_L, INTID, intid);
135
- ite.itel = FIELD_DP64(ite.itel, ITE_L, DOORBELL, INTID_SPURIOUS);
136
- ite.iteh = FIELD_DP32(ite.iteh, ITE_H, ICID, new_icid);
137
+ ite.itel = FIELD_DP64(ite.itel, ITE_L, ICID, new_icid);
138
+ ite.iteh = FIELD_DP32(ite.iteh, ITE_H, DOORBELL, INTID_SPURIOUS);
139
return update_ite(s, eventid, &dte, ite) ? CMD_CONTINUE : CMD_STALL;
140
}
141
142
--
143
2.25.1
144
145
diff view generated by jsdifflib
1
When identifying the DFSR format for an alignment fault, use
1
The get_ite() code has some awkward nested if statements; clean
2
the mmu index that we are passed, rather than calling cpu_mmu_index()
2
them up by returning early if the memory accesses fail.
3
to get the mmu index for the current CPU state. This doesn't actually
4
make any difference since the only cases where the current MMU index
5
differs from the index used for the load are the "unprivileged
6
load/store" instructions, and in that case the mmu index may
7
differ but the translation regime is the same (apart from the
8
"use from Hyp mode" case which is UNPREDICTABLE).
9
However it's the more logical thing to do.
10
3
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Reviewed-by: Alistair Francis <alistair.francis@xilinx.com>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
13
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
6
Message-id: 20220201193207.2771604-8-peter.maydell@linaro.org
14
Message-id: 1493122030-32191-2-git-send-email-peter.maydell@linaro.org
15
---
7
---
16
target/arm/op_helper.c | 2 +-
8
hw/intc/arm_gicv3_its.c | 26 ++++++++++++++------------
17
1 file changed, 1 insertion(+), 1 deletion(-)
9
1 file changed, 14 insertions(+), 12 deletions(-)
18
10
19
diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c
11
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
20
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
21
--- a/target/arm/op_helper.c
13
--- a/hw/intc/arm_gicv3_its.c
22
+++ b/target/arm/op_helper.c
14
+++ b/hw/intc/arm_gicv3_its.c
23
@@ -XXX,XX +XXX,XX @@ void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
15
@@ -XXX,XX +XXX,XX @@ static bool get_ite(GICv3ITSState *s, uint32_t eventid, const DTEntry *dte,
24
/* the DFSR for an alignment fault depends on whether we're using
16
hwaddr iteaddr = dte->ittaddr + eventid * ITS_ITT_ENTRY_SIZE;
25
* the LPAE long descriptor format, or the short descriptor format
17
26
*/
18
ite.itel = address_space_ldq_le(as, iteaddr, MEMTXATTRS_UNSPECIFIED, res);
27
- if (arm_s1_regime_using_lpae_format(env, cpu_mmu_index(env, false))) {
19
+ if (*res != MEMTX_OK) {
28
+ if (arm_s1_regime_using_lpae_format(env, mmu_idx)) {
20
+ return false;
29
env->exception.fsr = (1 << 9) | 0x21;
21
+ }
30
} else {
22
31
env->exception.fsr = 0x1;
23
- if (*res == MEMTX_OK) {
24
- ite.iteh = address_space_ldl_le(as, iteaddr + 8,
25
- MEMTXATTRS_UNSPECIFIED, res);
26
+ ite.iteh = address_space_ldl_le(as, iteaddr + 8,
27
+ MEMTXATTRS_UNSPECIFIED, res);
28
+ if (*res != MEMTX_OK) {
29
+ return false;
30
+ }
31
32
- if (*res == MEMTX_OK) {
33
- if (FIELD_EX64(ite.itel, ITE_L, VALID)) {
34
- int inttype = FIELD_EX64(ite.itel, ITE_L, INTTYPE);
35
- if (inttype == ITE_INTTYPE_PHYSICAL) {
36
- *pIntid = FIELD_EX64(ite.itel, ITE_L, INTID);
37
- *icid = FIELD_EX64(ite.itel, ITE_L, ICID);
38
- status = true;
39
- }
40
- }
41
+ if (FIELD_EX64(ite.itel, ITE_L, VALID)) {
42
+ int inttype = FIELD_EX64(ite.itel, ITE_L, INTTYPE);
43
+ if (inttype == ITE_INTTYPE_PHYSICAL) {
44
+ *pIntid = FIELD_EX64(ite.itel, ITE_L, INTID);
45
+ *icid = FIELD_EX64(ite.itel, ITE_L, ICID);
46
+ status = true;
47
}
48
}
49
return status;
32
--
50
--
33
2.7.4
51
2.25.1
34
52
35
53
diff view generated by jsdifflib
New patch
1
1
In get_ite() we currently return the caller some of the fields of an
2
Interrupt Table Entry via a set of pointer arguments, and validate
3
some of them internally (interrupt type and valid bit) to return a
4
simple true/false 'valid' indication. Define a new ITEntry struct
5
which has all the fields that the in-memory ITE has, and bring the
6
get_ite() function in to line with get_dte() and get_cte().
7
8
This paves the way for handling virtual interrupts, which will want
9
a different subset of the fields in the ITE. Handling them under
10
the old "lots of pointer arguments" scheme would have meant a
11
confusingly large set of arguments for this function.
12
13
The new struct ITEntry is obviously confusably similar to the
14
existing IteEntry struct, whose fields are the raw 12 bytes
15
of the in-memory ITE. In the next commit we will make update_ite()
16
use ITEntry instead of IteEntry, which will allow us to delete
17
the IteEntry struct and remove the confusion.
18
19
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
20
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
21
Message-id: 20220201193207.2771604-9-peter.maydell@linaro.org
22
---
23
hw/intc/arm_gicv3_its.c | 102 ++++++++++++++++++++++------------------
24
1 file changed, 55 insertions(+), 47 deletions(-)
25
26
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
27
index XXXXXXX..XXXXXXX 100644
28
--- a/hw/intc/arm_gicv3_its.c
29
+++ b/hw/intc/arm_gicv3_its.c
30
@@ -XXX,XX +XXX,XX @@ typedef struct CTEntry {
31
uint32_t rdbase;
32
} CTEntry;
33
34
+typedef struct ITEntry {
35
+ bool valid;
36
+ int inttype;
37
+ uint32_t intid;
38
+ uint32_t doorbell;
39
+ uint32_t icid;
40
+ uint32_t vpeid;
41
+} ITEntry;
42
+
43
+
44
/*
45
* The ITS spec permits a range of CONSTRAINED UNPREDICTABLE options
46
* if a command parameter is not correct. These include both "stall
47
@@ -XXX,XX +XXX,XX @@ static bool update_ite(GICv3ITSState *s, uint32_t eventid, const DTEntry *dte,
48
}
49
}
50
51
-static bool get_ite(GICv3ITSState *s, uint32_t eventid, const DTEntry *dte,
52
- uint16_t *icid, uint32_t *pIntid, MemTxResult *res)
53
+/*
54
+ * Read the Interrupt Table entry at index @eventid from the table specified
55
+ * by the DTE @dte. On success, we return MEMTX_OK and populate the ITEntry
56
+ * struct @ite accordingly. If there is an error reading memory then we return
57
+ * the error code.
58
+ */
59
+static MemTxResult get_ite(GICv3ITSState *s, uint32_t eventid,
60
+ const DTEntry *dte, ITEntry *ite)
61
{
62
AddressSpace *as = &s->gicv3->dma_as;
63
- bool status = false;
64
- IteEntry ite = {};
65
+ MemTxResult res = MEMTX_OK;
66
+ uint64_t itel;
67
+ uint32_t iteh;
68
hwaddr iteaddr = dte->ittaddr + eventid * ITS_ITT_ENTRY_SIZE;
69
70
- ite.itel = address_space_ldq_le(as, iteaddr, MEMTXATTRS_UNSPECIFIED, res);
71
- if (*res != MEMTX_OK) {
72
- return false;
73
+ itel = address_space_ldq_le(as, iteaddr, MEMTXATTRS_UNSPECIFIED, &res);
74
+ if (res != MEMTX_OK) {
75
+ return res;
76
}
77
78
- ite.iteh = address_space_ldl_le(as, iteaddr + 8,
79
- MEMTXATTRS_UNSPECIFIED, res);
80
- if (*res != MEMTX_OK) {
81
- return false;
82
+ iteh = address_space_ldl_le(as, iteaddr + 8, MEMTXATTRS_UNSPECIFIED, &res);
83
+ if (res != MEMTX_OK) {
84
+ return res;
85
}
86
87
- if (FIELD_EX64(ite.itel, ITE_L, VALID)) {
88
- int inttype = FIELD_EX64(ite.itel, ITE_L, INTTYPE);
89
- if (inttype == ITE_INTTYPE_PHYSICAL) {
90
- *pIntid = FIELD_EX64(ite.itel, ITE_L, INTID);
91
- *icid = FIELD_EX64(ite.itel, ITE_L, ICID);
92
- status = true;
93
- }
94
- }
95
- return status;
96
+ ite->valid = FIELD_EX64(itel, ITE_L, VALID);
97
+ ite->inttype = FIELD_EX64(itel, ITE_L, INTTYPE);
98
+ ite->intid = FIELD_EX64(itel, ITE_L, INTID);
99
+ ite->icid = FIELD_EX64(itel, ITE_L, ICID);
100
+ ite->vpeid = FIELD_EX64(itel, ITE_L, VPEID);
101
+ ite->doorbell = FIELD_EX64(iteh, ITE_H, DOORBELL);
102
+ return MEMTX_OK;
103
}
104
105
/*
106
@@ -XXX,XX +XXX,XX @@ static MemTxResult get_dte(GICv3ITSState *s, uint32_t devid, DTEntry *dte)
107
static ItsCmdResult do_process_its_cmd(GICv3ITSState *s, uint32_t devid,
108
uint32_t eventid, ItsCmdType cmd)
109
{
110
- MemTxResult res = MEMTX_OK;
111
uint64_t num_eventids;
112
- uint16_t icid = 0;
113
- uint32_t pIntid = 0;
114
- bool ite_valid = false;
115
DTEntry dte;
116
CTEntry cte;
117
+ ITEntry ite;
118
119
if (devid >= s->dt.num_entries) {
120
qemu_log_mask(LOG_GUEST_ERROR,
121
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult do_process_its_cmd(GICv3ITSState *s, uint32_t devid,
122
return CMD_CONTINUE;
123
}
124
125
- ite_valid = get_ite(s, eventid, &dte, &icid, &pIntid, &res);
126
- if (res != MEMTX_OK) {
127
+ if (get_ite(s, eventid, &dte, &ite) != MEMTX_OK) {
128
return CMD_STALL;
129
}
130
131
- if (!ite_valid) {
132
+ if (!ite.valid || ite.inttype != ITE_INTTYPE_PHYSICAL) {
133
qemu_log_mask(LOG_GUEST_ERROR,
134
"%s: invalid command attributes: invalid ITE\n",
135
__func__);
136
return CMD_CONTINUE;
137
}
138
139
- if (icid >= s->ct.num_entries) {
140
+ if (ite.icid >= s->ct.num_entries) {
141
qemu_log_mask(LOG_GUEST_ERROR,
142
"%s: invalid ICID 0x%x in ITE (table corrupted?)\n",
143
- __func__, icid);
144
+ __func__, ite.icid);
145
return CMD_CONTINUE;
146
}
147
148
- if (get_cte(s, icid, &cte) != MEMTX_OK) {
149
+ if (get_cte(s, ite.icid, &cte) != MEMTX_OK) {
150
return CMD_STALL;
151
}
152
if (!cte.valid) {
153
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult do_process_its_cmd(GICv3ITSState *s, uint32_t devid,
154
}
155
156
if ((cmd == CLEAR) || (cmd == DISCARD)) {
157
- gicv3_redist_process_lpi(&s->gicv3->cpu[cte.rdbase], pIntid, 0);
158
+ gicv3_redist_process_lpi(&s->gicv3->cpu[cte.rdbase], ite.intid, 0);
159
} else {
160
- gicv3_redist_process_lpi(&s->gicv3->cpu[cte.rdbase], pIntid, 1);
161
+ gicv3_redist_process_lpi(&s->gicv3->cpu[cte.rdbase], ite.intid, 1);
162
}
163
164
if (cmd == DISCARD) {
165
- IteEntry ite = {};
166
+ IteEntry itee = {};
167
/* remove mapping from interrupt translation table */
168
- return update_ite(s, eventid, &dte, ite) ? CMD_CONTINUE : CMD_STALL;
169
+ return update_ite(s, eventid, &dte, itee) ? CMD_CONTINUE : CMD_STALL;
170
}
171
return CMD_CONTINUE;
172
}
173
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_movall(GICv3ITSState *s, const uint64_t *cmdpkt)
174
175
static ItsCmdResult process_movi(GICv3ITSState *s, const uint64_t *cmdpkt)
176
{
177
- MemTxResult res = MEMTX_OK;
178
- uint32_t devid, eventid, intid;
179
- uint16_t old_icid, new_icid;
180
- bool ite_valid;
181
+ uint32_t devid, eventid;
182
+ uint16_t new_icid;
183
uint64_t num_eventids;
184
IteEntry ite = {};
185
DTEntry dte;
186
CTEntry old_cte, new_cte;
187
+ ITEntry old_ite;
188
189
devid = FIELD_EX64(cmdpkt[0], MOVI_0, DEVICEID);
190
eventid = FIELD_EX64(cmdpkt[1], MOVI_1, EVENTID);
191
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_movi(GICv3ITSState *s, const uint64_t *cmdpkt)
192
return CMD_CONTINUE;
193
}
194
195
- ite_valid = get_ite(s, eventid, &dte, &old_icid, &intid, &res);
196
- if (res != MEMTX_OK) {
197
+ if (get_ite(s, eventid, &dte, &old_ite) != MEMTX_OK) {
198
return CMD_STALL;
199
}
200
201
- if (!ite_valid) {
202
+ if (!old_ite.valid || old_ite.inttype != ITE_INTTYPE_PHYSICAL) {
203
qemu_log_mask(LOG_GUEST_ERROR,
204
"%s: invalid command attributes: invalid ITE\n",
205
__func__);
206
return CMD_CONTINUE;
207
}
208
209
- if (old_icid >= s->ct.num_entries) {
210
+ if (old_ite.icid >= s->ct.num_entries) {
211
qemu_log_mask(LOG_GUEST_ERROR,
212
"%s: invalid ICID 0x%x in ITE (table corrupted?)\n",
213
- __func__, old_icid);
214
+ __func__, old_ite.icid);
215
return CMD_CONTINUE;
216
}
217
218
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_movi(GICv3ITSState *s, const uint64_t *cmdpkt)
219
return CMD_CONTINUE;
220
}
221
222
- if (get_cte(s, old_icid, &old_cte) != MEMTX_OK) {
223
+ if (get_cte(s, old_ite.icid, &old_cte) != MEMTX_OK) {
224
return CMD_STALL;
225
}
226
if (!old_cte.valid) {
227
qemu_log_mask(LOG_GUEST_ERROR,
228
"%s: invalid command attributes: "
229
"invalid CTE for old ICID 0x%x\n",
230
- __func__, old_icid);
231
+ __func__, old_ite.icid);
232
return CMD_CONTINUE;
233
}
234
235
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_movi(GICv3ITSState *s, const uint64_t *cmdpkt)
236
/* Move the LPI from the old redistributor to the new one */
237
gicv3_redist_mov_lpi(&s->gicv3->cpu[old_cte.rdbase],
238
&s->gicv3->cpu[new_cte.rdbase],
239
- intid);
240
+ old_ite.intid);
241
}
242
243
/* Update the ICID field in the interrupt translation table entry */
244
ite.itel = FIELD_DP64(ite.itel, ITE_L, VALID, 1);
245
ite.itel = FIELD_DP64(ite.itel, ITE_L, INTTYPE, ITE_INTTYPE_PHYSICAL);
246
- ite.itel = FIELD_DP64(ite.itel, ITE_L, INTID, intid);
247
+ ite.itel = FIELD_DP64(ite.itel, ITE_L, INTID, old_ite.intid);
248
ite.itel = FIELD_DP64(ite.itel, ITE_L, ICID, new_icid);
249
ite.iteh = FIELD_DP32(ite.iteh, ITE_H, DOORBELL, INTID_SPURIOUS);
250
return update_ite(s, eventid, &dte, ite) ? CMD_CONTINUE : CMD_STALL;
251
--
252
2.25.1
253
254
diff view generated by jsdifflib
1
The M profile CPU's MPU has an awkward corner case which we
1
Make the update_ite() struct use the new ITEntry struct, so that
2
would like to implement with a different MMU index.
2
callers don't need to assemble the in-memory ITE data themselves, and
3
3
only get_ite() and update_ite() need to care about that in-memory
4
We can avoid having to bump the number of MMU modes ARM
4
layout. We can then drop the no-longer-used IteEntry struct
5
uses, because some of our existing MMU indexes are only
5
definition.
6
used by non-M-profile CPUs, so we can borrow one.
7
To avoid that getting too confusing, clean up the code
8
to try to keep the two meanings of the index separate.
9
10
Instead of ARMMMUIdx enum values being identical to core QEMU
11
MMU index values, they are now the core index values with some
12
high bits set. Any particular CPU always uses the same high
13
bits (so eventually A profile cores and M profile cores will
14
use different bits). New functions arm_to_core_mmu_idx()
15
and core_to_arm_mmu_idx() convert between the two.
16
17
In general core index values are stored in 'int' types, and
18
ARM values are stored in ARMMMUIdx types.
19
6
20
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
21
Message-id: 1493122030-32191-3-git-send-email-peter.maydell@linaro.org
8
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
9
Message-id: 20220201193207.2771604-10-peter.maydell@linaro.org
22
---
10
---
23
target/arm/cpu.h | 71 ++++++++++++++++-----
11
hw/intc/arm_gicv3_its.c | 62 +++++++++++++++++++++--------------------
24
target/arm/translate.h | 2 +-
12
1 file changed, 32 insertions(+), 30 deletions(-)
25
target/arm/helper.c | 151 ++++++++++++++++++++++++---------------------
26
target/arm/op_helper.c | 3 +-
27
target/arm/translate-a64.c | 18 ++++--
28
target/arm/translate.c | 10 +--
29
6 files changed, 156 insertions(+), 99 deletions(-)
30
13
31
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
14
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
32
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
33
--- a/target/arm/cpu.h
16
--- a/hw/intc/arm_gicv3_its.c
34
+++ b/target/arm/cpu.h
17
+++ b/hw/intc/arm_gicv3_its.c
35
@@ -XXX,XX +XXX,XX @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx,
18
@@ -XXX,XX +XXX,XX @@ typedef enum ItsCmdType {
36
* for the accesses done as part of a stage 1 page table walk, rather than
19
INTERRUPT = 3,
37
* having to walk the stage 2 page table over and over.)
20
} ItsCmdType;
38
*
21
39
+ * The ARMMMUIdx and the mmu index value used by the core QEMU TLB code
22
-typedef struct {
40
+ * are not quite the same -- different CPU types (most notably M profile
23
- uint32_t iteh;
41
+ * vs A/R profile) would like to use MMU indexes with different semantics,
24
- uint64_t itel;
42
+ * but since we don't ever need to use all of those in a single CPU we
25
-} IteEntry;
43
+ * can avoid setting NB_MMU_MODES to more than 8. The lower bits of
26
-
44
+ * ARMMMUIdx are the core TLB mmu index, and the higher bits are always
27
typedef struct DTEntry {
45
+ * the same for any particular CPU.
28
bool valid;
46
+ * Variables of type ARMMUIdx are always full values, and the core
29
unsigned size;
47
+ * index values are in variables of type 'int'.
30
@@ -XXX,XX +XXX,XX @@ static MemTxResult get_cte(GICv3ITSState *s, uint16_t icid, CTEntry *cte)
48
+ *
31
return MEMTX_OK;
49
* Our enumeration includes at the end some entries which are not "true"
32
}
50
* mmu_idx values in that they don't have corresponding TLBs and are only
33
51
* valid for doing slow path page table walks.
34
+/*
52
@@ -XXX,XX +XXX,XX @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx,
35
+ * Update the Interrupt Table entry at index @evinted in the table specified
53
* of the AT/ATS operations.
36
+ * by the dte @dte. Returns true on success, false if there was a memory
54
* The values used are carefully arranged to make mmu_idx => EL lookup easy.
37
+ * access error.
55
*/
38
+ */
56
+#define ARM_MMU_IDX_A 0x10 /* A profile (and M profile, for the moment) */
39
static bool update_ite(GICv3ITSState *s, uint32_t eventid, const DTEntry *dte,
57
+#define ARM_MMU_IDX_NOTLB 0x20 /* does not have a TLB */
40
- IteEntry ite)
41
+ const ITEntry *ite)
42
{
43
AddressSpace *as = &s->gicv3->dma_as;
44
MemTxResult res = MEMTX_OK;
45
hwaddr iteaddr = dte->ittaddr + eventid * ITS_ITT_ENTRY_SIZE;
46
+ uint64_t itel = 0;
47
+ uint32_t iteh = 0;
48
49
- address_space_stq_le(as, iteaddr, ite.itel, MEMTXATTRS_UNSPECIFIED, &res);
50
-
51
- if (res == MEMTX_OK) {
52
- address_space_stl_le(as, iteaddr + 8, ite.iteh,
53
- MEMTXATTRS_UNSPECIFIED, &res);
54
+ if (ite->valid) {
55
+ itel = FIELD_DP64(itel, ITE_L, VALID, 1);
56
+ itel = FIELD_DP64(itel, ITE_L, INTTYPE, ite->inttype);
57
+ itel = FIELD_DP64(itel, ITE_L, INTID, ite->intid);
58
+ itel = FIELD_DP64(itel, ITE_L, ICID, ite->icid);
59
+ itel = FIELD_DP64(itel, ITE_L, VPEID, ite->vpeid);
60
+ iteh = FIELD_DP32(iteh, ITE_H, DOORBELL, ite->doorbell);
61
}
58
+
62
+
59
+#define ARM_MMU_IDX_TYPE_MASK (~0x7)
63
+ address_space_stq_le(as, iteaddr, itel, MEMTXATTRS_UNSPECIFIED, &res);
60
+#define ARM_MMU_IDX_COREIDX_MASK 0x7
64
if (res != MEMTX_OK) {
61
+
65
return false;
62
typedef enum ARMMMUIdx {
66
- } else {
63
- ARMMMUIdx_S12NSE0 = 0,
67
- return true;
64
- ARMMMUIdx_S12NSE1 = 1,
68
}
65
- ARMMMUIdx_S1E2 = 2,
69
+ address_space_stl_le(as, iteaddr + 8, iteh, MEMTXATTRS_UNSPECIFIED, &res);
66
- ARMMMUIdx_S1E3 = 3,
70
+ return res == MEMTX_OK;
67
- ARMMMUIdx_S1SE0 = 4,
68
- ARMMMUIdx_S1SE1 = 5,
69
- ARMMMUIdx_S2NS = 6,
70
+ ARMMMUIdx_S12NSE0 = 0 | ARM_MMU_IDX_A,
71
+ ARMMMUIdx_S12NSE1 = 1 | ARM_MMU_IDX_A,
72
+ ARMMMUIdx_S1E2 = 2 | ARM_MMU_IDX_A,
73
+ ARMMMUIdx_S1E3 = 3 | ARM_MMU_IDX_A,
74
+ ARMMMUIdx_S1SE0 = 4 | ARM_MMU_IDX_A,
75
+ ARMMMUIdx_S1SE1 = 5 | ARM_MMU_IDX_A,
76
+ ARMMMUIdx_S2NS = 6 | ARM_MMU_IDX_A,
77
/* Indexes below here don't have TLBs and are used only for AT system
78
* instructions or for the first stage of an S12 page table walk.
79
*/
80
- ARMMMUIdx_S1NSE0 = 7,
81
- ARMMMUIdx_S1NSE1 = 8,
82
+ ARMMMUIdx_S1NSE0 = 0 | ARM_MMU_IDX_NOTLB,
83
+ ARMMMUIdx_S1NSE1 = 1 | ARM_MMU_IDX_NOTLB,
84
} ARMMMUIdx;
85
86
+/* Bit macros for the core-mmu-index values for each index,
87
+ * for use when calling tlb_flush_by_mmuidx() and friends.
88
+ */
89
+typedef enum ARMMMUIdxBit {
90
+ ARMMMUIdxBit_S12NSE0 = 1 << 0,
91
+ ARMMMUIdxBit_S12NSE1 = 1 << 1,
92
+ ARMMMUIdxBit_S1E2 = 1 << 2,
93
+ ARMMMUIdxBit_S1E3 = 1 << 3,
94
+ ARMMMUIdxBit_S1SE0 = 1 << 4,
95
+ ARMMMUIdxBit_S1SE1 = 1 << 5,
96
+ ARMMMUIdxBit_S2NS = 1 << 6,
97
+} ARMMMUIdxBit;
98
+
99
#define MMU_USER_IDX 0
100
101
+static inline int arm_to_core_mmu_idx(ARMMMUIdx mmu_idx)
102
+{
103
+ return mmu_idx & ARM_MMU_IDX_COREIDX_MASK;
104
+}
105
+
106
+static inline ARMMMUIdx core_to_arm_mmu_idx(CPUARMState *env, int mmu_idx)
107
+{
108
+ return mmu_idx | ARM_MMU_IDX_A;
109
+}
110
+
111
/* Return the exception level we're running at if this is our mmu_idx */
112
static inline int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx)
113
{
114
- assert(mmu_idx < ARMMMUIdx_S2NS);
115
- return mmu_idx & 3;
116
+ switch (mmu_idx & ARM_MMU_IDX_TYPE_MASK) {
117
+ case ARM_MMU_IDX_A:
118
+ return mmu_idx & 3;
119
+ default:
120
+ g_assert_not_reached();
121
+ }
122
}
71
}
123
72
124
/* Determine the current mmu_idx to use for normal loads/stores */
73
/*
125
@@ -XXX,XX +XXX,XX @@ static inline int cpu_mmu_index(CPUARMState *env, bool ifetch)
74
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult do_process_its_cmd(GICv3ITSState *s, uint32_t devid,
126
int el = arm_current_el(env);
127
128
if (el < 2 && arm_is_secure_below_el3(env)) {
129
- return ARMMMUIdx_S1SE0 + el;
130
+ return arm_to_core_mmu_idx(ARMMMUIdx_S1SE0 + el);
131
}
75
}
132
return el;
76
77
if (cmd == DISCARD) {
78
- IteEntry itee = {};
79
+ ITEntry ite = {};
80
/* remove mapping from interrupt translation table */
81
- return update_ite(s, eventid, &dte, itee) ? CMD_CONTINUE : CMD_STALL;
82
+ ite.valid = false;
83
+ return update_ite(s, eventid, &dte, &ite) ? CMD_CONTINUE : CMD_STALL;
84
}
85
return CMD_CONTINUE;
133
}
86
}
134
@@ -XXX,XX +XXX,XX @@ static inline uint32_t arm_regime_tbi1(CPUARMState *env, ARMMMUIdx mmu_idx)
87
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_mapti(GICv3ITSState *s, const uint64_t *cmdpkt,
135
static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
88
uint64_t num_eventids;
136
target_ulong *cs_base, uint32_t *flags)
89
uint32_t num_intids;
137
{
90
uint16_t icid = 0;
138
- ARMMMUIdx mmu_idx = cpu_mmu_index(env, false);
91
- IteEntry ite = {};
139
+ ARMMMUIdx mmu_idx = core_to_arm_mmu_idx(env, cpu_mmu_index(env, false));
92
DTEntry dte;
140
if (is_a64(env)) {
93
+ ITEntry ite;
141
*pc = env->pc;
94
142
*flags = ARM_TBFLAG_AARCH64_STATE_MASK;
95
devid = (cmdpkt[0] & DEVID_MASK) >> DEVID_SHIFT;
143
@@ -XXX,XX +XXX,XX @@ static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
96
eventid = cmdpkt[1] & EVENTID_MASK;
144
<< ARM_TBFLAG_XSCALE_CPAR_SHIFT);
97
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_mapti(GICv3ITSState *s, const uint64_t *cmdpkt,
145
}
98
}
146
99
147
- *flags |= (mmu_idx << ARM_TBFLAG_MMUIDX_SHIFT);
100
/* add ite entry to interrupt translation table */
148
+ *flags |= (arm_to_core_mmu_idx(mmu_idx) << ARM_TBFLAG_MMUIDX_SHIFT);
101
- ite.itel = FIELD_DP64(ite.itel, ITE_L, VALID, true);
149
102
- ite.itel = FIELD_DP64(ite.itel, ITE_L, INTTYPE, ITE_INTTYPE_PHYSICAL);
150
/* The SS_ACTIVE and PSTATE_SS bits correspond to the state machine
103
- ite.itel = FIELD_DP64(ite.itel, ITE_L, INTID, pIntid);
151
* states defined in the ARM ARM for software singlestep:
104
- ite.itel = FIELD_DP64(ite.itel, ITE_L, ICID, icid);
152
diff --git a/target/arm/translate.h b/target/arm/translate.h
105
- ite.iteh = FIELD_DP32(ite.iteh, ITE_H, DOORBELL, INTID_SPURIOUS);
153
index XXXXXXX..XXXXXXX 100644
106
-
154
--- a/target/arm/translate.h
107
- return update_ite(s, eventid, &dte, ite) ? CMD_CONTINUE : CMD_STALL;
155
+++ b/target/arm/translate.h
108
+ ite.valid = true;
156
@@ -XXX,XX +XXX,XX @@ static inline int arm_dc_feature(DisasContext *dc, int feature)
109
+ ite.inttype = ITE_INTTYPE_PHYSICAL;
157
110
+ ite.intid = pIntid;
158
static inline int get_mem_index(DisasContext *s)
111
+ ite.icid = icid;
159
{
112
+ ite.doorbell = INTID_SPURIOUS;
160
- return s->mmu_idx;
113
+ ite.vpeid = 0;
161
+ return arm_to_core_mmu_idx(s->mmu_idx);
114
+ return update_ite(s, eventid, &dte, &ite) ? CMD_CONTINUE : CMD_STALL;
162
}
115
}
163
116
164
/* Function used to determine the target exception EL when otherwise not known
117
/*
165
diff --git a/target/arm/helper.c b/target/arm/helper.c
118
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_movi(GICv3ITSState *s, const uint64_t *cmdpkt)
166
index XXXXXXX..XXXXXXX 100644
119
uint32_t devid, eventid;
167
--- a/target/arm/helper.c
120
uint16_t new_icid;
168
+++ b/target/arm/helper.c
121
uint64_t num_eventids;
169
@@ -XXX,XX +XXX,XX @@ static void tlbiall_nsnh_write(CPUARMState *env, const ARMCPRegInfo *ri,
122
- IteEntry ite = {};
170
CPUState *cs = ENV_GET_CPU(env);
123
DTEntry dte;
171
124
CTEntry old_cte, new_cte;
172
tlb_flush_by_mmuidx(cs,
125
ITEntry old_ite;
173
- (1 << ARMMMUIdx_S12NSE1) |
126
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_movi(GICv3ITSState *s, const uint64_t *cmdpkt)
174
- (1 << ARMMMUIdx_S12NSE0) |
127
}
175
- (1 << ARMMMUIdx_S2NS));
128
176
+ ARMMMUIdxBit_S12NSE1 |
129
/* Update the ICID field in the interrupt translation table entry */
177
+ ARMMMUIdxBit_S12NSE0 |
130
- ite.itel = FIELD_DP64(ite.itel, ITE_L, VALID, 1);
178
+ ARMMMUIdxBit_S2NS);
131
- ite.itel = FIELD_DP64(ite.itel, ITE_L, INTTYPE, ITE_INTTYPE_PHYSICAL);
132
- ite.itel = FIELD_DP64(ite.itel, ITE_L, INTID, old_ite.intid);
133
- ite.itel = FIELD_DP64(ite.itel, ITE_L, ICID, new_icid);
134
- ite.iteh = FIELD_DP32(ite.iteh, ITE_H, DOORBELL, INTID_SPURIOUS);
135
- return update_ite(s, eventid, &dte, ite) ? CMD_CONTINUE : CMD_STALL;
136
+ old_ite.icid = new_icid;
137
+ return update_ite(s, eventid, &dte, &old_ite) ? CMD_CONTINUE : CMD_STALL;
179
}
138
}
180
139
181
static void tlbiall_nsnh_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
140
/*
182
@@ -XXX,XX +XXX,XX @@ static void tlbiall_nsnh_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
183
CPUState *cs = ENV_GET_CPU(env);
184
185
tlb_flush_by_mmuidx_all_cpus_synced(cs,
186
- (1 << ARMMMUIdx_S12NSE1) |
187
- (1 << ARMMMUIdx_S12NSE0) |
188
- (1 << ARMMMUIdx_S2NS));
189
+ ARMMMUIdxBit_S12NSE1 |
190
+ ARMMMUIdxBit_S12NSE0 |
191
+ ARMMMUIdxBit_S2NS);
192
}
193
194
static void tlbiipas2_write(CPUARMState *env, const ARMCPRegInfo *ri,
195
@@ -XXX,XX +XXX,XX @@ static void tlbiipas2_write(CPUARMState *env, const ARMCPRegInfo *ri,
196
197
pageaddr = sextract64(value << 12, 0, 40);
198
199
- tlb_flush_page_by_mmuidx(cs, pageaddr, (1 << ARMMMUIdx_S2NS));
200
+ tlb_flush_page_by_mmuidx(cs, pageaddr, ARMMMUIdxBit_S2NS);
201
}
202
203
static void tlbiipas2_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
204
@@ -XXX,XX +XXX,XX @@ static void tlbiipas2_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
205
pageaddr = sextract64(value << 12, 0, 40);
206
207
tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr,
208
- (1 << ARMMMUIdx_S2NS));
209
+ ARMMMUIdxBit_S2NS);
210
}
211
212
static void tlbiall_hyp_write(CPUARMState *env, const ARMCPRegInfo *ri,
213
@@ -XXX,XX +XXX,XX @@ static void tlbiall_hyp_write(CPUARMState *env, const ARMCPRegInfo *ri,
214
{
215
CPUState *cs = ENV_GET_CPU(env);
216
217
- tlb_flush_by_mmuidx(cs, (1 << ARMMMUIdx_S1E2));
218
+ tlb_flush_by_mmuidx(cs, ARMMMUIdxBit_S1E2);
219
}
220
221
static void tlbiall_hyp_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
222
@@ -XXX,XX +XXX,XX @@ static void tlbiall_hyp_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
223
{
224
CPUState *cs = ENV_GET_CPU(env);
225
226
- tlb_flush_by_mmuidx_all_cpus_synced(cs, (1 << ARMMMUIdx_S1E2));
227
+ tlb_flush_by_mmuidx_all_cpus_synced(cs, ARMMMUIdxBit_S1E2);
228
}
229
230
static void tlbimva_hyp_write(CPUARMState *env, const ARMCPRegInfo *ri,
231
@@ -XXX,XX +XXX,XX @@ static void tlbimva_hyp_write(CPUARMState *env, const ARMCPRegInfo *ri,
232
CPUState *cs = ENV_GET_CPU(env);
233
uint64_t pageaddr = value & ~MAKE_64BIT_MASK(0, 12);
234
235
- tlb_flush_page_by_mmuidx(cs, pageaddr, (1 << ARMMMUIdx_S1E2));
236
+ tlb_flush_page_by_mmuidx(cs, pageaddr, ARMMMUIdxBit_S1E2);
237
}
238
239
static void tlbimva_hyp_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
240
@@ -XXX,XX +XXX,XX @@ static void tlbimva_hyp_is_write(CPUARMState *env, const ARMCPRegInfo *ri,
241
uint64_t pageaddr = value & ~MAKE_64BIT_MASK(0, 12);
242
243
tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr,
244
- (1 << ARMMMUIdx_S1E2));
245
+ ARMMMUIdxBit_S1E2);
246
}
247
248
static const ARMCPRegInfo cp_reginfo[] = {
249
@@ -XXX,XX +XXX,XX @@ static void vttbr_write(CPUARMState *env, const ARMCPRegInfo *ri,
250
/* Accesses to VTTBR may change the VMID so we must flush the TLB. */
251
if (raw_read(env, ri) != value) {
252
tlb_flush_by_mmuidx(cs,
253
- (1 << ARMMMUIdx_S12NSE1) |
254
- (1 << ARMMMUIdx_S12NSE0) |
255
- (1 << ARMMMUIdx_S2NS));
256
+ ARMMMUIdxBit_S12NSE1 |
257
+ ARMMMUIdxBit_S12NSE0 |
258
+ ARMMMUIdxBit_S2NS);
259
raw_write(env, ri, value);
260
}
261
}
262
@@ -XXX,XX +XXX,XX @@ static void tlbi_aa64_vmalle1_write(CPUARMState *env, const ARMCPRegInfo *ri,
263
264
if (arm_is_secure_below_el3(env)) {
265
tlb_flush_by_mmuidx(cs,
266
- (1 << ARMMMUIdx_S1SE1) |
267
- (1 << ARMMMUIdx_S1SE0));
268
+ ARMMMUIdxBit_S1SE1 |
269
+ ARMMMUIdxBit_S1SE0);
270
} else {
271
tlb_flush_by_mmuidx(cs,
272
- (1 << ARMMMUIdx_S12NSE1) |
273
- (1 << ARMMMUIdx_S12NSE0));
274
+ ARMMMUIdxBit_S12NSE1 |
275
+ ARMMMUIdxBit_S12NSE0);
276
}
277
}
278
279
@@ -XXX,XX +XXX,XX @@ static void tlbi_aa64_vmalle1is_write(CPUARMState *env, const ARMCPRegInfo *ri,
280
281
if (sec) {
282
tlb_flush_by_mmuidx_all_cpus_synced(cs,
283
- (1 << ARMMMUIdx_S1SE1) |
284
- (1 << ARMMMUIdx_S1SE0));
285
+ ARMMMUIdxBit_S1SE1 |
286
+ ARMMMUIdxBit_S1SE0);
287
} else {
288
tlb_flush_by_mmuidx_all_cpus_synced(cs,
289
- (1 << ARMMMUIdx_S12NSE1) |
290
- (1 << ARMMMUIdx_S12NSE0));
291
+ ARMMMUIdxBit_S12NSE1 |
292
+ ARMMMUIdxBit_S12NSE0);
293
}
294
}
295
296
@@ -XXX,XX +XXX,XX @@ static void tlbi_aa64_alle1_write(CPUARMState *env, const ARMCPRegInfo *ri,
297
298
if (arm_is_secure_below_el3(env)) {
299
tlb_flush_by_mmuidx(cs,
300
- (1 << ARMMMUIdx_S1SE1) |
301
- (1 << ARMMMUIdx_S1SE0));
302
+ ARMMMUIdxBit_S1SE1 |
303
+ ARMMMUIdxBit_S1SE0);
304
} else {
305
if (arm_feature(env, ARM_FEATURE_EL2)) {
306
tlb_flush_by_mmuidx(cs,
307
- (1 << ARMMMUIdx_S12NSE1) |
308
- (1 << ARMMMUIdx_S12NSE0) |
309
- (1 << ARMMMUIdx_S2NS));
310
+ ARMMMUIdxBit_S12NSE1 |
311
+ ARMMMUIdxBit_S12NSE0 |
312
+ ARMMMUIdxBit_S2NS);
313
} else {
314
tlb_flush_by_mmuidx(cs,
315
- (1 << ARMMMUIdx_S12NSE1) |
316
- (1 << ARMMMUIdx_S12NSE0));
317
+ ARMMMUIdxBit_S12NSE1 |
318
+ ARMMMUIdxBit_S12NSE0);
319
}
320
}
321
}
322
@@ -XXX,XX +XXX,XX @@ static void tlbi_aa64_alle2_write(CPUARMState *env, const ARMCPRegInfo *ri,
323
ARMCPU *cpu = arm_env_get_cpu(env);
324
CPUState *cs = CPU(cpu);
325
326
- tlb_flush_by_mmuidx(cs, (1 << ARMMMUIdx_S1E2));
327
+ tlb_flush_by_mmuidx(cs, ARMMMUIdxBit_S1E2);
328
}
329
330
static void tlbi_aa64_alle3_write(CPUARMState *env, const ARMCPRegInfo *ri,
331
@@ -XXX,XX +XXX,XX @@ static void tlbi_aa64_alle3_write(CPUARMState *env, const ARMCPRegInfo *ri,
332
ARMCPU *cpu = arm_env_get_cpu(env);
333
CPUState *cs = CPU(cpu);
334
335
- tlb_flush_by_mmuidx(cs, (1 << ARMMMUIdx_S1E3));
336
+ tlb_flush_by_mmuidx(cs, ARMMMUIdxBit_S1E3);
337
}
338
339
static void tlbi_aa64_alle1is_write(CPUARMState *env, const ARMCPRegInfo *ri,
340
@@ -XXX,XX +XXX,XX @@ static void tlbi_aa64_alle1is_write(CPUARMState *env, const ARMCPRegInfo *ri,
341
342
if (sec) {
343
tlb_flush_by_mmuidx_all_cpus_synced(cs,
344
- (1 << ARMMMUIdx_S1SE1) |
345
- (1 << ARMMMUIdx_S1SE0));
346
+ ARMMMUIdxBit_S1SE1 |
347
+ ARMMMUIdxBit_S1SE0);
348
} else if (has_el2) {
349
tlb_flush_by_mmuidx_all_cpus_synced(cs,
350
- (1 << ARMMMUIdx_S12NSE1) |
351
- (1 << ARMMMUIdx_S12NSE0) |
352
- (1 << ARMMMUIdx_S2NS));
353
+ ARMMMUIdxBit_S12NSE1 |
354
+ ARMMMUIdxBit_S12NSE0 |
355
+ ARMMMUIdxBit_S2NS);
356
} else {
357
tlb_flush_by_mmuidx_all_cpus_synced(cs,
358
- (1 << ARMMMUIdx_S12NSE1) |
359
- (1 << ARMMMUIdx_S12NSE0));
360
+ ARMMMUIdxBit_S12NSE1 |
361
+ ARMMMUIdxBit_S12NSE0);
362
}
363
}
364
365
@@ -XXX,XX +XXX,XX @@ static void tlbi_aa64_alle2is_write(CPUARMState *env, const ARMCPRegInfo *ri,
366
{
367
CPUState *cs = ENV_GET_CPU(env);
368
369
- tlb_flush_by_mmuidx_all_cpus_synced(cs, (1 << ARMMMUIdx_S1E2));
370
+ tlb_flush_by_mmuidx_all_cpus_synced(cs, ARMMMUIdxBit_S1E2);
371
}
372
373
static void tlbi_aa64_alle3is_write(CPUARMState *env, const ARMCPRegInfo *ri,
374
@@ -XXX,XX +XXX,XX @@ static void tlbi_aa64_alle3is_write(CPUARMState *env, const ARMCPRegInfo *ri,
375
{
376
CPUState *cs = ENV_GET_CPU(env);
377
378
- tlb_flush_by_mmuidx_all_cpus_synced(cs, (1 << ARMMMUIdx_S1E3));
379
+ tlb_flush_by_mmuidx_all_cpus_synced(cs, ARMMMUIdxBit_S1E3);
380
}
381
382
static void tlbi_aa64_vae1_write(CPUARMState *env, const ARMCPRegInfo *ri,
383
@@ -XXX,XX +XXX,XX @@ static void tlbi_aa64_vae1_write(CPUARMState *env, const ARMCPRegInfo *ri,
384
385
if (arm_is_secure_below_el3(env)) {
386
tlb_flush_page_by_mmuidx(cs, pageaddr,
387
- (1 << ARMMMUIdx_S1SE1) |
388
- (1 << ARMMMUIdx_S1SE0));
389
+ ARMMMUIdxBit_S1SE1 |
390
+ ARMMMUIdxBit_S1SE0);
391
} else {
392
tlb_flush_page_by_mmuidx(cs, pageaddr,
393
- (1 << ARMMMUIdx_S12NSE1) |
394
- (1 << ARMMMUIdx_S12NSE0));
395
+ ARMMMUIdxBit_S12NSE1 |
396
+ ARMMMUIdxBit_S12NSE0);
397
}
398
}
399
400
@@ -XXX,XX +XXX,XX @@ static void tlbi_aa64_vae2_write(CPUARMState *env, const ARMCPRegInfo *ri,
401
CPUState *cs = CPU(cpu);
402
uint64_t pageaddr = sextract64(value << 12, 0, 56);
403
404
- tlb_flush_page_by_mmuidx(cs, pageaddr, (1 << ARMMMUIdx_S1E2));
405
+ tlb_flush_page_by_mmuidx(cs, pageaddr, ARMMMUIdxBit_S1E2);
406
}
407
408
static void tlbi_aa64_vae3_write(CPUARMState *env, const ARMCPRegInfo *ri,
409
@@ -XXX,XX +XXX,XX @@ static void tlbi_aa64_vae3_write(CPUARMState *env, const ARMCPRegInfo *ri,
410
CPUState *cs = CPU(cpu);
411
uint64_t pageaddr = sextract64(value << 12, 0, 56);
412
413
- tlb_flush_page_by_mmuidx(cs, pageaddr, (1 << ARMMMUIdx_S1E3));
414
+ tlb_flush_page_by_mmuidx(cs, pageaddr, ARMMMUIdxBit_S1E3);
415
}
416
417
static void tlbi_aa64_vae1is_write(CPUARMState *env, const ARMCPRegInfo *ri,
418
@@ -XXX,XX +XXX,XX @@ static void tlbi_aa64_vae1is_write(CPUARMState *env, const ARMCPRegInfo *ri,
419
420
if (sec) {
421
tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr,
422
- (1 << ARMMMUIdx_S1SE1) |
423
- (1 << ARMMMUIdx_S1SE0));
424
+ ARMMMUIdxBit_S1SE1 |
425
+ ARMMMUIdxBit_S1SE0);
426
} else {
427
tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr,
428
- (1 << ARMMMUIdx_S12NSE1) |
429
- (1 << ARMMMUIdx_S12NSE0));
430
+ ARMMMUIdxBit_S12NSE1 |
431
+ ARMMMUIdxBit_S12NSE0);
432
}
433
}
434
435
@@ -XXX,XX +XXX,XX @@ static void tlbi_aa64_vae2is_write(CPUARMState *env, const ARMCPRegInfo *ri,
436
uint64_t pageaddr = sextract64(value << 12, 0, 56);
437
438
tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr,
439
- (1 << ARMMMUIdx_S1E2));
440
+ ARMMMUIdxBit_S1E2);
441
}
442
443
static void tlbi_aa64_vae3is_write(CPUARMState *env, const ARMCPRegInfo *ri,
444
@@ -XXX,XX +XXX,XX @@ static void tlbi_aa64_vae3is_write(CPUARMState *env, const ARMCPRegInfo *ri,
445
uint64_t pageaddr = sextract64(value << 12, 0, 56);
446
447
tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr,
448
- (1 << ARMMMUIdx_S1E3));
449
+ ARMMMUIdxBit_S1E3);
450
}
451
452
static void tlbi_aa64_ipas2e1_write(CPUARMState *env, const ARMCPRegInfo *ri,
453
@@ -XXX,XX +XXX,XX @@ static void tlbi_aa64_ipas2e1_write(CPUARMState *env, const ARMCPRegInfo *ri,
454
455
pageaddr = sextract64(value << 12, 0, 48);
456
457
- tlb_flush_page_by_mmuidx(cs, pageaddr, (1 << ARMMMUIdx_S2NS));
458
+ tlb_flush_page_by_mmuidx(cs, pageaddr, ARMMMUIdxBit_S2NS);
459
}
460
461
static void tlbi_aa64_ipas2e1is_write(CPUARMState *env, const ARMCPRegInfo *ri,
462
@@ -XXX,XX +XXX,XX @@ static void tlbi_aa64_ipas2e1is_write(CPUARMState *env, const ARMCPRegInfo *ri,
463
pageaddr = sextract64(value << 12, 0, 48);
464
465
tlb_flush_page_by_mmuidx_all_cpus_synced(cs, pageaddr,
466
- (1 << ARMMMUIdx_S2NS));
467
+ ARMMMUIdxBit_S2NS);
468
}
469
470
static CPAccessResult aa64_zva_access(CPUARMState *env, const ARMCPRegInfo *ri,
471
@@ -XXX,XX +XXX,XX @@ static inline TCR *regime_tcr(CPUARMState *env, ARMMMUIdx mmu_idx)
472
return &env->cp15.tcr_el[regime_el(env, mmu_idx)];
473
}
474
475
+/* Convert a possible stage1+2 MMU index into the appropriate
476
+ * stage 1 MMU index
477
+ */
478
+static inline ARMMMUIdx stage_1_mmu_idx(ARMMMUIdx mmu_idx)
479
+{
480
+ if (mmu_idx == ARMMMUIdx_S12NSE0 || mmu_idx == ARMMMUIdx_S12NSE1) {
481
+ mmu_idx += (ARMMMUIdx_S1NSE0 - ARMMMUIdx_S12NSE0);
482
+ }
483
+ return mmu_idx;
484
+}
485
+
486
/* Returns TBI0 value for current regime el */
487
uint32_t arm_regime_tbi0(CPUARMState *env, ARMMMUIdx mmu_idx)
488
{
489
@@ -XXX,XX +XXX,XX @@ uint32_t arm_regime_tbi0(CPUARMState *env, ARMMMUIdx mmu_idx)
490
uint32_t el;
491
492
/* For EL0 and EL1, TBI is controlled by stage 1's TCR, so convert
493
- * a stage 1+2 mmu index into the appropriate stage 1 mmu index.
494
- */
495
- if (mmu_idx == ARMMMUIdx_S12NSE0 || mmu_idx == ARMMMUIdx_S12NSE1) {
496
- mmu_idx += ARMMMUIdx_S1NSE0;
497
- }
498
+ * a stage 1+2 mmu index into the appropriate stage 1 mmu index.
499
+ */
500
+ mmu_idx = stage_1_mmu_idx(mmu_idx);
501
502
tcr = regime_tcr(env, mmu_idx);
503
el = regime_el(env, mmu_idx);
504
@@ -XXX,XX +XXX,XX @@ uint32_t arm_regime_tbi1(CPUARMState *env, ARMMMUIdx mmu_idx)
505
uint32_t el;
506
507
/* For EL0 and EL1, TBI is controlled by stage 1's TCR, so convert
508
- * a stage 1+2 mmu index into the appropriate stage 1 mmu index.
509
- */
510
- if (mmu_idx == ARMMMUIdx_S12NSE0 || mmu_idx == ARMMMUIdx_S12NSE1) {
511
- mmu_idx += ARMMMUIdx_S1NSE0;
512
- }
513
+ * a stage 1+2 mmu index into the appropriate stage 1 mmu index.
514
+ */
515
+ mmu_idx = stage_1_mmu_idx(mmu_idx);
516
517
tcr = regime_tcr(env, mmu_idx);
518
el = regime_el(env, mmu_idx);
519
@@ -XXX,XX +XXX,XX @@ static inline bool regime_using_lpae_format(CPUARMState *env,
520
* on whether the long or short descriptor format is in use. */
521
bool arm_s1_regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx)
522
{
523
- if (mmu_idx == ARMMMUIdx_S12NSE0 || mmu_idx == ARMMMUIdx_S12NSE1) {
524
- mmu_idx += ARMMMUIdx_S1NSE0;
525
- }
526
+ mmu_idx = stage_1_mmu_idx(mmu_idx);
527
528
return regime_using_lpae_format(env, mmu_idx);
529
}
530
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr(CPUARMState *env, target_ulong address,
531
int ret;
532
533
ret = get_phys_addr(env, address, access_type,
534
- mmu_idx + ARMMMUIdx_S1NSE0, &ipa, attrs,
535
+ stage_1_mmu_idx(mmu_idx), &ipa, attrs,
536
prot, page_size, fsr, fi);
537
538
/* If S1 fails or S2 is disabled, return early. */
539
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr(CPUARMState *env, target_ulong address,
540
/*
541
* For non-EL2 CPUs a stage1+stage2 translation is just stage 1.
542
*/
543
- mmu_idx += ARMMMUIdx_S1NSE0;
544
+ mmu_idx = stage_1_mmu_idx(mmu_idx);
545
}
546
}
547
548
@@ -XXX,XX +XXX,XX @@ bool arm_tlb_fill(CPUState *cs, vaddr address,
549
int ret;
550
MemTxAttrs attrs = {};
551
552
- ret = get_phys_addr(env, address, access_type, mmu_idx, &phys_addr,
553
+ ret = get_phys_addr(env, address, access_type,
554
+ core_to_arm_mmu_idx(env, mmu_idx), &phys_addr,
555
&attrs, &prot, &page_size, fsr, fi);
556
if (!ret) {
557
/* Map a single [sub]page. */
558
@@ -XXX,XX +XXX,XX @@ hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr,
559
bool ret;
560
uint32_t fsr;
561
ARMMMUFaultInfo fi = {};
562
+ ARMMMUIdx mmu_idx = core_to_arm_mmu_idx(env, cpu_mmu_index(env, false));
563
564
*attrs = (MemTxAttrs) {};
565
566
- ret = get_phys_addr(env, addr, 0, cpu_mmu_index(env, false), &phys_addr,
567
+ ret = get_phys_addr(env, addr, 0, mmu_idx, &phys_addr,
568
attrs, &prot, &page_size, &fsr, &fi);
569
570
if (ret) {
571
diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c
572
index XXXXXXX..XXXXXXX 100644
573
--- a/target/arm/op_helper.c
574
+++ b/target/arm/op_helper.c
575
@@ -XXX,XX +XXX,XX @@ void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
576
int target_el;
577
bool same_el;
578
uint32_t syn;
579
+ ARMMMUIdx arm_mmu_idx = core_to_arm_mmu_idx(env, mmu_idx);
580
581
if (retaddr) {
582
/* now we have a real cpu fault */
583
@@ -XXX,XX +XXX,XX @@ void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
584
/* the DFSR for an alignment fault depends on whether we're using
585
* the LPAE long descriptor format, or the short descriptor format
586
*/
587
- if (arm_s1_regime_using_lpae_format(env, mmu_idx)) {
588
+ if (arm_s1_regime_using_lpae_format(env, arm_mmu_idx)) {
589
env->exception.fsr = (1 << 9) | 0x21;
590
} else {
591
env->exception.fsr = 0x1;
592
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
593
index XXXXXXX..XXXXXXX 100644
594
--- a/target/arm/translate-a64.c
595
+++ b/target/arm/translate-a64.c
596
@@ -XXX,XX +XXX,XX @@ void a64_translate_init(void)
597
offsetof(CPUARMState, exclusive_high), "exclusive_high");
598
}
599
600
-static inline ARMMMUIdx get_a64_user_mem_index(DisasContext *s)
601
+static inline int get_a64_user_mem_index(DisasContext *s)
602
{
603
- /* Return the mmu_idx to use for A64 "unprivileged load/store" insns:
604
+ /* Return the core mmu_idx to use for A64 "unprivileged load/store" insns:
605
* if EL1, access as if EL0; otherwise access at current EL
606
*/
607
+ ARMMMUIdx useridx;
608
+
609
switch (s->mmu_idx) {
610
case ARMMMUIdx_S12NSE1:
611
- return ARMMMUIdx_S12NSE0;
612
+ useridx = ARMMMUIdx_S12NSE0;
613
+ break;
614
case ARMMMUIdx_S1SE1:
615
- return ARMMMUIdx_S1SE0;
616
+ useridx = ARMMMUIdx_S1SE0;
617
+ break;
618
case ARMMMUIdx_S2NS:
619
g_assert_not_reached();
620
default:
621
- return s->mmu_idx;
622
+ useridx = s->mmu_idx;
623
+ break;
624
}
625
+ return arm_to_core_mmu_idx(useridx);
626
}
627
628
void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
629
@@ -XXX,XX +XXX,XX @@ void gen_intermediate_code_a64(ARMCPU *cpu, TranslationBlock *tb)
630
dc->be_data = ARM_TBFLAG_BE_DATA(tb->flags) ? MO_BE : MO_LE;
631
dc->condexec_mask = 0;
632
dc->condexec_cond = 0;
633
- dc->mmu_idx = ARM_TBFLAG_MMUIDX(tb->flags);
634
+ dc->mmu_idx = core_to_arm_mmu_idx(env, ARM_TBFLAG_MMUIDX(tb->flags));
635
dc->tbi0 = ARM_TBFLAG_TBI0(tb->flags);
636
dc->tbi1 = ARM_TBFLAG_TBI1(tb->flags);
637
dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx);
638
diff --git a/target/arm/translate.c b/target/arm/translate.c
639
index XXXXXXX..XXXXXXX 100644
640
--- a/target/arm/translate.c
641
+++ b/target/arm/translate.c
642
@@ -XXX,XX +XXX,XX @@ static void disas_set_da_iss(DisasContext *s, TCGMemOp memop, ISSInfo issinfo)
643
disas_set_insn_syndrome(s, syn);
644
}
645
646
-static inline ARMMMUIdx get_a32_user_mem_index(DisasContext *s)
647
+static inline int get_a32_user_mem_index(DisasContext *s)
648
{
649
- /* Return the mmu_idx to use for A32/T32 "unprivileged load/store"
650
+ /* Return the core mmu_idx to use for A32/T32 "unprivileged load/store"
651
* insns:
652
* if PL2, UNPREDICTABLE (we choose to implement as if PL0)
653
* otherwise, access as if at PL0.
654
@@ -XXX,XX +XXX,XX @@ static inline ARMMMUIdx get_a32_user_mem_index(DisasContext *s)
655
case ARMMMUIdx_S1E2: /* this one is UNPREDICTABLE */
656
case ARMMMUIdx_S12NSE0:
657
case ARMMMUIdx_S12NSE1:
658
- return ARMMMUIdx_S12NSE0;
659
+ return arm_to_core_mmu_idx(ARMMMUIdx_S12NSE0);
660
case ARMMMUIdx_S1E3:
661
case ARMMMUIdx_S1SE0:
662
case ARMMMUIdx_S1SE1:
663
- return ARMMMUIdx_S1SE0;
664
+ return arm_to_core_mmu_idx(ARMMMUIdx_S1SE0);
665
case ARMMMUIdx_S2NS:
666
default:
667
g_assert_not_reached();
668
@@ -XXX,XX +XXX,XX @@ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
669
dc->be_data = ARM_TBFLAG_BE_DATA(tb->flags) ? MO_BE : MO_LE;
670
dc->condexec_mask = (ARM_TBFLAG_CONDEXEC(tb->flags) & 0xf) << 1;
671
dc->condexec_cond = ARM_TBFLAG_CONDEXEC(tb->flags) >> 4;
672
- dc->mmu_idx = ARM_TBFLAG_MMUIDX(tb->flags);
673
+ dc->mmu_idx = core_to_arm_mmu_idx(env, ARM_TBFLAG_MMUIDX(tb->flags));
674
dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx);
675
#if !defined(CONFIG_USER_ONLY)
676
dc->user = (dc->current_el == 0);
677
--
141
--
678
2.7.4
142
2.25.1
679
143
680
144
diff view generated by jsdifflib
1
From: Andrew Jones <drjones@redhat.com>
1
Currently we track in the TableDesc and CmdQDesc structs the state of
2
the GITS_BASER<n> and GITS_CBASER Valid bits. However we aren't very
3
consistent abut checking the valid field: we test it in update_cte()
4
and update_dte(), but not anywhere else we look things up in tables.
2
5
3
Cc: Shannon Zhao <zhaoshenglong@huawei.com>
6
The GIC specification says that it is UNPREDICTABLE if a guest fails
4
Signed-off-by: Andrew Jones <drjones@redhat.com>
7
to set any of these Valid bits before enabling the ITS via
5
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
8
GITS_CTLR.Enabled. So we can choose to handle Valid == 0 as
6
Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org>
9
equivalent to a zero-length table. This is in fact how we're already
7
Message-id: 20170529173751.3443-2-drjones@redhat.com
10
catching this case in most of the table-access paths: when Valid is 0
11
we leave the num_entries fields in TableDesc or CmdQDesc set to zero,
12
and then the out-of-bounds check "index >= num_entries" that we have
13
to do anyway before doing any of these table lookups will always be
14
true, catching the no-valid-table case without any extra code.
15
16
So we can remove the checks on the valid field from update_cte()
17
and update_dte(): since these happen after the bounds check there
18
was never any case when the test could fail. That means the valid
19
fields would be entirely unused, so just remove them.
20
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
21
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
22
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
23
Message-id: 20220201193207.2771604-11-peter.maydell@linaro.org
9
---
24
---
10
hw/arm/virt-acpi-build.c | 4 ++++
25
include/hw/intc/arm_gicv3_its_common.h | 2 --
11
1 file changed, 4 insertions(+)
26
hw/intc/arm_gicv3_its.c | 31 ++++++++++++--------------
27
2 files changed, 14 insertions(+), 19 deletions(-)
12
28
13
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
29
diff --git a/include/hw/intc/arm_gicv3_its_common.h b/include/hw/intc/arm_gicv3_its_common.h
14
index XXXXXXX..XXXXXXX 100644
30
index XXXXXXX..XXXXXXX 100644
15
--- a/hw/arm/virt-acpi-build.c
31
--- a/include/hw/intc/arm_gicv3_its_common.h
16
+++ b/hw/arm/virt-acpi-build.c
32
+++ b/include/hw/intc/arm_gicv3_its_common.h
17
@@ -XXX,XX +XXX,XX @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
33
@@ -XXX,XX +XXX,XX @@
18
if (nb_numa_nodes > 0) {
34
#define GITS_TRANSLATER 0x0040
19
acpi_add_table(table_offsets, tables_blob);
35
20
build_srat(tables_blob, tables->linker, vms);
36
typedef struct {
21
+ if (have_numa_distance) {
37
- bool valid;
22
+ acpi_add_table(table_offsets, tables_blob);
38
bool indirect;
23
+ build_slit(tables_blob, tables->linker);
39
uint16_t entry_sz;
24
+ }
40
uint32_t page_sz;
41
@@ -XXX,XX +XXX,XX @@ typedef struct {
42
} TableDesc;
43
44
typedef struct {
45
- bool valid;
46
uint32_t num_entries;
47
uint64_t base_addr;
48
} CmdQDesc;
49
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
50
index XXXXXXX..XXXXXXX 100644
51
--- a/hw/intc/arm_gicv3_its.c
52
+++ b/hw/intc/arm_gicv3_its.c
53
@@ -XXX,XX +XXX,XX @@ static bool update_cte(GICv3ITSState *s, uint16_t icid, const CTEntry *cte)
54
uint64_t cteval = 0;
55
MemTxResult res = MEMTX_OK;
56
57
- if (!s->ct.valid) {
58
- return true;
59
- }
60
-
61
if (cte->valid) {
62
/* add mapping entry to collection table */
63
cteval = FIELD_DP64(cteval, CTE, VALID, 1);
64
@@ -XXX,XX +XXX,XX @@ static bool update_dte(GICv3ITSState *s, uint32_t devid, const DTEntry *dte)
65
uint64_t dteval = 0;
66
MemTxResult res = MEMTX_OK;
67
68
- if (s->dt.valid) {
69
- if (dte->valid) {
70
- /* add mapping entry to device table */
71
- dteval = FIELD_DP64(dteval, DTE, VALID, 1);
72
- dteval = FIELD_DP64(dteval, DTE, SIZE, dte->size);
73
- dteval = FIELD_DP64(dteval, DTE, ITTADDR, dte->ittaddr);
74
- }
75
- } else {
76
- return true;
77
+ if (dte->valid) {
78
+ /* add mapping entry to device table */
79
+ dteval = FIELD_DP64(dteval, DTE, VALID, 1);
80
+ dteval = FIELD_DP64(dteval, DTE, SIZE, dte->size);
81
+ dteval = FIELD_DP64(dteval, DTE, ITTADDR, dte->ittaddr);
25
}
82
}
26
83
27
if (its_class_name() && !vmc->no_its) {
84
entry_addr = table_entry_addr(s, &s->dt, devid, &res);
85
@@ -XXX,XX +XXX,XX @@ static void extract_table_params(GICv3ITSState *s)
86
}
87
88
memset(td, 0, sizeof(*td));
89
- td->valid = FIELD_EX64(value, GITS_BASER, VALID);
90
/*
91
* If GITS_BASER<n>.Valid is 0 for any <n> then we will not process
92
* interrupts. (GITS_TYPER.HCC is 0 for this implementation, so we
93
@@ -XXX,XX +XXX,XX @@ static void extract_table_params(GICv3ITSState *s)
94
* for the register corresponding to the Collection table but we
95
* still have to process interrupts using non-memory-backed
96
* Collection table entries.)
97
+ * The specification makes it UNPREDICTABLE to enable the ITS without
98
+ * marking each BASER<n> as valid. We choose to handle these as if
99
+ * the table was zero-sized, so commands using the table will fail
100
+ * and interrupts requested via GITS_TRANSLATER writes will be ignored.
101
+ * This happens automatically by leaving the num_entries field at
102
+ * zero, which will be caught by the bounds checks we have before
103
+ * every table lookup anyway.
104
*/
105
- if (!td->valid) {
106
+ if (!FIELD_EX64(value, GITS_BASER, VALID)) {
107
continue;
108
}
109
td->page_sz = page_sz;
110
@@ -XXX,XX +XXX,XX @@ static void extract_cmdq_params(GICv3ITSState *s)
111
num_pages = FIELD_EX64(value, GITS_CBASER, SIZE) + 1;
112
113
memset(&s->cq, 0 , sizeof(s->cq));
114
- s->cq.valid = FIELD_EX64(value, GITS_CBASER, VALID);
115
116
- if (s->cq.valid) {
117
+ if (FIELD_EX64(value, GITS_CBASER, VALID)) {
118
s->cq.num_entries = (num_pages * GITS_PAGE_SIZE_4K) /
119
GITS_CMDQ_ENTRY_SIZE;
120
s->cq.base_addr = FIELD_EX64(value, GITS_CBASER, PHYADDR);
28
--
121
--
29
2.7.4
122
2.25.1
30
123
31
124
diff view generated by jsdifflib
1
From: Andrew Jones <drjones@redhat.com>
1
In the MAPC command, if V=0 this is a request to delete a collection
2
table entry and the rdbase field of the command packet will not be
3
used. In particular, the specification says that the "UNPREDICTABLE
4
if rdbase is not valid" only applies for V=1.
2
5
3
Don't allow load_uboot_image() to proceed when less bytes than
6
We were doing a check-and-log-guest-error on rdbase regardless of
4
header-size was read.
7
whether the V bit was set, and also (harmlessly but confusingly)
8
storing the contents of the rdbase field into the updated collection
9
table entry. Update the code so that if V=0 we don't check or use
10
the rdbase field value.
5
11
6
Signed-off-by: Andrew Jones <drjones@redhat.com>
7
Message-id: 20170524091315.20284-1-drjones@redhat.com
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
14
Message-id: 20220201193207.2771604-12-peter.maydell@linaro.org
10
---
15
---
11
hw/core/loader.c | 3 ++-
16
hw/intc/arm_gicv3_its.c | 24 ++++++++++++------------
12
1 file changed, 2 insertions(+), 1 deletion(-)
17
1 file changed, 12 insertions(+), 12 deletions(-)
13
18
14
diff --git a/hw/core/loader.c b/hw/core/loader.c
19
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
15
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/core/loader.c
21
--- a/hw/intc/arm_gicv3_its.c
17
+++ b/hw/core/loader.c
22
+++ b/hw/intc/arm_gicv3_its.c
18
@@ -XXX,XX +XXX,XX @@ static int load_uboot_image(const char *filename, hwaddr *ep, hwaddr *loadaddr,
23
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_mapc(GICv3ITSState *s, const uint64_t *cmdpkt)
19
return -1;
24
CTEntry cte;
20
25
21
size = read(fd, hdr, sizeof(uboot_image_header_t));
26
icid = cmdpkt[2] & ICID_MASK;
22
- if (size < 0)
27
-
23
+ if (size < sizeof(uboot_image_header_t)) {
28
- cte.rdbase = (cmdpkt[2] & R_MAPC_RDBASE_MASK) >> R_MAPC_RDBASE_SHIFT;
24
goto out;
29
- cte.rdbase &= RDBASE_PROCNUM_MASK;
30
-
31
cte.valid = cmdpkt[2] & CMD_FIELD_VALID_MASK;
32
+ if (cte.valid) {
33
+ cte.rdbase = (cmdpkt[2] & R_MAPC_RDBASE_MASK) >> R_MAPC_RDBASE_SHIFT;
34
+ cte.rdbase &= RDBASE_PROCNUM_MASK;
35
+ } else {
36
+ cte.rdbase = 0;
25
+ }
37
+ }
26
38
27
bswap_uboot_header(hdr);
39
- if ((icid >= s->ct.num_entries) || (cte.rdbase >= s->gicv3->num_cpu)) {
40
+ if (icid >= s->ct.num_entries) {
41
+ qemu_log_mask(LOG_GUEST_ERROR, "ITS MAPC: invalid ICID 0x%d", icid);
42
+ return CMD_CONTINUE;
43
+ }
44
+ if (cte.valid && cte.rdbase >= s->gicv3->num_cpu) {
45
qemu_log_mask(LOG_GUEST_ERROR,
46
- "ITS MAPC: invalid collection table attributes "
47
- "icid %d rdbase %u\n", icid, cte.rdbase);
48
- /*
49
- * in this implementation, in case of error
50
- * we ignore this command and move onto the next
51
- * command in the queue
52
- */
53
+ "ITS MAPC: invalid RDBASE %u ", cte.rdbase);
54
return CMD_CONTINUE;
55
}
28
56
29
--
57
--
30
2.7.4
58
2.25.1
31
59
32
60
diff view generated by jsdifflib
1
Now that we enforce both:
1
When handling MAPI/MAPTI, we allow the supplied interrupt ID to be
2
* pmsav7_dregion == 0 implies has_mpu == false
2
either 1023 or something in the valid LPI range. This is a mistake:
3
* PMSA with has_mpu == false means SCTLR.M cannot be set
3
only a real valid LPI is allowed. (The general behaviour of the ITS
4
we can remove a check on pmsav7_dregion from get_phys_addr_pmsav7(),
4
is that most interrupt ID fields require a value in the LPI range;
5
because we can only reach this code path if the MPU is enabled
5
the exception is that fields specifying a doorbell value, which are
6
(and so region_translation_disabled() returned false).
6
all in GICv4 commands, allow also 1023 to mean "no doorbell".)
7
Remove the condition that incorrectly allows 1023 here.
7
8
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
10
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
Message-id: 1493122030-32191-8-git-send-email-peter.maydell@linaro.org
11
Message-id: 20220201193207.2771604-13-peter.maydell@linaro.org
11
---
12
---
12
target/arm/helper.c | 3 +--
13
hw/intc/arm_gicv3_its.c | 3 +--
13
1 file changed, 1 insertion(+), 2 deletions(-)
14
1 file changed, 1 insertion(+), 2 deletions(-)
14
15
15
diff --git a/target/arm/helper.c b/target/arm/helper.c
16
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
16
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
17
--- a/target/arm/helper.c
18
--- a/hw/intc/arm_gicv3_its.c
18
+++ b/target/arm/helper.c
19
+++ b/hw/intc/arm_gicv3_its.c
19
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address,
20
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_mapti(GICv3ITSState *s, const uint64_t *cmdpkt,
20
}
21
21
22
if ((icid >= s->ct.num_entries)
22
if (n == -1) { /* no hits */
23
|| !dte.valid || (eventid >= num_eventids) ||
23
- if (cpu->pmsav7_dregion &&
24
- (((pIntid < GICV3_LPI_INTID_START) || (pIntid >= num_intids)) &&
24
- (is_user || !(regime_sctlr(env, mmu_idx) & SCTLR_BR))) {
25
- (pIntid != INTID_SPURIOUS))) {
25
+ if (is_user || !(regime_sctlr(env, mmu_idx) & SCTLR_BR)) {
26
+ (((pIntid < GICV3_LPI_INTID_START) || (pIntid >= num_intids)))) {
26
/* background fault */
27
qemu_log_mask(LOG_GUEST_ERROR,
27
*fsr = 0;
28
"%s: invalid command attributes "
28
return true;
29
"icid %d or eventid %d or pIntid %d or"
29
--
30
--
30
2.7.4
31
2.25.1
31
32
32
33
diff view generated by jsdifflib
1
Make M profile use completely separate ARMMMUIdx values from
1
In most of the ITS command processing, we check different error
2
those that A profile CPUs use. This is a prelude to adding
2
possibilities one at a time and log them appropriately. In
3
support for the MPU and for v8M, which together will require
3
process_mapti() and process_mapd() we have code which checks
4
6 MMU indexes which don't map cleanly onto the A profile
4
multiple error cases at once, which means the logging is less
5
uses:
5
specific than it could be. Split those cases up.
6
non secure User
7
non secure Privileged
8
non secure Privileged, execution priority < 0
9
secure User
10
secure Privileged
11
secure Privileged, execution priority < 0
12
6
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
Message-id: 1493122030-32191-4-git-send-email-peter.maydell@linaro.org
8
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
9
Message-id: 20220201193207.2771604-14-peter.maydell@linaro.org
15
---
10
---
16
target/arm/cpu.h | 21 +++++++++++++++++++--
11
hw/intc/arm_gicv3_its.c | 52 ++++++++++++++++++++++++-----------------
17
target/arm/helper.c | 5 +++++
12
1 file changed, 31 insertions(+), 21 deletions(-)
18
target/arm/translate.c | 3 +++
19
3 files changed, 27 insertions(+), 2 deletions(-)
20
13
21
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
14
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
22
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
23
--- a/target/arm/cpu.h
16
--- a/hw/intc/arm_gicv3_its.c
24
+++ b/target/arm/cpu.h
17
+++ b/hw/intc/arm_gicv3_its.c
25
@@ -XXX,XX +XXX,XX @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx,
18
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_mapti(GICv3ITSState *s, const uint64_t *cmdpkt,
26
* of the AT/ATS operations.
19
num_eventids = 1ULL << (dte.size + 1);
27
* The values used are carefully arranged to make mmu_idx => EL lookup easy.
20
num_intids = 1ULL << (GICD_TYPER_IDBITS + 1);
28
*/
21
29
-#define ARM_MMU_IDX_A 0x10 /* A profile (and M profile, for the moment) */
22
- if ((icid >= s->ct.num_entries)
30
+#define ARM_MMU_IDX_A 0x10 /* A profile */
23
- || !dte.valid || (eventid >= num_eventids) ||
31
#define ARM_MMU_IDX_NOTLB 0x20 /* does not have a TLB */
24
- (((pIntid < GICV3_LPI_INTID_START) || (pIntid >= num_intids)))) {
32
+#define ARM_MMU_IDX_M 0x40 /* M profile */
25
+ if (icid >= s->ct.num_entries) {
33
26
qemu_log_mask(LOG_GUEST_ERROR,
34
#define ARM_MMU_IDX_TYPE_MASK (~0x7)
27
- "%s: invalid command attributes "
35
#define ARM_MMU_IDX_COREIDX_MASK 0x7
28
- "icid %d or eventid %d or pIntid %d or"
36
@@ -XXX,XX +XXX,XX @@ typedef enum ARMMMUIdx {
29
- "unmapped dte %d\n", __func__, icid, eventid,
37
ARMMMUIdx_S1SE0 = 4 | ARM_MMU_IDX_A,
30
- pIntid, dte.valid);
38
ARMMMUIdx_S1SE1 = 5 | ARM_MMU_IDX_A,
31
- /*
39
ARMMMUIdx_S2NS = 6 | ARM_MMU_IDX_A,
32
- * in this implementation, in case of error
40
+ ARMMMUIdx_MUser = 0 | ARM_MMU_IDX_M,
33
- * we ignore this command and move onto the next
41
+ ARMMMUIdx_MPriv = 1 | ARM_MMU_IDX_M,
34
- * command in the queue
42
/* Indexes below here don't have TLBs and are used only for AT system
35
- */
43
* instructions or for the first stage of an S12 page table walk.
36
+ "%s: invalid ICID 0x%x >= 0x%x\n",
44
*/
37
+ __func__, icid, s->ct.num_entries);
45
@@ -XXX,XX +XXX,XX @@ typedef enum ARMMMUIdxBit {
38
+ return CMD_CONTINUE;
46
ARMMMUIdxBit_S1SE0 = 1 << 4,
47
ARMMMUIdxBit_S1SE1 = 1 << 5,
48
ARMMMUIdxBit_S2NS = 1 << 6,
49
+ ARMMMUIdxBit_MUser = 1 << 0,
50
+ ARMMMUIdxBit_MPriv = 1 << 1,
51
} ARMMMUIdxBit;
52
53
#define MMU_USER_IDX 0
54
@@ -XXX,XX +XXX,XX @@ static inline int arm_to_core_mmu_idx(ARMMMUIdx mmu_idx)
55
56
static inline ARMMMUIdx core_to_arm_mmu_idx(CPUARMState *env, int mmu_idx)
57
{
58
- return mmu_idx | ARM_MMU_IDX_A;
59
+ if (arm_feature(env, ARM_FEATURE_M)) {
60
+ return mmu_idx | ARM_MMU_IDX_M;
61
+ } else {
62
+ return mmu_idx | ARM_MMU_IDX_A;
63
+ }
64
}
65
66
/* Return the exception level we're running at if this is our mmu_idx */
67
@@ -XXX,XX +XXX,XX @@ static inline int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx)
68
switch (mmu_idx & ARM_MMU_IDX_TYPE_MASK) {
69
case ARM_MMU_IDX_A:
70
return mmu_idx & 3;
71
+ case ARM_MMU_IDX_M:
72
+ return mmu_idx & 1;
73
default:
74
g_assert_not_reached();
75
}
76
@@ -XXX,XX +XXX,XX @@ static inline int cpu_mmu_index(CPUARMState *env, bool ifetch)
77
{
78
int el = arm_current_el(env);
79
80
+ if (arm_feature(env, ARM_FEATURE_M)) {
81
+ ARMMMUIdx mmu_idx = el == 0 ? ARMMMUIdx_MUser : ARMMMUIdx_MPriv;
82
+
83
+ return arm_to_core_mmu_idx(mmu_idx);
84
+ }
39
+ }
85
+
40
+
86
if (el < 2 && arm_is_secure_below_el3(env)) {
41
+ if (!dte.valid) {
87
return arm_to_core_mmu_idx(ARMMMUIdx_S1SE0 + el);
42
+ qemu_log_mask(LOG_GUEST_ERROR,
43
+ "%s: no valid DTE for devid 0x%x\n", __func__, devid);
44
+ return CMD_CONTINUE;
45
+ }
46
+
47
+ if (eventid >= num_eventids) {
48
+ qemu_log_mask(LOG_GUEST_ERROR,
49
+ "%s: invalid event ID 0x%x >= 0x%" PRIx64 "\n",
50
+ __func__, eventid, num_eventids);
51
+ return CMD_CONTINUE;
52
+ }
53
+
54
+ if (pIntid < GICV3_LPI_INTID_START || pIntid >= num_intids) {
55
+ qemu_log_mask(LOG_GUEST_ERROR,
56
+ "%s: invalid interrupt ID 0x%x\n", __func__, pIntid);
57
return CMD_CONTINUE;
88
}
58
}
89
diff --git a/target/arm/helper.c b/target/arm/helper.c
59
90
index XXXXXXX..XXXXXXX 100644
60
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_mapd(GICv3ITSState *s, const uint64_t *cmdpkt)
91
--- a/target/arm/helper.c
61
dte.ittaddr = (cmdpkt[2] & ITTADDR_MASK) >> ITTADDR_SHIFT;
92
+++ b/target/arm/helper.c
62
dte.valid = cmdpkt[2] & CMD_FIELD_VALID_MASK;
93
@@ -XXX,XX +XXX,XX @@ static inline uint32_t regime_el(CPUARMState *env, ARMMMUIdx mmu_idx)
63
94
case ARMMMUIdx_S1SE1:
64
- if ((devid >= s->dt.num_entries) ||
95
case ARMMMUIdx_S1NSE0:
65
- (dte.size > FIELD_EX64(s->typer, GITS_TYPER, IDBITS))) {
96
case ARMMMUIdx_S1NSE1:
66
+ if (devid >= s->dt.num_entries) {
97
+ case ARMMMUIdx_MPriv:
67
qemu_log_mask(LOG_GUEST_ERROR,
98
+ case ARMMMUIdx_MUser:
68
- "ITS MAPD: invalid device table attributes "
99
return 1;
69
- "devid %d or size %d\n", devid, dte.size);
100
default:
70
- /*
101
g_assert_not_reached();
71
- * in this implementation, in case of error
102
@@ -XXX,XX +XXX,XX @@ static inline bool regime_is_secure(CPUARMState *env, ARMMMUIdx mmu_idx)
72
- * we ignore this command and move onto the next
103
case ARMMMUIdx_S1NSE1:
73
- * command in the queue
104
case ARMMMUIdx_S1E2:
74
- */
105
case ARMMMUIdx_S2NS:
75
+ "ITS MAPD: invalid device ID field 0x%x >= 0x%x\n",
106
+ case ARMMMUIdx_MPriv:
76
+ devid, s->dt.num_entries);
107
+ case ARMMMUIdx_MUser:
77
+ return CMD_CONTINUE;
108
return false;
78
+ }
109
case ARMMMUIdx_S1E3:
79
+
110
case ARMMMUIdx_S1SE0:
80
+ if (dte.size > FIELD_EX64(s->typer, GITS_TYPER, IDBITS)) {
111
@@ -XXX,XX +XXX,XX @@ static inline bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx)
81
+ qemu_log_mask(LOG_GUEST_ERROR,
112
switch (mmu_idx) {
82
+ "ITS MAPD: invalid size %d\n", dte.size);
113
case ARMMMUIdx_S1SE0:
83
return CMD_CONTINUE;
114
case ARMMMUIdx_S1NSE0:
84
}
115
+ case ARMMMUIdx_MUser:
85
116
return true;
117
default:
118
return false;
119
diff --git a/target/arm/translate.c b/target/arm/translate.c
120
index XXXXXXX..XXXXXXX 100644
121
--- a/target/arm/translate.c
122
+++ b/target/arm/translate.c
123
@@ -XXX,XX +XXX,XX @@ static inline int get_a32_user_mem_index(DisasContext *s)
124
case ARMMMUIdx_S1SE0:
125
case ARMMMUIdx_S1SE1:
126
return arm_to_core_mmu_idx(ARMMMUIdx_S1SE0);
127
+ case ARMMMUIdx_MUser:
128
+ case ARMMMUIdx_MPriv:
129
+ return arm_to_core_mmu_idx(ARMMMUIdx_MUser);
130
case ARMMMUIdx_S2NS:
131
default:
132
g_assert_not_reached();
133
--
86
--
134
2.7.4
87
2.25.1
135
88
136
89
diff view generated by jsdifflib
1
From: Cédric Le Goater <clg@kaod.org>
1
From: Kevin Townsend <kevin.townsend@linaro.org>
2
2
3
Largely inspired by the TMP105 temperature sensor, here is a model for
3
This commit adds emulation of the magnetometer on the LSM303DLHC.
4
the TMP42{1,2,3} temperature sensors.
4
It allows the magnetometer's X, Y and Z outputs to be set via the
5
mag-x, mag-y and mag-z properties, as well as the 12-bit
6
temperature output via the temperature property. Sensor can be
7
enabled with 'CONFIG_LSM303DLHC_MAG=y'.
5
8
6
Specs can be found here :
9
Signed-off-by: Kevin Townsend <kevin.townsend@linaro.org>
10
Message-id: 20220130095032.35392-1-kevin.townsend@linaro.org
11
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
---
14
hw/sensor/lsm303dlhc_mag.c | 556 ++++++++++++++++++++++++++++++
15
tests/qtest/lsm303dlhc-mag-test.c | 148 ++++++++
16
hw/sensor/Kconfig | 4 +
17
hw/sensor/meson.build | 1 +
18
tests/qtest/meson.build | 1 +
19
5 files changed, 710 insertions(+)
20
create mode 100644 hw/sensor/lsm303dlhc_mag.c
21
create mode 100644 tests/qtest/lsm303dlhc-mag-test.c
7
22
8
    http://www.ti.com/lit/gpn/tmp421
23
diff --git a/hw/sensor/lsm303dlhc_mag.c b/hw/sensor/lsm303dlhc_mag.c
9
10
Signed-off-by: Cédric Le Goater <clg@kaod.org>
11
Message-id: 1494827476-1487-6-git-send-email-clg@kaod.org
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
14
---
15
hw/misc/Makefile.objs | 1 +
16
hw/misc/tmp421.c | 401 ++++++++++++++++++++++++++++++++++++++++
17
default-configs/arm-softmmu.mak | 1 +
18
3 files changed, 403 insertions(+)
19
create mode 100644 hw/misc/tmp421.c
20
21
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
22
index XXXXXXX..XXXXXXX 100644
23
--- a/hw/misc/Makefile.objs
24
+++ b/hw/misc/Makefile.objs
25
@@ -XXX,XX +XXX,XX @@
26
common-obj-$(CONFIG_APPLESMC) += applesmc.o
27
common-obj-$(CONFIG_MAX111X) += max111x.o
28
common-obj-$(CONFIG_TMP105) += tmp105.o
29
+common-obj-$(CONFIG_TMP421) += tmp421.o
30
common-obj-$(CONFIG_ISA_DEBUG) += debugexit.o
31
common-obj-$(CONFIG_SGA) += sga.o
32
common-obj-$(CONFIG_ISA_TESTDEV) += pc-testdev.o
33
diff --git a/hw/misc/tmp421.c b/hw/misc/tmp421.c
34
new file mode 100644
24
new file mode 100644
35
index XXXXXXX..XXXXXXX
25
index XXXXXXX..XXXXXXX
36
--- /dev/null
26
--- /dev/null
37
+++ b/hw/misc/tmp421.c
27
+++ b/hw/sensor/lsm303dlhc_mag.c
38
@@ -XXX,XX +XXX,XX @@
28
@@ -XXX,XX +XXX,XX @@
39
+/*
29
+/*
40
+ * Texas Instruments TMP421 temperature sensor.
30
+ * LSM303DLHC I2C magnetometer.
41
+ *
31
+ *
42
+ * Copyright (c) 2016 IBM Corporation.
32
+ * Copyright (C) 2021 Linaro Ltd.
33
+ * Written by Kevin Townsend <kevin.townsend@linaro.org>
43
+ *
34
+ *
44
+ * Largely inspired by :
35
+ * Based on: https://www.st.com/resource/en/datasheet/lsm303dlhc.pdf
45
+ *
36
+ *
46
+ * Texas Instruments TMP105 temperature sensor.
37
+ * SPDX-License-Identifier: GPL-2.0-or-later
38
+ */
39
+
40
+/*
41
+ * The I2C address associated with this device is set on the command-line when
42
+ * initialising the machine, but the following address is standard: 0x1E.
47
+ *
43
+ *
48
+ * Copyright (C) 2008 Nokia Corporation
44
+ * Get and set functions for 'mag-x', 'mag-y' and 'mag-z' assume that
49
+ * Written by Andrzej Zaborowski <andrew@openedhand.com>
45
+ * 1 = 0.001 uT. (NOTE the 1 gauss = 100 uT, so setting a value of 100,000
46
+ * would be equal to 1 gauss or 100 uT.)
50
+ *
47
+ *
51
+ * This program is free software; you can redistribute it and/or
48
+ * Get and set functions for 'temperature' assume that 1 = 0.001 C, so 23.6 C
52
+ * modify it under the terms of the GNU General Public License as
49
+ * would be equal to 23600.
53
+ * published by the Free Software Foundation; either version 2 or
54
+ * (at your option) version 3 of the License.
55
+ *
56
+ * This program is distributed in the hope that it will be useful,
57
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
58
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
59
+ * GNU General Public License for more details.
60
+ *
61
+ * You should have received a copy of the GNU General Public License along
62
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
63
+ */
50
+ */
64
+
51
+
65
+#include "qemu/osdep.h"
52
+#include "qemu/osdep.h"
66
+#include "hw/hw.h"
67
+#include "hw/i2c/i2c.h"
53
+#include "hw/i2c/i2c.h"
54
+#include "migration/vmstate.h"
68
+#include "qapi/error.h"
55
+#include "qapi/error.h"
69
+#include "qapi/visitor.h"
56
+#include "qapi/visitor.h"
70
+
57
+#include "qemu/module.h"
71
+/* Manufacturer / Device ID's */
58
+#include "qemu/log.h"
72
+#define TMP421_MANUFACTURER_ID 0x55
59
+#include "qemu/bswap.h"
73
+#define TMP421_DEVICE_ID 0x21
60
+
74
+#define TMP422_DEVICE_ID 0x22
61
+enum LSM303DLHCMagReg {
75
+#define TMP423_DEVICE_ID 0x23
62
+ LSM303DLHC_MAG_REG_CRA = 0x00,
76
+
63
+ LSM303DLHC_MAG_REG_CRB = 0x01,
77
+typedef struct DeviceInfo {
64
+ LSM303DLHC_MAG_REG_MR = 0x02,
78
+ int model;
65
+ LSM303DLHC_MAG_REG_OUT_X_H = 0x03,
79
+ const char *name;
66
+ LSM303DLHC_MAG_REG_OUT_X_L = 0x04,
80
+} DeviceInfo;
67
+ LSM303DLHC_MAG_REG_OUT_Z_H = 0x05,
81
+
68
+ LSM303DLHC_MAG_REG_OUT_Z_L = 0x06,
82
+static const DeviceInfo devices[] = {
69
+ LSM303DLHC_MAG_REG_OUT_Y_H = 0x07,
83
+ { TMP421_DEVICE_ID, "tmp421" },
70
+ LSM303DLHC_MAG_REG_OUT_Y_L = 0x08,
84
+ { TMP422_DEVICE_ID, "tmp422" },
71
+ LSM303DLHC_MAG_REG_SR = 0x09,
85
+ { TMP423_DEVICE_ID, "tmp423" },
72
+ LSM303DLHC_MAG_REG_IRA = 0x0A,
73
+ LSM303DLHC_MAG_REG_IRB = 0x0B,
74
+ LSM303DLHC_MAG_REG_IRC = 0x0C,
75
+ LSM303DLHC_MAG_REG_TEMP_OUT_H = 0x31,
76
+ LSM303DLHC_MAG_REG_TEMP_OUT_L = 0x32
86
+};
77
+};
87
+
78
+
88
+typedef struct TMP421State {
79
+typedef struct LSM303DLHCMagState {
89
+ /*< private >*/
80
+ I2CSlave parent_obj;
90
+ I2CSlave i2c;
81
+ uint8_t cra;
91
+ /*< public >*/
82
+ uint8_t crb;
92
+
83
+ uint8_t mr;
93
+ int16_t temperature[4];
84
+ int16_t x;
94
+
85
+ int16_t z;
95
+ uint8_t status;
86
+ int16_t y;
96
+ uint8_t config[2];
87
+ int16_t x_lock;
97
+ uint8_t rate;
88
+ int16_t z_lock;
98
+
89
+ int16_t y_lock;
90
+ uint8_t sr;
91
+ uint8_t ira;
92
+ uint8_t irb;
93
+ uint8_t irc;
94
+ int16_t temperature;
95
+ int16_t temperature_lock;
99
+ uint8_t len;
96
+ uint8_t len;
100
+ uint8_t buf[2];
97
+ uint8_t buf;
101
+ uint8_t pointer;
98
+ uint8_t pointer;
102
+
99
+} LSM303DLHCMagState;
103
+} TMP421State;
100
+
104
+
101
+#define TYPE_LSM303DLHC_MAG "lsm303dlhc_mag"
105
+typedef struct TMP421Class {
102
+OBJECT_DECLARE_SIMPLE_TYPE(LSM303DLHCMagState, LSM303DLHC_MAG)
106
+ I2CSlaveClass parent_class;
103
+
107
+ DeviceInfo *dev;
104
+/*
108
+} TMP421Class;
105
+ * Conversion factor from Gauss to sensor values for each GN gain setting,
109
+
106
+ * in units "lsb per Gauss" (see data sheet table 3). There is no documented
110
+#define TYPE_TMP421 "tmp421-generic"
107
+ * behaviour if the GN setting in CRB is incorrectly set to 0b000;
111
+#define TMP421(obj) OBJECT_CHECK(TMP421State, (obj), TYPE_TMP421)
108
+ * we arbitrarily make it the same as 0b001.
112
+
109
+ */
113
+#define TMP421_CLASS(klass) \
110
+uint32_t xy_gain[] = { 1100, 1100, 855, 670, 450, 400, 330, 230 };
114
+ OBJECT_CLASS_CHECK(TMP421Class, (klass), TYPE_TMP421)
111
+uint32_t z_gain[] = { 980, 980, 760, 600, 400, 355, 295, 205 };
115
+#define TMP421_GET_CLASS(obj) \
112
+
116
+ OBJECT_GET_CLASS(TMP421Class, (obj), TYPE_TMP421)
113
+static void lsm303dlhc_mag_get_x(Object *obj, Visitor *v, const char *name,
117
+
114
+ void *opaque, Error **errp)
118
+/* the TMP421 registers */
115
+{
119
+#define TMP421_STATUS_REG 0x08
116
+ LSM303DLHCMagState *s = LSM303DLHC_MAG(obj);
120
+#define TMP421_STATUS_BUSY (1 << 7)
117
+ int gm = extract32(s->crb, 5, 3);
121
+#define TMP421_CONFIG_REG_1 0x09
118
+
122
+#define TMP421_CONFIG_RANGE (1 << 2)
119
+ /* Convert to uT where 1000 = 1 uT. Conversion factor depends on gain. */
123
+#define TMP421_CONFIG_SHUTDOWN (1 << 6)
120
+ int64_t value = muldiv64(s->x, 100000, xy_gain[gm]);
124
+#define TMP421_CONFIG_REG_2 0x0A
121
+ visit_type_int(v, name, &value, errp);
125
+#define TMP421_CONFIG_RC (1 << 2)
122
+}
126
+#define TMP421_CONFIG_LEN (1 << 3)
123
+
127
+#define TMP421_CONFIG_REN (1 << 4)
124
+static void lsm303dlhc_mag_get_y(Object *obj, Visitor *v, const char *name,
128
+#define TMP421_CONFIG_REN2 (1 << 5)
125
+ void *opaque, Error **errp)
129
+#define TMP421_CONFIG_REN3 (1 << 6)
126
+{
130
+
127
+ LSM303DLHCMagState *s = LSM303DLHC_MAG(obj);
131
+#define TMP421_CONVERSION_RATE_REG 0x0B
128
+ int gm = extract32(s->crb, 5, 3);
132
+#define TMP421_ONE_SHOT 0x0F
129
+
133
+
130
+ /* Convert to uT where 1000 = 1 uT. Conversion factor depends on gain. */
134
+#define TMP421_RESET 0xFC
131
+ int64_t value = muldiv64(s->y, 100000, xy_gain[gm]);
135
+#define TMP421_MANUFACTURER_ID_REG 0xFE
132
+ visit_type_int(v, name, &value, errp);
136
+#define TMP421_DEVICE_ID_REG 0xFF
133
+}
137
+
134
+
138
+#define TMP421_TEMP_MSB0 0x00
135
+static void lsm303dlhc_mag_get_z(Object *obj, Visitor *v, const char *name,
139
+#define TMP421_TEMP_MSB1 0x01
136
+ void *opaque, Error **errp)
140
+#define TMP421_TEMP_MSB2 0x02
137
+{
141
+#define TMP421_TEMP_MSB3 0x03
138
+ LSM303DLHCMagState *s = LSM303DLHC_MAG(obj);
142
+#define TMP421_TEMP_LSB0 0x10
139
+ int gm = extract32(s->crb, 5, 3);
143
+#define TMP421_TEMP_LSB1 0x11
140
+
144
+#define TMP421_TEMP_LSB2 0x12
141
+ /* Convert to uT where 1000 = 1 uT. Conversion factor depends on gain. */
145
+#define TMP421_TEMP_LSB3 0x13
142
+ int64_t value = muldiv64(s->z, 100000, z_gain[gm]);
146
+
143
+ visit_type_int(v, name, &value, errp);
147
+static const int32_t mins[2] = { -40000, -55000 };
144
+}
148
+static const int32_t maxs[2] = { 127000, 150000 };
145
+
149
+
146
+static void lsm303dlhc_mag_set_x(Object *obj, Visitor *v, const char *name,
150
+static void tmp421_get_temperature(Object *obj, Visitor *v, const char *name,
147
+ void *opaque, Error **errp)
151
+ void *opaque, Error **errp)
148
+{
152
+{
149
+ LSM303DLHCMagState *s = LSM303DLHC_MAG(obj);
153
+ TMP421State *s = TMP421(obj);
154
+ bool ext_range = (s->config[0] & TMP421_CONFIG_RANGE);
155
+ int offset = ext_range * 64 * 256;
156
+ int64_t value;
150
+ int64_t value;
157
+ int tempid;
151
+ int64_t reg;
158
+
152
+ int gm = extract32(s->crb, 5, 3);
159
+ if (sscanf(name, "temperature%d", &tempid) != 1) {
153
+
160
+ error_setg(errp, "error reading %s: %m", name);
154
+ if (!visit_type_int(v, name, &value, errp)) {
161
+ return;
155
+ return;
162
+ }
156
+ }
163
+
157
+
164
+ if (tempid >= 4 || tempid < 0) {
158
+ reg = muldiv64(value, xy_gain[gm], 100000);
165
+ error_setg(errp, "error reading %s", name);
159
+
160
+ /* Make sure we are within a 12-bit limit. */
161
+ if (reg > 2047 || reg < -2048) {
162
+ error_setg(errp, "value %" PRId64 " out of register's range", value);
166
+ return;
163
+ return;
167
+ }
164
+ }
168
+
165
+
169
+ value = ((s->temperature[tempid] - offset) * 1000 + 128) / 256;
166
+ s->x = (int16_t)reg;
167
+}
168
+
169
+static void lsm303dlhc_mag_set_y(Object *obj, Visitor *v, const char *name,
170
+ void *opaque, Error **errp)
171
+{
172
+ LSM303DLHCMagState *s = LSM303DLHC_MAG(obj);
173
+ int64_t value;
174
+ int64_t reg;
175
+ int gm = extract32(s->crb, 5, 3);
176
+
177
+ if (!visit_type_int(v, name, &value, errp)) {
178
+ return;
179
+ }
180
+
181
+ reg = muldiv64(value, xy_gain[gm], 100000);
182
+
183
+ /* Make sure we are within a 12-bit limit. */
184
+ if (reg > 2047 || reg < -2048) {
185
+ error_setg(errp, "value %" PRId64 " out of register's range", value);
186
+ return;
187
+ }
188
+
189
+ s->y = (int16_t)reg;
190
+}
191
+
192
+static void lsm303dlhc_mag_set_z(Object *obj, Visitor *v, const char *name,
193
+ void *opaque, Error **errp)
194
+{
195
+ LSM303DLHCMagState *s = LSM303DLHC_MAG(obj);
196
+ int64_t value;
197
+ int64_t reg;
198
+ int gm = extract32(s->crb, 5, 3);
199
+
200
+ if (!visit_type_int(v, name, &value, errp)) {
201
+ return;
202
+ }
203
+
204
+ reg = muldiv64(value, z_gain[gm], 100000);
205
+
206
+ /* Make sure we are within a 12-bit limit. */
207
+ if (reg > 2047 || reg < -2048) {
208
+ error_setg(errp, "value %" PRId64 " out of register's range", value);
209
+ return;
210
+ }
211
+
212
+ s->z = (int16_t)reg;
213
+}
214
+
215
+/*
216
+ * Get handler for the temperature property.
217
+ */
218
+static void lsm303dlhc_mag_get_temperature(Object *obj, Visitor *v,
219
+ const char *name, void *opaque,
220
+ Error **errp)
221
+{
222
+ LSM303DLHCMagState *s = LSM303DLHC_MAG(obj);
223
+ int64_t value;
224
+
225
+ /* Convert to 1 lsb = 0.125 C to 1 = 0.001 C for 'temperature' property. */
226
+ value = s->temperature * 125;
170
+
227
+
171
+ visit_type_int(v, name, &value, errp);
228
+ visit_type_int(v, name, &value, errp);
172
+}
229
+}
173
+
230
+
174
+/* Units are 0.001 centigrades relative to 0 C. s->temperature is 8.8
231
+/*
175
+ * fixed point, so units are 1/256 centigrades. A simple ratio will do.
232
+ * Set handler for the temperature property.
176
+ */
233
+ */
177
+static void tmp421_set_temperature(Object *obj, Visitor *v, const char *name,
234
+static void lsm303dlhc_mag_set_temperature(Object *obj, Visitor *v,
178
+ void *opaque, Error **errp)
235
+ const char *name, void *opaque,
179
+{
236
+ Error **errp)
180
+ TMP421State *s = TMP421(obj);
237
+{
181
+ Error *local_err = NULL;
238
+ LSM303DLHCMagState *s = LSM303DLHC_MAG(obj);
182
+ int64_t temp;
239
+ int64_t value;
183
+ bool ext_range = (s->config[0] & TMP421_CONFIG_RANGE);
240
+
184
+ int offset = ext_range * 64 * 256;
241
+ if (!visit_type_int(v, name, &value, errp)) {
185
+ int tempid;
186
+
187
+ visit_type_int(v, name, &temp, &local_err);
188
+ if (local_err) {
189
+ error_propagate(errp, local_err);
190
+ return;
242
+ return;
191
+ }
243
+ }
192
+
244
+
193
+ if (temp >= maxs[ext_range] || temp < mins[ext_range]) {
245
+ /* Input temperature is in 0.001 C units. Convert to 1 lsb = 0.125 C. */
194
+ error_setg(errp, "value %" PRId64 ".%03" PRIu64 " °C is out of range",
246
+ value /= 125;
195
+ temp / 1000, temp % 1000);
247
+
248
+ if (value > 2047 || value < -2048) {
249
+ error_setg(errp, "value %" PRId64 " lsb is out of range", value);
196
+ return;
250
+ return;
197
+ }
251
+ }
198
+
252
+
199
+ if (sscanf(name, "temperature%d", &tempid) != 1) {
253
+ s->temperature = (int16_t)value;
200
+ error_setg(errp, "error reading %s: %m", name);
254
+}
201
+ return;
255
+
202
+ }
256
+/*
203
+
257
+ * Callback handler whenever a 'I2C_START_RECV' (read) event is received.
204
+ if (tempid >= 4 || tempid < 0) {
258
+ */
205
+ error_setg(errp, "error reading %s", name);
259
+static void lsm303dlhc_mag_read(LSM303DLHCMagState *s)
206
+ return;
260
+{
207
+ }
261
+ /*
208
+
262
+ * Set the LOCK bit whenever a new read attempt is made. This will be
209
+ s->temperature[tempid] = (int16_t) ((temp * 256 - 128) / 1000) + offset;
263
+ * cleared in I2C_FINISH. Note that DRDY is always set to 1 in this driver.
210
+}
264
+ */
211
+
265
+ s->sr = 0x3;
212
+static void tmp421_read(TMP421State *s)
266
+
213
+{
267
+ /*
214
+ TMP421Class *sc = TMP421_GET_CLASS(s);
268
+ * Copy the current X/Y/Z and temp. values into the locked registers so
215
+
269
+ * that 'mag-x', 'mag-y', 'mag-z' and 'temperature' can continue to be
216
+ s->len = 0;
270
+ * updated via QOM, etc., without corrupting the current read event.
217
+
271
+ */
272
+ s->x_lock = s->x;
273
+ s->z_lock = s->z;
274
+ s->y_lock = s->y;
275
+ s->temperature_lock = s->temperature;
276
+}
277
+
278
+/*
279
+ * Callback handler whenever a 'I2C_FINISH' event is received.
280
+ */
281
+static void lsm303dlhc_mag_finish(LSM303DLHCMagState *s)
282
+{
283
+ /*
284
+ * Clear the LOCK bit when the read attempt terminates.
285
+ * This bit is initially set in the I2C_START_RECV handler.
286
+ */
287
+ s->sr = 0x1;
288
+}
289
+
290
+/*
291
+ * Callback handler when a device attempts to write to a register.
292
+ */
293
+static void lsm303dlhc_mag_write(LSM303DLHCMagState *s)
294
+{
218
+ switch (s->pointer) {
295
+ switch (s->pointer) {
219
+ case TMP421_MANUFACTURER_ID_REG:
296
+ case LSM303DLHC_MAG_REG_CRA:
220
+ s->buf[s->len++] = TMP421_MANUFACTURER_ID;
297
+ s->cra = s->buf;
221
+ break;
298
+ break;
222
+ case TMP421_DEVICE_ID_REG:
299
+ case LSM303DLHC_MAG_REG_CRB:
223
+ s->buf[s->len++] = sc->dev->model;
300
+ /* Make sure gain is at least 1, falling back to 1 on an error. */
224
+ break;
301
+ if (s->buf >> 5 == 0) {
225
+ case TMP421_CONFIG_REG_1:
302
+ s->buf = 1 << 5;
226
+ s->buf[s->len++] = s->config[0];
303
+ }
227
+ break;
304
+ s->crb = s->buf;
228
+ case TMP421_CONFIG_REG_2:
305
+ break;
229
+ s->buf[s->len++] = s->config[1];
306
+ case LSM303DLHC_MAG_REG_MR:
230
+ break;
307
+ s->mr = s->buf;
231
+ case TMP421_CONVERSION_RATE_REG:
308
+ break;
232
+ s->buf[s->len++] = s->rate;
309
+ case LSM303DLHC_MAG_REG_SR:
233
+ break;
310
+ s->sr = s->buf;
234
+ case TMP421_STATUS_REG:
311
+ break;
235
+ s->buf[s->len++] = s->status;
312
+ case LSM303DLHC_MAG_REG_IRA:
236
+ break;
313
+ s->ira = s->buf;
237
+
314
+ break;
238
+ /* FIXME: check for channel enablement in config registers */
315
+ case LSM303DLHC_MAG_REG_IRB:
239
+ case TMP421_TEMP_MSB0:
316
+ s->irb = s->buf;
240
+ s->buf[s->len++] = (((uint16_t) s->temperature[0]) >> 8);
317
+ break;
241
+ s->buf[s->len++] = (((uint16_t) s->temperature[0]) >> 0) & 0xf0;
318
+ case LSM303DLHC_MAG_REG_IRC:
242
+ break;
319
+ s->irc = s->buf;
243
+ case TMP421_TEMP_MSB1:
320
+ break;
244
+ s->buf[s->len++] = (((uint16_t) s->temperature[1]) >> 8);
321
+ default:
245
+ s->buf[s->len++] = (((uint16_t) s->temperature[1]) >> 0) & 0xf0;
322
+ qemu_log_mask(LOG_GUEST_ERROR, "reg is read-only: 0x%02X", s->buf);
246
+ break;
323
+ break;
247
+ case TMP421_TEMP_MSB2:
324
+ }
248
+ s->buf[s->len++] = (((uint16_t) s->temperature[2]) >> 8);
325
+}
249
+ s->buf[s->len++] = (((uint16_t) s->temperature[2]) >> 0) & 0xf0;
326
+
250
+ break;
327
+/*
251
+ case TMP421_TEMP_MSB3:
328
+ * Low-level master-to-slave transaction handler.
252
+ s->buf[s->len++] = (((uint16_t) s->temperature[3]) >> 8);
329
+ */
253
+ s->buf[s->len++] = (((uint16_t) s->temperature[3]) >> 0) & 0xf0;
330
+static int lsm303dlhc_mag_send(I2CSlave *i2c, uint8_t data)
254
+ break;
331
+{
255
+ case TMP421_TEMP_LSB0:
332
+ LSM303DLHCMagState *s = LSM303DLHC_MAG(i2c);
256
+ s->buf[s->len++] = (((uint16_t) s->temperature[0]) >> 0) & 0xf0;
257
+ break;
258
+ case TMP421_TEMP_LSB1:
259
+ s->buf[s->len++] = (((uint16_t) s->temperature[1]) >> 0) & 0xf0;
260
+ break;
261
+ case TMP421_TEMP_LSB2:
262
+ s->buf[s->len++] = (((uint16_t) s->temperature[2]) >> 0) & 0xf0;
263
+ break;
264
+ case TMP421_TEMP_LSB3:
265
+ s->buf[s->len++] = (((uint16_t) s->temperature[3]) >> 0) & 0xf0;
266
+ break;
267
+ }
268
+}
269
+
270
+static void tmp421_reset(I2CSlave *i2c);
271
+
272
+static void tmp421_write(TMP421State *s)
273
+{
274
+ switch (s->pointer) {
275
+ case TMP421_CONVERSION_RATE_REG:
276
+ s->rate = s->buf[0];
277
+ break;
278
+ case TMP421_CONFIG_REG_1:
279
+ s->config[0] = s->buf[0];
280
+ break;
281
+ case TMP421_CONFIG_REG_2:
282
+ s->config[1] = s->buf[0];
283
+ break;
284
+ case TMP421_RESET:
285
+ tmp421_reset(I2C_SLAVE(s));
286
+ break;
287
+ }
288
+}
289
+
290
+static int tmp421_rx(I2CSlave *i2c)
291
+{
292
+ TMP421State *s = TMP421(i2c);
293
+
294
+ if (s->len < 2) {
295
+ return s->buf[s->len++];
296
+ } else {
297
+ return 0xff;
298
+ }
299
+}
300
+
301
+static int tmp421_tx(I2CSlave *i2c, uint8_t data)
302
+{
303
+ TMP421State *s = TMP421(i2c);
304
+
333
+
305
+ if (s->len == 0) {
334
+ if (s->len == 0) {
306
+ /* first byte is the register pointer for a read or write
335
+ /* First byte is the reg pointer */
307
+ * operation */
308
+ s->pointer = data;
336
+ s->pointer = data;
309
+ s->len++;
337
+ s->len++;
310
+ } else if (s->len == 1) {
338
+ } else if (s->len == 1) {
311
+ /* second byte is the data to write. The device only supports
339
+ /* Second byte is the new register value. */
312
+ * one byte writes */
340
+ s->buf = data;
313
+ s->buf[0] = data;
341
+ lsm303dlhc_mag_write(s);
314
+ tmp421_write(s);
342
+ } else {
343
+ g_assert_not_reached();
315
+ }
344
+ }
316
+
345
+
317
+ return 0;
346
+ return 0;
318
+}
347
+}
319
+
348
+
320
+static int tmp421_event(I2CSlave *i2c, enum i2c_event event)
349
+/*
321
+{
350
+ * Low-level slave-to-master transaction handler (read attempts).
322
+ TMP421State *s = TMP421(i2c);
351
+ */
323
+
352
+static uint8_t lsm303dlhc_mag_recv(I2CSlave *i2c)
324
+ if (event == I2C_START_RECV) {
353
+{
325
+ tmp421_read(s);
354
+ LSM303DLHCMagState *s = LSM303DLHC_MAG(i2c);
355
+ uint8_t resp;
356
+
357
+ switch (s->pointer) {
358
+ case LSM303DLHC_MAG_REG_CRA:
359
+ resp = s->cra;
360
+ break;
361
+ case LSM303DLHC_MAG_REG_CRB:
362
+ resp = s->crb;
363
+ break;
364
+ case LSM303DLHC_MAG_REG_MR:
365
+ resp = s->mr;
366
+ break;
367
+ case LSM303DLHC_MAG_REG_OUT_X_H:
368
+ resp = (uint8_t)(s->x_lock >> 8);
369
+ break;
370
+ case LSM303DLHC_MAG_REG_OUT_X_L:
371
+ resp = (uint8_t)(s->x_lock);
372
+ break;
373
+ case LSM303DLHC_MAG_REG_OUT_Z_H:
374
+ resp = (uint8_t)(s->z_lock >> 8);
375
+ break;
376
+ case LSM303DLHC_MAG_REG_OUT_Z_L:
377
+ resp = (uint8_t)(s->z_lock);
378
+ break;
379
+ case LSM303DLHC_MAG_REG_OUT_Y_H:
380
+ resp = (uint8_t)(s->y_lock >> 8);
381
+ break;
382
+ case LSM303DLHC_MAG_REG_OUT_Y_L:
383
+ resp = (uint8_t)(s->y_lock);
384
+ break;
385
+ case LSM303DLHC_MAG_REG_SR:
386
+ resp = s->sr;
387
+ break;
388
+ case LSM303DLHC_MAG_REG_IRA:
389
+ resp = s->ira;
390
+ break;
391
+ case LSM303DLHC_MAG_REG_IRB:
392
+ resp = s->irb;
393
+ break;
394
+ case LSM303DLHC_MAG_REG_IRC:
395
+ resp = s->irc;
396
+ break;
397
+ case LSM303DLHC_MAG_REG_TEMP_OUT_H:
398
+ /* Check if the temperature sensor is enabled or not (CRA & 0x80). */
399
+ if (s->cra & 0x80) {
400
+ resp = (uint8_t)(s->temperature_lock >> 8);
401
+ } else {
402
+ resp = 0;
403
+ }
404
+ break;
405
+ case LSM303DLHC_MAG_REG_TEMP_OUT_L:
406
+ if (s->cra & 0x80) {
407
+ resp = (uint8_t)(s->temperature_lock & 0xff);
408
+ } else {
409
+ resp = 0;
410
+ }
411
+ break;
412
+ default:
413
+ resp = 0;
414
+ break;
415
+ }
416
+
417
+ /*
418
+ * The address pointer on the LSM303DLHC auto-increments whenever a byte
419
+ * is read, without the master device having to request the next address.
420
+ *
421
+ * The auto-increment process has the following logic:
422
+ *
423
+ * - if (s->pointer == 8) then s->pointer = 3
424
+ * - else: if (s->pointer == 12) then s->pointer = 0
425
+ * - else: s->pointer += 1
426
+ *
427
+ * Reading an invalid address return 0.
428
+ */
429
+ if (s->pointer == LSM303DLHC_MAG_REG_OUT_Y_L) {
430
+ s->pointer = LSM303DLHC_MAG_REG_OUT_X_H;
431
+ } else if (s->pointer == LSM303DLHC_MAG_REG_IRC) {
432
+ s->pointer = LSM303DLHC_MAG_REG_CRA;
433
+ } else {
434
+ s->pointer++;
435
+ }
436
+
437
+ return resp;
438
+}
439
+
440
+/*
441
+ * Bus state change handler.
442
+ */
443
+static int lsm303dlhc_mag_event(I2CSlave *i2c, enum i2c_event event)
444
+{
445
+ LSM303DLHCMagState *s = LSM303DLHC_MAG(i2c);
446
+
447
+ switch (event) {
448
+ case I2C_START_SEND:
449
+ break;
450
+ case I2C_START_RECV:
451
+ lsm303dlhc_mag_read(s);
452
+ break;
453
+ case I2C_FINISH:
454
+ lsm303dlhc_mag_finish(s);
455
+ break;
456
+ case I2C_NACK:
457
+ break;
326
+ }
458
+ }
327
+
459
+
328
+ s->len = 0;
460
+ s->len = 0;
329
+ return 0;
461
+ return 0;
330
+}
462
+}
331
+
463
+
332
+static const VMStateDescription vmstate_tmp421 = {
464
+/*
333
+ .name = "TMP421",
465
+ * Device data description using VMSTATE macros.
466
+ */
467
+static const VMStateDescription vmstate_lsm303dlhc_mag = {
468
+ .name = "LSM303DLHC_MAG",
334
+ .version_id = 0,
469
+ .version_id = 0,
335
+ .minimum_version_id = 0,
470
+ .minimum_version_id = 0,
336
+ .fields = (VMStateField[]) {
471
+ .fields = (VMStateField[]) {
337
+ VMSTATE_UINT8(len, TMP421State),
472
+
338
+ VMSTATE_UINT8_ARRAY(buf, TMP421State, 2),
473
+ VMSTATE_I2C_SLAVE(parent_obj, LSM303DLHCMagState),
339
+ VMSTATE_UINT8(pointer, TMP421State),
474
+ VMSTATE_UINT8(len, LSM303DLHCMagState),
340
+ VMSTATE_UINT8_ARRAY(config, TMP421State, 2),
475
+ VMSTATE_UINT8(buf, LSM303DLHCMagState),
341
+ VMSTATE_UINT8(status, TMP421State),
476
+ VMSTATE_UINT8(pointer, LSM303DLHCMagState),
342
+ VMSTATE_UINT8(rate, TMP421State),
477
+ VMSTATE_UINT8(cra, LSM303DLHCMagState),
343
+ VMSTATE_INT16_ARRAY(temperature, TMP421State, 4),
478
+ VMSTATE_UINT8(crb, LSM303DLHCMagState),
344
+ VMSTATE_I2C_SLAVE(i2c, TMP421State),
479
+ VMSTATE_UINT8(mr, LSM303DLHCMagState),
480
+ VMSTATE_INT16(x, LSM303DLHCMagState),
481
+ VMSTATE_INT16(z, LSM303DLHCMagState),
482
+ VMSTATE_INT16(y, LSM303DLHCMagState),
483
+ VMSTATE_INT16(x_lock, LSM303DLHCMagState),
484
+ VMSTATE_INT16(z_lock, LSM303DLHCMagState),
485
+ VMSTATE_INT16(y_lock, LSM303DLHCMagState),
486
+ VMSTATE_UINT8(sr, LSM303DLHCMagState),
487
+ VMSTATE_UINT8(ira, LSM303DLHCMagState),
488
+ VMSTATE_UINT8(irb, LSM303DLHCMagState),
489
+ VMSTATE_UINT8(irc, LSM303DLHCMagState),
490
+ VMSTATE_INT16(temperature, LSM303DLHCMagState),
491
+ VMSTATE_INT16(temperature_lock, LSM303DLHCMagState),
345
+ VMSTATE_END_OF_LIST()
492
+ VMSTATE_END_OF_LIST()
346
+ }
493
+ }
347
+};
494
+};
348
+
495
+
349
+static void tmp421_reset(I2CSlave *i2c)
496
+/*
350
+{
497
+ * Put the device into post-reset default state.
351
+ TMP421State *s = TMP421(i2c);
498
+ */
352
+ TMP421Class *sc = TMP421_GET_CLASS(s);
499
+static void lsm303dlhc_mag_default_cfg(LSM303DLHCMagState *s)
353
+
500
+{
354
+ memset(s->temperature, 0, sizeof(s->temperature));
501
+ /* Set the device into is default reset state. */
355
+ s->pointer = 0;
502
+ s->len = 0;
356
+
503
+ s->pointer = 0; /* Current register. */
357
+ s->config[0] = 0; /* TMP421_CONFIG_RANGE */
504
+ s->buf = 0; /* Shared buffer. */
358
+
505
+ s->cra = 0x10; /* Temp Enabled = 0, Data Rate = 15.0 Hz. */
359
+ /* resistance correction and channel enablement */
506
+ s->crb = 0x20; /* Gain = +/- 1.3 Gauss. */
360
+ switch (sc->dev->model) {
507
+ s->mr = 0x3; /* Operating Mode = Sleep. */
361
+ case TMP421_DEVICE_ID:
508
+ s->x = 0;
362
+ s->config[1] = 0x1c;
509
+ s->z = 0;
363
+ break;
510
+ s->y = 0;
364
+ case TMP422_DEVICE_ID:
511
+ s->x_lock = 0;
365
+ s->config[1] = 0x3c;
512
+ s->z_lock = 0;
366
+ break;
513
+ s->y_lock = 0;
367
+ case TMP423_DEVICE_ID:
514
+ s->sr = 0x1; /* DRDY = 1. */
368
+ s->config[1] = 0x7c;
515
+ s->ira = 0x48;
369
+ break;
516
+ s->irb = 0x34;
370
+ }
517
+ s->irc = 0x33;
371
+
518
+ s->temperature = 0; /* Default to 0 degrees C (0/8 lsb = 0 C). */
372
+ s->rate = 0x7; /* 8Hz */
519
+ s->temperature_lock = 0;
373
+ s->status = 0;
520
+}
374
+}
521
+
375
+
522
+/*
376
+static int tmp421_init(I2CSlave *i2c)
523
+ * Callback handler when DeviceState 'reset' is set to true.
377
+{
524
+ */
378
+ TMP421State *s = TMP421(i2c);
525
+static void lsm303dlhc_mag_reset(DeviceState *dev)
379
+
526
+{
380
+ tmp421_reset(&s->i2c);
527
+ I2CSlave *i2c = I2C_SLAVE(dev);
381
+
528
+ LSM303DLHCMagState *s = LSM303DLHC_MAG(i2c);
382
+ return 0;
529
+
383
+}
530
+ /* Set the device into its default reset state. */
384
+
531
+ lsm303dlhc_mag_default_cfg(s);
385
+static void tmp421_initfn(Object *obj)
532
+}
386
+{
533
+
387
+ object_property_add(obj, "temperature0", "int",
534
+/*
388
+ tmp421_get_temperature,
535
+ * Initialisation of any public properties.
389
+ tmp421_set_temperature, NULL, NULL, NULL);
536
+ */
390
+ object_property_add(obj, "temperature1", "int",
537
+static void lsm303dlhc_mag_initfn(Object *obj)
391
+ tmp421_get_temperature,
538
+{
392
+ tmp421_set_temperature, NULL, NULL, NULL);
539
+ object_property_add(obj, "mag-x", "int",
393
+ object_property_add(obj, "temperature2", "int",
540
+ lsm303dlhc_mag_get_x,
394
+ tmp421_get_temperature,
541
+ lsm303dlhc_mag_set_x, NULL, NULL);
395
+ tmp421_set_temperature, NULL, NULL, NULL);
542
+
396
+ object_property_add(obj, "temperature3", "int",
543
+ object_property_add(obj, "mag-y", "int",
397
+ tmp421_get_temperature,
544
+ lsm303dlhc_mag_get_y,
398
+ tmp421_set_temperature, NULL, NULL, NULL);
545
+ lsm303dlhc_mag_set_y, NULL, NULL);
399
+}
546
+
400
+
547
+ object_property_add(obj, "mag-z", "int",
401
+static void tmp421_class_init(ObjectClass *klass, void *data)
548
+ lsm303dlhc_mag_get_z,
549
+ lsm303dlhc_mag_set_z, NULL, NULL);
550
+
551
+ object_property_add(obj, "temperature", "int",
552
+ lsm303dlhc_mag_get_temperature,
553
+ lsm303dlhc_mag_set_temperature, NULL, NULL);
554
+}
555
+
556
+/*
557
+ * Set the virtual method pointers (bus state change, tx/rx, etc.).
558
+ */
559
+static void lsm303dlhc_mag_class_init(ObjectClass *klass, void *data)
402
+{
560
+{
403
+ DeviceClass *dc = DEVICE_CLASS(klass);
561
+ DeviceClass *dc = DEVICE_CLASS(klass);
404
+ I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
562
+ I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
405
+ TMP421Class *sc = TMP421_CLASS(klass);
563
+
406
+
564
+ dc->reset = lsm303dlhc_mag_reset;
407
+ k->init = tmp421_init;
565
+ dc->vmsd = &vmstate_lsm303dlhc_mag;
408
+ k->event = tmp421_event;
566
+ k->event = lsm303dlhc_mag_event;
409
+ k->recv = tmp421_rx;
567
+ k->recv = lsm303dlhc_mag_recv;
410
+ k->send = tmp421_tx;
568
+ k->send = lsm303dlhc_mag_send;
411
+ dc->vmsd = &vmstate_tmp421;
569
+}
412
+ sc->dev = (DeviceInfo *) data;
570
+
413
+}
571
+static const TypeInfo lsm303dlhc_mag_info = {
414
+
572
+ .name = TYPE_LSM303DLHC_MAG,
415
+static const TypeInfo tmp421_info = {
573
+ .parent = TYPE_I2C_SLAVE,
416
+ .name = TYPE_TMP421,
574
+ .instance_size = sizeof(LSM303DLHCMagState),
417
+ .parent = TYPE_I2C_SLAVE,
575
+ .instance_init = lsm303dlhc_mag_initfn,
418
+ .instance_size = sizeof(TMP421State),
576
+ .class_init = lsm303dlhc_mag_class_init,
419
+ .instance_init = tmp421_initfn,
420
+ .class_init = tmp421_class_init,
421
+};
577
+};
422
+
578
+
423
+static void tmp421_register_types(void)
579
+static void lsm303dlhc_mag_register_types(void)
424
+{
580
+{
425
+ int i;
581
+ type_register_static(&lsm303dlhc_mag_info);
426
+
582
+}
427
+ type_register_static(&tmp421_info);
583
+
428
+ for (i = 0; i < ARRAY_SIZE(devices); ++i) {
584
+type_init(lsm303dlhc_mag_register_types)
429
+ TypeInfo ti = {
585
diff --git a/tests/qtest/lsm303dlhc-mag-test.c b/tests/qtest/lsm303dlhc-mag-test.c
430
+ .name = devices[i].name,
586
new file mode 100644
431
+ .parent = TYPE_TMP421,
587
index XXXXXXX..XXXXXXX
432
+ .class_init = tmp421_class_init,
588
--- /dev/null
433
+ .class_data = (void *) &devices[i],
589
+++ b/tests/qtest/lsm303dlhc-mag-test.c
434
+ };
590
@@ -XXX,XX +XXX,XX @@
435
+ type_register(&ti);
591
+/*
436
+ }
592
+ * QTest testcase for the LSM303DLHC I2C magnetometer
437
+}
593
+ *
438
+
594
+ * Copyright (C) 2021 Linaro Ltd.
439
+type_init(tmp421_register_types)
595
+ * Written by Kevin Townsend <kevin.townsend@linaro.org>
440
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
596
+ *
597
+ * Based on: https://www.st.com/resource/en/datasheet/lsm303dlhc.pdf
598
+ *
599
+ * SPDX-License-Identifier: GPL-2.0-or-later
600
+ */
601
+
602
+#include "qemu/osdep.h"
603
+#include "libqtest-single.h"
604
+#include "libqos/qgraph.h"
605
+#include "libqos/i2c.h"
606
+#include "qapi/qmp/qdict.h"
607
+
608
+#define LSM303DLHC_MAG_TEST_ID "lsm303dlhc_mag-test"
609
+#define LSM303DLHC_MAG_REG_CRA 0x00
610
+#define LSM303DLHC_MAG_REG_CRB 0x01
611
+#define LSM303DLHC_MAG_REG_OUT_X_H 0x03
612
+#define LSM303DLHC_MAG_REG_OUT_Z_H 0x05
613
+#define LSM303DLHC_MAG_REG_OUT_Y_H 0x07
614
+#define LSM303DLHC_MAG_REG_IRC 0x0C
615
+#define LSM303DLHC_MAG_REG_TEMP_OUT_H 0x31
616
+
617
+static int qmp_lsm303dlhc_mag_get_property(const char *id, const char *prop)
618
+{
619
+ QDict *response;
620
+ int ret;
621
+
622
+ response = qmp("{ 'execute': 'qom-get', 'arguments': { 'path': %s, "
623
+ "'property': %s } }", id, prop);
624
+ g_assert(qdict_haskey(response, "return"));
625
+ ret = qdict_get_int(response, "return");
626
+ qobject_unref(response);
627
+ return ret;
628
+}
629
+
630
+static void qmp_lsm303dlhc_mag_set_property(const char *id, const char *prop,
631
+ int value)
632
+{
633
+ QDict *response;
634
+
635
+ response = qmp("{ 'execute': 'qom-set', 'arguments': { 'path': %s, "
636
+ "'property': %s, 'value': %d } }", id, prop, value);
637
+ g_assert(qdict_haskey(response, "return"));
638
+ qobject_unref(response);
639
+}
640
+
641
+static void send_and_receive(void *obj, void *data, QGuestAllocator *alloc)
642
+{
643
+ int64_t value;
644
+ QI2CDevice *i2cdev = (QI2CDevice *)obj;
645
+
646
+ /* Check default value for CRB */
647
+ g_assert_cmphex(i2c_get8(i2cdev, LSM303DLHC_MAG_REG_CRB), ==, 0x20);
648
+
649
+ /* Set x to 1.0 gauss and verify the value */
650
+ qmp_lsm303dlhc_mag_set_property(LSM303DLHC_MAG_TEST_ID, "mag-x", 100000);
651
+ value = qmp_lsm303dlhc_mag_get_property(
652
+ LSM303DLHC_MAG_TEST_ID, "mag-x");
653
+ g_assert_cmpint(value, ==, 100000);
654
+
655
+ /* Set y to 1.5 gauss and verify the value */
656
+ qmp_lsm303dlhc_mag_set_property(LSM303DLHC_MAG_TEST_ID, "mag-y", 150000);
657
+ value = qmp_lsm303dlhc_mag_get_property(
658
+ LSM303DLHC_MAG_TEST_ID, "mag-y");
659
+ g_assert_cmpint(value, ==, 150000);
660
+
661
+ /* Set z to 0.5 gauss and verify the value */
662
+ qmp_lsm303dlhc_mag_set_property(LSM303DLHC_MAG_TEST_ID, "mag-z", 50000);
663
+ value = qmp_lsm303dlhc_mag_get_property(
664
+ LSM303DLHC_MAG_TEST_ID, "mag-z");
665
+ g_assert_cmpint(value, ==, 50000);
666
+
667
+ /* Set temperature to 23.6 C and verify the value */
668
+ qmp_lsm303dlhc_mag_set_property(LSM303DLHC_MAG_TEST_ID,
669
+ "temperature", 23600);
670
+ value = qmp_lsm303dlhc_mag_get_property(
671
+ LSM303DLHC_MAG_TEST_ID, "temperature");
672
+ /* Should return 23.5 C due to 0.125°C steps. */
673
+ g_assert_cmpint(value, ==, 23500);
674
+
675
+ /* Read raw x axis registers (1 gauss = 1100 at +/-1.3 g gain) */
676
+ value = i2c_get16(i2cdev, LSM303DLHC_MAG_REG_OUT_X_H);
677
+ g_assert_cmphex(value, ==, 1100);
678
+
679
+ /* Read raw y axis registers (1.5 gauss = 1650 at +/- 1.3 g gain = ) */
680
+ value = i2c_get16(i2cdev, LSM303DLHC_MAG_REG_OUT_Y_H);
681
+ g_assert_cmphex(value, ==, 1650);
682
+
683
+ /* Read raw z axis registers (0.5 gauss = 490 at +/- 1.3 g gain = ) */
684
+ value = i2c_get16(i2cdev, LSM303DLHC_MAG_REG_OUT_Z_H);
685
+ g_assert_cmphex(value, ==, 490);
686
+
687
+ /* Read raw temperature registers with temp disabled (CRA = 0x10) */
688
+ value = i2c_get16(i2cdev, LSM303DLHC_MAG_REG_TEMP_OUT_H);
689
+ g_assert_cmphex(value, ==, 0);
690
+
691
+ /* Enable temperature reads (CRA = 0x90) */
692
+ i2c_set8(i2cdev, LSM303DLHC_MAG_REG_CRA, 0x90);
693
+
694
+ /* Read raw temp registers (23.5 C = 188 at 1 lsb = 0.125 C) */
695
+ value = i2c_get16(i2cdev, LSM303DLHC_MAG_REG_TEMP_OUT_H);
696
+ g_assert_cmphex(value, ==, 188);
697
+}
698
+
699
+static void reg_wraparound(void *obj, void *data, QGuestAllocator *alloc)
700
+{
701
+ uint8_t value[4];
702
+ QI2CDevice *i2cdev = (QI2CDevice *)obj;
703
+
704
+ /* Set x to 1.0 gauss, and y to 1.5 gauss for known test values */
705
+ qmp_lsm303dlhc_mag_set_property(LSM303DLHC_MAG_TEST_ID, "mag-x", 100000);
706
+ qmp_lsm303dlhc_mag_set_property(LSM303DLHC_MAG_TEST_ID, "mag-y", 150000);
707
+
708
+ /* Check that requesting 4 bytes starting at Y_H wraps around to X_L */
709
+ i2c_read_block(i2cdev, LSM303DLHC_MAG_REG_OUT_Y_H, value, 4);
710
+ /* 1.5 gauss = 1650 lsb = 0x672 */
711
+ g_assert_cmphex(value[0], ==, 0x06);
712
+ g_assert_cmphex(value[1], ==, 0x72);
713
+ /* 1.0 gauss = 1100 lsb = 0x44C */
714
+ g_assert_cmphex(value[2], ==, 0x04);
715
+ g_assert_cmphex(value[3], ==, 0x4C);
716
+
717
+ /* Check that requesting LSM303DLHC_MAG_REG_IRC wraps around to CRA */
718
+ i2c_read_block(i2cdev, LSM303DLHC_MAG_REG_IRC, value, 2);
719
+ /* Default value for IRC = 0x33 */
720
+ g_assert_cmphex(value[0], ==, 0x33);
721
+ /* Default value for CRA = 0x10 */
722
+ g_assert_cmphex(value[1], ==, 0x10);
723
+}
724
+
725
+static void lsm303dlhc_mag_register_nodes(void)
726
+{
727
+ QOSGraphEdgeOptions opts = {
728
+ .extra_device_opts = "id=" LSM303DLHC_MAG_TEST_ID ",address=0x1e"
729
+ };
730
+ add_qi2c_address(&opts, &(QI2CAddress) { 0x1E });
731
+
732
+ qos_node_create_driver("lsm303dlhc_mag", i2c_device_create);
733
+ qos_node_consumes("lsm303dlhc_mag", "i2c-bus", &opts);
734
+
735
+ qos_add_test("tx-rx", "lsm303dlhc_mag", send_and_receive, NULL);
736
+ qos_add_test("regwrap", "lsm303dlhc_mag", reg_wraparound, NULL);
737
+}
738
+libqos_init(lsm303dlhc_mag_register_nodes);
739
diff --git a/hw/sensor/Kconfig b/hw/sensor/Kconfig
441
index XXXXXXX..XXXXXXX 100644
740
index XXXXXXX..XXXXXXX 100644
442
--- a/default-configs/arm-softmmu.mak
741
--- a/hw/sensor/Kconfig
443
+++ b/default-configs/arm-softmmu.mak
742
+++ b/hw/sensor/Kconfig
444
@@ -XXX,XX +XXX,XX @@ CONFIG_TWL92230=y
743
@@ -XXX,XX +XXX,XX @@ config ADM1272
445
CONFIG_TSC2005=y
744
config MAX34451
446
CONFIG_LM832X=y
745
bool
447
CONFIG_TMP105=y
746
depends on I2C
448
+CONFIG_TMP421=y
747
+
449
CONFIG_STELLARIS=y
748
+config LSM303DLHC_MAG
450
CONFIG_STELLARIS_INPUT=y
749
+ bool
451
CONFIG_STELLARIS_ENET=y
750
+ depends on I2C
751
diff --git a/hw/sensor/meson.build b/hw/sensor/meson.build
752
index XXXXXXX..XXXXXXX 100644
753
--- a/hw/sensor/meson.build
754
+++ b/hw/sensor/meson.build
755
@@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_DPS310', if_true: files('dps310.c'))
756
softmmu_ss.add(when: 'CONFIG_EMC141X', if_true: files('emc141x.c'))
757
softmmu_ss.add(when: 'CONFIG_ADM1272', if_true: files('adm1272.c'))
758
softmmu_ss.add(when: 'CONFIG_MAX34451', if_true: files('max34451.c'))
759
+softmmu_ss.add(when: 'CONFIG_LSM303DLHC_MAG', if_true: files('lsm303dlhc_mag.c'))
760
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
761
index XXXXXXX..XXXXXXX 100644
762
--- a/tests/qtest/meson.build
763
+++ b/tests/qtest/meson.build
764
@@ -XXX,XX +XXX,XX @@ qos_test_ss.add(
765
'eepro100-test.c',
766
'es1370-test.c',
767
'ipoctal232-test.c',
768
+ 'lsm303dlhc-mag-test.c',
769
'max34451-test.c',
770
'megasas-test.c',
771
'ne2000-test.c',
452
--
772
--
453
2.7.4
773
2.25.1
454
774
455
775
diff view generated by jsdifflib