1
arm queue: big stuff here is my MVE codegen optimisation,
1
The following changes since commit 8f6330a807f2642dc2a3cdf33347aa28a4c00a87:
2
and Alex's Apple Silicon hvf support.
3
2
4
-- PMM
3
Merge tag 'pull-maintainer-updates-060324-1' of https://gitlab.com/stsquad/qemu into staging (2024-03-06 16:56:20 +0000)
5
6
The following changes since commit 7adb961995a3744f51396502b33ad04a56a317c3:
7
8
Merge remote-tracking branch 'remotes/dgilbert-gitlab/tags/pull-virtiofs-20210916' into staging (2021-09-19 18:53:29 +0100)
9
4
10
are available in the Git repository at:
5
are available in the Git repository at:
11
6
12
https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20210920
7
https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20240308
13
8
14
for you to fetch changes up to 1dc5a60bfe406bc1122d68cbdefda38d23134b27:
9
for you to fetch changes up to bbf6c6dbead82292a20951eb1204442a6b838de9:
15
10
16
target/arm: Optimize MVE 1op-immediate insns (2021-09-20 14:18:01 +0100)
11
target/arm: Move v7m-related code from cpu32.c into a separate file (2024-03-08 14:45:03 +0000)
17
12
18
----------------------------------------------------------------
13
----------------------------------------------------------------
19
target-arm queue:
14
target-arm queue:
20
* Optimize codegen for MVE when predication not active
15
* Implement FEAT_ECV
21
* hvf: Add Apple Silicon support
16
* STM32L4x5: Implement GPIO device
22
* hw/intc: Set GIC maintenance interrupt level to only 0 or 1
17
* Fix 32-bit SMOPA
23
* Fix mishandling of MVE FPSCR.LTPSIZE reset for usermode emulator
18
* Refactor v7m related code from cpu32.c into its own file
24
* elf2dmp: Fix coverity nits
19
* hw/rtc/sun4v-rtc: Relicense to GPLv2-or-later
25
20
26
----------------------------------------------------------------
21
----------------------------------------------------------------
27
Alexander Graf (7):
22
Inès Varhol (3):
28
arm: Move PMC register definitions to internals.h
23
hw/gpio: Implement STM32L4x5 GPIO
29
hvf: Add execute to dirty log permission bitmap
24
hw/arm: Connect STM32L4x5 GPIO to STM32L4x5 SoC
30
hvf: Introduce hvf_arch_init() callback
25
tests/qtest: Add STM32L4x5 GPIO QTest testcase
31
hvf: Add Apple Silicon support
32
hvf: arm: Implement PSCI handling
33
arm: Add Hypervisor.framework build target
34
hvf: arm: Add rudimentary PMC support
35
26
36
Peter Collingbourne (1):
27
Peter Maydell (9):
37
arm/hvf: Add a WFI handler
28
target/arm: Move some register related defines to internals.h
29
target/arm: Timer _EL02 registers UNDEF for E2H == 0
30
target/arm: use FIELD macro for CNTHCTL bit definitions
31
target/arm: Don't allow RES0 CNTHCTL_EL2 bits to be written
32
target/arm: Implement new FEAT_ECV trap bits
33
target/arm: Define CNTPCTSS_EL0 and CNTVCTSS_EL0
34
target/arm: Implement FEAT_ECV CNTPOFF_EL2 handling
35
target/arm: Enable FEAT_ECV for 'max' CPU
36
hw/rtc/sun4v-rtc: Relicense to GPLv2-or-later
38
37
39
Peter Maydell (18):
38
Richard Henderson (1):
40
elf2dmp: Check curl_easy_setopt() return value
39
target/arm: Fix 32-bit SMOPA
41
elf2dmp: Fail cleanly if PDB file specifies zero block_size
42
target/arm: Don't skip M-profile reset entirely in user mode
43
target/arm: Always clear exclusive monitor on reset
44
target/arm: Consolidate ifdef blocks in reset
45
hvf: arm: Implement -cpu host
46
target/arm: Avoid goto_tb if we're trying to exit to the main loop
47
target/arm: Enforce that FPDSCR.LTPSIZE is 4 on inbound migration
48
target/arm: Add TB flag for "MVE insns not predicated"
49
target/arm: Optimize MVE logic ops
50
target/arm: Optimize MVE arithmetic ops
51
target/arm: Optimize MVE VNEG, VABS
52
target/arm: Optimize MVE VDUP
53
target/arm: Optimize MVE VMVN
54
target/arm: Optimize MVE VSHL, VSHR immediate forms
55
target/arm: Optimize MVE VSHLL and VMOVL
56
target/arm: Optimize MVE VSLI and VSRI
57
target/arm: Optimize MVE 1op-immediate insns
58
40
59
Shashi Mallela (1):
41
Thomas Huth (1):
60
hw/intc: Set GIC maintenance interrupt level to only 0 or 1
42
target/arm: Move v7m-related code from cpu32.c into a separate file
61
43
62
meson.build | 8 +
44
MAINTAINERS | 1 +
63
include/sysemu/hvf_int.h | 12 +-
45
docs/system/arm/b-l475e-iot01a.rst | 2 +-
64
target/arm/cpu.h | 6 +-
46
docs/system/arm/emulation.rst | 1 +
65
target/arm/hvf_arm.h | 18 +
47
include/hw/arm/stm32l4x5_soc.h | 2 +
66
target/arm/internals.h | 44 ++
48
include/hw/gpio/stm32l4x5_gpio.h | 71 +++++
67
target/arm/kvm_arm.h | 2 -
49
include/hw/misc/stm32l4x5_syscfg.h | 3 +-
68
target/arm/translate.h | 2 +
50
include/hw/rtc/sun4v-rtc.h | 2 +-
69
accel/hvf/hvf-accel-ops.c | 21 +-
51
target/arm/cpu-features.h | 10 +
70
contrib/elf2dmp/download.c | 22 +-
52
target/arm/cpu.h | 129 +--------
71
contrib/elf2dmp/pdb.c | 4 +
53
target/arm/internals.h | 151 ++++++++++
72
hw/intc/arm_gicv3_cpuif.c | 5 +-
54
hw/arm/stm32l4x5_soc.c | 71 ++++-
73
target/arm/cpu.c | 56 +-
55
hw/gpio/stm32l4x5_gpio.c | 477 ++++++++++++++++++++++++++++++++
74
target/arm/helper.c | 77 ++-
56
hw/misc/stm32l4x5_syscfg.c | 1 +
75
target/arm/hvf/hvf.c | 1278 +++++++++++++++++++++++++++++++++++++++++
57
hw/rtc/sun4v-rtc.c | 2 +-
76
target/arm/machine.c | 13 +
58
target/arm/helper.c | 189 ++++++++++++-
77
target/arm/translate-m-nocp.c | 8 +-
59
target/arm/tcg/cpu-v7m.c | 290 +++++++++++++++++++
78
target/arm/translate-mve.c | 310 +++++++---
60
target/arm/tcg/cpu32.c | 261 ------------------
79
target/arm/translate-vfp.c | 33 +-
61
target/arm/tcg/cpu64.c | 1 +
80
target/arm/translate.c | 42 +-
62
target/arm/tcg/sme_helper.c | 77 +++---
81
target/i386/hvf/hvf.c | 10 +
63
tests/qtest/stm32l4x5_gpio-test.c | 551 +++++++++++++++++++++++++++++++++++++
82
MAINTAINERS | 5 +
64
tests/tcg/aarch64/sme-smopa-1.c | 47 ++++
83
target/arm/hvf/meson.build | 3 +
65
tests/tcg/aarch64/sme-smopa-2.c | 54 ++++
84
target/arm/hvf/trace-events | 11 +
66
hw/arm/Kconfig | 3 +-
85
target/arm/meson.build | 2 +
67
hw/gpio/Kconfig | 3 +
86
24 files changed, 1824 insertions(+), 168 deletions(-)
68
hw/gpio/meson.build | 1 +
87
create mode 100644 target/arm/hvf_arm.h
69
hw/gpio/trace-events | 6 +
88
create mode 100644 target/arm/hvf/hvf.c
70
target/arm/meson.build | 3 +
89
create mode 100644 target/arm/hvf/meson.build
71
target/arm/tcg/meson.build | 3 +
90
create mode 100644 target/arm/hvf/trace-events
72
target/arm/trace-events | 1 +
73
tests/qtest/meson.build | 3 +-
74
tests/tcg/aarch64/Makefile.target | 2 +-
75
31 files changed, 1962 insertions(+), 456 deletions(-)
76
create mode 100644 include/hw/gpio/stm32l4x5_gpio.h
77
create mode 100644 hw/gpio/stm32l4x5_gpio.c
78
create mode 100644 target/arm/tcg/cpu-v7m.c
79
create mode 100644 tests/qtest/stm32l4x5_gpio-test.c
80
create mode 100644 tests/tcg/aarch64/sme-smopa-1.c
81
create mode 100644 tests/tcg/aarch64/sme-smopa-2.c
91
82
diff view generated by jsdifflib
1
Optimize the MVE 1op-immediate insns (VORR, VBIC, VMOV) to
1
cpu.h has a lot of #defines relating to CPU register fields.
2
use TCG vector ops when possible.
2
Most of these aren't actually used outside target/arm code,
3
so there's no point in cluttering up the cpu.h file with them.
4
Move some easy ones to internals.h.
3
5
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20210913095440.13462-13-peter.maydell@linaro.org
9
Message-id: 20240301183219.2424889-2-peter.maydell@linaro.org
7
---
10
---
8
target/arm/translate-mve.c | 26 +++++++++++++++++++++-----
11
target/arm/cpu.h | 128 -----------------------------------------
9
1 file changed, 21 insertions(+), 5 deletions(-)
12
target/arm/internals.h | 128 +++++++++++++++++++++++++++++++++++++++++
13
2 files changed, 128 insertions(+), 128 deletions(-)
10
14
11
diff --git a/target/arm/translate-mve.c b/target/arm/translate-mve.c
15
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
12
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
13
--- a/target/arm/translate-mve.c
17
--- a/target/arm/cpu.h
14
+++ b/target/arm/translate-mve.c
18
+++ b/target/arm/cpu.h
15
@@ -XXX,XX +XXX,XX @@ static bool trans_VADDLV(DisasContext *s, arg_VADDLV *a)
19
@@ -XXX,XX +XXX,XX @@ typedef struct ARMGenericTimer {
16
return true;
20
uint64_t ctl; /* Timer Control register */
17
}
21
} ARMGenericTimer;
18
22
19
-static bool do_1imm(DisasContext *s, arg_1imm *a, MVEGenOneOpImmFn *fn)
23
-#define VTCR_NSW (1u << 29)
20
+static bool do_1imm(DisasContext *s, arg_1imm *a, MVEGenOneOpImmFn *fn,
24
-#define VTCR_NSA (1u << 30)
21
+ GVecGen2iFn *vecfn)
25
-#define VSTCR_SW VTCR_NSW
22
{
26
-#define VSTCR_SA VTCR_NSA
23
TCGv_ptr qd;
27
-
24
uint64_t imm;
28
/* Define a maximum sized vector register.
25
@@ -XXX,XX +XXX,XX @@ static bool do_1imm(DisasContext *s, arg_1imm *a, MVEGenOneOpImmFn *fn)
29
* For 32-bit, this is a 128-bit NEON/AdvSIMD register.
26
30
* For 64-bit, this is a 2048-bit SVE register.
27
imm = asimd_imm_const(a->imm, a->cmode, a->op);
31
@@ -XXX,XX +XXX,XX @@ void pmu_init(ARMCPU *cpu);
28
32
#define SCTLR_SPINTMASK (1ULL << 62) /* FEAT_NMI */
29
- qd = mve_qreg_ptr(a->qd);
33
#define SCTLR_TIDCP (1ULL << 63) /* FEAT_TIDCP1 */
30
- fn(cpu_env, qd, tcg_constant_i64(imm));
34
31
- tcg_temp_free_ptr(qd);
35
-/* Bit definitions for CPACR (AArch32 only) */
32
+ if (vecfn && mve_no_predication(s)) {
36
-FIELD(CPACR, CP10, 20, 2)
33
+ vecfn(MO_64, mve_qreg_offset(a->qd), mve_qreg_offset(a->qd),
37
-FIELD(CPACR, CP11, 22, 2)
34
+ imm, 16, 16);
38
-FIELD(CPACR, TRCDIS, 28, 1) /* matches CPACR_EL1.TTA */
35
+ } else {
39
-FIELD(CPACR, D32DIS, 30, 1) /* up to v7; RAZ in v8 */
36
+ qd = mve_qreg_ptr(a->qd);
40
-FIELD(CPACR, ASEDIS, 31, 1)
37
+ fn(cpu_env, qd, tcg_constant_i64(imm));
41
-
38
+ tcg_temp_free_ptr(qd);
42
-/* Bit definitions for CPACR_EL1 (AArch64 only) */
39
+ }
43
-FIELD(CPACR_EL1, ZEN, 16, 2)
40
mve_update_eci(s);
44
-FIELD(CPACR_EL1, FPEN, 20, 2)
41
return true;
45
-FIELD(CPACR_EL1, SMEN, 24, 2)
42
}
46
-FIELD(CPACR_EL1, TTA, 28, 1) /* matches CPACR.TRCDIS */
43
47
-
44
+static void gen_gvec_vmovi(unsigned vece, uint32_t dofs, uint32_t aofs,
48
-/* Bit definitions for HCPTR (AArch32 only) */
45
+ int64_t c, uint32_t oprsz, uint32_t maxsz)
49
-FIELD(HCPTR, TCP10, 10, 1)
46
+{
50
-FIELD(HCPTR, TCP11, 11, 1)
47
+ tcg_gen_gvec_dup_imm(vece, dofs, oprsz, maxsz, c);
51
-FIELD(HCPTR, TASE, 15, 1)
48
+}
52
-FIELD(HCPTR, TTA, 20, 1)
49
+
53
-FIELD(HCPTR, TAM, 30, 1) /* matches CPTR_EL2.TAM */
50
static bool trans_Vimm_1r(DisasContext *s, arg_1imm *a)
54
-FIELD(HCPTR, TCPAC, 31, 1) /* matches CPTR_EL2.TCPAC */
51
{
55
-
52
/* Handle decode of cmode/op here between VORR/VBIC/VMOV */
56
-/* Bit definitions for CPTR_EL2 (AArch64 only) */
53
MVEGenOneOpImmFn *fn;
57
-FIELD(CPTR_EL2, TZ, 8, 1) /* !E2H */
54
+ GVecGen2iFn *vecfn;
58
-FIELD(CPTR_EL2, TFP, 10, 1) /* !E2H, matches HCPTR.TCP10 */
55
59
-FIELD(CPTR_EL2, TSM, 12, 1) /* !E2H */
56
if ((a->cmode & 1) && a->cmode < 12) {
60
-FIELD(CPTR_EL2, ZEN, 16, 2) /* E2H */
57
if (a->op) {
61
-FIELD(CPTR_EL2, FPEN, 20, 2) /* E2H */
58
@@ -XXX,XX +XXX,XX @@ static bool trans_Vimm_1r(DisasContext *s, arg_1imm *a)
62
-FIELD(CPTR_EL2, SMEN, 24, 2) /* E2H */
59
* so the VBIC becomes a logical AND operation.
63
-FIELD(CPTR_EL2, TTA, 28, 1)
60
*/
64
-FIELD(CPTR_EL2, TAM, 30, 1) /* matches HCPTR.TAM */
61
fn = gen_helper_mve_vandi;
65
-FIELD(CPTR_EL2, TCPAC, 31, 1) /* matches HCPTR.TCPAC */
62
+ vecfn = tcg_gen_gvec_andi;
66
-
63
} else {
67
-/* Bit definitions for CPTR_EL3 (AArch64 only) */
64
fn = gen_helper_mve_vorri;
68
-FIELD(CPTR_EL3, EZ, 8, 1)
65
+ vecfn = tcg_gen_gvec_ori;
69
-FIELD(CPTR_EL3, TFP, 10, 1)
66
}
70
-FIELD(CPTR_EL3, ESM, 12, 1)
67
} else {
71
-FIELD(CPTR_EL3, TTA, 20, 1)
68
/* There is one unallocated cmode/op combination in this space */
72
-FIELD(CPTR_EL3, TAM, 30, 1)
69
@@ -XXX,XX +XXX,XX @@ static bool trans_Vimm_1r(DisasContext *s, arg_1imm *a)
73
-FIELD(CPTR_EL3, TCPAC, 31, 1)
70
}
74
-
71
/* asimd_imm_const() sorts out VMVNI vs VMOVI for us */
75
-#define MDCR_MTPME (1U << 28)
72
fn = gen_helper_mve_vmovi;
76
-#define MDCR_TDCC (1U << 27)
73
+ vecfn = gen_gvec_vmovi;
77
-#define MDCR_HLP (1U << 26) /* MDCR_EL2 */
74
}
78
-#define MDCR_SCCD (1U << 23) /* MDCR_EL3 */
75
- return do_1imm(s, a, fn);
79
-#define MDCR_HCCD (1U << 23) /* MDCR_EL2 */
76
+ return do_1imm(s, a, fn, vecfn);
80
-#define MDCR_EPMAD (1U << 21)
77
}
81
-#define MDCR_EDAD (1U << 20)
78
82
-#define MDCR_TTRF (1U << 19)
79
static bool do_2shift_vec(DisasContext *s, arg_2shift *a, MVEGenTwoOpShiftFn fn,
83
-#define MDCR_STE (1U << 18) /* MDCR_EL3 */
84
-#define MDCR_SPME (1U << 17) /* MDCR_EL3 */
85
-#define MDCR_HPMD (1U << 17) /* MDCR_EL2 */
86
-#define MDCR_SDD (1U << 16)
87
-#define MDCR_SPD (3U << 14)
88
-#define MDCR_TDRA (1U << 11)
89
-#define MDCR_TDOSA (1U << 10)
90
-#define MDCR_TDA (1U << 9)
91
-#define MDCR_TDE (1U << 8)
92
-#define MDCR_HPME (1U << 7)
93
-#define MDCR_TPM (1U << 6)
94
-#define MDCR_TPMCR (1U << 5)
95
-#define MDCR_HPMN (0x1fU)
96
-
97
-/* Not all of the MDCR_EL3 bits are present in the 32-bit SDCR */
98
-#define SDCR_VALID_MASK (MDCR_MTPME | MDCR_TDCC | MDCR_SCCD | \
99
- MDCR_EPMAD | MDCR_EDAD | MDCR_TTRF | \
100
- MDCR_STE | MDCR_SPME | MDCR_SPD)
101
-
102
#define CPSR_M (0x1fU)
103
#define CPSR_T (1U << 5)
104
#define CPSR_F (1U << 6)
105
@@ -XXX,XX +XXX,XX @@ FIELD(CPTR_EL3, TCPAC, 31, 1)
106
#define XPSR_NZCV CPSR_NZCV
107
#define XPSR_IT CPSR_IT
108
109
-#define TTBCR_N (7U << 0) /* TTBCR.EAE==0 */
110
-#define TTBCR_T0SZ (7U << 0) /* TTBCR.EAE==1 */
111
-#define TTBCR_PD0 (1U << 4)
112
-#define TTBCR_PD1 (1U << 5)
113
-#define TTBCR_EPD0 (1U << 7)
114
-#define TTBCR_IRGN0 (3U << 8)
115
-#define TTBCR_ORGN0 (3U << 10)
116
-#define TTBCR_SH0 (3U << 12)
117
-#define TTBCR_T1SZ (3U << 16)
118
-#define TTBCR_A1 (1U << 22)
119
-#define TTBCR_EPD1 (1U << 23)
120
-#define TTBCR_IRGN1 (3U << 24)
121
-#define TTBCR_ORGN1 (3U << 26)
122
-#define TTBCR_SH1 (1U << 28)
123
-#define TTBCR_EAE (1U << 31)
124
-
125
-FIELD(VTCR, T0SZ, 0, 6)
126
-FIELD(VTCR, SL0, 6, 2)
127
-FIELD(VTCR, IRGN0, 8, 2)
128
-FIELD(VTCR, ORGN0, 10, 2)
129
-FIELD(VTCR, SH0, 12, 2)
130
-FIELD(VTCR, TG0, 14, 2)
131
-FIELD(VTCR, PS, 16, 3)
132
-FIELD(VTCR, VS, 19, 1)
133
-FIELD(VTCR, HA, 21, 1)
134
-FIELD(VTCR, HD, 22, 1)
135
-FIELD(VTCR, HWU59, 25, 1)
136
-FIELD(VTCR, HWU60, 26, 1)
137
-FIELD(VTCR, HWU61, 27, 1)
138
-FIELD(VTCR, HWU62, 28, 1)
139
-FIELD(VTCR, NSW, 29, 1)
140
-FIELD(VTCR, NSA, 30, 1)
141
-FIELD(VTCR, DS, 32, 1)
142
-FIELD(VTCR, SL2, 33, 1)
143
-
144
/* Bit definitions for ARMv8 SPSR (PSTATE) format.
145
* Only these are valid when in AArch64 mode; in
146
* AArch32 mode SPSRs are basically CPSR-format.
147
@@ -XXX,XX +XXX,XX @@ static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask)
148
#define HCR_TWEDEN (1ULL << 59)
149
#define HCR_TWEDEL MAKE_64BIT_MASK(60, 4)
150
151
-#define HCRX_ENAS0 (1ULL << 0)
152
-#define HCRX_ENALS (1ULL << 1)
153
-#define HCRX_ENASR (1ULL << 2)
154
-#define HCRX_FNXS (1ULL << 3)
155
-#define HCRX_FGTNXS (1ULL << 4)
156
-#define HCRX_SMPME (1ULL << 5)
157
-#define HCRX_TALLINT (1ULL << 6)
158
-#define HCRX_VINMI (1ULL << 7)
159
-#define HCRX_VFNMI (1ULL << 8)
160
-#define HCRX_CMOW (1ULL << 9)
161
-#define HCRX_MCE2 (1ULL << 10)
162
-#define HCRX_MSCEN (1ULL << 11)
163
-
164
-#define HPFAR_NS (1ULL << 63)
165
-
166
#define SCR_NS (1ULL << 0)
167
#define SCR_IRQ (1ULL << 1)
168
#define SCR_FIQ (1ULL << 2)
169
@@ -XXX,XX +XXX,XX @@ static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask)
170
#define SCR_GPF (1ULL << 48)
171
#define SCR_NSE (1ULL << 62)
172
173
-#define HSTR_TTEE (1 << 16)
174
-#define HSTR_TJDBX (1 << 17)
175
-
176
-#define CNTHCTL_CNTVMASK (1 << 18)
177
-#define CNTHCTL_CNTPMASK (1 << 19)
178
-
179
/* Return the current FPSCR value. */
180
uint32_t vfp_get_fpscr(CPUARMState *env);
181
void vfp_set_fpscr(CPUARMState *env, uint32_t val);
182
diff --git a/target/arm/internals.h b/target/arm/internals.h
183
index XXXXXXX..XXXXXXX 100644
184
--- a/target/arm/internals.h
185
+++ b/target/arm/internals.h
186
@@ -XXX,XX +XXX,XX @@ FIELD(DBGWCR, WT, 20, 1)
187
FIELD(DBGWCR, MASK, 24, 5)
188
FIELD(DBGWCR, SSCE, 29, 1)
189
190
+#define VTCR_NSW (1u << 29)
191
+#define VTCR_NSA (1u << 30)
192
+#define VSTCR_SW VTCR_NSW
193
+#define VSTCR_SA VTCR_NSA
194
+
195
+/* Bit definitions for CPACR (AArch32 only) */
196
+FIELD(CPACR, CP10, 20, 2)
197
+FIELD(CPACR, CP11, 22, 2)
198
+FIELD(CPACR, TRCDIS, 28, 1) /* matches CPACR_EL1.TTA */
199
+FIELD(CPACR, D32DIS, 30, 1) /* up to v7; RAZ in v8 */
200
+FIELD(CPACR, ASEDIS, 31, 1)
201
+
202
+/* Bit definitions for CPACR_EL1 (AArch64 only) */
203
+FIELD(CPACR_EL1, ZEN, 16, 2)
204
+FIELD(CPACR_EL1, FPEN, 20, 2)
205
+FIELD(CPACR_EL1, SMEN, 24, 2)
206
+FIELD(CPACR_EL1, TTA, 28, 1) /* matches CPACR.TRCDIS */
207
+
208
+/* Bit definitions for HCPTR (AArch32 only) */
209
+FIELD(HCPTR, TCP10, 10, 1)
210
+FIELD(HCPTR, TCP11, 11, 1)
211
+FIELD(HCPTR, TASE, 15, 1)
212
+FIELD(HCPTR, TTA, 20, 1)
213
+FIELD(HCPTR, TAM, 30, 1) /* matches CPTR_EL2.TAM */
214
+FIELD(HCPTR, TCPAC, 31, 1) /* matches CPTR_EL2.TCPAC */
215
+
216
+/* Bit definitions for CPTR_EL2 (AArch64 only) */
217
+FIELD(CPTR_EL2, TZ, 8, 1) /* !E2H */
218
+FIELD(CPTR_EL2, TFP, 10, 1) /* !E2H, matches HCPTR.TCP10 */
219
+FIELD(CPTR_EL2, TSM, 12, 1) /* !E2H */
220
+FIELD(CPTR_EL2, ZEN, 16, 2) /* E2H */
221
+FIELD(CPTR_EL2, FPEN, 20, 2) /* E2H */
222
+FIELD(CPTR_EL2, SMEN, 24, 2) /* E2H */
223
+FIELD(CPTR_EL2, TTA, 28, 1)
224
+FIELD(CPTR_EL2, TAM, 30, 1) /* matches HCPTR.TAM */
225
+FIELD(CPTR_EL2, TCPAC, 31, 1) /* matches HCPTR.TCPAC */
226
+
227
+/* Bit definitions for CPTR_EL3 (AArch64 only) */
228
+FIELD(CPTR_EL3, EZ, 8, 1)
229
+FIELD(CPTR_EL3, TFP, 10, 1)
230
+FIELD(CPTR_EL3, ESM, 12, 1)
231
+FIELD(CPTR_EL3, TTA, 20, 1)
232
+FIELD(CPTR_EL3, TAM, 30, 1)
233
+FIELD(CPTR_EL3, TCPAC, 31, 1)
234
+
235
+#define MDCR_MTPME (1U << 28)
236
+#define MDCR_TDCC (1U << 27)
237
+#define MDCR_HLP (1U << 26) /* MDCR_EL2 */
238
+#define MDCR_SCCD (1U << 23) /* MDCR_EL3 */
239
+#define MDCR_HCCD (1U << 23) /* MDCR_EL2 */
240
+#define MDCR_EPMAD (1U << 21)
241
+#define MDCR_EDAD (1U << 20)
242
+#define MDCR_TTRF (1U << 19)
243
+#define MDCR_STE (1U << 18) /* MDCR_EL3 */
244
+#define MDCR_SPME (1U << 17) /* MDCR_EL3 */
245
+#define MDCR_HPMD (1U << 17) /* MDCR_EL2 */
246
+#define MDCR_SDD (1U << 16)
247
+#define MDCR_SPD (3U << 14)
248
+#define MDCR_TDRA (1U << 11)
249
+#define MDCR_TDOSA (1U << 10)
250
+#define MDCR_TDA (1U << 9)
251
+#define MDCR_TDE (1U << 8)
252
+#define MDCR_HPME (1U << 7)
253
+#define MDCR_TPM (1U << 6)
254
+#define MDCR_TPMCR (1U << 5)
255
+#define MDCR_HPMN (0x1fU)
256
+
257
+/* Not all of the MDCR_EL3 bits are present in the 32-bit SDCR */
258
+#define SDCR_VALID_MASK (MDCR_MTPME | MDCR_TDCC | MDCR_SCCD | \
259
+ MDCR_EPMAD | MDCR_EDAD | MDCR_TTRF | \
260
+ MDCR_STE | MDCR_SPME | MDCR_SPD)
261
+
262
+#define TTBCR_N (7U << 0) /* TTBCR.EAE==0 */
263
+#define TTBCR_T0SZ (7U << 0) /* TTBCR.EAE==1 */
264
+#define TTBCR_PD0 (1U << 4)
265
+#define TTBCR_PD1 (1U << 5)
266
+#define TTBCR_EPD0 (1U << 7)
267
+#define TTBCR_IRGN0 (3U << 8)
268
+#define TTBCR_ORGN0 (3U << 10)
269
+#define TTBCR_SH0 (3U << 12)
270
+#define TTBCR_T1SZ (3U << 16)
271
+#define TTBCR_A1 (1U << 22)
272
+#define TTBCR_EPD1 (1U << 23)
273
+#define TTBCR_IRGN1 (3U << 24)
274
+#define TTBCR_ORGN1 (3U << 26)
275
+#define TTBCR_SH1 (1U << 28)
276
+#define TTBCR_EAE (1U << 31)
277
+
278
+FIELD(VTCR, T0SZ, 0, 6)
279
+FIELD(VTCR, SL0, 6, 2)
280
+FIELD(VTCR, IRGN0, 8, 2)
281
+FIELD(VTCR, ORGN0, 10, 2)
282
+FIELD(VTCR, SH0, 12, 2)
283
+FIELD(VTCR, TG0, 14, 2)
284
+FIELD(VTCR, PS, 16, 3)
285
+FIELD(VTCR, VS, 19, 1)
286
+FIELD(VTCR, HA, 21, 1)
287
+FIELD(VTCR, HD, 22, 1)
288
+FIELD(VTCR, HWU59, 25, 1)
289
+FIELD(VTCR, HWU60, 26, 1)
290
+FIELD(VTCR, HWU61, 27, 1)
291
+FIELD(VTCR, HWU62, 28, 1)
292
+FIELD(VTCR, NSW, 29, 1)
293
+FIELD(VTCR, NSA, 30, 1)
294
+FIELD(VTCR, DS, 32, 1)
295
+FIELD(VTCR, SL2, 33, 1)
296
+
297
+#define HCRX_ENAS0 (1ULL << 0)
298
+#define HCRX_ENALS (1ULL << 1)
299
+#define HCRX_ENASR (1ULL << 2)
300
+#define HCRX_FNXS (1ULL << 3)
301
+#define HCRX_FGTNXS (1ULL << 4)
302
+#define HCRX_SMPME (1ULL << 5)
303
+#define HCRX_TALLINT (1ULL << 6)
304
+#define HCRX_VINMI (1ULL << 7)
305
+#define HCRX_VFNMI (1ULL << 8)
306
+#define HCRX_CMOW (1ULL << 9)
307
+#define HCRX_MCE2 (1ULL << 10)
308
+#define HCRX_MSCEN (1ULL << 11)
309
+
310
+#define HPFAR_NS (1ULL << 63)
311
+
312
+#define HSTR_TTEE (1 << 16)
313
+#define HSTR_TJDBX (1 << 17)
314
+
315
+#define CNTHCTL_CNTVMASK (1 << 18)
316
+#define CNTHCTL_CNTPMASK (1 << 19)
317
+
318
/* We use a few fake FSR values for internal purposes in M profile.
319
* M profile cores don't have A/R format FSRs, but currently our
320
* get_phys_addr() code assumes A/R profile and reports failures via
80
--
321
--
81
2.20.1
322
2.34.1
82
323
83
324
diff view generated by jsdifflib
1
Optimize the MVE VMVN insn by using TCG vector ops when possible.
1
The timer _EL02 registers should UNDEF for invalid accesses from EL2
2
or EL3 when HCR_EL2.E2H == 0, not take a cp access trap. We were
3
delivering the exception to EL2 with the wrong syndrome.
2
4
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Message-id: 20210913095440.13462-9-peter.maydell@linaro.org
7
Message-id: 20240301183219.2424889-3-peter.maydell@linaro.org
6
---
8
---
7
target/arm/translate-mve.c | 2 +-
9
target/arm/helper.c | 2 +-
8
1 file changed, 1 insertion(+), 1 deletion(-)
10
1 file changed, 1 insertion(+), 1 deletion(-)
9
11
10
diff --git a/target/arm/translate-mve.c b/target/arm/translate-mve.c
12
diff --git a/target/arm/helper.c b/target/arm/helper.c
11
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
12
--- a/target/arm/translate-mve.c
14
--- a/target/arm/helper.c
13
+++ b/target/arm/translate-mve.c
15
+++ b/target/arm/helper.c
14
@@ -XXX,XX +XXX,XX @@ static bool trans_VREV64(DisasContext *s, arg_1op *a)
16
@@ -XXX,XX +XXX,XX @@ static CPAccessResult e2h_access(CPUARMState *env, const ARMCPRegInfo *ri,
15
17
return CP_ACCESS_OK;
16
static bool trans_VMVN(DisasContext *s, arg_1op *a)
18
}
17
{
19
if (!(arm_hcr_el2_eff(env) & HCR_E2H)) {
18
- return do_1op(s, a, gen_helper_mve_vmvn);
20
- return CP_ACCESS_TRAP;
19
+ return do_1op_vec(s, a, gen_helper_mve_vmvn, tcg_gen_gvec_not);
21
+ return CP_ACCESS_TRAP_UNCATEGORIZED;
22
}
23
return CP_ACCESS_OK;
20
}
24
}
21
22
static bool trans_VABS_fp(DisasContext *s, arg_1op *a)
23
--
25
--
24
2.20.1
26
2.34.1
25
26
diff view generated by jsdifflib
1
From: Alexander Graf <agraf@csgraf.de>
1
We prefer the FIELD macro over ad-hoc #defines for register bits;
2
switch CNTHCTL to that style before we add any more bits.
2
3
3
We will need PMC register definitions in accel specific code later.
4
Move all constant definitions to common arm headers so we can reuse
5
them.
6
7
Signed-off-by: Alexander Graf <agraf@csgraf.de>
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Message-id: 20210916155404.86958-2-agraf@csgraf.de
10
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é <philmd@linaro.org>
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20240301183219.2424889-4-peter.maydell@linaro.org
11
---
8
---
12
target/arm/internals.h | 44 ++++++++++++++++++++++++++++++++++++++++++
9
target/arm/internals.h | 27 +++++++++++++++++++++++++--
13
target/arm/helper.c | 44 ------------------------------------------
10
target/arm/helper.c | 9 ++++-----
14
2 files changed, 44 insertions(+), 44 deletions(-)
11
2 files changed, 29 insertions(+), 7 deletions(-)
15
12
16
diff --git a/target/arm/internals.h b/target/arm/internals.h
13
diff --git a/target/arm/internals.h b/target/arm/internals.h
17
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
18
--- a/target/arm/internals.h
15
--- a/target/arm/internals.h
19
+++ b/target/arm/internals.h
16
+++ b/target/arm/internals.h
20
@@ -XXX,XX +XXX,XX @@ enum MVEECIState {
17
@@ -XXX,XX +XXX,XX @@ FIELD(VTCR, SL2, 33, 1)
21
/* All other values reserved */
18
#define HSTR_TTEE (1 << 16)
22
};
19
#define HSTR_TJDBX (1 << 17)
23
20
24
+/* Definitions for the PMU registers */
21
-#define CNTHCTL_CNTVMASK (1 << 18)
25
+#define PMCRN_MASK 0xf800
22
-#define CNTHCTL_CNTPMASK (1 << 19)
26
+#define PMCRN_SHIFT 11
27
+#define PMCRLC 0x40
28
+#define PMCRDP 0x20
29
+#define PMCRX 0x10
30
+#define PMCRD 0x8
31
+#define PMCRC 0x4
32
+#define PMCRP 0x2
33
+#define PMCRE 0x1
34
+/*
23
+/*
35
+ * Mask of PMCR bits writeable by guest (not including WO bits like C, P,
24
+ * Depending on the value of HCR_EL2.E2H, bits 0 and 1
36
+ * which can be written as 1 to trigger behaviour but which stay RAZ).
25
+ * have different bit definitions, and EL1PCTEN might be
26
+ * bit 0 or bit 10. We use _E2H1 and _E2H0 suffixes to
27
+ * disambiguate if necessary.
37
+ */
28
+ */
38
+#define PMCR_WRITEABLE_MASK (PMCRLC | PMCRDP | PMCRX | PMCRD | PMCRE)
29
+FIELD(CNTHCTL, EL0PCTEN_E2H1, 0, 1)
39
+
30
+FIELD(CNTHCTL, EL0VCTEN_E2H1, 1, 1)
40
+#define PMXEVTYPER_P 0x80000000
31
+FIELD(CNTHCTL, EL1PCTEN_E2H0, 0, 1)
41
+#define PMXEVTYPER_U 0x40000000
32
+FIELD(CNTHCTL, EL1PCEN_E2H0, 1, 1)
42
+#define PMXEVTYPER_NSK 0x20000000
33
+FIELD(CNTHCTL, EVNTEN, 2, 1)
43
+#define PMXEVTYPER_NSU 0x10000000
34
+FIELD(CNTHCTL, EVNTDIR, 3, 1)
44
+#define PMXEVTYPER_NSH 0x08000000
35
+FIELD(CNTHCTL, EVNTI, 4, 4)
45
+#define PMXEVTYPER_M 0x04000000
36
+FIELD(CNTHCTL, EL0VTEN, 8, 1)
46
+#define PMXEVTYPER_MT 0x02000000
37
+FIELD(CNTHCTL, EL0PTEN, 9, 1)
47
+#define PMXEVTYPER_EVTCOUNT 0x0000ffff
38
+FIELD(CNTHCTL, EL1PCTEN_E2H1, 10, 1)
48
+#define PMXEVTYPER_MASK (PMXEVTYPER_P | PMXEVTYPER_U | PMXEVTYPER_NSK | \
39
+FIELD(CNTHCTL, EL1PTEN, 11, 1)
49
+ PMXEVTYPER_NSU | PMXEVTYPER_NSH | \
40
+FIELD(CNTHCTL, ECV, 12, 1)
50
+ PMXEVTYPER_M | PMXEVTYPER_MT | \
41
+FIELD(CNTHCTL, EL1TVT, 13, 1)
51
+ PMXEVTYPER_EVTCOUNT)
42
+FIELD(CNTHCTL, EL1TVCT, 14, 1)
52
+
43
+FIELD(CNTHCTL, EL1NVPCT, 15, 1)
53
+#define PMCCFILTR 0xf8000000
44
+FIELD(CNTHCTL, EL1NVVCT, 16, 1)
54
+#define PMCCFILTR_M PMXEVTYPER_M
45
+FIELD(CNTHCTL, EVNTIS, 17, 1)
55
+#define PMCCFILTR_EL0 (PMCCFILTR | PMCCFILTR_M)
46
+FIELD(CNTHCTL, CNTVMASK, 18, 1)
56
+
47
+FIELD(CNTHCTL, CNTPMASK, 19, 1)
57
+static inline uint32_t pmu_num_counters(CPUARMState *env)
48
58
+{
49
/* We use a few fake FSR values for internal purposes in M profile.
59
+ return (env->cp15.c9_pmcr & PMCRN_MASK) >> PMCRN_SHIFT;
50
* M profile cores don't have A/R format FSRs, but currently our
60
+}
61
+
62
+/* Bits allowed to be set/cleared for PMCNTEN* and PMINTEN* */
63
+static inline uint64_t pmu_counter_mask(CPUARMState *env)
64
+{
65
+ return (1 << 31) | ((1 << pmu_num_counters(env)) - 1);
66
+}
67
+
68
#endif
69
diff --git a/target/arm/helper.c b/target/arm/helper.c
51
diff --git a/target/arm/helper.c b/target/arm/helper.c
70
index XXXXXXX..XXXXXXX 100644
52
index XXXXXXX..XXXXXXX 100644
71
--- a/target/arm/helper.c
53
--- a/target/arm/helper.c
72
+++ b/target/arm/helper.c
54
+++ b/target/arm/helper.c
73
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo v6_cp_reginfo[] = {
55
@@ -XXX,XX +XXX,XX @@ static void gt_update_irq(ARMCPU *cpu, int timeridx)
74
REGINFO_SENTINEL
56
* It is RES0 in Secure and NonSecure state.
75
};
57
*/
76
58
if ((ss == ARMSS_Root || ss == ARMSS_Realm) &&
77
-/* Definitions for the PMU registers */
59
- ((timeridx == GTIMER_VIRT && (cnthctl & CNTHCTL_CNTVMASK)) ||
78
-#define PMCRN_MASK 0xf800
60
- (timeridx == GTIMER_PHYS && (cnthctl & CNTHCTL_CNTPMASK)))) {
79
-#define PMCRN_SHIFT 11
61
+ ((timeridx == GTIMER_VIRT && (cnthctl & R_CNTHCTL_CNTVMASK_MASK)) ||
80
-#define PMCRLC 0x40
62
+ (timeridx == GTIMER_PHYS && (cnthctl & R_CNTHCTL_CNTPMASK_MASK)))) {
81
-#define PMCRDP 0x20
63
irqstate = 0;
82
-#define PMCRX 0x10
64
}
83
-#define PMCRD 0x8
65
84
-#define PMCRC 0x4
66
@@ -XXX,XX +XXX,XX @@ static void gt_cnthctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
85
-#define PMCRP 0x2
67
{
86
-#define PMCRE 0x1
68
ARMCPU *cpu = env_archcpu(env);
87
-/*
69
uint32_t oldval = env->cp15.cnthctl_el2;
88
- * Mask of PMCR bits writeable by guest (not including WO bits like C, P,
89
- * which can be written as 1 to trigger behaviour but which stay RAZ).
90
- */
91
-#define PMCR_WRITEABLE_MASK (PMCRLC | PMCRDP | PMCRX | PMCRD | PMCRE)
92
-
70
-
93
-#define PMXEVTYPER_P 0x80000000
71
raw_write(env, ri, value);
94
-#define PMXEVTYPER_U 0x40000000
72
95
-#define PMXEVTYPER_NSK 0x20000000
73
- if ((oldval ^ value) & CNTHCTL_CNTVMASK) {
96
-#define PMXEVTYPER_NSU 0x10000000
74
+ if ((oldval ^ value) & R_CNTHCTL_CNTVMASK_MASK) {
97
-#define PMXEVTYPER_NSH 0x08000000
75
gt_update_irq(cpu, GTIMER_VIRT);
98
-#define PMXEVTYPER_M 0x04000000
76
- } else if ((oldval ^ value) & CNTHCTL_CNTPMASK) {
99
-#define PMXEVTYPER_MT 0x02000000
77
+ } else if ((oldval ^ value) & R_CNTHCTL_CNTPMASK_MASK) {
100
-#define PMXEVTYPER_EVTCOUNT 0x0000ffff
78
gt_update_irq(cpu, GTIMER_PHYS);
101
-#define PMXEVTYPER_MASK (PMXEVTYPER_P | PMXEVTYPER_U | PMXEVTYPER_NSK | \
79
}
102
- PMXEVTYPER_NSU | PMXEVTYPER_NSH | \
80
}
103
- PMXEVTYPER_M | PMXEVTYPER_MT | \
104
- PMXEVTYPER_EVTCOUNT)
105
-
106
-#define PMCCFILTR 0xf8000000
107
-#define PMCCFILTR_M PMXEVTYPER_M
108
-#define PMCCFILTR_EL0 (PMCCFILTR | PMCCFILTR_M)
109
-
110
-static inline uint32_t pmu_num_counters(CPUARMState *env)
111
-{
112
- return (env->cp15.c9_pmcr & PMCRN_MASK) >> PMCRN_SHIFT;
113
-}
114
-
115
-/* Bits allowed to be set/cleared for PMCNTEN* and PMINTEN* */
116
-static inline uint64_t pmu_counter_mask(CPUARMState *env)
117
-{
118
- return (1 << 31) | ((1 << pmu_num_counters(env)) - 1);
119
-}
120
-
121
typedef struct pm_event {
122
uint16_t number; /* PMEVTYPER.evtCount is 16 bits wide */
123
/* If the event is supported on this CPU (used to generate PMCEID[01]) */
124
--
81
--
125
2.20.1
82
2.34.1
126
83
127
84
diff view generated by jsdifflib
1
Move an ifndef CONFIG_USER_ONLY code block up in arm_cpu_reset() so
1
Don't allow the guest to write CNTHCTL_EL2 bits which don't exist.
2
it can be merged with another earlier one.
2
This is not strictly architecturally required, but it is how we've
3
tended to implement registers more recently.
4
5
In particular, bits [19:18] are only present with FEAT_RME,
6
and bits [17:12] will only be present with FEAT_ECV.
3
7
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
9
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20210914120725.24992-4-peter.maydell@linaro.org
10
Message-id: 20240301183219.2424889-5-peter.maydell@linaro.org
7
---
11
---
8
target/arm/cpu.c | 22 ++++++++++------------
12
target/arm/helper.c | 18 ++++++++++++++++++
9
1 file changed, 10 insertions(+), 12 deletions(-)
13
1 file changed, 18 insertions(+)
10
14
11
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
15
diff --git a/target/arm/helper.c b/target/arm/helper.c
12
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
13
--- a/target/arm/cpu.c
17
--- a/target/arm/helper.c
14
+++ b/target/arm/cpu.c
18
+++ b/target/arm/helper.c
15
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_reset(DeviceState *dev)
19
@@ -XXX,XX +XXX,XX @@ static void gt_cnthctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
16
env->uncached_cpsr = ARM_CPU_MODE_SVC;
20
{
17
}
21
ARMCPU *cpu = env_archcpu(env);
18
env->daif = PSTATE_D | PSTATE_A | PSTATE_I | PSTATE_F;
22
uint32_t oldval = env->cp15.cnthctl_el2;
23
+ uint32_t valid_mask =
24
+ R_CNTHCTL_EL0PCTEN_E2H1_MASK |
25
+ R_CNTHCTL_EL0VCTEN_E2H1_MASK |
26
+ R_CNTHCTL_EVNTEN_MASK |
27
+ R_CNTHCTL_EVNTDIR_MASK |
28
+ R_CNTHCTL_EVNTI_MASK |
29
+ R_CNTHCTL_EL0VTEN_MASK |
30
+ R_CNTHCTL_EL0PTEN_MASK |
31
+ R_CNTHCTL_EL1PCTEN_E2H1_MASK |
32
+ R_CNTHCTL_EL1PTEN_MASK;
19
+
33
+
20
+ /* AArch32 has a hard highvec setting of 0xFFFF0000. If we are currently
34
+ if (cpu_isar_feature(aa64_rme, cpu)) {
21
+ * executing as AArch32 then check if highvecs are enabled and
35
+ valid_mask |= R_CNTHCTL_CNTVMASK_MASK | R_CNTHCTL_CNTPMASK_MASK;
22
+ * adjust the PC accordingly.
23
+ */
24
+ if (A32_BANKED_CURRENT_REG_GET(env, sctlr) & SCTLR_V) {
25
+ env->regs[15] = 0xFFFF0000;
26
+ }
36
+ }
27
+
37
+
28
+ env->vfp.xregs[ARM_VFP_FPEXC] = 0;
38
+ /* Clear RES0 bits */
29
#endif
39
+ value &= valid_mask;
30
40
+
31
if (arm_feature(env, ARM_FEATURE_M)) {
41
raw_write(env, ri, value);
32
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_reset(DeviceState *dev)
42
33
#endif
43
if ((oldval ^ value) & R_CNTHCTL_CNTVMASK_MASK) {
34
}
35
36
-#ifndef CONFIG_USER_ONLY
37
- /* AArch32 has a hard highvec setting of 0xFFFF0000. If we are currently
38
- * executing as AArch32 then check if highvecs are enabled and
39
- * adjust the PC accordingly.
40
- */
41
- if (A32_BANKED_CURRENT_REG_GET(env, sctlr) & SCTLR_V) {
42
- env->regs[15] = 0xFFFF0000;
43
- }
44
-
45
- env->vfp.xregs[ARM_VFP_FPEXC] = 0;
46
-#endif
47
-
48
/* M profile requires that reset clears the exclusive monitor;
49
* A profile does not, but clearing it makes more sense than having it
50
* set with an exclusive access on address zero.
51
--
44
--
52
2.20.1
45
2.34.1
53
54
diff view generated by jsdifflib
1
Optimize the MVE VSHL and VSHR immediate forms by using TCG vector
1
The functionality defined by ID_AA64MMFR0_EL1.ECV == 1 is:
2
ops when possible.
2
* four new trap bits for various counter and timer registers
3
* the CNTHCTL_EL2.EVNTIS and CNTKCTL_EL1.EVNTIS bits which control
4
scaling of the event stream. This is a no-op for us, because we don't
5
implement the event stream (our WFE is a NOP): all we need to do is
6
allow CNTHCTL_EL2.ENVTIS to be read and written.
7
* extensions to PMSCR_EL1.PCT, PMSCR_EL2.PCT, TRFCR_EL1.TS and
8
TRFCR_EL2.TS: these are all no-ops for us, because we don't implement
9
FEAT_SPE or FEAT_TRF.
10
* new registers CNTPCTSS_EL0 and NCTVCTSS_EL0 which are
11
"self-sychronizing" views of the CNTPCT_EL0 and CNTVCT_EL0, meaning
12
that no barriers are needed around their accesses. For us these
13
are just the same as the normal views, because all our sysregs are
14
inherently self-sychronizing.
15
16
In this commit we implement the trap handling and permit the new
17
CNTHCTL_EL2 bits to be written.
3
18
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
19
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
20
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20210913095440.13462-10-peter.maydell@linaro.org
21
Message-id: 20240301183219.2424889-6-peter.maydell@linaro.org
7
---
22
---
8
target/arm/translate-mve.c | 83 +++++++++++++++++++++++++++++---------
23
target/arm/cpu-features.h | 5 ++++
9
1 file changed, 63 insertions(+), 20 deletions(-)
24
target/arm/helper.c | 51 +++++++++++++++++++++++++++++++++++----
25
2 files changed, 51 insertions(+), 5 deletions(-)
10
26
11
diff --git a/target/arm/translate-mve.c b/target/arm/translate-mve.c
27
diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h
12
index XXXXXXX..XXXXXXX 100644
28
index XXXXXXX..XXXXXXX 100644
13
--- a/target/arm/translate-mve.c
29
--- a/target/arm/cpu-features.h
14
+++ b/target/arm/translate-mve.c
30
+++ b/target/arm/cpu-features.h
15
@@ -XXX,XX +XXX,XX @@ static bool trans_Vimm_1r(DisasContext *s, arg_1imm *a)
31
@@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_fgt(const ARMISARegisters *id)
16
return do_1imm(s, a, fn);
32
return FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, FGT) != 0;
17
}
33
}
18
34
19
-static bool do_2shift(DisasContext *s, arg_2shift *a, MVEGenTwoOpShiftFn fn,
35
+static inline bool isar_feature_aa64_ecv_traps(const ARMISARegisters *id)
20
- bool negateshift)
21
+static bool do_2shift_vec(DisasContext *s, arg_2shift *a, MVEGenTwoOpShiftFn fn,
22
+ bool negateshift, GVecGen2iFn vecfn)
23
{
24
TCGv_ptr qd, qm;
25
int shift = a->shift;
26
@@ -XXX,XX +XXX,XX @@ static bool do_2shift(DisasContext *s, arg_2shift *a, MVEGenTwoOpShiftFn fn,
27
shift = -shift;
28
}
29
30
- qd = mve_qreg_ptr(a->qd);
31
- qm = mve_qreg_ptr(a->qm);
32
- fn(cpu_env, qd, qm, tcg_constant_i32(shift));
33
- tcg_temp_free_ptr(qd);
34
- tcg_temp_free_ptr(qm);
35
+ if (vecfn && mve_no_predication(s)) {
36
+ vecfn(a->size, mve_qreg_offset(a->qd), mve_qreg_offset(a->qm),
37
+ shift, 16, 16);
38
+ } else {
39
+ qd = mve_qreg_ptr(a->qd);
40
+ qm = mve_qreg_ptr(a->qm);
41
+ fn(cpu_env, qd, qm, tcg_constant_i32(shift));
42
+ tcg_temp_free_ptr(qd);
43
+ tcg_temp_free_ptr(qm);
44
+ }
45
mve_update_eci(s);
46
return true;
47
}
48
49
-#define DO_2SHIFT(INSN, FN, NEGATESHIFT) \
50
- static bool trans_##INSN(DisasContext *s, arg_2shift *a) \
51
- { \
52
- static MVEGenTwoOpShiftFn * const fns[] = { \
53
- gen_helper_mve_##FN##b, \
54
- gen_helper_mve_##FN##h, \
55
- gen_helper_mve_##FN##w, \
56
- NULL, \
57
- }; \
58
- return do_2shift(s, a, fns[a->size], NEGATESHIFT); \
59
+static bool do_2shift(DisasContext *s, arg_2shift *a, MVEGenTwoOpShiftFn fn,
60
+ bool negateshift)
61
+{
36
+{
62
+ return do_2shift_vec(s, a, fn, negateshift, NULL);
37
+ return FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, ECV) > 0;
63
+}
38
+}
64
+
39
+
65
+#define DO_2SHIFT_VEC(INSN, FN, NEGATESHIFT, VECFN) \
40
static inline bool isar_feature_aa64_vh(const ARMISARegisters *id)
66
+ static bool trans_##INSN(DisasContext *s, arg_2shift *a) \
41
{
67
+ { \
42
return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, VH) != 0;
68
+ static MVEGenTwoOpShiftFn * const fns[] = { \
43
diff --git a/target/arm/helper.c b/target/arm/helper.c
69
+ gen_helper_mve_##FN##b, \
44
index XXXXXXX..XXXXXXX 100644
70
+ gen_helper_mve_##FN##h, \
45
--- a/target/arm/helper.c
71
+ gen_helper_mve_##FN##w, \
46
+++ b/target/arm/helper.c
72
+ NULL, \
47
@@ -XXX,XX +XXX,XX @@ static CPAccessResult gt_counter_access(CPUARMState *env, int timeridx,
73
+ }; \
48
: !extract32(env->cp15.cnthctl_el2, 0, 1))) {
74
+ return do_2shift_vec(s, a, fns[a->size], NEGATESHIFT, VECFN); \
49
return CP_ACCESS_TRAP_EL2;
50
}
51
+ if (has_el2 && timeridx == GTIMER_VIRT) {
52
+ if (FIELD_EX64(env->cp15.cnthctl_el2, CNTHCTL, EL1TVCT)) {
53
+ return CP_ACCESS_TRAP_EL2;
54
+ }
55
+ }
56
break;
75
}
57
}
76
58
return CP_ACCESS_OK;
77
-DO_2SHIFT(VSHLI, vshli_u, false)
59
@@ -XXX,XX +XXX,XX @@ static CPAccessResult gt_timer_access(CPUARMState *env, int timeridx,
78
+#define DO_2SHIFT(INSN, FN, NEGATESHIFT) \
60
}
79
+ DO_2SHIFT_VEC(INSN, FN, NEGATESHIFT, NULL)
61
}
80
+
62
}
81
+static void do_gvec_shri_s(unsigned vece, uint32_t dofs, uint32_t aofs,
63
+ if (has_el2 && timeridx == GTIMER_VIRT) {
82
+ int64_t shift, uint32_t oprsz, uint32_t maxsz)
64
+ if (FIELD_EX64(env->cp15.cnthctl_el2, CNTHCTL, EL1TVT)) {
65
+ return CP_ACCESS_TRAP_EL2;
66
+ }
67
+ }
68
break;
69
}
70
return CP_ACCESS_OK;
71
@@ -XXX,XX +XXX,XX @@ static void gt_cnthctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
72
if (cpu_isar_feature(aa64_rme, cpu)) {
73
valid_mask |= R_CNTHCTL_CNTVMASK_MASK | R_CNTHCTL_CNTPMASK_MASK;
74
}
75
+ if (cpu_isar_feature(aa64_ecv_traps, cpu)) {
76
+ valid_mask |=
77
+ R_CNTHCTL_EL1TVT_MASK |
78
+ R_CNTHCTL_EL1TVCT_MASK |
79
+ R_CNTHCTL_EL1NVPCT_MASK |
80
+ R_CNTHCTL_EL1NVVCT_MASK |
81
+ R_CNTHCTL_EVNTIS_MASK;
82
+ }
83
84
/* Clear RES0 bits */
85
value &= valid_mask;
86
@@ -XXX,XX +XXX,XX @@ static CPAccessResult e2h_access(CPUARMState *env, const ARMCPRegInfo *ri,
87
{
88
if (arm_current_el(env) == 1) {
89
/* This must be a FEAT_NV access */
90
- /* TODO: FEAT_ECV will need to check CNTHCTL_EL2 here */
91
return CP_ACCESS_OK;
92
}
93
if (!(arm_hcr_el2_eff(env) & HCR_E2H)) {
94
@@ -XXX,XX +XXX,XX @@ static CPAccessResult e2h_access(CPUARMState *env, const ARMCPRegInfo *ri,
95
return CP_ACCESS_OK;
96
}
97
98
+static CPAccessResult access_el1nvpct(CPUARMState *env, const ARMCPRegInfo *ri,
99
+ bool isread)
83
+{
100
+{
84
+ /*
101
+ if (arm_current_el(env) == 1) {
85
+ * We get here with a negated shift count, and we must handle
102
+ /* This must be a FEAT_NV access with NVx == 101 */
86
+ * shifts by the element size, which tcg_gen_gvec_sari() does not do.
103
+ if (FIELD_EX64(env->cp15.cnthctl_el2, CNTHCTL, EL1NVPCT)) {
87
+ */
104
+ return CP_ACCESS_TRAP_EL2;
88
+ shift = -shift;
105
+ }
89
+ if (shift == (8 << vece)) {
90
+ shift--;
91
+ }
106
+ }
92
+ tcg_gen_gvec_sari(vece, dofs, aofs, shift, oprsz, maxsz);
107
+ return e2h_access(env, ri, isread);
93
+}
108
+}
94
+
109
+
95
+static void do_gvec_shri_u(unsigned vece, uint32_t dofs, uint32_t aofs,
110
+static CPAccessResult access_el1nvvct(CPUARMState *env, const ARMCPRegInfo *ri,
96
+ int64_t shift, uint32_t oprsz, uint32_t maxsz)
111
+ bool isread)
97
+{
112
+{
98
+ /*
113
+ if (arm_current_el(env) == 1) {
99
+ * We get here with a negated shift count, and we must handle
114
+ /* This must be a FEAT_NV access with NVx == 101 */
100
+ * shifts by the element size, which tcg_gen_gvec_shri() does not do.
115
+ if (FIELD_EX64(env->cp15.cnthctl_el2, CNTHCTL, EL1NVVCT)) {
101
+ */
116
+ return CP_ACCESS_TRAP_EL2;
102
+ shift = -shift;
117
+ }
103
+ if (shift == (8 << vece)) {
104
+ tcg_gen_gvec_dup_imm(vece, dofs, oprsz, maxsz, 0);
105
+ } else {
106
+ tcg_gen_gvec_shri(vece, dofs, aofs, shift, oprsz, maxsz);
107
+ }
118
+ }
119
+ return e2h_access(env, ri, isread);
108
+}
120
+}
109
+
121
+
110
+DO_2SHIFT_VEC(VSHLI, vshli_u, false, tcg_gen_gvec_shli)
122
/* Test if system register redirection is to occur in the current state. */
111
DO_2SHIFT(VQSHLI_S, vqshli_s, false)
123
static bool redirect_for_e2h(CPUARMState *env)
112
DO_2SHIFT(VQSHLI_U, vqshli_u, false)
124
{
113
DO_2SHIFT(VQSHLUI, vqshlui_s, false)
125
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo vhe_reginfo[] = {
114
/* These right shifts use a left-shift helper with negated shift count */
126
{ .name = "CNTP_CTL_EL02", .state = ARM_CP_STATE_AA64,
115
-DO_2SHIFT(VSHRI_S, vshli_s, true)
127
.opc0 = 3, .opc1 = 5, .crn = 14, .crm = 2, .opc2 = 1,
116
-DO_2SHIFT(VSHRI_U, vshli_u, true)
128
.type = ARM_CP_IO | ARM_CP_ALIAS,
117
+DO_2SHIFT_VEC(VSHRI_S, vshli_s, true, do_gvec_shri_s)
129
- .access = PL2_RW, .accessfn = e2h_access,
118
+DO_2SHIFT_VEC(VSHRI_U, vshli_u, true, do_gvec_shri_u)
130
+ .access = PL2_RW, .accessfn = access_el1nvpct,
119
DO_2SHIFT(VRSHRI_S, vrshli_s, true)
131
.nv2_redirect_offset = 0x180 | NV2_REDIR_NO_NV1,
120
DO_2SHIFT(VRSHRI_U, vrshli_u, true)
132
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].ctl),
121
133
.writefn = gt_phys_ctl_write, .raw_writefn = raw_write },
134
{ .name = "CNTV_CTL_EL02", .state = ARM_CP_STATE_AA64,
135
.opc0 = 3, .opc1 = 5, .crn = 14, .crm = 3, .opc2 = 1,
136
.type = ARM_CP_IO | ARM_CP_ALIAS,
137
- .access = PL2_RW, .accessfn = e2h_access,
138
+ .access = PL2_RW, .accessfn = access_el1nvvct,
139
.nv2_redirect_offset = 0x170 | NV2_REDIR_NO_NV1,
140
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].ctl),
141
.writefn = gt_virt_ctl_write, .raw_writefn = raw_write },
142
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo vhe_reginfo[] = {
143
.type = ARM_CP_IO | ARM_CP_ALIAS,
144
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].cval),
145
.nv2_redirect_offset = 0x178 | NV2_REDIR_NO_NV1,
146
- .access = PL2_RW, .accessfn = e2h_access,
147
+ .access = PL2_RW, .accessfn = access_el1nvpct,
148
.writefn = gt_phys_cval_write, .raw_writefn = raw_write },
149
{ .name = "CNTV_CVAL_EL02", .state = ARM_CP_STATE_AA64,
150
.opc0 = 3, .opc1 = 5, .crn = 14, .crm = 3, .opc2 = 2,
151
.type = ARM_CP_IO | ARM_CP_ALIAS,
152
.nv2_redirect_offset = 0x168 | NV2_REDIR_NO_NV1,
153
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].cval),
154
- .access = PL2_RW, .accessfn = e2h_access,
155
+ .access = PL2_RW, .accessfn = access_el1nvvct,
156
.writefn = gt_virt_cval_write, .raw_writefn = raw_write },
157
#endif
158
};
122
--
159
--
123
2.20.1
160
2.34.1
124
125
diff view generated by jsdifflib
1
Optimize the MVE shift-and-insert insns by using TCG
1
For FEAT_ECV, new registers CNTPCTSS_EL0 and CNTVCTSS_EL0 are
2
vector ops when possible.
2
defined, which are "self-synchronized" views of the physical and
3
virtual counts as seen in the CNTPCT_EL0 and CNTVCT_EL0 registers
4
(meaning that no barriers are needed around accesses to them to
5
ensure that reads of them do not occur speculatively and out-of-order
6
with other instructions).
7
8
For QEMU, all our system registers are self-synchronized, so we can
9
simply copy the existing implementation of CNTPCT_EL0 and CNTVCT_EL0
10
to the new register encodings.
11
12
This means we now implement all the functionality required for
13
ID_AA64MMFR0_EL1.ECV == 0b0001.
3
14
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
16
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20210913095440.13462-12-peter.maydell@linaro.org
17
Message-id: 20240301183219.2424889-7-peter.maydell@linaro.org
7
---
18
---
8
target/arm/translate-mve.c | 4 ++--
19
target/arm/helper.c | 43 +++++++++++++++++++++++++++++++++++++++++++
9
1 file changed, 2 insertions(+), 2 deletions(-)
20
1 file changed, 43 insertions(+)
10
21
11
diff --git a/target/arm/translate-mve.c b/target/arm/translate-mve.c
22
diff --git a/target/arm/helper.c b/target/arm/helper.c
12
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
13
--- a/target/arm/translate-mve.c
24
--- a/target/arm/helper.c
14
+++ b/target/arm/translate-mve.c
25
+++ b/target/arm/helper.c
15
@@ -XXX,XX +XXX,XX @@ DO_2SHIFT_VEC(VSHRI_U, vshli_u, true, do_gvec_shri_u)
26
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
16
DO_2SHIFT(VRSHRI_S, vrshli_s, true)
27
},
17
DO_2SHIFT(VRSHRI_U, vrshli_u, true)
28
};
18
29
19
-DO_2SHIFT(VSRI, vsri, false)
30
+/*
20
-DO_2SHIFT(VSLI, vsli, false)
31
+ * FEAT_ECV adds extra views of CNTVCT_EL0 and CNTPCT_EL0 which
21
+DO_2SHIFT_VEC(VSRI, vsri, false, gen_gvec_sri)
32
+ * are "self-synchronizing". For QEMU all sysregs are self-synchronizing,
22
+DO_2SHIFT_VEC(VSLI, vsli, false, gen_gvec_sli)
33
+ * so our implementations here are identical to the normal registers.
23
34
+ */
24
#define DO_2SHIFT_FP(INSN, FN) \
35
+static const ARMCPRegInfo gen_timer_ecv_cp_reginfo[] = {
25
static bool trans_##INSN(DisasContext *s, arg_2shift *a) \
36
+ { .name = "CNTVCTSS", .cp = 15, .crm = 14, .opc1 = 9,
37
+ .access = PL0_R, .type = ARM_CP_64BIT | ARM_CP_NO_RAW | ARM_CP_IO,
38
+ .accessfn = gt_vct_access,
39
+ .readfn = gt_virt_cnt_read, .resetfn = arm_cp_reset_ignore,
40
+ },
41
+ { .name = "CNTVCTSS_EL0", .state = ARM_CP_STATE_AA64,
42
+ .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 0, .opc2 = 6,
43
+ .access = PL0_R, .type = ARM_CP_NO_RAW | ARM_CP_IO,
44
+ .accessfn = gt_vct_access, .readfn = gt_virt_cnt_read,
45
+ },
46
+ { .name = "CNTPCTSS", .cp = 15, .crm = 14, .opc1 = 8,
47
+ .access = PL0_R, .type = ARM_CP_64BIT | ARM_CP_NO_RAW | ARM_CP_IO,
48
+ .accessfn = gt_pct_access,
49
+ .readfn = gt_cnt_read, .resetfn = arm_cp_reset_ignore,
50
+ },
51
+ { .name = "CNTPCTSS_EL0", .state = ARM_CP_STATE_AA64,
52
+ .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 0, .opc2 = 5,
53
+ .access = PL0_R, .type = ARM_CP_NO_RAW | ARM_CP_IO,
54
+ .accessfn = gt_pct_access, .readfn = gt_cnt_read,
55
+ },
56
+};
57
+
58
#else
59
60
/*
61
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
62
},
63
};
64
65
+/*
66
+ * CNTVCTSS_EL0 has the same trap conditions as CNTVCT_EL0, so it also
67
+ * is exposed to userspace by Linux.
68
+ */
69
+static const ARMCPRegInfo gen_timer_ecv_cp_reginfo[] = {
70
+ { .name = "CNTVCTSS_EL0", .state = ARM_CP_STATE_AA64,
71
+ .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 0, .opc2 = 6,
72
+ .access = PL0_R, .type = ARM_CP_NO_RAW | ARM_CP_IO,
73
+ .readfn = gt_virt_cnt_read,
74
+ },
75
+};
76
+
77
#endif
78
79
static void par_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
80
@@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu)
81
if (arm_feature(env, ARM_FEATURE_GENERIC_TIMER)) {
82
define_arm_cp_regs(cpu, generic_timer_cp_reginfo);
83
}
84
+ if (cpu_isar_feature(aa64_ecv_traps, cpu)) {
85
+ define_arm_cp_regs(cpu, gen_timer_ecv_cp_reginfo);
86
+ }
87
if (arm_feature(env, ARM_FEATURE_VAPA)) {
88
ARMCPRegInfo vapa_cp_reginfo[] = {
89
{ .name = "PAR", .cp = 15, .crn = 7, .crm = 4, .opc1 = 0, .opc2 = 0,
26
--
90
--
27
2.20.1
91
2.34.1
28
29
diff view generated by jsdifflib
1
Our current codegen for MVE always calls out to helper functions,
1
When ID_AA64MMFR0_EL1.ECV is 0b0010, a new register CNTPOFF_EL2 is
2
because some byte lanes might be predicated. The common case is that
2
implemented. This is similar to the existing CNTVOFF_EL2, except
3
in fact there is no predication active and all lanes should be
3
that it controls a hypervisor-adjustable offset made to the physical
4
updated together, so we can produce better code by detecting that and
4
counter and timer.
5
using the TCG generic vector infrastructure.
6
5
7
Add a TB flag that is set when we can guarantee that there is no
6
Implement the handling for this register, which includes control/trap
8
active MVE predication, and a bool in the DisasContext. Subsequent
7
bits in SCR_EL3 and CNTHCTL_EL2.
9
patches will use this flag to generate improved code for some
10
instructions.
11
12
In most cases when the predication state changes we simply end the TB
13
after that instruction. For the code called from vfp_access_check()
14
that handles lazy state preservation and creating a new FP context,
15
we can usually avoid having to try to end the TB because luckily the
16
new value of the flag following the register changes in those
17
sequences doesn't depend on any runtime decisions. We do have to end
18
the TB if the guest has enabled lazy FP state preservation but not
19
automatic state preservation, but this is an odd corner case that is
20
not going to be common in real-world code.
21
8
22
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
23
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
24
Message-id: 20210913095440.13462-4-peter.maydell@linaro.org
11
Message-id: 20240301183219.2424889-8-peter.maydell@linaro.org
25
---
12
---
26
target/arm/cpu.h | 4 +++-
13
target/arm/cpu-features.h | 5 +++
27
target/arm/translate.h | 2 ++
14
target/arm/cpu.h | 1 +
28
target/arm/helper.c | 33 +++++++++++++++++++++++++++++++++
15
target/arm/helper.c | 68 +++++++++++++++++++++++++++++++++++++--
29
target/arm/translate-m-nocp.c | 8 +++++++-
16
target/arm/trace-events | 1 +
30
target/arm/translate-mve.c | 13 ++++++++++++-
17
4 files changed, 73 insertions(+), 2 deletions(-)
31
target/arm/translate-vfp.c | 33 +++++++++++++++++++++++++++------
32
target/arm/translate.c | 8 ++++++++
33
7 files changed, 92 insertions(+), 9 deletions(-)
34
18
19
diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h
20
index XXXXXXX..XXXXXXX 100644
21
--- a/target/arm/cpu-features.h
22
+++ b/target/arm/cpu-features.h
23
@@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_ecv_traps(const ARMISARegisters *id)
24
return FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, ECV) > 0;
25
}
26
27
+static inline bool isar_feature_aa64_ecv(const ARMISARegisters *id)
28
+{
29
+ return FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, ECV) > 1;
30
+}
31
+
32
static inline bool isar_feature_aa64_vh(const ARMISARegisters *id)
33
{
34
return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, VH) != 0;
35
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
35
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
36
index XXXXXXX..XXXXXXX 100644
36
index XXXXXXX..XXXXXXX 100644
37
--- a/target/arm/cpu.h
37
--- a/target/arm/cpu.h
38
+++ b/target/arm/cpu.h
38
+++ b/target/arm/cpu.h
39
@@ -XXX,XX +XXX,XX @@ typedef ARMCPU ArchCPU;
39
@@ -XXX,XX +XXX,XX @@ typedef struct CPUArchState {
40
* | TBFLAG_AM32 | +-----+----------+
40
uint64_t c14_cntkctl; /* Timer Control register */
41
* | | |TBFLAG_M32|
41
uint64_t cnthctl_el2; /* Counter/Timer Hyp Control register */
42
* +-------------+----------------+----------+
42
uint64_t cntvoff_el2; /* Counter Virtual Offset register */
43
- * 31 23 5 4 0
43
+ uint64_t cntpoff_el2; /* Counter Physical Offset register */
44
+ * 31 23 6 5 0
44
ARMGenericTimer c14_timer[NUM_GTIMERS];
45
*
45
uint32_t c15_cpar; /* XScale Coprocessor Access Register */
46
* Unless otherwise noted, these bits are cached in env->hflags.
46
uint32_t c15_ticonfig; /* TI925T configuration byte. */
47
*/
48
@@ -XXX,XX +XXX,XX @@ FIELD(TBFLAG_M32, LSPACT, 2, 1) /* Not cached. */
49
FIELD(TBFLAG_M32, NEW_FP_CTXT_NEEDED, 3, 1) /* Not cached. */
50
/* Set if FPCCR.S does not match current security state */
51
FIELD(TBFLAG_M32, FPCCR_S_WRONG, 4, 1) /* Not cached. */
52
+/* Set if MVE insns are definitely not predicated by VPR or LTPSIZE */
53
+FIELD(TBFLAG_M32, MVE_NO_PRED, 5, 1) /* Not cached. */
54
55
/*
56
* Bit usage when in AArch64 state
57
diff --git a/target/arm/translate.h b/target/arm/translate.h
58
index XXXXXXX..XXXXXXX 100644
59
--- a/target/arm/translate.h
60
+++ b/target/arm/translate.h
61
@@ -XXX,XX +XXX,XX @@ typedef struct DisasContext {
62
bool align_mem;
63
/* True if PSTATE.IL is set */
64
bool pstate_il;
65
+ /* True if MVE insns are definitely not predicated by VPR or LTPSIZE */
66
+ bool mve_no_pred;
67
/*
68
* >= 0, a copy of PSTATE.BTYPE, which will be 0 without v8.5-BTI.
69
* < 0, set by the current instruction.
70
diff --git a/target/arm/helper.c b/target/arm/helper.c
47
diff --git a/target/arm/helper.c b/target/arm/helper.c
71
index XXXXXXX..XXXXXXX 100644
48
index XXXXXXX..XXXXXXX 100644
72
--- a/target/arm/helper.c
49
--- a/target/arm/helper.c
73
+++ b/target/arm/helper.c
50
+++ b/target/arm/helper.c
74
@@ -XXX,XX +XXX,XX @@ static inline void assert_hflags_rebuild_correctly(CPUARMState *env)
51
@@ -XXX,XX +XXX,XX @@ static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
75
#endif
52
if (cpu_isar_feature(aa64_rme, cpu)) {
53
valid_mask |= SCR_NSE | SCR_GPF;
54
}
55
+ if (cpu_isar_feature(aa64_ecv, cpu)) {
56
+ valid_mask |= SCR_ECVEN;
57
+ }
58
} else {
59
valid_mask &= ~(SCR_RW | SCR_ST);
60
if (cpu_isar_feature(aa32_ras, cpu)) {
61
@@ -XXX,XX +XXX,XX @@ void gt_rme_post_el_change(ARMCPU *cpu, void *ignored)
62
gt_update_irq(cpu, GTIMER_PHYS);
76
}
63
}
77
64
78
+static bool mve_no_pred(CPUARMState *env)
65
+static uint64_t gt_phys_raw_cnt_offset(CPUARMState *env)
79
+{
66
+{
80
+ /*
67
+ if ((env->cp15.scr_el3 & SCR_ECVEN) &&
81
+ * Return true if there is definitely no predication of MVE
68
+ FIELD_EX64(env->cp15.cnthctl_el2, CNTHCTL, ECV) &&
82
+ * instructions by VPR or LTPSIZE. (Returning false even if there
69
+ arm_is_el2_enabled(env) &&
83
+ * isn't any predication is OK; generated code will just be
70
+ (arm_hcr_el2_eff(env) & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE)) {
84
+ * a little worse.)
71
+ return env->cp15.cntpoff_el2;
85
+ * If the CPU does not implement MVE then this TB flag is always 0.
86
+ *
87
+ * NOTE: if you change this logic, the "recalculate s->mve_no_pred"
88
+ * logic in gen_update_fp_context() needs to be updated to match.
89
+ *
90
+ * We do not include the effect of the ECI bits here -- they are
91
+ * tracked in other TB flags. This simplifies the logic for
92
+ * "when did we emit code that changes the MVE_NO_PRED TB flag
93
+ * and thus need to end the TB?".
94
+ */
95
+ if (cpu_isar_feature(aa32_mve, env_archcpu(env))) {
96
+ return false;
97
+ }
72
+ }
98
+ if (env->v7m.vpr) {
73
+ return 0;
99
+ return false;
100
+ }
101
+ if (env->v7m.ltpsize < 4) {
102
+ return false;
103
+ }
104
+ return true;
105
+}
74
+}
106
+
75
+
107
void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
76
+static uint64_t gt_phys_cnt_offset(CPUARMState *env)
108
target_ulong *cs_base, uint32_t *pflags)
77
+{
78
+ if (arm_current_el(env) >= 2) {
79
+ return 0;
80
+ }
81
+ return gt_phys_raw_cnt_offset(env);
82
+}
83
+
84
static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
109
{
85
{
110
@@ -XXX,XX +XXX,XX @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
86
ARMGenericTimer *gt = &cpu->env.cp15.c14_timer[timeridx];
111
if (env->v7m.fpccr[is_secure] & R_V7M_FPCCR_LSPACT_MASK) {
87
@@ -XXX,XX +XXX,XX @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
112
DP_TBFLAG_M32(flags, LSPACT, 1);
88
* reset timer to when ISTATUS next has to change
113
}
89
*/
90
uint64_t offset = timeridx == GTIMER_VIRT ?
91
- cpu->env.cp15.cntvoff_el2 : 0;
92
+ cpu->env.cp15.cntvoff_el2 : gt_phys_raw_cnt_offset(&cpu->env);
93
uint64_t count = gt_get_countervalue(&cpu->env);
94
/* Note that this must be unsigned 64 bit arithmetic: */
95
int istatus = count - offset >= gt->cval;
96
@@ -XXX,XX +XXX,XX @@ static void gt_timer_reset(CPUARMState *env, const ARMCPRegInfo *ri,
97
98
static uint64_t gt_cnt_read(CPUARMState *env, const ARMCPRegInfo *ri)
99
{
100
- return gt_get_countervalue(env);
101
+ return gt_get_countervalue(env) - gt_phys_cnt_offset(env);
102
}
103
104
static uint64_t gt_virt_cnt_offset(CPUARMState *env)
105
@@ -XXX,XX +XXX,XX @@ static uint64_t gt_tval_read(CPUARMState *env, const ARMCPRegInfo *ri,
106
case GTIMER_HYPVIRT:
107
offset = gt_virt_cnt_offset(env);
108
break;
109
+ case GTIMER_PHYS:
110
+ offset = gt_phys_cnt_offset(env);
111
+ break;
112
}
113
114
return (uint32_t)(env->cp15.c14_timer[timeridx].cval -
115
@@ -XXX,XX +XXX,XX @@ static void gt_tval_write(CPUARMState *env, const ARMCPRegInfo *ri,
116
case GTIMER_HYPVIRT:
117
offset = gt_virt_cnt_offset(env);
118
break;
119
+ case GTIMER_PHYS:
120
+ offset = gt_phys_cnt_offset(env);
121
+ break;
122
}
123
124
trace_arm_gt_tval_write(timeridx, value);
125
@@ -XXX,XX +XXX,XX @@ static void gt_cnthctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
126
R_CNTHCTL_EL1NVVCT_MASK |
127
R_CNTHCTL_EVNTIS_MASK;
128
}
129
+ if (cpu_isar_feature(aa64_ecv, cpu)) {
130
+ valid_mask |= R_CNTHCTL_ECV_MASK;
131
+ }
132
133
/* Clear RES0 bits */
134
value &= valid_mask;
135
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo gen_timer_ecv_cp_reginfo[] = {
136
},
137
};
138
139
+static CPAccessResult gt_cntpoff_access(CPUARMState *env,
140
+ const ARMCPRegInfo *ri,
141
+ bool isread)
142
+{
143
+ if (arm_current_el(env) == 2 && !(env->cp15.scr_el3 & SCR_ECVEN)) {
144
+ return CP_ACCESS_TRAP_EL3;
145
+ }
146
+ return CP_ACCESS_OK;
147
+}
114
+
148
+
115
+ if (mve_no_pred(env)) {
149
+static void gt_cntpoff_write(CPUARMState *env, const ARMCPRegInfo *ri,
116
+ DP_TBFLAG_M32(flags, MVE_NO_PRED, 1);
150
+ uint64_t value)
117
+ }
151
+{
118
} else {
152
+ ARMCPU *cpu = env_archcpu(env);
119
/*
153
+
120
* Note that XSCALE_CPAR shares bits with VECSTRIDE.
154
+ trace_arm_gt_cntpoff_write(value);
121
diff --git a/target/arm/translate-m-nocp.c b/target/arm/translate-m-nocp.c
155
+ raw_write(env, ri, value);
156
+ gt_recalc_timer(cpu, GTIMER_PHYS);
157
+}
158
+
159
+static const ARMCPRegInfo gen_timer_cntpoff_reginfo = {
160
+ .name = "CNTPOFF_EL2", .state = ARM_CP_STATE_AA64,
161
+ .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 0, .opc2 = 6,
162
+ .access = PL2_RW, .type = ARM_CP_IO, .resetvalue = 0,
163
+ .accessfn = gt_cntpoff_access, .writefn = gt_cntpoff_write,
164
+ .nv2_redirect_offset = 0x1a8,
165
+ .fieldoffset = offsetof(CPUARMState, cp15.cntpoff_el2),
166
+};
167
#else
168
169
/*
170
@@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu)
171
if (cpu_isar_feature(aa64_ecv_traps, cpu)) {
172
define_arm_cp_regs(cpu, gen_timer_ecv_cp_reginfo);
173
}
174
+#ifndef CONFIG_USER_ONLY
175
+ if (cpu_isar_feature(aa64_ecv, cpu)) {
176
+ define_one_arm_cp_reg(cpu, &gen_timer_cntpoff_reginfo);
177
+ }
178
+#endif
179
if (arm_feature(env, ARM_FEATURE_VAPA)) {
180
ARMCPRegInfo vapa_cp_reginfo[] = {
181
{ .name = "PAR", .cp = 15, .crn = 7, .crm = 4, .opc1 = 0, .opc2 = 0,
182
diff --git a/target/arm/trace-events b/target/arm/trace-events
122
index XXXXXXX..XXXXXXX 100644
183
index XXXXXXX..XXXXXXX 100644
123
--- a/target/arm/translate-m-nocp.c
184
--- a/target/arm/trace-events
124
+++ b/target/arm/translate-m-nocp.c
185
+++ b/target/arm/trace-events
125
@@ -XXX,XX +XXX,XX @@ static bool trans_VLLDM_VLSTM(DisasContext *s, arg_VLLDM_VLSTM *a)
186
@@ -XXX,XX +XXX,XX @@ arm_gt_tval_write(int timer, uint64_t value) "gt_tval_write: timer %d value 0x%"
126
187
arm_gt_ctl_write(int timer, uint64_t value) "gt_ctl_write: timer %d value 0x%" PRIx64
127
clear_eci_state(s);
188
arm_gt_imask_toggle(int timer) "gt_ctl_write: timer %d IMASK toggle"
128
189
arm_gt_cntvoff_write(uint64_t value) "gt_cntvoff_write: value 0x%" PRIx64
129
- /* End the TB, because we have updated FP control bits */
190
+arm_gt_cntpoff_write(uint64_t value) "gt_cntpoff_write: value 0x%" PRIx64
130
+ /*
191
arm_gt_update_irq(int timer, int irqstate) "gt_update_irq: timer %d irqstate %d"
131
+ * End the TB, because we have updated FP control bits,
192
132
+ * and possibly VPR or LTPSIZE.
193
# kvm.c
133
+ */
134
s->base.is_jmp = DISAS_UPDATE_EXIT;
135
return true;
136
}
137
@@ -XXX,XX +XXX,XX @@ static bool gen_M_fp_sysreg_write(DisasContext *s, int regno,
138
store_cpu_field(control, v7m.control[M_REG_S]);
139
tcg_gen_andi_i32(tmp, tmp, ~FPCR_NZCV_MASK);
140
gen_helper_vfp_set_fpscr(cpu_env, tmp);
141
+ s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
142
tcg_temp_free_i32(tmp);
143
tcg_temp_free_i32(sfpa);
144
break;
145
@@ -XXX,XX +XXX,XX @@ static bool gen_M_fp_sysreg_write(DisasContext *s, int regno,
146
}
147
tmp = loadfn(s, opaque, true);
148
store_cpu_field(tmp, v7m.vpr);
149
+ s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
150
break;
151
case ARM_VFP_P0:
152
{
153
@@ -XXX,XX +XXX,XX @@ static bool gen_M_fp_sysreg_write(DisasContext *s, int regno,
154
tcg_gen_deposit_i32(vpr, vpr, tmp,
155
R_V7M_VPR_P0_SHIFT, R_V7M_VPR_P0_LENGTH);
156
store_cpu_field(vpr, v7m.vpr);
157
+ s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
158
tcg_temp_free_i32(tmp);
159
break;
160
}
161
diff --git a/target/arm/translate-mve.c b/target/arm/translate-mve.c
162
index XXXXXXX..XXXXXXX 100644
163
--- a/target/arm/translate-mve.c
164
+++ b/target/arm/translate-mve.c
165
@@ -XXX,XX +XXX,XX @@ DO_LOGIC(VORR, gen_helper_mve_vorr)
166
DO_LOGIC(VORN, gen_helper_mve_vorn)
167
DO_LOGIC(VEOR, gen_helper_mve_veor)
168
169
-DO_LOGIC(VPSEL, gen_helper_mve_vpsel)
170
+static bool trans_VPSEL(DisasContext *s, arg_2op *a)
171
+{
172
+ /* This insn updates predication bits */
173
+ s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
174
+ return do_2op(s, a, gen_helper_mve_vpsel);
175
+}
176
177
#define DO_2OP(INSN, FN) \
178
static bool trans_##INSN(DisasContext *s, arg_2op *a) \
179
@@ -XXX,XX +XXX,XX @@ static bool trans_VPNOT(DisasContext *s, arg_VPNOT *a)
180
}
181
182
gen_helper_mve_vpnot(cpu_env);
183
+ /* This insn updates predication bits */
184
+ s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
185
mve_update_eci(s);
186
return true;
187
}
188
@@ -XXX,XX +XXX,XX @@ static bool do_vcmp(DisasContext *s, arg_vcmp *a, MVEGenCmpFn *fn)
189
/* VPT */
190
gen_vpst(s, a->mask);
191
}
192
+ /* This insn updates predication bits */
193
+ s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
194
mve_update_eci(s);
195
return true;
196
}
197
@@ -XXX,XX +XXX,XX @@ static bool do_vcmp_scalar(DisasContext *s, arg_vcmp_scalar *a,
198
/* VPT */
199
gen_vpst(s, a->mask);
200
}
201
+ /* This insn updates predication bits */
202
+ s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
203
mve_update_eci(s);
204
return true;
205
}
206
diff --git a/target/arm/translate-vfp.c b/target/arm/translate-vfp.c
207
index XXXXXXX..XXXXXXX 100644
208
--- a/target/arm/translate-vfp.c
209
+++ b/target/arm/translate-vfp.c
210
@@ -XXX,XX +XXX,XX @@ static inline long vfp_f16_offset(unsigned reg, bool top)
211
* Generate code for M-profile lazy FP state preservation if needed;
212
* this corresponds to the pseudocode PreserveFPState() function.
213
*/
214
-static void gen_preserve_fp_state(DisasContext *s)
215
+static void gen_preserve_fp_state(DisasContext *s, bool skip_context_update)
216
{
217
if (s->v7m_lspact) {
218
/*
219
@@ -XXX,XX +XXX,XX @@ static void gen_preserve_fp_state(DisasContext *s)
220
* any further FP insns in this TB.
221
*/
222
s->v7m_lspact = false;
223
+ /*
224
+ * The helper might have zeroed VPR, so we do not know the
225
+ * correct value for the MVE_NO_PRED TB flag any more.
226
+ * If we're about to create a new fp context then that
227
+ * will precisely determine the MVE_NO_PRED value (see
228
+ * gen_update_fp_context()). Otherwise, we must:
229
+ * - set s->mve_no_pred to false, so this instruction
230
+ * is generated to use helper functions
231
+ * - end the TB now, without chaining to the next TB
232
+ */
233
+ if (skip_context_update || !s->v7m_new_fp_ctxt_needed) {
234
+ s->mve_no_pred = false;
235
+ s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
236
+ }
237
}
238
}
239
240
@@ -XXX,XX +XXX,XX @@ static void gen_update_fp_context(DisasContext *s)
241
TCGv_i32 z32 = tcg_const_i32(0);
242
store_cpu_field(z32, v7m.vpr);
243
}
244
-
245
/*
246
- * We don't need to arrange to end the TB, because the only
247
- * parts of FPSCR which we cache in the TB flags are the VECLEN
248
- * and VECSTRIDE, and those don't exist for M-profile.
249
+ * We just updated the FPSCR and VPR. Some of this state is cached
250
+ * in the MVE_NO_PRED TB flag. We want to avoid having to end the
251
+ * TB here, which means we need the new value of the MVE_NO_PRED
252
+ * flag to be exactly known here and the same for all executions.
253
+ * Luckily FPDSCR.LTPSIZE is always constant 4 and the VPR is
254
+ * always set to 0, so the new MVE_NO_PRED flag is always 1
255
+ * if and only if we have MVE.
256
+ *
257
+ * (The other FPSCR state cached in TB flags is VECLEN and VECSTRIDE,
258
+ * but those do not exist for M-profile, so are not relevant here.)
259
*/
260
+ s->mve_no_pred = dc_isar_feature(aa32_mve, s);
261
262
if (s->v8m_secure) {
263
bits |= R_V7M_CONTROL_SFPA_MASK;
264
@@ -XXX,XX +XXX,XX @@ bool vfp_access_check_m(DisasContext *s, bool skip_context_update)
265
/* Handle M-profile lazy FP state mechanics */
266
267
/* Trigger lazy-state preservation if necessary */
268
- gen_preserve_fp_state(s);
269
+ gen_preserve_fp_state(s, skip_context_update);
270
271
if (!skip_context_update) {
272
/* Update ownership of FP context and create new FP context if needed */
273
diff --git a/target/arm/translate.c b/target/arm/translate.c
274
index XXXXXXX..XXXXXXX 100644
275
--- a/target/arm/translate.c
276
+++ b/target/arm/translate.c
277
@@ -XXX,XX +XXX,XX @@ static bool trans_DLS(DisasContext *s, arg_DLS *a)
278
/* DLSTP: set FPSCR.LTPSIZE */
279
tmp = tcg_const_i32(a->size);
280
store_cpu_field(tmp, v7m.ltpsize);
281
+ s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
282
}
283
return true;
284
}
285
@@ -XXX,XX +XXX,XX @@ static bool trans_WLS(DisasContext *s, arg_WLS *a)
286
assert(ok);
287
tmp = tcg_const_i32(a->size);
288
store_cpu_field(tmp, v7m.ltpsize);
289
+ /*
290
+ * LTPSIZE updated, but MVE_NO_PRED will always be the same thing (0)
291
+ * when we take this upcoming exit from this TB, so gen_jmp_tb() is OK.
292
+ */
293
}
294
gen_jmp_tb(s, s->base.pc_next, 1);
295
296
@@ -XXX,XX +XXX,XX @@ static bool trans_VCTP(DisasContext *s, arg_VCTP *a)
297
gen_helper_mve_vctp(cpu_env, masklen);
298
tcg_temp_free_i32(masklen);
299
tcg_temp_free_i32(rn_shifted);
300
+ /* This insn updates predication bits */
301
+ s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
302
mve_update_eci(s);
303
return true;
304
}
305
@@ -XXX,XX +XXX,XX @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
306
dc->v7m_new_fp_ctxt_needed =
307
EX_TBFLAG_M32(tb_flags, NEW_FP_CTXT_NEEDED);
308
dc->v7m_lspact = EX_TBFLAG_M32(tb_flags, LSPACT);
309
+ dc->mve_no_pred = EX_TBFLAG_M32(tb_flags, MVE_NO_PRED);
310
} else {
311
dc->debug_target_el = EX_TBFLAG_ANY(tb_flags, DEBUG_TARGET_EL);
312
dc->sctlr_b = EX_TBFLAG_A32(tb_flags, SCTLR__B);
313
--
194
--
314
2.20.1
195
2.34.1
315
316
diff view generated by jsdifflib
1
Optimize the MVE VSHLL insns by using TCG vector ops when possible.
1
Enable all FEAT_ECV features on the 'max' CPU.
2
This includes the VMOVL insn, which we handle in mve.decode as "VSHLL
3
with zero shift count".
4
2
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20210913095440.13462-11-peter.maydell@linaro.org
6
Message-id: 20240301183219.2424889-9-peter.maydell@linaro.org
8
---
7
---
9
target/arm/translate-mve.c | 67 +++++++++++++++++++++++++++++++++-----
8
docs/system/arm/emulation.rst | 1 +
10
1 file changed, 59 insertions(+), 8 deletions(-)
9
target/arm/tcg/cpu64.c | 1 +
10
2 files changed, 2 insertions(+)
11
11
12
diff --git a/target/arm/translate-mve.c b/target/arm/translate-mve.c
12
diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst
13
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
14
--- a/target/arm/translate-mve.c
14
--- a/docs/system/arm/emulation.rst
15
+++ b/target/arm/translate-mve.c
15
+++ b/docs/system/arm/emulation.rst
16
@@ -XXX,XX +XXX,XX @@ DO_2SHIFT_SCALAR(VQSHL_U_scalar, vqshli_u)
16
@@ -XXX,XX +XXX,XX @@ the following architecture extensions:
17
DO_2SHIFT_SCALAR(VQRSHL_S_scalar, vqrshli_s)
17
- FEAT_DotProd (Advanced SIMD dot product instructions)
18
DO_2SHIFT_SCALAR(VQRSHL_U_scalar, vqrshli_u)
18
- FEAT_DoubleFault (Double Fault Extension)
19
19
- FEAT_E0PD (Preventing EL0 access to halves of address maps)
20
-#define DO_VSHLL(INSN, FN) \
20
+- FEAT_ECV (Enhanced Counter Virtualization)
21
- static bool trans_##INSN(DisasContext *s, arg_2shift *a) \
21
- FEAT_EPAC (Enhanced pointer authentication)
22
- { \
22
- FEAT_ETS (Enhanced Translation Synchronization)
23
- static MVEGenTwoOpShiftFn * const fns[] = { \
23
- FEAT_EVT (Enhanced Virtualization Traps)
24
- gen_helper_mve_##FN##b, \
24
diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c
25
- gen_helper_mve_##FN##h, \
25
index XXXXXXX..XXXXXXX 100644
26
- }; \
26
--- a/target/arm/tcg/cpu64.c
27
- return do_2shift(s, a, fns[a->size], false); \
27
+++ b/target/arm/tcg/cpu64.c
28
+#define DO_VSHLL(INSN, FN) \
28
@@ -XXX,XX +XXX,XX @@ void aarch64_max_tcg_initfn(Object *obj)
29
+ static bool trans_##INSN(DisasContext *s, arg_2shift *a) \
29
t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN64_2, 2); /* 64k stage2 supported */
30
+ { \
30
t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN4_2, 2); /* 4k stage2 supported */
31
+ static MVEGenTwoOpShiftFn * const fns[] = { \
31
t = FIELD_DP64(t, ID_AA64MMFR0, FGT, 1); /* FEAT_FGT */
32
+ gen_helper_mve_##FN##b, \
32
+ t = FIELD_DP64(t, ID_AA64MMFR0, ECV, 2); /* FEAT_ECV */
33
+ gen_helper_mve_##FN##h, \
33
cpu->isar.id_aa64mmfr0 = t;
34
+ }; \
34
35
+ return do_2shift_vec(s, a, fns[a->size], false, do_gvec_##FN); \
35
t = cpu->isar.id_aa64mmfr1;
36
}
37
38
+/*
39
+ * For the VSHLL vector helpers, the vece is the size of the input
40
+ * (ie MO_8 or MO_16); the helpers want to work in the output size.
41
+ * The shift count can be 0..<input size>, inclusive. (0 is VMOVL.)
42
+ */
43
+static void do_gvec_vshllbs(unsigned vece, uint32_t dofs, uint32_t aofs,
44
+ int64_t shift, uint32_t oprsz, uint32_t maxsz)
45
+{
46
+ unsigned ovece = vece + 1;
47
+ unsigned ibits = vece == MO_8 ? 8 : 16;
48
+ tcg_gen_gvec_shli(ovece, dofs, aofs, ibits, oprsz, maxsz);
49
+ tcg_gen_gvec_sari(ovece, dofs, dofs, ibits - shift, oprsz, maxsz);
50
+}
51
+
52
+static void do_gvec_vshllbu(unsigned vece, uint32_t dofs, uint32_t aofs,
53
+ int64_t shift, uint32_t oprsz, uint32_t maxsz)
54
+{
55
+ unsigned ovece = vece + 1;
56
+ tcg_gen_gvec_andi(ovece, dofs, aofs,
57
+ ovece == MO_16 ? 0xff : 0xffff, oprsz, maxsz);
58
+ tcg_gen_gvec_shli(ovece, dofs, dofs, shift, oprsz, maxsz);
59
+}
60
+
61
+static void do_gvec_vshllts(unsigned vece, uint32_t dofs, uint32_t aofs,
62
+ int64_t shift, uint32_t oprsz, uint32_t maxsz)
63
+{
64
+ unsigned ovece = vece + 1;
65
+ unsigned ibits = vece == MO_8 ? 8 : 16;
66
+ if (shift == 0) {
67
+ tcg_gen_gvec_sari(ovece, dofs, aofs, ibits, oprsz, maxsz);
68
+ } else {
69
+ tcg_gen_gvec_andi(ovece, dofs, aofs,
70
+ ovece == MO_16 ? 0xff00 : 0xffff0000, oprsz, maxsz);
71
+ tcg_gen_gvec_sari(ovece, dofs, dofs, ibits - shift, oprsz, maxsz);
72
+ }
73
+}
74
+
75
+static void do_gvec_vshlltu(unsigned vece, uint32_t dofs, uint32_t aofs,
76
+ int64_t shift, uint32_t oprsz, uint32_t maxsz)
77
+{
78
+ unsigned ovece = vece + 1;
79
+ unsigned ibits = vece == MO_8 ? 8 : 16;
80
+ if (shift == 0) {
81
+ tcg_gen_gvec_shri(ovece, dofs, aofs, ibits, oprsz, maxsz);
82
+ } else {
83
+ tcg_gen_gvec_andi(ovece, dofs, aofs,
84
+ ovece == MO_16 ? 0xff00 : 0xffff0000, oprsz, maxsz);
85
+ tcg_gen_gvec_shri(ovece, dofs, dofs, ibits - shift, oprsz, maxsz);
86
+ }
87
+}
88
+
89
DO_VSHLL(VSHLL_BS, vshllbs)
90
DO_VSHLL(VSHLL_BU, vshllbu)
91
DO_VSHLL(VSHLL_TS, vshllts)
92
--
36
--
93
2.20.1
37
2.34.1
94
38
95
39
diff view generated by jsdifflib
1
Now that we have working system register sync, we push more target CPU
1
From: Inès Varhol <ines.varhol@telecom-paris.fr>
2
properties into the virtual machine. That might be useful in some
3
situations, but is not the typical case that users want.
4
2
5
So let's add a -cpu host option that allows them to explicitly pass all
3
Features supported :
6
CPU capabilities of their host CPU into the guest.
4
- the 8 STM32L4x5 GPIOs are initialized with their reset values
5
(except IDR, see below)
6
- input mode : setting a pin in input mode "externally" (using input
7
irqs) results in an out irq (transmitted to SYSCFG)
8
- output mode : setting a bit in ODR sets the corresponding out irq
9
(if this line is configured in output mode)
10
- pull-up, pull-down
11
- push-pull, open-drain
7
12
8
Signed-off-by: Alexander Graf <agraf@csgraf.de>
13
Difference with the real GPIOs :
9
Acked-by: Roman Bolshakov <r.bolshakov@yadro.com>
14
- Alternate Function and Analog mode aren't implemented :
10
Reviewed-by: Sergio Lopez <slp@redhat.com>
15
pins in AF/Analog behave like pins in input mode
11
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
16
- floating pins stay at their last value
12
Message-id: 20210916155404.86958-7-agraf@csgraf.de
17
- register IDR reset values differ from the real one :
13
[PMM: drop unnecessary #include line from .h file]
18
values are coherent with the other registers reset values
19
and the fact that AF/Analog modes aren't implemented
20
- setting I/O output speed isn't supported
21
- locking port bits isn't supported
22
- ADC function isn't supported
23
- GPIOH has 16 pins instead of 2 pins
24
- writing to registers LCKR, AFRL, AFRH and ASCR is ineffective
25
26
Signed-off-by: Arnaud Minier <arnaud.minier@telecom-paris.fr>
27
Signed-off-by: Inès Varhol <ines.varhol@telecom-paris.fr>
28
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
29
Acked-by: Alistair Francis <alistair.francis@wdc.com>
30
Message-id: 20240305210444.310665-2-ines.varhol@telecom-paris.fr
14
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
31
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
---
32
---
16
target/arm/cpu.h | 2 +
33
MAINTAINERS | 1 +
17
target/arm/hvf_arm.h | 18 +++++++++
34
docs/system/arm/b-l475e-iot01a.rst | 2 +-
18
target/arm/kvm_arm.h | 2 -
35
include/hw/gpio/stm32l4x5_gpio.h | 70 +++++
19
target/arm/cpu.c | 13 ++++--
36
hw/gpio/stm32l4x5_gpio.c | 477 +++++++++++++++++++++++++++++
20
target/arm/hvf/hvf.c | 95 ++++++++++++++++++++++++++++++++++++++++++++
37
hw/gpio/Kconfig | 3 +
21
5 files changed, 124 insertions(+), 6 deletions(-)
38
hw/gpio/meson.build | 1 +
22
create mode 100644 target/arm/hvf_arm.h
39
hw/gpio/trace-events | 6 +
40
7 files changed, 559 insertions(+), 1 deletion(-)
41
create mode 100644 include/hw/gpio/stm32l4x5_gpio.h
42
create mode 100644 hw/gpio/stm32l4x5_gpio.c
23
43
24
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
44
diff --git a/MAINTAINERS b/MAINTAINERS
25
index XXXXXXX..XXXXXXX 100644
45
index XXXXXXX..XXXXXXX 100644
26
--- a/target/arm/cpu.h
46
--- a/MAINTAINERS
27
+++ b/target/arm/cpu.h
47
+++ b/MAINTAINERS
28
@@ -XXX,XX +XXX,XX @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync);
48
@@ -XXX,XX +XXX,XX @@ F: hw/arm/stm32l4x5_soc.c
29
#define ARM_CPU_TYPE_NAME(name) (name ARM_CPU_TYPE_SUFFIX)
49
F: hw/misc/stm32l4x5_exti.c
30
#define CPU_RESOLVING_TYPE TYPE_ARM_CPU
50
F: hw/misc/stm32l4x5_syscfg.c
31
51
F: hw/misc/stm32l4x5_rcc.c
32
+#define TYPE_ARM_HOST_CPU "host-" TYPE_ARM_CPU
52
+F: hw/gpio/stm32l4x5_gpio.c
33
+
53
F: include/hw/*/stm32l4x5_*.h
34
#define cpu_signal_handler cpu_arm_signal_handler
54
35
#define cpu_list arm_cpu_list
55
B-L475E-IOT01A IoT Node
36
56
diff --git a/docs/system/arm/b-l475e-iot01a.rst b/docs/system/arm/b-l475e-iot01a.rst
37
diff --git a/target/arm/hvf_arm.h b/target/arm/hvf_arm.h
57
index XXXXXXX..XXXXXXX 100644
58
--- a/docs/system/arm/b-l475e-iot01a.rst
59
+++ b/docs/system/arm/b-l475e-iot01a.rst
60
@@ -XXX,XX +XXX,XX @@ Currently B-L475E-IOT01A machine's only supports the following devices:
61
- STM32L4x5 EXTI (Extended interrupts and events controller)
62
- STM32L4x5 SYSCFG (System configuration controller)
63
- STM32L4x5 RCC (Reset and clock control)
64
+- STM32L4x5 GPIOs (General-purpose I/Os)
65
66
Missing devices
67
"""""""""""""""
68
@@ -XXX,XX +XXX,XX @@ Missing devices
69
The B-L475E-IOT01A does *not* support the following devices:
70
71
- Serial ports (UART)
72
-- General-purpose I/Os (GPIO)
73
- Analog to Digital Converter (ADC)
74
- SPI controller
75
- Timer controller (TIMER)
76
diff --git a/include/hw/gpio/stm32l4x5_gpio.h b/include/hw/gpio/stm32l4x5_gpio.h
38
new file mode 100644
77
new file mode 100644
39
index XXXXXXX..XXXXXXX
78
index XXXXXXX..XXXXXXX
40
--- /dev/null
79
--- /dev/null
41
+++ b/target/arm/hvf_arm.h
80
+++ b/include/hw/gpio/stm32l4x5_gpio.h
42
@@ -XXX,XX +XXX,XX @@
81
@@ -XXX,XX +XXX,XX @@
43
+/*
82
+/*
44
+ * QEMU Hypervisor.framework (HVF) support -- ARM specifics
83
+ * STM32L4x5 GPIO (General Purpose Input/Ouput)
45
+ *
84
+ *
46
+ * Copyright (c) 2021 Alexander Graf
85
+ * Copyright (c) 2024 Arnaud Minier <arnaud.minier@telecom-paris.fr>
86
+ * Copyright (c) 2024 Inès Varhol <ines.varhol@telecom-paris.fr>
87
+ *
88
+ * SPDX-License-Identifier: GPL-2.0-or-later
47
+ *
89
+ *
48
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
90
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
49
+ * See the COPYING file in the top-level directory.
91
+ * See the COPYING file in the top-level directory.
92
+ */
93
+
94
+/*
95
+ * The reference used is the STMicroElectronics RM0351 Reference manual
96
+ * for STM32L4x5 and STM32L4x6 advanced Arm ® -based 32-bit MCUs.
97
+ * https://www.st.com/en/microcontrollers-microprocessors/stm32l4x5/documentation.html
98
+ */
99
+
100
+#ifndef HW_STM32L4X5_GPIO_H
101
+#define HW_STM32L4X5_GPIO_H
102
+
103
+#include "hw/sysbus.h"
104
+#include "qom/object.h"
105
+
106
+#define TYPE_STM32L4X5_GPIO "stm32l4x5-gpio"
107
+OBJECT_DECLARE_SIMPLE_TYPE(Stm32l4x5GpioState, STM32L4X5_GPIO)
108
+
109
+#define GPIO_NUM_PINS 16
110
+
111
+struct Stm32l4x5GpioState {
112
+ SysBusDevice parent_obj;
113
+
114
+ MemoryRegion mmio;
115
+
116
+ /* GPIO registers */
117
+ uint32_t moder;
118
+ uint32_t otyper;
119
+ uint32_t ospeedr;
120
+ uint32_t pupdr;
121
+ uint32_t idr;
122
+ uint32_t odr;
123
+ uint32_t lckr;
124
+ uint32_t afrl;
125
+ uint32_t afrh;
126
+ uint32_t ascr;
127
+
128
+ /* GPIO registers reset values */
129
+ uint32_t moder_reset;
130
+ uint32_t ospeedr_reset;
131
+ uint32_t pupdr_reset;
132
+
133
+ /*
134
+ * External driving of pins.
135
+ * The pins can be set externally through the device
136
+ * anonymous input GPIOs lines under certain conditions.
137
+ * The pin must not be in push-pull output mode,
138
+ * and can't be set high in open-drain mode.
139
+ * Pins driven externally and configured to
140
+ * output mode will in general be "disconnected"
141
+ * (see `get_gpio_pinmask_to_disconnect()`)
142
+ */
143
+ uint16_t disconnected_pins;
144
+ uint16_t pins_connected_high;
145
+
146
+ char *name;
147
+ Clock *clk;
148
+ qemu_irq pin[GPIO_NUM_PINS];
149
+};
150
+
151
+#endif
152
diff --git a/hw/gpio/stm32l4x5_gpio.c b/hw/gpio/stm32l4x5_gpio.c
153
new file mode 100644
154
index XXXXXXX..XXXXXXX
155
--- /dev/null
156
+++ b/hw/gpio/stm32l4x5_gpio.c
157
@@ -XXX,XX +XXX,XX @@
158
+/*
159
+ * STM32L4x5 GPIO (General Purpose Input/Ouput)
50
+ *
160
+ *
161
+ * Copyright (c) 2024 Arnaud Minier <arnaud.minier@telecom-paris.fr>
162
+ * Copyright (c) 2024 Inès Varhol <ines.varhol@telecom-paris.fr>
163
+ *
164
+ * SPDX-License-Identifier: GPL-2.0-or-later
165
+ *
166
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
167
+ * See the COPYING file in the top-level directory.
51
+ */
168
+ */
52
+
169
+
53
+#ifndef QEMU_HVF_ARM_H
170
+/*
54
+#define QEMU_HVF_ARM_H
171
+ * The reference used is the STMicroElectronics RM0351 Reference manual
55
+
172
+ * for STM32L4x5 and STM32L4x6 advanced Arm ® -based 32-bit MCUs.
56
+#include "cpu.h"
173
+ * https://www.st.com/en/microcontrollers-microprocessors/stm32l4x5/documentation.html
57
+
174
+ */
58
+void hvf_arm_set_cpu_features_from_host(struct ARMCPU *cpu);
175
+
59
+
176
+#include "qemu/osdep.h"
60
+#endif
177
+#include "qemu/log.h"
61
diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
178
+#include "hw/gpio/stm32l4x5_gpio.h"
179
+#include "hw/irq.h"
180
+#include "hw/qdev-clock.h"
181
+#include "hw/qdev-properties.h"
182
+#include "qapi/visitor.h"
183
+#include "qapi/error.h"
184
+#include "migration/vmstate.h"
185
+#include "trace.h"
186
+
187
+#define GPIO_MODER 0x00
188
+#define GPIO_OTYPER 0x04
189
+#define GPIO_OSPEEDR 0x08
190
+#define GPIO_PUPDR 0x0C
191
+#define GPIO_IDR 0x10
192
+#define GPIO_ODR 0x14
193
+#define GPIO_BSRR 0x18
194
+#define GPIO_LCKR 0x1C
195
+#define GPIO_AFRL 0x20
196
+#define GPIO_AFRH 0x24
197
+#define GPIO_BRR 0x28
198
+#define GPIO_ASCR 0x2C
199
+
200
+/* 0b11111111_11111111_00000000_00000000 */
201
+#define RESERVED_BITS_MASK 0xFFFF0000
202
+
203
+static void update_gpio_idr(Stm32l4x5GpioState *s);
204
+
205
+static bool is_pull_up(Stm32l4x5GpioState *s, unsigned pin)
206
+{
207
+ return extract32(s->pupdr, 2 * pin, 2) == 1;
208
+}
209
+
210
+static bool is_pull_down(Stm32l4x5GpioState *s, unsigned pin)
211
+{
212
+ return extract32(s->pupdr, 2 * pin, 2) == 2;
213
+}
214
+
215
+static bool is_output(Stm32l4x5GpioState *s, unsigned pin)
216
+{
217
+ return extract32(s->moder, 2 * pin, 2) == 1;
218
+}
219
+
220
+static bool is_open_drain(Stm32l4x5GpioState *s, unsigned pin)
221
+{
222
+ return extract32(s->otyper, pin, 1) == 1;
223
+}
224
+
225
+static bool is_push_pull(Stm32l4x5GpioState *s, unsigned pin)
226
+{
227
+ return extract32(s->otyper, pin, 1) == 0;
228
+}
229
+
230
+static void stm32l4x5_gpio_reset_hold(Object *obj)
231
+{
232
+ Stm32l4x5GpioState *s = STM32L4X5_GPIO(obj);
233
+
234
+ s->moder = s->moder_reset;
235
+ s->otyper = 0x00000000;
236
+ s->ospeedr = s->ospeedr_reset;
237
+ s->pupdr = s->pupdr_reset;
238
+ s->idr = 0x00000000;
239
+ s->odr = 0x00000000;
240
+ s->lckr = 0x00000000;
241
+ s->afrl = 0x00000000;
242
+ s->afrh = 0x00000000;
243
+ s->ascr = 0x00000000;
244
+
245
+ s->disconnected_pins = 0xFFFF;
246
+ s->pins_connected_high = 0x0000;
247
+ update_gpio_idr(s);
248
+}
249
+
250
+static void stm32l4x5_gpio_set(void *opaque, int line, int level)
251
+{
252
+ Stm32l4x5GpioState *s = opaque;
253
+ /*
254
+ * The pin isn't set if line is configured in output mode
255
+ * except if level is 0 and the output is open-drain.
256
+ * This way there will be no short-circuit prone situations.
257
+ */
258
+ if (is_output(s, line) && !(is_open_drain(s, line) && (level == 0))) {
259
+ qemu_log_mask(LOG_GUEST_ERROR, "Line %d can't be driven externally\n",
260
+ line);
261
+ return;
262
+ }
263
+
264
+ s->disconnected_pins &= ~(1 << line);
265
+ if (level) {
266
+ s->pins_connected_high |= (1 << line);
267
+ } else {
268
+ s->pins_connected_high &= ~(1 << line);
269
+ }
270
+ trace_stm32l4x5_gpio_pins(s->name, s->disconnected_pins,
271
+ s->pins_connected_high);
272
+ update_gpio_idr(s);
273
+}
274
+
275
+
276
+static void update_gpio_idr(Stm32l4x5GpioState *s)
277
+{
278
+ uint32_t new_idr_mask = 0;
279
+ uint32_t new_idr = s->odr;
280
+ uint32_t old_idr = s->idr;
281
+ int new_pin_state, old_pin_state;
282
+
283
+ for (int i = 0; i < GPIO_NUM_PINS; i++) {
284
+ if (is_output(s, i)) {
285
+ if (is_push_pull(s, i)) {
286
+ new_idr_mask |= (1 << i);
287
+ } else if (!(s->odr & (1 << i))) {
288
+ /* open-drain ODR 0 */
289
+ new_idr_mask |= (1 << i);
290
+ /* open-drain ODR 1 */
291
+ } else if (!(s->disconnected_pins & (1 << i)) &&
292
+ !(s->pins_connected_high & (1 << i))) {
293
+ /* open-drain ODR 1 with pin connected low */
294
+ new_idr_mask |= (1 << i);
295
+ new_idr &= ~(1 << i);
296
+ /* open-drain ODR 1 with unactive pin */
297
+ } else if (is_pull_up(s, i)) {
298
+ new_idr_mask |= (1 << i);
299
+ } else if (is_pull_down(s, i)) {
300
+ new_idr_mask |= (1 << i);
301
+ new_idr &= ~(1 << i);
302
+ }
303
+ /*
304
+ * The only case left is for open-drain ODR 1
305
+ * with unactive pin without pull-up or pull-down :
306
+ * the value is floating.
307
+ */
308
+ /* input or analog mode with connected pin */
309
+ } else if (!(s->disconnected_pins & (1 << i))) {
310
+ if (s->pins_connected_high & (1 << i)) {
311
+ /* pin high */
312
+ new_idr_mask |= (1 << i);
313
+ new_idr |= (1 << i);
314
+ } else {
315
+ /* pin low */
316
+ new_idr_mask |= (1 << i);
317
+ new_idr &= ~(1 << i);
318
+ }
319
+ /* input or analog mode with disconnected pin */
320
+ } else {
321
+ if (is_pull_up(s, i)) {
322
+ /* pull-up */
323
+ new_idr_mask |= (1 << i);
324
+ new_idr |= (1 << i);
325
+ } else if (is_pull_down(s, i)) {
326
+ /* pull-down */
327
+ new_idr_mask |= (1 << i);
328
+ new_idr &= ~(1 << i);
329
+ }
330
+ /*
331
+ * The only case left is for a disconnected pin
332
+ * without pull-up or pull-down :
333
+ * the value is floating.
334
+ */
335
+ }
336
+ }
337
+
338
+ s->idr = (old_idr & ~new_idr_mask) | (new_idr & new_idr_mask);
339
+ trace_stm32l4x5_gpio_update_idr(s->name, old_idr, s->idr);
340
+
341
+ for (int i = 0; i < GPIO_NUM_PINS; i++) {
342
+ if (new_idr_mask & (1 << i)) {
343
+ new_pin_state = (new_idr & (1 << i)) > 0;
344
+ old_pin_state = (old_idr & (1 << i)) > 0;
345
+ if (new_pin_state > old_pin_state) {
346
+ qemu_irq_raise(s->pin[i]);
347
+ } else if (new_pin_state < old_pin_state) {
348
+ qemu_irq_lower(s->pin[i]);
349
+ }
350
+ }
351
+ }
352
+}
353
+
354
+/*
355
+ * Return mask of pins that are both configured in output
356
+ * mode and externally driven (except pins in open-drain
357
+ * mode externally set to 0).
358
+ */
359
+static uint32_t get_gpio_pinmask_to_disconnect(Stm32l4x5GpioState *s)
360
+{
361
+ uint32_t pins_to_disconnect = 0;
362
+ for (int i = 0; i < GPIO_NUM_PINS; i++) {
363
+ /* for each connected pin in output mode */
364
+ if (!(s->disconnected_pins & (1 << i)) && is_output(s, i)) {
365
+ /* if either push-pull or high level */
366
+ if (is_push_pull(s, i) || s->pins_connected_high & (1 << i)) {
367
+ pins_to_disconnect |= (1 << i);
368
+ qemu_log_mask(LOG_GUEST_ERROR,
369
+ "Line %d can't be driven externally\n",
370
+ i);
371
+ }
372
+ }
373
+ }
374
+ return pins_to_disconnect;
375
+}
376
+
377
+/*
378
+ * Set field `disconnected_pins` and call `update_gpio_idr()`
379
+ */
380
+static void disconnect_gpio_pins(Stm32l4x5GpioState *s, uint16_t lines)
381
+{
382
+ s->disconnected_pins |= lines;
383
+ trace_stm32l4x5_gpio_pins(s->name, s->disconnected_pins,
384
+ s->pins_connected_high);
385
+ update_gpio_idr(s);
386
+}
387
+
388
+static void disconnected_pins_set(Object *obj, Visitor *v,
389
+ const char *name, void *opaque, Error **errp)
390
+{
391
+ Stm32l4x5GpioState *s = STM32L4X5_GPIO(obj);
392
+ uint16_t value;
393
+ if (!visit_type_uint16(v, name, &value, errp)) {
394
+ return;
395
+ }
396
+ disconnect_gpio_pins(s, value);
397
+}
398
+
399
+static void disconnected_pins_get(Object *obj, Visitor *v,
400
+ const char *name, void *opaque, Error **errp)
401
+{
402
+ visit_type_uint16(v, name, (uint16_t *)opaque, errp);
403
+}
404
+
405
+static void clock_freq_get(Object *obj, Visitor *v,
406
+ const char *name, void *opaque, Error **errp)
407
+{
408
+ Stm32l4x5GpioState *s = STM32L4X5_GPIO(obj);
409
+ uint32_t clock_freq_hz = clock_get_hz(s->clk);
410
+ visit_type_uint32(v, name, &clock_freq_hz, errp);
411
+}
412
+
413
+static void stm32l4x5_gpio_write(void *opaque, hwaddr addr,
414
+ uint64_t val64, unsigned int size)
415
+{
416
+ Stm32l4x5GpioState *s = opaque;
417
+
418
+ uint32_t value = val64;
419
+ trace_stm32l4x5_gpio_write(s->name, addr, val64);
420
+
421
+ switch (addr) {
422
+ case GPIO_MODER:
423
+ s->moder = value;
424
+ disconnect_gpio_pins(s, get_gpio_pinmask_to_disconnect(s));
425
+ qemu_log_mask(LOG_UNIMP,
426
+ "%s: Analog and AF modes aren't supported\n\
427
+ Analog and AF mode behave like input mode\n",
428
+ __func__);
429
+ return;
430
+ case GPIO_OTYPER:
431
+ s->otyper = value & ~RESERVED_BITS_MASK;
432
+ disconnect_gpio_pins(s, get_gpio_pinmask_to_disconnect(s));
433
+ return;
434
+ case GPIO_OSPEEDR:
435
+ qemu_log_mask(LOG_UNIMP,
436
+ "%s: Changing I/O output speed isn't supported\n\
437
+ I/O speed is already maximal\n",
438
+ __func__);
439
+ s->ospeedr = value;
440
+ return;
441
+ case GPIO_PUPDR:
442
+ s->pupdr = value;
443
+ update_gpio_idr(s);
444
+ return;
445
+ case GPIO_IDR:
446
+ qemu_log_mask(LOG_UNIMP,
447
+ "%s: GPIO->IDR is read-only\n",
448
+ __func__);
449
+ return;
450
+ case GPIO_ODR:
451
+ s->odr = value & ~RESERVED_BITS_MASK;
452
+ update_gpio_idr(s);
453
+ return;
454
+ case GPIO_BSRR: {
455
+ uint32_t bits_to_reset = (value & RESERVED_BITS_MASK) >> GPIO_NUM_PINS;
456
+ uint32_t bits_to_set = value & ~RESERVED_BITS_MASK;
457
+ /* If both BSx and BRx are set, BSx has priority.*/
458
+ s->odr &= ~bits_to_reset;
459
+ s->odr |= bits_to_set;
460
+ update_gpio_idr(s);
461
+ return;
462
+ }
463
+ case GPIO_LCKR:
464
+ qemu_log_mask(LOG_UNIMP,
465
+ "%s: Locking port bits configuration isn't supported\n",
466
+ __func__);
467
+ s->lckr = value & ~RESERVED_BITS_MASK;
468
+ return;
469
+ case GPIO_AFRL:
470
+ qemu_log_mask(LOG_UNIMP,
471
+ "%s: Alternate functions aren't supported\n",
472
+ __func__);
473
+ s->afrl = value;
474
+ return;
475
+ case GPIO_AFRH:
476
+ qemu_log_mask(LOG_UNIMP,
477
+ "%s: Alternate functions aren't supported\n",
478
+ __func__);
479
+ s->afrh = value;
480
+ return;
481
+ case GPIO_BRR: {
482
+ uint32_t bits_to_reset = value & ~RESERVED_BITS_MASK;
483
+ s->odr &= ~bits_to_reset;
484
+ update_gpio_idr(s);
485
+ return;
486
+ }
487
+ case GPIO_ASCR:
488
+ qemu_log_mask(LOG_UNIMP,
489
+ "%s: ADC function isn't supported\n",
490
+ __func__);
491
+ s->ascr = value & ~RESERVED_BITS_MASK;
492
+ return;
493
+ default:
494
+ qemu_log_mask(LOG_GUEST_ERROR,
495
+ "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, addr);
496
+ }
497
+}
498
+
499
+static uint64_t stm32l4x5_gpio_read(void *opaque, hwaddr addr,
500
+ unsigned int size)
501
+{
502
+ Stm32l4x5GpioState *s = opaque;
503
+
504
+ trace_stm32l4x5_gpio_read(s->name, addr);
505
+
506
+ switch (addr) {
507
+ case GPIO_MODER:
508
+ return s->moder;
509
+ case GPIO_OTYPER:
510
+ return s->otyper;
511
+ case GPIO_OSPEEDR:
512
+ return s->ospeedr;
513
+ case GPIO_PUPDR:
514
+ return s->pupdr;
515
+ case GPIO_IDR:
516
+ return s->idr;
517
+ case GPIO_ODR:
518
+ return s->odr;
519
+ case GPIO_BSRR:
520
+ return 0;
521
+ case GPIO_LCKR:
522
+ return s->lckr;
523
+ case GPIO_AFRL:
524
+ return s->afrl;
525
+ case GPIO_AFRH:
526
+ return s->afrh;
527
+ case GPIO_BRR:
528
+ return 0;
529
+ case GPIO_ASCR:
530
+ return s->ascr;
531
+ default:
532
+ qemu_log_mask(LOG_GUEST_ERROR,
533
+ "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, addr);
534
+ return 0;
535
+ }
536
+}
537
+
538
+static const MemoryRegionOps stm32l4x5_gpio_ops = {
539
+ .read = stm32l4x5_gpio_read,
540
+ .write = stm32l4x5_gpio_write,
541
+ .endianness = DEVICE_NATIVE_ENDIAN,
542
+ .impl = {
543
+ .min_access_size = 4,
544
+ .max_access_size = 4,
545
+ .unaligned = false,
546
+ },
547
+ .valid = {
548
+ .min_access_size = 4,
549
+ .max_access_size = 4,
550
+ .unaligned = false,
551
+ },
552
+};
553
+
554
+static void stm32l4x5_gpio_init(Object *obj)
555
+{
556
+ Stm32l4x5GpioState *s = STM32L4X5_GPIO(obj);
557
+
558
+ memory_region_init_io(&s->mmio, obj, &stm32l4x5_gpio_ops, s,
559
+ TYPE_STM32L4X5_GPIO, 0x400);
560
+
561
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
562
+
563
+ qdev_init_gpio_out(DEVICE(obj), s->pin, GPIO_NUM_PINS);
564
+ qdev_init_gpio_in(DEVICE(obj), stm32l4x5_gpio_set, GPIO_NUM_PINS);
565
+
566
+ s->clk = qdev_init_clock_in(DEVICE(s), "clk", NULL, s, 0);
567
+
568
+ object_property_add(obj, "disconnected-pins", "uint16",
569
+ disconnected_pins_get, disconnected_pins_set,
570
+ NULL, &s->disconnected_pins);
571
+ object_property_add(obj, "clock-freq-hz", "uint32",
572
+ clock_freq_get, NULL, NULL, NULL);
573
+}
574
+
575
+static void stm32l4x5_gpio_realize(DeviceState *dev, Error **errp)
576
+{
577
+ Stm32l4x5GpioState *s = STM32L4X5_GPIO(dev);
578
+ if (!clock_has_source(s->clk)) {
579
+ error_setg(errp, "GPIO: clk input must be connected");
580
+ return;
581
+ }
582
+}
583
+
584
+static const VMStateDescription vmstate_stm32l4x5_gpio = {
585
+ .name = TYPE_STM32L4X5_GPIO,
586
+ .version_id = 1,
587
+ .minimum_version_id = 1,
588
+ .fields = (VMStateField[]){
589
+ VMSTATE_UINT32(moder, Stm32l4x5GpioState),
590
+ VMSTATE_UINT32(otyper, Stm32l4x5GpioState),
591
+ VMSTATE_UINT32(ospeedr, Stm32l4x5GpioState),
592
+ VMSTATE_UINT32(pupdr, Stm32l4x5GpioState),
593
+ VMSTATE_UINT32(idr, Stm32l4x5GpioState),
594
+ VMSTATE_UINT32(odr, Stm32l4x5GpioState),
595
+ VMSTATE_UINT32(lckr, Stm32l4x5GpioState),
596
+ VMSTATE_UINT32(afrl, Stm32l4x5GpioState),
597
+ VMSTATE_UINT32(afrh, Stm32l4x5GpioState),
598
+ VMSTATE_UINT32(ascr, Stm32l4x5GpioState),
599
+ VMSTATE_UINT16(disconnected_pins, Stm32l4x5GpioState),
600
+ VMSTATE_UINT16(pins_connected_high, Stm32l4x5GpioState),
601
+ VMSTATE_END_OF_LIST()
602
+ }
603
+};
604
+
605
+static Property stm32l4x5_gpio_properties[] = {
606
+ DEFINE_PROP_STRING("name", Stm32l4x5GpioState, name),
607
+ DEFINE_PROP_UINT32("mode-reset", Stm32l4x5GpioState, moder_reset, 0),
608
+ DEFINE_PROP_UINT32("ospeed-reset", Stm32l4x5GpioState, ospeedr_reset, 0),
609
+ DEFINE_PROP_UINT32("pupd-reset", Stm32l4x5GpioState, pupdr_reset, 0),
610
+ DEFINE_PROP_END_OF_LIST(),
611
+};
612
+
613
+static void stm32l4x5_gpio_class_init(ObjectClass *klass, void *data)
614
+{
615
+ DeviceClass *dc = DEVICE_CLASS(klass);
616
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
617
+
618
+ device_class_set_props(dc, stm32l4x5_gpio_properties);
619
+ dc->vmsd = &vmstate_stm32l4x5_gpio;
620
+ dc->realize = stm32l4x5_gpio_realize;
621
+ rc->phases.hold = stm32l4x5_gpio_reset_hold;
622
+}
623
+
624
+static const TypeInfo stm32l4x5_gpio_types[] = {
625
+ {
626
+ .name = TYPE_STM32L4X5_GPIO,
627
+ .parent = TYPE_SYS_BUS_DEVICE,
628
+ .instance_size = sizeof(Stm32l4x5GpioState),
629
+ .instance_init = stm32l4x5_gpio_init,
630
+ .class_init = stm32l4x5_gpio_class_init,
631
+ },
632
+};
633
+
634
+DEFINE_TYPES(stm32l4x5_gpio_types)
635
diff --git a/hw/gpio/Kconfig b/hw/gpio/Kconfig
62
index XXXXXXX..XXXXXXX 100644
636
index XXXXXXX..XXXXXXX 100644
63
--- a/target/arm/kvm_arm.h
637
--- a/hw/gpio/Kconfig
64
+++ b/target/arm/kvm_arm.h
638
+++ b/hw/gpio/Kconfig
65
@@ -XXX,XX +XXX,XX @@ bool kvm_arm_create_scratch_host_vcpu(const uint32_t *cpus_to_try,
639
@@ -XXX,XX +XXX,XX @@ config GPIO_PWR
66
*/
640
67
void kvm_arm_destroy_scratch_host_vcpu(int *fdarray);
641
config SIFIVE_GPIO
68
642
bool
69
-#define TYPE_ARM_HOST_CPU "host-" TYPE_ARM_CPU
643
+
70
-
644
+config STM32L4X5_GPIO
71
/**
645
+ bool
72
* ARMHostCPUFeatures: information about the host CPU (identified
646
diff --git a/hw/gpio/meson.build b/hw/gpio/meson.build
73
* by asking the host kernel)
74
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
75
index XXXXXXX..XXXXXXX 100644
647
index XXXXXXX..XXXXXXX 100644
76
--- a/target/arm/cpu.c
648
--- a/hw/gpio/meson.build
77
+++ b/target/arm/cpu.c
649
+++ b/hw/gpio/meson.build
78
@@ -XXX,XX +XXX,XX @@
650
@@ -XXX,XX +XXX,XX @@ system_ss.add(when: 'CONFIG_RASPI', if_true: files(
79
#include "sysemu/tcg.h"
651
'bcm2835_gpio.c',
80
#include "sysemu/hw_accel.h"
652
'bcm2838_gpio.c'
81
#include "kvm_arm.h"
653
))
82
+#include "hvf_arm.h"
654
+system_ss.add(when: 'CONFIG_STM32L4X5_SOC', if_true: files('stm32l4x5_gpio.c'))
83
#include "disas/capstone.h"
655
system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_gpio.c'))
84
#include "fpu/softfloat.h"
656
system_ss.add(when: 'CONFIG_SIFIVE_GPIO', if_true: files('sifive_gpio.c'))
85
657
diff --git a/hw/gpio/trace-events b/hw/gpio/trace-events
86
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
87
* this is the first point where we can report it.
88
*/
89
if (cpu->host_cpu_probe_failed) {
90
- if (!kvm_enabled()) {
91
- error_setg(errp, "The 'host' CPU type can only be used with KVM");
92
+ if (!kvm_enabled() && !hvf_enabled()) {
93
+ error_setg(errp, "The 'host' CPU type can only be used with KVM or HVF");
94
} else {
95
error_setg(errp, "Failed to retrieve host CPU features");
96
}
97
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
98
#endif /* CONFIG_TCG */
99
}
100
101
-#ifdef CONFIG_KVM
102
+#if defined(CONFIG_KVM) || defined(CONFIG_HVF)
103
static void arm_host_initfn(Object *obj)
104
{
105
ARMCPU *cpu = ARM_CPU(obj);
106
107
+#ifdef CONFIG_KVM
108
kvm_arm_set_cpu_features_from_host(cpu);
109
if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
110
aarch64_add_sve_properties(obj);
111
}
112
+#else
113
+ hvf_arm_set_cpu_features_from_host(cpu);
114
+#endif
115
arm_cpu_post_init(obj);
116
}
117
118
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_register_types(void)
119
{
120
type_register_static(&arm_cpu_type_info);
121
122
-#ifdef CONFIG_KVM
123
+#if defined(CONFIG_KVM) || defined(CONFIG_HVF)
124
type_register_static(&host_arm_cpu_type_info);
125
#endif
126
}
127
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
128
index XXXXXXX..XXXXXXX 100644
658
index XXXXXXX..XXXXXXX 100644
129
--- a/target/arm/hvf/hvf.c
659
--- a/hw/gpio/trace-events
130
+++ b/target/arm/hvf/hvf.c
660
+++ b/hw/gpio/trace-events
131
@@ -XXX,XX +XXX,XX @@
661
@@ -XXX,XX +XXX,XX @@ sifive_gpio_update_output_irq(int64_t line, int64_t value) "line %" PRIi64 " val
132
#include "sysemu/hvf.h"
662
# aspeed_gpio.c
133
#include "sysemu/hvf_int.h"
663
aspeed_gpio_read(uint64_t offset, uint64_t value) "offset: 0x%" PRIx64 " value 0x%" PRIx64
134
#include "sysemu/hw_accel.h"
664
aspeed_gpio_write(uint64_t offset, uint64_t value) "offset: 0x%" PRIx64 " value 0x%" PRIx64
135
+#include "hvf_arm.h"
665
+
136
666
+# stm32l4x5_gpio.c
137
#include <mach/mach_time.h>
667
+stm32l4x5_gpio_read(char *gpio, uint64_t addr) "GPIO%s addr: 0x%" PRIx64 " "
138
668
+stm32l4x5_gpio_write(char *gpio, uint64_t addr, uint64_t data) "GPIO%s addr: 0x%" PRIx64 " val: 0x%" PRIx64 ""
139
@@ -XXX,XX +XXX,XX @@ typedef struct HVFVTimer {
669
+stm32l4x5_gpio_update_idr(char *gpio, uint32_t old_idr, uint32_t new_idr) "GPIO%s from: 0x%x to: 0x%x"
140
670
+stm32l4x5_gpio_pins(char *gpio, uint16_t disconnected, uint16_t high) "GPIO%s disconnected pins: 0x%x levels: 0x%x"
141
static HVFVTimer vtimer;
142
143
+typedef struct ARMHostCPUFeatures {
144
+ ARMISARegisters isar;
145
+ uint64_t features;
146
+ uint64_t midr;
147
+ uint32_t reset_sctlr;
148
+ const char *dtb_compatible;
149
+} ARMHostCPUFeatures;
150
+
151
+static ARMHostCPUFeatures arm_host_cpu_features;
152
+
153
struct hvf_reg_match {
154
int reg;
155
uint64_t offset;
156
@@ -XXX,XX +XXX,XX @@ static uint64_t hvf_get_reg(CPUState *cpu, int rt)
157
return val;
158
}
159
160
+static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
161
+{
162
+ ARMISARegisters host_isar = {};
163
+ const struct isar_regs {
164
+ int reg;
165
+ uint64_t *val;
166
+ } regs[] = {
167
+ { HV_SYS_REG_ID_AA64PFR0_EL1, &host_isar.id_aa64pfr0 },
168
+ { HV_SYS_REG_ID_AA64PFR1_EL1, &host_isar.id_aa64pfr1 },
169
+ { HV_SYS_REG_ID_AA64DFR0_EL1, &host_isar.id_aa64dfr0 },
170
+ { HV_SYS_REG_ID_AA64DFR1_EL1, &host_isar.id_aa64dfr1 },
171
+ { HV_SYS_REG_ID_AA64ISAR0_EL1, &host_isar.id_aa64isar0 },
172
+ { HV_SYS_REG_ID_AA64ISAR1_EL1, &host_isar.id_aa64isar1 },
173
+ { HV_SYS_REG_ID_AA64MMFR0_EL1, &host_isar.id_aa64mmfr0 },
174
+ { HV_SYS_REG_ID_AA64MMFR1_EL1, &host_isar.id_aa64mmfr1 },
175
+ { HV_SYS_REG_ID_AA64MMFR2_EL1, &host_isar.id_aa64mmfr2 },
176
+ };
177
+ hv_vcpu_t fd;
178
+ hv_return_t r = HV_SUCCESS;
179
+ hv_vcpu_exit_t *exit;
180
+ int i;
181
+
182
+ ahcf->dtb_compatible = "arm,arm-v8";
183
+ ahcf->features = (1ULL << ARM_FEATURE_V8) |
184
+ (1ULL << ARM_FEATURE_NEON) |
185
+ (1ULL << ARM_FEATURE_AARCH64) |
186
+ (1ULL << ARM_FEATURE_PMU) |
187
+ (1ULL << ARM_FEATURE_GENERIC_TIMER);
188
+
189
+ /* We set up a small vcpu to extract host registers */
190
+
191
+ if (hv_vcpu_create(&fd, &exit, NULL) != HV_SUCCESS) {
192
+ return false;
193
+ }
194
+
195
+ for (i = 0; i < ARRAY_SIZE(regs); i++) {
196
+ r |= hv_vcpu_get_sys_reg(fd, regs[i].reg, regs[i].val);
197
+ }
198
+ r |= hv_vcpu_get_sys_reg(fd, HV_SYS_REG_MIDR_EL1, &ahcf->midr);
199
+ r |= hv_vcpu_destroy(fd);
200
+
201
+ ahcf->isar = host_isar;
202
+
203
+ /*
204
+ * A scratch vCPU returns SCTLR 0, so let's fill our default with the M1
205
+ * boot SCTLR from https://github.com/AsahiLinux/m1n1/issues/97
206
+ */
207
+ ahcf->reset_sctlr = 0x30100180;
208
+ /*
209
+ * SPAN is disabled by default when SCTLR.SPAN=1. To improve compatibility,
210
+ * let's disable it on boot and then allow guest software to turn it on by
211
+ * setting it to 0.
212
+ */
213
+ ahcf->reset_sctlr |= 0x00800000;
214
+
215
+ /* Make sure we don't advertise AArch32 support for EL0/EL1 */
216
+ if ((host_isar.id_aa64pfr0 & 0xff) != 0x11) {
217
+ return false;
218
+ }
219
+
220
+ return r == HV_SUCCESS;
221
+}
222
+
223
+void hvf_arm_set_cpu_features_from_host(ARMCPU *cpu)
224
+{
225
+ if (!arm_host_cpu_features.dtb_compatible) {
226
+ if (!hvf_enabled() ||
227
+ !hvf_arm_get_host_cpu_features(&arm_host_cpu_features)) {
228
+ /*
229
+ * We can't report this error yet, so flag that we need to
230
+ * in arm_cpu_realizefn().
231
+ */
232
+ cpu->host_cpu_probe_failed = true;
233
+ return;
234
+ }
235
+ }
236
+
237
+ cpu->dtb_compatible = arm_host_cpu_features.dtb_compatible;
238
+ cpu->isar = arm_host_cpu_features.isar;
239
+ cpu->env.features = arm_host_cpu_features.features;
240
+ cpu->midr = arm_host_cpu_features.midr;
241
+ cpu->reset_sctlr = arm_host_cpu_features.reset_sctlr;
242
+}
243
+
244
void hvf_arch_vcpu_destroy(CPUState *cpu)
245
{
246
}
247
--
671
--
248
2.20.1
672
2.34.1
249
673
250
674
diff view generated by jsdifflib
1
From: Alexander Graf <agraf@csgraf.de>
1
From: Inès Varhol <ines.varhol@telecom-paris.fr>
2
2
3
We can expose cycle counters on the PMU easily. To be as compatible as
3
Signed-off-by: Arnaud Minier <arnaud.minier@telecom-paris.fr>
4
possible, let's do so, but make sure we don't expose any other architectural
4
Signed-off-by: Inès Varhol <ines.varhol@telecom-paris.fr>
5
counters that we can not model yet.
5
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
6
6
Acked-by: Alistair Francis <alistair.francis@wdc.com>
7
This allows OSs to work that require PMU support.
7
Message-id: 20240305210444.310665-3-ines.varhol@telecom-paris.fr
8
9
Signed-off-by: Alexander Graf <agraf@csgraf.de>
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
11
Message-id: 20210916155404.86958-10-agraf@csgraf.de
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
---
9
---
14
target/arm/hvf/hvf.c | 179 +++++++++++++++++++++++++++++++++++++++++++
10
include/hw/arm/stm32l4x5_soc.h | 2 +
15
1 file changed, 179 insertions(+)
11
include/hw/gpio/stm32l4x5_gpio.h | 1 +
16
12
include/hw/misc/stm32l4x5_syscfg.h | 3 +-
17
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
13
hw/arm/stm32l4x5_soc.c | 71 +++++++++++++++++++++++-------
18
index XXXXXXX..XXXXXXX 100644
14
hw/misc/stm32l4x5_syscfg.c | 1 +
19
--- a/target/arm/hvf/hvf.c
15
hw/arm/Kconfig | 3 +-
20
+++ b/target/arm/hvf/hvf.c
16
6 files changed, 63 insertions(+), 18 deletions(-)
21
@@ -XXX,XX +XXX,XX @@
17
22
#define SYSREG_OSLSR_EL1 SYSREG(2, 0, 1, 1, 4)
18
diff --git a/include/hw/arm/stm32l4x5_soc.h b/include/hw/arm/stm32l4x5_soc.h
23
#define SYSREG_OSDLR_EL1 SYSREG(2, 0, 1, 3, 4)
19
index XXXXXXX..XXXXXXX 100644
24
#define SYSREG_CNTPCT_EL0 SYSREG(3, 3, 14, 0, 1)
20
--- a/include/hw/arm/stm32l4x5_soc.h
25
+#define SYSREG_PMCR_EL0 SYSREG(3, 3, 9, 12, 0)
21
+++ b/include/hw/arm/stm32l4x5_soc.h
26
+#define SYSREG_PMUSERENR_EL0 SYSREG(3, 3, 9, 14, 0)
22
@@ -XXX,XX +XXX,XX @@
27
+#define SYSREG_PMCNTENSET_EL0 SYSREG(3, 3, 9, 12, 1)
23
#include "hw/misc/stm32l4x5_syscfg.h"
28
+#define SYSREG_PMCNTENCLR_EL0 SYSREG(3, 3, 9, 12, 2)
24
#include "hw/misc/stm32l4x5_exti.h"
29
+#define SYSREG_PMINTENCLR_EL1 SYSREG(3, 0, 9, 14, 2)
25
#include "hw/misc/stm32l4x5_rcc.h"
30
+#define SYSREG_PMOVSCLR_EL0 SYSREG(3, 3, 9, 12, 3)
26
+#include "hw/gpio/stm32l4x5_gpio.h"
31
+#define SYSREG_PMSWINC_EL0 SYSREG(3, 3, 9, 12, 4)
27
#include "qom/object.h"
32
+#define SYSREG_PMSELR_EL0 SYSREG(3, 3, 9, 12, 5)
28
33
+#define SYSREG_PMCEID0_EL0 SYSREG(3, 3, 9, 12, 6)
29
#define TYPE_STM32L4X5_SOC "stm32l4x5-soc"
34
+#define SYSREG_PMCEID1_EL0 SYSREG(3, 3, 9, 12, 7)
30
@@ -XXX,XX +XXX,XX @@ struct Stm32l4x5SocState {
35
+#define SYSREG_PMCCNTR_EL0 SYSREG(3, 3, 9, 13, 0)
31
OrIRQState exti_or_gates[NUM_EXTI_OR_GATES];
36
+#define SYSREG_PMCCFILTR_EL0 SYSREG(3, 3, 14, 15, 7)
32
Stm32l4x5SyscfgState syscfg;
37
33
Stm32l4x5RccState rcc;
38
#define WFX_IS_WFE (1 << 0)
34
+ Stm32l4x5GpioState gpio[NUM_GPIOS];
39
35
40
@@ -XXX,XX +XXX,XX @@ static int hvf_sysreg_read(CPUState *cpu, uint32_t reg, uint32_t rt)
36
MemoryRegion sram1;
41
val = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) /
37
MemoryRegion sram2;
42
gt_cntfrq_period_ns(arm_cpu);
38
diff --git a/include/hw/gpio/stm32l4x5_gpio.h b/include/hw/gpio/stm32l4x5_gpio.h
43
break;
39
index XXXXXXX..XXXXXXX 100644
44
+ case SYSREG_PMCR_EL0:
40
--- a/include/hw/gpio/stm32l4x5_gpio.h
45
+ val = env->cp15.c9_pmcr;
41
+++ b/include/hw/gpio/stm32l4x5_gpio.h
46
+ break;
42
@@ -XXX,XX +XXX,XX @@
47
+ case SYSREG_PMCCNTR_EL0:
43
#define TYPE_STM32L4X5_GPIO "stm32l4x5-gpio"
48
+ pmu_op_start(env);
44
OBJECT_DECLARE_SIMPLE_TYPE(Stm32l4x5GpioState, STM32L4X5_GPIO)
49
+ val = env->cp15.c15_ccnt;
45
50
+ pmu_op_finish(env);
46
+#define NUM_GPIOS 8
51
+ break;
47
#define GPIO_NUM_PINS 16
52
+ case SYSREG_PMCNTENCLR_EL0:
48
53
+ val = env->cp15.c9_pmcnten;
49
struct Stm32l4x5GpioState {
54
+ break;
50
diff --git a/include/hw/misc/stm32l4x5_syscfg.h b/include/hw/misc/stm32l4x5_syscfg.h
55
+ case SYSREG_PMOVSCLR_EL0:
51
index XXXXXXX..XXXXXXX 100644
56
+ val = env->cp15.c9_pmovsr;
52
--- a/include/hw/misc/stm32l4x5_syscfg.h
57
+ break;
53
+++ b/include/hw/misc/stm32l4x5_syscfg.h
58
+ case SYSREG_PMSELR_EL0:
54
@@ -XXX,XX +XXX,XX @@
59
+ val = env->cp15.c9_pmselr;
55
60
+ break;
56
#include "hw/sysbus.h"
61
+ case SYSREG_PMINTENCLR_EL1:
57
#include "qom/object.h"
62
+ val = env->cp15.c9_pminten;
58
+#include "hw/gpio/stm32l4x5_gpio.h"
63
+ break;
59
64
+ case SYSREG_PMCCFILTR_EL0:
60
#define TYPE_STM32L4X5_SYSCFG "stm32l4x5-syscfg"
65
+ val = env->cp15.pmccfiltr_el0;
61
OBJECT_DECLARE_SIMPLE_TYPE(Stm32l4x5SyscfgState, STM32L4X5_SYSCFG)
66
+ break;
62
67
+ case SYSREG_PMCNTENSET_EL0:
63
-#define NUM_GPIOS 8
68
+ val = env->cp15.c9_pmcnten;
64
-#define GPIO_NUM_PINS 16
69
+ break;
65
#define SYSCFG_NUM_EXTICR 4
70
+ case SYSREG_PMUSERENR_EL0:
66
71
+ val = env->cp15.c9_pmuserenr;
67
struct Stm32l4x5SyscfgState {
72
+ break;
68
diff --git a/hw/arm/stm32l4x5_soc.c b/hw/arm/stm32l4x5_soc.c
73
+ case SYSREG_PMCEID0_EL0:
69
index XXXXXXX..XXXXXXX 100644
74
+ case SYSREG_PMCEID1_EL0:
70
--- a/hw/arm/stm32l4x5_soc.c
75
+ /* We can't really count anything yet, declare all events invalid */
71
+++ b/hw/arm/stm32l4x5_soc.c
76
+ val = 0;
72
@@ -XXX,XX +XXX,XX @@
77
+ break;
73
#include "sysemu/sysemu.h"
78
case SYSREG_OSLSR_EL1:
74
#include "hw/or-irq.h"
79
val = env->cp15.oslsr_el1;
75
#include "hw/arm/stm32l4x5_soc.h"
80
break;
76
+#include "hw/gpio/stm32l4x5_gpio.h"
81
@@ -XXX,XX +XXX,XX @@ static int hvf_sysreg_read(CPUState *cpu, uint32_t reg, uint32_t rt)
77
#include "hw/qdev-clock.h"
82
return 0;
78
#include "hw/misc/unimp.h"
79
80
@@ -XXX,XX +XXX,XX @@ static const int exti_or_gate1_lines_in[EXTI_OR_GATE1_NUM_LINES_IN] = {
81
16, 35, 36, 37, 38,
82
};
83
84
+static const struct {
85
+ uint32_t addr;
86
+ uint32_t moder_reset;
87
+ uint32_t ospeedr_reset;
88
+ uint32_t pupdr_reset;
89
+} stm32l4x5_gpio_cfg[NUM_GPIOS] = {
90
+ { 0x48000000, 0xABFFFFFF, 0x0C000000, 0x64000000 },
91
+ { 0x48000400, 0xFFFFFEBF, 0x00000000, 0x00000100 },
92
+ { 0x48000800, 0xFFFFFFFF, 0x00000000, 0x00000000 },
93
+ { 0x48000C00, 0xFFFFFFFF, 0x00000000, 0x00000000 },
94
+ { 0x48001000, 0xFFFFFFFF, 0x00000000, 0x00000000 },
95
+ { 0x48001400, 0xFFFFFFFF, 0x00000000, 0x00000000 },
96
+ { 0x48001800, 0xFFFFFFFF, 0x00000000, 0x00000000 },
97
+ { 0x48001C00, 0x0000000F, 0x00000000, 0x00000000 },
98
+};
99
+
100
static void stm32l4x5_soc_initfn(Object *obj)
101
{
102
Stm32l4x5SocState *s = STM32L4X5_SOC(obj);
103
@@ -XXX,XX +XXX,XX @@ static void stm32l4x5_soc_initfn(Object *obj)
104
}
105
object_initialize_child(obj, "syscfg", &s->syscfg, TYPE_STM32L4X5_SYSCFG);
106
object_initialize_child(obj, "rcc", &s->rcc, TYPE_STM32L4X5_RCC);
107
+
108
+ for (unsigned i = 0; i < NUM_GPIOS; i++) {
109
+ g_autofree char *name = g_strdup_printf("gpio%c", 'a' + i);
110
+ object_initialize_child(obj, name, &s->gpio[i], TYPE_STM32L4X5_GPIO);
111
+ }
83
}
112
}
84
113
85
+static void pmu_update_irq(CPUARMState *env)
114
static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp)
86
+{
115
@@ -XXX,XX +XXX,XX @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp)
87
+ ARMCPU *cpu = env_archcpu(env);
116
Stm32l4x5SocState *s = STM32L4X5_SOC(dev_soc);
88
+ qemu_set_irq(cpu->pmu_interrupt, (env->cp15.c9_pmcr & PMCRE) &&
117
const Stm32l4x5SocClass *sc = STM32L4X5_SOC_GET_CLASS(dev_soc);
89
+ (env->cp15.c9_pminten & env->cp15.c9_pmovsr));
118
MemoryRegion *system_memory = get_system_memory();
90
+}
119
- DeviceState *armv7m;
91
+
120
+ DeviceState *armv7m, *dev;
92
+static bool pmu_event_supported(uint16_t number)
121
SysBusDevice *busdev;
93
+{
122
+ uint32_t pin_index;
94
+ return false;
123
95
+}
124
if (!memory_region_init_rom(&s->flash, OBJECT(dev_soc), "flash",
96
+
125
sc->flash_size, errp)) {
97
+/* Returns true if the counter (pass 31 for PMCCNTR) should count events using
126
@@ -XXX,XX +XXX,XX @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp)
98
+ * the current EL, security state, and register configuration.
127
return;
99
+ */
128
}
100
+static bool pmu_counter_enabled(CPUARMState *env, uint8_t counter)
129
101
+{
130
+ /* GPIOs */
102
+ uint64_t filter;
131
+ for (unsigned i = 0; i < NUM_GPIOS; i++) {
103
+ bool enabled, filtered = true;
132
+ g_autofree char *name = g_strdup_printf("%c", 'A' + i);
104
+ int el = arm_current_el(env);
133
+ dev = DEVICE(&s->gpio[i]);
105
+
134
+ qdev_prop_set_string(dev, "name", name);
106
+ enabled = (env->cp15.c9_pmcr & PMCRE) &&
135
+ qdev_prop_set_uint32(dev, "mode-reset",
107
+ (env->cp15.c9_pmcnten & (1 << counter));
136
+ stm32l4x5_gpio_cfg[i].moder_reset);
108
+
137
+ qdev_prop_set_uint32(dev, "ospeed-reset",
109
+ if (counter == 31) {
138
+ stm32l4x5_gpio_cfg[i].ospeedr_reset);
110
+ filter = env->cp15.pmccfiltr_el0;
139
+ qdev_prop_set_uint32(dev, "pupd-reset",
111
+ } else {
140
+ stm32l4x5_gpio_cfg[i].pupdr_reset);
112
+ filter = env->cp15.c14_pmevtyper[counter];
141
+ busdev = SYS_BUS_DEVICE(&s->gpio[i]);
142
+ g_free(name);
143
+ name = g_strdup_printf("gpio%c-out", 'a' + i);
144
+ qdev_connect_clock_in(DEVICE(&s->gpio[i]), "clk",
145
+ qdev_get_clock_out(DEVICE(&(s->rcc)), name));
146
+ if (!sysbus_realize(busdev, errp)) {
147
+ return;
148
+ }
149
+ sysbus_mmio_map(busdev, 0, stm32l4x5_gpio_cfg[i].addr);
113
+ }
150
+ }
114
+
151
+
115
+ if (el == 0) {
152
/* System configuration controller */
116
+ filtered = filter & PMXEVTYPER_U;
153
busdev = SYS_BUS_DEVICE(&s->syscfg);
117
+ } else if (el == 1) {
154
if (!sysbus_realize(busdev, errp)) {
118
+ filtered = filter & PMXEVTYPER_P;
155
return;
119
+ }
156
}
120
+
157
sysbus_mmio_map(busdev, 0, SYSCFG_ADDR);
121
+ if (counter != 31) {
158
- /*
122
+ /*
159
- * TODO: when the GPIO device is implemented, connect it
123
+ * If not checking PMCCNTR, ensure the counter is setup to an event we
160
- * to SYCFG using `qdev_connect_gpio_out`, NUM_GPIOS and
124
+ * support
161
- * GPIO_NUM_PINS.
125
+ */
162
- */
126
+ uint16_t event = filter & PMXEVTYPER_EVTCOUNT;
163
+
127
+ if (!pmu_event_supported(event)) {
164
+ for (unsigned i = 0; i < NUM_GPIOS; i++) {
128
+ return false;
165
+ for (unsigned j = 0; j < GPIO_NUM_PINS; j++) {
166
+ pin_index = GPIO_NUM_PINS * i + j;
167
+ qdev_connect_gpio_out(DEVICE(&s->gpio[i]), j,
168
+ qdev_get_gpio_in(DEVICE(&s->syscfg),
169
+ pin_index));
129
+ }
170
+ }
130
+ }
171
+ }
131
+
172
132
+ return enabled && !filtered;
173
/* EXTI device */
133
+}
174
busdev = SYS_BUS_DEVICE(&s->exti);
134
+
175
@@ -XXX,XX +XXX,XX @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp)
135
+static void pmswinc_write(CPUARMState *env, uint64_t value)
176
}
136
+{
177
}
137
+ unsigned int i;
178
138
+ for (i = 0; i < pmu_num_counters(env); i++) {
179
- for (unsigned i = 0; i < 16; i++) {
139
+ /* Increment a counter's count iff: */
180
+ for (unsigned i = 0; i < GPIO_NUM_PINS; i++) {
140
+ if ((value & (1 << i)) && /* counter's bit is set */
181
qdev_connect_gpio_out(DEVICE(&s->syscfg), i,
141
+ /* counter is enabled and not filtered */
182
qdev_get_gpio_in(DEVICE(&s->exti), i));
142
+ pmu_counter_enabled(env, i) &&
183
}
143
+ /* counter is SW_INCR */
184
@@ -XXX,XX +XXX,XX @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp)
144
+ (env->cp15.c14_pmevtyper[i] & PMXEVTYPER_EVTCOUNT) == 0x0) {
185
/* RESERVED: 0x40024400, 0x7FDBC00 */
145
+ /*
186
146
+ * Detect if this write causes an overflow since we can't predict
187
/* AHB2 BUS */
147
+ * PMSWINC overflows like we can for other events
188
- create_unimplemented_device("GPIOA", 0x48000000, 0x400);
148
+ */
189
- create_unimplemented_device("GPIOB", 0x48000400, 0x400);
149
+ uint32_t new_pmswinc = env->cp15.c14_pmevcntr[i] + 1;
190
- create_unimplemented_device("GPIOC", 0x48000800, 0x400);
150
+
191
- create_unimplemented_device("GPIOD", 0x48000C00, 0x400);
151
+ if (env->cp15.c14_pmevcntr[i] & ~new_pmswinc & INT32_MIN) {
192
- create_unimplemented_device("GPIOE", 0x48001000, 0x400);
152
+ env->cp15.c9_pmovsr |= (1 << i);
193
- create_unimplemented_device("GPIOF", 0x48001400, 0x400);
153
+ pmu_update_irq(env);
194
- create_unimplemented_device("GPIOG", 0x48001800, 0x400);
154
+ }
195
- create_unimplemented_device("GPIOH", 0x48001C00, 0x400);
155
+
196
/* RESERVED: 0x48002000, 0x7FDBC00 */
156
+ env->cp15.c14_pmevcntr[i] = new_pmswinc;
197
create_unimplemented_device("OTG_FS", 0x50000000, 0x40000);
157
+ }
198
create_unimplemented_device("ADC", 0x50040000, 0x400);
158
+ }
199
diff --git a/hw/misc/stm32l4x5_syscfg.c b/hw/misc/stm32l4x5_syscfg.c
159
+}
200
index XXXXXXX..XXXXXXX 100644
160
+
201
--- a/hw/misc/stm32l4x5_syscfg.c
161
static int hvf_sysreg_write(CPUState *cpu, uint32_t reg, uint64_t val)
202
+++ b/hw/misc/stm32l4x5_syscfg.c
162
{
203
@@ -XXX,XX +XXX,XX @@
163
ARMCPU *arm_cpu = ARM_CPU(cpu);
204
#include "hw/irq.h"
164
@@ -XXX,XX +XXX,XX @@ static int hvf_sysreg_write(CPUState *cpu, uint32_t reg, uint64_t val)
205
#include "migration/vmstate.h"
165
val);
206
#include "hw/misc/stm32l4x5_syscfg.h"
166
207
+#include "hw/gpio/stm32l4x5_gpio.h"
167
switch (reg) {
208
168
+ case SYSREG_PMCCNTR_EL0:
209
#define SYSCFG_MEMRMP 0x00
169
+ pmu_op_start(env);
210
#define SYSCFG_CFGR1 0x04
170
+ env->cp15.c15_ccnt = val;
211
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
171
+ pmu_op_finish(env);
212
index XXXXXXX..XXXXXXX 100644
172
+ break;
213
--- a/hw/arm/Kconfig
173
+ case SYSREG_PMCR_EL0:
214
+++ b/hw/arm/Kconfig
174
+ pmu_op_start(env);
215
@@ -XXX,XX +XXX,XX @@ config STM32L4X5_SOC
175
+
216
bool
176
+ if (val & PMCRC) {
217
select ARM_V7M
177
+ /* The counter has been reset */
218
select OR_IRQ
178
+ env->cp15.c15_ccnt = 0;
219
- select STM32L4X5_SYSCFG
179
+ }
220
select STM32L4X5_EXTI
180
+
221
+ select STM32L4X5_SYSCFG
181
+ if (val & PMCRP) {
222
select STM32L4X5_RCC
182
+ unsigned int i;
223
+ select STM32L4X5_GPIO
183
+ for (i = 0; i < pmu_num_counters(env); i++) {
224
184
+ env->cp15.c14_pmevcntr[i] = 0;
225
config XLNX_ZYNQMP_ARM
185
+ }
226
bool
186
+ }
187
+
188
+ env->cp15.c9_pmcr &= ~PMCR_WRITEABLE_MASK;
189
+ env->cp15.c9_pmcr |= (val & PMCR_WRITEABLE_MASK);
190
+
191
+ pmu_op_finish(env);
192
+ break;
193
+ case SYSREG_PMUSERENR_EL0:
194
+ env->cp15.c9_pmuserenr = val & 0xf;
195
+ break;
196
+ case SYSREG_PMCNTENSET_EL0:
197
+ env->cp15.c9_pmcnten |= (val & pmu_counter_mask(env));
198
+ break;
199
+ case SYSREG_PMCNTENCLR_EL0:
200
+ env->cp15.c9_pmcnten &= ~(val & pmu_counter_mask(env));
201
+ break;
202
+ case SYSREG_PMINTENCLR_EL1:
203
+ pmu_op_start(env);
204
+ env->cp15.c9_pminten |= val;
205
+ pmu_op_finish(env);
206
+ break;
207
+ case SYSREG_PMOVSCLR_EL0:
208
+ pmu_op_start(env);
209
+ env->cp15.c9_pmovsr &= ~val;
210
+ pmu_op_finish(env);
211
+ break;
212
+ case SYSREG_PMSWINC_EL0:
213
+ pmu_op_start(env);
214
+ pmswinc_write(env, val);
215
+ pmu_op_finish(env);
216
+ break;
217
+ case SYSREG_PMSELR_EL0:
218
+ env->cp15.c9_pmselr = val & 0x1f;
219
+ break;
220
+ case SYSREG_PMCCFILTR_EL0:
221
+ pmu_op_start(env);
222
+ env->cp15.pmccfiltr_el0 = val & PMCCFILTR_EL0;
223
+ pmu_op_finish(env);
224
+ break;
225
case SYSREG_OSLAR_EL1:
226
env->cp15.oslsr_el1 = val & 1;
227
break;
228
--
227
--
229
2.20.1
228
2.34.1
230
229
231
230
diff view generated by jsdifflib
1
From: Alexander Graf <agraf@csgraf.de>
1
From: Inès Varhol <ines.varhol@telecom-paris.fr>
2
2
3
With Apple Silicon available to the masses, it's a good time to add support
3
The testcase contains :
4
for driving its virtualization extensions from QEMU.
4
- `test_idr_reset_value()` :
5
Checks the reset values of MODER, OTYPER, PUPDR, ODR and IDR.
6
- `test_gpio_output_mode()` :
7
Checks that writing a bit in register ODR results in the corresponding
8
pin rising or lowering, if this pin is configured in output mode.
9
- `test_gpio_input_mode()` :
10
Checks that a input pin set high or low externally results
11
in the pin rising and lowering.
12
- `test_pull_up_pull_down()` :
13
Checks that a floating pin in pull-up/down mode is actually high/down.
14
- `test_push_pull()` :
15
Checks that a pin set externally is disconnected when configured in
16
push-pull output mode, and can't be set externally while in this mode.
17
- `test_open_drain()` :
18
Checks that a pin set externally high is disconnected when configured
19
in open-drain output mode, and can't be set high while in this mode.
20
- `test_bsrr_brr()` :
21
Checks that writing to BSRR and BRR has the desired result in ODR.
22
- `test_clock_enable()` :
23
Checks that GPIO clock is at the right frequency after enabling it.
5
24
6
This patch adds all necessary architecture specific code to get basic VMs
25
Acked-by: Thomas Huth <thuth@redhat.com>
7
working, including save/restore.
26
Signed-off-by: Arnaud Minier <arnaud.minier@telecom-paris.fr>
8
27
Signed-off-by: Inès Varhol <ines.varhol@telecom-paris.fr>
9
Known limitations:
28
Message-id: 20240305210444.310665-4-ines.varhol@telecom-paris.fr
10
11
- WFI handling is missing (follows in later patch)
12
- No watchpoint/breakpoint support
13
14
Signed-off-by: Alexander Graf <agraf@csgraf.de>
15
Reviewed-by: Roman Bolshakov <r.bolshakov@yadro.com>
16
Reviewed-by: Sergio Lopez <slp@redhat.com>
17
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
18
Message-id: 20210916155404.86958-5-agraf@csgraf.de
19
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
29
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
20
---
30
---
21
meson.build | 1 +
31
tests/qtest/stm32l4x5_gpio-test.c | 551 ++++++++++++++++++++++++++++++
22
include/sysemu/hvf_int.h | 10 +-
32
tests/qtest/meson.build | 3 +-
23
accel/hvf/hvf-accel-ops.c | 9 +
33
2 files changed, 553 insertions(+), 1 deletion(-)
24
target/arm/hvf/hvf.c | 794 ++++++++++++++++++++++++++++++++++++
34
create mode 100644 tests/qtest/stm32l4x5_gpio-test.c
25
target/i386/hvf/hvf.c | 5 +
26
MAINTAINERS | 5 +
27
target/arm/hvf/trace-events | 10 +
28
7 files changed, 833 insertions(+), 1 deletion(-)
29
create mode 100644 target/arm/hvf/hvf.c
30
create mode 100644 target/arm/hvf/trace-events
31
35
32
diff --git a/meson.build b/meson.build
36
diff --git a/tests/qtest/stm32l4x5_gpio-test.c b/tests/qtest/stm32l4x5_gpio-test.c
33
index XXXXXXX..XXXXXXX 100644
34
--- a/meson.build
35
+++ b/meson.build
36
@@ -XXX,XX +XXX,XX @@ if have_system or have_user
37
'accel/tcg',
38
'hw/core',
39
'target/arm',
40
+ 'target/arm/hvf',
41
'target/hppa',
42
'target/i386',
43
'target/i386/kvm',
44
diff --git a/include/sysemu/hvf_int.h b/include/sysemu/hvf_int.h
45
index XXXXXXX..XXXXXXX 100644
46
--- a/include/sysemu/hvf_int.h
47
+++ b/include/sysemu/hvf_int.h
48
@@ -XXX,XX +XXX,XX @@
49
#ifndef HVF_INT_H
50
#define HVF_INT_H
51
52
+#ifdef __aarch64__
53
+#include <Hypervisor/Hypervisor.h>
54
+#else
55
#include <Hypervisor/hv.h>
56
+#endif
57
58
/* hvf_slot flags */
59
#define HVF_SLOT_LOG (1 << 0)
60
@@ -XXX,XX +XXX,XX @@ struct HVFState {
61
int num_slots;
62
63
hvf_vcpu_caps *hvf_caps;
64
+ uint64_t vtimer_offset;
65
};
66
extern HVFState *hvf_state;
67
68
struct hvf_vcpu_state {
69
- int fd;
70
+ uint64_t fd;
71
+ void *exit;
72
+ bool vtimer_masked;
73
};
74
75
void assert_hvf_ok(hv_return_t ret);
76
@@ -XXX,XX +XXX,XX @@ int hvf_vcpu_exec(CPUState *);
77
hvf_slot *hvf_find_overlap_slot(uint64_t, uint64_t);
78
int hvf_put_registers(CPUState *);
79
int hvf_get_registers(CPUState *);
80
+void hvf_kick_vcpu_thread(CPUState *cpu);
81
82
#endif
83
diff --git a/accel/hvf/hvf-accel-ops.c b/accel/hvf/hvf-accel-ops.c
84
index XXXXXXX..XXXXXXX 100644
85
--- a/accel/hvf/hvf-accel-ops.c
86
+++ b/accel/hvf/hvf-accel-ops.c
87
@@ -XXX,XX +XXX,XX @@
88
89
HVFState *hvf_state;
90
91
+#ifdef __aarch64__
92
+#define HV_VM_DEFAULT NULL
93
+#endif
94
+
95
/* Memory slots */
96
97
hvf_slot *hvf_find_overlap_slot(uint64_t start, uint64_t size)
98
@@ -XXX,XX +XXX,XX @@ static int hvf_init_vcpu(CPUState *cpu)
99
pthread_sigmask(SIG_BLOCK, NULL, &set);
100
sigdelset(&set, SIG_IPI);
101
102
+#ifdef __aarch64__
103
+ r = hv_vcpu_create(&cpu->hvf->fd, (hv_vcpu_exit_t **)&cpu->hvf->exit, NULL);
104
+#else
105
r = hv_vcpu_create((hv_vcpuid_t *)&cpu->hvf->fd, HV_VCPU_DEFAULT);
106
+#endif
107
cpu->vcpu_dirty = 1;
108
assert_hvf_ok(r);
109
110
@@ -XXX,XX +XXX,XX @@ static void hvf_accel_ops_class_init(ObjectClass *oc, void *data)
111
AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
112
113
ops->create_vcpu_thread = hvf_start_vcpu_thread;
114
+ ops->kick_vcpu_thread = hvf_kick_vcpu_thread;
115
116
ops->synchronize_post_reset = hvf_cpu_synchronize_post_reset;
117
ops->synchronize_post_init = hvf_cpu_synchronize_post_init;
118
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
119
new file mode 100644
37
new file mode 100644
120
index XXXXXXX..XXXXXXX
38
index XXXXXXX..XXXXXXX
121
--- /dev/null
39
--- /dev/null
122
+++ b/target/arm/hvf/hvf.c
40
+++ b/tests/qtest/stm32l4x5_gpio-test.c
123
@@ -XXX,XX +XXX,XX @@
41
@@ -XXX,XX +XXX,XX @@
124
+/*
42
+/*
125
+ * QEMU Hypervisor.framework support for Apple Silicon
43
+ * QTest testcase for STM32L4x5_GPIO
126
+
44
+ *
127
+ * Copyright 2020 Alexander Graf <agraf@csgraf.de>
45
+ * Copyright (c) 2024 Arnaud Minier <arnaud.minier@telecom-paris.fr>
46
+ * Copyright (c) 2024 Inès Varhol <ines.varhol@telecom-paris.fr>
128
+ *
47
+ *
129
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
48
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
130
+ * See the COPYING file in the top-level directory.
49
+ * See the COPYING file in the top-level directory.
131
+ *
132
+ */
50
+ */
133
+
51
+
134
+#include "qemu/osdep.h"
52
+#include "qemu/osdep.h"
135
+#include "qemu-common.h"
53
+#include "libqtest-single.h"
136
+#include "qemu/error-report.h"
54
+
137
+
55
+#define GPIO_BASE_ADDR 0x48000000
138
+#include "sysemu/runstate.h"
56
+#define GPIO_SIZE 0x400
139
+#include "sysemu/hvf.h"
57
+#define NUM_GPIOS 8
140
+#include "sysemu/hvf_int.h"
58
+#define NUM_GPIO_PINS 16
141
+#include "sysemu/hw_accel.h"
59
+
142
+
60
+#define GPIO_A 0x48000000
143
+#include <mach/mach_time.h>
61
+#define GPIO_B 0x48000400
144
+
62
+#define GPIO_C 0x48000800
145
+#include "exec/address-spaces.h"
63
+#define GPIO_D 0x48000C00
146
+#include "hw/irq.h"
64
+#define GPIO_E 0x48001000
147
+#include "qemu/main-loop.h"
65
+#define GPIO_F 0x48001400
148
+#include "sysemu/cpus.h"
66
+#define GPIO_G 0x48001800
149
+#include "target/arm/cpu.h"
67
+#define GPIO_H 0x48001C00
150
+#include "target/arm/internals.h"
68
+
151
+#include "trace/trace-target_arm_hvf.h"
69
+#define MODER 0x00
152
+#include "migration/vmstate.h"
70
+#define OTYPER 0x04
153
+
71
+#define PUPDR 0x0C
154
+#define HVF_SYSREG(crn, crm, op0, op1, op2) \
72
+#define IDR 0x10
155
+ ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP, crn, crm, op0, op1, op2)
73
+#define ODR 0x14
156
+#define PL1_WRITE_MASK 0x4
74
+#define BSRR 0x18
157
+
75
+#define BRR 0x28
158
+#define SYSREG(op0, op1, crn, crm, op2) \
76
+
159
+ ((op0 << 20) | (op2 << 17) | (op1 << 14) | (crn << 10) | (crm << 1))
77
+#define MODER_INPUT 0
160
+#define SYSREG_MASK SYSREG(0x3, 0x7, 0xf, 0xf, 0x7)
78
+#define MODER_OUTPUT 1
161
+#define SYSREG_OSLAR_EL1 SYSREG(2, 0, 1, 0, 4)
79
+
162
+#define SYSREG_OSLSR_EL1 SYSREG(2, 0, 1, 1, 4)
80
+#define PUPDR_NONE 0
163
+#define SYSREG_OSDLR_EL1 SYSREG(2, 0, 1, 3, 4)
81
+#define PUPDR_PULLUP 1
164
+#define SYSREG_CNTPCT_EL0 SYSREG(3, 3, 14, 0, 1)
82
+#define PUPDR_PULLDOWN 2
165
+
83
+
166
+#define WFX_IS_WFE (1 << 0)
84
+#define OTYPER_PUSH_PULL 0
167
+
85
+#define OTYPER_OPEN_DRAIN 1
168
+#define TMR_CTL_ENABLE (1 << 0)
86
+
169
+#define TMR_CTL_IMASK (1 << 1)
87
+const uint32_t moder_reset[NUM_GPIOS] = {
170
+#define TMR_CTL_ISTATUS (1 << 2)
88
+ 0xABFFFFFF,
171
+
89
+ 0xFFFFFEBF,
172
+typedef struct HVFVTimer {
90
+ 0xFFFFFFFF,
173
+ /* Vtimer value during migration and paused state */
91
+ 0xFFFFFFFF,
174
+ uint64_t vtimer_val;
92
+ 0xFFFFFFFF,
175
+} HVFVTimer;
93
+ 0xFFFFFFFF,
176
+
94
+ 0xFFFFFFFF,
177
+static HVFVTimer vtimer;
95
+ 0x0000000F
178
+
179
+struct hvf_reg_match {
180
+ int reg;
181
+ uint64_t offset;
182
+};
96
+};
183
+
97
+
184
+static const struct hvf_reg_match hvf_reg_match[] = {
98
+const uint32_t pupdr_reset[NUM_GPIOS] = {
185
+ { HV_REG_X0, offsetof(CPUARMState, xregs[0]) },
99
+ 0x64000000,
186
+ { HV_REG_X1, offsetof(CPUARMState, xregs[1]) },
100
+ 0x00000100,
187
+ { HV_REG_X2, offsetof(CPUARMState, xregs[2]) },
101
+ 0x00000000,
188
+ { HV_REG_X3, offsetof(CPUARMState, xregs[3]) },
102
+ 0x00000000,
189
+ { HV_REG_X4, offsetof(CPUARMState, xregs[4]) },
103
+ 0x00000000,
190
+ { HV_REG_X5, offsetof(CPUARMState, xregs[5]) },
104
+ 0x00000000,
191
+ { HV_REG_X6, offsetof(CPUARMState, xregs[6]) },
105
+ 0x00000000,
192
+ { HV_REG_X7, offsetof(CPUARMState, xregs[7]) },
106
+ 0x00000000
193
+ { HV_REG_X8, offsetof(CPUARMState, xregs[8]) },
194
+ { HV_REG_X9, offsetof(CPUARMState, xregs[9]) },
195
+ { HV_REG_X10, offsetof(CPUARMState, xregs[10]) },
196
+ { HV_REG_X11, offsetof(CPUARMState, xregs[11]) },
197
+ { HV_REG_X12, offsetof(CPUARMState, xregs[12]) },
198
+ { HV_REG_X13, offsetof(CPUARMState, xregs[13]) },
199
+ { HV_REG_X14, offsetof(CPUARMState, xregs[14]) },
200
+ { HV_REG_X15, offsetof(CPUARMState, xregs[15]) },
201
+ { HV_REG_X16, offsetof(CPUARMState, xregs[16]) },
202
+ { HV_REG_X17, offsetof(CPUARMState, xregs[17]) },
203
+ { HV_REG_X18, offsetof(CPUARMState, xregs[18]) },
204
+ { HV_REG_X19, offsetof(CPUARMState, xregs[19]) },
205
+ { HV_REG_X20, offsetof(CPUARMState, xregs[20]) },
206
+ { HV_REG_X21, offsetof(CPUARMState, xregs[21]) },
207
+ { HV_REG_X22, offsetof(CPUARMState, xregs[22]) },
208
+ { HV_REG_X23, offsetof(CPUARMState, xregs[23]) },
209
+ { HV_REG_X24, offsetof(CPUARMState, xregs[24]) },
210
+ { HV_REG_X25, offsetof(CPUARMState, xregs[25]) },
211
+ { HV_REG_X26, offsetof(CPUARMState, xregs[26]) },
212
+ { HV_REG_X27, offsetof(CPUARMState, xregs[27]) },
213
+ { HV_REG_X28, offsetof(CPUARMState, xregs[28]) },
214
+ { HV_REG_X29, offsetof(CPUARMState, xregs[29]) },
215
+ { HV_REG_X30, offsetof(CPUARMState, xregs[30]) },
216
+ { HV_REG_PC, offsetof(CPUARMState, pc) },
217
+};
107
+};
218
+
108
+
219
+static const struct hvf_reg_match hvf_fpreg_match[] = {
109
+const uint32_t idr_reset[NUM_GPIOS] = {
220
+ { HV_SIMD_FP_REG_Q0, offsetof(CPUARMState, vfp.zregs[0]) },
110
+ 0x0000A000,
221
+ { HV_SIMD_FP_REG_Q1, offsetof(CPUARMState, vfp.zregs[1]) },
111
+ 0x00000010,
222
+ { HV_SIMD_FP_REG_Q2, offsetof(CPUARMState, vfp.zregs[2]) },
112
+ 0x00000000,
223
+ { HV_SIMD_FP_REG_Q3, offsetof(CPUARMState, vfp.zregs[3]) },
113
+ 0x00000000,
224
+ { HV_SIMD_FP_REG_Q4, offsetof(CPUARMState, vfp.zregs[4]) },
114
+ 0x00000000,
225
+ { HV_SIMD_FP_REG_Q5, offsetof(CPUARMState, vfp.zregs[5]) },
115
+ 0x00000000,
226
+ { HV_SIMD_FP_REG_Q6, offsetof(CPUARMState, vfp.zregs[6]) },
116
+ 0x00000000,
227
+ { HV_SIMD_FP_REG_Q7, offsetof(CPUARMState, vfp.zregs[7]) },
117
+ 0x00000000
228
+ { HV_SIMD_FP_REG_Q8, offsetof(CPUARMState, vfp.zregs[8]) },
229
+ { HV_SIMD_FP_REG_Q9, offsetof(CPUARMState, vfp.zregs[9]) },
230
+ { HV_SIMD_FP_REG_Q10, offsetof(CPUARMState, vfp.zregs[10]) },
231
+ { HV_SIMD_FP_REG_Q11, offsetof(CPUARMState, vfp.zregs[11]) },
232
+ { HV_SIMD_FP_REG_Q12, offsetof(CPUARMState, vfp.zregs[12]) },
233
+ { HV_SIMD_FP_REG_Q13, offsetof(CPUARMState, vfp.zregs[13]) },
234
+ { HV_SIMD_FP_REG_Q14, offsetof(CPUARMState, vfp.zregs[14]) },
235
+ { HV_SIMD_FP_REG_Q15, offsetof(CPUARMState, vfp.zregs[15]) },
236
+ { HV_SIMD_FP_REG_Q16, offsetof(CPUARMState, vfp.zregs[16]) },
237
+ { HV_SIMD_FP_REG_Q17, offsetof(CPUARMState, vfp.zregs[17]) },
238
+ { HV_SIMD_FP_REG_Q18, offsetof(CPUARMState, vfp.zregs[18]) },
239
+ { HV_SIMD_FP_REG_Q19, offsetof(CPUARMState, vfp.zregs[19]) },
240
+ { HV_SIMD_FP_REG_Q20, offsetof(CPUARMState, vfp.zregs[20]) },
241
+ { HV_SIMD_FP_REG_Q21, offsetof(CPUARMState, vfp.zregs[21]) },
242
+ { HV_SIMD_FP_REG_Q22, offsetof(CPUARMState, vfp.zregs[22]) },
243
+ { HV_SIMD_FP_REG_Q23, offsetof(CPUARMState, vfp.zregs[23]) },
244
+ { HV_SIMD_FP_REG_Q24, offsetof(CPUARMState, vfp.zregs[24]) },
245
+ { HV_SIMD_FP_REG_Q25, offsetof(CPUARMState, vfp.zregs[25]) },
246
+ { HV_SIMD_FP_REG_Q26, offsetof(CPUARMState, vfp.zregs[26]) },
247
+ { HV_SIMD_FP_REG_Q27, offsetof(CPUARMState, vfp.zregs[27]) },
248
+ { HV_SIMD_FP_REG_Q28, offsetof(CPUARMState, vfp.zregs[28]) },
249
+ { HV_SIMD_FP_REG_Q29, offsetof(CPUARMState, vfp.zregs[29]) },
250
+ { HV_SIMD_FP_REG_Q30, offsetof(CPUARMState, vfp.zregs[30]) },
251
+ { HV_SIMD_FP_REG_Q31, offsetof(CPUARMState, vfp.zregs[31]) },
252
+};
118
+};
253
+
119
+
254
+struct hvf_sreg_match {
120
+static uint32_t gpio_readl(unsigned int gpio, unsigned int offset)
255
+ int reg;
121
+{
256
+ uint32_t key;
122
+ return readl(gpio + offset);
257
+ uint32_t cp_idx;
123
+}
258
+};
124
+
259
+
125
+static void gpio_writel(unsigned int gpio, unsigned int offset, uint32_t value)
260
+static struct hvf_sreg_match hvf_sreg_match[] = {
126
+{
261
+ { HV_SYS_REG_DBGBVR0_EL1, HVF_SYSREG(0, 0, 14, 0, 4) },
127
+ writel(gpio + offset, value);
262
+ { HV_SYS_REG_DBGBCR0_EL1, HVF_SYSREG(0, 0, 14, 0, 5) },
128
+}
263
+ { HV_SYS_REG_DBGWVR0_EL1, HVF_SYSREG(0, 0, 14, 0, 6) },
129
+
264
+ { HV_SYS_REG_DBGWCR0_EL1, HVF_SYSREG(0, 0, 14, 0, 7) },
130
+static void gpio_set_bit(unsigned int gpio, unsigned int reg,
265
+
131
+ unsigned int pin, uint32_t value)
266
+ { HV_SYS_REG_DBGBVR1_EL1, HVF_SYSREG(0, 1, 14, 0, 4) },
132
+{
267
+ { HV_SYS_REG_DBGBCR1_EL1, HVF_SYSREG(0, 1, 14, 0, 5) },
133
+ uint32_t mask = 0xFFFFFFFF & ~(0x1 << pin);
268
+ { HV_SYS_REG_DBGWVR1_EL1, HVF_SYSREG(0, 1, 14, 0, 6) },
134
+ gpio_writel(gpio, reg, (gpio_readl(gpio, reg) & mask) | value << pin);
269
+ { HV_SYS_REG_DBGWCR1_EL1, HVF_SYSREG(0, 1, 14, 0, 7) },
135
+}
270
+
136
+
271
+ { HV_SYS_REG_DBGBVR2_EL1, HVF_SYSREG(0, 2, 14, 0, 4) },
137
+static void gpio_set_2bits(unsigned int gpio, unsigned int reg,
272
+ { HV_SYS_REG_DBGBCR2_EL1, HVF_SYSREG(0, 2, 14, 0, 5) },
138
+ unsigned int pin, uint32_t value)
273
+ { HV_SYS_REG_DBGWVR2_EL1, HVF_SYSREG(0, 2, 14, 0, 6) },
139
+{
274
+ { HV_SYS_REG_DBGWCR2_EL1, HVF_SYSREG(0, 2, 14, 0, 7) },
140
+ uint32_t offset = 2 * pin;
275
+
141
+ uint32_t mask = 0xFFFFFFFF & ~(0x3 << offset);
276
+ { HV_SYS_REG_DBGBVR3_EL1, HVF_SYSREG(0, 3, 14, 0, 4) },
142
+ gpio_writel(gpio, reg, (gpio_readl(gpio, reg) & mask) | value << offset);
277
+ { HV_SYS_REG_DBGBCR3_EL1, HVF_SYSREG(0, 3, 14, 0, 5) },
143
+}
278
+ { HV_SYS_REG_DBGWVR3_EL1, HVF_SYSREG(0, 3, 14, 0, 6) },
144
+
279
+ { HV_SYS_REG_DBGWCR3_EL1, HVF_SYSREG(0, 3, 14, 0, 7) },
145
+static unsigned int get_gpio_id(uint32_t gpio_addr)
280
+
146
+{
281
+ { HV_SYS_REG_DBGBVR4_EL1, HVF_SYSREG(0, 4, 14, 0, 4) },
147
+ return (gpio_addr - GPIO_BASE_ADDR) / GPIO_SIZE;
282
+ { HV_SYS_REG_DBGBCR4_EL1, HVF_SYSREG(0, 4, 14, 0, 5) },
148
+}
283
+ { HV_SYS_REG_DBGWVR4_EL1, HVF_SYSREG(0, 4, 14, 0, 6) },
149
+
284
+ { HV_SYS_REG_DBGWCR4_EL1, HVF_SYSREG(0, 4, 14, 0, 7) },
150
+static void gpio_set_irq(unsigned int gpio, int num, int level)
285
+
151
+{
286
+ { HV_SYS_REG_DBGBVR5_EL1, HVF_SYSREG(0, 5, 14, 0, 4) },
152
+ g_autofree char *name = g_strdup_printf("/machine/soc/gpio%c",
287
+ { HV_SYS_REG_DBGBCR5_EL1, HVF_SYSREG(0, 5, 14, 0, 5) },
153
+ get_gpio_id(gpio) + 'a');
288
+ { HV_SYS_REG_DBGWVR5_EL1, HVF_SYSREG(0, 5, 14, 0, 6) },
154
+ qtest_set_irq_in(global_qtest, name, NULL, num, level);
289
+ { HV_SYS_REG_DBGWCR5_EL1, HVF_SYSREG(0, 5, 14, 0, 7) },
155
+}
290
+
156
+
291
+ { HV_SYS_REG_DBGBVR6_EL1, HVF_SYSREG(0, 6, 14, 0, 4) },
157
+static void disconnect_all_pins(unsigned int gpio)
292
+ { HV_SYS_REG_DBGBCR6_EL1, HVF_SYSREG(0, 6, 14, 0, 5) },
158
+{
293
+ { HV_SYS_REG_DBGWVR6_EL1, HVF_SYSREG(0, 6, 14, 0, 6) },
159
+ g_autofree char *path = g_strdup_printf("/machine/soc/gpio%c",
294
+ { HV_SYS_REG_DBGWCR6_EL1, HVF_SYSREG(0, 6, 14, 0, 7) },
160
+ get_gpio_id(gpio) + 'a');
295
+
161
+ QDict *r;
296
+ { HV_SYS_REG_DBGBVR7_EL1, HVF_SYSREG(0, 7, 14, 0, 4) },
162
+
297
+ { HV_SYS_REG_DBGBCR7_EL1, HVF_SYSREG(0, 7, 14, 0, 5) },
163
+ r = qtest_qmp(global_qtest, "{ 'execute': 'qom-set', 'arguments': "
298
+ { HV_SYS_REG_DBGWVR7_EL1, HVF_SYSREG(0, 7, 14, 0, 6) },
164
+ "{ 'path': %s, 'property': 'disconnected-pins', 'value': %d } }",
299
+ { HV_SYS_REG_DBGWCR7_EL1, HVF_SYSREG(0, 7, 14, 0, 7) },
165
+ path, 0xFFFF);
300
+
166
+ g_assert_false(qdict_haskey(r, "error"));
301
+ { HV_SYS_REG_DBGBVR8_EL1, HVF_SYSREG(0, 8, 14, 0, 4) },
167
+ qobject_unref(r);
302
+ { HV_SYS_REG_DBGBCR8_EL1, HVF_SYSREG(0, 8, 14, 0, 5) },
168
+}
303
+ { HV_SYS_REG_DBGWVR8_EL1, HVF_SYSREG(0, 8, 14, 0, 6) },
169
+
304
+ { HV_SYS_REG_DBGWCR8_EL1, HVF_SYSREG(0, 8, 14, 0, 7) },
170
+static uint32_t get_disconnected_pins(unsigned int gpio)
305
+
171
+{
306
+ { HV_SYS_REG_DBGBVR9_EL1, HVF_SYSREG(0, 9, 14, 0, 4) },
172
+ g_autofree char *path = g_strdup_printf("/machine/soc/gpio%c",
307
+ { HV_SYS_REG_DBGBCR9_EL1, HVF_SYSREG(0, 9, 14, 0, 5) },
173
+ get_gpio_id(gpio) + 'a');
308
+ { HV_SYS_REG_DBGWVR9_EL1, HVF_SYSREG(0, 9, 14, 0, 6) },
174
+ uint32_t disconnected_pins = 0;
309
+ { HV_SYS_REG_DBGWCR9_EL1, HVF_SYSREG(0, 9, 14, 0, 7) },
175
+ QDict *r;
310
+
176
+
311
+ { HV_SYS_REG_DBGBVR10_EL1, HVF_SYSREG(0, 10, 14, 0, 4) },
177
+ r = qtest_qmp(global_qtest, "{ 'execute': 'qom-get', 'arguments':"
312
+ { HV_SYS_REG_DBGBCR10_EL1, HVF_SYSREG(0, 10, 14, 0, 5) },
178
+ " { 'path': %s, 'property': 'disconnected-pins'} }", path);
313
+ { HV_SYS_REG_DBGWVR10_EL1, HVF_SYSREG(0, 10, 14, 0, 6) },
179
+ g_assert_false(qdict_haskey(r, "error"));
314
+ { HV_SYS_REG_DBGWCR10_EL1, HVF_SYSREG(0, 10, 14, 0, 7) },
180
+ disconnected_pins = qdict_get_int(r, "return");
315
+
181
+ qobject_unref(r);
316
+ { HV_SYS_REG_DBGBVR11_EL1, HVF_SYSREG(0, 11, 14, 0, 4) },
182
+ return disconnected_pins;
317
+ { HV_SYS_REG_DBGBCR11_EL1, HVF_SYSREG(0, 11, 14, 0, 5) },
183
+}
318
+ { HV_SYS_REG_DBGWVR11_EL1, HVF_SYSREG(0, 11, 14, 0, 6) },
184
+
319
+ { HV_SYS_REG_DBGWCR11_EL1, HVF_SYSREG(0, 11, 14, 0, 7) },
185
+static uint32_t reset(uint32_t gpio, unsigned int offset)
320
+
186
+{
321
+ { HV_SYS_REG_DBGBVR12_EL1, HVF_SYSREG(0, 12, 14, 0, 4) },
187
+ switch (offset) {
322
+ { HV_SYS_REG_DBGBCR12_EL1, HVF_SYSREG(0, 12, 14, 0, 5) },
188
+ case MODER:
323
+ { HV_SYS_REG_DBGWVR12_EL1, HVF_SYSREG(0, 12, 14, 0, 6) },
189
+ return moder_reset[get_gpio_id(gpio)];
324
+ { HV_SYS_REG_DBGWCR12_EL1, HVF_SYSREG(0, 12, 14, 0, 7) },
190
+ case PUPDR:
325
+
191
+ return pupdr_reset[get_gpio_id(gpio)];
326
+ { HV_SYS_REG_DBGBVR13_EL1, HVF_SYSREG(0, 13, 14, 0, 4) },
192
+ case IDR:
327
+ { HV_SYS_REG_DBGBCR13_EL1, HVF_SYSREG(0, 13, 14, 0, 5) },
193
+ return idr_reset[get_gpio_id(gpio)];
328
+ { HV_SYS_REG_DBGWVR13_EL1, HVF_SYSREG(0, 13, 14, 0, 6) },
329
+ { HV_SYS_REG_DBGWCR13_EL1, HVF_SYSREG(0, 13, 14, 0, 7) },
330
+
331
+ { HV_SYS_REG_DBGBVR14_EL1, HVF_SYSREG(0, 14, 14, 0, 4) },
332
+ { HV_SYS_REG_DBGBCR14_EL1, HVF_SYSREG(0, 14, 14, 0, 5) },
333
+ { HV_SYS_REG_DBGWVR14_EL1, HVF_SYSREG(0, 14, 14, 0, 6) },
334
+ { HV_SYS_REG_DBGWCR14_EL1, HVF_SYSREG(0, 14, 14, 0, 7) },
335
+
336
+ { HV_SYS_REG_DBGBVR15_EL1, HVF_SYSREG(0, 15, 14, 0, 4) },
337
+ { HV_SYS_REG_DBGBCR15_EL1, HVF_SYSREG(0, 15, 14, 0, 5) },
338
+ { HV_SYS_REG_DBGWVR15_EL1, HVF_SYSREG(0, 15, 14, 0, 6) },
339
+ { HV_SYS_REG_DBGWCR15_EL1, HVF_SYSREG(0, 15, 14, 0, 7) },
340
+
341
+#ifdef SYNC_NO_RAW_REGS
342
+ /*
343
+ * The registers below are manually synced on init because they are
344
+ * marked as NO_RAW. We still list them to make number space sync easier.
345
+ */
346
+ { HV_SYS_REG_MDCCINT_EL1, HVF_SYSREG(0, 2, 2, 0, 0) },
347
+ { HV_SYS_REG_MIDR_EL1, HVF_SYSREG(0, 0, 3, 0, 0) },
348
+ { HV_SYS_REG_MPIDR_EL1, HVF_SYSREG(0, 0, 3, 0, 5) },
349
+ { HV_SYS_REG_ID_AA64PFR0_EL1, HVF_SYSREG(0, 4, 3, 0, 0) },
350
+#endif
351
+ { HV_SYS_REG_ID_AA64PFR1_EL1, HVF_SYSREG(0, 4, 3, 0, 2) },
352
+ { HV_SYS_REG_ID_AA64DFR0_EL1, HVF_SYSREG(0, 5, 3, 0, 0) },
353
+ { HV_SYS_REG_ID_AA64DFR1_EL1, HVF_SYSREG(0, 5, 3, 0, 1) },
354
+ { HV_SYS_REG_ID_AA64ISAR0_EL1, HVF_SYSREG(0, 6, 3, 0, 0) },
355
+ { HV_SYS_REG_ID_AA64ISAR1_EL1, HVF_SYSREG(0, 6, 3, 0, 1) },
356
+#ifdef SYNC_NO_MMFR0
357
+ /* We keep the hardware MMFR0 around. HW limits are there anyway */
358
+ { HV_SYS_REG_ID_AA64MMFR0_EL1, HVF_SYSREG(0, 7, 3, 0, 0) },
359
+#endif
360
+ { HV_SYS_REG_ID_AA64MMFR1_EL1, HVF_SYSREG(0, 7, 3, 0, 1) },
361
+ { HV_SYS_REG_ID_AA64MMFR2_EL1, HVF_SYSREG(0, 7, 3, 0, 2) },
362
+
363
+ { HV_SYS_REG_MDSCR_EL1, HVF_SYSREG(0, 2, 2, 0, 2) },
364
+ { HV_SYS_REG_SCTLR_EL1, HVF_SYSREG(1, 0, 3, 0, 0) },
365
+ { HV_SYS_REG_CPACR_EL1, HVF_SYSREG(1, 0, 3, 0, 2) },
366
+ { HV_SYS_REG_TTBR0_EL1, HVF_SYSREG(2, 0, 3, 0, 0) },
367
+ { HV_SYS_REG_TTBR1_EL1, HVF_SYSREG(2, 0, 3, 0, 1) },
368
+ { HV_SYS_REG_TCR_EL1, HVF_SYSREG(2, 0, 3, 0, 2) },
369
+
370
+ { HV_SYS_REG_APIAKEYLO_EL1, HVF_SYSREG(2, 1, 3, 0, 0) },
371
+ { HV_SYS_REG_APIAKEYHI_EL1, HVF_SYSREG(2, 1, 3, 0, 1) },
372
+ { HV_SYS_REG_APIBKEYLO_EL1, HVF_SYSREG(2, 1, 3, 0, 2) },
373
+ { HV_SYS_REG_APIBKEYHI_EL1, HVF_SYSREG(2, 1, 3, 0, 3) },
374
+ { HV_SYS_REG_APDAKEYLO_EL1, HVF_SYSREG(2, 2, 3, 0, 0) },
375
+ { HV_SYS_REG_APDAKEYHI_EL1, HVF_SYSREG(2, 2, 3, 0, 1) },
376
+ { HV_SYS_REG_APDBKEYLO_EL1, HVF_SYSREG(2, 2, 3, 0, 2) },
377
+ { HV_SYS_REG_APDBKEYHI_EL1, HVF_SYSREG(2, 2, 3, 0, 3) },
378
+ { HV_SYS_REG_APGAKEYLO_EL1, HVF_SYSREG(2, 3, 3, 0, 0) },
379
+ { HV_SYS_REG_APGAKEYHI_EL1, HVF_SYSREG(2, 3, 3, 0, 1) },
380
+
381
+ { HV_SYS_REG_SPSR_EL1, HVF_SYSREG(4, 0, 3, 0, 0) },
382
+ { HV_SYS_REG_ELR_EL1, HVF_SYSREG(4, 0, 3, 0, 1) },
383
+ { HV_SYS_REG_SP_EL0, HVF_SYSREG(4, 1, 3, 0, 0) },
384
+ { HV_SYS_REG_AFSR0_EL1, HVF_SYSREG(5, 1, 3, 0, 0) },
385
+ { HV_SYS_REG_AFSR1_EL1, HVF_SYSREG(5, 1, 3, 0, 1) },
386
+ { HV_SYS_REG_ESR_EL1, HVF_SYSREG(5, 2, 3, 0, 0) },
387
+ { HV_SYS_REG_FAR_EL1, HVF_SYSREG(6, 0, 3, 0, 0) },
388
+ { HV_SYS_REG_PAR_EL1, HVF_SYSREG(7, 4, 3, 0, 0) },
389
+ { HV_SYS_REG_MAIR_EL1, HVF_SYSREG(10, 2, 3, 0, 0) },
390
+ { HV_SYS_REG_AMAIR_EL1, HVF_SYSREG(10, 3, 3, 0, 0) },
391
+ { HV_SYS_REG_VBAR_EL1, HVF_SYSREG(12, 0, 3, 0, 0) },
392
+ { HV_SYS_REG_CONTEXTIDR_EL1, HVF_SYSREG(13, 0, 3, 0, 1) },
393
+ { HV_SYS_REG_TPIDR_EL1, HVF_SYSREG(13, 0, 3, 0, 4) },
394
+ { HV_SYS_REG_CNTKCTL_EL1, HVF_SYSREG(14, 1, 3, 0, 0) },
395
+ { HV_SYS_REG_CSSELR_EL1, HVF_SYSREG(0, 0, 3, 2, 0) },
396
+ { HV_SYS_REG_TPIDR_EL0, HVF_SYSREG(13, 0, 3, 3, 2) },
397
+ { HV_SYS_REG_TPIDRRO_EL0, HVF_SYSREG(13, 0, 3, 3, 3) },
398
+ { HV_SYS_REG_CNTV_CTL_EL0, HVF_SYSREG(14, 3, 3, 3, 1) },
399
+ { HV_SYS_REG_CNTV_CVAL_EL0, HVF_SYSREG(14, 3, 3, 3, 2) },
400
+ { HV_SYS_REG_SP_EL1, HVF_SYSREG(4, 1, 3, 4, 0) },
401
+};
402
+
403
+int hvf_get_registers(CPUState *cpu)
404
+{
405
+ ARMCPU *arm_cpu = ARM_CPU(cpu);
406
+ CPUARMState *env = &arm_cpu->env;
407
+ hv_return_t ret;
408
+ uint64_t val;
409
+ hv_simd_fp_uchar16_t fpval;
410
+ int i;
411
+
412
+ for (i = 0; i < ARRAY_SIZE(hvf_reg_match); i++) {
413
+ ret = hv_vcpu_get_reg(cpu->hvf->fd, hvf_reg_match[i].reg, &val);
414
+ *(uint64_t *)((void *)env + hvf_reg_match[i].offset) = val;
415
+ assert_hvf_ok(ret);
416
+ }
194
+ }
417
+
195
+ return 0x0;
418
+ for (i = 0; i < ARRAY_SIZE(hvf_fpreg_match); i++) {
196
+}
419
+ ret = hv_vcpu_get_simd_fp_reg(cpu->hvf->fd, hvf_fpreg_match[i].reg,
197
+
420
+ &fpval);
198
+static void system_reset(void)
421
+ memcpy((void *)env + hvf_fpreg_match[i].offset, &fpval, sizeof(fpval));
199
+{
422
+ assert_hvf_ok(ret);
200
+ QDict *r;
423
+ }
201
+ r = qtest_qmp(global_qtest, "{'execute': 'system_reset'}");
424
+
202
+ g_assert_false(qdict_haskey(r, "error"));
425
+ val = 0;
203
+ qobject_unref(r);
426
+ ret = hv_vcpu_get_reg(cpu->hvf->fd, HV_REG_FPCR, &val);
204
+}
427
+ assert_hvf_ok(ret);
205
+
428
+ vfp_set_fpcr(env, val);
206
+static void test_idr_reset_value(void)
429
+
207
+{
430
+ val = 0;
208
+ /*
431
+ ret = hv_vcpu_get_reg(cpu->hvf->fd, HV_REG_FPSR, &val);
209
+ * Checks that the values in MODER, OTYPER, PUPDR and ODR
432
+ assert_hvf_ok(ret);
210
+ * after reset are correct, and that the value in IDR is
433
+ vfp_set_fpsr(env, val);
211
+ * coherent.
434
+
212
+ * Since AF and analog modes aren't implemented, IDR reset
435
+ ret = hv_vcpu_get_reg(cpu->hvf->fd, HV_REG_CPSR, &val);
213
+ * values aren't the same as with a real board.
436
+ assert_hvf_ok(ret);
214
+ *
437
+ pstate_write(env, val);
215
+ * Register IDR contains the actual values of all GPIO pins.
438
+
216
+ * Its value depends on the pins' configuration
439
+ for (i = 0; i < ARRAY_SIZE(hvf_sreg_match); i++) {
217
+ * (intput/output/analog : register MODER, push-pull/open-drain :
440
+ if (hvf_sreg_match[i].cp_idx == -1) {
218
+ * register OTYPER, pull-up/pull-down/none : register PUPDR)
441
+ continue;
219
+ * and on the values stored in register ODR
442
+ }
220
+ * (in case the pin is in output mode).
443
+
221
+ */
444
+ ret = hv_vcpu_get_sys_reg(cpu->hvf->fd, hvf_sreg_match[i].reg, &val);
222
+
445
+ assert_hvf_ok(ret);
223
+ gpio_writel(GPIO_A, MODER, 0xDEADBEEF);
446
+
224
+ gpio_writel(GPIO_A, ODR, 0xDEADBEEF);
447
+ arm_cpu->cpreg_values[hvf_sreg_match[i].cp_idx] = val;
225
+ gpio_writel(GPIO_A, OTYPER, 0xDEADBEEF);
448
+ }
226
+ gpio_writel(GPIO_A, PUPDR, 0xDEADBEEF);
449
+ assert(write_list_to_cpustate(arm_cpu));
227
+
450
+
228
+ gpio_writel(GPIO_B, MODER, 0xDEADBEEF);
451
+ aarch64_restore_sp(env, arm_current_el(env));
229
+ gpio_writel(GPIO_B, ODR, 0xDEADBEEF);
452
+
230
+ gpio_writel(GPIO_B, OTYPER, 0xDEADBEEF);
453
+ return 0;
231
+ gpio_writel(GPIO_B, PUPDR, 0xDEADBEEF);
454
+}
232
+
455
+
233
+ gpio_writel(GPIO_C, MODER, 0xDEADBEEF);
456
+int hvf_put_registers(CPUState *cpu)
234
+ gpio_writel(GPIO_C, ODR, 0xDEADBEEF);
457
+{
235
+ gpio_writel(GPIO_C, OTYPER, 0xDEADBEEF);
458
+ ARMCPU *arm_cpu = ARM_CPU(cpu);
236
+ gpio_writel(GPIO_C, PUPDR, 0xDEADBEEF);
459
+ CPUARMState *env = &arm_cpu->env;
237
+
460
+ hv_return_t ret;
238
+ gpio_writel(GPIO_H, MODER, 0xDEADBEEF);
461
+ uint64_t val;
239
+ gpio_writel(GPIO_H, ODR, 0xDEADBEEF);
462
+ hv_simd_fp_uchar16_t fpval;
240
+ gpio_writel(GPIO_H, OTYPER, 0xDEADBEEF);
463
+ int i;
241
+ gpio_writel(GPIO_H, PUPDR, 0xDEADBEEF);
464
+
242
+
465
+ for (i = 0; i < ARRAY_SIZE(hvf_reg_match); i++) {
243
+ system_reset();
466
+ val = *(uint64_t *)((void *)env + hvf_reg_match[i].offset);
244
+
467
+ ret = hv_vcpu_set_reg(cpu->hvf->fd, hvf_reg_match[i].reg, val);
245
+ uint32_t moder = gpio_readl(GPIO_A, MODER);
468
+ assert_hvf_ok(ret);
246
+ uint32_t odr = gpio_readl(GPIO_A, ODR);
469
+ }
247
+ uint32_t otyper = gpio_readl(GPIO_A, OTYPER);
470
+
248
+ uint32_t pupdr = gpio_readl(GPIO_A, PUPDR);
471
+ for (i = 0; i < ARRAY_SIZE(hvf_fpreg_match); i++) {
249
+ uint32_t idr = gpio_readl(GPIO_A, IDR);
472
+ memcpy(&fpval, (void *)env + hvf_fpreg_match[i].offset, sizeof(fpval));
250
+ /* 15: AF, 14: AF, 13: AF, 12: Analog ... */
473
+ ret = hv_vcpu_set_simd_fp_reg(cpu->hvf->fd, hvf_fpreg_match[i].reg,
251
+ /* here AF is the same as Analog and Input mode */
474
+ fpval);
252
+ g_assert_cmphex(moder, ==, reset(GPIO_A, MODER));
475
+ assert_hvf_ok(ret);
253
+ g_assert_cmphex(odr, ==, reset(GPIO_A, ODR));
476
+ }
254
+ g_assert_cmphex(otyper, ==, reset(GPIO_A, OTYPER));
477
+
255
+ /* 15: pull-up, 14: pull-down, 13: pull-up, 12: neither ... */
478
+ ret = hv_vcpu_set_reg(cpu->hvf->fd, HV_REG_FPCR, vfp_get_fpcr(env));
256
+ g_assert_cmphex(pupdr, ==, reset(GPIO_A, PUPDR));
479
+ assert_hvf_ok(ret);
257
+ /* 15 : 1, 14: 0, 13: 1, 12 : reset value ... */
480
+
258
+ g_assert_cmphex(idr, ==, reset(GPIO_A, IDR));
481
+ ret = hv_vcpu_set_reg(cpu->hvf->fd, HV_REG_FPSR, vfp_get_fpsr(env));
259
+
482
+ assert_hvf_ok(ret);
260
+ moder = gpio_readl(GPIO_B, MODER);
483
+
261
+ odr = gpio_readl(GPIO_B, ODR);
484
+ ret = hv_vcpu_set_reg(cpu->hvf->fd, HV_REG_CPSR, pstate_read(env));
262
+ otyper = gpio_readl(GPIO_B, OTYPER);
485
+ assert_hvf_ok(ret);
263
+ pupdr = gpio_readl(GPIO_B, PUPDR);
486
+
264
+ idr = gpio_readl(GPIO_B, IDR);
487
+ aarch64_save_sp(env, arm_current_el(env));
265
+ /* ... 5: Analog, 4: AF, 3: AF, 2: Analog ... */
488
+
266
+ /* here AF is the same as Analog and Input mode */
489
+ assert(write_cpustate_to_list(arm_cpu, false));
267
+ g_assert_cmphex(moder, ==, reset(GPIO_B, MODER));
490
+ for (i = 0; i < ARRAY_SIZE(hvf_sreg_match); i++) {
268
+ g_assert_cmphex(odr, ==, reset(GPIO_B, ODR));
491
+ if (hvf_sreg_match[i].cp_idx == -1) {
269
+ g_assert_cmphex(otyper, ==, reset(GPIO_B, OTYPER));
492
+ continue;
270
+ /* ... 5: neither, 4: pull-up, 3: neither ... */
493
+ }
271
+ g_assert_cmphex(pupdr, ==, reset(GPIO_B, PUPDR));
494
+
272
+ /* ... 5 : reset value, 4 : 1, 3 : reset value ... */
495
+ val = arm_cpu->cpreg_values[hvf_sreg_match[i].cp_idx];
273
+ g_assert_cmphex(idr, ==, reset(GPIO_B, IDR));
496
+ ret = hv_vcpu_set_sys_reg(cpu->hvf->fd, hvf_sreg_match[i].reg, val);
274
+
497
+ assert_hvf_ok(ret);
275
+ moder = gpio_readl(GPIO_C, MODER);
498
+ }
276
+ odr = gpio_readl(GPIO_C, ODR);
499
+
277
+ otyper = gpio_readl(GPIO_C, OTYPER);
500
+ ret = hv_vcpu_set_vtimer_offset(cpu->hvf->fd, hvf_state->vtimer_offset);
278
+ pupdr = gpio_readl(GPIO_C, PUPDR);
501
+ assert_hvf_ok(ret);
279
+ idr = gpio_readl(GPIO_C, IDR);
502
+
280
+ /* Analog, same as Input mode*/
503
+ return 0;
281
+ g_assert_cmphex(moder, ==, reset(GPIO_C, MODER));
504
+}
282
+ g_assert_cmphex(odr, ==, reset(GPIO_C, ODR));
505
+
283
+ g_assert_cmphex(otyper, ==, reset(GPIO_C, OTYPER));
506
+static void flush_cpu_state(CPUState *cpu)
284
+ /* no pull-up or pull-down */
507
+{
285
+ g_assert_cmphex(pupdr, ==, reset(GPIO_C, PUPDR));
508
+ if (cpu->vcpu_dirty) {
286
+ /* reset value */
509
+ hvf_put_registers(cpu);
287
+ g_assert_cmphex(idr, ==, reset(GPIO_C, IDR));
510
+ cpu->vcpu_dirty = false;
288
+
511
+ }
289
+ moder = gpio_readl(GPIO_H, MODER);
512
+}
290
+ odr = gpio_readl(GPIO_H, ODR);
513
+
291
+ otyper = gpio_readl(GPIO_H, OTYPER);
514
+static void hvf_set_reg(CPUState *cpu, int rt, uint64_t val)
292
+ pupdr = gpio_readl(GPIO_H, PUPDR);
515
+{
293
+ idr = gpio_readl(GPIO_H, IDR);
516
+ hv_return_t r;
294
+ /* Analog, same as Input mode */
517
+
295
+ g_assert_cmphex(moder, ==, reset(GPIO_H, MODER));
518
+ flush_cpu_state(cpu);
296
+ g_assert_cmphex(odr, ==, reset(GPIO_H, ODR));
519
+
297
+ g_assert_cmphex(otyper, ==, reset(GPIO_H, OTYPER));
520
+ if (rt < 31) {
298
+ /* no pull-up or pull-down */
521
+ r = hv_vcpu_set_reg(cpu->hvf->fd, HV_REG_X0 + rt, val);
299
+ g_assert_cmphex(pupdr, ==, reset(GPIO_H, PUPDR));
522
+ assert_hvf_ok(r);
300
+ /* reset value */
523
+ }
301
+ g_assert_cmphex(idr, ==, reset(GPIO_H, IDR));
524
+}
302
+}
525
+
303
+
526
+static uint64_t hvf_get_reg(CPUState *cpu, int rt)
304
+static void test_gpio_output_mode(const void *data)
527
+{
305
+{
528
+ uint64_t val = 0;
306
+ /*
529
+ hv_return_t r;
307
+ * Checks that setting a bit in ODR sets the corresponding
530
+
308
+ * GPIO line high : it should set the right bit in IDR
531
+ flush_cpu_state(cpu);
309
+ * and send an irq to syscfg.
532
+
310
+ * Additionally, it checks that values written to ODR
533
+ if (rt < 31) {
311
+ * when not in output mode are stored and not discarded.
534
+ r = hv_vcpu_get_reg(cpu->hvf->fd, HV_REG_X0 + rt, &val);
312
+ */
535
+ assert_hvf_ok(r);
313
+ unsigned int pin = ((uint64_t)data) & 0xF;
536
+ }
314
+ uint32_t gpio = ((uint64_t)data) >> 32;
537
+
315
+ unsigned int gpio_id = get_gpio_id(gpio);
538
+ return val;
316
+
539
+}
317
+ qtest_irq_intercept_in(global_qtest, "/machine/soc/syscfg");
540
+
318
+
541
+void hvf_arch_vcpu_destroy(CPUState *cpu)
319
+ /* Set a bit in ODR and check nothing happens */
542
+{
320
+ gpio_set_bit(gpio, ODR, pin, 1);
543
+}
321
+ g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR));
544
+
322
+ g_assert_false(get_irq(gpio_id * NUM_GPIO_PINS + pin));
545
+int hvf_arch_init_vcpu(CPUState *cpu)
323
+
546
+{
324
+ /* Configure the relevant line as output and check the pin is high */
547
+ ARMCPU *arm_cpu = ARM_CPU(cpu);
325
+ gpio_set_2bits(gpio, MODER, pin, MODER_OUTPUT);
548
+ CPUARMState *env = &arm_cpu->env;
326
+ g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) | (1 << pin));
549
+ uint32_t sregs_match_len = ARRAY_SIZE(hvf_sreg_match);
327
+ g_assert_true(get_irq(gpio_id * NUM_GPIO_PINS + pin));
550
+ uint32_t sregs_cnt = 0;
328
+
551
+ uint64_t pfr;
329
+ /* Reset the bit in ODR and check the pin is low */
552
+ hv_return_t ret;
330
+ gpio_set_bit(gpio, ODR, pin, 0);
553
+ int i;
331
+ g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) & ~(1 << pin));
554
+
332
+ g_assert_false(get_irq(gpio_id * NUM_GPIO_PINS + pin));
555
+ env->aarch64 = 1;
333
+
556
+ asm volatile("mrs %0, cntfrq_el0" : "=r"(arm_cpu->gt_cntfrq_hz));
334
+ /* Clean the test */
557
+
335
+ gpio_writel(gpio, ODR, reset(gpio, ODR));
558
+ /* Allocate enough space for our sysreg sync */
336
+ gpio_writel(gpio, MODER, reset(gpio, MODER));
559
+ arm_cpu->cpreg_indexes = g_renew(uint64_t, arm_cpu->cpreg_indexes,
337
+ g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR));
560
+ sregs_match_len);
338
+ g_assert_false(get_irq(gpio_id * NUM_GPIO_PINS + pin));
561
+ arm_cpu->cpreg_values = g_renew(uint64_t, arm_cpu->cpreg_values,
339
+}
562
+ sregs_match_len);
340
+
563
+ arm_cpu->cpreg_vmstate_indexes = g_renew(uint64_t,
341
+static void test_gpio_input_mode(const void *data)
564
+ arm_cpu->cpreg_vmstate_indexes,
342
+{
565
+ sregs_match_len);
343
+ /*
566
+ arm_cpu->cpreg_vmstate_values = g_renew(uint64_t,
344
+ * Test that setting a line high/low externally sets the
567
+ arm_cpu->cpreg_vmstate_values,
345
+ * corresponding GPIO line high/low : it should set the
568
+ sregs_match_len);
346
+ * right bit in IDR and send an irq to syscfg.
569
+
347
+ */
570
+ memset(arm_cpu->cpreg_values, 0, sregs_match_len * sizeof(uint64_t));
348
+ unsigned int pin = ((uint64_t)data) & 0xF;
571
+
349
+ uint32_t gpio = ((uint64_t)data) >> 32;
572
+ /* Populate cp list for all known sysregs */
350
+ unsigned int gpio_id = get_gpio_id(gpio);
573
+ for (i = 0; i < sregs_match_len; i++) {
351
+
574
+ const ARMCPRegInfo *ri;
352
+ qtest_irq_intercept_in(global_qtest, "/machine/soc/syscfg");
575
+ uint32_t key = hvf_sreg_match[i].key;
353
+
576
+
354
+ /* Configure a line as input, raise it, and check that the pin is high */
577
+ ri = get_arm_cp_reginfo(arm_cpu->cp_regs, key);
355
+ gpio_set_2bits(gpio, MODER, pin, MODER_INPUT);
578
+ if (ri) {
356
+ gpio_set_irq(gpio, pin, 1);
579
+ assert(!(ri->type & ARM_CP_NO_RAW));
357
+ g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) | (1 << pin));
580
+ hvf_sreg_match[i].cp_idx = sregs_cnt;
358
+ g_assert_true(get_irq(gpio_id * NUM_GPIO_PINS + pin));
581
+ arm_cpu->cpreg_indexes[sregs_cnt++] = cpreg_to_kvm_id(key);
359
+
582
+ } else {
360
+ /* Lower the line and check that the pin is low */
583
+ hvf_sreg_match[i].cp_idx = -1;
361
+ gpio_set_irq(gpio, pin, 0);
584
+ }
362
+ g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) & ~(1 << pin));
585
+ }
363
+ g_assert_false(get_irq(gpio_id * NUM_GPIO_PINS + pin));
586
+ arm_cpu->cpreg_array_len = sregs_cnt;
364
+
587
+ arm_cpu->cpreg_vmstate_array_len = sregs_cnt;
365
+ /* Clean the test */
588
+
366
+ gpio_writel(gpio, MODER, reset(gpio, MODER));
589
+ assert(write_cpustate_to_list(arm_cpu, false));
367
+ disconnect_all_pins(gpio);
590
+
368
+ g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR));
591
+ /* Set CP_NO_RAW system registers on init */
369
+}
592
+ ret = hv_vcpu_set_sys_reg(cpu->hvf->fd, HV_SYS_REG_MIDR_EL1,
370
+
593
+ arm_cpu->midr);
371
+static void test_pull_up_pull_down(const void *data)
594
+ assert_hvf_ok(ret);
372
+{
595
+
373
+ /*
596
+ ret = hv_vcpu_set_sys_reg(cpu->hvf->fd, HV_SYS_REG_MPIDR_EL1,
374
+ * Test that a floating pin with pull-up sets the pin
597
+ arm_cpu->mp_affinity);
375
+ * high and vice-versa.
598
+ assert_hvf_ok(ret);
376
+ */
599
+
377
+ unsigned int pin = ((uint64_t)data) & 0xF;
600
+ ret = hv_vcpu_get_sys_reg(cpu->hvf->fd, HV_SYS_REG_ID_AA64PFR0_EL1, &pfr);
378
+ uint32_t gpio = ((uint64_t)data) >> 32;
601
+ assert_hvf_ok(ret);
379
+ unsigned int gpio_id = get_gpio_id(gpio);
602
+ pfr |= env->gicv3state ? (1 << 24) : 0;
380
+
603
+ ret = hv_vcpu_set_sys_reg(cpu->hvf->fd, HV_SYS_REG_ID_AA64PFR0_EL1, pfr);
381
+ qtest_irq_intercept_in(global_qtest, "/machine/soc/syscfg");
604
+ assert_hvf_ok(ret);
382
+
605
+
383
+ /* Configure a line as input with pull-up, check the line is set high */
606
+ /* We're limited to underlying hardware caps, override internal versions */
384
+ gpio_set_2bits(gpio, MODER, pin, MODER_INPUT);
607
+ ret = hv_vcpu_get_sys_reg(cpu->hvf->fd, HV_SYS_REG_ID_AA64MMFR0_EL1,
385
+ gpio_set_2bits(gpio, PUPDR, pin, PUPDR_PULLUP);
608
+ &arm_cpu->isar.id_aa64mmfr0);
386
+ g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) | (1 << pin));
609
+ assert_hvf_ok(ret);
387
+ g_assert_true(get_irq(gpio_id * NUM_GPIO_PINS + pin));
610
+
388
+
611
+ return 0;
389
+ /* Configure the line with pull-down, check the line is low */
612
+}
390
+ gpio_set_2bits(gpio, PUPDR, pin, PUPDR_PULLDOWN);
613
+
391
+ g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) & ~(1 << pin));
614
+void hvf_kick_vcpu_thread(CPUState *cpu)
392
+ g_assert_false(get_irq(gpio_id * NUM_GPIO_PINS + pin));
615
+{
393
+
616
+ hv_vcpus_exit(&cpu->hvf->fd, 1);
394
+ /* Clean the test */
617
+}
395
+ gpio_writel(gpio, MODER, reset(gpio, MODER));
618
+
396
+ gpio_writel(gpio, PUPDR, reset(gpio, PUPDR));
619
+static void hvf_raise_exception(CPUState *cpu, uint32_t excp,
397
+ g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR));
620
+ uint32_t syndrome)
398
+}
621
+{
399
+
622
+ ARMCPU *arm_cpu = ARM_CPU(cpu);
400
+static void test_push_pull(const void *data)
623
+ CPUARMState *env = &arm_cpu->env;
401
+{
624
+
402
+ /*
625
+ cpu->exception_index = excp;
403
+ * Test that configuring a line in push-pull output mode
626
+ env->exception.target_el = 1;
404
+ * disconnects the pin, that the pin can't be set or reset
627
+ env->exception.syndrome = syndrome;
405
+ * externally afterwards.
628
+
406
+ */
629
+ arm_cpu_do_interrupt(cpu);
407
+ unsigned int pin = ((uint64_t)data) & 0xF;
630
+}
408
+ uint32_t gpio = ((uint64_t)data) >> 32;
631
+
409
+ uint32_t gpio2 = GPIO_BASE_ADDR + (GPIO_H - gpio);
632
+static int hvf_sysreg_read(CPUState *cpu, uint32_t reg, uint32_t rt)
410
+
633
+{
411
+ qtest_irq_intercept_in(global_qtest, "/machine/soc/syscfg");
634
+ ARMCPU *arm_cpu = ARM_CPU(cpu);
412
+
635
+ CPUARMState *env = &arm_cpu->env;
413
+ /* Setting a line high externally, configuring it in push-pull output */
636
+ uint64_t val = 0;
414
+ /* And checking the pin was disconnected */
637
+
415
+ gpio_set_irq(gpio, pin, 1);
638
+ switch (reg) {
416
+ gpio_set_2bits(gpio, MODER, pin, MODER_OUTPUT);
639
+ case SYSREG_CNTPCT_EL0:
417
+ g_assert_cmphex(get_disconnected_pins(gpio), ==, 0xFFFF);
640
+ val = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) /
418
+ g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) & ~(1 << pin));
641
+ gt_cntfrq_period_ns(arm_cpu);
419
+
642
+ break;
420
+ /* Setting a line low externally, configuring it in push-pull output */
643
+ case SYSREG_OSLSR_EL1:
421
+ /* And checking the pin was disconnected */
644
+ val = env->cp15.oslsr_el1;
422
+ gpio_set_irq(gpio2, pin, 0);
645
+ break;
423
+ gpio_set_bit(gpio2, ODR, pin, 1);
646
+ case SYSREG_OSDLR_EL1:
424
+ gpio_set_2bits(gpio2, MODER, pin, MODER_OUTPUT);
647
+ /* Dummy register */
425
+ g_assert_cmphex(get_disconnected_pins(gpio2), ==, 0xFFFF);
648
+ break;
426
+ g_assert_cmphex(gpio_readl(gpio2, IDR), ==, reset(gpio2, IDR) | (1 << pin));
649
+ default:
427
+
650
+ cpu_synchronize_state(cpu);
428
+ /* Trying to set a push-pull output pin, checking it doesn't work */
651
+ trace_hvf_unhandled_sysreg_read(env->pc, reg,
429
+ gpio_set_irq(gpio, pin, 1);
652
+ (reg >> 20) & 0x3,
430
+ g_assert_cmphex(get_disconnected_pins(gpio), ==, 0xFFFF);
653
+ (reg >> 14) & 0x7,
431
+ g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) & ~(1 << pin));
654
+ (reg >> 10) & 0xf,
432
+
655
+ (reg >> 1) & 0xf,
433
+ /* Trying to reset a push-pull output pin, checking it doesn't work */
656
+ (reg >> 17) & 0x7);
434
+ gpio_set_irq(gpio2, pin, 0);
657
+ hvf_raise_exception(cpu, EXCP_UDEF, syn_uncategorized());
435
+ g_assert_cmphex(get_disconnected_pins(gpio2), ==, 0xFFFF);
658
+ return 1;
436
+ g_assert_cmphex(gpio_readl(gpio2, IDR), ==, reset(gpio2, IDR) | (1 << pin));
659
+ }
437
+
660
+
438
+ /* Clean the test */
661
+ trace_hvf_sysreg_read(reg,
439
+ gpio_writel(gpio, MODER, reset(gpio, MODER));
662
+ (reg >> 20) & 0x3,
440
+ gpio_writel(gpio2, ODR, reset(gpio2, ODR));
663
+ (reg >> 14) & 0x7,
441
+ gpio_writel(gpio2, MODER, reset(gpio2, MODER));
664
+ (reg >> 10) & 0xf,
442
+}
665
+ (reg >> 1) & 0xf,
443
+
666
+ (reg >> 17) & 0x7,
444
+static void test_open_drain(const void *data)
667
+ val);
445
+{
668
+ hvf_set_reg(cpu, rt, val);
446
+ /*
669
+
447
+ * Test that configuring a line in open-drain output mode
670
+ return 0;
448
+ * disconnects a pin set high externally and that the pin
671
+}
449
+ * can't be set high externally while configured in open-drain.
672
+
450
+ *
673
+static int hvf_sysreg_write(CPUState *cpu, uint32_t reg, uint64_t val)
451
+ * However a pin set low externally shouldn't be disconnected,
674
+{
452
+ * and it can be set low externally when in open-drain mode.
675
+ ARMCPU *arm_cpu = ARM_CPU(cpu);
453
+ */
676
+ CPUARMState *env = &arm_cpu->env;
454
+ unsigned int pin = ((uint64_t)data) & 0xF;
677
+
455
+ uint32_t gpio = ((uint64_t)data) >> 32;
678
+ trace_hvf_sysreg_write(reg,
456
+ uint32_t gpio2 = GPIO_BASE_ADDR + (GPIO_H - gpio);
679
+ (reg >> 20) & 0x3,
457
+
680
+ (reg >> 14) & 0x7,
458
+ qtest_irq_intercept_in(global_qtest, "/machine/soc/syscfg");
681
+ (reg >> 10) & 0xf,
459
+
682
+ (reg >> 1) & 0xf,
460
+ /* Setting a line high externally, configuring it in open-drain output */
683
+ (reg >> 17) & 0x7,
461
+ /* And checking the pin was disconnected */
684
+ val);
462
+ gpio_set_irq(gpio, pin, 1);
685
+
463
+ gpio_set_bit(gpio, OTYPER, pin, OTYPER_OPEN_DRAIN);
686
+ switch (reg) {
464
+ gpio_set_2bits(gpio, MODER, pin, MODER_OUTPUT);
687
+ case SYSREG_OSLAR_EL1:
465
+ g_assert_cmphex(get_disconnected_pins(gpio), ==, 0xFFFF);
688
+ env->cp15.oslsr_el1 = val & 1;
466
+ g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) & ~(1 << pin));
689
+ break;
467
+
690
+ case SYSREG_OSDLR_EL1:
468
+ /* Setting a line low externally, configuring it in open-drain output */
691
+ /* Dummy register */
469
+ /* And checking the pin wasn't disconnected */
692
+ break;
470
+ gpio_set_irq(gpio2, pin, 0);
693
+ default:
471
+ gpio_set_bit(gpio2, ODR, pin, 1);
694
+ cpu_synchronize_state(cpu);
472
+ gpio_set_bit(gpio2, OTYPER, pin, OTYPER_OPEN_DRAIN);
695
+ trace_hvf_unhandled_sysreg_write(env->pc, reg,
473
+ gpio_set_2bits(gpio2, MODER, pin, MODER_OUTPUT);
696
+ (reg >> 20) & 0x3,
474
+ g_assert_cmphex(get_disconnected_pins(gpio2), ==, 0xFFFF & ~(1 << pin));
697
+ (reg >> 14) & 0x7,
475
+ g_assert_cmphex(gpio_readl(gpio2, IDR), ==,
698
+ (reg >> 10) & 0xf,
476
+ reset(gpio2, IDR) & ~(1 << pin));
699
+ (reg >> 1) & 0xf,
477
+
700
+ (reg >> 17) & 0x7);
478
+ /* Trying to set a open-drain output pin, checking it doesn't work */
701
+ hvf_raise_exception(cpu, EXCP_UDEF, syn_uncategorized());
479
+ gpio_set_irq(gpio, pin, 1);
702
+ return 1;
480
+ g_assert_cmphex(get_disconnected_pins(gpio), ==, 0xFFFF);
703
+ }
481
+ g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) & ~(1 << pin));
704
+
482
+
705
+ return 0;
483
+ /* Trying to reset a open-drain output pin, checking it works */
706
+}
484
+ gpio_set_bit(gpio, ODR, pin, 1);
707
+
485
+ gpio_set_irq(gpio, pin, 0);
708
+static int hvf_inject_interrupts(CPUState *cpu)
486
+ g_assert_cmphex(get_disconnected_pins(gpio2), ==, 0xFFFF & ~(1 << pin));
709
+{
487
+ g_assert_cmphex(gpio_readl(gpio2, IDR), ==,
710
+ if (cpu->interrupt_request & CPU_INTERRUPT_FIQ) {
488
+ reset(gpio2, IDR) & ~(1 << pin));
711
+ trace_hvf_inject_fiq();
489
+
712
+ hv_vcpu_set_pending_interrupt(cpu->hvf->fd, HV_INTERRUPT_TYPE_FIQ,
490
+ /* Clean the test */
713
+ true);
491
+ disconnect_all_pins(gpio2);
714
+ }
492
+ gpio_writel(gpio2, OTYPER, reset(gpio2, OTYPER));
715
+
493
+ gpio_writel(gpio2, ODR, reset(gpio2, ODR));
716
+ if (cpu->interrupt_request & CPU_INTERRUPT_HARD) {
494
+ gpio_writel(gpio2, MODER, reset(gpio2, MODER));
717
+ trace_hvf_inject_irq();
495
+ g_assert_cmphex(gpio_readl(gpio2, IDR), ==, reset(gpio2, IDR));
718
+ hv_vcpu_set_pending_interrupt(cpu->hvf->fd, HV_INTERRUPT_TYPE_IRQ,
496
+ disconnect_all_pins(gpio);
719
+ true);
497
+ gpio_writel(gpio, OTYPER, reset(gpio, OTYPER));
720
+ }
498
+ gpio_writel(gpio, ODR, reset(gpio, ODR));
721
+
499
+ gpio_writel(gpio, MODER, reset(gpio, MODER));
722
+ return 0;
500
+ g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR));
723
+}
501
+}
724
+
502
+
725
+static uint64_t hvf_vtimer_val_raw(void)
503
+static void test_bsrr_brr(const void *data)
726
+{
504
+{
727
+ /*
505
+ /*
728
+ * mach_absolute_time() returns the vtimer value without the VM
506
+ * Test that writing a '1' in BSS and BSRR
729
+ * offset that we define. Add our own offset on top.
507
+ * has the desired effect on ODR.
730
+ */
508
+ * In BSRR, BSx has priority over BRx.
731
+ return mach_absolute_time() - hvf_state->vtimer_offset;
509
+ */
732
+}
510
+ unsigned int pin = ((uint64_t)data) & 0xF;
733
+
511
+ uint32_t gpio = ((uint64_t)data) >> 32;
734
+static void hvf_sync_vtimer(CPUState *cpu)
512
+
735
+{
513
+ gpio_writel(gpio, BSRR, (1 << pin));
736
+ ARMCPU *arm_cpu = ARM_CPU(cpu);
514
+ g_assert_cmphex(gpio_readl(gpio, ODR), ==, reset(gpio, ODR) | (1 << pin));
737
+ hv_return_t r;
515
+
738
+ uint64_t ctl;
516
+ gpio_writel(gpio, BSRR, (1 << (pin + NUM_GPIO_PINS)));
739
+ bool irq_state;
517
+ g_assert_cmphex(gpio_readl(gpio, ODR), ==, reset(gpio, ODR));
740
+
518
+
741
+ if (!cpu->hvf->vtimer_masked) {
519
+ gpio_writel(gpio, BSRR, (1 << pin));
742
+ /* We will get notified on vtimer changes by hvf, nothing to do */
520
+ g_assert_cmphex(gpio_readl(gpio, ODR), ==, reset(gpio, ODR) | (1 << pin));
743
+ return;
521
+
744
+ }
522
+ gpio_writel(gpio, BRR, (1 << pin));
745
+
523
+ g_assert_cmphex(gpio_readl(gpio, ODR), ==, reset(gpio, ODR));
746
+ r = hv_vcpu_get_sys_reg(cpu->hvf->fd, HV_SYS_REG_CNTV_CTL_EL0, &ctl);
524
+
747
+ assert_hvf_ok(r);
525
+ /* BSx should have priority over BRx */
748
+
526
+ gpio_writel(gpio, BSRR, (1 << pin) | (1 << (pin + NUM_GPIO_PINS)));
749
+ irq_state = (ctl & (TMR_CTL_ENABLE | TMR_CTL_IMASK | TMR_CTL_ISTATUS)) ==
527
+ g_assert_cmphex(gpio_readl(gpio, ODR), ==, reset(gpio, ODR) | (1 << pin));
750
+ (TMR_CTL_ENABLE | TMR_CTL_ISTATUS);
528
+
751
+ qemu_set_irq(arm_cpu->gt_timer_outputs[GTIMER_VIRT], irq_state);
529
+ gpio_writel(gpio, BRR, (1 << pin));
752
+
530
+ g_assert_cmphex(gpio_readl(gpio, ODR), ==, reset(gpio, ODR));
753
+ if (!irq_state) {
531
+
754
+ /* Timer no longer asserting, we can unmask it */
532
+ gpio_writel(gpio, ODR, reset(gpio, ODR));
755
+ hv_vcpu_set_vtimer_mask(cpu->hvf->fd, false);
533
+}
756
+ cpu->hvf->vtimer_masked = false;
534
+
757
+ }
535
+int main(int argc, char **argv)
758
+}
536
+{
759
+
537
+ int ret;
760
+int hvf_vcpu_exec(CPUState *cpu)
538
+
761
+{
539
+ g_test_init(&argc, &argv, NULL);
762
+ ARMCPU *arm_cpu = ARM_CPU(cpu);
540
+ g_test_set_nonfatal_assertions();
763
+ CPUARMState *env = &arm_cpu->env;
541
+ qtest_add_func("stm32l4x5/gpio/test_idr_reset_value",
764
+ hv_vcpu_exit_t *hvf_exit = cpu->hvf->exit;
542
+ test_idr_reset_value);
765
+ hv_return_t r;
543
+ /*
766
+ bool advance_pc = false;
544
+ * The inputs for the tests (gpio and pin) can be changed,
767
+
545
+ * but the tests don't work for pins that are high at reset
768
+ if (hvf_inject_interrupts(cpu)) {
546
+ * (GPIOA15, GPIO13 and GPIOB5).
769
+ return EXCP_INTERRUPT;
547
+ * Specifically, rising the pin then checking `get_irq()`
770
+ }
548
+ * is problematic since the pin was already high.
771
+
549
+ */
772
+ if (cpu->halted) {
550
+ qtest_add_data_func("stm32l4x5/gpio/test_gpioc5_output_mode",
773
+ return EXCP_HLT;
551
+ (void *)((uint64_t)GPIO_C << 32 | 5),
774
+ }
552
+ test_gpio_output_mode);
775
+
553
+ qtest_add_data_func("stm32l4x5/gpio/test_gpioh3_output_mode",
776
+ flush_cpu_state(cpu);
554
+ (void *)((uint64_t)GPIO_H << 32 | 3),
777
+
555
+ test_gpio_output_mode);
778
+ qemu_mutex_unlock_iothread();
556
+ qtest_add_data_func("stm32l4x5/gpio/test_gpio_input_mode1",
779
+ assert_hvf_ok(hv_vcpu_run(cpu->hvf->fd));
557
+ (void *)((uint64_t)GPIO_D << 32 | 6),
780
+
558
+ test_gpio_input_mode);
781
+ /* handle VMEXIT */
559
+ qtest_add_data_func("stm32l4x5/gpio/test_gpio_input_mode2",
782
+ uint64_t exit_reason = hvf_exit->reason;
560
+ (void *)((uint64_t)GPIO_C << 32 | 10),
783
+ uint64_t syndrome = hvf_exit->exception.syndrome;
561
+ test_gpio_input_mode);
784
+ uint32_t ec = syn_get_ec(syndrome);
562
+ qtest_add_data_func("stm32l4x5/gpio/test_gpio_pull_up_pull_down1",
785
+
563
+ (void *)((uint64_t)GPIO_B << 32 | 5),
786
+ qemu_mutex_lock_iothread();
564
+ test_pull_up_pull_down);
787
+ switch (exit_reason) {
565
+ qtest_add_data_func("stm32l4x5/gpio/test_gpio_pull_up_pull_down2",
788
+ case HV_EXIT_REASON_EXCEPTION:
566
+ (void *)((uint64_t)GPIO_F << 32 | 1),
789
+ /* This is the main one, handle below. */
567
+ test_pull_up_pull_down);
790
+ break;
568
+ qtest_add_data_func("stm32l4x5/gpio/test_gpio_push_pull1",
791
+ case HV_EXIT_REASON_VTIMER_ACTIVATED:
569
+ (void *)((uint64_t)GPIO_G << 32 | 6),
792
+ qemu_set_irq(arm_cpu->gt_timer_outputs[GTIMER_VIRT], 1);
570
+ test_push_pull);
793
+ cpu->hvf->vtimer_masked = true;
571
+ qtest_add_data_func("stm32l4x5/gpio/test_gpio_push_pull2",
794
+ return 0;
572
+ (void *)((uint64_t)GPIO_H << 32 | 3),
795
+ case HV_EXIT_REASON_CANCELED:
573
+ test_push_pull);
796
+ /* we got kicked, no exit to process */
574
+ qtest_add_data_func("stm32l4x5/gpio/test_gpio_open_drain1",
797
+ return 0;
575
+ (void *)((uint64_t)GPIO_C << 32 | 4),
798
+ default:
576
+ test_open_drain);
799
+ assert(0);
577
+ qtest_add_data_func("stm32l4x5/gpio/test_gpio_open_drain2",
800
+ }
578
+ (void *)((uint64_t)GPIO_E << 32 | 11),
801
+
579
+ test_open_drain);
802
+ hvf_sync_vtimer(cpu);
580
+ qtest_add_data_func("stm32l4x5/gpio/test_bsrr_brr1",
803
+
581
+ (void *)((uint64_t)GPIO_A << 32 | 12),
804
+ switch (ec) {
582
+ test_bsrr_brr);
805
+ case EC_DATAABORT: {
583
+ qtest_add_data_func("stm32l4x5/gpio/test_bsrr_brr2",
806
+ bool isv = syndrome & ARM_EL_ISV;
584
+ (void *)((uint64_t)GPIO_D << 32 | 0),
807
+ bool iswrite = (syndrome >> 6) & 1;
585
+ test_bsrr_brr);
808
+ bool s1ptw = (syndrome >> 7) & 1;
586
+
809
+ uint32_t sas = (syndrome >> 22) & 3;
587
+ qtest_start("-machine b-l475e-iot01a");
810
+ uint32_t len = 1 << sas;
588
+ ret = g_test_run();
811
+ uint32_t srt = (syndrome >> 16) & 0x1f;
589
+ qtest_end();
812
+ uint64_t val = 0;
590
+
813
+
591
+ return ret;
814
+ trace_hvf_data_abort(env->pc, hvf_exit->exception.virtual_address,
592
+}
815
+ hvf_exit->exception.physical_address, isv,
593
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
816
+ iswrite, s1ptw, len, srt);
817
+
818
+ assert(isv);
819
+
820
+ if (iswrite) {
821
+ val = hvf_get_reg(cpu, srt);
822
+ address_space_write(&address_space_memory,
823
+ hvf_exit->exception.physical_address,
824
+ MEMTXATTRS_UNSPECIFIED, &val, len);
825
+ } else {
826
+ address_space_read(&address_space_memory,
827
+ hvf_exit->exception.physical_address,
828
+ MEMTXATTRS_UNSPECIFIED, &val, len);
829
+ hvf_set_reg(cpu, srt, val);
830
+ }
831
+
832
+ advance_pc = true;
833
+ break;
834
+ }
835
+ case EC_SYSTEMREGISTERTRAP: {
836
+ bool isread = (syndrome >> 0) & 1;
837
+ uint32_t rt = (syndrome >> 5) & 0x1f;
838
+ uint32_t reg = syndrome & SYSREG_MASK;
839
+ uint64_t val;
840
+ int ret = 0;
841
+
842
+ if (isread) {
843
+ ret = hvf_sysreg_read(cpu, reg, rt);
844
+ } else {
845
+ val = hvf_get_reg(cpu, rt);
846
+ ret = hvf_sysreg_write(cpu, reg, val);
847
+ }
848
+
849
+ advance_pc = !ret;
850
+ break;
851
+ }
852
+ case EC_WFX_TRAP:
853
+ advance_pc = true;
854
+ break;
855
+ case EC_AA64_HVC:
856
+ cpu_synchronize_state(cpu);
857
+ trace_hvf_unknown_hvc(env->xregs[0]);
858
+ /* SMCCC 1.3 section 5.2 says every unknown SMCCC call returns -1 */
859
+ env->xregs[0] = -1;
860
+ break;
861
+ case EC_AA64_SMC:
862
+ cpu_synchronize_state(cpu);
863
+ trace_hvf_unknown_smc(env->xregs[0]);
864
+ hvf_raise_exception(cpu, EXCP_UDEF, syn_uncategorized());
865
+ break;
866
+ default:
867
+ cpu_synchronize_state(cpu);
868
+ trace_hvf_exit(syndrome, ec, env->pc);
869
+ error_report("0x%llx: unhandled exception ec=0x%x", env->pc, ec);
870
+ }
871
+
872
+ if (advance_pc) {
873
+ uint64_t pc;
874
+
875
+ flush_cpu_state(cpu);
876
+
877
+ r = hv_vcpu_get_reg(cpu->hvf->fd, HV_REG_PC, &pc);
878
+ assert_hvf_ok(r);
879
+ pc += 4;
880
+ r = hv_vcpu_set_reg(cpu->hvf->fd, HV_REG_PC, pc);
881
+ assert_hvf_ok(r);
882
+ }
883
+
884
+ return 0;
885
+}
886
+
887
+static const VMStateDescription vmstate_hvf_vtimer = {
888
+ .name = "hvf-vtimer",
889
+ .version_id = 1,
890
+ .minimum_version_id = 1,
891
+ .fields = (VMStateField[]) {
892
+ VMSTATE_UINT64(vtimer_val, HVFVTimer),
893
+ VMSTATE_END_OF_LIST()
894
+ },
895
+};
896
+
897
+static void hvf_vm_state_change(void *opaque, bool running, RunState state)
898
+{
899
+ HVFVTimer *s = opaque;
900
+
901
+ if (running) {
902
+ /* Update vtimer offset on all CPUs */
903
+ hvf_state->vtimer_offset = mach_absolute_time() - s->vtimer_val;
904
+ cpu_synchronize_all_states();
905
+ } else {
906
+ /* Remember vtimer value on every pause */
907
+ s->vtimer_val = hvf_vtimer_val_raw();
908
+ }
909
+}
910
+
911
+int hvf_arch_init(void)
912
+{
913
+ hvf_state->vtimer_offset = mach_absolute_time();
914
+ vmstate_register(NULL, 0, &vmstate_hvf_vtimer, &vtimer);
915
+ qemu_add_vm_change_state_handler(hvf_vm_state_change, &vtimer);
916
+ return 0;
917
+}
918
diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c
919
index XXXXXXX..XXXXXXX 100644
594
index XXXXXXX..XXXXXXX 100644
920
--- a/target/i386/hvf/hvf.c
595
--- a/tests/qtest/meson.build
921
+++ b/target/i386/hvf/hvf.c
596
+++ b/tests/qtest/meson.build
922
@@ -XXX,XX +XXX,XX @@ static inline bool apic_bus_freq_is_known(CPUX86State *env)
597
@@ -XXX,XX +XXX,XX @@ qtests_aspeed = \
923
return env->apic_bus_freq != 0;
598
qtests_stm32l4x5 = \
924
}
599
['stm32l4x5_exti-test',
925
600
'stm32l4x5_syscfg-test',
926
+void hvf_kick_vcpu_thread(CPUState *cpu)
601
- 'stm32l4x5_rcc-test']
927
+{
602
+ 'stm32l4x5_rcc-test',
928
+ cpus_kick_thread(cpu);
603
+ 'stm32l4x5_gpio-test']
929
+}
604
930
+
605
qtests_arm = \
931
int hvf_arch_init(void)
606
(config_all_devices.has_key('CONFIG_MPS2') ? ['sse-timer-test'] : []) + \
932
{
933
return 0;
934
diff --git a/MAINTAINERS b/MAINTAINERS
935
index XXXXXXX..XXXXXXX 100644
936
--- a/MAINTAINERS
937
+++ b/MAINTAINERS
938
@@ -XXX,XX +XXX,XX @@ F: accel/accel-*.c
939
F: accel/Makefile.objs
940
F: accel/stubs/Makefile.objs
941
942
+Apple Silicon HVF CPUs
943
+M: Alexander Graf <agraf@csgraf.de>
944
+S: Maintained
945
+F: target/arm/hvf/
946
+
947
X86 HVF CPUs
948
M: Cameron Esfahani <dirty@apple.com>
949
M: Roman Bolshakov <r.bolshakov@yadro.com>
950
diff --git a/target/arm/hvf/trace-events b/target/arm/hvf/trace-events
951
new file mode 100644
952
index XXXXXXX..XXXXXXX
953
--- /dev/null
954
+++ b/target/arm/hvf/trace-events
955
@@ -XXX,XX +XXX,XX @@
956
+hvf_unhandled_sysreg_read(uint64_t pc, uint32_t reg, uint32_t op0, uint32_t op1, uint32_t crn, uint32_t crm, uint32_t op2) "unhandled sysreg read at pc=0x%"PRIx64": 0x%08x (op0=%d op1=%d crn=%d crm=%d op2=%d)"
957
+hvf_unhandled_sysreg_write(uint64_t pc, uint32_t reg, uint32_t op0, uint32_t op1, uint32_t crn, uint32_t crm, uint32_t op2) "unhandled sysreg write at pc=0x%"PRIx64": 0x%08x (op0=%d op1=%d crn=%d crm=%d op2=%d)"
958
+hvf_inject_fiq(void) "injecting FIQ"
959
+hvf_inject_irq(void) "injecting IRQ"
960
+hvf_data_abort(uint64_t pc, uint64_t va, uint64_t pa, bool isv, bool iswrite, bool s1ptw, uint32_t len, uint32_t srt) "data abort: [pc=0x%"PRIx64" va=0x%016"PRIx64" pa=0x%016"PRIx64" isv=%d iswrite=%d s1ptw=%d len=%d srt=%d]"
961
+hvf_sysreg_read(uint32_t reg, uint32_t op0, uint32_t op1, uint32_t crn, uint32_t crm, uint32_t op2, uint64_t val) "sysreg read 0x%08x (op0=%d op1=%d crn=%d crm=%d op2=%d) = 0x%016"PRIx64
962
+hvf_sysreg_write(uint32_t reg, uint32_t op0, uint32_t op1, uint32_t crn, uint32_t crm, uint32_t op2, uint64_t val) "sysreg write 0x%08x (op0=%d op1=%d crn=%d crm=%d op2=%d, val=0x%016"PRIx64")"
963
+hvf_unknown_hvc(uint64_t x0) "unknown HVC! 0x%016"PRIx64
964
+hvf_unknown_smc(uint64_t x0) "unknown SMC! 0x%016"PRIx64
965
+hvf_exit(uint64_t syndrome, uint32_t ec, uint64_t pc) "exit: 0x%"PRIx64" [ec=0x%x pc=0x%"PRIx64"]"
966
--
607
--
967
2.20.1
608
2.34.1
968
609
969
610
diff view generated by jsdifflib
1
When not predicating, implement the MVE bitwise logical insns
1
From: Richard Henderson <richard.henderson@linaro.org>
2
directly using TCG vector operations.
2
3
3
While the 8-bit input elements are sequential in the input vector,
4
the 32-bit output elements are not sequential in the output matrix.
5
Do not attempt to compute 2 32-bit outputs at the same time.
6
7
Cc: qemu-stable@nongnu.org
8
Fixes: 23a5e3859f5 ("target/arm: Implement SME integer outer product")
9
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2083
10
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
11
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
12
Message-id: 20240305163931.242795-1-richard.henderson@linaro.org
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
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>
7
Message-id: 20210913095440.13462-5-peter.maydell@linaro.org
8
---
14
---
9
target/arm/translate-mve.c | 51 +++++++++++++++++++++++++++-----------
15
target/arm/tcg/sme_helper.c | 77 ++++++++++++++++++-------------
10
1 file changed, 36 insertions(+), 15 deletions(-)
16
tests/tcg/aarch64/sme-smopa-1.c | 47 +++++++++++++++++++
11
17
tests/tcg/aarch64/sme-smopa-2.c | 54 ++++++++++++++++++++++
12
diff --git a/target/arm/translate-mve.c b/target/arm/translate-mve.c
18
tests/tcg/aarch64/Makefile.target | 2 +-
19
4 files changed, 147 insertions(+), 33 deletions(-)
20
create mode 100644 tests/tcg/aarch64/sme-smopa-1.c
21
create mode 100644 tests/tcg/aarch64/sme-smopa-2.c
22
23
diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c
13
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
14
--- a/target/arm/translate-mve.c
25
--- a/target/arm/tcg/sme_helper.c
15
+++ b/target/arm/translate-mve.c
26
+++ b/target/arm/tcg/sme_helper.c
16
@@ -XXX,XX +XXX,XX @@ static TCGv_ptr mve_qreg_ptr(unsigned reg)
27
@@ -XXX,XX +XXX,XX @@ void HELPER(sme_bfmopa)(void *vza, void *vzn, void *vzm, void *vpn,
17
return ret;
28
}
18
}
29
}
19
30
20
+static bool mve_no_predication(DisasContext *s)
31
-typedef uint64_t IMOPFn(uint64_t, uint64_t, uint64_t, uint8_t, bool);
32
+typedef uint32_t IMOPFn32(uint32_t, uint32_t, uint32_t, uint8_t, bool);
33
+static inline void do_imopa_s(uint32_t *za, uint32_t *zn, uint32_t *zm,
34
+ uint8_t *pn, uint8_t *pm,
35
+ uint32_t desc, IMOPFn32 *fn)
21
+{
36
+{
22
+ /*
37
+ intptr_t row, col, oprsz = simd_oprsz(desc) / 4;
23
+ * Return true if we are executing the entire MVE instruction
38
+ bool neg = simd_data(desc);
24
+ * with no predication or partial-execution, and so we can safely
39
25
+ * use an inline TCG vector implementation.
40
-static inline void do_imopa(uint64_t *za, uint64_t *zn, uint64_t *zm,
26
+ */
41
- uint8_t *pn, uint8_t *pm,
27
+ return s->eci == 0 && s->mve_no_pred;
42
- uint32_t desc, IMOPFn *fn)
43
+ for (row = 0; row < oprsz; ++row) {
44
+ uint8_t pa = (pn[H1(row >> 1)] >> ((row & 1) * 4)) & 0xf;
45
+ uint32_t *za_row = &za[tile_vslice_index(row)];
46
+ uint32_t n = zn[H4(row)];
47
+
48
+ for (col = 0; col < oprsz; ++col) {
49
+ uint8_t pb = pm[H1(col >> 1)] >> ((col & 1) * 4);
50
+ uint32_t *a = &za_row[H4(col)];
51
+
52
+ *a = fn(n, zm[H4(col)], *a, pa & pb, neg);
53
+ }
54
+ }
28
+}
55
+}
29
+
56
+
30
static bool mve_check_qreg_bank(DisasContext *s, int qmask)
57
+typedef uint64_t IMOPFn64(uint64_t, uint64_t, uint64_t, uint8_t, bool);
58
+static inline void do_imopa_d(uint64_t *za, uint64_t *zn, uint64_t *zm,
59
+ uint8_t *pn, uint8_t *pm,
60
+ uint32_t desc, IMOPFn64 *fn)
31
{
61
{
32
/*
62
intptr_t row, col, oprsz = simd_oprsz(desc) / 8;
33
@@ -XXX,XX +XXX,XX @@ static bool trans_VNEG_fp(DisasContext *s, arg_1op *a)
63
bool neg = simd_data(desc);
34
return do_1op(s, a, fns[a->size]);
64
@@ -XXX,XX +XXX,XX @@ static inline void do_imopa(uint64_t *za, uint64_t *zn, uint64_t *zm,
35
}
65
}
36
66
37
-static bool do_2op(DisasContext *s, arg_2op *a, MVEGenTwoOpFn fn)
67
#define DEF_IMOP_32(NAME, NTYPE, MTYPE) \
38
+static bool do_2op_vec(DisasContext *s, arg_2op *a, MVEGenTwoOpFn fn,
68
-static uint64_t NAME(uint64_t n, uint64_t m, uint64_t a, uint8_t p, bool neg) \
39
+ GVecGen3Fn *vecfn)
69
+static uint32_t NAME(uint32_t n, uint32_t m, uint32_t a, uint8_t p, bool neg) \
40
{
70
{ \
41
TCGv_ptr qd, qn, qm;
71
- uint32_t sum0 = 0, sum1 = 0; \
42
72
+ uint32_t sum = 0; \
43
@@ -XXX,XX +XXX,XX @@ static bool do_2op(DisasContext *s, arg_2op *a, MVEGenTwoOpFn fn)
73
/* Apply P to N as a mask, making the inactive elements 0. */ \
44
return true;
74
n &= expand_pred_b(p); \
45
}
75
- sum0 += (NTYPE)(n >> 0) * (MTYPE)(m >> 0); \
46
76
- sum0 += (NTYPE)(n >> 8) * (MTYPE)(m >> 8); \
47
- qd = mve_qreg_ptr(a->qd);
77
- sum0 += (NTYPE)(n >> 16) * (MTYPE)(m >> 16); \
48
- qn = mve_qreg_ptr(a->qn);
78
- sum0 += (NTYPE)(n >> 24) * (MTYPE)(m >> 24); \
49
- qm = mve_qreg_ptr(a->qm);
79
- sum1 += (NTYPE)(n >> 32) * (MTYPE)(m >> 32); \
50
- fn(cpu_env, qd, qn, qm);
80
- sum1 += (NTYPE)(n >> 40) * (MTYPE)(m >> 40); \
51
- tcg_temp_free_ptr(qd);
81
- sum1 += (NTYPE)(n >> 48) * (MTYPE)(m >> 48); \
52
- tcg_temp_free_ptr(qn);
82
- sum1 += (NTYPE)(n >> 56) * (MTYPE)(m >> 56); \
53
- tcg_temp_free_ptr(qm);
83
- if (neg) { \
54
+ if (vecfn && mve_no_predication(s)) {
84
- sum0 = (uint32_t)a - sum0, sum1 = (uint32_t)(a >> 32) - sum1; \
55
+ vecfn(a->size, mve_qreg_offset(a->qd), mve_qreg_offset(a->qn),
85
- } else { \
56
+ mve_qreg_offset(a->qm), 16, 16);
86
- sum0 = (uint32_t)a + sum0, sum1 = (uint32_t)(a >> 32) + sum1; \
57
+ } else {
87
- } \
58
+ qd = mve_qreg_ptr(a->qd);
88
- return ((uint64_t)sum1 << 32) | sum0; \
59
+ qn = mve_qreg_ptr(a->qn);
89
+ sum += (NTYPE)(n >> 0) * (MTYPE)(m >> 0); \
60
+ qm = mve_qreg_ptr(a->qm);
90
+ sum += (NTYPE)(n >> 8) * (MTYPE)(m >> 8); \
61
+ fn(cpu_env, qd, qn, qm);
91
+ sum += (NTYPE)(n >> 16) * (MTYPE)(m >> 16); \
62
+ tcg_temp_free_ptr(qd);
92
+ sum += (NTYPE)(n >> 24) * (MTYPE)(m >> 24); \
63
+ tcg_temp_free_ptr(qn);
93
+ return neg ? a - sum : a + sum; \
64
+ tcg_temp_free_ptr(qm);
65
+ }
66
mve_update_eci(s);
67
return true;
68
}
94
}
69
95
70
-#define DO_LOGIC(INSN, HELPER) \
96
#define DEF_IMOP_64(NAME, NTYPE, MTYPE) \
71
+static bool do_2op(DisasContext *s, arg_2op *a, MVEGenTwoOpFn *fn)
97
@@ -XXX,XX +XXX,XX @@ DEF_IMOP_64(umopa_d, uint16_t, uint16_t)
98
DEF_IMOP_64(sumopa_d, int16_t, uint16_t)
99
DEF_IMOP_64(usmopa_d, uint16_t, int16_t)
100
101
-#define DEF_IMOPH(NAME) \
102
- void HELPER(sme_##NAME)(void *vza, void *vzn, void *vzm, void *vpn, \
103
- void *vpm, uint32_t desc) \
104
- { do_imopa(vza, vzn, vzm, vpn, vpm, desc, NAME); }
105
+#define DEF_IMOPH(NAME, S) \
106
+ void HELPER(sme_##NAME##_##S)(void *vza, void *vzn, void *vzm, \
107
+ void *vpn, void *vpm, uint32_t desc) \
108
+ { do_imopa_##S(vza, vzn, vzm, vpn, vpm, desc, NAME##_##S); }
109
110
-DEF_IMOPH(smopa_s)
111
-DEF_IMOPH(umopa_s)
112
-DEF_IMOPH(sumopa_s)
113
-DEF_IMOPH(usmopa_s)
114
-DEF_IMOPH(smopa_d)
115
-DEF_IMOPH(umopa_d)
116
-DEF_IMOPH(sumopa_d)
117
-DEF_IMOPH(usmopa_d)
118
+DEF_IMOPH(smopa, s)
119
+DEF_IMOPH(umopa, s)
120
+DEF_IMOPH(sumopa, s)
121
+DEF_IMOPH(usmopa, s)
122
+
123
+DEF_IMOPH(smopa, d)
124
+DEF_IMOPH(umopa, d)
125
+DEF_IMOPH(sumopa, d)
126
+DEF_IMOPH(usmopa, d)
127
diff --git a/tests/tcg/aarch64/sme-smopa-1.c b/tests/tcg/aarch64/sme-smopa-1.c
128
new file mode 100644
129
index XXXXXXX..XXXXXXX
130
--- /dev/null
131
+++ b/tests/tcg/aarch64/sme-smopa-1.c
132
@@ -XXX,XX +XXX,XX @@
133
+#include <stdio.h>
134
+#include <string.h>
135
+
136
+int main()
72
+{
137
+{
73
+ return do_2op_vec(s, a, fn, NULL);
138
+ static const int cmp[4][4] = {
139
+ { 110, 134, 158, 182 },
140
+ { 390, 478, 566, 654 },
141
+ { 670, 822, 974, 1126 },
142
+ { 950, 1166, 1382, 1598 }
143
+ };
144
+ int dst[4][4];
145
+ int *tmp = &dst[0][0];
146
+
147
+ asm volatile(
148
+ ".arch armv8-r+sme\n\t"
149
+ "smstart\n\t"
150
+ "index z0.b, #0, #1\n\t"
151
+ "movprfx z1, z0\n\t"
152
+ "add z1.b, z1.b, #16\n\t"
153
+ "ptrue p0.b\n\t"
154
+ "smopa za0.s, p0/m, p0/m, z0.b, z1.b\n\t"
155
+ "ptrue p0.s, vl4\n\t"
156
+ "mov w12, #0\n\t"
157
+ "st1w { za0h.s[w12, #0] }, p0, [%0]\n\t"
158
+ "add %0, %0, #16\n\t"
159
+ "st1w { za0h.s[w12, #1] }, p0, [%0]\n\t"
160
+ "add %0, %0, #16\n\t"
161
+ "st1w { za0h.s[w12, #2] }, p0, [%0]\n\t"
162
+ "add %0, %0, #16\n\t"
163
+ "st1w { za0h.s[w12, #3] }, p0, [%0]\n\t"
164
+ "smstop"
165
+ : "+r"(tmp) : : "memory");
166
+
167
+ if (memcmp(cmp, dst, sizeof(dst)) == 0) {
168
+ return 0;
169
+ }
170
+
171
+ /* See above for correct results. */
172
+ for (int i = 0; i < 4; ++i) {
173
+ for (int j = 0; j < 4; ++j) {
174
+ printf("%6d", dst[i][j]);
175
+ }
176
+ printf("\n");
177
+ }
178
+ return 1;
74
+}
179
+}
75
+
180
diff --git a/tests/tcg/aarch64/sme-smopa-2.c b/tests/tcg/aarch64/sme-smopa-2.c
76
+#define DO_LOGIC(INSN, HELPER, VECFN) \
181
new file mode 100644
77
static bool trans_##INSN(DisasContext *s, arg_2op *a) \
182
index XXXXXXX..XXXXXXX
78
{ \
183
--- /dev/null
79
- return do_2op(s, a, HELPER); \
184
+++ b/tests/tcg/aarch64/sme-smopa-2.c
80
+ return do_2op_vec(s, a, HELPER, VECFN); \
185
@@ -XXX,XX +XXX,XX @@
81
}
186
+#include <stdio.h>
82
187
+#include <string.h>
83
-DO_LOGIC(VAND, gen_helper_mve_vand)
188
+
84
-DO_LOGIC(VBIC, gen_helper_mve_vbic)
189
+int main()
85
-DO_LOGIC(VORR, gen_helper_mve_vorr)
190
+{
86
-DO_LOGIC(VORN, gen_helper_mve_vorn)
191
+ static const long cmp[4][4] = {
87
-DO_LOGIC(VEOR, gen_helper_mve_veor)
192
+ { 110, 134, 158, 182 },
88
+DO_LOGIC(VAND, gen_helper_mve_vand, tcg_gen_gvec_and)
193
+ { 390, 478, 566, 654 },
89
+DO_LOGIC(VBIC, gen_helper_mve_vbic, tcg_gen_gvec_andc)
194
+ { 670, 822, 974, 1126 },
90
+DO_LOGIC(VORR, gen_helper_mve_vorr, tcg_gen_gvec_or)
195
+ { 950, 1166, 1382, 1598 }
91
+DO_LOGIC(VORN, gen_helper_mve_vorn, tcg_gen_gvec_orc)
196
+ };
92
+DO_LOGIC(VEOR, gen_helper_mve_veor, tcg_gen_gvec_xor)
197
+ long dst[4][4];
93
198
+ long *tmp = &dst[0][0];
94
static bool trans_VPSEL(DisasContext *s, arg_2op *a)
199
+ long svl;
95
{
200
+
201
+ /* Validate that we have a wide enough vector for 4 elements. */
202
+ asm(".arch armv8-r+sme-i64\n\trdsvl %0, #1" : "=r"(svl));
203
+ if (svl < 32) {
204
+ return 0;
205
+ }
206
+
207
+ asm volatile(
208
+ "smstart\n\t"
209
+ "index z0.h, #0, #1\n\t"
210
+ "movprfx z1, z0\n\t"
211
+ "add z1.h, z1.h, #16\n\t"
212
+ "ptrue p0.b\n\t"
213
+ "smopa za0.d, p0/m, p0/m, z0.h, z1.h\n\t"
214
+ "ptrue p0.d, vl4\n\t"
215
+ "mov w12, #0\n\t"
216
+ "st1d { za0h.d[w12, #0] }, p0, [%0]\n\t"
217
+ "add %0, %0, #32\n\t"
218
+ "st1d { za0h.d[w12, #1] }, p0, [%0]\n\t"
219
+ "mov w12, #2\n\t"
220
+ "add %0, %0, #32\n\t"
221
+ "st1d { za0h.d[w12, #0] }, p0, [%0]\n\t"
222
+ "add %0, %0, #32\n\t"
223
+ "st1d { za0h.d[w12, #1] }, p0, [%0]\n\t"
224
+ "smstop"
225
+ : "+r"(tmp) : : "memory");
226
+
227
+ if (memcmp(cmp, dst, sizeof(dst)) == 0) {
228
+ return 0;
229
+ }
230
+
231
+ /* See above for correct results. */
232
+ for (int i = 0; i < 4; ++i) {
233
+ for (int j = 0; j < 4; ++j) {
234
+ printf("%6ld", dst[i][j]);
235
+ }
236
+ printf("\n");
237
+ }
238
+ return 1;
239
+}
240
diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target
241
index XXXXXXX..XXXXXXX 100644
242
--- a/tests/tcg/aarch64/Makefile.target
243
+++ b/tests/tcg/aarch64/Makefile.target
244
@@ -XXX,XX +XXX,XX @@ endif
245
246
# SME Tests
247
ifneq ($(CROSS_AS_HAS_ARMV9_SME),)
248
-AARCH64_TESTS += sme-outprod1
249
+AARCH64_TESTS += sme-outprod1 sme-smopa-1 sme-smopa-2
250
endif
251
252
# System Registers Tests
96
--
253
--
97
2.20.1
254
2.34.1
98
255
99
256
diff view generated by jsdifflib
1
Coverity points out that we aren't checking the return value
1
The sun4v RTC device model added under commit a0e893039cf2ce0 in 2016
2
from curl_easy_setopt().
2
was unfortunately added with a license of GPL-v3-or-later, which is
3
not compatible with other QEMU code which has a GPL-v2-only license.
3
4
4
Fixes: Coverity CID 1458895
5
Relicense the code in the .c and the .h file to GPL-v2-or-later,
5
Inspired-by: Peter Maydell <peter.maydell@linaro.org>
6
to make it compatible with the rest of QEMU.
6
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
7
7
Reviewed-by: Viktor Prutyanov <viktor.prutyanov@phystech.edu>
8
Cc: qemu-stable@nongnu.org
8
Tested-by: Viktor Prutyanov <viktor.prutyanov@phystech.edu>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Message-id: 20210910170656.366592-2-philmd@redhat.com
10
Signed-off-by: Paolo Bonzini (for Red Hat) <pbonzini@redhat.com>
11
Signed-off-by: Artyom Tarasenko <atar4qemu@gmail.com>
12
Signed-off-by: Markus Armbruster <armbru@redhat.com>
13
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
14
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
15
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
16
Acked-by: Alex Bennée <alex.bennee@linaro.org>
17
Message-id: 20240223161300.938542-1-peter.maydell@linaro.org
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
18
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
19
---
12
contrib/elf2dmp/download.c | 22 ++++++++++------------
20
include/hw/rtc/sun4v-rtc.h | 2 +-
13
1 file changed, 10 insertions(+), 12 deletions(-)
21
hw/rtc/sun4v-rtc.c | 2 +-
22
2 files changed, 2 insertions(+), 2 deletions(-)
14
23
15
diff --git a/contrib/elf2dmp/download.c b/contrib/elf2dmp/download.c
24
diff --git a/include/hw/rtc/sun4v-rtc.h b/include/hw/rtc/sun4v-rtc.h
16
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
17
--- a/contrib/elf2dmp/download.c
26
--- a/include/hw/rtc/sun4v-rtc.h
18
+++ b/contrib/elf2dmp/download.c
27
+++ b/include/hw/rtc/sun4v-rtc.h
19
@@ -XXX,XX +XXX,XX @@ int download_url(const char *name, const char *url)
28
@@ -XXX,XX +XXX,XX @@
20
goto out_curl;
29
*
21
}
30
* Copyright (c) 2016 Artyom Tarasenko
22
31
*
23
- curl_easy_setopt(curl, CURLOPT_URL, url);
32
- * This code is licensed under the GNU GPL v3 or (at your option) any later
24
- curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL);
33
+ * This code is licensed under the GNU GPL v2 or (at your option) any later
25
- curl_easy_setopt(curl, CURLOPT_WRITEDATA, file);
34
* version.
26
- curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
35
*/
27
- curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
36
28
-
37
diff --git a/hw/rtc/sun4v-rtc.c b/hw/rtc/sun4v-rtc.c
29
- if (curl_easy_perform(curl) != CURLE_OK) {
38
index XXXXXXX..XXXXXXX 100644
30
- err = 1;
39
--- a/hw/rtc/sun4v-rtc.c
31
- fclose(file);
40
+++ b/hw/rtc/sun4v-rtc.c
32
+ if (curl_easy_setopt(curl, CURLOPT_URL, url) != CURLE_OK
41
@@ -XXX,XX +XXX,XX @@
33
+ || curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL) != CURLE_OK
42
*
34
+ || curl_easy_setopt(curl, CURLOPT_WRITEDATA, file) != CURLE_OK
43
* Copyright (c) 2016 Artyom Tarasenko
35
+ || curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1) != CURLE_OK
44
*
36
+ || curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0) != CURLE_OK
45
- * This code is licensed under the GNU GPL v3 or (at your option) any later
37
+ || curl_easy_perform(curl) != CURLE_OK) {
46
+ * This code is licensed under the GNU GPL v2 or (at your option) any later
38
unlink(name);
47
* version.
39
- goto out_curl;
48
*/
40
+ fclose(file);
41
+ err = 1;
42
+ } else {
43
+ err = fclose(file);
44
}
45
46
- err = fclose(file);
47
-
48
out_curl:
49
curl_easy_cleanup(curl);
50
49
51
--
50
--
52
2.20.1
51
2.34.1
53
52
54
53
diff view generated by jsdifflib
Deleted patch
1
Coverity points out that if the PDB file we're trying to read
2
has a header specifying a block_size of zero then we will
3
end up trying to divide by zero in pdb_ds_read_file().
4
Check for this and fail cleanly instead.
5
1
6
Fixes: Coverity CID 1458869
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Viktor Prutyanov <viktor.prutyanov@phystech.edu>
9
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
10
Tested-by: Viktor Prutyanov <viktor.prutyanov@phystech.edu>
11
Message-id: 20210910170656.366592-3-philmd@redhat.com
12
Message-Id: <20210901143910.17112-3-peter.maydell@linaro.org>
13
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
14
---
15
contrib/elf2dmp/pdb.c | 4 ++++
16
1 file changed, 4 insertions(+)
17
18
diff --git a/contrib/elf2dmp/pdb.c b/contrib/elf2dmp/pdb.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/contrib/elf2dmp/pdb.c
21
+++ b/contrib/elf2dmp/pdb.c
22
@@ -XXX,XX +XXX,XX @@ out_symbols:
23
24
static int pdb_reader_ds_init(struct pdb_reader *r, PDB_DS_HEADER *hdr)
25
{
26
+ if (hdr->block_size == 0) {
27
+ return 1;
28
+ }
29
+
30
memset(r->file_used, 0, sizeof(r->file_used));
31
r->ds.header = hdr;
32
r->ds.toc = pdb_ds_read(hdr, (uint32_t *)((uint8_t *)hdr +
33
--
34
2.20.1
35
36
diff view generated by jsdifflib
Deleted patch
1
Currently all of the M-profile specific code in arm_cpu_reset() is
2
inside a !defined(CONFIG_USER_ONLY) ifdef block. This is
3
unintentional: it happened because originally the only
4
M-profile-specific handling was the setup of the initial SP and PC
5
from the vector table, which is system-emulation only. But then we
6
added a lot of other M-profile setup to the same "if (ARM_FEATURE_M)"
7
code block without noticing that it was all inside a not-user-mode
8
ifdef. This has generally been harmless, but with the addition of
9
v8.1M low-overhead-loop support we ran into a problem: the reset of
10
FPSCR.LTPSIZE to 4 was only being done for system emulation mode, so
11
if a user-mode guest tried to execute the LE instruction it would
12
incorrectly take a UsageFault.
13
1
14
Adjust the ifdefs so only the really system-emulation specific parts
15
are covered. Because this means we now run some reset code that sets
16
up initial values in the FPCCR and similar FPU related registers,
17
explicitly set up the registers controlling FPU context handling in
18
user-emulation mode so that the FPU works by design and not by
19
chance.
20
21
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/613
22
Cc: qemu-stable@nongnu.org
23
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
24
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
25
Message-id: 20210914120725.24992-2-peter.maydell@linaro.org
26
---
27
target/arm/cpu.c | 19 +++++++++++++++++++
28
1 file changed, 19 insertions(+)
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 @@ static void arm_cpu_reset(DeviceState *dev)
35
env->uncached_cpsr = ARM_CPU_MODE_SVC;
36
}
37
env->daif = PSTATE_D | PSTATE_A | PSTATE_I | PSTATE_F;
38
+#endif
39
40
if (arm_feature(env, ARM_FEATURE_M)) {
41
+#ifndef CONFIG_USER_ONLY
42
uint32_t initial_msp; /* Loaded from 0x0 */
43
uint32_t initial_pc; /* Loaded from 0x4 */
44
uint8_t *rom;
45
uint32_t vecbase;
46
+#endif
47
48
if (cpu_isar_feature(aa32_lob, cpu)) {
49
/*
50
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_reset(DeviceState *dev)
51
env->v7m.fpccr[M_REG_S] = R_V7M_FPCCR_ASPEN_MASK |
52
R_V7M_FPCCR_LSPEN_MASK | R_V7M_FPCCR_S_MASK;
53
}
54
+
55
+#ifndef CONFIG_USER_ONLY
56
/* Unlike A/R profile, M profile defines the reset LR value */
57
env->regs[14] = 0xffffffff;
58
59
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_reset(DeviceState *dev)
60
env->regs[13] = initial_msp & 0xFFFFFFFC;
61
env->regs[15] = initial_pc & ~1;
62
env->thumb = initial_pc & 1;
63
+#else
64
+ /*
65
+ * For user mode we run non-secure and with access to the FPU.
66
+ * The FPU context is active (ie does not need further setup)
67
+ * and is owned by non-secure.
68
+ */
69
+ env->v7m.secure = false;
70
+ env->v7m.nsacr = 0xcff;
71
+ env->v7m.cpacr[M_REG_NS] = 0xf0ffff;
72
+ env->v7m.fpccr[M_REG_S] &=
73
+ ~(R_V7M_FPCCR_LSPEN_MASK | R_V7M_FPCCR_S_MASK);
74
+ env->v7m.control[M_REG_S] |= R_V7M_CONTROL_FPCA_MASK;
75
+#endif
76
}
77
78
+#ifndef CONFIG_USER_ONLY
79
/* AArch32 has a hard highvec setting of 0xFFFF0000. If we are currently
80
* executing as AArch32 then check if highvecs are enabled and
81
* adjust the PC accordingly.
82
--
83
2.20.1
84
85
diff view generated by jsdifflib
Deleted patch
1
There's no particular reason why the exclusive monitor should
2
be only cleared on reset in system emulation mode. It doesn't
3
hurt if it isn't cleared in user mode, but we might as well
4
reduce the amount of code we have that's inside an ifdef.
5
1
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20210914120725.24992-3-peter.maydell@linaro.org
9
---
10
target/arm/cpu.c | 6 +++---
11
1 file changed, 3 insertions(+), 3 deletions(-)
12
13
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/target/arm/cpu.c
16
+++ b/target/arm/cpu.c
17
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_reset(DeviceState *dev)
18
env->regs[15] = 0xFFFF0000;
19
}
20
21
+ env->vfp.xregs[ARM_VFP_FPEXC] = 0;
22
+#endif
23
+
24
/* M profile requires that reset clears the exclusive monitor;
25
* A profile does not, but clearing it makes more sense than having it
26
* set with an exclusive access on address zero.
27
*/
28
arm_clear_exclusive(env);
29
30
- env->vfp.xregs[ARM_VFP_FPEXC] = 0;
31
-#endif
32
-
33
if (arm_feature(env, ARM_FEATURE_PMSA)) {
34
if (cpu->pmsav7_dregion > 0) {
35
if (arm_feature(env, ARM_FEATURE_V8)) {
36
--
37
2.20.1
38
39
diff view generated by jsdifflib
Deleted patch
1
From: Shashi Mallela <shashi.mallela@linaro.org>
2
1
3
During sbsa acs level 3 testing, it is seen that the GIC maintenance
4
interrupts are not triggered and the related test cases fail. This
5
is because we were incorrectly passing the value of the MISR register
6
(from maintenance_interrupt_state()) to qemu_set_irq() as the level
7
argument, whereas the device on the other end of this irq line
8
expects a 0/1 value.
9
10
Fix the logic to pass a 0/1 level indication, rather than a
11
0/not-0 value.
12
13
Fixes: c5fc89b36c0 ("hw/intc/arm_gicv3: Implement gicv3_cpuif_virt_update()")
14
Signed-off-by: Shashi Mallela <shashi.mallela@linaro.org>
15
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
16
Message-id: 20210915205809.59068-1-shashi.mallela@linaro.org
17
[PMM: tweaked commit message; collapsed nested if()s into one]
18
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
19
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
20
---
21
hw/intc/arm_gicv3_cpuif.c | 5 +++--
22
1 file changed, 3 insertions(+), 2 deletions(-)
23
24
diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
25
index XXXXXXX..XXXXXXX 100644
26
--- a/hw/intc/arm_gicv3_cpuif.c
27
+++ b/hw/intc/arm_gicv3_cpuif.c
28
@@ -XXX,XX +XXX,XX @@ static void gicv3_cpuif_virt_update(GICv3CPUState *cs)
29
}
30
}
31
32
- if (cs->ich_hcr_el2 & ICH_HCR_EL2_EN) {
33
- maintlevel = maintenance_interrupt_state(cs);
34
+ if ((cs->ich_hcr_el2 & ICH_HCR_EL2_EN) &&
35
+ maintenance_interrupt_state(cs) != 0) {
36
+ maintlevel = 1;
37
}
38
39
trace_gicv3_cpuif_virt_set_irqs(gicv3_redist_affid(cs), fiqlevel,
40
--
41
2.20.1
42
43
diff view generated by jsdifflib
Deleted patch
1
From: Alexander Graf <agraf@csgraf.de>
2
1
3
Hvf's permission bitmap during and after dirty logging does not include
4
the HV_MEMORY_EXEC permission. At least on Apple Silicon, this leads to
5
instruction faults once dirty logging was enabled.
6
7
Add the bit to make it work properly.
8
9
Signed-off-by: Alexander Graf <agraf@csgraf.de>
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
11
Message-id: 20210916155404.86958-3-agraf@csgraf.de
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
---
14
accel/hvf/hvf-accel-ops.c | 4 ++--
15
1 file changed, 2 insertions(+), 2 deletions(-)
16
17
diff --git a/accel/hvf/hvf-accel-ops.c b/accel/hvf/hvf-accel-ops.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/accel/hvf/hvf-accel-ops.c
20
+++ b/accel/hvf/hvf-accel-ops.c
21
@@ -XXX,XX +XXX,XX @@ static void hvf_set_dirty_tracking(MemoryRegionSection *section, bool on)
22
if (on) {
23
slot->flags |= HVF_SLOT_LOG;
24
hv_vm_protect((uintptr_t)slot->start, (size_t)slot->size,
25
- HV_MEMORY_READ);
26
+ HV_MEMORY_READ | HV_MEMORY_EXEC);
27
/* stop tracking region*/
28
} else {
29
slot->flags &= ~HVF_SLOT_LOG;
30
hv_vm_protect((uintptr_t)slot->start, (size_t)slot->size,
31
- HV_MEMORY_READ | HV_MEMORY_WRITE);
32
+ HV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC);
33
}
34
}
35
36
--
37
2.20.1
38
39
diff view generated by jsdifflib
Deleted patch
1
From: Alexander Graf <agraf@csgraf.de>
2
1
3
We will need to install a migration helper for the ARM hvf backend.
4
Let's introduce an arch callback for the overall hvf init chain to
5
do so.
6
7
Signed-off-by: Alexander Graf <agraf@csgraf.de>
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Message-id: 20210916155404.86958-4-agraf@csgraf.de
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
12
include/sysemu/hvf_int.h | 1 +
13
accel/hvf/hvf-accel-ops.c | 3 ++-
14
target/i386/hvf/hvf.c | 5 +++++
15
3 files changed, 8 insertions(+), 1 deletion(-)
16
17
diff --git a/include/sysemu/hvf_int.h b/include/sysemu/hvf_int.h
18
index XXXXXXX..XXXXXXX 100644
19
--- a/include/sysemu/hvf_int.h
20
+++ b/include/sysemu/hvf_int.h
21
@@ -XXX,XX +XXX,XX @@ struct hvf_vcpu_state {
22
};
23
24
void assert_hvf_ok(hv_return_t ret);
25
+int hvf_arch_init(void);
26
int hvf_arch_init_vcpu(CPUState *cpu);
27
void hvf_arch_vcpu_destroy(CPUState *cpu);
28
int hvf_vcpu_exec(CPUState *);
29
diff --git a/accel/hvf/hvf-accel-ops.c b/accel/hvf/hvf-accel-ops.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/accel/hvf/hvf-accel-ops.c
32
+++ b/accel/hvf/hvf-accel-ops.c
33
@@ -XXX,XX +XXX,XX @@ static int hvf_accel_init(MachineState *ms)
34
35
hvf_state = s;
36
memory_listener_register(&hvf_memory_listener, &address_space_memory);
37
- return 0;
38
+
39
+ return hvf_arch_init();
40
}
41
42
static void hvf_accel_class_init(ObjectClass *oc, void *data)
43
diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c
44
index XXXXXXX..XXXXXXX 100644
45
--- a/target/i386/hvf/hvf.c
46
+++ b/target/i386/hvf/hvf.c
47
@@ -XXX,XX +XXX,XX @@ static inline bool apic_bus_freq_is_known(CPUX86State *env)
48
return env->apic_bus_freq != 0;
49
}
50
51
+int hvf_arch_init(void)
52
+{
53
+ return 0;
54
+}
55
+
56
int hvf_arch_init_vcpu(CPUState *cpu)
57
{
58
X86CPU *x86cpu = X86_CPU(cpu);
59
--
60
2.20.1
61
62
diff view generated by jsdifflib
Deleted patch
1
From: Peter Collingbourne <pcc@google.com>
2
1
3
Sleep on WFI until the VTIMER is due but allow ourselves to be woken
4
up on IPI.
5
6
In this implementation IPI is blocked on the CPU thread at startup and
7
pselect() is used to atomically unblock the signal and begin sleeping.
8
The signal is sent unconditionally so there's no need to worry about
9
races between actually sleeping and the "we think we're sleeping"
10
state. It may lead to an extra wakeup but that's better than missing
11
it entirely.
12
13
Signed-off-by: Peter Collingbourne <pcc@google.com>
14
Signed-off-by: Alexander Graf <agraf@csgraf.de>
15
Acked-by: Roman Bolshakov <r.bolshakov@yadro.com>
16
Reviewed-by: Sergio Lopez <slp@redhat.com>
17
Message-id: 20210916155404.86958-6-agraf@csgraf.de
18
[agraf: Remove unused 'set' variable, always advance PC on WFX trap,
19
support vm stop / continue operations and cntv offsets]
20
Signed-off-by: Alexander Graf <agraf@csgraf.de>
21
Acked-by: Roman Bolshakov <r.bolshakov@yadro.com>
22
Reviewed-by: Sergio Lopez <slp@redhat.com>
23
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
24
---
25
include/sysemu/hvf_int.h | 1 +
26
accel/hvf/hvf-accel-ops.c | 5 +--
27
target/arm/hvf/hvf.c | 79 +++++++++++++++++++++++++++++++++++++++
28
3 files changed, 82 insertions(+), 3 deletions(-)
29
30
diff --git a/include/sysemu/hvf_int.h b/include/sysemu/hvf_int.h
31
index XXXXXXX..XXXXXXX 100644
32
--- a/include/sysemu/hvf_int.h
33
+++ b/include/sysemu/hvf_int.h
34
@@ -XXX,XX +XXX,XX @@ struct hvf_vcpu_state {
35
uint64_t fd;
36
void *exit;
37
bool vtimer_masked;
38
+ sigset_t unblock_ipi_mask;
39
};
40
41
void assert_hvf_ok(hv_return_t ret);
42
diff --git a/accel/hvf/hvf-accel-ops.c b/accel/hvf/hvf-accel-ops.c
43
index XXXXXXX..XXXXXXX 100644
44
--- a/accel/hvf/hvf-accel-ops.c
45
+++ b/accel/hvf/hvf-accel-ops.c
46
@@ -XXX,XX +XXX,XX @@ static int hvf_init_vcpu(CPUState *cpu)
47
cpu->hvf = g_malloc0(sizeof(*cpu->hvf));
48
49
/* init cpu signals */
50
- sigset_t set;
51
struct sigaction sigact;
52
53
memset(&sigact, 0, sizeof(sigact));
54
sigact.sa_handler = dummy_signal;
55
sigaction(SIG_IPI, &sigact, NULL);
56
57
- pthread_sigmask(SIG_BLOCK, NULL, &set);
58
- sigdelset(&set, SIG_IPI);
59
+ pthread_sigmask(SIG_BLOCK, NULL, &cpu->hvf->unblock_ipi_mask);
60
+ sigdelset(&cpu->hvf->unblock_ipi_mask, SIG_IPI);
61
62
#ifdef __aarch64__
63
r = hv_vcpu_create(&cpu->hvf->fd, (hv_vcpu_exit_t **)&cpu->hvf->exit, NULL);
64
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
65
index XXXXXXX..XXXXXXX 100644
66
--- a/target/arm/hvf/hvf.c
67
+++ b/target/arm/hvf/hvf.c
68
@@ -XXX,XX +XXX,XX @@
69
* QEMU Hypervisor.framework support for Apple Silicon
70
71
* Copyright 2020 Alexander Graf <agraf@csgraf.de>
72
+ * Copyright 2020 Google LLC
73
*
74
* This work is licensed under the terms of the GNU GPL, version 2 or later.
75
* See the COPYING file in the top-level directory.
76
@@ -XXX,XX +XXX,XX @@ int hvf_arch_init_vcpu(CPUState *cpu)
77
78
void hvf_kick_vcpu_thread(CPUState *cpu)
79
{
80
+ cpus_kick_thread(cpu);
81
hv_vcpus_exit(&cpu->hvf->fd, 1);
82
}
83
84
@@ -XXX,XX +XXX,XX @@ static uint64_t hvf_vtimer_val_raw(void)
85
return mach_absolute_time() - hvf_state->vtimer_offset;
86
}
87
88
+static uint64_t hvf_vtimer_val(void)
89
+{
90
+ if (!runstate_is_running()) {
91
+ /* VM is paused, the vtimer value is in vtimer.vtimer_val */
92
+ return vtimer.vtimer_val;
93
+ }
94
+
95
+ return hvf_vtimer_val_raw();
96
+}
97
+
98
+static void hvf_wait_for_ipi(CPUState *cpu, struct timespec *ts)
99
+{
100
+ /*
101
+ * Use pselect to sleep so that other threads can IPI us while we're
102
+ * sleeping.
103
+ */
104
+ qatomic_mb_set(&cpu->thread_kicked, false);
105
+ qemu_mutex_unlock_iothread();
106
+ pselect(0, 0, 0, 0, ts, &cpu->hvf->unblock_ipi_mask);
107
+ qemu_mutex_lock_iothread();
108
+}
109
+
110
+static void hvf_wfi(CPUState *cpu)
111
+{
112
+ ARMCPU *arm_cpu = ARM_CPU(cpu);
113
+ struct timespec ts;
114
+ hv_return_t r;
115
+ uint64_t ctl;
116
+ uint64_t cval;
117
+ int64_t ticks_to_sleep;
118
+ uint64_t seconds;
119
+ uint64_t nanos;
120
+ uint32_t cntfrq;
121
+
122
+ if (cpu->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_FIQ)) {
123
+ /* Interrupt pending, no need to wait */
124
+ return;
125
+ }
126
+
127
+ r = hv_vcpu_get_sys_reg(cpu->hvf->fd, HV_SYS_REG_CNTV_CTL_EL0, &ctl);
128
+ assert_hvf_ok(r);
129
+
130
+ if (!(ctl & 1) || (ctl & 2)) {
131
+ /* Timer disabled or masked, just wait for an IPI. */
132
+ hvf_wait_for_ipi(cpu, NULL);
133
+ return;
134
+ }
135
+
136
+ r = hv_vcpu_get_sys_reg(cpu->hvf->fd, HV_SYS_REG_CNTV_CVAL_EL0, &cval);
137
+ assert_hvf_ok(r);
138
+
139
+ ticks_to_sleep = cval - hvf_vtimer_val();
140
+ if (ticks_to_sleep < 0) {
141
+ return;
142
+ }
143
+
144
+ cntfrq = gt_cntfrq_period_ns(arm_cpu);
145
+ seconds = muldiv64(ticks_to_sleep, cntfrq, NANOSECONDS_PER_SECOND);
146
+ ticks_to_sleep -= muldiv64(seconds, NANOSECONDS_PER_SECOND, cntfrq);
147
+ nanos = ticks_to_sleep * cntfrq;
148
+
149
+ /*
150
+ * Don't sleep for less than the time a context switch would take,
151
+ * so that we can satisfy fast timer requests on the same CPU.
152
+ * Measurements on M1 show the sweet spot to be ~2ms.
153
+ */
154
+ if (!seconds && nanos < (2 * SCALE_MS)) {
155
+ return;
156
+ }
157
+
158
+ ts = (struct timespec) { seconds, nanos };
159
+ hvf_wait_for_ipi(cpu, &ts);
160
+}
161
+
162
static void hvf_sync_vtimer(CPUState *cpu)
163
{
164
ARMCPU *arm_cpu = ARM_CPU(cpu);
165
@@ -XXX,XX +XXX,XX @@ int hvf_vcpu_exec(CPUState *cpu)
166
}
167
case EC_WFX_TRAP:
168
advance_pc = true;
169
+ if (!(syndrome & WFX_IS_WFE)) {
170
+ hvf_wfi(cpu);
171
+ }
172
break;
173
case EC_AA64_HVC:
174
cpu_synchronize_state(cpu);
175
--
176
2.20.1
177
178
diff view generated by jsdifflib
Deleted patch
1
From: Alexander Graf <agraf@csgraf.de>
2
1
3
We need to handle PSCI calls. Most of the TCG code works for us,
4
but we can simplify it to only handle aa64 mode and we need to
5
handle SUSPEND differently.
6
7
This patch takes the TCG code as template and duplicates it in HVF.
8
9
To tell the guest that we support PSCI 0.2 now, update the check in
10
arm_cpu_initfn() as well.
11
12
Signed-off-by: Alexander Graf <agraf@csgraf.de>
13
Reviewed-by: Sergio Lopez <slp@redhat.com>
14
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
15
Message-id: 20210916155404.86958-8-agraf@csgraf.de
16
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
17
---
18
target/arm/cpu.c | 4 +-
19
target/arm/hvf/hvf.c | 141 ++++++++++++++++++++++++++++++++++--
20
target/arm/hvf/trace-events | 1 +
21
3 files changed, 139 insertions(+), 7 deletions(-)
22
23
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
24
index XXXXXXX..XXXXXXX 100644
25
--- a/target/arm/cpu.c
26
+++ b/target/arm/cpu.c
27
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_initfn(Object *obj)
28
cpu->psci_version = 1; /* By default assume PSCI v0.1 */
29
cpu->kvm_target = QEMU_KVM_ARM_TARGET_NONE;
30
31
- if (tcg_enabled()) {
32
- cpu->psci_version = 2; /* TCG implements PSCI 0.2 */
33
+ if (tcg_enabled() || hvf_enabled()) {
34
+ cpu->psci_version = 2; /* TCG and HVF implement PSCI 0.2 */
35
}
36
}
37
38
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
39
index XXXXXXX..XXXXXXX 100644
40
--- a/target/arm/hvf/hvf.c
41
+++ b/target/arm/hvf/hvf.c
42
@@ -XXX,XX +XXX,XX @@
43
#include "hw/irq.h"
44
#include "qemu/main-loop.h"
45
#include "sysemu/cpus.h"
46
+#include "arm-powerctl.h"
47
#include "target/arm/cpu.h"
48
#include "target/arm/internals.h"
49
#include "trace/trace-target_arm_hvf.h"
50
@@ -XXX,XX +XXX,XX @@
51
#define TMR_CTL_IMASK (1 << 1)
52
#define TMR_CTL_ISTATUS (1 << 2)
53
54
+static void hvf_wfi(CPUState *cpu);
55
+
56
typedef struct HVFVTimer {
57
/* Vtimer value during migration and paused state */
58
uint64_t vtimer_val;
59
@@ -XXX,XX +XXX,XX @@ static void hvf_raise_exception(CPUState *cpu, uint32_t excp,
60
arm_cpu_do_interrupt(cpu);
61
}
62
63
+static void hvf_psci_cpu_off(ARMCPU *arm_cpu)
64
+{
65
+ int32_t ret = arm_set_cpu_off(arm_cpu->mp_affinity);
66
+ assert(ret == QEMU_ARM_POWERCTL_RET_SUCCESS);
67
+}
68
+
69
+/*
70
+ * Handle a PSCI call.
71
+ *
72
+ * Returns 0 on success
73
+ * -1 when the PSCI call is unknown,
74
+ */
75
+static bool hvf_handle_psci_call(CPUState *cpu)
76
+{
77
+ ARMCPU *arm_cpu = ARM_CPU(cpu);
78
+ CPUARMState *env = &arm_cpu->env;
79
+ uint64_t param[4] = {
80
+ env->xregs[0],
81
+ env->xregs[1],
82
+ env->xregs[2],
83
+ env->xregs[3]
84
+ };
85
+ uint64_t context_id, mpidr;
86
+ bool target_aarch64 = true;
87
+ CPUState *target_cpu_state;
88
+ ARMCPU *target_cpu;
89
+ target_ulong entry;
90
+ int target_el = 1;
91
+ int32_t ret = 0;
92
+
93
+ trace_hvf_psci_call(param[0], param[1], param[2], param[3],
94
+ arm_cpu->mp_affinity);
95
+
96
+ switch (param[0]) {
97
+ case QEMU_PSCI_0_2_FN_PSCI_VERSION:
98
+ ret = QEMU_PSCI_0_2_RET_VERSION_0_2;
99
+ break;
100
+ case QEMU_PSCI_0_2_FN_MIGRATE_INFO_TYPE:
101
+ ret = QEMU_PSCI_0_2_RET_TOS_MIGRATION_NOT_REQUIRED; /* No trusted OS */
102
+ break;
103
+ case QEMU_PSCI_0_2_FN_AFFINITY_INFO:
104
+ case QEMU_PSCI_0_2_FN64_AFFINITY_INFO:
105
+ mpidr = param[1];
106
+
107
+ switch (param[2]) {
108
+ case 0:
109
+ target_cpu_state = arm_get_cpu_by_id(mpidr);
110
+ if (!target_cpu_state) {
111
+ ret = QEMU_PSCI_RET_INVALID_PARAMS;
112
+ break;
113
+ }
114
+ target_cpu = ARM_CPU(target_cpu_state);
115
+
116
+ ret = target_cpu->power_state;
117
+ break;
118
+ default:
119
+ /* Everything above affinity level 0 is always on. */
120
+ ret = 0;
121
+ }
122
+ break;
123
+ case QEMU_PSCI_0_2_FN_SYSTEM_RESET:
124
+ qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
125
+ /*
126
+ * QEMU reset and shutdown are async requests, but PSCI
127
+ * mandates that we never return from the reset/shutdown
128
+ * call, so power the CPU off now so it doesn't execute
129
+ * anything further.
130
+ */
131
+ hvf_psci_cpu_off(arm_cpu);
132
+ break;
133
+ case QEMU_PSCI_0_2_FN_SYSTEM_OFF:
134
+ qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
135
+ hvf_psci_cpu_off(arm_cpu);
136
+ break;
137
+ case QEMU_PSCI_0_1_FN_CPU_ON:
138
+ case QEMU_PSCI_0_2_FN_CPU_ON:
139
+ case QEMU_PSCI_0_2_FN64_CPU_ON:
140
+ mpidr = param[1];
141
+ entry = param[2];
142
+ context_id = param[3];
143
+ ret = arm_set_cpu_on(mpidr, entry, context_id,
144
+ target_el, target_aarch64);
145
+ break;
146
+ case QEMU_PSCI_0_1_FN_CPU_OFF:
147
+ case QEMU_PSCI_0_2_FN_CPU_OFF:
148
+ hvf_psci_cpu_off(arm_cpu);
149
+ break;
150
+ case QEMU_PSCI_0_1_FN_CPU_SUSPEND:
151
+ case QEMU_PSCI_0_2_FN_CPU_SUSPEND:
152
+ case QEMU_PSCI_0_2_FN64_CPU_SUSPEND:
153
+ /* Affinity levels are not supported in QEMU */
154
+ if (param[1] & 0xfffe0000) {
155
+ ret = QEMU_PSCI_RET_INVALID_PARAMS;
156
+ break;
157
+ }
158
+ /* Powerdown is not supported, we always go into WFI */
159
+ env->xregs[0] = 0;
160
+ hvf_wfi(cpu);
161
+ break;
162
+ case QEMU_PSCI_0_1_FN_MIGRATE:
163
+ case QEMU_PSCI_0_2_FN_MIGRATE:
164
+ ret = QEMU_PSCI_RET_NOT_SUPPORTED;
165
+ break;
166
+ default:
167
+ return false;
168
+ }
169
+
170
+ env->xregs[0] = ret;
171
+ return true;
172
+}
173
+
174
static int hvf_sysreg_read(CPUState *cpu, uint32_t reg, uint32_t rt)
175
{
176
ARMCPU *arm_cpu = ARM_CPU(cpu);
177
@@ -XXX,XX +XXX,XX @@ int hvf_vcpu_exec(CPUState *cpu)
178
break;
179
case EC_AA64_HVC:
180
cpu_synchronize_state(cpu);
181
- trace_hvf_unknown_hvc(env->xregs[0]);
182
- /* SMCCC 1.3 section 5.2 says every unknown SMCCC call returns -1 */
183
- env->xregs[0] = -1;
184
+ if (arm_cpu->psci_conduit == QEMU_PSCI_CONDUIT_HVC) {
185
+ if (!hvf_handle_psci_call(cpu)) {
186
+ trace_hvf_unknown_hvc(env->xregs[0]);
187
+ /* SMCCC 1.3 section 5.2 says every unknown SMCCC call returns -1 */
188
+ env->xregs[0] = -1;
189
+ }
190
+ } else {
191
+ trace_hvf_unknown_hvc(env->xregs[0]);
192
+ hvf_raise_exception(cpu, EXCP_UDEF, syn_uncategorized());
193
+ }
194
break;
195
case EC_AA64_SMC:
196
cpu_synchronize_state(cpu);
197
- trace_hvf_unknown_smc(env->xregs[0]);
198
- hvf_raise_exception(cpu, EXCP_UDEF, syn_uncategorized());
199
+ if (arm_cpu->psci_conduit == QEMU_PSCI_CONDUIT_SMC) {
200
+ advance_pc = true;
201
+
202
+ if (!hvf_handle_psci_call(cpu)) {
203
+ trace_hvf_unknown_smc(env->xregs[0]);
204
+ /* SMCCC 1.3 section 5.2 says every unknown SMCCC call returns -1 */
205
+ env->xregs[0] = -1;
206
+ }
207
+ } else {
208
+ trace_hvf_unknown_smc(env->xregs[0]);
209
+ hvf_raise_exception(cpu, EXCP_UDEF, syn_uncategorized());
210
+ }
211
break;
212
default:
213
cpu_synchronize_state(cpu);
214
diff --git a/target/arm/hvf/trace-events b/target/arm/hvf/trace-events
215
index XXXXXXX..XXXXXXX 100644
216
--- a/target/arm/hvf/trace-events
217
+++ b/target/arm/hvf/trace-events
218
@@ -XXX,XX +XXX,XX @@ hvf_sysreg_write(uint32_t reg, uint32_t op0, uint32_t op1, uint32_t crn, uint32_
219
hvf_unknown_hvc(uint64_t x0) "unknown HVC! 0x%016"PRIx64
220
hvf_unknown_smc(uint64_t x0) "unknown SMC! 0x%016"PRIx64
221
hvf_exit(uint64_t syndrome, uint32_t ec, uint64_t pc) "exit: 0x%"PRIx64" [ec=0x%x pc=0x%"PRIx64"]"
222
+hvf_psci_call(uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3, uint32_t cpuid) "PSCI Call x0=0x%016"PRIx64" x1=0x%016"PRIx64" x2=0x%016"PRIx64" x3=0x%016"PRIx64" cpu=0x%x"
223
--
224
2.20.1
225
226
diff view generated by jsdifflib
1
From: Alexander Graf <agraf@csgraf.de>
1
From: Thomas Huth <thuth@redhat.com>
2
2
3
Now that we have all logic in place that we need to handle Hypervisor.framework
3
Move the code to a separate file so that we do not have to compile
4
on Apple Silicon systems, let's add CONFIG_HVF for aarch64 as well so that we
4
it anymore if CONFIG_ARM_V7M is not set.
5
can build it.
6
5
7
Signed-off-by: Alexander Graf <agraf@csgraf.de>
6
Signed-off-by: Thomas Huth <thuth@redhat.com>
8
Reviewed-by: Roman Bolshakov <r.bolshakov@yadro.com>
7
Message-id: 20240308141051.536599-2-thuth@redhat.com
9
Tested-by: Roman Bolshakov <r.bolshakov@yadro.com> (x86 only)
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
11
Reviewed-by: Sergio Lopez <slp@redhat.com>
12
Message-id: 20210916155404.86958-9-agraf@csgraf.de
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
---
10
---
15
meson.build | 7 +++++++
11
target/arm/tcg/cpu-v7m.c | 290 +++++++++++++++++++++++++++++++++++++
16
target/arm/hvf/meson.build | 3 +++
12
target/arm/tcg/cpu32.c | 261 ---------------------------------
17
target/arm/meson.build | 2 ++
13
target/arm/meson.build | 3 +
18
3 files changed, 12 insertions(+)
14
target/arm/tcg/meson.build | 3 +
19
create mode 100644 target/arm/hvf/meson.build
15
4 files changed, 296 insertions(+), 261 deletions(-)
16
create mode 100644 target/arm/tcg/cpu-v7m.c
20
17
21
diff --git a/meson.build b/meson.build
18
diff --git a/target/arm/tcg/cpu-v7m.c b/target/arm/tcg/cpu-v7m.c
22
index XXXXXXX..XXXXXXX 100644
23
--- a/meson.build
24
+++ b/meson.build
25
@@ -XXX,XX +XXX,XX @@ else
26
endif
27
28
accelerator_targets = { 'CONFIG_KVM': kvm_targets }
29
+
30
+if cpu in ['aarch64']
31
+ accelerator_targets += {
32
+ 'CONFIG_HVF': ['aarch64-softmmu']
33
+ }
34
+endif
35
+
36
if cpu in ['x86', 'x86_64', 'arm', 'aarch64']
37
# i386 emulator provides xenpv machine type for multiple architectures
38
accelerator_targets += {
39
diff --git a/target/arm/hvf/meson.build b/target/arm/hvf/meson.build
40
new file mode 100644
19
new file mode 100644
41
index XXXXXXX..XXXXXXX
20
index XXXXXXX..XXXXXXX
42
--- /dev/null
21
--- /dev/null
43
+++ b/target/arm/hvf/meson.build
22
+++ b/target/arm/tcg/cpu-v7m.c
44
@@ -XXX,XX +XXX,XX @@
23
@@ -XXX,XX +XXX,XX @@
45
+arm_softmmu_ss.add(when: [hvf, 'CONFIG_HVF'], if_true: files(
24
+/*
46
+ 'hvf.c',
25
+ * QEMU ARMv7-M TCG-only CPUs.
47
+))
26
+ *
27
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
28
+ *
29
+ * This code is licensed under the GNU GPL v2 or later.
30
+ *
31
+ * SPDX-License-Identifier: GPL-2.0-or-later
32
+ */
33
+
34
+#include "qemu/osdep.h"
35
+#include "cpu.h"
36
+#include "hw/core/tcg-cpu-ops.h"
37
+#include "internals.h"
38
+
39
+#if !defined(CONFIG_USER_ONLY)
40
+
41
+#include "hw/intc/armv7m_nvic.h"
42
+
43
+static bool arm_v7m_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
44
+{
45
+ CPUClass *cc = CPU_GET_CLASS(cs);
46
+ ARMCPU *cpu = ARM_CPU(cs);
47
+ CPUARMState *env = &cpu->env;
48
+ bool ret = false;
49
+
50
+ /*
51
+ * ARMv7-M interrupt masking works differently than -A or -R.
52
+ * There is no FIQ/IRQ distinction. Instead of I and F bits
53
+ * masking FIQ and IRQ interrupts, an exception is taken only
54
+ * if it is higher priority than the current execution priority
55
+ * (which depends on state like BASEPRI, FAULTMASK and the
56
+ * currently active exception).
57
+ */
58
+ if (interrupt_request & CPU_INTERRUPT_HARD
59
+ && (armv7m_nvic_can_take_pending_exception(env->nvic))) {
60
+ cs->exception_index = EXCP_IRQ;
61
+ cc->tcg_ops->do_interrupt(cs);
62
+ ret = true;
63
+ }
64
+ return ret;
65
+}
66
+
67
+#endif /* !CONFIG_USER_ONLY */
68
+
69
+static void cortex_m0_initfn(Object *obj)
70
+{
71
+ ARMCPU *cpu = ARM_CPU(obj);
72
+ set_feature(&cpu->env, ARM_FEATURE_V6);
73
+ set_feature(&cpu->env, ARM_FEATURE_M);
74
+
75
+ cpu->midr = 0x410cc200;
76
+
77
+ /*
78
+ * These ID register values are not guest visible, because
79
+ * we do not implement the Main Extension. They must be set
80
+ * to values corresponding to the Cortex-M0's implemented
81
+ * features, because QEMU generally controls its emulation
82
+ * by looking at ID register fields. We use the same values as
83
+ * for the M3.
84
+ */
85
+ cpu->isar.id_pfr0 = 0x00000030;
86
+ cpu->isar.id_pfr1 = 0x00000200;
87
+ cpu->isar.id_dfr0 = 0x00100000;
88
+ cpu->id_afr0 = 0x00000000;
89
+ cpu->isar.id_mmfr0 = 0x00000030;
90
+ cpu->isar.id_mmfr1 = 0x00000000;
91
+ cpu->isar.id_mmfr2 = 0x00000000;
92
+ cpu->isar.id_mmfr3 = 0x00000000;
93
+ cpu->isar.id_isar0 = 0x01141110;
94
+ cpu->isar.id_isar1 = 0x02111000;
95
+ cpu->isar.id_isar2 = 0x21112231;
96
+ cpu->isar.id_isar3 = 0x01111110;
97
+ cpu->isar.id_isar4 = 0x01310102;
98
+ cpu->isar.id_isar5 = 0x00000000;
99
+ cpu->isar.id_isar6 = 0x00000000;
100
+}
101
+
102
+static void cortex_m3_initfn(Object *obj)
103
+{
104
+ ARMCPU *cpu = ARM_CPU(obj);
105
+ set_feature(&cpu->env, ARM_FEATURE_V7);
106
+ set_feature(&cpu->env, ARM_FEATURE_M);
107
+ set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
108
+ cpu->midr = 0x410fc231;
109
+ cpu->pmsav7_dregion = 8;
110
+ cpu->isar.id_pfr0 = 0x00000030;
111
+ cpu->isar.id_pfr1 = 0x00000200;
112
+ cpu->isar.id_dfr0 = 0x00100000;
113
+ cpu->id_afr0 = 0x00000000;
114
+ cpu->isar.id_mmfr0 = 0x00000030;
115
+ cpu->isar.id_mmfr1 = 0x00000000;
116
+ cpu->isar.id_mmfr2 = 0x00000000;
117
+ cpu->isar.id_mmfr3 = 0x00000000;
118
+ cpu->isar.id_isar0 = 0x01141110;
119
+ cpu->isar.id_isar1 = 0x02111000;
120
+ cpu->isar.id_isar2 = 0x21112231;
121
+ cpu->isar.id_isar3 = 0x01111110;
122
+ cpu->isar.id_isar4 = 0x01310102;
123
+ cpu->isar.id_isar5 = 0x00000000;
124
+ cpu->isar.id_isar6 = 0x00000000;
125
+}
126
+
127
+static void cortex_m4_initfn(Object *obj)
128
+{
129
+ ARMCPU *cpu = ARM_CPU(obj);
130
+
131
+ set_feature(&cpu->env, ARM_FEATURE_V7);
132
+ set_feature(&cpu->env, ARM_FEATURE_M);
133
+ set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
134
+ set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP);
135
+ cpu->midr = 0x410fc240; /* r0p0 */
136
+ cpu->pmsav7_dregion = 8;
137
+ cpu->isar.mvfr0 = 0x10110021;
138
+ cpu->isar.mvfr1 = 0x11000011;
139
+ cpu->isar.mvfr2 = 0x00000000;
140
+ cpu->isar.id_pfr0 = 0x00000030;
141
+ cpu->isar.id_pfr1 = 0x00000200;
142
+ cpu->isar.id_dfr0 = 0x00100000;
143
+ cpu->id_afr0 = 0x00000000;
144
+ cpu->isar.id_mmfr0 = 0x00000030;
145
+ cpu->isar.id_mmfr1 = 0x00000000;
146
+ cpu->isar.id_mmfr2 = 0x00000000;
147
+ cpu->isar.id_mmfr3 = 0x00000000;
148
+ cpu->isar.id_isar0 = 0x01141110;
149
+ cpu->isar.id_isar1 = 0x02111000;
150
+ cpu->isar.id_isar2 = 0x21112231;
151
+ cpu->isar.id_isar3 = 0x01111110;
152
+ cpu->isar.id_isar4 = 0x01310102;
153
+ cpu->isar.id_isar5 = 0x00000000;
154
+ cpu->isar.id_isar6 = 0x00000000;
155
+}
156
+
157
+static void cortex_m7_initfn(Object *obj)
158
+{
159
+ ARMCPU *cpu = ARM_CPU(obj);
160
+
161
+ set_feature(&cpu->env, ARM_FEATURE_V7);
162
+ set_feature(&cpu->env, ARM_FEATURE_M);
163
+ set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
164
+ set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP);
165
+ cpu->midr = 0x411fc272; /* r1p2 */
166
+ cpu->pmsav7_dregion = 8;
167
+ cpu->isar.mvfr0 = 0x10110221;
168
+ cpu->isar.mvfr1 = 0x12000011;
169
+ cpu->isar.mvfr2 = 0x00000040;
170
+ cpu->isar.id_pfr0 = 0x00000030;
171
+ cpu->isar.id_pfr1 = 0x00000200;
172
+ cpu->isar.id_dfr0 = 0x00100000;
173
+ cpu->id_afr0 = 0x00000000;
174
+ cpu->isar.id_mmfr0 = 0x00100030;
175
+ cpu->isar.id_mmfr1 = 0x00000000;
176
+ cpu->isar.id_mmfr2 = 0x01000000;
177
+ cpu->isar.id_mmfr3 = 0x00000000;
178
+ cpu->isar.id_isar0 = 0x01101110;
179
+ cpu->isar.id_isar1 = 0x02112000;
180
+ cpu->isar.id_isar2 = 0x20232231;
181
+ cpu->isar.id_isar3 = 0x01111131;
182
+ cpu->isar.id_isar4 = 0x01310132;
183
+ cpu->isar.id_isar5 = 0x00000000;
184
+ cpu->isar.id_isar6 = 0x00000000;
185
+}
186
+
187
+static void cortex_m33_initfn(Object *obj)
188
+{
189
+ ARMCPU *cpu = ARM_CPU(obj);
190
+
191
+ set_feature(&cpu->env, ARM_FEATURE_V8);
192
+ set_feature(&cpu->env, ARM_FEATURE_M);
193
+ set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
194
+ set_feature(&cpu->env, ARM_FEATURE_M_SECURITY);
195
+ set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP);
196
+ cpu->midr = 0x410fd213; /* r0p3 */
197
+ cpu->pmsav7_dregion = 16;
198
+ cpu->sau_sregion = 8;
199
+ cpu->isar.mvfr0 = 0x10110021;
200
+ cpu->isar.mvfr1 = 0x11000011;
201
+ cpu->isar.mvfr2 = 0x00000040;
202
+ cpu->isar.id_pfr0 = 0x00000030;
203
+ cpu->isar.id_pfr1 = 0x00000210;
204
+ cpu->isar.id_dfr0 = 0x00200000;
205
+ cpu->id_afr0 = 0x00000000;
206
+ cpu->isar.id_mmfr0 = 0x00101F40;
207
+ cpu->isar.id_mmfr1 = 0x00000000;
208
+ cpu->isar.id_mmfr2 = 0x01000000;
209
+ cpu->isar.id_mmfr3 = 0x00000000;
210
+ cpu->isar.id_isar0 = 0x01101110;
211
+ cpu->isar.id_isar1 = 0x02212000;
212
+ cpu->isar.id_isar2 = 0x20232232;
213
+ cpu->isar.id_isar3 = 0x01111131;
214
+ cpu->isar.id_isar4 = 0x01310132;
215
+ cpu->isar.id_isar5 = 0x00000000;
216
+ cpu->isar.id_isar6 = 0x00000000;
217
+ cpu->clidr = 0x00000000;
218
+ cpu->ctr = 0x8000c000;
219
+}
220
+
221
+static void cortex_m55_initfn(Object *obj)
222
+{
223
+ ARMCPU *cpu = ARM_CPU(obj);
224
+
225
+ set_feature(&cpu->env, ARM_FEATURE_V8);
226
+ set_feature(&cpu->env, ARM_FEATURE_V8_1M);
227
+ set_feature(&cpu->env, ARM_FEATURE_M);
228
+ set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
229
+ set_feature(&cpu->env, ARM_FEATURE_M_SECURITY);
230
+ set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP);
231
+ cpu->midr = 0x410fd221; /* r0p1 */
232
+ cpu->revidr = 0;
233
+ cpu->pmsav7_dregion = 16;
234
+ cpu->sau_sregion = 8;
235
+ /* These are the MVFR* values for the FPU + full MVE configuration */
236
+ cpu->isar.mvfr0 = 0x10110221;
237
+ cpu->isar.mvfr1 = 0x12100211;
238
+ cpu->isar.mvfr2 = 0x00000040;
239
+ cpu->isar.id_pfr0 = 0x20000030;
240
+ cpu->isar.id_pfr1 = 0x00000230;
241
+ cpu->isar.id_dfr0 = 0x10200000;
242
+ cpu->id_afr0 = 0x00000000;
243
+ cpu->isar.id_mmfr0 = 0x00111040;
244
+ cpu->isar.id_mmfr1 = 0x00000000;
245
+ cpu->isar.id_mmfr2 = 0x01000000;
246
+ cpu->isar.id_mmfr3 = 0x00000011;
247
+ cpu->isar.id_isar0 = 0x01103110;
248
+ cpu->isar.id_isar1 = 0x02212000;
249
+ cpu->isar.id_isar2 = 0x20232232;
250
+ cpu->isar.id_isar3 = 0x01111131;
251
+ cpu->isar.id_isar4 = 0x01310132;
252
+ cpu->isar.id_isar5 = 0x00000000;
253
+ cpu->isar.id_isar6 = 0x00000000;
254
+ cpu->clidr = 0x00000000; /* caches not implemented */
255
+ cpu->ctr = 0x8303c003;
256
+}
257
+
258
+static const TCGCPUOps arm_v7m_tcg_ops = {
259
+ .initialize = arm_translate_init,
260
+ .synchronize_from_tb = arm_cpu_synchronize_from_tb,
261
+ .debug_excp_handler = arm_debug_excp_handler,
262
+ .restore_state_to_opc = arm_restore_state_to_opc,
263
+
264
+#ifdef CONFIG_USER_ONLY
265
+ .record_sigsegv = arm_cpu_record_sigsegv,
266
+ .record_sigbus = arm_cpu_record_sigbus,
267
+#else
268
+ .tlb_fill = arm_cpu_tlb_fill,
269
+ .cpu_exec_interrupt = arm_v7m_cpu_exec_interrupt,
270
+ .do_interrupt = arm_v7m_cpu_do_interrupt,
271
+ .do_transaction_failed = arm_cpu_do_transaction_failed,
272
+ .do_unaligned_access = arm_cpu_do_unaligned_access,
273
+ .adjust_watchpoint_address = arm_adjust_watchpoint_address,
274
+ .debug_check_watchpoint = arm_debug_check_watchpoint,
275
+ .debug_check_breakpoint = arm_debug_check_breakpoint,
276
+#endif /* !CONFIG_USER_ONLY */
277
+};
278
+
279
+static void arm_v7m_class_init(ObjectClass *oc, void *data)
280
+{
281
+ ARMCPUClass *acc = ARM_CPU_CLASS(oc);
282
+ CPUClass *cc = CPU_CLASS(oc);
283
+
284
+ acc->info = data;
285
+ cc->tcg_ops = &arm_v7m_tcg_ops;
286
+ cc->gdb_core_xml_file = "arm-m-profile.xml";
287
+}
288
+
289
+static const ARMCPUInfo arm_v7m_cpus[] = {
290
+ { .name = "cortex-m0", .initfn = cortex_m0_initfn,
291
+ .class_init = arm_v7m_class_init },
292
+ { .name = "cortex-m3", .initfn = cortex_m3_initfn,
293
+ .class_init = arm_v7m_class_init },
294
+ { .name = "cortex-m4", .initfn = cortex_m4_initfn,
295
+ .class_init = arm_v7m_class_init },
296
+ { .name = "cortex-m7", .initfn = cortex_m7_initfn,
297
+ .class_init = arm_v7m_class_init },
298
+ { .name = "cortex-m33", .initfn = cortex_m33_initfn,
299
+ .class_init = arm_v7m_class_init },
300
+ { .name = "cortex-m55", .initfn = cortex_m55_initfn,
301
+ .class_init = arm_v7m_class_init },
302
+};
303
+
304
+static void arm_v7m_cpu_register_types(void)
305
+{
306
+ size_t i;
307
+
308
+ for (i = 0; i < ARRAY_SIZE(arm_v7m_cpus); ++i) {
309
+ arm_cpu_register(&arm_v7m_cpus[i]);
310
+ }
311
+}
312
+
313
+type_init(arm_v7m_cpu_register_types)
314
diff --git a/target/arm/tcg/cpu32.c b/target/arm/tcg/cpu32.c
315
index XXXXXXX..XXXXXXX 100644
316
--- a/target/arm/tcg/cpu32.c
317
+++ b/target/arm/tcg/cpu32.c
318
@@ -XXX,XX +XXX,XX @@
319
#include "hw/boards.h"
320
#endif
321
#include "cpregs.h"
322
-#if !defined(CONFIG_USER_ONLY) && defined(CONFIG_TCG)
323
-#include "hw/intc/armv7m_nvic.h"
324
-#endif
325
326
327
/* Share AArch32 -cpu max features with AArch64. */
328
@@ -XXX,XX +XXX,XX @@ void aa32_max_features(ARMCPU *cpu)
329
/* CPU models. These are not needed for the AArch64 linux-user build. */
330
#if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64)
331
332
-#if !defined(CONFIG_USER_ONLY)
333
-static bool arm_v7m_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
334
-{
335
- CPUClass *cc = CPU_GET_CLASS(cs);
336
- ARMCPU *cpu = ARM_CPU(cs);
337
- CPUARMState *env = &cpu->env;
338
- bool ret = false;
339
-
340
- /*
341
- * ARMv7-M interrupt masking works differently than -A or -R.
342
- * There is no FIQ/IRQ distinction. Instead of I and F bits
343
- * masking FIQ and IRQ interrupts, an exception is taken only
344
- * if it is higher priority than the current execution priority
345
- * (which depends on state like BASEPRI, FAULTMASK and the
346
- * currently active exception).
347
- */
348
- if (interrupt_request & CPU_INTERRUPT_HARD
349
- && (armv7m_nvic_can_take_pending_exception(env->nvic))) {
350
- cs->exception_index = EXCP_IRQ;
351
- cc->tcg_ops->do_interrupt(cs);
352
- ret = true;
353
- }
354
- return ret;
355
-}
356
-#endif /* !CONFIG_USER_ONLY */
357
-
358
static void arm926_initfn(Object *obj)
359
{
360
ARMCPU *cpu = ARM_CPU(obj);
361
@@ -XXX,XX +XXX,XX @@ static void cortex_a15_initfn(Object *obj)
362
define_arm_cp_regs(cpu, cortexa15_cp_reginfo);
363
}
364
365
-static void cortex_m0_initfn(Object *obj)
366
-{
367
- ARMCPU *cpu = ARM_CPU(obj);
368
- set_feature(&cpu->env, ARM_FEATURE_V6);
369
- set_feature(&cpu->env, ARM_FEATURE_M);
370
-
371
- cpu->midr = 0x410cc200;
372
-
373
- /*
374
- * These ID register values are not guest visible, because
375
- * we do not implement the Main Extension. They must be set
376
- * to values corresponding to the Cortex-M0's implemented
377
- * features, because QEMU generally controls its emulation
378
- * by looking at ID register fields. We use the same values as
379
- * for the M3.
380
- */
381
- cpu->isar.id_pfr0 = 0x00000030;
382
- cpu->isar.id_pfr1 = 0x00000200;
383
- cpu->isar.id_dfr0 = 0x00100000;
384
- cpu->id_afr0 = 0x00000000;
385
- cpu->isar.id_mmfr0 = 0x00000030;
386
- cpu->isar.id_mmfr1 = 0x00000000;
387
- cpu->isar.id_mmfr2 = 0x00000000;
388
- cpu->isar.id_mmfr3 = 0x00000000;
389
- cpu->isar.id_isar0 = 0x01141110;
390
- cpu->isar.id_isar1 = 0x02111000;
391
- cpu->isar.id_isar2 = 0x21112231;
392
- cpu->isar.id_isar3 = 0x01111110;
393
- cpu->isar.id_isar4 = 0x01310102;
394
- cpu->isar.id_isar5 = 0x00000000;
395
- cpu->isar.id_isar6 = 0x00000000;
396
-}
397
-
398
-static void cortex_m3_initfn(Object *obj)
399
-{
400
- ARMCPU *cpu = ARM_CPU(obj);
401
- set_feature(&cpu->env, ARM_FEATURE_V7);
402
- set_feature(&cpu->env, ARM_FEATURE_M);
403
- set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
404
- cpu->midr = 0x410fc231;
405
- cpu->pmsav7_dregion = 8;
406
- cpu->isar.id_pfr0 = 0x00000030;
407
- cpu->isar.id_pfr1 = 0x00000200;
408
- cpu->isar.id_dfr0 = 0x00100000;
409
- cpu->id_afr0 = 0x00000000;
410
- cpu->isar.id_mmfr0 = 0x00000030;
411
- cpu->isar.id_mmfr1 = 0x00000000;
412
- cpu->isar.id_mmfr2 = 0x00000000;
413
- cpu->isar.id_mmfr3 = 0x00000000;
414
- cpu->isar.id_isar0 = 0x01141110;
415
- cpu->isar.id_isar1 = 0x02111000;
416
- cpu->isar.id_isar2 = 0x21112231;
417
- cpu->isar.id_isar3 = 0x01111110;
418
- cpu->isar.id_isar4 = 0x01310102;
419
- cpu->isar.id_isar5 = 0x00000000;
420
- cpu->isar.id_isar6 = 0x00000000;
421
-}
422
-
423
-static void cortex_m4_initfn(Object *obj)
424
-{
425
- ARMCPU *cpu = ARM_CPU(obj);
426
-
427
- set_feature(&cpu->env, ARM_FEATURE_V7);
428
- set_feature(&cpu->env, ARM_FEATURE_M);
429
- set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
430
- set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP);
431
- cpu->midr = 0x410fc240; /* r0p0 */
432
- cpu->pmsav7_dregion = 8;
433
- cpu->isar.mvfr0 = 0x10110021;
434
- cpu->isar.mvfr1 = 0x11000011;
435
- cpu->isar.mvfr2 = 0x00000000;
436
- cpu->isar.id_pfr0 = 0x00000030;
437
- cpu->isar.id_pfr1 = 0x00000200;
438
- cpu->isar.id_dfr0 = 0x00100000;
439
- cpu->id_afr0 = 0x00000000;
440
- cpu->isar.id_mmfr0 = 0x00000030;
441
- cpu->isar.id_mmfr1 = 0x00000000;
442
- cpu->isar.id_mmfr2 = 0x00000000;
443
- cpu->isar.id_mmfr3 = 0x00000000;
444
- cpu->isar.id_isar0 = 0x01141110;
445
- cpu->isar.id_isar1 = 0x02111000;
446
- cpu->isar.id_isar2 = 0x21112231;
447
- cpu->isar.id_isar3 = 0x01111110;
448
- cpu->isar.id_isar4 = 0x01310102;
449
- cpu->isar.id_isar5 = 0x00000000;
450
- cpu->isar.id_isar6 = 0x00000000;
451
-}
452
-
453
-static void cortex_m7_initfn(Object *obj)
454
-{
455
- ARMCPU *cpu = ARM_CPU(obj);
456
-
457
- set_feature(&cpu->env, ARM_FEATURE_V7);
458
- set_feature(&cpu->env, ARM_FEATURE_M);
459
- set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
460
- set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP);
461
- cpu->midr = 0x411fc272; /* r1p2 */
462
- cpu->pmsav7_dregion = 8;
463
- cpu->isar.mvfr0 = 0x10110221;
464
- cpu->isar.mvfr1 = 0x12000011;
465
- cpu->isar.mvfr2 = 0x00000040;
466
- cpu->isar.id_pfr0 = 0x00000030;
467
- cpu->isar.id_pfr1 = 0x00000200;
468
- cpu->isar.id_dfr0 = 0x00100000;
469
- cpu->id_afr0 = 0x00000000;
470
- cpu->isar.id_mmfr0 = 0x00100030;
471
- cpu->isar.id_mmfr1 = 0x00000000;
472
- cpu->isar.id_mmfr2 = 0x01000000;
473
- cpu->isar.id_mmfr3 = 0x00000000;
474
- cpu->isar.id_isar0 = 0x01101110;
475
- cpu->isar.id_isar1 = 0x02112000;
476
- cpu->isar.id_isar2 = 0x20232231;
477
- cpu->isar.id_isar3 = 0x01111131;
478
- cpu->isar.id_isar4 = 0x01310132;
479
- cpu->isar.id_isar5 = 0x00000000;
480
- cpu->isar.id_isar6 = 0x00000000;
481
-}
482
-
483
-static void cortex_m33_initfn(Object *obj)
484
-{
485
- ARMCPU *cpu = ARM_CPU(obj);
486
-
487
- set_feature(&cpu->env, ARM_FEATURE_V8);
488
- set_feature(&cpu->env, ARM_FEATURE_M);
489
- set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
490
- set_feature(&cpu->env, ARM_FEATURE_M_SECURITY);
491
- set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP);
492
- cpu->midr = 0x410fd213; /* r0p3 */
493
- cpu->pmsav7_dregion = 16;
494
- cpu->sau_sregion = 8;
495
- cpu->isar.mvfr0 = 0x10110021;
496
- cpu->isar.mvfr1 = 0x11000011;
497
- cpu->isar.mvfr2 = 0x00000040;
498
- cpu->isar.id_pfr0 = 0x00000030;
499
- cpu->isar.id_pfr1 = 0x00000210;
500
- cpu->isar.id_dfr0 = 0x00200000;
501
- cpu->id_afr0 = 0x00000000;
502
- cpu->isar.id_mmfr0 = 0x00101F40;
503
- cpu->isar.id_mmfr1 = 0x00000000;
504
- cpu->isar.id_mmfr2 = 0x01000000;
505
- cpu->isar.id_mmfr3 = 0x00000000;
506
- cpu->isar.id_isar0 = 0x01101110;
507
- cpu->isar.id_isar1 = 0x02212000;
508
- cpu->isar.id_isar2 = 0x20232232;
509
- cpu->isar.id_isar3 = 0x01111131;
510
- cpu->isar.id_isar4 = 0x01310132;
511
- cpu->isar.id_isar5 = 0x00000000;
512
- cpu->isar.id_isar6 = 0x00000000;
513
- cpu->clidr = 0x00000000;
514
- cpu->ctr = 0x8000c000;
515
-}
516
-
517
-static void cortex_m55_initfn(Object *obj)
518
-{
519
- ARMCPU *cpu = ARM_CPU(obj);
520
-
521
- set_feature(&cpu->env, ARM_FEATURE_V8);
522
- set_feature(&cpu->env, ARM_FEATURE_V8_1M);
523
- set_feature(&cpu->env, ARM_FEATURE_M);
524
- set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
525
- set_feature(&cpu->env, ARM_FEATURE_M_SECURITY);
526
- set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP);
527
- cpu->midr = 0x410fd221; /* r0p1 */
528
- cpu->revidr = 0;
529
- cpu->pmsav7_dregion = 16;
530
- cpu->sau_sregion = 8;
531
- /* These are the MVFR* values for the FPU + full MVE configuration */
532
- cpu->isar.mvfr0 = 0x10110221;
533
- cpu->isar.mvfr1 = 0x12100211;
534
- cpu->isar.mvfr2 = 0x00000040;
535
- cpu->isar.id_pfr0 = 0x20000030;
536
- cpu->isar.id_pfr1 = 0x00000230;
537
- cpu->isar.id_dfr0 = 0x10200000;
538
- cpu->id_afr0 = 0x00000000;
539
- cpu->isar.id_mmfr0 = 0x00111040;
540
- cpu->isar.id_mmfr1 = 0x00000000;
541
- cpu->isar.id_mmfr2 = 0x01000000;
542
- cpu->isar.id_mmfr3 = 0x00000011;
543
- cpu->isar.id_isar0 = 0x01103110;
544
- cpu->isar.id_isar1 = 0x02212000;
545
- cpu->isar.id_isar2 = 0x20232232;
546
- cpu->isar.id_isar3 = 0x01111131;
547
- cpu->isar.id_isar4 = 0x01310132;
548
- cpu->isar.id_isar5 = 0x00000000;
549
- cpu->isar.id_isar6 = 0x00000000;
550
- cpu->clidr = 0x00000000; /* caches not implemented */
551
- cpu->ctr = 0x8303c003;
552
-}
553
-
554
static const ARMCPRegInfo cortexr5_cp_reginfo[] = {
555
/* Dummy the TCM region regs for the moment */
556
{ .name = "ATCM", .cp = 15, .opc1 = 0, .crn = 9, .crm = 1, .opc2 = 0,
557
@@ -XXX,XX +XXX,XX @@ static void pxa270c5_initfn(Object *obj)
558
cpu->reset_sctlr = 0x00000078;
559
}
560
561
-static const TCGCPUOps arm_v7m_tcg_ops = {
562
- .initialize = arm_translate_init,
563
- .synchronize_from_tb = arm_cpu_synchronize_from_tb,
564
- .debug_excp_handler = arm_debug_excp_handler,
565
- .restore_state_to_opc = arm_restore_state_to_opc,
566
-
567
-#ifdef CONFIG_USER_ONLY
568
- .record_sigsegv = arm_cpu_record_sigsegv,
569
- .record_sigbus = arm_cpu_record_sigbus,
570
-#else
571
- .tlb_fill = arm_cpu_tlb_fill,
572
- .cpu_exec_interrupt = arm_v7m_cpu_exec_interrupt,
573
- .do_interrupt = arm_v7m_cpu_do_interrupt,
574
- .do_transaction_failed = arm_cpu_do_transaction_failed,
575
- .do_unaligned_access = arm_cpu_do_unaligned_access,
576
- .adjust_watchpoint_address = arm_adjust_watchpoint_address,
577
- .debug_check_watchpoint = arm_debug_check_watchpoint,
578
- .debug_check_breakpoint = arm_debug_check_breakpoint,
579
-#endif /* !CONFIG_USER_ONLY */
580
-};
581
-
582
-static void arm_v7m_class_init(ObjectClass *oc, void *data)
583
-{
584
- ARMCPUClass *acc = ARM_CPU_CLASS(oc);
585
- CPUClass *cc = CPU_CLASS(oc);
586
-
587
- acc->info = data;
588
- cc->tcg_ops = &arm_v7m_tcg_ops;
589
- cc->gdb_core_xml_file = "arm-m-profile.xml";
590
-}
591
-
592
#ifndef TARGET_AARCH64
593
/*
594
* -cpu max: a CPU with as many features enabled as our emulation supports.
595
@@ -XXX,XX +XXX,XX @@ static const ARMCPUInfo arm_tcg_cpus[] = {
596
{ .name = "cortex-a8", .initfn = cortex_a8_initfn },
597
{ .name = "cortex-a9", .initfn = cortex_a9_initfn },
598
{ .name = "cortex-a15", .initfn = cortex_a15_initfn },
599
- { .name = "cortex-m0", .initfn = cortex_m0_initfn,
600
- .class_init = arm_v7m_class_init },
601
- { .name = "cortex-m3", .initfn = cortex_m3_initfn,
602
- .class_init = arm_v7m_class_init },
603
- { .name = "cortex-m4", .initfn = cortex_m4_initfn,
604
- .class_init = arm_v7m_class_init },
605
- { .name = "cortex-m7", .initfn = cortex_m7_initfn,
606
- .class_init = arm_v7m_class_init },
607
- { .name = "cortex-m33", .initfn = cortex_m33_initfn,
608
- .class_init = arm_v7m_class_init },
609
- { .name = "cortex-m55", .initfn = cortex_m55_initfn,
610
- .class_init = arm_v7m_class_init },
611
{ .name = "cortex-r5", .initfn = cortex_r5_initfn },
612
{ .name = "cortex-r5f", .initfn = cortex_r5f_initfn },
613
{ .name = "cortex-r52", .initfn = cortex_r52_initfn },
48
diff --git a/target/arm/meson.build b/target/arm/meson.build
614
diff --git a/target/arm/meson.build b/target/arm/meson.build
49
index XXXXXXX..XXXXXXX 100644
615
index XXXXXXX..XXXXXXX 100644
50
--- a/target/arm/meson.build
616
--- a/target/arm/meson.build
51
+++ b/target/arm/meson.build
617
+++ b/target/arm/meson.build
52
@@ -XXX,XX +XXX,XX @@ arm_softmmu_ss.add(files(
618
@@ -XXX,XX +XXX,XX @@ arm_system_ss.add(files(
619
'ptw.c',
620
))
621
622
+arm_user_ss = ss.source_set()
623
+
624
subdir('hvf')
625
626
if 'CONFIG_TCG' in config_all_accel
627
@@ -XXX,XX +XXX,XX @@ endif
628
629
target_arch += {'arm': arm_ss}
630
target_system_arch += {'arm': arm_system_ss}
631
+target_user_arch += {'arm': arm_user_ss}
632
diff --git a/target/arm/tcg/meson.build b/target/arm/tcg/meson.build
633
index XXXXXXX..XXXXXXX 100644
634
--- a/target/arm/tcg/meson.build
635
+++ b/target/arm/tcg/meson.build
636
@@ -XXX,XX +XXX,XX @@ arm_ss.add(when: 'TARGET_AARCH64', if_true: files(
637
arm_system_ss.add(files(
53
'psci.c',
638
'psci.c',
54
))
639
))
55
640
+
56
+subdir('hvf')
641
+arm_system_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('cpu-v7m.c'))
57
+
642
+arm_user_ss.add(when: 'TARGET_AARCH64', if_false: files('cpu-v7m.c'))
58
target_arch += {'arm': arm_ss}
59
target_softmmu_arch += {'arm': arm_softmmu_ss}
60
--
643
--
61
2.20.1
644
2.34.1
62
63
diff view generated by jsdifflib
Deleted patch
1
Currently gen_jmp_tb() assumes that if it is called then the jump it
2
is handling is the only reason that we might be trying to end the TB,
3
so it will use goto_tb if it can. This is usually the case: mostly
4
"we did something that means we must end the TB" happens on a
5
non-branch instruction. However, there are cases where we decide
6
early in handling an instruction that we need to end the TB and
7
return to the main loop, and then the insn is a complex one that
8
involves gen_jmp_tb(). For instance, for M-profile FP instructions,
9
in gen_preserve_fp_state() which is called from vfp_access_check() we
10
want to force an exit to the main loop if lazy state preservation is
11
active and we are in icount mode.
12
1
13
Make gen_jmp_tb() look at the current value of is_jmp, and only use
14
goto_tb if the previous is_jmp was DISAS_NEXT or DISAS_TOO_MANY.
15
16
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
17
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
18
Message-id: 20210913095440.13462-2-peter.maydell@linaro.org
19
---
20
target/arm/translate.c | 34 +++++++++++++++++++++++++++++++++-
21
1 file changed, 33 insertions(+), 1 deletion(-)
22
23
diff --git a/target/arm/translate.c b/target/arm/translate.c
24
index XXXXXXX..XXXXXXX 100644
25
--- a/target/arm/translate.c
26
+++ b/target/arm/translate.c
27
@@ -XXX,XX +XXX,XX @@ static inline void gen_jmp_tb(DisasContext *s, uint32_t dest, int tbno)
28
/* An indirect jump so that we still trigger the debug exception. */
29
gen_set_pc_im(s, dest);
30
s->base.is_jmp = DISAS_JUMP;
31
- } else {
32
+ return;
33
+ }
34
+ switch (s->base.is_jmp) {
35
+ case DISAS_NEXT:
36
+ case DISAS_TOO_MANY:
37
+ case DISAS_NORETURN:
38
+ /*
39
+ * The normal case: just go to the destination TB.
40
+ * NB: NORETURN happens if we generate code like
41
+ * gen_brcondi(l);
42
+ * gen_jmp();
43
+ * gen_set_label(l);
44
+ * gen_jmp();
45
+ * on the second call to gen_jmp().
46
+ */
47
gen_goto_tb(s, tbno, dest);
48
+ break;
49
+ case DISAS_UPDATE_NOCHAIN:
50
+ case DISAS_UPDATE_EXIT:
51
+ /*
52
+ * We already decided we're leaving the TB for some other reason.
53
+ * Avoid using goto_tb so we really do exit back to the main loop
54
+ * and don't chain to another TB.
55
+ */
56
+ gen_set_pc_im(s, dest);
57
+ gen_goto_ptr();
58
+ s->base.is_jmp = DISAS_NORETURN;
59
+ break;
60
+ default:
61
+ /*
62
+ * We shouldn't be emitting code for a jump and also have
63
+ * is_jmp set to one of the special cases like DISAS_SWI.
64
+ */
65
+ g_assert_not_reached();
66
}
67
}
68
69
--
70
2.20.1
71
72
diff view generated by jsdifflib
Deleted patch
1
Architecturally, for an M-profile CPU with the LOB feature the
2
LTPSIZE field in FPDSCR is always constant 4. QEMU's implementation
3
enforces this everywhere, except that we don't check that it is true
4
in incoming migration data.
5
1
6
We're going to add come in gen_update_fp_context() which relies on
7
the "always 4" property. Since this is TCG-only, we don't actually
8
need to be robust to bogus incoming migration data, and the effect of
9
it being wrong would be wrong code generation rather than a QEMU
10
crash; but if it did ever happen somehow it would be very difficult
11
to track down the cause. Add a check so that we fail the inbound
12
migration if the FPDSCR.LTPSIZE value is incorrect.
13
14
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
16
Message-id: 20210913095440.13462-3-peter.maydell@linaro.org
17
---
18
target/arm/machine.c | 13 +++++++++++++
19
1 file changed, 13 insertions(+)
20
21
diff --git a/target/arm/machine.c b/target/arm/machine.c
22
index XXXXXXX..XXXXXXX 100644
23
--- a/target/arm/machine.c
24
+++ b/target/arm/machine.c
25
@@ -XXX,XX +XXX,XX @@ static int cpu_post_load(void *opaque, int version_id)
26
hw_breakpoint_update_all(cpu);
27
hw_watchpoint_update_all(cpu);
28
29
+ /*
30
+ * TCG gen_update_fp_context() relies on the invariant that
31
+ * FPDSCR.LTPSIZE is constant 4 for M-profile with the LOB extension;
32
+ * forbid bogus incoming data with some other value.
33
+ */
34
+ if (arm_feature(env, ARM_FEATURE_M) && cpu_isar_feature(aa32_lob, cpu)) {
35
+ if (extract32(env->v7m.fpdscr[M_REG_NS],
36
+ FPCR_LTPSIZE_SHIFT, FPCR_LTPSIZE_LENGTH) != 4 ||
37
+ extract32(env->v7m.fpdscr[M_REG_S],
38
+ FPCR_LTPSIZE_SHIFT, FPCR_LTPSIZE_LENGTH) != 4) {
39
+ return -1;
40
+ }
41
+ }
42
if (!kvm_enabled()) {
43
pmu_op_finish(&cpu->env);
44
}
45
--
46
2.20.1
47
48
diff view generated by jsdifflib
Deleted patch
1
Optimize MVE arithmetic ops when we have a TCG
2
vector operation we can use.
3
1
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>
7
Message-id: 20210913095440.13462-6-peter.maydell@linaro.org
8
---
9
target/arm/translate-mve.c | 20 +++++++++++---------
10
1 file changed, 11 insertions(+), 9 deletions(-)
11
12
diff --git a/target/arm/translate-mve.c b/target/arm/translate-mve.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/target/arm/translate-mve.c
15
+++ b/target/arm/translate-mve.c
16
@@ -XXX,XX +XXX,XX @@ static bool trans_VPSEL(DisasContext *s, arg_2op *a)
17
return do_2op(s, a, gen_helper_mve_vpsel);
18
}
19
20
-#define DO_2OP(INSN, FN) \
21
+#define DO_2OP_VEC(INSN, FN, VECFN) \
22
static bool trans_##INSN(DisasContext *s, arg_2op *a) \
23
{ \
24
static MVEGenTwoOpFn * const fns[] = { \
25
@@ -XXX,XX +XXX,XX @@ static bool trans_VPSEL(DisasContext *s, arg_2op *a)
26
gen_helper_mve_##FN##w, \
27
NULL, \
28
}; \
29
- return do_2op(s, a, fns[a->size]); \
30
+ return do_2op_vec(s, a, fns[a->size], VECFN); \
31
}
32
33
-DO_2OP(VADD, vadd)
34
-DO_2OP(VSUB, vsub)
35
-DO_2OP(VMUL, vmul)
36
+#define DO_2OP(INSN, FN) DO_2OP_VEC(INSN, FN, NULL)
37
+
38
+DO_2OP_VEC(VADD, vadd, tcg_gen_gvec_add)
39
+DO_2OP_VEC(VSUB, vsub, tcg_gen_gvec_sub)
40
+DO_2OP_VEC(VMUL, vmul, tcg_gen_gvec_mul)
41
DO_2OP(VMULH_S, vmulhs)
42
DO_2OP(VMULH_U, vmulhu)
43
DO_2OP(VRMULH_S, vrmulhs)
44
DO_2OP(VRMULH_U, vrmulhu)
45
-DO_2OP(VMAX_S, vmaxs)
46
-DO_2OP(VMAX_U, vmaxu)
47
-DO_2OP(VMIN_S, vmins)
48
-DO_2OP(VMIN_U, vminu)
49
+DO_2OP_VEC(VMAX_S, vmaxs, tcg_gen_gvec_smax)
50
+DO_2OP_VEC(VMAX_U, vmaxu, tcg_gen_gvec_umax)
51
+DO_2OP_VEC(VMIN_S, vmins, tcg_gen_gvec_smin)
52
+DO_2OP_VEC(VMIN_U, vminu, tcg_gen_gvec_umin)
53
DO_2OP(VABD_S, vabds)
54
DO_2OP(VABD_U, vabdu)
55
DO_2OP(VHADD_S, vhadds)
56
--
57
2.20.1
58
59
diff view generated by jsdifflib
Deleted patch
1
Optimize the MVE VNEG and VABS insns by using TCG
2
vector ops when possible.
3
1
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>
7
Message-id: 20210913095440.13462-7-peter.maydell@linaro.org
8
---
9
target/arm/translate-mve.c | 32 ++++++++++++++++++++++----------
10
1 file changed, 22 insertions(+), 10 deletions(-)
11
12
diff --git a/target/arm/translate-mve.c b/target/arm/translate-mve.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/target/arm/translate-mve.c
15
+++ b/target/arm/translate-mve.c
16
@@ -XXX,XX +XXX,XX @@ static bool trans_VDUP(DisasContext *s, arg_VDUP *a)
17
return true;
18
}
19
20
-static bool do_1op(DisasContext *s, arg_1op *a, MVEGenOneOpFn fn)
21
+static bool do_1op_vec(DisasContext *s, arg_1op *a, MVEGenOneOpFn fn,
22
+ GVecGen2Fn vecfn)
23
{
24
TCGv_ptr qd, qm;
25
26
@@ -XXX,XX +XXX,XX @@ static bool do_1op(DisasContext *s, arg_1op *a, MVEGenOneOpFn fn)
27
return true;
28
}
29
30
- qd = mve_qreg_ptr(a->qd);
31
- qm = mve_qreg_ptr(a->qm);
32
- fn(cpu_env, qd, qm);
33
- tcg_temp_free_ptr(qd);
34
- tcg_temp_free_ptr(qm);
35
+ if (vecfn && mve_no_predication(s)) {
36
+ vecfn(a->size, mve_qreg_offset(a->qd), mve_qreg_offset(a->qm), 16, 16);
37
+ } else {
38
+ qd = mve_qreg_ptr(a->qd);
39
+ qm = mve_qreg_ptr(a->qm);
40
+ fn(cpu_env, qd, qm);
41
+ tcg_temp_free_ptr(qd);
42
+ tcg_temp_free_ptr(qm);
43
+ }
44
mve_update_eci(s);
45
return true;
46
}
47
48
-#define DO_1OP(INSN, FN) \
49
+static bool do_1op(DisasContext *s, arg_1op *a, MVEGenOneOpFn fn)
50
+{
51
+ return do_1op_vec(s, a, fn, NULL);
52
+}
53
+
54
+#define DO_1OP_VEC(INSN, FN, VECFN) \
55
static bool trans_##INSN(DisasContext *s, arg_1op *a) \
56
{ \
57
static MVEGenOneOpFn * const fns[] = { \
58
@@ -XXX,XX +XXX,XX @@ static bool do_1op(DisasContext *s, arg_1op *a, MVEGenOneOpFn fn)
59
gen_helper_mve_##FN##w, \
60
NULL, \
61
}; \
62
- return do_1op(s, a, fns[a->size]); \
63
+ return do_1op_vec(s, a, fns[a->size], VECFN); \
64
}
65
66
+#define DO_1OP(INSN, FN) DO_1OP_VEC(INSN, FN, NULL)
67
+
68
DO_1OP(VCLZ, vclz)
69
DO_1OP(VCLS, vcls)
70
-DO_1OP(VABS, vabs)
71
-DO_1OP(VNEG, vneg)
72
+DO_1OP_VEC(VABS, vabs, tcg_gen_gvec_abs)
73
+DO_1OP_VEC(VNEG, vneg, tcg_gen_gvec_neg)
74
DO_1OP(VQABS, vqabs)
75
DO_1OP(VQNEG, vqneg)
76
DO_1OP(VMAXA, vmaxa)
77
--
78
2.20.1
79
80
diff view generated by jsdifflib
Deleted patch
1
Optimize the MVE VDUP insns by using TCG vector ops when possible.
2
1
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Message-id: 20210913095440.13462-8-peter.maydell@linaro.org
6
---
7
target/arm/translate-mve.c | 12 ++++++++----
8
1 file changed, 8 insertions(+), 4 deletions(-)
9
10
diff --git a/target/arm/translate-mve.c b/target/arm/translate-mve.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/target/arm/translate-mve.c
13
+++ b/target/arm/translate-mve.c
14
@@ -XXX,XX +XXX,XX @@ static bool trans_VDUP(DisasContext *s, arg_VDUP *a)
15
return true;
16
}
17
18
- qd = mve_qreg_ptr(a->qd);
19
rt = load_reg(s, a->rt);
20
- tcg_gen_dup_i32(a->size, rt, rt);
21
- gen_helper_mve_vdup(cpu_env, qd, rt);
22
- tcg_temp_free_ptr(qd);
23
+ if (mve_no_predication(s)) {
24
+ tcg_gen_gvec_dup_i32(a->size, mve_qreg_offset(a->qd), 16, 16, rt);
25
+ } else {
26
+ qd = mve_qreg_ptr(a->qd);
27
+ tcg_gen_dup_i32(a->size, rt, rt);
28
+ gen_helper_mve_vdup(cpu_env, qd, rt);
29
+ tcg_temp_free_ptr(qd);
30
+ }
31
tcg_temp_free_i32(rt);
32
mve_update_eci(s);
33
return true;
34
--
35
2.20.1
36
37
diff view generated by jsdifflib