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 an unsigned 32bit value as decimal number to an u16 string 34 * 35 * @value: value to be printed 36 * @buf: pointer to buffer address 37 * on return position of terminating zero word 38 */ 39static void uint2dec(u32 value, u16 **buf) 40{ 41 u16 *pos = *buf; 42 int i; 43 u16 c; 44 u64 f; 45 46 /* 47 * Increment by .5 and multiply with 48 * (2 << 60) / 1,000,000,000 = 0x44B82FA0.9B5A52CC 49 * to move the first digit to bit 60-63. 50 */ 51 f = 0x225C17D0; 52 f += (0x9B5A52DULL * value) >> 28; 53 f += 0x44B82FA0ULL * value; 54 55 for (i = 0; i < 10; ++i) { 56 /* Write current digit */ 57 c = f >> 60; 58 if (c || pos != *buf) 59 *pos++ = c + '0'; 60 /* Eliminate current digit */ 61 f &= 0xfffffffffffffff; 62 /* Get next digit */ 63 f *= 0xaULL; 64 } 65 if (pos == *buf) 66 *pos++ = '0'; 67 *pos = 0; 68 *buf = pos; 69} 70 71/** 72 * print_uefi_revision() - print UEFI revision number 73 */ 74static void print_uefi_revision(void) 75{ 76 u16 rev[13] = {0}; 77 u16 *buf = rev; 78 u16 digit; 79 80 uint2dec(systable->hdr.revision >> 16, &buf); 81 *buf++ = '.'; 82 uint2dec(systable->hdr.revision & 0xffff, &buf); 83 84 /* Minor revision is only to be shown if non-zero */ 85 digit = *--buf; 86 if (digit == '0') { 87 *buf = 0; 88 } else { 89 *buf++ = '.'; 90 *buf = digit; 91 } 92 93 con_out->output_string(con_out, u"Running on UEFI "); 94 con_out->output_string(con_out, rev); 95 con_out->output_string(con_out, u"\r\n"); 96} 97 98/** 99 * print_config_tables() - print configuration tables 100 */ 101static void print_config_tables(void) 102{ 103 efi_uintn_t i; 104 105 /* Find configuration tables */ 106 for (i = 0; i < systable->nr_tables; ++i) { 107 if (!memcmp(&systable->tables[i].guid, &fdt_guid, 108 sizeof(efi_guid_t))) 109 con_out->output_string 110 (con_out, u"Have device tree\r\n"); 111 if (!memcmp(&systable->tables[i].guid, &acpi_guid, 112 sizeof(efi_guid_t))) 113 con_out->output_string 114 (con_out, u"Have ACPI 2.0 table\r\n"); 115 if (!memcmp(&systable->tables[i].guid, &smbios_guid, 116 sizeof(efi_guid_t))) 117 con_out->output_string 118 (con_out, u"Have SMBIOS table\r\n"); 119 } 120} 121 122/** 123 * print_load_options() - print load options 124 * 125 * @systable: system table 126 * @con_out: simple text output protocol 127 */ 128static void print_load_options(struct efi_loaded_image *loaded_image) 129{ 130 /* Output the load options */ 131 con_out->output_string(con_out, u"Load options: "); 132 if (loaded_image->load_options_size && loaded_image->load_options) 133 con_out->output_string(con_out, 134 (u16 *)loaded_image->load_options); 135 else 136 con_out->output_string(con_out, u"<none>"); 137 con_out->output_string(con_out, u"\r\n"); 138} 139 140/** 141 * print_device_path() - print device path 142 * 143 * @device_path: device path to print 144 * @dp2txt: device path to text protocol 145 */ 146static 147efi_status_t print_device_path(struct efi_device_path *device_path, 148 struct efi_device_path_to_text_protocol *dp2txt) 149{ 150 u16 *string; 151 efi_status_t ret; 152 153 if (!device_path) { 154 con_out->output_string(con_out, u"<none>\r\n"); 155 return EFI_SUCCESS; 156 } 157 158 string = dp2txt->convert_device_path_to_text(device_path, true, false); 159 if (!string) { 160 con_out->output_string 161 (con_out, u"Cannot convert device path to text\r\n"); 162 return EFI_OUT_OF_RESOURCES; 163 } 164 con_out->output_string(con_out, string); 165 con_out->output_string(con_out, u"\r\n"); 166 ret = boottime->free_pool(string); 167 if (ret != EFI_SUCCESS) { 168 con_out->output_string(con_out, u"Cannot free pool memory\r\n"); 169 return ret; 170 } 171 return EFI_SUCCESS; 172} 173 174/** 175 * efi_main() - entry point of the EFI application. 176 * 177 * @handle: handle of the loaded image 178 * @systab: system table 179 * Return: status code 180 */ 181efi_status_t EFIAPI efi_main(efi_handle_t handle, 182 struct efi_system_table *systab) 183{ 184 struct efi_loaded_image *loaded_image; 185 struct efi_device_path_to_text_protocol *device_path_to_text; 186 struct efi_device_path *device_path; 187 efi_status_t ret; 188 189 systable = systab; 190 boottime = systable->boottime; 191 con_out = systable->con_out; 192 193 /* UEFI requires CR LF */ 194 con_out->output_string(con_out, u"Hello, world!\r\n"); 195 196 print_uefi_revision(); 197 print_config_tables(); 198 199 /* Get the loaded image protocol */ 200 ret = boottime->open_protocol(handle, &loaded_image_guid, 201 (void **)&loaded_image, NULL, NULL, 202 EFI_OPEN_PROTOCOL_GET_PROTOCOL); 203 204 if (ret != EFI_SUCCESS) { 205 con_out->output_string 206 (con_out, u"Cannot open loaded image protocol\r\n"); 207 goto out; 208 } 209 print_load_options(loaded_image); 210 211 /* Get the device path to text protocol */ 212 ret = boottime->locate_protocol(&device_path_to_text_protocol_guid, 213 NULL, (void **)&device_path_to_text); 214 if (ret != EFI_SUCCESS) { 215 con_out->output_string 216 (con_out, u"Cannot open device path to text protocol\r\n"); 217 goto out; 218 } 219 con_out->output_string(con_out, u"File path: "); 220 ret = print_device_path(loaded_image->file_path, device_path_to_text); 221 if (ret != EFI_SUCCESS) 222 goto out; 223 if (!loaded_image->device_handle) { 224 con_out->output_string 225 (con_out, u"Missing device handle\r\n"); 226 goto out; 227 } 228 ret = boottime->open_protocol(loaded_image->device_handle, 229 &device_path_guid, 230 (void **)&device_path, NULL, NULL, 231 EFI_OPEN_PROTOCOL_GET_PROTOCOL); 232 if (ret != EFI_SUCCESS) { 233 con_out->output_string 234 (con_out, u"Missing device path for device handle\r\n"); 235 goto out; 236 } 237 con_out->output_string(con_out, u"Boot device: "); 238 ret = print_device_path(device_path, device_path_to_text); 239 if (ret != EFI_SUCCESS) 240 goto out; 241 242out: 243 boottime->exit(handle, ret, 0, NULL); 244 245 /* We should never arrive here */ 246 return ret; 247} 248