1
Two small bugfixes, plus most of RTH's refactoring of cpregs
1
Hi; here's another Arm pullreq: the big thing in here is
2
handling.
2
Bernhard's imx8mp-evk board model; there's also various cleanup
3
type patches from me, as well as some bugfixes.
3
4
5
thanks
4
-- PMM
6
-- PMM
5
7
6
The following changes since commit 1fba9dc71a170b3a05b9d3272dd8ecfe7f26e215:
8
The following changes since commit b69801dd6b1eb4d107f7c2f643adf0a4e3ec9124:
7
9
8
Merge tag 'pull-request-2022-05-04' of https://gitlab.com/thuth/qemu into staging (2022-05-04 08:07:02 -0700)
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)
9
11
10
are available in the Git repository at:
12
are available in the Git repository at:
11
13
12
https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20220505
14
https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20250225
13
15
14
for you to fetch changes up to 99a50d1a67c602126fc2b3a4812d3000eba9bf34:
16
for you to fetch changes up to 1aaf3478684ff1cd02d1b36c32a00bfac9a5dbd5:
15
17
16
target/arm: read access to performance counters from EL0 (2022-05-05 09:36:22 +0100)
18
hw/arm/fsl-imx8mp: Add on-chip RAM (2025-02-25 17:24:00 +0000)
17
19
18
----------------------------------------------------------------
20
----------------------------------------------------------------
19
target-arm queue:
21
target-arm queue:
20
* Enable read access to performance counters from EL0
22
* hw/arm/smmuv3: Fill u.f_cd_fetch.addr for SMMU_EVT_F_CD_FETCH
21
* Enable SCTLR_EL1.BT0 for aarch64-linux-user
23
* hw/arm/virt: Support larger highmem MMIO regions
22
* Refactoring of cpreg handling
24
* machine: Centralize -machine dumpdtb option handling and report
25
attempt to dump nonexistent DTB as an error
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")
23
32
24
----------------------------------------------------------------
33
----------------------------------------------------------------
25
Alex Zuepke (1):
34
Bernhard Beschow (16):
26
target/arm: read access to performance counters from EL0
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
27
51
28
Richard Henderson (22):
52
Joelle van Dyne (2):
29
target/arm: Enable SCTLR_EL1.BT0 for aarch64-linux-user
53
target/arm/hvf: Disable SME feature
30
target/arm: Split out cpregs.h
54
target/arm/hvf: sign extend the data for a load operation when SSE=1
31
target/arm: Reorg CPAccessResult and access_check_cp_reg
32
target/arm: Replace sentinels with ARRAY_SIZE in cpregs.h
33
target/arm: Make some more cpreg data static const
34
target/arm: Reorg ARMCPRegInfo type field bits
35
target/arm: Avoid bare abort() or assert(0)
36
target/arm: Change cpreg access permissions to enum
37
target/arm: Name CPState type
38
target/arm: Name CPSecureState type
39
target/arm: Drop always-true test in define_arm_vh_e2h_redirects_aliases
40
target/arm: Store cpregs key in the hash table directly
41
target/arm: Merge allocation of the cpreg and its name
42
target/arm: Hoist computation of key in add_cpreg_to_hashtable
43
target/arm: Consolidate cpreg updates in add_cpreg_to_hashtable
44
target/arm: Use bool for is64 and ns in add_cpreg_to_hashtable
45
target/arm: Hoist isbanked computation in add_cpreg_to_hashtable
46
target/arm: Perform override check early in add_cpreg_to_hashtable
47
target/arm: Reformat comments in add_cpreg_to_hashtable
48
target/arm: Remove HOST_BIG_ENDIAN ifdef in add_cpreg_to_hashtable
49
target/arm: Add isar predicates for FEAT_Debugv8p2
50
target/arm: Add isar_feature_{aa64,any}_ras
51
55
52
target/arm/cpregs.h | 453 ++++++++++++++++++++++++++++++++++++++
56
Matthew R. Ochs (1):
53
target/arm/cpu.h | 393 +++------------------------------
57
hw/arm/virt: Support larger highmem MMIO regions
54
hw/arm/pxa2xx.c | 2 +-
58
55
hw/arm/pxa2xx_pic.c | 2 +-
59
Nicolin Chen (1):
56
hw/intc/arm_gicv3_cpuif.c | 6 +-
60
hw/arm/smmuv3: Fill u.f_cd_fetch.addr for SMMU_EVT_F_CD_FETCH
57
hw/intc/arm_gicv3_kvm.c | 3 +-
61
58
target/arm/cpu.c | 25 +--
62
Peter Maydell (22):
59
target/arm/cpu64.c | 2 +-
63
monitor/hmp-cmds.c: Clean up hmp_dumpdtb printf
60
target/arm/cpu_tcg.c | 5 +-
64
hw/openrisc: Support monitor dumpdtb command
61
target/arm/gdbstub.c | 5 +-
65
hw/mips/boston: Check for error return from boston_fdt_filter()
62
target/arm/helper.c | 358 +++++++++++++-----------------
66
hw/mips/boston: Support dumpdtb monitor commands
63
target/arm/hvf/hvf.c | 2 +-
67
hw: Centralize handling of -machine dumpdtb option
64
target/arm/kvm-stub.c | 4 +-
68
hw/core/machine.c: Make -machine dumpdtb=file.dtb with no DTB an error
65
target/arm/kvm.c | 4 +-
69
fpu: Make targets specify floatx80 default Inf at runtime
66
target/arm/machine.c | 4 +-
70
target/m68k: Avoid using floatx80_infinity global const
67
target/arm/op_helper.c | 57 ++---
71
target/i386: Avoid using floatx80_infinity global const
68
target/arm/translate-a64.c | 14 +-
72
fpu: Pass float_status to floatx80_is_infinity()
69
target/arm/translate-neon.c | 2 +-
73
fpu: Make targets specify whether floatx80 Inf can have Int bit clear
70
target/arm/translate.c | 13 +-
74
fpu: Pass float_status to floatx80_invalid_encoding()
71
tests/tcg/aarch64/bti-3.c | 42 ++++
75
fpu: Make floatx80 invalid encoding settable at runtime
72
tests/tcg/aarch64/Makefile.target | 6 +-
76
fpu: Move m68k_denormal fmt flag into floatx80_behaviour
73
21 files changed, 738 insertions(+), 664 deletions(-)
77
fpu: Always decide no_signaling_nans() at runtime
74
create mode 100644 target/arm/cpregs.h
78
fpu: Always decide snan_bit_is_one() at runtime
75
create mode 100644 tests/tcg/aarch64/bti-3.c
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
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
New patch
1
In hmp_dumpdtb(), we print a message when the command succeeds. This
2
message is missing the trailing \n, so the HMP command prompt is
3
printed immediately after it. We also weren't capitalizing 'DTB', or
4
quoting the filename in the message. Fix these nits.
1
5
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
9
Message-id: 20250206151214.2947842-2-peter.maydell@linaro.org
10
---
11
monitor/hmp-cmds.c | 2 +-
12
1 file changed, 1 insertion(+), 1 deletion(-)
13
14
diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/monitor/hmp-cmds.c
17
+++ b/monitor/hmp-cmds.c
18
@@ -XXX,XX +XXX,XX @@ void hmp_dumpdtb(Monitor *mon, const QDict *qdict)
19
return;
20
}
21
22
- monitor_printf(mon, "dtb dumped to %s", filename);
23
+ monitor_printf(mon, "DTB dumped to '%s'\n", filename);
24
}
25
#endif
26
--
27
2.43.0
28
29
diff view generated by jsdifflib
New patch
1
The openrisc machines don't set MachineState::fdt to point to their
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".
1
6
7
Set MachineState::fdt in openrisc_load_fdt(), when we write it to
8
guest memory.
9
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
12
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
13
Message-id: 20250206151214.2947842-3-peter.maydell@linaro.org
14
---
15
include/hw/openrisc/boot.h | 3 ++-
16
hw/openrisc/boot.c | 7 +++++--
17
hw/openrisc/openrisc_sim.c | 2 +-
18
hw/openrisc/virt.c | 2 +-
19
4 files changed, 9 insertions(+), 5 deletions(-)
20
21
diff --git a/include/hw/openrisc/boot.h b/include/hw/openrisc/boot.h
22
index XXXXXXX..XXXXXXX 100644
23
--- a/include/hw/openrisc/boot.h
24
+++ b/include/hw/openrisc/boot.h
25
@@ -XXX,XX +XXX,XX @@
26
#define OPENRISC_BOOT_H
27
28
#include "exec/cpu-defs.h"
29
+#include "hw/boards.h"
30
31
hwaddr openrisc_load_kernel(ram_addr_t ram_size,
32
const char *kernel_filename,
33
@@ -XXX,XX +XXX,XX @@ hwaddr openrisc_load_kernel(ram_addr_t ram_size,
34
hwaddr openrisc_load_initrd(void *fdt, const char *filename,
35
hwaddr load_start, uint64_t mem_size);
36
37
-uint32_t openrisc_load_fdt(void *fdt, hwaddr load_start,
38
+uint32_t openrisc_load_fdt(MachineState *ms, void *fdt, hwaddr load_start,
39
uint64_t mem_size);
40
41
#endif /* OPENRISC_BOOT_H */
42
diff --git a/hw/openrisc/boot.c b/hw/openrisc/boot.c
43
index XXXXXXX..XXXXXXX 100644
44
--- a/hw/openrisc/boot.c
45
+++ b/hw/openrisc/boot.c
46
@@ -XXX,XX +XXX,XX @@ hwaddr openrisc_load_initrd(void *fdt, const char *filename,
47
return start + size;
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;
63
+
64
rom_add_blob_fixed_as("fdt", fdt, fdtsize, fdt_addr,
65
&address_space_memory);
66
qemu_register_reset_nosnapshotload(qemu_fdt_randomize_seeds,
67
diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c
68
index XXXXXXX..XXXXXXX 100644
69
--- a/hw/openrisc/openrisc_sim.c
70
+++ b/hw/openrisc/openrisc_sim.c
71
@@ -XXX,XX +XXX,XX @@ static void openrisc_sim_init(MachineState *machine)
72
machine->initrd_filename,
73
load_addr, machine->ram_size);
74
}
75
- boot_info.fdt_addr = openrisc_load_fdt(state->fdt, load_addr,
76
+ boot_info.fdt_addr = openrisc_load_fdt(machine, state->fdt, load_addr,
77
machine->ram_size);
78
}
79
}
80
diff --git a/hw/openrisc/virt.c b/hw/openrisc/virt.c
81
index XXXXXXX..XXXXXXX 100644
82
--- a/hw/openrisc/virt.c
83
+++ b/hw/openrisc/virt.c
84
@@ -XXX,XX +XXX,XX @@ static void openrisc_virt_init(MachineState *machine)
85
machine->initrd_filename,
86
load_addr, machine->ram_size);
87
}
88
- boot_info.fdt_addr = openrisc_load_fdt(state->fdt, load_addr,
89
+ boot_info.fdt_addr = openrisc_load_fdt(machine, state->fdt, load_addr,
90
machine->ram_size);
91
}
92
}
93
--
94
2.43.0
95
96
diff view generated by jsdifflib
New patch
1
The function boston_fdt_filter() can return NULL on errors (in which
2
case it will print an error message). When we call this from the
3
non-FIT-image codepath, we aren't checking the return value, so we
4
will plough on with a NULL pointer, and segfault in fdt_totalsize().
5
Check for errors here.
1
6
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
9
Message-id: 20250206151214.2947842-4-peter.maydell@linaro.org
10
---
11
hw/mips/boston.c | 4 ++++
12
1 file changed, 4 insertions(+)
13
14
diff --git a/hw/mips/boston.c b/hw/mips/boston.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/mips/boston.c
17
+++ b/hw/mips/boston.c
18
@@ -XXX,XX +XXX,XX @@ static void boston_mach_init(MachineState *machine)
19
20
dtb_load_data = boston_fdt_filter(s, dtb_file_data,
21
NULL, &dtb_vaddr);
22
+ if (!dtb_load_data) {
23
+ /* boston_fdt_filter() already printed the error for us */
24
+ exit(1);
25
+ }
26
27
/* Calculate real fdt size after filter */
28
dt_size = fdt_totalsize(dtb_load_data);
29
--
30
2.43.0
31
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
From: Richard Henderson <richard.henderson@linaro.org>
1
Currently we handle the 'dumpdtb' machine sub-option ad-hoc in every
2
2
board model that has an FDT. It's up to the board code to make sure
3
Simplify freeing cp_regs hash table entries by using a single
3
it calls qemu_fdt_dumpdtb() in the right place.
4
allocation for the entire value.
4
5
5
This means we're inconsistent and often just ignore the user's
6
This fixes a theoretical bug if we were to ever free the entire
6
command line argument:
7
hash table, because we've been installing string literal constants
7
* if the board doesn't have an FDT at all
8
into the cpreg structure in define_arm_vh_e2h_redirects_aliases.
8
* if the board supports FDT, but there happens not to be one
9
However, at present we only free entries created for AArch32
9
present (usually because of a missing -fdt option)
10
wildcard cpregs which get overwritten by more specific cpregs,
10
11
so this bug is never exposed.
11
This isn't very helpful because it gives the user no clue why their
12
12
option was ignored.
13
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
13
14
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
14
However, in order to support the QMP/HMP dumpdtb commands we require
15
Message-id: 20220501055028.646596-13-richard.henderson@linaro.org
15
now that every FDT machine stores a pointer to the FDT in
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.
23
16
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
24
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
25
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
17
---
26
---
18
target/arm/cpu.c | 16 +---------------
27
include/system/device_tree.h | 2 --
19
target/arm/helper.c | 10 ++++++++--
28
hw/arm/boot.c | 2 --
20
2 files changed, 9 insertions(+), 17 deletions(-)
29
hw/core/machine.c | 25 +++++++++++++++++++++++++
21
30
hw/loongarch/virt-fdt-build.c | 1 -
22
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
31
hw/mips/boston.c | 1 -
23
index XXXXXXX..XXXXXXX 100644
32
hw/openrisc/boot.c | 1 -
24
--- a/target/arm/cpu.c
33
hw/ppc/e500.c | 1 -
25
+++ b/target/arm/cpu.c
34
hw/ppc/pegasos2.c | 1 -
26
@@ -XXX,XX +XXX,XX @@ uint64_t arm_cpu_mp_affinity(int idx, uint8_t clustersz)
35
hw/ppc/pnv.c | 1 -
27
return (Aff1 << ARM_AFF1_SHIFT) | Aff0;
36
hw/ppc/spapr.c | 1 -
37
hw/riscv/boot.c | 2 --
38
system/device_tree.c | 15 ---------------
39
12 files changed, 25 insertions(+), 28 deletions(-)
40
41
diff --git a/include/system/device_tree.h b/include/system/device_tree.h
42
index XXXXXXX..XXXXXXX 100644
43
--- a/include/system/device_tree.h
44
+++ b/include/system/device_tree.h
45
@@ -XXX,XX +XXX,XX @@ int qemu_fdt_add_path(void *fdt, const char *path);
46
sizeof(qdt_tmp)); \
47
} while (0)
48
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);
60
}
61
62
- qemu_fdt_dumpdtb(fdt, size);
63
-
64
/* Put the DTB into the memory map as a ROM image: this will ensure
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);
28
}
81
}
29
82
30
-static void cpreg_hashtable_data_destroy(gpointer data)
83
+static void handle_machine_dumpdtb(MachineState *ms)
84
+{
85
+ if (!ms->dumpdtb) {
86
+ return;
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
99
+}
100
+
101
void qdev_machine_creation_done(void)
102
{
103
cpu_synchronize_all_post_init();
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.
111
+ */
112
+ handle_machine_dumpdtb(current_machine);
113
+
114
/* TODO: once all bus devices are qdevified, this should be done
115
* when bus is created by qdev.c */
116
/*
117
diff --git a/hw/loongarch/virt-fdt-build.c b/hw/loongarch/virt-fdt-build.c
118
index XXXXXXX..XXXXXXX 100644
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)));
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;
220
}
221
222
-void qemu_fdt_dumpdtb(void *fdt, int size)
31
-{
223
-{
32
- /*
224
- const char *dumpdtb = current_machine->dumpdtb;
33
- * Destroy function for cpu->cp_regs hashtable data entries.
225
-
34
- * We must free the name string because it was g_strdup()ed in
226
- if (dumpdtb) {
35
- * add_cpreg_to_hashtable(). It's OK to cast away the 'const'
227
- /* Dump the dtb to a file and quit */
36
- * from r->name because we know we definitely allocated it.
228
- if (g_file_set_contents(dumpdtb, fdt, size, NULL)) {
37
- */
229
- info_report("dtb dumped to %s. Exiting.", dumpdtb);
38
- ARMCPRegInfo *r = data;
230
- exit(0);
39
-
231
- }
40
- g_free((void *)r->name);
232
- error_report("%s: Failed dumping dtb to %s", __func__, dumpdtb);
41
- g_free(r);
233
- exit(1);
234
- }
42
-}
235
-}
43
-
236
-
44
static void arm_cpu_initfn(Object *obj)
237
int qemu_fdt_setprop_sized_cells_from_array(void *fdt,
45
{
238
const char *node_path,
46
ARMCPU *cpu = ARM_CPU(obj);
239
const char *property,
47
48
cpu_set_cpustate_pointers(cpu);
49
cpu->cp_regs = g_hash_table_new_full(g_direct_hash, g_direct_equal,
50
- NULL, cpreg_hashtable_data_destroy);
51
+ NULL, g_free);
52
53
QLIST_INIT(&cpu->pre_el_change_hooks);
54
QLIST_INIT(&cpu->el_change_hooks);
55
diff --git a/target/arm/helper.c b/target/arm/helper.c
56
index XXXXXXX..XXXXXXX 100644
57
--- a/target/arm/helper.c
58
+++ b/target/arm/helper.c
59
@@ -XXX,XX +XXX,XX @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
60
* add a single reginfo struct to the hash table.
61
*/
62
uint32_t key;
63
- ARMCPRegInfo *r2 = g_memdup(r, sizeof(ARMCPRegInfo));
64
+ ARMCPRegInfo *r2;
65
int is64 = (r->type & ARM_CP_64BIT) ? 1 : 0;
66
int ns = (secstate & ARM_CP_SECSTATE_NS) ? 1 : 0;
67
+ size_t name_len;
68
+
69
+ /* Combine cpreg and name into one allocation. */
70
+ name_len = strlen(name) + 1;
71
+ r2 = g_malloc(sizeof(*r2) + name_len);
72
+ *r2 = *r;
73
+ r2->name = memcpy(r2 + 1, name, name_len);
74
75
- r2->name = g_strdup(name);
76
/* Reset the secure state to the specific incoming state. This is
77
* necessary as the register may have been defined with both states.
78
*/
79
--
240
--
80
2.25.1
241
2.43.0
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
From: Richard Henderson <richard.henderson@linaro.org>
1
Currently we hardcode at compile time whether the floatx80 default
2
Infinity value has the explicit integer bit set or not (x86 sets it;
3
m68k does not). To be able to compile softfloat once for all targets
4
we'd like to move this setting to runtime.
2
5
3
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
6
Define a new FloatX80Behaviour enum which is a set of flags that
4
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
define the target's floatx80 handling. Initially we define just one
5
Message-id: 20220501055028.646596-24-richard.henderson@linaro.org
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.
32
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
33
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
34
Reviewed-by: Richard Henderson <richard.henderson@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
7
---
38
---
8
target/arm/cpu.h | 15 +++++++++++++++
39
include/fpu/softfloat-helpers.h | 12 ++++++++++++
9
1 file changed, 15 insertions(+)
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(-)
10
46
11
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
12
index XXXXXXX..XXXXXXX 100644
48
index XXXXXXX..XXXXXXX 100644
13
--- a/target/arm/cpu.h
49
--- a/include/fpu/softfloat-helpers.h
14
+++ b/target/arm/cpu.h
50
+++ b/include/fpu/softfloat-helpers.h
15
@@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa32_ssbs(const ARMISARegisters *id)
51
@@ -XXX,XX +XXX,XX @@ static inline void set_floatx80_rounding_precision(FloatX80RoundPrec val,
16
return FIELD_EX32(id->id_pfr2, ID_PFR2, SSBS) != 0;
52
status->floatx80_rounding_precision = val;
17
}
53
}
18
54
19
+static inline bool isar_feature_aa32_debugv8p2(const ARMISARegisters *id)
55
+static inline void set_floatx80_behaviour(FloatX80Behaviour b,
56
+ float_status *status)
20
+{
57
+{
21
+ return FIELD_EX32(id->id_dfr0, ID_DFR0, COPDBG) >= 8;
58
+ status->floatx80_behaviour = b;
22
+}
59
+}
23
+
60
+
24
/*
61
static inline void set_float_2nan_prop_rule(Float2NaNPropRule rule,
25
* 64-bit feature tests via id registers.
62
float_status *status)
26
*/
63
{
27
@@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_ssbs(const ARMISARegisters *id)
64
@@ -XXX,XX +XXX,XX @@ get_floatx80_rounding_precision(const float_status *status)
28
return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, SSBS) != 0;
65
return status->floatx80_rounding_precision;
29
}
66
}
30
67
31
+static inline bool isar_feature_aa64_debugv8p2(const ARMISARegisters *id)
68
+static inline FloatX80Behaviour
69
+get_floatx80_behaviour(const float_status *status)
32
+{
70
+{
33
+ return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, DEBUGVER) >= 8;
71
+ return status->floatx80_behaviour;
34
+}
72
+}
35
+
73
+
36
static inline bool isar_feature_aa64_sve2(const ARMISARegisters *id)
74
static inline Float2NaNPropRule
75
get_float_2nan_prop_rule(const float_status *status)
37
{
76
{
38
return FIELD_EX64(id->id_aa64zfr0, ID_AA64ZFR0, SVEVER) != 0;
77
diff --git a/include/fpu/softfloat-types.h b/include/fpu/softfloat-types.h
39
@@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_any_tts2uxn(const ARMISARegisters *id)
78
index XXXXXXX..XXXXXXX 100644
40
return isar_feature_aa64_tts2uxn(id) || isar_feature_aa32_tts2uxn(id);
79
--- a/include/fpu/softfloat-types.h
41
}
80
+++ b/include/fpu/softfloat-types.h
42
81
@@ -XXX,XX +XXX,XX @@ typedef enum __attribute__((__packed__)) {
43
+static inline bool isar_feature_any_debugv8p2(const ARMISARegisters *id)
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)
44
+{
171
+{
45
+ return isar_feature_aa64_debugv8p2(id) || isar_feature_aa32_debugv8p2(id);
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));
46
+}
178
+}
47
+
179
+
48
/*
180
#define floatx80_infinity_high 0x7FFF
49
* Forward to the above feature tests given an ARMCPU pointer.
181
#if defined(TARGET_M68K)
50
*/
182
#define floatx80_infinity_low UINT64_C(0x0000000000000000)
51
--
183
--
52
2.25.1
184
2.43.0
185
186
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
The global const floatx80_infinity is (unlike all the other
2
float*_infinity values) target-specific, because whether the explicit
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.
2
7
3
Rearrange the values of the enumerators of CPAccessResult
8
Replace the direct uses of floatx80_infinity in target/m68k with
4
so that we may directly extract the target el. For the two
9
calls to the new floatx80_default_inf() function.
5
special cases in access_check_cp_reg, use CPAccessResult.
6
10
7
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
10
Message-id: 20220501055028.646596-3-richard.henderson@linaro.org
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
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
12
---
16
---
13
target/arm/cpregs.h | 26 ++++++++++++--------
17
target/m68k/softfloat.c | 47 ++++++++++++++---------------------------
14
target/arm/op_helper.c | 56 +++++++++++++++++++++---------------------
18
1 file changed, 16 insertions(+), 31 deletions(-)
15
2 files changed, 44 insertions(+), 38 deletions(-)
16
19
17
diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
20
diff --git a/target/m68k/softfloat.c b/target/m68k/softfloat.c
18
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
19
--- a/target/arm/cpregs.h
22
--- a/target/m68k/softfloat.c
20
+++ b/target/arm/cpregs.h
23
+++ b/target/m68k/softfloat.c
21
@@ -XXX,XX +XXX,XX @@ static inline bool cptype_valid(int cptype)
24
@@ -XXX,XX +XXX,XX @@ floatx80 floatx80_scale(floatx80 a, floatx80 b, float_status *status)
22
typedef enum CPAccessResult {
25
if ((uint64_t) (aSig << 1)) {
23
/* Access is permitted */
26
return propagateFloatx80NaN(a, b, status);
24
CP_ACCESS_OK = 0,
27
}
25
+
28
- return packFloatx80(aSign, floatx80_infinity.high,
26
+ /*
29
- floatx80_infinity.low);
27
+ * Combined with one of the following, the low 2 bits indicate the
30
+ return floatx80_default_inf(aSign, status);
28
+ * target exception level. If 0, the exception is taken to the usual
29
+ * target EL (EL1 or PL1 if in EL0, otherwise to the current EL).
30
+ */
31
+ CP_ACCESS_EL_MASK = 3,
32
+
33
/*
34
* Access fails due to a configurable trap or enable which would
35
* result in a categorized exception syndrome giving information about
36
* the failing instruction (ie syndrome category 0x3, 0x4, 0x5, 0x6,
37
- * 0xc or 0x18). The exception is taken to the usual target EL (EL1 or
38
- * PL1 if in EL0, otherwise to the current EL).
39
+ * 0xc or 0x18).
40
*/
41
- CP_ACCESS_TRAP = 1,
42
+ CP_ACCESS_TRAP = (1 << 2),
43
+ CP_ACCESS_TRAP_EL2 = CP_ACCESS_TRAP | 2,
44
+ CP_ACCESS_TRAP_EL3 = CP_ACCESS_TRAP | 3,
45
+
46
/*
47
* Access fails and results in an exception syndrome 0x0 ("uncategorized").
48
* Note that this is not a catch-all case -- the set of cases which may
49
* result in this failure is specifically defined by the architecture.
50
*/
51
- CP_ACCESS_TRAP_UNCATEGORIZED = 2,
52
- /* As CP_ACCESS_TRAP, but for traps directly to EL2 or EL3 */
53
- CP_ACCESS_TRAP_EL2 = 3,
54
- CP_ACCESS_TRAP_EL3 = 4,
55
- /* As CP_ACCESS_UNCATEGORIZED, but for traps directly to EL2 or EL3 */
56
- CP_ACCESS_TRAP_UNCATEGORIZED_EL2 = 5,
57
- CP_ACCESS_TRAP_UNCATEGORIZED_EL3 = 6,
58
+ CP_ACCESS_TRAP_UNCATEGORIZED = (2 << 2),
59
+ CP_ACCESS_TRAP_UNCATEGORIZED_EL2 = CP_ACCESS_TRAP_UNCATEGORIZED | 2,
60
+ CP_ACCESS_TRAP_UNCATEGORIZED_EL3 = CP_ACCESS_TRAP_UNCATEGORIZED | 3,
61
} CPAccessResult;
62
63
typedef struct ARMCPRegInfo ARMCPRegInfo;
64
diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c
65
index XXXXXXX..XXXXXXX 100644
66
--- a/target/arm/op_helper.c
67
+++ b/target/arm/op_helper.c
68
@@ -XXX,XX +XXX,XX @@ void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome,
69
uint32_t isread)
70
{
71
const ARMCPRegInfo *ri = rip;
72
+ CPAccessResult res = CP_ACCESS_OK;
73
int target_el;
74
75
if (arm_feature(env, ARM_FEATURE_XSCALE) && ri->cp < 14
76
&& extract32(env->cp15.c15_cpar, ri->cp, 1) == 0) {
77
- raise_exception(env, EXCP_UDEF, syndrome, exception_target_el(env));
78
+ res = CP_ACCESS_TRAP;
79
+ goto fail;
80
}
31
}
81
32
if (aExp == 0) {
82
/*
33
if (aSig == 0) {
83
@@ -XXX,XX +XXX,XX @@ void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome,
34
@@ -XXX,XX +XXX,XX @@ floatx80 floatx80_lognp1(floatx80 a, float_status *status)
84
mask &= ~((1 << 4) | (1 << 14));
35
float_raise(float_flag_invalid, status);
85
36
return floatx80_default_nan(status);
86
if (env->cp15.hstr_el2 & mask) {
37
}
87
- target_el = 2;
38
- return packFloatx80(0, floatx80_infinity.high, floatx80_infinity.low);
88
- goto exept;
39
+ return floatx80_default_inf(0, status);
89
+ res = CP_ACCESS_TRAP_EL2;
40
}
90
+ goto fail;
41
42
if (aExp == 0 && aSig == 0) {
43
@@ -XXX,XX +XXX,XX @@ floatx80 floatx80_lognp1(floatx80 a, float_status *status)
44
if (aSign && aExp >= one_exp) {
45
if (aExp == one_exp && aSig == one_sig) {
46
float_raise(float_flag_divbyzero, status);
47
- return packFloatx80(aSign, floatx80_infinity.high,
48
- floatx80_infinity.low);
49
+ return floatx80_default_inf(aSign, status);
50
}
51
float_raise(float_flag_invalid, status);
52
return floatx80_default_nan(status);
53
@@ -XXX,XX +XXX,XX @@ floatx80 floatx80_logn(floatx80 a, float_status *status)
54
propagateFloatx80NaNOneArg(a, status);
55
}
56
if (aSign == 0) {
57
- return packFloatx80(0, floatx80_infinity.high,
58
- floatx80_infinity.low);
59
+ return floatx80_default_inf(0, status);
91
}
60
}
92
}
61
}
93
62
94
- if (!ri->accessfn) {
63
@@ -XXX,XX +XXX,XX @@ floatx80 floatx80_logn(floatx80 a, float_status *status)
95
+ if (ri->accessfn) {
64
if (aExp == 0) {
96
+ res = ri->accessfn(env, ri, isread);
65
if (aSig == 0) { /* zero */
97
+ }
66
float_raise(float_flag_divbyzero, status);
98
+ if (likely(res == CP_ACCESS_OK)) {
67
- return packFloatx80(1, floatx80_infinity.high,
99
return;
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
}
100
}
81
}
101
82
102
- switch (ri->accessfn(env, ri, isread)) {
83
if (aExp == 0 && aSig == 0) {
103
- case CP_ACCESS_OK:
84
float_raise(float_flag_divbyzero, status);
104
- return;
85
- return packFloatx80(1, floatx80_infinity.high,
105
+ fail:
86
- floatx80_infinity.low);
106
+ switch (res & ~CP_ACCESS_EL_MASK) {
87
+ return floatx80_default_inf(1, status);
107
case CP_ACCESS_TRAP:
108
- target_el = exception_target_el(env);
109
- break;
110
- case CP_ACCESS_TRAP_EL2:
111
- /* Requesting a trap to EL2 when we're in EL3 is
112
- * a bug in the access function.
113
- */
114
- assert(arm_current_el(env) != 3);
115
- target_el = 2;
116
- break;
117
- case CP_ACCESS_TRAP_EL3:
118
- target_el = 3;
119
break;
120
case CP_ACCESS_TRAP_UNCATEGORIZED:
121
- target_el = exception_target_el(env);
122
- syndrome = syn_uncategorized();
123
- break;
124
- case CP_ACCESS_TRAP_UNCATEGORIZED_EL2:
125
- target_el = 2;
126
- syndrome = syn_uncategorized();
127
- break;
128
- case CP_ACCESS_TRAP_UNCATEGORIZED_EL3:
129
- target_el = 3;
130
syndrome = syn_uncategorized();
131
break;
132
default:
133
g_assert_not_reached();
134
}
88
}
135
89
136
-exept:
90
if (aSign) {
137
+ target_el = res & CP_ACCESS_EL_MASK;
91
@@ -XXX,XX +XXX,XX @@ floatx80 floatx80_log2(floatx80 a, float_status *status)
138
+ switch (target_el) {
92
propagateFloatx80NaNOneArg(a, status);
139
+ case 0:
93
}
140
+ target_el = exception_target_el(env);
94
if (aSign == 0) {
141
+ break;
95
- return packFloatx80(0, floatx80_infinity.high,
142
+ case 2:
96
- floatx80_infinity.low);
143
+ assert(arm_current_el(env) != 3);
97
+ return floatx80_default_inf(0, status);
144
+ assert(arm_is_el2_enabled(env));
98
}
145
+ break;
99
}
146
+ case 3:
100
147
+ assert(arm_feature(env, ARM_FEATURE_EL3));
101
if (aExp == 0) {
148
+ break;
102
if (aSig == 0) {
149
+ default:
103
float_raise(float_flag_divbyzero, status);
150
+ /* No "direct" traps to EL1 */
104
- return packFloatx80(1, floatx80_infinity.high,
151
+ g_assert_not_reached();
105
- floatx80_infinity.low);
152
+ }
106
+ return floatx80_default_inf(1, status);
153
+
107
}
154
raise_exception(env, EXCP_UDEF, syndrome, target_el);
108
normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
155
}
109
}
156
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) {
157
--
180
--
158
2.25.1
181
2.43.0
159
182
160
183
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
The global const floatx80_infinity is (unlike all the other
2
float*_infinity values) target-specific, because whether the explicit
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.
2
7
3
These particular data structures are not modified at runtime.
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.
4
13
5
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20220501055028.646596-5-richard.henderson@linaro.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Reviewed-by: Richard Henderson <richard.henderson@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
10
---
19
---
11
target/arm/helper.c | 16 ++++++++--------
20
target/i386/tcg/fpu_helper.c | 7 +++----
12
1 file changed, 8 insertions(+), 8 deletions(-)
21
1 file changed, 3 insertions(+), 4 deletions(-)
13
22
14
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
15
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
16
--- a/target/arm/helper.c
25
--- a/target/i386/tcg/fpu_helper.c
17
+++ b/target/arm/helper.c
26
+++ b/target/i386/tcg/fpu_helper.c
18
@@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu)
27
@@ -XXX,XX +XXX,XX @@ void helper_fxtract(CPUX86State *env)
19
.resetvalue = cpu->pmceid1 },
28
} else if (floatx80_is_infinity(ST0)) {
20
};
29
fpush(env);
21
#ifdef CONFIG_USER_ONLY
30
ST0 = ST1;
22
- ARMCPRegUserSpaceInfo v8_user_idregs[] = {
31
- ST1 = floatx80_infinity;
23
+ static const ARMCPRegUserSpaceInfo v8_user_idregs[] = {
32
+ ST1 = floatx80_default_inf(0, &env->fp_status);
24
{ .name = "ID_AA64PFR0_EL1",
33
} else {
25
.exported_bits = 0x000f000f00ff0000,
34
int expdif;
26
.fixed_bits = 0x0000000000000011 },
35
27
@@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu)
36
@@ -XXX,XX +XXX,XX @@ void helper_fscale(CPUX86State *env)
28
*/
37
float_raise(float_flag_invalid, &env->fp_status);
29
if (arm_feature(env, ARM_FEATURE_EL3)) {
38
ST0 = floatx80_default_nan(&env->fp_status);
30
if (arm_feature(env, ARM_FEATURE_AARCH64)) {
39
} else {
31
- ARMCPRegInfo nsacr = {
40
- ST0 = (floatx80_is_neg(ST0) ?
32
+ static const ARMCPRegInfo nsacr = {
41
- floatx80_chs(floatx80_infinity) :
33
.name = "NSACR", .type = ARM_CP_CONST,
42
- floatx80_infinity);
34
.cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 2,
43
+ ST0 = floatx80_default_inf(floatx80_is_neg(ST0),
35
.access = PL1_RW, .accessfn = nsacr_access,
44
+ &env->fp_status);
36
@@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu)
45
}
37
};
38
define_one_arm_cp_reg(cpu, &nsacr);
39
} else {
40
- ARMCPRegInfo nsacr = {
41
+ static const ARMCPRegInfo nsacr = {
42
.name = "NSACR",
43
.cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 2,
44
.access = PL3_RW | PL1_R,
45
@@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu)
46
}
46
}
47
} else {
47
} else {
48
if (arm_feature(env, ARM_FEATURE_V8)) {
49
- ARMCPRegInfo nsacr = {
50
+ static const ARMCPRegInfo nsacr = {
51
.name = "NSACR", .type = ARM_CP_CONST,
52
.cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 2,
53
.access = PL1_R,
54
@@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu)
55
.access = PL1_R, .type = ARM_CP_CONST,
56
.resetvalue = cpu->pmsav7_dregion << 8
57
};
58
- ARMCPRegInfo crn0_wi_reginfo = {
59
+ static const ARMCPRegInfo crn0_wi_reginfo = {
60
.name = "CRN0_WI", .cp = 15, .crn = 0, .crm = CP_ANY,
61
.opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_W,
62
.type = ARM_CP_NOP | ARM_CP_OVERRIDE
63
};
64
#ifdef CONFIG_USER_ONLY
65
- ARMCPRegUserSpaceInfo id_v8_user_midr_cp_reginfo[] = {
66
+ static const ARMCPRegUserSpaceInfo id_v8_user_midr_cp_reginfo[] = {
67
{ .name = "MIDR_EL1",
68
.exported_bits = 0x00000000ffffffff },
69
{ .name = "REVIDR_EL1" },
70
@@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu)
71
.access = PL1_R, .readfn = mpidr_read, .type = ARM_CP_NO_RAW },
72
};
73
#ifdef CONFIG_USER_ONLY
74
- ARMCPRegUserSpaceInfo mpidr_user_cp_reginfo[] = {
75
+ static const ARMCPRegUserSpaceInfo mpidr_user_cp_reginfo[] = {
76
{ .name = "MPIDR_EL1",
77
.fixed_bits = 0x0000000080000000 },
78
};
79
@@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu)
80
}
81
82
if (arm_feature(env, ARM_FEATURE_VBAR)) {
83
- ARMCPRegInfo vbar_cp_reginfo[] = {
84
+ static const ARMCPRegInfo vbar_cp_reginfo[] = {
85
{ .name = "VBAR", .state = ARM_CP_STATE_BOTH,
86
.opc0 = 3, .crn = 12, .crm = 0, .opc1 = 0, .opc2 = 0,
87
.access = PL1_RW, .writefn = vbar_write,
88
--
48
--
89
2.25.1
49
2.43.0
90
50
91
51
diff view generated by jsdifflib
New patch
1
Unlike the other float formats, whether a floatx80 value is
2
considered to be an Infinity is target-dependent. (On x86 if the
3
explicit integer bit is clear this is a "pseudo-infinity" and not a
4
valid infinity; m68k does not care about the value of the integer
5
bit.)
1
6
7
Currently we select this target-specific logic at compile time with
8
an ifdef. We're going to want to do this at runtime, so change the
9
floatx80_is_infinity() function to take a float_status.
10
11
This commit doesn't change any logic; we'll do that in the
12
next commit.
13
14
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
16
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
17
Message-id: 20250224111524.1101196-5-peter.maydell@linaro.org
18
---
19
include/fpu/softfloat.h | 2 +-
20
target/i386/tcg/fpu_helper.c | 20 +++++++++++---------
21
target/m68k/fpu_helper.c | 2 +-
22
3 files changed, 13 insertions(+), 11 deletions(-)
23
24
diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h
25
index XXXXXXX..XXXXXXX 100644
26
--- a/include/fpu/softfloat.h
27
+++ b/include/fpu/softfloat.h
28
@@ -XXX,XX +XXX,XX @@ static inline floatx80 floatx80_chs(floatx80 a)
29
return a;
30
}
31
32
-static inline bool floatx80_is_infinity(floatx80 a)
33
+static inline bool floatx80_is_infinity(floatx80 a, float_status *status)
34
{
35
#if defined(TARGET_M68K)
36
return (a.high & 0x7fff) == floatx80_infinity.high && !(a.low << 1);
37
diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c
38
index XXXXXXX..XXXXXXX 100644
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;
126
--
127
2.43.0
128
129
diff view generated by jsdifflib
New patch
1
In Intel terminology, a floatx80 Infinity with the explicit integer
2
bit clear is a "pseudo-infinity"; for x86 these are not valid
3
infinity values. m68k is looser and does not care whether the
4
Integer bit is set or clear in an infinity.
1
5
6
Move this setting to runtime rather than using an ifdef in
7
floatx80_is_infinity().
8
9
Since this was the last use of the floatx80_infinity global constant,
10
we remove it and its definition here.
11
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
Reviewed-by: Richard Henderson <richard.henderson@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
17
---
18
include/fpu/softfloat-types.h | 5 +++++
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(-)
23
24
diff --git a/include/fpu/softfloat-types.h b/include/fpu/softfloat-types.h
25
index XXXXXXX..XXXXXXX 100644
26
--- a/include/fpu/softfloat-types.h
27
+++ b/include/fpu/softfloat-types.h
28
@@ -XXX,XX +XXX,XX @@ typedef enum __attribute__((__packed__)) {
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);
73
}
74
75
static inline bool floatx80_is_neg(floatx80 a)
76
diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c
77
index XXXXXXX..XXXXXXX 100644
78
--- a/target/m68k/cpu.c
79
+++ b/target/m68k/cpu.c
80
@@ -XXX,XX +XXX,XX @@ static void m68k_cpu_reset_hold(Object *obj, ResetType type)
81
/*
82
* m68k-specific floatx80 behaviour:
83
* * default Infinity values have a zero Integer bit
84
+ * * input Infinities may have the Integer bit either 0 or 1
85
*/
86
- set_floatx80_behaviour(floatx80_default_inf_int_bit_is_zero,
87
+ set_floatx80_behaviour(floatx80_default_inf_int_bit_is_zero |
88
+ floatx80_pseudo_inf_valid,
89
&env->fp_status);
90
91
nan = floatx80_default_nan(&env->fp_status);
92
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
93
index XXXXXXX..XXXXXXX 100644
94
--- a/fpu/softfloat-specialize.c.inc
95
+++ b/fpu/softfloat-specialize.c.inc
96
@@ -XXX,XX +XXX,XX @@ floatx80 floatx80_default_inf(bool zSign, float_status *status)
97
return packFloatx80(zSign, 0x7fff, z ? 0 : (1ULL << 63));
98
}
99
100
-#define floatx80_infinity_high 0x7FFF
101
-#if defined(TARGET_M68K)
102
-#define floatx80_infinity_low UINT64_C(0x0000000000000000)
103
-#else
104
-#define floatx80_infinity_low UINT64_C(0x8000000000000000)
105
-#endif
106
-
107
-const floatx80 floatx80_infinity
108
- = make_floatx80_init(floatx80_infinity_high, floatx80_infinity_low);
109
-
110
/*----------------------------------------------------------------------------
111
| Returns 1 if the half-precision floating-point value `a' is a quiet
112
| NaN; otherwise returns 0.
113
--
114
2.43.0
115
116
diff view generated by jsdifflib
New patch
1
The definition of which floatx80 encodings are invalid is
2
target-specific. Currently we handle this with an ifdef, but we
3
would like to defer this decision to runtime. In preparation, pass a
4
float_status argument to floatx80_invalid_encoding().
1
5
6
We will change the implementation from ifdef to looking at
7
the status argument in the following commit.
8
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
11
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
12
Message-id: 20250224111524.1101196-7-peter.maydell@linaro.org
13
---
14
include/fpu/softfloat.h | 2 +-
15
fpu/softfloat.c | 2 +-
16
target/i386/tcg/fpu_helper.c | 24 +++++++++++++-----------
17
3 files changed, 15 insertions(+), 13 deletions(-)
18
19
diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h
20
index XXXXXXX..XXXXXXX 100644
21
--- a/include/fpu/softfloat.h
22
+++ b/include/fpu/softfloat.h
23
@@ -XXX,XX +XXX,XX @@ static inline bool floatx80_unordered_quiet(floatx80 a, floatx80 b,
24
| pseudo-denormals, which must still be correctly handled as inputs even
25
| if they are never generated as outputs.
26
*----------------------------------------------------------------------------*/
27
-static inline bool floatx80_invalid_encoding(floatx80 a)
28
+static inline bool floatx80_invalid_encoding(floatx80 a, float_status *s)
29
{
30
#if defined(TARGET_M68K)
31
/*-------------------------------------------------------------------------
32
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
33
index XXXXXXX..XXXXXXX 100644
34
--- a/fpu/softfloat.c
35
+++ b/fpu/softfloat.c
36
@@ -XXX,XX +XXX,XX @@ static bool floatx80_unpack_canonical(FloatParts128 *p, floatx80 f,
37
g_assert_not_reached();
38
}
39
40
- if (unlikely(floatx80_invalid_encoding(f))) {
41
+ if (unlikely(floatx80_invalid_encoding(f, s))) {
42
float_raise(float_flag_invalid, s);
43
return false;
44
}
45
diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c
46
index XXXXXXX..XXXXXXX 100644
47
--- a/target/i386/tcg/fpu_helper.c
48
+++ b/target/i386/tcg/fpu_helper.c
49
@@ -XXX,XX +XXX,XX @@ void helper_f2xm1(CPUX86State *env)
50
int32_t exp = extractFloatx80Exp(ST0);
51
bool sign = extractFloatx80Sign(ST0);
52
53
- if (floatx80_invalid_encoding(ST0)) {
54
+ if (floatx80_invalid_encoding(ST0, &env->fp_status)) {
55
float_raise(float_flag_invalid, &env->fp_status);
56
ST0 = floatx80_default_nan(&env->fp_status);
57
} else if (floatx80_is_any_nan(ST0)) {
58
@@ -XXX,XX +XXX,XX @@ void helper_fpatan(CPUX86State *env)
59
} else if (floatx80_is_signaling_nan(ST1, &env->fp_status)) {
60
float_raise(float_flag_invalid, &env->fp_status);
61
ST1 = floatx80_silence_nan(ST1, &env->fp_status);
62
- } else if (floatx80_invalid_encoding(ST0) ||
63
- floatx80_invalid_encoding(ST1)) {
64
+ } else if (floatx80_invalid_encoding(ST0, &env->fp_status) ||
65
+ floatx80_invalid_encoding(ST1, &env->fp_status)) {
66
float_raise(float_flag_invalid, &env->fp_status);
67
ST1 = floatx80_default_nan(&env->fp_status);
68
} else if (floatx80_is_any_nan(ST0)) {
69
@@ -XXX,XX +XXX,XX @@ void helper_fxtract(CPUX86State *env)
70
&env->fp_status);
71
fpush(env);
72
ST0 = temp.d;
73
- } else if (floatx80_invalid_encoding(ST0)) {
74
+ } else if (floatx80_invalid_encoding(ST0, &env->fp_status)) {
75
float_raise(float_flag_invalid, &env->fp_status);
76
ST0 = floatx80_default_nan(&env->fp_status);
77
fpush(env);
78
@@ -XXX,XX +XXX,XX @@ static void helper_fprem_common(CPUX86State *env, bool mod)
79
env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */
80
if (floatx80_is_zero(ST0) || floatx80_is_zero(ST1) ||
81
exp0 == 0x7fff || exp1 == 0x7fff ||
82
- floatx80_invalid_encoding(ST0) || floatx80_invalid_encoding(ST1)) {
83
+ floatx80_invalid_encoding(ST0, &env->fp_status) ||
84
+ floatx80_invalid_encoding(ST1, &env->fp_status)) {
85
ST0 = floatx80_modrem(ST0, ST1, mod, &quotient, &env->fp_status);
86
} else {
87
if (exp0 == 0) {
88
@@ -XXX,XX +XXX,XX @@ void helper_fyl2xp1(CPUX86State *env)
89
} else if (floatx80_is_signaling_nan(ST1, &env->fp_status)) {
90
float_raise(float_flag_invalid, &env->fp_status);
91
ST1 = floatx80_silence_nan(ST1, &env->fp_status);
92
- } else if (floatx80_invalid_encoding(ST0) ||
93
- floatx80_invalid_encoding(ST1)) {
94
+ } else if (floatx80_invalid_encoding(ST0, &env->fp_status) ||
95
+ floatx80_invalid_encoding(ST1, &env->fp_status)) {
96
float_raise(float_flag_invalid, &env->fp_status);
97
ST1 = floatx80_default_nan(&env->fp_status);
98
} else if (floatx80_is_any_nan(ST0)) {
99
@@ -XXX,XX +XXX,XX @@ void helper_fyl2x(CPUX86State *env)
100
} else if (floatx80_is_signaling_nan(ST1, &env->fp_status)) {
101
float_raise(float_flag_invalid, &env->fp_status);
102
ST1 = floatx80_silence_nan(ST1, &env->fp_status);
103
- } else if (floatx80_invalid_encoding(ST0) ||
104
- floatx80_invalid_encoding(ST1)) {
105
+ } else if (floatx80_invalid_encoding(ST0, &env->fp_status) ||
106
+ floatx80_invalid_encoding(ST1, &env->fp_status)) {
107
float_raise(float_flag_invalid, &env->fp_status);
108
ST1 = floatx80_default_nan(&env->fp_status);
109
} else if (floatx80_is_any_nan(ST0)) {
110
@@ -XXX,XX +XXX,XX @@ void helper_frndint(CPUX86State *env)
111
void helper_fscale(CPUX86State *env)
112
{
113
uint8_t old_flags = save_exception_flags(env);
114
- if (floatx80_invalid_encoding(ST1) || floatx80_invalid_encoding(ST0)) {
115
+ if (floatx80_invalid_encoding(ST1, &env->fp_status) ||
116
+ floatx80_invalid_encoding(ST0, &env->fp_status)) {
117
float_raise(float_flag_invalid, &env->fp_status);
118
ST0 = floatx80_default_nan(&env->fp_status);
119
} else if (floatx80_is_any_nan(ST1)) {
120
@@ -XXX,XX +XXX,XX @@ void helper_fscale(CPUX86State *env)
121
ST0 = floatx80_silence_nan(ST0, &env->fp_status);
122
}
123
} else if (floatx80_is_infinity(ST1, &env->fp_status) &&
124
- !floatx80_invalid_encoding(ST0) &&
125
+ !floatx80_invalid_encoding(ST0, &env->fp_status) &&
126
!floatx80_is_any_nan(ST0)) {
127
if (floatx80_is_neg(ST1)) {
128
if (floatx80_is_infinity(ST0, &env->fp_status)) {
129
--
130
2.43.0
131
132
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
Because floatx80 has an explicit integer bit, this permits some
2
odd encodings where the integer bit is not set correctly for the
3
floating point value type. In In Intel terminology the
4
categories are:
5
exp == 0, int = 0, mantissa == 0 : zeroes
6
exp == 0, int = 0, mantissa != 0 : denormals
7
exp == 0, int = 1 : pseudo-denormals
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
2
14
3
Give this enum a name and use in ARMCPRegInfo,
15
The usual IEEE cases of zero, denormal, normal, inf and NaN are always valid.
4
add_cpreg_to_hashtable and define_one_arm_cp_reg_with_opaque.
16
x87 permits as input also pseudo-denormals.
17
m68k permits all those and also pseudo-infinities, pseudo-NaNs and unnormals.
5
18
6
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
19
Currently we have an ifdef in floatx80_invalid_encoding() to select
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
20
the x86 vs m68k behaviour. Add new floatx80_behaviour flags to
8
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
21
select whether pseudo-NaN and unnormal are valid, and use these
9
Message-id: 20220501055028.646596-9-richard.henderson@linaro.org
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.
27
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
28
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
29
Reviewed-by: Richard Henderson <richard.henderson@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
11
---
33
---
12
target/arm/cpregs.h | 6 +++---
34
include/fpu/softfloat-types.h | 14 ++++++++
13
target/arm/helper.c | 6 ++++--
35
include/fpu/softfloat.h | 68 ++++++++++++++++++-----------------
14
2 files changed, 7 insertions(+), 5 deletions(-)
36
target/m68k/cpu.c | 28 ++++++++++++++-
37
3 files changed, 77 insertions(+), 33 deletions(-)
15
38
16
diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
39
diff --git a/include/fpu/softfloat-types.h b/include/fpu/softfloat-types.h
17
index XXXXXXX..XXXXXXX 100644
40
index XXXXXXX..XXXXXXX 100644
18
--- a/target/arm/cpregs.h
41
--- a/include/fpu/softfloat-types.h
19
+++ b/target/arm/cpregs.h
42
+++ b/include/fpu/softfloat-types.h
20
@@ -XXX,XX +XXX,XX @@ enum {
43
@@ -XXX,XX +XXX,XX @@ typedef enum __attribute__((__packed__)) {
21
* Note that we rely on the values of these enums as we iterate through
44
/*
22
* the various states in some places.
45
* Are Pseudo-infinities (Inf with the Integer bit zero) valid?
23
*/
46
* If so, floatx80_is_infinity() will return true for them.
24
-enum {
47
+ * If not, floatx80_invalid_encoding will return false for them,
25
+typedef enum {
48
+ * and using them as inputs to a float op will raise Invalid.
26
ARM_CP_STATE_AA32 = 0,
49
*/
27
ARM_CP_STATE_AA64 = 1,
50
floatx80_pseudo_inf_valid = 2,
28
ARM_CP_STATE_BOTH = 2,
51
+ /*
29
-};
52
+ * Are Pseudo-NaNs (NaNs where the Integer bit is zero) valid?
30
+} CPState;
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;
31
64
32
/*
65
/*
33
* ARM CP register secure state flags. These flags identify security state
66
diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h
34
@@ -XXX,XX +XXX,XX @@ struct ARMCPRegInfo {
35
uint8_t opc1;
36
uint8_t opc2;
37
/* Execution state in which this register is visible: ARM_CP_STATE_* */
38
- int state;
39
+ CPState state;
40
/* Register type: ARM_CP_* bits/values */
41
int type;
42
/* Access rights: PL*_[RW] */
43
diff --git a/target/arm/helper.c b/target/arm/helper.c
44
index XXXXXXX..XXXXXXX 100644
67
index XXXXXXX..XXXXXXX 100644
45
--- a/target/arm/helper.c
68
--- a/include/fpu/softfloat.h
46
+++ b/target/arm/helper.c
69
+++ b/include/fpu/softfloat.h
47
@@ -XXX,XX +XXX,XX @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
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)
105
{
106
-#if defined(TARGET_M68K)
107
- /*-------------------------------------------------------------------------
108
- | With m68k, the explicit integer bit can be zero in the case of:
109
- | - zeros (exp == 0, mantissa == 0)
110
- | - denormalized numbers (exp == 0, mantissa != 0)
111
- | - unnormalized numbers (exp != 0, exp < 0x7FFF)
112
- | - infinities (exp == 0x7FFF, mantissa == 0)
113
- | - not-a-numbers (exp == 0x7FFF, mantissa != 0)
114
- |
115
- | For infinities and NaNs, the explicit integer bit can be either one or
116
- | zero.
117
- |
118
- | The IEEE 754 standard does not define a zero integer bit. Such a number
119
- | is an unnormalized number. Hardware does not directly support
120
- | denormalized and unnormalized numbers, but implicitly supports them by
121
- | trapping them as unimplemented data types, allowing efficient conversion
122
- | in software.
123
- |
124
- | See "M68000 FAMILY PROGRAMMER’S REFERENCE MANUAL",
125
- | "1.6 FLOATING-POINT DATA TYPES"
126
- *------------------------------------------------------------------------*/
127
- return false;
128
-#else
129
- return (a.low & (1ULL << 63)) == 0 && (a.high & 0x7FFF) != 0;
130
-#endif
131
+ if ((a.low >> 63) || (a.high & 0x7fff) == 0) {
132
+ /* Anything with the Integer bit set or the exponent 0 is valid */
133
+ return false;
134
+ }
135
+
136
+ if ((a.high & 0x7fff) == 0x7fff) {
137
+ if (a.low) {
138
+ return !(s->floatx80_behaviour & floatx80_pseudo_nan_valid);
139
+ } else {
140
+ return !(s->floatx80_behaviour & floatx80_pseudo_inf_valid);
141
+ }
142
+ } else {
143
+ return !(s->floatx80_behaviour & floatx80_unnormal_valid);
144
+ }
48
}
145
}
49
146
50
static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
147
#define floatx80_zero make_floatx80(0x0000, 0x0000000000000000LL)
51
- void *opaque, int state, int secstate,
148
diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c
52
+ void *opaque, CPState state, int secstate,
149
index XXXXXXX..XXXXXXX 100644
53
int crm, int opc1, int opc2,
150
--- a/target/m68k/cpu.c
54
const char *name)
151
+++ b/target/m68k/cpu.c
55
{
152
@@ -XXX,XX +XXX,XX @@ static void m68k_cpu_reset_hold(Object *obj, ResetType type)
56
@@ -XXX,XX +XXX,XX @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
153
* m68k-specific floatx80 behaviour:
57
* bits; the ARM_CP_64BIT* flag applies only to the AArch32 view of
154
* * default Infinity values have a zero Integer bit
58
* the register, if any.
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.
59
*/
180
*/
60
- int crm, opc1, opc2, state;
181
set_floatx80_behaviour(floatx80_default_inf_int_bit_is_zero |
61
+ int crm, opc1, opc2;
182
- floatx80_pseudo_inf_valid,
62
int crmmin = (r->crm == CP_ANY) ? 0 : r->crm;
183
+ floatx80_pseudo_inf_valid |
63
int crmmax = (r->crm == CP_ANY) ? 15 : r->crm;
184
+ floatx80_pseudo_nan_valid |
64
int opc1min = (r->opc1 == CP_ANY) ? 0 : r->opc1;
185
+ floatx80_unnormal_valid,
65
int opc1max = (r->opc1 == CP_ANY) ? 7 : r->opc1;
186
&env->fp_status);
66
int opc2min = (r->opc2 == CP_ANY) ? 0 : r->opc2;
187
67
int opc2max = (r->opc2 == CP_ANY) ? 7 : r->opc2;
188
nan = floatx80_default_nan(&env->fp_status);
68
+ CPState state;
69
+
70
/* 64 bit registers have only CRm and Opc1 fields */
71
assert(!((r->type & ARM_CP_64BIT) && (r->opc2 || r->crn)));
72
/* op0 only exists in the AArch64 encodings */
73
--
189
--
74
2.25.1
190
2.43.0
75
191
76
192
diff view generated by jsdifflib
New patch
1
Currently we compile-time set an 'm68k_denormal' flag in the FloatFmt
2
for floatx80 for m68k. This controls our handling of what the Intel
3
documentation calls a "pseudo-denormal": a value where the exponent
4
field is zero and the explicit integer bit is set.
1
5
6
For x86, the x87 FPU is supposed to accept a pseudo-denormal as
7
input, but never generate one on output. For m68k, these values are
8
permitted on input and may be produced on output.
9
10
Replace the flag in the FloatFmt with a flag indicating whether the
11
float format has an explicit bit (which will be true for floatx80 for
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.
22
23
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
24
Reviewed-by: Richard Henderson <richard.henderson@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
28
---
29
include/fpu/softfloat-types.h | 19 +++++++++++++++++++
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(-)
34
35
diff --git a/include/fpu/softfloat-types.h b/include/fpu/softfloat-types.h
36
index XXXXXXX..XXXXXXX 100644
37
--- a/include/fpu/softfloat-types.h
38
+++ b/include/fpu/softfloat-types.h
39
@@ -XXX,XX +XXX,XX @@ typedef enum __attribute__((__packed__)) {
40
* and using them as inputs to a float op will raise Invalid.
41
*/
42
floatx80_unnormal_valid = 8,
43
+
44
+ /*
45
+ * If the exponent is 0 and the Integer bit is set, Intel call
46
+ * this a "pseudo-denormal"; x86 supports that only on input
47
+ * (treating them as denormals by ignoring the Integer bit).
48
+ * For m68k, the integer bit is considered validly part of the
49
+ * input value when the exponent is 0, and may be 0 or 1,
50
+ * giving extra range. They may also be generated as outputs.
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;
149
}
150
} else if (likely(p->exp < fmt->exp_max) || fmt->arm_althp) {
151
p->cls = float_class_normal;
152
@@ -XXX,XX +XXX,XX @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s,
153
frac_clear(p);
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);
162
}
163
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) {
178
--
179
2.43.0
180
181
diff view generated by jsdifflib
New patch
1
Currently we have a compile-time shortcut where we
2
return false from no_signaling_nans() on everything except
3
Xtensa, because we know that's the only target that
4
might ever set status->no_signaling_nans.
1
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.
9
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
12
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
13
Message-id: 20250224111524.1101196-10-peter.maydell@linaro.org
14
Message-id: 20250217125055.160887-8-peter.maydell@linaro.org
15
---
16
fpu/softfloat-specialize.c.inc | 4 ----
17
1 file changed, 4 deletions(-)
18
19
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
20
index XXXXXXX..XXXXXXX 100644
21
--- a/fpu/softfloat-specialize.c.inc
22
+++ b/fpu/softfloat-specialize.c.inc
23
@@ -XXX,XX +XXX,XX @@ this code that are retained.
24
*/
25
static inline bool no_signaling_nans(float_status *status)
26
{
27
-#if defined(TARGET_XTENSA)
28
return status->no_signaling_nans;
29
-#else
30
- return false;
31
-#endif
32
}
33
34
/* Define how the architecture discriminates signaling NaNs.
35
--
36
2.43.0
37
38
diff view generated by jsdifflib
New patch
1
Currently we have a compile-time shortcut where we return a hardcode
2
value from snan_bit_is_one() on everything except MIPS, because we
3
know that's the only target that needs to change
4
status->no_signaling_nans at runtime.
1
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.
12
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
15
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
16
Message-id: 20250224111524.1101196-11-peter.maydell@linaro.org
17
Message-id: 20250217125055.160887-9-peter.maydell@linaro.org
18
---
19
target/hppa/fpu_helper.c | 1 +
20
target/sh4/cpu.c | 1 +
21
fpu/softfloat-specialize.c.inc | 7 -------
22
3 files changed, 2 insertions(+), 7 deletions(-)
23
24
diff --git a/target/hppa/fpu_helper.c b/target/hppa/fpu_helper.c
25
index XXXXXXX..XXXXXXX 100644
26
--- a/target/hppa/fpu_helper.c
27
+++ b/target/hppa/fpu_helper.c
28
@@ -XXX,XX +XXX,XX @@ void HELPER(loaded_fr0)(CPUHPPAState *env)
29
set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
30
/* Default NaN: sign bit clear, msb-1 frac bit set */
31
set_float_default_nan_pattern(0b00100000, &env->fp_status);
32
+ set_snan_bit_is_one(true, &env->fp_status);
33
/*
34
* "PA-RISC 2.0 Architecture" says it is IMPDEF whether the flushing
35
* enabled by FPSR.D happens before or after rounding. We pick "before"
36
diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c
37
index XXXXXXX..XXXXXXX 100644
38
--- a/target/sh4/cpu.c
39
+++ b/target/sh4/cpu.c
40
@@ -XXX,XX +XXX,XX @@ static void superh_cpu_reset_hold(Object *obj, ResetType type)
41
set_flush_to_zero(1, &env->fp_status);
42
#endif
43
set_default_nan_mode(1, &env->fp_status);
44
+ set_snan_bit_is_one(true, &env->fp_status);
45
/* sign bit clear, set all frac bits other than msb */
46
set_float_default_nan_pattern(0b00111111, &env->fp_status);
47
/*
48
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
49
index XXXXXXX..XXXXXXX 100644
50
--- a/fpu/softfloat-specialize.c.inc
51
+++ b/fpu/softfloat-specialize.c.inc
52
@@ -XXX,XX +XXX,XX @@ static inline bool no_signaling_nans(float_status *status)
53
* In IEEE 754-1985 this was implementation defined, but in IEEE 754-2008
54
* the msb must be zero. MIPS is (so far) unique in supporting both the
55
* 2008 revision and backward compatibility with their original choice.
56
- * Thus for MIPS we must make the choice at runtime.
57
*/
58
static inline bool snan_bit_is_one(float_status *status)
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
/*----------------------------------------------------------------------------
70
--
71
2.43.0
72
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
New patch
1
Now we have removed all the target-specifics from the softfloat code,
2
we can switch to building it once for the whole system rather than
3
once per target.
1
4
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org>
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20250224111524.1101196-13-peter.maydell@linaro.org
9
Message-id: 20250217125055.160887-11-peter.maydell@linaro.org
10
---
11
fpu/softfloat.c | 3 ---
12
fpu/meson.build | 2 +-
13
2 files changed, 1 insertion(+), 4 deletions(-)
14
15
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/fpu/softfloat.c
18
+++ b/fpu/softfloat.c
19
@@ -XXX,XX +XXX,XX @@ this code that are retained.
20
* version 2 or later. See the COPYING file in the top-level directory.
21
*/
22
23
-/* softfloat (and in particular the code in softfloat-specialize.h) is
24
- * target-dependent and needs the TARGET_* macros.
25
- */
26
#include "qemu/osdep.h"
27
#include <math.h>
28
#include "qemu/bitops.h"
29
diff --git a/fpu/meson.build b/fpu/meson.build
30
index XXXXXXX..XXXXXXX 100644
31
--- a/fpu/meson.build
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'))
36
--
37
2.43.0
38
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
New patch
1
The softfloat (i.e. TCG) specific handling for the FPCR
2
and FPSR is abstracted behind five functions:
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
1
8
9
Currently we rely on the first two calling softfloat functions that
10
work even in a KVM-only compile because they're defined as inline in
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.
13
14
Move the softfloat-specific versions of these functions to
15
tcg/vfp_helper.c, and provide the non-TCG stub versions in
16
tcg-stubs.c.
17
18
This lets us drop the softfloat header include and the last
19
set of CONFIG_TCG ifdefs from arm/vfp_helper.c.
20
21
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
22
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
23
Message-id: 20250221190957.811948-4-peter.maydell@linaro.org
24
---
25
target/arm/internals.h | 9 ++
26
target/arm/tcg-stubs.c | 22 ++++
27
target/arm/tcg/vfp_helper.c | 228 +++++++++++++++++++++++++++++++++
28
target/arm/vfp_helper.c | 248 ------------------------------------
29
4 files changed, 259 insertions(+), 248 deletions(-)
30
31
diff --git a/target/arm/internals.h b/target/arm/internals.h
32
index XXXXXXX..XXXXXXX 100644
33
--- a/target/arm/internals.h
34
+++ b/target/arm/internals.h
35
@@ -XXX,XX +XXX,XX @@ int alle1_tlbmask(CPUARMState *env);
36
void arm_set_default_fp_behaviours(float_status *s);
37
/* Set the float_status behaviour to match Arm FPCR.AH=1 behaviour */
38
void arm_set_ah_fp_behaviours(float_status *s);
39
+/* Read the float_status info and return the appropriate FPSR value */
40
+uint32_t vfp_get_fpsr_from_host(CPUARMState *env);
41
+/* Clear the exception status flags from all float_status fields */
42
+void vfp_clear_float_status_exc_flags(CPUARMState *env);
43
+/*
44
+ * Update float_status fields to handle the bits of the FPCR
45
+ * specified by mask changing to the values in val.
46
+ */
47
+void vfp_set_fpcr_to_host(CPUARMState *env, uint32_t val, uint32_t mask);
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
+}
315
+
316
/*
317
* VFP support. We follow the convention used for VFP instructions:
318
* Single precision routines have a "s" suffix, double precision a
319
diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_helper.c
320
index XXXXXXX..XXXXXXX 100644
321
--- a/target/arm/vfp_helper.c
322
+++ b/target/arm/vfp_helper.c
323
@@ -XXX,XX +XXX,XX @@
324
#include "cpu.h"
325
#include "internals.h"
326
#include "cpu-features.h"
327
-#include "fpu/softfloat.h"
328
-
329
-/*
330
- * Set the float_status behaviour to match the Arm defaults:
331
- * * tininess-before-rounding
332
- * * 2-input NaN propagation prefers SNaN over QNaN, and then
333
- * operand A over operand B (see FPProcessNaNs() pseudocode)
334
- * * 3-input NaN propagation prefers SNaN over QNaN, and then
335
- * operand C over A over B (see FPProcessNaNs3() pseudocode,
336
- * but note that for QEMU muladd is a * b + c, whereas for
337
- * the pseudocode function the arguments are in the order c, a, b.
338
- * * 0 * Inf + NaN returns the default NaN if the input NaN is quiet,
339
- * and the input NaN if it is signalling
340
- * * Default NaN has sign bit clear, msb frac bit set
341
- */
342
-void arm_set_default_fp_behaviours(float_status *s)
343
-{
344
- set_float_detect_tininess(float_tininess_before_rounding, s);
345
- set_float_ftz_detection(float_ftz_before_rounding, s);
346
- set_float_2nan_prop_rule(float_2nan_prop_s_ab, s);
347
- set_float_3nan_prop_rule(float_3nan_prop_s_cab, s);
348
- set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, s);
349
- set_float_default_nan_pattern(0b01000000, s);
350
-}
351
-
352
-/*
353
- * Set the float_status behaviour to match the FEAT_AFP
354
- * FPCR.AH=1 requirements:
355
- * * tininess-after-rounding
356
- * * 2-input NaN propagation prefers the first NaN
357
- * * 3-input NaN propagation prefers a over b over c
358
- * * 0 * Inf + NaN always returns the input NaN and doesn't
359
- * set Invalid for a QNaN
360
- * * default NaN has sign bit set, msb frac bit set
361
- */
362
-void arm_set_ah_fp_behaviours(float_status *s)
363
-{
364
- set_float_detect_tininess(float_tininess_after_rounding, s);
365
- set_float_ftz_detection(float_ftz_after_rounding, s);
366
- set_float_2nan_prop_rule(float_2nan_prop_ab, s);
367
- set_float_3nan_prop_rule(float_3nan_prop_abc, s);
368
- set_float_infzeronan_rule(float_infzeronan_dnan_never |
369
- float_infzeronan_suppress_invalid, s);
370
- set_float_default_nan_pattern(0b11000000, s);
371
-}
372
-
373
-#ifdef CONFIG_TCG
374
-
375
-/* Convert host exception flags to vfp form. */
376
-static inline uint32_t vfp_exceptbits_from_host(int host_bits, bool ah)
377
-{
378
- uint32_t target_bits = 0;
379
-
380
- if (host_bits & float_flag_invalid) {
381
- target_bits |= FPSR_IOC;
382
- }
383
- if (host_bits & float_flag_divbyzero) {
384
- target_bits |= FPSR_DZC;
385
- }
386
- if (host_bits & float_flag_overflow) {
387
- target_bits |= FPSR_OFC;
388
- }
389
- if (host_bits & (float_flag_underflow | float_flag_output_denormal_flushed)) {
390
- target_bits |= FPSR_UFC;
391
- }
392
- if (host_bits & float_flag_inexact) {
393
- target_bits |= FPSR_IXC;
394
- }
395
- if (host_bits & float_flag_input_denormal_flushed) {
396
- target_bits |= FPSR_IDC;
397
- }
398
- /*
399
- * With FPCR.AH, IDC is set when an input denormal is used,
400
- * and flushing an output denormal to zero sets both IXC and UFC.
401
- */
402
- if (ah && (host_bits & float_flag_input_denormal_used)) {
403
- target_bits |= FPSR_IDC;
404
- }
405
- if (ah && (host_bits & float_flag_output_denormal_flushed)) {
406
- target_bits |= FPSR_IXC;
407
- }
408
- return target_bits;
409
-}
410
-
411
-static uint32_t vfp_get_fpsr_from_host(CPUARMState *env)
412
-{
413
- uint32_t a32_flags = 0, a64_flags = 0;
414
-
415
- a32_flags |= get_float_exception_flags(&env->vfp.fp_status[FPST_A32]);
416
- a32_flags |= get_float_exception_flags(&env->vfp.fp_status[FPST_STD]);
417
- /* FZ16 does not generate an input denormal exception. */
418
- a32_flags |= (get_float_exception_flags(&env->vfp.fp_status[FPST_A32_F16])
419
- & ~float_flag_input_denormal_flushed);
420
- a32_flags |= (get_float_exception_flags(&env->vfp.fp_status[FPST_STD_F16])
421
- & ~float_flag_input_denormal_flushed);
422
-
423
- a64_flags |= get_float_exception_flags(&env->vfp.fp_status[FPST_A64]);
424
- a64_flags |= (get_float_exception_flags(&env->vfp.fp_status[FPST_A64_F16])
425
- & ~(float_flag_input_denormal_flushed | float_flag_input_denormal_used));
426
- /*
427
- * We do not merge in flags from FPST_AH or FPST_AH_F16, because
428
- * they are used for insns that must not set the cumulative exception bits.
429
- */
430
-
431
- /*
432
- * Flushing an input denormal *only* because FPCR.FIZ == 1 does
433
- * not set FPSR.IDC; if FPCR.FZ is also set then this takes
434
- * precedence and IDC is set (see the FPUnpackBase pseudocode).
435
- * So squash it unless (FPCR.AH == 0 && FPCR.FZ == 1).
436
- * We only do this for the a64 flags because FIZ has no effect
437
- * on AArch32 even if it is set.
438
- */
439
- if ((env->vfp.fpcr & (FPCR_FZ | FPCR_AH)) != FPCR_FZ) {
440
- a64_flags &= ~float_flag_input_denormal_flushed;
441
- }
442
- return vfp_exceptbits_from_host(a64_flags, env->vfp.fpcr & FPCR_AH) |
443
- vfp_exceptbits_from_host(a32_flags, false);
444
-}
445
-
446
-static void vfp_clear_float_status_exc_flags(CPUARMState *env)
447
-{
448
- /*
449
- * Clear out all the exception-flag information in the float_status
450
- * values. The caller should have arranged for env->vfp.fpsr to
451
- * be the architecturally up-to-date exception flag information first.
452
- */
453
- set_float_exception_flags(0, &env->vfp.fp_status[FPST_A32]);
454
- set_float_exception_flags(0, &env->vfp.fp_status[FPST_A64]);
455
- set_float_exception_flags(0, &env->vfp.fp_status[FPST_A32_F16]);
456
- set_float_exception_flags(0, &env->vfp.fp_status[FPST_A64_F16]);
457
- set_float_exception_flags(0, &env->vfp.fp_status[FPST_STD]);
458
- set_float_exception_flags(0, &env->vfp.fp_status[FPST_STD_F16]);
459
- set_float_exception_flags(0, &env->vfp.fp_status[FPST_AH]);
460
- set_float_exception_flags(0, &env->vfp.fp_status[FPST_AH_F16]);
461
-}
462
-
463
-static void vfp_sync_and_clear_float_status_exc_flags(CPUARMState *env)
464
-{
465
- /*
466
- * Synchronize any pending exception-flag information in the
467
- * float_status values into env->vfp.fpsr, and then clear out
468
- * the float_status data.
469
- */
470
- env->vfp.fpsr |= vfp_get_fpsr_from_host(env);
471
- vfp_clear_float_status_exc_flags(env);
472
-}
473
-
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)
577
{
578
--
579
2.43.0
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: Richard Henderson <richard.henderson@linaro.org>
1
From: Joelle van Dyne <j@getutm.app>
2
2
3
Standardize on g_assert_not_reached() for "should not happen".
3
In the syndrome value for a data abort, bit 21 is SSE, which is
4
Retain abort() when preceeded by fprintf or error_report.
4
set to indicate that the abort was on a sign-extending load. When
5
we handle the data abort from the guest via address_space_read(),
6
we forgot to handle this and so would return the wrong value if
7
the guest did a sign-extending load to an MMIO region. Add the
8
sign-extension of the returned data.
5
9
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
10
Cc: qemu-stable@nongnu.org
11
Signed-off-by: Joelle van Dyne <j@getutm.app>
12
Message-id: 20250224184123.50780-1-j@getutm.app
13
[PMM: Drop an unnecessary check on 'len'; expand commit message]
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
14
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Message-id: 20220501055028.646596-7-richard.henderson@linaro.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
16
---
11
target/arm/helper.c | 7 +++----
17
target/arm/hvf/hvf.c | 4 ++++
12
target/arm/hvf/hvf.c | 2 +-
18
1 file changed, 4 insertions(+)
13
target/arm/kvm-stub.c | 4 ++--
14
target/arm/kvm.c | 4 ++--
15
target/arm/machine.c | 4 ++--
16
target/arm/translate-a64.c | 4 ++--
17
target/arm/translate-neon.c | 2 +-
18
target/arm/translate.c | 4 ++--
19
8 files changed, 15 insertions(+), 16 deletions(-)
20
19
21
diff --git a/target/arm/helper.c b/target/arm/helper.c
22
index XXXXXXX..XXXXXXX 100644
23
--- a/target/arm/helper.c
24
+++ b/target/arm/helper.c
25
@@ -XXX,XX +XXX,XX @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
26
break;
27
default:
28
/* broken reginfo with out-of-range opc1 */
29
- assert(false);
30
- break;
31
+ g_assert_not_reached();
32
}
33
/* assert our permissions are not too lax (stricter is fine) */
34
assert((r->access & ~mask) == 0);
35
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address,
36
break;
37
default:
38
/* Never happens, but compiler isn't smart enough to tell. */
39
- abort();
40
+ g_assert_not_reached();
41
}
42
}
43
*prot = ap_to_rw_prot(env, mmu_idx, ap, domain_prot);
44
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address,
45
break;
46
default:
47
/* Never happens, but compiler isn't smart enough to tell. */
48
- abort();
49
+ g_assert_not_reached();
50
}
51
}
52
if (domain_prot == 3) {
53
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
20
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
54
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
55
--- a/target/arm/hvf/hvf.c
22
--- a/target/arm/hvf/hvf.c
56
+++ b/target/arm/hvf/hvf.c
23
+++ b/target/arm/hvf/hvf.c
57
@@ -XXX,XX +XXX,XX @@ int hvf_vcpu_exec(CPUState *cpu)
24
@@ -XXX,XX +XXX,XX @@ int hvf_vcpu_exec(CPUState *cpu)
58
/* we got kicked, no exit to process */
25
bool isv = syndrome & ARM_EL_ISV;
59
return 0;
26
bool iswrite = (syndrome >> 6) & 1;
60
default:
27
bool s1ptw = (syndrome >> 7) & 1;
61
- assert(0);
28
+ bool sse = (syndrome >> 21) & 1;
62
+ g_assert_not_reached();
29
uint32_t sas = (syndrome >> 22) & 3;
63
}
30
uint32_t len = 1 << sas;
64
31
uint32_t srt = (syndrome >> 16) & 0x1f;
65
hvf_sync_vtimer(cpu);
32
@@ -XXX,XX +XXX,XX @@ int hvf_vcpu_exec(CPUState *cpu)
66
diff --git a/target/arm/kvm-stub.c b/target/arm/kvm-stub.c
33
address_space_read(&address_space_memory,
67
index XXXXXXX..XXXXXXX 100644
34
hvf_exit->exception.physical_address,
68
--- a/target/arm/kvm-stub.c
35
MEMTXATTRS_UNSPECIFIED, &val, len);
69
+++ b/target/arm/kvm-stub.c
36
+ if (sse) {
70
@@ -XXX,XX +XXX,XX @@
37
+ val = sextract64(val, 0, len * 8);
71
38
+ }
72
bool write_kvmstate_to_list(ARMCPU *cpu)
39
hvf_set_reg(cpu, srt, val);
73
{
74
- abort();
75
+ g_assert_not_reached();
76
}
77
78
bool write_list_to_kvmstate(ARMCPU *cpu, int level)
79
{
80
- abort();
81
+ g_assert_not_reached();
82
}
83
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
84
index XXXXXXX..XXXXXXX 100644
85
--- a/target/arm/kvm.c
86
+++ b/target/arm/kvm.c
87
@@ -XXX,XX +XXX,XX @@ bool write_kvmstate_to_list(ARMCPU *cpu)
88
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &r);
89
break;
90
default:
91
- abort();
92
+ g_assert_not_reached();
93
}
40
}
94
if (ret) {
41
95
ok = false;
96
@@ -XXX,XX +XXX,XX @@ bool write_list_to_kvmstate(ARMCPU *cpu, int level)
97
r.addr = (uintptr_t)(cpu->cpreg_values + i);
98
break;
99
default:
100
- abort();
101
+ g_assert_not_reached();
102
}
103
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &r);
104
if (ret) {
105
diff --git a/target/arm/machine.c b/target/arm/machine.c
106
index XXXXXXX..XXXXXXX 100644
107
--- a/target/arm/machine.c
108
+++ b/target/arm/machine.c
109
@@ -XXX,XX +XXX,XX @@ static int cpu_pre_save(void *opaque)
110
if (kvm_enabled()) {
111
if (!write_kvmstate_to_list(cpu)) {
112
/* This should never fail */
113
- abort();
114
+ g_assert_not_reached();
115
}
116
117
/*
118
@@ -XXX,XX +XXX,XX @@ static int cpu_pre_save(void *opaque)
119
} else {
120
if (!write_cpustate_to_list(cpu, false)) {
121
/* This should never fail. */
122
- abort();
123
+ g_assert_not_reached();
124
}
125
}
126
127
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
128
index XXXXXXX..XXXXXXX 100644
129
--- a/target/arm/translate-a64.c
130
+++ b/target/arm/translate-a64.c
131
@@ -XXX,XX +XXX,XX @@ static void handle_fp_1src_half(DisasContext *s, int opcode, int rd, int rn)
132
gen_helper_advsimd_rinth(tcg_res, tcg_op, fpst);
133
break;
134
default:
135
- abort();
136
+ g_assert_not_reached();
137
}
138
139
write_fp_sreg(s, rd, tcg_res);
140
@@ -XXX,XX +XXX,XX @@ static void handle_fp_fcvt(DisasContext *s, int opcode,
141
break;
142
}
143
default:
144
- abort();
145
+ g_assert_not_reached();
146
}
147
}
148
149
diff --git a/target/arm/translate-neon.c b/target/arm/translate-neon.c
150
index XXXXXXX..XXXXXXX 100644
151
--- a/target/arm/translate-neon.c
152
+++ b/target/arm/translate-neon.c
153
@@ -XXX,XX +XXX,XX @@ static bool trans_VLDST_single(DisasContext *s, arg_VLDST_single *a)
154
}
155
break;
156
default:
157
- abort();
158
+ g_assert_not_reached();
159
}
160
if ((vd + a->stride * (nregs - 1)) > 31) {
161
/*
162
diff --git a/target/arm/translate.c b/target/arm/translate.c
163
index XXXXXXX..XXXXXXX 100644
164
--- a/target/arm/translate.c
165
+++ b/target/arm/translate.c
166
@@ -XXX,XX +XXX,XX @@ static void gen_srs(DisasContext *s,
167
offset = 4;
168
break;
169
default:
170
- abort();
171
+ g_assert_not_reached();
172
}
173
tcg_gen_addi_i32(addr, addr, offset);
174
tmp = load_reg(s, 14);
175
@@ -XXX,XX +XXX,XX @@ static void gen_srs(DisasContext *s,
176
offset = 0;
177
break;
178
default:
179
- abort();
180
+ g_assert_not_reached();
181
}
182
tcg_gen_addi_i32(addr, addr, offset);
183
gen_helper_set_r13_banked(cpu_env, tcg_constant_i32(mode), addr);
184
--
42
--
185
2.25.1
43
2.43.0
diff view generated by jsdifflib
1
From: Alex Zuepke <alex.zuepke@tum.de>
1
From: Pierrick Bouvier <pierrick.bouvier@linaro.org>
2
2
3
The ARMv8 manual defines that PMUSERENR_EL0.ER enables read-access
3
Regression introduced by cf76c4
4
to both PMXEVCNTR_EL0 and PMEVCNTR<n>_EL0 registers, however,
4
(hw/misc: Add nr_regs and cold_reset_values to NPCM CLK)
5
we only use it for PMXEVCNTR_EL0. Extend to PMEVCNTR<n>_EL0 as well.
6
5
7
Signed-off-by: Alex Zuepke <alex.zuepke@tum.de>
6
cold_reset_values has a different size, depending on device used
8
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
(NPCM7xx vs NPCM8xx). However, s->regs has a fixed size, which matches
9
Message-id: 20220428132717.84190-1-alex.zuepke@tum.de
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>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
67
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
68
---
12
target/arm/helper.c | 4 ++--
69
hw/misc/npcm_clk.c | 5 +++--
13
1 file changed, 2 insertions(+), 2 deletions(-)
70
1 file changed, 3 insertions(+), 2 deletions(-)
14
71
15
diff --git a/target/arm/helper.c b/target/arm/helper.c
72
diff --git a/hw/misc/npcm_clk.c b/hw/misc/npcm_clk.c
16
index XXXXXXX..XXXXXXX 100644
73
index XXXXXXX..XXXXXXX 100644
17
--- a/target/arm/helper.c
74
--- a/hw/misc/npcm_clk.c
18
+++ b/target/arm/helper.c
75
+++ b/hw/misc/npcm_clk.c
19
@@ -XXX,XX +XXX,XX @@ static void define_pmu_regs(ARMCPU *cpu)
76
@@ -XXX,XX +XXX,XX @@ static void npcm_clk_enter_reset(Object *obj, ResetType type)
20
.crm = 8 | (3 & (i >> 3)), .opc1 = 0, .opc2 = i & 7,
77
NPCMCLKState *s = NPCM_CLK(obj);
21
.access = PL0_RW, .type = ARM_CP_IO | ARM_CP_ALIAS,
78
NPCMCLKClass *c = NPCM_CLK_GET_CLASS(s);
22
.readfn = pmevcntr_readfn, .writefn = pmevcntr_writefn,
79
23
- .accessfn = pmreg_access },
80
- g_assert(sizeof(s->regs) >= c->nr_regs * sizeof(uint32_t));
24
+ .accessfn = pmreg_access_xevcntr },
81
- memcpy(s->regs, c->cold_reset_values, sizeof(s->regs));
25
{ .name = pmevcntr_el0_name, .state = ARM_CP_STATE_AA64,
82
+ size_t sizeof_regs = c->nr_regs * sizeof(uint32_t);
26
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 8 | (3 & (i >> 3)),
83
+ g_assert(sizeof(s->regs) >= sizeof_regs);
27
- .opc2 = i & 7, .access = PL0_RW, .accessfn = pmreg_access,
84
+ memcpy(s->regs, c->cold_reset_values, sizeof_regs);
28
+ .opc2 = i & 7, .access = PL0_RW, .accessfn = pmreg_access_xevcntr,
85
s->ref_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
29
.type = ARM_CP_IO,
86
npcm7xx_clk_update_all_clocks(s);
30
.readfn = pmevcntr_readfn, .writefn = pmevcntr_writefn,
87
/*
31
.raw_readfn = pmevcntr_rawread,
32
--
88
--
33
2.25.1
89
2.43.0
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Bernhard Beschow <shentey@gmail.com>
2
2
3
Bool is a more appropriate type for these variables.
3
While at it add missing GUSB2RHBCTL register as found in i.MX 8M Plus reference
4
manual.
4
5
5
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Message-id: 20220501055028.646596-16-richard.henderson@linaro.org
7
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
8
Message-id: 20250223114708.1780-2-shentey@gmail.com
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
10
---
10
target/arm/helper.c | 4 ++--
11
include/hw/usb/hcd-dwc3.h | 2 +-
11
1 file changed, 2 insertions(+), 2 deletions(-)
12
hw/usb/hcd-dwc3.c | 5 +++++
13
2 files changed, 6 insertions(+), 1 deletion(-)
12
14
13
diff --git a/target/arm/helper.c b/target/arm/helper.c
15
diff --git a/include/hw/usb/hcd-dwc3.h b/include/hw/usb/hcd-dwc3.h
14
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
15
--- a/target/arm/helper.c
17
--- a/include/hw/usb/hcd-dwc3.h
16
+++ b/target/arm/helper.c
18
+++ b/include/hw/usb/hcd-dwc3.h
17
@@ -XXX,XX +XXX,XX @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
19
@@ -XXX,XX +XXX,XX @@
18
*/
20
#define USB_DWC3(obj) \
19
uint32_t key;
21
OBJECT_CHECK(USBDWC3, (obj), TYPE_USB_DWC3)
20
ARMCPRegInfo *r2;
22
21
- int is64 = (r->type & ARM_CP_64BIT) ? 1 : 0;
23
-#define USB_DWC3_R_MAX ((0x530 / 4) + 1)
22
- int ns = (secstate & ARM_CP_SECSTATE_NS) ? 1 : 0;
24
+#define USB_DWC3_R_MAX (0x600 / 4)
23
+ bool is64 = r->type & ARM_CP_64BIT;
25
#define DWC3_SIZE 0x10000
24
+ bool ns = secstate & ARM_CP_SECSTATE_NS;
26
25
int cp = r->cp;
27
typedef struct USBDWC3 {
26
size_t name_len;
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
};
27
50
28
--
51
--
29
2.25.1
52
2.43.0
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Bernhard Beschow <shentey@gmail.com>
2
2
3
Put most of the value writeback to the same place,
3
On the real device, the PCIe root bus is only connected to a PCIe bridge and
4
and improve the comment that goes with them.
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.
5
7
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
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
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
13
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Message-id: 20220501055028.646596-15-richard.henderson@linaro.org
14
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
15
Message-id: 20250223114708.1780-3-shentey@gmail.com
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
17
---
11
target/arm/helper.c | 28 ++++++++++++----------------
18
include/hw/pci-host/designware.h | 7 +++++++
12
1 file changed, 12 insertions(+), 16 deletions(-)
19
hw/pci-host/designware.c | 18 +++++++++++++++++-
20
2 files changed, 24 insertions(+), 1 deletion(-)
13
21
14
diff --git a/target/arm/helper.c b/target/arm/helper.c
22
diff --git a/include/hw/pci-host/designware.h b/include/hw/pci-host/designware.h
15
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
16
--- a/target/arm/helper.c
24
--- a/include/hw/pci-host/designware.h
17
+++ b/target/arm/helper.c
25
+++ b/include/hw/pci-host/designware.h
18
@@ -XXX,XX +XXX,XX @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
26
@@ -XXX,XX +XXX,XX @@
19
*r2 = *r;
27
#include "hw/pci/pci_bridge.h"
20
r2->name = memcpy(r2 + 1, name, name_len);
28
#include "qom/object.h"
21
29
22
- /* Reset the secure state to the specific incoming state. This is
30
+#define TYPE_DESIGNWARE_PCIE_ROOT_BUS "designware-pcie-root-BUS"
23
- * necessary as the register may have been defined with both states.
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
+
24
+ /*
58
+ /*
25
+ * Update fields to match the instantiation, overwiting wildcards
59
+ * Designware has only a single root complex. Enforce the limit on the
26
+ * such as CP_ANY, ARM_CP_STATE_BOTH, or ARM_CP_SECSTATE_BOTH.
60
+ * parent bus
27
*/
61
+ */
28
+ r2->cp = cp;
62
+ k->max_dev = 1;
29
+ r2->crm = crm;
63
+}
30
+ r2->opc1 = opc1;
31
+ r2->opc2 = opc2;
32
+ r2->state = state;
33
r2->secure = secstate;
34
+ if (opaque) {
35
+ r2->opaque = opaque;
36
+ }
37
38
if (r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1]) {
39
/* Register is banked (using both entries in array).
40
@@ -XXX,XX +XXX,XX @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
41
#endif
42
}
43
}
44
- if (opaque) {
45
- r2->opaque = opaque;
46
- }
47
- /* reginfo passed to helpers is correct for the actual access,
48
- * and is never ARM_CP_STATE_BOTH:
49
- */
50
- r2->state = state;
51
- /* Make sure reginfo passed to helpers for wildcarded regs
52
- * has the correct crm/opc1/opc2 for this reg, not CP_ANY:
53
- */
54
- r2->cp = cp;
55
- r2->crm = crm;
56
- r2->opc1 = opc1;
57
- r2->opc2 = opc2;
58
+
64
+
59
/* By convention, for wildcarded registers only the first
65
static DesignwarePCIEHost *
60
* entry is used for migration; the others are marked as
66
designware_pcie_root_to_host(DesignwarePCIERoot *root)
61
* ALIAS so we don't try to transfer the register
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),
62
--
89
--
63
2.25.1
90
2.43.0
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Bernhard Beschow <shentey@gmail.com>
2
2
3
The new_key field is always non-zero -- drop the if.
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.
4
6
5
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
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
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Message-id: 20220501055028.646596-11-richard.henderson@linaro.org
8
[PMM: reinstated dropped PL3_RW mask]
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
12
---
11
target/arm/helper.c | 23 +++++++++++------------
13
hw/gpio/Kconfig | 8 ++++++++
12
1 file changed, 11 insertions(+), 12 deletions(-)
14
hw/misc/Kconfig | 8 --------
15
2 files changed, 8 insertions(+), 8 deletions(-)
13
16
14
diff --git a/target/arm/helper.c b/target/arm/helper.c
17
diff --git a/hw/gpio/Kconfig b/hw/gpio/Kconfig
15
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
16
--- a/target/arm/helper.c
19
--- a/hw/gpio/Kconfig
17
+++ b/target/arm/helper.c
20
+++ b/hw/gpio/Kconfig
18
@@ -XXX,XX +XXX,XX @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu)
21
@@ -XXX,XX +XXX,XX @@ config SIFIVE_GPIO
19
22
config STM32L4X5_GPIO
20
for (i = 0; i < ARRAY_SIZE(aliases); i++) {
23
bool
21
const struct E2HAlias *a = &aliases[i];
24
22
- ARMCPRegInfo *src_reg, *dst_reg;
25
+config PCA9552
23
+ ARMCPRegInfo *src_reg, *dst_reg, *new_reg;
26
+ bool
24
+ uint32_t *new_key;
27
+ depends on I2C
25
+ bool ok;
28
+
26
29
+config PCA9554
27
if (a->feature && !a->feature(&cpu->isar)) {
30
+ bool
28
continue;
31
+ depends on I2C
29
@@ -XXX,XX +XXX,XX @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu)
32
+
30
g_assert(src_reg->opaque == NULL);
33
config PCF8574
31
34
bool
32
/* Create alias before redirection so we dup the right data. */
35
depends on I2C
33
- if (a->new_key) {
36
diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
34
- ARMCPRegInfo *new_reg = g_memdup(src_reg, sizeof(ARMCPRegInfo));
37
index XXXXXXX..XXXXXXX 100644
35
- uint32_t *new_key = g_memdup(&a->new_key, sizeof(uint32_t));
38
--- a/hw/misc/Kconfig
36
- bool ok;
39
+++ b/hw/misc/Kconfig
37
+ new_reg = g_memdup(src_reg, sizeof(ARMCPRegInfo));
40
@@ -XXX,XX +XXX,XX @@ config EDU
38
+ new_key = g_memdup(&a->new_key, sizeof(uint32_t));
41
default y if TEST_DEVICES
39
42
depends on PCI && MSI_NONBROKEN
40
- new_reg->name = a->new_name;
43
41
- new_reg->type |= ARM_CP_ALIAS;
44
-config PCA9552
42
- /* Remove PL1/PL0 access, leaving PL2/PL3 R/W in place. */
45
- bool
43
- new_reg->access &= PL2_RW | PL3_RW;
46
- depends on I2C
44
+ new_reg->name = a->new_name;
47
-
45
+ new_reg->type |= ARM_CP_ALIAS;
48
-config PCA9554
46
+ /* Remove PL1/PL0 access, leaving PL2/PL3 R/W in place. */
49
- bool
47
+ new_reg->access &= PL2_RW | PL3_RW;
50
- depends on I2C
48
51
-
49
- ok = g_hash_table_insert(cpu->cp_regs, new_key, new_reg);
52
config I2C_ECHO
50
- g_assert(ok);
53
bool
51
- }
54
default y if TEST_DEVICES
52
+ ok = g_hash_table_insert(cpu->cp_regs, new_key, new_reg);
53
+ g_assert(ok);
54
55
src_reg->opaque = dst_reg;
56
src_reg->orig_readfn = src_reg->readfn ?: raw_read;
57
--
55
--
58
2.25.1
56
2.43.0
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Bernhard Beschow <shentey@gmail.com>
2
2
3
This controls whether the PACI{A,B}SP instructions trap with BTYPE=3
3
As a first step, implement the bare minimum: CPUs, RAM, interrupt controller,
4
(indirect branch from register other than x16/x17). The linux kernel
4
serial. All other devices of the A53 memory map are represented as
5
sets this in bti_enable().
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.
6
7
7
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/998
8
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
8
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
9
Message-id: 20250223114708.1780-5-shentey@gmail.com
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Message-id: 20220427042312.294300-1-richard.henderson@linaro.org
11
[PMM: drop 'static const' from serial_table[] definition to avoid
11
[PMM: remove stray change to makefile comment]
12
compile failure on GCC 7.5]
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
---
14
---
14
target/arm/cpu.c | 2 ++
15
MAINTAINERS | 9 +
15
tests/tcg/aarch64/bti-3.c | 42 +++++++++++++++++++++++++++++++
16
docs/system/arm/imx8mp-evk.rst | 54 +++++
16
tests/tcg/aarch64/Makefile.target | 6 ++---
17
docs/system/target-arm.rst | 1 +
17
3 files changed, 47 insertions(+), 3 deletions(-)
18
include/hw/arm/fsl-imx8mp.h | 189 +++++++++++++++++
18
create mode 100644 tests/tcg/aarch64/bti-3.c
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
19
28
20
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
29
diff --git a/MAINTAINERS b/MAINTAINERS
21
index XXXXXXX..XXXXXXX 100644
30
index XXXXXXX..XXXXXXX 100644
22
--- a/target/arm/cpu.c
31
--- a/MAINTAINERS
23
+++ b/target/arm/cpu.c
32
+++ b/MAINTAINERS
24
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_reset(DeviceState *dev)
33
@@ -XXX,XX +XXX,XX @@ F: hw/pci-host/designware.c
25
/* Enable all PAC keys. */
34
F: include/hw/pci-host/designware.h
26
env->cp15.sctlr_el[1] |= (SCTLR_EnIA | SCTLR_EnIB |
35
F: docs/system/arm/mcimx7d-sabre.rst
27
SCTLR_EnDA | SCTLR_EnDB);
36
28
+ /* Trap on btype=3 for PACIxSP. */
37
+MCIMX8MP-EVK / i.MX8MP
29
+ env->cp15.sctlr_el[1] |= SCTLR_BT0;
38
+M: Bernhard Beschow <shentey@gmail.com>
30
/* and to the FP/Neon instructions */
39
+L: qemu-arm@nongnu.org
31
env->cp15.cpacr_el1 = deposit64(env->cp15.cpacr_el1, 20, 2, 3);
40
+S: Maintained
32
/* and to the SVE instructions */
41
+F: hw/arm/imx8mp-evk.c
33
diff --git a/tests/tcg/aarch64/bti-3.c b/tests/tcg/aarch64/bti-3.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
34
new file mode 100644
50
new file mode 100644
35
index XXXXXXX..XXXXXXX
51
index XXXXXXX..XXXXXXX
36
--- /dev/null
52
--- /dev/null
37
+++ b/tests/tcg/aarch64/bti-3.c
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
38
@@ -XXX,XX +XXX,XX @@
126
@@ -XXX,XX +XXX,XX @@
39
+/*
127
+/*
40
+ * BTI vs PACIASP
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
41
+ */
133
+ */
42
+
134
+
43
+#include "bti-crt.inc.c"
135
+#ifndef FSL_IMX8MP_H
44
+
136
+#define FSL_IMX8MP_H
45
+static void skip2_sigill(int sig, siginfo_t *info, ucontext_t *uc)
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)
46
+{
508
+{
47
+ uc->uc_mcontext.pc += 8;
509
+ MachineState *ms = MACHINE(qdev_get_machine());
48
+ uc->uc_mcontext.pstate = 1;
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
+ }
49
+}
525
+}
50
+
526
+
51
+#define BTYPE_1() \
527
+static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
52
+ asm("mov %0,#1; adr x16, 1f; br x16; 1: hint #25; mov %0,#0" \
53
+ : "=r"(skipped) : : "x16", "x30")
54
+
55
+#define BTYPE_2() \
56
+ asm("mov %0,#1; adr x16, 1f; blr x16; 1: hint #25; mov %0,#0" \
57
+ : "=r"(skipped) : : "x16", "x30")
58
+
59
+#define BTYPE_3() \
60
+ asm("mov %0,#1; adr x15, 1f; br x15; 1: hint #25; mov %0,#0" \
61
+ : "=r"(skipped) : : "x15", "x30")
62
+
63
+#define TEST(WHICH, EXPECT) \
64
+ do { WHICH(); fail += skipped ^ EXPECT; } while (0)
65
+
66
+int main()
67
+{
528
+{
68
+ int fail = 0;
529
+ MachineState *ms = MACHINE(qdev_get_machine());
69
+ int skipped;
530
+ FslImx8mpState *s = FSL_IMX8MP(dev);
70
+
531
+ DeviceState *gicdev = DEVICE(&s->gic);
71
+ /* Signal-like with SA_SIGINFO. */
532
+ int i;
72
+ signal_info(SIGILL, skip2_sigill);
533
+
73
+
534
+ if (ms->smp.cpus > FSL_IMX8MP_NUM_CPUS) {
74
+ /* With SCTLR_EL1.BT0 set, PACIASP is not compatible with type=3. */
535
+ error_setg(errp, "%s: Only %d CPUs are supported (%d requested)",
75
+ TEST(BTYPE_1, 0);
536
+ TYPE_FSL_IMX8MP, FSL_IMX8MP_NUM_CPUS, ms->smp.cpus);
76
+ TEST(BTYPE_2, 0);
537
+ return;
77
+ TEST(BTYPE_3, 1);
538
+ }
78
+
539
+
79
+ return fail;
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
+ }
80
+}
667
+}
81
diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target
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
82
index XXXXXXX..XXXXXXX 100644
751
index XXXXXXX..XXXXXXX 100644
83
--- a/tests/tcg/aarch64/Makefile.target
752
--- a/hw/arm/Kconfig
84
+++ b/tests/tcg/aarch64/Makefile.target
753
+++ b/hw/arm/Kconfig
85
@@ -XXX,XX +XXX,XX @@ endif
754
@@ -XXX,XX +XXX,XX @@ config FSL_IMX7
86
# BTI Tests
755
select UNIMP
87
# bti-1 tests the elf notes, so we require special compiler support.
756
select USB_CHIPIDEA
88
ifneq ($(CROSS_CC_HAS_ARMV8_BTI),)
757
89
-AARCH64_TESTS += bti-1
758
+config FSL_IMX8MP
90
-bti-1: CFLAGS += -mbranch-protection=standard
759
+ bool
91
-bti-1: LDFLAGS += -nostdlib
760
+ select ARM_GIC
92
+AARCH64_TESTS += bti-1 bti-3
761
+ select IMX
93
+bti-1 bti-3: CFLAGS += -mbranch-protection=standard
762
+ select UNIMP
94
+bti-1 bti-3: LDFLAGS += -nostdlib
763
+
95
endif
764
+config FSL_IMX8MP_EVK
96
# bti-2 tests PROT_BTI, so no special compiler support required.
765
+ bool
97
AARCH64_TESTS += bti-2
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'))
98
--
786
--
99
2.25.1
787
2.43.0
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Bernhard Beschow <shentey@gmail.com>
2
2
3
Cast the uint32_t key into a gpointer directly, which
3
Fixes quite a few stack traces during the Linux boot process. Also provides the
4
allows us to avoid allocating storage for each key.
4
clocks for devices added later, e.g. enet1.
5
5
6
Use g_hash_table_lookup when we already have a gpointer
6
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
7
(e.g. for callbacks like count_cpreg), or when using
7
Message-id: 20250223114708.1780-6-shentey@gmail.com
8
get_arm_cp_reginfo would require casting away const.
9
10
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
11
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
12
Message-id: 20220501055028.646596-12-richard.henderson@linaro.org
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
---
10
---
15
target/arm/cpu.c | 4 ++--
11
MAINTAINERS | 2 +
16
target/arm/gdbstub.c | 2 +-
12
docs/system/arm/imx8mp-evk.rst | 1 +
17
target/arm/helper.c | 41 ++++++++++++++++++-----------------------
13
include/hw/arm/fsl-imx8mp.h | 4 +
18
3 files changed, 21 insertions(+), 26 deletions(-)
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
19
27
20
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
28
diff --git a/MAINTAINERS b/MAINTAINERS
21
index XXXXXXX..XXXXXXX 100644
29
index XXXXXXX..XXXXXXX 100644
22
--- a/target/arm/cpu.c
30
--- a/MAINTAINERS
23
+++ b/target/arm/cpu.c
31
+++ b/MAINTAINERS
24
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_initfn(Object *obj)
32
@@ -XXX,XX +XXX,XX @@ L: qemu-arm@nongnu.org
25
ARMCPU *cpu = ARM_CPU(obj);
33
S: Maintained
26
34
F: hw/arm/imx8mp-evk.c
27
cpu_set_cpustate_pointers(cpu);
35
F: hw/arm/fsl-imx8mp.c
28
- cpu->cp_regs = g_hash_table_new_full(g_int_hash, g_int_equal,
36
+F: hw/misc/imx8mp_*.c
29
- g_free, cpreg_hashtable_data_destroy);
37
F: include/hw/arm/fsl-imx8mp.h
30
+ cpu->cp_regs = g_hash_table_new_full(g_direct_hash, g_direct_equal,
38
+F: include/hw/misc/imx8mp_*.h
31
+ NULL, cpreg_hashtable_data_destroy);
39
F: docs/system/arm/imx8mp-evk.rst
32
40
33
QLIST_INIT(&cpu->pre_el_change_hooks);
41
MPS2 / MPS3
34
QLIST_INIT(&cpu->el_change_hooks);
42
diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8mp-evk.rst
35
diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c
36
index XXXXXXX..XXXXXXX 100644
43
index XXXXXXX..XXXXXXX 100644
37
--- a/target/arm/gdbstub.c
44
--- a/docs/system/arm/imx8mp-evk.rst
38
+++ b/target/arm/gdbstub.c
45
+++ b/docs/system/arm/imx8mp-evk.rst
39
@@ -XXX,XX +XXX,XX @@ static void arm_gen_one_xml_sysreg_tag(GString *s, DynamicGDBXMLInfo *dyn_xml,
46
@@ -XXX,XX +XXX,XX @@ The ``imx8mp-evk`` machine implements the following devices:
40
static void arm_register_sysreg_for_xml(gpointer key, gpointer value,
47
* Up to 4 Cortex-A53 cores
41
gpointer p)
48
* Generic Interrupt Controller (GICv3)
42
{
49
* 4 UARTs
43
- uint32_t ri_key = *(uint32_t *)key;
50
+ * Clock Tree
44
+ uint32_t ri_key = (uintptr_t)key;
51
45
ARMCPRegInfo *ri = value;
52
Boot options
46
RegisterSysregXmlParam *param = (RegisterSysregXmlParam *)p;
53
------------
47
GString *s = param->s;
54
diff --git a/include/hw/arm/fsl-imx8mp.h b/include/hw/arm/fsl-imx8mp.h
48
diff --git a/target/arm/helper.c b/target/arm/helper.c
49
index XXXXXXX..XXXXXXX 100644
55
index XXXXXXX..XXXXXXX 100644
50
--- a/target/arm/helper.c
56
--- a/include/hw/arm/fsl-imx8mp.h
51
+++ b/target/arm/helper.c
57
+++ b/include/hw/arm/fsl-imx8mp.h
52
@@ -XXX,XX +XXX,XX @@ bool write_list_to_cpustate(ARMCPU *cpu)
58
@@ -XXX,XX +XXX,XX @@
53
static void add_cpreg_to_list(gpointer key, gpointer opaque)
59
#include "cpu.h"
54
{
60
#include "hw/char/imx_serial.h"
55
ARMCPU *cpu = opaque;
61
#include "hw/intc/arm_gicv3_common.h"
56
- uint64_t regidx;
62
+#include "hw/misc/imx8mp_analog.h"
57
- const ARMCPRegInfo *ri;
63
+#include "hw/misc/imx8mp_ccm.h"
58
-
64
#include "qom/object.h"
59
- regidx = *(uint32_t *)key;
65
#include "qemu/units.h"
60
- ri = get_arm_cp_reginfo(cpu->cp_regs, regidx);
66
61
+ uint32_t regidx = (uintptr_t)key;
67
@@ -XXX,XX +XXX,XX @@ struct FslImx8mpState {
62
+ const ARMCPRegInfo *ri = get_arm_cp_reginfo(cpu->cp_regs, regidx);
68
63
69
ARMCPU cpu[FSL_IMX8MP_NUM_CPUS];
64
if (!(ri->type & (ARM_CP_NO_RAW|ARM_CP_ALIAS))) {
70
GICv3State gic;
65
cpu->cpreg_indexes[cpu->cpreg_array_len] = cpreg_to_kvm_id(regidx);
71
+ IMX8MPCCMState ccm;
66
@@ -XXX,XX +XXX,XX @@ static void add_cpreg_to_list(gpointer key, gpointer opaque)
72
+ IMX8MPAnalogState analog;
67
static void count_cpreg(gpointer key, gpointer opaque)
73
IMXSerialState uart[FSL_IMX8MP_NUM_UARTS];
68
{
74
};
69
ARMCPU *cpu = opaque;
75
70
- uint64_t regidx;
76
diff --git a/include/hw/misc/imx8mp_analog.h b/include/hw/misc/imx8mp_analog.h
71
const ARMCPRegInfo *ri;
77
new file mode 100644
72
78
index XXXXXXX..XXXXXXX
73
- regidx = *(uint32_t *)key;
79
--- /dev/null
74
- ri = get_arm_cp_reginfo(cpu->cp_regs, regidx);
80
+++ b/include/hw/misc/imx8mp_analog.h
75
+ ri = g_hash_table_lookup(cpu->cp_regs, key);
81
@@ -XXX,XX +XXX,XX @@
76
82
+/*
77
if (!(ri->type & (ARM_CP_NO_RAW|ARM_CP_ALIAS))) {
83
+ * Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
78
cpu->cpreg_array_len++;
84
+ *
79
@@ -XXX,XX +XXX,XX @@ static void count_cpreg(gpointer key, gpointer opaque)
85
+ * i.MX8MP ANALOG IP block emulation code
80
86
+ *
81
static gint cpreg_key_compare(gconstpointer a, gconstpointer b)
87
+ * SPDX-License-Identifier: GPL-2.0-or-later
82
{
88
+ */
83
- uint64_t aidx = cpreg_to_kvm_id(*(uint32_t *)a);
89
+
84
- uint64_t bidx = cpreg_to_kvm_id(*(uint32_t *)b);
90
+#ifndef IMX8MP_ANALOG_H
85
+ uint64_t aidx = cpreg_to_kvm_id((uintptr_t)a);
91
+#define IMX8MP_ANALOG_H
86
+ uint64_t bidx = cpreg_to_kvm_id((uintptr_t)b);
92
+
87
93
+#include "qom/object.h"
88
if (aidx > bidx) {
94
+#include "hw/sysbus.h"
89
return 1;
95
+
90
@@ -XXX,XX +XXX,XX @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu)
96
+enum IMX8MPAnalogRegisters {
91
for (i = 0; i < ARRAY_SIZE(aliases); i++) {
97
+ ANALOG_AUDIO_PLL1_GEN_CTRL = 0x000 / 4,
92
const struct E2HAlias *a = &aliases[i];
98
+ ANALOG_AUDIO_PLL1_FDIV_CTL0 = 0x004 / 4,
93
ARMCPRegInfo *src_reg, *dst_reg, *new_reg;
99
+ ANALOG_AUDIO_PLL1_FDIV_CTL1 = 0x008 / 4,
94
- uint32_t *new_key;
100
+ ANALOG_AUDIO_PLL1_SSCG_CTRL = 0x00c / 4,
95
bool ok;
101
+ ANALOG_AUDIO_PLL1_MNIT_CTRL = 0x010 / 4,
96
102
+ ANALOG_AUDIO_PLL2_GEN_CTRL = 0x014 / 4,
97
if (a->feature && !a->feature(&cpu->isar)) {
103
+ ANALOG_AUDIO_PLL2_FDIV_CTL0 = 0x018 / 4,
98
continue;
104
+ ANALOG_AUDIO_PLL2_FDIV_CTL1 = 0x01c / 4,
99
}
105
+ ANALOG_AUDIO_PLL2_SSCG_CTRL = 0x020 / 4,
100
106
+ ANALOG_AUDIO_PLL2_MNIT_CTRL = 0x024 / 4,
101
- src_reg = g_hash_table_lookup(cpu->cp_regs, &a->src_key);
107
+ ANALOG_VIDEO_PLL1_GEN_CTRL = 0x028 / 4,
102
- dst_reg = g_hash_table_lookup(cpu->cp_regs, &a->dst_key);
108
+ ANALOG_VIDEO_PLL1_FDIV_CTL0 = 0x02c / 4,
103
+ src_reg = g_hash_table_lookup(cpu->cp_regs,
109
+ ANALOG_VIDEO_PLL1_FDIV_CTL1 = 0x030 / 4,
104
+ (gpointer)(uintptr_t)a->src_key);
110
+ ANALOG_VIDEO_PLL1_SSCG_CTRL = 0x034 / 4,
105
+ dst_reg = g_hash_table_lookup(cpu->cp_regs,
111
+ ANALOG_VIDEO_PLL1_MNIT_CTRL = 0x038 / 4,
106
+ (gpointer)(uintptr_t)a->dst_key);
112
+ ANALOG_DRAM_PLL_GEN_CTRL = 0x050 / 4,
107
g_assert(src_reg != NULL);
113
+ ANALOG_DRAM_PLL_FDIV_CTL0 = 0x054 / 4,
108
g_assert(dst_reg != NULL);
114
+ ANALOG_DRAM_PLL_FDIV_CTL1 = 0x058 / 4,
109
115
+ ANALOG_DRAM_PLL_SSCG_CTRL = 0x05c / 4,
110
@@ -XXX,XX +XXX,XX @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu)
116
+ ANALOG_DRAM_PLL_MNIT_CTRL = 0x060 / 4,
111
117
+ ANALOG_GPU_PLL_GEN_CTRL = 0x064 / 4,
112
/* Create alias before redirection so we dup the right data. */
118
+ ANALOG_GPU_PLL_FDIV_CTL0 = 0x068 / 4,
113
new_reg = g_memdup(src_reg, sizeof(ARMCPRegInfo));
119
+ ANALOG_GPU_PLL_LOCKD_CTRL = 0x06c / 4,
114
- new_key = g_memdup(&a->new_key, sizeof(uint32_t));
120
+ ANALOG_GPU_PLL_MNIT_CTRL = 0x070 / 4,
115
121
+ ANALOG_VPU_PLL_GEN_CTRL = 0x074 / 4,
116
new_reg->name = a->new_name;
122
+ ANALOG_VPU_PLL_FDIV_CTL0 = 0x078 / 4,
117
new_reg->type |= ARM_CP_ALIAS;
123
+ ANALOG_VPU_PLL_LOCKD_CTRL = 0x07c / 4,
118
/* Remove PL1/PL0 access, leaving PL2/PL3 R/W in place. */
124
+ ANALOG_VPU_PLL_MNIT_CTRL = 0x080 / 4,
119
new_reg->access &= PL2_RW | PL3_RW;
125
+ ANALOG_ARM_PLL_GEN_CTRL = 0x084 / 4,
120
126
+ ANALOG_ARM_PLL_FDIV_CTL0 = 0x088 / 4,
121
- ok = g_hash_table_insert(cpu->cp_regs, new_key, new_reg);
127
+ ANALOG_ARM_PLL_LOCKD_CTRL = 0x08c / 4,
122
+ ok = g_hash_table_insert(cpu->cp_regs,
128
+ ANALOG_ARM_PLL_MNIT_CTRL = 0x090 / 4,
123
+ (gpointer)(uintptr_t)a->new_key, new_reg);
129
+ ANALOG_SYS_PLL1_GEN_CTRL = 0x094 / 4,
124
g_assert(ok);
130
+ ANALOG_SYS_PLL1_FDIV_CTL0 = 0x098 / 4,
125
131
+ ANALOG_SYS_PLL1_LOCKD_CTRL = 0x09c / 4,
126
src_reg->opaque = dst_reg;
132
+ ANALOG_SYS_PLL1_MNIT_CTRL = 0x100 / 4,
127
@@ -XXX,XX +XXX,XX @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
133
+ ANALOG_SYS_PLL2_GEN_CTRL = 0x104 / 4,
128
/* Private utility function for define_one_arm_cp_reg_with_opaque():
134
+ ANALOG_SYS_PLL2_FDIV_CTL0 = 0x108 / 4,
129
* add a single reginfo struct to the hash table.
135
+ ANALOG_SYS_PLL2_LOCKD_CTRL = 0x10c / 4,
130
*/
136
+ ANALOG_SYS_PLL2_MNIT_CTRL = 0x110 / 4,
131
- uint32_t *key = g_new(uint32_t, 1);
137
+ ANALOG_SYS_PLL3_GEN_CTRL = 0x114 / 4,
132
+ uint32_t key;
138
+ ANALOG_SYS_PLL3_FDIV_CTL0 = 0x118 / 4,
133
ARMCPRegInfo *r2 = g_memdup(r, sizeof(ARMCPRegInfo));
139
+ ANALOG_SYS_PLL3_LOCKD_CTRL = 0x11c / 4,
134
int is64 = (r->type & ARM_CP_64BIT) ? 1 : 0;
140
+ ANALOG_SYS_PLL3_MNIT_CTRL = 0x120 / 4,
135
int ns = (secstate & ARM_CP_SECSTATE_NS) ? 1 : 0;
141
+ ANALOG_OSC_MISC_CFG = 0x124 / 4,
136
@@ -XXX,XX +XXX,XX @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
142
+ ANALOG_ANAMIX_PLL_MNIT_CTL = 0x128 / 4,
137
if (r->cp == 0 || r->state == ARM_CP_STATE_BOTH) {
143
+
138
r2->cp = CP_REG_ARM64_SYSREG_CP;
144
+ ANALOG_DIGPROG = 0x800 / 4,
139
}
145
+ ANALOG_MAX,
140
- *key = ENCODE_AA64_CP_REG(r2->cp, r2->crn, crm,
146
+};
141
- r2->opc0, opc1, opc2);
147
+
142
+ key = ENCODE_AA64_CP_REG(r2->cp, r2->crn, crm,
148
+#define TYPE_IMX8MP_ANALOG "imx8mp.analog"
143
+ r2->opc0, opc1, opc2);
149
+OBJECT_DECLARE_SIMPLE_TYPE(IMX8MPAnalogState, IMX8MP_ANALOG)
144
} else {
150
+
145
- *key = ENCODE_CP_REG(r2->cp, is64, ns, r2->crn, crm, opc1, opc2);
151
+struct IMX8MPAnalogState {
146
+ key = ENCODE_CP_REG(r2->cp, is64, ns, r2->crn, crm, opc1, opc2);
152
+ SysBusDevice parent_obj;
147
}
153
+
148
if (opaque) {
154
+ struct {
149
r2->opaque = opaque;
155
+ MemoryRegion container;
150
@@ -XXX,XX +XXX,XX @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
156
+ MemoryRegion analog;
151
* requested.
157
+ } mmio;
152
*/
158
+
153
if (!(r->type & ARM_CP_OVERRIDE)) {
159
+ uint32_t analog[ANALOG_MAX];
154
- ARMCPRegInfo *oldreg;
160
+};
155
- oldreg = g_hash_table_lookup(cpu->cp_regs, key);
161
+
156
+ const ARMCPRegInfo *oldreg = get_arm_cp_reginfo(cpu->cp_regs, key);
162
+#endif /* IMX8MP_ANALOG_H */
157
if (oldreg && !(oldreg->type & ARM_CP_OVERRIDE)) {
163
diff --git a/include/hw/misc/imx8mp_ccm.h b/include/hw/misc/imx8mp_ccm.h
158
fprintf(stderr, "Register redefined: cp=%d %d bit "
164
new file mode 100644
159
"crn=%d crm=%d opc1=%d opc2=%d, "
165
index XXXXXXX..XXXXXXX
160
@@ -XXX,XX +XXX,XX @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
166
--- /dev/null
161
g_assert_not_reached();
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)
162
}
215
}
163
}
216
}
164
- g_hash_table_insert(cpu->cp_regs, key, r2);
217
165
+ g_hash_table_insert(cpu->cp_regs, (gpointer)(uintptr_t)key, r2);
218
+ /* CCM */
166
}
219
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->ccm), errp)) {
167
220
+ return;
168
221
+ }
169
@@ -XXX,XX +XXX,XX @@ void modify_arm_cp_regs_with_len(ARMCPRegInfo *regs, size_t regs_len,
222
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccm), 0,
170
223
+ fsl_imx8mp_memmap[FSL_IMX8MP_CCM].addr);
171
const ARMCPRegInfo *get_arm_cp_reginfo(GHashTable *cpregs, uint32_t encoded_cp)
224
+
172
{
225
+ /* Analog */
173
- return g_hash_table_lookup(cpregs, &encoded_cp);
226
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->analog), errp)) {
174
+ return g_hash_table_lookup(cpregs, (gpointer)(uintptr_t)encoded_cp);
227
+ return;
175
}
228
+ }
176
229
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->analog), 0,
177
void arm_cp_write_ignore(CPUARMState *env, const ARMCPRegInfo *ri,
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',
178
--
634
--
179
2.25.1
635
2.43.0
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Bernhard Beschow <shentey@gmail.com>
2
2
3
Since e03b56863d2bc, our host endian indicator is unconditionally
3
SNVS contains an RTC which allows Linux to deal correctly with time. This is
4
set, which means that we can use a normal C condition.
4
particularly useful when handling persistent storage which will be done in the
5
next patch.
5
6
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Message-id: 20220501055028.646596-20-richard.henderson@linaro.org
8
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
9
[PMM: quote correct git hash in commit message]
9
Message-id: 20250223114708.1780-7-shentey@gmail.com
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
11
---
12
target/arm/helper.c | 9 +++------
12
docs/system/arm/imx8mp-evk.rst | 1 +
13
1 file changed, 3 insertions(+), 6 deletions(-)
13
include/hw/arm/fsl-imx8mp.h | 2 ++
14
hw/arm/fsl-imx8mp.c | 10 ++++++++++
15
3 files changed, 13 insertions(+)
14
16
15
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
16
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
17
--- a/target/arm/helper.c
19
--- a/docs/system/arm/imx8mp-evk.rst
18
+++ b/target/arm/helper.c
20
+++ b/docs/system/arm/imx8mp-evk.rst
19
@@ -XXX,XX +XXX,XX @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
21
@@ -XXX,XX +XXX,XX @@ The ``imx8mp-evk`` machine implements the following devices:
20
r2->type |= ARM_CP_ALIAS;
22
* Up to 4 Cortex-A53 cores
21
}
23
* Generic Interrupt Controller (GICv3)
22
24
* 4 UARTs
23
- if (r->state == ARM_CP_STATE_BOTH) {
25
+ * Secure Non-Volatile Storage (SNVS) including an RTC
24
-#if HOST_BIG_ENDIAN
26
* Clock Tree
25
- if (r2->fieldoffset) {
27
26
- r2->fieldoffset += sizeof(uint32_t);
28
Boot options
27
- }
29
diff --git a/include/hw/arm/fsl-imx8mp.h b/include/hw/arm/fsl-imx8mp.h
28
-#endif
30
index XXXXXXX..XXXXXXX 100644
29
+ if (HOST_BIG_ENDIAN &&
31
--- a/include/hw/arm/fsl-imx8mp.h
30
+ r->state == ARM_CP_STATE_BOTH && r2->fieldoffset) {
32
+++ b/include/hw/arm/fsl-imx8mp.h
31
+ r2->fieldoffset += sizeof(uint32_t);
33
@@ -XXX,XX +XXX,XX @@
32
}
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));
33
}
64
}
34
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;
35
--
84
--
36
2.25.1
85
2.43.0
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Bernhard Beschow <shentey@gmail.com>
2
2
3
Give this enum a name and use in ARMCPRegInfo and add_cpreg_to_hashtable.
3
The USDHC emulation allows for running real-world images such as those generated
4
Add the enumerator ARM_CP_SECSTATE_BOTH to clarify how 0
4
by Buildroot. Convert the board documentation accordingly instead of running a
5
is handled in define_one_arm_cp_reg_with_opaque.
5
Linux kernel with ephemeral storage.
6
6
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
9
Message-id: 20220501055028.646596-10-richard.henderson@linaro.org
9
Message-id: 20250223114708.1780-8-shentey@gmail.com
10
[PMM: drop 'static const' from usdhc_table[] for GCC 7.5]
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
12
---
12
target/arm/cpregs.h | 7 ++++---
13
docs/system/arm/imx8mp-evk.rst | 18 ++++++++++++------
13
target/arm/helper.c | 7 +++++--
14
include/hw/arm/fsl-imx8mp.h | 7 +++++++
14
2 files changed, 9 insertions(+), 5 deletions(-)
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(-)
15
19
16
diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
20
diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8mp-evk.rst
17
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
18
--- a/target/arm/cpregs.h
22
--- a/docs/system/arm/imx8mp-evk.rst
19
+++ b/target/arm/cpregs.h
23
+++ b/docs/system/arm/imx8mp-evk.rst
20
@@ -XXX,XX +XXX,XX @@ typedef enum {
24
@@ -XXX,XX +XXX,XX @@ The ``imx8mp-evk`` machine implements the following devices:
21
* registered entry will only have one to identify whether the entry is secure
25
* Up to 4 Cortex-A53 cores
22
* or non-secure.
26
* Generic Interrupt Controller (GICv3)
23
*/
27
* 4 UARTs
24
-enum {
28
+ * 3 USDHC Storage Controllers
25
+typedef enum {
29
* Secure Non-Volatile Storage (SNVS) including an RTC
26
+ ARM_CP_SECSTATE_BOTH = 0, /* define one cpreg for each secstate */
30
* Clock Tree
27
ARM_CP_SECSTATE_S = (1 << 0), /* bit[0]: Secure state register */
31
28
ARM_CP_SECSTATE_NS = (1 << 1), /* bit[1]: Non-secure state register */
32
@@ -XXX,XX +XXX,XX @@ Direct Linux Kernel Boot
29
-};
33
30
+} CPSecureState;
34
Probably the easiest way to get started with a whole Linux system on the machine
31
35
is to generate an image with Buildroot. Version 2024.11.1 is tested at the time
32
/*
36
-of writing and involves two steps. First run the following commands in the
33
* Access rights:
37
+of writing and involves three steps. First run the following commands in the
34
@@ -XXX,XX +XXX,XX @@ struct ARMCPRegInfo {
38
toplevel directory of the Buildroot source tree:
35
/* Access rights: PL*_[RW] */
39
36
CPAccessRights access;
40
.. code-block:: bash
37
/* Security state: ARM_CP_SECSTATE_* bits/values */
41
38
- int secure;
42
- $ echo "BR2_TARGET_ROOTFS_CPIO=y" >> configs/freescale_imx8mpevk_defconfig
39
+ CPSecureState secure;
43
$ make freescale_imx8mpevk_defconfig
40
/*
44
$ make
41
* The opaque pointer passed to define_arm_cp_regs_with_opaque() when
45
42
* this register was defined: can be used to hand data through to the
46
Once finished successfully there is an ``output/image`` subfolder. Navigate into
43
diff --git a/target/arm/helper.c b/target/arm/helper.c
47
-it and patch the device tree with the following commands which will remove the
44
index XXXXXXX..XXXXXXX 100644
48
-``cpu-idle-states`` properties from CPU nodes:
45
--- a/target/arm/helper.c
49
+it and resize the SD card image to a power of two:
46
+++ b/target/arm/helper.c
50
+
47
@@ -XXX,XX +XXX,XX @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
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
+ }
48
}
120
}
49
121
50
static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
122
static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
51
- void *opaque, CPState state, int secstate,
123
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
52
+ void *opaque, CPState state,
124
qdev_get_gpio_in(gicdev, serial_table[i].irq));
53
+ CPSecureState secstate,
125
}
54
int crm, int opc1, int opc2,
126
55
const char *name)
127
+ /* USDHCs */
56
{
128
+ for (i = 0; i < FSL_IMX8MP_NUM_USDHCS; i++) {
57
@@ -XXX,XX +XXX,XX @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
129
+ struct {
58
r->secure, crm, opc1, opc2,
130
+ hwaddr addr;
59
r->name);
131
+ unsigned int irq;
60
break;
132
+ } usdhc_table[FSL_IMX8MP_NUM_USDHCS] = {
61
- default:
133
+ { fsl_imx8mp_memmap[FSL_IMX8MP_USDHC1].addr, FSL_IMX8MP_USDHC1_IRQ },
62
+ case ARM_CP_SECSTATE_BOTH:
134
+ { fsl_imx8mp_memmap[FSL_IMX8MP_USDHC2].addr, FSL_IMX8MP_USDHC2_IRQ },
63
name = g_strdup_printf("%s_S", r->name);
135
+ { fsl_imx8mp_memmap[FSL_IMX8MP_USDHC3].addr, FSL_IMX8MP_USDHC3_IRQ },
64
add_cpreg_to_hashtable(cpu, r, opaque, state,
136
+ };
65
ARM_CP_SECSTATE_S,
137
+
66
@@ -XXX,XX +XXX,XX @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
138
+ object_property_set_uint(OBJECT(&s->usdhc[i]), "vendor",
67
ARM_CP_SECSTATE_NS,
139
+ SDHCI_VENDOR_IMX, &error_abort);
68
crm, opc1, opc2, r->name);
140
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->usdhc[i]), errp)) {
69
break;
141
+ return;
70
+ default:
142
+ }
71
+ g_assert_not_reached();
143
+
72
}
144
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->usdhc[i]), 0, usdhc_table[i].addr);
73
} else {
145
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->usdhc[i]), 0,
74
/* AArch64 registers get mapped to non-secure instance
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
75
--
208
--
76
2.25.1
209
2.43.0
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Bernhard Beschow <shentey@gmail.com>
2
2
3
Move ARMCPRegInfo and all related declarations to a new
3
Linux checks for the PLLs in the PHY to be locked, so implement a model
4
internal header, out of the public cpu.h.
4
emulating that.
5
5
6
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
6
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
7
Message-id: 20250223114708.1780-9-shentey@gmail.com
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
9
Message-id: 20220501055028.646596-2-richard.henderson@linaro.org
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
10
---
12
target/arm/cpregs.h | 413 +++++++++++++++++++++++++++++++++++++
11
MAINTAINERS | 2 +
13
target/arm/cpu.h | 368 ---------------------------------
12
docs/system/arm/imx8mp-evk.rst | 1 +
14
hw/arm/pxa2xx.c | 1 +
13
include/hw/arm/fsl-imx8mp.h | 10 +++
15
hw/arm/pxa2xx_pic.c | 1 +
14
include/hw/pci-host/fsl_imx8m_phy.h | 28 +++++++++
16
hw/intc/arm_gicv3_cpuif.c | 1 +
15
hw/arm/fsl-imx8mp.c | 30 +++++++++
17
hw/intc/arm_gicv3_kvm.c | 2 +
16
hw/pci-host/fsl_imx8m_phy.c | 98 +++++++++++++++++++++++++++++
18
target/arm/cpu.c | 1 +
17
hw/arm/Kconfig | 3 +
19
target/arm/cpu64.c | 1 +
18
hw/pci-host/Kconfig | 3 +
20
target/arm/cpu_tcg.c | 1 +
19
hw/pci-host/meson.build | 1 +
21
target/arm/gdbstub.c | 3 +-
20
9 files changed, 176 insertions(+)
22
target/arm/helper.c | 1 +
21
create mode 100644 include/hw/pci-host/fsl_imx8m_phy.h
23
target/arm/op_helper.c | 1 +
22
create mode 100644 hw/pci-host/fsl_imx8m_phy.c
24
target/arm/translate-a64.c | 4 +-
25
target/arm/translate.c | 3 +-
26
14 files changed, 427 insertions(+), 374 deletions(-)
27
create mode 100644 target/arm/cpregs.h
28
23
29
diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
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
30
new file mode 100644
87
new file mode 100644
31
index XXXXXXX..XXXXXXX
88
index XXXXXXX..XXXXXXX
32
--- /dev/null
89
--- /dev/null
33
+++ b/target/arm/cpregs.h
90
+++ b/include/hw/pci-host/fsl_imx8m_phy.h
34
@@ -XXX,XX +XXX,XX @@
91
@@ -XXX,XX +XXX,XX @@
35
+/*
92
+/*
36
+ * QEMU ARM CP Register access and descriptions
93
+ * i.MX8 PCIe PHY emulation
37
+ *
94
+ *
38
+ * Copyright (c) 2022 Linaro Ltd
95
+ * Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
39
+ *
96
+ *
40
+ * This program is free software; you can redistribute it and/or
97
+ * SPDX-License-Identifier: GPL-2.0-or-later
41
+ * modify it under the terms of the GNU General Public License
98
+ */
42
+ * as published by the Free Software Foundation; either version 2
99
+
43
+ * of the License, or (at your option) any later version.
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
44
+ *
183
+ *
45
+ * This program is distributed in the hope that it will be useful,
184
+ * Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
46
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
47
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
48
+ * GNU General Public License for more details.
49
+ *
185
+ *
50
+ * You should have received a copy of the GNU General Public License
186
+ * SPDX-License-Identifier: GPL-2.0-or-later
51
+ * along with this program; if not, see
52
+ * <http://www.gnu.org/licenses/gpl-2.0.html>
53
+ */
187
+ */
54
+
188
+
55
+#ifndef TARGET_ARM_CPREGS_H
189
+#include "qemu/osdep.h"
56
+#define TARGET_ARM_CPREGS_H
190
+#include "hw/pci-host/fsl_imx8m_phy.h"
57
+
191
+#include "hw/resettable.h"
58
+/*
192
+#include "migration/vmstate.h"
59
+ * ARMCPRegInfo type field bits. If the SPECIAL bit is set this is a
193
+
60
+ * special-behaviour cp reg and bits [11..8] indicate what behaviour
194
+#define CMN_REG075 0x1d4
61
+ * it has. Otherwise it is a simple cp reg, where CONST indicates that
195
+#define ANA_PLL_LOCK_DONE BIT(1)
62
+ * TCG can assume the value to be constant (ie load at translate time)
196
+#define ANA_PLL_AFC_DONE BIT(0)
63
+ * and 64BIT indicates a 64 bit wide coprocessor register. SUPPRESS_TB_END
197
+
64
+ * indicates that the TB should not be ended after a write to this register
198
+static uint64_t fsl_imx8m_pcie_phy_read(void *opaque, hwaddr offset,
65
+ * (the default is that the TB ends after cp writes). OVERRIDE permits
199
+ unsigned size)
66
+ * a register definition to override a previous definition for the
200
+{
67
+ * same (cp, is64, crn, crm, opc1, opc2) tuple: either the new or the
201
+ FslImx8mPciePhyState *s = opaque;
68
+ * old must have the OVERRIDE bit set.
202
+
69
+ * ALIAS indicates that this register is an alias view of some underlying
203
+ if (offset == CMN_REG075) {
70
+ * state which is also visible via another register, and that the other
204
+ return s->data[offset] | ANA_PLL_LOCK_DONE | ANA_PLL_AFC_DONE;
71
+ * register is handling migration and reset; registers marked ALIAS will not be
205
+ }
72
+ * migrated but may have their state set by syncing of register state from KVM.
206
+
73
+ * NO_RAW indicates that this register has no underlying state and does not
207
+ return s->data[offset];
74
+ * support raw access for state saving/loading; it will not be used for either
208
+}
75
+ * migration or KVM state synchronization. (Typically this is for "registers"
209
+
76
+ * which are actually used as instructions for cache maintenance and so on.)
210
+static void fsl_imx8m_pcie_phy_write(void *opaque, hwaddr offset,
77
+ * IO indicates that this register does I/O and therefore its accesses
211
+ uint64_t value, unsigned size)
78
+ * need to be marked with gen_io_start() and also end the TB. In particular,
212
+{
79
+ * registers which implement clocks or timers require this.
213
+ FslImx8mPciePhyState *s = opaque;
80
+ * RAISES_EXC is for when the read or write hook might raise an exception;
214
+
81
+ * the generated code will synchronize the CPU state before calling the hook
215
+ s->data[offset] = value;
82
+ * so that it is safe for the hook to call raise_exception().
216
+}
83
+ * NEWEL is for writes to registers that might change the exception
217
+
84
+ * level - typically on older ARM chips. For those cases we need to
218
+static const MemoryRegionOps fsl_imx8m_pcie_phy_ops = {
85
+ * re-read the new el when recomputing the translation flags.
219
+ .read = fsl_imx8m_pcie_phy_read,
86
+ */
220
+ .write = fsl_imx8m_pcie_phy_write,
87
+#define ARM_CP_SPECIAL 0x0001
221
+ .impl = {
88
+#define ARM_CP_CONST 0x0002
222
+ .min_access_size = 1,
89
+#define ARM_CP_64BIT 0x0004
223
+ .max_access_size = 1,
90
+#define ARM_CP_SUPPRESS_TB_END 0x0008
224
+ },
91
+#define ARM_CP_OVERRIDE 0x0010
225
+ .valid = {
92
+#define ARM_CP_ALIAS 0x0020
226
+ .min_access_size = 1,
93
+#define ARM_CP_IO 0x0040
227
+ .max_access_size = 8,
94
+#define ARM_CP_NO_RAW 0x0080
228
+ },
95
+#define ARM_CP_NOP (ARM_CP_SPECIAL | 0x0100)
229
+ .endianness = DEVICE_LITTLE_ENDIAN,
96
+#define ARM_CP_WFI (ARM_CP_SPECIAL | 0x0200)
97
+#define ARM_CP_NZCV (ARM_CP_SPECIAL | 0x0300)
98
+#define ARM_CP_CURRENTEL (ARM_CP_SPECIAL | 0x0400)
99
+#define ARM_CP_DC_ZVA (ARM_CP_SPECIAL | 0x0500)
100
+#define ARM_CP_DC_GVA (ARM_CP_SPECIAL | 0x0600)
101
+#define ARM_CP_DC_GZVA (ARM_CP_SPECIAL | 0x0700)
102
+#define ARM_LAST_SPECIAL ARM_CP_DC_GZVA
103
+#define ARM_CP_FPU 0x1000
104
+#define ARM_CP_SVE 0x2000
105
+#define ARM_CP_NO_GDB 0x4000
106
+#define ARM_CP_RAISES_EXC 0x8000
107
+#define ARM_CP_NEWEL 0x10000
108
+/* Used only as a terminator for ARMCPRegInfo lists */
109
+#define ARM_CP_SENTINEL 0xfffff
110
+/* Mask of only the flag bits in a type field */
111
+#define ARM_CP_FLAG_MASK 0x1f0ff
112
+
113
+/*
114
+ * Valid values for ARMCPRegInfo state field, indicating which of
115
+ * the AArch32 and AArch64 execution states this register is visible in.
116
+ * If the reginfo doesn't explicitly specify then it is AArch32 only.
117
+ * If the reginfo is declared to be visible in both states then a second
118
+ * reginfo is synthesised for the AArch32 view of the AArch64 register,
119
+ * such that the AArch32 view is the lower 32 bits of the AArch64 one.
120
+ * Note that we rely on the values of these enums as we iterate through
121
+ * the various states in some places.
122
+ */
123
+enum {
124
+ ARM_CP_STATE_AA32 = 0,
125
+ ARM_CP_STATE_AA64 = 1,
126
+ ARM_CP_STATE_BOTH = 2,
127
+};
230
+};
128
+
231
+
129
+/*
232
+static void fsl_imx8m_pcie_phy_realize(DeviceState *dev, Error **errp)
130
+ * ARM CP register secure state flags. These flags identify security state
233
+{
131
+ * attributes for a given CP register entry.
234
+ FslImx8mPciePhyState *s = FSL_IMX8M_PCIE_PHY(dev);
132
+ * The existence of both or neither secure and non-secure flags indicates that
235
+
133
+ * the register has both a secure and non-secure hash entry. A single one of
236
+ memory_region_init_io(&s->iomem, OBJECT(s), &fsl_imx8m_pcie_phy_ops, s,
134
+ * these flags causes the register to only be hashed for the specified
237
+ TYPE_FSL_IMX8M_PCIE_PHY, ARRAY_SIZE(s->data));
135
+ * security state.
238
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
136
+ * Although definitions may have any combination of the S/NS bits, each
239
+}
137
+ * registered entry will only have one to identify whether the entry is secure
240
+
138
+ * or non-secure.
241
+static void fsl_imx8m_pcie_phy_reset_hold(Object *obj, ResetType type)
139
+ */
242
+{
140
+enum {
243
+ FslImx8mPciePhyState *s = FSL_IMX8M_PCIE_PHY(obj);
141
+ ARM_CP_SECSTATE_S = (1 << 0), /* bit[0]: Secure state register */
244
+
142
+ ARM_CP_SECSTATE_NS = (1 << 1), /* bit[1]: Non-secure state register */
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
+ }
143
+};
257
+};
144
+
258
+
145
+/*
259
+static void fsl_imx8m_pcie_phy_class_init(ObjectClass *klass, void *data)
146
+ * Return true if cptype is a valid type field. This is used to try to
260
+{
147
+ * catch errors where the sentinel has been accidentally left off the end
261
+ DeviceClass *dc = DEVICE_CLASS(klass);
148
+ * of a list of registers.
262
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
149
+ */
263
+
150
+static inline bool cptype_valid(int cptype)
264
+ dc->realize = fsl_imx8m_pcie_phy_realize;
151
+{
265
+ dc->vmsd = &fsl_imx8m_pcie_phy_vmstate;
152
+ return ((cptype & ~ARM_CP_FLAG_MASK) == 0)
266
+ rc->phases.hold = fsl_imx8m_pcie_phy_reset_hold;
153
+ || ((cptype & ARM_CP_SPECIAL) &&
267
+}
154
+ ((cptype & ~ARM_CP_FLAG_MASK) <= ARM_LAST_SPECIAL));
268
+
155
+}
269
+static const TypeInfo fsl_imx8m_pcie_phy_types[] = {
156
+
270
+ {
157
+/*
271
+ .name = TYPE_FSL_IMX8M_PCIE_PHY,
158
+ * Access rights:
272
+ .parent = TYPE_SYS_BUS_DEVICE,
159
+ * We define bits for Read and Write access for what rev C of the v7-AR ARM ARM
273
+ .instance_size = sizeof(FslImx8mPciePhyState),
160
+ * defines as PL0 (user), PL1 (fiq/irq/svc/abt/und/sys, ie privileged), and
274
+ .class_init = fsl_imx8m_pcie_phy_class_init,
161
+ * PL2 (hyp). The other level which has Read and Write bits is Secure PL1
275
+ }
162
+ * (ie any of the privileged modes in Secure state, or Monitor mode).
163
+ * If a register is accessible in one privilege level it's always accessible
164
+ * in higher privilege levels too. Since "Secure PL1" also follows this rule
165
+ * (ie anything visible in PL2 is visible in S-PL1, some things are only
166
+ * visible in S-PL1) but "Secure PL1" is a bit of a mouthful, we bend the
167
+ * terminology a little and call this PL3.
168
+ * In AArch64 things are somewhat simpler as the PLx bits line up exactly
169
+ * with the ELx exception levels.
170
+ *
171
+ * If access permissions for a register are more complex than can be
172
+ * described with these bits, then use a laxer set of restrictions, and
173
+ * do the more restrictive/complex check inside a helper function.
174
+ */
175
+#define PL3_R 0x80
176
+#define PL3_W 0x40
177
+#define PL2_R (0x20 | PL3_R)
178
+#define PL2_W (0x10 | PL3_W)
179
+#define PL1_R (0x08 | PL2_R)
180
+#define PL1_W (0x04 | PL2_W)
181
+#define PL0_R (0x02 | PL1_R)
182
+#define PL0_W (0x01 | PL1_W)
183
+
184
+/*
185
+ * For user-mode some registers are accessible to EL0 via a kernel
186
+ * trap-and-emulate ABI. In this case we define the read permissions
187
+ * as actually being PL0_R. However some bits of any given register
188
+ * may still be masked.
189
+ */
190
+#ifdef CONFIG_USER_ONLY
191
+#define PL0U_R PL0_R
192
+#else
193
+#define PL0U_R PL1_R
194
+#endif
195
+
196
+#define PL3_RW (PL3_R | PL3_W)
197
+#define PL2_RW (PL2_R | PL2_W)
198
+#define PL1_RW (PL1_R | PL1_W)
199
+#define PL0_RW (PL0_R | PL0_W)
200
+
201
+typedef enum CPAccessResult {
202
+ /* Access is permitted */
203
+ CP_ACCESS_OK = 0,
204
+ /*
205
+ * Access fails due to a configurable trap or enable which would
206
+ * result in a categorized exception syndrome giving information about
207
+ * the failing instruction (ie syndrome category 0x3, 0x4, 0x5, 0x6,
208
+ * 0xc or 0x18). The exception is taken to the usual target EL (EL1 or
209
+ * PL1 if in EL0, otherwise to the current EL).
210
+ */
211
+ CP_ACCESS_TRAP = 1,
212
+ /*
213
+ * Access fails and results in an exception syndrome 0x0 ("uncategorized").
214
+ * Note that this is not a catch-all case -- the set of cases which may
215
+ * result in this failure is specifically defined by the architecture.
216
+ */
217
+ CP_ACCESS_TRAP_UNCATEGORIZED = 2,
218
+ /* As CP_ACCESS_TRAP, but for traps directly to EL2 or EL3 */
219
+ CP_ACCESS_TRAP_EL2 = 3,
220
+ CP_ACCESS_TRAP_EL3 = 4,
221
+ /* As CP_ACCESS_UNCATEGORIZED, but for traps directly to EL2 or EL3 */
222
+ CP_ACCESS_TRAP_UNCATEGORIZED_EL2 = 5,
223
+ CP_ACCESS_TRAP_UNCATEGORIZED_EL3 = 6,
224
+} CPAccessResult;
225
+
226
+typedef struct ARMCPRegInfo ARMCPRegInfo;
227
+
228
+/*
229
+ * Access functions for coprocessor registers. These cannot fail and
230
+ * may not raise exceptions.
231
+ */
232
+typedef uint64_t CPReadFn(CPUARMState *env, const ARMCPRegInfo *opaque);
233
+typedef void CPWriteFn(CPUARMState *env, const ARMCPRegInfo *opaque,
234
+ uint64_t value);
235
+/* Access permission check functions for coprocessor registers. */
236
+typedef CPAccessResult CPAccessFn(CPUARMState *env,
237
+ const ARMCPRegInfo *opaque,
238
+ bool isread);
239
+/* Hook function for register reset */
240
+typedef void CPResetFn(CPUARMState *env, const ARMCPRegInfo *opaque);
241
+
242
+#define CP_ANY 0xff
243
+
244
+/* Definition of an ARM coprocessor register */
245
+struct ARMCPRegInfo {
246
+ /* Name of register (useful mainly for debugging, need not be unique) */
247
+ const char *name;
248
+ /*
249
+ * Location of register: coprocessor number and (crn,crm,opc1,opc2)
250
+ * tuple. Any of crm, opc1 and opc2 may be CP_ANY to indicate a
251
+ * 'wildcard' field -- any value of that field in the MRC/MCR insn
252
+ * will be decoded to this register. The register read and write
253
+ * callbacks will be passed an ARMCPRegInfo with the crn/crm/opc1/opc2
254
+ * used by the program, so it is possible to register a wildcard and
255
+ * then behave differently on read/write if necessary.
256
+ * For 64 bit registers, only crm and opc1 are relevant; crn and opc2
257
+ * must both be zero.
258
+ * For AArch64-visible registers, opc0 is also used.
259
+ * Since there are no "coprocessors" in AArch64, cp is purely used as a
260
+ * way to distinguish (for KVM's benefit) guest-visible system registers
261
+ * from demuxed ones provided to preserve the "no side effects on
262
+ * KVM register read/write from QEMU" semantics. cp==0x13 is guest
263
+ * visible (to match KVM's encoding); cp==0 will be converted to
264
+ * cp==0x13 when the ARMCPRegInfo is registered, for convenience.
265
+ */
266
+ uint8_t cp;
267
+ uint8_t crn;
268
+ uint8_t crm;
269
+ uint8_t opc0;
270
+ uint8_t opc1;
271
+ uint8_t opc2;
272
+ /* Execution state in which this register is visible: ARM_CP_STATE_* */
273
+ int state;
274
+ /* Register type: ARM_CP_* bits/values */
275
+ int type;
276
+ /* Access rights: PL*_[RW] */
277
+ int access;
278
+ /* Security state: ARM_CP_SECSTATE_* bits/values */
279
+ int secure;
280
+ /*
281
+ * The opaque pointer passed to define_arm_cp_regs_with_opaque() when
282
+ * this register was defined: can be used to hand data through to the
283
+ * register read/write functions, since they are passed the ARMCPRegInfo*.
284
+ */
285
+ void *opaque;
286
+ /*
287
+ * Value of this register, if it is ARM_CP_CONST. Otherwise, if
288
+ * fieldoffset is non-zero, the reset value of the register.
289
+ */
290
+ uint64_t resetvalue;
291
+ /*
292
+ * Offset of the field in CPUARMState for this register.
293
+ * This is not needed if either:
294
+ * 1. type is ARM_CP_CONST or one of the ARM_CP_SPECIALs
295
+ * 2. both readfn and writefn are specified
296
+ */
297
+ ptrdiff_t fieldoffset; /* offsetof(CPUARMState, field) */
298
+
299
+ /*
300
+ * Offsets of the secure and non-secure fields in CPUARMState for the
301
+ * register if it is banked. These fields are only used during the static
302
+ * registration of a register. During hashing the bank associated
303
+ * with a given security state is copied to fieldoffset which is used from
304
+ * there on out.
305
+ *
306
+ * It is expected that register definitions use either fieldoffset or
307
+ * bank_fieldoffsets in the definition but not both. It is also expected
308
+ * that both bank offsets are set when defining a banked register. This
309
+ * use indicates that a register is banked.
310
+ */
311
+ ptrdiff_t bank_fieldoffsets[2];
312
+
313
+ /*
314
+ * Function for making any access checks for this register in addition to
315
+ * those specified by the 'access' permissions bits. If NULL, no extra
316
+ * checks required. The access check is performed at runtime, not at
317
+ * translate time.
318
+ */
319
+ CPAccessFn *accessfn;
320
+ /*
321
+ * Function for handling reads of this register. If NULL, then reads
322
+ * will be done by loading from the offset into CPUARMState specified
323
+ * by fieldoffset.
324
+ */
325
+ CPReadFn *readfn;
326
+ /*
327
+ * Function for handling writes of this register. If NULL, then writes
328
+ * will be done by writing to the offset into CPUARMState specified
329
+ * by fieldoffset.
330
+ */
331
+ CPWriteFn *writefn;
332
+ /*
333
+ * Function for doing a "raw" read; used when we need to copy
334
+ * coprocessor state to the kernel for KVM or out for
335
+ * migration. This only needs to be provided if there is also a
336
+ * readfn and it has side effects (for instance clear-on-read bits).
337
+ */
338
+ CPReadFn *raw_readfn;
339
+ /*
340
+ * Function for doing a "raw" write; used when we need to copy KVM
341
+ * kernel coprocessor state into userspace, or for inbound
342
+ * migration. This only needs to be provided if there is also a
343
+ * writefn and it masks out "unwritable" bits or has write-one-to-clear
344
+ * or similar behaviour.
345
+ */
346
+ CPWriteFn *raw_writefn;
347
+ /*
348
+ * Function for resetting the register. If NULL, then reset will be done
349
+ * by writing resetvalue to the field specified in fieldoffset. If
350
+ * fieldoffset is 0 then no reset will be done.
351
+ */
352
+ CPResetFn *resetfn;
353
+
354
+ /*
355
+ * "Original" writefn and readfn.
356
+ * For ARMv8.1-VHE register aliases, we overwrite the read/write
357
+ * accessor functions of various EL1/EL0 to perform the runtime
358
+ * check for which sysreg should actually be modified, and then
359
+ * forwards the operation. Before overwriting the accessors,
360
+ * the original function is copied here, so that accesses that
361
+ * really do go to the EL1/EL0 version proceed normally.
362
+ * (The corresponding EL2 register is linked via opaque.)
363
+ */
364
+ CPReadFn *orig_readfn;
365
+ CPWriteFn *orig_writefn;
366
+};
276
+};
367
+
277
+
368
+/*
278
+DEFINE_TYPES(fsl_imx8m_pcie_phy_types)
369
+ * Macros which are lvalues for the field in CPUARMState for the
279
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
370
+ * ARMCPRegInfo *ri.
280
index XXXXXXX..XXXXXXX 100644
371
+ */
281
--- a/hw/arm/Kconfig
372
+#define CPREG_FIELD32(env, ri) \
282
+++ b/hw/arm/Kconfig
373
+ (*(uint32_t *)((char *)(env) + (ri)->fieldoffset))
283
@@ -XXX,XX +XXX,XX @@ config FSL_IMX7
374
+#define CPREG_FIELD64(env, ri) \
284
375
+ (*(uint64_t *)((char *)(env) + (ri)->fieldoffset))
285
config FSL_IMX8MP
376
+
286
bool
377
+#define REGINFO_SENTINEL { .type = ARM_CP_SENTINEL }
287
+ imply PCI_DEVICES
378
+
288
select ARM_GIC
379
+void define_arm_cp_regs_with_opaque(ARMCPU *cpu,
289
select FSL_IMX8MP_ANALOG
380
+ const ARMCPRegInfo *regs, void *opaque);
290
select FSL_IMX8MP_CCM
381
+void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
291
select IMX
382
+ const ARMCPRegInfo *regs, void *opaque);
292
+ select PCI_EXPRESS_DESIGNWARE
383
+static inline void define_arm_cp_regs(ARMCPU *cpu, const ARMCPRegInfo *regs)
293
+ select PCI_EXPRESS_FSL_IMX8M_PHY
384
+{
294
select SDHCI
385
+ define_arm_cp_regs_with_opaque(cpu, regs, 0);
295
select UNIMP
386
+}
296
387
+static inline void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *regs)
297
diff --git a/hw/pci-host/Kconfig b/hw/pci-host/Kconfig
388
+{
298
index XXXXXXX..XXXXXXX 100644
389
+ define_one_arm_cp_reg_with_opaque(cpu, regs, 0);
299
--- a/hw/pci-host/Kconfig
390
+}
300
+++ b/hw/pci-host/Kconfig
391
+const ARMCPRegInfo *get_arm_cp_reginfo(GHashTable *cpregs, uint32_t encoded_cp);
301
@@ -XXX,XX +XXX,XX @@ config ASTRO
392
+
302
bool
393
+/*
303
select PCI
394
+ * Definition of an ARM co-processor register as viewed from
304
395
+ * userspace. This is used for presenting sanitised versions of
305
+config PCI_EXPRESS_FSL_IMX8M_PHY
396
+ * registers to userspace when emulating the Linux AArch64 CPU
306
+ bool
397
+ * ID/feature ABI (advertised as HWCAP_CPUID).
307
+
398
+ */
308
config GT64120
399
+typedef struct ARMCPRegUserSpaceInfo {
309
bool
400
+ /* Name of register */
310
select PCI
401
+ const char *name;
311
diff --git a/hw/pci-host/meson.build b/hw/pci-host/meson.build
402
+
312
index XXXXXXX..XXXXXXX 100644
403
+ /* Is the name actually a glob pattern */
313
--- a/hw/pci-host/meson.build
404
+ bool is_glob;
314
+++ b/hw/pci-host/meson.build
405
+
315
@@ -XXX,XX +XXX,XX @@ pci_ss.add(when: 'CONFIG_ARTICIA', if_true: files('articia.c'))
406
+ /* Only some bits are exported to user space */
316
pci_ss.add(when: 'CONFIG_MV64361', if_true: files('mv64361.c'))
407
+ uint64_t exported_bits;
317
408
+
318
# ARM devices
409
+ /* Fixed bits are applied after the mask */
319
+pci_ss.add(when: 'CONFIG_PCI_EXPRESS_FSL_IMX8M_PHY', if_true: files('fsl_imx8m_phy.c'))
410
+ uint64_t fixed_bits;
320
pci_ss.add(when: 'CONFIG_VERSATILE_PCI', if_true: files('versatile.c'))
411
+} ARMCPRegUserSpaceInfo;
321
412
+
322
# HPPA devices
413
+#define REGUSERINFO_SENTINEL { .name = NULL }
414
+
415
+void modify_arm_cp_regs(ARMCPRegInfo *regs, const ARMCPRegUserSpaceInfo *mods);
416
+
417
+/* CPWriteFn that can be used to implement writes-ignored behaviour */
418
+void arm_cp_write_ignore(CPUARMState *env, const ARMCPRegInfo *ri,
419
+ uint64_t value);
420
+/* CPReadFn that can be used for read-as-zero behaviour */
421
+uint64_t arm_cp_read_zero(CPUARMState *env, const ARMCPRegInfo *ri);
422
+
423
+/*
424
+ * CPResetFn that does nothing, for use if no reset is required even
425
+ * if fieldoffset is non zero.
426
+ */
427
+void arm_cp_reset_ignore(CPUARMState *env, const ARMCPRegInfo *opaque);
428
+
429
+/*
430
+ * Return true if this reginfo struct's field in the cpu state struct
431
+ * is 64 bits wide.
432
+ */
433
+static inline bool cpreg_field_is_64bit(const ARMCPRegInfo *ri)
434
+{
435
+ return (ri->state == ARM_CP_STATE_AA64) || (ri->type & ARM_CP_64BIT);
436
+}
437
+
438
+static inline bool cp_access_ok(int current_el,
439
+ const ARMCPRegInfo *ri, int isread)
440
+{
441
+ return (ri->access >> ((current_el * 2) + isread)) & 1;
442
+}
443
+
444
+/* Raw read of a coprocessor register (as needed for migration, etc) */
445
+uint64_t read_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri);
446
+
447
+#endif /* TARGET_ARM_CPREGS_H */
448
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
449
index XXXXXXX..XXXXXXX 100644
450
--- a/target/arm/cpu.h
451
+++ b/target/arm/cpu.h
452
@@ -XXX,XX +XXX,XX @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
453
return kvmid;
454
}
455
456
-/* ARMCPRegInfo type field bits. If the SPECIAL bit is set this is a
457
- * special-behaviour cp reg and bits [11..8] indicate what behaviour
458
- * it has. Otherwise it is a simple cp reg, where CONST indicates that
459
- * TCG can assume the value to be constant (ie load at translate time)
460
- * and 64BIT indicates a 64 bit wide coprocessor register. SUPPRESS_TB_END
461
- * indicates that the TB should not be ended after a write to this register
462
- * (the default is that the TB ends after cp writes). OVERRIDE permits
463
- * a register definition to override a previous definition for the
464
- * same (cp, is64, crn, crm, opc1, opc2) tuple: either the new or the
465
- * old must have the OVERRIDE bit set.
466
- * ALIAS indicates that this register is an alias view of some underlying
467
- * state which is also visible via another register, and that the other
468
- * register is handling migration and reset; registers marked ALIAS will not be
469
- * migrated but may have their state set by syncing of register state from KVM.
470
- * NO_RAW indicates that this register has no underlying state and does not
471
- * support raw access for state saving/loading; it will not be used for either
472
- * migration or KVM state synchronization. (Typically this is for "registers"
473
- * which are actually used as instructions for cache maintenance and so on.)
474
- * IO indicates that this register does I/O and therefore its accesses
475
- * need to be marked with gen_io_start() and also end the TB. In particular,
476
- * registers which implement clocks or timers require this.
477
- * RAISES_EXC is for when the read or write hook might raise an exception;
478
- * the generated code will synchronize the CPU state before calling the hook
479
- * so that it is safe for the hook to call raise_exception().
480
- * NEWEL is for writes to registers that might change the exception
481
- * level - typically on older ARM chips. For those cases we need to
482
- * re-read the new el when recomputing the translation flags.
483
- */
484
-#define ARM_CP_SPECIAL 0x0001
485
-#define ARM_CP_CONST 0x0002
486
-#define ARM_CP_64BIT 0x0004
487
-#define ARM_CP_SUPPRESS_TB_END 0x0008
488
-#define ARM_CP_OVERRIDE 0x0010
489
-#define ARM_CP_ALIAS 0x0020
490
-#define ARM_CP_IO 0x0040
491
-#define ARM_CP_NO_RAW 0x0080
492
-#define ARM_CP_NOP (ARM_CP_SPECIAL | 0x0100)
493
-#define ARM_CP_WFI (ARM_CP_SPECIAL | 0x0200)
494
-#define ARM_CP_NZCV (ARM_CP_SPECIAL | 0x0300)
495
-#define ARM_CP_CURRENTEL (ARM_CP_SPECIAL | 0x0400)
496
-#define ARM_CP_DC_ZVA (ARM_CP_SPECIAL | 0x0500)
497
-#define ARM_CP_DC_GVA (ARM_CP_SPECIAL | 0x0600)
498
-#define ARM_CP_DC_GZVA (ARM_CP_SPECIAL | 0x0700)
499
-#define ARM_LAST_SPECIAL ARM_CP_DC_GZVA
500
-#define ARM_CP_FPU 0x1000
501
-#define ARM_CP_SVE 0x2000
502
-#define ARM_CP_NO_GDB 0x4000
503
-#define ARM_CP_RAISES_EXC 0x8000
504
-#define ARM_CP_NEWEL 0x10000
505
-/* Used only as a terminator for ARMCPRegInfo lists */
506
-#define ARM_CP_SENTINEL 0xfffff
507
-/* Mask of only the flag bits in a type field */
508
-#define ARM_CP_FLAG_MASK 0x1f0ff
509
-
510
-/* Valid values for ARMCPRegInfo state field, indicating which of
511
- * the AArch32 and AArch64 execution states this register is visible in.
512
- * If the reginfo doesn't explicitly specify then it is AArch32 only.
513
- * If the reginfo is declared to be visible in both states then a second
514
- * reginfo is synthesised for the AArch32 view of the AArch64 register,
515
- * such that the AArch32 view is the lower 32 bits of the AArch64 one.
516
- * Note that we rely on the values of these enums as we iterate through
517
- * the various states in some places.
518
- */
519
-enum {
520
- ARM_CP_STATE_AA32 = 0,
521
- ARM_CP_STATE_AA64 = 1,
522
- ARM_CP_STATE_BOTH = 2,
523
-};
524
-
525
-/* ARM CP register secure state flags. These flags identify security state
526
- * attributes for a given CP register entry.
527
- * The existence of both or neither secure and non-secure flags indicates that
528
- * the register has both a secure and non-secure hash entry. A single one of
529
- * these flags causes the register to only be hashed for the specified
530
- * security state.
531
- * Although definitions may have any combination of the S/NS bits, each
532
- * registered entry will only have one to identify whether the entry is secure
533
- * or non-secure.
534
- */
535
-enum {
536
- ARM_CP_SECSTATE_S = (1 << 0), /* bit[0]: Secure state register */
537
- ARM_CP_SECSTATE_NS = (1 << 1), /* bit[1]: Non-secure state register */
538
-};
539
-
540
-/* Return true if cptype is a valid type field. This is used to try to
541
- * catch errors where the sentinel has been accidentally left off the end
542
- * of a list of registers.
543
- */
544
-static inline bool cptype_valid(int cptype)
545
-{
546
- return ((cptype & ~ARM_CP_FLAG_MASK) == 0)
547
- || ((cptype & ARM_CP_SPECIAL) &&
548
- ((cptype & ~ARM_CP_FLAG_MASK) <= ARM_LAST_SPECIAL));
549
-}
550
-
551
-/* Access rights:
552
- * We define bits for Read and Write access for what rev C of the v7-AR ARM ARM
553
- * defines as PL0 (user), PL1 (fiq/irq/svc/abt/und/sys, ie privileged), and
554
- * PL2 (hyp). The other level which has Read and Write bits is Secure PL1
555
- * (ie any of the privileged modes in Secure state, or Monitor mode).
556
- * If a register is accessible in one privilege level it's always accessible
557
- * in higher privilege levels too. Since "Secure PL1" also follows this rule
558
- * (ie anything visible in PL2 is visible in S-PL1, some things are only
559
- * visible in S-PL1) but "Secure PL1" is a bit of a mouthful, we bend the
560
- * terminology a little and call this PL3.
561
- * In AArch64 things are somewhat simpler as the PLx bits line up exactly
562
- * with the ELx exception levels.
563
- *
564
- * If access permissions for a register are more complex than can be
565
- * described with these bits, then use a laxer set of restrictions, and
566
- * do the more restrictive/complex check inside a helper function.
567
- */
568
-#define PL3_R 0x80
569
-#define PL3_W 0x40
570
-#define PL2_R (0x20 | PL3_R)
571
-#define PL2_W (0x10 | PL3_W)
572
-#define PL1_R (0x08 | PL2_R)
573
-#define PL1_W (0x04 | PL2_W)
574
-#define PL0_R (0x02 | PL1_R)
575
-#define PL0_W (0x01 | PL1_W)
576
-
577
-/*
578
- * For user-mode some registers are accessible to EL0 via a kernel
579
- * trap-and-emulate ABI. In this case we define the read permissions
580
- * as actually being PL0_R. However some bits of any given register
581
- * may still be masked.
582
- */
583
-#ifdef CONFIG_USER_ONLY
584
-#define PL0U_R PL0_R
585
-#else
586
-#define PL0U_R PL1_R
587
-#endif
588
-
589
-#define PL3_RW (PL3_R | PL3_W)
590
-#define PL2_RW (PL2_R | PL2_W)
591
-#define PL1_RW (PL1_R | PL1_W)
592
-#define PL0_RW (PL0_R | PL0_W)
593
-
594
/* Return the highest implemented Exception Level */
595
static inline int arm_highest_el(CPUARMState *env)
596
{
597
@@ -XXX,XX +XXX,XX @@ static inline int arm_current_el(CPUARMState *env)
598
}
599
}
600
601
-typedef struct ARMCPRegInfo ARMCPRegInfo;
602
-
603
-typedef enum CPAccessResult {
604
- /* Access is permitted */
605
- CP_ACCESS_OK = 0,
606
- /* Access fails due to a configurable trap or enable which would
607
- * result in a categorized exception syndrome giving information about
608
- * the failing instruction (ie syndrome category 0x3, 0x4, 0x5, 0x6,
609
- * 0xc or 0x18). The exception is taken to the usual target EL (EL1 or
610
- * PL1 if in EL0, otherwise to the current EL).
611
- */
612
- CP_ACCESS_TRAP = 1,
613
- /* Access fails and results in an exception syndrome 0x0 ("uncategorized").
614
- * Note that this is not a catch-all case -- the set of cases which may
615
- * result in this failure is specifically defined by the architecture.
616
- */
617
- CP_ACCESS_TRAP_UNCATEGORIZED = 2,
618
- /* As CP_ACCESS_TRAP, but for traps directly to EL2 or EL3 */
619
- CP_ACCESS_TRAP_EL2 = 3,
620
- CP_ACCESS_TRAP_EL3 = 4,
621
- /* As CP_ACCESS_UNCATEGORIZED, but for traps directly to EL2 or EL3 */
622
- CP_ACCESS_TRAP_UNCATEGORIZED_EL2 = 5,
623
- CP_ACCESS_TRAP_UNCATEGORIZED_EL3 = 6,
624
-} CPAccessResult;
625
-
626
-/* Access functions for coprocessor registers. These cannot fail and
627
- * may not raise exceptions.
628
- */
629
-typedef uint64_t CPReadFn(CPUARMState *env, const ARMCPRegInfo *opaque);
630
-typedef void CPWriteFn(CPUARMState *env, const ARMCPRegInfo *opaque,
631
- uint64_t value);
632
-/* Access permission check functions for coprocessor registers. */
633
-typedef CPAccessResult CPAccessFn(CPUARMState *env,
634
- const ARMCPRegInfo *opaque,
635
- bool isread);
636
-/* Hook function for register reset */
637
-typedef void CPResetFn(CPUARMState *env, const ARMCPRegInfo *opaque);
638
-
639
-#define CP_ANY 0xff
640
-
641
-/* Definition of an ARM coprocessor register */
642
-struct ARMCPRegInfo {
643
- /* Name of register (useful mainly for debugging, need not be unique) */
644
- const char *name;
645
- /* Location of register: coprocessor number and (crn,crm,opc1,opc2)
646
- * tuple. Any of crm, opc1 and opc2 may be CP_ANY to indicate a
647
- * 'wildcard' field -- any value of that field in the MRC/MCR insn
648
- * will be decoded to this register. The register read and write
649
- * callbacks will be passed an ARMCPRegInfo with the crn/crm/opc1/opc2
650
- * used by the program, so it is possible to register a wildcard and
651
- * then behave differently on read/write if necessary.
652
- * For 64 bit registers, only crm and opc1 are relevant; crn and opc2
653
- * must both be zero.
654
- * For AArch64-visible registers, opc0 is also used.
655
- * Since there are no "coprocessors" in AArch64, cp is purely used as a
656
- * way to distinguish (for KVM's benefit) guest-visible system registers
657
- * from demuxed ones provided to preserve the "no side effects on
658
- * KVM register read/write from QEMU" semantics. cp==0x13 is guest
659
- * visible (to match KVM's encoding); cp==0 will be converted to
660
- * cp==0x13 when the ARMCPRegInfo is registered, for convenience.
661
- */
662
- uint8_t cp;
663
- uint8_t crn;
664
- uint8_t crm;
665
- uint8_t opc0;
666
- uint8_t opc1;
667
- uint8_t opc2;
668
- /* Execution state in which this register is visible: ARM_CP_STATE_* */
669
- int state;
670
- /* Register type: ARM_CP_* bits/values */
671
- int type;
672
- /* Access rights: PL*_[RW] */
673
- int access;
674
- /* Security state: ARM_CP_SECSTATE_* bits/values */
675
- int secure;
676
- /* The opaque pointer passed to define_arm_cp_regs_with_opaque() when
677
- * this register was defined: can be used to hand data through to the
678
- * register read/write functions, since they are passed the ARMCPRegInfo*.
679
- */
680
- void *opaque;
681
- /* Value of this register, if it is ARM_CP_CONST. Otherwise, if
682
- * fieldoffset is non-zero, the reset value of the register.
683
- */
684
- uint64_t resetvalue;
685
- /* Offset of the field in CPUARMState for this register.
686
- *
687
- * This is not needed if either:
688
- * 1. type is ARM_CP_CONST or one of the ARM_CP_SPECIALs
689
- * 2. both readfn and writefn are specified
690
- */
691
- ptrdiff_t fieldoffset; /* offsetof(CPUARMState, field) */
692
-
693
- /* Offsets of the secure and non-secure fields in CPUARMState for the
694
- * register if it is banked. These fields are only used during the static
695
- * registration of a register. During hashing the bank associated
696
- * with a given security state is copied to fieldoffset which is used from
697
- * there on out.
698
- *
699
- * It is expected that register definitions use either fieldoffset or
700
- * bank_fieldoffsets in the definition but not both. It is also expected
701
- * that both bank offsets are set when defining a banked register. This
702
- * use indicates that a register is banked.
703
- */
704
- ptrdiff_t bank_fieldoffsets[2];
705
-
706
- /* Function for making any access checks for this register in addition to
707
- * those specified by the 'access' permissions bits. If NULL, no extra
708
- * checks required. The access check is performed at runtime, not at
709
- * translate time.
710
- */
711
- CPAccessFn *accessfn;
712
- /* Function for handling reads of this register. If NULL, then reads
713
- * will be done by loading from the offset into CPUARMState specified
714
- * by fieldoffset.
715
- */
716
- CPReadFn *readfn;
717
- /* Function for handling writes of this register. If NULL, then writes
718
- * will be done by writing to the offset into CPUARMState specified
719
- * by fieldoffset.
720
- */
721
- CPWriteFn *writefn;
722
- /* Function for doing a "raw" read; used when we need to copy
723
- * coprocessor state to the kernel for KVM or out for
724
- * migration. This only needs to be provided if there is also a
725
- * readfn and it has side effects (for instance clear-on-read bits).
726
- */
727
- CPReadFn *raw_readfn;
728
- /* Function for doing a "raw" write; used when we need to copy KVM
729
- * kernel coprocessor state into userspace, or for inbound
730
- * migration. This only needs to be provided if there is also a
731
- * writefn and it masks out "unwritable" bits or has write-one-to-clear
732
- * or similar behaviour.
733
- */
734
- CPWriteFn *raw_writefn;
735
- /* Function for resetting the register. If NULL, then reset will be done
736
- * by writing resetvalue to the field specified in fieldoffset. If
737
- * fieldoffset is 0 then no reset will be done.
738
- */
739
- CPResetFn *resetfn;
740
-
741
- /*
742
- * "Original" writefn and readfn.
743
- * For ARMv8.1-VHE register aliases, we overwrite the read/write
744
- * accessor functions of various EL1/EL0 to perform the runtime
745
- * check for which sysreg should actually be modified, and then
746
- * forwards the operation. Before overwriting the accessors,
747
- * the original function is copied here, so that accesses that
748
- * really do go to the EL1/EL0 version proceed normally.
749
- * (The corresponding EL2 register is linked via opaque.)
750
- */
751
- CPReadFn *orig_readfn;
752
- CPWriteFn *orig_writefn;
753
-};
754
-
755
-/* Macros which are lvalues for the field in CPUARMState for the
756
- * ARMCPRegInfo *ri.
757
- */
758
-#define CPREG_FIELD32(env, ri) \
759
- (*(uint32_t *)((char *)(env) + (ri)->fieldoffset))
760
-#define CPREG_FIELD64(env, ri) \
761
- (*(uint64_t *)((char *)(env) + (ri)->fieldoffset))
762
-
763
-#define REGINFO_SENTINEL { .type = ARM_CP_SENTINEL }
764
-
765
-void define_arm_cp_regs_with_opaque(ARMCPU *cpu,
766
- const ARMCPRegInfo *regs, void *opaque);
767
-void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
768
- const ARMCPRegInfo *regs, void *opaque);
769
-static inline void define_arm_cp_regs(ARMCPU *cpu, const ARMCPRegInfo *regs)
770
-{
771
- define_arm_cp_regs_with_opaque(cpu, regs, 0);
772
-}
773
-static inline void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *regs)
774
-{
775
- define_one_arm_cp_reg_with_opaque(cpu, regs, 0);
776
-}
777
-const ARMCPRegInfo *get_arm_cp_reginfo(GHashTable *cpregs, uint32_t encoded_cp);
778
-
779
-/*
780
- * Definition of an ARM co-processor register as viewed from
781
- * userspace. This is used for presenting sanitised versions of
782
- * registers to userspace when emulating the Linux AArch64 CPU
783
- * ID/feature ABI (advertised as HWCAP_CPUID).
784
- */
785
-typedef struct ARMCPRegUserSpaceInfo {
786
- /* Name of register */
787
- const char *name;
788
-
789
- /* Is the name actually a glob pattern */
790
- bool is_glob;
791
-
792
- /* Only some bits are exported to user space */
793
- uint64_t exported_bits;
794
-
795
- /* Fixed bits are applied after the mask */
796
- uint64_t fixed_bits;
797
-} ARMCPRegUserSpaceInfo;
798
-
799
-#define REGUSERINFO_SENTINEL { .name = NULL }
800
-
801
-void modify_arm_cp_regs(ARMCPRegInfo *regs, const ARMCPRegUserSpaceInfo *mods);
802
-
803
-/* CPWriteFn that can be used to implement writes-ignored behaviour */
804
-void arm_cp_write_ignore(CPUARMState *env, const ARMCPRegInfo *ri,
805
- uint64_t value);
806
-/* CPReadFn that can be used for read-as-zero behaviour */
807
-uint64_t arm_cp_read_zero(CPUARMState *env, const ARMCPRegInfo *ri);
808
-
809
-/* CPResetFn that does nothing, for use if no reset is required even
810
- * if fieldoffset is non zero.
811
- */
812
-void arm_cp_reset_ignore(CPUARMState *env, const ARMCPRegInfo *opaque);
813
-
814
-/* Return true if this reginfo struct's field in the cpu state struct
815
- * is 64 bits wide.
816
- */
817
-static inline bool cpreg_field_is_64bit(const ARMCPRegInfo *ri)
818
-{
819
- return (ri->state == ARM_CP_STATE_AA64) || (ri->type & ARM_CP_64BIT);
820
-}
821
-
822
-static inline bool cp_access_ok(int current_el,
823
- const ARMCPRegInfo *ri, int isread)
824
-{
825
- return (ri->access >> ((current_el * 2) + isread)) & 1;
826
-}
827
-
828
-/* Raw read of a coprocessor register (as needed for migration, etc) */
829
-uint64_t read_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri);
830
-
831
/**
832
* write_list_to_cpustate
833
* @cpu: ARMCPU
834
diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c
835
index XXXXXXX..XXXXXXX 100644
836
--- a/hw/arm/pxa2xx.c
837
+++ b/hw/arm/pxa2xx.c
838
@@ -XXX,XX +XXX,XX @@
839
#include "qemu/cutils.h"
840
#include "qemu/log.h"
841
#include "qom/object.h"
842
+#include "target/arm/cpregs.h"
843
844
static struct {
845
hwaddr io_base;
846
diff --git a/hw/arm/pxa2xx_pic.c b/hw/arm/pxa2xx_pic.c
847
index XXXXXXX..XXXXXXX 100644
848
--- a/hw/arm/pxa2xx_pic.c
849
+++ b/hw/arm/pxa2xx_pic.c
850
@@ -XXX,XX +XXX,XX @@
851
#include "hw/sysbus.h"
852
#include "migration/vmstate.h"
853
#include "qom/object.h"
854
+#include "target/arm/cpregs.h"
855
856
#define ICIP    0x00    /* Interrupt Controller IRQ Pending register */
857
#define ICMR    0x04    /* Interrupt Controller Mask register */
858
diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
859
index XXXXXXX..XXXXXXX 100644
860
--- a/hw/intc/arm_gicv3_cpuif.c
861
+++ b/hw/intc/arm_gicv3_cpuif.c
862
@@ -XXX,XX +XXX,XX @@
863
#include "gicv3_internal.h"
864
#include "hw/irq.h"
865
#include "cpu.h"
866
+#include "target/arm/cpregs.h"
867
868
/*
869
* Special case return value from hppvi_index(); must be larger than
870
diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c
871
index XXXXXXX..XXXXXXX 100644
872
--- a/hw/intc/arm_gicv3_kvm.c
873
+++ b/hw/intc/arm_gicv3_kvm.c
874
@@ -XXX,XX +XXX,XX @@
875
#include "vgic_common.h"
876
#include "migration/blocker.h"
877
#include "qom/object.h"
878
+#include "target/arm/cpregs.h"
879
+
880
881
#ifdef DEBUG_GICV3_KVM
882
#define DPRINTF(fmt, ...) \
883
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
884
index XXXXXXX..XXXXXXX 100644
885
--- a/target/arm/cpu.c
886
+++ b/target/arm/cpu.c
887
@@ -XXX,XX +XXX,XX @@
888
#include "kvm_arm.h"
889
#include "disas/capstone.h"
890
#include "fpu/softfloat.h"
891
+#include "cpregs.h"
892
893
static void arm_cpu_set_pc(CPUState *cs, vaddr value)
894
{
895
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
896
index XXXXXXX..XXXXXXX 100644
897
--- a/target/arm/cpu64.c
898
+++ b/target/arm/cpu64.c
899
@@ -XXX,XX +XXX,XX @@
900
#include "hvf_arm.h"
901
#include "qapi/visitor.h"
902
#include "hw/qdev-properties.h"
903
+#include "cpregs.h"
904
905
906
#ifndef CONFIG_USER_ONLY
907
diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c
908
index XXXXXXX..XXXXXXX 100644
909
--- a/target/arm/cpu_tcg.c
910
+++ b/target/arm/cpu_tcg.c
911
@@ -XXX,XX +XXX,XX @@
912
#if !defined(CONFIG_USER_ONLY)
913
#include "hw/boards.h"
914
#endif
915
+#include "cpregs.h"
916
917
/* CPU models. These are not needed for the AArch64 linux-user build. */
918
#if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64)
919
diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c
920
index XXXXXXX..XXXXXXX 100644
921
--- a/target/arm/gdbstub.c
922
+++ b/target/arm/gdbstub.c
923
@@ -XXX,XX +XXX,XX @@
924
*/
925
#include "qemu/osdep.h"
926
#include "cpu.h"
927
-#include "internals.h"
928
#include "exec/gdbstub.h"
929
+#include "internals.h"
930
+#include "cpregs.h"
931
932
typedef struct RegisterSysregXmlParam {
933
CPUState *cs;
934
diff --git a/target/arm/helper.c b/target/arm/helper.c
935
index XXXXXXX..XXXXXXX 100644
936
--- a/target/arm/helper.c
937
+++ b/target/arm/helper.c
938
@@ -XXX,XX +XXX,XX @@
939
#include "exec/cpu_ldst.h"
940
#include "semihosting/common-semi.h"
941
#endif
942
+#include "cpregs.h"
943
944
#define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */
945
#define PMCR_NUM_COUNTERS 4 /* QEMU IMPDEF choice */
946
diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c
947
index XXXXXXX..XXXXXXX 100644
948
--- a/target/arm/op_helper.c
949
+++ b/target/arm/op_helper.c
950
@@ -XXX,XX +XXX,XX @@
951
#include "internals.h"
952
#include "exec/exec-all.h"
953
#include "exec/cpu_ldst.h"
954
+#include "cpregs.h"
955
956
#define SIGNBIT (uint32_t)0x80000000
957
#define SIGNBIT64 ((uint64_t)1 << 63)
958
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
959
index XXXXXXX..XXXXXXX 100644
960
--- a/target/arm/translate-a64.c
961
+++ b/target/arm/translate-a64.c
962
@@ -XXX,XX +XXX,XX @@
963
#include "translate.h"
964
#include "internals.h"
965
#include "qemu/host-utils.h"
966
-
967
#include "semihosting/semihost.h"
968
#include "exec/gen-icount.h"
969
-
970
#include "exec/helper-proto.h"
971
#include "exec/helper-gen.h"
972
#include "exec/log.h"
973
-
974
+#include "cpregs.h"
975
#include "translate-a64.h"
976
#include "qemu/atomic128.h"
977
978
diff --git a/target/arm/translate.c b/target/arm/translate.c
979
index XXXXXXX..XXXXXXX 100644
980
--- a/target/arm/translate.c
981
+++ b/target/arm/translate.c
982
@@ -XXX,XX +XXX,XX @@
983
#include "qemu/bitops.h"
984
#include "arm_ldst.h"
985
#include "semihosting/semihost.h"
986
-
987
#include "exec/helper-proto.h"
988
#include "exec/helper-gen.h"
989
-
990
#include "exec/log.h"
991
+#include "cpregs.h"
992
993
994
#define ENABLE_ARCH_4T arm_dc_feature(s, ARM_FEATURE_V4T)
995
--
323
--
996
2.25.1
324
2.43.0
997
998
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Bernhard Beschow <shentey@gmail.com>
2
2
3
Instead of defining ARM_CP_FLAG_MASK to remove flags,
4
define ARM_CP_SPECIAL_MASK to isolate special cases.
5
Sort the specials to the low bits. Use an enum.
6
7
Split the large comment block so as to document each
8
value separately.
9
10
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
11
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
3
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
12
Message-id: 20220501055028.646596-6-richard.henderson@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]
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
---
8
---
15
target/arm/cpregs.h | 130 +++++++++++++++++++++++--------------
9
docs/system/arm/imx8mp-evk.rst | 1 +
16
target/arm/cpu.c | 4 +-
10
include/hw/arm/fsl-imx8mp.h | 14 +++++++++
17
target/arm/helper.c | 4 +-
11
hw/arm/fsl-imx8mp.c | 55 ++++++++++++++++++++++++++++++++++
18
target/arm/translate-a64.c | 6 +-
12
3 files changed, 70 insertions(+)
19
target/arm/translate.c | 6 +-
20
5 files changed, 92 insertions(+), 58 deletions(-)
21
13
22
diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
14
diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8mp-evk.rst
23
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
24
--- a/target/arm/cpregs.h
16
--- a/docs/system/arm/imx8mp-evk.rst
25
+++ b/target/arm/cpregs.h
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
26
@@ -XXX,XX +XXX,XX @@
30
@@ -XXX,XX +XXX,XX @@
27
#define TARGET_ARM_CPREGS_H
31
28
32
#include "cpu.h"
29
/*
33
#include "hw/char/imx_serial.h"
30
- * ARMCPRegInfo type field bits. If the SPECIAL bit is set this is a
34
+#include "hw/gpio/imx_gpio.h"
31
- * special-behaviour cp reg and bits [11..8] indicate what behaviour
35
#include "hw/intc/arm_gicv3_common.h"
32
- * it has. Otherwise it is a simple cp reg, where CONST indicates that
36
#include "hw/misc/imx7_snvs.h"
33
- * TCG can assume the value to be constant (ie load at translate time)
37
#include "hw/misc/imx8mp_analog.h"
34
- * and 64BIT indicates a 64 bit wide coprocessor register. SUPPRESS_TB_END
38
@@ -XXX,XX +XXX,XX @@ OBJECT_DECLARE_SIMPLE_TYPE(FslImx8mpState, FSL_IMX8MP)
35
- * indicates that the TB should not be ended after a write to this register
39
36
- * (the default is that the TB ends after cp writes). OVERRIDE permits
40
enum FslImx8mpConfiguration {
37
- * a register definition to override a previous definition for the
41
FSL_IMX8MP_NUM_CPUS = 4,
38
- * same (cp, is64, crn, crm, opc1, opc2) tuple: either the new or the
42
+ FSL_IMX8MP_NUM_GPIOS = 5,
39
- * old must have the OVERRIDE bit set.
43
FSL_IMX8MP_NUM_IRQS = 160,
40
- * ALIAS indicates that this register is an alias view of some underlying
44
FSL_IMX8MP_NUM_UARTS = 4,
41
- * state which is also visible via another register, and that the other
45
FSL_IMX8MP_NUM_USDHCS = 3,
42
- * register is handling migration and reset; registers marked ALIAS will not be
46
@@ -XXX,XX +XXX,XX @@ struct FslImx8mpState {
43
- * migrated but may have their state set by syncing of register state from KVM.
47
44
- * NO_RAW indicates that this register has no underlying state and does not
48
ARMCPU cpu[FSL_IMX8MP_NUM_CPUS];
45
- * support raw access for state saving/loading; it will not be used for either
49
GICv3State gic;
46
- * migration or KVM state synchronization. (Typically this is for "registers"
50
+ IMXGPIOState gpio[FSL_IMX8MP_NUM_GPIOS];
47
- * which are actually used as instructions for cache maintenance and so on.)
51
IMX8MPCCMState ccm;
48
- * IO indicates that this register does I/O and therefore its accesses
52
IMX8MPAnalogState analog;
49
- * need to be marked with gen_io_start() and also end the TB. In particular,
53
IMX7SNVSState snvs;
50
- * registers which implement clocks or timers require this.
54
@@ -XXX,XX +XXX,XX @@ enum FslImx8mpIrqs {
51
- * RAISES_EXC is for when the read or write hook might raise an exception;
55
FSL_IMX8MP_UART5_IRQ = 30,
52
- * the generated code will synchronize the CPU state before calling the hook
56
FSL_IMX8MP_UART6_IRQ = 16,
53
- * so that it is safe for the hook to call raise_exception().
57
54
- * NEWEL is for writes to registers that might change the exception
58
+ FSL_IMX8MP_GPIO1_LOW_IRQ = 64,
55
- * level - typically on older ARM chips. For those cases we need to
59
+ FSL_IMX8MP_GPIO1_HIGH_IRQ = 65,
56
- * re-read the new el when recomputing the translation flags.
60
+ FSL_IMX8MP_GPIO2_LOW_IRQ = 66,
57
+ * ARMCPRegInfo type field bits:
61
+ FSL_IMX8MP_GPIO2_HIGH_IRQ = 67,
58
*/
62
+ FSL_IMX8MP_GPIO3_LOW_IRQ = 68,
59
-#define ARM_CP_SPECIAL 0x0001
63
+ FSL_IMX8MP_GPIO3_HIGH_IRQ = 69,
60
-#define ARM_CP_CONST 0x0002
64
+ FSL_IMX8MP_GPIO4_LOW_IRQ = 70,
61
-#define ARM_CP_64BIT 0x0004
65
+ FSL_IMX8MP_GPIO4_HIGH_IRQ = 71,
62
-#define ARM_CP_SUPPRESS_TB_END 0x0008
66
+ FSL_IMX8MP_GPIO5_LOW_IRQ = 72,
63
-#define ARM_CP_OVERRIDE 0x0010
67
+ FSL_IMX8MP_GPIO5_HIGH_IRQ = 73,
64
-#define ARM_CP_ALIAS 0x0020
65
-#define ARM_CP_IO 0x0040
66
-#define ARM_CP_NO_RAW 0x0080
67
-#define ARM_CP_NOP (ARM_CP_SPECIAL | 0x0100)
68
-#define ARM_CP_WFI (ARM_CP_SPECIAL | 0x0200)
69
-#define ARM_CP_NZCV (ARM_CP_SPECIAL | 0x0300)
70
-#define ARM_CP_CURRENTEL (ARM_CP_SPECIAL | 0x0400)
71
-#define ARM_CP_DC_ZVA (ARM_CP_SPECIAL | 0x0500)
72
-#define ARM_CP_DC_GVA (ARM_CP_SPECIAL | 0x0600)
73
-#define ARM_CP_DC_GZVA (ARM_CP_SPECIAL | 0x0700)
74
-#define ARM_LAST_SPECIAL ARM_CP_DC_GZVA
75
-#define ARM_CP_FPU 0x1000
76
-#define ARM_CP_SVE 0x2000
77
-#define ARM_CP_NO_GDB 0x4000
78
-#define ARM_CP_RAISES_EXC 0x8000
79
-#define ARM_CP_NEWEL 0x10000
80
-/* Mask of only the flag bits in a type field */
81
-#define ARM_CP_FLAG_MASK 0x1f0ff
82
+enum {
83
+ /*
84
+ * Register must be handled specially during translation.
85
+ * The method is one of the values below:
86
+ */
87
+ ARM_CP_SPECIAL_MASK = 0x000f,
88
+ /* Special: no change to PE state: writes ignored, reads ignored. */
89
+ ARM_CP_NOP = 0x0001,
90
+ /* Special: sysreg is WFI, for v5 and v6. */
91
+ ARM_CP_WFI = 0x0002,
92
+ /* Special: sysreg is NZCV. */
93
+ ARM_CP_NZCV = 0x0003,
94
+ /* Special: sysreg is CURRENTEL. */
95
+ ARM_CP_CURRENTEL = 0x0004,
96
+ /* Special: sysreg is DC ZVA or similar. */
97
+ ARM_CP_DC_ZVA = 0x0005,
98
+ ARM_CP_DC_GVA = 0x0006,
99
+ ARM_CP_DC_GZVA = 0x0007,
100
+
68
+
101
+ /* Flag: reads produce resetvalue; writes ignored. */
69
FSL_IMX8MP_PCI_INTA_IRQ = 126,
102
+ ARM_CP_CONST = 1 << 4,
70
FSL_IMX8MP_PCI_INTB_IRQ = 125,
103
+ /* Flag: For ARM_CP_STATE_AA32, sysreg is 64-bit. */
71
FSL_IMX8MP_PCI_INTC_IRQ = 124,
104
+ ARM_CP_64BIT = 1 << 5,
72
diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c
105
+ /*
106
+ * Flag: TB should not be ended after a write to this register
107
+ * (the default is that the TB ends after cp writes).
108
+ */
109
+ ARM_CP_SUPPRESS_TB_END = 1 << 6,
110
+ /*
111
+ * Flag: Permit a register definition to override a previous definition
112
+ * for the same (cp, is64, crn, crm, opc1, opc2) tuple: either the new
113
+ * or the old must have the ARM_CP_OVERRIDE bit set.
114
+ */
115
+ ARM_CP_OVERRIDE = 1 << 7,
116
+ /*
117
+ * Flag: Register is an alias view of some underlying state which is also
118
+ * visible via another register, and that the other register is handling
119
+ * migration and reset; registers marked ARM_CP_ALIAS will not be migrated
120
+ * but may have their state set by syncing of register state from KVM.
121
+ */
122
+ ARM_CP_ALIAS = 1 << 8,
123
+ /*
124
+ * Flag: Register does I/O and therefore its accesses need to be marked
125
+ * with gen_io_start() and also end the TB. In particular, registers which
126
+ * implement clocks or timers require this.
127
+ */
128
+ ARM_CP_IO = 1 << 9,
129
+ /*
130
+ * Flag: Register has no underlying state and does not support raw access
131
+ * for state saving/loading; it will not be used for either migration or
132
+ * KVM state synchronization. Typically this is for "registers" which are
133
+ * actually used as instructions for cache maintenance and so on.
134
+ */
135
+ ARM_CP_NO_RAW = 1 << 10,
136
+ /*
137
+ * Flag: The read or write hook might raise an exception; the generated
138
+ * code will synchronize the CPU state before calling the hook so that it
139
+ * is safe for the hook to call raise_exception().
140
+ */
141
+ ARM_CP_RAISES_EXC = 1 << 11,
142
+ /*
143
+ * Flag: Writes to the sysreg might change the exception level - typically
144
+ * on older ARM chips. For those cases we need to re-read the new el when
145
+ * recomputing the translation flags.
146
+ */
147
+ ARM_CP_NEWEL = 1 << 12,
148
+ /*
149
+ * Flag: Access check for this sysreg is identical to accessing FPU state
150
+ * from an instruction: use translation fp_access_check().
151
+ */
152
+ ARM_CP_FPU = 1 << 13,
153
+ /*
154
+ * Flag: Access check for this sysreg is identical to accessing SVE state
155
+ * from an instruction: use translation sve_access_check().
156
+ */
157
+ ARM_CP_SVE = 1 << 14,
158
+ /* Flag: Do not expose in gdb sysreg xml. */
159
+ ARM_CP_NO_GDB = 1 << 15,
160
+};
161
162
/*
163
* Valid values for ARMCPRegInfo state field, indicating which of
164
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
165
index XXXXXXX..XXXXXXX 100644
73
index XXXXXXX..XXXXXXX 100644
166
--- a/target/arm/cpu.c
74
--- a/hw/arm/fsl-imx8mp.c
167
+++ b/target/arm/cpu.c
75
+++ b/hw/arm/fsl-imx8mp.c
168
@@ -XXX,XX +XXX,XX @@ static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque)
76
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_init(Object *obj)
169
ARMCPRegInfo *ri = value;
77
object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL);
170
ARMCPU *cpu = opaque;
171
172
- if (ri->type & (ARM_CP_SPECIAL | ARM_CP_ALIAS)) {
173
+ if (ri->type & (ARM_CP_SPECIAL_MASK | ARM_CP_ALIAS)) {
174
return;
175
}
78
}
176
79
177
@@ -XXX,XX +XXX,XX @@ static void cp_reg_check_reset(gpointer key, gpointer value, gpointer opaque)
80
+ for (i = 0; i < FSL_IMX8MP_NUM_GPIOS; i++) {
178
ARMCPU *cpu = opaque;
81
+ g_autofree char *name = g_strdup_printf("gpio%d", i + 1);
179
uint64_t oldvalue, newvalue;
82
+ object_initialize_child(obj, name, &s->gpio[i], TYPE_IMX_GPIO);
180
83
+ }
181
- if (ri->type & (ARM_CP_SPECIAL | ARM_CP_ALIAS | ARM_CP_NO_RAW)) {
84
+
182
+ if (ri->type & (ARM_CP_SPECIAL_MASK | ARM_CP_ALIAS | ARM_CP_NO_RAW)) {
85
for (i = 0; i < FSL_IMX8MP_NUM_USDHCS; i++) {
183
return;
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));
184
}
90
}
185
91
186
diff --git a/target/arm/helper.c b/target/arm/helper.c
92
+ /* GPIOs */
187
index XXXXXXX..XXXXXXX 100644
93
+ for (i = 0; i < FSL_IMX8MP_NUM_GPIOS; i++) {
188
--- a/target/arm/helper.c
94
+ struct {
189
+++ b/target/arm/helper.c
95
+ hwaddr addr;
190
@@ -XXX,XX +XXX,XX @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
96
+ unsigned int irq_low;
191
* multiple times. Special registers (ie NOP/WFI) are
97
+ unsigned int irq_high;
192
* never migratable and not even raw-accessible.
98
+ } gpio_table[FSL_IMX8MP_NUM_GPIOS] = {
193
*/
99
+ {
194
- if ((r->type & ARM_CP_SPECIAL)) {
100
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPIO1].addr,
195
+ if (r->type & ARM_CP_SPECIAL_MASK) {
101
+ FSL_IMX8MP_GPIO1_LOW_IRQ,
196
r2->type |= ARM_CP_NO_RAW;
102
+ FSL_IMX8MP_GPIO1_HIGH_IRQ
197
}
103
+ },
198
if (((r->crm == CP_ANY) && crm != 0) ||
104
+ {
199
@@ -XXX,XX +XXX,XX @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
105
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPIO2].addr,
200
/* Check that the register definition has enough info to handle
106
+ FSL_IMX8MP_GPIO2_LOW_IRQ,
201
* reads and writes if they are permitted.
107
+ FSL_IMX8MP_GPIO2_HIGH_IRQ
202
*/
108
+ },
203
- if (!(r->type & (ARM_CP_SPECIAL|ARM_CP_CONST))) {
109
+ {
204
+ if (!(r->type & (ARM_CP_SPECIAL_MASK | ARM_CP_CONST))) {
110
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPIO3].addr,
205
if (r->access & PL3_R) {
111
+ FSL_IMX8MP_GPIO3_LOW_IRQ,
206
assert((r->fieldoffset ||
112
+ FSL_IMX8MP_GPIO3_HIGH_IRQ
207
(r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1])) ||
113
+ },
208
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
114
+ {
209
index XXXXXXX..XXXXXXX 100644
115
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPIO4].addr,
210
--- a/target/arm/translate-a64.c
116
+ FSL_IMX8MP_GPIO4_LOW_IRQ,
211
+++ b/target/arm/translate-a64.c
117
+ FSL_IMX8MP_GPIO4_HIGH_IRQ
212
@@ -XXX,XX +XXX,XX @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
118
+ },
213
}
119
+ {
214
120
+ fsl_imx8mp_memmap[FSL_IMX8MP_GPIO5].addr,
215
/* Handle special cases first */
121
+ FSL_IMX8MP_GPIO5_LOW_IRQ,
216
- switch (ri->type & ~(ARM_CP_FLAG_MASK & ~ARM_CP_SPECIAL)) {
122
+ FSL_IMX8MP_GPIO5_HIGH_IRQ
217
+ switch (ri->type & ARM_CP_SPECIAL_MASK) {
123
+ },
218
+ case 0:
124
+ };
219
+ break;
125
+
220
case ARM_CP_NOP:
126
+ object_property_set_bool(OBJECT(&s->gpio[i]), "has-edge-sel", true,
221
return;
127
+ &error_abort);
222
case ARM_CP_NZCV:
128
+ object_property_set_bool(OBJECT(&s->gpio[i]), "has-upper-pin-irq",
223
@@ -XXX,XX +XXX,XX @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
129
+ true, &error_abort);
224
}
130
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio[i]), errp)) {
225
return;
131
+ return;
226
default:
132
+ }
227
- break;
133
+
228
+ g_assert_not_reached();
134
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, gpio_table[i].addr);
229
}
135
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 0,
230
if ((ri->type & ARM_CP_FPU) && !fp_access_check(s)) {
136
+ qdev_get_gpio_in(gicdev, gpio_table[i].irq_low));
231
return;
137
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 1,
232
diff --git a/target/arm/translate.c b/target/arm/translate.c
138
+ qdev_get_gpio_in(gicdev, gpio_table[i].irq_high));
233
index XXXXXXX..XXXXXXX 100644
139
+ }
234
--- a/target/arm/translate.c
140
+
235
+++ b/target/arm/translate.c
141
/* USDHCs */
236
@@ -XXX,XX +XXX,XX @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64,
142
for (i = 0; i < FSL_IMX8MP_NUM_USDHCS; i++) {
237
}
143
struct {
238
144
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
239
/* Handle special cases first */
145
case FSL_IMX8MP_CCM:
240
- switch (ri->type & ~(ARM_CP_FLAG_MASK & ~ARM_CP_SPECIAL)) {
146
case FSL_IMX8MP_GIC_DIST:
241
+ switch (ri->type & ARM_CP_SPECIAL_MASK) {
147
case FSL_IMX8MP_GIC_REDIST:
242
+ case 0:
148
+ case FSL_IMX8MP_GPIO1 ... FSL_IMX8MP_GPIO5:
243
+ break;
149
case FSL_IMX8MP_PCIE1:
244
case ARM_CP_NOP:
150
case FSL_IMX8MP_PCIE_PHY1:
245
return;
151
case FSL_IMX8MP_RAM:
246
case ARM_CP_WFI:
247
@@ -XXX,XX +XXX,XX @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64,
248
s->base.is_jmp = DISAS_WFI;
249
return;
250
default:
251
- break;
252
+ g_assert_not_reached();
253
}
254
255
if ((tb_cflags(s->base.tb) & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
256
--
152
--
257
2.25.1
153
2.43.0
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Bernhard Beschow <shentey@gmail.com>
2
2
3
Put the block comments into the current coding style.
4
5
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
3
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Message-id: 20220501055028.646596-19-richard.henderson@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]
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
8
---
10
target/arm/helper.c | 24 +++++++++++++++---------
9
docs/system/arm/imx8mp-evk.rst | 1 +
11
1 file changed, 15 insertions(+), 9 deletions(-)
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(+)
12
14
13
diff --git a/target/arm/helper.c b/target/arm/helper.c
15
diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8mp-evk.rst
14
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
15
--- a/target/arm/helper.c
17
--- a/docs/system/arm/imx8mp-evk.rst
16
+++ b/target/arm/helper.c
18
+++ b/docs/system/arm/imx8mp-evk.rst
17
@@ -XXX,XX +XXX,XX @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
19
@@ -XXX,XX +XXX,XX @@ The ``imx8mp-evk`` machine implements the following devices:
18
return cpu_list;
20
* 3 USDHC Storage Controllers
19
}
21
* 1 Designware PCI Express Controller
20
22
* 5 GPIO Controllers
21
+/*
23
+ * 6 I2C Controllers
22
+ * Private utility function for define_one_arm_cp_reg_with_opaque():
24
* Secure Non-Volatile Storage (SNVS) including an RTC
23
+ * add a single reginfo struct to the hash table.
25
* Clock Tree
24
+ */
26
25
static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
27
diff --git a/include/hw/arm/fsl-imx8mp.h b/include/hw/arm/fsl-imx8mp.h
26
void *opaque, CPState state,
28
index XXXXXXX..XXXXXXX 100644
27
CPSecureState secstate,
29
--- a/include/hw/arm/fsl-imx8mp.h
28
int crm, int opc1, int opc2,
30
+++ b/include/hw/arm/fsl-imx8mp.h
29
const char *name)
31
@@ -XXX,XX +XXX,XX @@
30
{
32
#include "cpu.h"
31
- /* Private utility function for define_one_arm_cp_reg_with_opaque():
33
#include "hw/char/imx_serial.h"
32
- * add a single reginfo struct to the hash table.
34
#include "hw/gpio/imx_gpio.h"
33
- */
35
+#include "hw/i2c/imx_i2c.h"
34
uint32_t key;
36
#include "hw/intc/arm_gicv3_common.h"
35
ARMCPRegInfo *r2;
37
#include "hw/misc/imx7_snvs.h"
36
bool is64 = r->type & ARM_CP_64BIT;
38
#include "hw/misc/imx8mp_analog.h"
37
@@ -XXX,XX +XXX,XX @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
39
@@ -XXX,XX +XXX,XX @@ OBJECT_DECLARE_SIMPLE_TYPE(FslImx8mpState, FSL_IMX8MP)
38
40
enum FslImx8mpConfiguration {
39
isbanked = r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1];
41
FSL_IMX8MP_NUM_CPUS = 4,
40
if (isbanked) {
42
FSL_IMX8MP_NUM_GPIOS = 5,
41
- /* Register is banked (using both entries in array).
43
+ FSL_IMX8MP_NUM_I2CS = 6,
42
+ /*
44
FSL_IMX8MP_NUM_IRQS = 160,
43
+ * Register is banked (using both entries in array).
45
FSL_IMX8MP_NUM_UARTS = 4,
44
* Overwriting fieldoffset as the array is only used to define
46
FSL_IMX8MP_NUM_USDHCS = 3,
45
* banked registers but later only fieldoffset is used.
47
@@ -XXX,XX +XXX,XX @@ struct FslImx8mpState {
46
*/
48
IMX8MPCCMState ccm;
47
@@ -XXX,XX +XXX,XX @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
49
IMX8MPAnalogState analog;
48
50
IMX7SNVSState snvs;
49
if (state == ARM_CP_STATE_AA32) {
51
+ IMXI2CState i2c[FSL_IMX8MP_NUM_I2CS];
50
if (isbanked) {
52
IMXSerialState uart[FSL_IMX8MP_NUM_UARTS];
51
- /* If the register is banked then we don't need to migrate or
53
SDHCIState usdhc[FSL_IMX8MP_NUM_USDHCS];
52
+ /*
54
DesignwarePCIEHost pcie;
53
+ * If the register is banked then we don't need to migrate or
55
@@ -XXX,XX +XXX,XX @@ enum FslImx8mpIrqs {
54
* reset the 32-bit instance in certain cases:
56
FSL_IMX8MP_UART5_IRQ = 30,
55
*
57
FSL_IMX8MP_UART6_IRQ = 16,
56
* 1) If the register has both 32-bit and 64-bit instances then we
58
57
@@ -XXX,XX +XXX,XX @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
59
+ FSL_IMX8MP_I2C1_IRQ = 35,
58
r2->type |= ARM_CP_ALIAS;
60
+ FSL_IMX8MP_I2C2_IRQ = 36,
59
}
61
+ FSL_IMX8MP_I2C3_IRQ = 37,
60
} else if ((secstate != r->secure) && !ns) {
62
+ FSL_IMX8MP_I2C4_IRQ = 38,
61
- /* The register is not banked so we only want to allow migration of
63
+
62
- * the non-secure instance.
64
FSL_IMX8MP_GPIO1_LOW_IRQ = 64,
63
+ /*
65
FSL_IMX8MP_GPIO1_HIGH_IRQ = 65,
64
+ * The register is not banked so we only want to allow migration
66
FSL_IMX8MP_GPIO2_LOW_IRQ = 66,
65
+ * of the non-secure instance.
67
@@ -XXX,XX +XXX,XX @@ enum FslImx8mpIrqs {
66
*/
68
FSL_IMX8MP_GPIO5_LOW_IRQ = 72,
67
r2->type |= ARM_CP_ALIAS;
69
FSL_IMX8MP_GPIO5_HIGH_IRQ = 73,
68
}
70
69
@@ -XXX,XX +XXX,XX @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
71
+ FSL_IMX8MP_I2C5_IRQ = 76,
70
}
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);
71
}
83
}
72
84
73
- /* By convention, for wildcarded registers only the first
85
+ for (i = 0; i < FSL_IMX8MP_NUM_I2CS; i++) {
74
+ /*
86
+ g_autofree char *name = g_strdup_printf("i2c%d", i + 1);
75
+ * By convention, for wildcarded registers only the first
87
+ object_initialize_child(obj, name, &s->i2c[i], TYPE_IMX_I2C);
76
* entry is used for migration; the others are marked as
88
+ }
77
* ALIAS so we don't try to transfer the register
89
+
78
* multiple times. Special registers (ie NOP/WFI) are
90
for (i = 0; i < FSL_IMX8MP_NUM_GPIOS; i++) {
79
@@ -XXX,XX +XXX,XX @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
91
g_autofree char *name = g_strdup_printf("gpio%d", i + 1);
80
r2->type |= ARM_CP_ALIAS | ARM_CP_NO_GDB;
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));
81
}
95
}
82
96
83
- /* Check that raw accesses are either forbidden or handled. Note that
97
+ /* I2Cs */
84
+ /*
98
+ for (i = 0; i < FSL_IMX8MP_NUM_I2CS; i++) {
85
+ * Check that raw accesses are either forbidden or handled. Note that
99
+ struct {
86
* we can't assert this earlier because the setup of fieldoffset for
100
+ hwaddr addr;
87
* banked registers has to be done first.
101
+ unsigned int irq;
88
*/
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
89
--
149
--
90
2.25.1
150
2.43.0
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Bernhard Beschow <shentey@gmail.com>
2
2
3
Perform the override check early, so that it is still done
4
even when we decide to discard an unreachable cpreg.
5
6
Use assert not printf+abort.
7
8
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
3
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Message-id: 20220501055028.646596-18-richard.henderson@linaro.org
4
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
5
Message-id: 20250223114708.1780-12-shentey@gmail.com
6
[PMM: drop static const from spi_table for GCC 7.5]
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
---
8
---
13
target/arm/helper.c | 22 ++++++++--------------
9
docs/system/arm/imx8mp-evk.rst | 1 +
14
1 file changed, 8 insertions(+), 14 deletions(-)
10
include/hw/arm/fsl-imx8mp.h | 8 ++++++++
11
hw/arm/fsl-imx8mp.c | 26 ++++++++++++++++++++++++++
12
3 files changed, 35 insertions(+)
15
13
16
diff --git a/target/arm/helper.c b/target/arm/helper.c
14
diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8mp-evk.rst
17
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
18
--- a/target/arm/helper.c
16
--- a/docs/system/arm/imx8mp-evk.rst
19
+++ b/target/arm/helper.c
17
+++ b/docs/system/arm/imx8mp-evk.rst
20
@@ -XXX,XX +XXX,XX @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
18
@@ -XXX,XX +XXX,XX @@ The ``imx8mp-evk`` machine implements the following devices:
21
g_assert_not_reached();
19
* 1 Designware PCI Express Controller
20
* 5 GPIO Controllers
21
* 6 I2C Controllers
22
+ * 3 SPI 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
#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,
62
+
63
FSL_IMX8MP_I2C1_IRQ = 35,
64
FSL_IMX8MP_I2C2_IRQ = 36,
65
FSL_IMX8MP_I2C3_IRQ = 37,
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->usdhc[i], TYPE_IMX_USDHC);
22
}
72
}
23
73
24
+ /* Overriding of an existing definition must be explicitly requested. */
74
+ for (i = 0; i < FSL_IMX8MP_NUM_ECSPIS; i++) {
25
+ if (!(r->type & ARM_CP_OVERRIDE)) {
75
+ g_autofree char *name = g_strdup_printf("spi%d", i + 1);
26
+ const ARMCPRegInfo *oldreg = get_arm_cp_reginfo(cpu->cp_regs, key);
76
+ object_initialize_child(obj, name, &s->spi[i], TYPE_IMX_SPI);
27
+ if (oldreg) {
28
+ assert(oldreg->type & ARM_CP_OVERRIDE);
29
+ }
30
+ }
77
+ }
31
+
78
+
32
/* Combine cpreg and name into one allocation. */
79
object_initialize_child(obj, "pcie", &s->pcie, TYPE_DESIGNWARE_PCIE_HOST);
33
name_len = strlen(name) + 1;
80
object_initialize_child(obj, "pcie_phy", &s->pcie_phy,
34
r2 = g_malloc(sizeof(*r2) + name_len);
81
TYPE_FSL_IMX8M_PCIE_PHY);
35
@@ -XXX,XX +XXX,XX @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
82
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
36
assert(!raw_accessors_invalid(r2));
83
qdev_get_gpio_in(gicdev, usdhc_table[i].irq));
37
}
84
}
38
85
39
- /* Overriding of an existing definition must be explicitly
86
+ /* ECSPIs */
40
- * requested.
87
+ for (i = 0; i < FSL_IMX8MP_NUM_ECSPIS; i++) {
41
- */
88
+ struct {
42
- if (!(r->type & ARM_CP_OVERRIDE)) {
89
+ hwaddr addr;
43
- const ARMCPRegInfo *oldreg = get_arm_cp_reginfo(cpu->cp_regs, key);
90
+ unsigned int irq;
44
- if (oldreg && !(oldreg->type & ARM_CP_OVERRIDE)) {
91
+ } spi_table[FSL_IMX8MP_NUM_ECSPIS] = {
45
- fprintf(stderr, "Register redefined: cp=%d %d bit "
92
+ { fsl_imx8mp_memmap[FSL_IMX8MP_ECSPI1].addr, FSL_IMX8MP_ECSPI1_IRQ },
46
- "crn=%d crm=%d opc1=%d opc2=%d, "
93
+ { fsl_imx8mp_memmap[FSL_IMX8MP_ECSPI2].addr, FSL_IMX8MP_ECSPI2_IRQ },
47
- "was %s, now %s\n", r2->cp, 32 + 32 * is64,
94
+ { fsl_imx8mp_memmap[FSL_IMX8MP_ECSPI3].addr, FSL_IMX8MP_ECSPI3_IRQ },
48
- r2->crn, r2->crm, r2->opc1, r2->opc2,
95
+ };
49
- oldreg->name, r2->name);
96
+
50
- g_assert_not_reached();
97
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), errp)) {
51
- }
98
+ return;
52
- }
99
+ }
53
g_hash_table_insert(cpu->cp_regs, (gpointer)(uintptr_t)key, r2);
100
+
54
}
101
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, spi_table[i].addr);
55
102
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi[i]), 0,
103
+ qdev_get_gpio_in(gicdev, spi_table[i].irq));
104
+ }
105
+
106
/* SNVS */
107
if (!sysbus_realize(SYS_BUS_DEVICE(&s->snvs), errp)) {
108
return;
109
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
110
case FSL_IMX8MP_GIC_DIST:
111
case FSL_IMX8MP_GIC_REDIST:
112
case FSL_IMX8MP_GPIO1 ... FSL_IMX8MP_GPIO5:
113
+ case FSL_IMX8MP_ECSPI1 ... FSL_IMX8MP_ECSPI3:
114
case FSL_IMX8MP_I2C1 ... FSL_IMX8MP_I2C6:
115
case FSL_IMX8MP_PCIE1:
116
case FSL_IMX8MP_PCIE_PHY1:
56
--
117
--
57
2.25.1
118
2.43.0
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Bernhard Beschow <shentey@gmail.com>
2
2
3
Move the computation of key to the top of the function.
4
Hoist the resolution of cp as well, as an input to the
5
computation of key.
6
7
This will be required by a subsequent patch.
8
9
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
3
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
11
Message-id: 20220501055028.646596-14-richard.henderson@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]
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 | 49 +++++++++++++++++++++++++--------------------
9
docs/system/arm/imx8mp-evk.rst | 1 +
15
1 file changed, 27 insertions(+), 22 deletions(-)
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(+)
16
14
17
diff --git a/target/arm/helper.c b/target/arm/helper.c
15
diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8mp-evk.rst
18
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
19
--- a/target/arm/helper.c
17
--- a/docs/system/arm/imx8mp-evk.rst
20
+++ b/target/arm/helper.c
18
+++ b/docs/system/arm/imx8mp-evk.rst
21
@@ -XXX,XX +XXX,XX @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
19
@@ -XXX,XX +XXX,XX @@ The ``imx8mp-evk`` machine implements the following devices:
22
ARMCPRegInfo *r2;
20
* 5 GPIO Controllers
23
int is64 = (r->type & ARM_CP_64BIT) ? 1 : 0;
21
* 6 I2C Controllers
24
int ns = (secstate & ARM_CP_SECSTATE_NS) ? 1 : 0;
22
* 3 SPI Controllers
25
+ int cp = r->cp;
23
+ * 3 Watchdogs
26
size_t name_len;
24
* Secure Non-Volatile Storage (SNVS) including an RTC
27
25
* Clock Tree
28
+ switch (state) {
26
29
+ case ARM_CP_STATE_AA32:
27
diff --git a/include/hw/arm/fsl-imx8mp.h b/include/hw/arm/fsl-imx8mp.h
30
+ /* We assume it is a cp15 register if the .cp field is left unset. */
28
index XXXXXXX..XXXXXXX 100644
31
+ if (cp == 0 && r->state == ARM_CP_STATE_BOTH) {
29
--- a/include/hw/arm/fsl-imx8mp.h
32
+ cp = 15;
30
+++ b/include/hw/arm/fsl-imx8mp.h
33
+ }
31
@@ -XXX,XX +XXX,XX @@
34
+ key = ENCODE_CP_REG(cp, is64, ns, r->crn, crm, opc1, opc2);
32
#include "hw/pci-host/fsl_imx8m_phy.h"
35
+ break;
33
#include "hw/sd/sdhci.h"
36
+ case ARM_CP_STATE_AA64:
34
#include "hw/ssi/imx_spi.h"
37
+ /*
35
+#include "hw/watchdog/wdt_imx2.h"
38
+ * To allow abbreviation of ARMCPRegInfo definitions, we treat
36
#include "qom/object.h"
39
+ * cp == 0 as equivalent to the value for "standard guest-visible
37
#include "qemu/units.h"
40
+ * sysreg". STATE_BOTH definitions are also always "standard sysreg"
38
41
+ * in their AArch64 view (the .cp value may be non-zero for the
39
@@ -XXX,XX +XXX,XX @@ enum FslImx8mpConfiguration {
42
+ * benefit of the AArch32 view).
40
FSL_IMX8MP_NUM_IRQS = 160,
43
+ */
41
FSL_IMX8MP_NUM_UARTS = 4,
44
+ if (cp == 0 || r->state == ARM_CP_STATE_BOTH) {
42
FSL_IMX8MP_NUM_USDHCS = 3,
45
+ cp = CP_REG_ARM64_SYSREG_CP;
43
+ FSL_IMX8MP_NUM_WDTS = 3,
46
+ }
44
};
47
+ key = ENCODE_AA64_CP_REG(cp, r->crn, crm, r->opc0, opc1, opc2);
45
48
+ break;
46
struct FslImx8mpState {
49
+ default:
47
@@ -XXX,XX +XXX,XX @@ struct FslImx8mpState {
50
+ g_assert_not_reached();
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);
51
+ }
77
+ }
52
+
78
+
53
/* Combine cpreg and name into one allocation. */
79
object_initialize_child(obj, "pcie", &s->pcie, TYPE_DESIGNWARE_PCIE_HOST);
54
name_len = strlen(name) + 1;
80
object_initialize_child(obj, "pcie_phy", &s->pcie_phy,
55
r2 = g_malloc(sizeof(*r2) + name_len);
81
TYPE_FSL_IMX8M_PCIE_PHY);
56
@@ -XXX,XX +XXX,XX @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
82
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
57
}
83
sysbus_mmio_map(SYS_BUS_DEVICE(&s->snvs), 0,
58
84
fsl_imx8mp_memmap[FSL_IMX8MP_SNVS_HP].addr);
59
if (r->state == ARM_CP_STATE_BOTH) {
85
60
- /* We assume it is a cp15 register if the .cp field is left unset.
86
+ /* Watchdogs */
61
- */
87
+ for (i = 0; i < FSL_IMX8MP_NUM_WDTS; i++) {
62
- if (r2->cp == 0) {
88
+ struct {
63
- r2->cp = 15;
89
+ hwaddr addr;
64
- }
90
+ unsigned int irq;
65
-
91
+ } wdog_table[FSL_IMX8MP_NUM_WDTS] = {
66
#if HOST_BIG_ENDIAN
92
+ { fsl_imx8mp_memmap[FSL_IMX8MP_WDOG1].addr, FSL_IMX8MP_WDOG1_IRQ },
67
if (r2->fieldoffset) {
93
+ { fsl_imx8mp_memmap[FSL_IMX8MP_WDOG2].addr, FSL_IMX8MP_WDOG2_IRQ },
68
r2->fieldoffset += sizeof(uint32_t);
94
+ { fsl_imx8mp_memmap[FSL_IMX8MP_WDOG3].addr, FSL_IMX8MP_WDOG3_IRQ },
69
@@ -XXX,XX +XXX,XX @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
95
+ };
70
#endif
96
+
71
}
97
+ object_property_set_bool(OBJECT(&s->wdt[i]), "pretimeout-support",
72
}
98
+ true, &error_abort);
73
- if (state == ARM_CP_STATE_AA64) {
99
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) {
74
- /* To allow abbreviation of ARMCPRegInfo
100
+ return;
75
- * definitions, we treat cp == 0 as equivalent to
101
+ }
76
- * the value for "standard guest-visible sysreg".
102
+
77
- * STATE_BOTH definitions are also always "standard
103
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0, wdog_table[i].addr);
78
- * sysreg" in their AArch64 view (the .cp value may
104
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt[i]), 0,
79
- * be non-zero for the benefit of the AArch32 view).
105
+ qdev_get_gpio_in(gicdev, wdog_table[i].irq));
80
- */
106
+ }
81
- if (r->cp == 0 || r->state == ARM_CP_STATE_BOTH) {
107
+
82
- r2->cp = CP_REG_ARM64_SYSREG_CP;
108
/* PCIe */
83
- }
109
if (!sysbus_realize(SYS_BUS_DEVICE(&s->pcie), errp)) {
84
- key = ENCODE_AA64_CP_REG(r2->cp, r2->crn, crm,
110
return;
85
- r2->opc0, opc1, opc2);
111
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
86
- } else {
112
case FSL_IMX8MP_SNVS_HP:
87
- key = ENCODE_CP_REG(r2->cp, is64, ns, r2->crn, crm, opc1, opc2);
113
case FSL_IMX8MP_UART1 ... FSL_IMX8MP_UART4:
88
- }
114
case FSL_IMX8MP_USDHC1 ... FSL_IMX8MP_USDHC3:
89
if (opaque) {
115
+ case FSL_IMX8MP_WDOG1 ... FSL_IMX8MP_WDOG3:
90
r2->opaque = opaque;
116
/* device implemented and treated above */
91
}
117
break;
92
@@ -XXX,XX +XXX,XX @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
118
93
/* Make sure reginfo passed to helpers for wildcarded regs
119
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
94
* has the correct crm/opc1/opc2 for this reg, not CP_ANY:
120
index XXXXXXX..XXXXXXX 100644
95
*/
121
--- a/hw/arm/Kconfig
96
+ r2->cp = cp;
122
+++ b/hw/arm/Kconfig
97
r2->crm = crm;
123
@@ -XXX,XX +XXX,XX @@ config FSL_IMX8MP
98
r2->opc1 = opc1;
124
select PCI_EXPRESS_FSL_IMX8M_PHY
99
r2->opc2 = opc2;
125
select SDHCI
126
select UNIMP
127
+ select WDT_IMX2
128
129
config FSL_IMX8MP_EVK
130
bool
100
--
131
--
101
2.25.1
132
2.43.0
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Bernhard Beschow <shentey@gmail.com>
2
3
Add the aa64 predicate for detecting RAS support from id registers.
4
We already have the aa32 version from the M-profile work.
5
Add the 'any' predicate for testing both aa64 and aa32.
6
2
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
3
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
4
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
9
Message-id: 20220501055028.646596-34-richard.henderson@linaro.org
5
Message-id: 20250223114708.1780-14-shentey@gmail.com
6
[PMM: drop static const from gpt_attrs for GCC 7.5]
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
8
---
12
target/arm/cpu.h | 10 ++++++++++
9
docs/system/arm/imx8mp-evk.rst | 1 +
13
1 file changed, 10 insertions(+)
10
include/hw/arm/fsl-imx8mp.h | 11 +++++++
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(+)
14
16
15
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
17
diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8mp-evk.rst
16
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
17
--- a/target/arm/cpu.h
19
--- a/docs/system/arm/imx8mp-evk.rst
18
+++ b/target/arm/cpu.h
20
+++ b/docs/system/arm/imx8mp-evk.rst
19
@@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_aa32_el1(const ARMISARegisters *id)
21
@@ -XXX,XX +XXX,XX @@ The ``imx8mp-evk`` machine implements the following devices:
20
return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, EL1) >= 2;
22
* 6 I2C Controllers
23
* 3 SPI Controllers
24
* 3 Watchdogs
25
+ * 6 General Purpose Timers
26
* Secure Non-Volatile Storage (SNVS) including an RTC
27
* Clock Tree
28
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 "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);
101
}
102
103
+ for (i = 0; i < FSL_IMX8MP_NUM_GPTS; i++) {
104
+ g_autofree char *name = g_strdup_printf("gpt%d", i + 1);
105
+ object_initialize_child(obj, name, &s->gpt[i], TYPE_IMX8MP_GPT);
106
+ }
107
+ object_initialize_child(obj, "gpt5-gpt6-irq", &s->gpt5_gpt6_irq,
108
+ TYPE_OR_IRQ);
109
+
110
for (i = 0; i < FSL_IMX8MP_NUM_I2CS; i++) {
111
g_autofree char *name = g_strdup_printf("i2c%d", i + 1);
112
object_initialize_child(obj, name, &s->i2c[i], TYPE_IMX_I2C);
113
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
114
qdev_get_gpio_in(gicdev, serial_table[i].irq));
115
}
116
117
+ /* GPTs */
118
+ object_property_set_int(OBJECT(&s->gpt5_gpt6_irq), "num-lines", 2,
119
+ &error_abort);
120
+ if (!qdev_realize(DEVICE(&s->gpt5_gpt6_irq), NULL, errp)) {
121
+ return;
122
+ }
123
+
124
+ qdev_connect_gpio_out(DEVICE(&s->gpt5_gpt6_irq), 0,
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;
21
}
190
}
22
191
23
+static inline bool isar_feature_aa64_ras(const ARMISARegisters *id)
192
+static void imx8mp_gpt_init(Object *obj)
24
+{
193
+{
25
+ return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, RAS) != 0;
194
+ IMXGPTState *s = IMX_GPT(obj);
195
+
196
+ s->clocks = imx8mp_gpt_clocks;
26
+}
197
+}
27
+
198
+
28
static inline bool isar_feature_aa64_sve(const ARMISARegisters *id)
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)
29
{
213
{
30
return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, SVE) != 0;
214
type_register_static(&imx25_gpt_info);
31
@@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_any_debugv8p2(const ARMISARegisters *id)
215
@@ -XXX,XX +XXX,XX @@ static void imx_gpt_register_types(void)
32
return isar_feature_aa64_debugv8p2(id) || isar_feature_aa32_debugv8p2(id);
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);
33
}
220
}
34
221
35
+static inline bool isar_feature_any_ras(const ARMISARegisters *id)
222
type_init(imx_gpt_register_types)
36
+{
223
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
37
+ return isar_feature_aa64_ras(id) || isar_feature_aa32_ras(id);
224
index XXXXXXX..XXXXXXX 100644
38
+}
225
--- a/hw/arm/Kconfig
39
+
226
+++ b/hw/arm/Kconfig
40
/*
227
@@ -XXX,XX +XXX,XX @@ config FSL_IMX8MP
41
* Forward to the above feature tests given an ARMCPU pointer.
228
select FSL_IMX8MP_CCM
42
*/
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
43
--
235
--
44
2.25.1
236
2.43.0
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Bernhard Beschow <shentey@gmail.com>
2
2
3
Remove a possible source of error by removing REGINFO_SENTINEL
3
The i.MX 8M Plus SoC actually has two ethernet controllers, the usual ENET one
4
and using ARRAY_SIZE (convinently hidden inside a macro) to
4
and a Designware one. There is no device model for the latter, so only add the
5
find the end of the set of regs being registered or modified.
5
ENET one.
6
6
7
The space saved by not having the extra array element reduces
8
the executable's .data.rel.ro section by about 9k.
9
10
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
11
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
13
Message-id: 20220501055028.646596-4-richard.henderson@linaro.org
9
Message-id: 20250223114708.1780-15-shentey@gmail.com
14
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
---
11
---
16
target/arm/cpregs.h | 53 +++++++++---------
12
docs/system/arm/imx8mp-evk.rst | 1 +
17
hw/arm/pxa2xx.c | 1 -
13
include/hw/arm/fsl-imx8mp.h | 8 ++++++++
18
hw/arm/pxa2xx_pic.c | 1 -
14
hw/arm/fsl-imx8mp.c | 24 ++++++++++++++++++++++++
19
hw/intc/arm_gicv3_cpuif.c | 5 --
15
hw/arm/imx8mp-evk.c | 1 +
20
hw/intc/arm_gicv3_kvm.c | 1 -
16
hw/arm/Kconfig | 1 +
21
target/arm/cpu64.c | 1 -
17
5 files changed, 35 insertions(+)
22
target/arm/cpu_tcg.c | 4 --
23
target/arm/helper.c | 111 ++++++++------------------------------
24
8 files changed, 48 insertions(+), 129 deletions(-)
25
18
26
diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
19
diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8mp-evk.rst
27
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
28
--- a/target/arm/cpregs.h
21
--- a/docs/system/arm/imx8mp-evk.rst
29
+++ b/target/arm/cpregs.h
22
+++ b/docs/system/arm/imx8mp-evk.rst
23
@@ -XXX,XX +XXX,XX @@ The ``imx8mp-evk`` machine implements the following devices:
24
* 4 UARTs
25
* 3 USDHC Storage Controllers
26
* 1 Designware PCI Express Controller
27
+ * 1 Ethernet Controller
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
30
@@ -XXX,XX +XXX,XX @@
35
@@ -XXX,XX +XXX,XX @@
31
#define ARM_CP_NO_GDB 0x4000
36
#include "hw/misc/imx7_snvs.h"
32
#define ARM_CP_RAISES_EXC 0x8000
37
#include "hw/misc/imx8mp_analog.h"
33
#define ARM_CP_NEWEL 0x10000
38
#include "hw/misc/imx8mp_ccm.h"
34
-/* Used only as a terminator for ARMCPRegInfo lists */
39
+#include "hw/net/imx_fec.h"
35
-#define ARM_CP_SENTINEL 0xfffff
40
#include "hw/or-irq.h"
36
/* Mask of only the flag bits in a type field */
41
#include "hw/pci-host/designware.h"
37
#define ARM_CP_FLAG_MASK 0x1f0ff
42
#include "hw/pci-host/fsl_imx8m_phy.h"
38
43
@@ -XXX,XX +XXX,XX @@ struct FslImx8mpState {
39
@@ -XXX,XX +XXX,XX @@ enum {
44
IMXSPIState spi[FSL_IMX8MP_NUM_ECSPIS];
40
ARM_CP_SECSTATE_NS = (1 << 1), /* bit[1]: Non-secure state register */
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;
41
};
56
};
42
57
43
-/*
58
enum FslImx8mpMemoryRegions {
44
- * Return true if cptype is a valid type field. This is used to try to
59
@@ -XXX,XX +XXX,XX @@ enum FslImx8mpIrqs {
45
- * catch errors where the sentinel has been accidentally left off the end
60
FSL_IMX8MP_WDOG2_IRQ = 79,
46
- * of a list of registers.
61
FSL_IMX8MP_WDOG3_IRQ = 10,
47
- */
62
48
-static inline bool cptype_valid(int cptype)
63
+ FSL_IMX8MP_ENET1_MAC_IRQ = 118,
49
-{
64
+ FSL_IMX6_ENET1_MAC_1588_IRQ = 121,
50
- return ((cptype & ~ARM_CP_FLAG_MASK) == 0)
51
- || ((cptype & ARM_CP_SPECIAL) &&
52
- ((cptype & ~ARM_CP_FLAG_MASK) <= ARM_LAST_SPECIAL));
53
-}
54
-
55
/*
56
* Access rights:
57
* We define bits for Read and Write access for what rev C of the v7-AR ARM ARM
58
@@ -XXX,XX +XXX,XX @@ struct ARMCPRegInfo {
59
#define CPREG_FIELD64(env, ri) \
60
(*(uint64_t *)((char *)(env) + (ri)->fieldoffset))
61
62
-#define REGINFO_SENTINEL { .type = ARM_CP_SENTINEL }
63
+void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu, const ARMCPRegInfo *reg,
64
+ void *opaque);
65
66
-void define_arm_cp_regs_with_opaque(ARMCPU *cpu,
67
- const ARMCPRegInfo *regs, void *opaque);
68
-void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
69
- const ARMCPRegInfo *regs, void *opaque);
70
-static inline void define_arm_cp_regs(ARMCPU *cpu, const ARMCPRegInfo *regs)
71
-{
72
- define_arm_cp_regs_with_opaque(cpu, regs, 0);
73
-}
74
static inline void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *regs)
75
{
76
- define_one_arm_cp_reg_with_opaque(cpu, regs, 0);
77
+ define_one_arm_cp_reg_with_opaque(cpu, regs, NULL);
78
}
79
+
65
+
80
+void define_arm_cp_regs_with_opaque_len(ARMCPU *cpu, const ARMCPRegInfo *regs,
66
FSL_IMX8MP_PCI_INTA_IRQ = 126,
81
+ void *opaque, size_t len);
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);
82
+
78
+
83
+#define define_arm_cp_regs_with_opaque(CPU, REGS, OPAQUE) \
79
object_initialize_child(obj, "pcie", &s->pcie, TYPE_DESIGNWARE_PCIE_HOST);
84
+ do { \
80
object_initialize_child(obj, "pcie_phy", &s->pcie_phy,
85
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(REGS) == 0); \
81
TYPE_FSL_IMX8M_PCIE_PHY);
86
+ define_arm_cp_regs_with_opaque_len(CPU, REGS, OPAQUE, \
82
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
87
+ ARRAY_SIZE(REGS)); \
83
qdev_get_gpio_in(gicdev, spi_table[i].irq));
88
+ } while (0)
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));
89
+
100
+
90
+#define define_arm_cp_regs(CPU, REGS) \
101
/* SNVS */
91
+ define_arm_cp_regs_with_opaque(CPU, REGS, NULL)
102
if (!sysbus_realize(SYS_BUS_DEVICE(&s->snvs), errp)) {
92
+
103
return;
93
const ARMCPRegInfo *get_arm_cp_reginfo(GHashTable *cpregs, uint32_t encoded_cp);
104
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
94
105
case FSL_IMX8MP_GIC_REDIST:
95
/*
106
case FSL_IMX8MP_GPIO1 ... FSL_IMX8MP_GPIO5:
96
@@ -XXX,XX +XXX,XX @@ typedef struct ARMCPRegUserSpaceInfo {
107
case FSL_IMX8MP_ECSPI1 ... FSL_IMX8MP_ECSPI3:
97
uint64_t fixed_bits;
108
+ case FSL_IMX8MP_ENET1:
98
} ARMCPRegUserSpaceInfo;
109
case FSL_IMX8MP_I2C1 ... FSL_IMX8MP_I2C6:
99
110
case FSL_IMX8MP_PCIE1:
100
-#define REGUSERINFO_SENTINEL { .name = NULL }
111
case FSL_IMX8MP_PCIE_PHY1:
101
+void modify_arm_cp_regs_with_len(ARMCPRegInfo *regs, size_t regs_len,
112
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
102
+ const ARMCPRegUserSpaceInfo *mods,
103
+ size_t mods_len);
104
105
-void modify_arm_cp_regs(ARMCPRegInfo *regs, const ARMCPRegUserSpaceInfo *mods);
106
+#define modify_arm_cp_regs(REGS, MODS) \
107
+ do { \
108
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(REGS) == 0); \
109
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(MODS) == 0); \
110
+ modify_arm_cp_regs_with_len(REGS, ARRAY_SIZE(REGS), \
111
+ MODS, ARRAY_SIZE(MODS)); \
112
+ } while (0)
113
114
/* CPWriteFn that can be used to implement writes-ignored behaviour */
115
void arm_cp_write_ignore(CPUARMState *env, const ARMCPRegInfo *ri,
116
diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c
117
index XXXXXXX..XXXXXXX 100644
118
--- a/hw/arm/pxa2xx.c
119
+++ b/hw/arm/pxa2xx.c
120
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo pxa_cp_reginfo[] = {
121
{ .name = "PWRMODE", .cp = 14, .crn = 7, .crm = 0, .opc1 = 0, .opc2 = 0,
122
.access = PL1_RW, .type = ARM_CP_IO,
123
.readfn = arm_cp_read_zero, .writefn = pxa2xx_pwrmode_write },
124
- REGINFO_SENTINEL
125
};
126
127
static void pxa2xx_setup_cp14(PXA2xxState *s)
128
diff --git a/hw/arm/pxa2xx_pic.c b/hw/arm/pxa2xx_pic.c
129
index XXXXXXX..XXXXXXX 100644
130
--- a/hw/arm/pxa2xx_pic.c
131
+++ b/hw/arm/pxa2xx_pic.c
132
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo pxa_pic_cp_reginfo[] = {
133
REGINFO_FOR_PIC_CP("ICLR2", 8),
134
REGINFO_FOR_PIC_CP("ICFP2", 9),
135
REGINFO_FOR_PIC_CP("ICPR2", 0xa),
136
- REGINFO_SENTINEL
137
};
138
139
static const MemoryRegionOps pxa2xx_pic_ops = {
140
diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
141
index XXXXXXX..XXXXXXX 100644
142
--- a/hw/intc/arm_gicv3_cpuif.c
143
+++ b/hw/intc/arm_gicv3_cpuif.c
144
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = {
145
.readfn = icc_igrpen1_el3_read,
146
.writefn = icc_igrpen1_el3_write,
147
},
148
- REGINFO_SENTINEL
149
};
150
151
static uint64_t ich_ap_read(CPUARMState *env, const ARMCPRegInfo *ri)
152
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo gicv3_cpuif_hcr_reginfo[] = {
153
.readfn = ich_vmcr_read,
154
.writefn = ich_vmcr_write,
155
},
156
- REGINFO_SENTINEL
157
};
158
159
static const ARMCPRegInfo gicv3_cpuif_ich_apxr1_reginfo[] = {
160
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo gicv3_cpuif_ich_apxr1_reginfo[] = {
161
.readfn = ich_ap_read,
162
.writefn = ich_ap_write,
163
},
164
- REGINFO_SENTINEL
165
};
166
167
static const ARMCPRegInfo gicv3_cpuif_ich_apxr23_reginfo[] = {
168
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo gicv3_cpuif_ich_apxr23_reginfo[] = {
169
.readfn = ich_ap_read,
170
.writefn = ich_ap_write,
171
},
172
- REGINFO_SENTINEL
173
};
174
175
static void gicv3_cpuif_el_change_hook(ARMCPU *cpu, void *opaque)
176
@@ -XXX,XX +XXX,XX @@ void gicv3_init_cpuif(GICv3State *s)
177
.readfn = ich_lr_read,
178
.writefn = ich_lr_write,
179
},
180
- REGINFO_SENTINEL
181
};
182
define_arm_cp_regs(cpu, lr_regset);
183
}
184
diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c
185
index XXXXXXX..XXXXXXX 100644
186
--- a/hw/intc/arm_gicv3_kvm.c
187
+++ b/hw/intc/arm_gicv3_kvm.c
188
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo gicv3_cpuif_reginfo[] = {
189
*/
190
.resetfn = arm_gicv3_icc_reset,
191
},
192
- REGINFO_SENTINEL
193
};
194
195
/**
196
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
197
index XXXXXXX..XXXXXXX 100644
198
--- a/target/arm/cpu64.c
199
+++ b/target/arm/cpu64.c
200
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo cortex_a72_a57_a53_cp_reginfo[] = {
201
{ .name = "L2MERRSR",
202
.cp = 15, .opc1 = 3, .crm = 15,
203
.access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_64BIT, .resetvalue = 0 },
204
- REGINFO_SENTINEL
205
};
206
207
static void aarch64_a57_initfn(Object *obj)
208
diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c
209
index XXXXXXX..XXXXXXX 100644
210
--- a/target/arm/cpu_tcg.c
211
+++ b/target/arm/cpu_tcg.c
212
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo cortexa8_cp_reginfo[] = {
213
.access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
214
{ .name = "L2AUXCR", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 2,
215
.access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
216
- REGINFO_SENTINEL
217
};
218
219
static void cortex_a8_initfn(Object *obj)
220
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo cortexa9_cp_reginfo[] = {
221
.access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST },
222
{ .name = "TLB_ATTR", .cp = 15, .crn = 15, .crm = 7, .opc1 = 5, .opc2 = 2,
223
.access = PL1_RW, .resetvalue = 0, .type = ARM_CP_CONST },
224
- REGINFO_SENTINEL
225
};
226
227
static void cortex_a9_initfn(Object *obj)
228
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo cortexa15_cp_reginfo[] = {
229
#endif
230
{ .name = "L2ECTLR", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 3,
231
.access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
232
- REGINFO_SENTINEL
233
};
234
235
static void cortex_a7_initfn(Object *obj)
236
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo cortexr5_cp_reginfo[] = {
237
.access = PL1_RW, .type = ARM_CP_CONST },
238
{ .name = "DCACHE_INVAL", .cp = 15, .opc1 = 0, .crn = 15, .crm = 5,
239
.opc2 = 0, .access = PL1_W, .type = ARM_CP_NOP },
240
- REGINFO_SENTINEL
241
};
242
243
static void cortex_r5_initfn(Object *obj)
244
diff --git a/target/arm/helper.c b/target/arm/helper.c
245
index XXXXXXX..XXXXXXX 100644
246
--- a/target/arm/helper.c
247
+++ b/target/arm/helper.c
248
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo cp_reginfo[] = {
249
.secure = ARM_CP_SECSTATE_S,
250
.fieldoffset = offsetof(CPUARMState, cp15.contextidr_s),
251
.resetvalue = 0, .writefn = contextidr_write, .raw_writefn = raw_write, },
252
- REGINFO_SENTINEL
253
};
254
255
static const ARMCPRegInfo not_v8_cp_reginfo[] = {
256
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo not_v8_cp_reginfo[] = {
257
{ .name = "CACHEMAINT", .cp = 15, .crn = 7, .crm = CP_ANY,
258
.opc1 = 0, .opc2 = CP_ANY, .access = PL1_W,
259
.type = ARM_CP_NOP | ARM_CP_OVERRIDE },
260
- REGINFO_SENTINEL
261
};
262
263
static const ARMCPRegInfo not_v6_cp_reginfo[] = {
264
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo not_v6_cp_reginfo[] = {
265
*/
266
{ .name = "WFI_v5", .cp = 15, .crn = 7, .crm = 8, .opc1 = 0, .opc2 = 2,
267
.access = PL1_W, .type = ARM_CP_WFI },
268
- REGINFO_SENTINEL
269
};
270
271
static const ARMCPRegInfo not_v7_cp_reginfo[] = {
272
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo not_v7_cp_reginfo[] = {
273
.opc1 = 0, .opc2 = 0, .access = PL1_RW, .type = ARM_CP_NOP },
274
{ .name = "NMRR", .cp = 15, .crn = 10, .crm = 2,
275
.opc1 = 0, .opc2 = 1, .access = PL1_RW, .type = ARM_CP_NOP },
276
- REGINFO_SENTINEL
277
};
278
279
static void cpacr_write(CPUARMState *env, const ARMCPRegInfo *ri,
280
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo v6_cp_reginfo[] = {
281
.crn = 1, .crm = 0, .opc1 = 0, .opc2 = 2, .accessfn = cpacr_access,
282
.access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.cpacr_el1),
283
.resetfn = cpacr_reset, .writefn = cpacr_write, .readfn = cpacr_read },
284
- REGINFO_SENTINEL
285
};
286
287
typedef struct pm_event {
288
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
289
{ .name = "TLBIMVAA", .cp = 15, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 3,
290
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
291
.writefn = tlbimvaa_write },
292
- REGINFO_SENTINEL
293
};
294
295
static const ARMCPRegInfo v7mp_cp_reginfo[] = {
296
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo v7mp_cp_reginfo[] = {
297
{ .name = "TLBIMVAAIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 3,
298
.type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb,
299
.writefn = tlbimvaa_is_write },
300
- REGINFO_SENTINEL
301
};
302
303
static const ARMCPRegInfo pmovsset_cp_reginfo[] = {
304
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo pmovsset_cp_reginfo[] = {
305
.fieldoffset = offsetof(CPUARMState, cp15.c9_pmovsr),
306
.writefn = pmovsset_write,
307
.raw_writefn = raw_write },
308
- REGINFO_SENTINEL
309
};
310
311
static void teecr_write(CPUARMState *env, const ARMCPRegInfo *ri,
312
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo t2ee_cp_reginfo[] = {
313
{ .name = "TEEHBR", .cp = 14, .crn = 1, .crm = 0, .opc1 = 6, .opc2 = 0,
314
.access = PL0_RW, .fieldoffset = offsetof(CPUARMState, teehbr),
315
.accessfn = teehbr_access, .resetvalue = 0 },
316
- REGINFO_SENTINEL
317
};
318
319
static const ARMCPRegInfo v6k_cp_reginfo[] = {
320
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo v6k_cp_reginfo[] = {
321
.bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.tpidrprw_s),
322
offsetoflow32(CPUARMState, cp15.tpidrprw_ns) },
323
.resetvalue = 0 },
324
- REGINFO_SENTINEL
325
};
326
327
#ifndef CONFIG_USER_ONLY
328
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
329
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_SEC].cval),
330
.writefn = gt_sec_cval_write, .raw_writefn = raw_write,
331
},
332
- REGINFO_SENTINEL
333
};
334
335
static CPAccessResult e2h_access(CPUARMState *env, const ARMCPRegInfo *ri,
336
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
337
.access = PL0_R, .type = ARM_CP_NO_RAW | ARM_CP_IO,
338
.readfn = gt_virt_cnt_read,
339
},
340
- REGINFO_SENTINEL
341
};
342
343
#endif
344
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo vapa_cp_reginfo[] = {
345
.access = PL1_W, .accessfn = ats_access,
346
.writefn = ats_write, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC },
347
#endif
348
- REGINFO_SENTINEL
349
};
350
351
/* Return basic MPU access permission bits. */
352
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo pmsav7_cp_reginfo[] = {
353
.fieldoffset = offsetof(CPUARMState, pmsav7.rnr[M_REG_NS]),
354
.writefn = pmsav7_rgnr_write,
355
.resetfn = arm_cp_reset_ignore },
356
- REGINFO_SENTINEL
357
};
358
359
static const ARMCPRegInfo pmsav5_cp_reginfo[] = {
360
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo pmsav5_cp_reginfo[] = {
361
{ .name = "946_PRBS7", .cp = 15, .crn = 6, .crm = 7, .opc1 = 0,
362
.opc2 = CP_ANY, .access = PL1_RW, .resetvalue = 0,
363
.fieldoffset = offsetof(CPUARMState, cp15.c6_region[7]) },
364
- REGINFO_SENTINEL
365
};
366
367
static void vmsa_ttbcr_raw_write(CPUARMState *env, const ARMCPRegInfo *ri,
368
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo vmsa_pmsa_cp_reginfo[] = {
369
.access = PL1_RW, .accessfn = access_tvm_trvm,
370
.fieldoffset = offsetof(CPUARMState, cp15.far_el[1]),
371
.resetvalue = 0, },
372
- REGINFO_SENTINEL
373
};
374
375
static const ARMCPRegInfo vmsa_cp_reginfo[] = {
376
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = {
377
/* No offsetoflow32 -- pass the entire TCR to writefn/raw_writefn. */
378
.bank_fieldoffsets = { offsetof(CPUARMState, cp15.tcr_el[3]),
379
offsetof(CPUARMState, cp15.tcr_el[1])} },
380
- REGINFO_SENTINEL
381
};
382
383
/* Note that unlike TTBCR, writing to TTBCR2 does not require flushing
384
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo omap_cp_reginfo[] = {
385
{ .name = "C9", .cp = 15, .crn = 9,
386
.crm = CP_ANY, .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_RW,
387
.type = ARM_CP_CONST | ARM_CP_OVERRIDE, .resetvalue = 0 },
388
- REGINFO_SENTINEL
389
};
390
391
static void xscale_cpar_write(CPUARMState *env, const ARMCPRegInfo *ri,
392
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo xscale_cp_reginfo[] = {
393
{ .name = "XSCALE_UNLOCK_DCACHE",
394
.cp = 15, .opc1 = 0, .crn = 9, .crm = 2, .opc2 = 1,
395
.access = PL1_W, .type = ARM_CP_NOP },
396
- REGINFO_SENTINEL
397
};
398
399
static const ARMCPRegInfo dummy_c15_cp_reginfo[] = {
400
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo dummy_c15_cp_reginfo[] = {
401
.access = PL1_RW,
402
.type = ARM_CP_CONST | ARM_CP_NO_RAW | ARM_CP_OVERRIDE,
403
.resetvalue = 0 },
404
- REGINFO_SENTINEL
405
};
406
407
static const ARMCPRegInfo cache_dirty_status_cp_reginfo[] = {
408
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo cache_dirty_status_cp_reginfo[] = {
409
{ .name = "CDSR", .cp = 15, .crn = 7, .crm = 10, .opc1 = 0, .opc2 = 6,
410
.access = PL1_R, .type = ARM_CP_CONST | ARM_CP_NO_RAW,
411
.resetvalue = 0 },
412
- REGINFO_SENTINEL
413
};
414
415
static const ARMCPRegInfo cache_block_ops_cp_reginfo[] = {
416
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo cache_block_ops_cp_reginfo[] = {
417
.access = PL0_W, .type = ARM_CP_NOP|ARM_CP_64BIT },
418
{ .name = "CIDCR", .cp = 15, .crm = 14, .opc1 = 0,
419
.access = PL1_W, .type = ARM_CP_NOP|ARM_CP_64BIT },
420
- REGINFO_SENTINEL
421
};
422
423
static const ARMCPRegInfo cache_test_clean_cp_reginfo[] = {
424
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo cache_test_clean_cp_reginfo[] = {
425
{ .name = "TCI_DCACHE", .cp = 15, .crn = 7, .crm = 14, .opc1 = 0, .opc2 = 3,
426
.access = PL0_R, .type = ARM_CP_CONST | ARM_CP_NO_RAW,
427
.resetvalue = (1 << 30) },
428
- REGINFO_SENTINEL
429
};
430
431
static const ARMCPRegInfo strongarm_cp_reginfo[] = {
432
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo strongarm_cp_reginfo[] = {
433
.crm = CP_ANY, .opc1 = CP_ANY, .opc2 = CP_ANY,
434
.access = PL1_RW, .resetvalue = 0,
435
.type = ARM_CP_CONST | ARM_CP_OVERRIDE | ARM_CP_NO_RAW },
436
- REGINFO_SENTINEL
437
};
438
439
static uint64_t midr_read(CPUARMState *env, const ARMCPRegInfo *ri)
440
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo lpae_cp_reginfo[] = {
441
.bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr1_s),
442
offsetof(CPUARMState, cp15.ttbr1_ns) },
443
.writefn = vmsa_ttbr_write, },
444
- REGINFO_SENTINEL
445
};
446
447
static uint64_t aa64_fpcr_read(CPUARMState *env, const ARMCPRegInfo *ri)
448
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
449
.access = PL1_RW, .accessfn = access_trap_aa32s_el1,
450
.writefn = sdcr_write,
451
.fieldoffset = offsetoflow32(CPUARMState, cp15.mdcr_el3) },
452
- REGINFO_SENTINEL
453
};
454
455
/* Used to describe the behaviour of EL2 regs when EL2 does not exist. */
456
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo el3_no_el2_cp_reginfo[] = {
457
.type = ARM_CP_CONST,
458
.cp = 15, .opc1 = 4, .crn = 6, .crm = 0, .opc2 = 2,
459
.access = PL2_RW, .resetvalue = 0 },
460
- REGINFO_SENTINEL
461
};
462
463
/* Ditto, but for registers which exist in ARMv8 but not v7 */
464
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo el3_no_el2_v8_cp_reginfo[] = {
465
.cp = 15, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 4,
466
.access = PL2_RW,
467
.type = ARM_CP_CONST, .resetvalue = 0 },
468
- REGINFO_SENTINEL
469
};
470
471
static void do_hcr_write(CPUARMState *env, uint64_t value, uint64_t valid_mask)
472
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
473
.cp = 15, .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 3,
474
.access = PL2_RW,
475
.fieldoffset = offsetof(CPUARMState, cp15.hstr_el2) },
476
- REGINFO_SENTINEL
477
};
478
479
static const ARMCPRegInfo el2_v8_cp_reginfo[] = {
480
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo el2_v8_cp_reginfo[] = {
481
.access = PL2_RW,
482
.fieldoffset = offsetofhigh32(CPUARMState, cp15.hcr_el2),
483
.writefn = hcr_writehigh },
484
- REGINFO_SENTINEL
485
};
486
487
static CPAccessResult sel2_access(CPUARMState *env, const ARMCPRegInfo *ri,
488
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo el2_sec_cp_reginfo[] = {
489
.opc0 = 3, .opc1 = 4, .crn = 2, .crm = 6, .opc2 = 2,
490
.access = PL2_RW, .accessfn = sel2_access,
491
.fieldoffset = offsetof(CPUARMState, cp15.vstcr_el2) },
492
- REGINFO_SENTINEL
493
};
494
495
static CPAccessResult nsacr_access(CPUARMState *env, const ARMCPRegInfo *ri,
496
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo el3_cp_reginfo[] = {
497
.opc0 = 1, .opc1 = 6, .crn = 8, .crm = 7, .opc2 = 5,
498
.access = PL3_W, .type = ARM_CP_NO_RAW,
499
.writefn = tlbi_aa64_vae3_write },
500
- REGINFO_SENTINEL
501
};
502
503
#ifndef CONFIG_USER_ONLY
504
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
505
.cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 0,
506
.access = PL1_RW, .accessfn = access_tda,
507
.type = ARM_CP_NOP },
508
- REGINFO_SENTINEL
509
};
510
511
static const ARMCPRegInfo debug_lpae_cp_reginfo[] = {
512
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo debug_lpae_cp_reginfo[] = {
513
.access = PL0_R, .type = ARM_CP_CONST|ARM_CP_64BIT, .resetvalue = 0 },
514
{ .name = "DBGDSAR", .cp = 14, .crm = 2, .opc1 = 0,
515
.access = PL0_R, .type = ARM_CP_CONST|ARM_CP_64BIT, .resetvalue = 0 },
516
- REGINFO_SENTINEL
517
};
518
519
/* Return the exception level to which exceptions should be taken
520
@@ -XXX,XX +XXX,XX @@ static void define_debug_regs(ARMCPU *cpu)
521
.fieldoffset = offsetof(CPUARMState, cp15.dbgbcr[i]),
522
.writefn = dbgbcr_write, .raw_writefn = raw_write
523
},
524
- REGINFO_SENTINEL
525
};
526
define_arm_cp_regs(cpu, dbgregs);
527
}
528
@@ -XXX,XX +XXX,XX @@ static void define_debug_regs(ARMCPU *cpu)
529
.fieldoffset = offsetof(CPUARMState, cp15.dbgwcr[i]),
530
.writefn = dbgwcr_write, .raw_writefn = raw_write
531
},
532
- REGINFO_SENTINEL
533
};
534
define_arm_cp_regs(cpu, dbgregs);
535
}
536
@@ -XXX,XX +XXX,XX @@ static void define_pmu_regs(ARMCPU *cpu)
537
.type = ARM_CP_IO,
538
.readfn = pmevtyper_readfn, .writefn = pmevtyper_writefn,
539
.raw_writefn = pmevtyper_rawwrite },
540
- REGINFO_SENTINEL
541
};
542
define_arm_cp_regs(cpu, pmev_regs);
543
g_free(pmevcntr_name);
544
@@ -XXX,XX +XXX,XX @@ static void define_pmu_regs(ARMCPU *cpu)
545
.cp = 15, .opc1 = 0, .crn = 9, .crm = 14, .opc2 = 5,
546
.access = PL0_R, .accessfn = pmreg_access, .type = ARM_CP_CONST,
547
.resetvalue = extract64(cpu->pmceid1, 32, 32) },
548
- REGINFO_SENTINEL
549
};
550
define_arm_cp_regs(cpu, v81_pmu_regs);
551
}
552
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo lor_reginfo[] = {
553
.opc0 = 3, .opc1 = 0, .crn = 10, .crm = 4, .opc2 = 7,
554
.access = PL1_R, .accessfn = access_lor_ns,
555
.type = ARM_CP_CONST, .resetvalue = 0 },
556
- REGINFO_SENTINEL
557
};
558
559
#ifdef TARGET_AARCH64
560
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo pauth_reginfo[] = {
561
.opc0 = 3, .opc1 = 0, .crn = 2, .crm = 1, .opc2 = 3,
562
.access = PL1_RW, .accessfn = access_pauth,
563
.fieldoffset = offsetof(CPUARMState, keys.apib.hi) },
564
- REGINFO_SENTINEL
565
};
566
567
static const ARMCPRegInfo tlbirange_reginfo[] = {
568
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo tlbirange_reginfo[] = {
569
.opc0 = 1, .opc1 = 6, .crn = 8, .crm = 6, .opc2 = 5,
570
.access = PL3_W, .type = ARM_CP_NO_RAW,
571
.writefn = tlbi_aa64_rvae3_write },
572
- REGINFO_SENTINEL
573
};
574
575
static const ARMCPRegInfo tlbios_reginfo[] = {
576
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo tlbios_reginfo[] = {
577
.opc0 = 1, .opc1 = 6, .crn = 8, .crm = 1, .opc2 = 5,
578
.access = PL3_W, .type = ARM_CP_NO_RAW,
579
.writefn = tlbi_aa64_vae3is_write },
580
- REGINFO_SENTINEL
581
};
582
583
static uint64_t rndr_readfn(CPUARMState *env, const ARMCPRegInfo *ri)
584
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo rndr_reginfo[] = {
585
.type = ARM_CP_NO_RAW | ARM_CP_SUPPRESS_TB_END | ARM_CP_IO,
586
.opc0 = 3, .opc1 = 3, .crn = 2, .crm = 4, .opc2 = 1,
587
.access = PL0_R, .readfn = rndr_readfn },
588
- REGINFO_SENTINEL
589
};
590
591
#ifndef CONFIG_USER_ONLY
592
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo dcpop_reg[] = {
593
.opc0 = 1, .opc1 = 3, .crn = 7, .crm = 12, .opc2 = 1,
594
.access = PL0_W, .type = ARM_CP_NO_RAW | ARM_CP_SUPPRESS_TB_END,
595
.accessfn = aa64_cacheop_poc_access, .writefn = dccvap_writefn },
596
- REGINFO_SENTINEL
597
};
598
599
static const ARMCPRegInfo dcpodp_reg[] = {
600
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo dcpodp_reg[] = {
601
.opc0 = 1, .opc1 = 3, .crn = 7, .crm = 13, .opc2 = 1,
602
.access = PL0_W, .type = ARM_CP_NO_RAW | ARM_CP_SUPPRESS_TB_END,
603
.accessfn = aa64_cacheop_poc_access, .writefn = dccvap_writefn },
604
- REGINFO_SENTINEL
605
};
606
#endif /*CONFIG_USER_ONLY*/
607
608
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo mte_reginfo[] = {
609
{ .name = "DC_CIGDSW", .state = ARM_CP_STATE_AA64,
610
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 14, .opc2 = 6,
611
.type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_tsw },
612
- REGINFO_SENTINEL
613
};
614
615
static const ARMCPRegInfo mte_tco_ro_reginfo[] = {
616
{ .name = "TCO", .state = ARM_CP_STATE_AA64,
617
.opc0 = 3, .opc1 = 3, .crn = 4, .crm = 2, .opc2 = 7,
618
.type = ARM_CP_CONST, .access = PL0_RW, },
619
- REGINFO_SENTINEL
620
};
621
622
static const ARMCPRegInfo mte_el0_cacheop_reginfo[] = {
623
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo mte_el0_cacheop_reginfo[] = {
624
.accessfn = aa64_zva_access,
625
#endif
626
},
627
- REGINFO_SENTINEL
628
};
629
630
#endif
631
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo predinv_reginfo[] = {
632
{ .name = "CPPRCTX", .state = ARM_CP_STATE_AA32,
633
.cp = 15, .opc1 = 0, .crn = 7, .crm = 3, .opc2 = 7,
634
.type = ARM_CP_NOP, .access = PL0_W, .accessfn = access_predinv },
635
- REGINFO_SENTINEL
636
};
637
638
static uint64_t ccsidr2_read(CPUARMState *env, const ARMCPRegInfo *ri)
639
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo ccsidr2_reginfo[] = {
640
.access = PL1_R,
641
.accessfn = access_aa64_tid2,
642
.readfn = ccsidr2_read, .type = ARM_CP_NO_RAW },
643
- REGINFO_SENTINEL
644
};
645
646
static CPAccessResult access_aa64_tid3(CPUARMState *env, const ARMCPRegInfo *ri,
647
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo jazelle_regs[] = {
648
.cp = 14, .crn = 2, .crm = 0, .opc1 = 7, .opc2 = 0,
649
.accessfn = access_joscr_jmcr,
650
.access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
651
- REGINFO_SENTINEL
652
};
653
654
static const ARMCPRegInfo vhe_reginfo[] = {
655
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo vhe_reginfo[] = {
656
.access = PL2_RW, .accessfn = e2h_access,
657
.writefn = gt_virt_cval_write, .raw_writefn = raw_write },
658
#endif
659
- REGINFO_SENTINEL
660
};
661
662
#ifndef CONFIG_USER_ONLY
663
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo ats1e1_reginfo[] = {
664
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 9, .opc2 = 1,
665
.access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
666
.writefn = ats_write64 },
667
- REGINFO_SENTINEL
668
};
669
670
static const ARMCPRegInfo ats1cp_reginfo[] = {
671
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo ats1cp_reginfo[] = {
672
.cp = 15, .opc1 = 0, .crn = 7, .crm = 9, .opc2 = 1,
673
.access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
674
.writefn = ats_write },
675
- REGINFO_SENTINEL
676
};
677
#endif
678
679
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo actlr2_hactlr2_reginfo[] = {
680
.cp = 15, .opc1 = 4, .crn = 1, .crm = 0, .opc2 = 3,
681
.access = PL2_RW, .type = ARM_CP_CONST,
682
.resetvalue = 0 },
683
- REGINFO_SENTINEL
684
};
685
686
void register_cp_regs_for_features(ARMCPU *cpu)
687
@@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu)
688
.access = PL1_R, .type = ARM_CP_CONST,
689
.accessfn = access_aa32_tid3,
690
.resetvalue = cpu->isar.id_isar6 },
691
- REGINFO_SENTINEL
692
};
693
define_arm_cp_regs(cpu, v6_idregs);
694
define_arm_cp_regs(cpu, v6_cp_reginfo);
695
@@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu)
696
.opc0 = 3, .opc1 = 3, .crn = 9, .crm = 12, .opc2 = 7,
697
.access = PL0_R, .accessfn = pmreg_access, .type = ARM_CP_CONST,
698
.resetvalue = cpu->pmceid1 },
699
- REGINFO_SENTINEL
700
};
701
#ifdef CONFIG_USER_ONLY
702
ARMCPRegUserSpaceInfo v8_user_idregs[] = {
703
@@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu)
704
.exported_bits = 0x000000f0ffffffff },
705
{ .name = "ID_AA64ISAR*_EL1_RESERVED",
706
.is_glob = true },
707
- REGUSERINFO_SENTINEL
708
};
709
modify_arm_cp_regs(v8_idregs, v8_user_idregs);
710
#endif
711
@@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu)
712
.access = PL2_RW,
713
.resetvalue = vmpidr_def,
714
.fieldoffset = offsetof(CPUARMState, cp15.vmpidr_el2) },
715
- REGINFO_SENTINEL
716
};
717
define_arm_cp_regs(cpu, vpidr_regs);
718
define_arm_cp_regs(cpu, el2_cp_reginfo);
719
@@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu)
720
.access = PL2_RW, .accessfn = access_el3_aa32ns,
721
.type = ARM_CP_NO_RAW,
722
.writefn = arm_cp_write_ignore, .readfn = mpidr_read },
723
- REGINFO_SENTINEL
724
};
725
define_arm_cp_regs(cpu, vpidr_regs);
726
define_arm_cp_regs(cpu, el3_no_el2_cp_reginfo);
727
@@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu)
728
.raw_writefn = raw_write, .writefn = sctlr_write,
729
.fieldoffset = offsetof(CPUARMState, cp15.sctlr_el[3]),
730
.resetvalue = cpu->reset_sctlr },
731
- REGINFO_SENTINEL
732
};
733
734
define_arm_cp_regs(cpu, el3_regs);
735
@@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu)
736
{ .name = "DUMMY",
737
.cp = 15, .crn = 0, .crm = 7, .opc1 = 0, .opc2 = CP_ANY,
738
.access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 },
739
- REGINFO_SENTINEL
740
};
741
ARMCPRegInfo id_v8_midr_cp_reginfo[] = {
742
{ .name = "MIDR_EL1", .state = ARM_CP_STATE_BOTH,
743
@@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu)
744
.access = PL1_R,
745
.accessfn = access_aa64_tid1,
746
.type = ARM_CP_CONST, .resetvalue = cpu->revidr },
747
- REGINFO_SENTINEL
748
};
749
ARMCPRegInfo id_cp_reginfo[] = {
750
/* These are common to v8 and pre-v8 */
751
@@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu)
752
.access = PL1_R,
753
.accessfn = access_aa32_tid1,
754
.type = ARM_CP_CONST, .resetvalue = 0 },
755
- REGINFO_SENTINEL
756
};
757
/* TLBTR is specific to VMSA */
758
ARMCPRegInfo id_tlbtr_reginfo = {
759
@@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu)
760
{ .name = "MIDR_EL1",
761
.exported_bits = 0x00000000ffffffff },
762
{ .name = "REVIDR_EL1" },
763
- REGUSERINFO_SENTINEL
764
};
765
modify_arm_cp_regs(id_v8_midr_cp_reginfo, id_v8_user_midr_cp_reginfo);
766
#endif
767
if (arm_feature(env, ARM_FEATURE_OMAPCP) ||
768
arm_feature(env, ARM_FEATURE_STRONGARM)) {
769
- ARMCPRegInfo *r;
770
+ size_t i;
771
/* Register the blanket "writes ignored" value first to cover the
772
* whole space. Then update the specific ID registers to allow write
773
* access, so that they ignore writes rather than causing them to
774
* UNDEF.
775
*/
776
define_one_arm_cp_reg(cpu, &crn0_wi_reginfo);
777
- for (r = id_pre_v8_midr_cp_reginfo;
778
- r->type != ARM_CP_SENTINEL; r++) {
779
- r->access = PL1_RW;
780
+ for (i = 0; i < ARRAY_SIZE(id_pre_v8_midr_cp_reginfo); ++i) {
781
+ id_pre_v8_midr_cp_reginfo[i].access = PL1_RW;
782
}
783
- for (r = id_cp_reginfo; r->type != ARM_CP_SENTINEL; r++) {
784
- r->access = PL1_RW;
785
+ for (i = 0; i < ARRAY_SIZE(id_cp_reginfo); ++i) {
786
+ id_cp_reginfo[i].access = PL1_RW;
787
}
788
id_mpuir_reginfo.access = PL1_RW;
789
id_tlbtr_reginfo.access = PL1_RW;
790
@@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu)
791
{ .name = "MPIDR_EL1", .state = ARM_CP_STATE_BOTH,
792
.opc0 = 3, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 5,
793
.access = PL1_R, .readfn = mpidr_read, .type = ARM_CP_NO_RAW },
794
- REGINFO_SENTINEL
795
};
796
#ifdef CONFIG_USER_ONLY
797
ARMCPRegUserSpaceInfo mpidr_user_cp_reginfo[] = {
798
{ .name = "MPIDR_EL1",
799
.fixed_bits = 0x0000000080000000 },
800
- REGUSERINFO_SENTINEL
801
};
802
modify_arm_cp_regs(mpidr_cp_reginfo, mpidr_user_cp_reginfo);
803
#endif
804
@@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu)
805
.opc0 = 3, .opc1 = 6, .crn = 1, .crm = 0, .opc2 = 1,
806
.access = PL3_RW, .type = ARM_CP_CONST,
807
.resetvalue = 0 },
808
- REGINFO_SENTINEL
809
};
810
define_arm_cp_regs(cpu, auxcr_reginfo);
811
if (cpu_isar_feature(aa32_ac2, cpu)) {
812
@@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu)
813
.type = ARM_CP_CONST,
814
.opc0 = 3, .opc1 = 1, .crn = 15, .crm = 3, .opc2 = 0,
815
.access = PL1_R, .resetvalue = cpu->reset_cbar },
816
- REGINFO_SENTINEL
817
};
818
/* We don't implement a r/w 64 bit CBAR currently */
819
assert(arm_feature(env, ARM_FEATURE_CBAR_RO));
820
@@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu)
821
.bank_fieldoffsets = { offsetof(CPUARMState, cp15.vbar_s),
822
offsetof(CPUARMState, cp15.vbar_ns) },
823
.resetvalue = 0 },
824
- REGINFO_SENTINEL
825
};
826
define_arm_cp_regs(cpu, vbar_cp_reginfo);
827
}
828
@@ -XXX,XX +XXX,XX @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
829
r->writefn);
830
}
831
}
832
- /* Bad type field probably means missing sentinel at end of reg list */
833
- assert(cptype_valid(r->type));
834
+
835
for (crm = crmmin; crm <= crmmax; crm++) {
836
for (opc1 = opc1min; opc1 <= opc1max; opc1++) {
837
for (opc2 = opc2min; opc2 <= opc2max; opc2++) {
838
@@ -XXX,XX +XXX,XX @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
839
}
113
}
840
}
114
}
841
115
842
-void define_arm_cp_regs_with_opaque(ARMCPU *cpu,
116
+static const Property fsl_imx8mp_properties[] = {
843
- const ARMCPRegInfo *regs, void *opaque)
117
+ DEFINE_PROP_UINT32("fec1-phy-num", FslImx8mpState, phy_num, 0),
844
+/* Define a whole list of registers */
118
+ DEFINE_PROP_BOOL("fec1-phy-connected", FslImx8mpState, phy_connected, true),
845
+void define_arm_cp_regs_with_opaque_len(ARMCPU *cpu, const ARMCPRegInfo *regs,
119
+};
846
+ void *opaque, size_t len)
120
+
121
static void fsl_imx8mp_class_init(ObjectClass *oc, void *data)
847
{
122
{
848
- /* Define a whole list of registers */
123
DeviceClass *dc = DEVICE_CLASS(oc);
849
- const ARMCPRegInfo *r;
124
850
- for (r = regs; r->type != ARM_CP_SENTINEL; r++) {
125
+ device_class_set_props(dc, fsl_imx8mp_properties);
851
- define_one_arm_cp_reg_with_opaque(cpu, r, opaque);
126
dc->realize = fsl_imx8mp_realize;
852
+ size_t i;
127
853
+ for (i = 0; i < len; ++i) {
128
dc->desc = "i.MX 8M Plus SoC";
854
+ define_one_arm_cp_reg_with_opaque(cpu, regs + i, opaque);
129
diff --git a/hw/arm/imx8mp-evk.c b/hw/arm/imx8mp-evk.c
855
}
130
index XXXXXXX..XXXXXXX 100644
856
}
131
--- a/hw/arm/imx8mp-evk.c
857
132
+++ b/hw/arm/imx8mp-evk.c
858
@@ -XXX,XX +XXX,XX @@ void define_arm_cp_regs_with_opaque(ARMCPU *cpu,
133
@@ -XXX,XX +XXX,XX @@ static void imx8mp_evk_init(MachineState *machine)
859
* user-space cannot alter any values and dynamic values pertaining to
134
860
* execution state are hidden from user space view anyway.
135
s = FSL_IMX8MP(object_new(TYPE_FSL_IMX8MP));
861
*/
136
object_property_add_child(OBJECT(machine), "soc", OBJECT(s));
862
-void modify_arm_cp_regs(ARMCPRegInfo *regs, const ARMCPRegUserSpaceInfo *mods)
137
+ object_property_set_uint(OBJECT(s), "fec1-phy-num", 1, &error_fatal);
863
+void modify_arm_cp_regs_with_len(ARMCPRegInfo *regs, size_t regs_len,
138
qdev_realize(DEVICE(s), NULL, &error_fatal);
864
+ const ARMCPRegUserSpaceInfo *mods,
139
865
+ size_t mods_len)
140
memory_region_add_subregion(get_system_memory(), FSL_IMX8MP_RAM_START,
866
{
141
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
867
- const ARMCPRegUserSpaceInfo *m;
142
index XXXXXXX..XXXXXXX 100644
868
- ARMCPRegInfo *r;
143
--- a/hw/arm/Kconfig
869
-
144
+++ b/hw/arm/Kconfig
870
- for (m = mods; m->name; m++) {
145
@@ -XXX,XX +XXX,XX @@ config FSL_IMX8MP
871
+ for (size_t mi = 0; mi < mods_len; ++mi) {
146
select FSL_IMX8MP_ANALOG
872
+ const ARMCPRegUserSpaceInfo *m = mods + mi;
147
select FSL_IMX8MP_CCM
873
GPatternSpec *pat = NULL;
148
select IMX
874
+
149
+ select IMX_FEC
875
if (m->is_glob) {
150
select IMX_I2C
876
pat = g_pattern_spec_new(m->name);
151
select OR_IRQ
877
}
152
select PCI_EXPRESS_DESIGNWARE
878
- for (r = regs; r->type != ARM_CP_SENTINEL; r++) {
879
+ for (size_t ri = 0; ri < regs_len; ++ri) {
880
+ ARMCPRegInfo *r = regs + ri;
881
+
882
if (pat && g_pattern_match_string(pat, r->name)) {
883
r->type = ARM_CP_CONST;
884
r->access = PL0U_R;
885
--
153
--
886
2.25.1
154
2.43.0
887
888
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Bernhard Beschow <shentey@gmail.com>
2
2
3
Computing isbanked only once makes the code
3
Split the USB MMIO regions to better keep track of the implemented vs.
4
a bit easier to read.
4
unimplemented regions.
5
5
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Message-id: 20220501055028.646596-17-richard.henderson@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]
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
11
---
11
target/arm/helper.c | 6 ++++--
12
docs/system/arm/imx8mp-evk.rst | 1 +
12
1 file changed, 4 insertions(+), 2 deletions(-)
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(-)
13
17
14
diff --git a/target/arm/helper.c b/target/arm/helper.c
18
diff --git a/docs/system/arm/imx8mp-evk.rst b/docs/system/arm/imx8mp-evk.rst
15
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
16
--- a/target/arm/helper.c
20
--- a/docs/system/arm/imx8mp-evk.rst
17
+++ b/target/arm/helper.c
21
+++ b/docs/system/arm/imx8mp-evk.rst
18
@@ -XXX,XX +XXX,XX @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
22
@@ -XXX,XX +XXX,XX @@ The ``imx8mp-evk`` machine implements the following devices:
19
bool is64 = r->type & ARM_CP_64BIT;
23
* 3 USDHC Storage Controllers
20
bool ns = secstate & ARM_CP_SECSTATE_NS;
24
* 1 Designware PCI Express Controller
21
int cp = r->cp;
25
* 1 Ethernet Controller
22
+ bool isbanked;
26
+ * 2 Designware USB 3 Controllers
23
size_t name_len;
27
* 5 GPIO Controllers
24
28
* 6 I2C Controllers
25
switch (state) {
29
* 3 SPI Controllers
26
@@ -XXX,XX +XXX,XX @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
30
diff --git a/include/hw/arm/fsl-imx8mp.h b/include/hw/arm/fsl-imx8mp.h
27
r2->opaque = opaque;
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);
28
}
104
}
29
105
30
- if (r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1]) {
106
+ for (i = 0; i < FSL_IMX8MP_NUM_USBS; i++) {
31
+ isbanked = r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1];
107
+ g_autofree char *name = g_strdup_printf("usb%d", i);
32
+ if (isbanked) {
108
+ object_initialize_child(obj, name, &s->usb[i], TYPE_USB_DWC3);
33
/* Register is banked (using both entries in array).
109
+ }
34
* Overwriting fieldoffset as the array is only used to define
110
+
35
* banked registers but later only fieldoffset is used.
111
for (i = 0; i < FSL_IMX8MP_NUM_ECSPIS; i++) {
36
@@ -XXX,XX +XXX,XX @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
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));
37
}
116
}
38
117
39
if (state == ARM_CP_STATE_AA32) {
118
+ /* USBs */
40
- if (r->bank_fieldoffsets[0] && r->bank_fieldoffsets[1]) {
119
+ for (i = 0; i < FSL_IMX8MP_NUM_USBS; i++) {
41
+ if (isbanked) {
120
+ struct {
42
/* If the register is banked then we don't need to migrate or
121
+ hwaddr addr;
43
* reset the 32-bit instance in certain cases:
122
+ unsigned int irq;
44
*
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
45
--
162
--
46
2.25.1
163
2.43.0
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Bernhard Beschow <shentey@gmail.com>
2
3
Create a typedef as well, and use it in ARMCPRegInfo.
4
This won't be perfect for debugging, but it'll nicely
5
display the most common cases.
6
2
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
3
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
4
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
9
Message-id: 20220501055028.646596-8-richard.henderson@linaro.org
5
Message-id: 20250223114708.1780-18-shentey@gmail.com
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
7
---
12
target/arm/cpregs.h | 44 +++++++++++++++++++++++---------------------
8
include/hw/arm/fsl-imx8mp.h | 1 +
13
target/arm/helper.c | 2 +-
9
hw/arm/fsl-imx8mp.c | 11 +++++++++++
14
2 files changed, 24 insertions(+), 22 deletions(-)
10
2 files changed, 12 insertions(+)
15
11
16
diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h
12
diff --git a/include/hw/arm/fsl-imx8mp.h b/include/hw/arm/fsl-imx8mp.h
17
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
18
--- a/target/arm/cpregs.h
14
--- a/include/hw/arm/fsl-imx8mp.h
19
+++ b/target/arm/cpregs.h
15
+++ b/include/hw/arm/fsl-imx8mp.h
20
@@ -XXX,XX +XXX,XX @@ enum {
16
@@ -XXX,XX +XXX,XX @@ struct FslImx8mpState {
21
* described with these bits, then use a laxer set of restrictions, and
17
DesignwarePCIEHost pcie;
22
* do the more restrictive/complex check inside a helper function.
18
FslImx8mPciePhyState pcie_phy;
23
*/
19
OrIRQState gpt5_gpt6_irq;
24
-#define PL3_R 0x80
20
+ MemoryRegion ocram;
25
-#define PL3_W 0x40
21
26
-#define PL2_R (0x20 | PL3_R)
22
uint32_t phy_num;
27
-#define PL2_W (0x10 | PL3_W)
23
bool phy_connected;
28
-#define PL1_R (0x08 | PL2_R)
24
diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c
29
-#define PL1_W (0x04 | PL2_W)
30
-#define PL0_R (0x02 | PL1_R)
31
-#define PL0_W (0x01 | PL1_W)
32
+typedef enum {
33
+ PL3_R = 0x80,
34
+ PL3_W = 0x40,
35
+ PL2_R = 0x20 | PL3_R,
36
+ PL2_W = 0x10 | PL3_W,
37
+ PL1_R = 0x08 | PL2_R,
38
+ PL1_W = 0x04 | PL2_W,
39
+ PL0_R = 0x02 | PL1_R,
40
+ PL0_W = 0x01 | PL1_W,
41
42
-/*
43
- * For user-mode some registers are accessible to EL0 via a kernel
44
- * trap-and-emulate ABI. In this case we define the read permissions
45
- * as actually being PL0_R. However some bits of any given register
46
- * may still be masked.
47
- */
48
+ /*
49
+ * For user-mode some registers are accessible to EL0 via a kernel
50
+ * trap-and-emulate ABI. In this case we define the read permissions
51
+ * as actually being PL0_R. However some bits of any given register
52
+ * may still be masked.
53
+ */
54
#ifdef CONFIG_USER_ONLY
55
-#define PL0U_R PL0_R
56
+ PL0U_R = PL0_R,
57
#else
58
-#define PL0U_R PL1_R
59
+ PL0U_R = PL1_R,
60
#endif
61
62
-#define PL3_RW (PL3_R | PL3_W)
63
-#define PL2_RW (PL2_R | PL2_W)
64
-#define PL1_RW (PL1_R | PL1_W)
65
-#define PL0_RW (PL0_R | PL0_W)
66
+ PL3_RW = PL3_R | PL3_W,
67
+ PL2_RW = PL2_R | PL2_W,
68
+ PL1_RW = PL1_R | PL1_W,
69
+ PL0_RW = PL0_R | PL0_W,
70
+} CPAccessRights;
71
72
typedef enum CPAccessResult {
73
/* Access is permitted */
74
@@ -XXX,XX +XXX,XX @@ struct ARMCPRegInfo {
75
/* Register type: ARM_CP_* bits/values */
76
int type;
77
/* Access rights: PL*_[RW] */
78
- int access;
79
+ CPAccessRights access;
80
/* Security state: ARM_CP_SECSTATE_* bits/values */
81
int secure;
82
/*
83
diff --git a/target/arm/helper.c b/target/arm/helper.c
84
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
85
--- a/target/arm/helper.c
26
--- a/hw/arm/fsl-imx8mp.c
86
+++ b/target/arm/helper.c
27
+++ b/hw/arm/fsl-imx8mp.c
87
@@ -XXX,XX +XXX,XX @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
28
@@ -XXX,XX +XXX,XX @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
88
* to encompass the generic architectural permission check.
29
sysbus_mmio_map(SYS_BUS_DEVICE(&s->pcie_phy), 0,
89
*/
30
fsl_imx8mp_memmap[FSL_IMX8MP_PCIE_PHY1].addr);
90
if (r->state != ARM_CP_STATE_AA32) {
31
91
- int mask = 0;
32
+ /* On-Chip RAM */
92
+ CPAccessRights mask;
33
+ if (!memory_region_init_ram(&s->ocram, NULL, "imx8mp.ocram",
93
switch (r->opc1) {
34
+ fsl_imx8mp_memmap[FSL_IMX8MP_OCRAM].size,
94
case 0:
35
+ errp)) {
95
/* min_EL EL1, but some accessible to EL0 via kernel ABI */
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:
96
--
53
--
97
2.25.1
54
2.43.0
diff view generated by jsdifflib