Merge pull request #23706 from medhefgo/efi-clang
boot: Add printf functions
This commit is contained in:
+3
-3
@@ -175,12 +175,12 @@ static inline int __coverity_check_and_return__(int condition) {
|
||||
#define assert_message_se(expr, message) \
|
||||
do { \
|
||||
if (_unlikely_(!(expr))) \
|
||||
log_assert_failed(message, PROJECT_FILE, __LINE__, __PRETTY_FUNCTION__); \
|
||||
log_assert_failed(message, PROJECT_FILE, __LINE__, __func__); \
|
||||
} while (false)
|
||||
|
||||
#define assert_log(expr, message) ((_likely_(expr)) \
|
||||
? (true) \
|
||||
: (log_assert_failed_return(message, PROJECT_FILE, __LINE__, __PRETTY_FUNCTION__), false))
|
||||
: (log_assert_failed_return(message, PROJECT_FILE, __LINE__, __func__), false))
|
||||
|
||||
#endif /* __COVERITY__ */
|
||||
|
||||
@@ -195,7 +195,7 @@ static inline int __coverity_check_and_return__(int condition) {
|
||||
#endif
|
||||
|
||||
#define assert_not_reached() \
|
||||
log_assert_failed_unreachable(PROJECT_FILE, __LINE__, __PRETTY_FUNCTION__)
|
||||
log_assert_failed_unreachable(PROJECT_FILE, __LINE__, __func__)
|
||||
|
||||
#define assert_return(expr, r) \
|
||||
do { \
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <efi.h>
|
||||
#include <efilib.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
void efi_assert(const char *expr, const char *file, unsigned line, const char *function) {
|
||||
log_error_stall(L"systemd-boot assertion '%a' failed at %a:%u, function %a(). Halting.", expr, file, line, function);
|
||||
for (;;)
|
||||
BS->Stall(60 * 1000 * 1000);
|
||||
}
|
||||
+170
-143
@@ -3,6 +3,7 @@
|
||||
#include <efi.h>
|
||||
#include <efigpt.h>
|
||||
#include <efilib.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "bcd.h"
|
||||
#include "bootspec-fundamental.h"
|
||||
@@ -427,7 +428,7 @@ static char16_t *update_timeout_efivar(uint32_t *t, bool inc) {
|
||||
case TIMEOUT_MENU_HIDDEN:
|
||||
return xstrdup16(u"Menu disabled. Hold down key at bootup to show menu.");
|
||||
default:
|
||||
return xpool_print(L"Menu timeout set to %u s.", *t);
|
||||
return xasprintf("Menu timeout set to %u s.", *t);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -442,22 +443,9 @@ static bool unicode_supported(void) {
|
||||
return cache;
|
||||
}
|
||||
|
||||
static void ps_string(const char16_t *fmt, const void *value) {
|
||||
assert(fmt);
|
||||
if (value)
|
||||
Print(fmt, value);
|
||||
}
|
||||
|
||||
static void ps_bool(const char16_t *fmt, bool value) {
|
||||
assert(fmt);
|
||||
Print(fmt, yes_no(value));
|
||||
}
|
||||
|
||||
static bool ps_continue(void) {
|
||||
if (unicode_supported())
|
||||
Print(L"\n─── Press any key to continue, ESC or q to quit. ───\n\n");
|
||||
else
|
||||
Print(L"\n--- Press any key to continue, ESC or q to quit. ---\n\n");
|
||||
const char16_t *sep = unicode_supported() ? u"───" : u"---";
|
||||
printf("\n%ls Press any key to continue, ESC or q to quit. %ls\n\n", sep, sep);
|
||||
|
||||
uint64_t key;
|
||||
return console_key_read(&key, UINT64_MAX) == EFI_SUCCESS &&
|
||||
@@ -479,112 +467,143 @@ static void print_status(Config *config, char16_t *loaded_image_path) {
|
||||
secure = secure_boot_mode();
|
||||
(void) efivar_get(LOADER_GUID, L"LoaderDevicePartUUID", &device_part_uuid);
|
||||
|
||||
/* We employ some unusual indentation here for readability. */
|
||||
|
||||
ps_string(L" systemd-boot version: %a\n", GIT_VERSION);
|
||||
ps_string(L" loaded image: %s\n", loaded_image_path);
|
||||
ps_string(L" loader partition UUID: %s\n", device_part_uuid);
|
||||
ps_string(L" architecture: %a\n", EFI_MACHINE_TYPE_NAME);
|
||||
Print(L" UEFI specification: %u.%02u\n", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
|
||||
ps_string(L" firmware vendor: %s\n", ST->FirmwareVendor);
|
||||
Print(L" firmware version: %u.%02u\n", ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff);
|
||||
Print(L" OS indications: %lu\n", get_os_indications_supported());
|
||||
Print(L" secure boot: %s (%s)\n", yes_no(IN_SET(secure, SECURE_BOOT_USER, SECURE_BOOT_DEPLOYED)), secure_boot_mode_to_string(secure));
|
||||
ps_bool(L" shim: %s\n", shim_loaded());
|
||||
ps_bool(L" TPM: %s\n", tpm_present());
|
||||
Print(L" console mode: %d/%ld (%" PRIuN L"x%" PRIuN L" @%ux%u)\n", ST->ConOut->Mode->Mode, ST->ConOut->Mode->MaxMode - INT64_C(1), x_max, y_max, screen_width, screen_height);
|
||||
printf(" systemd-boot version: " GIT_VERSION "\n");
|
||||
if (loaded_image_path)
|
||||
printf(" loaded image: %ls\n", loaded_image_path);
|
||||
if (device_part_uuid)
|
||||
printf(" loader partition UUID: %ls\n", device_part_uuid);
|
||||
printf(" architecture: " EFI_MACHINE_TYPE_NAME "\n");
|
||||
printf(" UEFI specification: %u.%02u\n", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
|
||||
printf(" firmware vendor: %ls\n", ST->FirmwareVendor);
|
||||
printf(" firmware version: %u.%02u\n", ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff);
|
||||
printf(" OS indications: %#" PRIx64 "\n", get_os_indications_supported());
|
||||
printf(" secure boot: %ls (%ls)\n",
|
||||
yes_no(IN_SET(secure, SECURE_BOOT_USER, SECURE_BOOT_DEPLOYED)),
|
||||
secure_boot_mode_to_string(secure));
|
||||
printf(" shim: %ls\n", yes_no(shim_loaded()));
|
||||
printf(" TPM: %ls\n", yes_no(tpm_present()));
|
||||
printf(" console mode: %i/%" PRIi64 " (%zux%zu @%ux%u)\n",
|
||||
ST->ConOut->Mode->Mode, ST->ConOut->Mode->MaxMode - INT64_C(1),
|
||||
x_max, y_max, screen_width, screen_height);
|
||||
|
||||
if (!ps_continue())
|
||||
return;
|
||||
|
||||
switch (config->timeout_sec_config) {
|
||||
case TIMEOUT_UNSET:
|
||||
break;
|
||||
break;
|
||||
case TIMEOUT_MENU_FORCE:
|
||||
Print(L" timeout (config): menu-force\n"); break;
|
||||
printf(" timeout (config): menu-force\n");
|
||||
break;
|
||||
case TIMEOUT_MENU_HIDDEN:
|
||||
Print(L" timeout (config): menu-hidden\n"); break;
|
||||
printf(" timeout (config): menu-hidden\n");
|
||||
break;
|
||||
default:
|
||||
Print(L" timeout (config): %u s\n", config->timeout_sec_config);
|
||||
printf(" timeout (config): %u s\n", config->timeout_sec_config);
|
||||
}
|
||||
|
||||
switch (config->timeout_sec_efivar) {
|
||||
case TIMEOUT_UNSET:
|
||||
break;
|
||||
break;
|
||||
case TIMEOUT_MENU_FORCE:
|
||||
Print(L" timeout (EFI var): menu-force\n"); break;
|
||||
printf(" timeout (EFI var): menu-force\n");
|
||||
break;
|
||||
case TIMEOUT_MENU_HIDDEN:
|
||||
Print(L" timeout (EFI var): menu-hidden\n"); break;
|
||||
printf(" timeout (EFI var): menu-hidden\n");
|
||||
break;
|
||||
default:
|
||||
Print(L" timeout (EFI var): %u s\n", config->timeout_sec_efivar);
|
||||
printf(" timeout (EFI var): %u s\n", config->timeout_sec_efivar);
|
||||
}
|
||||
|
||||
ps_string(L" default (config): %s\n", config->entry_default_config);
|
||||
ps_string(L" default (EFI var): %s\n", config->entry_default_efivar);
|
||||
ps_string(L" default (one-shot): %s\n", config->entry_oneshot);
|
||||
ps_string(L" saved entry: %s\n", config->entry_saved);
|
||||
ps_bool(L" editor: %s\n", config->editor);
|
||||
ps_bool(L" auto-entries: %s\n", config->auto_entries);
|
||||
ps_bool(L" auto-firmware: %s\n", config->auto_firmware);
|
||||
ps_bool(L" beep: %s\n", config->beep);
|
||||
ps_bool(L" reboot-for-bitlocker: %s\n", config->reboot_for_bitlocker);
|
||||
if (config->entry_default_config)
|
||||
printf(" default (config): %ls\n", config->entry_default_config);
|
||||
if (config->entry_default_efivar)
|
||||
printf(" default (EFI var): %ls\n", config->entry_default_efivar);
|
||||
if (config->entry_oneshot)
|
||||
printf(" default (one-shot): %ls\n", config->entry_oneshot);
|
||||
if (config->entry_saved)
|
||||
printf(" saved entry: %ls\n", config->entry_saved);
|
||||
printf(" editor: %ls\n", yes_no(config->editor));
|
||||
printf(" auto-entries: %ls\n", yes_no(config->auto_entries));
|
||||
printf(" auto-firmware: %ls\n", yes_no(config->auto_firmware));
|
||||
printf(" beep: %ls\n", yes_no(config->beep));
|
||||
printf(" reboot-for-bitlocker: %ls\n", yes_no(config->reboot_for_bitlocker));
|
||||
|
||||
switch (config->secure_boot_enroll) {
|
||||
case ENROLL_OFF:
|
||||
Print(L" secure-boot-enroll: off\n"); break;
|
||||
printf(" secure-boot-enroll: off\n");
|
||||
break;
|
||||
case ENROLL_MANUAL:
|
||||
Print(L" secure-boot-enroll: manual\n"); break;
|
||||
printf(" secure-boot-enroll: manual\n");
|
||||
break;
|
||||
case ENROLL_FORCE:
|
||||
Print(L" secure-boot-enroll: force\n"); break;
|
||||
printf(" secure-boot-enroll: force\n");
|
||||
break;
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
switch (config->console_mode) {
|
||||
case CONSOLE_MODE_AUTO:
|
||||
Print(L" console-mode (config): %s\n", L"auto"); break;
|
||||
printf(" console-mode (config): auto\n");
|
||||
break;
|
||||
case CONSOLE_MODE_KEEP:
|
||||
Print(L" console-mode (config): %s\n", L"keep"); break;
|
||||
printf(" console-mode (config): keep\n");
|
||||
break;
|
||||
case CONSOLE_MODE_FIRMWARE_MAX:
|
||||
Print(L" console-mode (config): %s\n", L"max"); break;
|
||||
printf(" console-mode (config): max\n");
|
||||
break;
|
||||
default:
|
||||
Print(L" console-mode (config): %ld\n", config->console_mode); break;
|
||||
printf(" console-mode (config): %" PRIi64 "\n", config->console_mode);
|
||||
break;
|
||||
}
|
||||
|
||||
/* EFI var console mode is always a concrete value or unset. */
|
||||
if (config->console_mode_efivar != CONSOLE_MODE_KEEP)
|
||||
Print(L"console-mode (EFI var): %ld\n", config->console_mode_efivar);
|
||||
printf("console-mode (EFI var): %" PRIi64 "\n", config->console_mode_efivar);
|
||||
|
||||
if (!ps_continue())
|
||||
return;
|
||||
|
||||
for (UINTN i = 0; i < config->entry_count; i++) {
|
||||
ConfigEntry *entry = config->entries[i];
|
||||
EFI_DEVICE_PATH *dp = NULL;
|
||||
_cleanup_free_ char16_t *dp_str = NULL;
|
||||
|
||||
_cleanup_free_ char16_t *dp = NULL;
|
||||
if (entry->device)
|
||||
(void) device_path_to_str(DevicePathFromHandle(entry->device), &dp);
|
||||
if (entry->device &&
|
||||
BS->HandleProtocol(entry->device, &(EFI_GUID) EFI_DEVICE_PATH_PROTOCOL_GUID, (void **) &dp) ==
|
||||
EFI_SUCCESS)
|
||||
(void) device_path_to_str(dp, &dp_str);
|
||||
|
||||
Print(L" config entry: %" PRIuN L"/%" PRIuN L"\n", i + 1, config->entry_count);
|
||||
ps_string(L" id: %s\n", entry->id);
|
||||
ps_string(L" title: %s\n", entry->title);
|
||||
ps_string(L" title show: %s\n", streq16(entry->title, entry->title_show) ? NULL : entry->title_show);
|
||||
ps_string(L" sort key: %s\n", entry->sort_key);
|
||||
ps_string(L" version: %s\n", entry->version);
|
||||
ps_string(L" machine-id: %s\n", entry->machine_id);
|
||||
ps_string(L" device: %s\n", dp);
|
||||
ps_string(L" loader: %s\n", entry->loader);
|
||||
printf(" config entry: %zu/%zu\n", i + 1, config->entry_count);
|
||||
printf(" id: %ls\n", entry->id);
|
||||
if (entry->title)
|
||||
printf(" title: %ls\n", entry->title);
|
||||
if (entry->title_show && !streq16(entry->title, entry->title_show))
|
||||
printf(" title show: %ls\n", entry->title_show);
|
||||
if (entry->sort_key)
|
||||
printf(" sort key: %ls\n", entry->sort_key);
|
||||
if (entry->version)
|
||||
printf(" version: %ls\n", entry->version);
|
||||
if (entry->machine_id)
|
||||
printf(" machine-id: %ls\n", entry->machine_id);
|
||||
if (dp_str)
|
||||
printf(" device: %ls\n", dp_str);
|
||||
if (entry->loader)
|
||||
printf(" loader: %ls\n", entry->loader);
|
||||
STRV_FOREACH(initrd, entry->initrd)
|
||||
Print(L" initrd: %s\n", *initrd);
|
||||
ps_string(L" devicetree: %s\n", entry->devicetree);
|
||||
ps_string(L" options: %s\n", entry->options);
|
||||
ps_bool(L" internal call: %s\n", !!entry->call);
|
||||
printf(" initrd: %ls\n", *initrd);
|
||||
if (entry->devicetree)
|
||||
printf(" devicetree: %ls\n", entry->devicetree);
|
||||
if (entry->options)
|
||||
printf(" options: %ls\n", entry->options);
|
||||
printf(" internal call: %ls\n", yes_no(!!entry->call));
|
||||
|
||||
ps_bool(L"counting boots: %s\n", entry->tries_left >= 0);
|
||||
printf("counting boots: %ls\n", yes_no(entry->tries_left >= 0));
|
||||
if (entry->tries_left >= 0) {
|
||||
Print(L" tries: %u left, %u done\n", entry->tries_left, entry->tries_done);
|
||||
Print(L" current path: %s\\%s\n", entry->path, entry->current_name);
|
||||
Print(L" next path: %s\\%s\n", entry->path, entry->next_name);
|
||||
printf(" tries: %i left, %i done\n", entry->tries_left, entry->tries_done);
|
||||
printf(" current path: %ls\\%ls\n", entry->path, entry->current_name);
|
||||
printf(" next path: %ls\\%ls\n", entry->path, entry->next_name);
|
||||
}
|
||||
|
||||
if (!ps_continue())
|
||||
@@ -597,14 +616,14 @@ static EFI_STATUS reboot_into_firmware(void) {
|
||||
EFI_STATUS err;
|
||||
|
||||
if (!FLAGS_SET(get_os_indications_supported(), EFI_OS_INDICATIONS_BOOT_TO_FW_UI))
|
||||
return log_error_status_stall(EFI_UNSUPPORTED, L"Reboot to firmware interface not supported.");
|
||||
return log_error_status(EFI_UNSUPPORTED, "Reboot to firmware interface not supported.");
|
||||
|
||||
(void) efivar_get_uint64_le(EFI_GLOBAL_GUID, L"OsIndications", &osind);
|
||||
osind |= EFI_OS_INDICATIONS_BOOT_TO_FW_UI;
|
||||
|
||||
err = efivar_set_uint64_le(EFI_GLOBAL_GUID, L"OsIndications", osind, EFI_VARIABLE_NON_VOLATILE);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Error setting OsIndications: %r", err);
|
||||
return log_error_status(err, "Error setting OsIndications: %m");
|
||||
|
||||
RT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
|
||||
assert_not_reached();
|
||||
@@ -640,13 +659,13 @@ static bool menu_run(
|
||||
ST->ConOut->EnableCursor(ST->ConOut, false);
|
||||
|
||||
/* draw a single character to make ClearScreen work on some firmware */
|
||||
Print(L" ");
|
||||
ST->ConOut->OutputString(ST->ConOut, (char16_t *) u" ");
|
||||
|
||||
err = console_set_mode(config->console_mode_efivar != CONSOLE_MODE_KEEP ?
|
||||
config->console_mode_efivar : config->console_mode);
|
||||
if (err != EFI_SUCCESS) {
|
||||
clear_screen(COLOR_NORMAL);
|
||||
log_error_stall(L"Error switching console mode: %r", err);
|
||||
log_error_status(err, "Error switching console mode: %m");
|
||||
}
|
||||
|
||||
UINTN line_width = 0, entry_padding = 3;
|
||||
@@ -761,7 +780,7 @@ static bool menu_run(
|
||||
|
||||
if (timeout_remain > 0) {
|
||||
free(status);
|
||||
status = xpool_print(L"Boot in %u s.", timeout_remain);
|
||||
status = xasprintf("Boot in %u s.", timeout_remain);
|
||||
}
|
||||
|
||||
if (status) {
|
||||
@@ -940,9 +959,9 @@ static bool menu_run(
|
||||
break;
|
||||
|
||||
case KEYPRESS(0, 0, 'v'):
|
||||
status = xpool_print(
|
||||
L"systemd-boot " GIT_VERSION L" (" EFI_MACHINE_TYPE_NAME L"), "
|
||||
L"UEFI Specification %u.%02u, Vendor %s %u.%02u",
|
||||
status = xasprintf(
|
||||
"systemd-boot " GIT_VERSION " (" EFI_MACHINE_TYPE_NAME "), "
|
||||
"UEFI Specification %u.%02u, Vendor %ls %u.%02u",
|
||||
ST->Hdr.Revision >> 16,
|
||||
ST->Hdr.Revision & 0xffff,
|
||||
ST->FirmwareVendor,
|
||||
@@ -964,10 +983,12 @@ static bool menu_run(
|
||||
case KEYPRESS(0, 0, 'r'):
|
||||
err = console_set_mode(CONSOLE_MODE_NEXT);
|
||||
if (err != EFI_SUCCESS)
|
||||
status = xpool_print(L"Error changing console mode: %r", err);
|
||||
status = xasprintf_status(err, "Error changing console mode: %m");
|
||||
else {
|
||||
config->console_mode_efivar = ST->ConOut->Mode->Mode;
|
||||
status = xpool_print(L"Console mode changed to %ld.", config->console_mode_efivar);
|
||||
status = xasprintf(
|
||||
"Console mode changed to %" PRIi64 ".",
|
||||
config->console_mode_efivar);
|
||||
}
|
||||
new_mode = true;
|
||||
break;
|
||||
@@ -977,10 +998,13 @@ static bool menu_run(
|
||||
err = console_set_mode(config->console_mode == CONSOLE_MODE_KEEP ?
|
||||
console_mode_initial : config->console_mode);
|
||||
if (err != EFI_SUCCESS)
|
||||
status = xpool_print(L"Error resetting console mode: %r", err);
|
||||
status = xasprintf_status(err, "Error resetting console mode: %m");
|
||||
else
|
||||
status = xpool_print(L"Console mode reset to %s default.",
|
||||
config->console_mode == CONSOLE_MODE_KEEP ? L"firmware" : L"configuration file");
|
||||
status = xasprintf(
|
||||
"Console mode reset to %s default.",
|
||||
config->console_mode == CONSOLE_MODE_KEEP ?
|
||||
"firmware" :
|
||||
"configuration file");
|
||||
new_mode = true;
|
||||
break;
|
||||
|
||||
@@ -993,9 +1017,9 @@ static bool menu_run(
|
||||
if (FLAGS_SET(get_os_indications_supported(), EFI_OS_INDICATIONS_BOOT_TO_FW_UI)) {
|
||||
firmware_setup = true;
|
||||
/* Let's make sure the user really wants to do this. */
|
||||
status = xpool_print(L"Press Enter to reboot into firmware interface.");
|
||||
status = xstrdup16(u"Press Enter to reboot into firmware interface.");
|
||||
} else
|
||||
status = xpool_print(L"Reboot into firmware interface not supported.");
|
||||
status = xstrdup16(u"Reboot into firmware interface not supported.");
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1189,7 +1213,7 @@ static void config_defaults_load_from_file(Config *config, char *content) {
|
||||
else {
|
||||
uint64_t u;
|
||||
if (!parse_number8(value, &u, NULL) || u > TIMEOUT_TYPE_MAX) {
|
||||
log_error_stall(L"Error parsing 'timeout' config option: %a", value);
|
||||
log_error("Error parsing 'timeout' config option: %s", value);
|
||||
continue;
|
||||
}
|
||||
config->timeout_sec_config = u;
|
||||
@@ -1200,7 +1224,7 @@ static void config_defaults_load_from_file(Config *config, char *content) {
|
||||
|
||||
if (streq8(key, "default")) {
|
||||
if (value[0] == '@' && !strcaseeq8(value, "@saved")) {
|
||||
log_error_stall(L"Unsupported special entry identifier: %a", value);
|
||||
log_error("Unsupported special entry identifier: %s", value);
|
||||
continue;
|
||||
}
|
||||
free(config->entry_default_config);
|
||||
@@ -1211,35 +1235,35 @@ static void config_defaults_load_from_file(Config *config, char *content) {
|
||||
if (streq8(key, "editor")) {
|
||||
err = parse_boolean(value, &config->editor);
|
||||
if (err != EFI_SUCCESS)
|
||||
log_error_stall(L"Error parsing 'editor' config option: %a", value);
|
||||
log_error("Error parsing 'editor' config option: %s", value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (streq8(key, "auto-entries")) {
|
||||
err = parse_boolean(value, &config->auto_entries);
|
||||
if (err != EFI_SUCCESS)
|
||||
log_error_stall(L"Error parsing 'auto-entries' config option: %a", value);
|
||||
log_error("Error parsing 'auto-entries' config option: %s", value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (streq8(key, "auto-firmware")) {
|
||||
err = parse_boolean(value, &config->auto_firmware);
|
||||
if (err != EFI_SUCCESS)
|
||||
log_error_stall(L"Error parsing 'auto-firmware' config option: %a", value);
|
||||
log_error("Error parsing 'auto-firmware' config option: %s", value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (streq8(key, "beep")) {
|
||||
err = parse_boolean(value, &config->beep);
|
||||
if (err != EFI_SUCCESS)
|
||||
log_error_stall(L"Error parsing 'beep' config option: %a", value);
|
||||
log_error("Error parsing 'beep' config option: %s", value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (streq8(key, "reboot-for-bitlocker")) {
|
||||
err = parse_boolean(value, &config->reboot_for_bitlocker);
|
||||
if (err != EFI_SUCCESS)
|
||||
log_error_stall(L"Error parsing 'reboot-for-bitlocker' config option: %a", value);
|
||||
log_error("Error parsing 'reboot-for-bitlocker' config option: %s", value);
|
||||
}
|
||||
|
||||
if (streq8(key, "secure-boot-enroll")) {
|
||||
@@ -1250,7 +1274,7 @@ static void config_defaults_load_from_file(Config *config, char *content) {
|
||||
else if (streq8(value, "off"))
|
||||
config->secure_boot_enroll = ENROLL_OFF;
|
||||
else
|
||||
log_error_stall(L"Error parsing 'secure-boot-enroll' config option: %a", value);
|
||||
log_error("Error parsing 'secure-boot-enroll' config option: %s", value);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1264,7 +1288,7 @@ static void config_defaults_load_from_file(Config *config, char *content) {
|
||||
else {
|
||||
uint64_t u;
|
||||
if (!parse_number8(value, &u, NULL) || u > CONSOLE_MODE_RANGE_MAX) {
|
||||
log_error_stall(L"Error parsing 'console-mode' config option: %a", value);
|
||||
log_error("Error parsing 'console-mode' config option: %s", value);
|
||||
continue;
|
||||
}
|
||||
config->console_mode = u;
|
||||
@@ -1329,9 +1353,9 @@ static void config_entry_parse_tries(
|
||||
entry->tries_done = tries_done;
|
||||
entry->path = xstrdup16(path);
|
||||
entry->current_name = xstrdup16(file);
|
||||
entry->next_name = xpool_print(
|
||||
L"%.*s%u-%u%s",
|
||||
prefix_len,
|
||||
entry->next_name = xasprintf(
|
||||
"%.*ls%" PRIu64 "-%" PRIu64 "%ls",
|
||||
(int) prefix_len,
|
||||
file,
|
||||
LESS_BY(tries_left, 1u),
|
||||
MIN(tries_done + 1, (uint64_t) INT_MAX),
|
||||
@@ -1354,7 +1378,7 @@ static void config_entry_bump_counters(ConfigEntry *entry, EFI_FILE *root_dir) {
|
||||
if (!entry->path || !entry->current_name || !entry->next_name)
|
||||
return;
|
||||
|
||||
old_path = xpool_print(L"%s\\%s", entry->path, entry->current_name);
|
||||
old_path = xasprintf("%ls\\%ls", entry->path, entry->current_name);
|
||||
|
||||
err = root_dir->Open(root_dir, &handle, old_path, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE, 0ULL);
|
||||
if (err != EFI_SUCCESS)
|
||||
@@ -1368,7 +1392,7 @@ static void config_entry_bump_counters(ConfigEntry *entry, EFI_FILE *root_dir) {
|
||||
strcpy16(file_info->FileName, entry->next_name);
|
||||
err = handle->SetInfo(handle, &GenericFileInfo, file_info_size, file_info);
|
||||
if (err != EFI_SUCCESS) {
|
||||
log_error_stall(L"Failed to rename '%s' to '%s', ignoring: %r", old_path, entry->next_name, err);
|
||||
log_error_status(err, "Failed to rename '%ls' to '%ls', ignoring: %m", old_path, entry->next_name);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1377,7 +1401,7 @@ static void config_entry_bump_counters(ConfigEntry *entry, EFI_FILE *root_dir) {
|
||||
|
||||
/* Let's tell the OS that we renamed this file, so that it knows what to rename to the counter-less name on
|
||||
* success */
|
||||
new_path = xpool_print(L"%s\\%s", entry->path, entry->next_name);
|
||||
new_path = xasprintf("%ls\\%ls", entry->path, entry->next_name);
|
||||
efivar_set(LOADER_GUID, L"LoaderBootCountPath", new_path, 0);
|
||||
|
||||
/* If the file we just renamed is the loader path, then let's update that. */
|
||||
@@ -1491,7 +1515,7 @@ static void config_entry_add_type1(
|
||||
|
||||
new = xstr8_to_16(value);
|
||||
if (entry->options) {
|
||||
char16_t *s = xpool_print(L"%s %s", entry->options, new);
|
||||
char16_t *s = xasprintf("%ls %ls", entry->options, new);
|
||||
free(entry->options);
|
||||
entry->options = s;
|
||||
} else
|
||||
@@ -1576,7 +1600,7 @@ static void config_load_defaults(Config *config, EFI_FILE *root_dir) {
|
||||
if (err == EFI_SUCCESS)
|
||||
config->timeout_sec = config->timeout_sec_efivar;
|
||||
else if (err != EFI_NOT_FOUND)
|
||||
log_error_stall(u"Error reading LoaderConfigTimeout EFI variable: %r", err);
|
||||
log_error_status(err, "Error reading LoaderConfigTimeout EFI variable: %m");
|
||||
|
||||
err = efivar_get_timeout(u"LoaderConfigTimeoutOneShot", &config->timeout_sec);
|
||||
if (err == EFI_SUCCESS) {
|
||||
@@ -1585,7 +1609,7 @@ static void config_load_defaults(Config *config, EFI_FILE *root_dir) {
|
||||
|
||||
config->force_menu = true; /* force the menu when this is set */
|
||||
} else if (err != EFI_NOT_FOUND)
|
||||
log_error_stall(u"Error reading LoaderConfigTimeoutOneShot EFI variable: %r", err);
|
||||
log_error_status(err, "Error reading LoaderConfigTimeoutOneShot EFI variable: %m");
|
||||
|
||||
err = efivar_get_uint_string(LOADER_GUID, L"LoaderConfigConsoleMode", &value);
|
||||
if (err == EFI_SUCCESS)
|
||||
@@ -1808,7 +1832,7 @@ static void config_title_generate(Config *config) {
|
||||
continue;
|
||||
|
||||
_cleanup_free_ char16_t *t = config->entries[i]->title_show;
|
||||
config->entries[i]->title_show = xpool_print(L"%s (%s)", t, config->entries[i]->version);
|
||||
config->entries[i]->title_show = xasprintf("%ls (%ls)", t, config->entries[i]->version);
|
||||
}
|
||||
|
||||
if (entries_unique(config->entries, unique, config->entry_count))
|
||||
@@ -1825,11 +1849,7 @@ static void config_title_generate(Config *config) {
|
||||
continue;
|
||||
|
||||
_cleanup_free_ char16_t *t = config->entries[i]->title_show;
|
||||
config->entries[i]->title_show = xpool_print(
|
||||
L"%s (%.*s)",
|
||||
t,
|
||||
strnlen16(config->entries[i]->machine_id, 8),
|
||||
config->entries[i]->machine_id);
|
||||
config->entries[i]->title_show = xasprintf("%ls (%.8ls)", t, config->entries[i]->machine_id);
|
||||
}
|
||||
|
||||
if (entries_unique(config->entries, unique, config->entry_count))
|
||||
@@ -1841,7 +1861,7 @@ static void config_title_generate(Config *config) {
|
||||
continue;
|
||||
|
||||
_cleanup_free_ char16_t *t = config->entries[i]->title_show;
|
||||
config->entries[i]->title_show = xpool_print(L"%s (%s)", t, config->entries[i]->id);
|
||||
config->entries[i]->title_show = xasprintf("%ls (%ls)", t, config->entries[i]->id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2006,10 +2026,9 @@ static EFI_STATUS boot_windows_bitlocker(void) {
|
||||
|
||||
for (UINTN i = 0; i < boot_order_size / sizeof(uint16_t); i++) {
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
char16_t name[sizeof(L"Boot0000")];
|
||||
UINTN buf_size;
|
||||
|
||||
SPrint(name, sizeof(name), L"Boot%04x", (uint32_t) boot_order[i]);
|
||||
_cleanup_free_ char16_t *name = xasprintf("Boot%04x", boot_order[i]);
|
||||
err = efivar_get_raw(EFI_GLOBAL_GUID, name, &buf, &buf_size);
|
||||
if (err != EFI_SUCCESS)
|
||||
continue;
|
||||
@@ -2202,7 +2221,7 @@ static void config_entry_add_unified(
|
||||
.title = xstrdup16(good_name),
|
||||
.version = xstrdup16(good_version),
|
||||
.device = device,
|
||||
.loader = xpool_print(L"\\EFI\\Linux\\%s", f->FileName),
|
||||
.loader = xasprintf("\\EFI\\Linux\\%ls", f->FileName),
|
||||
.sort_key = xstrdup16(good_sort_key),
|
||||
.key = 'l',
|
||||
.tries_done = -1,
|
||||
@@ -2281,9 +2300,9 @@ static EFI_STATUS initrd_prepare(
|
||||
STRV_FOREACH(i, entry->initrd) {
|
||||
_cleanup_free_ char16_t *o = options;
|
||||
if (o)
|
||||
options = xpool_print(L"%s initrd=%s", o, *i);
|
||||
options = xasprintf("%ls initrd=%ls", o, *i);
|
||||
else
|
||||
options = xpool_print(L"initrd=%s", *i);
|
||||
options = xasprintf("initrd=%ls", *i);
|
||||
|
||||
_cleanup_(file_closep) EFI_FILE *handle = NULL;
|
||||
err = root->Open(root, &handle, *i, EFI_FILE_MODE_READ, 0);
|
||||
@@ -2314,7 +2333,7 @@ static EFI_STATUS initrd_prepare(
|
||||
|
||||
if (entry->options) {
|
||||
_cleanup_free_ char16_t *o = options;
|
||||
options = xpool_print(L"%s %s", o, entry->options);
|
||||
options = xasprintf("%ls %ls", o, entry->options);
|
||||
}
|
||||
|
||||
*ret_options = TAKE_PTR(options);
|
||||
@@ -2341,38 +2360,38 @@ static EFI_STATUS image_start(
|
||||
_cleanup_(file_closep) EFI_FILE *image_root = NULL;
|
||||
err = open_volume(entry->device, &image_root);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Error opening root path: %r", err);
|
||||
return log_error_status(err, "Error opening root path: %m");
|
||||
|
||||
err = make_file_device_path(entry->device, entry->loader, &path);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Error making file device path: %r", err);
|
||||
return log_error_status(err, "Error making file device path: %m");
|
||||
|
||||
UINTN initrd_size = 0;
|
||||
_cleanup_free_ void *initrd = NULL;
|
||||
_cleanup_free_ char16_t *options_initrd = NULL;
|
||||
err = initrd_prepare(image_root, entry, &options_initrd, &initrd, &initrd_size);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Error preparing initrd: %r", err);
|
||||
return log_error_status(err, "Error preparing initrd: %m");
|
||||
|
||||
err = shim_load_image(parent_image, path, &image);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Error loading %s: %r", entry->loader, err);
|
||||
return log_error_status(err, "Error loading %ls: %m", entry->loader);
|
||||
|
||||
if (entry->devicetree) {
|
||||
err = devicetree_install(&dtstate, image_root, entry->devicetree);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Error loading %s: %r", entry->devicetree, err);
|
||||
return log_error_status(err, "Error loading %ls: %m", entry->devicetree);
|
||||
}
|
||||
|
||||
_cleanup_(cleanup_initrd) EFI_HANDLE initrd_handle = NULL;
|
||||
err = initrd_register(initrd, initrd_size, &initrd_handle);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Error registering initrd: %r", err);
|
||||
return log_error_status(err, "Error registering initrd: %m");
|
||||
|
||||
EFI_LOADED_IMAGE_PROTOCOL *loaded_image;
|
||||
err = BS->HandleProtocol(image, &LoadedImageProtocol, (void **) &loaded_image);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Error getting LoadedImageProtocol handle: %r", err);
|
||||
return log_error_status(err, "Error getting LoadedImageProtocol handle: %m");
|
||||
|
||||
char16_t *options = options_initrd ?: entry->options;
|
||||
if (options) {
|
||||
@@ -2396,7 +2415,7 @@ static EFI_STATUS image_start(
|
||||
err = pe_kernel_info(loaded_image->ImageBase, &compat_address);
|
||||
if (err != EFI_SUCCESS) {
|
||||
if (err != EFI_UNSUPPORTED)
|
||||
return log_error_status_stall(err, L"Error finding kernel compat entry address: %r", err);
|
||||
return log_error_status(err, "Error finding kernel compat entry address: %m");
|
||||
} else if (compat_address > 0) {
|
||||
EFI_IMAGE_ENTRY_POINT kernel_entry =
|
||||
(EFI_IMAGE_ENTRY_POINT) ((uint8_t *) loaded_image->ImageBase + compat_address);
|
||||
@@ -2409,7 +2428,7 @@ static EFI_STATUS image_start(
|
||||
err = EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
return log_error_status_stall(err, L"Failed to execute %s (%s): %r", entry->title_show, entry->loader, err);
|
||||
return log_error_status(err, "Failed to execute %ls (%ls): %m", entry->title_show, entry->loader);
|
||||
}
|
||||
|
||||
static void config_free(Config *config) {
|
||||
@@ -2496,9 +2515,9 @@ static EFI_STATUS secure_boot_discover_keys(Config *config, EFI_FILE *root_dir)
|
||||
|
||||
entry = xnew(ConfigEntry, 1);
|
||||
*entry = (ConfigEntry) {
|
||||
.id = xpool_print(L"secure-boot-keys-%s", dirent->FileName),
|
||||
.title = xpool_print(L"Enroll Secure Boot keys: %s", dirent->FileName),
|
||||
.path = xpool_print(L"\\loader\\keys\\%s", dirent->FileName),
|
||||
.id = xasprintf("secure-boot-keys-%ls", dirent->FileName),
|
||||
.title = xasprintf("Enroll Secure Boot keys: %ls", dirent->FileName),
|
||||
.path = xasprintf("\\loader\\keys\\%ls", dirent->FileName),
|
||||
.type = LOADER_SECURE_BOOT_KEYS,
|
||||
.tries_done = -1,
|
||||
.tries_left = -1,
|
||||
@@ -2541,10 +2560,10 @@ static void export_variables(
|
||||
efivar_set_time_usec(LOADER_GUID, L"LoaderTimeInitUSec", init_usec);
|
||||
efivar_set(LOADER_GUID, L"LoaderInfo", L"systemd-boot " GIT_VERSION, 0);
|
||||
|
||||
infostr = xpool_print(L"%s %u.%02u", ST->FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff);
|
||||
infostr = xasprintf("%ls %u.%02u", ST->FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff);
|
||||
efivar_set(LOADER_GUID, L"LoaderFirmwareInfo", infostr, 0);
|
||||
|
||||
typestr = xpool_print(L"UEFI %u.%02u", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
|
||||
typestr = xasprintf("UEFI %u.%02u", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
|
||||
efivar_set(LOADER_GUID, L"LoaderFirmwareType", typestr, 0);
|
||||
|
||||
(void) efivar_set_uint64_le(LOADER_GUID, L"LoaderFeatures", loader_features, 0);
|
||||
@@ -2626,7 +2645,7 @@ static EFI_STATUS discover_root_dir(EFI_LOADED_IMAGE_PROTOCOL *loaded_image, EFI
|
||||
return open_volume(loaded_image->DeviceHandle, ret_dir);
|
||||
}
|
||||
|
||||
EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
static EFI_STATUS real_main(EFI_HANDLE image) {
|
||||
EFI_LOADED_IMAGE_PROTOCOL *loaded_image;
|
||||
_cleanup_(file_closep) EFI_FILE *root_dir = NULL;
|
||||
_cleanup_(config_free) Config config = {};
|
||||
@@ -2635,11 +2654,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
uint64_t init_usec;
|
||||
bool menu = false;
|
||||
|
||||
InitializeLib(image, sys_table);
|
||||
init_usec = time_usec();
|
||||
debug_hook(L"systemd-boot");
|
||||
/* Uncomment the next line if you need to wait for debugger. */
|
||||
// debug_break();
|
||||
|
||||
err = BS->OpenProtocol(image,
|
||||
&LoadedImageProtocol,
|
||||
@@ -2648,7 +2663,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
NULL,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Error getting a LoadedImageProtocol handle: %r", err);
|
||||
return log_error_status(err, "Error getting a LoadedImageProtocol handle: %m");
|
||||
|
||||
(void) device_path_to_str(loaded_image->FilePath, &loaded_image_path);
|
||||
|
||||
@@ -2656,14 +2671,14 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
|
||||
err = discover_root_dir(loaded_image, &root_dir);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Unable to open root directory: %r", err);
|
||||
return log_error_status(err, "Unable to open root directory: %m");
|
||||
|
||||
(void) load_drivers(image, loaded_image, root_dir);
|
||||
|
||||
config_load_all_entries(&config, loaded_image, loaded_image_path, root_dir);
|
||||
|
||||
if (config.entry_count == 0) {
|
||||
log_error_stall(L"No loader found. Configuration files in \\loader\\entries\\*.conf are needed.");
|
||||
log_error("No loader found. Configuration files in \\loader\\entries\\*.conf are needed.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -2728,3 +2743,15 @@ out:
|
||||
BS->CloseProtocol(image, &LoadedImageProtocol, image, NULL);
|
||||
return err;
|
||||
}
|
||||
|
||||
EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
InitializeLib(image, sys_table);
|
||||
|
||||
debug_hook("systemd-boot");
|
||||
/* Uncomment the next line if you need to wait for debugger. */
|
||||
// debug_break();
|
||||
|
||||
EFI_STATUS err = real_main(image);
|
||||
log_wait();
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ EFI_STATUS console_key_read(uint64_t *key, uint64_t timeout_usec) {
|
||||
|
||||
err = BS->CreateEvent(EVT_TIMER, 0, NULL, NULL, &timer);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Error creating timer event: %r", err);
|
||||
return log_error_status(err, "Error creating timer event: %m");
|
||||
|
||||
EFI_EVENT events[] = {
|
||||
timer,
|
||||
@@ -88,14 +88,14 @@ EFI_STATUS console_key_read(uint64_t *key, uint64_t timeout_usec) {
|
||||
TimerRelative,
|
||||
MIN(timeout_usec, watchdog_ping_usec) * 10);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Error arming timer event: %r", err);
|
||||
return log_error_status(err, "Error arming timer event: %m");
|
||||
|
||||
(void) BS->SetWatchdogTimer(watchdog_timeout_sec, 0x10000, 0, NULL);
|
||||
err = BS->WaitForEvent(n_events, events, &index);
|
||||
(void) BS->SetWatchdogTimer(watchdog_timeout_sec, 0x10000, 0, NULL);
|
||||
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Error waiting for events: %r", err);
|
||||
return log_error_status(err, "Error waiting for events: %m");
|
||||
|
||||
/* We have keyboard input, process it after this loop. */
|
||||
if (timer != events[index])
|
||||
@@ -172,6 +172,7 @@ static EFI_STATUS change_mode(int64_t mode) {
|
||||
mode = CLAMP(mode, CONSOLE_MODE_RANGE_MIN, CONSOLE_MODE_RANGE_MAX);
|
||||
old_mode = MAX(CONSOLE_MODE_RANGE_MIN, ST->ConOut->Mode->Mode);
|
||||
|
||||
log_wait();
|
||||
err = ST->ConOut->SetMode(ST->ConOut, mode);
|
||||
if (err == EFI_SUCCESS)
|
||||
return EFI_SUCCESS;
|
||||
|
||||
+17
-20
@@ -318,7 +318,7 @@ static char16_t *get_dropin_dir(const EFI_DEVICE_PATH *file_path) {
|
||||
return NULL;
|
||||
|
||||
convert_efi_path(file_path_str);
|
||||
return xpool_print(u"%s.extra.d", file_path_str);
|
||||
return xasprintf("%ls.extra.d", file_path_str);
|
||||
}
|
||||
|
||||
EFI_STATUS pack_cpio(
|
||||
@@ -357,8 +357,7 @@ EFI_STATUS pack_cpio(
|
||||
* its file handles. */
|
||||
goto nothing;
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(
|
||||
err, L"Unable to open root directory: %r", err);
|
||||
return log_error_status(err, "Unable to open root directory: %m");
|
||||
|
||||
if (!dropin_dir)
|
||||
dropin_dir = rel_dropin_dir = get_dropin_dir(loaded_image->FilePath);
|
||||
@@ -368,14 +367,14 @@ EFI_STATUS pack_cpio(
|
||||
/* No extra subdir, that's totally OK */
|
||||
goto nothing;
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Failed to open extra directory of loaded image: %r", err);
|
||||
return log_error_status(err, "Failed to open extra directory of loaded image: %m");
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char16_t *d = NULL;
|
||||
|
||||
err = readdir_harder(extra_dir, &dirent, &dirent_size);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Failed to read extra directory of loaded image: %r", err);
|
||||
return log_error_status(err, "Failed to read extra directory of loaded image: %m");
|
||||
if (!dirent) /* End of directory */
|
||||
break;
|
||||
|
||||
@@ -420,7 +419,7 @@ EFI_STATUS pack_cpio(
|
||||
* archive. Otherwise the cpio archive cannot be unpacked, since the leading dirs won't exist. */
|
||||
err = pack_cpio_prefix(target_dir_prefix, dir_mode, &inode, &buffer, &buffer_size);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Failed to pack cpio prefix: %r", err);
|
||||
return log_error_status(err, "Failed to pack cpio prefix: %m");
|
||||
|
||||
for (UINTN i = 0; i < n_items; i++) {
|
||||
_cleanup_free_ char *content = NULL;
|
||||
@@ -428,7 +427,7 @@ EFI_STATUS pack_cpio(
|
||||
|
||||
err = file_read(extra_dir, items[i], 0, 0, &content, &contentsize);
|
||||
if (err != EFI_SUCCESS) {
|
||||
log_error_status_stall(err, L"Failed to read %s, ignoring: %r", items[i], err);
|
||||
log_error_status(err, "Failed to read %ls, ignoring: %m", items[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -440,22 +439,21 @@ EFI_STATUS pack_cpio(
|
||||
&inode,
|
||||
&buffer, &buffer_size);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Failed to pack cpio file %s: %r", dirent->FileName, err);
|
||||
return log_error_status(err, "Failed to pack cpio file %ls: %m", dirent->FileName);
|
||||
}
|
||||
|
||||
err = pack_cpio_trailer(&buffer, &buffer_size);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Failed to pack cpio trailer: %r");
|
||||
return log_error_status(err, "Failed to pack cpio trailer: %m");
|
||||
|
||||
err = tpm_log_event(
|
||||
tpm_pcr, POINTER_TO_PHYSICAL_ADDRESS(buffer), buffer_size, tpm_description, ret_measured);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(
|
||||
return log_error_status(
|
||||
err,
|
||||
L"Unable to add cpio TPM measurement for PCR %u (%s), ignoring: %r",
|
||||
"Unable to add cpio TPM measurement for PCR %u (%ls), ignoring: %m",
|
||||
tpm_pcr,
|
||||
tpm_description,
|
||||
err);
|
||||
tpm_description);
|
||||
|
||||
*ret_buffer = TAKE_PTR(buffer);
|
||||
*ret_buffer_size = buffer_size;
|
||||
@@ -501,7 +499,7 @@ EFI_STATUS pack_cpio_literal(
|
||||
|
||||
err = pack_cpio_prefix(target_dir_prefix, dir_mode, &inode, &buffer, &buffer_size);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Failed to pack cpio prefix: %r", err);
|
||||
return log_error_status(err, "Failed to pack cpio prefix: %m");
|
||||
|
||||
err = pack_cpio_one(
|
||||
target_filename,
|
||||
@@ -511,21 +509,20 @@ EFI_STATUS pack_cpio_literal(
|
||||
&inode,
|
||||
&buffer, &buffer_size);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Failed to pack cpio file %s: %r", target_filename, err);
|
||||
return log_error_status(err, "Failed to pack cpio file %ls: %m", target_filename);
|
||||
|
||||
err = pack_cpio_trailer(&buffer, &buffer_size);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Failed to pack cpio trailer: %r");
|
||||
return log_error_status(err, "Failed to pack cpio trailer: %m");
|
||||
|
||||
err = tpm_log_event(
|
||||
tpm_pcr, POINTER_TO_PHYSICAL_ADDRESS(buffer), buffer_size, tpm_description, ret_measured);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(
|
||||
return log_error_status(
|
||||
err,
|
||||
L"Unable to add cpio TPM measurement for PCR %u (%s), ignoring: %r",
|
||||
"Unable to add cpio TPM measurement for PCR %u (%ls), ignoring: %m",
|
||||
tpm_pcr,
|
||||
tpm_description,
|
||||
err);
|
||||
tpm_description);
|
||||
|
||||
*ret_buffer = TAKE_PTR(buffer);
|
||||
*ret_buffer_size = buffer_size;
|
||||
|
||||
@@ -36,8 +36,7 @@ static EFI_STATUS devicetree_fixup(struct devicetree_state *state, UINTN len) {
|
||||
|
||||
err = BS->LocateProtocol(&EfiDtFixupProtocol, NULL, (void **) &fixup);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(EFI_SUCCESS,
|
||||
L"Could not locate device tree fixup protocol, skipping.");
|
||||
return log_error_status(EFI_SUCCESS, "Could not locate device tree fixup protocol, skipping.");
|
||||
|
||||
size = devicetree_allocated(state);
|
||||
err = fixup->Fixup(fixup, PHYSICAL_ADDRESS_TO_POINTER(state->addr), &size,
|
||||
|
||||
@@ -20,29 +20,29 @@ static EFI_STATUS load_one_driver(
|
||||
assert(loaded_image);
|
||||
assert(fname);
|
||||
|
||||
spath = xpool_print(L"\\EFI\\systemd\\drivers\\%s", fname);
|
||||
spath = xasprintf("\\EFI\\systemd\\drivers\\%ls", fname);
|
||||
err = make_file_device_path(loaded_image->DeviceHandle, spath, &path);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Error making file device path: %r", err);
|
||||
return log_error_status(err, "Error making file device path: %m");
|
||||
|
||||
err = BS->LoadImage(false, parent_image, path, NULL, 0, &image);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Failed to load image %s: %r", fname, err);
|
||||
return log_error_status(err, "Failed to load image %ls: %m", fname);
|
||||
|
||||
err = BS->HandleProtocol(image, &LoadedImageProtocol, (void **)&loaded_image);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Failed to find protocol in driver image %s: %r", fname, err);
|
||||
return log_error_status(err, "Failed to find protocol in driver image %ls: %m", fname);
|
||||
|
||||
if (loaded_image->ImageCodeType != EfiBootServicesCode &&
|
||||
loaded_image->ImageCodeType != EfiRuntimeServicesCode)
|
||||
return log_error_status_stall(EFI_INVALID_PARAMETER, L"Image %s is not a driver, refusing.", fname);
|
||||
return log_error("Image %ls is not a driver, refusing.", fname);
|
||||
|
||||
err = BS->StartImage(image, NULL, NULL);
|
||||
if (err != EFI_SUCCESS) {
|
||||
/* EFI_ABORTED signals an initializing driver. It uses this error code on success
|
||||
* so that it is unloaded after. */
|
||||
if (err != EFI_ABORTED)
|
||||
log_error_stall(L"Failed to start image %s: %r", fname, err);
|
||||
log_error_status(err, "Failed to start image %ls: %m", fname);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ EFI_STATUS reconnect_all_drivers(void) {
|
||||
|
||||
err = BS->LocateHandleBuffer(AllHandles, NULL, NULL, &n_handles, &handles);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Failed to get list of handles: %r", err);
|
||||
return log_error_status(err, "Failed to get list of handles: %m");
|
||||
|
||||
for (size_t i = 0; i < n_handles; i++)
|
||||
/* Some firmware gives us some bogus handles (or they might become bad due to
|
||||
@@ -87,12 +87,12 @@ EFI_STATUS load_drivers(
|
||||
if (err == EFI_NOT_FOUND)
|
||||
return EFI_SUCCESS;
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Failed to open \\EFI\\systemd\\drivers: %r", err);
|
||||
return log_error_status(err, "Failed to open \\EFI\\systemd\\drivers: %m");
|
||||
|
||||
for (;;) {
|
||||
err = readdir_harder(drivers_dir, &dirent, &dirent_size);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Failed to read extra directory of loaded image: %r", err);
|
||||
return log_error_status(err, "Failed to read extra directory of loaded image: %m");
|
||||
if (!dirent) /* End of directory */
|
||||
break;
|
||||
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "efi-string.h"
|
||||
|
||||
#if SD_BOOT
|
||||
# include "missing_efi.h"
|
||||
# include "util.h"
|
||||
#else
|
||||
# include <stdlib.h>
|
||||
@@ -378,6 +380,495 @@ bool efi_fnmatch(const char16_t *pattern, const char16_t *haystack) {
|
||||
DEFINE_PARSE_NUMBER(char, parse_number8);
|
||||
DEFINE_PARSE_NUMBER(char16_t, parse_number16);
|
||||
|
||||
static const char * const warn_table[] = {
|
||||
[EFI_SUCCESS] = "Success",
|
||||
#if SD_BOOT
|
||||
[EFI_WARN_UNKNOWN_GLYPH] = "Unknown glyph",
|
||||
[EFI_WARN_DELETE_FAILURE] = "Delete failure",
|
||||
[EFI_WARN_WRITE_FAILURE] = "Write failure",
|
||||
[EFI_WARN_BUFFER_TOO_SMALL] = "Buffer too small",
|
||||
[EFI_WARN_STALE_DATA] = "Stale data",
|
||||
[EFI_WARN_FILE_SYSTEM] = "File system",
|
||||
[EFI_WARN_RESET_REQUIRED] = "Reset required",
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Errors have MSB set, remove it to keep the table compact. */
|
||||
#define NOERR(err) ((err) & ~EFI_ERROR_MASK)
|
||||
|
||||
static const char * const err_table[] = {
|
||||
[NOERR(EFI_ERROR_MASK)] = "Error",
|
||||
[NOERR(EFI_LOAD_ERROR)] = "Load error",
|
||||
#if SD_BOOT
|
||||
[NOERR(EFI_INVALID_PARAMETER)] = "Invalid parameter",
|
||||
[NOERR(EFI_UNSUPPORTED)] = "Unsupported",
|
||||
[NOERR(EFI_BAD_BUFFER_SIZE)] = "Bad buffer size",
|
||||
[NOERR(EFI_BUFFER_TOO_SMALL)] = "Buffer too small",
|
||||
[NOERR(EFI_NOT_READY)] = "Not ready",
|
||||
[NOERR(EFI_DEVICE_ERROR)] = "Device error",
|
||||
[NOERR(EFI_WRITE_PROTECTED)] = "Write protected",
|
||||
[NOERR(EFI_OUT_OF_RESOURCES)] = "Out of resources",
|
||||
[NOERR(EFI_VOLUME_CORRUPTED)] = "Volume corrupt",
|
||||
[NOERR(EFI_VOLUME_FULL)] = "Volume full",
|
||||
[NOERR(EFI_NO_MEDIA)] = "No media",
|
||||
[NOERR(EFI_MEDIA_CHANGED)] = "Media changed",
|
||||
[NOERR(EFI_NOT_FOUND)] = "Not found",
|
||||
[NOERR(EFI_ACCESS_DENIED)] = "Access denied",
|
||||
[NOERR(EFI_NO_RESPONSE)] = "No response",
|
||||
[NOERR(EFI_NO_MAPPING)] = "No mapping",
|
||||
[NOERR(EFI_TIMEOUT)] = "Time out",
|
||||
[NOERR(EFI_NOT_STARTED)] = "Not started",
|
||||
[NOERR(EFI_ALREADY_STARTED)] = "Already started",
|
||||
[NOERR(EFI_ABORTED)] = "Aborted",
|
||||
[NOERR(EFI_ICMP_ERROR)] = "ICMP error",
|
||||
[NOERR(EFI_TFTP_ERROR)] = "TFTP error",
|
||||
[NOERR(EFI_PROTOCOL_ERROR)] = "Protocol error",
|
||||
[NOERR(EFI_INCOMPATIBLE_VERSION)] = "Incompatible version",
|
||||
[NOERR(EFI_SECURITY_VIOLATION)] = "Security violation",
|
||||
[NOERR(EFI_CRC_ERROR)] = "CRC error",
|
||||
[NOERR(EFI_END_OF_MEDIA)] = "End of media",
|
||||
[29] = "Reserved (29)",
|
||||
[30] = "Reserved (30)",
|
||||
[NOERR(EFI_END_OF_FILE)] = "End of file",
|
||||
[NOERR(EFI_INVALID_LANGUAGE)] = "Invalid language",
|
||||
[NOERR(EFI_COMPROMISED_DATA)] = "Compromised data",
|
||||
[NOERR(EFI_IP_ADDRESS_CONFLICT)] = "IP address conflict",
|
||||
[NOERR(EFI_HTTP_ERROR)] = "HTTP error",
|
||||
#endif
|
||||
};
|
||||
|
||||
static const char *status_to_string(EFI_STATUS status) {
|
||||
if (status <= ELEMENTSOF(warn_table) - 1)
|
||||
return warn_table[status];
|
||||
if (status >= EFI_ERROR_MASK && status <= ((ELEMENTSOF(err_table) - 1) | EFI_ERROR_MASK))
|
||||
return err_table[NOERR(status)];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
size_t padded_len; /* Field width in printf. */
|
||||
size_t len; /* Precision in printf. */
|
||||
bool pad_zero;
|
||||
bool align_left;
|
||||
bool alternative_form;
|
||||
bool long_arg;
|
||||
bool longlong_arg;
|
||||
bool have_field_width;
|
||||
|
||||
const char *str;
|
||||
const wchar_t *wstr;
|
||||
|
||||
/* For numbers. */
|
||||
bool is_signed;
|
||||
bool lowercase;
|
||||
int8_t base;
|
||||
char sign_pad; /* For + and (space) flags. */
|
||||
} SpecifierContext;
|
||||
|
||||
typedef struct {
|
||||
char16_t stack_buf[128]; /* We use stack_buf first to avoid allocations in most cases. */
|
||||
char16_t *dyn_buf; /* Allocated buf or NULL if stack_buf is used. */
|
||||
char16_t *buf; /* Points to the current active buf. */
|
||||
size_t n_buf; /* Len of buf (in char16_t's, not bytes!). */
|
||||
size_t n; /* Used len of buf (in char16_t's). This is always <n_buf. */
|
||||
|
||||
EFI_STATUS status;
|
||||
const char *format;
|
||||
va_list ap;
|
||||
} FormatContext;
|
||||
|
||||
static void grow_buf(FormatContext *ctx, size_t need) {
|
||||
assert(ctx);
|
||||
|
||||
assert_se(!__builtin_add_overflow(ctx->n, need, &need));
|
||||
|
||||
if (need < ctx->n_buf)
|
||||
return;
|
||||
|
||||
/* Greedily allocate if we can. */
|
||||
if (__builtin_mul_overflow(need, 2, &ctx->n_buf))
|
||||
ctx->n_buf = need;
|
||||
|
||||
/* We cannot use realloc here as ctx->buf may be ctx->stack_buf, which we cannot free. */
|
||||
char16_t *new_buf = xnew(char16_t, ctx->n_buf);
|
||||
memcpy(new_buf, ctx->buf, ctx->n * sizeof(*ctx->buf));
|
||||
|
||||
free(ctx->dyn_buf);
|
||||
ctx->buf = ctx->dyn_buf = new_buf;
|
||||
}
|
||||
|
||||
static void push_padding(FormatContext *ctx, char pad, size_t len) {
|
||||
assert(ctx);
|
||||
while (len > 0) {
|
||||
len--;
|
||||
ctx->buf[ctx->n++] = pad;
|
||||
}
|
||||
}
|
||||
|
||||
static bool push_str(FormatContext *ctx, SpecifierContext *sp) {
|
||||
assert(ctx);
|
||||
assert(sp);
|
||||
|
||||
sp->padded_len = LESS_BY(sp->padded_len, sp->len);
|
||||
|
||||
grow_buf(ctx, sp->padded_len + sp->len);
|
||||
|
||||
if (!sp->align_left)
|
||||
push_padding(ctx, ' ', sp->padded_len);
|
||||
|
||||
/* In userspace unit tests we cannot just memcpy() the wide string. */
|
||||
if (sp->wstr && sizeof(wchar_t) == sizeof(char16_t)) {
|
||||
memcpy(ctx->buf + ctx->n, sp->wstr, sp->len * sizeof(*sp->wstr));
|
||||
ctx->n += sp->len;
|
||||
} else
|
||||
for (size_t i = 0; i < sp->len; i++)
|
||||
ctx->buf[ctx->n++] = sp->str ? sp->str[i] : sp->wstr[i];
|
||||
|
||||
if (sp->align_left)
|
||||
push_padding(ctx, ' ', sp->padded_len);
|
||||
|
||||
assert(ctx->n < ctx->n_buf);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool push_num(FormatContext *ctx, SpecifierContext *sp, uint64_t u) {
|
||||
const char *digits = sp->lowercase ? "0123456789abcdef" : "0123456789ABCDEF";
|
||||
char16_t tmp[32];
|
||||
size_t n = 0;
|
||||
|
||||
assert(ctx);
|
||||
assert(sp);
|
||||
assert(IN_SET(sp->base, 10, 16));
|
||||
|
||||
/* "%.0u" prints nothing if value is 0. */
|
||||
if (u == 0 && sp->len == 0)
|
||||
return true;
|
||||
|
||||
if (sp->is_signed && (int64_t) u < 0) {
|
||||
/* We cannot just do "u = -(int64_t)u" here because -INT64_MIN overflows. */
|
||||
|
||||
uint64_t rem = -((int64_t) u % sp->base);
|
||||
u = (int64_t) u / -sp->base;
|
||||
tmp[n++] = digits[rem];
|
||||
sp->sign_pad = '-';
|
||||
}
|
||||
|
||||
while (u > 0 || n == 0) {
|
||||
uint64_t rem = u % sp->base;
|
||||
u /= sp->base;
|
||||
tmp[n++] = digits[rem];
|
||||
}
|
||||
|
||||
/* Note that numbers never get truncated! */
|
||||
size_t prefix = (sp->sign_pad != 0 ? 1 : 0) + (sp->alternative_form ? 2 : 0);
|
||||
size_t number_len = prefix + MAX(n, sp->len);
|
||||
grow_buf(ctx, MAX(sp->padded_len, number_len));
|
||||
|
||||
size_t padding = 0;
|
||||
if (sp->pad_zero)
|
||||
/* Leading zeroes go after the sign or 0x prefix. */
|
||||
number_len = MAX(number_len, sp->padded_len);
|
||||
else
|
||||
padding = LESS_BY(sp->padded_len, number_len);
|
||||
|
||||
if (!sp->align_left)
|
||||
push_padding(ctx, ' ', padding);
|
||||
|
||||
if (sp->sign_pad != 0)
|
||||
ctx->buf[ctx->n++] = sp->sign_pad;
|
||||
if (sp->alternative_form) {
|
||||
ctx->buf[ctx->n++] = '0';
|
||||
ctx->buf[ctx->n++] = sp->lowercase ? 'x' : 'X';
|
||||
}
|
||||
|
||||
push_padding(ctx, '0', LESS_BY(number_len, n + prefix));
|
||||
|
||||
while (n > 0)
|
||||
ctx->buf[ctx->n++] = tmp[--n];
|
||||
|
||||
if (sp->align_left)
|
||||
push_padding(ctx, ' ', padding);
|
||||
|
||||
assert(ctx->n < ctx->n_buf);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* This helps unit testing. */
|
||||
#if SD_BOOT
|
||||
# define NULLSTR "(null)"
|
||||
# define wcsnlen strnlen16
|
||||
#else
|
||||
# define NULLSTR "(nil)"
|
||||
#endif
|
||||
|
||||
static bool handle_format_specifier(FormatContext *ctx, SpecifierContext *sp) {
|
||||
/* Parses one item from the format specifier in ctx and put the info into sp. If we are done with
|
||||
* this specifier returns true, otherwise this function should be called again. */
|
||||
|
||||
/* This implementation assumes 32bit ints. Also note that all types smaller than int are promoted to
|
||||
* int in vararg functions, which is why we fetch only ints for any such types. The compiler would
|
||||
* otherwise warn about fetching smaller types. */
|
||||
assert_cc(sizeof(int) == 4);
|
||||
assert_cc(sizeof(wchar_t) <= sizeof(int));
|
||||
assert_cc(sizeof(intmax_t) <= sizeof(long long));
|
||||
|
||||
assert(ctx);
|
||||
assert(sp);
|
||||
|
||||
switch (*ctx->format) {
|
||||
case '#':
|
||||
sp->alternative_form = true;
|
||||
return false;
|
||||
case '.':
|
||||
sp->have_field_width = true;
|
||||
return false;
|
||||
case '-':
|
||||
sp->align_left = true;
|
||||
return false;
|
||||
case '+':
|
||||
case ' ':
|
||||
sp->sign_pad = *ctx->format;
|
||||
return false;
|
||||
|
||||
case '0':
|
||||
if (!sp->have_field_width) {
|
||||
sp->pad_zero = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* If field width has already been provided then 0 is part of precision (%.0s). */
|
||||
_fallthrough_;
|
||||
|
||||
case '*':
|
||||
case '1' ... '9': {
|
||||
int64_t i;
|
||||
|
||||
if (*ctx->format == '*')
|
||||
i = va_arg(ctx->ap, int);
|
||||
else {
|
||||
uint64_t u;
|
||||
if (!parse_number8(ctx->format, &u, &ctx->format) || u > INT_MAX)
|
||||
assert_not_reached();
|
||||
ctx->format--; /* Point it back to the last digit. */
|
||||
i = u;
|
||||
}
|
||||
|
||||
if (sp->have_field_width) {
|
||||
/* Negative precision is ignored. */
|
||||
if (i >= 0)
|
||||
sp->len = (size_t) i;
|
||||
} else {
|
||||
/* Negative field width is treated as positive field width with '-' flag. */
|
||||
if (i < 0) {
|
||||
i *= -1;
|
||||
sp->align_left = true;
|
||||
}
|
||||
sp->padded_len = i;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
case 'h':
|
||||
if (*(ctx->format + 1) == 'h')
|
||||
ctx->format++;
|
||||
/* char/short gets promoted to int, nothing to do here. */
|
||||
return false;
|
||||
|
||||
case 'l':
|
||||
if (*(ctx->format + 1) == 'l') {
|
||||
ctx->format++;
|
||||
sp->longlong_arg = true;
|
||||
} else
|
||||
sp->long_arg = true;
|
||||
return false;
|
||||
|
||||
case 'z':
|
||||
sp->long_arg = sizeof(size_t) == sizeof(long);
|
||||
sp->longlong_arg = !sp->long_arg && sizeof(size_t) == sizeof(long long);
|
||||
return false;
|
||||
|
||||
case 'j':
|
||||
sp->long_arg = sizeof(intmax_t) == sizeof(long);
|
||||
sp->longlong_arg = !sp->long_arg && sizeof(intmax_t) == sizeof(long long);
|
||||
return false;
|
||||
|
||||
case 't':
|
||||
sp->long_arg = sizeof(ptrdiff_t) == sizeof(long);
|
||||
sp->longlong_arg = !sp->long_arg && sizeof(ptrdiff_t) == sizeof(long long);
|
||||
return false;
|
||||
|
||||
case '%':
|
||||
sp->str = "%";
|
||||
sp->len = 1;
|
||||
return push_str(ctx, sp);
|
||||
|
||||
case 'c':
|
||||
sp->wstr = &(wchar_t){ va_arg(ctx->ap, int) };
|
||||
sp->len = 1;
|
||||
return push_str(ctx, sp);
|
||||
|
||||
case 's':
|
||||
if (sp->long_arg) {
|
||||
sp->wstr = va_arg(ctx->ap, const wchar_t *) ?: L"(null)";
|
||||
sp->len = wcsnlen(sp->wstr, sp->len);
|
||||
} else {
|
||||
sp->str = va_arg(ctx->ap, const char *) ?: "(null)";
|
||||
sp->len = strnlen8(sp->str, sp->len);
|
||||
}
|
||||
return push_str(ctx, sp);
|
||||
|
||||
case 'd':
|
||||
case 'i':
|
||||
case 'u':
|
||||
case 'x':
|
||||
case 'X':
|
||||
sp->lowercase = *ctx->format == 'x';
|
||||
sp->is_signed = IN_SET(*ctx->format, 'd', 'i');
|
||||
sp->base = IN_SET(*ctx->format, 'x', 'X') ? 16 : 10;
|
||||
if (sp->len == SIZE_MAX)
|
||||
sp->len = 1;
|
||||
|
||||
uint64_t v;
|
||||
if (sp->longlong_arg)
|
||||
v = sp->is_signed ? (uint64_t) va_arg(ctx->ap, long long) :
|
||||
va_arg(ctx->ap, unsigned long long);
|
||||
else if (sp->long_arg)
|
||||
v = sp->is_signed ? (uint64_t) va_arg(ctx->ap, long) : va_arg(ctx->ap, unsigned long);
|
||||
else
|
||||
v = sp->is_signed ? (uint64_t) va_arg(ctx->ap, int) : va_arg(ctx->ap, unsigned);
|
||||
|
||||
return push_num(ctx, sp, v);
|
||||
|
||||
case 'p': {
|
||||
const void *ptr = va_arg(ctx->ap, const void *);
|
||||
if (!ptr) {
|
||||
sp->str = NULLSTR;
|
||||
sp->len = STRLEN(NULLSTR);
|
||||
return push_str(ctx, sp);
|
||||
}
|
||||
|
||||
sp->base = 16;
|
||||
sp->lowercase = true;
|
||||
sp->alternative_form = true;
|
||||
sp->len = 0; /* Precision is ignored for %p. */
|
||||
return push_num(ctx, sp, (uintptr_t) ptr);
|
||||
}
|
||||
|
||||
case 'm': {
|
||||
sp->str = status_to_string(ctx->status);
|
||||
if (sp->str) {
|
||||
sp->len = strlen8(sp->str);
|
||||
return push_str(ctx, sp);
|
||||
}
|
||||
|
||||
sp->base = 16;
|
||||
sp->lowercase = true;
|
||||
sp->alternative_form = true;
|
||||
sp->len = 0;
|
||||
return push_num(ctx, sp, ctx->status);
|
||||
}
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
/* printf_internal is largely compatible to userspace vasprintf. Any features omitted should trigger asserts.
|
||||
*
|
||||
* Supported:
|
||||
* - Flags: #, 0, +, -, space
|
||||
* - Lengths: h, hh, l, ll, z, j, t
|
||||
* - Specifiers: %, c, s, u, i, d, x, X, p, m
|
||||
* - Precision and width (inline or as int arg using *)
|
||||
*
|
||||
* Notable differences:
|
||||
* - Passing NULL to %s is permitted and will print "(null)"
|
||||
* - %p will also use "(null)"
|
||||
* - The provided EFI_STATUS is used for %m instead of errno
|
||||
* - "\n" is translated to "\r\n" */
|
||||
_printf_(2, 0) static char16_t *printf_internal(EFI_STATUS status, const char *format, va_list ap, bool ret) {
|
||||
assert(format);
|
||||
|
||||
FormatContext ctx = {
|
||||
.buf = ctx.stack_buf,
|
||||
.n_buf = ELEMENTSOF(ctx.stack_buf),
|
||||
.format = format,
|
||||
.status = status,
|
||||
};
|
||||
|
||||
/* We cannot put this into the struct without making a copy. */
|
||||
va_copy(ctx.ap, ap);
|
||||
|
||||
while (*ctx.format != '\0') {
|
||||
SpecifierContext sp = { .len = SIZE_MAX };
|
||||
|
||||
switch (*ctx.format) {
|
||||
case '%':
|
||||
ctx.format++;
|
||||
while (!handle_format_specifier(&ctx, &sp))
|
||||
ctx.format++;
|
||||
ctx.format++;
|
||||
break;
|
||||
case '\n':
|
||||
ctx.format++;
|
||||
sp.str = "\r\n";
|
||||
sp.len = 2;
|
||||
push_str(&ctx, &sp);
|
||||
break;
|
||||
default:
|
||||
sp.str = ctx.format++;
|
||||
while (!IN_SET(*ctx.format, '%', '\n', '\0'))
|
||||
ctx.format++;
|
||||
sp.len = ctx.format - sp.str;
|
||||
push_str(&ctx, &sp);
|
||||
}
|
||||
}
|
||||
|
||||
va_end(ctx.ap);
|
||||
|
||||
assert(ctx.n < ctx.n_buf);
|
||||
ctx.buf[ctx.n++] = '\0';
|
||||
|
||||
if (ret) {
|
||||
if (ctx.dyn_buf)
|
||||
return TAKE_PTR(ctx.dyn_buf);
|
||||
|
||||
char16_t *ret_buf = xnew(char16_t, ctx.n);
|
||||
memcpy(ret_buf, ctx.buf, ctx.n * sizeof(*ctx.buf));
|
||||
return ret_buf;
|
||||
}
|
||||
|
||||
#if SD_BOOT
|
||||
ST->ConOut->OutputString(ST->ConOut, ctx.buf);
|
||||
#endif
|
||||
|
||||
return mfree(ctx.dyn_buf);
|
||||
}
|
||||
|
||||
void printf_status(EFI_STATUS status, const char *format, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
printf_internal(status, format, ap, false);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void vprintf_status(EFI_STATUS status, const char *format, va_list ap) {
|
||||
printf_internal(status, format, ap, false);
|
||||
}
|
||||
|
||||
char16_t *xasprintf_status(EFI_STATUS status, const char *format, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
char16_t *ret = printf_internal(status, format, ap, true);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
char16_t *xvasprintf_status(EFI_STATUS status, const char *format, va_list ap) {
|
||||
return printf_internal(status, format, ap, true);
|
||||
}
|
||||
|
||||
#if SD_BOOT
|
||||
/* To provide the actual implementation for these we need to remove the redirection to the builtins. */
|
||||
# undef memcmp
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <uchar.h>
|
||||
@@ -109,7 +110,32 @@ bool efi_fnmatch(const char16_t *pattern, const char16_t *haystack);
|
||||
bool parse_number8(const char *s, uint64_t *ret_u, const char **ret_tail);
|
||||
bool parse_number16(const char16_t *s, uint64_t *ret_u, const char16_t **ret_tail);
|
||||
|
||||
typedef size_t EFI_STATUS;
|
||||
|
||||
#if !SD_BOOT
|
||||
/* Provide these for unit testing. */
|
||||
enum {
|
||||
EFI_ERROR_MASK = ((EFI_STATUS) 1 << (sizeof(EFI_STATUS) * CHAR_BIT - 1)),
|
||||
EFI_SUCCESS = 0,
|
||||
EFI_LOAD_ERROR = 1 | EFI_ERROR_MASK,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
# define _gnu_printf_(a, b) _printf_(a, b)
|
||||
#else
|
||||
# define _gnu_printf_(a, b) __attribute__((format(gnu_printf, a, b)))
|
||||
#endif
|
||||
|
||||
_gnu_printf_(2, 3) void printf_status(EFI_STATUS status, const char *format, ...);
|
||||
_gnu_printf_(2, 0) void vprintf_status(EFI_STATUS status, const char *format, va_list ap);
|
||||
_gnu_printf_(2, 3) _warn_unused_result_ char16_t *xasprintf_status(EFI_STATUS status, const char *format, ...);
|
||||
_gnu_printf_(2, 0) _warn_unused_result_ char16_t *xvasprintf_status(EFI_STATUS status, const char *format, va_list ap);
|
||||
|
||||
#if SD_BOOT
|
||||
# define printf(...) printf_status(EFI_SUCCESS, __VA_ARGS__)
|
||||
# define xasprintf(...) xasprintf_status(EFI_SUCCESS, __VA_ARGS__)
|
||||
|
||||
/* The compiler normally has knowledge about standard functions such as memcmp, but this is not the case when
|
||||
* compiling with -ffreestanding. By referring to builtins, the compiler can check arguments and do
|
||||
* optimizations again. Note that we still need to provide implementations as the compiler is free to not
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "efi-string.h"
|
||||
#include "fuzz.h"
|
||||
#include "utf8.h"
|
||||
|
||||
typedef struct {
|
||||
EFI_STATUS status;
|
||||
int16_t field_width;
|
||||
int16_t precision;
|
||||
const void *ptr;
|
||||
char c;
|
||||
unsigned char uchar;
|
||||
signed char schar;
|
||||
unsigned short ushort;
|
||||
signed short sshort;
|
||||
unsigned int uint;
|
||||
signed int sint;
|
||||
unsigned long ulong;
|
||||
signed long slong;
|
||||
unsigned long long ulonglong;
|
||||
signed long long slonglong;
|
||||
size_t size;
|
||||
ssize_t ssize;
|
||||
intmax_t intmax;
|
||||
uintmax_t uintmax;
|
||||
ptrdiff_t ptrdiff;
|
||||
char str[];
|
||||
} Input;
|
||||
|
||||
#define PRINTF_ONE(...) \
|
||||
({ \
|
||||
_cleanup_free_ char16_t *_ret = xasprintf_status(__VA_ARGS__); \
|
||||
DO_NOT_OPTIMIZE(_ret); \
|
||||
})
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
if (outside_size_range(size, sizeof(Input), 1024 * 1024))
|
||||
return 0;
|
||||
|
||||
const Input *i = (const Input *) data;
|
||||
size_t len = size - offsetof(Input, str);
|
||||
|
||||
PRINTF_ONE(i->status, "%*.*s", i->field_width, (int) len, i->str);
|
||||
PRINTF_ONE(i->status, "%*.*ls", i->field_width, (int) (len / sizeof(wchar_t)), (const wchar_t *) i->str);
|
||||
|
||||
PRINTF_ONE(i->status, "%% %*.*m", i->field_width, i->precision);
|
||||
PRINTF_ONE(i->status, "%*p", i->field_width, i->ptr);
|
||||
PRINTF_ONE(i->status, "%*c %12340c %56789c", i->field_width, i->c, i->c, i->c);
|
||||
|
||||
PRINTF_ONE(i->status, "%*.*hhu", i->field_width, i->precision, i->uchar);
|
||||
PRINTF_ONE(i->status, "%*.*hhi", i->field_width, i->precision, i->schar);
|
||||
PRINTF_ONE(i->status, "%*.*hu", i->field_width, i->precision, i->ushort);
|
||||
PRINTF_ONE(i->status, "%*.*hi", i->field_width, i->precision, i->sshort);
|
||||
PRINTF_ONE(i->status, "%*.*u", i->field_width, i->precision, i->uint);
|
||||
PRINTF_ONE(i->status, "%*.*i", i->field_width, i->precision, i->sint);
|
||||
PRINTF_ONE(i->status, "%*.*lu", i->field_width, i->precision, i->ulong);
|
||||
PRINTF_ONE(i->status, "%*.*li", i->field_width, i->precision, i->slong);
|
||||
PRINTF_ONE(i->status, "%*.*llu", i->field_width, i->precision, i->ulonglong);
|
||||
PRINTF_ONE(i->status, "%*.*lli", i->field_width, i->precision, i->slonglong);
|
||||
|
||||
PRINTF_ONE(i->status, "%+*.*hhi", i->field_width, i->precision, i->schar);
|
||||
PRINTF_ONE(i->status, "%-*.*hi", i->field_width, i->precision, i->sshort);
|
||||
PRINTF_ONE(i->status, "% *.*i", i->field_width, i->precision, i->sint);
|
||||
PRINTF_ONE(i->status, "%0*li", i->field_width, i->slong);
|
||||
PRINTF_ONE(i->status, "%#*.*llx", i->field_width, i->precision, i->ulonglong);
|
||||
|
||||
PRINTF_ONE(i->status, "%-*.*zx", i->field_width, i->precision, i->size);
|
||||
PRINTF_ONE(i->status, "% *.*zi", i->field_width, i->precision, i->ssize);
|
||||
PRINTF_ONE(i->status, "%0*ji", i->field_width, i->intmax);
|
||||
PRINTF_ONE(i->status, "%#0*jX", i->field_width, i->uintmax);
|
||||
PRINTF_ONE(i->status, "%*.*ti", i->field_width, i->precision, i->ptrdiff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -25,16 +25,17 @@ EFI_STATUS graphics_mode(bool on) {
|
||||
return err == EFI_NOT_FOUND ? EFI_SUCCESS : err;
|
||||
|
||||
/* check current mode */
|
||||
err =ConsoleControl->GetMode(ConsoleControl, ¤t, &uga_exists, &stdin_locked);
|
||||
err = ConsoleControl->GetMode(ConsoleControl, ¤t, &uga_exists, &stdin_locked);
|
||||
if (err != EFI_SUCCESS)
|
||||
return err;
|
||||
|
||||
/* do not touch the mode */
|
||||
new = on ? EfiConsoleControlScreenGraphics : EfiConsoleControlScreenText;
|
||||
new = on ? EfiConsoleControlScreenGraphics : EfiConsoleControlScreenText;
|
||||
if (new == current)
|
||||
return EFI_SUCCESS;
|
||||
|
||||
err =ConsoleControl->SetMode(ConsoleControl, new);
|
||||
log_wait();
|
||||
err = ConsoleControl->SetMode(ConsoleControl, new);
|
||||
|
||||
/* some firmware enables the cursor when switching modes */
|
||||
ST->ConOut->EnableCursor(ST->ConOut, false);
|
||||
|
||||
@@ -120,17 +120,17 @@ EFI_STATUS linux_exec(
|
||||
initrd_length);
|
||||
#endif
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, u"Bad kernel image: %r", err);
|
||||
return log_error_status(err, "Bad kernel image: %m");
|
||||
|
||||
_cleanup_(unload_imagep) EFI_HANDLE kernel_image = NULL;
|
||||
err = load_image(parent, linux_buffer, linux_length, &kernel_image);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, u"Error loading kernel image: %r", err);
|
||||
return log_error_status(err, "Error loading kernel image: %m");
|
||||
|
||||
EFI_LOADED_IMAGE_PROTOCOL *loaded_image;
|
||||
err = BS->HandleProtocol(kernel_image, &LoadedImageProtocol, (void **) &loaded_image);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, u"Error getting kernel loaded image protocol: %r", err);
|
||||
return log_error_status(err, "Error getting kernel loaded image protocol: %m");
|
||||
|
||||
if (cmdline) {
|
||||
loaded_image->LoadOptions = (void *) cmdline;
|
||||
@@ -140,8 +140,9 @@ EFI_STATUS linux_exec(
|
||||
_cleanup_(cleanup_initrd) EFI_HANDLE initrd_handle = NULL;
|
||||
err = initrd_register(initrd_buffer, initrd_length, &initrd_handle);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, u"Error registering initrd: %r", err);
|
||||
return log_error_status(err, "Error registering initrd: %m");
|
||||
|
||||
log_wait();
|
||||
err = BS->StartImage(kernel_image, NULL, NULL);
|
||||
|
||||
/* Try calling the kernel compat entry point if one exists. */
|
||||
@@ -151,5 +152,5 @@ EFI_STATUS linux_exec(
|
||||
err = compat_entry(kernel_image, ST);
|
||||
}
|
||||
|
||||
return log_error_status_stall(err, u"Error starting kernel image: %r", err);
|
||||
return log_error_status(err, "Error starting kernel image: %m");
|
||||
}
|
||||
|
||||
@@ -141,28 +141,27 @@ EFI_STATUS linux_exec_efi_handover(
|
||||
|
||||
const BootParams *image_params = (const BootParams *) linux_buffer;
|
||||
if (image_params->hdr.header != SETUP_MAGIC || image_params->hdr.boot_flag != BOOT_FLAG_MAGIC)
|
||||
return log_error_status_stall(EFI_UNSUPPORTED, u"Unsupported kernel image.");
|
||||
return log_error_status(EFI_UNSUPPORTED, "Unsupported kernel image.");
|
||||
if (image_params->hdr.version < SETUP_VERSION_2_11)
|
||||
return log_error_status_stall(EFI_UNSUPPORTED, u"Kernel too old.");
|
||||
return log_error_status(EFI_UNSUPPORTED, "Kernel too old.");
|
||||
if (!image_params->hdr.relocatable_kernel)
|
||||
return log_error_status_stall(EFI_UNSUPPORTED, u"Kernel is not relocatable.");
|
||||
return log_error_status(EFI_UNSUPPORTED, "Kernel is not relocatable.");
|
||||
|
||||
/* The xloadflags were added in version 2.12+ of the boot protocol but the handover support predates
|
||||
* that, so we cannot safety-check this for 2.11. */
|
||||
if (image_params->hdr.version >= SETUP_VERSION_2_12 &&
|
||||
!FLAGS_SET(image_params->hdr.xloadflags, XLF_EFI_HANDOVER))
|
||||
return log_error_status_stall(EFI_UNSUPPORTED, u"Kernel does not support EFI handover protocol.");
|
||||
return log_error_status(EFI_UNSUPPORTED, "Kernel does not support EFI handover protocol.");
|
||||
|
||||
bool can_4g = image_params->hdr.version >= SETUP_VERSION_2_12 &&
|
||||
FLAGS_SET(image_params->hdr.xloadflags, XLF_CAN_BE_LOADED_ABOVE_4G);
|
||||
|
||||
if (!can_4g && POINTER_TO_PHYSICAL_ADDRESS(linux_buffer) + linux_length > UINT32_MAX)
|
||||
return log_error_status_stall(
|
||||
return log_error_status(
|
||||
EFI_UNSUPPORTED,
|
||||
u"Unified kernel image was loaded above 4G, but kernel lacks support.");
|
||||
"Unified kernel image was loaded above 4G, but kernel lacks support.");
|
||||
if (!can_4g && POINTER_TO_PHYSICAL_ADDRESS(initrd_buffer) + initrd_length > UINT32_MAX)
|
||||
return log_error_status_stall(
|
||||
EFI_UNSUPPORTED, u"Initrd is above 4G, but kernel lacks support.");
|
||||
return log_error_status(EFI_UNSUPPORTED, "Initrd is above 4G, but kernel lacks support.");
|
||||
|
||||
_cleanup_pages_ Pages boot_params_page = xmalloc_pages(
|
||||
can_4g ? AllocateAnyPages : AllocateMaxAddress,
|
||||
@@ -210,6 +209,7 @@ EFI_STATUS linux_exec_efi_handover(
|
||||
boot_params->hdr.ramdisk_size = initrd_length;
|
||||
boot_params->ext_ramdisk_size = ((uint64_t) initrd_length) >> 32;
|
||||
|
||||
log_wait();
|
||||
linux_efi_handover(parent, (uintptr_t) linux_buffer, boot_params);
|
||||
return EFI_LOAD_ERROR;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <efi.h>
|
||||
#include <efilib.h>
|
||||
|
||||
#include "log.h"
|
||||
|
||||
static unsigned log_count = 0;
|
||||
|
||||
void efi_assert(const char *expr, const char *file, unsigned line, const char *function) {
|
||||
log_error("systemd-boot assertion '%s' failed at %s:%u@%s. Halting.", expr, file, line, function);
|
||||
for (;;)
|
||||
BS->Stall(60 * 1000 * 1000);
|
||||
}
|
||||
|
||||
EFI_STATUS log_internal(EFI_STATUS status, const char *format, ...) {
|
||||
assert(format);
|
||||
|
||||
int32_t attr = ST->ConOut->Mode->Attribute;
|
||||
|
||||
if (ST->ConOut->Mode->CursorColumn > 0)
|
||||
ST->ConOut->OutputString(ST->ConOut, (char16_t *) u"\r\n");
|
||||
ST->ConOut->SetAttribute(ST->ConOut, EFI_LIGHTRED | EFI_BACKGROUND_BLACK);
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vprintf_status(status, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
ST->ConOut->OutputString(ST->ConOut, (char16_t *) u"\r\n");
|
||||
ST->ConOut->SetAttribute(ST->ConOut, attr);
|
||||
|
||||
log_count++;
|
||||
return status;
|
||||
}
|
||||
|
||||
void log_wait(void) {
|
||||
if (log_count == 0)
|
||||
return;
|
||||
|
||||
BS->Stall(MIN(4u, log_count) * 2500 * 1000);
|
||||
log_count = 0;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "efi-string.h"
|
||||
|
||||
void log_wait(void);
|
||||
_gnu_printf_(2, 3) EFI_STATUS log_internal(EFI_STATUS status, const char *format, ...);
|
||||
#define log_error_status(status, ...) log_internal(status, __VA_ARGS__)
|
||||
#define log_error(...) log_internal(EFI_INVALID_PARAMETER, __VA_ARGS__)
|
||||
#define log_oom() log_internal(EFI_OUT_OF_RESOURCES, "Out of memory.")
|
||||
#define log_trace() log_internal(EFI_SUCCESS, "%s:%i@%s", __FILE__, __LINE__, __func__)
|
||||
@@ -205,11 +205,10 @@ EFI_STATUS tpm_log_load_options(const char16_t *load_options, bool *ret_measured
|
||||
load_options,
|
||||
&measured);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(
|
||||
return log_error_status(
|
||||
err,
|
||||
L"Unable to add load options (i.e. kernel command) line measurement to PCR %u: %r",
|
||||
TPM_PCR_INDEX_KERNEL_PARAMETERS,
|
||||
err);
|
||||
"Unable to add load options (i.e. kernel command) line measurement to PCR %u: %m",
|
||||
TPM_PCR_INDEX_KERNEL_PARAMETERS);
|
||||
|
||||
if (ret_measured)
|
||||
*ret_measured = measured;
|
||||
|
||||
@@ -348,6 +348,7 @@ efi_headers = files(
|
||||
'graphics.h',
|
||||
'initrd.h',
|
||||
'linux.h',
|
||||
'log.h',
|
||||
'measure.h',
|
||||
'missing_efi.h',
|
||||
'part-discovery.h',
|
||||
@@ -361,7 +362,6 @@ efi_headers = files(
|
||||
)
|
||||
|
||||
common_sources = files(
|
||||
'assert.c',
|
||||
'console.c',
|
||||
'devicetree.c',
|
||||
'drivers.c',
|
||||
@@ -369,6 +369,7 @@ common_sources = files(
|
||||
'efi-string.c',
|
||||
'graphics.c',
|
||||
'initrd.c',
|
||||
'log.c',
|
||||
'measure.c',
|
||||
'part-discovery.c',
|
||||
'pe.c',
|
||||
@@ -412,6 +413,7 @@ if efi_arch[1] in ['ia32', 'x86_64', 'arm', 'aarch64']
|
||||
fuzzers += [
|
||||
[files('fuzz-bcd.c', 'bcd.c', 'efi-string.c')],
|
||||
[files('fuzz-efi-string.c', 'efi-string.c')],
|
||||
[files('fuzz-efi-printf.c', 'efi-string.c')],
|
||||
]
|
||||
endif
|
||||
|
||||
|
||||
@@ -398,3 +398,15 @@ typedef struct {
|
||||
void *StdErr;
|
||||
} EFI_SHELL_PARAMETERS_PROTOCOL;
|
||||
#endif
|
||||
|
||||
#ifndef EFI_WARN_UNKNOWN_GLYPH
|
||||
# define EFI_WARN_UNKNOWN_GLYPH 1
|
||||
#endif
|
||||
|
||||
#ifndef EFI_WARN_RESET_REQUIRED
|
||||
# define EFI_WARN_STALE_DATA 5
|
||||
# define EFI_WARN_FILE_SYSTEM 6
|
||||
# define EFI_WARN_RESET_REQUIRED 7
|
||||
# define EFI_IP_ADDRESS_CONFLICT EFIERR(34)
|
||||
# define EFI_HTTP_ERROR EFIERR(35)
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -158,7 +158,7 @@ static void locate_sections(
|
||||
|
||||
if (in_memory) {
|
||||
if (prev_section_addr > sect->VirtualAddress)
|
||||
log_error_stall(u"Overlapping PE sections detected. Boot may fail due to image memory corruption!");
|
||||
log_error("Overlapping PE sections detected. Boot may fail due to image memory corruption!");
|
||||
prev_section_addr = sect->VirtualAddress + sect->VirtualSize;
|
||||
}
|
||||
|
||||
|
||||
+22
-22
@@ -48,7 +48,7 @@ static EFI_STATUS acquire_rng(void *ret, UINTN size) {
|
||||
|
||||
err = rng->GetRNG(rng, NULL, size, ret);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Failed to acquire RNG data: %r", err);
|
||||
return log_error_status(err, "Failed to acquire RNG data: %m");
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -63,12 +63,12 @@ static EFI_STATUS acquire_system_token(void **ret, UINTN *ret_size) {
|
||||
err = efivar_get_raw(LOADER_GUID, L"LoaderSystemToken", &data, &size);
|
||||
if (err != EFI_SUCCESS) {
|
||||
if (err != EFI_NOT_FOUND)
|
||||
log_error_stall(L"Failed to read LoaderSystemToken EFI variable: %r", err);
|
||||
log_error_status(err, "Failed to read LoaderSystemToken EFI variable: %m");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (size <= 0)
|
||||
return log_error_status_stall(EFI_NOT_FOUND, L"System token too short, ignoring.");
|
||||
return log_error_status(EFI_NOT_FOUND, "System token too short, ignoring.");
|
||||
|
||||
*ret = TAKE_PTR(data);
|
||||
*ret_size = size;
|
||||
@@ -201,29 +201,29 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir) {
|
||||
0);
|
||||
if (err != EFI_SUCCESS) {
|
||||
if (err != EFI_NOT_FOUND && err != EFI_WRITE_PROTECTED)
|
||||
log_error_stall(L"Failed to open random seed file: %r", err);
|
||||
log_error_status(err, "Failed to open random seed file: %m");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = get_file_info_harder(handle, &info, NULL);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Failed to get file info for random seed: %r", err);
|
||||
return log_error_status(err, "Failed to get file info for random seed: %m");
|
||||
|
||||
size = info->FileSize;
|
||||
if (size < RANDOM_MAX_SIZE_MIN)
|
||||
return log_error_status_stall(EFI_INVALID_PARAMETER, L"Random seed file is too short.");
|
||||
return log_error("Random seed file is too short.");
|
||||
|
||||
if (size > RANDOM_MAX_SIZE_MAX)
|
||||
return log_error_status_stall(EFI_INVALID_PARAMETER, L"Random seed file is too large.");
|
||||
return log_error("Random seed file is too large.");
|
||||
|
||||
seed = xmalloc(size);
|
||||
rsize = size;
|
||||
err = handle->Read(handle, &rsize, seed);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Failed to read random seed file: %r", err);
|
||||
return log_error_status(err, "Failed to read random seed file: %m");
|
||||
if (rsize != size) {
|
||||
explicit_bzero_safe(seed, rsize);
|
||||
return log_error_status_stall(EFI_PROTOCOL_ERROR, L"Short read on random seed file.");
|
||||
return log_error_status(EFI_PROTOCOL_ERROR, "Short read on random seed file.");
|
||||
}
|
||||
|
||||
sha256_process_bytes(&size, sizeof(size), &hash);
|
||||
@@ -232,14 +232,14 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir) {
|
||||
|
||||
err = handle->SetPosition(handle, 0);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Failed to seek to beginning of random seed file: %r", err);
|
||||
return log_error_status(err, "Failed to seek to beginning of random seed file: %m");
|
||||
|
||||
/* Let's also include the UEFI monotonic counter (which is supposedly increasing on every single
|
||||
* boot) in the hash, so that even if the changes to the ESP for some reason should not be
|
||||
* persistent, the random seed we generate will still be different on every single boot. */
|
||||
err = BS->GetNextMonotonicCount(&uefi_monotonic_counter);
|
||||
if (err != EFI_SUCCESS && !seeded_by_efi)
|
||||
return log_error_status_stall(err, L"Failed to acquire UEFI monotonic counter: %r", err);
|
||||
return log_error_status(err, "Failed to acquire UEFI monotonic counter: %m");
|
||||
size = sizeof(uefi_monotonic_counter);
|
||||
sha256_process_bytes(&size, sizeof(size), &hash);
|
||||
sha256_process_bytes(&uefi_monotonic_counter, size, &hash);
|
||||
@@ -264,26 +264,26 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir) {
|
||||
if (size < info->FileSize) {
|
||||
err = handle->SetPosition(handle, size);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Failed to seek to offset of random seed file: %r", err);
|
||||
return log_error_status(err, "Failed to seek to offset of random seed file: %m");
|
||||
wsize = info->FileSize - size;
|
||||
err = handle->Write(handle, &wsize, seed /* All zeros now */);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Failed to write random seed file: %r", err);
|
||||
return log_error_status(err, "Failed to write random seed file: %m");
|
||||
if (wsize != info->FileSize - size)
|
||||
return log_error_status_stall(EFI_PROTOCOL_ERROR, L"Short write on random seed file.");
|
||||
return log_error_status(EFI_PROTOCOL_ERROR, "Short write on random seed file.");
|
||||
err = handle->Flush(handle);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Failed to flush random seed file: %r", err);
|
||||
return log_error_status(err, "Failed to flush random seed file: %m");
|
||||
err = handle->SetPosition(handle, 0);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Failed to seek to beginning of random seed file: %r", err);
|
||||
return log_error_status(err, "Failed to seek to beginning of random seed file: %m");
|
||||
|
||||
/* We could truncate the file here with something like:
|
||||
*
|
||||
* info->FileSize = size;
|
||||
* err = handle->SetInfo(handle, &GenericFileInfo, info->Size, info);
|
||||
* if (err != EFI_SUCCESS)
|
||||
* return log_error_status_stall(err, L"Failed to truncate random seed file: %r", err);
|
||||
* return log_error_status(err, "Failed to truncate random seed file: %u");
|
||||
*
|
||||
* But this is considered slightly risky, because EFI filesystem drivers are a little bit
|
||||
* flimsy. So instead we rely on userspace eventually truncating this when it writes a new
|
||||
@@ -293,18 +293,18 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir) {
|
||||
wsize = size;
|
||||
err = handle->Write(handle, &wsize, random_bytes);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Failed to write random seed file: %r", err);
|
||||
return log_error_status(err, "Failed to write random seed file: %m");
|
||||
if (wsize != size)
|
||||
return log_error_status_stall(EFI_PROTOCOL_ERROR, L"Short write on random seed file.");
|
||||
return log_error_status(EFI_PROTOCOL_ERROR, "Short write on random seed file.");
|
||||
err = handle->Flush(handle);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Failed to flush random seed file: %r", err);
|
||||
return log_error_status(err, "Failed to flush random seed file: %m");
|
||||
|
||||
err = BS->AllocatePool(EfiACPIReclaimMemory,
|
||||
offsetof(struct linux_efi_random_seed, seed) + DESIRED_SEED_SIZE,
|
||||
(void **) &new_seed_table);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Failed to allocate EFI table for random seed: %r", err);
|
||||
return log_error_status(err, "Failed to allocate EFI table for random seed: %m");
|
||||
new_seed_table->size = DESIRED_SEED_SIZE;
|
||||
|
||||
/* hash = hash_key || 1 */
|
||||
@@ -316,7 +316,7 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir) {
|
||||
|
||||
err = BS->InstallConfigurationTable(&(EFI_GUID)LINUX_EFI_RANDOM_SEED_TABLE_GUID, new_seed_table);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Failed to install EFI table for random seed: %r", err);
|
||||
return log_error_status(err, "Failed to install EFI table for random seed: %m");
|
||||
TAKE_PTR(new_seed_table);
|
||||
|
||||
if (previous_seed_table) {
|
||||
|
||||
@@ -44,16 +44,16 @@ EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path) {
|
||||
|
||||
clear_screen(COLOR_NORMAL);
|
||||
|
||||
Print(u"Enrolling secure boot keys from directory: %s\n", path);
|
||||
printf("Enrolling secure boot keys from directory: %ls\n", path);
|
||||
|
||||
/* Enrolling secure boot keys is safe to do in virtualized environments as there is nothing
|
||||
* we can brick there. */
|
||||
if (!in_hypervisor()) {
|
||||
Print(u"Warning: Enrolling custom Secure Boot keys might soft-brick your machine!\n");
|
||||
printf("Warning: Enrolling custom Secure Boot keys might soft-brick your machine!\n");
|
||||
|
||||
unsigned timeout_sec = 15;
|
||||
for (;;) {
|
||||
Print(u"\rEnrolling in %2u s, press any key to abort.", timeout_sec);
|
||||
printf("\rEnrolling in %2u s, press any key to abort.", timeout_sec);
|
||||
|
||||
uint64_t key;
|
||||
err = console_key_read(&key, 1000 * 1000);
|
||||
@@ -66,10 +66,9 @@ EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path) {
|
||||
continue;
|
||||
}
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(
|
||||
return log_error_status(
|
||||
err,
|
||||
L"Error waiting for user input to enroll Secure Boot keys: %r",
|
||||
err);
|
||||
"Error waiting for user input to enroll Secure Boot keys: %m");
|
||||
|
||||
/* user aborted, returning EFI_SUCCESS here allows the user to go back to the menu */
|
||||
return EFI_SUCCESS;
|
||||
@@ -80,7 +79,7 @@ EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path) {
|
||||
|
||||
err = open_directory(root_dir, path, &dir);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Failed opening keys directory %s: %r", path, err);
|
||||
return log_error_status(err, "Failed opening keys directory %ls: %m", path);
|
||||
|
||||
struct {
|
||||
const char16_t *name;
|
||||
@@ -98,7 +97,7 @@ EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path) {
|
||||
for (size_t i = 0; i < ELEMENTSOF(sb_vars); i++) {
|
||||
err = file_read(dir, sb_vars[i].filename, 0, 0, &sb_vars[i].buffer, &sb_vars[i].size);
|
||||
if (err != EFI_SUCCESS) {
|
||||
log_error_stall(L"Failed reading file %s\\%s: %r", path, sb_vars[i].filename, err);
|
||||
log_error_status(err, "Failed reading file %ls\\%ls: %m", path, sb_vars[i].filename);
|
||||
goto out_deallocate;
|
||||
}
|
||||
}
|
||||
@@ -112,7 +111,7 @@ EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path) {
|
||||
|
||||
err = efivar_set_raw(&sb_vars[i].vendor, sb_vars[i].name, sb_vars[i].buffer, sb_vars[i].size, sb_vars_opts);
|
||||
if (err != EFI_SUCCESS) {
|
||||
log_error_stall(L"Failed to write %s secure boot variable: %r", sb_vars[i].name, err);
|
||||
log_error_status(err, "Failed to write %ls secure boot variable: %m", sb_vars[i].name);
|
||||
goto out_deallocate;
|
||||
}
|
||||
}
|
||||
|
||||
+19
-12
@@ -114,14 +114,14 @@ static void export_variables(EFI_LOADED_IMAGE_PROTOCOL *loaded_image) {
|
||||
/* if LoaderFirmwareInfo is not set, let's set it */
|
||||
if (efivar_get_raw(LOADER_GUID, L"LoaderFirmwareInfo", NULL, NULL) != EFI_SUCCESS) {
|
||||
_cleanup_free_ char16_t *s = NULL;
|
||||
s = xpool_print(L"%s %u.%02u", ST->FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff);
|
||||
s = xasprintf("%ls %u.%02u", ST->FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff);
|
||||
efivar_set(LOADER_GUID, L"LoaderFirmwareInfo", s, 0);
|
||||
}
|
||||
|
||||
/* ditto for LoaderFirmwareType */
|
||||
if (efivar_get_raw(LOADER_GUID, L"LoaderFirmwareType", NULL, NULL) != EFI_SUCCESS) {
|
||||
_cleanup_free_ char16_t *s = NULL;
|
||||
s = xpool_print(L"UEFI %u.%02u", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
|
||||
s = xasprintf("UEFI %u.%02u", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
|
||||
efivar_set(LOADER_GUID, L"LoaderFirmwareType", s, 0);
|
||||
}
|
||||
|
||||
@@ -173,14 +173,14 @@ static bool use_load_options(
|
||||
*ret = xstrdup16(shell->Argv[1]);
|
||||
for (size_t i = 2; i < shell->Argc; i++) {
|
||||
_cleanup_free_ char16_t *old = *ret;
|
||||
*ret = xpool_print(u"%s %s", old, shell->Argv[i]);
|
||||
*ret = xasprintf("%ls %ls", old, shell->Argv[i]);
|
||||
}
|
||||
|
||||
mangle_stub_cmdline(*ret);
|
||||
return true;
|
||||
}
|
||||
|
||||
EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
static EFI_STATUS real_main(EFI_HANDLE image) {
|
||||
_cleanup_free_ void *credential_initrd = NULL, *global_credential_initrd = NULL, *sysext_initrd = NULL, *pcrsig_initrd = NULL, *pcrpkey_initrd = NULL;
|
||||
size_t credential_initrd_size = 0, global_credential_initrd_size = 0, sysext_initrd_size = 0, pcrsig_initrd_size = 0, pcrpkey_initrd_size = 0;
|
||||
size_t linux_size, initrd_size, dt_size;
|
||||
@@ -194,11 +194,6 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
uint64_t loader_features = 0;
|
||||
EFI_STATUS err;
|
||||
|
||||
InitializeLib(image, sys_table);
|
||||
debug_hook(L"systemd-stub");
|
||||
/* Uncomment the next line if you need to wait for debugger. */
|
||||
// debug_break();
|
||||
|
||||
err = BS->OpenProtocol(
|
||||
image,
|
||||
&LoadedImageProtocol,
|
||||
@@ -207,7 +202,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
NULL,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status_stall(err, L"Error getting a LoadedImageProtocol handle: %r", err);
|
||||
return log_error_status(err, "Error getting a LoadedImageProtocol handle: %m");
|
||||
|
||||
if (efivar_get_uint64_le(LOADER_GUID, L"LoaderFeatures", &loader_features) != EFI_SUCCESS ||
|
||||
!FLAGS_SET(loader_features, EFI_LOADER_FEATURE_RANDOM_SEED)) {
|
||||
@@ -222,7 +217,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
if (err != EFI_SUCCESS || szs[UNIFIED_SECTION_LINUX] == 0) {
|
||||
if (err == EFI_SUCCESS)
|
||||
err = EFI_NOT_FOUND;
|
||||
return log_error_status_stall(err, L"Unable to locate embedded .linux section: %r", err);
|
||||
return log_error_status(err, "Unable to locate embedded .linux section: %m");
|
||||
}
|
||||
|
||||
/* Measure all "payload" of this PE image into a separate PCR (i.e. where nothing else is written
|
||||
@@ -412,7 +407,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
err = devicetree_install_from_memory(
|
||||
&dt_state, PHYSICAL_ADDRESS_TO_POINTER(dt_base), dt_size);
|
||||
if (err != EFI_SUCCESS)
|
||||
log_error_stall(L"Error loading embedded devicetree: %r", err);
|
||||
log_error_status(err, "Error loading embedded devicetree: %m");
|
||||
}
|
||||
|
||||
err = linux_exec(image, cmdline,
|
||||
@@ -421,3 +416,15 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
graphics_mode(false);
|
||||
return err;
|
||||
}
|
||||
|
||||
EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
InitializeLib(image, sys_table);
|
||||
|
||||
debug_hook("systemd-stub");
|
||||
/* Uncomment the next line if you need to wait for debugger. */
|
||||
// debug_break();
|
||||
|
||||
EFI_STATUS err = real_main(image);
|
||||
log_wait();
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -468,6 +468,148 @@ TEST(parse_number16) {
|
||||
assert_se(streq16(tail, u"rest"));
|
||||
}
|
||||
|
||||
_printf_(1, 2) static void test_printf_one(const char *format, ...) {
|
||||
va_list ap, ap_efi;
|
||||
va_start(ap, format);
|
||||
va_copy(ap_efi, ap);
|
||||
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
int r = vasprintf(&buf, format, ap);
|
||||
assert_se(r >= 0);
|
||||
log_info("/* %s(%s) -> \"%.100s\" */", __func__, format, buf);
|
||||
|
||||
_cleanup_free_ char16_t *buf_efi = xvasprintf_status(0, format, ap_efi);
|
||||
|
||||
bool eq = true;
|
||||
for (size_t i = 0; i <= (size_t) r; i++) {
|
||||
if (buf[i] != buf_efi[i])
|
||||
eq = false;
|
||||
buf[i] = buf_efi[i];
|
||||
}
|
||||
|
||||
log_info("%.100s", buf);
|
||||
assert_se(eq);
|
||||
|
||||
va_end(ap);
|
||||
va_end(ap_efi);
|
||||
}
|
||||
|
||||
TEST(xvasprintf_status) {
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wformat-zero-length"
|
||||
test_printf_one("");
|
||||
#pragma GCC diagnostic pop
|
||||
test_printf_one("string");
|
||||
test_printf_one("%%-%%%%");
|
||||
|
||||
test_printf_one("%p %p %32p %*p %*p", NULL, (void *) 0xF, &errno, 0, &saved_argc, 20, &saved_argv);
|
||||
test_printf_one("%-10p %-32p %-*p %-*p", NULL, &errno, 0, &saved_argc, 20, &saved_argv);
|
||||
|
||||
test_printf_one("%c %3c %*c %*c %-8c", '1', '!', 0, 'a', 9, '_', '>');
|
||||
|
||||
test_printf_one("%s %s %s", "012345", "6789", "ab");
|
||||
test_printf_one("%.4s %.4s %.4s %.0s", "cdefgh", "ijkl", "mn", "@");
|
||||
test_printf_one("%8s %8s %8s", "opqrst", "uvwx", "yz");
|
||||
test_printf_one("%8.4s %8.4s %8.4s %8.0s", "ABCDEF", "GHIJ", "KL", "$");
|
||||
test_printf_one("%4.8s %4.8s %4.8s", "ABCDEFGHIJ", "ABCDEFGH", "ABCD");
|
||||
|
||||
test_printf_one("%.*s %.*s %.*s %.*s", 4, "012345", 4, "6789", 4, "ab", 0, "&");
|
||||
test_printf_one("%*s %*s %*s", 8, "cdefgh", 8, "ijkl", 8, "mn");
|
||||
test_printf_one("%*.*s %*.*s %*.*s %*.*s", 8, 4, "opqrst", 8, 4, "uvwx", 8, 4, "yz", 8, 0, "#");
|
||||
test_printf_one("%*.*s %*.*s %*.*s", 3, 8, "OPQRST", 3, 8, "UVWX", 3, 8, "YZ");
|
||||
|
||||
test_printf_one("%ls %ls %ls", L"012345", L"6789", L"ab");
|
||||
test_printf_one("%.4ls %.4ls %.4ls %.0ls", L"cdefgh", L"ijkl", L"mn", L"@");
|
||||
test_printf_one("%8ls %8ls %8ls", L"opqrst", L"uvwx", L"yz");
|
||||
test_printf_one("%8.4ls %8.4ls %8.4ls %8.0ls", L"ABCDEF", L"GHIJ", L"KL", L"$");
|
||||
test_printf_one("%4.8ls %4.8ls %4.8ls", L"ABCDEFGHIJ", L"ABCDEFGH", L"ABCD");
|
||||
|
||||
test_printf_one("%.*ls %.*ls %.*ls %.*ls", 4, L"012345", 4, L"6789", 4, L"ab", 0, L"&");
|
||||
test_printf_one("%*ls %*ls %*ls", 8, L"cdefgh", 8, L"ijkl", 8, L"mn");
|
||||
test_printf_one("%*.*ls %*.*ls %*.*ls %*.*ls", 8, 4, L"opqrst", 8, 4, L"uvwx", 8, 4, L"yz", 8, 0, L"#");
|
||||
test_printf_one("%*.*ls %*.*ls %*.*ls", 3, 8, L"OPQRST", 3, 8, L"UVWX", 3, 8, L"YZ");
|
||||
|
||||
test_printf_one("%-14s %-10.0s %-10.3s", "left", "", "chopped");
|
||||
test_printf_one("%-14ls %-10.0ls %-10.3ls", L"left", L"", L"chopped");
|
||||
|
||||
test_printf_one("%.6s", (char[]){ 'n', 'o', ' ', 'n', 'u', 'l' });
|
||||
test_printf_one("%.6ls", (wchar_t[]){ 'n', 'o', ' ', 'n', 'u', 'l' });
|
||||
|
||||
test_printf_one("%u %u %u", 0U, 42U, 1234567890U);
|
||||
test_printf_one("%i %i %i", 0, -42, -1234567890);
|
||||
test_printf_one("%x %x %x", 0x0U, 0x42U, 0x123ABCU);
|
||||
test_printf_one("%X %X %X", 0x1U, 0x43U, 0x234BCDU);
|
||||
test_printf_one("%#x %#x %#x", 0x2U, 0x44U, 0x345CDEU);
|
||||
test_printf_one("%#X %#X %#X", 0x3U, 0x45U, 0x456FEDU);
|
||||
|
||||
test_printf_one("%u %lu %llu %zu", UINT_MAX, ULONG_MAX, ULLONG_MAX, SIZE_MAX);
|
||||
test_printf_one("%i %i %zi", INT_MIN, INT_MAX, SSIZE_MAX);
|
||||
test_printf_one("%li %li %lli %lli", LONG_MIN, LONG_MAX, LLONG_MIN, LLONG_MAX);
|
||||
test_printf_one("%x %#lx %llx %#zx", UINT_MAX, ULONG_MAX, ULLONG_MAX, SIZE_MAX);
|
||||
test_printf_one("%X %#lX %llX %#zX", UINT_MAX, ULONG_MAX, ULLONG_MAX, SIZE_MAX);
|
||||
test_printf_one("%ju %ji %ji", UINTMAX_MAX, INTMAX_MIN, INTMAX_MAX);
|
||||
test_printf_one("%ti %ti", PTRDIFF_MIN, PTRDIFF_MAX);
|
||||
|
||||
test_printf_one("%" PRIu32 " %" PRIi32 " %" PRIi32, UINT32_MAX, INT32_MIN, INT32_MAX);
|
||||
test_printf_one("%" PRIx32 " %" PRIX32, UINT32_MAX, UINT32_MAX);
|
||||
test_printf_one("%#" PRIx32 " %#" PRIX32, UINT32_MAX, UINT32_MAX);
|
||||
|
||||
test_printf_one("%" PRIu64 " %" PRIi64 " %" PRIi64, UINT64_MAX, INT64_MIN, INT64_MAX);
|
||||
test_printf_one("%" PRIx64 " %" PRIX64, UINT64_MAX, UINT64_MAX);
|
||||
test_printf_one("%#" PRIx64 " %#" PRIX64, UINT64_MAX, UINT64_MAX);
|
||||
|
||||
test_printf_one("%.11u %.11i %.11x %.11X %#.11x %#.11X", 1U, -2, 3U, 0xA1U, 0xB2U, 0xC3U);
|
||||
test_printf_one("%13u %13i %13x %13X %#13x %#13X", 4U, -5, 6U, 0xD4U, 0xE5U, 0xF6U);
|
||||
test_printf_one("%9.5u %9.5i %9.5x %9.5X %#9.5x %#9.5X", 7U, -8, 9U, 0xA9U, 0xB8U, 0xC7U);
|
||||
test_printf_one("%09u %09i %09x %09X %#09x %#09X", 4U, -5, 6U, 0xD6U, 0xE5U, 0xF4U);
|
||||
|
||||
test_printf_one("%*u %.*u %*i %.*i", 15, 42U, 15, 43U, 15, -42, 15, -43);
|
||||
test_printf_one("%*.*u %*.*i", 14, 10, 13U, 14, 10, -14);
|
||||
test_printf_one("%*x %*X %.*x %.*X", 15, 0x1AU, 15, 0x2BU, 15, 0x3CU, 15, 0x4DU);
|
||||
test_printf_one("%#*x %#*X %#.*x %#.*X", 15, 0xA1U, 15, 0xB2U, 15, 0xC3U, 15, 0xD4U);
|
||||
test_printf_one("%*.*x %*.*X", 14, 10, 0x1AU, 14, 10, 0x2BU);
|
||||
test_printf_one("%#*.*x %#*.*X", 14, 10, 0x3CU, 14, 10, 0x4DU);
|
||||
|
||||
test_printf_one("%+.5i %+.5i % .7i % .7i", -15, 51, -15, 51);
|
||||
test_printf_one("%+5.i %+5.i % 7.i % 7.i", -15, 51, -15, 51);
|
||||
|
||||
test_printf_one("%-10u %-10i %-10x %#-10X %- 10i", 1u, -2, 0xA2D2u, 0XB3F4u, -512);
|
||||
test_printf_one("%-10.6u %-10.6i %-10.6x %#-10.6X %- 10.6i", 1u, -2, 0xA2D2u, 0XB3F4u, -512);
|
||||
test_printf_one("%-6.10u %-6.10i %-6.10x %#-6.10X %- 6.10i", 3u, -4, 0x2A2Du, 0X3B4Fu, -215);
|
||||
test_printf_one("%*.u %.*i %.*i", -4, 9u, -4, 8, -4, -6);
|
||||
|
||||
test_printf_one("%.0u %.0i %.0x %.0X", 0u, 0, 0u, 0u);
|
||||
test_printf_one("%.*u %.*i %.*x %.*X", 0, 0u, 0, 0, 0, 0u, 0, 0u);
|
||||
test_printf_one("%*u %*i %*x %*X", -1, 0u, -1, 0, -1, 0u, -1, 0u);
|
||||
|
||||
test_printf_one("%*s%*s%*s", 256, "", 256, "", 4096, ""); /* Test buf growing. */
|
||||
test_printf_one("%0*i%0*i%0*i", 256, 0, 256, 0, 4096, 0); /* Test buf growing. */
|
||||
test_printf_one("%0*i", INT16_MAX, 0); /* Poor programmer's memzero. */
|
||||
|
||||
/* Non printf-compatible behavior tests below. */
|
||||
char16_t *s;
|
||||
|
||||
assert_se(s = xasprintf_status(0, "\n \r \r\n"));
|
||||
assert_se(streq16(s, u"\r\n \r \r\r\n"));
|
||||
s = mfree(s);
|
||||
|
||||
assert_se(s = xasprintf_status(EFI_SUCCESS, "%m"));
|
||||
assert_se(streq16(s, u"Success"));
|
||||
s = mfree(s);
|
||||
|
||||
assert_se(s = xasprintf_status(EFI_SUCCESS, "%15m"));
|
||||
assert_se(streq16(s, u" Success"));
|
||||
s = mfree(s);
|
||||
|
||||
assert_se(s = xasprintf_status(EFI_LOAD_ERROR, "%m"));
|
||||
assert_se(streq16(s, u"Load error"));
|
||||
s = mfree(s);
|
||||
|
||||
assert_se(s = xasprintf_status(0x42, "%m"));
|
||||
assert_se(streq16(s, u"0x42"));
|
||||
s = mfree(s);
|
||||
}
|
||||
|
||||
TEST(efi_memcmp) {
|
||||
assert_se(efi_memcmp(NULL, NULL, 0) == 0);
|
||||
assert_se(efi_memcmp(NULL, NULL, 1) == 0);
|
||||
|
||||
+2
-29
@@ -339,34 +339,6 @@ EFI_STATUS file_read(EFI_FILE *dir, const char16_t *name, UINTN off, UINTN size,
|
||||
return err;
|
||||
}
|
||||
|
||||
void log_error_stall(const char16_t *fmt, ...) {
|
||||
va_list args;
|
||||
|
||||
assert(fmt);
|
||||
|
||||
int32_t attr = ST->ConOut->Mode->Attribute;
|
||||
ST->ConOut->SetAttribute(ST->ConOut, EFI_LIGHTRED|EFI_BACKGROUND_BLACK);
|
||||
|
||||
if (ST->ConOut->Mode->CursorColumn > 0)
|
||||
Print(L"\n");
|
||||
|
||||
va_start(args, fmt);
|
||||
VPrint(fmt, args);
|
||||
va_end(args);
|
||||
|
||||
Print(L"\n");
|
||||
|
||||
ST->ConOut->SetAttribute(ST->ConOut, attr);
|
||||
|
||||
/* Give the user a chance to see the message. */
|
||||
BS->Stall(3 * 1000 * 1000);
|
||||
}
|
||||
|
||||
EFI_STATUS log_oom(void) {
|
||||
log_error_stall(L"Out of memory.");
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
void print_at(UINTN x, UINTN y, UINTN attr, const char16_t *str) {
|
||||
assert(str);
|
||||
ST->ConOut->SetCursorPosition(ST->ConOut, x, y);
|
||||
@@ -375,6 +347,7 @@ void print_at(UINTN x, UINTN y, UINTN attr, const char16_t *str) {
|
||||
}
|
||||
|
||||
void clear_screen(UINTN attr) {
|
||||
log_wait();
|
||||
ST->ConOut->SetAttribute(ST->ConOut, attr);
|
||||
ST->ConOut->ClearScreen(ST->ConOut);
|
||||
}
|
||||
@@ -586,7 +559,7 @@ void hexdump(const char16_t *prefix, const void *data, UINTN size) {
|
||||
|
||||
buf[size*2] = 0;
|
||||
|
||||
log_error_stall(L"%s[%" PRIuN "]: %s", prefix, size, buf);
|
||||
log_error("%ls[%zu]: %ls", prefix, size, buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+2
-27
@@ -5,25 +5,12 @@
|
||||
#include <efilib.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "string-util-fundamental.h"
|
||||
|
||||
#define UINTN_MAX (~(UINTN)0)
|
||||
#define INTN_MAX ((INTN)(UINTN_MAX>>1))
|
||||
|
||||
/* gnu-efi format specifiers for integers are fixed to either 64bit with 'l' and 32bit without a size prefix.
|
||||
* We rely on %u/%d/%x to format regular ints, so ensure the size is what we expect. At the same time, we also
|
||||
* need specifiers for (U)INTN which are native (pointer) sized. */
|
||||
assert_cc(sizeof(int) == sizeof(uint32_t));
|
||||
#if __SIZEOF_POINTER__ == 4
|
||||
# define PRIuN L"u"
|
||||
# define PRIiN L"d"
|
||||
#elif __SIZEOF_POINTER__ == 8
|
||||
# define PRIuN L"lu"
|
||||
# define PRIiN L"ld"
|
||||
#else
|
||||
# error "Unexpected pointer size"
|
||||
#endif
|
||||
|
||||
static inline void free(void *p) {
|
||||
if (!p)
|
||||
return;
|
||||
@@ -67,7 +54,6 @@ static inline void *xrealloc(void *p, size_t old_size, size_t new_size) {
|
||||
return t;
|
||||
}
|
||||
|
||||
#define xpool_print(fmt, ...) ((char16_t *) ASSERT_SE_PTR(PoolPrint((fmt), ##__VA_ARGS__)))
|
||||
#define xnew(type, n) ((type *) xmalloc_multiply(sizeof(type), (n)))
|
||||
|
||||
typedef struct {
|
||||
@@ -139,17 +125,6 @@ static inline void unload_imagep(EFI_HANDLE *image) {
|
||||
&(const EFI_GUID) { 0x4a67b082, 0x0a4c, 0x41cf, { 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f } }
|
||||
#define EFI_GLOBAL_GUID &(const EFI_GUID) EFI_GLOBAL_VARIABLE
|
||||
|
||||
void log_error_stall(const char16_t *fmt, ...);
|
||||
EFI_STATUS log_oom(void);
|
||||
|
||||
/* This works just like log_error_errno() from userspace, but requires you
|
||||
* to provide err a second time if you want to use %r in the message! */
|
||||
#define log_error_status_stall(err, fmt, ...) \
|
||||
({ \
|
||||
log_error_stall(fmt, ##__VA_ARGS__); \
|
||||
err; \
|
||||
})
|
||||
|
||||
void print_at(UINTN x, UINTN y, UINTN attr, const char16_t *str);
|
||||
void clear_screen(UINTN attr);
|
||||
|
||||
@@ -191,7 +166,7 @@ void debug_break(void);
|
||||
extern uint8_t _text, _data;
|
||||
/* Report the relocated position of text and data sections so that a debugger
|
||||
* can attach to us. See debug-sd-boot.sh for how this can be done. */
|
||||
# define debug_hook(identity) Print(identity L"@0x%lx,0x%lx\n", POINTER_TO_PHYSICAL_ADDRESS(&_text), POINTER_TO_PHYSICAL_ADDRESS(&_data))
|
||||
# define debug_hook(identity) printf(identity "@%p,%p\n", &_text, &_data)
|
||||
#else
|
||||
# define debug_hook(identity)
|
||||
#endif
|
||||
|
||||
+1
-2
@@ -97,9 +97,8 @@ EFI_STATUS vmm_open(EFI_HANDLE *ret_vmm_dev, EFI_FILE **ret_vmm_dir) {
|
||||
|
||||
for (size_t order = 0;; order++) {
|
||||
_cleanup_free_ EFI_DEVICE_PATH *dp = NULL;
|
||||
char16_t order_str[STRLEN("VMMBootOrder") + 4 + 1];
|
||||
|
||||
SPrint(order_str, sizeof(order_str), u"VMMBootOrder%04x", order);
|
||||
_cleanup_free_ char16_t *order_str = xasprintf("VMMBootOrder%04zx", order);
|
||||
dp_err = efivar_get_raw(&(EFI_GUID)VMM_BOOT_ORDER_GUID, order_str, (char**)&dp, NULL);
|
||||
|
||||
for (size_t i = 0; i < n_handles; i++) {
|
||||
|
||||
@@ -74,11 +74,11 @@
|
||||
#define assert(expr)
|
||||
#define assert_not_reached() __builtin_unreachable()
|
||||
#else
|
||||
#define assert(expr) ({ _likely_(expr) ? VOID_0 : efi_assert(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); })
|
||||
#define assert_not_reached() efi_assert("Code should not be reached", __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
||||
#define assert(expr) ({ _likely_(expr) ? VOID_0 : efi_assert(#expr, __FILE__, __LINE__, __func__); })
|
||||
#define assert_not_reached() efi_assert("Code should not be reached", __FILE__, __LINE__, __func__)
|
||||
#endif
|
||||
#define static_assert _Static_assert
|
||||
#define assert_se(expr) ({ _likely_(expr) ? VOID_0 : efi_assert(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); })
|
||||
#define assert_se(expr) ({ _likely_(expr) ? VOID_0 : efi_assert(#expr, __FILE__, __LINE__, __func__); })
|
||||
#endif
|
||||
|
||||
/* This passes the argument through after (if asserts are enabled) checking that it is not null. */
|
||||
|
||||
@@ -30,7 +30,7 @@ _noreturn_ static void log_assert_errno(const char *text, int error, const char
|
||||
do { \
|
||||
int _r_ = (expr); \
|
||||
if (_unlikely_(_r_ < 0)) \
|
||||
log_assert_errno(#expr, -_r_, PROJECT_FILE, __LINE__, __PRETTY_FUNCTION__); \
|
||||
log_assert_errno(#expr, -_r_, PROJECT_FILE, __LINE__, __func__); \
|
||||
} while (false)
|
||||
|
||||
static ManagedJournalFile *test_open(const char *name) {
|
||||
|
||||
Reference in New Issue
Block a user