1
Mostly my stuff with a few easy patches from others. I know I have
1
Hi; here's another Arm pullreq: the big thing in here is
2
a few big series in my to-review queue, but I've been too jetlagged
2
Bernhard's imx8mp-evk board model; there's also various cleanup
3
to try to tackle those :-(
3
type patches from me, as well as some bugfixes.
4
4
5
thanks
5
thanks
6
-- PMM
6
-- PMM
7
7
8
The following changes since commit a26a98dfb9d448d7234d931ae3720feddf6f0651:
8
The following changes since commit b69801dd6b1eb4d107f7c2f643adf0a4e3ec9124:
9
9
10
Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20171006' into staging (2017-10-06 13:19:03 +0100)
10
Merge tag 'for_upstream' of https://git.kernel.org/pub/scm/virt/kvm/mst/qemu into staging (2025-02-22 05:06:39 +0800)
11
11
12
are available in the git repository at:
12
are available in the Git repository at:
13
13
14
git://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20171006
14
https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20250225
15
15
16
for you to fetch changes up to 04829ce334bece78d4fa1d0fdbc8bc27dae9b242:
16
for you to fetch changes up to 1aaf3478684ff1cd02d1b36c32a00bfac9a5dbd5:
17
17
18
nvic: Add missing code for writing SHCSR.HARDFAULTPENDED bit (2017-10-06 16:46:49 +0100)
18
hw/arm/fsl-imx8mp: Add on-chip RAM (2025-02-25 17:24:00 +0000)
19
19
20
----------------------------------------------------------------
20
----------------------------------------------------------------
21
target-arm:
21
target-arm queue:
22
* v8M: more preparatory work
22
* hw/arm/smmuv3: Fill u.f_cd_fetch.addr for SMMU_EVT_F_CD_FETCH
23
* nvic: reset properly rather than leaving the nvic in a weird state
23
* hw/arm/virt: Support larger highmem MMIO regions
24
* xlnx-zynqmp: Mark the "xlnx, zynqmp" device with user_creatable = false
24
* machine: Centralize -machine dumpdtb option handling and report
25
* sd: fix out-of-bounds check for multi block reads
25
attempt to dump nonexistent DTB as an error
26
* arm: Fix SMC reporting to EL2 when QEMU provides PSCI
26
* fpu: remove target ifdefs and build it only once
27
* target/arm: Refactor to move TCG-only vfp_helper code into tcg/
28
* target/arm/hvf: Disable SME feature
29
* target/arm/hvf: sign extend the data for a load operation when SSE=1
30
* hw/misc/npcm_clk: fix buffer-overflow
31
* hw/arm: Add i.MX 8M Plus EVK board ("imx8mp-evk")
27
32
28
----------------------------------------------------------------
33
----------------------------------------------------------------
29
Jan Kiszka (1):
34
Bernhard Beschow (16):
30
arm: Fix SMC reporting to EL2 when QEMU provides PSCI
35
hw/usb/hcd-dwc3: Align global registers size with Linux
36
hw/pci-host/designware: Prevent device attachment on internal PCIe root bus
37
hw/gpio/pca955*: Move Kconfig switches next to implementations
38
hw/arm: Add i.MX 8M Plus EVK board
39
hw/arm/fsl-imx8mp: Implement clock tree
40
hw/arm/fsl-imx8mp: Add SNVS
41
hw/arm/fsl-imx8mp: Add USDHC storage controllers
42
hw/arm/fsl-imx8mp: Add PCIe support
43
hw/arm/fsl-imx8mp: Add GPIO controllers
44
hw/arm/fsl-imx8mp: Add I2C controllers
45
hw/arm/fsl-imx8mp: Add SPI controllers
46
hw/arm/fsl-imx8mp: Add watchdog support
47
hw/arm/fsl-imx8mp: Implement general purpose timers
48
hw/arm/fsl-imx8mp: Add Ethernet controller
49
hw/arm/fsl-imx8mp: Add USB support
50
hw/arm/fsl-imx8mp: Add on-chip RAM
31
51
32
Michael Olbrich (1):
52
Joelle van Dyne (2):
33
hw/sd: fix out-of-bounds check for multi block reads
53
target/arm/hvf: Disable SME feature
54
target/arm/hvf: sign extend the data for a load operation when SSE=1
34
55
35
Peter Maydell (17):
56
Matthew R. Ochs (1):
36
nvic: Clear the vector arrays and prigroup on reset
57
hw/arm/virt: Support larger highmem MMIO regions
37
target/arm: Don't switch to target stack early in v7M exception return
38
target/arm: Prepare for CONTROL.SPSEL being nonzero in Handler mode
39
target/arm: Restore security state on exception return
40
target/arm: Restore SPSEL to correct CONTROL register on exception return
41
target/arm: Check for xPSR mismatch usage faults earlier for v8M
42
target/arm: Warn about restoring to unaligned stack
43
target/arm: Don't warn about exception return with PC low bit set for v8M
44
target/arm: Add new-in-v8M SFSR and SFAR
45
target/arm: Update excret sanity checks for v8M
46
target/arm: Add support for restoring v8M additional state context
47
target/arm: Add v8M support to exception entry code
48
nvic: Implement Security Attribution Unit registers
49
target/arm: Implement security attribute lookups for memory accesses
50
target/arm: Fix calculation of secure mm_idx values
51
target/arm: Factor out "get mmuidx for specified security state"
52
nvic: Add missing code for writing SHCSR.HARDFAULTPENDED bit
53
58
54
Thomas Huth (1):
59
Nicolin Chen (1):
55
hw/arm/xlnx-zynqmp: Mark the "xlnx, zynqmp" device with user_creatable = false
60
hw/arm/smmuv3: Fill u.f_cd_fetch.addr for SMMU_EVT_F_CD_FETCH
56
61
57
target/arm/cpu.h | 60 ++++-
62
Peter Maydell (22):
58
target/arm/internals.h | 15 ++
63
monitor/hmp-cmds.c: Clean up hmp_dumpdtb printf
59
hw/arm/xlnx-zynqmp.c | 2 +
64
hw/openrisc: Support monitor dumpdtb command
60
hw/intc/armv7m_nvic.c | 158 ++++++++++-
65
hw/mips/boston: Check for error return from boston_fdt_filter()
61
hw/sd/sd.c | 12 +-
66
hw/mips/boston: Support dumpdtb monitor commands
62
target/arm/cpu.c | 27 ++
67
hw: Centralize handling of -machine dumpdtb option
63
target/arm/helper.c | 691 +++++++++++++++++++++++++++++++++++++++++++------
68
hw/core/machine.c: Make -machine dumpdtb=file.dtb with no DTB an error
64
target/arm/machine.c | 16 ++
69
fpu: Make targets specify floatx80 default Inf at runtime
65
target/arm/op_helper.c | 27 +-
70
target/m68k: Avoid using floatx80_infinity global const
66
9 files changed, 898 insertions(+), 110 deletions(-)
71
target/i386: Avoid using floatx80_infinity global const
72
fpu: Pass float_status to floatx80_is_infinity()
73
fpu: Make targets specify whether floatx80 Inf can have Int bit clear
74
fpu: Pass float_status to floatx80_invalid_encoding()
75
fpu: Make floatx80 invalid encoding settable at runtime
76
fpu: Move m68k_denormal fmt flag into floatx80_behaviour
77
fpu: Always decide no_signaling_nans() at runtime
78
fpu: Always decide snan_bit_is_one() at runtime
79
fpu: Don't compile-time disable hardfloat for PPC targets
80
fpu: Build only once
81
target/arm: Move TCG-only VFP code into tcg/ subdir
82
target/arm: Move FPSCR get/set helpers to tcg/vfp_helper.c
83
target/arm: Move softfloat specific FPCR/FPSR handling to tcg/
84
target/arm: Rename vfp_helper.c to vfp_fpscr.c
67
85
86
Pierrick Bouvier (1):
87
hw/misc/npcm_clk: fix buffer-overflow
88
89
MAINTAINERS | 13 +
90
docs/system/arm/imx8mp-evk.rst | 70 ++++
91
docs/system/arm/virt.rst | 4 +
92
docs/system/target-arm.rst | 1 +
93
include/fpu/softfloat-helpers.h | 12 +
94
include/fpu/softfloat-types.h | 51 +++
95
include/fpu/softfloat.h | 91 ++---
96
include/hw/arm/fsl-imx8mp.h | 284 ++++++++++++++
97
include/hw/loader-fit.h | 21 +-
98
include/hw/misc/imx8mp_analog.h | 81 ++++
99
include/hw/misc/imx8mp_ccm.h | 30 ++
100
include/hw/openrisc/boot.h | 3 +-
101
include/hw/pci-host/designware.h | 7 +
102
include/hw/pci-host/fsl_imx8m_phy.h | 28 ++
103
include/hw/timer/imx_gpt.h | 1 +
104
include/hw/usb/hcd-dwc3.h | 2 +-
105
include/system/device_tree.h | 2 -
106
target/arm/internals.h | 9 +
107
fpu/softfloat.c | 23 +-
108
hw/arm/boot.c | 2 -
109
hw/arm/fsl-imx8mp.c | 714 ++++++++++++++++++++++++++++++++++++
110
hw/arm/imx8mp-evk.c | 74 ++++
111
hw/arm/smmuv3.c | 2 +-
112
hw/arm/virt.c | 52 ++-
113
hw/core/loader-fit.c | 38 +-
114
hw/core/machine.c | 23 ++
115
hw/loongarch/virt-fdt-build.c | 1 -
116
hw/mips/boston.c | 16 +-
117
hw/misc/imx8mp_analog.c | 160 ++++++++
118
hw/misc/imx8mp_ccm.c | 175 +++++++++
119
hw/misc/npcm_clk.c | 5 +-
120
hw/openrisc/boot.c | 8 +-
121
hw/openrisc/openrisc_sim.c | 2 +-
122
hw/openrisc/virt.c | 2 +-
123
hw/pci-host/designware.c | 18 +-
124
hw/pci-host/fsl_imx8m_phy.c | 98 +++++
125
hw/ppc/e500.c | 1 -
126
hw/ppc/pegasos2.c | 1 -
127
hw/ppc/pnv.c | 1 -
128
hw/ppc/spapr.c | 1 -
129
hw/riscv/boot.c | 2 -
130
hw/timer/imx_gpt.c | 25 ++
131
hw/usb/hcd-dwc3.c | 5 +
132
monitor/hmp-cmds.c | 2 +-
133
system/device_tree-stub.c | 5 +-
134
system/device_tree.c | 22 +-
135
target/arm/hvf/hvf.c | 16 +
136
target/arm/tcg-stubs.c | 22 ++
137
target/arm/{ => tcg}/vfp_helper.c | 189 +---------
138
target/arm/vfp_fpscr.c | 155 ++++++++
139
target/hppa/fpu_helper.c | 1 +
140
target/i386/tcg/fpu_helper.c | 51 +--
141
target/m68k/cpu.c | 35 ++
142
target/m68k/fpu_helper.c | 2 +-
143
target/m68k/softfloat.c | 47 +--
144
target/sh4/cpu.c | 1 +
145
fpu/softfloat-parts.c.inc | 27 +-
146
fpu/softfloat-specialize.c.inc | 29 +-
147
fpu/meson.build | 2 +-
148
hw/arm/Kconfig | 24 ++
149
hw/arm/meson.build | 2 +
150
hw/gpio/Kconfig | 8 +
151
hw/misc/Kconfig | 14 +-
152
hw/misc/meson.build | 2 +
153
hw/pci-host/Kconfig | 3 +
154
hw/pci-host/meson.build | 1 +
155
target/arm/meson.build | 2 +-
156
target/arm/tcg/meson.build | 1 +
157
68 files changed, 2439 insertions(+), 383 deletions(-)
158
create mode 100644 docs/system/arm/imx8mp-evk.rst
159
create mode 100644 include/hw/arm/fsl-imx8mp.h
160
create mode 100644 include/hw/misc/imx8mp_analog.h
161
create mode 100644 include/hw/misc/imx8mp_ccm.h
162
create mode 100644 include/hw/pci-host/fsl_imx8m_phy.h
163
create mode 100644 hw/arm/fsl-imx8mp.c
164
create mode 100644 hw/arm/imx8mp-evk.c
165
create mode 100644 hw/misc/imx8mp_analog.c
166
create mode 100644 hw/misc/imx8mp_ccm.c
167
create mode 100644 hw/pci-host/fsl_imx8m_phy.c
168
rename target/arm/{ => tcg}/vfp_helper.c (90%)
169
create mode 100644 target/arm/vfp_fpscr.c
diff view generated by jsdifflib
New patch
1
From: Nicolin Chen <nicolinc@nvidia.com>
1
2
3
When we fill in the SMMUEventInfo for SMMU_EVT_F_CD_FETCH we write
4
the address into the f_ste_fetch member of the union, but then when
5
we come to read it back in smmuv3_record_event() we will (correctly)
6
be using the f_cd_fetch member.
7
8
This is more like a cosmetics fix since the f_cd_fetch and f_ste_fetch are
9
basically the same field since they are in the exact same union with exact
10
same type, but it's conceptually wrong. Use the correct union member.
11
12
Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
13
Message-id: 20250220213832.80289-1-nicolinc@nvidia.com
14
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
---
17
hw/arm/smmuv3.c | 2 +-
18
1 file changed, 1 insertion(+), 1 deletion(-)
19
20
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
21
index XXXXXXX..XXXXXXX 100644
22
--- a/hw/arm/smmuv3.c
23
+++ b/hw/arm/smmuv3.c
24
@@ -XXX,XX +XXX,XX @@ static int smmu_get_cd(SMMUv3State *s, STE *ste, SMMUTransCfg *cfg,
25
qemu_log_mask(LOG_GUEST_ERROR,
26
"Cannot fetch pte at address=0x%"PRIx64"\n", addr);
27
event->type = SMMU_EVT_F_CD_FETCH;
28
- event->u.f_ste_fetch.addr = addr;
29
+ event->u.f_cd_fetch.addr = addr;
30
return -EINVAL;
31
}
32
for (i = 0; i < ARRAY_SIZE(buf->word); i++) {
33
--
34
2.43.0
diff view generated by jsdifflib
New patch
1
From: "Matthew R. Ochs" <mochs@nvidia.com>
1
2
3
The MMIO region size required to support virtualized environments with
4
large PCI BAR regions can exceed the hardcoded limit configured in QEMU.
5
For example, a VM with multiple NVIDIA Grace-Hopper GPUs passed through
6
requires more MMIO memory than the amount provided by VIRT_HIGH_PCIE_MMIO
7
(currently 512GB). Instead of updating VIRT_HIGH_PCIE_MMIO, introduce a
8
new parameter, highmem-mmio-size, that specifies the MMIO size required
9
to support the VM configuration.
10
11
Example usage with 1TB MMIO region size:
12
    -machine virt,gic-version=3,highmem-mmio-size=1T
13
14
Signed-off-by: Matthew R. Ochs <mochs@nvidia.com>
15
Reviewed-by: Gavin Shan <gshan@redhat.com>
16
Reviewed-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
17
Reviewed-by: Eric Auger <eric.auger@redhat.com>
18
Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
19
Message-id: 20250221145419.1281890-1-mochs@nvidia.com
20
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
21
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
22
---
23
docs/system/arm/virt.rst | 4 ++++
24
hw/arm/virt.c | 52 +++++++++++++++++++++++++++++++++++++++-
25
2 files changed, 55 insertions(+), 1 deletion(-)
26
27
diff --git a/docs/system/arm/virt.rst b/docs/system/arm/virt.rst
28
index XXXXXXX..XXXXXXX 100644
29
--- a/docs/system/arm/virt.rst
30
+++ b/docs/system/arm/virt.rst
31
@@ -XXX,XX +XXX,XX @@ highmem-mmio
32
Set ``on``/``off`` to enable/disable the high memory region for PCI MMIO.
33
The default is ``on``.
34
35
+highmem-mmio-size
36
+ Set the high memory region size for PCI MMIO. Must be a power of 2 and
37
+ greater than or equal to the default size (512G).
38
+
39
gic-version
40
Specify the version of the Generic Interrupt Controller (GIC) to provide.
41
Valid values are:
42
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
43
index XXXXXXX..XXXXXXX 100644
44
--- a/hw/arm/virt.c
45
+++ b/hw/arm/virt.c
46
@@ -XXX,XX +XXX,XX @@
47
#include "hw/loader.h"
48
#include "qapi/error.h"
49
#include "qemu/bitops.h"
50
+#include "qemu/cutils.h"
51
#include "qemu/error-report.h"
52
#include "qemu/module.h"
53
#include "hw/pci-host/gpex.h"
54
@@ -XXX,XX +XXX,XX @@ static const MemMapEntry base_memmap[] = {
55
[VIRT_MEM] = { GiB, LEGACY_RAMLIMIT_BYTES },
56
};
57
58
+/* Update the docs for highmem-mmio-size when changing this default */
59
+#define DEFAULT_HIGH_PCIE_MMIO_SIZE_GB 512
60
+#define DEFAULT_HIGH_PCIE_MMIO_SIZE (DEFAULT_HIGH_PCIE_MMIO_SIZE_GB * GiB)
61
+
62
/*
63
* Highmem IO Regions: This memory map is floating, located after the RAM.
64
* Each MemMapEntry base (GPA) will be dynamically computed, depending on the
65
@@ -XXX,XX +XXX,XX @@ static const MemMapEntry base_memmap[] = {
66
* PA space for one specific region is always reserved, even if the region
67
* has been disabled or doesn't fit into the PA space. However, the PA space
68
* for the region won't be reserved in these circumstances with compact layout.
69
+ *
70
+ * Note that the highmem-mmio-size property will update the high PCIE MMIO size
71
+ * field in this array.
72
*/
73
static MemMapEntry extended_memmap[] = {
74
/* Additional 64 MB redist region (can contain up to 512 redistributors) */
75
[VIRT_HIGH_GIC_REDIST2] = { 0x0, 64 * MiB },
76
[VIRT_HIGH_PCIE_ECAM] = { 0x0, 256 * MiB },
77
/* Second PCIe window */
78
- [VIRT_HIGH_PCIE_MMIO] = { 0x0, 512 * GiB },
79
+ [VIRT_HIGH_PCIE_MMIO] = { 0x0, DEFAULT_HIGH_PCIE_MMIO_SIZE },
80
};
81
82
static const int a15irqmap[] = {
83
@@ -XXX,XX +XXX,XX @@ static void virt_set_highmem_mmio(Object *obj, bool value, Error **errp)
84
vms->highmem_mmio = value;
85
}
86
87
+static void virt_get_highmem_mmio_size(Object *obj, Visitor *v,
88
+ const char *name, void *opaque,
89
+ Error **errp)
90
+{
91
+ uint64_t size = extended_memmap[VIRT_HIGH_PCIE_MMIO].size;
92
+
93
+ visit_type_size(v, name, &size, errp);
94
+}
95
+
96
+static void virt_set_highmem_mmio_size(Object *obj, Visitor *v,
97
+ const char *name, void *opaque,
98
+ Error **errp)
99
+{
100
+ uint64_t size;
101
+
102
+ if (!visit_type_size(v, name, &size, errp)) {
103
+ return;
104
+ }
105
+
106
+ if (!is_power_of_2(size)) {
107
+ error_setg(errp, "highmem-mmio-size is not a power of 2");
108
+ return;
109
+ }
110
+
111
+ if (size < DEFAULT_HIGH_PCIE_MMIO_SIZE) {
112
+ char *sz = size_to_str(DEFAULT_HIGH_PCIE_MMIO_SIZE);
113
+ error_setg(errp, "highmem-mmio-size cannot be set to a lower value "
114
+ "than the default (%s)", sz);
115
+ g_free(sz);
116
+ return;
117
+ }
118
+
119
+ extended_memmap[VIRT_HIGH_PCIE_MMIO].size = size;
120
+}
121
122
static bool virt_get_its(Object *obj, Error **errp)
123
{
124
@@ -XXX,XX +XXX,XX @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
125
"Set on/off to enable/disable high "
126
"memory region for PCI MMIO");
127
128
+ object_class_property_add(oc, "highmem-mmio-size", "size",
129
+ virt_get_highmem_mmio_size,
130
+ virt_set_highmem_mmio_size,
131
+ NULL, NULL);
132
+ object_class_property_set_description(oc, "highmem-mmio-size",
133
+ "Set the high memory region size "
134
+ "for PCI MMIO");
135
+
136
object_class_property_add_str(oc, "gic-version", virt_get_gic_version,
137
virt_set_gic_version);
138
object_class_property_set_description(oc, "gic-version",
139
--
140
2.43.0
diff view generated by jsdifflib
1
For v8M, exceptions from Secure to Non-Secure state will save
1
In hmp_dumpdtb(), we print a message when the command succeeds. This
2
callee-saved registers to the exception frame as well as the
2
message is missing the trailing \n, so the HMP command prompt is
3
caller-saved registers. Add support for unstacking these
3
printed immediately after it. We also weren't capitalizing 'DTB', or
4
registers in exception exit when necessary.
4
quoting the filename in the message. Fix these nits.
5
5
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 1506092407-26985-12-git-send-email-peter.maydell@linaro.org
8
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
9
Message-id: 20250206151214.2947842-2-peter.maydell@linaro.org
9
---
10
---
10
target/arm/helper.c | 30 ++++++++++++++++++++++++++++++
11
monitor/hmp-cmds.c | 2 +-
11
1 file changed, 30 insertions(+)
12
1 file changed, 1 insertion(+), 1 deletion(-)
12
13
13
diff --git a/target/arm/helper.c b/target/arm/helper.c
14
diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
14
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
15
--- a/target/arm/helper.c
16
--- a/monitor/hmp-cmds.c
16
+++ b/target/arm/helper.c
17
+++ b/monitor/hmp-cmds.c
17
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
18
@@ -XXX,XX +XXX,XX @@ void hmp_dumpdtb(Monitor *mon, const QDict *qdict)
18
"for destination state is UNPREDICTABLE\n");
19
return;
19
}
20
}
20
21
21
+ /* Do we need to pop callee-saved registers? */
22
- monitor_printf(mon, "dtb dumped to %s", filename);
22
+ if (return_to_secure &&
23
+ monitor_printf(mon, "DTB dumped to '%s'\n", filename);
23
+ ((excret & R_V7M_EXCRET_ES_MASK) == 0 ||
24
}
24
+ (excret & R_V7M_EXCRET_DCRS_MASK) == 0)) {
25
#endif
25
+ uint32_t expected_sig = 0xfefa125b;
26
+ uint32_t actual_sig = ldl_phys(cs->as, frameptr);
27
+
28
+ if (expected_sig != actual_sig) {
29
+ /* Take a SecureFault on the current stack */
30
+ env->v7m.sfsr |= R_V7M_SFSR_INVIS_MASK;
31
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
32
+ v7m_exception_taken(cpu, excret);
33
+ qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on existing "
34
+ "stackframe: failed exception return integrity "
35
+ "signature check\n");
36
+ return;
37
+ }
38
+
39
+ env->regs[4] = ldl_phys(cs->as, frameptr + 0x8);
40
+ env->regs[5] = ldl_phys(cs->as, frameptr + 0xc);
41
+ env->regs[6] = ldl_phys(cs->as, frameptr + 0x10);
42
+ env->regs[7] = ldl_phys(cs->as, frameptr + 0x14);
43
+ env->regs[8] = ldl_phys(cs->as, frameptr + 0x18);
44
+ env->regs[9] = ldl_phys(cs->as, frameptr + 0x1c);
45
+ env->regs[10] = ldl_phys(cs->as, frameptr + 0x20);
46
+ env->regs[11] = ldl_phys(cs->as, frameptr + 0x24);
47
+
48
+ frameptr += 0x28;
49
+ }
50
+
51
/* Pop registers. TODO: make these accesses use the correct
52
* attributes and address space (S/NS, priv/unpriv) and handle
53
* memory transaction failures.
54
--
26
--
55
2.7.4
27
2.43.0
56
28
57
29
diff view generated by jsdifflib
1
Add the new M profile Secure Fault Status Register
1
The openrisc machines don't set MachineState::fdt to point to their
2
and Secure Fault Address Register.
2
DTB blob. This means that although the command line '-machine
3
dumpdtb=file.dtb' option works, the equivalent QMP and HMP monitor
4
commands do not, but instead produce the error "This machine doesn't
5
have a FDT".
6
7
Set MachineState::fdt in openrisc_load_fdt(), when we write it to
8
guest memory.
3
9
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
11
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 1506092407-26985-10-git-send-email-peter.maydell@linaro.org
12
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
13
Message-id: 20250206151214.2947842-3-peter.maydell@linaro.org
7
---
14
---
8
target/arm/cpu.h | 12 ++++++++++++
15
include/hw/openrisc/boot.h | 3 ++-
9
hw/intc/armv7m_nvic.c | 34 ++++++++++++++++++++++++++++++++++
16
hw/openrisc/boot.c | 7 +++++--
10
target/arm/machine.c | 2 ++
17
hw/openrisc/openrisc_sim.c | 2 +-
11
3 files changed, 48 insertions(+)
18
hw/openrisc/virt.c | 2 +-
19
4 files changed, 9 insertions(+), 5 deletions(-)
12
20
13
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
21
diff --git a/include/hw/openrisc/boot.h b/include/hw/openrisc/boot.h
14
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
15
--- a/target/arm/cpu.h
23
--- a/include/hw/openrisc/boot.h
16
+++ b/target/arm/cpu.h
24
+++ b/include/hw/openrisc/boot.h
17
@@ -XXX,XX +XXX,XX @@ typedef struct CPUARMState {
25
@@ -XXX,XX +XXX,XX @@
18
uint32_t cfsr[M_REG_NUM_BANKS]; /* Configurable Fault Status */
26
#define OPENRISC_BOOT_H
19
uint32_t hfsr; /* HardFault Status */
27
20
uint32_t dfsr; /* Debug Fault Status Register */
28
#include "exec/cpu-defs.h"
21
+ uint32_t sfsr; /* Secure Fault Status Register */
29
+#include "hw/boards.h"
22
uint32_t mmfar[M_REG_NUM_BANKS]; /* MemManage Fault Address */
30
23
uint32_t bfar; /* BusFault Address */
31
hwaddr openrisc_load_kernel(ram_addr_t ram_size,
24
+ uint32_t sfar; /* Secure Fault Address Register */
32
const char *kernel_filename,
25
unsigned mpu_ctrl[M_REG_NUM_BANKS]; /* MPU_CTRL */
33
@@ -XXX,XX +XXX,XX @@ hwaddr openrisc_load_kernel(ram_addr_t ram_size,
26
int exception;
34
hwaddr openrisc_load_initrd(void *fdt, const char *filename,
27
uint32_t primask[M_REG_NUM_BANKS];
35
hwaddr load_start, uint64_t mem_size);
28
@@ -XXX,XX +XXX,XX @@ FIELD(V7M_DFSR, DWTTRAP, 2, 1)
36
29
FIELD(V7M_DFSR, VCATCH, 3, 1)
37
-uint32_t openrisc_load_fdt(void *fdt, hwaddr load_start,
30
FIELD(V7M_DFSR, EXTERNAL, 4, 1)
38
+uint32_t openrisc_load_fdt(MachineState *ms, void *fdt, hwaddr load_start,
31
39
uint64_t mem_size);
32
+/* V7M SFSR bits */
40
33
+FIELD(V7M_SFSR, INVEP, 0, 1)
41
#endif /* OPENRISC_BOOT_H */
34
+FIELD(V7M_SFSR, INVIS, 1, 1)
42
diff --git a/hw/openrisc/boot.c b/hw/openrisc/boot.c
35
+FIELD(V7M_SFSR, INVER, 2, 1)
43
index XXXXXXX..XXXXXXX 100644
36
+FIELD(V7M_SFSR, AUVIOL, 3, 1)
44
--- a/hw/openrisc/boot.c
37
+FIELD(V7M_SFSR, INVTRAN, 4, 1)
45
+++ b/hw/openrisc/boot.c
38
+FIELD(V7M_SFSR, LSPERR, 5, 1)
46
@@ -XXX,XX +XXX,XX @@ hwaddr openrisc_load_initrd(void *fdt, const char *filename,
39
+FIELD(V7M_SFSR, SFARVALID, 6, 1)
47
return start + size;
40
+FIELD(V7M_SFSR, LSERR, 7, 1)
48
}
49
50
-uint32_t openrisc_load_fdt(void *fdt, hwaddr load_start,
51
- uint64_t mem_size)
52
+uint32_t openrisc_load_fdt(MachineState *ms, void *fdt,
53
+ hwaddr load_start, uint64_t mem_size)
54
{
55
uint32_t fdt_addr;
56
int ret;
57
@@ -XXX,XX +XXX,XX @@ uint32_t openrisc_load_fdt(void *fdt, hwaddr load_start,
58
/* copy in the device tree */
59
qemu_fdt_dumpdtb(fdt, fdtsize);
60
61
+ /* Save FDT for dumpdtb monitor command */
62
+ ms->fdt = fdt;
41
+
63
+
42
/* v7M MPU_CTRL bits */
64
rom_add_blob_fixed_as("fdt", fdt, fdtsize, fdt_addr,
43
FIELD(V7M_MPU_CTRL, ENABLE, 0, 1)
65
&address_space_memory);
44
FIELD(V7M_MPU_CTRL, HFNMIENA, 1, 1)
66
qemu_register_reset_nosnapshotload(qemu_fdt_randomize_seeds,
45
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
67
diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c
46
index XXXXXXX..XXXXXXX 100644
68
index XXXXXXX..XXXXXXX 100644
47
--- a/hw/intc/armv7m_nvic.c
69
--- a/hw/openrisc/openrisc_sim.c
48
+++ b/hw/intc/armv7m_nvic.c
70
+++ b/hw/openrisc/openrisc_sim.c
49
@@ -XXX,XX +XXX,XX @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs)
71
@@ -XXX,XX +XXX,XX @@ static void openrisc_sim_init(MachineState *machine)
50
goto bad_offset;
72
machine->initrd_filename,
73
load_addr, machine->ram_size);
51
}
74
}
52
return cpu->env.pmsav8.mair1[attrs.secure];
75
- boot_info.fdt_addr = openrisc_load_fdt(state->fdt, load_addr,
53
+ case 0xde4: /* SFSR */
76
+ boot_info.fdt_addr = openrisc_load_fdt(machine, state->fdt, load_addr,
54
+ if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
77
machine->ram_size);
55
+ goto bad_offset;
78
}
56
+ }
79
}
57
+ if (!attrs.secure) {
80
diff --git a/hw/openrisc/virt.c b/hw/openrisc/virt.c
58
+ return 0;
59
+ }
60
+ return cpu->env.v7m.sfsr;
61
+ case 0xde8: /* SFAR */
62
+ if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
63
+ goto bad_offset;
64
+ }
65
+ if (!attrs.secure) {
66
+ return 0;
67
+ }
68
+ return cpu->env.v7m.sfar;
69
default:
70
bad_offset:
71
qemu_log_mask(LOG_GUEST_ERROR, "NVIC: Bad read offset 0x%x\n", offset);
72
@@ -XXX,XX +XXX,XX @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value,
73
* only affect cacheability, and we don't implement caching.
74
*/
75
break;
76
+ case 0xde4: /* SFSR */
77
+ if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
78
+ goto bad_offset;
79
+ }
80
+ if (!attrs.secure) {
81
+ return;
82
+ }
83
+ cpu->env.v7m.sfsr &= ~value; /* W1C */
84
+ break;
85
+ case 0xde8: /* SFAR */
86
+ if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
87
+ goto bad_offset;
88
+ }
89
+ if (!attrs.secure) {
90
+ return;
91
+ }
92
+ cpu->env.v7m.sfsr = value;
93
+ break;
94
case 0xf00: /* Software Triggered Interrupt Register */
95
{
96
int excnum = (value & 0x1ff) + NVIC_FIRST_IRQ;
97
diff --git a/target/arm/machine.c b/target/arm/machine.c
98
index XXXXXXX..XXXXXXX 100644
81
index XXXXXXX..XXXXXXX 100644
99
--- a/target/arm/machine.c
82
--- a/hw/openrisc/virt.c
100
+++ b/target/arm/machine.c
83
+++ b/hw/openrisc/virt.c
101
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_m_security = {
84
@@ -XXX,XX +XXX,XX @@ static void openrisc_virt_init(MachineState *machine)
102
VMSTATE_UINT32(env.v7m.ccr[M_REG_S], ARMCPU),
85
machine->initrd_filename,
103
VMSTATE_UINT32(env.v7m.mmfar[M_REG_S], ARMCPU),
86
load_addr, machine->ram_size);
104
VMSTATE_UINT32(env.v7m.cfsr[M_REG_S], ARMCPU),
87
}
105
+ VMSTATE_UINT32(env.v7m.sfsr, ARMCPU),
88
- boot_info.fdt_addr = openrisc_load_fdt(state->fdt, load_addr,
106
+ VMSTATE_UINT32(env.v7m.sfar, ARMCPU),
89
+ boot_info.fdt_addr = openrisc_load_fdt(machine, state->fdt, load_addr,
107
VMSTATE_END_OF_LIST()
90
machine->ram_size);
108
}
91
}
109
};
92
}
110
--
93
--
111
2.7.4
94
2.43.0
112
95
113
96
diff view generated by jsdifflib
1
ARM v8M specifies that the INVPC usage fault for mismatched
1
The function boston_fdt_filter() can return NULL on errors (in which
2
xPSR exception field and handler mode bit should be checked
2
case it will print an error message). When we call this from the
3
before updating the PSR and SP, so that the fault is taken
3
non-FIT-image codepath, we aren't checking the return value, so we
4
with the existing stack frame rather than by pushing a new one.
4
will plough on with a NULL pointer, and segfault in fdt_totalsize().
5
Perform this check in the right place for v8M.
5
Check for errors here.
6
7
Since v7M specifies in its pseudocode that this usage fault
8
check should happen later, we have to retain the original
9
code for that check rather than being able to merge the two.
10
(The distinction is architecturally visible but only in
11
very obscure corner cases like attempting an invalid exception
12
return with an exception frame in read only memory.)
13
6
14
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
16
Message-id: 1506092407-26985-7-git-send-email-peter.maydell@linaro.org
9
Message-id: 20250206151214.2947842-4-peter.maydell@linaro.org
17
---
10
---
18
target/arm/helper.c | 30 +++++++++++++++++++++++++++---
11
hw/mips/boston.c | 4 ++++
19
1 file changed, 27 insertions(+), 3 deletions(-)
12
1 file changed, 4 insertions(+)
20
13
21
diff --git a/target/arm/helper.c b/target/arm/helper.c
14
diff --git a/hw/mips/boston.c b/hw/mips/boston.c
22
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
23
--- a/target/arm/helper.c
16
--- a/hw/mips/boston.c
24
+++ b/target/arm/helper.c
17
+++ b/hw/mips/boston.c
25
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
18
@@ -XXX,XX +XXX,XX @@ static void boston_mach_init(MachineState *machine)
26
}
19
27
xpsr = ldl_phys(cs->as, frameptr + 0x1c);
20
dtb_load_data = boston_fdt_filter(s, dtb_file_data,
28
21
NULL, &dtb_vaddr);
29
+ if (arm_feature(env, ARM_FEATURE_V8)) {
22
+ if (!dtb_load_data) {
30
+ /* For v8M we have to check whether the xPSR exception field
23
+ /* boston_fdt_filter() already printed the error for us */
31
+ * matches the EXCRET value for return to handler/thread
24
+ exit(1);
32
+ * before we commit to changing the SP and xPSR.
33
+ */
34
+ bool will_be_handler = (xpsr & XPSR_EXCP) != 0;
35
+ if (return_to_handler != will_be_handler) {
36
+ /* Take an INVPC UsageFault on the current stack.
37
+ * By this point we will have switched to the security state
38
+ * for the background state, so this UsageFault will target
39
+ * that state.
40
+ */
41
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
42
+ env->v7m.secure);
43
+ env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
44
+ v7m_exception_taken(cpu, excret);
45
+ qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on existing "
46
+ "stackframe: failed exception return integrity "
47
+ "check\n");
48
+ return;
49
+ }
25
+ }
50
+ }
26
51
+
27
/* Calculate real fdt size after filter */
52
/* Commit to consuming the stack frame */
28
dt_size = fdt_totalsize(dtb_load_data);
53
frameptr += 0x20;
54
/* Undo stack alignment (the SPREALIGN bit indicates that the original
55
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
56
/* The restored xPSR exception field will be zero if we're
57
* resuming in Thread mode. If that doesn't match what the
58
* exception return excret specified then this is a UsageFault.
59
+ * v7M requires we make this check here; v8M did it earlier.
60
*/
61
if (return_to_handler != arm_v7m_is_handler_mode(env)) {
62
- /* Take an INVPC UsageFault by pushing the stack again.
63
- * TODO: the v8M version of this code should target the
64
- * background state for this exception.
65
+ /* Take an INVPC UsageFault by pushing the stack again;
66
+ * we know we're v7M so this is never a Secure UsageFault.
67
*/
68
+ assert(!arm_feature(env, ARM_FEATURE_V8));
69
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, false);
70
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
71
v7m_push_stack(cpu);
72
--
29
--
73
2.7.4
30
2.43.0
74
31
75
32
diff view generated by jsdifflib
New patch
1
1
The boston machine doesn't set MachineState::fdt to the DTB blob that
2
it has loaded or created, which means that the QMP/HMP dumpdtb
3
monitor commands don't work.
4
5
Setting MachineState::fdt is easy in the non-FIT codepath: we can
6
simply do so immediately before loading the DTB into guest memory.
7
The FIT codepath is a bit more awkward as currently the FIT loader
8
throws away the memory that the FDT was in after it loads it into
9
guest memory. So we add a void *pfdt argument to load_fit() for it
10
to store the FDT pointer into.
11
12
There is some readjustment required of the pointer handling in
13
loader-fit.c, so that it applies 'const' only where it should (e.g.
14
the data pointer we get back from fdt_getprop() is const, because
15
it's into the middle of the input FDT data, but the pointer that
16
fit_load_image_alloc() should not be const, because it's freshly
17
allocated memory that the caller can change if it likes).
18
19
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
20
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
21
Message-id: 20250206151214.2947842-5-peter.maydell@linaro.org
22
---
23
include/hw/loader-fit.h | 21 ++++++++++++++++++---
24
hw/core/loader-fit.c | 38 +++++++++++++++++++++-----------------
25
hw/mips/boston.c | 11 +++++++----
26
3 files changed, 46 insertions(+), 24 deletions(-)
27
28
diff --git a/include/hw/loader-fit.h b/include/hw/loader-fit.h
29
index XXXXXXX..XXXXXXX 100644
30
--- a/include/hw/loader-fit.h
31
+++ b/include/hw/loader-fit.h
32
@@ -XXX,XX +XXX,XX @@ struct fit_loader_match {
33
struct fit_loader {
34
const struct fit_loader_match *matches;
35
hwaddr (*addr_to_phys)(void *opaque, uint64_t addr);
36
- const void *(*fdt_filter)(void *opaque, const void *fdt,
37
- const void *match_data, hwaddr *load_addr);
38
+ void *(*fdt_filter)(void *opaque, const void *fdt,
39
+ const void *match_data, hwaddr *load_addr);
40
const void *(*kernel_filter)(void *opaque, const void *kernel,
41
hwaddr *load_addr, hwaddr *entry_addr);
42
};
43
44
-int load_fit(const struct fit_loader *ldr, const char *filename, void *opaque);
45
+/**
46
+ * load_fit: load a FIT format image
47
+ * @ldr: structure defining board specific properties and hooks
48
+ * @filename: image to load
49
+ * @pfdt: pointer to update with address of FDT blob
50
+ * @opaque: opaque value passed back to the hook functions in @ldr
51
+ * Returns: 0 on success, or a negative errno on failure
52
+ *
53
+ * @pfdt is used to tell the caller about the FDT blob. On return, it
54
+ * has been set to point to the FDT blob, and it is now the caller's
55
+ * responsibility to free that memory with g_free(). Usually the caller
56
+ * will want to pass in &machine->fdt here, to record the FDT blob for
57
+ * the dumpdtb option and QMP/HMP commands.
58
+ */
59
+int load_fit(const struct fit_loader *ldr, const char *filename, void **pfdt,
60
+ void *opaque);
61
62
#endif /* HW_LOADER_FIT_H */
63
diff --git a/hw/core/loader-fit.c b/hw/core/loader-fit.c
64
index XXXXXXX..XXXXXXX 100644
65
--- a/hw/core/loader-fit.c
66
+++ b/hw/core/loader-fit.c
67
@@ -XXX,XX +XXX,XX @@
68
69
#define FIT_LOADER_MAX_PATH (128)
70
71
-static const void *fit_load_image_alloc(const void *itb, const char *name,
72
- int *poff, size_t *psz, Error **errp)
73
+static void *fit_load_image_alloc(const void *itb, const char *name,
74
+ int *poff, size_t *psz, Error **errp)
75
{
76
const void *data;
77
const char *comp;
78
@@ -XXX,XX +XXX,XX @@ static const void *fit_load_image_alloc(const void *itb, const char *name,
79
return NULL;
80
}
81
82
- data = g_realloc(uncomp_data, uncomp_len);
83
+ uncomp_data = g_realloc(uncomp_data, uncomp_len);
84
if (psz) {
85
*psz = uncomp_len;
86
}
87
- return data;
88
+ return uncomp_data;
89
}
90
91
error_setg(errp, "unknown compression '%s'", comp);
92
@@ -XXX,XX +XXX,XX @@ out:
93
94
static int fit_load_fdt(const struct fit_loader *ldr, const void *itb,
95
int cfg, void *opaque, const void *match_data,
96
- hwaddr kernel_end, Error **errp)
97
+ hwaddr kernel_end, void **pfdt, Error **errp)
98
{
99
ERRP_GUARD();
100
Error *err = NULL;
101
const char *name;
102
- const void *data;
103
- const void *load_data;
104
+ void *data;
105
hwaddr load_addr;
106
int img_off;
107
size_t sz;
108
@@ -XXX,XX +XXX,XX @@ static int fit_load_fdt(const struct fit_loader *ldr, const void *itb,
109
return 0;
110
}
111
112
- load_data = data = fit_load_image_alloc(itb, name, &img_off, &sz, errp);
113
+ data = fit_load_image_alloc(itb, name, &img_off, &sz, errp);
114
if (!data) {
115
error_prepend(errp, "unable to load FDT image from FIT: ");
116
return -EINVAL;
117
@@ -XXX,XX +XXX,XX @@ static int fit_load_fdt(const struct fit_loader *ldr, const void *itb,
118
}
119
120
if (ldr->fdt_filter) {
121
- load_data = ldr->fdt_filter(opaque, data, match_data, &load_addr);
122
+ void *filtered_data;
123
+
124
+ filtered_data = ldr->fdt_filter(opaque, data, match_data, &load_addr);
125
+ if (filtered_data != data) {
126
+ g_free(data);
127
+ data = filtered_data;
128
+ }
129
}
130
131
load_addr = ldr->addr_to_phys(opaque, load_addr);
132
- sz = fdt_totalsize(load_data);
133
- rom_add_blob_fixed(name, load_data, sz, load_addr);
134
+ sz = fdt_totalsize(data);
135
+ rom_add_blob_fixed(name, data, sz, load_addr);
136
137
- ret = 0;
138
+ *pfdt = data;
139
+ return 0;
140
out:
141
g_free((void *) data);
142
- if (data != load_data) {
143
- g_free((void *) load_data);
144
- }
145
return ret;
146
}
147
148
@@ -XXX,XX +XXX,XX @@ out:
149
return ret;
150
}
151
152
-int load_fit(const struct fit_loader *ldr, const char *filename, void *opaque)
153
+int load_fit(const struct fit_loader *ldr, const char *filename,
154
+ void **pfdt, void *opaque)
155
{
156
Error *err = NULL;
157
const struct fit_loader_match *match;
158
@@ -XXX,XX +XXX,XX @@ int load_fit(const struct fit_loader *ldr, const char *filename, void *opaque)
159
goto out;
160
}
161
162
- ret = fit_load_fdt(ldr, itb, cfg_off, opaque, match_data, kernel_end,
163
+ ret = fit_load_fdt(ldr, itb, cfg_off, opaque, match_data, kernel_end, pfdt,
164
&err);
165
if (ret) {
166
error_report_err(err);
167
diff --git a/hw/mips/boston.c b/hw/mips/boston.c
168
index XXXXXXX..XXXXXXX 100644
169
--- a/hw/mips/boston.c
170
+++ b/hw/mips/boston.c
171
@@ -XXX,XX +XXX,XX @@ static void gen_firmware(void *p, hwaddr kernel_entry, hwaddr fdt_addr)
172
kernel_entry);
173
}
174
175
-static const void *boston_fdt_filter(void *opaque, const void *fdt_orig,
176
- const void *match_data, hwaddr *load_addr)
177
+static void *boston_fdt_filter(void *opaque, const void *fdt_orig,
178
+ const void *match_data, hwaddr *load_addr)
179
{
180
BostonState *s = BOSTON(opaque);
181
MachineState *machine = s->mach;
182
@@ -XXX,XX +XXX,XX @@ static void boston_mach_init(MachineState *machine)
183
if (kernel_size > 0) {
184
int dt_size;
185
g_autofree const void *dtb_file_data = NULL;
186
- g_autofree const void *dtb_load_data = NULL;
187
+ void *dtb_load_data = NULL;
188
hwaddr dtb_paddr = QEMU_ALIGN_UP(kernel_high, 64 * KiB);
189
hwaddr dtb_vaddr = cpu_mips_phys_to_kseg0(NULL, dtb_paddr);
190
191
@@ -XXX,XX +XXX,XX @@ static void boston_mach_init(MachineState *machine)
192
exit(1);
193
}
194
195
+ machine->fdt = dtb_load_data;
196
+
197
/* Calculate real fdt size after filter */
198
dt_size = fdt_totalsize(dtb_load_data);
199
rom_add_blob_fixed("dtb", dtb_load_data, dt_size, dtb_paddr);
200
@@ -XXX,XX +XXX,XX @@ static void boston_mach_init(MachineState *machine)
201
rom_ptr(dtb_paddr, dt_size));
202
} else {
203
/* Try to load file as FIT */
204
- fit_err = load_fit(&boston_fit_loader, machine->kernel_filename, s);
205
+ fit_err = load_fit(&boston_fit_loader, machine->kernel_filename,
206
+ &machine->fdt, s);
207
if (fit_err) {
208
error_report("unable to load kernel image");
209
exit(1);
210
--
211
2.43.0
212
213
diff view generated by jsdifflib
1
In the v7M architecture, there is an invariant that if the CPU is
1
Currently we handle the 'dumpdtb' machine sub-option ad-hoc in every
2
in Handler mode then the CONTROL.SPSEL bit cannot be nonzero.
2
board model that has an FDT. It's up to the board code to make sure
3
This in turn means that the current stack pointer is always
3
it calls qemu_fdt_dumpdtb() in the right place.
4
indicated by CONTROL.SPSEL, even though Handler mode always uses
4
5
the Main stack pointer.
5
This means we're inconsistent and often just ignore the user's
6
6
command line argument:
7
In v8M, this invariant is removed, and CONTROL.SPSEL may now
7
* if the board doesn't have an FDT at all
8
be nonzero in Handler mode (though Handler mode still always
8
* if the board supports FDT, but there happens not to be one
9
uses the Main stack pointer). In preparation for this change,
9
present (usually because of a missing -fdt option)
10
change how we handle this bit: rename switch_v7m_sp() to
10
11
the now more accurate write_v7m_control_spsel(), and make it
11
This isn't very helpful because it gives the user no clue why their
12
check both the handler mode state and the SPSEL bit.
12
option was ignored.
13
13
14
Note that this implicitly changes the point at which we switch
14
However, in order to support the QMP/HMP dumpdtb commands we require
15
active SP on exception exit from before we pop the exception
15
now that every FDT machine stores a pointer to the FDT in
16
frame to after it.
16
MachineState::fdt. This means we can handle -machine dumpdtb
17
centrally by calling the qmp_dumpdtb() function, unifying its
18
handling with the QMP/HMP commands. All the board code calls to
19
qemu_fdt_dumpdtb() can then be removed.
20
21
For this commit we retain the existing behaviour that if there
22
is no FDT we silently ignore the -machine dumpdtb option.
17
23
18
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
24
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
19
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
20
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
25
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
21
Message-id: 1506092407-26985-4-git-send-email-peter.maydell@linaro.org
22
---
26
---
23
target/arm/cpu.h | 8 ++++++-
27
include/system/device_tree.h | 2 --
24
hw/intc/armv7m_nvic.c | 2 +-
28
hw/arm/boot.c | 2 --
25
target/arm/helper.c | 65 ++++++++++++++++++++++++++++++++++-----------------
29
hw/core/machine.c | 25 +++++++++++++++++++++++++
26
3 files changed, 51 insertions(+), 24 deletions(-)
30
hw/loongarch/virt-fdt-build.c | 1 -
27
31
hw/mips/boston.c | 1 -
28
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
32
hw/openrisc/boot.c | 1 -
29
index XXXXXXX..XXXXXXX 100644
33
hw/ppc/e500.c | 1 -
30
--- a/target/arm/cpu.h
34
hw/ppc/pegasos2.c | 1 -
31
+++ b/target/arm/cpu.h
35
hw/ppc/pnv.c | 1 -
32
@@ -XXX,XX +XXX,XX @@ void pmccntr_sync(CPUARMState *env);
36
hw/ppc/spapr.c | 1 -
33
#define PSTATE_MODE_EL1t 4
37
hw/riscv/boot.c | 2 --
34
#define PSTATE_MODE_EL0t 0
38
system/device_tree.c | 15 ---------------
35
39
12 files changed, 25 insertions(+), 28 deletions(-)
36
+/* Write a new value to v7m.exception, thus transitioning into or out
40
37
+ * of Handler mode; this may result in a change of active stack pointer.
41
diff --git a/include/system/device_tree.h b/include/system/device_tree.h
38
+ */
42
index XXXXXXX..XXXXXXX 100644
39
+void write_v7m_exception(CPUARMState *env, uint32_t new_exc);
43
--- a/include/system/device_tree.h
40
+
44
+++ b/include/system/device_tree.h
41
/* Map EL and handler into a PSTATE_MODE. */
45
@@ -XXX,XX +XXX,XX @@ int qemu_fdt_add_path(void *fdt, const char *path);
42
static inline unsigned int aarch64_pstate_mode(unsigned int el, bool handler)
46
sizeof(qdt_tmp)); \
43
{
47
} while (0)
44
@@ -XXX,XX +XXX,XX @@ static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask)
48
45
env->condexec_bits |= (val >> 8) & 0xfc;
49
-void qemu_fdt_dumpdtb(void *fdt, int size);
50
-
51
/**
52
* qemu_fdt_setprop_sized_cells_from_array:
53
* @fdt: device tree blob
54
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
55
index XXXXXXX..XXXXXXX 100644
56
--- a/hw/arm/boot.c
57
+++ b/hw/arm/boot.c
58
@@ -XXX,XX +XXX,XX @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
59
binfo->modify_dtb(binfo, fdt);
46
}
60
}
47
if (mask & XPSR_EXCP) {
61
48
- env->v7m.exception = val & XPSR_EXCP;
62
- qemu_fdt_dumpdtb(fdt, size);
49
+ /* Note that this only happens on exception exit */
63
-
50
+ write_v7m_exception(env, val & XPSR_EXCP);
64
/* Put the DTB into the memory map as a ROM image: this will ensure
51
}
65
* the DTB is copied again upon reset, even if addr points into RAM.
66
*/
67
diff --git a/hw/core/machine.c b/hw/core/machine.c
68
index XXXXXXX..XXXXXXX 100644
69
--- a/hw/core/machine.c
70
+++ b/hw/core/machine.c
71
@@ -XXX,XX +XXX,XX @@
72
#include "qemu/error-report.h"
73
#include "qapi/error.h"
74
#include "qapi/qapi-visit-machine.h"
75
+#include "qapi/qapi-commands-machine.h"
76
#include "qemu/madvise.h"
77
#include "qom/object_interfaces.h"
78
#include "system/cpus.h"
79
@@ -XXX,XX +XXX,XX @@ void qemu_remove_machine_init_done_notifier(Notifier *notify)
80
notifier_remove(notify);
52
}
81
}
53
82
54
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
83
+static void handle_machine_dumpdtb(MachineState *ms)
55
index XXXXXXX..XXXXXXX 100644
84
+{
56
--- a/hw/intc/armv7m_nvic.c
85
+ if (!ms->dumpdtb) {
57
+++ b/hw/intc/armv7m_nvic.c
86
+ return;
58
@@ -XXX,XX +XXX,XX @@ bool armv7m_nvic_acknowledge_irq(void *opaque)
59
vec->active = 1;
60
vec->pending = 0;
61
62
- env->v7m.exception = s->vectpending;
63
+ write_v7m_exception(env, s->vectpending);
64
65
nvic_irq_update(s);
66
67
diff --git a/target/arm/helper.c b/target/arm/helper.c
68
index XXXXXXX..XXXXXXX 100644
69
--- a/target/arm/helper.c
70
+++ b/target/arm/helper.c
71
@@ -XXX,XX +XXX,XX @@ static bool v7m_using_psp(CPUARMState *env)
72
env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_SPSEL_MASK;
73
}
74
75
-/* Switch to V7M main or process stack pointer. */
76
-static void switch_v7m_sp(CPUARMState *env, bool new_spsel)
77
+/* Write to v7M CONTROL.SPSEL bit. This may change the current
78
+ * stack pointer between Main and Process stack pointers.
79
+ */
80
+static void write_v7m_control_spsel(CPUARMState *env, bool new_spsel)
81
{
82
uint32_t tmp;
83
- uint32_t old_control = env->v7m.control[env->v7m.secure];
84
- bool old_spsel = old_control & R_V7M_CONTROL_SPSEL_MASK;
85
+ bool new_is_psp, old_is_psp = v7m_using_psp(env);
86
+
87
+ env->v7m.control[env->v7m.secure] =
88
+ deposit32(env->v7m.control[env->v7m.secure],
89
+ R_V7M_CONTROL_SPSEL_SHIFT,
90
+ R_V7M_CONTROL_SPSEL_LENGTH, new_spsel);
91
+
92
+ new_is_psp = v7m_using_psp(env);
93
94
- if (old_spsel != new_spsel) {
95
+ if (old_is_psp != new_is_psp) {
96
tmp = env->v7m.other_sp;
97
env->v7m.other_sp = env->regs[13];
98
env->regs[13] = tmp;
99
+ }
87
+ }
88
+ if (!ms->fdt) {
89
+ /* Silently ignore dumpdtb option if there is nothing to dump */
90
+ return;
91
+ }
92
+#ifdef CONFIG_FDT
93
+ qmp_dumpdtb(ms->dumpdtb, &error_fatal);
94
+ exit(0);
95
+#else
96
+ error_report("This machine doesn't have an FDT");
97
+ exit(1);
98
+#endif
100
+}
99
+}
101
+
100
+
102
+void write_v7m_exception(CPUARMState *env, uint32_t new_exc)
101
void qdev_machine_creation_done(void)
103
+{
102
{
104
+ /* Write a new value to v7m.exception, thus transitioning into or out
103
cpu_synchronize_all_post_init();
105
+ * of Handler mode; this may result in a change of active stack pointer.
104
@@ -XXX,XX +XXX,XX @@ void qdev_machine_creation_done(void)
105
phase_advance(PHASE_MACHINE_READY);
106
qdev_assert_realized_properly();
107
108
+ /*
109
+ * If the user used -machine dumpdtb=file.dtb to request that we
110
+ * dump the DTB to a file, do it now, and exit.
106
+ */
111
+ */
107
+ bool new_is_psp, old_is_psp = v7m_using_psp(env);
112
+ handle_machine_dumpdtb(current_machine);
108
+ uint32_t tmp;
109
110
- env->v7m.control[env->v7m.secure] = deposit32(old_control,
111
- R_V7M_CONTROL_SPSEL_SHIFT,
112
- R_V7M_CONTROL_SPSEL_LENGTH, new_spsel);
113
+ env->v7m.exception = new_exc;
114
+
113
+
115
+ new_is_psp = v7m_using_psp(env);
114
/* TODO: once all bus devices are qdevified, this should be done
116
+
115
* when bus is created by qdev.c */
117
+ if (old_is_psp != new_is_psp) {
116
/*
118
+ tmp = env->v7m.other_sp;
117
diff --git a/hw/loongarch/virt-fdt-build.c b/hw/loongarch/virt-fdt-build.c
119
+ env->v7m.other_sp = env->regs[13];
118
index XXXXXXX..XXXXXXX 100644
120
+ env->regs[13] = tmp;
119
--- a/hw/loongarch/virt-fdt-build.c
120
+++ b/hw/loongarch/virt-fdt-build.c
121
@@ -XXX,XX +XXX,XX @@ void virt_fdt_setup(LoongArchVirtMachineState *lvms)
122
* Put the FDT into the memory map as a ROM image: this will ensure
123
* the FDT is copied again upon reset, even if addr points into RAM.
124
*/
125
- qemu_fdt_dumpdtb(machine->fdt, lvms->fdt_size);
126
rom_add_blob_fixed_as("fdt", machine->fdt, lvms->fdt_size, FDT_BASE,
127
&address_space_memory);
128
qemu_register_reset_nosnapshotload(qemu_fdt_randomize_seeds,
129
diff --git a/hw/mips/boston.c b/hw/mips/boston.c
130
index XXXXXXX..XXXXXXX 100644
131
--- a/hw/mips/boston.c
132
+++ b/hw/mips/boston.c
133
@@ -XXX,XX +XXX,XX @@ static void *boston_fdt_filter(void *opaque, const void *fdt_orig,
134
1, ram_high_sz);
135
136
fdt = g_realloc(fdt, fdt_totalsize(fdt));
137
- qemu_fdt_dumpdtb(fdt, fdt_sz);
138
139
s->fdt_base = *load_addr;
140
141
diff --git a/hw/openrisc/boot.c b/hw/openrisc/boot.c
142
index XXXXXXX..XXXXXXX 100644
143
--- a/hw/openrisc/boot.c
144
+++ b/hw/openrisc/boot.c
145
@@ -XXX,XX +XXX,XX @@ uint32_t openrisc_load_fdt(MachineState *ms, void *fdt,
146
/* Should only fail if we've built a corrupted tree */
147
g_assert(ret == 0);
148
/* copy in the device tree */
149
- qemu_fdt_dumpdtb(fdt, fdtsize);
150
151
/* Save FDT for dumpdtb monitor command */
152
ms->fdt = fdt;
153
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
154
index XXXXXXX..XXXXXXX 100644
155
--- a/hw/ppc/e500.c
156
+++ b/hw/ppc/e500.c
157
@@ -XXX,XX +XXX,XX @@ static int ppce500_load_device_tree(PPCE500MachineState *pms,
158
159
done:
160
if (!dry_run) {
161
- qemu_fdt_dumpdtb(fdt, fdt_size);
162
cpu_physical_memory_write(addr, fdt, fdt_size);
163
164
/* Set machine->fdt for 'dumpdtb' QMP/HMP command */
165
diff --git a/hw/ppc/pegasos2.c b/hw/ppc/pegasos2.c
166
index XXXXXXX..XXXXXXX 100644
167
--- a/hw/ppc/pegasos2.c
168
+++ b/hw/ppc/pegasos2.c
169
@@ -XXX,XX +XXX,XX @@ static void pegasos2_machine_reset(MachineState *machine, ResetType type)
170
d[1] = cpu_to_be64(pm->kernel_size - (pm->kernel_entry - pm->kernel_addr));
171
qemu_fdt_setprop(fdt, "/chosen", "qemu,boot-kernel", d, sizeof(d));
172
173
- qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt));
174
g_free(pm->fdt_blob);
175
pm->fdt_blob = fdt;
176
177
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
178
index XXXXXXX..XXXXXXX 100644
179
--- a/hw/ppc/pnv.c
180
+++ b/hw/ppc/pnv.c
181
@@ -XXX,XX +XXX,XX @@ static void pnv_reset(MachineState *machine, ResetType type)
182
_FDT((fdt_pack(fdt)));
121
}
183
}
184
185
- qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt));
186
cpu_physical_memory_write(PNV_FDT_ADDR, fdt, fdt_totalsize(fdt));
187
188
/* Update machine->fdt with latest fdt */
189
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
190
index XXXXXXX..XXXXXXX 100644
191
--- a/hw/ppc/spapr.c
192
+++ b/hw/ppc/spapr.c
193
@@ -XXX,XX +XXX,XX @@ static void spapr_machine_reset(MachineState *machine, ResetType type)
194
0, fdt_addr, 0);
195
cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));
196
}
197
- qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt));
198
199
g_free(spapr->fdt_blob);
200
spapr->fdt_size = fdt_totalsize(fdt);
201
diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c
202
index XXXXXXX..XXXXXXX 100644
203
--- a/hw/riscv/boot.c
204
+++ b/hw/riscv/boot.c
205
@@ -XXX,XX +XXX,XX @@ void riscv_load_fdt(hwaddr fdt_addr, void *fdt)
206
uint32_t fdtsize = fdt_totalsize(fdt);
207
208
/* copy in the device tree */
209
- qemu_fdt_dumpdtb(fdt, fdtsize);
210
-
211
rom_add_blob_fixed_as("fdt", fdt, fdtsize, fdt_addr,
212
&address_space_memory);
213
qemu_register_reset_nosnapshotload(qemu_fdt_randomize_seeds,
214
diff --git a/system/device_tree.c b/system/device_tree.c
215
index XXXXXXX..XXXXXXX 100644
216
--- a/system/device_tree.c
217
+++ b/system/device_tree.c
218
@@ -XXX,XX +XXX,XX @@ int qemu_fdt_add_path(void *fdt, const char *path)
219
return retval;
122
}
220
}
123
221
124
@@ -XXX,XX +XXX,XX @@ static uint32_t *get_v7m_sp_ptr(CPUARMState *env, bool secure, bool threadmode,
222
-void qemu_fdt_dumpdtb(void *fdt, int size)
125
bool want_psp = threadmode && spsel;
223
-{
126
224
- const char *dumpdtb = current_machine->dumpdtb;
127
if (secure == env->v7m.secure) {
225
-
128
- /* Currently switch_v7m_sp switches SP as it updates SPSEL,
226
- if (dumpdtb) {
129
- * so the SP we want is always in regs[13].
227
- /* Dump the dtb to a file and quit */
130
- * When we decouple SPSEL from the actually selected SP
228
- if (g_file_set_contents(dumpdtb, fdt, size, NULL)) {
131
- * we need to check want_psp against v7m_using_psp()
229
- info_report("dtb dumped to %s. Exiting.", dumpdtb);
132
- * to see whether we need regs[13] or v7m.other_sp.
230
- exit(0);
133
- */
231
- }
134
- return &env->regs[13];
232
- error_report("%s: Failed dumping dtb to %s", __func__, dumpdtb);
135
+ if (want_psp == v7m_using_psp(env)) {
233
- exit(1);
136
+ return &env->regs[13];
234
- }
137
+ } else {
235
-}
138
+ return &env->v7m.other_sp;
236
-
139
+ }
237
int qemu_fdt_setprop_sized_cells_from_array(void *fdt,
140
} else {
238
const char *node_path,
141
if (want_psp) {
239
const char *property,
142
return &env->v7m.other_ss_psp;
143
@@ -XXX,XX +XXX,XX @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr)
144
uint32_t addr;
145
146
armv7m_nvic_acknowledge_irq(env->nvic);
147
- switch_v7m_sp(env, 0);
148
+ write_v7m_control_spsel(env, 0);
149
arm_clear_exclusive(env);
150
/* Clear IT bits */
151
env->condexec_bits = 0;
152
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
153
return;
154
}
155
156
- /* Set CONTROL.SPSEL from excret.SPSEL. For QEMU this currently
157
- * causes us to switch the active SP, but we will change this
158
- * later to not do that so we can support v8M.
159
+ /* Set CONTROL.SPSEL from excret.SPSEL. Since we're still in
160
+ * Handler mode (and will be until we write the new XPSR.Interrupt
161
+ * field) this does not switch around the current stack pointer.
162
*/
163
- switch_v7m_sp(env, return_to_sp_process);
164
+ write_v7m_control_spsel(env, return_to_sp_process);
165
166
{
167
/* The stack pointer we should be reading the exception frame from
168
@@ -XXX,XX +XXX,XX @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val)
169
case 20: /* CONTROL */
170
/* Writing to the SPSEL bit only has an effect if we are in
171
* thread mode; other bits can be updated by any privileged code.
172
- * switch_v7m_sp() deals with updating the SPSEL bit in
173
+ * write_v7m_control_spsel() deals with updating the SPSEL bit in
174
* env->v7m.control, so we only need update the others.
175
*/
176
if (!arm_v7m_is_handler_mode(env)) {
177
- switch_v7m_sp(env, (val & R_V7M_CONTROL_SPSEL_MASK) != 0);
178
+ write_v7m_control_spsel(env, (val & R_V7M_CONTROL_SPSEL_MASK) != 0);
179
}
180
env->v7m.control[env->v7m.secure] &= ~R_V7M_CONTROL_NPRIV_MASK;
181
env->v7m.control[env->v7m.secure] |= val & R_V7M_CONTROL_NPRIV_MASK;
182
--
240
--
183
2.7.4
241
2.43.0
184
185
diff view generated by jsdifflib
New patch
1
Currently if the user requests via -machine dumpdtb=file.dtb that we
2
dump the DTB, but the machine doesn't have a DTB, we silently ignore
3
the option. This is confusing to users, and is a legacy of the old
4
board-specific implementation of the option, where if the execution
5
codepath didn't go via a call to qemu_fdt_dumpdtb() we would never
6
handle the option.
1
7
8
Now we handle the option in one place in machine.c, we can provide
9
the user with a useful message if they asked us to dump a DTB when
10
none exists. qmp_dumpdtb() already produces this error; remove the
11
logic in handle_machine_dumpdtb() that was there specifically to
12
avoid hitting it.
13
14
While we're here, beef up the error message a bit with a hint, and
15
make it consistent about "an FDT" rather than "a FDT". (In the
16
qmp_dumpdtb() case this needs an ERRP_GUARD to make
17
error_append_hint() work when the caller passes error_fatal.)
18
19
Note that the three places where we might report "doesn't have an
20
FDT" are hit in different situations:
21
22
(1) in handle_machine_dumpdtb(), if CONFIG_FDT is not set: this is
23
because the QEMU binary was built without libfdt at all. The
24
build system will not let you build with a machine type that
25
needs an FDT but no libfdt, so here we know both that the machine
26
doesn't use FDT and that QEMU doesn't have the support:
27
28
(2) in the device_tree-stub.c qmp_dumpdtb(): this is used when
29
we had libfdt at build time but the target architecture didn't
30
enable any machines which did "select DEVICE_TREE", so here we
31
know that the machine doesn't use FDT.
32
33
(3) in qmp_dumpdtb(), if current_machine->fdt is NULL all we know
34
is that this machine never set it. That might be because it doesn't
35
use FDT, or it might be because the user didn't pass an FDT
36
on the command line and the machine doesn't autogenerate an FDT.
37
38
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2733
39
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
40
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
41
Message-id: 20250206151214.2947842-7-peter.maydell@linaro.org
42
---
43
hw/core/machine.c | 6 ++----
44
system/device_tree-stub.c | 5 ++++-
45
system/device_tree.c | 7 ++++++-
46
3 files changed, 12 insertions(+), 6 deletions(-)
47
48
diff --git a/hw/core/machine.c b/hw/core/machine.c
49
index XXXXXXX..XXXXXXX 100644
50
--- a/hw/core/machine.c
51
+++ b/hw/core/machine.c
52
@@ -XXX,XX +XXX,XX @@ static void handle_machine_dumpdtb(MachineState *ms)
53
if (!ms->dumpdtb) {
54
return;
55
}
56
- if (!ms->fdt) {
57
- /* Silently ignore dumpdtb option if there is nothing to dump */
58
- return;
59
- }
60
#ifdef CONFIG_FDT
61
qmp_dumpdtb(ms->dumpdtb, &error_fatal);
62
exit(0);
63
#else
64
error_report("This machine doesn't have an FDT");
65
+ error_printf("(this machine type definitely doesn't use FDT, and "
66
+ "this QEMU doesn't have FDT support compiled in)\n");
67
exit(1);
68
#endif
69
}
70
diff --git a/system/device_tree-stub.c b/system/device_tree-stub.c
71
index XXXXXXX..XXXXXXX 100644
72
--- a/system/device_tree-stub.c
73
+++ b/system/device_tree-stub.c
74
@@ -XXX,XX +XXX,XX @@
75
#ifdef CONFIG_FDT
76
void qmp_dumpdtb(const char *filename, Error **errp)
77
{
78
- error_setg(errp, "This machine doesn't have a FDT");
79
+ ERRP_GUARD();
80
+
81
+ error_setg(errp, "This machine doesn't have an FDT");
82
+ error_append_hint(errp, "(this machine type definitely doesn't use FDT)\n");
83
}
84
#endif
85
diff --git a/system/device_tree.c b/system/device_tree.c
86
index XXXXXXX..XXXXXXX 100644
87
--- a/system/device_tree.c
88
+++ b/system/device_tree.c
89
@@ -XXX,XX +XXX,XX @@ out:
90
91
void qmp_dumpdtb(const char *filename, Error **errp)
92
{
93
+ ERRP_GUARD();
94
+
95
g_autoptr(GError) err = NULL;
96
uint32_t size;
97
98
if (!current_machine->fdt) {
99
- error_setg(errp, "This machine doesn't have a FDT");
100
+ error_setg(errp, "This machine doesn't have an FDT");
101
+ error_append_hint(errp,
102
+ "(Perhaps it doesn't support FDT at all, or perhaps "
103
+ "you need to provide an FDT with the -fdt option?)\n");
104
return;
105
}
106
107
--
108
2.43.0
diff view generated by jsdifflib
1
For the SG instruction and secure function return we are going
1
Currently we hardcode at compile time whether the floatx80 default
2
to want to do memory accesses using the MMU index of the CPU
2
Infinity value has the explicit integer bit set or not (x86 sets it;
3
in secure state, even though the CPU is currently in non-secure
3
m68k does not). To be able to compile softfloat once for all targets
4
state. Write arm_v7m_mmu_idx_for_secstate() to do this job,
4
we'd like to move this setting to runtime.
5
and use it in cpu_mmu_index().
5
6
Define a new FloatX80Behaviour enum which is a set of flags that
7
define the target's floatx80 handling. Initially we define just one
8
flag, for whether the default Infinity has the Integer bit set or
9
not, but we will expand this in future commits to cover the other
10
floatx80 target specifics that we currently make compile-time
11
settings.
12
13
Define a new function floatx80_default_inf() which returns the
14
appropriate default Infinity value of the given sign, and use it in
15
the code that was previously directly using the compile-time constant
16
floatx80_infinity_{low,high} values when packing an infinity into a
17
floatx80.
18
19
Since floatx80 is highly unlikely to be supported in any new
20
architecture, and the existing code is generally written as "default
21
to like x87, with an ifdef for m68k", we make the default value for
22
the floatx80 behaviour flags be "what x87 does". This means we only
23
need to change the m68k target to specify the behaviour flags.
24
25
(Other users of floatx80 are the Arm NWFPE emulation, which is
26
obsolete and probably not actually doing the right thing anyway, and
27
the PPC xsrqpxp insn. Making the default be "like x87" avoids our
28
needing to review and test for behaviour changes there.)
29
30
We will clean up the remaining uses of the floatx80_infinity global
31
constant in subsequent commits.
6
32
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
33
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
34
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
Message-id: 1506092407-26985-17-git-send-email-peter.maydell@linaro.org
35
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
36
Message-id: 20250224111524.1101196-2-peter.maydell@linaro.org
37
Message-id: 20250217125055.160887-2-peter.maydell@linaro.org
11
---
38
---
12
target/arm/cpu.h | 32 +++++++++++++++++++++-----------
39
include/fpu/softfloat-helpers.h | 12 ++++++++++++
13
1 file changed, 21 insertions(+), 11 deletions(-)
40
include/fpu/softfloat-types.h | 13 +++++++++++++
41
include/fpu/softfloat.h | 1 +
42
fpu/softfloat.c | 7 +++----
43
target/m68k/cpu.c | 6 ++++++
44
fpu/softfloat-specialize.c.inc | 10 ++++++++++
45
6 files changed, 45 insertions(+), 4 deletions(-)
14
46
15
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
47
diff --git a/include/fpu/softfloat-helpers.h b/include/fpu/softfloat-helpers.h
16
index XXXXXXX..XXXXXXX 100644
48
index XXXXXXX..XXXXXXX 100644
17
--- a/target/arm/cpu.h
49
--- a/include/fpu/softfloat-helpers.h
18
+++ b/target/arm/cpu.h
50
+++ b/include/fpu/softfloat-helpers.h
19
@@ -XXX,XX +XXX,XX @@ static inline int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx)
51
@@ -XXX,XX +XXX,XX @@ static inline void set_floatx80_rounding_precision(FloatX80RoundPrec val,
20
}
52
status->floatx80_rounding_precision = val;
21
}
53
}
22
54
23
+/* Return the MMU index for a v7M CPU in the specified security state */
55
+static inline void set_floatx80_behaviour(FloatX80Behaviour b,
24
+static inline ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env,
56
+ float_status *status)
25
+ bool secstate)
26
+{
57
+{
27
+ int el = arm_current_el(env);
58
+ status->floatx80_behaviour = b;
28
+ ARMMMUIdx mmu_idx;
29
+
30
+ if (el == 0) {
31
+ mmu_idx = secstate ? ARMMMUIdx_MSUser : ARMMMUIdx_MUser;
32
+ } else {
33
+ mmu_idx = secstate ? ARMMMUIdx_MSPriv : ARMMMUIdx_MPriv;
34
+ }
35
+
36
+ if (armv7m_nvic_neg_prio_requested(env->nvic, secstate)) {
37
+ mmu_idx = secstate ? ARMMMUIdx_MSNegPri : ARMMMUIdx_MNegPri;
38
+ }
39
+
40
+ return mmu_idx;
41
+}
59
+}
42
+
60
+
43
/* Determine the current mmu_idx to use for normal loads/stores */
61
static inline void set_float_2nan_prop_rule(Float2NaNPropRule rule,
44
static inline int cpu_mmu_index(CPUARMState *env, bool ifetch)
62
float_status *status)
45
{
63
{
46
int el = arm_current_el(env);
64
@@ -XXX,XX +XXX,XX @@ get_floatx80_rounding_precision(const float_status *status)
47
65
return status->floatx80_rounding_precision;
48
if (arm_feature(env, ARM_FEATURE_M)) {
66
}
49
- ARMMMUIdx mmu_idx;
67
50
-
68
+static inline FloatX80Behaviour
51
- if (el == 0) {
69
+get_floatx80_behaviour(const float_status *status)
52
- mmu_idx = env->v7m.secure ? ARMMMUIdx_MSUser : ARMMMUIdx_MUser;
70
+{
53
- } else {
71
+ return status->floatx80_behaviour;
54
- mmu_idx = env->v7m.secure ? ARMMMUIdx_MSPriv : ARMMMUIdx_MPriv;
72
+}
55
- }
73
+
56
-
74
static inline Float2NaNPropRule
57
- if (armv7m_nvic_neg_prio_requested(env->nvic, env->v7m.secure)) {
75
get_float_2nan_prop_rule(const float_status *status)
58
- mmu_idx = env->v7m.secure ? ARMMMUIdx_MSNegPri : ARMMMUIdx_MNegPri;
76
{
59
- }
77
diff --git a/include/fpu/softfloat-types.h b/include/fpu/softfloat-types.h
60
+ ARMMMUIdx mmu_idx = arm_v7m_mmu_idx_for_secstate(env, env->v7m.secure);
78
index XXXXXXX..XXXXXXX 100644
61
79
--- a/include/fpu/softfloat-types.h
62
return arm_to_core_mmu_idx(mmu_idx);
80
+++ b/include/fpu/softfloat-types.h
63
}
81
@@ -XXX,XX +XXX,XX @@ typedef enum __attribute__((__packed__)) {
82
float_ftz_before_rounding = 1,
83
} FloatFTZDetection;
84
85
+/*
86
+ * floatx80 is primarily used by x86 and m68k, and there are
87
+ * differences in the handling, largely related to the explicit
88
+ * Integer bit which floatx80 has and the other float formats do not.
89
+ * These flag values allow specification of the target's requirements
90
+ * and can be ORed together to set floatx80_behaviour.
91
+ */
92
+typedef enum __attribute__((__packed__)) {
93
+ /* In the default Infinity value, is the Integer bit 0 ? */
94
+ floatx80_default_inf_int_bit_is_zero = 1,
95
+} FloatX80Behaviour;
96
+
97
/*
98
* Floating Point Status. Individual architectures may maintain
99
* several versions of float_status for different functions. The
100
@@ -XXX,XX +XXX,XX @@ typedef struct float_status {
101
uint16_t float_exception_flags;
102
FloatRoundMode float_rounding_mode;
103
FloatX80RoundPrec floatx80_rounding_precision;
104
+ FloatX80Behaviour floatx80_behaviour;
105
Float2NaNPropRule float_2nan_prop_rule;
106
Float3NaNPropRule float_3nan_prop_rule;
107
FloatInfZeroNaNRule float_infzeronan_rule;
108
diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h
109
index XXXXXXX..XXXXXXX 100644
110
--- a/include/fpu/softfloat.h
111
+++ b/include/fpu/softfloat.h
112
@@ -XXX,XX +XXX,XX @@ float128 floatx80_to_float128(floatx80, float_status *status);
113
| The pattern for an extended double-precision inf.
114
*----------------------------------------------------------------------------*/
115
extern const floatx80 floatx80_infinity;
116
+floatx80 floatx80_default_inf(bool zSign, float_status *status);
117
118
/*----------------------------------------------------------------------------
119
| Software IEC/IEEE extended double-precision operations.
120
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
121
index XXXXXXX..XXXXXXX 100644
122
--- a/fpu/softfloat.c
123
+++ b/fpu/softfloat.c
124
@@ -XXX,XX +XXX,XX @@ static floatx80 floatx80_round_pack_canonical(FloatParts128 *p,
125
126
case float_class_inf:
127
/* x86 and m68k differ in the setting of the integer bit. */
128
- frac = floatx80_infinity_low;
129
+ frac = s->floatx80_behaviour & floatx80_default_inf_int_bit_is_zero ?
130
+ 0 : (1ULL << 63);
131
exp = fmt->exp_max;
132
break;
133
134
@@ -XXX,XX +XXX,XX @@ floatx80 roundAndPackFloatx80(FloatX80RoundPrec roundingPrecision, bool zSign,
135
) {
136
return packFloatx80( zSign, 0x7FFE, ~ roundMask );
137
}
138
- return packFloatx80(zSign,
139
- floatx80_infinity_high,
140
- floatx80_infinity_low);
141
+ return floatx80_default_inf(zSign, status);
142
}
143
if ( zExp <= 0 ) {
144
isTiny = status->tininess_before_rounding
145
diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c
146
index XXXXXXX..XXXXXXX 100644
147
--- a/target/m68k/cpu.c
148
+++ b/target/m68k/cpu.c
149
@@ -XXX,XX +XXX,XX @@ static void m68k_cpu_reset_hold(Object *obj, ResetType type)
150
set_float_2nan_prop_rule(float_2nan_prop_ab, &env->fp_status);
151
/* Default NaN: sign bit clear, all frac bits set */
152
set_float_default_nan_pattern(0b01111111, &env->fp_status);
153
+ /*
154
+ * m68k-specific floatx80 behaviour:
155
+ * * default Infinity values have a zero Integer bit
156
+ */
157
+ set_floatx80_behaviour(floatx80_default_inf_int_bit_is_zero,
158
+ &env->fp_status);
159
160
nan = floatx80_default_nan(&env->fp_status);
161
for (i = 0; i < 8; i++) {
162
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
163
index XXXXXXX..XXXXXXX 100644
164
--- a/fpu/softfloat-specialize.c.inc
165
+++ b/fpu/softfloat-specialize.c.inc
166
@@ -XXX,XX +XXX,XX @@ floatx80 floatx80_default_nan(float_status *status)
167
| The pattern for a default generated extended double-precision inf.
168
*----------------------------------------------------------------------------*/
169
170
+floatx80 floatx80_default_inf(bool zSign, float_status *status)
171
+{
172
+ /*
173
+ * Whether the Integer bit is set in the default Infinity is
174
+ * target dependent.
175
+ */
176
+ bool z = status->floatx80_behaviour & floatx80_default_inf_int_bit_is_zero;
177
+ return packFloatx80(zSign, 0x7fff, z ? 0 : (1ULL << 63));
178
+}
179
+
180
#define floatx80_infinity_high 0x7FFF
181
#if defined(TARGET_M68K)
182
#define floatx80_infinity_low UINT64_C(0x0000000000000000)
64
--
183
--
65
2.7.4
184
2.43.0
66
185
67
186
diff view generated by jsdifflib
1
In v8M, more bits are defined in the exception-return magic
1
The global const floatx80_infinity is (unlike all the other
2
values; update the code that checks these so we accept
2
float*_infinity values) target-specific, because whether the explicit
3
the v8M values when the CPU permits them.
3
Integer bit is set or not varies between m68k and i386. We want to
4
be able to compile softfloat once for multiple targets, so we can't
5
continue to use a single global whose value needs to be different
6
between targets.
7
8
Replace the direct uses of floatx80_infinity in target/m68k with
9
calls to the new floatx80_default_inf() function.
4
10
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
12
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 1506092407-26985-11-git-send-email-peter.maydell@linaro.org
13
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
14
Message-id: 20250224111524.1101196-3-peter.maydell@linaro.org
15
Message-id: 20250217125055.160887-3-peter.maydell@linaro.org
8
---
16
---
9
target/arm/helper.c | 73 ++++++++++++++++++++++++++++++++++++++++++-----------
17
target/m68k/softfloat.c | 47 ++++++++++++++---------------------------
10
1 file changed, 58 insertions(+), 15 deletions(-)
18
1 file changed, 16 insertions(+), 31 deletions(-)
11
19
12
diff --git a/target/arm/helper.c b/target/arm/helper.c
20
diff --git a/target/m68k/softfloat.c b/target/m68k/softfloat.c
13
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
14
--- a/target/arm/helper.c
22
--- a/target/m68k/softfloat.c
15
+++ b/target/arm/helper.c
23
+++ b/target/m68k/softfloat.c
16
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
24
@@ -XXX,XX +XXX,XX @@ floatx80 floatx80_scale(floatx80 a, floatx80 b, float_status *status)
17
uint32_t excret;
25
if ((uint64_t) (aSig << 1)) {
18
uint32_t xpsr;
26
return propagateFloatx80NaN(a, b, status);
19
bool ufault = false;
27
}
20
- bool return_to_sp_process = false;
28
- return packFloatx80(aSign, floatx80_infinity.high,
21
- bool return_to_handler = false;
29
- floatx80_infinity.low);
22
+ bool sfault = false;
30
+ return floatx80_default_inf(aSign, status);
23
+ bool return_to_sp_process;
24
+ bool return_to_handler;
25
bool rettobase = false;
26
bool exc_secure = false;
27
bool return_to_secure;
28
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
29
excret);
30
}
31
}
31
32
if (aExp == 0) {
32
+ if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
33
if (aSig == 0) {
33
+ /* EXC_RETURN.ES validation check (R_SMFL). We must do this before
34
@@ -XXX,XX +XXX,XX @@ floatx80 floatx80_lognp1(floatx80 a, float_status *status)
34
+ * we pick which FAULTMASK to clear.
35
float_raise(float_flag_invalid, status);
35
+ */
36
return floatx80_default_nan(status);
36
+ if (!env->v7m.secure &&
37
}
37
+ ((excret & R_V7M_EXCRET_ES_MASK) ||
38
- return packFloatx80(0, floatx80_infinity.high, floatx80_infinity.low);
38
+ !(excret & R_V7M_EXCRET_DCRS_MASK))) {
39
+ return floatx80_default_inf(0, status);
39
+ sfault = 1;
40
+ /* For all other purposes, treat ES as 0 (R_HXSR) */
41
+ excret &= ~R_V7M_EXCRET_ES_MASK;
42
+ }
43
+ }
44
+
45
if (env->v7m.exception != ARMV7M_EXCP_NMI) {
46
/* Auto-clear FAULTMASK on return from other than NMI.
47
* If the security extension is implemented then this only
48
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
49
g_assert_not_reached();
50
}
40
}
51
41
52
+ return_to_handler = !(excret & R_V7M_EXCRET_MODE_MASK);
42
if (aExp == 0 && aSig == 0) {
53
+ return_to_sp_process = excret & R_V7M_EXCRET_SPSEL_MASK;
43
@@ -XXX,XX +XXX,XX @@ floatx80 floatx80_lognp1(floatx80 a, float_status *status)
54
return_to_secure = arm_feature(env, ARM_FEATURE_M_SECURITY) &&
44
if (aSign && aExp >= one_exp) {
55
(excret & R_V7M_EXCRET_S_MASK);
45
if (aExp == one_exp && aSig == one_sig) {
56
46
float_raise(float_flag_divbyzero, status);
57
- switch (excret & 0xf) {
47
- return packFloatx80(aSign, floatx80_infinity.high,
58
- case 1: /* Return to Handler */
48
- floatx80_infinity.low);
59
- return_to_handler = true;
49
+ return floatx80_default_inf(aSign, status);
60
- break;
61
- case 13: /* Return to Thread using Process stack */
62
- return_to_sp_process = true;
63
- /* fall through */
64
- case 9: /* Return to Thread using Main stack */
65
- if (!rettobase &&
66
- !(env->v7m.ccr[env->v7m.secure] & R_V7M_CCR_NONBASETHRDENA_MASK)) {
67
+ if (arm_feature(env, ARM_FEATURE_V8)) {
68
+ if (!arm_feature(env, ARM_FEATURE_M_SECURITY)) {
69
+ /* UNPREDICTABLE if S == 1 or DCRS == 0 or ES == 1 (R_XLCP);
70
+ * we choose to take the UsageFault.
71
+ */
72
+ if ((excret & R_V7M_EXCRET_S_MASK) ||
73
+ (excret & R_V7M_EXCRET_ES_MASK) ||
74
+ !(excret & R_V7M_EXCRET_DCRS_MASK)) {
75
+ ufault = true;
76
+ }
77
+ }
78
+ if (excret & R_V7M_EXCRET_RES0_MASK) {
79
ufault = true;
80
}
50
}
81
- break;
51
float_raise(float_flag_invalid, status);
82
- default:
52
return floatx80_default_nan(status);
83
- ufault = true;
53
@@ -XXX,XX +XXX,XX @@ floatx80 floatx80_logn(floatx80 a, float_status *status)
84
+ } else {
54
propagateFloatx80NaNOneArg(a, status);
85
+ /* For v7M we only recognize certain combinations of the low bits */
55
}
86
+ switch (excret & 0xf) {
56
if (aSign == 0) {
87
+ case 1: /* Return to Handler */
57
- return packFloatx80(0, floatx80_infinity.high,
88
+ break;
58
- floatx80_infinity.low);
89
+ case 13: /* Return to Thread using Process stack */
59
+ return floatx80_default_inf(0, status);
90
+ case 9: /* Return to Thread using Main stack */
60
}
91
+ /* We only need to check NONBASETHRDENA for v7M, because in
92
+ * v8M this bit does not exist (it is RES1).
93
+ */
94
+ if (!rettobase &&
95
+ !(env->v7m.ccr[env->v7m.secure] &
96
+ R_V7M_CCR_NONBASETHRDENA_MASK)) {
97
+ ufault = true;
98
+ }
99
+ break;
100
+ default:
101
+ ufault = true;
102
+ }
103
+ }
104
+
105
+ if (sfault) {
106
+ env->v7m.sfsr |= R_V7M_SFSR_INVER_MASK;
107
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
108
+ v7m_exception_taken(cpu, excret);
109
+ qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on existing "
110
+ "stackframe: failed EXC_RETURN.ES validity check\n");
111
+ return;
112
}
61
}
113
62
114
if (ufault) {
63
@@ -XXX,XX +XXX,XX @@ floatx80 floatx80_logn(floatx80 a, float_status *status)
64
if (aExp == 0) {
65
if (aSig == 0) { /* zero */
66
float_raise(float_flag_divbyzero, status);
67
- return packFloatx80(1, floatx80_infinity.high,
68
- floatx80_infinity.low);
69
+ return floatx80_default_inf(1, status);
70
}
71
if ((aSig & one_sig) == 0) { /* denormal */
72
normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
73
@@ -XXX,XX +XXX,XX @@ floatx80 floatx80_log10(floatx80 a, float_status *status)
74
propagateFloatx80NaNOneArg(a, status);
75
}
76
if (aSign == 0) {
77
- return packFloatx80(0, floatx80_infinity.high,
78
- floatx80_infinity.low);
79
+ return floatx80_default_inf(0, status);
80
}
81
}
82
83
if (aExp == 0 && aSig == 0) {
84
float_raise(float_flag_divbyzero, status);
85
- return packFloatx80(1, floatx80_infinity.high,
86
- floatx80_infinity.low);
87
+ return floatx80_default_inf(1, status);
88
}
89
90
if (aSign) {
91
@@ -XXX,XX +XXX,XX @@ floatx80 floatx80_log2(floatx80 a, float_status *status)
92
propagateFloatx80NaNOneArg(a, status);
93
}
94
if (aSign == 0) {
95
- return packFloatx80(0, floatx80_infinity.high,
96
- floatx80_infinity.low);
97
+ return floatx80_default_inf(0, status);
98
}
99
}
100
101
if (aExp == 0) {
102
if (aSig == 0) {
103
float_raise(float_flag_divbyzero, status);
104
- return packFloatx80(1, floatx80_infinity.high,
105
- floatx80_infinity.low);
106
+ return floatx80_default_inf(1, status);
107
}
108
normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
109
}
110
@@ -XXX,XX +XXX,XX @@ floatx80 floatx80_etox(floatx80 a, float_status *status)
111
if (aSign) {
112
return packFloatx80(0, 0, 0);
113
}
114
- return packFloatx80(0, floatx80_infinity.high,
115
- floatx80_infinity.low);
116
+ return floatx80_default_inf(0, status);
117
}
118
119
if (aExp == 0 && aSig == 0) {
120
@@ -XXX,XX +XXX,XX @@ floatx80 floatx80_twotox(floatx80 a, float_status *status)
121
if (aSign) {
122
return packFloatx80(0, 0, 0);
123
}
124
- return packFloatx80(0, floatx80_infinity.high,
125
- floatx80_infinity.low);
126
+ return floatx80_default_inf(0, status);
127
}
128
129
if (aExp == 0 && aSig == 0) {
130
@@ -XXX,XX +XXX,XX @@ floatx80 floatx80_tentox(floatx80 a, float_status *status)
131
if (aSign) {
132
return packFloatx80(0, 0, 0);
133
}
134
- return packFloatx80(0, floatx80_infinity.high,
135
- floatx80_infinity.low);
136
+ return floatx80_default_inf(0, status);
137
}
138
139
if (aExp == 0 && aSig == 0) {
140
@@ -XXX,XX +XXX,XX @@ floatx80 floatx80_atanh(floatx80 a, float_status *status)
141
if (compact >= 0x3FFF8000) { /* |X| >= 1 */
142
if (aExp == one_exp && aSig == one_sig) { /* |X| == 1 */
143
float_raise(float_flag_divbyzero, status);
144
- return packFloatx80(aSign, floatx80_infinity.high,
145
- floatx80_infinity.low);
146
+ return floatx80_default_inf(aSign, status);
147
} else { /* |X| > 1 */
148
float_raise(float_flag_invalid, status);
149
return floatx80_default_nan(status);
150
@@ -XXX,XX +XXX,XX @@ floatx80 floatx80_etoxm1(floatx80 a, float_status *status)
151
if (aSign) {
152
return packFloatx80(aSign, one_exp, one_sig);
153
}
154
- return packFloatx80(0, floatx80_infinity.high,
155
- floatx80_infinity.low);
156
+ return floatx80_default_inf(0, status);
157
}
158
159
if (aExp == 0 && aSig == 0) {
160
@@ -XXX,XX +XXX,XX @@ floatx80 floatx80_sinh(floatx80 a, float_status *status)
161
if ((uint64_t) (aSig << 1)) {
162
return propagateFloatx80NaNOneArg(a, status);
163
}
164
- return packFloatx80(aSign, floatx80_infinity.high,
165
- floatx80_infinity.low);
166
+ return floatx80_default_inf(aSign, status);
167
}
168
169
if (aExp == 0 && aSig == 0) {
170
@@ -XXX,XX +XXX,XX @@ floatx80 floatx80_cosh(floatx80 a, float_status *status)
171
if ((uint64_t) (aSig << 1)) {
172
return propagateFloatx80NaNOneArg(a, status);
173
}
174
- return packFloatx80(0, floatx80_infinity.high,
175
- floatx80_infinity.low);
176
+ return floatx80_default_inf(0, status);
177
}
178
179
if (aExp == 0 && aSig == 0) {
115
--
180
--
116
2.7.4
181
2.43.0
117
182
118
183
diff view generated by jsdifflib
1
Now that we can handle the CONTROL.SPSEL bit not necessarily being
1
The global const floatx80_infinity is (unlike all the other
2
in sync with the current stack pointer, we can restore the correct
2
float*_infinity values) target-specific, because whether the explicit
3
security state on exception return. This happens before we start
3
Integer bit is set or not varies between m68k and i386. We want to
4
to read registers off the stack frame, but after we have taken
4
be able to compile softfloat once for multiple targets, so we can't
5
possible usage faults for bad exception return magic values and
5
continue to use a single global whose value needs to be different
6
updated CONTROL.SPSEL.
6
between targets.
7
8
Replace the direct uses of floatx80_infinity in target/i386 with
9
calls to the new floatx80_default_inf() function. Note that because
10
we can ask the function for either a negative or positive infinity,
11
we don't need to change the sign of a positive infinity via
12
floatx80_chs() for the negative-Inf case.
7
13
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
15
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
Message-id: 1506092407-26985-5-git-send-email-peter.maydell@linaro.org
16
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
17
Message-id: 20250224111524.1101196-4-peter.maydell@linaro.org
18
Message-id: 20250217125055.160887-4-peter.maydell@linaro.org
11
---
19
---
12
target/arm/helper.c | 2 ++
20
target/i386/tcg/fpu_helper.c | 7 +++----
13
1 file changed, 2 insertions(+)
21
1 file changed, 3 insertions(+), 4 deletions(-)
14
22
15
diff --git a/target/arm/helper.c b/target/arm/helper.c
23
diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c
16
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
17
--- a/target/arm/helper.c
25
--- a/target/i386/tcg/fpu_helper.c
18
+++ b/target/arm/helper.c
26
+++ b/target/i386/tcg/fpu_helper.c
19
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
27
@@ -XXX,XX +XXX,XX @@ void helper_fxtract(CPUX86State *env)
20
*/
28
} else if (floatx80_is_infinity(ST0)) {
21
write_v7m_control_spsel(env, return_to_sp_process);
29
fpush(env);
22
30
ST0 = ST1;
23
+ switch_v7m_security_state(env, return_to_secure);
31
- ST1 = floatx80_infinity;
24
+
32
+ ST1 = floatx80_default_inf(0, &env->fp_status);
25
{
33
} else {
26
/* The stack pointer we should be reading the exception frame from
34
int expdif;
27
* depends on bits in the magic exception return type value (and
35
36
@@ -XXX,XX +XXX,XX @@ void helper_fscale(CPUX86State *env)
37
float_raise(float_flag_invalid, &env->fp_status);
38
ST0 = floatx80_default_nan(&env->fp_status);
39
} else {
40
- ST0 = (floatx80_is_neg(ST0) ?
41
- floatx80_chs(floatx80_infinity) :
42
- floatx80_infinity);
43
+ ST0 = floatx80_default_inf(floatx80_is_neg(ST0),
44
+ &env->fp_status);
45
}
46
}
47
} else {
28
--
48
--
29
2.7.4
49
2.43.0
30
50
31
51
diff view generated by jsdifflib
1
Reset for devices does not include an automatic clear of the
1
Unlike the other float formats, whether a floatx80 value is
2
device state (unlike CPU state, where most of the state
2
considered to be an Infinity is target-dependent. (On x86 if the
3
structure is cleared to zero). Add some missing initialization
3
explicit integer bit is clear this is a "pseudo-infinity" and not a
4
of NVIC state that meant that the device was left in the wrong
4
valid infinity; m68k does not care about the value of the integer
5
state if the guest did a warm reset.
5
bit.)
6
6
7
(In particular, since we were resetting the computed state like
7
Currently we select this target-specific logic at compile time with
8
s->exception_prio but not all the state it was computed
8
an ifdef. We're going to want to do this at runtime, so change the
9
from like s->vectors[x].active, the NVIC wound up in an
9
floatx80_is_infinity() function to take a float_status.
10
inconsistent state that could later trigger assertion failures.)
10
11
This commit doesn't change any logic; we'll do that in the
12
next commit.
11
13
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
15
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
14
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
16
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
15
Message-id: 1506092407-26985-2-git-send-email-peter.maydell@linaro.org
17
Message-id: 20250224111524.1101196-5-peter.maydell@linaro.org
16
---
18
---
17
hw/intc/armv7m_nvic.c | 5 +++++
19
include/fpu/softfloat.h | 2 +-
18
1 file changed, 5 insertions(+)
20
target/i386/tcg/fpu_helper.c | 20 +++++++++++---------
21
target/m68k/fpu_helper.c | 2 +-
22
3 files changed, 13 insertions(+), 11 deletions(-)
19
23
20
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
24
diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h
21
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
22
--- a/hw/intc/armv7m_nvic.c
26
--- a/include/fpu/softfloat.h
23
+++ b/hw/intc/armv7m_nvic.c
27
+++ b/include/fpu/softfloat.h
24
@@ -XXX,XX +XXX,XX @@ static void armv7m_nvic_reset(DeviceState *dev)
28
@@ -XXX,XX +XXX,XX @@ static inline floatx80 floatx80_chs(floatx80 a)
25
int resetprio;
29
return a;
26
NVICState *s = NVIC(dev);
30
}
27
31
28
+ memset(s->vectors, 0, sizeof(s->vectors));
32
-static inline bool floatx80_is_infinity(floatx80 a)
29
+ memset(s->sec_vectors, 0, sizeof(s->sec_vectors));
33
+static inline bool floatx80_is_infinity(floatx80 a, float_status *status)
30
+ s->prigroup[M_REG_NS] = 0;
34
{
31
+ s->prigroup[M_REG_S] = 0;
35
#if defined(TARGET_M68K)
32
+
36
return (a.high & 0x7fff) == floatx80_infinity.high && !(a.low << 1);
33
s->vectors[ARMV7M_EXCP_NMI].enabled = 1;
37
diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c
34
/* MEM, BUS, and USAGE are enabled through
38
index XXXXXXX..XXXXXXX 100644
35
* the System Handler Control register
39
--- a/target/i386/tcg/fpu_helper.c
40
+++ b/target/i386/tcg/fpu_helper.c
41
@@ -XXX,XX +XXX,XX @@ void helper_fpatan(CPUX86State *env)
42
/* Pass this NaN through. */
43
} else if (floatx80_is_zero(ST1) && !arg0_sign) {
44
/* Pass this zero through. */
45
- } else if (((floatx80_is_infinity(ST0) && !floatx80_is_infinity(ST1)) ||
46
+ } else if (((floatx80_is_infinity(ST0, &env->fp_status) &&
47
+ !floatx80_is_infinity(ST1, &env->fp_status)) ||
48
arg0_exp - arg1_exp >= 80) &&
49
!arg0_sign) {
50
/*
51
@@ -XXX,XX +XXX,XX @@ void helper_fpatan(CPUX86State *env)
52
rexp = pi_exp;
53
rsig0 = pi_sig_high;
54
rsig1 = pi_sig_low;
55
- } else if (floatx80_is_infinity(ST1)) {
56
- if (floatx80_is_infinity(ST0)) {
57
+ } else if (floatx80_is_infinity(ST1, &env->fp_status)) {
58
+ if (floatx80_is_infinity(ST0, &env->fp_status)) {
59
if (arg0_sign) {
60
rexp = pi_34_exp;
61
rsig0 = pi_34_sig_high;
62
@@ -XXX,XX +XXX,XX @@ void helper_fpatan(CPUX86State *env)
63
rexp = pi_2_exp;
64
rsig0 = pi_2_sig_high;
65
rsig1 = pi_2_sig_low;
66
- } else if (floatx80_is_infinity(ST0) || arg0_exp - arg1_exp >= 80) {
67
+ } else if (floatx80_is_infinity(ST0, &env->fp_status) ||
68
+ arg0_exp - arg1_exp >= 80) {
69
/* ST0 is negative. */
70
rexp = pi_exp;
71
rsig0 = pi_sig_high;
72
@@ -XXX,XX +XXX,XX @@ void helper_fxtract(CPUX86State *env)
73
}
74
fpush(env);
75
ST0 = ST1;
76
- } else if (floatx80_is_infinity(ST0)) {
77
+ } else if (floatx80_is_infinity(ST0, &env->fp_status)) {
78
fpush(env);
79
ST0 = ST1;
80
ST1 = floatx80_default_inf(0, &env->fp_status);
81
@@ -XXX,XX +XXX,XX @@ void helper_fyl2x(CPUX86State *env)
82
} else if (arg0_sign && !floatx80_is_zero(ST0)) {
83
float_raise(float_flag_invalid, &env->fp_status);
84
ST1 = floatx80_default_nan(&env->fp_status);
85
- } else if (floatx80_is_infinity(ST1)) {
86
+ } else if (floatx80_is_infinity(ST1, &env->fp_status)) {
87
FloatRelation cmp = floatx80_compare(ST0, floatx80_one,
88
&env->fp_status);
89
switch (cmp) {
90
@@ -XXX,XX +XXX,XX @@ void helper_fyl2x(CPUX86State *env)
91
ST1 = floatx80_default_nan(&env->fp_status);
92
break;
93
}
94
- } else if (floatx80_is_infinity(ST0)) {
95
+ } else if (floatx80_is_infinity(ST0, &env->fp_status)) {
96
if (floatx80_is_zero(ST1)) {
97
float_raise(float_flag_invalid, &env->fp_status);
98
ST1 = floatx80_default_nan(&env->fp_status);
99
@@ -XXX,XX +XXX,XX @@ void helper_fscale(CPUX86State *env)
100
float_raise(float_flag_invalid, &env->fp_status);
101
ST0 = floatx80_silence_nan(ST0, &env->fp_status);
102
}
103
- } else if (floatx80_is_infinity(ST1) &&
104
+ } else if (floatx80_is_infinity(ST1, &env->fp_status) &&
105
!floatx80_invalid_encoding(ST0) &&
106
!floatx80_is_any_nan(ST0)) {
107
if (floatx80_is_neg(ST1)) {
108
- if (floatx80_is_infinity(ST0)) {
109
+ if (floatx80_is_infinity(ST0, &env->fp_status)) {
110
float_raise(float_flag_invalid, &env->fp_status);
111
ST0 = floatx80_default_nan(&env->fp_status);
112
} else {
113
diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c
114
index XXXXXXX..XXXXXXX 100644
115
--- a/target/m68k/fpu_helper.c
116
+++ b/target/m68k/fpu_helper.c
117
@@ -XXX,XX +XXX,XX @@ void HELPER(ftst)(CPUM68KState *env, FPReg *val)
118
119
if (floatx80_is_any_nan(val->d)) {
120
cc |= FPSR_CC_A;
121
- } else if (floatx80_is_infinity(val->d)) {
122
+ } else if (floatx80_is_infinity(val->d, &env->fp_status)) {
123
cc |= FPSR_CC_I;
124
} else if (floatx80_is_zero(val->d)) {
125
cc |= FPSR_CC_Z;
36
--
126
--
37
2.7.4
127
2.43.0
38
128
39
129
diff view generated by jsdifflib
1
On exception return for v8M, the SPSEL bit in the EXC_RETURN magic
1
In Intel terminology, a floatx80 Infinity with the explicit integer
2
value should be restored to the SPSEL bit in the CONTROL register
2
bit clear is a "pseudo-infinity"; for x86 these are not valid
3
banked specified by the EXC_RETURN.ES bit.
3
infinity values. m68k is looser and does not care whether the
4
Integer bit is set or clear in an infinity.
4
5
5
Add write_v7m_control_spsel_for_secstate() which behaves like
6
Move this setting to runtime rather than using an ifdef in
6
write_v7m_control_spsel() but allows the caller to specify which
7
floatx80_is_infinity().
7
CONTROL bank to use, reimplement write_v7m_control_spsel() in
8
8
terms of it, and use it in exception return.
9
Since this was the last use of the floatx80_infinity global constant,
10
we remove it and its definition here.
9
11
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
13
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
12
Message-id: 1506092407-26985-6-git-send-email-peter.maydell@linaro.org
14
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
15
Message-id: 20250224111524.1101196-6-peter.maydell@linaro.org
16
Message-id: 20250217125055.160887-5-peter.maydell@linaro.org
13
---
17
---
14
target/arm/helper.c | 40 +++++++++++++++++++++++++++-------------
18
include/fpu/softfloat-types.h | 5 +++++
15
1 file changed, 27 insertions(+), 13 deletions(-)
19
include/fpu/softfloat.h | 18 +++++++++++-------
20
target/m68k/cpu.c | 4 +++-
21
fpu/softfloat-specialize.c.inc | 10 ----------
22
4 files changed, 19 insertions(+), 18 deletions(-)
16
23
17
diff --git a/target/arm/helper.c b/target/arm/helper.c
24
diff --git a/include/fpu/softfloat-types.h b/include/fpu/softfloat-types.h
18
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
19
--- a/target/arm/helper.c
26
--- a/include/fpu/softfloat-types.h
20
+++ b/target/arm/helper.c
27
+++ b/include/fpu/softfloat-types.h
21
@@ -XXX,XX +XXX,XX @@ static bool v7m_using_psp(CPUARMState *env)
28
@@ -XXX,XX +XXX,XX @@ typedef enum __attribute__((__packed__)) {
22
env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_SPSEL_MASK;
29
typedef enum __attribute__((__packed__)) {
30
/* In the default Infinity value, is the Integer bit 0 ? */
31
floatx80_default_inf_int_bit_is_zero = 1,
32
+ /*
33
+ * Are Pseudo-infinities (Inf with the Integer bit zero) valid?
34
+ * If so, floatx80_is_infinity() will return true for them.
35
+ */
36
+ floatx80_pseudo_inf_valid = 2,
37
} FloatX80Behaviour;
38
39
/*
40
diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h
41
index XXXXXXX..XXXXXXX 100644
42
--- a/include/fpu/softfloat.h
43
+++ b/include/fpu/softfloat.h
44
@@ -XXX,XX +XXX,XX @@ float128 floatx80_to_float128(floatx80, float_status *status);
45
/*----------------------------------------------------------------------------
46
| The pattern for an extended double-precision inf.
47
*----------------------------------------------------------------------------*/
48
-extern const floatx80 floatx80_infinity;
49
floatx80 floatx80_default_inf(bool zSign, float_status *status);
50
51
/*----------------------------------------------------------------------------
52
@@ -XXX,XX +XXX,XX @@ static inline floatx80 floatx80_chs(floatx80 a)
53
54
static inline bool floatx80_is_infinity(floatx80 a, float_status *status)
55
{
56
-#if defined(TARGET_M68K)
57
- return (a.high & 0x7fff) == floatx80_infinity.high && !(a.low << 1);
58
-#else
59
- return (a.high & 0x7fff) == floatx80_infinity.high &&
60
- a.low == floatx80_infinity.low;
61
-#endif
62
+ /*
63
+ * It's target-specific whether the Integer bit is permitted
64
+ * to be 0 in a valid Infinity value. (x86 says no, m68k says yes).
65
+ */
66
+ bool intbit = a.low >> 63;
67
+
68
+ if (!intbit &&
69
+ !(status->floatx80_behaviour & floatx80_pseudo_inf_valid)) {
70
+ return false;
71
+ }
72
+ return (a.high & 0x7fff) == 0x7fff && !(a.low << 1);
23
}
73
}
24
74
25
-/* Write to v7M CONTROL.SPSEL bit. This may change the current
75
static inline bool floatx80_is_neg(floatx80 a)
26
- * stack pointer between Main and Process stack pointers.
76
diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c
27
+/* Write to v7M CONTROL.SPSEL bit for the specified security bank.
77
index XXXXXXX..XXXXXXX 100644
28
+ * This may change the current stack pointer between Main and Process
78
--- a/target/m68k/cpu.c
29
+ * stack pointers if it is done for the CONTROL register for the current
79
+++ b/target/m68k/cpu.c
30
+ * security state.
80
@@ -XXX,XX +XXX,XX @@ static void m68k_cpu_reset_hold(Object *obj, ResetType type)
31
*/
81
/*
32
-static void write_v7m_control_spsel(CPUARMState *env, bool new_spsel)
82
* m68k-specific floatx80 behaviour:
33
+static void write_v7m_control_spsel_for_secstate(CPUARMState *env,
83
* * default Infinity values have a zero Integer bit
34
+ bool new_spsel,
84
+ * * input Infinities may have the Integer bit either 0 or 1
35
+ bool secstate)
85
*/
36
{
86
- set_floatx80_behaviour(floatx80_default_inf_int_bit_is_zero,
37
- uint32_t tmp;
87
+ set_floatx80_behaviour(floatx80_default_inf_int_bit_is_zero |
38
- bool new_is_psp, old_is_psp = v7m_using_psp(env);
88
+ floatx80_pseudo_inf_valid,
39
+ bool old_is_psp = v7m_using_psp(env);
89
&env->fp_status);
40
90
41
- env->v7m.control[env->v7m.secure] =
91
nan = floatx80_default_nan(&env->fp_status);
42
- deposit32(env->v7m.control[env->v7m.secure],
92
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
43
+ env->v7m.control[secstate] =
93
index XXXXXXX..XXXXXXX 100644
44
+ deposit32(env->v7m.control[secstate],
94
--- a/fpu/softfloat-specialize.c.inc
45
R_V7M_CONTROL_SPSEL_SHIFT,
95
+++ b/fpu/softfloat-specialize.c.inc
46
R_V7M_CONTROL_SPSEL_LENGTH, new_spsel);
96
@@ -XXX,XX +XXX,XX @@ floatx80 floatx80_default_inf(bool zSign, float_status *status)
47
97
return packFloatx80(zSign, 0x7fff, z ? 0 : (1ULL << 63));
48
- new_is_psp = v7m_using_psp(env);
49
+ if (secstate == env->v7m.secure) {
50
+ bool new_is_psp = v7m_using_psp(env);
51
+ uint32_t tmp;
52
53
- if (old_is_psp != new_is_psp) {
54
- tmp = env->v7m.other_sp;
55
- env->v7m.other_sp = env->regs[13];
56
- env->regs[13] = tmp;
57
+ if (old_is_psp != new_is_psp) {
58
+ tmp = env->v7m.other_sp;
59
+ env->v7m.other_sp = env->regs[13];
60
+ env->regs[13] = tmp;
61
+ }
62
}
63
}
98
}
64
99
65
+/* Write to v7M CONTROL.SPSEL bit. This may change the current
100
-#define floatx80_infinity_high 0x7FFF
66
+ * stack pointer between Main and Process stack pointers.
101
-#if defined(TARGET_M68K)
67
+ */
102
-#define floatx80_infinity_low UINT64_C(0x0000000000000000)
68
+static void write_v7m_control_spsel(CPUARMState *env, bool new_spsel)
103
-#else
69
+{
104
-#define floatx80_infinity_low UINT64_C(0x8000000000000000)
70
+ write_v7m_control_spsel_for_secstate(env, new_spsel, env->v7m.secure);
105
-#endif
71
+}
106
-
72
+
107
-const floatx80 floatx80_infinity
73
void write_v7m_exception(CPUARMState *env, uint32_t new_exc)
108
- = make_floatx80_init(floatx80_infinity_high, floatx80_infinity_low);
74
{
109
-
75
/* Write a new value to v7m.exception, thus transitioning into or out
110
/*----------------------------------------------------------------------------
76
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
111
| Returns 1 if the half-precision floating-point value `a' is a quiet
77
* Handler mode (and will be until we write the new XPSR.Interrupt
112
| NaN; otherwise returns 0.
78
* field) this does not switch around the current stack pointer.
79
*/
80
- write_v7m_control_spsel(env, return_to_sp_process);
81
+ write_v7m_control_spsel_for_secstate(env, return_to_sp_process, exc_secure);
82
83
switch_v7m_security_state(env, return_to_secure);
84
85
--
113
--
86
2.7.4
114
2.43.0
87
115
88
116
diff view generated by jsdifflib
1
Currently our M profile exception return code switches to the
1
The definition of which floatx80 encodings are invalid is
2
target stack pointer relatively early in the process, before
2
target-specific. Currently we handle this with an ifdef, but we
3
it tries to pop the exception frame off the stack. This is
3
would like to defer this decision to runtime. In preparation, pass a
4
awkward for v8M for two reasons:
4
float_status argument to floatx80_invalid_encoding().
5
* in v8M the process vs main stack pointer is not selected
6
purely by the value of CONTROL.SPSEL, so updating SPSEL
7
and relying on that to switch to the right stack pointer
8
won't work
9
* the stack we should be reading the stack frame from and
10
the stack we will eventually switch to might not be the
11
same if the guest is doing strange things
12
5
13
Change our exception return code to use a 'frame pointer'
6
We will change the implementation from ifdef to looking at
14
to read the exception frame rather than assuming that we
7
the status argument in the following commit.
15
can switch the live stack pointer this early.
16
8
17
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
18
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
19
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
20
Message-id: 1506092407-26985-3-git-send-email-peter.maydell@linaro.org
11
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
12
Message-id: 20250224111524.1101196-7-peter.maydell@linaro.org
21
---
13
---
22
target/arm/helper.c | 130 +++++++++++++++++++++++++++++++++++++++-------------
14
include/fpu/softfloat.h | 2 +-
23
1 file changed, 98 insertions(+), 32 deletions(-)
15
fpu/softfloat.c | 2 +-
16
target/i386/tcg/fpu_helper.c | 24 +++++++++++++-----------
17
3 files changed, 15 insertions(+), 13 deletions(-)
24
18
25
diff --git a/target/arm/helper.c b/target/arm/helper.c
19
diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h
26
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
27
--- a/target/arm/helper.c
21
--- a/include/fpu/softfloat.h
28
+++ b/target/arm/helper.c
22
+++ b/include/fpu/softfloat.h
29
@@ -XXX,XX +XXX,XX @@ static void v7m_push(CPUARMState *env, uint32_t val)
23
@@ -XXX,XX +XXX,XX @@ static inline bool floatx80_unordered_quiet(floatx80 a, floatx80 b,
30
stl_phys(cs->as, env->regs[13], val);
24
| pseudo-denormals, which must still be correctly handled as inputs even
31
}
25
| if they are never generated as outputs.
32
26
*----------------------------------------------------------------------------*/
33
-static uint32_t v7m_pop(CPUARMState *env)
27
-static inline bool floatx80_invalid_encoding(floatx80 a)
34
-{
28
+static inline bool floatx80_invalid_encoding(floatx80 a, float_status *s)
35
- CPUState *cs = CPU(arm_env_get_cpu(env));
36
- uint32_t val;
37
-
38
- val = ldl_phys(cs->as, env->regs[13]);
39
- env->regs[13] += 4;
40
- return val;
41
-}
42
-
43
/* Return true if we're using the process stack pointer (not the MSP) */
44
static bool v7m_using_psp(CPUARMState *env)
45
{
29
{
46
@@ -XXX,XX +XXX,XX @@ void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest)
30
#if defined(TARGET_M68K)
47
env->regs[15] = dest & ~1;
31
/*-------------------------------------------------------------------------
48
}
32
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
49
33
index XXXXXXX..XXXXXXX 100644
50
+static uint32_t *get_v7m_sp_ptr(CPUARMState *env, bool secure, bool threadmode,
34
--- a/fpu/softfloat.c
51
+ bool spsel)
35
+++ b/fpu/softfloat.c
52
+{
36
@@ -XXX,XX +XXX,XX @@ static bool floatx80_unpack_canonical(FloatParts128 *p, floatx80 f,
53
+ /* Return a pointer to the location where we currently store the
54
+ * stack pointer for the requested security state and thread mode.
55
+ * This pointer will become invalid if the CPU state is updated
56
+ * such that the stack pointers are switched around (eg changing
57
+ * the SPSEL control bit).
58
+ * Compare the v8M ARM ARM pseudocode LookUpSP_with_security_mode().
59
+ * Unlike that pseudocode, we require the caller to pass us in the
60
+ * SPSEL control bit value; this is because we also use this
61
+ * function in handling of pushing of the callee-saves registers
62
+ * part of the v8M stack frame (pseudocode PushCalleeStack()),
63
+ * and in the tailchain codepath the SPSEL bit comes from the exception
64
+ * return magic LR value from the previous exception. The pseudocode
65
+ * opencodes the stack-selection in PushCalleeStack(), but we prefer
66
+ * to make this utility function generic enough to do the job.
67
+ */
68
+ bool want_psp = threadmode && spsel;
69
+
70
+ if (secure == env->v7m.secure) {
71
+ /* Currently switch_v7m_sp switches SP as it updates SPSEL,
72
+ * so the SP we want is always in regs[13].
73
+ * When we decouple SPSEL from the actually selected SP
74
+ * we need to check want_psp against v7m_using_psp()
75
+ * to see whether we need regs[13] or v7m.other_sp.
76
+ */
77
+ return &env->regs[13];
78
+ } else {
79
+ if (want_psp) {
80
+ return &env->v7m.other_ss_psp;
81
+ } else {
82
+ return &env->v7m.other_ss_msp;
83
+ }
84
+ }
85
+}
86
+
87
static uint32_t arm_v7m_load_vector(ARMCPU *cpu)
88
{
89
CPUState *cs = CPU(cpu);
90
@@ -XXX,XX +XXX,XX @@ static void v7m_push_stack(ARMCPU *cpu)
91
static void do_v7m_exception_exit(ARMCPU *cpu)
92
{
93
CPUARMState *env = &cpu->env;
94
+ CPUState *cs = CPU(cpu);
95
uint32_t excret;
96
uint32_t xpsr;
97
bool ufault = false;
98
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
99
bool return_to_handler = false;
100
bool rettobase = false;
101
bool exc_secure = false;
102
+ bool return_to_secure;
103
104
/* We can only get here from an EXCP_EXCEPTION_EXIT, and
105
* gen_bx_excret() enforces the architectural rule
106
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
107
g_assert_not_reached();
37
g_assert_not_reached();
108
}
38
}
109
39
110
+ return_to_secure = arm_feature(env, ARM_FEATURE_M_SECURITY) &&
40
- if (unlikely(floatx80_invalid_encoding(f))) {
111
+ (excret & R_V7M_EXCRET_S_MASK);
41
+ if (unlikely(floatx80_invalid_encoding(f, s))) {
112
+
42
float_raise(float_flag_invalid, s);
113
switch (excret & 0xf) {
43
return false;
114
case 1: /* Return to Handler */
115
return_to_handler = true;
116
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
117
return;
118
}
44
}
119
45
diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c
120
- /* Switch to the target stack. */
46
index XXXXXXX..XXXXXXX 100644
121
+ /* Set CONTROL.SPSEL from excret.SPSEL. For QEMU this currently
47
--- a/target/i386/tcg/fpu_helper.c
122
+ * causes us to switch the active SP, but we will change this
48
+++ b/target/i386/tcg/fpu_helper.c
123
+ * later to not do that so we can support v8M.
49
@@ -XXX,XX +XXX,XX @@ void helper_f2xm1(CPUX86State *env)
124
+ */
50
int32_t exp = extractFloatx80Exp(ST0);
125
switch_v7m_sp(env, return_to_sp_process);
51
bool sign = extractFloatx80Sign(ST0);
126
- /* Pop registers. */
52
127
- env->regs[0] = v7m_pop(env);
53
- if (floatx80_invalid_encoding(ST0)) {
128
- env->regs[1] = v7m_pop(env);
54
+ if (floatx80_invalid_encoding(ST0, &env->fp_status)) {
129
- env->regs[2] = v7m_pop(env);
55
float_raise(float_flag_invalid, &env->fp_status);
130
- env->regs[3] = v7m_pop(env);
56
ST0 = floatx80_default_nan(&env->fp_status);
131
- env->regs[12] = v7m_pop(env);
57
} else if (floatx80_is_any_nan(ST0)) {
132
- env->regs[14] = v7m_pop(env);
58
@@ -XXX,XX +XXX,XX @@ void helper_fpatan(CPUX86State *env)
133
- env->regs[15] = v7m_pop(env);
59
} else if (floatx80_is_signaling_nan(ST1, &env->fp_status)) {
134
- if (env->regs[15] & 1) {
60
float_raise(float_flag_invalid, &env->fp_status);
135
- qemu_log_mask(LOG_GUEST_ERROR,
61
ST1 = floatx80_silence_nan(ST1, &env->fp_status);
136
- "M profile return from interrupt with misaligned "
62
- } else if (floatx80_invalid_encoding(ST0) ||
137
- "PC is UNPREDICTABLE\n");
63
- floatx80_invalid_encoding(ST1)) {
138
- /* Actual hardware seems to ignore the lsbit, and there are several
64
+ } else if (floatx80_invalid_encoding(ST0, &env->fp_status) ||
139
- * RTOSes out there which incorrectly assume the r15 in the stack
65
+ floatx80_invalid_encoding(ST1, &env->fp_status)) {
140
- * frame should be a Thumb-style "lsbit indicates ARM/Thumb" value.
66
float_raise(float_flag_invalid, &env->fp_status);
141
+
67
ST1 = floatx80_default_nan(&env->fp_status);
142
+ {
68
} else if (floatx80_is_any_nan(ST0)) {
143
+ /* The stack pointer we should be reading the exception frame from
69
@@ -XXX,XX +XXX,XX @@ void helper_fxtract(CPUX86State *env)
144
+ * depends on bits in the magic exception return type value (and
70
&env->fp_status);
145
+ * for v8M isn't necessarily the stack pointer we will eventually
71
fpush(env);
146
+ * end up resuming execution with). Get a pointer to the location
72
ST0 = temp.d;
147
+ * in the CPU state struct where the SP we need is currently being
73
- } else if (floatx80_invalid_encoding(ST0)) {
148
+ * stored; we will use and modify it in place.
74
+ } else if (floatx80_invalid_encoding(ST0, &env->fp_status)) {
149
+ * We use this limited C variable scope so we don't accidentally
75
float_raise(float_flag_invalid, &env->fp_status);
150
+ * use 'frame_sp_p' after we do something that makes it invalid.
76
ST0 = floatx80_default_nan(&env->fp_status);
151
+ */
77
fpush(env);
152
+ uint32_t *frame_sp_p = get_v7m_sp_ptr(env,
78
@@ -XXX,XX +XXX,XX @@ static void helper_fprem_common(CPUX86State *env, bool mod)
153
+ return_to_secure,
79
env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */
154
+ !return_to_handler,
80
if (floatx80_is_zero(ST0) || floatx80_is_zero(ST1) ||
155
+ return_to_sp_process);
81
exp0 == 0x7fff || exp1 == 0x7fff ||
156
+ uint32_t frameptr = *frame_sp_p;
82
- floatx80_invalid_encoding(ST0) || floatx80_invalid_encoding(ST1)) {
157
+
83
+ floatx80_invalid_encoding(ST0, &env->fp_status) ||
158
+ /* Pop registers. TODO: make these accesses use the correct
84
+ floatx80_invalid_encoding(ST1, &env->fp_status)) {
159
+ * attributes and address space (S/NS, priv/unpriv) and handle
85
ST0 = floatx80_modrem(ST0, ST1, mod, &quotient, &env->fp_status);
160
+ * memory transaction failures.
86
} else {
161
*/
87
if (exp0 == 0) {
162
- env->regs[15] &= ~1U;
88
@@ -XXX,XX +XXX,XX @@ void helper_fyl2xp1(CPUX86State *env)
163
+ env->regs[0] = ldl_phys(cs->as, frameptr);
89
} else if (floatx80_is_signaling_nan(ST1, &env->fp_status)) {
164
+ env->regs[1] = ldl_phys(cs->as, frameptr + 0x4);
90
float_raise(float_flag_invalid, &env->fp_status);
165
+ env->regs[2] = ldl_phys(cs->as, frameptr + 0x8);
91
ST1 = floatx80_silence_nan(ST1, &env->fp_status);
166
+ env->regs[3] = ldl_phys(cs->as, frameptr + 0xc);
92
- } else if (floatx80_invalid_encoding(ST0) ||
167
+ env->regs[12] = ldl_phys(cs->as, frameptr + 0x10);
93
- floatx80_invalid_encoding(ST1)) {
168
+ env->regs[14] = ldl_phys(cs->as, frameptr + 0x14);
94
+ } else if (floatx80_invalid_encoding(ST0, &env->fp_status) ||
169
+ env->regs[15] = ldl_phys(cs->as, frameptr + 0x18);
95
+ floatx80_invalid_encoding(ST1, &env->fp_status)) {
170
+ if (env->regs[15] & 1) {
96
float_raise(float_flag_invalid, &env->fp_status);
171
+ qemu_log_mask(LOG_GUEST_ERROR,
97
ST1 = floatx80_default_nan(&env->fp_status);
172
+ "M profile return from interrupt with misaligned "
98
} else if (floatx80_is_any_nan(ST0)) {
173
+ "PC is UNPREDICTABLE\n");
99
@@ -XXX,XX +XXX,XX @@ void helper_fyl2x(CPUX86State *env)
174
+ /* Actual hardware seems to ignore the lsbit, and there are several
100
} else if (floatx80_is_signaling_nan(ST1, &env->fp_status)) {
175
+ * RTOSes out there which incorrectly assume the r15 in the stack
101
float_raise(float_flag_invalid, &env->fp_status);
176
+ * frame should be a Thumb-style "lsbit indicates ARM/Thumb" value.
102
ST1 = floatx80_silence_nan(ST1, &env->fp_status);
177
+ */
103
- } else if (floatx80_invalid_encoding(ST0) ||
178
+ env->regs[15] &= ~1U;
104
- floatx80_invalid_encoding(ST1)) {
179
+ }
105
+ } else if (floatx80_invalid_encoding(ST0, &env->fp_status) ||
180
+ xpsr = ldl_phys(cs->as, frameptr + 0x1c);
106
+ floatx80_invalid_encoding(ST1, &env->fp_status)) {
181
+
107
float_raise(float_flag_invalid, &env->fp_status);
182
+ /* Commit to consuming the stack frame */
108
ST1 = floatx80_default_nan(&env->fp_status);
183
+ frameptr += 0x20;
109
} else if (floatx80_is_any_nan(ST0)) {
184
+ /* Undo stack alignment (the SPREALIGN bit indicates that the original
110
@@ -XXX,XX +XXX,XX @@ void helper_frndint(CPUX86State *env)
185
+ * pre-exception SP was not 8-aligned and we added a padding word to
111
void helper_fscale(CPUX86State *env)
186
+ * align it, so we undo this by ORing in the bit that increases it
112
{
187
+ * from the current 8-aligned value to the 8-unaligned value. (Adding 4
113
uint8_t old_flags = save_exception_flags(env);
188
+ * would work too but a logical OR is how the pseudocode specifies it.)
114
- if (floatx80_invalid_encoding(ST1) || floatx80_invalid_encoding(ST0)) {
189
+ */
115
+ if (floatx80_invalid_encoding(ST1, &env->fp_status) ||
190
+ if (xpsr & XPSR_SPREALIGN) {
116
+ floatx80_invalid_encoding(ST0, &env->fp_status)) {
191
+ frameptr |= 4;
117
float_raise(float_flag_invalid, &env->fp_status);
192
+ }
118
ST0 = floatx80_default_nan(&env->fp_status);
193
+ *frame_sp_p = frameptr;
119
} else if (floatx80_is_any_nan(ST1)) {
194
}
120
@@ -XXX,XX +XXX,XX @@ void helper_fscale(CPUX86State *env)
195
- xpsr = v7m_pop(env);
121
ST0 = floatx80_silence_nan(ST0, &env->fp_status);
196
+ /* This xpsr_write() will invalidate frame_sp_p as it may switch stack */
122
}
197
xpsr_write(env, xpsr, ~XPSR_SPREALIGN);
123
} else if (floatx80_is_infinity(ST1, &env->fp_status) &&
198
- /* Undo stack alignment. */
124
- !floatx80_invalid_encoding(ST0) &&
199
- if (xpsr & XPSR_SPREALIGN) {
125
+ !floatx80_invalid_encoding(ST0, &env->fp_status) &&
200
- env->regs[13] |= 4;
126
!floatx80_is_any_nan(ST0)) {
201
- }
127
if (floatx80_is_neg(ST1)) {
202
128
if (floatx80_is_infinity(ST0, &env->fp_status)) {
203
/* The restored xPSR exception field will be zero if we're
204
* resuming in Thread mode. If that doesn't match what the
205
--
129
--
206
2.7.4
130
2.43.0
207
131
208
132
diff view generated by jsdifflib
1
Add support for v8M and in particular the security extension
1
Because floatx80 has an explicit integer bit, this permits some
2
to the exception entry code. This requires changes to:
2
odd encodings where the integer bit is not set correctly for the
3
* calculation of the exception-return magic LR value
3
floating point value type. In In Intel terminology the
4
* push the callee-saves registers in certain cases
4
categories are:
5
* clear registers when taking non-secure exceptions to avoid
5
exp == 0, int = 0, mantissa == 0 : zeroes
6
leaking information from the interrupted secure code
6
exp == 0, int = 0, mantissa != 0 : denormals
7
* switch to the correct security state on entry
7
exp == 0, int = 1 : pseudo-denormals
8
* use the vector table for the security state we're targeting
8
0 < exp < 0x7fff, int = 0 : unnormals
9
0 < exp < 0x7fff, int = 1 : normals
10
exp == 0x7fff, int = 0, mantissa == 0 : pseudo-infinities
11
exp == 0x7fff, int = 1, mantissa == 0 : infinities
12
exp == 0x7fff, int = 0, mantissa != 0 : pseudo-NaNs
13
exp == 0x7fff, int = 1, mantissa == 0 : NaNs
14
15
The usual IEEE cases of zero, denormal, normal, inf and NaN are always valid.
16
x87 permits as input also pseudo-denormals.
17
m68k permits all those and also pseudo-infinities, pseudo-NaNs and unnormals.
18
19
Currently we have an ifdef in floatx80_invalid_encoding() to select
20
the x86 vs m68k behaviour. Add new floatx80_behaviour flags to
21
select whether pseudo-NaN and unnormal are valid, and use these
22
(plus the existing pseudo_inf_valid flag) to decide whether these
23
encodings are invalid at runtime.
24
25
We leave pseudo-denormals as always-valid, since both x86 and m68k
26
accept them.
9
27
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
28
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
29
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
12
Message-id: 1506092407-26985-13-git-send-email-peter.maydell@linaro.org
30
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
31
Message-id: 20250224111524.1101196-8-peter.maydell@linaro.org
32
Message-id: 20250217125055.160887-6-peter.maydell@linaro.org
13
---
33
---
14
target/arm/helper.c | 165 +++++++++++++++++++++++++++++++++++++++++++++-------
34
include/fpu/softfloat-types.h | 14 ++++++++
15
1 file changed, 145 insertions(+), 20 deletions(-)
35
include/fpu/softfloat.h | 68 ++++++++++++++++++-----------------
36
target/m68k/cpu.c | 28 ++++++++++++++-
37
3 files changed, 77 insertions(+), 33 deletions(-)
16
38
17
diff --git a/target/arm/helper.c b/target/arm/helper.c
39
diff --git a/include/fpu/softfloat-types.h b/include/fpu/softfloat-types.h
18
index XXXXXXX..XXXXXXX 100644
40
index XXXXXXX..XXXXXXX 100644
19
--- a/target/arm/helper.c
41
--- a/include/fpu/softfloat-types.h
20
+++ b/target/arm/helper.c
42
+++ b/include/fpu/softfloat-types.h
21
@@ -XXX,XX +XXX,XX @@ static uint32_t *get_v7m_sp_ptr(CPUARMState *env, bool secure, bool threadmode,
43
@@ -XXX,XX +XXX,XX @@ typedef enum __attribute__((__packed__)) {
22
}
44
/*
23
}
45
* Are Pseudo-infinities (Inf with the Integer bit zero) valid?
24
46
* If so, floatx80_is_infinity() will return true for them.
25
-static uint32_t arm_v7m_load_vector(ARMCPU *cpu)
47
+ * If not, floatx80_invalid_encoding will return false for them,
26
+static uint32_t arm_v7m_load_vector(ARMCPU *cpu, bool targets_secure)
48
+ * and using them as inputs to a float op will raise Invalid.
49
*/
50
floatx80_pseudo_inf_valid = 2,
51
+ /*
52
+ * Are Pseudo-NaNs (NaNs where the Integer bit is zero) valid?
53
+ * If not, floatx80_invalid_encoding() will return false for them,
54
+ * and using them as inputs to a float op will raise Invalid.
55
+ */
56
+ floatx80_pseudo_nan_valid = 4,
57
+ /*
58
+ * Are Unnormals (0 < exp < 0x7fff, Integer bit zero) valid?
59
+ * If not, floatx80_invalid_encoding() will return false for them,
60
+ * and using them as inputs to a float op will raise Invalid.
61
+ */
62
+ floatx80_unnormal_valid = 8,
63
} FloatX80Behaviour;
64
65
/*
66
diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h
67
index XXXXXXX..XXXXXXX 100644
68
--- a/include/fpu/softfloat.h
69
+++ b/include/fpu/softfloat.h
70
@@ -XXX,XX +XXX,XX @@ static inline bool floatx80_unordered_quiet(floatx80 a, floatx80 b,
71
72
/*----------------------------------------------------------------------------
73
| Return whether the given value is an invalid floatx80 encoding.
74
-| Invalid floatx80 encodings arise when the integer bit is not set, but
75
-| the exponent is not zero. The only times the integer bit is permitted to
76
-| be zero is in subnormal numbers and the value zero.
77
-| This includes what the Intel software developer's manual calls pseudo-NaNs,
78
-| pseudo-infinities and un-normal numbers. It does not include
79
-| pseudo-denormals, which must still be correctly handled as inputs even
80
-| if they are never generated as outputs.
81
+| Invalid floatx80 encodings may arise when the integer bit is not set
82
+| correctly; this is target-specific. In Intel terminology the
83
+| categories are:
84
+| exp == 0, int = 0, mantissa == 0 : zeroes
85
+| exp == 0, int = 0, mantissa != 0 : denormals
86
+| exp == 0, int = 1 : pseudo-denormals
87
+| 0 < exp < 0x7fff, int = 0 : unnormals
88
+| 0 < exp < 0x7fff, int = 1 : normals
89
+| exp == 0x7fff, int = 0, mantissa == 0 : pseudo-infinities
90
+| exp == 0x7fff, int = 1, mantissa == 0 : infinities
91
+| exp == 0x7fff, int = 0, mantissa != 0 : pseudo-NaNs
92
+| exp == 0x7fff, int = 1, mantissa == 0 : NaNs
93
+|
94
+| The usual IEEE cases of zero, denormal, normal, inf and NaN are always valid.
95
+| x87 permits as input also pseudo-denormals.
96
+| m68k permits all those and also pseudo-infinities, pseudo-NaNs and unnormals.
97
+|
98
+| Since we don't have a target that handles floatx80 but prohibits
99
+| pseudo-denormals in input, we don't currently have a floatx80_behaviour
100
+| flag for that case, but instead always accept it. Conveniently this
101
+| means that all cases with either exponent 0 or the integer bit set are
102
+| valid for all targets.
103
*----------------------------------------------------------------------------*/
104
static inline bool floatx80_invalid_encoding(floatx80 a, float_status *s)
27
{
105
{
28
CPUState *cs = CPU(cpu);
106
-#if defined(TARGET_M68K)
29
CPUARMState *env = &cpu->env;
107
- /*-------------------------------------------------------------------------
30
MemTxResult result;
108
- | With m68k, the explicit integer bit can be zero in the case of:
31
- hwaddr vec = env->v7m.vecbase[env->v7m.secure] + env->v7m.exception * 4;
109
- | - zeros (exp == 0, mantissa == 0)
32
+ hwaddr vec = env->v7m.vecbase[targets_secure] + env->v7m.exception * 4;
110
- | - denormalized numbers (exp == 0, mantissa != 0)
33
uint32_t addr;
111
- | - unnormalized numbers (exp != 0, exp < 0x7FFF)
34
112
- | - infinities (exp == 0x7FFF, mantissa == 0)
35
addr = address_space_ldl(cs->as, vec,
113
- | - not-a-numbers (exp == 0x7FFF, mantissa != 0)
36
@@ -XXX,XX +XXX,XX @@ static uint32_t arm_v7m_load_vector(ARMCPU *cpu)
114
- |
37
* Since we don't model Lockup, we just report this guest error
115
- | For infinities and NaNs, the explicit integer bit can be either one or
38
* via cpu_abort().
116
- | zero.
39
*/
117
- |
40
- cpu_abort(cs, "Failed to read from exception vector table "
118
- | The IEEE 754 standard does not define a zero integer bit. Such a number
41
- "entry %08x\n", (unsigned)vec);
119
- | is an unnormalized number. Hardware does not directly support
42
+ cpu_abort(cs, "Failed to read from %s exception vector table "
120
- | denormalized and unnormalized numbers, but implicitly supports them by
43
+ "entry %08x\n", targets_secure ? "secure" : "nonsecure",
121
- | trapping them as unimplemented data types, allowing efficient conversion
44
+ (unsigned)vec);
122
- | in software.
45
}
123
- |
46
return addr;
124
- | See "M68000 FAMILY PROGRAMMER’S REFERENCE MANUAL",
47
}
125
- | "1.6 FLOATING-POINT DATA TYPES"
48
126
- *------------------------------------------------------------------------*/
49
-static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr)
127
- return false;
50
+static void v7m_push_callee_stack(ARMCPU *cpu, uint32_t lr, bool dotailchain)
128
-#else
51
+{
129
- return (a.low & (1ULL << 63)) == 0 && (a.high & 0x7FFF) != 0;
52
+ /* For v8M, push the callee-saves register part of the stack frame.
130
-#endif
53
+ * Compare the v8M pseudocode PushCalleeStack().
131
+ if ((a.low >> 63) || (a.high & 0x7fff) == 0) {
54
+ * In the tailchaining case this may not be the current stack.
132
+ /* Anything with the Integer bit set or the exponent 0 is valid */
55
+ */
133
+ return false;
56
+ CPUARMState *env = &cpu->env;
57
+ CPUState *cs = CPU(cpu);
58
+ uint32_t *frame_sp_p;
59
+ uint32_t frameptr;
60
+
61
+ if (dotailchain) {
62
+ frame_sp_p = get_v7m_sp_ptr(env, true,
63
+ lr & R_V7M_EXCRET_MODE_MASK,
64
+ lr & R_V7M_EXCRET_SPSEL_MASK);
65
+ } else {
66
+ frame_sp_p = &env->regs[13];
67
+ }
134
+ }
68
+
135
+
69
+ frameptr = *frame_sp_p - 0x28;
136
+ if ((a.high & 0x7fff) == 0x7fff) {
70
+
137
+ if (a.low) {
71
+ stl_phys(cs->as, frameptr, 0xfefa125b);
138
+ return !(s->floatx80_behaviour & floatx80_pseudo_nan_valid);
72
+ stl_phys(cs->as, frameptr + 0x8, env->regs[4]);
139
+ } else {
73
+ stl_phys(cs->as, frameptr + 0xc, env->regs[5]);
140
+ return !(s->floatx80_behaviour & floatx80_pseudo_inf_valid);
74
+ stl_phys(cs->as, frameptr + 0x10, env->regs[6]);
75
+ stl_phys(cs->as, frameptr + 0x14, env->regs[7]);
76
+ stl_phys(cs->as, frameptr + 0x18, env->regs[8]);
77
+ stl_phys(cs->as, frameptr + 0x1c, env->regs[9]);
78
+ stl_phys(cs->as, frameptr + 0x20, env->regs[10]);
79
+ stl_phys(cs->as, frameptr + 0x24, env->regs[11]);
80
+
81
+ *frame_sp_p = frameptr;
82
+}
83
+
84
+static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain)
85
{
86
/* Do the "take the exception" parts of exception entry,
87
* but not the pushing of state to the stack. This is
88
@@ -XXX,XX +XXX,XX @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr)
89
*/
90
CPUARMState *env = &cpu->env;
91
uint32_t addr;
92
+ bool targets_secure;
93
+
94
+ targets_secure = armv7m_nvic_acknowledge_irq(env->nvic);
95
96
- armv7m_nvic_acknowledge_irq(env->nvic);
97
+ if (arm_feature(env, ARM_FEATURE_V8)) {
98
+ if (arm_feature(env, ARM_FEATURE_M_SECURITY) &&
99
+ (lr & R_V7M_EXCRET_S_MASK)) {
100
+ /* The background code (the owner of the registers in the
101
+ * exception frame) is Secure. This means it may either already
102
+ * have or now needs to push callee-saves registers.
103
+ */
104
+ if (targets_secure) {
105
+ if (dotailchain && !(lr & R_V7M_EXCRET_ES_MASK)) {
106
+ /* We took an exception from Secure to NonSecure
107
+ * (which means the callee-saved registers got stacked)
108
+ * and are now tailchaining to a Secure exception.
109
+ * Clear DCRS so eventual return from this Secure
110
+ * exception unstacks the callee-saved registers.
111
+ */
112
+ lr &= ~R_V7M_EXCRET_DCRS_MASK;
113
+ }
114
+ } else {
115
+ /* We're going to a non-secure exception; push the
116
+ * callee-saves registers to the stack now, if they're
117
+ * not already saved.
118
+ */
119
+ if (lr & R_V7M_EXCRET_DCRS_MASK &&
120
+ !(dotailchain && (lr & R_V7M_EXCRET_ES_MASK))) {
121
+ v7m_push_callee_stack(cpu, lr, dotailchain);
122
+ }
123
+ lr |= R_V7M_EXCRET_DCRS_MASK;
124
+ }
125
+ }
126
+
127
+ lr &= ~R_V7M_EXCRET_ES_MASK;
128
+ if (targets_secure || !arm_feature(env, ARM_FEATURE_M_SECURITY)) {
129
+ lr |= R_V7M_EXCRET_ES_MASK;
130
+ }
131
+ lr &= ~R_V7M_EXCRET_SPSEL_MASK;
132
+ if (env->v7m.control[targets_secure] & R_V7M_CONTROL_SPSEL_MASK) {
133
+ lr |= R_V7M_EXCRET_SPSEL_MASK;
134
+ }
135
+
136
+ /* Clear registers if necessary to prevent non-secure exception
137
+ * code being able to see register values from secure code.
138
+ * Where register values become architecturally UNKNOWN we leave
139
+ * them with their previous values.
140
+ */
141
+ if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
142
+ if (!targets_secure) {
143
+ /* Always clear the caller-saved registers (they have been
144
+ * pushed to the stack earlier in v7m_push_stack()).
145
+ * Clear callee-saved registers if the background code is
146
+ * Secure (in which case these regs were saved in
147
+ * v7m_push_callee_stack()).
148
+ */
149
+ int i;
150
+
151
+ for (i = 0; i < 13; i++) {
152
+ /* r4..r11 are callee-saves, zero only if EXCRET.S == 1 */
153
+ if (i < 4 || i > 11 || (lr & R_V7M_EXCRET_S_MASK)) {
154
+ env->regs[i] = 0;
155
+ }
156
+ }
157
+ /* Clear EAPSR */
158
+ xpsr_write(env, 0, XPSR_NZCV | XPSR_Q | XPSR_GE | XPSR_IT);
159
+ }
160
+ }
161
+ }
162
+
163
+ /* Switch to target security state -- must do this before writing SPSEL */
164
+ switch_v7m_security_state(env, targets_secure);
165
write_v7m_control_spsel(env, 0);
166
arm_clear_exclusive(env);
167
/* Clear IT bits */
168
env->condexec_bits = 0;
169
env->regs[14] = lr;
170
- addr = arm_v7m_load_vector(cpu);
171
+ addr = arm_v7m_load_vector(cpu, targets_secure);
172
env->regs[15] = addr & 0xfffffffe;
173
env->thumb = addr & 1;
174
}
175
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
176
if (sfault) {
177
env->v7m.sfsr |= R_V7M_SFSR_INVER_MASK;
178
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
179
- v7m_exception_taken(cpu, excret);
180
+ v7m_exception_taken(cpu, excret, true);
181
qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on existing "
182
"stackframe: failed EXC_RETURN.ES validity check\n");
183
return;
184
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
185
*/
186
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
187
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
188
- v7m_exception_taken(cpu, excret);
189
+ v7m_exception_taken(cpu, excret, true);
190
qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on existing "
191
"stackframe: failed exception return integrity check\n");
192
return;
193
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
194
/* Take a SecureFault on the current stack */
195
env->v7m.sfsr |= R_V7M_SFSR_INVIS_MASK;
196
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
197
- v7m_exception_taken(cpu, excret);
198
+ v7m_exception_taken(cpu, excret, true);
199
qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on existing "
200
"stackframe: failed exception return integrity "
201
"signature check\n");
202
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
203
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
204
env->v7m.secure);
205
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
206
- v7m_exception_taken(cpu, excret);
207
+ v7m_exception_taken(cpu, excret, true);
208
qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on existing "
209
"stackframe: failed exception return integrity "
210
"check\n");
211
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
212
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, false);
213
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
214
v7m_push_stack(cpu);
215
- v7m_exception_taken(cpu, excret);
216
+ v7m_exception_taken(cpu, excret, false);
217
qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on new stackframe: "
218
"failed exception return integrity check\n");
219
return;
220
@@ -XXX,XX +XXX,XX @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
221
return; /* Never happens. Keep compiler happy. */
222
}
223
224
- lr = R_V7M_EXCRET_RES1_MASK |
225
- R_V7M_EXCRET_S_MASK |
226
- R_V7M_EXCRET_DCRS_MASK |
227
- R_V7M_EXCRET_FTYPE_MASK |
228
- R_V7M_EXCRET_ES_MASK;
229
- if (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_SPSEL_MASK) {
230
- lr |= R_V7M_EXCRET_SPSEL_MASK;
231
+ if (arm_feature(env, ARM_FEATURE_V8)) {
232
+ lr = R_V7M_EXCRET_RES1_MASK |
233
+ R_V7M_EXCRET_DCRS_MASK |
234
+ R_V7M_EXCRET_FTYPE_MASK;
235
+ /* The S bit indicates whether we should return to Secure
236
+ * or NonSecure (ie our current state).
237
+ * The ES bit indicates whether we're taking this exception
238
+ * to Secure or NonSecure (ie our target state). We set it
239
+ * later, in v7m_exception_taken().
240
+ * The SPSEL bit is also set in v7m_exception_taken() for v8M.
241
+ * This corresponds to the ARM ARM pseudocode for v8M setting
242
+ * some LR bits in PushStack() and some in ExceptionTaken();
243
+ * the distinction matters for the tailchain cases where we
244
+ * can take an exception without pushing the stack.
245
+ */
246
+ if (env->v7m.secure) {
247
+ lr |= R_V7M_EXCRET_S_MASK;
248
+ }
141
+ }
249
+ } else {
142
+ } else {
250
+ lr = R_V7M_EXCRET_RES1_MASK |
143
+ return !(s->floatx80_behaviour & floatx80_unnormal_valid);
251
+ R_V7M_EXCRET_S_MASK |
144
+ }
252
+ R_V7M_EXCRET_DCRS_MASK |
253
+ R_V7M_EXCRET_FTYPE_MASK |
254
+ R_V7M_EXCRET_ES_MASK;
255
+ if (env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_MASK) {
256
+ lr |= R_V7M_EXCRET_SPSEL_MASK;
257
+ }
258
}
259
if (!arm_v7m_is_handler_mode(env)) {
260
lr |= R_V7M_EXCRET_MODE_MASK;
261
}
262
263
v7m_push_stack(cpu);
264
- v7m_exception_taken(cpu, lr);
265
+ v7m_exception_taken(cpu, lr, false);
266
qemu_log_mask(CPU_LOG_INT, "... as %d\n", env->v7m.exception);
267
}
145
}
268
146
147
#define floatx80_zero make_floatx80(0x0000, 0x0000000000000000LL)
148
diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c
149
index XXXXXXX..XXXXXXX 100644
150
--- a/target/m68k/cpu.c
151
+++ b/target/m68k/cpu.c
152
@@ -XXX,XX +XXX,XX @@ static void m68k_cpu_reset_hold(Object *obj, ResetType type)
153
* m68k-specific floatx80 behaviour:
154
* * default Infinity values have a zero Integer bit
155
* * input Infinities may have the Integer bit either 0 or 1
156
+ * * pseudo-denormals supported for input and output
157
+ * * don't raise Invalid for pseudo-NaN/pseudo-Inf/Unnormal
158
+ *
159
+ * With m68k, the explicit integer bit can be zero in the case of:
160
+ * - zeros (exp == 0, mantissa == 0)
161
+ * - denormalized numbers (exp == 0, mantissa != 0)
162
+ * - unnormalized numbers (exp != 0, exp < 0x7FFF)
163
+ * - infinities (exp == 0x7FFF, mantissa == 0)
164
+ * - not-a-numbers (exp == 0x7FFF, mantissa != 0)
165
+ *
166
+ * For infinities and NaNs, the explicit integer bit can be either one or
167
+ * zero.
168
+ *
169
+ * The IEEE 754 standard does not define a zero integer bit. Such a number
170
+ * is an unnormalized number. Hardware does not directly support
171
+ * denormalized and unnormalized numbers, but implicitly supports them by
172
+ * trapping them as unimplemented data types, allowing efficient conversion
173
+ * in software.
174
+ *
175
+ * See "M68000 FAMILY PROGRAMMER’S REFERENCE MANUAL",
176
+ * "1.6 FLOATING-POINT DATA TYPES"
177
+ *
178
+ * Note though that QEMU's fp emulation does directly handle both
179
+ * denormal and unnormal values, and does not trap to guest software.
180
*/
181
set_floatx80_behaviour(floatx80_default_inf_int_bit_is_zero |
182
- floatx80_pseudo_inf_valid,
183
+ floatx80_pseudo_inf_valid |
184
+ floatx80_pseudo_nan_valid |
185
+ floatx80_unnormal_valid,
186
&env->fp_status);
187
188
nan = floatx80_default_nan(&env->fp_status);
269
--
189
--
270
2.7.4
190
2.43.0
271
191
272
192
diff view generated by jsdifflib
1
In cpu_mmu_index() we try to do this:
1
Currently we compile-time set an 'm68k_denormal' flag in the FloatFmt
2
if (env->v7m.secure) {
2
for floatx80 for m68k. This controls our handling of what the Intel
3
mmu_idx += ARMMMUIdx_MSUser;
3
documentation calls a "pseudo-denormal": a value where the exponent
4
}
4
field is zero and the explicit integer bit is set.
5
but it will give the wrong answer, because ARMMMUIdx_MSUser
5
6
includes the 0x40 ARM_MMU_IDX_M field, and so does the
6
For x86, the x87 FPU is supposed to accept a pseudo-denormal as
7
mmu_idx we're adding to, and we'll end up with 0x8n rather
7
input, but never generate one on output. For m68k, these values are
8
than 0x4n. This error is then nullified by the call to
8
permitted on input and may be produced on output.
9
arm_to_core_mmu_idx() which masks out the high part, but
9
10
we're about to factor out the code that calculates the
10
Replace the flag in the FloatFmt with a flag indicating whether the
11
ARMMMUIdx values so it can be used without passing it through
11
float format has an explicit bit (which will be true for floatx80 for
12
arm_to_core_mmu_idx(), so fix this bug first.
12
all targets, and false for every other float type). Then we can gate
13
the handling of these pseudo-denormals on the setting of a
14
floatx80_behaviour flag.
15
16
As far as I can see from the code we don't actually handle the
17
x86-mandated "accept on input but don't generate" behaviour, because
18
the handling in partsN(canonicalize) looked at fmt->m68k_denormal.
19
So I have added TODO comments to that effect.
20
21
This commit doesn't change any behaviour for any target.
13
22
14
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
23
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
16
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
24
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
17
Message-id: 1506092407-26985-16-git-send-email-peter.maydell@linaro.org
25
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
26
Message-id: 20250224111524.1101196-9-peter.maydell@linaro.org
27
Message-id: 20250217125055.160887-7-peter.maydell@linaro.org
18
---
28
---
19
target/arm/cpu.h | 12 +++++++-----
29
include/fpu/softfloat-types.h | 19 +++++++++++++++++++
20
1 file changed, 7 insertions(+), 5 deletions(-)
30
fpu/softfloat.c | 9 ++++-----
31
target/m68k/cpu.c | 3 ++-
32
fpu/softfloat-parts.c.inc | 27 ++++++++++++++++++++++++---
33
4 files changed, 49 insertions(+), 9 deletions(-)
21
34
22
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
35
diff --git a/include/fpu/softfloat-types.h b/include/fpu/softfloat-types.h
23
index XXXXXXX..XXXXXXX 100644
36
index XXXXXXX..XXXXXXX 100644
24
--- a/target/arm/cpu.h
37
--- a/include/fpu/softfloat-types.h
25
+++ b/target/arm/cpu.h
38
+++ b/include/fpu/softfloat-types.h
26
@@ -XXX,XX +XXX,XX @@ static inline int cpu_mmu_index(CPUARMState *env, bool ifetch)
39
@@ -XXX,XX +XXX,XX @@ typedef enum __attribute__((__packed__)) {
27
int el = arm_current_el(env);
40
* and using them as inputs to a float op will raise Invalid.
28
41
*/
29
if (arm_feature(env, ARM_FEATURE_M)) {
42
floatx80_unnormal_valid = 8,
30
- ARMMMUIdx mmu_idx = el == 0 ? ARMMMUIdx_MUser : ARMMMUIdx_MPriv;
43
+
31
+ ARMMMUIdx mmu_idx;
44
+ /*
32
45
+ * If the exponent is 0 and the Integer bit is set, Intel call
33
- if (armv7m_nvic_neg_prio_requested(env->nvic, env->v7m.secure)) {
46
+ * this a "pseudo-denormal"; x86 supports that only on input
34
- mmu_idx = ARMMMUIdx_MNegPri;
47
+ * (treating them as denormals by ignoring the Integer bit).
35
+ if (el == 0) {
48
+ * For m68k, the integer bit is considered validly part of the
36
+ mmu_idx = env->v7m.secure ? ARMMMUIdx_MSUser : ARMMMUIdx_MUser;
49
+ * input value when the exponent is 0, and may be 0 or 1,
37
+ } else {
50
+ * giving extra range. They may also be generated as outputs.
38
+ mmu_idx = env->v7m.secure ? ARMMMUIdx_MSPriv : ARMMMUIdx_MPriv;
51
+ * (The m68k manual actually calls these values part of the
52
+ * normalized number range, not the denormalized number range.)
53
+ *
54
+ * By default you get the Intel behaviour where the Integer
55
+ * bit is ignored; if this is set then the Integer bit value
56
+ * is honoured, m68k-style.
57
+ *
58
+ * Either way, floatx80_invalid_encoding() will always accept
59
+ * pseudo-denormals.
60
+ */
61
+ floatx80_pseudo_denormal_valid = 16,
62
} FloatX80Behaviour;
63
64
/*
65
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
66
index XXXXXXX..XXXXXXX 100644
67
--- a/fpu/softfloat.c
68
+++ b/fpu/softfloat.c
69
@@ -XXX,XX +XXX,XX @@ typedef struct {
70
* round_mask: bits below lsb which must be rounded
71
* The following optional modifiers are available:
72
* arm_althp: handle ARM Alternative Half Precision
73
- * m68k_denormal: explicit integer bit for extended precision may be 1
74
+ * has_explicit_bit: has an explicit integer bit; this affects whether
75
+ * the float_status floatx80_behaviour handling applies
76
*/
77
typedef struct {
78
int exp_size;
79
@@ -XXX,XX +XXX,XX @@ typedef struct {
80
int frac_size;
81
int frac_shift;
82
bool arm_althp;
83
- bool m68k_denormal;
84
+ bool has_explicit_bit;
85
uint64_t round_mask;
86
} FloatFmt;
87
88
@@ -XXX,XX +XXX,XX @@ static const FloatFmt floatx80_params[3] = {
89
[floatx80_precision_d] = { FLOATX80_PARAMS(52) },
90
[floatx80_precision_x] = {
91
FLOATX80_PARAMS(64),
92
-#ifdef TARGET_M68K
93
- .m68k_denormal = true,
94
-#endif
95
+ .has_explicit_bit = true,
96
},
97
};
98
99
diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c
100
index XXXXXXX..XXXXXXX 100644
101
--- a/target/m68k/cpu.c
102
+++ b/target/m68k/cpu.c
103
@@ -XXX,XX +XXX,XX @@ static void m68k_cpu_reset_hold(Object *obj, ResetType type)
104
set_floatx80_behaviour(floatx80_default_inf_int_bit_is_zero |
105
floatx80_pseudo_inf_valid |
106
floatx80_pseudo_nan_valid |
107
- floatx80_unnormal_valid,
108
+ floatx80_unnormal_valid |
109
+ floatx80_pseudo_denormal_valid,
110
&env->fp_status);
111
112
nan = floatx80_default_nan(&env->fp_status);
113
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
114
index XXXXXXX..XXXXXXX 100644
115
--- a/fpu/softfloat-parts.c.inc
116
+++ b/fpu/softfloat-parts.c.inc
117
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b,
118
static void partsN(canonicalize)(FloatPartsN *p, float_status *status,
119
const FloatFmt *fmt)
120
{
121
+ /*
122
+ * It's target-dependent how to handle the case of exponent 0
123
+ * and Integer bit set. Intel calls these "pseudodenormals",
124
+ * and treats them as if the integer bit was 0, and never
125
+ * produces them on output. This is the default behaviour for QEMU.
126
+ * For m68k, the integer bit is considered validly part of the
127
+ * input value when the exponent is 0, and may be 0 or 1,
128
+ * giving extra range. They may also be generated as outputs.
129
+ * (The m68k manual actually calls these values part of the
130
+ * normalized number range, not the denormalized number range,
131
+ * but that distinction is not important for us, because
132
+ * m68k doesn't care about the input_denormal_used status flag.)
133
+ * floatx80_pseudo_denormal_valid selects the m68k behaviour,
134
+ * which changes both how we canonicalize such a value and
135
+ * how we uncanonicalize results.
136
+ */
137
+ bool has_pseudo_denormals = fmt->has_explicit_bit &&
138
+ (status->floatx80_behaviour & floatx80_pseudo_denormal_valid);
139
+
140
if (unlikely(p->exp == 0)) {
141
if (likely(frac_eqz(p))) {
142
p->cls = float_class_zero;
143
@@ -XXX,XX +XXX,XX @@ static void partsN(canonicalize)(FloatPartsN *p, float_status *status,
144
int shift = frac_normalize(p);
145
p->cls = float_class_denormal;
146
p->exp = fmt->frac_shift - fmt->exp_bias
147
- - shift + !fmt->m68k_denormal;
148
+ - shift + !has_pseudo_denormals;
39
}
149
}
40
150
} else if (likely(p->exp < fmt->exp_max) || fmt->arm_althp) {
41
- if (env->v7m.secure) {
151
p->cls = float_class_normal;
42
- mmu_idx += ARMMMUIdx_MSUser;
152
@@ -XXX,XX +XXX,XX @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s,
43
+ if (armv7m_nvic_neg_prio_requested(env->nvic, env->v7m.secure)) {
153
frac_clear(p);
44
+ mmu_idx = env->v7m.secure ? ARMMMUIdx_MSNegPri : ARMMMUIdx_MNegPri;
154
} else {
155
bool is_tiny = s->tininess_before_rounding || exp < 0;
156
+ bool has_pseudo_denormals = fmt->has_explicit_bit &&
157
+ (s->floatx80_behaviour & floatx80_pseudo_denormal_valid);
158
159
if (!is_tiny) {
160
FloatPartsN discard;
161
is_tiny = !frac_addi(&discard, p, inc);
45
}
162
}
46
163
47
return arm_to_core_mmu_idx(mmu_idx);
164
- frac_shrjam(p, !fmt->m68k_denormal - exp);
165
+ frac_shrjam(p, !has_pseudo_denormals - exp);
166
167
if (p->frac_lo & round_mask) {
168
/* Need to recompute round-to-even/round-to-odd. */
169
@@ -XXX,XX +XXX,XX @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s,
170
p->frac_lo &= ~round_mask;
171
}
172
173
- exp = (p->frac_hi & DECOMPOSED_IMPLICIT_BIT) && !fmt->m68k_denormal;
174
+ exp = (p->frac_hi & DECOMPOSED_IMPLICIT_BIT) && !has_pseudo_denormals;
175
frac_shr(p, frac_shift);
176
177
if (is_tiny) {
48
--
178
--
49
2.7.4
179
2.43.0
50
180
51
181
diff view generated by jsdifflib
1
When we added support for the new SHCSR bits in v8M in commit
1
Currently we have a compile-time shortcut where we
2
437d59c17e9 the code to support writing to the new HARDFAULTPENDED
2
return false from no_signaling_nans() on everything except
3
bit was accidentally only added for non-secure writes; the
3
Xtensa, because we know that's the only target that
4
secure banked version of the bit should also be writable.
4
might ever set status->no_signaling_nans.
5
6
Remove the ifdef, so we always look at the status flag;
7
this has no behavioural change, but will be necessary
8
if we want to build softfloat once for all targets.
5
9
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
11
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
8
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
12
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
9
Message-id: 1506092407-26985-21-git-send-email-peter.maydell@linaro.org
13
Message-id: 20250224111524.1101196-10-peter.maydell@linaro.org
14
Message-id: 20250217125055.160887-8-peter.maydell@linaro.org
10
---
15
---
11
hw/intc/armv7m_nvic.c | 1 +
16
fpu/softfloat-specialize.c.inc | 4 ----
12
1 file changed, 1 insertion(+)
17
1 file changed, 4 deletions(-)
13
18
14
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
19
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
15
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/intc/armv7m_nvic.c
21
--- a/fpu/softfloat-specialize.c.inc
17
+++ b/hw/intc/armv7m_nvic.c
22
+++ b/fpu/softfloat-specialize.c.inc
18
@@ -XXX,XX +XXX,XX @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value,
23
@@ -XXX,XX +XXX,XX @@ this code that are retained.
19
s->sec_vectors[ARMV7M_EXCP_BUS].enabled = (value & (1 << 17)) != 0;
24
*/
20
s->sec_vectors[ARMV7M_EXCP_USAGE].enabled =
25
static inline bool no_signaling_nans(float_status *status)
21
(value & (1 << 18)) != 0;
26
{
22
+ s->sec_vectors[ARMV7M_EXCP_HARD].pending = (value & (1 << 21)) != 0;
27
-#if defined(TARGET_XTENSA)
23
/* SecureFault not banked, but RAZ/WI to NS */
28
return status->no_signaling_nans;
24
s->vectors[ARMV7M_EXCP_SECURE].active = (value & (1 << 4)) != 0;
29
-#else
25
s->vectors[ARMV7M_EXCP_SECURE].enabled = (value & (1 << 19)) != 0;
30
- return false;
31
-#endif
32
}
33
34
/* Define how the architecture discriminates signaling NaNs.
26
--
35
--
27
2.7.4
36
2.43.0
28
37
29
38
diff view generated by jsdifflib
1
In the v8M architecture, return from an exception to a PC which
1
Currently we have a compile-time shortcut where we return a hardcode
2
has bit 0 set is not UNPREDICTABLE; it is defined that bit 0
2
value from snan_bit_is_one() on everything except MIPS, because we
3
is discarded [R_HRJH]. Restrict our complaint about this to v7M.
3
know that's the only target that needs to change
4
status->no_signaling_nans at runtime.
5
6
Remove the ifdef, so we always look at the status flag. This means
7
we must update the two targets (HPPA and SH4) that were previously
8
hardcoded to return true so that they set the status flag correctly.
9
10
This has no behavioural change, but will be necessary if we want to
11
build softfloat once for all targets.
4
12
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
14
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
15
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 1506092407-26985-9-git-send-email-peter.maydell@linaro.org
16
Message-id: 20250224111524.1101196-11-peter.maydell@linaro.org
17
Message-id: 20250217125055.160887-9-peter.maydell@linaro.org
9
---
18
---
10
target/arm/helper.c | 22 +++++++++++++++-------
19
target/hppa/fpu_helper.c | 1 +
11
1 file changed, 15 insertions(+), 7 deletions(-)
20
target/sh4/cpu.c | 1 +
21
fpu/softfloat-specialize.c.inc | 7 -------
22
3 files changed, 2 insertions(+), 7 deletions(-)
12
23
13
diff --git a/target/arm/helper.c b/target/arm/helper.c
24
diff --git a/target/hppa/fpu_helper.c b/target/hppa/fpu_helper.c
14
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
15
--- a/target/arm/helper.c
26
--- a/target/hppa/fpu_helper.c
16
+++ b/target/arm/helper.c
27
+++ b/target/hppa/fpu_helper.c
17
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
28
@@ -XXX,XX +XXX,XX @@ void HELPER(loaded_fr0)(CPUHPPAState *env)
18
env->regs[12] = ldl_phys(cs->as, frameptr + 0x10);
29
set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
19
env->regs[14] = ldl_phys(cs->as, frameptr + 0x14);
30
/* Default NaN: sign bit clear, msb-1 frac bit set */
20
env->regs[15] = ldl_phys(cs->as, frameptr + 0x18);
31
set_float_default_nan_pattern(0b00100000, &env->fp_status);
21
+
32
+ set_snan_bit_is_one(true, &env->fp_status);
22
+ /* Returning from an exception with a PC with bit 0 set is defined
33
/*
23
+ * behaviour on v8M (bit 0 is ignored), but for v7M it was specified
34
* "PA-RISC 2.0 Architecture" says it is IMPDEF whether the flushing
24
+ * to be UNPREDICTABLE. In practice actual v7M hardware seems to ignore
35
* enabled by FPSR.D happens before or after rounding. We pick "before"
25
+ * the lsbit, and there are several RTOSes out there which incorrectly
36
diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c
26
+ * assume the r15 in the stack frame should be a Thumb-style "lsbit
37
index XXXXXXX..XXXXXXX 100644
27
+ * indicates ARM/Thumb" value, so ignore the bit on v7M as well, but
38
--- a/target/sh4/cpu.c
28
+ * complain about the badly behaved guest.
39
+++ b/target/sh4/cpu.c
29
+ */
40
@@ -XXX,XX +XXX,XX @@ static void superh_cpu_reset_hold(Object *obj, ResetType type)
30
if (env->regs[15] & 1) {
41
set_flush_to_zero(1, &env->fp_status);
31
- qemu_log_mask(LOG_GUEST_ERROR,
42
#endif
32
- "M profile return from interrupt with misaligned "
43
set_default_nan_mode(1, &env->fp_status);
33
- "PC is UNPREDICTABLE\n");
44
+ set_snan_bit_is_one(true, &env->fp_status);
34
- /* Actual hardware seems to ignore the lsbit, and there are several
45
/* sign bit clear, set all frac bits other than msb */
35
- * RTOSes out there which incorrectly assume the r15 in the stack
46
set_float_default_nan_pattern(0b00111111, &env->fp_status);
36
- * frame should be a Thumb-style "lsbit indicates ARM/Thumb" value.
47
/*
37
- */
48
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
38
env->regs[15] &= ~1U;
49
index XXXXXXX..XXXXXXX 100644
39
+ if (!arm_feature(env, ARM_FEATURE_V8)) {
50
--- a/fpu/softfloat-specialize.c.inc
40
+ qemu_log_mask(LOG_GUEST_ERROR,
51
+++ b/fpu/softfloat-specialize.c.inc
41
+ "M profile return from interrupt with misaligned "
52
@@ -XXX,XX +XXX,XX @@ static inline bool no_signaling_nans(float_status *status)
42
+ "PC is UNPREDICTABLE on v7M\n");
53
* In IEEE 754-1985 this was implementation defined, but in IEEE 754-2008
43
+ }
54
* the msb must be zero. MIPS is (so far) unique in supporting both the
44
}
55
* 2008 revision and backward compatibility with their original choice.
45
+
56
- * Thus for MIPS we must make the choice at runtime.
46
xpsr = ldl_phys(cs->as, frameptr + 0x1c);
57
*/
47
58
static inline bool snan_bit_is_one(float_status *status)
48
if (arm_feature(env, ARM_FEATURE_V8)) {
59
{
60
-#if defined(TARGET_MIPS)
61
return status->snan_bit_is_one;
62
-#elif defined(TARGET_HPPA) || defined(TARGET_SH4)
63
- return 1;
64
-#else
65
- return 0;
66
-#endif
67
}
68
69
/*----------------------------------------------------------------------------
49
--
70
--
50
2.7.4
71
2.43.0
51
72
52
73
diff view generated by jsdifflib
New patch
1
We happen to know that for the PPC target the FP status flags (and in
2
particular float_flag_inexact) will always be cleared before a
3
floating point operation, and so can_use_fpu() will always return
4
false. So we speed things up a little by forcing QEMU_NO_HARDFLOAT
5
to true on that target.
1
6
7
We would like to build softfloat once for all targets; that means
8
removing target-specific ifdefs. Remove the check for TARGET_PPC;
9
this won't change behaviour because can_use_fpu() will see that
10
float_flag_inexact is clear and take the softfloat path anyway.
11
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
14
Message-id: 20250224111524.1101196-12-peter.maydell@linaro.org
15
Message-id: 20250217125055.160887-10-peter.maydell@linaro.org
16
---
17
fpu/softfloat.c | 2 --
18
1 file changed, 2 deletions(-)
19
20
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
21
index XXXXXXX..XXXXXXX 100644
22
--- a/fpu/softfloat.c
23
+++ b/fpu/softfloat.c
24
@@ -XXX,XX +XXX,XX @@ GEN_INPUT_FLUSH3(float64_input_flush3, float64)
25
* the use of hardfloat, since hardfloat relies on the inexact flag being
26
* already set.
27
*/
28
-#if defined(TARGET_PPC) || defined(__FAST_MATH__)
29
# if defined(__FAST_MATH__)
30
# warning disabling hardfloat due to -ffast-math: hardfloat requires an exact \
31
IEEE implementation
32
-# endif
33
# define QEMU_NO_HARDFLOAT 1
34
# define QEMU_SOFTFLOAT_ATTR QEMU_FLATTEN
35
#else
36
--
37
2.43.0
diff view generated by jsdifflib
1
Attempting to do an exception return with an exception frame that
1
Now we have removed all the target-specifics from the softfloat code,
2
is not 8-aligned is UNPREDICTABLE in v8M; warn about this.
2
we can switch to building it once for the whole system rather than
3
(It is not UNPREDICTABLE in v7M, and our implementation can
3
once per target.
4
handle the merely-4-aligned case fine, so we don't need to
5
do anything except warn.)
6
4
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
6
Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org>
9
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
Message-id: 1506092407-26985-8-git-send-email-peter.maydell@linaro.org
8
Message-id: 20250224111524.1101196-13-peter.maydell@linaro.org
9
Message-id: 20250217125055.160887-11-peter.maydell@linaro.org
11
---
10
---
12
target/arm/helper.c | 7 +++++++
11
fpu/softfloat.c | 3 ---
13
1 file changed, 7 insertions(+)
12
fpu/meson.build | 2 +-
13
2 files changed, 1 insertion(+), 4 deletions(-)
14
14
15
diff --git a/target/arm/helper.c b/target/arm/helper.c
15
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
16
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
17
--- a/target/arm/helper.c
17
--- a/fpu/softfloat.c
18
+++ b/target/arm/helper.c
18
+++ b/fpu/softfloat.c
19
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
19
@@ -XXX,XX +XXX,XX @@ this code that are retained.
20
return_to_sp_process);
20
* version 2 or later. See the COPYING file in the top-level directory.
21
uint32_t frameptr = *frame_sp_p;
21
*/
22
22
23
+ if (!QEMU_IS_ALIGNED(frameptr, 8) &&
23
-/* softfloat (and in particular the code in softfloat-specialize.h) is
24
+ arm_feature(env, ARM_FEATURE_V8)) {
24
- * target-dependent and needs the TARGET_* macros.
25
+ qemu_log_mask(LOG_GUEST_ERROR,
25
- */
26
+ "M profile exception return with non-8-aligned SP "
26
#include "qemu/osdep.h"
27
+ "for destination state is UNPREDICTABLE\n");
27
#include <math.h>
28
+ }
28
#include "qemu/bitops.h"
29
+
29
diff --git a/fpu/meson.build b/fpu/meson.build
30
/* Pop registers. TODO: make these accesses use the correct
30
index XXXXXXX..XXXXXXX 100644
31
* attributes and address space (S/NS, priv/unpriv) and handle
31
--- a/fpu/meson.build
32
* memory transaction failures.
32
+++ b/fpu/meson.build
33
@@ -1 +1 @@
34
-specific_ss.add(when: 'CONFIG_TCG', if_true: files('softfloat.c'))
35
+common_ss.add(when: 'CONFIG_TCG', if_true: files('softfloat.c'))
33
--
36
--
34
2.7.4
37
2.43.0
35
38
36
39
diff view generated by jsdifflib
New patch
1
Most of the target/arm/vfp_helper.c file is purely TCG helper code,
2
guarded by #ifdef CONFIG_TCG. Move this into a new file in
3
target/arm/tcg/.
1
4
5
This leaves only the code relating to getting and setting the
6
FPCR/FPSR/FPSCR in the original file. (Some of this also is
7
TCG-only, but that needs more careful disentangling.)
8
9
Having two vfp_helper.c files might seem a bit confusing,
10
but once we've finished moving all the helper code out
11
of the old file we are going to rename it to vfp_fpscr.c.
12
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
15
Message-id: 20250221190957.811948-2-peter.maydell@linaro.org
16
---
17
target/arm/{ => tcg}/vfp_helper.c | 399 +----------
18
target/arm/vfp_helper.c | 1109 -----------------------------
19
target/arm/tcg/meson.build | 1 +
20
3 files changed, 4 insertions(+), 1505 deletions(-)
21
copy target/arm/{ => tcg}/vfp_helper.c (71%)
22
23
diff --git a/target/arm/vfp_helper.c b/target/arm/tcg/vfp_helper.c
24
similarity index 71%
25
copy from target/arm/vfp_helper.c
26
copy to target/arm/tcg/vfp_helper.c
27
index XXXXXXX..XXXXXXX 100644
28
--- a/target/arm/vfp_helper.c
29
+++ b/target/arm/tcg/vfp_helper.c
30
@@ -XXX,XX +XXX,XX @@
31
#include "internals.h"
32
#include "cpu-features.h"
33
#include "fpu/softfloat.h"
34
-#ifdef CONFIG_TCG
35
#include "qemu/log.h"
36
-#endif
37
-
38
-/* VFP support. We follow the convention used for VFP instructions:
39
- Single precision routines have a "s" suffix, double precision a
40
- "d" suffix. */
41
42
/*
43
- * Set the float_status behaviour to match the Arm defaults:
44
- * * tininess-before-rounding
45
- * * 2-input NaN propagation prefers SNaN over QNaN, and then
46
- * operand A over operand B (see FPProcessNaNs() pseudocode)
47
- * * 3-input NaN propagation prefers SNaN over QNaN, and then
48
- * operand C over A over B (see FPProcessNaNs3() pseudocode,
49
- * but note that for QEMU muladd is a * b + c, whereas for
50
- * the pseudocode function the arguments are in the order c, a, b.
51
- * * 0 * Inf + NaN returns the default NaN if the input NaN is quiet,
52
- * and the input NaN if it is signalling
53
- * * Default NaN has sign bit clear, msb frac bit set
54
+ * VFP support. We follow the convention used for VFP instructions:
55
+ * Single precision routines have a "s" suffix, double precision a
56
+ * "d" suffix.
57
*/
58
-void arm_set_default_fp_behaviours(float_status *s)
59
-{
60
- set_float_detect_tininess(float_tininess_before_rounding, s);
61
- set_float_ftz_detection(float_ftz_before_rounding, s);
62
- set_float_2nan_prop_rule(float_2nan_prop_s_ab, s);
63
- set_float_3nan_prop_rule(float_3nan_prop_s_cab, s);
64
- set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, s);
65
- set_float_default_nan_pattern(0b01000000, s);
66
-}
67
-
68
-/*
69
- * Set the float_status behaviour to match the FEAT_AFP
70
- * FPCR.AH=1 requirements:
71
- * * tininess-after-rounding
72
- * * 2-input NaN propagation prefers the first NaN
73
- * * 3-input NaN propagation prefers a over b over c
74
- * * 0 * Inf + NaN always returns the input NaN and doesn't
75
- * set Invalid for a QNaN
76
- * * default NaN has sign bit set, msb frac bit set
77
- */
78
-void arm_set_ah_fp_behaviours(float_status *s)
79
-{
80
- set_float_detect_tininess(float_tininess_after_rounding, s);
81
- set_float_ftz_detection(float_ftz_after_rounding, s);
82
- set_float_2nan_prop_rule(float_2nan_prop_ab, s);
83
- set_float_3nan_prop_rule(float_3nan_prop_abc, s);
84
- set_float_infzeronan_rule(float_infzeronan_dnan_never |
85
- float_infzeronan_suppress_invalid, s);
86
- set_float_default_nan_pattern(0b11000000, s);
87
-}
88
-
89
-#ifdef CONFIG_TCG
90
-
91
-/* Convert host exception flags to vfp form. */
92
-static inline uint32_t vfp_exceptbits_from_host(int host_bits, bool ah)
93
-{
94
- uint32_t target_bits = 0;
95
-
96
- if (host_bits & float_flag_invalid) {
97
- target_bits |= FPSR_IOC;
98
- }
99
- if (host_bits & float_flag_divbyzero) {
100
- target_bits |= FPSR_DZC;
101
- }
102
- if (host_bits & float_flag_overflow) {
103
- target_bits |= FPSR_OFC;
104
- }
105
- if (host_bits & (float_flag_underflow | float_flag_output_denormal_flushed)) {
106
- target_bits |= FPSR_UFC;
107
- }
108
- if (host_bits & float_flag_inexact) {
109
- target_bits |= FPSR_IXC;
110
- }
111
- if (host_bits & float_flag_input_denormal_flushed) {
112
- target_bits |= FPSR_IDC;
113
- }
114
- /*
115
- * With FPCR.AH, IDC is set when an input denormal is used,
116
- * and flushing an output denormal to zero sets both IXC and UFC.
117
- */
118
- if (ah && (host_bits & float_flag_input_denormal_used)) {
119
- target_bits |= FPSR_IDC;
120
- }
121
- if (ah && (host_bits & float_flag_output_denormal_flushed)) {
122
- target_bits |= FPSR_IXC;
123
- }
124
- return target_bits;
125
-}
126
-
127
-static uint32_t vfp_get_fpsr_from_host(CPUARMState *env)
128
-{
129
- uint32_t a32_flags = 0, a64_flags = 0;
130
-
131
- a32_flags |= get_float_exception_flags(&env->vfp.fp_status[FPST_A32]);
132
- a32_flags |= get_float_exception_flags(&env->vfp.fp_status[FPST_STD]);
133
- /* FZ16 does not generate an input denormal exception. */
134
- a32_flags |= (get_float_exception_flags(&env->vfp.fp_status[FPST_A32_F16])
135
- & ~float_flag_input_denormal_flushed);
136
- a32_flags |= (get_float_exception_flags(&env->vfp.fp_status[FPST_STD_F16])
137
- & ~float_flag_input_denormal_flushed);
138
-
139
- a64_flags |= get_float_exception_flags(&env->vfp.fp_status[FPST_A64]);
140
- a64_flags |= (get_float_exception_flags(&env->vfp.fp_status[FPST_A64_F16])
141
- & ~(float_flag_input_denormal_flushed | float_flag_input_denormal_used));
142
- /*
143
- * We do not merge in flags from FPST_AH or FPST_AH_F16, because
144
- * they are used for insns that must not set the cumulative exception bits.
145
- */
146
-
147
- /*
148
- * Flushing an input denormal *only* because FPCR.FIZ == 1 does
149
- * not set FPSR.IDC; if FPCR.FZ is also set then this takes
150
- * precedence and IDC is set (see the FPUnpackBase pseudocode).
151
- * So squash it unless (FPCR.AH == 0 && FPCR.FZ == 1).
152
- * We only do this for the a64 flags because FIZ has no effect
153
- * on AArch32 even if it is set.
154
- */
155
- if ((env->vfp.fpcr & (FPCR_FZ | FPCR_AH)) != FPCR_FZ) {
156
- a64_flags &= ~float_flag_input_denormal_flushed;
157
- }
158
- return vfp_exceptbits_from_host(a64_flags, env->vfp.fpcr & FPCR_AH) |
159
- vfp_exceptbits_from_host(a32_flags, false);
160
-}
161
-
162
-static void vfp_clear_float_status_exc_flags(CPUARMState *env)
163
-{
164
- /*
165
- * Clear out all the exception-flag information in the float_status
166
- * values. The caller should have arranged for env->vfp.fpsr to
167
- * be the architecturally up-to-date exception flag information first.
168
- */
169
- set_float_exception_flags(0, &env->vfp.fp_status[FPST_A32]);
170
- set_float_exception_flags(0, &env->vfp.fp_status[FPST_A64]);
171
- set_float_exception_flags(0, &env->vfp.fp_status[FPST_A32_F16]);
172
- set_float_exception_flags(0, &env->vfp.fp_status[FPST_A64_F16]);
173
- set_float_exception_flags(0, &env->vfp.fp_status[FPST_STD]);
174
- set_float_exception_flags(0, &env->vfp.fp_status[FPST_STD_F16]);
175
- set_float_exception_flags(0, &env->vfp.fp_status[FPST_AH]);
176
- set_float_exception_flags(0, &env->vfp.fp_status[FPST_AH_F16]);
177
-}
178
-
179
-static void vfp_sync_and_clear_float_status_exc_flags(CPUARMState *env)
180
-{
181
- /*
182
- * Synchronize any pending exception-flag information in the
183
- * float_status values into env->vfp.fpsr, and then clear out
184
- * the float_status data.
185
- */
186
- env->vfp.fpsr |= vfp_get_fpsr_from_host(env);
187
- vfp_clear_float_status_exc_flags(env);
188
-}
189
-
190
-static void vfp_set_fpcr_to_host(CPUARMState *env, uint32_t val, uint32_t mask)
191
-{
192
- uint64_t changed = env->vfp.fpcr;
193
-
194
- changed ^= val;
195
- changed &= mask;
196
- if (changed & (3 << 22)) {
197
- int i = (val >> 22) & 3;
198
- switch (i) {
199
- case FPROUNDING_TIEEVEN:
200
- i = float_round_nearest_even;
201
- break;
202
- case FPROUNDING_POSINF:
203
- i = float_round_up;
204
- break;
205
- case FPROUNDING_NEGINF:
206
- i = float_round_down;
207
- break;
208
- case FPROUNDING_ZERO:
209
- i = float_round_to_zero;
210
- break;
211
- }
212
- set_float_rounding_mode(i, &env->vfp.fp_status[FPST_A32]);
213
- set_float_rounding_mode(i, &env->vfp.fp_status[FPST_A64]);
214
- set_float_rounding_mode(i, &env->vfp.fp_status[FPST_A32_F16]);
215
- set_float_rounding_mode(i, &env->vfp.fp_status[FPST_A64_F16]);
216
- }
217
- if (changed & FPCR_FZ16) {
218
- bool ftz_enabled = val & FPCR_FZ16;
219
- set_flush_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_A32_F16]);
220
- set_flush_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_A64_F16]);
221
- set_flush_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_STD_F16]);
222
- set_flush_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_AH_F16]);
223
- set_flush_inputs_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_A32_F16]);
224
- set_flush_inputs_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_A64_F16]);
225
- set_flush_inputs_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_STD_F16]);
226
- set_flush_inputs_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_AH_F16]);
227
- }
228
- if (changed & FPCR_FZ) {
229
- bool ftz_enabled = val & FPCR_FZ;
230
- set_flush_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_A32]);
231
- set_flush_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_A64]);
232
- /* FIZ is A64 only so FZ always makes A32 code flush inputs to zero */
233
- set_flush_inputs_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_A32]);
234
- }
235
- if (changed & (FPCR_FZ | FPCR_AH | FPCR_FIZ)) {
236
- /*
237
- * A64: Flush denormalized inputs to zero if FPCR.FIZ = 1, or
238
- * both FPCR.AH = 0 and FPCR.FZ = 1.
239
- */
240
- bool fitz_enabled = (val & FPCR_FIZ) ||
241
- (val & (FPCR_FZ | FPCR_AH)) == FPCR_FZ;
242
- set_flush_inputs_to_zero(fitz_enabled, &env->vfp.fp_status[FPST_A64]);
243
- }
244
- if (changed & FPCR_DN) {
245
- bool dnan_enabled = val & FPCR_DN;
246
- set_default_nan_mode(dnan_enabled, &env->vfp.fp_status[FPST_A32]);
247
- set_default_nan_mode(dnan_enabled, &env->vfp.fp_status[FPST_A64]);
248
- set_default_nan_mode(dnan_enabled, &env->vfp.fp_status[FPST_A32_F16]);
249
- set_default_nan_mode(dnan_enabled, &env->vfp.fp_status[FPST_A64_F16]);
250
- set_default_nan_mode(dnan_enabled, &env->vfp.fp_status[FPST_AH]);
251
- set_default_nan_mode(dnan_enabled, &env->vfp.fp_status[FPST_AH_F16]);
252
- }
253
- if (changed & FPCR_AH) {
254
- bool ah_enabled = val & FPCR_AH;
255
-
256
- if (ah_enabled) {
257
- /* Change behaviours for A64 FP operations */
258
- arm_set_ah_fp_behaviours(&env->vfp.fp_status[FPST_A64]);
259
- arm_set_ah_fp_behaviours(&env->vfp.fp_status[FPST_A64_F16]);
260
- } else {
261
- arm_set_default_fp_behaviours(&env->vfp.fp_status[FPST_A64]);
262
- arm_set_default_fp_behaviours(&env->vfp.fp_status[FPST_A64_F16]);
263
- }
264
- }
265
- /*
266
- * If any bits changed that we look at in vfp_get_fpsr_from_host(),
267
- * we must sync the float_status flags into vfp.fpsr now (under the
268
- * old regime) before we update vfp.fpcr.
269
- */
270
- if (changed & (FPCR_FZ | FPCR_AH | FPCR_FIZ)) {
271
- vfp_sync_and_clear_float_status_exc_flags(env);
272
- }
273
-}
274
-
275
-#else
276
-
277
-static uint32_t vfp_get_fpsr_from_host(CPUARMState *env)
278
-{
279
- return 0;
280
-}
281
-
282
-static void vfp_clear_float_status_exc_flags(CPUARMState *env)
283
-{
284
-}
285
-
286
-static void vfp_set_fpcr_to_host(CPUARMState *env, uint32_t val, uint32_t mask)
287
-{
288
-}
289
-
290
-#endif
291
-
292
-uint32_t vfp_get_fpcr(CPUARMState *env)
293
-{
294
- uint32_t fpcr = env->vfp.fpcr
295
- | (env->vfp.vec_len << 16)
296
- | (env->vfp.vec_stride << 20);
297
-
298
- /*
299
- * M-profile LTPSIZE is the same bits [18:16] as A-profile Len; whichever
300
- * of the two is not applicable to this CPU will always be zero.
301
- */
302
- fpcr |= env->v7m.ltpsize << 16;
303
-
304
- return fpcr;
305
-}
306
-
307
-uint32_t vfp_get_fpsr(CPUARMState *env)
308
-{
309
- uint32_t fpsr = env->vfp.fpsr;
310
- uint32_t i;
311
-
312
- fpsr |= vfp_get_fpsr_from_host(env);
313
-
314
- i = env->vfp.qc[0] | env->vfp.qc[1] | env->vfp.qc[2] | env->vfp.qc[3];
315
- fpsr |= i ? FPSR_QC : 0;
316
- return fpsr;
317
-}
318
-
319
-uint32_t HELPER(vfp_get_fpscr)(CPUARMState *env)
320
-{
321
- return (vfp_get_fpcr(env) & FPSCR_FPCR_MASK) |
322
- (vfp_get_fpsr(env) & FPSCR_FPSR_MASK);
323
-}
324
-
325
-uint32_t vfp_get_fpscr(CPUARMState *env)
326
-{
327
- return HELPER(vfp_get_fpscr)(env);
328
-}
329
-
330
-void vfp_set_fpsr(CPUARMState *env, uint32_t val)
331
-{
332
- ARMCPU *cpu = env_archcpu(env);
333
-
334
- if (arm_feature(env, ARM_FEATURE_NEON) ||
335
- cpu_isar_feature(aa32_mve, cpu)) {
336
- /*
337
- * The bit we set within vfp.qc[] is arbitrary; the array as a
338
- * whole being zero/non-zero is what counts.
339
- */
340
- env->vfp.qc[0] = val & FPSR_QC;
341
- env->vfp.qc[1] = 0;
342
- env->vfp.qc[2] = 0;
343
- env->vfp.qc[3] = 0;
344
- }
345
-
346
- /*
347
- * NZCV lives only in env->vfp.fpsr. The cumulative exception flags
348
- * IOC|DZC|OFC|UFC|IXC|IDC also live in env->vfp.fpsr, with possible
349
- * extra pending exception information that hasn't yet been folded in
350
- * living in the float_status values (for TCG).
351
- * Since this FPSR write gives us the up to date values of the exception
352
- * flags, we want to store into vfp.fpsr the NZCV and CEXC bits, zeroing
353
- * anything else. We also need to clear out the float_status exception
354
- * information so that the next vfp_get_fpsr does not fold in stale data.
355
- */
356
- val &= FPSR_NZCV_MASK | FPSR_CEXC_MASK;
357
- env->vfp.fpsr = val;
358
- vfp_clear_float_status_exc_flags(env);
359
-}
360
-
361
-static void vfp_set_fpcr_masked(CPUARMState *env, uint32_t val, uint32_t mask)
362
-{
363
- /*
364
- * We only set FPCR bits defined by mask, and leave the others alone.
365
- * We assume the mask is sensible (e.g. doesn't try to set only
366
- * part of a field)
367
- */
368
- ARMCPU *cpu = env_archcpu(env);
369
-
370
- /* When ARMv8.2-FP16 is not supported, FZ16 is RES0. */
371
- if (!cpu_isar_feature(any_fp16, cpu)) {
372
- val &= ~FPCR_FZ16;
373
- }
374
- if (!cpu_isar_feature(aa64_afp, cpu)) {
375
- val &= ~(FPCR_FIZ | FPCR_AH | FPCR_NEP);
376
- }
377
-
378
- if (!cpu_isar_feature(aa64_ebf16, cpu)) {
379
- val &= ~FPCR_EBF;
380
- }
381
-
382
- vfp_set_fpcr_to_host(env, val, mask);
383
-
384
- if (mask & (FPCR_LEN_MASK | FPCR_STRIDE_MASK)) {
385
- if (!arm_feature(env, ARM_FEATURE_M)) {
386
- /*
387
- * Short-vector length and stride; on M-profile these bits
388
- * are used for different purposes.
389
- * We can't make this conditional be "if MVFR0.FPShVec != 0",
390
- * because in v7A no-short-vector-support cores still had to
391
- * allow Stride/Len to be written with the only effect that
392
- * some insns are required to UNDEF if the guest sets them.
393
- */
394
- env->vfp.vec_len = extract32(val, 16, 3);
395
- env->vfp.vec_stride = extract32(val, 20, 2);
396
- } else if (cpu_isar_feature(aa32_mve, cpu)) {
397
- env->v7m.ltpsize = extract32(val, FPCR_LTPSIZE_SHIFT,
398
- FPCR_LTPSIZE_LENGTH);
399
- }
400
- }
401
-
402
- /*
403
- * We don't implement trapped exception handling, so the
404
- * trap enable bits, IDE|IXE|UFE|OFE|DZE|IOE are all RAZ/WI (not RES0!)
405
- *
406
- * The FPCR bits we keep in vfp.fpcr are AHP, DN, FZ, RMode, EBF, FZ16,
407
- * FIZ, AH, and NEP.
408
- * Len, Stride and LTPSIZE we just handled. Store those bits
409
- * there, and zero any of the other FPCR bits and the RES0 and RAZ/WI
410
- * bits.
411
- */
412
- val &= FPCR_AHP | FPCR_DN | FPCR_FZ | FPCR_RMODE_MASK | FPCR_FZ16 |
413
- FPCR_EBF | FPCR_FIZ | FPCR_AH | FPCR_NEP;
414
- env->vfp.fpcr &= ~mask;
415
- env->vfp.fpcr |= val;
416
-}
417
-
418
-void vfp_set_fpcr(CPUARMState *env, uint32_t val)
419
-{
420
- vfp_set_fpcr_masked(env, val, MAKE_64BIT_MASK(0, 32));
421
-}
422
-
423
-void HELPER(vfp_set_fpscr)(CPUARMState *env, uint32_t val)
424
-{
425
- vfp_set_fpcr_masked(env, val, FPSCR_FPCR_MASK);
426
- vfp_set_fpsr(env, val & FPSCR_FPSR_MASK);
427
-}
428
-
429
-void vfp_set_fpscr(CPUARMState *env, uint32_t val)
430
-{
431
- HELPER(vfp_set_fpscr)(env, val);
432
-}
433
-
434
-#ifdef CONFIG_TCG
435
436
#define VFP_HELPER(name, p) HELPER(glue(glue(vfp_,name),p))
437
438
@@ -XXX,XX +XXX,XX @@ void HELPER(check_hcr_el2_trap)(CPUARMState *env, uint32_t rt, uint32_t reg)
439
440
raise_exception(env, EXCP_HYP_TRAP, syndrome, 2);
441
}
442
-
443
-#endif
444
diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_helper.c
445
index XXXXXXX..XXXXXXX 100644
446
--- a/target/arm/vfp_helper.c
447
+++ b/target/arm/vfp_helper.c
448
@@ -XXX,XX +XXX,XX @@
449
#include "internals.h"
450
#include "cpu-features.h"
451
#include "fpu/softfloat.h"
452
-#ifdef CONFIG_TCG
453
-#include "qemu/log.h"
454
-#endif
455
-
456
-/* VFP support. We follow the convention used for VFP instructions:
457
- Single precision routines have a "s" suffix, double precision a
458
- "d" suffix. */
459
460
/*
461
* Set the float_status behaviour to match the Arm defaults:
462
@@ -XXX,XX +XXX,XX @@ void vfp_set_fpscr(CPUARMState *env, uint32_t val)
463
{
464
HELPER(vfp_set_fpscr)(env, val);
465
}
466
-
467
-#ifdef CONFIG_TCG
468
-
469
-#define VFP_HELPER(name, p) HELPER(glue(glue(vfp_,name),p))
470
-
471
-#define VFP_BINOP(name) \
472
-dh_ctype_f16 VFP_HELPER(name, h)(dh_ctype_f16 a, dh_ctype_f16 b, float_status *fpst) \
473
-{ \
474
- return float16_ ## name(a, b, fpst); \
475
-} \
476
-float32 VFP_HELPER(name, s)(float32 a, float32 b, float_status *fpst) \
477
-{ \
478
- return float32_ ## name(a, b, fpst); \
479
-} \
480
-float64 VFP_HELPER(name, d)(float64 a, float64 b, float_status *fpst) \
481
-{ \
482
- return float64_ ## name(a, b, fpst); \
483
-}
484
-VFP_BINOP(add)
485
-VFP_BINOP(sub)
486
-VFP_BINOP(mul)
487
-VFP_BINOP(div)
488
-VFP_BINOP(min)
489
-VFP_BINOP(max)
490
-VFP_BINOP(minnum)
491
-VFP_BINOP(maxnum)
492
-#undef VFP_BINOP
493
-
494
-dh_ctype_f16 VFP_HELPER(sqrt, h)(dh_ctype_f16 a, float_status *fpst)
495
-{
496
- return float16_sqrt(a, fpst);
497
-}
498
-
499
-float32 VFP_HELPER(sqrt, s)(float32 a, float_status *fpst)
500
-{
501
- return float32_sqrt(a, fpst);
502
-}
503
-
504
-float64 VFP_HELPER(sqrt, d)(float64 a, float_status *fpst)
505
-{
506
- return float64_sqrt(a, fpst);
507
-}
508
-
509
-static void softfloat_to_vfp_compare(CPUARMState *env, FloatRelation cmp)
510
-{
511
- uint32_t flags;
512
- switch (cmp) {
513
- case float_relation_equal:
514
- flags = 0x6;
515
- break;
516
- case float_relation_less:
517
- flags = 0x8;
518
- break;
519
- case float_relation_greater:
520
- flags = 0x2;
521
- break;
522
- case float_relation_unordered:
523
- flags = 0x3;
524
- break;
525
- default:
526
- g_assert_not_reached();
527
- }
528
- env->vfp.fpsr = deposit64(env->vfp.fpsr, 28, 4, flags); /* NZCV */
529
-}
530
-
531
-/* XXX: check quiet/signaling case */
532
-#define DO_VFP_cmp(P, FLOATTYPE, ARGTYPE, FPST) \
533
-void VFP_HELPER(cmp, P)(ARGTYPE a, ARGTYPE b, CPUARMState *env) \
534
-{ \
535
- softfloat_to_vfp_compare(env, \
536
- FLOATTYPE ## _compare_quiet(a, b, &env->vfp.fp_status[FPST])); \
537
-} \
538
-void VFP_HELPER(cmpe, P)(ARGTYPE a, ARGTYPE b, CPUARMState *env) \
539
-{ \
540
- softfloat_to_vfp_compare(env, \
541
- FLOATTYPE ## _compare(a, b, &env->vfp.fp_status[FPST])); \
542
-}
543
-DO_VFP_cmp(h, float16, dh_ctype_f16, FPST_A32_F16)
544
-DO_VFP_cmp(s, float32, float32, FPST_A32)
545
-DO_VFP_cmp(d, float64, float64, FPST_A32)
546
-#undef DO_VFP_cmp
547
-
548
-/* Integer to float and float to integer conversions */
549
-
550
-#define CONV_ITOF(name, ftype, fsz, sign) \
551
-ftype HELPER(name)(uint32_t x, float_status *fpst) \
552
-{ \
553
- return sign##int32_to_##float##fsz((sign##int32_t)x, fpst); \
554
-}
555
-
556
-#define CONV_FTOI(name, ftype, fsz, sign, round) \
557
-sign##int32_t HELPER(name)(ftype x, float_status *fpst) \
558
-{ \
559
- if (float##fsz##_is_any_nan(x)) { \
560
- float_raise(float_flag_invalid, fpst); \
561
- return 0; \
562
- } \
563
- return float##fsz##_to_##sign##int32##round(x, fpst); \
564
-}
565
-
566
-#define FLOAT_CONVS(name, p, ftype, fsz, sign) \
567
- CONV_ITOF(vfp_##name##to##p, ftype, fsz, sign) \
568
- CONV_FTOI(vfp_to##name##p, ftype, fsz, sign, ) \
569
- CONV_FTOI(vfp_to##name##z##p, ftype, fsz, sign, _round_to_zero)
570
-
571
-FLOAT_CONVS(si, h, uint32_t, 16, )
572
-FLOAT_CONVS(si, s, float32, 32, )
573
-FLOAT_CONVS(si, d, float64, 64, )
574
-FLOAT_CONVS(ui, h, uint32_t, 16, u)
575
-FLOAT_CONVS(ui, s, float32, 32, u)
576
-FLOAT_CONVS(ui, d, float64, 64, u)
577
-
578
-#undef CONV_ITOF
579
-#undef CONV_FTOI
580
-#undef FLOAT_CONVS
581
-
582
-/* floating point conversion */
583
-float64 VFP_HELPER(fcvtd, s)(float32 x, float_status *status)
584
-{
585
- return float32_to_float64(x, status);
586
-}
587
-
588
-float32 VFP_HELPER(fcvts, d)(float64 x, float_status *status)
589
-{
590
- return float64_to_float32(x, status);
591
-}
592
-
593
-uint32_t HELPER(bfcvt)(float32 x, float_status *status)
594
-{
595
- return float32_to_bfloat16(x, status);
596
-}
597
-
598
-uint32_t HELPER(bfcvt_pair)(uint64_t pair, float_status *status)
599
-{
600
- bfloat16 lo = float32_to_bfloat16(extract64(pair, 0, 32), status);
601
- bfloat16 hi = float32_to_bfloat16(extract64(pair, 32, 32), status);
602
- return deposit32(lo, 16, 16, hi);
603
-}
604
-
605
-/*
606
- * VFP3 fixed point conversion. The AArch32 versions of fix-to-float
607
- * must always round-to-nearest; the AArch64 ones honour the FPSCR
608
- * rounding mode. (For AArch32 Neon the standard-FPSCR is set to
609
- * round-to-nearest so either helper will work.) AArch32 float-to-fix
610
- * must round-to-zero.
611
- */
612
-#define VFP_CONV_FIX_FLOAT(name, p, fsz, ftype, isz, itype) \
613
-ftype HELPER(vfp_##name##to##p)(uint##isz##_t x, uint32_t shift, \
614
- float_status *fpst) \
615
-{ return itype##_to_##float##fsz##_scalbn(x, -shift, fpst); }
616
-
617
-#define VFP_CONV_FIX_FLOAT_ROUND(name, p, fsz, ftype, isz, itype) \
618
- ftype HELPER(vfp_##name##to##p##_round_to_nearest)(uint##isz##_t x, \
619
- uint32_t shift, \
620
- float_status *fpst) \
621
- { \
622
- ftype ret; \
623
- FloatRoundMode oldmode = fpst->float_rounding_mode; \
624
- fpst->float_rounding_mode = float_round_nearest_even; \
625
- ret = itype##_to_##float##fsz##_scalbn(x, -shift, fpst); \
626
- fpst->float_rounding_mode = oldmode; \
627
- return ret; \
628
- }
629
-
630
-#define VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, ftype, isz, itype, ROUND, suff) \
631
-uint##isz##_t HELPER(vfp_to##name##p##suff)(ftype x, uint32_t shift, \
632
- float_status *fpst) \
633
-{ \
634
- if (unlikely(float##fsz##_is_any_nan(x))) { \
635
- float_raise(float_flag_invalid, fpst); \
636
- return 0; \
637
- } \
638
- return float##fsz##_to_##itype##_scalbn(x, ROUND, shift, fpst); \
639
-}
640
-
641
-#define VFP_CONV_FIX(name, p, fsz, ftype, isz, itype) \
642
-VFP_CONV_FIX_FLOAT(name, p, fsz, ftype, isz, itype) \
643
-VFP_CONV_FIX_FLOAT_ROUND(name, p, fsz, ftype, isz, itype) \
644
-VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, ftype, isz, itype, \
645
- float_round_to_zero, _round_to_zero) \
646
-VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, ftype, isz, itype, \
647
- get_float_rounding_mode(fpst), )
648
-
649
-#define VFP_CONV_FIX_A64(name, p, fsz, ftype, isz, itype) \
650
-VFP_CONV_FIX_FLOAT(name, p, fsz, ftype, isz, itype) \
651
-VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, ftype, isz, itype, \
652
- get_float_rounding_mode(fpst), )
653
-
654
-VFP_CONV_FIX(sh, d, 64, float64, 64, int16)
655
-VFP_CONV_FIX(sl, d, 64, float64, 64, int32)
656
-VFP_CONV_FIX_A64(sq, d, 64, float64, 64, int64)
657
-VFP_CONV_FIX(uh, d, 64, float64, 64, uint16)
658
-VFP_CONV_FIX(ul, d, 64, float64, 64, uint32)
659
-VFP_CONV_FIX_A64(uq, d, 64, float64, 64, uint64)
660
-VFP_CONV_FIX(sh, s, 32, float32, 32, int16)
661
-VFP_CONV_FIX(sl, s, 32, float32, 32, int32)
662
-VFP_CONV_FIX_A64(sq, s, 32, float32, 64, int64)
663
-VFP_CONV_FIX(uh, s, 32, float32, 32, uint16)
664
-VFP_CONV_FIX(ul, s, 32, float32, 32, uint32)
665
-VFP_CONV_FIX_A64(uq, s, 32, float32, 64, uint64)
666
-VFP_CONV_FIX(sh, h, 16, dh_ctype_f16, 32, int16)
667
-VFP_CONV_FIX(sl, h, 16, dh_ctype_f16, 32, int32)
668
-VFP_CONV_FIX_A64(sq, h, 16, dh_ctype_f16, 64, int64)
669
-VFP_CONV_FIX(uh, h, 16, dh_ctype_f16, 32, uint16)
670
-VFP_CONV_FIX(ul, h, 16, dh_ctype_f16, 32, uint32)
671
-VFP_CONV_FIX_A64(uq, h, 16, dh_ctype_f16, 64, uint64)
672
-VFP_CONV_FLOAT_FIX_ROUND(sq, d, 64, float64, 64, int64,
673
- float_round_to_zero, _round_to_zero)
674
-VFP_CONV_FLOAT_FIX_ROUND(uq, d, 64, float64, 64, uint64,
675
- float_round_to_zero, _round_to_zero)
676
-
677
-#undef VFP_CONV_FIX
678
-#undef VFP_CONV_FIX_FLOAT
679
-#undef VFP_CONV_FLOAT_FIX_ROUND
680
-#undef VFP_CONV_FIX_A64
681
-
682
-/* Set the current fp rounding mode and return the old one.
683
- * The argument is a softfloat float_round_ value.
684
- */
685
-uint32_t HELPER(set_rmode)(uint32_t rmode, float_status *fp_status)
686
-{
687
- uint32_t prev_rmode = get_float_rounding_mode(fp_status);
688
- set_float_rounding_mode(rmode, fp_status);
689
-
690
- return prev_rmode;
691
-}
692
-
693
-/* Half precision conversions. */
694
-float32 HELPER(vfp_fcvt_f16_to_f32)(uint32_t a, float_status *fpst,
695
- uint32_t ahp_mode)
696
-{
697
- /* Squash FZ16 to 0 for the duration of conversion. In this case,
698
- * it would affect flushing input denormals.
699
- */
700
- bool save = get_flush_inputs_to_zero(fpst);
701
- set_flush_inputs_to_zero(false, fpst);
702
- float32 r = float16_to_float32(a, !ahp_mode, fpst);
703
- set_flush_inputs_to_zero(save, fpst);
704
- return r;
705
-}
706
-
707
-uint32_t HELPER(vfp_fcvt_f32_to_f16)(float32 a, float_status *fpst,
708
- uint32_t ahp_mode)
709
-{
710
- /* Squash FZ16 to 0 for the duration of conversion. In this case,
711
- * it would affect flushing output denormals.
712
- */
713
- bool save = get_flush_to_zero(fpst);
714
- set_flush_to_zero(false, fpst);
715
- float16 r = float32_to_float16(a, !ahp_mode, fpst);
716
- set_flush_to_zero(save, fpst);
717
- return r;
718
-}
719
-
720
-float64 HELPER(vfp_fcvt_f16_to_f64)(uint32_t a, float_status *fpst,
721
- uint32_t ahp_mode)
722
-{
723
- /* Squash FZ16 to 0 for the duration of conversion. In this case,
724
- * it would affect flushing input denormals.
725
- */
726
- bool save = get_flush_inputs_to_zero(fpst);
727
- set_flush_inputs_to_zero(false, fpst);
728
- float64 r = float16_to_float64(a, !ahp_mode, fpst);
729
- set_flush_inputs_to_zero(save, fpst);
730
- return r;
731
-}
732
-
733
-uint32_t HELPER(vfp_fcvt_f64_to_f16)(float64 a, float_status *fpst,
734
- uint32_t ahp_mode)
735
-{
736
- /* Squash FZ16 to 0 for the duration of conversion. In this case,
737
- * it would affect flushing output denormals.
738
- */
739
- bool save = get_flush_to_zero(fpst);
740
- set_flush_to_zero(false, fpst);
741
- float16 r = float64_to_float16(a, !ahp_mode, fpst);
742
- set_flush_to_zero(save, fpst);
743
- return r;
744
-}
745
-
746
-/* NEON helpers. */
747
-
748
-/* Constants 256 and 512 are used in some helpers; we avoid relying on
749
- * int->float conversions at run-time. */
750
-#define float64_256 make_float64(0x4070000000000000LL)
751
-#define float64_512 make_float64(0x4080000000000000LL)
752
-#define float16_maxnorm make_float16(0x7bff)
753
-#define float32_maxnorm make_float32(0x7f7fffff)
754
-#define float64_maxnorm make_float64(0x7fefffffffffffffLL)
755
-
756
-/* Reciprocal functions
757
- *
758
- * The algorithm that must be used to calculate the estimate
759
- * is specified by the ARM ARM, see FPRecipEstimate()/RecipEstimate
760
- */
761
-
762
-/* See RecipEstimate()
763
- *
764
- * input is a 9 bit fixed point number
765
- * input range 256 .. 511 for a number from 0.5 <= x < 1.0.
766
- * result range 256 .. 511 for a number from 1.0 to 511/256.
767
- */
768
-
769
-static int recip_estimate(int input)
770
-{
771
- int a, b, r;
772
- assert(256 <= input && input < 512);
773
- a = (input * 2) + 1;
774
- b = (1 << 19) / a;
775
- r = (b + 1) >> 1;
776
- assert(256 <= r && r < 512);
777
- return r;
778
-}
779
-
780
-/*
781
- * Increased precision version:
782
- * input is a 13 bit fixed point number
783
- * input range 2048 .. 4095 for a number from 0.5 <= x < 1.0.
784
- * result range 4096 .. 8191 for a number from 1.0 to 2.0
785
- */
786
-static int recip_estimate_incprec(int input)
787
-{
788
- int a, b, r;
789
- assert(2048 <= input && input < 4096);
790
- a = (input * 2) + 1;
791
- /*
792
- * The pseudocode expresses this as an operation on infinite
793
- * precision reals where it calculates 2^25 / a and then looks
794
- * at the error between that and the rounded-down-to-integer
795
- * value to see if it should instead round up. We instead
796
- * follow the same approach as the pseudocode for the 8-bit
797
- * precision version, and calculate (2 * (2^25 / a)) as an
798
- * integer so we can do the "add one and halve" to round it.
799
- * So the 1 << 26 here is correct.
800
- */
801
- b = (1 << 26) / a;
802
- r = (b + 1) >> 1;
803
- assert(4096 <= r && r < 8192);
804
- return r;
805
-}
806
-
807
-/*
808
- * Common wrapper to call recip_estimate
809
- *
810
- * The parameters are exponent and 64 bit fraction (without implicit
811
- * bit) where the binary point is nominally at bit 52. Returns a
812
- * float64 which can then be rounded to the appropriate size by the
813
- * callee.
814
- */
815
-
816
-static uint64_t call_recip_estimate(int *exp, int exp_off, uint64_t frac,
817
- bool increasedprecision)
818
-{
819
- uint32_t scaled, estimate;
820
- uint64_t result_frac;
821
- int result_exp;
822
-
823
- /* Handle sub-normals */
824
- if (*exp == 0) {
825
- if (extract64(frac, 51, 1) == 0) {
826
- *exp = -1;
827
- frac <<= 2;
828
- } else {
829
- frac <<= 1;
830
- }
831
- }
832
-
833
- if (increasedprecision) {
834
- /* scaled = UInt('1':fraction<51:41>) */
835
- scaled = deposit32(1 << 11, 0, 11, extract64(frac, 41, 11));
836
- estimate = recip_estimate_incprec(scaled);
837
- } else {
838
- /* scaled = UInt('1':fraction<51:44>) */
839
- scaled = deposit32(1 << 8, 0, 8, extract64(frac, 44, 8));
840
- estimate = recip_estimate(scaled);
841
- }
842
-
843
- result_exp = exp_off - *exp;
844
- if (increasedprecision) {
845
- result_frac = deposit64(0, 40, 12, estimate);
846
- } else {
847
- result_frac = deposit64(0, 44, 8, estimate);
848
- }
849
- if (result_exp == 0) {
850
- result_frac = deposit64(result_frac >> 1, 51, 1, 1);
851
- } else if (result_exp == -1) {
852
- result_frac = deposit64(result_frac >> 2, 50, 2, 1);
853
- result_exp = 0;
854
- }
855
-
856
- *exp = result_exp;
857
-
858
- return result_frac;
859
-}
860
-
861
-static bool round_to_inf(float_status *fpst, bool sign_bit)
862
-{
863
- switch (fpst->float_rounding_mode) {
864
- case float_round_nearest_even: /* Round to Nearest */
865
- return true;
866
- case float_round_up: /* Round to +Inf */
867
- return !sign_bit;
868
- case float_round_down: /* Round to -Inf */
869
- return sign_bit;
870
- case float_round_to_zero: /* Round to Zero */
871
- return false;
872
- default:
873
- g_assert_not_reached();
874
- }
875
-}
876
-
877
-uint32_t HELPER(recpe_f16)(uint32_t input, float_status *fpst)
878
-{
879
- float16 f16 = float16_squash_input_denormal(input, fpst);
880
- uint32_t f16_val = float16_val(f16);
881
- uint32_t f16_sign = float16_is_neg(f16);
882
- int f16_exp = extract32(f16_val, 10, 5);
883
- uint32_t f16_frac = extract32(f16_val, 0, 10);
884
- uint64_t f64_frac;
885
-
886
- if (float16_is_any_nan(f16)) {
887
- float16 nan = f16;
888
- if (float16_is_signaling_nan(f16, fpst)) {
889
- float_raise(float_flag_invalid, fpst);
890
- if (!fpst->default_nan_mode) {
891
- nan = float16_silence_nan(f16, fpst);
892
- }
893
- }
894
- if (fpst->default_nan_mode) {
895
- nan = float16_default_nan(fpst);
896
- }
897
- return nan;
898
- } else if (float16_is_infinity(f16)) {
899
- return float16_set_sign(float16_zero, float16_is_neg(f16));
900
- } else if (float16_is_zero(f16)) {
901
- float_raise(float_flag_divbyzero, fpst);
902
- return float16_set_sign(float16_infinity, float16_is_neg(f16));
903
- } else if (float16_abs(f16) < (1 << 8)) {
904
- /* Abs(value) < 2.0^-16 */
905
- float_raise(float_flag_overflow | float_flag_inexact, fpst);
906
- if (round_to_inf(fpst, f16_sign)) {
907
- return float16_set_sign(float16_infinity, f16_sign);
908
- } else {
909
- return float16_set_sign(float16_maxnorm, f16_sign);
910
- }
911
- } else if (f16_exp >= 29 && fpst->flush_to_zero) {
912
- float_raise(float_flag_underflow, fpst);
913
- return float16_set_sign(float16_zero, float16_is_neg(f16));
914
- }
915
-
916
- f64_frac = call_recip_estimate(&f16_exp, 29,
917
- ((uint64_t) f16_frac) << (52 - 10), false);
918
-
919
- /* result = sign : result_exp<4:0> : fraction<51:42> */
920
- f16_val = deposit32(0, 15, 1, f16_sign);
921
- f16_val = deposit32(f16_val, 10, 5, f16_exp);
922
- f16_val = deposit32(f16_val, 0, 10, extract64(f64_frac, 52 - 10, 10));
923
- return make_float16(f16_val);
924
-}
925
-
926
-/*
927
- * FEAT_RPRES means the f32 FRECPE has an "increased precision" variant
928
- * which is used when FPCR.AH == 1.
929
- */
930
-static float32 do_recpe_f32(float32 input, float_status *fpst, bool rpres)
931
-{
932
- float32 f32 = float32_squash_input_denormal(input, fpst);
933
- uint32_t f32_val = float32_val(f32);
934
- bool f32_sign = float32_is_neg(f32);
935
- int f32_exp = extract32(f32_val, 23, 8);
936
- uint32_t f32_frac = extract32(f32_val, 0, 23);
937
- uint64_t f64_frac;
938
-
939
- if (float32_is_any_nan(f32)) {
940
- float32 nan = f32;
941
- if (float32_is_signaling_nan(f32, fpst)) {
942
- float_raise(float_flag_invalid, fpst);
943
- if (!fpst->default_nan_mode) {
944
- nan = float32_silence_nan(f32, fpst);
945
- }
946
- }
947
- if (fpst->default_nan_mode) {
948
- nan = float32_default_nan(fpst);
949
- }
950
- return nan;
951
- } else if (float32_is_infinity(f32)) {
952
- return float32_set_sign(float32_zero, float32_is_neg(f32));
953
- } else if (float32_is_zero(f32)) {
954
- float_raise(float_flag_divbyzero, fpst);
955
- return float32_set_sign(float32_infinity, float32_is_neg(f32));
956
- } else if (float32_abs(f32) < (1ULL << 21)) {
957
- /* Abs(value) < 2.0^-128 */
958
- float_raise(float_flag_overflow | float_flag_inexact, fpst);
959
- if (round_to_inf(fpst, f32_sign)) {
960
- return float32_set_sign(float32_infinity, f32_sign);
961
- } else {
962
- return float32_set_sign(float32_maxnorm, f32_sign);
963
- }
964
- } else if (f32_exp >= 253 && fpst->flush_to_zero) {
965
- float_raise(float_flag_underflow, fpst);
966
- return float32_set_sign(float32_zero, float32_is_neg(f32));
967
- }
968
-
969
- f64_frac = call_recip_estimate(&f32_exp, 253,
970
- ((uint64_t) f32_frac) << (52 - 23), rpres);
971
-
972
- /* result = sign : result_exp<7:0> : fraction<51:29> */
973
- f32_val = deposit32(0, 31, 1, f32_sign);
974
- f32_val = deposit32(f32_val, 23, 8, f32_exp);
975
- f32_val = deposit32(f32_val, 0, 23, extract64(f64_frac, 52 - 23, 23));
976
- return make_float32(f32_val);
977
-}
978
-
979
-float32 HELPER(recpe_f32)(float32 input, float_status *fpst)
980
-{
981
- return do_recpe_f32(input, fpst, false);
982
-}
983
-
984
-float32 HELPER(recpe_rpres_f32)(float32 input, float_status *fpst)
985
-{
986
- return do_recpe_f32(input, fpst, true);
987
-}
988
-
989
-float64 HELPER(recpe_f64)(float64 input, float_status *fpst)
990
-{
991
- float64 f64 = float64_squash_input_denormal(input, fpst);
992
- uint64_t f64_val = float64_val(f64);
993
- bool f64_sign = float64_is_neg(f64);
994
- int f64_exp = extract64(f64_val, 52, 11);
995
- uint64_t f64_frac = extract64(f64_val, 0, 52);
996
-
997
- /* Deal with any special cases */
998
- if (float64_is_any_nan(f64)) {
999
- float64 nan = f64;
1000
- if (float64_is_signaling_nan(f64, fpst)) {
1001
- float_raise(float_flag_invalid, fpst);
1002
- if (!fpst->default_nan_mode) {
1003
- nan = float64_silence_nan(f64, fpst);
1004
- }
1005
- }
1006
- if (fpst->default_nan_mode) {
1007
- nan = float64_default_nan(fpst);
1008
- }
1009
- return nan;
1010
- } else if (float64_is_infinity(f64)) {
1011
- return float64_set_sign(float64_zero, float64_is_neg(f64));
1012
- } else if (float64_is_zero(f64)) {
1013
- float_raise(float_flag_divbyzero, fpst);
1014
- return float64_set_sign(float64_infinity, float64_is_neg(f64));
1015
- } else if ((f64_val & ~(1ULL << 63)) < (1ULL << 50)) {
1016
- /* Abs(value) < 2.0^-1024 */
1017
- float_raise(float_flag_overflow | float_flag_inexact, fpst);
1018
- if (round_to_inf(fpst, f64_sign)) {
1019
- return float64_set_sign(float64_infinity, f64_sign);
1020
- } else {
1021
- return float64_set_sign(float64_maxnorm, f64_sign);
1022
- }
1023
- } else if (f64_exp >= 2045 && fpst->flush_to_zero) {
1024
- float_raise(float_flag_underflow, fpst);
1025
- return float64_set_sign(float64_zero, float64_is_neg(f64));
1026
- }
1027
-
1028
- f64_frac = call_recip_estimate(&f64_exp, 2045, f64_frac, false);
1029
-
1030
- /* result = sign : result_exp<10:0> : fraction<51:0>; */
1031
- f64_val = deposit64(0, 63, 1, f64_sign);
1032
- f64_val = deposit64(f64_val, 52, 11, f64_exp);
1033
- f64_val = deposit64(f64_val, 0, 52, f64_frac);
1034
- return make_float64(f64_val);
1035
-}
1036
-
1037
-/* The algorithm that must be used to calculate the estimate
1038
- * is specified by the ARM ARM.
1039
- */
1040
-
1041
-static int do_recip_sqrt_estimate(int a)
1042
-{
1043
- int b, estimate;
1044
-
1045
- assert(128 <= a && a < 512);
1046
- if (a < 256) {
1047
- a = a * 2 + 1;
1048
- } else {
1049
- a = (a >> 1) << 1;
1050
- a = (a + 1) * 2;
1051
- }
1052
- b = 512;
1053
- while (a * (b + 1) * (b + 1) < (1 << 28)) {
1054
- b += 1;
1055
- }
1056
- estimate = (b + 1) / 2;
1057
- assert(256 <= estimate && estimate < 512);
1058
-
1059
- return estimate;
1060
-}
1061
-
1062
-static int do_recip_sqrt_estimate_incprec(int a)
1063
-{
1064
- /*
1065
- * The Arm ARM describes the 12-bit precision version of RecipSqrtEstimate
1066
- * in terms of an infinite-precision floating point calculation of a
1067
- * square root. We implement this using the same kind of pure integer
1068
- * algorithm as the 8-bit mantissa, to get the same bit-for-bit result.
1069
- */
1070
- int64_t b, estimate;
1071
-
1072
- assert(1024 <= a && a < 4096);
1073
- if (a < 2048) {
1074
- a = a * 2 + 1;
1075
- } else {
1076
- a = (a >> 1) << 1;
1077
- a = (a + 1) * 2;
1078
- }
1079
- b = 8192;
1080
- while (a * (b + 1) * (b + 1) < (1ULL << 39)) {
1081
- b += 1;
1082
- }
1083
- estimate = (b + 1) / 2;
1084
-
1085
- assert(4096 <= estimate && estimate < 8192);
1086
-
1087
- return estimate;
1088
-}
1089
-
1090
-static uint64_t recip_sqrt_estimate(int *exp , int exp_off, uint64_t frac,
1091
- bool increasedprecision)
1092
-{
1093
- int estimate;
1094
- uint32_t scaled;
1095
-
1096
- if (*exp == 0) {
1097
- while (extract64(frac, 51, 1) == 0) {
1098
- frac = frac << 1;
1099
- *exp -= 1;
1100
- }
1101
- frac = extract64(frac, 0, 51) << 1;
1102
- }
1103
-
1104
- if (increasedprecision) {
1105
- if (*exp & 1) {
1106
- /* scaled = UInt('01':fraction<51:42>) */
1107
- scaled = deposit32(1 << 10, 0, 10, extract64(frac, 42, 10));
1108
- } else {
1109
- /* scaled = UInt('1':fraction<51:41>) */
1110
- scaled = deposit32(1 << 11, 0, 11, extract64(frac, 41, 11));
1111
- }
1112
- estimate = do_recip_sqrt_estimate_incprec(scaled);
1113
- } else {
1114
- if (*exp & 1) {
1115
- /* scaled = UInt('01':fraction<51:45>) */
1116
- scaled = deposit32(1 << 7, 0, 7, extract64(frac, 45, 7));
1117
- } else {
1118
- /* scaled = UInt('1':fraction<51:44>) */
1119
- scaled = deposit32(1 << 8, 0, 8, extract64(frac, 44, 8));
1120
- }
1121
- estimate = do_recip_sqrt_estimate(scaled);
1122
- }
1123
-
1124
- *exp = (exp_off - *exp) / 2;
1125
- if (increasedprecision) {
1126
- return extract64(estimate, 0, 12) << 40;
1127
- } else {
1128
- return extract64(estimate, 0, 8) << 44;
1129
- }
1130
-}
1131
-
1132
-uint32_t HELPER(rsqrte_f16)(uint32_t input, float_status *s)
1133
-{
1134
- float16 f16 = float16_squash_input_denormal(input, s);
1135
- uint16_t val = float16_val(f16);
1136
- bool f16_sign = float16_is_neg(f16);
1137
- int f16_exp = extract32(val, 10, 5);
1138
- uint16_t f16_frac = extract32(val, 0, 10);
1139
- uint64_t f64_frac;
1140
-
1141
- if (float16_is_any_nan(f16)) {
1142
- float16 nan = f16;
1143
- if (float16_is_signaling_nan(f16, s)) {
1144
- float_raise(float_flag_invalid, s);
1145
- if (!s->default_nan_mode) {
1146
- nan = float16_silence_nan(f16, s);
1147
- }
1148
- }
1149
- if (s->default_nan_mode) {
1150
- nan = float16_default_nan(s);
1151
- }
1152
- return nan;
1153
- } else if (float16_is_zero(f16)) {
1154
- float_raise(float_flag_divbyzero, s);
1155
- return float16_set_sign(float16_infinity, f16_sign);
1156
- } else if (f16_sign) {
1157
- float_raise(float_flag_invalid, s);
1158
- return float16_default_nan(s);
1159
- } else if (float16_is_infinity(f16)) {
1160
- return float16_zero;
1161
- }
1162
-
1163
- /* Scale and normalize to a double-precision value between 0.25 and 1.0,
1164
- * preserving the parity of the exponent. */
1165
-
1166
- f64_frac = ((uint64_t) f16_frac) << (52 - 10);
1167
-
1168
- f64_frac = recip_sqrt_estimate(&f16_exp, 44, f64_frac, false);
1169
-
1170
- /* result = sign : result_exp<4:0> : estimate<7:0> : Zeros(2) */
1171
- val = deposit32(0, 15, 1, f16_sign);
1172
- val = deposit32(val, 10, 5, f16_exp);
1173
- val = deposit32(val, 2, 8, extract64(f64_frac, 52 - 8, 8));
1174
- return make_float16(val);
1175
-}
1176
-
1177
-/*
1178
- * FEAT_RPRES means the f32 FRSQRTE has an "increased precision" variant
1179
- * which is used when FPCR.AH == 1.
1180
- */
1181
-static float32 do_rsqrte_f32(float32 input, float_status *s, bool rpres)
1182
-{
1183
- float32 f32 = float32_squash_input_denormal(input, s);
1184
- uint32_t val = float32_val(f32);
1185
- uint32_t f32_sign = float32_is_neg(f32);
1186
- int f32_exp = extract32(val, 23, 8);
1187
- uint32_t f32_frac = extract32(val, 0, 23);
1188
- uint64_t f64_frac;
1189
-
1190
- if (float32_is_any_nan(f32)) {
1191
- float32 nan = f32;
1192
- if (float32_is_signaling_nan(f32, s)) {
1193
- float_raise(float_flag_invalid, s);
1194
- if (!s->default_nan_mode) {
1195
- nan = float32_silence_nan(f32, s);
1196
- }
1197
- }
1198
- if (s->default_nan_mode) {
1199
- nan = float32_default_nan(s);
1200
- }
1201
- return nan;
1202
- } else if (float32_is_zero(f32)) {
1203
- float_raise(float_flag_divbyzero, s);
1204
- return float32_set_sign(float32_infinity, float32_is_neg(f32));
1205
- } else if (float32_is_neg(f32)) {
1206
- float_raise(float_flag_invalid, s);
1207
- return float32_default_nan(s);
1208
- } else if (float32_is_infinity(f32)) {
1209
- return float32_zero;
1210
- }
1211
-
1212
- /* Scale and normalize to a double-precision value between 0.25 and 1.0,
1213
- * preserving the parity of the exponent. */
1214
-
1215
- f64_frac = ((uint64_t) f32_frac) << 29;
1216
-
1217
- f64_frac = recip_sqrt_estimate(&f32_exp, 380, f64_frac, rpres);
1218
-
1219
- /*
1220
- * result = sign : result_exp<7:0> : estimate<7:0> : Zeros(15)
1221
- * or for increased precision
1222
- * result = sign : result_exp<7:0> : estimate<11:0> : Zeros(11)
1223
- */
1224
- val = deposit32(0, 31, 1, f32_sign);
1225
- val = deposit32(val, 23, 8, f32_exp);
1226
- if (rpres) {
1227
- val = deposit32(val, 11, 12, extract64(f64_frac, 52 - 12, 12));
1228
- } else {
1229
- val = deposit32(val, 15, 8, extract64(f64_frac, 52 - 8, 8));
1230
- }
1231
- return make_float32(val);
1232
-}
1233
-
1234
-float32 HELPER(rsqrte_f32)(float32 input, float_status *s)
1235
-{
1236
- return do_rsqrte_f32(input, s, false);
1237
-}
1238
-
1239
-float32 HELPER(rsqrte_rpres_f32)(float32 input, float_status *s)
1240
-{
1241
- return do_rsqrte_f32(input, s, true);
1242
-}
1243
-
1244
-float64 HELPER(rsqrte_f64)(float64 input, float_status *s)
1245
-{
1246
- float64 f64 = float64_squash_input_denormal(input, s);
1247
- uint64_t val = float64_val(f64);
1248
- bool f64_sign = float64_is_neg(f64);
1249
- int f64_exp = extract64(val, 52, 11);
1250
- uint64_t f64_frac = extract64(val, 0, 52);
1251
-
1252
- if (float64_is_any_nan(f64)) {
1253
- float64 nan = f64;
1254
- if (float64_is_signaling_nan(f64, s)) {
1255
- float_raise(float_flag_invalid, s);
1256
- if (!s->default_nan_mode) {
1257
- nan = float64_silence_nan(f64, s);
1258
- }
1259
- }
1260
- if (s->default_nan_mode) {
1261
- nan = float64_default_nan(s);
1262
- }
1263
- return nan;
1264
- } else if (float64_is_zero(f64)) {
1265
- float_raise(float_flag_divbyzero, s);
1266
- return float64_set_sign(float64_infinity, float64_is_neg(f64));
1267
- } else if (float64_is_neg(f64)) {
1268
- float_raise(float_flag_invalid, s);
1269
- return float64_default_nan(s);
1270
- } else if (float64_is_infinity(f64)) {
1271
- return float64_zero;
1272
- }
1273
-
1274
- f64_frac = recip_sqrt_estimate(&f64_exp, 3068, f64_frac, false);
1275
-
1276
- /* result = sign : result_exp<4:0> : estimate<7:0> : Zeros(44) */
1277
- val = deposit64(0, 61, 1, f64_sign);
1278
- val = deposit64(val, 52, 11, f64_exp);
1279
- val = deposit64(val, 44, 8, extract64(f64_frac, 52 - 8, 8));
1280
- return make_float64(val);
1281
-}
1282
-
1283
-uint32_t HELPER(recpe_u32)(uint32_t a)
1284
-{
1285
- int input, estimate;
1286
-
1287
- if ((a & 0x80000000) == 0) {
1288
- return 0xffffffff;
1289
- }
1290
-
1291
- input = extract32(a, 23, 9);
1292
- estimate = recip_estimate(input);
1293
-
1294
- return deposit32(0, (32 - 9), 9, estimate);
1295
-}
1296
-
1297
-uint32_t HELPER(rsqrte_u32)(uint32_t a)
1298
-{
1299
- int estimate;
1300
-
1301
- if ((a & 0xc0000000) == 0) {
1302
- return 0xffffffff;
1303
- }
1304
-
1305
- estimate = do_recip_sqrt_estimate(extract32(a, 23, 9));
1306
-
1307
- return deposit32(0, 23, 9, estimate);
1308
-}
1309
-
1310
-/* VFPv4 fused multiply-accumulate */
1311
-dh_ctype_f16 VFP_HELPER(muladd, h)(dh_ctype_f16 a, dh_ctype_f16 b,
1312
- dh_ctype_f16 c, float_status *fpst)
1313
-{
1314
- return float16_muladd(a, b, c, 0, fpst);
1315
-}
1316
-
1317
-float32 VFP_HELPER(muladd, s)(float32 a, float32 b, float32 c,
1318
- float_status *fpst)
1319
-{
1320
- return float32_muladd(a, b, c, 0, fpst);
1321
-}
1322
-
1323
-float64 VFP_HELPER(muladd, d)(float64 a, float64 b, float64 c,
1324
- float_status *fpst)
1325
-{
1326
- return float64_muladd(a, b, c, 0, fpst);
1327
-}
1328
-
1329
-/* ARMv8 round to integral */
1330
-dh_ctype_f16 HELPER(rinth_exact)(dh_ctype_f16 x, float_status *fp_status)
1331
-{
1332
- return float16_round_to_int(x, fp_status);
1333
-}
1334
-
1335
-float32 HELPER(rints_exact)(float32 x, float_status *fp_status)
1336
-{
1337
- return float32_round_to_int(x, fp_status);
1338
-}
1339
-
1340
-float64 HELPER(rintd_exact)(float64 x, float_status *fp_status)
1341
-{
1342
- return float64_round_to_int(x, fp_status);
1343
-}
1344
-
1345
-dh_ctype_f16 HELPER(rinth)(dh_ctype_f16 x, float_status *fp_status)
1346
-{
1347
- int old_flags = get_float_exception_flags(fp_status), new_flags;
1348
- float16 ret;
1349
-
1350
- ret = float16_round_to_int(x, fp_status);
1351
-
1352
- /* Suppress any inexact exceptions the conversion produced */
1353
- if (!(old_flags & float_flag_inexact)) {
1354
- new_flags = get_float_exception_flags(fp_status);
1355
- set_float_exception_flags(new_flags & ~float_flag_inexact, fp_status);
1356
- }
1357
-
1358
- return ret;
1359
-}
1360
-
1361
-float32 HELPER(rints)(float32 x, float_status *fp_status)
1362
-{
1363
- int old_flags = get_float_exception_flags(fp_status), new_flags;
1364
- float32 ret;
1365
-
1366
- ret = float32_round_to_int(x, fp_status);
1367
-
1368
- /* Suppress any inexact exceptions the conversion produced */
1369
- if (!(old_flags & float_flag_inexact)) {
1370
- new_flags = get_float_exception_flags(fp_status);
1371
- set_float_exception_flags(new_flags & ~float_flag_inexact, fp_status);
1372
- }
1373
-
1374
- return ret;
1375
-}
1376
-
1377
-float64 HELPER(rintd)(float64 x, float_status *fp_status)
1378
-{
1379
- int old_flags = get_float_exception_flags(fp_status), new_flags;
1380
- float64 ret;
1381
-
1382
- ret = float64_round_to_int(x, fp_status);
1383
-
1384
- /* Suppress any inexact exceptions the conversion produced */
1385
- if (!(old_flags & float_flag_inexact)) {
1386
- new_flags = get_float_exception_flags(fp_status);
1387
- set_float_exception_flags(new_flags & ~float_flag_inexact, fp_status);
1388
- }
1389
-
1390
- return ret;
1391
-}
1392
-
1393
-/* Convert ARM rounding mode to softfloat */
1394
-const FloatRoundMode arm_rmode_to_sf_map[] = {
1395
- [FPROUNDING_TIEEVEN] = float_round_nearest_even,
1396
- [FPROUNDING_POSINF] = float_round_up,
1397
- [FPROUNDING_NEGINF] = float_round_down,
1398
- [FPROUNDING_ZERO] = float_round_to_zero,
1399
- [FPROUNDING_TIEAWAY] = float_round_ties_away,
1400
- [FPROUNDING_ODD] = float_round_to_odd,
1401
-};
1402
-
1403
-/*
1404
- * Implement float64 to int32_t conversion without saturation;
1405
- * the result is supplied modulo 2^32.
1406
- */
1407
-uint64_t HELPER(fjcvtzs)(float64 value, float_status *status)
1408
-{
1409
- uint32_t frac, e_old, e_new;
1410
- bool inexact;
1411
-
1412
- e_old = get_float_exception_flags(status);
1413
- set_float_exception_flags(0, status);
1414
- frac = float64_to_int32_modulo(value, float_round_to_zero, status);
1415
- e_new = get_float_exception_flags(status);
1416
- set_float_exception_flags(e_old | e_new, status);
1417
-
1418
- /* Normal inexact, denormal with flush-to-zero, or overflow or NaN */
1419
- inexact = e_new & (float_flag_inexact |
1420
- float_flag_input_denormal_flushed |
1421
- float_flag_invalid);
1422
-
1423
- /* While not inexact for IEEE FP, -0.0 is inexact for JavaScript. */
1424
- inexact |= value == float64_chs(float64_zero);
1425
-
1426
- /* Pack the result and the env->ZF representation of Z together. */
1427
- return deposit64(frac, 32, 32, inexact);
1428
-}
1429
-
1430
-uint32_t HELPER(vjcvt)(float64 value, CPUARMState *env)
1431
-{
1432
- uint64_t pair = HELPER(fjcvtzs)(value, &env->vfp.fp_status[FPST_A32]);
1433
- uint32_t result = pair;
1434
- uint32_t z = (pair >> 32) == 0;
1435
-
1436
- /* Store Z, clear NCV, in FPSCR.NZCV. */
1437
- env->vfp.fpsr = (env->vfp.fpsr & ~FPSR_NZCV_MASK) | (z * FPSR_Z);
1438
-
1439
- return result;
1440
-}
1441
-
1442
-/* Round a float32 to an integer that fits in int32_t or int64_t. */
1443
-static float32 frint_s(float32 f, float_status *fpst, int intsize)
1444
-{
1445
- int old_flags = get_float_exception_flags(fpst);
1446
- uint32_t exp = extract32(f, 23, 8);
1447
-
1448
- if (unlikely(exp == 0xff)) {
1449
- /* NaN or Inf. */
1450
- goto overflow;
1451
- }
1452
-
1453
- /* Round and re-extract the exponent. */
1454
- f = float32_round_to_int(f, fpst);
1455
- exp = extract32(f, 23, 8);
1456
-
1457
- /* Validate the range of the result. */
1458
- if (exp < 126 + intsize) {
1459
- /* abs(F) <= INT{N}_MAX */
1460
- return f;
1461
- }
1462
- if (exp == 126 + intsize) {
1463
- uint32_t sign = extract32(f, 31, 1);
1464
- uint32_t frac = extract32(f, 0, 23);
1465
- if (sign && frac == 0) {
1466
- /* F == INT{N}_MIN */
1467
- return f;
1468
- }
1469
- }
1470
-
1471
- overflow:
1472
- /*
1473
- * Raise Invalid and return INT{N}_MIN as a float. Revert any
1474
- * inexact exception float32_round_to_int may have raised.
1475
- */
1476
- set_float_exception_flags(old_flags | float_flag_invalid, fpst);
1477
- return (0x100u + 126u + intsize) << 23;
1478
-}
1479
-
1480
-float32 HELPER(frint32_s)(float32 f, float_status *fpst)
1481
-{
1482
- return frint_s(f, fpst, 32);
1483
-}
1484
-
1485
-float32 HELPER(frint64_s)(float32 f, float_status *fpst)
1486
-{
1487
- return frint_s(f, fpst, 64);
1488
-}
1489
-
1490
-/* Round a float64 to an integer that fits in int32_t or int64_t. */
1491
-static float64 frint_d(float64 f, float_status *fpst, int intsize)
1492
-{
1493
- int old_flags = get_float_exception_flags(fpst);
1494
- uint32_t exp = extract64(f, 52, 11);
1495
-
1496
- if (unlikely(exp == 0x7ff)) {
1497
- /* NaN or Inf. */
1498
- goto overflow;
1499
- }
1500
-
1501
- /* Round and re-extract the exponent. */
1502
- f = float64_round_to_int(f, fpst);
1503
- exp = extract64(f, 52, 11);
1504
-
1505
- /* Validate the range of the result. */
1506
- if (exp < 1022 + intsize) {
1507
- /* abs(F) <= INT{N}_MAX */
1508
- return f;
1509
- }
1510
- if (exp == 1022 + intsize) {
1511
- uint64_t sign = extract64(f, 63, 1);
1512
- uint64_t frac = extract64(f, 0, 52);
1513
- if (sign && frac == 0) {
1514
- /* F == INT{N}_MIN */
1515
- return f;
1516
- }
1517
- }
1518
-
1519
- overflow:
1520
- /*
1521
- * Raise Invalid and return INT{N}_MIN as a float. Revert any
1522
- * inexact exception float64_round_to_int may have raised.
1523
- */
1524
- set_float_exception_flags(old_flags | float_flag_invalid, fpst);
1525
- return (uint64_t)(0x800 + 1022 + intsize) << 52;
1526
-}
1527
-
1528
-float64 HELPER(frint32_d)(float64 f, float_status *fpst)
1529
-{
1530
- return frint_d(f, fpst, 32);
1531
-}
1532
-
1533
-float64 HELPER(frint64_d)(float64 f, float_status *fpst)
1534
-{
1535
- return frint_d(f, fpst, 64);
1536
-}
1537
-
1538
-void HELPER(check_hcr_el2_trap)(CPUARMState *env, uint32_t rt, uint32_t reg)
1539
-{
1540
- uint32_t syndrome;
1541
-
1542
- switch (reg) {
1543
- case ARM_VFP_MVFR0:
1544
- case ARM_VFP_MVFR1:
1545
- case ARM_VFP_MVFR2:
1546
- if (!(arm_hcr_el2_eff(env) & HCR_TID3)) {
1547
- return;
1548
- }
1549
- break;
1550
- case ARM_VFP_FPSID:
1551
- if (!(arm_hcr_el2_eff(env) & HCR_TID0)) {
1552
- return;
1553
- }
1554
- break;
1555
- default:
1556
- g_assert_not_reached();
1557
- }
1558
-
1559
- syndrome = ((EC_FPIDTRAP << ARM_EL_EC_SHIFT)
1560
- | ARM_EL_IL
1561
- | (1 << 24) | (0xe << 20) | (7 << 14)
1562
- | (reg << 10) | (rt << 5) | 1);
1563
-
1564
- raise_exception(env, EXCP_HYP_TRAP, syndrome, 2);
1565
-}
1566
-
1567
-#endif
1568
diff --git a/target/arm/tcg/meson.build b/target/arm/tcg/meson.build
1569
index XXXXXXX..XXXXXXX 100644
1570
--- a/target/arm/tcg/meson.build
1571
+++ b/target/arm/tcg/meson.build
1572
@@ -XXX,XX +XXX,XX @@ arm_ss.add(files(
1573
'vec_helper.c',
1574
'tlb-insns.c',
1575
'arith_helper.c',
1576
+ 'vfp_helper.c',
1577
))
1578
1579
arm_ss.add(when: 'TARGET_AARCH64', if_true: files(
1580
--
1581
2.43.0
diff view generated by jsdifflib
New patch
1
Currently the helper_vfp_get_fpscr() and helper_vfp_set_fpscr()
2
functions do the actual work of updating the FPSCR, and we have
3
wrappers vfp_get_fpscr() and vfp_set_fpscr() which we use for calls
4
from other QEMU C code.
1
5
6
Flip these around so that it is vfp_get_fpscr() and vfp_set_fpscr()
7
which do the actual work, and helper_vfp_get_fpscr() and
8
helper_vfp_set_fpscr() which are the wrappers; this allows us to move
9
them to tcg/vfp_helper.c.
10
11
Since this is the last HELPER() we had in arm/vfp_helper.c, we can
12
drop the include of helper-proto.h.
13
14
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
16
Message-id: 20250221190957.811948-3-peter.maydell@linaro.org
17
---
18
target/arm/tcg/vfp_helper.c | 10 ++++++++++
19
target/arm/vfp_helper.c | 15 ++-------------
20
2 files changed, 12 insertions(+), 13 deletions(-)
21
22
diff --git a/target/arm/tcg/vfp_helper.c b/target/arm/tcg/vfp_helper.c
23
index XXXXXXX..XXXXXXX 100644
24
--- a/target/arm/tcg/vfp_helper.c
25
+++ b/target/arm/tcg/vfp_helper.c
26
@@ -XXX,XX +XXX,XX @@ void HELPER(check_hcr_el2_trap)(CPUARMState *env, uint32_t rt, uint32_t reg)
27
28
raise_exception(env, EXCP_HYP_TRAP, syndrome, 2);
29
}
30
+
31
+uint32_t HELPER(vfp_get_fpscr)(CPUARMState *env)
32
+{
33
+ return vfp_get_fpscr(env);
34
+}
35
+
36
+void HELPER(vfp_set_fpscr)(CPUARMState *env, uint32_t val)
37
+{
38
+ vfp_set_fpscr(env, val);
39
+}
40
diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_helper.c
41
index XXXXXXX..XXXXXXX 100644
42
--- a/target/arm/vfp_helper.c
43
+++ b/target/arm/vfp_helper.c
44
@@ -XXX,XX +XXX,XX @@
45
46
#include "qemu/osdep.h"
47
#include "cpu.h"
48
-#include "exec/helper-proto.h"
49
#include "internals.h"
50
#include "cpu-features.h"
51
#include "fpu/softfloat.h"
52
@@ -XXX,XX +XXX,XX @@ uint32_t vfp_get_fpsr(CPUARMState *env)
53
return fpsr;
54
}
55
56
-uint32_t HELPER(vfp_get_fpscr)(CPUARMState *env)
57
+uint32_t vfp_get_fpscr(CPUARMState *env)
58
{
59
return (vfp_get_fpcr(env) & FPSCR_FPCR_MASK) |
60
(vfp_get_fpsr(env) & FPSCR_FPSR_MASK);
61
}
62
63
-uint32_t vfp_get_fpscr(CPUARMState *env)
64
-{
65
- return HELPER(vfp_get_fpscr)(env);
66
-}
67
-
68
void vfp_set_fpsr(CPUARMState *env, uint32_t val)
69
{
70
ARMCPU *cpu = env_archcpu(env);
71
@@ -XXX,XX +XXX,XX @@ void vfp_set_fpcr(CPUARMState *env, uint32_t val)
72
vfp_set_fpcr_masked(env, val, MAKE_64BIT_MASK(0, 32));
73
}
74
75
-void HELPER(vfp_set_fpscr)(CPUARMState *env, uint32_t val)
76
+void vfp_set_fpscr(CPUARMState *env, uint32_t val)
77
{
78
vfp_set_fpcr_masked(env, val, FPSCR_FPCR_MASK);
79
vfp_set_fpsr(env, val & FPSCR_FPSR_MASK);
80
}
81
-
82
-void vfp_set_fpscr(CPUARMState *env, uint32_t val)
83
-{
84
- HELPER(vfp_set_fpscr)(env, val);
85
-}
86
--
87
2.43.0
diff view generated by jsdifflib
1
Implement the security attribute lookups for memory accesses
1
The softfloat (i.e. TCG) specific handling for the FPCR
2
in the get_phys_addr() functions, causing these to generate
2
and FPSR is abstracted behind five functions:
3
various kinds of SecureFault for bad accesses.
3
arm_set_default_fp_behaviours
4
arm_set_ah_fp_behaviours
5
vfp_get_fpsr_from_host
6
vfp_clear_float_status_exc_flags
7
vfp_set_fpsr_to_host
4
8
5
The major subtlety in this code relates to handling of the
9
Currently we rely on the first two calling softfloat functions that
6
case when the security attributes the SAU assigns to the
10
work even in a KVM-only compile because they're defined as inline in
7
address don't match the current security state of the CPU.
11
the softfloat header file, and we provide stub versions of the last
12
three in arm/vfp_helper.c if CONFIG_TCG isn't defined.
8
13
9
In the ARM ARM pseudocode for validating instruction
14
Move the softfloat-specific versions of these functions to
10
accesses, the security attributes of the address determine
15
tcg/vfp_helper.c, and provide the non-TCG stub versions in
11
whether the Secure or NonSecure MPU state is used. At face
16
tcg-stubs.c.
12
value, handling this would require us to encode the relevant
13
bits of state into mmu_idx for both S and NS at once, which
14
would result in our needing 16 mmu indexes. Fortunately we
15
don't actually need to do this because a mismatch between
16
address attributes and CPU state means either:
17
* some kind of fault (usually a SecureFault, but in theory
18
perhaps a UserFault for unaligned access to Device memory)
19
* execution of the SG instruction in NS state from a
20
Secure & NonSecure code region
21
17
22
The purpose of SG is simply to flip the CPU into Secure
18
This lets us drop the softfloat header include and the last
23
state, so we can handle it by emulating execution of that
19
set of CONFIG_TCG ifdefs from arm/vfp_helper.c.
24
instruction directly in arm_v7m_cpu_do_interrupt(), which
25
means we can treat all the mismatch cases as "throw an
26
exception" and we don't need to encode the state of the
27
other MPU bank into our mmu_idx values.
28
29
This commit doesn't include the actual emulation of SG;
30
it also doesn't include implementation of the IDAU, which
31
is a per-board way to specify hard-coded memory attributes
32
for addresses, which override the CPU-internal SAU if they
33
specify a more secure setting than the SAU is programmed to.
34
20
35
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
21
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
36
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
22
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
37
Message-id: 1506092407-26985-15-git-send-email-peter.maydell@linaro.org
23
Message-id: 20250221190957.811948-4-peter.maydell@linaro.org
38
---
24
---
39
target/arm/internals.h | 15 ++++
25
target/arm/internals.h | 9 ++
40
target/arm/helper.c | 182 ++++++++++++++++++++++++++++++++++++++++++++++++-
26
target/arm/tcg-stubs.c | 22 ++++
41
2 files changed, 195 insertions(+), 2 deletions(-)
27
target/arm/tcg/vfp_helper.c | 228 +++++++++++++++++++++++++++++++++
28
target/arm/vfp_helper.c | 248 ------------------------------------
29
4 files changed, 259 insertions(+), 248 deletions(-)
42
30
43
diff --git a/target/arm/internals.h b/target/arm/internals.h
31
diff --git a/target/arm/internals.h b/target/arm/internals.h
44
index XXXXXXX..XXXXXXX 100644
32
index XXXXXXX..XXXXXXX 100644
45
--- a/target/arm/internals.h
33
--- a/target/arm/internals.h
46
+++ b/target/arm/internals.h
34
+++ b/target/arm/internals.h
47
@@ -XXX,XX +XXX,XX @@ FIELD(V7M_EXCRET, DCRS, 5, 1)
35
@@ -XXX,XX +XXX,XX @@ int alle1_tlbmask(CPUARMState *env);
48
FIELD(V7M_EXCRET, S, 6, 1)
36
void arm_set_default_fp_behaviours(float_status *s);
49
FIELD(V7M_EXCRET, RES1, 7, 25) /* including the must-be-1 prefix */
37
/* Set the float_status behaviour to match Arm FPCR.AH=1 behaviour */
50
38
void arm_set_ah_fp_behaviours(float_status *s);
51
+/* We use a few fake FSR values for internal purposes in M profile.
39
+/* Read the float_status info and return the appropriate FPSR value */
52
+ * M profile cores don't have A/R format FSRs, but currently our
40
+uint32_t vfp_get_fpsr_from_host(CPUARMState *env);
53
+ * get_phys_addr() code assumes A/R profile and reports failures via
41
+/* Clear the exception status flags from all float_status fields */
54
+ * an A/R format FSR value. We then translate that into the proper
42
+void vfp_clear_float_status_exc_flags(CPUARMState *env);
55
+ * M profile exception and FSR status bit in arm_v7m_cpu_do_interrupt().
43
+/*
56
+ * Mostly the FSR values we use for this are those defined for v7PMSA,
44
+ * Update float_status fields to handle the bits of the FPCR
57
+ * since we share some of that codepath. A few kinds of fault are
45
+ * specified by mask changing to the values in val.
58
+ * only for M profile and have no A/R equivalent, though, so we have
59
+ * to pick a value from the reserved range (which we never otherwise
60
+ * generate) to use for these.
61
+ * These values will never be visible to the guest.
62
+ */
46
+ */
63
+#define M_FAKE_FSR_NSC_EXEC 0xf /* NS executing in S&NSC memory */
47
+void vfp_set_fpcr_to_host(CPUARMState *env, uint32_t val, uint32_t mask);
64
+#define M_FAKE_FSR_SFAULT 0xe /* SecureFault INVTRAN, INVEP or AUVIOL */
48
49
#endif
50
diff --git a/target/arm/tcg-stubs.c b/target/arm/tcg-stubs.c
51
index XXXXXXX..XXXXXXX 100644
52
--- a/target/arm/tcg-stubs.c
53
+++ b/target/arm/tcg-stubs.c
54
@@ -XXX,XX +XXX,XX @@ void assert_hflags_rebuild_correctly(CPUARMState *env)
55
void define_tlb_insn_regs(ARMCPU *cpu)
56
{
57
}
58
+
59
+/* With KVM, we never use float_status, so these can be no-ops */
60
+void arm_set_default_fp_behaviours(float_status *s)
61
+{
62
+}
63
+
64
+void arm_set_ah_fp_behaviours(float_status *s)
65
+{
66
+}
67
+
68
+uint32_t vfp_get_fpsr_from_host(CPUARMState *env)
69
+{
70
+ return 0;
71
+}
72
+
73
+void vfp_clear_float_status_exc_flags(CPUARMState *env)
74
+{
75
+}
76
+
77
+void vfp_set_fpcr_to_host(CPUARMState *env, uint32_t val, uint32_t mask)
78
+{
79
+}
80
diff --git a/target/arm/tcg/vfp_helper.c b/target/arm/tcg/vfp_helper.c
81
index XXXXXXX..XXXXXXX 100644
82
--- a/target/arm/tcg/vfp_helper.c
83
+++ b/target/arm/tcg/vfp_helper.c
84
@@ -XXX,XX +XXX,XX @@
85
#include "fpu/softfloat.h"
86
#include "qemu/log.h"
87
88
+/*
89
+ * Set the float_status behaviour to match the Arm defaults:
90
+ * * tininess-before-rounding
91
+ * * 2-input NaN propagation prefers SNaN over QNaN, and then
92
+ * operand A over operand B (see FPProcessNaNs() pseudocode)
93
+ * * 3-input NaN propagation prefers SNaN over QNaN, and then
94
+ * operand C over A over B (see FPProcessNaNs3() pseudocode,
95
+ * but note that for QEMU muladd is a * b + c, whereas for
96
+ * the pseudocode function the arguments are in the order c, a, b.
97
+ * * 0 * Inf + NaN returns the default NaN if the input NaN is quiet,
98
+ * and the input NaN if it is signalling
99
+ * * Default NaN has sign bit clear, msb frac bit set
100
+ */
101
+void arm_set_default_fp_behaviours(float_status *s)
102
+{
103
+ set_float_detect_tininess(float_tininess_before_rounding, s);
104
+ set_float_ftz_detection(float_ftz_before_rounding, s);
105
+ set_float_2nan_prop_rule(float_2nan_prop_s_ab, s);
106
+ set_float_3nan_prop_rule(float_3nan_prop_s_cab, s);
107
+ set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, s);
108
+ set_float_default_nan_pattern(0b01000000, s);
109
+}
110
+
111
+/*
112
+ * Set the float_status behaviour to match the FEAT_AFP
113
+ * FPCR.AH=1 requirements:
114
+ * * tininess-after-rounding
115
+ * * 2-input NaN propagation prefers the first NaN
116
+ * * 3-input NaN propagation prefers a over b over c
117
+ * * 0 * Inf + NaN always returns the input NaN and doesn't
118
+ * set Invalid for a QNaN
119
+ * * default NaN has sign bit set, msb frac bit set
120
+ */
121
+void arm_set_ah_fp_behaviours(float_status *s)
122
+{
123
+ set_float_detect_tininess(float_tininess_after_rounding, s);
124
+ set_float_ftz_detection(float_ftz_after_rounding, s);
125
+ set_float_2nan_prop_rule(float_2nan_prop_ab, s);
126
+ set_float_3nan_prop_rule(float_3nan_prop_abc, s);
127
+ set_float_infzeronan_rule(float_infzeronan_dnan_never |
128
+ float_infzeronan_suppress_invalid, s);
129
+ set_float_default_nan_pattern(0b11000000, s);
130
+}
131
+
132
+/* Convert host exception flags to vfp form. */
133
+static inline uint32_t vfp_exceptbits_from_host(int host_bits, bool ah)
134
+{
135
+ uint32_t target_bits = 0;
136
+
137
+ if (host_bits & float_flag_invalid) {
138
+ target_bits |= FPSR_IOC;
139
+ }
140
+ if (host_bits & float_flag_divbyzero) {
141
+ target_bits |= FPSR_DZC;
142
+ }
143
+ if (host_bits & float_flag_overflow) {
144
+ target_bits |= FPSR_OFC;
145
+ }
146
+ if (host_bits & (float_flag_underflow | float_flag_output_denormal_flushed)) {
147
+ target_bits |= FPSR_UFC;
148
+ }
149
+ if (host_bits & float_flag_inexact) {
150
+ target_bits |= FPSR_IXC;
151
+ }
152
+ if (host_bits & float_flag_input_denormal_flushed) {
153
+ target_bits |= FPSR_IDC;
154
+ }
155
+ /*
156
+ * With FPCR.AH, IDC is set when an input denormal is used,
157
+ * and flushing an output denormal to zero sets both IXC and UFC.
158
+ */
159
+ if (ah && (host_bits & float_flag_input_denormal_used)) {
160
+ target_bits |= FPSR_IDC;
161
+ }
162
+ if (ah && (host_bits & float_flag_output_denormal_flushed)) {
163
+ target_bits |= FPSR_IXC;
164
+ }
165
+ return target_bits;
166
+}
167
+
168
+uint32_t vfp_get_fpsr_from_host(CPUARMState *env)
169
+{
170
+ uint32_t a32_flags = 0, a64_flags = 0;
171
+
172
+ a32_flags |= get_float_exception_flags(&env->vfp.fp_status[FPST_A32]);
173
+ a32_flags |= get_float_exception_flags(&env->vfp.fp_status[FPST_STD]);
174
+ /* FZ16 does not generate an input denormal exception. */
175
+ a32_flags |= (get_float_exception_flags(&env->vfp.fp_status[FPST_A32_F16])
176
+ & ~float_flag_input_denormal_flushed);
177
+ a32_flags |= (get_float_exception_flags(&env->vfp.fp_status[FPST_STD_F16])
178
+ & ~float_flag_input_denormal_flushed);
179
+
180
+ a64_flags |= get_float_exception_flags(&env->vfp.fp_status[FPST_A64]);
181
+ a64_flags |= (get_float_exception_flags(&env->vfp.fp_status[FPST_A64_F16])
182
+ & ~(float_flag_input_denormal_flushed | float_flag_input_denormal_used));
183
+ /*
184
+ * We do not merge in flags from FPST_AH or FPST_AH_F16, because
185
+ * they are used for insns that must not set the cumulative exception bits.
186
+ */
187
+
188
+ /*
189
+ * Flushing an input denormal *only* because FPCR.FIZ == 1 does
190
+ * not set FPSR.IDC; if FPCR.FZ is also set then this takes
191
+ * precedence and IDC is set (see the FPUnpackBase pseudocode).
192
+ * So squash it unless (FPCR.AH == 0 && FPCR.FZ == 1).
193
+ * We only do this for the a64 flags because FIZ has no effect
194
+ * on AArch32 even if it is set.
195
+ */
196
+ if ((env->vfp.fpcr & (FPCR_FZ | FPCR_AH)) != FPCR_FZ) {
197
+ a64_flags &= ~float_flag_input_denormal_flushed;
198
+ }
199
+ return vfp_exceptbits_from_host(a64_flags, env->vfp.fpcr & FPCR_AH) |
200
+ vfp_exceptbits_from_host(a32_flags, false);
201
+}
202
+
203
+void vfp_clear_float_status_exc_flags(CPUARMState *env)
204
+{
205
+ /*
206
+ * Clear out all the exception-flag information in the float_status
207
+ * values. The caller should have arranged for env->vfp.fpsr to
208
+ * be the architecturally up-to-date exception flag information first.
209
+ */
210
+ set_float_exception_flags(0, &env->vfp.fp_status[FPST_A32]);
211
+ set_float_exception_flags(0, &env->vfp.fp_status[FPST_A64]);
212
+ set_float_exception_flags(0, &env->vfp.fp_status[FPST_A32_F16]);
213
+ set_float_exception_flags(0, &env->vfp.fp_status[FPST_A64_F16]);
214
+ set_float_exception_flags(0, &env->vfp.fp_status[FPST_STD]);
215
+ set_float_exception_flags(0, &env->vfp.fp_status[FPST_STD_F16]);
216
+ set_float_exception_flags(0, &env->vfp.fp_status[FPST_AH]);
217
+ set_float_exception_flags(0, &env->vfp.fp_status[FPST_AH_F16]);
218
+}
219
+
220
+static void vfp_sync_and_clear_float_status_exc_flags(CPUARMState *env)
221
+{
222
+ /*
223
+ * Synchronize any pending exception-flag information in the
224
+ * float_status values into env->vfp.fpsr, and then clear out
225
+ * the float_status data.
226
+ */
227
+ env->vfp.fpsr |= vfp_get_fpsr_from_host(env);
228
+ vfp_clear_float_status_exc_flags(env);
229
+}
230
+
231
+void vfp_set_fpcr_to_host(CPUARMState *env, uint32_t val, uint32_t mask)
232
+{
233
+ uint64_t changed = env->vfp.fpcr;
234
+
235
+ changed ^= val;
236
+ changed &= mask;
237
+ if (changed & (3 << 22)) {
238
+ int i = (val >> 22) & 3;
239
+ switch (i) {
240
+ case FPROUNDING_TIEEVEN:
241
+ i = float_round_nearest_even;
242
+ break;
243
+ case FPROUNDING_POSINF:
244
+ i = float_round_up;
245
+ break;
246
+ case FPROUNDING_NEGINF:
247
+ i = float_round_down;
248
+ break;
249
+ case FPROUNDING_ZERO:
250
+ i = float_round_to_zero;
251
+ break;
252
+ }
253
+ set_float_rounding_mode(i, &env->vfp.fp_status[FPST_A32]);
254
+ set_float_rounding_mode(i, &env->vfp.fp_status[FPST_A64]);
255
+ set_float_rounding_mode(i, &env->vfp.fp_status[FPST_A32_F16]);
256
+ set_float_rounding_mode(i, &env->vfp.fp_status[FPST_A64_F16]);
257
+ }
258
+ if (changed & FPCR_FZ16) {
259
+ bool ftz_enabled = val & FPCR_FZ16;
260
+ set_flush_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_A32_F16]);
261
+ set_flush_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_A64_F16]);
262
+ set_flush_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_STD_F16]);
263
+ set_flush_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_AH_F16]);
264
+ set_flush_inputs_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_A32_F16]);
265
+ set_flush_inputs_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_A64_F16]);
266
+ set_flush_inputs_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_STD_F16]);
267
+ set_flush_inputs_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_AH_F16]);
268
+ }
269
+ if (changed & FPCR_FZ) {
270
+ bool ftz_enabled = val & FPCR_FZ;
271
+ set_flush_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_A32]);
272
+ set_flush_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_A64]);
273
+ /* FIZ is A64 only so FZ always makes A32 code flush inputs to zero */
274
+ set_flush_inputs_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_A32]);
275
+ }
276
+ if (changed & (FPCR_FZ | FPCR_AH | FPCR_FIZ)) {
277
+ /*
278
+ * A64: Flush denormalized inputs to zero if FPCR.FIZ = 1, or
279
+ * both FPCR.AH = 0 and FPCR.FZ = 1.
280
+ */
281
+ bool fitz_enabled = (val & FPCR_FIZ) ||
282
+ (val & (FPCR_FZ | FPCR_AH)) == FPCR_FZ;
283
+ set_flush_inputs_to_zero(fitz_enabled, &env->vfp.fp_status[FPST_A64]);
284
+ }
285
+ if (changed & FPCR_DN) {
286
+ bool dnan_enabled = val & FPCR_DN;
287
+ set_default_nan_mode(dnan_enabled, &env->vfp.fp_status[FPST_A32]);
288
+ set_default_nan_mode(dnan_enabled, &env->vfp.fp_status[FPST_A64]);
289
+ set_default_nan_mode(dnan_enabled, &env->vfp.fp_status[FPST_A32_F16]);
290
+ set_default_nan_mode(dnan_enabled, &env->vfp.fp_status[FPST_A64_F16]);
291
+ set_default_nan_mode(dnan_enabled, &env->vfp.fp_status[FPST_AH]);
292
+ set_default_nan_mode(dnan_enabled, &env->vfp.fp_status[FPST_AH_F16]);
293
+ }
294
+ if (changed & FPCR_AH) {
295
+ bool ah_enabled = val & FPCR_AH;
296
+
297
+ if (ah_enabled) {
298
+ /* Change behaviours for A64 FP operations */
299
+ arm_set_ah_fp_behaviours(&env->vfp.fp_status[FPST_A64]);
300
+ arm_set_ah_fp_behaviours(&env->vfp.fp_status[FPST_A64_F16]);
301
+ } else {
302
+ arm_set_default_fp_behaviours(&env->vfp.fp_status[FPST_A64]);
303
+ arm_set_default_fp_behaviours(&env->vfp.fp_status[FPST_A64_F16]);
304
+ }
305
+ }
306
+ /*
307
+ * If any bits changed that we look at in vfp_get_fpsr_from_host(),
308
+ * we must sync the float_status flags into vfp.fpsr now (under the
309
+ * old regime) before we update vfp.fpcr.
310
+ */
311
+ if (changed & (FPCR_FZ | FPCR_AH | FPCR_FIZ)) {
312
+ vfp_sync_and_clear_float_status_exc_flags(env);
313
+ }
314
+}
65
+
315
+
66
/*
316
/*
67
* For AArch64, map a given EL to an index in the banked_spsr array.
317
* VFP support. We follow the convention used for VFP instructions:
68
* Note that this mapping and the AArch32 mapping defined in bank_number()
318
* Single precision routines have a "s" suffix, double precision a
69
diff --git a/target/arm/helper.c b/target/arm/helper.c
319
diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_helper.c
70
index XXXXXXX..XXXXXXX 100644
320
index XXXXXXX..XXXXXXX 100644
71
--- a/target/arm/helper.c
321
--- a/target/arm/vfp_helper.c
72
+++ b/target/arm/helper.c
322
+++ b/target/arm/vfp_helper.c
73
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
323
@@ -XXX,XX +XXX,XX @@
74
target_ulong *page_size_ptr, uint32_t *fsr,
324
#include "cpu.h"
75
ARMMMUFaultInfo *fi);
325
#include "internals.h"
76
326
#include "cpu-features.h"
77
+/* Security attributes for an address, as returned by v8m_security_lookup. */
327
-#include "fpu/softfloat.h"
78
+typedef struct V8M_SAttributes {
328
-
79
+ bool ns;
329
-/*
80
+ bool nsc;
330
- * Set the float_status behaviour to match the Arm defaults:
81
+ uint8_t sregion;
331
- * * tininess-before-rounding
82
+ bool srvalid;
332
- * * 2-input NaN propagation prefers SNaN over QNaN, and then
83
+ uint8_t iregion;
333
- * operand A over operand B (see FPProcessNaNs() pseudocode)
84
+ bool irvalid;
334
- * * 3-input NaN propagation prefers SNaN over QNaN, and then
85
+} V8M_SAttributes;
335
- * operand C over A over B (see FPProcessNaNs3() pseudocode,
86
+
336
- * but note that for QEMU muladd is a * b + c, whereas for
87
/* Definitions for the PMCCNTR and PMCR registers */
337
- * the pseudocode function the arguments are in the order c, a, b.
88
#define PMCRD 0x8
338
- * * 0 * Inf + NaN returns the default NaN if the input NaN is quiet,
89
#define PMCRC 0x4
339
- * and the input NaN if it is signalling
90
@@ -XXX,XX +XXX,XX @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
340
- * * Default NaN has sign bit clear, msb frac bit set
91
* raises the fault, in the A profile short-descriptor format.
341
- */
92
*/
342
-void arm_set_default_fp_behaviours(float_status *s)
93
switch (env->exception.fsr & 0xf) {
343
-{
94
+ case M_FAKE_FSR_NSC_EXEC:
344
- set_float_detect_tininess(float_tininess_before_rounding, s);
95
+ /* Exception generated when we try to execute code at an address
345
- set_float_ftz_detection(float_ftz_before_rounding, s);
96
+ * which is marked as Secure & Non-Secure Callable and the CPU
346
- set_float_2nan_prop_rule(float_2nan_prop_s_ab, s);
97
+ * is in the Non-Secure state. The only instruction which can
347
- set_float_3nan_prop_rule(float_3nan_prop_s_cab, s);
98
+ * be executed like this is SG (and that only if both halves of
348
- set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, s);
99
+ * the SG instruction have the same security attributes.)
349
- set_float_default_nan_pattern(0b01000000, s);
100
+ * Everything else must generate an INVEP SecureFault, so we
350
-}
101
+ * emulate the SG instruction here.
351
-
102
+ * TODO: actually emulate SG.
352
-/*
103
+ */
353
- * Set the float_status behaviour to match the FEAT_AFP
104
+ env->v7m.sfsr |= R_V7M_SFSR_INVEP_MASK;
354
- * FPCR.AH=1 requirements:
105
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
355
- * * tininess-after-rounding
106
+ qemu_log_mask(CPU_LOG_INT,
356
- * * 2-input NaN propagation prefers the first NaN
107
+ "...really SecureFault with SFSR.INVEP\n");
357
- * * 3-input NaN propagation prefers a over b over c
108
+ break;
358
- * * 0 * Inf + NaN always returns the input NaN and doesn't
109
+ case M_FAKE_FSR_SFAULT:
359
- * set Invalid for a QNaN
110
+ /* Various flavours of SecureFault for attempts to execute or
360
- * * default NaN has sign bit set, msb frac bit set
111
+ * access data in the wrong security state.
361
- */
112
+ */
362
-void arm_set_ah_fp_behaviours(float_status *s)
113
+ switch (cs->exception_index) {
363
-{
114
+ case EXCP_PREFETCH_ABORT:
364
- set_float_detect_tininess(float_tininess_after_rounding, s);
115
+ if (env->v7m.secure) {
365
- set_float_ftz_detection(float_ftz_after_rounding, s);
116
+ env->v7m.sfsr |= R_V7M_SFSR_INVTRAN_MASK;
366
- set_float_2nan_prop_rule(float_2nan_prop_ab, s);
117
+ qemu_log_mask(CPU_LOG_INT,
367
- set_float_3nan_prop_rule(float_3nan_prop_abc, s);
118
+ "...really SecureFault with SFSR.INVTRAN\n");
368
- set_float_infzeronan_rule(float_infzeronan_dnan_never |
119
+ } else {
369
- float_infzeronan_suppress_invalid, s);
120
+ env->v7m.sfsr |= R_V7M_SFSR_INVEP_MASK;
370
- set_float_default_nan_pattern(0b11000000, s);
121
+ qemu_log_mask(CPU_LOG_INT,
371
-}
122
+ "...really SecureFault with SFSR.INVEP\n");
372
-
123
+ }
373
-#ifdef CONFIG_TCG
124
+ break;
374
-
125
+ case EXCP_DATA_ABORT:
375
-/* Convert host exception flags to vfp form. */
126
+ /* This must be an NS access to S memory */
376
-static inline uint32_t vfp_exceptbits_from_host(int host_bits, bool ah)
127
+ env->v7m.sfsr |= R_V7M_SFSR_AUVIOL_MASK;
377
-{
128
+ qemu_log_mask(CPU_LOG_INT,
378
- uint32_t target_bits = 0;
129
+ "...really SecureFault with SFSR.AUVIOL\n");
379
-
130
+ break;
380
- if (host_bits & float_flag_invalid) {
131
+ }
381
- target_bits |= FPSR_IOC;
132
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false);
382
- }
133
+ break;
383
- if (host_bits & float_flag_divbyzero) {
134
case 0x8: /* External Abort */
384
- target_bits |= FPSR_DZC;
135
switch (cs->exception_index) {
385
- }
136
case EXCP_PREFETCH_ABORT:
386
- if (host_bits & float_flag_overflow) {
137
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address,
387
- target_bits |= FPSR_OFC;
138
return !(*prot & (1 << access_type));
388
- }
139
}
389
- if (host_bits & (float_flag_underflow | float_flag_output_denormal_flushed)) {
140
390
- target_bits |= FPSR_UFC;
141
+static bool v8m_is_sau_exempt(CPUARMState *env,
391
- }
142
+ uint32_t address, MMUAccessType access_type)
392
- if (host_bits & float_flag_inexact) {
143
+{
393
- target_bits |= FPSR_IXC;
144
+ /* The architecture specifies that certain address ranges are
394
- }
145
+ * exempt from v8M SAU/IDAU checks.
395
- if (host_bits & float_flag_input_denormal_flushed) {
146
+ */
396
- target_bits |= FPSR_IDC;
147
+ return
397
- }
148
+ (access_type == MMU_INST_FETCH && m_is_system_region(env, address)) ||
398
- /*
149
+ (address >= 0xe0000000 && address <= 0xe0002fff) ||
399
- * With FPCR.AH, IDC is set when an input denormal is used,
150
+ (address >= 0xe000e000 && address <= 0xe000efff) ||
400
- * and flushing an output denormal to zero sets both IXC and UFC.
151
+ (address >= 0xe002e000 && address <= 0xe002efff) ||
401
- */
152
+ (address >= 0xe0040000 && address <= 0xe0041fff) ||
402
- if (ah && (host_bits & float_flag_input_denormal_used)) {
153
+ (address >= 0xe00ff000 && address <= 0xe00fffff);
403
- target_bits |= FPSR_IDC;
154
+}
404
- }
155
+
405
- if (ah && (host_bits & float_flag_output_denormal_flushed)) {
156
+static void v8m_security_lookup(CPUARMState *env, uint32_t address,
406
- target_bits |= FPSR_IXC;
157
+ MMUAccessType access_type, ARMMMUIdx mmu_idx,
407
- }
158
+ V8M_SAttributes *sattrs)
408
- return target_bits;
159
+{
409
-}
160
+ /* Look up the security attributes for this address. Compare the
410
-
161
+ * pseudocode SecurityCheck() function.
411
-static uint32_t vfp_get_fpsr_from_host(CPUARMState *env)
162
+ * We assume the caller has zero-initialized *sattrs.
412
-{
163
+ */
413
- uint32_t a32_flags = 0, a64_flags = 0;
164
+ ARMCPU *cpu = arm_env_get_cpu(env);
414
-
165
+ int r;
415
- a32_flags |= get_float_exception_flags(&env->vfp.fp_status[FPST_A32]);
166
+
416
- a32_flags |= get_float_exception_flags(&env->vfp.fp_status[FPST_STD]);
167
+ /* TODO: implement IDAU */
417
- /* FZ16 does not generate an input denormal exception. */
168
+
418
- a32_flags |= (get_float_exception_flags(&env->vfp.fp_status[FPST_A32_F16])
169
+ if (access_type == MMU_INST_FETCH && extract32(address, 28, 4) == 0xf) {
419
- & ~float_flag_input_denormal_flushed);
170
+ /* 0xf0000000..0xffffffff is always S for insn fetches */
420
- a32_flags |= (get_float_exception_flags(&env->vfp.fp_status[FPST_STD_F16])
171
+ return;
421
- & ~float_flag_input_denormal_flushed);
172
+ }
422
-
173
+
423
- a64_flags |= get_float_exception_flags(&env->vfp.fp_status[FPST_A64]);
174
+ if (v8m_is_sau_exempt(env, address, access_type)) {
424
- a64_flags |= (get_float_exception_flags(&env->vfp.fp_status[FPST_A64_F16])
175
+ sattrs->ns = !regime_is_secure(env, mmu_idx);
425
- & ~(float_flag_input_denormal_flushed | float_flag_input_denormal_used));
176
+ return;
426
- /*
177
+ }
427
- * We do not merge in flags from FPST_AH or FPST_AH_F16, because
178
+
428
- * they are used for insns that must not set the cumulative exception bits.
179
+ switch (env->sau.ctrl & 3) {
429
- */
180
+ case 0: /* SAU.ENABLE == 0, SAU.ALLNS == 0 */
430
-
181
+ break;
431
- /*
182
+ case 2: /* SAU.ENABLE == 0, SAU.ALLNS == 1 */
432
- * Flushing an input denormal *only* because FPCR.FIZ == 1 does
183
+ sattrs->ns = true;
433
- * not set FPSR.IDC; if FPCR.FZ is also set then this takes
184
+ break;
434
- * precedence and IDC is set (see the FPUnpackBase pseudocode).
185
+ default: /* SAU.ENABLE == 1 */
435
- * So squash it unless (FPCR.AH == 0 && FPCR.FZ == 1).
186
+ for (r = 0; r < cpu->sau_sregion; r++) {
436
- * We only do this for the a64 flags because FIZ has no effect
187
+ if (env->sau.rlar[r] & 1) {
437
- * on AArch32 even if it is set.
188
+ uint32_t base = env->sau.rbar[r] & ~0x1f;
438
- */
189
+ uint32_t limit = env->sau.rlar[r] | 0x1f;
439
- if ((env->vfp.fpcr & (FPCR_FZ | FPCR_AH)) != FPCR_FZ) {
190
+
440
- a64_flags &= ~float_flag_input_denormal_flushed;
191
+ if (base <= address && limit >= address) {
441
- }
192
+ if (sattrs->srvalid) {
442
- return vfp_exceptbits_from_host(a64_flags, env->vfp.fpcr & FPCR_AH) |
193
+ /* If we hit in more than one region then we must report
443
- vfp_exceptbits_from_host(a32_flags, false);
194
+ * as Secure, not NS-Callable, with no valid region
444
-}
195
+ * number info.
445
-
196
+ */
446
-static void vfp_clear_float_status_exc_flags(CPUARMState *env)
197
+ sattrs->ns = false;
447
-{
198
+ sattrs->nsc = false;
448
- /*
199
+ sattrs->sregion = 0;
449
- * Clear out all the exception-flag information in the float_status
200
+ sattrs->srvalid = false;
450
- * values. The caller should have arranged for env->vfp.fpsr to
201
+ break;
451
- * be the architecturally up-to-date exception flag information first.
202
+ } else {
452
- */
203
+ if (env->sau.rlar[r] & 2) {
453
- set_float_exception_flags(0, &env->vfp.fp_status[FPST_A32]);
204
+ sattrs->nsc = true;
454
- set_float_exception_flags(0, &env->vfp.fp_status[FPST_A64]);
205
+ } else {
455
- set_float_exception_flags(0, &env->vfp.fp_status[FPST_A32_F16]);
206
+ sattrs->ns = true;
456
- set_float_exception_flags(0, &env->vfp.fp_status[FPST_A64_F16]);
207
+ }
457
- set_float_exception_flags(0, &env->vfp.fp_status[FPST_STD]);
208
+ sattrs->srvalid = true;
458
- set_float_exception_flags(0, &env->vfp.fp_status[FPST_STD_F16]);
209
+ sattrs->sregion = r;
459
- set_float_exception_flags(0, &env->vfp.fp_status[FPST_AH]);
210
+ }
460
- set_float_exception_flags(0, &env->vfp.fp_status[FPST_AH_F16]);
211
+ }
461
-}
212
+ }
462
-
213
+ }
463
-static void vfp_sync_and_clear_float_status_exc_flags(CPUARMState *env)
214
+
464
-{
215
+ /* TODO when we support the IDAU then it may override the result here */
465
- /*
216
+ break;
466
- * Synchronize any pending exception-flag information in the
217
+ }
467
- * float_status values into env->vfp.fpsr, and then clear out
218
+}
468
- * the float_status data.
219
+
469
- */
220
static bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address,
470
- env->vfp.fpsr |= vfp_get_fpsr_from_host(env);
221
MMUAccessType access_type, ARMMMUIdx mmu_idx,
471
- vfp_clear_float_status_exc_flags(env);
222
- hwaddr *phys_ptr, int *prot, uint32_t *fsr)
472
-}
223
+ hwaddr *phys_ptr, MemTxAttrs *txattrs,
473
-
224
+ int *prot, uint32_t *fsr)
474
-static void vfp_set_fpcr_to_host(CPUARMState *env, uint32_t val, uint32_t mask)
475
-{
476
- uint64_t changed = env->vfp.fpcr;
477
-
478
- changed ^= val;
479
- changed &= mask;
480
- if (changed & (3 << 22)) {
481
- int i = (val >> 22) & 3;
482
- switch (i) {
483
- case FPROUNDING_TIEEVEN:
484
- i = float_round_nearest_even;
485
- break;
486
- case FPROUNDING_POSINF:
487
- i = float_round_up;
488
- break;
489
- case FPROUNDING_NEGINF:
490
- i = float_round_down;
491
- break;
492
- case FPROUNDING_ZERO:
493
- i = float_round_to_zero;
494
- break;
495
- }
496
- set_float_rounding_mode(i, &env->vfp.fp_status[FPST_A32]);
497
- set_float_rounding_mode(i, &env->vfp.fp_status[FPST_A64]);
498
- set_float_rounding_mode(i, &env->vfp.fp_status[FPST_A32_F16]);
499
- set_float_rounding_mode(i, &env->vfp.fp_status[FPST_A64_F16]);
500
- }
501
- if (changed & FPCR_FZ16) {
502
- bool ftz_enabled = val & FPCR_FZ16;
503
- set_flush_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_A32_F16]);
504
- set_flush_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_A64_F16]);
505
- set_flush_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_STD_F16]);
506
- set_flush_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_AH_F16]);
507
- set_flush_inputs_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_A32_F16]);
508
- set_flush_inputs_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_A64_F16]);
509
- set_flush_inputs_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_STD_F16]);
510
- set_flush_inputs_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_AH_F16]);
511
- }
512
- if (changed & FPCR_FZ) {
513
- bool ftz_enabled = val & FPCR_FZ;
514
- set_flush_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_A32]);
515
- set_flush_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_A64]);
516
- /* FIZ is A64 only so FZ always makes A32 code flush inputs to zero */
517
- set_flush_inputs_to_zero(ftz_enabled, &env->vfp.fp_status[FPST_A32]);
518
- }
519
- if (changed & (FPCR_FZ | FPCR_AH | FPCR_FIZ)) {
520
- /*
521
- * A64: Flush denormalized inputs to zero if FPCR.FIZ = 1, or
522
- * both FPCR.AH = 0 and FPCR.FZ = 1.
523
- */
524
- bool fitz_enabled = (val & FPCR_FIZ) ||
525
- (val & (FPCR_FZ | FPCR_AH)) == FPCR_FZ;
526
- set_flush_inputs_to_zero(fitz_enabled, &env->vfp.fp_status[FPST_A64]);
527
- }
528
- if (changed & FPCR_DN) {
529
- bool dnan_enabled = val & FPCR_DN;
530
- set_default_nan_mode(dnan_enabled, &env->vfp.fp_status[FPST_A32]);
531
- set_default_nan_mode(dnan_enabled, &env->vfp.fp_status[FPST_A64]);
532
- set_default_nan_mode(dnan_enabled, &env->vfp.fp_status[FPST_A32_F16]);
533
- set_default_nan_mode(dnan_enabled, &env->vfp.fp_status[FPST_A64_F16]);
534
- set_default_nan_mode(dnan_enabled, &env->vfp.fp_status[FPST_AH]);
535
- set_default_nan_mode(dnan_enabled, &env->vfp.fp_status[FPST_AH_F16]);
536
- }
537
- if (changed & FPCR_AH) {
538
- bool ah_enabled = val & FPCR_AH;
539
-
540
- if (ah_enabled) {
541
- /* Change behaviours for A64 FP operations */
542
- arm_set_ah_fp_behaviours(&env->vfp.fp_status[FPST_A64]);
543
- arm_set_ah_fp_behaviours(&env->vfp.fp_status[FPST_A64_F16]);
544
- } else {
545
- arm_set_default_fp_behaviours(&env->vfp.fp_status[FPST_A64]);
546
- arm_set_default_fp_behaviours(&env->vfp.fp_status[FPST_A64_F16]);
547
- }
548
- }
549
- /*
550
- * If any bits changed that we look at in vfp_get_fpsr_from_host(),
551
- * we must sync the float_status flags into vfp.fpsr now (under the
552
- * old regime) before we update vfp.fpcr.
553
- */
554
- if (changed & (FPCR_FZ | FPCR_AH | FPCR_FIZ)) {
555
- vfp_sync_and_clear_float_status_exc_flags(env);
556
- }
557
-}
558
-
559
-#else
560
-
561
-static uint32_t vfp_get_fpsr_from_host(CPUARMState *env)
562
-{
563
- return 0;
564
-}
565
-
566
-static void vfp_clear_float_status_exc_flags(CPUARMState *env)
567
-{
568
-}
569
-
570
-static void vfp_set_fpcr_to_host(CPUARMState *env, uint32_t val, uint32_t mask)
571
-{
572
-}
573
-
574
-#endif
575
576
uint32_t vfp_get_fpcr(CPUARMState *env)
225
{
577
{
226
ARMCPU *cpu = arm_env_get_cpu(env);
227
bool is_user = regime_is_user(env, mmu_idx);
228
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address,
229
int n;
230
int matchregion = -1;
231
bool hit = false;
232
+ V8M_SAttributes sattrs = {};
233
234
*phys_ptr = address;
235
*prot = 0;
236
237
+ if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
238
+ v8m_security_lookup(env, address, access_type, mmu_idx, &sattrs);
239
+ if (access_type == MMU_INST_FETCH) {
240
+ /* Instruction fetches always use the MMU bank and the
241
+ * transaction attribute determined by the fetch address,
242
+ * regardless of CPU state. This is painful for QEMU
243
+ * to handle, because it would mean we need to encode
244
+ * into the mmu_idx not just the (user, negpri) information
245
+ * for the current security state but also that for the
246
+ * other security state, which would balloon the number
247
+ * of mmu_idx values needed alarmingly.
248
+ * Fortunately we can avoid this because it's not actually
249
+ * possible to arbitrarily execute code from memory with
250
+ * the wrong security attribute: it will always generate
251
+ * an exception of some kind or another, apart from the
252
+ * special case of an NS CPU executing an SG instruction
253
+ * in S&NSC memory. So we always just fail the translation
254
+ * here and sort things out in the exception handler
255
+ * (including possibly emulating an SG instruction).
256
+ */
257
+ if (sattrs.ns != !secure) {
258
+ *fsr = sattrs.nsc ? M_FAKE_FSR_NSC_EXEC : M_FAKE_FSR_SFAULT;
259
+ return true;
260
+ }
261
+ } else {
262
+ /* For data accesses we always use the MMU bank indicated
263
+ * by the current CPU state, but the security attributes
264
+ * might downgrade a secure access to nonsecure.
265
+ */
266
+ if (sattrs.ns) {
267
+ txattrs->secure = false;
268
+ } else if (!secure) {
269
+ /* NS access to S memory must fault.
270
+ * Architecturally we should first check whether the
271
+ * MPU information for this address indicates that we
272
+ * are doing an unaligned access to Device memory, which
273
+ * should generate a UsageFault instead. QEMU does not
274
+ * currently check for that kind of unaligned access though.
275
+ * If we added it we would need to do so as a special case
276
+ * for M_FAKE_FSR_SFAULT in arm_v7m_cpu_do_interrupt().
277
+ */
278
+ *fsr = M_FAKE_FSR_SFAULT;
279
+ return true;
280
+ }
281
+ }
282
+ }
283
+
284
/* Unlike the ARM ARM pseudocode, we don't need to check whether this
285
* was an exception vector read from the vector table (which is always
286
* done using the default system address map), because those accesses
287
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr(CPUARMState *env, target_ulong address,
288
if (arm_feature(env, ARM_FEATURE_V8)) {
289
/* PMSAv8 */
290
ret = get_phys_addr_pmsav8(env, address, access_type, mmu_idx,
291
- phys_ptr, prot, fsr);
292
+ phys_ptr, attrs, prot, fsr);
293
} else if (arm_feature(env, ARM_FEATURE_V7)) {
294
/* PMSAv7 */
295
ret = get_phys_addr_pmsav7(env, address, access_type, mmu_idx,
296
--
578
--
297
2.7.4
579
2.43.0
298
299
diff view generated by jsdifflib
New patch
1
The vfp_helper.c in the target/arm directory now only has
2
code for handling FPSCR/FPCR/FPSR in it, and no helper
3
functions. Rename it to vfp_fpscr.c; this helps keep it
4
distinct from tcg/vfp_helper.c.
1
5
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20250221190957.811948-5-peter.maydell@linaro.org
9
---
10
target/arm/{vfp_helper.c => vfp_fpscr.c} | 2 +-
11
target/arm/meson.build | 2 +-
12
2 files changed, 2 insertions(+), 2 deletions(-)
13
rename target/arm/{vfp_helper.c => vfp_fpscr.c} (98%)
14
15
diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_fpscr.c
16
similarity index 98%
17
rename from target/arm/vfp_helper.c
18
rename to target/arm/vfp_fpscr.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/target/arm/vfp_helper.c
21
+++ b/target/arm/vfp_fpscr.c
22
@@ -XXX,XX +XXX,XX @@
23
/*
24
- * ARM VFP floating-point operations
25
+ * ARM VFP floating-point: handling of FPSCR/FPCR/FPSR
26
*
27
* Copyright (c) 2003 Fabrice Bellard
28
*
29
diff --git a/target/arm/meson.build b/target/arm/meson.build
30
index XXXXXXX..XXXXXXX 100644
31
--- a/target/arm/meson.build
32
+++ b/target/arm/meson.build
33
@@ -XXX,XX +XXX,XX @@ arm_ss.add(files(
34
'debug_helper.c',
35
'gdbstub.c',
36
'helper.c',
37
- 'vfp_helper.c',
38
+ 'vfp_fpscr.c',
39
))
40
arm_ss.add(zlib)
41
42
--
43
2.43.0
diff view generated by jsdifflib
New patch
1
From: Joelle van Dyne <j@getutm.app>
1
2
3
macOS 15.2's Hypervisor.framework exposes SME feature on M4 Macs.
4
However, QEMU's hvf accelerator code does not properly support it
5
yet, causing QEMU to fail to start when hvf accelerator is used on
6
these systems, with the error message:
7
8
qemu-aarch64-softmmu: cannot disable sme4224
9
All SME vector lengths are disabled.
10
With SME enabled, at least one vector length must be enabled.
11
12
Ideally we would have SME support on these hosts; however, until that
13
point, we must suppress the SME feature in the ID registers, so that
14
users can at least run non-SME guests.
15
16
Cc: qemu-stable@nongnu.org
17
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2665
18
Signed-off-by: Joelle van Dyne <j@getutm.app>
19
Message-id: 20250224165735.36792-1-j@getutm.app
20
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
21
[PMM: expanded commit message, comment]
22
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
23
---
24
target/arm/hvf/hvf.c | 12 ++++++++++++
25
1 file changed, 12 insertions(+)
26
27
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
28
index XXXXXXX..XXXXXXX 100644
29
--- a/target/arm/hvf/hvf.c
30
+++ b/target/arm/hvf/hvf.c
31
@@ -XXX,XX +XXX,XX @@ static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
32
33
clamp_id_aa64mmfr0_parange_to_ipa_size(&host_isar.id_aa64mmfr0);
34
35
+ /*
36
+ * Disable SME, which is not properly handled by QEMU hvf yet.
37
+ * To allow this through we would need to:
38
+ * - make sure that the SME state is correctly handled in the
39
+ * get_registers/put_registers functions
40
+ * - get the SME-specific CPU properties to work with accelerators
41
+ * other than TCG
42
+ * - fix any assumptions we made that SME implies SVE (since
43
+ * on the M4 there is SME but not SVE)
44
+ */
45
+ host_isar.id_aa64pfr1 &= ~R_ID_AA64PFR1_SME_MASK;
46
+
47
ahcf->isar = host_isar;
48
49
/*
50
--
51
2.43.0
diff view generated by jsdifflib
1
From: Michael Olbrich <m.olbrich@pengutronix.de>
1
From: Joelle van Dyne <j@getutm.app>
2
2
3
The current code checks if the next block exceeds the size of the card.
3
In the syndrome value for a data abort, bit 21 is SSE, which is
4
This generates an error while reading the last block of the card.
4
set to indicate that the abort was on a sign-extending load. When
5
Do the out-of-bounds check when starting to read a new block to fix this.
5
we handle the data abort from the guest via address_space_read(),
6
6
we forgot to handle this and so would return the wrong value if
7
This issue became visible with increased error checking in Linux 4.13.
7
the guest did a sign-extending load to an MMIO region. Add the
8
sign-extension of the returned data.
8
9
9
Cc: qemu-stable@nongnu.org
10
Cc: qemu-stable@nongnu.org
10
Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
11
Signed-off-by: Joelle van Dyne <j@getutm.app>
11
Reviewed-by: Alistair Francis <alistair.francis@xilinx.com>
12
Message-id: 20250224184123.50780-1-j@getutm.app
12
Message-id: 20170916091611.10241-1-m.olbrich@pengutronix.de
13
[PMM: Drop an unnecessary check on 'len'; expand commit message]
14
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
---
16
---
15
hw/sd/sd.c | 12 ++++++------
17
target/arm/hvf/hvf.c | 4 ++++
16
1 file changed, 6 insertions(+), 6 deletions(-)
18
1 file changed, 4 insertions(+)
17
19
18
diff --git a/hw/sd/sd.c b/hw/sd/sd.c
20
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
19
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
20
--- a/hw/sd/sd.c
22
--- a/target/arm/hvf/hvf.c
21
+++ b/hw/sd/sd.c
23
+++ b/target/arm/hvf/hvf.c
22
@@ -XXX,XX +XXX,XX @@ uint8_t sd_read_data(SDState *sd)
24
@@ -XXX,XX +XXX,XX @@ int hvf_vcpu_exec(CPUState *cpu)
23
break;
25
bool isv = syndrome & ARM_EL_ISV;
24
26
bool iswrite = (syndrome >> 6) & 1;
25
case 18:    /* CMD18: READ_MULTIPLE_BLOCK */
27
bool s1ptw = (syndrome >> 7) & 1;
26
- if (sd->data_offset == 0)
28
+ bool sse = (syndrome >> 21) & 1;
27
+ if (sd->data_offset == 0) {
29
uint32_t sas = (syndrome >> 22) & 3;
28
+ if (sd->data_start + io_len > sd->size) {
30
uint32_t len = 1 << sas;
29
+ sd->card_status |= ADDRESS_ERROR;
31
uint32_t srt = (syndrome >> 16) & 0x1f;
30
+ return 0x00;
32
@@ -XXX,XX +XXX,XX @@ int hvf_vcpu_exec(CPUState *cpu)
33
address_space_read(&address_space_memory,
34
hvf_exit->exception.physical_address,
35
MEMTXATTRS_UNSPECIFIED, &val, len);
36
+ if (sse) {
37
+ val = sextract64(val, 0, len * 8);
31
+ }
38
+ }
32
BLK_READ_BLOCK(sd->data_start, io_len);
39
hvf_set_reg(cpu, srt, val);
33
+ }
34
ret = sd->data[sd->data_offset ++];
35
36
if (sd->data_offset >= io_len) {
37
@@ -XXX,XX +XXX,XX @@ uint8_t sd_read_data(SDState *sd)
38
break;
39
}
40
}
41
-
42
- if (sd->data_start + io_len > sd->size) {
43
- sd->card_status |= ADDRESS_ERROR;
44
- break;
45
- }
46
}
40
}
47
break;
48
41
49
--
42
--
50
2.7.4
43
2.43.0
51
52
diff view generated by jsdifflib
New patch
1
From: Pierrick Bouvier <pierrick.bouvier@linaro.org>
1
2
3
Regression introduced by cf76c4
4
(hw/misc: Add nr_regs and cold_reset_values to NPCM CLK)
5
6
cold_reset_values has a different size, depending on device used
7
(NPCM7xx vs NPCM8xx). However, s->regs has a fixed size, which matches
8
NPCM8xx. Thus, when initializing a NPCM7xx, we go past cold_reset_values
9
ending.
10
11
Report by asan:
12
==2066==ERROR: AddressSanitizer: global-buffer-overflow on address 0x55d68a3e97f0 at pc 0x7fcaf2b2d14b bp 0x7ffff0cc3890 sp 0x7ffff0cc3040
13
READ of size 196 at 0x55d68a3e97f0 thread T0
14
#0 0x7fcaf2b2d14a in __interceptor_memcpy ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:827
15
#1 0x55d688447e0d in memcpy /usr/include/x86_64-linux-gnu/bits/string_fortified.h:29
16
#2 0x55d688447e0d in npcm_clk_enter_reset ../hw/misc/npcm_clk.c:968
17
#3 0x55d6899b7213 in resettable_phase_enter ../hw/core/resettable.c:136
18
#4 0x55d6899a1ef7 in bus_reset_child_foreach ../hw/core/bus.c:97
19
#5 0x55d6899b717d in resettable_child_foreach ../hw/core/resettable.c:92
20
#6 0x55d6899b717d in resettable_phase_enter ../hw/core/resettable.c:129
21
#7 0x55d6899b4ead in resettable_container_child_foreach ../hw/core/resetcontainer.c:54
22
#8 0x55d6899b717d in resettable_child_foreach ../hw/core/resettable.c:92
23
#9 0x55d6899b717d in resettable_phase_enter ../hw/core/resettable.c:129
24
#10 0x55d6899b7bfa in resettable_assert_reset ../hw/core/resettable.c:55
25
#11 0x55d6899b8666 in resettable_reset ../hw/core/resettable.c:45
26
#12 0x55d688d15cd2 in qemu_system_reset ../system/runstate.c:527
27
#13 0x55d687fc5edd in qdev_machine_creation_done ../hw/core/machine.c:1738
28
#14 0x55d688d209bd in qemu_machine_creation_done ../system/vl.c:2779
29
#15 0x55d688d209bd in qmp_x_exit_preconfig ../system/vl.c:2807
30
#16 0x55d688d281fb in qemu_init ../system/vl.c:3838
31
#17 0x55d687ceab12 in main ../system/main.c:68
32
#18 0x7fcaef006249 (/lib/x86_64-linux-gnu/libc.so.6+0x27249)
33
#19 0x7fcaef006304 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x27304)
34
#20 0x55d687cf0010 in _start (/home/runner/work/qemu-ci/qemu-ci/build/qemu-system-arm+0x371c010)
35
36
0x55d68a3e97f0 is located 0 bytes to the right of global variable 'npcm7xx_cold_reset_values' defined in '../hw/misc/npcm_clk.c:134:23' (0x55d68a3e9780) of size 112
37
38
Impacted tests:
39
Summary of Failures:
40
41
check:
42
2/747 qemu:qtest+qtest-aarch64 / qtest-aarch64/qom-test ERROR 9.28s killed by signal 6 SIGABRT
43
4/747 qemu:qtest+qtest-arm / qtest-arm/qom-test ERROR 7.82s killed by signal 6 SIGABRT
44
32/747 qemu:qtest+qtest-aarch64 / qtest-aarch64/device-introspect-test ERROR 10.91s killed by signal 6 SIGABRT
45
35/747 qemu:qtest+qtest-arm / qtest-arm/device-introspect-test ERROR 11.33s killed by signal 6 SIGABRT
46
114/747 qemu:qtest+qtest-arm / qtest-arm/npcm7xx_pwm-test ERROR 0.98s killed by signal 6 SIGABRT
47
115/747 qemu:qtest+qtest-aarch64 / qtest-aarch64/test-hmp ERROR 2.95s killed by signal 6 SIGABRT
48
117/747 qemu:qtest+qtest-arm / qtest-arm/test-hmp ERROR 2.54s killed by signal 6 SIGABRT
49
151/747 qemu:qtest+qtest-arm / qtest-arm/npcm7xx_watchdog_timer-test ERROR 0.96s killed by signal 6 SIGABRT
50
247/747 qemu:qtest+qtest-arm / qtest-arm/npcm7xx_adc-test ERROR 0.96s killed by signal 6 SIGABRT
51
248/747 qemu:qtest+qtest-arm / qtest-arm/npcm7xx_gpio-test ERROR 1.05s killed by signal 6 SIGABRT
52
249/747 qemu:qtest+qtest-arm / qtest-arm/npcm7xx_rng-test ERROR 0.97s killed by signal 6 SIGABRT
53
250/747 qemu:qtest+qtest-arm / qtest-arm/npcm7xx_sdhci-test ERROR 0.97s killed by signal 6 SIGABRT
54
251/747 qemu:qtest+qtest-arm / qtest-arm/npcm7xx_smbus-test ERROR 0.89s killed by signal 6 SIGABRT
55
252/747 qemu:qtest+qtest-arm / qtest-arm/npcm7xx_timer-test ERROR 1.09s killed by signal 6 SIGABRT
56
253/747 qemu:qtest+qtest-arm / qtest-arm/npcm_gmac-test ERROR 1.12s killed by signal 6 SIGABRT
57
255/747 qemu:qtest+qtest-arm / qtest-arm/npcm7xx_emc-test ERROR 1.05s killed by signal 6 SIGABRT
58
59
check-functional:
60
22/203 qemu:func-thorough+func-arm-thorough+thorough / func-arm-arm_quanta_gsj ERROR 0.79s exit status 1
61
38/203 qemu:func-quick+func-aarch64 / func-aarch64-migration ERROR 1.97s exit status 1
62
45/203 qemu:func-quick+func-arm / func-arm-migration ERROR 1.90s exit status 1
63
64
Fixes: cf76c4e174e1 ("hw/misc: Add nr_regs and cold_reset_values to NPCM CLK")
65
Signed-off-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
66
Reviewed-by: Hao Wu <wuhaotsh@google.com>
67
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
68
---
69
hw/misc/npcm_clk.c | 5 +++--
70
1 file changed, 3 insertions(+), 2 deletions(-)
71
72
diff --git a/hw/misc/npcm_clk.c b/hw/misc/npcm_clk.c
73
index XXXXXXX..XXXXXXX 100644
74
--- a/hw/misc/npcm_clk.c
75
+++ b/hw/misc/npcm_clk.c
76
@@ -XXX,XX +XXX,XX @@ static void npcm_clk_enter_reset(Object *obj, ResetType type)
77
NPCMCLKState *s = NPCM_CLK(obj);
78
NPCMCLKClass *c = NPCM_CLK_GET_CLASS(s);
79
80
- g_assert(sizeof(s->regs) >= c->nr_regs * sizeof(uint32_t));
81
- memcpy(s->regs, c->cold_reset_values, sizeof(s->regs));
82
+ size_t sizeof_regs = c->nr_regs * sizeof(uint32_t);
83
+ g_assert(sizeof(s->regs) >= sizeof_regs);
84
+ memcpy(s->regs, c->cold_reset_values, sizeof_regs);
85
s->ref_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
86
npcm7xx_clk_update_all_clocks(s);
87
/*
88
--
89
2.43.0
diff view generated by jsdifflib
New patch
1
From: Bernhard Beschow <shentey@gmail.com>
1
2
3
While at it add missing GUSB2RHBCTL register as found in i.MX 8M Plus reference
4
manual.
5
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
8
Message-id: 20250223114708.1780-2-shentey@gmail.com
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
11
include/hw/usb/hcd-dwc3.h | 2 +-
12
hw/usb/hcd-dwc3.c | 5 +++++
13
2 files changed, 6 insertions(+), 1 deletion(-)
14
15
diff --git a/include/hw/usb/hcd-dwc3.h b/include/hw/usb/hcd-dwc3.h
16
index XXXXXXX..XXXXXXX 100644
17
--- a/include/hw/usb/hcd-dwc3.h
18
+++ b/include/hw/usb/hcd-dwc3.h
19
@@ -XXX,XX +XXX,XX @@
20
#define USB_DWC3(obj) \
21
OBJECT_CHECK(USBDWC3, (obj), TYPE_USB_DWC3)
22
23
-#define USB_DWC3_R_MAX ((0x530 / 4) + 1)
24
+#define USB_DWC3_R_MAX (0x600 / 4)
25
#define DWC3_SIZE 0x10000
26
27
typedef struct USBDWC3 {
28
diff --git a/hw/usb/hcd-dwc3.c b/hw/usb/hcd-dwc3.c
29
index XXXXXXX..XXXXXXX 100644
30
--- a/hw/usb/hcd-dwc3.c
31
+++ b/hw/usb/hcd-dwc3.c
32
@@ -XXX,XX +XXX,XX @@ REG32(GFLADJ, 0x530)
33
FIELD(GFLADJ, GFLADJ_REFCLK_FLADJ, 8, 14)
34
FIELD(GFLADJ, GFLADJ_30MHZ_SDBND_SEL, 7, 1)
35
FIELD(GFLADJ, GFLADJ_30MHZ, 0, 6)
36
+REG32(GUSB2RHBCTL, 0x540)
37
+ FIELD(GUSB2RHBCTL, OVRD_L1TIMEOUT, 0, 4)
38
39
#define DWC3_GLOBAL_OFFSET 0xC100
40
static void reset_csr(USBDWC3 * s)
41
@@ -XXX,XX +XXX,XX @@ static const RegisterAccessInfo usb_dwc3_regs_info[] = {
42
.rsvd = 0x40,
43
.ro = 0x400040,
44
.unimp = 0xffffffff,
45
+ },{ .name = "GUSB2RHBCTL", .addr = A_GUSB2RHBCTL,
46
+ .rsvd = 0xfffffff0,
47
+ .unimp = 0xffffffff,
48
}
49
};
50
51
--
52
2.43.0
diff view generated by jsdifflib
New patch
1
From: Bernhard Beschow <shentey@gmail.com>
1
2
3
On the real device, the PCIe root bus is only connected to a PCIe bridge and
4
does not allow for direct attachment of devices. Doing so in QEMU results in no
5
PCI devices being detected by Linux. Instead, PCI devices should plug into the
6
secondary PCIe bus spawned by the internal PCIe bridge.
7
8
Unfortunately, QEMU defaults to plugging devices into the PCIe root bus. To work
9
around this, every PCI device created on the command line needs an extra
10
`bus=dw-pcie` option which is error prone. Fix that by marking the PCIe root bus
11
as full which makes QEMU decend into the child PCIe bus.
12
13
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
14
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
15
Message-id: 20250223114708.1780-3-shentey@gmail.com
16
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
17
---
18
include/hw/pci-host/designware.h | 7 +++++++
19
hw/pci-host/designware.c | 18 +++++++++++++++++-
20
2 files changed, 24 insertions(+), 1 deletion(-)
21
22
diff --git a/include/hw/pci-host/designware.h b/include/hw/pci-host/designware.h
23
index XXXXXXX..XXXXXXX 100644
24
--- a/include/hw/pci-host/designware.h
25
+++ b/include/hw/pci-host/designware.h
26
@@ -XXX,XX +XXX,XX @@
27
#include "hw/pci/pci_bridge.h"
28
#include "qom/object.h"
29
30
+#define TYPE_DESIGNWARE_PCIE_ROOT_BUS "designware-pcie-root-BUS"
31
+OBJECT_DECLARE_SIMPLE_TYPE(DesignwarePCIERootBus, DESIGNWARE_PCIE_ROOT_BUS)
32
+
33
#define TYPE_DESIGNWARE_PCIE_HOST "designware-pcie-host"
34
OBJECT_DECLARE_SIMPLE_TYPE(DesignwarePCIEHost, DESIGNWARE_PCIE_HOST)
35
36
#define TYPE_DESIGNWARE_PCIE_ROOT "designware-pcie-root"
37
OBJECT_DECLARE_SIMPLE_TYPE(DesignwarePCIERoot, DESIGNWARE_PCIE_ROOT)
38
39
+struct DesignwarePCIERootBus {
40
+ PCIBus parent;
41
+};
42
+
43
typedef struct DesignwarePCIEViewport {
44
DesignwarePCIERoot *root;
45
46
diff --git a/hw/pci-host/designware.c b/hw/pci-host/designware.c
47
index XXXXXXX..XXXXXXX 100644
48
--- a/hw/pci-host/designware.c
49
+++ b/hw/pci-host/designware.c
50
@@ -XXX,XX +XXX,XX @@
51
#define DESIGNWARE_PCIE_ATU_DEVFN(x) (((x) >> 16) & 0xff)
52
#define DESIGNWARE_PCIE_ATU_UPPER_TARGET 0x91C
53
54
+static void designware_pcie_root_bus_class_init(ObjectClass *klass, void *data)
55
+{
56
+ BusClass *k = BUS_CLASS(klass);
57
+
58
+ /*
59
+ * Designware has only a single root complex. Enforce the limit on the
60
+ * parent bus
61
+ */
62
+ k->max_dev = 1;
63
+}
64
+
65
static DesignwarePCIEHost *
66
designware_pcie_root_to_host(DesignwarePCIERoot *root)
67
{
68
@@ -XXX,XX +XXX,XX @@ static void designware_pcie_host_realize(DeviceState *dev, Error **errp)
69
&s->pci.memory,
70
&s->pci.io,
71
0, 4,
72
- TYPE_PCIE_BUS);
73
+ TYPE_DESIGNWARE_PCIE_ROOT_BUS);
74
pci->bus->flags |= PCI_BUS_EXTENDED_CONFIG_SPACE;
75
76
memory_region_init(&s->pci.address_space_root,
77
@@ -XXX,XX +XXX,XX @@ static void designware_pcie_host_init(Object *obj)
78
79
static const TypeInfo designware_pcie_types[] = {
80
{
81
+ .name = TYPE_DESIGNWARE_PCIE_ROOT_BUS,
82
+ .parent = TYPE_PCIE_BUS,
83
+ .instance_size = sizeof(DesignwarePCIERootBus),
84
+ .class_init = designware_pcie_root_bus_class_init,
85
+ }, {
86
.name = TYPE_DESIGNWARE_PCIE_HOST,
87
.parent = TYPE_PCI_HOST_BRIDGE,
88
.instance_size = sizeof(DesignwarePCIEHost),
89
--
90
2.43.0
diff view generated by jsdifflib
New patch
1
From: Bernhard Beschow <shentey@gmail.com>
1
2
3
The move of the Kconfig bits to hw/gpio is fixing a bug in 6328d8ffa6cb9d
4
("misc/pca955*: Move models under hw/gpio"), which moved the code but forgot to
5
move the Kconfig sections.
6
7
Fixes: 6328d8ffa6cb9d "misc/pca955*: Move models under hw/gpio"
8
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
9
Message-id: 20250223114708.1780-4-shentey@gmail.com
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
---
13
hw/gpio/Kconfig | 8 ++++++++
14
hw/misc/Kconfig | 8 --------
15
2 files changed, 8 insertions(+), 8 deletions(-)
16
17
diff --git a/hw/gpio/Kconfig b/hw/gpio/Kconfig
18
index XXXXXXX..XXXXXXX 100644
19
--- a/hw/gpio/Kconfig
20
+++ b/hw/gpio/Kconfig
21
@@ -XXX,XX +XXX,XX @@ config SIFIVE_GPIO
22
config STM32L4X5_GPIO
23
bool
24
25
+config PCA9552
26
+ bool
27
+ depends on I2C
28
+
29
+config PCA9554
30
+ bool
31
+ depends on I2C
32
+
33
config PCF8574
34
bool
35
depends on I2C
36
diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
37
index XXXXXXX..XXXXXXX 100644
38
--- a/hw/misc/Kconfig
39
+++ b/hw/misc/Kconfig
40
@@ -XXX,XX +XXX,XX @@ config EDU
41
default y if TEST_DEVICES
42
depends on PCI && MSI_NONBROKEN
43
44
-config PCA9552
45
- bool
46
- depends on I2C
47
-
48
-config PCA9554
49
- bool
50
- depends on I2C
51
-
52
config I2C_ECHO
53
bool
54
default y if TEST_DEVICES
55
--
56
2.43.0
diff view generated by jsdifflib
New patch
1
From: Bernhard Beschow <shentey@gmail.com>
1
2
3
As a first step, implement the bare minimum: CPUs, RAM, interrupt controller,
4
serial. All other devices of the A53 memory map are represented as
5
TYPE_UNIMPLEMENTED_DEVICE, i.e. the whole memory map is provided. This allows
6
for running Linux without it crashing due to invalid memory accesses.
7
8
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
9
Message-id: 20250223114708.1780-5-shentey@gmail.com
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
11
[PMM: drop 'static const' from serial_table[] definition to avoid
12
compile failure on GCC 7.5]
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
---
15
MAINTAINERS | 9 +
16
docs/system/arm/imx8mp-evk.rst | 54 +++++
17
docs/system/target-arm.rst | 1 +
18
include/hw/arm/fsl-imx8mp.h | 189 +++++++++++++++++
19
hw/arm/fsl-imx8mp.c | 367 +++++++++++++++++++++++++++++++++
20
hw/arm/imx8mp-evk.c | 55 +++++
21
hw/arm/Kconfig | 12 ++
22
hw/arm/meson.build | 2 +
23
8 files changed, 689 insertions(+)
24
create mode 100644 docs/system/arm/imx8mp-evk.rst
25
create mode 100644 include/hw/arm/fsl-imx8mp.h
26
create mode 100644 hw/arm/fsl-imx8mp.c
27
create mode 100644 hw/arm/imx8mp-evk.c
28
29
diff --git a/MAINTAINERS b/MAINTAINERS
30
index XXXXXXX..XXXXXXX 100644
31
--- a/MAINTAINERS
32
+++ b/MAINTAINERS
33
@@ -XXX,XX +XXX,XX @@ F: hw/pci-host/designware.c
34
F: include/hw/pci-host/designware.h
35
F: docs/system/arm/mcimx7d-sabre.rst
36
37
+MCIMX8MP-EVK / i.MX8MP
38
+M: Bernhard Beschow <shentey@gmail.com>
39
+L: qemu-arm@nongnu.org
40
+S: Maintained
41
+F: hw/arm/imx8mp-evk.c
42
+F: hw/arm/fsl-imx8mp.c
43
+F: include/hw/arm/fsl-imx8mp.h
44
+F: docs/system/arm/imx8mp-evk.rst
45
+
46
MPS2 / MPS3
47
M: Peter Maydell <peter.maydell@linaro.org>
48
L: qemu-arm@nongnu.org
49
diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8mp-evk.rst
50
new file mode 100644
51
index XXXXXXX..XXXXXXX
52
--- /dev/null
53
+++ b/docs/system/arm/imx8mp-evk.rst
54
@@ -XXX,XX +XXX,XX @@
55
+NXP i.MX 8M Plus Evaluation Kit (``imx8mp-evk``)
56
+================================================
57
+
58
+The ``imx8mp-evk`` machine models the i.MX 8M Plus Evaluation Kit, based on an
59
+i.MX 8M Plus SoC.
60
+
61
+Supported devices
62
+-----------------
63
+
64
+The ``imx8mp-evk`` machine implements the following devices:
65
+
66
+ * Up to 4 Cortex-A53 cores
67
+ * Generic Interrupt Controller (GICv3)
68
+ * 4 UARTs
69
+
70
+Boot options
71
+------------
72
+
73
+The ``imx8mp-evk`` machine can start a Linux kernel directly using the standard
74
+``-kernel`` functionality.
75
+
76
+Direct Linux Kernel Boot
77
+''''''''''''''''''''''''
78
+
79
+Probably the easiest way to get started with a whole Linux system on the machine
80
+is to generate an image with Buildroot. Version 2024.11.1 is tested at the time
81
+of writing and involves two steps. First run the following commands in the
82
+toplevel directory of the Buildroot source tree:
83
+
84
+.. code-block:: bash
85
+
86
+ $ echo "BR2_TARGET_ROOTFS_CPIO=y" >> configs/freescale_imx8mpevk_defconfig
87
+ $ make freescale_imx8mpevk_defconfig
88
+ $ make
89
+
90
+Once finished successfully there is an ``output/image`` subfolder. Navigate into
91
+it and patch the device tree with the following commands which will remove the
92
+``cpu-idle-states`` properties from CPU nodes:
93
+
94
+.. code-block:: bash
95
+
96
+ $ dtc imx8mp-evk.dtb | sed '/cpu-idle-states/d' > imx8mp-evk-patched.dts
97
+ $ dtc imx8mp-evk-patched.dts -o imx8mp-evk-patched.dtb
98
+
99
+Now that everything is prepared the machine can be started as follows:
100
+
101
+.. code-block:: bash
102
+
103
+ $ qemu-system-aarch64 -M imx8mp-evk -smp 4 -m 3G \
104
+ -display none -serial null -serial stdio \
105
+ -kernel Image \
106
+ -dtb imx8mp-evk-patched.dtb \
107
+ -initrd rootfs.cpio \
108
+ -append "root=/dev/ram"
109
diff --git a/docs/system/target-arm.rst b/docs/system/target-arm.rst
110
index XXXXXXX..XXXXXXX 100644
111
--- a/docs/system/target-arm.rst
112
+++ b/docs/system/target-arm.rst
113
@@ -XXX,XX +XXX,XX @@ Board-specific documentation
114
arm/imx25-pdk
115
arm/mcimx6ul-evk
116
arm/mcimx7d-sabre
117
+ arm/imx8mp-evk
118
arm/orangepi
119
arm/raspi
120
arm/collie
121
diff --git a/include/hw/arm/fsl-imx8mp.h b/include/hw/arm/fsl-imx8mp.h
122
new file mode 100644
123
index XXXXXXX..XXXXXXX
124
--- /dev/null
125
+++ b/include/hw/arm/fsl-imx8mp.h
126
@@ -XXX,XX +XXX,XX @@
127
+/*
128
+ * i.MX 8M Plus SoC Definitions
129
+ *
130
+ * Copyright (c) 2024, Bernhard Beschow <shentey@gmail.com>
131
+ *
132
+ * SPDX-License-Identifier: GPL-2.0-or-later
133
+ */
134
+
135
+#ifndef FSL_IMX8MP_H
136
+#define FSL_IMX8MP_H
137
+
138
+#include "cpu.h"
139
+#include "hw/char/imx_serial.h"
140
+#include "hw/intc/arm_gicv3_common.h"
141
+#include "qom/object.h"
142
+#include "qemu/units.h"
143
+
144
+#define TYPE_FSL_IMX8MP "fsl-imx8mp"
145
+OBJECT_DECLARE_SIMPLE_TYPE(FslImx8mpState, FSL_IMX8MP)
146
+
147
+#define FSL_IMX8MP_RAM_START 0x40000000
148
+#define FSL_IMX8MP_RAM_SIZE_MAX (8 * GiB)
149
+
150
+enum FslImx8mpConfiguration {
151
+ FSL_IMX8MP_NUM_CPUS = 4,
152
+ FSL_IMX8MP_NUM_IRQS = 160,
153
+ FSL_IMX8MP_NUM_UARTS = 4,
154
+};
155
+
156
+struct FslImx8mpState {
157
+ DeviceState parent_obj;
158
+
159
+ ARMCPU cpu[FSL_IMX8MP_NUM_CPUS];
160
+ GICv3State gic;
161
+ IMXSerialState uart[FSL_IMX8MP_NUM_UARTS];
162
+};
163
+
164
+enum FslImx8mpMemoryRegions {
165
+ FSL_IMX8MP_A53_DAP,
166
+ FSL_IMX8MP_AIPS1_CONFIGURATION,
167
+ FSL_IMX8MP_AIPS2_CONFIGURATION,
168
+ FSL_IMX8MP_AIPS3_CONFIGURATION,
169
+ FSL_IMX8MP_AIPS4_CONFIGURATION,
170
+ FSL_IMX8MP_AIPS5_CONFIGURATION,
171
+ FSL_IMX8MP_ANA_OSC,
172
+ FSL_IMX8MP_ANA_PLL,
173
+ FSL_IMX8MP_ANA_TSENSOR,
174
+ FSL_IMX8MP_APBH_DMA,
175
+ FSL_IMX8MP_ASRC,
176
+ FSL_IMX8MP_AUDIO_BLK_CTRL,
177
+ FSL_IMX8MP_AUDIO_DSP,
178
+ FSL_IMX8MP_AUDIO_XCVR_RX,
179
+ FSL_IMX8MP_AUD_IRQ_STEER,
180
+ FSL_IMX8MP_BOOT_ROM,
181
+ FSL_IMX8MP_BOOT_ROM_PROTECTED,
182
+ FSL_IMX8MP_CAAM,
183
+ FSL_IMX8MP_CAAM_MEM,
184
+ FSL_IMX8MP_CCM,
185
+ FSL_IMX8MP_CSU,
186
+ FSL_IMX8MP_DDR_BLK_CTRL,
187
+ FSL_IMX8MP_DDR_CTL,
188
+ FSL_IMX8MP_DDR_PERF_MON,
189
+ FSL_IMX8MP_DDR_PHY,
190
+ FSL_IMX8MP_DDR_PHY_BROADCAST,
191
+ FSL_IMX8MP_ECSPI1,
192
+ FSL_IMX8MP_ECSPI2,
193
+ FSL_IMX8MP_ECSPI3,
194
+ FSL_IMX8MP_EDMA_CHANNELS,
195
+ FSL_IMX8MP_EDMA_MANAGEMENT_PAGE,
196
+ FSL_IMX8MP_ENET1,
197
+ FSL_IMX8MP_ENET2_TSN,
198
+ FSL_IMX8MP_FLEXCAN1,
199
+ FSL_IMX8MP_FLEXCAN2,
200
+ FSL_IMX8MP_GIC_DIST,
201
+ FSL_IMX8MP_GIC_REDIST,
202
+ FSL_IMX8MP_GPC,
203
+ FSL_IMX8MP_GPIO1,
204
+ FSL_IMX8MP_GPIO2,
205
+ FSL_IMX8MP_GPIO3,
206
+ FSL_IMX8MP_GPIO4,
207
+ FSL_IMX8MP_GPIO5,
208
+ FSL_IMX8MP_GPT1,
209
+ FSL_IMX8MP_GPT2,
210
+ FSL_IMX8MP_GPT3,
211
+ FSL_IMX8MP_GPT4,
212
+ FSL_IMX8MP_GPT5,
213
+ FSL_IMX8MP_GPT6,
214
+ FSL_IMX8MP_GPU2D,
215
+ FSL_IMX8MP_GPU3D,
216
+ FSL_IMX8MP_HDMI_TX,
217
+ FSL_IMX8MP_HDMI_TX_AUDLNK_MSTR,
218
+ FSL_IMX8MP_HSIO_BLK_CTL,
219
+ FSL_IMX8MP_I2C1,
220
+ FSL_IMX8MP_I2C2,
221
+ FSL_IMX8MP_I2C3,
222
+ FSL_IMX8MP_I2C4,
223
+ FSL_IMX8MP_I2C5,
224
+ FSL_IMX8MP_I2C6,
225
+ FSL_IMX8MP_INTERCONNECT,
226
+ FSL_IMX8MP_IOMUXC,
227
+ FSL_IMX8MP_IOMUXC_GPR,
228
+ FSL_IMX8MP_IPS_DEWARP,
229
+ FSL_IMX8MP_ISI,
230
+ FSL_IMX8MP_ISP1,
231
+ FSL_IMX8MP_ISP2,
232
+ FSL_IMX8MP_LCDIF1,
233
+ FSL_IMX8MP_LCDIF2,
234
+ FSL_IMX8MP_MEDIA_BLK_CTL,
235
+ FSL_IMX8MP_MIPI_CSI1,
236
+ FSL_IMX8MP_MIPI_CSI2,
237
+ FSL_IMX8MP_MIPI_DSI1,
238
+ FSL_IMX8MP_MU_1_A,
239
+ FSL_IMX8MP_MU_1_B,
240
+ FSL_IMX8MP_MU_2_A,
241
+ FSL_IMX8MP_MU_2_B,
242
+ FSL_IMX8MP_MU_3_A,
243
+ FSL_IMX8MP_MU_3_B,
244
+ FSL_IMX8MP_NPU,
245
+ FSL_IMX8MP_OCOTP_CTRL,
246
+ FSL_IMX8MP_OCRAM,
247
+ FSL_IMX8MP_OCRAM_S,
248
+ FSL_IMX8MP_PCIE1,
249
+ FSL_IMX8MP_PCIE1_MEM,
250
+ FSL_IMX8MP_PCIE_PHY1,
251
+ FSL_IMX8MP_PDM,
252
+ FSL_IMX8MP_PERFMON1,
253
+ FSL_IMX8MP_PERFMON2,
254
+ FSL_IMX8MP_PWM1,
255
+ FSL_IMX8MP_PWM2,
256
+ FSL_IMX8MP_PWM3,
257
+ FSL_IMX8MP_PWM4,
258
+ FSL_IMX8MP_QOSC,
259
+ FSL_IMX8MP_QSPI,
260
+ FSL_IMX8MP_QSPI1_RX_BUFFER,
261
+ FSL_IMX8MP_QSPI1_TX_BUFFER,
262
+ FSL_IMX8MP_QSPI_MEM,
263
+ FSL_IMX8MP_RAM,
264
+ FSL_IMX8MP_RDC,
265
+ FSL_IMX8MP_SAI1,
266
+ FSL_IMX8MP_SAI2,
267
+ FSL_IMX8MP_SAI3,
268
+ FSL_IMX8MP_SAI5,
269
+ FSL_IMX8MP_SAI6,
270
+ FSL_IMX8MP_SAI7,
271
+ FSL_IMX8MP_SDMA1,
272
+ FSL_IMX8MP_SDMA2,
273
+ FSL_IMX8MP_SDMA3,
274
+ FSL_IMX8MP_SEMAPHORE1,
275
+ FSL_IMX8MP_SEMAPHORE2,
276
+ FSL_IMX8MP_SEMAPHORE_HS,
277
+ FSL_IMX8MP_SNVS_HP,
278
+ FSL_IMX8MP_SPBA1,
279
+ FSL_IMX8MP_SPBA2,
280
+ FSL_IMX8MP_SRC,
281
+ FSL_IMX8MP_SYSCNT_CMP,
282
+ FSL_IMX8MP_SYSCNT_CTRL,
283
+ FSL_IMX8MP_SYSCNT_RD,
284
+ FSL_IMX8MP_TCM_DTCM,
285
+ FSL_IMX8MP_TCM_ITCM,
286
+ FSL_IMX8MP_TZASC,
287
+ FSL_IMX8MP_UART1,
288
+ FSL_IMX8MP_UART2,
289
+ FSL_IMX8MP_UART3,
290
+ FSL_IMX8MP_UART4,
291
+ FSL_IMX8MP_USB1,
292
+ FSL_IMX8MP_USB2,
293
+ FSL_IMX8MP_USDHC1,
294
+ FSL_IMX8MP_USDHC2,
295
+ FSL_IMX8MP_USDHC3,
296
+ FSL_IMX8MP_VPU,
297
+ FSL_IMX8MP_VPU_BLK_CTRL,
298
+ FSL_IMX8MP_VPU_G1_DECODER,
299
+ FSL_IMX8MP_VPU_G2_DECODER,
300
+ FSL_IMX8MP_VPU_VC8000E_ENCODER,
301
+ FSL_IMX8MP_WDOG1,
302
+ FSL_IMX8MP_WDOG2,
303
+ FSL_IMX8MP_WDOG3,
304
+};
305
+
306
+enum FslImx8mpIrqs {
307
+ FSL_IMX8MP_UART1_IRQ = 26,
308
+ FSL_IMX8MP_UART2_IRQ = 27,
309
+ FSL_IMX8MP_UART3_IRQ = 28,
310
+ FSL_IMX8MP_UART4_IRQ = 29,
311
+ FSL_IMX8MP_UART5_IRQ = 30,
312
+ FSL_IMX8MP_UART6_IRQ = 16,
313
+};
314
+
315
+#endif /* FSL_IMX8MP_H */
316
diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c
317
new file mode 100644
318
index XXXXXXX..XXXXXXX
319
--- /dev/null
320
+++ b/hw/arm/fsl-imx8mp.c
321
@@ -XXX,XX +XXX,XX @@
322
+/*
323
+ * i.MX 8M Plus SoC Implementation
324
+ *
325
+ * Based on hw/arm/fsl-imx6.c
326
+ *
327
+ * Copyright (c) 2024, Bernhard Beschow <shentey@gmail.com>
328
+ *
329
+ * SPDX-License-Identifier: GPL-2.0-or-later
330
+ */
331
+
332
+#include "qemu/osdep.h"
333
+#include "exec/address-spaces.h"
334
+#include "hw/arm/bsa.h"
335
+#include "hw/arm/fsl-imx8mp.h"
336
+#include "hw/intc/arm_gicv3.h"
337
+#include "hw/misc/unimp.h"
338
+#include "hw/boards.h"
339
+#include "system/system.h"
340
+#include "target/arm/cpu-qom.h"
341
+#include "qapi/error.h"
342
+#include "qobject/qlist.h"
343
+
344
+static const struct {
345
+ hwaddr addr;
346
+ size_t size;
347
+ const char *name;
348
+} fsl_imx8mp_memmap[] = {
349
+ [FSL_IMX8MP_RAM] = { FSL_IMX8MP_RAM_START, FSL_IMX8MP_RAM_SIZE_MAX, "ram" },
350
+ [FSL_IMX8MP_DDR_PHY_BROADCAST] = { 0x3dc00000, 4 * MiB, "ddr_phy_broadcast" },
351
+ [FSL_IMX8MP_DDR_PERF_MON] = { 0x3d800000, 4 * MiB, "ddr_perf_mon" },
352
+ [FSL_IMX8MP_DDR_CTL] = { 0x3d400000, 4 * MiB, "ddr_ctl" },
353
+ [FSL_IMX8MP_DDR_BLK_CTRL] = { 0x3d000000, 1 * MiB, "ddr_blk_ctrl" },
354
+ [FSL_IMX8MP_DDR_PHY] = { 0x3c000000, 16 * MiB, "ddr_phy" },
355
+ [FSL_IMX8MP_AUDIO_DSP] = { 0x3b000000, 16 * MiB, "audio_dsp" },
356
+ [FSL_IMX8MP_GIC_DIST] = { 0x38800000, 512 * KiB, "gic_dist" },
357
+ [FSL_IMX8MP_GIC_REDIST] = { 0x38880000, 512 * KiB, "gic_redist" },
358
+ [FSL_IMX8MP_NPU] = { 0x38500000, 2 * MiB, "npu" },
359
+ [FSL_IMX8MP_VPU] = { 0x38340000, 2 * MiB, "vpu" },
360
+ [FSL_IMX8MP_VPU_BLK_CTRL] = { 0x38330000, 2 * MiB, "vpu_blk_ctrl" },
361
+ [FSL_IMX8MP_VPU_VC8000E_ENCODER] = { 0x38320000, 2 * MiB, "vpu_vc8000e_encoder" },
362
+ [FSL_IMX8MP_VPU_G2_DECODER] = { 0x38310000, 2 * MiB, "vpu_g2_decoder" },
363
+ [FSL_IMX8MP_VPU_G1_DECODER] = { 0x38300000, 2 * MiB, "vpu_g1_decoder" },
364
+ [FSL_IMX8MP_USB2] = { 0x38200000, 1 * MiB, "usb2" },
365
+ [FSL_IMX8MP_USB1] = { 0x38100000, 1 * MiB, "usb1" },
366
+ [FSL_IMX8MP_GPU2D] = { 0x38008000, 32 * KiB, "gpu2d" },
367
+ [FSL_IMX8MP_GPU3D] = { 0x38000000, 32 * KiB, "gpu3d" },
368
+ [FSL_IMX8MP_QSPI1_RX_BUFFER] = { 0x34000000, 32 * MiB, "qspi1_rx_buffer" },
369
+ [FSL_IMX8MP_PCIE1] = { 0x33800000, 4 * MiB, "pcie1" },
370
+ [FSL_IMX8MP_QSPI1_TX_BUFFER] = { 0x33008000, 32 * KiB, "qspi1_tx_buffer" },
371
+ [FSL_IMX8MP_APBH_DMA] = { 0x33000000, 32 * KiB, "apbh_dma" },
372
+
373
+ /* AIPS-5 Begin */
374
+ [FSL_IMX8MP_MU_3_B] = { 0x30e90000, 64 * KiB, "mu_3_b" },
375
+ [FSL_IMX8MP_MU_3_A] = { 0x30e80000, 64 * KiB, "mu_3_a" },
376
+ [FSL_IMX8MP_MU_2_B] = { 0x30e70000, 64 * KiB, "mu_2_b" },
377
+ [FSL_IMX8MP_MU_2_A] = { 0x30e60000, 64 * KiB, "mu_2_a" },
378
+ [FSL_IMX8MP_EDMA_CHANNELS] = { 0x30e40000, 128 * KiB, "edma_channels" },
379
+ [FSL_IMX8MP_EDMA_MANAGEMENT_PAGE] = { 0x30e30000, 64 * KiB, "edma_management_page" },
380
+ [FSL_IMX8MP_AUDIO_BLK_CTRL] = { 0x30e20000, 64 * KiB, "audio_blk_ctrl" },
381
+ [FSL_IMX8MP_SDMA2] = { 0x30e10000, 64 * KiB, "sdma2" },
382
+ [FSL_IMX8MP_SDMA3] = { 0x30e00000, 64 * KiB, "sdma3" },
383
+ [FSL_IMX8MP_AIPS5_CONFIGURATION] = { 0x30df0000, 64 * KiB, "aips5_configuration" },
384
+ [FSL_IMX8MP_SPBA2] = { 0x30cf0000, 64 * KiB, "spba2" },
385
+ [FSL_IMX8MP_AUDIO_XCVR_RX] = { 0x30cc0000, 64 * KiB, "audio_xcvr_rx" },
386
+ [FSL_IMX8MP_HDMI_TX_AUDLNK_MSTR] = { 0x30cb0000, 64 * KiB, "hdmi_tx_audlnk_mstr" },
387
+ [FSL_IMX8MP_PDM] = { 0x30ca0000, 64 * KiB, "pdm" },
388
+ [FSL_IMX8MP_ASRC] = { 0x30c90000, 64 * KiB, "asrc" },
389
+ [FSL_IMX8MP_SAI7] = { 0x30c80000, 64 * KiB, "sai7" },
390
+ [FSL_IMX8MP_SAI6] = { 0x30c60000, 64 * KiB, "sai6" },
391
+ [FSL_IMX8MP_SAI5] = { 0x30c50000, 64 * KiB, "sai5" },
392
+ [FSL_IMX8MP_SAI3] = { 0x30c30000, 64 * KiB, "sai3" },
393
+ [FSL_IMX8MP_SAI2] = { 0x30c20000, 64 * KiB, "sai2" },
394
+ [FSL_IMX8MP_SAI1] = { 0x30c10000, 64 * KiB, "sai1" },
395
+ /* AIPS-5 End */
396
+
397
+ /* AIPS-4 Begin */
398
+ [FSL_IMX8MP_HDMI_TX] = { 0x32fc0000, 128 * KiB, "hdmi_tx" },
399
+ [FSL_IMX8MP_TZASC] = { 0x32f80000, 64 * KiB, "tzasc" },
400
+ [FSL_IMX8MP_HSIO_BLK_CTL] = { 0x32f10000, 64 * KiB, "hsio_blk_ctl" },
401
+ [FSL_IMX8MP_PCIE_PHY1] = { 0x32f00000, 64 * KiB, "pcie_phy1" },
402
+ [FSL_IMX8MP_MEDIA_BLK_CTL] = { 0x32ec0000, 64 * KiB, "media_blk_ctl" },
403
+ [FSL_IMX8MP_LCDIF2] = { 0x32e90000, 64 * KiB, "lcdif2" },
404
+ [FSL_IMX8MP_LCDIF1] = { 0x32e80000, 64 * KiB, "lcdif1" },
405
+ [FSL_IMX8MP_MIPI_DSI1] = { 0x32e60000, 64 * KiB, "mipi_dsi1" },
406
+ [FSL_IMX8MP_MIPI_CSI2] = { 0x32e50000, 64 * KiB, "mipi_csi2" },
407
+ [FSL_IMX8MP_MIPI_CSI1] = { 0x32e40000, 64 * KiB, "mipi_csi1" },
408
+ [FSL_IMX8MP_IPS_DEWARP] = { 0x32e30000, 64 * KiB, "ips_dewarp" },
409
+ [FSL_IMX8MP_ISP2] = { 0x32e20000, 64 * KiB, "isp2" },
410
+ [FSL_IMX8MP_ISP1] = { 0x32e10000, 64 * KiB, "isp1" },
411
+ [FSL_IMX8MP_ISI] = { 0x32e00000, 64 * KiB, "isi" },
412
+ [FSL_IMX8MP_AIPS4_CONFIGURATION] = { 0x32df0000, 64 * KiB, "aips4_configuration" },
413
+ /* AIPS-4 End */
414
+
415
+ [FSL_IMX8MP_INTERCONNECT] = { 0x32700000, 1 * MiB, "interconnect" },
416
+
417
+ /* AIPS-3 Begin */
418
+ [FSL_IMX8MP_ENET2_TSN] = { 0x30bf0000, 64 * KiB, "enet2_tsn" },
419
+ [FSL_IMX8MP_ENET1] = { 0x30be0000, 64 * KiB, "enet1" },
420
+ [FSL_IMX8MP_SDMA1] = { 0x30bd0000, 64 * KiB, "sdma1" },
421
+ [FSL_IMX8MP_QSPI] = { 0x30bb0000, 64 * KiB, "qspi" },
422
+ [FSL_IMX8MP_USDHC3] = { 0x30b60000, 64 * KiB, "usdhc3" },
423
+ [FSL_IMX8MP_USDHC2] = { 0x30b50000, 64 * KiB, "usdhc2" },
424
+ [FSL_IMX8MP_USDHC1] = { 0x30b40000, 64 * KiB, "usdhc1" },
425
+ [FSL_IMX8MP_I2C6] = { 0x30ae0000, 64 * KiB, "i2c6" },
426
+ [FSL_IMX8MP_I2C5] = { 0x30ad0000, 64 * KiB, "i2c5" },
427
+ [FSL_IMX8MP_SEMAPHORE_HS] = { 0x30ac0000, 64 * KiB, "semaphore_hs" },
428
+ [FSL_IMX8MP_MU_1_B] = { 0x30ab0000, 64 * KiB, "mu_1_b" },
429
+ [FSL_IMX8MP_MU_1_A] = { 0x30aa0000, 64 * KiB, "mu_1_a" },
430
+ [FSL_IMX8MP_AUD_IRQ_STEER] = { 0x30a80000, 64 * KiB, "aud_irq_steer" },
431
+ [FSL_IMX8MP_UART4] = { 0x30a60000, 64 * KiB, "uart4" },
432
+ [FSL_IMX8MP_I2C4] = { 0x30a50000, 64 * KiB, "i2c4" },
433
+ [FSL_IMX8MP_I2C3] = { 0x30a40000, 64 * KiB, "i2c3" },
434
+ [FSL_IMX8MP_I2C2] = { 0x30a30000, 64 * KiB, "i2c2" },
435
+ [FSL_IMX8MP_I2C1] = { 0x30a20000, 64 * KiB, "i2c1" },
436
+ [FSL_IMX8MP_AIPS3_CONFIGURATION] = { 0x309f0000, 64 * KiB, "aips3_configuration" },
437
+ [FSL_IMX8MP_CAAM] = { 0x30900000, 256 * KiB, "caam" },
438
+ [FSL_IMX8MP_SPBA1] = { 0x308f0000, 64 * KiB, "spba1" },
439
+ [FSL_IMX8MP_FLEXCAN2] = { 0x308d0000, 64 * KiB, "flexcan2" },
440
+ [FSL_IMX8MP_FLEXCAN1] = { 0x308c0000, 64 * KiB, "flexcan1" },
441
+ [FSL_IMX8MP_UART2] = { 0x30890000, 64 * KiB, "uart2" },
442
+ [FSL_IMX8MP_UART3] = { 0x30880000, 64 * KiB, "uart3" },
443
+ [FSL_IMX8MP_UART1] = { 0x30860000, 64 * KiB, "uart1" },
444
+ [FSL_IMX8MP_ECSPI3] = { 0x30840000, 64 * KiB, "ecspi3" },
445
+ [FSL_IMX8MP_ECSPI2] = { 0x30830000, 64 * KiB, "ecspi2" },
446
+ [FSL_IMX8MP_ECSPI1] = { 0x30820000, 64 * KiB, "ecspi1" },
447
+ /* AIPS-3 End */
448
+
449
+ /* AIPS-2 Begin */
450
+ [FSL_IMX8MP_QOSC] = { 0x307f0000, 64 * KiB, "qosc" },
451
+ [FSL_IMX8MP_PERFMON2] = { 0x307d0000, 64 * KiB, "perfmon2" },
452
+ [FSL_IMX8MP_PERFMON1] = { 0x307c0000, 64 * KiB, "perfmon1" },
453
+ [FSL_IMX8MP_GPT4] = { 0x30700000, 64 * KiB, "gpt4" },
454
+ [FSL_IMX8MP_GPT5] = { 0x306f0000, 64 * KiB, "gpt5" },
455
+ [FSL_IMX8MP_GPT6] = { 0x306e0000, 64 * KiB, "gpt6" },
456
+ [FSL_IMX8MP_SYSCNT_CTRL] = { 0x306c0000, 64 * KiB, "syscnt_ctrl" },
457
+ [FSL_IMX8MP_SYSCNT_CMP] = { 0x306b0000, 64 * KiB, "syscnt_cmp" },
458
+ [FSL_IMX8MP_SYSCNT_RD] = { 0x306a0000, 64 * KiB, "syscnt_rd" },
459
+ [FSL_IMX8MP_PWM4] = { 0x30690000, 64 * KiB, "pwm4" },
460
+ [FSL_IMX8MP_PWM3] = { 0x30680000, 64 * KiB, "pwm3" },
461
+ [FSL_IMX8MP_PWM2] = { 0x30670000, 64 * KiB, "pwm2" },
462
+ [FSL_IMX8MP_PWM1] = { 0x30660000, 64 * KiB, "pwm1" },
463
+ [FSL_IMX8MP_AIPS2_CONFIGURATION] = { 0x305f0000, 64 * KiB, "aips2_configuration" },
464
+ /* AIPS-2 End */
465
+
466
+ /* AIPS-1 Begin */
467
+ [FSL_IMX8MP_CSU] = { 0x303e0000, 64 * KiB, "csu" },
468
+ [FSL_IMX8MP_RDC] = { 0x303d0000, 64 * KiB, "rdc" },
469
+ [FSL_IMX8MP_SEMAPHORE2] = { 0x303c0000, 64 * KiB, "semaphore2" },
470
+ [FSL_IMX8MP_SEMAPHORE1] = { 0x303b0000, 64 * KiB, "semaphore1" },
471
+ [FSL_IMX8MP_GPC] = { 0x303a0000, 64 * KiB, "gpc" },
472
+ [FSL_IMX8MP_SRC] = { 0x30390000, 64 * KiB, "src" },
473
+ [FSL_IMX8MP_CCM] = { 0x30380000, 64 * KiB, "ccm" },
474
+ [FSL_IMX8MP_SNVS_HP] = { 0x30370000, 64 * KiB, "snvs_hp" },
475
+ [FSL_IMX8MP_ANA_PLL] = { 0x30360000, 64 * KiB, "ana_pll" },
476
+ [FSL_IMX8MP_OCOTP_CTRL] = { 0x30350000, 64 * KiB, "ocotp_ctrl" },
477
+ [FSL_IMX8MP_IOMUXC_GPR] = { 0x30340000, 64 * KiB, "iomuxc_gpr" },
478
+ [FSL_IMX8MP_IOMUXC] = { 0x30330000, 64 * KiB, "iomuxc" },
479
+ [FSL_IMX8MP_GPT3] = { 0x302f0000, 64 * KiB, "gpt3" },
480
+ [FSL_IMX8MP_GPT2] = { 0x302e0000, 64 * KiB, "gpt2" },
481
+ [FSL_IMX8MP_GPT1] = { 0x302d0000, 64 * KiB, "gpt1" },
482
+ [FSL_IMX8MP_WDOG3] = { 0x302a0000, 64 * KiB, "wdog3" },
483
+ [FSL_IMX8MP_WDOG2] = { 0x30290000, 64 * KiB, "wdog2" },
484
+ [FSL_IMX8MP_WDOG1] = { 0x30280000, 64 * KiB, "wdog1" },
485
+ [FSL_IMX8MP_ANA_OSC] = { 0x30270000, 64 * KiB, "ana_osc" },
486
+ [FSL_IMX8MP_ANA_TSENSOR] = { 0x30260000, 64 * KiB, "ana_tsensor" },
487
+ [FSL_IMX8MP_GPIO5] = { 0x30240000, 64 * KiB, "gpio5" },
488
+ [FSL_IMX8MP_GPIO4] = { 0x30230000, 64 * KiB, "gpio4" },
489
+ [FSL_IMX8MP_GPIO3] = { 0x30220000, 64 * KiB, "gpio3" },
490
+ [FSL_IMX8MP_GPIO2] = { 0x30210000, 64 * KiB, "gpio2" },
491
+ [FSL_IMX8MP_GPIO1] = { 0x30200000, 64 * KiB, "gpio1" },
492
+ [FSL_IMX8MP_AIPS1_CONFIGURATION] = { 0x301f0000, 64 * KiB, "aips1_configuration" },
493
+ /* AIPS-1 End */
494
+
495
+ [FSL_IMX8MP_A53_DAP] = { 0x28000000, 16 * MiB, "a53_dap" },
496
+ [FSL_IMX8MP_PCIE1_MEM] = { 0x18000000, 128 * MiB, "pcie1_mem" },
497
+ [FSL_IMX8MP_QSPI_MEM] = { 0x08000000, 256 * MiB, "qspi_mem" },
498
+ [FSL_IMX8MP_OCRAM] = { 0x00900000, 576 * KiB, "ocram" },
499
+ [FSL_IMX8MP_TCM_DTCM] = { 0x00800000, 128 * KiB, "tcm_dtcm" },
500
+ [FSL_IMX8MP_TCM_ITCM] = { 0x007e0000, 128 * KiB, "tcm_itcm" },
501
+ [FSL_IMX8MP_OCRAM_S] = { 0x00180000, 36 * KiB, "ocram_s" },
502
+ [FSL_IMX8MP_CAAM_MEM] = { 0x00100000, 32 * KiB, "caam_mem" },
503
+ [FSL_IMX8MP_BOOT_ROM_PROTECTED] = { 0x0003f000, 4 * KiB, "boot_rom_protected" },
504
+ [FSL_IMX8MP_BOOT_ROM] = { 0x00000000, 252 * KiB, "boot_rom" },
505
+};
506
+
507
+static void fsl_imx8mp_init(Object *obj)
508
+{
509
+ MachineState *ms = MACHINE(qdev_get_machine());
510
+ FslImx8mpState *s = FSL_IMX8MP(obj);
511
+ int i;
512
+
513
+ for (i = 0; i < MIN(ms->smp.cpus, FSL_IMX8MP_NUM_CPUS); i++) {
514
+ g_autofree char *name = g_strdup_printf("cpu%d", i);
515
+ object_initialize_child(obj, name, &s->cpu[i],
516
+ ARM_CPU_TYPE_NAME("cortex-a53"));
517
+ }
518
+
519
+ object_initialize_child(obj, "gic", &s->gic, TYPE_ARM_GICV3);
520
+
521
+ for (i = 0; i < FSL_IMX8MP_NUM_UARTS; i++) {
522
+ g_autofree char *name = g_strdup_printf("uart%d", i + 1);
523
+ object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL);
524
+ }
525
+}
526
+
527
+static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
528
+{
529
+ MachineState *ms = MACHINE(qdev_get_machine());
530
+ FslImx8mpState *s = FSL_IMX8MP(dev);
531
+ DeviceState *gicdev = DEVICE(&s->gic);
532
+ int i;
533
+
534
+ if (ms->smp.cpus > FSL_IMX8MP_NUM_CPUS) {
535
+ error_setg(errp, "%s: Only %d CPUs are supported (%d requested)",
536
+ TYPE_FSL_IMX8MP, FSL_IMX8MP_NUM_CPUS, ms->smp.cpus);
537
+ return;
538
+ }
539
+
540
+ /* CPUs */
541
+ for (i = 0; i < ms->smp.cpus; i++) {
542
+ /* On uniprocessor, the CBAR is set to 0 */
543
+ if (ms->smp.cpus > 1) {
544
+ object_property_set_int(OBJECT(&s->cpu[i]), "reset-cbar",
545
+ fsl_imx8mp_memmap[FSL_IMX8MP_GIC_DIST].addr,
546
+ &error_abort);
547
+ }
548
+
549
+ /*
550
+ * CNTFID0 base frequency in Hz of system counter
551
+ */
552
+ object_property_set_int(OBJECT(&s->cpu[i]), "cntfrq", 8000000,
553
+ &error_abort);
554
+
555
+ if (i) {
556
+ /*
557
+ * Secondary CPUs start in powered-down state (and can be
558
+ * powered up via the SRC system reset controller)
559
+ */
560
+ object_property_set_bool(OBJECT(&s->cpu[i]), "start-powered-off",
561
+ true, &error_abort);
562
+ }
563
+
564
+ if (!qdev_realize(DEVICE(&s->cpu[i]), NULL, errp)) {
565
+ return;
566
+ }
567
+ }
568
+
569
+ /* GIC */
570
+ {
571
+ SysBusDevice *gicsbd = SYS_BUS_DEVICE(&s->gic);
572
+ QList *redist_region_count;
573
+
574
+ qdev_prop_set_uint32(gicdev, "num-cpu", ms->smp.cpus);
575
+ qdev_prop_set_uint32(gicdev, "num-irq",
576
+ FSL_IMX8MP_NUM_IRQS + GIC_INTERNAL);
577
+ redist_region_count = qlist_new();
578
+ qlist_append_int(redist_region_count, ms->smp.cpus);
579
+ qdev_prop_set_array(gicdev, "redist-region-count", redist_region_count);
580
+ object_property_set_link(OBJECT(&s->gic), "sysmem",
581
+ OBJECT(get_system_memory()), &error_fatal);
582
+ if (!sysbus_realize(gicsbd, errp)) {
583
+ return;
584
+ }
585
+ sysbus_mmio_map(gicsbd, 0, fsl_imx8mp_memmap[FSL_IMX8MP_GIC_DIST].addr);
586
+ sysbus_mmio_map(gicsbd, 1, fsl_imx8mp_memmap[FSL_IMX8MP_GIC_REDIST].addr);
587
+
588
+ /*
589
+ * Wire the outputs from each CPU's generic timer and the GICv3
590
+ * maintenance interrupt signal to the appropriate GIC PPI inputs, and
591
+ * the GIC's IRQ/FIQ interrupt outputs to the CPU's inputs.
592
+ */
593
+ for (i = 0; i < ms->smp.cpus; i++) {
594
+ DeviceState *cpudev = DEVICE(&s->cpu[i]);
595
+ int intidbase = FSL_IMX8MP_NUM_IRQS + i * GIC_INTERNAL;
596
+ qemu_irq irq;
597
+
598
+ /*
599
+ * Mapping from the output timer irq lines from the CPU to the
600
+ * GIC PPI inputs.
601
+ */
602
+ static const int timer_irqs[] = {
603
+ [GTIMER_PHYS] = ARCH_TIMER_NS_EL1_IRQ,
604
+ [GTIMER_VIRT] = ARCH_TIMER_VIRT_IRQ,
605
+ [GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ,
606
+ [GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ,
607
+ };
608
+
609
+ for (int j = 0; j < ARRAY_SIZE(timer_irqs); j++) {
610
+ irq = qdev_get_gpio_in(gicdev, intidbase + timer_irqs[j]);
611
+ qdev_connect_gpio_out(cpudev, j, irq);
612
+ }
613
+
614
+ irq = qdev_get_gpio_in(gicdev, intidbase + ARCH_GIC_MAINT_IRQ);
615
+ qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt",
616
+ 0, irq);
617
+
618
+ irq = qdev_get_gpio_in(gicdev, intidbase + VIRTUAL_PMU_IRQ);
619
+ qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0, irq);
620
+
621
+ sysbus_connect_irq(gicsbd, i,
622
+ qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
623
+ sysbus_connect_irq(gicsbd, i + ms->smp.cpus,
624
+ qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
625
+ }
626
+ }
627
+
628
+ /* UARTs */
629
+ for (i = 0; i < FSL_IMX8MP_NUM_UARTS; i++) {
630
+ struct {
631
+ hwaddr addr;
632
+ unsigned int irq;
633
+ } serial_table[FSL_IMX8MP_NUM_UARTS] = {
634
+ { fsl_imx8mp_memmap[FSL_IMX8MP_UART1].addr, FSL_IMX8MP_UART1_IRQ },
635
+ { fsl_imx8mp_memmap[FSL_IMX8MP_UART2].addr, FSL_IMX8MP_UART2_IRQ },
636
+ { fsl_imx8mp_memmap[FSL_IMX8MP_UART3].addr, FSL_IMX8MP_UART3_IRQ },
637
+ { fsl_imx8mp_memmap[FSL_IMX8MP_UART4].addr, FSL_IMX8MP_UART4_IRQ },
638
+ };
639
+
640
+ qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", serial_hd(i));
641
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart[i]), errp)) {
642
+ return;
643
+ }
644
+
645
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, serial_table[i].addr);
646
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0,
647
+ qdev_get_gpio_in(gicdev, serial_table[i].irq));
648
+ }
649
+
650
+ /* Unimplemented devices */
651
+ for (i = 0; i < ARRAY_SIZE(fsl_imx8mp_memmap); i++) {
652
+ switch (i) {
653
+ case FSL_IMX8MP_GIC_DIST:
654
+ case FSL_IMX8MP_GIC_REDIST:
655
+ case FSL_IMX8MP_RAM:
656
+ case FSL_IMX8MP_UART1 ... FSL_IMX8MP_UART4:
657
+ /* device implemented and treated above */
658
+ break;
659
+
660
+ default:
661
+ create_unimplemented_device(fsl_imx8mp_memmap[i].name,
662
+ fsl_imx8mp_memmap[i].addr,
663
+ fsl_imx8mp_memmap[i].size);
664
+ break;
665
+ }
666
+ }
667
+}
668
+
669
+static void fsl_imx8mp_class_init(ObjectClass *oc, void *data)
670
+{
671
+ DeviceClass *dc = DEVICE_CLASS(oc);
672
+
673
+ dc->realize = fsl_imx8mp_realize;
674
+
675
+ dc->desc = "i.MX 8M Plus SoC";
676
+}
677
+
678
+static const TypeInfo fsl_imx8mp_types[] = {
679
+ {
680
+ .name = TYPE_FSL_IMX8MP,
681
+ .parent = TYPE_DEVICE,
682
+ .instance_size = sizeof(FslImx8mpState),
683
+ .instance_init = fsl_imx8mp_init,
684
+ .class_init = fsl_imx8mp_class_init,
685
+ },
686
+};
687
+
688
+DEFINE_TYPES(fsl_imx8mp_types)
689
diff --git a/hw/arm/imx8mp-evk.c b/hw/arm/imx8mp-evk.c
690
new file mode 100644
691
index XXXXXXX..XXXXXXX
692
--- /dev/null
693
+++ b/hw/arm/imx8mp-evk.c
694
@@ -XXX,XX +XXX,XX @@
695
+/*
696
+ * NXP i.MX 8M Plus Evaluation Kit System Emulation
697
+ *
698
+ * Copyright (c) 2024, Bernhard Beschow <shentey@gmail.com>
699
+ *
700
+ * SPDX-License-Identifier: GPL-2.0-or-later
701
+ */
702
+
703
+#include "qemu/osdep.h"
704
+#include "exec/address-spaces.h"
705
+#include "hw/arm/boot.h"
706
+#include "hw/arm/fsl-imx8mp.h"
707
+#include "hw/boards.h"
708
+#include "system/qtest.h"
709
+#include "qemu/error-report.h"
710
+#include "qapi/error.h"
711
+
712
+static void imx8mp_evk_init(MachineState *machine)
713
+{
714
+ static struct arm_boot_info boot_info;
715
+ FslImx8mpState *s;
716
+
717
+ if (machine->ram_size > FSL_IMX8MP_RAM_SIZE_MAX) {
718
+ error_report("RAM size " RAM_ADDR_FMT " above max supported (%08" PRIx64 ")",
719
+ machine->ram_size, FSL_IMX8MP_RAM_SIZE_MAX);
720
+ exit(1);
721
+ }
722
+
723
+ boot_info = (struct arm_boot_info) {
724
+ .loader_start = FSL_IMX8MP_RAM_START,
725
+ .board_id = -1,
726
+ .ram_size = machine->ram_size,
727
+ .psci_conduit = QEMU_PSCI_CONDUIT_SMC,
728
+ };
729
+
730
+ s = FSL_IMX8MP(object_new(TYPE_FSL_IMX8MP));
731
+ object_property_add_child(OBJECT(machine), "soc", OBJECT(s));
732
+ qdev_realize(DEVICE(s), NULL, &error_fatal);
733
+
734
+ memory_region_add_subregion(get_system_memory(), FSL_IMX8MP_RAM_START,
735
+ machine->ram);
736
+
737
+ if (!qtest_enabled()) {
738
+ arm_load_kernel(&s->cpu[0], machine, &boot_info);
739
+ }
740
+}
741
+
742
+static void imx8mp_evk_machine_init(MachineClass *mc)
743
+{
744
+ mc->desc = "NXP i.MX 8M Plus EVK Board";
745
+ mc->init = imx8mp_evk_init;
746
+ mc->max_cpus = FSL_IMX8MP_NUM_CPUS;
747
+ mc->default_ram_id = "imx8mp-evk.ram";
748
+}
749
+DEFINE_MACHINE("imx8mp-evk", imx8mp_evk_machine_init)
750
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
751
index XXXXXXX..XXXXXXX 100644
752
--- a/hw/arm/Kconfig
753
+++ b/hw/arm/Kconfig
754
@@ -XXX,XX +XXX,XX @@ config FSL_IMX7
755
select UNIMP
756
select USB_CHIPIDEA
757
758
+config FSL_IMX8MP
759
+ bool
760
+ select ARM_GIC
761
+ select IMX
762
+ select UNIMP
763
+
764
+config FSL_IMX8MP_EVK
765
+ bool
766
+ default y
767
+ depends on TCG && AARCH64
768
+ select FSL_IMX8MP
769
+
770
config ARM_SMMUV3
771
bool
772
773
diff --git a/hw/arm/meson.build b/hw/arm/meson.build
774
index XXXXXXX..XXXXXXX 100644
775
--- a/hw/arm/meson.build
776
+++ b/hw/arm/meson.build
777
@@ -XXX,XX +XXX,XX @@ arm_ss.add(when: 'CONFIG_MSF2', if_true: files('msf2-soc.c'))
778
arm_ss.add(when: 'CONFIG_MUSCA', if_true: files('musca.c'))
779
arm_ss.add(when: 'CONFIG_ARMSSE', if_true: files('armsse.c'))
780
arm_ss.add(when: 'CONFIG_FSL_IMX7', if_true: files('fsl-imx7.c', 'mcimx7d-sabre.c'))
781
+arm_ss.add(when: 'CONFIG_FSL_IMX8MP', if_true: files('fsl-imx8mp.c'))
782
+arm_ss.add(when: 'CONFIG_FSL_IMX8MP_EVK', if_true: files('imx8mp-evk.c'))
783
arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmuv3.c'))
784
arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c'))
785
arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c'))
786
--
787
2.43.0
diff view generated by jsdifflib
New patch
1
From: Bernhard Beschow <shentey@gmail.com>
1
2
3
Fixes quite a few stack traces during the Linux boot process. Also provides the
4
clocks for devices added later, e.g. enet1.
5
6
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
7
Message-id: 20250223114708.1780-6-shentey@gmail.com
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
11
MAINTAINERS | 2 +
12
docs/system/arm/imx8mp-evk.rst | 1 +
13
include/hw/arm/fsl-imx8mp.h | 4 +
14
include/hw/misc/imx8mp_analog.h | 81 +++++++++++++++
15
include/hw/misc/imx8mp_ccm.h | 30 ++++++
16
hw/arm/fsl-imx8mp.c | 20 ++++
17
hw/misc/imx8mp_analog.c | 160 +++++++++++++++++++++++++++++
18
hw/misc/imx8mp_ccm.c | 175 ++++++++++++++++++++++++++++++++
19
hw/arm/Kconfig | 2 +
20
hw/misc/Kconfig | 6 ++
21
hw/misc/meson.build | 2 +
22
11 files changed, 483 insertions(+)
23
create mode 100644 include/hw/misc/imx8mp_analog.h
24
create mode 100644 include/hw/misc/imx8mp_ccm.h
25
create mode 100644 hw/misc/imx8mp_analog.c
26
create mode 100644 hw/misc/imx8mp_ccm.c
27
28
diff --git a/MAINTAINERS b/MAINTAINERS
29
index XXXXXXX..XXXXXXX 100644
30
--- a/MAINTAINERS
31
+++ b/MAINTAINERS
32
@@ -XXX,XX +XXX,XX @@ L: qemu-arm@nongnu.org
33
S: Maintained
34
F: hw/arm/imx8mp-evk.c
35
F: hw/arm/fsl-imx8mp.c
36
+F: hw/misc/imx8mp_*.c
37
F: include/hw/arm/fsl-imx8mp.h
38
+F: include/hw/misc/imx8mp_*.h
39
F: docs/system/arm/imx8mp-evk.rst
40
41
MPS2 / MPS3
42
diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8mp-evk.rst
43
index XXXXXXX..XXXXXXX 100644
44
--- a/docs/system/arm/imx8mp-evk.rst
45
+++ b/docs/system/arm/imx8mp-evk.rst
46
@@ -XXX,XX +XXX,XX @@ The ``imx8mp-evk`` machine implements the following devices:
47
* Up to 4 Cortex-A53 cores
48
* Generic Interrupt Controller (GICv3)
49
* 4 UARTs
50
+ * Clock Tree
51
52
Boot options
53
------------
54
diff --git a/include/hw/arm/fsl-imx8mp.h b/include/hw/arm/fsl-imx8mp.h
55
index XXXXXXX..XXXXXXX 100644
56
--- a/include/hw/arm/fsl-imx8mp.h
57
+++ b/include/hw/arm/fsl-imx8mp.h
58
@@ -XXX,XX +XXX,XX @@
59
#include "cpu.h"
60
#include "hw/char/imx_serial.h"
61
#include "hw/intc/arm_gicv3_common.h"
62
+#include "hw/misc/imx8mp_analog.h"
63
+#include "hw/misc/imx8mp_ccm.h"
64
#include "qom/object.h"
65
#include "qemu/units.h"
66
67
@@ -XXX,XX +XXX,XX @@ struct FslImx8mpState {
68
69
ARMCPU cpu[FSL_IMX8MP_NUM_CPUS];
70
GICv3State gic;
71
+ IMX8MPCCMState ccm;
72
+ IMX8MPAnalogState analog;
73
IMXSerialState uart[FSL_IMX8MP_NUM_UARTS];
74
};
75
76
diff --git a/include/hw/misc/imx8mp_analog.h b/include/hw/misc/imx8mp_analog.h
77
new file mode 100644
78
index XXXXXXX..XXXXXXX
79
--- /dev/null
80
+++ b/include/hw/misc/imx8mp_analog.h
81
@@ -XXX,XX +XXX,XX @@
82
+/*
83
+ * Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
84
+ *
85
+ * i.MX8MP ANALOG IP block emulation code
86
+ *
87
+ * SPDX-License-Identifier: GPL-2.0-or-later
88
+ */
89
+
90
+#ifndef IMX8MP_ANALOG_H
91
+#define IMX8MP_ANALOG_H
92
+
93
+#include "qom/object.h"
94
+#include "hw/sysbus.h"
95
+
96
+enum IMX8MPAnalogRegisters {
97
+ ANALOG_AUDIO_PLL1_GEN_CTRL = 0x000 / 4,
98
+ ANALOG_AUDIO_PLL1_FDIV_CTL0 = 0x004 / 4,
99
+ ANALOG_AUDIO_PLL1_FDIV_CTL1 = 0x008 / 4,
100
+ ANALOG_AUDIO_PLL1_SSCG_CTRL = 0x00c / 4,
101
+ ANALOG_AUDIO_PLL1_MNIT_CTRL = 0x010 / 4,
102
+ ANALOG_AUDIO_PLL2_GEN_CTRL = 0x014 / 4,
103
+ ANALOG_AUDIO_PLL2_FDIV_CTL0 = 0x018 / 4,
104
+ ANALOG_AUDIO_PLL2_FDIV_CTL1 = 0x01c / 4,
105
+ ANALOG_AUDIO_PLL2_SSCG_CTRL = 0x020 / 4,
106
+ ANALOG_AUDIO_PLL2_MNIT_CTRL = 0x024 / 4,
107
+ ANALOG_VIDEO_PLL1_GEN_CTRL = 0x028 / 4,
108
+ ANALOG_VIDEO_PLL1_FDIV_CTL0 = 0x02c / 4,
109
+ ANALOG_VIDEO_PLL1_FDIV_CTL1 = 0x030 / 4,
110
+ ANALOG_VIDEO_PLL1_SSCG_CTRL = 0x034 / 4,
111
+ ANALOG_VIDEO_PLL1_MNIT_CTRL = 0x038 / 4,
112
+ ANALOG_DRAM_PLL_GEN_CTRL = 0x050 / 4,
113
+ ANALOG_DRAM_PLL_FDIV_CTL0 = 0x054 / 4,
114
+ ANALOG_DRAM_PLL_FDIV_CTL1 = 0x058 / 4,
115
+ ANALOG_DRAM_PLL_SSCG_CTRL = 0x05c / 4,
116
+ ANALOG_DRAM_PLL_MNIT_CTRL = 0x060 / 4,
117
+ ANALOG_GPU_PLL_GEN_CTRL = 0x064 / 4,
118
+ ANALOG_GPU_PLL_FDIV_CTL0 = 0x068 / 4,
119
+ ANALOG_GPU_PLL_LOCKD_CTRL = 0x06c / 4,
120
+ ANALOG_GPU_PLL_MNIT_CTRL = 0x070 / 4,
121
+ ANALOG_VPU_PLL_GEN_CTRL = 0x074 / 4,
122
+ ANALOG_VPU_PLL_FDIV_CTL0 = 0x078 / 4,
123
+ ANALOG_VPU_PLL_LOCKD_CTRL = 0x07c / 4,
124
+ ANALOG_VPU_PLL_MNIT_CTRL = 0x080 / 4,
125
+ ANALOG_ARM_PLL_GEN_CTRL = 0x084 / 4,
126
+ ANALOG_ARM_PLL_FDIV_CTL0 = 0x088 / 4,
127
+ ANALOG_ARM_PLL_LOCKD_CTRL = 0x08c / 4,
128
+ ANALOG_ARM_PLL_MNIT_CTRL = 0x090 / 4,
129
+ ANALOG_SYS_PLL1_GEN_CTRL = 0x094 / 4,
130
+ ANALOG_SYS_PLL1_FDIV_CTL0 = 0x098 / 4,
131
+ ANALOG_SYS_PLL1_LOCKD_CTRL = 0x09c / 4,
132
+ ANALOG_SYS_PLL1_MNIT_CTRL = 0x100 / 4,
133
+ ANALOG_SYS_PLL2_GEN_CTRL = 0x104 / 4,
134
+ ANALOG_SYS_PLL2_FDIV_CTL0 = 0x108 / 4,
135
+ ANALOG_SYS_PLL2_LOCKD_CTRL = 0x10c / 4,
136
+ ANALOG_SYS_PLL2_MNIT_CTRL = 0x110 / 4,
137
+ ANALOG_SYS_PLL3_GEN_CTRL = 0x114 / 4,
138
+ ANALOG_SYS_PLL3_FDIV_CTL0 = 0x118 / 4,
139
+ ANALOG_SYS_PLL3_LOCKD_CTRL = 0x11c / 4,
140
+ ANALOG_SYS_PLL3_MNIT_CTRL = 0x120 / 4,
141
+ ANALOG_OSC_MISC_CFG = 0x124 / 4,
142
+ ANALOG_ANAMIX_PLL_MNIT_CTL = 0x128 / 4,
143
+
144
+ ANALOG_DIGPROG = 0x800 / 4,
145
+ ANALOG_MAX,
146
+};
147
+
148
+#define TYPE_IMX8MP_ANALOG "imx8mp.analog"
149
+OBJECT_DECLARE_SIMPLE_TYPE(IMX8MPAnalogState, IMX8MP_ANALOG)
150
+
151
+struct IMX8MPAnalogState {
152
+ SysBusDevice parent_obj;
153
+
154
+ struct {
155
+ MemoryRegion container;
156
+ MemoryRegion analog;
157
+ } mmio;
158
+
159
+ uint32_t analog[ANALOG_MAX];
160
+};
161
+
162
+#endif /* IMX8MP_ANALOG_H */
163
diff --git a/include/hw/misc/imx8mp_ccm.h b/include/hw/misc/imx8mp_ccm.h
164
new file mode 100644
165
index XXXXXXX..XXXXXXX
166
--- /dev/null
167
+++ b/include/hw/misc/imx8mp_ccm.h
168
@@ -XXX,XX +XXX,XX @@
169
+/*
170
+ * Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
171
+ *
172
+ * i.MX 8M Plus CCM IP block emulation code
173
+ *
174
+ * SPDX-License-Identifier: GPL-2.0-or-later
175
+ */
176
+
177
+#ifndef IMX8MP_CCM_H
178
+#define IMX8MP_CCM_H
179
+
180
+#include "hw/misc/imx_ccm.h"
181
+#include "qom/object.h"
182
+
183
+enum IMX8MPCCMRegisters {
184
+ CCM_MAX = 0xc6fc / sizeof(uint32_t) + 1,
185
+};
186
+
187
+#define TYPE_IMX8MP_CCM "imx8mp.ccm"
188
+OBJECT_DECLARE_SIMPLE_TYPE(IMX8MPCCMState, IMX8MP_CCM)
189
+
190
+struct IMX8MPCCMState {
191
+ IMXCCMState parent_obj;
192
+
193
+ MemoryRegion iomem;
194
+
195
+ uint32_t ccm[CCM_MAX];
196
+};
197
+
198
+#endif /* IMX8MP_CCM_H */
199
diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c
200
index XXXXXXX..XXXXXXX 100644
201
--- a/hw/arm/fsl-imx8mp.c
202
+++ b/hw/arm/fsl-imx8mp.c
203
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_init(Object *obj)
204
205
object_initialize_child(obj, "gic", &s->gic, TYPE_ARM_GICV3);
206
207
+ object_initialize_child(obj, "ccm", &s->ccm, TYPE_IMX8MP_CCM);
208
+
209
+ object_initialize_child(obj, "analog", &s->analog, TYPE_IMX8MP_ANALOG);
210
+
211
for (i = 0; i < FSL_IMX8MP_NUM_UARTS; i++) {
212
g_autofree char *name = g_strdup_printf("uart%d", i + 1);
213
object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL);
214
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
215
}
216
}
217
218
+ /* CCM */
219
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->ccm), errp)) {
220
+ return;
221
+ }
222
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccm), 0,
223
+ fsl_imx8mp_memmap[FSL_IMX8MP_CCM].addr);
224
+
225
+ /* Analog */
226
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->analog), errp)) {
227
+ return;
228
+ }
229
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->analog), 0,
230
+ fsl_imx8mp_memmap[FSL_IMX8MP_ANA_PLL].addr);
231
+
232
/* UARTs */
233
for (i = 0; i < FSL_IMX8MP_NUM_UARTS; i++) {
234
struct {
235
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
236
/* Unimplemented devices */
237
for (i = 0; i < ARRAY_SIZE(fsl_imx8mp_memmap); i++) {
238
switch (i) {
239
+ case FSL_IMX8MP_ANA_PLL:
240
+ case FSL_IMX8MP_CCM:
241
case FSL_IMX8MP_GIC_DIST:
242
case FSL_IMX8MP_GIC_REDIST:
243
case FSL_IMX8MP_RAM:
244
diff --git a/hw/misc/imx8mp_analog.c b/hw/misc/imx8mp_analog.c
245
new file mode 100644
246
index XXXXXXX..XXXXXXX
247
--- /dev/null
248
+++ b/hw/misc/imx8mp_analog.c
249
@@ -XXX,XX +XXX,XX @@
250
+/*
251
+ * Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
252
+ *
253
+ * i.MX 8M Plus ANALOG IP block emulation code
254
+ *
255
+ * Based on hw/misc/imx7_ccm.c
256
+ *
257
+ * SPDX-License-Identifier: GPL-2.0-or-later
258
+ */
259
+
260
+#include "qemu/osdep.h"
261
+#include "qemu/log.h"
262
+
263
+#include "hw/misc/imx8mp_analog.h"
264
+#include "migration/vmstate.h"
265
+
266
+#define ANALOG_PLL_LOCK BIT(31)
267
+
268
+static void imx8mp_analog_reset(DeviceState *dev)
269
+{
270
+ IMX8MPAnalogState *s = IMX8MP_ANALOG(dev);
271
+
272
+ memset(s->analog, 0, sizeof(s->analog));
273
+
274
+ s->analog[ANALOG_AUDIO_PLL1_GEN_CTRL] = 0x00002010;
275
+ s->analog[ANALOG_AUDIO_PLL1_FDIV_CTL0] = 0x00145032;
276
+ s->analog[ANALOG_AUDIO_PLL1_FDIV_CTL1] = 0x00000000;
277
+ s->analog[ANALOG_AUDIO_PLL1_SSCG_CTRL] = 0x00000000;
278
+ s->analog[ANALOG_AUDIO_PLL1_MNIT_CTRL] = 0x00100103;
279
+ s->analog[ANALOG_AUDIO_PLL2_GEN_CTRL] = 0x00002010;
280
+ s->analog[ANALOG_AUDIO_PLL2_FDIV_CTL0] = 0x00145032;
281
+ s->analog[ANALOG_AUDIO_PLL2_FDIV_CTL1] = 0x00000000;
282
+ s->analog[ANALOG_AUDIO_PLL2_SSCG_CTRL] = 0x00000000;
283
+ s->analog[ANALOG_AUDIO_PLL2_MNIT_CTRL] = 0x00100103;
284
+ s->analog[ANALOG_VIDEO_PLL1_GEN_CTRL] = 0x00002010;
285
+ s->analog[ANALOG_VIDEO_PLL1_FDIV_CTL0] = 0x00145032;
286
+ s->analog[ANALOG_VIDEO_PLL1_FDIV_CTL1] = 0x00000000;
287
+ s->analog[ANALOG_VIDEO_PLL1_SSCG_CTRL] = 0x00000000;
288
+ s->analog[ANALOG_VIDEO_PLL1_MNIT_CTRL] = 0x00100103;
289
+ s->analog[ANALOG_DRAM_PLL_GEN_CTRL] = 0x00002010;
290
+ s->analog[ANALOG_DRAM_PLL_FDIV_CTL0] = 0x0012c032;
291
+ s->analog[ANALOG_DRAM_PLL_FDIV_CTL1] = 0x00000000;
292
+ s->analog[ANALOG_DRAM_PLL_SSCG_CTRL] = 0x00000000;
293
+ s->analog[ANALOG_DRAM_PLL_MNIT_CTRL] = 0x00100103;
294
+ s->analog[ANALOG_GPU_PLL_GEN_CTRL] = 0x00000810;
295
+ s->analog[ANALOG_GPU_PLL_FDIV_CTL0] = 0x000c8031;
296
+ s->analog[ANALOG_GPU_PLL_LOCKD_CTRL] = 0x0010003f;
297
+ s->analog[ANALOG_GPU_PLL_MNIT_CTRL] = 0x00280081;
298
+ s->analog[ANALOG_VPU_PLL_GEN_CTRL] = 0x00000810;
299
+ s->analog[ANALOG_VPU_PLL_FDIV_CTL0] = 0x0012c032;
300
+ s->analog[ANALOG_VPU_PLL_LOCKD_CTRL] = 0x0010003f;
301
+ s->analog[ANALOG_VPU_PLL_MNIT_CTRL] = 0x00280081;
302
+ s->analog[ANALOG_ARM_PLL_GEN_CTRL] = 0x00000810;
303
+ s->analog[ANALOG_ARM_PLL_FDIV_CTL0] = 0x000fa031;
304
+ s->analog[ANALOG_ARM_PLL_LOCKD_CTRL] = 0x0010003f;
305
+ s->analog[ANALOG_ARM_PLL_MNIT_CTRL] = 0x00280081;
306
+ s->analog[ANALOG_SYS_PLL1_GEN_CTRL] = 0x0aaaa810;
307
+ s->analog[ANALOG_SYS_PLL1_FDIV_CTL0] = 0x00190032;
308
+ s->analog[ANALOG_SYS_PLL1_LOCKD_CTRL] = 0x0010003f;
309
+ s->analog[ANALOG_SYS_PLL1_MNIT_CTRL] = 0x00280081;
310
+ s->analog[ANALOG_SYS_PLL2_GEN_CTRL] = 0x0aaaa810;
311
+ s->analog[ANALOG_SYS_PLL2_FDIV_CTL0] = 0x000fa031;
312
+ s->analog[ANALOG_SYS_PLL2_LOCKD_CTRL] = 0x0010003f;
313
+ s->analog[ANALOG_SYS_PLL2_MNIT_CTRL] = 0x00280081;
314
+ s->analog[ANALOG_SYS_PLL3_GEN_CTRL] = 0x00000810;
315
+ s->analog[ANALOG_SYS_PLL3_FDIV_CTL0] = 0x000fa031;
316
+ s->analog[ANALOG_SYS_PLL3_LOCKD_CTRL] = 0x0010003f;
317
+ s->analog[ANALOG_SYS_PLL3_MNIT_CTRL] = 0x00280081;
318
+ s->analog[ANALOG_OSC_MISC_CFG] = 0x00000000;
319
+ s->analog[ANALOG_ANAMIX_PLL_MNIT_CTL] = 0x00000000;
320
+ s->analog[ANALOG_DIGPROG] = 0x00824010;
321
+
322
+ /* all PLLs need to be locked */
323
+ s->analog[ANALOG_AUDIO_PLL1_GEN_CTRL] |= ANALOG_PLL_LOCK;
324
+ s->analog[ANALOG_AUDIO_PLL2_GEN_CTRL] |= ANALOG_PLL_LOCK;
325
+ s->analog[ANALOG_VIDEO_PLL1_GEN_CTRL] |= ANALOG_PLL_LOCK;
326
+ s->analog[ANALOG_DRAM_PLL_GEN_CTRL] |= ANALOG_PLL_LOCK;
327
+ s->analog[ANALOG_GPU_PLL_GEN_CTRL] |= ANALOG_PLL_LOCK;
328
+ s->analog[ANALOG_VPU_PLL_GEN_CTRL] |= ANALOG_PLL_LOCK;
329
+ s->analog[ANALOG_ARM_PLL_GEN_CTRL] |= ANALOG_PLL_LOCK;
330
+ s->analog[ANALOG_SYS_PLL1_GEN_CTRL] |= ANALOG_PLL_LOCK;
331
+ s->analog[ANALOG_SYS_PLL2_GEN_CTRL] |= ANALOG_PLL_LOCK;
332
+ s->analog[ANALOG_SYS_PLL3_GEN_CTRL] |= ANALOG_PLL_LOCK;
333
+}
334
+
335
+static uint64_t imx8mp_analog_read(void *opaque, hwaddr offset, unsigned size)
336
+{
337
+ IMX8MPAnalogState *s = opaque;
338
+
339
+ return s->analog[offset >> 2];
340
+}
341
+
342
+static void imx8mp_analog_write(void *opaque, hwaddr offset,
343
+ uint64_t value, unsigned size)
344
+{
345
+ IMX8MPAnalogState *s = opaque;
346
+
347
+ if (offset >> 2 == ANALOG_DIGPROG) {
348
+ qemu_log_mask(LOG_GUEST_ERROR,
349
+ "Guest write to read-only ANALOG_DIGPROG register\n");
350
+ } else {
351
+ s->analog[offset >> 2] = value;
352
+ }
353
+}
354
+
355
+static const struct MemoryRegionOps imx8mp_analog_ops = {
356
+ .read = imx8mp_analog_read,
357
+ .write = imx8mp_analog_write,
358
+ .endianness = DEVICE_NATIVE_ENDIAN,
359
+ .impl = {
360
+ .min_access_size = 4,
361
+ .max_access_size = 4,
362
+ .unaligned = false,
363
+ },
364
+};
365
+
366
+static void imx8mp_analog_init(Object *obj)
367
+{
368
+ IMX8MPAnalogState *s = IMX8MP_ANALOG(obj);
369
+ SysBusDevice *sd = SYS_BUS_DEVICE(obj);
370
+
371
+ memory_region_init(&s->mmio.container, obj, TYPE_IMX8MP_ANALOG, 0x10000);
372
+
373
+ memory_region_init_io(&s->mmio.analog, obj, &imx8mp_analog_ops, s,
374
+ TYPE_IMX8MP_ANALOG, sizeof(s->analog));
375
+ memory_region_add_subregion(&s->mmio.container, 0, &s->mmio.analog);
376
+
377
+ sysbus_init_mmio(sd, &s->mmio.container);
378
+}
379
+
380
+static const VMStateDescription imx8mp_analog_vmstate = {
381
+ .name = TYPE_IMX8MP_ANALOG,
382
+ .version_id = 1,
383
+ .minimum_version_id = 1,
384
+ .fields = (const VMStateField[]) {
385
+ VMSTATE_UINT32_ARRAY(analog, IMX8MPAnalogState, ANALOG_MAX),
386
+ VMSTATE_END_OF_LIST()
387
+ },
388
+};
389
+
390
+static void imx8mp_analog_class_init(ObjectClass *klass, void *data)
391
+{
392
+ DeviceClass *dc = DEVICE_CLASS(klass);
393
+
394
+ device_class_set_legacy_reset(dc, imx8mp_analog_reset);
395
+ dc->vmsd = &imx8mp_analog_vmstate;
396
+ dc->desc = "i.MX 8M Plus Analog Module";
397
+}
398
+
399
+static const TypeInfo imx8mp_analog_types[] = {
400
+ {
401
+ .name = TYPE_IMX8MP_ANALOG,
402
+ .parent = TYPE_SYS_BUS_DEVICE,
403
+ .instance_size = sizeof(IMX8MPAnalogState),
404
+ .instance_init = imx8mp_analog_init,
405
+ .class_init = imx8mp_analog_class_init,
406
+ }
407
+};
408
+
409
+DEFINE_TYPES(imx8mp_analog_types);
410
diff --git a/hw/misc/imx8mp_ccm.c b/hw/misc/imx8mp_ccm.c
411
new file mode 100644
412
index XXXXXXX..XXXXXXX
413
--- /dev/null
414
+++ b/hw/misc/imx8mp_ccm.c
415
@@ -XXX,XX +XXX,XX @@
416
+/*
417
+ * Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
418
+ *
419
+ * i.MX 8M Plus CCM IP block emulation code
420
+ *
421
+ * Based on hw/misc/imx7_ccm.c
422
+ *
423
+ * SPDX-License-Identifier: GPL-2.0-or-later
424
+ */
425
+
426
+#include "qemu/osdep.h"
427
+#include "qemu/log.h"
428
+
429
+#include "hw/misc/imx8mp_ccm.h"
430
+#include "migration/vmstate.h"
431
+
432
+#include "trace.h"
433
+
434
+#define CKIH_FREQ 16000000 /* 16MHz crystal input */
435
+
436
+static void imx8mp_ccm_reset(DeviceState *dev)
437
+{
438
+ IMX8MPCCMState *s = IMX8MP_CCM(dev);
439
+
440
+ memset(s->ccm, 0, sizeof(s->ccm));
441
+}
442
+
443
+#define CCM_INDEX(offset) (((offset) & ~(hwaddr)0xF) / sizeof(uint32_t))
444
+#define CCM_BITOP(offset) ((offset) & (hwaddr)0xF)
445
+
446
+enum {
447
+ CCM_BITOP_NONE = 0x00,
448
+ CCM_BITOP_SET = 0x04,
449
+ CCM_BITOP_CLR = 0x08,
450
+ CCM_BITOP_TOG = 0x0C,
451
+};
452
+
453
+static uint64_t imx8mp_set_clr_tog_read(void *opaque, hwaddr offset,
454
+ unsigned size)
455
+{
456
+ const uint32_t *mmio = opaque;
457
+
458
+ return mmio[CCM_INDEX(offset)];
459
+}
460
+
461
+static void imx8mp_set_clr_tog_write(void *opaque, hwaddr offset,
462
+ uint64_t value, unsigned size)
463
+{
464
+ const uint8_t bitop = CCM_BITOP(offset);
465
+ const uint32_t index = CCM_INDEX(offset);
466
+ uint32_t *mmio = opaque;
467
+
468
+ switch (bitop) {
469
+ case CCM_BITOP_NONE:
470
+ mmio[index] = value;
471
+ break;
472
+ case CCM_BITOP_SET:
473
+ mmio[index] |= value;
474
+ break;
475
+ case CCM_BITOP_CLR:
476
+ mmio[index] &= ~value;
477
+ break;
478
+ case CCM_BITOP_TOG:
479
+ mmio[index] ^= value;
480
+ break;
481
+ };
482
+}
483
+
484
+static const struct MemoryRegionOps imx8mp_set_clr_tog_ops = {
485
+ .read = imx8mp_set_clr_tog_read,
486
+ .write = imx8mp_set_clr_tog_write,
487
+ .endianness = DEVICE_NATIVE_ENDIAN,
488
+ .impl = {
489
+ /*
490
+ * Our device would not work correctly if the guest was doing
491
+ * unaligned access. This might not be a limitation on the real
492
+ * device but in practice there is no reason for a guest to access
493
+ * this device unaligned.
494
+ */
495
+ .min_access_size = 4,
496
+ .max_access_size = 4,
497
+ .unaligned = false,
498
+ },
499
+};
500
+
501
+static void imx8mp_ccm_init(Object *obj)
502
+{
503
+ SysBusDevice *sd = SYS_BUS_DEVICE(obj);
504
+ IMX8MPCCMState *s = IMX8MP_CCM(obj);
505
+
506
+ memory_region_init_io(&s->iomem,
507
+ obj,
508
+ &imx8mp_set_clr_tog_ops,
509
+ s->ccm,
510
+ TYPE_IMX8MP_CCM ".ccm",
511
+ sizeof(s->ccm));
512
+
513
+ sysbus_init_mmio(sd, &s->iomem);
514
+}
515
+
516
+static const VMStateDescription imx8mp_ccm_vmstate = {
517
+ .name = TYPE_IMX8MP_CCM,
518
+ .version_id = 1,
519
+ .minimum_version_id = 1,
520
+ .fields = (const VMStateField[]) {
521
+ VMSTATE_UINT32_ARRAY(ccm, IMX8MPCCMState, CCM_MAX),
522
+ VMSTATE_END_OF_LIST()
523
+ },
524
+};
525
+
526
+static uint32_t imx8mp_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock)
527
+{
528
+ /*
529
+ * This function is "consumed" by GPT emulation code. Some clocks
530
+ * have fixed frequencies and we can provide requested frequency
531
+ * easily. However for CCM provided clocks (like IPG) each GPT
532
+ * timer can have its own clock root.
533
+ * This means we need additional information when calling this
534
+ * function to know the requester's identity.
535
+ */
536
+ uint32_t freq = 0;
537
+
538
+ switch (clock) {
539
+ case CLK_NONE:
540
+ break;
541
+ case CLK_32k:
542
+ freq = CKIL_FREQ;
543
+ break;
544
+ case CLK_HIGH:
545
+ freq = CKIH_FREQ;
546
+ break;
547
+ case CLK_IPG:
548
+ case CLK_IPG_HIGH:
549
+ /*
550
+ * For now we don't have a way to figure out the device this
551
+ * function is called for. Until then the IPG derived clocks
552
+ * are left unimplemented.
553
+ */
554
+ qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Clock %d Not implemented\n",
555
+ TYPE_IMX8MP_CCM, __func__, clock);
556
+ break;
557
+ default:
558
+ qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: unsupported clock %d\n",
559
+ TYPE_IMX8MP_CCM, __func__, clock);
560
+ break;
561
+ }
562
+
563
+ trace_ccm_clock_freq(clock, freq);
564
+
565
+ return freq;
566
+}
567
+
568
+static void imx8mp_ccm_class_init(ObjectClass *klass, void *data)
569
+{
570
+ DeviceClass *dc = DEVICE_CLASS(klass);
571
+ IMXCCMClass *ccm = IMX_CCM_CLASS(klass);
572
+
573
+ device_class_set_legacy_reset(dc, imx8mp_ccm_reset);
574
+ dc->vmsd = &imx8mp_ccm_vmstate;
575
+ dc->desc = "i.MX 8M Plus Clock Control Module";
576
+
577
+ ccm->get_clock_frequency = imx8mp_ccm_get_clock_frequency;
578
+}
579
+
580
+static const TypeInfo imx8mp_ccm_types[] = {
581
+ {
582
+ .name = TYPE_IMX8MP_CCM,
583
+ .parent = TYPE_IMX_CCM,
584
+ .instance_size = sizeof(IMX8MPCCMState),
585
+ .instance_init = imx8mp_ccm_init,
586
+ .class_init = imx8mp_ccm_class_init,
587
+ },
588
+};
589
+
590
+DEFINE_TYPES(imx8mp_ccm_types);
591
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
592
index XXXXXXX..XXXXXXX 100644
593
--- a/hw/arm/Kconfig
594
+++ b/hw/arm/Kconfig
595
@@ -XXX,XX +XXX,XX @@ config FSL_IMX7
596
config FSL_IMX8MP
597
bool
598
select ARM_GIC
599
+ select FSL_IMX8MP_ANALOG
600
+ select FSL_IMX8MP_CCM
601
select IMX
602
select UNIMP
603
604
diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
605
index XXXXXXX..XXXXXXX 100644
606
--- a/hw/misc/Kconfig
607
+++ b/hw/misc/Kconfig
608
@@ -XXX,XX +XXX,XX @@ config IMX
609
select SSI
610
select USB_EHCI_SYSBUS
611
612
+config FSL_IMX8MP_ANALOG
613
+ bool
614
+
615
+config FSL_IMX8MP_CCM
616
+ bool
617
+
618
config STM32_RCC
619
bool
620
621
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
622
index XXXXXXX..XXXXXXX 100644
623
--- a/hw/misc/meson.build
624
+++ b/hw/misc/meson.build
625
@@ -XXX,XX +XXX,XX @@ system_ss.add(when: 'CONFIG_AXP2XX_PMU', if_true: files('axp2xx.c'))
626
system_ss.add(when: 'CONFIG_REALVIEW', if_true: files('arm_sysctl.c'))
627
system_ss.add(when: 'CONFIG_ECCMEMCTL', if_true: files('eccmemctl.c'))
628
system_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_pmu.c', 'exynos4210_clk.c', 'exynos4210_rng.c'))
629
+system_ss.add(when: 'CONFIG_FSL_IMX8MP_ANALOG', if_true: files('imx8mp_analog.c'))
630
+system_ss.add(when: 'CONFIG_FSL_IMX8MP_CCM', if_true: files('imx8mp_ccm.c'))
631
system_ss.add(when: 'CONFIG_IMX', if_true: files(
632
'imx25_ccm.c',
633
'imx31_ccm.c',
634
--
635
2.43.0
diff view generated by jsdifflib
New patch
1
From: Bernhard Beschow <shentey@gmail.com>
1
2
3
SNVS contains an RTC which allows Linux to deal correctly with time. This is
4
particularly useful when handling persistent storage which will be done in the
5
next patch.
6
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
9
Message-id: 20250223114708.1780-7-shentey@gmail.com
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
12
docs/system/arm/imx8mp-evk.rst | 1 +
13
include/hw/arm/fsl-imx8mp.h | 2 ++
14
hw/arm/fsl-imx8mp.c | 10 ++++++++++
15
3 files changed, 13 insertions(+)
16
17
diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8mp-evk.rst
18
index XXXXXXX..XXXXXXX 100644
19
--- a/docs/system/arm/imx8mp-evk.rst
20
+++ b/docs/system/arm/imx8mp-evk.rst
21
@@ -XXX,XX +XXX,XX @@ The ``imx8mp-evk`` machine implements the following devices:
22
* Up to 4 Cortex-A53 cores
23
* Generic Interrupt Controller (GICv3)
24
* 4 UARTs
25
+ * Secure Non-Volatile Storage (SNVS) including an RTC
26
* Clock Tree
27
28
Boot options
29
diff --git a/include/hw/arm/fsl-imx8mp.h b/include/hw/arm/fsl-imx8mp.h
30
index XXXXXXX..XXXXXXX 100644
31
--- a/include/hw/arm/fsl-imx8mp.h
32
+++ b/include/hw/arm/fsl-imx8mp.h
33
@@ -XXX,XX +XXX,XX @@
34
#include "cpu.h"
35
#include "hw/char/imx_serial.h"
36
#include "hw/intc/arm_gicv3_common.h"
37
+#include "hw/misc/imx7_snvs.h"
38
#include "hw/misc/imx8mp_analog.h"
39
#include "hw/misc/imx8mp_ccm.h"
40
#include "qom/object.h"
41
@@ -XXX,XX +XXX,XX @@ struct FslImx8mpState {
42
GICv3State gic;
43
IMX8MPCCMState ccm;
44
IMX8MPAnalogState analog;
45
+ IMX7SNVSState snvs;
46
IMXSerialState uart[FSL_IMX8MP_NUM_UARTS];
47
};
48
49
diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c
50
index XXXXXXX..XXXXXXX 100644
51
--- a/hw/arm/fsl-imx8mp.c
52
+++ b/hw/arm/fsl-imx8mp.c
53
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_init(Object *obj)
54
55
object_initialize_child(obj, "analog", &s->analog, TYPE_IMX8MP_ANALOG);
56
57
+ object_initialize_child(obj, "snvs", &s->snvs, TYPE_IMX7_SNVS);
58
+
59
for (i = 0; i < FSL_IMX8MP_NUM_UARTS; i++) {
60
g_autofree char *name = g_strdup_printf("uart%d", i + 1);
61
object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL);
62
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
63
qdev_get_gpio_in(gicdev, serial_table[i].irq));
64
}
65
66
+ /* SNVS */
67
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->snvs), errp)) {
68
+ return;
69
+ }
70
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->snvs), 0,
71
+ fsl_imx8mp_memmap[FSL_IMX8MP_SNVS_HP].addr);
72
+
73
/* Unimplemented devices */
74
for (i = 0; i < ARRAY_SIZE(fsl_imx8mp_memmap); i++) {
75
switch (i) {
76
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
77
case FSL_IMX8MP_GIC_DIST:
78
case FSL_IMX8MP_GIC_REDIST:
79
case FSL_IMX8MP_RAM:
80
+ case FSL_IMX8MP_SNVS_HP:
81
case FSL_IMX8MP_UART1 ... FSL_IMX8MP_UART4:
82
/* device implemented and treated above */
83
break;
84
--
85
2.43.0
diff view generated by jsdifflib
New patch
1
From: Bernhard Beschow <shentey@gmail.com>
1
2
3
The USDHC emulation allows for running real-world images such as those generated
4
by Buildroot. Convert the board documentation accordingly instead of running a
5
Linux kernel with ephemeral storage.
6
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
9
Message-id: 20250223114708.1780-8-shentey@gmail.com
10
[PMM: drop 'static const' from usdhc_table[] for GCC 7.5]
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
---
13
docs/system/arm/imx8mp-evk.rst | 18 ++++++++++++------
14
include/hw/arm/fsl-imx8mp.h | 7 +++++++
15
hw/arm/fsl-imx8mp.c | 28 ++++++++++++++++++++++++++++
16
hw/arm/imx8mp-evk.c | 18 ++++++++++++++++++
17
hw/arm/Kconfig | 1 +
18
5 files changed, 66 insertions(+), 6 deletions(-)
19
20
diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8mp-evk.rst
21
index XXXXXXX..XXXXXXX 100644
22
--- a/docs/system/arm/imx8mp-evk.rst
23
+++ b/docs/system/arm/imx8mp-evk.rst
24
@@ -XXX,XX +XXX,XX @@ The ``imx8mp-evk`` machine implements the following devices:
25
* Up to 4 Cortex-A53 cores
26
* Generic Interrupt Controller (GICv3)
27
* 4 UARTs
28
+ * 3 USDHC Storage Controllers
29
* Secure Non-Volatile Storage (SNVS) including an RTC
30
* Clock Tree
31
32
@@ -XXX,XX +XXX,XX @@ Direct Linux Kernel Boot
33
34
Probably the easiest way to get started with a whole Linux system on the machine
35
is to generate an image with Buildroot. Version 2024.11.1 is tested at the time
36
-of writing and involves two steps. First run the following commands in the
37
+of writing and involves three steps. First run the following commands in the
38
toplevel directory of the Buildroot source tree:
39
40
.. code-block:: bash
41
42
- $ echo "BR2_TARGET_ROOTFS_CPIO=y" >> configs/freescale_imx8mpevk_defconfig
43
$ make freescale_imx8mpevk_defconfig
44
$ make
45
46
Once finished successfully there is an ``output/image`` subfolder. Navigate into
47
-it and patch the device tree with the following commands which will remove the
48
-``cpu-idle-states`` properties from CPU nodes:
49
+it and resize the SD card image to a power of two:
50
+
51
+.. code-block:: bash
52
+
53
+ $ qemu-img resize sdcard.img 256M
54
+
55
+Finally, the device tree needs to be patched with the following commands which
56
+will remove the ``cpu-idle-states`` properties from CPU nodes:
57
58
.. code-block:: bash
59
60
@@ -XXX,XX +XXX,XX @@ Now that everything is prepared the machine can be started as follows:
61
-display none -serial null -serial stdio \
62
-kernel Image \
63
-dtb imx8mp-evk-patched.dtb \
64
- -initrd rootfs.cpio \
65
- -append "root=/dev/ram"
66
+ -append "root=/dev/mmcblk2p2" \
67
+ -drive file=sdcard.img,if=sd,bus=2,format=raw,id=mmcblk2
68
diff --git a/include/hw/arm/fsl-imx8mp.h b/include/hw/arm/fsl-imx8mp.h
69
index XXXXXXX..XXXXXXX 100644
70
--- a/include/hw/arm/fsl-imx8mp.h
71
+++ b/include/hw/arm/fsl-imx8mp.h
72
@@ -XXX,XX +XXX,XX @@
73
#include "hw/misc/imx7_snvs.h"
74
#include "hw/misc/imx8mp_analog.h"
75
#include "hw/misc/imx8mp_ccm.h"
76
+#include "hw/sd/sdhci.h"
77
#include "qom/object.h"
78
#include "qemu/units.h"
79
80
@@ -XXX,XX +XXX,XX @@ enum FslImx8mpConfiguration {
81
FSL_IMX8MP_NUM_CPUS = 4,
82
FSL_IMX8MP_NUM_IRQS = 160,
83
FSL_IMX8MP_NUM_UARTS = 4,
84
+ FSL_IMX8MP_NUM_USDHCS = 3,
85
};
86
87
struct FslImx8mpState {
88
@@ -XXX,XX +XXX,XX @@ struct FslImx8mpState {
89
IMX8MPAnalogState analog;
90
IMX7SNVSState snvs;
91
IMXSerialState uart[FSL_IMX8MP_NUM_UARTS];
92
+ SDHCIState usdhc[FSL_IMX8MP_NUM_USDHCS];
93
};
94
95
enum FslImx8mpMemoryRegions {
96
@@ -XXX,XX +XXX,XX @@ enum FslImx8mpMemoryRegions {
97
};
98
99
enum FslImx8mpIrqs {
100
+ FSL_IMX8MP_USDHC1_IRQ = 22,
101
+ FSL_IMX8MP_USDHC2_IRQ = 23,
102
+ FSL_IMX8MP_USDHC3_IRQ = 24,
103
+
104
FSL_IMX8MP_UART1_IRQ = 26,
105
FSL_IMX8MP_UART2_IRQ = 27,
106
FSL_IMX8MP_UART3_IRQ = 28,
107
diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c
108
index XXXXXXX..XXXXXXX 100644
109
--- a/hw/arm/fsl-imx8mp.c
110
+++ b/hw/arm/fsl-imx8mp.c
111
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_init(Object *obj)
112
g_autofree char *name = g_strdup_printf("uart%d", i + 1);
113
object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL);
114
}
115
+
116
+ for (i = 0; i < FSL_IMX8MP_NUM_USDHCS; i++) {
117
+ g_autofree char *name = g_strdup_printf("usdhc%d", i + 1);
118
+ object_initialize_child(obj, name, &s->usdhc[i], TYPE_IMX_USDHC);
119
+ }
120
}
121
122
static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
123
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
124
qdev_get_gpio_in(gicdev, serial_table[i].irq));
125
}
126
127
+ /* USDHCs */
128
+ for (i = 0; i < FSL_IMX8MP_NUM_USDHCS; i++) {
129
+ struct {
130
+ hwaddr addr;
131
+ unsigned int irq;
132
+ } usdhc_table[FSL_IMX8MP_NUM_USDHCS] = {
133
+ { fsl_imx8mp_memmap[FSL_IMX8MP_USDHC1].addr, FSL_IMX8MP_USDHC1_IRQ },
134
+ { fsl_imx8mp_memmap[FSL_IMX8MP_USDHC2].addr, FSL_IMX8MP_USDHC2_IRQ },
135
+ { fsl_imx8mp_memmap[FSL_IMX8MP_USDHC3].addr, FSL_IMX8MP_USDHC3_IRQ },
136
+ };
137
+
138
+ object_property_set_uint(OBJECT(&s->usdhc[i]), "vendor",
139
+ SDHCI_VENDOR_IMX, &error_abort);
140
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->usdhc[i]), errp)) {
141
+ return;
142
+ }
143
+
144
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->usdhc[i]), 0, usdhc_table[i].addr);
145
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->usdhc[i]), 0,
146
+ qdev_get_gpio_in(gicdev, usdhc_table[i].irq));
147
+ }
148
+
149
/* SNVS */
150
if (!sysbus_realize(SYS_BUS_DEVICE(&s->snvs), errp)) {
151
return;
152
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
153
case FSL_IMX8MP_RAM:
154
case FSL_IMX8MP_SNVS_HP:
155
case FSL_IMX8MP_UART1 ... FSL_IMX8MP_UART4:
156
+ case FSL_IMX8MP_USDHC1 ... FSL_IMX8MP_USDHC3:
157
/* device implemented and treated above */
158
break;
159
160
diff --git a/hw/arm/imx8mp-evk.c b/hw/arm/imx8mp-evk.c
161
index XXXXXXX..XXXXXXX 100644
162
--- a/hw/arm/imx8mp-evk.c
163
+++ b/hw/arm/imx8mp-evk.c
164
@@ -XXX,XX +XXX,XX @@
165
#include "hw/arm/boot.h"
166
#include "hw/arm/fsl-imx8mp.h"
167
#include "hw/boards.h"
168
+#include "hw/qdev-properties.h"
169
#include "system/qtest.h"
170
#include "qemu/error-report.h"
171
#include "qapi/error.h"
172
@@ -XXX,XX +XXX,XX @@ static void imx8mp_evk_init(MachineState *machine)
173
memory_region_add_subregion(get_system_memory(), FSL_IMX8MP_RAM_START,
174
machine->ram);
175
176
+ for (int i = 0; i < FSL_IMX8MP_NUM_USDHCS; i++) {
177
+ BusState *bus;
178
+ DeviceState *carddev;
179
+ BlockBackend *blk;
180
+ DriveInfo *di = drive_get(IF_SD, i, 0);
181
+
182
+ if (!di) {
183
+ continue;
184
+ }
185
+
186
+ blk = blk_by_legacy_dinfo(di);
187
+ bus = qdev_get_child_bus(DEVICE(&s->usdhc[i]), "sd-bus");
188
+ carddev = qdev_new(TYPE_SD_CARD);
189
+ qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal);
190
+ qdev_realize_and_unref(carddev, bus, &error_fatal);
191
+ }
192
+
193
if (!qtest_enabled()) {
194
arm_load_kernel(&s->cpu[0], machine, &boot_info);
195
}
196
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
197
index XXXXXXX..XXXXXXX 100644
198
--- a/hw/arm/Kconfig
199
+++ b/hw/arm/Kconfig
200
@@ -XXX,XX +XXX,XX @@ config FSL_IMX8MP
201
select FSL_IMX8MP_ANALOG
202
select FSL_IMX8MP_CCM
203
select IMX
204
+ select SDHCI
205
select UNIMP
206
207
config FSL_IMX8MP_EVK
208
--
209
2.43.0
diff view generated by jsdifflib
New patch
1
From: Bernhard Beschow <shentey@gmail.com>
1
2
3
Linux checks for the PLLs in the PHY to be locked, so implement a model
4
emulating that.
5
6
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
7
Message-id: 20250223114708.1780-9-shentey@gmail.com
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
11
MAINTAINERS | 2 +
12
docs/system/arm/imx8mp-evk.rst | 1 +
13
include/hw/arm/fsl-imx8mp.h | 10 +++
14
include/hw/pci-host/fsl_imx8m_phy.h | 28 +++++++++
15
hw/arm/fsl-imx8mp.c | 30 +++++++++
16
hw/pci-host/fsl_imx8m_phy.c | 98 +++++++++++++++++++++++++++++
17
hw/arm/Kconfig | 3 +
18
hw/pci-host/Kconfig | 3 +
19
hw/pci-host/meson.build | 1 +
20
9 files changed, 176 insertions(+)
21
create mode 100644 include/hw/pci-host/fsl_imx8m_phy.h
22
create mode 100644 hw/pci-host/fsl_imx8m_phy.c
23
24
diff --git a/MAINTAINERS b/MAINTAINERS
25
index XXXXXXX..XXXXXXX 100644
26
--- a/MAINTAINERS
27
+++ b/MAINTAINERS
28
@@ -XXX,XX +XXX,XX @@ S: Maintained
29
F: hw/arm/imx8mp-evk.c
30
F: hw/arm/fsl-imx8mp.c
31
F: hw/misc/imx8mp_*.c
32
+F: hw/pci-host/fsl_imx8m_phy.c
33
F: include/hw/arm/fsl-imx8mp.h
34
F: include/hw/misc/imx8mp_*.h
35
+F: include/hw/pci-host/fsl_imx8m_phy.h
36
F: docs/system/arm/imx8mp-evk.rst
37
38
MPS2 / MPS3
39
diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8mp-evk.rst
40
index XXXXXXX..XXXXXXX 100644
41
--- a/docs/system/arm/imx8mp-evk.rst
42
+++ b/docs/system/arm/imx8mp-evk.rst
43
@@ -XXX,XX +XXX,XX @@ The ``imx8mp-evk`` machine implements the following devices:
44
* Generic Interrupt Controller (GICv3)
45
* 4 UARTs
46
* 3 USDHC Storage Controllers
47
+ * 1 Designware PCI Express Controller
48
* Secure Non-Volatile Storage (SNVS) including an RTC
49
* Clock Tree
50
51
diff --git a/include/hw/arm/fsl-imx8mp.h b/include/hw/arm/fsl-imx8mp.h
52
index XXXXXXX..XXXXXXX 100644
53
--- a/include/hw/arm/fsl-imx8mp.h
54
+++ b/include/hw/arm/fsl-imx8mp.h
55
@@ -XXX,XX +XXX,XX @@
56
#include "hw/misc/imx7_snvs.h"
57
#include "hw/misc/imx8mp_analog.h"
58
#include "hw/misc/imx8mp_ccm.h"
59
+#include "hw/pci-host/designware.h"
60
+#include "hw/pci-host/fsl_imx8m_phy.h"
61
#include "hw/sd/sdhci.h"
62
#include "qom/object.h"
63
#include "qemu/units.h"
64
@@ -XXX,XX +XXX,XX @@ struct FslImx8mpState {
65
IMX7SNVSState snvs;
66
IMXSerialState uart[FSL_IMX8MP_NUM_UARTS];
67
SDHCIState usdhc[FSL_IMX8MP_NUM_USDHCS];
68
+ DesignwarePCIEHost pcie;
69
+ FslImx8mPciePhyState pcie_phy;
70
};
71
72
enum FslImx8mpMemoryRegions {
73
@@ -XXX,XX +XXX,XX @@ enum FslImx8mpIrqs {
74
FSL_IMX8MP_UART4_IRQ = 29,
75
FSL_IMX8MP_UART5_IRQ = 30,
76
FSL_IMX8MP_UART6_IRQ = 16,
77
+
78
+ FSL_IMX8MP_PCI_INTA_IRQ = 126,
79
+ FSL_IMX8MP_PCI_INTB_IRQ = 125,
80
+ FSL_IMX8MP_PCI_INTC_IRQ = 124,
81
+ FSL_IMX8MP_PCI_INTD_IRQ = 123,
82
+ FSL_IMX8MP_PCI_MSI_IRQ = 140,
83
};
84
85
#endif /* FSL_IMX8MP_H */
86
diff --git a/include/hw/pci-host/fsl_imx8m_phy.h b/include/hw/pci-host/fsl_imx8m_phy.h
87
new file mode 100644
88
index XXXXXXX..XXXXXXX
89
--- /dev/null
90
+++ b/include/hw/pci-host/fsl_imx8m_phy.h
91
@@ -XXX,XX +XXX,XX @@
92
+/*
93
+ * i.MX8 PCIe PHY emulation
94
+ *
95
+ * Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
96
+ *
97
+ * SPDX-License-Identifier: GPL-2.0-or-later
98
+ */
99
+
100
+#ifndef HW_PCIHOST_FSLIMX8MPCIEPHY_H
101
+#define HW_PCIHOST_FSLIMX8MPCIEPHY_H
102
+
103
+#include "hw/sysbus.h"
104
+#include "qom/object.h"
105
+#include "exec/memory.h"
106
+
107
+#define TYPE_FSL_IMX8M_PCIE_PHY "fsl-imx8m-pcie-phy"
108
+OBJECT_DECLARE_SIMPLE_TYPE(FslImx8mPciePhyState, FSL_IMX8M_PCIE_PHY)
109
+
110
+#define FSL_IMX8M_PCIE_PHY_DATA_SIZE 0x800
111
+
112
+struct FslImx8mPciePhyState {
113
+ SysBusDevice parent_obj;
114
+
115
+ MemoryRegion iomem;
116
+ uint8_t data[FSL_IMX8M_PCIE_PHY_DATA_SIZE];
117
+};
118
+
119
+#endif
120
diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c
121
index XXXXXXX..XXXXXXX 100644
122
--- a/hw/arm/fsl-imx8mp.c
123
+++ b/hw/arm/fsl-imx8mp.c
124
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_init(Object *obj)
125
g_autofree char *name = g_strdup_printf("usdhc%d", i + 1);
126
object_initialize_child(obj, name, &s->usdhc[i], TYPE_IMX_USDHC);
127
}
128
+
129
+ object_initialize_child(obj, "pcie", &s->pcie, TYPE_DESIGNWARE_PCIE_HOST);
130
+ object_initialize_child(obj, "pcie_phy", &s->pcie_phy,
131
+ TYPE_FSL_IMX8M_PCIE_PHY);
132
}
133
134
static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
135
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
136
sysbus_mmio_map(SYS_BUS_DEVICE(&s->snvs), 0,
137
fsl_imx8mp_memmap[FSL_IMX8MP_SNVS_HP].addr);
138
139
+ /* PCIe */
140
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->pcie), errp)) {
141
+ return;
142
+ }
143
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->pcie), 0,
144
+ fsl_imx8mp_memmap[FSL_IMX8MP_PCIE1].addr);
145
+
146
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 0,
147
+ qdev_get_gpio_in(gicdev, FSL_IMX8MP_PCI_INTA_IRQ));
148
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 1,
149
+ qdev_get_gpio_in(gicdev, FSL_IMX8MP_PCI_INTB_IRQ));
150
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 2,
151
+ qdev_get_gpio_in(gicdev, FSL_IMX8MP_PCI_INTC_IRQ));
152
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 3,
153
+ qdev_get_gpio_in(gicdev, FSL_IMX8MP_PCI_INTD_IRQ));
154
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 4,
155
+ qdev_get_gpio_in(gicdev, FSL_IMX8MP_PCI_MSI_IRQ));
156
+
157
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->pcie_phy), errp)) {
158
+ return;
159
+ }
160
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->pcie_phy), 0,
161
+ fsl_imx8mp_memmap[FSL_IMX8MP_PCIE_PHY1].addr);
162
+
163
/* Unimplemented devices */
164
for (i = 0; i < ARRAY_SIZE(fsl_imx8mp_memmap); i++) {
165
switch (i) {
166
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
167
case FSL_IMX8MP_CCM:
168
case FSL_IMX8MP_GIC_DIST:
169
case FSL_IMX8MP_GIC_REDIST:
170
+ case FSL_IMX8MP_PCIE1:
171
+ case FSL_IMX8MP_PCIE_PHY1:
172
case FSL_IMX8MP_RAM:
173
case FSL_IMX8MP_SNVS_HP:
174
case FSL_IMX8MP_UART1 ... FSL_IMX8MP_UART4:
175
diff --git a/hw/pci-host/fsl_imx8m_phy.c b/hw/pci-host/fsl_imx8m_phy.c
176
new file mode 100644
177
index XXXXXXX..XXXXXXX
178
--- /dev/null
179
+++ b/hw/pci-host/fsl_imx8m_phy.c
180
@@ -XXX,XX +XXX,XX @@
181
+/*
182
+ * i.MX8 PCIe PHY emulation
183
+ *
184
+ * Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
185
+ *
186
+ * SPDX-License-Identifier: GPL-2.0-or-later
187
+ */
188
+
189
+#include "qemu/osdep.h"
190
+#include "hw/pci-host/fsl_imx8m_phy.h"
191
+#include "hw/resettable.h"
192
+#include "migration/vmstate.h"
193
+
194
+#define CMN_REG075 0x1d4
195
+#define ANA_PLL_LOCK_DONE BIT(1)
196
+#define ANA_PLL_AFC_DONE BIT(0)
197
+
198
+static uint64_t fsl_imx8m_pcie_phy_read(void *opaque, hwaddr offset,
199
+ unsigned size)
200
+{
201
+ FslImx8mPciePhyState *s = opaque;
202
+
203
+ if (offset == CMN_REG075) {
204
+ return s->data[offset] | ANA_PLL_LOCK_DONE | ANA_PLL_AFC_DONE;
205
+ }
206
+
207
+ return s->data[offset];
208
+}
209
+
210
+static void fsl_imx8m_pcie_phy_write(void *opaque, hwaddr offset,
211
+ uint64_t value, unsigned size)
212
+{
213
+ FslImx8mPciePhyState *s = opaque;
214
+
215
+ s->data[offset] = value;
216
+}
217
+
218
+static const MemoryRegionOps fsl_imx8m_pcie_phy_ops = {
219
+ .read = fsl_imx8m_pcie_phy_read,
220
+ .write = fsl_imx8m_pcie_phy_write,
221
+ .impl = {
222
+ .min_access_size = 1,
223
+ .max_access_size = 1,
224
+ },
225
+ .valid = {
226
+ .min_access_size = 1,
227
+ .max_access_size = 8,
228
+ },
229
+ .endianness = DEVICE_LITTLE_ENDIAN,
230
+};
231
+
232
+static void fsl_imx8m_pcie_phy_realize(DeviceState *dev, Error **errp)
233
+{
234
+ FslImx8mPciePhyState *s = FSL_IMX8M_PCIE_PHY(dev);
235
+
236
+ memory_region_init_io(&s->iomem, OBJECT(s), &fsl_imx8m_pcie_phy_ops, s,
237
+ TYPE_FSL_IMX8M_PCIE_PHY, ARRAY_SIZE(s->data));
238
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
239
+}
240
+
241
+static void fsl_imx8m_pcie_phy_reset_hold(Object *obj, ResetType type)
242
+{
243
+ FslImx8mPciePhyState *s = FSL_IMX8M_PCIE_PHY(obj);
244
+
245
+ memset(s->data, 0, sizeof(s->data));
246
+}
247
+
248
+static const VMStateDescription fsl_imx8m_pcie_phy_vmstate = {
249
+ .name = "fsl-imx8m-pcie-phy",
250
+ .version_id = 1,
251
+ .minimum_version_id = 1,
252
+ .fields = (const VMStateField[]) {
253
+ VMSTATE_UINT8_ARRAY(data, FslImx8mPciePhyState,
254
+ FSL_IMX8M_PCIE_PHY_DATA_SIZE),
255
+ VMSTATE_END_OF_LIST()
256
+ }
257
+};
258
+
259
+static void fsl_imx8m_pcie_phy_class_init(ObjectClass *klass, void *data)
260
+{
261
+ DeviceClass *dc = DEVICE_CLASS(klass);
262
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
263
+
264
+ dc->realize = fsl_imx8m_pcie_phy_realize;
265
+ dc->vmsd = &fsl_imx8m_pcie_phy_vmstate;
266
+ rc->phases.hold = fsl_imx8m_pcie_phy_reset_hold;
267
+}
268
+
269
+static const TypeInfo fsl_imx8m_pcie_phy_types[] = {
270
+ {
271
+ .name = TYPE_FSL_IMX8M_PCIE_PHY,
272
+ .parent = TYPE_SYS_BUS_DEVICE,
273
+ .instance_size = sizeof(FslImx8mPciePhyState),
274
+ .class_init = fsl_imx8m_pcie_phy_class_init,
275
+ }
276
+};
277
+
278
+DEFINE_TYPES(fsl_imx8m_pcie_phy_types)
279
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
280
index XXXXXXX..XXXXXXX 100644
281
--- a/hw/arm/Kconfig
282
+++ b/hw/arm/Kconfig
283
@@ -XXX,XX +XXX,XX @@ config FSL_IMX7
284
285
config FSL_IMX8MP
286
bool
287
+ imply PCI_DEVICES
288
select ARM_GIC
289
select FSL_IMX8MP_ANALOG
290
select FSL_IMX8MP_CCM
291
select IMX
292
+ select PCI_EXPRESS_DESIGNWARE
293
+ select PCI_EXPRESS_FSL_IMX8M_PHY
294
select SDHCI
295
select UNIMP
296
297
diff --git a/hw/pci-host/Kconfig b/hw/pci-host/Kconfig
298
index XXXXXXX..XXXXXXX 100644
299
--- a/hw/pci-host/Kconfig
300
+++ b/hw/pci-host/Kconfig
301
@@ -XXX,XX +XXX,XX @@ config ASTRO
302
bool
303
select PCI
304
305
+config PCI_EXPRESS_FSL_IMX8M_PHY
306
+ bool
307
+
308
config GT64120
309
bool
310
select PCI
311
diff --git a/hw/pci-host/meson.build b/hw/pci-host/meson.build
312
index XXXXXXX..XXXXXXX 100644
313
--- a/hw/pci-host/meson.build
314
+++ b/hw/pci-host/meson.build
315
@@ -XXX,XX +XXX,XX @@ pci_ss.add(when: 'CONFIG_ARTICIA', if_true: files('articia.c'))
316
pci_ss.add(when: 'CONFIG_MV64361', if_true: files('mv64361.c'))
317
318
# ARM devices
319
+pci_ss.add(when: 'CONFIG_PCI_EXPRESS_FSL_IMX8M_PHY', if_true: files('fsl_imx8m_phy.c'))
320
pci_ss.add(when: 'CONFIG_VERSATILE_PCI', if_true: files('versatile.c'))
321
322
# HPPA devices
323
--
324
2.43.0
diff view generated by jsdifflib
New patch
1
From: Bernhard Beschow <shentey@gmail.com>
1
2
3
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
4
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
5
Message-id: 20250223114708.1780-10-shentey@gmail.com
6
[PMM: drop static const from gpio_table for GCC 7.5]
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
---
9
docs/system/arm/imx8mp-evk.rst | 1 +
10
include/hw/arm/fsl-imx8mp.h | 14 +++++++++
11
hw/arm/fsl-imx8mp.c | 55 ++++++++++++++++++++++++++++++++++
12
3 files changed, 70 insertions(+)
13
14
diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8mp-evk.rst
15
index XXXXXXX..XXXXXXX 100644
16
--- a/docs/system/arm/imx8mp-evk.rst
17
+++ b/docs/system/arm/imx8mp-evk.rst
18
@@ -XXX,XX +XXX,XX @@ The ``imx8mp-evk`` machine implements the following devices:
19
* 4 UARTs
20
* 3 USDHC Storage Controllers
21
* 1 Designware PCI Express Controller
22
+ * 5 GPIO Controllers
23
* Secure Non-Volatile Storage (SNVS) including an RTC
24
* Clock Tree
25
26
diff --git a/include/hw/arm/fsl-imx8mp.h b/include/hw/arm/fsl-imx8mp.h
27
index XXXXXXX..XXXXXXX 100644
28
--- a/include/hw/arm/fsl-imx8mp.h
29
+++ b/include/hw/arm/fsl-imx8mp.h
30
@@ -XXX,XX +XXX,XX @@
31
32
#include "cpu.h"
33
#include "hw/char/imx_serial.h"
34
+#include "hw/gpio/imx_gpio.h"
35
#include "hw/intc/arm_gicv3_common.h"
36
#include "hw/misc/imx7_snvs.h"
37
#include "hw/misc/imx8mp_analog.h"
38
@@ -XXX,XX +XXX,XX @@ OBJECT_DECLARE_SIMPLE_TYPE(FslImx8mpState, FSL_IMX8MP)
39
40
enum FslImx8mpConfiguration {
41
FSL_IMX8MP_NUM_CPUS = 4,
42
+ FSL_IMX8MP_NUM_GPIOS = 5,
43
FSL_IMX8MP_NUM_IRQS = 160,
44
FSL_IMX8MP_NUM_UARTS = 4,
45
FSL_IMX8MP_NUM_USDHCS = 3,
46
@@ -XXX,XX +XXX,XX @@ struct FslImx8mpState {
47
48
ARMCPU cpu[FSL_IMX8MP_NUM_CPUS];
49
GICv3State gic;
50
+ IMXGPIOState gpio[FSL_IMX8MP_NUM_GPIOS];
51
IMX8MPCCMState ccm;
52
IMX8MPAnalogState analog;
53
IMX7SNVSState snvs;
54
@@ -XXX,XX +XXX,XX @@ enum FslImx8mpIrqs {
55
FSL_IMX8MP_UART5_IRQ = 30,
56
FSL_IMX8MP_UART6_IRQ = 16,
57
58
+ FSL_IMX8MP_GPIO1_LOW_IRQ = 64,
59
+ FSL_IMX8MP_GPIO1_HIGH_IRQ = 65,
60
+ FSL_IMX8MP_GPIO2_LOW_IRQ = 66,
61
+ FSL_IMX8MP_GPIO2_HIGH_IRQ = 67,
62
+ FSL_IMX8MP_GPIO3_LOW_IRQ = 68,
63
+ FSL_IMX8MP_GPIO3_HIGH_IRQ = 69,
64
+ FSL_IMX8MP_GPIO4_LOW_IRQ = 70,
65
+ FSL_IMX8MP_GPIO4_HIGH_IRQ = 71,
66
+ FSL_IMX8MP_GPIO5_LOW_IRQ = 72,
67
+ FSL_IMX8MP_GPIO5_HIGH_IRQ = 73,
68
+
69
FSL_IMX8MP_PCI_INTA_IRQ = 126,
70
FSL_IMX8MP_PCI_INTB_IRQ = 125,
71
FSL_IMX8MP_PCI_INTC_IRQ = 124,
72
diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c
73
index XXXXXXX..XXXXXXX 100644
74
--- a/hw/arm/fsl-imx8mp.c
75
+++ b/hw/arm/fsl-imx8mp.c
76
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_init(Object *obj)
77
object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL);
78
}
79
80
+ for (i = 0; i < FSL_IMX8MP_NUM_GPIOS; i++) {
81
+ g_autofree char *name = g_strdup_printf("gpio%d", i + 1);
82
+ object_initialize_child(obj, name, &s->gpio[i], TYPE_IMX_GPIO);
83
+ }
84
+
85
for (i = 0; i < FSL_IMX8MP_NUM_USDHCS; i++) {
86
g_autofree char *name = g_strdup_printf("usdhc%d", i + 1);
87
object_initialize_child(obj, name, &s->usdhc[i], TYPE_IMX_USDHC);
88
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
89
qdev_get_gpio_in(gicdev, serial_table[i].irq));
90
}
91
92
+ /* GPIOs */
93
+ for (i = 0; i < FSL_IMX8MP_NUM_GPIOS; i++) {
94
+ struct {
95
+ hwaddr addr;
96
+ unsigned int irq_low;
97
+ unsigned int irq_high;
98
+ } gpio_table[FSL_IMX8MP_NUM_GPIOS] = {
99
+ {
100
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPIO1].addr,
101
+ FSL_IMX8MP_GPIO1_LOW_IRQ,
102
+ FSL_IMX8MP_GPIO1_HIGH_IRQ
103
+ },
104
+ {
105
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPIO2].addr,
106
+ FSL_IMX8MP_GPIO2_LOW_IRQ,
107
+ FSL_IMX8MP_GPIO2_HIGH_IRQ
108
+ },
109
+ {
110
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPIO3].addr,
111
+ FSL_IMX8MP_GPIO3_LOW_IRQ,
112
+ FSL_IMX8MP_GPIO3_HIGH_IRQ
113
+ },
114
+ {
115
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPIO4].addr,
116
+ FSL_IMX8MP_GPIO4_LOW_IRQ,
117
+ FSL_IMX8MP_GPIO4_HIGH_IRQ
118
+ },
119
+ {
120
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPIO5].addr,
121
+ FSL_IMX8MP_GPIO5_LOW_IRQ,
122
+ FSL_IMX8MP_GPIO5_HIGH_IRQ
123
+ },
124
+ };
125
+
126
+ object_property_set_bool(OBJECT(&s->gpio[i]), "has-edge-sel", true,
127
+ &error_abort);
128
+ object_property_set_bool(OBJECT(&s->gpio[i]), "has-upper-pin-irq",
129
+ true, &error_abort);
130
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio[i]), errp)) {
131
+ return;
132
+ }
133
+
134
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, gpio_table[i].addr);
135
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 0,
136
+ qdev_get_gpio_in(gicdev, gpio_table[i].irq_low));
137
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 1,
138
+ qdev_get_gpio_in(gicdev, gpio_table[i].irq_high));
139
+ }
140
+
141
/* USDHCs */
142
for (i = 0; i < FSL_IMX8MP_NUM_USDHCS; i++) {
143
struct {
144
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
145
case FSL_IMX8MP_CCM:
146
case FSL_IMX8MP_GIC_DIST:
147
case FSL_IMX8MP_GIC_REDIST:
148
+ case FSL_IMX8MP_GPIO1 ... FSL_IMX8MP_GPIO5:
149
case FSL_IMX8MP_PCIE1:
150
case FSL_IMX8MP_PCIE_PHY1:
151
case FSL_IMX8MP_RAM:
152
--
153
2.43.0
diff view generated by jsdifflib
New patch
1
From: Bernhard Beschow <shentey@gmail.com>
1
2
3
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
4
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
5
Message-id: 20250223114708.1780-11-shentey@gmail.com
6
[PMM: drop static const from i2c_table for GCC 7.5]
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
---
9
docs/system/arm/imx8mp-evk.rst | 1 +
10
include/hw/arm/fsl-imx8mp.h | 11 +++++++++++
11
hw/arm/fsl-imx8mp.c | 29 +++++++++++++++++++++++++++++
12
hw/arm/Kconfig | 2 ++
13
4 files changed, 43 insertions(+)
14
15
diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8mp-evk.rst
16
index XXXXXXX..XXXXXXX 100644
17
--- a/docs/system/arm/imx8mp-evk.rst
18
+++ b/docs/system/arm/imx8mp-evk.rst
19
@@ -XXX,XX +XXX,XX @@ The ``imx8mp-evk`` machine implements the following devices:
20
* 3 USDHC Storage Controllers
21
* 1 Designware PCI Express Controller
22
* 5 GPIO Controllers
23
+ * 6 I2C Controllers
24
* Secure Non-Volatile Storage (SNVS) including an RTC
25
* Clock Tree
26
27
diff --git a/include/hw/arm/fsl-imx8mp.h b/include/hw/arm/fsl-imx8mp.h
28
index XXXXXXX..XXXXXXX 100644
29
--- a/include/hw/arm/fsl-imx8mp.h
30
+++ b/include/hw/arm/fsl-imx8mp.h
31
@@ -XXX,XX +XXX,XX @@
32
#include "cpu.h"
33
#include "hw/char/imx_serial.h"
34
#include "hw/gpio/imx_gpio.h"
35
+#include "hw/i2c/imx_i2c.h"
36
#include "hw/intc/arm_gicv3_common.h"
37
#include "hw/misc/imx7_snvs.h"
38
#include "hw/misc/imx8mp_analog.h"
39
@@ -XXX,XX +XXX,XX @@ OBJECT_DECLARE_SIMPLE_TYPE(FslImx8mpState, FSL_IMX8MP)
40
enum FslImx8mpConfiguration {
41
FSL_IMX8MP_NUM_CPUS = 4,
42
FSL_IMX8MP_NUM_GPIOS = 5,
43
+ FSL_IMX8MP_NUM_I2CS = 6,
44
FSL_IMX8MP_NUM_IRQS = 160,
45
FSL_IMX8MP_NUM_UARTS = 4,
46
FSL_IMX8MP_NUM_USDHCS = 3,
47
@@ -XXX,XX +XXX,XX @@ struct FslImx8mpState {
48
IMX8MPCCMState ccm;
49
IMX8MPAnalogState analog;
50
IMX7SNVSState snvs;
51
+ IMXI2CState i2c[FSL_IMX8MP_NUM_I2CS];
52
IMXSerialState uart[FSL_IMX8MP_NUM_UARTS];
53
SDHCIState usdhc[FSL_IMX8MP_NUM_USDHCS];
54
DesignwarePCIEHost pcie;
55
@@ -XXX,XX +XXX,XX @@ enum FslImx8mpIrqs {
56
FSL_IMX8MP_UART5_IRQ = 30,
57
FSL_IMX8MP_UART6_IRQ = 16,
58
59
+ FSL_IMX8MP_I2C1_IRQ = 35,
60
+ FSL_IMX8MP_I2C2_IRQ = 36,
61
+ FSL_IMX8MP_I2C3_IRQ = 37,
62
+ FSL_IMX8MP_I2C4_IRQ = 38,
63
+
64
FSL_IMX8MP_GPIO1_LOW_IRQ = 64,
65
FSL_IMX8MP_GPIO1_HIGH_IRQ = 65,
66
FSL_IMX8MP_GPIO2_LOW_IRQ = 66,
67
@@ -XXX,XX +XXX,XX @@ enum FslImx8mpIrqs {
68
FSL_IMX8MP_GPIO5_LOW_IRQ = 72,
69
FSL_IMX8MP_GPIO5_HIGH_IRQ = 73,
70
71
+ FSL_IMX8MP_I2C5_IRQ = 76,
72
+ FSL_IMX8MP_I2C6_IRQ = 77,
73
+
74
FSL_IMX8MP_PCI_INTA_IRQ = 126,
75
FSL_IMX8MP_PCI_INTB_IRQ = 125,
76
FSL_IMX8MP_PCI_INTC_IRQ = 124,
77
diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c
78
index XXXXXXX..XXXXXXX 100644
79
--- a/hw/arm/fsl-imx8mp.c
80
+++ b/hw/arm/fsl-imx8mp.c
81
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_init(Object *obj)
82
object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL);
83
}
84
85
+ for (i = 0; i < FSL_IMX8MP_NUM_I2CS; i++) {
86
+ g_autofree char *name = g_strdup_printf("i2c%d", i + 1);
87
+ object_initialize_child(obj, name, &s->i2c[i], TYPE_IMX_I2C);
88
+ }
89
+
90
for (i = 0; i < FSL_IMX8MP_NUM_GPIOS; i++) {
91
g_autofree char *name = g_strdup_printf("gpio%d", i + 1);
92
object_initialize_child(obj, name, &s->gpio[i], TYPE_IMX_GPIO);
93
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
94
qdev_get_gpio_in(gicdev, serial_table[i].irq));
95
}
96
97
+ /* I2Cs */
98
+ for (i = 0; i < FSL_IMX8MP_NUM_I2CS; i++) {
99
+ struct {
100
+ hwaddr addr;
101
+ unsigned int irq;
102
+ } i2c_table[FSL_IMX8MP_NUM_I2CS] = {
103
+ { fsl_imx8mp_memmap[FSL_IMX8MP_I2C1].addr, FSL_IMX8MP_I2C1_IRQ },
104
+ { fsl_imx8mp_memmap[FSL_IMX8MP_I2C2].addr, FSL_IMX8MP_I2C2_IRQ },
105
+ { fsl_imx8mp_memmap[FSL_IMX8MP_I2C3].addr, FSL_IMX8MP_I2C3_IRQ },
106
+ { fsl_imx8mp_memmap[FSL_IMX8MP_I2C4].addr, FSL_IMX8MP_I2C4_IRQ },
107
+ { fsl_imx8mp_memmap[FSL_IMX8MP_I2C5].addr, FSL_IMX8MP_I2C5_IRQ },
108
+ { fsl_imx8mp_memmap[FSL_IMX8MP_I2C6].addr, FSL_IMX8MP_I2C6_IRQ },
109
+ };
110
+
111
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c[i]), errp)) {
112
+ return;
113
+ }
114
+
115
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c[i]), 0, i2c_table[i].addr);
116
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c[i]), 0,
117
+ qdev_get_gpio_in(gicdev, i2c_table[i].irq));
118
+ }
119
+
120
/* GPIOs */
121
for (i = 0; i < FSL_IMX8MP_NUM_GPIOS; i++) {
122
struct {
123
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
124
case FSL_IMX8MP_GIC_DIST:
125
case FSL_IMX8MP_GIC_REDIST:
126
case FSL_IMX8MP_GPIO1 ... FSL_IMX8MP_GPIO5:
127
+ case FSL_IMX8MP_I2C1 ... FSL_IMX8MP_I2C6:
128
case FSL_IMX8MP_PCIE1:
129
case FSL_IMX8MP_PCIE_PHY1:
130
case FSL_IMX8MP_RAM:
131
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
132
index XXXXXXX..XXXXXXX 100644
133
--- a/hw/arm/Kconfig
134
+++ b/hw/arm/Kconfig
135
@@ -XXX,XX +XXX,XX @@ config FSL_IMX7
136
137
config FSL_IMX8MP
138
bool
139
+ imply I2C_DEVICES
140
imply PCI_DEVICES
141
select ARM_GIC
142
select FSL_IMX8MP_ANALOG
143
select FSL_IMX8MP_CCM
144
select IMX
145
+ select IMX_I2C
146
select PCI_EXPRESS_DESIGNWARE
147
select PCI_EXPRESS_FSL_IMX8M_PHY
148
select SDHCI
149
--
150
2.43.0
diff view generated by jsdifflib
1
Implement the register interface for the SAU: SAU_CTRL,
1
From: Bernhard Beschow <shentey@gmail.com>
2
SAU_TYPE, SAU_RNR, SAU_RBAR and SAU_RLAR. None of the
3
actual behaviour is implemented here; registers just
4
read back as written.
5
2
6
When the CPU definition for Cortex-M33 is eventually
3
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
added, its initfn will set cpu->sau_sregion, in the same
4
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
8
way that we currently set cpu->pmsav7_dregion for the
5
Message-id: 20250223114708.1780-12-shentey@gmail.com
9
M3 and M4.
6
[PMM: drop static const from spi_table for GCC 7.5]
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
---
9
docs/system/arm/imx8mp-evk.rst | 1 +
10
include/hw/arm/fsl-imx8mp.h | 8 ++++++++
11
hw/arm/fsl-imx8mp.c | 26 ++++++++++++++++++++++++++
12
3 files changed, 35 insertions(+)
10
13
11
Number of SAU regions is typically a configurable
14
diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8mp-evk.rst
12
CPU parameter, but this patch doesn't provide a
13
QEMU CPU property for it. We can easily add one when
14
we have a board that requires it.
15
16
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
17
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
18
Message-id: 1506092407-26985-14-git-send-email-peter.maydell@linaro.org
19
---
20
target/arm/cpu.h | 10 +++++
21
hw/intc/armv7m_nvic.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++
22
target/arm/cpu.c | 27 ++++++++++++
23
target/arm/machine.c | 14 ++++++
24
4 files changed, 167 insertions(+)
25
26
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
27
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
28
--- a/target/arm/cpu.h
16
--- a/docs/system/arm/imx8mp-evk.rst
29
+++ b/target/arm/cpu.h
17
+++ b/docs/system/arm/imx8mp-evk.rst
30
@@ -XXX,XX +XXX,XX @@ typedef struct CPUARMState {
18
@@ -XXX,XX +XXX,XX @@ The ``imx8mp-evk`` machine implements the following devices:
31
uint32_t mair1[M_REG_NUM_BANKS];
19
* 1 Designware PCI Express Controller
32
} pmsav8;
20
* 5 GPIO Controllers
33
21
* 6 I2C Controllers
34
+ /* v8M SAU */
22
+ * 3 SPI Controllers
35
+ struct {
23
* Secure Non-Volatile Storage (SNVS) including an RTC
36
+ uint32_t *rbar;
24
* Clock Tree
37
+ uint32_t *rlar;
25
38
+ uint32_t rnr;
26
diff --git a/include/hw/arm/fsl-imx8mp.h b/include/hw/arm/fsl-imx8mp.h
39
+ uint32_t ctrl;
27
index XXXXXXX..XXXXXXX 100644
40
+ } sau;
28
--- a/include/hw/arm/fsl-imx8mp.h
29
+++ b/include/hw/arm/fsl-imx8mp.h
30
@@ -XXX,XX +XXX,XX @@
31
#include "hw/pci-host/designware.h"
32
#include "hw/pci-host/fsl_imx8m_phy.h"
33
#include "hw/sd/sdhci.h"
34
+#include "hw/ssi/imx_spi.h"
35
#include "qom/object.h"
36
#include "qemu/units.h"
37
38
@@ -XXX,XX +XXX,XX @@ OBJECT_DECLARE_SIMPLE_TYPE(FslImx8mpState, FSL_IMX8MP)
39
40
enum FslImx8mpConfiguration {
41
FSL_IMX8MP_NUM_CPUS = 4,
42
+ FSL_IMX8MP_NUM_ECSPIS = 3,
43
FSL_IMX8MP_NUM_GPIOS = 5,
44
FSL_IMX8MP_NUM_I2CS = 6,
45
FSL_IMX8MP_NUM_IRQS = 160,
46
@@ -XXX,XX +XXX,XX @@ struct FslImx8mpState {
47
IMX8MPCCMState ccm;
48
IMX8MPAnalogState analog;
49
IMX7SNVSState snvs;
50
+ IMXSPIState spi[FSL_IMX8MP_NUM_ECSPIS];
51
IMXI2CState i2c[FSL_IMX8MP_NUM_I2CS];
52
IMXSerialState uart[FSL_IMX8MP_NUM_UARTS];
53
SDHCIState usdhc[FSL_IMX8MP_NUM_USDHCS];
54
@@ -XXX,XX +XXX,XX @@ enum FslImx8mpIrqs {
55
FSL_IMX8MP_UART5_IRQ = 30,
56
FSL_IMX8MP_UART6_IRQ = 16,
57
58
+ FSL_IMX8MP_ECSPI1_IRQ = 31,
59
+ FSL_IMX8MP_ECSPI2_IRQ = 32,
60
+ FSL_IMX8MP_ECSPI3_IRQ = 33,
61
+ FSL_IMX8MP_ECSPI4_IRQ = 34,
41
+
62
+
42
void *nvic;
63
FSL_IMX8MP_I2C1_IRQ = 35,
43
const struct arm_boot_info *boot_info;
64
FSL_IMX8MP_I2C2_IRQ = 36,
44
/* Store GICv3CPUState to access from this struct */
65
FSL_IMX8MP_I2C3_IRQ = 37,
45
@@ -XXX,XX +XXX,XX @@ struct ARMCPU {
66
diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c
46
bool has_mpu;
47
/* PMSAv7 MPU number of supported regions */
48
uint32_t pmsav7_dregion;
49
+ /* v8M SAU number of supported regions */
50
+ uint32_t sau_sregion;
51
52
/* PSCI conduit used to invoke PSCI methods
53
* 0 - disabled, 1 - smc, 2 - hvc
54
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
55
index XXXXXXX..XXXXXXX 100644
67
index XXXXXXX..XXXXXXX 100644
56
--- a/hw/intc/armv7m_nvic.c
68
--- a/hw/arm/fsl-imx8mp.c
57
+++ b/hw/intc/armv7m_nvic.c
69
+++ b/hw/arm/fsl-imx8mp.c
58
@@ -XXX,XX +XXX,XX @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs)
70
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_init(Object *obj)
59
goto bad_offset;
71
object_initialize_child(obj, name, &s->usdhc[i], TYPE_IMX_USDHC);
60
}
61
return cpu->env.pmsav8.mair1[attrs.secure];
62
+ case 0xdd0: /* SAU_CTRL */
63
+ if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
64
+ goto bad_offset;
65
+ }
66
+ if (!attrs.secure) {
67
+ return 0;
68
+ }
69
+ return cpu->env.sau.ctrl;
70
+ case 0xdd4: /* SAU_TYPE */
71
+ if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
72
+ goto bad_offset;
73
+ }
74
+ if (!attrs.secure) {
75
+ return 0;
76
+ }
77
+ return cpu->sau_sregion;
78
+ case 0xdd8: /* SAU_RNR */
79
+ if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
80
+ goto bad_offset;
81
+ }
82
+ if (!attrs.secure) {
83
+ return 0;
84
+ }
85
+ return cpu->env.sau.rnr;
86
+ case 0xddc: /* SAU_RBAR */
87
+ {
88
+ int region = cpu->env.sau.rnr;
89
+
90
+ if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
91
+ goto bad_offset;
92
+ }
93
+ if (!attrs.secure) {
94
+ return 0;
95
+ }
96
+ if (region >= cpu->sau_sregion) {
97
+ return 0;
98
+ }
99
+ return cpu->env.sau.rbar[region];
100
+ }
101
+ case 0xde0: /* SAU_RLAR */
102
+ {
103
+ int region = cpu->env.sau.rnr;
104
+
105
+ if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
106
+ goto bad_offset;
107
+ }
108
+ if (!attrs.secure) {
109
+ return 0;
110
+ }
111
+ if (region >= cpu->sau_sregion) {
112
+ return 0;
113
+ }
114
+ return cpu->env.sau.rlar[region];
115
+ }
116
case 0xde4: /* SFSR */
117
if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
118
goto bad_offset;
119
@@ -XXX,XX +XXX,XX @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value,
120
* only affect cacheability, and we don't implement caching.
121
*/
122
break;
123
+ case 0xdd0: /* SAU_CTRL */
124
+ if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
125
+ goto bad_offset;
126
+ }
127
+ if (!attrs.secure) {
128
+ return;
129
+ }
130
+ cpu->env.sau.ctrl = value & 3;
131
+ case 0xdd4: /* SAU_TYPE */
132
+ if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
133
+ goto bad_offset;
134
+ }
135
+ break;
136
+ case 0xdd8: /* SAU_RNR */
137
+ if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
138
+ goto bad_offset;
139
+ }
140
+ if (!attrs.secure) {
141
+ return;
142
+ }
143
+ if (value >= cpu->sau_sregion) {
144
+ qemu_log_mask(LOG_GUEST_ERROR, "SAU region out of range %"
145
+ PRIu32 "/%" PRIu32 "\n",
146
+ value, cpu->sau_sregion);
147
+ } else {
148
+ cpu->env.sau.rnr = value;
149
+ }
150
+ break;
151
+ case 0xddc: /* SAU_RBAR */
152
+ {
153
+ int region = cpu->env.sau.rnr;
154
+
155
+ if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
156
+ goto bad_offset;
157
+ }
158
+ if (!attrs.secure) {
159
+ return;
160
+ }
161
+ if (region >= cpu->sau_sregion) {
162
+ return;
163
+ }
164
+ cpu->env.sau.rbar[region] = value & ~0x1f;
165
+ tlb_flush(CPU(cpu));
166
+ break;
167
+ }
168
+ case 0xde0: /* SAU_RLAR */
169
+ {
170
+ int region = cpu->env.sau.rnr;
171
+
172
+ if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
173
+ goto bad_offset;
174
+ }
175
+ if (!attrs.secure) {
176
+ return;
177
+ }
178
+ if (region >= cpu->sau_sregion) {
179
+ return;
180
+ }
181
+ cpu->env.sau.rlar[region] = value & ~0x1c;
182
+ tlb_flush(CPU(cpu));
183
+ break;
184
+ }
185
case 0xde4: /* SFSR */
186
if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
187
goto bad_offset;
188
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
189
index XXXXXXX..XXXXXXX 100644
190
--- a/target/arm/cpu.c
191
+++ b/target/arm/cpu.c
192
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_reset(CPUState *s)
193
env->pmsav8.mair1[M_REG_S] = 0;
194
}
72
}
195
73
196
+ if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
74
+ for (i = 0; i < FSL_IMX8MP_NUM_ECSPIS; i++) {
197
+ if (cpu->sau_sregion > 0) {
75
+ g_autofree char *name = g_strdup_printf("spi%d", i + 1);
198
+ memset(env->sau.rbar, 0, sizeof(*env->sau.rbar) * cpu->sau_sregion);
76
+ object_initialize_child(obj, name, &s->spi[i], TYPE_IMX_SPI);
199
+ memset(env->sau.rlar, 0, sizeof(*env->sau.rlar) * cpu->sau_sregion);
200
+ }
201
+ env->sau.rnr = 0;
202
+ /* SAU_CTRL reset value is IMPDEF; we choose 0, which is what
203
+ * the Cortex-M33 does.
204
+ */
205
+ env->sau.ctrl = 0;
206
+ }
77
+ }
207
+
78
+
208
set_flush_to_zero(1, &env->vfp.standard_fp_status);
79
object_initialize_child(obj, "pcie", &s->pcie, TYPE_DESIGNWARE_PCIE_HOST);
209
set_flush_inputs_to_zero(1, &env->vfp.standard_fp_status);
80
object_initialize_child(obj, "pcie_phy", &s->pcie_phy,
210
set_default_nan_mode(1, &env->vfp.standard_fp_status);
81
TYPE_FSL_IMX8M_PCIE_PHY);
211
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
82
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
212
}
83
qdev_get_gpio_in(gicdev, usdhc_table[i].irq));
213
}
84
}
214
85
215
+ if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
86
+ /* ECSPIs */
216
+ uint32_t nr = cpu->sau_sregion;
87
+ for (i = 0; i < FSL_IMX8MP_NUM_ECSPIS; i++) {
88
+ struct {
89
+ hwaddr addr;
90
+ unsigned int irq;
91
+ } spi_table[FSL_IMX8MP_NUM_ECSPIS] = {
92
+ { fsl_imx8mp_memmap[FSL_IMX8MP_ECSPI1].addr, FSL_IMX8MP_ECSPI1_IRQ },
93
+ { fsl_imx8mp_memmap[FSL_IMX8MP_ECSPI2].addr, FSL_IMX8MP_ECSPI2_IRQ },
94
+ { fsl_imx8mp_memmap[FSL_IMX8MP_ECSPI3].addr, FSL_IMX8MP_ECSPI3_IRQ },
95
+ };
217
+
96
+
218
+ if (nr > 0xff) {
97
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), errp)) {
219
+ error_setg(errp, "v8M SAU #regions invalid %" PRIu32, nr);
220
+ return;
98
+ return;
221
+ }
99
+ }
222
+
100
+
223
+ if (nr) {
101
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, spi_table[i].addr);
224
+ env->sau.rbar = g_new0(uint32_t, nr);
102
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi[i]), 0,
225
+ env->sau.rlar = g_new0(uint32_t, nr);
103
+ qdev_get_gpio_in(gicdev, spi_table[i].irq));
226
+ }
227
+ }
104
+ }
228
+
105
+
229
if (arm_feature(env, ARM_FEATURE_EL3)) {
106
/* SNVS */
230
set_feature(env, ARM_FEATURE_VBAR);
107
if (!sysbus_realize(SYS_BUS_DEVICE(&s->snvs), errp)) {
231
}
108
return;
232
@@ -XXX,XX +XXX,XX @@ static void cortex_m4_initfn(Object *obj)
109
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
233
cpu->midr = 0x410fc240; /* r0p0 */
110
case FSL_IMX8MP_GIC_DIST:
234
cpu->pmsav7_dregion = 8;
111
case FSL_IMX8MP_GIC_REDIST:
235
}
112
case FSL_IMX8MP_GPIO1 ... FSL_IMX8MP_GPIO5:
236
+
113
+ case FSL_IMX8MP_ECSPI1 ... FSL_IMX8MP_ECSPI3:
237
static void arm_v7m_class_init(ObjectClass *oc, void *data)
114
case FSL_IMX8MP_I2C1 ... FSL_IMX8MP_I2C6:
238
{
115
case FSL_IMX8MP_PCIE1:
239
CPUClass *cc = CPU_CLASS(oc);
116
case FSL_IMX8MP_PCIE_PHY1:
240
diff --git a/target/arm/machine.c b/target/arm/machine.c
241
index XXXXXXX..XXXXXXX 100644
242
--- a/target/arm/machine.c
243
+++ b/target/arm/machine.c
244
@@ -XXX,XX +XXX,XX @@ static bool s_rnr_vmstate_validate(void *opaque, int version_id)
245
return cpu->env.pmsav7.rnr[M_REG_S] < cpu->pmsav7_dregion;
246
}
247
248
+static bool sau_rnr_vmstate_validate(void *opaque, int version_id)
249
+{
250
+ ARMCPU *cpu = opaque;
251
+
252
+ return cpu->env.sau.rnr < cpu->sau_sregion;
253
+}
254
+
255
static bool m_security_needed(void *opaque)
256
{
257
ARMCPU *cpu = opaque;
258
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_m_security = {
259
VMSTATE_UINT32(env.v7m.cfsr[M_REG_S], ARMCPU),
260
VMSTATE_UINT32(env.v7m.sfsr, ARMCPU),
261
VMSTATE_UINT32(env.v7m.sfar, ARMCPU),
262
+ VMSTATE_VARRAY_UINT32(env.sau.rbar, ARMCPU, sau_sregion, 0,
263
+ vmstate_info_uint32, uint32_t),
264
+ VMSTATE_VARRAY_UINT32(env.sau.rlar, ARMCPU, sau_sregion, 0,
265
+ vmstate_info_uint32, uint32_t),
266
+ VMSTATE_UINT32(env.sau.rnr, ARMCPU),
267
+ VMSTATE_VALIDATE("SAU_RNR is valid", sau_rnr_vmstate_validate),
268
+ VMSTATE_UINT32(env.sau.ctrl, ARMCPU),
269
VMSTATE_END_OF_LIST()
270
}
271
};
272
--
117
--
273
2.7.4
118
2.43.0
274
275
diff view generated by jsdifflib
New patch
1
From: Bernhard Beschow <shentey@gmail.com>
1
2
3
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
4
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
5
Message-id: 20250223114708.1780-13-shentey@gmail.com
6
[PMM: drop static const from wdog_table for GCC 7.5]
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
---
9
docs/system/arm/imx8mp-evk.rst | 1 +
10
include/hw/arm/fsl-imx8mp.h | 7 +++++++
11
hw/arm/fsl-imx8mp.c | 28 ++++++++++++++++++++++++++++
12
hw/arm/Kconfig | 1 +
13
4 files changed, 37 insertions(+)
14
15
diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8mp-evk.rst
16
index XXXXXXX..XXXXXXX 100644
17
--- a/docs/system/arm/imx8mp-evk.rst
18
+++ b/docs/system/arm/imx8mp-evk.rst
19
@@ -XXX,XX +XXX,XX @@ The ``imx8mp-evk`` machine implements the following devices:
20
* 5 GPIO Controllers
21
* 6 I2C Controllers
22
* 3 SPI Controllers
23
+ * 3 Watchdogs
24
* Secure Non-Volatile Storage (SNVS) including an RTC
25
* Clock Tree
26
27
diff --git a/include/hw/arm/fsl-imx8mp.h b/include/hw/arm/fsl-imx8mp.h
28
index XXXXXXX..XXXXXXX 100644
29
--- a/include/hw/arm/fsl-imx8mp.h
30
+++ b/include/hw/arm/fsl-imx8mp.h
31
@@ -XXX,XX +XXX,XX @@
32
#include "hw/pci-host/fsl_imx8m_phy.h"
33
#include "hw/sd/sdhci.h"
34
#include "hw/ssi/imx_spi.h"
35
+#include "hw/watchdog/wdt_imx2.h"
36
#include "qom/object.h"
37
#include "qemu/units.h"
38
39
@@ -XXX,XX +XXX,XX @@ enum FslImx8mpConfiguration {
40
FSL_IMX8MP_NUM_IRQS = 160,
41
FSL_IMX8MP_NUM_UARTS = 4,
42
FSL_IMX8MP_NUM_USDHCS = 3,
43
+ FSL_IMX8MP_NUM_WDTS = 3,
44
};
45
46
struct FslImx8mpState {
47
@@ -XXX,XX +XXX,XX @@ struct FslImx8mpState {
48
IMXI2CState i2c[FSL_IMX8MP_NUM_I2CS];
49
IMXSerialState uart[FSL_IMX8MP_NUM_UARTS];
50
SDHCIState usdhc[FSL_IMX8MP_NUM_USDHCS];
51
+ IMX2WdtState wdt[FSL_IMX8MP_NUM_WDTS];
52
DesignwarePCIEHost pcie;
53
FslImx8mPciePhyState pcie_phy;
54
};
55
@@ -XXX,XX +XXX,XX @@ enum FslImx8mpIrqs {
56
FSL_IMX8MP_I2C5_IRQ = 76,
57
FSL_IMX8MP_I2C6_IRQ = 77,
58
59
+ FSL_IMX8MP_WDOG1_IRQ = 78,
60
+ FSL_IMX8MP_WDOG2_IRQ = 79,
61
+ FSL_IMX8MP_WDOG3_IRQ = 10,
62
+
63
FSL_IMX8MP_PCI_INTA_IRQ = 126,
64
FSL_IMX8MP_PCI_INTB_IRQ = 125,
65
FSL_IMX8MP_PCI_INTC_IRQ = 124,
66
diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c
67
index XXXXXXX..XXXXXXX 100644
68
--- a/hw/arm/fsl-imx8mp.c
69
+++ b/hw/arm/fsl-imx8mp.c
70
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_init(Object *obj)
71
object_initialize_child(obj, name, &s->spi[i], TYPE_IMX_SPI);
72
}
73
74
+ for (i = 0; i < FSL_IMX8MP_NUM_WDTS; i++) {
75
+ g_autofree char *name = g_strdup_printf("wdt%d", i);
76
+ object_initialize_child(obj, name, &s->wdt[i], TYPE_IMX2_WDT);
77
+ }
78
+
79
object_initialize_child(obj, "pcie", &s->pcie, TYPE_DESIGNWARE_PCIE_HOST);
80
object_initialize_child(obj, "pcie_phy", &s->pcie_phy,
81
TYPE_FSL_IMX8M_PCIE_PHY);
82
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
83
sysbus_mmio_map(SYS_BUS_DEVICE(&s->snvs), 0,
84
fsl_imx8mp_memmap[FSL_IMX8MP_SNVS_HP].addr);
85
86
+ /* Watchdogs */
87
+ for (i = 0; i < FSL_IMX8MP_NUM_WDTS; i++) {
88
+ struct {
89
+ hwaddr addr;
90
+ unsigned int irq;
91
+ } wdog_table[FSL_IMX8MP_NUM_WDTS] = {
92
+ { fsl_imx8mp_memmap[FSL_IMX8MP_WDOG1].addr, FSL_IMX8MP_WDOG1_IRQ },
93
+ { fsl_imx8mp_memmap[FSL_IMX8MP_WDOG2].addr, FSL_IMX8MP_WDOG2_IRQ },
94
+ { fsl_imx8mp_memmap[FSL_IMX8MP_WDOG3].addr, FSL_IMX8MP_WDOG3_IRQ },
95
+ };
96
+
97
+ object_property_set_bool(OBJECT(&s->wdt[i]), "pretimeout-support",
98
+ true, &error_abort);
99
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) {
100
+ return;
101
+ }
102
+
103
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0, wdog_table[i].addr);
104
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt[i]), 0,
105
+ qdev_get_gpio_in(gicdev, wdog_table[i].irq));
106
+ }
107
+
108
/* PCIe */
109
if (!sysbus_realize(SYS_BUS_DEVICE(&s->pcie), errp)) {
110
return;
111
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
112
case FSL_IMX8MP_SNVS_HP:
113
case FSL_IMX8MP_UART1 ... FSL_IMX8MP_UART4:
114
case FSL_IMX8MP_USDHC1 ... FSL_IMX8MP_USDHC3:
115
+ case FSL_IMX8MP_WDOG1 ... FSL_IMX8MP_WDOG3:
116
/* device implemented and treated above */
117
break;
118
119
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
120
index XXXXXXX..XXXXXXX 100644
121
--- a/hw/arm/Kconfig
122
+++ b/hw/arm/Kconfig
123
@@ -XXX,XX +XXX,XX @@ config FSL_IMX8MP
124
select PCI_EXPRESS_FSL_IMX8M_PHY
125
select SDHCI
126
select UNIMP
127
+ select WDT_IMX2
128
129
config FSL_IMX8MP_EVK
130
bool
131
--
132
2.43.0
diff view generated by jsdifflib
1
From: Jan Kiszka <jan.kiszka@siemens.com>
1
From: Bernhard Beschow <shentey@gmail.com>
2
2
3
This properly forwards SMC events to EL2 when PSCI is provided by QEMU
4
itself and, thus, ARM_FEATURE_EL3 is off.
5
6
Found and tested with the Jailhouse hypervisor. Solution based on
7
suggestions by Peter Maydell.
8
9
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
10
Message-id: 4f243068-aaea-776f-d18f-f9e05e7be9cd@siemens.com
11
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
3
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
4
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
5
Message-id: 20250223114708.1780-14-shentey@gmail.com
6
[PMM: drop static const from gpt_attrs for GCC 7.5]
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
---
8
---
14
target/arm/helper.c | 9 ++++++++-
9
docs/system/arm/imx8mp-evk.rst | 1 +
15
target/arm/op_helper.c | 27 +++++++++++++++++----------
10
include/hw/arm/fsl-imx8mp.h | 11 +++++++
16
2 files changed, 25 insertions(+), 11 deletions(-)
11
include/hw/timer/imx_gpt.h | 1 +
12
hw/arm/fsl-imx8mp.c | 53 ++++++++++++++++++++++++++++++++++
13
hw/timer/imx_gpt.c | 25 ++++++++++++++++
14
hw/arm/Kconfig | 1 +
15
6 files changed, 92 insertions(+)
17
16
18
diff --git a/target/arm/helper.c b/target/arm/helper.c
17
diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8mp-evk.rst
19
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
20
--- a/target/arm/helper.c
19
--- a/docs/system/arm/imx8mp-evk.rst
21
+++ b/target/arm/helper.c
20
+++ b/docs/system/arm/imx8mp-evk.rst
22
@@ -XXX,XX +XXX,XX @@ static void hcr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
21
@@ -XXX,XX +XXX,XX @@ The ``imx8mp-evk`` machine implements the following devices:
23
22
* 6 I2C Controllers
24
if (arm_feature(env, ARM_FEATURE_EL3)) {
23
* 3 SPI Controllers
25
valid_mask &= ~HCR_HCD;
24
* 3 Watchdogs
26
- } else {
25
+ * 6 General Purpose Timers
27
+ } else if (cpu->psci_conduit != QEMU_PSCI_CONDUIT_SMC) {
26
* Secure Non-Volatile Storage (SNVS) including an RTC
28
+ /* Architecturally HCR.TSC is RES0 if EL3 is not implemented.
27
* Clock Tree
29
+ * However, if we're using the SMC PSCI conduit then QEMU is
28
30
+ * effectively acting like EL3 firmware and so the guest at
29
diff --git a/include/hw/arm/fsl-imx8mp.h b/include/hw/arm/fsl-imx8mp.h
31
+ * EL2 should retain the ability to prevent EL1 from being
30
index XXXXXXX..XXXXXXX 100644
32
+ * able to make SMC calls into the ersatz firmware, so in
31
--- a/include/hw/arm/fsl-imx8mp.h
33
+ * that case HCR.TSC should be read/write.
32
+++ b/include/hw/arm/fsl-imx8mp.h
34
+ */
33
@@ -XXX,XX +XXX,XX @@
35
valid_mask &= ~HCR_TSC;
34
#include "hw/misc/imx7_snvs.h"
35
#include "hw/misc/imx8mp_analog.h"
36
#include "hw/misc/imx8mp_ccm.h"
37
+#include "hw/or-irq.h"
38
#include "hw/pci-host/designware.h"
39
#include "hw/pci-host/fsl_imx8m_phy.h"
40
#include "hw/sd/sdhci.h"
41
#include "hw/ssi/imx_spi.h"
42
+#include "hw/timer/imx_gpt.h"
43
#include "hw/watchdog/wdt_imx2.h"
44
#include "qom/object.h"
45
#include "qemu/units.h"
46
@@ -XXX,XX +XXX,XX @@ enum FslImx8mpConfiguration {
47
FSL_IMX8MP_NUM_CPUS = 4,
48
FSL_IMX8MP_NUM_ECSPIS = 3,
49
FSL_IMX8MP_NUM_GPIOS = 5,
50
+ FSL_IMX8MP_NUM_GPTS = 6,
51
FSL_IMX8MP_NUM_I2CS = 6,
52
FSL_IMX8MP_NUM_IRQS = 160,
53
FSL_IMX8MP_NUM_UARTS = 4,
54
@@ -XXX,XX +XXX,XX @@ struct FslImx8mpState {
55
56
ARMCPU cpu[FSL_IMX8MP_NUM_CPUS];
57
GICv3State gic;
58
+ IMXGPTState gpt[FSL_IMX8MP_NUM_GPTS];
59
IMXGPIOState gpio[FSL_IMX8MP_NUM_GPIOS];
60
IMX8MPCCMState ccm;
61
IMX8MPAnalogState analog;
62
@@ -XXX,XX +XXX,XX @@ struct FslImx8mpState {
63
IMX2WdtState wdt[FSL_IMX8MP_NUM_WDTS];
64
DesignwarePCIEHost pcie;
65
FslImx8mPciePhyState pcie_phy;
66
+ OrIRQState gpt5_gpt6_irq;
67
};
68
69
enum FslImx8mpMemoryRegions {
70
@@ -XXX,XX +XXX,XX @@ enum FslImx8mpIrqs {
71
FSL_IMX8MP_I2C3_IRQ = 37,
72
FSL_IMX8MP_I2C4_IRQ = 38,
73
74
+ FSL_IMX8MP_GPT1_IRQ = 55,
75
+ FSL_IMX8MP_GPT2_IRQ = 54,
76
+ FSL_IMX8MP_GPT3_IRQ = 53,
77
+ FSL_IMX8MP_GPT4_IRQ = 52,
78
+ FSL_IMX8MP_GPT5_GPT6_IRQ = 51,
79
+
80
FSL_IMX8MP_GPIO1_LOW_IRQ = 64,
81
FSL_IMX8MP_GPIO1_HIGH_IRQ = 65,
82
FSL_IMX8MP_GPIO2_LOW_IRQ = 66,
83
diff --git a/include/hw/timer/imx_gpt.h b/include/hw/timer/imx_gpt.h
84
index XXXXXXX..XXXXXXX 100644
85
--- a/include/hw/timer/imx_gpt.h
86
+++ b/include/hw/timer/imx_gpt.h
87
@@ -XXX,XX +XXX,XX @@
88
#define TYPE_IMX6_GPT "imx6.gpt"
89
#define TYPE_IMX6UL_GPT "imx6ul.gpt"
90
#define TYPE_IMX7_GPT "imx7.gpt"
91
+#define TYPE_IMX8MP_GPT "imx8mp.gpt"
92
93
#define TYPE_IMX_GPT TYPE_IMX25_GPT
94
95
diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c
96
index XXXXXXX..XXXXXXX 100644
97
--- a/hw/arm/fsl-imx8mp.c
98
+++ b/hw/arm/fsl-imx8mp.c
99
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_init(Object *obj)
100
object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL);
36
}
101
}
37
102
38
diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c
103
+ for (i = 0; i < FSL_IMX8MP_NUM_GPTS; i++) {
39
index XXXXXXX..XXXXXXX 100644
104
+ g_autofree char *name = g_strdup_printf("gpt%d", i + 1);
40
--- a/target/arm/op_helper.c
105
+ object_initialize_child(obj, name, &s->gpt[i], TYPE_IMX8MP_GPT);
41
+++ b/target/arm/op_helper.c
106
+ }
42
@@ -XXX,XX +XXX,XX @@ void HELPER(pre_smc)(CPUARMState *env, uint32_t syndrome)
107
+ object_initialize_child(obj, "gpt5-gpt6-irq", &s->gpt5_gpt6_irq,
43
*/
108
+ TYPE_OR_IRQ);
44
bool undef = arm_feature(env, ARM_FEATURE_AARCH64) ? smd : smd && !secure;
109
+
45
110
for (i = 0; i < FSL_IMX8MP_NUM_I2CS; i++) {
46
- if (arm_is_psci_call(cpu, EXCP_SMC)) {
111
g_autofree char *name = g_strdup_printf("i2c%d", i + 1);
47
- /* If PSCI is enabled and this looks like a valid PSCI call then
112
object_initialize_child(obj, name, &s->i2c[i], TYPE_IMX_I2C);
48
- * that overrides the architecturally mandated SMC behaviour.
113
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
49
+ if (!arm_feature(env, ARM_FEATURE_EL3) &&
114
qdev_get_gpio_in(gicdev, serial_table[i].irq));
50
+ cpu->psci_conduit != QEMU_PSCI_CONDUIT_SMC) {
51
+ /* If we have no EL3 then SMC always UNDEFs and can't be
52
+ * trapped to EL2. PSCI-via-SMC is a sort of ersatz EL3
53
+ * firmware within QEMU, and we want an EL2 guest to be able
54
+ * to forbid its EL1 from making PSCI calls into QEMU's
55
+ * "firmware" via HCR.TSC, so for these purposes treat
56
+ * PSCI-via-SMC as implying an EL3.
57
*/
58
- return;
59
- }
60
-
61
- if (!arm_feature(env, ARM_FEATURE_EL3)) {
62
- /* If we have no EL3 then SMC always UNDEFs */
63
undef = true;
64
} else if (!secure && cur_el == 1 && (env->cp15.hcr_el2 & HCR_TSC)) {
65
- /* In NS EL1, HCR controlled routing to EL2 has priority over SMD. */
66
+ /* In NS EL1, HCR controlled routing to EL2 has priority over SMD.
67
+ * We also want an EL2 guest to be able to forbid its EL1 from
68
+ * making PSCI calls into QEMU's "firmware" via HCR.TSC.
69
+ */
70
raise_exception(env, EXCP_HYP_TRAP, syndrome, 2);
71
}
115
}
72
116
73
- if (undef) {
117
+ /* GPTs */
74
+ /* If PSCI is enabled and this looks like a valid PSCI call then
118
+ object_property_set_int(OBJECT(&s->gpt5_gpt6_irq), "num-lines", 2,
75
+ * suppress the UNDEF -- we'll catch the SMC exception and
119
+ &error_abort);
76
+ * implement the PSCI call behaviour there.
120
+ if (!qdev_realize(DEVICE(&s->gpt5_gpt6_irq), NULL, errp)) {
77
+ */
121
+ return;
78
+ if (undef && !arm_is_psci_call(cpu, EXCP_SMC)) {
122
+ }
79
raise_exception(env, EXCP_UDEF, syn_uncategorized(),
123
+
80
exception_target_el(env));
124
+ qdev_connect_gpio_out(DEVICE(&s->gpt5_gpt6_irq), 0,
81
}
125
+ qdev_get_gpio_in(gicdev, FSL_IMX8MP_GPT5_GPT6_IRQ));
126
+
127
+ for (i = 0; i < FSL_IMX8MP_NUM_GPTS; i++) {
128
+ hwaddr gpt_addrs[FSL_IMX8MP_NUM_GPTS] = {
129
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPT1].addr,
130
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPT2].addr,
131
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPT3].addr,
132
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPT4].addr,
133
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPT5].addr,
134
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPT6].addr,
135
+ };
136
+
137
+ s->gpt[i].ccm = IMX_CCM(&s->ccm);
138
+
139
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpt[i]), errp)) {
140
+ return;
141
+ }
142
+
143
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpt[i]), 0, gpt_addrs[i]);
144
+
145
+ if (i < FSL_IMX8MP_NUM_GPTS - 2) {
146
+ static const unsigned int gpt_irqs[FSL_IMX8MP_NUM_GPTS - 2] = {
147
+ FSL_IMX8MP_GPT1_IRQ,
148
+ FSL_IMX8MP_GPT2_IRQ,
149
+ FSL_IMX8MP_GPT3_IRQ,
150
+ FSL_IMX8MP_GPT4_IRQ,
151
+ };
152
+
153
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt[i]), 0,
154
+ qdev_get_gpio_in(gicdev, gpt_irqs[i]));
155
+ } else {
156
+ int irq = i - FSL_IMX8MP_NUM_GPTS + 2;
157
+
158
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt[i]), 0,
159
+ qdev_get_gpio_in(DEVICE(&s->gpt5_gpt6_irq), irq));
160
+ }
161
+ }
162
+
163
/* I2Cs */
164
for (i = 0; i < FSL_IMX8MP_NUM_I2CS; i++) {
165
struct {
166
diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c
167
index XXXXXXX..XXXXXXX 100644
168
--- a/hw/timer/imx_gpt.c
169
+++ b/hw/timer/imx_gpt.c
170
@@ -XXX,XX +XXX,XX @@ static const IMXClk imx7_gpt_clocks[] = {
171
CLK_NONE, /* 111 not defined */
172
};
173
174
+static const IMXClk imx8mp_gpt_clocks[] = {
175
+ CLK_NONE, /* 000 No clock source */
176
+ CLK_IPG, /* 001 ipg_clk, 532MHz */
177
+ CLK_IPG_HIGH, /* 010 ipg_clk_highfreq */
178
+ CLK_EXT, /* 011 External clock */
179
+ CLK_32k, /* 100 ipg_clk_32k */
180
+ CLK_HIGH, /* 101 ipg_clk_16M */
181
+ CLK_NONE, /* 110 not defined */
182
+ CLK_NONE, /* 111 not defined */
183
+};
184
+
185
/* Must be called from within ptimer_transaction_begin/commit block */
186
static void imx_gpt_set_freq(IMXGPTState *s)
187
{
188
@@ -XXX,XX +XXX,XX @@ static void imx7_gpt_init(Object *obj)
189
s->clocks = imx7_gpt_clocks;
190
}
191
192
+static void imx8mp_gpt_init(Object *obj)
193
+{
194
+ IMXGPTState *s = IMX_GPT(obj);
195
+
196
+ s->clocks = imx8mp_gpt_clocks;
197
+}
198
+
199
static const TypeInfo imx25_gpt_info = {
200
.name = TYPE_IMX25_GPT,
201
.parent = TYPE_SYS_BUS_DEVICE,
202
@@ -XXX,XX +XXX,XX @@ static const TypeInfo imx7_gpt_info = {
203
.instance_init = imx7_gpt_init,
204
};
205
206
+static const TypeInfo imx8mp_gpt_info = {
207
+ .name = TYPE_IMX8MP_GPT,
208
+ .parent = TYPE_IMX25_GPT,
209
+ .instance_init = imx8mp_gpt_init,
210
+};
211
+
212
static void imx_gpt_register_types(void)
213
{
214
type_register_static(&imx25_gpt_info);
215
@@ -XXX,XX +XXX,XX @@ static void imx_gpt_register_types(void)
216
type_register_static(&imx6_gpt_info);
217
type_register_static(&imx6ul_gpt_info);
218
type_register_static(&imx7_gpt_info);
219
+ type_register_static(&imx8mp_gpt_info);
220
}
221
222
type_init(imx_gpt_register_types)
223
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
224
index XXXXXXX..XXXXXXX 100644
225
--- a/hw/arm/Kconfig
226
+++ b/hw/arm/Kconfig
227
@@ -XXX,XX +XXX,XX @@ config FSL_IMX8MP
228
select FSL_IMX8MP_CCM
229
select IMX
230
select IMX_I2C
231
+ select OR_IRQ
232
select PCI_EXPRESS_DESIGNWARE
233
select PCI_EXPRESS_FSL_IMX8M_PHY
234
select SDHCI
82
--
235
--
83
2.7.4
236
2.43.0
84
85
diff view generated by jsdifflib
1
From: Thomas Huth <thuth@redhat.com>
1
From: Bernhard Beschow <shentey@gmail.com>
2
2
3
The device uses serial_hds in its realize function and thus can't be
3
The i.MX 8M Plus SoC actually has two ethernet controllers, the usual ENET one
4
used twice. Apart from that, the comma in its name makes it quite hard
4
and a Designware one. There is no device model for the latter, so only add the
5
to use for the user anyway, since a comma is normally used to separate
5
ENET one.
6
the device name from its properties when using the "-device" parameter
7
or the "device_add" HMP command.
8
6
9
Signed-off-by: Thomas Huth <thuth@redhat.com>
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Reviewed-by: Alistair Francis <alistair.francis@xilinx.com>
8
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
11
Message-id: 1506441116-16627-1-git-send-email-thuth@redhat.com
9
Message-id: 20250223114708.1780-15-shentey@gmail.com
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
---
11
---
14
hw/arm/xlnx-zynqmp.c | 2 ++
12
docs/system/arm/imx8mp-evk.rst | 1 +
15
1 file changed, 2 insertions(+)
13
include/hw/arm/fsl-imx8mp.h | 8 ++++++++
14
hw/arm/fsl-imx8mp.c | 24 ++++++++++++++++++++++++
15
hw/arm/imx8mp-evk.c | 1 +
16
hw/arm/Kconfig | 1 +
17
5 files changed, 35 insertions(+)
16
18
17
diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
19
diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8mp-evk.rst
18
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
19
--- a/hw/arm/xlnx-zynqmp.c
21
--- a/docs/system/arm/imx8mp-evk.rst
20
+++ b/hw/arm/xlnx-zynqmp.c
22
+++ b/docs/system/arm/imx8mp-evk.rst
21
@@ -XXX,XX +XXX,XX @@ static void xlnx_zynqmp_class_init(ObjectClass *oc, void *data)
23
@@ -XXX,XX +XXX,XX @@ The ``imx8mp-evk`` machine implements the following devices:
22
24
* 4 UARTs
23
dc->props = xlnx_zynqmp_props;
25
* 3 USDHC Storage Controllers
24
dc->realize = xlnx_zynqmp_realize;
26
* 1 Designware PCI Express Controller
25
+ /* Reason: Uses serial_hds in realize function, thus can't be used twice */
27
+ * 1 Ethernet Controller
26
+ dc->user_creatable = false;
28
* 5 GPIO Controllers
29
* 6 I2C Controllers
30
* 3 SPI Controllers
31
diff --git a/include/hw/arm/fsl-imx8mp.h b/include/hw/arm/fsl-imx8mp.h
32
index XXXXXXX..XXXXXXX 100644
33
--- a/include/hw/arm/fsl-imx8mp.h
34
+++ b/include/hw/arm/fsl-imx8mp.h
35
@@ -XXX,XX +XXX,XX @@
36
#include "hw/misc/imx7_snvs.h"
37
#include "hw/misc/imx8mp_analog.h"
38
#include "hw/misc/imx8mp_ccm.h"
39
+#include "hw/net/imx_fec.h"
40
#include "hw/or-irq.h"
41
#include "hw/pci-host/designware.h"
42
#include "hw/pci-host/fsl_imx8m_phy.h"
43
@@ -XXX,XX +XXX,XX @@ struct FslImx8mpState {
44
IMXSPIState spi[FSL_IMX8MP_NUM_ECSPIS];
45
IMXI2CState i2c[FSL_IMX8MP_NUM_I2CS];
46
IMXSerialState uart[FSL_IMX8MP_NUM_UARTS];
47
+ IMXFECState enet;
48
SDHCIState usdhc[FSL_IMX8MP_NUM_USDHCS];
49
IMX2WdtState wdt[FSL_IMX8MP_NUM_WDTS];
50
DesignwarePCIEHost pcie;
51
FslImx8mPciePhyState pcie_phy;
52
OrIRQState gpt5_gpt6_irq;
53
+
54
+ uint32_t phy_num;
55
+ bool phy_connected;
56
};
57
58
enum FslImx8mpMemoryRegions {
59
@@ -XXX,XX +XXX,XX @@ enum FslImx8mpIrqs {
60
FSL_IMX8MP_WDOG2_IRQ = 79,
61
FSL_IMX8MP_WDOG3_IRQ = 10,
62
63
+ FSL_IMX8MP_ENET1_MAC_IRQ = 118,
64
+ FSL_IMX6_ENET1_MAC_1588_IRQ = 121,
65
+
66
FSL_IMX8MP_PCI_INTA_IRQ = 126,
67
FSL_IMX8MP_PCI_INTB_IRQ = 125,
68
FSL_IMX8MP_PCI_INTC_IRQ = 124,
69
diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c
70
index XXXXXXX..XXXXXXX 100644
71
--- a/hw/arm/fsl-imx8mp.c
72
+++ b/hw/arm/fsl-imx8mp.c
73
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_init(Object *obj)
74
object_initialize_child(obj, name, &s->wdt[i], TYPE_IMX2_WDT);
75
}
76
77
+ object_initialize_child(obj, "eth0", &s->enet, TYPE_IMX_ENET);
78
+
79
object_initialize_child(obj, "pcie", &s->pcie, TYPE_DESIGNWARE_PCIE_HOST);
80
object_initialize_child(obj, "pcie_phy", &s->pcie_phy,
81
TYPE_FSL_IMX8M_PCIE_PHY);
82
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
83
qdev_get_gpio_in(gicdev, spi_table[i].irq));
84
}
85
86
+ /* ENET1 */
87
+ object_property_set_uint(OBJECT(&s->enet), "phy-num", s->phy_num,
88
+ &error_abort);
89
+ object_property_set_uint(OBJECT(&s->enet), "tx-ring-num", 3, &error_abort);
90
+ qemu_configure_nic_device(DEVICE(&s->enet), true, NULL);
91
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->enet), errp)) {
92
+ return;
93
+ }
94
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->enet), 0,
95
+ fsl_imx8mp_memmap[FSL_IMX8MP_ENET1].addr);
96
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->enet), 0,
97
+ qdev_get_gpio_in(gicdev, FSL_IMX8MP_ENET1_MAC_IRQ));
98
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->enet), 1,
99
+ qdev_get_gpio_in(gicdev, FSL_IMX6_ENET1_MAC_1588_IRQ));
100
+
101
/* SNVS */
102
if (!sysbus_realize(SYS_BUS_DEVICE(&s->snvs), errp)) {
103
return;
104
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
105
case FSL_IMX8MP_GIC_REDIST:
106
case FSL_IMX8MP_GPIO1 ... FSL_IMX8MP_GPIO5:
107
case FSL_IMX8MP_ECSPI1 ... FSL_IMX8MP_ECSPI3:
108
+ case FSL_IMX8MP_ENET1:
109
case FSL_IMX8MP_I2C1 ... FSL_IMX8MP_I2C6:
110
case FSL_IMX8MP_PCIE1:
111
case FSL_IMX8MP_PCIE_PHY1:
112
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
113
}
27
}
114
}
28
115
29
static const TypeInfo xlnx_zynqmp_type_info = {
116
+static const Property fsl_imx8mp_properties[] = {
117
+ DEFINE_PROP_UINT32("fec1-phy-num", FslImx8mpState, phy_num, 0),
118
+ DEFINE_PROP_BOOL("fec1-phy-connected", FslImx8mpState, phy_connected, true),
119
+};
120
+
121
static void fsl_imx8mp_class_init(ObjectClass *oc, void *data)
122
{
123
DeviceClass *dc = DEVICE_CLASS(oc);
124
125
+ device_class_set_props(dc, fsl_imx8mp_properties);
126
dc->realize = fsl_imx8mp_realize;
127
128
dc->desc = "i.MX 8M Plus SoC";
129
diff --git a/hw/arm/imx8mp-evk.c b/hw/arm/imx8mp-evk.c
130
index XXXXXXX..XXXXXXX 100644
131
--- a/hw/arm/imx8mp-evk.c
132
+++ b/hw/arm/imx8mp-evk.c
133
@@ -XXX,XX +XXX,XX @@ static void imx8mp_evk_init(MachineState *machine)
134
135
s = FSL_IMX8MP(object_new(TYPE_FSL_IMX8MP));
136
object_property_add_child(OBJECT(machine), "soc", OBJECT(s));
137
+ object_property_set_uint(OBJECT(s), "fec1-phy-num", 1, &error_fatal);
138
qdev_realize(DEVICE(s), NULL, &error_fatal);
139
140
memory_region_add_subregion(get_system_memory(), FSL_IMX8MP_RAM_START,
141
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
142
index XXXXXXX..XXXXXXX 100644
143
--- a/hw/arm/Kconfig
144
+++ b/hw/arm/Kconfig
145
@@ -XXX,XX +XXX,XX @@ config FSL_IMX8MP
146
select FSL_IMX8MP_ANALOG
147
select FSL_IMX8MP_CCM
148
select IMX
149
+ select IMX_FEC
150
select IMX_I2C
151
select OR_IRQ
152
select PCI_EXPRESS_DESIGNWARE
30
--
153
--
31
2.7.4
154
2.43.0
32
33
diff view generated by jsdifflib
New patch
1
From: Bernhard Beschow <shentey@gmail.com>
1
2
3
Split the USB MMIO regions to better keep track of the implemented vs.
4
unimplemented regions.
5
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
8
Message-id: 20250223114708.1780-16-shentey@gmail.com
9
[PMM: drop "static const" from usb_table for GCC 7.5]
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
12
docs/system/arm/imx8mp-evk.rst | 1 +
13
include/hw/arm/fsl-imx8mp.h | 12 +++++++++++
14
hw/arm/fsl-imx8mp.c | 37 ++++++++++++++++++++++++++++++++--
15
hw/arm/Kconfig | 1 +
16
4 files changed, 49 insertions(+), 2 deletions(-)
17
18
diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8mp-evk.rst
19
index XXXXXXX..XXXXXXX 100644
20
--- a/docs/system/arm/imx8mp-evk.rst
21
+++ b/docs/system/arm/imx8mp-evk.rst
22
@@ -XXX,XX +XXX,XX @@ The ``imx8mp-evk`` machine implements the following devices:
23
* 3 USDHC Storage Controllers
24
* 1 Designware PCI Express Controller
25
* 1 Ethernet Controller
26
+ * 2 Designware USB 3 Controllers
27
* 5 GPIO Controllers
28
* 6 I2C Controllers
29
* 3 SPI Controllers
30
diff --git a/include/hw/arm/fsl-imx8mp.h b/include/hw/arm/fsl-imx8mp.h
31
index XXXXXXX..XXXXXXX 100644
32
--- a/include/hw/arm/fsl-imx8mp.h
33
+++ b/include/hw/arm/fsl-imx8mp.h
34
@@ -XXX,XX +XXX,XX @@
35
#include "hw/sd/sdhci.h"
36
#include "hw/ssi/imx_spi.h"
37
#include "hw/timer/imx_gpt.h"
38
+#include "hw/usb/hcd-dwc3.h"
39
#include "hw/watchdog/wdt_imx2.h"
40
#include "qom/object.h"
41
#include "qemu/units.h"
42
@@ -XXX,XX +XXX,XX @@ enum FslImx8mpConfiguration {
43
FSL_IMX8MP_NUM_I2CS = 6,
44
FSL_IMX8MP_NUM_IRQS = 160,
45
FSL_IMX8MP_NUM_UARTS = 4,
46
+ FSL_IMX8MP_NUM_USBS = 2,
47
FSL_IMX8MP_NUM_USDHCS = 3,
48
FSL_IMX8MP_NUM_WDTS = 3,
49
};
50
@@ -XXX,XX +XXX,XX @@ struct FslImx8mpState {
51
IMXFECState enet;
52
SDHCIState usdhc[FSL_IMX8MP_NUM_USDHCS];
53
IMX2WdtState wdt[FSL_IMX8MP_NUM_WDTS];
54
+ USBDWC3 usb[FSL_IMX8MP_NUM_USBS];
55
DesignwarePCIEHost pcie;
56
FslImx8mPciePhyState pcie_phy;
57
OrIRQState gpt5_gpt6_irq;
58
@@ -XXX,XX +XXX,XX @@ enum FslImx8mpMemoryRegions {
59
FSL_IMX8MP_UART4,
60
FSL_IMX8MP_USB1,
61
FSL_IMX8MP_USB2,
62
+ FSL_IMX8MP_USB1_DEV,
63
+ FSL_IMX8MP_USB2_DEV,
64
+ FSL_IMX8MP_USB1_OTG,
65
+ FSL_IMX8MP_USB2_OTG,
66
+ FSL_IMX8MP_USB1_GLUE,
67
+ FSL_IMX8MP_USB2_GLUE,
68
FSL_IMX8MP_USDHC1,
69
FSL_IMX8MP_USDHC2,
70
FSL_IMX8MP_USDHC3,
71
@@ -XXX,XX +XXX,XX @@ enum FslImx8mpIrqs {
72
FSL_IMX8MP_I2C3_IRQ = 37,
73
FSL_IMX8MP_I2C4_IRQ = 38,
74
75
+ FSL_IMX8MP_USB1_IRQ = 40,
76
+ FSL_IMX8MP_USB2_IRQ = 41,
77
+
78
FSL_IMX8MP_GPT1_IRQ = 55,
79
FSL_IMX8MP_GPT2_IRQ = 54,
80
FSL_IMX8MP_GPT3_IRQ = 53,
81
diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c
82
index XXXXXXX..XXXXXXX 100644
83
--- a/hw/arm/fsl-imx8mp.c
84
+++ b/hw/arm/fsl-imx8mp.c
85
@@ -XXX,XX +XXX,XX @@ static const struct {
86
[FSL_IMX8MP_VPU_VC8000E_ENCODER] = { 0x38320000, 2 * MiB, "vpu_vc8000e_encoder" },
87
[FSL_IMX8MP_VPU_G2_DECODER] = { 0x38310000, 2 * MiB, "vpu_g2_decoder" },
88
[FSL_IMX8MP_VPU_G1_DECODER] = { 0x38300000, 2 * MiB, "vpu_g1_decoder" },
89
- [FSL_IMX8MP_USB2] = { 0x38200000, 1 * MiB, "usb2" },
90
- [FSL_IMX8MP_USB1] = { 0x38100000, 1 * MiB, "usb1" },
91
+ [FSL_IMX8MP_USB2_GLUE] = { 0x382f0000, 0x100, "usb2_glue" },
92
+ [FSL_IMX8MP_USB2_OTG] = { 0x3820cc00, 0x100, "usb2_otg" },
93
+ [FSL_IMX8MP_USB2_DEV] = { 0x3820c700, 0x500, "usb2_dev" },
94
+ [FSL_IMX8MP_USB2] = { 0x38200000, 0xc700, "usb2" },
95
+ [FSL_IMX8MP_USB1_GLUE] = { 0x381f0000, 0x100, "usb1_glue" },
96
+ [FSL_IMX8MP_USB1_OTG] = { 0x3810cc00, 0x100, "usb1_otg" },
97
+ [FSL_IMX8MP_USB1_DEV] = { 0x3810c700, 0x500, "usb1_dev" },
98
+ [FSL_IMX8MP_USB1] = { 0x38100000, 0xc700, "usb1" },
99
[FSL_IMX8MP_GPU2D] = { 0x38008000, 32 * KiB, "gpu2d" },
100
[FSL_IMX8MP_GPU3D] = { 0x38000000, 32 * KiB, "gpu3d" },
101
[FSL_IMX8MP_QSPI1_RX_BUFFER] = { 0x34000000, 32 * MiB, "qspi1_rx_buffer" },
102
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_init(Object *obj)
103
object_initialize_child(obj, name, &s->usdhc[i], TYPE_IMX_USDHC);
104
}
105
106
+ for (i = 0; i < FSL_IMX8MP_NUM_USBS; i++) {
107
+ g_autofree char *name = g_strdup_printf("usb%d", i);
108
+ object_initialize_child(obj, name, &s->usb[i], TYPE_USB_DWC3);
109
+ }
110
+
111
for (i = 0; i < FSL_IMX8MP_NUM_ECSPIS; i++) {
112
g_autofree char *name = g_strdup_printf("spi%d", i + 1);
113
object_initialize_child(obj, name, &s->spi[i], TYPE_IMX_SPI);
114
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
115
qdev_get_gpio_in(gicdev, usdhc_table[i].irq));
116
}
117
118
+ /* USBs */
119
+ for (i = 0; i < FSL_IMX8MP_NUM_USBS; i++) {
120
+ struct {
121
+ hwaddr addr;
122
+ unsigned int irq;
123
+ } usb_table[FSL_IMX8MP_NUM_USBS] = {
124
+ { fsl_imx8mp_memmap[FSL_IMX8MP_USB1].addr, FSL_IMX8MP_USB1_IRQ },
125
+ { fsl_imx8mp_memmap[FSL_IMX8MP_USB2].addr, FSL_IMX8MP_USB2_IRQ },
126
+ };
127
+
128
+ qdev_prop_set_uint32(DEVICE(&s->usb[i].sysbus_xhci), "p2", 1);
129
+ qdev_prop_set_uint32(DEVICE(&s->usb[i].sysbus_xhci), "p3", 1);
130
+ qdev_prop_set_uint32(DEVICE(&s->usb[i].sysbus_xhci), "slots", 2);
131
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->usb[i]), errp)) {
132
+ return;
133
+ }
134
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->usb[i]), 0, usb_table[i].addr);
135
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->usb[i].sysbus_xhci), 0,
136
+ qdev_get_gpio_in(gicdev, usb_table[i].irq));
137
+ }
138
+
139
/* ECSPIs */
140
for (i = 0; i < FSL_IMX8MP_NUM_ECSPIS; i++) {
141
struct {
142
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
143
case FSL_IMX8MP_RAM:
144
case FSL_IMX8MP_SNVS_HP:
145
case FSL_IMX8MP_UART1 ... FSL_IMX8MP_UART4:
146
+ case FSL_IMX8MP_USB1 ... FSL_IMX8MP_USB2:
147
case FSL_IMX8MP_USDHC1 ... FSL_IMX8MP_USDHC3:
148
case FSL_IMX8MP_WDOG1 ... FSL_IMX8MP_WDOG3:
149
/* device implemented and treated above */
150
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
151
index XXXXXXX..XXXXXXX 100644
152
--- a/hw/arm/Kconfig
153
+++ b/hw/arm/Kconfig
154
@@ -XXX,XX +XXX,XX @@ config FSL_IMX8MP
155
select PCI_EXPRESS_FSL_IMX8M_PHY
156
select SDHCI
157
select UNIMP
158
+ select USB_DWC3
159
select WDT_IMX2
160
161
config FSL_IMX8MP_EVK
162
--
163
2.43.0
diff view generated by jsdifflib
New patch
1
From: Bernhard Beschow <shentey@gmail.com>
1
2
3
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
4
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
5
Message-id: 20250223114708.1780-18-shentey@gmail.com
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
---
8
include/hw/arm/fsl-imx8mp.h | 1 +
9
hw/arm/fsl-imx8mp.c | 11 +++++++++++
10
2 files changed, 12 insertions(+)
11
12
diff --git a/include/hw/arm/fsl-imx8mp.h b/include/hw/arm/fsl-imx8mp.h
13
index XXXXXXX..XXXXXXX 100644
14
--- a/include/hw/arm/fsl-imx8mp.h
15
+++ b/include/hw/arm/fsl-imx8mp.h
16
@@ -XXX,XX +XXX,XX @@ struct FslImx8mpState {
17
DesignwarePCIEHost pcie;
18
FslImx8mPciePhyState pcie_phy;
19
OrIRQState gpt5_gpt6_irq;
20
+ MemoryRegion ocram;
21
22
uint32_t phy_num;
23
bool phy_connected;
24
diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c
25
index XXXXXXX..XXXXXXX 100644
26
--- a/hw/arm/fsl-imx8mp.c
27
+++ b/hw/arm/fsl-imx8mp.c
28
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
29
sysbus_mmio_map(SYS_BUS_DEVICE(&s->pcie_phy), 0,
30
fsl_imx8mp_memmap[FSL_IMX8MP_PCIE_PHY1].addr);
31
32
+ /* On-Chip RAM */
33
+ if (!memory_region_init_ram(&s->ocram, NULL, "imx8mp.ocram",
34
+ fsl_imx8mp_memmap[FSL_IMX8MP_OCRAM].size,
35
+ errp)) {
36
+ return;
37
+ }
38
+ memory_region_add_subregion(get_system_memory(),
39
+ fsl_imx8mp_memmap[FSL_IMX8MP_OCRAM].addr,
40
+ &s->ocram);
41
+
42
/* Unimplemented devices */
43
for (i = 0; i < ARRAY_SIZE(fsl_imx8mp_memmap); i++) {
44
switch (i) {
45
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
46
case FSL_IMX8MP_ECSPI1 ... FSL_IMX8MP_ECSPI3:
47
case FSL_IMX8MP_ENET1:
48
case FSL_IMX8MP_I2C1 ... FSL_IMX8MP_I2C6:
49
+ case FSL_IMX8MP_OCRAM:
50
case FSL_IMX8MP_PCIE1:
51
case FSL_IMX8MP_PCIE_PHY1:
52
case FSL_IMX8MP_RAM:
53
--
54
2.43.0
diff view generated by jsdifflib