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