├── .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 |
--------------------------------------------------------------------------------