subr_csan.c revision 1.10 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