UEFI game

Assumption: All the commands assume that you are located in the NalogaEFI folder!

1. Compiling the code

The main program dodge.c is compiled to an .efi file using the make file. To compile the program simply enter the next command:

make

For the compilation to succeed you must first install GNU-EFI!

sudo apt-get update
sudo apt-get install gnu-efi

For more details on how the program is compiled please check in the makefile and in resources at the bottom of this readme.

2. Running the program

To run the program in quemu, start quemu with:

qemu-system-x86_64 -bios OVMF.fd -hda disk.vmdk

wait for the efi shell to appear and switch to the fs0 drive and start the executable.

fs0:
dodge.efi

3. Explanation

Because the code is quite long i won't go into details, but will just list all the functions and important bits, for more look at the dodge.c file, most of the code is commented on what it is supposed to do.

Here's a complete list of functions:

void printScreen(EFI_GRAPHICS_OUTPUT_PROTOCOL *gop); //Prints main game screen and blocks

void displayPlayer(EFI_GRAPHICS_OUTPUT_PROTOCOL *gop); //Prints player on main game screen

int rand(); //RNG - Random number generator

void addBlock(); //Adds block to a list of blocks with a certain probability

int checkPlayer(EFI_GRAPHICS_OUTPUT_PROTOCOL *gop); //Checks if player has hit any of the other blocks

int checkInput(); //Waits for some time and checks if player has pressed any key

int startGame(EFI_GRAPHICS_OUTPUT_PROTOCOL *gop); //The main game loop and resets data form previous game

void printMenu(int indx, EFI_GRAPHICS_OUTPUT_PROTOCOL *gop); //Displays main menu on screen

void help(); //Displays help on screen

int displayMenu(EFI_GRAPHICS_OUTPUT_PROTOCOL *gop); //Main menu loop, reads user input

void gameOver(EFI_GRAPHICS_OUTPUT_PROTOCOL *gop); //Displays game over screen

EFI_STATUS efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable); //Main program entry point

As you may have noticed there is no conventional main function, thats because the entry point for an efi program is a function named efi_main which returns a status of type EFI_STATUS.

I won't be copying and showing all of the code here, but just a few lines. So let's start.
The first thing the program does is initialize the main efi library and sets some handy variables. Then we check for and locate the Graphics Output Protocol which we will use for displaying graphics. If there is an error while doing this the program will terminate.
The program then reads the screen resolution and sets the seed for the RNG and enters the main loop.

In the main loop we first display the main menu and depending on the selection start the game, diplay help or exit the program. The menu display is pretty simple so i will use it to explain how we can write to the screen in EFI. With the first line we set the text and background color using the EFI constants that can be found in the specification on UEFI.org. The next line clears the screen and sets the new background for the whole screen. And the last function Print is used to write text to the screen. Please do note that in EFI the strings are 16bit which can be marked with an upper case L before the constant. The Print function was setup with a call to the InitializeLib function and it internally calls the OutputString() function which is part of the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL

1. uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_BACKGROUND_BLACK | EFI_WHITE);
2. uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
3. Print(L"Text");

As most of the code is simple C i won't go explaining every line, but i will explain just one more thing: How to draw on the screen. Drawing on the screen is done with writing directly to the video buffer, which is enabled by the GOP. To make this a bit simpler i'm using the Blt() function of the GOP protocol. Here's the Blt() function prototype from the UEFI specification:

typedef
EFI_STATUS
(EFIAPI *EFI_GRAPHICS_OUTPUT_PROTOCOL_BLT) (
  IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
  IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
  IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
  IN UINTN SourceX,
  IN UINTN SourceY,
  IN UINTN DestinationX,
  IN UINTN DestinationY,
  IN UINTN Width,
  IN UINTN Height,
  IN UINTN Delta OPTIONAL
 );

The function is pretty simple, it copies rectangle blocks of pixels from/to the BltBuffer to/from the video frame in memory. Most of the parameters are self-explanatory, but if you want to know more you can check in the specification. The main parameter of interest is the BltBuffer. It is an array of EFI_GRAPHICS_OUTPUT_BLT_PIXEL which represent the rectangle we wish to copy to or from. Each pixel is represented by 4 bytes. One is reserved and the other three are an RGB value. Because the order of RGB values is dependent on the current GOP mode i recommend using this structure for working with the video frame buffer as it makes it allot simpler. Other than that you can select different modes including EfiBltVideoFill, which fills the rectangle with a single pixel and EfiBltVideoToVideo.

This is all i have to say for now, the one thing i can recommend for learing to programm in UEFI is to read the official specification, it is the best resource i have found in my limited research.

Have fun!

4. Resources

https://github.com/vathpela/gnu-efi
http://www.uefi.org/sites/default/files/resources/UEFI%20Spec%202_6.pdf
http://wiki.phoenix.com/wiki/index.php/
https://kurtqiao.github.io/uefi/2015/01/06/wait-for-event.html
http://www.uefi.org/
http://www.rodsbooks.com/efi-programming/hello.html