Commit 32e2d7c8 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'efi-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull EFI updates from Ingo Molnar:
 "The main changes in this cycle were:

   - Changes to the EFI init code to establish whether secure boot
     authentication was performed at boot time. (Josh Boyer, David
     Howells)

   - Wire up the UEFI memory attributes table for x86. This eliminates
     any runtime memory regions that are both writable and executable,
     on recent firmware versions. (Sai Praneeth)

   - Move the BGRT init code to an earlier stage so that we can still
     use efi_mem_reserve(). (Dave Young)

   - Preserve debug symbols in the ARM/arm64 UEFI stub (Ard Biesheuvel)

   - Code deduplication work and various other cleanups (Lukas Wunner)

   - ... plus various other fixes and cleanups"

* 'efi-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  efi/libstub: Make file I/O chunking x86-specific
  efi: Print the secure boot status in x86 setup_arch()
  efi: Disable secure boot if shim is in insecure mode
  efi: Get and store the secure boot status
  efi: Add SHIM and image security database GUID definitions
  arm/efi: Allow invocation of arbitrary runtime services
  x86/efi: Allow invocation of arbitrary runtime services
  efi/libstub: Preserve .debug sections after absolute relocation check
  efi/x86: Add debug code to print cooked memmap
  efi/x86: Move the EFI BGRT init code to early init code
  efi: Use typed function pointers for the runtime services table
  efi/esrt: Fix typo in pr_err() message
  x86/efi: Add support for EFI_MEMORY_ATTRIBUTES_TABLE
  efi: Introduce the EFI_MEM_ATTR bit and set it from the memory attributes table
  efi: Make EFI_MEMORY_ATTRIBUTES_TABLE initialization common across all architectures
  x86/efi: Deduplicate efi_char16_printk()
  efi: Deduplicate efi_file_size() / _read() / _close()
parents f7458a5d b3879a4d
......@@ -31,6 +31,8 @@ Offset Proto Name Meaning
1E9/001 ALL eddbuf_entries Number of entries in eddbuf (below)
1EA/001 ALL edd_mbr_sig_buf_entries Number of entries in edd_mbr_sig_buffer
(below)
1EB/001 ALL kbd_status Numlock is enabled
1EC/001 ALL secure_boot Secure boot is enabled in the firmware
1EF/001 ALL sentinel Used to detect broken bootloaders
290/040 ALL edd_mbr_sig_buffer EDD MBR signatures
2D0/A00 ALL e820_map E820 memory map table
......
......@@ -55,6 +55,7 @@ void efi_virtmap_unload(void);
#define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__)
#define __efi_call_early(f, ...) f(__VA_ARGS__)
#define efi_call_runtime(f, ...) sys_table_arg->runtime->f(__VA_ARGS__)
#define efi_is_64bit() (false)
#define efi_call_proto(protocol, f, instance, ...) \
......
......@@ -50,6 +50,7 @@ int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md);
#define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__)
#define __efi_call_early(f, ...) f(__VA_ARGS__)
#define efi_call_runtime(f, ...) sys_table_arg->runtime->f(__VA_ARGS__)
#define efi_is_64bit() (true)
#define efi_call_proto(protocol, f, instance, ...) \
......
......@@ -32,160 +32,13 @@ static void setup_boot_services##bits(struct efi_config *c) \
\
table = (typeof(table))sys_table; \
\
c->runtime_services = table->runtime; \
c->boot_services = table->boottime; \
c->text_output = table->con_out; \
}
BOOT_SERVICES(32);
BOOT_SERVICES(64);
void efi_char16_printk(efi_system_table_t *, efi_char16_t *);
static efi_status_t
__file_size32(void *__fh, efi_char16_t *filename_16,
void **handle, u64 *file_sz)
{
efi_file_handle_32_t *h, *fh = __fh;
efi_file_info_t *info;
efi_status_t status;
efi_guid_t info_guid = EFI_FILE_INFO_ID;
u32 info_sz;
status = efi_early->call((unsigned long)fh->open, fh, &h, filename_16,
EFI_FILE_MODE_READ, (u64)0);
if (status != EFI_SUCCESS) {
efi_printk(sys_table, "Failed to open file: ");
efi_char16_printk(sys_table, filename_16);
efi_printk(sys_table, "\n");
return status;
}
*handle = h;
info_sz = 0;
status = efi_early->call((unsigned long)h->get_info, h, &info_guid,
&info_sz, NULL);
if (status != EFI_BUFFER_TOO_SMALL) {
efi_printk(sys_table, "Failed to get file info size\n");
return status;
}
grow:
status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
info_sz, (void **)&info);
if (status != EFI_SUCCESS) {
efi_printk(sys_table, "Failed to alloc mem for file info\n");
return status;
}
status = efi_early->call((unsigned long)h->get_info, h, &info_guid,
&info_sz, info);
if (status == EFI_BUFFER_TOO_SMALL) {
efi_call_early(free_pool, info);
goto grow;
}
*file_sz = info->file_size;
efi_call_early(free_pool, info);
if (status != EFI_SUCCESS)
efi_printk(sys_table, "Failed to get initrd info\n");
return status;
}
static efi_status_t
__file_size64(void *__fh, efi_char16_t *filename_16,
void **handle, u64 *file_sz)
{
efi_file_handle_64_t *h, *fh = __fh;
efi_file_info_t *info;
efi_status_t status;
efi_guid_t info_guid = EFI_FILE_INFO_ID;
u64 info_sz;
status = efi_early->call((unsigned long)fh->open, fh, &h, filename_16,
EFI_FILE_MODE_READ, (u64)0);
if (status != EFI_SUCCESS) {
efi_printk(sys_table, "Failed to open file: ");
efi_char16_printk(sys_table, filename_16);
efi_printk(sys_table, "\n");
return status;
}
*handle = h;
info_sz = 0;
status = efi_early->call((unsigned long)h->get_info, h, &info_guid,
&info_sz, NULL);
if (status != EFI_BUFFER_TOO_SMALL) {
efi_printk(sys_table, "Failed to get file info size\n");
return status;
}
grow:
status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
info_sz, (void **)&info);
if (status != EFI_SUCCESS) {
efi_printk(sys_table, "Failed to alloc mem for file info\n");
return status;
}
status = efi_early->call((unsigned long)h->get_info, h, &info_guid,
&info_sz, info);
if (status == EFI_BUFFER_TOO_SMALL) {
efi_call_early(free_pool, info);
goto grow;
}
*file_sz = info->file_size;
efi_call_early(free_pool, info);
if (status != EFI_SUCCESS)
efi_printk(sys_table, "Failed to get initrd info\n");
return status;
}
efi_status_t
efi_file_size(efi_system_table_t *sys_table, void *__fh,
efi_char16_t *filename_16, void **handle, u64 *file_sz)
{
if (efi_early->is64)
return __file_size64(__fh, filename_16, handle, file_sz);
return __file_size32(__fh, filename_16, handle, file_sz);
}
efi_status_t
efi_file_read(void *handle, unsigned long *size, void *addr)
{
unsigned long func;
if (efi_early->is64) {
efi_file_handle_64_t *fh = handle;
func = (unsigned long)fh->read;
return efi_early->call(func, handle, size, addr);
} else {
efi_file_handle_32_t *fh = handle;
func = (unsigned long)fh->read;
return efi_early->call(func, handle, size, addr);
}
}
efi_status_t efi_file_close(void *handle)
{
if (efi_early->is64) {
efi_file_handle_64_t *fh = handle;
return efi_early->call((unsigned long)fh->close, handle);
} else {
efi_file_handle_32_t *fh = handle;
return efi_early->call((unsigned long)fh->close, handle);
}
}
static inline efi_status_t __open_volume32(void *__image, void **__fh)
{
efi_file_io_interface_t *io;
......@@ -249,30 +102,8 @@ efi_open_volume(efi_system_table_t *sys_table, void *__image, void **__fh)
void efi_char16_printk(efi_system_table_t *table, efi_char16_t *str)
{
unsigned long output_string;
size_t offset;
if (efi_early->is64) {
struct efi_simple_text_output_protocol_64 *out;
u64 *func;
offset = offsetof(typeof(*out), output_string);
output_string = efi_early->text_output + offset;
out = (typeof(out))(unsigned long)efi_early->text_output;
func = (u64 *)output_string;
efi_early->call(*func, out, str);
} else {
struct efi_simple_text_output_protocol_32 *out;
u32 *func;
offset = offsetof(typeof(*out), output_string);
output_string = efi_early->text_output + offset;
out = (typeof(out))(unsigned long)efi_early->text_output;
func = (u32 *)output_string;
efi_early->call(*func, out, str);
}
efi_call_proto(efi_simple_text_output_protocol, output_string,
efi_early->text_output, str);
}
static efi_status_t
......@@ -1157,6 +988,13 @@ struct boot_params *efi_main(struct efi_config *c,
else
setup_boot_services32(efi_early);
/*
* If the boot loader gave us a value for secure_boot then we use that,
* otherwise we ask the BIOS.
*/
if (boot_params->secure_boot == efi_secureboot_mode_unset)
boot_params->secure_boot = efi_get_secureboot(sys_table);
setup_graphics(boot_params);
setup_efi_pci(boot_params);
......
......@@ -82,7 +82,7 @@ ENTRY(efi_pe_entry)
/* Relocate efi_config->call() */
leal efi32_config(%esi), %eax
add %esi, 32(%eax)
add %esi, 40(%eax)
pushl %eax
call make_boot_params
......@@ -108,7 +108,7 @@ ENTRY(efi32_stub_entry)
/* Relocate efi_config->call() */
leal efi32_config(%esi), %eax
add %esi, 32(%eax)
add %esi, 40(%eax)
pushl %eax
2:
call efi_main
......@@ -264,7 +264,7 @@ relocated:
#ifdef CONFIG_EFI_STUB
.data
efi32_config:
.fill 4,8,0
.fill 5,8,0
.long efi_call_phys
.long 0
.byte 0
......
......@@ -264,7 +264,7 @@ ENTRY(efi_pe_entry)
/*
* Relocate efi_config->call().
*/
addq %rbp, efi64_config+32(%rip)
addq %rbp, efi64_config+40(%rip)
movq %rax, %rdi
call make_boot_params
......@@ -284,7 +284,7 @@ handover_entry:
* Relocate efi_config->call().
*/
movq efi_config(%rip), %rax
addq %rbp, 32(%rax)
addq %rbp, 40(%rax)
2:
movq efi_config(%rip), %rdi
call efi_main
......@@ -456,14 +456,14 @@ efi_config:
#ifdef CONFIG_EFI_MIXED
.global efi32_config
efi32_config:
.fill 4,8,0
.fill 5,8,0
.quad efi64_thunk
.byte 0
#endif
.global efi64_config
efi64_config:
.fill 4,8,0
.fill 5,8,0
.quad efi_call
.byte 1
#endif /* CONFIG_EFI_STUB */
......
......@@ -191,6 +191,7 @@ static inline efi_status_t efi_thunk_set_virtual_address_map(
struct efi_config {
u64 image_handle;
u64 table;
u64 runtime_services;
u64 boot_services;
u64 text_output;
efi_status_t (*call)(unsigned long, ...);
......@@ -226,6 +227,10 @@ static inline bool efi_is_64bit(void)
#define __efi_call_early(f, ...) \
__efi_early()->call((unsigned long)f, __VA_ARGS__);
#define efi_call_runtime(f, ...) \
__efi_early()->call(efi_table_attr(efi_runtime_services, f, \
__efi_early()->runtime_services), __VA_ARGS__)
extern bool efi_reboot_required(void);
#else
......
......@@ -135,7 +135,8 @@ struct boot_params {
__u8 eddbuf_entries; /* 0x1e9 */
__u8 edd_mbr_sig_buf_entries; /* 0x1ea */
__u8 kbd_status; /* 0x1eb */
__u8 _pad5[3]; /* 0x1ec */
__u8 secure_boot; /* 0x1ec */
__u8 _pad5[2]; /* 0x1ed */
/*
* The sentinel is set to a nonzero value (0xff) in header.S.
*
......
......@@ -35,6 +35,7 @@
#include <linux/bootmem.h>
#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/efi-bgrt.h>
#include <asm/irqdomain.h>
#include <asm/pci_x86.h>
......@@ -1557,6 +1558,12 @@ int __init early_acpi_boot_init(void)
return 0;
}
static int __init acpi_parse_bgrt(struct acpi_table_header *table)
{
efi_bgrt_init(table);
return 0;
}
int __init acpi_boot_init(void)
{
/* those are executed after early-quirks are executed */
......@@ -1581,6 +1588,8 @@ int __init acpi_boot_init(void)
acpi_process_madt();
acpi_table_parse(ACPI_SIG_HPET, acpi_parse_hpet);
if (IS_ENABLED(CONFIG_ACPI_BGRT))
acpi_table_parse(ACPI_SIG_BGRT, acpi_parse_bgrt);
if (!acpi_noirq)
x86_init.pci.init = pci_acpi_init;
......
......@@ -81,6 +81,7 @@ void common(void) {
BLANK();
OFFSET(BP_scratch, boot_params, scratch);
OFFSET(BP_secure_boot, boot_params, secure_boot);
OFFSET(BP_loadflags, boot_params, hdr.loadflags);
OFFSET(BP_hardware_subarch, boot_params, hdr.hardware_subarch);
OFFSET(BP_version, boot_params, hdr.version);
......
......@@ -1176,6 +1176,20 @@ void __init setup_arch(char **cmdline_p)
/* Allocate bigger log buffer */
setup_log_buf(1);
if (efi_enabled(EFI_BOOT)) {
switch (boot_params.secure_boot) {
case efi_secureboot_mode_disabled:
pr_info("Secure boot disabled\n");
break;
case efi_secureboot_mode_enabled:
pr_info("Secure boot enabled\n");
break;
default:
pr_info("Secure boot could not be determined\n");
break;
}
}
reserve_initrd();
acpi_table_upgrade();
......
......@@ -19,8 +19,7 @@
#include <linux/efi.h>
#include <linux/efi-bgrt.h>
struct acpi_table_bgrt *bgrt_tab;
void *__initdata bgrt_image;
struct acpi_table_bgrt bgrt_tab;
size_t __initdata bgrt_image_size;
struct bmp_header {
......@@ -28,66 +27,58 @@ struct bmp_header {
u32 size;
} __packed;
void __init efi_bgrt_init(void)
void __init efi_bgrt_init(struct acpi_table_header *table)
{
acpi_status status;
void *image;
struct bmp_header bmp_header;
struct acpi_table_bgrt *bgrt = &bgrt_tab;
if (acpi_disabled)
return;
status = acpi_get_table("BGRT", 0,
(struct acpi_table_header **)&bgrt_tab);
if (ACPI_FAILURE(status))
return;
if (bgrt_tab->header.length < sizeof(*bgrt_tab)) {
if (table->length < sizeof(bgrt_tab)) {
pr_notice("Ignoring BGRT: invalid length %u (expected %zu)\n",
bgrt_tab->header.length, sizeof(*bgrt_tab));
table->length, sizeof(bgrt_tab));
return;
}
if (bgrt_tab->version != 1) {
*bgrt = *(struct acpi_table_bgrt *)table;
if (bgrt->version != 1) {
pr_notice("Ignoring BGRT: invalid version %u (expected 1)\n",
bgrt_tab->version);
return;
bgrt->version);
goto out;
}
if (bgrt_tab->status & 0xfe) {
if (bgrt->status & 0xfe) {
pr_notice("Ignoring BGRT: reserved status bits are non-zero %u\n",
bgrt_tab->status);
return;
bgrt->status);
goto out;
}
if (bgrt_tab->image_type != 0) {
if (bgrt->image_type != 0) {
pr_notice("Ignoring BGRT: invalid image type %u (expected 0)\n",
bgrt_tab->image_type);
return;
bgrt->image_type);
goto out;
}
if (!bgrt_tab->image_address) {
if (!bgrt->image_address) {
pr_notice("Ignoring BGRT: null image address\n");
return;
goto out;
}
image = memremap(bgrt_tab->image_address, sizeof(bmp_header), MEMREMAP_WB);
image = early_memremap(bgrt->image_address, sizeof(bmp_header));
if (!image) {
pr_notice("Ignoring BGRT: failed to map image header memory\n");
return;
goto out;
}
memcpy(&bmp_header, image, sizeof(bmp_header));
memunmap(image);
early_memunmap(image, sizeof(bmp_header));
if (bmp_header.id != 0x4d42) {
pr_notice("Ignoring BGRT: Incorrect BMP magic number 0x%x (expected 0x4d42)\n",
bmp_header.id);
return;
goto out;
}
bgrt_image_size = bmp_header.size;
efi_mem_reserve(bgrt->image_address, bgrt_image_size);
bgrt_image = memremap(bgrt_tab->image_address, bmp_header.size, MEMREMAP_WB);
if (!bgrt_image) {
pr_notice("Ignoring BGRT: failed to map image memory\n");
bgrt_image = NULL;
return;
}
efi_mem_reserve(bgrt_tab->image_address, bgrt_image_size);
return;
out:
memset(bgrt, 0, sizeof(bgrt_tab));
}
......@@ -542,11 +542,6 @@ void __init efi_init(void)
efi_print_memmap();
}
void __init efi_late_init(void)
{
efi_bgrt_init();
}
void __init efi_set_executable(efi_memory_desc_t *md, bool executable)
{
u64 addr, npages;
......@@ -960,6 +955,11 @@ static void __init __efi_enter_virtual_mode(void)
return;
}
if (efi_enabled(EFI_DBG)) {
pr_info("EFI runtime memory map:\n");
efi_print_memmap();
}
BUG_ON(!efi.systab);
if (efi_setup_page_tables(pa, 1 << pg_shift)) {
......
......@@ -414,10 +414,44 @@ void __init parse_efi_setup(u64 phys_addr, u32 data_len)
efi_setup = phys_addr + sizeof(struct setup_data);
}
void __init efi_runtime_update_mappings(void)
static int __init efi_update_mappings(efi_memory_desc_t *md, unsigned long pf)
{
unsigned long pfn;
pgd_t *pgd = efi_pgd;
int err1, err2;
/* Update the 1:1 mapping */
pfn = md->phys_addr >> PAGE_SHIFT;
err1 = kernel_map_pages_in_pgd(pgd, pfn, md->phys_addr, md->num_pages, pf);
if (err1) {
pr_err("Error while updating 1:1 mapping PA 0x%llx -> VA 0x%llx!\n",
md->phys_addr, md->virt_addr);
}
err2 = kernel_map_pages_in_pgd(pgd, pfn, md->virt_addr, md->num_pages, pf);
if (err2) {
pr_err("Error while updating VA mapping PA 0x%llx -> VA 0x%llx!\n",
md->phys_addr, md->virt_addr);
}
return err1 || err2;
}
static int __init efi_update_mem_attr(struct mm_struct *mm, efi_memory_desc_t *md)
{
unsigned long pf = 0;
if (md->attribute & EFI_MEMORY_XP)
pf |= _PAGE_NX;
if (!(md->attribute & EFI_MEMORY_RO))
pf |= _PAGE_RW;
return efi_update_mappings(md, pf);
}
void __init efi_runtime_update_mappings(void)
{
efi_memory_desc_t *md;
if (efi_enabled(EFI_OLD_MEMMAP)) {
......@@ -426,6 +460,24 @@ void __init efi_runtime_update_mappings(void)
return;
}
/*
* Use the EFI Memory Attribute Table for mapping permissions if it
* exists, since it is intended to supersede EFI_PROPERTIES_TABLE.
*/
if (efi_enabled(EFI_MEM_ATTR)) {
efi_memattr_apply_permissions(NULL, efi_update_mem_attr);
return;
}
/*
* EFI_MEMORY_ATTRIBUTES_TABLE is intended to replace
* EFI_PROPERTIES_TABLE. So, use EFI_PROPERTIES_TABLE to update
* permissions only if EFI_MEMORY_ATTRIBUTES_TABLE is not
* published by the firmware. Even if we find a buggy implementation of
* EFI_MEMORY_ATTRIBUTES_TABLE, don't fall back to
* EFI_PROPERTIES_TABLE, because of the same reason.
*/
if (!efi_enabled(EFI_NX_PE_DATA))
return;
......@@ -446,15 +498,7 @@ void __init efi_runtime_update_mappings(void)
(md->type != EFI_RUNTIME_SERVICES_CODE))
pf |= _PAGE_RW;
/* Update the 1:1 mapping */
pfn = md->phys_addr >> PAGE_SHIFT;
if (kernel_map_pages_in_pgd(pgd, pfn, md->phys_addr, md->num_pages, pf))
pr_warn("Error mapping PA 0x%llx -> VA 0x%llx!\n",
md->phys_addr, md->virt_addr);
if (kernel_map_pages_in_pgd(pgd, pfn, md->virt_addr, md->num_pages, pf))
pr_warn("Error mapping PA 0x%llx -> VA 0x%llx!\n",
md->phys_addr, md->virt_addr);
efi_update_mappings(md, pf);
}
}
......
......@@ -15,40 +15,41 @@
#include <linux/sysfs.h>
#include <linux/efi-bgrt.h>
static void *bgrt_image;
static struct kobject *bgrt_kobj;
static ssize_t show_version(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab->version);
return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab.version);
}
static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
static ssize_t show_status(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab->status);
return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab.status);
}
static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
static ssize_t show_type(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab->image_type);
return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab.image_type);
}
static DEVICE_ATTR(type, S_IRUGO, show_type, NULL);
static ssize_t show_xoffset(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab->image_offset_x);
return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab.image_offset_x);
}
static DEVICE_ATTR(xoffset, S_IRUGO, show_xoffset, NULL);
static ssize_t show_yoffset(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab->image_offset_y);
return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab.image_offset_y);
}
static DEVICE_ATTR(yoffset, S_IRUGO, show_yoffset, NULL);
......@@ -84,15 +85,24 @@ static int __init bgrt_init(void)
{
int ret;
if (!bgrt_image)
if (!bgrt_tab.image_address)
return -ENODEV;
bgrt_image = memremap(bgrt_tab.image_address, bgrt_image_size,
MEMREMAP_WB);
if (!bgrt_image) {
pr_notice("Ignoring BGRT: failed to map image memory\n");
return -ENOMEM;
}
bin_attr_image.private = bgrt_image;
bin_attr_image.size = bgrt_image_size;
bgrt_kobj = kobject_create_and_add("bgrt", acpi_kobj);
if (!bgrt_kobj)
return -EINVAL;
if (!bgrt_kobj) {
ret = -EINVAL;
goto out_memmap;
}
ret = sysfs_create_group(bgrt_kobj, &bgrt_attribute_group);
if (ret)
......@@ -102,6 +112,8 @@ static int __init bgrt_init(void)
out_kobject:
kobject_put(bgrt_kobj);
out_memmap:
memunmap(bgrt_image);
return ret;
}
device_initcall(bgrt_init);
......@@ -250,7 +250,6 @@ void __init efi_init(void)
}
reserve_regions();
efi_memattr_init();
efi_esrt_init();
efi_memmap_unmap();
......
......@@ -529,6 +529,8 @@ int __init efi_config_parse_tables(void *config_tables, int count, int sz,
}
}
efi_memattr_init();
/* Parse the EFI Properties table if it exists */
if (efi.properties_table != EFI_INVALID_TABLE_ADDR) {
efi_properties_table_t *tbl;
......
......@@ -269,7 +269,7 @@ void __init efi_esrt_init(void)
max -= efi.esrt;
if (max < size) {
pr_err("ESRT header doen't fit on single memory map entry. (size: %zu max: %zu)\n",
pr_err("ESRT header doesn't fit on single memory map entry. (size: %zu max: %zu)\n",
size, max);
return;
}
......
......@@ -11,7 +11,7 @@ cflags-$(CONFIG_X86) += -m$(BITS) -D__KERNEL__ -O2 \
-mno-mmx -mno-sse
cflags-$(CONFIG_ARM64) := $(subst -pg,,$(KBUILD_CFLAGS))
cflags-$(CONFIG_ARM) := $(subst -pg,,$(KBUILD_CFLAGS)) -g0 \
cflags-$(CONFIG_ARM) := $(subst -pg,,$(KBUILD_CFLAGS)) \
-fno-builtin -fpic -mno-single-pic-base
cflags-$(CONFIG_EFI_ARMSTUB) += -I$(srctree)/scripts/dtc/libfdt
......@@ -28,7 +28,7 @@ OBJECT_FILES_NON_STANDARD := y
# Prevents link failures: __sanitizer_cov_trace_pc() is not linked in.
KCOV_INSTRUMENT := n
lib-y := efi-stub-helper.o gop.o
lib-y := efi-stub-helper.o gop.o secureboot.o
# include the stub's generic dependencies from lib/ when building for ARM/arm64
arm-deps := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c fdt_empty_tree.c fdt_sw.c sort.c
......@@ -60,7 +60,7 @@ CFLAGS_arm64-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
extra-$(CONFIG_EFI_ARMSTUB) := $(lib-y)
lib-$(CONFIG_EFI_ARMSTUB) := $(patsubst %.o,%.stub.o,$(lib-y))
STUBCOPY_FLAGS-y := -R .debug* -R *ksymtab* -R *kcrctab*
STUBCOPY_RM-y := -R *ksymtab* -R *kcrctab*
STUBCOPY_FLAGS-$(CONFIG_ARM64) += --prefix-alloc-sections=.init \
--prefix-symbols=__efistub_
STUBCOPY_RELOC-$(CONFIG_ARM64) := R_AARCH64_ABS
......@@ -68,17 +68,25 @@ STUBCOPY_RELOC-$(CONFIG_ARM64) := R_AARCH64_ABS
$(obj)/%.stub.o: $(obj)/%.o FORCE
$(call if_changed,stubcopy)
#
# Strip debug sections and some other sections that may legally contain
# absolute relocations, so that we can inspect the remaining sections for
# such relocations. If none are found, regenerate the output object, but
# this time, use objcopy and leave all sections in place.
#
quiet_cmd_stubcopy = STUBCPY $@
cmd_stubcopy = if $(OBJCOPY) $(STUBCOPY_FLAGS-y) $< $@; then \
$(OBJDUMP) -r $@ | grep $(STUBCOPY_RELOC-y) \
&& (echo >&2 "$@: absolute symbol references not allowed in the EFI stub"; \
rm -f $@; /bin/false); else /bin/false; fi
cmd_stubcopy = if $(STRIP) --strip-debug $(STUBCOPY_RM-y) -o $@ $<; \
then if $(OBJDUMP) -r $@ | grep $(STUBCOPY_RELOC-y); \
then (echo >&2 "$@: absolute symbol references not allowed in the EFI stub"; \
rm -f $@; /bin/false); \
else $(OBJCOPY) $(STUBCOPY_FLAGS-y) $< $@; fi \
else /bin/false; fi
#
# ARM discards the .data section because it disallows r/w data in the
# decompressor. So move our .data to .data.efistub, which is preserved
# explicitly by the decompressor linker script.
#
STUBCOPY_FLAGS-$(CONFIG_ARM) += --rename-section .data=.data.efistub \
-R ___ksymtab+sort -R ___kcrctab+sort
STUBCOPY_FLAGS-$(CONFIG_ARM) += --rename-section .data=.data.efistub
STUBCOPY_RM-$(CONFIG_ARM) += -R ___ksymtab+sort -R ___kcrctab+sort
STUBCOPY_RELOC-$(CONFIG_ARM) := R_ARM_ABS
......@@ -20,52 +20,6 @@
bool __nokaslr;
static int efi_get_secureboot(efi_system_table_t *sys_table_arg)
{
static efi_char16_t const sb_var_name[] = {
'S', 'e', 'c', 'u', 'r', 'e', 'B', 'o', 'o', 't', 0 };
static efi_char16_t const sm_var_name[] = {
'S', 'e', 't', 'u', 'p', 'M', 'o', 'd', 'e', 0 };
efi_guid_t var_guid = EFI_GLOBAL_VARIABLE_GUID;
efi_get_variable_t *f_getvar = sys_table_arg->runtime->get_variable;
u8 val;
unsigned long size = sizeof(val);
efi_status_t status;
status = f_getvar((efi_char16_t *)sb_var_name, (efi_guid_t *)&var_guid,
NULL, &size, &val);
if (status != EFI_SUCCESS)
goto out_efi_err;
if (val == 0)
return 0;
status = f_getvar((efi_char16_t *)sm_var_name, (efi_guid_t *)&var_guid,
NULL, &size, &val);
if (status != EFI_SUCCESS)
goto out_efi_err;
if (val == 1)
return 0;
return 1;
out_efi_err:
switch (status) {
case EFI_NOT_FOUND:
return 0;
case EFI_DEVICE_ERROR:
return -EIO;
case EFI_SECURITY_VIOLATION:
return -EACCES;
default:
return -EINVAL;
}
}
efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg,
void *__image, void **__fh)
{
......@@ -91,75 +45,6 @@ efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg,
return status;
}
efi_status_t efi_file_close(void *handle)
{
efi_file_handle_t *fh = handle;
return fh->close(handle);
}
efi_status_t
efi_file_read(void *handle, unsigned long *size, void *addr)
{
efi_file_handle_t *fh = handle;
return fh->read(handle, size, addr);
}
efi_status_t
efi_file_size(efi_system_table_t *sys_table_arg, void *__fh,
efi_char16_t *filename_16, void **handle, u64 *file_sz)
{
efi_file_handle_t *h, *fh = __fh;
efi_file_info_t *info;
efi_status_t status;
efi_guid_t info_guid = EFI_FILE_INFO_ID;
unsigned long info_sz;
status = fh->open(fh, &h, filename_16, EFI_FILE_MODE_READ, (u64)0);
if (status != EFI_SUCCESS) {
efi_printk(sys_table_arg, "Failed to open file: ");
efi_char16_printk(sys_table_arg, filename_16);
efi_printk(sys_table_arg, "\n");
return status;
}
*handle = h;
info_sz = 0;
status = h->get_info(h, &info_guid, &info_sz, NULL);
if (status != EFI_BUFFER_TOO_SMALL) {
efi_printk(sys_table_arg, "Failed to get file info size\n");
return status;
}
grow:
status = sys_table_arg->boottime->allocate_pool(EFI_LOADER_DATA,
info_sz, (void **)&info);
if (status != EFI_SUCCESS) {
efi_printk(sys_table_arg, "Failed to alloc mem for file info\n");
return status;
}
status = h->get_info(h, &info_guid, &info_sz,
info);
if (status == EFI_BUFFER_TOO_SMALL) {
sys_table_arg->boottime->free_pool(info);
goto grow;
}
*file_sz = info->file_size;
sys_table_arg->boottime->free_pool(info);
if (status != EFI_SUCCESS)
efi_printk(sys_table_arg, "Failed to get initrd info\n");
return status;
}
void efi_char16_printk(efi_system_table_t *sys_table_arg,
efi_char16_t *str)
{
......@@ -226,7 +111,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
efi_guid_t loaded_image_proto = LOADED_IMAGE_PROTOCOL_GUID;
unsigned long reserve_addr = 0;
unsigned long reserve_size = 0;
int secure_boot = 0;
enum efi_secureboot_mode secure_boot;
struct screen_info *si;
/* Check if we were booted by the EFI firmware */
......@@ -296,19 +181,14 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
pr_efi_err(sys_table, "Failed to parse EFI cmdline options\n");
secure_boot = efi_get_secureboot(sys_table);
if (secure_boot > 0)
pr_efi(sys_table, "UEFI Secure Boot is enabled.\n");
if (secure_boot < 0) {
pr_efi_err(sys_table,
"could not determine UEFI Secure Boot status.\n");
}
/*
* Unauthenticated device tree data is a security hazard, so
* ignore 'dtb=' unless UEFI Secure Boot is disabled.
* Unauthenticated device tree data is a security hazard, so ignore
* 'dtb=' unless UEFI Secure Boot is disabled. We assume that secure
* boot is enabled if we can't determine its state.
*/
if (secure_boot != 0 && strstr(cmdline_ptr, "dtb=")) {
if (secure_boot != efi_secureboot_mode_disabled &&
strstr(cmdline_ptr, "dtb=")) {
pr_efi(sys_table, "Ignoring DTB from command line.\n");
} else {
status = handle_cmdline_files(sys_table, image, cmdline_ptr,
......
......@@ -338,6 +338,69 @@ void efi_free(efi_system_table_t *sys_table_arg, unsigned long size,
efi_call_early(free_pages, addr, nr_pages);
}
static efi_status_t efi_file_size(efi_system_table_t *sys_table_arg, void *__fh,
efi_char16_t *filename_16, void **handle,
u64 *file_sz)
{
efi_file_handle_t *h, *fh = __fh;
efi_file_info_t *info;
efi_status_t status;
efi_guid_t info_guid = EFI_FILE_INFO_ID;
unsigned long info_sz;
status = efi_call_proto(efi_file_handle, open, fh, &h, filename_16,
EFI_FILE_MODE_READ, (u64)0);
if (status != EFI_SUCCESS) {
efi_printk(sys_table_arg, "Failed to open file: ");
efi_char16_printk(sys_table_arg, filename_16);
efi_printk(sys_table_arg, "\n");
return status;
}
*handle = h;
info_sz = 0;
status = efi_call_proto(efi_file_handle, get_info, h, &info_guid,
&info_sz, NULL);
if (status != EFI_BUFFER_TOO_SMALL) {
efi_printk(sys_table_arg, "Failed to get file info size\n");
return status;
}
grow:
status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
info_sz, (void **)&info);
if (status != EFI_SUCCESS) {
efi_printk(sys_table_arg, "Failed to alloc mem for file info\n");
return status;
}
status = efi_call_proto(efi_file_handle, get_info, h, &info_guid,
&info_sz, info);
if (status == EFI_BUFFER_TOO_SMALL) {
efi_call_early(free_pool, info);
goto grow;
}
*file_sz = info->file_size;
efi_call_early(free_pool, info);
if (status != EFI_SUCCESS)
efi_printk(sys_table_arg, "Failed to get initrd info\n");
return status;
}
static efi_status_t efi_file_read(void *handle, unsigned long *size, void *addr)
{
return efi_call_proto(efi_file_handle, read, handle, size, addr);
}
static efi_status_t efi_file_close(void *handle)
{
return efi_call_proto(efi_file_handle, close, handle);
}
/*
* Parse the ASCII string 'cmdline' for EFI options, denoted by the efi=
* option, e.g. efi=nochunk.
......@@ -350,6 +413,14 @@ efi_status_t efi_parse_options(char *cmdline)
{
char *str;
/*
* Currently, the only efi= option we look for is 'nochunk', which
* is intended to work around known issues on certain x86 UEFI
* versions. So ignore for now on other architectures.
*/
if (!IS_ENABLED(CONFIG_X86))
return EFI_SUCCESS;
/*
* If no EFI parameters were specified on the cmdline we've got
* nothing to do.
......@@ -523,7 +594,8 @@ efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
size = files[j].size;
while (size) {
unsigned long chunksize;
if (size > __chunk_size)
if (IS_ENABLED(CONFIG_X86) && size > __chunk_size)
chunksize = __chunk_size;
else
chunksize = size;
......
......@@ -29,14 +29,6 @@ void efi_char16_printk(efi_system_table_t *, efi_char16_t *);
efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, void *__image,
void **__fh);
efi_status_t efi_file_size(efi_system_table_t *sys_table_arg, void *__fh,
efi_char16_t *filename_16, void **handle,
u64 *file_sz);
efi_status_t efi_file_read(void *handle, unsigned long *size, void *addr);
efi_status_t efi_file_close(void *handle);
unsigned long get_dram_base(efi_system_table_t *sys_table_arg);
efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
......
/*
* Secure boot handling.
*
* Copyright (C) 2013,2014 Linaro Limited
* Roy Franz <roy.franz@linaro.org
* Copyright (C) 2013 Red Hat, Inc.
* Mark Salter <msalter@redhat.com>
*
* This file is part of the Linux kernel, and is made available under the
* terms of the GNU General Public License version 2.
*/
#include <linux/efi.h>
#include <asm/efi.h>
/* BIOS variables */
static const efi_guid_t efi_variable_guid = EFI_GLOBAL_VARIABLE_GUID;
static const efi_char16_t const efi_SecureBoot_name[] = {
'S', 'e', 'c', 'u', 'r', 'e', 'B', 'o', 'o', 't', 0
};
static const efi_char16_t const efi_SetupMode_name[] = {
'S', 'e', 't', 'u', 'p', 'M', 'o', 'd', 'e', 0
};
/* SHIM variables */
static const efi_guid_t shim_guid = EFI_SHIM_LOCK_GUID;
static efi_char16_t const shim_MokSBState_name[] = {
'M', 'o', 'k', 'S', 'B', 'S', 't', 'a', 't', 'e', 0
};
#define get_efi_var(name, vendor, ...) \
efi_call_runtime(get_variable, \
(efi_char16_t *)(name), (efi_guid_t *)(vendor), \
__VA_ARGS__);
/*
* Determine whether we're in secure boot mode.
*/
enum efi_secureboot_mode efi_get_secureboot(efi_system_table_t *sys_table_arg)
{
u32 attr;
u8 secboot, setupmode, moksbstate;
unsigned long size;
efi_status_t status;
size = sizeof(secboot);
status = get_efi_var(efi_SecureBoot_name, &efi_variable_guid,
NULL, &size, &secboot);
if (status != EFI_SUCCESS)
goto out_efi_err;
size = sizeof(setupmode);
status = get_efi_var(efi_SetupMode_name, &efi_variable_guid,
NULL, &size, &setupmode);
if (status != EFI_SUCCESS)
goto out_efi_err;
if (secboot == 0 || setupmode == 1)
return efi_secureboot_mode_disabled;
/*
* See if a user has put the shim into insecure mode. If so, and if the
* variable doesn't have the runtime attribute set, we might as well
* honor that.
*/
size = sizeof(moksbstate);
status = get_efi_var(shim_MokSBState_name, &shim_guid,
&attr, &size, &moksbstate);
/* If it fails, we don't care why. Default to secure */
if (status != EFI_SUCCESS)
goto secure_boot_enabled;
if (!(attr & EFI_VARIABLE_RUNTIME_ACCESS) && moksbstate == 1)
return efi_secureboot_mode_disabled;
secure_boot_enabled:
pr_efi(sys_table_arg, "UEFI Secure Boot is enabled.\n");
return efi_secureboot_mode_enabled;
out_efi_err:
pr_efi_err(sys_table_arg, "Could not determine UEFI Secure Boot status.\n");
if (status == EFI_NOT_FOUND)
return efi_secureboot_mode_disabled;
return efi_secureboot_mode_unknown;
}
......@@ -43,6 +43,7 @@ int __init efi_memattr_init(void)
tbl_size = sizeof(*tbl) + tbl->num_entries * tbl->desc_size;
memblock_reserve(efi.mem_attr_table, tbl_size);
set_bit(EFI_MEM_ATTR, &efi.flags);
unmap:
early_memunmap(tbl, sizeof(*tbl));
......@@ -174,8 +175,11 @@ int __init efi_memattr_apply_permissions(struct mm_struct *mm,
md.phys_addr + size - 1,
efi_md_typeattr_format(buf, sizeof(buf), &md));
if (valid)
if (valid) {
ret = fn(mm, &md);
if (ret)
pr_err("Error updating mappings, skipping subsequent md's\n");
}
}
memunmap(tbl);
return ret;
......
#ifndef _LINUX_EFI_BGRT_H
#define _LINUX_EFI_BGRT_H
#ifdef CONFIG_ACPI_BGRT
#include <linux/acpi.h>
void efi_bgrt_init(void);
#ifdef CONFIG_ACPI_BGRT
void efi_bgrt_init(struct acpi_table_header *table);
/* The BGRT data itself; only valid if bgrt_image != NULL. */
extern void *bgrt_image;
extern size_t bgrt_image_size;
extern struct acpi_table_bgrt *bgrt_tab;
extern struct acpi_table_bgrt bgrt_tab;
#else /* !CONFIG_ACPI_BGRT */
static inline void efi_bgrt_init(void) {}
static inline void efi_bgrt_init(struct acpi_table_header *table) {}
#endif /* !CONFIG_ACPI_BGRT */
......
......@@ -509,24 +509,6 @@ typedef struct {
u64 query_variable_info;
} efi_runtime_services_64_t;
typedef struct {
efi_table_hdr_t hdr;
void *get_time;
void *set_time;
void *get_wakeup_time;
void *set_wakeup_time;
void *set_virtual_address_map;
void *convert_pointer;
void *get_variable;
void *get_next_variable;
void *set_variable;
void *get_next_high_mono_count;
void *reset_system;
void *update_capsule;
void *query_capsule_caps;
void *query_variable_info;
} efi_runtime_services_t;
typedef efi_status_t efi_get_time_t (efi_time_t *tm, efi_time_cap_t *tc);
typedef efi_status_t efi_set_time_t (efi_time_t *tm);
typedef efi_status_t efi_get_wakeup_time_t (efi_bool_t *enabled, efi_bool_t *pending,
......@@ -561,6 +543,24 @@ typedef efi_status_t efi_query_variable_store_t(u32 attributes,
unsigned long size,
bool nonblocking);
typedef struct {
efi_table_hdr_t hdr;
efi_get_time_t *get_time;
efi_set_time_t *set_time;
efi_get_wakeup_time_t *get_wakeup_time;
efi_set_wakeup_time_t *set_wakeup_time;
efi_set_virtual_address_map_t *set_virtual_address_map;
void *convert_pointer;
efi_get_variable_t *get_variable;
efi_get_next_variable_t *get_next_variable;
efi_set_variable_t *set_variable;
efi_get_next_high_mono_count_t *get_next_high_mono_count;
efi_reset_system_t *reset_system;
efi_update_capsule_t *update_capsule;
efi_query_capsule_caps_t *query_capsule_caps;
efi_query_variable_info_t *query_variable_info;
} efi_runtime_services_t;
void efi_native_runtime_setup(void);
/*
......@@ -611,6 +611,9 @@ void efi_native_runtime_setup(void);
#define EFI_CONSOLE_OUT_DEVICE_GUID EFI_GUID(0xd3b36f2c, 0xd551, 0x11d4, 0x9a, 0x46, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
#define APPLE_PROPERTIES_PROTOCOL_GUID EFI_GUID(0x91bd12fe, 0xf6c3, 0x44fb, 0xa5, 0xb7, 0x51, 0x22, 0xab, 0x30, 0x3a, 0xe0)
#define EFI_IMAGE_SECURITY_DATABASE_GUID EFI_GUID(0xd719b2cb, 0x3d3a, 0x4596, 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f)
#define EFI_SHIM_LOCK_GUID EFI_GUID(0x605dab50, 0xe046, 0x4300, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23)
/*
* This GUID is used to pass to the kernel proper the struct screen_info
* structure that was populated by the stub based on the GOP protocol instance
......@@ -1065,6 +1068,7 @@ extern int __init efi_setup_pcdp_console(char *);
#define EFI_ARCH_1 7 /* First arch-specific bit */
#define EFI_DBG 8 /* Print additional debug info at runtime */
#define EFI_NX_PE_DATA 9 /* Can runtime data regions be mapped non-executable? */
#define EFI_MEM_ATTR 10 /* Did firmware publish an EFI_MEMORY_ATTRIBUTES table? */
#ifdef CONFIG_EFI
/*
......@@ -1240,17 +1244,17 @@ struct efivar_entry {
bool deleting;
};
struct efi_simple_text_output_protocol_32 {
typedef struct {
u32 reset;
u32 output_string;
u32 test_string;
};
} efi_simple_text_output_protocol_32_t;
struct efi_simple_text_output_protocol_64 {
typedef struct {
u64 reset;
u64 output_string;
u64 test_string;
};
} efi_simple_text_output_protocol_64_t;
struct efi_simple_text_output_protocol {
void *reset;
......@@ -1476,6 +1480,14 @@ efi_status_t efi_setup_gop(efi_system_table_t *sys_table_arg,
bool efi_runtime_disabled(void);
extern void efi_call_virt_check_flags(unsigned long flags, const char *call);
enum efi_secureboot_mode {
efi_secureboot_mode_unset,
efi_secureboot_mode_unknown,
efi_secureboot_mode_disabled,
efi_secureboot_mode_enabled,
};
enum efi_secureboot_mode efi_get_secureboot(efi_system_table_t *sys_table);
/*
* Arch code can implement the following three template macros, avoiding
* reptition for the void/non-void return cases of {__,}efi_call_virt():
......
......@@ -663,7 +663,6 @@ asmlinkage __visible void __init start_kernel(void)
sfi_init_late();
if (efi_enabled(EFI_RUNTIME_SERVICES)) {
efi_late_init();
efi_free_boot_services();
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment