Compare commits
12 Commits
83ef67ad28
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 92e474853b | |||
| 24e7c443a1 | |||
| 37f63d51b9 | |||
| 09ff9f8f19 | |||
| 83df1a6048 | |||
| 36a7c9066a | |||
| 9b768a4e9e | |||
| 868d27cecb | |||
| c72a80832b | |||
| 54a54de423 | |||
| 8af36091ba | |||
| fa35f79e34 |
@@ -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
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
@@ -1,12 +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/EFI/BOOT/
|
||||
cp edk2/Build/UEFI_fireworks/DEBUG_GCC5/X64/UEFI_fireworks.efi build/
|
||||
cp edk2/Build/UEFI_fireworks/DEBUG_GCC5/X64/UEFI_fireworks.efi build/EFI/BOOT/BOOTX64.EFI
|
||||
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
@@ -6,13 +6,16 @@
|
||||
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
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#include "ProcessorBind.h"
|
||||
#include "Protocol/SimpleTextIn.h"
|
||||
#include "Uefi/UefiBaseType.h"
|
||||
#include "const.h"
|
||||
#include "drawing.h"
|
||||
#include "global.h"
|
||||
@@ -20,7 +22,7 @@
|
||||
#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;
|
||||
@@ -50,8 +52,8 @@ EFI_STATUS EFIAPI UefiMain(IN EFI_HANDLE imgHandle,
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
framebuffer =
|
||||
(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)GraphicsOutput->Mode->FrameBufferBase;
|
||||
framebuffer = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)(UINTN)
|
||||
GraphicsOutput->Mode->FrameBufferBase;
|
||||
|
||||
init_rng();
|
||||
init_rocket_blt();
|
||||
@@ -71,16 +73,10 @@ EFI_STATUS EFIAPI UefiMain(IN EFI_HANDLE imgHandle,
|
||||
|
||||
SERIAL_PRINT("DOES it work?\n");
|
||||
Print(L"If you see this message for long time, timer does not work\n");
|
||||
milisleep(1);
|
||||
microsleep(1);
|
||||
clear_screen();
|
||||
|
||||
/*rocket_instance rocket = {
|
||||
.x = GraphicsOutput->Mode->Info->HorizontalResolution / 2,
|
||||
.y = GraphicsOutput->Mode->Info->VerticalResolution - 50};
|
||||
while (step_rocket(&rocket, 100)) {
|
||||
milisleep(10);
|
||||
}*/
|
||||
|
||||
UINTN sleep_time = DEFAULT_SLEEP_TIME;
|
||||
while (TRUE) {
|
||||
UINT8 random;
|
||||
fill_random_bytes(&random, sizeof(random));
|
||||
@@ -124,8 +120,71 @@ EFI_STATUS EFIAPI UefiMain(IN EFI_HANDLE imgHandle,
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
|
||||
milisleep(10);
|
||||
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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -68,7 +68,7 @@ void init_rng() {
|
||||
Status = gRT->GetTime(&Time, NULL);
|
||||
if (EFI_ERROR(Status)) {
|
||||
Print(L"failed to get time\r\n");
|
||||
milisleep(2000);
|
||||
microsleep(2000000);
|
||||
starting = 1;
|
||||
} else {
|
||||
starting = Time.Second;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "Library/UefiLib.h"
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
EFI_STATUS
|
||||
milisleep(UINTN Milliseconds) {
|
||||
microsleep(UINTN n) {
|
||||
EFI_STATUS Status;
|
||||
EFI_EVENT TimerEvent;
|
||||
|
||||
@@ -13,7 +13,7 @@ milisleep(UINTN Milliseconds) {
|
||||
}
|
||||
|
||||
Status = gBS->SetTimer(TimerEvent, TimerRelative,
|
||||
EFI_TIMER_PERIOD_MILLISECONDS(Milliseconds));
|
||||
EFI_TIMER_PERIOD_MICROSECONDS(n));
|
||||
|
||||
if (!EFI_ERROR(Status)) {
|
||||
gBS->WaitForEvent(1, &TimerEvent, NULL);
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
#pragma once
|
||||
void milisleep(UINTN n);
|
||||
void microsleep(UINTN n);
|
||||
@@ -1,16 +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 \
|
||||
-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
|
||||
|
||||
Reference in New Issue
Block a user