1
0
mirror of https://github.com/systemd/systemd synced 2026-03-30 19:54:51 +02:00

Compare commits

..

11 Commits

Author SHA1 Message Date
Lennart Poettering
0a51337df1
Merge pull request #20983 from mxre/feature/aarch64
[sd-stub] Add support for aarch64 booting via pe-entry point
2021-10-15 10:26:10 +02:00
Zbigniew Jędrzejewski-Szmek
0bb6699edc
Merge pull request #20980 from bluca/compat_readme
docs: add guidelines w.r.t. compatibility to docs/CONTRIBUTING.md
2021-10-15 09:49:29 +02:00
Zbigniew Jędrzejewski-Szmek
6b292fa17b
Merge pull request #20996 from yuwata/udevadm-trigger-debug
test: show debug and verbose message
2021-10-15 09:44:59 +02:00
Yu Watanabe
a6d4e83b8a unit: networkd does not require AF_ALG anymore
As khash is retired.
2021-10-15 09:25:38 +02:00
Max Resch
dc46792831 [sd-stub] Add support for aarch64 booting via pe-entry point 2021-10-13 18:20:32 +02:00
Yu Watanabe
6870cf0729 test: show debug and verbose message 2021-10-13 12:58:24 +09:00
Yu Watanabe
6b652c03a4 sd-device-monitor: update log message to clarify the error will be ignored 2021-10-13 12:57:40 +09:00
Max Resch
200b1d997d move mfree to macro-fundamentals.h 2021-10-12 18:31:57 +02:00
Luca Boccassi
ea7ded75f3 docs: add guidelines w.r.t. compatibility to docs/CONTRIBUTING.md 2021-10-12 11:09:58 +01:00
Luca Boccassi
9eb3e30a76 LICENSES/README.md: remove reference to non-existing files
All example code was relicensed
2021-10-12 10:53:12 +01:00
Luca Boccassi
87bd39508b LICENSES/README.md: fix typo 2021-10-11 14:06:51 +01:00
16 changed files with 503 additions and 178 deletions

View File

@ -2,7 +2,7 @@
## Main License ## Main License
The systemd project uses single-line references to Unique Licese Identifiers as The systemd project uses single-line references to Unique License Identifiers as
defined by the Linux Foundation's SPDX project (https://spdx.org/). The line in defined by the Linux Foundation's SPDX project (https://spdx.org/). The line in
each individual source file identifies the license applicable to that file. each individual source file identifies the license applicable to that file.
@ -47,7 +47,7 @@ The following exceptions apply:
- src/basic/siphash24.h - src/basic/siphash24.h
- src/systemctl/systemd-sysv-install.SKELETON - src/systemctl/systemd-sysv-install.SKELETON
- tools/check-includes.pl - tools/check-includes.pl
- all examples, code and scripts, under man/ except where otherwise noted - all examples under man/
* the following sources are under **Public Domain** (LicenseRef-murmurhash2-public-domain): * the following sources are under **Public Domain** (LicenseRef-murmurhash2-public-domain):
- src/basic/MurmurHash2.c - src/basic/MurmurHash2.c
- src/basic/MurmurHash2.h - src/basic/MurmurHash2.h

View File

@ -44,3 +44,49 @@ See [reporting of security vulnerabilities](SECURITY.md).
We'd like to apologize in advance if we are not able to process and reply to your issue or PR right-away. We have a lot of work to do, but we are trying our best! We'd like to apologize in advance if we are not able to process and reply to your issue or PR right-away. We have a lot of work to do, but we are trying our best!
Thank you very much for your contributions! Thank you very much for your contributions!
# Backward Compatibility And External Dependencies
We strive to keep backward compatibility where possible and reasonable. The following are general guidelines, not hard
rules, and case-by-case exceptions might be applied at the discretion of the maintainers. The current set of build time
and runtime dependencies are documented in the [README](../README).
## New features
It is fine for new features/functionality/tools/daemons to require bleeding edge external dependencies, provided there
are runtime and build time graceful fallbacks (e.g.: daemon will not be built, runtime functionality will be skipped with
clear log message).
In case a new feature is added to both `systemd` and one of its dependencies, we expect the corresponding feature code to
be merged upstream in the dependency before accepting our side of the implementation.
Making use of new kernel syscalls can be achieved through compat wrappers in our tree (see: `src/basic/missing_syscall_def.h`),
and does not need to wait for glibc support.
## External Build/Runtime Dependencies
It is often tempting to bump external dependencies minimum versions to cut cruft, and in general it's an essential part
of the maintenance process. But as a generic rule, existing dependencies should not be bumped without very strong
reasons. When possible, we try to keep compatibility with the most recent LTS releases of each mainstream distribution
for optional components, and with all currently maintained (i.e.: not EOL) LTS releases for core components. When in
doubt, ask before committing time to work on contributions if it's not clear that cutting support would be obviously
acceptable.
## Kernel Requirements
Same principles as with other dependencies should be applied. It is fine to require newer kernel versions for additional
functionality or optional features, but very strong reasons should be required for breaking compatibility for existing
functionality, especially for core components. It is not uncommon, for example, for embedded systems to be stuck on older
kernel versions due to hardware requirements, so do not assume everybody is running with latest and greatest at all times.
In general, [currently maintained LTS branches](https://www.kernel.org/category/releases.html) should keep being supported
for existing functionality, especially for core components.
## `libsystemd.so`
`libsystemd.so` is a shared public library, so breaking ABI/API compatibility creates a lot of work for its users, and should
always be avoided apart from the most extreme circumstances. For example, always add a new interface instead of modifying
the signature of an existing function. It is fine to mark an interface as deprecated to gently nudge users toward a newer one,
but in general support for the old one should be maintained whenever possible.
Symbol versioning and the compiler's deprecated attribute should be used when managing the lifetime of a public interface.
## `libudev.so`
`libudev.so` is a shared public library, and is still maintained, but should not gain new symbols at this point.

View File

@ -49,12 +49,6 @@ typedef void (*free_func_t)(void *p);
#define malloc0(n) (calloc(1, (n) ?: 1)) #define malloc0(n) (calloc(1, (n) ?: 1))
#define mfree(memory) \
({ \
free(memory); \
(typeof(memory)) NULL; \
})
#define free_and_replace(a, b) \ #define free_and_replace(a, b) \
({ \ ({ \
typeof(a)* _a = &(a); \ typeof(a)* _a = &(a); \

View File

@ -1,109 +1,186 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Generic Linux boot protocol using the EFI/PE entry point of the kernel. Passes
* initrd with the LINUX_INITRD_MEDIA_GUID DevicePath and cmdline with
* EFI LoadedImageProtocol.
*
* This method works for Linux 5.8 and newer on ARM/Aarch64, x86/x68_64 and RISC-V.
*/
#include <efi.h> #include <efi.h>
#include <efilib.h> #include <efilib.h>
#include "linux.h"
#include "initrd.h" #include "initrd.h"
#include "linux.h"
#include "pe.h"
#include "util.h" #include "util.h"
#ifdef __i386__ static EFI_LOADED_IMAGE * loaded_image_free(EFI_LOADED_IMAGE *img) {
#define __regparm0__ __attribute__((regparm(0))) if (!img)
#else return NULL;
#define __regparm0__ mfree(img->LoadOptions);
#endif return mfree(img);
}
typedef VOID(*handover_f)(VOID *image, EFI_SYSTEM_TABLE *table, struct boot_params *params) __regparm0__; static EFI_STATUS loaded_image_register(
const CHAR8 *cmdline, UINTN cmdline_len,
const VOID *linux_buffer, UINTN linux_length,
EFI_HANDLE *ret_image) {
static VOID linux_efi_handover(EFI_HANDLE image, struct boot_params *params) { EFI_LOADED_IMAGE *loaded_image = NULL;
handover_f handover; EFI_STATUS err;
UINTN start = (UINTN)params->hdr.code32_start;
assert(params); assert(cmdline || cmdline_len > 0);
assert(linux_buffer && linux_length > 0);
assert(ret_image);
#ifdef __x86_64__ /* create and install new LoadedImage Protocol */
asm volatile ("cli"); loaded_image = AllocatePool(sizeof(EFI_LOADED_IMAGE));
start += 512; if (!loaded_image)
#endif return EFI_OUT_OF_RESOURCES;
handover = (handover_f)(start + params->hdr.handover_offset);
handover(image, ST, params); /* provide the image base address and size */
*loaded_image = (EFI_LOADED_IMAGE) {
.ImageBase = (VOID *) linux_buffer,
.ImageSize = linux_length
};
/* if a cmdline is set convert it to UTF16 */
if (cmdline) {
loaded_image->LoadOptions = stra_to_str(cmdline);
if (!loaded_image->LoadOptions) {
loaded_image = loaded_image_free(loaded_image);
return EFI_OUT_OF_RESOURCES;
}
loaded_image->LoadOptionsSize = StrSize(loaded_image->LoadOptions);
}
/* install a new LoadedImage protocol. ret_handle is a new image handle */
err = uefi_call_wrapper(BS->InstallMultipleProtocolInterfaces, 4,
ret_image,
&LoadedImageProtocol, loaded_image,
NULL);
if (EFI_ERROR(err))
loaded_image = loaded_image_free(loaded_image);
return err;
}
static EFI_STATUS loaded_image_unregister(EFI_HANDLE loaded_image_handle) {
EFI_LOADED_IMAGE_PROTOCOL *loaded_image;
EFI_STATUS err;
if (!loaded_image_handle)
return EFI_SUCCESS;
/* get the LoadedImage protocol that we allocated earlier */
err = uefi_call_wrapper(
BS->OpenProtocol, 6,
loaded_image_handle, &LoadedImageProtocol, (VOID **) &loaded_image,
NULL, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
if (EFI_ERROR(err))
return err;
/* close the handle */
(void) uefi_call_wrapper(
BS->CloseProtocol, 4,
loaded_image_handle, &LoadedImageProtocol, NULL, NULL);
err = uefi_call_wrapper(BS->UninstallMultipleProtocolInterfaces, 4,
loaded_image_handle,
&LoadedImageProtocol, loaded_image,
NULL);
if (EFI_ERROR(err))
return err;
loaded_image_handle = NULL;
loaded_image = loaded_image_free(loaded_image);
return EFI_SUCCESS;
}
static inline void cleanup_initrd(EFI_HANDLE *initrd_handle) {
(void) initrd_unregister(*initrd_handle);
*initrd_handle = NULL;
}
static inline void cleanup_loaded_image(EFI_HANDLE *loaded_image_handle) {
(void) loaded_image_unregister(*loaded_image_handle);
*loaded_image_handle = NULL;
}
/* struct to call cleanup_pages */
struct pages {
EFI_PHYSICAL_ADDRESS addr;
UINTN num;
};
static inline void cleanup_pages(struct pages *p) {
if (p->addr == 0)
return;
(void) uefi_call_wrapper(BS->FreePages, 2, p->addr, p->num);
} }
EFI_STATUS linux_exec( EFI_STATUS linux_exec(
EFI_HANDLE image, EFI_HANDLE image,
const CHAR8 *cmdline, UINTN cmdline_len, const CHAR8 *cmdline, UINTN cmdline_len,
const VOID *linux_buffer, const VOID *linux_buffer, UINTN linux_length,
const VOID *initrd_buffer, UINTN initrd_length) { const VOID *initrd_buffer, UINTN initrd_length) {
const struct boot_params *image_params; _cleanup_(cleanup_initrd) EFI_HANDLE initrd_handle = NULL;
struct boot_params *boot_params; _cleanup_(cleanup_loaded_image) EFI_HANDLE loaded_image_handle = NULL;
EFI_HANDLE initrd_handle = NULL; UINT32 kernel_alignment, kernel_size_of_image, kernel_entry_address;
EFI_PHYSICAL_ADDRESS addr; EFI_IMAGE_ENTRY_POINT kernel_entry;
UINT8 setup_sectors; _cleanup_(cleanup_pages) struct pages kernel = {};
VOID *new_buffer;
EFI_STATUS err; EFI_STATUS err;
assert(image); assert(image);
assert(cmdline || cmdline_len == 0); assert(cmdline || cmdline_len == 0);
assert(linux_buffer); assert(linux_buffer && linux_length > 0);
assert(initrd_buffer || initrd_length == 0); assert(initrd_buffer || initrd_length == 0);
image_params = (const struct boot_params *) linux_buffer; /* get the necessary fields from the PE header */
err = pe_alignment_info(linux_buffer, &kernel_entry_address, &kernel_size_of_image, &kernel_alignment);
if (EFI_ERROR(err))
return err;
/* sanity check */
assert(kernel_size_of_image >= linux_length);
if (image_params->hdr.boot_flag != 0xAA55 || /* Linux kernel complains if it's not loaded at a properly aligned memory address. The correct alignment
image_params->hdr.header != SETUP_MAGIC || is provided by Linux as the SegmentAlignment in the PeOptionalHeader. Additionally the kernel needs to
image_params->hdr.version < 0x20b || be in a memory segment thats SizeOfImage (again from PeOptionalHeader) large, so that the Kernel has
!image_params->hdr.relocatable_kernel) space for its BSS section. SizeOfImage is always larger than linux_length, which is only the size of
return EFI_LOAD_ERROR; Code, (static) Data and Headers.
addr = UINT32_MAX; /* Below the 32bit boundary */ Interrestingly only ARM/Aarch64 and RISC-V kernel stubs check these assertions and can even boot (with warnings)
if they are not met. x86 and x86_64 kernel stubs don't do checks and fail if the BSS section is too small.
*/
/* allocate SizeOfImage + SectionAlignment because the new_buffer can move up to Alignment-1 bytes */
kernel.num = EFI_SIZE_TO_PAGES(ALIGN_TO(kernel_size_of_image, kernel_alignment) + kernel_alignment);
err = uefi_call_wrapper( err = uefi_call_wrapper(
BS->AllocatePages, 4, BS->AllocatePages, 4,
AllocateMaxAddress, AllocateAnyPages, EfiLoaderData,
EfiLoaderData, kernel.num, &kernel.addr);
EFI_SIZE_TO_PAGES(0x4000), if (EFI_ERROR(err))
&addr); return EFI_OUT_OF_RESOURCES;
new_buffer = PHYSICAL_ADDRESS_TO_POINTER(ALIGN_TO(kernel.addr, kernel_alignment));
CopyMem(new_buffer, linux_buffer, linux_length);
/* zero out rest of memory (probably not needed, but BSS section should be 0) */
SetMem((UINT8 *)new_buffer + linux_length, kernel_size_of_image - linux_length, 0);
/* get the entry point inside the relocated kernel */
kernel_entry = (EFI_IMAGE_ENTRY_POINT) ((const UINT8 *)new_buffer + kernel_entry_address);
/* register a LoadedImage Protocol in order to pass on the commandline */
err = loaded_image_register(cmdline, cmdline_len, new_buffer, linux_length, &loaded_image_handle);
if (EFI_ERROR(err)) if (EFI_ERROR(err))
return err; return err;
boot_params = (struct boot_params *) PHYSICAL_ADDRESS_TO_POINTER(addr); /* register a LINUX_INITRD_MEDIA DevicePath to serve the initrd */
ZeroMem(boot_params, 0x4000);
boot_params->hdr = image_params->hdr;
boot_params->hdr.type_of_loader = 0xff;
setup_sectors = image_params->hdr.setup_sects > 0 ? image_params->hdr.setup_sects : 4;
boot_params->hdr.code32_start = (UINT32) POINTER_TO_PHYSICAL_ADDRESS(linux_buffer) + (setup_sectors + 1) * 512;
if (cmdline) {
addr = 0xA0000;
err = uefi_call_wrapper(
BS->AllocatePages, 4,
AllocateMaxAddress,
EfiLoaderData,
EFI_SIZE_TO_PAGES(cmdline_len + 1),
&addr);
if (EFI_ERROR(err))
return err;
CopyMem(PHYSICAL_ADDRESS_TO_POINTER(addr), cmdline, cmdline_len);
((CHAR8 *) PHYSICAL_ADDRESS_TO_POINTER(addr))[cmdline_len] = 0;
boot_params->hdr.cmd_line_ptr = (UINT32) addr;
}
/* Providing the initrd via LINUX_INITRD_MEDIA_GUID is only supported by Linux 5.8+ (5.7+ on ARM64).
Until supported kernels become more established, we continue to set ramdisk in the handover struct.
This value is overridden by kernels that support LINUX_INITRD_MEDIA_GUID.
If you need to know which protocol was used by the kernel, pass "efi=debug" to the kernel,
this will print a line when InitrdMediaGuid was successfully used to load the initrd.
*/
boot_params->hdr.ramdisk_image = (UINT32) POINTER_TO_PHYSICAL_ADDRESS(initrd_buffer);
boot_params->hdr.ramdisk_size = (UINT32) initrd_length;
/* register LINUX_INITRD_MEDIA_GUID */
err = initrd_register(initrd_buffer, initrd_length, &initrd_handle); err = initrd_register(initrd_buffer, initrd_length, &initrd_handle);
if (EFI_ERROR(err)) if (EFI_ERROR(err))
return err; return err;
linux_efi_handover(image, boot_params);
(void) initrd_unregister(initrd_handle); /* call the kernel */
initrd_handle = NULL; return uefi_call_wrapper(kernel_entry, 2, loaded_image_handle, ST);
return EFI_LOAD_ERROR;
} }

View File

@ -2,90 +2,9 @@
#pragma once #pragma once
#include <efi.h> #include <efi.h>
#include "macro-fundamental.h"
#define SETUP_MAGIC 0x53726448 /* "HdrS" */
struct setup_header {
UINT8 setup_sects;
UINT16 root_flags;
UINT32 syssize;
UINT16 ram_size;
UINT16 vid_mode;
UINT16 root_dev;
UINT16 boot_flag;
UINT16 jump;
UINT32 header;
UINT16 version;
UINT32 realmode_swtch;
UINT16 start_sys_seg;
UINT16 kernel_version;
UINT8 type_of_loader;
UINT8 loadflags;
UINT16 setup_move_size;
UINT32 code32_start;
UINT32 ramdisk_image;
UINT32 ramdisk_size;
UINT32 bootsect_kludge;
UINT16 heap_end_ptr;
UINT8 ext_loader_ver;
UINT8 ext_loader_type;
UINT32 cmd_line_ptr;
UINT32 initrd_addr_max;
UINT32 kernel_alignment;
UINT8 relocatable_kernel;
UINT8 min_alignment;
UINT16 xloadflags;
UINT32 cmdline_size;
UINT32 hardware_subarch;
UINT64 hardware_subarch_data;
UINT32 payload_offset;
UINT32 payload_length;
UINT64 setup_data;
UINT64 pref_address;
UINT32 init_size;
UINT32 handover_offset;
} _packed_;
/* adapted from linux' bootparam.h */
struct boot_params {
UINT8 screen_info[64]; // was: struct screen_info
UINT8 apm_bios_info[20]; // was: struct apm_bios_info
UINT8 _pad2[4];
UINT64 tboot_addr;
UINT8 ist_info[16]; // was: struct ist_info
UINT8 _pad3[16];
UINT8 hd0_info[16];
UINT8 hd1_info[16];
UINT8 sys_desc_table[16]; // was: struct sys_desc_table
UINT8 olpc_ofw_header[16]; // was: struct olpc_ofw_header
UINT32 ext_ramdisk_image;
UINT32 ext_ramdisk_size;
UINT32 ext_cmd_line_ptr;
UINT8 _pad4[116];
UINT8 edid_info[128]; // was: struct edid_info
UINT8 efi_info[32]; // was: struct efi_info
UINT32 alt_mem_k;
UINT32 scratch;
UINT8 e820_entries;
UINT8 eddbuf_entries;
UINT8 edd_mbr_sig_buf_entries;
UINT8 kbd_status;
UINT8 secure_boot;
UINT8 _pad5[2];
UINT8 sentinel;
UINT8 _pad6[1];
struct setup_header hdr;
UINT8 _pad7[0x290-0x1f1-sizeof(struct setup_header)];
UINT32 edd_mbr_sig_buffer[16]; // was: edd_mbr_sig_buffer[EDD_MBR_SIG_MAX]
UINT8 e820_table[20*128]; // was: struct boot_e820_entry e820_table[E820_MAX_ENTRIES_ZEROPAGE]
UINT8 _pad8[48];
UINT8 eddbuf[6*82]; // was: struct edd_info eddbuf[EDDMAXNR]
UINT8 _pad9[276];
} _packed_;
EFI_STATUS linux_exec( EFI_STATUS linux_exec(
EFI_HANDLE image, EFI_HANDLE image,
const CHAR8 *cmdline, UINTN cmdline_len, const CHAR8 *cmdline, UINTN cmdline_len,
const VOID *linux_buffer, const VOID *linux_buffer, UINTN linux_length,
const VOID *initrd_buffer, UINTN initrd_length); const VOID *initrd_buffer, UINTN initrd_length);

200
src/boot/efi/linux_x86.c Normal file
View File

@ -0,0 +1,200 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* x86 specific code to for EFI handover boot protocol
* Linux kernels version 5.8 and newer support providing the initrd by
* LINUX_INITRD_MEDIA_GUID DevicePath. In order to support older kernels too,
* this x86 specific linux_exec function passes the initrd by setting the
* corresponding fields in the setup_header struct.
*
* see https://www.kernel.org/doc/html/latest/x86/boot.html
*/
#include <efi.h>
#include <efilib.h>
#include "initrd.h"
#include "linux.h"
#include "macro-fundamental.h"
#include "util.h"
#define SETUP_MAGIC 0x53726448 /* "HdrS" */
struct setup_header {
UINT8 setup_sects;
UINT16 root_flags;
UINT32 syssize;
UINT16 ram_size;
UINT16 vid_mode;
UINT16 root_dev;
UINT16 boot_flag;
UINT16 jump;
UINT32 header;
UINT16 version;
UINT32 realmode_swtch;
UINT16 start_sys_seg;
UINT16 kernel_version;
UINT8 type_of_loader;
UINT8 loadflags;
UINT16 setup_move_size;
UINT32 code32_start;
UINT32 ramdisk_image;
UINT32 ramdisk_size;
UINT32 bootsect_kludge;
UINT16 heap_end_ptr;
UINT8 ext_loader_ver;
UINT8 ext_loader_type;
UINT32 cmd_line_ptr;
UINT32 initrd_addr_max;
UINT32 kernel_alignment;
UINT8 relocatable_kernel;
UINT8 min_alignment;
UINT16 xloadflags;
UINT32 cmdline_size;
UINT32 hardware_subarch;
UINT64 hardware_subarch_data;
UINT32 payload_offset;
UINT32 payload_length;
UINT64 setup_data;
UINT64 pref_address;
UINT32 init_size;
UINT32 handover_offset;
} _packed_;
/* adapted from linux' bootparam.h */
struct boot_params {
UINT8 screen_info[64]; // was: struct screen_info
UINT8 apm_bios_info[20]; // was: struct apm_bios_info
UINT8 _pad2[4];
UINT64 tboot_addr;
UINT8 ist_info[16]; // was: struct ist_info
UINT8 _pad3[16];
UINT8 hd0_info[16];
UINT8 hd1_info[16];
UINT8 sys_desc_table[16]; // was: struct sys_desc_table
UINT8 olpc_ofw_header[16]; // was: struct olpc_ofw_header
UINT32 ext_ramdisk_image;
UINT32 ext_ramdisk_size;
UINT32 ext_cmd_line_ptr;
UINT8 _pad4[116];
UINT8 edid_info[128]; // was: struct edid_info
UINT8 efi_info[32]; // was: struct efi_info
UINT32 alt_mem_k;
UINT32 scratch;
UINT8 e820_entries;
UINT8 eddbuf_entries;
UINT8 edd_mbr_sig_buf_entries;
UINT8 kbd_status;
UINT8 secure_boot;
UINT8 _pad5[2];
UINT8 sentinel;
UINT8 _pad6[1];
struct setup_header hdr;
UINT8 _pad7[0x290-0x1f1-sizeof(struct setup_header)];
UINT32 edd_mbr_sig_buffer[16]; // was: edd_mbr_sig_buffer[EDD_MBR_SIG_MAX]
UINT8 e820_table[20*128]; // was: struct boot_e820_entry e820_table[E820_MAX_ENTRIES_ZEROPAGE]
UINT8 _pad8[48];
UINT8 eddbuf[6*82]; // was: struct edd_info eddbuf[EDDMAXNR]
UINT8 _pad9[276];
} _packed_;
#ifdef __i386__
#define __regparm0__ __attribute__((regparm(0)))
#else
#define __regparm0__
#endif
typedef VOID(*handover_f)(VOID *image, EFI_SYSTEM_TABLE *table, struct boot_params *params) __regparm0__;
static VOID linux_efi_handover(EFI_HANDLE image, struct boot_params *params) {
handover_f handover;
UINTN start = (UINTN)params->hdr.code32_start;
assert(params);
#ifdef __x86_64__
asm volatile ("cli");
start += 512;
#endif
handover = (handover_f)(start + params->hdr.handover_offset);
handover(image, ST, params);
}
EFI_STATUS linux_exec(
EFI_HANDLE image,
const CHAR8 *cmdline, UINTN cmdline_len,
const VOID *linux_buffer, UINTN linux_length,
const VOID *initrd_buffer, UINTN initrd_length) {
const struct boot_params *image_params;
struct boot_params *boot_params;
EFI_HANDLE initrd_handle = NULL;
EFI_PHYSICAL_ADDRESS addr;
UINT8 setup_sectors;
EFI_STATUS err;
assert(image);
assert(cmdline || cmdline_len == 0);
assert(linux_buffer);
assert(initrd_buffer || initrd_length == 0);
image_params = (const struct boot_params *) linux_buffer;
if (image_params->hdr.boot_flag != 0xAA55 ||
image_params->hdr.header != SETUP_MAGIC ||
image_params->hdr.version < 0x20b ||
!image_params->hdr.relocatable_kernel)
return EFI_LOAD_ERROR;
addr = UINT32_MAX; /* Below the 32bit boundary */
err = uefi_call_wrapper(
BS->AllocatePages, 4,
AllocateMaxAddress,
EfiLoaderData,
EFI_SIZE_TO_PAGES(0x4000),
&addr);
if (EFI_ERROR(err))
return err;
boot_params = (struct boot_params *) PHYSICAL_ADDRESS_TO_POINTER(addr);
ZeroMem(boot_params, 0x4000);
boot_params->hdr = image_params->hdr;
boot_params->hdr.type_of_loader = 0xff;
setup_sectors = image_params->hdr.setup_sects > 0 ? image_params->hdr.setup_sects : 4;
boot_params->hdr.code32_start = (UINT32) POINTER_TO_PHYSICAL_ADDRESS(linux_buffer) + (setup_sectors + 1) * 512;
if (cmdline) {
addr = 0xA0000;
err = uefi_call_wrapper(
BS->AllocatePages, 4,
AllocateMaxAddress,
EfiLoaderData,
EFI_SIZE_TO_PAGES(cmdline_len + 1),
&addr);
if (EFI_ERROR(err))
return err;
CopyMem(PHYSICAL_ADDRESS_TO_POINTER(addr), cmdline, cmdline_len);
((CHAR8 *) PHYSICAL_ADDRESS_TO_POINTER(addr))[cmdline_len] = 0;
boot_params->hdr.cmd_line_ptr = (UINT32) addr;
}
/* Providing the initrd via LINUX_INITRD_MEDIA_GUID is only supported by Linux 5.8+ (5.7+ on ARM64).
Until supported kernels become more established, we continue to set ramdisk in the handover struct.
This value is overridden by kernels that support LINUX_INITRD_MEDIA_GUID.
If you need to know which protocol was used by the kernel, pass "efi=debug" to the kernel,
this will print a line when InitrdMediaGuid was successfully used to load the initrd.
*/
boot_params->hdr.ramdisk_image = (UINT32) POINTER_TO_PHYSICAL_ADDRESS(initrd_buffer);
boot_params->hdr.ramdisk_size = (UINT32) initrd_length;
/* register LINUX_INITRD_MEDIA_GUID */
err = initrd_register(initrd_buffer, initrd_length, &initrd_handle);
if (EFI_ERROR(err))
return err;
linux_efi_handover(image, boot_params);
(void) initrd_unregister(initrd_handle);
initrd_handle = NULL;
return EFI_LOAD_ERROR;
}

View File

@ -39,7 +39,6 @@ systemd_boot_sources = '''
'''.split() '''.split()
stub_sources = ''' stub_sources = '''
linux.c
initrd.c initrd.c
splash.c splash.c
stub.c stub.c
@ -209,6 +208,11 @@ if have_gnu_efi
'-include', efi_config_h, '-include', efi_config_h,
'-include', version_h, '-include', version_h,
] ]
if ['ia32', 'x86_64'].contains(efi_arch)
stub_sources += 'linux_x86.c'
else
stub_sources += 'linux.c'
endif
if efi_arch == 'x86_64' if efi_arch == 'x86_64'
compile_args += ['-mno-red-zone', compile_args += ['-mno-red-zone',
'-mno-sse', '-mno-sse',

View File

@ -56,10 +56,46 @@ struct CoffFileHeader {
UINT16 Characteristics; UINT16 Characteristics;
} _packed_; } _packed_;
#define OPTHDR32_MAGIC 0x10B /* PE32 OptionalHeader */
#define OPTHDR64_MAGIC 0x20B /* PE32+ OptionalHeader */
struct PeOptionalHeader {
UINT16 Magic;
UINT8 LinkerMajor;
UINT8 LinkerMinor;
UINT32 SizeOfCode;
UINT32 SizeOfInitializedData;
UINT32 SizeOfUninitializeData;
UINT32 AddressOfEntryPoint;
UINT32 BaseOfCode;
union {
struct { /* PE32 */
UINT32 BaseOfData;
UINT32 ImageBase32;
};
UINT64 ImageBase64; /* PE32+ */
};
UINT32 SectionAlignment;
UINT32 FileAlignment;
UINT16 MajorOperatingSystemVersion;
UINT16 MinorOperatingSystemVersion;
UINT16 MajorImageVersion;
UINT16 MinorImageVersion;
UINT16 MajorSubsystemVersion;
UINT16 MinorSubsystemVersion;
UINT32 Win32VersionValue;
UINT32 SizeOfImage;
UINT32 SizeOfHeaders;
UINT32 CheckSum;
UINT16 Subsystem;
UINT16 DllCharacteristics;
/* fields with different sizes for 32/64 omitted */
} _packed_;
struct PeFileHeader { struct PeFileHeader {
UINT8 Magic[4]; UINT8 Magic[4];
struct CoffFileHeader FileHeader; struct CoffFileHeader FileHeader;
/* OptionalHeader omitted */ struct PeOptionalHeader OptionalHeader;
} _packed_; } _packed_;
struct PeSectionHeader { struct PeSectionHeader {
@ -91,7 +127,7 @@ static inline BOOLEAN verify_pe(const struct PeFileHeader *pe) {
static inline UINTN section_table_offset(const struct DosFileHeader *dos, const struct PeFileHeader *pe) { static inline UINTN section_table_offset(const struct DosFileHeader *dos, const struct PeFileHeader *pe) {
assert(dos); assert(dos);
assert(pe); assert(pe);
return dos->ExeHeader + sizeof(struct PeFileHeader) + pe->FileHeader.SizeOfOptionalHeader; return dos->ExeHeader + OFFSETOF(struct PeFileHeader, OptionalHeader) + pe->FileHeader.SizeOfOptionalHeader;
} }
static VOID locate_sections( static VOID locate_sections(
@ -122,6 +158,41 @@ static VOID locate_sections(
} }
} }
EFI_STATUS pe_alignment_info(
const VOID *base,
UINT32 *ret_entry_point_address,
UINT32 *ret_size_of_image,
UINT32 *ret_section_alignment) {
const struct DosFileHeader *dos;
const struct PeFileHeader *pe;
assert(base);
assert(ret_entry_point_address);
assert(ret_size_of_image);
assert(ret_section_alignment);
dos = (const struct DosFileHeader *) base;
if (!verify_dos(dos))
return EFI_LOAD_ERROR;
pe = (const struct PeFileHeader*) ((const UINT8 *)base + dos->ExeHeader);
if (!verify_pe(pe))
return EFI_LOAD_ERROR;
*ret_entry_point_address = pe->OptionalHeader.AddressOfEntryPoint;
if (pe->OptionalHeader.Magic == OPTHDR32_MAGIC) {
*ret_size_of_image = pe->OptionalHeader.SizeOfImage;
*ret_section_alignment = pe->OptionalHeader.SectionAlignment;
} else if (pe->OptionalHeader.Magic == OPTHDR64_MAGIC) {
*ret_size_of_image = pe->OptionalHeader.SizeOfImage;
*ret_section_alignment = pe->OptionalHeader.SectionAlignment;
} else
return EFI_UNSUPPORTED;
return EFI_SUCCESS;
}
EFI_STATUS pe_memory_locate_sections( EFI_STATUS pe_memory_locate_sections(
const CHAR8 *base, const CHAR8 *base,
const CHAR8 **sections, const CHAR8 **sections,

View File

@ -15,3 +15,9 @@ EFI_STATUS pe_file_locate_sections(
const CHAR8 **sections, const CHAR8 **sections,
UINTN *offsets, UINTN *offsets,
UINTN *sizes); UINTN *sizes);
EFI_STATUS pe_alignment_info(
const VOID *base,
UINT32 *ret_entry_point_address,
UINT32 *ret_size_of_image,
UINT32 *ret_section_alignment);

View File

@ -152,7 +152,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
NULL, NULL,
}; };
UINTN cmdline_len = 0, initrd_size, credential_initrd_size = 0, sysext_initrd_size = 0; UINTN cmdline_len = 0, linux_size, initrd_size, credential_initrd_size = 0, sysext_initrd_size = 0;
_cleanup_freepool_ VOID *credential_initrd = NULL, *sysext_initrd = NULL; _cleanup_freepool_ VOID *credential_initrd = NULL, *sysext_initrd = NULL;
EFI_PHYSICAL_ADDRESS linux_base, initrd_base; EFI_PHYSICAL_ADDRESS linux_base, initrd_base;
EFI_LOADED_IMAGE *loaded_image; EFI_LOADED_IMAGE *loaded_image;
@ -222,6 +222,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
&sysext_initrd, &sysext_initrd,
&sysext_initrd_size); &sysext_initrd_size);
linux_size = szs[SECTION_LINUX];
linux_base = POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[SECTION_LINUX]; linux_base = POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[SECTION_LINUX];
initrd_size = szs[SECTION_INITRD]; initrd_size = szs[SECTION_INITRD];
@ -250,7 +251,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
} }
err = linux_exec(image, cmdline, cmdline_len, err = linux_exec(image, cmdline, cmdline_len,
PHYSICAL_ADDRESS_TO_POINTER(linux_base), PHYSICAL_ADDRESS_TO_POINTER(linux_base), linux_size,
PHYSICAL_ADDRESS_TO_POINTER(initrd_base), initrd_size); PHYSICAL_ADDRESS_TO_POINTER(initrd_base), initrd_size);
graphics_mode(FALSE); graphics_mode(FALSE);
return log_error_status_stall(err, L"Execution of embedded linux image failed: %r", err); return log_error_status_stall(err, L"Execution of embedded linux image failed: %r", err);

View File

@ -61,6 +61,7 @@
#endif #endif
#define memcpy(a, b, c) CopyMem((a), (b), (c)) #define memcpy(a, b, c) CopyMem((a), (b), (c))
#define free(a) FreePool(a)
#endif #endif
#if defined(static_assert) #if defined(static_assert)
@ -266,3 +267,9 @@
* @x: a string literal. * @x: a string literal.
*/ */
#define STRLEN(x) (sizeof(""x"") - sizeof(typeof(x[0]))) #define STRLEN(x) (sizeof(""x"") - sizeof(typeof(x[0])))
#define mfree(memory) \
({ \
free(memory); \
(typeof(memory)) NULL; \
})

View File

@ -178,7 +178,7 @@ int device_monitor_new_full(sd_device_monitor **ret, MonitorNetlinkGroup group,
netns = ioctl(m->sock, SIOCGSKNS); netns = ioctl(m->sock, SIOCGSKNS);
if (netns < 0) if (netns < 0)
log_debug_errno(errno, "sd-device-monitor: Unable to get network namespace of udev netlink socket, unable to determine if we are in host netns: %m"); log_debug_errno(errno, "sd-device-monitor: Unable to get network namespace of udev netlink socket, unable to determine if we are in host netns, ignoring: %m");
else { else {
struct stat a, b; struct stat a, b;
@ -191,9 +191,9 @@ int device_monitor_new_full(sd_device_monitor **ret, MonitorNetlinkGroup group,
if (ERRNO_IS_PRIVILEGE(errno)) if (ERRNO_IS_PRIVILEGE(errno))
/* If we can't access PID1's netns info due to permissions, it's fine, this is a /* If we can't access PID1's netns info due to permissions, it's fine, this is a
* safety check only after all. */ * safety check only after all. */
log_debug_errno(errno, "sd-device-monitor: No permission to stat PID1's netns, unable to determine if we are in host netns: %m"); log_debug_errno(errno, "sd-device-monitor: No permission to stat PID1's netns, unable to determine if we are in host netns, ignoring: %m");
else else
log_debug_errno(errno, "sd-device-monitor: Failed to stat PID1's netns: %m"); log_debug_errno(errno, "sd-device-monitor: Failed to stat PID1's netns, ignoring: %m");
} else if (a.st_dev != b.st_dev || a.st_ino != b.st_ino) } else if (a.st_dev != b.st_dev || a.st_ino != b.st_ino)
log_debug("sd-device-monitor: Netlink socket we listen on is not from host netns, we won't see device events."); log_debug("sd-device-monitor: Netlink socket we listen on is not from host netns, we won't see device events.");

View File

@ -28,7 +28,7 @@ teardown() {
run_test() { run_test() {
since="$(date +%T)" since="$(date +%T)"
udevadm trigger -w --action add /dev/null SYSTEMD_LOG_LEVEL=debug udevadm trigger --verbose --settle --action add /dev/null
for _ in {1..20}; do for _ in {1..20}; do
if coredumpctl --since "$since" --no-legend --no-pager | grep /bin/udevadm ; then if coredumpctl --since "$since" --no-legend --no-pager | grep /bin/udevadm ; then

View File

@ -15,7 +15,7 @@ ACTION=="change", SUBSYSTEM=="mem", KERNEL=="null", TAG+="changed"
EOF EOF
udevadm control --reload udevadm control --reload
udevadm trigger --settle --action add /dev/null SYSTEMD_LOG_LEVEL=debug udevadm trigger --verbose --settle --action add /dev/null
test -f /run/udev/tags/added/c1:3 test -f /run/udev/tags/added/c1:3
test ! -f /run/udev/tags/changed/c1:3 test ! -f /run/udev/tags/changed/c1:3
@ -24,7 +24,7 @@ udevadm info /dev/null | grep -q 'E: CURRENT_TAGS=.*:added:.*'
udevadm info /dev/null | grep -q 'E: TAGS=.*:changed:.*' && { echo 'unexpected TAGS='; exit 1; } udevadm info /dev/null | grep -q 'E: TAGS=.*:changed:.*' && { echo 'unexpected TAGS='; exit 1; }
udevadm info /dev/null | grep -q 'E: CURRENT_TAGS=.*:changed:.*' && { echo 'unexpected CURRENT_TAGS='; exit 1; } udevadm info /dev/null | grep -q 'E: CURRENT_TAGS=.*:changed:.*' && { echo 'unexpected CURRENT_TAGS='; exit 1; }
udevadm trigger --settle --action change /dev/null SYSTEMD_LOG_LEVEL=debug udevadm trigger --verbose --settle --action change /dev/null
test -f /run/udev/tags/added/c1:3 test -f /run/udev/tags/added/c1:3
test -f /run/udev/tags/changed/c1:3 test -f /run/udev/tags/changed/c1:3
@ -33,7 +33,7 @@ udevadm info /dev/null | grep -q 'E: CURRENT_TAGS=.*:added:.*' && { echo 'unexpe
udevadm info /dev/null | grep -q 'E: TAGS=.*:changed:.*' udevadm info /dev/null | grep -q 'E: TAGS=.*:changed:.*'
udevadm info /dev/null | grep -q 'E: CURRENT_TAGS=.*:changed:.*' udevadm info /dev/null | grep -q 'E: CURRENT_TAGS=.*:changed:.*'
udevadm trigger --settle --action add /dev/null SYSTEMD_LOG_LEVEL=debug udevadm trigger --verbose --settle --action add /dev/null
test -f /run/udev/tags/added/c1:3 test -f /run/udev/tags/added/c1:3
test -f /run/udev/tags/changed/c1:3 test -f /run/udev/tags/changed/c1:3

View File

@ -10,7 +10,7 @@ ACTION=="add", SUBSYSTEM=="mem", KERNEL=="null", IMPORT{program}="/bin/echo -e H
EOF EOF
udevadm control --reload udevadm control --reload
udevadm trigger --settle --action add /dev/null SYSTEMD_LOG_LEVEL=debug udevadm trigger --verbose --settle --action add /dev/null
test -f /run/udev/data/c1:3 test -f /run/udev/data/c1:3
udevadm info /dev/null | grep -q 'E: HOGE=aa\\x20\\x20\\x20bb' udevadm info /dev/null | grep -q 'E: HOGE=aa\\x20\\x20\\x20bb'

View File

@ -38,7 +38,7 @@ ProtectSystem=strict
Restart=on-failure Restart=on-failure
RestartKillSignal=SIGUSR2 RestartKillSignal=SIGUSR2
RestartSec=0 RestartSec=0
RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_INET AF_INET6 AF_PACKET AF_ALG RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_INET AF_INET6 AF_PACKET
RestrictNamespaces=yes RestrictNamespaces=yes
RestrictRealtime=yes RestrictRealtime=yes
RestrictSUIDSGID=yes RestrictSUIDSGID=yes