2016-07-13 Thomas Preud'homme <thomas.preudhomme@arm.com>
[official-gcc.git] / libmpx / mpxwrap / mpx_wrappers.c
blob171a780311d3295b418525c60307457a7472190d
1 /* MPX Wrappers Library
2 Copyright (C) 2014 Free Software Foundation, Inc.
3 Contributed by Ilya Enkovich (ilya.enkovich@intel.com)
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 <http://www.gnu.org/licenses/>. */
26 #include "stdlib.h"
27 #include "string.h"
28 #include <sys/mman.h>
29 #include <stdint.h>
30 #include <assert.h>
31 #include "mpxrt/mpxrt.h"
33 void *
34 __mpx_wrapper_malloc (size_t size)
36 void *p = (void *)malloc (size);
37 if (!p) return __bnd_null_ptr_bounds (p);
38 return __bnd_set_ptr_bounds (p, size);
42 void *
43 __mpx_wrapper_mmap (void *addr, size_t length, int prot, int flags,
44 int fd, off_t offset)
46 void *p = mmap (addr, length, prot, flags, fd, offset);
47 if (!p) return __bnd_null_ptr_bounds (p);
48 return __bnd_set_ptr_bounds (p, length);
51 void *
52 __mpx_wrapper_realloc (void *ptr, size_t n)
54 if (!ptr)
55 return __mpx_wrapper_malloc (n);
57 /* We don't kwnow how much data is copied by realloc
58 and therefore may check only lower bounds. */
59 __bnd_chk_ptr_lbounds (ptr);
60 ptr = realloc (ptr, n);
62 if (!ptr)
63 return __bnd_null_ptr_bounds (ptr);
65 return __bnd_set_ptr_bounds (ptr, n);
68 void *
69 __mpx_wrapper_calloc (size_t n_elements, size_t element_size)
71 void *p = calloc (n_elements, element_size);
72 if (!p)
73 return __bnd_null_ptr_bounds (p);
74 return __bnd_set_ptr_bounds (p, n_elements * element_size);
77 void *
78 __mpx_wrapper_memset (void *dstpp, int c, size_t len)
80 if (len > 0)
82 __bnd_chk_ptr_bounds (dstpp, len);
83 memset (dstpp, c, len);
85 return dstpp;
88 void
89 __mpx_wrapper_bzero (void *dst, size_t len)
91 __mpx_wrapper_memset (dst, 0, len);
94 /* The mpx_pointer type is used for getting bits
95 for bt_index (index in bounds table) and
96 bd_index (index in bounds directory). */
97 typedef union
99 struct
101 unsigned long ignored:NUM_IGN_BITS;
102 unsigned long l2entry:NUM_L2_BITS;
103 unsigned long l1index:NUM_L1_BITS;
105 void *pointer;
106 } mpx_pointer;
108 /* The mpx_bt_entry struct represents a cell in bounds table.
109 lb is the lower bound, ub is the upper bound,
110 p is the stored pointer. */
111 struct mpx_bt_entry
113 void *lb;
114 void *ub;
115 void *p;
116 void *reserved;
119 /* A special type for bd is needed because bt addresses can be modified. */
120 typedef struct mpx_bt_entry * volatile * bd_type;
122 /* Function alloc_bt is used for allocating bounds table
123 for the destination pointers if we don't have one.
124 We generate a bounds store for some pointer belonging
125 to that table and kernel allocates the table for us. */
126 static inline void __attribute__ ((bnd_legacy))
127 alloc_bt (void *ptr)
129 __asm__ __volatile__ ("bndstx %%bnd0, (%0,%0)"::"r" (ptr):"%bnd0");
132 /* get_bt returns address of bounds table that should
133 exist at BD[BD_INDEX]. If there is no address or the address is not valid,
134 we try to allocate a valid table.
135 If we succeed in getting bt, its address will be returned.
136 If we can't get a valid bt, NULL will be returned. */
137 __attribute__ ((bnd_legacy)) static inline struct mpx_bt_entry *
138 get_bt (unsigned bd_index, bd_type bd)
140 struct mpx_bt_entry *bt = (struct mpx_bt_entry *) ((uintptr_t) bd[bd_index]
141 & MPX_L2_ADDR_MASK);
142 if (!(bt) || !((uintptr_t) bd[bd_index] & MPX_L2_VALID_MASK))
144 mpx_pointer ptr;
145 ptr.l1index = bd_index;
146 /* If we don't have BT, allocate it. */
147 alloc_bt (ptr.pointer);
148 bt = (struct mpx_bt_entry *) ((uintptr_t) bd[bd_index]
149 & MPX_L2_ADDR_MASK);
150 if (!(bt) || !((uintptr_t) bd[bd_index] & MPX_L2_VALID_MASK))
151 return NULL;
153 return bt;
156 /* Function copy_if_possible moves elements from *FROM to *TO.
157 If ELEMS is less then the ELEMS_TO_COPY (elements we can copy),
158 it copies ELEMS elements and returns 0.
159 Otherwise, it copies ELEMS_TO_COPY elements and returns 1. */
160 __attribute__ ((bnd_legacy)) static inline int
161 copy_if_possible (int elems, int elems_to_copy, struct mpx_bt_entry *from,
162 struct mpx_bt_entry *to)
164 if (elems < elems_to_copy)
165 memmove (to, from, elems * sizeof (struct mpx_bt_entry));
166 else
168 memmove (to, from, elems_to_copy * sizeof (struct mpx_bt_entry));
169 return 1;
171 return 0;
174 /* Function copy_if_possible_from_end moves elements ending at *SRC_END
175 to the place where they will end at *DST_END.
176 If ELEMS is less then the ELEMS_TO_COPY (elements we can copy),
177 function copies ELEMS elements and returns 0.
178 Otherwise, it copies ELEMS_TO_COPY elements and returns 1. */
179 __attribute__ ((bnd_legacy)) static inline int
180 copy_if_possible_from_end (int elems, int elems_to_copy, struct mpx_bt_entry
181 *src_end, struct mpx_bt_entry *dst_end)
183 if (elems < elems_to_copy)
184 memmove (dst_end - elems, src_end - elems,
185 elems * sizeof (struct mpx_bt_entry));
186 else
188 memmove (dst_end - elems_to_copy,
189 src_end - elems_to_copy,
190 elems_to_copy * sizeof (struct mpx_bt_entry));
191 return 1;
193 return 0;
196 /* move_bounds function copies bounds for N bytes from bt of SRC to bt of DST.
197 It also copies bounds for all pointers inside.
198 There are 3 parts of the algorithm:
199 1) We copy everything till the end of the first bounds table of SRC
200 2) In loop we copy whole bound tables till the second-last one
201 3) Data in the last bounds table is copied separately, after the loop.
202 If one of bound tables in SRC doesn't exist,
203 we skip it because there are no pointers.
204 Depending on the arrangement of SRC and DST we copy from the beginning
205 or from the end. */
206 __attribute__ ((bnd_legacy)) static void
207 move_bounds (void *dst, const void *src, size_t n)
209 bd_type bd = (bd_type)get_bd ();
210 if (!(bd))
211 return;
213 /* We get indexes for all tables and number of elements for BT. */
214 unsigned long bt_num_of_elems = (1UL << NUM_L2_BITS);
215 mpx_pointer addr_src, addr_dst, addr_src_end, addr_dst_end;
216 addr_src.pointer = (char *) src;
217 addr_dst.pointer = (char *) dst;
218 addr_src_end.pointer = (char *) src + n - 1;
219 addr_dst_end.pointer = (char *) dst + n - 1;
220 unsigned dst_bd_index = addr_dst.l1index;
221 unsigned src_bd_index = addr_src.l1index;
222 unsigned dst_bt_index = addr_dst.l2entry;
223 unsigned src_bt_index = addr_src.l2entry;
225 unsigned dst_bd_index_end = addr_dst_end.l1index;
226 unsigned src_bd_index_end = addr_src_end.l1index;
227 unsigned dst_bt_index_end = addr_dst_end.l2entry;
228 unsigned src_bt_index_end = addr_src_end.l2entry;
230 int elems_to_copy = src_bt_index_end - src_bt_index + 1 + (src_bd_index_end
231 - src_bd_index) * bt_num_of_elems;
232 struct mpx_bt_entry *bt_src, *bt_dst;
233 uintptr_t bt_valid;
234 /* size1 and size2 will be used to find out what portions
235 can be used to copy data. */
236 int size1_elem, size2_elem, size1_bytes, size2_bytes;
238 /* Copy from the beginning. */
239 if (((char *) src - (char *) dst) > 0)
241 /* Copy everything till the end of the first bounds table (src) */
242 bt_src = (struct mpx_bt_entry *) ((uintptr_t) bd[src_bd_index]
243 & MPX_L2_ADDR_MASK);
244 bt_valid = (uintptr_t) bd[src_bd_index] & MPX_L2_VALID_MASK;
246 /* We can copy the whole preliminary piece of data. */
247 if (src_bt_index > dst_bt_index)
249 size1_elem = src_bt_index - dst_bt_index;
250 size2_elem = bt_num_of_elems - size1_elem;
251 size1_bytes = size1_elem * sizeof (struct mpx_bt_entry);
252 size2_bytes = size2_elem * sizeof (struct mpx_bt_entry);
254 /* Check we have bounds to copy. */
255 if (bt_src && bt_valid)
257 bt_dst = get_bt (dst_bd_index, bd);
258 if (!bt_dst)
259 return;
260 if (copy_if_possible (bt_num_of_elems - src_bt_index,
261 elems_to_copy, &(bt_src[src_bt_index]),
262 &(bt_dst[dst_bt_index])))
263 return;
265 elems_to_copy -= bt_num_of_elems - src_bt_index;
267 /* We have to copy preliminary data in two parts. */
268 else
270 size2_elem = dst_bt_index - src_bt_index;
271 size1_elem = bt_num_of_elems - size2_elem;
272 size1_bytes = size1_elem * sizeof (struct mpx_bt_entry);
273 size2_bytes = size2_elem * sizeof (struct mpx_bt_entry);
275 /* Check we have bounds to copy. */
276 if (bt_src && bt_valid)
278 bt_dst = get_bt (dst_bd_index, bd);
279 if (!bt_dst)
280 return;
282 if (copy_if_possible (bt_num_of_elems - dst_bt_index,
283 elems_to_copy, &(bt_src[src_bt_index]),
284 &(bt_dst[dst_bt_index])))
285 return;
286 elems_to_copy -= bt_num_of_elems - dst_bt_index;
288 dst_bd_index++;
290 bt_dst = get_bt (dst_bd_index, bd);
291 if (!bt_dst)
292 return;
293 if (copy_if_possible (size2_elem, elems_to_copy,
294 &(bt_src[size1_elem]), &(bt_dst[0])))
295 return;
296 elems_to_copy -= size2_elem;
298 else
299 elems_to_copy -= bt_num_of_elems - src_bt_index;
301 src_bd_index++;
303 /* For each bounds table check if it's valid and move it. */
304 for (; src_bd_index < src_bd_index_end; src_bd_index++)
306 bt_src = (struct mpx_bt_entry *) ((uintptr_t) bd[src_bd_index]
307 & MPX_L2_ADDR_MASK);
308 bt_valid = (uintptr_t) bd[src_bd_index] & MPX_L2_VALID_MASK;
310 /* Check we have bounds to copy. */
311 if (!bt_src || !bt_valid)
312 dst_bd_index++;
313 else
315 bt_dst = get_bt (dst_bd_index, bd);
316 if (!bt_dst)
317 return;
318 memmove (&(bt_dst[size2_elem]), &(bt_src[0]), size1_bytes);
319 dst_bd_index++;
320 bt_dst = get_bt (dst_bd_index, bd);
321 if (!bt_dst)
322 return;
323 memmove (&(bt_dst[0]), &(bt_src[size1_elem]), size2_bytes);
325 elems_to_copy -= bt_num_of_elems;
328 /* Now we have the last page that may be not full
329 we copy it separately. */
330 if (elems_to_copy > 0)
332 bt_src = (struct mpx_bt_entry *) ((uintptr_t) bd[src_bd_index]
333 & MPX_L2_ADDR_MASK);
334 bt_valid = (uintptr_t) bd[src_bd_index] & MPX_L2_VALID_MASK;
336 /* Check we have bounds to copy. */
337 if (bt_src && bt_valid)
339 bt_dst = get_bt (dst_bd_index, bd);
340 if (!bt_dst)
341 return;
343 if (copy_if_possible (size1_elem, elems_to_copy, &(bt_src[0]),
344 &(bt_dst[size2_elem])))
345 return;
347 elems_to_copy -= size1_elem;
348 dst_bd_index++;
349 bt_dst = get_bt (dst_bd_index, bd);
350 if (!bt_dst)
351 return;
352 memmove (&(bt_dst[0]), &(bt_src[size1_elem]),
353 elems_to_copy * sizeof (struct mpx_bt_entry));
358 /* Copy from the end. */
359 else
361 /* Copy everything till the end of the first bounds table (src) */
362 bt_src = (struct mpx_bt_entry *) ((uintptr_t) bd[src_bd_index_end]
363 & MPX_L2_ADDR_MASK);
364 bt_valid = (uintptr_t) bd[src_bd_index_end] & MPX_L2_VALID_MASK;
366 if (src_bt_index_end <= dst_bt_index_end)
367 /* We can copy the whole preliminary piece of data. */
369 size2_elem = dst_bt_index_end - src_bt_index_end;
370 size1_elem = bt_num_of_elems - size2_elem;
371 size1_bytes = size1_elem * sizeof (struct mpx_bt_entry);
372 size2_bytes = size2_elem * sizeof (struct mpx_bt_entry);
374 /* Check we have bounds to copy. */
375 if (bt_src && bt_valid)
377 bt_dst = get_bt (dst_bd_index_end, bd);
378 if (!bt_dst)
379 return;
381 if (copy_if_possible_from_end (src_bt_index_end + 1,
382 elems_to_copy, &(bt_src[src_bt_index_end + 1]),
383 &(bt_dst[dst_bt_index_end + 1])))
384 return;
386 elems_to_copy -= src_bt_index_end + 1;
388 /* We have to copy preliminary data in two parts. */
389 else
391 size1_elem = src_bt_index_end - dst_bt_index_end;
392 size2_elem = bt_num_of_elems - size1_elem;
393 size1_bytes = size1_elem * sizeof (struct mpx_bt_entry);
394 size2_bytes = size2_elem * sizeof (struct mpx_bt_entry);
396 /* Check we have bounds to copy. */
397 if (bt_src && bt_valid)
399 bt_dst = get_bt (dst_bd_index_end, bd);
400 if (!bt_dst)
401 return;
402 if (copy_if_possible_from_end (dst_bt_index_end + 1,
403 elems_to_copy, &(bt_src[src_bt_index_end + 1]),
404 &(bt_dst[dst_bt_index_end + 1])))
405 return;
406 elems_to_copy -= dst_bt_index_end + 1;
408 dst_bd_index_end--;
410 bt_dst = get_bt (dst_bd_index_end, bd);
411 if (!bt_dst)
412 return;
413 if (copy_if_possible_from_end (size1_elem, elems_to_copy,
414 &(bt_src[size1_elem]), &(bt_dst[bt_num_of_elems])))
415 return;
417 elems_to_copy -= size1_elem;
419 else
420 elems_to_copy -= src_bt_index_end + 1;
422 /* Go to previous table but beware of overflow.
423 We should have copied all required element
424 in case src_bd_index_end is 0. */
425 if (src_bd_index_end)
426 src_bd_index_end--;
427 else
429 assert (!elems_to_copy);
430 return;
432 /* For each bounds table we check if there are valid pointers inside.
433 If there are some, we copy table in pre-counted portions. */
434 for (; src_bd_index_end > src_bd_index; src_bd_index_end--)
436 bt_src = (struct mpx_bt_entry *) ((uintptr_t) bd[src_bd_index_end]
437 & MPX_L2_ADDR_MASK);
438 bt_valid = (uintptr_t) bd[src_bd_index_end] & MPX_L2_VALID_MASK;
439 /* Check we have bounds to copy. */
440 if (!bt_src || !bt_valid)
441 dst_bd_index_end--;
442 else
444 bt_dst = get_bt (dst_bd_index_end, bd);
445 if (!bt_dst)
446 return;
447 memmove (&(bt_dst[0]), &(bt_src[size1_elem]), size2_bytes);
448 dst_bd_index_end--;
449 bt_dst = get_bt (dst_bd_index_end, bd);
450 if (!bt_dst)
451 return;
452 memmove (&(bt_dst[size2_elem]), &(bt_src[0]), size1_bytes);
454 elems_to_copy -= bt_num_of_elems;
457 /* Now we have the last page that may be not full
458 we copy it separately. */
459 if (elems_to_copy > 0)
461 bt_src = (struct mpx_bt_entry *) ((uintptr_t) bd[src_bd_index_end]
462 & MPX_L2_ADDR_MASK);
463 bt_valid = (uintptr_t) bd[src_bd_index_end] & MPX_L2_VALID_MASK;
464 /* Check we have bounds to copy. */
465 if (bt_src && bt_valid)
467 bt_dst = get_bt (dst_bd_index_end, bd);
468 if (!bt_dst)
469 return;
470 if (copy_if_possible_from_end (size2_elem, elems_to_copy,
471 &(bt_src[bt_num_of_elems]), &(bt_dst[size2_elem])))
472 return;
474 elems_to_copy -= size2_elem;
475 dst_bd_index_end--;
476 bt_dst = get_bt (dst_bd_index_end, bd);
477 if (!bt_dst)
478 return;
479 memmove (&(bt_dst[dst_bt_index]), &(bt_src[src_bt_index]),
480 elems_to_copy * sizeof (struct mpx_bt_entry));
484 return;
487 void *
488 __mpx_wrapper_memmove (void *dst, const void *src, size_t n)
490 if (n == 0)
491 return dst;
493 __bnd_chk_ptr_bounds (dst, n);
494 __bnd_chk_ptr_bounds (src, n);
496 /* When we copy exactly one pointer it is faster to
497 just use bndldx + bndstx. */
498 if (n == sizeof (void *))
500 void *const *s = (void *const *) src;
501 void **d = (void **) dst;
502 *d = *s;
503 return dst;
506 memmove (dst, src, n);
508 /* Not necessary to copy bounds if size is less then size of pointer
509 or SRC==DST. */
510 if ((n >= sizeof (void *)) && (src != dst))
511 move_bounds (dst, src, n);
513 return dst;
517 void *
518 __mpx_wrapper_memcpy (void *dst, const void *src, size_t n)
520 return __mpx_wrapper_memmove (dst, src, n);
523 void *
524 __mpx_wrapper_mempcpy (void *dst, const void *src, size_t n)
526 return (char *)__mpx_wrapper_memcpy (dst, src, n) + n;
529 char *
530 __mpx_wrapper_strncat (char *dst, const char *src, size_t n)
532 size_t dst_size = strlen (dst);
533 size_t src_size = strnlen (src, n);
535 __bnd_chk_ptr_bounds (dst, dst_size + src_size + 1);
536 if (src_size < n)
537 __bnd_chk_ptr_bounds (src, src_size + 1);
538 else
539 __bnd_chk_ptr_bounds (src, src_size);
541 strncat (dst, src, n);
543 return dst;
546 char *
547 __mpx_wrapper_strcat (char *dst, const char *src)
549 size_t dst_size = strlen (dst);
550 size_t src_size = strlen (src);
552 __bnd_chk_ptr_bounds (dst, dst_size + src_size + 1);
553 __bnd_chk_ptr_bounds (src, src_size + 1);
555 strcat (dst, src);
557 return dst;
560 char *
561 __mpx_wrapper_stpcpy (char *dst, const char *src)
563 size_t src_size = strlen (src);
565 __bnd_chk_ptr_bounds (dst, src_size + 1);
566 __bnd_chk_ptr_bounds (src, src_size + 1);
568 memcpy (dst, src, src_size + 1);
570 return dst + src_size;
573 char *
574 __mpx_wrapper_stpncpy (char *dst, const char *src, size_t n)
576 size_t src_size = strnlen (src, n);
577 char *res;
579 __bnd_chk_ptr_bounds (dst, n);
580 if (src_size < n)
582 __bnd_chk_ptr_bounds (src, src_size + 1);
583 res = dst + src_size;
585 else
587 __bnd_chk_ptr_bounds (src, src_size);
588 res = dst + n;
591 memcpy (dst, src, src_size);
592 if (n > src_size)
593 memset (dst + src_size, 0, n - src_size);
595 return res;
598 char *
599 __mpx_wrapper_strcpy (char *dst, const char *src)
601 size_t src_size = strlen (src);
603 __bnd_chk_ptr_bounds (dst, src_size + 1);
604 __bnd_chk_ptr_bounds (src, src_size + 1);
606 memcpy (dst, src, src_size + 1);
608 return dst;
611 char *
612 __mpx_wrapper_strncpy (char *dst, const char *src, size_t n)
614 size_t src_size = strnlen (src, n);
616 __bnd_chk_ptr_bounds (dst, n);
617 if (src_size < n)
618 __bnd_chk_ptr_bounds (src, src_size + 1);
619 else
620 __bnd_chk_ptr_bounds (src, src_size);
622 memcpy (dst, src, src_size);
623 if (n > src_size)
624 memset (dst + src_size, 0, n - src_size);
626 return dst;
629 size_t
630 __mpx_wrapper_strlen (const char *s)
632 size_t length = strlen (s);
633 __bnd_chk_ptr_bounds (s, length + 1);
634 return length;