uboot/lib/efi_loader/helloworld.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Hello world EFI application
   4 *
   5 * Copyright 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
   6 *
   7 * This test program is used to test the invocation of an EFI application.
   8 * It writes
   9 *
  10 * * a greeting
  11 * * the firmware's UEFI version
  12 * * the installed configuration tables
  13 * * the boot device's device path and the file path
  14 *
  15 * to the console.
  16 */
  17
  18#include <efi_api.h>
  19
  20static const efi_guid_t loaded_image_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
  21static const efi_guid_t device_path_to_text_protocol_guid =
  22        EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID;
  23static const efi_guid_t device_path_guid = EFI_DEVICE_PATH_PROTOCOL_GUID;
  24static const efi_guid_t fdt_guid = EFI_FDT_GUID;
  25static const efi_guid_t acpi_guid = EFI_ACPI_TABLE_GUID;
  26static const efi_guid_t smbios_guid = SMBIOS_TABLE_GUID;
  27
  28static struct efi_system_table *systable;
  29static struct efi_boot_services *boottime;
  30static struct efi_simple_text_output_protocol *con_out;
  31
  32/**
  33 * print_uefi_revision() - print UEFI revision number
  34 */
  35static void print_uefi_revision(void)
  36{
  37        u16 rev[] = L"0.0.0";
  38
  39        rev[0] = (systable->hdr.revision >> 16) + '0';
  40        rev[4] = systable->hdr.revision & 0xffff;
  41        for (; rev[4] >= 10;) {
  42                rev[4] -= 10;
  43                ++rev[2];
  44        }
  45        /* Third digit is only to be shown if non-zero */
  46        if (rev[4])
  47                rev[4] += '0';
  48        else
  49                rev[3] = 0;
  50
  51        con_out->output_string(con_out, L"Running on UEFI ");
  52        con_out->output_string(con_out, rev);
  53        con_out->output_string(con_out, L"\r\n");
  54}
  55
  56/**
  57 * print_config_tables() - print configuration tables
  58 */
  59static void print_config_tables(void)
  60{
  61        efi_uintn_t i;
  62
  63        /* Find configuration tables */
  64        for (i = 0; i < systable->nr_tables; ++i) {
  65                if (!memcmp(&systable->tables[i].guid, &fdt_guid,
  66                            sizeof(efi_guid_t)))
  67                        con_out->output_string
  68                                        (con_out, L"Have device tree\r\n");
  69                if (!memcmp(&systable->tables[i].guid, &acpi_guid,
  70                            sizeof(efi_guid_t)))
  71                        con_out->output_string
  72                                        (con_out, L"Have ACPI 2.0 table\r\n");
  73                if (!memcmp(&systable->tables[i].guid, &smbios_guid,
  74                            sizeof(efi_guid_t)))
  75                        con_out->output_string
  76                                        (con_out, L"Have SMBIOS table\r\n");
  77        }
  78}
  79
  80/**
  81 * print_load_options() - print load options
  82 *
  83 * @systable:   system table
  84 * @con_out:    simple text output protocol
  85 */
  86void print_load_options(struct efi_loaded_image *loaded_image)
  87{
  88        /* Output the load options */
  89        con_out->output_string(con_out, L"Load options: ");
  90        if (loaded_image->load_options_size && loaded_image->load_options)
  91                con_out->output_string(con_out,
  92                                       (u16 *)loaded_image->load_options);
  93        else
  94                con_out->output_string(con_out, L"<none>");
  95        con_out->output_string(con_out, L"\r\n");
  96}
  97
  98/**
  99 * print_device_path() - print device path
 100 *
 101 * @device_path:        device path to print
 102 * @dp2txt:             device path to text protocol
 103 */
 104efi_status_t print_device_path(struct efi_device_path *device_path,
 105                               struct efi_device_path_to_text_protocol *dp2txt)
 106{
 107        u16 *string;
 108        efi_status_t ret;
 109
 110        if (!device_path) {
 111                con_out->output_string(con_out, L"<none>\r\n");
 112                return EFI_SUCCESS;
 113        }
 114
 115        string = dp2txt->convert_device_path_to_text(device_path, true, false);
 116        if (!string) {
 117                con_out->output_string
 118                        (con_out, L"Cannot convert device path to text\r\n");
 119                return EFI_OUT_OF_RESOURCES;
 120        }
 121        con_out->output_string(con_out, string);
 122        con_out->output_string(con_out, L"\r\n");
 123        ret = boottime->free_pool(string);
 124        if (ret != EFI_SUCCESS) {
 125                con_out->output_string(con_out, L"Cannot free pool memory\r\n");
 126                return ret;
 127        }
 128        return EFI_SUCCESS;
 129}
 130
 131/**
 132 * efi_main() - entry point of the EFI application.
 133 *
 134 * @handle:     handle of the loaded image
 135 * @systab:     system table
 136 * @return:     status code
 137 */
 138efi_status_t EFIAPI efi_main(efi_handle_t handle,
 139                             struct efi_system_table *systab)
 140{
 141        struct efi_loaded_image *loaded_image;
 142        struct efi_device_path_to_text_protocol *device_path_to_text;
 143        struct efi_device_path *device_path;
 144        efi_status_t ret;
 145
 146        systable = systab;
 147        boottime = systable->boottime;
 148        con_out = systable->con_out;
 149
 150        /* UEFI requires CR LF */
 151        con_out->output_string(con_out, L"Hello, world!\r\n");
 152
 153        print_uefi_revision();
 154        print_config_tables();
 155
 156        /* Get the loaded image protocol */
 157        ret = boottime->handle_protocol(handle, &loaded_image_guid,
 158                                        (void **)&loaded_image);
 159        if (ret != EFI_SUCCESS) {
 160                con_out->output_string
 161                        (con_out, L"Cannot open loaded image protocol\r\n");
 162                goto out;
 163        }
 164        print_load_options(loaded_image);
 165
 166        /* Get the device path to text protocol */
 167        ret = boottime->locate_protocol(&device_path_to_text_protocol_guid,
 168                                        NULL, (void **)&device_path_to_text);
 169        if (ret != EFI_SUCCESS) {
 170                con_out->output_string
 171                        (con_out, L"Cannot open device path to text protocol\r\n");
 172                goto out;
 173        }
 174        if (!loaded_image->device_handle) {
 175                con_out->output_string
 176                        (con_out, L"Missing device handle\r\n");
 177                goto out;
 178        }
 179        ret = boottime->handle_protocol(loaded_image->device_handle,
 180                                        &device_path_guid,
 181                                        (void **)&device_path);
 182        if (ret != EFI_SUCCESS) {
 183                con_out->output_string
 184                        (con_out, L"Missing device path for device handle\r\n");
 185                goto out;
 186        }
 187        con_out->output_string(con_out, L"Boot device: ");
 188        ret = print_device_path(device_path, device_path_to_text);
 189        if (ret != EFI_SUCCESS)
 190                goto out;
 191        con_out->output_string(con_out, L"File path: ");
 192        ret = print_device_path(loaded_image->file_path, device_path_to_text);
 193        if (ret != EFI_SUCCESS)
 194                goto out;
 195
 196out:
 197        boottime->exit(handle, ret, 0, NULL);
 198
 199        /* We should never arrive here */
 200        return ret;
 201}
 202