crt_aarch64.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. /*
  2. * crt_aarch64.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 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_AARCH64_RELATIVE 1027 /* 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. " ldr x2, =ImageBase\n"
  78. " adrp x3, _DYNAMIC\n"
  79. " add x3, x3, #:lo12:_DYNAMIC\n"
  80. " bl 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. " mov x16, sp\n"
  103. " stp x19, x20, [x0, #0]\n"
  104. " stp x21, x22, [x0, #16]\n"
  105. " stp x23, x24, [x0, #32]\n"
  106. " stp x25, x26, [x0, #48]\n"
  107. " stp x27, x28, [x0, #64]\n"
  108. " stp x29, x30, [x0, #80]\n"
  109. " str x16, [x0, #96]\n"
  110. " stp d8, d9, [x0, #112]\n"
  111. " stp d10, d11, [x0, #128]\n"
  112. " stp d12, d13, [x0, #144]\n"
  113. " stp d14, d15, [x0, #160]\n"
  114. " mov w0, #0\n"
  115. " ret\n"
  116. );
  117. __asm__ __volatile__ (
  118. " .globl longjmp\n"
  119. "longjmp:\n"
  120. " ldp x19, x20, [x0, #0]\n"
  121. " ldp x21, x22, [x0, #16]\n"
  122. " ldp x23, x24, [x0, #32]\n"
  123. " ldp x25, x26, [x0, #48]\n"
  124. " ldp x27, x28, [x0, #64]\n"
  125. " ldp x29, x30, [x0, #80]\n"
  126. " ldr x16, [x0, #96]\n"
  127. " ldp d8, d9, [x0, #112]\n"
  128. " ldp d10, d11, [x0, #128]\n"
  129. " ldp d12, d13, [x0, #144]\n"
  130. " ldp d14, d15, [x0, #160]\n"
  131. " mov sp, x16\n"
  132. " cmp w1, #0\n"
  133. " mov w0, #1\n"
  134. " csel w0, w1, w0, ne\n"
  135. " br x30\n"
  136. );
  137. }
  138. /**
  139. * Initialize POSIX-UEFI and call the application's main() function
  140. */
  141. efi_status_t uefi_init (
  142. efi_handle_t image, efi_system_table_t *systab
  143. #ifndef __clang__
  144. , uintptr_t ldbase, Elf64_Dyn *dyn
  145. #endif
  146. ) {
  147. efi_guid_t shpGuid = EFI_SHELL_PARAMETERS_PROTOCOL_GUID;
  148. efi_shell_parameters_protocol_t *shp = NULL;
  149. efi_guid_t shiGuid = SHELL_INTERFACE_PROTOCOL_GUID;
  150. efi_shell_interface_protocol_t *shi = NULL;
  151. efi_guid_t lipGuid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
  152. efi_status_t status;
  153. int argc = 0, i, ret;
  154. wchar_t **argv = NULL;
  155. #ifndef UEFI_NO_UTF8
  156. int j;
  157. char *s;
  158. #endif
  159. #ifndef __clang__
  160. long relsz = 0, relent = 0;
  161. Elf64_Rel *rel = 0;
  162. uintptr_t *addr;
  163. /* handle relocations */
  164. for (i = 0; dyn[i].d_tag != DT_NULL; ++i) {
  165. switch (dyn[i].d_tag) {
  166. case DT_RELA: rel = (Elf64_Rel*)((unsigned long)dyn[i].d_un.d_ptr + ldbase); break;
  167. case DT_RELASZ: relsz = dyn[i].d_un.d_val; break;
  168. case DT_RELAENT: relent = dyn[i].d_un.d_val; break;
  169. default: break;
  170. }
  171. }
  172. if (rel && relent) {
  173. while (relsz > 0) {
  174. if(ELF64_R_TYPE (rel->r_info) == R_AARCH64_RELATIVE)
  175. { addr = (unsigned long *)(ldbase + rel->r_offset); *addr += ldbase; }
  176. rel = (Elf64_Rel*) ((char *) rel + relent);
  177. relsz -= relent;
  178. }
  179. }
  180. #else
  181. (void)i;
  182. #endif
  183. /* failsafes, should never happen */
  184. if(!image || !systab || !systab->BootServices || !systab->BootServices->HandleProtocol ||
  185. !systab->BootServices->OpenProtocol || !systab->BootServices->AllocatePool || !systab->BootServices->FreePool)
  186. return EFI_UNSUPPORTED;
  187. /* save EFI pointers and loaded image into globals */
  188. IM = image;
  189. ST = systab;
  190. BS = systab->BootServices;
  191. RT = systab->RuntimeServices;
  192. BS->HandleProtocol(image, &lipGuid, (void **)&LIP);
  193. /* get command line arguments */
  194. status = BS->OpenProtocol(image, &shpGuid, (void **)&shp, image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
  195. if(!EFI_ERROR(status) && shp) { argc = (int)shp->Argc; argv = shp->Argv; }
  196. else {
  197. /* if shell 2.0 failed, fallback to shell 1.0 interface */
  198. status = BS->OpenProtocol(image, &shiGuid, (void **)&shi, image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
  199. if(!EFI_ERROR(status) && shi) { argc = (int)shi->Argc; argv = shi->Argv; }
  200. }
  201. /* call main */
  202. #ifndef UEFI_NO_UTF8
  203. if(argc && argv) {
  204. ret = (argc + 1) * ((int)sizeof(uintptr_t) + 1);
  205. for(i = 0; i < argc; i++)
  206. for(j = 0; argv[i] && argv[i][j]; j++)
  207. ret += argv[i][j] < 0x80 ? 1 : (argv[i][j] < 0x800 ? 2 : 3);
  208. status = BS->AllocatePool(LIP ? LIP->ImageDataType : EfiLoaderData, (uintn_t)ret, (void **)&__argvutf8);
  209. if(EFI_ERROR(status) || !__argvutf8) { argc = 0; __argvutf8 = NULL; }
  210. else {
  211. s = __argvutf8 + argc * (int)sizeof(uintptr_t);
  212. *((uintptr_t*)s) = (uintptr_t)0; s += sizeof(uintptr_t);
  213. for(i = 0; i < argc; i++) {
  214. *((uintptr_t*)(__argvutf8 + i * (int)sizeof(uintptr_t))) = (uintptr_t)s;
  215. for(j = 0; argv[i] && argv[i][j]; j++) {
  216. if(argv[i][j]<0x80) { *s++ = argv[i][j]; } else
  217. if(argv[i][j]<0x800) { *s++ = ((argv[i][j]>>6)&0x1F)|0xC0; *s++ = (argv[i][j]&0x3F)|0x80; } else
  218. { *s++ = ((argv[i][j]>>12)&0x0F)|0xE0; *s++ = ((argv[i][j]>>6)&0x3F)|0x80; *s++ = (argv[i][j]&0x3F)|0x80; }
  219. }
  220. *s++ = 0;
  221. }
  222. }
  223. }
  224. ret = main(argc, (char**)__argvutf8);
  225. if(__argvutf8) BS->FreePool(__argvutf8);
  226. return ret;
  227. #else
  228. ret = main(argc, argv);
  229. #endif
  230. return ret ? EFIERR(ret) : EFI_SUCCESS;
  231. }