More EFI changes for v5.8:
- Rename pr_efi/pr_efi_err to efi_info/efi_err, and use them consistently - Simplify and unify initrd loading - Parse the builtin command line on x86 (if provided) - Implement printk() support, including support for wide character strings - Some fixes for issues introduced by the first batch of v5.8 changes - Fix a missing prototypes warning - Simplify GDT handling in early mixed mode thunking code - Some other minor fixes and cleanups -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEnNKg2mrY9zMBdeK7wjcgfpV0+n0FAl7Lb8UACgkQwjcgfpV0 +n3/aAgAkEqqR/BoyzFiyYHujq6bXjESKYr8LrIjNWfnofB6nZqp1yXwFdL0qbj/ PTZ1qIQAnOMmj11lvy1X894h2ZLqE6XEkqv7Xd2oxkh3fF6amlQUWfMpXUuGLo1k C4QGSfA0OOiM0OOi0Aqk1fL7sTmH23/j63dTR+fH8JMuYgjdls/yWNs0miqf8W2H ftj8fAKgHIJzFvdTC0vn1DZ6dEKczGLPEcVZ2ns2IJOJ69DsStKPLcD0mlW+EgV2 EyfRSCQv55RYZRhdUOb+yVLRfU0M0IMDrrCDErHxZHXnQy00tmKXiEL20yuegv3u MUtRRw8ocn2/RskjgZkxtMjAAlty9A== =AwCh -----END PGP SIGNATURE----- Merge tag 'efi-changes-for-v5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi into efi/core More EFI changes for v5.8: - Rename pr_efi/pr_efi_err to efi_info/efi_err, and use them consistently - Simplify and unify initrd loading - Parse the builtin command line on x86 (if provided) - Implement printk() support, including support for wide character strings - Some fixes for issues introduced by the first batch of v5.8 changes - Fix a missing prototypes warning - Simplify GDT handling in early mixed mode thunking code - Some other minor fixes and cleanups Conflicts: drivers/firmware/efi/libstub/efistub.h Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
d1343da330
|
@ -63,4 +63,9 @@ auto
|
|||
with the highest resolution, it will choose one with the highest color
|
||||
depth.
|
||||
|
||||
list
|
||||
The EFI stub will list out all the display modes that are available. A
|
||||
specific mode can then be chosen using one of the above options for the
|
||||
next boot.
|
||||
|
||||
Edgar Hucek <gimli@dark-green.com>
|
||||
|
|
|
@ -60,7 +60,7 @@ optional_header:
|
|||
.long __pecoff_code_size @ SizeOfCode
|
||||
.long __pecoff_data_size @ SizeOfInitializedData
|
||||
.long 0 @ SizeOfUninitializedData
|
||||
.long efi_entry - start @ AddressOfEntryPoint
|
||||
.long efi_pe_entry - start @ AddressOfEntryPoint
|
||||
.long start_offset @ BaseOfCode
|
||||
.long __pecoff_data_start - start @ BaseOfData
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
SYM_CODE_START(efi_enter_kernel)
|
||||
/*
|
||||
* efi_entry() will have copied the kernel image if necessary and we
|
||||
* efi_pe_entry() will have copied the kernel image if necessary and we
|
||||
* end up here with device tree address in x1 and the kernel entry
|
||||
* point stored in x0. Save those values in registers which are
|
||||
* callee preserved.
|
||||
|
|
|
@ -27,7 +27,7 @@ optional_header:
|
|||
.long __initdata_begin - efi_header_end // SizeOfCode
|
||||
.long __pecoff_data_size // SizeOfInitializedData
|
||||
.long 0 // SizeOfUninitializedData
|
||||
.long __efistub_efi_entry - _head // AddressOfEntryPoint
|
||||
.long __efistub_efi_pe_entry - _head // AddressOfEntryPoint
|
||||
.long efi_header_end - _head // BaseOfCode
|
||||
|
||||
extra_header_fields:
|
||||
|
|
|
@ -28,8 +28,6 @@ SYM_FUNC_START(__efi64_thunk)
|
|||
push %rbx
|
||||
|
||||
leaq 1f(%rip), %rbp
|
||||
leaq efi_gdt64(%rip), %rbx
|
||||
movl %ebx, 2(%rbx) /* Fixup the gdt base address */
|
||||
|
||||
movl %ds, %eax
|
||||
push %rax
|
||||
|
@ -48,7 +46,8 @@ SYM_FUNC_START(__efi64_thunk)
|
|||
movl %r8d, 0xc(%rsp)
|
||||
movl %r9d, 0x10(%rsp)
|
||||
|
||||
sgdt 0x14(%rsp)
|
||||
leaq 0x14(%rsp), %rbx
|
||||
sgdt (%rbx)
|
||||
|
||||
/*
|
||||
* Switch to gdt with 32-bit segments. This is the firmware GDT
|
||||
|
@ -68,8 +67,7 @@ SYM_FUNC_START(__efi64_thunk)
|
|||
pushq %rax
|
||||
lretq
|
||||
|
||||
1: lgdt 0x14(%rsp)
|
||||
addq $32, %rsp
|
||||
1: addq $32, %rsp
|
||||
movq %rdi, %rax
|
||||
|
||||
pop %rbx
|
||||
|
@ -175,14 +173,3 @@ SYM_DATA_END(efi32_boot_cs)
|
|||
SYM_DATA_START(efi32_boot_ds)
|
||||
.word 0
|
||||
SYM_DATA_END(efi32_boot_ds)
|
||||
|
||||
SYM_DATA_START(efi_gdt64)
|
||||
.word efi_gdt64_end - efi_gdt64
|
||||
.long 0 /* Filled out by user */
|
||||
.word 0
|
||||
.quad 0x0000000000000000 /* NULL descriptor */
|
||||
.quad 0x00af9a000000ffff /* __KERNEL_CS */
|
||||
.quad 0x00cf92000000ffff /* __KERNEL_DS */
|
||||
.quad 0x0080890000000000 /* TS descriptor */
|
||||
.quad 0x0000000000000000 /* TS continued */
|
||||
SYM_DATA_END_LABEL(efi_gdt64, SYM_L_LOCAL, efi_gdt64_end)
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <asm/nospec-branch.h>
|
||||
#include <asm/mmu_context.h>
|
||||
#include <linux/build_bug.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
extern unsigned long efi_fw_vendor, efi_config_table;
|
||||
|
||||
|
@ -225,13 +226,15 @@ efi_status_t efi_set_virtual_address_map(unsigned long memory_map_size,
|
|||
|
||||
/* arch specific definitions used by the stub code */
|
||||
|
||||
extern const bool efi_is64;
|
||||
#ifdef CONFIG_EFI_MIXED
|
||||
|
||||
#define ARCH_HAS_EFISTUB_WRAPPERS
|
||||
|
||||
static inline bool efi_is_64bit(void)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_EFI_MIXED))
|
||||
return efi_is64;
|
||||
return IS_ENABLED(CONFIG_X86_64);
|
||||
extern const bool efi_is64;
|
||||
|
||||
return efi_is64;
|
||||
}
|
||||
|
||||
static inline bool efi_is_native(void)
|
||||
|
@ -291,6 +294,15 @@ static inline u32 efi64_convert_status(efi_status_t status)
|
|||
#define __efi64_argmap_allocate_pool(type, size, buffer) \
|
||||
((type), (size), efi64_zero_upper(buffer))
|
||||
|
||||
#define __efi64_argmap_create_event(type, tpl, f, c, event) \
|
||||
((type), (tpl), (f), (c), efi64_zero_upper(event))
|
||||
|
||||
#define __efi64_argmap_set_timer(event, type, time) \
|
||||
((event), (type), lower_32_bits(time), upper_32_bits(time))
|
||||
|
||||
#define __efi64_argmap_wait_for_event(num, event, index) \
|
||||
((num), (event), efi64_zero_upper(index))
|
||||
|
||||
#define __efi64_argmap_handle_protocol(handle, protocol, interface) \
|
||||
((handle), (protocol), efi64_zero_upper(interface))
|
||||
|
||||
|
@ -356,6 +368,15 @@ static inline u32 efi64_convert_status(efi_status_t status)
|
|||
runtime), \
|
||||
func, __VA_ARGS__))
|
||||
|
||||
#else /* CONFIG_EFI_MIXED */
|
||||
|
||||
static inline bool efi_is_64bit(void)
|
||||
{
|
||||
return IS_ENABLED(CONFIG_X86_64);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_EFI_MIXED */
|
||||
|
||||
extern bool efi_reboot_required(void);
|
||||
extern bool efi_is_table_address(unsigned long phys_addr);
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ static efi_system_table_t efi_systab_xen __initdata = {
|
|||
.fw_vendor = EFI_INVALID_TABLE_ADDR, /* Initialized later. */
|
||||
.fw_revision = 0, /* Initialized later. */
|
||||
.con_in_handle = EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */
|
||||
.con_in = EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */
|
||||
.con_in = NULL, /* Not used under Xen. */
|
||||
.con_out_handle = EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */
|
||||
.con_out = NULL, /* Not used under Xen. */
|
||||
.stderr_handle = EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */
|
||||
|
|
|
@ -522,8 +522,10 @@ efivar_create_sysfs_entry(struct efivar_entry *new_var)
|
|||
ret = kobject_init_and_add(&new_var->kobj, &efivar_ktype,
|
||||
NULL, "%s", short_name);
|
||||
kfree(short_name);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
kobject_put(&new_var->kobj);
|
||||
return ret;
|
||||
}
|
||||
|
||||
kobject_uevent(&new_var->kobj, KOBJ_ADD);
|
||||
if (efivar_entry_add(new_var, &efivar_sysfs_list)) {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#
|
||||
cflags-$(CONFIG_X86_32) := -march=i386
|
||||
cflags-$(CONFIG_X86_64) := -mcmodel=small
|
||||
cflags-$(CONFIG_X86) += -m$(BITS) -D__KERNEL__ -O2 \
|
||||
cflags-$(CONFIG_X86) += -m$(BITS) -D__KERNEL__ \
|
||||
-fPIC -fno-strict-aliasing -mno-red-zone \
|
||||
-mno-mmx -mno-sse -fshort-wchar \
|
||||
-Wno-pointer-sign \
|
||||
|
@ -25,11 +25,12 @@ cflags-$(CONFIG_ARM) := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) \
|
|||
|
||||
cflags-$(CONFIG_EFI_GENERIC_STUB) += -I$(srctree)/scripts/dtc/libfdt
|
||||
|
||||
KBUILD_CFLAGS := $(cflags-y) -DDISABLE_BRANCH_PROFILING \
|
||||
KBUILD_CFLAGS := $(cflags-y) -Os -DDISABLE_BRANCH_PROFILING \
|
||||
-include $(srctree)/drivers/firmware/efi/libstub/hidden.h \
|
||||
-D__NO_FORTIFY \
|
||||
$(call cc-option,-ffreestanding) \
|
||||
$(call cc-option,-fno-stack-protector) \
|
||||
$(call cc-option,-fno-addrsig) \
|
||||
-D__DISABLE_EXPORTS
|
||||
|
||||
GCOV_PROFILE := n
|
||||
|
@ -43,7 +44,7 @@ KCOV_INSTRUMENT := n
|
|||
lib-y := efi-stub-helper.o gop.o secureboot.o tpm.o \
|
||||
file.o mem.o random.o randomalloc.o pci.o \
|
||||
skip_spaces.o lib-cmdline.o lib-ctype.o \
|
||||
alignedmem.o relocate.o
|
||||
alignedmem.o relocate.o vsprintf.o
|
||||
|
||||
# include the stub's generic dependencies from lib/ when building for ARM/arm64
|
||||
efi-deps-y := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c fdt_empty_tree.c fdt_sw.c
|
||||
|
|
|
@ -18,7 +18,7 @@ efi_status_t check_platform_features(void)
|
|||
/* LPAE kernels need compatible hardware */
|
||||
block = cpuid_feature_extract(CPUID_EXT_MMFR0, 0);
|
||||
if (block < 5) {
|
||||
pr_efi_err("This LPAE kernel is not supported by your CPU\n");
|
||||
efi_err("This LPAE kernel is not supported by your CPU\n");
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
return EFI_SUCCESS;
|
||||
|
@ -120,7 +120,7 @@ static efi_status_t reserve_kernel_base(unsigned long dram_base,
|
|||
*/
|
||||
status = efi_get_memory_map(&map);
|
||||
if (status != EFI_SUCCESS) {
|
||||
pr_efi_err("reserve_kernel_base(): Unable to retrieve memory map.\n");
|
||||
efi_err("reserve_kernel_base(): Unable to retrieve memory map.\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -162,7 +162,7 @@ static efi_status_t reserve_kernel_base(unsigned long dram_base,
|
|||
(end - start) / EFI_PAGE_SIZE,
|
||||
&start);
|
||||
if (status != EFI_SUCCESS) {
|
||||
pr_efi_err("reserve_kernel_base(): alloc failed.\n");
|
||||
efi_err("reserve_kernel_base(): alloc failed.\n");
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
|
@ -219,7 +219,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
|
|||
|
||||
status = reserve_kernel_base(kernel_base, reserve_addr, reserve_size);
|
||||
if (status != EFI_SUCCESS) {
|
||||
pr_efi_err("Unable to allocate memory for uncompressed kernel.\n");
|
||||
efi_err("Unable to allocate memory for uncompressed kernel.\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -232,7 +232,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
|
|||
status = efi_relocate_kernel(image_addr, *image_size, *image_size,
|
||||
kernel_base + MAX_UNCOMP_KERNEL_SIZE, 0, 0);
|
||||
if (status != EFI_SUCCESS) {
|
||||
pr_efi_err("Failed to relocate kernel.\n");
|
||||
efi_err("Failed to relocate kernel.\n");
|
||||
efi_free(*reserve_size, *reserve_addr);
|
||||
*reserve_size = 0;
|
||||
return status;
|
||||
|
@ -244,7 +244,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
|
|||
* address at which the zImage is loaded.
|
||||
*/
|
||||
if (*image_addr + *image_size > dram_base + ZIMAGE_OFFSET_LIMIT) {
|
||||
pr_efi_err("Failed to relocate kernel, no low memory available.\n");
|
||||
efi_err("Failed to relocate kernel, no low memory available.\n");
|
||||
efi_free(*reserve_size, *reserve_addr);
|
||||
*reserve_size = 0;
|
||||
efi_free(*image_size, *image_addr);
|
||||
|
|
|
@ -26,9 +26,9 @@ efi_status_t check_platform_features(void)
|
|||
tg = (read_cpuid(ID_AA64MMFR0_EL1) >> ID_AA64MMFR0_TGRAN_SHIFT) & 0xf;
|
||||
if (tg != ID_AA64MMFR0_TGRAN_SUPPORTED) {
|
||||
if (IS_ENABLED(CONFIG_ARM64_64K_PAGES))
|
||||
pr_efi_err("This 64 KB granular kernel is not supported by your CPU\n");
|
||||
efi_err("This 64 KB granular kernel is not supported by your CPU\n");
|
||||
else
|
||||
pr_efi_err("This 16 KB granular kernel is not supported by your CPU\n");
|
||||
efi_err("This 16 KB granular kernel is not supported by your CPU\n");
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
return EFI_SUCCESS;
|
||||
|
@ -59,18 +59,18 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
|
|||
status = efi_get_random_bytes(sizeof(phys_seed),
|
||||
(u8 *)&phys_seed);
|
||||
if (status == EFI_NOT_FOUND) {
|
||||
pr_efi("EFI_RNG_PROTOCOL unavailable, no randomness supplied\n");
|
||||
efi_info("EFI_RNG_PROTOCOL unavailable, no randomness supplied\n");
|
||||
} else if (status != EFI_SUCCESS) {
|
||||
pr_efi_err("efi_get_random_bytes() failed\n");
|
||||
efi_err("efi_get_random_bytes() failed\n");
|
||||
return status;
|
||||
}
|
||||
} else {
|
||||
pr_efi("KASLR disabled on kernel command line\n");
|
||||
efi_info("KASLR disabled on kernel command line\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (image->image_base != _text)
|
||||
pr_efi_err("FIRMWARE BUG: efi_loaded_image_t::image_base has bogus value\n");
|
||||
efi_err("FIRMWARE BUG: efi_loaded_image_t::image_base has bogus value\n");
|
||||
|
||||
kernel_size = _edata - _text;
|
||||
kernel_memsize = kernel_size + (_end - _edata);
|
||||
|
@ -102,7 +102,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
|
|||
ULONG_MAX, min_kimg_align);
|
||||
|
||||
if (status != EFI_SUCCESS) {
|
||||
pr_efi_err("Failed to relocate kernel\n");
|
||||
efi_err("Failed to relocate kernel\n");
|
||||
*reserve_size = 0;
|
||||
return status;
|
||||
}
|
||||
|
|
|
@ -7,15 +7,21 @@
|
|||
* Copyright 2011 Intel Corporation; author Matt Fleming
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/efi.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/printk.h> /* For CONSOLE_LOGLEVEL_* */
|
||||
#include <asm/efi.h>
|
||||
#include <asm/setup.h>
|
||||
|
||||
#include "efistub.h"
|
||||
|
||||
bool efi_nochunk;
|
||||
bool efi_nokaslr;
|
||||
bool efi_noinitrd;
|
||||
bool efi_quiet;
|
||||
int efi_loglevel = CONSOLE_LOGLEVEL_DEFAULT;
|
||||
bool efi_novamap;
|
||||
|
||||
static bool efi_nosoftreserve;
|
||||
|
@ -26,21 +32,126 @@ bool __pure __efi_soft_reserve_enabled(void)
|
|||
return !efi_nosoftreserve;
|
||||
}
|
||||
|
||||
void efi_printk(char *str)
|
||||
void efi_char16_puts(efi_char16_t *str)
|
||||
{
|
||||
char *s8;
|
||||
efi_call_proto(efi_table_attr(efi_system_table, con_out),
|
||||
output_string, str);
|
||||
}
|
||||
|
||||
for (s8 = str; *s8; s8++) {
|
||||
efi_char16_t ch[2] = { 0 };
|
||||
static
|
||||
u32 utf8_to_utf32(const u8 **s8)
|
||||
{
|
||||
u32 c32;
|
||||
u8 c0, cx;
|
||||
size_t clen, i;
|
||||
|
||||
ch[0] = *s8;
|
||||
if (*s8 == '\n') {
|
||||
efi_char16_t nl[2] = { '\r', 0 };
|
||||
efi_char16_printk(nl);
|
||||
}
|
||||
|
||||
efi_char16_printk(ch);
|
||||
c0 = cx = *(*s8)++;
|
||||
/*
|
||||
* The position of the most-significant 0 bit gives us the length of
|
||||
* a multi-octet encoding.
|
||||
*/
|
||||
for (clen = 0; cx & 0x80; ++clen)
|
||||
cx <<= 1;
|
||||
/*
|
||||
* If the 0 bit is in position 8, this is a valid single-octet
|
||||
* encoding. If the 0 bit is in position 7 or positions 1-3, the
|
||||
* encoding is invalid.
|
||||
* In either case, we just return the first octet.
|
||||
*/
|
||||
if (clen < 2 || clen > 4)
|
||||
return c0;
|
||||
/* Get the bits from the first octet. */
|
||||
c32 = cx >> clen--;
|
||||
for (i = 0; i < clen; ++i) {
|
||||
/* Trailing octets must have 10 in most significant bits. */
|
||||
cx = (*s8)[i] ^ 0x80;
|
||||
if (cx & 0xc0)
|
||||
return c0;
|
||||
c32 = (c32 << 6) | cx;
|
||||
}
|
||||
/*
|
||||
* Check for validity:
|
||||
* - The character must be in the Unicode range.
|
||||
* - It must not be a surrogate.
|
||||
* - It must be encoded using the correct number of octets.
|
||||
*/
|
||||
if (c32 > 0x10ffff ||
|
||||
(c32 & 0xf800) == 0xd800 ||
|
||||
clen != (c32 >= 0x80) + (c32 >= 0x800) + (c32 >= 0x10000))
|
||||
return c0;
|
||||
*s8 += clen;
|
||||
return c32;
|
||||
}
|
||||
|
||||
void efi_puts(const char *str)
|
||||
{
|
||||
efi_char16_t buf[128];
|
||||
size_t pos = 0, lim = ARRAY_SIZE(buf);
|
||||
const u8 *s8 = (const u8 *)str;
|
||||
u32 c32;
|
||||
|
||||
while (*s8) {
|
||||
if (*s8 == '\n')
|
||||
buf[pos++] = L'\r';
|
||||
c32 = utf8_to_utf32(&s8);
|
||||
if (c32 < 0x10000) {
|
||||
/* Characters in plane 0 use a single word. */
|
||||
buf[pos++] = c32;
|
||||
} else {
|
||||
/*
|
||||
* Characters in other planes encode into a surrogate
|
||||
* pair.
|
||||
*/
|
||||
buf[pos++] = (0xd800 - (0x10000 >> 10)) + (c32 >> 10);
|
||||
buf[pos++] = 0xdc00 + (c32 & 0x3ff);
|
||||
}
|
||||
if (*s8 == '\0' || pos >= lim - 2) {
|
||||
buf[pos] = L'\0';
|
||||
efi_char16_puts(buf);
|
||||
pos = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int efi_printk(const char *fmt, ...)
|
||||
{
|
||||
char printf_buf[256];
|
||||
va_list args;
|
||||
int printed;
|
||||
int loglevel = printk_get_level(fmt);
|
||||
|
||||
switch (loglevel) {
|
||||
case '0' ... '9':
|
||||
loglevel -= '0';
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* Use loglevel -1 for cases where we just want to print to
|
||||
* the screen.
|
||||
*/
|
||||
loglevel = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (loglevel >= efi_loglevel)
|
||||
return 0;
|
||||
|
||||
if (loglevel >= 0)
|
||||
efi_puts("EFI stub: ");
|
||||
|
||||
fmt = printk_skip_level(fmt);
|
||||
|
||||
va_start(args, fmt);
|
||||
printed = vsnprintf(printf_buf, sizeof(printf_buf), fmt, args);
|
||||
va_end(args);
|
||||
|
||||
efi_puts(printf_buf);
|
||||
if (printed >= sizeof(printf_buf)) {
|
||||
efi_puts("[Message truncated]\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return printed;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -71,7 +182,7 @@ efi_status_t efi_parse_options(char const *cmdline)
|
|||
if (!strcmp(param, "nokaslr")) {
|
||||
efi_nokaslr = true;
|
||||
} else if (!strcmp(param, "quiet")) {
|
||||
efi_quiet = true;
|
||||
efi_loglevel = CONSOLE_LOGLEVEL_QUIET;
|
||||
} else if (!strcmp(param, "noinitrd")) {
|
||||
efi_noinitrd = true;
|
||||
} else if (!strcmp(param, "efi") && val) {
|
||||
|
@ -85,6 +196,8 @@ efi_status_t efi_parse_options(char const *cmdline)
|
|||
efi_disable_pci_dma = true;
|
||||
if (parse_option_str(val, "no_disable_early_pci_dma"))
|
||||
efi_disable_pci_dma = false;
|
||||
if (parse_option_str(val, "debug"))
|
||||
efi_loglevel = CONSOLE_LOGLEVEL_DEBUG;
|
||||
} else if (!strcmp(param, "video") &&
|
||||
val && strstarts(val, "efifb:")) {
|
||||
efi_parse_option_graphics(val + strlen("efifb:"));
|
||||
|
@ -94,98 +207,80 @@ efi_status_t efi_parse_options(char const *cmdline)
|
|||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the number of UTF-8 bytes corresponding to an UTF-16 character.
|
||||
* This overestimates for surrogates, but that is okay.
|
||||
*/
|
||||
static int efi_utf8_bytes(u16 c)
|
||||
{
|
||||
return 1 + (c >= 0x80) + (c >= 0x800);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert an UTF-16 string, not necessarily null terminated, to UTF-8.
|
||||
*/
|
||||
static u8 *efi_utf16_to_utf8(u8 *dst, const u16 *src, int n)
|
||||
{
|
||||
unsigned int c;
|
||||
|
||||
while (n--) {
|
||||
c = *src++;
|
||||
if (n && c >= 0xd800 && c <= 0xdbff &&
|
||||
*src >= 0xdc00 && *src <= 0xdfff) {
|
||||
c = 0x10000 + ((c & 0x3ff) << 10) + (*src & 0x3ff);
|
||||
src++;
|
||||
n--;
|
||||
}
|
||||
if (c >= 0xd800 && c <= 0xdfff)
|
||||
c = 0xfffd; /* Unmatched surrogate */
|
||||
if (c < 0x80) {
|
||||
*dst++ = c;
|
||||
continue;
|
||||
}
|
||||
if (c < 0x800) {
|
||||
*dst++ = 0xc0 + (c >> 6);
|
||||
goto t1;
|
||||
}
|
||||
if (c < 0x10000) {
|
||||
*dst++ = 0xe0 + (c >> 12);
|
||||
goto t2;
|
||||
}
|
||||
*dst++ = 0xf0 + (c >> 18);
|
||||
*dst++ = 0x80 + ((c >> 12) & 0x3f);
|
||||
t2:
|
||||
*dst++ = 0x80 + ((c >> 6) & 0x3f);
|
||||
t1:
|
||||
*dst++ = 0x80 + (c & 0x3f);
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert the unicode UEFI command line to ASCII to pass to kernel.
|
||||
* Size of memory allocated return in *cmd_line_len.
|
||||
* Returns NULL on error.
|
||||
*/
|
||||
char *efi_convert_cmdline(efi_loaded_image_t *image,
|
||||
int *cmd_line_len, unsigned long max_addr)
|
||||
char *efi_convert_cmdline(efi_loaded_image_t *image, int *cmd_line_len)
|
||||
{
|
||||
const u16 *s2;
|
||||
u8 *s1 = NULL;
|
||||
unsigned long cmdline_addr = 0;
|
||||
int load_options_chars = efi_table_attr(image, load_options_size) / 2;
|
||||
int options_chars = efi_table_attr(image, load_options_size) / 2;
|
||||
const u16 *options = efi_table_attr(image, load_options);
|
||||
int options_bytes = 0; /* UTF-8 bytes */
|
||||
int options_chars = 0; /* UTF-16 chars */
|
||||
int options_bytes = 0, safe_options_bytes = 0; /* UTF-8 bytes */
|
||||
bool in_quote = false;
|
||||
efi_status_t status;
|
||||
u16 zero = 0;
|
||||
|
||||
if (options) {
|
||||
s2 = options;
|
||||
while (*s2 && *s2 != '\n'
|
||||
&& options_chars < load_options_chars) {
|
||||
options_bytes += efi_utf8_bytes(*s2++);
|
||||
options_chars++;
|
||||
}
|
||||
}
|
||||
while (options_bytes < COMMAND_LINE_SIZE && options_chars--) {
|
||||
u16 c = *s2++;
|
||||
|
||||
if (!options_chars) {
|
||||
/* No command line options, so return empty string*/
|
||||
options = &zero;
|
||||
if (c < 0x80) {
|
||||
if (c == L'\0' || c == L'\n')
|
||||
break;
|
||||
if (c == L'"')
|
||||
in_quote = !in_quote;
|
||||
else if (!in_quote && isspace((char)c))
|
||||
safe_options_bytes = options_bytes;
|
||||
|
||||
options_bytes++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the number of UTF-8 bytes corresponding to a
|
||||
* UTF-16 character.
|
||||
* The first part handles everything in the BMP.
|
||||
*/
|
||||
options_bytes += 2 + (c >= 0x800);
|
||||
/*
|
||||
* Add one more byte for valid surrogate pairs. Invalid
|
||||
* surrogates will be replaced with 0xfffd and take up
|
||||
* only 3 bytes.
|
||||
*/
|
||||
if ((c & 0xfc00) == 0xd800) {
|
||||
/*
|
||||
* If the very last word is a high surrogate,
|
||||
* we must ignore it since we can't access the
|
||||
* low surrogate.
|
||||
*/
|
||||
if (!options_chars) {
|
||||
options_bytes -= 3;
|
||||
} else if ((*s2 & 0xfc00) == 0xdc00) {
|
||||
options_bytes++;
|
||||
options_chars--;
|
||||
s2++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (options_bytes >= COMMAND_LINE_SIZE) {
|
||||
options_bytes = safe_options_bytes;
|
||||
efi_err("Command line is too long: truncated to %d bytes\n",
|
||||
options_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
options_bytes++; /* NUL termination */
|
||||
|
||||
status = efi_allocate_pages(options_bytes, &cmdline_addr, max_addr);
|
||||
status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, options_bytes,
|
||||
(void **)&cmdline_addr);
|
||||
if (status != EFI_SUCCESS)
|
||||
return NULL;
|
||||
|
||||
s1 = (u8 *)cmdline_addr;
|
||||
s2 = (const u16 *)options;
|
||||
|
||||
s1 = efi_utf16_to_utf8(s1, s2, options_chars);
|
||||
*s1 = '\0';
|
||||
snprintf((char *)cmdline_addr, options_bytes, "%.*ls",
|
||||
options_bytes - 1, options);
|
||||
|
||||
*cmd_line_len = options_bytes;
|
||||
return (char *)cmdline_addr;
|
||||
|
@ -284,12 +379,6 @@ void *get_efi_config_table(efi_guid_t guid)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void efi_char16_printk(efi_char16_t *str)
|
||||
{
|
||||
efi_call_proto(efi_table_attr(efi_system_table, con_out),
|
||||
output_string, str);
|
||||
}
|
||||
|
||||
/*
|
||||
* The LINUX_EFI_INITRD_MEDIA_GUID vendor media device path below provides a way
|
||||
* for the firmware or bootloader to expose the initrd data directly to the stub
|
||||
|
@ -331,6 +420,7 @@ static const struct {
|
|||
* %EFI_OUT_OF_RESOURCES if memory allocation failed
|
||||
* %EFI_LOAD_ERROR in all other cases
|
||||
*/
|
||||
static
|
||||
efi_status_t efi_load_initrd_dev_path(unsigned long *load_addr,
|
||||
unsigned long *load_size,
|
||||
unsigned long max)
|
||||
|
@ -343,9 +433,6 @@ efi_status_t efi_load_initrd_dev_path(unsigned long *load_addr,
|
|||
efi_handle_t handle;
|
||||
efi_status_t status;
|
||||
|
||||
if (!load_addr || !load_size)
|
||||
return EFI_INVALID_PARAMETER;
|
||||
|
||||
dp = (efi_device_path_protocol_t *)&initrd_dev_path;
|
||||
status = efi_bs_call(locate_device_path, &lf2_proto_guid, &dp, &handle);
|
||||
if (status != EFI_SUCCESS)
|
||||
|
@ -375,3 +462,80 @@ efi_status_t efi_load_initrd_dev_path(unsigned long *load_addr,
|
|||
*load_size = initrd_size;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
static
|
||||
efi_status_t efi_load_initrd_cmdline(efi_loaded_image_t *image,
|
||||
unsigned long *load_addr,
|
||||
unsigned long *load_size,
|
||||
unsigned long soft_limit,
|
||||
unsigned long hard_limit)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER) ||
|
||||
(IS_ENABLED(CONFIG_X86) && (!efi_is_native() || image == NULL))) {
|
||||
*load_addr = *load_size = 0;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
return handle_cmdline_files(image, L"initrd=", sizeof(L"initrd=") - 2,
|
||||
soft_limit, hard_limit,
|
||||
load_addr, load_size);
|
||||
}
|
||||
|
||||
efi_status_t efi_load_initrd(efi_loaded_image_t *image,
|
||||
unsigned long *load_addr,
|
||||
unsigned long *load_size,
|
||||
unsigned long soft_limit,
|
||||
unsigned long hard_limit)
|
||||
{
|
||||
efi_status_t status;
|
||||
|
||||
if (!load_addr || !load_size)
|
||||
return EFI_INVALID_PARAMETER;
|
||||
|
||||
status = efi_load_initrd_dev_path(load_addr, load_size, hard_limit);
|
||||
if (status == EFI_SUCCESS) {
|
||||
efi_info("Loaded initrd from LINUX_EFI_INITRD_MEDIA_GUID device path\n");
|
||||
} else if (status == EFI_NOT_FOUND) {
|
||||
status = efi_load_initrd_cmdline(image, load_addr, load_size,
|
||||
soft_limit, hard_limit);
|
||||
if (status == EFI_SUCCESS && *load_size > 0)
|
||||
efi_info("Loaded initrd from command line option\n");
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
efi_status_t efi_wait_for_key(unsigned long usec, efi_input_key_t *key)
|
||||
{
|
||||
efi_event_t events[2], timer;
|
||||
unsigned long index;
|
||||
efi_simple_text_input_protocol_t *con_in;
|
||||
efi_status_t status;
|
||||
|
||||
con_in = efi_table_attr(efi_system_table, con_in);
|
||||
if (!con_in)
|
||||
return EFI_UNSUPPORTED;
|
||||
efi_set_event_at(events, 0, efi_table_attr(con_in, wait_for_key));
|
||||
|
||||
status = efi_bs_call(create_event, EFI_EVT_TIMER, 0, NULL, NULL, &timer);
|
||||
if (status != EFI_SUCCESS)
|
||||
return status;
|
||||
|
||||
status = efi_bs_call(set_timer, timer, EfiTimerRelative,
|
||||
EFI_100NSEC_PER_USEC * usec);
|
||||
if (status != EFI_SUCCESS)
|
||||
return status;
|
||||
efi_set_event_at(events, 1, timer);
|
||||
|
||||
status = efi_bs_call(wait_for_event, 2, events, &index);
|
||||
if (status == EFI_SUCCESS) {
|
||||
if (index == 0)
|
||||
status = efi_call_proto(con_in, read_keystroke, key);
|
||||
else
|
||||
status = EFI_TIMEOUT;
|
||||
}
|
||||
|
||||
efi_bs_call(close_event, timer);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@ static void install_memreserve_table(void)
|
|||
status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, sizeof(*rsv),
|
||||
(void **)&rsv);
|
||||
if (status != EFI_SUCCESS) {
|
||||
pr_efi_err("Failed to allocate memreserve entry!\n");
|
||||
efi_err("Failed to allocate memreserve entry!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -84,7 +84,7 @@ static void install_memreserve_table(void)
|
|||
status = efi_bs_call(install_configuration_table,
|
||||
&memreserve_table_guid, rsv);
|
||||
if (status != EFI_SUCCESS)
|
||||
pr_efi_err("Failed to install memreserve config table!\n");
|
||||
efi_err("Failed to install memreserve config table!\n");
|
||||
}
|
||||
|
||||
static unsigned long get_dram_base(void)
|
||||
|
@ -144,7 +144,8 @@ asmlinkage void __noreturn efi_enter_kernel(unsigned long entrypoint,
|
|||
* for both archictectures, with the arch-specific code provided in the
|
||||
* handle_kernel_image() function.
|
||||
*/
|
||||
efi_status_t efi_entry(efi_handle_t handle, efi_system_table_t *sys_table_arg)
|
||||
efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
|
||||
efi_system_table_t *sys_table_arg)
|
||||
{
|
||||
efi_loaded_image_t *image;
|
||||
efi_status_t status;
|
||||
|
@ -186,13 +187,13 @@ efi_status_t efi_entry(efi_handle_t handle, efi_system_table_t *sys_table_arg)
|
|||
status = efi_system_table->boottime->handle_protocol(handle,
|
||||
&loaded_image_proto, (void *)&image);
|
||||
if (status != EFI_SUCCESS) {
|
||||
pr_efi_err("Failed to get loaded image protocol\n");
|
||||
efi_err("Failed to get loaded image protocol\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dram_base = get_dram_base();
|
||||
if (dram_base == EFI_ERROR) {
|
||||
pr_efi_err("Failed to find DRAM base\n");
|
||||
efi_err("Failed to find DRAM base\n");
|
||||
status = EFI_LOAD_ERROR;
|
||||
goto fail;
|
||||
}
|
||||
|
@ -202,22 +203,32 @@ efi_status_t efi_entry(efi_handle_t handle, efi_system_table_t *sys_table_arg)
|
|||
* protocol. We are going to copy the command line into the
|
||||
* device tree, so this can be allocated anywhere.
|
||||
*/
|
||||
cmdline_ptr = efi_convert_cmdline(image, &cmdline_size, ULONG_MAX);
|
||||
cmdline_ptr = efi_convert_cmdline(image, &cmdline_size);
|
||||
if (!cmdline_ptr) {
|
||||
pr_efi_err("getting command line via LOADED_IMAGE_PROTOCOL\n");
|
||||
efi_err("getting command line via LOADED_IMAGE_PROTOCOL\n");
|
||||
status = EFI_OUT_OF_RESOURCES;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_CMDLINE_EXTEND) ||
|
||||
IS_ENABLED(CONFIG_CMDLINE_FORCE) ||
|
||||
cmdline_size == 0)
|
||||
efi_parse_options(CONFIG_CMDLINE);
|
||||
cmdline_size == 0) {
|
||||
status = efi_parse_options(CONFIG_CMDLINE);
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_err("Failed to parse options\n");
|
||||
goto fail_free_cmdline;
|
||||
}
|
||||
}
|
||||
|
||||
if (!IS_ENABLED(CONFIG_CMDLINE_FORCE) && cmdline_size > 0)
|
||||
efi_parse_options(cmdline_ptr);
|
||||
if (!IS_ENABLED(CONFIG_CMDLINE_FORCE) && cmdline_size > 0) {
|
||||
status = efi_parse_options(cmdline_ptr);
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_err("Failed to parse options\n");
|
||||
goto fail_free_cmdline;
|
||||
}
|
||||
}
|
||||
|
||||
pr_efi("Booting Linux Kernel...\n");
|
||||
efi_info("Booting Linux Kernel...\n");
|
||||
|
||||
si = setup_graphics();
|
||||
|
||||
|
@ -226,8 +237,8 @@ efi_status_t efi_entry(efi_handle_t handle, efi_system_table_t *sys_table_arg)
|
|||
&reserve_size,
|
||||
dram_base, image);
|
||||
if (status != EFI_SUCCESS) {
|
||||
pr_efi_err("Failed to relocate kernel\n");
|
||||
goto fail_free_cmdline;
|
||||
efi_err("Failed to relocate kernel\n");
|
||||
goto fail_free_screeninfo;
|
||||
}
|
||||
|
||||
efi_retrieve_tpm2_eventlog();
|
||||
|
@ -245,42 +256,34 @@ efi_status_t efi_entry(efi_handle_t handle, efi_system_table_t *sys_table_arg)
|
|||
if (!IS_ENABLED(CONFIG_EFI_ARMSTUB_DTB_LOADER) ||
|
||||
secure_boot != efi_secureboot_mode_disabled) {
|
||||
if (strstr(cmdline_ptr, "dtb="))
|
||||
pr_efi("Ignoring DTB from command line.\n");
|
||||
efi_err("Ignoring DTB from command line.\n");
|
||||
} else {
|
||||
status = efi_load_dtb(image, &fdt_addr, &fdt_size);
|
||||
|
||||
if (status != EFI_SUCCESS) {
|
||||
pr_efi_err("Failed to load device tree!\n");
|
||||
efi_err("Failed to load device tree!\n");
|
||||
goto fail_free_image;
|
||||
}
|
||||
}
|
||||
|
||||
if (fdt_addr) {
|
||||
pr_efi("Using DTB from command line\n");
|
||||
efi_info("Using DTB from command line\n");
|
||||
} else {
|
||||
/* Look for a device tree configuration table entry. */
|
||||
fdt_addr = (uintptr_t)get_fdt(&fdt_size);
|
||||
if (fdt_addr)
|
||||
pr_efi("Using DTB from configuration table\n");
|
||||
efi_info("Using DTB from configuration table\n");
|
||||
}
|
||||
|
||||
if (!fdt_addr)
|
||||
pr_efi("Generating empty DTB\n");
|
||||
efi_info("Generating empty DTB\n");
|
||||
|
||||
if (!efi_noinitrd) {
|
||||
max_addr = efi_get_max_initrd_addr(dram_base, image_addr);
|
||||
status = efi_load_initrd_dev_path(&initrd_addr, &initrd_size,
|
||||
max_addr);
|
||||
if (status == EFI_SUCCESS) {
|
||||
pr_efi("Loaded initrd from LINUX_EFI_INITRD_MEDIA_GUID device path\n");
|
||||
} else if (status == EFI_NOT_FOUND) {
|
||||
status = efi_load_initrd(image, &initrd_addr, &initrd_size,
|
||||
ULONG_MAX, max_addr);
|
||||
if (status == EFI_SUCCESS && initrd_size > 0)
|
||||
pr_efi("Loaded initrd from command line option\n");
|
||||
}
|
||||
status = efi_load_initrd(image, &initrd_addr, &initrd_size,
|
||||
ULONG_MAX, max_addr);
|
||||
if (status != EFI_SUCCESS)
|
||||
pr_efi_err("Failed to load initrd!\n");
|
||||
efi_err("Failed to load initrd!\n");
|
||||
}
|
||||
|
||||
efi_random_get_seed();
|
||||
|
@ -330,7 +333,7 @@ efi_status_t efi_entry(efi_handle_t handle, efi_system_table_t *sys_table_arg)
|
|||
/* not reached */
|
||||
|
||||
fail_free_initrd:
|
||||
pr_efi_err("Failed to update FDT and exit boot services\n");
|
||||
efi_err("Failed to update FDT and exit boot services\n");
|
||||
|
||||
efi_free(initrd_size, initrd_addr);
|
||||
efi_free(fdt_size, fdt_addr);
|
||||
|
@ -338,9 +341,10 @@ fail_free_initrd:
|
|||
fail_free_image:
|
||||
efi_free(image_size, image_addr);
|
||||
efi_free(reserve_size, reserve_addr);
|
||||
fail_free_cmdline:
|
||||
fail_free_screeninfo:
|
||||
free_screen_info(si);
|
||||
efi_free(cmdline_size, (unsigned long)cmdline_ptr);
|
||||
fail_free_cmdline:
|
||||
efi_bs_call(free_pool, cmdline_ptr);
|
||||
fail:
|
||||
return status;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,13 @@
|
|||
#ifndef _DRIVERS_FIRMWARE_EFI_EFISTUB_H
|
||||
#define _DRIVERS_FIRMWARE_EFI_EFISTUB_H
|
||||
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/efi.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kern_levels.h>
|
||||
#include <linux/types.h>
|
||||
#include <asm/efi.h>
|
||||
|
||||
/* error code which can't be mistaken for valid address */
|
||||
#define EFI_ERROR (~0UL)
|
||||
|
||||
|
@ -28,32 +35,30 @@
|
|||
extern bool efi_nochunk;
|
||||
extern bool efi_nokaslr;
|
||||
extern bool efi_noinitrd;
|
||||
extern bool efi_quiet;
|
||||
extern int efi_loglevel;
|
||||
extern bool efi_novamap;
|
||||
|
||||
extern const efi_system_table_t *efi_system_table;
|
||||
|
||||
#ifndef efi_bs_call
|
||||
#define efi_bs_call(func, ...) efi_system_table->boottime->func(__VA_ARGS__)
|
||||
#endif
|
||||
#ifndef efi_rt_call
|
||||
#define efi_rt_call(func, ...) efi_system_table->runtime->func(__VA_ARGS__)
|
||||
#endif
|
||||
#ifndef efi_is_native
|
||||
efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
|
||||
efi_system_table_t *sys_table_arg);
|
||||
|
||||
#ifndef ARCH_HAS_EFISTUB_WRAPPERS
|
||||
|
||||
#define efi_is_native() (true)
|
||||
#endif
|
||||
#ifndef efi_table_attr
|
||||
#define efi_bs_call(func, ...) efi_system_table->boottime->func(__VA_ARGS__)
|
||||
#define efi_rt_call(func, ...) efi_system_table->runtime->func(__VA_ARGS__)
|
||||
#define efi_table_attr(inst, attr) (inst->attr)
|
||||
#endif
|
||||
#ifndef efi_call_proto
|
||||
#define efi_call_proto(inst, func, ...) inst->func(inst, ##__VA_ARGS__)
|
||||
|
||||
#endif
|
||||
|
||||
#define pr_efi(msg) do { \
|
||||
if (!efi_quiet) efi_printk("EFI stub: "msg); \
|
||||
} while (0)
|
||||
|
||||
#define pr_efi_err(msg) efi_printk("EFI stub: ERROR: "msg)
|
||||
#define efi_info(fmt, ...) \
|
||||
efi_printk(KERN_INFO fmt, ##__VA_ARGS__)
|
||||
#define efi_err(fmt, ...) \
|
||||
efi_printk(KERN_ERR "ERROR: " fmt, ##__VA_ARGS__)
|
||||
#define efi_debug(fmt, ...) \
|
||||
efi_printk(KERN_DEBUG "DEBUG: " fmt, ##__VA_ARGS__)
|
||||
|
||||
/* Helper macros for the usual case of using simple C variables: */
|
||||
#ifndef fdt_setprop_inplace_var
|
||||
|
@ -87,6 +92,13 @@ extern const efi_system_table_t *efi_system_table;
|
|||
((handle = efi_get_handle_at((array), i)) || true); \
|
||||
i++)
|
||||
|
||||
static inline
|
||||
void efi_set_u64_split(u64 data, u32 *lo, u32 *hi)
|
||||
{
|
||||
*lo = lower_32_bits(data);
|
||||
*hi = upper_32_bits(data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocation types for calls to boottime->allocate_pages.
|
||||
*/
|
||||
|
@ -102,6 +114,16 @@ extern const efi_system_table_t *efi_system_table;
|
|||
#define EFI_LOCATE_BY_REGISTER_NOTIFY 1
|
||||
#define EFI_LOCATE_BY_PROTOCOL 2
|
||||
|
||||
/*
|
||||
* boottime->stall takes the time period in microseconds
|
||||
*/
|
||||
#define EFI_USEC_PER_SEC 1000000
|
||||
|
||||
/*
|
||||
* boottime->set_timer takes the time in 100ns units
|
||||
*/
|
||||
#define EFI_100NSEC_PER_USEC ((u64)10)
|
||||
|
||||
/*
|
||||
* An efi_boot_memmap is used by efi_get_memory_map() to return the
|
||||
* EFI memory map in a dynamically allocated buffer.
|
||||
|
@ -126,6 +148,39 @@ struct efi_boot_memmap {
|
|||
|
||||
typedef struct efi_generic_dev_path efi_device_path_protocol_t;
|
||||
|
||||
typedef void *efi_event_t;
|
||||
/* Note that notifications won't work in mixed mode */
|
||||
typedef void (__efiapi *efi_event_notify_t)(efi_event_t, void *);
|
||||
|
||||
#define EFI_EVT_TIMER 0x80000000U
|
||||
#define EFI_EVT_RUNTIME 0x40000000U
|
||||
#define EFI_EVT_NOTIFY_WAIT 0x00000100U
|
||||
#define EFI_EVT_NOTIFY_SIGNAL 0x00000200U
|
||||
|
||||
/*
|
||||
* boottime->wait_for_event takes an array of events as input.
|
||||
* Provide a helper to set it up correctly for mixed mode.
|
||||
*/
|
||||
static inline
|
||||
void efi_set_event_at(efi_event_t *events, size_t idx, efi_event_t event)
|
||||
{
|
||||
if (efi_is_native())
|
||||
events[idx] = event;
|
||||
else
|
||||
((u32 *)events)[idx] = (u32)(unsigned long)event;
|
||||
}
|
||||
|
||||
#define EFI_TPL_APPLICATION 4
|
||||
#define EFI_TPL_CALLBACK 8
|
||||
#define EFI_TPL_NOTIFY 16
|
||||
#define EFI_TPL_HIGH_LEVEL 31
|
||||
|
||||
typedef enum {
|
||||
EfiTimerCancel,
|
||||
EfiTimerPeriodic,
|
||||
EfiTimerRelative
|
||||
} EFI_TIMER_DELAY;
|
||||
|
||||
/*
|
||||
* EFI Boot Services table
|
||||
*/
|
||||
|
@ -144,11 +199,16 @@ union efi_boot_services {
|
|||
efi_status_t (__efiapi *allocate_pool)(int, unsigned long,
|
||||
void **);
|
||||
efi_status_t (__efiapi *free_pool)(void *);
|
||||
void *create_event;
|
||||
void *set_timer;
|
||||
void *wait_for_event;
|
||||
efi_status_t (__efiapi *create_event)(u32, unsigned long,
|
||||
efi_event_notify_t, void *,
|
||||
efi_event_t *);
|
||||
efi_status_t (__efiapi *set_timer)(efi_event_t,
|
||||
EFI_TIMER_DELAY, u64);
|
||||
efi_status_t (__efiapi *wait_for_event)(unsigned long,
|
||||
efi_event_t *,
|
||||
unsigned long *);
|
||||
void *signal_event;
|
||||
void *close_event;
|
||||
efi_status_t (__efiapi *close_event)(efi_event_t);
|
||||
void *check_event;
|
||||
void *install_protocol_interface;
|
||||
void *reinstall_protocol_interface;
|
||||
|
@ -175,7 +235,7 @@ union efi_boot_services {
|
|||
efi_status_t (__efiapi *exit_boot_services)(efi_handle_t,
|
||||
unsigned long);
|
||||
void *get_next_monotonic_count;
|
||||
void *stall;
|
||||
efi_status_t (__efiapi *stall)(unsigned long);
|
||||
void *set_watchdog_timer;
|
||||
void *connect_controller;
|
||||
efi_status_t (__efiapi *disconnect_controller)(efi_handle_t,
|
||||
|
@ -260,6 +320,27 @@ union efi_uga_draw_protocol {
|
|||
} mixed_mode;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
u16 scan_code;
|
||||
efi_char16_t unicode_char;
|
||||
} efi_input_key_t;
|
||||
|
||||
union efi_simple_text_input_protocol {
|
||||
struct {
|
||||
void *reset;
|
||||
efi_status_t (__efiapi *read_keystroke)(efi_simple_text_input_protocol_t *,
|
||||
efi_input_key_t *);
|
||||
efi_event_t wait_for_key;
|
||||
};
|
||||
struct {
|
||||
u32 reset;
|
||||
u32 read_keystroke;
|
||||
u32 wait_for_key;
|
||||
} mixed_mode;
|
||||
};
|
||||
|
||||
efi_status_t efi_wait_for_key(unsigned long usec, efi_input_key_t *key);
|
||||
|
||||
union efi_simple_text_output_protocol {
|
||||
struct {
|
||||
void *reset;
|
||||
|
@ -612,8 +693,6 @@ efi_status_t efi_exit_boot_services(void *handle,
|
|||
void *priv,
|
||||
efi_exit_boot_map_processing priv_func);
|
||||
|
||||
void efi_char16_printk(efi_char16_t *);
|
||||
|
||||
efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
|
||||
unsigned long *new_fdt_addr,
|
||||
unsigned long max_addr,
|
||||
|
@ -637,12 +716,15 @@ efi_status_t check_platform_features(void);
|
|||
|
||||
void *get_efi_config_table(efi_guid_t guid);
|
||||
|
||||
void efi_printk(char *str);
|
||||
/* NOTE: These functions do not print a trailing newline after the string */
|
||||
void efi_char16_puts(efi_char16_t *);
|
||||
void efi_puts(const char *str);
|
||||
|
||||
__printf(1, 2) int efi_printk(char const *fmt, ...);
|
||||
|
||||
void efi_free(unsigned long size, unsigned long addr);
|
||||
|
||||
char *efi_convert_cmdline(efi_loaded_image_t *image, int *cmd_line_len,
|
||||
unsigned long max_addr);
|
||||
char *efi_convert_cmdline(efi_loaded_image_t *image, int *cmd_line_len);
|
||||
|
||||
efi_status_t efi_get_memory_map(struct efi_boot_memmap *map);
|
||||
|
||||
|
@ -683,21 +765,10 @@ static inline efi_status_t efi_load_dtb(efi_loaded_image_t *image,
|
|||
ULONG_MAX, ULONG_MAX, load_addr, load_size);
|
||||
}
|
||||
|
||||
static inline efi_status_t efi_load_initrd(efi_loaded_image_t *image,
|
||||
unsigned long *load_addr,
|
||||
unsigned long *load_size,
|
||||
unsigned long soft_limit,
|
||||
unsigned long hard_limit)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER))
|
||||
return EFI_SUCCESS;
|
||||
|
||||
return handle_cmdline_files(image, L"initrd=", sizeof(L"initrd=") - 2,
|
||||
soft_limit, hard_limit, load_addr, load_size);
|
||||
}
|
||||
|
||||
efi_status_t efi_load_initrd_dev_path(unsigned long *load_addr,
|
||||
unsigned long *load_size,
|
||||
unsigned long max);
|
||||
efi_status_t efi_load_initrd(efi_loaded_image_t *image,
|
||||
unsigned long *load_addr,
|
||||
unsigned long *load_size,
|
||||
unsigned long soft_limit,
|
||||
unsigned long hard_limit);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -39,7 +39,7 @@ static efi_status_t update_fdt(void *orig_fdt, unsigned long orig_fdt_size,
|
|||
/* Do some checks on provided FDT, if it exists: */
|
||||
if (orig_fdt) {
|
||||
if (fdt_check_header(orig_fdt)) {
|
||||
pr_efi_err("Device Tree header not valid!\n");
|
||||
efi_err("Device Tree header not valid!\n");
|
||||
return EFI_LOAD_ERROR;
|
||||
}
|
||||
/*
|
||||
|
@ -47,7 +47,7 @@ static efi_status_t update_fdt(void *orig_fdt, unsigned long orig_fdt_size,
|
|||
* configuration table:
|
||||
*/
|
||||
if (orig_fdt_size && fdt_totalsize(orig_fdt) > orig_fdt_size) {
|
||||
pr_efi_err("Truncated device tree! foo!\n");
|
||||
efi_err("Truncated device tree! foo!\n");
|
||||
return EFI_LOAD_ERROR;
|
||||
}
|
||||
}
|
||||
|
@ -270,16 +270,16 @@ efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
|
|||
*/
|
||||
status = efi_get_memory_map(&map);
|
||||
if (status != EFI_SUCCESS) {
|
||||
pr_efi_err("Unable to retrieve UEFI memory map.\n");
|
||||
efi_err("Unable to retrieve UEFI memory map.\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
pr_efi("Exiting boot services and installing virtual address map...\n");
|
||||
efi_info("Exiting boot services and installing virtual address map...\n");
|
||||
|
||||
map.map = &memory_map;
|
||||
status = efi_allocate_pages(MAX_FDT_SIZE, new_fdt_addr, max_addr);
|
||||
if (status != EFI_SUCCESS) {
|
||||
pr_efi_err("Unable to allocate memory for new device tree.\n");
|
||||
efi_err("Unable to allocate memory for new device tree.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@ -296,7 +296,7 @@ efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
|
|||
initrd_addr, initrd_size);
|
||||
|
||||
if (status != EFI_SUCCESS) {
|
||||
pr_efi_err("Unable to construct new device tree.\n");
|
||||
efi_err("Unable to construct new device tree.\n");
|
||||
goto fail_free_new_fdt;
|
||||
}
|
||||
|
||||
|
@ -342,7 +342,7 @@ efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
|
|||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
pr_efi_err("Exit boot services failed.\n");
|
||||
efi_err("Exit boot services failed.\n");
|
||||
|
||||
fail_free_new_fdt:
|
||||
efi_free(MAX_FDT_SIZE, *new_fdt_addr);
|
||||
|
@ -363,7 +363,7 @@ void *get_fdt(unsigned long *fdt_size)
|
|||
return NULL;
|
||||
|
||||
if (fdt_check_header(fdt) != 0) {
|
||||
pr_efi_err("Invalid header detected on UEFI supplied FDT, ignoring ...\n");
|
||||
efi_err("Invalid header detected on UEFI supplied FDT, ignoring ...\n");
|
||||
return NULL;
|
||||
}
|
||||
*fdt_size = fdt_totalsize(fdt);
|
||||
|
|
|
@ -46,16 +46,14 @@ static efi_status_t efi_open_file(efi_file_protocol_t *volume,
|
|||
|
||||
status = volume->open(volume, &fh, fi->filename, EFI_FILE_MODE_READ, 0);
|
||||
if (status != EFI_SUCCESS) {
|
||||
pr_efi_err("Failed to open file: ");
|
||||
efi_char16_printk(fi->filename);
|
||||
efi_printk("\n");
|
||||
efi_err("Failed to open file: %ls\n", fi->filename);
|
||||
return status;
|
||||
}
|
||||
|
||||
info_sz = sizeof(struct finfo);
|
||||
status = fh->get_info(fh, &info_guid, &info_sz, fi);
|
||||
if (status != EFI_SUCCESS) {
|
||||
pr_efi_err("Failed to get file info\n");
|
||||
efi_err("Failed to get file info\n");
|
||||
fh->close(fh);
|
||||
return status;
|
||||
}
|
||||
|
@ -75,13 +73,13 @@ static efi_status_t efi_open_volume(efi_loaded_image_t *image,
|
|||
status = efi_bs_call(handle_protocol, image->device_handle, &fs_proto,
|
||||
(void **)&io);
|
||||
if (status != EFI_SUCCESS) {
|
||||
pr_efi_err("Failed to handle fs_proto\n");
|
||||
efi_err("Failed to handle fs_proto\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
status = io->open_volume(io, fh);
|
||||
if (status != EFI_SUCCESS)
|
||||
pr_efi_err("Failed to open volume\n");
|
||||
efi_err("Failed to open volume\n");
|
||||
|
||||
return status;
|
||||
}
|
||||
|
@ -191,7 +189,7 @@ efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
|
|||
&alloc_addr,
|
||||
hard_limit);
|
||||
if (status != EFI_SUCCESS) {
|
||||
pr_efi_err("Failed to allocate memory for files\n");
|
||||
efi_err("Failed to allocate memory for files\n");
|
||||
goto err_close_file;
|
||||
}
|
||||
|
||||
|
@ -215,7 +213,7 @@ efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
|
|||
|
||||
status = file->read(file, &chunksize, addr);
|
||||
if (status != EFI_SUCCESS) {
|
||||
pr_efi_err("Failed to read file\n");
|
||||
efi_err("Failed to read file\n");
|
||||
goto err_close_file;
|
||||
}
|
||||
addr += chunksize;
|
||||
|
|
|
@ -19,7 +19,8 @@ enum efi_cmdline_option {
|
|||
EFI_CMDLINE_NONE,
|
||||
EFI_CMDLINE_MODE_NUM,
|
||||
EFI_CMDLINE_RES,
|
||||
EFI_CMDLINE_AUTO
|
||||
EFI_CMDLINE_AUTO,
|
||||
EFI_CMDLINE_LIST
|
||||
};
|
||||
|
||||
static struct {
|
||||
|
@ -100,6 +101,19 @@ static bool parse_auto(char *option, char **next)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool parse_list(char *option, char **next)
|
||||
{
|
||||
if (!strstarts(option, "list"))
|
||||
return false;
|
||||
option += strlen("list");
|
||||
if (*option && *option++ != ',')
|
||||
return false;
|
||||
cmdline.option = EFI_CMDLINE_LIST;
|
||||
|
||||
*next = option;
|
||||
return true;
|
||||
}
|
||||
|
||||
void efi_parse_option_graphics(char *option)
|
||||
{
|
||||
while (*option) {
|
||||
|
@ -109,6 +123,8 @@ void efi_parse_option_graphics(char *option)
|
|||
continue;
|
||||
if (parse_auto(option, &option))
|
||||
continue;
|
||||
if (parse_list(option, &option))
|
||||
continue;
|
||||
|
||||
while (*option && *option++ != ',')
|
||||
;
|
||||
|
@ -134,14 +150,14 @@ static u32 choose_mode_modenum(efi_graphics_output_protocol_t *gop)
|
|||
|
||||
max_mode = efi_table_attr(mode, max_mode);
|
||||
if (cmdline.mode >= max_mode) {
|
||||
efi_printk("Requested mode is invalid\n");
|
||||
efi_err("Requested mode is invalid\n");
|
||||
return cur_mode;
|
||||
}
|
||||
|
||||
status = efi_call_proto(gop, query_mode, cmdline.mode,
|
||||
&info_size, &info);
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_printk("Couldn't get mode information\n");
|
||||
efi_err("Couldn't get mode information\n");
|
||||
return cur_mode;
|
||||
}
|
||||
|
||||
|
@ -150,7 +166,7 @@ static u32 choose_mode_modenum(efi_graphics_output_protocol_t *gop)
|
|||
efi_bs_call(free_pool, info);
|
||||
|
||||
if (pf == PIXEL_BLT_ONLY || pf >= PIXEL_FORMAT_MAX) {
|
||||
efi_printk("Invalid PixelFormat\n");
|
||||
efi_err("Invalid PixelFormat\n");
|
||||
return cur_mode;
|
||||
}
|
||||
|
||||
|
@ -222,7 +238,7 @@ static u32 choose_mode_res(efi_graphics_output_protocol_t *gop)
|
|||
return m;
|
||||
}
|
||||
|
||||
efi_printk("Couldn't find requested mode\n");
|
||||
efi_err("Couldn't find requested mode\n");
|
||||
|
||||
return cur_mode;
|
||||
}
|
||||
|
@ -290,6 +306,82 @@ static u32 choose_mode_auto(efi_graphics_output_protocol_t *gop)
|
|||
return best_mode;
|
||||
}
|
||||
|
||||
static u32 choose_mode_list(efi_graphics_output_protocol_t *gop)
|
||||
{
|
||||
efi_status_t status;
|
||||
|
||||
efi_graphics_output_protocol_mode_t *mode;
|
||||
efi_graphics_output_mode_info_t *info;
|
||||
unsigned long info_size;
|
||||
|
||||
u32 max_mode, cur_mode;
|
||||
int pf;
|
||||
efi_pixel_bitmask_t pi;
|
||||
u32 m, w, h;
|
||||
u8 d;
|
||||
const char *dstr;
|
||||
bool valid;
|
||||
efi_input_key_t key;
|
||||
|
||||
mode = efi_table_attr(gop, mode);
|
||||
|
||||
cur_mode = efi_table_attr(mode, mode);
|
||||
max_mode = efi_table_attr(mode, max_mode);
|
||||
|
||||
efi_printk("Available graphics modes are 0-%u\n", max_mode-1);
|
||||
efi_puts(" * = current mode\n"
|
||||
" - = unusable mode\n");
|
||||
for (m = 0; m < max_mode; m++) {
|
||||
status = efi_call_proto(gop, query_mode, m,
|
||||
&info_size, &info);
|
||||
if (status != EFI_SUCCESS)
|
||||
continue;
|
||||
|
||||
pf = info->pixel_format;
|
||||
pi = info->pixel_information;
|
||||
w = info->horizontal_resolution;
|
||||
h = info->vertical_resolution;
|
||||
|
||||
efi_bs_call(free_pool, info);
|
||||
|
||||
valid = !(pf == PIXEL_BLT_ONLY || pf >= PIXEL_FORMAT_MAX);
|
||||
d = 0;
|
||||
switch (pf) {
|
||||
case PIXEL_RGB_RESERVED_8BIT_PER_COLOR:
|
||||
dstr = "rgb";
|
||||
break;
|
||||
case PIXEL_BGR_RESERVED_8BIT_PER_COLOR:
|
||||
dstr = "bgr";
|
||||
break;
|
||||
case PIXEL_BIT_MASK:
|
||||
dstr = "";
|
||||
d = pixel_bpp(pf, pi);
|
||||
break;
|
||||
case PIXEL_BLT_ONLY:
|
||||
dstr = "blt";
|
||||
break;
|
||||
default:
|
||||
dstr = "xxx";
|
||||
break;
|
||||
}
|
||||
|
||||
efi_printk("Mode %3u %c%c: Resolution %ux%u-%s%.0hhu\n",
|
||||
m,
|
||||
m == cur_mode ? '*' : ' ',
|
||||
!valid ? '-' : ' ',
|
||||
w, h, dstr, d);
|
||||
}
|
||||
|
||||
efi_puts("\nPress any key to continue (or wait 10 seconds)\n");
|
||||
status = efi_wait_for_key(10 * EFI_USEC_PER_SEC, &key);
|
||||
if (status != EFI_SUCCESS && status != EFI_TIMEOUT) {
|
||||
efi_err("Unable to read key, continuing in 10 seconds\n");
|
||||
efi_bs_call(stall, 10 * EFI_USEC_PER_SEC);
|
||||
}
|
||||
|
||||
return cur_mode;
|
||||
}
|
||||
|
||||
static void set_mode(efi_graphics_output_protocol_t *gop)
|
||||
{
|
||||
efi_graphics_output_protocol_mode_t *mode;
|
||||
|
@ -305,6 +397,9 @@ static void set_mode(efi_graphics_output_protocol_t *gop)
|
|||
case EFI_CMDLINE_AUTO:
|
||||
new_mode = choose_mode_auto(gop);
|
||||
break;
|
||||
case EFI_CMDLINE_LIST:
|
||||
new_mode = choose_mode_list(gop);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
@ -316,7 +411,7 @@ static void set_mode(efi_graphics_output_protocol_t *gop)
|
|||
return;
|
||||
|
||||
if (efi_call_proto(gop, set_mode, new_mode) != EFI_SUCCESS)
|
||||
efi_printk("Failed to set requested mode\n");
|
||||
efi_err("Failed to set requested mode\n");
|
||||
}
|
||||
|
||||
static void find_bits(u32 mask, u8 *pos, u8 *size)
|
||||
|
@ -422,7 +517,6 @@ static efi_status_t setup_gop(struct screen_info *si, efi_guid_t *proto,
|
|||
efi_graphics_output_protocol_t *gop;
|
||||
efi_graphics_output_protocol_mode_t *mode;
|
||||
efi_graphics_output_mode_info_t *info;
|
||||
efi_physical_addr_t fb_base;
|
||||
|
||||
gop = find_gop(proto, size, handles);
|
||||
|
||||
|
@ -442,9 +536,8 @@ static efi_status_t setup_gop(struct screen_info *si, efi_guid_t *proto,
|
|||
si->lfb_width = info->horizontal_resolution;
|
||||
si->lfb_height = info->vertical_resolution;
|
||||
|
||||
fb_base = efi_table_attr(mode, frame_buffer_base);
|
||||
si->lfb_base = lower_32_bits(fb_base);
|
||||
si->ext_lfb_base = upper_32_bits(fb_base);
|
||||
efi_set_u64_split(efi_table_attr(mode, frame_buffer_base),
|
||||
&si->lfb_base, &si->ext_lfb_base);
|
||||
if (si->ext_lfb_base)
|
||||
si->capabilities |= VIDEO_CAPABILITY_64BIT_BASE;
|
||||
|
||||
|
|
|
@ -28,21 +28,21 @@ void efi_pci_disable_bridge_busmaster(void)
|
|||
|
||||
if (status != EFI_BUFFER_TOO_SMALL) {
|
||||
if (status != EFI_SUCCESS && status != EFI_NOT_FOUND)
|
||||
pr_efi_err("Failed to locate PCI I/O handles'\n");
|
||||
efi_err("Failed to locate PCI I/O handles'\n");
|
||||
return;
|
||||
}
|
||||
|
||||
status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, pci_handle_size,
|
||||
(void **)&pci_handle);
|
||||
if (status != EFI_SUCCESS) {
|
||||
pr_efi_err("Failed to allocate memory for 'pci_handle'\n");
|
||||
efi_err("Failed to allocate memory for 'pci_handle'\n");
|
||||
return;
|
||||
}
|
||||
|
||||
status = efi_bs_call(locate_handle, EFI_LOCATE_BY_PROTOCOL, &pci_proto,
|
||||
NULL, &pci_handle_size, pci_handle);
|
||||
if (status != EFI_SUCCESS) {
|
||||
pr_efi_err("Failed to locate PCI I/O handles'\n");
|
||||
efi_err("Failed to locate PCI I/O handles'\n");
|
||||
goto free_handle;
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,7 @@ void efi_pci_disable_bridge_busmaster(void)
|
|||
* access to the framebuffer. Drivers for true PCIe graphics
|
||||
* controllers that are behind a PCIe root port do not use
|
||||
* DMA to implement the GOP framebuffer anyway [although they
|
||||
* may use it in their implentation of Gop->Blt()], and so
|
||||
* may use it in their implementation of Gop->Blt()], and so
|
||||
* disabling DMA in the PCI bridge should not interfere with
|
||||
* normal operation of the device.
|
||||
*/
|
||||
|
@ -106,7 +106,7 @@ void efi_pci_disable_bridge_busmaster(void)
|
|||
status = efi_call_proto(pci, pci.write, EfiPciIoWidthUint16,
|
||||
PCI_COMMAND, 1, &command);
|
||||
if (status != EFI_SUCCESS)
|
||||
pr_efi_err("Failed to disable PCI busmastering\n");
|
||||
efi_err("Failed to disable PCI busmastering\n");
|
||||
}
|
||||
|
||||
free_handle:
|
||||
|
|
|
@ -140,7 +140,7 @@ efi_status_t efi_relocate_kernel(unsigned long *image_addr,
|
|||
* The EFI firmware loader could have placed the kernel image
|
||||
* anywhere in memory, but the kernel has restrictions on the
|
||||
* max physical address it can run at. Some architectures
|
||||
* also have a prefered address, so first try to relocate
|
||||
* also have a preferred address, so first try to relocate
|
||||
* to the preferred address. If that fails, allocate as low
|
||||
* as possible while respecting the required alignment.
|
||||
*/
|
||||
|
@ -157,7 +157,7 @@ efi_status_t efi_relocate_kernel(unsigned long *image_addr,
|
|||
min_addr);
|
||||
}
|
||||
if (status != EFI_SUCCESS) {
|
||||
pr_efi_err("Failed to allocate usable memory for kernel.\n");
|
||||
efi_err("Failed to allocate usable memory for kernel.\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
|
@ -67,10 +67,10 @@ enum efi_secureboot_mode efi_get_secureboot(void)
|
|||
return efi_secureboot_mode_disabled;
|
||||
|
||||
secure_boot_enabled:
|
||||
pr_efi("UEFI Secure Boot is enabled.\n");
|
||||
efi_info("UEFI Secure Boot is enabled.\n");
|
||||
return efi_secureboot_mode_enabled;
|
||||
|
||||
out_efi_err:
|
||||
pr_efi_err("Could not determine UEFI Secure Boot status.\n");
|
||||
efi_err("Could not determine UEFI Secure Boot status.\n");
|
||||
return efi_secureboot_mode_unknown;
|
||||
}
|
||||
|
|
|
@ -119,7 +119,7 @@ void efi_retrieve_tpm2_eventlog(void)
|
|||
sizeof(*log_tbl) + log_size, (void **)&log_tbl);
|
||||
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_printk("Unable to allocate memory for event log\n");
|
||||
efi_err("Unable to allocate memory for event log\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,564 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* -*- linux-c -*- ------------------------------------------------------- *
|
||||
*
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
* Copyright 2007 rPath, Inc. - All Rights Reserved
|
||||
*
|
||||
* ----------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Oh, it's a waste of space, but oh-so-yummy for debugging.
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/limits.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
static
|
||||
int skip_atoi(const char **s)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (isdigit(**s))
|
||||
i = i * 10 + *((*s)++) - '0';
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* put_dec_full4 handles numbers in the range 0 <= r < 10000.
|
||||
* The multiplier 0xccd is round(2^15/10), and the approximation
|
||||
* r/10 == (r * 0xccd) >> 15 is exact for all r < 16389.
|
||||
*/
|
||||
static
|
||||
void put_dec_full4(char *end, unsigned int r)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
unsigned int q = (r * 0xccd) >> 15;
|
||||
*--end = '0' + (r - q * 10);
|
||||
r = q;
|
||||
}
|
||||
*--end = '0' + r;
|
||||
}
|
||||
|
||||
/* put_dec is copied from lib/vsprintf.c with small modifications */
|
||||
|
||||
/*
|
||||
* Call put_dec_full4 on x % 10000, return x / 10000.
|
||||
* The approximation x/10000 == (x * 0x346DC5D7) >> 43
|
||||
* holds for all x < 1,128,869,999. The largest value this
|
||||
* helper will ever be asked to convert is 1,125,520,955.
|
||||
* (second call in the put_dec code, assuming n is all-ones).
|
||||
*/
|
||||
static
|
||||
unsigned int put_dec_helper4(char *end, unsigned int x)
|
||||
{
|
||||
unsigned int q = (x * 0x346DC5D7ULL) >> 43;
|
||||
|
||||
put_dec_full4(end, x - q * 10000);
|
||||
return q;
|
||||
}
|
||||
|
||||
/* Based on code by Douglas W. Jones found at
|
||||
* <http://www.cs.uiowa.edu/~jones/bcd/decimal.html#sixtyfour>
|
||||
* (with permission from the author).
|
||||
* Performs no 64-bit division and hence should be fast on 32-bit machines.
|
||||
*/
|
||||
static
|
||||
char *put_dec(char *end, unsigned long long n)
|
||||
{
|
||||
unsigned int d3, d2, d1, q, h;
|
||||
char *p = end;
|
||||
|
||||
d1 = ((unsigned int)n >> 16); /* implicit "& 0xffff" */
|
||||
h = (n >> 32);
|
||||
d2 = (h ) & 0xffff;
|
||||
d3 = (h >> 16); /* implicit "& 0xffff" */
|
||||
|
||||
/* n = 2^48 d3 + 2^32 d2 + 2^16 d1 + d0
|
||||
= 281_4749_7671_0656 d3 + 42_9496_7296 d2 + 6_5536 d1 + d0 */
|
||||
q = 656 * d3 + 7296 * d2 + 5536 * d1 + ((unsigned int)n & 0xffff);
|
||||
q = put_dec_helper4(p, q);
|
||||
p -= 4;
|
||||
|
||||
q += 7671 * d3 + 9496 * d2 + 6 * d1;
|
||||
q = put_dec_helper4(p, q);
|
||||
p -= 4;
|
||||
|
||||
q += 4749 * d3 + 42 * d2;
|
||||
q = put_dec_helper4(p, q);
|
||||
p -= 4;
|
||||
|
||||
q += 281 * d3;
|
||||
q = put_dec_helper4(p, q);
|
||||
p -= 4;
|
||||
|
||||
put_dec_full4(p, q);
|
||||
p -= 4;
|
||||
|
||||
/* strip off the extra 0's we printed */
|
||||
while (p < end && *p == '0')
|
||||
++p;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static
|
||||
char *number(char *end, unsigned long long num, int base, char locase)
|
||||
{
|
||||
/*
|
||||
* locase = 0 or 0x20. ORing digits or letters with 'locase'
|
||||
* produces same digits or (maybe lowercased) letters
|
||||
*/
|
||||
|
||||
/* we are called with base 8, 10 or 16, only, thus don't need "G..." */
|
||||
static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
|
||||
|
||||
switch (base) {
|
||||
case 10:
|
||||
if (num != 0)
|
||||
end = put_dec(end, num);
|
||||
break;
|
||||
case 8:
|
||||
for (; num != 0; num >>= 3)
|
||||
*--end = '0' + (num & 07);
|
||||
break;
|
||||
case 16:
|
||||
for (; num != 0; num >>= 4)
|
||||
*--end = digits[num & 0xf] | locase;
|
||||
break;
|
||||
default:
|
||||
unreachable();
|
||||
};
|
||||
|
||||
return end;
|
||||
}
|
||||
|
||||
#define ZEROPAD 1 /* pad with zero */
|
||||
#define SIGN 2 /* unsigned/signed long */
|
||||
#define PLUS 4 /* show plus */
|
||||
#define SPACE 8 /* space if plus */
|
||||
#define LEFT 16 /* left justified */
|
||||
#define SMALL 32 /* Must be 32 == 0x20 */
|
||||
#define SPECIAL 64 /* 0x */
|
||||
#define WIDE 128 /* UTF-16 string */
|
||||
|
||||
static
|
||||
int get_flags(const char **fmt)
|
||||
{
|
||||
int flags = 0;
|
||||
|
||||
do {
|
||||
switch (**fmt) {
|
||||
case '-':
|
||||
flags |= LEFT;
|
||||
break;
|
||||
case '+':
|
||||
flags |= PLUS;
|
||||
break;
|
||||
case ' ':
|
||||
flags |= SPACE;
|
||||
break;
|
||||
case '#':
|
||||
flags |= SPECIAL;
|
||||
break;
|
||||
case '0':
|
||||
flags |= ZEROPAD;
|
||||
break;
|
||||
default:
|
||||
return flags;
|
||||
}
|
||||
++(*fmt);
|
||||
} while (1);
|
||||
}
|
||||
|
||||
static
|
||||
int get_int(const char **fmt, va_list *ap)
|
||||
{
|
||||
if (isdigit(**fmt))
|
||||
return skip_atoi(fmt);
|
||||
if (**fmt == '*') {
|
||||
++(*fmt);
|
||||
/* it's the next argument */
|
||||
return va_arg(*ap, int);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
unsigned long long get_number(int sign, int qualifier, va_list *ap)
|
||||
{
|
||||
if (sign) {
|
||||
switch (qualifier) {
|
||||
case 'L':
|
||||
return va_arg(*ap, long long);
|
||||
case 'l':
|
||||
return va_arg(*ap, long);
|
||||
case 'h':
|
||||
return (short)va_arg(*ap, int);
|
||||
case 'H':
|
||||
return (signed char)va_arg(*ap, int);
|
||||
default:
|
||||
return va_arg(*ap, int);
|
||||
};
|
||||
} else {
|
||||
switch (qualifier) {
|
||||
case 'L':
|
||||
return va_arg(*ap, unsigned long long);
|
||||
case 'l':
|
||||
return va_arg(*ap, unsigned long);
|
||||
case 'h':
|
||||
return (unsigned short)va_arg(*ap, int);
|
||||
case 'H':
|
||||
return (unsigned char)va_arg(*ap, int);
|
||||
default:
|
||||
return va_arg(*ap, unsigned int);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
char get_sign(long long *num, int flags)
|
||||
{
|
||||
if (!(flags & SIGN))
|
||||
return 0;
|
||||
if (*num < 0) {
|
||||
*num = -(*num);
|
||||
return '-';
|
||||
}
|
||||
if (flags & PLUS)
|
||||
return '+';
|
||||
if (flags & SPACE)
|
||||
return ' ';
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
size_t utf16s_utf8nlen(const u16 *s16, size_t maxlen)
|
||||
{
|
||||
size_t len, clen;
|
||||
|
||||
for (len = 0; len < maxlen && *s16; len += clen) {
|
||||
u16 c0 = *s16++;
|
||||
|
||||
/* First, get the length for a BMP character */
|
||||
clen = 1 + (c0 >= 0x80) + (c0 >= 0x800);
|
||||
if (len + clen > maxlen)
|
||||
break;
|
||||
/*
|
||||
* If this is a high surrogate, and we're already at maxlen, we
|
||||
* can't include the character if it's a valid surrogate pair.
|
||||
* Avoid accessing one extra word just to check if it's valid
|
||||
* or not.
|
||||
*/
|
||||
if ((c0 & 0xfc00) == 0xd800) {
|
||||
if (len + clen == maxlen)
|
||||
break;
|
||||
if ((*s16 & 0xfc00) == 0xdc00) {
|
||||
++s16;
|
||||
++clen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static
|
||||
u32 utf16_to_utf32(const u16 **s16)
|
||||
{
|
||||
u16 c0, c1;
|
||||
|
||||
c0 = *(*s16)++;
|
||||
/* not a surrogate */
|
||||
if ((c0 & 0xf800) != 0xd800)
|
||||
return c0;
|
||||
/* invalid: low surrogate instead of high */
|
||||
if (c0 & 0x0400)
|
||||
return 0xfffd;
|
||||
c1 = **s16;
|
||||
/* invalid: missing low surrogate */
|
||||
if ((c1 & 0xfc00) != 0xdc00)
|
||||
return 0xfffd;
|
||||
/* valid surrogate pair */
|
||||
++(*s16);
|
||||
return (0x10000 - (0xd800 << 10) - 0xdc00) + (c0 << 10) + c1;
|
||||
}
|
||||
|
||||
#define PUTC(c) \
|
||||
do { \
|
||||
if (pos < size) \
|
||||
buf[pos] = (c); \
|
||||
++pos; \
|
||||
} while (0);
|
||||
|
||||
int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap)
|
||||
{
|
||||
/* The maximum space required is to print a 64-bit number in octal */
|
||||
char tmp[(sizeof(unsigned long long) * 8 + 2) / 3];
|
||||
char *tmp_end = &tmp[ARRAY_SIZE(tmp)];
|
||||
long long num;
|
||||
int base;
|
||||
const char *s;
|
||||
size_t len, pos;
|
||||
char sign;
|
||||
|
||||
int flags; /* flags to number() */
|
||||
|
||||
int field_width; /* width of output field */
|
||||
int precision; /* min. # of digits for integers; max
|
||||
number of chars for from string */
|
||||
int qualifier; /* 'h', 'hh', 'l' or 'll' for integer fields */
|
||||
|
||||
va_list args;
|
||||
|
||||
/*
|
||||
* We want to pass our input va_list to helper functions by reference,
|
||||
* but there's an annoying edge case. If va_list was originally passed
|
||||
* to us by value, we could just pass &ap down to the helpers. This is
|
||||
* the case on, for example, X86_32.
|
||||
* However, on X86_64 (and possibly others), va_list is actually a
|
||||
* size-1 array containing a structure. Our function parameter ap has
|
||||
* decayed from T[1] to T*, and &ap has type T** rather than T(*)[1],
|
||||
* which is what will be expected by a function taking a va_list *
|
||||
* parameter.
|
||||
* One standard way to solve this mess is by creating a copy in a local
|
||||
* variable of type va_list and then passing a pointer to that local
|
||||
* copy instead, which is what we do here.
|
||||
*/
|
||||
va_copy(args, ap);
|
||||
|
||||
for (pos = 0; *fmt; ++fmt) {
|
||||
if (*fmt != '%' || *++fmt == '%') {
|
||||
PUTC(*fmt);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* process flags */
|
||||
flags = get_flags(&fmt);
|
||||
|
||||
/* get field width */
|
||||
field_width = get_int(&fmt, &args);
|
||||
if (field_width < 0) {
|
||||
field_width = -field_width;
|
||||
flags |= LEFT;
|
||||
}
|
||||
|
||||
if (flags & LEFT)
|
||||
flags &= ~ZEROPAD;
|
||||
|
||||
/* get the precision */
|
||||
precision = -1;
|
||||
if (*fmt == '.') {
|
||||
++fmt;
|
||||
precision = get_int(&fmt, &args);
|
||||
if (precision >= 0)
|
||||
flags &= ~ZEROPAD;
|
||||
}
|
||||
|
||||
/* get the conversion qualifier */
|
||||
qualifier = -1;
|
||||
if (*fmt == 'h' || *fmt == 'l') {
|
||||
qualifier = *fmt;
|
||||
++fmt;
|
||||
if (qualifier == *fmt) {
|
||||
qualifier -= 'a'-'A';
|
||||
++fmt;
|
||||
}
|
||||
}
|
||||
|
||||
sign = 0;
|
||||
|
||||
switch (*fmt) {
|
||||
case 'c':
|
||||
flags &= LEFT;
|
||||
s = tmp;
|
||||
if (qualifier == 'l') {
|
||||
((u16 *)tmp)[0] = (u16)va_arg(args, unsigned int);
|
||||
((u16 *)tmp)[1] = L'\0';
|
||||
precision = INT_MAX;
|
||||
goto wstring;
|
||||
} else {
|
||||
tmp[0] = (unsigned char)va_arg(args, int);
|
||||
precision = len = 1;
|
||||
}
|
||||
goto output;
|
||||
|
||||
case 's':
|
||||
flags &= LEFT;
|
||||
if (precision < 0)
|
||||
precision = INT_MAX;
|
||||
s = va_arg(args, void *);
|
||||
if (!s)
|
||||
s = precision < 6 ? "" : "(null)";
|
||||
else if (qualifier == 'l') {
|
||||
wstring:
|
||||
flags |= WIDE;
|
||||
precision = len = utf16s_utf8nlen((const u16 *)s, precision);
|
||||
goto output;
|
||||
}
|
||||
precision = len = strnlen(s, precision);
|
||||
goto output;
|
||||
|
||||
/* integer number formats - set up the flags and "break" */
|
||||
case 'o':
|
||||
base = 8;
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
if (precision < 0)
|
||||
precision = 2 * sizeof(void *);
|
||||
fallthrough;
|
||||
case 'x':
|
||||
flags |= SMALL;
|
||||
fallthrough;
|
||||
case 'X':
|
||||
base = 16;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
case 'i':
|
||||
flags |= SIGN;
|
||||
fallthrough;
|
||||
case 'u':
|
||||
flags &= ~SPECIAL;
|
||||
base = 10;
|
||||
break;
|
||||
|
||||
default:
|
||||
/*
|
||||
* Bail out if the conversion specifier is invalid.
|
||||
* There's probably a typo in the format string and the
|
||||
* remaining specifiers are unlikely to match up with
|
||||
* the arguments.
|
||||
*/
|
||||
goto fail;
|
||||
}
|
||||
if (*fmt == 'p') {
|
||||
num = (unsigned long)va_arg(args, void *);
|
||||
} else {
|
||||
num = get_number(flags & SIGN, qualifier, &args);
|
||||
}
|
||||
|
||||
sign = get_sign(&num, flags);
|
||||
if (sign)
|
||||
--field_width;
|
||||
|
||||
s = number(tmp_end, num, base, flags & SMALL);
|
||||
len = tmp_end - s;
|
||||
/* default precision is 1 */
|
||||
if (precision < 0)
|
||||
precision = 1;
|
||||
/* precision is minimum number of digits to print */
|
||||
if (precision < len)
|
||||
precision = len;
|
||||
if (flags & SPECIAL) {
|
||||
/*
|
||||
* For octal, a leading 0 is printed only if necessary,
|
||||
* i.e. if it's not already there because of the
|
||||
* precision.
|
||||
*/
|
||||
if (base == 8 && precision == len)
|
||||
++precision;
|
||||
/*
|
||||
* For hexadecimal, the leading 0x is skipped if the
|
||||
* output is empty, i.e. both the number and the
|
||||
* precision are 0.
|
||||
*/
|
||||
if (base == 16 && precision > 0)
|
||||
field_width -= 2;
|
||||
else
|
||||
flags &= ~SPECIAL;
|
||||
}
|
||||
/*
|
||||
* For zero padding, increase the precision to fill the field
|
||||
* width.
|
||||
*/
|
||||
if ((flags & ZEROPAD) && field_width > precision)
|
||||
precision = field_width;
|
||||
|
||||
output:
|
||||
/* Calculate the padding necessary */
|
||||
field_width -= precision;
|
||||
/* Leading padding with ' ' */
|
||||
if (!(flags & LEFT))
|
||||
while (field_width-- > 0)
|
||||
PUTC(' ');
|
||||
/* sign */
|
||||
if (sign)
|
||||
PUTC(sign);
|
||||
/* 0x/0X for hexadecimal */
|
||||
if (flags & SPECIAL) {
|
||||
PUTC('0');
|
||||
PUTC( 'X' | (flags & SMALL));
|
||||
}
|
||||
/* Zero padding and excess precision */
|
||||
while (precision-- > len)
|
||||
PUTC('0');
|
||||
/* Actual output */
|
||||
if (flags & WIDE) {
|
||||
const u16 *ws = (const u16 *)s;
|
||||
|
||||
while (len-- > 0) {
|
||||
u32 c32 = utf16_to_utf32(&ws);
|
||||
u8 *s8;
|
||||
size_t clen;
|
||||
|
||||
if (c32 < 0x80) {
|
||||
PUTC(c32);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Number of trailing octets */
|
||||
clen = 1 + (c32 >= 0x800) + (c32 >= 0x10000);
|
||||
|
||||
len -= clen;
|
||||
s8 = (u8 *)&buf[pos];
|
||||
|
||||
/* Avoid writing partial character */
|
||||
PUTC('\0');
|
||||
pos += clen;
|
||||
if (pos >= size)
|
||||
continue;
|
||||
|
||||
/* Set high bits of leading octet */
|
||||
*s8 = (0xf00 >> 1) >> clen;
|
||||
/* Write trailing octets in reverse order */
|
||||
for (s8 += clen; clen; --clen, c32 >>= 6)
|
||||
*s8-- = 0x80 | (c32 & 0x3f);
|
||||
/* Set low bits of leading octet */
|
||||
*s8 |= c32;
|
||||
}
|
||||
} else {
|
||||
while (len-- > 0)
|
||||
PUTC(*s++);
|
||||
}
|
||||
/* Trailing padding with ' ' */
|
||||
while (field_width-- > 0)
|
||||
PUTC(' ');
|
||||
}
|
||||
fail:
|
||||
va_end(args);
|
||||
|
||||
if (size)
|
||||
buf[min(pos, size-1)] = '\0';
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
int snprintf(char *buf, size_t size, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
int i;
|
||||
|
||||
va_start(args, fmt);
|
||||
i = vsnprintf(buf, size, fmt, args);
|
||||
va_end(args);
|
||||
return i;
|
||||
}
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
const efi_system_table_t *efi_system_table;
|
||||
extern u32 image_offset;
|
||||
static efi_loaded_image_t *image = NULL;
|
||||
|
||||
static efi_status_t
|
||||
preserve_pci_rom_image(efi_pci_io_protocol_t *pci, struct pci_setup_rom **__rom)
|
||||
|
@ -49,7 +50,7 @@ preserve_pci_rom_image(efi_pci_io_protocol_t *pci, struct pci_setup_rom **__rom)
|
|||
status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, size,
|
||||
(void **)&rom);
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_printk("Failed to allocate memory for 'rom'\n");
|
||||
efi_err("Failed to allocate memory for 'rom'\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -65,7 +66,7 @@ preserve_pci_rom_image(efi_pci_io_protocol_t *pci, struct pci_setup_rom **__rom)
|
|||
PCI_VENDOR_ID, 1, &rom->vendor);
|
||||
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_printk("Failed to read rom->vendor\n");
|
||||
efi_err("Failed to read rom->vendor\n");
|
||||
goto free_struct;
|
||||
}
|
||||
|
||||
|
@ -73,7 +74,7 @@ preserve_pci_rom_image(efi_pci_io_protocol_t *pci, struct pci_setup_rom **__rom)
|
|||
PCI_DEVICE_ID, 1, &rom->devid);
|
||||
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_printk("Failed to read rom->devid\n");
|
||||
efi_err("Failed to read rom->devid\n");
|
||||
goto free_struct;
|
||||
}
|
||||
|
||||
|
@ -118,7 +119,7 @@ static void setup_efi_pci(struct boot_params *params)
|
|||
(void **)&pci_handle);
|
||||
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_printk("Failed to allocate memory for 'pci_handle'\n");
|
||||
efi_err("Failed to allocate memory for 'pci_handle'\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -172,7 +173,7 @@ static void retrieve_apple_device_properties(struct boot_params *boot_params)
|
|||
return;
|
||||
|
||||
if (efi_table_attr(p, version) != 0x10000) {
|
||||
efi_printk("Unsupported properties proto version\n");
|
||||
efi_err("Unsupported properties proto version\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -185,7 +186,7 @@ static void retrieve_apple_device_properties(struct boot_params *boot_params)
|
|||
size + sizeof(struct setup_data),
|
||||
(void **)&new);
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_printk("Failed to allocate memory for 'properties'\n");
|
||||
efi_err("Failed to allocate memory for 'properties'\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -355,7 +356,6 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
|
|||
{
|
||||
struct boot_params *boot_params;
|
||||
struct setup_header *hdr;
|
||||
efi_loaded_image_t *image;
|
||||
void *image_base;
|
||||
efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID;
|
||||
int options_size = 0;
|
||||
|
@ -372,20 +372,21 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
|
|||
|
||||
status = efi_bs_call(handle_protocol, handle, &proto, (void **)&image);
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_printk("Failed to get handle for LOADED_IMAGE_PROTOCOL\n");
|
||||
efi_err("Failed to get handle for LOADED_IMAGE_PROTOCOL\n");
|
||||
efi_exit(handle, status);
|
||||
}
|
||||
|
||||
image_base = efi_table_attr(image, image_base);
|
||||
image_offset = (void *)startup_32 - image_base;
|
||||
|
||||
status = efi_allocate_pages(0x4000, (unsigned long *)&boot_params, ULONG_MAX);
|
||||
status = efi_allocate_pages(sizeof(struct boot_params),
|
||||
(unsigned long *)&boot_params, ULONG_MAX);
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_printk("Failed to allocate lowmem for boot params\n");
|
||||
efi_err("Failed to allocate lowmem for boot params\n");
|
||||
efi_exit(handle, status);
|
||||
}
|
||||
|
||||
memset(boot_params, 0x0, 0x4000);
|
||||
memset(boot_params, 0x0, sizeof(struct boot_params));
|
||||
|
||||
hdr = &boot_params->hdr;
|
||||
|
||||
|
@ -403,43 +404,21 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
|
|||
hdr->type_of_loader = 0x21;
|
||||
|
||||
/* Convert unicode cmdline to ascii */
|
||||
cmdline_ptr = efi_convert_cmdline(image, &options_size, ULONG_MAX);
|
||||
cmdline_ptr = efi_convert_cmdline(image, &options_size);
|
||||
if (!cmdline_ptr)
|
||||
goto fail;
|
||||
|
||||
hdr->cmd_line_ptr = (unsigned long)cmdline_ptr;
|
||||
/* Fill in upper bits of command line address, NOP on 32 bit */
|
||||
boot_params->ext_cmd_line_ptr = (u64)(unsigned long)cmdline_ptr >> 32;
|
||||
efi_set_u64_split((unsigned long)cmdline_ptr,
|
||||
&hdr->cmd_line_ptr, &boot_params->ext_cmd_line_ptr);
|
||||
|
||||
hdr->ramdisk_image = 0;
|
||||
hdr->ramdisk_size = 0;
|
||||
|
||||
if (efi_is_native()) {
|
||||
status = efi_parse_options(cmdline_ptr);
|
||||
if (status != EFI_SUCCESS)
|
||||
goto fail2;
|
||||
|
||||
if (!efi_noinitrd) {
|
||||
status = efi_load_initrd(image, &ramdisk_addr,
|
||||
&ramdisk_size,
|
||||
hdr->initrd_addr_max,
|
||||
ULONG_MAX);
|
||||
if (status != EFI_SUCCESS)
|
||||
goto fail2;
|
||||
hdr->ramdisk_image = ramdisk_addr & 0xffffffff;
|
||||
hdr->ramdisk_size = ramdisk_size & 0xffffffff;
|
||||
boot_params->ext_ramdisk_image = (u64)ramdisk_addr >> 32;
|
||||
boot_params->ext_ramdisk_size = (u64)ramdisk_size >> 32;
|
||||
}
|
||||
}
|
||||
|
||||
efi_stub_entry(handle, sys_table_arg, boot_params);
|
||||
/* not reached */
|
||||
|
||||
fail2:
|
||||
efi_free(options_size, (unsigned long)cmdline_ptr);
|
||||
fail:
|
||||
efi_free(0x4000, (unsigned long)boot_params);
|
||||
efi_free(sizeof(struct boot_params), (unsigned long)boot_params);
|
||||
|
||||
efi_exit(handle, status);
|
||||
}
|
||||
|
@ -632,17 +611,14 @@ static efi_status_t exit_boot_func(struct efi_boot_memmap *map,
|
|||
: EFI32_LOADER_SIGNATURE;
|
||||
memcpy(&p->efi->efi_loader_signature, signature, sizeof(__u32));
|
||||
|
||||
p->efi->efi_systab = (unsigned long)efi_system_table;
|
||||
efi_set_u64_split((unsigned long)efi_system_table,
|
||||
&p->efi->efi_systab, &p->efi->efi_systab_hi);
|
||||
p->efi->efi_memdesc_size = *map->desc_size;
|
||||
p->efi->efi_memdesc_version = *map->desc_ver;
|
||||
p->efi->efi_memmap = (unsigned long)*map->map;
|
||||
efi_set_u64_split((unsigned long)*map->map,
|
||||
&p->efi->efi_memmap, &p->efi->efi_memmap_hi);
|
||||
p->efi->efi_memmap_size = *map->map_size;
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
p->efi->efi_systab_hi = (unsigned long)efi_system_table >> 32;
|
||||
p->efi->efi_memmap_hi = (unsigned long)*map->map >> 32;
|
||||
#endif
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -698,7 +674,6 @@ unsigned long efi_main(efi_handle_t handle,
|
|||
unsigned long buffer_start, buffer_end;
|
||||
struct setup_header *hdr = &boot_params->hdr;
|
||||
efi_status_t status;
|
||||
unsigned long cmdline_paddr;
|
||||
|
||||
efi_system_table = sys_table_arg;
|
||||
|
||||
|
@ -746,7 +721,7 @@ unsigned long efi_main(efi_handle_t handle,
|
|||
hdr->kernel_alignment,
|
||||
LOAD_PHYSICAL_ADDR);
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_printk("efi_relocate_kernel() failed!\n");
|
||||
efi_err("efi_relocate_kernel() failed!\n");
|
||||
goto fail;
|
||||
}
|
||||
/*
|
||||
|
@ -757,35 +732,46 @@ unsigned long efi_main(efi_handle_t handle,
|
|||
image_offset = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* efi_pe_entry() may have been called before efi_main(), in which
|
||||
* case this is the second time we parse the cmdline. This is ok,
|
||||
* parsing the cmdline multiple times does not have side-effects.
|
||||
*/
|
||||
cmdline_paddr = ((u64)hdr->cmd_line_ptr |
|
||||
((u64)boot_params->ext_cmd_line_ptr << 32));
|
||||
efi_parse_options((char *)cmdline_paddr);
|
||||
#ifdef CONFIG_CMDLINE_BOOL
|
||||
status = efi_parse_options(CONFIG_CMDLINE);
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_err("Failed to parse options\n");
|
||||
goto fail;
|
||||
}
|
||||
#endif
|
||||
if (!IS_ENABLED(CONFIG_CMDLINE_OVERRIDE)) {
|
||||
unsigned long cmdline_paddr = ((u64)hdr->cmd_line_ptr |
|
||||
((u64)boot_params->ext_cmd_line_ptr << 32));
|
||||
status = efi_parse_options((char *)cmdline_paddr);
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_err("Failed to parse options\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point, an initrd may already have been loaded, either by
|
||||
* the bootloader and passed via bootparams, or loaded from a initrd=
|
||||
* command line option by efi_pe_entry() above. In either case, we
|
||||
* permit an initrd loaded from the LINUX_EFI_INITRD_MEDIA_GUID device
|
||||
* path to supersede it.
|
||||
* At this point, an initrd may already have been loaded by the
|
||||
* bootloader and passed via bootparams. We permit an initrd loaded
|
||||
* from the LINUX_EFI_INITRD_MEDIA_GUID device path to supersede it.
|
||||
*
|
||||
* If the device path is not present, any command-line initrd=
|
||||
* arguments will be processed only if image is not NULL, which will be
|
||||
* the case only if we were loaded via the PE entry point.
|
||||
*/
|
||||
if (!efi_noinitrd) {
|
||||
unsigned long addr, size;
|
||||
|
||||
status = efi_load_initrd_dev_path(&addr, &size, ULONG_MAX);
|
||||
if (status == EFI_SUCCESS) {
|
||||
hdr->ramdisk_image = (u32)addr;
|
||||
hdr->ramdisk_size = (u32)size;
|
||||
boot_params->ext_ramdisk_image = (u64)addr >> 32;
|
||||
boot_params->ext_ramdisk_size = (u64)size >> 32;
|
||||
} else if (status != EFI_NOT_FOUND) {
|
||||
efi_printk("efi_load_initrd_dev_path() failed!\n");
|
||||
status = efi_load_initrd(image, &addr, &size,
|
||||
hdr->initrd_addr_max, ULONG_MAX);
|
||||
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_err("Failed to load initrd!\n");
|
||||
goto fail;
|
||||
}
|
||||
efi_set_u64_split(addr, &hdr->ramdisk_image,
|
||||
&boot_params->ext_ramdisk_image);
|
||||
efi_set_u64_split(size, &hdr->ramdisk_size,
|
||||
&boot_params->ext_ramdisk_size);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -810,13 +796,13 @@ unsigned long efi_main(efi_handle_t handle,
|
|||
|
||||
status = exit_boot(boot_params, handle);
|
||||
if (status != EFI_SUCCESS) {
|
||||
efi_printk("exit_boot() failed!\n");
|
||||
efi_err("exit_boot() failed!\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return bzimage_addr;
|
||||
fail:
|
||||
efi_printk("efi_main() failed!\n");
|
||||
efi_err("efi_main() failed!\n");
|
||||
|
||||
efi_exit(handle, status);
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#define EFI_WRITE_PROTECTED ( 8 | (1UL << (BITS_PER_LONG-1)))
|
||||
#define EFI_OUT_OF_RESOURCES ( 9 | (1UL << (BITS_PER_LONG-1)))
|
||||
#define EFI_NOT_FOUND (14 | (1UL << (BITS_PER_LONG-1)))
|
||||
#define EFI_TIMEOUT (18 | (1UL << (BITS_PER_LONG-1)))
|
||||
#define EFI_ABORTED (21 | (1UL << (BITS_PER_LONG-1)))
|
||||
#define EFI_SECURITY_VIOLATION (26 | (1UL << (BITS_PER_LONG-1)))
|
||||
|
||||
|
@ -426,6 +427,7 @@ typedef struct {
|
|||
u32 tables;
|
||||
} efi_system_table_32_t;
|
||||
|
||||
typedef union efi_simple_text_input_protocol efi_simple_text_input_protocol_t;
|
||||
typedef union efi_simple_text_output_protocol efi_simple_text_output_protocol_t;
|
||||
|
||||
typedef union {
|
||||
|
@ -434,7 +436,7 @@ typedef union {
|
|||
unsigned long fw_vendor; /* physical addr of CHAR16 vendor string */
|
||||
u32 fw_revision;
|
||||
unsigned long con_in_handle;
|
||||
unsigned long con_in;
|
||||
efi_simple_text_input_protocol_t *con_in;
|
||||
unsigned long con_out_handle;
|
||||
efi_simple_text_output_protocol_t *con_out;
|
||||
unsigned long stderr_handle;
|
||||
|
|
Loading…
Reference in New Issue