Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

efi: libstub: Enable efi_printk() in zboot decompressor

Split the efi_printk() routine into its own source file, and provide
local implementations of strlen() and strnlen() so that the standalone
zboot app can efi_err and efi_info etc.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>

+198 -173
-2
arch/arm64/kernel/image-vars.h
··· 22 22 * position independent manner 23 23 */ 24 24 PROVIDE(__efistub_memchr = __pi_memchr); 25 - PROVIDE(__efistub_strlen = __pi_strlen); 26 - PROVIDE(__efistub_strnlen = __pi_strnlen); 27 25 PROVIDE(__efistub_strcmp = __pi_strcmp); 28 26 PROVIDE(__efistub_strrchr = __pi_strrchr); 29 27 PROVIDE(__efistub_dcache_clean_poc = __pi_dcache_clean_poc);
-2
arch/loongarch/kernel/image-vars.h
··· 10 10 __efistub_memchr = memchr; 11 11 __efistub_strcat = strcat; 12 12 __efistub_strcmp = strcmp; 13 - __efistub_strlen = strlen; 14 13 __efistub_strncat = strncat; 15 14 __efistub_strnstr = strnstr; 16 - __efistub_strnlen = strnlen; 17 15 __efistub_strrchr = strrchr; 18 16 __efistub_kernel_entry = kernel_entry; 19 17 __efistub_kernel_asize = kernel_asize;
-2
arch/riscv/kernel/image-vars.h
··· 24 24 * position independent manner 25 25 */ 26 26 __efistub_memchr = memchr; 27 - __efistub_strlen = strlen; 28 - __efistub_strnlen = strnlen; 29 27 __efistub_strcmp = strcmp; 30 28 __efistub_strrchr = strrchr; 31 29
+3 -2
drivers/firmware/efi/libstub/Makefile
··· 24 24 # disable the stackleak plugin 25 25 cflags-$(CONFIG_ARM64) += -fpie $(DISABLE_STACKLEAK_PLUGIN) \ 26 26 $(call cc-option,-mbranch-protection=none) 27 - cflags-$(CONFIG_ARM) += -fno-builtin -fpic \ 27 + cflags-$(CONFIG_ARM) += -DEFI_HAVE_STRLEN -DEFI_HAVE_STRNLEN \ 28 + -fno-builtin -fpic \ 28 29 $(call cc-option,-mno-single-pic-base) 29 30 cflags-$(CONFIG_RISCV) += -fpic 30 31 cflags-$(CONFIG_LOONGARCH) += -fpie ··· 69 68 lib-y := efi-stub-helper.o gop.o secureboot.o tpm.o \ 70 69 file.o mem.o random.o randomalloc.o pci.o \ 71 70 skip_spaces.o lib-cmdline.o lib-ctype.o \ 72 - alignedmem.o relocate.o vsprintf.o 71 + alignedmem.o relocate.o printk.o vsprintf.o 73 72 74 73 # include the stub's libfdt dependencies from lib/ when needed 75 74 libfdt-deps := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c \
-143
drivers/firmware/efi/libstub/efi-stub-helper.c
··· 9 9 10 10 #include <linux/stdarg.h> 11 11 12 - #include <linux/ctype.h> 13 12 #include <linux/efi.h> 14 13 #include <linux/kernel.h> 15 - #include <linux/printk.h> /* For CONSOLE_LOGLEVEL_* */ 16 14 #include <asm/efi.h> 17 15 #include <asm/setup.h> 18 16 ··· 18 20 19 21 bool efi_nochunk; 20 22 bool efi_nokaslr = !IS_ENABLED(CONFIG_RANDOMIZE_BASE); 21 - int efi_loglevel = CONSOLE_LOGLEVEL_DEFAULT; 22 23 bool efi_novamap; 23 24 24 25 static bool efi_noinitrd; ··· 27 30 bool __pure __efi_soft_reserve_enabled(void) 28 31 { 29 32 return !efi_nosoftreserve; 30 - } 31 - 32 - /** 33 - * efi_char16_puts() - Write a UCS-2 encoded string to the console 34 - * @str: UCS-2 encoded string 35 - */ 36 - void efi_char16_puts(efi_char16_t *str) 37 - { 38 - efi_call_proto(efi_table_attr(efi_system_table, con_out), 39 - output_string, str); 40 - } 41 - 42 - static 43 - u32 utf8_to_utf32(const u8 **s8) 44 - { 45 - u32 c32; 46 - u8 c0, cx; 47 - size_t clen, i; 48 - 49 - c0 = cx = *(*s8)++; 50 - /* 51 - * The position of the most-significant 0 bit gives us the length of 52 - * a multi-octet encoding. 53 - */ 54 - for (clen = 0; cx & 0x80; ++clen) 55 - cx <<= 1; 56 - /* 57 - * If the 0 bit is in position 8, this is a valid single-octet 58 - * encoding. If the 0 bit is in position 7 or positions 1-3, the 59 - * encoding is invalid. 60 - * In either case, we just return the first octet. 61 - */ 62 - if (clen < 2 || clen > 4) 63 - return c0; 64 - /* Get the bits from the first octet. */ 65 - c32 = cx >> clen--; 66 - for (i = 0; i < clen; ++i) { 67 - /* Trailing octets must have 10 in most significant bits. */ 68 - cx = (*s8)[i] ^ 0x80; 69 - if (cx & 0xc0) 70 - return c0; 71 - c32 = (c32 << 6) | cx; 72 - } 73 - /* 74 - * Check for validity: 75 - * - The character must be in the Unicode range. 76 - * - It must not be a surrogate. 77 - * - It must be encoded using the correct number of octets. 78 - */ 79 - if (c32 > 0x10ffff || 80 - (c32 & 0xf800) == 0xd800 || 81 - clen != (c32 >= 0x80) + (c32 >= 0x800) + (c32 >= 0x10000)) 82 - return c0; 83 - *s8 += clen; 84 - return c32; 85 - } 86 - 87 - /** 88 - * efi_puts() - Write a UTF-8 encoded string to the console 89 - * @str: UTF-8 encoded string 90 - */ 91 - void efi_puts(const char *str) 92 - { 93 - efi_char16_t buf[128]; 94 - size_t pos = 0, lim = ARRAY_SIZE(buf); 95 - const u8 *s8 = (const u8 *)str; 96 - u32 c32; 97 - 98 - while (*s8) { 99 - if (*s8 == '\n') 100 - buf[pos++] = L'\r'; 101 - c32 = utf8_to_utf32(&s8); 102 - if (c32 < 0x10000) { 103 - /* Characters in plane 0 use a single word. */ 104 - buf[pos++] = c32; 105 - } else { 106 - /* 107 - * Characters in other planes encode into a surrogate 108 - * pair. 109 - */ 110 - buf[pos++] = (0xd800 - (0x10000 >> 10)) + (c32 >> 10); 111 - buf[pos++] = 0xdc00 + (c32 & 0x3ff); 112 - } 113 - if (*s8 == '\0' || pos >= lim - 2) { 114 - buf[pos] = L'\0'; 115 - efi_char16_puts(buf); 116 - pos = 0; 117 - } 118 - } 119 - } 120 - 121 - /** 122 - * efi_printk() - Print a kernel message 123 - * @fmt: format string 124 - * 125 - * The first letter of the format string is used to determine the logging level 126 - * of the message. If the level is less then the current EFI logging level, the 127 - * message is suppressed. The message will be truncated to 255 bytes. 128 - * 129 - * Return: number of printed characters 130 - */ 131 - int efi_printk(const char *fmt, ...) 132 - { 133 - char printf_buf[256]; 134 - va_list args; 135 - int printed; 136 - int loglevel = printk_get_level(fmt); 137 - 138 - switch (loglevel) { 139 - case '0' ... '9': 140 - loglevel -= '0'; 141 - break; 142 - default: 143 - /* 144 - * Use loglevel -1 for cases where we just want to print to 145 - * the screen. 146 - */ 147 - loglevel = -1; 148 - break; 149 - } 150 - 151 - if (loglevel >= efi_loglevel) 152 - return 0; 153 - 154 - if (loglevel >= 0) 155 - efi_puts("EFI stub: "); 156 - 157 - fmt = printk_skip_level(fmt); 158 - 159 - va_start(args, fmt); 160 - printed = vsnprintf(printf_buf, sizeof(printf_buf), fmt, args); 161 - va_end(args); 162 - 163 - efi_puts(printf_buf); 164 - if (printed >= sizeof(printf_buf)) { 165 - efi_puts("[Message truncated]\n"); 166 - return -1; 167 - } 168 - 169 - return printed; 170 33 } 171 34 172 35 /**
+154
drivers/firmware/efi/libstub/printk.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <linux/stdarg.h> 4 + 5 + #include <linux/ctype.h> 6 + #include <linux/efi.h> 7 + #include <linux/kernel.h> 8 + #include <linux/printk.h> /* For CONSOLE_LOGLEVEL_* */ 9 + #include <asm/efi.h> 10 + #include <asm/setup.h> 11 + 12 + #include "efistub.h" 13 + 14 + int efi_loglevel = CONSOLE_LOGLEVEL_DEFAULT; 15 + 16 + /** 17 + * efi_char16_puts() - Write a UCS-2 encoded string to the console 18 + * @str: UCS-2 encoded string 19 + */ 20 + void efi_char16_puts(efi_char16_t *str) 21 + { 22 + efi_call_proto(efi_table_attr(efi_system_table, con_out), 23 + output_string, str); 24 + } 25 + 26 + static 27 + u32 utf8_to_utf32(const u8 **s8) 28 + { 29 + u32 c32; 30 + u8 c0, cx; 31 + size_t clen, i; 32 + 33 + c0 = cx = *(*s8)++; 34 + /* 35 + * The position of the most-significant 0 bit gives us the length of 36 + * a multi-octet encoding. 37 + */ 38 + for (clen = 0; cx & 0x80; ++clen) 39 + cx <<= 1; 40 + /* 41 + * If the 0 bit is in position 8, this is a valid single-octet 42 + * encoding. If the 0 bit is in position 7 or positions 1-3, the 43 + * encoding is invalid. 44 + * In either case, we just return the first octet. 45 + */ 46 + if (clen < 2 || clen > 4) 47 + return c0; 48 + /* Get the bits from the first octet. */ 49 + c32 = cx >> clen--; 50 + for (i = 0; i < clen; ++i) { 51 + /* Trailing octets must have 10 in most significant bits. */ 52 + cx = (*s8)[i] ^ 0x80; 53 + if (cx & 0xc0) 54 + return c0; 55 + c32 = (c32 << 6) | cx; 56 + } 57 + /* 58 + * Check for validity: 59 + * - The character must be in the Unicode range. 60 + * - It must not be a surrogate. 61 + * - It must be encoded using the correct number of octets. 62 + */ 63 + if (c32 > 0x10ffff || 64 + (c32 & 0xf800) == 0xd800 || 65 + clen != (c32 >= 0x80) + (c32 >= 0x800) + (c32 >= 0x10000)) 66 + return c0; 67 + *s8 += clen; 68 + return c32; 69 + } 70 + 71 + /** 72 + * efi_puts() - Write a UTF-8 encoded string to the console 73 + * @str: UTF-8 encoded string 74 + */ 75 + void efi_puts(const char *str) 76 + { 77 + efi_char16_t buf[128]; 78 + size_t pos = 0, lim = ARRAY_SIZE(buf); 79 + const u8 *s8 = (const u8 *)str; 80 + u32 c32; 81 + 82 + while (*s8) { 83 + if (*s8 == '\n') 84 + buf[pos++] = L'\r'; 85 + c32 = utf8_to_utf32(&s8); 86 + if (c32 < 0x10000) { 87 + /* Characters in plane 0 use a single word. */ 88 + buf[pos++] = c32; 89 + } else { 90 + /* 91 + * Characters in other planes encode into a surrogate 92 + * pair. 93 + */ 94 + buf[pos++] = (0xd800 - (0x10000 >> 10)) + (c32 >> 10); 95 + buf[pos++] = 0xdc00 + (c32 & 0x3ff); 96 + } 97 + if (*s8 == '\0' || pos >= lim - 2) { 98 + buf[pos] = L'\0'; 99 + efi_char16_puts(buf); 100 + pos = 0; 101 + } 102 + } 103 + } 104 + 105 + /** 106 + * efi_printk() - Print a kernel message 107 + * @fmt: format string 108 + * 109 + * The first letter of the format string is used to determine the logging level 110 + * of the message. If the level is less then the current EFI logging level, the 111 + * message is suppressed. The message will be truncated to 255 bytes. 112 + * 113 + * Return: number of printed characters 114 + */ 115 + int efi_printk(const char *fmt, ...) 116 + { 117 + char printf_buf[256]; 118 + va_list args; 119 + int printed; 120 + int loglevel = printk_get_level(fmt); 121 + 122 + switch (loglevel) { 123 + case '0' ... '9': 124 + loglevel -= '0'; 125 + break; 126 + default: 127 + /* 128 + * Use loglevel -1 for cases where we just want to print to 129 + * the screen. 130 + */ 131 + loglevel = -1; 132 + break; 133 + } 134 + 135 + if (loglevel >= efi_loglevel) 136 + return 0; 137 + 138 + if (loglevel >= 0) 139 + efi_puts("EFI stub: "); 140 + 141 + fmt = printk_skip_level(fmt); 142 + 143 + va_start(args, fmt); 144 + printed = vsnprintf(printf_buf, sizeof(printf_buf), fmt, args); 145 + va_end(args); 146 + 147 + efi_puts(printf_buf); 148 + if (printed >= sizeof(printf_buf)) { 149 + efi_puts("[Message truncated]\n"); 150 + return -1; 151 + } 152 + 153 + return printed; 154 + }
+31 -2
drivers/firmware/efi/libstub/string.c
··· 11 11 #include <linux/types.h> 12 12 #include <linux/string.h> 13 13 14 - #ifndef __HAVE_ARCH_STRSTR 14 + #ifndef EFI_HAVE_STRLEN 15 + /** 16 + * strlen - Find the length of a string 17 + * @s: The string to be sized 18 + */ 19 + size_t strlen(const char *s) 20 + { 21 + const char *sc; 22 + 23 + for (sc = s; *sc != '\0'; ++sc) 24 + /* nothing */; 25 + return sc - s; 26 + } 27 + #endif 28 + 29 + #ifndef EFI_HAVE_STRNLEN 30 + /** 31 + * strnlen - Find the length of a length-limited string 32 + * @s: The string to be sized 33 + * @count: The maximum number of bytes to search 34 + */ 35 + size_t strnlen(const char *s, size_t count) 36 + { 37 + const char *sc; 38 + 39 + for (sc = s; count-- && *sc != '\0'; ++sc) 40 + /* nothing */; 41 + return sc - s; 42 + } 43 + #endif 44 + 15 45 /** 16 46 * strstr - Find the first substring in a %NUL terminated string 17 47 * @s1: The string to be searched ··· 63 33 } 64 34 return NULL; 65 35 } 66 - #endif 67 36 68 37 /** 69 38 * strncmp - Compare two length-limited strings
+10 -20
drivers/firmware/efi/libstub/zboot.c
··· 32 32 extern char efi_zboot_header[]; 33 33 extern char _gzdata_start[], _gzdata_end[]; 34 34 35 - static void log(efi_char16_t str[]) 36 - { 37 - efi_call_proto(efi_table_attr(efi_system_table, con_out), 38 - output_string, L"EFI decompressor: "); 39 - efi_call_proto(efi_table_attr(efi_system_table, con_out), 40 - output_string, str); 41 - efi_call_proto(efi_table_attr(efi_system_table, con_out), 42 - output_string, L"\n"); 43 - } 44 - 45 35 static void error(char *x) 46 36 { 47 - log(L"error() called from decompressor library\n"); 37 + efi_err("EFI decompressor: %s\n", x); 48 38 } 49 39 50 40 static efi_status_t __efiapi ··· 81 91 ret = __decompress(_gzdata_start, compressed_size, NULL, NULL, 82 92 buffer, size, NULL, error); 83 93 if (ret < 0) { 84 - log(L"Decompression failed"); 94 + error("Decompression failed"); 85 95 return EFI_DEVICE_ERROR; 86 96 } 87 97 } else { ··· 170 180 status = efi_bs_call(handle_protocol, handle, 171 181 &LOADED_IMAGE_PROTOCOL_GUID, (void **)&parent); 172 182 if (status != EFI_SUCCESS) { 173 - log(L"Failed to locate parent's loaded image protocol"); 183 + error("Failed to locate parent's loaded image protocol"); 174 184 return status; 175 185 } 176 186 ··· 197 207 sizeof(struct efi_vendor_dev_path), 198 208 (void **)&dp_alloc); 199 209 if (status != EFI_SUCCESS) { 200 - log(L"Failed to allocate device path pool memory"); 210 + error("Failed to allocate device path pool memory"); 201 211 return status; 202 212 } 203 213 ··· 226 236 &EFI_LOAD_FILE2_PROTOCOL_GUID, &zboot_load_file2, 227 237 NULL); 228 238 if (status != EFI_SUCCESS) { 229 - log(L"Failed to install LoadFile2 protocol and device path"); 239 + error("Failed to install LoadFile2 protocol and device path"); 230 240 goto free_dpalloc; 231 241 } 232 242 233 243 status = efi_bs_call(load_image, false, handle, li_dp, NULL, 0, 234 244 &child_handle); 235 245 if (status != EFI_SUCCESS) { 236 - log(L"Failed to load image"); 246 + error("Failed to load image"); 237 247 goto uninstall_lf2; 238 248 } 239 249 240 250 status = efi_bs_call(handle_protocol, child_handle, 241 251 &LOADED_IMAGE_PROTOCOL_GUID, (void **)&child); 242 252 if (status != EFI_SUCCESS) { 243 - log(L"Failed to locate child's loaded image protocol"); 253 + error("Failed to locate child's loaded image protocol"); 244 254 goto unload_image; 245 255 } 246 256 ··· 251 261 status = efi_bs_call(start_image, child_handle, &exit_data_size, 252 262 &exit_data); 253 263 if (status != EFI_SUCCESS) { 254 - log(L"StartImage() returned with error"); 264 + error("StartImage() returned with error:"); 255 265 if (exit_data_size > 0) 256 - log(exit_data); 266 + efi_err("%ls\n", exit_data); 257 267 258 268 // If StartImage() returns EFI_SECURITY_VIOLATION, the image is 259 269 // not unloaded so we need to do it by hand. ··· 276 286 277 287 // Free ExitData in case Exit() returned with a failure code, 278 288 // but return the original status code. 279 - log(L"Exit() returned with failure code"); 289 + error("Exit() returned with failure code"); 280 290 if (exit_data != NULL) 281 291 efi_bs_call(free_pool, exit_data); 282 292 return status;