├── .gitignore ├── BadApple.inf ├── BadApplePkg.dsc └── HelloWorld.c /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | *.log -------------------------------------------------------------------------------- /BadApple.inf: -------------------------------------------------------------------------------- 1 | ## @file 2 | # Brief Description of UEFI Bad Apple 3 | # 4 | # Detailed Description of UEFI Bad Apple 5 | # 6 | # Copyright for UEFI Bad Apple 7 | # 8 | # License for UEFI Bad Apple 9 | # 10 | ## 11 | 12 | [Defines] 13 | INF_VERSION = 1.25 14 | BASE_NAME = BadApple 15 | FILE_GUID = 476c4715-27f0-4f4c-b732-c5276cef7fa0 #Copy and paste the GUID from http://www.guidgen.com/ here 16 | MODULE_TYPE = UEFI_APPLICATION 17 | VERSION_STRING = 1.0 18 | ENTRY_POINT = UefiMain 19 | # 20 | # The following information is for reference only and not required by the build tools. 21 | # 22 | # VALID_ARCHITECTURES = IA32 X64 IPF EBC Etc... 23 | # 24 | 25 | [Sources] 26 | HelloWorld.c 27 | 28 | 29 | [Packages] 30 | MdePkg/MdePkg.dec 31 | MdeModulePkg/MdeModulePkg.dec 32 | ShellPkg/ShellPkg.dec 33 | 34 | [LibraryClasses] 35 | UefiApplicationEntryPoint 36 | UefiLib 37 | FileHandleLib 38 | UefiHiiServicesLib 39 | ShellLib 40 | BmpSupportLib 41 | SafeIntLib 42 | DebugLib 43 | 44 | [Guids] 45 | 46 | [Ppis] 47 | 48 | #[Protocols] 49 | # gEfiSimpleTextInputExProtocolGuid 50 | 51 | [FeaturePcd] 52 | 53 | [Pcd] -------------------------------------------------------------------------------- /BadApplePkg.dsc: -------------------------------------------------------------------------------- 1 | ## @file 2 | # BadApplePkg 3 | # 4 | # Copyright (c) 2021, Inoki. All rights reserved.
5 | # SPDX-License-Identifier: BSD-2-Clause-Patent 6 | ## 7 | 8 | [Defines] 9 | PLATFORM_NAME = BadApplePkg 10 | PLATFORM_GUID = c80dffb1-1821-4711-b7b5-f9be0b4530fd 11 | PLATFORM_VERSION = 0.01 12 | DSC_SPECIFICATION = 0x00010006 13 | OUTPUT_DIRECTORY = Build/BadApplePkg 14 | SUPPORTED_ARCHITECTURES = IA32|X64|ARM|AARCH64 15 | BUILD_TARGETS = DEBUG|RELEASE|NOOPT 16 | SKUID_IDENTIFIER = DEFAULT 17 | 18 | # 19 | # Debug output control 20 | # 21 | DEFINE DEBUG_ENABLE_OUTPUT = FALSE # Set to TRUE to enable debug output 22 | DEFINE DEBUG_PRINT_ERROR_LEVEL = 0x80000040 # Flags to control amount of debug output 23 | DEFINE DEBUG_PROPERTY_MASK = 0 24 | 25 | [LibraryClasses] 26 | # 27 | # Entry Point Libraries 28 | # 29 | UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf 30 | # 31 | # Common Libraries 32 | # 33 | BaseLib|MdePkg/Library/BaseLib/BaseLib.inf 34 | BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf 35 | UefiLib|MdePkg/Library/UefiLib/UefiLib.inf 36 | PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf 37 | PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf 38 | MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf 39 | !if $(DEBUG_ENABLE_OUTPUT) 40 | DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf 41 | DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf 42 | !else ## DEBUG_ENABLE_OUTPUT 43 | DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf 44 | !endif ## DEBUG_ENABLE_OUTPUT 45 | UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf 46 | UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf 47 | DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf 48 | RegisterFilterLib|MdePkg/Library/RegisterFilterLibNull/RegisterFilterLibNull.inf 49 | 50 | PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf 51 | IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf 52 | PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf 53 | PciCf8Lib|MdePkg/Library/BasePciCf8Lib/BasePciCf8Lib.inf 54 | SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf 55 | UefiRuntimeLib|MdePkg/Library/UefiRuntimeLib/UefiRuntimeLib.inf 56 | HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf 57 | UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf 58 | PerformanceLib|MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.inf 59 | HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf 60 | FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf 61 | SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf 62 | 63 | ShellLib|ShellPkg/Library/UefiShellLib/UefiShellLib.inf 64 | ShellCommandLib|ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf 65 | 66 | CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf 67 | 68 | BmpSupportLib|MdeModulePkg/Library/BaseBmpSupportLib/BaseBmpSupportLib.inf 69 | SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf 70 | 71 | [Components] 72 | BadApplePkg/BadApple.inf -------------------------------------------------------------------------------- /HelloWorld.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // Provide gBS 6 | #include 7 | 8 | // Protocols 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | #define VIDEO_WIDTH 480 21 | #define VIDEO_HEIGHT 360 22 | 23 | EFI_STATUS 24 | LoadBMP ( 25 | IN CHAR16 *FileName, 26 | OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **Buffer, 27 | OUT UINTN *Height, 28 | OUT UINTN *Width, 29 | OUT UINTN *Size 30 | ) 31 | { 32 | EFI_STATUS Status = EFI_SUCCESS; 33 | SHELL_FILE_HANDLE FileHandle; 34 | CHAR16 *FullFileName; 35 | 36 | if (FileName == NULL) { 37 | return EFI_UNSUPPORTED; 38 | } 39 | 40 | FullFileName = ShellFindFilePath(FileName); 41 | if (FullFileName == NULL) { 42 | Status = EFI_NOT_FOUND; 43 | goto Cleanup; 44 | } 45 | Status = ShellOpenFileByName(FullFileName, &FileHandle, EFI_FILE_MODE_READ, 0); 46 | if (EFI_ERROR(Status)) { 47 | goto Cleanup; 48 | } 49 | 50 | ShellSetFilePosition(FileHandle, 0); 51 | EFI_FILE_INFO *FileInfo = ShellGetFileInfo(FileHandle); 52 | 53 | void *File = (void *) 1; //To make BmpSupportLib happy 54 | //UINTN Size = FileInfo->FileSize; 55 | 56 | ShellReadFile(FileHandle, &FileInfo->FileSize, File); 57 | if (EFI_ERROR(Status)) { 58 | goto Cleanup; 59 | } 60 | 61 | // *Buffer = 0; 62 | *Height = 0; 63 | *Width = 0; 64 | 65 | Status = TranslateBmpToGopBlt(File, FileInfo->FileSize, Buffer, Size, Height, Width); 66 | if (EFI_ERROR(Status)) { 67 | goto Cleanup; 68 | } 69 | Cleanup: 70 | ShellCloseFile(&FileHandle); 71 | if (FullFileName != NULL) { 72 | FreePool(FullFileName); 73 | } 74 | 75 | return Status; 76 | } 77 | 78 | /** 79 | Entry point for the game. 80 | 81 | @param[in] ImageHandle The firmware allocated handle for the EFI image. 82 | @param[in] SystemTable A pointer to the EFI System Table. 83 | 84 | @retval EFI_SUCCESS The entry point is executed successfully. 85 | @retval other Some error occurs when executing this entry point. 86 | 87 | **/ 88 | EFI_STATUS 89 | EFIAPI 90 | UefiMain ( 91 | IN EFI_HANDLE ImageHandle, 92 | IN EFI_SYSTEM_TABLE *SystemTable 93 | ) 94 | { 95 | EFI_STATUS Status = EFI_SUCCESS; 96 | 97 | Print(L"Hello World!\n"); 98 | EFI_GRAPHICS_OUTPUT_PROTOCOL *graphicsProtocol = NULL; 99 | Status = gBS->LocateProtocol(&gEfiGraphicsOutputProtocolGuid, NULL, (void**)&graphicsProtocol); 100 | if (EFI_SUCCESS != Status) { 101 | Print(L"Error locating graphics protocol\n"); 102 | return Status; 103 | } 104 | Print(L"Graphics protocol located\n"); 105 | // graphicsProtocol->QueryMode(graphicsProtocol, ); 106 | UINTN SizeOfInfo = 0; 107 | EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; 108 | 109 | UINT32 screenWidth = VIDEO_WIDTH, screenHeight = VIDEO_HEIGHT; 110 | for(UINTN i = 0; i < graphicsProtocol->Mode->MaxMode; i++) 111 | { 112 | Status = graphicsProtocol->QueryMode( 113 | graphicsProtocol, 114 | i, 115 | &SizeOfInfo, 116 | &Info 117 | ); 118 | if(EFI_ERROR(Status)) 119 | { 120 | Print(L"Failed to Querymode.\n"); 121 | return Status; 122 | } 123 | if (Info->HorizontalResolution >= 480 && Info->VerticalResolution >= 360) { 124 | // Buffer the screen scale 125 | screenWidth = Info->HorizontalResolution; 126 | screenHeight = Info->VerticalResolution; 127 | Print(L"Screen info %dx%d.\n", screenWidth, screenHeight); 128 | Status = graphicsProtocol->SetMode(graphicsProtocol, i); 129 | break; 130 | } 131 | } 132 | 133 | // Read files 134 | SHELL_FILE_HANDLE BABinFileHandle; 135 | CHAR16 *FullFileName; 136 | FullFileName = ShellFindFilePath(L"BA.bin"); 137 | if (FullFileName == NULL) { 138 | Print(L"Failed to find BadApple bin compression file.\n"); 139 | goto Cleanup; 140 | } 141 | Status = ShellOpenFileByName(FullFileName, &BABinFileHandle, EFI_FILE_MODE_READ, 0); 142 | if (EFI_ERROR(Status)) { 143 | Print(L"Failed to load BadApple bin compression file.\n"); 144 | goto Cleanup; 145 | } 146 | 147 | EFI_STRING StringPtr = NULL; 148 | UINTN Length = StrLen (L"BadAppleIFrames\\image-000.bmp") + 1; 149 | StringPtr = AllocateZeroPool (Length * sizeof (CHAR16)); 150 | UINTN SpriteSheetSize; 151 | UINTN SpriteSheetHeight; 152 | UINTN SpriteSheetWidth; 153 | EFI_GRAPHICS_OUTPUT_BLT_PIXEL *intraFrames[52]; 154 | for (int i = 0; i < 52; i+=1) { 155 | intraFrames[i] = NULL; 156 | UnicodeSPrint (StringPtr, Length * sizeof (CHAR16), L"BadAppleIFrames\\image-%03d.bmp", i + 1); 157 | // Print(L"Loading key frame %d.\n", i + 1); 158 | Status = LoadBMP(StringPtr, &intraFrames[i], &SpriteSheetHeight, &SpriteSheetWidth, &SpriteSheetSize); 159 | if (EFI_ERROR(Status)) { 160 | Print(L"Failed to load key frame.\n"); 161 | goto Cleanup; 162 | } 163 | // Print(L"Key frame %d loaded.\n", i + 1); 164 | } 165 | 166 | // Setup tick loop 167 | // BadAppleFrames 168 | Print(L"Setup tick loop.\n"); 169 | EFI_EVENT TickEvent; 170 | UINTN eventId; 171 | gBS->CreateEvent(EVT_TIMER, 0, NULL, NULL, &TickEvent); 172 | gBS->SetTimer(TickEvent, TimerPeriodic, EFI_TIMER_PERIOD_MILLISECONDS(33)); 173 | 174 | EFI_GRAPHICS_OUTPUT_BLT_PIXEL *DrawBuffer; 175 | UINTN ReadLength = 4; 176 | UINTN BeginX = (screenWidth - VIDEO_WIDTH) / 2; 177 | UINTN BeginY = (screenHeight - VIDEO_HEIGHT) / 2; 178 | DrawBuffer = NULL; // = AllocateCopyPool(VIDEO_WIDTH * BMP_TILE_LENGTH * VIDEO_HEIGHT * BMP_TILE_LENGTH, BackgroundBuffer); 179 | int intraFrameIndex = 0; 180 | unsigned char Buffer[4]; 181 | int NeedRefresh = 1; 182 | for (int i = 0; i < 6573; i+=1) { 183 | NeedRefresh = 1; 184 | UINTN DecodedInt32; 185 | ReadLength = 4; 186 | Status = ShellReadFile(BABinFileHandle, &ReadLength, (void *)Buffer); 187 | if (ReadLength != 4) { 188 | // FIXME: How can this happens 189 | } 190 | // Read as little endian 191 | DecodedInt32 = ((Buffer[3] << 24) | (Buffer[2] << 16) | (Buffer[1] << 8) | Buffer[0]); 192 | // Print(L"Read %d bytes: 0x%04X.\n", ReadLength, DecodedInt32); 193 | if (EFI_ERROR(Status)) { 194 | Print(L"Read file failed at %d.\n", i); 195 | goto Cleanup; 196 | } 197 | if ((DecodedInt32 & 0x80000000) != 0) { 198 | if ((DecodedInt32 & 0x7FFF7FFF) == 0x7FFF7FFF) { 199 | // Keep frame and do not refresh 200 | NeedRefresh = 0; 201 | // Print(L"Not need refresh at %d.\n", i); 202 | } else { 203 | // Print(L"Patching at %d.\n", i); 204 | do { 205 | UINTN PatchX = ((DecodedInt32 & 0x0FFF0000) >> 16), PatchY = (DecodedInt32 & 0x7FFF); 206 | UINTN GrayScale = ((DecodedInt32 & 0x70000000) >> 28); 207 | // Begin patch until 0xFFFFFFFF 208 | if (PatchX < VIDEO_WIDTH && PatchY <= VIDEO_HEIGHT) { 209 | EFI_GRAPHICS_OUTPUT_BLT_PIXEL *PickedPixel = (DrawBuffer + PatchY * VIDEO_WIDTH + PatchX); 210 | switch (GrayScale) 211 | { 212 | case 0: 213 | PickedPixel->Blue = 0; 214 | PickedPixel->Green = 0; 215 | PickedPixel->Red = 0; 216 | break; 217 | case 7: 218 | PickedPixel->Blue = 255; 219 | PickedPixel->Green = 255; 220 | PickedPixel->Red = 255; 221 | break; 222 | default: 223 | PickedPixel->Blue = 32 * GrayScale; 224 | PickedPixel->Green = 32 * GrayScale; 225 | PickedPixel->Red = 32 * GrayScale; 226 | break; 227 | } 228 | } 229 | 230 | // Read next 231 | ReadLength = 4; 232 | Status = ShellReadFile(BABinFileHandle, &ReadLength, (void *)Buffer); 233 | // Read as little endian 234 | DecodedInt32 = ((Buffer[3] << 24) | (Buffer[2] << 16) | (Buffer[1] << 8) | Buffer[0]); 235 | // Print(L"Read %d bytes: 0x%04X.\n", ReadLength, DecodedInt32); 236 | } while ((DecodedInt32 & 0x7FFF7FFF) != 0x7FFF7FFF); 237 | } 238 | } else { 239 | // Read one intra-frame 240 | // Print(L"Print key frame %d at %d.\n", intraFrameIndex, i); 241 | DrawBuffer = intraFrames[intraFrameIndex++]; 242 | } 243 | 244 | // Wait for tick 245 | gBS->WaitForEvent(1, &TickEvent, &eventId); 246 | if (NeedRefresh) 247 | graphicsProtocol->Blt(graphicsProtocol, DrawBuffer, EfiBltBufferToVideo, 0, 0, BeginX, BeginY, VIDEO_WIDTH, VIDEO_HEIGHT, 0); 248 | } 249 | Cleanup: 250 | FreePool(StringPtr); 251 | if (DrawBuffer != NULL) { 252 | FreePool(DrawBuffer); 253 | } 254 | ShellCloseFile(&BABinFileHandle); 255 | if (FullFileName != NULL) { 256 | FreePool(FullFileName); 257 | } 258 | gBS->CloseEvent(TickEvent); 259 | gST->ConOut->EnableCursor(gST->ConOut, TRUE); 260 | if (!EFI_ERROR(Status)) { 261 | gST->ConOut->ClearScreen(gST->ConOut); 262 | } 263 | return Status; 264 | } 265 | --------------------------------------------------------------------------------