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 <stdlib.h>
17 #include <stdint.h>
18 #include <reent.h>
19
20 /* _sbrk_r expects us to use the real errno, not the reentrant one. */
21 #include <errno.h>
22 #undef errno
23 extern int errno;
24
25 /* The runtime passes in heap space like this. */
26 struct heap {
27 int64_t size;
28 char data[0];
29 };
30
31 static char *__heap_ptr = (char*)-1;
32 static char *__heap_end = (char*)-1;
33 static int __heap_lock = 0;
34 static void *__heap_lock_id = NULL;
35 static int __heap_lock_cnt = 0;
36
37 void *
sbrk(ptrdiff_t nbytes)38 sbrk (ptrdiff_t nbytes)
39 {
40 if (__heap_ptr == (char *)-1)
41 {
42 /* Find the heap from kernargs. */
43 char *kernargs;
44 #if defined(__has_builtin) && __has_builtin(__builtin_gcn_kernarg_ptr)
45 kernargs = __builtin_gcn_kernarg_ptr ();
46 #else
47 /* The kernargs pointer is in s[8:9].
48 This will break if the enable_sgpr_* flags are ever changed. */
49 __asm__ ("s_mov_b64 %0, s[8:9]" : "=Sg"(kernargs));
50 #endif
51
52 /* The heap data is at kernargs[3]. */
53 struct heap *heap = *(struct heap **)(kernargs + 24);
54
55 __heap_ptr = heap->data;
56 __heap_end = __heap_ptr + heap->size;
57 }
58
59 if ((__heap_ptr + nbytes) >= __heap_end)
60 {
61 errno = ENOMEM;
62 return (void*)-1;
63 }
64
65 char *base = __heap_ptr;
66 __heap_ptr += nbytes;
67
68 return base;
69 }
70
71 void
__malloc_lock(struct _reent * reent)72 __malloc_lock (struct _reent *reent)
73 {
74 void *id = reent;
75
76 if (id == __heap_lock_id)
77 {
78 if (__heap_lock_cnt < 1)
79 abort ();
80 ++__heap_lock_cnt;
81 return;
82 }
83
84 while (__sync_lock_test_and_set (&__heap_lock, 1))
85 /* A sleep seems like it should allow the wavefront to yeild (maybe?)
86 Use the shortest possible sleep time of 1*64 cycles. */
87 __asm__ volatile ("s_sleep\t1" ::: "memory");
88
89 if (__heap_lock_id != NULL)
90 abort ();
91 if (__heap_lock_cnt != 0)
92 abort ();
93
94 __heap_lock_cnt = 1;
95 __heap_lock_id = id;
96 }
97
98 void
__malloc_unlock(struct _reent * reent)99 __malloc_unlock (struct _reent *reent)
100 {
101 void *id = reent;
102
103 if (id != __heap_lock_id)
104 abort ();
105 if (__heap_lock_cnt < 1)
106 abort ();
107
108 --__heap_lock_cnt;
109
110 if (__heap_lock_cnt > 0)
111 return;
112
113 __heap_lock_id = NULL;
114 __sync_lock_release (&__heap_lock);
115 }
116