xref: /netbsd-src/sys/kern/subr_csan.c (revision 627f7eb200a4419d89b531d55fccd2ee3ffdcde0)
1 /*	$NetBSD: subr_csan.c,v 1.10 2020/09/10 14:04:45 maxv Exp $	*/
2 
3 /*
4  * Copyright (c) 2019-2020 Maxime Villard, m00nbsd.net
5  * All rights reserved.
6  *
7  * This code is part of the KCSAN subsystem of the NetBSD kernel.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: subr_csan.c,v 1.10 2020/09/10 14:04:45 maxv Exp $");
33 
34 #include <sys/param.h>
35 #include <sys/device.h>
36 #include <sys/kernel.h>
37 #include <sys/param.h>
38 #include <sys/conf.h>
39 #include <sys/systm.h>
40 #include <sys/types.h>
41 #include <sys/csan.h>
42 #include <sys/cpu.h>
43 
44 #ifdef KCSAN_PANIC
45 #define REPORT panic
46 #else
47 #define REPORT printf
48 #endif
49 
50 typedef struct {
51 	uintptr_t addr;
52 	uint32_t size;
53 	bool write:1;
54 	bool atomic:1;
55 	uintptr_t pc;
56 } csan_cell_t;
57 
58 typedef struct {
59 	bool inited;
60 	uint32_t cnt;
61 	csan_cell_t cell;
62 } csan_cpu_t;
63 
64 static csan_cpu_t kcsan_cpus[MAXCPUS];
65 static bool kcsan_enabled __read_mostly;
66 
67 #define __RET_ADDR	(uintptr_t)__builtin_return_address(0)
68 
69 #define KCSAN_NACCESSES	1024
70 #define KCSAN_DELAY	10	/* 10 microseconds */
71 
72 /* -------------------------------------------------------------------------- */
73 
74 /* The MD code. */
75 #include <machine/csan.h>
76 
77 /* -------------------------------------------------------------------------- */
78 
79 void
80 kcsan_init(void)
81 {
82 	kcsan_enabled = true;
83 }
84 
85 void
86 kcsan_cpu_init(struct cpu_info *ci)
87 {
88 	kcsan_cpus[cpu_index(ci)].inited = true;
89 }
90 
91 /* -------------------------------------------------------------------------- */
92 
93 static inline void
94 kcsan_report(csan_cell_t *new, cpuid_t newcpu, csan_cell_t *old, cpuid_t oldcpu)
95 {
96 	const char *newsym, *oldsym;
97 
98 	if (ksyms_getname(NULL, &newsym, (vaddr_t)new->pc, KSYMS_PROC) != 0) {
99 		newsym = "Unknown";
100 	}
101 	if (ksyms_getname(NULL, &oldsym, (vaddr_t)old->pc, KSYMS_PROC) != 0) {
102 		oldsym = "Unknown";
103 	}
104 	REPORT("CSan: Racy Access "
105 	    "[Cpu%lu %s%s Addr=%p Size=%u PC=%p<%s>] "
106 	    "[Cpu%lu %s%s Addr=%p Size=%u PC=%p<%s>]\n",
107 	    newcpu,
108 	    (new->atomic ? "Atomic " : ""), (new->write ? "Write" : "Read"),
109 	    (void *)new->addr, new->size, (void *)new->pc, newsym,
110 	    oldcpu,
111 	    (old->atomic ? "Atomic " : ""), (old->write ? "Write" : "Read"),
112 	    (void *)old->addr, old->size, (void *)old->pc, oldsym);
113 	kcsan_md_unwind();
114 }
115 
116 static inline bool
117 kcsan_access_is_atomic(csan_cell_t *new, csan_cell_t *old)
118 {
119 	if (new->write && !new->atomic)
120 		return false;
121 	if (old->write && !old->atomic)
122 		return false;
123 	return true;
124 }
125 
126 static inline void
127 kcsan_access(uintptr_t addr, size_t size, bool write, bool atomic, uintptr_t pc)
128 {
129 	csan_cell_t old, new;
130 	csan_cpu_t *cpu;
131 	uint64_t intr;
132 	size_t i;
133 
134 	if (__predict_false(!kcsan_enabled))
135 		return;
136 	if (__predict_false(kcsan_md_unsupported((vaddr_t)addr)))
137 		return;
138 
139 	new.addr = addr;
140 	new.size = size;
141 	new.write = write;
142 	new.atomic = atomic;
143 	new.pc = pc;
144 
145 	for (i = 0; i < ncpu; i++) {
146 		__builtin_memcpy(&old, &kcsan_cpus[i].cell, sizeof(old));
147 
148 		if (old.addr + old.size <= new.addr)
149 			continue;
150 		if (new.addr + new.size <= old.addr)
151 			continue;
152 		if (__predict_true(!old.write && !new.write))
153 			continue;
154 		if (__predict_true(kcsan_access_is_atomic(&new, &old)))
155 			continue;
156 
157 		kcsan_report(&new, cpu_number(), &old, i);
158 		break;
159 	}
160 
161 	if (__predict_false(!kcsan_md_is_avail()))
162 		return;
163 
164 	kcsan_md_disable_intrs(&intr);
165 
166 	cpu = &kcsan_cpus[cpu_number()];
167 	if (__predict_false(!cpu->inited))
168 		goto out;
169 	cpu->cnt = (cpu->cnt + 1) % KCSAN_NACCESSES;
170 	if (__predict_true(cpu->cnt != 0))
171 		goto out;
172 
173 	__builtin_memcpy(&cpu->cell, &new, sizeof(new));
174 	kcsan_md_delay(KCSAN_DELAY);
175 	__builtin_memset(&cpu->cell, 0, sizeof(new));
176 
177 out:
178 	kcsan_md_enable_intrs(&intr);
179 }
180 
181 #define CSAN_READ(size)							\
182 	void __tsan_read##size(uintptr_t);				\
183 	void __tsan_read##size(uintptr_t addr)				\
184 	{								\
185 		kcsan_access(addr, size, false, false, __RET_ADDR);	\
186 	}
187 
188 CSAN_READ(1)
189 CSAN_READ(2)
190 CSAN_READ(4)
191 CSAN_READ(8)
192 CSAN_READ(16)
193 
194 #define CSAN_WRITE(size)						\
195 	void __tsan_write##size(uintptr_t);				\
196 	void __tsan_write##size(uintptr_t addr)				\
197 	{								\
198 		kcsan_access(addr, size, true, false, __RET_ADDR);	\
199 	}
200 
201 CSAN_WRITE(1)
202 CSAN_WRITE(2)
203 CSAN_WRITE(4)
204 CSAN_WRITE(8)
205 CSAN_WRITE(16)
206 
207 void __tsan_read_range(uintptr_t, size_t);
208 void __tsan_write_range(uintptr_t, size_t);
209 
210 void
211 __tsan_read_range(uintptr_t addr, size_t size)
212 {
213 	kcsan_access(addr, size, false, false, __RET_ADDR);
214 }
215 
216 void
217 __tsan_write_range(uintptr_t addr, size_t size)
218 {
219 	kcsan_access(addr, size, true, false, __RET_ADDR);
220 }
221 
222 void __tsan_init(void);
223 void __tsan_func_entry(void *);
224 void __tsan_func_exit(void);
225 
226 void
227 __tsan_init(void)
228 {
229 }
230 
231 void
232 __tsan_func_entry(void *call_pc)
233 {
234 }
235 
236 void
237 __tsan_func_exit(void)
238 {
239 }
240 
241 /* -------------------------------------------------------------------------- */
242 
243 void *
244 kcsan_memcpy(void *dst, const void *src, size_t len)
245 {
246 	kcsan_access((uintptr_t)src, len, false, false, __RET_ADDR);
247 	kcsan_access((uintptr_t)dst, len, true, false, __RET_ADDR);
248 	return __builtin_memcpy(dst, src, len);
249 }
250 
251 int
252 kcsan_memcmp(const void *b1, const void *b2, size_t len)
253 {
254 	kcsan_access((uintptr_t)b1, len, false, false, __RET_ADDR);
255 	kcsan_access((uintptr_t)b2, len, false, false, __RET_ADDR);
256 	return __builtin_memcmp(b1, b2, len);
257 }
258 
259 void *
260 kcsan_memset(void *b, int c, size_t len)
261 {
262 	kcsan_access((uintptr_t)b, len, true, false, __RET_ADDR);
263 	return __builtin_memset(b, c, len);
264 }
265 
266 void *
267 kcsan_memmove(void *dst, const void *src, size_t len)
268 {
269 	kcsan_access((uintptr_t)src, len, false, false, __RET_ADDR);
270 	kcsan_access((uintptr_t)dst, len, true, false, __RET_ADDR);
271 	return __builtin_memmove(dst, src, len);
272 }
273 
274 char *
275 kcsan_strcpy(char *dst, const char *src)
276 {
277 	char *save = dst;
278 
279 	while (1) {
280 		kcsan_access((uintptr_t)src, 1, false, false, __RET_ADDR);
281 		kcsan_access((uintptr_t)dst, 1, true, false, __RET_ADDR);
282 		*dst = *src;
283 		if (*src == '\0')
284 			break;
285 		src++, dst++;
286 	}
287 
288 	return save;
289 }
290 
291 int
292 kcsan_strcmp(const char *s1, const char *s2)
293 {
294 	while (1) {
295 		kcsan_access((uintptr_t)s1, 1, false, false, __RET_ADDR);
296 		kcsan_access((uintptr_t)s2, 1, false, false, __RET_ADDR);
297 		if (*s1 != *s2)
298 			break;
299 		if (*s1 == '\0')
300 			return 0;
301 		s1++, s2++;
302 	}
303 
304 	return (*(const unsigned char *)s1 - *(const unsigned char *)s2);
305 }
306 
307 size_t
308 kcsan_strlen(const char *str)
309 {
310 	const char *s;
311 
312 	s = str;
313 	while (1) {
314 		kcsan_access((uintptr_t)s, 1, false, false, __RET_ADDR);
315 		if (*s == '\0')
316 			break;
317 		s++;
318 	}
319 
320 	return (s - str);
321 }
322 
323 #undef kcopy
324 #undef copyinstr
325 #undef copyoutstr
326 #undef copyin
327 #undef copyout
328 
329 int	kcsan_kcopy(const void *, void *, size_t);
330 int	kcsan_copyinstr(const void *, void *, size_t, size_t *);
331 int	kcsan_copyoutstr(const void *, void *, size_t, size_t *);
332 int	kcsan_copyin(const void *, void *, size_t);
333 int	kcsan_copyout(const void *, void *, size_t);
334 int	kcopy(const void *, void *, size_t);
335 int	copyinstr(const void *, void *, size_t, size_t *);
336 int	copyoutstr(const void *, void *, size_t, size_t *);
337 int	copyin(const void *, void *, size_t);
338 int	copyout(const void *, void *, size_t);
339 
340 int
341 kcsan_kcopy(const void *src, void *dst, size_t len)
342 {
343 	kcsan_access((uintptr_t)src, len, false, false, __RET_ADDR);
344 	kcsan_access((uintptr_t)dst, len, true, false, __RET_ADDR);
345 	return kcopy(src, dst, len);
346 }
347 
348 int
349 kcsan_copyin(const void *uaddr, void *kaddr, size_t len)
350 {
351 	kcsan_access((uintptr_t)kaddr, len, true, false, __RET_ADDR);
352 	return copyin(uaddr, kaddr, len);
353 }
354 
355 int
356 kcsan_copyout(const void *kaddr, void *uaddr, size_t len)
357 {
358 	kcsan_access((uintptr_t)kaddr, len, false, false, __RET_ADDR);
359 	return copyout(kaddr, uaddr, len);
360 }
361 
362 int
363 kcsan_copyinstr(const void *uaddr, void *kaddr, size_t len, size_t *done)
364 {
365 	kcsan_access((uintptr_t)kaddr, len, true, false, __RET_ADDR);
366 	return copyinstr(uaddr, kaddr, len, done);
367 }
368 
369 int
370 kcsan_copyoutstr(const void *kaddr, void *uaddr, size_t len, size_t *done)
371 {
372 	kcsan_access((uintptr_t)kaddr, len, false, false, __RET_ADDR);
373 	return copyoutstr(kaddr, uaddr, len, done);
374 }
375 
376 /* -------------------------------------------------------------------------- */
377 
378 #undef atomic_add_32
379 #undef atomic_add_int
380 #undef atomic_add_long
381 #undef atomic_add_ptr
382 #undef atomic_add_64
383 #undef atomic_add_32_nv
384 #undef atomic_add_int_nv
385 #undef atomic_add_long_nv
386 #undef atomic_add_ptr_nv
387 #undef atomic_add_64_nv
388 #undef atomic_and_32
389 #undef atomic_and_uint
390 #undef atomic_and_ulong
391 #undef atomic_and_64
392 #undef atomic_and_32_nv
393 #undef atomic_and_uint_nv
394 #undef atomic_and_ulong_nv
395 #undef atomic_and_64_nv
396 #undef atomic_or_32
397 #undef atomic_or_uint
398 #undef atomic_or_ulong
399 #undef atomic_or_64
400 #undef atomic_or_32_nv
401 #undef atomic_or_uint_nv
402 #undef atomic_or_ulong_nv
403 #undef atomic_or_64_nv
404 #undef atomic_cas_32
405 #undef atomic_cas_uint
406 #undef atomic_cas_ulong
407 #undef atomic_cas_ptr
408 #undef atomic_cas_64
409 #undef atomic_cas_32_ni
410 #undef atomic_cas_uint_ni
411 #undef atomic_cas_ulong_ni
412 #undef atomic_cas_ptr_ni
413 #undef atomic_cas_64_ni
414 #undef atomic_swap_32
415 #undef atomic_swap_uint
416 #undef atomic_swap_ulong
417 #undef atomic_swap_ptr
418 #undef atomic_swap_64
419 #undef atomic_dec_32
420 #undef atomic_dec_uint
421 #undef atomic_dec_ulong
422 #undef atomic_dec_ptr
423 #undef atomic_dec_64
424 #undef atomic_dec_32_nv
425 #undef atomic_dec_uint_nv
426 #undef atomic_dec_ulong_nv
427 #undef atomic_dec_ptr_nv
428 #undef atomic_dec_64_nv
429 #undef atomic_inc_32
430 #undef atomic_inc_uint
431 #undef atomic_inc_ulong
432 #undef atomic_inc_ptr
433 #undef atomic_inc_64
434 #undef atomic_inc_32_nv
435 #undef atomic_inc_uint_nv
436 #undef atomic_inc_ulong_nv
437 #undef atomic_inc_ptr_nv
438 #undef atomic_inc_64_nv
439 
440 #define CSAN_ATOMIC_FUNC_ADD(name, tret, targ1, targ2) \
441 	void atomic_add_##name(volatile targ1 *, targ2); \
442 	void kcsan_atomic_add_##name(volatile targ1 *, targ2); \
443 	void kcsan_atomic_add_##name(volatile targ1 *ptr, targ2 val) \
444 	{ \
445 		kcsan_access((uintptr_t)ptr, sizeof(tret), true, true, \
446 		    __RET_ADDR); \
447 		atomic_add_##name(ptr, val); \
448 	} \
449 	tret atomic_add_##name##_nv(volatile targ1 *, targ2); \
450 	tret kcsan_atomic_add_##name##_nv(volatile targ1 *, targ2); \
451 	tret kcsan_atomic_add_##name##_nv(volatile targ1 *ptr, targ2 val) \
452 	{ \
453 		kcsan_access((uintptr_t)ptr, sizeof(tret), true, true, \
454 		    __RET_ADDR); \
455 		return atomic_add_##name##_nv(ptr, val); \
456 	}
457 
458 #define CSAN_ATOMIC_FUNC_AND(name, tret, targ1, targ2) \
459 	void atomic_and_##name(volatile targ1 *, targ2); \
460 	void kcsan_atomic_and_##name(volatile targ1 *, targ2); \
461 	void kcsan_atomic_and_##name(volatile targ1 *ptr, targ2 val) \
462 	{ \
463 		kcsan_access((uintptr_t)ptr, sizeof(tret), true, true, \
464 		    __RET_ADDR); \
465 		atomic_and_##name(ptr, val); \
466 	} \
467 	tret atomic_and_##name##_nv(volatile targ1 *, targ2); \
468 	tret kcsan_atomic_and_##name##_nv(volatile targ1 *, targ2); \
469 	tret kcsan_atomic_and_##name##_nv(volatile targ1 *ptr, targ2 val) \
470 	{ \
471 		kcsan_access((uintptr_t)ptr, sizeof(tret), true, true, \
472 		    __RET_ADDR); \
473 		return atomic_and_##name##_nv(ptr, val); \
474 	}
475 
476 #define CSAN_ATOMIC_FUNC_OR(name, tret, targ1, targ2) \
477 	void atomic_or_##name(volatile targ1 *, targ2); \
478 	void kcsan_atomic_or_##name(volatile targ1 *, targ2); \
479 	void kcsan_atomic_or_##name(volatile targ1 *ptr, targ2 val) \
480 	{ \
481 		kcsan_access((uintptr_t)ptr, sizeof(tret), true, true, \
482 		    __RET_ADDR); \
483 		atomic_or_##name(ptr, val); \
484 	} \
485 	tret atomic_or_##name##_nv(volatile targ1 *, targ2); \
486 	tret kcsan_atomic_or_##name##_nv(volatile targ1 *, targ2); \
487 	tret kcsan_atomic_or_##name##_nv(volatile targ1 *ptr, targ2 val) \
488 	{ \
489 		kcsan_access((uintptr_t)ptr, sizeof(tret), true, true, \
490 		    __RET_ADDR); \
491 		return atomic_or_##name##_nv(ptr, val); \
492 	}
493 
494 #define CSAN_ATOMIC_FUNC_CAS(name, tret, targ1, targ2) \
495 	tret atomic_cas_##name(volatile targ1 *, targ2, targ2); \
496 	tret kcsan_atomic_cas_##name(volatile targ1 *, targ2, targ2); \
497 	tret kcsan_atomic_cas_##name(volatile targ1 *ptr, targ2 exp, targ2 new) \
498 	{ \
499 		kcsan_access((uintptr_t)ptr, sizeof(tret), true, true, \
500 		    __RET_ADDR); \
501 		return atomic_cas_##name(ptr, exp, new); \
502 	} \
503 	tret atomic_cas_##name##_ni(volatile targ1 *, targ2, targ2); \
504 	tret kcsan_atomic_cas_##name##_ni(volatile targ1 *, targ2, targ2); \
505 	tret kcsan_atomic_cas_##name##_ni(volatile targ1 *ptr, targ2 exp, targ2 new) \
506 	{ \
507 		kcsan_access((uintptr_t)ptr, sizeof(tret), true, true, \
508 		    __RET_ADDR); \
509 		return atomic_cas_##name##_ni(ptr, exp, new); \
510 	}
511 
512 #define CSAN_ATOMIC_FUNC_SWAP(name, tret, targ1, targ2) \
513 	tret atomic_swap_##name(volatile targ1 *, targ2); \
514 	tret kcsan_atomic_swap_##name(volatile targ1 *, targ2); \
515 	tret kcsan_atomic_swap_##name(volatile targ1 *ptr, targ2 val) \
516 	{ \
517 		kcsan_access((uintptr_t)ptr, sizeof(tret), true, true, \
518 		    __RET_ADDR); \
519 		return atomic_swap_##name(ptr, val); \
520 	}
521 
522 #define CSAN_ATOMIC_FUNC_DEC(name, tret, targ1) \
523 	void atomic_dec_##name(volatile targ1 *); \
524 	void kcsan_atomic_dec_##name(volatile targ1 *); \
525 	void kcsan_atomic_dec_##name(volatile targ1 *ptr) \
526 	{ \
527 		kcsan_access((uintptr_t)ptr, sizeof(tret), true, true, \
528 		    __RET_ADDR); \
529 		atomic_dec_##name(ptr); \
530 	} \
531 	tret atomic_dec_##name##_nv(volatile targ1 *); \
532 	tret kcsan_atomic_dec_##name##_nv(volatile targ1 *); \
533 	tret kcsan_atomic_dec_##name##_nv(volatile targ1 *ptr) \
534 	{ \
535 		kcsan_access((uintptr_t)ptr, sizeof(tret), true, true, \
536 		    __RET_ADDR); \
537 		return atomic_dec_##name##_nv(ptr); \
538 	}
539 
540 #define CSAN_ATOMIC_FUNC_INC(name, tret, targ1) \
541 	void atomic_inc_##name(volatile targ1 *); \
542 	void kcsan_atomic_inc_##name(volatile targ1 *); \
543 	void kcsan_atomic_inc_##name(volatile targ1 *ptr) \
544 	{ \
545 		kcsan_access((uintptr_t)ptr, sizeof(tret), true, true, \
546 		    __RET_ADDR); \
547 		atomic_inc_##name(ptr); \
548 	} \
549 	tret atomic_inc_##name##_nv(volatile targ1 *); \
550 	tret kcsan_atomic_inc_##name##_nv(volatile targ1 *); \
551 	tret kcsan_atomic_inc_##name##_nv(volatile targ1 *ptr) \
552 	{ \
553 		kcsan_access((uintptr_t)ptr, sizeof(tret), true, true, \
554 		    __RET_ADDR); \
555 		return atomic_inc_##name##_nv(ptr); \
556 	}
557 
558 CSAN_ATOMIC_FUNC_ADD(32, uint32_t, uint32_t, int32_t);
559 CSAN_ATOMIC_FUNC_ADD(64, uint64_t, uint64_t, int64_t);
560 CSAN_ATOMIC_FUNC_ADD(int, unsigned int, unsigned int, int);
561 CSAN_ATOMIC_FUNC_ADD(long, unsigned long, unsigned long, long);
562 CSAN_ATOMIC_FUNC_ADD(ptr, void *, void, ssize_t);
563 
564 CSAN_ATOMIC_FUNC_AND(32, uint32_t, uint32_t, uint32_t);
565 CSAN_ATOMIC_FUNC_AND(64, uint64_t, uint64_t, uint64_t);
566 CSAN_ATOMIC_FUNC_AND(uint, unsigned int, unsigned int, unsigned int);
567 CSAN_ATOMIC_FUNC_AND(ulong, unsigned long, unsigned long, unsigned long);
568 
569 CSAN_ATOMIC_FUNC_OR(32, uint32_t, uint32_t, uint32_t);
570 CSAN_ATOMIC_FUNC_OR(64, uint64_t, uint64_t, uint64_t);
571 CSAN_ATOMIC_FUNC_OR(uint, unsigned int, unsigned int, unsigned int);
572 CSAN_ATOMIC_FUNC_OR(ulong, unsigned long, unsigned long, unsigned long);
573 
574 CSAN_ATOMIC_FUNC_CAS(32, uint32_t, uint32_t, uint32_t);
575 CSAN_ATOMIC_FUNC_CAS(64, uint64_t, uint64_t, uint64_t);
576 CSAN_ATOMIC_FUNC_CAS(uint, unsigned int, unsigned int, unsigned int);
577 CSAN_ATOMIC_FUNC_CAS(ulong, unsigned long, unsigned long, unsigned long);
578 CSAN_ATOMIC_FUNC_CAS(ptr, void *, void, void *);
579 
580 CSAN_ATOMIC_FUNC_SWAP(32, uint32_t, uint32_t, uint32_t);
581 CSAN_ATOMIC_FUNC_SWAP(64, uint64_t, uint64_t, uint64_t);
582 CSAN_ATOMIC_FUNC_SWAP(uint, unsigned int, unsigned int, unsigned int);
583 CSAN_ATOMIC_FUNC_SWAP(ulong, unsigned long, unsigned long, unsigned long);
584 CSAN_ATOMIC_FUNC_SWAP(ptr, void *, void, void *);
585 
586 CSAN_ATOMIC_FUNC_DEC(32, uint32_t, uint32_t)
587 CSAN_ATOMIC_FUNC_DEC(64, uint64_t, uint64_t)
588 CSAN_ATOMIC_FUNC_DEC(uint, unsigned int, unsigned int);
589 CSAN_ATOMIC_FUNC_DEC(ulong, unsigned long, unsigned long);
590 CSAN_ATOMIC_FUNC_DEC(ptr, void *, void);
591 
592 CSAN_ATOMIC_FUNC_INC(32, uint32_t, uint32_t)
593 CSAN_ATOMIC_FUNC_INC(64, uint64_t, uint64_t)
594 CSAN_ATOMIC_FUNC_INC(uint, unsigned int, unsigned int);
595 CSAN_ATOMIC_FUNC_INC(ulong, unsigned long, unsigned long);
596 CSAN_ATOMIC_FUNC_INC(ptr, void *, void);
597 
598 void
599 kcsan_atomic_load(const volatile void *p, void *v, int size)
600 {
601 	kcsan_access((uintptr_t)p, size, false, true, __RET_ADDR);
602 	switch (size) {
603 	case 1: *(uint8_t *)v = *(const volatile uint8_t *)p; break;
604 	case 2: *(uint16_t *)v = *(const volatile uint16_t *)p; break;
605 	case 4: *(uint32_t *)v = *(const volatile uint32_t *)p; break;
606 	case 8: *(uint64_t *)v = *(const volatile uint64_t *)p; break;
607 	}
608 }
609 
610 void
611 kcsan_atomic_store(volatile void *p, const void *v, int size)
612 {
613 	kcsan_access((uintptr_t)p, size, true, true, __RET_ADDR);
614 	switch (size) {
615 	case 1: *(volatile uint8_t *)p = *(const uint8_t *)v; break;
616 	case 2: *(volatile uint16_t *)p = *(const uint16_t *)v; break;
617 	case 4: *(volatile uint32_t *)p = *(const uint32_t *)v; break;
618 	case 8: *(volatile uint64_t *)p = *(const uint64_t *)v; break;
619 	}
620 }
621 
622 /* -------------------------------------------------------------------------- */
623 
624 #include <sys/bus.h>
625 
626 #undef bus_space_read_multi_1
627 #undef bus_space_read_multi_2
628 #undef bus_space_read_multi_4
629 #undef bus_space_read_multi_8
630 #undef bus_space_read_multi_stream_1
631 #undef bus_space_read_multi_stream_2
632 #undef bus_space_read_multi_stream_4
633 #undef bus_space_read_multi_stream_8
634 #undef bus_space_read_region_1
635 #undef bus_space_read_region_2
636 #undef bus_space_read_region_4
637 #undef bus_space_read_region_8
638 #undef bus_space_read_region_stream_1
639 #undef bus_space_read_region_stream_2
640 #undef bus_space_read_region_stream_4
641 #undef bus_space_read_region_stream_8
642 #undef bus_space_write_multi_1
643 #undef bus_space_write_multi_2
644 #undef bus_space_write_multi_4
645 #undef bus_space_write_multi_8
646 #undef bus_space_write_multi_stream_1
647 #undef bus_space_write_multi_stream_2
648 #undef bus_space_write_multi_stream_4
649 #undef bus_space_write_multi_stream_8
650 #undef bus_space_write_region_1
651 #undef bus_space_write_region_2
652 #undef bus_space_write_region_4
653 #undef bus_space_write_region_8
654 #undef bus_space_write_region_stream_1
655 #undef bus_space_write_region_stream_2
656 #undef bus_space_write_region_stream_4
657 #undef bus_space_write_region_stream_8
658 
659 #define CSAN_BUS_READ_FUNC(bytes, bits) \
660 	void bus_space_read_multi_##bytes(bus_space_tag_t, bus_space_handle_t,	\
661 	    bus_size_t, uint##bits##_t *, bus_size_t);				\
662 	void kcsan_bus_space_read_multi_##bytes(bus_space_tag_t,		\
663 	    bus_space_handle_t, bus_size_t, uint##bits##_t *, bus_size_t);	\
664 	void kcsan_bus_space_read_multi_##bytes(bus_space_tag_t tag,		\
665 	    bus_space_handle_t hnd, bus_size_t size, uint##bits##_t *buf,	\
666 	    bus_size_t count)							\
667 	{									\
668 		kcsan_access((uintptr_t)buf, sizeof(uint##bits##_t) * count,	\
669 		    false, false, __RET_ADDR);					\
670 		bus_space_read_multi_##bytes(tag, hnd, size, buf, count);	\
671 	}									\
672 	void bus_space_read_multi_stream_##bytes(bus_space_tag_t,		\
673 	    bus_space_handle_t, bus_size_t, uint##bits##_t *, bus_size_t);	\
674 	void kcsan_bus_space_read_multi_stream_##bytes(bus_space_tag_t,		\
675 	    bus_space_handle_t, bus_size_t, uint##bits##_t *, bus_size_t);	\
676 	void kcsan_bus_space_read_multi_stream_##bytes(bus_space_tag_t tag,	\
677 	    bus_space_handle_t hnd, bus_size_t size, uint##bits##_t *buf,	\
678 	    bus_size_t count)							\
679 	{									\
680 		kcsan_access((uintptr_t)buf, sizeof(uint##bits##_t) * count,	\
681 		    false, false, __RET_ADDR);					\
682 		bus_space_read_multi_stream_##bytes(tag, hnd, size, buf, count);\
683 	}									\
684 	void bus_space_read_region_##bytes(bus_space_tag_t, bus_space_handle_t,	\
685 	    bus_size_t, uint##bits##_t *, bus_size_t);				\
686 	void kcsan_bus_space_read_region_##bytes(bus_space_tag_t,		\
687 	    bus_space_handle_t, bus_size_t, uint##bits##_t *, bus_size_t);	\
688 	void kcsan_bus_space_read_region_##bytes(bus_space_tag_t tag,		\
689 	    bus_space_handle_t hnd, bus_size_t size, uint##bits##_t *buf,	\
690 	    bus_size_t count)							\
691 	{									\
692 		kcsan_access((uintptr_t)buf, sizeof(uint##bits##_t) * count,	\
693 		    false, false, __RET_ADDR);					\
694 		bus_space_read_region_##bytes(tag, hnd, size, buf, count);	\
695 	}									\
696 	void bus_space_read_region_stream_##bytes(bus_space_tag_t,		\
697 	    bus_space_handle_t, bus_size_t, uint##bits##_t *, bus_size_t);	\
698 	void kcsan_bus_space_read_region_stream_##bytes(bus_space_tag_t,	\
699 	    bus_space_handle_t, bus_size_t, uint##bits##_t *, bus_size_t);	\
700 	void kcsan_bus_space_read_region_stream_##bytes(bus_space_tag_t tag,	\
701 	    bus_space_handle_t hnd, bus_size_t size, uint##bits##_t *buf,	\
702 	    bus_size_t count)							\
703 	{									\
704 		kcsan_access((uintptr_t)buf, sizeof(uint##bits##_t) * count,	\
705 		    false, false, __RET_ADDR);					\
706 		bus_space_read_region_stream_##bytes(tag, hnd, size, buf, count);\
707 	}
708 
709 #define CSAN_BUS_WRITE_FUNC(bytes, bits) \
710 	void bus_space_write_multi_##bytes(bus_space_tag_t, bus_space_handle_t,	\
711 	    bus_size_t, const uint##bits##_t *, bus_size_t);			\
712 	void kcsan_bus_space_write_multi_##bytes(bus_space_tag_t,		\
713 	    bus_space_handle_t, bus_size_t, const uint##bits##_t *, bus_size_t);\
714 	void kcsan_bus_space_write_multi_##bytes(bus_space_tag_t tag,		\
715 	    bus_space_handle_t hnd, bus_size_t size, const uint##bits##_t *buf,	\
716 	    bus_size_t count)							\
717 	{									\
718 		kcsan_access((uintptr_t)buf, sizeof(uint##bits##_t) * count,	\
719 		    true, false, __RET_ADDR);					\
720 		bus_space_write_multi_##bytes(tag, hnd, size, buf, count);	\
721 	}									\
722 	void bus_space_write_multi_stream_##bytes(bus_space_tag_t,		\
723 	    bus_space_handle_t, bus_size_t, const uint##bits##_t *, bus_size_t);\
724 	void kcsan_bus_space_write_multi_stream_##bytes(bus_space_tag_t,	\
725 	    bus_space_handle_t, bus_size_t, const uint##bits##_t *, bus_size_t);\
726 	void kcsan_bus_space_write_multi_stream_##bytes(bus_space_tag_t tag,	\
727 	    bus_space_handle_t hnd, bus_size_t size, const uint##bits##_t *buf,	\
728 	    bus_size_t count)							\
729 	{									\
730 		kcsan_access((uintptr_t)buf, sizeof(uint##bits##_t) * count,	\
731 		    true, false, __RET_ADDR);					\
732 		bus_space_write_multi_stream_##bytes(tag, hnd, size, buf, count);\
733 	}									\
734 	void bus_space_write_region_##bytes(bus_space_tag_t, bus_space_handle_t,\
735 	    bus_size_t, const uint##bits##_t *, bus_size_t);			\
736 	void kcsan_bus_space_write_region_##bytes(bus_space_tag_t,		\
737 	    bus_space_handle_t, bus_size_t, const uint##bits##_t *, bus_size_t);\
738 	void kcsan_bus_space_write_region_##bytes(bus_space_tag_t tag,		\
739 	    bus_space_handle_t hnd, bus_size_t size, const uint##bits##_t *buf,	\
740 	    bus_size_t count)							\
741 	{									\
742 		kcsan_access((uintptr_t)buf, sizeof(uint##bits##_t) * count,	\
743 		    true, false, __RET_ADDR);					\
744 		bus_space_write_region_##bytes(tag, hnd, size, buf, count);	\
745 	}									\
746 	void bus_space_write_region_stream_##bytes(bus_space_tag_t,		\
747 	    bus_space_handle_t, bus_size_t, const uint##bits##_t *, bus_size_t);\
748 	void kcsan_bus_space_write_region_stream_##bytes(bus_space_tag_t,	\
749 	    bus_space_handle_t, bus_size_t, const uint##bits##_t *, bus_size_t);\
750 	void kcsan_bus_space_write_region_stream_##bytes(bus_space_tag_t tag,	\
751 	    bus_space_handle_t hnd, bus_size_t size, const uint##bits##_t *buf,	\
752 	    bus_size_t count)							\
753 	{									\
754 		kcsan_access((uintptr_t)buf, sizeof(uint##bits##_t) * count,	\
755 		    true, false, __RET_ADDR);					\
756 		bus_space_write_region_stream_##bytes(tag, hnd, size, buf, count);\
757 	}
758 
759 CSAN_BUS_READ_FUNC(1, 8)
760 CSAN_BUS_READ_FUNC(2, 16)
761 CSAN_BUS_READ_FUNC(4, 32)
762 CSAN_BUS_READ_FUNC(8, 64)
763 
764 CSAN_BUS_WRITE_FUNC(1, 8)
765 CSAN_BUS_WRITE_FUNC(2, 16)
766 CSAN_BUS_WRITE_FUNC(4, 32)
767 CSAN_BUS_WRITE_FUNC(8, 64)
768