1 /*
2 * Support file for AMDGCN in newlib.
3 * Copyright (c) 2017 Mentor Graphics.
4 *
5 * The authors hereby grant permission to use, copy, modify, distribute,
6 * and license this software and its documentation for any purpose, provided
7 * that existing copyright notices are retained in all copies and that this
8 * notice is included verbatim in any distributions. No written agreement,
9 * license, or royalty fee is required for any of the authorized uses.
10 * Modifications to this software may be copyrighted by their authors
11 * and need not follow the licensing terms described here, provided that
12 * the new terms are clearly indicated on the first page of each file where
13 * they apply.
14 */
15
16 #include <picolibc.h>
17
18 #include <stdlib.h>
19 #include <stdint.h>
20 #include <reent.h>
21
22 /* _sbrk_r expects us to use the real errno, not the reentrant one. */
23 #include <errno.h>
24 #undef errno
25 extern int errno;
26
27 /* The runtime passes in heap space like this. */
28 struct heap {
29 int64_t size;
30 char data[0];
31 };
32
33 static char *__heap_ptr = (char*)-1;
34 static char *__heap_end = (char*)-1;
35 static int __heap_lock = 0;
36 static void *__heap_lock_id = NULL;
37 static int __heap_lock_cnt = 0;
38
39 void *
sbrk(ptrdiff_t nbytes)40 sbrk (ptrdiff_t nbytes)
41 {
42 if (__heap_ptr == (char *)-1)
43 {
44 /* Find the heap from kernargs. */
45 char *kernargs;
46 #if defined(__has_builtin) && __has_builtin(__builtin_gcn_kernarg_ptr)
47 kernargs = __builtin_gcn_kernarg_ptr ();
48 #else
49 /* The kernargs pointer is in s[8:9].
50 This will break if the enable_sgpr_* flags are ever changed. */
51 __asm__ ("s_mov_b64 %0, s[8:9]" : "=Sg"(kernargs));
52 #endif
53
54 /* The heap data is at kernargs[3]. */
55 struct heap *heap = *(struct heap **)(kernargs + 24);
56
57 __heap_ptr = heap->data;
58 __heap_end = __heap_ptr + heap->size;
59 }
60
61 if ((__heap_ptr + nbytes) >= __heap_end)
62 {
63 errno = ENOMEM;
64 return (void*)-1;
65 }
66
67 char *base = __heap_ptr;
68 __heap_ptr += nbytes;
69
70 return base;
71 }
72
73 void
__malloc_lock(struct _reent * reent)74 __malloc_lock (struct _reent *reent)
75 {
76 void *id = reent;
77
78 if (id == __heap_lock_id)
79 {
80 if (__heap_lock_cnt < 1)
81 abort ();
82 ++__heap_lock_cnt;
83 return;
84 }
85
86 while (__sync_lock_test_and_set (&__heap_lock, 1))
87 /* A sleep seems like it should allow the wavefront to yeild (maybe?)
88 Use the shortest possible sleep time of 1*64 cycles. */
89 __asm__ volatile ("s_sleep\t1" ::: "memory");
90
91 if (__heap_lock_id != NULL)
92 abort ();
93 if (__heap_lock_cnt != 0)
94 abort ();
95
96 __heap_lock_cnt = 1;
97 __heap_lock_id = id;
98 }
99
100 void
__malloc_unlock(struct _reent * reent)101 __malloc_unlock (struct _reent *reent)
102 {
103 void *id = reent;
104
105 if (id != __heap_lock_id)
106 abort ();
107 if (__heap_lock_cnt < 1)
108 abort ();
109
110 --__heap_lock_cnt;
111
112 if (__heap_lock_cnt > 0)
113 return;
114
115 __heap_lock_id = NULL;
116 __sync_lock_release (&__heap_lock);
117 }
118