Search code examples
uefignu-efi

Writing my first EFI application with gnu-efi


I got an Alexa device and I’m using an esp8266 to get request from the echo dot. I can wake on lan my Pc but it’s not enough. I have windows and Linux on my Pc so I thought “I need some code to run before boot so I can communicate with my esp8266 to know witch os should be booted”. So I started searching everywhere to find a solution and I think I’m really close to it. What I did was to put the efi-shell as main boot, let it execute the startup.nsh. In this startup.nsh I want to start my efi application who can communicate with the esp8266. Is this the right way to do this thing? Should I do something else? The problem is that I can’t code this app. I can’t understand how to use protocols and which protocols are the solutions. The application should send a simple character to the esp to let it know that the computer is ready to get boot instruction. The esp should reply “1” for windows or “2” for Linux. Can someone give me some advices for this task? Is it the right way or am I doing a lot of useless stuff? Maybe exists a better way


Solution

  • Here is a sample how to load and start an UEFI application with EDK2, porting it to gnu-efi should be an easy task, wrap all gBS-> calls with the uefi_call_wrapper.

    Based on the response from the esp8266 you have to start the Linux or Windows loader application.

    I posted an UDP sample as answer to your first question.

    #include <Uefi.h>
    #include <Library\UefiLib.h>
    #include <Protocol\LoadedImage.h>
    #include <Protocol\DevicePath.h>
    #include <Library\DevicePathLib.h>
    
    #ifndef LOG
    #define LOG(fmt, ...) AsciiPrint(fmt, __VA_ARGS__)
    #endif
    
    #ifndef TRACE
    #define TRACE(status)   LOG("Status: '%r', Function: '%a', File: '%a', Line: '%d'\r\n", status, __FUNCTION__, __FILE__, __LINE__)
    #endif
    
    extern EFI_BOOT_SERVICES    *gBS;
    
    /*
    Configuration
    */
    static CHAR16 gFilePath[] = L"\\Tools\\Udp4Sample.efi";
    
    EFI_STATUS
    EFIAPI
    UefiMain(
        IN EFI_HANDLE        ImageHandle,
        IN EFI_SYSTEM_TABLE  *SystemTable)
    {
        EFI_STATUS                  Status;
    
        EFI_LOADED_IMAGE            *LoadedImageProtocol = NULL;
    
        EFI_DEVICE_PATH_PROTOCOL    *AppDevicePath = NULL;
    
        EFI_HANDLE                  AppHandle = NULL;
        
        /*
        Step 1: Handle the LoadedImageProtocol of the current application
        */
    
        Status = gBS->HandleProtocol(
            ImageHandle,
            &gEfiLoadedImageProtocolGuid,
            &LoadedImageProtocol);
    
        if (EFI_ERROR(Status)) {
            TRACE(Status);
            // Error handling
            return Status;
        }
    
        /*
        Step 2: Create a device path that points to the application, the application must be located on the same device (partition) as this one
        */
    
        AppDevicePath = FileDevicePath(LoadedImageProtocol->DeviceHandle, gFilePath);
    
        if (!AppDevicePath) {
            TRACE(EFI_INVALID_PARAMETER);
            // Error handling
            return EFI_INVALID_PARAMETER;
        }
        
        /*
        Step 3: Load the application
        */
    
        Status = gBS->LoadImage(
            FALSE,
            ImageHandle,
            AppDevicePath,
            NULL,
            0,
            &AppHandle);
        
        gBS->FreePool(AppDevicePath);
    
        if (EFI_ERROR(Status)) {
            TRACE(Status);
            // Error handling
            return Status;
        }
    
        /*
        Step 4: Start the application
        */
    
        Status = gBS->StartImage(
            AppHandle,
            NULL,
            NULL);
    
        if (EFI_ERROR(Status)) {
            TRACE(Status);
            // Error handling
            return Status;
        }
    
        return EFI_SUCCESS;
    }