Commit f5a8160c authored by Linus Torvalds's avatar Linus Torvalds

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()
  ...
parents 7eeef2ab 78b9bc94
...@@ -60,5 +60,3 @@ linux,uefi-mmap-desc-ver | 32-bit | Version of the mmap descriptor format. ...@@ -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. linux,uefi-stub-kern-ver | string | Copy of linux_banner from build.
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
For verbose debug messages, specify 'uefi_debug' on the kernel command line.
...@@ -1094,6 +1094,21 @@ bytes respectively. Such letter suffixes can also be entirely omitted. ...@@ -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 you are really sure that your UEFI does sane gc and
fulfills the spec otherwise your board may brick. 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] eisa_irq_edge= [PARISC,HW]
See header of drivers/parisc/eisa.c. See header of drivers/parisc/eisa.c.
......
...@@ -92,4 +92,9 @@ static inline const char *acpi_get_enable_method(int cpu) ...@@ -92,4 +92,9 @@ static inline const char *acpi_get_enable_method(int cpu)
{ {
return acpi_psci_present() ? "psci" : NULL; 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*/ #endif /*_ASM_ACPI_H*/
...@@ -94,6 +94,7 @@ ...@@ -94,6 +94,7 @@
#define MT_DEVICE_GRE 2 #define MT_DEVICE_GRE 2
#define MT_NORMAL_NC 3 #define MT_NORMAL_NC 3
#define MT_NORMAL 4 #define MT_NORMAL 4
#define MT_NORMAL_WT 5
/* /*
* Memory types for Stage-2 translation * Memory types for Stage-2 translation
......
...@@ -60,8 +60,10 @@ extern void __pgd_error(const char *file, int line, unsigned long val); ...@@ -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_DEFAULT (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED)
#define PROT_SECT_DEFAULT (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S) #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_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_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_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)) #define PROT_SECT_DEVICE_nGnRE (PROT_SECT_DEFAULT | PMD_SECT_PXN | PMD_SECT_UXN | PMD_ATTRINDX(MT_DEVICE_nGnRE))
......
...@@ -29,6 +29,11 @@ ...@@ -29,6 +29,11 @@
#include <asm/cpu_ops.h> #include <asm/cpu_ops.h>
#include <asm/smp_plat.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_noirq = 1; /* skip ACPI IRQ initialization */
int acpi_disabled = 1; int acpi_disabled = 1;
EXPORT_SYMBOL(acpi_disabled); EXPORT_SYMBOL(acpi_disabled);
...@@ -230,3 +235,27 @@ void __init acpi_gic_init(void) ...@@ -230,3 +235,27 @@ void __init acpi_gic_init(void)
early_acpi_os_unmap_memory((char *)table, tbl_size); 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
...@@ -51,15 +51,6 @@ static struct mm_struct efi_mm = { ...@@ -51,15 +51,6 @@ static struct mm_struct efi_mm = {
INIT_MM_CONTEXT(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) static int __init is_normal_ram(efi_memory_desc_t *md)
{ {
if (md->attribute & EFI_MEMORY_WB) if (md->attribute & EFI_MEMORY_WB)
...@@ -171,14 +162,14 @@ static __init void reserve_regions(void) ...@@ -171,14 +162,14 @@ static __init void reserve_regions(void)
efi_memory_desc_t *md; efi_memory_desc_t *md;
u64 paddr, npages, size; u64 paddr, npages, size;
if (uefi_debug) if (efi_enabled(EFI_DBG))
pr_info("Processing EFI memory map:\n"); pr_info("Processing EFI memory map:\n");
for_each_efi_memory_desc(&memmap, md) { for_each_efi_memory_desc(&memmap, md) {
paddr = md->phys_addr; paddr = md->phys_addr;
npages = md->num_pages; npages = md->num_pages;
if (uefi_debug) { if (efi_enabled(EFI_DBG)) {
char buf[64]; char buf[64];
pr_info(" 0x%012llx-0x%012llx %s", pr_info(" 0x%012llx-0x%012llx %s",
...@@ -194,11 +185,11 @@ static __init void reserve_regions(void) ...@@ -194,11 +185,11 @@ static __init void reserve_regions(void)
if (is_reserve_region(md)) { if (is_reserve_region(md)) {
memblock_reserve(paddr, size); memblock_reserve(paddr, size);
if (uefi_debug) if (efi_enabled(EFI_DBG))
pr_cont("*"); pr_cont("*");
} }
if (uefi_debug) if (efi_enabled(EFI_DBG))
pr_cont("\n"); pr_cont("\n");
} }
...@@ -210,14 +201,14 @@ void __init efi_init(void) ...@@ -210,14 +201,14 @@ void __init efi_init(void)
struct efi_fdt_params params; struct efi_fdt_params params;
/* Grab UEFI information placed in FDT by stub */ /* Grab UEFI information placed in FDT by stub */
if (!efi_get_fdt_params(&params, uefi_debug)) if (!efi_get_fdt_params(&params))
return; return;
efi_system_table = params.system_table; efi_system_table = params.system_table;
memblock_reserve(params.mmap & PAGE_MASK, memblock_reserve(params.mmap & PAGE_MASK,
PAGE_ALIGN(params.mmap_size + (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 = early_memremap(params.mmap, params.mmap_size);
memmap.map_end = memmap.map + params.mmap_size; memmap.map_end = memmap.map + params.mmap_size;
memmap.desc_size = params.desc_size; memmap.desc_size = params.desc_size;
...@@ -291,7 +282,7 @@ static int __init arm64_enable_runtime_services(void) ...@@ -291,7 +282,7 @@ static int __init arm64_enable_runtime_services(void)
pr_info("Remapping and enabling EFI services.\n"); pr_info("Remapping and enabling EFI services.\n");
mapsize = memmap.map_end - memmap.map; 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); mapsize);
if (!memmap.map) { if (!memmap.map) {
pr_err("Failed to remap EFI memory map\n"); pr_err("Failed to remap EFI memory map\n");
......
...@@ -163,12 +163,14 @@ ENTRY(__cpu_setup) ...@@ -163,12 +163,14 @@ ENTRY(__cpu_setup)
* DEVICE_GRE 010 00001100 * DEVICE_GRE 010 00001100
* NORMAL_NC 011 01000100 * NORMAL_NC 011 01000100
* NORMAL 100 11111111 * NORMAL 100 11111111
* NORMAL_WT 101 10111011
*/ */
ldr x5, =MAIR(0x00, MT_DEVICE_nGnRnE) | \ ldr x5, =MAIR(0x00, MT_DEVICE_nGnRnE) | \
MAIR(0x04, MT_DEVICE_nGnRE) | \ MAIR(0x04, MT_DEVICE_nGnRE) | \
MAIR(0x0c, MT_DEVICE_GRE) | \ MAIR(0x0c, MT_DEVICE_GRE) | \
MAIR(0x44, MT_NORMAL_NC) | \ MAIR(0x44, MT_NORMAL_NC) | \
MAIR(0xff, MT_NORMAL) MAIR(0xff, MT_NORMAL) | \
MAIR(0xbb, MT_NORMAL_WT)
msr mair_el1, x5 msr mair_el1, x5
/* /*
* Prepare SCTLR * Prepare SCTLR
......
...@@ -624,7 +624,7 @@ setup_pixel_info(struct screen_info *si, u32 pixels_per_scan_line, ...@@ -624,7 +624,7 @@ setup_pixel_info(struct screen_info *si, u32 pixels_per_scan_line,
static efi_status_t static efi_status_t
__gop_query32(struct efi_graphics_output_protocol_32 *gop32, __gop_query32(struct efi_graphics_output_protocol_32 *gop32,
struct efi_graphics_output_mode_info **info, 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; struct efi_graphics_output_protocol_mode_32 *mode;
efi_status_t status; efi_status_t status;
...@@ -650,7 +650,8 @@ setup_gop32(struct screen_info *si, efi_guid_t *proto, ...@@ -650,7 +650,8 @@ setup_gop32(struct screen_info *si, efi_guid_t *proto,
unsigned long nr_gops; unsigned long nr_gops;
u16 width, height; u16 width, height;
u32 pixels_per_scan_line; u32 pixels_per_scan_line;
u32 fb_base; u32 ext_lfb_base;
u64 fb_base;
struct efi_pixel_bitmask pixel_info; struct efi_pixel_bitmask pixel_info;
int pixel_format; int pixel_format;
efi_status_t status; efi_status_t status;
...@@ -667,7 +668,7 @@ setup_gop32(struct screen_info *si, efi_guid_t *proto, ...@@ -667,7 +668,7 @@ setup_gop32(struct screen_info *si, efi_guid_t *proto,
bool conout_found = false; bool conout_found = false;
void *dummy = NULL; void *dummy = NULL;
u32 h = handles[i]; u32 h = handles[i];
u32 current_fb_base; u64 current_fb_base;
status = efi_call_early(handle_protocol, h, status = efi_call_early(handle_protocol, h,
proto, (void **)&gop32); proto, (void **)&gop32);
...@@ -715,6 +716,13 @@ setup_gop32(struct screen_info *si, efi_guid_t *proto, ...@@ -715,6 +716,13 @@ setup_gop32(struct screen_info *si, efi_guid_t *proto,
si->lfb_width = width; si->lfb_width = width;
si->lfb_height = height; si->lfb_height = height;
si->lfb_base = fb_base; 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; si->pages = 1;
setup_pixel_info(si, pixels_per_scan_line, pixel_info, pixel_format); 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, ...@@ -729,7 +737,7 @@ setup_gop32(struct screen_info *si, efi_guid_t *proto,
static efi_status_t static efi_status_t
__gop_query64(struct efi_graphics_output_protocol_64 *gop64, __gop_query64(struct efi_graphics_output_protocol_64 *gop64,
struct efi_graphics_output_mode_info **info, 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; struct efi_graphics_output_protocol_mode_64 *mode;
efi_status_t status; efi_status_t status;
...@@ -755,7 +763,8 @@ setup_gop64(struct screen_info *si, efi_guid_t *proto, ...@@ -755,7 +763,8 @@ setup_gop64(struct screen_info *si, efi_guid_t *proto,
unsigned long nr_gops; unsigned long nr_gops;
u16 width, height; u16 width, height;
u32 pixels_per_scan_line; u32 pixels_per_scan_line;
u32 fb_base; u32 ext_lfb_base;
u64 fb_base;
struct efi_pixel_bitmask pixel_info; struct efi_pixel_bitmask pixel_info;
int pixel_format; int pixel_format;
efi_status_t status; efi_status_t status;
...@@ -772,7 +781,7 @@ setup_gop64(struct screen_info *si, efi_guid_t *proto, ...@@ -772,7 +781,7 @@ setup_gop64(struct screen_info *si, efi_guid_t *proto,
bool conout_found = false; bool conout_found = false;
void *dummy = NULL; void *dummy = NULL;
u64 h = handles[i]; u64 h = handles[i];
u32 current_fb_base; u64 current_fb_base;
status = efi_call_early(handle_protocol, h, status = efi_call_early(handle_protocol, h,
proto, (void **)&gop64); proto, (void **)&gop64);
...@@ -820,6 +829,13 @@ setup_gop64(struct screen_info *si, efi_guid_t *proto, ...@@ -820,6 +829,13 @@ setup_gop64(struct screen_info *si, efi_guid_t *proto,
si->lfb_width = width; si->lfb_width = width;
si->lfb_height = height; si->lfb_height = height;
si->lfb_base = fb_base; 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; si->pages = 1;
setup_pixel_info(si, pixels_per_scan_line, pixel_info, pixel_format); setup_pixel_info(si, pixels_per_scan_line, pixel_info, pixel_format);
......
...@@ -154,7 +154,7 @@ extra_header_fields: ...@@ -154,7 +154,7 @@ extra_header_fields:
#else #else
.quad 0 # ImageBase .quad 0 # ImageBase
#endif #endif
.long CONFIG_PHYSICAL_ALIGN # SectionAlignment .long 0x20 # SectionAlignment
.long 0x20 # FileAlignment .long 0x20 # FileAlignment
.word 0 # MajorOperatingSystemVersion .word 0 # MajorOperatingSystemVersion
.word 0 # MinorOperatingSystemVersion .word 0 # MinorOperatingSystemVersion
......
...@@ -32,6 +32,10 @@ ...@@ -32,6 +32,10 @@
#include <asm/mpspec.h> #include <asm/mpspec.h>
#include <asm/realmode.h> #include <asm/realmode.h>
#ifdef CONFIG_ACPI_APEI
# include <asm/pgtable_types.h>
#endif
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
extern int acpi_lapic; extern int acpi_lapic;
extern int acpi_ioapic; extern int acpi_ioapic;
...@@ -147,4 +151,23 @@ extern int x86_acpi_numa_init(void); ...@@ -147,4 +151,23 @@ extern int x86_acpi_numa_init(void);
#define acpi_unlazy_tlb(x) leave_mm(x) #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 */ #endif /* _ASM_X86_ACPI_H */
...@@ -105,6 +105,7 @@ extern void __init efi_set_executable(efi_memory_desc_t *md, bool executable); ...@@ -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 int __init efi_memblock_x86_reserve_range(void);
extern pgd_t * __init efi_call_phys_prolog(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_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_unmap_memmap(void);
extern void __init efi_memory_uc(u64 addr, unsigned long size); extern void __init efi_memory_uc(u64 addr, unsigned long size);
extern void __init efi_map_region(efi_memory_desc_t *md); extern void __init efi_map_region(efi_memory_desc_t *md);
......
...@@ -1079,8 +1079,10 @@ void __init setup_arch(char **cmdline_p) ...@@ -1079,8 +1079,10 @@ void __init setup_arch(char **cmdline_p)
memblock_set_current_limit(ISA_END_ADDRESS); memblock_set_current_limit(ISA_END_ADDRESS);
memblock_x86_fill(); memblock_x86_fill();
if (efi_enabled(EFI_BOOT)) if (efi_enabled(EFI_BOOT)) {
efi_fake_memmap();
efi_find_mirror(); efi_find_mirror();
}
/* /*
* The EFI specification says that boot service code won't be called * The EFI specification says that boot service code won't be called
......
...@@ -647,9 +647,12 @@ __split_large_page(struct cpa_data *cpa, pte_t *kpte, unsigned long address, ...@@ -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) for (i = 0; i < PTRS_PER_PTE; i++, pfn += pfninc)
set_pte(&pbase[i], pfn_pte(pfn, canon_pgprot(ref_prot))); set_pte(&pbase[i], pfn_pte(pfn, canon_pgprot(ref_prot)));
if (pfn_range_is_mapped(PFN_DOWN(__pa(address)), if (virt_addr_valid(address)) {
PFN_DOWN(__pa(address)) + 1)) unsigned long pfn = PFN_DOWN(__pa(address));
split_page_count(level);
if (pfn_range_is_mapped(pfn, pfn + 1))
split_page_count(level);
}
/* /*
* Install the new, split up pagetable. * Install the new, split up pagetable.
......
...@@ -50,11 +50,16 @@ void __init efi_bgrt_init(void) ...@@ -50,11 +50,16 @@ void __init efi_bgrt_init(void)
bgrt_tab->version); bgrt_tab->version);
return; return;
} }
if (bgrt_tab->status != 1) { if (bgrt_tab->status & 0xfe) {
pr_err("Ignoring BGRT: invalid status %u (expected 1)\n", pr_err("Ignoring BGRT: reserved status bits are non-zero %u\n",
bgrt_tab->status); bgrt_tab->status);
return; 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) { if (bgrt_tab->image_type != 0) {
pr_err("Ignoring BGRT: invalid image type %u (expected 0)\n", pr_err("Ignoring BGRT: invalid image type %u (expected 0)\n",
bgrt_tab->image_type); bgrt_tab->image_type);
......
...@@ -194,7 +194,7 @@ static void __init do_add_efi_memmap(void) ...@@ -194,7 +194,7 @@ static void __init do_add_efi_memmap(void)
int __init efi_memblock_x86_reserve_range(void) int __init efi_memblock_x86_reserve_range(void)
{ {
struct efi_info *e = &boot_params.efi_info; struct efi_info *e = &boot_params.efi_info;
unsigned long pmap; phys_addr_t pmap;
if (efi_enabled(EFI_PARAVIRT)) if (efi_enabled(EFI_PARAVIRT))
return 0; return 0;
...@@ -209,7 +209,7 @@ int __init efi_memblock_x86_reserve_range(void) ...@@ -209,7 +209,7 @@ int __init efi_memblock_x86_reserve_range(void)
#else #else
pmap = (e->efi_memmap | ((__u64)e->efi_memmap_hi << 32)); pmap = (e->efi_memmap | ((__u64)e->efi_memmap_hi << 32));
#endif #endif
memmap.phys_map = (void *)pmap; memmap.phys_map = pmap;
memmap.nr_map = e->efi_memmap_size / memmap.nr_map = e->efi_memmap_size /
e->efi_memdesc_size; e->efi_memdesc_size;
memmap.desc_size = e->efi_memdesc_size; memmap.desc_size = e->efi_memdesc_size;
...@@ -222,7 +222,7 @@ int __init efi_memblock_x86_reserve_range(void) ...@@ -222,7 +222,7 @@ int __init efi_memblock_x86_reserve_range(void)
return 0; return 0;
} }
static void __init print_efi_memmap(void) void __init efi_print_memmap(void)
{ {
#ifdef EFI_DEBUG #ifdef EFI_DEBUG
efi_memory_desc_t *md; efi_memory_desc_t *md;
...@@ -524,7 +524,7 @@ void __init efi_init(void) ...@@ -524,7 +524,7 @@ void __init efi_init(void)
return; return;
if (efi_enabled(EFI_DBG)) if (efi_enabled(EFI_DBG))
print_efi_memmap(); efi_print_memmap();
efi_esrt_init(); efi_esrt_init();
} }
...@@ -1017,24 +1017,6 @@ u32 efi_mem_type(unsigned long phys_addr) ...@@ -1017,24 +1017,6 @@ u32 efi_mem_type(unsigned long phys_addr)
return 0; 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) static int __init arch_parse_efi_cmdline(char *str)
{ {
if (!str) { if (!str) {
...@@ -1044,8 +1026,6 @@ static int __init arch_parse_efi_cmdline(char *str) ...@@ -1044,8 +1026,6 @@ static int __init arch_parse_efi_cmdline(char *str)
if (parse_option_str(str, "old_map")) if (parse_option_str(str, "old_map"))
set_bit(EFI_OLD_MEMMAP, &efi.flags); set_bit(EFI_OLD_MEMMAP, &efi.flags);
if (parse_option_str(str, "debug"))
set_bit(EFI_DBG, &efi.flags);
return 0; return 0;
} }
......
...@@ -157,11 +157,15 @@ static void __iomem *ghes_ioremap_pfn_nmi(u64 pfn) ...@@ -157,11 +157,15 @@ static void __iomem *ghes_ioremap_pfn_nmi(u64 pfn)
static void __iomem *ghes_ioremap_pfn_irq(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); 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; return (void __iomem *)vaddr;
} }
......
...@@ -52,6 +52,28 @@ config EFI_RUNTIME_MAP ...@@ -52,6 +52,28 @@ config EFI_RUNTIME_MAP
See also Documentation/ABI/testing/sysfs-firmware-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 config EFI_PARAMS_FROM_FDT
bool bool
help help
......
...@@ -9,3 +9,4 @@ obj-$(CONFIG_UEFI_CPER) += cper.o ...@@ -9,3 +9,4 @@ obj-$(CONFIG_UEFI_CPER) += cper.o
obj-$(CONFIG_EFI_RUNTIME_MAP) += runtime-map.o obj-$(CONFIG_EFI_RUNTIME_MAP) += runtime-map.o
obj-$(CONFIG_EFI_RUNTIME_WRAPPERS) += runtime-wrappers.o obj-$(CONFIG_EFI_RUNTIME_WRAPPERS) += runtime-wrappers.o
obj-$(CONFIG_EFI_STUB) += libstub/ obj-$(CONFIG_EFI_STUB) += libstub/
obj-$(CONFIG_EFI_FAKE_MEMMAP) += fake_mem.o
...@@ -400,3 +400,4 @@ module_exit(efivars_pstore_exit); ...@@ -400,3 +400,4 @@ module_exit(efivars_pstore_exit);
MODULE_DESCRIPTION("EFI variable backend for pstore"); MODULE_DESCRIPTION("EFI variable backend for pstore");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:efivars");
...@@ -26,20 +26,21 @@ ...@@ -26,20 +26,21 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
struct efi __read_mostly efi = { struct efi __read_mostly efi = {
.mps = EFI_INVALID_TABLE_ADDR, .mps = EFI_INVALID_TABLE_ADDR,
.acpi = EFI_INVALID_TABLE_ADDR, .acpi = EFI_INVALID_TABLE_ADDR,
.acpi20 = EFI_INVALID_TABLE_ADDR, .acpi20 = EFI_INVALID_TABLE_ADDR,
.smbios = EFI_INVALID_TABLE_ADDR, .smbios = EFI_INVALID_TABLE_ADDR,
.smbios3 = EFI_INVALID_TABLE_ADDR, .smbios3 = EFI_INVALID_TABLE_ADDR,
.sal_systab = EFI_INVALID_TABLE_ADDR, .sal_systab = EFI_INVALID_TABLE_ADDR,
.boot_info = EFI_INVALID_TABLE_ADDR, .boot_info = EFI_INVALID_TABLE_ADDR,
.hcdp = EFI_INVALID_TABLE_ADDR, .hcdp = EFI_INVALID_TABLE_ADDR,
.uga = EFI_INVALID_TABLE_ADDR, .uga = EFI_INVALID_TABLE_ADDR,
.uv_systab = EFI_INVALID_TABLE_ADDR, .uv_systab = EFI_INVALID_TABLE_ADDR,
.fw_vendor = EFI_INVALID_TABLE_ADDR, .fw_vendor = EFI_INVALID_TABLE_ADDR,
.runtime = EFI_INVALID_TABLE_ADDR, .runtime = EFI_INVALID_TABLE_ADDR,
.config_table = EFI_INVALID_TABLE_ADDR, .config_table = EFI_INVALID_TABLE_ADDR,
.esrt = EFI_INVALID_TABLE_ADDR, .esrt = EFI_INVALID_TABLE_ADDR,
.properties_table = EFI_INVALID_TABLE_ADDR,
}; };
EXPORT_SYMBOL(efi); EXPORT_SYMBOL(efi);
...@@ -63,6 +64,9 @@ static int __init parse_efi_cmdline(char *str) ...@@ -63,6 +64,9 @@ static int __init parse_efi_cmdline(char *str)
return -EINVAL; return -EINVAL;
} }
if (parse_option_str(str, "debug"))
set_bit(EFI_DBG, &efi.flags);
if (parse_option_str(str, "noruntime")) if (parse_option_str(str, "noruntime"))
disable_runtime = true; disable_runtime = true;
...@@ -250,7 +254,7 @@ subsys_initcall(efisubsys_init); ...@@ -250,7 +254,7 @@ subsys_initcall(efisubsys_init);
int __init efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md) int __init efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md)
{ {
struct efi_memory_map *map = efi.memmap; struct efi_memory_map *map = efi.memmap;
void *p, *e; phys_addr_t p, e;
if (!efi_enabled(EFI_MEMMAP)) { if (!efi_enabled(EFI_MEMMAP)) {
pr_err_once("EFI_MEMMAP is not enabled.\n"); 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) ...@@ -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. * 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) { if (!md) {
pr_err_once("early_memremap(%p, %zu) failed.\n", pr_err_once("early_memremap(%pa, %zu) failed.\n",
p, sizeof (*md)); &p, sizeof (*md));
return -ENOMEM; return -ENOMEM;
} }
...@@ -362,6 +366,7 @@ static __initdata efi_config_table_type_t common_tables[] = { ...@@ -362,6 +366,7 @@ static __initdata efi_config_table_type_t common_tables[] = {
{SMBIOS3_TABLE_GUID, "SMBIOS 3.0", &efi.smbios3}, {SMBIOS3_TABLE_GUID, "SMBIOS 3.0", &efi.smbios3},
{UGA_IO_PROTOCOL_GUID, "UGA", &efi.uga}, {UGA_IO_PROTOCOL_GUID, "UGA", &efi.uga},
{EFI_SYSTEM_RESOURCE_TABLE_GUID, "ESRT", &efi.esrt}, {EFI_SYSTEM_RESOURCE_TABLE_GUID, "ESRT", &efi.esrt},
{EFI_PROPERTIES_TABLE_GUID, "PROP", &efi.properties_table},
{NULL_GUID, NULL, NULL}, {NULL_GUID, NULL, NULL},
}; };
...@@ -421,6 +426,24 @@ int __init efi_config_parse_tables(void *config_tables, int count, int sz, ...@@ -421,6 +426,24 @@ int __init efi_config_parse_tables(void *config_tables, int count, int sz,
} }
pr_cont("\n"); pr_cont("\n");
set_bit(EFI_CONFIG_TABLES, &efi.flags); 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; return 0;
} }
...@@ -489,7 +512,6 @@ static __initdata struct { ...@@ -489,7 +512,6 @@ static __initdata struct {
}; };
struct param_info { struct param_info {
int verbose;
int found; int found;
void *params; void *params;
}; };
...@@ -520,21 +542,20 @@ static int __init fdt_find_uefi_params(unsigned long node, const char *uname, ...@@ -520,21 +542,20 @@ static int __init fdt_find_uefi_params(unsigned long node, const char *uname,
else else
*(u64 *)dest = val; *(u64 *)dest = val;
if (info->verbose) if (efi_enabled(EFI_DBG))
pr_info(" %s: 0x%0*llx\n", dt_params[i].name, pr_info(" %s: 0x%0*llx\n", dt_params[i].name,
dt_params[i].size * 2, val); dt_params[i].size * 2, val);
} }
return 1; 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; struct param_info info;
int ret; int ret;
pr_info("Getting EFI parameters from FDT:\n"); pr_info("Getting EFI parameters from FDT:\n");
info.verbose = verbose;
info.found = 0; info.found = 0;
info.params = params; info.params = params;
...@@ -588,16 +609,19 @@ char * __init efi_md_typeattr_format(char *buf, size_t size, ...@@ -588,16 +609,19 @@ char * __init efi_md_typeattr_format(char *buf, size_t size,
attr = md->attribute; attr = md->attribute;
if (attr & ~(EFI_MEMORY_UC | EFI_MEMORY_WC | EFI_MEMORY_WT | if (attr & ~(EFI_MEMORY_UC | EFI_MEMORY_WC | EFI_MEMORY_WT |
EFI_MEMORY_WB | EFI_MEMORY_UCE | EFI_MEMORY_WP | EFI_MEMORY_WB | EFI_MEMORY_UCE | EFI_MEMORY_RO |
EFI_MEMORY_RP | EFI_MEMORY_XP | EFI_MEMORY_RUNTIME)) EFI_MEMORY_WP | EFI_MEMORY_RP | EFI_MEMORY_XP |
EFI_MEMORY_RUNTIME | EFI_MEMORY_MORE_RELIABLE))
snprintf(pos, size, "|attr=0x%016llx]", snprintf(pos, size, "|attr=0x%016llx]",
(unsigned long long)attr); (unsigned long long)attr);
else 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_RUNTIME ? "RUN" : "",
attr & EFI_MEMORY_MORE_RELIABLE ? "MR" : "",
attr & EFI_MEMORY_XP ? "XP" : "", attr & EFI_MEMORY_XP ? "XP" : "",
attr & EFI_MEMORY_RP ? "RP" : "", attr & EFI_MEMORY_RP ? "RP" : "",
attr & EFI_MEMORY_WP ? "WP" : "", attr & EFI_MEMORY_WP ? "WP" : "",
attr & EFI_MEMORY_RO ? "RO" : "",
attr & EFI_MEMORY_UCE ? "UCE" : "", attr & EFI_MEMORY_UCE ? "UCE" : "",
attr & EFI_MEMORY_WB ? "WB" : "", attr & EFI_MEMORY_WB ? "WB" : "",
attr & EFI_MEMORY_WT ? "WT" : "", attr & EFI_MEMORY_WT ? "WT" : "",
...@@ -605,3 +629,36 @@ char * __init efi_md_typeattr_format(char *buf, size_t size, ...@@ -605,3 +629,36 @@ char * __init efi_md_typeattr_format(char *buf, size_t size,
attr & EFI_MEMORY_UC ? "UC" : ""); attr & EFI_MEMORY_UC ? "UC" : "");
return buf; 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;
}
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include <linux/kobject.h> #include <linux/kobject.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/memblock.h> #include <linux/memblock.h>
#include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -450,22 +449,10 @@ static int __init esrt_sysfs_init(void) ...@@ -450,22 +449,10 @@ static int __init esrt_sysfs_init(void)
esrt = NULL; esrt = NULL;
return error; 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_AUTHOR("Peter Jones <pjones@redhat.com>");
MODULE_DESCRIPTION("EFI System Resource Table support"); MODULE_DESCRIPTION("EFI System Resource Table support");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
*/
/*
* 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);
...@@ -114,6 +114,20 @@ static int efifb_setup(char *options) ...@@ -114,6 +114,20 @@ static int efifb_setup(char *options)
return 0; 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) static int efifb_probe(struct platform_device *dev)
{ {
struct fb_info *info; struct fb_info *info;
...@@ -141,7 +155,7 @@ static int efifb_probe(struct platform_device *dev) ...@@ -141,7 +155,7 @@ static int efifb_probe(struct platform_device *dev)
screen_info.lfb_depth = 32; screen_info.lfb_depth = 32;
if (!screen_info.pages) if (!screen_info.pages)
screen_info.pages = 1; screen_info.pages = 1;
if (!screen_info.lfb_base) { if (!fb_base_is_valid()) {
printk(KERN_DEBUG "efifb: invalid framebuffer address\n"); printk(KERN_DEBUG "efifb: invalid framebuffer address\n");
return -ENODEV; return -ENODEV;
} }
...@@ -160,6 +174,14 @@ static int efifb_probe(struct platform_device *dev) ...@@ -160,6 +174,14 @@ static int efifb_probe(struct platform_device *dev)
} }
efifb_fix.smem_start = screen_info.lfb_base; 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.bits_per_pixel = screen_info.lfb_depth;
efifb_defined.xres = screen_info.lfb_width; efifb_defined.xres = screen_info.lfb_width;
efifb_defined.yres = screen_info.lfb_height; efifb_defined.yres = screen_info.lfb_height;
......
...@@ -99,6 +99,7 @@ typedef struct { ...@@ -99,6 +99,7 @@ typedef struct {
#define EFI_MEMORY_XP ((u64)0x0000000000004000ULL) /* execute-protect */ #define EFI_MEMORY_XP ((u64)0x0000000000004000ULL) /* execute-protect */
#define EFI_MEMORY_MORE_RELIABLE \ #define EFI_MEMORY_MORE_RELIABLE \
((u64)0x0000000000010000ULL) /* higher reliability */ ((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_RUNTIME ((u64)0x8000000000000000ULL) /* range requires runtime mapping */
#define EFI_MEMORY_DESCRIPTOR_VERSION 1 #define EFI_MEMORY_DESCRIPTOR_VERSION 1
...@@ -595,6 +596,9 @@ void efi_native_runtime_setup(void); ...@@ -595,6 +596,9 @@ void efi_native_runtime_setup(void);
#define DEVICE_TREE_GUID \ #define DEVICE_TREE_GUID \
EFI_GUID( 0xb1b621d5, 0xf19c, 0x41a5, 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0 ) 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 { typedef struct {
efi_guid_t guid; efi_guid_t guid;
u64 table; u64 table;
...@@ -676,7 +680,7 @@ typedef struct { ...@@ -676,7 +680,7 @@ typedef struct {
} efi_system_table_t; } efi_system_table_t;
struct efi_memory_map { struct efi_memory_map {
void *phys_map; phys_addr_t phys_map;
void *map; void *map;
void *map_end; void *map_end;
int nr_map; int nr_map;
...@@ -808,6 +812,15 @@ typedef struct _efi_file_io_interface { ...@@ -808,6 +812,15 @@ typedef struct _efi_file_io_interface {
#define EFI_FILE_MODE_WRITE 0x0000000000000002 #define EFI_FILE_MODE_WRITE 0x0000000000000002
#define EFI_FILE_MODE_CREATE 0x8000000000000000 #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) #define EFI_INVALID_TABLE_ADDR (~0UL)
/* /*
...@@ -830,6 +843,7 @@ extern struct efi { ...@@ -830,6 +843,7 @@ extern struct efi {
unsigned long runtime; /* runtime table */ unsigned long runtime; /* runtime table */
unsigned long config_table; /* config tables */ unsigned long config_table; /* config tables */
unsigned long esrt; /* ESRT table */ unsigned long esrt; /* ESRT table */
unsigned long properties_table; /* properties table */
efi_get_time_t *get_time; efi_get_time_t *get_time;
efi_set_time_t *set_time; efi_set_time_t *set_time;
efi_get_wakeup_time_t *get_wakeup_time; efi_get_wakeup_time_t *get_wakeup_time;
...@@ -901,13 +915,19 @@ extern void efi_initialize_iomem_resources(struct resource *code_resource, ...@@ -901,13 +915,19 @@ extern void efi_initialize_iomem_resources(struct resource *code_resource,
struct resource *data_resource, struct resource *bss_resource); struct resource *data_resource, struct resource *bss_resource);
extern void efi_get_time(struct timespec *now); extern void efi_get_time(struct timespec *now);
extern void efi_reserve_boot_services(void); 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 efi_memory_map memmap;
extern struct kobject *efi_kobj; extern struct kobject *efi_kobj;
extern int efi_reboot_quirk_mode; extern int efi_reboot_quirk_mode;
extern bool efi_poweroff_required(void); 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 */ /* Iterate through an efi_memory_map */
#define for_each_efi_memory_desc(m, md) \ #define for_each_efi_memory_desc(m, md) \
for ((md) = (m)->map; \ for ((md) = (m)->map; \
...@@ -959,6 +979,7 @@ extern int __init efi_setup_pcdp_console(char *); ...@@ -959,6 +979,7 @@ extern int __init efi_setup_pcdp_console(char *);
#define EFI_PARAVIRT 6 /* Access is via a paravirt interface */ #define EFI_PARAVIRT 6 /* Access is via a paravirt interface */
#define EFI_ARCH_1 7 /* First arch-specific bit */ #define EFI_ARCH_1 7 /* First arch-specific bit */
#define EFI_DBG 8 /* Print additional debug info at runtime */ #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 #ifdef CONFIG_EFI
/* /*
......
...@@ -43,7 +43,8 @@ struct screen_info { ...@@ -43,7 +43,8 @@ struct screen_info {
__u16 pages; /* 0x32 */ __u16 pages; /* 0x32 */
__u16 vesa_attributes; /* 0x34 */ __u16 vesa_attributes; /* 0x34 */
__u32 capabilities; /* 0x36 */ __u32 capabilities; /* 0x36 */
__u8 _reserved[6]; /* 0x3a */ __u32 ext_lfb_base; /* 0x3a */
__u8 _reserved[2]; /* 0x3e */
} __attribute__((packed)); } __attribute__((packed));
#define VIDEO_TYPE_MDA 0x10 /* Monochrome Text Display */ #define VIDEO_TYPE_MDA 0x10 /* Monochrome Text Display */
...@@ -69,6 +70,6 @@ struct screen_info { ...@@ -69,6 +70,6 @@ struct screen_info {
#define VIDEO_FLAGS_NOCURSOR (1 << 0) /* The video mode has no cursor set */ #define VIDEO_FLAGS_NOCURSOR (1 << 0) /* The video mode has no cursor set */
#define VIDEO_CAPABILITY_SKIP_QUIRKS (1 << 0) #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 */ #endif /* _UAPI_SCREEN_INFO_H */
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