Compare commits

...

18 Commits

Author SHA1 Message Date
PoliEcho 92e474853b Update README.md 2025-08-19 19:33:50 +00:00
PoliEcho 24e7c443a1 fix aarch64 compilation 2025-08-19 21:13:02 +02:00
PoliEcho 37f63d51b9 README additions 2025-08-19 20:11:57 +02:00
PoliEcho 09ff9f8f19 some misc changes 2025-08-19 19:30:50 +02:00
PoliEcho 83df1a6048 Update README.md 2025-08-19 17:05:27 +02:00
PoliEcho 36a7c9066a misc changes 2025-08-19 16:38:32 +02:00
PoliEcho 9b768a4e9e README and build.sh changes 2025-08-19 16:35:16 +02:00
PoliEcho 868d27cecb update edk2 2025-08-18 23:16:58 +02:00
PoliEcho c72a80832b forgot to commit README 2025-08-18 21:05:24 +02:00
PoliEcho 54a54de423 enhance build script 2025-08-18 21:05:04 +02:00
PoliEcho 8af36091ba add input 2025-08-18 20:47:56 +02:00
PoliEcho fa35f79e34 addtions to test script 2025-08-17 15:14:07 +02:00
PoliEcho 83ef67ad28 fix rockets a bit 2025-08-17 14:37:30 +02:00
PoliEcho 91001e09ba add rockets 2025-08-16 16:29:37 +02:00
PoliEcho 8c53885621 update gitignore 2025-08-16 16:28:59 +02:00
PoliEcho 887e393d92 polishing a bit 2025-08-16 13:20:03 +02:00
PoliEcho f2ad30047a fix on real hardware 2025-08-15 19:26:00 +02:00
PoliEcho 24edc2599b addded simulation and fixed serial 2025-08-15 17:09:27 +02:00
23 changed files with 643 additions and 85 deletions
+2 -1
View File
@@ -1,3 +1,4 @@
build/
.cache/
compile_commands.json
compile_commands.json
src/UEFI_fireworks/rocket.c
+86 -3
View File
@@ -1,5 +1,88 @@
Arch uefi_run fix: sudo ln -s /usr/share/edk2/x64/OVMF_CODE.4m.fd /usr/share/qemu/OVMF.fd
# UEFI Fireworks
### Retro fireworks you can run on your modern UEFI system
Simple automatic fireworks app that runs on your UEFI firmware with basic controls.
Primary purpose of this app is just to look at something nice.
cd edk2
> [!CAUTION]
> This app may cause epileptic seizures in people with epilepsy.
> $\color{red}{\text{!!!If you have a history of seizures, do not use this program!!!}}$
> I don't know if colorful expanding circles can cause seizures and i don't want for anyone to get hurt
## How to build
> [!IMPORTANT]
> You will need these programs to compile:
> - git
> - gcc
> - xxd
> - ImageMagick (if you changed the firework image)
```bash
git submodule update --init --recursive
cd edk2
source edksetup.sh
make -C BaseTools # if first run
make -C BaseTools
cd ..
./build.sh # to build for a different arch than X64 change TARGET_ARCH in build.sh
```
## How to use
### Download release
#### On real hardware
If you have an amd64 (x86_64) UEFI computer,
download the release and copy UEFI_fireworks.efi to /EFI/BOOT/bootx64.efi (case-insensitive).
#### On VM
You will need OVMF firmware; you can get it here: https://qemu.weilnetz.de/test/ovmf/usr/share/OVMF/OVMF_CODE_4M.fd
Run:
```bash
qemu-system-x86_64 -machine type=q35,accel=kvm -drive if=pflash,format=raw,readonly=on,file="$OVMF_CODE_PATH" -hda fat:rw:build -boot order=c -smp 4 -s -serial mon:stdio
```
### Build
#### On VM
You will need OVMF firmware; you can get it here: https://qemu.weilnetz.de/test/ovmf/usr/share/OVMF/OVMF_CODE_4M.fd
Run:
```bash
./test.sh $OVMF_CODE_PATH # only works on AMD64
```
to run in a VM using QEMU.
#### On real hardware
Copy:
```
edk2/Build/UEFI_fireworks/DEBUG_GCC5//UEFI_fireworks.efi
```
to a FAT32 or FAT16 USB at the following location:
| Architecture | Default Boot Path |
| --------------- | ------------------------ |
| x86_64 (AMD64) | `/EFI/BOOT/BOOTX64.EFI` |
| x86 (IA32) | `/EFI/BOOT/BOOTIA32.EFI` |
| ARM64 (AARCH64) | `/EFI/BOOT/BOOTAA64.EFI` |
| ARM (32-bit) | `/EFI/BOOT/BOOTARM.EFI` |
## Controlling
| Key | Action | Note |
| ---------- | ------------ | ---------------------------------- |
| ARROW_UP | speed up | delays under 1ms may be unreliable |
| ARROW_DOWN | slow down | max delay is about UINT32_MAX μs |
| PAGE_UP | speed up | 10× step |
| PAGE_DOWN | slow down | 10× step |
| Home | reset speed | reset frame delay to 10ms |
| Delete | clear screen | |
## Showcase
In QEMU/KVM
https://github.com/user-attachments/assets/275e28aa-eb2e-4348-ac08-95f909c46a1f
+9 -4
View File
@@ -4,7 +4,7 @@
PLATFORM_VERSION = 1.0
DSC_SPECIFICATION = 0x00010005
OUTPUT_DIRECTORY = Build/UEFI_fireworks
SUPPORTED_ARCHITECTURES = X64
SUPPORTED_ARCHITECTURES = X64|IA32|AARCH64
BUILD_TARGETS = DEBUG|RELEASE
SKUID_IDENTIFIER = DEFAULT
@@ -17,16 +17,21 @@ MemoryAllocationLib|edk2/MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAlloca
DevicePathLib|edk2/MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
UefiBootServicesTableLib|edk2/MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
UefiRuntimeServicesTableLib|edk2/MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
DebugLib|edk2/MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf
DebugLib|edk2/MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf
PrintLib|edk2/MdePkg/Library/BasePrintLib/BasePrintLib.inf
PcdLib|edk2/MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
RegisterFilterLib|edk2/MdePkg/Library/RegisterFilterLibNull/RegisterFilterLibNull.inf
StackCheckLib|edk2/MdePkg/Library/StackCheckLibNull/StackCheckLibNull.inf
TimerLib|edk2/MdePkg/Library/SecPeiDxeTimerLibCpu/SecPeiDxeTimerLibCpu.inf
IoLib|edk2/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
RngLib|edk2/MdePkg/Library/BaseRngLib/BaseRngLib.inf
SerialPortLib|edk2/MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.inf
DebugPrintErrorLevelLib|edk2/MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
LocalApicLib|edk2/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.inf
CpuLib|edk2/MdePkg/Library/BaseCpuLib/BaseCpuLib.inf
UefiRuntimeServicesTableLib|edk2/MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
TimerLib|edk2/MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf
BmpSupportLib|edk2/MdeModulePkg/Library/BaseBmpSupportLib/BaseBmpSupportLib.inf
SafeIntLib|edk2/MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf
[Components]
src/UEFI_fireworks/UEFI_fireworks.inf
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
View File
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

+15 -4
View File
@@ -1,9 +1,20 @@
#!/bin/bash
export PACKAGES_PATH=$PWD:$PWD/edk2
export TARGET_ARCH=X64
# export GCC5_AARCH64_PREFIX=aarch64-linux-gnu- # uncomment for AARCH64 crosscompilation or you can use
# export GCC5_AARCH64_PREFIX=aarch64-none-elf-
magick assets/rocket_orig.bmp -type TrueColor -define bmp:format=bmp3 -compress None assets/rocket.bmp
xxd -i assets/rocket.bmp > src/UEFI_fireworks/rocket.c
if [ "$1" == "debug" ]; then
build -a X64 -t GCC5 -p UEFI_fireworks.dsc -b DEBUG
build -a $TARGET_ARCH -t GCC5 -p UEFI_fireworks.dsc -b DEBUG
else
build -a X64 -t GCC5 -p UEFI_fireworks.dsc
build -a $TARGET_ARCH -t GCC5 -p UEFI_fireworks.dsc -b RELEASE
fi
mkdir -p build
cp edk2/Build/UEFI_fireworks/DEBUG_GCC5/X64/UEFI_fireworks.efi build/
mkdir -p build/EFI/BOOT/
if [ "$1" == "debug" ]; then
cp -v $(find edk2/Build/UEFI_fireworks/DEBUG_GCC5/ -name "UEFI_fireworks.efi" -type f | head -1) build/
cp -v $(find edk2/Build/UEFI_fireworks/DEBUG_GCC5/ -name "UEFI_fireworks.efi" -type f | head -1) build/EFI/BOOT/BOOTX64.EFI
else
cp -v $(find edk2/Build/UEFI_fireworks/RELEASE_GCC5/ -name "UEFI_fireworks.efi" -type f | head -1) build/
cp -v $(find edk2/Build/UEFI_fireworks/RELEASE_GCC5/ -name "UEFI_fireworks.efi" -type f | head -1) build/EFI/BOOT/BOOTX64.EFI
fi
+1 -1
Submodule edk2 updated: 808f1f1f87...d46aa46c83
+9 -1
View File
@@ -6,9 +6,15 @@
VERSION_STRING = 1.0
ENTRY_POINT = UefiMain
[Sources]
[Sources.Common]
UefiMain.c
drawing.c
rng.c
time.c
rocket.c
[Sources.AARCH64]
memcpy.c
[Packages]
edk2/MdePkg/MdePkg.dec
@@ -27,6 +33,8 @@
TimerLib
RngLib
SerialPortLib
UefiRuntimeServicesTableLib
BmpSupportLib
[Protocols]
gEfiRngProtocolGuid
+163 -46
View File
@@ -1,8 +1,12 @@
#include "Library/UefiApplicationEntryPoint.h"
#include "ProcessorBind.h"
#include "Protocol/SimpleTextIn.h"
#include "Uefi/UefiBaseType.h"
#include "const.h"
#include "drawing.h"
#include "global.h"
#include "macros.h"
#include "rng.h"
#include "time.h"
#include "types.h"
#include <Base.h>
#include <Library/BaseLib.h>
@@ -10,20 +14,26 @@
#include <Library/MemoryAllocationLib.h>
#include <Library/RngLib.h>
#include <Library/SerialPortLib.h>
#include <Library/TimerLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Protocol/GraphicsOutput.h>
#include <Uefi.h>
#include <stdint.h>
EFI_GRAPHICS_OUTPUT_BLT_PIXEL night_sky =
COLOR_FROM_HEX(0x090531); // this cannot be const becose EDK2 said so
#define DEFAULT_SLEEP_TIME 10000
firework_instance create_firework();
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput = NULL;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *framebuffer = NULL;
EFI_STATUS EFIAPI UefiMain(IN EFI_HANDLE imgHandle,
IN EFI_SYSTEM_TABLE *sysTable) {
Print(L"Starting program\n");
gST = sysTable;
gBS = sysTable->BootServices;
gImageHandle = imgHandle;
gRT = sysTable->RuntimeServices;
// UEFI apps automatically exit after 5 minutes. Stop that here
gBS->SetWatchdogTimer(0, 0, 0, NULL);
@@ -37,63 +47,170 @@ EFI_STATUS EFIAPI UefiMain(IN EFI_HANDLE imgHandle,
gBS->LocateProtocol(&gEfiGraphicsOutputProtocolGuid, NULL,
(VOID **)&GraphicsOutput);
framebuffer =
(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)GraphicsOutput->Mode->FrameBufferBase;
if (GraphicsOutput == NULL) {
Print(L"GraphicsOutput protocol not found!\n");
return EFI_NOT_FOUND;
}
clear_screen(GraphicsOutput);
framebuffer = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)(UINTN)
GraphicsOutput->Mode->FrameBufferBase;
LIST_ENTRY firework_list;
InitializeListHead(&firework_list);
init_rng();
init_rocket_blt();
if (SerialPortInitialize() == RETURN_SUCCESS) {
SERIAL_PRINT("Serial initialized");
SERIAL_PRINT("Serial initialized\n");
} else {
Print(L"Failed to initialize Serial");
Exit(RETURN_DEVICE_ERROR);
Print(L"Failed to initialize Serial!\n");
}
SerialPortSetControl(EFI_SERIAL_CLEAR_TO_SEND |
EFI_SERIAL_DATA_TERMINAL_READY |
EFI_SERIAL_REQUEST_TO_SEND);
firework_instance *firework_array[UINT8_MAX];
gBS->SetMem(firework_array, sizeof(firework_array),
0); // make all pointers null
SERIAL_PRINT("DOES it work?\n");
Print(L"If you see this message for long time, timer does not work\n");
microsleep(1);
clear_screen();
UINTN sleep_time = DEFAULT_SLEEP_TIME;
while (TRUE) {
UINT32 random;
GetRandomNumber32(&random);
if (random % 6 == 0) {
UINT8 random;
fill_random_bytes(&random, sizeof(random));
if (random % 30 == 0) {
// spawn new firework
firework_node *new_firework_node =
AllocateZeroPool(sizeof(firework_node));
if (new_firework_node == NULL) {
firework_instance *new_firework_instence =
AllocateZeroPool(sizeof(firework_instance));
if (new_firework_instence == NULL) {
return EFI_OUT_OF_RESOURCES;
}
new_firework_node->Signature = FIREWORK_NODE_SIGNATURE;
GetRandomNumber32(&random);
new_firework_node->Firework.max_r =
random % 501; // so max number can be 500
for (UINT8 i = 0; i < ARRAY_SIZE(new_firework_node->Firework.color);
i++) {
GetRandomNumber32(
(UINT32 *)&new_firework_node->Firework.color[i]); // belive
new_firework_node->Firework.r[i] = 0;
*new_firework_instence = create_firework();
for (UINT8 i = 0; i < ARRAY_SIZE(firework_array); i++) {
if (firework_array[i] == NULL ||
firework_array[i]->status == INACTIVE) {
if (firework_array[i] != NULL) {
FreePool(firework_array[i]); // free firework
firework_array[i] = NULL;
}
firework_array[i] = new_firework_instence;
goto assgned;
} // firework will not be created if if all slots are full
}
new_firework_node->Firework.cleanup_r = 0;
GetRandomNumber32(&random);
new_firework_node->Firework.x =
random % GraphicsOutput->Mode->Info->HorizontalResolution + 1;
GetRandomNumber32(&random);
new_firework_node->Firework.y =
random % GraphicsOutput->Mode->Info->VerticalResolution + 1;
InsertTailList(&firework_list, &new_firework_node->Link);
SERIAL_PRINT("NO free slots\n");
}
firework_node *current_node = NULL;
for (LIST_ENTRY *node = GetFirstNode(&firework_list);
!IsNodeAtEnd(&firework_list, node);
node = GetNextNode(&firework_list, node)) {
// Print(L"Processing firework\r\n");
current_node = CR(node, firework_node, Link, FIREWORK_NODE_SIGNATURE);
if (!step_firework(&current_node->Firework)) {
RemoveEntryList(node); // remove if firework ended
assgned:
for (UINT8 i = 0; i < ARRAY_SIZE(firework_array); i++) {
if (firework_array[i] != NULL) {
if (firework_array[i]->status == ACTIVE) {
if (!step_firework(firework_array[i])) {
firework_array[i]->status = INACTIVE;
}
} else if (firework_array[i]->status == LAUNCHING) {
if (!step_rocket(&firework_array[i]->rocket, firework_array[i]->y)) {
firework_array[i]->status = ACTIVE;
}
} else {
FreePool(firework_array[i]); // free firework
firework_array[i] = NULL;
}
}
}
MicroSecondDelay(500000);
EFI_INPUT_KEY key;
EFI_STATUS status = gST->ConIn->ReadKeyStroke(gST->ConIn, &key);
gST->ConIn->Reset(gST->ConIn, FALSE);
if (status == EFI_SUCCESS) {
switch (key.ScanCode) {
case SCAN_UP: // increase simulation speed
if (sleep_time > 100) {
sleep_time = sleep_time - 100;
} else if (sleep_time > 10) {
sleep_time = sleep_time - 10;
} else if (sleep_time > 1) {
sleep_time = sleep_time - 1;
}
break;
case SCAN_DOWN:
if (sleep_time < UINT32_MAX - 100) {
sleep_time = sleep_time + 100;
} else if (sleep_time < UINT32_MAX - 10) {
sleep_time = sleep_time + 10;
} else if (sleep_time < UINT32_MAX - 1) {
sleep_time = sleep_time + 1;
}
break;
case SCAN_PAGE_UP:
if (sleep_time > 1000) {
sleep_time = sleep_time - 1000;
} else if (sleep_time > 100) {
sleep_time = sleep_time - 100;
} else if (sleep_time > 10) {
sleep_time = sleep_time - 10;
} else if (sleep_time > 1) {
sleep_time = sleep_time - 1;
}
break;
case SCAN_PAGE_DOWN:
if (sleep_time < UINT32_MAX - 1000) {
sleep_time = sleep_time + 1000;
} else if (sleep_time < UINT32_MAX - 100) {
sleep_time = sleep_time + 100;
} else if (sleep_time < UINT32_MAX - 10) {
sleep_time = sleep_time + 10;
} else if (sleep_time < UINT32_MAX - 1) {
sleep_time = sleep_time + 1;
}
break;
case SCAN_HOME:
sleep_time = DEFAULT_SLEEP_TIME;
break;
case SCAN_DELETE:
for (UINT8 i = 0; i < ARRAY_SIZE(firework_array); i++) {
if (firework_array[i] != NULL) {
FreePool(firework_array[i]);
firework_array[i] = NULL;
}
}
// clear_screen(); does not work on real hardware here for some unknown
// reason
for (UINTN i = 0; i < GraphicsOutput->Mode->FrameBufferSize; i++) {
framebuffer[i] = night_sky;
}
break;
}
}
microsleep(sleep_time);
}
return EFI_SUCCESS;
}
firework_instance create_firework() {
firework_instance firework;
UINT32 random;
fill_random_bytes(&random, sizeof(random));
firework.max_r = (random % 190) + 10; // 10 to 200,
for (UINT8 i = 0; i < ARRAY_SIZE(firework.color); i++) {
fill_random_bytes(&firework.color[i],
sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL) - 1);
firework.r[i] = 0;
}
firework.cleanup_r = 0;
fill_random_bytes(&random, sizeof(random));
firework.x = random % GraphicsOutput->Mode->Info->HorizontalResolution;
fill_random_bytes(&random, sizeof(random));
firework.y = random % GraphicsOutput->Mode->Info->VerticalResolution /
2; // spawn only on upper half of the screen
firework.rocket.x = firework.x + rocket_asset.width / 2;
firework.rocket.y = GraphicsOutput->Mode->Info->VerticalResolution;
firework.status = LAUNCHING;
return firework;
}
+3
View File
@@ -0,0 +1,3 @@
#pragma once
extern unsigned char assets_rocket_bmp[];
extern unsigned int assets_rocket_bmp_len;
+3 -2
View File
@@ -2,5 +2,6 @@
#include "macros.h"
#include <Protocol/GraphicsOutput.h>
EFI_GRAPHICS_OUTPUT_BLT_PIXEL night_sky =
COLOR_FROM_HEX(0x11095e); // this cannot be const becose EDK2 said so
extern EFI_GRAPHICS_OUTPUT_BLT_PIXEL night_sky;
enum firework_status { INACTIVE, ACTIVE, LAUNCHING };
+75 -5
View File
@@ -1,20 +1,29 @@
#include "Base.h"
#include "Library/BaseMemoryLib.h"
#include "Library/MemoryAllocationLib.h"
#include "Library/UefiLib.h"
#include "ProcessorBind.h"
#include "bmp.h"
#include "const.h"
#include "global.h"
#include "time.h"
#include "types.h"
#include <../MdeModulePkg/Include/Library/BmpSupportLib.h>
#include <Library/UefiApplicationEntryPoint.h>
#include <Protocol/GraphicsOutput.h>
#include <alloca.h>
void draw_pixel(const UINT32 x, const UINT32 y,
const EFI_GRAPHICS_OUTPUT_BLT_PIXEL pixel) {
if (x >= GraphicsOutput->Mode->Info->HorizontalResolution ||
y >= GraphicsOutput->Mode->Info
->VerticalResolution) { // ignore when out of bounds
return;
}
UINTN framebuffer_offset =
(y * GraphicsOutput->Mode->Info->PixelsPerScanLine) + x;
if (framebuffer_offset <
GraphicsOutput->Mode->FrameBufferSize) { // ignre when out of bounds
framebuffer[framebuffer_offset] = pixel;
}
framebuffer[framebuffer_offset] = pixel;
}
// uses Mid-Point Circle Drawing Algorithm
@@ -82,7 +91,7 @@ void clear_screen() {
}
}
BOOLEAN step_firework(struct firework_instance *firework) {
BOOLEAN step_firework(firework_instance *firework) {
for (UINT8 i = 0; i < ARRAY_SIZE(firework->r); i++) {
if (firework->r[i] < firework->max_r) {
if (i == 0 || (firework->max_r / 3.5) * i <= firework->r[i - 1]) {
@@ -102,3 +111,64 @@ BOOLEAN step_firework(struct firework_instance *firework) {
}
return TRUE;
}
rocket_blt rocket_asset;
BOOLEAN **rocket_alfa_mask;
UINT32 *rocket_clean_up_mask;
void init_rocket_blt() {
EFI_STATUS Status = TranslateBmpToGopBlt(
assets_rocket_bmp, assets_rocket_bmp_len, &rocket_asset.blt,
&rocket_asset.blt_size, &rocket_asset.height, &rocket_asset.width);
if (EFI_ERROR(Status)) {
Print(L"Failed to load rocket asset: %r\n", Status);
Exit(Status);
}
rocket_clean_up_mask = AllocatePool(rocket_asset.width * sizeof(location));
rocket_alfa_mask = AllocateZeroPool(rocket_asset.height * sizeof(BOOLEAN *));
for (UINT32 i = 0; i < rocket_asset.height; i++) {
rocket_alfa_mask[i] = AllocatePool(rocket_asset.width * sizeof(BOOLEAN));
for (UINT32 j = 0; j < rocket_asset.width; j++) {
if (rocket_asset.blt[i * rocket_asset.width + j].Blue == 0 &&
rocket_asset.blt[i * rocket_asset.width + j].Green == 0 &&
rocket_asset.blt[i * rocket_asset.width + j].Red == 0) {
rocket_alfa_mask[i][j] = FALSE;
} else {
rocket_alfa_mask[i][j] = TRUE;
rocket_clean_up_mask[j] = i + 1; // build the cleanup mask
}
}
}
}
void draw_rocket(location *rocket) {
for (UINT32 i = 0; i < rocket_asset.width; i++) {
for (UINT32 j = 0; j < rocket_asset.height; j++) {
if (rocket_alfa_mask[j][i]) {
draw_pixel(i + rocket->x, j + rocket->y,
rocket_asset.blt[j * rocket_asset.width + i]);
}
}
}
}
BOOLEAN step_rocket(location *rocket, UINT32 max_y) {
draw_rocket(rocket);
for (UINT8 i = 0; i < rocket_asset.width; i++) {
draw_pixel(rocket->x + i, rocket->y + rocket_clean_up_mask[i], night_sky);
}
if (rocket->y <= max_y) {
// remove rocket
for (UINT32 i = 0; i < rocket_asset.width; i++) {
for (UINT32 j = 0; j < rocket_asset.height; j++) {
if (rocket_alfa_mask[j][i]) {
draw_pixel(i + rocket->x, j + rocket->y, night_sky);
}
}
}
return FALSE;
} else {
rocket->y--;
return TRUE;
}
}
+4 -2
View File
@@ -3,5 +3,7 @@
#include <Protocol/GraphicsOutput.h>
void draw_circle(int xc, int yc, int r,
const EFI_GRAPHICS_OUTPUT_BLT_PIXEL color);
void clear_screen(EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput);
BOOLEAN step_firework(struct firework_instance *firework);
void clear_screen();
BOOLEAN step_firework(firework_instance *firework);
void init_rocket_blt();
BOOLEAN step_rocket(location *rocket, UINT32 max_y);
+3 -1
View File
@@ -1,4 +1,6 @@
#pragma once
#include "types.h"
#include <Protocol/GraphicsOutput.h>
extern EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
extern EFI_GRAPHICS_OUTPUT_BLT_PIXEL *framebuffer;
extern EFI_GRAPHICS_OUTPUT_BLT_PIXEL *framebuffer;
extern rocket_blt rocket_asset;
+1 -1
View File
@@ -5,4 +5,4 @@
.Red = ((hex) >> 16) & 0xFF, \
.Reserved = 0}
#define SERIAL_PRINT(str) SerialPortWrite((UINT8 *)str, AsciiStrLen(str))
#define SERIAL_PRINT(str) SerialPortWrite((UINT8 *)str, AsciiStrLen(str))
+96
View File
@@ -0,0 +1,96 @@
#include <Library/BaseLib.h>
#include <Uefi.h>
VOID *memcpy(VOID *CONST Destination, CONST VOID *Source, UINTN Length) {
UINT8 *Dest = (UINT8 *)Destination;
CONST UINT8 *Src = (CONST UINT8 *)Source;
if (Length < 16) {
switch (Length) {
case 15:
*Dest++ = *Src++;
case 14:
*Dest++ = *Src++;
case 13:
*Dest++ = *Src++;
case 12:
*Dest++ = *Src++;
case 11:
*Dest++ = *Src++;
case 10:
*Dest++ = *Src++;
case 9:
*Dest++ = *Src++;
case 8:
*Dest++ = *Src++;
case 7:
*Dest++ = *Src++;
case 6:
*Dest++ = *Src++;
case 5:
*Dest++ = *Src++;
case 4:
*Dest++ = *Src++;
case 3:
*Dest++ = *Src++;
case 2:
*Dest++ = *Src++;
case 1:
*Dest++ = *Src++;
case 0:
break;
}
return Destination;
}
#ifdef MDE_CPU_X64
typedef UINT64 WORD_T;
#else
typedef UINT32 WORD_T;
#endif
while ((UINTN)Dest & (sizeof(WORD_T) - 1)) {
*Dest++ = *Src++;
Length--;
}
WORD_T *WordDest = (WORD_T *)Dest;
CONST WORD_T *WordSrc = (CONST WORD_T *)Src;
while (Length >= 8 * sizeof(WORD_T)) {
WordDest[0] = WordSrc[0];
WordDest[1] = WordSrc[1];
WordDest[2] = WordSrc[2];
WordDest[3] = WordSrc[3];
WordDest[4] = WordSrc[4];
WordDest[5] = WordSrc[5];
WordDest[6] = WordSrc[6];
WordDest[7] = WordSrc[7];
WordDest += 8;
WordSrc += 8;
Length -= 8 * sizeof(WORD_T);
}
while (Length >= 4 * sizeof(WORD_T)) {
WordDest[0] = WordSrc[0];
WordDest[1] = WordSrc[1];
WordDest[2] = WordSrc[2];
WordDest[3] = WordSrc[3];
WordDest += 4;
WordSrc += 4;
Length -= 4 * sizeof(WORD_T);
}
while (Length >= sizeof(WORD_T)) {
*WordDest++ = *WordSrc++;
Length -= sizeof(WORD_T);
}
Dest = (UINT8 *)WordDest;
Src = (CONST UINT8 *)WordSrc;
while (Length--) {
*Dest++ = *Src++;
}
return Destination;
}
+119
View File
@@ -0,0 +1,119 @@
#include "rng.h"
#include "Library/UefiBootServicesTableLib.h"
#include "Library/UefiLib.h"
#include "ProcessorBind.h"
#include "Uefi/UefiBaseType.h"
#include "time.h"
#include <Library/BaseLib.h>
#include <Library/RngLib.h>
#include <Library/TimerLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Uefi.h>
#include <stdint.h>
void (*fill_random_bytes)(void *dst, UINTN n);
UINT16 shift_LFSR(UINT16 LFSR) {
UINT16 lsb = LFSR & 1;
LFSR >>= 1;
if (lsb) {
LFSR ^= 0xB400;
}
return LFSR;
}
void fill_random_bytes_TRUE(void *dst, UINTN n) {
UINT16 rand;
if (n % 2 != 0) {
GetRandomNumber16(&rand);
*(UINT8 *)dst = (UINT8)rand;
dst++;
n--;
}
while (n != 0) {
GetRandomNumber16(&rand);
*(UINT16 *)dst = rand;
dst += 2;
n -= 2;
}
}
UINT16 LFSR;
void fill_random_bytes_LFSR(void *dst, UINTN n) {
if (n % 2 != 0) {
LFSR = shift_LFSR(LFSR);
*(UINT8 *)dst = (UINT8)LFSR;
dst++;
n--;
}
while (n != 0) {
LFSR = shift_LFSR(LFSR);
*(UINT16 *)dst = LFSR;
dst += 2;
n -= 2;
}
}
void init_rng() {
UINT16 test_var;
if (GetRandomNumber16(&test_var)) {
fill_random_bytes = fill_random_bytes_TRUE;
} else {
gST->ConOut->SetAttribute(gST->ConOut, EFI_YELLOW);
Print(L"[WARNING]");
gST->ConOut->SetAttribute(gST->ConOut, EFI_WHITE);
Print(L" RNG device not available falling back to LFSR!\r\n");
EFI_TIME Time;
EFI_STATUS Status;
UINT32 starting;
Status = gRT->GetTime(&Time, NULL);
if (EFI_ERROR(Status)) {
Print(L"failed to get time\r\n");
microsleep(2000000);
starting = 1;
} else {
starting = Time.Second;
}
Print(L"Press any key to seed the LFSR\r\n");
EFI_INPUT_KEY Key;
UINTN Index;
Status = gBS->WaitForEvent(1, &(gST->ConIn->WaitForKey), &Index);
if (EFI_ERROR(Status)) {
Print(L"failed to wait key\r\n");
Key.ScanCode = 1;
Key.UnicodeChar = 1;
} else {
Status = gST->ConIn->ReadKeyStroke(gST->ConIn, &Key);
if (EFI_ERROR(Status)) {
Print(L"failed to read key\r\n");
Key.ScanCode = 1;
Key.UnicodeChar = 1;
}
}
if (Key.ScanCode == 0) {
Key.ScanCode = 1;
}
Status = gRT->GetTime(&Time, NULL);
if (EFI_ERROR(Status)) {
Print(L"failed to get time\r\n");
Time.Second = 1;
}
UINT8 time_diff = (Time.Second - starting);
if (time_diff == 0) {
time_diff = 1;
}
LFSR = (typeof(LFSR))(((UINTN)Key.ScanCode * (UINTN)Key.UnicodeChar *
(UINTN)(time_diff)) %
UINT16_MAX);
if (LFSR <= 1) {
LFSR = 0xf5d7;
}
fill_random_bytes = fill_random_bytes_LFSR;
}
}
+3
View File
@@ -0,0 +1,3 @@
#pragma once
extern void (*fill_random_bytes)(void *dst, UINTN n);
void init_rng();
+24
View File
@@ -0,0 +1,24 @@
#include "Library/UefiLib.h"
#include <Library/UefiBootServicesTableLib.h>
EFI_STATUS
microsleep(UINTN n) {
EFI_STATUS Status;
EFI_EVENT TimerEvent;
Status =
gBS->CreateEvent(EVT_TIMER, TPL_APPLICATION, NULL, NULL, &TimerEvent);
if (EFI_ERROR(Status)) {
return Status;
}
Status = gBS->SetTimer(TimerEvent, TimerRelative,
EFI_TIMER_PERIOD_MICROSECONDS(n));
if (!EFI_ERROR(Status)) {
gBS->WaitForEvent(1, &TimerEvent, NULL);
}
gBS->CloseEvent(TimerEvent);
return Status;
}
+2
View File
@@ -0,0 +1,2 @@
#pragma once
void microsleep(UINTN n);
+16 -7
View File
@@ -1,19 +1,28 @@
#pragma once
#include "ProcessorBind.h"
#include "Protocol/GraphicsOutput.h"
#include "const.h"
#include <Library/BaseLib.h>
struct firework_instance {
typedef struct {
UINT32 x;
UINT32 y;
} location;
typedef struct {
enum firework_status status; // IF INACTIVE can be overwriten
UINT32 x;
UINT32 y;
UINT16 max_r;
UINT16 r[3];
EFI_GRAPHICS_OUTPUT_BLT_PIXEL color[3];
UINT16 cleanup_r;
};
location rocket;
} firework_instance;
typedef struct {
UINTN Signature;
struct firework_instance Firework;
LIST_ENTRY Link;
} firework_node;
#define FIREWORK_NODE_SIGNATURE SIGNATURE_32('f', 'w', 'r', 'k')
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *blt;
UINTN blt_size;
UINTN height;
UINTN width;
} rocket_blt;
+9 -7
View File
@@ -1,14 +1,16 @@
#!/bin/bash
cp /usr/share/edk2/x64/OVMF_VARS.4m.fd ./my_ovmf_vars.fd
if [ $# -ge 1 ]; then
OVMF_CODE_PATH=$1
else
OVMF_CODE_PATH=/usr/share/edk2/x64/OVMF_CODE.4m.fd
fi
qemu-system-x86_64 \
-machine type=q35,accel=kvm \
-drive if=pflash,format=raw,readonly=on,file=/usr/share/edk2/x64/OVMF_CODE.4m.fd \
-drive if=pflash,format=raw,file=./my_ovmf_vars.fd \
-hda fat:rw:$(dirname build/UEFI_fireworks.efi) \
-drive if=pflash,format=raw,readonly=on,file="$OVMF_CODE_PATH" \
-hda fat:rw:build \
-boot order=c \
-smp 4 \
-s \
-serial mon:stdio
rm ./my_ovmf_vars.fd
-serial mon:stdio