1
A last collection of patches to squeeze in before rc0.
1
The following changes since commit 61fee7f45955cd0bf9b79be9fa9c7ebabb5e6a85:
2
The patches from me are all bugfixes. Philippe's are just
3
code-movement, but I wanted to get these into 4.1 because
4
that kind of patch is so painful to have to rebase.
5
(The diffstat is huge but it's just code moving from file to file.)
6
2
7
thanks
3
Merge remote-tracking branch 'remotes/philmd-gitlab/tags/acceptance-testing-20200622' into staging (2020-06-22 20:50:10 +0100)
8
-- PMM
9
10
The following changes since commit 234e256511e588680300600ce087c5185d68cf2a:
11
12
Merge remote-tracking branch 'remotes/armbru/tags/pull-build-2019-07-02-v2' into staging (2019-07-04 15:58:46 +0100)
13
4
14
are available in the Git repository at:
5
are available in the Git repository at:
15
6
16
https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20190704
7
https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20200623
17
8
18
for you to fetch changes up to b75f3735802b5b33f10e4bfe374d4b17bb86d29a:
9
for you to fetch changes up to 539533b85fbd269f777bed931de8ccae1dd837e9:
19
10
20
target/arm: Correct VMOV_imm_dp handling of short vectors (2019-07-04 16:52:05 +0100)
11
arm/virt: Add memory hot remove support (2020-06-23 11:39:48 +0100)
21
12
22
----------------------------------------------------------------
13
----------------------------------------------------------------
23
target-arm queue:
14
target-arm queue:
24
* more code-movement to separate TCG-only functions into their own files
15
* util/oslib-posix : qemu_init_exec_dir implementation for Mac
25
* Correct VMOV_imm_dp handling of short vectors
16
* target/arm: Last parts of neon decodetree conversion
26
* Execute Thumb instructions when their condbits are 0xf
17
* hw/arm/virt: Add 5.0 HW compat props
27
* armv7m_systick: Forbid non-privileged accesses
18
* hw/watchdog/cmsdk-apb-watchdog: Add trace event for lock status
28
* Use _ra versions of cpu_stl_data() in v7M helpers
19
* mps2: Add CMSDK APB watchdog, FPGAIO block, S2I devices and I2C devices
29
* v8M: Check state of exception being returned from
20
* mps2: Add some unimplemented-device stubs for audio and GPIO
30
* v8M: Forcibly clear negative-priority exceptions on deactivate
21
* mps2-tz: Use the ARM SBCon two-wire serial bus interface
22
* target/arm: Check supported KVM features globally (not per vCPU)
23
* tests/qtest/arm-cpu-features: Add feature setting tests
24
* arm/virt: Add memory hot remove support
31
25
32
----------------------------------------------------------------
26
----------------------------------------------------------------
33
Peter Maydell (6):
27
Andrew Jones (2):
34
arm v8M: Forcibly clear negative-priority exceptions on deactivate
28
hw/arm/virt: Add 5.0 HW compat props
35
target/arm: v8M: Check state of exception being returned from
29
tests/qtest/arm-cpu-features: Add feature setting tests
36
target/arm: Use _ra versions of cpu_stl_data() in v7M helpers
37
hw/timer/armv7m_systick: Forbid non-privileged accesses
38
target/arm: Execute Thumb instructions when their condbits are 0xf
39
target/arm: Correct VMOV_imm_dp handling of short vectors
40
30
41
Philippe Mathieu-Daudé (3):
31
David CARLIER (1):
42
target/arm: Move debug routines to debug_helper.c
32
util/oslib-posix : qemu_init_exec_dir implementation for Mac
43
target/arm: Restrict semi-hosting to TCG
44
target/arm/helper: Move M profile routines to m_helper.c
45
33
46
target/arm/Makefile.objs | 5 +-
34
Peter Maydell (23):
47
target/arm/cpu.h | 7 +
35
target/arm: Convert Neon 2-reg-misc VREV64 to decodetree
48
hw/intc/armv7m_nvic.c | 54 +-
36
target/arm: Convert Neon 2-reg-misc pairwise ops to decodetree
49
hw/timer/armv7m_systick.c | 26 +-
37
target/arm: Convert VZIP, VUZP to decodetree
50
target/arm/cpu.c | 9 +-
38
target/arm: Convert Neon narrowing moves to decodetree
51
target/arm/debug_helper.c | 311 +++++
39
target/arm: Convert Neon 2-reg-misc VSHLL to decodetree
52
target/arm/helper.c | 2646 +--------------------------------------
40
target/arm: Convert Neon VCVT f16/f32 insns to decodetree
53
target/arm/m_helper.c | 2679 ++++++++++++++++++++++++++++++++++++++++
41
target/arm: Convert vectorised 2-reg-misc Neon ops to decodetree
54
target/arm/op_helper.c | 295 -----
42
target/arm: Convert Neon 2-reg-misc crypto operations to decodetree
55
target/arm/translate-vfp.inc.c | 2 +-
43
target/arm: Rename NeonGenOneOpFn to NeonGenOne64OpFn
56
target/arm/translate.c | 15 +-
44
target/arm: Fix capitalization in NeonGenTwo{Single, Double}OPFn typedefs
57
11 files changed, 3096 insertions(+), 2953 deletions(-)
45
target/arm: Make gen_swap_half() take separate src and dest
58
create mode 100644 target/arm/debug_helper.c
46
target/arm: Convert Neon 2-reg-misc VREV32 and VREV16 to decodetree
59
create mode 100644 target/arm/m_helper.c
47
target/arm: Convert remaining simple 2-reg-misc Neon ops
48
target/arm: Convert Neon VQABS, VQNEG to decodetree
49
target/arm: Convert simple fp Neon 2-reg-misc insns
50
target/arm: Convert Neon 2-reg-misc fp-compare-with-zero insns to decodetree
51
target/arm: Convert Neon 2-reg-misc VRINT insns to decodetree
52
target/arm: Convert Neon 2-reg-misc VCVT insns to decodetree
53
target/arm: Convert Neon VSWP to decodetree
54
target/arm: Convert Neon VTRN to decodetree
55
target/arm: Move some functions used only in translate-neon.inc.c to that file
56
target/arm: Remove unnecessary gen_io_end() calls
57
target/arm: Remove dead code relating to SABA and UABA
60
58
59
Philippe Mathieu-Daudé (15):
60
hw/watchdog/cmsdk-apb-watchdog: Add trace event for lock status
61
hw/i2c/versatile_i2c: Add definitions for register addresses
62
hw/i2c/versatile_i2c: Add SCL/SDA definitions
63
hw/i2c: Add header for ARM SBCon two-wire serial bus interface
64
hw/arm: Use TYPE_VERSATILE_I2C instead of hardcoded string
65
hw/arm/mps2: Document CMSDK/FPGA APB subsystem sections
66
hw/arm/mps2: Rename CMSDK AHB peripheral region
67
hw/arm/mps2: Add CMSDK APB watchdog device
68
hw/arm/mps2: Add CMSDK AHB GPIO peripherals as unimplemented devices
69
hw/arm/mps2: Map the FPGA I/O block
70
hw/arm/mps2: Add SPI devices
71
hw/arm/mps2: Add I2C devices
72
hw/arm/mps2: Add audio I2S interface as unimplemented device
73
hw/arm/mps2-tz: Use the ARM SBCon two-wire serial bus interface
74
target/arm: Check supported KVM features globally (not per vCPU)
75
76
Shameer Kolothum (1):
77
arm/virt: Add memory hot remove support
78
79
include/hw/i2c/arm_sbcon_i2c.h | 35 ++
80
target/arm/cpu.h | 2 +-
81
target/arm/kvm_arm.h | 21 +-
82
target/arm/translate.h | 8 +-
83
target/arm/neon-dp.decode | 106 ++++
84
hw/acpi/generic_event_device.c | 29 +
85
hw/arm/mps2-tz.c | 23 +-
86
hw/arm/mps2.c | 65 ++-
87
hw/arm/realview.c | 3 +-
88
hw/arm/versatilepb.c | 3 +-
89
hw/arm/vexpress.c | 3 +-
90
hw/arm/virt.c | 63 +-
91
hw/i2c/versatile_i2c.c | 38 +-
92
hw/watchdog/cmsdk-apb-watchdog.c | 1 +
93
target/arm/cpu.c | 2 +-
94
target/arm/cpu64.c | 10 +-
95
target/arm/kvm.c | 4 +-
96
target/arm/kvm64.c | 14 +-
97
target/arm/translate-a64.c | 20 +-
98
target/arm/translate-neon.inc.c | 1191 +++++++++++++++++++++++++++++++++++++-
99
target/arm/translate-vfp.inc.c | 7 +-
100
target/arm/translate.c | 1064 +---------------------------------
101
tests/qtest/arm-cpu-features.c | 38 +-
102
util/oslib-posix.c | 15 +
103
MAINTAINERS | 1 +
104
hw/arm/Kconfig | 8 +-
105
hw/watchdog/trace-events | 1 +
106
27 files changed, 1624 insertions(+), 1151 deletions(-)
107
create mode 100644 include/hw/i2c/arm_sbcon_i2c.h
108
diff view generated by jsdifflib
New patch
1
From: Andrew Jones <drjones@redhat.com>
1
2
3
Cc: Cornelia Huck <cohuck@redhat.com>
4
Signed-off-by: Andrew Jones <drjones@redhat.com>
5
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
6
Message-id: 20200616140803.25515-1-drjones@redhat.com
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
---
9
hw/arm/virt.c | 1 +
10
1 file changed, 1 insertion(+)
11
12
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/hw/arm/virt.c
15
+++ b/hw/arm/virt.c
16
@@ -XXX,XX +XXX,XX @@ DEFINE_VIRT_MACHINE_AS_LATEST(5, 1)
17
static void virt_machine_5_0_options(MachineClass *mc)
18
{
19
virt_machine_5_1_options(mc);
20
+ compat_props_add(mc->compat_props, hw_compat_5_0, hw_compat_5_0_len);
21
}
22
DEFINE_VIRT_MACHINE(5, 0)
23
24
--
25
2.20.1
26
27
diff view generated by jsdifflib
New patch
1
From: David CARLIER <devnexen@gmail.com>
1
2
3
From 3025a0ce3fdf7d3559fc35a52c659f635f5c750c Mon Sep 17 00:00:00 2001
4
From: David Carlier <devnexen@gmail.com>
5
Date: Tue, 26 May 2020 21:35:27 +0100
6
Subject: [PATCH] util/oslib-posix : qemu_init_exec_dir implementation for Mac
7
8
Using dyld API to get the full path of the current process.
9
10
Signed-off-by: David Carlier <devnexen@gmail.com>
11
Message-id: CA+XhMqxwC10XHVs4Z-JfE0-WLAU3ztDuU9QKVi31mjr59HWCxg@mail.gmail.com
12
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
---
15
util/oslib-posix.c | 15 +++++++++++++++
16
1 file changed, 15 insertions(+)
17
18
diff --git a/util/oslib-posix.c b/util/oslib-posix.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/util/oslib-posix.c
21
+++ b/util/oslib-posix.c
22
@@ -XXX,XX +XXX,XX @@
23
#include <lwp.h>
24
#endif
25
26
+#ifdef __APPLE__
27
+#include <mach-o/dyld.h>
28
+#endif
29
+
30
#include "qemu/mmap-alloc.h"
31
32
#ifdef CONFIG_DEBUG_STACK_USAGE
33
@@ -XXX,XX +XXX,XX @@ void qemu_init_exec_dir(const char *argv0)
34
p = buf;
35
}
36
}
37
+#elif defined(__APPLE__)
38
+ {
39
+ char fpath[PATH_MAX];
40
+ uint32_t len = sizeof(fpath);
41
+ if (_NSGetExecutablePath(fpath, &len) == 0) {
42
+ p = realpath(fpath, buf);
43
+ if (!p) {
44
+ return;
45
+ }
46
+ }
47
+ }
48
#endif
49
/* If we don't have any way of figuring out the actual executable
50
location then try argv[0]. */
51
--
52
2.20.1
53
54
diff view generated by jsdifflib
New patch
1
Convert the Neon VREV64 insn from the 2-reg-misc grouping to decodetree.
1
2
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Message-id: 20200616170844.13318-2-peter.maydell@linaro.org
6
---
7
target/arm/neon-dp.decode | 12 ++++++++
8
target/arm/translate-neon.inc.c | 50 +++++++++++++++++++++++++++++++++
9
target/arm/translate.c | 24 ++--------------
10
3 files changed, 64 insertions(+), 22 deletions(-)
11
12
diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode
13
index XXXXXXX..XXXXXXX 100644
14
--- a/target/arm/neon-dp.decode
15
+++ b/target/arm/neon-dp.decode
16
@@ -XXX,XX +XXX,XX @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm
17
vm=%vm_dp vd=%vd_dp size=1
18
VDUP_scalar 1111 001 1 1 . 11 index:1 100 .... 11 000 q:1 . 0 .... \
19
vm=%vm_dp vd=%vd_dp size=2
20
+
21
+ ##################################################################
22
+ # 2-reg-misc grouping:
23
+ # 1111 001 11 D 11 size:2 opc1:2 Vd:4 0 opc2:4 q:1 M 0 Vm:4
24
+ ##################################################################
25
+
26
+ &2misc vd vm q size
27
+
28
+ @2misc .... ... .. . .. size:2 .. .... . .... q:1 . . .... \
29
+ &2misc vm=%vm_dp vd=%vd_dp
30
+
31
+ VREV64 1111 001 11 . 11 .. 00 .... 0 0000 . . 0 .... @2misc
32
]
33
34
# Subgroup for size != 0b11
35
diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c
36
index XXXXXXX..XXXXXXX 100644
37
--- a/target/arm/translate-neon.inc.c
38
+++ b/target/arm/translate-neon.inc.c
39
@@ -XXX,XX +XXX,XX @@ static bool trans_VDUP_scalar(DisasContext *s, arg_VDUP_scalar *a)
40
a->q ? 16 : 8, a->q ? 16 : 8);
41
return true;
42
}
43
+
44
+static bool trans_VREV64(DisasContext *s, arg_VREV64 *a)
45
+{
46
+ int pass, half;
47
+
48
+ if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
49
+ return false;
50
+ }
51
+
52
+ /* UNDEF accesses to D16-D31 if they don't exist. */
53
+ if (!dc_isar_feature(aa32_simd_r32, s) &&
54
+ ((a->vd | a->vm) & 0x10)) {
55
+ return false;
56
+ }
57
+
58
+ if ((a->vd | a->vm) & a->q) {
59
+ return false;
60
+ }
61
+
62
+ if (a->size == 3) {
63
+ return false;
64
+ }
65
+
66
+ if (!vfp_access_check(s)) {
67
+ return true;
68
+ }
69
+
70
+ for (pass = 0; pass < (a->q ? 2 : 1); pass++) {
71
+ TCGv_i32 tmp[2];
72
+
73
+ for (half = 0; half < 2; half++) {
74
+ tmp[half] = neon_load_reg(a->vm, pass * 2 + half);
75
+ switch (a->size) {
76
+ case 0:
77
+ tcg_gen_bswap32_i32(tmp[half], tmp[half]);
78
+ break;
79
+ case 1:
80
+ gen_swap_half(tmp[half]);
81
+ break;
82
+ case 2:
83
+ break;
84
+ default:
85
+ g_assert_not_reached();
86
+ }
87
+ }
88
+ neon_store_reg(a->vd, pass * 2, tmp[1]);
89
+ neon_store_reg(a->vd, pass * 2 + 1, tmp[0]);
90
+ }
91
+ return true;
92
+}
93
diff --git a/target/arm/translate.c b/target/arm/translate.c
94
index XXXXXXX..XXXXXXX 100644
95
--- a/target/arm/translate.c
96
+++ b/target/arm/translate.c
97
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
98
}
99
switch (op) {
100
case NEON_2RM_VREV64:
101
- for (pass = 0; pass < (q ? 2 : 1); pass++) {
102
- tmp = neon_load_reg(rm, pass * 2);
103
- tmp2 = neon_load_reg(rm, pass * 2 + 1);
104
- switch (size) {
105
- case 0: tcg_gen_bswap32_i32(tmp, tmp); break;
106
- case 1: gen_swap_half(tmp); break;
107
- case 2: /* no-op */ break;
108
- default: abort();
109
- }
110
- neon_store_reg(rd, pass * 2 + 1, tmp);
111
- if (size == 2) {
112
- neon_store_reg(rd, pass * 2, tmp2);
113
- } else {
114
- switch (size) {
115
- case 0: tcg_gen_bswap32_i32(tmp2, tmp2); break;
116
- case 1: gen_swap_half(tmp2); break;
117
- default: abort();
118
- }
119
- neon_store_reg(rd, pass * 2, tmp2);
120
- }
121
- }
122
- break;
123
+ /* handled by decodetree */
124
+ return 1;
125
case NEON_2RM_VPADDL: case NEON_2RM_VPADDL_U:
126
case NEON_2RM_VPADAL: case NEON_2RM_VPADAL_U:
127
for (pass = 0; pass < q + 1; pass++) {
128
--
129
2.20.1
130
131
diff view generated by jsdifflib
New patch
1
1
Convert the pairwise ops VPADDL and VPADAL in the 2-reg-misc grouping
2
to decodetree.
3
4
At this point we can get rid of the weird CPU_V001 #define that was
5
used to avoid having to explicitly list all the arguments being
6
passed to some TCG gen/helper functions.
7
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
Message-id: 20200616170844.13318-3-peter.maydell@linaro.org
11
---
12
target/arm/neon-dp.decode | 6 ++
13
target/arm/translate-neon.inc.c | 149 ++++++++++++++++++++++++++++++++
14
target/arm/translate.c | 35 +-------
15
3 files changed, 157 insertions(+), 33 deletions(-)
16
17
diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode
18
index XXXXXXX..XXXXXXX 100644
19
--- a/target/arm/neon-dp.decode
20
+++ b/target/arm/neon-dp.decode
21
@@ -XXX,XX +XXX,XX @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm
22
&2misc vm=%vm_dp vd=%vd_dp
23
24
VREV64 1111 001 11 . 11 .. 00 .... 0 0000 . . 0 .... @2misc
25
+
26
+ VPADDL_S 1111 001 11 . 11 .. 00 .... 0 0100 . . 0 .... @2misc
27
+ VPADDL_U 1111 001 11 . 11 .. 00 .... 0 0101 . . 0 .... @2misc
28
+
29
+ VPADAL_S 1111 001 11 . 11 .. 00 .... 0 1100 . . 0 .... @2misc
30
+ VPADAL_U 1111 001 11 . 11 .. 00 .... 0 1101 . . 0 .... @2misc
31
]
32
33
# Subgroup for size != 0b11
34
diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c
35
index XXXXXXX..XXXXXXX 100644
36
--- a/target/arm/translate-neon.inc.c
37
+++ b/target/arm/translate-neon.inc.c
38
@@ -XXX,XX +XXX,XX @@ static bool trans_VREV64(DisasContext *s, arg_VREV64 *a)
39
}
40
return true;
41
}
42
+
43
+static bool do_2misc_pairwise(DisasContext *s, arg_2misc *a,
44
+ NeonGenWidenFn *widenfn,
45
+ NeonGenTwo64OpFn *opfn,
46
+ NeonGenTwo64OpFn *accfn)
47
+{
48
+ /*
49
+ * Pairwise long operations: widen both halves of the pair,
50
+ * combine the pairs with the opfn, and then possibly accumulate
51
+ * into the destination with the accfn.
52
+ */
53
+ int pass;
54
+
55
+ if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
56
+ return false;
57
+ }
58
+
59
+ /* UNDEF accesses to D16-D31 if they don't exist. */
60
+ if (!dc_isar_feature(aa32_simd_r32, s) &&
61
+ ((a->vd | a->vm) & 0x10)) {
62
+ return false;
63
+ }
64
+
65
+ if ((a->vd | a->vm) & a->q) {
66
+ return false;
67
+ }
68
+
69
+ if (!widenfn) {
70
+ return false;
71
+ }
72
+
73
+ if (!vfp_access_check(s)) {
74
+ return true;
75
+ }
76
+
77
+ for (pass = 0; pass < a->q + 1; pass++) {
78
+ TCGv_i32 tmp;
79
+ TCGv_i64 rm0_64, rm1_64, rd_64;
80
+
81
+ rm0_64 = tcg_temp_new_i64();
82
+ rm1_64 = tcg_temp_new_i64();
83
+ rd_64 = tcg_temp_new_i64();
84
+ tmp = neon_load_reg(a->vm, pass * 2);
85
+ widenfn(rm0_64, tmp);
86
+ tcg_temp_free_i32(tmp);
87
+ tmp = neon_load_reg(a->vm, pass * 2 + 1);
88
+ widenfn(rm1_64, tmp);
89
+ tcg_temp_free_i32(tmp);
90
+ opfn(rd_64, rm0_64, rm1_64);
91
+ tcg_temp_free_i64(rm0_64);
92
+ tcg_temp_free_i64(rm1_64);
93
+
94
+ if (accfn) {
95
+ TCGv_i64 tmp64 = tcg_temp_new_i64();
96
+ neon_load_reg64(tmp64, a->vd + pass);
97
+ accfn(rd_64, tmp64, rd_64);
98
+ tcg_temp_free_i64(tmp64);
99
+ }
100
+ neon_store_reg64(rd_64, a->vd + pass);
101
+ tcg_temp_free_i64(rd_64);
102
+ }
103
+ return true;
104
+}
105
+
106
+static bool trans_VPADDL_S(DisasContext *s, arg_2misc *a)
107
+{
108
+ static NeonGenWidenFn * const widenfn[] = {
109
+ gen_helper_neon_widen_s8,
110
+ gen_helper_neon_widen_s16,
111
+ tcg_gen_ext_i32_i64,
112
+ NULL,
113
+ };
114
+ static NeonGenTwo64OpFn * const opfn[] = {
115
+ gen_helper_neon_paddl_u16,
116
+ gen_helper_neon_paddl_u32,
117
+ tcg_gen_add_i64,
118
+ NULL,
119
+ };
120
+
121
+ return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], NULL);
122
+}
123
+
124
+static bool trans_VPADDL_U(DisasContext *s, arg_2misc *a)
125
+{
126
+ static NeonGenWidenFn * const widenfn[] = {
127
+ gen_helper_neon_widen_u8,
128
+ gen_helper_neon_widen_u16,
129
+ tcg_gen_extu_i32_i64,
130
+ NULL,
131
+ };
132
+ static NeonGenTwo64OpFn * const opfn[] = {
133
+ gen_helper_neon_paddl_u16,
134
+ gen_helper_neon_paddl_u32,
135
+ tcg_gen_add_i64,
136
+ NULL,
137
+ };
138
+
139
+ return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], NULL);
140
+}
141
+
142
+static bool trans_VPADAL_S(DisasContext *s, arg_2misc *a)
143
+{
144
+ static NeonGenWidenFn * const widenfn[] = {
145
+ gen_helper_neon_widen_s8,
146
+ gen_helper_neon_widen_s16,
147
+ tcg_gen_ext_i32_i64,
148
+ NULL,
149
+ };
150
+ static NeonGenTwo64OpFn * const opfn[] = {
151
+ gen_helper_neon_paddl_u16,
152
+ gen_helper_neon_paddl_u32,
153
+ tcg_gen_add_i64,
154
+ NULL,
155
+ };
156
+ static NeonGenTwo64OpFn * const accfn[] = {
157
+ gen_helper_neon_addl_u16,
158
+ gen_helper_neon_addl_u32,
159
+ tcg_gen_add_i64,
160
+ NULL,
161
+ };
162
+
163
+ return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size],
164
+ accfn[a->size]);
165
+}
166
+
167
+static bool trans_VPADAL_U(DisasContext *s, arg_2misc *a)
168
+{
169
+ static NeonGenWidenFn * const widenfn[] = {
170
+ gen_helper_neon_widen_u8,
171
+ gen_helper_neon_widen_u16,
172
+ tcg_gen_extu_i32_i64,
173
+ NULL,
174
+ };
175
+ static NeonGenTwo64OpFn * const opfn[] = {
176
+ gen_helper_neon_paddl_u16,
177
+ gen_helper_neon_paddl_u32,
178
+ tcg_gen_add_i64,
179
+ NULL,
180
+ };
181
+ static NeonGenTwo64OpFn * const accfn[] = {
182
+ gen_helper_neon_addl_u16,
183
+ gen_helper_neon_addl_u32,
184
+ tcg_gen_add_i64,
185
+ NULL,
186
+ };
187
+
188
+ return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size],
189
+ accfn[a->size]);
190
+}
191
diff --git a/target/arm/translate.c b/target/arm/translate.c
192
index XXXXXXX..XXXXXXX 100644
193
--- a/target/arm/translate.c
194
+++ b/target/arm/translate.c
195
@@ -XXX,XX +XXX,XX @@ static void gen_exception_return(DisasContext *s, TCGv_i32 pc)
196
gen_rfe(s, pc, load_cpu_field(spsr));
197
}
198
199
-#define CPU_V001 cpu_V0, cpu_V0, cpu_V1
200
-
201
static int gen_neon_unzip(int rd, int rm, int size, int q)
202
{
203
TCGv_ptr pd, pm;
204
@@ -XXX,XX +XXX,XX @@ static inline void gen_neon_widen(TCGv_i64 dest, TCGv_i32 src, int size, int u)
205
tcg_temp_free_i32(src);
206
}
207
208
-static inline void gen_neon_addl(int size)
209
-{
210
- switch (size) {
211
- case 0: gen_helper_neon_addl_u16(CPU_V001); break;
212
- case 1: gen_helper_neon_addl_u32(CPU_V001); break;
213
- case 2: tcg_gen_add_i64(CPU_V001); break;
214
- default: abort();
215
- }
216
-}
217
-
218
static void gen_neon_narrow_op(int op, int u, int size,
219
TCGv_i32 dest, TCGv_i64 src)
220
{
221
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
222
}
223
switch (op) {
224
case NEON_2RM_VREV64:
225
- /* handled by decodetree */
226
- return 1;
227
case NEON_2RM_VPADDL: case NEON_2RM_VPADDL_U:
228
case NEON_2RM_VPADAL: case NEON_2RM_VPADAL_U:
229
- for (pass = 0; pass < q + 1; pass++) {
230
- tmp = neon_load_reg(rm, pass * 2);
231
- gen_neon_widen(cpu_V0, tmp, size, op & 1);
232
- tmp = neon_load_reg(rm, pass * 2 + 1);
233
- gen_neon_widen(cpu_V1, tmp, size, op & 1);
234
- switch (size) {
235
- case 0: gen_helper_neon_paddl_u16(CPU_V001); break;
236
- case 1: gen_helper_neon_paddl_u32(CPU_V001); break;
237
- case 2: tcg_gen_add_i64(CPU_V001); break;
238
- default: abort();
239
- }
240
- if (op >= NEON_2RM_VPADAL) {
241
- /* Accumulate. */
242
- neon_load_reg64(cpu_V1, rd + pass);
243
- gen_neon_addl(size);
244
- }
245
- neon_store_reg64(cpu_V0, rd + pass);
246
- }
247
- break;
248
+ /* handled by decodetree */
249
+ return 1;
250
case NEON_2RM_VTRN:
251
if (size == 2) {
252
int n;
253
--
254
2.20.1
255
256
diff view generated by jsdifflib
New patch
1
1
Convert the Neon VZIP and VUZP insns in the 2-reg-misc group to
2
decodetree.
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20200616170844.13318-4-peter.maydell@linaro.org
7
---
8
target/arm/neon-dp.decode | 3 ++
9
target/arm/translate-neon.inc.c | 74 ++++++++++++++++++++++++++
10
target/arm/translate.c | 92 +--------------------------------
11
3 files changed, 79 insertions(+), 90 deletions(-)
12
13
diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode
14
index XXXXXXX..XXXXXXX 100644
15
--- a/target/arm/neon-dp.decode
16
+++ b/target/arm/neon-dp.decode
17
@@ -XXX,XX +XXX,XX @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm
18
19
VPADAL_S 1111 001 11 . 11 .. 00 .... 0 1100 . . 0 .... @2misc
20
VPADAL_U 1111 001 11 . 11 .. 00 .... 0 1101 . . 0 .... @2misc
21
+
22
+ VUZP 1111 001 11 . 11 .. 10 .... 0 0010 . . 0 .... @2misc
23
+ VZIP 1111 001 11 . 11 .. 10 .... 0 0011 . . 0 .... @2misc
24
]
25
26
# Subgroup for size != 0b11
27
diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c
28
index XXXXXXX..XXXXXXX 100644
29
--- a/target/arm/translate-neon.inc.c
30
+++ b/target/arm/translate-neon.inc.c
31
@@ -XXX,XX +XXX,XX @@ static bool trans_VPADAL_U(DisasContext *s, arg_2misc *a)
32
return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size],
33
accfn[a->size]);
34
}
35
+
36
+typedef void ZipFn(TCGv_ptr, TCGv_ptr);
37
+
38
+static bool do_zip_uzp(DisasContext *s, arg_2misc *a,
39
+ ZipFn *fn)
40
+{
41
+ TCGv_ptr pd, pm;
42
+
43
+ if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
44
+ return false;
45
+ }
46
+
47
+ /* UNDEF accesses to D16-D31 if they don't exist. */
48
+ if (!dc_isar_feature(aa32_simd_r32, s) &&
49
+ ((a->vd | a->vm) & 0x10)) {
50
+ return false;
51
+ }
52
+
53
+ if ((a->vd | a->vm) & a->q) {
54
+ return false;
55
+ }
56
+
57
+ if (!fn) {
58
+ /* Bad size or size/q combination */
59
+ return false;
60
+ }
61
+
62
+ if (!vfp_access_check(s)) {
63
+ return true;
64
+ }
65
+
66
+ pd = vfp_reg_ptr(true, a->vd);
67
+ pm = vfp_reg_ptr(true, a->vm);
68
+ fn(pd, pm);
69
+ tcg_temp_free_ptr(pd);
70
+ tcg_temp_free_ptr(pm);
71
+ return true;
72
+}
73
+
74
+static bool trans_VUZP(DisasContext *s, arg_2misc *a)
75
+{
76
+ static ZipFn * const fn[2][4] = {
77
+ {
78
+ gen_helper_neon_unzip8,
79
+ gen_helper_neon_unzip16,
80
+ NULL,
81
+ NULL,
82
+ }, {
83
+ gen_helper_neon_qunzip8,
84
+ gen_helper_neon_qunzip16,
85
+ gen_helper_neon_qunzip32,
86
+ NULL,
87
+ }
88
+ };
89
+ return do_zip_uzp(s, a, fn[a->q][a->size]);
90
+}
91
+
92
+static bool trans_VZIP(DisasContext *s, arg_2misc *a)
93
+{
94
+ static ZipFn * const fn[2][4] = {
95
+ {
96
+ gen_helper_neon_zip8,
97
+ gen_helper_neon_zip16,
98
+ NULL,
99
+ NULL,
100
+ }, {
101
+ gen_helper_neon_qzip8,
102
+ gen_helper_neon_qzip16,
103
+ gen_helper_neon_qzip32,
104
+ NULL,
105
+ }
106
+ };
107
+ return do_zip_uzp(s, a, fn[a->q][a->size]);
108
+}
109
diff --git a/target/arm/translate.c b/target/arm/translate.c
110
index XXXXXXX..XXXXXXX 100644
111
--- a/target/arm/translate.c
112
+++ b/target/arm/translate.c
113
@@ -XXX,XX +XXX,XX @@ static void gen_exception_return(DisasContext *s, TCGv_i32 pc)
114
gen_rfe(s, pc, load_cpu_field(spsr));
115
}
116
117
-static int gen_neon_unzip(int rd, int rm, int size, int q)
118
-{
119
- TCGv_ptr pd, pm;
120
-
121
- if (!q && size == 2) {
122
- return 1;
123
- }
124
- pd = vfp_reg_ptr(true, rd);
125
- pm = vfp_reg_ptr(true, rm);
126
- if (q) {
127
- switch (size) {
128
- case 0:
129
- gen_helper_neon_qunzip8(pd, pm);
130
- break;
131
- case 1:
132
- gen_helper_neon_qunzip16(pd, pm);
133
- break;
134
- case 2:
135
- gen_helper_neon_qunzip32(pd, pm);
136
- break;
137
- default:
138
- abort();
139
- }
140
- } else {
141
- switch (size) {
142
- case 0:
143
- gen_helper_neon_unzip8(pd, pm);
144
- break;
145
- case 1:
146
- gen_helper_neon_unzip16(pd, pm);
147
- break;
148
- default:
149
- abort();
150
- }
151
- }
152
- tcg_temp_free_ptr(pd);
153
- tcg_temp_free_ptr(pm);
154
- return 0;
155
-}
156
-
157
-static int gen_neon_zip(int rd, int rm, int size, int q)
158
-{
159
- TCGv_ptr pd, pm;
160
-
161
- if (!q && size == 2) {
162
- return 1;
163
- }
164
- pd = vfp_reg_ptr(true, rd);
165
- pm = vfp_reg_ptr(true, rm);
166
- if (q) {
167
- switch (size) {
168
- case 0:
169
- gen_helper_neon_qzip8(pd, pm);
170
- break;
171
- case 1:
172
- gen_helper_neon_qzip16(pd, pm);
173
- break;
174
- case 2:
175
- gen_helper_neon_qzip32(pd, pm);
176
- break;
177
- default:
178
- abort();
179
- }
180
- } else {
181
- switch (size) {
182
- case 0:
183
- gen_helper_neon_zip8(pd, pm);
184
- break;
185
- case 1:
186
- gen_helper_neon_zip16(pd, pm);
187
- break;
188
- default:
189
- abort();
190
- }
191
- }
192
- tcg_temp_free_ptr(pd);
193
- tcg_temp_free_ptr(pm);
194
- return 0;
195
-}
196
-
197
static void gen_neon_trn_u8(TCGv_i32 t0, TCGv_i32 t1)
198
{
199
TCGv_i32 rd, tmp;
200
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
201
case NEON_2RM_VREV64:
202
case NEON_2RM_VPADDL: case NEON_2RM_VPADDL_U:
203
case NEON_2RM_VPADAL: case NEON_2RM_VPADAL_U:
204
+ case NEON_2RM_VUZP:
205
+ case NEON_2RM_VZIP:
206
/* handled by decodetree */
207
return 1;
208
case NEON_2RM_VTRN:
209
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
210
goto elementwise;
211
}
212
break;
213
- case NEON_2RM_VUZP:
214
- if (gen_neon_unzip(rd, rm, size, q)) {
215
- return 1;
216
- }
217
- break;
218
- case NEON_2RM_VZIP:
219
- if (gen_neon_zip(rd, rm, size, q)) {
220
- return 1;
221
- }
222
- break;
223
case NEON_2RM_VMOVN: case NEON_2RM_VQMOVN:
224
/* also VQMOVUN; op field and mnemonics don't line up */
225
if (rm & 1) {
226
--
227
2.20.1
228
229
diff view generated by jsdifflib
New patch
1
1
Convert the Neon narrowing moves VMQNV, VQMOVN, VQMOVUN in the 2-reg-misc
2
group to decodetree.
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20200616170844.13318-5-peter.maydell@linaro.org
7
---
8
target/arm/neon-dp.decode | 9 ++++
9
target/arm/translate-neon.inc.c | 59 ++++++++++++++++++++++++
10
target/arm/translate.c | 81 +--------------------------------
11
3 files changed, 70 insertions(+), 79 deletions(-)
12
13
diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode
14
index XXXXXXX..XXXXXXX 100644
15
--- a/target/arm/neon-dp.decode
16
+++ b/target/arm/neon-dp.decode
17
@@ -XXX,XX +XXX,XX @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm
18
19
@2misc .... ... .. . .. size:2 .. .... . .... q:1 . . .... \
20
&2misc vm=%vm_dp vd=%vd_dp
21
+ @2misc_q0 .... ... .. . .. size:2 .. .... . .... . . . .... \
22
+ &2misc vm=%vm_dp vd=%vd_dp q=0
23
24
VREV64 1111 001 11 . 11 .. 00 .... 0 0000 . . 0 .... @2misc
25
26
@@ -XXX,XX +XXX,XX @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm
27
28
VUZP 1111 001 11 . 11 .. 10 .... 0 0010 . . 0 .... @2misc
29
VZIP 1111 001 11 . 11 .. 10 .... 0 0011 . . 0 .... @2misc
30
+
31
+ VMOVN 1111 001 11 . 11 .. 10 .... 0 0100 0 . 0 .... @2misc_q0
32
+ # VQMOVUN: unsigned result (source is always signed)
33
+ VQMOVUN 1111 001 11 . 11 .. 10 .... 0 0100 1 . 0 .... @2misc_q0
34
+ # VQMOVN: signed result, source may be signed (_S) or unsigned (_U)
35
+ VQMOVN_S 1111 001 11 . 11 .. 10 .... 0 0101 0 . 0 .... @2misc_q0
36
+ VQMOVN_U 1111 001 11 . 11 .. 10 .... 0 0101 1 . 0 .... @2misc_q0
37
]
38
39
# Subgroup for size != 0b11
40
diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c
41
index XXXXXXX..XXXXXXX 100644
42
--- a/target/arm/translate-neon.inc.c
43
+++ b/target/arm/translate-neon.inc.c
44
@@ -XXX,XX +XXX,XX @@ static bool trans_VZIP(DisasContext *s, arg_2misc *a)
45
};
46
return do_zip_uzp(s, a, fn[a->q][a->size]);
47
}
48
+
49
+static bool do_vmovn(DisasContext *s, arg_2misc *a,
50
+ NeonGenNarrowEnvFn *narrowfn)
51
+{
52
+ TCGv_i64 rm;
53
+ TCGv_i32 rd0, rd1;
54
+
55
+ if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
56
+ return false;
57
+ }
58
+
59
+ /* UNDEF accesses to D16-D31 if they don't exist. */
60
+ if (!dc_isar_feature(aa32_simd_r32, s) &&
61
+ ((a->vd | a->vm) & 0x10)) {
62
+ return false;
63
+ }
64
+
65
+ if (a->vm & 1) {
66
+ return false;
67
+ }
68
+
69
+ if (!narrowfn) {
70
+ return false;
71
+ }
72
+
73
+ if (!vfp_access_check(s)) {
74
+ return true;
75
+ }
76
+
77
+ rm = tcg_temp_new_i64();
78
+ rd0 = tcg_temp_new_i32();
79
+ rd1 = tcg_temp_new_i32();
80
+
81
+ neon_load_reg64(rm, a->vm);
82
+ narrowfn(rd0, cpu_env, rm);
83
+ neon_load_reg64(rm, a->vm + 1);
84
+ narrowfn(rd1, cpu_env, rm);
85
+ neon_store_reg(a->vd, 0, rd0);
86
+ neon_store_reg(a->vd, 1, rd1);
87
+ tcg_temp_free_i64(rm);
88
+ return true;
89
+}
90
+
91
+#define DO_VMOVN(INSN, FUNC) \
92
+ static bool trans_##INSN(DisasContext *s, arg_2misc *a) \
93
+ { \
94
+ static NeonGenNarrowEnvFn * const narrowfn[] = { \
95
+ FUNC##8, \
96
+ FUNC##16, \
97
+ FUNC##32, \
98
+ NULL, \
99
+ }; \
100
+ return do_vmovn(s, a, narrowfn[a->size]); \
101
+ }
102
+
103
+DO_VMOVN(VMOVN, gen_neon_narrow_u)
104
+DO_VMOVN(VQMOVUN, gen_helper_neon_unarrow_sat)
105
+DO_VMOVN(VQMOVN_S, gen_helper_neon_narrow_sat_s)
106
+DO_VMOVN(VQMOVN_U, gen_helper_neon_narrow_sat_u)
107
diff --git a/target/arm/translate.c b/target/arm/translate.c
108
index XXXXXXX..XXXXXXX 100644
109
--- a/target/arm/translate.c
110
+++ b/target/arm/translate.c
111
@@ -XXX,XX +XXX,XX @@ static void gen_neon_trn_u16(TCGv_i32 t0, TCGv_i32 t1)
112
tcg_temp_free_i32(rd);
113
}
114
115
-static inline void gen_neon_narrow(int size, TCGv_i32 dest, TCGv_i64 src)
116
-{
117
- switch (size) {
118
- case 0: gen_helper_neon_narrow_u8(dest, src); break;
119
- case 1: gen_helper_neon_narrow_u16(dest, src); break;
120
- case 2: tcg_gen_extrl_i64_i32(dest, src); break;
121
- default: abort();
122
- }
123
-}
124
-
125
-static inline void gen_neon_narrow_sats(int size, TCGv_i32 dest, TCGv_i64 src)
126
-{
127
- switch (size) {
128
- case 0: gen_helper_neon_narrow_sat_s8(dest, cpu_env, src); break;
129
- case 1: gen_helper_neon_narrow_sat_s16(dest, cpu_env, src); break;
130
- case 2: gen_helper_neon_narrow_sat_s32(dest, cpu_env, src); break;
131
- default: abort();
132
- }
133
-}
134
-
135
-static inline void gen_neon_narrow_satu(int size, TCGv_i32 dest, TCGv_i64 src)
136
-{
137
- switch (size) {
138
- case 0: gen_helper_neon_narrow_sat_u8(dest, cpu_env, src); break;
139
- case 1: gen_helper_neon_narrow_sat_u16(dest, cpu_env, src); break;
140
- case 2: gen_helper_neon_narrow_sat_u32(dest, cpu_env, src); break;
141
- default: abort();
142
- }
143
-}
144
-
145
-static inline void gen_neon_unarrow_sats(int size, TCGv_i32 dest, TCGv_i64 src)
146
-{
147
- switch (size) {
148
- case 0: gen_helper_neon_unarrow_sat8(dest, cpu_env, src); break;
149
- case 1: gen_helper_neon_unarrow_sat16(dest, cpu_env, src); break;
150
- case 2: gen_helper_neon_unarrow_sat32(dest, cpu_env, src); break;
151
- default: abort();
152
- }
153
-}
154
-
155
static inline void gen_neon_widen(TCGv_i64 dest, TCGv_i32 src, int size, int u)
156
{
157
if (u) {
158
@@ -XXX,XX +XXX,XX @@ static inline void gen_neon_widen(TCGv_i64 dest, TCGv_i32 src, int size, int u)
159
tcg_temp_free_i32(src);
160
}
161
162
-static void gen_neon_narrow_op(int op, int u, int size,
163
- TCGv_i32 dest, TCGv_i64 src)
164
-{
165
- if (op) {
166
- if (u) {
167
- gen_neon_unarrow_sats(size, dest, src);
168
- } else {
169
- gen_neon_narrow(size, dest, src);
170
- }
171
- } else {
172
- if (u) {
173
- gen_neon_narrow_satu(size, dest, src);
174
- } else {
175
- gen_neon_narrow_sats(size, dest, src);
176
- }
177
- }
178
-}
179
-
180
/* Symbolic constants for op fields for Neon 2-register miscellaneous.
181
* The values correspond to bits [17:16,10:7]; see the ARM ARM DDI0406B
182
* table A7-13.
183
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
184
!arm_dc_feature(s, ARM_FEATURE_V8)) {
185
return 1;
186
}
187
- if ((op != NEON_2RM_VMOVN && op != NEON_2RM_VQMOVN) &&
188
- q && ((rm | rd) & 1)) {
189
+ if (q && ((rm | rd) & 1)) {
190
return 1;
191
}
192
switch (op) {
193
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
194
case NEON_2RM_VPADAL: case NEON_2RM_VPADAL_U:
195
case NEON_2RM_VUZP:
196
case NEON_2RM_VZIP:
197
+ case NEON_2RM_VMOVN: case NEON_2RM_VQMOVN:
198
/* handled by decodetree */
199
return 1;
200
case NEON_2RM_VTRN:
201
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
202
goto elementwise;
203
}
204
break;
205
- case NEON_2RM_VMOVN: case NEON_2RM_VQMOVN:
206
- /* also VQMOVUN; op field and mnemonics don't line up */
207
- if (rm & 1) {
208
- return 1;
209
- }
210
- tmp2 = NULL;
211
- for (pass = 0; pass < 2; pass++) {
212
- neon_load_reg64(cpu_V0, rm + pass);
213
- tmp = tcg_temp_new_i32();
214
- gen_neon_narrow_op(op == NEON_2RM_VMOVN, q, size,
215
- tmp, cpu_V0);
216
- if (pass == 0) {
217
- tmp2 = tmp;
218
- } else {
219
- neon_store_reg(rd, 0, tmp2);
220
- neon_store_reg(rd, 1, tmp);
221
- }
222
- }
223
- break;
224
case NEON_2RM_VSHLL:
225
if (q || (rd & 1)) {
226
return 1;
227
--
228
2.20.1
229
230
diff view generated by jsdifflib
New patch
1
Convert the VSHLL insn in the 2-reg-misc Neon group to decodetree.
1
2
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Message-id: 20200616170844.13318-6-peter.maydell@linaro.org
6
---
7
target/arm/neon-dp.decode | 2 ++
8
target/arm/translate-neon.inc.c | 52 +++++++++++++++++++++++++++++++++
9
target/arm/translate.c | 35 +---------------------
10
3 files changed, 55 insertions(+), 34 deletions(-)
11
12
diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode
13
index XXXXXXX..XXXXXXX 100644
14
--- a/target/arm/neon-dp.decode
15
+++ b/target/arm/neon-dp.decode
16
@@ -XXX,XX +XXX,XX @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm
17
# VQMOVN: signed result, source may be signed (_S) or unsigned (_U)
18
VQMOVN_S 1111 001 11 . 11 .. 10 .... 0 0101 0 . 0 .... @2misc_q0
19
VQMOVN_U 1111 001 11 . 11 .. 10 .... 0 0101 1 . 0 .... @2misc_q0
20
+
21
+ VSHLL 1111 001 11 . 11 .. 10 .... 0 0110 0 . 0 .... @2misc_q0
22
]
23
24
# Subgroup for size != 0b11
25
diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c
26
index XXXXXXX..XXXXXXX 100644
27
--- a/target/arm/translate-neon.inc.c
28
+++ b/target/arm/translate-neon.inc.c
29
@@ -XXX,XX +XXX,XX @@ DO_VMOVN(VMOVN, gen_neon_narrow_u)
30
DO_VMOVN(VQMOVUN, gen_helper_neon_unarrow_sat)
31
DO_VMOVN(VQMOVN_S, gen_helper_neon_narrow_sat_s)
32
DO_VMOVN(VQMOVN_U, gen_helper_neon_narrow_sat_u)
33
+
34
+static bool trans_VSHLL(DisasContext *s, arg_2misc *a)
35
+{
36
+ TCGv_i32 rm0, rm1;
37
+ TCGv_i64 rd;
38
+ static NeonGenWidenFn * const widenfns[] = {
39
+ gen_helper_neon_widen_u8,
40
+ gen_helper_neon_widen_u16,
41
+ tcg_gen_extu_i32_i64,
42
+ NULL,
43
+ };
44
+ NeonGenWidenFn *widenfn = widenfns[a->size];
45
+
46
+ if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
47
+ return false;
48
+ }
49
+
50
+ /* UNDEF accesses to D16-D31 if they don't exist. */
51
+ if (!dc_isar_feature(aa32_simd_r32, s) &&
52
+ ((a->vd | a->vm) & 0x10)) {
53
+ return false;
54
+ }
55
+
56
+ if (a->vd & 1) {
57
+ return false;
58
+ }
59
+
60
+ if (!widenfn) {
61
+ return false;
62
+ }
63
+
64
+ if (!vfp_access_check(s)) {
65
+ return true;
66
+ }
67
+
68
+ rd = tcg_temp_new_i64();
69
+
70
+ rm0 = neon_load_reg(a->vm, 0);
71
+ rm1 = neon_load_reg(a->vm, 1);
72
+
73
+ widenfn(rd, rm0);
74
+ tcg_gen_shli_i64(rd, rd, 8 << a->size);
75
+ neon_store_reg64(rd, a->vd);
76
+ widenfn(rd, rm1);
77
+ tcg_gen_shli_i64(rd, rd, 8 << a->size);
78
+ neon_store_reg64(rd, a->vd + 1);
79
+
80
+ tcg_temp_free_i64(rd);
81
+ tcg_temp_free_i32(rm0);
82
+ tcg_temp_free_i32(rm1);
83
+ return true;
84
+}
85
diff --git a/target/arm/translate.c b/target/arm/translate.c
86
index XXXXXXX..XXXXXXX 100644
87
--- a/target/arm/translate.c
88
+++ b/target/arm/translate.c
89
@@ -XXX,XX +XXX,XX @@ static void gen_neon_trn_u16(TCGv_i32 t0, TCGv_i32 t1)
90
tcg_temp_free_i32(rd);
91
}
92
93
-static inline void gen_neon_widen(TCGv_i64 dest, TCGv_i32 src, int size, int u)
94
-{
95
- if (u) {
96
- switch (size) {
97
- case 0: gen_helper_neon_widen_u8(dest, src); break;
98
- case 1: gen_helper_neon_widen_u16(dest, src); break;
99
- case 2: tcg_gen_extu_i32_i64(dest, src); break;
100
- default: abort();
101
- }
102
- } else {
103
- switch (size) {
104
- case 0: gen_helper_neon_widen_s8(dest, src); break;
105
- case 1: gen_helper_neon_widen_s16(dest, src); break;
106
- case 2: tcg_gen_ext_i32_i64(dest, src); break;
107
- default: abort();
108
- }
109
- }
110
- tcg_temp_free_i32(src);
111
-}
112
-
113
/* Symbolic constants for op fields for Neon 2-register miscellaneous.
114
* The values correspond to bits [17:16,10:7]; see the ARM ARM DDI0406B
115
* table A7-13.
116
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
117
case NEON_2RM_VUZP:
118
case NEON_2RM_VZIP:
119
case NEON_2RM_VMOVN: case NEON_2RM_VQMOVN:
120
+ case NEON_2RM_VSHLL:
121
/* handled by decodetree */
122
return 1;
123
case NEON_2RM_VTRN:
124
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
125
goto elementwise;
126
}
127
break;
128
- case NEON_2RM_VSHLL:
129
- if (q || (rd & 1)) {
130
- return 1;
131
- }
132
- tmp = neon_load_reg(rm, 0);
133
- tmp2 = neon_load_reg(rm, 1);
134
- for (pass = 0; pass < 2; pass++) {
135
- if (pass == 1)
136
- tmp = tmp2;
137
- gen_neon_widen(cpu_V0, tmp, size, 1);
138
- tcg_gen_shli_i64(cpu_V0, cpu_V0, 8 << size);
139
- neon_store_reg64(cpu_V0, rd + pass);
140
- }
141
- break;
142
case NEON_2RM_VCVT_F16_F32:
143
{
144
TCGv_ptr fpst;
145
--
146
2.20.1
147
148
diff view generated by jsdifflib
New patch
1
1
Convert the Neon insns in the 2-reg-misc group which are
2
VCVT between f32 and f16 to decodetree.
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20200616170844.13318-7-peter.maydell@linaro.org
7
---
8
target/arm/neon-dp.decode | 3 ++
9
target/arm/translate-neon.inc.c | 96 +++++++++++++++++++++++++++++++++
10
target/arm/translate.c | 65 ++--------------------
11
3 files changed, 102 insertions(+), 62 deletions(-)
12
13
diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode
14
index XXXXXXX..XXXXXXX 100644
15
--- a/target/arm/neon-dp.decode
16
+++ b/target/arm/neon-dp.decode
17
@@ -XXX,XX +XXX,XX @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm
18
VQMOVN_U 1111 001 11 . 11 .. 10 .... 0 0101 1 . 0 .... @2misc_q0
19
20
VSHLL 1111 001 11 . 11 .. 10 .... 0 0110 0 . 0 .... @2misc_q0
21
+
22
+ VCVT_F16_F32 1111 001 11 . 11 .. 10 .... 0 1100 0 . 0 .... @2misc_q0
23
+ VCVT_F32_F16 1111 001 11 . 11 .. 10 .... 0 1110 0 . 0 .... @2misc_q0
24
]
25
26
# Subgroup for size != 0b11
27
diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c
28
index XXXXXXX..XXXXXXX 100644
29
--- a/target/arm/translate-neon.inc.c
30
+++ b/target/arm/translate-neon.inc.c
31
@@ -XXX,XX +XXX,XX @@ static bool trans_VSHLL(DisasContext *s, arg_2misc *a)
32
tcg_temp_free_i32(rm1);
33
return true;
34
}
35
+
36
+static bool trans_VCVT_F16_F32(DisasContext *s, arg_2misc *a)
37
+{
38
+ TCGv_ptr fpst;
39
+ TCGv_i32 ahp, tmp, tmp2, tmp3;
40
+
41
+ if (!arm_dc_feature(s, ARM_FEATURE_NEON) ||
42
+ !dc_isar_feature(aa32_fp16_spconv, s)) {
43
+ return false;
44
+ }
45
+
46
+ /* UNDEF accesses to D16-D31 if they don't exist. */
47
+ if (!dc_isar_feature(aa32_simd_r32, s) &&
48
+ ((a->vd | a->vm) & 0x10)) {
49
+ return false;
50
+ }
51
+
52
+ if ((a->vm & 1) || (a->size != 1)) {
53
+ return false;
54
+ }
55
+
56
+ if (!vfp_access_check(s)) {
57
+ return true;
58
+ }
59
+
60
+ fpst = get_fpstatus_ptr(true);
61
+ ahp = get_ahp_flag();
62
+ tmp = neon_load_reg(a->vm, 0);
63
+ gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp);
64
+ tmp2 = neon_load_reg(a->vm, 1);
65
+ gen_helper_vfp_fcvt_f32_to_f16(tmp2, tmp2, fpst, ahp);
66
+ tcg_gen_shli_i32(tmp2, tmp2, 16);
67
+ tcg_gen_or_i32(tmp2, tmp2, tmp);
68
+ tcg_temp_free_i32(tmp);
69
+ tmp = neon_load_reg(a->vm, 2);
70
+ gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp);
71
+ tmp3 = neon_load_reg(a->vm, 3);
72
+ neon_store_reg(a->vd, 0, tmp2);
73
+ gen_helper_vfp_fcvt_f32_to_f16(tmp3, tmp3, fpst, ahp);
74
+ tcg_gen_shli_i32(tmp3, tmp3, 16);
75
+ tcg_gen_or_i32(tmp3, tmp3, tmp);
76
+ neon_store_reg(a->vd, 1, tmp3);
77
+ tcg_temp_free_i32(tmp);
78
+ tcg_temp_free_i32(ahp);
79
+ tcg_temp_free_ptr(fpst);
80
+
81
+ return true;
82
+}
83
+
84
+static bool trans_VCVT_F32_F16(DisasContext *s, arg_2misc *a)
85
+{
86
+ TCGv_ptr fpst;
87
+ TCGv_i32 ahp, tmp, tmp2, tmp3;
88
+
89
+ if (!arm_dc_feature(s, ARM_FEATURE_NEON) ||
90
+ !dc_isar_feature(aa32_fp16_spconv, s)) {
91
+ return false;
92
+ }
93
+
94
+ /* UNDEF accesses to D16-D31 if they don't exist. */
95
+ if (!dc_isar_feature(aa32_simd_r32, s) &&
96
+ ((a->vd | a->vm) & 0x10)) {
97
+ return false;
98
+ }
99
+
100
+ if ((a->vd & 1) || (a->size != 1)) {
101
+ return false;
102
+ }
103
+
104
+ if (!vfp_access_check(s)) {
105
+ return true;
106
+ }
107
+
108
+ fpst = get_fpstatus_ptr(true);
109
+ ahp = get_ahp_flag();
110
+ tmp3 = tcg_temp_new_i32();
111
+ tmp = neon_load_reg(a->vm, 0);
112
+ tmp2 = neon_load_reg(a->vm, 1);
113
+ tcg_gen_ext16u_i32(tmp3, tmp);
114
+ gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp);
115
+ neon_store_reg(a->vd, 0, tmp3);
116
+ tcg_gen_shri_i32(tmp, tmp, 16);
117
+ gen_helper_vfp_fcvt_f16_to_f32(tmp, tmp, fpst, ahp);
118
+ neon_store_reg(a->vd, 1, tmp);
119
+ tmp3 = tcg_temp_new_i32();
120
+ tcg_gen_ext16u_i32(tmp3, tmp2);
121
+ gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp);
122
+ neon_store_reg(a->vd, 2, tmp3);
123
+ tcg_gen_shri_i32(tmp2, tmp2, 16);
124
+ gen_helper_vfp_fcvt_f16_to_f32(tmp2, tmp2, fpst, ahp);
125
+ neon_store_reg(a->vd, 3, tmp2);
126
+ tcg_temp_free_i32(ahp);
127
+ tcg_temp_free_ptr(fpst);
128
+
129
+ return true;
130
+}
131
diff --git a/target/arm/translate.c b/target/arm/translate.c
132
index XXXXXXX..XXXXXXX 100644
133
--- a/target/arm/translate.c
134
+++ b/target/arm/translate.c
135
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
136
int pass;
137
int u;
138
int vec_size;
139
- TCGv_i32 tmp, tmp2, tmp3;
140
+ TCGv_i32 tmp, tmp2;
141
142
if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
143
return 1;
144
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
145
case NEON_2RM_VZIP:
146
case NEON_2RM_VMOVN: case NEON_2RM_VQMOVN:
147
case NEON_2RM_VSHLL:
148
+ case NEON_2RM_VCVT_F16_F32:
149
+ case NEON_2RM_VCVT_F32_F16:
150
/* handled by decodetree */
151
return 1;
152
case NEON_2RM_VTRN:
153
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
154
goto elementwise;
155
}
156
break;
157
- case NEON_2RM_VCVT_F16_F32:
158
- {
159
- TCGv_ptr fpst;
160
- TCGv_i32 ahp;
161
-
162
- if (!dc_isar_feature(aa32_fp16_spconv, s) ||
163
- q || (rm & 1)) {
164
- return 1;
165
- }
166
- fpst = get_fpstatus_ptr(true);
167
- ahp = get_ahp_flag();
168
- tmp = neon_load_reg(rm, 0);
169
- gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp);
170
- tmp2 = neon_load_reg(rm, 1);
171
- gen_helper_vfp_fcvt_f32_to_f16(tmp2, tmp2, fpst, ahp);
172
- tcg_gen_shli_i32(tmp2, tmp2, 16);
173
- tcg_gen_or_i32(tmp2, tmp2, tmp);
174
- tcg_temp_free_i32(tmp);
175
- tmp = neon_load_reg(rm, 2);
176
- gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp);
177
- tmp3 = neon_load_reg(rm, 3);
178
- neon_store_reg(rd, 0, tmp2);
179
- gen_helper_vfp_fcvt_f32_to_f16(tmp3, tmp3, fpst, ahp);
180
- tcg_gen_shli_i32(tmp3, tmp3, 16);
181
- tcg_gen_or_i32(tmp3, tmp3, tmp);
182
- neon_store_reg(rd, 1, tmp3);
183
- tcg_temp_free_i32(tmp);
184
- tcg_temp_free_i32(ahp);
185
- tcg_temp_free_ptr(fpst);
186
- break;
187
- }
188
- case NEON_2RM_VCVT_F32_F16:
189
- {
190
- TCGv_ptr fpst;
191
- TCGv_i32 ahp;
192
- if (!dc_isar_feature(aa32_fp16_spconv, s) ||
193
- q || (rd & 1)) {
194
- return 1;
195
- }
196
- fpst = get_fpstatus_ptr(true);
197
- ahp = get_ahp_flag();
198
- tmp3 = tcg_temp_new_i32();
199
- tmp = neon_load_reg(rm, 0);
200
- tmp2 = neon_load_reg(rm, 1);
201
- tcg_gen_ext16u_i32(tmp3, tmp);
202
- gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp);
203
- neon_store_reg(rd, 0, tmp3);
204
- tcg_gen_shri_i32(tmp, tmp, 16);
205
- gen_helper_vfp_fcvt_f16_to_f32(tmp, tmp, fpst, ahp);
206
- neon_store_reg(rd, 1, tmp);
207
- tmp3 = tcg_temp_new_i32();
208
- tcg_gen_ext16u_i32(tmp3, tmp2);
209
- gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp);
210
- neon_store_reg(rd, 2, tmp3);
211
- tcg_gen_shri_i32(tmp2, tmp2, 16);
212
- gen_helper_vfp_fcvt_f16_to_f32(tmp2, tmp2, fpst, ahp);
213
- neon_store_reg(rd, 3, tmp2);
214
- tcg_temp_free_i32(ahp);
215
- tcg_temp_free_ptr(fpst);
216
- break;
217
- }
218
case NEON_2RM_AESE: case NEON_2RM_AESMC:
219
if (!dc_isar_feature(aa32_aes, s) || ((rm | rd) & 1)) {
220
return 1;
221
--
222
2.20.1
223
224
diff view generated by jsdifflib
New patch
1
Convert to decodetree the insns in the Neon 2-reg-misc grouping which
2
we implement using gvec.
1
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20200616170844.13318-8-peter.maydell@linaro.org
7
---
8
target/arm/neon-dp.decode | 11 +++++++
9
target/arm/translate-neon.inc.c | 55 +++++++++++++++++++++++++++++++++
10
target/arm/translate.c | 35 +++++----------------
11
3 files changed, 74 insertions(+), 27 deletions(-)
12
13
diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode
14
index XXXXXXX..XXXXXXX 100644
15
--- a/target/arm/neon-dp.decode
16
+++ b/target/arm/neon-dp.decode
17
@@ -XXX,XX +XXX,XX @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm
18
VPADDL_S 1111 001 11 . 11 .. 00 .... 0 0100 . . 0 .... @2misc
19
VPADDL_U 1111 001 11 . 11 .. 00 .... 0 0101 . . 0 .... @2misc
20
21
+ VMVN 1111 001 11 . 11 .. 00 .... 0 1011 . . 0 .... @2misc
22
+
23
VPADAL_S 1111 001 11 . 11 .. 00 .... 0 1100 . . 0 .... @2misc
24
VPADAL_U 1111 001 11 . 11 .. 00 .... 0 1101 . . 0 .... @2misc
25
26
+ VCGT0 1111 001 11 . 11 .. 01 .... 0 0000 . . 0 .... @2misc
27
+ VCGE0 1111 001 11 . 11 .. 01 .... 0 0001 . . 0 .... @2misc
28
+ VCEQ0 1111 001 11 . 11 .. 01 .... 0 0010 . . 0 .... @2misc
29
+ VCLE0 1111 001 11 . 11 .. 01 .... 0 0011 . . 0 .... @2misc
30
+ VCLT0 1111 001 11 . 11 .. 01 .... 0 0100 . . 0 .... @2misc
31
+
32
+ VABS 1111 001 11 . 11 .. 01 .... 0 0110 . . 0 .... @2misc
33
+ VNEG 1111 001 11 . 11 .. 01 .... 0 0111 . . 0 .... @2misc
34
+
35
VUZP 1111 001 11 . 11 .. 10 .... 0 0010 . . 0 .... @2misc
36
VZIP 1111 001 11 . 11 .. 10 .... 0 0011 . . 0 .... @2misc
37
38
diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c
39
index XXXXXXX..XXXXXXX 100644
40
--- a/target/arm/translate-neon.inc.c
41
+++ b/target/arm/translate-neon.inc.c
42
@@ -XXX,XX +XXX,XX @@ static bool trans_VCVT_F32_F16(DisasContext *s, arg_2misc *a)
43
44
return true;
45
}
46
+
47
+static bool do_2misc_vec(DisasContext *s, arg_2misc *a, GVecGen2Fn *fn)
48
+{
49
+ int vec_size = a->q ? 16 : 8;
50
+ int rd_ofs = neon_reg_offset(a->vd, 0);
51
+ int rm_ofs = neon_reg_offset(a->vm, 0);
52
+
53
+ if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
54
+ return false;
55
+ }
56
+
57
+ /* UNDEF accesses to D16-D31 if they don't exist. */
58
+ if (!dc_isar_feature(aa32_simd_r32, s) &&
59
+ ((a->vd | a->vm) & 0x10)) {
60
+ return false;
61
+ }
62
+
63
+ if (a->size == 3) {
64
+ return false;
65
+ }
66
+
67
+ if ((a->vd | a->vm) & a->q) {
68
+ return false;
69
+ }
70
+
71
+ if (!vfp_access_check(s)) {
72
+ return true;
73
+ }
74
+
75
+ fn(a->size, rd_ofs, rm_ofs, vec_size, vec_size);
76
+
77
+ return true;
78
+}
79
+
80
+#define DO_2MISC_VEC(INSN, FN) \
81
+ static bool trans_##INSN(DisasContext *s, arg_2misc *a) \
82
+ { \
83
+ return do_2misc_vec(s, a, FN); \
84
+ }
85
+
86
+DO_2MISC_VEC(VNEG, tcg_gen_gvec_neg)
87
+DO_2MISC_VEC(VABS, tcg_gen_gvec_abs)
88
+DO_2MISC_VEC(VCEQ0, gen_gvec_ceq0)
89
+DO_2MISC_VEC(VCGT0, gen_gvec_cgt0)
90
+DO_2MISC_VEC(VCLE0, gen_gvec_cle0)
91
+DO_2MISC_VEC(VCGE0, gen_gvec_cge0)
92
+DO_2MISC_VEC(VCLT0, gen_gvec_clt0)
93
+
94
+static bool trans_VMVN(DisasContext *s, arg_2misc *a)
95
+{
96
+ if (a->size != 0) {
97
+ return false;
98
+ }
99
+ return do_2misc_vec(s, a, tcg_gen_gvec_not);
100
+}
101
diff --git a/target/arm/translate.c b/target/arm/translate.c
102
index XXXXXXX..XXXXXXX 100644
103
--- a/target/arm/translate.c
104
+++ b/target/arm/translate.c
105
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
106
int size;
107
int pass;
108
int u;
109
- int vec_size;
110
TCGv_i32 tmp, tmp2;
111
112
if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
113
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
114
VFP_DREG_D(rd, insn);
115
VFP_DREG_M(rm, insn);
116
size = (insn >> 20) & 3;
117
- vec_size = q ? 16 : 8;
118
rd_ofs = neon_reg_offset(rd, 0);
119
rm_ofs = neon_reg_offset(rm, 0);
120
121
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
122
case NEON_2RM_VSHLL:
123
case NEON_2RM_VCVT_F16_F32:
124
case NEON_2RM_VCVT_F32_F16:
125
+ case NEON_2RM_VMVN:
126
+ case NEON_2RM_VNEG:
127
+ case NEON_2RM_VABS:
128
+ case NEON_2RM_VCEQ0:
129
+ case NEON_2RM_VCGT0:
130
+ case NEON_2RM_VCLE0:
131
+ case NEON_2RM_VCGE0:
132
+ case NEON_2RM_VCLT0:
133
/* handled by decodetree */
134
return 1;
135
case NEON_2RM_VTRN:
136
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
137
q ? gen_helper_crypto_sha256su0
138
: gen_helper_crypto_sha1su1);
139
break;
140
- case NEON_2RM_VMVN:
141
- tcg_gen_gvec_not(0, rd_ofs, rm_ofs, vec_size, vec_size);
142
- break;
143
- case NEON_2RM_VNEG:
144
- tcg_gen_gvec_neg(size, rd_ofs, rm_ofs, vec_size, vec_size);
145
- break;
146
- case NEON_2RM_VABS:
147
- tcg_gen_gvec_abs(size, rd_ofs, rm_ofs, vec_size, vec_size);
148
- break;
149
-
150
- case NEON_2RM_VCEQ0:
151
- gen_gvec_ceq0(size, rd_ofs, rm_ofs, vec_size, vec_size);
152
- break;
153
- case NEON_2RM_VCGT0:
154
- gen_gvec_cgt0(size, rd_ofs, rm_ofs, vec_size, vec_size);
155
- break;
156
- case NEON_2RM_VCLE0:
157
- gen_gvec_cle0(size, rd_ofs, rm_ofs, vec_size, vec_size);
158
- break;
159
- case NEON_2RM_VCGE0:
160
- gen_gvec_cge0(size, rd_ofs, rm_ofs, vec_size, vec_size);
161
- break;
162
- case NEON_2RM_VCLT0:
163
- gen_gvec_clt0(size, rd_ofs, rm_ofs, vec_size, vec_size);
164
- break;
165
166
default:
167
elementwise:
168
--
169
2.20.1
170
171
diff view generated by jsdifflib
New patch
1
Convert the Neon-2-reg misc crypto ops (AESE, AESMC, SHA1H, SHA1SU1)
2
to decodetree.
1
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20200616170844.13318-9-peter.maydell@linaro.org
7
---
8
target/arm/neon-dp.decode | 12 ++++++++
9
target/arm/translate-neon.inc.c | 42 ++++++++++++++++++++++++++
10
target/arm/translate.c | 52 +++------------------------------
11
3 files changed, 58 insertions(+), 48 deletions(-)
12
13
diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode
14
index XXXXXXX..XXXXXXX 100644
15
--- a/target/arm/neon-dp.decode
16
+++ b/target/arm/neon-dp.decode
17
@@ -XXX,XX +XXX,XX @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm
18
&2misc vm=%vm_dp vd=%vd_dp
19
@2misc_q0 .... ... .. . .. size:2 .. .... . .... . . . .... \
20
&2misc vm=%vm_dp vd=%vd_dp q=0
21
+ @2misc_q1 .... ... .. . .. size:2 .. .... . .... . . . .... \
22
+ &2misc vm=%vm_dp vd=%vd_dp q=1
23
24
VREV64 1111 001 11 . 11 .. 00 .... 0 0000 . . 0 .... @2misc
25
26
VPADDL_S 1111 001 11 . 11 .. 00 .... 0 0100 . . 0 .... @2misc
27
VPADDL_U 1111 001 11 . 11 .. 00 .... 0 0101 . . 0 .... @2misc
28
29
+ AESE 1111 001 11 . 11 .. 00 .... 0 0110 0 . 0 .... @2misc_q1
30
+ AESD 1111 001 11 . 11 .. 00 .... 0 0110 1 . 0 .... @2misc_q1
31
+ AESMC 1111 001 11 . 11 .. 00 .... 0 0111 0 . 0 .... @2misc_q1
32
+ AESIMC 1111 001 11 . 11 .. 00 .... 0 0111 1 . 0 .... @2misc_q1
33
+
34
VMVN 1111 001 11 . 11 .. 00 .... 0 1011 . . 0 .... @2misc
35
36
VPADAL_S 1111 001 11 . 11 .. 00 .... 0 1100 . . 0 .... @2misc
37
@@ -XXX,XX +XXX,XX @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm
38
VCLE0 1111 001 11 . 11 .. 01 .... 0 0011 . . 0 .... @2misc
39
VCLT0 1111 001 11 . 11 .. 01 .... 0 0100 . . 0 .... @2misc
40
41
+ SHA1H 1111 001 11 . 11 .. 01 .... 0 0101 1 . 0 .... @2misc_q1
42
+
43
VABS 1111 001 11 . 11 .. 01 .... 0 0110 . . 0 .... @2misc
44
VNEG 1111 001 11 . 11 .. 01 .... 0 0111 . . 0 .... @2misc
45
46
@@ -XXX,XX +XXX,XX @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm
47
48
VSHLL 1111 001 11 . 11 .. 10 .... 0 0110 0 . 0 .... @2misc_q0
49
50
+ SHA1SU1 1111 001 11 . 11 .. 10 .... 0 0111 0 . 0 .... @2misc_q1
51
+ SHA256SU0 1111 001 11 . 11 .. 10 .... 0 0111 1 . 0 .... @2misc_q1
52
+
53
VCVT_F16_F32 1111 001 11 . 11 .. 10 .... 0 1100 0 . 0 .... @2misc_q0
54
VCVT_F32_F16 1111 001 11 . 11 .. 10 .... 0 1110 0 . 0 .... @2misc_q0
55
]
56
diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c
57
index XXXXXXX..XXXXXXX 100644
58
--- a/target/arm/translate-neon.inc.c
59
+++ b/target/arm/translate-neon.inc.c
60
@@ -XXX,XX +XXX,XX @@ static bool trans_VMVN(DisasContext *s, arg_2misc *a)
61
}
62
return do_2misc_vec(s, a, tcg_gen_gvec_not);
63
}
64
+
65
+#define WRAP_2M_3_OOL_FN(WRAPNAME, FUNC, DATA) \
66
+ static void WRAPNAME(unsigned vece, uint32_t rd_ofs, \
67
+ uint32_t rm_ofs, uint32_t oprsz, \
68
+ uint32_t maxsz) \
69
+ { \
70
+ tcg_gen_gvec_3_ool(rd_ofs, rd_ofs, rm_ofs, oprsz, maxsz, \
71
+ DATA, FUNC); \
72
+ }
73
+
74
+#define WRAP_2M_2_OOL_FN(WRAPNAME, FUNC, DATA) \
75
+ static void WRAPNAME(unsigned vece, uint32_t rd_ofs, \
76
+ uint32_t rm_ofs, uint32_t oprsz, \
77
+ uint32_t maxsz) \
78
+ { \
79
+ tcg_gen_gvec_2_ool(rd_ofs, rm_ofs, oprsz, maxsz, DATA, FUNC); \
80
+ }
81
+
82
+WRAP_2M_3_OOL_FN(gen_AESE, gen_helper_crypto_aese, 0)
83
+WRAP_2M_3_OOL_FN(gen_AESD, gen_helper_crypto_aese, 1)
84
+WRAP_2M_2_OOL_FN(gen_AESMC, gen_helper_crypto_aesmc, 0)
85
+WRAP_2M_2_OOL_FN(gen_AESIMC, gen_helper_crypto_aesmc, 1)
86
+WRAP_2M_2_OOL_FN(gen_SHA1H, gen_helper_crypto_sha1h, 0)
87
+WRAP_2M_2_OOL_FN(gen_SHA1SU1, gen_helper_crypto_sha1su1, 0)
88
+WRAP_2M_2_OOL_FN(gen_SHA256SU0, gen_helper_crypto_sha256su0, 0)
89
+
90
+#define DO_2M_CRYPTO(INSN, FEATURE, SIZE) \
91
+ static bool trans_##INSN(DisasContext *s, arg_2misc *a) \
92
+ { \
93
+ if (!dc_isar_feature(FEATURE, s) || a->size != SIZE) { \
94
+ return false; \
95
+ } \
96
+ return do_2misc_vec(s, a, gen_##INSN); \
97
+ }
98
+
99
+DO_2M_CRYPTO(AESE, aa32_aes, 0)
100
+DO_2M_CRYPTO(AESD, aa32_aes, 0)
101
+DO_2M_CRYPTO(AESMC, aa32_aes, 0)
102
+DO_2M_CRYPTO(AESIMC, aa32_aes, 0)
103
+DO_2M_CRYPTO(SHA1H, aa32_sha1, 2)
104
+DO_2M_CRYPTO(SHA1SU1, aa32_sha1, 2)
105
+DO_2M_CRYPTO(SHA256SU0, aa32_sha2, 2)
106
diff --git a/target/arm/translate.c b/target/arm/translate.c
107
index XXXXXXX..XXXXXXX 100644
108
--- a/target/arm/translate.c
109
+++ b/target/arm/translate.c
110
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
111
{
112
int op;
113
int q;
114
- int rd, rm, rd_ofs, rm_ofs;
115
+ int rd, rm;
116
int size;
117
int pass;
118
int u;
119
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
120
VFP_DREG_D(rd, insn);
121
VFP_DREG_M(rm, insn);
122
size = (insn >> 20) & 3;
123
- rd_ofs = neon_reg_offset(rd, 0);
124
- rm_ofs = neon_reg_offset(rm, 0);
125
126
if ((insn & (1 << 23)) == 0) {
127
/* Three register same length: handled by decodetree */
128
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
129
case NEON_2RM_VCLE0:
130
case NEON_2RM_VCGE0:
131
case NEON_2RM_VCLT0:
132
+ case NEON_2RM_AESE: case NEON_2RM_AESMC:
133
+ case NEON_2RM_SHA1H:
134
+ case NEON_2RM_SHA1SU1:
135
/* handled by decodetree */
136
return 1;
137
case NEON_2RM_VTRN:
138
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
139
goto elementwise;
140
}
141
break;
142
- case NEON_2RM_AESE: case NEON_2RM_AESMC:
143
- if (!dc_isar_feature(aa32_aes, s) || ((rm | rd) & 1)) {
144
- return 1;
145
- }
146
- /*
147
- * Bit 6 is the lowest opcode bit; it distinguishes
148
- * between encryption (AESE/AESMC) and decryption
149
- * (AESD/AESIMC).
150
- */
151
- if (op == NEON_2RM_AESE) {
152
- tcg_gen_gvec_3_ool(vfp_reg_offset(true, rd),
153
- vfp_reg_offset(true, rd),
154
- vfp_reg_offset(true, rm),
155
- 16, 16, extract32(insn, 6, 1),
156
- gen_helper_crypto_aese);
157
- } else {
158
- tcg_gen_gvec_2_ool(vfp_reg_offset(true, rd),
159
- vfp_reg_offset(true, rm),
160
- 16, 16, extract32(insn, 6, 1),
161
- gen_helper_crypto_aesmc);
162
- }
163
- break;
164
- case NEON_2RM_SHA1H:
165
- if (!dc_isar_feature(aa32_sha1, s) || ((rm | rd) & 1)) {
166
- return 1;
167
- }
168
- tcg_gen_gvec_2_ool(rd_ofs, rm_ofs, 16, 16, 0,
169
- gen_helper_crypto_sha1h);
170
- break;
171
- case NEON_2RM_SHA1SU1:
172
- if ((rm | rd) & 1) {
173
- return 1;
174
- }
175
- /* bit 6 (q): set -> SHA256SU0, cleared -> SHA1SU1 */
176
- if (q) {
177
- if (!dc_isar_feature(aa32_sha2, s)) {
178
- return 1;
179
- }
180
- } else if (!dc_isar_feature(aa32_sha1, s)) {
181
- return 1;
182
- }
183
- tcg_gen_gvec_2_ool(rd_ofs, rm_ofs, 16, 16, 0,
184
- q ? gen_helper_crypto_sha256su0
185
- : gen_helper_crypto_sha1su1);
186
- break;
187
188
default:
189
elementwise:
190
--
191
2.20.1
192
193
diff view generated by jsdifflib
New patch
1
The NeonGenOneOpFn typedef breaks with the pattern of the other
2
NeonGen*Fn typedefs, because it is a TCGv_i64 -> TCGv_i64 operation
3
but it does not have '64' in its name. Rename it to NeonGenOne64OpFn,
4
so that the old name is available for a TCGv_i32 -> TCGv_i32 operation
5
(which we will need in a subsequent commit).
1
6
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
9
Message-id: 20200616170844.13318-10-peter.maydell@linaro.org
10
---
11
target/arm/translate.h | 2 +-
12
target/arm/translate-a64.c | 4 ++--
13
2 files changed, 3 insertions(+), 3 deletions(-)
14
15
diff --git a/target/arm/translate.h b/target/arm/translate.h
16
index XXXXXXX..XXXXXXX 100644
17
--- a/target/arm/translate.h
18
+++ b/target/arm/translate.h
19
@@ -XXX,XX +XXX,XX @@ typedef void NeonGenWidenFn(TCGv_i64, TCGv_i32);
20
typedef void NeonGenTwoOpWidenFn(TCGv_i64, TCGv_i32, TCGv_i32);
21
typedef void NeonGenTwoSingleOPFn(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_ptr);
22
typedef void NeonGenTwoDoubleOPFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_ptr);
23
-typedef void NeonGenOneOpFn(TCGv_i64, TCGv_i64);
24
+typedef void NeonGenOne64OpFn(TCGv_i64, TCGv_i64);
25
typedef void CryptoTwoOpFn(TCGv_ptr, TCGv_ptr);
26
typedef void CryptoThreeOpIntFn(TCGv_ptr, TCGv_ptr, TCGv_i32);
27
typedef void CryptoThreeOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr);
28
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
29
index XXXXXXX..XXXXXXX 100644
30
--- a/target/arm/translate-a64.c
31
+++ b/target/arm/translate-a64.c
32
@@ -XXX,XX +XXX,XX @@ static void handle_2misc_pairwise(DisasContext *s, int opcode, bool u,
33
} else {
34
for (pass = 0; pass < maxpass; pass++) {
35
TCGv_i64 tcg_op = tcg_temp_new_i64();
36
- NeonGenOneOpFn *genfn;
37
- static NeonGenOneOpFn * const fns[2][2] = {
38
+ NeonGenOne64OpFn *genfn;
39
+ static NeonGenOne64OpFn * const fns[2][2] = {
40
{ gen_helper_neon_addlp_s8, gen_helper_neon_addlp_u8 },
41
{ gen_helper_neon_addlp_s16, gen_helper_neon_addlp_u16 },
42
};
43
--
44
2.20.1
45
46
diff view generated by jsdifflib
New patch
1
All the other typedefs like these spell "Op" with a lowercase 'p';
2
remane the NeonGenTwoSingleOPFn and NeonGenTwoDoubleOPFn typedefs to
3
match.
1
4
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20200616170844.13318-11-peter.maydell@linaro.org
8
---
9
target/arm/translate.h | 4 ++--
10
target/arm/translate-a64.c | 4 ++--
11
target/arm/translate-neon.inc.c | 2 +-
12
3 files changed, 5 insertions(+), 5 deletions(-)
13
14
diff --git a/target/arm/translate.h b/target/arm/translate.h
15
index XXXXXXX..XXXXXXX 100644
16
--- a/target/arm/translate.h
17
+++ b/target/arm/translate.h
18
@@ -XXX,XX +XXX,XX @@ typedef void NeonGenNarrowFn(TCGv_i32, TCGv_i64);
19
typedef void NeonGenNarrowEnvFn(TCGv_i32, TCGv_ptr, TCGv_i64);
20
typedef void NeonGenWidenFn(TCGv_i64, TCGv_i32);
21
typedef void NeonGenTwoOpWidenFn(TCGv_i64, TCGv_i32, TCGv_i32);
22
-typedef void NeonGenTwoSingleOPFn(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_ptr);
23
-typedef void NeonGenTwoDoubleOPFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_ptr);
24
+typedef void NeonGenTwoSingleOpFn(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_ptr);
25
+typedef void NeonGenTwoDoubleOpFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_ptr);
26
typedef void NeonGenOne64OpFn(TCGv_i64, TCGv_i64);
27
typedef void CryptoTwoOpFn(TCGv_ptr, TCGv_ptr);
28
typedef void CryptoThreeOpIntFn(TCGv_ptr, TCGv_ptr, TCGv_i32);
29
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/target/arm/translate-a64.c
32
+++ b/target/arm/translate-a64.c
33
@@ -XXX,XX +XXX,XX @@ static void handle_2misc_fcmp_zero(DisasContext *s, int opcode,
34
TCGv_i64 tcg_op = tcg_temp_new_i64();
35
TCGv_i64 tcg_zero = tcg_const_i64(0);
36
TCGv_i64 tcg_res = tcg_temp_new_i64();
37
- NeonGenTwoDoubleOPFn *genfn;
38
+ NeonGenTwoDoubleOpFn *genfn;
39
bool swap = false;
40
int pass;
41
42
@@ -XXX,XX +XXX,XX @@ static void handle_2misc_fcmp_zero(DisasContext *s, int opcode,
43
TCGv_i32 tcg_op = tcg_temp_new_i32();
44
TCGv_i32 tcg_zero = tcg_const_i32(0);
45
TCGv_i32 tcg_res = tcg_temp_new_i32();
46
- NeonGenTwoSingleOPFn *genfn;
47
+ NeonGenTwoSingleOpFn *genfn;
48
bool swap = false;
49
int pass, maxpasses;
50
51
diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c
52
index XXXXXXX..XXXXXXX 100644
53
--- a/target/arm/translate-neon.inc.c
54
+++ b/target/arm/translate-neon.inc.c
55
@@ -XXX,XX +XXX,XX @@ static bool trans_VSHLL_U_2sh(DisasContext *s, arg_2reg_shift *a)
56
}
57
58
static bool do_fp_2sh(DisasContext *s, arg_2reg_shift *a,
59
- NeonGenTwoSingleOPFn *fn)
60
+ NeonGenTwoSingleOpFn *fn)
61
{
62
/* FP operations in 2-reg-and-shift group */
63
TCGv_i32 tmp, shiftv;
64
--
65
2.20.1
66
67
diff view generated by jsdifflib
1
In the various helper functions for v7M/v8M instructions, use
1
Make gen_swap_half() take a source and destination TCGv_i32 rather
2
the _ra versions of cpu_stl_data() and friends. Otherwise we
2
than modifying the input TCGv_i32; we're going to want to be able to
3
may get wrong behaviour or an assert() due to not being able
3
use it with the more flexible function signature, and this also
4
to locate the TB if there is an exception on the memory access
4
brings it into line with other functions like gen_rev16() and
5
or if it performs an IO operation when in icount mode.
5
gen_revsh().
6
6
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
9
Message-id: 20190617175317.27557-5-peter.maydell@linaro.org
9
Message-id: 20200616170844.13318-12-peter.maydell@linaro.org
10
---
10
---
11
target/arm/m_helper.c | 21 ++++++++++++---------
11
target/arm/translate-neon.inc.c | 2 +-
12
1 file changed, 12 insertions(+), 9 deletions(-)
12
target/arm/translate.c | 10 +++++-----
13
2 files changed, 6 insertions(+), 6 deletions(-)
13
14
14
diff --git a/target/arm/m_helper.c b/target/arm/m_helper.c
15
diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c
15
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
16
--- a/target/arm/m_helper.c
17
--- a/target/arm/translate-neon.inc.c
17
+++ b/target/arm/m_helper.c
18
+++ b/target/arm/translate-neon.inc.c
18
@@ -XXX,XX +XXX,XX @@ void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest)
19
@@ -XXX,XX +XXX,XX @@ static bool trans_VREV64(DisasContext *s, arg_VREV64 *a)
20
tcg_gen_bswap32_i32(tmp[half], tmp[half]);
21
break;
22
case 1:
23
- gen_swap_half(tmp[half]);
24
+ gen_swap_half(tmp[half], tmp[half]);
25
break;
26
case 2:
27
break;
28
diff --git a/target/arm/translate.c b/target/arm/translate.c
29
index XXXXXXX..XXXXXXX 100644
30
--- a/target/arm/translate.c
31
+++ b/target/arm/translate.c
32
@@ -XXX,XX +XXX,XX @@ static void gen_revsh(TCGv_i32 dest, TCGv_i32 var)
33
}
34
35
/* Swap low and high halfwords. */
36
-static void gen_swap_half(TCGv_i32 var)
37
+static void gen_swap_half(TCGv_i32 dest, TCGv_i32 var)
38
{
39
- tcg_gen_rotri_i32(var, var, 16);
40
+ tcg_gen_rotri_i32(dest, var, 16);
41
}
42
43
/* Dual 16-bit add. Result placed in t0 and t1 is marked as dead.
44
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
45
case NEON_2RM_VREV32:
46
switch (size) {
47
case 0: tcg_gen_bswap32_i32(tmp, tmp); break;
48
- case 1: gen_swap_half(tmp); break;
49
+ case 1: gen_swap_half(tmp, tmp); break;
50
default: abort();
51
}
52
break;
53
@@ -XXX,XX +XXX,XX @@ static bool op_smlad(DisasContext *s, arg_rrrr *a, bool m_swap, bool sub)
54
t1 = load_reg(s, a->rn);
55
t2 = load_reg(s, a->rm);
56
if (m_swap) {
57
- gen_swap_half(t2);
58
+ gen_swap_half(t2, t2);
19
}
59
}
20
60
gen_smul_dual(t1, t2);
21
/* Note that these stores can throw exceptions on MPU faults */
61
22
- cpu_stl_data(env, sp, nextinst);
62
@@ -XXX,XX +XXX,XX @@ static bool op_smlald(DisasContext *s, arg_rrrr *a, bool m_swap, bool sub)
23
- cpu_stl_data(env, sp + 4, saved_psr);
63
t1 = load_reg(s, a->rn);
24
+ cpu_stl_data_ra(env, sp, nextinst, GETPC());
64
t2 = load_reg(s, a->rm);
25
+ cpu_stl_data_ra(env, sp + 4, saved_psr, GETPC());
65
if (m_swap) {
26
66
- gen_swap_half(t2);
27
env->regs[13] = sp;
67
+ gen_swap_half(t2, t2);
28
env->regs[14] = 0xfeffffff;
29
@@ -XXX,XX +XXX,XX @@ void HELPER(v7m_vlstm)(CPUARMState *env, uint32_t fptr)
30
/* fptr is the value of Rn, the frame pointer we store the FP regs to */
31
bool s = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK;
32
bool lspact = env->v7m.fpccr[s] & R_V7M_FPCCR_LSPACT_MASK;
33
+ uintptr_t ra = GETPC();
34
35
assert(env->v7m.secure);
36
37
@@ -XXX,XX +XXX,XX @@ void HELPER(v7m_vlstm)(CPUARMState *env, uint32_t fptr)
38
* Note that we do not use v7m_stack_write() here, because the
39
* accesses should not set the FSR bits for stacking errors if they
40
* fail. (In pseudocode terms, they are AccType_NORMAL, not AccType_STACK
41
- * or AccType_LAZYFP). Faults in cpu_stl_data() will throw exceptions
42
+ * or AccType_LAZYFP). Faults in cpu_stl_data_ra() will throw exceptions
43
* and longjmp out.
44
*/
45
if (!(env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPEN_MASK)) {
46
@@ -XXX,XX +XXX,XX @@ void HELPER(v7m_vlstm)(CPUARMState *env, uint32_t fptr)
47
if (i >= 16) {
48
faddr += 8; /* skip the slot for the FPSCR */
49
}
50
- cpu_stl_data(env, faddr, slo);
51
- cpu_stl_data(env, faddr + 4, shi);
52
+ cpu_stl_data_ra(env, faddr, slo, ra);
53
+ cpu_stl_data_ra(env, faddr + 4, shi, ra);
54
}
55
- cpu_stl_data(env, fptr + 0x40, vfp_get_fpscr(env));
56
+ cpu_stl_data_ra(env, fptr + 0x40, vfp_get_fpscr(env), ra);
57
58
/*
59
* If TS is 0 then s0 to s15 and FPSCR are UNKNOWN; we choose to
60
@@ -XXX,XX +XXX,XX @@ void HELPER(v7m_vlstm)(CPUARMState *env, uint32_t fptr)
61
62
void HELPER(v7m_vlldm)(CPUARMState *env, uint32_t fptr)
63
{
64
+ uintptr_t ra = GETPC();
65
+
66
/* fptr is the value of Rn, the frame pointer we load the FP regs from */
67
assert(env->v7m.secure);
68
69
@@ -XXX,XX +XXX,XX @@ void HELPER(v7m_vlldm)(CPUARMState *env, uint32_t fptr)
70
faddr += 8; /* skip the slot for the FPSCR */
71
}
72
73
- slo = cpu_ldl_data(env, faddr);
74
- shi = cpu_ldl_data(env, faddr + 4);
75
+ slo = cpu_ldl_data_ra(env, faddr, ra);
76
+ shi = cpu_ldl_data_ra(env, faddr + 4, ra);
77
78
dn = (uint64_t) shi << 32 | slo;
79
*aa32_vfp_dreg(env, i / 2) = dn;
80
}
81
- fpscr = cpu_ldl_data(env, fptr + 0x40);
82
+ fpscr = cpu_ldl_data_ra(env, fptr + 0x40, ra);
83
vfp_set_fpscr(env, fpscr);
84
}
68
}
69
gen_smul_dual(t1, t2);
85
70
86
--
71
--
87
2.20.1
72
2.20.1
88
73
89
74
diff view generated by jsdifflib
New patch
1
Convert the VREV32 and VREV16 insns in the Neon 2-reg-misc group
2
to decodetree.
1
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20200616170844.13318-13-peter.maydell@linaro.org
7
---
8
target/arm/translate.h | 1 +
9
target/arm/neon-dp.decode | 2 ++
10
target/arm/translate-neon.inc.c | 55 +++++++++++++++++++++++++++++++++
11
target/arm/translate.c | 12 ++-----
12
4 files changed, 60 insertions(+), 10 deletions(-)
13
14
diff --git a/target/arm/translate.h b/target/arm/translate.h
15
index XXXXXXX..XXXXXXX 100644
16
--- a/target/arm/translate.h
17
+++ b/target/arm/translate.h
18
@@ -XXX,XX +XXX,XX @@ typedef void GVecGen4Fn(unsigned, uint32_t, uint32_t, uint32_t,
19
uint32_t, uint32_t, uint32_t);
20
21
/* Function prototype for gen_ functions for calling Neon helpers */
22
+typedef void NeonGenOneOpFn(TCGv_i32, TCGv_i32);
23
typedef void NeonGenOneOpEnvFn(TCGv_i32, TCGv_ptr, TCGv_i32);
24
typedef void NeonGenTwoOpFn(TCGv_i32, TCGv_i32, TCGv_i32);
25
typedef void NeonGenTwoOpEnvFn(TCGv_i32, TCGv_ptr, TCGv_i32, TCGv_i32);
26
diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode
27
index XXXXXXX..XXXXXXX 100644
28
--- a/target/arm/neon-dp.decode
29
+++ b/target/arm/neon-dp.decode
30
@@ -XXX,XX +XXX,XX @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm
31
&2misc vm=%vm_dp vd=%vd_dp q=1
32
33
VREV64 1111 001 11 . 11 .. 00 .... 0 0000 . . 0 .... @2misc
34
+ VREV32 1111 001 11 . 11 .. 00 .... 0 0001 . . 0 .... @2misc
35
+ VREV16 1111 001 11 . 11 .. 00 .... 0 0010 . . 0 .... @2misc
36
37
VPADDL_S 1111 001 11 . 11 .. 00 .... 0 0100 . . 0 .... @2misc
38
VPADDL_U 1111 001 11 . 11 .. 00 .... 0 0101 . . 0 .... @2misc
39
diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c
40
index XXXXXXX..XXXXXXX 100644
41
--- a/target/arm/translate-neon.inc.c
42
+++ b/target/arm/translate-neon.inc.c
43
@@ -XXX,XX +XXX,XX @@ DO_2M_CRYPTO(AESIMC, aa32_aes, 0)
44
DO_2M_CRYPTO(SHA1H, aa32_sha1, 2)
45
DO_2M_CRYPTO(SHA1SU1, aa32_sha1, 2)
46
DO_2M_CRYPTO(SHA256SU0, aa32_sha2, 2)
47
+
48
+static bool do_2misc(DisasContext *s, arg_2misc *a, NeonGenOneOpFn *fn)
49
+{
50
+ int pass;
51
+
52
+ /* Handle a 2-reg-misc operation by iterating 32 bits at a time */
53
+ if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
54
+ return false;
55
+ }
56
+
57
+ /* UNDEF accesses to D16-D31 if they don't exist. */
58
+ if (!dc_isar_feature(aa32_simd_r32, s) &&
59
+ ((a->vd | a->vm) & 0x10)) {
60
+ return false;
61
+ }
62
+
63
+ if (!fn) {
64
+ return false;
65
+ }
66
+
67
+ if ((a->vd | a->vm) & a->q) {
68
+ return false;
69
+ }
70
+
71
+ if (!vfp_access_check(s)) {
72
+ return true;
73
+ }
74
+
75
+ for (pass = 0; pass < (a->q ? 4 : 2); pass++) {
76
+ TCGv_i32 tmp = neon_load_reg(a->vm, pass);
77
+ fn(tmp, tmp);
78
+ neon_store_reg(a->vd, pass, tmp);
79
+ }
80
+
81
+ return true;
82
+}
83
+
84
+static bool trans_VREV32(DisasContext *s, arg_2misc *a)
85
+{
86
+ static NeonGenOneOpFn * const fn[] = {
87
+ tcg_gen_bswap32_i32,
88
+ gen_swap_half,
89
+ NULL,
90
+ NULL,
91
+ };
92
+ return do_2misc(s, a, fn[a->size]);
93
+}
94
+
95
+static bool trans_VREV16(DisasContext *s, arg_2misc *a)
96
+{
97
+ if (a->size != 0) {
98
+ return false;
99
+ }
100
+ return do_2misc(s, a, gen_rev16);
101
+}
102
diff --git a/target/arm/translate.c b/target/arm/translate.c
103
index XXXXXXX..XXXXXXX 100644
104
--- a/target/arm/translate.c
105
+++ b/target/arm/translate.c
106
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
107
case NEON_2RM_AESE: case NEON_2RM_AESMC:
108
case NEON_2RM_SHA1H:
109
case NEON_2RM_SHA1SU1:
110
+ case NEON_2RM_VREV32:
111
+ case NEON_2RM_VREV16:
112
/* handled by decodetree */
113
return 1;
114
case NEON_2RM_VTRN:
115
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
116
for (pass = 0; pass < (q ? 4 : 2); pass++) {
117
tmp = neon_load_reg(rm, pass);
118
switch (op) {
119
- case NEON_2RM_VREV32:
120
- switch (size) {
121
- case 0: tcg_gen_bswap32_i32(tmp, tmp); break;
122
- case 1: gen_swap_half(tmp, tmp); break;
123
- default: abort();
124
- }
125
- break;
126
- case NEON_2RM_VREV16:
127
- gen_rev16(tmp, tmp);
128
- break;
129
case NEON_2RM_VCLS:
130
switch (size) {
131
case 0: gen_helper_neon_cls_s8(tmp, tmp); break;
132
--
133
2.20.1
134
135
diff view generated by jsdifflib
New patch
1
Convert the remaining ops in the Neon 2-reg-misc group which
2
can be implemented simply with our do_2misc() helper.
1
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20200616170844.13318-14-peter.maydell@linaro.org
7
---
8
target/arm/neon-dp.decode | 10 +++++
9
target/arm/translate-neon.inc.c | 69 +++++++++++++++++++++++++++++++++
10
target/arm/translate.c | 38 ++++--------------
11
3 files changed, 86 insertions(+), 31 deletions(-)
12
13
diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode
14
index XXXXXXX..XXXXXXX 100644
15
--- a/target/arm/neon-dp.decode
16
+++ b/target/arm/neon-dp.decode
17
@@ -XXX,XX +XXX,XX @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm
18
AESMC 1111 001 11 . 11 .. 00 .... 0 0111 0 . 0 .... @2misc_q1
19
AESIMC 1111 001 11 . 11 .. 00 .... 0 0111 1 . 0 .... @2misc_q1
20
21
+ VCLS 1111 001 11 . 11 .. 00 .... 0 1000 . . 0 .... @2misc
22
+ VCLZ 1111 001 11 . 11 .. 00 .... 0 1001 . . 0 .... @2misc
23
+ VCNT 1111 001 11 . 11 .. 00 .... 0 1010 . . 0 .... @2misc
24
+
25
VMVN 1111 001 11 . 11 .. 00 .... 0 1011 . . 0 .... @2misc
26
27
VPADAL_S 1111 001 11 . 11 .. 00 .... 0 1100 . . 0 .... @2misc
28
@@ -XXX,XX +XXX,XX @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm
29
VABS 1111 001 11 . 11 .. 01 .... 0 0110 . . 0 .... @2misc
30
VNEG 1111 001 11 . 11 .. 01 .... 0 0111 . . 0 .... @2misc
31
32
+ VABS_F 1111 001 11 . 11 .. 01 .... 0 1110 . . 0 .... @2misc
33
+ VNEG_F 1111 001 11 . 11 .. 01 .... 0 1111 . . 0 .... @2misc
34
+
35
VUZP 1111 001 11 . 11 .. 10 .... 0 0010 . . 0 .... @2misc
36
VZIP 1111 001 11 . 11 .. 10 .... 0 0011 . . 0 .... @2misc
37
38
@@ -XXX,XX +XXX,XX @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm
39
40
VCVT_F16_F32 1111 001 11 . 11 .. 10 .... 0 1100 0 . 0 .... @2misc_q0
41
VCVT_F32_F16 1111 001 11 . 11 .. 10 .... 0 1110 0 . 0 .... @2misc_q0
42
+
43
+ VRECPE 1111 001 11 . 11 .. 11 .... 0 1000 . . 0 .... @2misc
44
+ VRSQRTE 1111 001 11 . 11 .. 11 .... 0 1001 . . 0 .... @2misc
45
]
46
47
# Subgroup for size != 0b11
48
diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c
49
index XXXXXXX..XXXXXXX 100644
50
--- a/target/arm/translate-neon.inc.c
51
+++ b/target/arm/translate-neon.inc.c
52
@@ -XXX,XX +XXX,XX @@ static bool trans_VREV16(DisasContext *s, arg_2misc *a)
53
}
54
return do_2misc(s, a, gen_rev16);
55
}
56
+
57
+static bool trans_VCLS(DisasContext *s, arg_2misc *a)
58
+{
59
+ static NeonGenOneOpFn * const fn[] = {
60
+ gen_helper_neon_cls_s8,
61
+ gen_helper_neon_cls_s16,
62
+ gen_helper_neon_cls_s32,
63
+ NULL,
64
+ };
65
+ return do_2misc(s, a, fn[a->size]);
66
+}
67
+
68
+static void do_VCLZ_32(TCGv_i32 rd, TCGv_i32 rm)
69
+{
70
+ tcg_gen_clzi_i32(rd, rm, 32);
71
+}
72
+
73
+static bool trans_VCLZ(DisasContext *s, arg_2misc *a)
74
+{
75
+ static NeonGenOneOpFn * const fn[] = {
76
+ gen_helper_neon_clz_u8,
77
+ gen_helper_neon_clz_u16,
78
+ do_VCLZ_32,
79
+ NULL,
80
+ };
81
+ return do_2misc(s, a, fn[a->size]);
82
+}
83
+
84
+static bool trans_VCNT(DisasContext *s, arg_2misc *a)
85
+{
86
+ if (a->size != 0) {
87
+ return false;
88
+ }
89
+ return do_2misc(s, a, gen_helper_neon_cnt_u8);
90
+}
91
+
92
+static bool trans_VABS_F(DisasContext *s, arg_2misc *a)
93
+{
94
+ if (a->size != 2) {
95
+ return false;
96
+ }
97
+ /* TODO: FP16 : size == 1 */
98
+ return do_2misc(s, a, gen_helper_vfp_abss);
99
+}
100
+
101
+static bool trans_VNEG_F(DisasContext *s, arg_2misc *a)
102
+{
103
+ if (a->size != 2) {
104
+ return false;
105
+ }
106
+ /* TODO: FP16 : size == 1 */
107
+ return do_2misc(s, a, gen_helper_vfp_negs);
108
+}
109
+
110
+static bool trans_VRECPE(DisasContext *s, arg_2misc *a)
111
+{
112
+ if (a->size != 2) {
113
+ return false;
114
+ }
115
+ return do_2misc(s, a, gen_helper_recpe_u32);
116
+}
117
+
118
+static bool trans_VRSQRTE(DisasContext *s, arg_2misc *a)
119
+{
120
+ if (a->size != 2) {
121
+ return false;
122
+ }
123
+ return do_2misc(s, a, gen_helper_rsqrte_u32);
124
+}
125
diff --git a/target/arm/translate.c b/target/arm/translate.c
126
index XXXXXXX..XXXXXXX 100644
127
--- a/target/arm/translate.c
128
+++ b/target/arm/translate.c
129
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
130
case NEON_2RM_SHA1SU1:
131
case NEON_2RM_VREV32:
132
case NEON_2RM_VREV16:
133
+ case NEON_2RM_VCLS:
134
+ case NEON_2RM_VCLZ:
135
+ case NEON_2RM_VCNT:
136
+ case NEON_2RM_VABS_F:
137
+ case NEON_2RM_VNEG_F:
138
+ case NEON_2RM_VRECPE:
139
+ case NEON_2RM_VRSQRTE:
140
/* handled by decodetree */
141
return 1;
142
case NEON_2RM_VTRN:
143
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
144
for (pass = 0; pass < (q ? 4 : 2); pass++) {
145
tmp = neon_load_reg(rm, pass);
146
switch (op) {
147
- case NEON_2RM_VCLS:
148
- switch (size) {
149
- case 0: gen_helper_neon_cls_s8(tmp, tmp); break;
150
- case 1: gen_helper_neon_cls_s16(tmp, tmp); break;
151
- case 2: gen_helper_neon_cls_s32(tmp, tmp); break;
152
- default: abort();
153
- }
154
- break;
155
- case NEON_2RM_VCLZ:
156
- switch (size) {
157
- case 0: gen_helper_neon_clz_u8(tmp, tmp); break;
158
- case 1: gen_helper_neon_clz_u16(tmp, tmp); break;
159
- case 2: tcg_gen_clzi_i32(tmp, tmp, 32); break;
160
- default: abort();
161
- }
162
- break;
163
- case NEON_2RM_VCNT:
164
- gen_helper_neon_cnt_u8(tmp, tmp);
165
- break;
166
case NEON_2RM_VQABS:
167
switch (size) {
168
case 0:
169
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
170
tcg_temp_free_ptr(fpstatus);
171
break;
172
}
173
- case NEON_2RM_VABS_F:
174
- gen_helper_vfp_abss(tmp, tmp);
175
- break;
176
- case NEON_2RM_VNEG_F:
177
- gen_helper_vfp_negs(tmp, tmp);
178
- break;
179
case NEON_2RM_VSWP:
180
tmp2 = neon_load_reg(rd, pass);
181
neon_store_reg(rm, pass, tmp2);
182
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
183
tcg_temp_free_ptr(fpst);
184
break;
185
}
186
- case NEON_2RM_VRECPE:
187
- gen_helper_recpe_u32(tmp, tmp);
188
- break;
189
- case NEON_2RM_VRSQRTE:
190
- gen_helper_rsqrte_u32(tmp, tmp);
191
- break;
192
case NEON_2RM_VRECPE_F:
193
{
194
TCGv_ptr fpstatus = get_fpstatus_ptr(1);
195
--
196
2.20.1
197
198
diff view generated by jsdifflib
New patch
1
Convert the Neon VQABS and VQNEG insns to decodetree.
2
Since these are the only ones which need cpu_env passing to
3
the helper, we wrap the helper rather than creating a whole
4
new do_2misc_env() function.
1
5
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20200616170844.13318-15-peter.maydell@linaro.org
9
---
10
target/arm/neon-dp.decode | 3 +++
11
target/arm/translate-neon.inc.c | 35 +++++++++++++++++++++++++++++++++
12
target/arm/translate.c | 30 ++--------------------------
13
3 files changed, 40 insertions(+), 28 deletions(-)
14
15
diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode
16
index XXXXXXX..XXXXXXX 100644
17
--- a/target/arm/neon-dp.decode
18
+++ b/target/arm/neon-dp.decode
19
@@ -XXX,XX +XXX,XX @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm
20
VPADAL_S 1111 001 11 . 11 .. 00 .... 0 1100 . . 0 .... @2misc
21
VPADAL_U 1111 001 11 . 11 .. 00 .... 0 1101 . . 0 .... @2misc
22
23
+ VQABS 1111 001 11 . 11 .. 00 .... 0 1110 . . 0 .... @2misc
24
+ VQNEG 1111 001 11 . 11 .. 00 .... 0 1111 . . 0 .... @2misc
25
+
26
VCGT0 1111 001 11 . 11 .. 01 .... 0 0000 . . 0 .... @2misc
27
VCGE0 1111 001 11 . 11 .. 01 .... 0 0001 . . 0 .... @2misc
28
VCEQ0 1111 001 11 . 11 .. 01 .... 0 0010 . . 0 .... @2misc
29
diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/target/arm/translate-neon.inc.c
32
+++ b/target/arm/translate-neon.inc.c
33
@@ -XXX,XX +XXX,XX @@ static bool trans_VRSQRTE(DisasContext *s, arg_2misc *a)
34
}
35
return do_2misc(s, a, gen_helper_rsqrte_u32);
36
}
37
+
38
+#define WRAP_1OP_ENV_FN(WRAPNAME, FUNC) \
39
+ static void WRAPNAME(TCGv_i32 d, TCGv_i32 m) \
40
+ { \
41
+ FUNC(d, cpu_env, m); \
42
+ }
43
+
44
+WRAP_1OP_ENV_FN(gen_VQABS_s8, gen_helper_neon_qabs_s8)
45
+WRAP_1OP_ENV_FN(gen_VQABS_s16, gen_helper_neon_qabs_s16)
46
+WRAP_1OP_ENV_FN(gen_VQABS_s32, gen_helper_neon_qabs_s32)
47
+WRAP_1OP_ENV_FN(gen_VQNEG_s8, gen_helper_neon_qneg_s8)
48
+WRAP_1OP_ENV_FN(gen_VQNEG_s16, gen_helper_neon_qneg_s16)
49
+WRAP_1OP_ENV_FN(gen_VQNEG_s32, gen_helper_neon_qneg_s32)
50
+
51
+static bool trans_VQABS(DisasContext *s, arg_2misc *a)
52
+{
53
+ static NeonGenOneOpFn * const fn[] = {
54
+ gen_VQABS_s8,
55
+ gen_VQABS_s16,
56
+ gen_VQABS_s32,
57
+ NULL,
58
+ };
59
+ return do_2misc(s, a, fn[a->size]);
60
+}
61
+
62
+static bool trans_VQNEG(DisasContext *s, arg_2misc *a)
63
+{
64
+ static NeonGenOneOpFn * const fn[] = {
65
+ gen_VQNEG_s8,
66
+ gen_VQNEG_s16,
67
+ gen_VQNEG_s32,
68
+ NULL,
69
+ };
70
+ return do_2misc(s, a, fn[a->size]);
71
+}
72
diff --git a/target/arm/translate.c b/target/arm/translate.c
73
index XXXXXXX..XXXXXXX 100644
74
--- a/target/arm/translate.c
75
+++ b/target/arm/translate.c
76
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
77
case NEON_2RM_VNEG_F:
78
case NEON_2RM_VRECPE:
79
case NEON_2RM_VRSQRTE:
80
+ case NEON_2RM_VQABS:
81
+ case NEON_2RM_VQNEG:
82
/* handled by decodetree */
83
return 1;
84
case NEON_2RM_VTRN:
85
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
86
for (pass = 0; pass < (q ? 4 : 2); pass++) {
87
tmp = neon_load_reg(rm, pass);
88
switch (op) {
89
- case NEON_2RM_VQABS:
90
- switch (size) {
91
- case 0:
92
- gen_helper_neon_qabs_s8(tmp, cpu_env, tmp);
93
- break;
94
- case 1:
95
- gen_helper_neon_qabs_s16(tmp, cpu_env, tmp);
96
- break;
97
- case 2:
98
- gen_helper_neon_qabs_s32(tmp, cpu_env, tmp);
99
- break;
100
- default: abort();
101
- }
102
- break;
103
- case NEON_2RM_VQNEG:
104
- switch (size) {
105
- case 0:
106
- gen_helper_neon_qneg_s8(tmp, cpu_env, tmp);
107
- break;
108
- case 1:
109
- gen_helper_neon_qneg_s16(tmp, cpu_env, tmp);
110
- break;
111
- case 2:
112
- gen_helper_neon_qneg_s32(tmp, cpu_env, tmp);
113
- break;
114
- default: abort();
115
- }
116
- break;
117
case NEON_2RM_VCGT0_F:
118
{
119
TCGv_ptr fpstatus = get_fpstatus_ptr(1);
120
--
121
2.20.1
122
123
diff view generated by jsdifflib
New patch
1
1
Convert the Neon 2-reg-misc insns which are implemented with
2
simple calls to functions that take the input, output and
3
fpstatus pointer.
4
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20200616170844.13318-16-peter.maydell@linaro.org
8
---
9
target/arm/translate.h | 1 +
10
target/arm/neon-dp.decode | 8 +++++
11
target/arm/translate-neon.inc.c | 62 +++++++++++++++++++++++++++++++++
12
target/arm/translate.c | 56 ++++-------------------------
13
4 files changed, 78 insertions(+), 49 deletions(-)
14
15
diff --git a/target/arm/translate.h b/target/arm/translate.h
16
index XXXXXXX..XXXXXXX 100644
17
--- a/target/arm/translate.h
18
+++ b/target/arm/translate.h
19
@@ -XXX,XX +XXX,XX @@ typedef void NeonGenNarrowFn(TCGv_i32, TCGv_i64);
20
typedef void NeonGenNarrowEnvFn(TCGv_i32, TCGv_ptr, TCGv_i64);
21
typedef void NeonGenWidenFn(TCGv_i64, TCGv_i32);
22
typedef void NeonGenTwoOpWidenFn(TCGv_i64, TCGv_i32, TCGv_i32);
23
+typedef void NeonGenOneSingleOpFn(TCGv_i32, TCGv_i32, TCGv_ptr);
24
typedef void NeonGenTwoSingleOpFn(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_ptr);
25
typedef void NeonGenTwoDoubleOpFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_ptr);
26
typedef void NeonGenOne64OpFn(TCGv_i64, TCGv_i64);
27
diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode
28
index XXXXXXX..XXXXXXX 100644
29
--- a/target/arm/neon-dp.decode
30
+++ b/target/arm/neon-dp.decode
31
@@ -XXX,XX +XXX,XX @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm
32
SHA1SU1 1111 001 11 . 11 .. 10 .... 0 0111 0 . 0 .... @2misc_q1
33
SHA256SU0 1111 001 11 . 11 .. 10 .... 0 0111 1 . 0 .... @2misc_q1
34
35
+ VRINTX 1111 001 11 . 11 .. 10 .... 0 1001 . . 0 .... @2misc
36
+
37
VCVT_F16_F32 1111 001 11 . 11 .. 10 .... 0 1100 0 . 0 .... @2misc_q0
38
VCVT_F32_F16 1111 001 11 . 11 .. 10 .... 0 1110 0 . 0 .... @2misc_q0
39
40
VRECPE 1111 001 11 . 11 .. 11 .... 0 1000 . . 0 .... @2misc
41
VRSQRTE 1111 001 11 . 11 .. 11 .... 0 1001 . . 0 .... @2misc
42
+ VRECPE_F 1111 001 11 . 11 .. 11 .... 0 1010 . . 0 .... @2misc
43
+ VRSQRTE_F 1111 001 11 . 11 .. 11 .... 0 1011 . . 0 .... @2misc
44
+ VCVT_FS 1111 001 11 . 11 .. 11 .... 0 1100 . . 0 .... @2misc
45
+ VCVT_FU 1111 001 11 . 11 .. 11 .... 0 1101 . . 0 .... @2misc
46
+ VCVT_SF 1111 001 11 . 11 .. 11 .... 0 1110 . . 0 .... @2misc
47
+ VCVT_UF 1111 001 11 . 11 .. 11 .... 0 1111 . . 0 .... @2misc
48
]
49
50
# Subgroup for size != 0b11
51
diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c
52
index XXXXXXX..XXXXXXX 100644
53
--- a/target/arm/translate-neon.inc.c
54
+++ b/target/arm/translate-neon.inc.c
55
@@ -XXX,XX +XXX,XX @@ static bool trans_VQNEG(DisasContext *s, arg_2misc *a)
56
};
57
return do_2misc(s, a, fn[a->size]);
58
}
59
+
60
+static bool do_2misc_fp(DisasContext *s, arg_2misc *a,
61
+ NeonGenOneSingleOpFn *fn)
62
+{
63
+ int pass;
64
+ TCGv_ptr fpst;
65
+
66
+ /* Handle a 2-reg-misc operation by iterating 32 bits at a time */
67
+ if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
68
+ return false;
69
+ }
70
+
71
+ /* UNDEF accesses to D16-D31 if they don't exist. */
72
+ if (!dc_isar_feature(aa32_simd_r32, s) &&
73
+ ((a->vd | a->vm) & 0x10)) {
74
+ return false;
75
+ }
76
+
77
+ if (a->size != 2) {
78
+ /* TODO: FP16 will be the size == 1 case */
79
+ return false;
80
+ }
81
+
82
+ if ((a->vd | a->vm) & a->q) {
83
+ return false;
84
+ }
85
+
86
+ if (!vfp_access_check(s)) {
87
+ return true;
88
+ }
89
+
90
+ fpst = get_fpstatus_ptr(1);
91
+ for (pass = 0; pass < (a->q ? 4 : 2); pass++) {
92
+ TCGv_i32 tmp = neon_load_reg(a->vm, pass);
93
+ fn(tmp, tmp, fpst);
94
+ neon_store_reg(a->vd, pass, tmp);
95
+ }
96
+ tcg_temp_free_ptr(fpst);
97
+
98
+ return true;
99
+}
100
+
101
+#define DO_2MISC_FP(INSN, FUNC) \
102
+ static bool trans_##INSN(DisasContext *s, arg_2misc *a) \
103
+ { \
104
+ return do_2misc_fp(s, a, FUNC); \
105
+ }
106
+
107
+DO_2MISC_FP(VRECPE_F, gen_helper_recpe_f32)
108
+DO_2MISC_FP(VRSQRTE_F, gen_helper_rsqrte_f32)
109
+DO_2MISC_FP(VCVT_FS, gen_helper_vfp_sitos)
110
+DO_2MISC_FP(VCVT_FU, gen_helper_vfp_uitos)
111
+DO_2MISC_FP(VCVT_SF, gen_helper_vfp_tosizs)
112
+DO_2MISC_FP(VCVT_UF, gen_helper_vfp_touizs)
113
+
114
+static bool trans_VRINTX(DisasContext *s, arg_2misc *a)
115
+{
116
+ if (!arm_dc_feature(s, ARM_FEATURE_V8)) {
117
+ return false;
118
+ }
119
+ return do_2misc_fp(s, a, gen_helper_rints_exact);
120
+}
121
diff --git a/target/arm/translate.c b/target/arm/translate.c
122
index XXXXXXX..XXXXXXX 100644
123
--- a/target/arm/translate.c
124
+++ b/target/arm/translate.c
125
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
126
case NEON_2RM_VRSQRTE:
127
case NEON_2RM_VQABS:
128
case NEON_2RM_VQNEG:
129
+ case NEON_2RM_VRECPE_F:
130
+ case NEON_2RM_VRSQRTE_F:
131
+ case NEON_2RM_VCVT_FS:
132
+ case NEON_2RM_VCVT_FU:
133
+ case NEON_2RM_VCVT_SF:
134
+ case NEON_2RM_VCVT_UF:
135
+ case NEON_2RM_VRINTX:
136
/* handled by decodetree */
137
return 1;
138
case NEON_2RM_VTRN:
139
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
140
tcg_temp_free_i32(tcg_rmode);
141
break;
142
}
143
- case NEON_2RM_VRINTX:
144
- {
145
- TCGv_ptr fpstatus = get_fpstatus_ptr(1);
146
- gen_helper_rints_exact(tmp, tmp, fpstatus);
147
- tcg_temp_free_ptr(fpstatus);
148
- break;
149
- }
150
case NEON_2RM_VCVTAU:
151
case NEON_2RM_VCVTAS:
152
case NEON_2RM_VCVTNU:
153
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
154
tcg_temp_free_ptr(fpst);
155
break;
156
}
157
- case NEON_2RM_VRECPE_F:
158
- {
159
- TCGv_ptr fpstatus = get_fpstatus_ptr(1);
160
- gen_helper_recpe_f32(tmp, tmp, fpstatus);
161
- tcg_temp_free_ptr(fpstatus);
162
- break;
163
- }
164
- case NEON_2RM_VRSQRTE_F:
165
- {
166
- TCGv_ptr fpstatus = get_fpstatus_ptr(1);
167
- gen_helper_rsqrte_f32(tmp, tmp, fpstatus);
168
- tcg_temp_free_ptr(fpstatus);
169
- break;
170
- }
171
- case NEON_2RM_VCVT_FS: /* VCVT.F32.S32 */
172
- {
173
- TCGv_ptr fpstatus = get_fpstatus_ptr(1);
174
- gen_helper_vfp_sitos(tmp, tmp, fpstatus);
175
- tcg_temp_free_ptr(fpstatus);
176
- break;
177
- }
178
- case NEON_2RM_VCVT_FU: /* VCVT.F32.U32 */
179
- {
180
- TCGv_ptr fpstatus = get_fpstatus_ptr(1);
181
- gen_helper_vfp_uitos(tmp, tmp, fpstatus);
182
- tcg_temp_free_ptr(fpstatus);
183
- break;
184
- }
185
- case NEON_2RM_VCVT_SF: /* VCVT.S32.F32 */
186
- {
187
- TCGv_ptr fpstatus = get_fpstatus_ptr(1);
188
- gen_helper_vfp_tosizs(tmp, tmp, fpstatus);
189
- tcg_temp_free_ptr(fpstatus);
190
- break;
191
- }
192
- case NEON_2RM_VCVT_UF: /* VCVT.U32.F32 */
193
- {
194
- TCGv_ptr fpstatus = get_fpstatus_ptr(1);
195
- gen_helper_vfp_touizs(tmp, tmp, fpstatus);
196
- tcg_temp_free_ptr(fpstatus);
197
- break;
198
- }
199
default:
200
/* Reserved op values were caught by the
201
* neon_2rm_sizes[] check earlier.
202
--
203
2.20.1
204
205
diff view generated by jsdifflib
New patch
1
Convert the fp-compare-with-zero insns in the Neon 2-reg-misc group to
2
decodetree.
1
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20200616170844.13318-17-peter.maydell@linaro.org
7
---
8
target/arm/neon-dp.decode | 6 ++++
9
target/arm/translate-neon.inc.c | 28 ++++++++++++++++++
10
target/arm/translate.c | 50 ++++-----------------------------
11
3 files changed, 39 insertions(+), 45 deletions(-)
12
13
diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode
14
index XXXXXXX..XXXXXXX 100644
15
--- a/target/arm/neon-dp.decode
16
+++ b/target/arm/neon-dp.decode
17
@@ -XXX,XX +XXX,XX @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm
18
VABS 1111 001 11 . 11 .. 01 .... 0 0110 . . 0 .... @2misc
19
VNEG 1111 001 11 . 11 .. 01 .... 0 0111 . . 0 .... @2misc
20
21
+ VCGT0_F 1111 001 11 . 11 .. 01 .... 0 1000 . . 0 .... @2misc
22
+ VCGE0_F 1111 001 11 . 11 .. 01 .... 0 1001 . . 0 .... @2misc
23
+ VCEQ0_F 1111 001 11 . 11 .. 01 .... 0 1010 . . 0 .... @2misc
24
+ VCLE0_F 1111 001 11 . 11 .. 01 .... 0 1011 . . 0 .... @2misc
25
+ VCLT0_F 1111 001 11 . 11 .. 01 .... 0 1100 . . 0 .... @2misc
26
+
27
VABS_F 1111 001 11 . 11 .. 01 .... 0 1110 . . 0 .... @2misc
28
VNEG_F 1111 001 11 . 11 .. 01 .... 0 1111 . . 0 .... @2misc
29
30
diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c
31
index XXXXXXX..XXXXXXX 100644
32
--- a/target/arm/translate-neon.inc.c
33
+++ b/target/arm/translate-neon.inc.c
34
@@ -XXX,XX +XXX,XX @@ static bool trans_VRINTX(DisasContext *s, arg_2misc *a)
35
}
36
return do_2misc_fp(s, a, gen_helper_rints_exact);
37
}
38
+
39
+#define WRAP_FP_CMP0_FWD(WRAPNAME, FUNC) \
40
+ static void WRAPNAME(TCGv_i32 d, TCGv_i32 m, TCGv_ptr fpst) \
41
+ { \
42
+ TCGv_i32 zero = tcg_const_i32(0); \
43
+ FUNC(d, m, zero, fpst); \
44
+ tcg_temp_free_i32(zero); \
45
+ }
46
+#define WRAP_FP_CMP0_REV(WRAPNAME, FUNC) \
47
+ static void WRAPNAME(TCGv_i32 d, TCGv_i32 m, TCGv_ptr fpst) \
48
+ { \
49
+ TCGv_i32 zero = tcg_const_i32(0); \
50
+ FUNC(d, zero, m, fpst); \
51
+ tcg_temp_free_i32(zero); \
52
+ }
53
+
54
+#define DO_FP_CMP0(INSN, FUNC, REV) \
55
+ WRAP_FP_CMP0_##REV(gen_##INSN, FUNC) \
56
+ static bool trans_##INSN(DisasContext *s, arg_2misc *a) \
57
+ { \
58
+ return do_2misc_fp(s, a, gen_##INSN); \
59
+ }
60
+
61
+DO_FP_CMP0(VCGT0_F, gen_helper_neon_cgt_f32, FWD)
62
+DO_FP_CMP0(VCGE0_F, gen_helper_neon_cge_f32, FWD)
63
+DO_FP_CMP0(VCEQ0_F, gen_helper_neon_ceq_f32, FWD)
64
+DO_FP_CMP0(VCLE0_F, gen_helper_neon_cge_f32, REV)
65
+DO_FP_CMP0(VCLT0_F, gen_helper_neon_cgt_f32, REV)
66
diff --git a/target/arm/translate.c b/target/arm/translate.c
67
index XXXXXXX..XXXXXXX 100644
68
--- a/target/arm/translate.c
69
+++ b/target/arm/translate.c
70
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
71
case NEON_2RM_VCVT_SF:
72
case NEON_2RM_VCVT_UF:
73
case NEON_2RM_VRINTX:
74
+ case NEON_2RM_VCGT0_F:
75
+ case NEON_2RM_VCGE0_F:
76
+ case NEON_2RM_VCEQ0_F:
77
+ case NEON_2RM_VCLE0_F:
78
+ case NEON_2RM_VCLT0_F:
79
/* handled by decodetree */
80
return 1;
81
case NEON_2RM_VTRN:
82
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
83
for (pass = 0; pass < (q ? 4 : 2); pass++) {
84
tmp = neon_load_reg(rm, pass);
85
switch (op) {
86
- case NEON_2RM_VCGT0_F:
87
- {
88
- TCGv_ptr fpstatus = get_fpstatus_ptr(1);
89
- tmp2 = tcg_const_i32(0);
90
- gen_helper_neon_cgt_f32(tmp, tmp, tmp2, fpstatus);
91
- tcg_temp_free_i32(tmp2);
92
- tcg_temp_free_ptr(fpstatus);
93
- break;
94
- }
95
- case NEON_2RM_VCGE0_F:
96
- {
97
- TCGv_ptr fpstatus = get_fpstatus_ptr(1);
98
- tmp2 = tcg_const_i32(0);
99
- gen_helper_neon_cge_f32(tmp, tmp, tmp2, fpstatus);
100
- tcg_temp_free_i32(tmp2);
101
- tcg_temp_free_ptr(fpstatus);
102
- break;
103
- }
104
- case NEON_2RM_VCEQ0_F:
105
- {
106
- TCGv_ptr fpstatus = get_fpstatus_ptr(1);
107
- tmp2 = tcg_const_i32(0);
108
- gen_helper_neon_ceq_f32(tmp, tmp, tmp2, fpstatus);
109
- tcg_temp_free_i32(tmp2);
110
- tcg_temp_free_ptr(fpstatus);
111
- break;
112
- }
113
- case NEON_2RM_VCLE0_F:
114
- {
115
- TCGv_ptr fpstatus = get_fpstatus_ptr(1);
116
- tmp2 = tcg_const_i32(0);
117
- gen_helper_neon_cge_f32(tmp, tmp2, tmp, fpstatus);
118
- tcg_temp_free_i32(tmp2);
119
- tcg_temp_free_ptr(fpstatus);
120
- break;
121
- }
122
- case NEON_2RM_VCLT0_F:
123
- {
124
- TCGv_ptr fpstatus = get_fpstatus_ptr(1);
125
- tmp2 = tcg_const_i32(0);
126
- gen_helper_neon_cgt_f32(tmp, tmp2, tmp, fpstatus);
127
- tcg_temp_free_i32(tmp2);
128
- tcg_temp_free_ptr(fpstatus);
129
- break;
130
- }
131
case NEON_2RM_VSWP:
132
tmp2 = neon_load_reg(rd, pass);
133
neon_store_reg(rm, pass, tmp2);
134
--
135
2.20.1
136
137
diff view generated by jsdifflib
1
Thumb instructions in an IT block are set up to be conditionally
1
Convert the Neon 2-reg-misc VRINT insns to decodetree.
2
executed depending on a set of condition bits encoded into the IT
2
Giving these insns their own do_vrint() function allows us
3
bits of the CPSR/XPSR. The architecture specifies that if the
3
to change the rounding mode just once at the start and end
4
condition bits are 0b1111 this means "always execute" (like 0b1110),
4
rather than doing it for every element in the vector.
5
not "never execute"; we were treating it as "never execute". (See
6
the ConditionHolds() pseudocode in both the A-profile and M-profile
7
Arm ARM.)
8
9
This is a bit of an obscure corner case, because the only legal
10
way to get to an 0b1111 set of condbits is to do an exception
11
return which sets the XPSR/CPSR up that way. An IT instruction
12
which encodes a condition sequence that would include an 0b1111 is
13
UNPREDICTABLE, and for v8A the CONSTRAINED UNPREDICTABLE choices
14
for such an IT insn are to NOP, UNDEF, or treat 0b1111 like 0b1110.
15
Add a comment noting that we take the latter option.
16
5
17
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
18
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
19
Message-id: 20190617175317.27557-7-peter.maydell@linaro.org
8
Message-id: 20200616170844.13318-18-peter.maydell@linaro.org
20
---
9
---
21
target/arm/translate.c | 15 +++++++++++++--
10
target/arm/neon-dp.decode | 8 +++++
22
1 file changed, 13 insertions(+), 2 deletions(-)
11
target/arm/translate-neon.inc.c | 61 +++++++++++++++++++++++++++++++++
12
target/arm/translate.c | 31 +++--------------
13
3 files changed, 74 insertions(+), 26 deletions(-)
23
14
15
diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode
16
index XXXXXXX..XXXXXXX 100644
17
--- a/target/arm/neon-dp.decode
18
+++ b/target/arm/neon-dp.decode
19
@@ -XXX,XX +XXX,XX @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm
20
SHA1SU1 1111 001 11 . 11 .. 10 .... 0 0111 0 . 0 .... @2misc_q1
21
SHA256SU0 1111 001 11 . 11 .. 10 .... 0 0111 1 . 0 .... @2misc_q1
22
23
+ VRINTN 1111 001 11 . 11 .. 10 .... 0 1000 . . 0 .... @2misc
24
VRINTX 1111 001 11 . 11 .. 10 .... 0 1001 . . 0 .... @2misc
25
+ VRINTA 1111 001 11 . 11 .. 10 .... 0 1010 . . 0 .... @2misc
26
+ VRINTZ 1111 001 11 . 11 .. 10 .... 0 1011 . . 0 .... @2misc
27
28
VCVT_F16_F32 1111 001 11 . 11 .. 10 .... 0 1100 0 . 0 .... @2misc_q0
29
+
30
+ VRINTM 1111 001 11 . 11 .. 10 .... 0 1101 . . 0 .... @2misc
31
+
32
VCVT_F32_F16 1111 001 11 . 11 .. 10 .... 0 1110 0 . 0 .... @2misc_q0
33
34
+ VRINTP 1111 001 11 . 11 .. 10 .... 0 1111 . . 0 .... @2misc
35
+
36
VRECPE 1111 001 11 . 11 .. 11 .... 0 1000 . . 0 .... @2misc
37
VRSQRTE 1111 001 11 . 11 .. 11 .... 0 1001 . . 0 .... @2misc
38
VRECPE_F 1111 001 11 . 11 .. 11 .... 0 1010 . . 0 .... @2misc
39
diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c
40
index XXXXXXX..XXXXXXX 100644
41
--- a/target/arm/translate-neon.inc.c
42
+++ b/target/arm/translate-neon.inc.c
43
@@ -XXX,XX +XXX,XX @@ DO_FP_CMP0(VCGE0_F, gen_helper_neon_cge_f32, FWD)
44
DO_FP_CMP0(VCEQ0_F, gen_helper_neon_ceq_f32, FWD)
45
DO_FP_CMP0(VCLE0_F, gen_helper_neon_cge_f32, REV)
46
DO_FP_CMP0(VCLT0_F, gen_helper_neon_cgt_f32, REV)
47
+
48
+static bool do_vrint(DisasContext *s, arg_2misc *a, int rmode)
49
+{
50
+ /*
51
+ * Handle a VRINT* operation by iterating 32 bits at a time,
52
+ * with a specified rounding mode in operation.
53
+ */
54
+ int pass;
55
+ TCGv_ptr fpst;
56
+ TCGv_i32 tcg_rmode;
57
+
58
+ if (!arm_dc_feature(s, ARM_FEATURE_NEON) ||
59
+ !arm_dc_feature(s, ARM_FEATURE_V8)) {
60
+ return false;
61
+ }
62
+
63
+ /* UNDEF accesses to D16-D31 if they don't exist. */
64
+ if (!dc_isar_feature(aa32_simd_r32, s) &&
65
+ ((a->vd | a->vm) & 0x10)) {
66
+ return false;
67
+ }
68
+
69
+ if (a->size != 2) {
70
+ /* TODO: FP16 will be the size == 1 case */
71
+ return false;
72
+ }
73
+
74
+ if ((a->vd | a->vm) & a->q) {
75
+ return false;
76
+ }
77
+
78
+ if (!vfp_access_check(s)) {
79
+ return true;
80
+ }
81
+
82
+ fpst = get_fpstatus_ptr(1);
83
+ tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rmode));
84
+ gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode, cpu_env);
85
+ for (pass = 0; pass < (a->q ? 4 : 2); pass++) {
86
+ TCGv_i32 tmp = neon_load_reg(a->vm, pass);
87
+ gen_helper_rints(tmp, tmp, fpst);
88
+ neon_store_reg(a->vd, pass, tmp);
89
+ }
90
+ gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode, cpu_env);
91
+ tcg_temp_free_i32(tcg_rmode);
92
+ tcg_temp_free_ptr(fpst);
93
+
94
+ return true;
95
+}
96
+
97
+#define DO_VRINT(INSN, RMODE) \
98
+ static bool trans_##INSN(DisasContext *s, arg_2misc *a) \
99
+ { \
100
+ return do_vrint(s, a, RMODE); \
101
+ }
102
+
103
+DO_VRINT(VRINTN, FPROUNDING_TIEEVEN)
104
+DO_VRINT(VRINTA, FPROUNDING_TIEAWAY)
105
+DO_VRINT(VRINTZ, FPROUNDING_ZERO)
106
+DO_VRINT(VRINTM, FPROUNDING_NEGINF)
107
+DO_VRINT(VRINTP, FPROUNDING_POSINF)
24
diff --git a/target/arm/translate.c b/target/arm/translate.c
108
diff --git a/target/arm/translate.c b/target/arm/translate.c
25
index XXXXXXX..XXXXXXX 100644
109
index XXXXXXX..XXXXXXX 100644
26
--- a/target/arm/translate.c
110
--- a/target/arm/translate.c
27
+++ b/target/arm/translate.c
111
+++ b/target/arm/translate.c
28
@@ -XXX,XX +XXX,XX @@ static void disas_thumb_insn(DisasContext *s, uint32_t insn)
112
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
29
gen_nop_hint(s, (insn >> 4) & 0xf);
113
case NEON_2RM_VCEQ0_F:
30
break;
114
case NEON_2RM_VCLE0_F:
31
}
115
case NEON_2RM_VCLT0_F:
32
- /* If Then. */
116
+ case NEON_2RM_VRINTN:
33
+ /*
117
+ case NEON_2RM_VRINTA:
34
+ * IT (If-Then)
118
+ case NEON_2RM_VRINTM:
35
+ *
119
+ case NEON_2RM_VRINTP:
36
+ * Combinations of firstcond and mask which set up an 0b1111
120
+ case NEON_2RM_VRINTZ:
37
+ * condition are UNPREDICTABLE; we take the CONSTRAINED
121
/* handled by decodetree */
38
+ * UNPREDICTABLE choice to treat 0b1111 the same as 0b1110,
122
return 1;
39
+ * i.e. both meaning "execute always".
123
case NEON_2RM_VTRN:
40
+ */
124
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
41
s->condexec_cond = (insn >> 4) & 0xe;
125
}
42
s->condexec_mask = insn & 0x1f;
126
neon_store_reg(rm, pass, tmp2);
43
/* No actual code generated for this insn, just setup state. */
127
break;
44
@@ -XXX,XX +XXX,XX @@ static void thumb_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
128
- case NEON_2RM_VRINTN:
45
if (dc->condexec_mask && !thumb_insn_is_unconditional(dc, insn)) {
129
- case NEON_2RM_VRINTA:
46
uint32_t cond = dc->condexec_cond;
130
- case NEON_2RM_VRINTM:
47
131
- case NEON_2RM_VRINTP:
48
- if (cond != 0x0e) { /* Skip conditional when condition is AL. */
132
- case NEON_2RM_VRINTZ:
49
+ /*
133
- {
50
+ * Conditionally skip the insn. Note that both 0xe and 0xf mean
134
- TCGv_i32 tcg_rmode;
51
+ * "always"; 0xf is not "never".
135
- TCGv_ptr fpstatus = get_fpstatus_ptr(1);
52
+ */
136
- int rmode;
53
+ if (cond < 0x0e) {
137
-
54
arm_skip_unless(dc, cond);
138
- if (op == NEON_2RM_VRINTZ) {
55
}
139
- rmode = FPROUNDING_ZERO;
56
}
140
- } else {
141
- rmode = fp_decode_rm[((op & 0x6) >> 1) ^ 1];
142
- }
143
-
144
- tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rmode));
145
- gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode,
146
- cpu_env);
147
- gen_helper_rints(tmp, tmp, fpstatus);
148
- gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode,
149
- cpu_env);
150
- tcg_temp_free_ptr(fpstatus);
151
- tcg_temp_free_i32(tcg_rmode);
152
- break;
153
- }
154
case NEON_2RM_VCVTAU:
155
case NEON_2RM_VCVTAS:
156
case NEON_2RM_VCVTNU:
57
--
157
--
58
2.20.1
158
2.20.1
59
159
60
160
diff view generated by jsdifflib
1
In v8M, an attempt to return from an exception which is not
1
Convert the VCVT instructions in the 2-reg-misc grouping to
2
active is an illegal exception return. For this purpose,
2
decodetree.
3
exceptions which can configurably target either Secure or
4
NonSecure are not considered to be active if they are
5
configured for the opposite security state for the one
6
we're trying to return from (eg attempt to return from
7
an NS NMI but NMI targets Secure). In the pseudocode this
8
is handled by IsActiveForState().
9
10
Detect this case rather than counting an active exception
11
possibly of the wrong security state as being sufficient.
12
3
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
15
Message-id: 20190617175317.27557-4-peter.maydell@linaro.org
6
Message-id: 20200616170844.13318-19-peter.maydell@linaro.org
16
---
7
---
17
hw/intc/armv7m_nvic.c | 14 +++++++++++++-
8
target/arm/neon-dp.decode | 9 +++++
18
1 file changed, 13 insertions(+), 1 deletion(-)
9
target/arm/translate-neon.inc.c | 70 +++++++++++++++++++++++++++++++++
19
10
target/arm/translate.c | 70 ++++-----------------------------
20
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
11
3 files changed, 87 insertions(+), 62 deletions(-)
12
13
diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode
21
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
22
--- a/hw/intc/armv7m_nvic.c
15
--- a/target/arm/neon-dp.decode
23
+++ b/hw/intc/armv7m_nvic.c
16
+++ b/target/arm/neon-dp.decode
24
@@ -XXX,XX +XXX,XX @@ int armv7m_nvic_complete_irq(void *opaque, int irq, bool secure)
17
@@ -XXX,XX +XXX,XX @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm
25
return -1;
18
26
}
19
VRINTP 1111 001 11 . 11 .. 10 .... 0 1111 . . 0 .... @2misc
27
20
28
- ret = nvic_rettobase(s);
21
+ VCVTAS 1111 001 11 . 11 .. 11 .... 0 0000 . . 0 .... @2misc
22
+ VCVTAU 1111 001 11 . 11 .. 11 .... 0 0001 . . 0 .... @2misc
23
+ VCVTNS 1111 001 11 . 11 .. 11 .... 0 0010 . . 0 .... @2misc
24
+ VCVTNU 1111 001 11 . 11 .. 11 .... 0 0011 . . 0 .... @2misc
25
+ VCVTPS 1111 001 11 . 11 .. 11 .... 0 0100 . . 0 .... @2misc
26
+ VCVTPU 1111 001 11 . 11 .. 11 .... 0 0101 . . 0 .... @2misc
27
+ VCVTMS 1111 001 11 . 11 .. 11 .... 0 0110 . . 0 .... @2misc
28
+ VCVTMU 1111 001 11 . 11 .. 11 .... 0 0111 . . 0 .... @2misc
29
+
30
VRECPE 1111 001 11 . 11 .. 11 .... 0 1000 . . 0 .... @2misc
31
VRSQRTE 1111 001 11 . 11 .. 11 .... 0 1001 . . 0 .... @2misc
32
VRECPE_F 1111 001 11 . 11 .. 11 .... 0 1010 . . 0 .... @2misc
33
diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c
34
index XXXXXXX..XXXXXXX 100644
35
--- a/target/arm/translate-neon.inc.c
36
+++ b/target/arm/translate-neon.inc.c
37
@@ -XXX,XX +XXX,XX @@ DO_VRINT(VRINTA, FPROUNDING_TIEAWAY)
38
DO_VRINT(VRINTZ, FPROUNDING_ZERO)
39
DO_VRINT(VRINTM, FPROUNDING_NEGINF)
40
DO_VRINT(VRINTP, FPROUNDING_POSINF)
41
+
42
+static bool do_vcvt(DisasContext *s, arg_2misc *a, int rmode, bool is_signed)
43
+{
29
+ /*
44
+ /*
30
+ * If this is a configurable exception and it is currently
45
+ * Handle a VCVT* operation by iterating 32 bits at a time,
31
+ * targeting the opposite security state from the one we're trying
46
+ * with a specified rounding mode in operation.
32
+ * to complete it for, this counts as an illegal exception return.
33
+ * We still need to deactivate whatever vector the logic above has
34
+ * selected, though, as it might not be the same as the one for the
35
+ * requested exception number.
36
+ */
47
+ */
37
+ if (!exc_is_banked(irq) && exc_targets_secure(s, irq) != secure) {
48
+ int pass;
38
+ ret = -1;
49
+ TCGv_ptr fpst;
39
+ } else {
50
+ TCGv_i32 tcg_rmode, tcg_shift;
40
+ ret = nvic_rettobase(s);
51
+
41
+ }
52
+ if (!arm_dc_feature(s, ARM_FEATURE_NEON) ||
42
53
+ !arm_dc_feature(s, ARM_FEATURE_V8)) {
43
vec->active = 0;
54
+ return false;
44
if (vec->level) {
55
+ }
56
+
57
+ /* UNDEF accesses to D16-D31 if they don't exist. */
58
+ if (!dc_isar_feature(aa32_simd_r32, s) &&
59
+ ((a->vd | a->vm) & 0x10)) {
60
+ return false;
61
+ }
62
+
63
+ if (a->size != 2) {
64
+ /* TODO: FP16 will be the size == 1 case */
65
+ return false;
66
+ }
67
+
68
+ if ((a->vd | a->vm) & a->q) {
69
+ return false;
70
+ }
71
+
72
+ if (!vfp_access_check(s)) {
73
+ return true;
74
+ }
75
+
76
+ fpst = get_fpstatus_ptr(1);
77
+ tcg_shift = tcg_const_i32(0);
78
+ tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rmode));
79
+ gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode, cpu_env);
80
+ for (pass = 0; pass < (a->q ? 4 : 2); pass++) {
81
+ TCGv_i32 tmp = neon_load_reg(a->vm, pass);
82
+ if (is_signed) {
83
+ gen_helper_vfp_tosls(tmp, tmp, tcg_shift, fpst);
84
+ } else {
85
+ gen_helper_vfp_touls(tmp, tmp, tcg_shift, fpst);
86
+ }
87
+ neon_store_reg(a->vd, pass, tmp);
88
+ }
89
+ gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode, cpu_env);
90
+ tcg_temp_free_i32(tcg_rmode);
91
+ tcg_temp_free_i32(tcg_shift);
92
+ tcg_temp_free_ptr(fpst);
93
+
94
+ return true;
95
+}
96
+
97
+#define DO_VCVT(INSN, RMODE, SIGNED) \
98
+ static bool trans_##INSN(DisasContext *s, arg_2misc *a) \
99
+ { \
100
+ return do_vcvt(s, a, RMODE, SIGNED); \
101
+ }
102
+
103
+DO_VCVT(VCVTAU, FPROUNDING_TIEAWAY, false)
104
+DO_VCVT(VCVTAS, FPROUNDING_TIEAWAY, true)
105
+DO_VCVT(VCVTNU, FPROUNDING_TIEEVEN, false)
106
+DO_VCVT(VCVTNS, FPROUNDING_TIEEVEN, true)
107
+DO_VCVT(VCVTPU, FPROUNDING_POSINF, false)
108
+DO_VCVT(VCVTPS, FPROUNDING_POSINF, true)
109
+DO_VCVT(VCVTMU, FPROUNDING_NEGINF, false)
110
+DO_VCVT(VCVTMS, FPROUNDING_NEGINF, true)
111
diff --git a/target/arm/translate.c b/target/arm/translate.c
112
index XXXXXXX..XXXXXXX 100644
113
--- a/target/arm/translate.c
114
+++ b/target/arm/translate.c
115
@@ -XXX,XX +XXX,XX @@ static void gen_neon_trn_u16(TCGv_i32 t0, TCGv_i32 t1)
116
#define NEON_2RM_VCVT_SF 62
117
#define NEON_2RM_VCVT_UF 63
118
119
-static bool neon_2rm_is_v8_op(int op)
120
-{
121
- /* Return true if this neon 2reg-misc op is ARMv8 and up */
122
- switch (op) {
123
- case NEON_2RM_VRINTN:
124
- case NEON_2RM_VRINTA:
125
- case NEON_2RM_VRINTM:
126
- case NEON_2RM_VRINTP:
127
- case NEON_2RM_VRINTZ:
128
- case NEON_2RM_VRINTX:
129
- case NEON_2RM_VCVTAU:
130
- case NEON_2RM_VCVTAS:
131
- case NEON_2RM_VCVTNU:
132
- case NEON_2RM_VCVTNS:
133
- case NEON_2RM_VCVTPU:
134
- case NEON_2RM_VCVTPS:
135
- case NEON_2RM_VCVTMU:
136
- case NEON_2RM_VCVTMS:
137
- return true;
138
- default:
139
- return false;
140
- }
141
-}
142
-
143
/* Each entry in this array has bit n set if the insn allows
144
* size value n (otherwise it will UNDEF). Since unallocated
145
* op values will have no bits set they always UNDEF.
146
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
147
if ((neon_2rm_sizes[op] & (1 << size)) == 0) {
148
return 1;
149
}
150
- if (neon_2rm_is_v8_op(op) &&
151
- !arm_dc_feature(s, ARM_FEATURE_V8)) {
152
- return 1;
153
- }
154
if (q && ((rm | rd) & 1)) {
155
return 1;
156
}
157
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
158
case NEON_2RM_VRINTM:
159
case NEON_2RM_VRINTP:
160
case NEON_2RM_VRINTZ:
161
+ case NEON_2RM_VCVTAU:
162
+ case NEON_2RM_VCVTAS:
163
+ case NEON_2RM_VCVTNU:
164
+ case NEON_2RM_VCVTNS:
165
+ case NEON_2RM_VCVTPU:
166
+ case NEON_2RM_VCVTPS:
167
+ case NEON_2RM_VCVTMU:
168
+ case NEON_2RM_VCVTMS:
169
/* handled by decodetree */
170
return 1;
171
case NEON_2RM_VTRN:
172
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
173
}
174
neon_store_reg(rm, pass, tmp2);
175
break;
176
- case NEON_2RM_VCVTAU:
177
- case NEON_2RM_VCVTAS:
178
- case NEON_2RM_VCVTNU:
179
- case NEON_2RM_VCVTNS:
180
- case NEON_2RM_VCVTPU:
181
- case NEON_2RM_VCVTPS:
182
- case NEON_2RM_VCVTMU:
183
- case NEON_2RM_VCVTMS:
184
- {
185
- bool is_signed = !extract32(insn, 7, 1);
186
- TCGv_ptr fpst = get_fpstatus_ptr(1);
187
- TCGv_i32 tcg_rmode, tcg_shift;
188
- int rmode = fp_decode_rm[extract32(insn, 8, 2)];
189
-
190
- tcg_shift = tcg_const_i32(0);
191
- tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rmode));
192
- gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode,
193
- cpu_env);
194
-
195
- if (is_signed) {
196
- gen_helper_vfp_tosls(tmp, tmp,
197
- tcg_shift, fpst);
198
- } else {
199
- gen_helper_vfp_touls(tmp, tmp,
200
- tcg_shift, fpst);
201
- }
202
-
203
- gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode,
204
- cpu_env);
205
- tcg_temp_free_i32(tcg_rmode);
206
- tcg_temp_free_i32(tcg_shift);
207
- tcg_temp_free_ptr(fpst);
208
- break;
209
- }
210
default:
211
/* Reserved op values were caught by the
212
* neon_2rm_sizes[] check earlier.
45
--
213
--
46
2.20.1
214
2.20.1
47
215
48
216
diff view generated by jsdifflib
1
To prevent execution priority remaining negative if the guest
1
Convert the Neon VSWP insn to decodetree. Since the new implementation
2
returns from an NMI or HardFault with a corrupted IPSR, the
2
doesn't have to share a pass-loop with the other 2-reg-misc operations
3
v8M interrupt deactivation process forces the HardFault and NMI
3
we can implement the swap with 64-bit accesses rather than 32-bits
4
to inactive based on the current raw execution priority,
4
(which brings us into line with the pseudocode and is more efficient).
5
even if the interrupt the guest is trying to deactivate
6
is something else. In the pseudocode this is done in the
7
Deactivate() function.
8
5
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
11
Message-id: 20190617175317.27557-3-peter.maydell@linaro.org
8
Message-id: 20200616170844.13318-20-peter.maydell@linaro.org
12
---
9
---
13
hw/intc/armv7m_nvic.c | 40 +++++++++++++++++++++++++++++++++++-----
10
target/arm/neon-dp.decode | 2 ++
14
1 file changed, 35 insertions(+), 5 deletions(-)
11
target/arm/translate-neon.inc.c | 41 +++++++++++++++++++++++++++++++++
12
target/arm/translate.c | 5 +---
13
3 files changed, 44 insertions(+), 4 deletions(-)
15
14
16
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
15
diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode
17
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
18
--- a/hw/intc/armv7m_nvic.c
17
--- a/target/arm/neon-dp.decode
19
+++ b/hw/intc/armv7m_nvic.c
18
+++ b/target/arm/neon-dp.decode
20
@@ -XXX,XX +XXX,XX @@ void armv7m_nvic_get_pending_irq_info(void *opaque,
19
@@ -XXX,XX +XXX,XX @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm
21
int armv7m_nvic_complete_irq(void *opaque, int irq, bool secure)
20
VABS_F 1111 001 11 . 11 .. 01 .... 0 1110 . . 0 .... @2misc
22
{
21
VNEG_F 1111 001 11 . 11 .. 01 .... 0 1111 . . 0 .... @2misc
23
NVICState *s = (NVICState *)opaque;
22
24
- VecInfo *vec;
23
+ VSWP 1111 001 11 . 11 .. 10 .... 0 0000 . . 0 .... @2misc
25
+ VecInfo *vec = NULL;
24
+
26
int ret;
25
VUZP 1111 001 11 . 11 .. 10 .... 0 0010 . . 0 .... @2misc
27
26
VZIP 1111 001 11 . 11 .. 10 .... 0 0011 . . 0 .... @2misc
28
assert(irq > ARMV7M_EXCP_RESET && irq < s->num_irq);
27
29
28
diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c
30
- if (secure && exc_is_banked(irq)) {
29
index XXXXXXX..XXXXXXX 100644
31
- vec = &s->sec_vectors[irq];
30
--- a/target/arm/translate-neon.inc.c
32
- } else {
31
+++ b/target/arm/translate-neon.inc.c
33
- vec = &s->vectors[irq];
32
@@ -XXX,XX +XXX,XX @@ DO_VCVT(VCVTPU, FPROUNDING_POSINF, false)
34
+ /*
33
DO_VCVT(VCVTPS, FPROUNDING_POSINF, true)
35
+ * For negative priorities, v8M will forcibly deactivate the appropriate
34
DO_VCVT(VCVTMU, FPROUNDING_NEGINF, false)
36
+ * NMI or HardFault regardless of what interrupt we're being asked to
35
DO_VCVT(VCVTMS, FPROUNDING_NEGINF, true)
37
+ * deactivate (compare the DeActivate() pseudocode). This is a guard
36
+
38
+ * against software returning from NMI or HardFault with a corrupted
37
+static bool trans_VSWP(DisasContext *s, arg_2misc *a)
39
+ * IPSR and leaving the CPU in a negative-priority state.
38
+{
40
+ * v7M does not do this, but simply deactivates the requested interrupt.
39
+ TCGv_i64 rm, rd;
41
+ */
40
+ int pass;
42
+ if (arm_feature(&s->cpu->env, ARM_FEATURE_V8)) {
41
+
43
+ switch (armv7m_nvic_raw_execution_priority(s)) {
42
+ if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
44
+ case -1:
43
+ return false;
45
+ if (s->cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK) {
46
+ vec = &s->vectors[ARMV7M_EXCP_HARD];
47
+ } else {
48
+ vec = &s->sec_vectors[ARMV7M_EXCP_HARD];
49
+ }
50
+ break;
51
+ case -2:
52
+ vec = &s->vectors[ARMV7M_EXCP_NMI];
53
+ break;
54
+ case -3:
55
+ vec = &s->sec_vectors[ARMV7M_EXCP_HARD];
56
+ break;
57
+ default:
58
+ break;
59
+ }
60
+ }
44
+ }
61
+
45
+
62
+ if (!vec) {
46
+ /* UNDEF accesses to D16-D31 if they don't exist. */
63
+ if (secure && exc_is_banked(irq)) {
47
+ if (!dc_isar_feature(aa32_simd_r32, s) &&
64
+ vec = &s->sec_vectors[irq];
48
+ ((a->vd | a->vm) & 0x10)) {
65
+ } else {
49
+ return false;
66
+ vec = &s->vectors[irq];
50
+ }
67
+ }
51
+
68
}
52
+ if (a->size != 0) {
69
53
+ return false;
70
trace_nvic_complete_irq(irq, secure);
54
+ }
55
+
56
+ if ((a->vd | a->vm) & a->q) {
57
+ return false;
58
+ }
59
+
60
+ if (!vfp_access_check(s)) {
61
+ return true;
62
+ }
63
+
64
+ rm = tcg_temp_new_i64();
65
+ rd = tcg_temp_new_i64();
66
+ for (pass = 0; pass < (a->q ? 2 : 1); pass++) {
67
+ neon_load_reg64(rm, a->vm + pass);
68
+ neon_load_reg64(rd, a->vd + pass);
69
+ neon_store_reg64(rm, a->vd + pass);
70
+ neon_store_reg64(rd, a->vm + pass);
71
+ }
72
+ tcg_temp_free_i64(rm);
73
+ tcg_temp_free_i64(rd);
74
+
75
+ return true;
76
+}
77
diff --git a/target/arm/translate.c b/target/arm/translate.c
78
index XXXXXXX..XXXXXXX 100644
79
--- a/target/arm/translate.c
80
+++ b/target/arm/translate.c
81
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
82
case NEON_2RM_VCVTPS:
83
case NEON_2RM_VCVTMU:
84
case NEON_2RM_VCVTMS:
85
+ case NEON_2RM_VSWP:
86
/* handled by decodetree */
87
return 1;
88
case NEON_2RM_VTRN:
89
@@ -XXX,XX +XXX,XX @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
90
for (pass = 0; pass < (q ? 4 : 2); pass++) {
91
tmp = neon_load_reg(rm, pass);
92
switch (op) {
93
- case NEON_2RM_VSWP:
94
- tmp2 = neon_load_reg(rd, pass);
95
- neon_store_reg(rm, pass, tmp2);
96
- break;
97
case NEON_2RM_VTRN:
98
tmp2 = neon_load_reg(rd, pass);
99
switch (size) {
71
--
100
--
72
2.20.1
101
2.20.1
73
102
74
103
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
Convert the Neon VTRN insn to decodetree. This is the last insn in the
2
Neon data-processing group, so we can remove all the now-unused old
3
decoder framework.
2
4
3
These routines are TCG specific.
5
It's possible that there's a more efficient implementation of
6
VTRN, but for this conversion we just copy the existing approach.
4
7
5
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
6
Message-id: 20190701194942.10092-2-philmd@redhat.com
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
Message-id: 20200616170844.13318-21-peter.maydell@linaro.org
9
---
11
---
10
target/arm/Makefile.objs | 2 +-
12
target/arm/neon-dp.decode | 2 +-
11
target/arm/cpu.c | 9 +-
13
target/arm/translate-neon.inc.c | 90 ++++++++
12
target/arm/debug_helper.c | 311 ++++++++++++++++++++++++++++++++++++++
14
target/arm/translate.c | 363 +-------------------------------
13
target/arm/op_helper.c | 295 ------------------------------------
15
3 files changed, 93 insertions(+), 362 deletions(-)
14
4 files changed, 315 insertions(+), 302 deletions(-)
15
create mode 100644 target/arm/debug_helper.c
16
16
17
diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs
17
diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode
18
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
19
--- a/target/arm/Makefile.objs
19
--- a/target/arm/neon-dp.decode
20
+++ b/target/arm/Makefile.objs
20
+++ b/target/arm/neon-dp.decode
21
@@ -XXX,XX +XXX,XX @@ target/arm/translate-sve.o: target/arm/decode-sve.inc.c
21
@@ -XXX,XX +XXX,XX @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm
22
target/arm/translate.o: target/arm/decode-vfp.inc.c
22
VNEG_F 1111 001 11 . 11 .. 01 .... 0 1111 . . 0 .... @2misc
23
target/arm/translate.o: target/arm/decode-vfp-uncond.inc.c
23
24
24
VSWP 1111 001 11 . 11 .. 10 .... 0 0000 . . 0 .... @2misc
25
-obj-y += tlb_helper.o
25
-
26
+obj-y += tlb_helper.o debug_helper.o
26
+ VTRN 1111 001 11 . 11 .. 10 .... 0 0001 . . 0 .... @2misc
27
obj-y += translate.o op_helper.o
27
VUZP 1111 001 11 . 11 .. 10 .... 0 0010 . . 0 .... @2misc
28
obj-y += crypto_helper.o
28
VZIP 1111 001 11 . 11 .. 10 .... 0 0011 . . 0 .... @2misc
29
obj-y += iwmmxt_helper.o vec_helper.o neon_helper.o
29
30
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
30
diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c
31
index XXXXXXX..XXXXXXX 100644
31
index XXXXXXX..XXXXXXX 100644
32
--- a/target/arm/cpu.c
32
--- a/target/arm/translate-neon.inc.c
33
+++ b/target/arm/cpu.c
33
+++ b/target/arm/translate-neon.inc.c
34
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
34
@@ -XXX,XX +XXX,XX @@ static bool trans_VSWP(DisasContext *s, arg_2misc *a)
35
cc->gdb_arch_name = arm_gdb_arch_name;
35
36
cc->gdb_get_dynamic_xml = arm_gdb_get_dynamic_xml;
36
return true;
37
cc->gdb_stop_before_watchpoint = true;
38
- cc->debug_excp_handler = arm_debug_excp_handler;
39
- cc->debug_check_watchpoint = arm_debug_check_watchpoint;
40
-#if !defined(CONFIG_USER_ONLY)
41
- cc->adjust_watchpoint_address = arm_adjust_watchpoint_address;
42
-#endif
43
-
44
cc->disas_set_info = arm_disas_set_info;
45
#ifdef CONFIG_TCG
46
cc->tcg_initialize = arm_translate_init;
47
cc->tlb_fill = arm_cpu_tlb_fill;
48
+ cc->debug_excp_handler = arm_debug_excp_handler;
49
+ cc->debug_check_watchpoint = arm_debug_check_watchpoint;
50
#if !defined(CONFIG_USER_ONLY)
51
cc->do_unaligned_access = arm_cpu_do_unaligned_access;
52
cc->do_transaction_failed = arm_cpu_do_transaction_failed;
53
+ cc->adjust_watchpoint_address = arm_adjust_watchpoint_address;
54
#endif /* CONFIG_TCG && !CONFIG_USER_ONLY */
55
#endif
56
}
37
}
57
diff --git a/target/arm/debug_helper.c b/target/arm/debug_helper.c
38
+static void gen_neon_trn_u8(TCGv_i32 t0, TCGv_i32 t1)
58
new file mode 100644
59
index XXXXXXX..XXXXXXX
60
--- /dev/null
61
+++ b/target/arm/debug_helper.c
62
@@ -XXX,XX +XXX,XX @@
63
+/*
64
+ * ARM debug helpers.
65
+ *
66
+ * This code is licensed under the GNU GPL v2 or later.
67
+ *
68
+ * SPDX-License-Identifier: GPL-2.0-or-later
69
+ */
70
+#include "qemu/osdep.h"
71
+#include "cpu.h"
72
+#include "internals.h"
73
+#include "exec/exec-all.h"
74
+#include "exec/helper-proto.h"
75
+
76
+/* Return true if the linked breakpoint entry lbn passes its checks */
77
+static bool linked_bp_matches(ARMCPU *cpu, int lbn)
78
+{
39
+{
79
+ CPUARMState *env = &cpu->env;
40
+ TCGv_i32 rd, tmp;
80
+ uint64_t bcr = env->cp15.dbgbcr[lbn];
41
+
81
+ int brps = extract32(cpu->dbgdidr, 24, 4);
42
+ rd = tcg_temp_new_i32();
82
+ int ctx_cmps = extract32(cpu->dbgdidr, 20, 4);
43
+ tmp = tcg_temp_new_i32();
83
+ int bt;
44
+
84
+ uint32_t contextidr;
45
+ tcg_gen_shli_i32(rd, t0, 8);
85
+
46
+ tcg_gen_andi_i32(rd, rd, 0xff00ff00);
86
+ /*
47
+ tcg_gen_andi_i32(tmp, t1, 0x00ff00ff);
87
+ * Links to unimplemented or non-context aware breakpoints are
48
+ tcg_gen_or_i32(rd, rd, tmp);
88
+ * CONSTRAINED UNPREDICTABLE: either behave as if disabled, or
49
+
89
+ * as if linked to an UNKNOWN context-aware breakpoint (in which
50
+ tcg_gen_shri_i32(t1, t1, 8);
90
+ * case DBGWCR<n>_EL1.LBN must indicate that breakpoint).
51
+ tcg_gen_andi_i32(t1, t1, 0x00ff00ff);
91
+ * We choose the former.
52
+ tcg_gen_andi_i32(tmp, t0, 0xff00ff00);
92
+ */
53
+ tcg_gen_or_i32(t1, t1, tmp);
93
+ if (lbn > brps || lbn < (brps - ctx_cmps)) {
54
+ tcg_gen_mov_i32(t0, rd);
55
+
56
+ tcg_temp_free_i32(tmp);
57
+ tcg_temp_free_i32(rd);
58
+}
59
+
60
+static void gen_neon_trn_u16(TCGv_i32 t0, TCGv_i32 t1)
61
+{
62
+ TCGv_i32 rd, tmp;
63
+
64
+ rd = tcg_temp_new_i32();
65
+ tmp = tcg_temp_new_i32();
66
+
67
+ tcg_gen_shli_i32(rd, t0, 16);
68
+ tcg_gen_andi_i32(tmp, t1, 0xffff);
69
+ tcg_gen_or_i32(rd, rd, tmp);
70
+ tcg_gen_shri_i32(t1, t1, 16);
71
+ tcg_gen_andi_i32(tmp, t0, 0xffff0000);
72
+ tcg_gen_or_i32(t1, t1, tmp);
73
+ tcg_gen_mov_i32(t0, rd);
74
+
75
+ tcg_temp_free_i32(tmp);
76
+ tcg_temp_free_i32(rd);
77
+}
78
+
79
+static bool trans_VTRN(DisasContext *s, arg_2misc *a)
80
+{
81
+ TCGv_i32 tmp, tmp2;
82
+ int pass;
83
+
84
+ if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
94
+ return false;
85
+ return false;
95
+ }
86
+ }
96
+
87
+
97
+ bcr = env->cp15.dbgbcr[lbn];
88
+ /* UNDEF accesses to D16-D31 if they don't exist. */
98
+
89
+ if (!dc_isar_feature(aa32_simd_r32, s) &&
99
+ if (extract64(bcr, 0, 1) == 0) {
90
+ ((a->vd | a->vm) & 0x10)) {
100
+ /* Linked breakpoint disabled : generate no events */
101
+ return false;
91
+ return false;
102
+ }
92
+ }
103
+
93
+
104
+ bt = extract64(bcr, 20, 4);
94
+ if ((a->vd | a->vm) & a->q) {
105
+
106
+ /*
107
+ * We match the whole register even if this is AArch32 using the
108
+ * short descriptor format (in which case it holds both PROCID and ASID),
109
+ * since we don't implement the optional v7 context ID masking.
110
+ */
111
+ contextidr = extract64(env->cp15.contextidr_el[1], 0, 32);
112
+
113
+ switch (bt) {
114
+ case 3: /* linked context ID match */
115
+ if (arm_current_el(env) > 1) {
116
+ /* Context matches never fire in EL2 or (AArch64) EL3 */
117
+ return false;
118
+ }
119
+ return (contextidr == extract64(env->cp15.dbgbvr[lbn], 0, 32));
120
+ case 5: /* linked address mismatch (reserved in AArch64) */
121
+ case 9: /* linked VMID match (reserved if no EL2) */
122
+ case 11: /* linked context ID and VMID match (reserved if no EL2) */
123
+ default:
124
+ /*
125
+ * Links to Unlinked context breakpoints must generate no
126
+ * events; we choose to do the same for reserved values too.
127
+ */
128
+ return false;
95
+ return false;
129
+ }
96
+ }
130
+
97
+
131
+ return false;
98
+ if (a->size == 3) {
132
+}
99
+ return false;
133
+
100
+ }
134
+static bool bp_wp_matches(ARMCPU *cpu, int n, bool is_wp)
101
+
135
+{
102
+ if (!vfp_access_check(s)) {
136
+ CPUARMState *env = &cpu->env;
103
+ return true;
137
+ uint64_t cr;
104
+ }
138
+ int pac, hmc, ssc, wt, lbn;
105
+
139
+ /*
106
+ if (a->size == 2) {
140
+ * Note that for watchpoints the check is against the CPU security
107
+ for (pass = 0; pass < (a->q ? 4 : 2); pass += 2) {
141
+ * state, not the S/NS attribute on the offending data access.
108
+ tmp = neon_load_reg(a->vm, pass);
142
+ */
109
+ tmp2 = neon_load_reg(a->vd, pass + 1);
143
+ bool is_secure = arm_is_secure(env);
110
+ neon_store_reg(a->vm, pass, tmp2);
144
+ int access_el = arm_current_el(env);
111
+ neon_store_reg(a->vd, pass + 1, tmp);
145
+
146
+ if (is_wp) {
147
+ CPUWatchpoint *wp = env->cpu_watchpoint[n];
148
+
149
+ if (!wp || !(wp->flags & BP_WATCHPOINT_HIT)) {
150
+ return false;
151
+ }
152
+ cr = env->cp15.dbgwcr[n];
153
+ if (wp->hitattrs.user) {
154
+ /*
155
+ * The LDRT/STRT/LDT/STT "unprivileged access" instructions should
156
+ * match watchpoints as if they were accesses done at EL0, even if
157
+ * the CPU is at EL1 or higher.
158
+ */
159
+ access_el = 0;
160
+ }
112
+ }
161
+ } else {
113
+ } else {
162
+ uint64_t pc = is_a64(env) ? env->pc : env->regs[15];
114
+ for (pass = 0; pass < (a->q ? 4 : 2); pass++) {
163
+
115
+ tmp = neon_load_reg(a->vm, pass);
164
+ if (!env->cpu_breakpoint[n] || env->cpu_breakpoint[n]->pc != pc) {
116
+ tmp2 = neon_load_reg(a->vd, pass);
165
+ return false;
117
+ if (a->size == 0) {
118
+ gen_neon_trn_u8(tmp, tmp2);
119
+ } else {
120
+ gen_neon_trn_u16(tmp, tmp2);
121
+ }
122
+ neon_store_reg(a->vm, pass, tmp2);
123
+ neon_store_reg(a->vd, pass, tmp);
166
+ }
124
+ }
167
+ cr = env->cp15.dbgbcr[n];
168
+ }
125
+ }
169
+ /*
170
+ * The WATCHPOINT_HIT flag guarantees us that the watchpoint is
171
+ * enabled and that the address and access type match; for breakpoints
172
+ * we know the address matched; check the remaining fields, including
173
+ * linked breakpoints. We rely on WCR and BCR having the same layout
174
+ * for the LBN, SSC, HMC, PAC/PMC and is-linked fields.
175
+ * Note that some combinations of {PAC, HMC, SSC} are reserved and
176
+ * must act either like some valid combination or as if the watchpoint
177
+ * were disabled. We choose the former, and use this together with
178
+ * the fact that EL3 must always be Secure and EL2 must always be
179
+ * Non-Secure to simplify the code slightly compared to the full
180
+ * table in the ARM ARM.
181
+ */
182
+ pac = extract64(cr, 1, 2);
183
+ hmc = extract64(cr, 13, 1);
184
+ ssc = extract64(cr, 14, 2);
185
+
186
+ switch (ssc) {
187
+ case 0:
188
+ break;
189
+ case 1:
190
+ case 3:
191
+ if (is_secure) {
192
+ return false;
193
+ }
194
+ break;
195
+ case 2:
196
+ if (!is_secure) {
197
+ return false;
198
+ }
199
+ break;
200
+ }
201
+
202
+ switch (access_el) {
203
+ case 3:
204
+ case 2:
205
+ if (!hmc) {
206
+ return false;
207
+ }
208
+ break;
209
+ case 1:
210
+ if (extract32(pac, 0, 1) == 0) {
211
+ return false;
212
+ }
213
+ break;
214
+ case 0:
215
+ if (extract32(pac, 1, 1) == 0) {
216
+ return false;
217
+ }
218
+ break;
219
+ default:
220
+ g_assert_not_reached();
221
+ }
222
+
223
+ wt = extract64(cr, 20, 1);
224
+ lbn = extract64(cr, 16, 4);
225
+
226
+ if (wt && !linked_bp_matches(cpu, lbn)) {
227
+ return false;
228
+ }
229
+
230
+ return true;
126
+ return true;
231
+}
127
+}
232
+
128
diff --git a/target/arm/translate.c b/target/arm/translate.c
233
+static bool check_watchpoints(ARMCPU *cpu)
234
+{
235
+ CPUARMState *env = &cpu->env;
236
+ int n;
237
+
238
+ /*
239
+ * If watchpoints are disabled globally or we can't take debug
240
+ * exceptions here then watchpoint firings are ignored.
241
+ */
242
+ if (extract32(env->cp15.mdscr_el1, 15, 1) == 0
243
+ || !arm_generate_debug_exceptions(env)) {
244
+ return false;
245
+ }
246
+
247
+ for (n = 0; n < ARRAY_SIZE(env->cpu_watchpoint); n++) {
248
+ if (bp_wp_matches(cpu, n, true)) {
249
+ return true;
250
+ }
251
+ }
252
+ return false;
253
+}
254
+
255
+static bool check_breakpoints(ARMCPU *cpu)
256
+{
257
+ CPUARMState *env = &cpu->env;
258
+ int n;
259
+
260
+ /*
261
+ * If breakpoints are disabled globally or we can't take debug
262
+ * exceptions here then breakpoint firings are ignored.
263
+ */
264
+ if (extract32(env->cp15.mdscr_el1, 15, 1) == 0
265
+ || !arm_generate_debug_exceptions(env)) {
266
+ return false;
267
+ }
268
+
269
+ for (n = 0; n < ARRAY_SIZE(env->cpu_breakpoint); n++) {
270
+ if (bp_wp_matches(cpu, n, false)) {
271
+ return true;
272
+ }
273
+ }
274
+ return false;
275
+}
276
+
277
+void HELPER(check_breakpoints)(CPUARMState *env)
278
+{
279
+ ARMCPU *cpu = env_archcpu(env);
280
+
281
+ if (check_breakpoints(cpu)) {
282
+ HELPER(exception_internal(env, EXCP_DEBUG));
283
+ }
284
+}
285
+
286
+bool arm_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp)
287
+{
288
+ /*
289
+ * Called by core code when a CPU watchpoint fires; need to check if this
290
+ * is also an architectural watchpoint match.
291
+ */
292
+ ARMCPU *cpu = ARM_CPU(cs);
293
+
294
+ return check_watchpoints(cpu);
295
+}
296
+
297
+void arm_debug_excp_handler(CPUState *cs)
298
+{
299
+ /*
300
+ * Called by core code when a watchpoint or breakpoint fires;
301
+ * need to check which one and raise the appropriate exception.
302
+ */
303
+ ARMCPU *cpu = ARM_CPU(cs);
304
+ CPUARMState *env = &cpu->env;
305
+ CPUWatchpoint *wp_hit = cs->watchpoint_hit;
306
+
307
+ if (wp_hit) {
308
+ if (wp_hit->flags & BP_CPU) {
309
+ bool wnr = (wp_hit->flags & BP_WATCHPOINT_HIT_WRITE) != 0;
310
+ bool same_el = arm_debug_target_el(env) == arm_current_el(env);
311
+
312
+ cs->watchpoint_hit = NULL;
313
+
314
+ env->exception.fsr = arm_debug_exception_fsr(env);
315
+ env->exception.vaddress = wp_hit->hitaddr;
316
+ raise_exception(env, EXCP_DATA_ABORT,
317
+ syn_watchpoint(same_el, 0, wnr),
318
+ arm_debug_target_el(env));
319
+ }
320
+ } else {
321
+ uint64_t pc = is_a64(env) ? env->pc : env->regs[15];
322
+ bool same_el = (arm_debug_target_el(env) == arm_current_el(env));
323
+
324
+ /*
325
+ * (1) GDB breakpoints should be handled first.
326
+ * (2) Do not raise a CPU exception if no CPU breakpoint has fired,
327
+ * since singlestep is also done by generating a debug internal
328
+ * exception.
329
+ */
330
+ if (cpu_breakpoint_test(cs, pc, BP_GDB)
331
+ || !cpu_breakpoint_test(cs, pc, BP_CPU)) {
332
+ return;
333
+ }
334
+
335
+ env->exception.fsr = arm_debug_exception_fsr(env);
336
+ /*
337
+ * FAR is UNKNOWN: clear vaddress to avoid potentially exposing
338
+ * values to the guest that it shouldn't be able to see at its
339
+ * exception/security level.
340
+ */
341
+ env->exception.vaddress = 0;
342
+ raise_exception(env, EXCP_PREFETCH_ABORT,
343
+ syn_breakpoint(same_el),
344
+ arm_debug_target_el(env));
345
+ }
346
+}
347
+
348
+#if !defined(CONFIG_USER_ONLY)
349
+
350
+vaddr arm_adjust_watchpoint_address(CPUState *cs, vaddr addr, int len)
351
+{
352
+ ARMCPU *cpu = ARM_CPU(cs);
353
+ CPUARMState *env = &cpu->env;
354
+
355
+ /*
356
+ * In BE32 system mode, target memory is stored byteswapped (on a
357
+ * little-endian host system), and by the time we reach here (via an
358
+ * opcode helper) the addresses of subword accesses have been adjusted
359
+ * to account for that, which means that watchpoints will not match.
360
+ * Undo the adjustment here.
361
+ */
362
+ if (arm_sctlr_b(env)) {
363
+ if (len == 1) {
364
+ addr ^= 3;
365
+ } else if (len == 2) {
366
+ addr ^= 2;
367
+ }
368
+ }
369
+
370
+ return addr;
371
+}
372
+
373
+#endif
374
diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c
375
index XXXXXXX..XXXXXXX 100644
129
index XXXXXXX..XXXXXXX 100644
376
--- a/target/arm/op_helper.c
130
--- a/target/arm/translate.c
377
+++ b/target/arm/op_helper.c
131
+++ b/target/arm/translate.c
378
@@ -XXX,XX +XXX,XX @@ void HELPER(pre_smc)(CPUARMState *env, uint32_t syndrome)
132
@@ -XXX,XX +XXX,XX @@ static void gen_exception_return(DisasContext *s, TCGv_i32 pc)
379
}
133
gen_rfe(s, pc, load_cpu_field(spsr));
380
}
134
}
381
135
382
-/* Return true if the linked breakpoint entry lbn passes its checks */
136
-static void gen_neon_trn_u8(TCGv_i32 t0, TCGv_i32 t1)
383
-static bool linked_bp_matches(ARMCPU *cpu, int lbn)
384
-{
137
-{
385
- CPUARMState *env = &cpu->env;
138
- TCGv_i32 rd, tmp;
386
- uint64_t bcr = env->cp15.dbgbcr[lbn];
139
-
387
- int brps = extract32(cpu->dbgdidr, 24, 4);
140
- rd = tcg_temp_new_i32();
388
- int ctx_cmps = extract32(cpu->dbgdidr, 20, 4);
141
- tmp = tcg_temp_new_i32();
389
- int bt;
142
-
390
- uint32_t contextidr;
143
- tcg_gen_shli_i32(rd, t0, 8);
391
-
144
- tcg_gen_andi_i32(rd, rd, 0xff00ff00);
392
- /*
145
- tcg_gen_andi_i32(tmp, t1, 0x00ff00ff);
393
- * Links to unimplemented or non-context aware breakpoints are
146
- tcg_gen_or_i32(rd, rd, tmp);
394
- * CONSTRAINED UNPREDICTABLE: either behave as if disabled, or
147
-
395
- * as if linked to an UNKNOWN context-aware breakpoint (in which
148
- tcg_gen_shri_i32(t1, t1, 8);
396
- * case DBGWCR<n>_EL1.LBN must indicate that breakpoint).
149
- tcg_gen_andi_i32(t1, t1, 0x00ff00ff);
397
- * We choose the former.
150
- tcg_gen_andi_i32(tmp, t0, 0xff00ff00);
151
- tcg_gen_or_i32(t1, t1, tmp);
152
- tcg_gen_mov_i32(t0, rd);
153
-
154
- tcg_temp_free_i32(tmp);
155
- tcg_temp_free_i32(rd);
156
-}
157
-
158
-static void gen_neon_trn_u16(TCGv_i32 t0, TCGv_i32 t1)
159
-{
160
- TCGv_i32 rd, tmp;
161
-
162
- rd = tcg_temp_new_i32();
163
- tmp = tcg_temp_new_i32();
164
-
165
- tcg_gen_shli_i32(rd, t0, 16);
166
- tcg_gen_andi_i32(tmp, t1, 0xffff);
167
- tcg_gen_or_i32(rd, rd, tmp);
168
- tcg_gen_shri_i32(t1, t1, 16);
169
- tcg_gen_andi_i32(tmp, t0, 0xffff0000);
170
- tcg_gen_or_i32(t1, t1, tmp);
171
- tcg_gen_mov_i32(t0, rd);
172
-
173
- tcg_temp_free_i32(tmp);
174
- tcg_temp_free_i32(rd);
175
-}
176
-
177
-/* Symbolic constants for op fields for Neon 2-register miscellaneous.
178
- * The values correspond to bits [17:16,10:7]; see the ARM ARM DDI0406B
179
- * table A7-13.
180
- */
181
-#define NEON_2RM_VREV64 0
182
-#define NEON_2RM_VREV32 1
183
-#define NEON_2RM_VREV16 2
184
-#define NEON_2RM_VPADDL 4
185
-#define NEON_2RM_VPADDL_U 5
186
-#define NEON_2RM_AESE 6 /* Includes AESD */
187
-#define NEON_2RM_AESMC 7 /* Includes AESIMC */
188
-#define NEON_2RM_VCLS 8
189
-#define NEON_2RM_VCLZ 9
190
-#define NEON_2RM_VCNT 10
191
-#define NEON_2RM_VMVN 11
192
-#define NEON_2RM_VPADAL 12
193
-#define NEON_2RM_VPADAL_U 13
194
-#define NEON_2RM_VQABS 14
195
-#define NEON_2RM_VQNEG 15
196
-#define NEON_2RM_VCGT0 16
197
-#define NEON_2RM_VCGE0 17
198
-#define NEON_2RM_VCEQ0 18
199
-#define NEON_2RM_VCLE0 19
200
-#define NEON_2RM_VCLT0 20
201
-#define NEON_2RM_SHA1H 21
202
-#define NEON_2RM_VABS 22
203
-#define NEON_2RM_VNEG 23
204
-#define NEON_2RM_VCGT0_F 24
205
-#define NEON_2RM_VCGE0_F 25
206
-#define NEON_2RM_VCEQ0_F 26
207
-#define NEON_2RM_VCLE0_F 27
208
-#define NEON_2RM_VCLT0_F 28
209
-#define NEON_2RM_VABS_F 30
210
-#define NEON_2RM_VNEG_F 31
211
-#define NEON_2RM_VSWP 32
212
-#define NEON_2RM_VTRN 33
213
-#define NEON_2RM_VUZP 34
214
-#define NEON_2RM_VZIP 35
215
-#define NEON_2RM_VMOVN 36 /* Includes VQMOVN, VQMOVUN */
216
-#define NEON_2RM_VQMOVN 37 /* Includes VQMOVUN */
217
-#define NEON_2RM_VSHLL 38
218
-#define NEON_2RM_SHA1SU1 39 /* Includes SHA256SU0 */
219
-#define NEON_2RM_VRINTN 40
220
-#define NEON_2RM_VRINTX 41
221
-#define NEON_2RM_VRINTA 42
222
-#define NEON_2RM_VRINTZ 43
223
-#define NEON_2RM_VCVT_F16_F32 44
224
-#define NEON_2RM_VRINTM 45
225
-#define NEON_2RM_VCVT_F32_F16 46
226
-#define NEON_2RM_VRINTP 47
227
-#define NEON_2RM_VCVTAU 48
228
-#define NEON_2RM_VCVTAS 49
229
-#define NEON_2RM_VCVTNU 50
230
-#define NEON_2RM_VCVTNS 51
231
-#define NEON_2RM_VCVTPU 52
232
-#define NEON_2RM_VCVTPS 53
233
-#define NEON_2RM_VCVTMU 54
234
-#define NEON_2RM_VCVTMS 55
235
-#define NEON_2RM_VRECPE 56
236
-#define NEON_2RM_VRSQRTE 57
237
-#define NEON_2RM_VRECPE_F 58
238
-#define NEON_2RM_VRSQRTE_F 59
239
-#define NEON_2RM_VCVT_FS 60
240
-#define NEON_2RM_VCVT_FU 61
241
-#define NEON_2RM_VCVT_SF 62
242
-#define NEON_2RM_VCVT_UF 63
243
-
244
-/* Each entry in this array has bit n set if the insn allows
245
- * size value n (otherwise it will UNDEF). Since unallocated
246
- * op values will have no bits set they always UNDEF.
247
- */
248
-static const uint8_t neon_2rm_sizes[] = {
249
- [NEON_2RM_VREV64] = 0x7,
250
- [NEON_2RM_VREV32] = 0x3,
251
- [NEON_2RM_VREV16] = 0x1,
252
- [NEON_2RM_VPADDL] = 0x7,
253
- [NEON_2RM_VPADDL_U] = 0x7,
254
- [NEON_2RM_AESE] = 0x1,
255
- [NEON_2RM_AESMC] = 0x1,
256
- [NEON_2RM_VCLS] = 0x7,
257
- [NEON_2RM_VCLZ] = 0x7,
258
- [NEON_2RM_VCNT] = 0x1,
259
- [NEON_2RM_VMVN] = 0x1,
260
- [NEON_2RM_VPADAL] = 0x7,
261
- [NEON_2RM_VPADAL_U] = 0x7,
262
- [NEON_2RM_VQABS] = 0x7,
263
- [NEON_2RM_VQNEG] = 0x7,
264
- [NEON_2RM_VCGT0] = 0x7,
265
- [NEON_2RM_VCGE0] = 0x7,
266
- [NEON_2RM_VCEQ0] = 0x7,
267
- [NEON_2RM_VCLE0] = 0x7,
268
- [NEON_2RM_VCLT0] = 0x7,
269
- [NEON_2RM_SHA1H] = 0x4,
270
- [NEON_2RM_VABS] = 0x7,
271
- [NEON_2RM_VNEG] = 0x7,
272
- [NEON_2RM_VCGT0_F] = 0x4,
273
- [NEON_2RM_VCGE0_F] = 0x4,
274
- [NEON_2RM_VCEQ0_F] = 0x4,
275
- [NEON_2RM_VCLE0_F] = 0x4,
276
- [NEON_2RM_VCLT0_F] = 0x4,
277
- [NEON_2RM_VABS_F] = 0x4,
278
- [NEON_2RM_VNEG_F] = 0x4,
279
- [NEON_2RM_VSWP] = 0x1,
280
- [NEON_2RM_VTRN] = 0x7,
281
- [NEON_2RM_VUZP] = 0x7,
282
- [NEON_2RM_VZIP] = 0x7,
283
- [NEON_2RM_VMOVN] = 0x7,
284
- [NEON_2RM_VQMOVN] = 0x7,
285
- [NEON_2RM_VSHLL] = 0x7,
286
- [NEON_2RM_SHA1SU1] = 0x4,
287
- [NEON_2RM_VRINTN] = 0x4,
288
- [NEON_2RM_VRINTX] = 0x4,
289
- [NEON_2RM_VRINTA] = 0x4,
290
- [NEON_2RM_VRINTZ] = 0x4,
291
- [NEON_2RM_VCVT_F16_F32] = 0x2,
292
- [NEON_2RM_VRINTM] = 0x4,
293
- [NEON_2RM_VCVT_F32_F16] = 0x2,
294
- [NEON_2RM_VRINTP] = 0x4,
295
- [NEON_2RM_VCVTAU] = 0x4,
296
- [NEON_2RM_VCVTAS] = 0x4,
297
- [NEON_2RM_VCVTNU] = 0x4,
298
- [NEON_2RM_VCVTNS] = 0x4,
299
- [NEON_2RM_VCVTPU] = 0x4,
300
- [NEON_2RM_VCVTPS] = 0x4,
301
- [NEON_2RM_VCVTMU] = 0x4,
302
- [NEON_2RM_VCVTMS] = 0x4,
303
- [NEON_2RM_VRECPE] = 0x4,
304
- [NEON_2RM_VRSQRTE] = 0x4,
305
- [NEON_2RM_VRECPE_F] = 0x4,
306
- [NEON_2RM_VRSQRTE_F] = 0x4,
307
- [NEON_2RM_VCVT_FS] = 0x4,
308
- [NEON_2RM_VCVT_FU] = 0x4,
309
- [NEON_2RM_VCVT_SF] = 0x4,
310
- [NEON_2RM_VCVT_UF] = 0x4,
311
-};
312
-
313
static void gen_gvec_fn3_qc(uint32_t rd_ofs, uint32_t rn_ofs, uint32_t rm_ofs,
314
uint32_t opr_sz, uint32_t max_sz,
315
gen_helper_gvec_3_ptr *fn)
316
@@ -XXX,XX +XXX,XX @@ void gen_gvec_uaba(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
317
tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, &ops[vece]);
318
}
319
320
-/* Translate a NEON data processing instruction. Return nonzero if the
321
- instruction is invalid.
322
- We process data in a mixture of 32-bit and 64-bit chunks.
323
- Mostly we use 32-bit chunks so we can use normal scalar instructions. */
324
-
325
-static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
326
-{
327
- int op;
328
- int q;
329
- int rd, rm;
330
- int size;
331
- int pass;
332
- int u;
333
- TCGv_i32 tmp, tmp2;
334
-
335
- if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
336
- return 1;
337
- }
338
-
339
- /* FIXME: this access check should not take precedence over UNDEF
340
- * for invalid encodings; we will generate incorrect syndrome information
341
- * for attempts to execute invalid vfp/neon encodings with FP disabled.
398
- */
342
- */
399
- if (lbn > brps || lbn < (brps - ctx_cmps)) {
343
- if (s->fp_excp_el) {
400
- return false;
344
- gen_exception_insn(s, s->pc_curr, EXCP_UDEF,
345
- syn_simd_access_trap(1, 0xe, false), s->fp_excp_el);
346
- return 0;
401
- }
347
- }
402
-
348
-
403
- bcr = env->cp15.dbgbcr[lbn];
349
- if (!s->vfp_enabled)
404
-
350
- return 1;
405
- if (extract64(bcr, 0, 1) == 0) {
351
- q = (insn & (1 << 6)) != 0;
406
- /* Linked breakpoint disabled : generate no events */
352
- u = (insn >> 24) & 1;
407
- return false;
353
- VFP_DREG_D(rd, insn);
408
- }
354
- VFP_DREG_M(rm, insn);
409
-
355
- size = (insn >> 20) & 3;
410
- bt = extract64(bcr, 20, 4);
356
-
411
-
357
- if ((insn & (1 << 23)) == 0) {
412
- /*
358
- /* Three register same length: handled by decodetree */
413
- * We match the whole register even if this is AArch32 using the
359
- return 1;
414
- * short descriptor format (in which case it holds both PROCID and ASID),
360
- } else if (insn & (1 << 4)) {
415
- * since we don't implement the optional v7 context ID masking.
361
- /* Two registers and shift or reg and imm: handled by decodetree */
416
- */
362
- return 1;
417
- contextidr = extract64(env->cp15.contextidr_el[1], 0, 32);
363
- } else { /* (insn & 0x00800010 == 0x00800000) */
418
-
364
- if (size != 3) {
419
- switch (bt) {
420
- case 3: /* linked context ID match */
421
- if (arm_current_el(env) > 1) {
422
- /* Context matches never fire in EL2 or (AArch64) EL3 */
423
- return false;
424
- }
425
- return (contextidr == extract64(env->cp15.dbgbvr[lbn], 0, 32));
426
- case 5: /* linked address mismatch (reserved in AArch64) */
427
- case 9: /* linked VMID match (reserved if no EL2) */
428
- case 11: /* linked context ID and VMID match (reserved if no EL2) */
429
- default:
430
- /*
431
- * Links to Unlinked context breakpoints must generate no
432
- * events; we choose to do the same for reserved values too.
433
- */
434
- return false;
435
- }
436
-
437
- return false;
438
-}
439
-
440
-static bool bp_wp_matches(ARMCPU *cpu, int n, bool is_wp)
441
-{
442
- CPUARMState *env = &cpu->env;
443
- uint64_t cr;
444
- int pac, hmc, ssc, wt, lbn;
445
- /*
446
- * Note that for watchpoints the check is against the CPU security
447
- * state, not the S/NS attribute on the offending data access.
448
- */
449
- bool is_secure = arm_is_secure(env);
450
- int access_el = arm_current_el(env);
451
-
452
- if (is_wp) {
453
- CPUWatchpoint *wp = env->cpu_watchpoint[n];
454
-
455
- if (!wp || !(wp->flags & BP_WATCHPOINT_HIT)) {
456
- return false;
457
- }
458
- cr = env->cp15.dbgwcr[n];
459
- if (wp->hitattrs.user) {
460
- /*
365
- /*
461
- * The LDRT/STRT/LDT/STT "unprivileged access" instructions should
366
- * Three registers of different lengths, or two registers and
462
- * match watchpoints as if they were accesses done at EL0, even if
367
- * a scalar: handled by decodetree
463
- * the CPU is at EL1 or higher.
464
- */
368
- */
465
- access_el = 0;
369
- return 1;
466
- }
370
- } else { /* size == 3 */
467
- } else {
371
- if (!u) {
468
- uint64_t pc = is_a64(env) ? env->pc : env->regs[15];
372
- /* Extract: handled by decodetree */
469
-
373
- return 1;
470
- if (!env->cpu_breakpoint[n] || env->cpu_breakpoint[n]->pc != pc) {
374
- } else if ((insn & (1 << 11)) == 0) {
471
- return false;
375
- /* Two register misc. */
472
- }
376
- op = ((insn >> 12) & 0x30) | ((insn >> 7) & 0xf);
473
- cr = env->cp15.dbgbcr[n];
377
- size = (insn >> 18) & 3;
474
- }
378
- /* UNDEF for unknown op values and bad op-size combinations */
475
- /*
379
- if ((neon_2rm_sizes[op] & (1 << size)) == 0) {
476
- * The WATCHPOINT_HIT flag guarantees us that the watchpoint is
380
- return 1;
477
- * enabled and that the address and access type match; for breakpoints
381
- }
478
- * we know the address matched; check the remaining fields, including
382
- if (q && ((rm | rd) & 1)) {
479
- * linked breakpoints. We rely on WCR and BCR having the same layout
383
- return 1;
480
- * for the LBN, SSC, HMC, PAC/PMC and is-linked fields.
384
- }
481
- * Note that some combinations of {PAC, HMC, SSC} are reserved and
385
- switch (op) {
482
- * must act either like some valid combination or as if the watchpoint
386
- case NEON_2RM_VREV64:
483
- * were disabled. We choose the former, and use this together with
387
- case NEON_2RM_VPADDL: case NEON_2RM_VPADDL_U:
484
- * the fact that EL3 must always be Secure and EL2 must always be
388
- case NEON_2RM_VPADAL: case NEON_2RM_VPADAL_U:
485
- * Non-Secure to simplify the code slightly compared to the full
389
- case NEON_2RM_VUZP:
486
- * table in the ARM ARM.
390
- case NEON_2RM_VZIP:
487
- */
391
- case NEON_2RM_VMOVN: case NEON_2RM_VQMOVN:
488
- pac = extract64(cr, 1, 2);
392
- case NEON_2RM_VSHLL:
489
- hmc = extract64(cr, 13, 1);
393
- case NEON_2RM_VCVT_F16_F32:
490
- ssc = extract64(cr, 14, 2);
394
- case NEON_2RM_VCVT_F32_F16:
491
-
395
- case NEON_2RM_VMVN:
492
- switch (ssc) {
396
- case NEON_2RM_VNEG:
493
- case 0:
397
- case NEON_2RM_VABS:
494
- break;
398
- case NEON_2RM_VCEQ0:
495
- case 1:
399
- case NEON_2RM_VCGT0:
496
- case 3:
400
- case NEON_2RM_VCLE0:
497
- if (is_secure) {
401
- case NEON_2RM_VCGE0:
498
- return false;
402
- case NEON_2RM_VCLT0:
499
- }
403
- case NEON_2RM_AESE: case NEON_2RM_AESMC:
500
- break;
404
- case NEON_2RM_SHA1H:
501
- case 2:
405
- case NEON_2RM_SHA1SU1:
502
- if (!is_secure) {
406
- case NEON_2RM_VREV32:
503
- return false;
407
- case NEON_2RM_VREV16:
504
- }
408
- case NEON_2RM_VCLS:
505
- break;
409
- case NEON_2RM_VCLZ:
506
- }
410
- case NEON_2RM_VCNT:
507
-
411
- case NEON_2RM_VABS_F:
508
- switch (access_el) {
412
- case NEON_2RM_VNEG_F:
509
- case 3:
413
- case NEON_2RM_VRECPE:
510
- case 2:
414
- case NEON_2RM_VRSQRTE:
511
- if (!hmc) {
415
- case NEON_2RM_VQABS:
512
- return false;
416
- case NEON_2RM_VQNEG:
513
- }
417
- case NEON_2RM_VRECPE_F:
514
- break;
418
- case NEON_2RM_VRSQRTE_F:
515
- case 1:
419
- case NEON_2RM_VCVT_FS:
516
- if (extract32(pac, 0, 1) == 0) {
420
- case NEON_2RM_VCVT_FU:
517
- return false;
421
- case NEON_2RM_VCVT_SF:
518
- }
422
- case NEON_2RM_VCVT_UF:
519
- break;
423
- case NEON_2RM_VRINTX:
520
- case 0:
424
- case NEON_2RM_VCGT0_F:
521
- if (extract32(pac, 1, 1) == 0) {
425
- case NEON_2RM_VCGE0_F:
522
- return false;
426
- case NEON_2RM_VCEQ0_F:
523
- }
427
- case NEON_2RM_VCLE0_F:
524
- break;
428
- case NEON_2RM_VCLT0_F:
525
- default:
429
- case NEON_2RM_VRINTN:
526
- g_assert_not_reached();
430
- case NEON_2RM_VRINTA:
527
- }
431
- case NEON_2RM_VRINTM:
528
-
432
- case NEON_2RM_VRINTP:
529
- wt = extract64(cr, 20, 1);
433
- case NEON_2RM_VRINTZ:
530
- lbn = extract64(cr, 16, 4);
434
- case NEON_2RM_VCVTAU:
531
-
435
- case NEON_2RM_VCVTAS:
532
- if (wt && !linked_bp_matches(cpu, lbn)) {
436
- case NEON_2RM_VCVTNU:
533
- return false;
437
- case NEON_2RM_VCVTNS:
534
- }
438
- case NEON_2RM_VCVTPU:
535
-
439
- case NEON_2RM_VCVTPS:
536
- return true;
440
- case NEON_2RM_VCVTMU:
537
-}
441
- case NEON_2RM_VCVTMS:
538
-
442
- case NEON_2RM_VSWP:
539
-static bool check_watchpoints(ARMCPU *cpu)
443
- /* handled by decodetree */
540
-{
444
- return 1;
541
- CPUARMState *env = &cpu->env;
445
- case NEON_2RM_VTRN:
542
- int n;
446
- if (size == 2) {
543
-
447
- int n;
544
- /*
448
- for (n = 0; n < (q ? 4 : 2); n += 2) {
545
- * If watchpoints are disabled globally or we can't take debug
449
- tmp = neon_load_reg(rm, n);
546
- * exceptions here then watchpoint firings are ignored.
450
- tmp2 = neon_load_reg(rd, n + 1);
547
- */
451
- neon_store_reg(rm, n, tmp2);
548
- if (extract32(env->cp15.mdscr_el1, 15, 1) == 0
452
- neon_store_reg(rd, n + 1, tmp);
549
- || !arm_generate_debug_exceptions(env)) {
453
- }
550
- return false;
454
- } else {
551
- }
455
- goto elementwise;
552
-
456
- }
553
- for (n = 0; n < ARRAY_SIZE(env->cpu_watchpoint); n++) {
457
- break;
554
- if (bp_wp_matches(cpu, n, true)) {
458
-
555
- return true;
459
- default:
460
- elementwise:
461
- for (pass = 0; pass < (q ? 4 : 2); pass++) {
462
- tmp = neon_load_reg(rm, pass);
463
- switch (op) {
464
- case NEON_2RM_VTRN:
465
- tmp2 = neon_load_reg(rd, pass);
466
- switch (size) {
467
- case 0: gen_neon_trn_u8(tmp, tmp2); break;
468
- case 1: gen_neon_trn_u16(tmp, tmp2); break;
469
- default: abort();
470
- }
471
- neon_store_reg(rm, pass, tmp2);
472
- break;
473
- default:
474
- /* Reserved op values were caught by the
475
- * neon_2rm_sizes[] check earlier.
476
- */
477
- abort();
478
- }
479
- neon_store_reg(rd, pass, tmp);
480
- }
481
- break;
482
- }
483
- } else {
484
- /* VTBL, VTBX, VDUP: handled by decodetree */
485
- return 1;
486
- }
556
- }
487
- }
557
- }
488
- }
558
- return false;
489
- return 0;
559
-}
490
-}
560
-
491
-
561
-static bool check_breakpoints(ARMCPU *cpu)
492
static int disas_coproc_insn(DisasContext *s, uint32_t insn)
562
-{
493
{
563
- CPUARMState *env = &cpu->env;
494
int cpnum, is64, crn, crm, opc1, opc2, isread, rt, rt2;
564
- int n;
495
@@ -XXX,XX +XXX,XX @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
565
-
496
}
566
- /*
497
/* fall back to legacy decoder */
567
- * If breakpoints are disabled globally or we can't take debug
498
568
- * exceptions here then breakpoint firings are ignored.
499
- if (((insn >> 25) & 7) == 1) {
569
- */
500
- /* NEON Data processing. */
570
- if (extract32(env->cp15.mdscr_el1, 15, 1) == 0
501
- if (disas_neon_data_insn(s, insn)) {
571
- || !arm_generate_debug_exceptions(env)) {
502
- goto illegal_op;
572
- return false;
503
- }
573
- }
574
-
575
- for (n = 0; n < ARRAY_SIZE(env->cpu_breakpoint); n++) {
576
- if (bp_wp_matches(cpu, n, false)) {
577
- return true;
578
- }
579
- }
580
- return false;
581
-}
582
-
583
-void HELPER(check_breakpoints)(CPUARMState *env)
584
-{
585
- ARMCPU *cpu = env_archcpu(env);
586
-
587
- if (check_breakpoints(cpu)) {
588
- HELPER(exception_internal(env, EXCP_DEBUG));
589
- }
590
-}
591
-
592
-bool arm_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp)
593
-{
594
- /*
595
- * Called by core code when a CPU watchpoint fires; need to check if this
596
- * is also an architectural watchpoint match.
597
- */
598
- ARMCPU *cpu = ARM_CPU(cs);
599
-
600
- return check_watchpoints(cpu);
601
-}
602
-
603
-vaddr arm_adjust_watchpoint_address(CPUState *cs, vaddr addr, int len)
604
-{
605
- ARMCPU *cpu = ARM_CPU(cs);
606
- CPUARMState *env = &cpu->env;
607
-
608
- /*
609
- * In BE32 system mode, target memory is stored byteswapped (on a
610
- * little-endian host system), and by the time we reach here (via an
611
- * opcode helper) the addresses of subword accesses have been adjusted
612
- * to account for that, which means that watchpoints will not match.
613
- * Undo the adjustment here.
614
- */
615
- if (arm_sctlr_b(env)) {
616
- if (len == 1) {
617
- addr ^= 3;
618
- } else if (len == 2) {
619
- addr ^= 2;
620
- }
621
- }
622
-
623
- return addr;
624
-}
625
-
626
-void arm_debug_excp_handler(CPUState *cs)
627
-{
628
- /*
629
- * Called by core code when a watchpoint or breakpoint fires;
630
- * need to check which one and raise the appropriate exception.
631
- */
632
- ARMCPU *cpu = ARM_CPU(cs);
633
- CPUARMState *env = &cpu->env;
634
- CPUWatchpoint *wp_hit = cs->watchpoint_hit;
635
-
636
- if (wp_hit) {
637
- if (wp_hit->flags & BP_CPU) {
638
- bool wnr = (wp_hit->flags & BP_WATCHPOINT_HIT_WRITE) != 0;
639
- bool same_el = arm_debug_target_el(env) == arm_current_el(env);
640
-
641
- cs->watchpoint_hit = NULL;
642
-
643
- env->exception.fsr = arm_debug_exception_fsr(env);
644
- env->exception.vaddress = wp_hit->hitaddr;
645
- raise_exception(env, EXCP_DATA_ABORT,
646
- syn_watchpoint(same_el, 0, wnr),
647
- arm_debug_target_el(env));
648
- }
649
- } else {
650
- uint64_t pc = is_a64(env) ? env->pc : env->regs[15];
651
- bool same_el = (arm_debug_target_el(env) == arm_current_el(env));
652
-
653
- /*
654
- * (1) GDB breakpoints should be handled first.
655
- * (2) Do not raise a CPU exception if no CPU breakpoint has fired,
656
- * since singlestep is also done by generating a debug internal
657
- * exception.
658
- */
659
- if (cpu_breakpoint_test(cs, pc, BP_GDB)
660
- || !cpu_breakpoint_test(cs, pc, BP_CPU)) {
661
- return;
504
- return;
662
- }
505
- }
663
-
506
if ((insn & 0x0e000f00) == 0x0c000100) {
664
- env->exception.fsr = arm_debug_exception_fsr(env);
507
if (arm_dc_feature(s, ARM_FEATURE_IWMMXT)) {
665
- /*
508
/* iWMMXt register transfer. */
666
- * FAR is UNKNOWN: clear vaddress to avoid potentially exposing
509
@@ -XXX,XX +XXX,XX @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
667
- * values to the guest that it shouldn't be able to see at its
510
break;
668
- * exception/security level.
511
}
669
- */
512
if (((insn >> 24) & 3) == 3) {
670
- env->exception.vaddress = 0;
513
- /* Translate into the equivalent ARM encoding. */
671
- raise_exception(env, EXCP_PREFETCH_ABORT,
514
- insn = (insn & 0xe2ffffff) | ((insn & (1 << 28)) >> 4) | (1 << 28);
672
- syn_breakpoint(same_el),
515
- if (disas_neon_data_insn(s, insn)) {
673
- arm_debug_target_el(env));
516
- goto illegal_op;
674
- }
517
- }
675
-}
518
+ /* Neon DP, but failed disas_neon_dp() */
676
-
519
+ goto illegal_op;
677
/* ??? Flag setting arithmetic is awkward because we need to do comparisons.
520
} else if (((insn >> 8) & 0xe) == 10) {
678
The only way to do that in TCG is a conditional branch, which clobbers
521
/* VFP, but failed disas_vfp. */
679
all our temporaries. For now implement these as helper functions. */
522
goto illegal_op;
680
--
523
--
681
2.20.1
524
2.20.1
682
525
683
526
diff view generated by jsdifflib
1
Like most of the v7M memory mapped system registers, the systick
1
The functions neon_element_offset(), neon_load_element(),
2
registers are accessible to privileged code only and user accesses
2
neon_load_element64(), neon_store_element() and
3
must generate a BusFault. We implement that for registers in
3
neon_store_element64() are used only in the translate-neon.inc.c
4
the NVIC proper already, but missed it for systick since we
4
file, so move their definitions there.
5
implement it as a separate device. Correct the omission.
5
6
Since the .inc.c file is #included in translate.c this doesn't make
7
much difference currently, but it's a more logical place to put the
8
functions and it might be helpful if we ever decide to try to make
9
the .inc.c files genuinely separate compilation units.
6
10
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
12
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
9
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
13
Message-id: 20200616170844.13318-22-peter.maydell@linaro.org
10
Message-id: 20190617175317.27557-6-peter.maydell@linaro.org
11
---
14
---
12
hw/timer/armv7m_systick.c | 26 ++++++++++++++++++++------
15
target/arm/translate-neon.inc.c | 101 ++++++++++++++++++++++++++++++++
13
1 file changed, 20 insertions(+), 6 deletions(-)
16
target/arm/translate.c | 101 --------------------------------
14
17
2 files changed, 101 insertions(+), 101 deletions(-)
15
diff --git a/hw/timer/armv7m_systick.c b/hw/timer/armv7m_systick.c
18
19
diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c
16
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
17
--- a/hw/timer/armv7m_systick.c
21
--- a/target/arm/translate-neon.inc.c
18
+++ b/hw/timer/armv7m_systick.c
22
+++ b/target/arm/translate-neon.inc.c
19
@@ -XXX,XX +XXX,XX @@ static void systick_timer_tick(void *opaque)
23
@@ -XXX,XX +XXX,XX @@ static inline int rsub_8(DisasContext *s, int x)
20
}
24
#include "decode-neon-ls.inc.c"
25
#include "decode-neon-shared.inc.c"
26
27
+/* Return the offset of a 2**SIZE piece of a NEON register, at index ELE,
28
+ * where 0 is the least significant end of the register.
29
+ */
30
+static inline long
31
+neon_element_offset(int reg, int element, MemOp size)
32
+{
33
+ int element_size = 1 << size;
34
+ int ofs = element * element_size;
35
+#ifdef HOST_WORDS_BIGENDIAN
36
+ /* Calculate the offset assuming fully little-endian,
37
+ * then XOR to account for the order of the 8-byte units.
38
+ */
39
+ if (element_size < 8) {
40
+ ofs ^= 8 - element_size;
41
+ }
42
+#endif
43
+ return neon_reg_offset(reg, 0) + ofs;
44
+}
45
+
46
+static void neon_load_element(TCGv_i32 var, int reg, int ele, MemOp mop)
47
+{
48
+ long offset = neon_element_offset(reg, ele, mop & MO_SIZE);
49
+
50
+ switch (mop) {
51
+ case MO_UB:
52
+ tcg_gen_ld8u_i32(var, cpu_env, offset);
53
+ break;
54
+ case MO_UW:
55
+ tcg_gen_ld16u_i32(var, cpu_env, offset);
56
+ break;
57
+ case MO_UL:
58
+ tcg_gen_ld_i32(var, cpu_env, offset);
59
+ break;
60
+ default:
61
+ g_assert_not_reached();
62
+ }
63
+}
64
+
65
+static void neon_load_element64(TCGv_i64 var, int reg, int ele, MemOp mop)
66
+{
67
+ long offset = neon_element_offset(reg, ele, mop & MO_SIZE);
68
+
69
+ switch (mop) {
70
+ case MO_UB:
71
+ tcg_gen_ld8u_i64(var, cpu_env, offset);
72
+ break;
73
+ case MO_UW:
74
+ tcg_gen_ld16u_i64(var, cpu_env, offset);
75
+ break;
76
+ case MO_UL:
77
+ tcg_gen_ld32u_i64(var, cpu_env, offset);
78
+ break;
79
+ case MO_Q:
80
+ tcg_gen_ld_i64(var, cpu_env, offset);
81
+ break;
82
+ default:
83
+ g_assert_not_reached();
84
+ }
85
+}
86
+
87
+static void neon_store_element(int reg, int ele, MemOp size, TCGv_i32 var)
88
+{
89
+ long offset = neon_element_offset(reg, ele, size);
90
+
91
+ switch (size) {
92
+ case MO_8:
93
+ tcg_gen_st8_i32(var, cpu_env, offset);
94
+ break;
95
+ case MO_16:
96
+ tcg_gen_st16_i32(var, cpu_env, offset);
97
+ break;
98
+ case MO_32:
99
+ tcg_gen_st_i32(var, cpu_env, offset);
100
+ break;
101
+ default:
102
+ g_assert_not_reached();
103
+ }
104
+}
105
+
106
+static void neon_store_element64(int reg, int ele, MemOp size, TCGv_i64 var)
107
+{
108
+ long offset = neon_element_offset(reg, ele, size);
109
+
110
+ switch (size) {
111
+ case MO_8:
112
+ tcg_gen_st8_i64(var, cpu_env, offset);
113
+ break;
114
+ case MO_16:
115
+ tcg_gen_st16_i64(var, cpu_env, offset);
116
+ break;
117
+ case MO_32:
118
+ tcg_gen_st32_i64(var, cpu_env, offset);
119
+ break;
120
+ case MO_64:
121
+ tcg_gen_st_i64(var, cpu_env, offset);
122
+ break;
123
+ default:
124
+ g_assert_not_reached();
125
+ }
126
+}
127
+
128
static bool trans_VCMLA(DisasContext *s, arg_VCMLA *a)
129
{
130
int opr_sz;
131
diff --git a/target/arm/translate.c b/target/arm/translate.c
132
index XXXXXXX..XXXXXXX 100644
133
--- a/target/arm/translate.c
134
+++ b/target/arm/translate.c
135
@@ -XXX,XX +XXX,XX @@ neon_reg_offset (int reg, int n)
136
return vfp_reg_offset(0, sreg);
21
}
137
}
22
138
23
-static uint64_t systick_read(void *opaque, hwaddr addr, unsigned size)
139
-/* Return the offset of a 2**SIZE piece of a NEON register, at index ELE,
24
+static MemTxResult systick_read(void *opaque, hwaddr addr, uint64_t *data,
140
- * where 0 is the least significant end of the register.
25
+ unsigned size, MemTxAttrs attrs)
141
- */
26
{
142
-static inline long
27
SysTickState *s = opaque;
143
-neon_element_offset(int reg, int element, MemOp size)
28
uint32_t val;
144
-{
29
145
- int element_size = 1 << size;
30
+ if (attrs.user) {
146
- int ofs = element * element_size;
31
+ /* Generate BusFault for unprivileged accesses */
147
-#ifdef HOST_WORDS_BIGENDIAN
32
+ return MEMTX_ERROR;
148
- /* Calculate the offset assuming fully little-endian,
33
+ }
149
- * then XOR to account for the order of the 8-byte units.
34
+
150
- */
35
switch (addr) {
151
- if (element_size < 8) {
36
case 0x0: /* SysTick Control and Status. */
152
- ofs ^= 8 - element_size;
37
val = s->control;
153
- }
38
@@ -XXX,XX +XXX,XX @@ static uint64_t systick_read(void *opaque, hwaddr addr, unsigned size)
154
-#endif
39
}
155
- return neon_reg_offset(reg, 0) + ofs;
40
156
-}
41
trace_systick_read(addr, val, size);
157
-
42
- return val;
158
static TCGv_i32 neon_load_reg(int reg, int pass)
43
+ *data = val;
159
{
44
+ return MEMTX_OK;
160
TCGv_i32 tmp = tcg_temp_new_i32();
161
@@ -XXX,XX +XXX,XX @@ static TCGv_i32 neon_load_reg(int reg, int pass)
162
return tmp;
45
}
163
}
46
164
47
-static void systick_write(void *opaque, hwaddr addr,
165
-static void neon_load_element(TCGv_i32 var, int reg, int ele, MemOp mop)
48
- uint64_t value, unsigned size)
166
-{
49
+static MemTxResult systick_write(void *opaque, hwaddr addr,
167
- long offset = neon_element_offset(reg, ele, mop & MO_SIZE);
50
+ uint64_t value, unsigned size,
168
-
51
+ MemTxAttrs attrs)
169
- switch (mop) {
52
{
170
- case MO_UB:
53
SysTickState *s = opaque;
171
- tcg_gen_ld8u_i32(var, cpu_env, offset);
54
172
- break;
55
+ if (attrs.user) {
173
- case MO_UW:
56
+ /* Generate BusFault for unprivileged accesses */
174
- tcg_gen_ld16u_i32(var, cpu_env, offset);
57
+ return MEMTX_ERROR;
175
- break;
58
+ }
176
- case MO_UL:
59
+
177
- tcg_gen_ld_i32(var, cpu_env, offset);
60
trace_systick_write(addr, value, size);
178
- break;
61
179
- default:
62
switch (addr) {
180
- g_assert_not_reached();
63
@@ -XXX,XX +XXX,XX @@ static void systick_write(void *opaque, hwaddr addr,
181
- }
64
qemu_log_mask(LOG_GUEST_ERROR,
182
-}
65
"SysTick: Bad write offset 0x%" HWADDR_PRIx "\n", addr);
183
-
66
}
184
-static void neon_load_element64(TCGv_i64 var, int reg, int ele, MemOp mop)
67
+ return MEMTX_OK;
185
-{
186
- long offset = neon_element_offset(reg, ele, mop & MO_SIZE);
187
-
188
- switch (mop) {
189
- case MO_UB:
190
- tcg_gen_ld8u_i64(var, cpu_env, offset);
191
- break;
192
- case MO_UW:
193
- tcg_gen_ld16u_i64(var, cpu_env, offset);
194
- break;
195
- case MO_UL:
196
- tcg_gen_ld32u_i64(var, cpu_env, offset);
197
- break;
198
- case MO_Q:
199
- tcg_gen_ld_i64(var, cpu_env, offset);
200
- break;
201
- default:
202
- g_assert_not_reached();
203
- }
204
-}
205
-
206
static void neon_store_reg(int reg, int pass, TCGv_i32 var)
207
{
208
tcg_gen_st_i32(var, cpu_env, neon_reg_offset(reg, pass));
209
tcg_temp_free_i32(var);
68
}
210
}
69
211
70
static const MemoryRegionOps systick_ops = {
212
-static void neon_store_element(int reg, int ele, MemOp size, TCGv_i32 var)
71
- .read = systick_read,
213
-{
72
- .write = systick_write,
214
- long offset = neon_element_offset(reg, ele, size);
73
+ .read_with_attrs = systick_read,
215
-
74
+ .write_with_attrs = systick_write,
216
- switch (size) {
75
.endianness = DEVICE_NATIVE_ENDIAN,
217
- case MO_8:
76
.valid.min_access_size = 4,
218
- tcg_gen_st8_i32(var, cpu_env, offset);
77
.valid.max_access_size = 4,
219
- break;
220
- case MO_16:
221
- tcg_gen_st16_i32(var, cpu_env, offset);
222
- break;
223
- case MO_32:
224
- tcg_gen_st_i32(var, cpu_env, offset);
225
- break;
226
- default:
227
- g_assert_not_reached();
228
- }
229
-}
230
-
231
-static void neon_store_element64(int reg, int ele, MemOp size, TCGv_i64 var)
232
-{
233
- long offset = neon_element_offset(reg, ele, size);
234
-
235
- switch (size) {
236
- case MO_8:
237
- tcg_gen_st8_i64(var, cpu_env, offset);
238
- break;
239
- case MO_16:
240
- tcg_gen_st16_i64(var, cpu_env, offset);
241
- break;
242
- case MO_32:
243
- tcg_gen_st32_i64(var, cpu_env, offset);
244
- break;
245
- case MO_64:
246
- tcg_gen_st_i64(var, cpu_env, offset);
247
- break;
248
- default:
249
- g_assert_not_reached();
250
- }
251
-}
252
-
253
static inline void neon_load_reg64(TCGv_i64 var, int reg)
254
{
255
tcg_gen_ld_i64(var, cpu_env, vfp_reg_offset(1, reg));
78
--
256
--
79
2.20.1
257
2.20.1
80
258
81
259
diff view generated by jsdifflib
1
Coverity points out (CID 1402195) that the loop in trans_VMOV_imm_dp()
1
Since commit ba3e7926691ed3 it has been unnecessary for target code
2
that iterates over the destination registers in a short-vector VMOV
2
to call gen_io_end() after an IO instruction in icount mode; it is
3
accidentally throws away the returned updated register number
3
sufficient to call gen_io_start() before it and to force the end of
4
from vfp_advance_dreg(). Add the missing assignment. (We got this
4
the TB.
5
correct in trans_VMOV_imm_sp().)
6
5
7
Fixes: 18cf951af9a27ae573a
6
Many now-unnecessary calls to gen_io_end() were removed in commit
7
9e9b10c6491153b, but some were missed or accidentally added later.
8
Remove unneeded calls from the arm target:
9
10
* the call in the handling of exception-return-via-LDM is
11
unnecessary, and the code is already forcing end-of-TB
12
* the call in the VFP access check code is more complicated:
13
we weren't ending the TB, so we need to add the code to
14
force that by setting DISAS_UPDATE
15
* the doc comment for ARM_CP_IO doesn't need to mention
16
gen_io_end() any more
17
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
18
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
19
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
9
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
20
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
Message-id: 20190702105115.9465-1-peter.maydell@linaro.org
21
Reviewed-by: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
22
Message-id: 20200619170324.12093-1-peter.maydell@linaro.org
11
---
23
---
12
target/arm/translate-vfp.inc.c | 2 +-
24
target/arm/cpu.h | 2 +-
13
1 file changed, 1 insertion(+), 1 deletion(-)
25
target/arm/translate-vfp.inc.c | 7 +++----
26
target/arm/translate.c | 3 ---
27
3 files changed, 4 insertions(+), 8 deletions(-)
14
28
29
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
30
index XXXXXXX..XXXXXXX 100644
31
--- a/target/arm/cpu.h
32
+++ b/target/arm/cpu.h
33
@@ -XXX,XX +XXX,XX @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
34
* migration or KVM state synchronization. (Typically this is for "registers"
35
* which are actually used as instructions for cache maintenance and so on.)
36
* IO indicates that this register does I/O and therefore its accesses
37
- * need to be surrounded by gen_io_start()/gen_io_end(). In particular,
38
+ * need to be marked with gen_io_start() and also end the TB. In particular,
39
* registers which implement clocks or timers require this.
40
* RAISES_EXC is for when the read or write hook might raise an exception;
41
* the generated code will synchronize the CPU state before calling the hook
15
diff --git a/target/arm/translate-vfp.inc.c b/target/arm/translate-vfp.inc.c
42
diff --git a/target/arm/translate-vfp.inc.c b/target/arm/translate-vfp.inc.c
16
index XXXXXXX..XXXXXXX 100644
43
index XXXXXXX..XXXXXXX 100644
17
--- a/target/arm/translate-vfp.inc.c
44
--- a/target/arm/translate-vfp.inc.c
18
+++ b/target/arm/translate-vfp.inc.c
45
+++ b/target/arm/translate-vfp.inc.c
19
@@ -XXX,XX +XXX,XX @@ static bool trans_VMOV_imm_dp(DisasContext *s, arg_VMOV_imm_dp *a)
46
@@ -XXX,XX +XXX,XX @@ static bool full_vfp_access_check(DisasContext *s, bool ignore_vfp_enabled)
20
47
if (s->v7m_lspact) {
21
/* Set up the operands for the next iteration */
48
/*
22
veclen--;
49
* Lazy state saving affects external memory and also the NVIC,
23
- vfp_advance_dreg(vd, delta_d);
50
- * so we must mark it as an IO operation for icount.
24
+ vd = vfp_advance_dreg(vd, delta_d);
51
+ * so we must mark it as an IO operation for icount (and cause
25
}
52
+ * this to be the last insn in the TB).
26
53
*/
27
tcg_temp_free_i64(fd);
54
if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
55
+ s->base.is_jmp = DISAS_UPDATE;
56
gen_io_start();
57
}
58
gen_helper_v7m_preserve_fp_state(cpu_env);
59
- if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
60
- gen_io_end();
61
- }
62
/*
63
* If the preserve_fp_state helper doesn't throw an exception
64
* then it will clear LSPACT; we don't need to repeat this for
65
diff --git a/target/arm/translate.c b/target/arm/translate.c
66
index XXXXXXX..XXXXXXX 100644
67
--- a/target/arm/translate.c
68
+++ b/target/arm/translate.c
69
@@ -XXX,XX +XXX,XX @@ static bool do_ldm(DisasContext *s, arg_ldst_block *a, int min_n)
70
gen_io_start();
71
}
72
gen_helper_cpsr_write_eret(cpu_env, tmp);
73
- if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
74
- gen_io_end();
75
- }
76
tcg_temp_free_i32(tmp);
77
/* Must exit loop to check un-masked IRQs */
78
s->base.is_jmp = DISAS_EXIT;
28
--
79
--
29
2.20.1
80
2.20.1
30
81
31
82
diff view generated by jsdifflib
New patch
1
In commit cfdb2c0c95ae9205b0 ("target/arm: Vectorize SABA/UABA") we
2
replaced the old handling of SABA/UABA with a vectorized implementation
3
which returns early rather than falling into the loop-ever-elements
4
code. We forgot to delete the part of the old looping code that
5
did the accumulate step, and Coverity correctly warns (CID 1428955)
6
that this code is now dead. Delete it.
1
7
8
Fixes: cfdb2c0c95ae9205b0
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
11
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
12
Message-id: 20200619171547.29780-1-peter.maydell@linaro.org
13
---
14
target/arm/translate-a64.c | 12 ------------
15
1 file changed, 12 deletions(-)
16
17
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/target/arm/translate-a64.c
20
+++ b/target/arm/translate-a64.c
21
@@ -XXX,XX +XXX,XX @@ static void disas_simd_3same_int(DisasContext *s, uint32_t insn)
22
genfn(tcg_res, tcg_op1, tcg_op2);
23
}
24
25
- if (opcode == 0xf) {
26
- /* SABA, UABA: accumulating ops */
27
- static NeonGenTwoOpFn * const fns[3] = {
28
- gen_helper_neon_add_u8,
29
- gen_helper_neon_add_u16,
30
- tcg_gen_add_i32,
31
- };
32
-
33
- read_vec_element_i32(s, tcg_op1, rd, pass, MO_32);
34
- fns[size](tcg_res, tcg_op1, tcg_res);
35
- }
36
-
37
write_vec_element_i32(s, tcg_res, rd, pass, MO_32);
38
39
tcg_temp_free_i32(tcg_res);
40
--
41
2.20.1
42
43
diff view generated by jsdifflib
New patch
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
1
2
3
Add a trace event to see when a guest disable/enable the watchdog.
4
5
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
6
Message-id: 20200617072539.32686-2-f4bug@amsat.org
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
10
hw/watchdog/cmsdk-apb-watchdog.c | 1 +
11
hw/watchdog/trace-events | 1 +
12
2 files changed, 2 insertions(+)
13
14
diff --git a/hw/watchdog/cmsdk-apb-watchdog.c b/hw/watchdog/cmsdk-apb-watchdog.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/watchdog/cmsdk-apb-watchdog.c
17
+++ b/hw/watchdog/cmsdk-apb-watchdog.c
18
@@ -XXX,XX +XXX,XX @@ static void cmsdk_apb_watchdog_write(void *opaque, hwaddr offset,
19
break;
20
case A_WDOGLOCK:
21
s->lock = (value != WDOG_UNLOCK_VALUE);
22
+ trace_cmsdk_apb_watchdog_lock(s->lock);
23
break;
24
case A_WDOGITCR:
25
if (s->is_luminary) {
26
diff --git a/hw/watchdog/trace-events b/hw/watchdog/trace-events
27
index XXXXXXX..XXXXXXX 100644
28
--- a/hw/watchdog/trace-events
29
+++ b/hw/watchdog/trace-events
30
@@ -XXX,XX +XXX,XX @@
31
cmsdk_apb_watchdog_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB watchdog read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
32
cmsdk_apb_watchdog_write(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB watchdog write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
33
cmsdk_apb_watchdog_reset(void) "CMSDK APB watchdog: reset"
34
+cmsdk_apb_watchdog_lock(uint32_t lock) "CMSDK APB watchdog: lock %" PRIu32
35
--
36
2.20.1
37
38
diff view generated by jsdifflib
New patch
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
1
2
3
Use self-explicit definitions instead of magic values.
4
5
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
6
Message-id: 20200617072539.32686-3-f4bug@amsat.org
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
10
hw/i2c/versatile_i2c.c | 14 ++++++++++----
11
1 file changed, 10 insertions(+), 4 deletions(-)
12
13
diff --git a/hw/i2c/versatile_i2c.c b/hw/i2c/versatile_i2c.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/hw/i2c/versatile_i2c.c
16
+++ b/hw/i2c/versatile_i2c.c
17
@@ -XXX,XX +XXX,XX @@
18
#include "qemu/osdep.h"
19
#include "hw/sysbus.h"
20
#include "hw/i2c/bitbang_i2c.h"
21
+#include "hw/registerfields.h"
22
#include "qemu/log.h"
23
#include "qemu/module.h"
24
25
@@ -XXX,XX +XXX,XX @@ typedef struct VersatileI2CState {
26
int in;
27
} VersatileI2CState;
28
29
+REG32(CONTROL_GET, 0)
30
+REG32(CONTROL_SET, 0)
31
+REG32(CONTROL_CLR, 4)
32
+
33
static uint64_t versatile_i2c_read(void *opaque, hwaddr offset,
34
unsigned size)
35
{
36
VersatileI2CState *s = (VersatileI2CState *)opaque;
37
38
- if (offset == 0) {
39
+ switch (offset) {
40
+ case A_CONTROL_SET:
41
return (s->out & 1) | (s->in << 1);
42
- } else {
43
+ default:
44
qemu_log_mask(LOG_GUEST_ERROR,
45
"%s: Bad offset 0x%x\n", __func__, (int)offset);
46
return -1;
47
@@ -XXX,XX +XXX,XX @@ static void versatile_i2c_write(void *opaque, hwaddr offset,
48
VersatileI2CState *s = (VersatileI2CState *)opaque;
49
50
switch (offset) {
51
- case 0:
52
+ case A_CONTROL_SET:
53
s->out |= value & 3;
54
break;
55
- case 4:
56
+ case A_CONTROL_CLR:
57
s->out &= ~value;
58
break;
59
default:
60
--
61
2.20.1
62
63
diff view generated by jsdifflib
New patch
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
1
2
3
Use self-explicit definitions instead of magic values.
4
5
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
6
Message-id: 20200617072539.32686-4-f4bug@amsat.org
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
10
hw/i2c/versatile_i2c.c | 7 +++++--
11
1 file changed, 5 insertions(+), 2 deletions(-)
12
13
diff --git a/hw/i2c/versatile_i2c.c b/hw/i2c/versatile_i2c.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/hw/i2c/versatile_i2c.c
16
+++ b/hw/i2c/versatile_i2c.c
17
@@ -XXX,XX +XXX,XX @@ REG32(CONTROL_GET, 0)
18
REG32(CONTROL_SET, 0)
19
REG32(CONTROL_CLR, 4)
20
21
+#define SCL BIT(0)
22
+#define SDA BIT(1)
23
+
24
static uint64_t versatile_i2c_read(void *opaque, hwaddr offset,
25
unsigned size)
26
{
27
@@ -XXX,XX +XXX,XX @@ static void versatile_i2c_write(void *opaque, hwaddr offset,
28
qemu_log_mask(LOG_GUEST_ERROR,
29
"%s: Bad offset 0x%x\n", __func__, (int)offset);
30
}
31
- bitbang_i2c_set(&s->bitbang, BITBANG_I2C_SCL, (s->out & 1) != 0);
32
- s->in = bitbang_i2c_set(&s->bitbang, BITBANG_I2C_SDA, (s->out & 2) != 0);
33
+ bitbang_i2c_set(&s->bitbang, BITBANG_I2C_SCL, (s->out & SCL) != 0);
34
+ s->in = bitbang_i2c_set(&s->bitbang, BITBANG_I2C_SDA, (s->out & SDA) != 0);
35
}
36
37
static const MemoryRegionOps versatile_i2c_ops = {
38
--
39
2.20.1
40
41
diff view generated by jsdifflib
New patch
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
1
2
3
'ARM SBCon two-wire serial bus interface' is the official
4
name describing the pair of registers used to bitbanging
5
I2C in the Versatile boards.
6
7
Make the private VersatileI2CState structure as public
8
ArmSbconI2CState.
9
Add the TYPE_ARM_SBCON_I2C, alias to our current
10
TYPE_VERSATILE_I2C model.
11
Rename the memory region description as 'arm_sbcon_i2c'.
12
13
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
14
Message-id: 20200617072539.32686-5-f4bug@amsat.org
15
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
16
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
17
---
18
include/hw/i2c/arm_sbcon_i2c.h | 35 ++++++++++++++++++++++++++++++++++
19
hw/i2c/versatile_i2c.c | 17 +++++------------
20
MAINTAINERS | 1 +
21
3 files changed, 41 insertions(+), 12 deletions(-)
22
create mode 100644 include/hw/i2c/arm_sbcon_i2c.h
23
24
diff --git a/include/hw/i2c/arm_sbcon_i2c.h b/include/hw/i2c/arm_sbcon_i2c.h
25
new file mode 100644
26
index XXXXXXX..XXXXXXX
27
--- /dev/null
28
+++ b/include/hw/i2c/arm_sbcon_i2c.h
29
@@ -XXX,XX +XXX,XX @@
30
+/*
31
+ * ARM SBCon two-wire serial bus interface (I2C bitbang)
32
+ * a.k.a.
33
+ * ARM Versatile I2C controller
34
+ *
35
+ * Copyright (c) 2006-2007 CodeSourcery.
36
+ * Copyright (c) 2012 Oskar Andero <oskar.andero@gmail.com>
37
+ * Copyright (C) 2020 Philippe Mathieu-Daudé <f4bug@amsat.org>
38
+ *
39
+ * SPDX-License-Identifier: GPL-2.0-or-later
40
+ */
41
+#ifndef HW_I2C_ARM_SBCON_H
42
+#define HW_I2C_ARM_SBCON_H
43
+
44
+#include "hw/sysbus.h"
45
+#include "hw/i2c/bitbang_i2c.h"
46
+
47
+#define TYPE_VERSATILE_I2C "versatile_i2c"
48
+#define TYPE_ARM_SBCON_I2C TYPE_VERSATILE_I2C
49
+
50
+#define ARM_SBCON_I2C(obj) \
51
+ OBJECT_CHECK(ArmSbconI2CState, (obj), TYPE_ARM_SBCON_I2C)
52
+
53
+typedef struct ArmSbconI2CState {
54
+ /*< private >*/
55
+ SysBusDevice parent_obj;
56
+ /*< public >*/
57
+
58
+ MemoryRegion iomem;
59
+ bitbang_i2c_interface bitbang;
60
+ int out;
61
+ int in;
62
+} ArmSbconI2CState;
63
+
64
+#endif /* HW_I2C_ARM_SBCON_H */
65
diff --git a/hw/i2c/versatile_i2c.c b/hw/i2c/versatile_i2c.c
66
index XXXXXXX..XXXXXXX 100644
67
--- a/hw/i2c/versatile_i2c.c
68
+++ b/hw/i2c/versatile_i2c.c
69
@@ -XXX,XX +XXX,XX @@
70
/*
71
- * ARM Versatile I2C controller
72
+ * ARM SBCon two-wire serial bus interface (I2C bitbang)
73
+ * a.k.a. ARM Versatile I2C controller
74
*
75
* Copyright (c) 2006-2007 CodeSourcery.
76
* Copyright (c) 2012 Oskar Andero <oskar.andero@gmail.com>
77
@@ -XXX,XX +XXX,XX @@
78
*/
79
80
#include "qemu/osdep.h"
81
-#include "hw/sysbus.h"
82
-#include "hw/i2c/bitbang_i2c.h"
83
+#include "hw/i2c/arm_sbcon_i2c.h"
84
#include "hw/registerfields.h"
85
#include "qemu/log.h"
86
#include "qemu/module.h"
87
88
-#define TYPE_VERSATILE_I2C "versatile_i2c"
89
#define VERSATILE_I2C(obj) \
90
OBJECT_CHECK(VersatileI2CState, (obj), TYPE_VERSATILE_I2C)
91
92
-typedef struct VersatileI2CState {
93
- SysBusDevice parent_obj;
94
+typedef ArmSbconI2CState VersatileI2CState;
95
96
- MemoryRegion iomem;
97
- bitbang_i2c_interface bitbang;
98
- int out;
99
- int in;
100
-} VersatileI2CState;
101
102
REG32(CONTROL_GET, 0)
103
REG32(CONTROL_SET, 0)
104
@@ -XXX,XX +XXX,XX @@ static void versatile_i2c_init(Object *obj)
105
bus = i2c_init_bus(dev, "i2c");
106
bitbang_i2c_init(&s->bitbang, bus);
107
memory_region_init_io(&s->iomem, obj, &versatile_i2c_ops, s,
108
- "versatile_i2c", 0x1000);
109
+ "arm_sbcon_i2c", 0x1000);
110
sysbus_init_mmio(sbd, &s->iomem);
111
}
112
113
diff --git a/MAINTAINERS b/MAINTAINERS
114
index XXXXXXX..XXXXXXX 100644
115
--- a/MAINTAINERS
116
+++ b/MAINTAINERS
117
@@ -XXX,XX +XXX,XX @@ M: Peter Maydell <peter.maydell@linaro.org>
118
L: qemu-arm@nongnu.org
119
S: Maintained
120
F: hw/*/versatile*
121
+F: include/hw/i2c/arm_sbcon_i2c.h
122
F: hw/misc/arm_sysctl.c
123
F: docs/system/arm/versatile.rst
124
125
--
126
2.20.1
127
128
diff view generated by jsdifflib
New patch
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
1
2
3
By using the TYPE_* definitions for devices, we can:
4
- quickly find where devices are used with 'git-grep'
5
- easily rename a device (one-line change).
6
7
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
Message-id: 20200617072539.32686-6-f4bug@amsat.org
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
12
hw/arm/realview.c | 3 ++-
13
hw/arm/versatilepb.c | 3 ++-
14
hw/arm/vexpress.c | 3 ++-
15
3 files changed, 6 insertions(+), 3 deletions(-)
16
17
diff --git a/hw/arm/realview.c b/hw/arm/realview.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/hw/arm/realview.c
20
+++ b/hw/arm/realview.c
21
@@ -XXX,XX +XXX,XX @@
22
#include "hw/cpu/a9mpcore.h"
23
#include "hw/intc/realview_gic.h"
24
#include "hw/irq.h"
25
+#include "hw/i2c/arm_sbcon_i2c.h"
26
27
#define SMP_BOOT_ADDR 0xe0000000
28
#define SMP_BOOTREG_ADDR 0x10000030
29
@@ -XXX,XX +XXX,XX @@ static void realview_init(MachineState *machine,
30
}
31
}
32
33
- dev = sysbus_create_simple("versatile_i2c", 0x10002000, NULL);
34
+ dev = sysbus_create_simple(TYPE_VERSATILE_I2C, 0x10002000, NULL);
35
i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c");
36
i2c_create_slave(i2c, "ds1338", 0x68);
37
38
diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c
39
index XXXXXXX..XXXXXXX 100644
40
--- a/hw/arm/versatilepb.c
41
+++ b/hw/arm/versatilepb.c
42
@@ -XXX,XX +XXX,XX @@
43
#include "sysemu/sysemu.h"
44
#include "hw/pci/pci.h"
45
#include "hw/i2c/i2c.h"
46
+#include "hw/i2c/arm_sbcon_i2c.h"
47
#include "hw/irq.h"
48
#include "hw/boards.h"
49
#include "exec/address-spaces.h"
50
@@ -XXX,XX +XXX,XX @@ static void versatile_init(MachineState *machine, int board_id)
51
/* Add PL031 Real Time Clock. */
52
sysbus_create_simple("pl031", 0x101e8000, pic[10]);
53
54
- dev = sysbus_create_simple("versatile_i2c", 0x10002000, NULL);
55
+ dev = sysbus_create_simple(TYPE_VERSATILE_I2C, 0x10002000, NULL);
56
i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c");
57
i2c_create_slave(i2c, "ds1338", 0x68);
58
59
diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c
60
index XXXXXXX..XXXXXXX 100644
61
--- a/hw/arm/vexpress.c
62
+++ b/hw/arm/vexpress.c
63
@@ -XXX,XX +XXX,XX @@
64
#include "hw/char/pl011.h"
65
#include "hw/cpu/a9mpcore.h"
66
#include "hw/cpu/a15mpcore.h"
67
+#include "hw/i2c/arm_sbcon_i2c.h"
68
69
#define VEXPRESS_BOARD_ID 0x8e0
70
#define VEXPRESS_FLASH_SIZE (64 * 1024 * 1024)
71
@@ -XXX,XX +XXX,XX @@ static void vexpress_common_init(MachineState *machine)
72
sysbus_create_simple("sp804", map[VE_TIMER01], pic[2]);
73
sysbus_create_simple("sp804", map[VE_TIMER23], pic[3]);
74
75
- dev = sysbus_create_simple("versatile_i2c", map[VE_SERIALDVI], NULL);
76
+ dev = sysbus_create_simple(TYPE_VERSATILE_I2C, map[VE_SERIALDVI], NULL);
77
i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c");
78
i2c_create_slave(i2c, "sii9022", 0x39);
79
80
--
81
2.20.1
82
83
diff view generated by jsdifflib
New patch
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
1
2
3
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
4
Message-id: 20200617072539.32686-7-f4bug@amsat.org
5
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
---
8
hw/arm/mps2.c | 5 ++++-
9
1 file changed, 4 insertions(+), 1 deletion(-)
10
11
diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/hw/arm/mps2.c
14
+++ b/hw/arm/mps2.c
15
@@ -XXX,XX +XXX,XX @@ typedef struct {
16
MemoryRegion blockram_m2;
17
MemoryRegion blockram_m3;
18
MemoryRegion sram;
19
+ /* FPGA APB subsystem */
20
MPS2SCC scc;
21
+ /* CMSDK APB subsystem */
22
CMSDKAPBDualTimer dualtimer;
23
} MPS2MachineState;
24
25
@@ -XXX,XX +XXX,XX @@ static void mps2_common_init(MachineState *machine)
26
g_assert_not_reached();
27
}
28
29
+ /* CMSDK APB subsystem */
30
cmsdk_apb_timer_create(0x40000000, qdev_get_gpio_in(armv7m, 8), SYSCLK_FRQ);
31
cmsdk_apb_timer_create(0x40001000, qdev_get_gpio_in(armv7m, 9), SYSCLK_FRQ);
32
-
33
object_initialize_child(OBJECT(mms), "dualtimer", &mms->dualtimer,
34
TYPE_CMSDK_APB_DUALTIMER);
35
qdev_prop_set_uint32(DEVICE(&mms->dualtimer), "pclk-frq", SYSCLK_FRQ);
36
@@ -XXX,XX +XXX,XX @@ static void mps2_common_init(MachineState *machine)
37
qdev_get_gpio_in(armv7m, 10));
38
sysbus_mmio_map(SYS_BUS_DEVICE(&mms->dualtimer), 0, 0x40002000);
39
40
+ /* FPGA APB subsystem */
41
object_initialize_child(OBJECT(mms), "scc", &mms->scc, TYPE_MPS2_SCC);
42
sccdev = DEVICE(&mms->scc);
43
qdev_prop_set_uint32(sccdev, "scc-cfg4", 0x2);
44
--
45
2.20.1
46
47
diff view generated by jsdifflib
New patch
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
1
2
3
To differenciate with the CMSDK APB peripheral region,
4
rename this region 'CMSDK AHB peripheral region'.
5
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
Message-id: 20200617072539.32686-8-f4bug@amsat.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
11
hw/arm/mps2.c | 3 ++-
12
1 file changed, 2 insertions(+), 1 deletion(-)
13
14
diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/arm/mps2.c
17
+++ b/hw/arm/mps2.c
18
@@ -XXX,XX +XXX,XX @@ static void mps2_common_init(MachineState *machine)
19
*/
20
create_unimplemented_device("CMSDK APB peripheral region @0x40000000",
21
0x40000000, 0x00010000);
22
- create_unimplemented_device("CMSDK peripheral region @0x40010000",
23
+ create_unimplemented_device("CMSDK AHB peripheral region @0x40010000",
24
0x40010000, 0x00010000);
25
create_unimplemented_device("Extra peripheral region @0x40020000",
26
0x40020000, 0x00010000);
27
+
28
create_unimplemented_device("RESERVED 4", 0x40030000, 0x001D0000);
29
create_unimplemented_device("VGA", 0x41000000, 0x0200000);
30
31
--
32
2.20.1
33
34
diff view generated by jsdifflib
New patch
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
1
2
3
We already model the CMSDK APB watchdog device, let's use it!
4
5
Suggested-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
7
Message-id: 20200617072539.32686-9-f4bug@amsat.org
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
11
hw/arm/mps2.c | 7 +++++++
12
hw/arm/Kconfig | 1 +
13
2 files changed, 8 insertions(+)
14
15
diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/hw/arm/mps2.c
18
+++ b/hw/arm/mps2.c
19
@@ -XXX,XX +XXX,XX @@ static void mps2_common_init(MachineState *machine)
20
sysbus_connect_irq(SYS_BUS_DEVICE(&mms->dualtimer), 0,
21
qdev_get_gpio_in(armv7m, 10));
22
sysbus_mmio_map(SYS_BUS_DEVICE(&mms->dualtimer), 0, 0x40002000);
23
+ object_initialize_child(OBJECT(mms), "watchdog", &mms->watchdog,
24
+ TYPE_CMSDK_APB_WATCHDOG);
25
+ qdev_prop_set_uint32(DEVICE(&mms->watchdog), "wdogclk-frq", SYSCLK_FRQ);
26
+ sysbus_realize(SYS_BUS_DEVICE(&mms->watchdog), &error_fatal);
27
+ sysbus_connect_irq(SYS_BUS_DEVICE(&mms->watchdog), 0,
28
+ qdev_get_gpio_in_named(armv7m, "NMI", 0));
29
+ sysbus_mmio_map(SYS_BUS_DEVICE(&mms->watchdog), 0, 0x40008000);
30
31
/* FPGA APB subsystem */
32
object_initialize_child(OBJECT(mms), "scc", &mms->scc, TYPE_MPS2_SCC);
33
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
34
index XXXXXXX..XXXXXXX 100644
35
--- a/hw/arm/Kconfig
36
+++ b/hw/arm/Kconfig
37
@@ -XXX,XX +XXX,XX @@ config MPS2
38
select PL080 # DMA controller
39
select SPLIT_IRQ
40
select UNIMP
41
+ select CMSDK_APB_WATCHDOG
42
43
config FSL_IMX7
44
bool
45
--
46
2.20.1
47
48
diff view generated by jsdifflib
New patch
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
1
2
3
Register the GPIO peripherals as unimplemented to better
4
follow their accesses, for example booting Zephyr:
5
6
----------------
7
IN: arm_mps2_pinmux_init
8
0x00001160: f64f 0231 movw r2, #0xf831
9
0x00001164: 4b06 ldr r3, [pc, #0x18]
10
0x00001166: 2000 movs r0, #0
11
0x00001168: 619a str r2, [r3, #0x18]
12
0x0000116a: f24c 426f movw r2, #0xc46f
13
0x0000116e: f503 5380 add.w r3, r3, #0x1000
14
0x00001172: 619a str r2, [r3, #0x18]
15
0x00001174: f44f 529e mov.w r2, #0x13c0
16
0x00001178: f503 5380 add.w r3, r3, #0x1000
17
0x0000117c: 619a str r2, [r3, #0x18]
18
0x0000117e: 4770 bx lr
19
cmsdk-ahb-gpio: unimplemented device write (size 4, value 0xf831, offset 0x18)
20
cmsdk-ahb-gpio: unimplemented device write (size 4, value 0xc46f, offset 0x18)
21
cmsdk-ahb-gpio: unimplemented device write (size 4, value 0x13c0, offset 0x18)
22
23
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
24
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
25
Message-id: 20200617072539.32686-10-f4bug@amsat.org
26
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
27
---
28
hw/arm/mps2.c | 8 ++++++--
29
1 file changed, 6 insertions(+), 2 deletions(-)
30
31
diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c
32
index XXXXXXX..XXXXXXX 100644
33
--- a/hw/arm/mps2.c
34
+++ b/hw/arm/mps2.c
35
@@ -XXX,XX +XXX,XX @@ static void mps2_common_init(MachineState *machine)
36
MemoryRegion *system_memory = get_system_memory();
37
MachineClass *mc = MACHINE_GET_CLASS(machine);
38
DeviceState *armv7m, *sccdev;
39
+ int i;
40
41
if (strcmp(machine->cpu_type, mc->default_cpu_type) != 0) {
42
error_report("This board can only be used with CPU %s",
43
@@ -XXX,XX +XXX,XX @@ static void mps2_common_init(MachineState *machine)
44
*/
45
Object *orgate;
46
DeviceState *orgate_dev;
47
- int i;
48
49
orgate = object_new(TYPE_OR_IRQ);
50
object_property_set_int(orgate, 6, "num-lines", &error_fatal);
51
@@ -XXX,XX +XXX,XX @@ static void mps2_common_init(MachineState *machine)
52
*/
53
Object *orgate;
54
DeviceState *orgate_dev;
55
- int i;
56
57
orgate = object_new(TYPE_OR_IRQ);
58
object_property_set_int(orgate, 10, "num-lines", &error_fatal);
59
@@ -XXX,XX +XXX,XX @@ static void mps2_common_init(MachineState *machine)
60
default:
61
g_assert_not_reached();
62
}
63
+ for (i = 0; i < 4; i++) {
64
+ static const hwaddr gpiobase[] = {0x40010000, 0x40011000,
65
+ 0x40012000, 0x40013000};
66
+ create_unimplemented_device("cmsdk-ahb-gpio", gpiobase[i], 0x1000);
67
+ }
68
69
/* CMSDK APB subsystem */
70
cmsdk_apb_timer_create(0x40000000, qdev_get_gpio_in(armv7m, 8), SYSCLK_FRQ);
71
--
72
2.20.1
73
74
diff view generated by jsdifflib
New patch
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
1
2
3
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
4
Message-id: 20200617072539.32686-11-f4bug@amsat.org
5
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
---
8
hw/arm/mps2.c | 9 +++++++++
9
1 file changed, 9 insertions(+)
10
11
diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/hw/arm/mps2.c
14
+++ b/hw/arm/mps2.c
15
@@ -XXX,XX +XXX,XX @@
16
#include "hw/timer/cmsdk-apb-timer.h"
17
#include "hw/timer/cmsdk-apb-dualtimer.h"
18
#include "hw/misc/mps2-scc.h"
19
+#include "hw/misc/mps2-fpgaio.h"
20
#include "hw/net/lan9118.h"
21
#include "net/net.h"
22
+#include "hw/watchdog/cmsdk-apb-watchdog.h"
23
24
typedef enum MPS2FPGAType {
25
FPGA_AN385,
26
@@ -XXX,XX +XXX,XX @@ typedef struct {
27
MemoryRegion sram;
28
/* FPGA APB subsystem */
29
MPS2SCC scc;
30
+ MPS2FPGAIO fpgaio;
31
/* CMSDK APB subsystem */
32
CMSDKAPBDualTimer dualtimer;
33
+ CMSDKAPBWatchdog watchdog;
34
} MPS2MachineState;
35
36
#define TYPE_MPS2_MACHINE "mps2"
37
@@ -XXX,XX +XXX,XX @@ static void mps2_common_init(MachineState *machine)
38
qdev_prop_set_uint32(sccdev, "scc-id", mmc->scc_id);
39
sysbus_realize(SYS_BUS_DEVICE(&mms->scc), &error_fatal);
40
sysbus_mmio_map(SYS_BUS_DEVICE(sccdev), 0, 0x4002f000);
41
+ object_initialize_child(OBJECT(mms), "fpgaio",
42
+ &mms->fpgaio, TYPE_MPS2_FPGAIO);
43
+ qdev_prop_set_uint32(DEVICE(&mms->fpgaio), "prescale-clk", 25000000);
44
+ sysbus_realize(SYS_BUS_DEVICE(&mms->fpgaio), &error_fatal);
45
+ sysbus_mmio_map(SYS_BUS_DEVICE(&mms->fpgaio), 0, 0x40028000);
46
47
/* In hardware this is a LAN9220; the LAN9118 is software compatible
48
* except that it doesn't support the checksum-offload feature.
49
--
50
2.20.1
51
52
diff view generated by jsdifflib
New patch
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
1
2
3
From 'Application Note AN385', chapter 3.9, SPI:
4
5
The SMM implements five PL022 SPI modules.
6
7
Two pairs of modules share the same OR-gated IRQ.
8
9
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
10
Message-id: 20200617072539.32686-12-f4bug@amsat.org
11
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
---
14
hw/arm/mps2.c | 24 ++++++++++++++++++++++++
15
hw/arm/Kconfig | 6 +++---
16
2 files changed, 27 insertions(+), 3 deletions(-)
17
18
diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/hw/arm/mps2.c
21
+++ b/hw/arm/mps2.c
22
@@ -XXX,XX +XXX,XX @@
23
#include "hw/timer/cmsdk-apb-dualtimer.h"
24
#include "hw/misc/mps2-scc.h"
25
#include "hw/misc/mps2-fpgaio.h"
26
+#include "hw/ssi/pl022.h"
27
#include "hw/net/lan9118.h"
28
#include "net/net.h"
29
#include "hw/watchdog/cmsdk-apb-watchdog.h"
30
@@ -XXX,XX +XXX,XX @@ static void mps2_common_init(MachineState *machine)
31
qdev_prop_set_uint32(DEVICE(&mms->fpgaio), "prescale-clk", 25000000);
32
sysbus_realize(SYS_BUS_DEVICE(&mms->fpgaio), &error_fatal);
33
sysbus_mmio_map(SYS_BUS_DEVICE(&mms->fpgaio), 0, 0x40028000);
34
+ sysbus_create_simple(TYPE_PL022, 0x40025000, /* External ADC */
35
+ qdev_get_gpio_in(armv7m, 22));
36
+ for (i = 0; i < 2; i++) {
37
+ static const int spi_irqno[] = {11, 24};
38
+ static const hwaddr spibase[] = {0x40020000, /* APB */
39
+ 0x40021000, /* LCD */
40
+ 0x40026000, /* Shield0 */
41
+ 0x40027000}; /* Shield1 */
42
+ DeviceState *orgate_dev;
43
+ Object *orgate;
44
+ int j;
45
+
46
+ orgate = object_new(TYPE_OR_IRQ);
47
+ object_property_set_int(orgate, 2, "num-lines", &error_fatal);
48
+ orgate_dev = DEVICE(orgate);
49
+ qdev_realize(orgate_dev, NULL, &error_fatal);
50
+ qdev_connect_gpio_out(orgate_dev, 0,
51
+ qdev_get_gpio_in(armv7m, spi_irqno[i]));
52
+ for (j = 0; j < 2; j++) {
53
+ sysbus_create_simple(TYPE_PL022, spibase[2 * i + j],
54
+ qdev_get_gpio_in(orgate_dev, j));
55
+ }
56
+ }
57
58
/* In hardware this is a LAN9220; the LAN9118 is software compatible
59
* except that it doesn't support the checksum-offload feature.
60
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
61
index XXXXXXX..XXXXXXX 100644
62
--- a/hw/arm/Kconfig
63
+++ b/hw/arm/Kconfig
64
@@ -XXX,XX +XXX,XX @@ config HIGHBANK
65
select ARM_TIMER # sp804
66
select ARM_V7M
67
select PL011 # UART
68
- select PL022 # Serial port
69
+ select PL022 # SPI
70
select PL031 # RTC
71
select PL061 # GPIO
72
select PL310 # cache controller
73
@@ -XXX,XX +XXX,XX @@ config STELLARIS
74
select CMSDK_APB_WATCHDOG
75
select I2C
76
select PL011 # UART
77
- select PL022 # Serial port
78
+ select PL022 # SPI
79
select PL061 # GPIO
80
select SSD0303 # OLED display
81
select SSD0323 # OLED display
82
@@ -XXX,XX +XXX,XX @@ config MPS2
83
select MPS2_FPGAIO
84
select MPS2_SCC
85
select OR_IRQ
86
- select PL022 # Serial port
87
+ select PL022 # SPI
88
select PL080 # DMA controller
89
select SPLIT_IRQ
90
select UNIMP
91
--
92
2.20.1
93
94
diff view generated by jsdifflib
New patch
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
1
2
3
From 'Application Note AN385', chapter 3.14:
4
5
The SMM implements a simple SBCon interface based on I2C.
6
7
There are 4 SBCon interfaces on the FPGA APB subsystem.
8
9
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
10
Message-id: 20200617072539.32686-13-f4bug@amsat.org
11
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
---
14
hw/arm/mps2.c | 8 ++++++++
15
hw/arm/Kconfig | 1 +
16
2 files changed, 9 insertions(+)
17
18
diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/hw/arm/mps2.c
21
+++ b/hw/arm/mps2.c
22
@@ -XXX,XX +XXX,XX @@
23
#include "hw/misc/mps2-scc.h"
24
#include "hw/misc/mps2-fpgaio.h"
25
#include "hw/ssi/pl022.h"
26
+#include "hw/i2c/arm_sbcon_i2c.h"
27
#include "hw/net/lan9118.h"
28
#include "net/net.h"
29
#include "hw/watchdog/cmsdk-apb-watchdog.h"
30
@@ -XXX,XX +XXX,XX @@ static void mps2_common_init(MachineState *machine)
31
qdev_get_gpio_in(orgate_dev, j));
32
}
33
}
34
+ for (i = 0; i < 4; i++) {
35
+ static const hwaddr i2cbase[] = {0x40022000, /* Touch */
36
+ 0x40023000, /* Audio */
37
+ 0x40029000, /* Shield0 */
38
+ 0x4002a000}; /* Shield1 */
39
+ sysbus_create_simple(TYPE_ARM_SBCON_I2C, i2cbase[i], NULL);
40
+ }
41
42
/* In hardware this is a LAN9220; the LAN9118 is software compatible
43
* except that it doesn't support the checksum-offload feature.
44
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
45
index XXXXXXX..XXXXXXX 100644
46
--- a/hw/arm/Kconfig
47
+++ b/hw/arm/Kconfig
48
@@ -XXX,XX +XXX,XX @@ config MPS2
49
select SPLIT_IRQ
50
select UNIMP
51
select CMSDK_APB_WATCHDOG
52
+ select VERSATILE_I2C
53
54
config FSL_IMX7
55
bool
56
--
57
2.20.1
58
59
diff view generated by jsdifflib
New patch
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
1
2
3
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
4
Message-id: 20200617072539.32686-14-f4bug@amsat.org
5
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
---
8
hw/arm/mps2.c | 1 +
9
1 file changed, 1 insertion(+)
10
11
diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/hw/arm/mps2.c
14
+++ b/hw/arm/mps2.c
15
@@ -XXX,XX +XXX,XX @@ static void mps2_common_init(MachineState *machine)
16
0x4002a000}; /* Shield1 */
17
sysbus_create_simple(TYPE_ARM_SBCON_I2C, i2cbase[i], NULL);
18
}
19
+ create_unimplemented_device("i2s", 0x40024000, 0x400);
20
21
/* In hardware this is a LAN9220; the LAN9118 is software compatible
22
* except that it doesn't support the checksum-offload feature.
23
--
24
2.20.1
25
26
diff view generated by jsdifflib
New patch
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
1
2
3
From 'Application Note AN521', chapter 4.7:
4
5
The SMM implements four SBCon serial modules:
6
7
One SBCon module for use by the Color LCD touch interface.
8
One SBCon module to configure the audio controller.
9
Two general purpose SBCon modules, that connect to the
10
Expansion headers J7 and J8, are intended for use with the
11
V2C-Shield1 which provide an I2C interface on the headers.
12
13
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
14
Message-id: 20200617072539.32686-15-f4bug@amsat.org
15
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
16
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
17
---
18
hw/arm/mps2-tz.c | 23 ++++++++++++++++++-----
19
1 file changed, 18 insertions(+), 5 deletions(-)
20
21
diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c
22
index XXXXXXX..XXXXXXX 100644
23
--- a/hw/arm/mps2-tz.c
24
+++ b/hw/arm/mps2-tz.c
25
@@ -XXX,XX +XXX,XX @@
26
#include "hw/arm/armsse.h"
27
#include "hw/dma/pl080.h"
28
#include "hw/ssi/pl022.h"
29
+#include "hw/i2c/arm_sbcon_i2c.h"
30
#include "hw/net/lan9118.h"
31
#include "net/net.h"
32
#include "hw/core/split-irq.h"
33
@@ -XXX,XX +XXX,XX @@ typedef struct {
34
TZPPC ppc[5];
35
TZMPC ssram_mpc[3];
36
PL022State spi[5];
37
- UnimplementedDeviceState i2c[4];
38
+ ArmSbconI2CState i2c[4];
39
UnimplementedDeviceState i2s_audio;
40
UnimplementedDeviceState gpio[4];
41
UnimplementedDeviceState gfx;
42
@@ -XXX,XX +XXX,XX @@ static MemoryRegion *make_spi(MPS2TZMachineState *mms, void *opaque,
43
return sysbus_mmio_get_region(s, 0);
44
}
45
46
+static MemoryRegion *make_i2c(MPS2TZMachineState *mms, void *opaque,
47
+ const char *name, hwaddr size)
48
+{
49
+ ArmSbconI2CState *i2c = opaque;
50
+ SysBusDevice *s;
51
+
52
+ object_initialize_child(OBJECT(mms), name, i2c, TYPE_ARM_SBCON_I2C);
53
+ s = SYS_BUS_DEVICE(i2c);
54
+ sysbus_realize(s, &error_fatal);
55
+ return sysbus_mmio_get_region(s, 0);
56
+}
57
+
58
static void mps2tz_common_init(MachineState *machine)
59
{
60
MPS2TZMachineState *mms = MPS2TZ_MACHINE(machine);
61
@@ -XXX,XX +XXX,XX @@ static void mps2tz_common_init(MachineState *machine)
62
{ "uart2", make_uart, &mms->uart[2], 0x40202000, 0x1000 },
63
{ "uart3", make_uart, &mms->uart[3], 0x40203000, 0x1000 },
64
{ "uart4", make_uart, &mms->uart[4], 0x40204000, 0x1000 },
65
- { "i2c0", make_unimp_dev, &mms->i2c[0], 0x40207000, 0x1000 },
66
- { "i2c1", make_unimp_dev, &mms->i2c[1], 0x40208000, 0x1000 },
67
- { "i2c2", make_unimp_dev, &mms->i2c[2], 0x4020c000, 0x1000 },
68
- { "i2c3", make_unimp_dev, &mms->i2c[3], 0x4020d000, 0x1000 },
69
+ { "i2c0", make_i2c, &mms->i2c[0], 0x40207000, 0x1000 },
70
+ { "i2c1", make_i2c, &mms->i2c[1], 0x40208000, 0x1000 },
71
+ { "i2c2", make_i2c, &mms->i2c[2], 0x4020c000, 0x1000 },
72
+ { "i2c3", make_i2c, &mms->i2c[3], 0x4020d000, 0x1000 },
73
},
74
}, {
75
.name = "apb_ppcexp2",
76
--
77
2.20.1
78
79
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
2
2
3
Per Peter Maydell:
3
Since commit d70c996df23f, when enabling the PMU we get:
4
4
5
Semihosting hooks either SVC or HLT instructions, and inside KVM
5
$ qemu-system-aarch64 -cpu host,pmu=on -M virt,accel=kvm,gic-version=3
6
both of those go to EL1, ie to the guest, and can't be trapped to
6
Segmentation fault (core dumped)
7
KVM.
7
8
8
Thread 1 "qemu-system-aar" received signal SIGSEGV, Segmentation fault.
9
Let check_for_semihosting() return False when not running on TCG.
9
0x0000aaaaaae356d0 in kvm_ioctl (s=0x0, type=44547) at accel/kvm/kvm-all.c:2588
10
10
2588 ret = ioctl(s->fd, type, arg);
11
(gdb) bt
12
#0 0x0000aaaaaae356d0 in kvm_ioctl (s=0x0, type=44547) at accel/kvm/kvm-all.c:2588
13
#1 0x0000aaaaaae31568 in kvm_check_extension (s=0x0, extension=126) at accel/kvm/kvm-all.c:916
14
#2 0x0000aaaaaafce254 in kvm_arm_pmu_supported (cpu=0xaaaaac214ab0) at target/arm/kvm.c:213
15
#3 0x0000aaaaaafc0f94 in arm_set_pmu (obj=0xaaaaac214ab0, value=true, errp=0xffffffffe438) at target/arm/cpu.c:1111
16
#4 0x0000aaaaab5533ac in property_set_bool (obj=0xaaaaac214ab0, v=0xaaaaac223a80, name=0xaaaaac11a970 "pmu", opaque=0xaaaaac222730, errp=0xffffffffe438) at qom/object.c:2170
17
#5 0x0000aaaaab5512f0 in object_property_set (obj=0xaaaaac214ab0, v=0xaaaaac223a80, name=0xaaaaac11a970 "pmu", errp=0xffffffffe438) at qom/object.c:1328
18
#6 0x0000aaaaab551e10 in object_property_parse (obj=0xaaaaac214ab0, string=0xaaaaac11b4c0 "on", name=0xaaaaac11a970 "pmu", errp=0xffffffffe438) at qom/object.c:1561
19
#7 0x0000aaaaab54ee8c in object_apply_global_props (obj=0xaaaaac214ab0, props=0xaaaaac018e20, errp=0xaaaaabd6fd88 <error_fatal>) at qom/object.c:407
20
#8 0x0000aaaaab1dd5a4 in qdev_prop_set_globals (dev=0xaaaaac214ab0) at hw/core/qdev-properties.c:1218
21
#9 0x0000aaaaab1d9fac in device_post_init (obj=0xaaaaac214ab0) at hw/core/qdev.c:1050
22
...
23
#15 0x0000aaaaab54f310 in object_initialize_with_type (obj=0xaaaaac214ab0, size=52208, type=0xaaaaabe237f0) at qom/object.c:512
24
#16 0x0000aaaaab54fa24 in object_new_with_type (type=0xaaaaabe237f0) at qom/object.c:687
25
#17 0x0000aaaaab54fa80 in object_new (typename=0xaaaaabe23970 "host-arm-cpu") at qom/object.c:702
26
#18 0x0000aaaaaaf04a74 in machvirt_init (machine=0xaaaaac0a8550) at hw/arm/virt.c:1770
27
#19 0x0000aaaaab1e8720 in machine_run_board_init (machine=0xaaaaac0a8550) at hw/core/machine.c:1138
28
#20 0x0000aaaaaaf95394 in qemu_init (argc=5, argv=0xffffffffea58, envp=0xffffffffea88) at softmmu/vl.c:4348
29
#21 0x0000aaaaaada3f74 in main (argc=<optimized out>, argv=<optimized out>, envp=<optimized out>) at softmmu/main.c:48
30
31
This is because in frame #2, cpu->kvm_state is still NULL
32
(the vCPU is not yet realized).
33
34
KVM has a hard requirement of all cores supporting the same
35
feature set. We only need to check if the accelerator supports
36
a feature, not each vCPU individually.
37
38
Fix by removing the 'CPUState *cpu' argument from the
39
kvm_arm_<FEATURE>_supported() functions.
40
41
Fixes: d70c996df23f ('Use CPUState::kvm_state in kvm_arm_pmu_supported')
42
Reported-by: Haibo Xu <haibo.xu@linaro.org>
43
Reviewed-by: Andrew Jones <drjones@redhat.com>
44
Acked-by: Paolo Bonzini <pbonzini@redhat.com>
11
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
45
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
12
Message-id: 20190701194942.10092-3-philmd@redhat.com
46
Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
13
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
47
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
14
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
48
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
---
49
---
16
target/arm/Makefile.objs | 2 +-
50
target/arm/kvm_arm.h | 21 +++++++++------------
17
target/arm/cpu.h | 7 +++++++
51
target/arm/cpu.c | 2 +-
18
target/arm/helper.c | 8 +++++++-
52
target/arm/cpu64.c | 10 +++++-----
19
3 files changed, 15 insertions(+), 2 deletions(-)
53
target/arm/kvm.c | 4 ++--
20
54
target/arm/kvm64.c | 14 +++++---------
21
diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs
55
5 files changed, 22 insertions(+), 29 deletions(-)
22
index XXXXXXX..XXXXXXX 100644
56
23
--- a/target/arm/Makefile.objs
57
diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
24
+++ b/target/arm/Makefile.objs
58
index XXXXXXX..XXXXXXX 100644
25
@@ -XXX,XX +XXX,XX @@
59
--- a/target/arm/kvm_arm.h
26
-obj-y += arm-semi.o
60
+++ b/target/arm/kvm_arm.h
27
+obj-$(CONFIG_TCG) += arm-semi.o
61
@@ -XXX,XX +XXX,XX @@ void kvm_arm_add_vcpu_properties(Object *obj);
28
obj-y += helper.o vfp_helper.o
62
29
obj-y += cpu.o gdbstub.o
63
/**
30
obj-$(TARGET_AARCH64) += cpu64.o gdbstub64.o
64
* kvm_arm_aarch32_supported:
31
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
65
- * @cs: CPUState
32
index XXXXXXX..XXXXXXX 100644
66
*
33
--- a/target/arm/cpu.h
67
- * Returns: true if the KVM VCPU can enable AArch32 mode
34
+++ b/target/arm/cpu.h
68
+ * Returns: true if KVM can enable AArch32 mode
35
@@ -XXX,XX +XXX,XX @@ static inline void aarch64_sve_change_el(CPUARMState *env, int o,
69
* and false otherwise.
36
{ }
70
*/
37
#endif
71
-bool kvm_arm_aarch32_supported(CPUState *cs);
38
72
+bool kvm_arm_aarch32_supported(void);
39
+#if !defined(CONFIG_TCG)
73
40
+static inline target_ulong do_arm_semihosting(CPUARMState *env)
74
/**
41
+{
75
* kvm_arm_pmu_supported:
42
+ g_assert_not_reached();
76
- * @cs: CPUState
43
+}
77
*
44
+#else
78
- * Returns: true if the KVM VCPU can enable its PMU
45
target_ulong do_arm_semihosting(CPUARMState *env);
79
+ * Returns: true if KVM can enable the PMU
46
+#endif
80
* and false otherwise.
47
void aarch64_sync_32_to_64(CPUARMState *env);
81
*/
48
void aarch64_sync_64_to_32(CPUARMState *env);
82
-bool kvm_arm_pmu_supported(CPUState *cs);
49
83
+bool kvm_arm_pmu_supported(void);
50
diff --git a/target/arm/helper.c b/target/arm/helper.c
84
51
index XXXXXXX..XXXXXXX 100644
85
/**
52
--- a/target/arm/helper.c
86
* kvm_arm_sve_supported:
53
+++ b/target/arm/helper.c
87
- * @cs: CPUState
54
@@ -XXX,XX +XXX,XX @@
88
*
55
#include "qemu/qemu-print.h"
89
- * Returns true if the KVM VCPU can enable SVE and false otherwise.
56
#include "exec/exec-all.h"
90
+ * Returns true if KVM can enable SVE and false otherwise.
57
#include "exec/cpu_ldst.h"
91
*/
58
-#include "arm_ldst.h"
92
-bool kvm_arm_sve_supported(CPUState *cs);
59
#include <zlib.h> /* For crc32 */
93
+bool kvm_arm_sve_supported(void);
60
#include "hw/semihosting/semihost.h"
94
61
#include "sysemu/cpus.h"
95
/**
62
@@ -XXX,XX +XXX,XX @@
96
* kvm_arm_get_max_vm_ipa_size:
63
#include "qapi/qapi-commands-machine-target.h"
97
@@ -XXX,XX +XXX,XX @@ static inline void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu)
64
#include "qapi/error.h"
98
65
#include "qemu/guest-random.h"
99
static inline void kvm_arm_add_vcpu_properties(Object *obj) {}
66
+#ifdef CONFIG_TCG
100
67
+#include "arm_ldst.h"
101
-static inline bool kvm_arm_aarch32_supported(CPUState *cs)
68
+#endif
102
+static inline bool kvm_arm_aarch32_supported(void)
69
103
{
70
#define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */
104
return false;
71
105
}
72
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs)
106
73
107
-static inline bool kvm_arm_pmu_supported(CPUState *cs)
74
static inline bool check_for_semihosting(CPUState *cs)
108
+static inline bool kvm_arm_pmu_supported(void)
75
{
109
{
76
+#ifdef CONFIG_TCG
110
return false;
77
/* Check whether this exception is a semihosting call; if so
111
}
78
* then handle it and return true; otherwise return false.
112
113
-static inline bool kvm_arm_sve_supported(CPUState *cs)
114
+static inline bool kvm_arm_sve_supported(void)
115
{
116
return false;
117
}
118
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
119
index XXXXXXX..XXXXXXX 100644
120
--- a/target/arm/cpu.c
121
+++ b/target/arm/cpu.c
122
@@ -XXX,XX +XXX,XX @@ static void arm_set_pmu(Object *obj, bool value, Error **errp)
123
ARMCPU *cpu = ARM_CPU(obj);
124
125
if (value) {
126
- if (kvm_enabled() && !kvm_arm_pmu_supported(CPU(cpu))) {
127
+ if (kvm_enabled() && !kvm_arm_pmu_supported()) {
128
error_setg(errp, "'pmu' feature not supported by KVM on this host");
129
return;
130
}
131
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
132
index XXXXXXX..XXXXXXX 100644
133
--- a/target/arm/cpu64.c
134
+++ b/target/arm/cpu64.c
135
@@ -XXX,XX +XXX,XX @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
136
137
/* Collect the set of vector lengths supported by KVM. */
138
bitmap_zero(kvm_supported, ARM_MAX_VQ);
139
- if (kvm_enabled() && kvm_arm_sve_supported(CPU(cpu))) {
140
+ if (kvm_enabled() && kvm_arm_sve_supported()) {
141
kvm_arm_sve_get_vls(CPU(cpu), kvm_supported);
142
} else if (kvm_enabled()) {
143
assert(!cpu_isar_feature(aa64_sve, cpu));
144
@@ -XXX,XX +XXX,XX @@ static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name,
145
return;
146
}
147
148
- if (kvm_enabled() && !kvm_arm_sve_supported(CPU(cpu))) {
149
+ if (kvm_enabled() && !kvm_arm_sve_supported()) {
150
error_setg(errp, "cannot set sve-max-vq");
151
error_append_hint(errp, "SVE not supported by KVM on this host\n");
152
return;
153
@@ -XXX,XX +XXX,XX @@ static void cpu_arm_set_sve_vq(Object *obj, Visitor *v, const char *name,
154
return;
155
}
156
157
- if (value && kvm_enabled() && !kvm_arm_sve_supported(CPU(cpu))) {
158
+ if (value && kvm_enabled() && !kvm_arm_sve_supported()) {
159
error_setg(errp, "cannot enable %s", name);
160
error_append_hint(errp, "SVE not supported by KVM on this host\n");
161
return;
162
@@ -XXX,XX +XXX,XX @@ static void cpu_arm_set_sve(Object *obj, Visitor *v, const char *name,
163
return;
164
}
165
166
- if (value && kvm_enabled() && !kvm_arm_sve_supported(CPU(cpu))) {
167
+ if (value && kvm_enabled() && !kvm_arm_sve_supported()) {
168
error_setg(errp, "'sve' feature not supported by KVM on this host");
169
return;
170
}
171
@@ -XXX,XX +XXX,XX @@ static void aarch64_cpu_set_aarch64(Object *obj, bool value, Error **errp)
172
* uniform execution state like do_interrupt.
79
*/
173
*/
80
@@ -XXX,XX +XXX,XX @@ static inline bool check_for_semihosting(CPUState *cs)
174
if (value == false) {
81
env->regs[0] = do_arm_semihosting(env);
175
- if (!kvm_enabled() || !kvm_arm_aarch32_supported(CPU(cpu))) {
82
return true;
176
+ if (!kvm_enabled() || !kvm_arm_aarch32_supported()) {
83
}
177
error_setg(errp, "'aarch64' feature cannot be disabled "
84
+#else
178
"unless KVM is enabled and 32-bit EL1 "
85
+ return false;
179
"is supported");
86
+#endif
180
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
87
}
181
index XXXXXXX..XXXXXXX 100644
88
182
--- a/target/arm/kvm.c
89
/* Handle a CPU exception for A and R profile CPUs.
183
+++ b/target/arm/kvm.c
184
@@ -XXX,XX +XXX,XX @@ void kvm_arm_add_vcpu_properties(Object *obj)
185
}
186
}
187
188
-bool kvm_arm_pmu_supported(CPUState *cpu)
189
+bool kvm_arm_pmu_supported(void)
190
{
191
- return kvm_check_extension(cpu->kvm_state, KVM_CAP_ARM_PMU_V3);
192
+ return kvm_check_extension(kvm_state, KVM_CAP_ARM_PMU_V3);
193
}
194
195
int kvm_arm_get_max_vm_ipa_size(MachineState *ms)
196
diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
197
index XXXXXXX..XXXXXXX 100644
198
--- a/target/arm/kvm64.c
199
+++ b/target/arm/kvm64.c
200
@@ -XXX,XX +XXX,XX @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
201
return true;
202
}
203
204
-bool kvm_arm_aarch32_supported(CPUState *cpu)
205
+bool kvm_arm_aarch32_supported(void)
206
{
207
- KVMState *s = KVM_STATE(current_accel());
208
-
209
- return kvm_check_extension(s, KVM_CAP_ARM_EL1_32BIT);
210
+ return kvm_check_extension(kvm_state, KVM_CAP_ARM_EL1_32BIT);
211
}
212
213
-bool kvm_arm_sve_supported(CPUState *cpu)
214
+bool kvm_arm_sve_supported(void)
215
{
216
- KVMState *s = KVM_STATE(current_accel());
217
-
218
- return kvm_check_extension(s, KVM_CAP_ARM_SVE);
219
+ return kvm_check_extension(kvm_state, KVM_CAP_ARM_SVE);
220
}
221
222
QEMU_BUILD_BUG_ON(KVM_ARM64_SVE_VQ_MIN != 1);
223
@@ -XXX,XX +XXX,XX @@ int kvm_arch_init_vcpu(CPUState *cs)
224
env->features &= ~(1ULL << ARM_FEATURE_PMU);
225
}
226
if (cpu_isar_feature(aa64_sve, cpu)) {
227
- assert(kvm_arm_sve_supported(cs));
228
+ assert(kvm_arm_sve_supported());
229
cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_SVE;
230
}
231
90
--
232
--
91
2.20.1
233
2.20.1
92
234
93
235
diff view generated by jsdifflib
New patch
1
From: Andrew Jones <drjones@redhat.com>
1
2
3
Some cpu features may be enabled and disabled for all configurations
4
that support the feature. Let's test that.
5
6
A recent regression[*] inspired adding these tests.
7
8
[*] '-cpu host,pmu=on' caused a segfault
9
10
Signed-off-by: Andrew Jones <drjones@redhat.com>
11
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
12
Message-id: 20200623090622.30365-2-philmd@redhat.com
13
Message-Id: <20200623082310.17577-1-drjones@redhat.com>
14
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
---
17
tests/qtest/arm-cpu-features.c | 38 ++++++++++++++++++++++++++++++----
18
1 file changed, 34 insertions(+), 4 deletions(-)
19
20
diff --git a/tests/qtest/arm-cpu-features.c b/tests/qtest/arm-cpu-features.c
21
index XXXXXXX..XXXXXXX 100644
22
--- a/tests/qtest/arm-cpu-features.c
23
+++ b/tests/qtest/arm-cpu-features.c
24
@@ -XXX,XX +XXX,XX @@ static bool resp_get_feature(QDict *resp, const char *feature)
25
qobject_unref(_resp); \
26
})
27
28
-#define assert_feature(qts, cpu_type, feature, expected_value) \
29
+#define resp_assert_feature(resp, feature, expected_value) \
30
({ \
31
- QDict *_resp, *_props; \
32
+ QDict *_props; \
33
\
34
- _resp = do_query_no_props(qts, cpu_type); \
35
g_assert(_resp); \
36
g_assert(resp_has_props(_resp)); \
37
_props = resp_get_props(_resp); \
38
g_assert(qdict_get(_props, feature)); \
39
g_assert(qdict_get_bool(_props, feature) == (expected_value)); \
40
+})
41
+
42
+#define assert_feature(qts, cpu_type, feature, expected_value) \
43
+({ \
44
+ QDict *_resp; \
45
+ \
46
+ _resp = do_query_no_props(qts, cpu_type); \
47
+ g_assert(_resp); \
48
+ resp_assert_feature(_resp, feature, expected_value); \
49
+ qobject_unref(_resp); \
50
+})
51
+
52
+#define assert_set_feature(qts, cpu_type, feature, value) \
53
+({ \
54
+ const char *_fmt = (value) ? "{ %s: true }" : "{ %s: false }"; \
55
+ QDict *_resp; \
56
+ \
57
+ _resp = do_query(qts, cpu_type, _fmt, feature); \
58
+ g_assert(_resp); \
59
+ resp_assert_feature(_resp, feature, value); \
60
qobject_unref(_resp); \
61
})
62
63
@@ -XXX,XX +XXX,XX @@ static void test_query_cpu_model_expansion(const void *data)
64
assert_error(qts, "host", "The CPU type 'host' requires KVM", NULL);
65
66
/* Test expected feature presence/absence for some cpu types */
67
- assert_has_feature_enabled(qts, "max", "pmu");
68
assert_has_feature_enabled(qts, "cortex-a15", "pmu");
69
assert_has_not_feature(qts, "cortex-a15", "aarch64");
70
71
+ /* Enabling and disabling pmu should always work. */
72
+ assert_has_feature_enabled(qts, "max", "pmu");
73
+ assert_set_feature(qts, "max", "pmu", false);
74
+ assert_set_feature(qts, "max", "pmu", true);
75
+
76
assert_has_not_feature(qts, "max", "kvm-no-adjvtime");
77
78
if (g_str_equal(qtest_get_arch(), "aarch64")) {
79
@@ -XXX,XX +XXX,XX @@ static void test_query_cpu_model_expansion_kvm(const void *data)
80
return;
81
}
82
83
+ /* Enabling and disabling kvm-no-adjvtime should always work. */
84
assert_has_feature_disabled(qts, "host", "kvm-no-adjvtime");
85
+ assert_set_feature(qts, "host", "kvm-no-adjvtime", true);
86
+ assert_set_feature(qts, "host", "kvm-no-adjvtime", false);
87
88
if (g_str_equal(qtest_get_arch(), "aarch64")) {
89
bool kvm_supports_sve;
90
@@ -XXX,XX +XXX,XX @@ static void test_query_cpu_model_expansion_kvm(const void *data)
91
char *error;
92
93
assert_has_feature_enabled(qts, "host", "aarch64");
94
+
95
+ /* Enabling and disabling pmu should always work. */
96
assert_has_feature_enabled(qts, "host", "pmu");
97
+ assert_set_feature(qts, "host", "pmu", false);
98
+ assert_set_feature(qts, "host", "pmu", true);
99
100
assert_error(qts, "cortex-a15",
101
"We cannot guarantee the CPU type 'cortex-a15' works "
102
--
103
2.20.1
104
105
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
2
2
3
In preparation for supporting TCG disablement on ARM, we move most
3
This adds support for memory(pc-dimm) hot remove on arm/virt that
4
of TCG related v7m/v8m helpers and APIs into their own file.
4
uses acpi ged device.
5
5
6
Note: It is easier to review this commit using the 'histogram'
6
NVDIMM hot removal is not yet supported.
7
diff algorithm:
8
7
9
$ git diff --diff-algorithm=histogram ...
8
Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
10
or
9
Message-id: 20200622124157.20360-1-shameerali.kolothum.thodi@huawei.com
11
$ git diff --histogram ...
10
Reviewed-by: Eric Auger <eric.auger@redhat.com>
12
11
Tested-by: Eric Auger <eric.auger@redhat.com>
13
Suggested-by: Samuel Ortiz <sameo@linux.intel.com>
14
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
15
Message-id: 20190702144335.10717-2-philmd@redhat.com
16
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
17
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
18
---
13
---
19
target/arm/Makefile.objs | 1 +
14
hw/acpi/generic_event_device.c | 29 ++++++++++++++++
20
target/arm/helper.c | 2638 +------------------------------------
15
hw/arm/virt.c | 62 ++++++++++++++++++++++++++++++++--
21
target/arm/m_helper.c | 2676 ++++++++++++++++++++++++++++++++++++++
16
2 files changed, 89 insertions(+), 2 deletions(-)
22
3 files changed, 2681 insertions(+), 2634 deletions(-)
23
create mode 100644 target/arm/m_helper.c
24
17
25
diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs
18
diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c
26
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
27
--- a/target/arm/Makefile.objs
20
--- a/hw/acpi/generic_event_device.c
28
+++ b/target/arm/Makefile.objs
21
+++ b/hw/acpi/generic_event_device.c
29
@@ -XXX,XX +XXX,XX @@ obj-y += tlb_helper.o debug_helper.o
22
@@ -XXX,XX +XXX,XX @@ static void acpi_ged_device_plug_cb(HotplugHandler *hotplug_dev,
30
obj-y += translate.o op_helper.o
31
obj-y += crypto_helper.o
32
obj-y += iwmmxt_helper.o vec_helper.o neon_helper.o
33
+obj-y += m_helper.o
34
35
obj-$(CONFIG_SOFTMMU) += psci.o
36
37
diff --git a/target/arm/helper.c b/target/arm/helper.c
38
index XXXXXXX..XXXXXXX 100644
39
--- a/target/arm/helper.c
40
+++ b/target/arm/helper.c
41
@@ -XXX,XX +XXX,XX @@
42
#include "qemu/crc32c.h"
43
#include "qemu/qemu-print.h"
44
#include "exec/exec-all.h"
45
-#include "exec/cpu_ldst.h"
46
#include <zlib.h> /* For crc32 */
47
#include "hw/semihosting/semihost.h"
48
#include "sysemu/cpus.h"
49
@@ -XXX,XX +XXX,XX @@
50
#include "qemu/guest-random.h"
51
#ifdef CONFIG_TCG
52
#include "arm_ldst.h"
53
+#include "exec/cpu_ldst.h"
54
#endif
55
56
#define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */
57
@@ -XXX,XX +XXX,XX @@ uint32_t HELPER(rbit)(uint32_t x)
58
59
#ifdef CONFIG_USER_ONLY
60
61
-/* These should probably raise undefined insn exceptions. */
62
-void HELPER(v7m_msr)(CPUARMState *env, uint32_t reg, uint32_t val)
63
-{
64
- ARMCPU *cpu = env_archcpu(env);
65
-
66
- cpu_abort(CPU(cpu), "v7m_msr %d\n", reg);
67
-}
68
-
69
-uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
70
-{
71
- ARMCPU *cpu = env_archcpu(env);
72
-
73
- cpu_abort(CPU(cpu), "v7m_mrs %d\n", reg);
74
- return 0;
75
-}
76
-
77
-void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest)
78
-{
79
- /* translate.c should never generate calls here in user-only mode */
80
- g_assert_not_reached();
81
-}
82
-
83
-void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest)
84
-{
85
- /* translate.c should never generate calls here in user-only mode */
86
- g_assert_not_reached();
87
-}
88
-
89
-void HELPER(v7m_preserve_fp_state)(CPUARMState *env)
90
-{
91
- /* translate.c should never generate calls here in user-only mode */
92
- g_assert_not_reached();
93
-}
94
-
95
-void HELPER(v7m_vlstm)(CPUARMState *env, uint32_t fptr)
96
-{
97
- /* translate.c should never generate calls here in user-only mode */
98
- g_assert_not_reached();
99
-}
100
-
101
-void HELPER(v7m_vlldm)(CPUARMState *env, uint32_t fptr)
102
-{
103
- /* translate.c should never generate calls here in user-only mode */
104
- g_assert_not_reached();
105
-}
106
-
107
-uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
108
-{
109
- /*
110
- * The TT instructions can be used by unprivileged code, but in
111
- * user-only emulation we don't have the MPU.
112
- * Luckily since we know we are NonSecure unprivileged (and that in
113
- * turn means that the A flag wasn't specified), all the bits in the
114
- * register must be zero:
115
- * IREGION: 0 because IRVALID is 0
116
- * IRVALID: 0 because NS
117
- * S: 0 because NS
118
- * NSRW: 0 because NS
119
- * NSR: 0 because NS
120
- * RW: 0 because unpriv and A flag not set
121
- * R: 0 because unpriv and A flag not set
122
- * SRVALID: 0 because NS
123
- * MRVALID: 0 because unpriv and A flag not set
124
- * SREGION: 0 becaus SRVALID is 0
125
- * MREGION: 0 because MRVALID is 0
126
- */
127
- return 0;
128
-}
129
-
130
static void switch_mode(CPUARMState *env, int mode)
131
{
132
ARMCPU *cpu = env_archcpu(env);
133
@@ -XXX,XX +XXX,XX @@ void arm_log_exception(int idx)
134
}
23
}
135
}
24
}
136
25
137
-/*
26
+static void acpi_ged_unplug_request_cb(HotplugHandler *hotplug_dev,
138
- * What kind of stack write are we doing? This affects how exceptions
27
+ DeviceState *dev, Error **errp)
139
- * generated during the stacking are treated.
28
+{
140
- */
29
+ AcpiGedState *s = ACPI_GED(hotplug_dev);
141
-typedef enum StackingMode {
142
- STACK_NORMAL,
143
- STACK_IGNFAULTS,
144
- STACK_LAZYFP,
145
-} StackingMode;
146
-
147
-static bool v7m_stack_write(ARMCPU *cpu, uint32_t addr, uint32_t value,
148
- ARMMMUIdx mmu_idx, StackingMode mode)
149
-{
150
- CPUState *cs = CPU(cpu);
151
- CPUARMState *env = &cpu->env;
152
- MemTxAttrs attrs = {};
153
- MemTxResult txres;
154
- target_ulong page_size;
155
- hwaddr physaddr;
156
- int prot;
157
- ARMMMUFaultInfo fi = {};
158
- bool secure = mmu_idx & ARM_MMU_IDX_M_S;
159
- int exc;
160
- bool exc_secure;
161
-
162
- if (get_phys_addr(env, addr, MMU_DATA_STORE, mmu_idx, &physaddr,
163
- &attrs, &prot, &page_size, &fi, NULL)) {
164
- /* MPU/SAU lookup failed */
165
- if (fi.type == ARMFault_QEMU_SFault) {
166
- if (mode == STACK_LAZYFP) {
167
- qemu_log_mask(CPU_LOG_INT,
168
- "...SecureFault with SFSR.LSPERR "
169
- "during lazy stacking\n");
170
- env->v7m.sfsr |= R_V7M_SFSR_LSPERR_MASK;
171
- } else {
172
- qemu_log_mask(CPU_LOG_INT,
173
- "...SecureFault with SFSR.AUVIOL "
174
- "during stacking\n");
175
- env->v7m.sfsr |= R_V7M_SFSR_AUVIOL_MASK;
176
- }
177
- env->v7m.sfsr |= R_V7M_SFSR_SFARVALID_MASK;
178
- env->v7m.sfar = addr;
179
- exc = ARMV7M_EXCP_SECURE;
180
- exc_secure = false;
181
- } else {
182
- if (mode == STACK_LAZYFP) {
183
- qemu_log_mask(CPU_LOG_INT,
184
- "...MemManageFault with CFSR.MLSPERR\n");
185
- env->v7m.cfsr[secure] |= R_V7M_CFSR_MLSPERR_MASK;
186
- } else {
187
- qemu_log_mask(CPU_LOG_INT,
188
- "...MemManageFault with CFSR.MSTKERR\n");
189
- env->v7m.cfsr[secure] |= R_V7M_CFSR_MSTKERR_MASK;
190
- }
191
- exc = ARMV7M_EXCP_MEM;
192
- exc_secure = secure;
193
- }
194
- goto pend_fault;
195
- }
196
- address_space_stl_le(arm_addressspace(cs, attrs), physaddr, value,
197
- attrs, &txres);
198
- if (txres != MEMTX_OK) {
199
- /* BusFault trying to write the data */
200
- if (mode == STACK_LAZYFP) {
201
- qemu_log_mask(CPU_LOG_INT, "...BusFault with BFSR.LSPERR\n");
202
- env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_LSPERR_MASK;
203
- } else {
204
- qemu_log_mask(CPU_LOG_INT, "...BusFault with BFSR.STKERR\n");
205
- env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_STKERR_MASK;
206
- }
207
- exc = ARMV7M_EXCP_BUS;
208
- exc_secure = false;
209
- goto pend_fault;
210
- }
211
- return true;
212
-
213
-pend_fault:
214
- /*
215
- * By pending the exception at this point we are making
216
- * the IMPDEF choice "overridden exceptions pended" (see the
217
- * MergeExcInfo() pseudocode). The other choice would be to not
218
- * pend them now and then make a choice about which to throw away
219
- * later if we have two derived exceptions.
220
- * The only case when we must not pend the exception but instead
221
- * throw it away is if we are doing the push of the callee registers
222
- * and we've already generated a derived exception (this is indicated
223
- * by the caller passing STACK_IGNFAULTS). Even in this case we will
224
- * still update the fault status registers.
225
- */
226
- switch (mode) {
227
- case STACK_NORMAL:
228
- armv7m_nvic_set_pending_derived(env->nvic, exc, exc_secure);
229
- break;
230
- case STACK_LAZYFP:
231
- armv7m_nvic_set_pending_lazyfp(env->nvic, exc, exc_secure);
232
- break;
233
- case STACK_IGNFAULTS:
234
- break;
235
- }
236
- return false;
237
-}
238
-
239
-static bool v7m_stack_read(ARMCPU *cpu, uint32_t *dest, uint32_t addr,
240
- ARMMMUIdx mmu_idx)
241
-{
242
- CPUState *cs = CPU(cpu);
243
- CPUARMState *env = &cpu->env;
244
- MemTxAttrs attrs = {};
245
- MemTxResult txres;
246
- target_ulong page_size;
247
- hwaddr physaddr;
248
- int prot;
249
- ARMMMUFaultInfo fi = {};
250
- bool secure = mmu_idx & ARM_MMU_IDX_M_S;
251
- int exc;
252
- bool exc_secure;
253
- uint32_t value;
254
-
255
- if (get_phys_addr(env, addr, MMU_DATA_LOAD, mmu_idx, &physaddr,
256
- &attrs, &prot, &page_size, &fi, NULL)) {
257
- /* MPU/SAU lookup failed */
258
- if (fi.type == ARMFault_QEMU_SFault) {
259
- qemu_log_mask(CPU_LOG_INT,
260
- "...SecureFault with SFSR.AUVIOL during unstack\n");
261
- env->v7m.sfsr |= R_V7M_SFSR_AUVIOL_MASK | R_V7M_SFSR_SFARVALID_MASK;
262
- env->v7m.sfar = addr;
263
- exc = ARMV7M_EXCP_SECURE;
264
- exc_secure = false;
265
- } else {
266
- qemu_log_mask(CPU_LOG_INT,
267
- "...MemManageFault with CFSR.MUNSTKERR\n");
268
- env->v7m.cfsr[secure] |= R_V7M_CFSR_MUNSTKERR_MASK;
269
- exc = ARMV7M_EXCP_MEM;
270
- exc_secure = secure;
271
- }
272
- goto pend_fault;
273
- }
274
-
275
- value = address_space_ldl(arm_addressspace(cs, attrs), physaddr,
276
- attrs, &txres);
277
- if (txres != MEMTX_OK) {
278
- /* BusFault trying to read the data */
279
- qemu_log_mask(CPU_LOG_INT, "...BusFault with BFSR.UNSTKERR\n");
280
- env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_UNSTKERR_MASK;
281
- exc = ARMV7M_EXCP_BUS;
282
- exc_secure = false;
283
- goto pend_fault;
284
- }
285
-
286
- *dest = value;
287
- return true;
288
-
289
-pend_fault:
290
- /*
291
- * By pending the exception at this point we are making
292
- * the IMPDEF choice "overridden exceptions pended" (see the
293
- * MergeExcInfo() pseudocode). The other choice would be to not
294
- * pend them now and then make a choice about which to throw away
295
- * later if we have two derived exceptions.
296
- */
297
- armv7m_nvic_set_pending(env->nvic, exc, exc_secure);
298
- return false;
299
-}
300
-
301
-void HELPER(v7m_preserve_fp_state)(CPUARMState *env)
302
-{
303
- /*
304
- * Preserve FP state (because LSPACT was set and we are about
305
- * to execute an FP instruction). This corresponds to the
306
- * PreserveFPState() pseudocode.
307
- * We may throw an exception if the stacking fails.
308
- */
309
- ARMCPU *cpu = env_archcpu(env);
310
- bool is_secure = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK;
311
- bool negpri = !(env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_HFRDY_MASK);
312
- bool is_priv = !(env->v7m.fpccr[is_secure] & R_V7M_FPCCR_USER_MASK);
313
- bool splimviol = env->v7m.fpccr[is_secure] & R_V7M_FPCCR_SPLIMVIOL_MASK;
314
- uint32_t fpcar = env->v7m.fpcar[is_secure];
315
- bool stacked_ok = true;
316
- bool ts = is_secure && (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK);
317
- bool take_exception;
318
-
319
- /* Take the iothread lock as we are going to touch the NVIC */
320
- qemu_mutex_lock_iothread();
321
-
322
- /* Check the background context had access to the FPU */
323
- if (!v7m_cpacr_pass(env, is_secure, is_priv)) {
324
- armv7m_nvic_set_pending_lazyfp(env->nvic, ARMV7M_EXCP_USAGE, is_secure);
325
- env->v7m.cfsr[is_secure] |= R_V7M_CFSR_NOCP_MASK;
326
- stacked_ok = false;
327
- } else if (!is_secure && !extract32(env->v7m.nsacr, 10, 1)) {
328
- armv7m_nvic_set_pending_lazyfp(env->nvic, ARMV7M_EXCP_USAGE, M_REG_S);
329
- env->v7m.cfsr[M_REG_S] |= R_V7M_CFSR_NOCP_MASK;
330
- stacked_ok = false;
331
- }
332
-
333
- if (!splimviol && stacked_ok) {
334
- /* We only stack if the stack limit wasn't violated */
335
- int i;
336
- ARMMMUIdx mmu_idx;
337
-
338
- mmu_idx = arm_v7m_mmu_idx_all(env, is_secure, is_priv, negpri);
339
- for (i = 0; i < (ts ? 32 : 16); i += 2) {
340
- uint64_t dn = *aa32_vfp_dreg(env, i / 2);
341
- uint32_t faddr = fpcar + 4 * i;
342
- uint32_t slo = extract64(dn, 0, 32);
343
- uint32_t shi = extract64(dn, 32, 32);
344
-
345
- if (i >= 16) {
346
- faddr += 8; /* skip the slot for the FPSCR */
347
- }
348
- stacked_ok = stacked_ok &&
349
- v7m_stack_write(cpu, faddr, slo, mmu_idx, STACK_LAZYFP) &&
350
- v7m_stack_write(cpu, faddr + 4, shi, mmu_idx, STACK_LAZYFP);
351
- }
352
-
353
- stacked_ok = stacked_ok &&
354
- v7m_stack_write(cpu, fpcar + 0x40,
355
- vfp_get_fpscr(env), mmu_idx, STACK_LAZYFP);
356
- }
357
-
358
- /*
359
- * We definitely pended an exception, but it's possible that it
360
- * might not be able to be taken now. If its priority permits us
361
- * to take it now, then we must not update the LSPACT or FP regs,
362
- * but instead jump out to take the exception immediately.
363
- * If it's just pending and won't be taken until the current
364
- * handler exits, then we do update LSPACT and the FP regs.
365
- */
366
- take_exception = !stacked_ok &&
367
- armv7m_nvic_can_take_pending_exception(env->nvic);
368
-
369
- qemu_mutex_unlock_iothread();
370
-
371
- if (take_exception) {
372
- raise_exception_ra(env, EXCP_LAZYFP, 0, 1, GETPC());
373
- }
374
-
375
- env->v7m.fpccr[is_secure] &= ~R_V7M_FPCCR_LSPACT_MASK;
376
-
377
- if (ts) {
378
- /* Clear s0 to s31 and the FPSCR */
379
- int i;
380
-
381
- for (i = 0; i < 32; i += 2) {
382
- *aa32_vfp_dreg(env, i / 2) = 0;
383
- }
384
- vfp_set_fpscr(env, 0);
385
- }
386
- /*
387
- * Otherwise s0 to s15 and FPSCR are UNKNOWN; we choose to leave them
388
- * unchanged.
389
- */
390
-}
391
-
392
-/*
393
- * Write to v7M CONTROL.SPSEL bit for the specified security bank.
394
- * This may change the current stack pointer between Main and Process
395
- * stack pointers if it is done for the CONTROL register for the current
396
- * security state.
397
- */
398
-static void write_v7m_control_spsel_for_secstate(CPUARMState *env,
399
- bool new_spsel,
400
- bool secstate)
401
-{
402
- bool old_is_psp = v7m_using_psp(env);
403
-
404
- env->v7m.control[secstate] =
405
- deposit32(env->v7m.control[secstate],
406
- R_V7M_CONTROL_SPSEL_SHIFT,
407
- R_V7M_CONTROL_SPSEL_LENGTH, new_spsel);
408
-
409
- if (secstate == env->v7m.secure) {
410
- bool new_is_psp = v7m_using_psp(env);
411
- uint32_t tmp;
412
-
413
- if (old_is_psp != new_is_psp) {
414
- tmp = env->v7m.other_sp;
415
- env->v7m.other_sp = env->regs[13];
416
- env->regs[13] = tmp;
417
- }
418
- }
419
-}
420
-
421
-/*
422
- * Write to v7M CONTROL.SPSEL bit. This may change the current
423
- * stack pointer between Main and Process stack pointers.
424
- */
425
-static void write_v7m_control_spsel(CPUARMState *env, bool new_spsel)
426
-{
427
- write_v7m_control_spsel_for_secstate(env, new_spsel, env->v7m.secure);
428
-}
429
-
430
-void write_v7m_exception(CPUARMState *env, uint32_t new_exc)
431
-{
432
- /*
433
- * Write a new value to v7m.exception, thus transitioning into or out
434
- * of Handler mode; this may result in a change of active stack pointer.
435
- */
436
- bool new_is_psp, old_is_psp = v7m_using_psp(env);
437
- uint32_t tmp;
438
-
439
- env->v7m.exception = new_exc;
440
-
441
- new_is_psp = v7m_using_psp(env);
442
-
443
- if (old_is_psp != new_is_psp) {
444
- tmp = env->v7m.other_sp;
445
- env->v7m.other_sp = env->regs[13];
446
- env->regs[13] = tmp;
447
- }
448
-}
449
-
450
-/* Switch M profile security state between NS and S */
451
-static void switch_v7m_security_state(CPUARMState *env, bool new_secstate)
452
-{
453
- uint32_t new_ss_msp, new_ss_psp;
454
-
455
- if (env->v7m.secure == new_secstate) {
456
- return;
457
- }
458
-
459
- /*
460
- * All the banked state is accessed by looking at env->v7m.secure
461
- * except for the stack pointer; rearrange the SP appropriately.
462
- */
463
- new_ss_msp = env->v7m.other_ss_msp;
464
- new_ss_psp = env->v7m.other_ss_psp;
465
-
466
- if (v7m_using_psp(env)) {
467
- env->v7m.other_ss_psp = env->regs[13];
468
- env->v7m.other_ss_msp = env->v7m.other_sp;
469
- } else {
470
- env->v7m.other_ss_msp = env->regs[13];
471
- env->v7m.other_ss_psp = env->v7m.other_sp;
472
- }
473
-
474
- env->v7m.secure = new_secstate;
475
-
476
- if (v7m_using_psp(env)) {
477
- env->regs[13] = new_ss_psp;
478
- env->v7m.other_sp = new_ss_msp;
479
- } else {
480
- env->regs[13] = new_ss_msp;
481
- env->v7m.other_sp = new_ss_psp;
482
- }
483
-}
484
-
485
-void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest)
486
-{
487
- /*
488
- * Handle v7M BXNS:
489
- * - if the return value is a magic value, do exception return (like BX)
490
- * - otherwise bit 0 of the return value is the target security state
491
- */
492
- uint32_t min_magic;
493
-
494
- if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
495
- /* Covers FNC_RETURN and EXC_RETURN magic */
496
- min_magic = FNC_RETURN_MIN_MAGIC;
497
- } else {
498
- /* EXC_RETURN magic only */
499
- min_magic = EXC_RETURN_MIN_MAGIC;
500
- }
501
-
502
- if (dest >= min_magic) {
503
- /*
504
- * This is an exception return magic value; put it where
505
- * do_v7m_exception_exit() expects and raise EXCEPTION_EXIT.
506
- * Note that if we ever add gen_ss_advance() singlestep support to
507
- * M profile this should count as an "instruction execution complete"
508
- * event (compare gen_bx_excret_final_code()).
509
- */
510
- env->regs[15] = dest & ~1;
511
- env->thumb = dest & 1;
512
- HELPER(exception_internal)(env, EXCP_EXCEPTION_EXIT);
513
- /* notreached */
514
- }
515
-
516
- /* translate.c should have made BXNS UNDEF unless we're secure */
517
- assert(env->v7m.secure);
518
-
519
- if (!(dest & 1)) {
520
- env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
521
- }
522
- switch_v7m_security_state(env, dest & 1);
523
- env->thumb = 1;
524
- env->regs[15] = dest & ~1;
525
-}
526
-
527
-void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest)
528
-{
529
- /*
530
- * Handle v7M BLXNS:
531
- * - bit 0 of the destination address is the target security state
532
- */
533
-
534
- /* At this point regs[15] is the address just after the BLXNS */
535
- uint32_t nextinst = env->regs[15] | 1;
536
- uint32_t sp = env->regs[13] - 8;
537
- uint32_t saved_psr;
538
-
539
- /* translate.c will have made BLXNS UNDEF unless we're secure */
540
- assert(env->v7m.secure);
541
-
542
- if (dest & 1) {
543
- /*
544
- * Target is Secure, so this is just a normal BLX,
545
- * except that the low bit doesn't indicate Thumb/not.
546
- */
547
- env->regs[14] = nextinst;
548
- env->thumb = 1;
549
- env->regs[15] = dest & ~1;
550
- return;
551
- }
552
-
553
- /* Target is non-secure: first push a stack frame */
554
- if (!QEMU_IS_ALIGNED(sp, 8)) {
555
- qemu_log_mask(LOG_GUEST_ERROR,
556
- "BLXNS with misaligned SP is UNPREDICTABLE\n");
557
- }
558
-
559
- if (sp < v7m_sp_limit(env)) {
560
- raise_exception(env, EXCP_STKOF, 0, 1);
561
- }
562
-
563
- saved_psr = env->v7m.exception;
564
- if (env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK) {
565
- saved_psr |= XPSR_SFPA;
566
- }
567
-
568
- /* Note that these stores can throw exceptions on MPU faults */
569
- cpu_stl_data(env, sp, nextinst);
570
- cpu_stl_data(env, sp + 4, saved_psr);
571
-
572
- env->regs[13] = sp;
573
- env->regs[14] = 0xfeffffff;
574
- if (arm_v7m_is_handler_mode(env)) {
575
- /*
576
- * Write a dummy value to IPSR, to avoid leaking the current secure
577
- * exception number to non-secure code. This is guaranteed not
578
- * to cause write_v7m_exception() to actually change stacks.
579
- */
580
- write_v7m_exception(env, 1);
581
- }
582
- env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
583
- switch_v7m_security_state(env, 0);
584
- env->thumb = 1;
585
- env->regs[15] = dest;
586
-}
587
-
588
-static uint32_t *get_v7m_sp_ptr(CPUARMState *env, bool secure, bool threadmode,
589
- bool spsel)
590
-{
591
- /*
592
- * Return a pointer to the location where we currently store the
593
- * stack pointer for the requested security state and thread mode.
594
- * This pointer will become invalid if the CPU state is updated
595
- * such that the stack pointers are switched around (eg changing
596
- * the SPSEL control bit).
597
- * Compare the v8M ARM ARM pseudocode LookUpSP_with_security_mode().
598
- * Unlike that pseudocode, we require the caller to pass us in the
599
- * SPSEL control bit value; this is because we also use this
600
- * function in handling of pushing of the callee-saves registers
601
- * part of the v8M stack frame (pseudocode PushCalleeStack()),
602
- * and in the tailchain codepath the SPSEL bit comes from the exception
603
- * return magic LR value from the previous exception. The pseudocode
604
- * opencodes the stack-selection in PushCalleeStack(), but we prefer
605
- * to make this utility function generic enough to do the job.
606
- */
607
- bool want_psp = threadmode && spsel;
608
-
609
- if (secure == env->v7m.secure) {
610
- if (want_psp == v7m_using_psp(env)) {
611
- return &env->regs[13];
612
- } else {
613
- return &env->v7m.other_sp;
614
- }
615
- } else {
616
- if (want_psp) {
617
- return &env->v7m.other_ss_psp;
618
- } else {
619
- return &env->v7m.other_ss_msp;
620
- }
621
- }
622
-}
623
-
624
-static bool arm_v7m_load_vector(ARMCPU *cpu, int exc, bool targets_secure,
625
- uint32_t *pvec)
626
-{
627
- CPUState *cs = CPU(cpu);
628
- CPUARMState *env = &cpu->env;
629
- MemTxResult result;
630
- uint32_t addr = env->v7m.vecbase[targets_secure] + exc * 4;
631
- uint32_t vector_entry;
632
- MemTxAttrs attrs = {};
633
- ARMMMUIdx mmu_idx;
634
- bool exc_secure;
635
-
636
- mmu_idx = arm_v7m_mmu_idx_for_secstate_and_priv(env, targets_secure, true);
637
-
638
- /*
639
- * We don't do a get_phys_addr() here because the rules for vector
640
- * loads are special: they always use the default memory map, and
641
- * the default memory map permits reads from all addresses.
642
- * Since there's no easy way to pass through to pmsav8_mpu_lookup()
643
- * that we want this special case which would always say "yes",
644
- * we just do the SAU lookup here followed by a direct physical load.
645
- */
646
- attrs.secure = targets_secure;
647
- attrs.user = false;
648
-
649
- if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
650
- V8M_SAttributes sattrs = {};
651
-
652
- v8m_security_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, &sattrs);
653
- if (sattrs.ns) {
654
- attrs.secure = false;
655
- } else if (!targets_secure) {
656
- /* NS access to S memory */
657
- goto load_fail;
658
- }
659
- }
660
-
661
- vector_entry = address_space_ldl(arm_addressspace(cs, attrs), addr,
662
- attrs, &result);
663
- if (result != MEMTX_OK) {
664
- goto load_fail;
665
- }
666
- *pvec = vector_entry;
667
- return true;
668
-
669
-load_fail:
670
- /*
671
- * All vector table fetch fails are reported as HardFault, with
672
- * HFSR.VECTTBL and .FORCED set. (FORCED is set because
673
- * technically the underlying exception is a MemManage or BusFault
674
- * that is escalated to HardFault.) This is a terminal exception,
675
- * so we will either take the HardFault immediately or else enter
676
- * lockup (the latter case is handled in armv7m_nvic_set_pending_derived()).
677
- */
678
- exc_secure = targets_secure ||
679
- !(cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK);
680
- env->v7m.hfsr |= R_V7M_HFSR_VECTTBL_MASK | R_V7M_HFSR_FORCED_MASK;
681
- armv7m_nvic_set_pending_derived(env->nvic, ARMV7M_EXCP_HARD, exc_secure);
682
- return false;
683
-}
684
-
685
-static uint32_t v7m_integrity_sig(CPUARMState *env, uint32_t lr)
686
-{
687
- /*
688
- * Return the integrity signature value for the callee-saves
689
- * stack frame section. @lr is the exception return payload/LR value
690
- * whose FType bit forms bit 0 of the signature if FP is present.
691
- */
692
- uint32_t sig = 0xfefa125a;
693
-
694
- if (!arm_feature(env, ARM_FEATURE_VFP) || (lr & R_V7M_EXCRET_FTYPE_MASK)) {
695
- sig |= 1;
696
- }
697
- return sig;
698
-}
699
-
700
-static bool v7m_push_callee_stack(ARMCPU *cpu, uint32_t lr, bool dotailchain,
701
- bool ignore_faults)
702
-{
703
- /*
704
- * For v8M, push the callee-saves register part of the stack frame.
705
- * Compare the v8M pseudocode PushCalleeStack().
706
- * In the tailchaining case this may not be the current stack.
707
- */
708
- CPUARMState *env = &cpu->env;
709
- uint32_t *frame_sp_p;
710
- uint32_t frameptr;
711
- ARMMMUIdx mmu_idx;
712
- bool stacked_ok;
713
- uint32_t limit;
714
- bool want_psp;
715
- uint32_t sig;
716
- StackingMode smode = ignore_faults ? STACK_IGNFAULTS : STACK_NORMAL;
717
-
718
- if (dotailchain) {
719
- bool mode = lr & R_V7M_EXCRET_MODE_MASK;
720
- bool priv = !(env->v7m.control[M_REG_S] & R_V7M_CONTROL_NPRIV_MASK) ||
721
- !mode;
722
-
723
- mmu_idx = arm_v7m_mmu_idx_for_secstate_and_priv(env, M_REG_S, priv);
724
- frame_sp_p = get_v7m_sp_ptr(env, M_REG_S, mode,
725
- lr & R_V7M_EXCRET_SPSEL_MASK);
726
- want_psp = mode && (lr & R_V7M_EXCRET_SPSEL_MASK);
727
- if (want_psp) {
728
- limit = env->v7m.psplim[M_REG_S];
729
- } else {
730
- limit = env->v7m.msplim[M_REG_S];
731
- }
732
- } else {
733
- mmu_idx = arm_mmu_idx(env);
734
- frame_sp_p = &env->regs[13];
735
- limit = v7m_sp_limit(env);
736
- }
737
-
738
- frameptr = *frame_sp_p - 0x28;
739
- if (frameptr < limit) {
740
- /*
741
- * Stack limit failure: set SP to the limit value, and generate
742
- * STKOF UsageFault. Stack pushes below the limit must not be
743
- * performed. It is IMPDEF whether pushes above the limit are
744
- * performed; we choose not to.
745
- */
746
- qemu_log_mask(CPU_LOG_INT,
747
- "...STKOF during callee-saves register stacking\n");
748
- env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_STKOF_MASK;
749
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
750
- env->v7m.secure);
751
- *frame_sp_p = limit;
752
- return true;
753
- }
754
-
755
- /*
756
- * Write as much of the stack frame as we can. A write failure may
757
- * cause us to pend a derived exception.
758
- */
759
- sig = v7m_integrity_sig(env, lr);
760
- stacked_ok =
761
- v7m_stack_write(cpu, frameptr, sig, mmu_idx, smode) &&
762
- v7m_stack_write(cpu, frameptr + 0x8, env->regs[4], mmu_idx, smode) &&
763
- v7m_stack_write(cpu, frameptr + 0xc, env->regs[5], mmu_idx, smode) &&
764
- v7m_stack_write(cpu, frameptr + 0x10, env->regs[6], mmu_idx, smode) &&
765
- v7m_stack_write(cpu, frameptr + 0x14, env->regs[7], mmu_idx, smode) &&
766
- v7m_stack_write(cpu, frameptr + 0x18, env->regs[8], mmu_idx, smode) &&
767
- v7m_stack_write(cpu, frameptr + 0x1c, env->regs[9], mmu_idx, smode) &&
768
- v7m_stack_write(cpu, frameptr + 0x20, env->regs[10], mmu_idx, smode) &&
769
- v7m_stack_write(cpu, frameptr + 0x24, env->regs[11], mmu_idx, smode);
770
-
771
- /* Update SP regardless of whether any of the stack accesses failed. */
772
- *frame_sp_p = frameptr;
773
-
774
- return !stacked_ok;
775
-}
776
-
777
-static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain,
778
- bool ignore_stackfaults)
779
-{
780
- /*
781
- * Do the "take the exception" parts of exception entry,
782
- * but not the pushing of state to the stack. This is
783
- * similar to the pseudocode ExceptionTaken() function.
784
- */
785
- CPUARMState *env = &cpu->env;
786
- uint32_t addr;
787
- bool targets_secure;
788
- int exc;
789
- bool push_failed = false;
790
-
791
- armv7m_nvic_get_pending_irq_info(env->nvic, &exc, &targets_secure);
792
- qemu_log_mask(CPU_LOG_INT, "...taking pending %s exception %d\n",
793
- targets_secure ? "secure" : "nonsecure", exc);
794
-
795
- if (dotailchain) {
796
- /* Sanitize LR FType and PREFIX bits */
797
- if (!arm_feature(env, ARM_FEATURE_VFP)) {
798
- lr |= R_V7M_EXCRET_FTYPE_MASK;
799
- }
800
- lr = deposit32(lr, 24, 8, 0xff);
801
- }
802
-
803
- if (arm_feature(env, ARM_FEATURE_V8)) {
804
- if (arm_feature(env, ARM_FEATURE_M_SECURITY) &&
805
- (lr & R_V7M_EXCRET_S_MASK)) {
806
- /*
807
- * The background code (the owner of the registers in the
808
- * exception frame) is Secure. This means it may either already
809
- * have or now needs to push callee-saves registers.
810
- */
811
- if (targets_secure) {
812
- if (dotailchain && !(lr & R_V7M_EXCRET_ES_MASK)) {
813
- /*
814
- * We took an exception from Secure to NonSecure
815
- * (which means the callee-saved registers got stacked)
816
- * and are now tailchaining to a Secure exception.
817
- * Clear DCRS so eventual return from this Secure
818
- * exception unstacks the callee-saved registers.
819
- */
820
- lr &= ~R_V7M_EXCRET_DCRS_MASK;
821
- }
822
- } else {
823
- /*
824
- * We're going to a non-secure exception; push the
825
- * callee-saves registers to the stack now, if they're
826
- * not already saved.
827
- */
828
- if (lr & R_V7M_EXCRET_DCRS_MASK &&
829
- !(dotailchain && !(lr & R_V7M_EXCRET_ES_MASK))) {
830
- push_failed = v7m_push_callee_stack(cpu, lr, dotailchain,
831
- ignore_stackfaults);
832
- }
833
- lr |= R_V7M_EXCRET_DCRS_MASK;
834
- }
835
- }
836
-
837
- lr &= ~R_V7M_EXCRET_ES_MASK;
838
- if (targets_secure || !arm_feature(env, ARM_FEATURE_M_SECURITY)) {
839
- lr |= R_V7M_EXCRET_ES_MASK;
840
- }
841
- lr &= ~R_V7M_EXCRET_SPSEL_MASK;
842
- if (env->v7m.control[targets_secure] & R_V7M_CONTROL_SPSEL_MASK) {
843
- lr |= R_V7M_EXCRET_SPSEL_MASK;
844
- }
845
-
846
- /*
847
- * Clear registers if necessary to prevent non-secure exception
848
- * code being able to see register values from secure code.
849
- * Where register values become architecturally UNKNOWN we leave
850
- * them with their previous values.
851
- */
852
- if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
853
- if (!targets_secure) {
854
- /*
855
- * Always clear the caller-saved registers (they have been
856
- * pushed to the stack earlier in v7m_push_stack()).
857
- * Clear callee-saved registers if the background code is
858
- * Secure (in which case these regs were saved in
859
- * v7m_push_callee_stack()).
860
- */
861
- int i;
862
-
863
- for (i = 0; i < 13; i++) {
864
- /* r4..r11 are callee-saves, zero only if EXCRET.S == 1 */
865
- if (i < 4 || i > 11 || (lr & R_V7M_EXCRET_S_MASK)) {
866
- env->regs[i] = 0;
867
- }
868
- }
869
- /* Clear EAPSR */
870
- xpsr_write(env, 0, XPSR_NZCV | XPSR_Q | XPSR_GE | XPSR_IT);
871
- }
872
- }
873
- }
874
-
875
- if (push_failed && !ignore_stackfaults) {
876
- /*
877
- * Derived exception on callee-saves register stacking:
878
- * we might now want to take a different exception which
879
- * targets a different security state, so try again from the top.
880
- */
881
- qemu_log_mask(CPU_LOG_INT,
882
- "...derived exception on callee-saves register stacking");
883
- v7m_exception_taken(cpu, lr, true, true);
884
- return;
885
- }
886
-
887
- if (!arm_v7m_load_vector(cpu, exc, targets_secure, &addr)) {
888
- /* Vector load failed: derived exception */
889
- qemu_log_mask(CPU_LOG_INT, "...derived exception on vector table load");
890
- v7m_exception_taken(cpu, lr, true, true);
891
- return;
892
- }
893
-
894
- /*
895
- * Now we've done everything that might cause a derived exception
896
- * we can go ahead and activate whichever exception we're going to
897
- * take (which might now be the derived exception).
898
- */
899
- armv7m_nvic_acknowledge_irq(env->nvic);
900
-
901
- /* Switch to target security state -- must do this before writing SPSEL */
902
- switch_v7m_security_state(env, targets_secure);
903
- write_v7m_control_spsel(env, 0);
904
- arm_clear_exclusive(env);
905
- /* Clear SFPA and FPCA (has no effect if no FPU) */
906
- env->v7m.control[M_REG_S] &=
907
- ~(R_V7M_CONTROL_FPCA_MASK | R_V7M_CONTROL_SFPA_MASK);
908
- /* Clear IT bits */
909
- env->condexec_bits = 0;
910
- env->regs[14] = lr;
911
- env->regs[15] = addr & 0xfffffffe;
912
- env->thumb = addr & 1;
913
-}
914
-
915
-static void v7m_update_fpccr(CPUARMState *env, uint32_t frameptr,
916
- bool apply_splim)
917
-{
918
- /*
919
- * Like the pseudocode UpdateFPCCR: save state in FPCAR and FPCCR
920
- * that we will need later in order to do lazy FP reg stacking.
921
- */
922
- bool is_secure = env->v7m.secure;
923
- void *nvic = env->nvic;
924
- /*
925
- * Some bits are unbanked and live always in fpccr[M_REG_S]; some bits
926
- * are banked and we want to update the bit in the bank for the
927
- * current security state; and in one case we want to specifically
928
- * update the NS banked version of a bit even if we are secure.
929
- */
930
- uint32_t *fpccr_s = &env->v7m.fpccr[M_REG_S];
931
- uint32_t *fpccr_ns = &env->v7m.fpccr[M_REG_NS];
932
- uint32_t *fpccr = &env->v7m.fpccr[is_secure];
933
- bool hfrdy, bfrdy, mmrdy, ns_ufrdy, s_ufrdy, sfrdy, monrdy;
934
-
935
- env->v7m.fpcar[is_secure] = frameptr & ~0x7;
936
-
937
- if (apply_splim && arm_feature(env, ARM_FEATURE_V8)) {
938
- bool splimviol;
939
- uint32_t splim = v7m_sp_limit(env);
940
- bool ign = armv7m_nvic_neg_prio_requested(nvic, is_secure) &&
941
- (env->v7m.ccr[is_secure] & R_V7M_CCR_STKOFHFNMIGN_MASK);
942
-
943
- splimviol = !ign && frameptr < splim;
944
- *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, SPLIMVIOL, splimviol);
945
- }
946
-
947
- *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, LSPACT, 1);
948
-
949
- *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, S, is_secure);
950
-
951
- *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, USER, arm_current_el(env) == 0);
952
-
953
- *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, THREAD,
954
- !arm_v7m_is_handler_mode(env));
955
-
956
- hfrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_HARD, false);
957
- *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, HFRDY, hfrdy);
958
-
959
- bfrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_BUS, false);
960
- *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, BFRDY, bfrdy);
961
-
962
- mmrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_MEM, is_secure);
963
- *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, MMRDY, mmrdy);
964
-
965
- ns_ufrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_USAGE, false);
966
- *fpccr_ns = FIELD_DP32(*fpccr_ns, V7M_FPCCR, UFRDY, ns_ufrdy);
967
-
968
- monrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_DEBUG, false);
969
- *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, MONRDY, monrdy);
970
-
971
- if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
972
- s_ufrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_USAGE, true);
973
- *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, UFRDY, s_ufrdy);
974
-
975
- sfrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_SECURE, false);
976
- *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, SFRDY, sfrdy);
977
- }
978
-}
979
-
980
-void HELPER(v7m_vlstm)(CPUARMState *env, uint32_t fptr)
981
-{
982
- /* fptr is the value of Rn, the frame pointer we store the FP regs to */
983
- bool s = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK;
984
- bool lspact = env->v7m.fpccr[s] & R_V7M_FPCCR_LSPACT_MASK;
985
-
986
- assert(env->v7m.secure);
987
-
988
- if (!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK)) {
989
- return;
990
- }
991
-
992
- /* Check access to the coprocessor is permitted */
993
- if (!v7m_cpacr_pass(env, true, arm_current_el(env) != 0)) {
994
- raise_exception_ra(env, EXCP_NOCP, 0, 1, GETPC());
995
- }
996
-
997
- if (lspact) {
998
- /* LSPACT should not be active when there is active FP state */
999
- raise_exception_ra(env, EXCP_LSERR, 0, 1, GETPC());
1000
- }
1001
-
1002
- if (fptr & 7) {
1003
- raise_exception_ra(env, EXCP_UNALIGNED, 0, 1, GETPC());
1004
- }
1005
-
1006
- /*
1007
- * Note that we do not use v7m_stack_write() here, because the
1008
- * accesses should not set the FSR bits for stacking errors if they
1009
- * fail. (In pseudocode terms, they are AccType_NORMAL, not AccType_STACK
1010
- * or AccType_LAZYFP). Faults in cpu_stl_data() will throw exceptions
1011
- * and longjmp out.
1012
- */
1013
- if (!(env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPEN_MASK)) {
1014
- bool ts = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK;
1015
- int i;
1016
-
1017
- for (i = 0; i < (ts ? 32 : 16); i += 2) {
1018
- uint64_t dn = *aa32_vfp_dreg(env, i / 2);
1019
- uint32_t faddr = fptr + 4 * i;
1020
- uint32_t slo = extract64(dn, 0, 32);
1021
- uint32_t shi = extract64(dn, 32, 32);
1022
-
1023
- if (i >= 16) {
1024
- faddr += 8; /* skip the slot for the FPSCR */
1025
- }
1026
- cpu_stl_data(env, faddr, slo);
1027
- cpu_stl_data(env, faddr + 4, shi);
1028
- }
1029
- cpu_stl_data(env, fptr + 0x40, vfp_get_fpscr(env));
1030
-
1031
- /*
1032
- * If TS is 0 then s0 to s15 and FPSCR are UNKNOWN; we choose to
1033
- * leave them unchanged, matching our choice in v7m_preserve_fp_state.
1034
- */
1035
- if (ts) {
1036
- for (i = 0; i < 32; i += 2) {
1037
- *aa32_vfp_dreg(env, i / 2) = 0;
1038
- }
1039
- vfp_set_fpscr(env, 0);
1040
- }
1041
- } else {
1042
- v7m_update_fpccr(env, fptr, false);
1043
- }
1044
-
1045
- env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_FPCA_MASK;
1046
-}
1047
-
1048
-void HELPER(v7m_vlldm)(CPUARMState *env, uint32_t fptr)
1049
-{
1050
- /* fptr is the value of Rn, the frame pointer we load the FP regs from */
1051
- assert(env->v7m.secure);
1052
-
1053
- if (!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK)) {
1054
- return;
1055
- }
1056
-
1057
- /* Check access to the coprocessor is permitted */
1058
- if (!v7m_cpacr_pass(env, true, arm_current_el(env) != 0)) {
1059
- raise_exception_ra(env, EXCP_NOCP, 0, 1, GETPC());
1060
- }
1061
-
1062
- if (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPACT_MASK) {
1063
- /* State in FP is still valid */
1064
- env->v7m.fpccr[M_REG_S] &= ~R_V7M_FPCCR_LSPACT_MASK;
1065
- } else {
1066
- bool ts = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK;
1067
- int i;
1068
- uint32_t fpscr;
1069
-
1070
- if (fptr & 7) {
1071
- raise_exception_ra(env, EXCP_UNALIGNED, 0, 1, GETPC());
1072
- }
1073
-
1074
- for (i = 0; i < (ts ? 32 : 16); i += 2) {
1075
- uint32_t slo, shi;
1076
- uint64_t dn;
1077
- uint32_t faddr = fptr + 4 * i;
1078
-
1079
- if (i >= 16) {
1080
- faddr += 8; /* skip the slot for the FPSCR */
1081
- }
1082
-
1083
- slo = cpu_ldl_data(env, faddr);
1084
- shi = cpu_ldl_data(env, faddr + 4);
1085
-
1086
- dn = (uint64_t) shi << 32 | slo;
1087
- *aa32_vfp_dreg(env, i / 2) = dn;
1088
- }
1089
- fpscr = cpu_ldl_data(env, fptr + 0x40);
1090
- vfp_set_fpscr(env, fpscr);
1091
- }
1092
-
1093
- env->v7m.control[M_REG_S] |= R_V7M_CONTROL_FPCA_MASK;
1094
-}
1095
-
1096
-static bool v7m_push_stack(ARMCPU *cpu)
1097
-{
1098
- /*
1099
- * Do the "set up stack frame" part of exception entry,
1100
- * similar to pseudocode PushStack().
1101
- * Return true if we generate a derived exception (and so
1102
- * should ignore further stack faults trying to process
1103
- * that derived exception.)
1104
- */
1105
- bool stacked_ok = true, limitviol = false;
1106
- CPUARMState *env = &cpu->env;
1107
- uint32_t xpsr = xpsr_read(env);
1108
- uint32_t frameptr = env->regs[13];
1109
- ARMMMUIdx mmu_idx = arm_mmu_idx(env);
1110
- uint32_t framesize;
1111
- bool nsacr_cp10 = extract32(env->v7m.nsacr, 10, 1);
1112
-
1113
- if ((env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK) &&
1114
- (env->v7m.secure || nsacr_cp10)) {
1115
- if (env->v7m.secure &&
1116
- env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK) {
1117
- framesize = 0xa8;
1118
- } else {
1119
- framesize = 0x68;
1120
- }
1121
- } else {
1122
- framesize = 0x20;
1123
- }
1124
-
1125
- /* Align stack pointer if the guest wants that */
1126
- if ((frameptr & 4) &&
1127
- (env->v7m.ccr[env->v7m.secure] & R_V7M_CCR_STKALIGN_MASK)) {
1128
- frameptr -= 4;
1129
- xpsr |= XPSR_SPREALIGN;
1130
- }
1131
-
1132
- xpsr &= ~XPSR_SFPA;
1133
- if (env->v7m.secure &&
1134
- (env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK)) {
1135
- xpsr |= XPSR_SFPA;
1136
- }
1137
-
1138
- frameptr -= framesize;
1139
-
1140
- if (arm_feature(env, ARM_FEATURE_V8)) {
1141
- uint32_t limit = v7m_sp_limit(env);
1142
-
1143
- if (frameptr < limit) {
1144
- /*
1145
- * Stack limit failure: set SP to the limit value, and generate
1146
- * STKOF UsageFault. Stack pushes below the limit must not be
1147
- * performed. It is IMPDEF whether pushes above the limit are
1148
- * performed; we choose not to.
1149
- */
1150
- qemu_log_mask(CPU_LOG_INT,
1151
- "...STKOF during stacking\n");
1152
- env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_STKOF_MASK;
1153
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
1154
- env->v7m.secure);
1155
- env->regs[13] = limit;
1156
- /*
1157
- * We won't try to perform any further memory accesses but
1158
- * we must continue through the following code to check for
1159
- * permission faults during FPU state preservation, and we
1160
- * must update FPCCR if lazy stacking is enabled.
1161
- */
1162
- limitviol = true;
1163
- stacked_ok = false;
1164
- }
1165
- }
1166
-
1167
- /*
1168
- * Write as much of the stack frame as we can. If we fail a stack
1169
- * write this will result in a derived exception being pended
1170
- * (which may be taken in preference to the one we started with
1171
- * if it has higher priority).
1172
- */
1173
- stacked_ok = stacked_ok &&
1174
- v7m_stack_write(cpu, frameptr, env->regs[0], mmu_idx, STACK_NORMAL) &&
1175
- v7m_stack_write(cpu, frameptr + 4, env->regs[1],
1176
- mmu_idx, STACK_NORMAL) &&
1177
- v7m_stack_write(cpu, frameptr + 8, env->regs[2],
1178
- mmu_idx, STACK_NORMAL) &&
1179
- v7m_stack_write(cpu, frameptr + 12, env->regs[3],
1180
- mmu_idx, STACK_NORMAL) &&
1181
- v7m_stack_write(cpu, frameptr + 16, env->regs[12],
1182
- mmu_idx, STACK_NORMAL) &&
1183
- v7m_stack_write(cpu, frameptr + 20, env->regs[14],
1184
- mmu_idx, STACK_NORMAL) &&
1185
- v7m_stack_write(cpu, frameptr + 24, env->regs[15],
1186
- mmu_idx, STACK_NORMAL) &&
1187
- v7m_stack_write(cpu, frameptr + 28, xpsr, mmu_idx, STACK_NORMAL);
1188
-
1189
- if (env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK) {
1190
- /* FPU is active, try to save its registers */
1191
- bool fpccr_s = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK;
1192
- bool lspact = env->v7m.fpccr[fpccr_s] & R_V7M_FPCCR_LSPACT_MASK;
1193
-
1194
- if (lspact && arm_feature(env, ARM_FEATURE_M_SECURITY)) {
1195
- qemu_log_mask(CPU_LOG_INT,
1196
- "...SecureFault because LSPACT and FPCA both set\n");
1197
- env->v7m.sfsr |= R_V7M_SFSR_LSERR_MASK;
1198
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
1199
- } else if (!env->v7m.secure && !nsacr_cp10) {
1200
- qemu_log_mask(CPU_LOG_INT,
1201
- "...Secure UsageFault with CFSR.NOCP because "
1202
- "NSACR.CP10 prevents stacking FP regs\n");
1203
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, M_REG_S);
1204
- env->v7m.cfsr[M_REG_S] |= R_V7M_CFSR_NOCP_MASK;
1205
- } else {
1206
- if (!(env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPEN_MASK)) {
1207
- /* Lazy stacking disabled, save registers now */
1208
- int i;
1209
- bool cpacr_pass = v7m_cpacr_pass(env, env->v7m.secure,
1210
- arm_current_el(env) != 0);
1211
-
1212
- if (stacked_ok && !cpacr_pass) {
1213
- /*
1214
- * Take UsageFault if CPACR forbids access. The pseudocode
1215
- * here does a full CheckCPEnabled() but we know the NSACR
1216
- * check can never fail as we have already handled that.
1217
- */
1218
- qemu_log_mask(CPU_LOG_INT,
1219
- "...UsageFault with CFSR.NOCP because "
1220
- "CPACR.CP10 prevents stacking FP regs\n");
1221
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
1222
- env->v7m.secure);
1223
- env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_NOCP_MASK;
1224
- stacked_ok = false;
1225
- }
1226
-
1227
- for (i = 0; i < ((framesize == 0xa8) ? 32 : 16); i += 2) {
1228
- uint64_t dn = *aa32_vfp_dreg(env, i / 2);
1229
- uint32_t faddr = frameptr + 0x20 + 4 * i;
1230
- uint32_t slo = extract64(dn, 0, 32);
1231
- uint32_t shi = extract64(dn, 32, 32);
1232
-
1233
- if (i >= 16) {
1234
- faddr += 8; /* skip the slot for the FPSCR */
1235
- }
1236
- stacked_ok = stacked_ok &&
1237
- v7m_stack_write(cpu, faddr, slo,
1238
- mmu_idx, STACK_NORMAL) &&
1239
- v7m_stack_write(cpu, faddr + 4, shi,
1240
- mmu_idx, STACK_NORMAL);
1241
- }
1242
- stacked_ok = stacked_ok &&
1243
- v7m_stack_write(cpu, frameptr + 0x60,
1244
- vfp_get_fpscr(env), mmu_idx, STACK_NORMAL);
1245
- if (cpacr_pass) {
1246
- for (i = 0; i < ((framesize == 0xa8) ? 32 : 16); i += 2) {
1247
- *aa32_vfp_dreg(env, i / 2) = 0;
1248
- }
1249
- vfp_set_fpscr(env, 0);
1250
- }
1251
- } else {
1252
- /* Lazy stacking enabled, save necessary info to stack later */
1253
- v7m_update_fpccr(env, frameptr + 0x20, true);
1254
- }
1255
- }
1256
- }
1257
-
1258
- /*
1259
- * If we broke a stack limit then SP was already updated earlier;
1260
- * otherwise we update SP regardless of whether any of the stack
1261
- * accesses failed or we took some other kind of fault.
1262
- */
1263
- if (!limitviol) {
1264
- env->regs[13] = frameptr;
1265
- }
1266
-
1267
- return !stacked_ok;
1268
-}
1269
-
1270
-static void do_v7m_exception_exit(ARMCPU *cpu)
1271
-{
1272
- CPUARMState *env = &cpu->env;
1273
- uint32_t excret;
1274
- uint32_t xpsr, xpsr_mask;
1275
- bool ufault = false;
1276
- bool sfault = false;
1277
- bool return_to_sp_process;
1278
- bool return_to_handler;
1279
- bool rettobase = false;
1280
- bool exc_secure = false;
1281
- bool return_to_secure;
1282
- bool ftype;
1283
- bool restore_s16_s31;
1284
-
1285
- /*
1286
- * If we're not in Handler mode then jumps to magic exception-exit
1287
- * addresses don't have magic behaviour. However for the v8M
1288
- * security extensions the magic secure-function-return has to
1289
- * work in thread mode too, so to avoid doing an extra check in
1290
- * the generated code we allow exception-exit magic to also cause the
1291
- * internal exception and bring us here in thread mode. Correct code
1292
- * will never try to do this (the following insn fetch will always
1293
- * fault) so we the overhead of having taken an unnecessary exception
1294
- * doesn't matter.
1295
- */
1296
- if (!arm_v7m_is_handler_mode(env)) {
1297
- return;
1298
- }
1299
-
1300
- /*
1301
- * In the spec pseudocode ExceptionReturn() is called directly
1302
- * from BXWritePC() and gets the full target PC value including
1303
- * bit zero. In QEMU's implementation we treat it as a normal
1304
- * jump-to-register (which is then caught later on), and so split
1305
- * the target value up between env->regs[15] and env->thumb in
1306
- * gen_bx(). Reconstitute it.
1307
- */
1308
- excret = env->regs[15];
1309
- if (env->thumb) {
1310
- excret |= 1;
1311
- }
1312
-
1313
- qemu_log_mask(CPU_LOG_INT, "Exception return: magic PC %" PRIx32
1314
- " previous exception %d\n",
1315
- excret, env->v7m.exception);
1316
-
1317
- if ((excret & R_V7M_EXCRET_RES1_MASK) != R_V7M_EXCRET_RES1_MASK) {
1318
- qemu_log_mask(LOG_GUEST_ERROR, "M profile: zero high bits in exception "
1319
- "exit PC value 0x%" PRIx32 " are UNPREDICTABLE\n",
1320
- excret);
1321
- }
1322
-
1323
- ftype = excret & R_V7M_EXCRET_FTYPE_MASK;
1324
-
1325
- if (!arm_feature(env, ARM_FEATURE_VFP) && !ftype) {
1326
- qemu_log_mask(LOG_GUEST_ERROR, "M profile: zero FTYPE in exception "
1327
- "exit PC value 0x%" PRIx32 " is UNPREDICTABLE "
1328
- "if FPU not present\n",
1329
- excret);
1330
- ftype = true;
1331
- }
1332
-
1333
- if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
1334
- /*
1335
- * EXC_RETURN.ES validation check (R_SMFL). We must do this before
1336
- * we pick which FAULTMASK to clear.
1337
- */
1338
- if (!env->v7m.secure &&
1339
- ((excret & R_V7M_EXCRET_ES_MASK) ||
1340
- !(excret & R_V7M_EXCRET_DCRS_MASK))) {
1341
- sfault = 1;
1342
- /* For all other purposes, treat ES as 0 (R_HXSR) */
1343
- excret &= ~R_V7M_EXCRET_ES_MASK;
1344
- }
1345
- exc_secure = excret & R_V7M_EXCRET_ES_MASK;
1346
- }
1347
-
1348
- if (env->v7m.exception != ARMV7M_EXCP_NMI) {
1349
- /*
1350
- * Auto-clear FAULTMASK on return from other than NMI.
1351
- * If the security extension is implemented then this only
1352
- * happens if the raw execution priority is >= 0; the
1353
- * value of the ES bit in the exception return value indicates
1354
- * which security state's faultmask to clear. (v8M ARM ARM R_KBNF.)
1355
- */
1356
- if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
1357
- if (armv7m_nvic_raw_execution_priority(env->nvic) >= 0) {
1358
- env->v7m.faultmask[exc_secure] = 0;
1359
- }
1360
- } else {
1361
- env->v7m.faultmask[M_REG_NS] = 0;
1362
- }
1363
- }
1364
-
1365
- switch (armv7m_nvic_complete_irq(env->nvic, env->v7m.exception,
1366
- exc_secure)) {
1367
- case -1:
1368
- /* attempt to exit an exception that isn't active */
1369
- ufault = true;
1370
- break;
1371
- case 0:
1372
- /* still an irq active now */
1373
- break;
1374
- case 1:
1375
- /*
1376
- * We returned to base exception level, no nesting.
1377
- * (In the pseudocode this is written using "NestedActivation != 1"
1378
- * where we have 'rettobase == false'.)
1379
- */
1380
- rettobase = true;
1381
- break;
1382
- default:
1383
- g_assert_not_reached();
1384
- }
1385
-
1386
- return_to_handler = !(excret & R_V7M_EXCRET_MODE_MASK);
1387
- return_to_sp_process = excret & R_V7M_EXCRET_SPSEL_MASK;
1388
- return_to_secure = arm_feature(env, ARM_FEATURE_M_SECURITY) &&
1389
- (excret & R_V7M_EXCRET_S_MASK);
1390
-
1391
- if (arm_feature(env, ARM_FEATURE_V8)) {
1392
- if (!arm_feature(env, ARM_FEATURE_M_SECURITY)) {
1393
- /*
1394
- * UNPREDICTABLE if S == 1 or DCRS == 0 or ES == 1 (R_XLCP);
1395
- * we choose to take the UsageFault.
1396
- */
1397
- if ((excret & R_V7M_EXCRET_S_MASK) ||
1398
- (excret & R_V7M_EXCRET_ES_MASK) ||
1399
- !(excret & R_V7M_EXCRET_DCRS_MASK)) {
1400
- ufault = true;
1401
- }
1402
- }
1403
- if (excret & R_V7M_EXCRET_RES0_MASK) {
1404
- ufault = true;
1405
- }
1406
- } else {
1407
- /* For v7M we only recognize certain combinations of the low bits */
1408
- switch (excret & 0xf) {
1409
- case 1: /* Return to Handler */
1410
- break;
1411
- case 13: /* Return to Thread using Process stack */
1412
- case 9: /* Return to Thread using Main stack */
1413
- /*
1414
- * We only need to check NONBASETHRDENA for v7M, because in
1415
- * v8M this bit does not exist (it is RES1).
1416
- */
1417
- if (!rettobase &&
1418
- !(env->v7m.ccr[env->v7m.secure] &
1419
- R_V7M_CCR_NONBASETHRDENA_MASK)) {
1420
- ufault = true;
1421
- }
1422
- break;
1423
- default:
1424
- ufault = true;
1425
- }
1426
- }
1427
-
1428
- /*
1429
- * Set CONTROL.SPSEL from excret.SPSEL. Since we're still in
1430
- * Handler mode (and will be until we write the new XPSR.Interrupt
1431
- * field) this does not switch around the current stack pointer.
1432
- * We must do this before we do any kind of tailchaining, including
1433
- * for the derived exceptions on integrity check failures, or we will
1434
- * give the guest an incorrect EXCRET.SPSEL value on exception entry.
1435
- */
1436
- write_v7m_control_spsel_for_secstate(env, return_to_sp_process, exc_secure);
1437
-
1438
- /*
1439
- * Clear scratch FP values left in caller saved registers; this
1440
- * must happen before any kind of tail chaining.
1441
- */
1442
- if ((env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_CLRONRET_MASK) &&
1443
- (env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK)) {
1444
- if (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPACT_MASK) {
1445
- env->v7m.sfsr |= R_V7M_SFSR_LSERR_MASK;
1446
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
1447
- qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on existing "
1448
- "stackframe: error during lazy state deactivation\n");
1449
- v7m_exception_taken(cpu, excret, true, false);
1450
- return;
1451
- } else {
1452
- /* Clear s0..s15 and FPSCR */
1453
- int i;
1454
-
1455
- for (i = 0; i < 16; i += 2) {
1456
- *aa32_vfp_dreg(env, i / 2) = 0;
1457
- }
1458
- vfp_set_fpscr(env, 0);
1459
- }
1460
- }
1461
-
1462
- if (sfault) {
1463
- env->v7m.sfsr |= R_V7M_SFSR_INVER_MASK;
1464
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
1465
- qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on existing "
1466
- "stackframe: failed EXC_RETURN.ES validity check\n");
1467
- v7m_exception_taken(cpu, excret, true, false);
1468
- return;
1469
- }
1470
-
1471
- if (ufault) {
1472
- /*
1473
- * Bad exception return: instead of popping the exception
1474
- * stack, directly take a usage fault on the current stack.
1475
- */
1476
- env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
1477
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
1478
- qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on existing "
1479
- "stackframe: failed exception return integrity check\n");
1480
- v7m_exception_taken(cpu, excret, true, false);
1481
- return;
1482
- }
1483
-
1484
- /*
1485
- * Tailchaining: if there is currently a pending exception that
1486
- * is high enough priority to preempt execution at the level we're
1487
- * about to return to, then just directly take that exception now,
1488
- * avoiding an unstack-and-then-stack. Note that now we have
1489
- * deactivated the previous exception by calling armv7m_nvic_complete_irq()
1490
- * our current execution priority is already the execution priority we are
1491
- * returning to -- none of the state we would unstack or set based on
1492
- * the EXCRET value affects it.
1493
- */
1494
- if (armv7m_nvic_can_take_pending_exception(env->nvic)) {
1495
- qemu_log_mask(CPU_LOG_INT, "...tailchaining to pending exception\n");
1496
- v7m_exception_taken(cpu, excret, true, false);
1497
- return;
1498
- }
1499
-
1500
- switch_v7m_security_state(env, return_to_secure);
1501
-
1502
- {
1503
- /*
1504
- * The stack pointer we should be reading the exception frame from
1505
- * depends on bits in the magic exception return type value (and
1506
- * for v8M isn't necessarily the stack pointer we will eventually
1507
- * end up resuming execution with). Get a pointer to the location
1508
- * in the CPU state struct where the SP we need is currently being
1509
- * stored; we will use and modify it in place.
1510
- * We use this limited C variable scope so we don't accidentally
1511
- * use 'frame_sp_p' after we do something that makes it invalid.
1512
- */
1513
- uint32_t *frame_sp_p = get_v7m_sp_ptr(env,
1514
- return_to_secure,
1515
- !return_to_handler,
1516
- return_to_sp_process);
1517
- uint32_t frameptr = *frame_sp_p;
1518
- bool pop_ok = true;
1519
- ARMMMUIdx mmu_idx;
1520
- bool return_to_priv = return_to_handler ||
1521
- !(env->v7m.control[return_to_secure] & R_V7M_CONTROL_NPRIV_MASK);
1522
-
1523
- mmu_idx = arm_v7m_mmu_idx_for_secstate_and_priv(env, return_to_secure,
1524
- return_to_priv);
1525
-
1526
- if (!QEMU_IS_ALIGNED(frameptr, 8) &&
1527
- arm_feature(env, ARM_FEATURE_V8)) {
1528
- qemu_log_mask(LOG_GUEST_ERROR,
1529
- "M profile exception return with non-8-aligned SP "
1530
- "for destination state is UNPREDICTABLE\n");
1531
- }
1532
-
1533
- /* Do we need to pop callee-saved registers? */
1534
- if (return_to_secure &&
1535
- ((excret & R_V7M_EXCRET_ES_MASK) == 0 ||
1536
- (excret & R_V7M_EXCRET_DCRS_MASK) == 0)) {
1537
- uint32_t actual_sig;
1538
-
1539
- pop_ok = v7m_stack_read(cpu, &actual_sig, frameptr, mmu_idx);
1540
-
1541
- if (pop_ok && v7m_integrity_sig(env, excret) != actual_sig) {
1542
- /* Take a SecureFault on the current stack */
1543
- env->v7m.sfsr |= R_V7M_SFSR_INVIS_MASK;
1544
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
1545
- qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on existing "
1546
- "stackframe: failed exception return integrity "
1547
- "signature check\n");
1548
- v7m_exception_taken(cpu, excret, true, false);
1549
- return;
1550
- }
1551
-
1552
- pop_ok = pop_ok &&
1553
- v7m_stack_read(cpu, &env->regs[4], frameptr + 0x8, mmu_idx) &&
1554
- v7m_stack_read(cpu, &env->regs[5], frameptr + 0xc, mmu_idx) &&
1555
- v7m_stack_read(cpu, &env->regs[6], frameptr + 0x10, mmu_idx) &&
1556
- v7m_stack_read(cpu, &env->regs[7], frameptr + 0x14, mmu_idx) &&
1557
- v7m_stack_read(cpu, &env->regs[8], frameptr + 0x18, mmu_idx) &&
1558
- v7m_stack_read(cpu, &env->regs[9], frameptr + 0x1c, mmu_idx) &&
1559
- v7m_stack_read(cpu, &env->regs[10], frameptr + 0x20, mmu_idx) &&
1560
- v7m_stack_read(cpu, &env->regs[11], frameptr + 0x24, mmu_idx);
1561
-
1562
- frameptr += 0x28;
1563
- }
1564
-
1565
- /* Pop registers */
1566
- pop_ok = pop_ok &&
1567
- v7m_stack_read(cpu, &env->regs[0], frameptr, mmu_idx) &&
1568
- v7m_stack_read(cpu, &env->regs[1], frameptr + 0x4, mmu_idx) &&
1569
- v7m_stack_read(cpu, &env->regs[2], frameptr + 0x8, mmu_idx) &&
1570
- v7m_stack_read(cpu, &env->regs[3], frameptr + 0xc, mmu_idx) &&
1571
- v7m_stack_read(cpu, &env->regs[12], frameptr + 0x10, mmu_idx) &&
1572
- v7m_stack_read(cpu, &env->regs[14], frameptr + 0x14, mmu_idx) &&
1573
- v7m_stack_read(cpu, &env->regs[15], frameptr + 0x18, mmu_idx) &&
1574
- v7m_stack_read(cpu, &xpsr, frameptr + 0x1c, mmu_idx);
1575
-
1576
- if (!pop_ok) {
1577
- /*
1578
- * v7m_stack_read() pended a fault, so take it (as a tail
1579
- * chained exception on the same stack frame)
1580
- */
1581
- qemu_log_mask(CPU_LOG_INT, "...derived exception on unstacking\n");
1582
- v7m_exception_taken(cpu, excret, true, false);
1583
- return;
1584
- }
1585
-
1586
- /*
1587
- * Returning from an exception with a PC with bit 0 set is defined
1588
- * behaviour on v8M (bit 0 is ignored), but for v7M it was specified
1589
- * to be UNPREDICTABLE. In practice actual v7M hardware seems to ignore
1590
- * the lsbit, and there are several RTOSes out there which incorrectly
1591
- * assume the r15 in the stack frame should be a Thumb-style "lsbit
1592
- * indicates ARM/Thumb" value, so ignore the bit on v7M as well, but
1593
- * complain about the badly behaved guest.
1594
- */
1595
- if (env->regs[15] & 1) {
1596
- env->regs[15] &= ~1U;
1597
- if (!arm_feature(env, ARM_FEATURE_V8)) {
1598
- qemu_log_mask(LOG_GUEST_ERROR,
1599
- "M profile return from interrupt with misaligned "
1600
- "PC is UNPREDICTABLE on v7M\n");
1601
- }
1602
- }
1603
-
1604
- if (arm_feature(env, ARM_FEATURE_V8)) {
1605
- /*
1606
- * For v8M we have to check whether the xPSR exception field
1607
- * matches the EXCRET value for return to handler/thread
1608
- * before we commit to changing the SP and xPSR.
1609
- */
1610
- bool will_be_handler = (xpsr & XPSR_EXCP) != 0;
1611
- if (return_to_handler != will_be_handler) {
1612
- /*
1613
- * Take an INVPC UsageFault on the current stack.
1614
- * By this point we will have switched to the security state
1615
- * for the background state, so this UsageFault will target
1616
- * that state.
1617
- */
1618
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
1619
- env->v7m.secure);
1620
- env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
1621
- qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on existing "
1622
- "stackframe: failed exception return integrity "
1623
- "check\n");
1624
- v7m_exception_taken(cpu, excret, true, false);
1625
- return;
1626
- }
1627
- }
1628
-
1629
- if (!ftype) {
1630
- /* FP present and we need to handle it */
1631
- if (!return_to_secure &&
1632
- (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPACT_MASK)) {
1633
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
1634
- env->v7m.sfsr |= R_V7M_SFSR_LSERR_MASK;
1635
- qemu_log_mask(CPU_LOG_INT,
1636
- "...taking SecureFault on existing stackframe: "
1637
- "Secure LSPACT set but exception return is "
1638
- "not to secure state\n");
1639
- v7m_exception_taken(cpu, excret, true, false);
1640
- return;
1641
- }
1642
-
1643
- restore_s16_s31 = return_to_secure &&
1644
- (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK);
1645
-
1646
- if (env->v7m.fpccr[return_to_secure] & R_V7M_FPCCR_LSPACT_MASK) {
1647
- /* State in FPU is still valid, just clear LSPACT */
1648
- env->v7m.fpccr[return_to_secure] &= ~R_V7M_FPCCR_LSPACT_MASK;
1649
- } else {
1650
- int i;
1651
- uint32_t fpscr;
1652
- bool cpacr_pass, nsacr_pass;
1653
-
1654
- cpacr_pass = v7m_cpacr_pass(env, return_to_secure,
1655
- return_to_priv);
1656
- nsacr_pass = return_to_secure ||
1657
- extract32(env->v7m.nsacr, 10, 1);
1658
-
1659
- if (!cpacr_pass) {
1660
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
1661
- return_to_secure);
1662
- env->v7m.cfsr[return_to_secure] |= R_V7M_CFSR_NOCP_MASK;
1663
- qemu_log_mask(CPU_LOG_INT,
1664
- "...taking UsageFault on existing "
1665
- "stackframe: CPACR.CP10 prevents unstacking "
1666
- "FP regs\n");
1667
- v7m_exception_taken(cpu, excret, true, false);
1668
- return;
1669
- } else if (!nsacr_pass) {
1670
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, true);
1671
- env->v7m.cfsr[M_REG_S] |= R_V7M_CFSR_INVPC_MASK;
1672
- qemu_log_mask(CPU_LOG_INT,
1673
- "...taking Secure UsageFault on existing "
1674
- "stackframe: NSACR.CP10 prevents unstacking "
1675
- "FP regs\n");
1676
- v7m_exception_taken(cpu, excret, true, false);
1677
- return;
1678
- }
1679
-
1680
- for (i = 0; i < (restore_s16_s31 ? 32 : 16); i += 2) {
1681
- uint32_t slo, shi;
1682
- uint64_t dn;
1683
- uint32_t faddr = frameptr + 0x20 + 4 * i;
1684
-
1685
- if (i >= 16) {
1686
- faddr += 8; /* Skip the slot for the FPSCR */
1687
- }
1688
-
1689
- pop_ok = pop_ok &&
1690
- v7m_stack_read(cpu, &slo, faddr, mmu_idx) &&
1691
- v7m_stack_read(cpu, &shi, faddr + 4, mmu_idx);
1692
-
1693
- if (!pop_ok) {
1694
- break;
1695
- }
1696
-
1697
- dn = (uint64_t)shi << 32 | slo;
1698
- *aa32_vfp_dreg(env, i / 2) = dn;
1699
- }
1700
- pop_ok = pop_ok &&
1701
- v7m_stack_read(cpu, &fpscr, frameptr + 0x60, mmu_idx);
1702
- if (pop_ok) {
1703
- vfp_set_fpscr(env, fpscr);
1704
- }
1705
- if (!pop_ok) {
1706
- /*
1707
- * These regs are 0 if security extension present;
1708
- * otherwise merely UNKNOWN. We zero always.
1709
- */
1710
- for (i = 0; i < (restore_s16_s31 ? 32 : 16); i += 2) {
1711
- *aa32_vfp_dreg(env, i / 2) = 0;
1712
- }
1713
- vfp_set_fpscr(env, 0);
1714
- }
1715
- }
1716
- }
1717
- env->v7m.control[M_REG_S] = FIELD_DP32(env->v7m.control[M_REG_S],
1718
- V7M_CONTROL, FPCA, !ftype);
1719
-
1720
- /* Commit to consuming the stack frame */
1721
- frameptr += 0x20;
1722
- if (!ftype) {
1723
- frameptr += 0x48;
1724
- if (restore_s16_s31) {
1725
- frameptr += 0x40;
1726
- }
1727
- }
1728
- /*
1729
- * Undo stack alignment (the SPREALIGN bit indicates that the original
1730
- * pre-exception SP was not 8-aligned and we added a padding word to
1731
- * align it, so we undo this by ORing in the bit that increases it
1732
- * from the current 8-aligned value to the 8-unaligned value. (Adding 4
1733
- * would work too but a logical OR is how the pseudocode specifies it.)
1734
- */
1735
- if (xpsr & XPSR_SPREALIGN) {
1736
- frameptr |= 4;
1737
- }
1738
- *frame_sp_p = frameptr;
1739
- }
1740
-
1741
- xpsr_mask = ~(XPSR_SPREALIGN | XPSR_SFPA);
1742
- if (!arm_feature(env, ARM_FEATURE_THUMB_DSP)) {
1743
- xpsr_mask &= ~XPSR_GE;
1744
- }
1745
- /* This xpsr_write() will invalidate frame_sp_p as it may switch stack */
1746
- xpsr_write(env, xpsr, xpsr_mask);
1747
-
1748
- if (env->v7m.secure) {
1749
- bool sfpa = xpsr & XPSR_SFPA;
1750
-
1751
- env->v7m.control[M_REG_S] = FIELD_DP32(env->v7m.control[M_REG_S],
1752
- V7M_CONTROL, SFPA, sfpa);
1753
- }
1754
-
1755
- /*
1756
- * The restored xPSR exception field will be zero if we're
1757
- * resuming in Thread mode. If that doesn't match what the
1758
- * exception return excret specified then this is a UsageFault.
1759
- * v7M requires we make this check here; v8M did it earlier.
1760
- */
1761
- if (return_to_handler != arm_v7m_is_handler_mode(env)) {
1762
- /*
1763
- * Take an INVPC UsageFault by pushing the stack again;
1764
- * we know we're v7M so this is never a Secure UsageFault.
1765
- */
1766
- bool ignore_stackfaults;
1767
-
1768
- assert(!arm_feature(env, ARM_FEATURE_V8));
1769
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, false);
1770
- env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
1771
- ignore_stackfaults = v7m_push_stack(cpu);
1772
- qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on new stackframe: "
1773
- "failed exception return integrity check\n");
1774
- v7m_exception_taken(cpu, excret, false, ignore_stackfaults);
1775
- return;
1776
- }
1777
-
1778
- /* Otherwise, we have a successful exception exit. */
1779
- arm_clear_exclusive(env);
1780
- qemu_log_mask(CPU_LOG_INT, "...successful exception return\n");
1781
-}
1782
-
1783
-static bool do_v7m_function_return(ARMCPU *cpu)
1784
-{
1785
- /*
1786
- * v8M security extensions magic function return.
1787
- * We may either:
1788
- * (1) throw an exception (longjump)
1789
- * (2) return true if we successfully handled the function return
1790
- * (3) return false if we failed a consistency check and have
1791
- * pended a UsageFault that needs to be taken now
1792
- *
1793
- * At this point the magic return value is split between env->regs[15]
1794
- * and env->thumb. We don't bother to reconstitute it because we don't
1795
- * need it (all values are handled the same way).
1796
- */
1797
- CPUARMState *env = &cpu->env;
1798
- uint32_t newpc, newpsr, newpsr_exc;
1799
-
1800
- qemu_log_mask(CPU_LOG_INT, "...really v7M secure function return\n");
1801
-
1802
- {
1803
- bool threadmode, spsel;
1804
- TCGMemOpIdx oi;
1805
- ARMMMUIdx mmu_idx;
1806
- uint32_t *frame_sp_p;
1807
- uint32_t frameptr;
1808
-
1809
- /* Pull the return address and IPSR from the Secure stack */
1810
- threadmode = !arm_v7m_is_handler_mode(env);
1811
- spsel = env->v7m.control[M_REG_S] & R_V7M_CONTROL_SPSEL_MASK;
1812
-
1813
- frame_sp_p = get_v7m_sp_ptr(env, true, threadmode, spsel);
1814
- frameptr = *frame_sp_p;
1815
-
1816
- /*
1817
- * These loads may throw an exception (for MPU faults). We want to
1818
- * do them as secure, so work out what MMU index that is.
1819
- */
1820
- mmu_idx = arm_v7m_mmu_idx_for_secstate(env, true);
1821
- oi = make_memop_idx(MO_LE, arm_to_core_mmu_idx(mmu_idx));
1822
- newpc = helper_le_ldul_mmu(env, frameptr, oi, 0);
1823
- newpsr = helper_le_ldul_mmu(env, frameptr + 4, oi, 0);
1824
-
1825
- /* Consistency checks on new IPSR */
1826
- newpsr_exc = newpsr & XPSR_EXCP;
1827
- if (!((env->v7m.exception == 0 && newpsr_exc == 0) ||
1828
- (env->v7m.exception == 1 && newpsr_exc != 0))) {
1829
- /* Pend the fault and tell our caller to take it */
1830
- env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
1831
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
1832
- env->v7m.secure);
1833
- qemu_log_mask(CPU_LOG_INT,
1834
- "...taking INVPC UsageFault: "
1835
- "IPSR consistency check failed\n");
1836
- return false;
1837
- }
1838
-
1839
- *frame_sp_p = frameptr + 8;
1840
- }
1841
-
1842
- /* This invalidates frame_sp_p */
1843
- switch_v7m_security_state(env, true);
1844
- env->v7m.exception = newpsr_exc;
1845
- env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
1846
- if (newpsr & XPSR_SFPA) {
1847
- env->v7m.control[M_REG_S] |= R_V7M_CONTROL_SFPA_MASK;
1848
- }
1849
- xpsr_write(env, 0, XPSR_IT);
1850
- env->thumb = newpc & 1;
1851
- env->regs[15] = newpc & ~1;
1852
-
1853
- qemu_log_mask(CPU_LOG_INT, "...function return successful\n");
1854
- return true;
1855
-}
1856
-
1857
-static bool v7m_read_half_insn(ARMCPU *cpu, ARMMMUIdx mmu_idx,
1858
- uint32_t addr, uint16_t *insn)
1859
-{
1860
- /*
1861
- * Load a 16-bit portion of a v7M instruction, returning true on success,
1862
- * or false on failure (in which case we will have pended the appropriate
1863
- * exception).
1864
- * We need to do the instruction fetch's MPU and SAU checks
1865
- * like this because there is no MMU index that would allow
1866
- * doing the load with a single function call. Instead we must
1867
- * first check that the security attributes permit the load
1868
- * and that they don't mismatch on the two halves of the instruction,
1869
- * and then we do the load as a secure load (ie using the security
1870
- * attributes of the address, not the CPU, as architecturally required).
1871
- */
1872
- CPUState *cs = CPU(cpu);
1873
- CPUARMState *env = &cpu->env;
1874
- V8M_SAttributes sattrs = {};
1875
- MemTxAttrs attrs = {};
1876
- ARMMMUFaultInfo fi = {};
1877
- MemTxResult txres;
1878
- target_ulong page_size;
1879
- hwaddr physaddr;
1880
- int prot;
1881
-
1882
- v8m_security_lookup(env, addr, MMU_INST_FETCH, mmu_idx, &sattrs);
1883
- if (!sattrs.nsc || sattrs.ns) {
1884
- /*
1885
- * This must be the second half of the insn, and it straddles a
1886
- * region boundary with the second half not being S&NSC.
1887
- */
1888
- env->v7m.sfsr |= R_V7M_SFSR_INVEP_MASK;
1889
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
1890
- qemu_log_mask(CPU_LOG_INT,
1891
- "...really SecureFault with SFSR.INVEP\n");
1892
- return false;
1893
- }
1894
- if (get_phys_addr(env, addr, MMU_INST_FETCH, mmu_idx,
1895
- &physaddr, &attrs, &prot, &page_size, &fi, NULL)) {
1896
- /* the MPU lookup failed */
1897
- env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_IACCVIOL_MASK;
1898
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM, env->v7m.secure);
1899
- qemu_log_mask(CPU_LOG_INT, "...really MemManage with CFSR.IACCVIOL\n");
1900
- return false;
1901
- }
1902
- *insn = address_space_lduw_le(arm_addressspace(cs, attrs), physaddr,
1903
- attrs, &txres);
1904
- if (txres != MEMTX_OK) {
1905
- env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_IBUSERR_MASK;
1906
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_BUS, false);
1907
- qemu_log_mask(CPU_LOG_INT, "...really BusFault with CFSR.IBUSERR\n");
1908
- return false;
1909
- }
1910
- return true;
1911
-}
1912
-
1913
-static bool v7m_handle_execute_nsc(ARMCPU *cpu)
1914
-{
1915
- /*
1916
- * Check whether this attempt to execute code in a Secure & NS-Callable
1917
- * memory region is for an SG instruction; if so, then emulate the
1918
- * effect of the SG instruction and return true. Otherwise pend
1919
- * the correct kind of exception and return false.
1920
- */
1921
- CPUARMState *env = &cpu->env;
1922
- ARMMMUIdx mmu_idx;
1923
- uint16_t insn;
1924
-
1925
- /*
1926
- * We should never get here unless get_phys_addr_pmsav8() caused
1927
- * an exception for NS executing in S&NSC memory.
1928
- */
1929
- assert(!env->v7m.secure);
1930
- assert(arm_feature(env, ARM_FEATURE_M_SECURITY));
1931
-
1932
- /* We want to do the MPU lookup as secure; work out what mmu_idx that is */
1933
- mmu_idx = arm_v7m_mmu_idx_for_secstate(env, true);
1934
-
1935
- if (!v7m_read_half_insn(cpu, mmu_idx, env->regs[15], &insn)) {
1936
- return false;
1937
- }
1938
-
1939
- if (!env->thumb) {
1940
- goto gen_invep;
1941
- }
1942
-
1943
- if (insn != 0xe97f) {
1944
- /*
1945
- * Not an SG instruction first half (we choose the IMPDEF
1946
- * early-SG-check option).
1947
- */
1948
- goto gen_invep;
1949
- }
1950
-
1951
- if (!v7m_read_half_insn(cpu, mmu_idx, env->regs[15] + 2, &insn)) {
1952
- return false;
1953
- }
1954
-
1955
- if (insn != 0xe97f) {
1956
- /*
1957
- * Not an SG instruction second half (yes, both halves of the SG
1958
- * insn have the same hex value)
1959
- */
1960
- goto gen_invep;
1961
- }
1962
-
1963
- /*
1964
- * OK, we have confirmed that we really have an SG instruction.
1965
- * We know we're NS in S memory so don't need to repeat those checks.
1966
- */
1967
- qemu_log_mask(CPU_LOG_INT, "...really an SG instruction at 0x%08" PRIx32
1968
- ", executing it\n", env->regs[15]);
1969
- env->regs[14] &= ~1;
1970
- env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
1971
- switch_v7m_security_state(env, true);
1972
- xpsr_write(env, 0, XPSR_IT);
1973
- env->regs[15] += 4;
1974
- return true;
1975
-
1976
-gen_invep:
1977
- env->v7m.sfsr |= R_V7M_SFSR_INVEP_MASK;
1978
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
1979
- qemu_log_mask(CPU_LOG_INT,
1980
- "...really SecureFault with SFSR.INVEP\n");
1981
- return false;
1982
-}
1983
-
1984
-void arm_v7m_cpu_do_interrupt(CPUState *cs)
1985
-{
1986
- ARMCPU *cpu = ARM_CPU(cs);
1987
- CPUARMState *env = &cpu->env;
1988
- uint32_t lr;
1989
- bool ignore_stackfaults;
1990
-
1991
- arm_log_exception(cs->exception_index);
1992
-
1993
- /*
1994
- * For exceptions we just mark as pending on the NVIC, and let that
1995
- * handle it.
1996
- */
1997
- switch (cs->exception_index) {
1998
- case EXCP_UDEF:
1999
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
2000
- env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_UNDEFINSTR_MASK;
2001
- break;
2002
- case EXCP_NOCP:
2003
- {
2004
- /*
2005
- * NOCP might be directed to something other than the current
2006
- * security state if this fault is because of NSACR; we indicate
2007
- * the target security state using exception.target_el.
2008
- */
2009
- int target_secstate;
2010
-
2011
- if (env->exception.target_el == 3) {
2012
- target_secstate = M_REG_S;
2013
- } else {
2014
- target_secstate = env->v7m.secure;
2015
- }
2016
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, target_secstate);
2017
- env->v7m.cfsr[target_secstate] |= R_V7M_CFSR_NOCP_MASK;
2018
- break;
2019
- }
2020
- case EXCP_INVSTATE:
2021
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
2022
- env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVSTATE_MASK;
2023
- break;
2024
- case EXCP_STKOF:
2025
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
2026
- env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_STKOF_MASK;
2027
- break;
2028
- case EXCP_LSERR:
2029
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
2030
- env->v7m.sfsr |= R_V7M_SFSR_LSERR_MASK;
2031
- break;
2032
- case EXCP_UNALIGNED:
2033
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
2034
- env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_UNALIGNED_MASK;
2035
- break;
2036
- case EXCP_SWI:
2037
- /* The PC already points to the next instruction. */
2038
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SVC, env->v7m.secure);
2039
- break;
2040
- case EXCP_PREFETCH_ABORT:
2041
- case EXCP_DATA_ABORT:
2042
- /*
2043
- * Note that for M profile we don't have a guest facing FSR, but
2044
- * the env->exception.fsr will be populated by the code that
2045
- * raises the fault, in the A profile short-descriptor format.
2046
- */
2047
- switch (env->exception.fsr & 0xf) {
2048
- case M_FAKE_FSR_NSC_EXEC:
2049
- /*
2050
- * Exception generated when we try to execute code at an address
2051
- * which is marked as Secure & Non-Secure Callable and the CPU
2052
- * is in the Non-Secure state. The only instruction which can
2053
- * be executed like this is SG (and that only if both halves of
2054
- * the SG instruction have the same security attributes.)
2055
- * Everything else must generate an INVEP SecureFault, so we
2056
- * emulate the SG instruction here.
2057
- */
2058
- if (v7m_handle_execute_nsc(cpu)) {
2059
- return;
2060
- }
2061
- break;
2062
- case M_FAKE_FSR_SFAULT:
2063
- /*
2064
- * Various flavours of SecureFault for attempts to execute or
2065
- * access data in the wrong security state.
2066
- */
2067
- switch (cs->exception_index) {
2068
- case EXCP_PREFETCH_ABORT:
2069
- if (env->v7m.secure) {
2070
- env->v7m.sfsr |= R_V7M_SFSR_INVTRAN_MASK;
2071
- qemu_log_mask(CPU_LOG_INT,
2072
- "...really SecureFault with SFSR.INVTRAN\n");
2073
- } else {
2074
- env->v7m.sfsr |= R_V7M_SFSR_INVEP_MASK;
2075
- qemu_log_mask(CPU_LOG_INT,
2076
- "...really SecureFault with SFSR.INVEP\n");
2077
- }
2078
- break;
2079
- case EXCP_DATA_ABORT:
2080
- /* This must be an NS access to S memory */
2081
- env->v7m.sfsr |= R_V7M_SFSR_AUVIOL_MASK;
2082
- qemu_log_mask(CPU_LOG_INT,
2083
- "...really SecureFault with SFSR.AUVIOL\n");
2084
- break;
2085
- }
2086
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
2087
- break;
2088
- case 0x8: /* External Abort */
2089
- switch (cs->exception_index) {
2090
- case EXCP_PREFETCH_ABORT:
2091
- env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_IBUSERR_MASK;
2092
- qemu_log_mask(CPU_LOG_INT, "...with CFSR.IBUSERR\n");
2093
- break;
2094
- case EXCP_DATA_ABORT:
2095
- env->v7m.cfsr[M_REG_NS] |=
2096
- (R_V7M_CFSR_PRECISERR_MASK | R_V7M_CFSR_BFARVALID_MASK);
2097
- env->v7m.bfar = env->exception.vaddress;
2098
- qemu_log_mask(CPU_LOG_INT,
2099
- "...with CFSR.PRECISERR and BFAR 0x%x\n",
2100
- env->v7m.bfar);
2101
- break;
2102
- }
2103
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_BUS, false);
2104
- break;
2105
- default:
2106
- /*
2107
- * All other FSR values are either MPU faults or "can't happen
2108
- * for M profile" cases.
2109
- */
2110
- switch (cs->exception_index) {
2111
- case EXCP_PREFETCH_ABORT:
2112
- env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_IACCVIOL_MASK;
2113
- qemu_log_mask(CPU_LOG_INT, "...with CFSR.IACCVIOL\n");
2114
- break;
2115
- case EXCP_DATA_ABORT:
2116
- env->v7m.cfsr[env->v7m.secure] |=
2117
- (R_V7M_CFSR_DACCVIOL_MASK | R_V7M_CFSR_MMARVALID_MASK);
2118
- env->v7m.mmfar[env->v7m.secure] = env->exception.vaddress;
2119
- qemu_log_mask(CPU_LOG_INT,
2120
- "...with CFSR.DACCVIOL and MMFAR 0x%x\n",
2121
- env->v7m.mmfar[env->v7m.secure]);
2122
- break;
2123
- }
2124
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM,
2125
- env->v7m.secure);
2126
- break;
2127
- }
2128
- break;
2129
- case EXCP_BKPT:
2130
- if (semihosting_enabled()) {
2131
- int nr;
2132
- nr = arm_lduw_code(env, env->regs[15], arm_sctlr_b(env)) & 0xff;
2133
- if (nr == 0xab) {
2134
- env->regs[15] += 2;
2135
- qemu_log_mask(CPU_LOG_INT,
2136
- "...handling as semihosting call 0x%x\n",
2137
- env->regs[0]);
2138
- env->regs[0] = do_arm_semihosting(env);
2139
- return;
2140
- }
2141
- }
2142
- armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_DEBUG, false);
2143
- break;
2144
- case EXCP_IRQ:
2145
- break;
2146
- case EXCP_EXCEPTION_EXIT:
2147
- if (env->regs[15] < EXC_RETURN_MIN_MAGIC) {
2148
- /* Must be v8M security extension function return */
2149
- assert(env->regs[15] >= FNC_RETURN_MIN_MAGIC);
2150
- assert(arm_feature(env, ARM_FEATURE_M_SECURITY));
2151
- if (do_v7m_function_return(cpu)) {
2152
- return;
2153
- }
2154
- } else {
2155
- do_v7m_exception_exit(cpu);
2156
- return;
2157
- }
2158
- break;
2159
- case EXCP_LAZYFP:
2160
- /*
2161
- * We already pended the specific exception in the NVIC in the
2162
- * v7m_preserve_fp_state() helper function.
2163
- */
2164
- break;
2165
- default:
2166
- cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index);
2167
- return; /* Never happens. Keep compiler happy. */
2168
- }
2169
-
2170
- if (arm_feature(env, ARM_FEATURE_V8)) {
2171
- lr = R_V7M_EXCRET_RES1_MASK |
2172
- R_V7M_EXCRET_DCRS_MASK;
2173
- /*
2174
- * The S bit indicates whether we should return to Secure
2175
- * or NonSecure (ie our current state).
2176
- * The ES bit indicates whether we're taking this exception
2177
- * to Secure or NonSecure (ie our target state). We set it
2178
- * later, in v7m_exception_taken().
2179
- * The SPSEL bit is also set in v7m_exception_taken() for v8M.
2180
- * This corresponds to the ARM ARM pseudocode for v8M setting
2181
- * some LR bits in PushStack() and some in ExceptionTaken();
2182
- * the distinction matters for the tailchain cases where we
2183
- * can take an exception without pushing the stack.
2184
- */
2185
- if (env->v7m.secure) {
2186
- lr |= R_V7M_EXCRET_S_MASK;
2187
- }
2188
- if (!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK)) {
2189
- lr |= R_V7M_EXCRET_FTYPE_MASK;
2190
- }
2191
- } else {
2192
- lr = R_V7M_EXCRET_RES1_MASK |
2193
- R_V7M_EXCRET_S_MASK |
2194
- R_V7M_EXCRET_DCRS_MASK |
2195
- R_V7M_EXCRET_FTYPE_MASK |
2196
- R_V7M_EXCRET_ES_MASK;
2197
- if (env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_MASK) {
2198
- lr |= R_V7M_EXCRET_SPSEL_MASK;
2199
- }
2200
- }
2201
- if (!arm_v7m_is_handler_mode(env)) {
2202
- lr |= R_V7M_EXCRET_MODE_MASK;
2203
- }
2204
-
2205
- ignore_stackfaults = v7m_push_stack(cpu);
2206
- v7m_exception_taken(cpu, lr, false, ignore_stackfaults);
2207
-}
2208
-
2209
/*
2210
* Function used to synchronize QEMU's AArch64 register set with AArch32
2211
* register set. This is necessary when switching between AArch32 and AArch64
2212
@@ -XXX,XX +XXX,XX @@ hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr,
2213
return phys_addr;
2214
}
2215
2216
-uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
2217
-{
2218
- uint32_t mask;
2219
- unsigned el = arm_current_el(env);
2220
-
2221
- /* First handle registers which unprivileged can read */
2222
-
2223
- switch (reg) {
2224
- case 0 ... 7: /* xPSR sub-fields */
2225
- mask = 0;
2226
- if ((reg & 1) && el) {
2227
- mask |= XPSR_EXCP; /* IPSR (unpriv. reads as zero) */
2228
- }
2229
- if (!(reg & 4)) {
2230
- mask |= XPSR_NZCV | XPSR_Q; /* APSR */
2231
- if (arm_feature(env, ARM_FEATURE_THUMB_DSP)) {
2232
- mask |= XPSR_GE;
2233
- }
2234
- }
2235
- /* EPSR reads as zero */
2236
- return xpsr_read(env) & mask;
2237
- break;
2238
- case 20: /* CONTROL */
2239
- {
2240
- uint32_t value = env->v7m.control[env->v7m.secure];
2241
- if (!env->v7m.secure) {
2242
- /* SFPA is RAZ/WI from NS; FPCA is stored in the M_REG_S bank */
2243
- value |= env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK;
2244
- }
2245
- return value;
2246
- }
2247
- case 0x94: /* CONTROL_NS */
2248
- /*
2249
- * We have to handle this here because unprivileged Secure code
2250
- * can read the NS CONTROL register.
2251
- */
2252
- if (!env->v7m.secure) {
2253
- return 0;
2254
- }
2255
- return env->v7m.control[M_REG_NS] |
2256
- (env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK);
2257
- }
2258
-
2259
- if (el == 0) {
2260
- return 0; /* unprivileged reads others as zero */
2261
- }
2262
-
2263
- if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
2264
- switch (reg) {
2265
- case 0x88: /* MSP_NS */
2266
- if (!env->v7m.secure) {
2267
- return 0;
2268
- }
2269
- return env->v7m.other_ss_msp;
2270
- case 0x89: /* PSP_NS */
2271
- if (!env->v7m.secure) {
2272
- return 0;
2273
- }
2274
- return env->v7m.other_ss_psp;
2275
- case 0x8a: /* MSPLIM_NS */
2276
- if (!env->v7m.secure) {
2277
- return 0;
2278
- }
2279
- return env->v7m.msplim[M_REG_NS];
2280
- case 0x8b: /* PSPLIM_NS */
2281
- if (!env->v7m.secure) {
2282
- return 0;
2283
- }
2284
- return env->v7m.psplim[M_REG_NS];
2285
- case 0x90: /* PRIMASK_NS */
2286
- if (!env->v7m.secure) {
2287
- return 0;
2288
- }
2289
- return env->v7m.primask[M_REG_NS];
2290
- case 0x91: /* BASEPRI_NS */
2291
- if (!env->v7m.secure) {
2292
- return 0;
2293
- }
2294
- return env->v7m.basepri[M_REG_NS];
2295
- case 0x93: /* FAULTMASK_NS */
2296
- if (!env->v7m.secure) {
2297
- return 0;
2298
- }
2299
- return env->v7m.faultmask[M_REG_NS];
2300
- case 0x98: /* SP_NS */
2301
- {
2302
- /*
2303
- * This gives the non-secure SP selected based on whether we're
2304
- * currently in handler mode or not, using the NS CONTROL.SPSEL.
2305
- */
2306
- bool spsel = env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_MASK;
2307
-
2308
- if (!env->v7m.secure) {
2309
- return 0;
2310
- }
2311
- if (!arm_v7m_is_handler_mode(env) && spsel) {
2312
- return env->v7m.other_ss_psp;
2313
- } else {
2314
- return env->v7m.other_ss_msp;
2315
- }
2316
- }
2317
- default:
2318
- break;
2319
- }
2320
- }
2321
-
2322
- switch (reg) {
2323
- case 8: /* MSP */
2324
- return v7m_using_psp(env) ? env->v7m.other_sp : env->regs[13];
2325
- case 9: /* PSP */
2326
- return v7m_using_psp(env) ? env->regs[13] : env->v7m.other_sp;
2327
- case 10: /* MSPLIM */
2328
- if (!arm_feature(env, ARM_FEATURE_V8)) {
2329
- goto bad_reg;
2330
- }
2331
- return env->v7m.msplim[env->v7m.secure];
2332
- case 11: /* PSPLIM */
2333
- if (!arm_feature(env, ARM_FEATURE_V8)) {
2334
- goto bad_reg;
2335
- }
2336
- return env->v7m.psplim[env->v7m.secure];
2337
- case 16: /* PRIMASK */
2338
- return env->v7m.primask[env->v7m.secure];
2339
- case 17: /* BASEPRI */
2340
- case 18: /* BASEPRI_MAX */
2341
- return env->v7m.basepri[env->v7m.secure];
2342
- case 19: /* FAULTMASK */
2343
- return env->v7m.faultmask[env->v7m.secure];
2344
- default:
2345
- bad_reg:
2346
- qemu_log_mask(LOG_GUEST_ERROR, "Attempt to read unknown special"
2347
- " register %d\n", reg);
2348
- return 0;
2349
- }
2350
-}
2351
-
2352
-void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val)
2353
-{
2354
- /*
2355
- * We're passed bits [11..0] of the instruction; extract
2356
- * SYSm and the mask bits.
2357
- * Invalid combinations of SYSm and mask are UNPREDICTABLE;
2358
- * we choose to treat them as if the mask bits were valid.
2359
- * NB that the pseudocode 'mask' variable is bits [11..10],
2360
- * whereas ours is [11..8].
2361
- */
2362
- uint32_t mask = extract32(maskreg, 8, 4);
2363
- uint32_t reg = extract32(maskreg, 0, 8);
2364
- int cur_el = arm_current_el(env);
2365
-
2366
- if (cur_el == 0 && reg > 7 && reg != 20) {
2367
- /*
2368
- * only xPSR sub-fields and CONTROL.SFPA may be written by
2369
- * unprivileged code
2370
- */
2371
- return;
2372
- }
2373
-
2374
- if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
2375
- switch (reg) {
2376
- case 0x88: /* MSP_NS */
2377
- if (!env->v7m.secure) {
2378
- return;
2379
- }
2380
- env->v7m.other_ss_msp = val;
2381
- return;
2382
- case 0x89: /* PSP_NS */
2383
- if (!env->v7m.secure) {
2384
- return;
2385
- }
2386
- env->v7m.other_ss_psp = val;
2387
- return;
2388
- case 0x8a: /* MSPLIM_NS */
2389
- if (!env->v7m.secure) {
2390
- return;
2391
- }
2392
- env->v7m.msplim[M_REG_NS] = val & ~7;
2393
- return;
2394
- case 0x8b: /* PSPLIM_NS */
2395
- if (!env->v7m.secure) {
2396
- return;
2397
- }
2398
- env->v7m.psplim[M_REG_NS] = val & ~7;
2399
- return;
2400
- case 0x90: /* PRIMASK_NS */
2401
- if (!env->v7m.secure) {
2402
- return;
2403
- }
2404
- env->v7m.primask[M_REG_NS] = val & 1;
2405
- return;
2406
- case 0x91: /* BASEPRI_NS */
2407
- if (!env->v7m.secure || !arm_feature(env, ARM_FEATURE_M_MAIN)) {
2408
- return;
2409
- }
2410
- env->v7m.basepri[M_REG_NS] = val & 0xff;
2411
- return;
2412
- case 0x93: /* FAULTMASK_NS */
2413
- if (!env->v7m.secure || !arm_feature(env, ARM_FEATURE_M_MAIN)) {
2414
- return;
2415
- }
2416
- env->v7m.faultmask[M_REG_NS] = val & 1;
2417
- return;
2418
- case 0x94: /* CONTROL_NS */
2419
- if (!env->v7m.secure) {
2420
- return;
2421
- }
2422
- write_v7m_control_spsel_for_secstate(env,
2423
- val & R_V7M_CONTROL_SPSEL_MASK,
2424
- M_REG_NS);
2425
- if (arm_feature(env, ARM_FEATURE_M_MAIN)) {
2426
- env->v7m.control[M_REG_NS] &= ~R_V7M_CONTROL_NPRIV_MASK;
2427
- env->v7m.control[M_REG_NS] |= val & R_V7M_CONTROL_NPRIV_MASK;
2428
- }
2429
- /*
2430
- * SFPA is RAZ/WI from NS. FPCA is RO if NSACR.CP10 == 0,
2431
- * RES0 if the FPU is not present, and is stored in the S bank
2432
- */
2433
- if (arm_feature(env, ARM_FEATURE_VFP) &&
2434
- extract32(env->v7m.nsacr, 10, 1)) {
2435
- env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_FPCA_MASK;
2436
- env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_FPCA_MASK;
2437
- }
2438
- return;
2439
- case 0x98: /* SP_NS */
2440
- {
2441
- /*
2442
- * This gives the non-secure SP selected based on whether we're
2443
- * currently in handler mode or not, using the NS CONTROL.SPSEL.
2444
- */
2445
- bool spsel = env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_MASK;
2446
- bool is_psp = !arm_v7m_is_handler_mode(env) && spsel;
2447
- uint32_t limit;
2448
-
2449
- if (!env->v7m.secure) {
2450
- return;
2451
- }
2452
-
2453
- limit = is_psp ? env->v7m.psplim[false] : env->v7m.msplim[false];
2454
-
2455
- if (val < limit) {
2456
- CPUState *cs = env_cpu(env);
2457
-
2458
- cpu_restore_state(cs, GETPC(), true);
2459
- raise_exception(env, EXCP_STKOF, 0, 1);
2460
- }
2461
-
2462
- if (is_psp) {
2463
- env->v7m.other_ss_psp = val;
2464
- } else {
2465
- env->v7m.other_ss_msp = val;
2466
- }
2467
- return;
2468
- }
2469
- default:
2470
- break;
2471
- }
2472
- }
2473
-
2474
- switch (reg) {
2475
- case 0 ... 7: /* xPSR sub-fields */
2476
- /* only APSR is actually writable */
2477
- if (!(reg & 4)) {
2478
- uint32_t apsrmask = 0;
2479
-
2480
- if (mask & 8) {
2481
- apsrmask |= XPSR_NZCV | XPSR_Q;
2482
- }
2483
- if ((mask & 4) && arm_feature(env, ARM_FEATURE_THUMB_DSP)) {
2484
- apsrmask |= XPSR_GE;
2485
- }
2486
- xpsr_write(env, val, apsrmask);
2487
- }
2488
- break;
2489
- case 8: /* MSP */
2490
- if (v7m_using_psp(env)) {
2491
- env->v7m.other_sp = val;
2492
- } else {
2493
- env->regs[13] = val;
2494
- }
2495
- break;
2496
- case 9: /* PSP */
2497
- if (v7m_using_psp(env)) {
2498
- env->regs[13] = val;
2499
- } else {
2500
- env->v7m.other_sp = val;
2501
- }
2502
- break;
2503
- case 10: /* MSPLIM */
2504
- if (!arm_feature(env, ARM_FEATURE_V8)) {
2505
- goto bad_reg;
2506
- }
2507
- env->v7m.msplim[env->v7m.secure] = val & ~7;
2508
- break;
2509
- case 11: /* PSPLIM */
2510
- if (!arm_feature(env, ARM_FEATURE_V8)) {
2511
- goto bad_reg;
2512
- }
2513
- env->v7m.psplim[env->v7m.secure] = val & ~7;
2514
- break;
2515
- case 16: /* PRIMASK */
2516
- env->v7m.primask[env->v7m.secure] = val & 1;
2517
- break;
2518
- case 17: /* BASEPRI */
2519
- if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
2520
- goto bad_reg;
2521
- }
2522
- env->v7m.basepri[env->v7m.secure] = val & 0xff;
2523
- break;
2524
- case 18: /* BASEPRI_MAX */
2525
- if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
2526
- goto bad_reg;
2527
- }
2528
- val &= 0xff;
2529
- if (val != 0 && (val < env->v7m.basepri[env->v7m.secure]
2530
- || env->v7m.basepri[env->v7m.secure] == 0)) {
2531
- env->v7m.basepri[env->v7m.secure] = val;
2532
- }
2533
- break;
2534
- case 19: /* FAULTMASK */
2535
- if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
2536
- goto bad_reg;
2537
- }
2538
- env->v7m.faultmask[env->v7m.secure] = val & 1;
2539
- break;
2540
- case 20: /* CONTROL */
2541
- /*
2542
- * Writing to the SPSEL bit only has an effect if we are in
2543
- * thread mode; other bits can be updated by any privileged code.
2544
- * write_v7m_control_spsel() deals with updating the SPSEL bit in
2545
- * env->v7m.control, so we only need update the others.
2546
- * For v7M, we must just ignore explicit writes to SPSEL in handler
2547
- * mode; for v8M the write is permitted but will have no effect.
2548
- * All these bits are writes-ignored from non-privileged code,
2549
- * except for SFPA.
2550
- */
2551
- if (cur_el > 0 && (arm_feature(env, ARM_FEATURE_V8) ||
2552
- !arm_v7m_is_handler_mode(env))) {
2553
- write_v7m_control_spsel(env, (val & R_V7M_CONTROL_SPSEL_MASK) != 0);
2554
- }
2555
- if (cur_el > 0 && arm_feature(env, ARM_FEATURE_M_MAIN)) {
2556
- env->v7m.control[env->v7m.secure] &= ~R_V7M_CONTROL_NPRIV_MASK;
2557
- env->v7m.control[env->v7m.secure] |= val & R_V7M_CONTROL_NPRIV_MASK;
2558
- }
2559
- if (arm_feature(env, ARM_FEATURE_VFP)) {
2560
- /*
2561
- * SFPA is RAZ/WI from NS or if no FPU.
2562
- * FPCA is RO if NSACR.CP10 == 0, RES0 if the FPU is not present.
2563
- * Both are stored in the S bank.
2564
- */
2565
- if (env->v7m.secure) {
2566
- env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
2567
- env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_SFPA_MASK;
2568
- }
2569
- if (cur_el > 0 &&
2570
- (env->v7m.secure || !arm_feature(env, ARM_FEATURE_M_SECURITY) ||
2571
- extract32(env->v7m.nsacr, 10, 1))) {
2572
- env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_FPCA_MASK;
2573
- env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_FPCA_MASK;
2574
- }
2575
- }
2576
- break;
2577
- default:
2578
- bad_reg:
2579
- qemu_log_mask(LOG_GUEST_ERROR, "Attempt to write unknown special"
2580
- " register %d\n", reg);
2581
- return;
2582
- }
2583
-}
2584
-
2585
-uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
2586
-{
2587
- /* Implement the TT instruction. op is bits [7:6] of the insn. */
2588
- bool forceunpriv = op & 1;
2589
- bool alt = op & 2;
2590
- V8M_SAttributes sattrs = {};
2591
- uint32_t tt_resp;
2592
- bool r, rw, nsr, nsrw, mrvalid;
2593
- int prot;
2594
- ARMMMUFaultInfo fi = {};
2595
- MemTxAttrs attrs = {};
2596
- hwaddr phys_addr;
2597
- ARMMMUIdx mmu_idx;
2598
- uint32_t mregion;
2599
- bool targetpriv;
2600
- bool targetsec = env->v7m.secure;
2601
- bool is_subpage;
2602
-
2603
- /*
2604
- * Work out what the security state and privilege level we're
2605
- * interested in is...
2606
- */
2607
- if (alt) {
2608
- targetsec = !targetsec;
2609
- }
2610
-
2611
- if (forceunpriv) {
2612
- targetpriv = false;
2613
- } else {
2614
- targetpriv = arm_v7m_is_handler_mode(env) ||
2615
- !(env->v7m.control[targetsec] & R_V7M_CONTROL_NPRIV_MASK);
2616
- }
2617
-
2618
- /* ...and then figure out which MMU index this is */
2619
- mmu_idx = arm_v7m_mmu_idx_for_secstate_and_priv(env, targetsec, targetpriv);
2620
-
2621
- /*
2622
- * We know that the MPU and SAU don't care about the access type
2623
- * for our purposes beyond that we don't want to claim to be
2624
- * an insn fetch, so we arbitrarily call this a read.
2625
- */
2626
-
2627
- /*
2628
- * MPU region info only available for privileged or if
2629
- * inspecting the other MPU state.
2630
- */
2631
- if (arm_current_el(env) != 0 || alt) {
2632
- /* We can ignore the return value as prot is always set */
2633
- pmsav8_mpu_lookup(env, addr, MMU_DATA_LOAD, mmu_idx,
2634
- &phys_addr, &attrs, &prot, &is_subpage,
2635
- &fi, &mregion);
2636
- if (mregion == -1) {
2637
- mrvalid = false;
2638
- mregion = 0;
2639
- } else {
2640
- mrvalid = true;
2641
- }
2642
- r = prot & PAGE_READ;
2643
- rw = prot & PAGE_WRITE;
2644
- } else {
2645
- r = false;
2646
- rw = false;
2647
- mrvalid = false;
2648
- mregion = 0;
2649
- }
2650
-
2651
- if (env->v7m.secure) {
2652
- v8m_security_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, &sattrs);
2653
- nsr = sattrs.ns && r;
2654
- nsrw = sattrs.ns && rw;
2655
- } else {
2656
- sattrs.ns = true;
2657
- nsr = false;
2658
- nsrw = false;
2659
- }
2660
-
2661
- tt_resp = (sattrs.iregion << 24) |
2662
- (sattrs.irvalid << 23) |
2663
- ((!sattrs.ns) << 22) |
2664
- (nsrw << 21) |
2665
- (nsr << 20) |
2666
- (rw << 19) |
2667
- (r << 18) |
2668
- (sattrs.srvalid << 17) |
2669
- (mrvalid << 16) |
2670
- (sattrs.sregion << 8) |
2671
- mregion;
2672
-
2673
- return tt_resp;
2674
-}
2675
-
2676
#endif
2677
2678
/* Note that signed overflow is undefined in C. The following routines are
2679
@@ -XXX,XX +XXX,XX @@ int fp_exception_el(CPUARMState *env, int cur_el)
2680
return 0;
2681
}
2682
2683
-ARMMMUIdx arm_v7m_mmu_idx_all(CPUARMState *env,
2684
- bool secstate, bool priv, bool negpri)
2685
-{
2686
- ARMMMUIdx mmu_idx = ARM_MMU_IDX_M;
2687
-
2688
- if (priv) {
2689
- mmu_idx |= ARM_MMU_IDX_M_PRIV;
2690
- }
2691
-
2692
- if (negpri) {
2693
- mmu_idx |= ARM_MMU_IDX_M_NEGPRI;
2694
- }
2695
-
2696
- if (secstate) {
2697
- mmu_idx |= ARM_MMU_IDX_M_S;
2698
- }
2699
-
2700
- return mmu_idx;
2701
-}
2702
-
2703
-ARMMMUIdx arm_v7m_mmu_idx_for_secstate_and_priv(CPUARMState *env,
2704
- bool secstate, bool priv)
2705
-{
2706
- bool negpri = armv7m_nvic_neg_prio_requested(env->nvic, secstate);
2707
-
2708
- return arm_v7m_mmu_idx_all(env, secstate, priv, negpri);
2709
-}
2710
-
2711
-/* Return the MMU index for a v7M CPU in the specified security state */
2712
+#ifndef CONFIG_TCG
2713
ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate)
2714
{
2715
- bool priv = arm_current_el(env) != 0;
2716
-
2717
- return arm_v7m_mmu_idx_for_secstate_and_priv(env, secstate, priv);
2718
+ g_assert_not_reached();
2719
}
2720
+#endif
2721
2722
ARMMMUIdx arm_mmu_idx(CPUARMState *env)
2723
{
2724
diff --git a/target/arm/m_helper.c b/target/arm/m_helper.c
2725
new file mode 100644
2726
index XXXXXXX..XXXXXXX
2727
--- /dev/null
2728
+++ b/target/arm/m_helper.c
2729
@@ -XXX,XX +XXX,XX @@
2730
+/*
2731
+ * ARM generic helpers.
2732
+ *
2733
+ * This code is licensed under the GNU GPL v2 or later.
2734
+ *
2735
+ * SPDX-License-Identifier: GPL-2.0-or-later
2736
+ */
2737
+#include "qemu/osdep.h"
2738
+#include "qemu/units.h"
2739
+#include "target/arm/idau.h"
2740
+#include "trace.h"
2741
+#include "cpu.h"
2742
+#include "internals.h"
2743
+#include "exec/gdbstub.h"
2744
+#include "exec/helper-proto.h"
2745
+#include "qemu/host-utils.h"
2746
+#include "sysemu/sysemu.h"
2747
+#include "qemu/bitops.h"
2748
+#include "qemu/crc32c.h"
2749
+#include "qemu/qemu-print.h"
2750
+#include "exec/exec-all.h"
2751
+#include <zlib.h> /* For crc32 */
2752
+#include "hw/semihosting/semihost.h"
2753
+#include "sysemu/cpus.h"
2754
+#include "sysemu/kvm.h"
2755
+#include "qemu/range.h"
2756
+#include "qapi/qapi-commands-target.h"
2757
+#include "qapi/error.h"
2758
+#include "qemu/guest-random.h"
2759
+#ifdef CONFIG_TCG
2760
+#include "arm_ldst.h"
2761
+#include "exec/cpu_ldst.h"
2762
+#endif
2763
+
30
+
2764
+#ifdef CONFIG_USER_ONLY
31
+ if ((object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) &&
2765
+
32
+ !(object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)))) {
2766
+/* These should probably raise undefined insn exceptions. */
33
+ acpi_memory_unplug_request_cb(hotplug_dev, &s->memhp_state, dev, errp);
2767
+void HELPER(v7m_msr)(CPUARMState *env, uint32_t reg, uint32_t val)
34
+ } else {
2768
+{
35
+ error_setg(errp, "acpi: device unplug request for unsupported device"
2769
+ ARMCPU *cpu = env_archcpu(env);
36
+ " type: %s", object_get_typename(OBJECT(dev)));
2770
+
2771
+ cpu_abort(CPU(cpu), "v7m_msr %d\n", reg);
2772
+}
2773
+
2774
+uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
2775
+{
2776
+ ARMCPU *cpu = env_archcpu(env);
2777
+
2778
+ cpu_abort(CPU(cpu), "v7m_mrs %d\n", reg);
2779
+ return 0;
2780
+}
2781
+
2782
+void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest)
2783
+{
2784
+ /* translate.c should never generate calls here in user-only mode */
2785
+ g_assert_not_reached();
2786
+}
2787
+
2788
+void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest)
2789
+{
2790
+ /* translate.c should never generate calls here in user-only mode */
2791
+ g_assert_not_reached();
2792
+}
2793
+
2794
+void HELPER(v7m_preserve_fp_state)(CPUARMState *env)
2795
+{
2796
+ /* translate.c should never generate calls here in user-only mode */
2797
+ g_assert_not_reached();
2798
+}
2799
+
2800
+void HELPER(v7m_vlstm)(CPUARMState *env, uint32_t fptr)
2801
+{
2802
+ /* translate.c should never generate calls here in user-only mode */
2803
+ g_assert_not_reached();
2804
+}
2805
+
2806
+void HELPER(v7m_vlldm)(CPUARMState *env, uint32_t fptr)
2807
+{
2808
+ /* translate.c should never generate calls here in user-only mode */
2809
+ g_assert_not_reached();
2810
+}
2811
+
2812
+uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
2813
+{
2814
+ /*
2815
+ * The TT instructions can be used by unprivileged code, but in
2816
+ * user-only emulation we don't have the MPU.
2817
+ * Luckily since we know we are NonSecure unprivileged (and that in
2818
+ * turn means that the A flag wasn't specified), all the bits in the
2819
+ * register must be zero:
2820
+ * IREGION: 0 because IRVALID is 0
2821
+ * IRVALID: 0 because NS
2822
+ * S: 0 because NS
2823
+ * NSRW: 0 because NS
2824
+ * NSR: 0 because NS
2825
+ * RW: 0 because unpriv and A flag not set
2826
+ * R: 0 because unpriv and A flag not set
2827
+ * SRVALID: 0 because NS
2828
+ * MRVALID: 0 because unpriv and A flag not set
2829
+ * SREGION: 0 becaus SRVALID is 0
2830
+ * MREGION: 0 because MRVALID is 0
2831
+ */
2832
+ return 0;
2833
+}
2834
+
2835
+#else
2836
+
2837
+/*
2838
+ * What kind of stack write are we doing? This affects how exceptions
2839
+ * generated during the stacking are treated.
2840
+ */
2841
+typedef enum StackingMode {
2842
+ STACK_NORMAL,
2843
+ STACK_IGNFAULTS,
2844
+ STACK_LAZYFP,
2845
+} StackingMode;
2846
+
2847
+static bool v7m_stack_write(ARMCPU *cpu, uint32_t addr, uint32_t value,
2848
+ ARMMMUIdx mmu_idx, StackingMode mode)
2849
+{
2850
+ CPUState *cs = CPU(cpu);
2851
+ CPUARMState *env = &cpu->env;
2852
+ MemTxAttrs attrs = {};
2853
+ MemTxResult txres;
2854
+ target_ulong page_size;
2855
+ hwaddr physaddr;
2856
+ int prot;
2857
+ ARMMMUFaultInfo fi = {};
2858
+ bool secure = mmu_idx & ARM_MMU_IDX_M_S;
2859
+ int exc;
2860
+ bool exc_secure;
2861
+
2862
+ if (get_phys_addr(env, addr, MMU_DATA_STORE, mmu_idx, &physaddr,
2863
+ &attrs, &prot, &page_size, &fi, NULL)) {
2864
+ /* MPU/SAU lookup failed */
2865
+ if (fi.type == ARMFault_QEMU_SFault) {
2866
+ if (mode == STACK_LAZYFP) {
2867
+ qemu_log_mask(CPU_LOG_INT,
2868
+ "...SecureFault with SFSR.LSPERR "
2869
+ "during lazy stacking\n");
2870
+ env->v7m.sfsr |= R_V7M_SFSR_LSPERR_MASK;
2871
+ } else {
2872
+ qemu_log_mask(CPU_LOG_INT,
2873
+ "...SecureFault with SFSR.AUVIOL "
2874
+ "during stacking\n");
2875
+ env->v7m.sfsr |= R_V7M_SFSR_AUVIOL_MASK;
2876
+ }
2877
+ env->v7m.sfsr |= R_V7M_SFSR_SFARVALID_MASK;
2878
+ env->v7m.sfar = addr;
2879
+ exc = ARMV7M_EXCP_SECURE;
2880
+ exc_secure = false;
2881
+ } else {
2882
+ if (mode == STACK_LAZYFP) {
2883
+ qemu_log_mask(CPU_LOG_INT,
2884
+ "...MemManageFault with CFSR.MLSPERR\n");
2885
+ env->v7m.cfsr[secure] |= R_V7M_CFSR_MLSPERR_MASK;
2886
+ } else {
2887
+ qemu_log_mask(CPU_LOG_INT,
2888
+ "...MemManageFault with CFSR.MSTKERR\n");
2889
+ env->v7m.cfsr[secure] |= R_V7M_CFSR_MSTKERR_MASK;
2890
+ }
2891
+ exc = ARMV7M_EXCP_MEM;
2892
+ exc_secure = secure;
2893
+ }
2894
+ goto pend_fault;
2895
+ }
2896
+ address_space_stl_le(arm_addressspace(cs, attrs), physaddr, value,
2897
+ attrs, &txres);
2898
+ if (txres != MEMTX_OK) {
2899
+ /* BusFault trying to write the data */
2900
+ if (mode == STACK_LAZYFP) {
2901
+ qemu_log_mask(CPU_LOG_INT, "...BusFault with BFSR.LSPERR\n");
2902
+ env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_LSPERR_MASK;
2903
+ } else {
2904
+ qemu_log_mask(CPU_LOG_INT, "...BusFault with BFSR.STKERR\n");
2905
+ env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_STKERR_MASK;
2906
+ }
2907
+ exc = ARMV7M_EXCP_BUS;
2908
+ exc_secure = false;
2909
+ goto pend_fault;
2910
+ }
2911
+ return true;
2912
+
2913
+pend_fault:
2914
+ /*
2915
+ * By pending the exception at this point we are making
2916
+ * the IMPDEF choice "overridden exceptions pended" (see the
2917
+ * MergeExcInfo() pseudocode). The other choice would be to not
2918
+ * pend them now and then make a choice about which to throw away
2919
+ * later if we have two derived exceptions.
2920
+ * The only case when we must not pend the exception but instead
2921
+ * throw it away is if we are doing the push of the callee registers
2922
+ * and we've already generated a derived exception (this is indicated
2923
+ * by the caller passing STACK_IGNFAULTS). Even in this case we will
2924
+ * still update the fault status registers.
2925
+ */
2926
+ switch (mode) {
2927
+ case STACK_NORMAL:
2928
+ armv7m_nvic_set_pending_derived(env->nvic, exc, exc_secure);
2929
+ break;
2930
+ case STACK_LAZYFP:
2931
+ armv7m_nvic_set_pending_lazyfp(env->nvic, exc, exc_secure);
2932
+ break;
2933
+ case STACK_IGNFAULTS:
2934
+ break;
2935
+ }
2936
+ return false;
2937
+}
2938
+
2939
+static bool v7m_stack_read(ARMCPU *cpu, uint32_t *dest, uint32_t addr,
2940
+ ARMMMUIdx mmu_idx)
2941
+{
2942
+ CPUState *cs = CPU(cpu);
2943
+ CPUARMState *env = &cpu->env;
2944
+ MemTxAttrs attrs = {};
2945
+ MemTxResult txres;
2946
+ target_ulong page_size;
2947
+ hwaddr physaddr;
2948
+ int prot;
2949
+ ARMMMUFaultInfo fi = {};
2950
+ bool secure = mmu_idx & ARM_MMU_IDX_M_S;
2951
+ int exc;
2952
+ bool exc_secure;
2953
+ uint32_t value;
2954
+
2955
+ if (get_phys_addr(env, addr, MMU_DATA_LOAD, mmu_idx, &physaddr,
2956
+ &attrs, &prot, &page_size, &fi, NULL)) {
2957
+ /* MPU/SAU lookup failed */
2958
+ if (fi.type == ARMFault_QEMU_SFault) {
2959
+ qemu_log_mask(CPU_LOG_INT,
2960
+ "...SecureFault with SFSR.AUVIOL during unstack\n");
2961
+ env->v7m.sfsr |= R_V7M_SFSR_AUVIOL_MASK | R_V7M_SFSR_SFARVALID_MASK;
2962
+ env->v7m.sfar = addr;
2963
+ exc = ARMV7M_EXCP_SECURE;
2964
+ exc_secure = false;
2965
+ } else {
2966
+ qemu_log_mask(CPU_LOG_INT,
2967
+ "...MemManageFault with CFSR.MUNSTKERR\n");
2968
+ env->v7m.cfsr[secure] |= R_V7M_CFSR_MUNSTKERR_MASK;
2969
+ exc = ARMV7M_EXCP_MEM;
2970
+ exc_secure = secure;
2971
+ }
2972
+ goto pend_fault;
2973
+ }
2974
+
2975
+ value = address_space_ldl(arm_addressspace(cs, attrs), physaddr,
2976
+ attrs, &txres);
2977
+ if (txres != MEMTX_OK) {
2978
+ /* BusFault trying to read the data */
2979
+ qemu_log_mask(CPU_LOG_INT, "...BusFault with BFSR.UNSTKERR\n");
2980
+ env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_UNSTKERR_MASK;
2981
+ exc = ARMV7M_EXCP_BUS;
2982
+ exc_secure = false;
2983
+ goto pend_fault;
2984
+ }
2985
+
2986
+ *dest = value;
2987
+ return true;
2988
+
2989
+pend_fault:
2990
+ /*
2991
+ * By pending the exception at this point we are making
2992
+ * the IMPDEF choice "overridden exceptions pended" (see the
2993
+ * MergeExcInfo() pseudocode). The other choice would be to not
2994
+ * pend them now and then make a choice about which to throw away
2995
+ * later if we have two derived exceptions.
2996
+ */
2997
+ armv7m_nvic_set_pending(env->nvic, exc, exc_secure);
2998
+ return false;
2999
+}
3000
+
3001
+void HELPER(v7m_preserve_fp_state)(CPUARMState *env)
3002
+{
3003
+ /*
3004
+ * Preserve FP state (because LSPACT was set and we are about
3005
+ * to execute an FP instruction). This corresponds to the
3006
+ * PreserveFPState() pseudocode.
3007
+ * We may throw an exception if the stacking fails.
3008
+ */
3009
+ ARMCPU *cpu = env_archcpu(env);
3010
+ bool is_secure = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK;
3011
+ bool negpri = !(env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_HFRDY_MASK);
3012
+ bool is_priv = !(env->v7m.fpccr[is_secure] & R_V7M_FPCCR_USER_MASK);
3013
+ bool splimviol = env->v7m.fpccr[is_secure] & R_V7M_FPCCR_SPLIMVIOL_MASK;
3014
+ uint32_t fpcar = env->v7m.fpcar[is_secure];
3015
+ bool stacked_ok = true;
3016
+ bool ts = is_secure && (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK);
3017
+ bool take_exception;
3018
+
3019
+ /* Take the iothread lock as we are going to touch the NVIC */
3020
+ qemu_mutex_lock_iothread();
3021
+
3022
+ /* Check the background context had access to the FPU */
3023
+ if (!v7m_cpacr_pass(env, is_secure, is_priv)) {
3024
+ armv7m_nvic_set_pending_lazyfp(env->nvic, ARMV7M_EXCP_USAGE, is_secure);
3025
+ env->v7m.cfsr[is_secure] |= R_V7M_CFSR_NOCP_MASK;
3026
+ stacked_ok = false;
3027
+ } else if (!is_secure && !extract32(env->v7m.nsacr, 10, 1)) {
3028
+ armv7m_nvic_set_pending_lazyfp(env->nvic, ARMV7M_EXCP_USAGE, M_REG_S);
3029
+ env->v7m.cfsr[M_REG_S] |= R_V7M_CFSR_NOCP_MASK;
3030
+ stacked_ok = false;
3031
+ }
3032
+
3033
+ if (!splimviol && stacked_ok) {
3034
+ /* We only stack if the stack limit wasn't violated */
3035
+ int i;
3036
+ ARMMMUIdx mmu_idx;
3037
+
3038
+ mmu_idx = arm_v7m_mmu_idx_all(env, is_secure, is_priv, negpri);
3039
+ for (i = 0; i < (ts ? 32 : 16); i += 2) {
3040
+ uint64_t dn = *aa32_vfp_dreg(env, i / 2);
3041
+ uint32_t faddr = fpcar + 4 * i;
3042
+ uint32_t slo = extract64(dn, 0, 32);
3043
+ uint32_t shi = extract64(dn, 32, 32);
3044
+
3045
+ if (i >= 16) {
3046
+ faddr += 8; /* skip the slot for the FPSCR */
3047
+ }
3048
+ stacked_ok = stacked_ok &&
3049
+ v7m_stack_write(cpu, faddr, slo, mmu_idx, STACK_LAZYFP) &&
3050
+ v7m_stack_write(cpu, faddr + 4, shi, mmu_idx, STACK_LAZYFP);
3051
+ }
3052
+
3053
+ stacked_ok = stacked_ok &&
3054
+ v7m_stack_write(cpu, fpcar + 0x40,
3055
+ vfp_get_fpscr(env), mmu_idx, STACK_LAZYFP);
3056
+ }
3057
+
3058
+ /*
3059
+ * We definitely pended an exception, but it's possible that it
3060
+ * might not be able to be taken now. If its priority permits us
3061
+ * to take it now, then we must not update the LSPACT or FP regs,
3062
+ * but instead jump out to take the exception immediately.
3063
+ * If it's just pending and won't be taken until the current
3064
+ * handler exits, then we do update LSPACT and the FP regs.
3065
+ */
3066
+ take_exception = !stacked_ok &&
3067
+ armv7m_nvic_can_take_pending_exception(env->nvic);
3068
+
3069
+ qemu_mutex_unlock_iothread();
3070
+
3071
+ if (take_exception) {
3072
+ raise_exception_ra(env, EXCP_LAZYFP, 0, 1, GETPC());
3073
+ }
3074
+
3075
+ env->v7m.fpccr[is_secure] &= ~R_V7M_FPCCR_LSPACT_MASK;
3076
+
3077
+ if (ts) {
3078
+ /* Clear s0 to s31 and the FPSCR */
3079
+ int i;
3080
+
3081
+ for (i = 0; i < 32; i += 2) {
3082
+ *aa32_vfp_dreg(env, i / 2) = 0;
3083
+ }
3084
+ vfp_set_fpscr(env, 0);
3085
+ }
3086
+ /*
3087
+ * Otherwise s0 to s15 and FPSCR are UNKNOWN; we choose to leave them
3088
+ * unchanged.
3089
+ */
3090
+}
3091
+
3092
+/*
3093
+ * Write to v7M CONTROL.SPSEL bit for the specified security bank.
3094
+ * This may change the current stack pointer between Main and Process
3095
+ * stack pointers if it is done for the CONTROL register for the current
3096
+ * security state.
3097
+ */
3098
+static void write_v7m_control_spsel_for_secstate(CPUARMState *env,
3099
+ bool new_spsel,
3100
+ bool secstate)
3101
+{
3102
+ bool old_is_psp = v7m_using_psp(env);
3103
+
3104
+ env->v7m.control[secstate] =
3105
+ deposit32(env->v7m.control[secstate],
3106
+ R_V7M_CONTROL_SPSEL_SHIFT,
3107
+ R_V7M_CONTROL_SPSEL_LENGTH, new_spsel);
3108
+
3109
+ if (secstate == env->v7m.secure) {
3110
+ bool new_is_psp = v7m_using_psp(env);
3111
+ uint32_t tmp;
3112
+
3113
+ if (old_is_psp != new_is_psp) {
3114
+ tmp = env->v7m.other_sp;
3115
+ env->v7m.other_sp = env->regs[13];
3116
+ env->regs[13] = tmp;
3117
+ }
3118
+ }
37
+ }
3119
+}
38
+}
3120
+
39
+
3121
+/*
40
+static void acpi_ged_unplug_cb(HotplugHandler *hotplug_dev,
3122
+ * Write to v7M CONTROL.SPSEL bit. This may change the current
41
+ DeviceState *dev, Error **errp)
3123
+ * stack pointer between Main and Process stack pointers.
3124
+ */
3125
+static void write_v7m_control_spsel(CPUARMState *env, bool new_spsel)
3126
+{
42
+{
3127
+ write_v7m_control_spsel_for_secstate(env, new_spsel, env->v7m.secure);
43
+ AcpiGedState *s = ACPI_GED(hotplug_dev);
3128
+}
3129
+
44
+
3130
+void write_v7m_exception(CPUARMState *env, uint32_t new_exc)
45
+ if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
3131
+{
46
+ acpi_memory_unplug_cb(&s->memhp_state, dev, errp);
3132
+ /*
47
+ } else {
3133
+ * Write a new value to v7m.exception, thus transitioning into or out
48
+ error_setg(errp, "acpi: device unplug for unsupported device"
3134
+ * of Handler mode; this may result in a change of active stack pointer.
49
+ " type: %s", object_get_typename(OBJECT(dev)));
3135
+ */
3136
+ bool new_is_psp, old_is_psp = v7m_using_psp(env);
3137
+ uint32_t tmp;
3138
+
3139
+ env->v7m.exception = new_exc;
3140
+
3141
+ new_is_psp = v7m_using_psp(env);
3142
+
3143
+ if (old_is_psp != new_is_psp) {
3144
+ tmp = env->v7m.other_sp;
3145
+ env->v7m.other_sp = env->regs[13];
3146
+ env->regs[13] = tmp;
3147
+ }
50
+ }
3148
+}
51
+}
3149
+
52
+
3150
+/* Switch M profile security state between NS and S */
53
static void acpi_ged_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev)
3151
+static void switch_v7m_security_state(CPUARMState *env, bool new_secstate)
54
{
55
AcpiGedState *s = ACPI_GED(adev);
56
@@ -XXX,XX +XXX,XX @@ static void acpi_ged_class_init(ObjectClass *class, void *data)
57
dc->vmsd = &vmstate_acpi_ged;
58
59
hc->plug = acpi_ged_device_plug_cb;
60
+ hc->unplug_request = acpi_ged_unplug_request_cb;
61
+ hc->unplug = acpi_ged_unplug_cb;
62
63
adevc->send_event = acpi_ged_send_event;
64
}
65
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
66
index XXXXXXX..XXXXXXX 100644
67
--- a/hw/arm/virt.c
68
+++ b/hw/arm/virt.c
69
@@ -XXX,XX +XXX,XX @@ static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev,
70
}
71
}
72
73
+static void virt_dimm_unplug_request(HotplugHandler *hotplug_dev,
74
+ DeviceState *dev, Error **errp)
3152
+{
75
+{
3153
+ uint32_t new_ss_msp, new_ss_psp;
76
+ VirtMachineState *vms = VIRT_MACHINE(hotplug_dev);
77
+ Error *local_err = NULL;
3154
+
78
+
3155
+ if (env->v7m.secure == new_secstate) {
79
+ if (!vms->acpi_dev) {
3156
+ return;
80
+ error_setg(&local_err,
81
+ "memory hotplug is not enabled: missing acpi-ged device");
82
+ goto out;
3157
+ }
83
+ }
3158
+
84
+
3159
+ /*
85
+ if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) {
3160
+ * All the banked state is accessed by looking at env->v7m.secure
86
+ error_setg(&local_err,
3161
+ * except for the stack pointer; rearrange the SP appropriately.
87
+ "nvdimm device hot unplug is not supported yet.");
3162
+ */
88
+ goto out;
3163
+ new_ss_msp = env->v7m.other_ss_msp;
3164
+ new_ss_psp = env->v7m.other_ss_psp;
3165
+
3166
+ if (v7m_using_psp(env)) {
3167
+ env->v7m.other_ss_psp = env->regs[13];
3168
+ env->v7m.other_ss_msp = env->v7m.other_sp;
3169
+ } else {
3170
+ env->v7m.other_ss_msp = env->regs[13];
3171
+ env->v7m.other_ss_psp = env->v7m.other_sp;
3172
+ }
89
+ }
3173
+
90
+
3174
+ env->v7m.secure = new_secstate;
91
+ hotplug_handler_unplug_request(HOTPLUG_HANDLER(vms->acpi_dev), dev,
92
+ &local_err);
93
+out:
94
+ error_propagate(errp, local_err);
95
+}
3175
+
96
+
3176
+ if (v7m_using_psp(env)) {
97
+static void virt_dimm_unplug(HotplugHandler *hotplug_dev,
3177
+ env->regs[13] = new_ss_psp;
98
+ DeviceState *dev, Error **errp)
3178
+ env->v7m.other_sp = new_ss_msp;
99
+{
100
+ VirtMachineState *vms = VIRT_MACHINE(hotplug_dev);
101
+ Error *local_err = NULL;
102
+
103
+ hotplug_handler_unplug(HOTPLUG_HANDLER(vms->acpi_dev), dev, &local_err);
104
+ if (local_err) {
105
+ goto out;
106
+ }
107
+
108
+ pc_dimm_unplug(PC_DIMM(dev), MACHINE(vms));
109
+ qdev_unrealize(dev);
110
+
111
+out:
112
+ error_propagate(errp, local_err);
113
+}
114
+
115
static void virt_machine_device_unplug_request_cb(HotplugHandler *hotplug_dev,
116
DeviceState *dev, Error **errp)
117
{
118
- error_setg(errp, "device unplug request for unsupported device"
119
- " type: %s", object_get_typename(OBJECT(dev)));
120
+ if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
121
+ virt_dimm_unplug_request(hotplug_dev, dev, errp);
3179
+ } else {
122
+ } else {
3180
+ env->regs[13] = new_ss_msp;
123
+ error_setg(errp, "device unplug request for unsupported device"
3181
+ env->v7m.other_sp = new_ss_psp;
124
+ " type: %s", object_get_typename(OBJECT(dev)));
3182
+ }
125
+ }
3183
+}
126
+}
3184
+
127
+
3185
+void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest)
128
+static void virt_machine_device_unplug_cb(HotplugHandler *hotplug_dev,
129
+ DeviceState *dev, Error **errp)
3186
+{
130
+{
3187
+ /*
131
+ if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
3188
+ * Handle v7M BXNS:
132
+ virt_dimm_unplug(hotplug_dev, dev, errp);
3189
+ * - if the return value is a magic value, do exception return (like BX)
3190
+ * - otherwise bit 0 of the return value is the target security state
3191
+ */
3192
+ uint32_t min_magic;
3193
+
3194
+ if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
3195
+ /* Covers FNC_RETURN and EXC_RETURN magic */
3196
+ min_magic = FNC_RETURN_MIN_MAGIC;
3197
+ } else {
133
+ } else {
3198
+ /* EXC_RETURN magic only */
134
+ error_setg(errp, "virt: device unplug for unsupported device"
3199
+ min_magic = EXC_RETURN_MIN_MAGIC;
135
+ " type: %s", object_get_typename(OBJECT(dev)));
3200
+ }
136
+ }
3201
+
137
}
3202
+ if (dest >= min_magic) {
138
3203
+ /*
139
static HotplugHandler *virt_machine_get_hotplug_handler(MachineState *machine,
3204
+ * This is an exception return magic value; put it where
140
@@ -XXX,XX +XXX,XX @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
3205
+ * do_v7m_exception_exit() expects and raise EXCEPTION_EXIT.
141
hc->pre_plug = virt_machine_device_pre_plug_cb;
3206
+ * Note that if we ever add gen_ss_advance() singlestep support to
142
hc->plug = virt_machine_device_plug_cb;
3207
+ * M profile this should count as an "instruction execution complete"
143
hc->unplug_request = virt_machine_device_unplug_request_cb;
3208
+ * event (compare gen_bx_excret_final_code()).
144
+ hc->unplug = virt_machine_device_unplug_cb;
3209
+ */
145
mc->numa_mem_supported = true;
3210
+ env->regs[15] = dest & ~1;
146
mc->nvdimm_supported = true;
3211
+ env->thumb = dest & 1;
147
mc->auto_enable_numa_with_memhp = true;
3212
+ HELPER(exception_internal)(env, EXCP_EXCEPTION_EXIT);
3213
+ /* notreached */
3214
+ }
3215
+
3216
+ /* translate.c should have made BXNS UNDEF unless we're secure */
3217
+ assert(env->v7m.secure);
3218
+
3219
+ if (!(dest & 1)) {
3220
+ env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
3221
+ }
3222
+ switch_v7m_security_state(env, dest & 1);
3223
+ env->thumb = 1;
3224
+ env->regs[15] = dest & ~1;
3225
+}
3226
+
3227
+void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest)
3228
+{
3229
+ /*
3230
+ * Handle v7M BLXNS:
3231
+ * - bit 0 of the destination address is the target security state
3232
+ */
3233
+
3234
+ /* At this point regs[15] is the address just after the BLXNS */
3235
+ uint32_t nextinst = env->regs[15] | 1;
3236
+ uint32_t sp = env->regs[13] - 8;
3237
+ uint32_t saved_psr;
3238
+
3239
+ /* translate.c will have made BLXNS UNDEF unless we're secure */
3240
+ assert(env->v7m.secure);
3241
+
3242
+ if (dest & 1) {
3243
+ /*
3244
+ * Target is Secure, so this is just a normal BLX,
3245
+ * except that the low bit doesn't indicate Thumb/not.
3246
+ */
3247
+ env->regs[14] = nextinst;
3248
+ env->thumb = 1;
3249
+ env->regs[15] = dest & ~1;
3250
+ return;
3251
+ }
3252
+
3253
+ /* Target is non-secure: first push a stack frame */
3254
+ if (!QEMU_IS_ALIGNED(sp, 8)) {
3255
+ qemu_log_mask(LOG_GUEST_ERROR,
3256
+ "BLXNS with misaligned SP is UNPREDICTABLE\n");
3257
+ }
3258
+
3259
+ if (sp < v7m_sp_limit(env)) {
3260
+ raise_exception(env, EXCP_STKOF, 0, 1);
3261
+ }
3262
+
3263
+ saved_psr = env->v7m.exception;
3264
+ if (env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK) {
3265
+ saved_psr |= XPSR_SFPA;
3266
+ }
3267
+
3268
+ /* Note that these stores can throw exceptions on MPU faults */
3269
+ cpu_stl_data(env, sp, nextinst);
3270
+ cpu_stl_data(env, sp + 4, saved_psr);
3271
+
3272
+ env->regs[13] = sp;
3273
+ env->regs[14] = 0xfeffffff;
3274
+ if (arm_v7m_is_handler_mode(env)) {
3275
+ /*
3276
+ * Write a dummy value to IPSR, to avoid leaking the current secure
3277
+ * exception number to non-secure code. This is guaranteed not
3278
+ * to cause write_v7m_exception() to actually change stacks.
3279
+ */
3280
+ write_v7m_exception(env, 1);
3281
+ }
3282
+ env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
3283
+ switch_v7m_security_state(env, 0);
3284
+ env->thumb = 1;
3285
+ env->regs[15] = dest;
3286
+}
3287
+
3288
+static uint32_t *get_v7m_sp_ptr(CPUARMState *env, bool secure, bool threadmode,
3289
+ bool spsel)
3290
+{
3291
+ /*
3292
+ * Return a pointer to the location where we currently store the
3293
+ * stack pointer for the requested security state and thread mode.
3294
+ * This pointer will become invalid if the CPU state is updated
3295
+ * such that the stack pointers are switched around (eg changing
3296
+ * the SPSEL control bit).
3297
+ * Compare the v8M ARM ARM pseudocode LookUpSP_with_security_mode().
3298
+ * Unlike that pseudocode, we require the caller to pass us in the
3299
+ * SPSEL control bit value; this is because we also use this
3300
+ * function in handling of pushing of the callee-saves registers
3301
+ * part of the v8M stack frame (pseudocode PushCalleeStack()),
3302
+ * and in the tailchain codepath the SPSEL bit comes from the exception
3303
+ * return magic LR value from the previous exception. The pseudocode
3304
+ * opencodes the stack-selection in PushCalleeStack(), but we prefer
3305
+ * to make this utility function generic enough to do the job.
3306
+ */
3307
+ bool want_psp = threadmode && spsel;
3308
+
3309
+ if (secure == env->v7m.secure) {
3310
+ if (want_psp == v7m_using_psp(env)) {
3311
+ return &env->regs[13];
3312
+ } else {
3313
+ return &env->v7m.other_sp;
3314
+ }
3315
+ } else {
3316
+ if (want_psp) {
3317
+ return &env->v7m.other_ss_psp;
3318
+ } else {
3319
+ return &env->v7m.other_ss_msp;
3320
+ }
3321
+ }
3322
+}
3323
+
3324
+static bool arm_v7m_load_vector(ARMCPU *cpu, int exc, bool targets_secure,
3325
+ uint32_t *pvec)
3326
+{
3327
+ CPUState *cs = CPU(cpu);
3328
+ CPUARMState *env = &cpu->env;
3329
+ MemTxResult result;
3330
+ uint32_t addr = env->v7m.vecbase[targets_secure] + exc * 4;
3331
+ uint32_t vector_entry;
3332
+ MemTxAttrs attrs = {};
3333
+ ARMMMUIdx mmu_idx;
3334
+ bool exc_secure;
3335
+
3336
+ mmu_idx = arm_v7m_mmu_idx_for_secstate_and_priv(env, targets_secure, true);
3337
+
3338
+ /*
3339
+ * We don't do a get_phys_addr() here because the rules for vector
3340
+ * loads are special: they always use the default memory map, and
3341
+ * the default memory map permits reads from all addresses.
3342
+ * Since there's no easy way to pass through to pmsav8_mpu_lookup()
3343
+ * that we want this special case which would always say "yes",
3344
+ * we just do the SAU lookup here followed by a direct physical load.
3345
+ */
3346
+ attrs.secure = targets_secure;
3347
+ attrs.user = false;
3348
+
3349
+ if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
3350
+ V8M_SAttributes sattrs = {};
3351
+
3352
+ v8m_security_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, &sattrs);
3353
+ if (sattrs.ns) {
3354
+ attrs.secure = false;
3355
+ } else if (!targets_secure) {
3356
+ /* NS access to S memory */
3357
+ goto load_fail;
3358
+ }
3359
+ }
3360
+
3361
+ vector_entry = address_space_ldl(arm_addressspace(cs, attrs), addr,
3362
+ attrs, &result);
3363
+ if (result != MEMTX_OK) {
3364
+ goto load_fail;
3365
+ }
3366
+ *pvec = vector_entry;
3367
+ return true;
3368
+
3369
+load_fail:
3370
+ /*
3371
+ * All vector table fetch fails are reported as HardFault, with
3372
+ * HFSR.VECTTBL and .FORCED set. (FORCED is set because
3373
+ * technically the underlying exception is a MemManage or BusFault
3374
+ * that is escalated to HardFault.) This is a terminal exception,
3375
+ * so we will either take the HardFault immediately or else enter
3376
+ * lockup (the latter case is handled in armv7m_nvic_set_pending_derived()).
3377
+ */
3378
+ exc_secure = targets_secure ||
3379
+ !(cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK);
3380
+ env->v7m.hfsr |= R_V7M_HFSR_VECTTBL_MASK | R_V7M_HFSR_FORCED_MASK;
3381
+ armv7m_nvic_set_pending_derived(env->nvic, ARMV7M_EXCP_HARD, exc_secure);
3382
+ return false;
3383
+}
3384
+
3385
+static uint32_t v7m_integrity_sig(CPUARMState *env, uint32_t lr)
3386
+{
3387
+ /*
3388
+ * Return the integrity signature value for the callee-saves
3389
+ * stack frame section. @lr is the exception return payload/LR value
3390
+ * whose FType bit forms bit 0 of the signature if FP is present.
3391
+ */
3392
+ uint32_t sig = 0xfefa125a;
3393
+
3394
+ if (!arm_feature(env, ARM_FEATURE_VFP) || (lr & R_V7M_EXCRET_FTYPE_MASK)) {
3395
+ sig |= 1;
3396
+ }
3397
+ return sig;
3398
+}
3399
+
3400
+static bool v7m_push_callee_stack(ARMCPU *cpu, uint32_t lr, bool dotailchain,
3401
+ bool ignore_faults)
3402
+{
3403
+ /*
3404
+ * For v8M, push the callee-saves register part of the stack frame.
3405
+ * Compare the v8M pseudocode PushCalleeStack().
3406
+ * In the tailchaining case this may not be the current stack.
3407
+ */
3408
+ CPUARMState *env = &cpu->env;
3409
+ uint32_t *frame_sp_p;
3410
+ uint32_t frameptr;
3411
+ ARMMMUIdx mmu_idx;
3412
+ bool stacked_ok;
3413
+ uint32_t limit;
3414
+ bool want_psp;
3415
+ uint32_t sig;
3416
+ StackingMode smode = ignore_faults ? STACK_IGNFAULTS : STACK_NORMAL;
3417
+
3418
+ if (dotailchain) {
3419
+ bool mode = lr & R_V7M_EXCRET_MODE_MASK;
3420
+ bool priv = !(env->v7m.control[M_REG_S] & R_V7M_CONTROL_NPRIV_MASK) ||
3421
+ !mode;
3422
+
3423
+ mmu_idx = arm_v7m_mmu_idx_for_secstate_and_priv(env, M_REG_S, priv);
3424
+ frame_sp_p = get_v7m_sp_ptr(env, M_REG_S, mode,
3425
+ lr & R_V7M_EXCRET_SPSEL_MASK);
3426
+ want_psp = mode && (lr & R_V7M_EXCRET_SPSEL_MASK);
3427
+ if (want_psp) {
3428
+ limit = env->v7m.psplim[M_REG_S];
3429
+ } else {
3430
+ limit = env->v7m.msplim[M_REG_S];
3431
+ }
3432
+ } else {
3433
+ mmu_idx = arm_mmu_idx(env);
3434
+ frame_sp_p = &env->regs[13];
3435
+ limit = v7m_sp_limit(env);
3436
+ }
3437
+
3438
+ frameptr = *frame_sp_p - 0x28;
3439
+ if (frameptr < limit) {
3440
+ /*
3441
+ * Stack limit failure: set SP to the limit value, and generate
3442
+ * STKOF UsageFault. Stack pushes below the limit must not be
3443
+ * performed. It is IMPDEF whether pushes above the limit are
3444
+ * performed; we choose not to.
3445
+ */
3446
+ qemu_log_mask(CPU_LOG_INT,
3447
+ "...STKOF during callee-saves register stacking\n");
3448
+ env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_STKOF_MASK;
3449
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
3450
+ env->v7m.secure);
3451
+ *frame_sp_p = limit;
3452
+ return true;
3453
+ }
3454
+
3455
+ /*
3456
+ * Write as much of the stack frame as we can. A write failure may
3457
+ * cause us to pend a derived exception.
3458
+ */
3459
+ sig = v7m_integrity_sig(env, lr);
3460
+ stacked_ok =
3461
+ v7m_stack_write(cpu, frameptr, sig, mmu_idx, smode) &&
3462
+ v7m_stack_write(cpu, frameptr + 0x8, env->regs[4], mmu_idx, smode) &&
3463
+ v7m_stack_write(cpu, frameptr + 0xc, env->regs[5], mmu_idx, smode) &&
3464
+ v7m_stack_write(cpu, frameptr + 0x10, env->regs[6], mmu_idx, smode) &&
3465
+ v7m_stack_write(cpu, frameptr + 0x14, env->regs[7], mmu_idx, smode) &&
3466
+ v7m_stack_write(cpu, frameptr + 0x18, env->regs[8], mmu_idx, smode) &&
3467
+ v7m_stack_write(cpu, frameptr + 0x1c, env->regs[9], mmu_idx, smode) &&
3468
+ v7m_stack_write(cpu, frameptr + 0x20, env->regs[10], mmu_idx, smode) &&
3469
+ v7m_stack_write(cpu, frameptr + 0x24, env->regs[11], mmu_idx, smode);
3470
+
3471
+ /* Update SP regardless of whether any of the stack accesses failed. */
3472
+ *frame_sp_p = frameptr;
3473
+
3474
+ return !stacked_ok;
3475
+}
3476
+
3477
+static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain,
3478
+ bool ignore_stackfaults)
3479
+{
3480
+ /*
3481
+ * Do the "take the exception" parts of exception entry,
3482
+ * but not the pushing of state to the stack. This is
3483
+ * similar to the pseudocode ExceptionTaken() function.
3484
+ */
3485
+ CPUARMState *env = &cpu->env;
3486
+ uint32_t addr;
3487
+ bool targets_secure;
3488
+ int exc;
3489
+ bool push_failed = false;
3490
+
3491
+ armv7m_nvic_get_pending_irq_info(env->nvic, &exc, &targets_secure);
3492
+ qemu_log_mask(CPU_LOG_INT, "...taking pending %s exception %d\n",
3493
+ targets_secure ? "secure" : "nonsecure", exc);
3494
+
3495
+ if (dotailchain) {
3496
+ /* Sanitize LR FType and PREFIX bits */
3497
+ if (!arm_feature(env, ARM_FEATURE_VFP)) {
3498
+ lr |= R_V7M_EXCRET_FTYPE_MASK;
3499
+ }
3500
+ lr = deposit32(lr, 24, 8, 0xff);
3501
+ }
3502
+
3503
+ if (arm_feature(env, ARM_FEATURE_V8)) {
3504
+ if (arm_feature(env, ARM_FEATURE_M_SECURITY) &&
3505
+ (lr & R_V7M_EXCRET_S_MASK)) {
3506
+ /*
3507
+ * The background code (the owner of the registers in the
3508
+ * exception frame) is Secure. This means it may either already
3509
+ * have or now needs to push callee-saves registers.
3510
+ */
3511
+ if (targets_secure) {
3512
+ if (dotailchain && !(lr & R_V7M_EXCRET_ES_MASK)) {
3513
+ /*
3514
+ * We took an exception from Secure to NonSecure
3515
+ * (which means the callee-saved registers got stacked)
3516
+ * and are now tailchaining to a Secure exception.
3517
+ * Clear DCRS so eventual return from this Secure
3518
+ * exception unstacks the callee-saved registers.
3519
+ */
3520
+ lr &= ~R_V7M_EXCRET_DCRS_MASK;
3521
+ }
3522
+ } else {
3523
+ /*
3524
+ * We're going to a non-secure exception; push the
3525
+ * callee-saves registers to the stack now, if they're
3526
+ * not already saved.
3527
+ */
3528
+ if (lr & R_V7M_EXCRET_DCRS_MASK &&
3529
+ !(dotailchain && !(lr & R_V7M_EXCRET_ES_MASK))) {
3530
+ push_failed = v7m_push_callee_stack(cpu, lr, dotailchain,
3531
+ ignore_stackfaults);
3532
+ }
3533
+ lr |= R_V7M_EXCRET_DCRS_MASK;
3534
+ }
3535
+ }
3536
+
3537
+ lr &= ~R_V7M_EXCRET_ES_MASK;
3538
+ if (targets_secure || !arm_feature(env, ARM_FEATURE_M_SECURITY)) {
3539
+ lr |= R_V7M_EXCRET_ES_MASK;
3540
+ }
3541
+ lr &= ~R_V7M_EXCRET_SPSEL_MASK;
3542
+ if (env->v7m.control[targets_secure] & R_V7M_CONTROL_SPSEL_MASK) {
3543
+ lr |= R_V7M_EXCRET_SPSEL_MASK;
3544
+ }
3545
+
3546
+ /*
3547
+ * Clear registers if necessary to prevent non-secure exception
3548
+ * code being able to see register values from secure code.
3549
+ * Where register values become architecturally UNKNOWN we leave
3550
+ * them with their previous values.
3551
+ */
3552
+ if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
3553
+ if (!targets_secure) {
3554
+ /*
3555
+ * Always clear the caller-saved registers (they have been
3556
+ * pushed to the stack earlier in v7m_push_stack()).
3557
+ * Clear callee-saved registers if the background code is
3558
+ * Secure (in which case these regs were saved in
3559
+ * v7m_push_callee_stack()).
3560
+ */
3561
+ int i;
3562
+
3563
+ for (i = 0; i < 13; i++) {
3564
+ /* r4..r11 are callee-saves, zero only if EXCRET.S == 1 */
3565
+ if (i < 4 || i > 11 || (lr & R_V7M_EXCRET_S_MASK)) {
3566
+ env->regs[i] = 0;
3567
+ }
3568
+ }
3569
+ /* Clear EAPSR */
3570
+ xpsr_write(env, 0, XPSR_NZCV | XPSR_Q | XPSR_GE | XPSR_IT);
3571
+ }
3572
+ }
3573
+ }
3574
+
3575
+ if (push_failed && !ignore_stackfaults) {
3576
+ /*
3577
+ * Derived exception on callee-saves register stacking:
3578
+ * we might now want to take a different exception which
3579
+ * targets a different security state, so try again from the top.
3580
+ */
3581
+ qemu_log_mask(CPU_LOG_INT,
3582
+ "...derived exception on callee-saves register stacking");
3583
+ v7m_exception_taken(cpu, lr, true, true);
3584
+ return;
3585
+ }
3586
+
3587
+ if (!arm_v7m_load_vector(cpu, exc, targets_secure, &addr)) {
3588
+ /* Vector load failed: derived exception */
3589
+ qemu_log_mask(CPU_LOG_INT, "...derived exception on vector table load");
3590
+ v7m_exception_taken(cpu, lr, true, true);
3591
+ return;
3592
+ }
3593
+
3594
+ /*
3595
+ * Now we've done everything that might cause a derived exception
3596
+ * we can go ahead and activate whichever exception we're going to
3597
+ * take (which might now be the derived exception).
3598
+ */
3599
+ armv7m_nvic_acknowledge_irq(env->nvic);
3600
+
3601
+ /* Switch to target security state -- must do this before writing SPSEL */
3602
+ switch_v7m_security_state(env, targets_secure);
3603
+ write_v7m_control_spsel(env, 0);
3604
+ arm_clear_exclusive(env);
3605
+ /* Clear SFPA and FPCA (has no effect if no FPU) */
3606
+ env->v7m.control[M_REG_S] &=
3607
+ ~(R_V7M_CONTROL_FPCA_MASK | R_V7M_CONTROL_SFPA_MASK);
3608
+ /* Clear IT bits */
3609
+ env->condexec_bits = 0;
3610
+ env->regs[14] = lr;
3611
+ env->regs[15] = addr & 0xfffffffe;
3612
+ env->thumb = addr & 1;
3613
+}
3614
+
3615
+static void v7m_update_fpccr(CPUARMState *env, uint32_t frameptr,
3616
+ bool apply_splim)
3617
+{
3618
+ /*
3619
+ * Like the pseudocode UpdateFPCCR: save state in FPCAR and FPCCR
3620
+ * that we will need later in order to do lazy FP reg stacking.
3621
+ */
3622
+ bool is_secure = env->v7m.secure;
3623
+ void *nvic = env->nvic;
3624
+ /*
3625
+ * Some bits are unbanked and live always in fpccr[M_REG_S]; some bits
3626
+ * are banked and we want to update the bit in the bank for the
3627
+ * current security state; and in one case we want to specifically
3628
+ * update the NS banked version of a bit even if we are secure.
3629
+ */
3630
+ uint32_t *fpccr_s = &env->v7m.fpccr[M_REG_S];
3631
+ uint32_t *fpccr_ns = &env->v7m.fpccr[M_REG_NS];
3632
+ uint32_t *fpccr = &env->v7m.fpccr[is_secure];
3633
+ bool hfrdy, bfrdy, mmrdy, ns_ufrdy, s_ufrdy, sfrdy, monrdy;
3634
+
3635
+ env->v7m.fpcar[is_secure] = frameptr & ~0x7;
3636
+
3637
+ if (apply_splim && arm_feature(env, ARM_FEATURE_V8)) {
3638
+ bool splimviol;
3639
+ uint32_t splim = v7m_sp_limit(env);
3640
+ bool ign = armv7m_nvic_neg_prio_requested(nvic, is_secure) &&
3641
+ (env->v7m.ccr[is_secure] & R_V7M_CCR_STKOFHFNMIGN_MASK);
3642
+
3643
+ splimviol = !ign && frameptr < splim;
3644
+ *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, SPLIMVIOL, splimviol);
3645
+ }
3646
+
3647
+ *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, LSPACT, 1);
3648
+
3649
+ *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, S, is_secure);
3650
+
3651
+ *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, USER, arm_current_el(env) == 0);
3652
+
3653
+ *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, THREAD,
3654
+ !arm_v7m_is_handler_mode(env));
3655
+
3656
+ hfrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_HARD, false);
3657
+ *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, HFRDY, hfrdy);
3658
+
3659
+ bfrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_BUS, false);
3660
+ *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, BFRDY, bfrdy);
3661
+
3662
+ mmrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_MEM, is_secure);
3663
+ *fpccr = FIELD_DP32(*fpccr, V7M_FPCCR, MMRDY, mmrdy);
3664
+
3665
+ ns_ufrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_USAGE, false);
3666
+ *fpccr_ns = FIELD_DP32(*fpccr_ns, V7M_FPCCR, UFRDY, ns_ufrdy);
3667
+
3668
+ monrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_DEBUG, false);
3669
+ *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, MONRDY, monrdy);
3670
+
3671
+ if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
3672
+ s_ufrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_USAGE, true);
3673
+ *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, UFRDY, s_ufrdy);
3674
+
3675
+ sfrdy = armv7m_nvic_get_ready_status(nvic, ARMV7M_EXCP_SECURE, false);
3676
+ *fpccr_s = FIELD_DP32(*fpccr_s, V7M_FPCCR, SFRDY, sfrdy);
3677
+ }
3678
+}
3679
+
3680
+void HELPER(v7m_vlstm)(CPUARMState *env, uint32_t fptr)
3681
+{
3682
+ /* fptr is the value of Rn, the frame pointer we store the FP regs to */
3683
+ bool s = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK;
3684
+ bool lspact = env->v7m.fpccr[s] & R_V7M_FPCCR_LSPACT_MASK;
3685
+
3686
+ assert(env->v7m.secure);
3687
+
3688
+ if (!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK)) {
3689
+ return;
3690
+ }
3691
+
3692
+ /* Check access to the coprocessor is permitted */
3693
+ if (!v7m_cpacr_pass(env, true, arm_current_el(env) != 0)) {
3694
+ raise_exception_ra(env, EXCP_NOCP, 0, 1, GETPC());
3695
+ }
3696
+
3697
+ if (lspact) {
3698
+ /* LSPACT should not be active when there is active FP state */
3699
+ raise_exception_ra(env, EXCP_LSERR, 0, 1, GETPC());
3700
+ }
3701
+
3702
+ if (fptr & 7) {
3703
+ raise_exception_ra(env, EXCP_UNALIGNED, 0, 1, GETPC());
3704
+ }
3705
+
3706
+ /*
3707
+ * Note that we do not use v7m_stack_write() here, because the
3708
+ * accesses should not set the FSR bits for stacking errors if they
3709
+ * fail. (In pseudocode terms, they are AccType_NORMAL, not AccType_STACK
3710
+ * or AccType_LAZYFP). Faults in cpu_stl_data() will throw exceptions
3711
+ * and longjmp out.
3712
+ */
3713
+ if (!(env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPEN_MASK)) {
3714
+ bool ts = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK;
3715
+ int i;
3716
+
3717
+ for (i = 0; i < (ts ? 32 : 16); i += 2) {
3718
+ uint64_t dn = *aa32_vfp_dreg(env, i / 2);
3719
+ uint32_t faddr = fptr + 4 * i;
3720
+ uint32_t slo = extract64(dn, 0, 32);
3721
+ uint32_t shi = extract64(dn, 32, 32);
3722
+
3723
+ if (i >= 16) {
3724
+ faddr += 8; /* skip the slot for the FPSCR */
3725
+ }
3726
+ cpu_stl_data(env, faddr, slo);
3727
+ cpu_stl_data(env, faddr + 4, shi);
3728
+ }
3729
+ cpu_stl_data(env, fptr + 0x40, vfp_get_fpscr(env));
3730
+
3731
+ /*
3732
+ * If TS is 0 then s0 to s15 and FPSCR are UNKNOWN; we choose to
3733
+ * leave them unchanged, matching our choice in v7m_preserve_fp_state.
3734
+ */
3735
+ if (ts) {
3736
+ for (i = 0; i < 32; i += 2) {
3737
+ *aa32_vfp_dreg(env, i / 2) = 0;
3738
+ }
3739
+ vfp_set_fpscr(env, 0);
3740
+ }
3741
+ } else {
3742
+ v7m_update_fpccr(env, fptr, false);
3743
+ }
3744
+
3745
+ env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_FPCA_MASK;
3746
+}
3747
+
3748
+void HELPER(v7m_vlldm)(CPUARMState *env, uint32_t fptr)
3749
+{
3750
+ /* fptr is the value of Rn, the frame pointer we load the FP regs from */
3751
+ assert(env->v7m.secure);
3752
+
3753
+ if (!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK)) {
3754
+ return;
3755
+ }
3756
+
3757
+ /* Check access to the coprocessor is permitted */
3758
+ if (!v7m_cpacr_pass(env, true, arm_current_el(env) != 0)) {
3759
+ raise_exception_ra(env, EXCP_NOCP, 0, 1, GETPC());
3760
+ }
3761
+
3762
+ if (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPACT_MASK) {
3763
+ /* State in FP is still valid */
3764
+ env->v7m.fpccr[M_REG_S] &= ~R_V7M_FPCCR_LSPACT_MASK;
3765
+ } else {
3766
+ bool ts = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK;
3767
+ int i;
3768
+ uint32_t fpscr;
3769
+
3770
+ if (fptr & 7) {
3771
+ raise_exception_ra(env, EXCP_UNALIGNED, 0, 1, GETPC());
3772
+ }
3773
+
3774
+ for (i = 0; i < (ts ? 32 : 16); i += 2) {
3775
+ uint32_t slo, shi;
3776
+ uint64_t dn;
3777
+ uint32_t faddr = fptr + 4 * i;
3778
+
3779
+ if (i >= 16) {
3780
+ faddr += 8; /* skip the slot for the FPSCR */
3781
+ }
3782
+
3783
+ slo = cpu_ldl_data(env, faddr);
3784
+ shi = cpu_ldl_data(env, faddr + 4);
3785
+
3786
+ dn = (uint64_t) shi << 32 | slo;
3787
+ *aa32_vfp_dreg(env, i / 2) = dn;
3788
+ }
3789
+ fpscr = cpu_ldl_data(env, fptr + 0x40);
3790
+ vfp_set_fpscr(env, fpscr);
3791
+ }
3792
+
3793
+ env->v7m.control[M_REG_S] |= R_V7M_CONTROL_FPCA_MASK;
3794
+}
3795
+
3796
+static bool v7m_push_stack(ARMCPU *cpu)
3797
+{
3798
+ /*
3799
+ * Do the "set up stack frame" part of exception entry,
3800
+ * similar to pseudocode PushStack().
3801
+ * Return true if we generate a derived exception (and so
3802
+ * should ignore further stack faults trying to process
3803
+ * that derived exception.)
3804
+ */
3805
+ bool stacked_ok = true, limitviol = false;
3806
+ CPUARMState *env = &cpu->env;
3807
+ uint32_t xpsr = xpsr_read(env);
3808
+ uint32_t frameptr = env->regs[13];
3809
+ ARMMMUIdx mmu_idx = arm_mmu_idx(env);
3810
+ uint32_t framesize;
3811
+ bool nsacr_cp10 = extract32(env->v7m.nsacr, 10, 1);
3812
+
3813
+ if ((env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK) &&
3814
+ (env->v7m.secure || nsacr_cp10)) {
3815
+ if (env->v7m.secure &&
3816
+ env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK) {
3817
+ framesize = 0xa8;
3818
+ } else {
3819
+ framesize = 0x68;
3820
+ }
3821
+ } else {
3822
+ framesize = 0x20;
3823
+ }
3824
+
3825
+ /* Align stack pointer if the guest wants that */
3826
+ if ((frameptr & 4) &&
3827
+ (env->v7m.ccr[env->v7m.secure] & R_V7M_CCR_STKALIGN_MASK)) {
3828
+ frameptr -= 4;
3829
+ xpsr |= XPSR_SPREALIGN;
3830
+ }
3831
+
3832
+ xpsr &= ~XPSR_SFPA;
3833
+ if (env->v7m.secure &&
3834
+ (env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK)) {
3835
+ xpsr |= XPSR_SFPA;
3836
+ }
3837
+
3838
+ frameptr -= framesize;
3839
+
3840
+ if (arm_feature(env, ARM_FEATURE_V8)) {
3841
+ uint32_t limit = v7m_sp_limit(env);
3842
+
3843
+ if (frameptr < limit) {
3844
+ /*
3845
+ * Stack limit failure: set SP to the limit value, and generate
3846
+ * STKOF UsageFault. Stack pushes below the limit must not be
3847
+ * performed. It is IMPDEF whether pushes above the limit are
3848
+ * performed; we choose not to.
3849
+ */
3850
+ qemu_log_mask(CPU_LOG_INT,
3851
+ "...STKOF during stacking\n");
3852
+ env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_STKOF_MASK;
3853
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
3854
+ env->v7m.secure);
3855
+ env->regs[13] = limit;
3856
+ /*
3857
+ * We won't try to perform any further memory accesses but
3858
+ * we must continue through the following code to check for
3859
+ * permission faults during FPU state preservation, and we
3860
+ * must update FPCCR if lazy stacking is enabled.
3861
+ */
3862
+ limitviol = true;
3863
+ stacked_ok = false;
3864
+ }
3865
+ }
3866
+
3867
+ /*
3868
+ * Write as much of the stack frame as we can. If we fail a stack
3869
+ * write this will result in a derived exception being pended
3870
+ * (which may be taken in preference to the one we started with
3871
+ * if it has higher priority).
3872
+ */
3873
+ stacked_ok = stacked_ok &&
3874
+ v7m_stack_write(cpu, frameptr, env->regs[0], mmu_idx, STACK_NORMAL) &&
3875
+ v7m_stack_write(cpu, frameptr + 4, env->regs[1],
3876
+ mmu_idx, STACK_NORMAL) &&
3877
+ v7m_stack_write(cpu, frameptr + 8, env->regs[2],
3878
+ mmu_idx, STACK_NORMAL) &&
3879
+ v7m_stack_write(cpu, frameptr + 12, env->regs[3],
3880
+ mmu_idx, STACK_NORMAL) &&
3881
+ v7m_stack_write(cpu, frameptr + 16, env->regs[12],
3882
+ mmu_idx, STACK_NORMAL) &&
3883
+ v7m_stack_write(cpu, frameptr + 20, env->regs[14],
3884
+ mmu_idx, STACK_NORMAL) &&
3885
+ v7m_stack_write(cpu, frameptr + 24, env->regs[15],
3886
+ mmu_idx, STACK_NORMAL) &&
3887
+ v7m_stack_write(cpu, frameptr + 28, xpsr, mmu_idx, STACK_NORMAL);
3888
+
3889
+ if (env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK) {
3890
+ /* FPU is active, try to save its registers */
3891
+ bool fpccr_s = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK;
3892
+ bool lspact = env->v7m.fpccr[fpccr_s] & R_V7M_FPCCR_LSPACT_MASK;
3893
+
3894
+ if (lspact && arm_feature(env, ARM_FEATURE_M_SECURITY)) {
3895
+ qemu_log_mask(CPU_LOG_INT,
3896
+ "...SecureFault because LSPACT and FPCA both set\n");
3897
+ env->v7m.sfsr |= R_V7M_SFSR_LSERR_MASK;
3898
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
3899
+ } else if (!env->v7m.secure && !nsacr_cp10) {
3900
+ qemu_log_mask(CPU_LOG_INT,
3901
+ "...Secure UsageFault with CFSR.NOCP because "
3902
+ "NSACR.CP10 prevents stacking FP regs\n");
3903
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, M_REG_S);
3904
+ env->v7m.cfsr[M_REG_S] |= R_V7M_CFSR_NOCP_MASK;
3905
+ } else {
3906
+ if (!(env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPEN_MASK)) {
3907
+ /* Lazy stacking disabled, save registers now */
3908
+ int i;
3909
+ bool cpacr_pass = v7m_cpacr_pass(env, env->v7m.secure,
3910
+ arm_current_el(env) != 0);
3911
+
3912
+ if (stacked_ok && !cpacr_pass) {
3913
+ /*
3914
+ * Take UsageFault if CPACR forbids access. The pseudocode
3915
+ * here does a full CheckCPEnabled() but we know the NSACR
3916
+ * check can never fail as we have already handled that.
3917
+ */
3918
+ qemu_log_mask(CPU_LOG_INT,
3919
+ "...UsageFault with CFSR.NOCP because "
3920
+ "CPACR.CP10 prevents stacking FP regs\n");
3921
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
3922
+ env->v7m.secure);
3923
+ env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_NOCP_MASK;
3924
+ stacked_ok = false;
3925
+ }
3926
+
3927
+ for (i = 0; i < ((framesize == 0xa8) ? 32 : 16); i += 2) {
3928
+ uint64_t dn = *aa32_vfp_dreg(env, i / 2);
3929
+ uint32_t faddr = frameptr + 0x20 + 4 * i;
3930
+ uint32_t slo = extract64(dn, 0, 32);
3931
+ uint32_t shi = extract64(dn, 32, 32);
3932
+
3933
+ if (i >= 16) {
3934
+ faddr += 8; /* skip the slot for the FPSCR */
3935
+ }
3936
+ stacked_ok = stacked_ok &&
3937
+ v7m_stack_write(cpu, faddr, slo,
3938
+ mmu_idx, STACK_NORMAL) &&
3939
+ v7m_stack_write(cpu, faddr + 4, shi,
3940
+ mmu_idx, STACK_NORMAL);
3941
+ }
3942
+ stacked_ok = stacked_ok &&
3943
+ v7m_stack_write(cpu, frameptr + 0x60,
3944
+ vfp_get_fpscr(env), mmu_idx, STACK_NORMAL);
3945
+ if (cpacr_pass) {
3946
+ for (i = 0; i < ((framesize == 0xa8) ? 32 : 16); i += 2) {
3947
+ *aa32_vfp_dreg(env, i / 2) = 0;
3948
+ }
3949
+ vfp_set_fpscr(env, 0);
3950
+ }
3951
+ } else {
3952
+ /* Lazy stacking enabled, save necessary info to stack later */
3953
+ v7m_update_fpccr(env, frameptr + 0x20, true);
3954
+ }
3955
+ }
3956
+ }
3957
+
3958
+ /*
3959
+ * If we broke a stack limit then SP was already updated earlier;
3960
+ * otherwise we update SP regardless of whether any of the stack
3961
+ * accesses failed or we took some other kind of fault.
3962
+ */
3963
+ if (!limitviol) {
3964
+ env->regs[13] = frameptr;
3965
+ }
3966
+
3967
+ return !stacked_ok;
3968
+}
3969
+
3970
+static void do_v7m_exception_exit(ARMCPU *cpu)
3971
+{
3972
+ CPUARMState *env = &cpu->env;
3973
+ uint32_t excret;
3974
+ uint32_t xpsr, xpsr_mask;
3975
+ bool ufault = false;
3976
+ bool sfault = false;
3977
+ bool return_to_sp_process;
3978
+ bool return_to_handler;
3979
+ bool rettobase = false;
3980
+ bool exc_secure = false;
3981
+ bool return_to_secure;
3982
+ bool ftype;
3983
+ bool restore_s16_s31;
3984
+
3985
+ /*
3986
+ * If we're not in Handler mode then jumps to magic exception-exit
3987
+ * addresses don't have magic behaviour. However for the v8M
3988
+ * security extensions the magic secure-function-return has to
3989
+ * work in thread mode too, so to avoid doing an extra check in
3990
+ * the generated code we allow exception-exit magic to also cause the
3991
+ * internal exception and bring us here in thread mode. Correct code
3992
+ * will never try to do this (the following insn fetch will always
3993
+ * fault) so we the overhead of having taken an unnecessary exception
3994
+ * doesn't matter.
3995
+ */
3996
+ if (!arm_v7m_is_handler_mode(env)) {
3997
+ return;
3998
+ }
3999
+
4000
+ /*
4001
+ * In the spec pseudocode ExceptionReturn() is called directly
4002
+ * from BXWritePC() and gets the full target PC value including
4003
+ * bit zero. In QEMU's implementation we treat it as a normal
4004
+ * jump-to-register (which is then caught later on), and so split
4005
+ * the target value up between env->regs[15] and env->thumb in
4006
+ * gen_bx(). Reconstitute it.
4007
+ */
4008
+ excret = env->regs[15];
4009
+ if (env->thumb) {
4010
+ excret |= 1;
4011
+ }
4012
+
4013
+ qemu_log_mask(CPU_LOG_INT, "Exception return: magic PC %" PRIx32
4014
+ " previous exception %d\n",
4015
+ excret, env->v7m.exception);
4016
+
4017
+ if ((excret & R_V7M_EXCRET_RES1_MASK) != R_V7M_EXCRET_RES1_MASK) {
4018
+ qemu_log_mask(LOG_GUEST_ERROR, "M profile: zero high bits in exception "
4019
+ "exit PC value 0x%" PRIx32 " are UNPREDICTABLE\n",
4020
+ excret);
4021
+ }
4022
+
4023
+ ftype = excret & R_V7M_EXCRET_FTYPE_MASK;
4024
+
4025
+ if (!arm_feature(env, ARM_FEATURE_VFP) && !ftype) {
4026
+ qemu_log_mask(LOG_GUEST_ERROR, "M profile: zero FTYPE in exception "
4027
+ "exit PC value 0x%" PRIx32 " is UNPREDICTABLE "
4028
+ "if FPU not present\n",
4029
+ excret);
4030
+ ftype = true;
4031
+ }
4032
+
4033
+ if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
4034
+ /*
4035
+ * EXC_RETURN.ES validation check (R_SMFL). We must do this before
4036
+ * we pick which FAULTMASK to clear.
4037
+ */
4038
+ if (!env->v7m.secure &&
4039
+ ((excret & R_V7M_EXCRET_ES_MASK) ||
4040
+ !(excret & R_V7M_EXCRET_DCRS_MASK))) {
4041
+ sfault = 1;
4042
+ /* For all other purposes, treat ES as 0 (R_HXSR) */
4043
+ excret &= ~R_V7M_EXCRET_ES_MASK;
4044
+ }
4045
+ exc_secure = excret & R_V7M_EXCRET_ES_MASK;
4046
+ }
4047
+
4048
+ if (env->v7m.exception != ARMV7M_EXCP_NMI) {
4049
+ /*
4050
+ * Auto-clear FAULTMASK on return from other than NMI.
4051
+ * If the security extension is implemented then this only
4052
+ * happens if the raw execution priority is >= 0; the
4053
+ * value of the ES bit in the exception return value indicates
4054
+ * which security state's faultmask to clear. (v8M ARM ARM R_KBNF.)
4055
+ */
4056
+ if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
4057
+ if (armv7m_nvic_raw_execution_priority(env->nvic) >= 0) {
4058
+ env->v7m.faultmask[exc_secure] = 0;
4059
+ }
4060
+ } else {
4061
+ env->v7m.faultmask[M_REG_NS] = 0;
4062
+ }
4063
+ }
4064
+
4065
+ switch (armv7m_nvic_complete_irq(env->nvic, env->v7m.exception,
4066
+ exc_secure)) {
4067
+ case -1:
4068
+ /* attempt to exit an exception that isn't active */
4069
+ ufault = true;
4070
+ break;
4071
+ case 0:
4072
+ /* still an irq active now */
4073
+ break;
4074
+ case 1:
4075
+ /*
4076
+ * We returned to base exception level, no nesting.
4077
+ * (In the pseudocode this is written using "NestedActivation != 1"
4078
+ * where we have 'rettobase == false'.)
4079
+ */
4080
+ rettobase = true;
4081
+ break;
4082
+ default:
4083
+ g_assert_not_reached();
4084
+ }
4085
+
4086
+ return_to_handler = !(excret & R_V7M_EXCRET_MODE_MASK);
4087
+ return_to_sp_process = excret & R_V7M_EXCRET_SPSEL_MASK;
4088
+ return_to_secure = arm_feature(env, ARM_FEATURE_M_SECURITY) &&
4089
+ (excret & R_V7M_EXCRET_S_MASK);
4090
+
4091
+ if (arm_feature(env, ARM_FEATURE_V8)) {
4092
+ if (!arm_feature(env, ARM_FEATURE_M_SECURITY)) {
4093
+ /*
4094
+ * UNPREDICTABLE if S == 1 or DCRS == 0 or ES == 1 (R_XLCP);
4095
+ * we choose to take the UsageFault.
4096
+ */
4097
+ if ((excret & R_V7M_EXCRET_S_MASK) ||
4098
+ (excret & R_V7M_EXCRET_ES_MASK) ||
4099
+ !(excret & R_V7M_EXCRET_DCRS_MASK)) {
4100
+ ufault = true;
4101
+ }
4102
+ }
4103
+ if (excret & R_V7M_EXCRET_RES0_MASK) {
4104
+ ufault = true;
4105
+ }
4106
+ } else {
4107
+ /* For v7M we only recognize certain combinations of the low bits */
4108
+ switch (excret & 0xf) {
4109
+ case 1: /* Return to Handler */
4110
+ break;
4111
+ case 13: /* Return to Thread using Process stack */
4112
+ case 9: /* Return to Thread using Main stack */
4113
+ /*
4114
+ * We only need to check NONBASETHRDENA for v7M, because in
4115
+ * v8M this bit does not exist (it is RES1).
4116
+ */
4117
+ if (!rettobase &&
4118
+ !(env->v7m.ccr[env->v7m.secure] &
4119
+ R_V7M_CCR_NONBASETHRDENA_MASK)) {
4120
+ ufault = true;
4121
+ }
4122
+ break;
4123
+ default:
4124
+ ufault = true;
4125
+ }
4126
+ }
4127
+
4128
+ /*
4129
+ * Set CONTROL.SPSEL from excret.SPSEL. Since we're still in
4130
+ * Handler mode (and will be until we write the new XPSR.Interrupt
4131
+ * field) this does not switch around the current stack pointer.
4132
+ * We must do this before we do any kind of tailchaining, including
4133
+ * for the derived exceptions on integrity check failures, or we will
4134
+ * give the guest an incorrect EXCRET.SPSEL value on exception entry.
4135
+ */
4136
+ write_v7m_control_spsel_for_secstate(env, return_to_sp_process, exc_secure);
4137
+
4138
+ /*
4139
+ * Clear scratch FP values left in caller saved registers; this
4140
+ * must happen before any kind of tail chaining.
4141
+ */
4142
+ if ((env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_CLRONRET_MASK) &&
4143
+ (env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK)) {
4144
+ if (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPACT_MASK) {
4145
+ env->v7m.sfsr |= R_V7M_SFSR_LSERR_MASK;
4146
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
4147
+ qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on existing "
4148
+ "stackframe: error during lazy state deactivation\n");
4149
+ v7m_exception_taken(cpu, excret, true, false);
4150
+ return;
4151
+ } else {
4152
+ /* Clear s0..s15 and FPSCR */
4153
+ int i;
4154
+
4155
+ for (i = 0; i < 16; i += 2) {
4156
+ *aa32_vfp_dreg(env, i / 2) = 0;
4157
+ }
4158
+ vfp_set_fpscr(env, 0);
4159
+ }
4160
+ }
4161
+
4162
+ if (sfault) {
4163
+ env->v7m.sfsr |= R_V7M_SFSR_INVER_MASK;
4164
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
4165
+ qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on existing "
4166
+ "stackframe: failed EXC_RETURN.ES validity check\n");
4167
+ v7m_exception_taken(cpu, excret, true, false);
4168
+ return;
4169
+ }
4170
+
4171
+ if (ufault) {
4172
+ /*
4173
+ * Bad exception return: instead of popping the exception
4174
+ * stack, directly take a usage fault on the current stack.
4175
+ */
4176
+ env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
4177
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
4178
+ qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on existing "
4179
+ "stackframe: failed exception return integrity check\n");
4180
+ v7m_exception_taken(cpu, excret, true, false);
4181
+ return;
4182
+ }
4183
+
4184
+ /*
4185
+ * Tailchaining: if there is currently a pending exception that
4186
+ * is high enough priority to preempt execution at the level we're
4187
+ * about to return to, then just directly take that exception now,
4188
+ * avoiding an unstack-and-then-stack. Note that now we have
4189
+ * deactivated the previous exception by calling armv7m_nvic_complete_irq()
4190
+ * our current execution priority is already the execution priority we are
4191
+ * returning to -- none of the state we would unstack or set based on
4192
+ * the EXCRET value affects it.
4193
+ */
4194
+ if (armv7m_nvic_can_take_pending_exception(env->nvic)) {
4195
+ qemu_log_mask(CPU_LOG_INT, "...tailchaining to pending exception\n");
4196
+ v7m_exception_taken(cpu, excret, true, false);
4197
+ return;
4198
+ }
4199
+
4200
+ switch_v7m_security_state(env, return_to_secure);
4201
+
4202
+ {
4203
+ /*
4204
+ * The stack pointer we should be reading the exception frame from
4205
+ * depends on bits in the magic exception return type value (and
4206
+ * for v8M isn't necessarily the stack pointer we will eventually
4207
+ * end up resuming execution with). Get a pointer to the location
4208
+ * in the CPU state struct where the SP we need is currently being
4209
+ * stored; we will use and modify it in place.
4210
+ * We use this limited C variable scope so we don't accidentally
4211
+ * use 'frame_sp_p' after we do something that makes it invalid.
4212
+ */
4213
+ uint32_t *frame_sp_p = get_v7m_sp_ptr(env,
4214
+ return_to_secure,
4215
+ !return_to_handler,
4216
+ return_to_sp_process);
4217
+ uint32_t frameptr = *frame_sp_p;
4218
+ bool pop_ok = true;
4219
+ ARMMMUIdx mmu_idx;
4220
+ bool return_to_priv = return_to_handler ||
4221
+ !(env->v7m.control[return_to_secure] & R_V7M_CONTROL_NPRIV_MASK);
4222
+
4223
+ mmu_idx = arm_v7m_mmu_idx_for_secstate_and_priv(env, return_to_secure,
4224
+ return_to_priv);
4225
+
4226
+ if (!QEMU_IS_ALIGNED(frameptr, 8) &&
4227
+ arm_feature(env, ARM_FEATURE_V8)) {
4228
+ qemu_log_mask(LOG_GUEST_ERROR,
4229
+ "M profile exception return with non-8-aligned SP "
4230
+ "for destination state is UNPREDICTABLE\n");
4231
+ }
4232
+
4233
+ /* Do we need to pop callee-saved registers? */
4234
+ if (return_to_secure &&
4235
+ ((excret & R_V7M_EXCRET_ES_MASK) == 0 ||
4236
+ (excret & R_V7M_EXCRET_DCRS_MASK) == 0)) {
4237
+ uint32_t actual_sig;
4238
+
4239
+ pop_ok = v7m_stack_read(cpu, &actual_sig, frameptr, mmu_idx);
4240
+
4241
+ if (pop_ok && v7m_integrity_sig(env, excret) != actual_sig) {
4242
+ /* Take a SecureFault on the current stack */
4243
+ env->v7m.sfsr |= R_V7M_SFSR_INVIS_MASK;
4244
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
4245
+ qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on existing "
4246
+ "stackframe: failed exception return integrity "
4247
+ "signature check\n");
4248
+ v7m_exception_taken(cpu, excret, true, false);
4249
+ return;
4250
+ }
4251
+
4252
+ pop_ok = pop_ok &&
4253
+ v7m_stack_read(cpu, &env->regs[4], frameptr + 0x8, mmu_idx) &&
4254
+ v7m_stack_read(cpu, &env->regs[5], frameptr + 0xc, mmu_idx) &&
4255
+ v7m_stack_read(cpu, &env->regs[6], frameptr + 0x10, mmu_idx) &&
4256
+ v7m_stack_read(cpu, &env->regs[7], frameptr + 0x14, mmu_idx) &&
4257
+ v7m_stack_read(cpu, &env->regs[8], frameptr + 0x18, mmu_idx) &&
4258
+ v7m_stack_read(cpu, &env->regs[9], frameptr + 0x1c, mmu_idx) &&
4259
+ v7m_stack_read(cpu, &env->regs[10], frameptr + 0x20, mmu_idx) &&
4260
+ v7m_stack_read(cpu, &env->regs[11], frameptr + 0x24, mmu_idx);
4261
+
4262
+ frameptr += 0x28;
4263
+ }
4264
+
4265
+ /* Pop registers */
4266
+ pop_ok = pop_ok &&
4267
+ v7m_stack_read(cpu, &env->regs[0], frameptr, mmu_idx) &&
4268
+ v7m_stack_read(cpu, &env->regs[1], frameptr + 0x4, mmu_idx) &&
4269
+ v7m_stack_read(cpu, &env->regs[2], frameptr + 0x8, mmu_idx) &&
4270
+ v7m_stack_read(cpu, &env->regs[3], frameptr + 0xc, mmu_idx) &&
4271
+ v7m_stack_read(cpu, &env->regs[12], frameptr + 0x10, mmu_idx) &&
4272
+ v7m_stack_read(cpu, &env->regs[14], frameptr + 0x14, mmu_idx) &&
4273
+ v7m_stack_read(cpu, &env->regs[15], frameptr + 0x18, mmu_idx) &&
4274
+ v7m_stack_read(cpu, &xpsr, frameptr + 0x1c, mmu_idx);
4275
+
4276
+ if (!pop_ok) {
4277
+ /*
4278
+ * v7m_stack_read() pended a fault, so take it (as a tail
4279
+ * chained exception on the same stack frame)
4280
+ */
4281
+ qemu_log_mask(CPU_LOG_INT, "...derived exception on unstacking\n");
4282
+ v7m_exception_taken(cpu, excret, true, false);
4283
+ return;
4284
+ }
4285
+
4286
+ /*
4287
+ * Returning from an exception with a PC with bit 0 set is defined
4288
+ * behaviour on v8M (bit 0 is ignored), but for v7M it was specified
4289
+ * to be UNPREDICTABLE. In practice actual v7M hardware seems to ignore
4290
+ * the lsbit, and there are several RTOSes out there which incorrectly
4291
+ * assume the r15 in the stack frame should be a Thumb-style "lsbit
4292
+ * indicates ARM/Thumb" value, so ignore the bit on v7M as well, but
4293
+ * complain about the badly behaved guest.
4294
+ */
4295
+ if (env->regs[15] & 1) {
4296
+ env->regs[15] &= ~1U;
4297
+ if (!arm_feature(env, ARM_FEATURE_V8)) {
4298
+ qemu_log_mask(LOG_GUEST_ERROR,
4299
+ "M profile return from interrupt with misaligned "
4300
+ "PC is UNPREDICTABLE on v7M\n");
4301
+ }
4302
+ }
4303
+
4304
+ if (arm_feature(env, ARM_FEATURE_V8)) {
4305
+ /*
4306
+ * For v8M we have to check whether the xPSR exception field
4307
+ * matches the EXCRET value for return to handler/thread
4308
+ * before we commit to changing the SP and xPSR.
4309
+ */
4310
+ bool will_be_handler = (xpsr & XPSR_EXCP) != 0;
4311
+ if (return_to_handler != will_be_handler) {
4312
+ /*
4313
+ * Take an INVPC UsageFault on the current stack.
4314
+ * By this point we will have switched to the security state
4315
+ * for the background state, so this UsageFault will target
4316
+ * that state.
4317
+ */
4318
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
4319
+ env->v7m.secure);
4320
+ env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
4321
+ qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on existing "
4322
+ "stackframe: failed exception return integrity "
4323
+ "check\n");
4324
+ v7m_exception_taken(cpu, excret, true, false);
4325
+ return;
4326
+ }
4327
+ }
4328
+
4329
+ if (!ftype) {
4330
+ /* FP present and we need to handle it */
4331
+ if (!return_to_secure &&
4332
+ (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_LSPACT_MASK)) {
4333
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
4334
+ env->v7m.sfsr |= R_V7M_SFSR_LSERR_MASK;
4335
+ qemu_log_mask(CPU_LOG_INT,
4336
+ "...taking SecureFault on existing stackframe: "
4337
+ "Secure LSPACT set but exception return is "
4338
+ "not to secure state\n");
4339
+ v7m_exception_taken(cpu, excret, true, false);
4340
+ return;
4341
+ }
4342
+
4343
+ restore_s16_s31 = return_to_secure &&
4344
+ (env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_TS_MASK);
4345
+
4346
+ if (env->v7m.fpccr[return_to_secure] & R_V7M_FPCCR_LSPACT_MASK) {
4347
+ /* State in FPU is still valid, just clear LSPACT */
4348
+ env->v7m.fpccr[return_to_secure] &= ~R_V7M_FPCCR_LSPACT_MASK;
4349
+ } else {
4350
+ int i;
4351
+ uint32_t fpscr;
4352
+ bool cpacr_pass, nsacr_pass;
4353
+
4354
+ cpacr_pass = v7m_cpacr_pass(env, return_to_secure,
4355
+ return_to_priv);
4356
+ nsacr_pass = return_to_secure ||
4357
+ extract32(env->v7m.nsacr, 10, 1);
4358
+
4359
+ if (!cpacr_pass) {
4360
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
4361
+ return_to_secure);
4362
+ env->v7m.cfsr[return_to_secure] |= R_V7M_CFSR_NOCP_MASK;
4363
+ qemu_log_mask(CPU_LOG_INT,
4364
+ "...taking UsageFault on existing "
4365
+ "stackframe: CPACR.CP10 prevents unstacking "
4366
+ "FP regs\n");
4367
+ v7m_exception_taken(cpu, excret, true, false);
4368
+ return;
4369
+ } else if (!nsacr_pass) {
4370
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, true);
4371
+ env->v7m.cfsr[M_REG_S] |= R_V7M_CFSR_INVPC_MASK;
4372
+ qemu_log_mask(CPU_LOG_INT,
4373
+ "...taking Secure UsageFault on existing "
4374
+ "stackframe: NSACR.CP10 prevents unstacking "
4375
+ "FP regs\n");
4376
+ v7m_exception_taken(cpu, excret, true, false);
4377
+ return;
4378
+ }
4379
+
4380
+ for (i = 0; i < (restore_s16_s31 ? 32 : 16); i += 2) {
4381
+ uint32_t slo, shi;
4382
+ uint64_t dn;
4383
+ uint32_t faddr = frameptr + 0x20 + 4 * i;
4384
+
4385
+ if (i >= 16) {
4386
+ faddr += 8; /* Skip the slot for the FPSCR */
4387
+ }
4388
+
4389
+ pop_ok = pop_ok &&
4390
+ v7m_stack_read(cpu, &slo, faddr, mmu_idx) &&
4391
+ v7m_stack_read(cpu, &shi, faddr + 4, mmu_idx);
4392
+
4393
+ if (!pop_ok) {
4394
+ break;
4395
+ }
4396
+
4397
+ dn = (uint64_t)shi << 32 | slo;
4398
+ *aa32_vfp_dreg(env, i / 2) = dn;
4399
+ }
4400
+ pop_ok = pop_ok &&
4401
+ v7m_stack_read(cpu, &fpscr, frameptr + 0x60, mmu_idx);
4402
+ if (pop_ok) {
4403
+ vfp_set_fpscr(env, fpscr);
4404
+ }
4405
+ if (!pop_ok) {
4406
+ /*
4407
+ * These regs are 0 if security extension present;
4408
+ * otherwise merely UNKNOWN. We zero always.
4409
+ */
4410
+ for (i = 0; i < (restore_s16_s31 ? 32 : 16); i += 2) {
4411
+ *aa32_vfp_dreg(env, i / 2) = 0;
4412
+ }
4413
+ vfp_set_fpscr(env, 0);
4414
+ }
4415
+ }
4416
+ }
4417
+ env->v7m.control[M_REG_S] = FIELD_DP32(env->v7m.control[M_REG_S],
4418
+ V7M_CONTROL, FPCA, !ftype);
4419
+
4420
+ /* Commit to consuming the stack frame */
4421
+ frameptr += 0x20;
4422
+ if (!ftype) {
4423
+ frameptr += 0x48;
4424
+ if (restore_s16_s31) {
4425
+ frameptr += 0x40;
4426
+ }
4427
+ }
4428
+ /*
4429
+ * Undo stack alignment (the SPREALIGN bit indicates that the original
4430
+ * pre-exception SP was not 8-aligned and we added a padding word to
4431
+ * align it, so we undo this by ORing in the bit that increases it
4432
+ * from the current 8-aligned value to the 8-unaligned value. (Adding 4
4433
+ * would work too but a logical OR is how the pseudocode specifies it.)
4434
+ */
4435
+ if (xpsr & XPSR_SPREALIGN) {
4436
+ frameptr |= 4;
4437
+ }
4438
+ *frame_sp_p = frameptr;
4439
+ }
4440
+
4441
+ xpsr_mask = ~(XPSR_SPREALIGN | XPSR_SFPA);
4442
+ if (!arm_feature(env, ARM_FEATURE_THUMB_DSP)) {
4443
+ xpsr_mask &= ~XPSR_GE;
4444
+ }
4445
+ /* This xpsr_write() will invalidate frame_sp_p as it may switch stack */
4446
+ xpsr_write(env, xpsr, xpsr_mask);
4447
+
4448
+ if (env->v7m.secure) {
4449
+ bool sfpa = xpsr & XPSR_SFPA;
4450
+
4451
+ env->v7m.control[M_REG_S] = FIELD_DP32(env->v7m.control[M_REG_S],
4452
+ V7M_CONTROL, SFPA, sfpa);
4453
+ }
4454
+
4455
+ /*
4456
+ * The restored xPSR exception field will be zero if we're
4457
+ * resuming in Thread mode. If that doesn't match what the
4458
+ * exception return excret specified then this is a UsageFault.
4459
+ * v7M requires we make this check here; v8M did it earlier.
4460
+ */
4461
+ if (return_to_handler != arm_v7m_is_handler_mode(env)) {
4462
+ /*
4463
+ * Take an INVPC UsageFault by pushing the stack again;
4464
+ * we know we're v7M so this is never a Secure UsageFault.
4465
+ */
4466
+ bool ignore_stackfaults;
4467
+
4468
+ assert(!arm_feature(env, ARM_FEATURE_V8));
4469
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, false);
4470
+ env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
4471
+ ignore_stackfaults = v7m_push_stack(cpu);
4472
+ qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on new stackframe: "
4473
+ "failed exception return integrity check\n");
4474
+ v7m_exception_taken(cpu, excret, false, ignore_stackfaults);
4475
+ return;
4476
+ }
4477
+
4478
+ /* Otherwise, we have a successful exception exit. */
4479
+ arm_clear_exclusive(env);
4480
+ qemu_log_mask(CPU_LOG_INT, "...successful exception return\n");
4481
+}
4482
+
4483
+static bool do_v7m_function_return(ARMCPU *cpu)
4484
+{
4485
+ /*
4486
+ * v8M security extensions magic function return.
4487
+ * We may either:
4488
+ * (1) throw an exception (longjump)
4489
+ * (2) return true if we successfully handled the function return
4490
+ * (3) return false if we failed a consistency check and have
4491
+ * pended a UsageFault that needs to be taken now
4492
+ *
4493
+ * At this point the magic return value is split between env->regs[15]
4494
+ * and env->thumb. We don't bother to reconstitute it because we don't
4495
+ * need it (all values are handled the same way).
4496
+ */
4497
+ CPUARMState *env = &cpu->env;
4498
+ uint32_t newpc, newpsr, newpsr_exc;
4499
+
4500
+ qemu_log_mask(CPU_LOG_INT, "...really v7M secure function return\n");
4501
+
4502
+ {
4503
+ bool threadmode, spsel;
4504
+ TCGMemOpIdx oi;
4505
+ ARMMMUIdx mmu_idx;
4506
+ uint32_t *frame_sp_p;
4507
+ uint32_t frameptr;
4508
+
4509
+ /* Pull the return address and IPSR from the Secure stack */
4510
+ threadmode = !arm_v7m_is_handler_mode(env);
4511
+ spsel = env->v7m.control[M_REG_S] & R_V7M_CONTROL_SPSEL_MASK;
4512
+
4513
+ frame_sp_p = get_v7m_sp_ptr(env, true, threadmode, spsel);
4514
+ frameptr = *frame_sp_p;
4515
+
4516
+ /*
4517
+ * These loads may throw an exception (for MPU faults). We want to
4518
+ * do them as secure, so work out what MMU index that is.
4519
+ */
4520
+ mmu_idx = arm_v7m_mmu_idx_for_secstate(env, true);
4521
+ oi = make_memop_idx(MO_LE, arm_to_core_mmu_idx(mmu_idx));
4522
+ newpc = helper_le_ldul_mmu(env, frameptr, oi, 0);
4523
+ newpsr = helper_le_ldul_mmu(env, frameptr + 4, oi, 0);
4524
+
4525
+ /* Consistency checks on new IPSR */
4526
+ newpsr_exc = newpsr & XPSR_EXCP;
4527
+ if (!((env->v7m.exception == 0 && newpsr_exc == 0) ||
4528
+ (env->v7m.exception == 1 && newpsr_exc != 0))) {
4529
+ /* Pend the fault and tell our caller to take it */
4530
+ env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
4531
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
4532
+ env->v7m.secure);
4533
+ qemu_log_mask(CPU_LOG_INT,
4534
+ "...taking INVPC UsageFault: "
4535
+ "IPSR consistency check failed\n");
4536
+ return false;
4537
+ }
4538
+
4539
+ *frame_sp_p = frameptr + 8;
4540
+ }
4541
+
4542
+ /* This invalidates frame_sp_p */
4543
+ switch_v7m_security_state(env, true);
4544
+ env->v7m.exception = newpsr_exc;
4545
+ env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
4546
+ if (newpsr & XPSR_SFPA) {
4547
+ env->v7m.control[M_REG_S] |= R_V7M_CONTROL_SFPA_MASK;
4548
+ }
4549
+ xpsr_write(env, 0, XPSR_IT);
4550
+ env->thumb = newpc & 1;
4551
+ env->regs[15] = newpc & ~1;
4552
+
4553
+ qemu_log_mask(CPU_LOG_INT, "...function return successful\n");
4554
+ return true;
4555
+}
4556
+
4557
+static bool v7m_read_half_insn(ARMCPU *cpu, ARMMMUIdx mmu_idx,
4558
+ uint32_t addr, uint16_t *insn)
4559
+{
4560
+ /*
4561
+ * Load a 16-bit portion of a v7M instruction, returning true on success,
4562
+ * or false on failure (in which case we will have pended the appropriate
4563
+ * exception).
4564
+ * We need to do the instruction fetch's MPU and SAU checks
4565
+ * like this because there is no MMU index that would allow
4566
+ * doing the load with a single function call. Instead we must
4567
+ * first check that the security attributes permit the load
4568
+ * and that they don't mismatch on the two halves of the instruction,
4569
+ * and then we do the load as a secure load (ie using the security
4570
+ * attributes of the address, not the CPU, as architecturally required).
4571
+ */
4572
+ CPUState *cs = CPU(cpu);
4573
+ CPUARMState *env = &cpu->env;
4574
+ V8M_SAttributes sattrs = {};
4575
+ MemTxAttrs attrs = {};
4576
+ ARMMMUFaultInfo fi = {};
4577
+ MemTxResult txres;
4578
+ target_ulong page_size;
4579
+ hwaddr physaddr;
4580
+ int prot;
4581
+
4582
+ v8m_security_lookup(env, addr, MMU_INST_FETCH, mmu_idx, &sattrs);
4583
+ if (!sattrs.nsc || sattrs.ns) {
4584
+ /*
4585
+ * This must be the second half of the insn, and it straddles a
4586
+ * region boundary with the second half not being S&NSC.
4587
+ */
4588
+ env->v7m.sfsr |= R_V7M_SFSR_INVEP_MASK;
4589
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
4590
+ qemu_log_mask(CPU_LOG_INT,
4591
+ "...really SecureFault with SFSR.INVEP\n");
4592
+ return false;
4593
+ }
4594
+ if (get_phys_addr(env, addr, MMU_INST_FETCH, mmu_idx,
4595
+ &physaddr, &attrs, &prot, &page_size, &fi, NULL)) {
4596
+ /* the MPU lookup failed */
4597
+ env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_IACCVIOL_MASK;
4598
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM, env->v7m.secure);
4599
+ qemu_log_mask(CPU_LOG_INT, "...really MemManage with CFSR.IACCVIOL\n");
4600
+ return false;
4601
+ }
4602
+ *insn = address_space_lduw_le(arm_addressspace(cs, attrs), physaddr,
4603
+ attrs, &txres);
4604
+ if (txres != MEMTX_OK) {
4605
+ env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_IBUSERR_MASK;
4606
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_BUS, false);
4607
+ qemu_log_mask(CPU_LOG_INT, "...really BusFault with CFSR.IBUSERR\n");
4608
+ return false;
4609
+ }
4610
+ return true;
4611
+}
4612
+
4613
+static bool v7m_handle_execute_nsc(ARMCPU *cpu)
4614
+{
4615
+ /*
4616
+ * Check whether this attempt to execute code in a Secure & NS-Callable
4617
+ * memory region is for an SG instruction; if so, then emulate the
4618
+ * effect of the SG instruction and return true. Otherwise pend
4619
+ * the correct kind of exception and return false.
4620
+ */
4621
+ CPUARMState *env = &cpu->env;
4622
+ ARMMMUIdx mmu_idx;
4623
+ uint16_t insn;
4624
+
4625
+ /*
4626
+ * We should never get here unless get_phys_addr_pmsav8() caused
4627
+ * an exception for NS executing in S&NSC memory.
4628
+ */
4629
+ assert(!env->v7m.secure);
4630
+ assert(arm_feature(env, ARM_FEATURE_M_SECURITY));
4631
+
4632
+ /* We want to do the MPU lookup as secure; work out what mmu_idx that is */
4633
+ mmu_idx = arm_v7m_mmu_idx_for_secstate(env, true);
4634
+
4635
+ if (!v7m_read_half_insn(cpu, mmu_idx, env->regs[15], &insn)) {
4636
+ return false;
4637
+ }
4638
+
4639
+ if (!env->thumb) {
4640
+ goto gen_invep;
4641
+ }
4642
+
4643
+ if (insn != 0xe97f) {
4644
+ /*
4645
+ * Not an SG instruction first half (we choose the IMPDEF
4646
+ * early-SG-check option).
4647
+ */
4648
+ goto gen_invep;
4649
+ }
4650
+
4651
+ if (!v7m_read_half_insn(cpu, mmu_idx, env->regs[15] + 2, &insn)) {
4652
+ return false;
4653
+ }
4654
+
4655
+ if (insn != 0xe97f) {
4656
+ /*
4657
+ * Not an SG instruction second half (yes, both halves of the SG
4658
+ * insn have the same hex value)
4659
+ */
4660
+ goto gen_invep;
4661
+ }
4662
+
4663
+ /*
4664
+ * OK, we have confirmed that we really have an SG instruction.
4665
+ * We know we're NS in S memory so don't need to repeat those checks.
4666
+ */
4667
+ qemu_log_mask(CPU_LOG_INT, "...really an SG instruction at 0x%08" PRIx32
4668
+ ", executing it\n", env->regs[15]);
4669
+ env->regs[14] &= ~1;
4670
+ env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
4671
+ switch_v7m_security_state(env, true);
4672
+ xpsr_write(env, 0, XPSR_IT);
4673
+ env->regs[15] += 4;
4674
+ return true;
4675
+
4676
+gen_invep:
4677
+ env->v7m.sfsr |= R_V7M_SFSR_INVEP_MASK;
4678
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
4679
+ qemu_log_mask(CPU_LOG_INT,
4680
+ "...really SecureFault with SFSR.INVEP\n");
4681
+ return false;
4682
+}
4683
+
4684
+void arm_v7m_cpu_do_interrupt(CPUState *cs)
4685
+{
4686
+ ARMCPU *cpu = ARM_CPU(cs);
4687
+ CPUARMState *env = &cpu->env;
4688
+ uint32_t lr;
4689
+ bool ignore_stackfaults;
4690
+
4691
+ arm_log_exception(cs->exception_index);
4692
+
4693
+ /*
4694
+ * For exceptions we just mark as pending on the NVIC, and let that
4695
+ * handle it.
4696
+ */
4697
+ switch (cs->exception_index) {
4698
+ case EXCP_UDEF:
4699
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
4700
+ env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_UNDEFINSTR_MASK;
4701
+ break;
4702
+ case EXCP_NOCP:
4703
+ {
4704
+ /*
4705
+ * NOCP might be directed to something other than the current
4706
+ * security state if this fault is because of NSACR; we indicate
4707
+ * the target security state using exception.target_el.
4708
+ */
4709
+ int target_secstate;
4710
+
4711
+ if (env->exception.target_el == 3) {
4712
+ target_secstate = M_REG_S;
4713
+ } else {
4714
+ target_secstate = env->v7m.secure;
4715
+ }
4716
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, target_secstate);
4717
+ env->v7m.cfsr[target_secstate] |= R_V7M_CFSR_NOCP_MASK;
4718
+ break;
4719
+ }
4720
+ case EXCP_INVSTATE:
4721
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
4722
+ env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVSTATE_MASK;
4723
+ break;
4724
+ case EXCP_STKOF:
4725
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
4726
+ env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_STKOF_MASK;
4727
+ break;
4728
+ case EXCP_LSERR:
4729
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
4730
+ env->v7m.sfsr |= R_V7M_SFSR_LSERR_MASK;
4731
+ break;
4732
+ case EXCP_UNALIGNED:
4733
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
4734
+ env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_UNALIGNED_MASK;
4735
+ break;
4736
+ case EXCP_SWI:
4737
+ /* The PC already points to the next instruction. */
4738
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SVC, env->v7m.secure);
4739
+ break;
4740
+ case EXCP_PREFETCH_ABORT:
4741
+ case EXCP_DATA_ABORT:
4742
+ /*
4743
+ * Note that for M profile we don't have a guest facing FSR, but
4744
+ * the env->exception.fsr will be populated by the code that
4745
+ * raises the fault, in the A profile short-descriptor format.
4746
+ */
4747
+ switch (env->exception.fsr & 0xf) {
4748
+ case M_FAKE_FSR_NSC_EXEC:
4749
+ /*
4750
+ * Exception generated when we try to execute code at an address
4751
+ * which is marked as Secure & Non-Secure Callable and the CPU
4752
+ * is in the Non-Secure state. The only instruction which can
4753
+ * be executed like this is SG (and that only if both halves of
4754
+ * the SG instruction have the same security attributes.)
4755
+ * Everything else must generate an INVEP SecureFault, so we
4756
+ * emulate the SG instruction here.
4757
+ */
4758
+ if (v7m_handle_execute_nsc(cpu)) {
4759
+ return;
4760
+ }
4761
+ break;
4762
+ case M_FAKE_FSR_SFAULT:
4763
+ /*
4764
+ * Various flavours of SecureFault for attempts to execute or
4765
+ * access data in the wrong security state.
4766
+ */
4767
+ switch (cs->exception_index) {
4768
+ case EXCP_PREFETCH_ABORT:
4769
+ if (env->v7m.secure) {
4770
+ env->v7m.sfsr |= R_V7M_SFSR_INVTRAN_MASK;
4771
+ qemu_log_mask(CPU_LOG_INT,
4772
+ "...really SecureFault with SFSR.INVTRAN\n");
4773
+ } else {
4774
+ env->v7m.sfsr |= R_V7M_SFSR_INVEP_MASK;
4775
+ qemu_log_mask(CPU_LOG_INT,
4776
+ "...really SecureFault with SFSR.INVEP\n");
4777
+ }
4778
+ break;
4779
+ case EXCP_DATA_ABORT:
4780
+ /* This must be an NS access to S memory */
4781
+ env->v7m.sfsr |= R_V7M_SFSR_AUVIOL_MASK;
4782
+ qemu_log_mask(CPU_LOG_INT,
4783
+ "...really SecureFault with SFSR.AUVIOL\n");
4784
+ break;
4785
+ }
4786
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
4787
+ break;
4788
+ case 0x8: /* External Abort */
4789
+ switch (cs->exception_index) {
4790
+ case EXCP_PREFETCH_ABORT:
4791
+ env->v7m.cfsr[M_REG_NS] |= R_V7M_CFSR_IBUSERR_MASK;
4792
+ qemu_log_mask(CPU_LOG_INT, "...with CFSR.IBUSERR\n");
4793
+ break;
4794
+ case EXCP_DATA_ABORT:
4795
+ env->v7m.cfsr[M_REG_NS] |=
4796
+ (R_V7M_CFSR_PRECISERR_MASK | R_V7M_CFSR_BFARVALID_MASK);
4797
+ env->v7m.bfar = env->exception.vaddress;
4798
+ qemu_log_mask(CPU_LOG_INT,
4799
+ "...with CFSR.PRECISERR and BFAR 0x%x\n",
4800
+ env->v7m.bfar);
4801
+ break;
4802
+ }
4803
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_BUS, false);
4804
+ break;
4805
+ default:
4806
+ /*
4807
+ * All other FSR values are either MPU faults or "can't happen
4808
+ * for M profile" cases.
4809
+ */
4810
+ switch (cs->exception_index) {
4811
+ case EXCP_PREFETCH_ABORT:
4812
+ env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_IACCVIOL_MASK;
4813
+ qemu_log_mask(CPU_LOG_INT, "...with CFSR.IACCVIOL\n");
4814
+ break;
4815
+ case EXCP_DATA_ABORT:
4816
+ env->v7m.cfsr[env->v7m.secure] |=
4817
+ (R_V7M_CFSR_DACCVIOL_MASK | R_V7M_CFSR_MMARVALID_MASK);
4818
+ env->v7m.mmfar[env->v7m.secure] = env->exception.vaddress;
4819
+ qemu_log_mask(CPU_LOG_INT,
4820
+ "...with CFSR.DACCVIOL and MMFAR 0x%x\n",
4821
+ env->v7m.mmfar[env->v7m.secure]);
4822
+ break;
4823
+ }
4824
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM,
4825
+ env->v7m.secure);
4826
+ break;
4827
+ }
4828
+ break;
4829
+ case EXCP_BKPT:
4830
+ if (semihosting_enabled()) {
4831
+ int nr;
4832
+ nr = arm_lduw_code(env, env->regs[15], arm_sctlr_b(env)) & 0xff;
4833
+ if (nr == 0xab) {
4834
+ env->regs[15] += 2;
4835
+ qemu_log_mask(CPU_LOG_INT,
4836
+ "...handling as semihosting call 0x%x\n",
4837
+ env->regs[0]);
4838
+ env->regs[0] = do_arm_semihosting(env);
4839
+ return;
4840
+ }
4841
+ }
4842
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_DEBUG, false);
4843
+ break;
4844
+ case EXCP_IRQ:
4845
+ break;
4846
+ case EXCP_EXCEPTION_EXIT:
4847
+ if (env->regs[15] < EXC_RETURN_MIN_MAGIC) {
4848
+ /* Must be v8M security extension function return */
4849
+ assert(env->regs[15] >= FNC_RETURN_MIN_MAGIC);
4850
+ assert(arm_feature(env, ARM_FEATURE_M_SECURITY));
4851
+ if (do_v7m_function_return(cpu)) {
4852
+ return;
4853
+ }
4854
+ } else {
4855
+ do_v7m_exception_exit(cpu);
4856
+ return;
4857
+ }
4858
+ break;
4859
+ case EXCP_LAZYFP:
4860
+ /*
4861
+ * We already pended the specific exception in the NVIC in the
4862
+ * v7m_preserve_fp_state() helper function.
4863
+ */
4864
+ break;
4865
+ default:
4866
+ cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index);
4867
+ return; /* Never happens. Keep compiler happy. */
4868
+ }
4869
+
4870
+ if (arm_feature(env, ARM_FEATURE_V8)) {
4871
+ lr = R_V7M_EXCRET_RES1_MASK |
4872
+ R_V7M_EXCRET_DCRS_MASK;
4873
+ /*
4874
+ * The S bit indicates whether we should return to Secure
4875
+ * or NonSecure (ie our current state).
4876
+ * The ES bit indicates whether we're taking this exception
4877
+ * to Secure or NonSecure (ie our target state). We set it
4878
+ * later, in v7m_exception_taken().
4879
+ * The SPSEL bit is also set in v7m_exception_taken() for v8M.
4880
+ * This corresponds to the ARM ARM pseudocode for v8M setting
4881
+ * some LR bits in PushStack() and some in ExceptionTaken();
4882
+ * the distinction matters for the tailchain cases where we
4883
+ * can take an exception without pushing the stack.
4884
+ */
4885
+ if (env->v7m.secure) {
4886
+ lr |= R_V7M_EXCRET_S_MASK;
4887
+ }
4888
+ if (!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK)) {
4889
+ lr |= R_V7M_EXCRET_FTYPE_MASK;
4890
+ }
4891
+ } else {
4892
+ lr = R_V7M_EXCRET_RES1_MASK |
4893
+ R_V7M_EXCRET_S_MASK |
4894
+ R_V7M_EXCRET_DCRS_MASK |
4895
+ R_V7M_EXCRET_FTYPE_MASK |
4896
+ R_V7M_EXCRET_ES_MASK;
4897
+ if (env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_MASK) {
4898
+ lr |= R_V7M_EXCRET_SPSEL_MASK;
4899
+ }
4900
+ }
4901
+ if (!arm_v7m_is_handler_mode(env)) {
4902
+ lr |= R_V7M_EXCRET_MODE_MASK;
4903
+ }
4904
+
4905
+ ignore_stackfaults = v7m_push_stack(cpu);
4906
+ v7m_exception_taken(cpu, lr, false, ignore_stackfaults);
4907
+}
4908
+
4909
+uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
4910
+{
4911
+ uint32_t mask;
4912
+ unsigned el = arm_current_el(env);
4913
+
4914
+ /* First handle registers which unprivileged can read */
4915
+
4916
+ switch (reg) {
4917
+ case 0 ... 7: /* xPSR sub-fields */
4918
+ mask = 0;
4919
+ if ((reg & 1) && el) {
4920
+ mask |= XPSR_EXCP; /* IPSR (unpriv. reads as zero) */
4921
+ }
4922
+ if (!(reg & 4)) {
4923
+ mask |= XPSR_NZCV | XPSR_Q; /* APSR */
4924
+ if (arm_feature(env, ARM_FEATURE_THUMB_DSP)) {
4925
+ mask |= XPSR_GE;
4926
+ }
4927
+ }
4928
+ /* EPSR reads as zero */
4929
+ return xpsr_read(env) & mask;
4930
+ break;
4931
+ case 20: /* CONTROL */
4932
+ {
4933
+ uint32_t value = env->v7m.control[env->v7m.secure];
4934
+ if (!env->v7m.secure) {
4935
+ /* SFPA is RAZ/WI from NS; FPCA is stored in the M_REG_S bank */
4936
+ value |= env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK;
4937
+ }
4938
+ return value;
4939
+ }
4940
+ case 0x94: /* CONTROL_NS */
4941
+ /*
4942
+ * We have to handle this here because unprivileged Secure code
4943
+ * can read the NS CONTROL register.
4944
+ */
4945
+ if (!env->v7m.secure) {
4946
+ return 0;
4947
+ }
4948
+ return env->v7m.control[M_REG_NS] |
4949
+ (env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK);
4950
+ }
4951
+
4952
+ if (el == 0) {
4953
+ return 0; /* unprivileged reads others as zero */
4954
+ }
4955
+
4956
+ if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
4957
+ switch (reg) {
4958
+ case 0x88: /* MSP_NS */
4959
+ if (!env->v7m.secure) {
4960
+ return 0;
4961
+ }
4962
+ return env->v7m.other_ss_msp;
4963
+ case 0x89: /* PSP_NS */
4964
+ if (!env->v7m.secure) {
4965
+ return 0;
4966
+ }
4967
+ return env->v7m.other_ss_psp;
4968
+ case 0x8a: /* MSPLIM_NS */
4969
+ if (!env->v7m.secure) {
4970
+ return 0;
4971
+ }
4972
+ return env->v7m.msplim[M_REG_NS];
4973
+ case 0x8b: /* PSPLIM_NS */
4974
+ if (!env->v7m.secure) {
4975
+ return 0;
4976
+ }
4977
+ return env->v7m.psplim[M_REG_NS];
4978
+ case 0x90: /* PRIMASK_NS */
4979
+ if (!env->v7m.secure) {
4980
+ return 0;
4981
+ }
4982
+ return env->v7m.primask[M_REG_NS];
4983
+ case 0x91: /* BASEPRI_NS */
4984
+ if (!env->v7m.secure) {
4985
+ return 0;
4986
+ }
4987
+ return env->v7m.basepri[M_REG_NS];
4988
+ case 0x93: /* FAULTMASK_NS */
4989
+ if (!env->v7m.secure) {
4990
+ return 0;
4991
+ }
4992
+ return env->v7m.faultmask[M_REG_NS];
4993
+ case 0x98: /* SP_NS */
4994
+ {
4995
+ /*
4996
+ * This gives the non-secure SP selected based on whether we're
4997
+ * currently in handler mode or not, using the NS CONTROL.SPSEL.
4998
+ */
4999
+ bool spsel = env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_MASK;
5000
+
5001
+ if (!env->v7m.secure) {
5002
+ return 0;
5003
+ }
5004
+ if (!arm_v7m_is_handler_mode(env) && spsel) {
5005
+ return env->v7m.other_ss_psp;
5006
+ } else {
5007
+ return env->v7m.other_ss_msp;
5008
+ }
5009
+ }
5010
+ default:
5011
+ break;
5012
+ }
5013
+ }
5014
+
5015
+ switch (reg) {
5016
+ case 8: /* MSP */
5017
+ return v7m_using_psp(env) ? env->v7m.other_sp : env->regs[13];
5018
+ case 9: /* PSP */
5019
+ return v7m_using_psp(env) ? env->regs[13] : env->v7m.other_sp;
5020
+ case 10: /* MSPLIM */
5021
+ if (!arm_feature(env, ARM_FEATURE_V8)) {
5022
+ goto bad_reg;
5023
+ }
5024
+ return env->v7m.msplim[env->v7m.secure];
5025
+ case 11: /* PSPLIM */
5026
+ if (!arm_feature(env, ARM_FEATURE_V8)) {
5027
+ goto bad_reg;
5028
+ }
5029
+ return env->v7m.psplim[env->v7m.secure];
5030
+ case 16: /* PRIMASK */
5031
+ return env->v7m.primask[env->v7m.secure];
5032
+ case 17: /* BASEPRI */
5033
+ case 18: /* BASEPRI_MAX */
5034
+ return env->v7m.basepri[env->v7m.secure];
5035
+ case 19: /* FAULTMASK */
5036
+ return env->v7m.faultmask[env->v7m.secure];
5037
+ default:
5038
+ bad_reg:
5039
+ qemu_log_mask(LOG_GUEST_ERROR, "Attempt to read unknown special"
5040
+ " register %d\n", reg);
5041
+ return 0;
5042
+ }
5043
+}
5044
+
5045
+void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val)
5046
+{
5047
+ /*
5048
+ * We're passed bits [11..0] of the instruction; extract
5049
+ * SYSm and the mask bits.
5050
+ * Invalid combinations of SYSm and mask are UNPREDICTABLE;
5051
+ * we choose to treat them as if the mask bits were valid.
5052
+ * NB that the pseudocode 'mask' variable is bits [11..10],
5053
+ * whereas ours is [11..8].
5054
+ */
5055
+ uint32_t mask = extract32(maskreg, 8, 4);
5056
+ uint32_t reg = extract32(maskreg, 0, 8);
5057
+ int cur_el = arm_current_el(env);
5058
+
5059
+ if (cur_el == 0 && reg > 7 && reg != 20) {
5060
+ /*
5061
+ * only xPSR sub-fields and CONTROL.SFPA may be written by
5062
+ * unprivileged code
5063
+ */
5064
+ return;
5065
+ }
5066
+
5067
+ if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
5068
+ switch (reg) {
5069
+ case 0x88: /* MSP_NS */
5070
+ if (!env->v7m.secure) {
5071
+ return;
5072
+ }
5073
+ env->v7m.other_ss_msp = val;
5074
+ return;
5075
+ case 0x89: /* PSP_NS */
5076
+ if (!env->v7m.secure) {
5077
+ return;
5078
+ }
5079
+ env->v7m.other_ss_psp = val;
5080
+ return;
5081
+ case 0x8a: /* MSPLIM_NS */
5082
+ if (!env->v7m.secure) {
5083
+ return;
5084
+ }
5085
+ env->v7m.msplim[M_REG_NS] = val & ~7;
5086
+ return;
5087
+ case 0x8b: /* PSPLIM_NS */
5088
+ if (!env->v7m.secure) {
5089
+ return;
5090
+ }
5091
+ env->v7m.psplim[M_REG_NS] = val & ~7;
5092
+ return;
5093
+ case 0x90: /* PRIMASK_NS */
5094
+ if (!env->v7m.secure) {
5095
+ return;
5096
+ }
5097
+ env->v7m.primask[M_REG_NS] = val & 1;
5098
+ return;
5099
+ case 0x91: /* BASEPRI_NS */
5100
+ if (!env->v7m.secure || !arm_feature(env, ARM_FEATURE_M_MAIN)) {
5101
+ return;
5102
+ }
5103
+ env->v7m.basepri[M_REG_NS] = val & 0xff;
5104
+ return;
5105
+ case 0x93: /* FAULTMASK_NS */
5106
+ if (!env->v7m.secure || !arm_feature(env, ARM_FEATURE_M_MAIN)) {
5107
+ return;
5108
+ }
5109
+ env->v7m.faultmask[M_REG_NS] = val & 1;
5110
+ return;
5111
+ case 0x94: /* CONTROL_NS */
5112
+ if (!env->v7m.secure) {
5113
+ return;
5114
+ }
5115
+ write_v7m_control_spsel_for_secstate(env,
5116
+ val & R_V7M_CONTROL_SPSEL_MASK,
5117
+ M_REG_NS);
5118
+ if (arm_feature(env, ARM_FEATURE_M_MAIN)) {
5119
+ env->v7m.control[M_REG_NS] &= ~R_V7M_CONTROL_NPRIV_MASK;
5120
+ env->v7m.control[M_REG_NS] |= val & R_V7M_CONTROL_NPRIV_MASK;
5121
+ }
5122
+ /*
5123
+ * SFPA is RAZ/WI from NS. FPCA is RO if NSACR.CP10 == 0,
5124
+ * RES0 if the FPU is not present, and is stored in the S bank
5125
+ */
5126
+ if (arm_feature(env, ARM_FEATURE_VFP) &&
5127
+ extract32(env->v7m.nsacr, 10, 1)) {
5128
+ env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_FPCA_MASK;
5129
+ env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_FPCA_MASK;
5130
+ }
5131
+ return;
5132
+ case 0x98: /* SP_NS */
5133
+ {
5134
+ /*
5135
+ * This gives the non-secure SP selected based on whether we're
5136
+ * currently in handler mode or not, using the NS CONTROL.SPSEL.
5137
+ */
5138
+ bool spsel = env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_MASK;
5139
+ bool is_psp = !arm_v7m_is_handler_mode(env) && spsel;
5140
+ uint32_t limit;
5141
+
5142
+ if (!env->v7m.secure) {
5143
+ return;
5144
+ }
5145
+
5146
+ limit = is_psp ? env->v7m.psplim[false] : env->v7m.msplim[false];
5147
+
5148
+ if (val < limit) {
5149
+ CPUState *cs = env_cpu(env);
5150
+
5151
+ cpu_restore_state(cs, GETPC(), true);
5152
+ raise_exception(env, EXCP_STKOF, 0, 1);
5153
+ }
5154
+
5155
+ if (is_psp) {
5156
+ env->v7m.other_ss_psp = val;
5157
+ } else {
5158
+ env->v7m.other_ss_msp = val;
5159
+ }
5160
+ return;
5161
+ }
5162
+ default:
5163
+ break;
5164
+ }
5165
+ }
5166
+
5167
+ switch (reg) {
5168
+ case 0 ... 7: /* xPSR sub-fields */
5169
+ /* only APSR is actually writable */
5170
+ if (!(reg & 4)) {
5171
+ uint32_t apsrmask = 0;
5172
+
5173
+ if (mask & 8) {
5174
+ apsrmask |= XPSR_NZCV | XPSR_Q;
5175
+ }
5176
+ if ((mask & 4) && arm_feature(env, ARM_FEATURE_THUMB_DSP)) {
5177
+ apsrmask |= XPSR_GE;
5178
+ }
5179
+ xpsr_write(env, val, apsrmask);
5180
+ }
5181
+ break;
5182
+ case 8: /* MSP */
5183
+ if (v7m_using_psp(env)) {
5184
+ env->v7m.other_sp = val;
5185
+ } else {
5186
+ env->regs[13] = val;
5187
+ }
5188
+ break;
5189
+ case 9: /* PSP */
5190
+ if (v7m_using_psp(env)) {
5191
+ env->regs[13] = val;
5192
+ } else {
5193
+ env->v7m.other_sp = val;
5194
+ }
5195
+ break;
5196
+ case 10: /* MSPLIM */
5197
+ if (!arm_feature(env, ARM_FEATURE_V8)) {
5198
+ goto bad_reg;
5199
+ }
5200
+ env->v7m.msplim[env->v7m.secure] = val & ~7;
5201
+ break;
5202
+ case 11: /* PSPLIM */
5203
+ if (!arm_feature(env, ARM_FEATURE_V8)) {
5204
+ goto bad_reg;
5205
+ }
5206
+ env->v7m.psplim[env->v7m.secure] = val & ~7;
5207
+ break;
5208
+ case 16: /* PRIMASK */
5209
+ env->v7m.primask[env->v7m.secure] = val & 1;
5210
+ break;
5211
+ case 17: /* BASEPRI */
5212
+ if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
5213
+ goto bad_reg;
5214
+ }
5215
+ env->v7m.basepri[env->v7m.secure] = val & 0xff;
5216
+ break;
5217
+ case 18: /* BASEPRI_MAX */
5218
+ if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
5219
+ goto bad_reg;
5220
+ }
5221
+ val &= 0xff;
5222
+ if (val != 0 && (val < env->v7m.basepri[env->v7m.secure]
5223
+ || env->v7m.basepri[env->v7m.secure] == 0)) {
5224
+ env->v7m.basepri[env->v7m.secure] = val;
5225
+ }
5226
+ break;
5227
+ case 19: /* FAULTMASK */
5228
+ if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
5229
+ goto bad_reg;
5230
+ }
5231
+ env->v7m.faultmask[env->v7m.secure] = val & 1;
5232
+ break;
5233
+ case 20: /* CONTROL */
5234
+ /*
5235
+ * Writing to the SPSEL bit only has an effect if we are in
5236
+ * thread mode; other bits can be updated by any privileged code.
5237
+ * write_v7m_control_spsel() deals with updating the SPSEL bit in
5238
+ * env->v7m.control, so we only need update the others.
5239
+ * For v7M, we must just ignore explicit writes to SPSEL in handler
5240
+ * mode; for v8M the write is permitted but will have no effect.
5241
+ * All these bits are writes-ignored from non-privileged code,
5242
+ * except for SFPA.
5243
+ */
5244
+ if (cur_el > 0 && (arm_feature(env, ARM_FEATURE_V8) ||
5245
+ !arm_v7m_is_handler_mode(env))) {
5246
+ write_v7m_control_spsel(env, (val & R_V7M_CONTROL_SPSEL_MASK) != 0);
5247
+ }
5248
+ if (cur_el > 0 && arm_feature(env, ARM_FEATURE_M_MAIN)) {
5249
+ env->v7m.control[env->v7m.secure] &= ~R_V7M_CONTROL_NPRIV_MASK;
5250
+ env->v7m.control[env->v7m.secure] |= val & R_V7M_CONTROL_NPRIV_MASK;
5251
+ }
5252
+ if (arm_feature(env, ARM_FEATURE_VFP)) {
5253
+ /*
5254
+ * SFPA is RAZ/WI from NS or if no FPU.
5255
+ * FPCA is RO if NSACR.CP10 == 0, RES0 if the FPU is not present.
5256
+ * Both are stored in the S bank.
5257
+ */
5258
+ if (env->v7m.secure) {
5259
+ env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
5260
+ env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_SFPA_MASK;
5261
+ }
5262
+ if (cur_el > 0 &&
5263
+ (env->v7m.secure || !arm_feature(env, ARM_FEATURE_M_SECURITY) ||
5264
+ extract32(env->v7m.nsacr, 10, 1))) {
5265
+ env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_FPCA_MASK;
5266
+ env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_FPCA_MASK;
5267
+ }
5268
+ }
5269
+ break;
5270
+ default:
5271
+ bad_reg:
5272
+ qemu_log_mask(LOG_GUEST_ERROR, "Attempt to write unknown special"
5273
+ " register %d\n", reg);
5274
+ return;
5275
+ }
5276
+}
5277
+
5278
+uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
5279
+{
5280
+ /* Implement the TT instruction. op is bits [7:6] of the insn. */
5281
+ bool forceunpriv = op & 1;
5282
+ bool alt = op & 2;
5283
+ V8M_SAttributes sattrs = {};
5284
+ uint32_t tt_resp;
5285
+ bool r, rw, nsr, nsrw, mrvalid;
5286
+ int prot;
5287
+ ARMMMUFaultInfo fi = {};
5288
+ MemTxAttrs attrs = {};
5289
+ hwaddr phys_addr;
5290
+ ARMMMUIdx mmu_idx;
5291
+ uint32_t mregion;
5292
+ bool targetpriv;
5293
+ bool targetsec = env->v7m.secure;
5294
+ bool is_subpage;
5295
+
5296
+ /*
5297
+ * Work out what the security state and privilege level we're
5298
+ * interested in is...
5299
+ */
5300
+ if (alt) {
5301
+ targetsec = !targetsec;
5302
+ }
5303
+
5304
+ if (forceunpriv) {
5305
+ targetpriv = false;
5306
+ } else {
5307
+ targetpriv = arm_v7m_is_handler_mode(env) ||
5308
+ !(env->v7m.control[targetsec] & R_V7M_CONTROL_NPRIV_MASK);
5309
+ }
5310
+
5311
+ /* ...and then figure out which MMU index this is */
5312
+ mmu_idx = arm_v7m_mmu_idx_for_secstate_and_priv(env, targetsec, targetpriv);
5313
+
5314
+ /*
5315
+ * We know that the MPU and SAU don't care about the access type
5316
+ * for our purposes beyond that we don't want to claim to be
5317
+ * an insn fetch, so we arbitrarily call this a read.
5318
+ */
5319
+
5320
+ /*
5321
+ * MPU region info only available for privileged or if
5322
+ * inspecting the other MPU state.
5323
+ */
5324
+ if (arm_current_el(env) != 0 || alt) {
5325
+ /* We can ignore the return value as prot is always set */
5326
+ pmsav8_mpu_lookup(env, addr, MMU_DATA_LOAD, mmu_idx,
5327
+ &phys_addr, &attrs, &prot, &is_subpage,
5328
+ &fi, &mregion);
5329
+ if (mregion == -1) {
5330
+ mrvalid = false;
5331
+ mregion = 0;
5332
+ } else {
5333
+ mrvalid = true;
5334
+ }
5335
+ r = prot & PAGE_READ;
5336
+ rw = prot & PAGE_WRITE;
5337
+ } else {
5338
+ r = false;
5339
+ rw = false;
5340
+ mrvalid = false;
5341
+ mregion = 0;
5342
+ }
5343
+
5344
+ if (env->v7m.secure) {
5345
+ v8m_security_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, &sattrs);
5346
+ nsr = sattrs.ns && r;
5347
+ nsrw = sattrs.ns && rw;
5348
+ } else {
5349
+ sattrs.ns = true;
5350
+ nsr = false;
5351
+ nsrw = false;
5352
+ }
5353
+
5354
+ tt_resp = (sattrs.iregion << 24) |
5355
+ (sattrs.irvalid << 23) |
5356
+ ((!sattrs.ns) << 22) |
5357
+ (nsrw << 21) |
5358
+ (nsr << 20) |
5359
+ (rw << 19) |
5360
+ (r << 18) |
5361
+ (sattrs.srvalid << 17) |
5362
+ (mrvalid << 16) |
5363
+ (sattrs.sregion << 8) |
5364
+ mregion;
5365
+
5366
+ return tt_resp;
5367
+}
5368
+
5369
+#endif /* !CONFIG_USER_ONLY */
5370
+
5371
+ARMMMUIdx arm_v7m_mmu_idx_all(CPUARMState *env,
5372
+ bool secstate, bool priv, bool negpri)
5373
+{
5374
+ ARMMMUIdx mmu_idx = ARM_MMU_IDX_M;
5375
+
5376
+ if (priv) {
5377
+ mmu_idx |= ARM_MMU_IDX_M_PRIV;
5378
+ }
5379
+
5380
+ if (negpri) {
5381
+ mmu_idx |= ARM_MMU_IDX_M_NEGPRI;
5382
+ }
5383
+
5384
+ if (secstate) {
5385
+ mmu_idx |= ARM_MMU_IDX_M_S;
5386
+ }
5387
+
5388
+ return mmu_idx;
5389
+}
5390
+
5391
+ARMMMUIdx arm_v7m_mmu_idx_for_secstate_and_priv(CPUARMState *env,
5392
+ bool secstate, bool priv)
5393
+{
5394
+ bool negpri = armv7m_nvic_neg_prio_requested(env->nvic, secstate);
5395
+
5396
+ return arm_v7m_mmu_idx_all(env, secstate, priv, negpri);
5397
+}
5398
+
5399
+/* Return the MMU index for a v7M CPU in the specified security state */
5400
+ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate)
5401
+{
5402
+ bool priv = arm_current_el(env) != 0;
5403
+
5404
+ return arm_v7m_mmu_idx_for_secstate_and_priv(env, secstate, priv);
5405
+}
5406
--
148
--
5407
2.20.1
149
2.20.1
5408
150
5409
151
diff view generated by jsdifflib