summaryrefslogtreecommitdiffstats
path: root/src/boot
diff options
context:
space:
mode:
Diffstat (limited to 'src/boot')
-rw-r--r--src/boot/bootctl-install.c2
-rw-r--r--src/boot/efi/boot.c11
-rw-r--r--src/boot/efi/efi-string.c2
-rw-r--r--src/boot/efi/linux.c6
-rw-r--r--src/boot/efi/linux.h3
-rw-r--r--src/boot/efi/linux_x86.c21
-rw-r--r--src/boot/efi/meson.build11
-rw-r--r--src/boot/efi/pe.c7
-rw-r--r--src/boot/efi/pe.h2
-rw-r--r--src/boot/efi/util.c12
-rw-r--r--src/boot/efi/util.h2
-rw-r--r--src/boot/efi/vmm.c22
12 files changed, 73 insertions, 28 deletions
diff --git a/src/boot/bootctl-install.c b/src/boot/bootctl-install.c
index dc46d30..fd26b43 100644
--- a/src/boot/bootctl-install.c
+++ b/src/boot/bootctl-install.c
@@ -45,7 +45,7 @@ static int load_etc_machine_info(void) {
_cleanup_free_ char *p = NULL, *s = NULL, *layout = NULL;
int r;
- p = path_join(arg_root, "etc/machine-info");
+ p = path_join(arg_root, "/etc/machine-info");
if (!p)
return log_oom();
diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c
index 79de121..93e1236 100644
--- a/src/boot/efi/boot.c
+++ b/src/boot/efi/boot.c
@@ -879,6 +879,7 @@ static bool menu_run(
switch (key) {
case KEYPRESS(0, SCAN_UP, 0):
+ case KEYPRESS(0, SCAN_VOLUME_UP, 0): /* Handle phones/tablets that only have a volume up/down rocker + power key (and otherwise just touchscreen input) */
case KEYPRESS(0, 0, 'k'):
case KEYPRESS(0, 0, 'K'):
if (idx_highlight > 0)
@@ -886,6 +887,7 @@ static bool menu_run(
break;
case KEYPRESS(0, SCAN_DOWN, 0):
+ case KEYPRESS(0, SCAN_VOLUME_DOWN, 0):
case KEYPRESS(0, 0, 'j'):
case KEYPRESS(0, 0, 'J'):
if (idx_highlight < config->n_entries-1)
@@ -923,9 +925,10 @@ static bool menu_run(
case KEYPRESS(0, 0, '\n'):
case KEYPRESS(0, 0, '\r'):
- case KEYPRESS(0, SCAN_F3, 0): /* EZpad Mini 4s firmware sends malformed events */
- case KEYPRESS(0, SCAN_F3, '\r'): /* Teclast X98+ II firmware sends malformed events */
+ case KEYPRESS(0, SCAN_F3, 0): /* EZpad Mini 4s firmware sends malformed events */
+ case KEYPRESS(0, SCAN_F3, '\r'): /* Teclast X98+ II firmware sends malformed events */
case KEYPRESS(0, SCAN_RIGHT, 0):
+ case KEYPRESS(0, SCAN_SUSPEND, 0): /* Handle phones/tablets with only a power key + volume up/down rocker (and otherwise just touchscreen input) */
action = ACTION_RUN;
break;
@@ -1334,7 +1337,7 @@ static void boot_entry_parse_tries(
return;
/* Boot counter in the middle of the name? */
- if (!streq16(counter, suffix))
+ if (!strcaseeq16(counter, suffix))
return;
entry->tries_left = tries_left;
@@ -2402,7 +2405,7 @@ static EFI_STATUS image_start(
if (err == EFI_UNSUPPORTED && entry->type == LOADER_LINUX) {
uint32_t compat_address;
- err = pe_kernel_info(loaded_image->ImageBase, &compat_address);
+ err = pe_kernel_info(loaded_image->ImageBase, &compat_address, /* ret_size_in_memory= */ NULL);
if (err != EFI_SUCCESS) {
if (err != EFI_UNSUPPORTED)
return log_error_status(err, "Error finding kernel compat entry address: %m");
diff --git a/src/boot/efi/efi-string.c b/src/boot/efi/efi-string.c
index 3bdb802..db00890 100644
--- a/src/boot/efi/efi-string.c
+++ b/src/boot/efi/efi-string.c
@@ -481,7 +481,7 @@ char *line_get_key_value(char *s, const char *sep, size_t *pos, char **ret_key,
}
char16_t *hexdump(const void *data, size_t size) {
- static const char hex[16] = "0123456789abcdef";
+ static const char hex[] = "0123456789abcdef";
const uint8_t *d = data;
assert(data || size == 0);
diff --git a/src/boot/efi/linux.c b/src/boot/efi/linux.c
index 65bc176..c8e5951 100644
--- a/src/boot/efi/linux.c
+++ b/src/boot/efi/linux.c
@@ -98,6 +98,7 @@ EFI_STATUS linux_exec(
const void *initrd_buffer,
size_t initrd_length) {
+ size_t kernel_size_in_memory = 0;
uint32_t compat_address;
EFI_STATUS err;
@@ -105,7 +106,7 @@ EFI_STATUS linux_exec(
assert(linux_buffer && linux_length > 0);
assert(initrd_buffer || initrd_length == 0);
- err = pe_kernel_info(linux_buffer, &compat_address);
+ err = pe_kernel_info(linux_buffer, &compat_address, &kernel_size_in_memory);
#if defined(__i386__) || defined(__x86_64__)
if (err == EFI_UNSUPPORTED)
/* Kernel is too old to support LINUX_INITRD_MEDIA_GUID, try the deprecated EFI handover
@@ -116,7 +117,8 @@ EFI_STATUS linux_exec(
linux_buffer,
linux_length,
initrd_buffer,
- initrd_length);
+ initrd_length,
+ kernel_size_in_memory);
#endif
if (err != EFI_SUCCESS)
return log_error_status(err, "Bad kernel image: %m");
diff --git a/src/boot/efi/linux.h b/src/boot/efi/linux.h
index 46b5f4f..0d74c6a 100644
--- a/src/boot/efi/linux.h
+++ b/src/boot/efi/linux.h
@@ -16,4 +16,5 @@ EFI_STATUS linux_exec_efi_handover(
const void *linux_buffer,
size_t linux_length,
const void *initrd_buffer,
- size_t initrd_length);
+ size_t initrd_length,
+ size_t kernel_size_in_memory);
diff --git a/src/boot/efi/linux_x86.c b/src/boot/efi/linux_x86.c
index 757902d..58b1b3c 100644
--- a/src/boot/efi/linux_x86.c
+++ b/src/boot/efi/linux_x86.c
@@ -7,12 +7,13 @@
* this x86 specific linux_exec function passes the initrd by setting the
* corresponding fields in the setup_header struct.
*
- * see https://docs.kernel.org/x86/boot.html
+ * see https://docs.kernel.org/arch/x86/boot.html
*/
#include "initrd.h"
#include "linux.h"
#include "macro-fundamental.h"
+#include "memory-util-fundamental.h"
#include "util.h"
#define KERNEL_SECTOR_SIZE 512u
@@ -126,7 +127,8 @@ EFI_STATUS linux_exec_efi_handover(
const void *linux_buffer,
size_t linux_length,
const void *initrd_buffer,
- size_t initrd_length) {
+ size_t initrd_length,
+ size_t kernel_size_in_memory) {
assert(parent);
assert(linux_buffer);
@@ -153,13 +155,22 @@ EFI_STATUS linux_exec_efi_handover(
FLAGS_SET(image_params->hdr.xloadflags, XLF_CAN_BE_LOADED_ABOVE_4G);
/* There is no way to pass the high bits of code32_start. Newer kernels seems to handle this
- * just fine, but older kernels will fail even if they otherwise have above 4G boot support. */
+ * just fine, but older kernels will fail even if they otherwise have above 4G boot support.
+ * A PE image's memory footprint can be larger than its file size, due to unallocated virtual
+ * memory sections. While normally all PE headers should be taken into account, this case only
+ * involves x86 Linux bzImage kernel images, for which unallocated areas are only part of the last
+ * header, so parsing SizeOfImage and zeroeing the buffer past the image size is enough. */
_cleanup_pages_ Pages linux_relocated = {};
- if (POINTER_TO_PHYSICAL_ADDRESS(linux_buffer) + linux_length > UINT32_MAX) {
+ if (POINTER_TO_PHYSICAL_ADDRESS(linux_buffer) + linux_length > UINT32_MAX || kernel_size_in_memory > linux_length) {
linux_relocated = xmalloc_pages(
- AllocateMaxAddress, EfiLoaderCode, EFI_SIZE_TO_PAGES(linux_length), UINT32_MAX);
+ AllocateMaxAddress,
+ EfiLoaderCode,
+ EFI_SIZE_TO_PAGES(kernel_size_in_memory > linux_length ? kernel_size_in_memory : linux_length),
+ UINT32_MAX);
linux_buffer = memcpy(
PHYSICAL_ADDRESS_TO_POINTER(linux_relocated.addr), linux_buffer, linux_length);
+ if (kernel_size_in_memory > linux_length)
+ memzero((uint8_t *) linux_buffer + linux_length, kernel_size_in_memory - linux_length);
}
_cleanup_pages_ Pages initrd_relocated = {};
diff --git a/src/boot/efi/meson.build b/src/boot/efi/meson.build
index 7a60b0e..a1bdd58 100644
--- a/src/boot/efi/meson.build
+++ b/src/boot/efi/meson.build
@@ -63,13 +63,14 @@ foreach ctype : ['color-normal', 'color-entry', 'color-highlight', 'color-edit']
'EFI_' + c[1].strip().underscorify().to_upper()))
endforeach
+efi_conf.set_quoted('PROJECT_VERSION', project_major_version)
+efi_conf.set_quoted('VERSION_TAG', version_tag)
+efi_conf.set('PROJECT_URL', conf.get('PROJECT_URL'))
+
if meson.is_cross_build() and get_option('sbat-distro') == 'auto'
warning('Auto detection of SBAT information not supported when cross-building, disabling SBAT.')
elif get_option('sbat-distro') != ''
efi_conf.set_quoted('SBAT_PROJECT', meson.project_name())
- efi_conf.set_quoted('PROJECT_VERSION', meson.project_version().split('~')[0])
- efi_conf.set_quoted('VERSION_TAG', version_tag)
- efi_conf.set('PROJECT_URL', conf.get('PROJECT_URL'))
if get_option('sbat-distro-generation') < 1
error('SBAT Distro Generation must be a positive integer')
endif
@@ -388,8 +389,8 @@ foreach efi_elf_binary : efi_elf_binaries
install_tag : 'systemd-boot',
command : [
elf2efi_py,
- '--version-major=' + meson.project_version().split('~')[0],
- '--version-minor=0',
+ '--version-major=' + project_major_version,
+ '--version-minor=' + project_minor_version,
'--efi-major=1',
'--efi-minor=1',
'--subsystem=10',
diff --git a/src/boot/efi/pe.c b/src/boot/efi/pe.c
index 829266b..fdca0c9 100644
--- a/src/boot/efi/pe.c
+++ b/src/boot/efi/pe.c
@@ -209,7 +209,7 @@ static uint32_t get_compatibility_entry_address(const DosFileHeader *dos, const
return 0;
}
-EFI_STATUS pe_kernel_info(const void *base, uint32_t *ret_compat_address) {
+EFI_STATUS pe_kernel_info(const void *base, uint32_t *ret_compat_address, size_t *ret_size_in_memory) {
assert(base);
assert(ret_compat_address);
@@ -221,6 +221,11 @@ EFI_STATUS pe_kernel_info(const void *base, uint32_t *ret_compat_address) {
if (!verify_pe(pe, /* allow_compatibility= */ true))
return EFI_LOAD_ERROR;
+ /* When allocating we need to also consider the virtual/uninitialized data sections, so parse it out
+ * of the SizeOfImage field in the PE header and return it */
+ if (ret_size_in_memory)
+ *ret_size_in_memory = pe->OptionalHeader.SizeOfImage;
+
/* Support for LINUX_INITRD_MEDIA_GUID was added in kernel stub 1.0. */
if (pe->OptionalHeader.MajorImageVersion < 1)
return EFI_UNSUPPORTED;
diff --git a/src/boot/efi/pe.h b/src/boot/efi/pe.h
index 7e2258f..860cfe5 100644
--- a/src/boot/efi/pe.h
+++ b/src/boot/efi/pe.h
@@ -16,4 +16,4 @@ EFI_STATUS pe_file_locate_sections(
size_t *offsets,
size_t *sizes);
-EFI_STATUS pe_kernel_info(const void *base, uint32_t *ret_compat_address);
+EFI_STATUS pe_kernel_info(const void *base, uint32_t *ret_compat_address, size_t *ret_size_in_memory);
diff --git a/src/boot/efi/util.c b/src/boot/efi/util.c
index b5c8c63..eb29eb2 100644
--- a/src/boot/efi/util.c
+++ b/src/boot/efi/util.c
@@ -330,7 +330,14 @@ EFI_STATUS chunked_read(EFI_FILE *file, size_t *size, void *buf) {
return EFI_SUCCESS;
}
-EFI_STATUS file_read(EFI_FILE *dir, const char16_t *name, size_t off, size_t size, char **ret, size_t *ret_size) {
+EFI_STATUS file_read(
+ EFI_FILE *dir,
+ const char16_t *name,
+ uint64_t off,
+ size_t size,
+ char **ret,
+ size_t *ret_size) {
+
_cleanup_(file_closep) EFI_FILE *handle = NULL;
_cleanup_free_ char *buf = NULL;
EFI_STATUS err;
@@ -350,6 +357,9 @@ EFI_STATUS file_read(EFI_FILE *dir, const char16_t *name, size_t off, size_t siz
if (err != EFI_SUCCESS)
return err;
+ if (info->FileSize > SIZE_MAX)
+ return EFI_BAD_BUFFER_SIZE;
+
size = info->FileSize;
}
diff --git a/src/boot/efi/util.h b/src/boot/efi/util.h
index ceac07c..dc624f4 100644
--- a/src/boot/efi/util.h
+++ b/src/boot/efi/util.h
@@ -102,7 +102,7 @@ char16_t *xstr8_to_path(const char *stra);
char16_t *mangle_stub_cmdline(char16_t *cmdline);
EFI_STATUS chunked_read(EFI_FILE *file, size_t *size, void *buf);
-EFI_STATUS file_read(EFI_FILE *dir, const char16_t *name, size_t off, size_t size, char **content, size_t *content_size);
+EFI_STATUS file_read(EFI_FILE *dir, const char16_t *name, uint64_t off, size_t size, char **content, size_t *content_size);
static inline void file_closep(EFI_FILE **handle) {
if (!*handle)
diff --git a/src/boot/efi/vmm.c b/src/boot/efi/vmm.c
index 60e216d..ed654f6 100644
--- a/src/boot/efi/vmm.c
+++ b/src/boot/efi/vmm.c
@@ -241,13 +241,21 @@ static const SmbiosHeader *get_smbios_table(uint8_t type, uint64_t *ret_size_lef
size -= header->length;
p += header->length;
- /* Skip over string table. */
+ /* Special case: if there are no strings appended, we'll see two NUL bytes, skip over them */
+ if (size >= 2 && p[0] == 0 && p[1] == 0) {
+ size -= 2;
+ p += 2;
+ continue;
+ }
+
+ /* Skip over a populated string table. */
+ bool first = true;
for (;;) {
const uint8_t *e = memchr(p, 0, size);
if (!e)
return NULL;
- if (e == p) {/* Double NUL byte means we've reached the end of the string table. */
+ if (!first && e == p) {/* Double NUL byte means we've reached the end of the string table. */
p++;
size--;
break;
@@ -255,6 +263,7 @@ static const SmbiosHeader *get_smbios_table(uint8_t type, uint64_t *ret_size_lef
size -= e + 1 - p;
p = e + 1;
+ first = false;
}
}
@@ -337,7 +346,7 @@ static uint64_t msr(uint32_t index) {
return val;
}
-static bool detect_hyperv_sev(void) {
+static bool detect_hyperv_cvm(uint32_t isoltype) {
uint32_t eax, ebx, ecx, edx, feat;
char sig[13] = {};
@@ -354,7 +363,7 @@ static bool detect_hyperv_sev(void) {
if (ebx & CPUID_HYPERV_ISOLATION && !(ebx & CPUID_HYPERV_CPU_MANAGEMENT)) {
__cpuid(CPUID_HYPERV_ISOLATION_CONFIG, eax, ebx, ecx, edx);
- if ((ebx & CPUID_HYPERV_ISOLATION_TYPE_MASK) == CPUID_HYPERV_ISOLATION_TYPE_SNP)
+ if ((ebx & CPUID_HYPERV_ISOLATION_TYPE_MASK) == isoltype)
return true;
}
@@ -379,7 +388,7 @@ static bool detect_sev(void) {
* specific CPUID checks.
*/
if (!(eax & EAX_SEV))
- return detect_hyperv_sev();
+ return detect_hyperv_cvm(CPUID_HYPERV_ISOLATION_TYPE_SNP);
msrval = msr(MSR_AMD64_SEV);
@@ -403,6 +412,9 @@ static bool detect_tdx(void) {
if (memcmp(sig, CPUID_SIG_INTEL_TDX, sizeof(sig)) == 0)
return true;
+ if (detect_hyperv_cvm(CPUID_HYPERV_ISOLATION_TYPE_TDX))
+ return true;
+
return false;
}
#endif /* ! __i386__ && ! __x86_64__ */