crt_riscv64.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /*
  2. * crt_riscv64.c
  3. *
  4. * Copyright (C) 2023 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 C runtime, bootstraps an EFI application to call standard main()
  28. *
  29. */
  30. #include <uefi.h>
  31. /* this is implemented by the application */
  32. extern int main(int argc, char_t **argv);
  33. /* definitions for elf relocations */
  34. #ifndef __clang__
  35. typedef uint64_t Elf64_Xword;
  36. typedef int64_t Elf64_Sxword;
  37. typedef uint64_t Elf64_Addr;
  38. typedef struct
  39. {
  40. Elf64_Sxword d_tag; /* Dynamic entry type */
  41. union
  42. {
  43. Elf64_Xword d_val; /* Integer value */
  44. Elf64_Addr d_ptr; /* Address value */
  45. } d_un;
  46. } Elf64_Dyn;
  47. #define DT_NULL 0 /* Marks end of dynamic section */
  48. #define DT_RELA 7 /* Address of Rela relocs */
  49. #define DT_RELASZ 8 /* Total size of Rela relocs */
  50. #define DT_RELAENT 9 /* Size of one Rela reloc */
  51. typedef struct
  52. {
  53. Elf64_Addr r_offset; /* Address */
  54. Elf64_Xword r_info; /* Relocation type and symbol index */
  55. } Elf64_Rel;
  56. #define ELF64_R_TYPE(i) ((i) & 0xffffffff)
  57. #define R_RISCV_RELATIVE 3 /* Adjust by program base */
  58. #endif
  59. /* globals to store system table pointers */
  60. efi_handle_t IM = NULL;
  61. efi_system_table_t *ST = NULL;
  62. efi_boot_services_t *BS = NULL;
  63. efi_runtime_services_t *RT = NULL;
  64. efi_loaded_image_protocol_t *LIP = NULL;
  65. #ifndef UEFI_NO_UTF8
  66. char *__argvutf8 = NULL;
  67. #endif
  68. /* we only need one .o file, so use inline Assembly here */
  69. void bootstrap(void)
  70. {
  71. __asm__ __volatile__ (
  72. /* call init in C */
  73. " .align 4\n"
  74. #ifndef __clang__
  75. " .globl _start\n"
  76. "_start:\n"
  77. " lla a2, ImageBase\n"
  78. " lui a3, %hi(_DYNAMIC)\n"
  79. " addi a3, a3, %lo(_DYNAMIC)\n"
  80. " call uefi_init\n"
  81. " ret\n"
  82. /* fake a relocation record, so that EFI won't complain */
  83. " .data\n"
  84. "dummy: .long 0\n"
  85. " .section .reloc, \"a\"\n"
  86. "label1:\n"
  87. " .long dummy-label1\n"
  88. " .long 10\n"
  89. " .word 0\n"
  90. ".text\n"
  91. #else
  92. " .globl __chkstk\n"
  93. "__chkstk:\n"
  94. " ret\n"
  95. #endif
  96. );
  97. /* setjmp and longjmp */
  98. __asm__ __volatile__ (
  99. " .p2align 3\n"
  100. " .globl setjmp\n"
  101. "setjmp:\n"
  102. " sd ra, 0(a0)\n"
  103. " sd sp, 8(a0)\n"
  104. " sd s0, 16(a0)\n"
  105. " sd s1, 24(a0)\n"
  106. " sd s2, 32(a0)\n"
  107. " sd s3, 40(a0)\n"
  108. " sd s4, 48(a0)\n"
  109. " sd s5, 56(a0)\n"
  110. " sd s6, 64(a0)\n"
  111. " sd s7, 72(a0)\n"
  112. " sd s8, 80(a0)\n"
  113. " sd s9, 88(a0)\n"
  114. " sd s10, 96(a0)\n"
  115. " sd s11, 104(a0)\n"
  116. #ifndef __riscv_float_abi_soft
  117. " fsd fs0, 112(a0)\n"
  118. " fsd fs1, 120(a0)\n"
  119. " fsd fs2, 128(a0)\n"
  120. " fsd fs3, 136(a0)\n"
  121. " fsd fs4, 144(a0)\n"
  122. " fsd fs5, 152(a0)\n"
  123. " fsd fs6, 160(a0)\n"
  124. " fsd fs7, 168(a0)\n"
  125. " fsd fs8, 176(a0)\n"
  126. " fsd fs9, 184(a0)\n"
  127. " fsd fs10,192(a0)\n"
  128. " fsd fs11,200(a0)\n"
  129. #endif
  130. " li a0, 0\n"
  131. " ret\n"
  132. );
  133. __asm__ __volatile__ (
  134. " .globl longjmp\n"
  135. "longjmp:\n"
  136. " ld ra, 0(a0)\n"
  137. " ld sp, 8(a0)\n"
  138. " ld s0, 16(a0)\n"
  139. " ld s1, 24(a0)\n"
  140. " ld s2, 32(a0)\n"
  141. " ld s3, 40(a0)\n"
  142. " ld s4, 48(a0)\n"
  143. " ld s5, 56(a0)\n"
  144. " ld s6, 64(a0)\n"
  145. " ld s7, 72(a0)\n"
  146. " ld s8, 80(a0)\n"
  147. " ld s9, 88(a0)\n"
  148. " ld s10, 96(a0)\n"
  149. " ld s11, 104(a0)\n"
  150. #ifndef __riscv_float_abi_soft
  151. " fld fs0, 112(a0)\n"
  152. " fld fs1, 120(a0)\n"
  153. " fld fs2, 128(a0)\n"
  154. " fld fs3, 136(a0)\n"
  155. " fld fs4, 144(a0)\n"
  156. " fld fs5, 152(a0)\n"
  157. " fld fs6, 160(a0)\n"
  158. " fld fs7, 168(a0)\n"
  159. " fld fs8, 176(a0)\n"
  160. " fld fs9, 184(a0)\n"
  161. " fld fs10,192(a0)\n"
  162. " fld fs11,200(a0)\n"
  163. #endif
  164. " seqz a0, a1\n"
  165. " add a0, a0, a1\n"
  166. " ret\n"
  167. );
  168. }
  169. /**
  170. * Initialize POSIX-UEFI and call the application's main() function
  171. */
  172. efi_status_t uefi_init (
  173. efi_handle_t image, efi_system_table_t *systab
  174. #ifndef __clang__
  175. , uintptr_t ldbase, Elf64_Dyn *dyn
  176. #endif
  177. ) {
  178. efi_guid_t shpGuid = EFI_SHELL_PARAMETERS_PROTOCOL_GUID;
  179. efi_shell_parameters_protocol_t *shp = NULL;
  180. efi_guid_t shiGuid = SHELL_INTERFACE_PROTOCOL_GUID;
  181. efi_shell_interface_protocol_t *shi = NULL;
  182. efi_guid_t lipGuid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
  183. efi_status_t status;
  184. int argc = 0, i, ret;
  185. wchar_t **argv = NULL;
  186. #ifndef UEFI_NO_UTF8
  187. int j;
  188. char *s;
  189. #endif
  190. #ifndef __clang__
  191. long relsz = 0, relent = 0;
  192. Elf64_Rel *rel = 0;
  193. uintptr_t *addr;
  194. /* handle relocations */
  195. for (i = 0; dyn[i].d_tag != DT_NULL; ++i) {
  196. switch (dyn[i].d_tag) {
  197. case DT_RELA: rel = (Elf64_Rel*)((unsigned long)dyn[i].d_un.d_ptr + ldbase); break;
  198. case DT_RELASZ: relsz = dyn[i].d_un.d_val; break;
  199. case DT_RELAENT: relent = dyn[i].d_un.d_val; break;
  200. default: break;
  201. }
  202. }
  203. if (rel && relent) {
  204. while (relsz > 0) {
  205. if(ELF64_R_TYPE (rel->r_info) == R_RISCV_RELATIVE)
  206. { addr = (unsigned long *)(ldbase + rel->r_offset); *addr += ldbase; }
  207. rel = (Elf64_Rel*) ((char *) rel + relent);
  208. relsz -= relent;
  209. }
  210. }
  211. #else
  212. (void)i;
  213. #endif
  214. /* failsafes, should never happen */
  215. if(!image || !systab || !systab->BootServices || !systab->BootServices->HandleProtocol ||
  216. !systab->BootServices->OpenProtocol || !systab->BootServices->AllocatePool || !systab->BootServices->FreePool)
  217. return EFI_UNSUPPORTED;
  218. /* save EFI pointers and loaded image into globals */
  219. IM = image;
  220. ST = systab;
  221. BS = systab->BootServices;
  222. RT = systab->RuntimeServices;
  223. BS->HandleProtocol(image, &lipGuid, (void **)&LIP);
  224. /* get command line arguments */
  225. status = BS->OpenProtocol(image, &shpGuid, (void **)&shp, image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
  226. if(!EFI_ERROR(status) && shp) { argc = (int)shp->Argc; argv = shp->Argv; }
  227. else {
  228. /* if shell 2.0 failed, fallback to shell 1.0 interface */
  229. status = BS->OpenProtocol(image, &shiGuid, (void **)&shi, image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
  230. if(!EFI_ERROR(status) && shi) { argc = (int)shi->Argc; argv = shi->Argv; }
  231. }
  232. /* call main */
  233. #ifndef UEFI_NO_UTF8
  234. if(argc && argv) {
  235. ret = (argc + 1) * ((int)sizeof(uintptr_t) + 1);
  236. for(i = 0; i < argc; i++)
  237. for(j = 0; argv[i] && argv[i][j]; j++)
  238. ret += argv[i][j] < 0x80 ? 1 : (argv[i][j] < 0x800 ? 2 : 3);
  239. status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, (uintn_t)ret, (void **)&__argvutf8);
  240. if(EFI_ERROR(status) || !__argvutf8) { argc = 0; __argvutf8 = NULL; }
  241. else {
  242. s = __argvutf8 + argc * (int)sizeof(uintptr_t);
  243. *((uintptr_t*)s) = (uintptr_t)0; s += sizeof(uintptr_t);
  244. for(i = 0; i < argc; i++) {
  245. *((uintptr_t*)(__argvutf8 + i * (int)sizeof(uintptr_t))) = (uintptr_t)s;
  246. for(j = 0; argv[i] && argv[i][j]; j++) {
  247. if(argv[i][j]<0x80) { *s++ = argv[i][j]; } else
  248. if(argv[i][j]<0x800) { *s++ = ((argv[i][j]>>6)&0x1F)|0xC0; *s++ = (argv[i][j]&0x3F)|0x80; } else
  249. { *s++ = ((argv[i][j]>>12)&0x0F)|0xE0; *s++ = ((argv[i][j]>>6)&0x3F)|0x80; *s++ = (argv[i][j]&0x3F)|0x80; }
  250. }
  251. *s++ = 0;
  252. }
  253. }
  254. }
  255. ret = main(argc, (char**)__argvutf8);
  256. if(__argvutf8) BS->FreePool(__argvutf8);
  257. return ret;
  258. #else
  259. ret = main(argc, argv);
  260. #endif
  261. return ret ? EFIERR(ret) : EFI_SUCCESS;
  262. }