bootloader.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. //
  2. // Copyright 2026 Aarav Ravindra Kharade
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. //
  16. #include <efi.h>
  17. #include <efilib.h>
  18. // Simulated hardware secure key
  19. #define HARDWARE_SECURE_KEY "ARK-OS-9aaafa37077ee91e5df2f47a8e9e1564beecde1cc13b279f51d915bf8c746eb4"
  20. EFI_STATUS check_os_signature(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {
  21. // Conceptual hardware verified boot check
  22. int has_key = 1;
  23. int match = 1;
  24. if (has_key) {
  25. if (match) {
  26. return EFI_SUCCESS;
  27. } else {
  28. return EFI_SECURITY_VIOLATION;
  29. }
  30. } else {
  31. return EFI_SUCCESS;
  32. }
  33. }
  34. EFI_STATUS load_drm_module() {
  35. // Conceptual DRM module loading
  36. return EFI_SUCCESS;
  37. }
  38. static EFI_STATUS read_file_from_esp(
  39. EFI_HANDLE ImageHandle,
  40. EFI_SYSTEM_TABLE *SystemTable,
  41. CHAR16 *FileName,
  42. VOID **BufferOut,
  43. UINTN *SizeOut
  44. ) {
  45. EFI_STATUS status;
  46. EFI_LOADED_IMAGE *loaded_image = NULL;
  47. EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *fs = NULL;
  48. EFI_FILE_HANDLE root = NULL;
  49. EFI_FILE_HANDLE file = NULL;
  50. // 1. Get the LoadedImage protocol for the current bootloader
  51. status = uefi_call_wrapper(
  52. SystemTable->BootServices->HandleProtocol,
  53. 3,
  54. ImageHandle,
  55. &LoadedImageProtocol,
  56. (VOID **)&loaded_image
  57. );
  58. if (EFI_ERROR(status)) return status;
  59. // 2. Open the SimpleFileSystem protocol on the device handle of the loaded image
  60. status = uefi_call_wrapper(
  61. SystemTable->BootServices->HandleProtocol,
  62. 3,
  63. loaded_image->DeviceHandle,
  64. &FileSystemProtocol,
  65. (VOID **)&fs
  66. );
  67. if (EFI_ERROR(status)) return status;
  68. // 3. Open the volume
  69. status = uefi_call_wrapper(fs->OpenVolume, 2, fs, &root);
  70. if (EFI_ERROR(status)) return status;
  71. // 4. Open the file
  72. status = uefi_call_wrapper(
  73. root->Open,
  74. 5,
  75. root,
  76. &file,
  77. FileName,
  78. EFI_FILE_MODE_READ,
  79. 0
  80. );
  81. if (EFI_ERROR(status)) {
  82. uefi_call_wrapper(root->Close, 1, root);
  83. return status;
  84. }
  85. // 5. Get file info to determine size
  86. EFI_FILE_INFO *file_info = NULL;
  87. UINTN info_size = 0;
  88. status = uefi_call_wrapper(
  89. file->GetInfo,
  90. 4,
  91. file,
  92. &GenericFileInfo,
  93. &info_size,
  94. NULL
  95. );
  96. if (status == EFI_BUFFER_TOO_SMALL) {
  97. status = uefi_call_wrapper(
  98. SystemTable->BootServices->AllocatePool,
  99. 3,
  100. EfiLoaderData,
  101. info_size,
  102. (VOID **)&file_info
  103. );
  104. if (EFI_ERROR(status)) {
  105. uefi_call_wrapper(file->Close, 1, file);
  106. uefi_call_wrapper(root->Close, 1, root);
  107. return status;
  108. }
  109. status = uefi_call_wrapper(
  110. file->GetInfo,
  111. 4,
  112. file,
  113. &GenericFileInfo,
  114. &info_size,
  115. (VOID *)file_info
  116. );
  117. }
  118. if (EFI_ERROR(status)) {
  119. if (file_info) uefi_call_wrapper(SystemTable->BootServices->FreePool, 1, file_info);
  120. uefi_call_wrapper(file->Close, 1, file);
  121. uefi_call_wrapper(root->Close, 1, root);
  122. return status;
  123. }
  124. UINTN file_size = file_info->FileSize;
  125. uefi_call_wrapper(SystemTable->BootServices->FreePool, 1, file_info);
  126. // 6. Allocate buffer for file contents using AllocatePages for large buffers
  127. UINTN num_pages = (file_size + 4095) / 4096;
  128. EFI_PHYSICAL_ADDRESS phys_buffer = 0;
  129. status = uefi_call_wrapper(
  130. SystemTable->BootServices->AllocatePages,
  131. 4,
  132. AllocateAnyPages,
  133. EfiLoaderData,
  134. num_pages,
  135. &phys_buffer
  136. );
  137. if (EFI_ERROR(status)) {
  138. uefi_call_wrapper(file->Close, 1, file);
  139. uefi_call_wrapper(root->Close, 1, root);
  140. return status;
  141. }
  142. VOID *buffer = (VOID *)(UINTN)phys_buffer;
  143. // 7. Read file contents
  144. UINTN read_size = file_size;
  145. status = uefi_call_wrapper(file->Read, 3, file, &read_size, buffer);
  146. if (EFI_ERROR(status) || read_size != file_size) {
  147. uefi_call_wrapper(SystemTable->BootServices->FreePages, 2, phys_buffer, num_pages);
  148. uefi_call_wrapper(file->Close, 1, file);
  149. uefi_call_wrapper(root->Close, 1, root);
  150. return EFI_DEVICE_ERROR;
  151. }
  152. // 8. Clean up and return
  153. uefi_call_wrapper(file->Close, 1, file);
  154. uefi_call_wrapper(root->Close, 1, root);
  155. *BufferOut = buffer;
  156. *SizeOut = file_size;
  157. return EFI_SUCCESS;
  158. }
  159. EFI_STATUS efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {
  160. InitializeLib(ImageHandle, SystemTable);
  161. EFI_STATUS status;
  162. // 1. Locate the Graphics Output Protocol (GOP)
  163. EFI_GRAPHICS_OUTPUT_PROTOCOL *gop = NULL;
  164. EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
  165. status = uefi_call_wrapper(
  166. SystemTable->BootServices->LocateProtocol,
  167. 3,
  168. &gop_guid,
  169. NULL,
  170. (VOID **)&gop
  171. );
  172. if (!EFI_ERROR(status) && gop) {
  173. UINT32 max_mode = gop->Mode->MaxMode;
  174. UINT32 target_mode = gop->Mode->Mode;
  175. UINT32 max_res = 0;
  176. for (UINT32 i = 0; i < max_mode; i++) {
  177. EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info;
  178. UINTN size_of_info;
  179. EFI_STATUS s = uefi_call_wrapper(gop->QueryMode, 4, gop, i, &size_of_info, &info);
  180. if (!EFI_ERROR(s)) {
  181. if (info->HorizontalResolution == 3840 && info->VerticalResolution == 2160) {
  182. target_mode = i;
  183. uefi_call_wrapper(SystemTable->BootServices->FreePool, 1, info);
  184. break;
  185. }
  186. UINT32 res = info->HorizontalResolution * info->VerticalResolution;
  187. if (res > max_res) {
  188. max_res = res;
  189. target_mode = i;
  190. }
  191. uefi_call_wrapper(SystemTable->BootServices->FreePool, 1, info);
  192. }
  193. }
  194. uefi_call_wrapper(gop->SetMode, 2, gop, target_mode);
  195. }
  196. UINTN center_x = 0;
  197. UINTN center_y = 0;
  198. UINTN anim_width = 200;
  199. UINTN anim_height = 200;
  200. // 2. Clear screen to black and display the white dot
  201. if (!EFI_ERROR(status) && gop) {
  202. EFI_GRAPHICS_OUTPUT_BLT_PIXEL black = {0, 0, 0, 0};
  203. uefi_call_wrapper(
  204. gop->Blt,
  205. 10,
  206. gop,
  207. &black,
  208. EfiBltVideoFill,
  209. 0, 0,
  210. 0, 0,
  211. gop->Mode->Info->HorizontalResolution,
  212. gop->Mode->Info->VerticalResolution,
  213. 0
  214. );
  215. center_x = (gop->Mode->Info->HorizontalResolution - anim_width) / 2;
  216. center_y = (gop->Mode->Info->VerticalResolution - anim_height) / 2;
  217. // Draw a 6x6 pixel white dot in the center of the 200x200 region
  218. EFI_GRAPHICS_OUTPUT_BLT_PIXEL white = {255, 255, 255, 0};
  219. uefi_call_wrapper(
  220. gop->Blt,
  221. 10,
  222. gop,
  223. &white,
  224. EfiBltVideoFill,
  225. 0, 0,
  226. center_x + 97, center_y + 97,
  227. 6, 6,
  228. 0
  229. );
  230. }
  231. // 3. Perform OS Key signature check and load DRM
  232. status = check_os_signature(ImageHandle, SystemTable);
  233. if (EFI_ERROR(status)) {
  234. return status;
  235. }
  236. load_drm_module();
  237. // 4. Resolve path and load the kernel image (bzImage)
  238. EFI_LOADED_IMAGE *loaded_image = NULL;
  239. status = uefi_call_wrapper(
  240. SystemTable->BootServices->HandleProtocol,
  241. 3,
  242. ImageHandle,
  243. &LoadedImageProtocol,
  244. (VOID **)&loaded_image
  245. );
  246. if (EFI_ERROR(status)) return status;
  247. EFI_DEVICE_PATH *kernel_path = FileDevicePath(loaded_image->DeviceHandle, L"\\EFI\\BOOT\\bzImage");
  248. if (kernel_path == NULL) return EFI_OUT_OF_RESOURCES;
  249. EFI_HANDLE kernel_img = NULL;
  250. status = uefi_call_wrapper(
  251. SystemTable->BootServices->LoadImage,
  252. 6,
  253. FALSE,
  254. ImageHandle,
  255. kernel_path,
  256. NULL,
  257. 0,
  258. &kernel_img
  259. );
  260. if (EFI_ERROR(status)) return status;
  261. // 5. Play the boot animation (expanding nucleus) from ESP
  262. if (gop) {
  263. VOID *anim_buffer = NULL;
  264. UINTN anim_size = 0;
  265. status = read_file_from_esp(ImageHandle, SystemTable, L"\\EFI\\BOOT\\animation.bin", &anim_buffer, &anim_size);
  266. if (EFI_ERROR(status)) {
  267. EFI_GRAPHICS_OUTPUT_BLT_PIXEL red = {0, 0, 255, 0};
  268. uefi_call_wrapper(gop->Blt, 10, gop, &red, EfiBltVideoFill, 0, 0, center_x + 97, center_y + 97, 16, 16, 0);
  269. uefi_call_wrapper(SystemTable->BootServices->Stall, 1, 3000000); // 3 seconds
  270. } else {
  271. UINTN num_frames = 60;
  272. UINTN expected_size = num_frames * anim_width * anim_height * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
  273. if (anim_size < expected_size) {
  274. EFI_GRAPHICS_OUTPUT_BLT_PIXEL green = {0, 255, 0, 0};
  275. uefi_call_wrapper(gop->Blt, 10, gop, &green, EfiBltVideoFill, 0, 0, center_x + 97, center_y + 97, 16, 16, 0);
  276. uefi_call_wrapper(SystemTable->BootServices->Stall, 1, 3000000); // 3 seconds
  277. } else {
  278. // Clear the white dot to black first
  279. EFI_GRAPHICS_OUTPUT_BLT_PIXEL black = {0, 0, 0, 0};
  280. uefi_call_wrapper(
  281. gop->Blt,
  282. 10,
  283. gop,
  284. &black,
  285. EfiBltVideoFill,
  286. 0, 0,
  287. 0, 0,
  288. gop->Mode->Info->HorizontalResolution,
  289. gop->Mode->Info->VerticalResolution,
  290. 0
  291. );
  292. EFI_GRAPHICS_OUTPUT_BLT_PIXEL *frames = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)anim_buffer;
  293. for (UINTN f = 0; f < num_frames; f++) {
  294. EFI_GRAPHICS_OUTPUT_BLT_PIXEL *frame = &frames[f * anim_width * anim_height];
  295. uefi_call_wrapper(
  296. gop->Blt,
  297. 10,
  298. gop,
  299. frame,
  300. EfiBltBufferToVideo,
  301. 0, 0,
  302. center_x, center_y,
  303. anim_width, anim_height,
  304. anim_width * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
  305. );
  306. uefi_call_wrapper(SystemTable->BootServices->Stall, 1, 16666);
  307. }
  308. }
  309. uefi_call_wrapper(SystemTable->BootServices->FreePages, 2, (EFI_PHYSICAL_ADDRESS)(UINTN)anim_buffer, (anim_size + 4095) / 4096);
  310. }
  311. }
  312. // 6. Set command line options for the kernel
  313. EFI_LOADED_IMAGE *kernel_loaded_image = NULL;
  314. status = uefi_call_wrapper(
  315. SystemTable->BootServices->HandleProtocol,
  316. 3,
  317. kernel_img,
  318. &LoadedImageProtocol,
  319. (VOID **)&kernel_loaded_image
  320. );
  321. if (EFI_ERROR(status)) return status;
  322. CHAR16 *cmd_line = L"initrd=\\EFI\\BOOT\\initramfs.img console=ttyS0 console=tty0 loglevel=0 logo.nologo init=/init root=/dev/sdb rw quiet vt.global_cursor_default=0";
  323. kernel_loaded_image->LoadOptions = cmd_line;
  324. kernel_loaded_image->LoadOptionsSize = (StrLen(cmd_line) + 1) * sizeof(CHAR16);
  325. // 7. Start the kernel
  326. UINTN exit_data_size = 0;
  327. CHAR16 *exit_data = NULL;
  328. status = uefi_call_wrapper(
  329. SystemTable->BootServices->StartImage,
  330. 3,
  331. kernel_img,
  332. &exit_data_size,
  333. &exit_data
  334. );
  335. return status;
  336. }