Monorepo for Aesthetic.Computer aesthetic.computer
at main 162 lines 5.4 kB view raw
1// splash.c — UEFI chainloader that shows "Aesthetic.Computer" then boots the kernel 2// Replaces the OEM (Lenovo) logo with a custom splash screen. 3// Built with gnu-efi, output is splash.efi (copied as BOOTX64.EFI). 4// The real kernel lives at \EFI\BOOT\KERNEL.EFI on the same partition. 5 6#include <efi.h> 7#include <efilib.h> 8 9#include "font8x8.h" 10 11#define KERNEL_PATH L"\\EFI\\BOOT\\KERNEL.EFI" 12#define LOADER_PATH L"\\EFI\\BOOT\\LOADER.EFI" 13 14// --- GOP helpers --- 15 16static EFI_GRAPHICS_OUTPUT_PROTOCOL *gop = NULL; 17static UINT32 hres, vres, ppsl; 18static UINT32 *fb; 19static int pixel_is_rgb = 0; // 0 = BGR (default), 1 = RGB 20 21static EFI_STATUS init_gop(void) { 22 EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; 23 EFI_STATUS status = uefi_call_wrapper(BS->LocateProtocol, 3, 24 &gop_guid, NULL, (void **)&gop); 25 if (EFI_ERROR(status)) return status; 26 27 hres = gop->Mode->Info->HorizontalResolution; 28 vres = gop->Mode->Info->VerticalResolution; 29 ppsl = gop->Mode->Info->PixelsPerScanLine; 30 fb = (UINT32 *)(UINTN)gop->Mode->FrameBufferBase; 31 32 // Detect pixel format 33 if (gop->Mode->Info->PixelFormat == PixelRedGreenBlueReserved8BitPerColor) 34 pixel_is_rgb = 1; 35 // PixelBlueGreenRedReserved8BitPerColor = 0 (default) 36 // PixelBitMask: would need mask parsing, assume BGR for now 37 38 return EFI_SUCCESS; 39} 40 41// Pack RGB into framebuffer pixel (handles BGR vs RGB format) 42static UINT32 pack_color(UINT8 r, UINT8 g, UINT8 b) { 43 if (pixel_is_rgb) 44 return ((UINT32)r) | ((UINT32)g << 8) | ((UINT32)b << 16); 45 else 46 return ((UINT32)b) | ((UINT32)g << 8) | ((UINT32)r << 16); 47} 48 49static void fill_screen(UINT32 color) { 50 UINTN total = (UINTN)ppsl * vres; 51 for (UINTN i = 0; i < total; i++) 52 fb[i] = color; 53} 54 55static void draw_pixel(UINT32 x, UINT32 y, UINT32 color) { 56 if (x < hres && y < vres) 57 fb[y * ppsl + x] = color; 58} 59 60// Draw one 8x8 character scaled by `scale` 61static void draw_char(unsigned char c, UINT32 x, UINT32 y, UINT32 scale, UINT32 color) { 62 if (c < 32 || c > 127) return; 63 const char *glyph = font8x8_basic[c]; 64 for (UINT32 row = 0; row < 8; row++) { 65 unsigned char bits = (unsigned char)glyph[row]; 66 for (UINT32 col = 0; col < 8; col++) { 67 if (bits & (1 << col)) { 68 for (UINT32 sy = 0; sy < scale; sy++) 69 for (UINT32 sx = 0; sx < scale; sx++) 70 draw_pixel(x + col * scale + sx, 71 y + row * scale + sy, color); 72 } 73 } 74 } 75} 76 77static UINT32 measure_string(const char *s, UINT32 scale) { 78 UINT32 len = 0; 79 while (s[len]) len++; 80 return len * 8 * scale; 81} 82 83static void draw_string(const char *s, UINT32 x, UINT32 y, 84 UINT32 scale, UINT32 color) { 85 while (*s) { 86 draw_char((unsigned char)*s, x, y, scale, color); 87 x += 8 * scale; 88 s++; 89 } 90} 91 92// --- Chainload --- 93 94static EFI_STATUS chainload(EFI_HANDLE ImageHandle, CHAR16 *path) { 95 EFI_STATUS status; 96 EFI_HANDLE new_image; 97 EFI_LOADED_IMAGE *loaded_image; 98 EFI_GUID lip_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID; 99 EFI_DEVICE_PATH *dev_path; 100 101 status = uefi_call_wrapper(BS->HandleProtocol, 3, 102 ImageHandle, &lip_guid, (void **)&loaded_image); 103 if (EFI_ERROR(status)) return status; 104 105 dev_path = FileDevicePath(loaded_image->DeviceHandle, path); 106 if (!dev_path) return EFI_NOT_FOUND; 107 108 status = uefi_call_wrapper(BS->LoadImage, 6, 109 FALSE, ImageHandle, dev_path, NULL, 0, &new_image); 110 FreePool(dev_path); 111 if (EFI_ERROR(status)) return status; 112 113 // Transfer control — does not return on success 114 status = uefi_call_wrapper(BS->StartImage, 3, new_image, NULL, NULL); 115 return status; 116} 117 118// --- Entry point --- 119 120EFI_STATUS EFIAPI efi_main(EFI_HANDLE ImageHandle, 121 EFI_SYSTEM_TABLE *SystemTable) { 122 EFI_STATUS status; 123 124 InitializeLib(ImageHandle, SystemTable); 125 126 // Disable UEFI watchdog timer (prevents auto-reset if boot takes long) 127 uefi_call_wrapper(BS->SetWatchdogTimer, 4, 0, 0, 0, NULL); 128 129 // Disable firmware console output (prevents POST text from appearing) 130 uefi_call_wrapper(ST->ConOut->EnableCursor, 2, ST->ConOut, FALSE); 131 uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); 132 133 // Initialize GOP 134 status = init_gop(); 135 if (EFI_ERROR(status)) goto chain; 136 137 // Clear screen to black 138 fill_screen(pack_color(0, 0, 0)); 139 140 // Draw "Aesthetic.Computer" centered 141 { 142 const char *text = "Aesthetic.Computer"; 143 UINT32 scale = (hres >= 2560) ? 4 : (hres >= 1920) ? 3 : 2; 144 UINT32 tw = measure_string(text, scale); 145 UINT32 x = (hres - tw) / 2; 146 UINT32 y = (vres - 8 * scale) / 2; 147 // Soft pink/lavender: R=220 G=180 B=200 148 UINT32 color = pack_color(220, 180, 200); 149 draw_string(text, x, y, scale, color); 150 } 151 152chain: 153 // Try systemd-boot first (for Mac split-kernel boot), fall back to direct kernel 154 status = chainload(ImageHandle, LOADER_PATH); 155 // LOADER.EFI not found or failed — try direct kernel (non-Mac boot) 156 status = chainload(ImageHandle, KERNEL_PATH); 157 158 // Both failed — show error 159 Print(L"Boot failed: %r\n", status); 160 uefi_call_wrapper(BS->Stall, 1, 5000000); 161 return status; 162}