1
Another go at the v8.5-MemTag linux-user support, plus a
1
First arm pullreq of the cycle; this is mostly my softfloat NaN
2
couple more npcm7xx devices.
2
handling series. (Lots more in my to-review queue, but I don't
3
like pullreqs growing too close to a hundred patches at a time :-))
3
4
5
thanks
4
-- PMM
6
-- PMM
5
7
6
The following changes since commit 8ba4bca570ace1e60614a0808631a517cf5df67a:
8
The following changes since commit 97f2796a3736ed37a1b85dc1c76a6c45b829dd17:
7
9
8
Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging (2021-02-15 17:13:57 +0000)
10
Open 10.0 development tree (2024-12-10 17:41:17 +0000)
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-20210216
14
https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20241211
13
15
14
for you to fetch changes up to 64fd5bddf3b71d1b92b55382ab39768bd87ecfbd:
16
for you to fetch changes up to 1abe28d519239eea5cf9620bb13149423e5665f8:
15
17
16
tests/qtests: Add npcm7xx emc model test (2021-02-16 14:27:05 +0000)
18
MAINTAINERS: Add correct email address for Vikram Garhwal (2024-12-11 15:31:09 +0000)
17
19
18
----------------------------------------------------------------
20
----------------------------------------------------------------
19
target-arm queue:
21
target-arm queue:
20
* Support ARMv8.5-MemTag for linux-user
22
* hw/net/lan9118: Extract PHY model, reuse with imx_fec, fix bugs
21
* ncpm7xx: Support SMBus, EMC ethernet devices
23
* fpu: Make muladd NaN handling runtime-selected, not compile-time
22
* MAINTAINERS: add section for Clock framework
24
* fpu: Make default NaN pattern runtime-selected, not compile-time
25
* fpu: Minor NaN-related cleanups
26
* MAINTAINERS: email address updates
23
27
24
----------------------------------------------------------------
28
----------------------------------------------------------------
25
Doug Evans (3):
29
Bernhard Beschow (5):
26
hw/net: Add npcm7xx emc model
30
hw/net/lan9118: Extract lan9118_phy
27
hw/arm: Add npcm7xx emc model
31
hw/net/lan9118_phy: Reuse in imx_fec and consolidate implementations
28
tests/qtests: Add npcm7xx emc model test
32
hw/net/lan9118_phy: Fix off-by-one error in MII_ANLPAR register
33
hw/net/lan9118_phy: Reuse MII constants
34
hw/net/lan9118_phy: Add missing 100 mbps full duplex advertisement
29
35
30
Hao Wu (5):
36
Leif Lindholm (1):
31
hw/i2c: Implement NPCM7XX SMBus Module Single Mode
37
MAINTAINERS: update email address for Leif Lindholm
32
hw/arm: Add I2C sensors for NPCM750 eval board
33
hw/arm: Add I2C sensors and EEPROM for GSJ machine
34
hw/i2c: Add a QTest for NPCM7XX SMBus Device
35
hw/i2c: Implement NPCM7XX SMBus Module FIFO Mode
36
38
37
Luc Michel (1):
39
Peter Maydell (54):
38
MAINTAINERS: add myself maintainer for the clock framework
40
fpu: handle raising Invalid for infzero in pick_nan_muladd
41
fpu: Check for default_nan_mode before calling pickNaNMulAdd
42
softfloat: Allow runtime choice of inf * 0 + NaN result
43
tests/fp: Explicitly set inf-zero-nan rule
44
target/arm: Set FloatInfZeroNaNRule explicitly
45
target/s390: Set FloatInfZeroNaNRule explicitly
46
target/ppc: Set FloatInfZeroNaNRule explicitly
47
target/mips: Set FloatInfZeroNaNRule explicitly
48
target/sparc: Set FloatInfZeroNaNRule explicitly
49
target/xtensa: Set FloatInfZeroNaNRule explicitly
50
target/x86: Set FloatInfZeroNaNRule explicitly
51
target/loongarch: Set FloatInfZeroNaNRule explicitly
52
target/hppa: Set FloatInfZeroNaNRule explicitly
53
softfloat: Pass have_snan to pickNaNMulAdd
54
softfloat: Allow runtime choice of NaN propagation for muladd
55
tests/fp: Explicitly set 3-NaN propagation rule
56
target/arm: Set Float3NaNPropRule explicitly
57
target/loongarch: Set Float3NaNPropRule explicitly
58
target/ppc: Set Float3NaNPropRule explicitly
59
target/s390x: Set Float3NaNPropRule explicitly
60
target/sparc: Set Float3NaNPropRule explicitly
61
target/mips: Set Float3NaNPropRule explicitly
62
target/xtensa: Set Float3NaNPropRule explicitly
63
target/i386: Set Float3NaNPropRule explicitly
64
target/hppa: Set Float3NaNPropRule explicitly
65
fpu: Remove use_first_nan field from float_status
66
target/m68k: Don't pass NULL float_status to floatx80_default_nan()
67
softfloat: Create floatx80 default NaN from parts64_default_nan
68
target/loongarch: Use normal float_status in fclass_s and fclass_d helpers
69
target/m68k: In frem helper, initialize local float_status from env->fp_status
70
target/m68k: Init local float_status from env fp_status in gdb get/set reg
71
target/sparc: Initialize local scratch float_status from env->fp_status
72
target/ppc: Use env->fp_status in helper_compute_fprf functions
73
fpu: Allow runtime choice of default NaN value
74
tests/fp: Set default NaN pattern explicitly
75
target/microblaze: Set default NaN pattern explicitly
76
target/i386: Set default NaN pattern explicitly
77
target/hppa: Set default NaN pattern explicitly
78
target/alpha: Set default NaN pattern explicitly
79
target/arm: Set default NaN pattern explicitly
80
target/loongarch: Set default NaN pattern explicitly
81
target/m68k: Set default NaN pattern explicitly
82
target/mips: Set default NaN pattern explicitly
83
target/openrisc: Set default NaN pattern explicitly
84
target/ppc: Set default NaN pattern explicitly
85
target/sh4: Set default NaN pattern explicitly
86
target/rx: Set default NaN pattern explicitly
87
target/s390x: Set default NaN pattern explicitly
88
target/sparc: Set default NaN pattern explicitly
89
target/xtensa: Set default NaN pattern explicitly
90
target/hexagon: Set default NaN pattern explicitly
91
target/riscv: Set default NaN pattern explicitly
92
target/tricore: Set default NaN pattern explicitly
93
fpu: Remove default handling for dnan_pattern
39
94
40
Richard Henderson (31):
95
Richard Henderson (11):
41
tcg: Introduce target-specific page data for user-only
96
target/arm: Copy entire float_status in is_ebf
42
linux-user: Introduce PAGE_ANON
97
softfloat: Inline pickNaNMulAdd
43
exec: Use uintptr_t for guest_base
98
softfloat: Use goto for default nan case in pick_nan_muladd
44
exec: Use uintptr_t in cpu_ldst.h
99
softfloat: Remove which from parts_pick_nan_muladd
45
exec: Improve types for guest_addr_valid
100
softfloat: Pad array size in pick_nan_muladd
46
linux-user: Check for overflow in access_ok
101
softfloat: Move propagateFloatx80NaN to softfloat.c
47
linux-user: Tidy VERIFY_READ/VERIFY_WRITE
102
softfloat: Use parts_pick_nan in propagateFloatx80NaN
48
bsd-user: Tidy VERIFY_READ/VERIFY_WRITE
103
softfloat: Inline pickNaN
49
linux-user: Do not use guest_addr_valid for h2g_valid
104
softfloat: Share code between parts_pick_nan cases
50
linux-user: Fix guest_addr_valid vs reserved_va
105
softfloat: Sink frac_cmp in parts_pick_nan until needed
51
exec: Introduce cpu_untagged_addr
106
softfloat: Replace WHICH with RET in parts_pick_nan
52
exec: Use cpu_untagged_addr in g2h; split out g2h_untagged
53
linux-user: Explicitly untag memory management syscalls
54
linux-user: Use guest_range_valid in access_ok
55
exec: Rename guest_{addr,range}_valid to *_untagged
56
linux-user: Use cpu_untagged_addr in access_ok; split out *_untagged
57
linux-user: Move lock_user et al out of line
58
linux-user: Fix types in uaccess.c
59
linux-user: Handle tags in lock_user/unlock_user
60
linux-user/aarch64: Implement PR_TAGGED_ADDR_ENABLE
61
target/arm: Improve gen_top_byte_ignore
62
target/arm: Use the proper TBI settings for linux-user
63
linux-user/aarch64: Implement PR_MTE_TCF and PR_MTE_TAG
64
linux-user/aarch64: Implement PROT_MTE
65
target/arm: Split out syndrome.h from internals.h
66
linux-user/aarch64: Pass syndrome to EXC_*_ABORT
67
linux-user/aarch64: Signal SEGV_MTESERR for sync tag check fault
68
linux-user/aarch64: Signal SEGV_MTEAERR for async tag check error
69
target/arm: Add allocation tag storage for user mode
70
target/arm: Enable MTE for user-only
71
tests/tcg/aarch64: Add mte smoke tests
72
107
73
docs/system/arm/nuvoton.rst | 5 +-
108
Vikram Garhwal (1):
74
bsd-user/qemu.h | 17 +-
109
MAINTAINERS: Add correct email address for Vikram Garhwal
75
include/exec/cpu-all.h | 47 +-
76
include/exec/cpu_ldst.h | 39 +-
77
include/exec/exec-all.h | 2 +-
78
include/hw/arm/npcm7xx.h | 4 +
79
include/hw/i2c/npcm7xx_smbus.h | 113 ++++
80
include/hw/net/npcm7xx_emc.h | 286 +++++++++
81
linux-user/aarch64/target_signal.h | 3 +
82
linux-user/aarch64/target_syscall.h | 13 +
83
linux-user/qemu.h | 76 +--
84
linux-user/syscall_defs.h | 1 +
85
target/arm/cpu-param.h | 3 +
86
target/arm/cpu.h | 32 +
87
target/arm/internals.h | 249 +-------
88
target/arm/syndrome.h | 273 +++++++++
89
tests/tcg/aarch64/mte.h | 60 ++
90
accel/tcg/translate-all.c | 32 +-
91
accel/tcg/user-exec.c | 51 +-
92
bsd-user/elfload.c | 2 +-
93
bsd-user/main.c | 8 +-
94
bsd-user/mmap.c | 23 +-
95
hw/arm/npcm7xx.c | 118 +++-
96
hw/arm/npcm7xx_boards.c | 46 ++
97
hw/i2c/npcm7xx_smbus.c | 1099 +++++++++++++++++++++++++++++++++++
98
hw/net/npcm7xx_emc.c | 857 +++++++++++++++++++++++++++
99
linux-user/aarch64/cpu_loop.c | 38 +-
100
linux-user/elfload.c | 18 +-
101
linux-user/flatload.c | 2 +-
102
linux-user/hppa/cpu_loop.c | 39 +-
103
linux-user/i386/cpu_loop.c | 6 +-
104
linux-user/i386/signal.c | 5 +-
105
linux-user/main.c | 4 +-
106
linux-user/mmap.c | 88 +--
107
linux-user/ppc/signal.c | 4 +-
108
linux-user/syscall.c | 165 ++++--
109
linux-user/uaccess.c | 82 ++-
110
target/arm/cpu.c | 25 +-
111
target/arm/helper-a64.c | 4 +-
112
target/arm/mte_helper.c | 39 +-
113
target/arm/tlb_helper.c | 15 +-
114
target/arm/translate-a64.c | 25 +-
115
target/hppa/op_helper.c | 2 +-
116
target/i386/tcg/mem_helper.c | 2 +-
117
target/s390x/mem_helper.c | 4 +-
118
tests/qtest/npcm7xx_emc-test.c | 862 +++++++++++++++++++++++++++
119
tests/qtest/npcm7xx_smbus-test.c | 495 ++++++++++++++++
120
tests/tcg/aarch64/mte-1.c | 28 +
121
tests/tcg/aarch64/mte-2.c | 45 ++
122
tests/tcg/aarch64/mte-3.c | 51 ++
123
tests/tcg/aarch64/mte-4.c | 45 ++
124
tests/tcg/aarch64/pauth-2.c | 1 -
125
MAINTAINERS | 11 +
126
hw/arm/Kconfig | 1 +
127
hw/i2c/meson.build | 1 +
128
hw/i2c/trace-events | 12 +
129
hw/net/meson.build | 1 +
130
hw/net/trace-events | 17 +
131
tests/qtest/meson.build | 2 +
132
tests/tcg/aarch64/Makefile.target | 6 +
133
tests/tcg/configure.sh | 4 +
134
61 files changed, 5052 insertions(+), 556 deletions(-)
135
create mode 100644 include/hw/i2c/npcm7xx_smbus.h
136
create mode 100644 include/hw/net/npcm7xx_emc.h
137
create mode 100644 target/arm/syndrome.h
138
create mode 100644 tests/tcg/aarch64/mte.h
139
create mode 100644 hw/i2c/npcm7xx_smbus.c
140
create mode 100644 hw/net/npcm7xx_emc.c
141
create mode 100644 tests/qtest/npcm7xx_emc-test.c
142
create mode 100644 tests/qtest/npcm7xx_smbus-test.c
143
create mode 100644 tests/tcg/aarch64/mte-1.c
144
create mode 100644 tests/tcg/aarch64/mte-2.c
145
create mode 100644 tests/tcg/aarch64/mte-3.c
146
create mode 100644 tests/tcg/aarch64/mte-4.c
147
110
111
MAINTAINERS | 4 +-
112
include/fpu/softfloat-helpers.h | 38 +++-
113
include/fpu/softfloat-types.h | 89 +++++++-
114
include/hw/net/imx_fec.h | 9 +-
115
include/hw/net/lan9118_phy.h | 37 ++++
116
include/hw/net/mii.h | 6 +
117
target/mips/fpu_helper.h | 20 ++
118
target/sparc/helper.h | 4 +-
119
fpu/softfloat.c | 19 ++
120
hw/net/imx_fec.c | 146 ++------------
121
hw/net/lan9118.c | 137 ++-----------
122
hw/net/lan9118_phy.c | 222 ++++++++++++++++++++
123
linux-user/arm/nwfpe/fpa11.c | 5 +
124
target/alpha/cpu.c | 2 +
125
target/arm/cpu.c | 10 +
126
target/arm/tcg/vec_helper.c | 20 +-
127
target/hexagon/cpu.c | 2 +
128
target/hppa/fpu_helper.c | 12 ++
129
target/i386/tcg/fpu_helper.c | 12 ++
130
target/loongarch/tcg/fpu_helper.c | 14 +-
131
target/m68k/cpu.c | 14 +-
132
target/m68k/fpu_helper.c | 6 +-
133
target/m68k/helper.c | 6 +-
134
target/microblaze/cpu.c | 2 +
135
target/mips/msa.c | 10 +
136
target/openrisc/cpu.c | 2 +
137
target/ppc/cpu_init.c | 19 ++
138
target/ppc/fpu_helper.c | 3 +-
139
target/riscv/cpu.c | 2 +
140
target/rx/cpu.c | 2 +
141
target/s390x/cpu.c | 5 +
142
target/sh4/cpu.c | 2 +
143
target/sparc/cpu.c | 6 +
144
target/sparc/fop_helper.c | 8 +-
145
target/sparc/translate.c | 4 +-
146
target/tricore/helper.c | 2 +
147
target/xtensa/cpu.c | 4 +
148
target/xtensa/fpu_helper.c | 3 +-
149
tests/fp/fp-bench.c | 7 +
150
tests/fp/fp-test-log2.c | 1 +
151
tests/fp/fp-test.c | 7 +
152
fpu/softfloat-parts.c.inc | 152 +++++++++++---
153
fpu/softfloat-specialize.c.inc | 412 ++------------------------------------
154
.mailmap | 5 +-
155
hw/net/Kconfig | 5 +
156
hw/net/meson.build | 1 +
157
hw/net/trace-events | 10 +-
158
47 files changed, 778 insertions(+), 730 deletions(-)
159
create mode 100644 include/hw/net/lan9118_phy.h
160
create mode 100644 hw/net/lan9118_phy.c
diff view generated by jsdifflib
1
From: Doug Evans <dje@google.com>
1
From: Bernhard Beschow <shentey@gmail.com>
2
2
3
This is a 10/100 ethernet device that has several features.
3
A very similar implementation of the same device exists in imx_fec. Prepare for
4
Only the ones needed by the Linux driver have been implemented.
4
a common implementation by extracting a device model into its own files.
5
See npcm7xx_emc.c for a list of unimplemented features.
6
5
7
Reviewed-by: Hao Wu <wuhaotsh@google.com>
6
Some migration state has been moved into the new device model which breaks
8
Reviewed-by: Avi Fishman <avi.fishman@nuvoton.com>
7
migration compatibility for the following machines:
8
* smdkc210
9
* realview-*
10
* vexpress-*
11
* kzm
12
* mps2-*
13
14
While breaking migration ABI, fix the size of the MII registers to be 16 bit,
15
as defined by IEEE 802.3u.
16
17
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
18
Tested-by: Guenter Roeck <linux@roeck-us.net>
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
19
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Doug Evans <dje@google.com>
20
Message-id: 20241102125724.532843-2-shentey@gmail.com
11
Message-id: 20210213002520.1374134-2-dje@google.com
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
21
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
---
22
---
14
include/hw/net/npcm7xx_emc.h | 286 ++++++++++++
23
include/hw/net/lan9118_phy.h | 37 ++++++++
15
hw/net/npcm7xx_emc.c | 857 +++++++++++++++++++++++++++++++++++
24
hw/net/lan9118.c | 137 +++++-----------------------
25
hw/net/lan9118_phy.c | 169 +++++++++++++++++++++++++++++++++++
26
hw/net/Kconfig | 4 +
16
hw/net/meson.build | 1 +
27
hw/net/meson.build | 1 +
17
hw/net/trace-events | 17 +
28
5 files changed, 233 insertions(+), 115 deletions(-)
18
4 files changed, 1161 insertions(+)
29
create mode 100644 include/hw/net/lan9118_phy.h
19
create mode 100644 include/hw/net/npcm7xx_emc.h
30
create mode 100644 hw/net/lan9118_phy.c
20
create mode 100644 hw/net/npcm7xx_emc.c
21
31
22
diff --git a/include/hw/net/npcm7xx_emc.h b/include/hw/net/npcm7xx_emc.h
32
diff --git a/include/hw/net/lan9118_phy.h b/include/hw/net/lan9118_phy.h
23
new file mode 100644
33
new file mode 100644
24
index XXXXXXX..XXXXXXX
34
index XXXXXXX..XXXXXXX
25
--- /dev/null
35
--- /dev/null
26
+++ b/include/hw/net/npcm7xx_emc.h
36
+++ b/include/hw/net/lan9118_phy.h
27
@@ -XXX,XX +XXX,XX @@
37
@@ -XXX,XX +XXX,XX @@
28
+/*
38
+/*
29
+ * Nuvoton NPCM7xx EMC Module
39
+ * SMSC LAN9118 PHY emulation
30
+ *
40
+ *
31
+ * Copyright 2020 Google LLC
41
+ * Copyright (c) 2009 CodeSourcery, LLC.
42
+ * Written by Paul Brook
32
+ *
43
+ *
33
+ * This program is free software; you can redistribute it and/or modify it
44
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
34
+ * under the terms of the GNU General Public License as published by the
45
+ * See the COPYING file in the top-level directory.
35
+ * Free Software Foundation; either version 2 of the License, or
36
+ * (at your option) any later version.
37
+ *
38
+ * This program is distributed in the hope that it will be useful, but WITHOUT
39
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
40
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
41
+ * for more details.
42
+ */
46
+ */
43
+
47
+
44
+#ifndef NPCM7XX_EMC_H
48
+#ifndef HW_NET_LAN9118_PHY_H
45
+#define NPCM7XX_EMC_H
49
+#define HW_NET_LAN9118_PHY_H
46
+
50
+
47
+#include "hw/irq.h"
51
+#include "qom/object.h"
48
+#include "hw/sysbus.h"
52
+#include "hw/sysbus.h"
49
+#include "net/net.h"
53
+
50
+
54
+#define TYPE_LAN9118_PHY "lan9118-phy"
51
+/* 32-bit register indices. */
55
+OBJECT_DECLARE_SIMPLE_TYPE(Lan9118PhyState, LAN9118_PHY)
52
+enum NPCM7xxPWMRegister {
56
+
53
+ /* Control registers. */
57
+typedef struct Lan9118PhyState {
54
+ REG_CAMCMR,
58
+ SysBusDevice parent_obj;
55
+ REG_CAMEN,
59
+
56
+
60
+ uint16_t status;
57
+ /* There are 16 CAMn[ML] registers. */
61
+ uint16_t control;
58
+ REG_CAMM_BASE,
62
+ uint16_t advertise;
59
+ REG_CAML_BASE,
63
+ uint16_t ints;
60
+ REG_CAMML_LAST = 0x21,
64
+ uint16_t int_mask;
61
+
65
+ qemu_irq irq;
62
+ REG_TXDLSA = 0x22,
66
+ bool link_down;
63
+ REG_RXDLSA,
67
+} Lan9118PhyState;
64
+ REG_MCMDR,
68
+
65
+ REG_MIID,
69
+void lan9118_phy_update_link(Lan9118PhyState *s, bool link_down);
66
+ REG_MIIDA,
70
+void lan9118_phy_reset(Lan9118PhyState *s);
67
+ REG_FFTCR,
71
+uint16_t lan9118_phy_read(Lan9118PhyState *s, int reg);
68
+ REG_TSDR,
72
+void lan9118_phy_write(Lan9118PhyState *s, int reg, uint16_t val);
69
+ REG_RSDR,
73
+
70
+ REG_DMARFC,
74
+#endif
71
+ REG_MIEN,
75
diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c
72
+
76
index XXXXXXX..XXXXXXX 100644
73
+ /* Status registers. */
77
--- a/hw/net/lan9118.c
74
+ REG_MISTA,
78
+++ b/hw/net/lan9118.c
75
+ REG_MGSTA,
79
@@ -XXX,XX +XXX,XX @@
76
+ REG_MPCNT,
80
#include "net/net.h"
77
+ REG_MRPC,
81
#include "net/eth.h"
78
+ REG_MRPCC,
82
#include "hw/irq.h"
79
+ REG_MREPC,
83
+#include "hw/net/lan9118_phy.h"
80
+ REG_DMARFS,
84
#include "hw/net/lan9118.h"
81
+ REG_CTXDSA,
85
#include "hw/ptimer.h"
82
+ REG_CTXBSA,
86
#include "hw/qdev-properties.h"
83
+ REG_CRXDSA,
87
@@ -XXX,XX +XXX,XX @@ do { printf("lan9118: " fmt , ## __VA_ARGS__); } while (0)
84
+ REG_CRXBSA,
88
#define MAC_CR_RXEN 0x00000004
85
+
89
#define MAC_CR_RESERVED 0x7f404213
86
+ NPCM7XX_NUM_EMC_REGS,
90
87
+};
91
-#define PHY_INT_ENERGYON 0x80
88
+
92
-#define PHY_INT_AUTONEG_COMPLETE 0x40
89
+/* REG_CAMCMR fields */
93
-#define PHY_INT_FAULT 0x20
90
+/* Enable CAM Compare */
94
-#define PHY_INT_DOWN 0x10
91
+#define REG_CAMCMR_ECMP (1 << 4)
95
-#define PHY_INT_AUTONEG_LP 0x08
92
+/* Complement CAM Compare */
96
-#define PHY_INT_PARFAULT 0x04
93
+#define REG_CAMCMR_CCAM (1 << 3)
97
-#define PHY_INT_AUTONEG_PAGE 0x02
94
+/* Accept Broadcast Packet */
98
-
95
+#define REG_CAMCMR_ABP (1 << 2)
99
#define GPT_TIMER_EN 0x20000000
96
+/* Accept Multicast Packet */
100
97
+#define REG_CAMCMR_AMP (1 << 1)
101
/*
98
+/* Accept Unicast Packet */
102
@@ -XXX,XX +XXX,XX @@ struct lan9118_state {
99
+#define REG_CAMCMR_AUP (1 << 0)
103
uint32_t mac_mii_data;
100
+
104
uint32_t mac_flow;
101
+/* REG_MCMDR fields */
105
102
+/* Software Reset */
106
- uint32_t phy_status;
103
+#define REG_MCMDR_SWR (1 << 24)
107
- uint32_t phy_control;
104
+/* Internal Loopback Select */
108
- uint32_t phy_advertise;
105
+#define REG_MCMDR_LBK (1 << 21)
109
- uint32_t phy_int;
106
+/* Operation Mode Select */
110
- uint32_t phy_int_mask;
107
+#define REG_MCMDR_OPMOD (1 << 20)
111
+ Lan9118PhyState mii;
108
+/* Enable MDC Clock Generation */
112
+ IRQState mii_irq;
109
+#define REG_MCMDR_ENMDC (1 << 19)
113
110
+/* Full-Duplex Mode Select */
114
int32_t eeprom_writable;
111
+#define REG_MCMDR_FDUP (1 << 18)
115
uint8_t eeprom[128];
112
+/* Enable SQE Checking */
116
@@ -XXX,XX +XXX,XX @@ struct lan9118_state {
113
+#define REG_MCMDR_ENSEQ (1 << 17)
117
114
+/* Send PAUSE Frame */
118
static const VMStateDescription vmstate_lan9118 = {
115
+#define REG_MCMDR_SDPZ (1 << 16)
119
.name = "lan9118",
116
+/* No Defer */
120
- .version_id = 2,
117
+#define REG_MCMDR_NDEF (1 << 9)
121
- .minimum_version_id = 1,
118
+/* Frame Transmission On */
122
+ .version_id = 3,
119
+#define REG_MCMDR_TXON (1 << 8)
123
+ .minimum_version_id = 3,
120
+/* Strip CRC Checksum */
124
.fields = (const VMStateField[]) {
121
+#define REG_MCMDR_SPCRC (1 << 5)
125
VMSTATE_PTIMER(timer, lan9118_state),
122
+/* Accept CRC Error Packet */
126
VMSTATE_UINT32(irq_cfg, lan9118_state),
123
+#define REG_MCMDR_AEP (1 << 4)
127
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_lan9118 = {
124
+/* Accept Control Packet */
128
VMSTATE_UINT32(mac_mii_acc, lan9118_state),
125
+#define REG_MCMDR_ACP (1 << 3)
129
VMSTATE_UINT32(mac_mii_data, lan9118_state),
126
+/* Accept Runt Packet */
130
VMSTATE_UINT32(mac_flow, lan9118_state),
127
+#define REG_MCMDR_ARP (1 << 2)
131
- VMSTATE_UINT32(phy_status, lan9118_state),
128
+/* Accept Long Packet */
132
- VMSTATE_UINT32(phy_control, lan9118_state),
129
+#define REG_MCMDR_ALP (1 << 1)
133
- VMSTATE_UINT32(phy_advertise, lan9118_state),
130
+/* Frame Reception On */
134
- VMSTATE_UINT32(phy_int, lan9118_state),
131
+#define REG_MCMDR_RXON (1 << 0)
135
- VMSTATE_UINT32(phy_int_mask, lan9118_state),
132
+
136
VMSTATE_INT32(eeprom_writable, lan9118_state),
133
+/* REG_MIEN fields */
137
VMSTATE_UINT8_ARRAY(eeprom, lan9118_state, 128),
134
+/* Enable Transmit Descriptor Unavailable Interrupt */
138
VMSTATE_INT32(tx_fifo_size, lan9118_state),
135
+#define REG_MIEN_ENTDU (1 << 23)
139
@@ -XXX,XX +XXX,XX @@ static void lan9118_reload_eeprom(lan9118_state *s)
136
+/* Enable Transmit Completion Interrupt */
140
lan9118_mac_changed(s);
137
+#define REG_MIEN_ENTXCP (1 << 18)
141
}
138
+/* Enable Transmit Interrupt */
142
139
+#define REG_MIEN_ENTXINTR (1 << 16)
143
-static void phy_update_irq(lan9118_state *s)
140
+/* Enable Receive Descriptor Unavailable Interrupt */
144
+static void lan9118_update_irq(void *opaque, int n, int level)
141
+#define REG_MIEN_ENRDU (1 << 10)
145
{
142
+/* Enable Receive Good Interrupt */
146
- if (s->phy_int & s->phy_int_mask) {
143
+#define REG_MIEN_ENRXGD (1 << 4)
147
+ lan9118_state *s = opaque;
144
+/* Enable Receive Interrupt */
148
+
145
+#define REG_MIEN_ENRXINTR (1 << 0)
149
+ if (level) {
146
+
150
s->int_sts |= PHY_INT;
147
+/* REG_MISTA fields */
151
} else {
148
+/* TODO: Add error fields and support simulated errors? */
152
s->int_sts &= ~PHY_INT;
149
+/* Transmit Bus Error Interrupt */
153
@@ -XXX,XX +XXX,XX @@ static void phy_update_irq(lan9118_state *s)
150
+#define REG_MISTA_TXBERR (1 << 24)
154
lan9118_update(s);
151
+/* Transmit Descriptor Unavailable Interrupt */
155
}
152
+#define REG_MISTA_TDU (1 << 23)
156
153
+/* Transmit Completion Interrupt */
157
-static void phy_update_link(lan9118_state *s)
154
+#define REG_MISTA_TXCP (1 << 18)
158
-{
155
+/* Transmit Interrupt */
159
- /* Autonegotiation status mirrors link status. */
156
+#define REG_MISTA_TXINTR (1 << 16)
160
- if (qemu_get_queue(s->nic)->link_down) {
157
+/* Receive Bus Error Interrupt */
161
- s->phy_status &= ~0x0024;
158
+#define REG_MISTA_RXBERR (1 << 11)
162
- s->phy_int |= PHY_INT_DOWN;
159
+/* Receive Descriptor Unavailable Interrupt */
163
- } else {
160
+#define REG_MISTA_RDU (1 << 10)
164
- s->phy_status |= 0x0024;
161
+/* DMA Early Notification Interrupt */
165
- s->phy_int |= PHY_INT_ENERGYON;
162
+#define REG_MISTA_DENI (1 << 9)
166
- s->phy_int |= PHY_INT_AUTONEG_COMPLETE;
163
+/* Maximum Frame Length Interrupt */
167
- }
164
+#define REG_MISTA_DFOI (1 << 8)
168
- phy_update_irq(s);
165
+/* Receive Good Interrupt */
169
-}
166
+#define REG_MISTA_RXGD (1 << 4)
170
-
167
+/* Packet Too Long Interrupt */
171
static void lan9118_set_link(NetClientState *nc)
168
+#define REG_MISTA_PTLE (1 << 3)
172
{
169
+/* Receive Interrupt */
173
- phy_update_link(qemu_get_nic_opaque(nc));
170
+#define REG_MISTA_RXINTR (1 << 0)
174
-}
171
+
175
-
172
+/* REG_MGSTA fields */
176
-static void phy_reset(lan9118_state *s)
173
+/* Transmission Halted */
177
-{
174
+#define REG_MGSTA_TXHA (1 << 11)
178
- s->phy_status = 0x7809;
175
+/* Receive Halted */
179
- s->phy_control = 0x3000;
176
+#define REG_MGSTA_RXHA (1 << 11)
180
- s->phy_advertise = 0x01e1;
177
+
181
- s->phy_int_mask = 0;
178
+/* REG_DMARFC fields */
182
- s->phy_int = 0;
179
+/* Maximum Receive Frame Length */
183
- phy_update_link(s);
180
+#define REG_DMARFC_RXMS(word) extract32((word), 0, 16)
184
+ lan9118_phy_update_link(&LAN9118(qemu_get_nic_opaque(nc))->mii,
181
+
185
+ nc->link_down);
182
+/* REG MIIDA fields */
186
}
183
+/* Busy Bit */
187
184
+#define REG_MIIDA_BUSY (1 << 17)
188
static void lan9118_reset(DeviceState *d)
185
+
189
@@ -XXX,XX +XXX,XX @@ static void lan9118_reset(DeviceState *d)
186
+/* Transmit and receive descriptors */
190
s->read_word_n = 0;
187
+typedef struct NPCM7xxEMCTxDesc NPCM7xxEMCTxDesc;
191
s->write_word_n = 0;
188
+typedef struct NPCM7xxEMCRxDesc NPCM7xxEMCRxDesc;
192
189
+
193
- phy_reset(s);
190
+struct NPCM7xxEMCTxDesc {
194
-
191
+ uint32_t flags;
195
s->eeprom_writable = 0;
192
+ uint32_t txbsa;
196
lan9118_reload_eeprom(s);
193
+ uint32_t status_and_length;
197
}
194
+ uint32_t ntxdsa;
198
@@ -XXX,XX +XXX,XX @@ static void do_tx_packet(lan9118_state *s)
195
+};
199
uint32_t status;
196
+
200
197
+struct NPCM7xxEMCRxDesc {
201
/* FIXME: Honor TX disable, and allow queueing of packets. */
198
+ uint32_t status_and_length;
202
- if (s->phy_control & 0x4000) {
199
+ uint32_t rxbsa;
203
+ if (s->mii.control & 0x4000) {
200
+ uint32_t reserved;
204
/* This assumes the receive routine doesn't touch the VLANClient. */
201
+ uint32_t nrxdsa;
205
qemu_receive_packet(qemu_get_queue(s->nic), s->txp->data, s->txp->len);
202
+};
206
} else {
203
+
207
@@ -XXX,XX +XXX,XX @@ static void tx_fifo_push(lan9118_state *s, uint32_t val)
204
+/* NPCM7xxEMCTxDesc.flags values */
208
}
205
+/* Owner: 0 = cpu, 1 = emc */
209
}
206
+#define TX_DESC_FLAG_OWNER_MASK (1 << 31)
210
207
+/* Transmit interrupt enable */
211
-static uint32_t do_phy_read(lan9118_state *s, int reg)
208
+#define TX_DESC_FLAG_INTEN (1 << 2)
212
-{
209
+/* CRC append */
213
- uint32_t val;
210
+#define TX_DESC_FLAG_CRCAPP (1 << 1)
214
-
211
+/* Padding enable */
215
- switch (reg) {
212
+#define TX_DESC_FLAG_PADEN (1 << 0)
216
- case 0: /* Basic Control */
213
+
217
- return s->phy_control;
214
+/* NPCM7xxEMCTxDesc.status_and_length values */
218
- case 1: /* Basic Status */
215
+/* Collision count */
219
- return s->phy_status;
216
+#define TX_DESC_STATUS_CCNT_SHIFT 28
220
- case 2: /* ID1 */
217
+#define TX_DESC_STATUS_CCNT_BITSIZE 4
221
- return 0x0007;
218
+/* SQE error */
222
- case 3: /* ID2 */
219
+#define TX_DESC_STATUS_SQE (1 << 26)
223
- return 0xc0d1;
220
+/* Transmission paused */
224
- case 4: /* Auto-neg advertisement */
221
+#define TX_DESC_STATUS_PAU (1 << 25)
225
- return s->phy_advertise;
222
+/* P transmission halted */
226
- case 5: /* Auto-neg Link Partner Ability */
223
+#define TX_DESC_STATUS_TXHA (1 << 24)
227
- return 0x0f71;
224
+/* Late collision */
228
- case 6: /* Auto-neg Expansion */
225
+#define TX_DESC_STATUS_LC (1 << 23)
229
- return 1;
226
+/* Transmission abort */
230
- /* TODO 17, 18, 27, 29, 30, 31 */
227
+#define TX_DESC_STATUS_TXABT (1 << 22)
231
- case 29: /* Interrupt source. */
228
+/* No carrier sense */
232
- val = s->phy_int;
229
+#define TX_DESC_STATUS_NCS (1 << 21)
233
- s->phy_int = 0;
230
+/* Defer exceed */
234
- phy_update_irq(s);
231
+#define TX_DESC_STATUS_EXDEF (1 << 20)
235
- return val;
232
+/* Transmission complete */
236
- case 30: /* Interrupt mask */
233
+#define TX_DESC_STATUS_TXCP (1 << 19)
237
- return s->phy_int_mask;
234
+/* Transmission deferred */
238
- default:
235
+#define TX_DESC_STATUS_DEF (1 << 17)
239
- qemu_log_mask(LOG_GUEST_ERROR,
236
+/* Transmit interrupt */
240
- "do_phy_read: PHY read reg %d\n", reg);
237
+#define TX_DESC_STATUS_TXINTR (1 << 16)
241
- return 0;
238
+
242
- }
239
+#define TX_DESC_PKT_LEN(word) extract32((word), 0, 16)
243
-}
240
+
244
-
241
+/* Transmit buffer start address */
245
-static void do_phy_write(lan9118_state *s, int reg, uint32_t val)
242
+#define TX_DESC_TXBSA(word) ((uint32_t) (word) & ~3u)
246
-{
243
+
247
- switch (reg) {
244
+/* Next transmit descriptor start address */
248
- case 0: /* Basic Control */
245
+#define TX_DESC_NTXDSA(word) ((uint32_t) (word) & ~3u)
249
- if (val & 0x8000) {
246
+
250
- phy_reset(s);
247
+/* NPCM7xxEMCRxDesc.status_and_length values */
251
- break;
248
+/* Owner: 0b00 = cpu, 0b01 = undefined, 0b10 = emc, 0b11 = undefined */
252
- }
249
+#define RX_DESC_STATUS_OWNER_SHIFT 30
253
- s->phy_control = val & 0x7980;
250
+#define RX_DESC_STATUS_OWNER_BITSIZE 2
254
- /* Complete autonegotiation immediately. */
251
+#define RX_DESC_STATUS_OWNER_MASK (3 << RX_DESC_STATUS_OWNER_SHIFT)
255
- if (val & 0x1000) {
252
+/* Runt packet */
256
- s->phy_status |= 0x0020;
253
+#define RX_DESC_STATUS_RP (1 << 22)
257
- }
254
+/* Alignment error */
258
- break;
255
+#define RX_DESC_STATUS_ALIE (1 << 21)
259
- case 4: /* Auto-neg advertisement */
256
+/* Frame reception complete */
260
- s->phy_advertise = (val & 0x2d7f) | 0x80;
257
+#define RX_DESC_STATUS_RXGD (1 << 20)
261
- break;
258
+/* Packet too long */
262
- /* TODO 17, 18, 27, 31 */
259
+#define RX_DESC_STATUS_PTLE (1 << 19)
263
- case 30: /* Interrupt mask */
260
+/* CRC error */
264
- s->phy_int_mask = val & 0xff;
261
+#define RX_DESC_STATUS_CRCE (1 << 17)
265
- phy_update_irq(s);
262
+/* Receive interrupt */
266
- break;
263
+#define RX_DESC_STATUS_RXINTR (1 << 16)
267
- default:
264
+
268
- qemu_log_mask(LOG_GUEST_ERROR,
265
+#define RX_DESC_PKT_LEN(word) extract32((word), 0, 16)
269
- "do_phy_write: PHY write reg %d = 0x%04x\n", reg, val);
266
+
270
- }
267
+/* Receive buffer start address */
271
-}
268
+#define RX_DESC_RXBSA(word) ((uint32_t) (word) & ~3u)
272
-
269
+
273
static void do_mac_write(lan9118_state *s, int reg, uint32_t val)
270
+/* Next receive descriptor start address */
274
{
271
+#define RX_DESC_NRXDSA(word) ((uint32_t) (word) & ~3u)
275
switch (reg) {
272
+
276
@@ -XXX,XX +XXX,XX @@ static void do_mac_write(lan9118_state *s, int reg, uint32_t val)
273
+/* Minimum packet length, when TX_DESC_FLAG_PADEN is set. */
277
if (val & 2) {
274
+#define MIN_PACKET_LENGTH 64
278
DPRINTF("PHY write %d = 0x%04x\n",
275
+
279
(val >> 6) & 0x1f, s->mac_mii_data);
276
+struct NPCM7xxEMCState {
280
- do_phy_write(s, (val >> 6) & 0x1f, s->mac_mii_data);
277
+ /*< private >*/
281
+ lan9118_phy_write(&s->mii, (val >> 6) & 0x1f, s->mac_mii_data);
278
+ SysBusDevice parent;
282
} else {
279
+ /*< public >*/
283
- s->mac_mii_data = do_phy_read(s, (val >> 6) & 0x1f);
280
+
284
+ s->mac_mii_data = lan9118_phy_read(&s->mii, (val >> 6) & 0x1f);
281
+ MemoryRegion iomem;
285
DPRINTF("PHY read %d = 0x%04x\n",
282
+
286
(val >> 6) & 0x1f, s->mac_mii_data);
283
+ qemu_irq tx_irq;
287
}
284
+ qemu_irq rx_irq;
288
@@ -XXX,XX +XXX,XX @@ static void lan9118_writel(void *opaque, hwaddr offset,
285
+
289
break;
286
+ NICState *nic;
290
case CSR_PMT_CTRL:
287
+ NICConf conf;
291
if (val & 0x400) {
288
+
292
- phy_reset(s);
289
+ /* 0 or 1, for log messages */
293
+ lan9118_phy_reset(&s->mii);
290
+ uint8_t emc_num;
294
}
291
+
295
s->pmt_ctrl &= ~0x34e;
292
+ uint32_t regs[NPCM7XX_NUM_EMC_REGS];
296
s->pmt_ctrl |= (val & 0x34e);
293
+
297
@@ -XXX,XX +XXX,XX @@ static void lan9118_realize(DeviceState *dev, Error **errp)
294
+ /*
298
const MemoryRegionOps *mem_ops =
295
+ * tx is active. Set to true by TSDR and then switches off when out of
299
s->mode_16bit ? &lan9118_16bit_mem_ops : &lan9118_mem_ops;
296
+ * descriptors. If the TXON bit in REG_MCMDR is off then this is off.
300
297
+ */
301
+ qemu_init_irq(&s->mii_irq, lan9118_update_irq, s, 0);
298
+ bool tx_active;
302
+ object_initialize_child(OBJECT(s), "mii", &s->mii, TYPE_LAN9118_PHY);
299
+
303
+ if (!sysbus_realize_and_unref(SYS_BUS_DEVICE(&s->mii), errp)) {
300
+ /*
304
+ return;
301
+ * rx is active. Set to true by RSDR and then switches off when out of
305
+ }
302
+ * descriptors. If the RXON bit in REG_MCMDR is off then this is off.
306
+ qdev_connect_gpio_out(DEVICE(&s->mii), 0, &s->mii_irq);
303
+ */
307
+
304
+ bool rx_active;
308
memory_region_init_io(&s->mmio, OBJECT(dev), mem_ops, s,
305
+};
309
"lan9118-mmio", 0x100);
306
+
310
sysbus_init_mmio(sbd, &s->mmio);
307
+typedef struct NPCM7xxEMCState NPCM7xxEMCState;
311
diff --git a/hw/net/lan9118_phy.c b/hw/net/lan9118_phy.c
308
+
309
+#define TYPE_NPCM7XX_EMC "npcm7xx-emc"
310
+#define NPCM7XX_EMC(obj) \
311
+ OBJECT_CHECK(NPCM7xxEMCState, (obj), TYPE_NPCM7XX_EMC)
312
+
313
+#endif /* NPCM7XX_EMC_H */
314
diff --git a/hw/net/npcm7xx_emc.c b/hw/net/npcm7xx_emc.c
315
new file mode 100644
312
new file mode 100644
316
index XXXXXXX..XXXXXXX
313
index XXXXXXX..XXXXXXX
317
--- /dev/null
314
--- /dev/null
318
+++ b/hw/net/npcm7xx_emc.c
315
+++ b/hw/net/lan9118_phy.c
319
@@ -XXX,XX +XXX,XX @@
316
@@ -XXX,XX +XXX,XX @@
320
+/*
317
+/*
321
+ * Nuvoton NPCM7xx EMC Module
318
+ * SMSC LAN9118 PHY emulation
322
+ *
319
+ *
323
+ * Copyright 2020 Google LLC
320
+ * Copyright (c) 2009 CodeSourcery, LLC.
321
+ * Written by Paul Brook
324
+ *
322
+ *
325
+ * This program is free software; you can redistribute it and/or modify it
323
+ * This code is licensed under the GNU GPL v2
326
+ * under the terms of the GNU General Public License as published by the
327
+ * Free Software Foundation; either version 2 of the License, or
328
+ * (at your option) any later version.
329
+ *
324
+ *
330
+ * This program is distributed in the hope that it will be useful, but WITHOUT
325
+ * Contributions after 2012-01-13 are licensed under the terms of the
331
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
326
+ * GNU GPL, version 2 or (at your option) any later version.
332
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
333
+ * for more details.
334
+ *
335
+ * Unsupported/unimplemented features:
336
+ * - MCMDR.FDUP (full duplex) is ignored, half duplex is not supported
337
+ * - Only CAM0 is supported, CAM[1-15] are not
338
+ * - writes to CAMEN.[1-15] are ignored, these bits always read as zeroes
339
+ * - MII is not implemented, MIIDA.BUSY and MIID always return zero
340
+ * - MCMDR.LBK is not implemented
341
+ * - MCMDR.{OPMOD,ENSQE,AEP,ARP} are not supported
342
+ * - H/W FIFOs are not supported, MCMDR.FFTCR is ignored
343
+ * - MGSTA.SQE is not supported
344
+ * - pause and control frames are not implemented
345
+ * - MGSTA.CCNT is not supported
346
+ * - MPCNT, DMARFS are not implemented
347
+ */
327
+ */
348
+
328
+
349
+#include "qemu/osdep.h"
329
+#include "qemu/osdep.h"
350
+
330
+#include "hw/net/lan9118_phy.h"
351
+/* For crc32 */
352
+#include <zlib.h>
353
+
354
+#include "qemu-common.h"
355
+#include "hw/irq.h"
331
+#include "hw/irq.h"
356
+#include "hw/qdev-clock.h"
332
+#include "hw/resettable.h"
357
+#include "hw/qdev-properties.h"
358
+#include "hw/net/npcm7xx_emc.h"
359
+#include "net/eth.h"
360
+#include "migration/vmstate.h"
333
+#include "migration/vmstate.h"
361
+#include "qemu/bitops.h"
362
+#include "qemu/error-report.h"
363
+#include "qemu/log.h"
334
+#include "qemu/log.h"
364
+#include "qemu/module.h"
335
+
365
+#include "qemu/units.h"
336
+#define PHY_INT_ENERGYON (1 << 7)
366
+#include "sysemu/dma.h"
337
+#define PHY_INT_AUTONEG_COMPLETE (1 << 6)
367
+#include "trace.h"
338
+#define PHY_INT_FAULT (1 << 5)
368
+
339
+#define PHY_INT_DOWN (1 << 4)
369
+#define CRC_LENGTH 4
340
+#define PHY_INT_AUTONEG_LP (1 << 3)
370
+
341
+#define PHY_INT_PARFAULT (1 << 2)
371
+/*
342
+#define PHY_INT_AUTONEG_PAGE (1 << 1)
372
+ * The maximum size of a (layer 2) ethernet frame as defined by 802.3.
343
+
373
+ * 1518 = 6(dest macaddr) + 6(src macaddr) + 2(proto) + 4(crc) + 1500(payload)
344
+static void lan9118_phy_update_irq(Lan9118PhyState *s)
374
+ * This does not include an additional 4 for the vlan field (802.1q).
345
+{
375
+ */
346
+ qemu_set_irq(s->irq, !!(s->ints & s->int_mask));
376
+#define MAX_ETH_FRAME_SIZE 1518
347
+}
377
+
348
+
378
+static const char *emc_reg_name(int regno)
349
+uint16_t lan9118_phy_read(Lan9118PhyState *s, int reg)
379
+{
350
+{
380
+#define REG(name) case REG_ ## name: return #name;
351
+ uint16_t val;
381
+ switch (regno) {
352
+
382
+ REG(CAMCMR)
353
+ switch (reg) {
383
+ REG(CAMEN)
354
+ case 0: /* Basic Control */
384
+ REG(TXDLSA)
355
+ return s->control;
385
+ REG(RXDLSA)
356
+ case 1: /* Basic Status */
386
+ REG(MCMDR)
357
+ return s->status;
387
+ REG(MIID)
358
+ case 2: /* ID1 */
388
+ REG(MIIDA)
359
+ return 0x0007;
389
+ REG(FFTCR)
360
+ case 3: /* ID2 */
390
+ REG(TSDR)
361
+ return 0xc0d1;
391
+ REG(RSDR)
362
+ case 4: /* Auto-neg advertisement */
392
+ REG(DMARFC)
363
+ return s->advertise;
393
+ REG(MIEN)
364
+ case 5: /* Auto-neg Link Partner Ability */
394
+ REG(MISTA)
365
+ return 0x0f71;
395
+ REG(MGSTA)
366
+ case 6: /* Auto-neg Expansion */
396
+ REG(MPCNT)
367
+ return 1;
397
+ REG(MRPC)
368
+ /* TODO 17, 18, 27, 29, 30, 31 */
398
+ REG(MRPCC)
369
+ case 29: /* Interrupt source. */
399
+ REG(MREPC)
370
+ val = s->ints;
400
+ REG(DMARFS)
371
+ s->ints = 0;
401
+ REG(CTXDSA)
372
+ lan9118_phy_update_irq(s);
402
+ REG(CTXBSA)
373
+ return val;
403
+ REG(CRXDSA)
374
+ case 30: /* Interrupt mask */
404
+ REG(CRXBSA)
375
+ return s->int_mask;
405
+ case REG_CAMM_BASE + 0: return "CAM0M";
406
+ case REG_CAML_BASE + 0: return "CAM0L";
407
+ case REG_CAMM_BASE + 2 ... REG_CAMML_LAST:
408
+ /* Only CAM0 is supported, fold the others into something simple. */
409
+ if (regno & 1) {
410
+ return "CAM<n>L";
411
+ } else {
412
+ return "CAM<n>M";
413
+ }
414
+ default: return "UNKNOWN";
415
+ }
416
+#undef REG
417
+}
418
+
419
+static void emc_reset(NPCM7xxEMCState *emc)
420
+{
421
+ trace_npcm7xx_emc_reset(emc->emc_num);
422
+
423
+ memset(&emc->regs[0], 0, sizeof(emc->regs));
424
+
425
+ /* These regs have non-zero reset values. */
426
+ emc->regs[REG_TXDLSA] = 0xfffffffc;
427
+ emc->regs[REG_RXDLSA] = 0xfffffffc;
428
+ emc->regs[REG_MIIDA] = 0x00900000;
429
+ emc->regs[REG_FFTCR] = 0x0101;
430
+ emc->regs[REG_DMARFC] = 0x0800;
431
+ emc->regs[REG_MPCNT] = 0x7fff;
432
+
433
+ emc->tx_active = false;
434
+ emc->rx_active = false;
435
+}
436
+
437
+static void npcm7xx_emc_reset(DeviceState *dev)
438
+{
439
+ NPCM7xxEMCState *emc = NPCM7XX_EMC(dev);
440
+ emc_reset(emc);
441
+}
442
+
443
+static void emc_soft_reset(NPCM7xxEMCState *emc)
444
+{
445
+ /*
446
+ * The docs say at least MCMDR.{LBK,OPMOD} bits are not changed during a
447
+ * soft reset, but does not go into further detail. For now, KISS.
448
+ */
449
+ uint32_t mcmdr = emc->regs[REG_MCMDR];
450
+ emc_reset(emc);
451
+ emc->regs[REG_MCMDR] = mcmdr & (REG_MCMDR_LBK | REG_MCMDR_OPMOD);
452
+
453
+ qemu_set_irq(emc->tx_irq, 0);
454
+ qemu_set_irq(emc->rx_irq, 0);
455
+}
456
+
457
+static void emc_set_link(NetClientState *nc)
458
+{
459
+ /* Nothing to do yet. */
460
+}
461
+
462
+/* MISTA.TXINTR is the union of the individual bits with their enables. */
463
+static void emc_update_mista_txintr(NPCM7xxEMCState *emc)
464
+{
465
+ /* Only look at the bits we support. */
466
+ uint32_t mask = (REG_MISTA_TXBERR |
467
+ REG_MISTA_TDU |
468
+ REG_MISTA_TXCP);
469
+ if (emc->regs[REG_MISTA] & emc->regs[REG_MIEN] & mask) {
470
+ emc->regs[REG_MISTA] |= REG_MISTA_TXINTR;
471
+ } else {
472
+ emc->regs[REG_MISTA] &= ~REG_MISTA_TXINTR;
473
+ }
474
+}
475
+
476
+/* MISTA.RXINTR is the union of the individual bits with their enables. */
477
+static void emc_update_mista_rxintr(NPCM7xxEMCState *emc)
478
+{
479
+ /* Only look at the bits we support. */
480
+ uint32_t mask = (REG_MISTA_RXBERR |
481
+ REG_MISTA_RDU |
482
+ REG_MISTA_RXGD);
483
+ if (emc->regs[REG_MISTA] & emc->regs[REG_MIEN] & mask) {
484
+ emc->regs[REG_MISTA] |= REG_MISTA_RXINTR;
485
+ } else {
486
+ emc->regs[REG_MISTA] &= ~REG_MISTA_RXINTR;
487
+ }
488
+}
489
+
490
+/* N.B. emc_update_mista_txintr must have already been called. */
491
+static void emc_update_tx_irq(NPCM7xxEMCState *emc)
492
+{
493
+ int level = !!(emc->regs[REG_MISTA] &
494
+ emc->regs[REG_MIEN] &
495
+ REG_MISTA_TXINTR);
496
+ trace_npcm7xx_emc_update_tx_irq(level);
497
+ qemu_set_irq(emc->tx_irq, level);
498
+}
499
+
500
+/* N.B. emc_update_mista_rxintr must have already been called. */
501
+static void emc_update_rx_irq(NPCM7xxEMCState *emc)
502
+{
503
+ int level = !!(emc->regs[REG_MISTA] &
504
+ emc->regs[REG_MIEN] &
505
+ REG_MISTA_RXINTR);
506
+ trace_npcm7xx_emc_update_rx_irq(level);
507
+ qemu_set_irq(emc->rx_irq, level);
508
+}
509
+
510
+/* Update IRQ states due to changes in MIEN,MISTA. */
511
+static void emc_update_irq_from_reg_change(NPCM7xxEMCState *emc)
512
+{
513
+ emc_update_mista_txintr(emc);
514
+ emc_update_tx_irq(emc);
515
+
516
+ emc_update_mista_rxintr(emc);
517
+ emc_update_rx_irq(emc);
518
+}
519
+
520
+static int emc_read_tx_desc(dma_addr_t addr, NPCM7xxEMCTxDesc *desc)
521
+{
522
+ if (dma_memory_read(&address_space_memory, addr, desc, sizeof(*desc))) {
523
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to read descriptor @ 0x%"
524
+ HWADDR_PRIx "\n", __func__, addr);
525
+ return -1;
526
+ }
527
+ desc->flags = le32_to_cpu(desc->flags);
528
+ desc->txbsa = le32_to_cpu(desc->txbsa);
529
+ desc->status_and_length = le32_to_cpu(desc->status_and_length);
530
+ desc->ntxdsa = le32_to_cpu(desc->ntxdsa);
531
+ return 0;
532
+}
533
+
534
+static int emc_write_tx_desc(const NPCM7xxEMCTxDesc *desc, dma_addr_t addr)
535
+{
536
+ NPCM7xxEMCTxDesc le_desc;
537
+
538
+ le_desc.flags = cpu_to_le32(desc->flags);
539
+ le_desc.txbsa = cpu_to_le32(desc->txbsa);
540
+ le_desc.status_and_length = cpu_to_le32(desc->status_and_length);
541
+ le_desc.ntxdsa = cpu_to_le32(desc->ntxdsa);
542
+ if (dma_memory_write(&address_space_memory, addr, &le_desc,
543
+ sizeof(le_desc))) {
544
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to write descriptor @ 0x%"
545
+ HWADDR_PRIx "\n", __func__, addr);
546
+ return -1;
547
+ }
548
+ return 0;
549
+}
550
+
551
+static int emc_read_rx_desc(dma_addr_t addr, NPCM7xxEMCRxDesc *desc)
552
+{
553
+ if (dma_memory_read(&address_space_memory, addr, desc, sizeof(*desc))) {
554
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to read descriptor @ 0x%"
555
+ HWADDR_PRIx "\n", __func__, addr);
556
+ return -1;
557
+ }
558
+ desc->status_and_length = le32_to_cpu(desc->status_and_length);
559
+ desc->rxbsa = le32_to_cpu(desc->rxbsa);
560
+ desc->reserved = le32_to_cpu(desc->reserved);
561
+ desc->nrxdsa = le32_to_cpu(desc->nrxdsa);
562
+ return 0;
563
+}
564
+
565
+static int emc_write_rx_desc(const NPCM7xxEMCRxDesc *desc, dma_addr_t addr)
566
+{
567
+ NPCM7xxEMCRxDesc le_desc;
568
+
569
+ le_desc.status_and_length = cpu_to_le32(desc->status_and_length);
570
+ le_desc.rxbsa = cpu_to_le32(desc->rxbsa);
571
+ le_desc.reserved = cpu_to_le32(desc->reserved);
572
+ le_desc.nrxdsa = cpu_to_le32(desc->nrxdsa);
573
+ if (dma_memory_write(&address_space_memory, addr, &le_desc,
574
+ sizeof(le_desc))) {
575
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to write descriptor @ 0x%"
576
+ HWADDR_PRIx "\n", __func__, addr);
577
+ return -1;
578
+ }
579
+ return 0;
580
+}
581
+
582
+static void emc_set_mista(NPCM7xxEMCState *emc, uint32_t flags)
583
+{
584
+ trace_npcm7xx_emc_set_mista(flags);
585
+ emc->regs[REG_MISTA] |= flags;
586
+ if (extract32(flags, 16, 16)) {
587
+ emc_update_mista_txintr(emc);
588
+ }
589
+ if (extract32(flags, 0, 16)) {
590
+ emc_update_mista_rxintr(emc);
591
+ }
592
+}
593
+
594
+static void emc_halt_tx(NPCM7xxEMCState *emc, uint32_t mista_flag)
595
+{
596
+ emc->tx_active = false;
597
+ emc_set_mista(emc, mista_flag);
598
+}
599
+
600
+static void emc_halt_rx(NPCM7xxEMCState *emc, uint32_t mista_flag)
601
+{
602
+ emc->rx_active = false;
603
+ emc_set_mista(emc, mista_flag);
604
+}
605
+
606
+static void emc_set_next_tx_descriptor(NPCM7xxEMCState *emc,
607
+ const NPCM7xxEMCTxDesc *tx_desc,
608
+ uint32_t desc_addr)
609
+{
610
+ /* Update the current descriptor, if only to reset the owner flag. */
611
+ if (emc_write_tx_desc(tx_desc, desc_addr)) {
612
+ /*
613
+ * We just read it so this shouldn't generally happen.
614
+ * Error already reported.
615
+ */
616
+ emc_set_mista(emc, REG_MISTA_TXBERR);
617
+ }
618
+ emc->regs[REG_CTXDSA] = TX_DESC_NTXDSA(tx_desc->ntxdsa);
619
+}
620
+
621
+static void emc_set_next_rx_descriptor(NPCM7xxEMCState *emc,
622
+ const NPCM7xxEMCRxDesc *rx_desc,
623
+ uint32_t desc_addr)
624
+{
625
+ /* Update the current descriptor, if only to reset the owner flag. */
626
+ if (emc_write_rx_desc(rx_desc, desc_addr)) {
627
+ /*
628
+ * We just read it so this shouldn't generally happen.
629
+ * Error already reported.
630
+ */
631
+ emc_set_mista(emc, REG_MISTA_RXBERR);
632
+ }
633
+ emc->regs[REG_CRXDSA] = RX_DESC_NRXDSA(rx_desc->nrxdsa);
634
+}
635
+
636
+static void emc_try_send_next_packet(NPCM7xxEMCState *emc)
637
+{
638
+ /* Working buffer for sending out packets. Most packets fit in this. */
639
+#define TX_BUFFER_SIZE 2048
640
+ uint8_t tx_send_buffer[TX_BUFFER_SIZE];
641
+ uint32_t desc_addr = TX_DESC_NTXDSA(emc->regs[REG_CTXDSA]);
642
+ NPCM7xxEMCTxDesc tx_desc;
643
+ uint32_t next_buf_addr, length;
644
+ uint8_t *buf;
645
+ g_autofree uint8_t *malloced_buf = NULL;
646
+
647
+ if (emc_read_tx_desc(desc_addr, &tx_desc)) {
648
+ /* Error reading descriptor, already reported. */
649
+ emc_halt_tx(emc, REG_MISTA_TXBERR);
650
+ emc_update_tx_irq(emc);
651
+ return;
652
+ }
653
+
654
+ /* Nothing we can do if we don't own the descriptor. */
655
+ if (!(tx_desc.flags & TX_DESC_FLAG_OWNER_MASK)) {
656
+ trace_npcm7xx_emc_cpu_owned_desc(desc_addr);
657
+ emc_halt_tx(emc, REG_MISTA_TDU);
658
+ emc_update_tx_irq(emc);
659
+ return;
660
+ }
661
+
662
+ /* Give the descriptor back regardless of what happens. */
663
+ tx_desc.flags &= ~TX_DESC_FLAG_OWNER_MASK;
664
+ tx_desc.status_and_length &= 0xffff;
665
+
666
+ /*
667
+ * Despite the h/w documentation saying the tx buffer is word aligned,
668
+ * the linux driver does not word align the buffer. There is value in not
669
+ * aligning the buffer: See the description of NET_IP_ALIGN in linux
670
+ * kernel sources.
671
+ */
672
+ next_buf_addr = tx_desc.txbsa;
673
+ emc->regs[REG_CTXBSA] = next_buf_addr;
674
+ length = TX_DESC_PKT_LEN(tx_desc.status_and_length);
675
+ buf = &tx_send_buffer[0];
676
+
677
+ if (length > sizeof(tx_send_buffer)) {
678
+ malloced_buf = g_malloc(length);
679
+ buf = malloced_buf;
680
+ }
681
+
682
+ if (dma_memory_read(&address_space_memory, next_buf_addr, buf, length)) {
683
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to read packet @ 0x%x\n",
684
+ __func__, next_buf_addr);
685
+ emc_set_mista(emc, REG_MISTA_TXBERR);
686
+ emc_set_next_tx_descriptor(emc, &tx_desc, desc_addr);
687
+ emc_update_tx_irq(emc);
688
+ trace_npcm7xx_emc_tx_done(emc->regs[REG_CTXDSA]);
689
+ return;
690
+ }
691
+
692
+ if ((tx_desc.flags & TX_DESC_FLAG_PADEN) && (length < MIN_PACKET_LENGTH)) {
693
+ memset(buf + length, 0, MIN_PACKET_LENGTH - length);
694
+ length = MIN_PACKET_LENGTH;
695
+ }
696
+
697
+ /* N.B. emc_receive can get called here. */
698
+ qemu_send_packet(qemu_get_queue(emc->nic), buf, length);
699
+ trace_npcm7xx_emc_sent_packet(length);
700
+
701
+ tx_desc.status_and_length |= TX_DESC_STATUS_TXCP;
702
+ if (tx_desc.flags & TX_DESC_FLAG_INTEN) {
703
+ emc_set_mista(emc, REG_MISTA_TXCP);
704
+ }
705
+ if (emc->regs[REG_MISTA] & emc->regs[REG_MIEN] & REG_MISTA_TXINTR) {
706
+ tx_desc.status_and_length |= TX_DESC_STATUS_TXINTR;
707
+ }
708
+
709
+ emc_set_next_tx_descriptor(emc, &tx_desc, desc_addr);
710
+ emc_update_tx_irq(emc);
711
+ trace_npcm7xx_emc_tx_done(emc->regs[REG_CTXDSA]);
712
+}
713
+
714
+static bool emc_can_receive(NetClientState *nc)
715
+{
716
+ NPCM7xxEMCState *emc = NPCM7XX_EMC(qemu_get_nic_opaque(nc));
717
+
718
+ bool can_receive = emc->rx_active;
719
+ trace_npcm7xx_emc_can_receive(can_receive);
720
+ return can_receive;
721
+}
722
+
723
+/* If result is false then *fail_reason contains the reason. */
724
+static bool emc_receive_filter1(NPCM7xxEMCState *emc, const uint8_t *buf,
725
+ size_t len, const char **fail_reason)
726
+{
727
+ eth_pkt_types_e pkt_type = get_eth_packet_type(PKT_GET_ETH_HDR(buf));
728
+
729
+ switch (pkt_type) {
730
+ case ETH_PKT_BCAST:
731
+ if (emc->regs[REG_CAMCMR] & REG_CAMCMR_CCAM) {
732
+ return true;
733
+ } else {
734
+ *fail_reason = "Broadcast packet disabled";
735
+ return !!(emc->regs[REG_CAMCMR] & REG_CAMCMR_ABP);
736
+ }
737
+ case ETH_PKT_MCAST:
738
+ if (emc->regs[REG_CAMCMR] & REG_CAMCMR_CCAM) {
739
+ return true;
740
+ } else {
741
+ *fail_reason = "Multicast packet disabled";
742
+ return !!(emc->regs[REG_CAMCMR] & REG_CAMCMR_AMP);
743
+ }
744
+ case ETH_PKT_UCAST: {
745
+ bool matches;
746
+ if (emc->regs[REG_CAMCMR] & REG_CAMCMR_AUP) {
747
+ return true;
748
+ }
749
+ matches = ((emc->regs[REG_CAMCMR] & REG_CAMCMR_ECMP) &&
750
+ /* We only support one CAM register, CAM0. */
751
+ (emc->regs[REG_CAMEN] & (1 << 0)) &&
752
+ memcmp(buf, emc->conf.macaddr.a, ETH_ALEN) == 0);
753
+ if (emc->regs[REG_CAMCMR] & REG_CAMCMR_CCAM) {
754
+ *fail_reason = "MACADDR matched, comparison complemented";
755
+ return !matches;
756
+ } else {
757
+ *fail_reason = "MACADDR didn't match";
758
+ return matches;
759
+ }
760
+ }
761
+ default:
376
+ default:
762
+ g_assert_not_reached();
763
+ }
764
+}
765
+
766
+static bool emc_receive_filter(NPCM7xxEMCState *emc, const uint8_t *buf,
767
+ size_t len)
768
+{
769
+ const char *fail_reason = NULL;
770
+ bool ok = emc_receive_filter1(emc, buf, len, &fail_reason);
771
+ if (!ok) {
772
+ trace_npcm7xx_emc_packet_filtered_out(fail_reason);
773
+ }
774
+ return ok;
775
+}
776
+
777
+static ssize_t emc_receive(NetClientState *nc, const uint8_t *buf, size_t len1)
778
+{
779
+ NPCM7xxEMCState *emc = NPCM7XX_EMC(qemu_get_nic_opaque(nc));
780
+ const uint32_t len = len1;
781
+ size_t max_frame_len;
782
+ bool long_frame;
783
+ uint32_t desc_addr;
784
+ NPCM7xxEMCRxDesc rx_desc;
785
+ uint32_t crc;
786
+ uint8_t *crc_ptr;
787
+ uint32_t buf_addr;
788
+
789
+ trace_npcm7xx_emc_receiving_packet(len);
790
+
791
+ if (!emc_can_receive(nc)) {
792
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Unexpected packet\n", __func__);
793
+ return -1;
794
+ }
795
+
796
+ if (len < ETH_HLEN ||
797
+ /* Defensive programming: drop unsupportable large packets. */
798
+ len > 0xffff - CRC_LENGTH) {
799
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Dropped frame of %u bytes\n",
800
+ __func__, len);
801
+ return len;
802
+ }
803
+
804
+ /*
805
+ * DENI is set if EMC received the Length/Type field of the incoming
806
+ * packet, so it will be set regardless of what happens next.
807
+ */
808
+ emc_set_mista(emc, REG_MISTA_DENI);
809
+
810
+ if (!emc_receive_filter(emc, buf, len)) {
811
+ emc_update_rx_irq(emc);
812
+ return len;
813
+ }
814
+
815
+ /* Huge frames (> DMARFC) are dropped. */
816
+ max_frame_len = REG_DMARFC_RXMS(emc->regs[REG_DMARFC]);
817
+ if (len + CRC_LENGTH > max_frame_len) {
818
+ trace_npcm7xx_emc_packet_dropped(len);
819
+ emc_set_mista(emc, REG_MISTA_DFOI);
820
+ emc_update_rx_irq(emc);
821
+ return len;
822
+ }
823
+
824
+ /*
825
+ * Long Frames (> MAX_ETH_FRAME_SIZE) are also dropped, unless MCMDR.ALP
826
+ * is set.
827
+ */
828
+ long_frame = false;
829
+ if (len + CRC_LENGTH > MAX_ETH_FRAME_SIZE) {
830
+ if (emc->regs[REG_MCMDR] & REG_MCMDR_ALP) {
831
+ long_frame = true;
832
+ } else {
833
+ trace_npcm7xx_emc_packet_dropped(len);
834
+ emc_set_mista(emc, REG_MISTA_PTLE);
835
+ emc_update_rx_irq(emc);
836
+ return len;
837
+ }
838
+ }
839
+
840
+ desc_addr = RX_DESC_NRXDSA(emc->regs[REG_CRXDSA]);
841
+ if (emc_read_rx_desc(desc_addr, &rx_desc)) {
842
+ /* Error reading descriptor, already reported. */
843
+ emc_halt_rx(emc, REG_MISTA_RXBERR);
844
+ emc_update_rx_irq(emc);
845
+ return len;
846
+ }
847
+
848
+ /* Nothing we can do if we don't own the descriptor. */
849
+ if (!(rx_desc.status_and_length & RX_DESC_STATUS_OWNER_MASK)) {
850
+ trace_npcm7xx_emc_cpu_owned_desc(desc_addr);
851
+ emc_halt_rx(emc, REG_MISTA_RDU);
852
+ emc_update_rx_irq(emc);
853
+ return len;
854
+ }
855
+
856
+ crc = 0;
857
+ crc_ptr = (uint8_t *) &crc;
858
+ if (!(emc->regs[REG_MCMDR] & REG_MCMDR_SPCRC)) {
859
+ crc = cpu_to_be32(crc32(~0, buf, len));
860
+ }
861
+
862
+ /* Give the descriptor back regardless of what happens. */
863
+ rx_desc.status_and_length &= ~RX_DESC_STATUS_OWNER_MASK;
864
+
865
+ buf_addr = rx_desc.rxbsa;
866
+ emc->regs[REG_CRXBSA] = buf_addr;
867
+ if (dma_memory_write(&address_space_memory, buf_addr, buf, len) ||
868
+ (!(emc->regs[REG_MCMDR] & REG_MCMDR_SPCRC) &&
869
+ dma_memory_write(&address_space_memory, buf_addr + len, crc_ptr,
870
+ 4))) {
871
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bus error writing packet\n",
872
+ __func__);
873
+ emc_set_mista(emc, REG_MISTA_RXBERR);
874
+ emc_set_next_rx_descriptor(emc, &rx_desc, desc_addr);
875
+ emc_update_rx_irq(emc);
876
+ trace_npcm7xx_emc_rx_done(emc->regs[REG_CRXDSA]);
877
+ return len;
878
+ }
879
+
880
+ trace_npcm7xx_emc_received_packet(len);
881
+
882
+ /* Note: We've already verified len+4 <= 0xffff. */
883
+ rx_desc.status_and_length = len;
884
+ if (!(emc->regs[REG_MCMDR] & REG_MCMDR_SPCRC)) {
885
+ rx_desc.status_and_length += 4;
886
+ }
887
+ rx_desc.status_and_length |= RX_DESC_STATUS_RXGD;
888
+ emc_set_mista(emc, REG_MISTA_RXGD);
889
+
890
+ if (emc->regs[REG_MISTA] & emc->regs[REG_MIEN] & REG_MISTA_RXINTR) {
891
+ rx_desc.status_and_length |= RX_DESC_STATUS_RXINTR;
892
+ }
893
+ if (long_frame) {
894
+ rx_desc.status_and_length |= RX_DESC_STATUS_PTLE;
895
+ }
896
+
897
+ emc_set_next_rx_descriptor(emc, &rx_desc, desc_addr);
898
+ emc_update_rx_irq(emc);
899
+ trace_npcm7xx_emc_rx_done(emc->regs[REG_CRXDSA]);
900
+ return len;
901
+}
902
+
903
+static void emc_try_receive_next_packet(NPCM7xxEMCState *emc)
904
+{
905
+ if (emc_can_receive(qemu_get_queue(emc->nic))) {
906
+ qemu_flush_queued_packets(qemu_get_queue(emc->nic));
907
+ }
908
+}
909
+
910
+static uint64_t npcm7xx_emc_read(void *opaque, hwaddr offset, unsigned size)
911
+{
912
+ NPCM7xxEMCState *emc = opaque;
913
+ uint32_t reg = offset / sizeof(uint32_t);
914
+ uint32_t result;
915
+
916
+ if (reg >= NPCM7XX_NUM_EMC_REGS) {
917
+ qemu_log_mask(LOG_GUEST_ERROR,
377
+ qemu_log_mask(LOG_GUEST_ERROR,
918
+ "%s: Invalid offset 0x%04" HWADDR_PRIx "\n",
378
+ "lan9118_phy_read: PHY read reg %d\n", reg);
919
+ __func__, offset);
920
+ return 0;
379
+ return 0;
921
+ }
380
+ }
922
+
381
+}
382
+
383
+void lan9118_phy_write(Lan9118PhyState *s, int reg, uint16_t val)
384
+{
923
+ switch (reg) {
385
+ switch (reg) {
924
+ case REG_MIID:
386
+ case 0: /* Basic Control */
925
+ /*
387
+ if (val & 0x8000) {
926
+ * We don't implement MII. For determinism, always return zero as
388
+ lan9118_phy_reset(s);
927
+ * writes record the last value written for debugging purposes.
928
+ */
929
+ qemu_log_mask(LOG_UNIMP, "%s: Read of MIID, returning 0\n", __func__);
930
+ result = 0;
931
+ break;
932
+ case REG_TSDR:
933
+ case REG_RSDR:
934
+ qemu_log_mask(LOG_GUEST_ERROR,
935
+ "%s: Read of write-only reg, %s/%d\n",
936
+ __func__, emc_reg_name(reg), reg);
937
+ return 0;
938
+ default:
939
+ result = emc->regs[reg];
940
+ break;
941
+ }
942
+
943
+ trace_npcm7xx_emc_reg_read(emc->emc_num, result, emc_reg_name(reg), reg);
944
+ return result;
945
+}
946
+
947
+static void npcm7xx_emc_write(void *opaque, hwaddr offset,
948
+ uint64_t v, unsigned size)
949
+{
950
+ NPCM7xxEMCState *emc = opaque;
951
+ uint32_t reg = offset / sizeof(uint32_t);
952
+ uint32_t value = v;
953
+
954
+ g_assert(size == sizeof(uint32_t));
955
+
956
+ if (reg >= NPCM7XX_NUM_EMC_REGS) {
957
+ qemu_log_mask(LOG_GUEST_ERROR,
958
+ "%s: Invalid offset 0x%04" HWADDR_PRIx "\n",
959
+ __func__, offset);
960
+ return;
961
+ }
962
+
963
+ trace_npcm7xx_emc_reg_write(emc->emc_num, emc_reg_name(reg), reg, value);
964
+
965
+ switch (reg) {
966
+ case REG_CAMCMR:
967
+ emc->regs[reg] = value;
968
+ break;
969
+ case REG_CAMEN:
970
+ /* Only CAM0 is supported, don't pretend otherwise. */
971
+ if (value & ~1) {
972
+ qemu_log_mask(LOG_GUEST_ERROR,
973
+ "%s: Only CAM0 is supported, cannot enable others"
974
+ ": 0x%x\n",
975
+ __func__, value);
976
+ }
977
+ emc->regs[reg] = value & 1;
978
+ break;
979
+ case REG_CAMM_BASE + 0:
980
+ emc->regs[reg] = value;
981
+ emc->conf.macaddr.a[0] = value >> 24;
982
+ emc->conf.macaddr.a[1] = value >> 16;
983
+ emc->conf.macaddr.a[2] = value >> 8;
984
+ emc->conf.macaddr.a[3] = value >> 0;
985
+ break;
986
+ case REG_CAML_BASE + 0:
987
+ emc->regs[reg] = value;
988
+ emc->conf.macaddr.a[4] = value >> 24;
989
+ emc->conf.macaddr.a[5] = value >> 16;
990
+ break;
991
+ case REG_MCMDR: {
992
+ uint32_t prev;
993
+ if (value & REG_MCMDR_SWR) {
994
+ emc_soft_reset(emc);
995
+ /* On h/w the reset happens over multiple cycles. For now KISS. */
996
+ break;
389
+ break;
997
+ }
390
+ }
998
+ prev = emc->regs[reg];
391
+ s->control = val & 0x7980;
999
+ emc->regs[reg] = value;
392
+ /* Complete autonegotiation immediately. */
1000
+ /* Update tx state. */
393
+ if (val & 0x1000) {
1001
+ if (!(prev & REG_MCMDR_TXON) &&
394
+ s->status |= 0x0020;
1002
+ (value & REG_MCMDR_TXON)) {
1003
+ emc->regs[REG_CTXDSA] = emc->regs[REG_TXDLSA];
1004
+ /*
1005
+ * Linux kernel turns TX on with CPU still holding descriptor,
1006
+ * which suggests we should wait for a write to TSDR before trying
1007
+ * to send a packet: so we don't send one here.
1008
+ */
1009
+ } else if ((prev & REG_MCMDR_TXON) &&
1010
+ !(value & REG_MCMDR_TXON)) {
1011
+ emc->regs[REG_MGSTA] |= REG_MGSTA_TXHA;
1012
+ }
1013
+ if (!(value & REG_MCMDR_TXON)) {
1014
+ emc_halt_tx(emc, 0);
1015
+ }
1016
+ /* Update rx state. */
1017
+ if (!(prev & REG_MCMDR_RXON) &&
1018
+ (value & REG_MCMDR_RXON)) {
1019
+ emc->regs[REG_CRXDSA] = emc->regs[REG_RXDLSA];
1020
+ } else if ((prev & REG_MCMDR_RXON) &&
1021
+ !(value & REG_MCMDR_RXON)) {
1022
+ emc->regs[REG_MGSTA] |= REG_MGSTA_RXHA;
1023
+ }
1024
+ if (!(value & REG_MCMDR_RXON)) {
1025
+ emc_halt_rx(emc, 0);
1026
+ }
395
+ }
1027
+ break;
396
+ break;
1028
+ }
397
+ case 4: /* Auto-neg advertisement */
1029
+ case REG_TXDLSA:
398
+ s->advertise = (val & 0x2d7f) | 0x80;
1030
+ case REG_RXDLSA:
1031
+ case REG_DMARFC:
1032
+ case REG_MIID:
1033
+ emc->regs[reg] = value;
1034
+ break;
399
+ break;
1035
+ case REG_MIEN:
400
+ /* TODO 17, 18, 27, 31 */
1036
+ emc->regs[reg] = value;
401
+ case 30: /* Interrupt mask */
1037
+ emc_update_irq_from_reg_change(emc);
402
+ s->int_mask = val & 0xff;
1038
+ break;
403
+ lan9118_phy_update_irq(s);
1039
+ case REG_MISTA:
1040
+ /* Clear the bits that have 1 in "value". */
1041
+ emc->regs[reg] &= ~value;
1042
+ emc_update_irq_from_reg_change(emc);
1043
+ break;
1044
+ case REG_MGSTA:
1045
+ /* Clear the bits that have 1 in "value". */
1046
+ emc->regs[reg] &= ~value;
1047
+ break;
1048
+ case REG_TSDR:
1049
+ if (emc->regs[REG_MCMDR] & REG_MCMDR_TXON) {
1050
+ emc->tx_active = true;
1051
+ /* Keep trying to send packets until we run out. */
1052
+ while (emc->tx_active) {
1053
+ emc_try_send_next_packet(emc);
1054
+ }
1055
+ }
1056
+ break;
1057
+ case REG_RSDR:
1058
+ if (emc->regs[REG_MCMDR] & REG_MCMDR_RXON) {
1059
+ emc->rx_active = true;
1060
+ emc_try_receive_next_packet(emc);
1061
+ }
1062
+ break;
1063
+ case REG_MIIDA:
1064
+ emc->regs[reg] = value & ~REG_MIIDA_BUSY;
1065
+ break;
1066
+ case REG_MRPC:
1067
+ case REG_MRPCC:
1068
+ case REG_MREPC:
1069
+ case REG_CTXDSA:
1070
+ case REG_CTXBSA:
1071
+ case REG_CRXDSA:
1072
+ case REG_CRXBSA:
1073
+ qemu_log_mask(LOG_GUEST_ERROR,
1074
+ "%s: Write to read-only reg %s/%d\n",
1075
+ __func__, emc_reg_name(reg), reg);
1076
+ break;
404
+ break;
1077
+ default:
405
+ default:
1078
+ qemu_log_mask(LOG_UNIMP, "%s: Write to unimplemented reg %s/%d\n",
406
+ qemu_log_mask(LOG_GUEST_ERROR,
1079
+ __func__, emc_reg_name(reg), reg);
407
+ "lan9118_phy_write: PHY write reg %d = 0x%04x\n", reg, val);
1080
+ break;
1081
+ }
408
+ }
1082
+}
409
+}
1083
+
410
+
1084
+static const struct MemoryRegionOps npcm7xx_emc_ops = {
411
+void lan9118_phy_update_link(Lan9118PhyState *s, bool link_down)
1085
+ .read = npcm7xx_emc_read,
412
+{
1086
+ .write = npcm7xx_emc_write,
413
+ s->link_down = link_down;
1087
+ .endianness = DEVICE_LITTLE_ENDIAN,
414
+
1088
+ .valid = {
415
+ /* Autonegotiation status mirrors link status. */
1089
+ .min_access_size = 4,
416
+ if (link_down) {
1090
+ .max_access_size = 4,
417
+ s->status &= ~0x0024;
1091
+ .unaligned = false,
418
+ s->ints |= PHY_INT_DOWN;
1092
+ },
419
+ } else {
420
+ s->status |= 0x0024;
421
+ s->ints |= PHY_INT_ENERGYON;
422
+ s->ints |= PHY_INT_AUTONEG_COMPLETE;
423
+ }
424
+ lan9118_phy_update_irq(s);
425
+}
426
+
427
+void lan9118_phy_reset(Lan9118PhyState *s)
428
+{
429
+ s->control = 0x3000;
430
+ s->status = 0x7809;
431
+ s->advertise = 0x01e1;
432
+ s->int_mask = 0;
433
+ s->ints = 0;
434
+ lan9118_phy_update_link(s, s->link_down);
435
+}
436
+
437
+static void lan9118_phy_reset_hold(Object *obj, ResetType type)
438
+{
439
+ Lan9118PhyState *s = LAN9118_PHY(obj);
440
+
441
+ lan9118_phy_reset(s);
442
+}
443
+
444
+static void lan9118_phy_init(Object *obj)
445
+{
446
+ Lan9118PhyState *s = LAN9118_PHY(obj);
447
+
448
+ qdev_init_gpio_out(DEVICE(s), &s->irq, 1);
449
+}
450
+
451
+static const VMStateDescription vmstate_lan9118_phy = {
452
+ .name = "lan9118-phy",
453
+ .version_id = 1,
454
+ .minimum_version_id = 1,
455
+ .fields = (const VMStateField[]) {
456
+ VMSTATE_UINT16(control, Lan9118PhyState),
457
+ VMSTATE_UINT16(status, Lan9118PhyState),
458
+ VMSTATE_UINT16(advertise, Lan9118PhyState),
459
+ VMSTATE_UINT16(ints, Lan9118PhyState),
460
+ VMSTATE_UINT16(int_mask, Lan9118PhyState),
461
+ VMSTATE_BOOL(link_down, Lan9118PhyState),
462
+ VMSTATE_END_OF_LIST()
463
+ }
1093
+};
464
+};
1094
+
465
+
1095
+static void emc_cleanup(NetClientState *nc)
466
+static void lan9118_phy_class_init(ObjectClass *klass, void *data)
1096
+{
467
+{
1097
+ /* Nothing to do yet. */
468
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
1098
+}
469
+ DeviceClass *dc = DEVICE_CLASS(klass);
1099
+
470
+
1100
+static NetClientInfo net_npcm7xx_emc_info = {
471
+ rc->phases.hold = lan9118_phy_reset_hold;
1101
+ .type = NET_CLIENT_DRIVER_NIC,
472
+ dc->vmsd = &vmstate_lan9118_phy;
1102
+ .size = sizeof(NICState),
473
+}
1103
+ .can_receive = emc_can_receive,
474
+
1104
+ .receive = emc_receive,
475
+static const TypeInfo types[] = {
1105
+ .cleanup = emc_cleanup,
476
+ {
1106
+ .link_status_changed = emc_set_link,
477
+ .name = TYPE_LAN9118_PHY,
478
+ .parent = TYPE_SYS_BUS_DEVICE,
479
+ .instance_size = sizeof(Lan9118PhyState),
480
+ .instance_init = lan9118_phy_init,
481
+ .class_init = lan9118_phy_class_init,
482
+ }
1107
+};
483
+};
1108
+
484
+
1109
+static void npcm7xx_emc_realize(DeviceState *dev, Error **errp)
485
+DEFINE_TYPES(types)
1110
+{
486
diff --git a/hw/net/Kconfig b/hw/net/Kconfig
1111
+ NPCM7xxEMCState *emc = NPCM7XX_EMC(dev);
487
index XXXXXXX..XXXXXXX 100644
1112
+ SysBusDevice *sbd = SYS_BUS_DEVICE(emc);
488
--- a/hw/net/Kconfig
1113
+
489
+++ b/hw/net/Kconfig
1114
+ memory_region_init_io(&emc->iomem, OBJECT(emc), &npcm7xx_emc_ops, emc,
490
@@ -XXX,XX +XXX,XX @@ config VMXNET3_PCI
1115
+ TYPE_NPCM7XX_EMC, 4 * KiB);
491
config SMC91C111
1116
+ sysbus_init_mmio(sbd, &emc->iomem);
492
bool
1117
+ sysbus_init_irq(sbd, &emc->tx_irq);
493
1118
+ sysbus_init_irq(sbd, &emc->rx_irq);
494
+config LAN9118_PHY
1119
+
495
+ bool
1120
+ qemu_macaddr_default_if_unset(&emc->conf.macaddr);
496
+
1121
+ emc->nic = qemu_new_nic(&net_npcm7xx_emc_info, &emc->conf,
497
config LAN9118
1122
+ object_get_typename(OBJECT(dev)), dev->id, emc);
498
bool
1123
+ qemu_format_nic_info_str(qemu_get_queue(emc->nic), emc->conf.macaddr.a);
499
+ select LAN9118_PHY
1124
+}
500
select PTIMER
1125
+
501
1126
+static void npcm7xx_emc_unrealize(DeviceState *dev)
502
config NE2000_ISA
1127
+{
1128
+ NPCM7xxEMCState *emc = NPCM7XX_EMC(dev);
1129
+
1130
+ qemu_del_nic(emc->nic);
1131
+}
1132
+
1133
+static const VMStateDescription vmstate_npcm7xx_emc = {
1134
+ .name = TYPE_NPCM7XX_EMC,
1135
+ .version_id = 0,
1136
+ .minimum_version_id = 0,
1137
+ .fields = (VMStateField[]) {
1138
+ VMSTATE_UINT8(emc_num, NPCM7xxEMCState),
1139
+ VMSTATE_UINT32_ARRAY(regs, NPCM7xxEMCState, NPCM7XX_NUM_EMC_REGS),
1140
+ VMSTATE_BOOL(tx_active, NPCM7xxEMCState),
1141
+ VMSTATE_BOOL(rx_active, NPCM7xxEMCState),
1142
+ VMSTATE_END_OF_LIST(),
1143
+ },
1144
+};
1145
+
1146
+static Property npcm7xx_emc_properties[] = {
1147
+ DEFINE_NIC_PROPERTIES(NPCM7xxEMCState, conf),
1148
+ DEFINE_PROP_END_OF_LIST(),
1149
+};
1150
+
1151
+static void npcm7xx_emc_class_init(ObjectClass *klass, void *data)
1152
+{
1153
+ DeviceClass *dc = DEVICE_CLASS(klass);
1154
+
1155
+ set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
1156
+ dc->desc = "NPCM7xx EMC Controller";
1157
+ dc->realize = npcm7xx_emc_realize;
1158
+ dc->unrealize = npcm7xx_emc_unrealize;
1159
+ dc->reset = npcm7xx_emc_reset;
1160
+ dc->vmsd = &vmstate_npcm7xx_emc;
1161
+ device_class_set_props(dc, npcm7xx_emc_properties);
1162
+}
1163
+
1164
+static const TypeInfo npcm7xx_emc_info = {
1165
+ .name = TYPE_NPCM7XX_EMC,
1166
+ .parent = TYPE_SYS_BUS_DEVICE,
1167
+ .instance_size = sizeof(NPCM7xxEMCState),
1168
+ .class_init = npcm7xx_emc_class_init,
1169
+};
1170
+
1171
+static void npcm7xx_emc_register_type(void)
1172
+{
1173
+ type_register_static(&npcm7xx_emc_info);
1174
+}
1175
+
1176
+type_init(npcm7xx_emc_register_type)
1177
diff --git a/hw/net/meson.build b/hw/net/meson.build
503
diff --git a/hw/net/meson.build b/hw/net/meson.build
1178
index XXXXXXX..XXXXXXX 100644
504
index XXXXXXX..XXXXXXX 100644
1179
--- a/hw/net/meson.build
505
--- a/hw/net/meson.build
1180
+++ b/hw/net/meson.build
506
+++ b/hw/net/meson.build
1181
@@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_I82596_COMMON', if_true: files('i82596.c'))
507
@@ -XXX,XX +XXX,XX @@ system_ss.add(when: 'CONFIG_VMXNET3_PCI', if_true: files('vmxnet3.c'))
1182
softmmu_ss.add(when: 'CONFIG_SUNHME', if_true: files('sunhme.c'))
508
1183
softmmu_ss.add(when: 'CONFIG_FTGMAC100', if_true: files('ftgmac100.c'))
509
system_ss.add(when: 'CONFIG_SMC91C111', if_true: files('smc91c111.c'))
1184
softmmu_ss.add(when: 'CONFIG_SUNGEM', if_true: files('sungem.c'))
510
system_ss.add(when: 'CONFIG_LAN9118', if_true: files('lan9118.c'))
1185
+softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_emc.c'))
511
+system_ss.add(when: 'CONFIG_LAN9118_PHY', if_true: files('lan9118_phy.c'))
1186
512
system_ss.add(when: 'CONFIG_NE2000_ISA', if_true: files('ne2000-isa.c'))
1187
softmmu_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_eth.c'))
513
system_ss.add(when: 'CONFIG_OPENCORES_ETH', if_true: files('opencores_eth.c'))
1188
softmmu_ss.add(when: 'CONFIG_COLDFIRE', if_true: files('mcf_fec.c'))
514
system_ss.add(when: 'CONFIG_XGMAC', if_true: files('xgmac.c'))
1189
diff --git a/hw/net/trace-events b/hw/net/trace-events
1190
index XXXXXXX..XXXXXXX 100644
1191
--- a/hw/net/trace-events
1192
+++ b/hw/net/trace-events
1193
@@ -XXX,XX +XXX,XX @@ imx_fec_receive_last(int last) "rx frame flags 0x%04x"
1194
imx_enet_receive(size_t size) "len %zu"
1195
imx_enet_receive_len(uint64_t addr, int len) "rx_bd 0x%"PRIx64" length %d"
1196
imx_enet_receive_last(int last) "rx frame flags 0x%04x"
1197
+
1198
+# npcm7xx_emc.c
1199
+npcm7xx_emc_reset(int emc_num) "Resetting emc%d"
1200
+npcm7xx_emc_update_tx_irq(int level) "Setting tx irq to %d"
1201
+npcm7xx_emc_update_rx_irq(int level) "Setting rx irq to %d"
1202
+npcm7xx_emc_set_mista(uint32_t flags) "ORing 0x%x into MISTA"
1203
+npcm7xx_emc_cpu_owned_desc(uint32_t addr) "Can't process cpu-owned descriptor @0x%x"
1204
+npcm7xx_emc_sent_packet(uint32_t len) "Sent %u byte packet"
1205
+npcm7xx_emc_tx_done(uint32_t ctxdsa) "TX done, CTXDSA=0x%x"
1206
+npcm7xx_emc_can_receive(int can_receive) "Can receive: %d"
1207
+npcm7xx_emc_packet_filtered_out(const char* fail_reason) "Packet filtered out: %s"
1208
+npcm7xx_emc_packet_dropped(uint32_t len) "%u byte packet dropped"
1209
+npcm7xx_emc_receiving_packet(uint32_t len) "Receiving %u byte packet"
1210
+npcm7xx_emc_received_packet(uint32_t len) "Received %u byte packet"
1211
+npcm7xx_emc_rx_done(uint32_t crxdsa) "RX done, CRXDSA=0x%x"
1212
+npcm7xx_emc_reg_read(int emc_num, uint32_t result, const char *name, int regno) "emc%d: 0x%x = reg[%s/%d]"
1213
+npcm7xx_emc_reg_write(int emc_num, const char *name, int regno, uint32_t value) "emc%d: reg[%s/%d] = 0x%x"
1214
--
515
--
1215
2.20.1
516
2.34.1
1216
1217
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Bernhard Beschow <shentey@gmail.com>
2
2
3
These functions are not small, except for unlock_user
3
imx_fec models the same PHY as lan9118_phy. The code is almost the same with
4
without debugging enabled. Move them out of line, and
4
imx_fec having more logging and tracing. Merge these improvements into
5
add missing braces on the way.
5
lan9118_phy and reuse in imx_fec to fix the code duplication.
6
6
7
Some migration state how resides in the new device model which breaks migration
8
compatibility for the following machines:
9
* imx25-pdk
10
* sabrelite
11
* mcimx7d-sabre
12
* mcimx6ul-evk
13
14
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
15
Tested-by: Guenter Roeck <linux@roeck-us.net>
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
16
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
17
Message-id: 20241102125724.532843-3-shentey@gmail.com
9
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
10
Message-id: 20210212184902.1251044-18-richard.henderson@linaro.org
11
[PMM: fixed the sense of an ifdef test in qemu.h]
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
18
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
---
19
---
14
linux-user/qemu.h | 47 +++++++-------------------------------------
20
include/hw/net/imx_fec.h | 9 ++-
15
linux-user/uaccess.c | 46 +++++++++++++++++++++++++++++++++++++++++++
21
hw/net/imx_fec.c | 146 ++++-----------------------------------
16
2 files changed, 53 insertions(+), 40 deletions(-)
22
hw/net/lan9118_phy.c | 82 ++++++++++++++++------
23
hw/net/Kconfig | 1 +
24
hw/net/trace-events | 10 +--
25
5 files changed, 85 insertions(+), 163 deletions(-)
17
26
18
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
27
diff --git a/include/hw/net/imx_fec.h b/include/hw/net/imx_fec.h
19
index XXXXXXX..XXXXXXX 100644
28
index XXXXXXX..XXXXXXX 100644
20
--- a/linux-user/qemu.h
29
--- a/include/hw/net/imx_fec.h
21
+++ b/linux-user/qemu.h
30
+++ b/include/hw/net/imx_fec.h
22
@@ -XXX,XX +XXX,XX @@ abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len);
31
@@ -XXX,XX +XXX,XX @@ OBJECT_DECLARE_SIMPLE_TYPE(IMXFECState, IMX_FEC)
23
32
#define TYPE_IMX_ENET "imx.enet"
24
/* Lock an area of guest memory into the host. If copy is true then the
33
25
host area will have the same contents as the guest. */
34
#include "hw/sysbus.h"
26
-static inline void *lock_user(int type, abi_ulong guest_addr, long len, int copy)
35
+#include "hw/net/lan9118_phy.h"
36
+#include "hw/irq.h"
37
#include "net/net.h"
38
39
#define ENET_EIR 1
40
@@ -XXX,XX +XXX,XX @@ struct IMXFECState {
41
uint32_t tx_descriptor[ENET_TX_RING_NUM];
42
uint32_t tx_ring_num;
43
44
- uint32_t phy_status;
45
- uint32_t phy_control;
46
- uint32_t phy_advertise;
47
- uint32_t phy_int;
48
- uint32_t phy_int_mask;
49
+ Lan9118PhyState mii;
50
+ IRQState mii_irq;
51
uint32_t phy_num;
52
bool phy_connected;
53
struct IMXFECState *phy_consumer;
54
diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c
55
index XXXXXXX..XXXXXXX 100644
56
--- a/hw/net/imx_fec.c
57
+++ b/hw/net/imx_fec.c
58
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_imx_eth_txdescs = {
59
60
static const VMStateDescription vmstate_imx_eth = {
61
.name = TYPE_IMX_FEC,
62
- .version_id = 2,
63
- .minimum_version_id = 2,
64
+ .version_id = 3,
65
+ .minimum_version_id = 3,
66
.fields = (const VMStateField[]) {
67
VMSTATE_UINT32_ARRAY(regs, IMXFECState, ENET_MAX),
68
VMSTATE_UINT32(rx_descriptor, IMXFECState),
69
VMSTATE_UINT32(tx_descriptor[0], IMXFECState),
70
- VMSTATE_UINT32(phy_status, IMXFECState),
71
- VMSTATE_UINT32(phy_control, IMXFECState),
72
- VMSTATE_UINT32(phy_advertise, IMXFECState),
73
- VMSTATE_UINT32(phy_int, IMXFECState),
74
- VMSTATE_UINT32(phy_int_mask, IMXFECState),
75
VMSTATE_END_OF_LIST()
76
},
77
.subsections = (const VMStateDescription * const []) {
78
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_imx_eth = {
79
},
80
};
81
82
-#define PHY_INT_ENERGYON (1 << 7)
83
-#define PHY_INT_AUTONEG_COMPLETE (1 << 6)
84
-#define PHY_INT_FAULT (1 << 5)
85
-#define PHY_INT_DOWN (1 << 4)
86
-#define PHY_INT_AUTONEG_LP (1 << 3)
87
-#define PHY_INT_PARFAULT (1 << 2)
88
-#define PHY_INT_AUTONEG_PAGE (1 << 1)
89
-
90
static void imx_eth_update(IMXFECState *s);
91
92
/*
93
@@ -XXX,XX +XXX,XX @@ static void imx_eth_update(IMXFECState *s);
94
* For now we don't handle any GPIO/interrupt line, so the OS will
95
* have to poll for the PHY status.
96
*/
97
-static void imx_phy_update_irq(IMXFECState *s)
98
+static void imx_phy_update_irq(void *opaque, int n, int level)
99
{
100
- imx_eth_update(s);
101
-}
102
-
103
-static void imx_phy_update_link(IMXFECState *s)
27
-{
104
-{
28
- if (!access_ok_untagged(type, guest_addr, len)) {
105
- /* Autonegotiation status mirrors link status. */
29
- return NULL;
106
- if (qemu_get_queue(s->nic)->link_down) {
107
- trace_imx_phy_update_link("down");
108
- s->phy_status &= ~0x0024;
109
- s->phy_int |= PHY_INT_DOWN;
110
- } else {
111
- trace_imx_phy_update_link("up");
112
- s->phy_status |= 0x0024;
113
- s->phy_int |= PHY_INT_ENERGYON;
114
- s->phy_int |= PHY_INT_AUTONEG_COMPLETE;
30
- }
115
- }
31
-#ifdef DEBUG_REMAP
116
- imx_phy_update_irq(s);
32
- {
117
+ imx_eth_update(opaque);
33
- void *addr;
118
}
34
- addr = g_malloc(len);
119
35
- if (copy)
120
static void imx_eth_set_link(NetClientState *nc)
36
- memcpy(addr, g2h(guest_addr), len);
121
{
37
- else
122
- imx_phy_update_link(IMX_FEC(qemu_get_nic_opaque(nc)));
38
- memset(addr, 0, len);
123
-}
39
- return addr;
124
-
125
-static void imx_phy_reset(IMXFECState *s)
126
-{
127
- trace_imx_phy_reset();
128
-
129
- s->phy_status = 0x7809;
130
- s->phy_control = 0x3000;
131
- s->phy_advertise = 0x01e1;
132
- s->phy_int_mask = 0;
133
- s->phy_int = 0;
134
- imx_phy_update_link(s);
135
+ lan9118_phy_update_link(&IMX_FEC(qemu_get_nic_opaque(nc))->mii,
136
+ nc->link_down);
137
}
138
139
static uint32_t imx_phy_read(IMXFECState *s, int reg)
140
{
141
- uint32_t val;
142
uint32_t phy = reg / 32;
143
144
if (!s->phy_connected) {
145
@@ -XXX,XX +XXX,XX @@ static uint32_t imx_phy_read(IMXFECState *s, int reg)
146
147
reg %= 32;
148
149
- switch (reg) {
150
- case 0: /* Basic Control */
151
- val = s->phy_control;
152
- break;
153
- case 1: /* Basic Status */
154
- val = s->phy_status;
155
- break;
156
- case 2: /* ID1 */
157
- val = 0x0007;
158
- break;
159
- case 3: /* ID2 */
160
- val = 0xc0d1;
161
- break;
162
- case 4: /* Auto-neg advertisement */
163
- val = s->phy_advertise;
164
- break;
165
- case 5: /* Auto-neg Link Partner Ability */
166
- val = 0x0f71;
167
- break;
168
- case 6: /* Auto-neg Expansion */
169
- val = 1;
170
- break;
171
- case 29: /* Interrupt source. */
172
- val = s->phy_int;
173
- s->phy_int = 0;
174
- imx_phy_update_irq(s);
175
- break;
176
- case 30: /* Interrupt mask */
177
- val = s->phy_int_mask;
178
- break;
179
- case 17:
180
- case 18:
181
- case 27:
182
- case 31:
183
- qemu_log_mask(LOG_UNIMP, "[%s.phy]%s: reg %d not implemented\n",
184
- TYPE_IMX_FEC, __func__, reg);
185
- val = 0;
186
- break;
187
- default:
188
- qemu_log_mask(LOG_GUEST_ERROR, "[%s.phy]%s: Bad address at offset %d\n",
189
- TYPE_IMX_FEC, __func__, reg);
190
- val = 0;
191
- break;
40
- }
192
- }
41
-#else
193
-
42
- return g2h_untagged(guest_addr);
194
- trace_imx_phy_read(val, phy, reg);
43
-#endif
195
-
44
-}
196
- return val;
45
+void *lock_user(int type, abi_ulong guest_addr, long len, int copy);
197
+ return lan9118_phy_read(&s->mii, reg);
46
198
}
47
/* Unlock an area of guest memory. The first LEN bytes must be
199
48
flushed back to guest memory. host_ptr = NULL is explicitly
200
static void imx_phy_write(IMXFECState *s, int reg, uint32_t val)
49
allowed and does nothing. */
201
@@ -XXX,XX +XXX,XX @@ static void imx_phy_write(IMXFECState *s, int reg, uint32_t val)
50
-static inline void unlock_user(void *host_ptr, abi_ulong guest_addr,
202
51
- long len)
203
reg %= 32;
52
-{
204
53
-
205
- trace_imx_phy_write(val, phy, reg);
54
-#ifdef DEBUG_REMAP
206
-
55
- if (!host_ptr)
207
- switch (reg) {
56
- return;
208
- case 0: /* Basic Control */
57
- if (host_ptr == g2h_untagged(guest_addr))
209
- if (val & 0x8000) {
58
- return;
210
- imx_phy_reset(s);
59
- if (len > 0)
211
- } else {
60
- memcpy(g2h_untagged(guest_addr), host_ptr, len);
212
- s->phy_control = val & 0x7980;
61
- g_free(host_ptr);
213
- /* Complete autonegotiation immediately. */
62
+#ifndef DEBUG_REMAP
214
- if (val & 0x1000) {
63
+static inline void unlock_user(void *host_ptr, abi_ulong guest_addr, long len)
215
- s->phy_status |= 0x0020;
64
+{ }
216
- }
65
+#else
217
- }
66
+void unlock_user(void *host_ptr, abi_ulong guest_addr, long len);
218
- break;
67
#endif
219
- case 4: /* Auto-neg advertisement */
68
-}
220
- s->phy_advertise = (val & 0x2d7f) | 0x80;
69
221
- break;
70
/* Return the length of a string in target memory or -TARGET_EFAULT if
222
- case 30: /* Interrupt mask */
71
access error. */
223
- s->phy_int_mask = val & 0xff;
72
abi_long target_strlen(abi_ulong gaddr);
224
- imx_phy_update_irq(s);
73
225
- break;
74
/* Like lock_user but for null terminated strings. */
226
- case 17:
75
-static inline void *lock_user_string(abi_ulong guest_addr)
227
- case 18:
76
-{
228
- case 27:
77
- abi_long len;
229
- case 31:
78
- len = target_strlen(guest_addr);
230
- qemu_log_mask(LOG_UNIMP, "[%s.phy)%s: reg %d not implemented\n",
79
- if (len < 0)
231
- TYPE_IMX_FEC, __func__, reg);
80
- return NULL;
232
- break;
81
- return lock_user(VERIFY_READ, guest_addr, (long)(len + 1), 1);
233
- default:
82
-}
234
- qemu_log_mask(LOG_GUEST_ERROR, "[%s.phy]%s: Bad address at offset %d\n",
83
+void *lock_user_string(abi_ulong guest_addr);
235
- TYPE_IMX_FEC, __func__, reg);
84
236
- break;
85
/* Helper macros for locking/unlocking a target struct. */
237
- }
86
#define lock_user_struct(type, host_ptr, guest_addr, copy)    \
238
+ lan9118_phy_write(&s->mii, reg, val);
87
diff --git a/linux-user/uaccess.c b/linux-user/uaccess.c
239
}
88
index XXXXXXX..XXXXXXX 100644
240
89
--- a/linux-user/uaccess.c
241
static void imx_fec_read_bd(IMXFECBufDesc *bd, dma_addr_t addr)
90
+++ b/linux-user/uaccess.c
242
@@ -XXX,XX +XXX,XX @@ static void imx_eth_reset(DeviceState *d)
91
@@ -XXX,XX +XXX,XX @@
243
92
244
s->rx_descriptor = 0;
93
#include "qemu.h"
245
memset(s->tx_descriptor, 0, sizeof(s->tx_descriptor));
94
246
-
95
+void *lock_user(int type, abi_ulong guest_addr, long len, int copy)
247
- /* We also reset the PHY */
96
+{
248
- imx_phy_reset(s);
97
+ if (!access_ok_untagged(type, guest_addr, len)) {
249
}
98
+ return NULL;
250
99
+ }
251
static uint32_t imx_default_read(IMXFECState *s, uint32_t index)
100
+#ifdef DEBUG_REMAP
252
@@ -XXX,XX +XXX,XX @@ static void imx_eth_realize(DeviceState *dev, Error **errp)
101
+ {
253
sysbus_init_irq(sbd, &s->irq[0]);
102
+ void *addr;
254
sysbus_init_irq(sbd, &s->irq[1]);
103
+ addr = g_malloc(len);
255
104
+ if (copy) {
256
+ qemu_init_irq(&s->mii_irq, imx_phy_update_irq, s, 0);
105
+ memcpy(addr, g2h(guest_addr), len);
257
+ object_initialize_child(OBJECT(s), "mii", &s->mii, TYPE_LAN9118_PHY);
106
+ } else {
258
+ if (!sysbus_realize_and_unref(SYS_BUS_DEVICE(&s->mii), errp)) {
107
+ memset(addr, 0, len);
108
+ }
109
+ return addr;
110
+ }
111
+#else
112
+ return g2h_untagged(guest_addr);
113
+#endif
114
+}
115
+
116
+#ifdef DEBUG_REMAP
117
+void unlock_user(void *host_ptr, abi_ulong guest_addr, long len);
118
+{
119
+ if (!host_ptr) {
120
+ return;
259
+ return;
121
+ }
260
+ }
122
+ if (host_ptr == g2h_untagged(guest_addr)) {
261
+ qdev_connect_gpio_out(DEVICE(&s->mii), 0, &s->mii_irq);
123
+ return;
262
+
124
+ }
263
qemu_macaddr_default_if_unset(&s->conf.macaddr);
125
+ if (len > 0) {
264
126
+ memcpy(g2h_untagged(guest_addr), host_ptr, len);
265
s->nic = qemu_new_nic(&imx_eth_net_info, &s->conf,
127
+ }
266
diff --git a/hw/net/lan9118_phy.c b/hw/net/lan9118_phy.c
128
+ g_free(host_ptr);
267
index XXXXXXX..XXXXXXX 100644
129
+}
268
--- a/hw/net/lan9118_phy.c
130
+#endif
269
+++ b/hw/net/lan9118_phy.c
131
+
270
@@ -XXX,XX +XXX,XX @@
132
+void *lock_user_string(abi_ulong guest_addr)
271
* Copyright (c) 2009 CodeSourcery, LLC.
133
+{
272
* Written by Paul Brook
134
+ abi_long len = target_strlen(guest_addr);
273
*
135
+ if (len < 0) {
274
+ * Copyright (c) 2013 Jean-Christophe Dubois. <jcd@tribudubois.net>
136
+ return NULL;
275
+ *
137
+ }
276
* This code is licensed under the GNU GPL v2
138
+ return lock_user(VERIFY_READ, guest_addr, (long)(len + 1), 1);
277
*
139
+}
278
* Contributions after 2012-01-13 are licensed under the terms of the
140
+
279
@@ -XXX,XX +XXX,XX @@
141
/* copy_from_user() and copy_to_user() are usually used to copy data
280
#include "hw/resettable.h"
142
* buffers between the target and host. These internally perform
281
#include "migration/vmstate.h"
143
* locking/unlocking of the memory.
282
#include "qemu/log.h"
283
+#include "trace.h"
284
285
#define PHY_INT_ENERGYON (1 << 7)
286
#define PHY_INT_AUTONEG_COMPLETE (1 << 6)
287
@@ -XXX,XX +XXX,XX @@ uint16_t lan9118_phy_read(Lan9118PhyState *s, int reg)
288
289
switch (reg) {
290
case 0: /* Basic Control */
291
- return s->control;
292
+ val = s->control;
293
+ break;
294
case 1: /* Basic Status */
295
- return s->status;
296
+ val = s->status;
297
+ break;
298
case 2: /* ID1 */
299
- return 0x0007;
300
+ val = 0x0007;
301
+ break;
302
case 3: /* ID2 */
303
- return 0xc0d1;
304
+ val = 0xc0d1;
305
+ break;
306
case 4: /* Auto-neg advertisement */
307
- return s->advertise;
308
+ val = s->advertise;
309
+ break;
310
case 5: /* Auto-neg Link Partner Ability */
311
- return 0x0f71;
312
+ val = 0x0f71;
313
+ break;
314
case 6: /* Auto-neg Expansion */
315
- return 1;
316
- /* TODO 17, 18, 27, 29, 30, 31 */
317
+ val = 1;
318
+ break;
319
case 29: /* Interrupt source. */
320
val = s->ints;
321
s->ints = 0;
322
lan9118_phy_update_irq(s);
323
- return val;
324
+ break;
325
case 30: /* Interrupt mask */
326
- return s->int_mask;
327
+ val = s->int_mask;
328
+ break;
329
+ case 17:
330
+ case 18:
331
+ case 27:
332
+ case 31:
333
+ qemu_log_mask(LOG_UNIMP, "%s: reg %d not implemented\n",
334
+ __func__, reg);
335
+ val = 0;
336
+ break;
337
default:
338
- qemu_log_mask(LOG_GUEST_ERROR,
339
- "lan9118_phy_read: PHY read reg %d\n", reg);
340
- return 0;
341
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad address at offset %d\n",
342
+ __func__, reg);
343
+ val = 0;
344
+ break;
345
}
346
+
347
+ trace_lan9118_phy_read(val, reg);
348
+
349
+ return val;
350
}
351
352
void lan9118_phy_write(Lan9118PhyState *s, int reg, uint16_t val)
353
{
354
+ trace_lan9118_phy_write(val, reg);
355
+
356
switch (reg) {
357
case 0: /* Basic Control */
358
if (val & 0x8000) {
359
lan9118_phy_reset(s);
360
- break;
361
- }
362
- s->control = val & 0x7980;
363
- /* Complete autonegotiation immediately. */
364
- if (val & 0x1000) {
365
- s->status |= 0x0020;
366
+ } else {
367
+ s->control = val & 0x7980;
368
+ /* Complete autonegotiation immediately. */
369
+ if (val & 0x1000) {
370
+ s->status |= 0x0020;
371
+ }
372
}
373
break;
374
case 4: /* Auto-neg advertisement */
375
s->advertise = (val & 0x2d7f) | 0x80;
376
break;
377
- /* TODO 17, 18, 27, 31 */
378
case 30: /* Interrupt mask */
379
s->int_mask = val & 0xff;
380
lan9118_phy_update_irq(s);
381
break;
382
+ case 17:
383
+ case 18:
384
+ case 27:
385
+ case 31:
386
+ qemu_log_mask(LOG_UNIMP, "%s: reg %d not implemented\n",
387
+ __func__, reg);
388
+ break;
389
default:
390
- qemu_log_mask(LOG_GUEST_ERROR,
391
- "lan9118_phy_write: PHY write reg %d = 0x%04x\n", reg, val);
392
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad address at offset %d\n",
393
+ __func__, reg);
394
+ break;
395
}
396
}
397
398
@@ -XXX,XX +XXX,XX @@ void lan9118_phy_update_link(Lan9118PhyState *s, bool link_down)
399
400
/* Autonegotiation status mirrors link status. */
401
if (link_down) {
402
+ trace_lan9118_phy_update_link("down");
403
s->status &= ~0x0024;
404
s->ints |= PHY_INT_DOWN;
405
} else {
406
+ trace_lan9118_phy_update_link("up");
407
s->status |= 0x0024;
408
s->ints |= PHY_INT_ENERGYON;
409
s->ints |= PHY_INT_AUTONEG_COMPLETE;
410
@@ -XXX,XX +XXX,XX @@ void lan9118_phy_update_link(Lan9118PhyState *s, bool link_down)
411
412
void lan9118_phy_reset(Lan9118PhyState *s)
413
{
414
+ trace_lan9118_phy_reset();
415
+
416
s->control = 0x3000;
417
s->status = 0x7809;
418
s->advertise = 0x01e1;
419
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_lan9118_phy = {
420
.version_id = 1,
421
.minimum_version_id = 1,
422
.fields = (const VMStateField[]) {
423
- VMSTATE_UINT16(control, Lan9118PhyState),
424
VMSTATE_UINT16(status, Lan9118PhyState),
425
+ VMSTATE_UINT16(control, Lan9118PhyState),
426
VMSTATE_UINT16(advertise, Lan9118PhyState),
427
VMSTATE_UINT16(ints, Lan9118PhyState),
428
VMSTATE_UINT16(int_mask, Lan9118PhyState),
429
diff --git a/hw/net/Kconfig b/hw/net/Kconfig
430
index XXXXXXX..XXXXXXX 100644
431
--- a/hw/net/Kconfig
432
+++ b/hw/net/Kconfig
433
@@ -XXX,XX +XXX,XX @@ config ALLWINNER_SUN8I_EMAC
434
435
config IMX_FEC
436
bool
437
+ select LAN9118_PHY
438
439
config CADENCE
440
bool
441
diff --git a/hw/net/trace-events b/hw/net/trace-events
442
index XXXXXXX..XXXXXXX 100644
443
--- a/hw/net/trace-events
444
+++ b/hw/net/trace-events
445
@@ -XXX,XX +XXX,XX @@ allwinner_sun8i_emac_set_link(bool active) "Set link: active=%u"
446
allwinner_sun8i_emac_read(uint64_t offset, uint64_t val) "MMIO read: offset=0x%" PRIx64 " value=0x%" PRIx64
447
allwinner_sun8i_emac_write(uint64_t offset, uint64_t val) "MMIO write: offset=0x%" PRIx64 " value=0x%" PRIx64
448
449
+# lan9118_phy.c
450
+lan9118_phy_read(uint16_t val, int reg) "[0x%02x] -> 0x%04" PRIx16
451
+lan9118_phy_write(uint16_t val, int reg) "[0x%02x] <- 0x%04" PRIx16
452
+lan9118_phy_update_link(const char *s) "%s"
453
+lan9118_phy_reset(void) ""
454
+
455
# lance.c
456
lance_mem_readw(uint64_t addr, uint32_t ret) "addr=0x%"PRIx64"val=0x%04x"
457
lance_mem_writew(uint64_t addr, uint32_t val) "addr=0x%"PRIx64"val=0x%04x"
458
@@ -XXX,XX +XXX,XX @@ i82596_set_multicast(uint16_t count) "Added %d multicast entries"
459
i82596_channel_attention(void *s) "%p: Received CHANNEL ATTENTION"
460
461
# imx_fec.c
462
-imx_phy_read(uint32_t val, int phy, int reg) "0x%04"PRIx32" <= phy[%d].reg[%d]"
463
imx_phy_read_num(int phy, int configured) "read request from unconfigured phy %d (configured %d)"
464
-imx_phy_write(uint32_t val, int phy, int reg) "0x%04"PRIx32" => phy[%d].reg[%d]"
465
imx_phy_write_num(int phy, int configured) "write request to unconfigured phy %d (configured %d)"
466
-imx_phy_update_link(const char *s) "%s"
467
-imx_phy_reset(void) ""
468
imx_fec_read_bd(uint64_t addr, int flags, int len, int data) "tx_bd 0x%"PRIx64" flags 0x%04x len %d data 0x%08x"
469
imx_enet_read_bd(uint64_t addr, int flags, int len, int data, int options, int status) "tx_bd 0x%"PRIx64" flags 0x%04x len %d data 0x%08x option 0x%04x status 0x%04x"
470
imx_eth_tx_bd_busy(void) "tx_bd ran out of descriptors to transmit"
144
--
471
--
145
2.20.1
472
2.34.1
146
147
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Bernhard Beschow <shentey@gmail.com>
2
2
3
The real kernel collects _TIF_MTE_ASYNC_FAULT into the current thread's
3
Turns 0x70 into 0xe0 (== 0x70 << 1) which adds the missing MII_ANLPAR_TX and
4
state on any kernel entry (interrupt, exception etc), and then delivers
4
fixes the MSB of selector field to be zero, as specified in the datasheet.
5
the signal in advance of resuming the thread.
6
5
7
This means that while the signal won't be delivered immediately, it will
6
Fixes: 2a424990170b "LAN9118 emulation"
8
not be delayed forever -- at minimum it will be delivered after the next
7
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
9
clock interrupt.
8
Tested-by: Guenter Roeck <linux@roeck-us.net>
10
11
We don't have a clock interrupt in linux-user, so we issue a cpu_kick
12
to signal a return to the main loop at the end of the current TB.
13
14
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
15
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
10
Message-id: 20241102125724.532843-4-shentey@gmail.com
16
Message-id: 20210212184902.1251044-29-richard.henderson@linaro.org
17
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
18
---
12
---
19
linux-user/aarch64/target_signal.h | 1 +
13
hw/net/lan9118_phy.c | 2 +-
20
linux-user/aarch64/cpu_loop.c | 11 +++++++++++
14
1 file changed, 1 insertion(+), 1 deletion(-)
21
target/arm/mte_helper.c | 10 ++++++++++
22
3 files changed, 22 insertions(+)
23
15
24
diff --git a/linux-user/aarch64/target_signal.h b/linux-user/aarch64/target_signal.h
16
diff --git a/hw/net/lan9118_phy.c b/hw/net/lan9118_phy.c
25
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
26
--- a/linux-user/aarch64/target_signal.h
18
--- a/hw/net/lan9118_phy.c
27
+++ b/linux-user/aarch64/target_signal.h
19
+++ b/hw/net/lan9118_phy.c
28
@@ -XXX,XX +XXX,XX @@ typedef struct target_sigaltstack {
20
@@ -XXX,XX +XXX,XX @@ uint16_t lan9118_phy_read(Lan9118PhyState *s, int reg)
29
21
val = s->advertise;
30
#include "../generic/signal.h"
31
32
+#define TARGET_SEGV_MTEAERR 8 /* Asynchronous ARM MTE error */
33
#define TARGET_SEGV_MTESERR 9 /* Synchronous ARM MTE exception */
34
35
#define TARGET_ARCH_HAS_SETUP_FRAME
36
diff --git a/linux-user/aarch64/cpu_loop.c b/linux-user/aarch64/cpu_loop.c
37
index XXXXXXX..XXXXXXX 100644
38
--- a/linux-user/aarch64/cpu_loop.c
39
+++ b/linux-user/aarch64/cpu_loop.c
40
@@ -XXX,XX +XXX,XX @@ void cpu_loop(CPUARMState *env)
41
EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
42
abort();
43
}
44
+
45
+ /* Check for MTE asynchronous faults */
46
+ if (unlikely(env->cp15.tfsr_el[0])) {
47
+ env->cp15.tfsr_el[0] = 0;
48
+ info.si_signo = TARGET_SIGSEGV;
49
+ info.si_errno = 0;
50
+ info._sifields._sigfault._addr = 0;
51
+ info.si_code = TARGET_SEGV_MTEAERR;
52
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
53
+ }
54
+
55
process_pending_signals(env);
56
/* Exception return on AArch64 always clears the exclusive monitor,
57
* so any return to running guest code implies this.
58
diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c
59
index XXXXXXX..XXXXXXX 100644
60
--- a/target/arm/mte_helper.c
61
+++ b/target/arm/mte_helper.c
62
@@ -XXX,XX +XXX,XX @@ static void mte_check_fail(CPUARMState *env, uint32_t desc,
63
select = 0;
64
}
65
env->cp15.tfsr_el[el] |= 1 << select;
66
+#ifdef CONFIG_USER_ONLY
67
+ /*
68
+ * Stand in for a timer irq, setting _TIF_MTE_ASYNC_FAULT,
69
+ * which then sends a SIGSEGV when the thread is next scheduled.
70
+ * This cpu will return to the main loop at the end of the TB,
71
+ * which is rather sooner than "normal". But the alternative
72
+ * is waiting until the next syscall.
73
+ */
74
+ qemu_cpu_kick(env_cpu(env));
75
+#endif
76
break;
22
break;
77
23
case 5: /* Auto-neg Link Partner Ability */
78
default:
24
- val = 0x0f71;
25
+ val = 0x0fe1;
26
break;
27
case 6: /* Auto-neg Expansion */
28
val = 1;
79
--
29
--
80
2.20.1
30
2.34.1
81
82
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Bernhard Beschow <shentey@gmail.com>
2
2
3
This is the prctl bit that controls whether syscalls accept tagged
3
Prefer named constants over magic values for better readability.
4
addresses. See Documentation/arm64/tagged-address-abi.rst in the
5
linux kernel.
6
4
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
9
Message-id: 20210212184902.1251044-21-richard.henderson@linaro.org
7
Tested-by: Guenter Roeck <linux@roeck-us.net>
8
Message-id: 20241102125724.532843-5-shentey@gmail.com
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
10
---
12
linux-user/aarch64/target_syscall.h | 4 ++++
11
include/hw/net/mii.h | 6 +++++
13
target/arm/cpu-param.h | 3 +++
12
hw/net/lan9118_phy.c | 63 ++++++++++++++++++++++++++++----------------
14
target/arm/cpu.h | 31 +++++++++++++++++++++++++++++
13
2 files changed, 46 insertions(+), 23 deletions(-)
15
linux-user/syscall.c | 24 ++++++++++++++++++++++
16
4 files changed, 62 insertions(+)
17
14
18
diff --git a/linux-user/aarch64/target_syscall.h b/linux-user/aarch64/target_syscall.h
15
diff --git a/include/hw/net/mii.h b/include/hw/net/mii.h
19
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
20
--- a/linux-user/aarch64/target_syscall.h
17
--- a/include/hw/net/mii.h
21
+++ b/linux-user/aarch64/target_syscall.h
18
+++ b/include/hw/net/mii.h
22
@@ -XXX,XX +XXX,XX @@ struct target_pt_regs {
19
@@ -XXX,XX +XXX,XX @@
23
# define TARGET_PR_PAC_APDBKEY (1 << 3)
20
#define MII_BMSR_JABBER (1 << 1) /* Jabber detected */
24
# define TARGET_PR_PAC_APGAKEY (1 << 4)
21
#define MII_BMSR_EXTCAP (1 << 0) /* Ext-reg capability */
25
22
26
+#define TARGET_PR_SET_TAGGED_ADDR_CTRL 55
23
+#define MII_ANAR_RFAULT (1 << 13) /* Say we can detect faults */
27
+#define TARGET_PR_GET_TAGGED_ADDR_CTRL 56
24
#define MII_ANAR_PAUSE_ASYM (1 << 11) /* Try for asymmetric pause */
28
+# define TARGET_PR_TAGGED_ADDR_ENABLE (1UL << 0)
25
#define MII_ANAR_PAUSE (1 << 10) /* Try for pause */
26
#define MII_ANAR_TXFD (1 << 8)
27
@@ -XXX,XX +XXX,XX @@
28
#define MII_ANAR_10FD (1 << 6)
29
#define MII_ANAR_10 (1 << 5)
30
#define MII_ANAR_CSMACD (1 << 0)
31
+#define MII_ANAR_SELECT (0x001f) /* Selector bits */
32
33
#define MII_ANLPAR_ACK (1 << 14)
34
#define MII_ANLPAR_PAUSEASY (1 << 11) /* can pause asymmetrically */
35
@@ -XXX,XX +XXX,XX @@
36
#define RTL8201CP_PHYID1 0x0000
37
#define RTL8201CP_PHYID2 0x8201
38
39
+/* SMSC LAN9118 */
40
+#define SMSCLAN9118_PHYID1 0x0007
41
+#define SMSCLAN9118_PHYID2 0xc0d1
29
+
42
+
30
#endif /* AARCH64_TARGET_SYSCALL_H */
43
/* RealTek 8211E */
31
diff --git a/target/arm/cpu-param.h b/target/arm/cpu-param.h
44
#define RTL8211E_PHYID1 0x001c
45
#define RTL8211E_PHYID2 0xc915
46
diff --git a/hw/net/lan9118_phy.c b/hw/net/lan9118_phy.c
32
index XXXXXXX..XXXXXXX 100644
47
index XXXXXXX..XXXXXXX 100644
33
--- a/target/arm/cpu-param.h
48
--- a/hw/net/lan9118_phy.c
34
+++ b/target/arm/cpu-param.h
49
+++ b/hw/net/lan9118_phy.c
35
@@ -XXX,XX +XXX,XX @@
50
@@ -XXX,XX +XXX,XX @@
36
51
37
#ifdef CONFIG_USER_ONLY
52
#include "qemu/osdep.h"
38
#define TARGET_PAGE_BITS 12
53
#include "hw/net/lan9118_phy.h"
39
+# ifdef TARGET_AARCH64
54
+#include "hw/net/mii.h"
40
+# define TARGET_TAGGED_ADDRESSES
55
#include "hw/irq.h"
41
+# endif
56
#include "hw/resettable.h"
42
#else
57
#include "migration/vmstate.h"
43
/*
58
@@ -XXX,XX +XXX,XX @@ uint16_t lan9118_phy_read(Lan9118PhyState *s, int reg)
44
* ARMv7 and later CPUs have 4K pages minimum, but ARMv5 and v6
59
uint16_t val;
45
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
60
46
index XXXXXXX..XXXXXXX 100644
61
switch (reg) {
47
--- a/target/arm/cpu.h
62
- case 0: /* Basic Control */
48
+++ b/target/arm/cpu.h
63
+ case MII_BMCR:
49
@@ -XXX,XX +XXX,XX @@ typedef struct CPUARMState {
64
val = s->control;
50
const struct arm_boot_info *boot_info;
65
break;
51
/* Store GICv3CPUState to access from this struct */
66
- case 1: /* Basic Status */
52
void *gicv3state;
67
+ case MII_BMSR:
53
+
68
val = s->status;
54
+#ifdef TARGET_TAGGED_ADDRESSES
69
break;
55
+ /* Linux syscall tagged address support */
70
- case 2: /* ID1 */
56
+ bool tagged_addr_enable;
71
- val = 0x0007;
57
+#endif
72
+ case MII_PHYID1:
58
} CPUARMState;
73
+ val = SMSCLAN9118_PHYID1;
59
74
break;
60
static inline void set_feature(CPUARMState *env, int feature)
75
- case 3: /* ID2 */
61
@@ -XXX,XX +XXX,XX @@ static inline MemTxAttrs *typecheck_memtxattrs(MemTxAttrs *x)
76
- val = 0xc0d1;
62
*/
77
+ case MII_PHYID2:
63
#define PAGE_BTI PAGE_TARGET_1
78
+ val = SMSCLAN9118_PHYID2;
64
79
break;
65
+#ifdef TARGET_TAGGED_ADDRESSES
80
- case 4: /* Auto-neg advertisement */
66
+/**
81
+ case MII_ANAR:
67
+ * cpu_untagged_addr:
82
val = s->advertise;
68
+ * @cs: CPU context
83
break;
69
+ * @x: tagged address
84
- case 5: /* Auto-neg Link Partner Ability */
70
+ *
85
- val = 0x0fe1;
71
+ * Remove any address tag from @x. This is explicitly related to the
86
+ case MII_ANLPAR:
72
+ * linux syscall TIF_TAGGED_ADDR setting, not TBI in general.
87
+ val = MII_ANLPAR_PAUSEASY | MII_ANLPAR_PAUSE | MII_ANLPAR_T4 |
73
+ *
88
+ MII_ANLPAR_TXFD | MII_ANLPAR_TX | MII_ANLPAR_10FD |
74
+ * There should be a better place to put this, but we need this in
89
+ MII_ANLPAR_10 | MII_ANLPAR_CSMACD;
75
+ * include/exec/cpu_ldst.h, and not some place linux-user specific.
90
break;
76
+ */
91
- case 6: /* Auto-neg Expansion */
77
+static inline target_ulong cpu_untagged_addr(CPUState *cs, target_ulong x)
92
- val = 1;
78
+{
93
+ case MII_ANER:
79
+ ARMCPU *cpu = ARM_CPU(cs);
94
+ val = MII_ANER_NWAY;
80
+ if (cpu->env.tagged_addr_enable) {
95
break;
81
+ /*
96
case 29: /* Interrupt source. */
82
+ * TBI is enabled for userspace but not kernelspace addresses.
97
val = s->ints;
83
+ * Only clear the tag if bit 55 is clear.
98
@@ -XXX,XX +XXX,XX @@ void lan9118_phy_write(Lan9118PhyState *s, int reg, uint16_t val)
84
+ */
99
trace_lan9118_phy_write(val, reg);
85
+ x &= sextract64(x, 0, 56);
100
86
+ }
101
switch (reg) {
87
+ return x;
102
- case 0: /* Basic Control */
88
+}
103
- if (val & 0x8000) {
89
+#endif
104
+ case MII_BMCR:
90
+
105
+ if (val & MII_BMCR_RESET) {
91
/*
106
lan9118_phy_reset(s);
92
* Naming convention for isar_feature functions:
107
} else {
93
* Functions which test 32-bit ID registers should have _aa32_ in
108
- s->control = val & 0x7980;
94
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
109
+ s->control = val & (MII_BMCR_LOOPBACK | MII_BMCR_SPEED100 |
95
index XXXXXXX..XXXXXXX 100644
110
+ MII_BMCR_AUTOEN | MII_BMCR_PDOWN | MII_BMCR_FD |
96
--- a/linux-user/syscall.c
111
+ MII_BMCR_CTST);
97
+++ b/linux-user/syscall.c
112
/* Complete autonegotiation immediately. */
98
@@ -XXX,XX +XXX,XX @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
113
- if (val & 0x1000) {
99
}
114
- s->status |= 0x0020;
115
+ if (val & MII_BMCR_AUTOEN) {
116
+ s->status |= MII_BMSR_AN_COMP;
100
}
117
}
101
return -TARGET_EINVAL;
118
}
102
+ case TARGET_PR_SET_TAGGED_ADDR_CTRL:
119
break;
103
+ {
120
- case 4: /* Auto-neg advertisement */
104
+ abi_ulong valid_mask = TARGET_PR_TAGGED_ADDR_ENABLE;
121
- s->advertise = (val & 0x2d7f) | 0x80;
105
+ CPUARMState *env = cpu_env;
122
+ case MII_ANAR:
106
+
123
+ s->advertise = (val & (MII_ANAR_RFAULT | MII_ANAR_PAUSE_ASYM |
107
+ if ((arg2 & ~valid_mask) || arg3 || arg4 || arg5) {
124
+ MII_ANAR_PAUSE | MII_ANAR_10FD | MII_ANAR_10 |
108
+ return -TARGET_EINVAL;
125
+ MII_ANAR_SELECT))
109
+ }
126
+ | MII_ANAR_TX;
110
+ env->tagged_addr_enable = arg2 & TARGET_PR_TAGGED_ADDR_ENABLE;
127
break;
111
+ return 0;
128
case 30: /* Interrupt mask */
112
+ }
129
s->int_mask = val & 0xff;
113
+ case TARGET_PR_GET_TAGGED_ADDR_CTRL:
130
@@ -XXX,XX +XXX,XX @@ void lan9118_phy_update_link(Lan9118PhyState *s, bool link_down)
114
+ {
131
/* Autonegotiation status mirrors link status. */
115
+ abi_long ret = 0;
132
if (link_down) {
116
+ CPUARMState *env = cpu_env;
133
trace_lan9118_phy_update_link("down");
117
+
134
- s->status &= ~0x0024;
118
+ if (arg2 || arg3 || arg4 || arg5) {
135
+ s->status &= ~(MII_BMSR_AN_COMP | MII_BMSR_LINK_ST);
119
+ return -TARGET_EINVAL;
136
s->ints |= PHY_INT_DOWN;
120
+ }
137
} else {
121
+ if (env->tagged_addr_enable) {
138
trace_lan9118_phy_update_link("up");
122
+ ret |= TARGET_PR_TAGGED_ADDR_ENABLE;
139
- s->status |= 0x0024;
123
+ }
140
+ s->status |= MII_BMSR_AN_COMP | MII_BMSR_LINK_ST;
124
+ return ret;
141
s->ints |= PHY_INT_ENERGYON;
125
+ }
142
s->ints |= PHY_INT_AUTONEG_COMPLETE;
126
#endif /* AARCH64 */
143
}
127
case PR_GET_SECCOMP:
144
@@ -XXX,XX +XXX,XX @@ void lan9118_phy_reset(Lan9118PhyState *s)
128
case PR_SET_SECCOMP:
145
{
146
trace_lan9118_phy_reset();
147
148
- s->control = 0x3000;
149
- s->status = 0x7809;
150
- s->advertise = 0x01e1;
151
+ s->control = MII_BMCR_AUTOEN | MII_BMCR_SPEED100;
152
+ s->status = MII_BMSR_100TX_FD
153
+ | MII_BMSR_100TX_HD
154
+ | MII_BMSR_10T_FD
155
+ | MII_BMSR_10T_HD
156
+ | MII_BMSR_AUTONEG
157
+ | MII_BMSR_EXTCAP;
158
+ s->advertise = MII_ANAR_TXFD
159
+ | MII_ANAR_TX
160
+ | MII_ANAR_10FD
161
+ | MII_ANAR_10
162
+ | MII_ANAR_CSMACD;
163
s->int_mask = 0;
164
s->ints = 0;
165
lan9118_phy_update_link(s, s->link_down);
129
--
166
--
130
2.20.1
167
2.34.1
131
132
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Bernhard Beschow <shentey@gmail.com>
2
3
The real device advertises this mode and the device model already advertises
4
100 mbps half duplex and 10 mbps full+half duplex. So advertise this mode to
5
make the model more realistic.
2
6
3
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
4
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
5
Message-id: 20210212184902.1251044-28-richard.henderson@linaro.org
9
Tested-by: Guenter Roeck <linux@roeck-us.net>
10
Message-id: 20241102125724.532843-6-shentey@gmail.com
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
---
12
---
8
linux-user/aarch64/target_signal.h | 2 ++
13
hw/net/lan9118_phy.c | 4 ++--
9
linux-user/aarch64/cpu_loop.c | 3 +++
14
1 file changed, 2 insertions(+), 2 deletions(-)
10
2 files changed, 5 insertions(+)
11
15
12
diff --git a/linux-user/aarch64/target_signal.h b/linux-user/aarch64/target_signal.h
16
diff --git a/hw/net/lan9118_phy.c b/hw/net/lan9118_phy.c
13
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
14
--- a/linux-user/aarch64/target_signal.h
18
--- a/hw/net/lan9118_phy.c
15
+++ b/linux-user/aarch64/target_signal.h
19
+++ b/hw/net/lan9118_phy.c
16
@@ -XXX,XX +XXX,XX @@ typedef struct target_sigaltstack {
20
@@ -XXX,XX +XXX,XX @@ void lan9118_phy_write(Lan9118PhyState *s, int reg, uint16_t val)
17
21
break;
18
#include "../generic/signal.h"
22
case MII_ANAR:
19
23
s->advertise = (val & (MII_ANAR_RFAULT | MII_ANAR_PAUSE_ASYM |
20
+#define TARGET_SEGV_MTESERR 9 /* Synchronous ARM MTE exception */
24
- MII_ANAR_PAUSE | MII_ANAR_10FD | MII_ANAR_10 |
21
+
25
- MII_ANAR_SELECT))
22
#define TARGET_ARCH_HAS_SETUP_FRAME
26
+ MII_ANAR_PAUSE | MII_ANAR_TXFD | MII_ANAR_10FD |
23
#endif /* AARCH64_TARGET_SIGNAL_H */
27
+ MII_ANAR_10 | MII_ANAR_SELECT))
24
diff --git a/linux-user/aarch64/cpu_loop.c b/linux-user/aarch64/cpu_loop.c
28
| MII_ANAR_TX;
25
index XXXXXXX..XXXXXXX 100644
29
break;
26
--- a/linux-user/aarch64/cpu_loop.c
30
case 30: /* Interrupt mask */
27
+++ b/linux-user/aarch64/cpu_loop.c
28
@@ -XXX,XX +XXX,XX @@ void cpu_loop(CPUARMState *env)
29
case 0x0d ... 0x0f: /* Permission fault, level {1-3} */
30
info.si_code = TARGET_SEGV_ACCERR;
31
break;
32
+ case 0x11: /* Synchronous Tag Check Fault */
33
+ info.si_code = TARGET_SEGV_MTESERR;
34
+ break;
35
default:
36
g_assert_not_reached();
37
}
38
--
31
--
39
2.20.1
32
2.34.1
40
41
diff view generated by jsdifflib
1
From: Hao Wu <wuhaotsh@google.com>
1
For IEEE fused multiply-add, the (0 * inf) + NaN case should raise
2
Invalid for the multiplication of 0 by infinity. Currently we handle
3
this in the per-architecture ifdef ladder in pickNaNMulAdd().
4
However, since this isn't really architecture specific we can hoist
5
it up to the generic code.
2
6
3
This commit implements the single-byte mode of the SMBus.
7
For the cases where the infzero test in pickNaNMulAdd was
8
returning 2, we can delete the check entirely and allow the
9
code to fall into the normal pick-a-NaN handling, because this
10
will return 2 anyway (input 'c' being the only NaN in this case).
11
For the cases where infzero was returning 3 to indicate "return
12
the default NaN", we must retain that "return 3".
4
13
5
Each Nuvoton SoC has 16 System Management Bus (SMBus). These buses
14
For Arm, this looks like it might be a behaviour change because we
6
compliant with SMBus and I2C protocol.
15
used to set float_flag_invalid | float_flag_invalid_imz only if C is
16
a quiet NaN. However, it is not, because Arm target code never looks
17
at float_flag_invalid_imz, and for the (0 * inf) + SNaN case we
18
already raised float_flag_invalid via the "abc_mask &
19
float_cmask_snan" check in pick_nan_muladd.
7
20
8
This patch implements the single-byte mode of the SMBus. In this mode,
21
For any target architecture using the "default implementation" at the
9
the user sends or receives a byte each time. The SMBus device transmits
22
bottom of the ifdef, this is a behaviour change but will be fixing a
10
it to the underlying i2c device and sends an interrupt back to the QEMU
23
bug (where we failed to raise the Invalid exception for (0 * inf +
11
guest.
24
QNaN). The architectures using the default case are:
25
* hppa
26
* i386
27
* sh4
28
* tricore
12
29
13
Reviewed-by: Doug Evans<dje@google.com>
30
The x86, Tricore and SH4 CPU architecture manuals are clear that this
14
Reviewed-by: Tyrong Ting<kfting@nuvoton.com>
31
should have raised Invalid; HPPA is a bit vaguer but still seems
15
Signed-off-by: Hao Wu <wuhaotsh@google.com>
32
clear enough.
16
Reviewed-by: Corey Minyard <cminyard@mvista.com>
33
17
Message-id: 20210210220426.3577804-2-wuhaotsh@google.com
18
Acked-by: Corey Minyard <cminyard@mvista.com>
19
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
34
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
35
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
36
Message-id: 20241202131347.498124-2-peter.maydell@linaro.org
20
---
37
---
21
docs/system/arm/nuvoton.rst | 2 +-
38
fpu/softfloat-parts.c.inc | 13 +++++++------
22
include/hw/arm/npcm7xx.h | 2 +
39
fpu/softfloat-specialize.c.inc | 29 +----------------------------
23
include/hw/i2c/npcm7xx_smbus.h | 88 ++++
40
2 files changed, 8 insertions(+), 34 deletions(-)
24
hw/arm/npcm7xx.c | 68 ++-
25
hw/i2c/npcm7xx_smbus.c | 783 +++++++++++++++++++++++++++++++++
26
hw/i2c/meson.build | 1 +
27
hw/i2c/trace-events | 11 +
28
7 files changed, 938 insertions(+), 17 deletions(-)
29
create mode 100644 include/hw/i2c/npcm7xx_smbus.h
30
create mode 100644 hw/i2c/npcm7xx_smbus.c
31
41
32
diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst
42
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
33
index XXXXXXX..XXXXXXX 100644
43
index XXXXXXX..XXXXXXX 100644
34
--- a/docs/system/arm/nuvoton.rst
44
--- a/fpu/softfloat-parts.c.inc
35
+++ b/docs/system/arm/nuvoton.rst
45
+++ b/fpu/softfloat-parts.c.inc
36
@@ -XXX,XX +XXX,XX @@ Supported devices
46
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b,
37
* GPIO controller
47
int ab_mask, int abc_mask)
38
* Analog to Digital Converter (ADC)
48
{
39
* Pulse Width Modulation (PWM)
49
int which;
40
+ * SMBus controller (SMBF)
50
+ bool infzero = (ab_mask == float_cmask_infzero);
41
51
42
Missing devices
52
if (unlikely(abc_mask & float_cmask_snan)) {
43
---------------
53
float_raise(float_flag_invalid | float_flag_invalid_snan, s);
44
@@ -XXX,XX +XXX,XX @@ Missing devices
45
46
* Ethernet controllers (GMAC and EMC)
47
* USB device (USBD)
48
- * SMBus controller (SMBF)
49
* Peripheral SPI controller (PSPI)
50
* SD/MMC host
51
* PECI interface
52
diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
53
index XXXXXXX..XXXXXXX 100644
54
--- a/include/hw/arm/npcm7xx.h
55
+++ b/include/hw/arm/npcm7xx.h
56
@@ -XXX,XX +XXX,XX @@
57
#include "hw/adc/npcm7xx_adc.h"
58
#include "hw/cpu/a9mpcore.h"
59
#include "hw/gpio/npcm7xx_gpio.h"
60
+#include "hw/i2c/npcm7xx_smbus.h"
61
#include "hw/mem/npcm7xx_mc.h"
62
#include "hw/misc/npcm7xx_clk.h"
63
#include "hw/misc/npcm7xx_gcr.h"
64
@@ -XXX,XX +XXX,XX @@ typedef struct NPCM7xxState {
65
NPCM7xxMCState mc;
66
NPCM7xxRNGState rng;
67
NPCM7xxGPIOState gpio[8];
68
+ NPCM7xxSMBusState smbus[16];
69
EHCISysBusState ehci;
70
OHCISysBusState ohci;
71
NPCM7xxFIUState fiu[2];
72
diff --git a/include/hw/i2c/npcm7xx_smbus.h b/include/hw/i2c/npcm7xx_smbus.h
73
new file mode 100644
74
index XXXXXXX..XXXXXXX
75
--- /dev/null
76
+++ b/include/hw/i2c/npcm7xx_smbus.h
77
@@ -XXX,XX +XXX,XX @@
78
+/*
79
+ * Nuvoton NPCM7xx SMBus Module.
80
+ *
81
+ * Copyright 2020 Google LLC
82
+ *
83
+ * This program is free software; you can redistribute it and/or modify it
84
+ * under the terms of the GNU General Public License as published by the
85
+ * Free Software Foundation; either version 2 of the License, or
86
+ * (at your option) any later version.
87
+ *
88
+ * This program is distributed in the hope that it will be useful, but WITHOUT
89
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
90
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
91
+ * for more details.
92
+ */
93
+#ifndef NPCM7XX_SMBUS_H
94
+#define NPCM7XX_SMBUS_H
95
+
96
+#include "exec/memory.h"
97
+#include "hw/i2c/i2c.h"
98
+#include "hw/irq.h"
99
+#include "hw/sysbus.h"
100
+
101
+/*
102
+ * Number of addresses this module contains. Do not change this without
103
+ * incrementing the version_id in the vmstate.
104
+ */
105
+#define NPCM7XX_SMBUS_NR_ADDRS 10
106
+
107
+typedef enum NPCM7xxSMBusStatus {
108
+ NPCM7XX_SMBUS_STATUS_IDLE,
109
+ NPCM7XX_SMBUS_STATUS_SENDING,
110
+ NPCM7XX_SMBUS_STATUS_RECEIVING,
111
+ NPCM7XX_SMBUS_STATUS_NEGACK,
112
+ NPCM7XX_SMBUS_STATUS_STOPPING_LAST_RECEIVE,
113
+ NPCM7XX_SMBUS_STATUS_STOPPING_NEGACK,
114
+} NPCM7xxSMBusStatus;
115
+
116
+/*
117
+ * struct NPCM7xxSMBusState - System Management Bus device state.
118
+ * @bus: The underlying I2C Bus.
119
+ * @irq: GIC interrupt line to fire on events (if enabled).
120
+ * @sda: The serial data register.
121
+ * @st: The status register.
122
+ * @cst: The control status register.
123
+ * @cst2: The control status register 2.
124
+ * @cst3: The control status register 3.
125
+ * @ctl1: The control register 1.
126
+ * @ctl2: The control register 2.
127
+ * @ctl3: The control register 3.
128
+ * @ctl4: The control register 4.
129
+ * @ctl5: The control register 5.
130
+ * @addr: The SMBus module's own addresses on the I2C bus.
131
+ * @scllt: The SCL low time register.
132
+ * @sclht: The SCL high time register.
133
+ * @status: The current status of the SMBus.
134
+ */
135
+typedef struct NPCM7xxSMBusState {
136
+ SysBusDevice parent;
137
+
138
+ MemoryRegion iomem;
139
+
140
+ I2CBus *bus;
141
+ qemu_irq irq;
142
+
143
+ uint8_t sda;
144
+ uint8_t st;
145
+ uint8_t cst;
146
+ uint8_t cst2;
147
+ uint8_t cst3;
148
+ uint8_t ctl1;
149
+ uint8_t ctl2;
150
+ uint8_t ctl3;
151
+ uint8_t ctl4;
152
+ uint8_t ctl5;
153
+ uint8_t addr[NPCM7XX_SMBUS_NR_ADDRS];
154
+
155
+ uint8_t scllt;
156
+ uint8_t sclht;
157
+
158
+ NPCM7xxSMBusStatus status;
159
+} NPCM7xxSMBusState;
160
+
161
+#define TYPE_NPCM7XX_SMBUS "npcm7xx-smbus"
162
+#define NPCM7XX_SMBUS(obj) OBJECT_CHECK(NPCM7xxSMBusState, (obj), \
163
+ TYPE_NPCM7XX_SMBUS)
164
+
165
+#endif /* NPCM7XX_SMBUS_H */
166
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
167
index XXXXXXX..XXXXXXX 100644
168
--- a/hw/arm/npcm7xx.c
169
+++ b/hw/arm/npcm7xx.c
170
@@ -XXX,XX +XXX,XX @@ enum NPCM7xxInterrupt {
171
NPCM7XX_WDG2_IRQ, /* Timer Module 2 Watchdog */
172
NPCM7XX_EHCI_IRQ = 61,
173
NPCM7XX_OHCI_IRQ = 62,
174
+ NPCM7XX_SMBUS0_IRQ = 64,
175
+ NPCM7XX_SMBUS1_IRQ,
176
+ NPCM7XX_SMBUS2_IRQ,
177
+ NPCM7XX_SMBUS3_IRQ,
178
+ NPCM7XX_SMBUS4_IRQ,
179
+ NPCM7XX_SMBUS5_IRQ,
180
+ NPCM7XX_SMBUS6_IRQ,
181
+ NPCM7XX_SMBUS7_IRQ,
182
+ NPCM7XX_SMBUS8_IRQ,
183
+ NPCM7XX_SMBUS9_IRQ,
184
+ NPCM7XX_SMBUS10_IRQ,
185
+ NPCM7XX_SMBUS11_IRQ,
186
+ NPCM7XX_SMBUS12_IRQ,
187
+ NPCM7XX_SMBUS13_IRQ,
188
+ NPCM7XX_SMBUS14_IRQ,
189
+ NPCM7XX_SMBUS15_IRQ,
190
NPCM7XX_PWM0_IRQ = 93, /* PWM module 0 */
191
NPCM7XX_PWM1_IRQ, /* PWM module 1 */
192
NPCM7XX_GPIO0_IRQ = 116,
193
@@ -XXX,XX +XXX,XX @@ static const hwaddr npcm7xx_pwm_addr[] = {
194
0xf0104000,
195
};
196
197
+/* Direct memory-mapped access to each SMBus Module. */
198
+static const hwaddr npcm7xx_smbus_addr[] = {
199
+ 0xf0080000,
200
+ 0xf0081000,
201
+ 0xf0082000,
202
+ 0xf0083000,
203
+ 0xf0084000,
204
+ 0xf0085000,
205
+ 0xf0086000,
206
+ 0xf0087000,
207
+ 0xf0088000,
208
+ 0xf0089000,
209
+ 0xf008a000,
210
+ 0xf008b000,
211
+ 0xf008c000,
212
+ 0xf008d000,
213
+ 0xf008e000,
214
+ 0xf008f000,
215
+};
216
+
217
static const struct {
218
hwaddr regs_addr;
219
uint32_t unconnected_pins;
220
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_init(Object *obj)
221
object_initialize_child(obj, "gpio[*]", &s->gpio[i], TYPE_NPCM7XX_GPIO);
222
}
54
}
223
55
224
+ for (i = 0; i < ARRAY_SIZE(s->smbus); i++) {
56
- which = pickNaNMulAdd(a->cls, b->cls, c->cls,
225
+ object_initialize_child(obj, "smbus[*]", &s->smbus[i],
57
- ab_mask == float_cmask_infzero, s);
226
+ TYPE_NPCM7XX_SMBUS);
58
+ if (infzero) {
59
+ /* This is (0 * inf) + NaN or (inf * 0) + NaN */
60
+ float_raise(float_flag_invalid | float_flag_invalid_imz, s);
227
+ }
61
+ }
228
+
62
+
229
object_initialize_child(obj, "ehci", &s->ehci, TYPE_NPCM7XX_EHCI);
63
+ which = pickNaNMulAdd(a->cls, b->cls, c->cls, infzero, s);
230
object_initialize_child(obj, "ohci", &s->ohci, TYPE_SYSBUS_OHCI);
64
231
65
if (s->default_nan_mode || which == 3) {
232
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
66
- /*
233
npcm7xx_irq(s, NPCM7XX_GPIO0_IRQ + i));
67
- * Note that this check is after pickNaNMulAdd so that function
68
- * has an opportunity to set the Invalid flag for infzero.
69
- */
70
parts_default_nan(a, s);
71
return a;
234
}
72
}
235
73
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
236
+ /* SMBus modules. Cannot fail. */
74
index XXXXXXX..XXXXXXX 100644
237
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_smbus_addr) != ARRAY_SIZE(s->smbus));
75
--- a/fpu/softfloat-specialize.c.inc
238
+ for (i = 0; i < ARRAY_SIZE(s->smbus); i++) {
76
+++ b/fpu/softfloat-specialize.c.inc
239
+ Object *obj = OBJECT(&s->smbus[i]);
77
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
78
* the default NaN
79
*/
80
if (infzero && is_qnan(c_cls)) {
81
- float_raise(float_flag_invalid | float_flag_invalid_imz, status);
82
return 3;
83
}
84
85
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
86
* case sets InvalidOp and returns the default NaN
87
*/
88
if (infzero) {
89
- float_raise(float_flag_invalid | float_flag_invalid_imz, status);
90
return 3;
91
}
92
/* Prefer sNaN over qNaN, in the a, b, c order. */
93
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
94
* For MIPS systems that conform to IEEE754-2008, the (inf,zero,nan)
95
* case sets InvalidOp and returns the input value 'c'
96
*/
97
- if (infzero) {
98
- float_raise(float_flag_invalid | float_flag_invalid_imz, status);
99
- return 2;
100
- }
101
/* Prefer sNaN over qNaN, in the c, a, b order. */
102
if (is_snan(c_cls)) {
103
return 2;
104
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
105
* For LoongArch systems that conform to IEEE754-2008, the (inf,zero,nan)
106
* case sets InvalidOp and returns the input value 'c'
107
*/
108
- if (infzero) {
109
- float_raise(float_flag_invalid | float_flag_invalid_imz, status);
110
- return 2;
111
- }
240
+
112
+
241
+ sysbus_realize(SYS_BUS_DEVICE(obj), &error_abort);
113
/* Prefer sNaN over qNaN, in the c, a, b order. */
242
+ sysbus_mmio_map(SYS_BUS_DEVICE(obj), 0, npcm7xx_smbus_addr[i]);
114
if (is_snan(c_cls)) {
243
+ sysbus_connect_irq(SYS_BUS_DEVICE(obj), 0,
115
return 2;
244
+ npcm7xx_irq(s, NPCM7XX_SMBUS0_IRQ + i));
116
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
245
+ }
117
* to return an input NaN if we have one (ie c) rather than generating
246
+
118
* a default NaN
247
/* USB Host */
119
*/
248
object_property_set_bool(OBJECT(&s->ehci), "companion-enable", true,
120
- if (infzero) {
249
&error_abort);
121
- float_raise(float_flag_invalid | float_flag_invalid_imz, status);
250
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
122
- return 2;
251
create_unimplemented_device("npcm7xx.pcierc", 0xe1000000, 64 * KiB);
123
- }
252
create_unimplemented_device("npcm7xx.kcs", 0xf0007000, 4 * KiB);
124
253
create_unimplemented_device("npcm7xx.gfxi", 0xf000e000, 4 * KiB);
125
/* If fRA is a NaN return it; otherwise if fRB is a NaN return it;
254
- create_unimplemented_device("npcm7xx.smbus[0]", 0xf0080000, 4 * KiB);
126
* otherwise return fRC. Note that muladd on PPC is (fRA * fRC) + frB
255
- create_unimplemented_device("npcm7xx.smbus[1]", 0xf0081000, 4 * KiB);
127
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
256
- create_unimplemented_device("npcm7xx.smbus[2]", 0xf0082000, 4 * KiB);
128
return 1;
257
- create_unimplemented_device("npcm7xx.smbus[3]", 0xf0083000, 4 * KiB);
129
}
258
- create_unimplemented_device("npcm7xx.smbus[4]", 0xf0084000, 4 * KiB);
130
#elif defined(TARGET_RISCV)
259
- create_unimplemented_device("npcm7xx.smbus[5]", 0xf0085000, 4 * KiB);
131
- /* For RISC-V, InvalidOp is set when multiplicands are Inf and zero */
260
- create_unimplemented_device("npcm7xx.smbus[6]", 0xf0086000, 4 * KiB);
132
- if (infzero) {
261
- create_unimplemented_device("npcm7xx.smbus[7]", 0xf0087000, 4 * KiB);
133
- float_raise(float_flag_invalid | float_flag_invalid_imz, status);
262
- create_unimplemented_device("npcm7xx.smbus[8]", 0xf0088000, 4 * KiB);
134
- }
263
- create_unimplemented_device("npcm7xx.smbus[9]", 0xf0089000, 4 * KiB);
135
return 3; /* default NaN */
264
- create_unimplemented_device("npcm7xx.smbus[10]", 0xf008a000, 4 * KiB);
136
#elif defined(TARGET_S390X)
265
- create_unimplemented_device("npcm7xx.smbus[11]", 0xf008b000, 4 * KiB);
137
if (infzero) {
266
- create_unimplemented_device("npcm7xx.smbus[12]", 0xf008c000, 4 * KiB);
138
- float_raise(float_flag_invalid | float_flag_invalid_imz, status);
267
- create_unimplemented_device("npcm7xx.smbus[13]", 0xf008d000, 4 * KiB);
139
return 3;
268
- create_unimplemented_device("npcm7xx.smbus[14]", 0xf008e000, 4 * KiB);
140
}
269
- create_unimplemented_device("npcm7xx.smbus[15]", 0xf008f000, 4 * KiB);
141
270
create_unimplemented_device("npcm7xx.espi", 0xf009f000, 4 * KiB);
142
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
271
create_unimplemented_device("npcm7xx.peci", 0xf0100000, 4 * KiB);
143
return 2;
272
create_unimplemented_device("npcm7xx.siox[1]", 0xf0101000, 4 * KiB);
144
}
273
diff --git a/hw/i2c/npcm7xx_smbus.c b/hw/i2c/npcm7xx_smbus.c
145
#elif defined(TARGET_SPARC)
274
new file mode 100644
146
- /* For (inf,0,nan) return c. */
275
index XXXXXXX..XXXXXXX
147
- if (infzero) {
276
--- /dev/null
148
- float_raise(float_flag_invalid | float_flag_invalid_imz, status);
277
+++ b/hw/i2c/npcm7xx_smbus.c
149
- return 2;
278
@@ -XXX,XX +XXX,XX @@
150
- }
279
+/*
151
/* Prefer SNaN over QNaN, order C, B, A. */
280
+ * Nuvoton NPCM7xx SMBus Module.
152
if (is_snan(c_cls)) {
281
+ *
153
return 2;
282
+ * Copyright 2020 Google LLC
154
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
283
+ *
155
* For Xtensa, the (inf,zero,nan) case sets InvalidOp and returns
284
+ * This program is free software; you can redistribute it and/or modify it
156
* an input NaN if we have one (ie c).
285
+ * under the terms of the GNU General Public License as published by the
157
*/
286
+ * Free Software Foundation; either version 2 of the License, or
158
- if (infzero) {
287
+ * (at your option) any later version.
159
- float_raise(float_flag_invalid | float_flag_invalid_imz, status);
288
+ *
160
- return 2;
289
+ * This program is distributed in the hope that it will be useful, but WITHOUT
161
- }
290
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
162
if (status->use_first_nan) {
291
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
163
if (is_nan(a_cls)) {
292
+ * for more details.
164
return 0;
293
+ */
294
+
295
+#include "qemu/osdep.h"
296
+
297
+#include "hw/i2c/npcm7xx_smbus.h"
298
+#include "migration/vmstate.h"
299
+#include "qemu/bitops.h"
300
+#include "qemu/guest-random.h"
301
+#include "qemu/log.h"
302
+#include "qemu/module.h"
303
+#include "qemu/units.h"
304
+
305
+#include "trace.h"
306
+
307
+enum NPCM7xxSMBusCommonRegister {
308
+ NPCM7XX_SMB_SDA = 0x0,
309
+ NPCM7XX_SMB_ST = 0x2,
310
+ NPCM7XX_SMB_CST = 0x4,
311
+ NPCM7XX_SMB_CTL1 = 0x6,
312
+ NPCM7XX_SMB_ADDR1 = 0x8,
313
+ NPCM7XX_SMB_CTL2 = 0xa,
314
+ NPCM7XX_SMB_ADDR2 = 0xc,
315
+ NPCM7XX_SMB_CTL3 = 0xe,
316
+ NPCM7XX_SMB_CST2 = 0x18,
317
+ NPCM7XX_SMB_CST3 = 0x19,
318
+ NPCM7XX_SMB_VER = 0x1f,
319
+};
320
+
321
+enum NPCM7xxSMBusBank0Register {
322
+ NPCM7XX_SMB_ADDR3 = 0x10,
323
+ NPCM7XX_SMB_ADDR7 = 0x11,
324
+ NPCM7XX_SMB_ADDR4 = 0x12,
325
+ NPCM7XX_SMB_ADDR8 = 0x13,
326
+ NPCM7XX_SMB_ADDR5 = 0x14,
327
+ NPCM7XX_SMB_ADDR9 = 0x15,
328
+ NPCM7XX_SMB_ADDR6 = 0x16,
329
+ NPCM7XX_SMB_ADDR10 = 0x17,
330
+ NPCM7XX_SMB_CTL4 = 0x1a,
331
+ NPCM7XX_SMB_CTL5 = 0x1b,
332
+ NPCM7XX_SMB_SCLLT = 0x1c,
333
+ NPCM7XX_SMB_FIF_CTL = 0x1d,
334
+ NPCM7XX_SMB_SCLHT = 0x1e,
335
+};
336
+
337
+enum NPCM7xxSMBusBank1Register {
338
+ NPCM7XX_SMB_FIF_CTS = 0x10,
339
+ NPCM7XX_SMB_FAIR_PER = 0x11,
340
+ NPCM7XX_SMB_TXF_CTL = 0x12,
341
+ NPCM7XX_SMB_T_OUT = 0x14,
342
+ NPCM7XX_SMB_TXF_STS = 0x1a,
343
+ NPCM7XX_SMB_RXF_STS = 0x1c,
344
+ NPCM7XX_SMB_RXF_CTL = 0x1e,
345
+};
346
+
347
+/* ST fields */
348
+#define NPCM7XX_SMBST_STP BIT(7)
349
+#define NPCM7XX_SMBST_SDAST BIT(6)
350
+#define NPCM7XX_SMBST_BER BIT(5)
351
+#define NPCM7XX_SMBST_NEGACK BIT(4)
352
+#define NPCM7XX_SMBST_STASTR BIT(3)
353
+#define NPCM7XX_SMBST_NMATCH BIT(2)
354
+#define NPCM7XX_SMBST_MODE BIT(1)
355
+#define NPCM7XX_SMBST_XMIT BIT(0)
356
+
357
+/* CST fields */
358
+#define NPCM7XX_SMBCST_ARPMATCH BIT(7)
359
+#define NPCM7XX_SMBCST_MATCHAF BIT(6)
360
+#define NPCM7XX_SMBCST_TGSCL BIT(5)
361
+#define NPCM7XX_SMBCST_TSDA BIT(4)
362
+#define NPCM7XX_SMBCST_GCMATCH BIT(3)
363
+#define NPCM7XX_SMBCST_MATCH BIT(2)
364
+#define NPCM7XX_SMBCST_BB BIT(1)
365
+#define NPCM7XX_SMBCST_BUSY BIT(0)
366
+
367
+/* CST2 fields */
368
+#define NPCM7XX_SMBCST2_INTSTS BIT(7)
369
+#define NPCM7XX_SMBCST2_MATCH7F BIT(6)
370
+#define NPCM7XX_SMBCST2_MATCH6F BIT(5)
371
+#define NPCM7XX_SMBCST2_MATCH5F BIT(4)
372
+#define NPCM7XX_SMBCST2_MATCH4F BIT(3)
373
+#define NPCM7XX_SMBCST2_MATCH3F BIT(2)
374
+#define NPCM7XX_SMBCST2_MATCH2F BIT(1)
375
+#define NPCM7XX_SMBCST2_MATCH1F BIT(0)
376
+
377
+/* CST3 fields */
378
+#define NPCM7XX_SMBCST3_EO_BUSY BIT(7)
379
+#define NPCM7XX_SMBCST3_MATCH10F BIT(2)
380
+#define NPCM7XX_SMBCST3_MATCH9F BIT(1)
381
+#define NPCM7XX_SMBCST3_MATCH8F BIT(0)
382
+
383
+/* CTL1 fields */
384
+#define NPCM7XX_SMBCTL1_STASTRE BIT(7)
385
+#define NPCM7XX_SMBCTL1_NMINTE BIT(6)
386
+#define NPCM7XX_SMBCTL1_GCMEN BIT(5)
387
+#define NPCM7XX_SMBCTL1_ACK BIT(4)
388
+#define NPCM7XX_SMBCTL1_EOBINTE BIT(3)
389
+#define NPCM7XX_SMBCTL1_INTEN BIT(2)
390
+#define NPCM7XX_SMBCTL1_STOP BIT(1)
391
+#define NPCM7XX_SMBCTL1_START BIT(0)
392
+
393
+/* CTL2 fields */
394
+#define NPCM7XX_SMBCTL2_SCLFRQ(rv) extract8((rv), 1, 6)
395
+#define NPCM7XX_SMBCTL2_ENABLE BIT(0)
396
+
397
+/* CTL3 fields */
398
+#define NPCM7XX_SMBCTL3_SCL_LVL BIT(7)
399
+#define NPCM7XX_SMBCTL3_SDA_LVL BIT(6)
400
+#define NPCM7XX_SMBCTL3_BNK_SEL BIT(5)
401
+#define NPCM7XX_SMBCTL3_400K_MODE BIT(4)
402
+#define NPCM7XX_SMBCTL3_IDL_START BIT(3)
403
+#define NPCM7XX_SMBCTL3_ARPMEN BIT(2)
404
+#define NPCM7XX_SMBCTL3_SCLFRQ(rv) extract8((rv), 0, 2)
405
+
406
+/* ADDR fields */
407
+#define NPCM7XX_ADDR_EN BIT(7)
408
+#define NPCM7XX_ADDR_A(rv) extract8((rv), 0, 6)
409
+
410
+#define KEEP_OLD_BIT(o, n, b) (((n) & (~(b))) | ((o) & (b)))
411
+#define WRITE_ONE_CLEAR(o, n, b) ((n) & (b) ? (o) & (~(b)) : (o))
412
+
413
+#define NPCM7XX_SMBUS_ENABLED(s) ((s)->ctl2 & NPCM7XX_SMBCTL2_ENABLE)
414
+
415
+/* VERSION fields values, read-only. */
416
+#define NPCM7XX_SMBUS_VERSION_NUMBER 1
417
+#define NPCM7XX_SMBUS_VERSION_FIFO_SUPPORTED 0
418
+
419
+/* Reset values */
420
+#define NPCM7XX_SMB_ST_INIT_VAL 0x00
421
+#define NPCM7XX_SMB_CST_INIT_VAL 0x10
422
+#define NPCM7XX_SMB_CST2_INIT_VAL 0x00
423
+#define NPCM7XX_SMB_CST3_INIT_VAL 0x00
424
+#define NPCM7XX_SMB_CTL1_INIT_VAL 0x00
425
+#define NPCM7XX_SMB_CTL2_INIT_VAL 0x00
426
+#define NPCM7XX_SMB_CTL3_INIT_VAL 0xc0
427
+#define NPCM7XX_SMB_CTL4_INIT_VAL 0x07
428
+#define NPCM7XX_SMB_CTL5_INIT_VAL 0x00
429
+#define NPCM7XX_SMB_ADDR_INIT_VAL 0x00
430
+#define NPCM7XX_SMB_SCLLT_INIT_VAL 0x00
431
+#define NPCM7XX_SMB_SCLHT_INIT_VAL 0x00
432
+
433
+static uint8_t npcm7xx_smbus_get_version(void)
434
+{
435
+ return NPCM7XX_SMBUS_VERSION_FIFO_SUPPORTED << 7 |
436
+ NPCM7XX_SMBUS_VERSION_NUMBER;
437
+}
438
+
439
+static void npcm7xx_smbus_update_irq(NPCM7xxSMBusState *s)
440
+{
441
+ int level;
442
+
443
+ if (s->ctl1 & NPCM7XX_SMBCTL1_INTEN) {
444
+ level = !!((s->ctl1 & NPCM7XX_SMBCTL1_NMINTE &&
445
+ s->st & NPCM7XX_SMBST_NMATCH) ||
446
+ (s->st & NPCM7XX_SMBST_BER) ||
447
+ (s->st & NPCM7XX_SMBST_NEGACK) ||
448
+ (s->st & NPCM7XX_SMBST_SDAST) ||
449
+ (s->ctl1 & NPCM7XX_SMBCTL1_STASTRE &&
450
+ s->st & NPCM7XX_SMBST_SDAST) ||
451
+ (s->ctl1 & NPCM7XX_SMBCTL1_EOBINTE &&
452
+ s->cst3 & NPCM7XX_SMBCST3_EO_BUSY));
453
+
454
+ if (level) {
455
+ s->cst2 |= NPCM7XX_SMBCST2_INTSTS;
456
+ } else {
457
+ s->cst2 &= ~NPCM7XX_SMBCST2_INTSTS;
458
+ }
459
+ qemu_set_irq(s->irq, level);
460
+ }
461
+}
462
+
463
+static void npcm7xx_smbus_nack(NPCM7xxSMBusState *s)
464
+{
465
+ s->st &= ~NPCM7XX_SMBST_SDAST;
466
+ s->st |= NPCM7XX_SMBST_NEGACK;
467
+ s->status = NPCM7XX_SMBUS_STATUS_NEGACK;
468
+}
469
+
470
+static void npcm7xx_smbus_send_byte(NPCM7xxSMBusState *s, uint8_t value)
471
+{
472
+ int rv = i2c_send(s->bus, value);
473
+
474
+ if (rv) {
475
+ npcm7xx_smbus_nack(s);
476
+ } else {
477
+ s->st |= NPCM7XX_SMBST_SDAST;
478
+ }
479
+ trace_npcm7xx_smbus_send_byte((DEVICE(s)->canonical_path), value, !rv);
480
+ npcm7xx_smbus_update_irq(s);
481
+}
482
+
483
+static void npcm7xx_smbus_recv_byte(NPCM7xxSMBusState *s)
484
+{
485
+ s->sda = i2c_recv(s->bus);
486
+ s->st |= NPCM7XX_SMBST_SDAST;
487
+ if (s->st & NPCM7XX_SMBCTL1_ACK) {
488
+ trace_npcm7xx_smbus_nack(DEVICE(s)->canonical_path);
489
+ i2c_nack(s->bus);
490
+ s->st &= NPCM7XX_SMBCTL1_ACK;
491
+ }
492
+ trace_npcm7xx_smbus_recv_byte((DEVICE(s)->canonical_path), s->sda);
493
+ npcm7xx_smbus_update_irq(s);
494
+}
495
+
496
+static void npcm7xx_smbus_start(NPCM7xxSMBusState *s)
497
+{
498
+ /*
499
+ * We can start the bus if one of these is true:
500
+ * 1. The bus is idle (so we can request it)
501
+ * 2. We are the occupier (it's a repeated start condition.)
502
+ */
503
+ int available = !i2c_bus_busy(s->bus) ||
504
+ s->status != NPCM7XX_SMBUS_STATUS_IDLE;
505
+
506
+ if (available) {
507
+ s->st |= NPCM7XX_SMBST_MODE | NPCM7XX_SMBST_XMIT | NPCM7XX_SMBST_SDAST;
508
+ s->cst |= NPCM7XX_SMBCST_BUSY;
509
+ } else {
510
+ s->st &= ~NPCM7XX_SMBST_MODE;
511
+ s->cst &= ~NPCM7XX_SMBCST_BUSY;
512
+ s->st |= NPCM7XX_SMBST_BER;
513
+ }
514
+
515
+ trace_npcm7xx_smbus_start(DEVICE(s)->canonical_path, available);
516
+ s->cst |= NPCM7XX_SMBCST_BB;
517
+ s->status = NPCM7XX_SMBUS_STATUS_IDLE;
518
+ npcm7xx_smbus_update_irq(s);
519
+}
520
+
521
+static void npcm7xx_smbus_send_address(NPCM7xxSMBusState *s, uint8_t value)
522
+{
523
+ int recv;
524
+ int rv;
525
+
526
+ recv = value & BIT(0);
527
+ rv = i2c_start_transfer(s->bus, value >> 1, recv);
528
+ trace_npcm7xx_smbus_send_address(DEVICE(s)->canonical_path,
529
+ value >> 1, recv, !rv);
530
+ if (rv) {
531
+ qemu_log_mask(LOG_GUEST_ERROR,
532
+ "%s: requesting i2c bus for 0x%02x failed: %d\n",
533
+ DEVICE(s)->canonical_path, value, rv);
534
+ /* Failed to start transfer. NACK to reject.*/
535
+ if (recv) {
536
+ s->st &= ~NPCM7XX_SMBST_XMIT;
537
+ } else {
538
+ s->st |= NPCM7XX_SMBST_XMIT;
539
+ }
540
+ npcm7xx_smbus_nack(s);
541
+ npcm7xx_smbus_update_irq(s);
542
+ return;
543
+ }
544
+
545
+ s->st &= ~NPCM7XX_SMBST_NEGACK;
546
+ if (recv) {
547
+ s->status = NPCM7XX_SMBUS_STATUS_RECEIVING;
548
+ s->st &= ~NPCM7XX_SMBST_XMIT;
549
+ } else {
550
+ s->status = NPCM7XX_SMBUS_STATUS_SENDING;
551
+ s->st |= NPCM7XX_SMBST_XMIT;
552
+ }
553
+
554
+ if (s->ctl1 & NPCM7XX_SMBCTL1_STASTRE) {
555
+ s->st |= NPCM7XX_SMBST_STASTR;
556
+ if (!recv) {
557
+ s->st |= NPCM7XX_SMBST_SDAST;
558
+ }
559
+ } else if (recv) {
560
+ npcm7xx_smbus_recv_byte(s);
561
+ }
562
+ npcm7xx_smbus_update_irq(s);
563
+}
564
+
565
+static void npcm7xx_smbus_execute_stop(NPCM7xxSMBusState *s)
566
+{
567
+ i2c_end_transfer(s->bus);
568
+ s->st = 0;
569
+ s->cst = 0;
570
+ s->status = NPCM7XX_SMBUS_STATUS_IDLE;
571
+ s->cst3 |= NPCM7XX_SMBCST3_EO_BUSY;
572
+ trace_npcm7xx_smbus_stop(DEVICE(s)->canonical_path);
573
+ npcm7xx_smbus_update_irq(s);
574
+}
575
+
576
+
577
+static void npcm7xx_smbus_stop(NPCM7xxSMBusState *s)
578
+{
579
+ if (s->st & NPCM7XX_SMBST_MODE) {
580
+ switch (s->status) {
581
+ case NPCM7XX_SMBUS_STATUS_RECEIVING:
582
+ case NPCM7XX_SMBUS_STATUS_STOPPING_LAST_RECEIVE:
583
+ s->status = NPCM7XX_SMBUS_STATUS_STOPPING_LAST_RECEIVE;
584
+ break;
585
+
586
+ case NPCM7XX_SMBUS_STATUS_NEGACK:
587
+ s->status = NPCM7XX_SMBUS_STATUS_STOPPING_NEGACK;
588
+ break;
589
+
590
+ default:
591
+ npcm7xx_smbus_execute_stop(s);
592
+ break;
593
+ }
594
+ }
595
+}
596
+
597
+static uint8_t npcm7xx_smbus_read_sda(NPCM7xxSMBusState *s)
598
+{
599
+ uint8_t value = s->sda;
600
+
601
+ switch (s->status) {
602
+ case NPCM7XX_SMBUS_STATUS_STOPPING_LAST_RECEIVE:
603
+ npcm7xx_smbus_execute_stop(s);
604
+ break;
605
+
606
+ case NPCM7XX_SMBUS_STATUS_RECEIVING:
607
+ npcm7xx_smbus_recv_byte(s);
608
+ break;
609
+
610
+ default:
611
+ /* Do nothing */
612
+ break;
613
+ }
614
+
615
+ return value;
616
+}
617
+
618
+static void npcm7xx_smbus_write_sda(NPCM7xxSMBusState *s, uint8_t value)
619
+{
620
+ s->sda = value;
621
+ if (s->st & NPCM7XX_SMBST_MODE) {
622
+ switch (s->status) {
623
+ case NPCM7XX_SMBUS_STATUS_IDLE:
624
+ npcm7xx_smbus_send_address(s, value);
625
+ break;
626
+ case NPCM7XX_SMBUS_STATUS_SENDING:
627
+ npcm7xx_smbus_send_byte(s, value);
628
+ break;
629
+ default:
630
+ qemu_log_mask(LOG_GUEST_ERROR,
631
+ "%s: write to SDA in invalid status %d: %u\n",
632
+ DEVICE(s)->canonical_path, s->status, value);
633
+ break;
634
+ }
635
+ }
636
+}
637
+
638
+static void npcm7xx_smbus_write_st(NPCM7xxSMBusState *s, uint8_t value)
639
+{
640
+ s->st = WRITE_ONE_CLEAR(s->st, value, NPCM7XX_SMBST_STP);
641
+ s->st = WRITE_ONE_CLEAR(s->st, value, NPCM7XX_SMBST_BER);
642
+ s->st = WRITE_ONE_CLEAR(s->st, value, NPCM7XX_SMBST_STASTR);
643
+ s->st = WRITE_ONE_CLEAR(s->st, value, NPCM7XX_SMBST_NMATCH);
644
+
645
+ if (value & NPCM7XX_SMBST_NEGACK) {
646
+ s->st &= ~NPCM7XX_SMBST_NEGACK;
647
+ if (s->status == NPCM7XX_SMBUS_STATUS_STOPPING_NEGACK) {
648
+ npcm7xx_smbus_execute_stop(s);
649
+ }
650
+ }
651
+
652
+ if (value & NPCM7XX_SMBST_STASTR &&
653
+ s->status == NPCM7XX_SMBUS_STATUS_RECEIVING) {
654
+ npcm7xx_smbus_recv_byte(s);
655
+ }
656
+
657
+ npcm7xx_smbus_update_irq(s);
658
+}
659
+
660
+static void npcm7xx_smbus_write_cst(NPCM7xxSMBusState *s, uint8_t value)
661
+{
662
+ uint8_t new_value = s->cst;
663
+
664
+ s->cst = WRITE_ONE_CLEAR(new_value, value, NPCM7XX_SMBCST_BB);
665
+ npcm7xx_smbus_update_irq(s);
666
+}
667
+
668
+static void npcm7xx_smbus_write_cst3(NPCM7xxSMBusState *s, uint8_t value)
669
+{
670
+ s->cst3 = WRITE_ONE_CLEAR(s->cst3, value, NPCM7XX_SMBCST3_EO_BUSY);
671
+ npcm7xx_smbus_update_irq(s);
672
+}
673
+
674
+static void npcm7xx_smbus_write_ctl1(NPCM7xxSMBusState *s, uint8_t value)
675
+{
676
+ s->ctl1 = KEEP_OLD_BIT(s->ctl1, value,
677
+ NPCM7XX_SMBCTL1_START | NPCM7XX_SMBCTL1_STOP | NPCM7XX_SMBCTL1_ACK);
678
+
679
+ if (value & NPCM7XX_SMBCTL1_START) {
680
+ npcm7xx_smbus_start(s);
681
+ }
682
+
683
+ if (value & NPCM7XX_SMBCTL1_STOP) {
684
+ npcm7xx_smbus_stop(s);
685
+ }
686
+
687
+ npcm7xx_smbus_update_irq(s);
688
+}
689
+
690
+static void npcm7xx_smbus_write_ctl2(NPCM7xxSMBusState *s, uint8_t value)
691
+{
692
+ s->ctl2 = value;
693
+
694
+ if (!NPCM7XX_SMBUS_ENABLED(s)) {
695
+ /* Disable this SMBus module. */
696
+ s->ctl1 = 0;
697
+ s->st = 0;
698
+ s->cst3 = s->cst3 & (~NPCM7XX_SMBCST3_EO_BUSY);
699
+ s->cst = 0;
700
+ }
701
+}
702
+
703
+static void npcm7xx_smbus_write_ctl3(NPCM7xxSMBusState *s, uint8_t value)
704
+{
705
+ uint8_t old_ctl3 = s->ctl3;
706
+
707
+ /* Write to SDA and SCL bits are ignored. */
708
+ s->ctl3 = KEEP_OLD_BIT(old_ctl3, value,
709
+ NPCM7XX_SMBCTL3_SCL_LVL | NPCM7XX_SMBCTL3_SDA_LVL);
710
+}
711
+
712
+static uint64_t npcm7xx_smbus_read(void *opaque, hwaddr offset, unsigned size)
713
+{
714
+ NPCM7xxSMBusState *s = opaque;
715
+ uint64_t value = 0;
716
+ uint8_t bank = s->ctl3 & NPCM7XX_SMBCTL3_BNK_SEL;
717
+
718
+ /* The order of the registers are their order in memory. */
719
+ switch (offset) {
720
+ case NPCM7XX_SMB_SDA:
721
+ value = npcm7xx_smbus_read_sda(s);
722
+ break;
723
+
724
+ case NPCM7XX_SMB_ST:
725
+ value = s->st;
726
+ break;
727
+
728
+ case NPCM7XX_SMB_CST:
729
+ value = s->cst;
730
+ break;
731
+
732
+ case NPCM7XX_SMB_CTL1:
733
+ value = s->ctl1;
734
+ break;
735
+
736
+ case NPCM7XX_SMB_ADDR1:
737
+ value = s->addr[0];
738
+ break;
739
+
740
+ case NPCM7XX_SMB_CTL2:
741
+ value = s->ctl2;
742
+ break;
743
+
744
+ case NPCM7XX_SMB_ADDR2:
745
+ value = s->addr[1];
746
+ break;
747
+
748
+ case NPCM7XX_SMB_CTL3:
749
+ value = s->ctl3;
750
+ break;
751
+
752
+ case NPCM7XX_SMB_CST2:
753
+ value = s->cst2;
754
+ break;
755
+
756
+ case NPCM7XX_SMB_CST3:
757
+ value = s->cst3;
758
+ break;
759
+
760
+ case NPCM7XX_SMB_VER:
761
+ value = npcm7xx_smbus_get_version();
762
+ break;
763
+
764
+ /* This register is either invalid or banked at this point. */
765
+ default:
766
+ if (bank) {
767
+ /* Bank 1 */
768
+ qemu_log_mask(LOG_GUEST_ERROR,
769
+ "%s: read from invalid offset 0x%" HWADDR_PRIx "\n",
770
+ DEVICE(s)->canonical_path, offset);
771
+ } else {
772
+ /* Bank 0 */
773
+ switch (offset) {
774
+ case NPCM7XX_SMB_ADDR3:
775
+ value = s->addr[2];
776
+ break;
777
+
778
+ case NPCM7XX_SMB_ADDR7:
779
+ value = s->addr[6];
780
+ break;
781
+
782
+ case NPCM7XX_SMB_ADDR4:
783
+ value = s->addr[3];
784
+ break;
785
+
786
+ case NPCM7XX_SMB_ADDR8:
787
+ value = s->addr[7];
788
+ break;
789
+
790
+ case NPCM7XX_SMB_ADDR5:
791
+ value = s->addr[4];
792
+ break;
793
+
794
+ case NPCM7XX_SMB_ADDR9:
795
+ value = s->addr[8];
796
+ break;
797
+
798
+ case NPCM7XX_SMB_ADDR6:
799
+ value = s->addr[5];
800
+ break;
801
+
802
+ case NPCM7XX_SMB_ADDR10:
803
+ value = s->addr[9];
804
+ break;
805
+
806
+ case NPCM7XX_SMB_CTL4:
807
+ value = s->ctl4;
808
+ break;
809
+
810
+ case NPCM7XX_SMB_CTL5:
811
+ value = s->ctl5;
812
+ break;
813
+
814
+ case NPCM7XX_SMB_SCLLT:
815
+ value = s->scllt;
816
+ break;
817
+
818
+ case NPCM7XX_SMB_SCLHT:
819
+ value = s->sclht;
820
+ break;
821
+
822
+ default:
823
+ qemu_log_mask(LOG_GUEST_ERROR,
824
+ "%s: read from invalid offset 0x%" HWADDR_PRIx "\n",
825
+ DEVICE(s)->canonical_path, offset);
826
+ break;
827
+ }
828
+ }
829
+ break;
830
+ }
831
+
832
+ trace_npcm7xx_smbus_read(DEVICE(s)->canonical_path, offset, value, size);
833
+
834
+ return value;
835
+}
836
+
837
+static void npcm7xx_smbus_write(void *opaque, hwaddr offset, uint64_t value,
838
+ unsigned size)
839
+{
840
+ NPCM7xxSMBusState *s = opaque;
841
+ uint8_t bank = s->ctl3 & NPCM7XX_SMBCTL3_BNK_SEL;
842
+
843
+ trace_npcm7xx_smbus_write(DEVICE(s)->canonical_path, offset, value, size);
844
+
845
+ /* The order of the registers are their order in memory. */
846
+ switch (offset) {
847
+ case NPCM7XX_SMB_SDA:
848
+ npcm7xx_smbus_write_sda(s, value);
849
+ break;
850
+
851
+ case NPCM7XX_SMB_ST:
852
+ npcm7xx_smbus_write_st(s, value);
853
+ break;
854
+
855
+ case NPCM7XX_SMB_CST:
856
+ npcm7xx_smbus_write_cst(s, value);
857
+ break;
858
+
859
+ case NPCM7XX_SMB_CTL1:
860
+ npcm7xx_smbus_write_ctl1(s, value);
861
+ break;
862
+
863
+ case NPCM7XX_SMB_ADDR1:
864
+ s->addr[0] = value;
865
+ break;
866
+
867
+ case NPCM7XX_SMB_CTL2:
868
+ npcm7xx_smbus_write_ctl2(s, value);
869
+ break;
870
+
871
+ case NPCM7XX_SMB_ADDR2:
872
+ s->addr[1] = value;
873
+ break;
874
+
875
+ case NPCM7XX_SMB_CTL3:
876
+ npcm7xx_smbus_write_ctl3(s, value);
877
+ break;
878
+
879
+ case NPCM7XX_SMB_CST2:
880
+ qemu_log_mask(LOG_GUEST_ERROR,
881
+ "%s: write to read-only reg: offset 0x%" HWADDR_PRIx "\n",
882
+ DEVICE(s)->canonical_path, offset);
883
+ break;
884
+
885
+ case NPCM7XX_SMB_CST3:
886
+ npcm7xx_smbus_write_cst3(s, value);
887
+ break;
888
+
889
+ case NPCM7XX_SMB_VER:
890
+ qemu_log_mask(LOG_GUEST_ERROR,
891
+ "%s: write to read-only reg: offset 0x%" HWADDR_PRIx "\n",
892
+ DEVICE(s)->canonical_path, offset);
893
+ break;
894
+
895
+ /* This register is either invalid or banked at this point. */
896
+ default:
897
+ if (bank) {
898
+ /* Bank 1 */
899
+ qemu_log_mask(LOG_GUEST_ERROR,
900
+ "%s: write to invalid offset 0x%" HWADDR_PRIx "\n",
901
+ DEVICE(s)->canonical_path, offset);
902
+ } else {
903
+ /* Bank 0 */
904
+ switch (offset) {
905
+ case NPCM7XX_SMB_ADDR3:
906
+ s->addr[2] = value;
907
+ break;
908
+
909
+ case NPCM7XX_SMB_ADDR7:
910
+ s->addr[6] = value;
911
+ break;
912
+
913
+ case NPCM7XX_SMB_ADDR4:
914
+ s->addr[3] = value;
915
+ break;
916
+
917
+ case NPCM7XX_SMB_ADDR8:
918
+ s->addr[7] = value;
919
+ break;
920
+
921
+ case NPCM7XX_SMB_ADDR5:
922
+ s->addr[4] = value;
923
+ break;
924
+
925
+ case NPCM7XX_SMB_ADDR9:
926
+ s->addr[8] = value;
927
+ break;
928
+
929
+ case NPCM7XX_SMB_ADDR6:
930
+ s->addr[5] = value;
931
+ break;
932
+
933
+ case NPCM7XX_SMB_ADDR10:
934
+ s->addr[9] = value;
935
+ break;
936
+
937
+ case NPCM7XX_SMB_CTL4:
938
+ s->ctl4 = value;
939
+ break;
940
+
941
+ case NPCM7XX_SMB_CTL5:
942
+ s->ctl5 = value;
943
+ break;
944
+
945
+ case NPCM7XX_SMB_SCLLT:
946
+ s->scllt = value;
947
+ break;
948
+
949
+ case NPCM7XX_SMB_SCLHT:
950
+ s->sclht = value;
951
+ break;
952
+
953
+ default:
954
+ qemu_log_mask(LOG_GUEST_ERROR,
955
+ "%s: write to invalid offset 0x%" HWADDR_PRIx "\n",
956
+ DEVICE(s)->canonical_path, offset);
957
+ break;
958
+ }
959
+ }
960
+ break;
961
+ }
962
+}
963
+
964
+static const MemoryRegionOps npcm7xx_smbus_ops = {
965
+ .read = npcm7xx_smbus_read,
966
+ .write = npcm7xx_smbus_write,
967
+ .endianness = DEVICE_LITTLE_ENDIAN,
968
+ .valid = {
969
+ .min_access_size = 1,
970
+ .max_access_size = 1,
971
+ .unaligned = false,
972
+ },
973
+};
974
+
975
+static void npcm7xx_smbus_enter_reset(Object *obj, ResetType type)
976
+{
977
+ NPCM7xxSMBusState *s = NPCM7XX_SMBUS(obj);
978
+
979
+ s->st = NPCM7XX_SMB_ST_INIT_VAL;
980
+ s->cst = NPCM7XX_SMB_CST_INIT_VAL;
981
+ s->cst2 = NPCM7XX_SMB_CST2_INIT_VAL;
982
+ s->cst3 = NPCM7XX_SMB_CST3_INIT_VAL;
983
+ s->ctl1 = NPCM7XX_SMB_CTL1_INIT_VAL;
984
+ s->ctl2 = NPCM7XX_SMB_CTL2_INIT_VAL;
985
+ s->ctl3 = NPCM7XX_SMB_CTL3_INIT_VAL;
986
+ s->ctl4 = NPCM7XX_SMB_CTL4_INIT_VAL;
987
+ s->ctl5 = NPCM7XX_SMB_CTL5_INIT_VAL;
988
+
989
+ for (int i = 0; i < NPCM7XX_SMBUS_NR_ADDRS; ++i) {
990
+ s->addr[i] = NPCM7XX_SMB_ADDR_INIT_VAL;
991
+ }
992
+ s->scllt = NPCM7XX_SMB_SCLLT_INIT_VAL;
993
+ s->sclht = NPCM7XX_SMB_SCLHT_INIT_VAL;
994
+
995
+ s->status = NPCM7XX_SMBUS_STATUS_IDLE;
996
+}
997
+
998
+static void npcm7xx_smbus_hold_reset(Object *obj)
999
+{
1000
+ NPCM7xxSMBusState *s = NPCM7XX_SMBUS(obj);
1001
+
1002
+ qemu_irq_lower(s->irq);
1003
+}
1004
+
1005
+static void npcm7xx_smbus_init(Object *obj)
1006
+{
1007
+ NPCM7xxSMBusState *s = NPCM7XX_SMBUS(obj);
1008
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
1009
+
1010
+ sysbus_init_irq(sbd, &s->irq);
1011
+ memory_region_init_io(&s->iomem, obj, &npcm7xx_smbus_ops, s,
1012
+ "regs", 4 * KiB);
1013
+ sysbus_init_mmio(sbd, &s->iomem);
1014
+
1015
+ s->bus = i2c_init_bus(DEVICE(s), "i2c-bus");
1016
+ s->status = NPCM7XX_SMBUS_STATUS_IDLE;
1017
+}
1018
+
1019
+static const VMStateDescription vmstate_npcm7xx_smbus = {
1020
+ .name = "npcm7xx-smbus",
1021
+ .version_id = 0,
1022
+ .minimum_version_id = 0,
1023
+ .fields = (VMStateField[]) {
1024
+ VMSTATE_UINT8(sda, NPCM7xxSMBusState),
1025
+ VMSTATE_UINT8(st, NPCM7xxSMBusState),
1026
+ VMSTATE_UINT8(cst, NPCM7xxSMBusState),
1027
+ VMSTATE_UINT8(cst2, NPCM7xxSMBusState),
1028
+ VMSTATE_UINT8(cst3, NPCM7xxSMBusState),
1029
+ VMSTATE_UINT8(ctl1, NPCM7xxSMBusState),
1030
+ VMSTATE_UINT8(ctl2, NPCM7xxSMBusState),
1031
+ VMSTATE_UINT8(ctl3, NPCM7xxSMBusState),
1032
+ VMSTATE_UINT8(ctl4, NPCM7xxSMBusState),
1033
+ VMSTATE_UINT8(ctl5, NPCM7xxSMBusState),
1034
+ VMSTATE_UINT8_ARRAY(addr, NPCM7xxSMBusState, NPCM7XX_SMBUS_NR_ADDRS),
1035
+ VMSTATE_UINT8(scllt, NPCM7xxSMBusState),
1036
+ VMSTATE_UINT8(sclht, NPCM7xxSMBusState),
1037
+ VMSTATE_END_OF_LIST(),
1038
+ },
1039
+};
1040
+
1041
+static void npcm7xx_smbus_class_init(ObjectClass *klass, void *data)
1042
+{
1043
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
1044
+ DeviceClass *dc = DEVICE_CLASS(klass);
1045
+
1046
+ dc->desc = "NPCM7xx System Management Bus";
1047
+ dc->vmsd = &vmstate_npcm7xx_smbus;
1048
+ rc->phases.enter = npcm7xx_smbus_enter_reset;
1049
+ rc->phases.hold = npcm7xx_smbus_hold_reset;
1050
+}
1051
+
1052
+static const TypeInfo npcm7xx_smbus_types[] = {
1053
+ {
1054
+ .name = TYPE_NPCM7XX_SMBUS,
1055
+ .parent = TYPE_SYS_BUS_DEVICE,
1056
+ .instance_size = sizeof(NPCM7xxSMBusState),
1057
+ .class_init = npcm7xx_smbus_class_init,
1058
+ .instance_init = npcm7xx_smbus_init,
1059
+ },
1060
+};
1061
+DEFINE_TYPES(npcm7xx_smbus_types);
1062
diff --git a/hw/i2c/meson.build b/hw/i2c/meson.build
1063
index XXXXXXX..XXXXXXX 100644
1064
--- a/hw/i2c/meson.build
1065
+++ b/hw/i2c/meson.build
1066
@@ -XXX,XX +XXX,XX @@ i2c_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_i2c.c'))
1067
i2c_ss.add(when: 'CONFIG_IMX_I2C', if_true: files('imx_i2c.c'))
1068
i2c_ss.add(when: 'CONFIG_MPC_I2C', if_true: files('mpc_i2c.c'))
1069
i2c_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('microbit_i2c.c'))
1070
+i2c_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_smbus.c'))
1071
i2c_ss.add(when: 'CONFIG_SMBUS_EEPROM', if_true: files('smbus_eeprom.c'))
1072
i2c_ss.add(when: 'CONFIG_VERSATILE_I2C', if_true: files('versatile_i2c.c'))
1073
i2c_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_i2c.c'))
1074
diff --git a/hw/i2c/trace-events b/hw/i2c/trace-events
1075
index XXXXXXX..XXXXXXX 100644
1076
--- a/hw/i2c/trace-events
1077
+++ b/hw/i2c/trace-events
1078
@@ -XXX,XX +XXX,XX @@ aspeed_i2c_bus_read(uint32_t busid, uint64_t offset, unsigned size, uint64_t val
1079
aspeed_i2c_bus_write(uint32_t busid, uint64_t offset, unsigned size, uint64_t value) "bus[%d]: To 0x%" PRIx64 " of size %u: 0x%" PRIx64
1080
aspeed_i2c_bus_send(const char *mode, int i, int count, uint8_t byte) "%s send %d/%d 0x%02x"
1081
aspeed_i2c_bus_recv(const char *mode, int i, int count, uint8_t byte) "%s recv %d/%d 0x%02x"
1082
+
1083
+# npcm7xx_smbus.c
1084
+
1085
+npcm7xx_smbus_read(const char *id, uint64_t offset, uint64_t value, unsigned size) "%s offset: 0x%04" PRIx64 " value: 0x%02" PRIx64 " size: %u"
1086
+npcm7xx_smbus_write(const char *id, uint64_t offset, uint64_t value, unsigned size) "%s offset: 0x%04" PRIx64 " value: 0x%02" PRIx64 " size: %u"
1087
+npcm7xx_smbus_start(const char *id, int success) "%s starting, success: %d"
1088
+npcm7xx_smbus_send_address(const char *id, uint8_t addr, int recv, int success) "%s sending address: 0x%02x, recv: %d, success: %d"
1089
+npcm7xx_smbus_send_byte(const char *id, uint8_t value, int success) "%s send byte: 0x%02x, success: %d"
1090
+npcm7xx_smbus_recv_byte(const char *id, uint8_t value) "%s recv byte: 0x%02x"
1091
+npcm7xx_smbus_stop(const char *id) "%s stopping"
1092
+npcm7xx_smbus_nack(const char *id) "%s nacking"
1093
--
165
--
1094
2.20.1
166
2.34.1
1095
1096
diff view generated by jsdifflib
New patch
1
If the target sets default_nan_mode then we're always going to return
2
the default NaN, and pickNaNMulAdd() no longer has any side effects.
3
For consistency with pickNaN(), check for default_nan_mode before
4
calling pickNaNMulAdd().
1
5
6
When we convert pickNaNMulAdd() to allow runtime selection of the NaN
7
propagation rule, this means we won't have to make the targets which
8
use default_nan_mode also set a propagation rule.
9
10
Since RiscV always uses default_nan_mode, this allows us to remove
11
its ifdef case from pickNaNMulAdd().
12
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
15
Message-id: 20241202131347.498124-3-peter.maydell@linaro.org
16
---
17
fpu/softfloat-parts.c.inc | 8 ++++++--
18
fpu/softfloat-specialize.c.inc | 9 +++++++--
19
2 files changed, 13 insertions(+), 4 deletions(-)
20
21
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
22
index XXXXXXX..XXXXXXX 100644
23
--- a/fpu/softfloat-parts.c.inc
24
+++ b/fpu/softfloat-parts.c.inc
25
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b,
26
float_raise(float_flag_invalid | float_flag_invalid_imz, s);
27
}
28
29
- which = pickNaNMulAdd(a->cls, b->cls, c->cls, infzero, s);
30
+ if (s->default_nan_mode) {
31
+ which = 3;
32
+ } else {
33
+ which = pickNaNMulAdd(a->cls, b->cls, c->cls, infzero, s);
34
+ }
35
36
- if (s->default_nan_mode || which == 3) {
37
+ if (which == 3) {
38
parts_default_nan(a, s);
39
return a;
40
}
41
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
42
index XXXXXXX..XXXXXXX 100644
43
--- a/fpu/softfloat-specialize.c.inc
44
+++ b/fpu/softfloat-specialize.c.inc
45
@@ -XXX,XX +XXX,XX @@ static int pickNaN(FloatClass a_cls, FloatClass b_cls,
46
static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
47
bool infzero, float_status *status)
48
{
49
+ /*
50
+ * We guarantee not to require the target to tell us how to
51
+ * pick a NaN if we're always returning the default NaN.
52
+ * But if we're not in default-NaN mode then the target must
53
+ * specify.
54
+ */
55
+ assert(!status->default_nan_mode);
56
#if defined(TARGET_ARM)
57
/* For ARM, the (inf,zero,qnan) case sets InvalidOp and returns
58
* the default NaN
59
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
60
} else {
61
return 1;
62
}
63
-#elif defined(TARGET_RISCV)
64
- return 3; /* default NaN */
65
#elif defined(TARGET_S390X)
66
if (infzero) {
67
return 3;
68
--
69
2.34.1
diff view generated by jsdifflib
1
From: Hao Wu <wuhaotsh@google.com>
1
IEEE 758 does not define a fixed rule for what NaN to return in
2
2
the case of a fused multiply-add of inf * 0 + NaN. Different
3
Add AT24 EEPROM and temperature sensors for GSJ machine.
3
architectures thus do different things:
4
4
* some return the default NaN
5
Reviewed-by: Doug Evans<dje@google.com>
5
* some return the input NaN
6
Reviewed-by: Tyrong Ting<kfting@nuvoton.com>
6
* Arm returns the default NaN if the input NaN is quiet,
7
Signed-off-by: Hao Wu <wuhaotsh@google.com>
7
and the input NaN if it is signalling
8
Message-id: 20210210220426.3577804-4-wuhaotsh@google.com
8
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
We want to make this logic be runtime selected rather than
10
hardcoded into the binary, because:
11
* this will let us have multiple targets in one QEMU binary
12
* the Arm FEAT_AFP architectural feature includes letting
13
the guest select a NaN propagation rule at runtime
14
15
In this commit we add an enum for the propagation rule, the field in
16
float_status, and the corresponding getters and setters. We change
17
pickNaNMulAdd to honour this, but because all targets still leave
18
this field at its default 0 value, the fallback logic will pick the
19
rule type with the old ifdef ladder.
20
21
Note that four architectures both use the muladd softfloat functions
22
and did not have a branch of the ifdef ladder to specify their
23
behaviour (and so were ending up with the "default" case, probably
24
wrongly): i386, HPPA, SH4 and Tricore. SH4 and Tricore both set
25
default_nan_mode, and so will never get into pickNaNMulAdd(). For
26
HPPA and i386 we retain the same behaviour as the old default-case,
27
which is to not ever return the default NaN. This might not be
28
correct but it is not a behaviour change.
29
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
30
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
31
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
32
Message-id: 20241202131347.498124-4-peter.maydell@linaro.org
11
---
33
---
12
hw/arm/npcm7xx_boards.c | 27 +++++++++++++++++++++++++++
34
include/fpu/softfloat-helpers.h | 11 ++++
13
hw/arm/Kconfig | 1 +
35
include/fpu/softfloat-types.h | 23 +++++++++
14
2 files changed, 28 insertions(+)
36
fpu/softfloat-specialize.c.inc | 91 ++++++++++++++++++++++-----------
15
37
3 files changed, 95 insertions(+), 30 deletions(-)
16
diff --git a/hw/arm/npcm7xx_boards.c b/hw/arm/npcm7xx_boards.c
38
39
diff --git a/include/fpu/softfloat-helpers.h b/include/fpu/softfloat-helpers.h
17
index XXXXXXX..XXXXXXX 100644
40
index XXXXXXX..XXXXXXX 100644
18
--- a/hw/arm/npcm7xx_boards.c
41
--- a/include/fpu/softfloat-helpers.h
19
+++ b/hw/arm/npcm7xx_boards.c
42
+++ b/include/fpu/softfloat-helpers.h
20
@@ -XXX,XX +XXX,XX @@
43
@@ -XXX,XX +XXX,XX @@ static inline void set_float_2nan_prop_rule(Float2NaNPropRule rule,
21
#include "exec/address-spaces.h"
44
status->float_2nan_prop_rule = rule;
22
#include "hw/arm/npcm7xx.h"
23
#include "hw/core/cpu.h"
24
+#include "hw/i2c/smbus_eeprom.h"
25
#include "hw/loader.h"
26
#include "hw/qdev-properties.h"
27
#include "qapi/error.h"
28
@@ -XXX,XX +XXX,XX @@ static I2CBus *npcm7xx_i2c_get_bus(NPCM7xxState *soc, uint32_t num)
29
return I2C_BUS(qdev_get_child_bus(DEVICE(&soc->smbus[num]), "i2c-bus"));
30
}
45
}
31
46
32
+static void at24c_eeprom_init(NPCM7xxState *soc, int bus, uint8_t addr,
47
+static inline void set_float_infzeronan_rule(FloatInfZeroNaNRule rule,
33
+ uint32_t rsize)
48
+ float_status *status)
34
+{
49
+{
35
+ I2CBus *i2c_bus = npcm7xx_i2c_get_bus(soc, bus);
50
+ status->float_infzeronan_rule = rule;
36
+ I2CSlave *i2c_dev = i2c_slave_new("at24c-eeprom", addr);
37
+ DeviceState *dev = DEVICE(i2c_dev);
38
+
39
+ qdev_prop_set_uint32(dev, "rom-size", rsize);
40
+ i2c_slave_realize_and_unref(i2c_dev, i2c_bus, &error_abort);
41
+}
51
+}
42
+
52
+
43
static void npcm750_evb_i2c_init(NPCM7xxState *soc)
53
static inline void set_flush_to_zero(bool val, float_status *status)
44
{
54
{
45
/* lm75 temperature sensor on SVB, tmp105 is compatible */
55
status->flush_to_zero = val;
46
@@ -XXX,XX +XXX,XX @@ static void npcm750_evb_i2c_init(NPCM7xxState *soc)
56
@@ -XXX,XX +XXX,XX @@ static inline Float2NaNPropRule get_float_2nan_prop_rule(float_status *status)
47
i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 6), "tmp105", 0x48);
57
return status->float_2nan_prop_rule;
48
}
58
}
49
59
50
+static void quanta_gsj_i2c_init(NPCM7xxState *soc)
60
+static inline FloatInfZeroNaNRule get_float_infzeronan_rule(float_status *status)
51
+{
61
+{
52
+ /* GSJ machine have 4 max31725 temperature sensors, tmp105 is compatible. */
62
+ return status->float_infzeronan_rule;
53
+ i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 1), "tmp105", 0x5c);
54
+ i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 2), "tmp105", 0x5c);
55
+ i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 3), "tmp105", 0x5c);
56
+ i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 4), "tmp105", 0x5c);
57
+
58
+ at24c_eeprom_init(soc, 9, 0x55, 8192);
59
+ at24c_eeprom_init(soc, 10, 0x55, 8192);
60
+
61
+ /* TODO: Add additional i2c devices. */
62
+}
63
+}
63
+
64
+
64
static void npcm750_evb_init(MachineState *machine)
65
static inline bool get_flush_to_zero(float_status *status)
65
{
66
{
66
NPCM7xxState *soc;
67
return status->flush_to_zero;
67
@@ -XXX,XX +XXX,XX @@ static void quanta_gsj_init(MachineState *machine)
68
diff --git a/include/fpu/softfloat-types.h b/include/fpu/softfloat-types.h
68
npcm7xx_load_bootrom(machine, soc);
69
npcm7xx_connect_flash(&soc->fiu[0], 0, "mx25l25635e",
70
drive_get(IF_MTD, 0, 0));
71
+ quanta_gsj_i2c_init(soc);
72
npcm7xx_load_kernel(machine, soc);
73
}
74
75
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
76
index XXXXXXX..XXXXXXX 100644
69
index XXXXXXX..XXXXXXX 100644
77
--- a/hw/arm/Kconfig
70
--- a/include/fpu/softfloat-types.h
78
+++ b/hw/arm/Kconfig
71
+++ b/include/fpu/softfloat-types.h
79
@@ -XXX,XX +XXX,XX @@ config NPCM7XX
72
@@ -XXX,XX +XXX,XX @@ typedef enum __attribute__((__packed__)) {
80
bool
73
float_2nan_prop_x87,
81
select A9MPCORE
74
} Float2NaNPropRule;
82
select ARM_GIC
75
83
+ select AT24C # EEPROM
76
+/*
84
select PL310 # cache controller
77
+ * Rule for result of fused multiply-add 0 * Inf + NaN.
85
select SERIAL
78
+ * This must be a NaN, but implementations differ on whether this
86
select SSI
79
+ * is the input NaN or the default NaN.
80
+ *
81
+ * You don't need to set this if default_nan_mode is enabled.
82
+ * When not in default-NaN mode, it is an error for the target
83
+ * not to set the rule in float_status if it uses muladd, and we
84
+ * will assert if we need to handle an input NaN and no rule was
85
+ * selected.
86
+ */
87
+typedef enum __attribute__((__packed__)) {
88
+ /* No propagation rule specified */
89
+ float_infzeronan_none = 0,
90
+ /* Result is never the default NaN (so always the input NaN) */
91
+ float_infzeronan_dnan_never,
92
+ /* Result is always the default NaN */
93
+ float_infzeronan_dnan_always,
94
+ /* Result is the default NaN if the input NaN is quiet */
95
+ float_infzeronan_dnan_if_qnan,
96
+} FloatInfZeroNaNRule;
97
+
98
/*
99
* Floating Point Status. Individual architectures may maintain
100
* several versions of float_status for different functions. The
101
@@ -XXX,XX +XXX,XX @@ typedef struct float_status {
102
FloatRoundMode float_rounding_mode;
103
FloatX80RoundPrec floatx80_rounding_precision;
104
Float2NaNPropRule float_2nan_prop_rule;
105
+ FloatInfZeroNaNRule float_infzeronan_rule;
106
bool tininess_before_rounding;
107
/* should denormalised results go to zero and set the inexact flag? */
108
bool flush_to_zero;
109
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
110
index XXXXXXX..XXXXXXX 100644
111
--- a/fpu/softfloat-specialize.c.inc
112
+++ b/fpu/softfloat-specialize.c.inc
113
@@ -XXX,XX +XXX,XX @@ static int pickNaN(FloatClass a_cls, FloatClass b_cls,
114
static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
115
bool infzero, float_status *status)
116
{
117
+ FloatInfZeroNaNRule rule = status->float_infzeronan_rule;
118
+
119
/*
120
* We guarantee not to require the target to tell us how to
121
* pick a NaN if we're always returning the default NaN.
122
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
123
* specify.
124
*/
125
assert(!status->default_nan_mode);
126
+
127
+ if (rule == float_infzeronan_none) {
128
+ /*
129
+ * Temporarily fall back to ifdef ladder
130
+ */
131
#if defined(TARGET_ARM)
132
- /* For ARM, the (inf,zero,qnan) case sets InvalidOp and returns
133
- * the default NaN
134
- */
135
- if (infzero && is_qnan(c_cls)) {
136
- return 3;
137
+ /*
138
+ * For ARM, the (inf,zero,qnan) case returns the default NaN,
139
+ * but (inf,zero,snan) returns the input NaN.
140
+ */
141
+ rule = float_infzeronan_dnan_if_qnan;
142
+#elif defined(TARGET_MIPS)
143
+ if (snan_bit_is_one(status)) {
144
+ /*
145
+ * For MIPS systems that conform to IEEE754-1985, the (inf,zero,nan)
146
+ * case sets InvalidOp and returns the default NaN
147
+ */
148
+ rule = float_infzeronan_dnan_always;
149
+ } else {
150
+ /*
151
+ * For MIPS systems that conform to IEEE754-2008, the (inf,zero,nan)
152
+ * case sets InvalidOp and returns the input value 'c'
153
+ */
154
+ rule = float_infzeronan_dnan_never;
155
+ }
156
+#elif defined(TARGET_PPC) || defined(TARGET_SPARC) || \
157
+ defined(TARGET_XTENSA) || defined(TARGET_HPPA) || \
158
+ defined(TARGET_I386) || defined(TARGET_LOONGARCH)
159
+ /*
160
+ * For LoongArch systems that conform to IEEE754-2008, the (inf,zero,nan)
161
+ * case sets InvalidOp and returns the input value 'c'
162
+ */
163
+ /*
164
+ * For PPC, the (inf,zero,qnan) case sets InvalidOp, but we prefer
165
+ * to return an input NaN if we have one (ie c) rather than generating
166
+ * a default NaN
167
+ */
168
+ rule = float_infzeronan_dnan_never;
169
+#elif defined(TARGET_S390X)
170
+ rule = float_infzeronan_dnan_always;
171
+#endif
172
}
173
174
+ if (infzero) {
175
+ /*
176
+ * Inf * 0 + NaN -- some implementations return the default NaN here,
177
+ * and some return the input NaN.
178
+ */
179
+ switch (rule) {
180
+ case float_infzeronan_dnan_never:
181
+ return 2;
182
+ case float_infzeronan_dnan_always:
183
+ return 3;
184
+ case float_infzeronan_dnan_if_qnan:
185
+ return is_qnan(c_cls) ? 3 : 2;
186
+ default:
187
+ g_assert_not_reached();
188
+ }
189
+ }
190
+
191
+#if defined(TARGET_ARM)
192
+
193
/* This looks different from the ARM ARM pseudocode, because the ARM ARM
194
* puts the operands to a fused mac operation (a*b)+c in the order c,a,b.
195
*/
196
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
197
}
198
#elif defined(TARGET_MIPS)
199
if (snan_bit_is_one(status)) {
200
- /*
201
- * For MIPS systems that conform to IEEE754-1985, the (inf,zero,nan)
202
- * case sets InvalidOp and returns the default NaN
203
- */
204
- if (infzero) {
205
- return 3;
206
- }
207
/* Prefer sNaN over qNaN, in the a, b, c order. */
208
if (is_snan(a_cls)) {
209
return 0;
210
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
211
return 2;
212
}
213
} else {
214
- /*
215
- * For MIPS systems that conform to IEEE754-2008, the (inf,zero,nan)
216
- * case sets InvalidOp and returns the input value 'c'
217
- */
218
/* Prefer sNaN over qNaN, in the c, a, b order. */
219
if (is_snan(c_cls)) {
220
return 2;
221
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
222
}
223
}
224
#elif defined(TARGET_LOONGARCH64)
225
- /*
226
- * For LoongArch systems that conform to IEEE754-2008, the (inf,zero,nan)
227
- * case sets InvalidOp and returns the input value 'c'
228
- */
229
-
230
/* Prefer sNaN over qNaN, in the c, a, b order. */
231
if (is_snan(c_cls)) {
232
return 2;
233
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
234
return 1;
235
}
236
#elif defined(TARGET_PPC)
237
- /* For PPC, the (inf,zero,qnan) case sets InvalidOp, but we prefer
238
- * to return an input NaN if we have one (ie c) rather than generating
239
- * a default NaN
240
- */
241
-
242
/* If fRA is a NaN return it; otherwise if fRB is a NaN return it;
243
* otherwise return fRC. Note that muladd on PPC is (fRA * fRC) + frB
244
*/
245
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
246
return 1;
247
}
248
#elif defined(TARGET_S390X)
249
- if (infzero) {
250
- return 3;
251
- }
252
-
253
if (is_snan(a_cls)) {
254
return 0;
255
} else if (is_snan(b_cls)) {
87
--
256
--
88
2.20.1
257
2.34.1
89
90
diff view generated by jsdifflib
New patch
1
Explicitly set a rule in the softfloat tests for the inf-zero-nan
2
muladd special case. In meson.build we put -DTARGET_ARM in fpcflags,
3
and so we should select here the Arm rule of
4
float_infzeronan_dnan_if_qnan.
1
5
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Message-id: 20241202131347.498124-5-peter.maydell@linaro.org
9
---
10
tests/fp/fp-bench.c | 5 +++++
11
tests/fp/fp-test.c | 5 +++++
12
2 files changed, 10 insertions(+)
13
14
diff --git a/tests/fp/fp-bench.c b/tests/fp/fp-bench.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/tests/fp/fp-bench.c
17
+++ b/tests/fp/fp-bench.c
18
@@ -XXX,XX +XXX,XX @@ static void run_bench(void)
19
{
20
bench_func_t f;
21
22
+ /*
23
+ * These implementation-defined choices for various things IEEE
24
+ * doesn't specify match those used by the Arm architecture.
25
+ */
26
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &soft_status);
27
+ set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, &soft_status);
28
29
f = bench_funcs[operation][precision];
30
g_assert(f);
31
diff --git a/tests/fp/fp-test.c b/tests/fp/fp-test.c
32
index XXXXXXX..XXXXXXX 100644
33
--- a/tests/fp/fp-test.c
34
+++ b/tests/fp/fp-test.c
35
@@ -XXX,XX +XXX,XX @@ void run_test(void)
36
{
37
unsigned int i;
38
39
+ /*
40
+ * These implementation-defined choices for various things IEEE
41
+ * doesn't specify match those used by the Arm architecture.
42
+ */
43
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &qsf);
44
+ set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, &qsf);
45
46
genCases_setLevel(test_level);
47
verCases_maxErrorCount = n_max_errors;
48
--
49
2.34.1
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
Set the FloatInfZeroNaNRule explicitly for the Arm target,
2
so we can remove the ifdef from pickNaNMulAdd().
2
3
3
A proper syndrome is required to fill in the proper si_code.
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Use page_get_flags to determine permission vs translation for user-only.
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20241202131347.498124-6-peter.maydell@linaro.org
7
---
8
target/arm/cpu.c | 3 +++
9
fpu/softfloat-specialize.c.inc | 8 +-------
10
2 files changed, 4 insertions(+), 7 deletions(-)
5
11
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
12
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20210212184902.1251044-27-richard.henderson@linaro.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
11
linux-user/aarch64/cpu_loop.c | 24 +++++++++++++++++++++---
12
target/arm/tlb_helper.c | 15 +++++++++------
13
2 files changed, 30 insertions(+), 9 deletions(-)
14
15
diff --git a/linux-user/aarch64/cpu_loop.c b/linux-user/aarch64/cpu_loop.c
16
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
17
--- a/linux-user/aarch64/cpu_loop.c
14
--- a/target/arm/cpu.c
18
+++ b/linux-user/aarch64/cpu_loop.c
15
+++ b/target/arm/cpu.c
19
@@ -XXX,XX +XXX,XX @@
16
@@ -XXX,XX +XXX,XX @@ void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook,
20
#include "cpu_loop-common.h"
17
* * tininess-before-rounding
21
#include "qemu/guest-random.h"
18
* * 2-input NaN propagation prefers SNaN over QNaN, and then
22
#include "hw/semihosting/common-semi.h"
19
* operand A over operand B (see FPProcessNaNs() pseudocode)
23
+#include "target/arm/syndrome.h"
20
+ * * 0 * Inf + NaN returns the default NaN if the input NaN is quiet,
24
21
+ * and the input NaN if it is signalling
25
#define get_user_code_u32(x, gaddr, env) \
22
*/
26
({ abi_long __r = get_user_u32((x), (gaddr)); \
23
static void arm_set_default_fp_behaviours(float_status *s)
27
@@ -XXX,XX +XXX,XX @@
28
void cpu_loop(CPUARMState *env)
29
{
24
{
30
CPUState *cs = env_cpu(env);
25
set_float_detect_tininess(float_tininess_before_rounding, s);
31
- int trapnr;
26
set_float_2nan_prop_rule(float_2nan_prop_s_ab, s);
32
+ int trapnr, ec, fsc;
27
+ set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, s);
33
abi_long ret;
28
}
34
target_siginfo_t info;
29
35
30
static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque)
36
@@ -XXX,XX +XXX,XX @@ void cpu_loop(CPUARMState *env)
31
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
37
case EXCP_DATA_ABORT:
38
info.si_signo = TARGET_SIGSEGV;
39
info.si_errno = 0;
40
- /* XXX: check env->error_code */
41
- info.si_code = TARGET_SEGV_MAPERR;
42
info._sifields._sigfault._addr = env->exception.vaddress;
43
+
44
+ /* We should only arrive here with EC in {DATAABORT, INSNABORT}. */
45
+ ec = syn_get_ec(env->exception.syndrome);
46
+ assert(ec == EC_DATAABORT || ec == EC_INSNABORT);
47
+
48
+ /* Both EC have the same format for FSC, or close enough. */
49
+ fsc = extract32(env->exception.syndrome, 0, 6);
50
+ switch (fsc) {
51
+ case 0x04 ... 0x07: /* Translation fault, level {0-3} */
52
+ info.si_code = TARGET_SEGV_MAPERR;
53
+ break;
54
+ case 0x09 ... 0x0b: /* Access flag fault, level {1-3} */
55
+ case 0x0d ... 0x0f: /* Permission fault, level {1-3} */
56
+ info.si_code = TARGET_SEGV_ACCERR;
57
+ break;
58
+ default:
59
+ g_assert_not_reached();
60
+ }
61
+
62
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
63
break;
64
case EXCP_DEBUG:
65
diff --git a/target/arm/tlb_helper.c b/target/arm/tlb_helper.c
66
index XXXXXXX..XXXXXXX 100644
32
index XXXXXXX..XXXXXXX 100644
67
--- a/target/arm/tlb_helper.c
33
--- a/fpu/softfloat-specialize.c.inc
68
+++ b/target/arm/tlb_helper.c
34
+++ b/fpu/softfloat-specialize.c.inc
69
@@ -XXX,XX +XXX,XX @@ bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
35
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
70
bool probe, uintptr_t retaddr)
36
/*
71
{
37
* Temporarily fall back to ifdef ladder
72
ARMCPU *cpu = ARM_CPU(cs);
38
*/
73
+ ARMMMUFaultInfo fi = {};
39
-#if defined(TARGET_ARM)
74
40
- /*
75
#ifdef CONFIG_USER_ONLY
41
- * For ARM, the (inf,zero,qnan) case returns the default NaN,
76
- cpu->env.exception.vaddress = address;
42
- * but (inf,zero,snan) returns the input NaN.
77
- if (access_type == MMU_INST_FETCH) {
43
- */
78
- cs->exception_index = EXCP_PREFETCH_ABORT;
44
- rule = float_infzeronan_dnan_if_qnan;
79
+ int flags = page_get_flags(useronly_clean_ptr(address));
45
-#elif defined(TARGET_MIPS)
80
+ if (flags & PAGE_VALID) {
46
+#if defined(TARGET_MIPS)
81
+ fi.type = ARMFault_Permission;
47
if (snan_bit_is_one(status)) {
82
} else {
48
/*
83
- cs->exception_index = EXCP_DATA_ABORT;
49
* For MIPS systems that conform to IEEE754-1985, the (inf,zero,nan)
84
+ fi.type = ARMFault_Translation;
85
}
86
- cpu_loop_exit_restore(cs, retaddr);
87
+
88
+ /* now we have a real cpu fault */
89
+ cpu_restore_state(cs, retaddr, true);
90
+ arm_deliver_fault(cpu, address, access_type, mmu_idx, &fi);
91
#else
92
hwaddr phys_addr;
93
target_ulong page_size;
94
int prot, ret;
95
MemTxAttrs attrs = {};
96
- ARMMMUFaultInfo fi = {};
97
ARMCacheAttrs cacheattrs = {};
98
99
/*
100
--
50
--
101
2.20.1
51
2.34.1
102
103
diff view generated by jsdifflib
New patch
1
Set the FloatInfZeroNaNRule explicitly for s390, so we
2
can remove the ifdef from pickNaNMulAdd().
1
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20241202131347.498124-7-peter.maydell@linaro.org
7
---
8
target/s390x/cpu.c | 2 ++
9
fpu/softfloat-specialize.c.inc | 2 --
10
2 files changed, 2 insertions(+), 2 deletions(-)
11
12
diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/target/s390x/cpu.c
15
+++ b/target/s390x/cpu.c
16
@@ -XXX,XX +XXX,XX @@ static void s390_cpu_reset_hold(Object *obj, ResetType type)
17
set_float_detect_tininess(float_tininess_before_rounding,
18
&env->fpu_status);
19
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &env->fpu_status);
20
+ set_float_infzeronan_rule(float_infzeronan_dnan_always,
21
+ &env->fpu_status);
22
/* fall through */
23
case RESET_TYPE_S390_CPU_NORMAL:
24
env->psw.mask &= ~PSW_MASK_RI;
25
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
26
index XXXXXXX..XXXXXXX 100644
27
--- a/fpu/softfloat-specialize.c.inc
28
+++ b/fpu/softfloat-specialize.c.inc
29
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
30
* a default NaN
31
*/
32
rule = float_infzeronan_dnan_never;
33
-#elif defined(TARGET_S390X)
34
- rule = float_infzeronan_dnan_always;
35
#endif
36
}
37
38
--
39
2.34.1
diff view generated by jsdifflib
New patch
1
Set the FloatInfZeroNaNRule explicitly for the PPC target,
2
so we can remove the ifdef from pickNaNMulAdd().
1
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20241202131347.498124-8-peter.maydell@linaro.org
7
---
8
target/ppc/cpu_init.c | 7 +++++++
9
fpu/softfloat-specialize.c.inc | 7 +------
10
2 files changed, 8 insertions(+), 6 deletions(-)
11
12
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/target/ppc/cpu_init.c
15
+++ b/target/ppc/cpu_init.c
16
@@ -XXX,XX +XXX,XX @@ static void ppc_cpu_reset_hold(Object *obj, ResetType type)
17
*/
18
set_float_2nan_prop_rule(float_2nan_prop_ab, &env->fp_status);
19
set_float_2nan_prop_rule(float_2nan_prop_ab, &env->vec_status);
20
+ /*
21
+ * For PPC, the (inf,zero,qnan) case sets InvalidOp, but we prefer
22
+ * to return an input NaN if we have one (ie c) rather than generating
23
+ * a default NaN
24
+ */
25
+ set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
26
+ set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->vec_status);
27
28
for (i = 0; i < ARRAY_SIZE(env->spr_cb); i++) {
29
ppc_spr_t *spr = &env->spr_cb[i];
30
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
31
index XXXXXXX..XXXXXXX 100644
32
--- a/fpu/softfloat-specialize.c.inc
33
+++ b/fpu/softfloat-specialize.c.inc
34
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
35
*/
36
rule = float_infzeronan_dnan_never;
37
}
38
-#elif defined(TARGET_PPC) || defined(TARGET_SPARC) || \
39
+#elif defined(TARGET_SPARC) || \
40
defined(TARGET_XTENSA) || defined(TARGET_HPPA) || \
41
defined(TARGET_I386) || defined(TARGET_LOONGARCH)
42
/*
43
* For LoongArch systems that conform to IEEE754-2008, the (inf,zero,nan)
44
* case sets InvalidOp and returns the input value 'c'
45
*/
46
- /*
47
- * For PPC, the (inf,zero,qnan) case sets InvalidOp, but we prefer
48
- * to return an input NaN if we have one (ie c) rather than generating
49
- * a default NaN
50
- */
51
rule = float_infzeronan_dnan_never;
52
#endif
53
}
54
--
55
2.34.1
diff view generated by jsdifflib
New patch
1
Set the FloatInfZeroNaNRule explicitly for the MIPS target,
2
so we can remove the ifdef from pickNaNMulAdd().
1
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20241202131347.498124-9-peter.maydell@linaro.org
7
---
8
target/mips/fpu_helper.h | 9 +++++++++
9
target/mips/msa.c | 4 ++++
10
fpu/softfloat-specialize.c.inc | 16 +---------------
11
3 files changed, 14 insertions(+), 15 deletions(-)
12
13
diff --git a/target/mips/fpu_helper.h b/target/mips/fpu_helper.h
14
index XXXXXXX..XXXXXXX 100644
15
--- a/target/mips/fpu_helper.h
16
+++ b/target/mips/fpu_helper.h
17
@@ -XXX,XX +XXX,XX @@ static inline void restore_flush_mode(CPUMIPSState *env)
18
static inline void restore_snan_bit_mode(CPUMIPSState *env)
19
{
20
bool nan2008 = env->active_fpu.fcr31 & (1 << FCR31_NAN2008);
21
+ FloatInfZeroNaNRule izn_rule;
22
23
/*
24
* With nan2008, SNaNs are silenced in the usual way.
25
@@ -XXX,XX +XXX,XX @@ static inline void restore_snan_bit_mode(CPUMIPSState *env)
26
*/
27
set_snan_bit_is_one(!nan2008, &env->active_fpu.fp_status);
28
set_default_nan_mode(!nan2008, &env->active_fpu.fp_status);
29
+ /*
30
+ * For MIPS systems that conform to IEEE754-1985, the (inf,zero,nan)
31
+ * case sets InvalidOp and returns the default NaN.
32
+ * For MIPS systems that conform to IEEE754-2008, the (inf,zero,nan)
33
+ * case sets InvalidOp and returns the input value 'c'.
34
+ */
35
+ izn_rule = nan2008 ? float_infzeronan_dnan_never : float_infzeronan_dnan_always;
36
+ set_float_infzeronan_rule(izn_rule, &env->active_fpu.fp_status);
37
}
38
39
static inline void restore_fp_status(CPUMIPSState *env)
40
diff --git a/target/mips/msa.c b/target/mips/msa.c
41
index XXXXXXX..XXXXXXX 100644
42
--- a/target/mips/msa.c
43
+++ b/target/mips/msa.c
44
@@ -XXX,XX +XXX,XX @@ void msa_reset(CPUMIPSState *env)
45
46
/* set proper signanling bit meaning ("1" means "quiet") */
47
set_snan_bit_is_one(0, &env->active_tc.msa_fp_status);
48
+
49
+ /* Inf * 0 + NaN returns the input NaN */
50
+ set_float_infzeronan_rule(float_infzeronan_dnan_never,
51
+ &env->active_tc.msa_fp_status);
52
}
53
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
54
index XXXXXXX..XXXXXXX 100644
55
--- a/fpu/softfloat-specialize.c.inc
56
+++ b/fpu/softfloat-specialize.c.inc
57
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
58
/*
59
* Temporarily fall back to ifdef ladder
60
*/
61
-#if defined(TARGET_MIPS)
62
- if (snan_bit_is_one(status)) {
63
- /*
64
- * For MIPS systems that conform to IEEE754-1985, the (inf,zero,nan)
65
- * case sets InvalidOp and returns the default NaN
66
- */
67
- rule = float_infzeronan_dnan_always;
68
- } else {
69
- /*
70
- * For MIPS systems that conform to IEEE754-2008, the (inf,zero,nan)
71
- * case sets InvalidOp and returns the input value 'c'
72
- */
73
- rule = float_infzeronan_dnan_never;
74
- }
75
-#elif defined(TARGET_SPARC) || \
76
+#if defined(TARGET_SPARC) || \
77
defined(TARGET_XTENSA) || defined(TARGET_HPPA) || \
78
defined(TARGET_I386) || defined(TARGET_LOONGARCH)
79
/*
80
--
81
2.34.1
diff view generated by jsdifflib
New patch
1
Set the FloatInfZeroNaNRule explicitly for the SPARC target,
2
so we can remove the ifdef from pickNaNMulAdd().
1
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20241202131347.498124-10-peter.maydell@linaro.org
7
---
8
target/sparc/cpu.c | 2 ++
9
fpu/softfloat-specialize.c.inc | 3 +--
10
2 files changed, 3 insertions(+), 2 deletions(-)
11
12
diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/target/sparc/cpu.c
15
+++ b/target/sparc/cpu.c
16
@@ -XXX,XX +XXX,XX @@ static void sparc_cpu_realizefn(DeviceState *dev, Error **errp)
17
* the CPU state struct so it won't get zeroed on reset.
18
*/
19
set_float_2nan_prop_rule(float_2nan_prop_s_ba, &env->fp_status);
20
+ /* For inf * 0 + NaN, return the input NaN */
21
+ set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
22
23
cpu_exec_realizefn(cs, &local_err);
24
if (local_err != NULL) {
25
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
26
index XXXXXXX..XXXXXXX 100644
27
--- a/fpu/softfloat-specialize.c.inc
28
+++ b/fpu/softfloat-specialize.c.inc
29
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
30
/*
31
* Temporarily fall back to ifdef ladder
32
*/
33
-#if defined(TARGET_SPARC) || \
34
- defined(TARGET_XTENSA) || defined(TARGET_HPPA) || \
35
+#if defined(TARGET_XTENSA) || defined(TARGET_HPPA) || \
36
defined(TARGET_I386) || defined(TARGET_LOONGARCH)
37
/*
38
* For LoongArch systems that conform to IEEE754-2008, the (inf,zero,nan)
39
--
40
2.34.1
diff view generated by jsdifflib
New patch
1
Set the FloatInfZeroNaNRule explicitly for the xtensa target,
2
so we can remove the ifdef from pickNaNMulAdd().
1
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20241202131347.498124-11-peter.maydell@linaro.org
7
---
8
target/xtensa/cpu.c | 2 ++
9
fpu/softfloat-specialize.c.inc | 2 +-
10
2 files changed, 3 insertions(+), 1 deletion(-)
11
12
diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/target/xtensa/cpu.c
15
+++ b/target/xtensa/cpu.c
16
@@ -XXX,XX +XXX,XX @@ static void xtensa_cpu_reset_hold(Object *obj, ResetType type)
17
reset_mmu(env);
18
cs->halted = env->runstall;
19
#endif
20
+ /* For inf * 0 + NaN, return the input NaN */
21
+ set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
22
set_no_signaling_nans(!dfpu, &env->fp_status);
23
xtensa_use_first_nan(env, !dfpu);
24
}
25
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
26
index XXXXXXX..XXXXXXX 100644
27
--- a/fpu/softfloat-specialize.c.inc
28
+++ b/fpu/softfloat-specialize.c.inc
29
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
30
/*
31
* Temporarily fall back to ifdef ladder
32
*/
33
-#if defined(TARGET_XTENSA) || defined(TARGET_HPPA) || \
34
+#if defined(TARGET_HPPA) || \
35
defined(TARGET_I386) || defined(TARGET_LOONGARCH)
36
/*
37
* For LoongArch systems that conform to IEEE754-2008, the (inf,zero,nan)
38
--
39
2.34.1
diff view generated by jsdifflib
New patch
1
Set the FloatInfZeroNaNRule explicitly for the x86 target.
1
2
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Message-id: 20241202131347.498124-12-peter.maydell@linaro.org
6
---
7
target/i386/tcg/fpu_helper.c | 7 +++++++
8
fpu/softfloat-specialize.c.inc | 2 +-
9
2 files changed, 8 insertions(+), 1 deletion(-)
10
11
diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/target/i386/tcg/fpu_helper.c
14
+++ b/target/i386/tcg/fpu_helper.c
15
@@ -XXX,XX +XXX,XX @@ void cpu_init_fp_statuses(CPUX86State *env)
16
*/
17
set_float_2nan_prop_rule(float_2nan_prop_x87, &env->mmx_status);
18
set_float_2nan_prop_rule(float_2nan_prop_x87, &env->sse_status);
19
+ /*
20
+ * Only SSE has multiply-add instructions. In the SDM Section 14.5.2
21
+ * "Fused-Multiply-ADD (FMA) Numeric Behavior" the NaN handling is
22
+ * specified -- for 0 * inf + NaN the input NaN is selected, and if
23
+ * there are multiple input NaNs they are selected in the order a, b, c.
24
+ */
25
+ set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->sse_status);
26
}
27
28
static inline uint8_t save_exception_flags(CPUX86State *env)
29
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
30
index XXXXXXX..XXXXXXX 100644
31
--- a/fpu/softfloat-specialize.c.inc
32
+++ b/fpu/softfloat-specialize.c.inc
33
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
34
* Temporarily fall back to ifdef ladder
35
*/
36
#if defined(TARGET_HPPA) || \
37
- defined(TARGET_I386) || defined(TARGET_LOONGARCH)
38
+ defined(TARGET_LOONGARCH)
39
/*
40
* For LoongArch systems that conform to IEEE754-2008, the (inf,zero,nan)
41
* case sets InvalidOp and returns the input value 'c'
42
--
43
2.34.1
diff view generated by jsdifflib
New patch
1
Set the FloatInfZeroNaNRule explicitly for the loongarch target.
1
2
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Message-id: 20241202131347.498124-13-peter.maydell@linaro.org
6
---
7
target/loongarch/tcg/fpu_helper.c | 5 +++++
8
fpu/softfloat-specialize.c.inc | 7 +------
9
2 files changed, 6 insertions(+), 6 deletions(-)
10
11
diff --git a/target/loongarch/tcg/fpu_helper.c b/target/loongarch/tcg/fpu_helper.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/target/loongarch/tcg/fpu_helper.c
14
+++ b/target/loongarch/tcg/fpu_helper.c
15
@@ -XXX,XX +XXX,XX @@ void restore_fp_status(CPULoongArchState *env)
16
&env->fp_status);
17
set_flush_to_zero(0, &env->fp_status);
18
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &env->fp_status);
19
+ /*
20
+ * For LoongArch systems that conform to IEEE754-2008, the (inf,zero,nan)
21
+ * case sets InvalidOp and returns the input value 'c'
22
+ */
23
+ set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
24
}
25
26
int ieee_ex_to_loongarch(int xcpt)
27
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
28
index XXXXXXX..XXXXXXX 100644
29
--- a/fpu/softfloat-specialize.c.inc
30
+++ b/fpu/softfloat-specialize.c.inc
31
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
32
/*
33
* Temporarily fall back to ifdef ladder
34
*/
35
-#if defined(TARGET_HPPA) || \
36
- defined(TARGET_LOONGARCH)
37
- /*
38
- * For LoongArch systems that conform to IEEE754-2008, the (inf,zero,nan)
39
- * case sets InvalidOp and returns the input value 'c'
40
- */
41
+#if defined(TARGET_HPPA)
42
rule = float_infzeronan_dnan_never;
43
#endif
44
}
45
--
46
2.34.1
diff view generated by jsdifflib
New patch
1
Set the FloatInfZeroNaNRule explicitly for the HPPA target,
2
so we can remove the ifdef from pickNaNMulAdd().
1
3
4
As this is the last target to be converted to explicitly setting
5
the rule, we can remove the fallback code in pickNaNMulAdd()
6
entirely.
7
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
Message-id: 20241202131347.498124-14-peter.maydell@linaro.org
11
---
12
target/hppa/fpu_helper.c | 2 ++
13
fpu/softfloat-specialize.c.inc | 13 +------------
14
2 files changed, 3 insertions(+), 12 deletions(-)
15
16
diff --git a/target/hppa/fpu_helper.c b/target/hppa/fpu_helper.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/target/hppa/fpu_helper.c
19
+++ b/target/hppa/fpu_helper.c
20
@@ -XXX,XX +XXX,XX @@ void HELPER(loaded_fr0)(CPUHPPAState *env)
21
* HPPA does note implement a CPU reset method at all...
22
*/
23
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &env->fp_status);
24
+ /* For inf * 0 + NaN, return the input NaN */
25
+ set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
26
}
27
28
void cpu_hppa_loaded_fr0(CPUHPPAState *env)
29
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
30
index XXXXXXX..XXXXXXX 100644
31
--- a/fpu/softfloat-specialize.c.inc
32
+++ b/fpu/softfloat-specialize.c.inc
33
@@ -XXX,XX +XXX,XX @@ static int pickNaN(FloatClass a_cls, FloatClass b_cls,
34
static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
35
bool infzero, float_status *status)
36
{
37
- FloatInfZeroNaNRule rule = status->float_infzeronan_rule;
38
-
39
/*
40
* We guarantee not to require the target to tell us how to
41
* pick a NaN if we're always returning the default NaN.
42
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
43
*/
44
assert(!status->default_nan_mode);
45
46
- if (rule == float_infzeronan_none) {
47
- /*
48
- * Temporarily fall back to ifdef ladder
49
- */
50
-#if defined(TARGET_HPPA)
51
- rule = float_infzeronan_dnan_never;
52
-#endif
53
- }
54
-
55
if (infzero) {
56
/*
57
* Inf * 0 + NaN -- some implementations return the default NaN here,
58
* and some return the input NaN.
59
*/
60
- switch (rule) {
61
+ switch (status->float_infzeronan_rule) {
62
case float_infzeronan_dnan_never:
63
return 2;
64
case float_infzeronan_dnan_always:
65
--
66
2.34.1
diff view generated by jsdifflib
New patch
1
The new implementation of pickNaNMulAdd() will find it convenient
2
to know whether at least one of the three arguments to the muladd
3
was a signaling NaN. We already calculate that in the caller,
4
so pass it in as a new bool have_snan.
1
5
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20241202131347.498124-15-peter.maydell@linaro.org
9
---
10
fpu/softfloat-parts.c.inc | 5 +++--
11
fpu/softfloat-specialize.c.inc | 2 +-
12
2 files changed, 4 insertions(+), 3 deletions(-)
13
14
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
15
index XXXXXXX..XXXXXXX 100644
16
--- a/fpu/softfloat-parts.c.inc
17
+++ b/fpu/softfloat-parts.c.inc
18
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b,
19
{
20
int which;
21
bool infzero = (ab_mask == float_cmask_infzero);
22
+ bool have_snan = (abc_mask & float_cmask_snan);
23
24
- if (unlikely(abc_mask & float_cmask_snan)) {
25
+ if (unlikely(have_snan)) {
26
float_raise(float_flag_invalid | float_flag_invalid_snan, s);
27
}
28
29
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b,
30
if (s->default_nan_mode) {
31
which = 3;
32
} else {
33
- which = pickNaNMulAdd(a->cls, b->cls, c->cls, infzero, s);
34
+ which = pickNaNMulAdd(a->cls, b->cls, c->cls, infzero, have_snan, s);
35
}
36
37
if (which == 3) {
38
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
39
index XXXXXXX..XXXXXXX 100644
40
--- a/fpu/softfloat-specialize.c.inc
41
+++ b/fpu/softfloat-specialize.c.inc
42
@@ -XXX,XX +XXX,XX @@ static int pickNaN(FloatClass a_cls, FloatClass b_cls,
43
| Return values : 0 : a; 1 : b; 2 : c; 3 : default-NaN
44
*----------------------------------------------------------------------------*/
45
static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
46
- bool infzero, float_status *status)
47
+ bool infzero, bool have_snan, float_status *status)
48
{
49
/*
50
* We guarantee not to require the target to tell us how to
51
--
52
2.34.1
diff view generated by jsdifflib
1
From: Hao Wu <wuhaotsh@google.com>
1
IEEE 758 does not define a fixed rule for which NaN to pick as the
2
2
result if both operands of a 3-operand fused multiply-add operation
3
Add I2C temperature sensors for NPCM750 eval board.
3
are NaNs. As a result different architectures have ended up with
4
4
different rules for propagating NaNs.
5
Reviewed-by: Doug Evans<dje@google.com>
5
6
Reviewed-by: Tyrong Ting<kfting@nuvoton.com>
6
QEMU currently hardcodes the NaN propagation logic into the binary
7
Signed-off-by: Hao Wu <wuhaotsh@google.com>
7
because pickNaNMulAdd() has an ifdef ladder for different targets.
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
We want to make the propagation rule instead be selectable at
9
Message-id: 20210210220426.3577804-3-wuhaotsh@google.com
9
runtime, because:
10
* this will let us have multiple targets in one QEMU binary
11
* the Arm FEAT_AFP architectural feature includes letting
12
the guest select a NaN propagation rule at runtime
13
14
In this commit we add an enum for the propagation rule, the field in
15
float_status, and the corresponding getters and setters. We change
16
pickNaNMulAdd to honour this, but because all targets still leave
17
this field at its default 0 value, the fallback logic will pick the
18
rule type with the old ifdef ladder.
19
20
It's valid not to set a propagation rule if default_nan_mode is
21
enabled, because in that case there's no need to pick a NaN; all the
22
callers of pickNaNMulAdd() catch this case and skip calling it.
23
10
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>
26
Message-id: 20241202131347.498124-16-peter.maydell@linaro.org
11
---
27
---
12
hw/arm/npcm7xx_boards.c | 19 +++++++++++++++++++
28
include/fpu/softfloat-helpers.h | 11 +++
13
1 file changed, 19 insertions(+)
29
include/fpu/softfloat-types.h | 55 +++++++++++
14
30
fpu/softfloat-specialize.c.inc | 167 ++++++++------------------------
15
diff --git a/hw/arm/npcm7xx_boards.c b/hw/arm/npcm7xx_boards.c
31
3 files changed, 107 insertions(+), 126 deletions(-)
32
33
diff --git a/include/fpu/softfloat-helpers.h b/include/fpu/softfloat-helpers.h
16
index XXXXXXX..XXXXXXX 100644
34
index XXXXXXX..XXXXXXX 100644
17
--- a/hw/arm/npcm7xx_boards.c
35
--- a/include/fpu/softfloat-helpers.h
18
+++ b/hw/arm/npcm7xx_boards.c
36
+++ b/include/fpu/softfloat-helpers.h
19
@@ -XXX,XX +XXX,XX @@ static NPCM7xxState *npcm7xx_create_soc(MachineState *machine,
37
@@ -XXX,XX +XXX,XX @@ static inline void set_float_2nan_prop_rule(Float2NaNPropRule rule,
20
return NPCM7XX(obj);
38
status->float_2nan_prop_rule = rule;
21
}
39
}
22
40
23
+static I2CBus *npcm7xx_i2c_get_bus(NPCM7xxState *soc, uint32_t num)
41
+static inline void set_float_3nan_prop_rule(Float3NaNPropRule rule,
42
+ float_status *status)
24
+{
43
+{
25
+ g_assert(num < ARRAY_SIZE(soc->smbus));
44
+ status->float_3nan_prop_rule = rule;
26
+ return I2C_BUS(qdev_get_child_bus(DEVICE(&soc->smbus[num]), "i2c-bus"));
27
+}
45
+}
28
+
46
+
29
+static void npcm750_evb_i2c_init(NPCM7xxState *soc)
47
static inline void set_float_infzeronan_rule(FloatInfZeroNaNRule rule,
48
float_status *status)
49
{
50
@@ -XXX,XX +XXX,XX @@ static inline Float2NaNPropRule get_float_2nan_prop_rule(float_status *status)
51
return status->float_2nan_prop_rule;
52
}
53
54
+static inline Float3NaNPropRule get_float_3nan_prop_rule(float_status *status)
30
+{
55
+{
31
+ /* lm75 temperature sensor on SVB, tmp105 is compatible */
56
+ return status->float_3nan_prop_rule;
32
+ i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 0), "tmp105", 0x48);
33
+ /* lm75 temperature sensor on EB, tmp105 is compatible */
34
+ i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 1), "tmp105", 0x48);
35
+ /* tmp100 temperature sensor on EB, tmp105 is compatible */
36
+ i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 2), "tmp105", 0x48);
37
+ /* tmp100 temperature sensor on SVB, tmp105 is compatible */
38
+ i2c_slave_create_simple(npcm7xx_i2c_get_bus(soc, 6), "tmp105", 0x48);
39
+}
57
+}
40
+
58
+
41
static void npcm750_evb_init(MachineState *machine)
59
static inline FloatInfZeroNaNRule get_float_infzeronan_rule(float_status *status)
42
{
60
{
43
NPCM7xxState *soc;
61
return status->float_infzeronan_rule;
44
@@ -XXX,XX +XXX,XX @@ static void npcm750_evb_init(MachineState *machine)
62
diff --git a/include/fpu/softfloat-types.h b/include/fpu/softfloat-types.h
45
63
index XXXXXXX..XXXXXXX 100644
46
npcm7xx_load_bootrom(machine, soc);
64
--- a/include/fpu/softfloat-types.h
47
npcm7xx_connect_flash(&soc->fiu[0], 0, "w25q256", drive_get(IF_MTD, 0, 0));
65
+++ b/include/fpu/softfloat-types.h
48
+ npcm750_evb_i2c_init(soc);
66
@@ -XXX,XX +XXX,XX @@ this code that are retained.
49
npcm7xx_load_kernel(machine, soc);
67
#ifndef SOFTFLOAT_TYPES_H
68
#define SOFTFLOAT_TYPES_H
69
70
+#include "hw/registerfields.h"
71
+
72
/*
73
* Software IEC/IEEE floating-point types.
74
*/
75
@@ -XXX,XX +XXX,XX @@ typedef enum __attribute__((__packed__)) {
76
float_2nan_prop_x87,
77
} Float2NaNPropRule;
78
79
+/*
80
+ * 3-input NaN propagation rule, for fused multiply-add. Individual
81
+ * architectures have different rules for which input NaN is
82
+ * propagated to the output when there is more than one NaN on the
83
+ * input.
84
+ *
85
+ * If default_nan_mode is enabled then it is valid not to set a NaN
86
+ * propagation rule, because the softfloat code guarantees not to try
87
+ * to pick a NaN to propagate in default NaN mode. When not in
88
+ * default-NaN mode, it is an error for the target not to set the rule
89
+ * in float_status if it uses a muladd, and we will assert if we need
90
+ * to handle an input NaN and no rule was selected.
91
+ *
92
+ * The naming scheme for Float3NaNPropRule values is:
93
+ * float_3nan_prop_s_abc:
94
+ * = "Prefer SNaN over QNaN, then operand A over B over C"
95
+ * float_3nan_prop_abc:
96
+ * = "Prefer A over B over C regardless of SNaN vs QNAN"
97
+ *
98
+ * For QEMU, the multiply-add operation is A * B + C.
99
+ */
100
+
101
+/*
102
+ * We set the Float3NaNPropRule enum values up so we can select the
103
+ * right value in pickNaNMulAdd in a data driven way.
104
+ */
105
+FIELD(3NAN, 1ST, 0, 2) /* which operand is most preferred ? */
106
+FIELD(3NAN, 2ND, 2, 2) /* which operand is next most preferred ? */
107
+FIELD(3NAN, 3RD, 4, 2) /* which operand is least preferred ? */
108
+FIELD(3NAN, SNAN, 6, 1) /* do we prefer SNaN over QNaN ? */
109
+
110
+#define PROPRULE(X, Y, Z) \
111
+ ((X << R_3NAN_1ST_SHIFT) | (Y << R_3NAN_2ND_SHIFT) | (Z << R_3NAN_3RD_SHIFT))
112
+
113
+typedef enum __attribute__((__packed__)) {
114
+ float_3nan_prop_none = 0, /* No propagation rule specified */
115
+ float_3nan_prop_abc = PROPRULE(0, 1, 2),
116
+ float_3nan_prop_acb = PROPRULE(0, 2, 1),
117
+ float_3nan_prop_bac = PROPRULE(1, 0, 2),
118
+ float_3nan_prop_bca = PROPRULE(1, 2, 0),
119
+ float_3nan_prop_cab = PROPRULE(2, 0, 1),
120
+ float_3nan_prop_cba = PROPRULE(2, 1, 0),
121
+ float_3nan_prop_s_abc = float_3nan_prop_abc | R_3NAN_SNAN_MASK,
122
+ float_3nan_prop_s_acb = float_3nan_prop_acb | R_3NAN_SNAN_MASK,
123
+ float_3nan_prop_s_bac = float_3nan_prop_bac | R_3NAN_SNAN_MASK,
124
+ float_3nan_prop_s_bca = float_3nan_prop_bca | R_3NAN_SNAN_MASK,
125
+ float_3nan_prop_s_cab = float_3nan_prop_cab | R_3NAN_SNAN_MASK,
126
+ float_3nan_prop_s_cba = float_3nan_prop_cba | R_3NAN_SNAN_MASK,
127
+} Float3NaNPropRule;
128
+
129
+#undef PROPRULE
130
+
131
/*
132
* Rule for result of fused multiply-add 0 * Inf + NaN.
133
* This must be a NaN, but implementations differ on whether this
134
@@ -XXX,XX +XXX,XX @@ typedef struct float_status {
135
FloatRoundMode float_rounding_mode;
136
FloatX80RoundPrec floatx80_rounding_precision;
137
Float2NaNPropRule float_2nan_prop_rule;
138
+ Float3NaNPropRule float_3nan_prop_rule;
139
FloatInfZeroNaNRule float_infzeronan_rule;
140
bool tininess_before_rounding;
141
/* should denormalised results go to zero and set the inexact flag? */
142
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
143
index XXXXXXX..XXXXXXX 100644
144
--- a/fpu/softfloat-specialize.c.inc
145
+++ b/fpu/softfloat-specialize.c.inc
146
@@ -XXX,XX +XXX,XX @@ static int pickNaN(FloatClass a_cls, FloatClass b_cls,
147
static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
148
bool infzero, bool have_snan, float_status *status)
149
{
150
+ FloatClass cls[3] = { a_cls, b_cls, c_cls };
151
+ Float3NaNPropRule rule = status->float_3nan_prop_rule;
152
+ int which;
153
+
154
/*
155
* We guarantee not to require the target to tell us how to
156
* pick a NaN if we're always returning the default NaN.
157
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
158
}
159
}
160
161
+ if (rule == float_3nan_prop_none) {
162
#if defined(TARGET_ARM)
163
-
164
- /* This looks different from the ARM ARM pseudocode, because the ARM ARM
165
- * puts the operands to a fused mac operation (a*b)+c in the order c,a,b.
166
- */
167
- if (is_snan(c_cls)) {
168
- return 2;
169
- } else if (is_snan(a_cls)) {
170
- return 0;
171
- } else if (is_snan(b_cls)) {
172
- return 1;
173
- } else if (is_qnan(c_cls)) {
174
- return 2;
175
- } else if (is_qnan(a_cls)) {
176
- return 0;
177
- } else {
178
- return 1;
179
- }
180
+ /*
181
+ * This looks different from the ARM ARM pseudocode, because the ARM ARM
182
+ * puts the operands to a fused mac operation (a*b)+c in the order c,a,b
183
+ */
184
+ rule = float_3nan_prop_s_cab;
185
#elif defined(TARGET_MIPS)
186
- if (snan_bit_is_one(status)) {
187
- /* Prefer sNaN over qNaN, in the a, b, c order. */
188
- if (is_snan(a_cls)) {
189
- return 0;
190
- } else if (is_snan(b_cls)) {
191
- return 1;
192
- } else if (is_snan(c_cls)) {
193
- return 2;
194
- } else if (is_qnan(a_cls)) {
195
- return 0;
196
- } else if (is_qnan(b_cls)) {
197
- return 1;
198
+ if (snan_bit_is_one(status)) {
199
+ rule = float_3nan_prop_s_abc;
200
} else {
201
- return 2;
202
+ rule = float_3nan_prop_s_cab;
203
}
204
- } else {
205
- /* Prefer sNaN over qNaN, in the c, a, b order. */
206
- if (is_snan(c_cls)) {
207
- return 2;
208
- } else if (is_snan(a_cls)) {
209
- return 0;
210
- } else if (is_snan(b_cls)) {
211
- return 1;
212
- } else if (is_qnan(c_cls)) {
213
- return 2;
214
- } else if (is_qnan(a_cls)) {
215
- return 0;
216
- } else {
217
- return 1;
218
- }
219
- }
220
#elif defined(TARGET_LOONGARCH64)
221
- /* Prefer sNaN over qNaN, in the c, a, b order. */
222
- if (is_snan(c_cls)) {
223
- return 2;
224
- } else if (is_snan(a_cls)) {
225
- return 0;
226
- } else if (is_snan(b_cls)) {
227
- return 1;
228
- } else if (is_qnan(c_cls)) {
229
- return 2;
230
- } else if (is_qnan(a_cls)) {
231
- return 0;
232
- } else {
233
- return 1;
234
- }
235
+ rule = float_3nan_prop_s_cab;
236
#elif defined(TARGET_PPC)
237
- /* If fRA is a NaN return it; otherwise if fRB is a NaN return it;
238
- * otherwise return fRC. Note that muladd on PPC is (fRA * fRC) + frB
239
- */
240
- if (is_nan(a_cls)) {
241
- return 0;
242
- } else if (is_nan(c_cls)) {
243
- return 2;
244
- } else {
245
- return 1;
246
- }
247
+ /*
248
+ * If fRA is a NaN return it; otherwise if fRB is a NaN return it;
249
+ * otherwise return fRC. Note that muladd on PPC is (fRA * fRC) + frB
250
+ */
251
+ rule = float_3nan_prop_acb;
252
#elif defined(TARGET_S390X)
253
- if (is_snan(a_cls)) {
254
- return 0;
255
- } else if (is_snan(b_cls)) {
256
- return 1;
257
- } else if (is_snan(c_cls)) {
258
- return 2;
259
- } else if (is_qnan(a_cls)) {
260
- return 0;
261
- } else if (is_qnan(b_cls)) {
262
- return 1;
263
- } else {
264
- return 2;
265
- }
266
+ rule = float_3nan_prop_s_abc;
267
#elif defined(TARGET_SPARC)
268
- /* Prefer SNaN over QNaN, order C, B, A. */
269
- if (is_snan(c_cls)) {
270
- return 2;
271
- } else if (is_snan(b_cls)) {
272
- return 1;
273
- } else if (is_snan(a_cls)) {
274
- return 0;
275
- } else if (is_qnan(c_cls)) {
276
- return 2;
277
- } else if (is_qnan(b_cls)) {
278
- return 1;
279
- } else {
280
- return 0;
281
- }
282
+ rule = float_3nan_prop_s_cba;
283
#elif defined(TARGET_XTENSA)
284
- /*
285
- * For Xtensa, the (inf,zero,nan) case sets InvalidOp and returns
286
- * an input NaN if we have one (ie c).
287
- */
288
- if (status->use_first_nan) {
289
- if (is_nan(a_cls)) {
290
- return 0;
291
- } else if (is_nan(b_cls)) {
292
- return 1;
293
+ if (status->use_first_nan) {
294
+ rule = float_3nan_prop_abc;
295
} else {
296
- return 2;
297
+ rule = float_3nan_prop_cba;
298
}
299
- } else {
300
- if (is_nan(c_cls)) {
301
- return 2;
302
- } else if (is_nan(b_cls)) {
303
- return 1;
304
- } else {
305
- return 0;
306
- }
307
- }
308
#else
309
- /* A default implementation: prefer a to b to c.
310
- * This is unlikely to actually match any real implementation.
311
- */
312
- if (is_nan(a_cls)) {
313
- return 0;
314
- } else if (is_nan(b_cls)) {
315
- return 1;
316
- } else {
317
- return 2;
318
- }
319
+ rule = float_3nan_prop_abc;
320
#endif
321
+ }
322
+
323
+ assert(rule != float_3nan_prop_none);
324
+ if (have_snan && (rule & R_3NAN_SNAN_MASK)) {
325
+ /* We have at least one SNaN input and should prefer it */
326
+ do {
327
+ which = rule & R_3NAN_1ST_MASK;
328
+ rule >>= R_3NAN_1ST_LENGTH;
329
+ } while (!is_snan(cls[which]));
330
+ } else {
331
+ do {
332
+ which = rule & R_3NAN_1ST_MASK;
333
+ rule >>= R_3NAN_1ST_LENGTH;
334
+ } while (!is_nan(cls[which]));
335
+ }
336
+ return which;
50
}
337
}
51
338
339
/*----------------------------------------------------------------------------
52
--
340
--
53
2.20.1
341
2.34.1
54
55
diff view generated by jsdifflib
New patch
1
Explicitly set a rule in the softfloat tests for propagating NaNs in
2
the muladd case. In meson.build we put -DTARGET_ARM in fpcflags, and
3
so we should select here the Arm rule of float_3nan_prop_s_cab.
1
4
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20241202131347.498124-17-peter.maydell@linaro.org
8
---
9
tests/fp/fp-bench.c | 1 +
10
tests/fp/fp-test.c | 1 +
11
2 files changed, 2 insertions(+)
12
13
diff --git a/tests/fp/fp-bench.c b/tests/fp/fp-bench.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/tests/fp/fp-bench.c
16
+++ b/tests/fp/fp-bench.c
17
@@ -XXX,XX +XXX,XX @@ static void run_bench(void)
18
* doesn't specify match those used by the Arm architecture.
19
*/
20
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &soft_status);
21
+ set_float_3nan_prop_rule(float_3nan_prop_s_cab, &soft_status);
22
set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, &soft_status);
23
24
f = bench_funcs[operation][precision];
25
diff --git a/tests/fp/fp-test.c b/tests/fp/fp-test.c
26
index XXXXXXX..XXXXXXX 100644
27
--- a/tests/fp/fp-test.c
28
+++ b/tests/fp/fp-test.c
29
@@ -XXX,XX +XXX,XX @@ void run_test(void)
30
* doesn't specify match those used by the Arm architecture.
31
*/
32
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &qsf);
33
+ set_float_3nan_prop_rule(float_3nan_prop_s_cab, &qsf);
34
set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, &qsf);
35
36
genCases_setLevel(test_level);
37
--
38
2.34.1
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
Set the Float3NaNPropRule explicitly for Arm, and remove the
2
ifdef from pickNaNMulAdd().
2
3
3
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
4
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
5
Message-id: 20210212184902.1251044-31-richard.henderson@linaro.org
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20241202131347.498124-18-peter.maydell@linaro.org
7
---
7
---
8
target/arm/cpu.c | 15 +++++++++++++++
8
target/arm/cpu.c | 5 +++++
9
1 file changed, 15 insertions(+)
9
fpu/softfloat-specialize.c.inc | 8 +-------
10
2 files changed, 6 insertions(+), 7 deletions(-)
10
11
11
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
12
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
12
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
13
--- a/target/arm/cpu.c
14
--- a/target/arm/cpu.c
14
+++ b/target/arm/cpu.c
15
+++ b/target/arm/cpu.c
15
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_reset(DeviceState *dev)
16
@@ -XXX,XX +XXX,XX @@ void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook,
16
* Note that this must match useronly_clean_ptr.
17
* * tininess-before-rounding
17
*/
18
* * 2-input NaN propagation prefers SNaN over QNaN, and then
18
env->cp15.tcr_el[1].raw_tcr = (1ULL << 37);
19
* operand A over operand B (see FPProcessNaNs() pseudocode)
19
+
20
+ * * 3-input NaN propagation prefers SNaN over QNaN, and then
20
+ /* Enable MTE */
21
+ * operand C over A over B (see FPProcessNaNs3() pseudocode,
21
+ if (cpu_isar_feature(aa64_mte, cpu)) {
22
+ * but note that for QEMU muladd is a * b + c, whereas for
22
+ /* Enable tag access, but leave TCF0 as No Effect (0). */
23
+ * the pseudocode function the arguments are in the order c, a, b.
23
+ env->cp15.sctlr_el[1] |= SCTLR_ATA0;
24
* * 0 * Inf + NaN returns the default NaN if the input NaN is quiet,
24
+ /*
25
* and the input NaN if it is signalling
25
+ * Exclude all tags, so that tag 0 is always used.
26
*/
26
+ * This corresponds to Linux current->thread.gcr_incl = 0.
27
@@ -XXX,XX +XXX,XX @@ static void arm_set_default_fp_behaviours(float_status *s)
27
+ *
28
{
28
+ * Set RRND, so that helper_irg() will generate a seed later.
29
set_float_detect_tininess(float_tininess_before_rounding, s);
29
+ * Here in cpu_reset(), the crypto subsystem has not yet been
30
set_float_2nan_prop_rule(float_2nan_prop_s_ab, s);
30
+ * initialized.
31
+ set_float_3nan_prop_rule(float_3nan_prop_s_cab, s);
31
+ */
32
set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, s);
32
+ env->cp15.gcr_el1 = 0x1ffff;
33
}
33
+ }
34
34
#else
35
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
35
/* Reset into the highest available EL */
36
index XXXXXXX..XXXXXXX 100644
36
if (arm_feature(env, ARM_FEATURE_EL3)) {
37
--- a/fpu/softfloat-specialize.c.inc
38
+++ b/fpu/softfloat-specialize.c.inc
39
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
40
}
41
42
if (rule == float_3nan_prop_none) {
43
-#if defined(TARGET_ARM)
44
- /*
45
- * This looks different from the ARM ARM pseudocode, because the ARM ARM
46
- * puts the operands to a fused mac operation (a*b)+c in the order c,a,b
47
- */
48
- rule = float_3nan_prop_s_cab;
49
-#elif defined(TARGET_MIPS)
50
+#if defined(TARGET_MIPS)
51
if (snan_bit_is_one(status)) {
52
rule = float_3nan_prop_s_abc;
53
} else {
37
--
54
--
38
2.20.1
55
2.34.1
39
40
diff view generated by jsdifflib
New patch
1
Set the Float3NaNPropRule explicitly for loongarch, and remove the
2
ifdef from pickNaNMulAdd().
1
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20241202131347.498124-19-peter.maydell@linaro.org
7
---
8
target/loongarch/tcg/fpu_helper.c | 1 +
9
fpu/softfloat-specialize.c.inc | 2 --
10
2 files changed, 1 insertion(+), 2 deletions(-)
11
12
diff --git a/target/loongarch/tcg/fpu_helper.c b/target/loongarch/tcg/fpu_helper.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/target/loongarch/tcg/fpu_helper.c
15
+++ b/target/loongarch/tcg/fpu_helper.c
16
@@ -XXX,XX +XXX,XX @@ void restore_fp_status(CPULoongArchState *env)
17
* case sets InvalidOp and returns the input value 'c'
18
*/
19
set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
20
+ set_float_3nan_prop_rule(float_3nan_prop_s_cab, &env->fp_status);
21
}
22
23
int ieee_ex_to_loongarch(int xcpt)
24
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
25
index XXXXXXX..XXXXXXX 100644
26
--- a/fpu/softfloat-specialize.c.inc
27
+++ b/fpu/softfloat-specialize.c.inc
28
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
29
} else {
30
rule = float_3nan_prop_s_cab;
31
}
32
-#elif defined(TARGET_LOONGARCH64)
33
- rule = float_3nan_prop_s_cab;
34
#elif defined(TARGET_PPC)
35
/*
36
* If fRA is a NaN return it; otherwise if fRB is a NaN return it;
37
--
38
2.34.1
diff view generated by jsdifflib
New patch
1
Set the Float3NaNPropRule explicitly for PPC, and remove the
2
ifdef from pickNaNMulAdd().
1
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20241202131347.498124-20-peter.maydell@linaro.org
7
---
8
target/ppc/cpu_init.c | 8 ++++++++
9
fpu/softfloat-specialize.c.inc | 6 ------
10
2 files changed, 8 insertions(+), 6 deletions(-)
11
12
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/target/ppc/cpu_init.c
15
+++ b/target/ppc/cpu_init.c
16
@@ -XXX,XX +XXX,XX @@ static void ppc_cpu_reset_hold(Object *obj, ResetType type)
17
*/
18
set_float_2nan_prop_rule(float_2nan_prop_ab, &env->fp_status);
19
set_float_2nan_prop_rule(float_2nan_prop_ab, &env->vec_status);
20
+ /*
21
+ * NaN propagation for fused multiply-add:
22
+ * if fRA is a NaN return it; otherwise if fRB is a NaN return it;
23
+ * otherwise return fRC. Note that muladd on PPC is (fRA * fRC) + frB
24
+ * whereas QEMU labels the operands as (a * b) + c.
25
+ */
26
+ set_float_3nan_prop_rule(float_3nan_prop_acb, &env->fp_status);
27
+ set_float_3nan_prop_rule(float_3nan_prop_acb, &env->vec_status);
28
/*
29
* For PPC, the (inf,zero,qnan) case sets InvalidOp, but we prefer
30
* to return an input NaN if we have one (ie c) rather than generating
31
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
32
index XXXXXXX..XXXXXXX 100644
33
--- a/fpu/softfloat-specialize.c.inc
34
+++ b/fpu/softfloat-specialize.c.inc
35
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
36
} else {
37
rule = float_3nan_prop_s_cab;
38
}
39
-#elif defined(TARGET_PPC)
40
- /*
41
- * If fRA is a NaN return it; otherwise if fRB is a NaN return it;
42
- * otherwise return fRC. Note that muladd on PPC is (fRA * fRC) + frB
43
- */
44
- rule = float_3nan_prop_acb;
45
#elif defined(TARGET_S390X)
46
rule = float_3nan_prop_s_abc;
47
#elif defined(TARGET_SPARC)
48
--
49
2.34.1
diff view generated by jsdifflib
New patch
1
Set the Float3NaNPropRule explicitly for s390x, and remove the
2
ifdef from pickNaNMulAdd().
1
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20241202131347.498124-21-peter.maydell@linaro.org
7
---
8
target/s390x/cpu.c | 1 +
9
fpu/softfloat-specialize.c.inc | 2 --
10
2 files changed, 1 insertion(+), 2 deletions(-)
11
12
diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/target/s390x/cpu.c
15
+++ b/target/s390x/cpu.c
16
@@ -XXX,XX +XXX,XX @@ static void s390_cpu_reset_hold(Object *obj, ResetType type)
17
set_float_detect_tininess(float_tininess_before_rounding,
18
&env->fpu_status);
19
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &env->fpu_status);
20
+ set_float_3nan_prop_rule(float_3nan_prop_s_abc, &env->fpu_status);
21
set_float_infzeronan_rule(float_infzeronan_dnan_always,
22
&env->fpu_status);
23
/* fall through */
24
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
25
index XXXXXXX..XXXXXXX 100644
26
--- a/fpu/softfloat-specialize.c.inc
27
+++ b/fpu/softfloat-specialize.c.inc
28
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
29
} else {
30
rule = float_3nan_prop_s_cab;
31
}
32
-#elif defined(TARGET_S390X)
33
- rule = float_3nan_prop_s_abc;
34
#elif defined(TARGET_SPARC)
35
rule = float_3nan_prop_s_cba;
36
#elif defined(TARGET_XTENSA)
37
--
38
2.34.1
diff view generated by jsdifflib
New patch
1
Set the Float3NaNPropRule explicitly for SPARC, and remove the
2
ifdef from pickNaNMulAdd().
1
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20241202131347.498124-22-peter.maydell@linaro.org
7
---
8
target/sparc/cpu.c | 2 ++
9
fpu/softfloat-specialize.c.inc | 2 --
10
2 files changed, 2 insertions(+), 2 deletions(-)
11
12
diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/target/sparc/cpu.c
15
+++ b/target/sparc/cpu.c
16
@@ -XXX,XX +XXX,XX @@ static void sparc_cpu_realizefn(DeviceState *dev, Error **errp)
17
* the CPU state struct so it won't get zeroed on reset.
18
*/
19
set_float_2nan_prop_rule(float_2nan_prop_s_ba, &env->fp_status);
20
+ /* For fused-multiply add, prefer SNaN over QNaN, then C->B->A */
21
+ set_float_3nan_prop_rule(float_3nan_prop_s_cba, &env->fp_status);
22
/* For inf * 0 + NaN, return the input NaN */
23
set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
24
25
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
26
index XXXXXXX..XXXXXXX 100644
27
--- a/fpu/softfloat-specialize.c.inc
28
+++ b/fpu/softfloat-specialize.c.inc
29
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
30
} else {
31
rule = float_3nan_prop_s_cab;
32
}
33
-#elif defined(TARGET_SPARC)
34
- rule = float_3nan_prop_s_cba;
35
#elif defined(TARGET_XTENSA)
36
if (status->use_first_nan) {
37
rule = float_3nan_prop_abc;
38
--
39
2.34.1
diff view generated by jsdifflib
New patch
1
Set the Float3NaNPropRule explicitly for Arm, and remove the
2
ifdef from pickNaNMulAdd().
1
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20241202131347.498124-23-peter.maydell@linaro.org
7
---
8
target/mips/fpu_helper.h | 4 ++++
9
target/mips/msa.c | 3 +++
10
fpu/softfloat-specialize.c.inc | 8 +-------
11
3 files changed, 8 insertions(+), 7 deletions(-)
12
13
diff --git a/target/mips/fpu_helper.h b/target/mips/fpu_helper.h
14
index XXXXXXX..XXXXXXX 100644
15
--- a/target/mips/fpu_helper.h
16
+++ b/target/mips/fpu_helper.h
17
@@ -XXX,XX +XXX,XX @@ static inline void restore_snan_bit_mode(CPUMIPSState *env)
18
{
19
bool nan2008 = env->active_fpu.fcr31 & (1 << FCR31_NAN2008);
20
FloatInfZeroNaNRule izn_rule;
21
+ Float3NaNPropRule nan3_rule;
22
23
/*
24
* With nan2008, SNaNs are silenced in the usual way.
25
@@ -XXX,XX +XXX,XX @@ static inline void restore_snan_bit_mode(CPUMIPSState *env)
26
*/
27
izn_rule = nan2008 ? float_infzeronan_dnan_never : float_infzeronan_dnan_always;
28
set_float_infzeronan_rule(izn_rule, &env->active_fpu.fp_status);
29
+ nan3_rule = nan2008 ? float_3nan_prop_s_cab : float_3nan_prop_s_abc;
30
+ set_float_3nan_prop_rule(nan3_rule, &env->active_fpu.fp_status);
31
+
32
}
33
34
static inline void restore_fp_status(CPUMIPSState *env)
35
diff --git a/target/mips/msa.c b/target/mips/msa.c
36
index XXXXXXX..XXXXXXX 100644
37
--- a/target/mips/msa.c
38
+++ b/target/mips/msa.c
39
@@ -XXX,XX +XXX,XX @@ void msa_reset(CPUMIPSState *env)
40
set_float_2nan_prop_rule(float_2nan_prop_s_ab,
41
&env->active_tc.msa_fp_status);
42
43
+ set_float_3nan_prop_rule(float_3nan_prop_s_cab,
44
+ &env->active_tc.msa_fp_status);
45
+
46
/* clear float_status exception flags */
47
set_float_exception_flags(0, &env->active_tc.msa_fp_status);
48
49
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
50
index XXXXXXX..XXXXXXX 100644
51
--- a/fpu/softfloat-specialize.c.inc
52
+++ b/fpu/softfloat-specialize.c.inc
53
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
54
}
55
56
if (rule == float_3nan_prop_none) {
57
-#if defined(TARGET_MIPS)
58
- if (snan_bit_is_one(status)) {
59
- rule = float_3nan_prop_s_abc;
60
- } else {
61
- rule = float_3nan_prop_s_cab;
62
- }
63
-#elif defined(TARGET_XTENSA)
64
+#if defined(TARGET_XTENSA)
65
if (status->use_first_nan) {
66
rule = float_3nan_prop_abc;
67
} else {
68
--
69
2.34.1
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
Set the Float3NaNPropRule explicitly for xtensa, and remove the
2
ifdef from pickNaNMulAdd().
2
3
3
Provide both tagged and untagged versions of access_ok.
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
In a few places use thread_cpu, as the user is several
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
callees removed from do_syscall1.
6
Message-id: 20241202131347.498124-24-peter.maydell@linaro.org
7
---
8
target/xtensa/fpu_helper.c | 2 ++
9
fpu/softfloat-specialize.c.inc | 8 --------
10
2 files changed, 2 insertions(+), 8 deletions(-)
6
11
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
12
diff --git a/target/xtensa/fpu_helper.c b/target/xtensa/fpu_helper.c
8
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
9
Message-id: 20210212184902.1251044-17-richard.henderson@linaro.org
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
12
linux-user/qemu.h | 11 +++++++++--
13
linux-user/elfload.c | 2 +-
14
linux-user/hppa/cpu_loop.c | 8 ++++----
15
linux-user/i386/cpu_loop.c | 2 +-
16
linux-user/i386/signal.c | 5 +++--
17
linux-user/syscall.c | 9 ++++++---
18
6 files changed, 24 insertions(+), 13 deletions(-)
19
20
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
21
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
22
--- a/linux-user/qemu.h
14
--- a/target/xtensa/fpu_helper.c
23
+++ b/linux-user/qemu.h
15
+++ b/target/xtensa/fpu_helper.c
24
@@ -XXX,XX +XXX,XX @@ extern unsigned long guest_stack_size;
16
@@ -XXX,XX +XXX,XX @@ void xtensa_use_first_nan(CPUXtensaState *env, bool use_first)
25
#define VERIFY_READ PAGE_READ
17
set_use_first_nan(use_first, &env->fp_status);
26
#define VERIFY_WRITE (PAGE_READ | PAGE_WRITE)
18
set_float_2nan_prop_rule(use_first ? float_2nan_prop_ab : float_2nan_prop_ba,
27
19
&env->fp_status);
28
-static inline bool access_ok(int type, abi_ulong addr, abi_ulong size)
20
+ set_float_3nan_prop_rule(use_first ? float_3nan_prop_abc : float_3nan_prop_cba,
29
+static inline bool access_ok_untagged(int type, abi_ulong addr, abi_ulong size)
21
+ &env->fp_status);
30
{
31
if (size == 0
32
? !guest_addr_valid_untagged(addr)
33
@@ -XXX,XX +XXX,XX @@ static inline bool access_ok(int type, abi_ulong addr, abi_ulong size)
34
return page_check_range((target_ulong)addr, size, type) == 0;
35
}
22
}
36
23
37
+static inline bool access_ok(CPUState *cpu, int type,
24
void HELPER(wur_fpu2k_fcr)(CPUXtensaState *env, uint32_t v)
38
+ abi_ulong addr, abi_ulong size)
25
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
39
+{
40
+ return access_ok_untagged(type, cpu_untagged_addr(cpu, addr), size);
41
+}
42
+
43
/* NOTE __get_user and __put_user use host pointers and don't check access.
44
These are usually used to access struct data members once the struct has
45
been locked - usually with lock_user_struct. */
46
@@ -XXX,XX +XXX,XX @@ abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len);
47
host area will have the same contents as the guest. */
48
static inline void *lock_user(int type, abi_ulong guest_addr, long len, int copy)
49
{
50
- if (!access_ok(type, guest_addr, len))
51
+ if (!access_ok_untagged(type, guest_addr, len)) {
52
return NULL;
53
+ }
54
#ifdef DEBUG_REMAP
55
{
56
void *addr;
57
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
58
index XXXXXXX..XXXXXXX 100644
26
index XXXXXXX..XXXXXXX 100644
59
--- a/linux-user/elfload.c
27
--- a/fpu/softfloat-specialize.c.inc
60
+++ b/linux-user/elfload.c
28
+++ b/fpu/softfloat-specialize.c.inc
61
@@ -XXX,XX +XXX,XX @@ static int vma_get_mapping_count(const struct mm_struct *mm)
29
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
62
static abi_ulong vma_dump_size(const struct vm_area_struct *vma)
63
{
64
/* if we cannot even read the first page, skip it */
65
- if (!access_ok(VERIFY_READ, vma->vma_start, TARGET_PAGE_SIZE))
66
+ if (!access_ok_untagged(VERIFY_READ, vma->vma_start, TARGET_PAGE_SIZE))
67
return (0);
68
69
/*
70
diff --git a/linux-user/hppa/cpu_loop.c b/linux-user/hppa/cpu_loop.c
71
index XXXXXXX..XXXXXXX 100644
72
--- a/linux-user/hppa/cpu_loop.c
73
+++ b/linux-user/hppa/cpu_loop.c
74
@@ -XXX,XX +XXX,XX @@ static abi_ulong hppa_lws(CPUHPPAState *env)
75
return -TARGET_ENOSYS;
76
77
case 0: /* elf32 atomic 32bit cmpxchg */
78
- if ((addr & 3) || !access_ok(VERIFY_WRITE, addr, 4)) {
79
+ if ((addr & 3) || !access_ok(cs, VERIFY_WRITE, addr, 4)) {
80
return -TARGET_EFAULT;
81
}
82
old = tswap32(old);
83
@@ -XXX,XX +XXX,XX @@ static abi_ulong hppa_lws(CPUHPPAState *env)
84
return -TARGET_ENOSYS;
85
}
86
if (((addr | old | new) & ((1 << size) - 1))
87
- || !access_ok(VERIFY_WRITE, addr, 1 << size)
88
- || !access_ok(VERIFY_READ, old, 1 << size)
89
- || !access_ok(VERIFY_READ, new, 1 << size)) {
90
+ || !access_ok(cs, VERIFY_WRITE, addr, 1 << size)
91
+ || !access_ok(cs, VERIFY_READ, old, 1 << size)
92
+ || !access_ok(cs, VERIFY_READ, new, 1 << size)) {
93
return -TARGET_EFAULT;
94
}
95
/* Note that below we use host-endian loads so that the cmpxchg
96
diff --git a/linux-user/i386/cpu_loop.c b/linux-user/i386/cpu_loop.c
97
index XXXXXXX..XXXXXXX 100644
98
--- a/linux-user/i386/cpu_loop.c
99
+++ b/linux-user/i386/cpu_loop.c
100
@@ -XXX,XX +XXX,XX @@ static bool write_ok_or_segv(CPUX86State *env, abi_ptr addr, size_t len)
101
* For all the vsyscalls, NULL means "don't write anything" not
102
* "write it at address 0".
103
*/
104
- if (addr == 0 || access_ok(VERIFY_WRITE, addr, len)) {
105
+ if (addr == 0 || access_ok(env_cpu(env), VERIFY_WRITE, addr, len)) {
106
return true;
107
}
30
}
108
31
109
diff --git a/linux-user/i386/signal.c b/linux-user/i386/signal.c
32
if (rule == float_3nan_prop_none) {
110
index XXXXXXX..XXXXXXX 100644
33
-#if defined(TARGET_XTENSA)
111
--- a/linux-user/i386/signal.c
34
- if (status->use_first_nan) {
112
+++ b/linux-user/i386/signal.c
35
- rule = float_3nan_prop_abc;
113
@@ -XXX,XX +XXX,XX @@ restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc)
36
- } else {
114
37
- rule = float_3nan_prop_cba;
115
fpstate_addr = tswapl(sc->fpstate);
38
- }
116
if (fpstate_addr != 0) {
39
-#else
117
- if (!access_ok(VERIFY_READ, fpstate_addr,
40
rule = float_3nan_prop_abc;
118
- sizeof(struct target_fpstate)))
41
-#endif
119
+ if (!access_ok(env_cpu(env), VERIFY_READ, fpstate_addr,
120
+ sizeof(struct target_fpstate))) {
121
goto badframe;
122
+ }
123
#ifndef TARGET_X86_64
124
cpu_x86_frstor(env, fpstate_addr, 1);
125
#else
126
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
127
index XXXXXXX..XXXXXXX 100644
128
--- a/linux-user/syscall.c
129
+++ b/linux-user/syscall.c
130
@@ -XXX,XX +XXX,XX @@ static abi_long do_accept4(int fd, abi_ulong target_addr,
131
return -TARGET_EINVAL;
132
}
42
}
133
43
134
- if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
44
assert(rule != float_3nan_prop_none);
135
+ if (!access_ok(thread_cpu, VERIFY_WRITE, target_addr, addrlen)) {
136
return -TARGET_EFAULT;
137
+ }
138
139
addr = alloca(addrlen);
140
141
@@ -XXX,XX +XXX,XX @@ static abi_long do_getpeername(int fd, abi_ulong target_addr,
142
return -TARGET_EINVAL;
143
}
144
145
- if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
146
+ if (!access_ok(thread_cpu, VERIFY_WRITE, target_addr, addrlen)) {
147
return -TARGET_EFAULT;
148
+ }
149
150
addr = alloca(addrlen);
151
152
@@ -XXX,XX +XXX,XX @@ static abi_long do_getsockname(int fd, abi_ulong target_addr,
153
return -TARGET_EINVAL;
154
}
155
156
- if (!access_ok(VERIFY_WRITE, target_addr, addrlen))
157
+ if (!access_ok(thread_cpu, VERIFY_WRITE, target_addr, addrlen)) {
158
return -TARGET_EFAULT;
159
+ }
160
161
addr = alloca(addrlen);
162
163
--
45
--
164
2.20.1
46
2.34.1
165
166
diff view generated by jsdifflib
New patch
1
Set the Float3NaNPropRule explicitly for i386. We had no
2
i386-specific behaviour in the old ifdef ladder, so we were using the
3
default "prefer a then b then c" fallback; this is actually the
4
correct per-the-spec handling for i386.
1
5
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20241202131347.498124-25-peter.maydell@linaro.org
9
---
10
target/i386/tcg/fpu_helper.c | 1 +
11
1 file changed, 1 insertion(+)
12
13
diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/target/i386/tcg/fpu_helper.c
16
+++ b/target/i386/tcg/fpu_helper.c
17
@@ -XXX,XX +XXX,XX @@ void cpu_init_fp_statuses(CPUX86State *env)
18
* there are multiple input NaNs they are selected in the order a, b, c.
19
*/
20
set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->sse_status);
21
+ set_float_3nan_prop_rule(float_3nan_prop_abc, &env->sse_status);
22
}
23
24
static inline uint8_t save_exception_flags(CPUX86State *env)
25
--
26
2.34.1
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
Set the Float3NaNPropRule explicitly for HPPA, and remove the
2
ifdef from pickNaNMulAdd().
2
3
3
These prctl fields are required for the function of MTE.
4
HPPA is the only target that was using the default branch of the
5
ifdef ladder (other targets either do not use muladd or set
6
default_nan_mode), so we can remove the ifdef fallback entirely now
7
(allowing the "rule not set" case to fall into the default of the
8
switch statement and assert).
4
9
5
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
We add a TODO note that the HPPA rule is probably wrong; this is
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
11
not a behavioural change for this refactoring.
7
Message-id: 20210212184902.1251044-24-richard.henderson@linaro.org
12
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
15
Message-id: 20241202131347.498124-26-peter.maydell@linaro.org
9
---
16
---
10
linux-user/aarch64/target_syscall.h | 9 ++++++
17
target/hppa/fpu_helper.c | 8 ++++++++
11
linux-user/syscall.c | 43 +++++++++++++++++++++++++++++
18
fpu/softfloat-specialize.c.inc | 4 ----
12
2 files changed, 52 insertions(+)
19
2 files changed, 8 insertions(+), 4 deletions(-)
13
20
14
diff --git a/linux-user/aarch64/target_syscall.h b/linux-user/aarch64/target_syscall.h
21
diff --git a/target/hppa/fpu_helper.c b/target/hppa/fpu_helper.c
15
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
16
--- a/linux-user/aarch64/target_syscall.h
23
--- a/target/hppa/fpu_helper.c
17
+++ b/linux-user/aarch64/target_syscall.h
24
+++ b/target/hppa/fpu_helper.c
18
@@ -XXX,XX +XXX,XX @@ struct target_pt_regs {
25
@@ -XXX,XX +XXX,XX @@ void HELPER(loaded_fr0)(CPUHPPAState *env)
19
#define TARGET_PR_SET_TAGGED_ADDR_CTRL 55
26
* HPPA does note implement a CPU reset method at all...
20
#define TARGET_PR_GET_TAGGED_ADDR_CTRL 56
27
*/
21
# define TARGET_PR_TAGGED_ADDR_ENABLE (1UL << 0)
28
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &env->fp_status);
22
+/* MTE tag check fault modes */
29
+ /*
23
+# define TARGET_PR_MTE_TCF_SHIFT 1
30
+ * TODO: The HPPA architecture reference only documents its NaN
24
+# define TARGET_PR_MTE_TCF_NONE (0UL << TARGET_PR_MTE_TCF_SHIFT)
31
+ * propagation rule for 2-operand operations. Testing on real hardware
25
+# define TARGET_PR_MTE_TCF_SYNC (1UL << TARGET_PR_MTE_TCF_SHIFT)
32
+ * might be necessary to confirm whether this order for muladd is correct.
26
+# define TARGET_PR_MTE_TCF_ASYNC (2UL << TARGET_PR_MTE_TCF_SHIFT)
33
+ * Not preferring the SNaN is almost certainly incorrect as it diverges
27
+# define TARGET_PR_MTE_TCF_MASK (3UL << TARGET_PR_MTE_TCF_SHIFT)
34
+ * from the documented rules for 2-operand operations.
28
+/* MTE tag inclusion mask */
35
+ */
29
+# define TARGET_PR_MTE_TAG_SHIFT 3
36
+ set_float_3nan_prop_rule(float_3nan_prop_abc, &env->fp_status);
30
+# define TARGET_PR_MTE_TAG_MASK (0xffffUL << TARGET_PR_MTE_TAG_SHIFT)
37
/* For inf * 0 + NaN, return the input NaN */
31
38
set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
32
#endif /* AARCH64_TARGET_SYSCALL_H */
39
}
33
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
40
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
34
index XXXXXXX..XXXXXXX 100644
41
index XXXXXXX..XXXXXXX 100644
35
--- a/linux-user/syscall.c
42
--- a/fpu/softfloat-specialize.c.inc
36
+++ b/linux-user/syscall.c
43
+++ b/fpu/softfloat-specialize.c.inc
37
@@ -XXX,XX +XXX,XX @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
44
@@ -XXX,XX +XXX,XX @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
38
{
45
}
39
abi_ulong valid_mask = TARGET_PR_TAGGED_ADDR_ENABLE;
46
}
40
CPUARMState *env = cpu_env;
47
41
+ ARMCPU *cpu = env_archcpu(env);
48
- if (rule == float_3nan_prop_none) {
42
+
49
- rule = float_3nan_prop_abc;
43
+ if (cpu_isar_feature(aa64_mte, cpu)) {
50
- }
44
+ valid_mask |= TARGET_PR_MTE_TCF_MASK;
51
-
45
+ valid_mask |= TARGET_PR_MTE_TAG_MASK;
52
assert(rule != float_3nan_prop_none);
46
+ }
53
if (have_snan && (rule & R_3NAN_SNAN_MASK)) {
47
54
/* We have at least one SNaN input and should prefer it */
48
if ((arg2 & ~valid_mask) || arg3 || arg4 || arg5) {
49
return -TARGET_EINVAL;
50
}
51
env->tagged_addr_enable = arg2 & TARGET_PR_TAGGED_ADDR_ENABLE;
52
+
53
+ if (cpu_isar_feature(aa64_mte, cpu)) {
54
+ switch (arg2 & TARGET_PR_MTE_TCF_MASK) {
55
+ case TARGET_PR_MTE_TCF_NONE:
56
+ case TARGET_PR_MTE_TCF_SYNC:
57
+ case TARGET_PR_MTE_TCF_ASYNC:
58
+ break;
59
+ default:
60
+ return -EINVAL;
61
+ }
62
+
63
+ /*
64
+ * Write PR_MTE_TCF to SCTLR_EL1[TCF0].
65
+ * Note that the syscall values are consistent with hw.
66
+ */
67
+ env->cp15.sctlr_el[1] =
68
+ deposit64(env->cp15.sctlr_el[1], 38, 2,
69
+ arg2 >> TARGET_PR_MTE_TCF_SHIFT);
70
+
71
+ /*
72
+ * Write PR_MTE_TAG to GCR_EL1[Exclude].
73
+ * Note that the syscall uses an include mask,
74
+ * and hardware uses an exclude mask -- invert.
75
+ */
76
+ env->cp15.gcr_el1 =
77
+ deposit64(env->cp15.gcr_el1, 0, 16,
78
+ ~arg2 >> TARGET_PR_MTE_TAG_SHIFT);
79
+ arm_rebuild_hflags(env);
80
+ }
81
return 0;
82
}
83
case TARGET_PR_GET_TAGGED_ADDR_CTRL:
84
{
85
abi_long ret = 0;
86
CPUARMState *env = cpu_env;
87
+ ARMCPU *cpu = env_archcpu(env);
88
89
if (arg2 || arg3 || arg4 || arg5) {
90
return -TARGET_EINVAL;
91
@@ -XXX,XX +XXX,XX @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
92
if (env->tagged_addr_enable) {
93
ret |= TARGET_PR_TAGGED_ADDR_ENABLE;
94
}
95
+ if (cpu_isar_feature(aa64_mte, cpu)) {
96
+ /* See above. */
97
+ ret |= (extract64(env->cp15.sctlr_el[1], 38, 2)
98
+ << TARGET_PR_MTE_TCF_SHIFT);
99
+ ret = deposit64(ret, TARGET_PR_MTE_TAG_SHIFT, 16,
100
+ ~env->cp15.gcr_el1);
101
+ }
102
return ret;
103
}
104
#endif /* AARCH64 */
105
--
55
--
106
2.20.1
56
2.34.1
107
108
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
The use_first_nan field in float_status was an xtensa-specific way to
2
select at runtime from two different NaN propagation rules. Now that
3
xtensa is using the target-agnostic NaN propagation rule selection
4
that we've just added, we can remove use_first_nan, because there is
5
no longer any code that reads it.
2
6
3
Move everything related to syndromes to a new file,
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
which can be shared with linux-user.
8
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
9
Message-id: 20241202131347.498124-27-peter.maydell@linaro.org
10
---
11
include/fpu/softfloat-helpers.h | 5 -----
12
include/fpu/softfloat-types.h | 1 -
13
target/xtensa/fpu_helper.c | 1 -
14
3 files changed, 7 deletions(-)
5
15
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
16
diff --git a/include/fpu/softfloat-helpers.h b/include/fpu/softfloat-helpers.h
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Message-id: 20210212184902.1251044-26-richard.henderson@linaro.org
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
12
target/arm/internals.h | 245 +-----------------------------------
13
target/arm/syndrome.h | 273 +++++++++++++++++++++++++++++++++++++++++
14
2 files changed, 274 insertions(+), 244 deletions(-)
15
create mode 100644 target/arm/syndrome.h
16
17
diff --git a/target/arm/internals.h b/target/arm/internals.h
18
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
19
--- a/target/arm/internals.h
18
--- a/include/fpu/softfloat-helpers.h
20
+++ b/target/arm/internals.h
19
+++ b/include/fpu/softfloat-helpers.h
21
@@ -XXX,XX +XXX,XX @@
20
@@ -XXX,XX +XXX,XX @@ static inline void set_snan_bit_is_one(bool val, float_status *status)
22
#define TARGET_ARM_INTERNALS_H
21
status->snan_bit_is_one = val;
23
24
#include "hw/registerfields.h"
25
+#include "syndrome.h"
26
27
/* register banks for CPU modes */
28
#define BANK_USRSYS 0
29
@@ -XXX,XX +XXX,XX @@ static inline bool extended_addresses_enabled(CPUARMState *env)
30
(arm_feature(env, ARM_FEATURE_LPAE) && (tcr->raw_tcr & TTBCR_EAE));
31
}
22
}
32
23
33
-/* Valid Syndrome Register EC field values */
24
-static inline void set_use_first_nan(bool val, float_status *status)
34
-enum arm_exception_class {
35
- EC_UNCATEGORIZED = 0x00,
36
- EC_WFX_TRAP = 0x01,
37
- EC_CP15RTTRAP = 0x03,
38
- EC_CP15RRTTRAP = 0x04,
39
- EC_CP14RTTRAP = 0x05,
40
- EC_CP14DTTRAP = 0x06,
41
- EC_ADVSIMDFPACCESSTRAP = 0x07,
42
- EC_FPIDTRAP = 0x08,
43
- EC_PACTRAP = 0x09,
44
- EC_CP14RRTTRAP = 0x0c,
45
- EC_BTITRAP = 0x0d,
46
- EC_ILLEGALSTATE = 0x0e,
47
- EC_AA32_SVC = 0x11,
48
- EC_AA32_HVC = 0x12,
49
- EC_AA32_SMC = 0x13,
50
- EC_AA64_SVC = 0x15,
51
- EC_AA64_HVC = 0x16,
52
- EC_AA64_SMC = 0x17,
53
- EC_SYSTEMREGISTERTRAP = 0x18,
54
- EC_SVEACCESSTRAP = 0x19,
55
- EC_INSNABORT = 0x20,
56
- EC_INSNABORT_SAME_EL = 0x21,
57
- EC_PCALIGNMENT = 0x22,
58
- EC_DATAABORT = 0x24,
59
- EC_DATAABORT_SAME_EL = 0x25,
60
- EC_SPALIGNMENT = 0x26,
61
- EC_AA32_FPTRAP = 0x28,
62
- EC_AA64_FPTRAP = 0x2c,
63
- EC_SERROR = 0x2f,
64
- EC_BREAKPOINT = 0x30,
65
- EC_BREAKPOINT_SAME_EL = 0x31,
66
- EC_SOFTWARESTEP = 0x32,
67
- EC_SOFTWARESTEP_SAME_EL = 0x33,
68
- EC_WATCHPOINT = 0x34,
69
- EC_WATCHPOINT_SAME_EL = 0x35,
70
- EC_AA32_BKPT = 0x38,
71
- EC_VECTORCATCH = 0x3a,
72
- EC_AA64_BKPT = 0x3c,
73
-};
74
-
75
-#define ARM_EL_EC_SHIFT 26
76
-#define ARM_EL_IL_SHIFT 25
77
-#define ARM_EL_ISV_SHIFT 24
78
-#define ARM_EL_IL (1 << ARM_EL_IL_SHIFT)
79
-#define ARM_EL_ISV (1 << ARM_EL_ISV_SHIFT)
80
-
81
-static inline uint32_t syn_get_ec(uint32_t syn)
82
-{
25
-{
83
- return syn >> ARM_EL_EC_SHIFT;
26
- status->use_first_nan = val;
84
-}
27
-}
85
-
28
-
86
-/* Utility functions for constructing various kinds of syndrome value.
29
static inline void set_no_signaling_nans(bool val, float_status *status)
87
- * Note that in general we follow the AArch64 syndrome values; in a
30
{
88
- * few cases the value in HSR for exceptions taken to AArch32 Hyp
31
status->no_signaling_nans = val;
89
- * mode differs slightly, and we fix this up when populating HSR in
32
diff --git a/include/fpu/softfloat-types.h b/include/fpu/softfloat-types.h
90
- * arm_cpu_do_interrupt_aarch32_hyp().
33
index XXXXXXX..XXXXXXX 100644
91
- * The exception is FP/SIMD access traps -- these report extra information
34
--- a/include/fpu/softfloat-types.h
92
- * when taking an exception to AArch32. For those we include the extra coproc
35
+++ b/include/fpu/softfloat-types.h
93
- * and TA fields, and mask them out when taking the exception to AArch64.
36
@@ -XXX,XX +XXX,XX @@ typedef struct float_status {
94
- */
37
* softfloat-specialize.inc.c)
95
-static inline uint32_t syn_uncategorized(void)
38
*/
96
-{
39
bool snan_bit_is_one;
97
- return (EC_UNCATEGORIZED << ARM_EL_EC_SHIFT) | ARM_EL_IL;
40
- bool use_first_nan;
98
-}
41
bool no_signaling_nans;
99
-
42
/* should overflowed results subtract re_bias to its exponent? */
100
-static inline uint32_t syn_aa64_svc(uint32_t imm16)
43
bool rebias_overflow;
101
-{
44
diff --git a/target/xtensa/fpu_helper.c b/target/xtensa/fpu_helper.c
102
- return (EC_AA64_SVC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff);
45
index XXXXXXX..XXXXXXX 100644
103
-}
46
--- a/target/xtensa/fpu_helper.c
104
-
47
+++ b/target/xtensa/fpu_helper.c
105
-static inline uint32_t syn_aa64_hvc(uint32_t imm16)
48
@@ -XXX,XX +XXX,XX @@ static const struct {
106
-{
49
107
- return (EC_AA64_HVC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff);
50
void xtensa_use_first_nan(CPUXtensaState *env, bool use_first)
108
-}
51
{
109
-
52
- set_use_first_nan(use_first, &env->fp_status);
110
-static inline uint32_t syn_aa64_smc(uint32_t imm16)
53
set_float_2nan_prop_rule(use_first ? float_2nan_prop_ab : float_2nan_prop_ba,
111
-{
54
&env->fp_status);
112
- return (EC_AA64_SMC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff);
55
set_float_3nan_prop_rule(use_first ? float_3nan_prop_abc : float_3nan_prop_cba,
113
-}
114
-
115
-static inline uint32_t syn_aa32_svc(uint32_t imm16, bool is_16bit)
116
-{
117
- return (EC_AA32_SVC << ARM_EL_EC_SHIFT) | (imm16 & 0xffff)
118
- | (is_16bit ? 0 : ARM_EL_IL);
119
-}
120
-
121
-static inline uint32_t syn_aa32_hvc(uint32_t imm16)
122
-{
123
- return (EC_AA32_HVC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff);
124
-}
125
-
126
-static inline uint32_t syn_aa32_smc(void)
127
-{
128
- return (EC_AA32_SMC << ARM_EL_EC_SHIFT) | ARM_EL_IL;
129
-}
130
-
131
-static inline uint32_t syn_aa64_bkpt(uint32_t imm16)
132
-{
133
- return (EC_AA64_BKPT << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff);
134
-}
135
-
136
-static inline uint32_t syn_aa32_bkpt(uint32_t imm16, bool is_16bit)
137
-{
138
- return (EC_AA32_BKPT << ARM_EL_EC_SHIFT) | (imm16 & 0xffff)
139
- | (is_16bit ? 0 : ARM_EL_IL);
140
-}
141
-
142
-static inline uint32_t syn_aa64_sysregtrap(int op0, int op1, int op2,
143
- int crn, int crm, int rt,
144
- int isread)
145
-{
146
- return (EC_SYSTEMREGISTERTRAP << ARM_EL_EC_SHIFT) | ARM_EL_IL
147
- | (op0 << 20) | (op2 << 17) | (op1 << 14) | (crn << 10) | (rt << 5)
148
- | (crm << 1) | isread;
149
-}
150
-
151
-static inline uint32_t syn_cp14_rt_trap(int cv, int cond, int opc1, int opc2,
152
- int crn, int crm, int rt, int isread,
153
- bool is_16bit)
154
-{
155
- return (EC_CP14RTTRAP << ARM_EL_EC_SHIFT)
156
- | (is_16bit ? 0 : ARM_EL_IL)
157
- | (cv << 24) | (cond << 20) | (opc2 << 17) | (opc1 << 14)
158
- | (crn << 10) | (rt << 5) | (crm << 1) | isread;
159
-}
160
-
161
-static inline uint32_t syn_cp15_rt_trap(int cv, int cond, int opc1, int opc2,
162
- int crn, int crm, int rt, int isread,
163
- bool is_16bit)
164
-{
165
- return (EC_CP15RTTRAP << ARM_EL_EC_SHIFT)
166
- | (is_16bit ? 0 : ARM_EL_IL)
167
- | (cv << 24) | (cond << 20) | (opc2 << 17) | (opc1 << 14)
168
- | (crn << 10) | (rt << 5) | (crm << 1) | isread;
169
-}
170
-
171
-static inline uint32_t syn_cp14_rrt_trap(int cv, int cond, int opc1, int crm,
172
- int rt, int rt2, int isread,
173
- bool is_16bit)
174
-{
175
- return (EC_CP14RRTTRAP << ARM_EL_EC_SHIFT)
176
- | (is_16bit ? 0 : ARM_EL_IL)
177
- | (cv << 24) | (cond << 20) | (opc1 << 16)
178
- | (rt2 << 10) | (rt << 5) | (crm << 1) | isread;
179
-}
180
-
181
-static inline uint32_t syn_cp15_rrt_trap(int cv, int cond, int opc1, int crm,
182
- int rt, int rt2, int isread,
183
- bool is_16bit)
184
-{
185
- return (EC_CP15RRTTRAP << ARM_EL_EC_SHIFT)
186
- | (is_16bit ? 0 : ARM_EL_IL)
187
- | (cv << 24) | (cond << 20) | (opc1 << 16)
188
- | (rt2 << 10) | (rt << 5) | (crm << 1) | isread;
189
-}
190
-
191
-static inline uint32_t syn_fp_access_trap(int cv, int cond, bool is_16bit)
192
-{
193
- /* AArch32 FP trap or any AArch64 FP/SIMD trap: TA == 0 coproc == 0xa */
194
- return (EC_ADVSIMDFPACCESSTRAP << ARM_EL_EC_SHIFT)
195
- | (is_16bit ? 0 : ARM_EL_IL)
196
- | (cv << 24) | (cond << 20) | 0xa;
197
-}
198
-
199
-static inline uint32_t syn_simd_access_trap(int cv, int cond, bool is_16bit)
200
-{
201
- /* AArch32 SIMD trap: TA == 1 coproc == 0 */
202
- return (EC_ADVSIMDFPACCESSTRAP << ARM_EL_EC_SHIFT)
203
- | (is_16bit ? 0 : ARM_EL_IL)
204
- | (cv << 24) | (cond << 20) | (1 << 5);
205
-}
206
-
207
-static inline uint32_t syn_sve_access_trap(void)
208
-{
209
- return EC_SVEACCESSTRAP << ARM_EL_EC_SHIFT;
210
-}
211
-
212
-static inline uint32_t syn_pactrap(void)
213
-{
214
- return EC_PACTRAP << ARM_EL_EC_SHIFT;
215
-}
216
-
217
-static inline uint32_t syn_btitrap(int btype)
218
-{
219
- return (EC_BTITRAP << ARM_EL_EC_SHIFT) | btype;
220
-}
221
-
222
-static inline uint32_t syn_insn_abort(int same_el, int ea, int s1ptw, int fsc)
223
-{
224
- return (EC_INSNABORT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT)
225
- | ARM_EL_IL | (ea << 9) | (s1ptw << 7) | fsc;
226
-}
227
-
228
-static inline uint32_t syn_data_abort_no_iss(int same_el, int fnv,
229
- int ea, int cm, int s1ptw,
230
- int wnr, int fsc)
231
-{
232
- return (EC_DATAABORT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT)
233
- | ARM_EL_IL
234
- | (fnv << 10) | (ea << 9) | (cm << 8) | (s1ptw << 7)
235
- | (wnr << 6) | fsc;
236
-}
237
-
238
-static inline uint32_t syn_data_abort_with_iss(int same_el,
239
- int sas, int sse, int srt,
240
- int sf, int ar,
241
- int ea, int cm, int s1ptw,
242
- int wnr, int fsc,
243
- bool is_16bit)
244
-{
245
- return (EC_DATAABORT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT)
246
- | (is_16bit ? 0 : ARM_EL_IL)
247
- | ARM_EL_ISV | (sas << 22) | (sse << 21) | (srt << 16)
248
- | (sf << 15) | (ar << 14)
249
- | (ea << 9) | (cm << 8) | (s1ptw << 7) | (wnr << 6) | fsc;
250
-}
251
-
252
-static inline uint32_t syn_swstep(int same_el, int isv, int ex)
253
-{
254
- return (EC_SOFTWARESTEP << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT)
255
- | ARM_EL_IL | (isv << 24) | (ex << 6) | 0x22;
256
-}
257
-
258
-static inline uint32_t syn_watchpoint(int same_el, int cm, int wnr)
259
-{
260
- return (EC_WATCHPOINT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT)
261
- | ARM_EL_IL | (cm << 8) | (wnr << 6) | 0x22;
262
-}
263
-
264
-static inline uint32_t syn_breakpoint(int same_el)
265
-{
266
- return (EC_BREAKPOINT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT)
267
- | ARM_EL_IL | 0x22;
268
-}
269
-
270
-static inline uint32_t syn_wfx(int cv, int cond, int ti, bool is_16bit)
271
-{
272
- return (EC_WFX_TRAP << ARM_EL_EC_SHIFT) |
273
- (is_16bit ? 0 : (1 << ARM_EL_IL_SHIFT)) |
274
- (cv << 24) | (cond << 20) | ti;
275
-}
276
-
277
/* Update a QEMU watchpoint based on the information the guest has set in the
278
* DBGWCR<n>_EL1 and DBGWVR<n>_EL1 registers.
279
*/
280
diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
281
new file mode 100644
282
index XXXXXXX..XXXXXXX
283
--- /dev/null
284
+++ b/target/arm/syndrome.h
285
@@ -XXX,XX +XXX,XX @@
286
+/*
287
+ * QEMU ARM CPU -- syndrome functions and types
288
+ *
289
+ * Copyright (c) 2014 Linaro Ltd
290
+ *
291
+ * This program is free software; you can redistribute it and/or
292
+ * modify it under the terms of the GNU General Public License
293
+ * as published by the Free Software Foundation; either version 2
294
+ * of the License, or (at your option) any later version.
295
+ *
296
+ * This program is distributed in the hope that it will be useful,
297
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
298
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
299
+ * GNU General Public License for more details.
300
+ *
301
+ * You should have received a copy of the GNU General Public License
302
+ * along with this program; if not, see
303
+ * <http://www.gnu.org/licenses/gpl-2.0.html>
304
+ *
305
+ * This header defines functions, types, etc which need to be shared
306
+ * between different source files within target/arm/ but which are
307
+ * private to it and not required by the rest of QEMU.
308
+ */
309
+
310
+#ifndef TARGET_ARM_SYNDROME_H
311
+#define TARGET_ARM_SYNDROME_H
312
+
313
+/* Valid Syndrome Register EC field values */
314
+enum arm_exception_class {
315
+ EC_UNCATEGORIZED = 0x00,
316
+ EC_WFX_TRAP = 0x01,
317
+ EC_CP15RTTRAP = 0x03,
318
+ EC_CP15RRTTRAP = 0x04,
319
+ EC_CP14RTTRAP = 0x05,
320
+ EC_CP14DTTRAP = 0x06,
321
+ EC_ADVSIMDFPACCESSTRAP = 0x07,
322
+ EC_FPIDTRAP = 0x08,
323
+ EC_PACTRAP = 0x09,
324
+ EC_CP14RRTTRAP = 0x0c,
325
+ EC_BTITRAP = 0x0d,
326
+ EC_ILLEGALSTATE = 0x0e,
327
+ EC_AA32_SVC = 0x11,
328
+ EC_AA32_HVC = 0x12,
329
+ EC_AA32_SMC = 0x13,
330
+ EC_AA64_SVC = 0x15,
331
+ EC_AA64_HVC = 0x16,
332
+ EC_AA64_SMC = 0x17,
333
+ EC_SYSTEMREGISTERTRAP = 0x18,
334
+ EC_SVEACCESSTRAP = 0x19,
335
+ EC_INSNABORT = 0x20,
336
+ EC_INSNABORT_SAME_EL = 0x21,
337
+ EC_PCALIGNMENT = 0x22,
338
+ EC_DATAABORT = 0x24,
339
+ EC_DATAABORT_SAME_EL = 0x25,
340
+ EC_SPALIGNMENT = 0x26,
341
+ EC_AA32_FPTRAP = 0x28,
342
+ EC_AA64_FPTRAP = 0x2c,
343
+ EC_SERROR = 0x2f,
344
+ EC_BREAKPOINT = 0x30,
345
+ EC_BREAKPOINT_SAME_EL = 0x31,
346
+ EC_SOFTWARESTEP = 0x32,
347
+ EC_SOFTWARESTEP_SAME_EL = 0x33,
348
+ EC_WATCHPOINT = 0x34,
349
+ EC_WATCHPOINT_SAME_EL = 0x35,
350
+ EC_AA32_BKPT = 0x38,
351
+ EC_VECTORCATCH = 0x3a,
352
+ EC_AA64_BKPT = 0x3c,
353
+};
354
+
355
+#define ARM_EL_EC_SHIFT 26
356
+#define ARM_EL_IL_SHIFT 25
357
+#define ARM_EL_ISV_SHIFT 24
358
+#define ARM_EL_IL (1 << ARM_EL_IL_SHIFT)
359
+#define ARM_EL_ISV (1 << ARM_EL_ISV_SHIFT)
360
+
361
+static inline uint32_t syn_get_ec(uint32_t syn)
362
+{
363
+ return syn >> ARM_EL_EC_SHIFT;
364
+}
365
+
366
+/*
367
+ * Utility functions for constructing various kinds of syndrome value.
368
+ * Note that in general we follow the AArch64 syndrome values; in a
369
+ * few cases the value in HSR for exceptions taken to AArch32 Hyp
370
+ * mode differs slightly, and we fix this up when populating HSR in
371
+ * arm_cpu_do_interrupt_aarch32_hyp().
372
+ * The exception is FP/SIMD access traps -- these report extra information
373
+ * when taking an exception to AArch32. For those we include the extra coproc
374
+ * and TA fields, and mask them out when taking the exception to AArch64.
375
+ */
376
+static inline uint32_t syn_uncategorized(void)
377
+{
378
+ return (EC_UNCATEGORIZED << ARM_EL_EC_SHIFT) | ARM_EL_IL;
379
+}
380
+
381
+static inline uint32_t syn_aa64_svc(uint32_t imm16)
382
+{
383
+ return (EC_AA64_SVC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff);
384
+}
385
+
386
+static inline uint32_t syn_aa64_hvc(uint32_t imm16)
387
+{
388
+ return (EC_AA64_HVC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff);
389
+}
390
+
391
+static inline uint32_t syn_aa64_smc(uint32_t imm16)
392
+{
393
+ return (EC_AA64_SMC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff);
394
+}
395
+
396
+static inline uint32_t syn_aa32_svc(uint32_t imm16, bool is_16bit)
397
+{
398
+ return (EC_AA32_SVC << ARM_EL_EC_SHIFT) | (imm16 & 0xffff)
399
+ | (is_16bit ? 0 : ARM_EL_IL);
400
+}
401
+
402
+static inline uint32_t syn_aa32_hvc(uint32_t imm16)
403
+{
404
+ return (EC_AA32_HVC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff);
405
+}
406
+
407
+static inline uint32_t syn_aa32_smc(void)
408
+{
409
+ return (EC_AA32_SMC << ARM_EL_EC_SHIFT) | ARM_EL_IL;
410
+}
411
+
412
+static inline uint32_t syn_aa64_bkpt(uint32_t imm16)
413
+{
414
+ return (EC_AA64_BKPT << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff);
415
+}
416
+
417
+static inline uint32_t syn_aa32_bkpt(uint32_t imm16, bool is_16bit)
418
+{
419
+ return (EC_AA32_BKPT << ARM_EL_EC_SHIFT) | (imm16 & 0xffff)
420
+ | (is_16bit ? 0 : ARM_EL_IL);
421
+}
422
+
423
+static inline uint32_t syn_aa64_sysregtrap(int op0, int op1, int op2,
424
+ int crn, int crm, int rt,
425
+ int isread)
426
+{
427
+ return (EC_SYSTEMREGISTERTRAP << ARM_EL_EC_SHIFT) | ARM_EL_IL
428
+ | (op0 << 20) | (op2 << 17) | (op1 << 14) | (crn << 10) | (rt << 5)
429
+ | (crm << 1) | isread;
430
+}
431
+
432
+static inline uint32_t syn_cp14_rt_trap(int cv, int cond, int opc1, int opc2,
433
+ int crn, int crm, int rt, int isread,
434
+ bool is_16bit)
435
+{
436
+ return (EC_CP14RTTRAP << ARM_EL_EC_SHIFT)
437
+ | (is_16bit ? 0 : ARM_EL_IL)
438
+ | (cv << 24) | (cond << 20) | (opc2 << 17) | (opc1 << 14)
439
+ | (crn << 10) | (rt << 5) | (crm << 1) | isread;
440
+}
441
+
442
+static inline uint32_t syn_cp15_rt_trap(int cv, int cond, int opc1, int opc2,
443
+ int crn, int crm, int rt, int isread,
444
+ bool is_16bit)
445
+{
446
+ return (EC_CP15RTTRAP << ARM_EL_EC_SHIFT)
447
+ | (is_16bit ? 0 : ARM_EL_IL)
448
+ | (cv << 24) | (cond << 20) | (opc2 << 17) | (opc1 << 14)
449
+ | (crn << 10) | (rt << 5) | (crm << 1) | isread;
450
+}
451
+
452
+static inline uint32_t syn_cp14_rrt_trap(int cv, int cond, int opc1, int crm,
453
+ int rt, int rt2, int isread,
454
+ bool is_16bit)
455
+{
456
+ return (EC_CP14RRTTRAP << ARM_EL_EC_SHIFT)
457
+ | (is_16bit ? 0 : ARM_EL_IL)
458
+ | (cv << 24) | (cond << 20) | (opc1 << 16)
459
+ | (rt2 << 10) | (rt << 5) | (crm << 1) | isread;
460
+}
461
+
462
+static inline uint32_t syn_cp15_rrt_trap(int cv, int cond, int opc1, int crm,
463
+ int rt, int rt2, int isread,
464
+ bool is_16bit)
465
+{
466
+ return (EC_CP15RRTTRAP << ARM_EL_EC_SHIFT)
467
+ | (is_16bit ? 0 : ARM_EL_IL)
468
+ | (cv << 24) | (cond << 20) | (opc1 << 16)
469
+ | (rt2 << 10) | (rt << 5) | (crm << 1) | isread;
470
+}
471
+
472
+static inline uint32_t syn_fp_access_trap(int cv, int cond, bool is_16bit)
473
+{
474
+ /* AArch32 FP trap or any AArch64 FP/SIMD trap: TA == 0 coproc == 0xa */
475
+ return (EC_ADVSIMDFPACCESSTRAP << ARM_EL_EC_SHIFT)
476
+ | (is_16bit ? 0 : ARM_EL_IL)
477
+ | (cv << 24) | (cond << 20) | 0xa;
478
+}
479
+
480
+static inline uint32_t syn_simd_access_trap(int cv, int cond, bool is_16bit)
481
+{
482
+ /* AArch32 SIMD trap: TA == 1 coproc == 0 */
483
+ return (EC_ADVSIMDFPACCESSTRAP << ARM_EL_EC_SHIFT)
484
+ | (is_16bit ? 0 : ARM_EL_IL)
485
+ | (cv << 24) | (cond << 20) | (1 << 5);
486
+}
487
+
488
+static inline uint32_t syn_sve_access_trap(void)
489
+{
490
+ return EC_SVEACCESSTRAP << ARM_EL_EC_SHIFT;
491
+}
492
+
493
+static inline uint32_t syn_pactrap(void)
494
+{
495
+ return EC_PACTRAP << ARM_EL_EC_SHIFT;
496
+}
497
+
498
+static inline uint32_t syn_btitrap(int btype)
499
+{
500
+ return (EC_BTITRAP << ARM_EL_EC_SHIFT) | btype;
501
+}
502
+
503
+static inline uint32_t syn_insn_abort(int same_el, int ea, int s1ptw, int fsc)
504
+{
505
+ return (EC_INSNABORT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT)
506
+ | ARM_EL_IL | (ea << 9) | (s1ptw << 7) | fsc;
507
+}
508
+
509
+static inline uint32_t syn_data_abort_no_iss(int same_el, int fnv,
510
+ int ea, int cm, int s1ptw,
511
+ int wnr, int fsc)
512
+{
513
+ return (EC_DATAABORT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT)
514
+ | ARM_EL_IL
515
+ | (fnv << 10) | (ea << 9) | (cm << 8) | (s1ptw << 7)
516
+ | (wnr << 6) | fsc;
517
+}
518
+
519
+static inline uint32_t syn_data_abort_with_iss(int same_el,
520
+ int sas, int sse, int srt,
521
+ int sf, int ar,
522
+ int ea, int cm, int s1ptw,
523
+ int wnr, int fsc,
524
+ bool is_16bit)
525
+{
526
+ return (EC_DATAABORT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT)
527
+ | (is_16bit ? 0 : ARM_EL_IL)
528
+ | ARM_EL_ISV | (sas << 22) | (sse << 21) | (srt << 16)
529
+ | (sf << 15) | (ar << 14)
530
+ | (ea << 9) | (cm << 8) | (s1ptw << 7) | (wnr << 6) | fsc;
531
+}
532
+
533
+static inline uint32_t syn_swstep(int same_el, int isv, int ex)
534
+{
535
+ return (EC_SOFTWARESTEP << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT)
536
+ | ARM_EL_IL | (isv << 24) | (ex << 6) | 0x22;
537
+}
538
+
539
+static inline uint32_t syn_watchpoint(int same_el, int cm, int wnr)
540
+{
541
+ return (EC_WATCHPOINT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT)
542
+ | ARM_EL_IL | (cm << 8) | (wnr << 6) | 0x22;
543
+}
544
+
545
+static inline uint32_t syn_breakpoint(int same_el)
546
+{
547
+ return (EC_BREAKPOINT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT)
548
+ | ARM_EL_IL | 0x22;
549
+}
550
+
551
+static inline uint32_t syn_wfx(int cv, int cond, int ti, bool is_16bit)
552
+{
553
+ return (EC_WFX_TRAP << ARM_EL_EC_SHIFT) |
554
+ (is_16bit ? 0 : (1 << ARM_EL_IL_SHIFT)) |
555
+ (cv << 24) | (cond << 20) | ti;
556
+}
557
+
558
+#endif /* TARGET_ARM_SYNDROME_H */
559
--
56
--
560
2.20.1
57
2.34.1
561
562
diff view generated by jsdifflib
New patch
1
Currently m68k_cpu_reset_hold() calls floatx80_default_nan(NULL)
2
to get the NaN bit pattern to reset the FPU registers. This
3
works because it happens that our implementation of
4
floatx80_default_nan() doesn't actually look at the float_status
5
pointer except for TARGET_MIPS. However, this isn't guaranteed,
6
and to be able to remove the ifdef in floatx80_default_nan()
7
we're going to need a real float_status here.
1
8
9
Rearrange m68k_cpu_reset_hold() so that we initialize env->fp_status
10
earlier, and thus can pass it to floatx80_default_nan().
11
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
14
Message-id: 20241202131347.498124-28-peter.maydell@linaro.org
15
---
16
target/m68k/cpu.c | 12 +++++++-----
17
1 file changed, 7 insertions(+), 5 deletions(-)
18
19
diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/target/m68k/cpu.c
22
+++ b/target/m68k/cpu.c
23
@@ -XXX,XX +XXX,XX @@ static void m68k_cpu_reset_hold(Object *obj, ResetType type)
24
CPUState *cs = CPU(obj);
25
M68kCPUClass *mcc = M68K_CPU_GET_CLASS(obj);
26
CPUM68KState *env = cpu_env(cs);
27
- floatx80 nan = floatx80_default_nan(NULL);
28
+ floatx80 nan;
29
int i;
30
31
if (mcc->parent_phases.hold) {
32
@@ -XXX,XX +XXX,XX @@ static void m68k_cpu_reset_hold(Object *obj, ResetType type)
33
#else
34
cpu_m68k_set_sr(env, SR_S | SR_I);
35
#endif
36
- for (i = 0; i < 8; i++) {
37
- env->fregs[i].d = nan;
38
- }
39
- cpu_m68k_set_fpcr(env, 0);
40
/*
41
* M68000 FAMILY PROGRAMMER'S REFERENCE MANUAL
42
* 3.4 FLOATING-POINT INSTRUCTION DETAILS
43
@@ -XXX,XX +XXX,XX @@ static void m68k_cpu_reset_hold(Object *obj, ResetType type)
44
* preceding paragraph for nonsignaling NaNs.
45
*/
46
set_float_2nan_prop_rule(float_2nan_prop_ab, &env->fp_status);
47
+
48
+ nan = floatx80_default_nan(&env->fp_status);
49
+ for (i = 0; i < 8; i++) {
50
+ env->fregs[i].d = nan;
51
+ }
52
+ cpu_m68k_set_fpcr(env, 0);
53
env->fpsr = 0;
54
55
/* TODO: We should set PC from the interrupt vector. */
56
--
57
2.34.1
diff view generated by jsdifflib
New patch
1
We create our 128-bit default NaN by calling parts64_default_nan()
2
and then adjusting the result. We can do the same trick for creating
3
the floatx80 default NaN, which lets us drop a target ifdef.
1
4
5
floatx80 is used only by:
6
i386
7
m68k
8
arm nwfpe old floating-point emulation emulation support
9
(which is essentially dead, especially the parts involving floatx80)
10
PPC (only in the xsrqpxp instruction, which just rounds an input
11
value by converting to floatx80 and back, so will never generate
12
the default NaN)
13
14
The floatx80 default NaN as currently implemented is:
15
m68k: sign = 0, exp = 1...1, int = 1, frac = 1....1
16
i386: sign = 1, exp = 1...1, int = 1, frac = 10...0
17
18
These are the same as the parts64_default_nan for these architectures.
19
20
This is technically a possible behaviour change for arm linux-user
21
nwfpe emulation emulation, because the default NaN will now have the
22
sign bit clear. But we were already generating a different floatx80
23
default NaN from the real kernel emulation we are supposedly
24
following, which appears to use an all-bits-1 value:
25
https://elixir.bootlin.com/linux/v6.12/source/arch/arm/nwfpe/softfloat-specialize#L267
26
27
This won't affect the only "real" use of the nwfpe emulation, which
28
is ancient binaries that used it as part of the old floating point
29
calling convention; that only uses loads and stores of 32 and 64 bit
30
floats, not any of the floatx80 behaviour the original hardware had.
31
We also get the nwfpe float64 default NaN value wrong:
32
https://elixir.bootlin.com/linux/v6.12/source/arch/arm/nwfpe/softfloat-specialize#L166
33
so if we ever cared about this obscure corner the right fix would be
34
to correct that so nwfpe used its own default-NaN setting rather
35
than the Arm VFP one.
36
37
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
38
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
39
Message-id: 20241202131347.498124-29-peter.maydell@linaro.org
40
---
41
fpu/softfloat-specialize.c.inc | 20 ++++++++++----------
42
1 file changed, 10 insertions(+), 10 deletions(-)
43
44
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
45
index XXXXXXX..XXXXXXX 100644
46
--- a/fpu/softfloat-specialize.c.inc
47
+++ b/fpu/softfloat-specialize.c.inc
48
@@ -XXX,XX +XXX,XX @@ static void parts128_silence_nan(FloatParts128 *p, float_status *status)
49
floatx80 floatx80_default_nan(float_status *status)
50
{
51
floatx80 r;
52
+ /*
53
+ * Extrapolate from the choices made by parts64_default_nan to fill
54
+ * in the floatx80 format. We assume that floatx80's explicit
55
+ * integer bit is always set (this is true for i386 and m68k,
56
+ * which are the only real users of this format).
57
+ */
58
+ FloatParts64 p64;
59
+ parts64_default_nan(&p64, status);
60
61
- /* None of the targets that have snan_bit_is_one use floatx80. */
62
- assert(!snan_bit_is_one(status));
63
-#if defined(TARGET_M68K)
64
- r.low = UINT64_C(0xFFFFFFFFFFFFFFFF);
65
- r.high = 0x7FFF;
66
-#else
67
- /* X86 */
68
- r.low = UINT64_C(0xC000000000000000);
69
- r.high = 0xFFFF;
70
-#endif
71
+ r.high = 0x7FFF | (p64.sign << 15);
72
+ r.low = (1ULL << DECOMPOSED_BINARY_POINT) | p64.frac;
73
return r;
74
}
75
76
--
77
2.34.1
diff view generated by jsdifflib
New patch
1
In target/loongarch's helper_fclass_s() and helper_fclass_d() we pass
2
a zero-initialized float_status struct to float32_is_quiet_nan() and
3
float64_is_quiet_nan(), with the cryptic comment "for
4
snan_bit_is_one".
1
5
6
This pattern appears to have been copied from target/riscv, where it
7
is used because the functions there do not have ready access to the
8
CPU state struct. The comment presumably refers to the fact that the
9
main reason the is_quiet_nan() functions want the float_state is
10
because they want to know about the snan_bit_is_one config.
11
12
In the loongarch helpers, though, we have the CPU state struct
13
to hand. Use the usual env->fp_status here. This avoids our needing
14
to track that we need to update the initializer of the local
15
float_status structs when the core softfloat code adds new
16
options for targets to configure their behaviour.
17
18
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
19
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
20
Message-id: 20241202131347.498124-30-peter.maydell@linaro.org
21
---
22
target/loongarch/tcg/fpu_helper.c | 6 ++----
23
1 file changed, 2 insertions(+), 4 deletions(-)
24
25
diff --git a/target/loongarch/tcg/fpu_helper.c b/target/loongarch/tcg/fpu_helper.c
26
index XXXXXXX..XXXXXXX 100644
27
--- a/target/loongarch/tcg/fpu_helper.c
28
+++ b/target/loongarch/tcg/fpu_helper.c
29
@@ -XXX,XX +XXX,XX @@ uint64_t helper_fclass_s(CPULoongArchState *env, uint64_t fj)
30
} else if (float32_is_zero_or_denormal(f)) {
31
return sign ? 1 << 4 : 1 << 8;
32
} else if (float32_is_any_nan(f)) {
33
- float_status s = { }; /* for snan_bit_is_one */
34
- return float32_is_quiet_nan(f, &s) ? 1 << 1 : 1 << 0;
35
+ return float32_is_quiet_nan(f, &env->fp_status) ? 1 << 1 : 1 << 0;
36
} else {
37
return sign ? 1 << 3 : 1 << 7;
38
}
39
@@ -XXX,XX +XXX,XX @@ uint64_t helper_fclass_d(CPULoongArchState *env, uint64_t fj)
40
} else if (float64_is_zero_or_denormal(f)) {
41
return sign ? 1 << 4 : 1 << 8;
42
} else if (float64_is_any_nan(f)) {
43
- float_status s = { }; /* for snan_bit_is_one */
44
- return float64_is_quiet_nan(f, &s) ? 1 << 1 : 1 << 0;
45
+ return float64_is_quiet_nan(f, &env->fp_status) ? 1 << 1 : 1 << 0;
46
} else {
47
return sign ? 1 << 3 : 1 << 7;
48
}
49
--
50
2.34.1
diff view generated by jsdifflib
New patch
1
In the frem helper, we have a local float_status because we want to
2
execute the floatx80_div() with a custom rounding mode. Instead of
3
zero-initializing the local float_status and then having to set it up
4
with the m68k standard behaviour (including the NaN propagation rule
5
and copying the rounding precision from env->fp_status), initialize
6
it as a complete copy of env->fp_status. This will avoid our having
7
to add new code in this function for every new config knob we add
8
to fp_status.
1
9
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
12
Message-id: 20241202131347.498124-31-peter.maydell@linaro.org
13
---
14
target/m68k/fpu_helper.c | 6 ++----
15
1 file changed, 2 insertions(+), 4 deletions(-)
16
17
diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/target/m68k/fpu_helper.c
20
+++ b/target/m68k/fpu_helper.c
21
@@ -XXX,XX +XXX,XX @@ void HELPER(frem)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1)
22
23
fp_rem = floatx80_rem(val1->d, val0->d, &env->fp_status);
24
if (!floatx80_is_any_nan(fp_rem)) {
25
- float_status fp_status = { };
26
+ /* Use local temporary fp_status to set different rounding mode */
27
+ float_status fp_status = env->fp_status;
28
uint32_t quotient;
29
int sign;
30
31
/* Calculate quotient directly using round to nearest mode */
32
- set_float_2nan_prop_rule(float_2nan_prop_ab, &fp_status);
33
set_float_rounding_mode(float_round_nearest_even, &fp_status);
34
- set_floatx80_rounding_precision(
35
- get_floatx80_rounding_precision(&env->fp_status), &fp_status);
36
fp_quot.d = floatx80_div(val1->d, val0->d, &fp_status);
37
38
sign = extractFloatx80Sign(fp_quot.d);
39
--
40
2.34.1
diff view generated by jsdifflib
New patch
1
In cf_fpu_gdb_get_reg() and cf_fpu_gdb_set_reg() we do the conversion
2
from float64 to floatx80 using a scratch float_status, because we
3
don't want the conversion to affect the CPU's floating point exception
4
status. Currently we use a zero-initialized float_status. This will
5
get steadily more awkward as we add config knobs to float_status
6
that the target must initialize. Avoid having to add any of that
7
configuration here by instead initializing our local float_status
8
from the env->fp_status.
1
9
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
12
Message-id: 20241202131347.498124-32-peter.maydell@linaro.org
13
---
14
target/m68k/helper.c | 6 ++++--
15
1 file changed, 4 insertions(+), 2 deletions(-)
16
17
diff --git a/target/m68k/helper.c b/target/m68k/helper.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/target/m68k/helper.c
20
+++ b/target/m68k/helper.c
21
@@ -XXX,XX +XXX,XX @@ static int cf_fpu_gdb_get_reg(CPUState *cs, GByteArray *mem_buf, int n)
22
CPUM68KState *env = &cpu->env;
23
24
if (n < 8) {
25
- float_status s = {};
26
+ /* Use scratch float_status so any exceptions don't change CPU state */
27
+ float_status s = env->fp_status;
28
return gdb_get_reg64(mem_buf, floatx80_to_float64(env->fregs[n].d, &s));
29
}
30
switch (n) {
31
@@ -XXX,XX +XXX,XX @@ static int cf_fpu_gdb_set_reg(CPUState *cs, uint8_t *mem_buf, int n)
32
CPUM68KState *env = &cpu->env;
33
34
if (n < 8) {
35
- float_status s = {};
36
+ /* Use scratch float_status so any exceptions don't change CPU state */
37
+ float_status s = env->fp_status;
38
env->fregs[n].d = float64_to_floatx80(ldq_be_p(mem_buf), &s);
39
return 8;
40
}
41
--
42
2.34.1
diff view generated by jsdifflib
1
From: Hao Wu <wuhaotsh@google.com>
1
In the helper functions flcmps and flcmpd we use a scratch float_status
2
so that we don't change the CPU state if the comparison raises any
3
floating point exception flags. Instead of zero-initializing this
4
scratch float_status, initialize it as a copy of env->fp_status. This
5
avoids the need to explicitly initialize settings like the NaN
6
propagation rule or others we might add to softfloat in future.
2
7
3
This patch implements the FIFO mode of the SMBus module. In FIFO, the
8
To do this we need to pass the CPU env pointer in to the helper.
4
user transmits or receives at most 16 bytes at a time. The FIFO mode
5
allows the module to transmit large amount of data faster than single
6
byte mode.
7
9
8
Since we only added the device in a patch that is only a few commits
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
away in the same patch set. We do not increase the VMstate version
11
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
number in this special case.
12
Message-id: 20241202131347.498124-33-peter.maydell@linaro.org
13
---
14
target/sparc/helper.h | 4 ++--
15
target/sparc/fop_helper.c | 8 ++++----
16
target/sparc/translate.c | 4 ++--
17
3 files changed, 8 insertions(+), 8 deletions(-)
11
18
12
Reviewed-by: Doug Evans<dje@google.com>
19
diff --git a/target/sparc/helper.h b/target/sparc/helper.h
13
Reviewed-by: Tyrong Ting<kfting@nuvoton.com>
14
Signed-off-by: Hao Wu <wuhaotsh@google.com>
15
Reviewed-by: Corey Minyard <cminyard@mvista.com>
16
Message-id: 20210210220426.3577804-6-wuhaotsh@google.com
17
Acked-by: Corey Minyard <cminyard@mvista.com>
18
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
19
---
20
include/hw/i2c/npcm7xx_smbus.h | 25 +++
21
hw/i2c/npcm7xx_smbus.c | 342 +++++++++++++++++++++++++++++--
22
tests/qtest/npcm7xx_smbus-test.c | 149 +++++++++++++-
23
hw/i2c/trace-events | 1 +
24
4 files changed, 501 insertions(+), 16 deletions(-)
25
26
diff --git a/include/hw/i2c/npcm7xx_smbus.h b/include/hw/i2c/npcm7xx_smbus.h
27
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
28
--- a/include/hw/i2c/npcm7xx_smbus.h
21
--- a/target/sparc/helper.h
29
+++ b/include/hw/i2c/npcm7xx_smbus.h
22
+++ b/target/sparc/helper.h
30
@@ -XXX,XX +XXX,XX @@
23
@@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_3(fcmpd, TCG_CALL_NO_WG, i32, env, f64, f64)
31
*/
24
DEF_HELPER_FLAGS_3(fcmped, TCG_CALL_NO_WG, i32, env, f64, f64)
32
#define NPCM7XX_SMBUS_NR_ADDRS 10
25
DEF_HELPER_FLAGS_3(fcmpq, TCG_CALL_NO_WG, i32, env, i128, i128)
33
26
DEF_HELPER_FLAGS_3(fcmpeq, TCG_CALL_NO_WG, i32, env, i128, i128)
34
+/* Size of the FIFO buffer. */
27
-DEF_HELPER_FLAGS_2(flcmps, TCG_CALL_NO_RWG_SE, i32, f32, f32)
35
+#define NPCM7XX_SMBUS_FIFO_SIZE 16
28
-DEF_HELPER_FLAGS_2(flcmpd, TCG_CALL_NO_RWG_SE, i32, f64, f64)
36
+
29
+DEF_HELPER_FLAGS_3(flcmps, TCG_CALL_NO_RWG_SE, i32, env, f32, f32)
37
typedef enum NPCM7xxSMBusStatus {
30
+DEF_HELPER_FLAGS_3(flcmpd, TCG_CALL_NO_RWG_SE, i32, env, f64, f64)
38
NPCM7XX_SMBUS_STATUS_IDLE,
31
DEF_HELPER_2(raise_exception, noreturn, env, int)
39
NPCM7XX_SMBUS_STATUS_SENDING,
32
40
@@ -XXX,XX +XXX,XX @@ typedef enum NPCM7xxSMBusStatus {
33
DEF_HELPER_FLAGS_3(faddd, TCG_CALL_NO_WG, f64, env, f64, f64)
41
* @addr: The SMBus module's own addresses on the I2C bus.
34
diff --git a/target/sparc/fop_helper.c b/target/sparc/fop_helper.c
42
* @scllt: The SCL low time register.
43
* @sclht: The SCL high time register.
44
+ * @fif_ctl: The FIFO control register.
45
+ * @fif_cts: The FIFO control status register.
46
+ * @fair_per: The fair preriod register.
47
+ * @txf_ctl: The transmit FIFO control register.
48
+ * @t_out: The SMBus timeout register.
49
+ * @txf_sts: The transmit FIFO status register.
50
+ * @rxf_sts: The receive FIFO status register.
51
+ * @rxf_ctl: The receive FIFO control register.
52
+ * @rx_fifo: The FIFO buffer for receiving in FIFO mode.
53
+ * @rx_cur: The current position of rx_fifo.
54
* @status: The current status of the SMBus.
55
*/
56
typedef struct NPCM7xxSMBusState {
57
@@ -XXX,XX +XXX,XX @@ typedef struct NPCM7xxSMBusState {
58
uint8_t scllt;
59
uint8_t sclht;
60
61
+ uint8_t fif_ctl;
62
+ uint8_t fif_cts;
63
+ uint8_t fair_per;
64
+ uint8_t txf_ctl;
65
+ uint8_t t_out;
66
+ uint8_t txf_sts;
67
+ uint8_t rxf_sts;
68
+ uint8_t rxf_ctl;
69
+
70
+ uint8_t rx_fifo[NPCM7XX_SMBUS_FIFO_SIZE];
71
+ uint8_t rx_cur;
72
+
73
NPCM7xxSMBusStatus status;
74
} NPCM7xxSMBusState;
75
76
diff --git a/hw/i2c/npcm7xx_smbus.c b/hw/i2c/npcm7xx_smbus.c
77
index XXXXXXX..XXXXXXX 100644
35
index XXXXXXX..XXXXXXX 100644
78
--- a/hw/i2c/npcm7xx_smbus.c
36
--- a/target/sparc/fop_helper.c
79
+++ b/hw/i2c/npcm7xx_smbus.c
37
+++ b/target/sparc/fop_helper.c
80
@@ -XXX,XX +XXX,XX @@ enum NPCM7xxSMBusBank1Register {
38
@@ -XXX,XX +XXX,XX @@ uint32_t helper_fcmpeq(CPUSPARCState *env, Int128 src1, Int128 src2)
81
#define NPCM7XX_ADDR_EN BIT(7)
39
return finish_fcmp(env, r, GETPC());
82
#define NPCM7XX_ADDR_A(rv) extract8((rv), 0, 6)
83
84
+/* FIFO Mode Register Fields */
85
+/* FIF_CTL fields */
86
+#define NPCM7XX_SMBFIF_CTL_FIFO_EN BIT(4)
87
+#define NPCM7XX_SMBFIF_CTL_FAIR_RDY_IE BIT(2)
88
+#define NPCM7XX_SMBFIF_CTL_FAIR_RDY BIT(1)
89
+#define NPCM7XX_SMBFIF_CTL_FAIR_BUSY BIT(0)
90
+/* FIF_CTS fields */
91
+#define NPCM7XX_SMBFIF_CTS_STR BIT(7)
92
+#define NPCM7XX_SMBFIF_CTS_CLR_FIFO BIT(6)
93
+#define NPCM7XX_SMBFIF_CTS_RFTE_IE BIT(3)
94
+#define NPCM7XX_SMBFIF_CTS_RXF_TXE BIT(1)
95
+/* TXF_CTL fields */
96
+#define NPCM7XX_SMBTXF_CTL_THR_TXIE BIT(6)
97
+#define NPCM7XX_SMBTXF_CTL_TX_THR(rv) extract8((rv), 0, 5)
98
+/* T_OUT fields */
99
+#define NPCM7XX_SMBT_OUT_ST BIT(7)
100
+#define NPCM7XX_SMBT_OUT_IE BIT(6)
101
+#define NPCM7XX_SMBT_OUT_CLKDIV(rv) extract8((rv), 0, 6)
102
+/* TXF_STS fields */
103
+#define NPCM7XX_SMBTXF_STS_TX_THST BIT(6)
104
+#define NPCM7XX_SMBTXF_STS_TX_BYTES(rv) extract8((rv), 0, 5)
105
+/* RXF_STS fields */
106
+#define NPCM7XX_SMBRXF_STS_RX_THST BIT(6)
107
+#define NPCM7XX_SMBRXF_STS_RX_BYTES(rv) extract8((rv), 0, 5)
108
+/* RXF_CTL fields */
109
+#define NPCM7XX_SMBRXF_CTL_THR_RXIE BIT(6)
110
+#define NPCM7XX_SMBRXF_CTL_LAST BIT(5)
111
+#define NPCM7XX_SMBRXF_CTL_RX_THR(rv) extract8((rv), 0, 5)
112
+
113
#define KEEP_OLD_BIT(o, n, b) (((n) & (~(b))) | ((o) & (b)))
114
#define WRITE_ONE_CLEAR(o, n, b) ((n) & (b) ? (o) & (~(b)) : (o))
115
116
#define NPCM7XX_SMBUS_ENABLED(s) ((s)->ctl2 & NPCM7XX_SMBCTL2_ENABLE)
117
+#define NPCM7XX_SMBUS_FIFO_ENABLED(s) ((s)->fif_ctl & \
118
+ NPCM7XX_SMBFIF_CTL_FIFO_EN)
119
120
/* VERSION fields values, read-only. */
121
#define NPCM7XX_SMBUS_VERSION_NUMBER 1
122
-#define NPCM7XX_SMBUS_VERSION_FIFO_SUPPORTED 0
123
+#define NPCM7XX_SMBUS_VERSION_FIFO_SUPPORTED 1
124
125
/* Reset values */
126
#define NPCM7XX_SMB_ST_INIT_VAL 0x00
127
@@ -XXX,XX +XXX,XX @@ enum NPCM7xxSMBusBank1Register {
128
#define NPCM7XX_SMB_ADDR_INIT_VAL 0x00
129
#define NPCM7XX_SMB_SCLLT_INIT_VAL 0x00
130
#define NPCM7XX_SMB_SCLHT_INIT_VAL 0x00
131
+#define NPCM7XX_SMB_FIF_CTL_INIT_VAL 0x00
132
+#define NPCM7XX_SMB_FIF_CTS_INIT_VAL 0x00
133
+#define NPCM7XX_SMB_FAIR_PER_INIT_VAL 0x00
134
+#define NPCM7XX_SMB_TXF_CTL_INIT_VAL 0x00
135
+#define NPCM7XX_SMB_T_OUT_INIT_VAL 0x3f
136
+#define NPCM7XX_SMB_TXF_STS_INIT_VAL 0x00
137
+#define NPCM7XX_SMB_RXF_STS_INIT_VAL 0x00
138
+#define NPCM7XX_SMB_RXF_CTL_INIT_VAL 0x01
139
140
static uint8_t npcm7xx_smbus_get_version(void)
141
{
142
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_smbus_update_irq(NPCM7xxSMBusState *s)
143
(s->ctl1 & NPCM7XX_SMBCTL1_STASTRE &&
144
s->st & NPCM7XX_SMBST_SDAST) ||
145
(s->ctl1 & NPCM7XX_SMBCTL1_EOBINTE &&
146
- s->cst3 & NPCM7XX_SMBCST3_EO_BUSY));
147
+ s->cst3 & NPCM7XX_SMBCST3_EO_BUSY) ||
148
+ (s->rxf_ctl & NPCM7XX_SMBRXF_CTL_THR_RXIE &&
149
+ s->rxf_sts & NPCM7XX_SMBRXF_STS_RX_THST) ||
150
+ (s->txf_ctl & NPCM7XX_SMBTXF_CTL_THR_TXIE &&
151
+ s->txf_sts & NPCM7XX_SMBTXF_STS_TX_THST) ||
152
+ (s->fif_cts & NPCM7XX_SMBFIF_CTS_RFTE_IE &&
153
+ s->fif_cts & NPCM7XX_SMBFIF_CTS_RXF_TXE));
154
155
if (level) {
156
s->cst2 |= NPCM7XX_SMBCST2_INTSTS;
157
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_smbus_nack(NPCM7xxSMBusState *s)
158
s->status = NPCM7XX_SMBUS_STATUS_NEGACK;
159
}
40
}
160
41
161
+static void npcm7xx_smbus_clear_buffer(NPCM7xxSMBusState *s)
42
-uint32_t helper_flcmps(float32 src1, float32 src2)
162
+{
43
+uint32_t helper_flcmps(CPUSPARCState *env, float32 src1, float32 src2)
163
+ s->fif_cts &= ~NPCM7XX_SMBFIF_CTS_RXF_TXE;
164
+ s->txf_sts = 0;
165
+ s->rxf_sts = 0;
166
+}
167
+
168
static void npcm7xx_smbus_send_byte(NPCM7xxSMBusState *s, uint8_t value)
169
{
170
int rv = i2c_send(s->bus, value);
171
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_smbus_send_byte(NPCM7xxSMBusState *s, uint8_t value)
172
npcm7xx_smbus_nack(s);
173
} else {
174
s->st |= NPCM7XX_SMBST_SDAST;
175
+ if (NPCM7XX_SMBUS_FIFO_ENABLED(s)) {
176
+ s->fif_cts |= NPCM7XX_SMBFIF_CTS_RXF_TXE;
177
+ if (NPCM7XX_SMBTXF_STS_TX_BYTES(s->txf_sts) ==
178
+ NPCM7XX_SMBTXF_CTL_TX_THR(s->txf_ctl)) {
179
+ s->txf_sts = NPCM7XX_SMBTXF_STS_TX_THST;
180
+ } else {
181
+ s->txf_sts = 0;
182
+ }
183
+ }
184
}
185
trace_npcm7xx_smbus_send_byte((DEVICE(s)->canonical_path), value, !rv);
186
npcm7xx_smbus_update_irq(s);
187
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_smbus_recv_byte(NPCM7xxSMBusState *s)
188
npcm7xx_smbus_update_irq(s);
189
}
190
191
+static void npcm7xx_smbus_recv_fifo(NPCM7xxSMBusState *s)
192
+{
193
+ uint8_t expected_bytes = NPCM7XX_SMBRXF_CTL_RX_THR(s->rxf_ctl);
194
+ uint8_t received_bytes = NPCM7XX_SMBRXF_STS_RX_BYTES(s->rxf_sts);
195
+ uint8_t pos;
196
+
197
+ if (received_bytes == expected_bytes) {
198
+ return;
199
+ }
200
+
201
+ while (received_bytes < expected_bytes &&
202
+ received_bytes < NPCM7XX_SMBUS_FIFO_SIZE) {
203
+ pos = (s->rx_cur + received_bytes) % NPCM7XX_SMBUS_FIFO_SIZE;
204
+ s->rx_fifo[pos] = i2c_recv(s->bus);
205
+ trace_npcm7xx_smbus_recv_byte((DEVICE(s)->canonical_path),
206
+ s->rx_fifo[pos]);
207
+ ++received_bytes;
208
+ }
209
+
210
+ trace_npcm7xx_smbus_recv_fifo((DEVICE(s)->canonical_path),
211
+ received_bytes, expected_bytes);
212
+ s->rxf_sts = received_bytes;
213
+ if (unlikely(received_bytes < expected_bytes)) {
214
+ qemu_log_mask(LOG_GUEST_ERROR,
215
+ "%s: invalid rx_thr value: 0x%02x\n",
216
+ DEVICE(s)->canonical_path, expected_bytes);
217
+ return;
218
+ }
219
+
220
+ s->rxf_sts |= NPCM7XX_SMBRXF_STS_RX_THST;
221
+ if (s->rxf_ctl & NPCM7XX_SMBRXF_CTL_LAST) {
222
+ trace_npcm7xx_smbus_nack(DEVICE(s)->canonical_path);
223
+ i2c_nack(s->bus);
224
+ s->rxf_ctl &= ~NPCM7XX_SMBRXF_CTL_LAST;
225
+ }
226
+ if (received_bytes == NPCM7XX_SMBUS_FIFO_SIZE) {
227
+ s->st |= NPCM7XX_SMBST_SDAST;
228
+ s->fif_cts |= NPCM7XX_SMBFIF_CTS_RXF_TXE;
229
+ } else if (!(s->rxf_ctl & NPCM7XX_SMBRXF_CTL_THR_RXIE)) {
230
+ s->st |= NPCM7XX_SMBST_SDAST;
231
+ } else {
232
+ s->st &= ~NPCM7XX_SMBST_SDAST;
233
+ }
234
+ npcm7xx_smbus_update_irq(s);
235
+}
236
+
237
+static void npcm7xx_smbus_read_byte_fifo(NPCM7xxSMBusState *s)
238
+{
239
+ uint8_t received_bytes = NPCM7XX_SMBRXF_STS_RX_BYTES(s->rxf_sts);
240
+
241
+ if (received_bytes == 0) {
242
+ npcm7xx_smbus_recv_fifo(s);
243
+ return;
244
+ }
245
+
246
+ s->sda = s->rx_fifo[s->rx_cur];
247
+ s->rx_cur = (s->rx_cur + 1u) % NPCM7XX_SMBUS_FIFO_SIZE;
248
+ --s->rxf_sts;
249
+ npcm7xx_smbus_update_irq(s);
250
+}
251
+
252
static void npcm7xx_smbus_start(NPCM7xxSMBusState *s)
253
{
44
{
254
/*
45
/*
255
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_smbus_start(NPCM7xxSMBusState *s)
46
* FLCMP never raises an exception nor modifies any FSR fields.
256
if (available) {
47
* Perform the comparison with a dummy fp environment.
257
s->st |= NPCM7XX_SMBST_MODE | NPCM7XX_SMBST_XMIT | NPCM7XX_SMBST_SDAST;
48
*/
258
s->cst |= NPCM7XX_SMBCST_BUSY;
49
- float_status discard = { };
259
+ if (NPCM7XX_SMBUS_FIFO_ENABLED(s)) {
50
+ float_status discard = env->fp_status;
260
+ s->fif_cts |= NPCM7XX_SMBFIF_CTS_RXF_TXE;
51
FloatRelation r;
261
+ }
52
262
} else {
53
set_float_2nan_prop_rule(float_2nan_prop_s_ba, &discard);
263
s->st &= ~NPCM7XX_SMBST_MODE;
54
@@ -XXX,XX +XXX,XX @@ uint32_t helper_flcmps(float32 src1, float32 src2)
264
s->cst &= ~NPCM7XX_SMBCST_BUSY;
55
g_assert_not_reached();
265
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_smbus_send_address(NPCM7xxSMBusState *s, uint8_t value)
266
s->st |= NPCM7XX_SMBST_SDAST;
267
}
268
} else if (recv) {
269
- npcm7xx_smbus_recv_byte(s);
270
+ s->st |= NPCM7XX_SMBST_SDAST;
271
+ if (NPCM7XX_SMBUS_FIFO_ENABLED(s)) {
272
+ npcm7xx_smbus_recv_fifo(s);
273
+ } else {
274
+ npcm7xx_smbus_recv_byte(s);
275
+ }
276
+ } else if (NPCM7XX_SMBUS_FIFO_ENABLED(s)) {
277
+ s->st |= NPCM7XX_SMBST_SDAST;
278
+ s->fif_cts |= NPCM7XX_SMBFIF_CTS_RXF_TXE;
279
}
280
npcm7xx_smbus_update_irq(s);
281
}
56
}
282
@@ -XXX,XX +XXX,XX @@ static uint8_t npcm7xx_smbus_read_sda(NPCM7xxSMBusState *s)
57
283
58
-uint32_t helper_flcmpd(float64 src1, float64 src2)
284
switch (s->status) {
59
+uint32_t helper_flcmpd(CPUSPARCState *env, float64 src1, float64 src2)
285
case NPCM7XX_SMBUS_STATUS_STOPPING_LAST_RECEIVE:
60
{
286
- npcm7xx_smbus_execute_stop(s);
61
- float_status discard = { };
287
+ if (NPCM7XX_SMBUS_FIFO_ENABLED(s)) {
62
+ float_status discard = env->fp_status;
288
+ if (NPCM7XX_SMBRXF_STS_RX_BYTES(s->rxf_sts) <= 1) {
63
FloatRelation r;
289
+ npcm7xx_smbus_execute_stop(s);
64
290
+ }
65
set_float_2nan_prop_rule(float_2nan_prop_s_ba, &discard);
291
+ if (NPCM7XX_SMBRXF_STS_RX_BYTES(s->rxf_sts) == 0) {
66
diff --git a/target/sparc/translate.c b/target/sparc/translate.c
292
+ qemu_log_mask(LOG_GUEST_ERROR,
67
index XXXXXXX..XXXXXXX 100644
293
+ "%s: read to SDA with an empty rx-fifo buffer, "
68
--- a/target/sparc/translate.c
294
+ "result undefined: %u\n",
69
+++ b/target/sparc/translate.c
295
+ DEVICE(s)->canonical_path, s->sda);
70
@@ -XXX,XX +XXX,XX @@ static bool trans_FLCMPs(DisasContext *dc, arg_FLCMPs *a)
296
+ break;
71
297
+ }
72
src1 = gen_load_fpr_F(dc, a->rs1);
298
+ npcm7xx_smbus_read_byte_fifo(s);
73
src2 = gen_load_fpr_F(dc, a->rs2);
299
+ value = s->sda;
74
- gen_helper_flcmps(cpu_fcc[a->cc], src1, src2);
300
+ } else {
75
+ gen_helper_flcmps(cpu_fcc[a->cc], tcg_env, src1, src2);
301
+ npcm7xx_smbus_execute_stop(s);
76
return advance_pc(dc);
302
+ }
303
break;
304
305
case NPCM7XX_SMBUS_STATUS_RECEIVING:
306
- npcm7xx_smbus_recv_byte(s);
307
+ if (NPCM7XX_SMBUS_FIFO_ENABLED(s)) {
308
+ npcm7xx_smbus_read_byte_fifo(s);
309
+ value = s->sda;
310
+ } else {
311
+ npcm7xx_smbus_recv_byte(s);
312
+ }
313
break;
314
315
default:
316
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_smbus_write_st(NPCM7xxSMBusState *s, uint8_t value)
317
}
318
319
if (value & NPCM7XX_SMBST_STASTR &&
320
- s->status == NPCM7XX_SMBUS_STATUS_RECEIVING) {
321
- npcm7xx_smbus_recv_byte(s);
322
+ s->status == NPCM7XX_SMBUS_STATUS_RECEIVING) {
323
+ if (NPCM7XX_SMBUS_FIFO_ENABLED(s)) {
324
+ npcm7xx_smbus_recv_fifo(s);
325
+ } else {
326
+ npcm7xx_smbus_recv_byte(s);
327
+ }
328
}
329
330
npcm7xx_smbus_update_irq(s);
331
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_smbus_write_ctl2(NPCM7xxSMBusState *s, uint8_t value)
332
s->st = 0;
333
s->cst3 = s->cst3 & (~NPCM7XX_SMBCST3_EO_BUSY);
334
s->cst = 0;
335
+ npcm7xx_smbus_clear_buffer(s);
336
}
337
}
77
}
338
78
339
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_smbus_write_ctl3(NPCM7xxSMBusState *s, uint8_t value)
79
@@ -XXX,XX +XXX,XX @@ static bool trans_FLCMPd(DisasContext *dc, arg_FLCMPd *a)
340
NPCM7XX_SMBCTL3_SCL_LVL | NPCM7XX_SMBCTL3_SDA_LVL);
80
81
src1 = gen_load_fpr_D(dc, a->rs1);
82
src2 = gen_load_fpr_D(dc, a->rs2);
83
- gen_helper_flcmpd(cpu_fcc[a->cc], src1, src2);
84
+ gen_helper_flcmpd(cpu_fcc[a->cc], tcg_env, src1, src2);
85
return advance_pc(dc);
341
}
86
}
342
87
343
+static void npcm7xx_smbus_write_fif_ctl(NPCM7xxSMBusState *s, uint8_t value)
344
+{
345
+ uint8_t new_ctl = value;
346
+
347
+ new_ctl = KEEP_OLD_BIT(s->fif_ctl, new_ctl, NPCM7XX_SMBFIF_CTL_FAIR_RDY);
348
+ new_ctl = WRITE_ONE_CLEAR(new_ctl, value, NPCM7XX_SMBFIF_CTL_FAIR_RDY);
349
+ new_ctl = KEEP_OLD_BIT(s->fif_ctl, new_ctl, NPCM7XX_SMBFIF_CTL_FAIR_BUSY);
350
+ s->fif_ctl = new_ctl;
351
+}
352
+
353
+static void npcm7xx_smbus_write_fif_cts(NPCM7xxSMBusState *s, uint8_t value)
354
+{
355
+ s->fif_cts = WRITE_ONE_CLEAR(s->fif_cts, value, NPCM7XX_SMBFIF_CTS_STR);
356
+ s->fif_cts = WRITE_ONE_CLEAR(s->fif_cts, value, NPCM7XX_SMBFIF_CTS_RXF_TXE);
357
+ s->fif_cts = KEEP_OLD_BIT(value, s->fif_cts, NPCM7XX_SMBFIF_CTS_RFTE_IE);
358
+
359
+ if (value & NPCM7XX_SMBFIF_CTS_CLR_FIFO) {
360
+ npcm7xx_smbus_clear_buffer(s);
361
+ }
362
+}
363
+
364
+static void npcm7xx_smbus_write_txf_ctl(NPCM7xxSMBusState *s, uint8_t value)
365
+{
366
+ s->txf_ctl = value;
367
+}
368
+
369
+static void npcm7xx_smbus_write_t_out(NPCM7xxSMBusState *s, uint8_t value)
370
+{
371
+ uint8_t new_t_out = value;
372
+
373
+ if ((value & NPCM7XX_SMBT_OUT_ST) || (!(s->t_out & NPCM7XX_SMBT_OUT_ST))) {
374
+ new_t_out &= ~NPCM7XX_SMBT_OUT_ST;
375
+ } else {
376
+ new_t_out |= NPCM7XX_SMBT_OUT_ST;
377
+ }
378
+
379
+ s->t_out = new_t_out;
380
+}
381
+
382
+static void npcm7xx_smbus_write_txf_sts(NPCM7xxSMBusState *s, uint8_t value)
383
+{
384
+ s->txf_sts = WRITE_ONE_CLEAR(s->txf_sts, value, NPCM7XX_SMBTXF_STS_TX_THST);
385
+}
386
+
387
+static void npcm7xx_smbus_write_rxf_sts(NPCM7xxSMBusState *s, uint8_t value)
388
+{
389
+ if (value & NPCM7XX_SMBRXF_STS_RX_THST) {
390
+ s->rxf_sts &= ~NPCM7XX_SMBRXF_STS_RX_THST;
391
+ if (s->status == NPCM7XX_SMBUS_STATUS_RECEIVING) {
392
+ npcm7xx_smbus_recv_fifo(s);
393
+ }
394
+ }
395
+}
396
+
397
+static void npcm7xx_smbus_write_rxf_ctl(NPCM7xxSMBusState *s, uint8_t value)
398
+{
399
+ uint8_t new_ctl = value;
400
+
401
+ if (!(value & NPCM7XX_SMBRXF_CTL_LAST)) {
402
+ new_ctl = KEEP_OLD_BIT(s->rxf_ctl, new_ctl, NPCM7XX_SMBRXF_CTL_LAST);
403
+ }
404
+ s->rxf_ctl = new_ctl;
405
+}
406
+
407
static uint64_t npcm7xx_smbus_read(void *opaque, hwaddr offset, unsigned size)
408
{
409
NPCM7xxSMBusState *s = opaque;
410
@@ -XXX,XX +XXX,XX @@ static uint64_t npcm7xx_smbus_read(void *opaque, hwaddr offset, unsigned size)
411
default:
412
if (bank) {
413
/* Bank 1 */
414
- qemu_log_mask(LOG_GUEST_ERROR,
415
- "%s: read from invalid offset 0x%" HWADDR_PRIx "\n",
416
- DEVICE(s)->canonical_path, offset);
417
+ switch (offset) {
418
+ case NPCM7XX_SMB_FIF_CTS:
419
+ value = s->fif_cts;
420
+ break;
421
+
422
+ case NPCM7XX_SMB_FAIR_PER:
423
+ value = s->fair_per;
424
+ break;
425
+
426
+ case NPCM7XX_SMB_TXF_CTL:
427
+ value = s->txf_ctl;
428
+ break;
429
+
430
+ case NPCM7XX_SMB_T_OUT:
431
+ value = s->t_out;
432
+ break;
433
+
434
+ case NPCM7XX_SMB_TXF_STS:
435
+ value = s->txf_sts;
436
+ break;
437
+
438
+ case NPCM7XX_SMB_RXF_STS:
439
+ value = s->rxf_sts;
440
+ break;
441
+
442
+ case NPCM7XX_SMB_RXF_CTL:
443
+ value = s->rxf_ctl;
444
+ break;
445
+
446
+ default:
447
+ qemu_log_mask(LOG_GUEST_ERROR,
448
+ "%s: read from invalid offset 0x%" HWADDR_PRIx "\n",
449
+ DEVICE(s)->canonical_path, offset);
450
+ break;
451
+ }
452
} else {
453
/* Bank 0 */
454
switch (offset) {
455
@@ -XXX,XX +XXX,XX @@ static uint64_t npcm7xx_smbus_read(void *opaque, hwaddr offset, unsigned size)
456
value = s->scllt;
457
break;
458
459
+ case NPCM7XX_SMB_FIF_CTL:
460
+ value = s->fif_ctl;
461
+ break;
462
+
463
case NPCM7XX_SMB_SCLHT:
464
value = s->sclht;
465
break;
466
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_smbus_write(void *opaque, hwaddr offset, uint64_t value,
467
default:
468
if (bank) {
469
/* Bank 1 */
470
- qemu_log_mask(LOG_GUEST_ERROR,
471
- "%s: write to invalid offset 0x%" HWADDR_PRIx "\n",
472
- DEVICE(s)->canonical_path, offset);
473
+ switch (offset) {
474
+ case NPCM7XX_SMB_FIF_CTS:
475
+ npcm7xx_smbus_write_fif_cts(s, value);
476
+ break;
477
+
478
+ case NPCM7XX_SMB_FAIR_PER:
479
+ s->fair_per = value;
480
+ break;
481
+
482
+ case NPCM7XX_SMB_TXF_CTL:
483
+ npcm7xx_smbus_write_txf_ctl(s, value);
484
+ break;
485
+
486
+ case NPCM7XX_SMB_T_OUT:
487
+ npcm7xx_smbus_write_t_out(s, value);
488
+ break;
489
+
490
+ case NPCM7XX_SMB_TXF_STS:
491
+ npcm7xx_smbus_write_txf_sts(s, value);
492
+ break;
493
+
494
+ case NPCM7XX_SMB_RXF_STS:
495
+ npcm7xx_smbus_write_rxf_sts(s, value);
496
+ break;
497
+
498
+ case NPCM7XX_SMB_RXF_CTL:
499
+ npcm7xx_smbus_write_rxf_ctl(s, value);
500
+ break;
501
+
502
+ default:
503
+ qemu_log_mask(LOG_GUEST_ERROR,
504
+ "%s: write to invalid offset 0x%" HWADDR_PRIx "\n",
505
+ DEVICE(s)->canonical_path, offset);
506
+ break;
507
+ }
508
} else {
509
/* Bank 0 */
510
switch (offset) {
511
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_smbus_write(void *opaque, hwaddr offset, uint64_t value,
512
s->scllt = value;
513
break;
514
515
+ case NPCM7XX_SMB_FIF_CTL:
516
+ npcm7xx_smbus_write_fif_ctl(s, value);
517
+ break;
518
+
519
case NPCM7XX_SMB_SCLHT:
520
s->sclht = value;
521
break;
522
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_smbus_enter_reset(Object *obj, ResetType type)
523
s->scllt = NPCM7XX_SMB_SCLLT_INIT_VAL;
524
s->sclht = NPCM7XX_SMB_SCLHT_INIT_VAL;
525
526
+ s->fif_ctl = NPCM7XX_SMB_FIF_CTL_INIT_VAL;
527
+ s->fif_cts = NPCM7XX_SMB_FIF_CTS_INIT_VAL;
528
+ s->fair_per = NPCM7XX_SMB_FAIR_PER_INIT_VAL;
529
+ s->txf_ctl = NPCM7XX_SMB_TXF_CTL_INIT_VAL;
530
+ s->t_out = NPCM7XX_SMB_T_OUT_INIT_VAL;
531
+ s->txf_sts = NPCM7XX_SMB_TXF_STS_INIT_VAL;
532
+ s->rxf_sts = NPCM7XX_SMB_RXF_STS_INIT_VAL;
533
+ s->rxf_ctl = NPCM7XX_SMB_RXF_CTL_INIT_VAL;
534
+
535
+ npcm7xx_smbus_clear_buffer(s);
536
s->status = NPCM7XX_SMBUS_STATUS_IDLE;
537
+ s->rx_cur = 0;
538
}
539
540
static void npcm7xx_smbus_hold_reset(Object *obj)
541
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_npcm7xx_smbus = {
542
VMSTATE_UINT8_ARRAY(addr, NPCM7xxSMBusState, NPCM7XX_SMBUS_NR_ADDRS),
543
VMSTATE_UINT8(scllt, NPCM7xxSMBusState),
544
VMSTATE_UINT8(sclht, NPCM7xxSMBusState),
545
+ VMSTATE_UINT8(fif_ctl, NPCM7xxSMBusState),
546
+ VMSTATE_UINT8(fif_cts, NPCM7xxSMBusState),
547
+ VMSTATE_UINT8(fair_per, NPCM7xxSMBusState),
548
+ VMSTATE_UINT8(txf_ctl, NPCM7xxSMBusState),
549
+ VMSTATE_UINT8(t_out, NPCM7xxSMBusState),
550
+ VMSTATE_UINT8(txf_sts, NPCM7xxSMBusState),
551
+ VMSTATE_UINT8(rxf_sts, NPCM7xxSMBusState),
552
+ VMSTATE_UINT8(rxf_ctl, NPCM7xxSMBusState),
553
+ VMSTATE_UINT8_ARRAY(rx_fifo, NPCM7xxSMBusState,
554
+ NPCM7XX_SMBUS_FIFO_SIZE),
555
+ VMSTATE_UINT8(rx_cur, NPCM7xxSMBusState),
556
VMSTATE_END_OF_LIST(),
557
},
558
};
559
diff --git a/tests/qtest/npcm7xx_smbus-test.c b/tests/qtest/npcm7xx_smbus-test.c
560
index XXXXXXX..XXXXXXX 100644
561
--- a/tests/qtest/npcm7xx_smbus-test.c
562
+++ b/tests/qtest/npcm7xx_smbus-test.c
563
@@ -XXX,XX +XXX,XX @@ enum NPCM7xxSMBusBank1Register {
564
#define ADDR_EN BIT(7)
565
#define ADDR_A(rv) extract8((rv), 0, 6)
566
567
+/* FIF_CTL fields */
568
+#define FIF_CTL_FIFO_EN BIT(4)
569
+
570
+/* FIF_CTS fields */
571
+#define FIF_CTS_CLR_FIFO BIT(6)
572
+#define FIF_CTS_RFTE_IE BIT(3)
573
+#define FIF_CTS_RXF_TXE BIT(1)
574
+
575
+/* TXF_CTL fields */
576
+#define TXF_CTL_THR_TXIE BIT(6)
577
+#define TXF_CTL_TX_THR(rv) extract8((rv), 0, 5)
578
+
579
+/* TXF_STS fields */
580
+#define TXF_STS_TX_THST BIT(6)
581
+#define TXF_STS_TX_BYTES(rv) extract8((rv), 0, 5)
582
+
583
+/* RXF_CTL fields */
584
+#define RXF_CTL_THR_RXIE BIT(6)
585
+#define RXF_CTL_LAST BIT(5)
586
+#define RXF_CTL_RX_THR(rv) extract8((rv), 0, 5)
587
+
588
+/* RXF_STS fields */
589
+#define RXF_STS_RX_THST BIT(6)
590
+#define RXF_STS_RX_BYTES(rv) extract8((rv), 0, 5)
591
+
592
+
593
+static void choose_bank(QTestState *qts, uint64_t base_addr, uint8_t bank)
594
+{
595
+ uint8_t ctl3 = qtest_readb(qts, base_addr + OFFSET_CTL3);
596
+
597
+ if (bank) {
598
+ ctl3 |= CTL3_BNK_SEL;
599
+ } else {
600
+ ctl3 &= ~CTL3_BNK_SEL;
601
+ }
602
+
603
+ qtest_writeb(qts, base_addr + OFFSET_CTL3, ctl3);
604
+}
605
606
static void check_running(QTestState *qts, uint64_t base_addr)
607
{
608
@@ -XXX,XX +XXX,XX @@ static void send_byte(QTestState *qts, uint64_t base_addr, uint8_t byte)
609
qtest_writeb(qts, base_addr + OFFSET_SDA, byte);
610
}
611
612
+static bool check_recv(QTestState *qts, uint64_t base_addr)
613
+{
614
+ uint8_t st, fif_ctl, rxf_ctl, rxf_sts;
615
+ bool fifo;
616
+
617
+ st = qtest_readb(qts, base_addr + OFFSET_ST);
618
+ choose_bank(qts, base_addr, 0);
619
+ fif_ctl = qtest_readb(qts, base_addr + OFFSET_FIF_CTL);
620
+ fifo = fif_ctl & FIF_CTL_FIFO_EN;
621
+ if (!fifo) {
622
+ return st == (ST_MODE | ST_SDAST);
623
+ }
624
+
625
+ choose_bank(qts, base_addr, 1);
626
+ rxf_ctl = qtest_readb(qts, base_addr + OFFSET_RXF_CTL);
627
+ rxf_sts = qtest_readb(qts, base_addr + OFFSET_RXF_STS);
628
+
629
+ if ((rxf_ctl & RXF_CTL_THR_RXIE) && RXF_STS_RX_BYTES(rxf_sts) < 16) {
630
+ return st == ST_MODE;
631
+ } else {
632
+ return st == (ST_MODE | ST_SDAST);
633
+ }
634
+}
635
+
636
static uint8_t recv_byte(QTestState *qts, uint64_t base_addr)
637
{
638
- g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_ST), ==,
639
- ST_MODE | ST_SDAST);
640
+ g_assert_true(check_recv(qts, base_addr));
641
return qtest_readb(qts, base_addr + OFFSET_SDA);
642
}
643
644
@@ -XXX,XX +XXX,XX @@ static void send_address(QTestState *qts, uint64_t base_addr, uint8_t addr,
645
qtest_writeb(qts, base_addr + OFFSET_ST, ST_STASTR);
646
st = qtest_readb(qts, base_addr + OFFSET_ST);
647
if (recv) {
648
- g_assert_cmphex(st, ==, ST_MODE | ST_SDAST);
649
+ g_assert_true(check_recv(qts, base_addr));
650
} else {
651
g_assert_cmphex(st, ==, ST_MODE | ST_XMIT | ST_SDAST);
652
}
653
@@ -XXX,XX +XXX,XX @@ static void send_nack(QTestState *qts, uint64_t base_addr)
654
qtest_writeb(qts, base_addr + OFFSET_CTL1, ctl1);
655
}
656
657
+static void start_fifo_mode(QTestState *qts, uint64_t base_addr)
658
+{
659
+ choose_bank(qts, base_addr, 0);
660
+ qtest_writeb(qts, base_addr + OFFSET_FIF_CTL, FIF_CTL_FIFO_EN);
661
+ g_assert_true(qtest_readb(qts, base_addr + OFFSET_FIF_CTL) &
662
+ FIF_CTL_FIFO_EN);
663
+ choose_bank(qts, base_addr, 1);
664
+ qtest_writeb(qts, base_addr + OFFSET_FIF_CTS,
665
+ FIF_CTS_CLR_FIFO | FIF_CTS_RFTE_IE);
666
+ g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_FIF_CTS), ==,
667
+ FIF_CTS_RFTE_IE);
668
+ g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_TXF_STS), ==, 0);
669
+ g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_RXF_STS), ==, 0);
670
+}
671
+
672
+static void start_recv_fifo(QTestState *qts, uint64_t base_addr, uint8_t bytes)
673
+{
674
+ choose_bank(qts, base_addr, 1);
675
+ qtest_writeb(qts, base_addr + OFFSET_TXF_CTL, 0);
676
+ qtest_writeb(qts, base_addr + OFFSET_RXF_CTL,
677
+ RXF_CTL_THR_RXIE | RXF_CTL_LAST | bytes);
678
+}
679
+
680
/* Check the SMBus's status is set correctly when disabled. */
681
static void test_disable_bus(gconstpointer data)
682
{
683
@@ -XXX,XX +XXX,XX @@ static void test_single_mode(gconstpointer data)
684
qtest_quit(qts);
685
}
686
687
+/* Check the SMBus can send and receive bytes in FIFO mode. */
688
+static void test_fifo_mode(gconstpointer data)
689
+{
690
+ intptr_t index = (intptr_t)data;
691
+ uint64_t base_addr = SMBUS_ADDR(index);
692
+ int irq = SMBUS_IRQ(index);
693
+ uint8_t value = 0x60;
694
+ QTestState *qts = qtest_init("-machine npcm750-evb");
695
+
696
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
697
+ enable_bus(qts, base_addr);
698
+ start_fifo_mode(qts, base_addr);
699
+ g_assert_false(qtest_get_irq(qts, irq));
700
+
701
+ /* Sending */
702
+ start_transfer(qts, base_addr);
703
+ send_address(qts, base_addr, EVB_DEVICE_ADDR, false, true);
704
+ choose_bank(qts, base_addr, 1);
705
+ g_assert_true(qtest_readb(qts, base_addr + OFFSET_FIF_CTS) &
706
+ FIF_CTS_RXF_TXE);
707
+ qtest_writeb(qts, base_addr + OFFSET_TXF_CTL, TXF_CTL_THR_TXIE);
708
+ send_byte(qts, base_addr, TMP105_REG_CONFIG);
709
+ send_byte(qts, base_addr, value);
710
+ g_assert_true(qtest_readb(qts, base_addr + OFFSET_FIF_CTS) &
711
+ FIF_CTS_RXF_TXE);
712
+ g_assert_true(qtest_readb(qts, base_addr + OFFSET_TXF_STS) &
713
+ TXF_STS_TX_THST);
714
+ g_assert_cmpuint(TXF_STS_TX_BYTES(
715
+ qtest_readb(qts, base_addr + OFFSET_TXF_STS)), ==, 0);
716
+ g_assert_true(qtest_get_irq(qts, irq));
717
+ stop_transfer(qts, base_addr);
718
+ check_stopped(qts, base_addr);
719
+
720
+ /* Receiving */
721
+ start_fifo_mode(qts, base_addr);
722
+ start_transfer(qts, base_addr);
723
+ send_address(qts, base_addr, EVB_DEVICE_ADDR, false, true);
724
+ send_byte(qts, base_addr, TMP105_REG_CONFIG);
725
+ start_transfer(qts, base_addr);
726
+ qtest_writeb(qts, base_addr + OFFSET_FIF_CTS, FIF_CTS_RXF_TXE);
727
+ start_recv_fifo(qts, base_addr, 1);
728
+ send_address(qts, base_addr, EVB_DEVICE_ADDR, true, true);
729
+ g_assert_false(qtest_readb(qts, base_addr + OFFSET_FIF_CTS) &
730
+ FIF_CTS_RXF_TXE);
731
+ g_assert_true(qtest_readb(qts, base_addr + OFFSET_RXF_STS) &
732
+ RXF_STS_RX_THST);
733
+ g_assert_cmpuint(RXF_STS_RX_BYTES(
734
+ qtest_readb(qts, base_addr + OFFSET_RXF_STS)), ==, 1);
735
+ send_nack(qts, base_addr);
736
+ stop_transfer(qts, base_addr);
737
+ check_running(qts, base_addr);
738
+ g_assert_cmphex(recv_byte(qts, base_addr), ==, value);
739
+ g_assert_cmpuint(RXF_STS_RX_BYTES(
740
+ qtest_readb(qts, base_addr + OFFSET_RXF_STS)), ==, 0);
741
+ check_stopped(qts, base_addr);
742
+ qtest_quit(qts);
743
+}
744
+
745
static void smbus_add_test(const char *name, int index, GTestDataFunc fn)
746
{
747
g_autofree char *full_name = g_strdup_printf(
748
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
749
750
for (i = 0; i < ARRAY_SIZE(evb_bus_list); ++i) {
751
add_test(single_mode, evb_bus_list[i]);
752
+ add_test(fifo_mode, evb_bus_list[i]);
753
}
754
755
return g_test_run();
756
diff --git a/hw/i2c/trace-events b/hw/i2c/trace-events
757
index XXXXXXX..XXXXXXX 100644
758
--- a/hw/i2c/trace-events
759
+++ b/hw/i2c/trace-events
760
@@ -XXX,XX +XXX,XX @@ npcm7xx_smbus_send_byte(const char *id, uint8_t value, int success) "%s send byt
761
npcm7xx_smbus_recv_byte(const char *id, uint8_t value) "%s recv byte: 0x%02x"
762
npcm7xx_smbus_stop(const char *id) "%s stopping"
763
npcm7xx_smbus_nack(const char *id) "%s nacking"
764
+npcm7xx_smbus_recv_fifo(const char *id, uint8_t received, uint8_t expected) "%s recv fifo: received %u, expected %u"
765
--
88
--
766
2.20.1
89
2.34.1
767
768
diff view generated by jsdifflib
New patch
1
In the helper_compute_fprf functions, we pass a dummy float_status
2
in to the is_signaling_nan() function. This is unnecessary, because
3
we have convenient access to the CPU env pointer here and that
4
is already set up with the correct values for the snan_bit_is_one
5
and no_signaling_nans config settings. is_signaling_nan() doesn't
6
ever update the fp_status with any exception flags, so there is
7
no reason not to use env->fp_status here.
1
8
9
Use env->fp_status instead of the dummy fp_status.
10
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
13
Message-id: 20241202131347.498124-34-peter.maydell@linaro.org
14
---
15
target/ppc/fpu_helper.c | 3 +--
16
1 file changed, 1 insertion(+), 2 deletions(-)
17
18
diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/target/ppc/fpu_helper.c
21
+++ b/target/ppc/fpu_helper.c
22
@@ -XXX,XX +XXX,XX @@ void helper_compute_fprf_##tp(CPUPPCState *env, tp arg) \
23
} else if (tp##_is_infinity(arg)) { \
24
fprf = neg ? 0x09 << FPSCR_FPRF : 0x05 << FPSCR_FPRF; \
25
} else { \
26
- float_status dummy = { }; /* snan_bit_is_one = 0 */ \
27
- if (tp##_is_signaling_nan(arg, &dummy)) { \
28
+ if (tp##_is_signaling_nan(arg, &env->fp_status)) { \
29
fprf = 0x00 << FPSCR_FPRF; \
30
} else { \
31
fprf = 0x11 << FPSCR_FPRF; \
32
--
33
2.34.1
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
Remember the PROT_MTE bit as PAGE_MTE/PAGE_TARGET_2.
3
Now that float_status has a bunch of fp parameters,
4
Otherwise this does not yet have effect.
4
it is easier to copy an existing structure than create
5
one from scratch. Begin by copying the structure that
6
corresponds to the FPSR and make only the adjustments
7
required for BFloat16 semantics.
5
8
9
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
10
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
11
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
12
Message-id: 20241203203949.483774-2-richard.henderson@linaro.org
8
Message-id: 20210212184902.1251044-25-richard.henderson@linaro.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
14
---
11
include/exec/cpu-all.h | 1 +
15
target/arm/tcg/vec_helper.c | 20 +++++++-------------
12
linux-user/syscall_defs.h | 1 +
16
1 file changed, 7 insertions(+), 13 deletions(-)
13
target/arm/cpu.h | 1 +
14
linux-user/mmap.c | 22 ++++++++++++++--------
15
4 files changed, 17 insertions(+), 8 deletions(-)
16
17
17
diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h
18
diff --git a/target/arm/tcg/vec_helper.c b/target/arm/tcg/vec_helper.c
18
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
19
--- a/include/exec/cpu-all.h
20
--- a/target/arm/tcg/vec_helper.c
20
+++ b/include/exec/cpu-all.h
21
+++ b/target/arm/tcg/vec_helper.c
21
@@ -XXX,XX +XXX,XX @@ extern intptr_t qemu_host_page_mask;
22
@@ -XXX,XX +XXX,XX @@ bool is_ebf(CPUARMState *env, float_status *statusp, float_status *oddstatusp)
22
#endif
23
* no effect on AArch32 instructions.
23
/* Target-specific bits that will be used via page_get_flags(). */
24
*/
24
#define PAGE_TARGET_1 0x0080
25
bool ebf = is_a64(env) && env->vfp.fpcr & FPCR_EBF;
25
+#define PAGE_TARGET_2 0x0200
26
- *statusp = (float_status){
26
27
- .tininess_before_rounding = float_tininess_before_rounding,
27
#if defined(CONFIG_USER_ONLY)
28
- .float_rounding_mode = float_round_to_odd_inf,
28
void page_dump(FILE *f);
29
- .flush_to_zero = true,
29
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
30
- .flush_inputs_to_zero = true,
30
index XXXXXXX..XXXXXXX 100644
31
- .default_nan_mode = true,
31
--- a/linux-user/syscall_defs.h
32
- };
32
+++ b/linux-user/syscall_defs.h
33
@@ -XXX,XX +XXX,XX @@ struct target_winsize {
34
35
#ifdef TARGET_AARCH64
36
#define TARGET_PROT_BTI 0x10
37
+#define TARGET_PROT_MTE 0x20
38
#endif
39
40
/* Common */
41
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
42
index XXXXXXX..XXXXXXX 100644
43
--- a/target/arm/cpu.h
44
+++ b/target/arm/cpu.h
45
@@ -XXX,XX +XXX,XX @@ static inline MemTxAttrs *typecheck_memtxattrs(MemTxAttrs *x)
46
* AArch64 usage of the PAGE_TARGET_* bits for linux-user.
47
*/
48
#define PAGE_BTI PAGE_TARGET_1
49
+#define PAGE_MTE PAGE_TARGET_2
50
51
#ifdef TARGET_TAGGED_ADDRESSES
52
/**
53
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
54
index XXXXXXX..XXXXXXX 100644
55
--- a/linux-user/mmap.c
56
+++ b/linux-user/mmap.c
57
@@ -XXX,XX +XXX,XX @@ static int validate_prot_to_pageflags(int *host_prot, int prot)
58
| (prot & PROT_EXEC ? PROT_READ : 0);
59
60
#ifdef TARGET_AARCH64
61
- /*
62
- * The PROT_BTI bit is only accepted if the cpu supports the feature.
63
- * Since this is the unusual case, don't bother checking unless
64
- * the bit has been requested. If set and valid, record the bit
65
- * within QEMU's page_flags.
66
- */
67
- if (prot & TARGET_PROT_BTI) {
68
+ {
69
ARMCPU *cpu = ARM_CPU(thread_cpu);
70
- if (cpu_isar_feature(aa64_bti, cpu)) {
71
+
33
+
72
+ /*
34
+ *statusp = env->vfp.fp_status;
73
+ * The PROT_BTI bit is only accepted if the cpu supports the feature.
35
+ set_default_nan_mode(true, statusp);
74
+ * Since this is the unusual case, don't bother checking unless
36
75
+ * the bit has been requested. If set and valid, record the bit
37
if (ebf) {
76
+ * within QEMU's page_flags.
38
- float_status *fpst = &env->vfp.fp_status;
77
+ */
39
- set_flush_to_zero(get_flush_to_zero(fpst), statusp);
78
+ if ((prot & TARGET_PROT_BTI) && cpu_isar_feature(aa64_bti, cpu)) {
40
- set_flush_inputs_to_zero(get_flush_inputs_to_zero(fpst), statusp);
79
valid |= TARGET_PROT_BTI;
41
- set_float_rounding_mode(get_float_rounding_mode(fpst), statusp);
80
page_flags |= PAGE_BTI;
42
-
81
}
43
/* EBF=1 needs to do a step with round-to-odd semantics */
82
+ /* Similarly for the PROT_MTE bit. */
44
*oddstatusp = *statusp;
83
+ if ((prot & TARGET_PROT_MTE) && cpu_isar_feature(aa64_mte, cpu)) {
45
set_float_rounding_mode(float_round_to_odd, oddstatusp);
84
+ valid |= TARGET_PROT_MTE;
46
+ } else {
85
+ page_flags |= PAGE_MTE;
47
+ set_flush_to_zero(true, statusp);
86
+ }
48
+ set_flush_inputs_to_zero(true, statusp);
49
+ set_float_rounding_mode(float_round_to_odd_inf, statusp);
87
}
50
}
88
#endif
51
-
52
return ebf;
53
}
89
54
90
--
55
--
91
2.20.1
56
2.34.1
92
57
93
58
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
Currently we hardcode the default NaN value in parts64_default_nan()
2
using a compile-time ifdef ladder. This is awkward for two cases:
3
* for single-QEMU-binary we can't hard-code target-specifics like this
4
* for Arm FEAT_AFP the default NaN value depends on FPCR.AH
5
(specifically the sign bit is different)
2
6
3
This data can be allocated by page_alloc_target_data() and
7
Add a field to float_status to specify the default NaN value; fall
4
released by page_set_flags(start, end, prot | PAGE_RESET).
8
back to the old ifdef behaviour if these are not set.
5
9
6
This data will be used to hold tag memory for AArch64 MTE.
10
The default NaN value is specified by setting a uint8_t to a
11
pattern corresponding to the sign and upper fraction parts of
12
the NaN; the lower bits of the fraction are set from bit 0 of
13
the pattern.
7
14
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
10
Message-id: 20210212184902.1251044-2-richard.henderson@linaro.org
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
17
Message-id: 20241202131347.498124-35-peter.maydell@linaro.org
12
---
18
---
13
include/exec/cpu-all.h | 42 +++++++++++++++++++++++++++++++++------
19
include/fpu/softfloat-helpers.h | 11 +++++++
14
accel/tcg/translate-all.c | 28 ++++++++++++++++++++++++++
20
include/fpu/softfloat-types.h | 10 ++++++
15
linux-user/mmap.c | 4 +++-
21
fpu/softfloat-specialize.c.inc | 55 ++++++++++++++++++++-------------
16
linux-user/syscall.c | 4 ++--
22
3 files changed, 54 insertions(+), 22 deletions(-)
17
4 files changed, 69 insertions(+), 9 deletions(-)
18
23
19
diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h
24
diff --git a/include/fpu/softfloat-helpers.h b/include/fpu/softfloat-helpers.h
20
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
21
--- a/include/exec/cpu-all.h
26
--- a/include/fpu/softfloat-helpers.h
22
+++ b/include/exec/cpu-all.h
27
+++ b/include/fpu/softfloat-helpers.h
23
@@ -XXX,XX +XXX,XX @@ extern intptr_t qemu_host_page_mask;
28
@@ -XXX,XX +XXX,XX @@ static inline void set_float_infzeronan_rule(FloatInfZeroNaNRule rule,
24
#define PAGE_EXEC 0x0004
29
status->float_infzeronan_rule = rule;
25
#define PAGE_BITS (PAGE_READ | PAGE_WRITE | PAGE_EXEC)
26
#define PAGE_VALID 0x0008
27
-/* original state of the write flag (used when tracking self-modifying
28
- code */
29
+/*
30
+ * Original state of the write flag (used when tracking self-modifying code)
31
+ */
32
#define PAGE_WRITE_ORG 0x0010
33
-/* Invalidate the TLB entry immediately, helpful for s390x
34
- * Low-Address-Protection. Used with PAGE_WRITE in tlb_set_page_with_attrs() */
35
-#define PAGE_WRITE_INV 0x0040
36
+/*
37
+ * Invalidate the TLB entry immediately, helpful for s390x
38
+ * Low-Address-Protection. Used with PAGE_WRITE in tlb_set_page_with_attrs()
39
+ */
40
+#define PAGE_WRITE_INV 0x0020
41
+/* For use with page_set_flags: page is being replaced; target_data cleared. */
42
+#define PAGE_RESET 0x0040
43
+
44
#if defined(CONFIG_BSD) && defined(CONFIG_USER_ONLY)
45
/* FIXME: Code that sets/uses this is broken and needs to go away. */
46
-#define PAGE_RESERVED 0x0020
47
+#define PAGE_RESERVED 0x0100
48
#endif
49
/* Target-specific bits that will be used via page_get_flags(). */
50
#define PAGE_TARGET_1 0x0080
51
@@ -XXX,XX +XXX,XX @@ int walk_memory_regions(void *, walk_memory_regions_fn);
52
int page_get_flags(target_ulong address);
53
void page_set_flags(target_ulong start, target_ulong end, int flags);
54
int page_check_range(target_ulong start, target_ulong len, int flags);
55
+
56
+/**
57
+ * page_alloc_target_data(address, size)
58
+ * @address: guest virtual address
59
+ * @size: size of data to allocate
60
+ *
61
+ * Allocate @size bytes of out-of-band data to associate with the
62
+ * guest page at @address. If the page is not mapped, NULL will
63
+ * be returned. If there is existing data associated with @address,
64
+ * no new memory will be allocated.
65
+ *
66
+ * The memory will be freed when the guest page is deallocated,
67
+ * e.g. with the munmap system call.
68
+ */
69
+void *page_alloc_target_data(target_ulong address, size_t size);
70
+
71
+/**
72
+ * page_get_target_data(address)
73
+ * @address: guest virtual address
74
+ *
75
+ * Return any out-of-bound memory assocated with the guest page
76
+ * at @address, as per page_alloc_target_data.
77
+ */
78
+void *page_get_target_data(target_ulong address);
79
#endif
80
81
CPUArchState *cpu_copy(CPUArchState *env);
82
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
83
index XXXXXXX..XXXXXXX 100644
84
--- a/accel/tcg/translate-all.c
85
+++ b/accel/tcg/translate-all.c
86
@@ -XXX,XX +XXX,XX @@ typedef struct PageDesc {
87
unsigned int code_write_count;
88
#else
89
unsigned long flags;
90
+ void *target_data;
91
#endif
92
#ifndef CONFIG_USER_ONLY
93
QemuSpin lock;
94
@@ -XXX,XX +XXX,XX @@ int page_get_flags(target_ulong address)
95
void page_set_flags(target_ulong start, target_ulong end, int flags)
96
{
97
target_ulong addr, len;
98
+ bool reset_target_data;
99
100
/* This function should never be called with addresses outside the
101
guest address space. If this assert fires, it probably indicates
102
@@ -XXX,XX +XXX,XX @@ void page_set_flags(target_ulong start, target_ulong end, int flags)
103
if (flags & PAGE_WRITE) {
104
flags |= PAGE_WRITE_ORG;
105
}
106
+ reset_target_data = !(flags & PAGE_VALID) || (flags & PAGE_RESET);
107
+ flags &= ~PAGE_RESET;
108
109
for (addr = start, len = end - start;
110
len != 0;
111
@@ -XXX,XX +XXX,XX @@ void page_set_flags(target_ulong start, target_ulong end, int flags)
112
p->first_tb) {
113
tb_invalidate_phys_page(addr, 0);
114
}
115
+ if (reset_target_data && p->target_data) {
116
+ g_free(p->target_data);
117
+ p->target_data = NULL;
118
+ }
119
p->flags = flags;
120
}
121
}
30
}
122
31
123
+void *page_get_target_data(target_ulong address)
32
+static inline void set_float_default_nan_pattern(uint8_t dnan_pattern,
33
+ float_status *status)
124
+{
34
+{
125
+ PageDesc *p = page_find(address >> TARGET_PAGE_BITS);
35
+ status->default_nan_pattern = dnan_pattern;
126
+ return p ? p->target_data : NULL;
127
+}
36
+}
128
+
37
+
129
+void *page_alloc_target_data(target_ulong address, size_t size)
38
static inline void set_flush_to_zero(bool val, float_status *status)
39
{
40
status->flush_to_zero = val;
41
@@ -XXX,XX +XXX,XX @@ static inline FloatInfZeroNaNRule get_float_infzeronan_rule(float_status *status
42
return status->float_infzeronan_rule;
43
}
44
45
+static inline uint8_t get_float_default_nan_pattern(float_status *status)
130
+{
46
+{
131
+ PageDesc *p = page_find(address >> TARGET_PAGE_BITS);
47
+ return status->default_nan_pattern;
132
+ void *ret = NULL;
133
+
134
+ if (p->flags & PAGE_VALID) {
135
+ ret = p->target_data;
136
+ if (!ret) {
137
+ p->target_data = ret = g_malloc0(size);
138
+ }
139
+ }
140
+ return ret;
141
+}
48
+}
142
+
49
+
143
int page_check_range(target_ulong start, target_ulong len, int flags)
50
static inline bool get_flush_to_zero(float_status *status)
144
{
51
{
145
PageDesc *p;
52
return status->flush_to_zero;
146
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
53
diff --git a/include/fpu/softfloat-types.h b/include/fpu/softfloat-types.h
147
index XXXXXXX..XXXXXXX 100644
54
index XXXXXXX..XXXXXXX 100644
148
--- a/linux-user/mmap.c
55
--- a/include/fpu/softfloat-types.h
149
+++ b/linux-user/mmap.c
56
+++ b/include/fpu/softfloat-types.h
150
@@ -XXX,XX +XXX,XX @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot,
57
@@ -XXX,XX +XXX,XX @@ typedef struct float_status {
151
}
58
/* should denormalised inputs go to zero and set the input_denormal flag? */
152
}
59
bool flush_inputs_to_zero;
153
the_end1:
60
bool default_nan_mode;
154
+ page_flags |= PAGE_RESET;
61
+ /*
155
page_set_flags(start, start + len, page_flags);
62
+ * The pattern to use for the default NaN. Here the high bit specifies
156
the_end:
63
+ * the default NaN's sign bit, and bits 6..0 specify the high bits of the
157
trace_target_mmap_complete(start);
64
+ * fractional part. The low bits of the fractional part are copies of bit 0.
158
@@ -XXX,XX +XXX,XX @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
65
+ * The exponent of the default NaN is (as for any NaN) always all 1s.
159
new_addr = h2g(host_addr);
66
+ * Note that a value of 0 here is not a valid NaN. The target must set
160
prot = page_get_flags(old_addr);
67
+ * this to the correct non-zero value, or we will assert when trying to
161
page_set_flags(old_addr, old_addr + old_size, 0);
68
+ * create a default NaN.
162
- page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID);
69
+ */
163
+ page_set_flags(new_addr, new_addr + new_size,
70
+ uint8_t default_nan_pattern;
164
+ prot | PAGE_VALID | PAGE_RESET);
71
/*
165
}
72
* The flags below are not used on all specializations and may
166
tb_invalidate_phys_range(new_addr, new_addr + new_size);
73
* constant fold away (see snan_bit_is_one()/no_signalling_nans() in
167
mmap_unlock();
74
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
168
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
169
index XXXXXXX..XXXXXXX 100644
75
index XXXXXXX..XXXXXXX 100644
170
--- a/linux-user/syscall.c
76
--- a/fpu/softfloat-specialize.c.inc
171
+++ b/linux-user/syscall.c
77
+++ b/fpu/softfloat-specialize.c.inc
172
@@ -XXX,XX +XXX,XX @@ static inline abi_ulong do_shmat(CPUArchState *cpu_env,
78
@@ -XXX,XX +XXX,XX @@ static void parts64_default_nan(FloatParts64 *p, float_status *status)
173
raddr=h2g((unsigned long)host_raddr);
79
{
174
80
bool sign = 0;
175
page_set_flags(raddr, raddr + shm_info.shm_segsz,
81
uint64_t frac;
176
- PAGE_VALID | PAGE_READ |
82
+ uint8_t dnan_pattern = status->default_nan_pattern;
177
- ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
83
178
+ PAGE_VALID | PAGE_RESET | PAGE_READ |
84
+ if (dnan_pattern == 0) {
179
+ (shmflg & SHM_RDONLY ? 0 : PAGE_WRITE));
85
#if defined(TARGET_SPARC) || defined(TARGET_M68K)
180
86
- /* !snan_bit_is_one, set all bits */
181
for (i = 0; i < N_SHM_REGIONS; i++) {
87
- frac = (1ULL << DECOMPOSED_BINARY_POINT) - 1;
182
if (!shm_regions[i].in_use) {
88
-#elif defined(TARGET_I386) || defined(TARGET_X86_64) \
89
+ /* Sign bit clear, all frac bits set */
90
+ dnan_pattern = 0b01111111;
91
+#elif defined(TARGET_I386) || defined(TARGET_X86_64) \
92
|| defined(TARGET_MICROBLAZE)
93
- /* !snan_bit_is_one, set sign and msb */
94
- frac = 1ULL << (DECOMPOSED_BINARY_POINT - 1);
95
- sign = 1;
96
+ /* Sign bit set, most significant frac bit set */
97
+ dnan_pattern = 0b11000000;
98
#elif defined(TARGET_HPPA)
99
- /* snan_bit_is_one, set msb-1. */
100
- frac = 1ULL << (DECOMPOSED_BINARY_POINT - 2);
101
+ /* Sign bit clear, msb-1 frac bit set */
102
+ dnan_pattern = 0b00100000;
103
#elif defined(TARGET_HEXAGON)
104
- sign = 1;
105
- frac = ~0ULL;
106
+ /* Sign bit set, all frac bits set. */
107
+ dnan_pattern = 0b11111111;
108
#else
109
- /*
110
- * This case is true for Alpha, ARM, MIPS, OpenRISC, PPC, RISC-V,
111
- * S390, SH4, TriCore, and Xtensa. Our other supported targets
112
- * do not have floating-point.
113
- */
114
- if (snan_bit_is_one(status)) {
115
- /* set all bits other than msb */
116
- frac = (1ULL << (DECOMPOSED_BINARY_POINT - 1)) - 1;
117
- } else {
118
- /* set msb */
119
- frac = 1ULL << (DECOMPOSED_BINARY_POINT - 1);
120
- }
121
+ /*
122
+ * This case is true for Alpha, ARM, MIPS, OpenRISC, PPC, RISC-V,
123
+ * S390, SH4, TriCore, and Xtensa. Our other supported targets
124
+ * do not have floating-point.
125
+ */
126
+ if (snan_bit_is_one(status)) {
127
+ /* sign bit clear, set all frac bits other than msb */
128
+ dnan_pattern = 0b00111111;
129
+ } else {
130
+ /* sign bit clear, set frac msb */
131
+ dnan_pattern = 0b01000000;
132
+ }
133
#endif
134
+ }
135
+ assert(dnan_pattern != 0);
136
+
137
+ sign = dnan_pattern >> 7;
138
+ /*
139
+ * Place default_nan_pattern [6:0] into bits [62:56],
140
+ * and replecate bit [0] down into [55:0]
141
+ */
142
+ frac = deposit64(0, DECOMPOSED_BINARY_POINT - 7, 7, dnan_pattern);
143
+ frac = deposit64(frac, 0, DECOMPOSED_BINARY_POINT - 7, -(dnan_pattern & 1));
144
145
*p = (FloatParts64) {
146
.cls = float_class_qnan,
183
--
147
--
184
2.20.1
148
2.34.1
185
186
diff view generated by jsdifflib
New patch
1
Set the default NaN pattern explicitly for the tests/fp code.
1
2
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Message-id: 20241202131347.498124-36-peter.maydell@linaro.org
6
---
7
tests/fp/fp-bench.c | 1 +
8
tests/fp/fp-test-log2.c | 1 +
9
tests/fp/fp-test.c | 1 +
10
3 files changed, 3 insertions(+)
11
12
diff --git a/tests/fp/fp-bench.c b/tests/fp/fp-bench.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/tests/fp/fp-bench.c
15
+++ b/tests/fp/fp-bench.c
16
@@ -XXX,XX +XXX,XX @@ static void run_bench(void)
17
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &soft_status);
18
set_float_3nan_prop_rule(float_3nan_prop_s_cab, &soft_status);
19
set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, &soft_status);
20
+ set_float_default_nan_pattern(0b01000000, &soft_status);
21
22
f = bench_funcs[operation][precision];
23
g_assert(f);
24
diff --git a/tests/fp/fp-test-log2.c b/tests/fp/fp-test-log2.c
25
index XXXXXXX..XXXXXXX 100644
26
--- a/tests/fp/fp-test-log2.c
27
+++ b/tests/fp/fp-test-log2.c
28
@@ -XXX,XX +XXX,XX @@ int main(int ac, char **av)
29
int i;
30
31
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &qsf);
32
+ set_float_default_nan_pattern(0b01000000, &qsf);
33
set_float_rounding_mode(float_round_nearest_even, &qsf);
34
35
test.d = 0.0;
36
diff --git a/tests/fp/fp-test.c b/tests/fp/fp-test.c
37
index XXXXXXX..XXXXXXX 100644
38
--- a/tests/fp/fp-test.c
39
+++ b/tests/fp/fp-test.c
40
@@ -XXX,XX +XXX,XX @@ void run_test(void)
41
*/
42
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &qsf);
43
set_float_3nan_prop_rule(float_3nan_prop_s_cab, &qsf);
44
+ set_float_default_nan_pattern(0b01000000, &qsf);
45
set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, &qsf);
46
47
genCases_setLevel(test_level);
48
--
49
2.34.1
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
Set the default NaN pattern explicitly, and remove the ifdef from
2
parts64_default_nan().
2
3
3
We're currently open-coding the range check in access_ok;
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
use guest_range_valid when size != 0.
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20241202131347.498124-37-peter.maydell@linaro.org
7
---
8
target/microblaze/cpu.c | 2 ++
9
fpu/softfloat-specialize.c.inc | 3 +--
10
2 files changed, 3 insertions(+), 2 deletions(-)
5
11
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
12
diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20210212184902.1251044-15-richard.henderson@linaro.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
11
linux-user/qemu.h | 9 +++------
12
1 file changed, 3 insertions(+), 6 deletions(-)
13
14
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
15
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
16
--- a/linux-user/qemu.h
14
--- a/target/microblaze/cpu.c
17
+++ b/linux-user/qemu.h
15
+++ b/target/microblaze/cpu.c
18
@@ -XXX,XX +XXX,XX @@ extern unsigned long guest_stack_size;
16
@@ -XXX,XX +XXX,XX @@ static void mb_cpu_reset_hold(Object *obj, ResetType type)
19
17
* this architecture.
20
static inline bool access_ok(int type, abi_ulong addr, abi_ulong size)
18
*/
21
{
19
set_float_2nan_prop_rule(float_2nan_prop_x87, &env->fp_status);
22
- if (!guest_addr_valid(addr)) {
20
+ /* Default NaN: sign bit set, most significant frac bit set */
23
- return false;
21
+ set_float_default_nan_pattern(0b11000000, &env->fp_status);
24
- }
22
25
- if (size != 0 &&
23
#if defined(CONFIG_USER_ONLY)
26
- (addr + size - 1 < addr ||
24
/* start in user mode with interrupts enabled. */
27
- !guest_addr_valid(addr + size - 1))) {
25
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
28
+ if (size == 0
26
index XXXXXXX..XXXXXXX 100644
29
+ ? !guest_addr_valid(addr)
27
--- a/fpu/softfloat-specialize.c.inc
30
+ : !guest_range_valid(addr, size)) {
28
+++ b/fpu/softfloat-specialize.c.inc
31
return false;
29
@@ -XXX,XX +XXX,XX @@ static void parts64_default_nan(FloatParts64 *p, float_status *status)
32
}
30
#if defined(TARGET_SPARC) || defined(TARGET_M68K)
33
return page_check_range((target_ulong)addr, size, type) == 0;
31
/* Sign bit clear, all frac bits set */
32
dnan_pattern = 0b01111111;
33
-#elif defined(TARGET_I386) || defined(TARGET_X86_64) \
34
- || defined(TARGET_MICROBLAZE)
35
+#elif defined(TARGET_I386) || defined(TARGET_X86_64)
36
/* Sign bit set, most significant frac bit set */
37
dnan_pattern = 0b11000000;
38
#elif defined(TARGET_HPPA)
34
--
39
--
35
2.20.1
40
2.34.1
36
37
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
Set the default NaN pattern explicitly, and remove the ifdef from
2
parts64_default_nan().
2
3
3
Use g2h_untagged in contexts that have no cpu, e.g. the binary
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
loaders that operate before the primary cpu is created. As a
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
colollary, target_mmap and friends must use untagged addresses,
6
Message-id: 20241202131347.498124-38-peter.maydell@linaro.org
6
since they are used by the loaders.
7
---
8
target/i386/tcg/fpu_helper.c | 4 ++++
9
fpu/softfloat-specialize.c.inc | 3 ---
10
2 files changed, 4 insertions(+), 3 deletions(-)
7
11
8
Use g2h_untagged on values returned from target_mmap, as the
12
diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c
9
kernel never applies a tag itself.
10
11
Use g2h_untagged on all pc values. The only current user of
12
tags, aarch64, removes tags from code addresses upon branch,
13
so "pc" is always untagged.
14
15
Use g2h with the cpu context on hand wherever possible.
16
17
Use g2h_untagged in lock_user, which will be updated soon.
18
19
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
20
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
21
Message-id: 20210212184902.1251044-13-richard.henderson@linaro.org
22
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
23
---
24
bsd-user/qemu.h | 8 ++--
25
include/exec/cpu_ldst.h | 12 +++++-
26
include/exec/exec-all.h | 2 +-
27
linux-user/qemu.h | 6 +--
28
accel/tcg/translate-all.c | 4 +-
29
accel/tcg/user-exec.c | 48 ++++++++++++------------
30
bsd-user/elfload.c | 2 +-
31
bsd-user/main.c | 4 +-
32
bsd-user/mmap.c | 23 ++++++------
33
linux-user/elfload.c | 12 +++---
34
linux-user/flatload.c | 2 +-
35
linux-user/hppa/cpu_loop.c | 31 ++++++++--------
36
linux-user/i386/cpu_loop.c | 4 +-
37
linux-user/mmap.c | 45 +++++++++++-----------
38
linux-user/ppc/signal.c | 4 +-
39
linux-user/syscall.c | 72 +++++++++++++++++++-----------------
40
target/arm/helper-a64.c | 4 +-
41
target/hppa/op_helper.c | 2 +-
42
target/i386/tcg/mem_helper.c | 2 +-
43
target/s390x/mem_helper.c | 4 +-
44
20 files changed, 154 insertions(+), 137 deletions(-)
45
46
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
47
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
48
--- a/bsd-user/qemu.h
14
--- a/target/i386/tcg/fpu_helper.c
49
+++ b/bsd-user/qemu.h
15
+++ b/target/i386/tcg/fpu_helper.c
50
@@ -XXX,XX +XXX,XX @@ static inline void *lock_user(int type, abi_ulong guest_addr, long len, int copy
16
@@ -XXX,XX +XXX,XX @@ void cpu_init_fp_statuses(CPUX86State *env)
51
void *addr;
17
*/
52
addr = g_malloc(len);
18
set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->sse_status);
53
if (copy)
19
set_float_3nan_prop_rule(float_3nan_prop_abc, &env->sse_status);
54
- memcpy(addr, g2h(guest_addr), len);
20
+ /* Default NaN: sign bit set, most significant frac bit set */
55
+ memcpy(addr, g2h_untagged(guest_addr), len);
21
+ set_float_default_nan_pattern(0b11000000, &env->fp_status);
56
else
22
+ set_float_default_nan_pattern(0b11000000, &env->mmx_status);
57
memset(addr, 0, len);
23
+ set_float_default_nan_pattern(0b11000000, &env->sse_status);
58
return addr;
59
}
60
#else
61
- return g2h(guest_addr);
62
+ return g2h_untagged(guest_addr);
63
#endif
64
}
24
}
65
25
66
@@ -XXX,XX +XXX,XX @@ static inline void unlock_user(void *host_ptr, abi_ulong guest_addr,
26
static inline uint8_t save_exception_flags(CPUX86State *env)
67
#ifdef DEBUG_REMAP
27
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
68
if (!host_ptr)
69
return;
70
- if (host_ptr == g2h(guest_addr))
71
+ if (host_ptr == g2h_untagged(guest_addr))
72
return;
73
if (len > 0)
74
- memcpy(g2h(guest_addr), host_ptr, len);
75
+ memcpy(g2h_untagged(guest_addr), host_ptr, len);
76
g_free(host_ptr);
77
#endif
78
}
79
diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h
80
index XXXXXXX..XXXXXXX 100644
28
index XXXXXXX..XXXXXXX 100644
81
--- a/include/exec/cpu_ldst.h
29
--- a/fpu/softfloat-specialize.c.inc
82
+++ b/include/exec/cpu_ldst.h
30
+++ b/fpu/softfloat-specialize.c.inc
83
@@ -XXX,XX +XXX,XX @@ static inline abi_ptr cpu_untagged_addr(CPUState *cs, abi_ptr x)
31
@@ -XXX,XX +XXX,XX @@ static void parts64_default_nan(FloatParts64 *p, float_status *status)
84
#endif
32
#if defined(TARGET_SPARC) || defined(TARGET_M68K)
85
33
/* Sign bit clear, all frac bits set */
86
/* All direct uses of g2h and h2g need to go away for usermode softmmu. */
34
dnan_pattern = 0b01111111;
87
-#define g2h(x) ((void *)((uintptr_t)(abi_ptr)(x) + guest_base))
35
-#elif defined(TARGET_I386) || defined(TARGET_X86_64)
88
+static inline void *g2h_untagged(abi_ptr x)
36
- /* Sign bit set, most significant frac bit set */
89
+{
37
- dnan_pattern = 0b11000000;
90
+ return (void *)((uintptr_t)(x) + guest_base);
38
#elif defined(TARGET_HPPA)
91
+}
39
/* Sign bit clear, msb-1 frac bit set */
92
+
40
dnan_pattern = 0b00100000;
93
+static inline void *g2h(CPUState *cs, abi_ptr x)
94
+{
95
+ return g2h_untagged(cpu_untagged_addr(cs, x));
96
+}
97
98
static inline bool guest_addr_valid(abi_ulong x)
99
{
100
@@ -XXX,XX +XXX,XX @@ static inline int cpu_ldsw_code(CPUArchState *env, abi_ptr addr)
101
static inline void *tlb_vaddr_to_host(CPUArchState *env, abi_ptr addr,
102
MMUAccessType access_type, int mmu_idx)
103
{
104
- return g2h(addr);
105
+ return g2h(env_cpu(env), addr);
106
}
107
#else
108
void *tlb_vaddr_to_host(CPUArchState *env, abi_ptr addr,
109
diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
110
index XXXXXXX..XXXXXXX 100644
111
--- a/include/exec/exec-all.h
112
+++ b/include/exec/exec-all.h
113
@@ -XXX,XX +XXX,XX @@ static inline tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env,
114
void **hostp)
115
{
116
if (hostp) {
117
- *hostp = g2h(addr);
118
+ *hostp = g2h_untagged(addr);
119
}
120
return addr;
121
}
122
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
123
index XXXXXXX..XXXXXXX 100644
124
--- a/linux-user/qemu.h
125
+++ b/linux-user/qemu.h
126
@@ -XXX,XX +XXX,XX @@ static inline void *lock_user(int type, abi_ulong guest_addr, long len, int copy
127
return addr;
128
}
129
#else
130
- return g2h(guest_addr);
131
+ return g2h_untagged(guest_addr);
132
#endif
133
}
134
135
@@ -XXX,XX +XXX,XX @@ static inline void unlock_user(void *host_ptr, abi_ulong guest_addr,
136
#ifdef DEBUG_REMAP
137
if (!host_ptr)
138
return;
139
- if (host_ptr == g2h(guest_addr))
140
+ if (host_ptr == g2h_untagged(guest_addr))
141
return;
142
if (len > 0)
143
- memcpy(g2h(guest_addr), host_ptr, len);
144
+ memcpy(g2h_untagged(guest_addr), host_ptr, len);
145
g_free(host_ptr);
146
#endif
147
}
148
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
149
index XXXXXXX..XXXXXXX 100644
150
--- a/accel/tcg/translate-all.c
151
+++ b/accel/tcg/translate-all.c
152
@@ -XXX,XX +XXX,XX @@ static inline void tb_page_add(PageDesc *p, TranslationBlock *tb,
153
prot |= p2->flags;
154
p2->flags &= ~PAGE_WRITE;
155
}
156
- mprotect(g2h(page_addr), qemu_host_page_size,
157
+ mprotect(g2h_untagged(page_addr), qemu_host_page_size,
158
(prot & PAGE_BITS) & ~PAGE_WRITE);
159
if (DEBUG_TB_INVALIDATE_GATE) {
160
printf("protecting code page: 0x" TB_PAGE_ADDR_FMT "\n", page_addr);
161
@@ -XXX,XX +XXX,XX @@ int page_unprotect(target_ulong address, uintptr_t pc)
162
}
163
#endif
164
}
165
- mprotect((void *)g2h(host_start), qemu_host_page_size,
166
+ mprotect((void *)g2h_untagged(host_start), qemu_host_page_size,
167
prot & PAGE_BITS);
168
}
169
mmap_unlock();
170
diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c
171
index XXXXXXX..XXXXXXX 100644
172
--- a/accel/tcg/user-exec.c
173
+++ b/accel/tcg/user-exec.c
174
@@ -XXX,XX +XXX,XX @@ int probe_access_flags(CPUArchState *env, target_ulong addr,
175
int flags;
176
177
flags = probe_access_internal(env, addr, 0, access_type, nonfault, ra);
178
- *phost = flags ? NULL : g2h(addr);
179
+ *phost = flags ? NULL : g2h(env_cpu(env), addr);
180
return flags;
181
}
182
183
@@ -XXX,XX +XXX,XX @@ void *probe_access(CPUArchState *env, target_ulong addr, int size,
184
flags = probe_access_internal(env, addr, size, access_type, false, ra);
185
g_assert(flags == 0);
186
187
- return size ? g2h(addr) : NULL;
188
+ return size ? g2h(env_cpu(env), addr) : NULL;
189
}
190
191
#if defined(__i386__)
192
@@ -XXX,XX +XXX,XX @@ uint32_t cpu_ldub_data(CPUArchState *env, abi_ptr ptr)
193
uint16_t meminfo = trace_mem_get_info(MO_UB, MMU_USER_IDX, false);
194
195
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
196
- ret = ldub_p(g2h(ptr));
197
+ ret = ldub_p(g2h(env_cpu(env), ptr));
198
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
199
return ret;
200
}
201
@@ -XXX,XX +XXX,XX @@ int cpu_ldsb_data(CPUArchState *env, abi_ptr ptr)
202
uint16_t meminfo = trace_mem_get_info(MO_SB, MMU_USER_IDX, false);
203
204
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
205
- ret = ldsb_p(g2h(ptr));
206
+ ret = ldsb_p(g2h(env_cpu(env), ptr));
207
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
208
return ret;
209
}
210
@@ -XXX,XX +XXX,XX @@ uint32_t cpu_lduw_be_data(CPUArchState *env, abi_ptr ptr)
211
uint16_t meminfo = trace_mem_get_info(MO_BEUW, MMU_USER_IDX, false);
212
213
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
214
- ret = lduw_be_p(g2h(ptr));
215
+ ret = lduw_be_p(g2h(env_cpu(env), ptr));
216
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
217
return ret;
218
}
219
@@ -XXX,XX +XXX,XX @@ int cpu_ldsw_be_data(CPUArchState *env, abi_ptr ptr)
220
uint16_t meminfo = trace_mem_get_info(MO_BESW, MMU_USER_IDX, false);
221
222
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
223
- ret = ldsw_be_p(g2h(ptr));
224
+ ret = ldsw_be_p(g2h(env_cpu(env), ptr));
225
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
226
return ret;
227
}
228
@@ -XXX,XX +XXX,XX @@ uint32_t cpu_ldl_be_data(CPUArchState *env, abi_ptr ptr)
229
uint16_t meminfo = trace_mem_get_info(MO_BEUL, MMU_USER_IDX, false);
230
231
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
232
- ret = ldl_be_p(g2h(ptr));
233
+ ret = ldl_be_p(g2h(env_cpu(env), ptr));
234
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
235
return ret;
236
}
237
@@ -XXX,XX +XXX,XX @@ uint64_t cpu_ldq_be_data(CPUArchState *env, abi_ptr ptr)
238
uint16_t meminfo = trace_mem_get_info(MO_BEQ, MMU_USER_IDX, false);
239
240
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
241
- ret = ldq_be_p(g2h(ptr));
242
+ ret = ldq_be_p(g2h(env_cpu(env), ptr));
243
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
244
return ret;
245
}
246
@@ -XXX,XX +XXX,XX @@ uint32_t cpu_lduw_le_data(CPUArchState *env, abi_ptr ptr)
247
uint16_t meminfo = trace_mem_get_info(MO_LEUW, MMU_USER_IDX, false);
248
249
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
250
- ret = lduw_le_p(g2h(ptr));
251
+ ret = lduw_le_p(g2h(env_cpu(env), ptr));
252
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
253
return ret;
254
}
255
@@ -XXX,XX +XXX,XX @@ int cpu_ldsw_le_data(CPUArchState *env, abi_ptr ptr)
256
uint16_t meminfo = trace_mem_get_info(MO_LESW, MMU_USER_IDX, false);
257
258
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
259
- ret = ldsw_le_p(g2h(ptr));
260
+ ret = ldsw_le_p(g2h(env_cpu(env), ptr));
261
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
262
return ret;
263
}
264
@@ -XXX,XX +XXX,XX @@ uint32_t cpu_ldl_le_data(CPUArchState *env, abi_ptr ptr)
265
uint16_t meminfo = trace_mem_get_info(MO_LEUL, MMU_USER_IDX, false);
266
267
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
268
- ret = ldl_le_p(g2h(ptr));
269
+ ret = ldl_le_p(g2h(env_cpu(env), ptr));
270
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
271
return ret;
272
}
273
@@ -XXX,XX +XXX,XX @@ uint64_t cpu_ldq_le_data(CPUArchState *env, abi_ptr ptr)
274
uint16_t meminfo = trace_mem_get_info(MO_LEQ, MMU_USER_IDX, false);
275
276
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
277
- ret = ldq_le_p(g2h(ptr));
278
+ ret = ldq_le_p(g2h(env_cpu(env), ptr));
279
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
280
return ret;
281
}
282
@@ -XXX,XX +XXX,XX @@ void cpu_stb_data(CPUArchState *env, abi_ptr ptr, uint32_t val)
283
uint16_t meminfo = trace_mem_get_info(MO_UB, MMU_USER_IDX, true);
284
285
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
286
- stb_p(g2h(ptr), val);
287
+ stb_p(g2h(env_cpu(env), ptr), val);
288
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
289
}
290
291
@@ -XXX,XX +XXX,XX @@ void cpu_stw_be_data(CPUArchState *env, abi_ptr ptr, uint32_t val)
292
uint16_t meminfo = trace_mem_get_info(MO_BEUW, MMU_USER_IDX, true);
293
294
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
295
- stw_be_p(g2h(ptr), val);
296
+ stw_be_p(g2h(env_cpu(env), ptr), val);
297
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
298
}
299
300
@@ -XXX,XX +XXX,XX @@ void cpu_stl_be_data(CPUArchState *env, abi_ptr ptr, uint32_t val)
301
uint16_t meminfo = trace_mem_get_info(MO_BEUL, MMU_USER_IDX, true);
302
303
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
304
- stl_be_p(g2h(ptr), val);
305
+ stl_be_p(g2h(env_cpu(env), ptr), val);
306
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
307
}
308
309
@@ -XXX,XX +XXX,XX @@ void cpu_stq_be_data(CPUArchState *env, abi_ptr ptr, uint64_t val)
310
uint16_t meminfo = trace_mem_get_info(MO_BEQ, MMU_USER_IDX, true);
311
312
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
313
- stq_be_p(g2h(ptr), val);
314
+ stq_be_p(g2h(env_cpu(env), ptr), val);
315
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
316
}
317
318
@@ -XXX,XX +XXX,XX @@ void cpu_stw_le_data(CPUArchState *env, abi_ptr ptr, uint32_t val)
319
uint16_t meminfo = trace_mem_get_info(MO_LEUW, MMU_USER_IDX, true);
320
321
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
322
- stw_le_p(g2h(ptr), val);
323
+ stw_le_p(g2h(env_cpu(env), ptr), val);
324
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
325
}
326
327
@@ -XXX,XX +XXX,XX @@ void cpu_stl_le_data(CPUArchState *env, abi_ptr ptr, uint32_t val)
328
uint16_t meminfo = trace_mem_get_info(MO_LEUL, MMU_USER_IDX, true);
329
330
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
331
- stl_le_p(g2h(ptr), val);
332
+ stl_le_p(g2h(env_cpu(env), ptr), val);
333
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
334
}
335
336
@@ -XXX,XX +XXX,XX @@ void cpu_stq_le_data(CPUArchState *env, abi_ptr ptr, uint64_t val)
337
uint16_t meminfo = trace_mem_get_info(MO_LEQ, MMU_USER_IDX, true);
338
339
trace_guest_mem_before_exec(env_cpu(env), ptr, meminfo);
340
- stq_le_p(g2h(ptr), val);
341
+ stq_le_p(g2h(env_cpu(env), ptr), val);
342
qemu_plugin_vcpu_mem_cb(env_cpu(env), ptr, meminfo);
343
}
344
345
@@ -XXX,XX +XXX,XX @@ uint32_t cpu_ldub_code(CPUArchState *env, abi_ptr ptr)
346
uint32_t ret;
347
348
set_helper_retaddr(1);
349
- ret = ldub_p(g2h(ptr));
350
+ ret = ldub_p(g2h_untagged(ptr));
351
clear_helper_retaddr();
352
return ret;
353
}
354
@@ -XXX,XX +XXX,XX @@ uint32_t cpu_lduw_code(CPUArchState *env, abi_ptr ptr)
355
uint32_t ret;
356
357
set_helper_retaddr(1);
358
- ret = lduw_p(g2h(ptr));
359
+ ret = lduw_p(g2h_untagged(ptr));
360
clear_helper_retaddr();
361
return ret;
362
}
363
@@ -XXX,XX +XXX,XX @@ uint32_t cpu_ldl_code(CPUArchState *env, abi_ptr ptr)
364
uint32_t ret;
365
366
set_helper_retaddr(1);
367
- ret = ldl_p(g2h(ptr));
368
+ ret = ldl_p(g2h_untagged(ptr));
369
clear_helper_retaddr();
370
return ret;
371
}
372
@@ -XXX,XX +XXX,XX @@ uint64_t cpu_ldq_code(CPUArchState *env, abi_ptr ptr)
373
uint64_t ret;
374
375
set_helper_retaddr(1);
376
- ret = ldq_p(g2h(ptr));
377
+ ret = ldq_p(g2h_untagged(ptr));
378
clear_helper_retaddr();
379
return ret;
380
}
381
@@ -XXX,XX +XXX,XX @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr,
382
if (unlikely(addr & (size - 1))) {
383
cpu_loop_exit_atomic(env_cpu(env), retaddr);
384
}
385
- void *ret = g2h(addr);
386
+ void *ret = g2h(env_cpu(env), addr);
387
set_helper_retaddr(retaddr);
388
return ret;
389
}
390
diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c
391
index XXXXXXX..XXXXXXX 100644
392
--- a/bsd-user/elfload.c
393
+++ b/bsd-user/elfload.c
394
@@ -XXX,XX +XXX,XX @@ static void padzero(abi_ulong elf_bss, abi_ulong last_bss)
395
end_addr1 = REAL_HOST_PAGE_ALIGN(elf_bss);
396
end_addr = HOST_PAGE_ALIGN(elf_bss);
397
if (end_addr1 < end_addr) {
398
- mmap((void *)g2h(end_addr1), end_addr - end_addr1,
399
+ mmap((void *)g2h_untagged(end_addr1), end_addr - end_addr1,
400
PROT_READ|PROT_WRITE|PROT_EXEC,
401
MAP_FIXED|MAP_PRIVATE|MAP_ANON, -1, 0);
402
}
403
diff --git a/bsd-user/main.c b/bsd-user/main.c
404
index XXXXXXX..XXXXXXX 100644
405
--- a/bsd-user/main.c
406
+++ b/bsd-user/main.c
407
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
408
env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1),
409
PROT_READ|PROT_WRITE,
410
MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
411
- idt_table = g2h(env->idt.base);
412
+ idt_table = g2h_untagged(env->idt.base);
413
set_idt(0, 0);
414
set_idt(1, 0);
415
set_idt(2, 0);
416
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
417
PROT_READ|PROT_WRITE,
418
MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
419
env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1;
420
- gdt_table = g2h(env->gdt.base);
421
+ gdt_table = g2h_untagged(env->gdt.base);
422
#ifdef TARGET_ABI32
423
write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
424
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
425
diff --git a/bsd-user/mmap.c b/bsd-user/mmap.c
426
index XXXXXXX..XXXXXXX 100644
427
--- a/bsd-user/mmap.c
428
+++ b/bsd-user/mmap.c
429
@@ -XXX,XX +XXX,XX @@ int target_mprotect(abi_ulong start, abi_ulong len, int prot)
430
}
431
end = host_end;
432
}
433
- ret = mprotect(g2h(host_start), qemu_host_page_size, prot1 & PAGE_BITS);
434
+ ret = mprotect(g2h_untagged(host_start),
435
+ qemu_host_page_size, prot1 & PAGE_BITS);
436
if (ret != 0)
437
goto error;
438
host_start += qemu_host_page_size;
439
@@ -XXX,XX +XXX,XX @@ int target_mprotect(abi_ulong start, abi_ulong len, int prot)
440
for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
441
prot1 |= page_get_flags(addr);
442
}
443
- ret = mprotect(g2h(host_end - qemu_host_page_size), qemu_host_page_size,
444
- prot1 & PAGE_BITS);
445
+ ret = mprotect(g2h_untagged(host_end - qemu_host_page_size),
446
+ qemu_host_page_size, prot1 & PAGE_BITS);
447
if (ret != 0)
448
goto error;
449
host_end -= qemu_host_page_size;
450
@@ -XXX,XX +XXX,XX @@ int target_mprotect(abi_ulong start, abi_ulong len, int prot)
451
452
/* handle the pages in the middle */
453
if (host_start < host_end) {
454
- ret = mprotect(g2h(host_start), host_end - host_start, prot);
455
+ ret = mprotect(g2h_untagged(host_start), host_end - host_start, prot);
456
if (ret != 0)
457
goto error;
458
}
459
@@ -XXX,XX +XXX,XX @@ static int mmap_frag(abi_ulong real_start,
460
int prot1, prot_new;
461
462
real_end = real_start + qemu_host_page_size;
463
- host_start = g2h(real_start);
464
+ host_start = g2h_untagged(real_start);
465
466
/* get the protection of the target pages outside the mapping */
467
prot1 = 0;
468
@@ -XXX,XX +XXX,XX @@ static int mmap_frag(abi_ulong real_start,
469
mprotect(host_start, qemu_host_page_size, prot1 | PROT_WRITE);
470
471
/* read the corresponding file data */
472
- pread(fd, g2h(start), end - start, offset);
473
+ pread(fd, g2h_untagged(start), end - start, offset);
474
475
/* put final protection */
476
if (prot_new != (prot1 | PROT_WRITE))
477
@@ -XXX,XX +XXX,XX @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
478
/* Note: we prefer to control the mapping address. It is
479
especially important if qemu_host_page_size >
480
qemu_real_host_page_size */
481
- p = mmap(g2h(mmap_start),
482
+ p = mmap(g2h_untagged(mmap_start),
483
host_len, prot, flags | MAP_FIXED, fd, host_offset);
484
if (p == MAP_FAILED)
485
goto fail;
486
@@ -XXX,XX +XXX,XX @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
487
-1, 0);
488
if (retaddr == -1)
489
goto fail;
490
- pread(fd, g2h(start), len, offset);
491
+ pread(fd, g2h_untagged(start), len, offset);
492
if (!(prot & PROT_WRITE)) {
493
ret = target_mprotect(start, len, prot);
494
if (ret != 0) {
495
@@ -XXX,XX +XXX,XX @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
496
offset1 = 0;
497
else
498
offset1 = offset + real_start - start;
499
- p = mmap(g2h(real_start), real_end - real_start,
500
+ p = mmap(g2h_untagged(real_start), real_end - real_start,
501
prot, flags, fd, offset1);
502
if (p == MAP_FAILED)
503
goto fail;
504
@@ -XXX,XX +XXX,XX @@ int target_munmap(abi_ulong start, abi_ulong len)
505
ret = 0;
506
/* unmap what we can */
507
if (real_start < real_end) {
508
- ret = munmap(g2h(real_start), real_end - real_start);
509
+ ret = munmap(g2h_untagged(real_start), real_end - real_start);
510
}
511
512
if (ret == 0)
513
@@ -XXX,XX +XXX,XX @@ int target_msync(abi_ulong start, abi_ulong len, int flags)
514
return 0;
515
516
start &= qemu_host_page_mask;
517
- return msync(g2h(start), end - start, flags);
518
+ return msync(g2h_untagged(start), end - start, flags);
519
}
520
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
521
index XXXXXXX..XXXXXXX 100644
522
--- a/linux-user/elfload.c
523
+++ b/linux-user/elfload.c
524
@@ -XXX,XX +XXX,XX @@ enum {
525
526
static bool init_guest_commpage(void)
527
{
528
- void *want = g2h(ARM_COMMPAGE & -qemu_host_page_size);
529
+ void *want = g2h_untagged(ARM_COMMPAGE & -qemu_host_page_size);
530
void *addr = mmap(want, qemu_host_page_size, PROT_READ | PROT_WRITE,
531
MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
532
533
@@ -XXX,XX +XXX,XX @@ static bool init_guest_commpage(void)
534
}
535
536
/* Set kernel helper versions; rest of page is 0. */
537
- __put_user(5, (uint32_t *)g2h(0xffff0ffcu));
538
+ __put_user(5, (uint32_t *)g2h_untagged(0xffff0ffcu));
539
540
if (mprotect(addr, qemu_host_page_size, PROT_READ)) {
541
perror("Protecting guest commpage");
542
@@ -XXX,XX +XXX,XX @@ static void zero_bss(abi_ulong elf_bss, abi_ulong last_bss, int prot)
543
here is still actually needed. For now, continue with it,
544
but merge it with the "normal" mmap that would allocate the bss. */
545
546
- host_start = (uintptr_t) g2h(elf_bss);
547
- host_end = (uintptr_t) g2h(last_bss);
548
+ host_start = (uintptr_t) g2h_untagged(elf_bss);
549
+ host_end = (uintptr_t) g2h_untagged(last_bss);
550
host_map_start = REAL_HOST_PAGE_ALIGN(host_start);
551
552
if (host_map_start < host_end) {
553
@@ -XXX,XX +XXX,XX @@ static void pgb_have_guest_base(const char *image_name, abi_ulong guest_loaddr,
554
}
555
556
/* Reserve the address space for the binary, or reserved_va. */
557
- test = g2h(guest_loaddr);
558
+ test = g2h_untagged(guest_loaddr);
559
addr = mmap(test, guest_hiaddr - guest_loaddr, PROT_NONE, flags, -1, 0);
560
if (test != addr) {
561
pgb_fail_in_use(image_name);
562
@@ -XXX,XX +XXX,XX @@ static void pgb_reserved_va(const char *image_name, abi_ulong guest_loaddr,
563
564
/* Reserve the memory on the host. */
565
assert(guest_base != 0);
566
- test = g2h(0);
567
+ test = g2h_untagged(0);
568
addr = mmap(test, reserved_va, PROT_NONE, flags, -1, 0);
569
if (addr == MAP_FAILED || addr != test) {
570
error_report("Unable to reserve 0x%lx bytes of virtual address "
571
diff --git a/linux-user/flatload.c b/linux-user/flatload.c
572
index XXXXXXX..XXXXXXX 100644
573
--- a/linux-user/flatload.c
574
+++ b/linux-user/flatload.c
575
@@ -XXX,XX +XXX,XX @@ static int load_flat_file(struct linux_binprm * bprm,
576
}
577
578
/* zero the BSS. */
579
- memset(g2h(datapos + data_len), 0, bss_len);
580
+ memset(g2h_untagged(datapos + data_len), 0, bss_len);
581
582
return 0;
583
}
584
diff --git a/linux-user/hppa/cpu_loop.c b/linux-user/hppa/cpu_loop.c
585
index XXXXXXX..XXXXXXX 100644
586
--- a/linux-user/hppa/cpu_loop.c
587
+++ b/linux-user/hppa/cpu_loop.c
588
@@ -XXX,XX +XXX,XX @@
589
590
static abi_ulong hppa_lws(CPUHPPAState *env)
591
{
592
+ CPUState *cs = env_cpu(env);
593
uint32_t which = env->gr[20];
594
abi_ulong addr = env->gr[26];
595
abi_ulong old = env->gr[25];
596
@@ -XXX,XX +XXX,XX @@ static abi_ulong hppa_lws(CPUHPPAState *env)
597
}
598
old = tswap32(old);
599
new = tswap32(new);
600
- ret = qatomic_cmpxchg((uint32_t *)g2h(addr), old, new);
601
+ ret = qatomic_cmpxchg((uint32_t *)g2h(cs, addr), old, new);
602
ret = tswap32(ret);
603
break;
604
605
@@ -XXX,XX +XXX,XX @@ static abi_ulong hppa_lws(CPUHPPAState *env)
606
can be host-endian as well. */
607
switch (size) {
608
case 0:
609
- old = *(uint8_t *)g2h(old);
610
- new = *(uint8_t *)g2h(new);
611
- ret = qatomic_cmpxchg((uint8_t *)g2h(addr), old, new);
612
+ old = *(uint8_t *)g2h(cs, old);
613
+ new = *(uint8_t *)g2h(cs, new);
614
+ ret = qatomic_cmpxchg((uint8_t *)g2h(cs, addr), old, new);
615
ret = ret != old;
616
break;
617
case 1:
618
- old = *(uint16_t *)g2h(old);
619
- new = *(uint16_t *)g2h(new);
620
- ret = qatomic_cmpxchg((uint16_t *)g2h(addr), old, new);
621
+ old = *(uint16_t *)g2h(cs, old);
622
+ new = *(uint16_t *)g2h(cs, new);
623
+ ret = qatomic_cmpxchg((uint16_t *)g2h(cs, addr), old, new);
624
ret = ret != old;
625
break;
626
case 2:
627
- old = *(uint32_t *)g2h(old);
628
- new = *(uint32_t *)g2h(new);
629
- ret = qatomic_cmpxchg((uint32_t *)g2h(addr), old, new);
630
+ old = *(uint32_t *)g2h(cs, old);
631
+ new = *(uint32_t *)g2h(cs, new);
632
+ ret = qatomic_cmpxchg((uint32_t *)g2h(cs, addr), old, new);
633
ret = ret != old;
634
break;
635
case 3:
636
{
637
uint64_t o64, n64, r64;
638
- o64 = *(uint64_t *)g2h(old);
639
- n64 = *(uint64_t *)g2h(new);
640
+ o64 = *(uint64_t *)g2h(cs, old);
641
+ n64 = *(uint64_t *)g2h(cs, new);
642
#ifdef CONFIG_ATOMIC64
643
- r64 = qatomic_cmpxchg__nocheck((uint64_t *)g2h(addr),
644
+ r64 = qatomic_cmpxchg__nocheck((uint64_t *)g2h(cs, addr),
645
o64, n64);
646
ret = r64 != o64;
647
#else
648
start_exclusive();
649
- r64 = *(uint64_t *)g2h(addr);
650
+ r64 = *(uint64_t *)g2h(cs, addr);
651
ret = 1;
652
if (r64 == o64) {
653
- *(uint64_t *)g2h(addr) = n64;
654
+ *(uint64_t *)g2h(cs, addr) = n64;
655
ret = 0;
656
}
657
end_exclusive();
658
diff --git a/linux-user/i386/cpu_loop.c b/linux-user/i386/cpu_loop.c
659
index XXXXXXX..XXXXXXX 100644
660
--- a/linux-user/i386/cpu_loop.c
661
+++ b/linux-user/i386/cpu_loop.c
662
@@ -XXX,XX +XXX,XX @@ void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
663
env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1),
664
PROT_READ|PROT_WRITE,
665
MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
666
- idt_table = g2h(env->idt.base);
667
+ idt_table = g2h_untagged(env->idt.base);
668
set_idt(0, 0);
669
set_idt(1, 0);
670
set_idt(2, 0);
671
@@ -XXX,XX +XXX,XX @@ void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
672
PROT_READ|PROT_WRITE,
673
MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
674
env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1;
675
- gdt_table = g2h(env->gdt.base);
676
+ gdt_table = g2h_untagged(env->gdt.base);
677
#ifdef TARGET_ABI32
678
write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
679
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
680
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
681
index XXXXXXX..XXXXXXX 100644
682
--- a/linux-user/mmap.c
683
+++ b/linux-user/mmap.c
684
@@ -XXX,XX +XXX,XX @@ int target_mprotect(abi_ulong start, abi_ulong len, int target_prot)
685
}
686
end = host_end;
687
}
688
- ret = mprotect(g2h(host_start), qemu_host_page_size,
689
+ ret = mprotect(g2h_untagged(host_start), qemu_host_page_size,
690
prot1 & PAGE_BITS);
691
if (ret != 0) {
692
goto error;
693
@@ -XXX,XX +XXX,XX @@ int target_mprotect(abi_ulong start, abi_ulong len, int target_prot)
694
for (addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
695
prot1 |= page_get_flags(addr);
696
}
697
- ret = mprotect(g2h(host_end - qemu_host_page_size),
698
+ ret = mprotect(g2h_untagged(host_end - qemu_host_page_size),
699
qemu_host_page_size, prot1 & PAGE_BITS);
700
if (ret != 0) {
701
goto error;
702
@@ -XXX,XX +XXX,XX @@ int target_mprotect(abi_ulong start, abi_ulong len, int target_prot)
703
704
/* handle the pages in the middle */
705
if (host_start < host_end) {
706
- ret = mprotect(g2h(host_start), host_end - host_start, host_prot);
707
+ ret = mprotect(g2h_untagged(host_start),
708
+ host_end - host_start, host_prot);
709
if (ret != 0) {
710
goto error;
711
}
712
@@ -XXX,XX +XXX,XX @@ static int mmap_frag(abi_ulong real_start,
713
int prot1, prot_new;
714
715
real_end = real_start + qemu_host_page_size;
716
- host_start = g2h(real_start);
717
+ host_start = g2h_untagged(real_start);
718
719
/* get the protection of the target pages outside the mapping */
720
prot1 = 0;
721
@@ -XXX,XX +XXX,XX @@ static int mmap_frag(abi_ulong real_start,
722
mprotect(host_start, qemu_host_page_size, prot1 | PROT_WRITE);
723
724
/* read the corresponding file data */
725
- if (pread(fd, g2h(start), end - start, offset) == -1)
726
+ if (pread(fd, g2h_untagged(start), end - start, offset) == -1)
727
return -1;
728
729
/* put final protection */
730
@@ -XXX,XX +XXX,XX @@ static int mmap_frag(abi_ulong real_start,
731
mprotect(host_start, qemu_host_page_size, prot_new);
732
}
733
if (prot_new & PROT_WRITE) {
734
- memset(g2h(start), 0, end - start);
735
+ memset(g2h_untagged(start), 0, end - start);
736
}
737
}
738
return 0;
739
@@ -XXX,XX +XXX,XX @@ abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size, abi_ulong align)
740
* - mremap() with MREMAP_FIXED flag
741
* - shmat() with SHM_REMAP flag
742
*/
743
- ptr = mmap(g2h(addr), size, PROT_NONE,
744
+ ptr = mmap(g2h_untagged(addr), size, PROT_NONE,
745
MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0);
746
747
/* ENOMEM, if host address space has no memory */
748
@@ -XXX,XX +XXX,XX @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot,
749
/* Note: we prefer to control the mapping address. It is
750
especially important if qemu_host_page_size >
751
qemu_real_host_page_size */
752
- p = mmap(g2h(start), host_len, host_prot,
753
+ p = mmap(g2h_untagged(start), host_len, host_prot,
754
flags | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
755
if (p == MAP_FAILED) {
756
goto fail;
757
@@ -XXX,XX +XXX,XX @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot,
758
/* update start so that it points to the file position at 'offset' */
759
host_start = (unsigned long)p;
760
if (!(flags & MAP_ANONYMOUS)) {
761
- p = mmap(g2h(start), len, host_prot,
762
+ p = mmap(g2h_untagged(start), len, host_prot,
763
flags | MAP_FIXED, fd, host_offset);
764
if (p == MAP_FAILED) {
765
- munmap(g2h(start), host_len);
766
+ munmap(g2h_untagged(start), host_len);
767
goto fail;
768
}
769
host_start += offset - host_offset;
770
@@ -XXX,XX +XXX,XX @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot,
771
-1, 0);
772
if (retaddr == -1)
773
goto fail;
774
- if (pread(fd, g2h(start), len, offset) == -1)
775
+ if (pread(fd, g2h_untagged(start), len, offset) == -1)
776
goto fail;
777
if (!(host_prot & PROT_WRITE)) {
778
ret = target_mprotect(start, len, target_prot);
779
@@ -XXX,XX +XXX,XX @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot,
780
offset1 = 0;
781
else
782
offset1 = offset + real_start - start;
783
- p = mmap(g2h(real_start), real_end - real_start,
784
+ p = mmap(g2h_untagged(real_start), real_end - real_start,
785
host_prot, flags, fd, offset1);
786
if (p == MAP_FAILED)
787
goto fail;
788
@@ -XXX,XX +XXX,XX @@ static void mmap_reserve(abi_ulong start, abi_ulong size)
789
real_end -= qemu_host_page_size;
790
}
791
if (real_start != real_end) {
792
- mmap(g2h(real_start), real_end - real_start, PROT_NONE,
793
+ mmap(g2h_untagged(real_start), real_end - real_start, PROT_NONE,
794
MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE,
795
-1, 0);
796
}
797
@@ -XXX,XX +XXX,XX @@ int target_munmap(abi_ulong start, abi_ulong len)
798
if (reserved_va) {
799
mmap_reserve(real_start, real_end - real_start);
800
} else {
801
- ret = munmap(g2h(real_start), real_end - real_start);
802
+ ret = munmap(g2h_untagged(real_start), real_end - real_start);
803
}
804
}
805
806
@@ -XXX,XX +XXX,XX @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
807
mmap_lock();
808
809
if (flags & MREMAP_FIXED) {
810
- host_addr = mremap(g2h(old_addr), old_size, new_size,
811
- flags, g2h(new_addr));
812
+ host_addr = mremap(g2h_untagged(old_addr), old_size, new_size,
813
+ flags, g2h_untagged(new_addr));
814
815
if (reserved_va && host_addr != MAP_FAILED) {
816
/* If new and old addresses overlap then the above mremap will
817
@@ -XXX,XX +XXX,XX @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
818
errno = ENOMEM;
819
host_addr = MAP_FAILED;
820
} else {
821
- host_addr = mremap(g2h(old_addr), old_size, new_size,
822
- flags | MREMAP_FIXED, g2h(mmap_start));
823
+ host_addr = mremap(g2h_untagged(old_addr), old_size, new_size,
824
+ flags | MREMAP_FIXED,
825
+ g2h_untagged(mmap_start));
826
if (reserved_va) {
827
mmap_reserve(old_addr, old_size);
828
}
829
@@ -XXX,XX +XXX,XX @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
830
}
831
}
832
if (prot == 0) {
833
- host_addr = mremap(g2h(old_addr), old_size, new_size, flags);
834
+ host_addr = mremap(g2h_untagged(old_addr),
835
+ old_size, new_size, flags);
836
837
if (host_addr != MAP_FAILED) {
838
/* Check if address fits target address space */
839
if (!guest_range_valid(h2g(host_addr), new_size)) {
840
/* Revert mremap() changes */
841
- host_addr = mremap(g2h(old_addr), new_size, old_size,
842
- flags);
843
+ host_addr = mremap(g2h_untagged(old_addr),
844
+ new_size, old_size, flags);
845
errno = ENOMEM;
846
host_addr = MAP_FAILED;
847
} else if (reserved_va && old_size > new_size) {
848
diff --git a/linux-user/ppc/signal.c b/linux-user/ppc/signal.c
849
index XXXXXXX..XXXXXXX 100644
850
--- a/linux-user/ppc/signal.c
851
+++ b/linux-user/ppc/signal.c
852
@@ -XXX,XX +XXX,XX @@ static void restore_user_regs(CPUPPCState *env,
853
uint64_t v_addr;
854
/* 64-bit needs to recover the pointer to the vectors from the frame */
855
__get_user(v_addr, &frame->v_regs);
856
- v_regs = g2h(v_addr);
857
+ v_regs = g2h(env_cpu(env), v_addr);
858
#else
859
v_regs = (ppc_avr_t *)frame->mc_vregs.altivec;
860
#endif
861
@@ -XXX,XX +XXX,XX @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
862
if (get_ppc64_abi(image) < 2) {
863
/* ELFv1 PPC64 function pointers are pointers to OPD entries. */
864
struct target_func_ptr *handler =
865
- (struct target_func_ptr *)g2h(ka->_sa_handler);
866
+ (struct target_func_ptr *)g2h(env_cpu(env), ka->_sa_handler);
867
env->nip = tswapl(handler->entry);
868
env->gpr[2] = tswapl(handler->toc);
869
} else {
870
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
871
index XXXXXXX..XXXXXXX 100644
872
--- a/linux-user/syscall.c
873
+++ b/linux-user/syscall.c
874
@@ -XXX,XX +XXX,XX @@ abi_long do_brk(abi_ulong new_brk)
875
/* Heap contents are initialized to zero, as for anonymous
876
* mapped pages. */
877
if (new_brk > target_brk) {
878
- memset(g2h(target_brk), 0, new_brk - target_brk);
879
+ memset(g2h_untagged(target_brk), 0, new_brk - target_brk);
880
}
881
    target_brk = new_brk;
882
DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
883
@@ -XXX,XX +XXX,XX @@ abi_long do_brk(abi_ulong new_brk)
884
* come from the remaining part of the previous page: it may
885
* contains garbage data due to a previous heap usage (grown
886
* then shrunken). */
887
- memset(g2h(target_brk), 0, brk_page - target_brk);
888
+ memset(g2h_untagged(target_brk), 0, brk_page - target_brk);
889
890
target_brk = new_brk;
891
brk_page = HOST_PAGE_ALIGN(target_brk);
892
@@ -XXX,XX +XXX,XX @@ static inline abi_ulong do_shmat(CPUArchState *cpu_env,
893
mmap_lock();
894
895
if (shmaddr)
896
- host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
897
+ host_raddr = shmat(shmid, (void *)g2h_untagged(shmaddr), shmflg);
898
else {
899
abi_ulong mmap_start;
900
901
@@ -XXX,XX +XXX,XX @@ static inline abi_ulong do_shmat(CPUArchState *cpu_env,
902
errno = ENOMEM;
903
host_raddr = (void *)-1;
904
} else
905
- host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
906
+ host_raddr = shmat(shmid, g2h_untagged(mmap_start),
907
+ shmflg | SHM_REMAP);
908
}
909
910
if (host_raddr == (void *)-1) {
911
@@ -XXX,XX +XXX,XX @@ static inline abi_long do_shmdt(abi_ulong shmaddr)
912
break;
913
}
914
}
915
- rv = get_errno(shmdt(g2h(shmaddr)));
916
+ rv = get_errno(shmdt(g2h_untagged(shmaddr)));
917
918
mmap_unlock();
919
920
@@ -XXX,XX +XXX,XX @@ static abi_long write_ldt(CPUX86State *env,
921
MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
922
if (env->ldt.base == -1)
923
return -TARGET_ENOMEM;
924
- memset(g2h(env->ldt.base), 0,
925
+ memset(g2h_untagged(env->ldt.base), 0,
926
TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
927
env->ldt.limit = 0xffff;
928
- ldt_table = g2h(env->ldt.base);
929
+ ldt_table = g2h_untagged(env->ldt.base);
930
}
931
932
/* NOTE: same code as Linux kernel */
933
@@ -XXX,XX +XXX,XX @@ static abi_long do_modify_ldt(CPUX86State *env, int func, abi_ulong ptr,
934
#if defined(TARGET_ABI32)
935
abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr)
936
{
937
- uint64_t *gdt_table = g2h(env->gdt.base);
938
+ uint64_t *gdt_table = g2h_untagged(env->gdt.base);
939
struct target_modify_ldt_ldt_s ldt_info;
940
struct target_modify_ldt_ldt_s *target_ldt_info;
941
int seg_32bit, contents, read_exec_only, limit_in_pages;
942
@@ -XXX,XX +XXX,XX @@ install:
943
static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr)
944
{
945
struct target_modify_ldt_ldt_s *target_ldt_info;
946
- uint64_t *gdt_table = g2h(env->gdt.base);
947
+ uint64_t *gdt_table = g2h_untagged(env->gdt.base);
948
uint32_t base_addr, limit, flags;
949
int seg_32bit, contents, read_exec_only, limit_in_pages, idx;
950
int seg_not_present, useable, lm;
951
@@ -XXX,XX +XXX,XX @@ static int do_safe_futex(int *uaddr, int op, int val,
952
tricky. However they're probably useless because guest atomic
953
operations won't work either. */
954
#if defined(TARGET_NR_futex)
955
-static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
956
- target_ulong uaddr2, int val3)
957
+static int do_futex(CPUState *cpu, target_ulong uaddr, int op, int val,
958
+ target_ulong timeout, target_ulong uaddr2, int val3)
959
{
960
struct timespec ts, *pts;
961
int base_op;
962
@@ -XXX,XX +XXX,XX @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
963
} else {
964
pts = NULL;
965
}
966
- return do_safe_futex(g2h(uaddr), op, tswap32(val), pts, NULL, val3);
967
+ return do_safe_futex(g2h(cpu, uaddr),
968
+ op, tswap32(val), pts, NULL, val3);
969
case FUTEX_WAKE:
970
- return do_safe_futex(g2h(uaddr), op, val, NULL, NULL, 0);
971
+ return do_safe_futex(g2h(cpu, uaddr),
972
+ op, val, NULL, NULL, 0);
973
case FUTEX_FD:
974
- return do_safe_futex(g2h(uaddr), op, val, NULL, NULL, 0);
975
+ return do_safe_futex(g2h(cpu, uaddr),
976
+ op, val, NULL, NULL, 0);
977
case FUTEX_REQUEUE:
978
case FUTEX_CMP_REQUEUE:
979
case FUTEX_WAKE_OP:
980
@@ -XXX,XX +XXX,XX @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
981
to satisfy the compiler. We do not need to tswap TIMEOUT
982
since it's not compared to guest memory. */
983
pts = (struct timespec *)(uintptr_t) timeout;
984
- return do_safe_futex(g2h(uaddr), op, val, pts, g2h(uaddr2),
985
+ return do_safe_futex(g2h(cpu, uaddr), op, val, pts, g2h(cpu, uaddr2),
986
(base_op == FUTEX_CMP_REQUEUE
987
- ? tswap32(val3)
988
- : val3));
989
+ ? tswap32(val3) : val3));
990
default:
991
return -TARGET_ENOSYS;
992
}
993
@@ -XXX,XX +XXX,XX @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
994
#endif
995
996
#if defined(TARGET_NR_futex_time64)
997
-static int do_futex_time64(target_ulong uaddr, int op, int val, target_ulong timeout,
998
+static int do_futex_time64(CPUState *cpu, target_ulong uaddr, int op,
999
+ int val, target_ulong timeout,
1000
target_ulong uaddr2, int val3)
1001
{
1002
struct timespec ts, *pts;
1003
@@ -XXX,XX +XXX,XX @@ static int do_futex_time64(target_ulong uaddr, int op, int val, target_ulong tim
1004
} else {
1005
pts = NULL;
1006
}
1007
- return do_safe_futex(g2h(uaddr), op, tswap32(val), pts, NULL, val3);
1008
+ return do_safe_futex(g2h(cpu, uaddr), op,
1009
+ tswap32(val), pts, NULL, val3);
1010
case FUTEX_WAKE:
1011
- return do_safe_futex(g2h(uaddr), op, val, NULL, NULL, 0);
1012
+ return do_safe_futex(g2h(cpu, uaddr), op, val, NULL, NULL, 0);
1013
case FUTEX_FD:
1014
- return do_safe_futex(g2h(uaddr), op, val, NULL, NULL, 0);
1015
+ return do_safe_futex(g2h(cpu, uaddr), op, val, NULL, NULL, 0);
1016
case FUTEX_REQUEUE:
1017
case FUTEX_CMP_REQUEUE:
1018
case FUTEX_WAKE_OP:
1019
@@ -XXX,XX +XXX,XX @@ static int do_futex_time64(target_ulong uaddr, int op, int val, target_ulong tim
1020
to satisfy the compiler. We do not need to tswap TIMEOUT
1021
since it's not compared to guest memory. */
1022
pts = (struct timespec *)(uintptr_t) timeout;
1023
- return do_safe_futex(g2h(uaddr), op, val, pts, g2h(uaddr2),
1024
+ return do_safe_futex(g2h(cpu, uaddr), op, val, pts, g2h(cpu, uaddr2),
1025
(base_op == FUTEX_CMP_REQUEUE
1026
- ? tswap32(val3)
1027
- : val3));
1028
+ ? tswap32(val3) : val3));
1029
default:
1030
return -TARGET_ENOSYS;
1031
}
1032
@@ -XXX,XX +XXX,XX @@ static int open_self_maps(void *cpu_env, int fd)
1033
const char *path;
1034
1035
max = h2g_valid(max - 1) ?
1036
- max : (uintptr_t) g2h(GUEST_ADDR_MAX) + 1;
1037
+ max : (uintptr_t) g2h_untagged(GUEST_ADDR_MAX) + 1;
1038
1039
if (page_check_range(h2g(min), max - min, flags) == -1) {
1040
continue;
1041
@@ -XXX,XX +XXX,XX @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
1042
1043
if (ts->child_tidptr) {
1044
put_user_u32(0, ts->child_tidptr);
1045
- do_sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
1046
- NULL, NULL, 0);
1047
+ do_sys_futex(g2h(cpu, ts->child_tidptr),
1048
+ FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
1049
}
1050
thread_cpu = NULL;
1051
g_free(ts);
1052
@@ -XXX,XX +XXX,XX @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
1053
if (!arg5) {
1054
ret = mount(p, p2, p3, (unsigned long)arg4, NULL);
1055
} else {
1056
- ret = mount(p, p2, p3, (unsigned long)arg4, g2h(arg5));
1057
+ ret = mount(p, p2, p3, (unsigned long)arg4, g2h(cpu, arg5));
1058
}
1059
ret = get_errno(ret);
1060
1061
@@ -XXX,XX +XXX,XX @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
1062
/* ??? msync/mlock/munlock are broken for softmmu. */
1063
#ifdef TARGET_NR_msync
1064
case TARGET_NR_msync:
1065
- return get_errno(msync(g2h(arg1), arg2, arg3));
1066
+ return get_errno(msync(g2h(cpu, arg1), arg2, arg3));
1067
#endif
1068
#ifdef TARGET_NR_mlock
1069
case TARGET_NR_mlock:
1070
- return get_errno(mlock(g2h(arg1), arg2));
1071
+ return get_errno(mlock(g2h(cpu, arg1), arg2));
1072
#endif
1073
#ifdef TARGET_NR_munlock
1074
case TARGET_NR_munlock:
1075
- return get_errno(munlock(g2h(arg1), arg2));
1076
+ return get_errno(munlock(g2h(cpu, arg1), arg2));
1077
#endif
1078
#ifdef TARGET_NR_mlockall
1079
case TARGET_NR_mlockall:
1080
@@ -XXX,XX +XXX,XX @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
1081
1082
#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
1083
case TARGET_NR_set_tid_address:
1084
- return get_errno(set_tid_address((int *)g2h(arg1)));
1085
+ return get_errno(set_tid_address((int *)g2h(cpu, arg1)));
1086
#endif
1087
1088
case TARGET_NR_tkill:
1089
@@ -XXX,XX +XXX,XX @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
1090
#endif
1091
#ifdef TARGET_NR_futex
1092
case TARGET_NR_futex:
1093
- return do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
1094
+ return do_futex(cpu, arg1, arg2, arg3, arg4, arg5, arg6);
1095
#endif
1096
#ifdef TARGET_NR_futex_time64
1097
case TARGET_NR_futex_time64:
1098
- return do_futex_time64(arg1, arg2, arg3, arg4, arg5, arg6);
1099
+ return do_futex_time64(cpu, arg1, arg2, arg3, arg4, arg5, arg6);
1100
#endif
1101
#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
1102
case TARGET_NR_inotify_init:
1103
diff --git a/target/arm/helper-a64.c b/target/arm/helper-a64.c
1104
index XXXXXXX..XXXXXXX 100644
1105
--- a/target/arm/helper-a64.c
1106
+++ b/target/arm/helper-a64.c
1107
@@ -XXX,XX +XXX,XX @@ uint64_t HELPER(paired_cmpxchg64_le)(CPUARMState *env, uint64_t addr,
1108
1109
#ifdef CONFIG_USER_ONLY
1110
/* ??? Enforce alignment. */
1111
- uint64_t *haddr = g2h(addr);
1112
+ uint64_t *haddr = g2h(env_cpu(env), addr);
1113
1114
set_helper_retaddr(ra);
1115
o0 = ldq_le_p(haddr + 0);
1116
@@ -XXX,XX +XXX,XX @@ uint64_t HELPER(paired_cmpxchg64_be)(CPUARMState *env, uint64_t addr,
1117
1118
#ifdef CONFIG_USER_ONLY
1119
/* ??? Enforce alignment. */
1120
- uint64_t *haddr = g2h(addr);
1121
+ uint64_t *haddr = g2h(env_cpu(env), addr);
1122
1123
set_helper_retaddr(ra);
1124
o1 = ldq_be_p(haddr + 0);
1125
diff --git a/target/hppa/op_helper.c b/target/hppa/op_helper.c
1126
index XXXXXXX..XXXXXXX 100644
1127
--- a/target/hppa/op_helper.c
1128
+++ b/target/hppa/op_helper.c
1129
@@ -XXX,XX +XXX,XX @@ static void atomic_store_3(CPUHPPAState *env, target_ulong addr, uint32_t val,
1130
#ifdef CONFIG_USER_ONLY
1131
uint32_t old, new, cmp;
1132
1133
- uint32_t *haddr = g2h(addr - 1);
1134
+ uint32_t *haddr = g2h(env_cpu(env), addr - 1);
1135
old = *haddr;
1136
while (1) {
1137
new = (old & ~mask) | (val & mask);
1138
diff --git a/target/i386/tcg/mem_helper.c b/target/i386/tcg/mem_helper.c
1139
index XXXXXXX..XXXXXXX 100644
1140
--- a/target/i386/tcg/mem_helper.c
1141
+++ b/target/i386/tcg/mem_helper.c
1142
@@ -XXX,XX +XXX,XX @@ void helper_cmpxchg8b(CPUX86State *env, target_ulong a0)
1143
1144
#ifdef CONFIG_USER_ONLY
1145
{
1146
- uint64_t *haddr = g2h(a0);
1147
+ uint64_t *haddr = g2h(env_cpu(env), a0);
1148
cmpv = cpu_to_le64(cmpv);
1149
newv = cpu_to_le64(newv);
1150
oldv = qatomic_cmpxchg__nocheck(haddr, cmpv, newv);
1151
diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c
1152
index XXXXXXX..XXXXXXX 100644
1153
--- a/target/s390x/mem_helper.c
1154
+++ b/target/s390x/mem_helper.c
1155
@@ -XXX,XX +XXX,XX @@ static uint32_t do_csst(CPUS390XState *env, uint32_t r3, uint64_t a1,
1156
1157
if (parallel) {
1158
#ifdef CONFIG_USER_ONLY
1159
- uint32_t *haddr = g2h(a1);
1160
+ uint32_t *haddr = g2h(env_cpu(env), a1);
1161
ov = qatomic_cmpxchg__nocheck(haddr, cv, nv);
1162
#else
1163
TCGMemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mem_idx);
1164
@@ -XXX,XX +XXX,XX @@ static uint32_t do_csst(CPUS390XState *env, uint32_t r3, uint64_t a1,
1165
if (parallel) {
1166
#ifdef CONFIG_ATOMIC64
1167
# ifdef CONFIG_USER_ONLY
1168
- uint64_t *haddr = g2h(a1);
1169
+ uint64_t *haddr = g2h(env_cpu(env), a1);
1170
ov = qatomic_cmpxchg__nocheck(haddr, cv, nv);
1171
# else
1172
TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN, mem_idx);
1173
--
41
--
1174
2.20.1
42
2.34.1
1175
1176
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
Set the default NaN pattern explicitly, and remove the ifdef from
2
parts64_default_nan().
2
3
3
This is the only use of guest_addr_valid that does not begin
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
with a guest address, but a host address being transformed to
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
a guest address.
6
Message-id: 20241202131347.498124-39-peter.maydell@linaro.org
7
---
8
target/hppa/fpu_helper.c | 2 ++
9
fpu/softfloat-specialize.c.inc | 3 ---
10
2 files changed, 2 insertions(+), 3 deletions(-)
6
11
7
We will shortly adjust guest_addr_valid to handle guest memory
12
diff --git a/target/hppa/fpu_helper.c b/target/hppa/fpu_helper.c
8
tags, and the host address should not be subjected to that.
9
10
Move h2g_valid adjacent to the other h2g macros.
11
12
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
13
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
14
Message-id: 20210212184902.1251044-10-richard.henderson@linaro.org
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
---
17
include/exec/cpu_ldst.h | 5 ++++-
18
1 file changed, 4 insertions(+), 1 deletion(-)
19
20
diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h
21
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
22
--- a/include/exec/cpu_ldst.h
14
--- a/target/hppa/fpu_helper.c
23
+++ b/include/exec/cpu_ldst.h
15
+++ b/target/hppa/fpu_helper.c
24
@@ -XXX,XX +XXX,XX @@ typedef uint64_t abi_ptr;
16
@@ -XXX,XX +XXX,XX @@ void HELPER(loaded_fr0)(CPUHPPAState *env)
25
#else
17
set_float_3nan_prop_rule(float_3nan_prop_abc, &env->fp_status);
26
#define guest_addr_valid(x) ((x) <= GUEST_ADDR_MAX)
18
/* For inf * 0 + NaN, return the input NaN */
27
#endif
19
set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
28
-#define h2g_valid(x) guest_addr_valid((uintptr_t)(x) - guest_base)
20
+ /* Default NaN: sign bit clear, msb-1 frac bit set */
29
21
+ set_float_default_nan_pattern(0b00100000, &env->fp_status);
30
static inline bool guest_range_valid(abi_ulong start, abi_ulong len)
31
{
32
return len - 1 <= GUEST_ADDR_MAX && start <= GUEST_ADDR_MAX - len + 1;
33
}
22
}
34
23
35
+#define h2g_valid(x) \
24
void cpu_hppa_loaded_fr0(CPUHPPAState *env)
36
+ (HOST_LONG_BITS <= TARGET_VIRT_ADDR_SPACE_BITS || \
25
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
37
+ (uintptr_t)(x) - guest_base <= GUEST_ADDR_MAX)
26
index XXXXXXX..XXXXXXX 100644
38
+
27
--- a/fpu/softfloat-specialize.c.inc
39
#define h2g_nocheck(x) ({ \
28
+++ b/fpu/softfloat-specialize.c.inc
40
uintptr_t __ret = (uintptr_t)(x) - guest_base; \
29
@@ -XXX,XX +XXX,XX @@ static void parts64_default_nan(FloatParts64 *p, float_status *status)
41
(abi_ptr)__ret; \
30
#if defined(TARGET_SPARC) || defined(TARGET_M68K)
31
/* Sign bit clear, all frac bits set */
32
dnan_pattern = 0b01111111;
33
-#elif defined(TARGET_HPPA)
34
- /* Sign bit clear, msb-1 frac bit set */
35
- dnan_pattern = 0b00100000;
36
#elif defined(TARGET_HEXAGON)
37
/* Sign bit set, all frac bits set. */
38
dnan_pattern = 0b11111111;
42
--
39
--
43
2.20.1
40
2.34.1
44
45
diff view generated by jsdifflib
New patch
1
Set the default NaN pattern explicitly for the alpha target.
1
2
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Message-id: 20241202131347.498124-40-peter.maydell@linaro.org
6
---
7
target/alpha/cpu.c | 2 ++
8
1 file changed, 2 insertions(+)
9
10
diff --git a/target/alpha/cpu.c b/target/alpha/cpu.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/target/alpha/cpu.c
13
+++ b/target/alpha/cpu.c
14
@@ -XXX,XX +XXX,XX @@ static void alpha_cpu_initfn(Object *obj)
15
* operand in Fa. That is float_2nan_prop_ba.
16
*/
17
set_float_2nan_prop_rule(float_2nan_prop_x87, &env->fp_status);
18
+ /* Default NaN: sign bit clear, msb frac bit set */
19
+ set_float_default_nan_pattern(0b01000000, &env->fp_status);
20
#if defined(CONFIG_USER_ONLY)
21
env->flags = ENV_FLAG_PS_USER | ENV_FLAG_FEN;
22
cpu_alpha_store_fpcr(env, (uint64_t)(FPCR_INVD | FPCR_DZED | FPCR_OVFD
23
--
24
2.34.1
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
Set the default NaN pattern explicitly for the arm target.
2
This includes setting it for the old linux-user nwfpe emulation.
3
For nwfpe, our default doesn't match the real kernel, but we
4
avoid making a behaviour change in this commit.
2
5
3
We were fudging TBI1 enabled to speed up the generated code.
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Now that we've improved the code generation, remove this.
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Also, tidy the comment to reflect the current code.
8
Message-id: 20241202131347.498124-41-peter.maydell@linaro.org
9
---
10
linux-user/arm/nwfpe/fpa11.c | 5 +++++
11
target/arm/cpu.c | 2 ++
12
2 files changed, 7 insertions(+)
6
13
7
The pauth test was testing a kernel address (-1) and making
14
diff --git a/linux-user/arm/nwfpe/fpa11.c b/linux-user/arm/nwfpe/fpa11.c
8
incorrect assumptions about TBI1; stick to userland addresses.
9
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
12
Message-id: 20210212184902.1251044-23-richard.henderson@linaro.org
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
---
15
target/arm/internals.h | 4 ++--
16
target/arm/cpu.c | 10 +++-------
17
tests/tcg/aarch64/pauth-2.c | 1 -
18
3 files changed, 5 insertions(+), 10 deletions(-)
19
20
diff --git a/target/arm/internals.h b/target/arm/internals.h
21
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
22
--- a/target/arm/internals.h
16
--- a/linux-user/arm/nwfpe/fpa11.c
23
+++ b/target/arm/internals.h
17
+++ b/linux-user/arm/nwfpe/fpa11.c
24
@@ -XXX,XX +XXX,XX @@ static inline bool tcma_check(uint32_t desc, int bit55, int ptr_tag)
18
@@ -XXX,XX +XXX,XX @@ void resetFPA11(void)
25
*/
19
* this late date.
26
static inline uint64_t useronly_clean_ptr(uint64_t ptr)
20
*/
27
{
21
set_float_2nan_prop_rule(float_2nan_prop_s_ab, &fpa11->fp_status);
28
- /* TBI is known to be enabled. */
22
+ /*
29
#ifdef CONFIG_USER_ONLY
23
+ * Use the same default NaN value as Arm VFP. This doesn't match
30
- ptr = sextract64(ptr, 0, 56);
24
+ * the Linux kernel's nwfpe emulation, which uses an all-1s value.
31
+ /* TBI0 is known to be enabled, while TBI1 is disabled. */
25
+ */
32
+ ptr &= sextract64(ptr, 0, 56);
26
+ set_float_default_nan_pattern(0b01000000, &fpa11->fp_status);
33
#endif
34
return ptr;
35
}
27
}
28
29
void SetRoundingMode(const unsigned int opcode)
36
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
30
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
37
index XXXXXXX..XXXXXXX 100644
31
index XXXXXXX..XXXXXXX 100644
38
--- a/target/arm/cpu.c
32
--- a/target/arm/cpu.c
39
+++ b/target/arm/cpu.c
33
+++ b/target/arm/cpu.c
40
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_reset(DeviceState *dev)
34
@@ -XXX,XX +XXX,XX @@ void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook,
41
env->vfp.zcr_el[1] = MIN(cpu->sve_max_vq - 1, 3);
35
* the pseudocode function the arguments are in the order c, a, b.
42
}
36
* * 0 * Inf + NaN returns the default NaN if the input NaN is quiet,
43
/*
37
* and the input NaN if it is signalling
44
- * Enable TBI0 and TBI1. While the real kernel only enables TBI0,
38
+ * * Default NaN has sign bit clear, msb frac bit set
45
- * turning on both here will produce smaller code and otherwise
39
*/
46
- * make no difference to the user-level emulation.
40
static void arm_set_default_fp_behaviours(float_status *s)
47
- *
48
- * In sve_probe_page, we assume that this is set.
49
- * Do not modify this without other changes.
50
+ * Enable TBI0 but not TBI1.
51
+ * Note that this must match useronly_clean_ptr.
52
*/
53
- env->cp15.tcr_el[1].raw_tcr = (3ULL << 37);
54
+ env->cp15.tcr_el[1].raw_tcr = (1ULL << 37);
55
#else
56
/* Reset into the highest available EL */
57
if (arm_feature(env, ARM_FEATURE_EL3)) {
58
diff --git a/tests/tcg/aarch64/pauth-2.c b/tests/tcg/aarch64/pauth-2.c
59
index XXXXXXX..XXXXXXX 100644
60
--- a/tests/tcg/aarch64/pauth-2.c
61
+++ b/tests/tcg/aarch64/pauth-2.c
62
@@ -XXX,XX +XXX,XX @@ void do_test(uint64_t value)
63
int main()
64
{
41
{
65
do_test(0);
42
@@ -XXX,XX +XXX,XX @@ static void arm_set_default_fp_behaviours(float_status *s)
66
- do_test(-1);
43
set_float_2nan_prop_rule(float_2nan_prop_s_ab, s);
67
do_test(0xda004acedeadbeefull);
44
set_float_3nan_prop_rule(float_3nan_prop_s_cab, s);
68
return 0;
45
set_float_infzeronan_rule(float_infzeronan_dnan_if_qnan, s);
46
+ set_float_default_nan_pattern(0b01000000, s);
69
}
47
}
48
49
static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque)
70
--
50
--
71
2.20.1
51
2.34.1
72
73
diff view generated by jsdifflib
1
From: Doug Evans <dje@google.com>
1
Set the default NaN pattern explicitly for loongarch.
2
2
3
This is a 10/100 ethernet device that has several features.
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Only the ones needed by the Linux driver have been implemented.
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
See npcm7xx_emc.c for a list of unimplemented features.
5
Message-id: 20241202131347.498124-42-peter.maydell@linaro.org
6
---
7
target/loongarch/tcg/fpu_helper.c | 2 ++
8
1 file changed, 2 insertions(+)
6
9
7
Reviewed-by: Hao Wu <wuhaotsh@google.com>
10
diff --git a/target/loongarch/tcg/fpu_helper.c b/target/loongarch/tcg/fpu_helper.c
8
Reviewed-by: Avi Fishman <avi.fishman@nuvoton.com>
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Doug Evans <dje@google.com>
11
Message-id: 20210213002520.1374134-3-dje@google.com
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
---
14
docs/system/arm/nuvoton.rst | 3 ++-
15
include/hw/arm/npcm7xx.h | 2 ++
16
hw/arm/npcm7xx.c | 50 +++++++++++++++++++++++++++++++++++--
17
3 files changed, 52 insertions(+), 3 deletions(-)
18
19
diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst
20
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
21
--- a/docs/system/arm/nuvoton.rst
12
--- a/target/loongarch/tcg/fpu_helper.c
22
+++ b/docs/system/arm/nuvoton.rst
13
+++ b/target/loongarch/tcg/fpu_helper.c
23
@@ -XXX,XX +XXX,XX @@ Supported devices
14
@@ -XXX,XX +XXX,XX @@ void restore_fp_status(CPULoongArchState *env)
24
* Analog to Digital Converter (ADC)
15
*/
25
* Pulse Width Modulation (PWM)
16
set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
26
* SMBus controller (SMBF)
17
set_float_3nan_prop_rule(float_3nan_prop_s_cab, &env->fp_status);
27
+ * Ethernet controller (EMC)
18
+ /* Default NaN: sign bit clear, msb frac bit set */
28
19
+ set_float_default_nan_pattern(0b01000000, &env->fp_status);
29
Missing devices
30
---------------
31
@@ -XXX,XX +XXX,XX @@ Missing devices
32
* Shared memory (SHM)
33
* eSPI slave interface
34
35
- * Ethernet controllers (GMAC and EMC)
36
+ * Ethernet controller (GMAC)
37
* USB device (USBD)
38
* Peripheral SPI controller (PSPI)
39
* SD/MMC host
40
diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
41
index XXXXXXX..XXXXXXX 100644
42
--- a/include/hw/arm/npcm7xx.h
43
+++ b/include/hw/arm/npcm7xx.h
44
@@ -XXX,XX +XXX,XX @@
45
#include "hw/misc/npcm7xx_gcr.h"
46
#include "hw/misc/npcm7xx_pwm.h"
47
#include "hw/misc/npcm7xx_rng.h"
48
+#include "hw/net/npcm7xx_emc.h"
49
#include "hw/nvram/npcm7xx_otp.h"
50
#include "hw/timer/npcm7xx_timer.h"
51
#include "hw/ssi/npcm7xx_fiu.h"
52
@@ -XXX,XX +XXX,XX @@ typedef struct NPCM7xxState {
53
EHCISysBusState ehci;
54
OHCISysBusState ohci;
55
NPCM7xxFIUState fiu[2];
56
+ NPCM7xxEMCState emc[2];
57
} NPCM7xxState;
58
59
#define TYPE_NPCM7XX "npcm7xx"
60
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
61
index XXXXXXX..XXXXXXX 100644
62
--- a/hw/arm/npcm7xx.c
63
+++ b/hw/arm/npcm7xx.c
64
@@ -XXX,XX +XXX,XX @@ enum NPCM7xxInterrupt {
65
NPCM7XX_UART1_IRQ,
66
NPCM7XX_UART2_IRQ,
67
NPCM7XX_UART3_IRQ,
68
+ NPCM7XX_EMC1RX_IRQ = 15,
69
+ NPCM7XX_EMC1TX_IRQ,
70
NPCM7XX_TIMER0_IRQ = 32, /* Timer Module 0 */
71
NPCM7XX_TIMER1_IRQ,
72
NPCM7XX_TIMER2_IRQ,
73
@@ -XXX,XX +XXX,XX @@ enum NPCM7xxInterrupt {
74
NPCM7XX_SMBUS15_IRQ,
75
NPCM7XX_PWM0_IRQ = 93, /* PWM module 0 */
76
NPCM7XX_PWM1_IRQ, /* PWM module 1 */
77
+ NPCM7XX_EMC2RX_IRQ = 114,
78
+ NPCM7XX_EMC2TX_IRQ,
79
NPCM7XX_GPIO0_IRQ = 116,
80
NPCM7XX_GPIO1_IRQ,
81
NPCM7XX_GPIO2_IRQ,
82
@@ -XXX,XX +XXX,XX @@ static const hwaddr npcm7xx_smbus_addr[] = {
83
0xf008f000,
84
};
85
86
+/* Register base address for each EMC Module */
87
+static const hwaddr npcm7xx_emc_addr[] = {
88
+ 0xf0825000,
89
+ 0xf0826000,
90
+};
91
+
92
static const struct {
93
hwaddr regs_addr;
94
uint32_t unconnected_pins;
95
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_init(Object *obj)
96
for (i = 0; i < ARRAY_SIZE(s->pwm); i++) {
97
object_initialize_child(obj, "pwm[*]", &s->pwm[i], TYPE_NPCM7XX_PWM);
98
}
99
+
100
+ for (i = 0; i < ARRAY_SIZE(s->emc); i++) {
101
+ object_initialize_child(obj, "emc[*]", &s->emc[i], TYPE_NPCM7XX_EMC);
102
+ }
103
}
20
}
104
21
105
static void npcm7xx_realize(DeviceState *dev, Error **errp)
22
int ieee_ex_to_loongarch(int xcpt)
106
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
107
sysbus_connect_irq(sbd, i, npcm7xx_irq(s, NPCM7XX_PWM0_IRQ + i));
108
}
109
110
+ /*
111
+ * EMC Modules. Cannot fail.
112
+ * The mapping of the device to its netdev backend works as follows:
113
+ * emc[i] = nd_table[i]
114
+ * This works around the inability to specify the netdev property for the
115
+ * emc device: it's not pluggable and thus the -device option can't be
116
+ * used.
117
+ */
118
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_emc_addr) != ARRAY_SIZE(s->emc));
119
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(s->emc) != 2);
120
+ for (i = 0; i < ARRAY_SIZE(s->emc); i++) {
121
+ s->emc[i].emc_num = i;
122
+ SysBusDevice *sbd = SYS_BUS_DEVICE(&s->emc[i]);
123
+ if (nd_table[i].used) {
124
+ qemu_check_nic_model(&nd_table[i], TYPE_NPCM7XX_EMC);
125
+ qdev_set_nic_properties(DEVICE(sbd), &nd_table[i]);
126
+ }
127
+ /*
128
+ * The device exists regardless of whether it's connected to a QEMU
129
+ * netdev backend. So always instantiate it even if there is no
130
+ * backend.
131
+ */
132
+ sysbus_realize(sbd, &error_abort);
133
+ sysbus_mmio_map(sbd, 0, npcm7xx_emc_addr[i]);
134
+ int tx_irq = i == 0 ? NPCM7XX_EMC1TX_IRQ : NPCM7XX_EMC2TX_IRQ;
135
+ int rx_irq = i == 0 ? NPCM7XX_EMC1RX_IRQ : NPCM7XX_EMC2RX_IRQ;
136
+ /*
137
+ * N.B. The values for the second argument sysbus_connect_irq are
138
+ * chosen to match the registration order in npcm7xx_emc_realize.
139
+ */
140
+ sysbus_connect_irq(sbd, 0, npcm7xx_irq(s, tx_irq));
141
+ sysbus_connect_irq(sbd, 1, npcm7xx_irq(s, rx_irq));
142
+ }
143
+
144
/*
145
* Flash Interface Unit (FIU). Can fail if incorrect number of chip selects
146
* specified, but this is a programming error.
147
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
148
create_unimplemented_device("npcm7xx.vcd", 0xf0810000, 64 * KiB);
149
create_unimplemented_device("npcm7xx.ece", 0xf0820000, 8 * KiB);
150
create_unimplemented_device("npcm7xx.vdma", 0xf0822000, 8 * KiB);
151
- create_unimplemented_device("npcm7xx.emc1", 0xf0825000, 4 * KiB);
152
- create_unimplemented_device("npcm7xx.emc2", 0xf0826000, 4 * KiB);
153
create_unimplemented_device("npcm7xx.usbd[0]", 0xf0830000, 4 * KiB);
154
create_unimplemented_device("npcm7xx.usbd[1]", 0xf0831000, 4 * KiB);
155
create_unimplemented_device("npcm7xx.usbd[2]", 0xf0832000, 4 * KiB);
156
--
23
--
157
2.20.1
24
2.34.1
158
159
diff view generated by jsdifflib
New patch
1
Set the default NaN pattern explicitly for m68k.
1
2
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Message-id: 20241202131347.498124-43-peter.maydell@linaro.org
6
---
7
target/m68k/cpu.c | 2 ++
8
fpu/softfloat-specialize.c.inc | 2 +-
9
2 files changed, 3 insertions(+), 1 deletion(-)
10
11
diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/target/m68k/cpu.c
14
+++ b/target/m68k/cpu.c
15
@@ -XXX,XX +XXX,XX @@ static void m68k_cpu_reset_hold(Object *obj, ResetType type)
16
* preceding paragraph for nonsignaling NaNs.
17
*/
18
set_float_2nan_prop_rule(float_2nan_prop_ab, &env->fp_status);
19
+ /* Default NaN: sign bit clear, all frac bits set */
20
+ set_float_default_nan_pattern(0b01111111, &env->fp_status);
21
22
nan = floatx80_default_nan(&env->fp_status);
23
for (i = 0; i < 8; i++) {
24
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
25
index XXXXXXX..XXXXXXX 100644
26
--- a/fpu/softfloat-specialize.c.inc
27
+++ b/fpu/softfloat-specialize.c.inc
28
@@ -XXX,XX +XXX,XX @@ static void parts64_default_nan(FloatParts64 *p, float_status *status)
29
uint8_t dnan_pattern = status->default_nan_pattern;
30
31
if (dnan_pattern == 0) {
32
-#if defined(TARGET_SPARC) || defined(TARGET_M68K)
33
+#if defined(TARGET_SPARC)
34
/* Sign bit clear, all frac bits set */
35
dnan_pattern = 0b01111111;
36
#elif defined(TARGET_HEXAGON)
37
--
38
2.34.1
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
Set the default NaN pattern explicitly for MIPS. Note that this
2
is our only target which currently changes the default NaN
3
at runtime (which it was previously doing indirectly when it
4
changed the snan_bit_is_one setting).
2
5
3
Resolve the untagged address once, using thread_cpu.
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Tidy the DEBUG_REMAP code using glib routines.
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20241202131347.498124-44-peter.maydell@linaro.org
9
---
10
target/mips/fpu_helper.h | 7 +++++++
11
target/mips/msa.c | 3 +++
12
2 files changed, 10 insertions(+)
5
13
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
14
diff --git a/target/mips/fpu_helper.h b/target/mips/fpu_helper.h
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20210212184902.1251044-20-richard.henderson@linaro.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
11
linux-user/uaccess.c | 27 ++++++++++++++-------------
12
1 file changed, 14 insertions(+), 13 deletions(-)
13
14
diff --git a/linux-user/uaccess.c b/linux-user/uaccess.c
15
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
16
--- a/linux-user/uaccess.c
16
--- a/target/mips/fpu_helper.h
17
+++ b/linux-user/uaccess.c
17
+++ b/target/mips/fpu_helper.h
18
@@ -XXX,XX +XXX,XX @@
18
@@ -XXX,XX +XXX,XX @@ static inline void restore_snan_bit_mode(CPUMIPSState *env)
19
19
set_float_infzeronan_rule(izn_rule, &env->active_fpu.fp_status);
20
void *lock_user(int type, abi_ulong guest_addr, size_t len, bool copy)
20
nan3_rule = nan2008 ? float_3nan_prop_s_cab : float_3nan_prop_s_abc;
21
{
21
set_float_3nan_prop_rule(nan3_rule, &env->active_fpu.fp_status);
22
+ void *host_addr;
22
+ /*
23
+
23
+ * With nan2008, the default NaN value has the sign bit clear and the
24
+ guest_addr = cpu_untagged_addr(thread_cpu, guest_addr);
24
+ * frac msb set; with the older mode, the sign bit is clear, and all
25
if (!access_ok_untagged(type, guest_addr, len)) {
25
+ * frac bits except the msb are set.
26
return NULL;
26
+ */
27
}
27
+ set_float_default_nan_pattern(nan2008 ? 0b01000000 : 0b00111111,
28
+ host_addr = g2h_untagged(guest_addr);
28
+ &env->active_fpu.fp_status);
29
#ifdef DEBUG_REMAP
29
30
- {
31
- void *addr;
32
- addr = g_malloc(len);
33
- if (copy) {
34
- memcpy(addr, g2h(guest_addr), len);
35
- } else {
36
- memset(addr, 0, len);
37
- }
38
- return addr;
39
+ if (copy) {
40
+ host_addr = g_memdup(host_addr, len);
41
+ } else {
42
+ host_addr = g_malloc0(len);
43
}
44
-#else
45
- return g2h_untagged(guest_addr);
46
#endif
47
+ return host_addr;
48
}
30
}
49
31
50
#ifdef DEBUG_REMAP
32
diff --git a/target/mips/msa.c b/target/mips/msa.c
51
void unlock_user(void *host_ptr, abi_ulong guest_addr, size_t len);
33
index XXXXXXX..XXXXXXX 100644
52
{
34
--- a/target/mips/msa.c
53
+ void *host_ptr_conv;
35
+++ b/target/mips/msa.c
54
+
36
@@ -XXX,XX +XXX,XX @@ void msa_reset(CPUMIPSState *env)
55
if (!host_ptr) {
37
/* Inf * 0 + NaN returns the input NaN */
56
return;
38
set_float_infzeronan_rule(float_infzeronan_dnan_never,
57
}
39
&env->active_tc.msa_fp_status);
58
- if (host_ptr == g2h_untagged(guest_addr)) {
40
+ /* Default NaN: sign bit clear, frac msb set */
59
+ host_ptr_conv = g2h(thread_cpu, guest_addr);
41
+ set_float_default_nan_pattern(0b01000000,
60
+ if (host_ptr == host_ptr_conv) {
42
+ &env->active_tc.msa_fp_status);
61
return;
62
}
63
if (len != 0) {
64
- memcpy(g2h_untagged(guest_addr), host_ptr, len);
65
+ memcpy(host_ptr_conv, host_ptr, len);
66
}
67
g_free(host_ptr);
68
}
43
}
69
--
44
--
70
2.20.1
45
2.34.1
71
72
diff view generated by jsdifflib
New patch
1
Set the default NaN pattern explicitly for openrisc.
1
2
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Message-id: 20241202131347.498124-45-peter.maydell@linaro.org
6
---
7
target/openrisc/cpu.c | 2 ++
8
1 file changed, 2 insertions(+)
9
10
diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/target/openrisc/cpu.c
13
+++ b/target/openrisc/cpu.c
14
@@ -XXX,XX +XXX,XX @@ static void openrisc_cpu_reset_hold(Object *obj, ResetType type)
15
*/
16
set_float_2nan_prop_rule(float_2nan_prop_x87, &cpu->env.fp_status);
17
18
+ /* Default NaN: sign bit clear, frac msb set */
19
+ set_float_default_nan_pattern(0b01000000, &cpu->env.fp_status);
20
21
#ifndef CONFIG_USER_ONLY
22
cpu->env.picmr = 0x00000000;
23
--
24
2.34.1
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
Set the default NaN pattern explicitly for ppc.
2
2
3
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
4
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
5
Message-id: 20210212184902.1251044-32-richard.henderson@linaro.org
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Message-id: 20241202131347.498124-46-peter.maydell@linaro.org
7
---
6
---
8
tests/tcg/aarch64/mte.h | 60 +++++++++++++++++++++++++++++++
7
target/ppc/cpu_init.c | 4 ++++
9
tests/tcg/aarch64/mte-1.c | 28 +++++++++++++++
8
1 file changed, 4 insertions(+)
10
tests/tcg/aarch64/mte-2.c | 45 +++++++++++++++++++++++
11
tests/tcg/aarch64/mte-3.c | 51 ++++++++++++++++++++++++++
12
tests/tcg/aarch64/mte-4.c | 45 +++++++++++++++++++++++
13
tests/tcg/aarch64/Makefile.target | 6 ++++
14
tests/tcg/configure.sh | 4 +++
15
7 files changed, 239 insertions(+)
16
create mode 100644 tests/tcg/aarch64/mte.h
17
create mode 100644 tests/tcg/aarch64/mte-1.c
18
create mode 100644 tests/tcg/aarch64/mte-2.c
19
create mode 100644 tests/tcg/aarch64/mte-3.c
20
create mode 100644 tests/tcg/aarch64/mte-4.c
21
9
22
diff --git a/tests/tcg/aarch64/mte.h b/tests/tcg/aarch64/mte.h
10
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
23
new file mode 100644
11
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX
12
--- a/target/ppc/cpu_init.c
25
--- /dev/null
13
+++ b/target/ppc/cpu_init.c
26
+++ b/tests/tcg/aarch64/mte.h
14
@@ -XXX,XX +XXX,XX @@ static void ppc_cpu_reset_hold(Object *obj, ResetType type)
27
@@ -XXX,XX +XXX,XX @@
15
set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
28
+/*
16
set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->vec_status);
29
+ * Linux kernel fallback API definitions for MTE and test helpers.
17
30
+ *
18
+ /* Default NaN: sign bit clear, set frac msb */
31
+ * Copyright (c) 2021 Linaro Ltd
19
+ set_float_default_nan_pattern(0b01000000, &env->fp_status);
32
+ * SPDX-License-Identifier: GPL-2.0-or-later
20
+ set_float_default_nan_pattern(0b01000000, &env->vec_status);
33
+ */
34
+
21
+
35
+#include <assert.h>
22
for (i = 0; i < ARRAY_SIZE(env->spr_cb); i++) {
36
+#include <string.h>
23
ppc_spr_t *spr = &env->spr_cb[i];
37
+#include <stdlib.h>
38
+#include <stdio.h>
39
+#include <unistd.h>
40
+#include <signal.h>
41
+#include <sys/mman.h>
42
+#include <sys/prctl.h>
43
+
44
+#ifndef PR_SET_TAGGED_ADDR_CTRL
45
+# define PR_SET_TAGGED_ADDR_CTRL 55
46
+#endif
47
+#ifndef PR_TAGGED_ADDR_ENABLE
48
+# define PR_TAGGED_ADDR_ENABLE (1UL << 0)
49
+#endif
50
+#ifndef PR_MTE_TCF_SHIFT
51
+# define PR_MTE_TCF_SHIFT 1
52
+# define PR_MTE_TCF_NONE (0UL << PR_MTE_TCF_SHIFT)
53
+# define PR_MTE_TCF_SYNC (1UL << PR_MTE_TCF_SHIFT)
54
+# define PR_MTE_TCF_ASYNC (2UL << PR_MTE_TCF_SHIFT)
55
+# define PR_MTE_TAG_SHIFT 3
56
+#endif
57
+
58
+#ifndef PROT_MTE
59
+# define PROT_MTE 0x20
60
+#endif
61
+
62
+#ifndef SEGV_MTEAERR
63
+# define SEGV_MTEAERR 8
64
+# define SEGV_MTESERR 9
65
+#endif
66
+
67
+static void enable_mte(int tcf)
68
+{
69
+ int r = prctl(PR_SET_TAGGED_ADDR_CTRL,
70
+ PR_TAGGED_ADDR_ENABLE | tcf | (0xfffe << PR_MTE_TAG_SHIFT),
71
+ 0, 0, 0);
72
+ if (r < 0) {
73
+ perror("PR_SET_TAGGED_ADDR_CTRL");
74
+ exit(2);
75
+ }
76
+}
77
+
78
+static void *alloc_mte_mem(size_t size)
79
+{
80
+ void *p = mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_MTE,
81
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
82
+ if (p == MAP_FAILED) {
83
+ perror("mmap PROT_MTE");
84
+ exit(2);
85
+ }
86
+ return p;
87
+}
88
diff --git a/tests/tcg/aarch64/mte-1.c b/tests/tcg/aarch64/mte-1.c
89
new file mode 100644
90
index XXXXXXX..XXXXXXX
91
--- /dev/null
92
+++ b/tests/tcg/aarch64/mte-1.c
93
@@ -XXX,XX +XXX,XX @@
94
+/*
95
+ * Memory tagging, basic pass cases.
96
+ *
97
+ * Copyright (c) 2021 Linaro Ltd
98
+ * SPDX-License-Identifier: GPL-2.0-or-later
99
+ */
100
+
101
+#include "mte.h"
102
+
103
+int main(int ac, char **av)
104
+{
105
+ int *p0, *p1, *p2;
106
+ long c;
107
+
108
+ enable_mte(PR_MTE_TCF_NONE);
109
+ p0 = alloc_mte_mem(sizeof(*p0));
110
+
111
+ asm("irg %0,%1,%2" : "=r"(p1) : "r"(p0), "r"(1));
112
+ assert(p1 != p0);
113
+ asm("subp %0,%1,%2" : "=r"(c) : "r"(p0), "r"(p1));
114
+ assert(c == 0);
115
+
116
+ asm("stg %0, [%0]" : : "r"(p1));
117
+ asm("ldg %0, [%1]" : "=r"(p2) : "r"(p0), "0"(p0));
118
+ assert(p1 == p2);
119
+
120
+ return 0;
121
+}
122
diff --git a/tests/tcg/aarch64/mte-2.c b/tests/tcg/aarch64/mte-2.c
123
new file mode 100644
124
index XXXXXXX..XXXXXXX
125
--- /dev/null
126
+++ b/tests/tcg/aarch64/mte-2.c
127
@@ -XXX,XX +XXX,XX @@
128
+/*
129
+ * Memory tagging, basic fail cases, synchronous signals.
130
+ *
131
+ * Copyright (c) 2021 Linaro Ltd
132
+ * SPDX-License-Identifier: GPL-2.0-or-later
133
+ */
134
+
135
+#include "mte.h"
136
+
137
+void pass(int sig, siginfo_t *info, void *uc)
138
+{
139
+ assert(info->si_code == SEGV_MTESERR);
140
+ exit(0);
141
+}
142
+
143
+int main(int ac, char **av)
144
+{
145
+ struct sigaction sa;
146
+ int *p0, *p1, *p2;
147
+ long excl = 1;
148
+
149
+ enable_mte(PR_MTE_TCF_SYNC);
150
+ p0 = alloc_mte_mem(sizeof(*p0));
151
+
152
+ /* Create two differently tagged pointers. */
153
+ asm("irg %0,%1,%2" : "=r"(p1) : "r"(p0), "r"(excl));
154
+ asm("gmi %0,%1,%0" : "+r"(excl) : "r" (p1));
155
+ assert(excl != 1);
156
+ asm("irg %0,%1,%2" : "=r"(p2) : "r"(p0), "r"(excl));
157
+ assert(p1 != p2);
158
+
159
+ /* Store the tag from the first pointer. */
160
+ asm("stg %0, [%0]" : : "r"(p1));
161
+
162
+ *p1 = 0;
163
+
164
+ memset(&sa, 0, sizeof(sa));
165
+ sa.sa_sigaction = pass;
166
+ sa.sa_flags = SA_SIGINFO;
167
+ sigaction(SIGSEGV, &sa, NULL);
168
+
169
+ *p2 = 0;
170
+
171
+ abort();
172
+}
173
diff --git a/tests/tcg/aarch64/mte-3.c b/tests/tcg/aarch64/mte-3.c
174
new file mode 100644
175
index XXXXXXX..XXXXXXX
176
--- /dev/null
177
+++ b/tests/tcg/aarch64/mte-3.c
178
@@ -XXX,XX +XXX,XX @@
179
+/*
180
+ * Memory tagging, basic fail cases, asynchronous signals.
181
+ *
182
+ * Copyright (c) 2021 Linaro Ltd
183
+ * SPDX-License-Identifier: GPL-2.0-or-later
184
+ */
185
+
186
+#include "mte.h"
187
+
188
+void pass(int sig, siginfo_t *info, void *uc)
189
+{
190
+ assert(info->si_code == SEGV_MTEAERR);
191
+ exit(0);
192
+}
193
+
194
+int main(int ac, char **av)
195
+{
196
+ struct sigaction sa;
197
+ long *p0, *p1, *p2;
198
+ long excl = 1;
199
+
200
+ enable_mte(PR_MTE_TCF_ASYNC);
201
+ p0 = alloc_mte_mem(sizeof(*p0));
202
+
203
+ /* Create two differently tagged pointers. */
204
+ asm("irg %0,%1,%2" : "=r"(p1) : "r"(p0), "r"(excl));
205
+ asm("gmi %0,%1,%0" : "+r"(excl) : "r" (p1));
206
+ assert(excl != 1);
207
+ asm("irg %0,%1,%2" : "=r"(p2) : "r"(p0), "r"(excl));
208
+ assert(p1 != p2);
209
+
210
+ /* Store the tag from the first pointer. */
211
+ asm("stg %0, [%0]" : : "r"(p1));
212
+
213
+ *p1 = 0;
214
+
215
+ memset(&sa, 0, sizeof(sa));
216
+ sa.sa_sigaction = pass;
217
+ sa.sa_flags = SA_SIGINFO;
218
+ sigaction(SIGSEGV, &sa, NULL);
219
+
220
+ /*
221
+ * Signal for async error will happen eventually.
222
+ * For a real kernel this should be after the next IRQ (e.g. timer).
223
+ * For qemu linux-user, we kick the cpu and exit at the next TB.
224
+ * In either case, loop until this happens (or killed by timeout).
225
+ * For extra sauce, yield, producing EXCP_YIELD to cpu_loop().
226
+ */
227
+ asm("str %0, [%0]; yield" : : "r"(p2));
228
+ while (1);
229
+}
230
diff --git a/tests/tcg/aarch64/mte-4.c b/tests/tcg/aarch64/mte-4.c
231
new file mode 100644
232
index XXXXXXX..XXXXXXX
233
--- /dev/null
234
+++ b/tests/tcg/aarch64/mte-4.c
235
@@ -XXX,XX +XXX,XX @@
236
+/*
237
+ * Memory tagging, re-reading tag checks.
238
+ *
239
+ * Copyright (c) 2021 Linaro Ltd
240
+ * SPDX-License-Identifier: GPL-2.0-or-later
241
+ */
242
+
243
+#include "mte.h"
244
+
245
+void __attribute__((noinline)) tagset(void *p, size_t size)
246
+{
247
+ size_t i;
248
+ for (i = 0; i < size; i += 16) {
249
+ asm("stg %0, [%0]" : : "r"(p + i));
250
+ }
251
+}
252
+
253
+void __attribute__((noinline)) tagcheck(void *p, size_t size)
254
+{
255
+ size_t i;
256
+ void *c;
257
+
258
+ for (i = 0; i < size; i += 16) {
259
+ asm("ldg %0, [%1]" : "=r"(c) : "r"(p + i), "0"(p));
260
+ assert(c == p);
261
+ }
262
+}
263
+
264
+int main(int ac, char **av)
265
+{
266
+ size_t size = getpagesize() * 4;
267
+ long excl = 1;
268
+ int *p0, *p1;
269
+
270
+ enable_mte(PR_MTE_TCF_ASYNC);
271
+ p0 = alloc_mte_mem(size);
272
+
273
+ /* Tag the pointer. */
274
+ asm("irg %0,%1,%2" : "=r"(p1) : "r"(p0), "r"(excl));
275
+
276
+ tagset(p1, size);
277
+ tagcheck(p1, size);
278
+
279
+ return 0;
280
+}
281
diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target
282
index XXXXXXX..XXXXXXX 100644
283
--- a/tests/tcg/aarch64/Makefile.target
284
+++ b/tests/tcg/aarch64/Makefile.target
285
@@ -XXX,XX +XXX,XX @@ endif
286
# bti-2 tests PROT_BTI, so no special compiler support required.
287
AARCH64_TESTS += bti-2
288
289
+# MTE Tests
290
+ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_ARMV8_MTE),)
291
+AARCH64_TESTS += mte-1 mte-2 mte-3 mte-4
292
+mte-%: CFLAGS += -march=armv8.5-a+memtag
293
+endif
294
+
295
# Semihosting smoke test for linux-user
296
AARCH64_TESTS += semihosting
297
run-semihosting: semihosting
298
diff --git a/tests/tcg/configure.sh b/tests/tcg/configure.sh
299
index XXXXXXX..XXXXXXX 100755
300
--- a/tests/tcg/configure.sh
301
+++ b/tests/tcg/configure.sh
302
@@ -XXX,XX +XXX,XX @@ for target in $target_list; do
303
-mbranch-protection=standard -o $TMPE $TMPC; then
304
echo "CROSS_CC_HAS_ARMV8_BTI=y" >> $config_target_mak
305
fi
306
+ if do_compiler "$target_compiler" $target_compiler_cflags \
307
+ -march=armv8.5-a+memtag -o $TMPE $TMPC; then
308
+ echo "CROSS_CC_HAS_ARMV8_MTE=y" >> $config_target_mak
309
+ fi
310
;;
311
esac
312
24
313
--
25
--
314
2.20.1
26
2.34.1
315
316
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
Set the default NaN pattern explicitly for sh4. Note that sh4
2
is one of the only three targets (the others being HPPA and
3
sometimes MIPS) that has snan_bit_is_one set.
2
4
3
For copy_*_user, only 0 and -TARGET_EFAULT are returned; no need
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
to involve abi_long. Use size_t for lengths. Use bool for the
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
lock_user copy argument. Use ssize_t for target_strlen, because
7
Message-id: 20241202131347.498124-47-peter.maydell@linaro.org
6
we can't overflow the host memory space.
8
---
9
target/sh4/cpu.c | 2 ++
10
1 file changed, 2 insertions(+)
7
11
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
12
diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c
9
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
10
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
11
Message-id: 20210212184902.1251044-19-richard.henderson@linaro.org
12
[PMM: moved fix for ifdef error to previous commit]
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
---
15
linux-user/qemu.h | 12 +++++-------
16
linux-user/uaccess.c | 45 ++++++++++++++++++++++----------------------
17
2 files changed, 28 insertions(+), 29 deletions(-)
18
19
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
20
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
21
--- a/linux-user/qemu.h
14
--- a/target/sh4/cpu.c
22
+++ b/linux-user/qemu.h
15
+++ b/target/sh4/cpu.c
23
@@ -XXX,XX +XXX,XX @@
16
@@ -XXX,XX +XXX,XX @@ static void superh_cpu_reset_hold(Object *obj, ResetType type)
24
#include "exec/cpu_ldst.h"
17
set_flush_to_zero(1, &env->fp_status);
25
18
#endif
26
#undef DEBUG_REMAP
19
set_default_nan_mode(1, &env->fp_status);
27
-#ifdef DEBUG_REMAP
20
+ /* sign bit clear, set all frac bits other than msb */
28
-#endif /* DEBUG_REMAP */
21
+ set_float_default_nan_pattern(0b00111111, &env->fp_status);
29
30
#include "exec/user/abitypes.h"
31
32
@@ -XXX,XX +XXX,XX @@ static inline bool access_ok(CPUState *cpu, int type,
33
* buffers between the target and host. These internally perform
34
* locking/unlocking of the memory.
35
*/
36
-abi_long copy_from_user(void *hptr, abi_ulong gaddr, size_t len);
37
-abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len);
38
+int copy_from_user(void *hptr, abi_ulong gaddr, size_t len);
39
+int copy_to_user(abi_ulong gaddr, void *hptr, size_t len);
40
41
/* Functions for accessing guest memory. The tget and tput functions
42
read/write single values, byteswapping as necessary. The lock_user function
43
@@ -XXX,XX +XXX,XX @@ abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len);
44
45
/* Lock an area of guest memory into the host. If copy is true then the
46
host area will have the same contents as the guest. */
47
-void *lock_user(int type, abi_ulong guest_addr, long len, int copy);
48
+void *lock_user(int type, abi_ulong guest_addr, size_t len, bool copy);
49
50
/* Unlock an area of guest memory. The first LEN bytes must be
51
flushed back to guest memory. host_ptr = NULL is explicitly
52
allowed and does nothing. */
53
#ifndef DEBUG_REMAP
54
-static inline void unlock_user(void *host_ptr, abi_ulong guest_addr, long len)
55
+static inline void unlock_user(void *host_ptr, abi_ulong guest_addr, size_t len)
56
{ }
57
#else
58
void unlock_user(void *host_ptr, abi_ulong guest_addr, long len);
59
@@ -XXX,XX +XXX,XX @@ void unlock_user(void *host_ptr, abi_ulong guest_addr, long len);
60
61
/* Return the length of a string in target memory or -TARGET_EFAULT if
62
access error. */
63
-abi_long target_strlen(abi_ulong gaddr);
64
+ssize_t target_strlen(abi_ulong gaddr);
65
66
/* Like lock_user but for null terminated strings. */
67
void *lock_user_string(abi_ulong guest_addr);
68
diff --git a/linux-user/uaccess.c b/linux-user/uaccess.c
69
index XXXXXXX..XXXXXXX 100644
70
--- a/linux-user/uaccess.c
71
+++ b/linux-user/uaccess.c
72
@@ -XXX,XX +XXX,XX @@
73
74
#include "qemu.h"
75
76
-void *lock_user(int type, abi_ulong guest_addr, long len, int copy)
77
+void *lock_user(int type, abi_ulong guest_addr, size_t len, bool copy)
78
{
79
if (!access_ok_untagged(type, guest_addr, len)) {
80
return NULL;
81
@@ -XXX,XX +XXX,XX @@ void *lock_user(int type, abi_ulong guest_addr, long len, int copy)
82
}
22
}
83
23
84
#ifdef DEBUG_REMAP
24
static void superh_cpu_disas_set_info(CPUState *cpu, disassemble_info *info)
85
-void unlock_user(void *host_ptr, abi_ulong guest_addr, long len);
86
+void unlock_user(void *host_ptr, abi_ulong guest_addr, size_t len);
87
{
88
if (!host_ptr) {
89
return;
90
@@ -XXX,XX +XXX,XX @@ void unlock_user(void *host_ptr, abi_ulong guest_addr, long len);
91
if (host_ptr == g2h_untagged(guest_addr)) {
92
return;
93
}
94
- if (len > 0) {
95
+ if (len != 0) {
96
memcpy(g2h_untagged(guest_addr), host_ptr, len);
97
}
98
g_free(host_ptr);
99
@@ -XXX,XX +XXX,XX @@ void unlock_user(void *host_ptr, abi_ulong guest_addr, long len);
100
101
void *lock_user_string(abi_ulong guest_addr)
102
{
103
- abi_long len = target_strlen(guest_addr);
104
+ ssize_t len = target_strlen(guest_addr);
105
if (len < 0) {
106
return NULL;
107
}
108
- return lock_user(VERIFY_READ, guest_addr, (long)(len + 1), 1);
109
+ return lock_user(VERIFY_READ, guest_addr, (size_t)len + 1, 1);
110
}
111
112
/* copy_from_user() and copy_to_user() are usually used to copy data
113
* buffers between the target and host. These internally perform
114
* locking/unlocking of the memory.
115
*/
116
-abi_long copy_from_user(void *hptr, abi_ulong gaddr, size_t len)
117
+int copy_from_user(void *hptr, abi_ulong gaddr, size_t len)
118
{
119
- abi_long ret = 0;
120
- void *ghptr;
121
+ int ret = 0;
122
+ void *ghptr = lock_user(VERIFY_READ, gaddr, len, 1);
123
124
- if ((ghptr = lock_user(VERIFY_READ, gaddr, len, 1))) {
125
+ if (ghptr) {
126
memcpy(hptr, ghptr, len);
127
unlock_user(ghptr, gaddr, 0);
128
- } else
129
+ } else {
130
ret = -TARGET_EFAULT;
131
-
132
+ }
133
return ret;
134
}
135
136
-
137
-abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len)
138
+int copy_to_user(abi_ulong gaddr, void *hptr, size_t len)
139
{
140
- abi_long ret = 0;
141
- void *ghptr;
142
+ int ret = 0;
143
+ void *ghptr = lock_user(VERIFY_WRITE, gaddr, len, 0);
144
145
- if ((ghptr = lock_user(VERIFY_WRITE, gaddr, len, 0))) {
146
+ if (ghptr) {
147
memcpy(ghptr, hptr, len);
148
unlock_user(ghptr, gaddr, len);
149
- } else
150
+ } else {
151
ret = -TARGET_EFAULT;
152
+ }
153
154
return ret;
155
}
156
157
/* Return the length of a string in target memory or -TARGET_EFAULT if
158
access error */
159
-abi_long target_strlen(abi_ulong guest_addr1)
160
+ssize_t target_strlen(abi_ulong guest_addr1)
161
{
162
uint8_t *ptr;
163
abi_ulong guest_addr;
164
- int max_len, len;
165
+ size_t max_len, len;
166
167
guest_addr = guest_addr1;
168
for(;;) {
169
@@ -XXX,XX +XXX,XX @@ abi_long target_strlen(abi_ulong guest_addr1)
170
unlock_user(ptr, guest_addr, 0);
171
guest_addr += len;
172
/* we don't allow wrapping or integer overflow */
173
- if (guest_addr == 0 ||
174
- (guest_addr - guest_addr1) > 0x7fffffff)
175
+ if (guest_addr == 0 || (guest_addr - guest_addr1) > 0x7fffffff) {
176
return -TARGET_EFAULT;
177
- if (len != max_len)
178
+ }
179
+ if (len != max_len) {
180
break;
181
+ }
182
}
183
return guest_addr - guest_addr1;
184
}
185
--
25
--
186
2.20.1
26
2.34.1
187
188
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
Set the default NaN pattern explicitly for rx.
2
2
3
These constants are only ever used with access_ok, and friends.
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Rather than translating them to PAGE_* bits, let them equal
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
the PAGE_* bits to begin.
5
Message-id: 20241202131347.498124-48-peter.maydell@linaro.org
6
---
7
target/rx/cpu.c | 2 ++
8
1 file changed, 2 insertions(+)
6
9
7
Reviewed-by: Warner Losh <imp@bsdimp.com>
10
diff --git a/target/rx/cpu.c b/target/rx/cpu.c
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
10
Message-id: 20210212184902.1251044-9-richard.henderson@linaro.org
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
---
13
bsd-user/qemu.h | 9 ++++-----
14
1 file changed, 4 insertions(+), 5 deletions(-)
15
16
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
17
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
18
--- a/bsd-user/qemu.h
12
--- a/target/rx/cpu.c
19
+++ b/bsd-user/qemu.h
13
+++ b/target/rx/cpu.c
20
@@ -XXX,XX +XXX,XX @@ extern unsigned long x86_stack_size;
14
@@ -XXX,XX +XXX,XX @@ static void rx_cpu_reset_hold(Object *obj, ResetType type)
21
15
* then prefer dest over source", which is float_2nan_prop_s_ab.
22
/* user access */
16
*/
23
17
set_float_2nan_prop_rule(float_2nan_prop_x87, &env->fp_status);
24
-#define VERIFY_READ 0
18
+ /* Default NaN value: sign bit clear, set frac msb */
25
-#define VERIFY_WRITE 1 /* implies read access */
19
+ set_float_default_nan_pattern(0b01000000, &env->fp_status);
26
+#define VERIFY_READ PAGE_READ
27
+#define VERIFY_WRITE (PAGE_READ | PAGE_WRITE)
28
29
-static inline int access_ok(int type, abi_ulong addr, abi_ulong size)
30
+static inline bool access_ok(int type, abi_ulong addr, abi_ulong size)
31
{
32
- return page_check_range((target_ulong)addr, size,
33
- (type == VERIFY_READ) ? PAGE_READ : (PAGE_READ | PAGE_WRITE)) == 0;
34
+ return page_check_range((target_ulong)addr, size, type) == 0;
35
}
20
}
36
21
37
/* NOTE __get_user and __put_user use host pointers and don't check access. */
22
static ObjectClass *rx_cpu_class_by_name(const char *cpu_model)
38
--
23
--
39
2.20.1
24
2.34.1
40
41
diff view generated by jsdifflib
New patch
1
Set the default NaN pattern explicitly for s390x.
1
2
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Message-id: 20241202131347.498124-49-peter.maydell@linaro.org
6
---
7
target/s390x/cpu.c | 2 ++
8
1 file changed, 2 insertions(+)
9
10
diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/target/s390x/cpu.c
13
+++ b/target/s390x/cpu.c
14
@@ -XXX,XX +XXX,XX @@ static void s390_cpu_reset_hold(Object *obj, ResetType type)
15
set_float_3nan_prop_rule(float_3nan_prop_s_abc, &env->fpu_status);
16
set_float_infzeronan_rule(float_infzeronan_dnan_always,
17
&env->fpu_status);
18
+ /* Default NaN value: sign bit clear, frac msb set */
19
+ set_float_default_nan_pattern(0b01000000, &env->fpu_status);
20
/* fall through */
21
case RESET_TYPE_S390_CPU_NORMAL:
22
env->psw.mask &= ~PSW_MASK_RI;
23
--
24
2.34.1
diff view generated by jsdifflib
New patch
1
Set the default NaN pattern explicitly for SPARC, and remove
2
the ifdef from parts64_default_nan.
1
3
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20241202131347.498124-50-peter.maydell@linaro.org
7
---
8
target/sparc/cpu.c | 2 ++
9
fpu/softfloat-specialize.c.inc | 5 +----
10
2 files changed, 3 insertions(+), 4 deletions(-)
11
12
diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/target/sparc/cpu.c
15
+++ b/target/sparc/cpu.c
16
@@ -XXX,XX +XXX,XX @@ static void sparc_cpu_realizefn(DeviceState *dev, Error **errp)
17
set_float_3nan_prop_rule(float_3nan_prop_s_cba, &env->fp_status);
18
/* For inf * 0 + NaN, return the input NaN */
19
set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
20
+ /* Default NaN value: sign bit clear, all frac bits set */
21
+ set_float_default_nan_pattern(0b01111111, &env->fp_status);
22
23
cpu_exec_realizefn(cs, &local_err);
24
if (local_err != NULL) {
25
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
26
index XXXXXXX..XXXXXXX 100644
27
--- a/fpu/softfloat-specialize.c.inc
28
+++ b/fpu/softfloat-specialize.c.inc
29
@@ -XXX,XX +XXX,XX @@ static void parts64_default_nan(FloatParts64 *p, float_status *status)
30
uint8_t dnan_pattern = status->default_nan_pattern;
31
32
if (dnan_pattern == 0) {
33
-#if defined(TARGET_SPARC)
34
- /* Sign bit clear, all frac bits set */
35
- dnan_pattern = 0b01111111;
36
-#elif defined(TARGET_HEXAGON)
37
+#if defined(TARGET_HEXAGON)
38
/* Sign bit set, all frac bits set. */
39
dnan_pattern = 0b11111111;
40
#else
41
--
42
2.34.1
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
Set the default NaN pattern explicitly for xtensa.
2
2
3
Provide an identity fallback for target that do not
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
use tagged addresses.
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Message-id: 20241202131347.498124-51-peter.maydell@linaro.org
6
---
7
target/xtensa/cpu.c | 2 ++
8
1 file changed, 2 insertions(+)
5
9
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20210212184902.1251044-12-richard.henderson@linaro.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
11
include/exec/cpu_ldst.h | 7 +++++++
12
1 file changed, 7 insertions(+)
13
14
diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h
15
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
16
--- a/include/exec/cpu_ldst.h
12
--- a/target/xtensa/cpu.c
17
+++ b/include/exec/cpu_ldst.h
13
+++ b/target/xtensa/cpu.c
18
@@ -XXX,XX +XXX,XX @@ typedef uint64_t abi_ptr;
14
@@ -XXX,XX +XXX,XX @@ static void xtensa_cpu_reset_hold(Object *obj, ResetType type)
19
#define TARGET_ABI_FMT_ptr "%"PRIx64
15
/* For inf * 0 + NaN, return the input NaN */
20
#endif
16
set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
21
17
set_no_signaling_nans(!dfpu, &env->fp_status);
22
+#ifndef TARGET_TAGGED_ADDRESSES
18
+ /* Default NaN value: sign bit clear, set frac msb */
23
+static inline abi_ptr cpu_untagged_addr(CPUState *cs, abi_ptr x)
19
+ set_float_default_nan_pattern(0b01000000, &env->fp_status);
24
+{
20
xtensa_use_first_nan(env, !dfpu);
25
+ return x;
21
}
26
+}
27
+#endif
28
+
29
/* All direct uses of g2h and h2g need to go away for usermode softmmu. */
30
#define g2h(x) ((void *)((uintptr_t)(abi_ptr)(x) + guest_base))
31
22
32
--
23
--
33
2.20.1
24
2.34.1
34
35
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
Set the default NaN pattern explicitly for hexagon.
2
Remove the ifdef from parts64_default_nan(); the only
3
remaining unconverted targets all use the default case.
2
4
3
This is more descriptive than 'unsigned long'.
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
No functional change, since these match on all linux+bsd hosts.
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20241202131347.498124-52-peter.maydell@linaro.org
8
---
9
target/hexagon/cpu.c | 2 ++
10
fpu/softfloat-specialize.c.inc | 5 -----
11
2 files changed, 2 insertions(+), 5 deletions(-)
5
12
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
13
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Message-id: 20210212184902.1251044-5-richard.henderson@linaro.org
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
12
include/exec/cpu_ldst.h | 6 +++---
13
1 file changed, 3 insertions(+), 3 deletions(-)
14
15
diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h
16
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
17
--- a/include/exec/cpu_ldst.h
15
--- a/target/hexagon/cpu.c
18
+++ b/include/exec/cpu_ldst.h
16
+++ b/target/hexagon/cpu.c
19
@@ -XXX,XX +XXX,XX @@ typedef uint64_t abi_ptr;
17
@@ -XXX,XX +XXX,XX @@ static void hexagon_cpu_reset_hold(Object *obj, ResetType type)
20
#endif
18
21
19
set_default_nan_mode(1, &env->fp_status);
22
/* All direct uses of g2h and h2g need to go away for usermode softmmu. */
20
set_float_detect_tininess(float_tininess_before_rounding, &env->fp_status);
23
-#define g2h(x) ((void *)((unsigned long)(abi_ptr)(x) + guest_base))
21
+ /* Default NaN value: sign bit set, all frac bits set */
24
+#define g2h(x) ((void *)((uintptr_t)(abi_ptr)(x) + guest_base))
22
+ set_float_default_nan_pattern(0b11111111, &env->fp_status);
25
26
#if HOST_LONG_BITS <= TARGET_VIRT_ADDR_SPACE_BITS
27
#define guest_addr_valid(x) (1)
28
#else
29
#define guest_addr_valid(x) ((x) <= GUEST_ADDR_MAX)
30
#endif
31
-#define h2g_valid(x) guest_addr_valid((unsigned long)(x) - guest_base)
32
+#define h2g_valid(x) guest_addr_valid((uintptr_t)(x) - guest_base)
33
34
static inline int guest_range_valid(unsigned long start, unsigned long len)
35
{
36
@@ -XXX,XX +XXX,XX @@ static inline int guest_range_valid(unsigned long start, unsigned long len)
37
}
23
}
38
24
39
#define h2g_nocheck(x) ({ \
25
static void hexagon_cpu_disas_set_info(CPUState *s, disassemble_info *info)
40
- unsigned long __ret = (unsigned long)(x) - guest_base; \
26
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
41
+ uintptr_t __ret = (uintptr_t)(x) - guest_base; \
27
index XXXXXXX..XXXXXXX 100644
42
(abi_ptr)__ret; \
28
--- a/fpu/softfloat-specialize.c.inc
43
})
29
+++ b/fpu/softfloat-specialize.c.inc
30
@@ -XXX,XX +XXX,XX @@ static void parts64_default_nan(FloatParts64 *p, float_status *status)
31
uint8_t dnan_pattern = status->default_nan_pattern;
32
33
if (dnan_pattern == 0) {
34
-#if defined(TARGET_HEXAGON)
35
- /* Sign bit set, all frac bits set. */
36
- dnan_pattern = 0b11111111;
37
-#else
38
/*
39
* This case is true for Alpha, ARM, MIPS, OpenRISC, PPC, RISC-V,
40
* S390, SH4, TriCore, and Xtensa. Our other supported targets
41
@@ -XXX,XX +XXX,XX @@ static void parts64_default_nan(FloatParts64 *p, float_status *status)
42
/* sign bit clear, set frac msb */
43
dnan_pattern = 0b01000000;
44
}
45
-#endif
46
}
47
assert(dnan_pattern != 0);
44
48
45
--
49
--
46
2.20.1
50
2.34.1
47
48
diff view generated by jsdifflib
New patch
1
Set the default NaN pattern explicitly for riscv.
1
2
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Message-id: 20241202131347.498124-53-peter.maydell@linaro.org
6
---
7
target/riscv/cpu.c | 2 ++
8
1 file changed, 2 insertions(+)
9
10
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/target/riscv/cpu.c
13
+++ b/target/riscv/cpu.c
14
@@ -XXX,XX +XXX,XX @@ static void riscv_cpu_reset_hold(Object *obj, ResetType type)
15
cs->exception_index = RISCV_EXCP_NONE;
16
env->load_res = -1;
17
set_default_nan_mode(1, &env->fp_status);
18
+ /* Default NaN value: sign bit clear, frac msb set */
19
+ set_float_default_nan_pattern(0b01000000, &env->fp_status);
20
env->vill = true;
21
22
#ifndef CONFIG_USER_ONLY
23
--
24
2.34.1
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
Set the default NaN pattern explicitly for tricore.
2
2
3
These constants are only ever used with access_ok, and friends.
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Rather than translating them to PAGE_* bits, let them equal
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
the PAGE_* bits to begin.
5
Message-id: 20241202131347.498124-54-peter.maydell@linaro.org
6
---
7
target/tricore/helper.c | 2 ++
8
1 file changed, 2 insertions(+)
6
9
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
diff --git a/target/tricore/helper.c b/target/tricore/helper.c
8
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
9
Message-id: 20210212184902.1251044-8-richard.henderson@linaro.org
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
12
linux-user/qemu.h | 8 +++-----
13
1 file changed, 3 insertions(+), 5 deletions(-)
14
15
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
16
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
17
--- a/linux-user/qemu.h
12
--- a/target/tricore/helper.c
18
+++ b/linux-user/qemu.h
13
+++ b/target/tricore/helper.c
19
@@ -XXX,XX +XXX,XX @@ extern unsigned long guest_stack_size;
14
@@ -XXX,XX +XXX,XX @@ void fpu_set_state(CPUTriCoreState *env)
20
15
set_flush_to_zero(1, &env->fp_status);
21
/* user access */
16
set_float_detect_tininess(float_tininess_before_rounding, &env->fp_status);
22
17
set_default_nan_mode(1, &env->fp_status);
23
-#define VERIFY_READ 0
18
+ /* Default NaN pattern: sign bit clear, frac msb set */
24
-#define VERIFY_WRITE 1 /* implies read access */
19
+ set_float_default_nan_pattern(0b01000000, &env->fp_status);
25
+#define VERIFY_READ PAGE_READ
26
+#define VERIFY_WRITE (PAGE_READ | PAGE_WRITE)
27
28
static inline bool access_ok(int type, abi_ulong addr, abi_ulong size)
29
{
30
@@ -XXX,XX +XXX,XX @@ static inline bool access_ok(int type, abi_ulong addr, abi_ulong size)
31
!guest_addr_valid(addr + size - 1))) {
32
return false;
33
}
34
- return page_check_range((target_ulong)addr, size,
35
- (type == VERIFY_READ) ? PAGE_READ :
36
- (PAGE_READ | PAGE_WRITE)) == 0;
37
+ return page_check_range((target_ulong)addr, size, type) == 0;
38
}
20
}
39
21
40
/* NOTE __get_user and __put_user use host pointers and don't check access.
22
uint32_t psw_read(CPUTriCoreState *env)
41
--
23
--
42
2.20.1
24
2.34.1
43
44
diff view generated by jsdifflib
New patch
1
Now that all our targets have bene converted to explicitly specify
2
their pattern for the default NaN value we can remove the remaining
3
fallback code in parts64_default_nan().
1
4
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20241202131347.498124-55-peter.maydell@linaro.org
8
---
9
fpu/softfloat-specialize.c.inc | 14 --------------
10
1 file changed, 14 deletions(-)
11
12
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
13
index XXXXXXX..XXXXXXX 100644
14
--- a/fpu/softfloat-specialize.c.inc
15
+++ b/fpu/softfloat-specialize.c.inc
16
@@ -XXX,XX +XXX,XX @@ static void parts64_default_nan(FloatParts64 *p, float_status *status)
17
uint64_t frac;
18
uint8_t dnan_pattern = status->default_nan_pattern;
19
20
- if (dnan_pattern == 0) {
21
- /*
22
- * This case is true for Alpha, ARM, MIPS, OpenRISC, PPC, RISC-V,
23
- * S390, SH4, TriCore, and Xtensa. Our other supported targets
24
- * do not have floating-point.
25
- */
26
- if (snan_bit_is_one(status)) {
27
- /* sign bit clear, set all frac bits other than msb */
28
- dnan_pattern = 0b00111111;
29
- } else {
30
- /* sign bit clear, set frac msb */
31
- dnan_pattern = 0b01000000;
32
- }
33
- }
34
assert(dnan_pattern != 0);
35
36
sign = dnan_pattern >> 7;
37
--
38
2.34.1
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
Use simple arithmetic instead of a conditional
3
Inline pickNaNMulAdd into its only caller. This makes
4
move when tbi0 != tbi1.
4
one assert redundant with the immediately preceding IF.
5
5
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20210212184902.1251044-22-richard.henderson@linaro.org
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
8
Message-id: 20241203203949.483774-3-richard.henderson@linaro.org
9
[PMM: keep comment from old code in new location]
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/translate-a64.c | 25 ++++++++++++++-----------
12
fpu/softfloat-parts.c.inc | 41 +++++++++++++++++++++++++-
12
1 file changed, 14 insertions(+), 11 deletions(-)
13
fpu/softfloat-specialize.c.inc | 54 ----------------------------------
14
2 files changed, 40 insertions(+), 55 deletions(-)
13
15
14
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
16
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
15
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
16
--- a/target/arm/translate-a64.c
18
--- a/fpu/softfloat-parts.c.inc
17
+++ b/target/arm/translate-a64.c
19
+++ b/fpu/softfloat-parts.c.inc
18
@@ -XXX,XX +XXX,XX @@ static void gen_top_byte_ignore(DisasContext *s, TCGv_i64 dst,
20
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b,
19
/* Sign-extend from bit 55. */
21
}
20
tcg_gen_sextract_i64(dst, src, 0, 56);
22
21
23
if (s->default_nan_mode) {
22
- if (tbi != 3) {
24
+ /*
23
- TCGv_i64 tcg_zero = tcg_const_i64(0);
25
+ * We guarantee not to require the target to tell us how to
24
-
26
+ * pick a NaN if we're always returning the default NaN.
25
- /*
27
+ * But if we're not in default-NaN mode then the target must
26
- * The two TBI bits differ.
28
+ * specify.
27
- * If tbi0, then !tbi1: only use the extension if positive.
29
+ */
28
- * if !tbi0, then tbi1: only use the extension if negative.
30
which = 3;
29
- */
31
+ } else if (infzero) {
30
- tcg_gen_movcond_i64(tbi == 1 ? TCG_COND_GE : TCG_COND_LT,
32
+ /*
31
- dst, dst, tcg_zero, dst, src);
33
+ * Inf * 0 + NaN -- some implementations return the
32
- tcg_temp_free_i64(tcg_zero);
34
+ * default NaN here, and some return the input NaN.
33
+ switch (tbi) {
35
+ */
34
+ case 1:
36
+ switch (s->float_infzeronan_rule) {
35
+ /* tbi0 but !tbi1: only use the extension if positive */
37
+ case float_infzeronan_dnan_never:
36
+ tcg_gen_and_i64(dst, dst, src);
38
+ which = 2;
37
+ break;
39
+ break;
38
+ case 2:
40
+ case float_infzeronan_dnan_always:
39
+ /* !tbi0 but tbi1: only use the extension if negative */
41
+ which = 3;
40
+ tcg_gen_or_i64(dst, dst, src);
41
+ break;
42
+ break;
42
+ case 3:
43
+ case float_infzeronan_dnan_if_qnan:
43
+ /* tbi0 and tbi1: always use the extension */
44
+ which = is_qnan(c->cls) ? 3 : 2;
44
+ break;
45
+ break;
45
+ default:
46
+ default:
46
+ g_assert_not_reached();
47
+ g_assert_not_reached();
47
}
48
+ }
49
} else {
50
- which = pickNaNMulAdd(a->cls, b->cls, c->cls, infzero, have_snan, s);
51
+ FloatClass cls[3] = { a->cls, b->cls, c->cls };
52
+ Float3NaNPropRule rule = s->float_3nan_prop_rule;
53
+
54
+ assert(rule != float_3nan_prop_none);
55
+ if (have_snan && (rule & R_3NAN_SNAN_MASK)) {
56
+ /* We have at least one SNaN input and should prefer it */
57
+ do {
58
+ which = rule & R_3NAN_1ST_MASK;
59
+ rule >>= R_3NAN_1ST_LENGTH;
60
+ } while (!is_snan(cls[which]));
61
+ } else {
62
+ do {
63
+ which = rule & R_3NAN_1ST_MASK;
64
+ rule >>= R_3NAN_1ST_LENGTH;
65
+ } while (!is_nan(cls[which]));
66
+ }
67
}
68
69
if (which == 3) {
70
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
71
index XXXXXXX..XXXXXXX 100644
72
--- a/fpu/softfloat-specialize.c.inc
73
+++ b/fpu/softfloat-specialize.c.inc
74
@@ -XXX,XX +XXX,XX @@ static int pickNaN(FloatClass a_cls, FloatClass b_cls,
48
}
75
}
49
}
76
}
77
78
-/*----------------------------------------------------------------------------
79
-| Select which NaN to propagate for a three-input operation.
80
-| For the moment we assume that no CPU needs the 'larger significand'
81
-| information.
82
-| Return values : 0 : a; 1 : b; 2 : c; 3 : default-NaN
83
-*----------------------------------------------------------------------------*/
84
-static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
85
- bool infzero, bool have_snan, float_status *status)
86
-{
87
- FloatClass cls[3] = { a_cls, b_cls, c_cls };
88
- Float3NaNPropRule rule = status->float_3nan_prop_rule;
89
- int which;
90
-
91
- /*
92
- * We guarantee not to require the target to tell us how to
93
- * pick a NaN if we're always returning the default NaN.
94
- * But if we're not in default-NaN mode then the target must
95
- * specify.
96
- */
97
- assert(!status->default_nan_mode);
98
-
99
- if (infzero) {
100
- /*
101
- * Inf * 0 + NaN -- some implementations return the default NaN here,
102
- * and some return the input NaN.
103
- */
104
- switch (status->float_infzeronan_rule) {
105
- case float_infzeronan_dnan_never:
106
- return 2;
107
- case float_infzeronan_dnan_always:
108
- return 3;
109
- case float_infzeronan_dnan_if_qnan:
110
- return is_qnan(c_cls) ? 3 : 2;
111
- default:
112
- g_assert_not_reached();
113
- }
114
- }
115
-
116
- assert(rule != float_3nan_prop_none);
117
- if (have_snan && (rule & R_3NAN_SNAN_MASK)) {
118
- /* We have at least one SNaN input and should prefer it */
119
- do {
120
- which = rule & R_3NAN_1ST_MASK;
121
- rule >>= R_3NAN_1ST_LENGTH;
122
- } while (!is_snan(cls[which]));
123
- } else {
124
- do {
125
- which = rule & R_3NAN_1ST_MASK;
126
- rule >>= R_3NAN_1ST_LENGTH;
127
- } while (!is_nan(cls[which]));
128
- }
129
- return which;
130
-}
131
-
132
/*----------------------------------------------------------------------------
133
| Returns 1 if the double-precision floating-point value `a' is a quiet
134
| NaN; otherwise returns 0.
50
--
135
--
51
2.20.1
136
2.34.1
52
137
53
138
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
This is more descriptive than 'unsigned long'.
3
Remove "3" as a special case for which and simply
4
No functional change, since these match on all linux+bsd hosts.
4
branch to return the desired value.
5
5
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
9
Message-id: 20210212184902.1251044-4-richard.henderson@linaro.org
8
Message-id: 20241203203949.483774-4-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
include/exec/cpu-all.h | 2 +-
11
fpu/softfloat-parts.c.inc | 20 ++++++++++----------
13
bsd-user/main.c | 4 ++--
12
1 file changed, 10 insertions(+), 10 deletions(-)
14
linux-user/elfload.c | 4 ++--
15
linux-user/main.c | 4 ++--
16
4 files changed, 7 insertions(+), 7 deletions(-)
17
13
18
diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h
14
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
19
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
20
--- a/include/exec/cpu-all.h
16
--- a/fpu/softfloat-parts.c.inc
21
+++ b/include/exec/cpu-all.h
17
+++ b/fpu/softfloat-parts.c.inc
22
@@ -XXX,XX +XXX,XX @@ static inline void tswap64s(uint64_t *s)
18
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b,
23
/* On some host systems the guest address space is reserved on the host.
19
* But if we're not in default-NaN mode then the target must
24
* This allows the guest address space to be offset to a convenient location.
20
* specify.
25
*/
21
*/
26
-extern unsigned long guest_base;
22
- which = 3;
27
+extern uintptr_t guest_base;
23
+ goto default_nan;
28
extern bool have_guest_base;
24
} else if (infzero) {
29
extern unsigned long reserved_va;
25
/*
30
26
* Inf * 0 + NaN -- some implementations return the
31
diff --git a/bsd-user/main.c b/bsd-user/main.c
27
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b,
32
index XXXXXXX..XXXXXXX 100644
28
*/
33
--- a/bsd-user/main.c
29
switch (s->float_infzeronan_rule) {
34
+++ b/bsd-user/main.c
30
case float_infzeronan_dnan_never:
35
@@ -XXX,XX +XXX,XX @@
31
- which = 2;
36
32
break;
37
int singlestep;
33
case float_infzeronan_dnan_always:
38
unsigned long mmap_min_addr;
34
- which = 3;
39
-unsigned long guest_base;
35
- break;
40
+uintptr_t guest_base;
36
+ goto default_nan;
41
bool have_guest_base;
37
case float_infzeronan_dnan_if_qnan:
42
unsigned long reserved_va;
38
- which = is_qnan(c->cls) ? 3 : 2;
43
39
+ if (is_qnan(c->cls)) {
44
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
40
+ goto default_nan;
45
g_free(target_environ);
41
+ }
46
42
break;
47
if (qemu_loglevel_mask(CPU_LOG_PAGE)) {
43
default:
48
- qemu_log("guest_base 0x%lx\n", guest_base);
44
g_assert_not_reached();
49
+ qemu_log("guest_base %p\n", (void *)guest_base);
45
}
50
log_page_dump("binary load");
46
+ which = 2;
51
47
} else {
52
qemu_log("start_brk 0x" TARGET_ABI_FMT_lx "\n", info->start_brk);
48
FloatClass cls[3] = { a->cls, b->cls, c->cls };
53
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
49
Float3NaNPropRule rule = s->float_3nan_prop_rule;
54
index XXXXXXX..XXXXXXX 100644
50
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b,
55
--- a/linux-user/elfload.c
51
}
56
+++ b/linux-user/elfload.c
57
@@ -XXX,XX +XXX,XX @@ static void pgb_have_guest_base(const char *image_name, abi_ulong guest_loaddr,
58
void *addr, *test;
59
60
if (!QEMU_IS_ALIGNED(guest_base, align)) {
61
- fprintf(stderr, "Requested guest base 0x%lx does not satisfy "
62
+ fprintf(stderr, "Requested guest base %p does not satisfy "
63
"host minimum alignment (0x%lx)\n",
64
- guest_base, align);
65
+ (void *)guest_base, align);
66
exit(EXIT_FAILURE);
67
}
52
}
68
53
69
diff --git a/linux-user/main.c b/linux-user/main.c
54
- if (which == 3) {
70
index XXXXXXX..XXXXXXX 100644
55
- parts_default_nan(a, s);
71
--- a/linux-user/main.c
56
- return a;
72
+++ b/linux-user/main.c
57
- }
73
@@ -XXX,XX +XXX,XX @@ static const char *cpu_model;
58
-
74
static const char *cpu_type;
59
switch (which) {
75
static const char *seed_optarg;
60
case 0:
76
unsigned long mmap_min_addr;
61
break;
77
-unsigned long guest_base;
62
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b,
78
+uintptr_t guest_base;
63
parts_silence_nan(a, s);
79
bool have_guest_base;
64
}
65
return a;
66
+
67
+ default_nan:
68
+ parts_default_nan(a, s);
69
+ return a;
70
}
80
71
81
/*
72
/*
82
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv, char **envp)
83
g_free(target_environ);
84
85
if (qemu_loglevel_mask(CPU_LOG_PAGE)) {
86
- qemu_log("guest_base 0x%lx\n", guest_base);
87
+ qemu_log("guest_base %p\n", (void *)guest_base);
88
log_page_dump("binary load");
89
90
qemu_log("start_brk 0x" TARGET_ABI_FMT_lx "\n", info->start_brk);
91
--
73
--
92
2.20.1
74
2.34.1
93
75
94
76
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
Record whether the backing page is anonymous, or if it has file
3
Assign the pointer return value to 'a' directly,
4
backing. This will allow us to get close to the Linux AArch64
4
rather than going through an intermediary index.
5
ABI for MTE, which allows tag memory only on ram-backed VMAs.
6
5
7
The real ABI allows tag memory on files, when those files are
8
on ram-backed filesystems, such as tmpfs. We will not be able
9
to implement that in QEMU linux-user.
10
11
Thankfully, anonymous memory for malloc arenas is the primary
12
consumer of this feature, so this restricted version should
13
still be of use.
14
15
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
16
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
17
Message-id: 20210212184902.1251044-3-richard.henderson@linaro.org
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
8
Message-id: 20241203203949.483774-5-richard.henderson@linaro.org
18
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
19
---
10
---
20
include/exec/cpu-all.h | 2 ++
11
fpu/softfloat-parts.c.inc | 32 ++++++++++----------------------
21
linux-user/mmap.c | 3 +++
12
1 file changed, 10 insertions(+), 22 deletions(-)
22
2 files changed, 5 insertions(+)
23
13
24
diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h
14
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
25
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
26
--- a/include/exec/cpu-all.h
16
--- a/fpu/softfloat-parts.c.inc
27
+++ b/include/exec/cpu-all.h
17
+++ b/fpu/softfloat-parts.c.inc
28
@@ -XXX,XX +XXX,XX @@ extern intptr_t qemu_host_page_mask;
18
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b,
29
#define PAGE_WRITE_INV 0x0020
19
FloatPartsN *c, float_status *s,
30
/* For use with page_set_flags: page is being replaced; target_data cleared. */
20
int ab_mask, int abc_mask)
31
#define PAGE_RESET 0x0040
21
{
32
+/* For linux-user, indicates that the page is MAP_ANON. */
22
- int which;
33
+#define PAGE_ANON 0x0080
23
bool infzero = (ab_mask == float_cmask_infzero);
34
24
bool have_snan = (abc_mask & float_cmask_snan);
35
#if defined(CONFIG_BSD) && defined(CONFIG_USER_ONLY)
25
+ FloatPartsN *ret;
36
/* FIXME: Code that sets/uses this is broken and needs to go away. */
26
37
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
27
if (unlikely(have_snan)) {
38
index XXXXXXX..XXXXXXX 100644
28
float_raise(float_flag_invalid | float_flag_invalid_snan, s);
39
--- a/linux-user/mmap.c
29
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b,
40
+++ b/linux-user/mmap.c
30
default:
41
@@ -XXX,XX +XXX,XX @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot,
31
g_assert_not_reached();
32
}
33
- which = 2;
34
+ ret = c;
35
} else {
36
- FloatClass cls[3] = { a->cls, b->cls, c->cls };
37
+ FloatPartsN *val[3] = { a, b, c };
38
Float3NaNPropRule rule = s->float_3nan_prop_rule;
39
40
assert(rule != float_3nan_prop_none);
41
if (have_snan && (rule & R_3NAN_SNAN_MASK)) {
42
/* We have at least one SNaN input and should prefer it */
43
do {
44
- which = rule & R_3NAN_1ST_MASK;
45
+ ret = val[rule & R_3NAN_1ST_MASK];
46
rule >>= R_3NAN_1ST_LENGTH;
47
- } while (!is_snan(cls[which]));
48
+ } while (!is_snan(ret->cls));
49
} else {
50
do {
51
- which = rule & R_3NAN_1ST_MASK;
52
+ ret = val[rule & R_3NAN_1ST_MASK];
53
rule >>= R_3NAN_1ST_LENGTH;
54
- } while (!is_nan(cls[which]));
55
+ } while (!is_nan(ret->cls));
42
}
56
}
43
}
57
}
44
the_end1:
58
45
+ if (flags & MAP_ANONYMOUS) {
59
- switch (which) {
46
+ page_flags |= PAGE_ANON;
60
- case 0:
47
+ }
61
- break;
48
page_flags |= PAGE_RESET;
62
- case 1:
49
page_set_flags(start, start + len, page_flags);
63
- a = b;
50
the_end:
64
- break;
65
- case 2:
66
- a = c;
67
- break;
68
- default:
69
- g_assert_not_reached();
70
+ if (is_snan(ret->cls)) {
71
+ parts_silence_nan(ret, s);
72
}
73
- if (is_snan(a->cls)) {
74
- parts_silence_nan(a, s);
75
- }
76
- return a;
77
+ return ret;
78
79
default_nan:
80
parts_default_nan(a, s);
51
--
81
--
52
2.20.1
82
2.34.1
53
83
54
84
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
Return bool not int; pass abi_ulong not 'unsigned long'.
3
While all indices into val[] should be in [0-2], the mask
4
All callers use abi_ulong already, so the change in type
4
applied is two bits. To help static analysis see there is
5
has no effect.
5
no possibility of read beyond the end of the array, pad the
6
array to 4 entries, with the final being (implicitly) NULL.
6
7
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
9
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
10
Message-id: 20210212184902.1251044-6-richard.henderson@linaro.org
10
Message-id: 20241203203949.483774-6-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
---
12
---
13
include/exec/cpu_ldst.h | 2 +-
13
fpu/softfloat-parts.c.inc | 2 +-
14
1 file changed, 1 insertion(+), 1 deletion(-)
14
1 file changed, 1 insertion(+), 1 deletion(-)
15
15
16
diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h
16
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
17
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
18
--- a/include/exec/cpu_ldst.h
18
--- a/fpu/softfloat-parts.c.inc
19
+++ b/include/exec/cpu_ldst.h
19
+++ b/fpu/softfloat-parts.c.inc
20
@@ -XXX,XX +XXX,XX @@ typedef uint64_t abi_ptr;
20
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b,
21
#endif
21
}
22
#define h2g_valid(x) guest_addr_valid((uintptr_t)(x) - guest_base)
22
ret = c;
23
23
} else {
24
-static inline int guest_range_valid(unsigned long start, unsigned long len)
24
- FloatPartsN *val[3] = { a, b, c };
25
+static inline bool guest_range_valid(abi_ulong start, abi_ulong len)
25
+ FloatPartsN *val[R_3NAN_1ST_MASK + 1] = { a, b, c };
26
{
26
Float3NaNPropRule rule = s->float_3nan_prop_rule;
27
return len - 1 <= GUEST_ADDR_MAX && start <= GUEST_ADDR_MAX - len + 1;
27
28
}
28
assert(rule != float_3nan_prop_none);
29
--
29
--
30
2.20.1
30
2.34.1
31
31
32
32
diff view generated by jsdifflib
1
From: Doug Evans <dje@google.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
Reviewed-by: Hao Wu <wuhaotsh@google.com>
3
This function is part of the public interface and
4
Reviewed-by: Avi Fishman <avi.fishman@nuvoton.com>
4
is not "specialized" to any target in any way.
5
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
5
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Doug Evans <dje@google.com>
8
Message-id: 20241203203949.483774-7-richard.henderson@linaro.org
7
Message-id: 20210213002520.1374134-4-dje@google.com
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
10
---
10
tests/qtest/npcm7xx_emc-test.c | 862 +++++++++++++++++++++++++++++++++
11
fpu/softfloat.c | 52 ++++++++++++++++++++++++++++++++++
11
tests/qtest/meson.build | 1 +
12
fpu/softfloat-specialize.c.inc | 52 ----------------------------------
12
2 files changed, 863 insertions(+)
13
2 files changed, 52 insertions(+), 52 deletions(-)
13
create mode 100644 tests/qtest/npcm7xx_emc-test.c
14
14
15
diff --git a/tests/qtest/npcm7xx_emc-test.c b/tests/qtest/npcm7xx_emc-test.c
15
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
16
new file mode 100644
16
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX
17
--- a/fpu/softfloat.c
18
--- /dev/null
18
+++ b/fpu/softfloat.c
19
+++ b/tests/qtest/npcm7xx_emc-test.c
19
@@ -XXX,XX +XXX,XX @@ void normalizeFloatx80Subnormal(uint64_t aSig, int32_t *zExpPtr,
20
@@ -XXX,XX +XXX,XX @@
20
*zExpPtr = 1 - shiftCount;
21
+/*
21
}
22
+ * QTests for Nuvoton NPCM7xx EMC Modules.
22
23
+ *
23
+/*----------------------------------------------------------------------------
24
+ * Copyright 2020 Google LLC
24
+| Takes two extended double-precision floating-point values `a' and `b', one
25
+ *
25
+| of which is a NaN, and returns the appropriate NaN result. If either `a' or
26
+ * This program is free software; you can redistribute it and/or modify it
26
+| `b' is a signaling NaN, the invalid exception is raised.
27
+ * under the terms of the GNU General Public License as published by the
27
+*----------------------------------------------------------------------------*/
28
+ * Free Software Foundation; either version 2 of the License, or
29
+ * (at your option) any later version.
30
+ *
31
+ * This program is distributed in the hope that it will be useful, but WITHOUT
32
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
33
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
34
+ * for more details.
35
+ */
36
+
28
+
37
+#include "qemu/osdep.h"
29
+floatx80 propagateFloatx80NaN(floatx80 a, floatx80 b, float_status *status)
38
+#include "qemu-common.h"
30
+{
39
+#include "libqos/libqos.h"
31
+ bool aIsLargerSignificand;
40
+#include "qapi/qmp/qdict.h"
32
+ FloatClass a_cls, b_cls;
41
+#include "qapi/qmp/qnum.h"
42
+#include "qemu/bitops.h"
43
+#include "qemu/iov.h"
44
+
33
+
45
+/* Name of the emc device. */
34
+ /* This is not complete, but is good enough for pickNaN. */
46
+#define TYPE_NPCM7XX_EMC "npcm7xx-emc"
35
+ a_cls = (!floatx80_is_any_nan(a)
36
+ ? float_class_normal
37
+ : floatx80_is_signaling_nan(a, status)
38
+ ? float_class_snan
39
+ : float_class_qnan);
40
+ b_cls = (!floatx80_is_any_nan(b)
41
+ ? float_class_normal
42
+ : floatx80_is_signaling_nan(b, status)
43
+ ? float_class_snan
44
+ : float_class_qnan);
47
+
45
+
48
+/* Timeout for various operations, in seconds. */
46
+ if (is_snan(a_cls) || is_snan(b_cls)) {
49
+#define TIMEOUT_SECONDS 10
47
+ float_raise(float_flag_invalid, status);
50
+
51
+/* Address in memory of the descriptor. */
52
+#define DESC_ADDR (1 << 20) /* 1 MiB */
53
+
54
+/* Address in memory of the data packet. */
55
+#define DATA_ADDR (DESC_ADDR + 4096)
56
+
57
+#define CRC_LENGTH 4
58
+
59
+#define NUM_TX_DESCRIPTORS 3
60
+#define NUM_RX_DESCRIPTORS 2
61
+
62
+/* Size of tx,rx test buffers. */
63
+#define TX_DATA_LEN 64
64
+#define RX_DATA_LEN 64
65
+
66
+#define TX_STEP_COUNT 10000
67
+#define RX_STEP_COUNT 10000
68
+
69
+/* 32-bit register indices. */
70
+typedef enum NPCM7xxPWMRegister {
71
+ /* Control registers. */
72
+ REG_CAMCMR,
73
+ REG_CAMEN,
74
+
75
+ /* There are 16 CAMn[ML] registers. */
76
+ REG_CAMM_BASE,
77
+ REG_CAML_BASE,
78
+
79
+ REG_TXDLSA = 0x22,
80
+ REG_RXDLSA,
81
+ REG_MCMDR,
82
+ REG_MIID,
83
+ REG_MIIDA,
84
+ REG_FFTCR,
85
+ REG_TSDR,
86
+ REG_RSDR,
87
+ REG_DMARFC,
88
+ REG_MIEN,
89
+
90
+ /* Status registers. */
91
+ REG_MISTA,
92
+ REG_MGSTA,
93
+ REG_MPCNT,
94
+ REG_MRPC,
95
+ REG_MRPCC,
96
+ REG_MREPC,
97
+ REG_DMARFS,
98
+ REG_CTXDSA,
99
+ REG_CTXBSA,
100
+ REG_CRXDSA,
101
+ REG_CRXBSA,
102
+
103
+ NPCM7XX_NUM_EMC_REGS,
104
+} NPCM7xxPWMRegister;
105
+
106
+enum { NUM_CAMML_REGS = 16 };
107
+
108
+/* REG_CAMCMR fields */
109
+/* Enable CAM Compare */
110
+#define REG_CAMCMR_ECMP (1 << 4)
111
+/* Accept Unicast Packet */
112
+#define REG_CAMCMR_AUP (1 << 0)
113
+
114
+/* REG_MCMDR fields */
115
+/* Software Reset */
116
+#define REG_MCMDR_SWR (1 << 24)
117
+/* Frame Transmission On */
118
+#define REG_MCMDR_TXON (1 << 8)
119
+/* Accept Long Packet */
120
+#define REG_MCMDR_ALP (1 << 1)
121
+/* Frame Reception On */
122
+#define REG_MCMDR_RXON (1 << 0)
123
+
124
+/* REG_MIEN fields */
125
+/* Enable Transmit Completion Interrupt */
126
+#define REG_MIEN_ENTXCP (1 << 18)
127
+/* Enable Transmit Interrupt */
128
+#define REG_MIEN_ENTXINTR (1 << 16)
129
+/* Enable Receive Good Interrupt */
130
+#define REG_MIEN_ENRXGD (1 << 4)
131
+/* ENable Receive Interrupt */
132
+#define REG_MIEN_ENRXINTR (1 << 0)
133
+
134
+/* REG_MISTA fields */
135
+/* Transmit Bus Error Interrupt */
136
+#define REG_MISTA_TXBERR (1 << 24)
137
+/* Transmit Descriptor Unavailable Interrupt */
138
+#define REG_MISTA_TDU (1 << 23)
139
+/* Transmit Completion Interrupt */
140
+#define REG_MISTA_TXCP (1 << 18)
141
+/* Transmit Interrupt */
142
+#define REG_MISTA_TXINTR (1 << 16)
143
+/* Receive Bus Error Interrupt */
144
+#define REG_MISTA_RXBERR (1 << 11)
145
+/* Receive Descriptor Unavailable Interrupt */
146
+#define REG_MISTA_RDU (1 << 10)
147
+/* DMA Early Notification Interrupt */
148
+#define REG_MISTA_DENI (1 << 9)
149
+/* Maximum Frame Length Interrupt */
150
+#define REG_MISTA_DFOI (1 << 8)
151
+/* Receive Good Interrupt */
152
+#define REG_MISTA_RXGD (1 << 4)
153
+/* Packet Too Long Interrupt */
154
+#define REG_MISTA_PTLE (1 << 3)
155
+/* Receive Interrupt */
156
+#define REG_MISTA_RXINTR (1 << 0)
157
+
158
+typedef struct NPCM7xxEMCTxDesc NPCM7xxEMCTxDesc;
159
+typedef struct NPCM7xxEMCRxDesc NPCM7xxEMCRxDesc;
160
+
161
+struct NPCM7xxEMCTxDesc {
162
+ uint32_t flags;
163
+ uint32_t txbsa;
164
+ uint32_t status_and_length;
165
+ uint32_t ntxdsa;
166
+};
167
+
168
+struct NPCM7xxEMCRxDesc {
169
+ uint32_t status_and_length;
170
+ uint32_t rxbsa;
171
+ uint32_t reserved;
172
+ uint32_t nrxdsa;
173
+};
174
+
175
+/* NPCM7xxEMCTxDesc.flags values */
176
+/* Owner: 0 = cpu, 1 = emc */
177
+#define TX_DESC_FLAG_OWNER_MASK (1 << 31)
178
+/* Transmit interrupt enable */
179
+#define TX_DESC_FLAG_INTEN (1 << 2)
180
+
181
+/* NPCM7xxEMCTxDesc.status_and_length values */
182
+/* Transmission complete */
183
+#define TX_DESC_STATUS_TXCP (1 << 19)
184
+/* Transmit interrupt */
185
+#define TX_DESC_STATUS_TXINTR (1 << 16)
186
+
187
+/* NPCM7xxEMCRxDesc.status_and_length values */
188
+/* Owner: 0b00 = cpu, 0b10 = emc */
189
+#define RX_DESC_STATUS_OWNER_SHIFT 30
190
+#define RX_DESC_STATUS_OWNER_MASK 0xc0000000
191
+/* Frame Reception Complete */
192
+#define RX_DESC_STATUS_RXGD (1 << 20)
193
+/* Packet too long */
194
+#define RX_DESC_STATUS_PTLE (1 << 19)
195
+/* Receive Interrupt */
196
+#define RX_DESC_STATUS_RXINTR (1 << 16)
197
+
198
+#define RX_DESC_PKT_LEN(word) ((uint32_t) (word) & 0xffff)
199
+
200
+typedef struct EMCModule {
201
+ int rx_irq;
202
+ int tx_irq;
203
+ uint64_t base_addr;
204
+} EMCModule;
205
+
206
+typedef struct TestData {
207
+ const EMCModule *module;
208
+} TestData;
209
+
210
+static const EMCModule emc_module_list[] = {
211
+ {
212
+ .rx_irq = 15,
213
+ .tx_irq = 16,
214
+ .base_addr = 0xf0825000
215
+ },
216
+ {
217
+ .rx_irq = 114,
218
+ .tx_irq = 115,
219
+ .base_addr = 0xf0826000
220
+ }
221
+};
222
+
223
+/* Returns the index of the EMC module. */
224
+static int emc_module_index(const EMCModule *mod)
225
+{
226
+ ptrdiff_t diff = mod - emc_module_list;
227
+
228
+ g_assert_true(diff >= 0 && diff < ARRAY_SIZE(emc_module_list));
229
+
230
+ return diff;
231
+}
232
+
233
+static void packet_test_clear(void *sockets)
234
+{
235
+ int *test_sockets = sockets;
236
+
237
+ close(test_sockets[0]);
238
+ g_free(test_sockets);
239
+}
240
+
241
+static int *packet_test_init(int module_num, GString *cmd_line)
242
+{
243
+ int *test_sockets = g_new(int, 2);
244
+ int ret = socketpair(PF_UNIX, SOCK_STREAM, 0, test_sockets);
245
+ g_assert_cmpint(ret, != , -1);
246
+
247
+ /*
248
+ * KISS and use -nic. We specify two nics (both emc{0,1}) because there's
249
+ * currently no way to specify only emc1: The driver implicitly relies on
250
+ * emc[i] == nd_table[i].
251
+ */
252
+ if (module_num == 0) {
253
+ g_string_append_printf(cmd_line,
254
+ " -nic socket,fd=%d,model=" TYPE_NPCM7XX_EMC " "
255
+ " -nic user,model=" TYPE_NPCM7XX_EMC " ",
256
+ test_sockets[1]);
257
+ } else {
258
+ g_string_append_printf(cmd_line,
259
+ " -nic user,model=" TYPE_NPCM7XX_EMC " "
260
+ " -nic socket,fd=%d,model=" TYPE_NPCM7XX_EMC " ",
261
+ test_sockets[1]);
262
+ }
48
+ }
263
+
49
+
264
+ g_test_queue_destroy(packet_test_clear, test_sockets);
50
+ if (status->default_nan_mode) {
265
+ return test_sockets;
51
+ return floatx80_default_nan(status);
266
+}
267
+
268
+static uint32_t emc_read(QTestState *qts, const EMCModule *mod,
269
+ NPCM7xxPWMRegister regno)
270
+{
271
+ return qtest_readl(qts, mod->base_addr + regno * sizeof(uint32_t));
272
+}
273
+
274
+static void emc_write(QTestState *qts, const EMCModule *mod,
275
+ NPCM7xxPWMRegister regno, uint32_t value)
276
+{
277
+ qtest_writel(qts, mod->base_addr + regno * sizeof(uint32_t), value);
278
+}
279
+
280
+static void emc_read_tx_desc(QTestState *qts, uint32_t addr,
281
+ NPCM7xxEMCTxDesc *desc)
282
+{
283
+ qtest_memread(qts, addr, desc, sizeof(*desc));
284
+ desc->flags = le32_to_cpu(desc->flags);
285
+ desc->txbsa = le32_to_cpu(desc->txbsa);
286
+ desc->status_and_length = le32_to_cpu(desc->status_and_length);
287
+ desc->ntxdsa = le32_to_cpu(desc->ntxdsa);
288
+}
289
+
290
+static void emc_write_tx_desc(QTestState *qts, const NPCM7xxEMCTxDesc *desc,
291
+ uint32_t addr)
292
+{
293
+ NPCM7xxEMCTxDesc le_desc;
294
+
295
+ le_desc.flags = cpu_to_le32(desc->flags);
296
+ le_desc.txbsa = cpu_to_le32(desc->txbsa);
297
+ le_desc.status_and_length = cpu_to_le32(desc->status_and_length);
298
+ le_desc.ntxdsa = cpu_to_le32(desc->ntxdsa);
299
+ qtest_memwrite(qts, addr, &le_desc, sizeof(le_desc));
300
+}
301
+
302
+static void emc_read_rx_desc(QTestState *qts, uint32_t addr,
303
+ NPCM7xxEMCRxDesc *desc)
304
+{
305
+ qtest_memread(qts, addr, desc, sizeof(*desc));
306
+ desc->status_and_length = le32_to_cpu(desc->status_and_length);
307
+ desc->rxbsa = le32_to_cpu(desc->rxbsa);
308
+ desc->reserved = le32_to_cpu(desc->reserved);
309
+ desc->nrxdsa = le32_to_cpu(desc->nrxdsa);
310
+}
311
+
312
+static void emc_write_rx_desc(QTestState *qts, const NPCM7xxEMCRxDesc *desc,
313
+ uint32_t addr)
314
+{
315
+ NPCM7xxEMCRxDesc le_desc;
316
+
317
+ le_desc.status_and_length = cpu_to_le32(desc->status_and_length);
318
+ le_desc.rxbsa = cpu_to_le32(desc->rxbsa);
319
+ le_desc.reserved = cpu_to_le32(desc->reserved);
320
+ le_desc.nrxdsa = cpu_to_le32(desc->nrxdsa);
321
+ qtest_memwrite(qts, addr, &le_desc, sizeof(le_desc));
322
+}
323
+
324
+/*
325
+ * Reset the EMC module.
326
+ * The module must be reset before, e.g., TXDLSA,RXDLSA are changed.
327
+ */
328
+static bool emc_soft_reset(QTestState *qts, const EMCModule *mod)
329
+{
330
+ uint32_t val;
331
+ uint64_t end_time;
332
+
333
+ emc_write(qts, mod, REG_MCMDR, REG_MCMDR_SWR);
334
+
335
+ /*
336
+ * Wait for device to reset as the linux driver does.
337
+ * During reset the AHB reads 0 for all registers. So first wait for
338
+ * something that resets to non-zero, and then wait for SWR becoming 0.
339
+ */
340
+ end_time = g_get_monotonic_time() + TIMEOUT_SECONDS * G_TIME_SPAN_SECOND;
341
+
342
+ do {
343
+ qtest_clock_step(qts, 100);
344
+ val = emc_read(qts, mod, REG_FFTCR);
345
+ } while (val == 0 && g_get_monotonic_time() < end_time);
346
+ if (val != 0) {
347
+ do {
348
+ qtest_clock_step(qts, 100);
349
+ val = emc_read(qts, mod, REG_MCMDR);
350
+ if ((val & REG_MCMDR_SWR) == 0) {
351
+ /*
352
+ * N.B. The CAMs have been reset here, so macaddr matching of
353
+ * incoming packets will not work.
354
+ */
355
+ return true;
356
+ }
357
+ } while (g_get_monotonic_time() < end_time);
358
+ }
52
+ }
359
+
53
+
360
+ g_message("%s: Timeout expired", __func__);
54
+ if (a.low < b.low) {
361
+ return false;
55
+ aIsLargerSignificand = 0;
362
+}
56
+ } else if (b.low < a.low) {
363
+
57
+ aIsLargerSignificand = 1;
364
+/* Check emc registers are reset to default value. */
58
+ } else {
365
+static void test_init(gconstpointer test_data)
59
+ aIsLargerSignificand = (a.high < b.high) ? 1 : 0;
366
+{
367
+ const TestData *td = test_data;
368
+ const EMCModule *mod = td->module;
369
+ QTestState *qts = qtest_init("-machine quanta-gsj");
370
+ int i;
371
+
372
+#define CHECK_REG(regno, value) \
373
+ do { \
374
+ g_assert_cmphex(emc_read(qts, mod, (regno)), ==, (value)); \
375
+ } while (0)
376
+
377
+ CHECK_REG(REG_CAMCMR, 0);
378
+ CHECK_REG(REG_CAMEN, 0);
379
+ CHECK_REG(REG_TXDLSA, 0xfffffffc);
380
+ CHECK_REG(REG_RXDLSA, 0xfffffffc);
381
+ CHECK_REG(REG_MCMDR, 0);
382
+ CHECK_REG(REG_MIID, 0);
383
+ CHECK_REG(REG_MIIDA, 0x00900000);
384
+ CHECK_REG(REG_FFTCR, 0x0101);
385
+ CHECK_REG(REG_DMARFC, 0x0800);
386
+ CHECK_REG(REG_MIEN, 0);
387
+ CHECK_REG(REG_MISTA, 0);
388
+ CHECK_REG(REG_MGSTA, 0);
389
+ CHECK_REG(REG_MPCNT, 0x7fff);
390
+ CHECK_REG(REG_MRPC, 0);
391
+ CHECK_REG(REG_MRPCC, 0);
392
+ CHECK_REG(REG_MREPC, 0);
393
+ CHECK_REG(REG_DMARFS, 0);
394
+ CHECK_REG(REG_CTXDSA, 0);
395
+ CHECK_REG(REG_CTXBSA, 0);
396
+ CHECK_REG(REG_CRXDSA, 0);
397
+ CHECK_REG(REG_CRXBSA, 0);
398
+
399
+#undef CHECK_REG
400
+
401
+ for (i = 0; i < NUM_CAMML_REGS; ++i) {
402
+ g_assert_cmpuint(emc_read(qts, mod, REG_CAMM_BASE + i * 2), ==,
403
+ 0);
404
+ g_assert_cmpuint(emc_read(qts, mod, REG_CAML_BASE + i * 2), ==,
405
+ 0);
406
+ }
60
+ }
407
+
61
+
408
+ qtest_quit(qts);
62
+ if (pickNaN(a_cls, b_cls, aIsLargerSignificand, status)) {
409
+}
63
+ if (is_snan(b_cls)) {
410
+
64
+ return floatx80_silence_nan(b, status);
411
+static bool emc_wait_irq(QTestState *qts, const EMCModule *mod, int step,
412
+ bool is_tx)
413
+{
414
+ uint64_t end_time =
415
+ g_get_monotonic_time() + TIMEOUT_SECONDS * G_TIME_SPAN_SECOND;
416
+
417
+ do {
418
+ if (qtest_get_irq(qts, is_tx ? mod->tx_irq : mod->rx_irq)) {
419
+ return true;
420
+ }
65
+ }
421
+ qtest_clock_step(qts, step);
66
+ return b;
422
+ } while (g_get_monotonic_time() < end_time);
67
+ } else {
423
+
68
+ if (is_snan(a_cls)) {
424
+ g_message("%s: Timeout expired", __func__);
69
+ return floatx80_silence_nan(a, status);
425
+ return false;
426
+}
427
+
428
+static bool emc_wait_mista(QTestState *qts, const EMCModule *mod, int step,
429
+ uint32_t flag)
430
+{
431
+ uint64_t end_time =
432
+ g_get_monotonic_time() + TIMEOUT_SECONDS * G_TIME_SPAN_SECOND;
433
+
434
+ do {
435
+ uint32_t mista = emc_read(qts, mod, REG_MISTA);
436
+ if (mista & flag) {
437
+ return true;
438
+ }
70
+ }
439
+ qtest_clock_step(qts, step);
71
+ return a;
440
+ } while (g_get_monotonic_time() < end_time);
441
+
442
+ g_message("%s: Timeout expired", __func__);
443
+ return false;
444
+}
445
+
446
+static bool wait_socket_readable(int fd)
447
+{
448
+ fd_set read_fds;
449
+ struct timeval tv;
450
+ int rv;
451
+
452
+ FD_ZERO(&read_fds);
453
+ FD_SET(fd, &read_fds);
454
+ tv.tv_sec = TIMEOUT_SECONDS;
455
+ tv.tv_usec = 0;
456
+ rv = select(fd + 1, &read_fds, NULL, NULL, &tv);
457
+ if (rv == -1) {
458
+ perror("select");
459
+ } else if (rv == 0) {
460
+ g_message("%s: Timeout expired", __func__);
461
+ }
462
+ return rv == 1;
463
+}
464
+
465
+/* Initialize *desc (in host endian format). */
466
+static void init_tx_desc(NPCM7xxEMCTxDesc *desc, size_t count,
467
+ uint32_t desc_addr)
468
+{
469
+ g_assert(count >= 2);
470
+ memset(&desc[0], 0, sizeof(*desc) * count);
471
+ /* Leave the last one alone, owned by the cpu -> stops transmission. */
472
+ for (size_t i = 0; i < count - 1; ++i) {
473
+ desc[i].flags =
474
+ (TX_DESC_FLAG_OWNER_MASK | /* owner = 1: emc */
475
+ TX_DESC_FLAG_INTEN |
476
+ 0 | /* crc append = 0 */
477
+ 0 /* padding enable = 0 */);
478
+ desc[i].status_and_length =
479
+ (0 | /* collision count = 0 */
480
+ 0 | /* SQE = 0 */
481
+ 0 | /* PAU = 0 */
482
+ 0 | /* TXHA = 0 */
483
+ 0 | /* LC = 0 */
484
+ 0 | /* TXABT = 0 */
485
+ 0 | /* NCS = 0 */
486
+ 0 | /* EXDEF = 0 */
487
+ 0 | /* TXCP = 0 */
488
+ 0 | /* DEF = 0 */
489
+ 0 | /* TXINTR = 0 */
490
+ 0 /* length filled in later */);
491
+ desc[i].ntxdsa = desc_addr + (i + 1) * sizeof(*desc);
492
+ }
72
+ }
493
+}
73
+}
494
+
74
+
495
+static void enable_tx(QTestState *qts, const EMCModule *mod,
75
/*----------------------------------------------------------------------------
496
+ const NPCM7xxEMCTxDesc *desc, size_t count,
76
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
497
+ uint32_t desc_addr, uint32_t mien_flags)
77
| and extended significand formed by the concatenation of `zSig0' and `zSig1',
498
+{
78
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
499
+ /* Write the descriptors to guest memory. */
500
+ for (size_t i = 0; i < count; ++i) {
501
+ emc_write_tx_desc(qts, desc + i, desc_addr + i * sizeof(*desc));
502
+ }
503
+
504
+ /* Trigger sending the packet. */
505
+ /* The module must be reset before changing TXDLSA. */
506
+ g_assert(emc_soft_reset(qts, mod));
507
+ emc_write(qts, mod, REG_TXDLSA, desc_addr);
508
+ emc_write(qts, mod, REG_CTXDSA, ~0);
509
+ emc_write(qts, mod, REG_MIEN, REG_MIEN_ENTXCP | mien_flags);
510
+ {
511
+ uint32_t mcmdr = emc_read(qts, mod, REG_MCMDR);
512
+ mcmdr |= REG_MCMDR_TXON;
513
+ emc_write(qts, mod, REG_MCMDR, mcmdr);
514
+ }
515
+
516
+ /* Prod the device to send the packet. */
517
+ emc_write(qts, mod, REG_TSDR, 1);
518
+}
519
+
520
+static void emc_send_verify1(QTestState *qts, const EMCModule *mod, int fd,
521
+ bool with_irq, uint32_t desc_addr,
522
+ uint32_t next_desc_addr,
523
+ const char *test_data, int test_size)
524
+{
525
+ NPCM7xxEMCTxDesc result_desc;
526
+ uint32_t expected_mask, expected_value, recv_len;
527
+ int ret;
528
+ char buffer[TX_DATA_LEN];
529
+
530
+ g_assert(wait_socket_readable(fd));
531
+
532
+ /* Read the descriptor back. */
533
+ emc_read_tx_desc(qts, desc_addr, &result_desc);
534
+ /* Descriptor should be owned by cpu now. */
535
+ g_assert((result_desc.flags & TX_DESC_FLAG_OWNER_MASK) == 0);
536
+ /* Test the status bits, ignoring the length field. */
537
+ expected_mask = 0xffff << 16;
538
+ expected_value = TX_DESC_STATUS_TXCP;
539
+ if (with_irq) {
540
+ expected_value |= TX_DESC_STATUS_TXINTR;
541
+ }
542
+ g_assert_cmphex((result_desc.status_and_length & expected_mask), ==,
543
+ expected_value);
544
+
545
+ /* Check data sent to the backend. */
546
+ recv_len = ~0;
547
+ ret = qemu_recv(fd, &recv_len, sizeof(recv_len), MSG_DONTWAIT);
548
+ g_assert_cmpint(ret, == , sizeof(recv_len));
549
+
550
+ g_assert(wait_socket_readable(fd));
551
+ memset(buffer, 0xff, sizeof(buffer));
552
+ ret = qemu_recv(fd, buffer, test_size, MSG_DONTWAIT);
553
+ g_assert_cmpmem(buffer, ret, test_data, test_size);
554
+}
555
+
556
+static void emc_send_verify(QTestState *qts, const EMCModule *mod, int fd,
557
+ bool with_irq)
558
+{
559
+ NPCM7xxEMCTxDesc desc[NUM_TX_DESCRIPTORS];
560
+ uint32_t desc_addr = DESC_ADDR;
561
+ static const char test1_data[] = "TEST1";
562
+ static const char test2_data[] = "Testing 1 2 3 ...";
563
+ uint32_t data1_addr = DATA_ADDR;
564
+ uint32_t data2_addr = data1_addr + sizeof(test1_data);
565
+ bool got_tdu;
566
+ uint32_t end_desc_addr;
567
+
568
+ /* Prepare test data buffer. */
569
+ qtest_memwrite(qts, data1_addr, test1_data, sizeof(test1_data));
570
+ qtest_memwrite(qts, data2_addr, test2_data, sizeof(test2_data));
571
+
572
+ init_tx_desc(&desc[0], NUM_TX_DESCRIPTORS, desc_addr);
573
+ desc[0].txbsa = data1_addr;
574
+ desc[0].status_and_length |= sizeof(test1_data);
575
+ desc[1].txbsa = data2_addr;
576
+ desc[1].status_and_length |= sizeof(test2_data);
577
+
578
+ enable_tx(qts, mod, &desc[0], NUM_TX_DESCRIPTORS, desc_addr,
579
+ with_irq ? REG_MIEN_ENTXINTR : 0);
580
+
581
+ /*
582
+ * It's problematic to observe the interrupt for each packet.
583
+ * Instead just wait until all the packets go out.
584
+ */
585
+ got_tdu = false;
586
+ while (!got_tdu) {
587
+ if (with_irq) {
588
+ g_assert_true(emc_wait_irq(qts, mod, TX_STEP_COUNT,
589
+ /*is_tx=*/true));
590
+ } else {
591
+ g_assert_true(emc_wait_mista(qts, mod, TX_STEP_COUNT,
592
+ REG_MISTA_TXINTR));
593
+ }
594
+ got_tdu = !!(emc_read(qts, mod, REG_MISTA) & REG_MISTA_TDU);
595
+ /* If we don't have TDU yet, reset the interrupt. */
596
+ if (!got_tdu) {
597
+ emc_write(qts, mod, REG_MISTA,
598
+ emc_read(qts, mod, REG_MISTA) & 0xffff0000);
599
+ }
600
+ }
601
+
602
+ end_desc_addr = desc_addr + 2 * sizeof(desc[0]);
603
+ g_assert_cmphex(emc_read(qts, mod, REG_CTXDSA), ==, end_desc_addr);
604
+ g_assert_cmphex(emc_read(qts, mod, REG_MISTA), ==,
605
+ REG_MISTA_TXCP | REG_MISTA_TXINTR | REG_MISTA_TDU);
606
+
607
+ emc_send_verify1(qts, mod, fd, with_irq,
608
+ desc_addr, end_desc_addr,
609
+ test1_data, sizeof(test1_data));
610
+ emc_send_verify1(qts, mod, fd, with_irq,
611
+ desc_addr + sizeof(desc[0]), end_desc_addr,
612
+ test2_data, sizeof(test2_data));
613
+}
614
+
615
+/* Initialize *desc (in host endian format). */
616
+static void init_rx_desc(NPCM7xxEMCRxDesc *desc, size_t count,
617
+ uint32_t desc_addr, uint32_t data_addr)
618
+{
619
+ g_assert_true(count >= 2);
620
+ memset(desc, 0, sizeof(*desc) * count);
621
+ desc[0].rxbsa = data_addr;
622
+ desc[0].status_and_length =
623
+ (0b10 << RX_DESC_STATUS_OWNER_SHIFT | /* owner = 10: emc */
624
+ 0 | /* RP = 0 */
625
+ 0 | /* ALIE = 0 */
626
+ 0 | /* RXGD = 0 */
627
+ 0 | /* PTLE = 0 */
628
+ 0 | /* CRCE = 0 */
629
+ 0 | /* RXINTR = 0 */
630
+ 0 /* length (filled in later) */);
631
+ /* Leave the last one alone, owned by the cpu -> stops transmission. */
632
+ desc[0].nrxdsa = desc_addr + sizeof(*desc);
633
+}
634
+
635
+static void enable_rx(QTestState *qts, const EMCModule *mod,
636
+ const NPCM7xxEMCRxDesc *desc, size_t count,
637
+ uint32_t desc_addr, uint32_t mien_flags,
638
+ uint32_t mcmdr_flags)
639
+{
640
+ /*
641
+ * Write the descriptor to guest memory.
642
+ * FWIW, IWBN if the docs said the buffer needs to be at least DMARFC
643
+ * bytes.
644
+ */
645
+ for (size_t i = 0; i < count; ++i) {
646
+ emc_write_rx_desc(qts, desc + i, desc_addr + i * sizeof(*desc));
647
+ }
648
+
649
+ /* Trigger receiving the packet. */
650
+ /* The module must be reset before changing RXDLSA. */
651
+ g_assert(emc_soft_reset(qts, mod));
652
+ emc_write(qts, mod, REG_RXDLSA, desc_addr);
653
+ emc_write(qts, mod, REG_MIEN, REG_MIEN_ENRXGD | mien_flags);
654
+
655
+ /*
656
+ * We don't know what the device's macaddr is, so just accept all
657
+ * unicast packets (AUP).
658
+ */
659
+ emc_write(qts, mod, REG_CAMCMR, REG_CAMCMR_AUP);
660
+ emc_write(qts, mod, REG_CAMEN, 1 << 0);
661
+ {
662
+ uint32_t mcmdr = emc_read(qts, mod, REG_MCMDR);
663
+ mcmdr |= REG_MCMDR_RXON | mcmdr_flags;
664
+ emc_write(qts, mod, REG_MCMDR, mcmdr);
665
+ }
666
+
667
+ /* Prod the device to accept a packet. */
668
+ emc_write(qts, mod, REG_RSDR, 1);
669
+}
670
+
671
+static void emc_recv_verify(QTestState *qts, const EMCModule *mod, int fd,
672
+ bool with_irq)
673
+{
674
+ NPCM7xxEMCRxDesc desc[NUM_RX_DESCRIPTORS];
675
+ uint32_t desc_addr = DESC_ADDR;
676
+ uint32_t data_addr = DATA_ADDR;
677
+ int ret;
678
+ uint32_t expected_mask, expected_value;
679
+ NPCM7xxEMCRxDesc result_desc;
680
+
681
+ /* Prepare test data buffer. */
682
+ const char test[RX_DATA_LEN] = "TEST";
683
+ int len = htonl(sizeof(test));
684
+ const struct iovec iov[] = {
685
+ {
686
+ .iov_base = &len,
687
+ .iov_len = sizeof(len),
688
+ },{
689
+ .iov_base = (char *) test,
690
+ .iov_len = sizeof(test),
691
+ },
692
+ };
693
+
694
+ /*
695
+ * Reset the device BEFORE sending a test packet, otherwise the packet
696
+ * may get swallowed by an active device of an earlier test.
697
+ */
698
+ init_rx_desc(&desc[0], NUM_RX_DESCRIPTORS, desc_addr, data_addr);
699
+ enable_rx(qts, mod, &desc[0], NUM_RX_DESCRIPTORS, desc_addr,
700
+ with_irq ? REG_MIEN_ENRXINTR : 0, 0);
701
+
702
+ /* Send test packet to device's socket. */
703
+ ret = iov_send(fd, iov, 2, 0, sizeof(len) + sizeof(test));
704
+ g_assert_cmpint(ret, == , sizeof(test) + sizeof(len));
705
+
706
+ /* Wait for RX interrupt. */
707
+ if (with_irq) {
708
+ g_assert_true(emc_wait_irq(qts, mod, RX_STEP_COUNT, /*is_tx=*/false));
709
+ } else {
710
+ g_assert_true(emc_wait_mista(qts, mod, RX_STEP_COUNT, REG_MISTA_RXGD));
711
+ }
712
+
713
+ g_assert_cmphex(emc_read(qts, mod, REG_CRXDSA), ==,
714
+ desc_addr + sizeof(desc[0]));
715
+
716
+ expected_mask = 0xffff;
717
+ expected_value = (REG_MISTA_DENI |
718
+ REG_MISTA_RXGD |
719
+ REG_MISTA_RXINTR);
720
+ g_assert_cmphex((emc_read(qts, mod, REG_MISTA) & expected_mask),
721
+ ==, expected_value);
722
+
723
+ /* Read the descriptor back. */
724
+ emc_read_rx_desc(qts, desc_addr, &result_desc);
725
+ /* Descriptor should be owned by cpu now. */
726
+ g_assert((result_desc.status_and_length & RX_DESC_STATUS_OWNER_MASK) == 0);
727
+ /* Test the status bits, ignoring the length field. */
728
+ expected_mask = 0xffff << 16;
729
+ expected_value = RX_DESC_STATUS_RXGD;
730
+ if (with_irq) {
731
+ expected_value |= RX_DESC_STATUS_RXINTR;
732
+ }
733
+ g_assert_cmphex((result_desc.status_and_length & expected_mask), ==,
734
+ expected_value);
735
+ g_assert_cmpint(RX_DESC_PKT_LEN(result_desc.status_and_length), ==,
736
+ RX_DATA_LEN + CRC_LENGTH);
737
+
738
+ {
739
+ char buffer[RX_DATA_LEN];
740
+ qtest_memread(qts, data_addr, buffer, sizeof(buffer));
741
+ g_assert_cmpstr(buffer, == , "TEST");
742
+ }
743
+}
744
+
745
+static void emc_test_ptle(QTestState *qts, const EMCModule *mod, int fd)
746
+{
747
+ NPCM7xxEMCRxDesc desc[NUM_RX_DESCRIPTORS];
748
+ uint32_t desc_addr = DESC_ADDR;
749
+ uint32_t data_addr = DATA_ADDR;
750
+ int ret;
751
+ NPCM7xxEMCRxDesc result_desc;
752
+ uint32_t expected_mask, expected_value;
753
+
754
+ /* Prepare test data buffer. */
755
+#define PTLE_DATA_LEN 1600
756
+ char test_data[PTLE_DATA_LEN];
757
+ int len = htonl(sizeof(test_data));
758
+ const struct iovec iov[] = {
759
+ {
760
+ .iov_base = &len,
761
+ .iov_len = sizeof(len),
762
+ },{
763
+ .iov_base = (char *) test_data,
764
+ .iov_len = sizeof(test_data),
765
+ },
766
+ };
767
+ memset(test_data, 42, sizeof(test_data));
768
+
769
+ /*
770
+ * Reset the device BEFORE sending a test packet, otherwise the packet
771
+ * may get swallowed by an active device of an earlier test.
772
+ */
773
+ init_rx_desc(&desc[0], NUM_RX_DESCRIPTORS, desc_addr, data_addr);
774
+ enable_rx(qts, mod, &desc[0], NUM_RX_DESCRIPTORS, desc_addr,
775
+ REG_MIEN_ENRXINTR, REG_MCMDR_ALP);
776
+
777
+ /* Send test packet to device's socket. */
778
+ ret = iov_send(fd, iov, 2, 0, sizeof(len) + sizeof(test_data));
779
+ g_assert_cmpint(ret, == , sizeof(test_data) + sizeof(len));
780
+
781
+ /* Wait for RX interrupt. */
782
+ g_assert_true(emc_wait_irq(qts, mod, RX_STEP_COUNT, /*is_tx=*/false));
783
+
784
+ /* Read the descriptor back. */
785
+ emc_read_rx_desc(qts, desc_addr, &result_desc);
786
+ /* Descriptor should be owned by cpu now. */
787
+ g_assert((result_desc.status_and_length & RX_DESC_STATUS_OWNER_MASK) == 0);
788
+ /* Test the status bits, ignoring the length field. */
789
+ expected_mask = 0xffff << 16;
790
+ expected_value = (RX_DESC_STATUS_RXGD |
791
+ RX_DESC_STATUS_PTLE |
792
+ RX_DESC_STATUS_RXINTR);
793
+ g_assert_cmphex((result_desc.status_and_length & expected_mask), ==,
794
+ expected_value);
795
+ g_assert_cmpint(RX_DESC_PKT_LEN(result_desc.status_and_length), ==,
796
+ PTLE_DATA_LEN + CRC_LENGTH);
797
+
798
+ {
799
+ char buffer[PTLE_DATA_LEN];
800
+ qtest_memread(qts, data_addr, buffer, sizeof(buffer));
801
+ g_assert(memcmp(buffer, test_data, PTLE_DATA_LEN) == 0);
802
+ }
803
+}
804
+
805
+static void test_tx(gconstpointer test_data)
806
+{
807
+ const TestData *td = test_data;
808
+ GString *cmd_line = g_string_new("-machine quanta-gsj");
809
+ int *test_sockets = packet_test_init(emc_module_index(td->module),
810
+ cmd_line);
811
+ QTestState *qts = qtest_init(cmd_line->str);
812
+
813
+ /*
814
+ * TODO: For pedantic correctness test_sockets[0] should be closed after
815
+ * the fork and before the exec, but that will require some harness
816
+ * improvements.
817
+ */
818
+ close(test_sockets[1]);
819
+ /* Defensive programming */
820
+ test_sockets[1] = -1;
821
+
822
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
823
+
824
+ emc_send_verify(qts, td->module, test_sockets[0], /*with_irq=*/false);
825
+ emc_send_verify(qts, td->module, test_sockets[0], /*with_irq=*/true);
826
+
827
+ qtest_quit(qts);
828
+}
829
+
830
+static void test_rx(gconstpointer test_data)
831
+{
832
+ const TestData *td = test_data;
833
+ GString *cmd_line = g_string_new("-machine quanta-gsj");
834
+ int *test_sockets = packet_test_init(emc_module_index(td->module),
835
+ cmd_line);
836
+ QTestState *qts = qtest_init(cmd_line->str);
837
+
838
+ /*
839
+ * TODO: For pedantic correctness test_sockets[0] should be closed after
840
+ * the fork and before the exec, but that will require some harness
841
+ * improvements.
842
+ */
843
+ close(test_sockets[1]);
844
+ /* Defensive programming */
845
+ test_sockets[1] = -1;
846
+
847
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
848
+
849
+ emc_recv_verify(qts, td->module, test_sockets[0], /*with_irq=*/false);
850
+ emc_recv_verify(qts, td->module, test_sockets[0], /*with_irq=*/true);
851
+ emc_test_ptle(qts, td->module, test_sockets[0]);
852
+
853
+ qtest_quit(qts);
854
+}
855
+
856
+static void emc_add_test(const char *name, const TestData* td,
857
+ GTestDataFunc fn)
858
+{
859
+ g_autofree char *full_name = g_strdup_printf(
860
+ "npcm7xx_emc/emc[%d]/%s", emc_module_index(td->module), name);
861
+ qtest_add_data_func(full_name, td, fn);
862
+}
863
+#define add_test(name, td) emc_add_test(#name, td, test_##name)
864
+
865
+int main(int argc, char **argv)
866
+{
867
+ TestData test_data_list[ARRAY_SIZE(emc_module_list)];
868
+
869
+ g_test_init(&argc, &argv, NULL);
870
+
871
+ for (int i = 0; i < ARRAY_SIZE(emc_module_list); ++i) {
872
+ TestData *td = &test_data_list[i];
873
+
874
+ td->module = &emc_module_list[i];
875
+
876
+ add_test(init, td);
877
+ add_test(tx, td);
878
+ add_test(rx, td);
879
+ }
880
+
881
+ return g_test_run();
882
+}
883
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
884
index XXXXXXX..XXXXXXX 100644
79
index XXXXXXX..XXXXXXX 100644
885
--- a/tests/qtest/meson.build
80
--- a/fpu/softfloat-specialize.c.inc
886
+++ b/tests/qtest/meson.build
81
+++ b/fpu/softfloat-specialize.c.inc
887
@@ -XXX,XX +XXX,XX @@ qtests_sparc64 = \
82
@@ -XXX,XX +XXX,XX @@ floatx80 floatx80_silence_nan(floatx80 a, float_status *status)
888
83
return a;
889
qtests_npcm7xx = \
84
}
890
['npcm7xx_adc-test',
85
891
+ 'npcm7xx_emc-test',
86
-/*----------------------------------------------------------------------------
892
'npcm7xx_gpio-test',
87
-| Takes two extended double-precision floating-point values `a' and `b', one
893
'npcm7xx_pwm-test',
88
-| of which is a NaN, and returns the appropriate NaN result. If either `a' or
894
'npcm7xx_rng-test',
89
-| `b' is a signaling NaN, the invalid exception is raised.
90
-*----------------------------------------------------------------------------*/
91
-
92
-floatx80 propagateFloatx80NaN(floatx80 a, floatx80 b, float_status *status)
93
-{
94
- bool aIsLargerSignificand;
95
- FloatClass a_cls, b_cls;
96
-
97
- /* This is not complete, but is good enough for pickNaN. */
98
- a_cls = (!floatx80_is_any_nan(a)
99
- ? float_class_normal
100
- : floatx80_is_signaling_nan(a, status)
101
- ? float_class_snan
102
- : float_class_qnan);
103
- b_cls = (!floatx80_is_any_nan(b)
104
- ? float_class_normal
105
- : floatx80_is_signaling_nan(b, status)
106
- ? float_class_snan
107
- : float_class_qnan);
108
-
109
- if (is_snan(a_cls) || is_snan(b_cls)) {
110
- float_raise(float_flag_invalid, status);
111
- }
112
-
113
- if (status->default_nan_mode) {
114
- return floatx80_default_nan(status);
115
- }
116
-
117
- if (a.low < b.low) {
118
- aIsLargerSignificand = 0;
119
- } else if (b.low < a.low) {
120
- aIsLargerSignificand = 1;
121
- } else {
122
- aIsLargerSignificand = (a.high < b.high) ? 1 : 0;
123
- }
124
-
125
- if (pickNaN(a_cls, b_cls, aIsLargerSignificand, status)) {
126
- if (is_snan(b_cls)) {
127
- return floatx80_silence_nan(b, status);
128
- }
129
- return b;
130
- } else {
131
- if (is_snan(a_cls)) {
132
- return floatx80_silence_nan(a, status);
133
- }
134
- return a;
135
- }
136
-}
137
-
138
/*----------------------------------------------------------------------------
139
| Returns 1 if the quadruple-precision floating-point value `a' is a quiet
140
| NaN; otherwise returns 0.
895
--
141
--
896
2.20.1
142
2.34.1
897
898
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
Verify that addr + size - 1 does not wrap around.
3
Unpacking and repacking the parts may be slightly more work
4
than we did before, but we get to reuse more code. For a
5
code path handling exceptional values, this is an improvement.
4
6
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20241203203949.483774-8-richard.henderson@linaro.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20210212184902.1251044-7-richard.henderson@linaro.org
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
11
---
10
linux-user/qemu.h | 17 ++++++++++++-----
12
fpu/softfloat.c | 43 +++++--------------------------------------
11
1 file changed, 12 insertions(+), 5 deletions(-)
13
1 file changed, 5 insertions(+), 38 deletions(-)
12
14
13
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
15
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
14
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
15
--- a/linux-user/qemu.h
17
--- a/fpu/softfloat.c
16
+++ b/linux-user/qemu.h
18
+++ b/fpu/softfloat.c
17
@@ -XXX,XX +XXX,XX @@ extern unsigned long guest_stack_size;
19
@@ -XXX,XX +XXX,XX @@ void normalizeFloatx80Subnormal(uint64_t aSig, int32_t *zExpPtr,
18
#define VERIFY_READ 0
20
19
#define VERIFY_WRITE 1 /* implies read access */
21
floatx80 propagateFloatx80NaN(floatx80 a, floatx80 b, float_status *status)
20
21
-static inline int access_ok(int type, abi_ulong addr, abi_ulong size)
22
+static inline bool access_ok(int type, abi_ulong addr, abi_ulong size)
23
{
22
{
24
- return guest_addr_valid(addr) &&
23
- bool aIsLargerSignificand;
25
- (size == 0 || guest_addr_valid(addr + size - 1)) &&
24
- FloatClass a_cls, b_cls;
26
- page_check_range((target_ulong)addr, size,
25
+ FloatParts128 pa, pb, *pr;
27
- (type == VERIFY_READ) ? PAGE_READ : (PAGE_READ | PAGE_WRITE)) == 0;
26
28
+ if (!guest_addr_valid(addr)) {
27
- /* This is not complete, but is good enough for pickNaN. */
29
+ return false;
28
- a_cls = (!floatx80_is_any_nan(a)
30
+ }
29
- ? float_class_normal
31
+ if (size != 0 &&
30
- : floatx80_is_signaling_nan(a, status)
32
+ (addr + size - 1 < addr ||
31
- ? float_class_snan
33
+ !guest_addr_valid(addr + size - 1))) {
32
- : float_class_qnan);
34
+ return false;
33
- b_cls = (!floatx80_is_any_nan(b)
35
+ }
34
- ? float_class_normal
36
+ return page_check_range((target_ulong)addr, size,
35
- : floatx80_is_signaling_nan(b, status)
37
+ (type == VERIFY_READ) ? PAGE_READ :
36
- ? float_class_snan
38
+ (PAGE_READ | PAGE_WRITE)) == 0;
37
- : float_class_qnan);
38
-
39
- if (is_snan(a_cls) || is_snan(b_cls)) {
40
- float_raise(float_flag_invalid, status);
41
- }
42
-
43
- if (status->default_nan_mode) {
44
+ if (!floatx80_unpack_canonical(&pa, a, status) ||
45
+ !floatx80_unpack_canonical(&pb, b, status)) {
46
return floatx80_default_nan(status);
47
}
48
49
- if (a.low < b.low) {
50
- aIsLargerSignificand = 0;
51
- } else if (b.low < a.low) {
52
- aIsLargerSignificand = 1;
53
- } else {
54
- aIsLargerSignificand = (a.high < b.high) ? 1 : 0;
55
- }
56
-
57
- if (pickNaN(a_cls, b_cls, aIsLargerSignificand, status)) {
58
- if (is_snan(b_cls)) {
59
- return floatx80_silence_nan(b, status);
60
- }
61
- return b;
62
- } else {
63
- if (is_snan(a_cls)) {
64
- return floatx80_silence_nan(a, status);
65
- }
66
- return a;
67
- }
68
+ pr = parts_pick_nan(&pa, &pb, status);
69
+ return floatx80_round_pack_canonical(pr, status);
39
}
70
}
40
71
41
/* NOTE __get_user and __put_user use host pointers and don't check access.
72
/*----------------------------------------------------------------------------
42
--
73
--
43
2.20.1
74
2.34.1
44
45
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
Use the now-saved PAGE_ANON and PAGE_MTE bits,
3
Inline pickNaN into its only caller. This makes one assert
4
and the per-page saved data.
4
redundant with the immediately preceding IF.
5
5
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20210212184902.1251044-30-richard.henderson@linaro.org
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
8
Message-id: 20241203203949.483774-9-richard.henderson@linaro.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
10
---
11
target/arm/mte_helper.c | 29 +++++++++++++++++++++++++++--
11
fpu/softfloat-parts.c.inc | 82 +++++++++++++++++++++++++----
12
1 file changed, 27 insertions(+), 2 deletions(-)
12
fpu/softfloat-specialize.c.inc | 96 ----------------------------------
13
13
2 files changed, 73 insertions(+), 105 deletions(-)
14
diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c
14
15
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
15
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
16
--- a/target/arm/mte_helper.c
17
--- a/fpu/softfloat-parts.c.inc
17
+++ b/target/arm/mte_helper.c
18
+++ b/fpu/softfloat-parts.c.inc
18
@@ -XXX,XX +XXX,XX @@ static uint8_t *allocation_tag_mem(CPUARMState *env, int ptr_mmu_idx,
19
@@ -XXX,XX +XXX,XX @@ static void partsN(return_nan)(FloatPartsN *a, float_status *s)
19
int tag_size, uintptr_t ra)
20
static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b,
21
float_status *s)
20
{
22
{
21
#ifdef CONFIG_USER_ONLY
23
+ int cmp, which;
22
- /* Tag storage not implemented. */
23
- return NULL;
24
+ uint64_t clean_ptr = useronly_clean_ptr(ptr);
25
+ int flags = page_get_flags(clean_ptr);
26
+ uint8_t *tags;
27
+ uintptr_t index;
28
+
24
+
29
+ if (!(flags & (ptr_access == MMU_DATA_STORE ? PAGE_WRITE : PAGE_READ))) {
25
if (is_snan(a->cls) || is_snan(b->cls)) {
30
+ /* SIGSEGV */
26
float_raise(float_flag_invalid | float_flag_invalid_snan, s);
31
+ arm_cpu_tlb_fill(env_cpu(env), ptr, ptr_size, ptr_access,
27
}
32
+ ptr_mmu_idx, false, ra);
28
29
if (s->default_nan_mode) {
30
parts_default_nan(a, s);
31
- } else {
32
- int cmp = frac_cmp(a, b);
33
- if (cmp == 0) {
34
- cmp = a->sign < b->sign;
35
- }
36
+ return a;
37
+ }
38
39
- if (pickNaN(a->cls, b->cls, cmp > 0, s)) {
40
- a = b;
41
- }
42
+ cmp = frac_cmp(a, b);
43
+ if (cmp == 0) {
44
+ cmp = a->sign < b->sign;
45
+ }
46
+
47
+ switch (s->float_2nan_prop_rule) {
48
+ case float_2nan_prop_s_ab:
49
if (is_snan(a->cls)) {
50
- parts_silence_nan(a, s);
51
+ which = 0;
52
+ } else if (is_snan(b->cls)) {
53
+ which = 1;
54
+ } else if (is_qnan(a->cls)) {
55
+ which = 0;
56
+ } else {
57
+ which = 1;
58
}
59
+ break;
60
+ case float_2nan_prop_s_ba:
61
+ if (is_snan(b->cls)) {
62
+ which = 1;
63
+ } else if (is_snan(a->cls)) {
64
+ which = 0;
65
+ } else if (is_qnan(b->cls)) {
66
+ which = 1;
67
+ } else {
68
+ which = 0;
69
+ }
70
+ break;
71
+ case float_2nan_prop_ab:
72
+ which = is_nan(a->cls) ? 0 : 1;
73
+ break;
74
+ case float_2nan_prop_ba:
75
+ which = is_nan(b->cls) ? 1 : 0;
76
+ break;
77
+ case float_2nan_prop_x87:
78
+ /*
79
+ * This implements x87 NaN propagation rules:
80
+ * SNaN + QNaN => return the QNaN
81
+ * two SNaNs => return the one with the larger significand, silenced
82
+ * two QNaNs => return the one with the larger significand
83
+ * SNaN and a non-NaN => return the SNaN, silenced
84
+ * QNaN and a non-NaN => return the QNaN
85
+ *
86
+ * If we get down to comparing significands and they are the same,
87
+ * return the NaN with the positive sign bit (if any).
88
+ */
89
+ if (is_snan(a->cls)) {
90
+ if (is_snan(b->cls)) {
91
+ which = cmp > 0 ? 0 : 1;
92
+ } else {
93
+ which = is_qnan(b->cls) ? 1 : 0;
94
+ }
95
+ } else if (is_qnan(a->cls)) {
96
+ if (is_snan(b->cls) || !is_qnan(b->cls)) {
97
+ which = 0;
98
+ } else {
99
+ which = cmp > 0 ? 0 : 1;
100
+ }
101
+ } else {
102
+ which = 1;
103
+ }
104
+ break;
105
+ default:
33
+ g_assert_not_reached();
106
+ g_assert_not_reached();
34
+ }
107
+ }
35
+
108
+
36
+ /* Require both MAP_ANON and PROT_MTE for the page. */
109
+ if (which) {
37
+ if (!(flags & PAGE_ANON) || !(flags & PAGE_MTE)) {
110
+ a = b;
38
+ return NULL;
111
+ }
39
+ }
112
+ if (is_snan(a->cls)) {
40
+
113
+ parts_silence_nan(a, s);
41
+ tags = page_get_target_data(clean_ptr);
114
}
42
+ if (tags == NULL) {
115
return a;
43
+ size_t alloc_size = TARGET_PAGE_SIZE >> (LOG2_TAG_GRANULE + 1);
116
}
44
+ tags = page_alloc_target_data(clean_ptr, alloc_size);
117
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
45
+ assert(tags != NULL);
118
index XXXXXXX..XXXXXXX 100644
46
+ }
119
--- a/fpu/softfloat-specialize.c.inc
47
+
120
+++ b/fpu/softfloat-specialize.c.inc
48
+ index = extract32(ptr, LOG2_TAG_GRANULE + 1,
121
@@ -XXX,XX +XXX,XX @@ bool float32_is_signaling_nan(float32 a_, float_status *status)
49
+ TARGET_PAGE_BITS - LOG2_TAG_GRANULE - 1);
122
}
50
+ return tags + index;
123
}
51
#else
124
52
uintptr_t index;
125
-/*----------------------------------------------------------------------------
53
CPUIOTLBEntry *iotlbentry;
126
-| Select which NaN to propagate for a two-input operation.
127
-| IEEE754 doesn't specify all the details of this, so the
128
-| algorithm is target-specific.
129
-| The routine is passed various bits of information about the
130
-| two NaNs and should return 0 to select NaN a and 1 for NaN b.
131
-| Note that signalling NaNs are always squashed to quiet NaNs
132
-| by the caller, by calling floatXX_silence_nan() before
133
-| returning them.
134
-|
135
-| aIsLargerSignificand is only valid if both a and b are NaNs
136
-| of some kind, and is true if a has the larger significand,
137
-| or if both a and b have the same significand but a is
138
-| positive but b is negative. It is only needed for the x87
139
-| tie-break rule.
140
-*----------------------------------------------------------------------------*/
141
-
142
-static int pickNaN(FloatClass a_cls, FloatClass b_cls,
143
- bool aIsLargerSignificand, float_status *status)
144
-{
145
- /*
146
- * We guarantee not to require the target to tell us how to
147
- * pick a NaN if we're always returning the default NaN.
148
- * But if we're not in default-NaN mode then the target must
149
- * specify via set_float_2nan_prop_rule().
150
- */
151
- assert(!status->default_nan_mode);
152
-
153
- switch (status->float_2nan_prop_rule) {
154
- case float_2nan_prop_s_ab:
155
- if (is_snan(a_cls)) {
156
- return 0;
157
- } else if (is_snan(b_cls)) {
158
- return 1;
159
- } else if (is_qnan(a_cls)) {
160
- return 0;
161
- } else {
162
- return 1;
163
- }
164
- break;
165
- case float_2nan_prop_s_ba:
166
- if (is_snan(b_cls)) {
167
- return 1;
168
- } else if (is_snan(a_cls)) {
169
- return 0;
170
- } else if (is_qnan(b_cls)) {
171
- return 1;
172
- } else {
173
- return 0;
174
- }
175
- break;
176
- case float_2nan_prop_ab:
177
- if (is_nan(a_cls)) {
178
- return 0;
179
- } else {
180
- return 1;
181
- }
182
- break;
183
- case float_2nan_prop_ba:
184
- if (is_nan(b_cls)) {
185
- return 1;
186
- } else {
187
- return 0;
188
- }
189
- break;
190
- case float_2nan_prop_x87:
191
- /*
192
- * This implements x87 NaN propagation rules:
193
- * SNaN + QNaN => return the QNaN
194
- * two SNaNs => return the one with the larger significand, silenced
195
- * two QNaNs => return the one with the larger significand
196
- * SNaN and a non-NaN => return the SNaN, silenced
197
- * QNaN and a non-NaN => return the QNaN
198
- *
199
- * If we get down to comparing significands and they are the same,
200
- * return the NaN with the positive sign bit (if any).
201
- */
202
- if (is_snan(a_cls)) {
203
- if (is_snan(b_cls)) {
204
- return aIsLargerSignificand ? 0 : 1;
205
- }
206
- return is_qnan(b_cls) ? 1 : 0;
207
- } else if (is_qnan(a_cls)) {
208
- if (is_snan(b_cls) || !is_qnan(b_cls)) {
209
- return 0;
210
- } else {
211
- return aIsLargerSignificand ? 0 : 1;
212
- }
213
- } else {
214
- return 1;
215
- }
216
- default:
217
- g_assert_not_reached();
218
- }
219
-}
220
-
221
/*----------------------------------------------------------------------------
222
| Returns 1 if the double-precision floating-point value `a' is a quiet
223
| NaN; otherwise returns 0.
54
--
224
--
55
2.20.1
225
2.34.1
56
226
57
227
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
We define target_mmap et al as untagged, so that they can be
3
Remember if there was an SNaN, and use that to simplify
4
used from the binary loaders. Explicitly call cpu_untagged_addr
4
float_2nan_prop_s_{ab,ba} to only the snan component.
5
for munmap, mprotect, mremap syscall entry points.
5
Then, fall through to the corresponding
6
float_2nan_prop_{ab,ba} case to handle any remaining
7
nans, which must be quiet.
6
8
7
Add a few comments for the syscalls that are exempted by the
9
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
kernel's tagged-address-abi.rst.
9
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
11
Message-id: 20241203203949.483774-10-richard.henderson@linaro.org
12
Message-id: 20210212184902.1251044-14-richard.henderson@linaro.org
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
---
13
---
15
linux-user/syscall.c | 11 +++++++++++
14
fpu/softfloat-parts.c.inc | 32 ++++++++++++--------------------
16
1 file changed, 11 insertions(+)
15
1 file changed, 12 insertions(+), 20 deletions(-)
17
16
18
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
17
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
19
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
20
--- a/linux-user/syscall.c
19
--- a/fpu/softfloat-parts.c.inc
21
+++ b/linux-user/syscall.c
20
+++ b/fpu/softfloat-parts.c.inc
22
@@ -XXX,XX +XXX,XX @@ abi_long do_brk(abi_ulong new_brk)
21
@@ -XXX,XX +XXX,XX @@ static void partsN(return_nan)(FloatPartsN *a, float_status *s)
23
abi_long mapped_addr;
22
static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b,
24
abi_ulong new_alloc_size;
23
float_status *s)
25
24
{
26
+ /* brk pointers are always untagged */
25
+ bool have_snan = false;
27
+
26
int cmp, which;
28
DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);
27
29
28
if (is_snan(a->cls) || is_snan(b->cls)) {
30
if (!new_brk) {
29
float_raise(float_flag_invalid | float_flag_invalid_snan, s);
31
@@ -XXX,XX +XXX,XX @@ static inline abi_ulong do_shmat(CPUArchState *cpu_env,
30
+ have_snan = true;
32
int i,ret;
31
}
33
abi_ulong shmlba;
32
34
33
if (s->default_nan_mode) {
35
+ /* shmat pointers are always untagged */
34
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b,
36
+
35
37
/* find out the length of the shared memory segment */
36
switch (s->float_2nan_prop_rule) {
38
ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
37
case float_2nan_prop_s_ab:
39
if (is_error(ret)) {
38
- if (is_snan(a->cls)) {
40
@@ -XXX,XX +XXX,XX @@ static inline abi_long do_shmdt(abi_ulong shmaddr)
39
- which = 0;
41
int i;
40
- } else if (is_snan(b->cls)) {
42
abi_long rv;
41
- which = 1;
43
42
- } else if (is_qnan(a->cls)) {
44
+ /* shmdt pointers are always untagged */
43
- which = 0;
45
+
44
- } else {
46
mmap_lock();
45
- which = 1;
47
46
+ if (have_snan) {
48
for (i = 0; i < N_SHM_REGIONS; ++i) {
47
+ which = is_snan(a->cls) ? 0 : 1;
49
@@ -XXX,XX +XXX,XX @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
48
+ break;
50
v5, v6));
51
}
49
}
52
#else
50
- break;
53
+ /* mmap pointers are always untagged */
51
- case float_2nan_prop_s_ba:
54
ret = get_errno(target_mmap(arg1, arg2, arg3,
52
- if (is_snan(b->cls)) {
55
target_to_host_bitmask(arg4, mmap_flags_tbl),
53
- which = 1;
56
arg5,
54
- } else if (is_snan(a->cls)) {
57
@@ -XXX,XX +XXX,XX @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
55
- which = 0;
58
return get_errno(ret);
56
- } else if (is_qnan(b->cls)) {
59
#endif
57
- which = 1;
60
case TARGET_NR_munmap:
58
- } else {
61
+ arg1 = cpu_untagged_addr(cpu, arg1);
59
- which = 0;
62
return get_errno(target_munmap(arg1, arg2));
60
- }
63
case TARGET_NR_mprotect:
61
- break;
64
+ arg1 = cpu_untagged_addr(cpu, arg1);
62
+ /* fall through */
65
{
63
case float_2nan_prop_ab:
66
TaskState *ts = cpu->opaque;
64
which = is_nan(a->cls) ? 0 : 1;
67
/* Special hack to detect libc making the stack executable. */
65
break;
68
@@ -XXX,XX +XXX,XX @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
66
+ case float_2nan_prop_s_ba:
69
return get_errno(target_mprotect(arg1, arg2, arg3));
67
+ if (have_snan) {
70
#ifdef TARGET_NR_mremap
68
+ which = is_snan(b->cls) ? 1 : 0;
71
case TARGET_NR_mremap:
69
+ break;
72
+ arg1 = cpu_untagged_addr(cpu, arg1);
70
+ }
73
+ /* mremap new_addr (arg5) is always untagged */
71
+ /* fall through */
74
return get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
72
case float_2nan_prop_ba:
75
#endif
73
which = is_nan(b->cls) ? 1 : 0;
76
/* ??? msync/mlock/munlock are broken for softmmu. */
74
break;
77
--
75
--
78
2.20.1
76
2.34.1
79
80
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
We must always use GUEST_ADDR_MAX, because even 32-bit hosts can
3
Move the fractional comparison to the end of the
4
use -R <reserved_va> to restrict the memory address of the guest.
4
float_2nan_prop_x87 case. This is not required for
5
any other 2nan propagation rule. Reorganize the
6
x87 case itself to break out of the switch when the
7
fractional comparison is not required.
5
8
9
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
11
Message-id: 20241203203949.483774-11-richard.henderson@linaro.org
8
Message-id: 20210212184902.1251044-11-richard.henderson@linaro.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
13
---
11
include/exec/cpu_ldst.h | 9 ++++-----
14
fpu/softfloat-parts.c.inc | 19 +++++++++----------
12
1 file changed, 4 insertions(+), 5 deletions(-)
15
1 file changed, 9 insertions(+), 10 deletions(-)
13
16
14
diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h
17
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
15
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
16
--- a/include/exec/cpu_ldst.h
19
--- a/fpu/softfloat-parts.c.inc
17
+++ b/include/exec/cpu_ldst.h
20
+++ b/fpu/softfloat-parts.c.inc
18
@@ -XXX,XX +XXX,XX @@ typedef uint64_t abi_ptr;
21
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b,
19
/* All direct uses of g2h and h2g need to go away for usermode softmmu. */
22
return a;
20
#define g2h(x) ((void *)((uintptr_t)(abi_ptr)(x) + guest_base))
23
}
21
24
22
-#if HOST_LONG_BITS <= TARGET_VIRT_ADDR_SPACE_BITS
25
- cmp = frac_cmp(a, b);
23
-#define guest_addr_valid(x) (1)
26
- if (cmp == 0) {
24
-#else
27
- cmp = a->sign < b->sign;
25
-#define guest_addr_valid(x) ((x) <= GUEST_ADDR_MAX)
28
- }
26
-#endif
29
-
27
+static inline bool guest_addr_valid(abi_ulong x)
30
switch (s->float_2nan_prop_rule) {
28
+{
31
case float_2nan_prop_s_ab:
29
+ return x <= GUEST_ADDR_MAX;
32
if (have_snan) {
30
+}
33
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b,
31
34
* return the NaN with the positive sign bit (if any).
32
static inline bool guest_range_valid(abi_ulong start, abi_ulong len)
35
*/
33
{
36
if (is_snan(a->cls)) {
37
- if (is_snan(b->cls)) {
38
- which = cmp > 0 ? 0 : 1;
39
- } else {
40
+ if (!is_snan(b->cls)) {
41
which = is_qnan(b->cls) ? 1 : 0;
42
+ break;
43
}
44
} else if (is_qnan(a->cls)) {
45
if (is_snan(b->cls) || !is_qnan(b->cls)) {
46
which = 0;
47
- } else {
48
- which = cmp > 0 ? 0 : 1;
49
+ break;
50
}
51
} else {
52
which = 1;
53
+ break;
54
}
55
+ cmp = frac_cmp(a, b);
56
+ if (cmp == 0) {
57
+ cmp = a->sign < b->sign;
58
+ }
59
+ which = cmp > 0 ? 0 : 1;
60
break;
61
default:
62
g_assert_not_reached();
34
--
63
--
35
2.20.1
64
2.34.1
36
37
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
The places that use these are better off using untagged
3
Replace the "index" selecting between A and B with a result variable
4
addresses, so do not provide a tagged versions. Rename
4
of the proper type. This improves clarity within the function.
5
to make it clear about the address type.
6
5
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
9
Message-id: 20210212184902.1251044-16-richard.henderson@linaro.org
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
8
Message-id: 20241203203949.483774-12-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
include/exec/cpu_ldst.h | 4 ++--
11
fpu/softfloat-parts.c.inc | 28 +++++++++++++---------------
13
linux-user/qemu.h | 4 ++--
12
1 file changed, 13 insertions(+), 15 deletions(-)
14
accel/tcg/user-exec.c | 3 ++-
15
linux-user/mmap.c | 14 +++++++-------
16
linux-user/syscall.c | 2 +-
17
5 files changed, 14 insertions(+), 13 deletions(-)
18
13
19
diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h
14
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
20
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
21
--- a/include/exec/cpu_ldst.h
16
--- a/fpu/softfloat-parts.c.inc
22
+++ b/include/exec/cpu_ldst.h
17
+++ b/fpu/softfloat-parts.c.inc
23
@@ -XXX,XX +XXX,XX @@ static inline void *g2h(CPUState *cs, abi_ptr x)
18
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b,
24
return g2h_untagged(cpu_untagged_addr(cs, x));
19
float_status *s)
25
}
26
27
-static inline bool guest_addr_valid(abi_ulong x)
28
+static inline bool guest_addr_valid_untagged(abi_ulong x)
29
{
20
{
30
return x <= GUEST_ADDR_MAX;
21
bool have_snan = false;
31
}
22
- int cmp, which;
32
23
+ FloatPartsN *ret;
33
-static inline bool guest_range_valid(abi_ulong start, abi_ulong len)
24
+ int cmp;
34
+static inline bool guest_range_valid_untagged(abi_ulong start, abi_ulong len)
25
35
{
26
if (is_snan(a->cls) || is_snan(b->cls)) {
36
return len - 1 <= GUEST_ADDR_MAX && start <= GUEST_ADDR_MAX - len + 1;
27
float_raise(float_flag_invalid | float_flag_invalid_snan, s);
37
}
28
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b,
38
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
29
switch (s->float_2nan_prop_rule) {
39
index XXXXXXX..XXXXXXX 100644
30
case float_2nan_prop_s_ab:
40
--- a/linux-user/qemu.h
31
if (have_snan) {
41
+++ b/linux-user/qemu.h
32
- which = is_snan(a->cls) ? 0 : 1;
42
@@ -XXX,XX +XXX,XX @@ extern unsigned long guest_stack_size;
33
+ ret = is_snan(a->cls) ? a : b;
43
static inline bool access_ok(int type, abi_ulong addr, abi_ulong size)
34
break;
44
{
35
}
45
if (size == 0
36
/* fall through */
46
- ? !guest_addr_valid(addr)
37
case float_2nan_prop_ab:
47
- : !guest_range_valid(addr, size)) {
38
- which = is_nan(a->cls) ? 0 : 1;
48
+ ? !guest_addr_valid_untagged(addr)
39
+ ret = is_nan(a->cls) ? a : b;
49
+ : !guest_range_valid_untagged(addr, size)) {
40
break;
50
return false;
41
case float_2nan_prop_s_ba:
51
}
42
if (have_snan) {
52
return page_check_range((target_ulong)addr, size, type) == 0;
43
- which = is_snan(b->cls) ? 1 : 0;
53
diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c
44
+ ret = is_snan(b->cls) ? b : a;
54
index XXXXXXX..XXXXXXX 100644
45
break;
55
--- a/accel/tcg/user-exec.c
46
}
56
+++ b/accel/tcg/user-exec.c
47
/* fall through */
57
@@ -XXX,XX +XXX,XX @@ static int probe_access_internal(CPUArchState *env, target_ulong addr,
48
case float_2nan_prop_ba:
49
- which = is_nan(b->cls) ? 1 : 0;
50
+ ret = is_nan(b->cls) ? b : a;
51
break;
52
case float_2nan_prop_x87:
53
/*
54
@@ -XXX,XX +XXX,XX @@ static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b,
55
*/
56
if (is_snan(a->cls)) {
57
if (!is_snan(b->cls)) {
58
- which = is_qnan(b->cls) ? 1 : 0;
59
+ ret = is_qnan(b->cls) ? b : a;
60
break;
61
}
62
} else if (is_qnan(a->cls)) {
63
if (is_snan(b->cls) || !is_qnan(b->cls)) {
64
- which = 0;
65
+ ret = a;
66
break;
67
}
68
} else {
69
- which = 1;
70
+ ret = b;
71
break;
72
}
73
cmp = frac_cmp(a, b);
74
if (cmp == 0) {
75
cmp = a->sign < b->sign;
76
}
77
- which = cmp > 0 ? 0 : 1;
78
+ ret = cmp > 0 ? a : b;
79
break;
80
default:
58
g_assert_not_reached();
81
g_assert_not_reached();
59
}
82
}
60
83
61
- if (!guest_addr_valid(addr) || page_check_range(addr, 1, flags) < 0) {
84
- if (which) {
62
+ if (!guest_addr_valid_untagged(addr) ||
85
- a = b;
63
+ page_check_range(addr, 1, flags) < 0) {
86
+ if (is_snan(ret->cls)) {
64
if (nonfault) {
87
+ parts_silence_nan(ret, s);
65
return TLB_INVALID_MASK;
66
} else {
67
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
68
index XXXXXXX..XXXXXXX 100644
69
--- a/linux-user/mmap.c
70
+++ b/linux-user/mmap.c
71
@@ -XXX,XX +XXX,XX @@ int target_mprotect(abi_ulong start, abi_ulong len, int target_prot)
72
}
88
}
73
len = TARGET_PAGE_ALIGN(len);
89
- if (is_snan(a->cls)) {
74
end = start + len;
90
- parts_silence_nan(a, s);
75
- if (!guest_range_valid(start, len)) {
91
- }
76
+ if (!guest_range_valid_untagged(start, len)) {
92
- return a;
77
return -TARGET_ENOMEM;
93
+ return ret;
78
}
94
}
79
if (len == 0) {
95
80
@@ -XXX,XX +XXX,XX @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot,
96
static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b,
81
* It can fail only on 64-bit host with 32-bit target.
82
* On any other target/host host mmap() handles this error correctly.
83
*/
84
- if (end < start || !guest_range_valid(start, len)) {
85
+ if (end < start || !guest_range_valid_untagged(start, len)) {
86
errno = ENOMEM;
87
goto fail;
88
}
89
@@ -XXX,XX +XXX,XX @@ int target_munmap(abi_ulong start, abi_ulong len)
90
if (start & ~TARGET_PAGE_MASK)
91
return -TARGET_EINVAL;
92
len = TARGET_PAGE_ALIGN(len);
93
- if (len == 0 || !guest_range_valid(start, len)) {
94
+ if (len == 0 || !guest_range_valid_untagged(start, len)) {
95
return -TARGET_EINVAL;
96
}
97
98
@@ -XXX,XX +XXX,XX @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
99
int prot;
100
void *host_addr;
101
102
- if (!guest_range_valid(old_addr, old_size) ||
103
+ if (!guest_range_valid_untagged(old_addr, old_size) ||
104
((flags & MREMAP_FIXED) &&
105
- !guest_range_valid(new_addr, new_size)) ||
106
+ !guest_range_valid_untagged(new_addr, new_size)) ||
107
((flags & MREMAP_MAYMOVE) == 0 &&
108
- !guest_range_valid(old_addr, new_size))) {
109
+ !guest_range_valid_untagged(old_addr, new_size))) {
110
errno = ENOMEM;
111
return -1;
112
}
113
@@ -XXX,XX +XXX,XX @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
114
115
if (host_addr != MAP_FAILED) {
116
/* Check if address fits target address space */
117
- if (!guest_range_valid(h2g(host_addr), new_size)) {
118
+ if (!guest_range_valid_untagged(h2g(host_addr), new_size)) {
119
/* Revert mremap() changes */
120
host_addr = mremap(g2h_untagged(old_addr),
121
new_size, old_size, flags);
122
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
123
index XXXXXXX..XXXXXXX 100644
124
--- a/linux-user/syscall.c
125
+++ b/linux-user/syscall.c
126
@@ -XXX,XX +XXX,XX @@ static inline abi_ulong do_shmat(CPUArchState *cpu_env,
127
return -TARGET_EINVAL;
128
}
129
}
130
- if (!guest_range_valid(shmaddr, shm_info.shm_segsz)) {
131
+ if (!guest_range_valid_untagged(shmaddr, shm_info.shm_segsz)) {
132
return -TARGET_EINVAL;
133
}
134
135
--
97
--
136
2.20.1
98
2.34.1
137
99
138
100
diff view generated by jsdifflib
1
From: Hao Wu <wuhaotsh@google.com>
1
From: Leif Lindholm <quic_llindhol@quicinc.com>
2
2
3
This patch adds a QTest for NPCM7XX SMBus's single byte mode. It sends a
3
I'm migrating to Qualcomm's new open source email infrastructure, so
4
byte to a device in the evaluation board, and verify the retrieved value
4
update my email address, and update the mailmap to match.
5
is equivalent to the sent value.
6
5
7
Reviewed-by: Doug Evans<dje@google.com>
6
Signed-off-by: Leif Lindholm <leif.lindholm@oss.qualcomm.com>
8
Reviewed-by: Tyrong Ting<kfting@nuvoton.com>
7
Reviewed-by: Leif Lindholm <quic_llindhol@quicinc.com>
9
Signed-off-by: Hao Wu <wuhaotsh@google.com>
8
Reviewed-by: Brian Cain <brian.cain@oss.qualcomm.com>
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
11
Message-id: 20210210220426.3577804-5-wuhaotsh@google.com
10
Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org>
11
Message-id: 20241205114047.1125842-1-leif.lindholm@oss.qualcomm.com
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
---
13
---
14
tests/qtest/npcm7xx_smbus-test.c | 352 +++++++++++++++++++++++++++++++
14
MAINTAINERS | 2 +-
15
tests/qtest/meson.build | 1 +
15
.mailmap | 5 +++--
16
2 files changed, 353 insertions(+)
16
2 files changed, 4 insertions(+), 3 deletions(-)
17
create mode 100644 tests/qtest/npcm7xx_smbus-test.c
18
17
19
diff --git a/tests/qtest/npcm7xx_smbus-test.c b/tests/qtest/npcm7xx_smbus-test.c
18
diff --git a/MAINTAINERS b/MAINTAINERS
20
new file mode 100644
21
index XXXXXXX..XXXXXXX
22
--- /dev/null
23
+++ b/tests/qtest/npcm7xx_smbus-test.c
24
@@ -XXX,XX +XXX,XX @@
25
+/*
26
+ * QTests for Nuvoton NPCM7xx SMBus Modules.
27
+ *
28
+ * Copyright 2020 Google LLC
29
+ *
30
+ * This program is free software; you can redistribute it and/or modify it
31
+ * under the terms of the GNU General Public License as published by the
32
+ * Free Software Foundation; either version 2 of the License, or
33
+ * (at your option) any later version.
34
+ *
35
+ * This program is distributed in the hope that it will be useful, but WITHOUT
36
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
37
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
38
+ * for more details.
39
+ */
40
+
41
+#include "qemu/osdep.h"
42
+#include "qemu/bitops.h"
43
+#include "libqos/i2c.h"
44
+#include "libqos/libqtest.h"
45
+#include "hw/misc/tmp105_regs.h"
46
+
47
+#define NR_SMBUS_DEVICES 16
48
+#define SMBUS_ADDR(x) (0xf0080000 + 0x1000 * (x))
49
+#define SMBUS_IRQ(x) (64 + (x))
50
+
51
+#define EVB_DEVICE_ADDR 0x48
52
+#define INVALID_DEVICE_ADDR 0x01
53
+
54
+const int evb_bus_list[] = {0, 1, 2, 6};
55
+
56
+/* Offsets */
57
+enum CommonRegister {
58
+ OFFSET_SDA = 0x0,
59
+ OFFSET_ST = 0x2,
60
+ OFFSET_CST = 0x4,
61
+ OFFSET_CTL1 = 0x6,
62
+ OFFSET_ADDR1 = 0x8,
63
+ OFFSET_CTL2 = 0xa,
64
+ OFFSET_ADDR2 = 0xc,
65
+ OFFSET_CTL3 = 0xe,
66
+ OFFSET_CST2 = 0x18,
67
+ OFFSET_CST3 = 0x19,
68
+};
69
+
70
+enum NPCM7xxSMBusBank0Register {
71
+ OFFSET_ADDR3 = 0x10,
72
+ OFFSET_ADDR7 = 0x11,
73
+ OFFSET_ADDR4 = 0x12,
74
+ OFFSET_ADDR8 = 0x13,
75
+ OFFSET_ADDR5 = 0x14,
76
+ OFFSET_ADDR9 = 0x15,
77
+ OFFSET_ADDR6 = 0x16,
78
+ OFFSET_ADDR10 = 0x17,
79
+ OFFSET_CTL4 = 0x1a,
80
+ OFFSET_CTL5 = 0x1b,
81
+ OFFSET_SCLLT = 0x1c,
82
+ OFFSET_FIF_CTL = 0x1d,
83
+ OFFSET_SCLHT = 0x1e,
84
+};
85
+
86
+enum NPCM7xxSMBusBank1Register {
87
+ OFFSET_FIF_CTS = 0x10,
88
+ OFFSET_FAIR_PER = 0x11,
89
+ OFFSET_TXF_CTL = 0x12,
90
+ OFFSET_T_OUT = 0x14,
91
+ OFFSET_TXF_STS = 0x1a,
92
+ OFFSET_RXF_STS = 0x1c,
93
+ OFFSET_RXF_CTL = 0x1e,
94
+};
95
+
96
+/* ST fields */
97
+#define ST_STP BIT(7)
98
+#define ST_SDAST BIT(6)
99
+#define ST_BER BIT(5)
100
+#define ST_NEGACK BIT(4)
101
+#define ST_STASTR BIT(3)
102
+#define ST_NMATCH BIT(2)
103
+#define ST_MODE BIT(1)
104
+#define ST_XMIT BIT(0)
105
+
106
+/* CST fields */
107
+#define CST_ARPMATCH BIT(7)
108
+#define CST_MATCHAF BIT(6)
109
+#define CST_TGSCL BIT(5)
110
+#define CST_TSDA BIT(4)
111
+#define CST_GCMATCH BIT(3)
112
+#define CST_MATCH BIT(2)
113
+#define CST_BB BIT(1)
114
+#define CST_BUSY BIT(0)
115
+
116
+/* CST2 fields */
117
+#define CST2_INSTTS BIT(7)
118
+#define CST2_MATCH7F BIT(6)
119
+#define CST2_MATCH6F BIT(5)
120
+#define CST2_MATCH5F BIT(4)
121
+#define CST2_MATCH4F BIT(3)
122
+#define CST2_MATCH3F BIT(2)
123
+#define CST2_MATCH2F BIT(1)
124
+#define CST2_MATCH1F BIT(0)
125
+
126
+/* CST3 fields */
127
+#define CST3_EO_BUSY BIT(7)
128
+#define CST3_MATCH10F BIT(2)
129
+#define CST3_MATCH9F BIT(1)
130
+#define CST3_MATCH8F BIT(0)
131
+
132
+/* CTL1 fields */
133
+#define CTL1_STASTRE BIT(7)
134
+#define CTL1_NMINTE BIT(6)
135
+#define CTL1_GCMEN BIT(5)
136
+#define CTL1_ACK BIT(4)
137
+#define CTL1_EOBINTE BIT(3)
138
+#define CTL1_INTEN BIT(2)
139
+#define CTL1_STOP BIT(1)
140
+#define CTL1_START BIT(0)
141
+
142
+/* CTL2 fields */
143
+#define CTL2_SCLFRQ(rv) extract8((rv), 1, 6)
144
+#define CTL2_ENABLE BIT(0)
145
+
146
+/* CTL3 fields */
147
+#define CTL3_SCL_LVL BIT(7)
148
+#define CTL3_SDA_LVL BIT(6)
149
+#define CTL3_BNK_SEL BIT(5)
150
+#define CTL3_400K_MODE BIT(4)
151
+#define CTL3_IDL_START BIT(3)
152
+#define CTL3_ARPMEN BIT(2)
153
+#define CTL3_SCLFRQ(rv) extract8((rv), 0, 2)
154
+
155
+/* ADDR fields */
156
+#define ADDR_EN BIT(7)
157
+#define ADDR_A(rv) extract8((rv), 0, 6)
158
+
159
+
160
+static void check_running(QTestState *qts, uint64_t base_addr)
161
+{
162
+ g_assert_true(qtest_readb(qts, base_addr + OFFSET_CST) & CST_BUSY);
163
+ g_assert_true(qtest_readb(qts, base_addr + OFFSET_CST) & CST_BB);
164
+}
165
+
166
+static void check_stopped(QTestState *qts, uint64_t base_addr)
167
+{
168
+ uint8_t cst3;
169
+
170
+ g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_ST), ==, 0);
171
+ g_assert_false(qtest_readb(qts, base_addr + OFFSET_CST) & CST_BUSY);
172
+ g_assert_false(qtest_readb(qts, base_addr + OFFSET_CST) & CST_BB);
173
+
174
+ cst3 = qtest_readb(qts, base_addr + OFFSET_CST3);
175
+ g_assert_true(cst3 & CST3_EO_BUSY);
176
+ qtest_writeb(qts, base_addr + OFFSET_CST3, cst3);
177
+ cst3 = qtest_readb(qts, base_addr + OFFSET_CST3);
178
+ g_assert_false(cst3 & CST3_EO_BUSY);
179
+}
180
+
181
+static void enable_bus(QTestState *qts, uint64_t base_addr)
182
+{
183
+ uint8_t ctl2 = qtest_readb(qts, base_addr + OFFSET_CTL2);
184
+
185
+ ctl2 |= CTL2_ENABLE;
186
+ qtest_writeb(qts, base_addr + OFFSET_CTL2, ctl2);
187
+ g_assert_true(qtest_readb(qts, base_addr + OFFSET_CTL2) & CTL2_ENABLE);
188
+}
189
+
190
+static void disable_bus(QTestState *qts, uint64_t base_addr)
191
+{
192
+ uint8_t ctl2 = qtest_readb(qts, base_addr + OFFSET_CTL2);
193
+
194
+ ctl2 &= ~CTL2_ENABLE;
195
+ qtest_writeb(qts, base_addr + OFFSET_CTL2, ctl2);
196
+ g_assert_false(qtest_readb(qts, base_addr + OFFSET_CTL2) & CTL2_ENABLE);
197
+}
198
+
199
+static void start_transfer(QTestState *qts, uint64_t base_addr)
200
+{
201
+ uint8_t ctl1;
202
+
203
+ ctl1 = CTL1_START | CTL1_INTEN | CTL1_STASTRE;
204
+ qtest_writeb(qts, base_addr + OFFSET_CTL1, ctl1);
205
+ g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_CTL1), ==,
206
+ CTL1_INTEN | CTL1_STASTRE | CTL1_INTEN);
207
+ g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_ST), ==,
208
+ ST_MODE | ST_XMIT | ST_SDAST);
209
+ check_running(qts, base_addr);
210
+}
211
+
212
+static void stop_transfer(QTestState *qts, uint64_t base_addr)
213
+{
214
+ uint8_t ctl1 = qtest_readb(qts, base_addr + OFFSET_CTL1);
215
+
216
+ ctl1 &= ~(CTL1_START | CTL1_ACK);
217
+ ctl1 |= CTL1_STOP | CTL1_INTEN | CTL1_EOBINTE;
218
+ qtest_writeb(qts, base_addr + OFFSET_CTL1, ctl1);
219
+ ctl1 = qtest_readb(qts, base_addr + OFFSET_CTL1);
220
+ g_assert_false(ctl1 & CTL1_STOP);
221
+}
222
+
223
+static void send_byte(QTestState *qts, uint64_t base_addr, uint8_t byte)
224
+{
225
+ g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_ST), ==,
226
+ ST_MODE | ST_XMIT | ST_SDAST);
227
+ qtest_writeb(qts, base_addr + OFFSET_SDA, byte);
228
+}
229
+
230
+static uint8_t recv_byte(QTestState *qts, uint64_t base_addr)
231
+{
232
+ g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_ST), ==,
233
+ ST_MODE | ST_SDAST);
234
+ return qtest_readb(qts, base_addr + OFFSET_SDA);
235
+}
236
+
237
+static void send_address(QTestState *qts, uint64_t base_addr, uint8_t addr,
238
+ bool recv, bool valid)
239
+{
240
+ uint8_t encoded_addr = (addr << 1) | (recv ? 1 : 0);
241
+ uint8_t st;
242
+
243
+ qtest_writeb(qts, base_addr + OFFSET_SDA, encoded_addr);
244
+ st = qtest_readb(qts, base_addr + OFFSET_ST);
245
+
246
+ if (valid) {
247
+ if (recv) {
248
+ g_assert_cmphex(st, ==, ST_MODE | ST_SDAST | ST_STASTR);
249
+ } else {
250
+ g_assert_cmphex(st, ==, ST_MODE | ST_XMIT | ST_SDAST | ST_STASTR);
251
+ }
252
+
253
+ qtest_writeb(qts, base_addr + OFFSET_ST, ST_STASTR);
254
+ st = qtest_readb(qts, base_addr + OFFSET_ST);
255
+ if (recv) {
256
+ g_assert_cmphex(st, ==, ST_MODE | ST_SDAST);
257
+ } else {
258
+ g_assert_cmphex(st, ==, ST_MODE | ST_XMIT | ST_SDAST);
259
+ }
260
+ } else {
261
+ if (recv) {
262
+ g_assert_cmphex(st, ==, ST_MODE | ST_NEGACK);
263
+ } else {
264
+ g_assert_cmphex(st, ==, ST_MODE | ST_XMIT | ST_NEGACK);
265
+ }
266
+ }
267
+}
268
+
269
+static void send_nack(QTestState *qts, uint64_t base_addr)
270
+{
271
+ uint8_t ctl1 = qtest_readb(qts, base_addr + OFFSET_CTL1);
272
+
273
+ ctl1 &= ~(CTL1_START | CTL1_STOP);
274
+ ctl1 |= CTL1_ACK | CTL1_INTEN;
275
+ qtest_writeb(qts, base_addr + OFFSET_CTL1, ctl1);
276
+}
277
+
278
+/* Check the SMBus's status is set correctly when disabled. */
279
+static void test_disable_bus(gconstpointer data)
280
+{
281
+ intptr_t index = (intptr_t)data;
282
+ uint64_t base_addr = SMBUS_ADDR(index);
283
+ QTestState *qts = qtest_init("-machine npcm750-evb");
284
+
285
+ disable_bus(qts, base_addr);
286
+ g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_CTL1), ==, 0);
287
+ g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_ST), ==, 0);
288
+ g_assert_false(qtest_readb(qts, base_addr + OFFSET_CST3) & CST3_EO_BUSY);
289
+ g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_CST), ==, 0);
290
+ qtest_quit(qts);
291
+}
292
+
293
+/* Check the SMBus returns a NACK for an invalid address. */
294
+static void test_invalid_addr(gconstpointer data)
295
+{
296
+ intptr_t index = (intptr_t)data;
297
+ uint64_t base_addr = SMBUS_ADDR(index);
298
+ int irq = SMBUS_IRQ(index);
299
+ QTestState *qts = qtest_init("-machine npcm750-evb");
300
+
301
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
302
+ enable_bus(qts, base_addr);
303
+ g_assert_false(qtest_get_irq(qts, irq));
304
+ start_transfer(qts, base_addr);
305
+ send_address(qts, base_addr, INVALID_DEVICE_ADDR, false, false);
306
+ g_assert_true(qtest_get_irq(qts, irq));
307
+ stop_transfer(qts, base_addr);
308
+ check_running(qts, base_addr);
309
+ qtest_writeb(qts, base_addr + OFFSET_ST, ST_NEGACK);
310
+ g_assert_false(qtest_readb(qts, base_addr + OFFSET_ST) & ST_NEGACK);
311
+ check_stopped(qts, base_addr);
312
+ qtest_quit(qts);
313
+}
314
+
315
+/* Check the SMBus can send and receive bytes to a device in single mode. */
316
+static void test_single_mode(gconstpointer data)
317
+{
318
+ intptr_t index = (intptr_t)data;
319
+ uint64_t base_addr = SMBUS_ADDR(index);
320
+ int irq = SMBUS_IRQ(index);
321
+ uint8_t value = 0x60;
322
+ QTestState *qts = qtest_init("-machine npcm750-evb");
323
+
324
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
325
+ enable_bus(qts, base_addr);
326
+
327
+ /* Sending */
328
+ g_assert_false(qtest_get_irq(qts, irq));
329
+ start_transfer(qts, base_addr);
330
+ g_assert_true(qtest_get_irq(qts, irq));
331
+ send_address(qts, base_addr, EVB_DEVICE_ADDR, false, true);
332
+ send_byte(qts, base_addr, TMP105_REG_CONFIG);
333
+ send_byte(qts, base_addr, value);
334
+ stop_transfer(qts, base_addr);
335
+ check_stopped(qts, base_addr);
336
+
337
+ /* Receiving */
338
+ start_transfer(qts, base_addr);
339
+ send_address(qts, base_addr, EVB_DEVICE_ADDR, false, true);
340
+ send_byte(qts, base_addr, TMP105_REG_CONFIG);
341
+ start_transfer(qts, base_addr);
342
+ send_address(qts, base_addr, EVB_DEVICE_ADDR, true, true);
343
+ send_nack(qts, base_addr);
344
+ stop_transfer(qts, base_addr);
345
+ check_running(qts, base_addr);
346
+ g_assert_cmphex(recv_byte(qts, base_addr), ==, value);
347
+ check_stopped(qts, base_addr);
348
+ qtest_quit(qts);
349
+}
350
+
351
+static void smbus_add_test(const char *name, int index, GTestDataFunc fn)
352
+{
353
+ g_autofree char *full_name = g_strdup_printf(
354
+ "npcm7xx_smbus[%d]/%s", index, name);
355
+ qtest_add_data_func(full_name, (void *)(intptr_t)index, fn);
356
+}
357
+#define add_test(name, td) smbus_add_test(#name, td, test_##name)
358
+
359
+int main(int argc, char **argv)
360
+{
361
+ int i;
362
+
363
+ g_test_init(&argc, &argv, NULL);
364
+ g_test_set_nonfatal_assertions();
365
+
366
+ for (i = 0; i < NR_SMBUS_DEVICES; ++i) {
367
+ add_test(disable_bus, i);
368
+ add_test(invalid_addr, i);
369
+ }
370
+
371
+ for (i = 0; i < ARRAY_SIZE(evb_bus_list); ++i) {
372
+ add_test(single_mode, evb_bus_list[i]);
373
+ }
374
+
375
+ return g_test_run();
376
+}
377
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
378
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
379
--- a/tests/qtest/meson.build
20
--- a/MAINTAINERS
380
+++ b/tests/qtest/meson.build
21
+++ b/MAINTAINERS
381
@@ -XXX,XX +XXX,XX @@ qtests_npcm7xx = \
22
@@ -XXX,XX +XXX,XX @@ F: include/hw/ssi/imx_spi.h
382
'npcm7xx_gpio-test',
23
SBSA-REF
383
'npcm7xx_pwm-test',
24
M: Radoslaw Biernacki <rad@semihalf.com>
384
'npcm7xx_rng-test',
25
M: Peter Maydell <peter.maydell@linaro.org>
385
+ 'npcm7xx_smbus-test',
26
-R: Leif Lindholm <quic_llindhol@quicinc.com>
386
'npcm7xx_timer-test',
27
+R: Leif Lindholm <leif.lindholm@oss.qualcomm.com>
387
'npcm7xx_watchdog_timer-test']
28
R: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org>
388
qtests_arm = \
29
L: qemu-arm@nongnu.org
30
S: Maintained
31
diff --git a/.mailmap b/.mailmap
32
index XXXXXXX..XXXXXXX 100644
33
--- a/.mailmap
34
+++ b/.mailmap
35
@@ -XXX,XX +XXX,XX @@ Huacai Chen <chenhuacai@kernel.org> <chenhc@lemote.com>
36
Huacai Chen <chenhuacai@kernel.org> <chenhuacai@loongson.cn>
37
James Hogan <jhogan@kernel.org> <james.hogan@imgtec.com>
38
Juan Quintela <quintela@trasno.org> <quintela@redhat.com>
39
-Leif Lindholm <quic_llindhol@quicinc.com> <leif.lindholm@linaro.org>
40
-Leif Lindholm <quic_llindhol@quicinc.com> <leif@nuviainc.com>
41
+Leif Lindholm <leif.lindholm@oss.qualcomm.com> <quic_llindhol@quicinc.com>
42
+Leif Lindholm <leif.lindholm@oss.qualcomm.com> <leif.lindholm@linaro.org>
43
+Leif Lindholm <leif.lindholm@oss.qualcomm.com> <leif@nuviainc.com>
44
Luc Michel <luc@lmichel.fr> <luc.michel@git.antfield.fr>
45
Luc Michel <luc@lmichel.fr> <luc.michel@greensocs.com>
46
Luc Michel <luc@lmichel.fr> <lmichel@kalray.eu>
389
--
47
--
390
2.20.1
48
2.34.1
391
49
392
50
diff view generated by jsdifflib
1
From: Luc Michel <luc@lmichel.fr>
1
From: Vikram Garhwal <vikram.garhwal@bytedance.com>
2
2
3
Also add Damien as a reviewer.
3
Previously, maintainer role was paused due to inactive email id. Commit id:
4
c009d715721861984c4987bcc78b7ee183e86d75.
4
5
5
Signed-off-by: Luc Michel <luc@lmichel.fr>
6
Signed-off-by: Vikram Garhwal <vikram.garhwal@bytedance.com>
6
Acked-by: Damien Hedde <damien.hedde@greensocs.com>
7
Reviewed-by: Francisco Iglesias <francisco.iglesias@amd.com>
7
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
Message-id: 20241204184205.12952-1-vikram.garhwal@bytedance.com
8
Message-id: 20210211085318.2507-1-luc@lmichel.fr
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
10
---
11
MAINTAINERS | 11 +++++++++++
11
MAINTAINERS | 2 ++
12
1 file changed, 11 insertions(+)
12
1 file changed, 2 insertions(+)
13
13
14
diff --git a/MAINTAINERS b/MAINTAINERS
14
diff --git a/MAINTAINERS b/MAINTAINERS
15
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
16
--- a/MAINTAINERS
16
--- a/MAINTAINERS
17
+++ b/MAINTAINERS
17
+++ b/MAINTAINERS
18
@@ -XXX,XX +XXX,XX @@ F: pc-bios/opensbi-*
18
@@ -XXX,XX +XXX,XX @@ F: tests/qtest/fuzz-sb16-test.c
19
F: .gitlab-ci.d/opensbi.yml
19
20
F: .gitlab-ci.d/opensbi/
20
Xilinx CAN
21
21
M: Francisco Iglesias <francisco.iglesias@amd.com>
22
+Clock framework
22
+M: Vikram Garhwal <vikram.garhwal@bytedance.com>
23
+M: Luc Michel <luc@lmichel.fr>
23
S: Maintained
24
+R: Damien Hedde <damien.hedde@greensocs.com>
24
F: hw/net/can/xlnx-*
25
+S: Maintained
25
F: include/hw/net/xlnx-*
26
+F: include/hw/clock.h
26
@@ -XXX,XX +XXX,XX @@ F: include/hw/rx/
27
+F: include/hw/qdev-clock.h
27
CAN bus subsystem and hardware
28
+F: hw/core/clock.c
28
M: Pavel Pisa <pisa@cmp.felk.cvut.cz>
29
+F: hw/core/clock-vmstate.c
29
M: Francisco Iglesias <francisco.iglesias@amd.com>
30
+F: hw/core/qdev-clock.c
30
+M: Vikram Garhwal <vikram.garhwal@bytedance.com>
31
+F: docs/devel/clocks.rst
31
S: Maintained
32
+
32
W: https://canbus.pages.fel.cvut.cz/
33
Usermode Emulation
33
F: net/can/*
34
------------------
35
Overall usermode emulation
36
--
34
--
37
2.20.1
35
2.34.1
38
39
diff view generated by jsdifflib