hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/arch/s390/mm/maccess.c
....@@ -16,6 +16,7 @@
1616 #include <linux/cpu.h>
1717 #include <asm/ctl_reg.h>
1818 #include <asm/io.h>
19
+#include <asm/stacktrace.h>
1920
2021 static notrace long s390_kernel_write_odd(void *dst, const void *src, size_t size)
2122 {
....@@ -51,24 +52,32 @@
5152 * Therefore we have a read-modify-write sequence: the function reads eight
5253 * bytes from destination at an eight byte boundary, modifies the bytes
5354 * requested and writes the result back in a loop.
54
- *
55
- * Note: this means that this function may not be called concurrently on
56
- * several cpus with overlapping words, since this may potentially
57
- * cause data corruption.
5855 */
59
-void notrace s390_kernel_write(void *dst, const void *src, size_t size)
56
+static DEFINE_SPINLOCK(s390_kernel_write_lock);
57
+
58
+notrace void *s390_kernel_write(void *dst, const void *src, size_t size)
6059 {
60
+ void *tmp = dst;
61
+ unsigned long flags;
6162 long copied;
6263
63
- while (size) {
64
- copied = s390_kernel_write_odd(dst, src, size);
65
- dst += copied;
66
- src += copied;
67
- size -= copied;
64
+ spin_lock_irqsave(&s390_kernel_write_lock, flags);
65
+ if (!(flags & PSW_MASK_DAT)) {
66
+ memcpy(dst, src, size);
67
+ } else {
68
+ while (size) {
69
+ copied = s390_kernel_write_odd(tmp, src, size);
70
+ tmp += copied;
71
+ src += copied;
72
+ size -= copied;
73
+ }
6874 }
75
+ spin_unlock_irqrestore(&s390_kernel_write_lock, flags);
76
+
77
+ return dst;
6978 }
7079
71
-static int __memcpy_real(void *dest, void *src, size_t count)
80
+static int __no_sanitize_address __memcpy_real(void *dest, void *src, size_t count)
7281 {
7382 register unsigned long _dest asm("2") = (unsigned long) dest;
7483 register unsigned long _len1 asm("3") = (unsigned long) count;
....@@ -89,21 +98,23 @@
8998 return rc;
9099 }
91100
92
-/*
93
- * Copy memory in real mode (kernel to kernel)
94
- */
95
-int memcpy_real(void *dest, void *src, size_t count)
101
+static unsigned long __no_sanitize_address _memcpy_real(unsigned long dest,
102
+ unsigned long src,
103
+ unsigned long count)
96104 {
97105 int irqs_disabled, rc;
98106 unsigned long flags;
99107
100108 if (!count)
101109 return 0;
102
- flags = __arch_local_irq_stnsm(0xf8UL);
110
+ flags = arch_local_irq_save();
103111 irqs_disabled = arch_irqs_disabled_flags(flags);
104112 if (!irqs_disabled)
105113 trace_hardirqs_off();
106
- rc = __memcpy_real(dest, src, count);
114
+ __arch_local_irq_stnsm(0xf8); // disable DAT
115
+ rc = __memcpy_real((void *) dest, (void *) src, (size_t) count);
116
+ if (flags & PSW_MASK_DAT)
117
+ __arch_local_irq_stosm(0x04); // enable DAT
107118 if (!irqs_disabled)
108119 trace_hardirqs_on();
109120 __arch_local_irq_ssm(flags);
....@@ -111,6 +122,29 @@
111122 }
112123
113124 /*
125
+ * Copy memory in real mode (kernel to kernel)
126
+ */
127
+int memcpy_real(void *dest, void *src, size_t count)
128
+{
129
+ int rc;
130
+
131
+ if (S390_lowcore.nodat_stack != 0) {
132
+ preempt_disable();
133
+ rc = CALL_ON_STACK(_memcpy_real, S390_lowcore.nodat_stack, 3,
134
+ dest, src, count);
135
+ preempt_enable();
136
+ return rc;
137
+ }
138
+ /*
139
+ * This is a really early memcpy_real call, the stacks are
140
+ * not set up yet. Just call _memcpy_real on the early boot
141
+ * stack
142
+ */
143
+ return _memcpy_real((unsigned long) dest,(unsigned long) src,
144
+ (unsigned long) count);
145
+}
146
+
147
+/*
114148 * Copy memory in absolute mode (kernel to kernel)
115149 */
116150 void memcpy_absolute(void *dest, void *src, size_t count)