stdlib.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. /*
  2. * stdlib.c
  3. *
  4. * Copyright (C) 2021 bzt (bztsrc@gitlab)
  5. *
  6. * Permission is hereby granted, free of charge, to any person
  7. * obtaining a copy of this software and associated documentation
  8. * files (the "Software"), to deal in the Software without
  9. * restriction, including without limitation the rights to use, copy,
  10. * modify, merge, publish, distribute, sublicense, and/or sell copies
  11. * of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be
  15. * included in all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  18. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  19. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  20. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  21. * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  22. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  24. * DEALINGS IN THE SOFTWARE.
  25. *
  26. * This file is part of the POSIX-UEFI package.
  27. * @brief Implementing functions which are defined in stdlib.h
  28. *
  29. */
  30. #include <uefi.h>
  31. int errno = 0;
  32. static uint64_t __srand_seed = 6364136223846793005ULL;
  33. extern void __stdio_cleanup(void);
  34. #ifndef UEFI_NO_TRACK_ALLOC
  35. static uintptr_t *__stdlib_allocs = NULL;
  36. static uintn_t __stdlib_numallocs = 0;
  37. #endif
  38. int atoi(const char_t *s)
  39. {
  40. return (int)atol(s);
  41. }
  42. int64_t atol(const char_t *s)
  43. {
  44. int64_t sign = 1;
  45. if(!s || !*s) return 0;
  46. if(*s == CL('-')) { sign = -1; s++; }
  47. if(s[0] == CL('0')) {
  48. if(s[1] == CL('x'))
  49. return strtol(s + 2, NULL, 16) * sign;
  50. if(s[1] >= CL('0') && s[1] <= CL('7'))
  51. return strtol(s, NULL, 8) * sign;
  52. }
  53. return strtol(s, NULL, 10) * sign;
  54. }
  55. int64_t strtol (const char_t *s, char_t **__endptr, int __base)
  56. {
  57. int64_t v=0, sign = 1;
  58. if(!s || !*s) return 0;
  59. if(*s == CL('-')) { sign = -1; s++; }
  60. while(!(*s < CL('0') || (__base < 10 && *s >= __base + CL('0')) || (__base >= 10 && ((*s > CL('9') && *s < CL('A')) ||
  61. (*s > CL('F') && *s < CL('a')) || *s > CL('f'))))) {
  62. v *= __base;
  63. if(*s >= CL('0') && *s <= (__base < 10 ? __base + CL('0') : CL('9')))
  64. v += (*s)-CL('0');
  65. else if(__base == 16 && *s >= CL('a') && *s <= CL('f'))
  66. v += (*s)-CL('a')+10;
  67. else if(__base == 16 && *s >= CL('A') && *s <= CL('F'))
  68. v += (*s)-CL('A')+10;
  69. s++;
  70. }
  71. if(__endptr) *__endptr = (char_t*)s;
  72. return v * sign;
  73. }
  74. void *malloc (size_t __size)
  75. {
  76. void *ret = NULL;
  77. efi_status_t status;
  78. #ifndef UEFI_NO_TRACK_ALLOC
  79. uintn_t i;
  80. for(i = 0; i < __stdlib_numallocs && __stdlib_allocs[i] != 0; i += 2);
  81. if(i == __stdlib_numallocs) {
  82. /* no free slots found, (re)allocate the housekeeping array */
  83. status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, (__stdlib_numallocs + 2) * sizeof(uintptr_t), &ret);
  84. if(EFI_ERROR(status) || !ret) { errno = ENOMEM; return NULL; }
  85. if(__stdlib_allocs) memcpy(ret, __stdlib_allocs, __stdlib_numallocs * sizeof(uintptr_t));
  86. __stdlib_allocs = (uintptr_t*)ret;
  87. __stdlib_allocs[i] = __stdlib_allocs[i + 1] = 0;
  88. __stdlib_numallocs += 2;
  89. ret = NULL;
  90. }
  91. #endif
  92. status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, __size, &ret);
  93. if(EFI_ERROR(status) || !ret) { errno = ENOMEM; ret = NULL; }
  94. #ifndef UEFI_NO_TRACK_ALLOC
  95. __stdlib_allocs[i] = (uintptr_t)ret;
  96. __stdlib_allocs[i + 1] = (uintptr_t)__size;
  97. #endif
  98. return ret;
  99. }
  100. void *calloc (size_t __nmemb, size_t __size)
  101. {
  102. void *ret = malloc(__nmemb * __size);
  103. if(ret) memset(ret, 0, __nmemb * __size);
  104. return ret;
  105. }
  106. void *realloc (void *__ptr, size_t __size)
  107. {
  108. void *ret = NULL;
  109. efi_status_t status;
  110. #ifndef UEFI_NO_TRACK_ALLOC
  111. uintn_t i;
  112. #endif
  113. if(!__ptr) return malloc(__size);
  114. if(!__size) { free(__ptr); return NULL; }
  115. #ifndef UEFI_NO_TRACK_ALLOC
  116. /* get the slot which stores the old size for this buffer */
  117. for(i = 0; i < __stdlib_numallocs && __stdlib_allocs[i] != (uintptr_t)__ptr; i += 2);
  118. if(i == __stdlib_numallocs) { errno = ENOMEM; return NULL; }
  119. /* allocate a new buffer and copy data from old buffer */
  120. status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, __size, &ret);
  121. if(EFI_ERROR(status) || !ret) { errno = ENOMEM; ret = NULL; }
  122. else {
  123. memcpy(ret, (void*)__stdlib_allocs[i], __stdlib_allocs[i + 1] < __size ? __stdlib_allocs[i + 1] : __size);
  124. if(__size > __stdlib_allocs[i + 1]) memset((uint8_t*)ret + __stdlib_allocs[i + 1], 0, __size - __stdlib_allocs[i + 1]);
  125. /* free old buffer and store new buffer in slot */
  126. BS->FreePool((void*)__stdlib_allocs[i]);
  127. __stdlib_allocs[i] = (uintptr_t)ret;
  128. __stdlib_allocs[i + 1] = (uintptr_t)__size;
  129. }
  130. #else
  131. status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, __size, &ret);
  132. if(EFI_ERROR(status) || !ret) { errno = ENOMEM; return NULL; }
  133. /* this means out of bounds read, but fine with POSIX as the end of new buffer supposed to be left uninitialized) */
  134. memcpy(ret, (void*)__ptr, __size);
  135. BS->FreePool((void*)__ptr);
  136. #endif
  137. return ret;
  138. }
  139. void free (void *__ptr)
  140. {
  141. efi_status_t status;
  142. #ifndef UEFI_NO_TRACK_ALLOC
  143. uintn_t i;
  144. #endif
  145. if(!__ptr) { errno = ENOMEM; return; }
  146. #ifndef UEFI_NO_TRACK_ALLOC
  147. /* find and clear the slot */
  148. for(i = 0; i < __stdlib_numallocs && __stdlib_allocs[i] != (uintptr_t)__ptr; i += 2);
  149. if(i == __stdlib_numallocs) { errno = ENOMEM; return; }
  150. __stdlib_allocs[i] = 0;
  151. __stdlib_allocs[i + 1] = 0;
  152. /* if there are only empty slots, free the housekeeping array too */
  153. for(i = 0; i < __stdlib_numallocs && __stdlib_allocs[i] == 0; i += 2);
  154. if(i == __stdlib_numallocs) { BS->FreePool(__stdlib_allocs); __stdlib_allocs = NULL; __stdlib_numallocs = 0; }
  155. #endif
  156. status = BS->FreePool(__ptr);
  157. if(EFI_ERROR(status)) errno = ENOMEM;
  158. }
  159. void abort ()
  160. {
  161. #ifndef UEFI_NO_TRACK_ALLOC
  162. if(__stdlib_allocs)
  163. BS->FreePool(__stdlib_allocs);
  164. __stdlib_allocs = NULL;
  165. __stdlib_numallocs = 0;
  166. #endif
  167. __stdio_cleanup();
  168. BS->Exit(IM, EFI_ABORTED, 0, NULL);
  169. }
  170. void exit (int __status)
  171. {
  172. #ifndef UEFI_NO_TRACK_ALLOC
  173. if(__stdlib_allocs)
  174. BS->FreePool(__stdlib_allocs);
  175. __stdlib_allocs = NULL;
  176. __stdlib_numallocs = 0;
  177. #endif
  178. __stdio_cleanup();
  179. BS->Exit(IM, !__status ? 0 : (__status < 0 ? EFIERR(-__status) : EFIERR(__status)), 0, NULL);
  180. }
  181. int exit_bs()
  182. {
  183. efi_status_t status = 0;
  184. efi_memory_descriptor_t *memory_map = NULL;
  185. uintn_t cnt = 3, memory_map_size=0, map_key=0, desc_size=0;
  186. #ifndef UEFI_NO_TRACK_ALLOC
  187. if(__stdlib_allocs)
  188. BS->FreePool(__stdlib_allocs);
  189. __stdlib_allocs = NULL;
  190. __stdlib_numallocs = 0;
  191. #endif
  192. __stdio_cleanup();
  193. while(cnt--) {
  194. status = BS->GetMemoryMap(&memory_map_size, memory_map, &map_key, &desc_size, NULL);
  195. if (status!=EFI_BUFFER_TOO_SMALL) break;
  196. status = BS->ExitBootServices(IM, map_key);
  197. if(!EFI_ERROR(status)) return 0;
  198. }
  199. return (int)(status & 0xffff);
  200. }
  201. void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, __compar_fn_t cmp)
  202. {
  203. uint64_t s=0, e=nmemb, m;
  204. int ret;
  205. while (s < e) {
  206. m = s + (e-s)/2;
  207. ret = cmp(key, (uint8_t*)base + m*size);
  208. if (ret < 0) e = m; else
  209. if (ret > 0) s = m+1; else
  210. return (void *)((uint8_t*)base + m*size);
  211. }
  212. return NULL;
  213. }
  214. int mblen(const char *s, size_t n)
  215. {
  216. const char *e = s+n;
  217. int c = 0;
  218. if(s) {
  219. while(s < e && *s) {
  220. if((*s & 128) != 0) {
  221. if((*s & 32) == 0 ) s++; else
  222. if((*s & 16) == 0 ) s+=2; else
  223. if((*s & 8) == 0 ) s+=3;
  224. }
  225. c++;
  226. s++;
  227. }
  228. }
  229. return c;
  230. }
  231. int mbtowc (wchar_t * __pwc, const char *s, size_t n)
  232. {
  233. wchar_t arg;
  234. int ret = 1;
  235. if(!s || !*s) return 0;
  236. arg = (wchar_t)*s;
  237. if((*s & 128) != 0) {
  238. if((*s & 32) == 0 && n > 0) { arg = ((*s & 0x1F)<<6)|(*(s+1) & 0x3F); ret = 2; } else
  239. if((*s & 16) == 0 && n > 1) { arg = ((*s & 0xF)<<12)|((*(s+1) & 0x3F)<<6)|(*(s+2) & 0x3F); ret = 3; } else
  240. if((*s & 8) == 0 && n > 2) { arg = ((*s & 0x7)<<18)|((*(s+1) & 0x3F)<<12)|((*(s+2) & 0x3F)<<6)|(*(s+3) & 0x3F); ret = 4; }
  241. else return -1;
  242. }
  243. if(__pwc) *__pwc = arg;
  244. return ret;
  245. }
  246. int wctomb (char *s, wchar_t u)
  247. {
  248. int ret = 0;
  249. if(u<0x80) {
  250. *s = u;
  251. ret = 1;
  252. } else if(u<0x800) {
  253. *(s+0)=((u>>6)&0x1F)|0xC0;
  254. *(s+1)=(u&0x3F)|0x80;
  255. ret = 2;
  256. } else {
  257. *(s+0)=((u>>12)&0x0F)|0xE0;
  258. *(s+1)=((u>>6)&0x3F)|0x80;
  259. *(s+2)=(u&0x3F)|0x80;
  260. ret = 3;
  261. }
  262. return ret;
  263. }
  264. size_t mbstowcs (wchar_t *__pwcs, const char *__s, size_t __n)
  265. {
  266. int r;
  267. wchar_t *orig = __pwcs;
  268. if(!__s || !*__s) return 0;
  269. while(*__s) {
  270. r = mbtowc(__pwcs, __s, __n - (size_t)(__pwcs - orig));
  271. if(r < 0) return (size_t)-1;
  272. __pwcs++;
  273. __s += r;
  274. }
  275. *__pwcs = 0;
  276. return (size_t)(__pwcs - orig);
  277. }
  278. size_t wcstombs (char *__s, const wchar_t *__pwcs, size_t __n)
  279. {
  280. int r;
  281. char *orig = __s;
  282. if(!__s || !__pwcs || !*__pwcs) return 0;
  283. while(*__pwcs && ((size_t)(__s - orig + 4) < __n)) {
  284. r = wctomb(__s, *__pwcs);
  285. if(r < 0) return (size_t)-1;
  286. __pwcs++;
  287. __s += r;
  288. }
  289. *__s = 0;
  290. return (size_t)(__s - orig);
  291. }
  292. void srand(unsigned int __seed)
  293. {
  294. __srand_seed = __seed - 1;
  295. }
  296. int rand()
  297. {
  298. efi_guid_t rngGuid = EFI_RNG_PROTOCOL_GUID;
  299. efi_rng_protocol_t *rng = NULL;
  300. efi_status_t status;
  301. int ret = 0;
  302. __srand_seed = 6364136223846793005ULL*__srand_seed + 1;
  303. status = BS->LocateProtocol(&rngGuid, NULL, (void**)&rng);
  304. if(!EFI_ERROR(status) && rng)
  305. rng->GetRNG(rng, NULL, (uintn_t)sizeof(int), (uint8_t*)&ret);
  306. ret ^= (int)(__srand_seed>>33);
  307. return ret;
  308. }
  309. uint8_t *getenv(char_t *name, uintn_t *len)
  310. {
  311. efi_guid_t globGuid = EFI_GLOBAL_VARIABLE;
  312. uint8_t tmp[EFI_MAXIMUM_VARIABLE_SIZE], *ret;
  313. uint32_t attr;
  314. efi_status_t status;
  315. #ifndef UEFI_NO_UTF8
  316. wchar_t wcname[256];
  317. mbstowcs((wchar_t*)&wcname, name, 256);
  318. status = RT->GetVariable((wchar_t*)&wcname, &globGuid, &attr, len, &tmp);
  319. #else
  320. status = RT->GetVariable(name, &globGuid, &attr, len, &tmp);
  321. #endif
  322. if(EFI_ERROR(status) || *len < 1 || !(ret = malloc((*len) + 1))) {
  323. *len = 0;
  324. return NULL;
  325. }
  326. memcpy(ret, tmp, *len);
  327. ret[*len] = 0;
  328. return ret;
  329. }
  330. int setenv(char_t *name, uintn_t len, uint8_t *data)
  331. {
  332. efi_guid_t globGuid = EFI_GLOBAL_VARIABLE;
  333. efi_status_t status;
  334. #ifndef UEFI_NO_UTF8
  335. wchar_t wcname[256];
  336. mbstowcs((wchar_t*)&wcname, name, 256);
  337. status = RT->SetVariable(wcname, &globGuid, 0, len, data);
  338. #else
  339. status = RT->SetVariable(name, &globGuid, 0, len, data);
  340. #endif
  341. return !EFI_ERROR(status);
  342. }