^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Helper functions used by the EFI stub on multiple
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * architectures. This should be #included by the EFI stub
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * implementation files.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright 2011 Intel Corporation; author Matt Fleming
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <stdarg.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/ctype.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/efi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/printk.h> /* For CONSOLE_LOGLEVEL_* */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <asm/efi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <asm/setup.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include "efistub.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) bool efi_nochunk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) bool efi_nokaslr = !IS_ENABLED(CONFIG_RANDOMIZE_BASE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) bool efi_noinitrd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) int efi_loglevel = CONSOLE_LOGLEVEL_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) bool efi_novamap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) static bool efi_nosoftreserve;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) static bool efi_disable_pci_dma = IS_ENABLED(CONFIG_EFI_DISABLE_PCI_DMA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) bool __pure __efi_soft_reserve_enabled(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) return !efi_nosoftreserve;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * efi_char16_puts() - Write a UCS-2 encoded string to the console
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * @str: UCS-2 encoded string
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) void efi_char16_puts(efi_char16_t *str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) efi_call_proto(efi_table_attr(efi_system_table, con_out),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) output_string, str);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) u32 utf8_to_utf32(const u8 **s8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) u32 c32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) u8 c0, cx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) size_t clen, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) c0 = cx = *(*s8)++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * The position of the most-significant 0 bit gives us the length of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * a multi-octet encoding.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) for (clen = 0; cx & 0x80; ++clen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) cx <<= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * If the 0 bit is in position 8, this is a valid single-octet
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * encoding. If the 0 bit is in position 7 or positions 1-3, the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * encoding is invalid.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) * In either case, we just return the first octet.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) if (clen < 2 || clen > 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) return c0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) /* Get the bits from the first octet. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) c32 = cx >> clen--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) for (i = 0; i < clen; ++i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) /* Trailing octets must have 10 in most significant bits. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) cx = (*s8)[i] ^ 0x80;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) if (cx & 0xc0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) return c0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) c32 = (c32 << 6) | cx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) * Check for validity:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * - The character must be in the Unicode range.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) * - It must not be a surrogate.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) * - It must be encoded using the correct number of octets.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) if (c32 > 0x10ffff ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) (c32 & 0xf800) == 0xd800 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) clen != (c32 >= 0x80) + (c32 >= 0x800) + (c32 >= 0x10000))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) return c0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) *s8 += clen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) return c32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) * efi_puts() - Write a UTF-8 encoded string to the console
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) * @str: UTF-8 encoded string
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) void efi_puts(const char *str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) efi_char16_t buf[128];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) size_t pos = 0, lim = ARRAY_SIZE(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) const u8 *s8 = (const u8 *)str;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) u32 c32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) while (*s8) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) if (*s8 == '\n')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) buf[pos++] = L'\r';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) c32 = utf8_to_utf32(&s8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) if (c32 < 0x10000) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) /* Characters in plane 0 use a single word. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) buf[pos++] = c32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) * Characters in other planes encode into a surrogate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) * pair.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) buf[pos++] = (0xd800 - (0x10000 >> 10)) + (c32 >> 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) buf[pos++] = 0xdc00 + (c32 & 0x3ff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) if (*s8 == '\0' || pos >= lim - 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) buf[pos] = L'\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) efi_char16_puts(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) pos = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) * efi_printk() - Print a kernel message
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) * @fmt: format string
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) * The first letter of the format string is used to determine the logging level
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) * of the message. If the level is less then the current EFI logging level, the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) * message is suppressed. The message will be truncated to 255 bytes.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * Return: number of printed characters
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) int efi_printk(const char *fmt, ...)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) char printf_buf[256];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) va_list args;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) int printed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) int loglevel = printk_get_level(fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) switch (loglevel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) case '0' ... '9':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) loglevel -= '0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) * Use loglevel -1 for cases where we just want to print to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) * the screen.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) loglevel = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) if (loglevel >= efi_loglevel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) if (loglevel >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) efi_puts("EFI stub: ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) fmt = printk_skip_level(fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) va_start(args, fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) printed = vsnprintf(printf_buf, sizeof(printf_buf), fmt, args);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) va_end(args);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) efi_puts(printf_buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) if (printed >= sizeof(printf_buf)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) efi_puts("[Message truncated]\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) return printed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) * efi_parse_options() - Parse EFI command line options
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) * @cmdline: kernel command line
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) * Parse the ASCII string @cmdline for EFI options, denoted by the efi=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) * option, e.g. efi=nochunk.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) * It should be noted that efi= is parsed in two very different
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) * environments, first in the early boot environment of the EFI boot
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) * stub, and subsequently during the kernel boot.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) * Return: status code
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) efi_status_t efi_parse_options(char const *cmdline)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) size_t len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) efi_status_t status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) char *str, *buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) if (!cmdline)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) return EFI_SUCCESS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) len = strnlen(cmdline, COMMAND_LINE_SIZE - 1) + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, len, (void **)&buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) if (status != EFI_SUCCESS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) return status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) memcpy(buf, cmdline, len - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) buf[len - 1] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) str = skip_spaces(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) while (*str) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) char *param, *val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) str = next_arg(str, ¶m, &val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) if (!val && !strcmp(param, "--"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) if (!strcmp(param, "nokaslr")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) efi_nokaslr = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) } else if (!strcmp(param, "quiet")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) efi_loglevel = CONSOLE_LOGLEVEL_QUIET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) } else if (!strcmp(param, "noinitrd")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) efi_noinitrd = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) } else if (!strcmp(param, "efi") && val) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) efi_nochunk = parse_option_str(val, "nochunk");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) efi_novamap = parse_option_str(val, "novamap");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) efi_nosoftreserve = IS_ENABLED(CONFIG_EFI_SOFT_RESERVE) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) parse_option_str(val, "nosoftreserve");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) if (parse_option_str(val, "disable_early_pci_dma"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) efi_disable_pci_dma = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) if (parse_option_str(val, "no_disable_early_pci_dma"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) efi_disable_pci_dma = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) if (parse_option_str(val, "debug"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) efi_loglevel = CONSOLE_LOGLEVEL_DEBUG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) } else if (!strcmp(param, "video") &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) val && strstarts(val, "efifb:")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) efi_parse_option_graphics(val + strlen("efifb:"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) efi_bs_call(free_pool, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) return EFI_SUCCESS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) * The EFI_LOAD_OPTION descriptor has the following layout:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) * u32 Attributes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) * u16 FilePathListLength;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) * u16 Description[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) * efi_device_path_protocol_t FilePathList[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) * u8 OptionalData[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) * This function validates and unpacks the variable-size data fields.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) bool efi_load_option_unpack(efi_load_option_unpacked_t *dest,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) const efi_load_option_t *src, size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) const void *pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) u16 c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) efi_device_path_protocol_t header;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) const efi_char16_t *description;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) const efi_device_path_protocol_t *file_path_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) if (size < offsetof(efi_load_option_t, variable_data))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) pos = src->variable_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) size -= offsetof(efi_load_option_t, variable_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) if ((src->attributes & ~EFI_LOAD_OPTION_MASK) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) /* Scan description. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) description = pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) if (size < sizeof(c))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) c = *(const u16 *)pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) pos += sizeof(c);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) size -= sizeof(c);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) } while (c != L'\0');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) /* Scan file_path_list. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) file_path_list = pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) if (size < sizeof(header))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) header = *(const efi_device_path_protocol_t *)pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) if (header.length < sizeof(header))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) if (size < header.length)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) pos += header.length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) size -= header.length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) } while ((header.type != EFI_DEV_END_PATH && header.type != EFI_DEV_END_PATH2) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) (header.sub_type != EFI_DEV_END_ENTIRE));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) if (pos != (const void *)file_path_list + src->file_path_list_length)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) dest->attributes = src->attributes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) dest->file_path_list_length = src->file_path_list_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) dest->description = description;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) dest->file_path_list = file_path_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) dest->optional_data_size = size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) dest->optional_data = size ? pos : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) * At least some versions of Dell firmware pass the entire contents of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) * Boot#### variable, i.e. the EFI_LOAD_OPTION descriptor, rather than just the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) * OptionalData field.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) * Detect this case and extract OptionalData.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) void efi_apply_loadoptions_quirk(const void **load_options, int *load_options_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) const efi_load_option_t *load_option = *load_options;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) efi_load_option_unpacked_t load_option_unpacked;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) if (!IS_ENABLED(CONFIG_X86))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) if (!load_option)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) if (*load_options_size < sizeof(*load_option))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) if ((load_option->attributes & ~EFI_LOAD_OPTION_BOOT_MASK) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) if (!efi_load_option_unpack(&load_option_unpacked, load_option, *load_options_size))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) efi_warn_once(FW_BUG "LoadOptions is an EFI_LOAD_OPTION descriptor\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) efi_warn_once(FW_BUG "Using OptionalData as a workaround\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) *load_options = load_option_unpacked.optional_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) *load_options_size = load_option_unpacked.optional_data_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) * Convert the unicode UEFI command line to ASCII to pass to kernel.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) * Size of memory allocated return in *cmd_line_len.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) * Returns NULL on error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) char *efi_convert_cmdline(efi_loaded_image_t *image, int *cmd_line_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) const u16 *s2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) unsigned long cmdline_addr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) int options_chars = efi_table_attr(image, load_options_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) const u16 *options = efi_table_attr(image, load_options);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) int options_bytes = 0, safe_options_bytes = 0; /* UTF-8 bytes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) bool in_quote = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) efi_status_t status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) efi_apply_loadoptions_quirk((const void **)&options, &options_chars);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) options_chars /= sizeof(*options);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) if (options) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) s2 = options;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) while (options_bytes < COMMAND_LINE_SIZE && options_chars--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) u16 c = *s2++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) if (c < 0x80) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) if (c == L'\0' || c == L'\n')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) if (c == L'"')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) in_quote = !in_quote;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) else if (!in_quote && isspace((char)c))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) safe_options_bytes = options_bytes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) options_bytes++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) * Get the number of UTF-8 bytes corresponding to a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) * UTF-16 character.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) * The first part handles everything in the BMP.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) options_bytes += 2 + (c >= 0x800);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) * Add one more byte for valid surrogate pairs. Invalid
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) * surrogates will be replaced with 0xfffd and take up
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) * only 3 bytes.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) if ((c & 0xfc00) == 0xd800) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) * If the very last word is a high surrogate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) * we must ignore it since we can't access the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) * low surrogate.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) if (!options_chars) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) options_bytes -= 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) } else if ((*s2 & 0xfc00) == 0xdc00) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) options_bytes++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) options_chars--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) s2++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) if (options_bytes >= COMMAND_LINE_SIZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) options_bytes = safe_options_bytes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) efi_err("Command line is too long: truncated to %d bytes\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) options_bytes);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) options_bytes++; /* NUL termination */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, options_bytes,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) (void **)&cmdline_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) if (status != EFI_SUCCESS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) snprintf((char *)cmdline_addr, options_bytes, "%.*ls",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) options_bytes - 1, options);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) *cmd_line_len = options_bytes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) return (char *)cmdline_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) * efi_exit_boot_services() - Exit boot services
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) * @handle: handle of the exiting image
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) * @map: pointer to receive the memory map
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) * @priv: argument to be passed to @priv_func
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) * @priv_func: function to process the memory map before exiting boot services
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) * Handle calling ExitBootServices according to the requirements set out by the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) * spec. Obtains the current memory map, and returns that info after calling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) * ExitBootServices. The client must specify a function to perform any
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) * processing of the memory map data prior to ExitBootServices. A client
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) * specific structure may be passed to the function via priv. The client
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) * function may be called multiple times.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) * Return: status code
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) efi_status_t efi_exit_boot_services(void *handle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) struct efi_boot_memmap *map,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) void *priv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) efi_exit_boot_map_processing priv_func)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) efi_status_t status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) status = efi_get_memory_map(map);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) if (status != EFI_SUCCESS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) status = priv_func(map, priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) if (status != EFI_SUCCESS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) goto free_map;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) if (efi_disable_pci_dma)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) efi_pci_disable_bridge_busmaster();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) status = efi_bs_call(exit_boot_services, handle, *map->key_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) if (status == EFI_INVALID_PARAMETER) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) * The memory map changed between efi_get_memory_map() and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) * exit_boot_services(). Per the UEFI Spec v2.6, Section 6.4:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) * EFI_BOOT_SERVICES.ExitBootServices we need to get the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) * updated map, and try again. The spec implies one retry
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) * should be sufficent, which is confirmed against the EDK2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) * implementation. Per the spec, we can only invoke
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) * get_memory_map() and exit_boot_services() - we cannot alloc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) * so efi_get_memory_map() cannot be used, and we must reuse
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) * the buffer. For all practical purposes, the headroom in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) * buffer should account for any changes in the map so the call
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) * to get_memory_map() is expected to succeed here.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) *map->map_size = *map->buff_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) status = efi_bs_call(get_memory_map,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) map->map_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) *map->map,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) map->key_ptr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) map->desc_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) map->desc_ver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) /* exit_boot_services() was called, thus cannot free */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) if (status != EFI_SUCCESS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) status = priv_func(map, priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) /* exit_boot_services() was called, thus cannot free */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) if (status != EFI_SUCCESS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) status = efi_bs_call(exit_boot_services, handle, *map->key_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) /* exit_boot_services() was called, thus cannot free */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) if (status != EFI_SUCCESS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) return EFI_SUCCESS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) free_map:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) efi_bs_call(free_pool, *map->map);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) return status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) * get_efi_config_table() - retrieve UEFI configuration table
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) * @guid: GUID of the configuration table to be retrieved
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) * Return: pointer to the configuration table or NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) void *get_efi_config_table(efi_guid_t guid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) unsigned long tables = efi_table_attr(efi_system_table, tables);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) int nr_tables = efi_table_attr(efi_system_table, nr_tables);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) for (i = 0; i < nr_tables; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) efi_config_table_t *t = (void *)tables;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) if (efi_guidcmp(t->guid, guid) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) return efi_table_attr(t, table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) tables += efi_is_native() ? sizeof(efi_config_table_t)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) : sizeof(efi_config_table_32_t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) * The LINUX_EFI_INITRD_MEDIA_GUID vendor media device path below provides a way
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) * for the firmware or bootloader to expose the initrd data directly to the stub
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) * via the trivial LoadFile2 protocol, which is defined in the UEFI spec, and is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) * very easy to implement. It is a simple Linux initrd specific conduit between
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) * kernel and firmware, allowing us to put the EFI stub (being part of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) * kernel) in charge of where and when to load the initrd, while leaving it up
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) * to the firmware to decide whether it needs to expose its filesystem hierarchy
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) * via EFI protocols.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) static const struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) struct efi_vendor_dev_path vendor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) struct efi_generic_dev_path end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) } __packed initrd_dev_path = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) EFI_DEV_MEDIA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) EFI_DEV_MEDIA_VENDOR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) sizeof(struct efi_vendor_dev_path),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) LINUX_EFI_INITRD_MEDIA_GUID
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) EFI_DEV_END_PATH,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) EFI_DEV_END_ENTIRE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) sizeof(struct efi_generic_dev_path)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) * efi_load_initrd_dev_path() - load the initrd from the Linux initrd device path
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) * @load_addr: pointer to store the address where the initrd was loaded
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) * @load_size: pointer to store the size of the loaded initrd
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) * @max: upper limit for the initrd memory allocation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) * Return:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) * * %EFI_SUCCESS if the initrd was loaded successfully, in which
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) * case @load_addr and @load_size are assigned accordingly
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) * * %EFI_NOT_FOUND if no LoadFile2 protocol exists on the initrd device path
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) * * %EFI_INVALID_PARAMETER if load_addr == NULL or load_size == NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) * * %EFI_OUT_OF_RESOURCES if memory allocation failed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) * * %EFI_LOAD_ERROR in all other cases
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) efi_status_t efi_load_initrd_dev_path(unsigned long *load_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) unsigned long *load_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) unsigned long max)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) efi_guid_t lf2_proto_guid = EFI_LOAD_FILE2_PROTOCOL_GUID;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) efi_device_path_protocol_t *dp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) efi_load_file2_protocol_t *lf2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) unsigned long initrd_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) unsigned long initrd_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) efi_handle_t handle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) efi_status_t status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) dp = (efi_device_path_protocol_t *)&initrd_dev_path;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) status = efi_bs_call(locate_device_path, &lf2_proto_guid, &dp, &handle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) if (status != EFI_SUCCESS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) return status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) status = efi_bs_call(handle_protocol, handle, &lf2_proto_guid,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) (void **)&lf2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) if (status != EFI_SUCCESS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) return status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) status = efi_call_proto(lf2, load_file, dp, false, &initrd_size, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) if (status != EFI_BUFFER_TOO_SMALL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) return EFI_LOAD_ERROR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) status = efi_allocate_pages(initrd_size, &initrd_addr, max);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) if (status != EFI_SUCCESS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) return status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) status = efi_call_proto(lf2, load_file, dp, false, &initrd_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) (void *)initrd_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) if (status != EFI_SUCCESS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) efi_free(initrd_size, initrd_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) return EFI_LOAD_ERROR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) *load_addr = initrd_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) *load_size = initrd_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) return EFI_SUCCESS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) efi_status_t efi_load_initrd_cmdline(efi_loaded_image_t *image,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) unsigned long *load_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) unsigned long *load_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) unsigned long soft_limit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) unsigned long hard_limit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) if (!IS_ENABLED(CONFIG_EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) (IS_ENABLED(CONFIG_X86) && (!efi_is_native() || image == NULL))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) *load_addr = *load_size = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) return EFI_SUCCESS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) return handle_cmdline_files(image, L"initrd=", sizeof(L"initrd=") - 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) soft_limit, hard_limit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) load_addr, load_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) * efi_load_initrd() - Load initial RAM disk
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) * @image: EFI loaded image protocol
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) * @load_addr: pointer to loaded initrd
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) * @load_size: size of loaded initrd
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) * @soft_limit: preferred size of allocated memory for loading the initrd
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) * @hard_limit: minimum size of allocated memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) * Return: status code
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) efi_status_t efi_load_initrd(efi_loaded_image_t *image,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) unsigned long *load_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) unsigned long *load_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) unsigned long soft_limit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) unsigned long hard_limit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) efi_status_t status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) if (!load_addr || !load_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) return EFI_INVALID_PARAMETER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) status = efi_load_initrd_dev_path(load_addr, load_size, hard_limit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) if (status == EFI_SUCCESS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) efi_info("Loaded initrd from LINUX_EFI_INITRD_MEDIA_GUID device path\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) } else if (status == EFI_NOT_FOUND) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) status = efi_load_initrd_cmdline(image, load_addr, load_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) soft_limit, hard_limit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) if (status == EFI_SUCCESS && *load_size > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) efi_info("Loaded initrd from command line option\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) return status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) * efi_wait_for_key() - Wait for key stroke
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) * @usec: number of microseconds to wait for key stroke
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) * @key: key entered
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) * Wait for up to @usec microseconds for a key stroke.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) * Return: status code, EFI_SUCCESS if key received
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) efi_status_t efi_wait_for_key(unsigned long usec, efi_input_key_t *key)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) efi_event_t events[2], timer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) unsigned long index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) efi_simple_text_input_protocol_t *con_in;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) efi_status_t status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) con_in = efi_table_attr(efi_system_table, con_in);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) if (!con_in)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) return EFI_UNSUPPORTED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) efi_set_event_at(events, 0, efi_table_attr(con_in, wait_for_key));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) status = efi_bs_call(create_event, EFI_EVT_TIMER, 0, NULL, NULL, &timer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) if (status != EFI_SUCCESS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) return status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) status = efi_bs_call(set_timer, timer, EfiTimerRelative,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) EFI_100NSEC_PER_USEC * usec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) if (status != EFI_SUCCESS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) return status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) efi_set_event_at(events, 1, timer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) status = efi_bs_call(wait_for_event, 2, events, &index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) if (status == EFI_SUCCESS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) if (index == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) status = efi_call_proto(con_in, read_keystroke, key);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) status = EFI_TIMEOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) efi_bs_call(close_event, timer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) return status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) }