xref: /linux/arch/s390/mm/maccess.c (revision 97884ca8c2925d14c32188e865069f21378b4b4f)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Access kernel memory without faulting -- s390 specific implementation.
4  *
5  * Copyright IBM Corp. 2009, 2015
6  *
7  *   Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>,
8  *
9  */
10 
11 #include <linux/uaccess.h>
12 #include <linux/kernel.h>
13 #include <linux/types.h>
14 #include <linux/errno.h>
15 #include <linux/gfp.h>
16 #include <linux/cpu.h>
17 #include <asm/ctl_reg.h>
18 #include <asm/io.h>
19 #include <asm/stacktrace.h>
20 
21 static notrace long s390_kernel_write_odd(void *dst, const void *src, size_t size)
22 {
23 	unsigned long aligned, offset, count;
24 	char tmp[8];
25 
26 	aligned = (unsigned long) dst & ~7UL;
27 	offset = (unsigned long) dst & 7UL;
28 	size = min(8UL - offset, size);
29 	count = size - 1;
30 	asm volatile(
31 		"	bras	1,0f\n"
32 		"	mvc	0(1,%4),0(%5)\n"
33 		"0:	mvc	0(8,%3),0(%0)\n"
34 		"	ex	%1,0(1)\n"
35 		"	lg	%1,0(%3)\n"
36 		"	lra	%0,0(%0)\n"
37 		"	sturg	%1,%0\n"
38 		: "+&a" (aligned), "+&a" (count), "=m" (tmp)
39 		: "a" (&tmp), "a" (&tmp[offset]), "a" (src)
40 		: "cc", "memory", "1");
41 	return size;
42 }
43 
44 /*
45  * s390_kernel_write - write to kernel memory bypassing DAT
46  * @dst: destination address
47  * @src: source address
48  * @size: number of bytes to copy
49  *
50  * This function writes to kernel memory bypassing DAT and possible page table
51  * write protection. It writes to the destination using the sturg instruction.
52  * Therefore we have a read-modify-write sequence: the function reads eight
53  * bytes from destination at an eight byte boundary, modifies the bytes
54  * requested and writes the result back in a loop.
55  */
56 static DEFINE_SPINLOCK(s390_kernel_write_lock);
57 
58 notrace void *s390_kernel_write(void *dst, const void *src, size_t size)
59 {
60 	void *tmp = dst;
61 	unsigned long flags;
62 	long copied;
63 
64 	spin_lock_irqsave(&s390_kernel_write_lock, flags);
65 	while (size) {
66 		copied = s390_kernel_write_odd(tmp, src, size);
67 		tmp += copied;
68 		src += copied;
69 		size -= copied;
70 	}
71 	spin_unlock_irqrestore(&s390_kernel_write_lock, flags);
72 
73 	return dst;
74 }
75 
76 static int __no_sanitize_address __memcpy_real(void *dest, void *src, size_t count)
77 {
78 	register unsigned long _dest asm("2") = (unsigned long) dest;
79 	register unsigned long _len1 asm("3") = (unsigned long) count;
80 	register unsigned long _src  asm("4") = (unsigned long) src;
81 	register unsigned long _len2 asm("5") = (unsigned long) count;
82 	int rc = -EFAULT;
83 
84 	asm volatile (
85 		"0:	mvcle	%1,%2,0x0\n"
86 		"1:	jo	0b\n"
87 		"	lhi	%0,0x0\n"
88 		"2:\n"
89 		EX_TABLE(1b,2b)
90 		: "+d" (rc), "+d" (_dest), "+d" (_src), "+d" (_len1),
91 		  "+d" (_len2), "=m" (*((long *) dest))
92 		: "m" (*((long *) src))
93 		: "cc", "memory");
94 	return rc;
95 }
96 
97 static unsigned long __no_sanitize_address _memcpy_real(unsigned long dest,
98 							unsigned long src,
99 							unsigned long count)
100 {
101 	int irqs_disabled, rc;
102 	unsigned long flags;
103 
104 	if (!count)
105 		return 0;
106 	flags = arch_local_irq_save();
107 	irqs_disabled = arch_irqs_disabled_flags(flags);
108 	if (!irqs_disabled)
109 		trace_hardirqs_off();
110 	__arch_local_irq_stnsm(0xf8); // disable DAT
111 	rc = __memcpy_real((void *) dest, (void *) src, (size_t) count);
112 	if (flags & PSW_MASK_DAT)
113 		__arch_local_irq_stosm(0x04); // enable DAT
114 	if (!irqs_disabled)
115 		trace_hardirqs_on();
116 	__arch_local_irq_ssm(flags);
117 	return rc;
118 }
119 
120 /*
121  * Copy memory in real mode (kernel to kernel)
122  */
123 int memcpy_real(void *dest, void *src, size_t count)
124 {
125 	int rc;
126 
127 	if (S390_lowcore.nodat_stack != 0) {
128 		preempt_disable();
129 		rc = CALL_ON_STACK(_memcpy_real, S390_lowcore.nodat_stack, 3,
130 				   dest, src, count);
131 		preempt_enable();
132 		return rc;
133 	}
134 	/*
135 	 * This is a really early memcpy_real call, the stacks are
136 	 * not set up yet. Just call _memcpy_real on the early boot
137 	 * stack
138 	 */
139 	return _memcpy_real((unsigned long) dest,(unsigned long) src,
140 			    (unsigned long) count);
141 }
142 
143 /*
144  * Copy memory in absolute mode (kernel to kernel)
145  */
146 void memcpy_absolute(void *dest, void *src, size_t count)
147 {
148 	unsigned long cr0, flags, prefix;
149 
150 	flags = arch_local_irq_save();
151 	__ctl_store(cr0, 0, 0);
152 	__ctl_clear_bit(0, 28); /* disable lowcore protection */
153 	prefix = store_prefix();
154 	if (prefix) {
155 		local_mcck_disable();
156 		set_prefix(0);
157 		memcpy(dest, src, count);
158 		set_prefix(prefix);
159 		local_mcck_enable();
160 	} else {
161 		memcpy(dest, src, count);
162 	}
163 	__ctl_load(cr0, 0, 0);
164 	arch_local_irq_restore(flags);
165 }
166 
167 /*
168  * Copy memory from kernel (real) to user (virtual)
169  */
170 int copy_to_user_real(void __user *dest, void *src, unsigned long count)
171 {
172 	int offs = 0, size, rc;
173 	char *buf;
174 
175 	buf = (char *) __get_free_page(GFP_KERNEL);
176 	if (!buf)
177 		return -ENOMEM;
178 	rc = -EFAULT;
179 	while (offs < count) {
180 		size = min(PAGE_SIZE, count - offs);
181 		if (memcpy_real(buf, src + offs, size))
182 			goto out;
183 		if (copy_to_user(dest + offs, buf, size))
184 			goto out;
185 		offs += size;
186 	}
187 	rc = 0;
188 out:
189 	free_page((unsigned long) buf);
190 	return rc;
191 }
192 
193 /*
194  * Check if physical address is within prefix or zero page
195  */
196 static int is_swapped(unsigned long addr)
197 {
198 	unsigned long lc;
199 	int cpu;
200 
201 	if (addr < sizeof(struct lowcore))
202 		return 1;
203 	for_each_online_cpu(cpu) {
204 		lc = (unsigned long) lowcore_ptr[cpu];
205 		if (addr > lc + sizeof(struct lowcore) - 1 || addr < lc)
206 			continue;
207 		return 1;
208 	}
209 	return 0;
210 }
211 
212 /*
213  * Convert a physical pointer for /dev/mem access
214  *
215  * For swapped prefix pages a new buffer is returned that contains a copy of
216  * the absolute memory. The buffer size is maximum one page large.
217  */
218 void *xlate_dev_mem_ptr(phys_addr_t addr)
219 {
220 	void *bounce = (void *) addr;
221 	unsigned long size;
222 
223 	get_online_cpus();
224 	preempt_disable();
225 	if (is_swapped(addr)) {
226 		size = PAGE_SIZE - (addr & ~PAGE_MASK);
227 		bounce = (void *) __get_free_page(GFP_ATOMIC);
228 		if (bounce)
229 			memcpy_absolute(bounce, (void *) addr, size);
230 	}
231 	preempt_enable();
232 	put_online_cpus();
233 	return bounce;
234 }
235 
236 /*
237  * Free converted buffer for /dev/mem access (if necessary)
238  */
239 void unxlate_dev_mem_ptr(phys_addr_t addr, void *buf)
240 {
241 	if ((void *) addr != buf)
242 		free_page((unsigned long) buf);
243 }
244