1
Arm changes for before softfreeze: mostly my PL061/GPIO patches,
1
The following changes since commit 55ef0b702bc2c90c3c4ed97f97676d8f139e5ca1:
2
but also a new M-profile board and various other things.
3
2
4
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)
5
-- PMM
6
7
The following changes since commit 05de778b5b8ab0b402996769117b88c7ea5c7c61:
8
9
Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging (2021-07-09 14:30:01 +0100)
10
4
11
are available in the Git repository at:
5
are available in the Git repository at:
12
6
13
https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20210709
7
https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20220208
14
8
15
for you to fetch changes up to 05449abb1d4c5f0c69ceb3d8d03cbc75de39b646:
9
for you to fetch changes up to 4fd1ebb10593087d45d2f56f7f3d13447d24802c:
16
10
17
hw/intc: Improve formatting of MEMTX_ERROR guest error message (2021-07-09 16:09:12 +0100)
11
hw/sensor: Add lsm303dlhc magnetometer device (2022-02-08 10:56:29 +0000)
18
12
19
----------------------------------------------------------------
13
----------------------------------------------------------------
20
target-arm queue:
14
target-arm queue:
21
* New machine type: stm32vldiscovery
15
* Fix handling of SVE ZCR_LEN when using VHE
22
* hw/intc/arm_gicv3_cpuif: Fix virtual irq number check in icv_[dir|eoir]_write
16
* xlnx-zynqmp: 'Or' the QSPI / QSPI DMA IRQs
23
* hw/gpio/pl061: Honour Luminary PL061 PUR and PDR registers
17
* Don't ever enable PSCI when booting guest in EL3
24
* virt: Fix implementation of GPIO-based powerdown/shutdown mechanism
18
* Adhere to SMCCC 1.3 section 5.2
25
* Correct the encoding of MDCCSR_EL0 and DBGDSCRint
19
* highbank: Fix issues with booting SMP
26
* hw/intc: Improve formatting of MEMTX_ERROR guest error message
20
* midway: Fix issues booting at all
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
27
28
28
----------------------------------------------------------------
29
----------------------------------------------------------------
29
Alexandre Iooss (4):
30
Alex Bennée (1):
30
stm32f100: Add the stm32f100 SoC
31
arm: force flag recalculation when messing with DAIF
31
stm32vldiscovery: Add the STM32VLDISCOVERY Machine
32
docs/system: arm: Add stm32 boards description
33
tests/boot-serial-test: Add STM32VLDISCOVERY board testcase
34
32
35
Peter Maydell (10):
33
Edgar E. Iglesias (1):
36
hw/gpio/pl061: Convert DPRINTF to tracepoints
34
hw/arm: versal-virt: Always call arm_load_kernel()
37
hw/gpio/pl061: Clean up read/write offset handling logic
38
hw/gpio/pl061: Add tracepoints for register read and write
39
hw/gpio/pl061: Document the interface of this device
40
hw/gpio/pl061: Honour Luminary PL061 PUR and PDR registers
41
hw/gpio/pl061: Make pullup/pulldown of outputs configurable
42
hw/arm/virt: Make PL061 GPIO lines pulled low, not high
43
hw/gpio/pl061: Convert to 3-phase reset and assert GPIO lines correctly on reset
44
hw/gpio/pl061: Document a shortcoming in our implementation
45
hw/arm/stellaris: Expand comment about handling of OLED chipselect
46
35
47
Rebecca Cran (1):
36
Eric Auger (1):
48
hw/intc: Improve formatting of MEMTX_ERROR guest error message
37
hw/arm/smmuv3: Fix device reset
49
38
50
Ricardo Koller (1):
39
Francisco Iglesias (1):
51
hw/intc/arm_gicv3_cpuif: Fix virtual irq number check in icv_[dir|eoir]_write
40
hw/arm/xlnx-zynqmp: 'Or' the QSPI / QSPI DMA IRQs
52
41
53
hnick@vmware.com (1):
42
Kevin Townsend (1):
54
target/arm: Correct the encoding of MDCCSR_EL0 and DBGDSCRint
43
hw/sensor: Add lsm303dlhc magnetometer device
55
44
56
docs/system/arm/stm32.rst | 66 +++++++
45
Peter Maydell (29):
57
docs/system/target-arm.rst | 1 +
46
target/arm: make psci-conduit settable after realize
58
default-configs/devices/arm-softmmu.mak | 1 +
47
cpu.c: Make start-powered-off settable after realize
59
include/hw/arm/stm32f100_soc.h | 57 ++++++
48
hw/arm/boot: Support setting psci-conduit based on guest EL
60
hw/arm/stellaris.c | 56 +++++-
49
hw/arm: imx: Don't enable PSCI conduit when booting guest in EL3
61
hw/arm/stm32f100_soc.c | 182 +++++++++++++++++
50
hw/arm: allwinner: Don't enable PSCI conduit when booting guest in EL3
62
hw/arm/stm32vldiscovery.c | 66 +++++++
51
hw/arm/xlnx-zcu102: Don't enable PSCI conduit when booting guest in EL3
63
hw/arm/virt.c | 3 +
52
hw/arm/versal: Let boot.c handle PSCI enablement
64
hw/gpio/pl061.c | 341 +++++++++++++++++++++++++-------
53
hw/arm/virt: Let boot.c handle PSCI enablement
65
hw/intc/arm_gicv3_cpuif.c | 4 +-
54
hw/arm: highbank: For EL3 guests, don't enable PSCI, start all cores
66
hw/intc/arm_gicv3_redist.c | 4 +-
55
arm: tcg: Adhere to SMCCC 1.3 section 5.2
67
target/arm/helper.c | 16 +-
56
hw/arm/highbank: Drop use of secure_board_setup
68
tests/qtest/boot-serial-test.c | 37 ++++
57
hw/arm/boot: Prevent setting both psci_conduit and secure_board_setup
69
MAINTAINERS | 13 ++
58
hw/arm/boot: Don't write secondary boot stub if using PSCI
70
hw/arm/Kconfig | 10 +
59
hw/arm/highbank: Drop unused secondary boot stub code
71
hw/arm/meson.build | 2 +
60
hw/arm/boot: Drop nb_cpus field from arm_boot_info
72
hw/gpio/trace-events | 9 +
61
hw/arm/boot: Drop existing dtb /psci node rather than retaining it
73
17 files changed, 790 insertions(+), 78 deletions(-)
62
hw/intc/arm_gicv3_its: Use address_space_map() to access command queue packets
74
create mode 100644 docs/system/arm/stm32.rst
63
hw/intc/arm_gicv3_its: Keep DTEs as a struct, not a raw uint64_t
75
create mode 100644 include/hw/arm/stm32f100_soc.h
64
hw/intc/arm_gicv3_its: Pass DTEntry to update_dte()
76
create mode 100644 hw/arm/stm32f100_soc.c
65
hw/intc/arm_gicv3_its: Keep CTEs as a struct, not a raw uint64_t
77
create mode 100644 hw/arm/stm32vldiscovery.c
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
78
75
76
Richard Henderson (4):
77
target/arm: Fix sve_zcr_len_for_el for VHE mode running
78
target/arm: Tidy sve_exception_el for CPACR_EL1 access
79
target/arm: Fix {fp, sve}_exception_el for VHE mode running
80
target/arm: Use CPTR_TFP with CPTR_EL3 in fp_exception_el
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
New patch
1
From: Richard Henderson <richard.henderson@linaro.org>
1
2
3
When HCR_EL2.{E2H,TGE} == '11', ZCR_EL1 is unused.
4
5
Reported-by: Zenghui Yu <yuzenghui@huawei.com>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Zenghui Yu <yuzenghui@huawei.com>
9
Message-id: 20220127063428.30212-2-richard.henderson@linaro.org
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
12
target/arm/helper.c | 3 ++-
13
1 file changed, 2 insertions(+), 1 deletion(-)
14
15
diff --git a/target/arm/helper.c b/target/arm/helper.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/target/arm/helper.c
18
+++ b/target/arm/helper.c
19
@@ -XXX,XX +XXX,XX @@ uint32_t sve_zcr_len_for_el(CPUARMState *env, int el)
20
ARMCPU *cpu = env_archcpu(env);
21
uint32_t zcr_len = cpu->sve_max_vq - 1;
22
23
- if (el <= 1) {
24
+ if (el <= 1 &&
25
+ (arm_hcr_el2_eff(env) & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE)) {
26
zcr_len = MIN(zcr_len, 0xf & (uint32_t)env->vfp.zcr_el[1]);
27
}
28
if (el <= 2 && arm_feature(env, ARM_FEATURE_EL2)) {
29
--
30
2.25.1
31
32
diff view generated by jsdifflib
New patch
1
From: Richard Henderson <richard.henderson@linaro.org>
1
2
3
Extract entire fields for ZEN and FPEN, rather than testing specific bits.
4
This makes it easier to follow the code versus the ARM spec.
5
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Zenghui Yu <yuzenghui@huawei.com>
9
Message-id: 20220127063428.30212-3-richard.henderson@linaro.org
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
12
target/arm/helper.c | 36 +++++++++++++++++-------------------
13
1 file changed, 17 insertions(+), 19 deletions(-)
14
15
diff --git a/target/arm/helper.c b/target/arm/helper.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/target/arm/helper.c
18
+++ b/target/arm/helper.c
19
@@ -XXX,XX +XXX,XX @@ int sve_exception_el(CPUARMState *env, int el)
20
uint64_t hcr_el2 = arm_hcr_el2_eff(env);
21
22
if (el <= 1 && (hcr_el2 & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE)) {
23
- bool disabled = false;
24
-
25
- /* The CPACR.ZEN controls traps to EL1:
26
- * 0, 2 : trap EL0 and EL1 accesses
27
- * 1 : trap only EL0 accesses
28
- * 3 : trap no accesses
29
- */
30
- if (!extract32(env->cp15.cpacr_el1, 16, 1)) {
31
- disabled = true;
32
- } else if (!extract32(env->cp15.cpacr_el1, 17, 1)) {
33
- disabled = el == 0;
34
- }
35
- if (disabled) {
36
+ /* Check CPACR.ZEN. */
37
+ switch (extract32(env->cp15.cpacr_el1, 16, 2)) {
38
+ case 1:
39
+ if (el != 0) {
40
+ break;
41
+ }
42
+ /* fall through */
43
+ case 0:
44
+ case 2:
45
/* route_to_el2 */
46
return hcr_el2 & HCR_TGE ? 2 : 1;
47
}
48
49
/* Check CPACR.FPEN. */
50
- if (!extract32(env->cp15.cpacr_el1, 20, 1)) {
51
- disabled = true;
52
- } else if (!extract32(env->cp15.cpacr_el1, 21, 1)) {
53
- disabled = el == 0;
54
- }
55
- if (disabled) {
56
+ switch (extract32(env->cp15.cpacr_el1, 20, 2)) {
57
+ case 1:
58
+ if (el != 0) {
59
+ break;
60
+ }
61
+ /* fall through */
62
+ case 0:
63
+ case 2:
64
return 0;
65
}
66
}
67
--
68
2.25.1
69
70
diff view generated by jsdifflib
New patch
1
From: Richard Henderson <richard.henderson@linaro.org>
1
2
3
When HCR_EL2.E2H is set, the format of CPTR_EL2 changes to
4
look more like CPACR_EL1, with ZEN and FPEN fields instead
5
of TZ and TFP fields.
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
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
---
13
target/arm/helper.c | 77 +++++++++++++++++++++++++++++++++++----------
14
1 file changed, 60 insertions(+), 17 deletions(-)
15
16
diff --git a/target/arm/helper.c b/target/arm/helper.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/target/arm/helper.c
19
+++ b/target/arm/helper.c
20
@@ -XXX,XX +XXX,XX @@ int sve_exception_el(CPUARMState *env, int el)
21
}
22
}
23
24
- /* CPTR_EL2. Since TZ and TFP are positive,
25
- * they will be zero when EL2 is not present.
26
+ /*
27
+ * CPTR_EL2 changes format with HCR_EL2.E2H (regardless of TGE).
28
*/
29
- if (el <= 2 && arm_is_el2_enabled(env)) {
30
- if (env->cp15.cptr_el[2] & CPTR_TZ) {
31
- return 2;
32
- }
33
- if (env->cp15.cptr_el[2] & CPTR_TFP) {
34
- return 0;
35
+ if (el <= 2) {
36
+ if (hcr_el2 & HCR_E2H) {
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)
72
{
73
#ifndef CONFIG_USER_ONLY
74
+ uint64_t hcr_el2;
75
+
76
/* CPACR and the CPTR registers don't exist before v6, so FP is
77
* always accessible
78
*/
79
@@ -XXX,XX +XXX,XX @@ int fp_exception_el(CPUARMState *env, int cur_el)
80
return 0;
81
}
82
83
+ hcr_el2 = arm_hcr_el2_eff(env);
84
+
85
/* The CPACR controls traps to EL1, or PL1 if we're 32 bit:
86
* 0, 2 : trap EL0 and EL1/PL1 accesses
87
* 1 : trap only EL0 accesses
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
+ }
129
+ }
130
}
131
132
/* CPTR_EL3 : present in v8 */
133
--
134
2.25.1
135
136
diff view generated by jsdifflib
1
From: "hnick@vmware.com" <hnick@vmware.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
Signed-off-by: Nick Hudson <hnick@vmware.com>
3
Use the named bit rather than a bare extract32.
4
5
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
4
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Zenghui Yu <yuzenghui@huawei.com>
8
Message-id: 20220127063428.30212-5-richard.henderson@linaro.org
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
---
10
---
7
target/arm/helper.c | 16 +++++++++++++---
11
target/arm/helper.c | 2 +-
8
1 file changed, 13 insertions(+), 3 deletions(-)
12
1 file changed, 1 insertion(+), 1 deletion(-)
9
13
10
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
11
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
12
--- a/target/arm/helper.c
16
--- a/target/arm/helper.c
13
+++ b/target/arm/helper.c
17
+++ b/target/arm/helper.c
14
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
18
@@ -XXX,XX +XXX,XX @@ int fp_exception_el(CPUARMState *env, int cur_el)
15
.access = PL1_RW, .accessfn = access_tda,
19
}
16
.fieldoffset = offsetof(CPUARMState, cp15.mdscr_el1),
20
17
.resetvalue = 0 },
21
/* CPTR_EL3 : present in v8 */
18
- /* MDCCSR_EL0, aka DBGDSCRint. This is a read-only mirror of MDSCR_EL1.
22
- if (extract32(env->cp15.cptr_el[3], 10, 1)) {
19
+ /*
23
+ if (env->cp15.cptr_el[3] & CPTR_TFP) {
20
+ * MDCCSR_EL0[30:29] map to EDSCR[30:29]. Simply RAZ as the external
24
/* Trap all FP ops to EL3 */
21
+ * Debug Communication Channel is not implemented.
25
return 3;
22
+ */
26
}
23
+ { .name = "MDCCSR_EL0", .state = ARM_CP_STATE_AA64,
24
+ .opc0 = 2, .opc1 = 3, .crn = 0, .crm = 1, .opc2 = 0,
25
+ .access = PL0_R, .accessfn = access_tda,
26
+ .type = ARM_CP_CONST, .resetvalue = 0 },
27
+ /*
28
+ * DBGDSCRint[15,12,5:2] map to MDSCR_EL1[15,12,5:2]. Map all bits as
29
+ * it is unlikely a guest will care.
30
* We don't implement the configurable EL0 access.
31
*/
32
- { .name = "MDCCSR_EL0", .state = ARM_CP_STATE_BOTH,
33
- .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 0,
34
+ { .name = "DBGDSCRint", .state = ARM_CP_STATE_AA32,
35
+ .cp = 14, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 0,
36
.type = ARM_CP_ALIAS,
37
.access = PL1_R, .accessfn = access_tda,
38
.fieldoffset = offsetof(CPUARMState, cp15.mdscr_el1), },
39
--
27
--
40
2.20.1
28
2.25.1
41
29
42
30
diff view generated by jsdifflib
New patch
1
From: Francisco Iglesias <francisco.iglesias@xilinx.com>
1
2
3
'Or' the IRQs coming from the QSPI and QSPI DMA models. This is done for
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).
7
8
Signed-off-by: Francisco Iglesias <francisco.iglesias@xilinx.com>
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
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
---
14
include/hw/arm/xlnx-zynqmp.h | 2 ++
15
hw/arm/xlnx-zynqmp.c | 14 ++++++++++++--
16
2 files changed, 14 insertions(+), 2 deletions(-)
17
18
diff --git a/include/hw/arm/xlnx-zynqmp.h b/include/hw/arm/xlnx-zynqmp.h
19
index XXXXXXX..XXXXXXX 100644
20
--- a/include/hw/arm/xlnx-zynqmp.h
21
+++ b/include/hw/arm/xlnx-zynqmp.h
22
@@ -XXX,XX +XXX,XX @@
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)
51
}
52
53
object_initialize_child(obj, "qspi-dma", &s->qspi_dma, TYPE_XLNX_CSU_DMA);
54
+ object_initialize_child(obj, "qspi-irq-orgate",
55
+ &s->qspi_irq_orgate, TYPE_OR_IRQ);
56
}
57
58
static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
59
@@ -XXX,XX +XXX,XX @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
60
gic_spi[adma_ch_intr[i]]);
61
}
62
63
+ object_property_set_int(OBJECT(&s->qspi_irq_orgate),
64
+ "num-lines", NUM_QSPI_IRQ_LINES, &error_fatal);
65
+ qdev_realize(DEVICE(&s->qspi_irq_orgate), NULL, &error_fatal);
66
+ qdev_connect_gpio_out(DEVICE(&s->qspi_irq_orgate), 0, gic_spi[QSPI_IRQ]);
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);
91
--
92
2.25.1
93
94
diff view generated by jsdifflib
New patch
1
We want to allow the psci-conduit property to be set after realize,
2
because the parts of the code which are best placed to decide if it's
3
OK to enable QEMU's builtin PSCI emulation (the board code and the
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.
1
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.)
20
21
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
22
Reviewed-by: Richard Henderson <richard.henderson@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
26
---
27
target/arm/cpu.c | 6 +++++-
28
1 file changed, 5 insertions(+), 1 deletion(-)
29
30
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
31
index XXXXXXX..XXXXXXX 100644
32
--- a/target/arm/cpu.c
33
+++ b/target/arm/cpu.c
34
@@ -XXX,XX +XXX,XX @@ void arm_cpu_post_init(Object *obj)
35
OBJ_PROP_FLAG_READWRITE);
36
}
37
38
+ /* Not DEFINE_PROP_UINT32: we want this to be settable after realize */
39
+ object_property_add_uint32_ptr(obj, "psci-conduit",
40
+ &cpu->psci_conduit,
41
+ OBJ_PROP_FLAG_READWRITE);
42
+
43
qdev_property_add_static(DEVICE(obj), &arm_cpu_cfgend_property);
44
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),
54
--
55
2.25.1
56
57
diff view generated by jsdifflib
1
The Luminary variant of the PL061 has registers GPIOPUR and GPIOPDR
1
The CPU object's start-powered-off property is currently only
2
which lets the guest configure whether the GPIO lines are pull-up,
2
settable before the CPU object is realized. For arm machines this is
3
pull-down, or truly floating. Instead of assuming all lines are pulled
3
awkward, because we would like to decide whether the CPU should be
4
high, honour the PUR and PDR registers.
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.
5
9
6
For the plain PL061, continue to assume that lines have an external
10
Allow start-powered-off to be set after realize. Since this isn't
7
pull-up resistor, as we did before.
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.
8
14
9
The stellaris board actually relies on this behaviour -- the CD line
15
Note that it doesn't conceptually make sense to change the setting of
10
of the ssd0323 display device is connected to GPIO output C7, and it
16
the property after the machine has been completely initialized,
11
is only because of a different bug which we're about to fix that we
17
beacuse this would mean that the behaviour of the machine when first
12
weren't incorrectly driving this line high on reset and putting the
18
started would differ from its behaviour when the system is
13
ssd0323 into data mode.
19
subsequently reset. (It would also require the underlying state to
20
be migrated, which we don't do.)
14
21
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
22
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
Reviewed-by: Richard Henderson <richard.henderson@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
17
---
27
---
18
hw/gpio/pl061.c | 58 +++++++++++++++++++++++++++++++++++++++++---
28
cpu.c | 22 +++++++++++++++++++++-
19
hw/gpio/trace-events | 2 +-
29
1 file changed, 21 insertions(+), 1 deletion(-)
20
2 files changed, 55 insertions(+), 5 deletions(-)
21
30
22
diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.c
31
diff --git a/cpu.c b/cpu.c
23
index XXXXXXX..XXXXXXX 100644
32
index XXXXXXX..XXXXXXX 100644
24
--- a/hw/gpio/pl061.c
33
--- a/cpu.c
25
+++ b/hw/gpio/pl061.c
34
+++ b/cpu.c
26
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_pl061 = {
35
@@ -XXX,XX +XXX,XX @@ static Property cpu_common_props[] = {
27
}
36
DEFINE_PROP_LINK("memory", CPUState, memory, TYPE_MEMORY_REGION,
37
MemoryRegion *),
38
#endif
39
- DEFINE_PROP_BOOL("start-powered-off", CPUState, start_powered_off, false),
40
DEFINE_PROP_END_OF_LIST(),
28
};
41
};
29
42
30
+static uint8_t pl061_floating(PL061State *s)
43
+static bool cpu_get_start_powered_off(Object *obj, Error **errp)
31
+{
44
+{
32
+ /*
45
+ CPUState *cpu = CPU(obj);
33
+ * Return mask of bits which correspond to pins configured as inputs
46
+ return cpu->start_powered_off;
34
+ * and which are floating (neither pulled up to 1 nor down to 0).
35
+ */
36
+ uint8_t floating;
37
+
38
+ if (s->id == pl061_id_luminary) {
39
+ /*
40
+ * If both PUR and PDR bits are clear, there is neither a pullup
41
+ * nor a pulldown in place, and the output truly floats.
42
+ */
43
+ floating = ~(s->pur | s->pdr);
44
+ } else {
45
+ /* Assume outputs are pulled high. FIXME: this is board dependent. */
46
+ floating = 0;
47
+ }
48
+ return floating & ~s->dir;
49
+}
47
+}
50
+
48
+
51
+static uint8_t pl061_pullups(PL061State *s)
49
+static void cpu_set_start_powered_off(Object *obj, bool value, Error **errp)
52
+{
50
+{
53
+ /*
51
+ CPUState *cpu = CPU(obj);
54
+ * Return mask of bits which correspond to pins configured as inputs
52
+ cpu->start_powered_off = value;
55
+ * and which are pulled up to 1.
56
+ */
57
+ uint8_t pullups;
58
+
59
+ if (s->id == pl061_id_luminary) {
60
+ /*
61
+ * The Luminary variant of the PL061 has an extra registers which
62
+ * the guest can use to configure whether lines should be pullup
63
+ * or pulldown.
64
+ */
65
+ pullups = s->pur;
66
+ } else {
67
+ /* Assume outputs are pulled high. FIXME: this is board dependent. */
68
+ pullups = 0xff;
69
+ }
70
+ return pullups & ~s->dir;
71
+}
53
+}
72
+
54
+
73
static void pl061_update(PL061State *s)
55
void cpu_class_init_props(DeviceClass *dc)
74
{
56
{
75
uint8_t changed;
57
+ ObjectClass *oc = OBJECT_CLASS(dc);
76
uint8_t mask;
58
+
77
uint8_t out;
59
device_class_set_props(dc, cpu_common_props);
78
int i;
79
+ uint8_t pullups = pl061_pullups(s);
80
+ uint8_t floating = pl061_floating(s);
81
82
- trace_pl061_update(DEVICE(s)->canonical_path, s->dir, s->data);
83
+ trace_pl061_update(DEVICE(s)->canonical_path, s->dir, s->data,
84
+ pullups, floating);
85
86
- /* Outputs float high. */
87
- /* FIXME: This is board dependent. */
88
- out = (s->data & s->dir) | ~s->dir;
89
+ /*
60
+ /*
90
+ * Pins configured as output are driven from the data register;
61
+ * We can't use DEFINE_PROP_BOOL in the Property array for this
91
+ * otherwise if they're pulled up they're 1, and if they're floating
62
+ * property, because we want this to be settable after realize.
92
+ * then we give them the same value they had previously, so we don't
93
+ * report any change to the other end.
94
+ */
63
+ */
95
+ out = (s->data & s->dir) | pullups | (s->old_out_data & floating);
64
+ object_class_property_add_bool(oc, "start-powered-off",
96
changed = s->old_out_data ^ out;
65
+ cpu_get_start_powered_off,
97
if (changed) {
66
+ cpu_set_start_powered_off);
98
s->old_out_data = out;
67
}
99
diff --git a/hw/gpio/trace-events b/hw/gpio/trace-events
68
100
index XXXXXXX..XXXXXXX 100644
69
void cpu_exec_initfn(CPUState *cpu)
101
--- a/hw/gpio/trace-events
102
+++ b/hw/gpio/trace-events
103
@@ -XXX,XX +XXX,XX @@ nrf51_gpio_set(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64
104
nrf51_gpio_update_output_irq(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64
105
106
# pl061.c
107
-pl061_update(const char *id, uint32_t dir, uint32_t data) "%s GPIODIR 0x%x GPIODATA 0x%x"
108
+pl061_update(const char *id, uint32_t dir, uint32_t data, uint32_t pullups, uint32_t floating) "%s GPIODIR 0x%x GPIODATA 0x%x pullups 0x%x floating 0x%x"
109
pl061_set_output(const char *id, int gpio, int level) "%s setting output %d to %d"
110
pl061_input_change(const char *id, int gpio, int level) "%s input %d changed to %d"
111
pl061_update_istate(const char *id, uint32_t istate, uint32_t im, int level) "%s GPIORIS 0x%x GPIOIE 0x%x interrupt level %d"
112
--
70
--
113
2.20.1
71
2.25.1
114
72
115
73
diff view generated by jsdifflib
1
The Luminary PL061s in the Stellaris LM3S9695 don't all have the same
1
Currently we expect board code to set the psci-conduit property on
2
reset value for GPIOPUR. We can get away with not letting the board
2
CPUs and ensure that secondary CPUs are created with the
3
configure the PUR reset value because we don't actually wire anything
3
start-powered-off property set to false, if the board wishes to use
4
up to the lines which should reset to pull-up. Add a comment noting
4
QEMU's builtin PSCI emulation. This worked OK for the virt board
5
this omission.
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.
6
61
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
62
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
63
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
64
Tested-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
65
Tested-by: Cédric Le Goater <clg@kaod.org>
66
Message-id: 20220127154639.2090164-4-peter.maydell@linaro.org
9
---
67
---
10
hw/gpio/pl061.c | 9 +++++++++
68
include/hw/arm/boot.h | 10 +++++++++
11
1 file changed, 9 insertions(+)
69
hw/arm/boot.c | 50 +++++++++++++++++++++++++++++++++++++++++++
70
2 files changed, 60 insertions(+)
12
71
13
diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.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/hw/gpio/pl061.c
74
--- a/include/hw/arm/boot.h
16
+++ b/hw/gpio/pl061.c
75
+++ b/include/hw/arm/boot.h
17
@@ -XXX,XX +XXX,XX @@ static void pl061_enter_reset(Object *obj, ResetType type)
76
@@ -XXX,XX +XXX,XX @@ struct arm_boot_info {
18
trace_pl061_reset(DEVICE(s)->canonical_path);
77
* the user it should implement this hook.
19
78
*/
20
/* reset values from PL061 TRM, Stellaris LM3S5P31 & LM3S8962 Data Sheet */
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);
108
}
109
110
+ /*
111
+ * Disable the PSCI conduit if it is set up to target the same
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;
129
+ }
130
+
131
+ if ((info->psci_conduit == QEMU_PSCI_CONDUIT_HVC && boot_el >= 2) ||
132
+ (info->psci_conduit == QEMU_PSCI_CONDUIT_SMC && boot_el == 3)) {
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
+ }
21
+
153
+
22
+ /*
154
+ /*
23
+ * FIXME: For the LM3S6965, not all of the PL061 instances have the
155
+ * arm_load_dtb() may add a PSCI node so it must be called after we have
24
+ * same reset values for GPIOPUR, GPIOAFSEL and GPIODEN, so in theory
156
+ * decided whether to enable PSCI and set the psci-conduit CPU properties.
25
+ * we should allow the board to configure these via properties.
26
+ * In practice, we don't wire anything up to the affected GPIO lines
27
+ * (PB7, PC0, PC1, PC2, PC3 -- they're used for JTAG), so we can
28
+ * get away with this inaccuracy.
29
+ */
157
+ */
30
s->data = 0;
158
if (!info->skip_dtb_autoload && have_dtb(info)) {
31
s->old_in_data = 0;
159
if (arm_load_dtb(info->dtb_start, info, info->dtb_limit, as, ms) < 0) {
32
s->dir = 0;
160
exit(1);
33
--
161
--
34
2.20.1
162
2.25.1
35
163
36
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
New patch
1
Change the allwinner-h3 based board to use the new boot.c
2
functionality to allow us to enable psci-conduit only if the guest is
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.
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 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).
20
21
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
22
Reviewed-by: Richard Henderson <richard.henderson@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
27
---
28
hw/arm/allwinner-h3.c | 9 ++++-----
29
hw/arm/orangepi.c | 1 +
30
2 files changed, 5 insertions(+), 5 deletions(-)
31
32
diff --git a/hw/arm/allwinner-h3.c b/hw/arm/allwinner-h3.c
33
index XXXXXXX..XXXXXXX 100644
34
--- a/hw/arm/allwinner-h3.c
35
+++ b/hw/arm/allwinner-h3.c
36
@@ -XXX,XX +XXX,XX @@ static void allwinner_h3_realize(DeviceState *dev, Error **errp)
37
/* CPUs */
38
for (i = 0; i < AW_H3_NUM_CPUS; i++) {
39
40
- /* Provide Power State Coordination Interface */
41
- qdev_prop_set_int32(DEVICE(&s->cpus[i]), "psci-conduit",
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);
62
}
63
64
--
65
2.25.1
66
67
diff view generated by jsdifflib
1
Add tracepoints for reads and writes to the PL061 registers. This requires
1
Change the Xilinx ZynqMP-based board xlnx-zcu102 to use the new
2
restructuring pl061_read() to only return after the tracepoint, rather
2
boot.c functionality to allow us to enable psci-conduit only if
3
than having lots of early-returns.
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.
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.
4
16
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
17
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
18
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
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
8
---
26
---
9
hw/gpio/pl061.c | 70 ++++++++++++++++++++++++++++++--------------
27
hw/arm/xlnx-zcu102.c | 1 +
10
hw/gpio/trace-events | 2 ++
28
hw/arm/xlnx-zynqmp.c | 11 ++++++-----
11
2 files changed, 50 insertions(+), 22 deletions(-)
29
2 files changed, 7 insertions(+), 5 deletions(-)
12
30
13
diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.c
31
diff --git a/hw/arm/xlnx-zcu102.c b/hw/arm/xlnx-zcu102.c
14
index XXXXXXX..XXXXXXX 100644
32
index XXXXXXX..XXXXXXX 100644
15
--- a/hw/gpio/pl061.c
33
--- a/hw/arm/xlnx-zcu102.c
16
+++ b/hw/gpio/pl061.c
34
+++ b/hw/arm/xlnx-zcu102.c
17
@@ -XXX,XX +XXX,XX @@ static uint64_t pl061_read(void *opaque, hwaddr offset,
35
@@ -XXX,XX +XXX,XX @@ static void xlnx_zcu102_init(MachineState *machine)
18
unsigned size)
36
s->binfo.ram_size = ram_size;
19
{
37
s->binfo.loader_start = 0;
20
PL061State *s = (PL061State *)opaque;
38
s->binfo.modify_dtb = zcu102_modify_dtb;
21
+ uint64_t r = 0;
39
+ s->binfo.psci_conduit = QEMU_PSCI_CONDUIT_SMC;
22
40
arm_load_kernel(s->soc.boot_cpu_ptr, machine, &s->binfo);
23
switch (offset) {
24
case 0x0 ... 0x3ff: /* Data */
25
- return s->data & (offset >> 2);
26
+ r = s->data & (offset >> 2);
27
+ break;
28
case 0x400: /* Direction */
29
- return s->dir;
30
+ r = s->dir;
31
+ break;
32
case 0x404: /* Interrupt sense */
33
- return s->isense;
34
+ r = s->isense;
35
+ break;
36
case 0x408: /* Interrupt both edges */
37
- return s->ibe;
38
+ r = s->ibe;
39
+ break;
40
case 0x40c: /* Interrupt event */
41
- return s->iev;
42
+ r = s->iev;
43
+ break;
44
case 0x410: /* Interrupt mask */
45
- return s->im;
46
+ r = s->im;
47
+ break;
48
case 0x414: /* Raw interrupt status */
49
- return s->istate;
50
+ r = s->istate;
51
+ break;
52
case 0x418: /* Masked interrupt status */
53
- return s->istate & s->im;
54
+ r = s->istate & s->im;
55
+ break;
56
case 0x420: /* Alternate function select */
57
- return s->afsel;
58
+ r = s->afsel;
59
+ break;
60
case 0x500: /* 2mA drive */
61
if (s->id != pl061_id_luminary) {
62
goto bad_offset;
63
}
64
- return s->dr2r;
65
+ r = s->dr2r;
66
+ break;
67
case 0x504: /* 4mA drive */
68
if (s->id != pl061_id_luminary) {
69
goto bad_offset;
70
}
71
- return s->dr4r;
72
+ r = s->dr4r;
73
+ break;
74
case 0x508: /* 8mA drive */
75
if (s->id != pl061_id_luminary) {
76
goto bad_offset;
77
}
78
- return s->dr8r;
79
+ r = s->dr8r;
80
+ break;
81
case 0x50c: /* Open drain */
82
if (s->id != pl061_id_luminary) {
83
goto bad_offset;
84
}
85
- return s->odr;
86
+ r = s->odr;
87
+ break;
88
case 0x510: /* Pull-up */
89
if (s->id != pl061_id_luminary) {
90
goto bad_offset;
91
}
92
- return s->pur;
93
+ r = s->pur;
94
+ break;
95
case 0x514: /* Pull-down */
96
if (s->id != pl061_id_luminary) {
97
goto bad_offset;
98
}
99
- return s->pdr;
100
+ r = s->pdr;
101
+ break;
102
case 0x518: /* Slew rate control */
103
if (s->id != pl061_id_luminary) {
104
goto bad_offset;
105
}
106
- return s->slr;
107
+ r = s->slr;
108
+ break;
109
case 0x51c: /* Digital enable */
110
if (s->id != pl061_id_luminary) {
111
goto bad_offset;
112
}
113
- return s->den;
114
+ r = s->den;
115
+ break;
116
case 0x520: /* Lock */
117
if (s->id != pl061_id_luminary) {
118
goto bad_offset;
119
}
120
- return s->locked;
121
+ r = s->locked;
122
+ break;
123
case 0x524: /* Commit */
124
if (s->id != pl061_id_luminary) {
125
goto bad_offset;
126
}
127
- return s->cr;
128
+ r = s->cr;
129
+ break;
130
case 0x528: /* Analog mode select */
131
if (s->id != pl061_id_luminary) {
132
goto bad_offset;
133
}
134
- return s->amsel;
135
+ r = s->amsel;
136
+ break;
137
case 0xfd0 ... 0xfff: /* ID registers */
138
- return s->id[(offset - 0xfd0) >> 2];
139
+ r = s->id[(offset - 0xfd0) >> 2];
140
+ break;
141
default:
142
bad_offset:
143
qemu_log_mask(LOG_GUEST_ERROR,
144
"pl061_read: Bad offset %x\n", (int)offset);
145
break;
146
}
147
- return 0;
148
+
149
+ trace_pl061_read(DEVICE(s)->canonical_path, offset, r);
150
+ return r;
151
}
41
}
152
42
153
static void pl061_write(void *opaque, hwaddr offset,
43
diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
154
@@ -XXX,XX +XXX,XX @@ static void pl061_write(void *opaque, hwaddr offset,
155
PL061State *s = (PL061State *)opaque;
156
uint8_t mask;
157
158
+ trace_pl061_write(DEVICE(s)->canonical_path, offset, value);
159
+
160
switch (offset) {
161
case 0 ... 0x3ff:
162
mask = (offset >> 2) & s->dir;
163
diff --git a/hw/gpio/trace-events b/hw/gpio/trace-events
164
index XXXXXXX..XXXXXXX 100644
44
index XXXXXXX..XXXXXXX 100644
165
--- a/hw/gpio/trace-events
45
--- a/hw/arm/xlnx-zynqmp.c
166
+++ b/hw/gpio/trace-events
46
+++ b/hw/arm/xlnx-zynqmp.c
167
@@ -XXX,XX +XXX,XX @@ pl061_update(const char *id, uint32_t dir, uint32_t data) "%s GPIODIR 0x%x GPIOD
47
@@ -XXX,XX +XXX,XX @@ static void xlnx_zynqmp_create_rpu(MachineState *ms, XlnxZynqMPState *s,
168
pl061_set_output(const char *id, int gpio, int level) "%s setting output %d to %d"
48
169
pl061_input_change(const char *id, int gpio, int level) "%s input %d changed to %d"
49
name = object_get_canonical_path_component(OBJECT(&s->rpu_cpu[i]));
170
pl061_update_istate(const char *id, uint32_t istate, uint32_t im, int level) "%s GPIORIS 0x%x GPIOIE 0x%x interrupt level %d"
50
if (strcmp(name, boot_cpu)) {
171
+pl061_read(const char *id, uint64_t offset, uint64_t r) "%s offset 0x%" PRIx64 " value 0x%" PRIx64
51
- /* Secondary CPUs start in PSCI powered-down state */
172
+pl061_write(const char *id, uint64_t offset, uint64_t value) "%s offset 0x%" PRIx64 " value 0x%" PRIx64
52
+ /*
173
53
+ * Secondary CPUs start in powered-down state.
174
# sifive_gpio.c
54
+ */
175
sifive_gpio_read(uint64_t offset, uint64_t r) "offset 0x%" PRIx64 " value 0x%" PRIx64
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 {
176
--
74
--
177
2.20.1
75
2.25.1
178
76
179
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
For the virt board we have two PL061 devices -- one for NonSecure which
1
Instead of setting the CPU psci-conduit and start-powered-off
2
is inputs only, and one for Secure which is outputs only. For the former,
2
properties in the virt board code, set the arm_boot_info psci_conduit
3
we don't care whether its outputs are pulled low or high when the line is
3
field so that the boot.c code can do it.
4
configured as an input, because we don't connect them. For the latter,
5
we do care, because we wire the lines up to the gpio-pwr device, which
6
assumes that level 1 means "do the action" and 1 means "do nothing".
7
For consistency in case we add more outputs in future, configure both
8
PL061s to pull GPIO lines down to 0.
9
4
10
Reported-by: Maxim Uvarov <maxim.uvarov@linaro.org>
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.)
10
11
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>
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
13
---
17
---
14
hw/arm/virt.c | 3 +++
18
hw/arm/virt.c | 12 +-----------
15
1 file changed, 3 insertions(+)
19
1 file changed, 1 insertion(+), 11 deletions(-)
16
20
17
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
18
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
19
--- a/hw/arm/virt.c
23
--- a/hw/arm/virt.c
20
+++ b/hw/arm/virt.c
24
+++ b/hw/arm/virt.c
21
@@ -XXX,XX +XXX,XX @@ static void create_gpio_devices(const VirtMachineState *vms, int gpio,
25
@@ -XXX,XX +XXX,XX @@ static void machvirt_init(MachineState *machine)
22
MachineState *ms = MACHINE(vms);
26
object_property_set_bool(cpuobj, "has_el2", false, NULL);
23
27
}
24
pl061_dev = qdev_new("pl061");
28
25
+ /* Pull lines down to 0 if not driven by the PL061 */
29
- if (vms->psci_conduit != QEMU_PSCI_CONDUIT_DISABLED) {
26
+ qdev_prop_set_uint32(pl061_dev, "pullups", 0);
30
- object_property_set_int(cpuobj, "psci-conduit", vms->psci_conduit,
27
+ qdev_prop_set_uint32(pl061_dev, "pulldowns", 0xff);
31
- NULL);
28
s = SYS_BUS_DEVICE(pl061_dev);
32
-
29
sysbus_realize_and_unref(s, &error_fatal);
33
- /* Secondary CPUs start in PSCI powered-down state */
30
memory_region_add_subregion(mem, base, sysbus_mmio_get_region(s, 0));
34
- if (n > 0) {
35
- object_property_set_bool(cpuobj, "start-powered-off", true,
36
- NULL);
37
- }
38
- }
39
-
40
if (vmc->kvm_no_adjvtime &&
41
object_property_find(cpuobj, "kvm-no-adjvtime")) {
42
object_property_set_bool(cpuobj, "kvm-no-adjvtime", true, NULL);
43
@@ -XXX,XX +XXX,XX @@ static void machvirt_init(MachineState *machine)
44
vms->bootinfo.get_dtb = machvirt_dtb;
45
vms->bootinfo.skip_dtb_autoload = true;
46
vms->bootinfo.firmware_loaded = firmware_loaded;
47
+ vms->bootinfo.psci_conduit = vms->psci_conduit;
48
arm_load_kernel(ARM_CPU(first_cpu), machine, &vms->bootinfo);
49
50
vms->machine_done.notify = virt_machine_done;
31
--
51
--
32
2.20.1
52
2.25.1
33
53
34
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: Alexandre Iooss <erdnaxe@crans.org>
1
The SMCCC 1.3 spec section 5.2 says
2
2
3
New mini-kernel test for STM32VLDISCOVERY USART1.
3
The Unknown SMC Function Identifier is a sign-extended value of (-1)
4
that is returned in the R0, W0 or X0 registers. An implementation must
5
return this error code when it receives:
4
6
5
Signed-off-by: Alexandre Iooss <erdnaxe@crans.org>
7
* An SMC or HVC call with an unknown Function Identifier
6
Acked-by: Thomas Huth <thuth@redhat.com>
8
* An SMC or HVC call for a removed Function Identifier
7
Acked-by: Alistair Francis <alistair.francis@wdc.com>
9
* An SMC64/HVC64 call from AArch32 state
8
Message-id: 20210617165647.2575955-5-erdnaxe@crans.org
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>
27
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
28
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
29
---
11
tests/qtest/boot-serial-test.c | 37 ++++++++++++++++++++++++++++++++++
30
target/arm/psci.c | 35 ++++++-----------------------------
12
1 file changed, 37 insertions(+)
31
1 file changed, 6 insertions(+), 29 deletions(-)
13
32
14
diff --git a/tests/qtest/boot-serial-test.c b/tests/qtest/boot-serial-test.c
33
diff --git a/target/arm/psci.c b/target/arm/psci.c
15
index XXXXXXX..XXXXXXX 100644
34
index XXXXXXX..XXXXXXX 100644
16
--- a/tests/qtest/boot-serial-test.c
35
--- a/target/arm/psci.c
17
+++ b/tests/qtest/boot-serial-test.c
36
+++ b/target/arm/psci.c
18
@@ -XXX,XX +XXX,XX @@ static const uint8_t kernel_nrf51[] = {
37
@@ -XXX,XX +XXX,XX @@
19
0x1c, 0x25, 0x00, 0x40 /* 0x4000251c = UART TXD */
38
20
};
39
bool arm_is_psci_call(ARMCPU *cpu, int excp_type)
21
40
{
22
+static const uint8_t kernel_stm32vldiscovery[] = {
41
- /* Return true if the r0/x0 value indicates a PSCI call and
23
+ 0x00, 0x00, 0x00, 0x00, /* Stack top address */
42
- * the exception type matches the configured PSCI conduit. This is
24
+ 0x1d, 0x00, 0x00, 0x00, /* Reset handler address */
43
- * called before the SMC/HVC instruction is executed, to decide whether
25
+ 0x00, 0x00, 0x00, 0x00, /* NMI */
44
- * we should treat it as a PSCI call or with the architecturally
26
+ 0x00, 0x00, 0x00, 0x00, /* Hard fault */
45
+ /*
27
+ 0x00, 0x00, 0x00, 0x00, /* Memory management fault */
46
+ * Return true if the exception type matches the configured PSCI conduit.
28
+ 0x00, 0x00, 0x00, 0x00, /* Bus fault */
47
+ * This is called before the SMC/HVC instruction is executed, to decide
29
+ 0x00, 0x00, 0x00, 0x00, /* Usage fault */
48
+ * whether we should treat it as a PSCI call or with the architecturally
30
+ 0x0b, 0x4b, /* ldr r3, [pc, #44] Get RCC */
49
* defined behaviour for an SMC or HVC (which might be UNDEF or trap
31
+ 0x44, 0xf2, 0x04, 0x02, /* movw r2, #16388 */
50
* to EL2 or to EL3).
32
+ 0x1a, 0x60, /* str r2, [r3] */
51
*/
33
+ 0x0a, 0x4b, /* ldr r3, [pc, #40] Get GPIOA */
52
- CPUARMState *env = &cpu->env;
34
+ 0x1a, 0x68, /* ldr r2, [r3] */
53
- uint64_t param = is_a64(env) ? env->xregs[0] : env->regs[0];
35
+ 0x22, 0xf0, 0xf0, 0x02, /* bic r2, r2, #240 */
54
36
+ 0x1a, 0x60, /* str r2, [r3] */
55
switch (excp_type) {
37
+ 0x1a, 0x68, /* ldr r2, [r3] */
56
case EXCP_HVC:
38
+ 0x42, 0xf0, 0xb0, 0x02, /* orr r2, r2, #176 */
57
@@ -XXX,XX +XXX,XX @@ bool arm_is_psci_call(ARMCPU *cpu, int excp_type)
39
+ 0x1a, 0x60, /* str r2, [r3] */
58
return false;
40
+ 0x07, 0x4b, /* ldr r3, [pc, #26] Get BAUD */
59
}
41
+ 0x45, 0x22, /* movs r2, #69 */
60
42
+ 0x1a, 0x60, /* str r2, [r3] */
61
- switch (param) {
43
+ 0x06, 0x4b, /* ldr r3, [pc, #24] Get ENABLE */
62
- case QEMU_PSCI_0_2_FN_PSCI_VERSION:
44
+ 0x42, 0xf2, 0x08, 0x02, /* movw r2, #8200 */
63
- case QEMU_PSCI_0_2_FN_MIGRATE_INFO_TYPE:
45
+ 0x1a, 0x60, /* str r2, [r3] */
64
- case QEMU_PSCI_0_2_FN_AFFINITY_INFO:
46
+ 0x05, 0x4b, /* ldr r3, [pc, #20] Get TXD */
65
- case QEMU_PSCI_0_2_FN64_AFFINITY_INFO:
47
+ 0x54, 0x22, /* movs r2, 'T' */
66
- case QEMU_PSCI_0_2_FN_SYSTEM_RESET:
48
+ 0x1a, 0x60, /* str r2, [r3] */
67
- case QEMU_PSCI_0_2_FN_SYSTEM_OFF:
49
+ 0xfe, 0xe7, /* b . */
68
- case QEMU_PSCI_0_1_FN_CPU_ON:
50
+ 0x18, 0x10, 0x02, 0x40, /* 0x40021018 = RCC */
69
- case QEMU_PSCI_0_2_FN_CPU_ON:
51
+ 0x04, 0x08, 0x01, 0x40, /* 0x40010804 = GPIOA */
70
- case QEMU_PSCI_0_2_FN64_CPU_ON:
52
+ 0x08, 0x38, 0x01, 0x40, /* 0x40013808 = USART1 BAUD */
71
- case QEMU_PSCI_0_1_FN_CPU_OFF:
53
+ 0x0c, 0x38, 0x01, 0x40, /* 0x4001380c = USART1 ENABLE */
72
- case QEMU_PSCI_0_2_FN_CPU_OFF:
54
+ 0x04, 0x38, 0x01, 0x40 /* 0x40013804 = USART1 TXD */
73
- case QEMU_PSCI_0_1_FN_CPU_SUSPEND:
55
+};
74
- case QEMU_PSCI_0_2_FN_CPU_SUSPEND:
56
+
75
- case QEMU_PSCI_0_2_FN64_CPU_SUSPEND:
57
typedef struct testdef {
76
- case QEMU_PSCI_0_1_FN_MIGRATE:
58
const char *arch; /* Target architecture */
77
- case QEMU_PSCI_0_2_FN_MIGRATE:
59
const char *machine; /* Name of the machine */
78
- return true;
60
@@ -XXX,XX +XXX,XX @@ static testdef_t tests[] = {
79
- default:
61
{ "aarch64", "virt", "-cpu max", "TT", sizeof(kernel_aarch64),
80
- return false;
62
kernel_aarch64 },
81
- }
63
{ "arm", "microbit", "", "T", sizeof(kernel_nrf51), kernel_nrf51 },
82
+ return true;
64
+ { "arm", "stm32vldiscovery", "", "T",
83
}
65
+ sizeof(kernel_stm32vldiscovery), kernel_stm32vldiscovery },
84
66
85
void arm_handle_psci_call(ARMCPU *cpu)
67
{ NULL }
86
@@ -XXX,XX +XXX,XX @@ void arm_handle_psci_call(ARMCPU *cpu)
68
};
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();
95
}
96
97
err:
69
--
98
--
70
2.20.1
99
2.25.1
71
100
72
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
New patch
1
If we're using PSCI emulation to start secondary CPUs, there is no
2
point in writing the "secondary boot" stub code, because it will
3
never be used -- secondary CPUs start powered-off, and when powered
4
on are set to begin execution at the address specified by the guest's
5
power-on PSCI call, not at the stub.
1
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.)
14
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
Reviewed-by: Richard Henderson <richard.henderson@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
21
---
22
include/hw/arm/boot.h | 3 +++
23
hw/arm/boot.c | 35 ++++++++++++++++++++++++-----------
24
2 files changed, 27 insertions(+), 11 deletions(-)
25
26
diff --git a/include/hw/arm/boot.h b/include/hw/arm/boot.h
27
index XXXXXXX..XXXXXXX 100644
28
--- a/include/hw/arm/boot.h
29
+++ b/include/hw/arm/boot.h
30
@@ -XXX,XX +XXX,XX @@ struct arm_boot_info {
31
* boot loader/boot ROM code, and secondary_cpu_reset_hook() should
32
* perform any necessary CPU reset handling and set the PC for the
33
* secondary CPUs to point at this boot blob.
34
+ *
35
+ * These hooks won't be called if secondary CPUs are booting via
36
+ * emulated PSCI (see psci_conduit below).
37
*/
38
void (*write_secondary_boot)(ARMCPU *cpu,
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;
55
}
56
57
- if (!info->secondary_cpu_reset_hook) {
58
- info->secondary_cpu_reset_hook = default_reset_secondary;
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;
102
+ }
103
+
104
/*
105
* arm_load_dtb() may add a PSCI node so it must be called after we have
106
* decided whether to enable PSCI and set the psci-conduit CPU properties.
107
--
108
2.25.1
109
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
New patch
1
1
We use the arm_boot_info::nb_cpus field in only one place, and that
2
place can easily get the number of CPUs locally rather than relying
3
on the board code to have set the field correctly. (At least one
4
board, xlnx-versal-virt, does not set the field despite having more
5
than one CPU.)
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-16-peter.maydell@linaro.org
13
---
14
include/hw/arm/boot.h | 1 -
15
hw/arm/aspeed.c | 1 -
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).
46
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
47
index XXXXXXX..XXXXXXX 100644
48
--- a/hw/arm/aspeed.c
49
+++ b/hw/arm/aspeed.c
50
@@ -XXX,XX +XXX,XX @@ static void aspeed_machine_init(MachineState *machine)
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)
178
{
179
- NPCM7xxClass *sc = NPCM7XX_GET_CLASS(soc);
180
-
181
npcm7xx_binfo.ram_size = machine->ram_size;
182
- npcm7xx_binfo.nb_cpus = sc->num_cpus;
183
184
arm_load_kernel(&soc->cpu[0], machine, &npcm7xx_binfo);
185
}
186
diff --git a/hw/arm/orangepi.c b/hw/arm/orangepi.c
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;
285
--
286
2.25.1
287
288
diff view generated by jsdifflib
New patch
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.)
1
5
6
This is a problem if the existing node doesn't match our PSCI
7
emulation. In particular, it might specify the wrong method (HVC vs
8
SMC), or wrong function IDs for cpu_suspend/cpu_off/etc, in which
9
case the guest will not get the behaviour it wants when it makes PSCI
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.
25
26
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
27
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
28
Reviewed-by: Niek Linnenbank <nieklinnenbank@gmail.com>
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
33
---
34
hw/arm/boot.c | 7 ++++---
35
1 file changed, 4 insertions(+), 3 deletions(-)
36
37
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
38
index XXXXXXX..XXXXXXX 100644
39
--- a/hw/arm/boot.c
40
+++ b/hw/arm/boot.c
41
@@ -XXX,XX +XXX,XX @@ static void fdt_add_psci_node(void *fdt)
42
}
43
44
/*
45
- * If /psci node is present in provided DTB, assume that no fixup
46
- * is necessary and all PSCI configuration should be taken as-is
47
+ * A pre-existing /psci node might specify function ID values
48
+ * that don't match QEMU's PSCI implementation. Delete the whole
49
+ * node and put our own in instead.
50
*/
51
rc = fdt_path_offset(fdt, "/psci");
52
if (rc >= 0) {
53
- return;
54
+ qemu_fdt_nop_node(fdt, "/psci");
55
}
56
57
qemu_fdt_add_subnode(fdt, "/psci");
58
--
59
2.25.1
60
61
diff view generated by jsdifflib
1
From: Rebecca Cran <rebecca@nuviainc.com>
1
From: "Edgar E. Iglesias" <edgar.iglesias@xilinx.com>
2
2
3
Add a space in the message printed when gicr_read*/gicr_write* returns
3
Always call arm_load_kernel() regardless of kernel_filename being
4
MEMTX_ERROR in arm_gicv3_redist.c.
4
set. This is needed because arm_load_kernel() sets up reset for
5
the CPUs.
5
6
6
Signed-off-by: Rebecca Cran <rebecca@nuviainc.com>
7
Fixes: 6f16da53ff (hw/arm: versal: Add a virtual Xilinx Versal board)
7
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
Reported-by: Peter Maydell <peter.maydell@linaro.org>
8
Message-id: 20210706211432.31902-1-rebecca@nuviainc.com
9
Signed-off-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
10
Message-id: 20220130110313.4045351-2-edgar.iglesias@gmail.com
11
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>
10
---
13
---
11
hw/intc/arm_gicv3_redist.c | 4 ++--
14
hw/arm/xlnx-versal-virt.c | 11 ++---------
12
1 file changed, 2 insertions(+), 2 deletions(-)
15
1 file changed, 2 insertions(+), 9 deletions(-)
13
16
14
diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c
17
diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c
15
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/intc/arm_gicv3_redist.c
19
--- a/hw/arm/xlnx-versal-virt.c
17
+++ b/hw/intc/arm_gicv3_redist.c
20
+++ b/hw/arm/xlnx-versal-virt.c
18
@@ -XXX,XX +XXX,XX @@ MemTxResult gicv3_redist_read(void *opaque, hwaddr offset, uint64_t *data,
21
@@ -XXX,XX +XXX,XX @@ static void versal_virt_init(MachineState *machine)
19
if (r == MEMTX_ERROR) {
22
s->binfo.get_dtb = versal_virt_get_dtb;
20
qemu_log_mask(LOG_GUEST_ERROR,
23
s->binfo.modify_dtb = versal_virt_modify_dtb;
21
"%s: invalid guest read at offset " TARGET_FMT_plx
24
s->binfo.psci_conduit = psci_conduit;
22
- "size %u\n", __func__, offset, size);
25
- if (machine->kernel_filename) {
23
+ " size %u\n", __func__, offset, size);
26
- arm_load_kernel(&s->soc.fpd.apu.cpu[0], machine, &s->binfo);
24
trace_gicv3_redist_badread(gicv3_redist_affid(cs), offset,
27
- } else {
25
size, attrs.secure);
28
- AddressSpace *as = arm_boot_address_space(&s->soc.fpd.apu.cpu[0],
26
/* The spec requires that reserved registers are RAZ/WI;
29
- &s->binfo);
27
@@ -XXX,XX +XXX,XX @@ MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data,
30
+ if (!machine->kernel_filename) {
28
if (r == MEMTX_ERROR) {
31
/* Some boot-loaders (e.g u-boot) don't like blobs at address 0 (NULL).
29
qemu_log_mask(LOG_GUEST_ERROR,
32
* Offset things by 4K. */
30
"%s: invalid guest write at offset " TARGET_FMT_plx
33
s->binfo.loader_start = 0x1000;
31
- "size %u\n", __func__, offset, size);
34
s->binfo.dtb_limit = 0x1000000;
32
+ " size %u\n", __func__, offset, size);
35
- if (arm_load_dtb(s->binfo.loader_start,
33
trace_gicv3_redist_badwrite(gicv3_redist_affid(cs), offset, data,
36
- &s->binfo, s->binfo.dtb_limit, as, machine) < 0) {
34
size, attrs.secure);
37
- exit(EXIT_FAILURE);
35
/* The spec requires that reserved registers are RAZ/WI;
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;
36
--
44
--
37
2.20.1
45
2.25.1
38
46
39
47
diff view generated by jsdifflib
1
From: Alexandre Iooss <erdnaxe@crans.org>
1
From: Alex Bennée <alex.bennee@linaro.org>
2
2
3
This adds the target guide for Netduino 2, Netduino Plus 2 and STM32VLDISCOVERY.
3
The recently introduced debug tests in kvm-unit-tests exposed an error
4
in our handling of singlestep cause by stale hflags. This is caught by
5
--enable-debug-tcg when running the tests.
4
6
5
Signed-off-by: Alexandre Iooss <erdnaxe@crans.org>
7
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
6
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
8
Reported-by: Andrew Jones <drjones@redhat.com>
7
Message-id: 20210617165647.2575955-4-erdnaxe@crans.org
9
Tested-by: Andrew Jones <drjones@redhat.com>
10
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
11
Message-id: 20220202122353.457084-1-alex.bennee@linaro.org
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
13
---
10
docs/system/arm/stm32.rst | 66 ++++++++++++++++++++++++++++++++++++++
14
target/arm/helper-a64.c | 2 ++
11
docs/system/target-arm.rst | 1 +
15
1 file changed, 2 insertions(+)
12
MAINTAINERS | 1 +
13
3 files changed, 68 insertions(+)
14
create mode 100644 docs/system/arm/stm32.rst
15
16
16
diff --git a/docs/system/arm/stm32.rst b/docs/system/arm/stm32.rst
17
diff --git a/target/arm/helper-a64.c b/target/arm/helper-a64.c
17
new file mode 100644
18
index XXXXXXX..XXXXXXX
19
--- /dev/null
20
+++ b/docs/system/arm/stm32.rst
21
@@ -XXX,XX +XXX,XX @@
22
+STMicroelectronics STM32 boards (``netduino2``, ``netduinoplus2``, ``stm32vldiscovery``)
23
+========================================================================================
24
+
25
+The `STM32`_ chips are a family of 32-bit ARM-based microcontroller by
26
+STMicroelectronics.
27
+
28
+.. _STM32: https://www.st.com/en/microcontrollers-microprocessors/stm32-32-bit-arm-cortex-mcus.html
29
+
30
+The STM32F1 series is based on ARM Cortex-M3 core. The following machines are
31
+based on this chip :
32
+
33
+- ``stm32vldiscovery`` STM32VLDISCOVERY board with STM32F100RBT6 microcontroller
34
+
35
+The STM32F2 series is based on ARM Cortex-M3 core. The following machines are
36
+based on this chip :
37
+
38
+- ``netduino2`` Netduino 2 board with STM32F205RFT6 microcontroller
39
+
40
+The STM32F4 series is based on ARM Cortex-M4F core. This series is pin-to-pin
41
+compatible with STM32F2 series. The following machines are based on this chip :
42
+
43
+- ``netduinoplus2`` Netduino Plus 2 board with STM32F405RGT6 microcontroller
44
+
45
+There are many other STM32 series that are currently not supported by QEMU.
46
+
47
+Supported devices
48
+-----------------
49
+
50
+ * ARM Cortex-M3, Cortex M4F
51
+ * Analog to Digital Converter (ADC)
52
+ * EXTI interrupt
53
+ * Serial ports (USART)
54
+ * SPI controller
55
+ * System configuration (SYSCFG)
56
+ * Timer controller (TIMER)
57
+
58
+Missing devices
59
+---------------
60
+
61
+ * Camera interface (DCMI)
62
+ * Controller Area Network (CAN)
63
+ * Cycle Redundancy Check (CRC) calculation unit
64
+ * Digital to Analog Converter (DAC)
65
+ * DMA controller
66
+ * Ethernet controller
67
+ * Flash Interface Unit
68
+ * GPIO controller
69
+ * I2C controller
70
+ * Inter-Integrated Sound (I2S) controller
71
+ * Power supply configuration (PWR)
72
+ * Random Number Generator (RNG)
73
+ * Real-Time Clock (RTC) controller
74
+ * Reset and Clock Controller (RCC)
75
+ * Secure Digital Input/Output (SDIO) interface
76
+ * USB OTG
77
+ * Watchdog controller (IWDG, WWDG)
78
+
79
+Boot options
80
+------------
81
+
82
+The STM32 machines can be started using the ``-kernel`` option to load a
83
+firmware. Example:
84
+
85
+.. code-block:: bash
86
+
87
+ $ qemu-system-arm -M stm32vldiscovery -kernel firmware.bin
88
diff --git a/docs/system/target-arm.rst b/docs/system/target-arm.rst
89
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
90
--- a/docs/system/target-arm.rst
19
--- a/target/arm/helper-a64.c
91
+++ b/docs/system/target-arm.rst
20
+++ b/target/arm/helper-a64.c
92
@@ -XXX,XX +XXX,XX @@ undocumented; you can get a complete list by running
21
@@ -XXX,XX +XXX,XX @@ void HELPER(msr_i_daifset)(CPUARMState *env, uint32_t imm)
93
arm/collie
22
{
94
arm/sx1
23
daif_check(env, 0x1e, imm, GETPC());
95
arm/stellaris
24
env->daif |= (imm << 6) & PSTATE_DAIF;
96
+ arm/stm32
25
+ arm_rebuild_hflags(env);
97
arm/virt
26
}
98
arm/xlnx-versal-virt
27
99
28
void HELPER(msr_i_daifclear)(CPUARMState *env, uint32_t imm)
100
diff --git a/MAINTAINERS b/MAINTAINERS
29
{
101
index XXXXXXX..XXXXXXX 100644
30
daif_check(env, 0x1f, imm, GETPC());
102
--- a/MAINTAINERS
31
env->daif &= ~((imm << 6) & PSTATE_DAIF);
103
+++ b/MAINTAINERS
32
+ arm_rebuild_hflags(env);
104
@@ -XXX,XX +XXX,XX @@ M: Alexandre Iooss <erdnaxe@crans.org>
33
}
105
L: qemu-arm@nongnu.org
34
106
S: Maintained
35
/* Convert a softfloat float_relation_ (as returned by
107
F: hw/arm/stm32vldiscovery.c
108
+F: docs/system/arm/stm32.rst
109
110
Versatile Express
111
M: Peter Maydell <peter.maydell@linaro.org>
112
--
36
--
113
2.20.1
37
2.25.1
114
38
115
39
diff view generated by jsdifflib
1
From: Ricardo Koller <ricarkol@google.com>
1
From: Richard Petri <git@rpls.de>
2
2
3
icv_eoir_write() and icv_dir_write() ignore invalid virtual IRQ numbers
3
Starting the SysTick timer and changing the clock source a the same time
4
(like LPIs). The issue is that these functions check against the number
4
will result in an error, if the previous clock period was zero. For exmaple,
5
of implemented IRQs (QEMU's default is num_irq=288) which can be lower
5
on the mps2-tz platforms, no refclk is present. Right after reset, the
6
than the maximum virtual IRQ number (1020 - 1). The consequence is that
6
configured ptimer period is zero, and trying to enabling it will turn it off
7
if a hypervisor creates an LR for an IRQ between 288 and 1020, then the
7
right away. E.g., code running on the platform setting
8
guest is unable to deactivate the resulting IRQ. Note that other
9
functions that deal with large IRQ numbers, like icv_iar_read, check
10
against 1020 and not against num_irq.
11
8
12
Fix the checks by using GICV3_MAXIRQ (1020) instead of the number of
9
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk;
13
implemented IRQs.
14
10
15
Signed-off-by: Ricardo Koller <ricarkol@google.com>
11
should change the clock source and enable the timer on real hardware, but
16
Message-id: 20210702233701.3369-1-ricarkol@google.com
12
resulted in an error in qemu.
13
14
Signed-off-by: Richard Petri <git@rpls.de>
17
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
15
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
16
Message-id: 20220201192650.289584-1-git@rpls.de
18
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
17
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
19
---
18
---
20
hw/intc/arm_gicv3_cpuif.c | 4 ++--
19
hw/timer/armv7m_systick.c | 8 ++++----
21
1 file changed, 2 insertions(+), 2 deletions(-)
20
1 file changed, 4 insertions(+), 4 deletions(-)
22
21
23
diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
22
diff --git a/hw/timer/armv7m_systick.c b/hw/timer/armv7m_systick.c
24
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
25
--- a/hw/intc/arm_gicv3_cpuif.c
24
--- a/hw/timer/armv7m_systick.c
26
+++ b/hw/intc/arm_gicv3_cpuif.c
25
+++ b/hw/timer/armv7m_systick.c
27
@@ -XXX,XX +XXX,XX @@ static void icv_dir_write(CPUARMState *env, const ARMCPRegInfo *ri,
26
@@ -XXX,XX +XXX,XX @@ static MemTxResult systick_write(void *opaque, hwaddr addr,
28
27
s->control &= 0xfffffff8;
29
trace_gicv3_icv_dir_write(gicv3_redist_affid(cs), value);
28
s->control |= value & 7;
30
29
31
- if (irq >= cs->gic->num_irq) {
30
+ if ((oldval ^ value) & SYSTICK_CLKSOURCE) {
32
+ if (irq >= GICV3_MAXIRQ) {
31
+ systick_set_period_from_clock(s);
33
/* Also catches special interrupt numbers and LPIs */
32
+ }
34
return;
33
+
35
}
34
if ((oldval ^ value) & SYSTICK_ENABLE) {
36
@@ -XXX,XX +XXX,XX @@ static void icv_eoir_write(CPUARMState *env, const ARMCPRegInfo *ri,
35
if (value & SYSTICK_ENABLE) {
37
trace_gicv3_icv_eoir_write(ri->crm == 8 ? 0 : 1,
36
ptimer_run(s->ptimer, 0);
38
gicv3_redist_affid(cs), value);
37
@@ -XXX,XX +XXX,XX @@ static MemTxResult systick_write(void *opaque, hwaddr addr,
39
38
ptimer_stop(s->ptimer);
40
- if (irq >= cs->gic->num_irq) {
39
}
41
+ if (irq >= GICV3_MAXIRQ) {
40
}
42
/* Also catches special interrupt numbers and LPIs */
41
-
43
return;
42
- if ((oldval ^ value) & SYSTICK_CLKSOURCE) {
43
- systick_set_period_from_clock(s);
44
- }
45
ptimer_transaction_commit(s->ptimer);
46
break;
44
}
47
}
45
--
48
--
46
2.20.1
49
2.25.1
47
50
48
51
diff view generated by jsdifflib
1
From: Alexandre Iooss <erdnaxe@crans.org>
1
From: Eric Auger <eric.auger@redhat.com>
2
2
3
This is a Cortex-M3 based machine. Information can be found at:
3
We currently miss a bunch of register resets in the device reset
4
https://www.st.com/en/evaluation-tools/stm32vldiscovery.html
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
Signed-off-by: Alexandre Iooss <erdnaxe@crans.org>
8
invalid STE
7
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
9
smmuv3-iommu-memory-region-0-0 translation failed for iova=0x13a9d2000(SMMU_EVT_C_BAD_STE)
8
Message-id: 20210617165647.2575955-3-erdnaxe@crans.org
10
Invalid read at addr 0x13A9D2000, size 2, region '(null)', reason: rejected
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
15
16
Signed-off-by: Eric Auger <eric.auger@redhat.com>
17
Message-id: 20220202111602.627429-1-eric.auger@redhat.com
18
Fixes: 10a83cb988 ("hw/arm/smmuv3: Skeleton")
19
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
20
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
21
---
11
default-configs/devices/arm-softmmu.mak | 1 +
22
hw/arm/smmuv3.c | 6 ++++++
12
hw/arm/stm32vldiscovery.c | 66 +++++++++++++++++++++++++
23
1 file changed, 6 insertions(+)
13
MAINTAINERS | 6 +++
14
hw/arm/Kconfig | 4 ++
15
hw/arm/meson.build | 1 +
16
5 files changed, 78 insertions(+)
17
create mode 100644 hw/arm/stm32vldiscovery.c
18
24
19
diff --git a/default-configs/devices/arm-softmmu.mak b/default-configs/devices/arm-softmmu.mak
25
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
20
index XXXXXXX..XXXXXXX 100644
26
index XXXXXXX..XXXXXXX 100644
21
--- a/default-configs/devices/arm-softmmu.mak
27
--- a/hw/arm/smmuv3.c
22
+++ b/default-configs/devices/arm-softmmu.mak
28
+++ b/hw/arm/smmuv3.c
23
@@ -XXX,XX +XXX,XX @@ CONFIG_CHEETAH=y
29
@@ -XXX,XX +XXX,XX @@ static void smmuv3_init_regs(SMMUv3State *s)
24
CONFIG_SX1=y
30
s->features = 0;
25
CONFIG_NSERIES=y
31
s->sid_split = 0;
26
CONFIG_STELLARIS=y
32
s->aidr = 0x1;
27
+CONFIG_STM32VLDISCOVERY=y
33
+ s->cr[0] = 0;
28
CONFIG_REALVIEW=y
34
+ s->cr0ack = 0;
29
CONFIG_VERSATILE=y
35
+ s->irq_ctrl = 0;
30
CONFIG_VEXPRESS=y
36
+ s->gerror = 0;
31
diff --git a/hw/arm/stm32vldiscovery.c b/hw/arm/stm32vldiscovery.c
37
+ s->gerrorn = 0;
32
new file mode 100644
38
+ s->statusr = 0;
33
index XXXXXXX..XXXXXXX
39
}
34
--- /dev/null
40
35
+++ b/hw/arm/stm32vldiscovery.c
41
static int smmu_get_ste(SMMUv3State *s, dma_addr_t addr, STE *buf,
36
@@ -XXX,XX +XXX,XX @@
37
+/*
38
+ * ST STM32VLDISCOVERY machine
39
+ *
40
+ * Copyright (c) 2021 Alexandre Iooss <erdnaxe@crans.org>
41
+ * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
42
+ *
43
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
44
+ * of this software and associated documentation files (the "Software"), to deal
45
+ * in the Software without restriction, including without limitation the rights
46
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
47
+ * copies of the Software, and to permit persons to whom the Software is
48
+ * furnished to do so, subject to the following conditions:
49
+ *
50
+ * The above copyright notice and this permission notice shall be included in
51
+ * all copies or substantial portions of the Software.
52
+ *
53
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
54
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
55
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
56
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
57
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
58
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
59
+ * THE SOFTWARE.
60
+ */
61
+
62
+#include "qemu/osdep.h"
63
+#include "qapi/error.h"
64
+#include "hw/boards.h"
65
+#include "hw/qdev-properties.h"
66
+#include "qemu/error-report.h"
67
+#include "hw/arm/stm32f100_soc.h"
68
+#include "hw/arm/boot.h"
69
+
70
+/* stm32vldiscovery implementation is derived from netduinoplus2 */
71
+
72
+/* Main SYSCLK frequency in Hz (24MHz) */
73
+#define SYSCLK_FRQ 24000000ULL
74
+
75
+static void stm32vldiscovery_init(MachineState *machine)
76
+{
77
+ DeviceState *dev;
78
+
79
+ /*
80
+ * TODO: ideally we would model the SoC RCC and let it handle
81
+ * system_clock_scale, including its ability to define different
82
+ * possible SYSCLK sources.
83
+ */
84
+ system_clock_scale = NANOSECONDS_PER_SECOND / SYSCLK_FRQ;
85
+
86
+ dev = qdev_new(TYPE_STM32F100_SOC);
87
+ qdev_prop_set_string(dev, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m3"));
88
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
89
+
90
+ armv7m_load_kernel(ARM_CPU(first_cpu),
91
+ machine->kernel_filename,
92
+ FLASH_SIZE);
93
+}
94
+
95
+static void stm32vldiscovery_machine_init(MachineClass *mc)
96
+{
97
+ mc->desc = "ST STM32VLDISCOVERY (Cortex-M3)";
98
+ mc->init = stm32vldiscovery_init;
99
+}
100
+
101
+DEFINE_MACHINE("stm32vldiscovery", stm32vldiscovery_machine_init)
102
+
103
diff --git a/MAINTAINERS b/MAINTAINERS
104
index XXXXXXX..XXXXXXX 100644
105
--- a/MAINTAINERS
106
+++ b/MAINTAINERS
107
@@ -XXX,XX +XXX,XX @@ F: hw/*/stellaris*
108
F: include/hw/input/gamepad.h
109
F: docs/system/arm/stellaris.rst
110
111
+STM32VLDISCOVERY
112
+M: Alexandre Iooss <erdnaxe@crans.org>
113
+L: qemu-arm@nongnu.org
114
+S: Maintained
115
+F: hw/arm/stm32vldiscovery.c
116
+
117
Versatile Express
118
M: Peter Maydell <peter.maydell@linaro.org>
119
L: qemu-arm@nongnu.org
120
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
121
index XXXXXXX..XXXXXXX 100644
122
--- a/hw/arm/Kconfig
123
+++ b/hw/arm/Kconfig
124
@@ -XXX,XX +XXX,XX @@ config STELLARIS
125
select STELLARIS_ENET # ethernet
126
select UNIMP
127
128
+config STM32VLDISCOVERY
129
+ bool
130
+ select STM32F100_SOC
131
+
132
config STRONGARM
133
bool
134
select PXA2XX
135
diff --git a/hw/arm/meson.build b/hw/arm/meson.build
136
index XXXXXXX..XXXXXXX 100644
137
--- a/hw/arm/meson.build
138
+++ b/hw/arm/meson.build
139
@@ -XXX,XX +XXX,XX @@ arm_ss.add(when: 'CONFIG_Z2', if_true: files('z2.c'))
140
arm_ss.add(when: 'CONFIG_REALVIEW', if_true: files('realview.c'))
141
arm_ss.add(when: 'CONFIG_SBSA_REF', if_true: files('sbsa-ref.c'))
142
arm_ss.add(when: 'CONFIG_STELLARIS', if_true: files('stellaris.c'))
143
+arm_ss.add(when: 'CONFIG_STM32VLDISCOVERY', if_true: files('stm32vldiscovery.c'))
144
arm_ss.add(when: 'CONFIG_COLLIE', if_true: files('collie.c'))
145
arm_ss.add(when: 'CONFIG_VERSATILE', if_true: files('versatilepb.c'))
146
arm_ss.add(when: 'CONFIG_VEXPRESS', if_true: files('vexpress.c'))
147
--
42
--
148
2.20.1
43
2.25.1
149
44
150
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
The PL061 comes out of reset with all its lines configured as input,
1
Make update_dte() take a DTEntry struct rather than all the fields of
2
which means they might need to be pulled to 0 or 1 depending on the
2
the new DTE as separate arguments.
3
'pullups' and 'pulldowns' properties. Currently we do not assert
4
these lines on reset; they will only be set whenever the guest first
5
touches a register that triggers a call to pl061_update().
6
7
Convert the device to three-phase reset so we have a place where we
8
can safely call qemu_set_irq() to set the floating lines to their
9
correct values.
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: Philippe Mathieu-Daudé <f4bug@amsat.org>
13
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20220201193207.2771604-4-peter.maydell@linaro.org
14
---
7
---
15
hw/gpio/pl061.c | 29 +++++++++++++++++++++++++----
8
hw/intc/arm_gicv3_its.c | 35 ++++++++++++++++++-----------------
16
hw/gpio/trace-events | 1 +
9
1 file changed, 18 insertions(+), 17 deletions(-)
17
2 files changed, 26 insertions(+), 4 deletions(-)
18
10
19
diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.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/gpio/pl061.c
13
--- a/hw/intc/arm_gicv3_its.c
22
+++ b/hw/gpio/pl061.c
14
+++ b/hw/intc/arm_gicv3_its.c
23
@@ -XXX,XX +XXX,XX @@ static void pl061_write(void *opaque, hwaddr offset,
15
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_mapc(GICv3ITSState *s, const uint64_t *cmdpkt)
24
return;
16
return update_cte(s, icid, valid, rdbase) ? CMD_CONTINUE : CMD_STALL;
25
}
17
}
26
18
27
-static void pl061_reset(DeviceState *dev)
19
-static bool update_dte(GICv3ITSState *s, uint32_t devid, bool valid,
28
+static void pl061_enter_reset(Object *obj, ResetType type)
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)
29
{
26
{
30
- PL061State *s = PL061(dev);
27
AddressSpace *as = &s->gicv3->dma_as;
31
+ PL061State *s = PL061(obj);
28
uint64_t entry_addr;
32
+
29
- uint64_t dte = 0;
33
+ trace_pl061_reset(DEVICE(s)->canonical_path);
30
+ uint64_t dteval = 0;
34
31
MemTxResult res = MEMTX_OK;
35
/* reset values from PL061 TRM, Stellaris LM3S5P31 & LM3S8962 Data Sheet */
32
36
s->data = 0;
33
if (s->dt.valid) {
37
- s->old_out_data = 0;
34
- if (valid) {
38
s->old_in_data = 0;
35
+ if (dte->valid) {
39
s->dir = 0;
36
/* add mapping entry to device table */
40
s->isense = 0;
37
- dte = FIELD_DP64(dte, DTE, VALID, 1);
41
@@ -XXX,XX +XXX,XX @@ static void pl061_reset(DeviceState *dev)
38
- dte = FIELD_DP64(dte, DTE, SIZE, size);
42
s->amsel = 0;
39
- dte = FIELD_DP64(dte, DTE, ITTADDR, itt_addr);
40
+ dteval = FIELD_DP64(dteval, DTE, VALID, 1);
41
+ dteval = FIELD_DP64(dteval, DTE, SIZE, dte->size);
42
+ dteval = FIELD_DP64(dteval, DTE, ITTADDR, dte->ittaddr);
43
}
44
} else {
45
return true;
46
@@ -XXX,XX +XXX,XX @@ static bool update_dte(GICv3ITSState *s, uint32_t devid, bool valid,
47
/* No L2 table for this index: discard write and continue */
48
return true;
49
}
50
- address_space_stq_le(as, entry_addr, dte, MEMTXATTRS_UNSPECIFIED, &res);
51
+ address_space_stq_le(as, entry_addr, dteval, MEMTXATTRS_UNSPECIFIED, &res);
52
return res == MEMTX_OK;
43
}
53
}
44
54
45
+static void pl061_hold_reset(Object *obj)
55
static ItsCmdResult process_mapd(GICv3ITSState *s, const uint64_t *cmdpkt)
46
+{
47
+ PL061State *s = PL061(obj);
48
+ int i, level;
49
+ uint8_t floating = pl061_floating(s);
50
+ uint8_t pullups = pl061_pullups(s);
51
+
52
+ for (i = 0; i < N_GPIOS; i++) {
53
+ if (extract32(floating, i, 1)) {
54
+ continue;
55
+ }
56
+ level = extract32(pullups, i, 1);
57
+ trace_pl061_set_output(DEVICE(s)->canonical_path, i, level);
58
+ qemu_set_irq(s->out[i], level);
59
+ }
60
+ s->old_out_data = pullups;
61
+}
62
+
63
static void pl061_set_irq(void * opaque, int irq, int level)
64
{
56
{
65
PL061State *s = (PL061State *)opaque;
57
uint32_t devid;
66
@@ -XXX,XX +XXX,XX @@ static Property pl061_props[] = {
58
- uint8_t size;
67
static void pl061_class_init(ObjectClass *klass, void *data)
59
- uint64_t itt_addr;
68
{
60
- bool valid;
69
DeviceClass *dc = DEVICE_CLASS(klass);
61
+ DTEntry dte;
70
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
62
71
63
devid = (cmdpkt[0] & DEVID_MASK) >> DEVID_SHIFT;
72
dc->vmsd = &vmstate_pl061;
64
- size = cmdpkt[1] & SIZE_MASK;
73
- dc->reset = &pl061_reset;
65
- itt_addr = (cmdpkt[2] & ITTADDR_MASK) >> ITTADDR_SHIFT;
74
dc->realize = pl061_realize;
66
- valid = cmdpkt[2] & CMD_FIELD_VALID_MASK;
75
device_class_set_props(dc, pl061_props);
67
+ dte.size = cmdpkt[1] & SIZE_MASK;
76
+ rc->phases.enter = pl061_enter_reset;
68
+ dte.ittaddr = (cmdpkt[2] & ITTADDR_MASK) >> ITTADDR_SHIFT;
77
+ rc->phases.hold = pl061_hold_reset;
69
+ dte.valid = cmdpkt[2] & CMD_FIELD_VALID_MASK;
70
71
if ((devid >= s->dt.num_entries) ||
72
- (size > FIELD_EX64(s->typer, GITS_TYPER, IDBITS))) {
73
+ (dte.size > FIELD_EX64(s->typer, GITS_TYPER, IDBITS))) {
74
qemu_log_mask(LOG_GUEST_ERROR,
75
"ITS MAPD: invalid device table attributes "
76
- "devid %d or size %d\n", devid, size);
77
+ "devid %d or size %d\n", devid, dte.size);
78
/*
79
* in this implementation, in case of error
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;
83
}
84
85
- return update_dte(s, devid, valid, size, itt_addr) ? CMD_CONTINUE : CMD_STALL;
86
+ return update_dte(s, devid, &dte) ? CMD_CONTINUE : CMD_STALL;
78
}
87
}
79
88
80
static const TypeInfo pl061_info = {
89
static ItsCmdResult process_movall(GICv3ITSState *s, const uint64_t *cmdpkt)
81
diff --git a/hw/gpio/trace-events b/hw/gpio/trace-events
82
index XXXXXXX..XXXXXXX 100644
83
--- a/hw/gpio/trace-events
84
+++ b/hw/gpio/trace-events
85
@@ -XXX,XX +XXX,XX @@ pl061_input_change(const char *id, int gpio, int level) "%s input %d changed to
86
pl061_update_istate(const char *id, uint32_t istate, uint32_t im, int level) "%s GPIORIS 0x%x GPIOIE 0x%x interrupt level %d"
87
pl061_read(const char *id, uint64_t offset, uint64_t r) "%s offset 0x%" PRIx64 " value 0x%" PRIx64
88
pl061_write(const char *id, uint64_t offset, uint64_t value) "%s offset 0x%" PRIx64 " value 0x%" PRIx64
89
+pl061_reset(const char *id) "%s reset"
90
91
# sifive_gpio.c
92
sifive_gpio_read(uint64_t offset, uint64_t r) "offset 0x%" PRIx64 " value 0x%" PRIx64
93
--
90
--
94
2.20.1
91
2.25.1
95
92
96
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
Currently the pl061_read() and pl061_write() functions handle offsets
1
Make update_cte() take a CTEntry struct rather than all the fields
2
using a combination of three if() statements and a switch(). Clean
2
of the new CTE as separate arguments.
3
this up to use just a switch, using case ranges.
4
3
5
This requires that instead of catching accesses to the luminary-only
4
This brings it into line with the update_dte() API.
6
registers on a stock PL061 via a check on s->rsvd_start we use
7
an "is this luminary?" check in the cases for each luminary-only
8
register.
9
5
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20220201193207.2771604-6-peter.maydell@linaro.org
12
---
9
---
13
hw/gpio/pl061.c | 104 ++++++++++++++++++++++++++++++++++++------------
10
hw/intc/arm_gicv3_its.c | 32 +++++++++++++++++---------------
14
1 file changed, 79 insertions(+), 25 deletions(-)
11
1 file changed, 17 insertions(+), 15 deletions(-)
15
12
16
diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.c
13
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
17
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
18
--- a/hw/gpio/pl061.c
15
--- a/hw/intc/arm_gicv3_its.c
19
+++ b/hw/gpio/pl061.c
16
+++ b/hw/intc/arm_gicv3_its.c
20
@@ -XXX,XX +XXX,XX @@ struct PL061State {
17
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_mapti(GICv3ITSState *s, const uint64_t *cmdpkt,
21
qemu_irq irq;
18
return update_ite(s, eventid, &dte, ite) ? CMD_CONTINUE : CMD_STALL;
22
qemu_irq out[N_GPIOS];
19
}
23
const unsigned char *id;
20
24
- uint32_t rsvd_start; /* reserved area: [rsvd_start, 0xfcc] */
21
-static bool update_cte(GICv3ITSState *s, uint16_t icid, bool valid,
25
};
22
- uint64_t rdbase)
26
23
+/*
27
static const VMStateDescription vmstate_pl061 = {
24
+ * Update the Collection Table entry for @icid to @cte. Returns true
28
@@ -XXX,XX +XXX,XX @@ static uint64_t pl061_read(void *opaque, hwaddr offset,
25
+ * on success, false if there was a memory access error.
26
+ */
27
+static bool update_cte(GICv3ITSState *s, uint16_t icid, const CTEntry *cte)
29
{
28
{
30
PL061State *s = (PL061State *)opaque;
29
AddressSpace *as = &s->gicv3->dma_as;
31
30
uint64_t entry_addr;
32
- if (offset < 0x400) {
31
- uint64_t cte = 0;
33
- return s->data & (offset >> 2);
32
+ uint64_t cteval = 0;
34
- }
33
MemTxResult res = MEMTX_OK;
35
- if (offset >= s->rsvd_start && offset <= 0xfcc) {
34
36
- goto err_out;
35
if (!s->ct.valid) {
37
- }
36
return true;
38
- if (offset >= 0xfd0 && offset < 0x1000) {
39
- return s->id[(offset - 0xfd0) >> 2];
40
- }
41
switch (offset) {
42
+ case 0x0 ... 0x3ff: /* Data */
43
+ return s->data & (offset >> 2);
44
case 0x400: /* Direction */
45
return s->dir;
46
case 0x404: /* Interrupt sense */
47
@@ -XXX,XX +XXX,XX @@ static uint64_t pl061_read(void *opaque, hwaddr offset,
48
case 0x420: /* Alternate function select */
49
return s->afsel;
50
case 0x500: /* 2mA drive */
51
+ if (s->id != pl061_id_luminary) {
52
+ goto bad_offset;
53
+ }
54
return s->dr2r;
55
case 0x504: /* 4mA drive */
56
+ if (s->id != pl061_id_luminary) {
57
+ goto bad_offset;
58
+ }
59
return s->dr4r;
60
case 0x508: /* 8mA drive */
61
+ if (s->id != pl061_id_luminary) {
62
+ goto bad_offset;
63
+ }
64
return s->dr8r;
65
case 0x50c: /* Open drain */
66
+ if (s->id != pl061_id_luminary) {
67
+ goto bad_offset;
68
+ }
69
return s->odr;
70
case 0x510: /* Pull-up */
71
+ if (s->id != pl061_id_luminary) {
72
+ goto bad_offset;
73
+ }
74
return s->pur;
75
case 0x514: /* Pull-down */
76
+ if (s->id != pl061_id_luminary) {
77
+ goto bad_offset;
78
+ }
79
return s->pdr;
80
case 0x518: /* Slew rate control */
81
+ if (s->id != pl061_id_luminary) {
82
+ goto bad_offset;
83
+ }
84
return s->slr;
85
case 0x51c: /* Digital enable */
86
+ if (s->id != pl061_id_luminary) {
87
+ goto bad_offset;
88
+ }
89
return s->den;
90
case 0x520: /* Lock */
91
+ if (s->id != pl061_id_luminary) {
92
+ goto bad_offset;
93
+ }
94
return s->locked;
95
case 0x524: /* Commit */
96
+ if (s->id != pl061_id_luminary) {
97
+ goto bad_offset;
98
+ }
99
return s->cr;
100
case 0x528: /* Analog mode select */
101
+ if (s->id != pl061_id_luminary) {
102
+ goto bad_offset;
103
+ }
104
return s->amsel;
105
+ case 0xfd0 ... 0xfff: /* ID registers */
106
+ return s->id[(offset - 0xfd0) >> 2];
107
default:
108
+ bad_offset:
109
+ qemu_log_mask(LOG_GUEST_ERROR,
110
+ "pl061_read: Bad offset %x\n", (int)offset);
111
break;
112
}
37
}
113
-err_out:
38
114
- qemu_log_mask(LOG_GUEST_ERROR,
39
- if (valid) {
115
- "pl061_read: Bad offset %x\n", (int)offset);
40
+ if (cte->valid) {
116
return 0;
41
/* add mapping entry to collection table */
42
- cte = FIELD_DP64(cte, CTE, VALID, 1);
43
- cte = FIELD_DP64(cte, CTE, RDBASE, rdbase);
44
+ cteval = FIELD_DP64(cteval, CTE, VALID, 1);
45
+ cteval = FIELD_DP64(cteval, CTE, RDBASE, cte->rdbase);
46
}
47
48
entry_addr = table_entry_addr(s, &s->ct, icid, &res);
49
@@ -XXX,XX +XXX,XX @@ static bool update_cte(GICv3ITSState *s, uint16_t icid, bool valid,
50
return true;
51
}
52
53
- address_space_stq_le(as, entry_addr, cte, MEMTXATTRS_UNSPECIFIED, &res);
54
+ address_space_stq_le(as, entry_addr, cteval, MEMTXATTRS_UNSPECIFIED, &res);
55
return res == MEMTX_OK;
117
}
56
}
118
57
119
@@ -XXX,XX +XXX,XX @@ static void pl061_write(void *opaque, hwaddr offset,
58
static ItsCmdResult process_mapc(GICv3ITSState *s, const uint64_t *cmdpkt)
120
PL061State *s = (PL061State *)opaque;
59
{
121
uint8_t mask;
60
uint16_t icid;
122
61
- uint64_t rdbase;
123
- if (offset < 0x400) {
62
- bool valid;
124
+ switch (offset) {
63
+ CTEntry cte;
125
+ case 0 ... 0x3ff:
64
126
mask = (offset >> 2) & s->dir;
65
icid = cmdpkt[2] & ICID_MASK;
127
s->data = (s->data & ~mask) | (value & mask);
66
128
pl061_update(s);
67
- rdbase = (cmdpkt[2] & R_MAPC_RDBASE_MASK) >> R_MAPC_RDBASE_SHIFT;
129
return;
68
- rdbase &= RDBASE_PROCNUM_MASK;
130
- }
69
+ cte.rdbase = (cmdpkt[2] & R_MAPC_RDBASE_MASK) >> R_MAPC_RDBASE_SHIFT;
131
- if (offset >= s->rsvd_start) {
70
+ cte.rdbase &= RDBASE_PROCNUM_MASK;
132
- goto err_out;
71
133
- }
72
- valid = cmdpkt[2] & CMD_FIELD_VALID_MASK;
134
- switch (offset) {
73
+ cte.valid = cmdpkt[2] & CMD_FIELD_VALID_MASK;
135
case 0x400: /* Direction */
74
136
s->dir = value & 0xff;
75
- if ((icid >= s->ct.num_entries) || (rdbase >= s->gicv3->num_cpu)) {
137
break;
76
+ if ((icid >= s->ct.num_entries) || (cte.rdbase >= s->gicv3->num_cpu)) {
138
@@ -XXX,XX +XXX,XX @@ static void pl061_write(void *opaque, hwaddr offset,
77
qemu_log_mask(LOG_GUEST_ERROR,
139
s->afsel = (s->afsel & ~mask) | (value & mask);
78
"ITS MAPC: invalid collection table attributes "
140
break;
79
- "icid %d rdbase %" PRIu64 "\n", icid, rdbase);
141
case 0x500: /* 2mA drive */
80
+ "icid %d rdbase %u\n", icid, cte.rdbase);
142
+ if (s->id != pl061_id_luminary) {
81
/*
143
+ goto bad_offset;
82
* in this implementation, in case of error
144
+ }
83
* we ignore this command and move onto the next
145
s->dr2r = value & 0xff;
84
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_mapc(GICv3ITSState *s, const uint64_t *cmdpkt)
146
break;
85
return CMD_CONTINUE;
147
case 0x504: /* 4mA drive */
148
+ if (s->id != pl061_id_luminary) {
149
+ goto bad_offset;
150
+ }
151
s->dr4r = value & 0xff;
152
break;
153
case 0x508: /* 8mA drive */
154
+ if (s->id != pl061_id_luminary) {
155
+ goto bad_offset;
156
+ }
157
s->dr8r = value & 0xff;
158
break;
159
case 0x50c: /* Open drain */
160
+ if (s->id != pl061_id_luminary) {
161
+ goto bad_offset;
162
+ }
163
s->odr = value & 0xff;
164
break;
165
case 0x510: /* Pull-up */
166
+ if (s->id != pl061_id_luminary) {
167
+ goto bad_offset;
168
+ }
169
s->pur = value & 0xff;
170
break;
171
case 0x514: /* Pull-down */
172
+ if (s->id != pl061_id_luminary) {
173
+ goto bad_offset;
174
+ }
175
s->pdr = value & 0xff;
176
break;
177
case 0x518: /* Slew rate control */
178
+ if (s->id != pl061_id_luminary) {
179
+ goto bad_offset;
180
+ }
181
s->slr = value & 0xff;
182
break;
183
case 0x51c: /* Digital enable */
184
+ if (s->id != pl061_id_luminary) {
185
+ goto bad_offset;
186
+ }
187
s->den = value & 0xff;
188
break;
189
case 0x520: /* Lock */
190
+ if (s->id != pl061_id_luminary) {
191
+ goto bad_offset;
192
+ }
193
s->locked = (value != 0xacce551);
194
break;
195
case 0x524: /* Commit */
196
+ if (s->id != pl061_id_luminary) {
197
+ goto bad_offset;
198
+ }
199
if (!s->locked)
200
s->cr = value & 0xff;
201
break;
202
case 0x528:
203
+ if (s->id != pl061_id_luminary) {
204
+ goto bad_offset;
205
+ }
206
s->amsel = value & 0xff;
207
break;
208
default:
209
- goto err_out;
210
+ bad_offset:
211
+ qemu_log_mask(LOG_GUEST_ERROR,
212
+ "pl061_write: Bad offset %x\n", (int)offset);
213
+ return;
214
}
86
}
215
pl061_update(s);
87
216
return;
88
- return update_cte(s, icid, valid, rdbase) ? CMD_CONTINUE : CMD_STALL;
217
-err_out:
89
+ return update_cte(s, icid, &cte) ? CMD_CONTINUE : CMD_STALL;
218
- qemu_log_mask(LOG_GUEST_ERROR,
219
- "pl061_write: Bad offset %x\n", (int)offset);
220
}
90
}
221
91
222
static void pl061_reset(DeviceState *dev)
92
/*
223
@@ -XXX,XX +XXX,XX @@ static void pl061_luminary_init(Object *obj)
224
PL061State *s = PL061(obj);
225
226
s->id = pl061_id_luminary;
227
- s->rsvd_start = 0x52c;
228
}
229
230
static void pl061_init(Object *obj)
231
@@ -XXX,XX +XXX,XX @@ static void pl061_init(Object *obj)
232
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
233
234
s->id = pl061_id;
235
- s->rsvd_start = 0x424;
236
237
memory_region_init_io(&s->iomem, obj, &pl061_ops, s, "pl061", 0x1000);
238
sysbus_init_mmio(sbd, &s->iomem);
239
--
93
--
240
2.20.1
94
2.25.1
241
95
242
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
Convert the use of the DPRINTF debug macro in the PL061 model to
1
The get_ite() code has some awkward nested if statements; clean
2
use tracepoints.
2
them up by returning early if the memory accesses fail.
3
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20220201193207.2771604-8-peter.maydell@linaro.org
7
---
7
---
8
hw/gpio/pl061.c | 27 +++++++++------------------
8
hw/intc/arm_gicv3_its.c | 26 ++++++++++++++------------
9
hw/gpio/trace-events | 6 ++++++
9
1 file changed, 14 insertions(+), 12 deletions(-)
10
2 files changed, 15 insertions(+), 18 deletions(-)
11
10
12
diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.c
11
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
13
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
14
--- a/hw/gpio/pl061.c
13
--- a/hw/intc/arm_gicv3_its.c
15
+++ b/hw/gpio/pl061.c
14
+++ b/hw/intc/arm_gicv3_its.c
16
@@ -XXX,XX +XXX,XX @@
15
@@ -XXX,XX +XXX,XX @@ static bool get_ite(GICv3ITSState *s, uint32_t eventid, const DTEntry *dte,
17
#include "qemu/log.h"
16
hwaddr iteaddr = dte->ittaddr + eventid * ITS_ITT_ENTRY_SIZE;
18
#include "qemu/module.h"
17
19
#include "qom/object.h"
18
ite.itel = address_space_ldq_le(as, iteaddr, MEMTXATTRS_UNSPECIFIED, res);
20
-
19
+ if (*res != MEMTX_OK) {
21
-//#define DEBUG_PL061 1
20
+ return false;
22
-
21
+ }
23
-#ifdef DEBUG_PL061
22
24
-#define DPRINTF(fmt, ...) \
23
- if (*res == MEMTX_OK) {
25
-do { printf("pl061: " fmt , ## __VA_ARGS__); } while (0)
24
- ite.iteh = address_space_ldl_le(as, iteaddr + 8,
26
-#define BADF(fmt, ...) \
25
- MEMTXATTRS_UNSPECIFIED, res);
27
-do { fprintf(stderr, "pl061: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
26
+ ite.iteh = address_space_ldl_le(as, iteaddr + 8,
28
-#else
27
+ MEMTXATTRS_UNSPECIFIED, res);
29
-#define DPRINTF(fmt, ...) do {} while(0)
28
+ if (*res != MEMTX_OK) {
30
-#define BADF(fmt, ...) \
29
+ return false;
31
-do { fprintf(stderr, "pl061: error: " fmt , ## __VA_ARGS__);} while (0)
30
+ }
32
-#endif
31
33
+#include "trace.h"
32
- if (*res == MEMTX_OK) {
34
33
- if (FIELD_EX64(ite.itel, ITE_L, VALID)) {
35
static const uint8_t pl061_id[12] =
34
- int inttype = FIELD_EX64(ite.itel, ITE_L, INTTYPE);
36
{ 0x00, 0x00, 0x00, 0x00, 0x61, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
35
- if (inttype == ITE_INTTYPE_PHYSICAL) {
37
@@ -XXX,XX +XXX,XX @@ static void pl061_update(PL061State *s)
36
- *pIntid = FIELD_EX64(ite.itel, ITE_L, INTID);
38
uint8_t out;
37
- *icid = FIELD_EX64(ite.itel, ITE_L, ICID);
39
int i;
38
- status = true;
40
39
- }
41
- DPRINTF("dir = %d, data = %d\n", s->dir, s->data);
40
- }
42
+ trace_pl061_update(DEVICE(s)->canonical_path, s->dir, s->data);
41
+ if (FIELD_EX64(ite.itel, ITE_L, VALID)) {
43
42
+ int inttype = FIELD_EX64(ite.itel, ITE_L, INTTYPE);
44
/* Outputs float high. */
43
+ if (inttype == ITE_INTTYPE_PHYSICAL) {
45
/* FIXME: This is board dependent. */
44
+ *pIntid = FIELD_EX64(ite.itel, ITE_L, INTID);
46
@@ -XXX,XX +XXX,XX @@ static void pl061_update(PL061State *s)
45
+ *icid = FIELD_EX64(ite.itel, ITE_L, ICID);
47
for (i = 0; i < N_GPIOS; i++) {
46
+ status = true;
48
mask = 1 << i;
49
if (changed & mask) {
50
- DPRINTF("Set output %d = %d\n", i, (out & mask) != 0);
51
- qemu_set_irq(s->out[i], (out & mask) != 0);
52
+ int level = (out & mask) != 0;
53
+ trace_pl061_set_output(DEVICE(s)->canonical_path, i, level);
54
+ qemu_set_irq(s->out[i], level);
55
}
56
}
47
}
57
}
48
}
58
@@ -XXX,XX +XXX,XX @@ static void pl061_update(PL061State *s)
49
return status;
59
for (i = 0; i < N_GPIOS; i++) {
60
mask = 1 << i;
61
if (changed & mask) {
62
- DPRINTF("Changed input %d = %d\n", i, (s->data & mask) != 0);
63
+ trace_pl061_input_change(DEVICE(s)->canonical_path, i,
64
+ (s->data & mask) != 0);
65
66
if (!(s->isense & mask)) {
67
/* Edge interrupt */
68
@@ -XXX,XX +XXX,XX @@ static void pl061_update(PL061State *s)
69
/* Level interrupt */
70
s->istate |= ~(s->data ^ s->iev) & s->isense;
71
72
- DPRINTF("istate = %02X\n", s->istate);
73
+ trace_pl061_update_istate(DEVICE(s)->canonical_path,
74
+ s->istate, s->im, (s->istate & s->im) != 0);
75
76
qemu_set_irq(s->irq, (s->istate & s->im) != 0);
77
}
78
diff --git a/hw/gpio/trace-events b/hw/gpio/trace-events
79
index XXXXXXX..XXXXXXX 100644
80
--- a/hw/gpio/trace-events
81
+++ b/hw/gpio/trace-events
82
@@ -XXX,XX +XXX,XX @@ nrf51_gpio_write(uint64_t offset, uint64_t value) "offset 0x%" PRIx64 " value 0x
83
nrf51_gpio_set(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64
84
nrf51_gpio_update_output_irq(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64
85
86
+# pl061.c
87
+pl061_update(const char *id, uint32_t dir, uint32_t data) "%s GPIODIR 0x%x GPIODATA 0x%x"
88
+pl061_set_output(const char *id, int gpio, int level) "%s setting output %d to %d"
89
+pl061_input_change(const char *id, int gpio, int level) "%s input %d changed to %d"
90
+pl061_update_istate(const char *id, uint32_t istate, uint32_t im, int level) "%s GPIORIS 0x%x GPIOIE 0x%x interrupt level %d"
91
+
92
# sifive_gpio.c
93
sifive_gpio_read(uint64_t offset, uint64_t r) "offset 0x%" PRIx64 " value 0x%" PRIx64
94
sifive_gpio_write(uint64_t offset, uint64_t value) "offset 0x%" PRIx64 " value 0x%" PRIx64
95
--
50
--
96
2.20.1
51
2.25.1
97
52
98
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 PL061 GPIO does not itself include pullup or pulldown resistors
1
Make the update_ite() struct use the new ITEntry struct, so that
2
to set the value of a GPIO line treated as an output when it is
2
callers don't need to assemble the in-memory ITE data themselves, and
3
configured as an input (ie when the PL061 itself is not driving it).
3
only get_ite() and update_ite() need to care about that in-memory
4
In real hardware it is up to the board to add suitable pullups or
4
layout. We can then drop the no-longer-used IteEntry struct
5
pulldowns. Currently our implementation hardwires this to "outputs
5
definition.
6
pulled high", which is correct for some boards (eg the realview ones:
7
see figure 3-29 in the "RealView Platform Baseboard for ARM926EJ-S
8
User Guide" DUI0224I), but wrong for others.
9
10
In particular, the wiring in the 'virt' board and the gpio-pwr device
11
assumes that wires should be pulled low, because otherwise the
12
pull-to-high will trigger a shutdown or reset action. (The only
13
reason this doesn't happen immediately on startup is due to another
14
bug in the PL061, where we don't assert the GPIOs to the correct
15
value on reset, but will do so as soon as the guest touches a
16
register and pl061_update() gets called.)
17
18
Add properties to the pl061 so the board can configure whether it
19
wants GPIO lines to have pullup, pulldown, or neither.
20
6
21
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
22
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
9
Message-id: 20220201193207.2771604-10-peter.maydell@linaro.org
23
---
10
---
24
hw/gpio/pl061.c | 51 +++++++++++++++++++++++++++++++++++++++++++++----
11
hw/intc/arm_gicv3_its.c | 62 +++++++++++++++++++++--------------------
25
1 file changed, 47 insertions(+), 4 deletions(-)
12
1 file changed, 32 insertions(+), 30 deletions(-)
26
13
27
diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.c
14
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
28
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
29
--- a/hw/gpio/pl061.c
16
--- a/hw/intc/arm_gicv3_its.c
30
+++ b/hw/gpio/pl061.c
17
+++ b/hw/intc/arm_gicv3_its.c
31
@@ -XXX,XX +XXX,XX @@
18
@@ -XXX,XX +XXX,XX @@ typedef enum ItsCmdType {
32
* + unnamed GPIO inputs 0..7: inputs to connect to the emulated GPIO lines
19
INTERRUPT = 3,
33
* + unnamed GPIO outputs 0..7: the emulated GPIO lines, considered as
20
} ItsCmdType;
34
* outputs
21
35
+ * + QOM property "pullups": an integer defining whether non-floating lines
22
-typedef struct {
36
+ * configured as inputs should be pulled up to logical 1 (ie whether in
23
- uint32_t iteh;
37
+ * real hardware they have a pullup resistor on the line out of the PL061).
24
- uint64_t itel;
38
+ * This should be an 8-bit value, where bit 0 is 1 if GPIO line 0 should
25
-} IteEntry;
39
+ * be pulled high, bit 1 configures line 1, and so on. The default is 0xff,
26
-
40
+ * indicating that all GPIO lines are pulled up to logical 1.
27
typedef struct DTEntry {
41
+ * + QOM property "pulldowns": an integer defining whether non-floating lines
28
bool valid;
42
+ * configured as inputs should be pulled down to logical 0 (ie whether in
29
unsigned size;
43
+ * real hardware they have a pulldown resistor on the line out of the PL061).
30
@@ -XXX,XX +XXX,XX @@ static MemTxResult get_cte(GICv3ITSState *s, uint16_t icid, CTEntry *cte)
44
+ * This should be an 8-bit value, where bit 0 is 1 if GPIO line 0 should
31
return MEMTX_OK;
45
+ * be pulled low, bit 1 configures line 1, and so on. The default is 0x0.
32
}
46
+ * It is an error to set a bit in both "pullups" and "pulldowns". If a bit
33
47
+ * is 0 in both, then the line is considered to be floating, and it will
34
+/*
48
+ * not have qemu_set_irq() called on it when it is configured as an input.
35
+ * Update the Interrupt Table entry at index @evinted in the table specified
49
*/
36
+ * by the dte @dte. Returns true on success, false if there was a memory
50
37
+ * access error.
51
#include "qemu/osdep.h"
38
+ */
52
#include "hw/irq.h"
39
static bool update_ite(GICv3ITSState *s, uint32_t eventid, const DTEntry *dte,
53
#include "hw/sysbus.h"
40
- IteEntry ite)
54
+#include "hw/qdev-properties.h"
41
+ const ITEntry *ite)
55
#include "migration/vmstate.h"
42
{
56
+#include "qapi/error.h"
43
AddressSpace *as = &s->gicv3->dma_as;
57
#include "qemu/log.h"
44
MemTxResult res = MEMTX_OK;
58
#include "qemu/module.h"
45
hwaddr iteaddr = dte->ittaddr + eventid * ITS_ITT_ENTRY_SIZE;
59
#include "qom/object.h"
46
+ uint64_t itel = 0;
60
@@ -XXX,XX +XXX,XX @@ struct PL061State {
47
+ uint32_t iteh = 0;
61
qemu_irq irq;
48
62
qemu_irq out[N_GPIOS];
49
- address_space_stq_le(as, iteaddr, ite.itel, MEMTXATTRS_UNSPECIFIED, &res);
63
const unsigned char *id;
50
-
64
+ /* Properties, for non-Luminary PL061 */
51
- if (res == MEMTX_OK) {
65
+ uint32_t pullups;
52
- address_space_stl_le(as, iteaddr + 8, ite.iteh,
66
+ uint32_t pulldowns;
53
- MEMTXATTRS_UNSPECIFIED, &res);
67
};
54
+ if (ite->valid) {
68
55
+ itel = FIELD_DP64(itel, ITE_L, VALID, 1);
69
static const VMStateDescription vmstate_pl061 = {
56
+ itel = FIELD_DP64(itel, ITE_L, INTTYPE, ite->inttype);
70
@@ -XXX,XX +XXX,XX @@ static uint8_t pl061_floating(PL061State *s)
57
+ itel = FIELD_DP64(itel, ITE_L, INTID, ite->intid);
71
*/
58
+ itel = FIELD_DP64(itel, ITE_L, ICID, ite->icid);
72
floating = ~(s->pur | s->pdr);
59
+ itel = FIELD_DP64(itel, ITE_L, VPEID, ite->vpeid);
73
} else {
60
+ iteh = FIELD_DP32(iteh, ITE_H, DOORBELL, ite->doorbell);
74
- /* Assume outputs are pulled high. FIXME: this is board dependent. */
75
- floating = 0;
76
+ floating = ~(s->pullups | s->pulldowns);
77
}
61
}
78
return floating & ~s->dir;
62
+
63
+ address_space_stq_le(as, iteaddr, itel, MEMTXATTRS_UNSPECIFIED, &res);
64
if (res != MEMTX_OK) {
65
return false;
66
- } else {
67
- return true;
68
}
69
+ address_space_stl_le(as, iteaddr + 8, iteh, MEMTXATTRS_UNSPECIFIED, &res);
70
+ return res == MEMTX_OK;
79
}
71
}
80
@@ -XXX,XX +XXX,XX @@ static uint8_t pl061_pullups(PL061State *s)
72
81
*/
73
/*
82
pullups = s->pur;
74
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult do_process_its_cmd(GICv3ITSState *s, uint32_t devid,
83
} else {
84
- /* Assume outputs are pulled high. FIXME: this is board dependent. */
85
- pullups = 0xff;
86
+ pullups = s->pullups;
87
}
75
}
88
return pullups & ~s->dir;
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;
89
}
86
}
90
@@ -XXX,XX +XXX,XX @@ static void pl061_init(Object *obj)
87
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_mapti(GICv3ITSState *s, const uint64_t *cmdpkt,
91
qdev_init_gpio_out(dev, s->out, N_GPIOS);
88
uint64_t num_eventids;
89
uint32_t num_intids;
90
uint16_t icid = 0;
91
- IteEntry ite = {};
92
DTEntry dte;
93
+ ITEntry ite;
94
95
devid = (cmdpkt[0] & DEVID_MASK) >> DEVID_SHIFT;
96
eventid = cmdpkt[1] & EVENTID_MASK;
97
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_mapti(GICv3ITSState *s, const uint64_t *cmdpkt,
98
}
99
100
/* add ite entry to interrupt translation table */
101
- ite.itel = FIELD_DP64(ite.itel, ITE_L, VALID, true);
102
- ite.itel = FIELD_DP64(ite.itel, ITE_L, INTTYPE, ITE_INTTYPE_PHYSICAL);
103
- ite.itel = FIELD_DP64(ite.itel, ITE_L, INTID, pIntid);
104
- ite.itel = FIELD_DP64(ite.itel, ITE_L, ICID, icid);
105
- ite.iteh = FIELD_DP32(ite.iteh, ITE_H, DOORBELL, INTID_SPURIOUS);
106
-
107
- return update_ite(s, eventid, &dte, ite) ? CMD_CONTINUE : CMD_STALL;
108
+ ite.valid = true;
109
+ ite.inttype = ITE_INTTYPE_PHYSICAL;
110
+ ite.intid = pIntid;
111
+ ite.icid = icid;
112
+ ite.doorbell = INTID_SPURIOUS;
113
+ ite.vpeid = 0;
114
+ return update_ite(s, eventid, &dte, &ite) ? CMD_CONTINUE : CMD_STALL;
92
}
115
}
93
116
94
+static void pl061_realize(DeviceState *dev, Error **errp)
117
/*
95
+{
118
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_movi(GICv3ITSState *s, const uint64_t *cmdpkt)
96
+ PL061State *s = PL061(dev);
119
uint32_t devid, eventid;
97
+
120
uint16_t new_icid;
98
+ if (s->pullups > 0xff) {
121
uint64_t num_eventids;
99
+ error_setg(errp, "pullups property must be between 0 and 0xff");
122
- IteEntry ite = {};
100
+ return;
123
DTEntry dte;
101
+ }
124
CTEntry old_cte, new_cte;
102
+ if (s->pulldowns > 0xff) {
125
ITEntry old_ite;
103
+ error_setg(errp, "pulldowns property must be between 0 and 0xff");
126
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_movi(GICv3ITSState *s, const uint64_t *cmdpkt)
104
+ return;
127
}
105
+ }
128
106
+ if (s->pullups & s->pulldowns) {
129
/* Update the ICID field in the interrupt translation table entry */
107
+ error_setg(errp, "no bit may be set both in pullups and pulldowns");
130
- ite.itel = FIELD_DP64(ite.itel, ITE_L, VALID, 1);
108
+ return;
131
- ite.itel = FIELD_DP64(ite.itel, ITE_L, INTTYPE, ITE_INTTYPE_PHYSICAL);
109
+ }
132
- ite.itel = FIELD_DP64(ite.itel, ITE_L, INTID, old_ite.intid);
110
+}
133
- ite.itel = FIELD_DP64(ite.itel, ITE_L, ICID, new_icid);
111
+
134
- ite.iteh = FIELD_DP32(ite.iteh, ITE_H, DOORBELL, INTID_SPURIOUS);
112
+static Property pl061_props[] = {
135
- return update_ite(s, eventid, &dte, ite) ? CMD_CONTINUE : CMD_STALL;
113
+ DEFINE_PROP_UINT32("pullups", PL061State, pullups, 0xff),
136
+ old_ite.icid = new_icid;
114
+ DEFINE_PROP_UINT32("pulldowns", PL061State, pulldowns, 0x0),
137
+ return update_ite(s, eventid, &dte, &old_ite) ? CMD_CONTINUE : CMD_STALL;
115
+ DEFINE_PROP_END_OF_LIST()
116
+};
117
+
118
static void pl061_class_init(ObjectClass *klass, void *data)
119
{
120
DeviceClass *dc = DEVICE_CLASS(klass);
121
122
dc->vmsd = &vmstate_pl061;
123
dc->reset = &pl061_reset;
124
+ dc->realize = pl061_realize;
125
+ device_class_set_props(dc, pl061_props);
126
}
138
}
127
139
128
static const TypeInfo pl061_info = {
140
/*
129
--
141
--
130
2.20.1
142
2.25.1
131
143
132
144
diff view generated by jsdifflib
New patch
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.
1
5
6
The GIC specification says that it is UNPREDICTABLE if a guest fails
7
to set any of these Valid bits before enabling the ITS via
8
GITS_CTLR.Enabled. So we can choose to handle Valid == 0 as
9
equivalent to a zero-length table. This is in fact how we're already
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
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
24
---
25
include/hw/intc/arm_gicv3_its_common.h | 2 --
26
hw/intc/arm_gicv3_its.c | 31 ++++++++++++--------------
27
2 files changed, 14 insertions(+), 19 deletions(-)
28
29
diff --git a/include/hw/intc/arm_gicv3_its_common.h b/include/hw/intc/arm_gicv3_its_common.h
30
index XXXXXXX..XXXXXXX 100644
31
--- a/include/hw/intc/arm_gicv3_its_common.h
32
+++ b/include/hw/intc/arm_gicv3_its_common.h
33
@@ -XXX,XX +XXX,XX @@
34
#define GITS_TRANSLATER 0x0040
35
36
typedef struct {
37
- bool valid;
38
bool indirect;
39
uint16_t entry_sz;
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);
82
}
83
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);
121
--
122
2.25.1
123
124
diff view generated by jsdifflib
New patch
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.
1
5
6
We were doing a check-and-log-guest-error on rdbase regardless of
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.
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-12-peter.maydell@linaro.org
15
---
16
hw/intc/arm_gicv3_its.c | 24 ++++++++++++------------
17
1 file changed, 12 insertions(+), 12 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 @@ static ItsCmdResult process_mapc(GICv3ITSState *s, const uint64_t *cmdpkt)
24
CTEntry cte;
25
26
icid = cmdpkt[2] & ICID_MASK;
27
-
28
- cte.rdbase = (cmdpkt[2] & R_MAPC_RDBASE_MASK) >> R_MAPC_RDBASE_SHIFT;
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;
37
+ }
38
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
}
56
57
--
58
2.25.1
59
60
diff view generated by jsdifflib
1
Add a comment documenting the "QEMU interface" of this device:
1
When handling MAPI/MAPTI, we allow the supplied interrupt ID to be
2
which MMIO regions, IRQ lines, GPIO lines, etc it exposes.
2
either 1023 or something in the valid LPI range. This is a mistake:
3
only a real valid LPI is allowed. (The general behaviour of the ITS
4
is that most interrupt ID fields require a value in the LPI range;
5
the exception is that fields specifying a doorbell value, which are
6
all in GICv4 commands, allow also 1023 to mean "no doorbell".)
7
Remove the condition that incorrectly allows 1023 here.
3
8
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
11
Message-id: 20220201193207.2771604-13-peter.maydell@linaro.org
6
---
12
---
7
hw/gpio/pl061.c | 7 +++++++
13
hw/intc/arm_gicv3_its.c | 3 +--
8
1 file changed, 7 insertions(+)
14
1 file changed, 1 insertion(+), 2 deletions(-)
9
15
10
diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.c
16
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
11
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
12
--- a/hw/gpio/pl061.c
18
--- a/hw/intc/arm_gicv3_its.c
13
+++ b/hw/gpio/pl061.c
19
+++ b/hw/intc/arm_gicv3_its.c
14
@@ -XXX,XX +XXX,XX @@
20
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_mapti(GICv3ITSState *s, const uint64_t *cmdpkt,
15
* Written by Paul Brook
21
16
*
22
if ((icid >= s->ct.num_entries)
17
* This code is licensed under the GPL.
23
|| !dte.valid || (eventid >= num_eventids) ||
18
+ *
24
- (((pIntid < GICV3_LPI_INTID_START) || (pIntid >= num_intids)) &&
19
+ * QEMU interface:
25
- (pIntid != INTID_SPURIOUS))) {
20
+ * + sysbus MMIO region 0: the device registers
26
+ (((pIntid < GICV3_LPI_INTID_START) || (pIntid >= num_intids)))) {
21
+ * + sysbus IRQ: the GPIOINTR interrupt line
27
qemu_log_mask(LOG_GUEST_ERROR,
22
+ * + unnamed GPIO inputs 0..7: inputs to connect to the emulated GPIO lines
28
"%s: invalid command attributes "
23
+ * + unnamed GPIO outputs 0..7: the emulated GPIO lines, considered as
29
"icid %d or eventid %d or pIntid %d or"
24
+ * outputs
25
*/
26
27
#include "qemu/osdep.h"
28
--
30
--
29
2.20.1
31
2.25.1
30
32
31
33
diff view generated by jsdifflib
1
The stellaris board doesn't emulate the handling of the OLED
1
In most of the ITS command processing, we check different error
2
chipselect line correctly. Expand the comment describing this,
2
possibilities one at a time and log them appropriately. In
3
including a sketch of the theoretical correct way to do it.
3
process_mapti() and process_mapd() we have code which checks
4
multiple error cases at once, which means the logging is less
5
specific than it could be. Split those cases up.
4
6
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
9
Message-id: 20220201193207.2771604-14-peter.maydell@linaro.org
6
---
10
---
7
hw/arm/stellaris.c | 56 +++++++++++++++++++++++++++++++++++++++++++++-
11
hw/intc/arm_gicv3_its.c | 52 ++++++++++++++++++++++++-----------------
8
1 file changed, 55 insertions(+), 1 deletion(-)
12
1 file changed, 31 insertions(+), 21 deletions(-)
9
13
10
diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c
14
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
11
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
12
--- a/hw/arm/stellaris.c
16
--- a/hw/intc/arm_gicv3_its.c
13
+++ b/hw/arm/stellaris.c
17
+++ b/hw/intc/arm_gicv3_its.c
14
@@ -XXX,XX +XXX,XX @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board)
18
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_mapti(GICv3ITSState *s, const uint64_t *cmdpkt,
15
DeviceState *sddev;
19
num_eventids = 1ULL << (dte.size + 1);
16
DeviceState *ssddev;
20
num_intids = 1ULL << (GICD_TYPER_IDBITS + 1);
17
21
18
- /* Some boards have both an OLED controller and SD card connected to
22
- if ((icid >= s->ct.num_entries)
19
+ /*
23
- || !dte.valid || (eventid >= num_eventids) ||
20
+ * Some boards have both an OLED controller and SD card connected to
24
- (((pIntid < GICV3_LPI_INTID_START) || (pIntid >= num_intids)))) {
21
* the same SSI port, with the SD card chip select connected to a
25
+ if (icid >= s->ct.num_entries) {
22
* GPIO pin. Technically the OLED chip select is connected to the
26
qemu_log_mask(LOG_GUEST_ERROR,
23
* SSI Fss pin. We do not bother emulating that as both devices
27
- "%s: invalid command attributes "
24
* should never be selected simultaneously, and our OLED controller
28
- "icid %d or eventid %d or pIntid %d or"
25
* ignores stray 0xff commands that occur when deselecting the SD
29
- "unmapped dte %d\n", __func__, icid, eventid,
26
* card.
30
- pIntid, dte.valid);
27
+ *
31
- /*
28
+ * The h/w wiring is:
32
- * in this implementation, in case of error
29
+ * - GPIO pin D0 is wired to the active-low SD card chip select
33
- * we ignore this command and move onto the next
30
+ * - GPIO pin A3 is wired to the active-low OLED chip select
34
- * command in the queue
31
+ * - The SoC wiring of the PL061 "auxiliary function" for A3 is
35
- */
32
+ * SSI0Fss ("frame signal"), which is an output from the SoC's
36
+ "%s: invalid ICID 0x%x >= 0x%x\n",
33
+ * SSI controller. The SSI controller takes SSI0Fss low when it
37
+ __func__, icid, s->ct.num_entries);
34
+ * transmits a frame, so it can work as a chip-select signal.
38
+ return CMD_CONTINUE;
35
+ * - GPIO A4 is aux-function SSI0Rx, and wired to the SD card Tx
39
+ }
36
+ * (the OLED never sends data to the CPU, so no wiring needed)
40
+
37
+ * - GPIO A5 is aux-function SSI0Tx, and wired to the SD card Rx
41
+ if (!dte.valid) {
38
+ * and the OLED display-data-in
42
+ qemu_log_mask(LOG_GUEST_ERROR,
39
+ * - GPIO A2 is aux-function SSI0Clk, wired to SD card and OLED
43
+ "%s: no valid DTE for devid 0x%x\n", __func__, devid);
40
+ * serial-clock input
44
+ return CMD_CONTINUE;
41
+ * So a guest that wants to use the OLED can configure the PL061
45
+ }
42
+ * to make pins A2, A3, A5 aux-function, so they are connected
46
+
43
+ * directly to the SSI controller. When the SSI controller sends
47
+ if (eventid >= num_eventids) {
44
+ * data it asserts SSI0Fss which selects the OLED.
48
+ qemu_log_mask(LOG_GUEST_ERROR,
45
+ * A guest that wants to use the SD card configures A2, A4 and A5
49
+ "%s: invalid event ID 0x%x >= 0x%" PRIx64 "\n",
46
+ * as aux-function, but leaves A3 as a software-controlled GPIO
50
+ __func__, eventid, num_eventids);
47
+ * line. It asserts the SD card chip-select by using the PL061
51
+ return CMD_CONTINUE;
48
+ * to control pin D0, and lets the SSI controller handle Clk, Tx
52
+ }
49
+ * and Rx. (The SSI controller asserts Fss during tx cycles as
53
+
50
+ * usual, but because A3 is not set to aux-function this is not
54
+ if (pIntid < GICV3_LPI_INTID_START || pIntid >= num_intids) {
51
+ * forwarded to the OLED, and so the OLED stays unselected.)
55
+ qemu_log_mask(LOG_GUEST_ERROR,
52
+ *
56
+ "%s: invalid interrupt ID 0x%x\n", __func__, pIntid);
53
+ * The QEMU implementation instead is:
57
return CMD_CONTINUE;
54
+ * - GPIO pin D0 is wired to the active-low SD card chip select,
58
}
55
+ * and also to the OLED chip-select which is implemented
59
56
+ * as *active-high*
60
@@ -XXX,XX +XXX,XX @@ static ItsCmdResult process_mapd(GICv3ITSState *s, const uint64_t *cmdpkt)
57
+ * - SSI controller signals go to the devices regardless of
61
dte.ittaddr = (cmdpkt[2] & ITTADDR_MASK) >> ITTADDR_SHIFT;
58
+ * whether the guest programs A2, A4, A5 as aux-function or not
62
dte.valid = cmdpkt[2] & CMD_FIELD_VALID_MASK;
59
+ *
63
60
+ * The problem with this implementation is if the guest doesn't
64
- if ((devid >= s->dt.num_entries) ||
61
+ * care about the SD card and only uses the OLED. In that case it
65
- (dte.size > FIELD_EX64(s->typer, GITS_TYPER, IDBITS))) {
62
+ * may choose never to do anything with D0 (leaving it in its
66
+ if (devid >= s->dt.num_entries) {
63
+ * default floating state, which reliably leaves the card disabled
67
qemu_log_mask(LOG_GUEST_ERROR,
64
+ * because an SD card has a pullup on CS within the card itself),
68
- "ITS MAPD: invalid device table attributes "
65
+ * and only set up A2, A3, A5. This for us would mean the OLED
69
- "devid %d or size %d\n", devid, dte.size);
66
+ * never gets the chip-select assert it needs. We work around
70
- /*
67
+ * this with a manual raise of D0 here (despite board creation
71
- * in this implementation, in case of error
68
+ * code being the wrong place to raise IRQ lines) to put the OLED
72
- * we ignore this command and move onto the next
69
+ * into an initially selected state.
73
- * command in the queue
70
+ *
74
- */
71
+ * In theory the right way to model this would be:
75
+ "ITS MAPD: invalid device ID field 0x%x >= 0x%x\n",
72
+ * - Implement aux-function support in the PL061, with an
76
+ devid, s->dt.num_entries);
73
+ * extra set of AFIN and AFOUT GPIO lines (set up so that
77
+ return CMD_CONTINUE;
74
+ * if a GPIO line is in auxfn mode the main GPIO in and out
78
+ }
75
+ * track the AFIN and AFOUT lines)
79
+
76
+ * - Wire the AFOUT for D0 up to either a line from the
80
+ if (dte.size > FIELD_EX64(s->typer, GITS_TYPER, IDBITS)) {
77
+ * SSI controller that's pulled low around every transmit,
81
+ qemu_log_mask(LOG_GUEST_ERROR,
78
+ * or at least to an always-0 line here on the board
82
+ "ITS MAPD: invalid size %d\n", dte.size);
79
+ * - Make the ssd0323 OLED controller chipselect active-low
83
return CMD_CONTINUE;
80
*/
84
}
81
bus = qdev_get_child_bus(dev, "ssi");
82
85
83
--
86
--
84
2.20.1
87
2.25.1
85
88
86
89
diff view generated by jsdifflib
1
From: Alexandre Iooss <erdnaxe@crans.org>
1
From: Kevin Townsend <kevin.townsend@linaro.org>
2
2
3
This SoC is similar to stm32f205 SoC.
3
This commit adds emulation of the magnetometer on the LSM303DLHC.
4
This will be used by the STM32VLDISCOVERY to create a machine.
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
Signed-off-by: Alexandre Iooss <erdnaxe@crans.org>
9
Signed-off-by: Kevin Townsend <kevin.townsend@linaro.org>
7
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
10
Message-id: 20220130095032.35392-1-kevin.townsend@linaro.org
8
Message-id: 20210617165647.2575955-2-erdnaxe@crans.org
11
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>
10
---
13
---
11
include/hw/arm/stm32f100_soc.h | 57 +++++++++++
14
hw/sensor/lsm303dlhc_mag.c | 556 ++++++++++++++++++++++++++++++
12
hw/arm/stm32f100_soc.c | 182 +++++++++++++++++++++++++++++++++
15
tests/qtest/lsm303dlhc-mag-test.c | 148 ++++++++
13
MAINTAINERS | 6 ++
16
hw/sensor/Kconfig | 4 +
14
hw/arm/Kconfig | 6 ++
17
hw/sensor/meson.build | 1 +
15
hw/arm/meson.build | 1 +
18
tests/qtest/meson.build | 1 +
16
5 files changed, 252 insertions(+)
19
5 files changed, 710 insertions(+)
17
create mode 100644 include/hw/arm/stm32f100_soc.h
20
create mode 100644 hw/sensor/lsm303dlhc_mag.c
18
create mode 100644 hw/arm/stm32f100_soc.c
21
create mode 100644 tests/qtest/lsm303dlhc-mag-test.c
19
22
20
diff --git a/include/hw/arm/stm32f100_soc.h b/include/hw/arm/stm32f100_soc.h
23
diff --git a/hw/sensor/lsm303dlhc_mag.c b/hw/sensor/lsm303dlhc_mag.c
21
new file mode 100644
24
new file mode 100644
22
index XXXXXXX..XXXXXXX
25
index XXXXXXX..XXXXXXX
23
--- /dev/null
26
--- /dev/null
24
+++ b/include/hw/arm/stm32f100_soc.h
27
+++ b/hw/sensor/lsm303dlhc_mag.c
25
@@ -XXX,XX +XXX,XX @@
28
@@ -XXX,XX +XXX,XX @@
26
+/*
29
+/*
27
+ * STM32F100 SoC
30
+ * LSM303DLHC I2C magnetometer.
28
+ *
31
+ *
29
+ * Copyright (c) 2021 Alexandre Iooss <erdnaxe@crans.org>
32
+ * Copyright (C) 2021 Linaro Ltd.
33
+ * Written by Kevin Townsend <kevin.townsend@linaro.org>
30
+ *
34
+ *
31
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
35
+ * Based on: https://www.st.com/resource/en/datasheet/lsm303dlhc.pdf
32
+ * of this software and associated documentation files (the "Software"), to deal
33
+ * in the Software without restriction, including without limitation the rights
34
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
35
+ * copies of the Software, and to permit persons to whom the Software is
36
+ * furnished to do so, subject to the following conditions:
37
+ *
36
+ *
38
+ * The above copyright notice and this permission notice shall be included in
37
+ * SPDX-License-Identifier: GPL-2.0-or-later
39
+ * all copies or substantial portions of the Software.
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.
40
+ *
43
+ *
41
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
44
+ * Get and set functions for 'mag-x', 'mag-y' and 'mag-z' assume that
42
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
45
+ * 1 = 0.001 uT. (NOTE the 1 gauss = 100 uT, so setting a value of 100,000
43
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
46
+ * would be equal to 1 gauss or 100 uT.)
44
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
47
+ *
45
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
48
+ * Get and set functions for 'temperature' assume that 1 = 0.001 C, so 23.6 C
46
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
49
+ * would be equal to 23600.
47
+ * THE SOFTWARE.
50
+ */
48
+ */
51
+
49
+
52
+#include "qemu/osdep.h"
50
+#ifndef HW_ARM_STM32F100_SOC_H
53
+#include "hw/i2c/i2c.h"
51
+#define HW_ARM_STM32F100_SOC_H
54
+#include "migration/vmstate.h"
52
+
55
+#include "qapi/error.h"
53
+#include "hw/char/stm32f2xx_usart.h"
56
+#include "qapi/visitor.h"
54
+#include "hw/ssi/stm32f2xx_spi.h"
57
+#include "qemu/module.h"
55
+#include "hw/arm/armv7m.h"
58
+#include "qemu/log.h"
56
+#include "qom/object.h"
59
+#include "qemu/bswap.h"
57
+
60
+
58
+#define TYPE_STM32F100_SOC "stm32f100-soc"
61
+enum LSM303DLHCMagReg {
59
+OBJECT_DECLARE_SIMPLE_TYPE(STM32F100State, STM32F100_SOC)
62
+ LSM303DLHC_MAG_REG_CRA = 0x00,
60
+
63
+ LSM303DLHC_MAG_REG_CRB = 0x01,
61
+#define STM_NUM_USARTS 3
64
+ LSM303DLHC_MAG_REG_MR = 0x02,
62
+#define STM_NUM_SPIS 2
65
+ LSM303DLHC_MAG_REG_OUT_X_H = 0x03,
63
+
66
+ LSM303DLHC_MAG_REG_OUT_X_L = 0x04,
64
+#define FLASH_BASE_ADDRESS 0x08000000
67
+ LSM303DLHC_MAG_REG_OUT_Z_H = 0x05,
65
+#define FLASH_SIZE (128 * 1024)
68
+ LSM303DLHC_MAG_REG_OUT_Z_L = 0x06,
66
+#define SRAM_BASE_ADDRESS 0x20000000
69
+ LSM303DLHC_MAG_REG_OUT_Y_H = 0x07,
67
+#define SRAM_SIZE (8 * 1024)
70
+ LSM303DLHC_MAG_REG_OUT_Y_L = 0x08,
68
+
71
+ LSM303DLHC_MAG_REG_SR = 0x09,
69
+struct STM32F100State {
72
+ LSM303DLHC_MAG_REG_IRA = 0x0A,
70
+ /*< private >*/
73
+ LSM303DLHC_MAG_REG_IRB = 0x0B,
71
+ SysBusDevice parent_obj;
74
+ LSM303DLHC_MAG_REG_IRC = 0x0C,
72
+
75
+ LSM303DLHC_MAG_REG_TEMP_OUT_H = 0x31,
73
+ /*< public >*/
76
+ LSM303DLHC_MAG_REG_TEMP_OUT_L = 0x32
74
+ char *cpu_type;
75
+
76
+ ARMv7MState armv7m;
77
+
78
+ STM32F2XXUsartState usart[STM_NUM_USARTS];
79
+ STM32F2XXSPIState spi[STM_NUM_SPIS];
80
+};
77
+};
81
+
78
+
82
+#endif
79
+typedef struct LSM303DLHCMagState {
83
diff --git a/hw/arm/stm32f100_soc.c b/hw/arm/stm32f100_soc.c
80
+ I2CSlave parent_obj;
81
+ uint8_t cra;
82
+ uint8_t crb;
83
+ uint8_t mr;
84
+ int16_t x;
85
+ int16_t z;
86
+ int16_t y;
87
+ int16_t x_lock;
88
+ int16_t z_lock;
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;
96
+ uint8_t len;
97
+ uint8_t buf;
98
+ uint8_t pointer;
99
+} LSM303DLHCMagState;
100
+
101
+#define TYPE_LSM303DLHC_MAG "lsm303dlhc_mag"
102
+OBJECT_DECLARE_SIMPLE_TYPE(LSM303DLHCMagState, LSM303DLHC_MAG)
103
+
104
+/*
105
+ * Conversion factor from Gauss to sensor values for each GN gain setting,
106
+ * in units "lsb per Gauss" (see data sheet table 3). There is no documented
107
+ * behaviour if the GN setting in CRB is incorrectly set to 0b000;
108
+ * we arbitrarily make it the same as 0b001.
109
+ */
110
+uint32_t xy_gain[] = { 1100, 1100, 855, 670, 450, 400, 330, 230 };
111
+uint32_t z_gain[] = { 980, 980, 760, 600, 400, 355, 295, 205 };
112
+
113
+static void lsm303dlhc_mag_get_x(Object *obj, Visitor *v, const char *name,
114
+ void *opaque, Error **errp)
115
+{
116
+ LSM303DLHCMagState *s = LSM303DLHC_MAG(obj);
117
+ int gm = extract32(s->crb, 5, 3);
118
+
119
+ /* Convert to uT where 1000 = 1 uT. Conversion factor depends on gain. */
120
+ int64_t value = muldiv64(s->x, 100000, xy_gain[gm]);
121
+ visit_type_int(v, name, &value, errp);
122
+}
123
+
124
+static void lsm303dlhc_mag_get_y(Object *obj, Visitor *v, const char *name,
125
+ void *opaque, Error **errp)
126
+{
127
+ LSM303DLHCMagState *s = LSM303DLHC_MAG(obj);
128
+ int gm = extract32(s->crb, 5, 3);
129
+
130
+ /* Convert to uT where 1000 = 1 uT. Conversion factor depends on gain. */
131
+ int64_t value = muldiv64(s->y, 100000, xy_gain[gm]);
132
+ visit_type_int(v, name, &value, errp);
133
+}
134
+
135
+static void lsm303dlhc_mag_get_z(Object *obj, Visitor *v, const char *name,
136
+ void *opaque, Error **errp)
137
+{
138
+ LSM303DLHCMagState *s = LSM303DLHC_MAG(obj);
139
+ int gm = extract32(s->crb, 5, 3);
140
+
141
+ /* Convert to uT where 1000 = 1 uT. Conversion factor depends on gain. */
142
+ int64_t value = muldiv64(s->z, 100000, z_gain[gm]);
143
+ visit_type_int(v, name, &value, errp);
144
+}
145
+
146
+static void lsm303dlhc_mag_set_x(Object *obj, Visitor *v, const char *name,
147
+ void *opaque, Error **errp)
148
+{
149
+ LSM303DLHCMagState *s = LSM303DLHC_MAG(obj);
150
+ int64_t value;
151
+ int64_t reg;
152
+ int gm = extract32(s->crb, 5, 3);
153
+
154
+ if (!visit_type_int(v, name, &value, errp)) {
155
+ return;
156
+ }
157
+
158
+ reg = muldiv64(value, xy_gain[gm], 100000);
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);
163
+ return;
164
+ }
165
+
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;
227
+
228
+ visit_type_int(v, name, &value, errp);
229
+}
230
+
231
+/*
232
+ * Set handler for the temperature property.
233
+ */
234
+static void lsm303dlhc_mag_set_temperature(Object *obj, Visitor *v,
235
+ const char *name, void *opaque,
236
+ Error **errp)
237
+{
238
+ LSM303DLHCMagState *s = LSM303DLHC_MAG(obj);
239
+ int64_t value;
240
+
241
+ if (!visit_type_int(v, name, &value, errp)) {
242
+ return;
243
+ }
244
+
245
+ /* Input temperature is in 0.001 C units. Convert to 1 lsb = 0.125 C. */
246
+ value /= 125;
247
+
248
+ if (value > 2047 || value < -2048) {
249
+ error_setg(errp, "value %" PRId64 " lsb is out of range", value);
250
+ return;
251
+ }
252
+
253
+ s->temperature = (int16_t)value;
254
+}
255
+
256
+/*
257
+ * Callback handler whenever a 'I2C_START_RECV' (read) event is received.
258
+ */
259
+static void lsm303dlhc_mag_read(LSM303DLHCMagState *s)
260
+{
261
+ /*
262
+ * Set the LOCK bit whenever a new read attempt is made. This will be
263
+ * cleared in I2C_FINISH. Note that DRDY is always set to 1 in this driver.
264
+ */
265
+ s->sr = 0x3;
266
+
267
+ /*
268
+ * Copy the current X/Y/Z and temp. values into the locked registers so
269
+ * that 'mag-x', 'mag-y', 'mag-z' and 'temperature' can continue to be
270
+ * updated via QOM, etc., without corrupting the current read event.
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
+{
295
+ switch (s->pointer) {
296
+ case LSM303DLHC_MAG_REG_CRA:
297
+ s->cra = s->buf;
298
+ break;
299
+ case LSM303DLHC_MAG_REG_CRB:
300
+ /* Make sure gain is at least 1, falling back to 1 on an error. */
301
+ if (s->buf >> 5 == 0) {
302
+ s->buf = 1 << 5;
303
+ }
304
+ s->crb = s->buf;
305
+ break;
306
+ case LSM303DLHC_MAG_REG_MR:
307
+ s->mr = s->buf;
308
+ break;
309
+ case LSM303DLHC_MAG_REG_SR:
310
+ s->sr = s->buf;
311
+ break;
312
+ case LSM303DLHC_MAG_REG_IRA:
313
+ s->ira = s->buf;
314
+ break;
315
+ case LSM303DLHC_MAG_REG_IRB:
316
+ s->irb = s->buf;
317
+ break;
318
+ case LSM303DLHC_MAG_REG_IRC:
319
+ s->irc = s->buf;
320
+ break;
321
+ default:
322
+ qemu_log_mask(LOG_GUEST_ERROR, "reg is read-only: 0x%02X", s->buf);
323
+ break;
324
+ }
325
+}
326
+
327
+/*
328
+ * Low-level master-to-slave transaction handler.
329
+ */
330
+static int lsm303dlhc_mag_send(I2CSlave *i2c, uint8_t data)
331
+{
332
+ LSM303DLHCMagState *s = LSM303DLHC_MAG(i2c);
333
+
334
+ if (s->len == 0) {
335
+ /* First byte is the reg pointer */
336
+ s->pointer = data;
337
+ s->len++;
338
+ } else if (s->len == 1) {
339
+ /* Second byte is the new register value. */
340
+ s->buf = data;
341
+ lsm303dlhc_mag_write(s);
342
+ } else {
343
+ g_assert_not_reached();
344
+ }
345
+
346
+ return 0;
347
+}
348
+
349
+/*
350
+ * Low-level slave-to-master transaction handler (read attempts).
351
+ */
352
+static uint8_t lsm303dlhc_mag_recv(I2CSlave *i2c)
353
+{
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;
458
+ }
459
+
460
+ s->len = 0;
461
+ return 0;
462
+}
463
+
464
+/*
465
+ * Device data description using VMSTATE macros.
466
+ */
467
+static const VMStateDescription vmstate_lsm303dlhc_mag = {
468
+ .name = "LSM303DLHC_MAG",
469
+ .version_id = 0,
470
+ .minimum_version_id = 0,
471
+ .fields = (VMStateField[]) {
472
+
473
+ VMSTATE_I2C_SLAVE(parent_obj, LSM303DLHCMagState),
474
+ VMSTATE_UINT8(len, LSM303DLHCMagState),
475
+ VMSTATE_UINT8(buf, LSM303DLHCMagState),
476
+ VMSTATE_UINT8(pointer, LSM303DLHCMagState),
477
+ VMSTATE_UINT8(cra, LSM303DLHCMagState),
478
+ VMSTATE_UINT8(crb, LSM303DLHCMagState),
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),
492
+ VMSTATE_END_OF_LIST()
493
+ }
494
+};
495
+
496
+/*
497
+ * Put the device into post-reset default state.
498
+ */
499
+static void lsm303dlhc_mag_default_cfg(LSM303DLHCMagState *s)
500
+{
501
+ /* Set the device into is default reset state. */
502
+ s->len = 0;
503
+ s->pointer = 0; /* Current register. */
504
+ s->buf = 0; /* Shared buffer. */
505
+ s->cra = 0x10; /* Temp Enabled = 0, Data Rate = 15.0 Hz. */
506
+ s->crb = 0x20; /* Gain = +/- 1.3 Gauss. */
507
+ s->mr = 0x3; /* Operating Mode = Sleep. */
508
+ s->x = 0;
509
+ s->z = 0;
510
+ s->y = 0;
511
+ s->x_lock = 0;
512
+ s->z_lock = 0;
513
+ s->y_lock = 0;
514
+ s->sr = 0x1; /* DRDY = 1. */
515
+ s->ira = 0x48;
516
+ s->irb = 0x34;
517
+ s->irc = 0x33;
518
+ s->temperature = 0; /* Default to 0 degrees C (0/8 lsb = 0 C). */
519
+ s->temperature_lock = 0;
520
+}
521
+
522
+/*
523
+ * Callback handler when DeviceState 'reset' is set to true.
524
+ */
525
+static void lsm303dlhc_mag_reset(DeviceState *dev)
526
+{
527
+ I2CSlave *i2c = I2C_SLAVE(dev);
528
+ LSM303DLHCMagState *s = LSM303DLHC_MAG(i2c);
529
+
530
+ /* Set the device into its default reset state. */
531
+ lsm303dlhc_mag_default_cfg(s);
532
+}
533
+
534
+/*
535
+ * Initialisation of any public properties.
536
+ */
537
+static void lsm303dlhc_mag_initfn(Object *obj)
538
+{
539
+ object_property_add(obj, "mag-x", "int",
540
+ lsm303dlhc_mag_get_x,
541
+ lsm303dlhc_mag_set_x, NULL, NULL);
542
+
543
+ object_property_add(obj, "mag-y", "int",
544
+ lsm303dlhc_mag_get_y,
545
+ lsm303dlhc_mag_set_y, NULL, NULL);
546
+
547
+ object_property_add(obj, "mag-z", "int",
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)
560
+{
561
+ DeviceClass *dc = DEVICE_CLASS(klass);
562
+ I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
563
+
564
+ dc->reset = lsm303dlhc_mag_reset;
565
+ dc->vmsd = &vmstate_lsm303dlhc_mag;
566
+ k->event = lsm303dlhc_mag_event;
567
+ k->recv = lsm303dlhc_mag_recv;
568
+ k->send = lsm303dlhc_mag_send;
569
+}
570
+
571
+static const TypeInfo lsm303dlhc_mag_info = {
572
+ .name = TYPE_LSM303DLHC_MAG,
573
+ .parent = TYPE_I2C_SLAVE,
574
+ .instance_size = sizeof(LSM303DLHCMagState),
575
+ .instance_init = lsm303dlhc_mag_initfn,
576
+ .class_init = lsm303dlhc_mag_class_init,
577
+};
578
+
579
+static void lsm303dlhc_mag_register_types(void)
580
+{
581
+ type_register_static(&lsm303dlhc_mag_info);
582
+}
583
+
584
+type_init(lsm303dlhc_mag_register_types)
585
diff --git a/tests/qtest/lsm303dlhc-mag-test.c b/tests/qtest/lsm303dlhc-mag-test.c
84
new file mode 100644
586
new file mode 100644
85
index XXXXXXX..XXXXXXX
587
index XXXXXXX..XXXXXXX
86
--- /dev/null
588
--- /dev/null
87
+++ b/hw/arm/stm32f100_soc.c
589
+++ b/tests/qtest/lsm303dlhc-mag-test.c
88
@@ -XXX,XX +XXX,XX @@
590
@@ -XXX,XX +XXX,XX @@
89
+/*
591
+/*
90
+ * STM32F100 SoC
592
+ * QTest testcase for the LSM303DLHC I2C magnetometer
91
+ *
593
+ *
92
+ * Copyright (c) 2021 Alexandre Iooss <erdnaxe@crans.org>
594
+ * Copyright (C) 2021 Linaro Ltd.
93
+ * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
595
+ * Written by Kevin Townsend <kevin.townsend@linaro.org>
94
+ *
596
+ *
95
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
597
+ * Based on: https://www.st.com/resource/en/datasheet/lsm303dlhc.pdf
96
+ * of this software and associated documentation files (the "Software"), to deal
97
+ * in the Software without restriction, including without limitation the rights
98
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
99
+ * copies of the Software, and to permit persons to whom the Software is
100
+ * furnished to do so, subject to the following conditions:
101
+ *
598
+ *
102
+ * The above copyright notice and this permission notice shall be included in
599
+ * SPDX-License-Identifier: GPL-2.0-or-later
103
+ * all copies or substantial portions of the Software.
104
+ *
105
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
106
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
107
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
108
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
109
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
110
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
111
+ * THE SOFTWARE.
112
+ */
600
+ */
113
+
601
+
114
+#include "qemu/osdep.h"
602
+#include "qemu/osdep.h"
115
+#include "qapi/error.h"
603
+#include "libqtest-single.h"
116
+#include "qemu/module.h"
604
+#include "libqos/qgraph.h"
117
+#include "hw/arm/boot.h"
605
+#include "libqos/i2c.h"
118
+#include "exec/address-spaces.h"
606
+#include "qapi/qmp/qdict.h"
119
+#include "hw/arm/stm32f100_soc.h"
607
+
120
+#include "hw/qdev-properties.h"
608
+#define LSM303DLHC_MAG_TEST_ID "lsm303dlhc_mag-test"
121
+#include "hw/misc/unimp.h"
609
+#define LSM303DLHC_MAG_REG_CRA 0x00
122
+#include "sysemu/sysemu.h"
610
+#define LSM303DLHC_MAG_REG_CRB 0x01
123
+
611
+#define LSM303DLHC_MAG_REG_OUT_X_H 0x03
124
+/* stm32f100_soc implementation is derived from stm32f205_soc */
612
+#define LSM303DLHC_MAG_REG_OUT_Z_H 0x05
125
+
613
+#define LSM303DLHC_MAG_REG_OUT_Y_H 0x07
126
+static const uint32_t usart_addr[STM_NUM_USARTS] = { 0x40013800, 0x40004400,
614
+#define LSM303DLHC_MAG_REG_IRC 0x0C
127
+ 0x40004800 };
615
+#define LSM303DLHC_MAG_REG_TEMP_OUT_H 0x31
128
+static const uint32_t spi_addr[STM_NUM_SPIS] = { 0x40013000, 0x40003800 };
616
+
129
+
617
+static int qmp_lsm303dlhc_mag_get_property(const char *id, const char *prop)
130
+static const int usart_irq[STM_NUM_USARTS] = {37, 38, 39};
618
+{
131
+static const int spi_irq[STM_NUM_SPIS] = {35, 36};
619
+ QDict *response;
132
+
620
+ int ret;
133
+static void stm32f100_soc_initfn(Object *obj)
621
+
134
+{
622
+ response = qmp("{ 'execute': 'qom-get', 'arguments': { 'path': %s, "
135
+ STM32F100State *s = STM32F100_SOC(obj);
623
+ "'property': %s } }", id, prop);
136
+ int i;
624
+ g_assert(qdict_haskey(response, "return"));
137
+
625
+ ret = qdict_get_int(response, "return");
138
+ object_initialize_child(obj, "armv7m", &s->armv7m, TYPE_ARMV7M);
626
+ qobject_unref(response);
139
+
627
+ return ret;
140
+ for (i = 0; i < STM_NUM_USARTS; i++) {
628
+}
141
+ object_initialize_child(obj, "usart[*]", &s->usart[i],
629
+
142
+ TYPE_STM32F2XX_USART);
630
+static void qmp_lsm303dlhc_mag_set_property(const char *id, const char *prop,
143
+ }
631
+ int value)
144
+
632
+{
145
+ for (i = 0; i < STM_NUM_SPIS; i++) {
633
+ QDict *response;
146
+ object_initialize_child(obj, "spi[*]", &s->spi[i], TYPE_STM32F2XX_SPI);
634
+
147
+ }
635
+ response = qmp("{ 'execute': 'qom-set', 'arguments': { 'path': %s, "
148
+}
636
+ "'property': %s, 'value': %d } }", id, prop, value);
149
+
637
+ g_assert(qdict_haskey(response, "return"));
150
+static void stm32f100_soc_realize(DeviceState *dev_soc, Error **errp)
638
+ qobject_unref(response);
151
+{
639
+}
152
+ STM32F100State *s = STM32F100_SOC(dev_soc);
640
+
153
+ DeviceState *dev, *armv7m;
641
+static void send_and_receive(void *obj, void *data, QGuestAllocator *alloc)
154
+ SysBusDevice *busdev;
642
+{
155
+ int i;
643
+ int64_t value;
156
+
644
+ QI2CDevice *i2cdev = (QI2CDevice *)obj;
157
+ MemoryRegion *system_memory = get_system_memory();
645
+
158
+ MemoryRegion *sram = g_new(MemoryRegion, 1);
646
+ /* Check default value for CRB */
159
+ MemoryRegion *flash = g_new(MemoryRegion, 1);
647
+ g_assert_cmphex(i2c_get8(i2cdev, LSM303DLHC_MAG_REG_CRB), ==, 0x20);
160
+ MemoryRegion *flash_alias = g_new(MemoryRegion, 1);
648
+
161
+
649
+ /* Set x to 1.0 gauss and verify the value */
162
+ /*
650
+ qmp_lsm303dlhc_mag_set_property(LSM303DLHC_MAG_TEST_ID, "mag-x", 100000);
163
+ * Init flash region
651
+ value = qmp_lsm303dlhc_mag_get_property(
164
+ * Flash starts at 0x08000000 and then is aliased to boot memory at 0x0
652
+ LSM303DLHC_MAG_TEST_ID, "mag-x");
165
+ */
653
+ g_assert_cmpint(value, ==, 100000);
166
+ memory_region_init_rom(flash, OBJECT(dev_soc), "STM32F100.flash",
654
+
167
+ FLASH_SIZE, &error_fatal);
655
+ /* Set y to 1.5 gauss and verify the value */
168
+ memory_region_init_alias(flash_alias, OBJECT(dev_soc),
656
+ qmp_lsm303dlhc_mag_set_property(LSM303DLHC_MAG_TEST_ID, "mag-y", 150000);
169
+ "STM32F100.flash.alias", flash, 0, FLASH_SIZE);
657
+ value = qmp_lsm303dlhc_mag_get_property(
170
+ memory_region_add_subregion(system_memory, FLASH_BASE_ADDRESS, flash);
658
+ LSM303DLHC_MAG_TEST_ID, "mag-y");
171
+ memory_region_add_subregion(system_memory, 0, flash_alias);
659
+ g_assert_cmpint(value, ==, 150000);
172
+
660
+
173
+ /* Init SRAM region */
661
+ /* Set z to 0.5 gauss and verify the value */
174
+ memory_region_init_ram(sram, NULL, "STM32F100.sram", SRAM_SIZE,
662
+ qmp_lsm303dlhc_mag_set_property(LSM303DLHC_MAG_TEST_ID, "mag-z", 50000);
175
+ &error_fatal);
663
+ value = qmp_lsm303dlhc_mag_get_property(
176
+ memory_region_add_subregion(system_memory, SRAM_BASE_ADDRESS, sram);
664
+ LSM303DLHC_MAG_TEST_ID, "mag-z");
177
+
665
+ g_assert_cmpint(value, ==, 50000);
178
+ /* Init ARMv7m */
666
+
179
+ armv7m = DEVICE(&s->armv7m);
667
+ /* Set temperature to 23.6 C and verify the value */
180
+ qdev_prop_set_uint32(armv7m, "num-irq", 61);
668
+ qmp_lsm303dlhc_mag_set_property(LSM303DLHC_MAG_TEST_ID,
181
+ qdev_prop_set_string(armv7m, "cpu-type", s->cpu_type);
669
+ "temperature", 23600);
182
+ qdev_prop_set_bit(armv7m, "enable-bitband", true);
670
+ value = qmp_lsm303dlhc_mag_get_property(
183
+ object_property_set_link(OBJECT(&s->armv7m), "memory",
671
+ LSM303DLHC_MAG_TEST_ID, "temperature");
184
+ OBJECT(get_system_memory()), &error_abort);
672
+ /* Should return 23.5 C due to 0.125°C steps. */
185
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), errp)) {
673
+ g_assert_cmpint(value, ==, 23500);
186
+ return;
674
+
187
+ }
675
+ /* Read raw x axis registers (1 gauss = 1100 at +/-1.3 g gain) */
188
+
676
+ value = i2c_get16(i2cdev, LSM303DLHC_MAG_REG_OUT_X_H);
189
+ /* Attach UART (uses USART registers) and USART controllers */
677
+ g_assert_cmphex(value, ==, 1100);
190
+ for (i = 0; i < STM_NUM_USARTS; i++) {
678
+
191
+ dev = DEVICE(&(s->usart[i]));
679
+ /* Read raw y axis registers (1.5 gauss = 1650 at +/- 1.3 g gain = ) */
192
+ qdev_prop_set_chr(dev, "chardev", serial_hd(i));
680
+ value = i2c_get16(i2cdev, LSM303DLHC_MAG_REG_OUT_Y_H);
193
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->usart[i]), errp)) {
681
+ g_assert_cmphex(value, ==, 1650);
194
+ return;
682
+
195
+ }
683
+ /* Read raw z axis registers (0.5 gauss = 490 at +/- 1.3 g gain = ) */
196
+ busdev = SYS_BUS_DEVICE(dev);
684
+ value = i2c_get16(i2cdev, LSM303DLHC_MAG_REG_OUT_Z_H);
197
+ sysbus_mmio_map(busdev, 0, usart_addr[i]);
685
+ g_assert_cmphex(value, ==, 490);
198
+ sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, usart_irq[i]));
686
+
199
+ }
687
+ /* Read raw temperature registers with temp disabled (CRA = 0x10) */
200
+
688
+ value = i2c_get16(i2cdev, LSM303DLHC_MAG_REG_TEMP_OUT_H);
201
+ /* SPI 1 and 2 */
689
+ g_assert_cmphex(value, ==, 0);
202
+ for (i = 0; i < STM_NUM_SPIS; i++) {
690
+
203
+ dev = DEVICE(&(s->spi[i]));
691
+ /* Enable temperature reads (CRA = 0x90) */
204
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), errp)) {
692
+ i2c_set8(i2cdev, LSM303DLHC_MAG_REG_CRA, 0x90);
205
+ return;
693
+
206
+ }
694
+ /* Read raw temp registers (23.5 C = 188 at 1 lsb = 0.125 C) */
207
+ busdev = SYS_BUS_DEVICE(dev);
695
+ value = i2c_get16(i2cdev, LSM303DLHC_MAG_REG_TEMP_OUT_H);
208
+ sysbus_mmio_map(busdev, 0, spi_addr[i]);
696
+ g_assert_cmphex(value, ==, 188);
209
+ sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, spi_irq[i]));
697
+}
210
+ }
698
+
211
+
699
+static void reg_wraparound(void *obj, void *data, QGuestAllocator *alloc)
212
+ create_unimplemented_device("timer[2]", 0x40000000, 0x400);
700
+{
213
+ create_unimplemented_device("timer[3]", 0x40000400, 0x400);
701
+ uint8_t value[4];
214
+ create_unimplemented_device("timer[4]", 0x40000800, 0x400);
702
+ QI2CDevice *i2cdev = (QI2CDevice *)obj;
215
+ create_unimplemented_device("timer[6]", 0x40001000, 0x400);
703
+
216
+ create_unimplemented_device("timer[7]", 0x40001400, 0x400);
704
+ /* Set x to 1.0 gauss, and y to 1.5 gauss for known test values */
217
+ create_unimplemented_device("RTC", 0x40002800, 0x400);
705
+ qmp_lsm303dlhc_mag_set_property(LSM303DLHC_MAG_TEST_ID, "mag-x", 100000);
218
+ create_unimplemented_device("WWDG", 0x40002C00, 0x400);
706
+ qmp_lsm303dlhc_mag_set_property(LSM303DLHC_MAG_TEST_ID, "mag-y", 150000);
219
+ create_unimplemented_device("IWDG", 0x40003000, 0x400);
707
+
220
+ create_unimplemented_device("I2C1", 0x40005400, 0x400);
708
+ /* Check that requesting 4 bytes starting at Y_H wraps around to X_L */
221
+ create_unimplemented_device("I2C2", 0x40005800, 0x400);
709
+ i2c_read_block(i2cdev, LSM303DLHC_MAG_REG_OUT_Y_H, value, 4);
222
+ create_unimplemented_device("BKP", 0x40006C00, 0x400);
710
+ /* 1.5 gauss = 1650 lsb = 0x672 */
223
+ create_unimplemented_device("PWR", 0x40007000, 0x400);
711
+ g_assert_cmphex(value[0], ==, 0x06);
224
+ create_unimplemented_device("DAC", 0x40007400, 0x400);
712
+ g_assert_cmphex(value[1], ==, 0x72);
225
+ create_unimplemented_device("CEC", 0x40007800, 0x400);
713
+ /* 1.0 gauss = 1100 lsb = 0x44C */
226
+ create_unimplemented_device("AFIO", 0x40010000, 0x400);
714
+ g_assert_cmphex(value[2], ==, 0x04);
227
+ create_unimplemented_device("EXTI", 0x40010400, 0x400);
715
+ g_assert_cmphex(value[3], ==, 0x4C);
228
+ create_unimplemented_device("GPIOA", 0x40010800, 0x400);
716
+
229
+ create_unimplemented_device("GPIOB", 0x40010C00, 0x400);
717
+ /* Check that requesting LSM303DLHC_MAG_REG_IRC wraps around to CRA */
230
+ create_unimplemented_device("GPIOC", 0x40011000, 0x400);
718
+ i2c_read_block(i2cdev, LSM303DLHC_MAG_REG_IRC, value, 2);
231
+ create_unimplemented_device("GPIOD", 0x40011400, 0x400);
719
+ /* Default value for IRC = 0x33 */
232
+ create_unimplemented_device("GPIOE", 0x40011800, 0x400);
720
+ g_assert_cmphex(value[0], ==, 0x33);
233
+ create_unimplemented_device("ADC1", 0x40012400, 0x400);
721
+ /* Default value for CRA = 0x10 */
234
+ create_unimplemented_device("timer[1]", 0x40012C00, 0x400);
722
+ g_assert_cmphex(value[1], ==, 0x10);
235
+ create_unimplemented_device("timer[15]", 0x40014000, 0x400);
723
+}
236
+ create_unimplemented_device("timer[16]", 0x40014400, 0x400);
724
+
237
+ create_unimplemented_device("timer[17]", 0x40014800, 0x400);
725
+static void lsm303dlhc_mag_register_nodes(void)
238
+ create_unimplemented_device("DMA", 0x40020000, 0x400);
726
+{
239
+ create_unimplemented_device("RCC", 0x40021000, 0x400);
727
+ QOSGraphEdgeOptions opts = {
240
+ create_unimplemented_device("Flash Int", 0x40022000, 0x400);
728
+ .extra_device_opts = "id=" LSM303DLHC_MAG_TEST_ID ",address=0x1e"
241
+ create_unimplemented_device("CRC", 0x40023000, 0x400);
729
+ };
242
+}
730
+ add_qi2c_address(&opts, &(QI2CAddress) { 0x1E });
243
+
731
+
244
+static Property stm32f100_soc_properties[] = {
732
+ qos_node_create_driver("lsm303dlhc_mag", i2c_device_create);
245
+ DEFINE_PROP_STRING("cpu-type", STM32F100State, cpu_type),
733
+ qos_node_consumes("lsm303dlhc_mag", "i2c-bus", &opts);
246
+ DEFINE_PROP_END_OF_LIST(),
734
+
247
+};
735
+ qos_add_test("tx-rx", "lsm303dlhc_mag", send_and_receive, NULL);
248
+
736
+ qos_add_test("regwrap", "lsm303dlhc_mag", reg_wraparound, NULL);
249
+static void stm32f100_soc_class_init(ObjectClass *klass, void *data)
737
+}
250
+{
738
+libqos_init(lsm303dlhc_mag_register_nodes);
251
+ DeviceClass *dc = DEVICE_CLASS(klass);
739
diff --git a/hw/sensor/Kconfig b/hw/sensor/Kconfig
252
+
253
+ dc->realize = stm32f100_soc_realize;
254
+ device_class_set_props(dc, stm32f100_soc_properties);
255
+}
256
+
257
+static const TypeInfo stm32f100_soc_info = {
258
+ .name = TYPE_STM32F100_SOC,
259
+ .parent = TYPE_SYS_BUS_DEVICE,
260
+ .instance_size = sizeof(STM32F100State),
261
+ .instance_init = stm32f100_soc_initfn,
262
+ .class_init = stm32f100_soc_class_init,
263
+};
264
+
265
+static void stm32f100_soc_types(void)
266
+{
267
+ type_register_static(&stm32f100_soc_info);
268
+}
269
+
270
+type_init(stm32f100_soc_types)
271
diff --git a/MAINTAINERS b/MAINTAINERS
272
index XXXXXXX..XXXXXXX 100644
740
index XXXXXXX..XXXXXXX 100644
273
--- a/MAINTAINERS
741
--- a/hw/sensor/Kconfig
274
+++ b/MAINTAINERS
742
+++ b/hw/sensor/Kconfig
275
@@ -XXX,XX +XXX,XX @@ L: qemu-arm@nongnu.org
743
@@ -XXX,XX +XXX,XX @@ config ADM1272
276
S: Maintained
744
config MAX34451
277
F: hw/arm/virt-acpi-build.c
745
bool
278
746
depends on I2C
279
+STM32F100
747
+
280
+M: Alexandre Iooss <erdnaxe@crans.org>
748
+config LSM303DLHC_MAG
281
+L: qemu-arm@nongnu.org
749
+ bool
282
+S: Maintained
750
+ depends on I2C
283
+F: hw/arm/stm32f100_soc.c
751
diff --git a/hw/sensor/meson.build b/hw/sensor/meson.build
284
+
285
STM32F205
286
M: Alistair Francis <alistair@alistair23.me>
287
M: Peter Maydell <peter.maydell@linaro.org>
288
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
289
index XXXXXXX..XXXXXXX 100644
752
index XXXXXXX..XXXXXXX 100644
290
--- a/hw/arm/Kconfig
753
--- a/hw/sensor/meson.build
291
+++ b/hw/arm/Kconfig
754
+++ b/hw/sensor/meson.build
292
@@ -XXX,XX +XXX,XX @@ config RASPI
755
@@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_DPS310', if_true: files('dps310.c'))
293
select SDHCI
756
softmmu_ss.add(when: 'CONFIG_EMC141X', if_true: files('emc141x.c'))
294
select USB_DWC2
757
softmmu_ss.add(when: 'CONFIG_ADM1272', if_true: files('adm1272.c'))
295
758
softmmu_ss.add(when: 'CONFIG_MAX34451', if_true: files('max34451.c'))
296
+config STM32F100_SOC
759
+softmmu_ss.add(when: 'CONFIG_LSM303DLHC_MAG', if_true: files('lsm303dlhc_mag.c'))
297
+ bool
760
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
298
+ select ARM_V7M
299
+ select STM32F2XX_USART
300
+ select STM32F2XX_SPI
301
+
302
config STM32F205_SOC
303
bool
304
select ARM_V7M
305
diff --git a/hw/arm/meson.build b/hw/arm/meson.build
306
index XXXXXXX..XXXXXXX 100644
761
index XXXXXXX..XXXXXXX 100644
307
--- a/hw/arm/meson.build
762
--- a/tests/qtest/meson.build
308
+++ b/hw/arm/meson.build
763
+++ b/tests/qtest/meson.build
309
@@ -XXX,XX +XXX,XX @@ arm_ss.add(when: 'CONFIG_STRONGARM', if_true: files('strongarm.c'))
764
@@ -XXX,XX +XXX,XX @@ qos_test_ss.add(
310
arm_ss.add(when: 'CONFIG_ALLWINNER_A10', if_true: files('allwinner-a10.c', 'cubieboard.c'))
765
'eepro100-test.c',
311
arm_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-h3.c', 'orangepi.c'))
766
'es1370-test.c',
312
arm_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_peripherals.c', 'bcm2836.c', 'raspi.c'))
767
'ipoctal232-test.c',
313
+arm_ss.add(when: 'CONFIG_STM32F100_SOC', if_true: files('stm32f100_soc.c'))
768
+ 'lsm303dlhc-mag-test.c',
314
arm_ss.add(when: 'CONFIG_STM32F205_SOC', if_true: files('stm32f205_soc.c'))
769
'max34451-test.c',
315
arm_ss.add(when: 'CONFIG_STM32F405_SOC', if_true: files('stm32f405_soc.c'))
770
'megasas-test.c',
316
arm_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx-zynqmp.c', 'xlnx-zcu102.c'))
771
'ne2000-test.c',
317
--
772
--
318
2.20.1
773
2.25.1
319
774
320
775
diff view generated by jsdifflib