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

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

   - further EFI code generalization to make it more workable for ARM64
   - various extensions, such as 64-bit framebuffer address support,
     UEFI v2.5 EFI_PROPERTIES_TABLE support
   - code modularization simplifications and cleanups
   - new debugging parameters
   - various fixes and smaller additions"

* 'core-efi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (23 commits)
  efi: Fix warning of int-to-pointer-cast on x86 32-bit builds
  efi: Use correct type for struct efi_memory_map::phys_map
  x86/efi: Fix kernel panic when CONFIG_DEBUG_VIRTUAL is enabled
  efi: Add "efi_fake_mem" boot option
  x86/efi: Rename print_efi_memmap() to efi_print_memmap()
  efi: Auto-load the efi-pstore module
  efi: Introduce EFI_NX_PE_DATA bit and set it from properties table
  efi: Add support for UEFIv2.5 Properties table
  efi: Add EFI_MEMORY_MORE_RELIABLE support to efi_md_typeattr_format()
  efifb: Add support for 64-bit frame buffer addresses
  efi/arm64: Clean up efi_get_fdt_params() interface
  arm64: Use core efi=debug instead of uefi_debug command line parameter
  efi/x86: Move efi=debug option parsing to core
  drivers/firmware: Make efi/esrt.c driver explicitly non-modular
  efi: Use the generic efi.memmap instead of 'memmap'
  acpi/apei: Use appropriate pgprot_t to map GHES memory
  arm64, acpi/apei: Implement arch_apei_get_mem_attributes()
  arm64/mm: Add PROT_DEVICE_nGnRnE and PROT_NORMAL_WT
  acpi, x86: Implement arch_apei_get_mem_attributes()
  efi, x86: Rearrange efi_mem_attributes()
  ...
This commit is contained in:
Linus Torvalds 2015-11-03 15:05:52 -08:00
commit f5a8160c1e
26 changed files with 532 additions and 105 deletions

View File

@ -60,5 +60,3 @@ linux,uefi-mmap-desc-ver | 32-bit | Version of the mmap descriptor format.
--------------------------------------------------------------------------------
linux,uefi-stub-kern-ver | string | Copy of linux_banner from build.
--------------------------------------------------------------------------------
For verbose debug messages, specify 'uefi_debug' on the kernel command line.

View File

@ -1094,6 +1094,21 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
you are really sure that your UEFI does sane gc and
fulfills the spec otherwise your board may brick.
efi_fake_mem= nn[KMG]@ss[KMG]:aa[,nn[KMG]@ss[KMG]:aa,..] [EFI; X86]
Add arbitrary attribute to specific memory range by
updating original EFI memory map.
Region of memory which aa attribute is added to is
from ss to ss+nn.
If efi_fake_mem=2G@4G:0x10000,2G@0x10a0000000:0x10000
is specified, EFI_MEMORY_MORE_RELIABLE(0x10000)
attribute is added to range 0x100000000-0x180000000 and
0x10a0000000-0x1120000000.
Using this parameter you can do debugging of EFI memmap
related feature. For example, you can do debugging of
Address Range Mirroring feature even if your box
doesn't support it.
eisa_irq_edge= [PARISC,HW]
See header of drivers/parisc/eisa.c.

View File

@ -92,4 +92,9 @@ static inline const char *acpi_get_enable_method(int cpu)
{
return acpi_psci_present() ? "psci" : NULL;
}
#ifdef CONFIG_ACPI_APEI
pgprot_t arch_apei_get_mem_attribute(phys_addr_t addr);
#endif
#endif /*_ASM_ACPI_H*/

View File

@ -94,6 +94,7 @@
#define MT_DEVICE_GRE 2
#define MT_NORMAL_NC 3
#define MT_NORMAL 4
#define MT_NORMAL_WT 5
/*
* Memory types for Stage-2 translation

View File

@ -60,8 +60,10 @@ extern void __pgd_error(const char *file, int line, unsigned long val);
#define PROT_DEFAULT (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED)
#define PROT_SECT_DEFAULT (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S)
#define PROT_DEVICE_nGnRnE (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_ATTRINDX(MT_DEVICE_nGnRnE))
#define PROT_DEVICE_nGnRE (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_ATTRINDX(MT_DEVICE_nGnRE))
#define PROT_NORMAL_NC (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_ATTRINDX(MT_NORMAL_NC))
#define PROT_NORMAL_WT (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_ATTRINDX(MT_NORMAL_WT))
#define PROT_NORMAL (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_ATTRINDX(MT_NORMAL))
#define PROT_SECT_DEVICE_nGnRE (PROT_SECT_DEFAULT | PMD_SECT_PXN | PMD_SECT_UXN | PMD_ATTRINDX(MT_DEVICE_nGnRE))

View File

@ -29,6 +29,11 @@
#include <asm/cpu_ops.h>
#include <asm/smp_plat.h>
#ifdef CONFIG_ACPI_APEI
# include <linux/efi.h>
# include <asm/pgtable.h>
#endif
int acpi_noirq = 1; /* skip ACPI IRQ initialization */
int acpi_disabled = 1;
EXPORT_SYMBOL(acpi_disabled);
@ -230,3 +235,27 @@ void __init acpi_gic_init(void)
early_acpi_os_unmap_memory((char *)table, tbl_size);
}
#ifdef CONFIG_ACPI_APEI
pgprot_t arch_apei_get_mem_attribute(phys_addr_t addr)
{
/*
* According to "Table 8 Map: EFI memory types to AArch64 memory
* types" of UEFI 2.5 section 2.3.6.1, each EFI memory type is
* mapped to a corresponding MAIR attribute encoding.
* The EFI memory attribute advises all possible capabilities
* of a memory region. We use the most efficient capability.
*/
u64 attr;
attr = efi_mem_attributes(addr);
if (attr & EFI_MEMORY_WB)
return PAGE_KERNEL;
if (attr & EFI_MEMORY_WT)
return __pgprot(PROT_NORMAL_WT);
if (attr & EFI_MEMORY_WC)
return __pgprot(PROT_NORMAL_NC);
return __pgprot(PROT_DEVICE_nGnRnE);
}
#endif

View File

@ -51,15 +51,6 @@ static struct mm_struct efi_mm = {
INIT_MM_CONTEXT(efi_mm)
};
static int uefi_debug __initdata;
static int __init uefi_debug_setup(char *str)
{
uefi_debug = 1;
return 0;
}
early_param("uefi_debug", uefi_debug_setup);
static int __init is_normal_ram(efi_memory_desc_t *md)
{
if (md->attribute & EFI_MEMORY_WB)
@ -171,14 +162,14 @@ static __init void reserve_regions(void)
efi_memory_desc_t *md;
u64 paddr, npages, size;
if (uefi_debug)
if (efi_enabled(EFI_DBG))
pr_info("Processing EFI memory map:\n");
for_each_efi_memory_desc(&memmap, md) {
paddr = md->phys_addr;
npages = md->num_pages;
if (uefi_debug) {
if (efi_enabled(EFI_DBG)) {
char buf[64];
pr_info(" 0x%012llx-0x%012llx %s",
@ -194,11 +185,11 @@ static __init void reserve_regions(void)
if (is_reserve_region(md)) {
memblock_reserve(paddr, size);
if (uefi_debug)
if (efi_enabled(EFI_DBG))
pr_cont("*");
}
if (uefi_debug)
if (efi_enabled(EFI_DBG))
pr_cont("\n");
}
@ -210,14 +201,14 @@ void __init efi_init(void)
struct efi_fdt_params params;
/* Grab UEFI information placed in FDT by stub */
if (!efi_get_fdt_params(&params, uefi_debug))
if (!efi_get_fdt_params(&params))
return;
efi_system_table = params.system_table;
memblock_reserve(params.mmap & PAGE_MASK,
PAGE_ALIGN(params.mmap_size + (params.mmap & ~PAGE_MASK)));
memmap.phys_map = (void *)params.mmap;
memmap.phys_map = params.mmap;
memmap.map = early_memremap(params.mmap, params.mmap_size);
memmap.map_end = memmap.map + params.mmap_size;
memmap.desc_size = params.desc_size;
@ -291,7 +282,7 @@ static int __init arm64_enable_runtime_services(void)
pr_info("Remapping and enabling EFI services.\n");
mapsize = memmap.map_end - memmap.map;
memmap.map = (__force void *)ioremap_cache((phys_addr_t)memmap.phys_map,
memmap.map = (__force void *)ioremap_cache(memmap.phys_map,
mapsize);
if (!memmap.map) {
pr_err("Failed to remap EFI memory map\n");

View File

@ -163,12 +163,14 @@ ENTRY(__cpu_setup)
* DEVICE_GRE 010 00001100
* NORMAL_NC 011 01000100
* NORMAL 100 11111111
* NORMAL_WT 101 10111011
*/
ldr x5, =MAIR(0x00, MT_DEVICE_nGnRnE) | \
MAIR(0x04, MT_DEVICE_nGnRE) | \
MAIR(0x0c, MT_DEVICE_GRE) | \
MAIR(0x44, MT_NORMAL_NC) | \
MAIR(0xff, MT_NORMAL)
MAIR(0xff, MT_NORMAL) | \
MAIR(0xbb, MT_NORMAL_WT)
msr mair_el1, x5
/*
* Prepare SCTLR

View File

@ -624,7 +624,7 @@ setup_pixel_info(struct screen_info *si, u32 pixels_per_scan_line,
static efi_status_t
__gop_query32(struct efi_graphics_output_protocol_32 *gop32,
struct efi_graphics_output_mode_info **info,
unsigned long *size, u32 *fb_base)
unsigned long *size, u64 *fb_base)
{
struct efi_graphics_output_protocol_mode_32 *mode;
efi_status_t status;
@ -650,7 +650,8 @@ setup_gop32(struct screen_info *si, efi_guid_t *proto,
unsigned long nr_gops;
u16 width, height;
u32 pixels_per_scan_line;
u32 fb_base;
u32 ext_lfb_base;
u64 fb_base;
struct efi_pixel_bitmask pixel_info;
int pixel_format;
efi_status_t status;
@ -667,7 +668,7 @@ setup_gop32(struct screen_info *si, efi_guid_t *proto,
bool conout_found = false;
void *dummy = NULL;
u32 h = handles[i];
u32 current_fb_base;
u64 current_fb_base;
status = efi_call_early(handle_protocol, h,
proto, (void **)&gop32);
@ -715,6 +716,13 @@ setup_gop32(struct screen_info *si, efi_guid_t *proto,
si->lfb_width = width;
si->lfb_height = height;
si->lfb_base = fb_base;
ext_lfb_base = (u64)(unsigned long)fb_base >> 32;
if (ext_lfb_base) {
si->capabilities |= VIDEO_CAPABILITY_64BIT_BASE;
si->ext_lfb_base = ext_lfb_base;
}
si->pages = 1;
setup_pixel_info(si, pixels_per_scan_line, pixel_info, pixel_format);
@ -729,7 +737,7 @@ setup_gop32(struct screen_info *si, efi_guid_t *proto,
static efi_status_t
__gop_query64(struct efi_graphics_output_protocol_64 *gop64,
struct efi_graphics_output_mode_info **info,
unsigned long *size, u32 *fb_base)
unsigned long *size, u64 *fb_base)
{
struct efi_graphics_output_protocol_mode_64 *mode;
efi_status_t status;
@ -755,7 +763,8 @@ setup_gop64(struct screen_info *si, efi_guid_t *proto,
unsigned long nr_gops;
u16 width, height;
u32 pixels_per_scan_line;
u32 fb_base;
u32 ext_lfb_base;
u64 fb_base;
struct efi_pixel_bitmask pixel_info;
int pixel_format;
efi_status_t status;
@ -772,7 +781,7 @@ setup_gop64(struct screen_info *si, efi_guid_t *proto,
bool conout_found = false;
void *dummy = NULL;
u64 h = handles[i];
u32 current_fb_base;
u64 current_fb_base;
status = efi_call_early(handle_protocol, h,
proto, (void **)&gop64);
@ -820,6 +829,13 @@ setup_gop64(struct screen_info *si, efi_guid_t *proto,
si->lfb_width = width;
si->lfb_height = height;
si->lfb_base = fb_base;
ext_lfb_base = (u64)(unsigned long)fb_base >> 32;
if (ext_lfb_base) {
si->capabilities |= VIDEO_CAPABILITY_64BIT_BASE;
si->ext_lfb_base = ext_lfb_base;
}
si->pages = 1;
setup_pixel_info(si, pixels_per_scan_line, pixel_info, pixel_format);

View File

@ -154,7 +154,7 @@ extra_header_fields:
#else
.quad 0 # ImageBase
#endif
.long CONFIG_PHYSICAL_ALIGN # SectionAlignment
.long 0x20 # SectionAlignment
.long 0x20 # FileAlignment
.word 0 # MajorOperatingSystemVersion
.word 0 # MinorOperatingSystemVersion

View File

@ -32,6 +32,10 @@
#include <asm/mpspec.h>
#include <asm/realmode.h>
#ifdef CONFIG_ACPI_APEI
# include <asm/pgtable_types.h>
#endif
#ifdef CONFIG_ACPI
extern int acpi_lapic;
extern int acpi_ioapic;
@ -147,4 +151,23 @@ extern int x86_acpi_numa_init(void);
#define acpi_unlazy_tlb(x) leave_mm(x)
#ifdef CONFIG_ACPI_APEI
static inline pgprot_t arch_apei_get_mem_attribute(phys_addr_t addr)
{
/*
* We currently have no way to look up the EFI memory map
* attributes for a region in a consistent way, because the
* memmap is discarded after efi_free_boot_services(). So if
* you call efi_mem_attributes() during boot and at runtime,
* you could theoretically see different attributes.
*
* Since we are yet to see any x86 platforms that require
* anything other than PAGE_KERNEL (some arm64 platforms
* require the equivalent of PAGE_KERNEL_NOCACHE), return that
* until we know differently.
*/
return PAGE_KERNEL;
}
#endif
#endif /* _ASM_X86_ACPI_H */

View File

@ -105,6 +105,7 @@ extern void __init efi_set_executable(efi_memory_desc_t *md, bool executable);
extern int __init efi_memblock_x86_reserve_range(void);
extern pgd_t * __init efi_call_phys_prolog(void);
extern void __init efi_call_phys_epilog(pgd_t *save_pgd);
extern void __init efi_print_memmap(void);
extern void __init efi_unmap_memmap(void);
extern void __init efi_memory_uc(u64 addr, unsigned long size);
extern void __init efi_map_region(efi_memory_desc_t *md);

View File

@ -1079,8 +1079,10 @@ void __init setup_arch(char **cmdline_p)
memblock_set_current_limit(ISA_END_ADDRESS);
memblock_x86_fill();
if (efi_enabled(EFI_BOOT))
if (efi_enabled(EFI_BOOT)) {
efi_fake_memmap();
efi_find_mirror();
}
/*
* The EFI specification says that boot service code won't be called

View File

@ -647,9 +647,12 @@ __split_large_page(struct cpa_data *cpa, pte_t *kpte, unsigned long address,
for (i = 0; i < PTRS_PER_PTE; i++, pfn += pfninc)
set_pte(&pbase[i], pfn_pte(pfn, canon_pgprot(ref_prot)));
if (pfn_range_is_mapped(PFN_DOWN(__pa(address)),
PFN_DOWN(__pa(address)) + 1))
split_page_count(level);
if (virt_addr_valid(address)) {
unsigned long pfn = PFN_DOWN(__pa(address));
if (pfn_range_is_mapped(pfn, pfn + 1))
split_page_count(level);
}
/*
* Install the new, split up pagetable.

View File

@ -50,11 +50,16 @@ void __init efi_bgrt_init(void)
bgrt_tab->version);
return;
}
if (bgrt_tab->status != 1) {
pr_err("Ignoring BGRT: invalid status %u (expected 1)\n",
if (bgrt_tab->status & 0xfe) {
pr_err("Ignoring BGRT: reserved status bits are non-zero %u\n",
bgrt_tab->status);
return;
}
if (bgrt_tab->status != 1) {
pr_debug("Ignoring BGRT: invalid status %u (expected 1)\n",
bgrt_tab->status);
return;
}
if (bgrt_tab->image_type != 0) {
pr_err("Ignoring BGRT: invalid image type %u (expected 0)\n",
bgrt_tab->image_type);

View File

@ -194,7 +194,7 @@ static void __init do_add_efi_memmap(void)
int __init efi_memblock_x86_reserve_range(void)
{
struct efi_info *e = &boot_params.efi_info;
unsigned long pmap;
phys_addr_t pmap;
if (efi_enabled(EFI_PARAVIRT))
return 0;
@ -209,7 +209,7 @@ int __init efi_memblock_x86_reserve_range(void)
#else
pmap = (e->efi_memmap | ((__u64)e->efi_memmap_hi << 32));
#endif
memmap.phys_map = (void *)pmap;
memmap.phys_map = pmap;
memmap.nr_map = e->efi_memmap_size /
e->efi_memdesc_size;
memmap.desc_size = e->efi_memdesc_size;
@ -222,7 +222,7 @@ int __init efi_memblock_x86_reserve_range(void)
return 0;
}
static void __init print_efi_memmap(void)
void __init efi_print_memmap(void)
{
#ifdef EFI_DEBUG
efi_memory_desc_t *md;
@ -524,7 +524,7 @@ void __init efi_init(void)
return;
if (efi_enabled(EFI_DBG))
print_efi_memmap();
efi_print_memmap();
efi_esrt_init();
}
@ -1017,24 +1017,6 @@ u32 efi_mem_type(unsigned long phys_addr)
return 0;
}
u64 efi_mem_attributes(unsigned long phys_addr)
{
efi_memory_desc_t *md;
void *p;
if (!efi_enabled(EFI_MEMMAP))
return 0;
for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
md = p;
if ((md->phys_addr <= phys_addr) &&
(phys_addr < (md->phys_addr +
(md->num_pages << EFI_PAGE_SHIFT))))
return md->attribute;
}
return 0;
}
static int __init arch_parse_efi_cmdline(char *str)
{
if (!str) {
@ -1044,8 +1026,6 @@ static int __init arch_parse_efi_cmdline(char *str)
if (parse_option_str(str, "old_map"))
set_bit(EFI_OLD_MEMMAP, &efi.flags);
if (parse_option_str(str, "debug"))
set_bit(EFI_DBG, &efi.flags);
return 0;
}

View File

@ -157,11 +157,15 @@ static void __iomem *ghes_ioremap_pfn_nmi(u64 pfn)
static void __iomem *ghes_ioremap_pfn_irq(u64 pfn)
{
unsigned long vaddr;
unsigned long vaddr, paddr;
pgprot_t prot;
vaddr = (unsigned long)GHES_IOREMAP_IRQ_PAGE(ghes_ioremap_area->addr);
ioremap_page_range(vaddr, vaddr + PAGE_SIZE,
pfn << PAGE_SHIFT, PAGE_KERNEL);
paddr = pfn << PAGE_SHIFT;
prot = arch_apei_get_mem_attribute(paddr);
ioremap_page_range(vaddr, vaddr + PAGE_SIZE, paddr, prot);
return (void __iomem *)vaddr;
}

View File

@ -52,6 +52,28 @@ config EFI_RUNTIME_MAP
See also Documentation/ABI/testing/sysfs-firmware-efi-runtime-map.
config EFI_FAKE_MEMMAP
bool "Enable EFI fake memory map"
depends on EFI && X86
default n
help
Saying Y here will enable "efi_fake_mem" boot option.
By specifying this parameter, you can add arbitrary attribute
to specific memory range by updating original (firmware provided)
EFI memmap.
This is useful for debugging of EFI memmap related feature.
e.g. Address Range Mirroring feature.
config EFI_MAX_FAKE_MEM
int "maximum allowable number of ranges in efi_fake_mem boot option"
depends on EFI_FAKE_MEMMAP
range 1 128
default 8
help
Maximum allowable number of ranges in efi_fake_mem boot option.
Ranges can be set up to this value using comma-separated list.
The default value is 8.
config EFI_PARAMS_FROM_FDT
bool
help

View File

@ -9,3 +9,4 @@ obj-$(CONFIG_UEFI_CPER) += cper.o
obj-$(CONFIG_EFI_RUNTIME_MAP) += runtime-map.o
obj-$(CONFIG_EFI_RUNTIME_WRAPPERS) += runtime-wrappers.o
obj-$(CONFIG_EFI_STUB) += libstub/
obj-$(CONFIG_EFI_FAKE_MEMMAP) += fake_mem.o

View File

@ -400,3 +400,4 @@ module_exit(efivars_pstore_exit);
MODULE_DESCRIPTION("EFI variable backend for pstore");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:efivars");

View File

@ -26,20 +26,21 @@
#include <linux/platform_device.h>
struct efi __read_mostly efi = {
.mps = EFI_INVALID_TABLE_ADDR,
.acpi = EFI_INVALID_TABLE_ADDR,
.acpi20 = EFI_INVALID_TABLE_ADDR,
.smbios = EFI_INVALID_TABLE_ADDR,
.smbios3 = EFI_INVALID_TABLE_ADDR,
.sal_systab = EFI_INVALID_TABLE_ADDR,
.boot_info = EFI_INVALID_TABLE_ADDR,
.hcdp = EFI_INVALID_TABLE_ADDR,
.uga = EFI_INVALID_TABLE_ADDR,
.uv_systab = EFI_INVALID_TABLE_ADDR,
.fw_vendor = EFI_INVALID_TABLE_ADDR,
.runtime = EFI_INVALID_TABLE_ADDR,
.config_table = EFI_INVALID_TABLE_ADDR,
.esrt = EFI_INVALID_TABLE_ADDR,
.mps = EFI_INVALID_TABLE_ADDR,
.acpi = EFI_INVALID_TABLE_ADDR,
.acpi20 = EFI_INVALID_TABLE_ADDR,
.smbios = EFI_INVALID_TABLE_ADDR,
.smbios3 = EFI_INVALID_TABLE_ADDR,
.sal_systab = EFI_INVALID_TABLE_ADDR,
.boot_info = EFI_INVALID_TABLE_ADDR,
.hcdp = EFI_INVALID_TABLE_ADDR,
.uga = EFI_INVALID_TABLE_ADDR,
.uv_systab = EFI_INVALID_TABLE_ADDR,
.fw_vendor = EFI_INVALID_TABLE_ADDR,
.runtime = EFI_INVALID_TABLE_ADDR,
.config_table = EFI_INVALID_TABLE_ADDR,
.esrt = EFI_INVALID_TABLE_ADDR,
.properties_table = EFI_INVALID_TABLE_ADDR,
};
EXPORT_SYMBOL(efi);
@ -63,6 +64,9 @@ static int __init parse_efi_cmdline(char *str)
return -EINVAL;
}
if (parse_option_str(str, "debug"))
set_bit(EFI_DBG, &efi.flags);
if (parse_option_str(str, "noruntime"))
disable_runtime = true;
@ -250,7 +254,7 @@ subsys_initcall(efisubsys_init);
int __init efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md)
{
struct efi_memory_map *map = efi.memmap;
void *p, *e;
phys_addr_t p, e;
if (!efi_enabled(EFI_MEMMAP)) {
pr_err_once("EFI_MEMMAP is not enabled.\n");
@ -282,10 +286,10 @@ int __init efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md)
* So just always get our own virtual map on the CPU.
*
*/
md = early_memremap((phys_addr_t)p, sizeof (*md));
md = early_memremap(p, sizeof (*md));
if (!md) {
pr_err_once("early_memremap(%p, %zu) failed.\n",
p, sizeof (*md));
pr_err_once("early_memremap(%pa, %zu) failed.\n",
&p, sizeof (*md));
return -ENOMEM;
}
@ -362,6 +366,7 @@ static __initdata efi_config_table_type_t common_tables[] = {
{SMBIOS3_TABLE_GUID, "SMBIOS 3.0", &efi.smbios3},
{UGA_IO_PROTOCOL_GUID, "UGA", &efi.uga},
{EFI_SYSTEM_RESOURCE_TABLE_GUID, "ESRT", &efi.esrt},
{EFI_PROPERTIES_TABLE_GUID, "PROP", &efi.properties_table},
{NULL_GUID, NULL, NULL},
};
@ -421,6 +426,24 @@ int __init efi_config_parse_tables(void *config_tables, int count, int sz,
}
pr_cont("\n");
set_bit(EFI_CONFIG_TABLES, &efi.flags);
/* Parse the EFI Properties table if it exists */
if (efi.properties_table != EFI_INVALID_TABLE_ADDR) {
efi_properties_table_t *tbl;
tbl = early_memremap(efi.properties_table, sizeof(*tbl));
if (tbl == NULL) {
pr_err("Could not map Properties table!\n");
return -ENOMEM;
}
if (tbl->memory_protection_attribute &
EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA)
set_bit(EFI_NX_PE_DATA, &efi.flags);
early_memunmap(tbl, sizeof(*tbl));
}
return 0;
}
@ -489,7 +512,6 @@ static __initdata struct {
};
struct param_info {
int verbose;
int found;
void *params;
};
@ -520,21 +542,20 @@ static int __init fdt_find_uefi_params(unsigned long node, const char *uname,
else
*(u64 *)dest = val;
if (info->verbose)
if (efi_enabled(EFI_DBG))
pr_info(" %s: 0x%0*llx\n", dt_params[i].name,
dt_params[i].size * 2, val);
}
return 1;
}
int __init efi_get_fdt_params(struct efi_fdt_params *params, int verbose)
int __init efi_get_fdt_params(struct efi_fdt_params *params)
{
struct param_info info;
int ret;
pr_info("Getting EFI parameters from FDT:\n");
info.verbose = verbose;
info.found = 0;
info.params = params;
@ -588,16 +609,19 @@ char * __init efi_md_typeattr_format(char *buf, size_t size,
attr = md->attribute;
if (attr & ~(EFI_MEMORY_UC | EFI_MEMORY_WC | EFI_MEMORY_WT |
EFI_MEMORY_WB | EFI_MEMORY_UCE | EFI_MEMORY_WP |
EFI_MEMORY_RP | EFI_MEMORY_XP | EFI_MEMORY_RUNTIME))
EFI_MEMORY_WB | EFI_MEMORY_UCE | EFI_MEMORY_RO |
EFI_MEMORY_WP | EFI_MEMORY_RP | EFI_MEMORY_XP |
EFI_MEMORY_RUNTIME | EFI_MEMORY_MORE_RELIABLE))
snprintf(pos, size, "|attr=0x%016llx]",
(unsigned long long)attr);
else
snprintf(pos, size, "|%3s|%2s|%2s|%2s|%3s|%2s|%2s|%2s|%2s]",
snprintf(pos, size, "|%3s|%2s|%2s|%2s|%2s|%2s|%3s|%2s|%2s|%2s|%2s]",
attr & EFI_MEMORY_RUNTIME ? "RUN" : "",
attr & EFI_MEMORY_MORE_RELIABLE ? "MR" : "",
attr & EFI_MEMORY_XP ? "XP" : "",
attr & EFI_MEMORY_RP ? "RP" : "",
attr & EFI_MEMORY_WP ? "WP" : "",
attr & EFI_MEMORY_RO ? "RO" : "",
attr & EFI_MEMORY_UCE ? "UCE" : "",
attr & EFI_MEMORY_WB ? "WB" : "",
attr & EFI_MEMORY_WT ? "WT" : "",
@ -605,3 +629,36 @@ char * __init efi_md_typeattr_format(char *buf, size_t size,
attr & EFI_MEMORY_UC ? "UC" : "");
return buf;
}
/*
* efi_mem_attributes - lookup memmap attributes for physical address
* @phys_addr: the physical address to lookup
*
* Search in the EFI memory map for the region covering
* @phys_addr. Returns the EFI memory attributes if the region
* was found in the memory map, 0 otherwise.
*
* Despite being marked __weak, most architectures should *not*
* override this function. It is __weak solely for the benefit
* of ia64 which has a funky EFI memory map that doesn't work
* the same way as other architectures.
*/
u64 __weak efi_mem_attributes(unsigned long phys_addr)
{
struct efi_memory_map *map;
efi_memory_desc_t *md;
void *p;
if (!efi_enabled(EFI_MEMMAP))
return 0;
map = efi.memmap;
for (p = map->map; p < map->map_end; p += map->desc_size) {
md = p;
if ((md->phys_addr <= phys_addr) &&
(phys_addr < (md->phys_addr +
(md->num_pages << EFI_PAGE_SHIFT))))
return md->attribute;
}
return 0;
}

View File

@ -20,7 +20,6 @@
#include <linux/kobject.h>
#include <linux/list.h>
#include <linux/memblock.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/types.h>
@ -450,22 +449,10 @@ static int __init esrt_sysfs_init(void)
esrt = NULL;
return error;
}
device_initcall(esrt_sysfs_init);
static void __exit esrt_sysfs_exit(void)
{
pr_debug("esrt-sysfs: unloading.\n");
cleanup_entry_list();
kset_unregister(esrt_kset);
sysfs_remove_group(esrt_kobj, &esrt_attr_group);
kfree(esrt);
esrt = NULL;
kobject_del(esrt_kobj);
kobject_put(esrt_kobj);
}
module_init(esrt_sysfs_init);
module_exit(esrt_sysfs_exit);
/*
MODULE_AUTHOR("Peter Jones <pjones@redhat.com>");
MODULE_DESCRIPTION("EFI System Resource Table support");
MODULE_LICENSE("GPL");
*/

View File

@ -0,0 +1,238 @@
/*
* fake_mem.c
*
* Copyright (C) 2015 FUJITSU LIMITED
* Author: Taku Izumi <izumi.taku@jp.fujitsu.com>
*
* This code introduces new boot option named "efi_fake_mem"
* By specifying this parameter, you can add arbitrary attribute to
* specific memory range by updating original (firmware provided) EFI
* memmap.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, see <http://www.gnu.org/licenses/>.
*
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*/
#include <linux/kernel.h>
#include <linux/efi.h>
#include <linux/init.h>
#include <linux/memblock.h>
#include <linux/types.h>
#include <linux/sort.h>
#include <asm/efi.h>
#define EFI_MAX_FAKEMEM CONFIG_EFI_MAX_FAKE_MEM
struct fake_mem {
struct range range;
u64 attribute;
};
static struct fake_mem fake_mems[EFI_MAX_FAKEMEM];
static int nr_fake_mem;
static int __init cmp_fake_mem(const void *x1, const void *x2)
{
const struct fake_mem *m1 = x1;
const struct fake_mem *m2 = x2;
if (m1->range.start < m2->range.start)
return -1;
if (m1->range.start > m2->range.start)
return 1;
return 0;
}
void __init efi_fake_memmap(void)
{
u64 start, end, m_start, m_end, m_attr;
int new_nr_map = memmap.nr_map;
efi_memory_desc_t *md;
phys_addr_t new_memmap_phy;
void *new_memmap;
void *old, *new;
int i;
if (!nr_fake_mem || !efi_enabled(EFI_MEMMAP))
return;
/* count up the number of EFI memory descriptor */
for (old = memmap.map; old < memmap.map_end; old += memmap.desc_size) {
md = old;
start = md->phys_addr;
end = start + (md->num_pages << EFI_PAGE_SHIFT) - 1;
for (i = 0; i < nr_fake_mem; i++) {
/* modifying range */
m_start = fake_mems[i].range.start;
m_end = fake_mems[i].range.end;
if (m_start <= start) {
/* split into 2 parts */
if (start < m_end && m_end < end)
new_nr_map++;
}
if (start < m_start && m_start < end) {
/* split into 3 parts */
if (m_end < end)
new_nr_map += 2;
/* split into 2 parts */
if (end <= m_end)
new_nr_map++;
}
}
}
/* allocate memory for new EFI memmap */
new_memmap_phy = memblock_alloc(memmap.desc_size * new_nr_map,
PAGE_SIZE);
if (!new_memmap_phy)
return;
/* create new EFI memmap */
new_memmap = early_memremap(new_memmap_phy,
memmap.desc_size * new_nr_map);
if (!new_memmap) {
memblock_free(new_memmap_phy, memmap.desc_size * new_nr_map);
return;
}
for (old = memmap.map, new = new_memmap;
old < memmap.map_end;
old += memmap.desc_size, new += memmap.desc_size) {
/* copy original EFI memory descriptor */
memcpy(new, old, memmap.desc_size);
md = new;
start = md->phys_addr;
end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1;
for (i = 0; i < nr_fake_mem; i++) {
/* modifying range */
m_start = fake_mems[i].range.start;
m_end = fake_mems[i].range.end;
m_attr = fake_mems[i].attribute;
if (m_start <= start && end <= m_end)
md->attribute |= m_attr;
if (m_start <= start &&
(start < m_end && m_end < end)) {
/* first part */
md->attribute |= m_attr;
md->num_pages = (m_end - md->phys_addr + 1) >>
EFI_PAGE_SHIFT;
/* latter part */
new += memmap.desc_size;
memcpy(new, old, memmap.desc_size);
md = new;
md->phys_addr = m_end + 1;
md->num_pages = (end - md->phys_addr + 1) >>
EFI_PAGE_SHIFT;
}
if ((start < m_start && m_start < end) && m_end < end) {
/* first part */
md->num_pages = (m_start - md->phys_addr) >>
EFI_PAGE_SHIFT;
/* middle part */
new += memmap.desc_size;
memcpy(new, old, memmap.desc_size);
md = new;
md->attribute |= m_attr;
md->phys_addr = m_start;
md->num_pages = (m_end - m_start + 1) >>
EFI_PAGE_SHIFT;
/* last part */
new += memmap.desc_size;
memcpy(new, old, memmap.desc_size);
md = new;
md->phys_addr = m_end + 1;
md->num_pages = (end - m_end) >>
EFI_PAGE_SHIFT;
}
if ((start < m_start && m_start < end) &&
(end <= m_end)) {
/* first part */
md->num_pages = (m_start - md->phys_addr) >>
EFI_PAGE_SHIFT;
/* latter part */
new += memmap.desc_size;
memcpy(new, old, memmap.desc_size);
md = new;
md->phys_addr = m_start;
md->num_pages = (end - md->phys_addr + 1) >>
EFI_PAGE_SHIFT;
md->attribute |= m_attr;
}
}
}
/* swap into new EFI memmap */
efi_unmap_memmap();
memmap.map = new_memmap;
memmap.phys_map = new_memmap_phy;
memmap.nr_map = new_nr_map;
memmap.map_end = memmap.map + memmap.nr_map * memmap.desc_size;
set_bit(EFI_MEMMAP, &efi.flags);
/* print new EFI memmap */
efi_print_memmap();
}
static int __init setup_fake_mem(char *p)
{
u64 start = 0, mem_size = 0, attribute = 0;
int i;
if (!p)
return -EINVAL;
while (*p != '\0') {
mem_size = memparse(p, &p);
if (*p == '@')
start = memparse(p+1, &p);
else
break;
if (*p == ':')
attribute = simple_strtoull(p+1, &p, 0);
else
break;
if (nr_fake_mem >= EFI_MAX_FAKEMEM)
break;
fake_mems[nr_fake_mem].range.start = start;
fake_mems[nr_fake_mem].range.end = start + mem_size - 1;
fake_mems[nr_fake_mem].attribute = attribute;
nr_fake_mem++;
if (*p == ',')
p++;
}
sort(fake_mems, nr_fake_mem, sizeof(struct fake_mem),
cmp_fake_mem, NULL);
for (i = 0; i < nr_fake_mem; i++)
pr_info("efi_fake_mem: add attr=0x%016llx to [mem 0x%016llx-0x%016llx]",
fake_mems[i].attribute, fake_mems[i].range.start,
fake_mems[i].range.end);
return *p == '\0' ? 0 : -EINVAL;
}
early_param("efi_fake_mem", setup_fake_mem);

View File

@ -114,6 +114,20 @@ static int efifb_setup(char *options)
return 0;
}
static inline bool fb_base_is_valid(void)
{
if (screen_info.lfb_base)
return true;
if (!(screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE))
return false;
if (screen_info.ext_lfb_base)
return true;
return false;
}
static int efifb_probe(struct platform_device *dev)
{
struct fb_info *info;
@ -141,7 +155,7 @@ static int efifb_probe(struct platform_device *dev)
screen_info.lfb_depth = 32;
if (!screen_info.pages)
screen_info.pages = 1;
if (!screen_info.lfb_base) {
if (!fb_base_is_valid()) {
printk(KERN_DEBUG "efifb: invalid framebuffer address\n");
return -ENODEV;
}
@ -160,6 +174,14 @@ static int efifb_probe(struct platform_device *dev)
}
efifb_fix.smem_start = screen_info.lfb_base;
if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE) {
u64 ext_lfb_base;
ext_lfb_base = (u64)(unsigned long)screen_info.ext_lfb_base << 32;
efifb_fix.smem_start |= ext_lfb_base;
}
efifb_defined.bits_per_pixel = screen_info.lfb_depth;
efifb_defined.xres = screen_info.lfb_width;
efifb_defined.yres = screen_info.lfb_height;

View File

@ -99,6 +99,7 @@ typedef struct {
#define EFI_MEMORY_XP ((u64)0x0000000000004000ULL) /* execute-protect */
#define EFI_MEMORY_MORE_RELIABLE \
((u64)0x0000000000010000ULL) /* higher reliability */
#define EFI_MEMORY_RO ((u64)0x0000000000020000ULL) /* read-only */
#define EFI_MEMORY_RUNTIME ((u64)0x8000000000000000ULL) /* range requires runtime mapping */
#define EFI_MEMORY_DESCRIPTOR_VERSION 1
@ -595,6 +596,9 @@ void efi_native_runtime_setup(void);
#define DEVICE_TREE_GUID \
EFI_GUID( 0xb1b621d5, 0xf19c, 0x41a5, 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0 )
#define EFI_PROPERTIES_TABLE_GUID \
EFI_GUID( 0x880aaca3, 0x4adc, 0x4a04, 0x90, 0x79, 0xb7, 0x47, 0x34, 0x08, 0x25, 0xe5 )
typedef struct {
efi_guid_t guid;
u64 table;
@ -676,7 +680,7 @@ typedef struct {
} efi_system_table_t;
struct efi_memory_map {
void *phys_map;
phys_addr_t phys_map;
void *map;
void *map_end;
int nr_map;
@ -808,6 +812,15 @@ typedef struct _efi_file_io_interface {
#define EFI_FILE_MODE_WRITE 0x0000000000000002
#define EFI_FILE_MODE_CREATE 0x8000000000000000
typedef struct {
u32 version;
u32 length;
u64 memory_protection_attribute;
} efi_properties_table_t;
#define EFI_PROPERTIES_TABLE_VERSION 0x00010000
#define EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA 0x1
#define EFI_INVALID_TABLE_ADDR (~0UL)
/*
@ -830,6 +843,7 @@ extern struct efi {
unsigned long runtime; /* runtime table */
unsigned long config_table; /* config tables */
unsigned long esrt; /* ESRT table */
unsigned long properties_table; /* properties table */
efi_get_time_t *get_time;
efi_set_time_t *set_time;
efi_get_wakeup_time_t *get_wakeup_time;
@ -901,13 +915,19 @@ extern void efi_initialize_iomem_resources(struct resource *code_resource,
struct resource *data_resource, struct resource *bss_resource);
extern void efi_get_time(struct timespec *now);
extern void efi_reserve_boot_services(void);
extern int efi_get_fdt_params(struct efi_fdt_params *params, int verbose);
extern int efi_get_fdt_params(struct efi_fdt_params *params);
extern struct efi_memory_map memmap;
extern struct kobject *efi_kobj;
extern int efi_reboot_quirk_mode;
extern bool efi_poweroff_required(void);
#ifdef CONFIG_EFI_FAKE_MEMMAP
extern void __init efi_fake_memmap(void);
#else
static inline void efi_fake_memmap(void) { }
#endif
/* Iterate through an efi_memory_map */
#define for_each_efi_memory_desc(m, md) \
for ((md) = (m)->map; \
@ -959,6 +979,7 @@ extern int __init efi_setup_pcdp_console(char *);
#define EFI_PARAVIRT 6 /* Access is via a paravirt interface */
#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? */
#ifdef CONFIG_EFI
/*

View File

@ -43,7 +43,8 @@ struct screen_info {
__u16 pages; /* 0x32 */
__u16 vesa_attributes; /* 0x34 */
__u32 capabilities; /* 0x36 */
__u8 _reserved[6]; /* 0x3a */
__u32 ext_lfb_base; /* 0x3a */
__u8 _reserved[2]; /* 0x3e */
} __attribute__((packed));
#define VIDEO_TYPE_MDA 0x10 /* Monochrome Text Display */
@ -69,6 +70,6 @@ struct screen_info {
#define VIDEO_FLAGS_NOCURSOR (1 << 0) /* The video mode has no cursor set */
#define VIDEO_CAPABILITY_SKIP_QUIRKS (1 << 0)
#define VIDEO_CAPABILITY_64BIT_BASE (1 << 1) /* Frame buffer base is 64-bit */
#endif /* _UAPI_SCREEN_INFO_H */