mirror of
https://github.com/systemd/systemd
synced 2026-03-30 19:54:51 +02:00
Compare commits
No commits in common. "0a51337df1b40a0799bb17fb4bf95332e0652f28" and "81218ac1e14b4b50b4337938bcf55cacc76f0728" have entirely different histories.
0a51337df1
...
81218ac1e1
@ -2,7 +2,7 @@
|
||||
|
||||
## Main License
|
||||
|
||||
The systemd project uses single-line references to Unique License Identifiers as
|
||||
The systemd project uses single-line references to Unique Licese Identifiers as
|
||||
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.
|
||||
|
||||
@ -47,7 +47,7 @@ The following exceptions apply:
|
||||
- src/basic/siphash24.h
|
||||
- src/systemctl/systemd-sysv-install.SKELETON
|
||||
- tools/check-includes.pl
|
||||
- all examples under man/
|
||||
- all examples, code and scripts, under man/ except where otherwise noted
|
||||
* the following sources are under **Public Domain** (LicenseRef-murmurhash2-public-domain):
|
||||
- src/basic/MurmurHash2.c
|
||||
- src/basic/MurmurHash2.h
|
||||
|
||||
@ -44,49 +44,3 @@ 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!
|
||||
|
||||
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.
|
||||
|
||||
@ -49,6 +49,12 @@ typedef void (*free_func_t)(void *p);
|
||||
|
||||
#define malloc0(n) (calloc(1, (n) ?: 1))
|
||||
|
||||
#define mfree(memory) \
|
||||
({ \
|
||||
free(memory); \
|
||||
(typeof(memory)) NULL; \
|
||||
})
|
||||
|
||||
#define free_and_replace(a, b) \
|
||||
({ \
|
||||
typeof(a)* _a = &(a); \
|
||||
|
||||
@ -1,186 +1,109 @@
|
||||
/* 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 <efilib.h>
|
||||
|
||||
#include "initrd.h"
|
||||
#include "linux.h"
|
||||
#include "pe.h"
|
||||
#include "initrd.h"
|
||||
#include "util.h"
|
||||
|
||||
static EFI_LOADED_IMAGE * loaded_image_free(EFI_LOADED_IMAGE *img) {
|
||||
if (!img)
|
||||
return NULL;
|
||||
mfree(img->LoadOptions);
|
||||
return mfree(img);
|
||||
}
|
||||
#ifdef __i386__
|
||||
#define __regparm0__ __attribute__((regparm(0)))
|
||||
#else
|
||||
#define __regparm0__
|
||||
#endif
|
||||
|
||||
static EFI_STATUS loaded_image_register(
|
||||
const CHAR8 *cmdline, UINTN cmdline_len,
|
||||
const VOID *linux_buffer, UINTN linux_length,
|
||||
EFI_HANDLE *ret_image) {
|
||||
typedef VOID(*handover_f)(VOID *image, EFI_SYSTEM_TABLE *table, struct boot_params *params) __regparm0__;
|
||||
|
||||
EFI_LOADED_IMAGE *loaded_image = NULL;
|
||||
EFI_STATUS err;
|
||||
static VOID linux_efi_handover(EFI_HANDLE image, struct boot_params *params) {
|
||||
handover_f handover;
|
||||
UINTN start = (UINTN)params->hdr.code32_start;
|
||||
|
||||
assert(cmdline || cmdline_len > 0);
|
||||
assert(linux_buffer && linux_length > 0);
|
||||
assert(ret_image);
|
||||
assert(params);
|
||||
|
||||
/* create and install new LoadedImage Protocol */
|
||||
loaded_image = AllocatePool(sizeof(EFI_LOADED_IMAGE));
|
||||
if (!loaded_image)
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
|
||||
/* 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);
|
||||
#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 *linux_buffer,
|
||||
const VOID *initrd_buffer, UINTN initrd_length) {
|
||||
|
||||
_cleanup_(cleanup_initrd) EFI_HANDLE initrd_handle = NULL;
|
||||
_cleanup_(cleanup_loaded_image) EFI_HANDLE loaded_image_handle = NULL;
|
||||
UINT32 kernel_alignment, kernel_size_of_image, kernel_entry_address;
|
||||
EFI_IMAGE_ENTRY_POINT kernel_entry;
|
||||
_cleanup_(cleanup_pages) struct pages kernel = {};
|
||||
VOID *new_buffer;
|
||||
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 && linux_length > 0);
|
||||
assert(linux_buffer);
|
||||
assert(initrd_buffer || initrd_length == 0);
|
||||
|
||||
/* 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);
|
||||
image_params = (const struct boot_params *) linux_buffer;
|
||||
|
||||
/* Linux kernel complains if it's not loaded at a properly aligned memory address. The correct alignment
|
||||
is provided by Linux as the SegmentAlignment in the PeOptionalHeader. Additionally the kernel needs to
|
||||
be in a memory segment thats SizeOfImage (again from PeOptionalHeader) large, so that the Kernel has
|
||||
space for its BSS section. SizeOfImage is always larger than linux_length, which is only the size of
|
||||
Code, (static) Data and Headers.
|
||||
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;
|
||||
|
||||
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);
|
||||
addr = UINT32_MAX; /* Below the 32bit boundary */
|
||||
err = uefi_call_wrapper(
|
||||
BS->AllocatePages, 4,
|
||||
AllocateAnyPages, EfiLoaderData,
|
||||
kernel.num, &kernel.addr);
|
||||
if (EFI_ERROR(err))
|
||||
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);
|
||||
BS->AllocatePages, 4,
|
||||
AllocateMaxAddress,
|
||||
EfiLoaderData,
|
||||
EFI_SIZE_TO_PAGES(0x4000),
|
||||
&addr);
|
||||
if (EFI_ERROR(err))
|
||||
return err;
|
||||
|
||||
/* register a LINUX_INITRD_MEDIA DevicePath to serve the initrd */
|
||||
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;
|
||||
|
||||
/* call the kernel */
|
||||
return uefi_call_wrapper(kernel_entry, 2, loaded_image_handle, ST);
|
||||
linux_efi_handover(image, boot_params);
|
||||
(void) initrd_unregister(initrd_handle);
|
||||
initrd_handle = NULL;
|
||||
return EFI_LOAD_ERROR;
|
||||
}
|
||||
|
||||
@ -2,9 +2,90 @@
|
||||
#pragma once
|
||||
|
||||
#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_HANDLE image,
|
||||
const CHAR8 *cmdline, UINTN cmdline_len,
|
||||
const VOID *linux_buffer, UINTN linux_length,
|
||||
const VOID *linux_buffer,
|
||||
const VOID *initrd_buffer, UINTN initrd_length);
|
||||
|
||||
@ -1,200 +0,0 @@
|
||||
/* 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;
|
||||
}
|
||||
@ -39,6 +39,7 @@ systemd_boot_sources = '''
|
||||
'''.split()
|
||||
|
||||
stub_sources = '''
|
||||
linux.c
|
||||
initrd.c
|
||||
splash.c
|
||||
stub.c
|
||||
@ -208,11 +209,6 @@ if have_gnu_efi
|
||||
'-include', efi_config_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'
|
||||
compile_args += ['-mno-red-zone',
|
||||
'-mno-sse',
|
||||
|
||||
@ -56,46 +56,10 @@ struct CoffFileHeader {
|
||||
UINT16 Characteristics;
|
||||
} _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 {
|
||||
UINT8 Magic[4];
|
||||
struct CoffFileHeader FileHeader;
|
||||
struct PeOptionalHeader OptionalHeader;
|
||||
/* OptionalHeader omitted */
|
||||
} _packed_;
|
||||
|
||||
struct PeSectionHeader {
|
||||
@ -127,7 +91,7 @@ static inline BOOLEAN verify_pe(const struct PeFileHeader *pe) {
|
||||
static inline UINTN section_table_offset(const struct DosFileHeader *dos, const struct PeFileHeader *pe) {
|
||||
assert(dos);
|
||||
assert(pe);
|
||||
return dos->ExeHeader + OFFSETOF(struct PeFileHeader, OptionalHeader) + pe->FileHeader.SizeOfOptionalHeader;
|
||||
return dos->ExeHeader + sizeof(struct PeFileHeader) + pe->FileHeader.SizeOfOptionalHeader;
|
||||
}
|
||||
|
||||
static VOID locate_sections(
|
||||
@ -158,41 +122,6 @@ 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(
|
||||
const CHAR8 *base,
|
||||
const CHAR8 **sections,
|
||||
|
||||
@ -15,9 +15,3 @@ EFI_STATUS pe_file_locate_sections(
|
||||
const CHAR8 **sections,
|
||||
UINTN *offsets,
|
||||
UINTN *sizes);
|
||||
|
||||
EFI_STATUS pe_alignment_info(
|
||||
const VOID *base,
|
||||
UINT32 *ret_entry_point_address,
|
||||
UINT32 *ret_size_of_image,
|
||||
UINT32 *ret_section_alignment);
|
||||
|
||||
@ -152,7 +152,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
NULL,
|
||||
};
|
||||
|
||||
UINTN cmdline_len = 0, linux_size, initrd_size, credential_initrd_size = 0, sysext_initrd_size = 0;
|
||||
UINTN cmdline_len = 0, initrd_size, credential_initrd_size = 0, sysext_initrd_size = 0;
|
||||
_cleanup_freepool_ VOID *credential_initrd = NULL, *sysext_initrd = NULL;
|
||||
EFI_PHYSICAL_ADDRESS linux_base, initrd_base;
|
||||
EFI_LOADED_IMAGE *loaded_image;
|
||||
@ -222,7 +222,6 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
&sysext_initrd,
|
||||
&sysext_initrd_size);
|
||||
|
||||
linux_size = szs[SECTION_LINUX];
|
||||
linux_base = POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[SECTION_LINUX];
|
||||
|
||||
initrd_size = szs[SECTION_INITRD];
|
||||
@ -251,7 +250,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
}
|
||||
|
||||
err = linux_exec(image, cmdline, cmdline_len,
|
||||
PHYSICAL_ADDRESS_TO_POINTER(linux_base), linux_size,
|
||||
PHYSICAL_ADDRESS_TO_POINTER(linux_base),
|
||||
PHYSICAL_ADDRESS_TO_POINTER(initrd_base), initrd_size);
|
||||
graphics_mode(FALSE);
|
||||
return log_error_status_stall(err, L"Execution of embedded linux image failed: %r", err);
|
||||
|
||||
@ -61,7 +61,6 @@
|
||||
#endif
|
||||
|
||||
#define memcpy(a, b, c) CopyMem((a), (b), (c))
|
||||
#define free(a) FreePool(a)
|
||||
#endif
|
||||
|
||||
#if defined(static_assert)
|
||||
@ -267,9 +266,3 @@
|
||||
* @x: a string literal.
|
||||
*/
|
||||
#define STRLEN(x) (sizeof(""x"") - sizeof(typeof(x[0])))
|
||||
|
||||
#define mfree(memory) \
|
||||
({ \
|
||||
free(memory); \
|
||||
(typeof(memory)) NULL; \
|
||||
})
|
||||
|
||||
@ -178,7 +178,7 @@ int device_monitor_new_full(sd_device_monitor **ret, MonitorNetlinkGroup group,
|
||||
|
||||
netns = ioctl(m->sock, SIOCGSKNS);
|
||||
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, ignoring: %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: %m");
|
||||
else {
|
||||
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 we can't access PID1's netns info due to permissions, it's fine, this is a
|
||||
* 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, ignoring: %m");
|
||||
log_debug_errno(errno, "sd-device-monitor: No permission to stat PID1's netns, unable to determine if we are in host netns: %m");
|
||||
else
|
||||
log_debug_errno(errno, "sd-device-monitor: Failed to stat PID1's netns, ignoring: %m");
|
||||
log_debug_errno(errno, "sd-device-monitor: Failed to stat PID1's netns: %m");
|
||||
|
||||
} 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.");
|
||||
|
||||
@ -28,7 +28,7 @@ teardown() {
|
||||
run_test() {
|
||||
since="$(date +%T)"
|
||||
|
||||
SYSTEMD_LOG_LEVEL=debug udevadm trigger --verbose --settle --action add /dev/null
|
||||
udevadm trigger -w --action add /dev/null
|
||||
|
||||
for _ in {1..20}; do
|
||||
if coredumpctl --since "$since" --no-legend --no-pager | grep /bin/udevadm ; then
|
||||
|
||||
@ -15,7 +15,7 @@ ACTION=="change", SUBSYSTEM=="mem", KERNEL=="null", TAG+="changed"
|
||||
EOF
|
||||
|
||||
udevadm control --reload
|
||||
SYSTEMD_LOG_LEVEL=debug udevadm trigger --verbose --settle --action add /dev/null
|
||||
udevadm trigger --settle --action add /dev/null
|
||||
|
||||
test -f /run/udev/tags/added/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: CURRENT_TAGS=.*:changed:.*' && { echo 'unexpected CURRENT_TAGS='; exit 1; }
|
||||
|
||||
SYSTEMD_LOG_LEVEL=debug udevadm trigger --verbose --settle --action change /dev/null
|
||||
udevadm trigger --settle --action change /dev/null
|
||||
|
||||
test -f /run/udev/tags/added/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: CURRENT_TAGS=.*:changed:.*'
|
||||
|
||||
SYSTEMD_LOG_LEVEL=debug udevadm trigger --verbose --settle --action add /dev/null
|
||||
udevadm trigger --settle --action add /dev/null
|
||||
|
||||
test -f /run/udev/tags/added/c1:3
|
||||
test -f /run/udev/tags/changed/c1:3
|
||||
|
||||
@ -10,7 +10,7 @@ ACTION=="add", SUBSYSTEM=="mem", KERNEL=="null", IMPORT{program}="/bin/echo -e H
|
||||
EOF
|
||||
|
||||
udevadm control --reload
|
||||
SYSTEMD_LOG_LEVEL=debug udevadm trigger --verbose --settle --action add /dev/null
|
||||
udevadm trigger --settle --action add /dev/null
|
||||
|
||||
test -f /run/udev/data/c1:3
|
||||
udevadm info /dev/null | grep -q 'E: HOGE=aa\\x20\\x20\\x20bb'
|
||||
|
||||
@ -38,7 +38,7 @@ ProtectSystem=strict
|
||||
Restart=on-failure
|
||||
RestartKillSignal=SIGUSR2
|
||||
RestartSec=0
|
||||
RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_INET AF_INET6 AF_PACKET
|
||||
RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_INET AF_INET6 AF_PACKET AF_ALG
|
||||
RestrictNamespaces=yes
|
||||
RestrictRealtime=yes
|
||||
RestrictSUIDSGID=yes
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user