Commit 69019d77 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull x86 EFI changes from Ingo Molnar:
 "Main changes:

   - Add support for earlyprintk=efi which uses the EFI framebuffer.
     Very useful for debugging boot problems.

   - EFI stub support for large memory maps (more than 128 entries)

   - EFI ARM support - this was mostly done by generalizing x86 <-> ARM
     platform differences, such as by moving x86 EFI code into
     drivers/firmware/efi/ and sharing it with ARM.

   - Documentation updates

   - misc fixes"

* 'x86-efi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (26 commits)
  x86/efi: Add EFI framebuffer earlyprintk support
  boot, efi: Remove redundant memset()
  x86/efi: Fix config_table_type array termination
  x86 efi: bugfix interrupt disabling sequence
  x86: EFI stub support for large memory maps
  efi: resolve warnings found on ARM compile
  efi: Fix types in EFI calls to match EFI function definitions.
  efi: Renames in handle_cmdline_files() to complete generalization.
  efi: Generalize handle_ramdisks() and rename to handle_cmdline_files().
  efi: Allow efi_free() to be called with size of 0
  efi: use efi_get_memory_map() to get final map for x86
  efi: generalize efi_get_memory_map()
  efi: Rename __get_map() to efi_get_memory_map()
  efi: Move unicode to ASCII conversion to shared function.
  efi: Generalize relocate_kernel() for use by other architectures.
  efi: Move relocate_kernel() to shared file.
  efi: Enforce minimum alignment of 1 page on allocations.
  efi: Rename memory allocation/free functions
  efi: Add system table pointer argument to shared functions.
  efi: Move common EFI stub code from x86 arch code to common location
  ...
parents 6df1e7f2 88392e9d
...@@ -847,6 +847,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted. ...@@ -847,6 +847,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
earlyprintk= [X86,SH,BLACKFIN,ARM] earlyprintk= [X86,SH,BLACKFIN,ARM]
earlyprintk=vga earlyprintk=vga
earlyprintk=efi
earlyprintk=xen earlyprintk=xen
earlyprintk=serial[,ttySn[,baudrate]] earlyprintk=serial[,ttySn[,baudrate]]
earlyprintk=serial[,0x...[,baudrate]] earlyprintk=serial[,0x...[,baudrate]]
...@@ -860,7 +861,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted. ...@@ -860,7 +861,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
Append ",keep" to not disable it when the real console Append ",keep" to not disable it when the real console
takes over. takes over.
Only vga or serial or usb debug port at a time. Only one of vga, efi, serial, or usb debug port can
be used at a time.
Currently only ttyS0 and ttyS1 may be specified by Currently only ttyS0 and ttyS1 may be specified by
name. Other I/O ports may be explicitly specified name. Other I/O ports may be explicitly specified
...@@ -874,8 +876,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted. ...@@ -874,8 +876,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
Interaction with the standard serial driver is not Interaction with the standard serial driver is not
very good. very good.
The VGA output is eventually overwritten by the real The VGA and EFI output is eventually overwritten by
console. the real console.
The xen output can only be used by Xen PV guests. The xen output can only be used by Xen PV guests.
......
...@@ -424,6 +424,7 @@ extern void __iomem * ioremap(unsigned long offset, unsigned long size); ...@@ -424,6 +424,7 @@ extern void __iomem * ioremap(unsigned long offset, unsigned long size);
extern void __iomem * ioremap_nocache (unsigned long offset, unsigned long size); extern void __iomem * ioremap_nocache (unsigned long offset, unsigned long size);
extern void iounmap (volatile void __iomem *addr); extern void iounmap (volatile void __iomem *addr);
extern void __iomem * early_ioremap (unsigned long phys_addr, unsigned long size); extern void __iomem * early_ioremap (unsigned long phys_addr, unsigned long size);
#define early_memremap(phys_addr, size) early_ioremap(phys_addr, size)
extern void early_iounmap (volatile void __iomem *addr, unsigned long size); extern void early_iounmap (volatile void __iomem *addr, unsigned long size);
static inline void __iomem * ioremap_cache (unsigned long phys_addr, unsigned long size) static inline void __iomem * ioremap_cache (unsigned long phys_addr, unsigned long size)
{ {
......
...@@ -44,10 +44,15 @@ ...@@ -44,10 +44,15 @@
#define EFI_DEBUG 0 #define EFI_DEBUG 0
static __initdata unsigned long palo_phys;
static __initdata efi_config_table_type_t arch_tables[] = {
{PROCESSOR_ABSTRACTION_LAYER_OVERWRITE_GUID, "PALO", &palo_phys},
{NULL_GUID, NULL, 0},
};
extern efi_status_t efi_call_phys (void *, ...); extern efi_status_t efi_call_phys (void *, ...);
struct efi efi;
EXPORT_SYMBOL(efi);
static efi_runtime_services_t *runtime; static efi_runtime_services_t *runtime;
static u64 mem_limit = ~0UL, max_addr = ~0UL, min_addr = 0UL; static u64 mem_limit = ~0UL, max_addr = ~0UL, min_addr = 0UL;
...@@ -423,9 +428,9 @@ static u8 __init palo_checksum(u8 *buffer, u32 length) ...@@ -423,9 +428,9 @@ static u8 __init palo_checksum(u8 *buffer, u32 length)
* Parse and handle PALO table which is published at: * Parse and handle PALO table which is published at:
* http://www.dig64.org/home/DIG64_PALO_R1_0.pdf * http://www.dig64.org/home/DIG64_PALO_R1_0.pdf
*/ */
static void __init handle_palo(unsigned long palo_phys) static void __init handle_palo(unsigned long phys_addr)
{ {
struct palo_table *palo = __va(palo_phys); struct palo_table *palo = __va(phys_addr);
u8 checksum; u8 checksum;
if (strncmp(palo->signature, PALO_SIG, sizeof(PALO_SIG) - 1)) { if (strncmp(palo->signature, PALO_SIG, sizeof(PALO_SIG) - 1)) {
...@@ -467,12 +472,10 @@ void __init ...@@ -467,12 +472,10 @@ void __init
efi_init (void) efi_init (void)
{ {
void *efi_map_start, *efi_map_end; void *efi_map_start, *efi_map_end;
efi_config_table_t *config_tables;
efi_char16_t *c16; efi_char16_t *c16;
u64 efi_desc_size; u64 efi_desc_size;
char *cp, vendor[100] = "unknown"; char *cp, vendor[100] = "unknown";
int i; int i;
unsigned long palo_phys;
/* /*
* It's too early to be able to use the standard kernel command line * It's too early to be able to use the standard kernel command line
...@@ -514,8 +517,6 @@ efi_init (void) ...@@ -514,8 +517,6 @@ efi_init (void)
efi.systab->hdr.revision >> 16, efi.systab->hdr.revision >> 16,
efi.systab->hdr.revision & 0xffff); efi.systab->hdr.revision & 0xffff);
config_tables = __va(efi.systab->tables);
/* Show what we know for posterity */ /* Show what we know for posterity */
c16 = __va(efi.systab->fw_vendor); c16 = __va(efi.systab->fw_vendor);
if (c16) { if (c16) {
...@@ -528,43 +529,10 @@ efi_init (void) ...@@ -528,43 +529,10 @@ efi_init (void)
efi.systab->hdr.revision >> 16, efi.systab->hdr.revision >> 16,
efi.systab->hdr.revision & 0xffff, vendor); efi.systab->hdr.revision & 0xffff, vendor);
efi.mps = EFI_INVALID_TABLE_ADDR;
efi.acpi = EFI_INVALID_TABLE_ADDR;
efi.acpi20 = EFI_INVALID_TABLE_ADDR;
efi.smbios = EFI_INVALID_TABLE_ADDR;
efi.sal_systab = EFI_INVALID_TABLE_ADDR;
efi.boot_info = EFI_INVALID_TABLE_ADDR;
efi.hcdp = EFI_INVALID_TABLE_ADDR;
efi.uga = EFI_INVALID_TABLE_ADDR;
palo_phys = EFI_INVALID_TABLE_ADDR; palo_phys = EFI_INVALID_TABLE_ADDR;
for (i = 0; i < (int) efi.systab->nr_tables; i++) { if (efi_config_init(arch_tables) != 0)
if (efi_guidcmp(config_tables[i].guid, MPS_TABLE_GUID) == 0) { return;
efi.mps = config_tables[i].table;
printk(" MPS=0x%lx", config_tables[i].table);
} else if (efi_guidcmp(config_tables[i].guid, ACPI_20_TABLE_GUID) == 0) {
efi.acpi20 = config_tables[i].table;
printk(" ACPI 2.0=0x%lx", config_tables[i].table);
} else if (efi_guidcmp(config_tables[i].guid, ACPI_TABLE_GUID) == 0) {
efi.acpi = config_tables[i].table;
printk(" ACPI=0x%lx", config_tables[i].table);
} else if (efi_guidcmp(config_tables[i].guid, SMBIOS_TABLE_GUID) == 0) {
efi.smbios = config_tables[i].table;
printk(" SMBIOS=0x%lx", config_tables[i].table);
} else if (efi_guidcmp(config_tables[i].guid, SAL_SYSTEM_TABLE_GUID) == 0) {
efi.sal_systab = config_tables[i].table;
printk(" SALsystab=0x%lx", config_tables[i].table);
} else if (efi_guidcmp(config_tables[i].guid, HCDP_TABLE_GUID) == 0) {
efi.hcdp = config_tables[i].table;
printk(" HCDP=0x%lx", config_tables[i].table);
} else if (efi_guidcmp(config_tables[i].guid,
PROCESSOR_ABSTRACTION_LAYER_OVERWRITE_GUID) == 0) {
palo_phys = config_tables[i].table;
printk(" PALO=0x%lx", config_tables[i].table);
}
}
printk("\n");
if (palo_phys != EFI_INVALID_TABLE_ADDR) if (palo_phys != EFI_INVALID_TABLE_ADDR)
handle_palo(palo_phys); handle_palo(palo_phys);
......
...@@ -1597,7 +1597,7 @@ config EFI_STUB ...@@ -1597,7 +1597,7 @@ config EFI_STUB
This kernel feature allows a bzImage to be loaded directly This kernel feature allows a bzImage to be loaded directly
by EFI firmware without the use of a bootloader. by EFI firmware without the use of a bootloader.
See Documentation/x86/efi-stub.txt for more information. See Documentation/efi-stub.txt for more information.
config SECCOMP config SECCOMP
def_bool y def_bool y
......
...@@ -59,6 +59,16 @@ config EARLY_PRINTK_DBGP ...@@ -59,6 +59,16 @@ config EARLY_PRINTK_DBGP
with klogd/syslogd or the X server. You should normally N here, with klogd/syslogd or the X server. You should normally N here,
unless you want to debug such a crash. You need usb debug device. unless you want to debug such a crash. You need usb debug device.
config EARLY_PRINTK_EFI
bool "Early printk via the EFI framebuffer"
depends on EFI && EARLY_PRINTK
select FONT_SUPPORT
---help---
Write kernel log output directly into the EFI framebuffer.
This is useful for kernel debugging when your machine crashes very
early before the console code is initialized.
config X86_PTDUMP config X86_PTDUMP
bool "Export kernel pagetable layout to userspace via debugfs" bool "Export kernel pagetable layout to userspace via debugfs"
depends on DEBUG_KERNEL depends on DEBUG_KERNEL
......
This diff is collapsed.
...@@ -11,9 +11,6 @@ ...@@ -11,9 +11,6 @@
#define DESC_TYPE_CODE_DATA (1 << 0) #define DESC_TYPE_CODE_DATA (1 << 0)
#define EFI_PAGE_SIZE (1UL << EFI_PAGE_SHIFT)
#define EFI_READ_CHUNK_SIZE (1024 * 1024)
#define EFI_CONSOLE_OUT_DEVICE_GUID \ #define EFI_CONSOLE_OUT_DEVICE_GUID \
EFI_GUID(0xd3b36f2c, 0xd551, 0x11d4, 0x9a, 0x46, 0x0, 0x90, 0x27, \ EFI_GUID(0xd3b36f2c, 0xd551, 0x11d4, 0x9a, 0x46, 0x0, 0x90, 0x27, \
0x3f, 0xc1, 0x4d) 0x3f, 0xc1, 0x4d)
...@@ -62,10 +59,4 @@ struct efi_uga_draw_protocol { ...@@ -62,10 +59,4 @@ struct efi_uga_draw_protocol {
void *blt; void *blt;
}; };
struct efi_simple_text_output_protocol {
void *reset;
void *output_string;
void *test_string;
};
#endif /* BOOT_COMPRESSED_EBOOT_H */ #endif /* BOOT_COMPRESSED_EBOOT_H */
...@@ -109,6 +109,8 @@ static inline bool efi_is_native(void) ...@@ -109,6 +109,8 @@ static inline bool efi_is_native(void)
return IS_ENABLED(CONFIG_X86_64) == efi_enabled(EFI_64BIT); return IS_ENABLED(CONFIG_X86_64) == efi_enabled(EFI_64BIT);
} }
extern struct console early_efi_console;
#else #else
/* /*
* IF EFI is not configured, have the EFI calls return -ENOSYS. * IF EFI is not configured, have the EFI calls return -ENOSYS.
......
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
#include <asm/mrst.h> #include <asm/mrst.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <linux/usb/ehci_def.h> #include <linux/usb/ehci_def.h>
#include <linux/efi.h>
#include <asm/efi.h>
/* Simple VGA output */ /* Simple VGA output */
#define VGABASE (__ISA_IO_base + 0xb8000) #define VGABASE (__ISA_IO_base + 0xb8000)
...@@ -234,6 +236,11 @@ static int __init setup_early_printk(char *buf) ...@@ -234,6 +236,11 @@ static int __init setup_early_printk(char *buf)
early_console_register(&early_hsu_console, keep); early_console_register(&early_hsu_console, keep);
} }
#endif #endif
#ifdef CONFIG_EARLY_PRINTK_EFI
if (!strncmp(buf, "efi", 3))
early_console_register(&early_efi_console, keep);
#endif
buf++; buf++;
} }
return 0; return 0;
......
obj-$(CONFIG_EFI) += efi.o efi_$(BITS).o efi_stub_$(BITS).o obj-$(CONFIG_EFI) += efi.o efi_$(BITS).o efi_stub_$(BITS).o
obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o
obj-$(CONFIG_EARLY_PRINTK_EFI) += early_printk.o
/*
* Copyright (C) 2013 Intel Corporation; author Matt Fleming
*
* 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/console.h>
#include <linux/efi.h>
#include <linux/font.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <asm/setup.h>
static const struct font_desc *font;
static u32 efi_x, efi_y;
static __init void early_efi_clear_scanline(unsigned int y)
{
unsigned long base, *dst;
u16 len;
base = boot_params.screen_info.lfb_base;
len = boot_params.screen_info.lfb_linelength;
dst = early_ioremap(base + y*len, len);
if (!dst)
return;
memset(dst, 0, len);
early_iounmap(dst, len);
}
static __init void early_efi_scroll_up(void)
{
unsigned long base, *dst, *src;
u16 len;
u32 i, height;
base = boot_params.screen_info.lfb_base;
len = boot_params.screen_info.lfb_linelength;
height = boot_params.screen_info.lfb_height;
for (i = 0; i < height - font->height; i++) {
dst = early_ioremap(base + i*len, len);
if (!dst)
return;
src = early_ioremap(base + (i + font->height) * len, len);
if (!src) {
early_iounmap(dst, len);
return;
}
memmove(dst, src, len);
early_iounmap(src, len);
early_iounmap(dst, len);
}
}
static void early_efi_write_char(u32 *dst, unsigned char c, unsigned int h)
{
const u32 color_black = 0x00000000;
const u32 color_white = 0x00ffffff;
const u8 *src;
u8 s8;
int m;
src = font->data + c * font->height;
s8 = *(src + h);
for (m = 0; m < 8; m++) {
if ((s8 >> (7 - m)) & 1)
*dst = color_white;
else
*dst = color_black;
dst++;
}
}
static __init void
early_efi_write(struct console *con, const char *str, unsigned int num)
{
struct screen_info *si;
unsigned long base;
unsigned int len;
const char *s;
void *dst;
base = boot_params.screen_info.lfb_base;
si = &boot_params.screen_info;
len = si->lfb_linelength;
while (num) {
unsigned int linemax;
unsigned int h, count = 0;
for (s = str; *s && *s != '\n'; s++) {
if (count == num)
break;
count++;
}
linemax = (si->lfb_width - efi_x) / font->width;
if (count > linemax)
count = linemax;
for (h = 0; h < font->height; h++) {
unsigned int n, x;
dst = early_ioremap(base + (efi_y + h) * len, len);
if (!dst)
return;
s = str;
n = count;
x = efi_x;
while (n-- > 0) {
early_efi_write_char(dst + x*4, *s, h);
x += font->width;
s++;
}
early_iounmap(dst, len);
}
num -= count;
efi_x += count * font->width;
str += count;
if (num > 0 && *s == '\n') {
efi_x = 0;
efi_y += font->height;
str++;
num--;
}
if (efi_x >= si->lfb_width) {
efi_x = 0;
efi_y += font->height;
}
if (efi_y + font->height >= si->lfb_height) {
u32 i;
efi_y -= font->height;
early_efi_scroll_up();
for (i = 0; i < font->height; i++)
early_efi_clear_scanline(efi_y + i);
}
}
}
static __init int early_efi_setup(struct console *con, char *options)
{
struct screen_info *si;
u16 xres, yres;
u32 i;
si = &boot_params.screen_info;
xres = si->lfb_width;
yres = si->lfb_height;
/*
* early_efi_write_char() implicitly assumes a framebuffer with
* 32-bits per pixel.
*/
if (si->lfb_depth != 32)
return -ENODEV;
font = get_default_font(xres, yres, -1, -1);
if (!font)
return -ENODEV;
efi_y = rounddown(yres, font->height) - font->height;
for (i = 0; i < (yres - efi_y) / font->height; i++)
early_efi_scroll_up();
return 0;
}
struct console early_efi_console = {
.name = "earlyefi",
.write = early_efi_write,
.setup = early_efi_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
};
...@@ -60,19 +60,6 @@ ...@@ -60,19 +60,6 @@
static efi_char16_t efi_dummy_name[6] = { 'D', 'U', 'M', 'M', 'Y', 0 }; static efi_char16_t efi_dummy_name[6] = { 'D', 'U', 'M', 'M', 'Y', 0 };
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,
.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,
};
EXPORT_SYMBOL(efi);
struct efi_memory_map memmap; struct efi_memory_map memmap;
static struct efi efi_phys __initdata; static struct efi efi_phys __initdata;
...@@ -80,6 +67,13 @@ static efi_system_table_t efi_systab __initdata; ...@@ -80,6 +67,13 @@ static efi_system_table_t efi_systab __initdata;
unsigned long x86_efi_facility; unsigned long x86_efi_facility;
static __initdata efi_config_table_type_t arch_tables[] = {
#ifdef CONFIG_X86_UV
{UV_SYSTEM_TABLE_GUID, "UVsystab", &efi.uv_systab},
#endif
{NULL_GUID, NULL, NULL},
};
/* /*
* Returns 1 if 'facility' is enabled, 0 otherwise. * Returns 1 if 'facility' is enabled, 0 otherwise.
*/ */
...@@ -399,6 +393,8 @@ int __init efi_memblock_x86_reserve_range(void) ...@@ -399,6 +393,8 @@ int __init efi_memblock_x86_reserve_range(void)
memblock_reserve(pmap, memmap.nr_map * memmap.desc_size); memblock_reserve(pmap, memmap.nr_map * memmap.desc_size);
efi.memmap = &memmap;
return 0; return 0;
} }
...@@ -578,80 +574,6 @@ static int __init efi_systab_init(void *phys) ...@@ -578,80 +574,6 @@ static int __init efi_systab_init(void *phys)
return 0; return 0;
} }
static int __init efi_config_init(u64 tables, int nr_tables)
{
void *config_tables, *tablep;
int i, sz;
if (efi_enabled(EFI_64BIT))
sz = sizeof(efi_config_table_64_t);
else
sz = sizeof(efi_config_table_32_t);
/*
* Let's see what config tables the firmware passed to us.
*/
config_tables = early_ioremap(tables, nr_tables * sz);
if (config_tables == NULL) {
pr_err("Could not map Configuration table!\n");
return -ENOMEM;
}
tablep = config_tables;
pr_info("");
for (i = 0; i < efi.systab->nr_tables; i++) {
efi_guid_t guid;
unsigned long table;
if (efi_enabled(EFI_64BIT)) {
u64 table64;
guid = ((efi_config_table_64_t *)tablep)->guid;
table64 = ((efi_config_table_64_t *)tablep)->table;
table = table64;
#ifdef CONFIG_X86_32
if (table64 >> 32) {
pr_cont("\n");
pr_err("Table located above 4GB, disabling EFI.\n");
early_iounmap(config_tables,
efi.systab->nr_tables * sz);
return -EINVAL;
}
#endif
} else {
guid = ((efi_config_table_32_t *)tablep)->guid;
table = ((efi_config_table_32_t *)tablep)->table;
}
if (!efi_guidcmp(guid, MPS_TABLE_GUID)) {
efi.mps = table;
pr_cont(" MPS=0x%lx ", table);
} else if (!efi_guidcmp(guid, ACPI_20_TABLE_GUID)) {
efi.acpi20 = table;
pr_cont(" ACPI 2.0=0x%lx ", table);
} else if (!efi_guidcmp(guid, ACPI_TABLE_GUID)) {
efi.acpi = table;
pr_cont(" ACPI=0x%lx ", table);
} else if (!efi_guidcmp(guid, SMBIOS_TABLE_GUID)) {
efi.smbios = table;
pr_cont(" SMBIOS=0x%lx ", table);
#ifdef CONFIG_X86_UV
} else if (!efi_guidcmp(guid, UV_SYSTEM_TABLE_GUID)) {
efi.uv_systab = table;
pr_cont(" UVsystab=0x%lx ", table);
#endif
} else if (!efi_guidcmp(guid, HCDP_TABLE_GUID)) {
efi.hcdp = table;
pr_cont(" HCDP=0x%lx ", table);
} else if (!efi_guidcmp(guid, UGA_IO_PROTOCOL_GUID)) {
efi.uga = table;
pr_cont(" UGA=0x%lx ", table);
}
tablep += sz;
}
pr_cont("\n");
early_iounmap(config_tables, efi.systab->nr_tables * sz);
return 0;
}
static int __init efi_runtime_init(void) static int __init efi_runtime_init(void)
{ {
efi_runtime_services_t *runtime; efi_runtime_services_t *runtime;
...@@ -745,7 +667,7 @@ void __init efi_init(void) ...@@ -745,7 +667,7 @@ void __init efi_init(void)
efi.systab->hdr.revision >> 16, efi.systab->hdr.revision >> 16,
efi.systab->hdr.revision & 0xffff, vendor); efi.systab->hdr.revision & 0xffff, vendor);
if (efi_config_init(efi.systab->tables, efi.systab->nr_tables)) if (efi_config_init(arch_tables))
return; return;
set_bit(EFI_CONFIG_TABLES, &x86_efi_facility); set_bit(EFI_CONFIG_TABLES, &x86_efi_facility);
...@@ -816,34 +738,6 @@ static void __init runtime_code_page_mkexec(void) ...@@ -816,34 +738,6 @@ static void __init runtime_code_page_mkexec(void)
} }
} }
/*
* We can't ioremap data in EFI boot services RAM, because we've already mapped
* it as RAM. So, look it up in the existing EFI memory map instead. Only
* callable after efi_enter_virtual_mode and before efi_free_boot_services.
*/
void __iomem *efi_lookup_mapped_addr(u64 phys_addr)
{
void *p;
if (WARN_ON(!memmap.map))
return NULL;
for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
efi_memory_desc_t *md = p;
u64 size = md->num_pages << EFI_PAGE_SHIFT;
u64 end = md->phys_addr + size;
if (!(md->attribute & EFI_MEMORY_RUNTIME) &&
md->type != EFI_BOOT_SERVICES_CODE &&
md->type != EFI_BOOT_SERVICES_DATA)
continue;
if (!md->virt_addr)
continue;
if (phys_addr >= md->phys_addr && phys_addr < end) {
phys_addr += md->virt_addr - md->phys_addr;
return (__force void __iomem *)(unsigned long)phys_addr;
}
}
return NULL;
}
void efi_memory_uc(u64 addr, unsigned long size) void efi_memory_uc(u64 addr, unsigned long size)
{ {
unsigned long page_shift = 1UL << EFI_PAGE_SHIFT; unsigned long page_shift = 1UL << EFI_PAGE_SHIFT;
......
This diff is collapsed.
...@@ -13,11 +13,27 @@ ...@@ -13,11 +13,27 @@
* This file is released under the GPLv2. * This file is released under the GPLv2.
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kobject.h> #include <linux/kobject.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/efi.h> #include <linux/efi.h>
#include <linux/io.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,
.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,
};
EXPORT_SYMBOL(efi);
static struct kobject *efi_kobj; static struct kobject *efi_kobj;
static struct kobject *efivars_kobj; static struct kobject *efivars_kobj;
...@@ -132,3 +148,127 @@ static int __init efisubsys_init(void) ...@@ -132,3 +148,127 @@ static int __init efisubsys_init(void)
} }
subsys_initcall(efisubsys_init); subsys_initcall(efisubsys_init);
/*
* We can't ioremap data in EFI boot services RAM, because we've already mapped
* it as RAM. So, look it up in the existing EFI memory map instead. Only
* callable after efi_enter_virtual_mode and before efi_free_boot_services.
*/
void __iomem *efi_lookup_mapped_addr(u64 phys_addr)
{
struct efi_memory_map *map;
void *p;
map = efi.memmap;
if (!map)
return NULL;
if (WARN_ON(!map->map))
return NULL;
for (p = map->map; p < map->map_end; p += map->desc_size) {
efi_memory_desc_t *md = p;
u64 size = md->num_pages << EFI_PAGE_SHIFT;
u64 end = md->phys_addr + size;
if (!(md->attribute & EFI_MEMORY_RUNTIME) &&
md->type != EFI_BOOT_SERVICES_CODE &&
md->type != EFI_BOOT_SERVICES_DATA)
continue;
if (!md->virt_addr)
continue;
if (phys_addr >= md->phys_addr && phys_addr < end) {
phys_addr += md->virt_addr - md->phys_addr;
return (__force void __iomem *)(unsigned long)phys_addr;
}
}
return NULL;
}
static __initdata efi_config_table_type_t common_tables[] = {
{ACPI_20_TABLE_GUID, "ACPI 2.0", &efi.acpi20},
{ACPI_TABLE_GUID, "ACPI", &efi.acpi},
{HCDP_TABLE_GUID, "HCDP", &efi.hcdp},
{MPS_TABLE_GUID, "MPS", &efi.mps},
{SAL_SYSTEM_TABLE_GUID, "SALsystab", &efi.sal_systab},
{SMBIOS_TABLE_GUID, "SMBIOS", &efi.smbios},
{UGA_IO_PROTOCOL_GUID, "UGA", &efi.uga},
{NULL_GUID, NULL, 0},
};
static __init int match_config_table(efi_guid_t *guid,
unsigned long table,
efi_config_table_type_t *table_types)
{
u8 str[EFI_VARIABLE_GUID_LEN + 1];
int i;
if (table_types) {
efi_guid_unparse(guid, str);
for (i = 0; efi_guidcmp(table_types[i].guid, NULL_GUID); i++) {
efi_guid_unparse(&table_types[i].guid, str);
if (!efi_guidcmp(*guid, table_types[i].guid)) {
*(table_types[i].ptr) = table;
pr_cont(" %s=0x%lx ",
table_types[i].name, table);
return 1;
}
}
}
return 0;
}
int __init efi_config_init(efi_config_table_type_t *arch_tables)
{
void *config_tables, *tablep;
int i, sz;
if (efi_enabled(EFI_64BIT))
sz = sizeof(efi_config_table_64_t);
else
sz = sizeof(efi_config_table_32_t);
/*
* Let's see what config tables the firmware passed to us.
*/
config_tables = early_memremap(efi.systab->tables,
efi.systab->nr_tables * sz);
if (config_tables == NULL) {
pr_err("Could not map Configuration table!\n");
return -ENOMEM;
}
tablep = config_tables;
pr_info("");
for (i = 0; i < efi.systab->nr_tables; i++) {
efi_guid_t guid;
unsigned long table;
if (efi_enabled(EFI_64BIT)) {
u64 table64;
guid = ((efi_config_table_64_t *)tablep)->guid;
table64 = ((efi_config_table_64_t *)tablep)->table;
table = table64;
#ifndef CONFIG_64BIT
if (table64 >> 32) {
pr_cont("\n");
pr_err("Table located above 4GB, disabling EFI.\n");
early_iounmap(config_tables,
efi.systab->nr_tables * sz);
return -EINVAL;
}
#endif
} else {
guid = ((efi_config_table_32_t *)tablep)->guid;
table = ((efi_config_table_32_t *)tablep)->table;
}
if (!match_config_table(&guid, table, common_tables))
match_config_table(&guid, table, arch_tables);
tablep += sz;
}
pr_cont("\n");
early_iounmap(config_tables, efi.systab->nr_tables * sz);
return 0;
}
...@@ -564,7 +564,7 @@ static int efivar_sysfs_destroy(struct efivar_entry *entry, void *data) ...@@ -564,7 +564,7 @@ static int efivar_sysfs_destroy(struct efivar_entry *entry, void *data)
return 0; return 0;
} }
void efivars_sysfs_exit(void) static void efivars_sysfs_exit(void)
{ {
/* Remove all entries and destroy */ /* Remove all entries and destroy */
__efivar_entry_iter(efivar_sysfs_destroy, &efivar_sysfs_list, NULL, NULL); __efivar_entry_iter(efivar_sysfs_destroy, &efivar_sysfs_list, NULL, NULL);
......
...@@ -39,6 +39,8 @@ ...@@ -39,6 +39,8 @@
typedef unsigned long efi_status_t; typedef unsigned long efi_status_t;
typedef u8 efi_bool_t; typedef u8 efi_bool_t;
typedef u16 efi_char16_t; /* UNICODE character */ typedef u16 efi_char16_t; /* UNICODE character */
typedef u64 efi_physical_addr_t;
typedef void *efi_handle_t;
typedef struct { typedef struct {
...@@ -96,6 +98,7 @@ typedef struct { ...@@ -96,6 +98,7 @@ typedef struct {
#define EFI_MEMORY_DESCRIPTOR_VERSION 1 #define EFI_MEMORY_DESCRIPTOR_VERSION 1
#define EFI_PAGE_SHIFT 12 #define EFI_PAGE_SHIFT 12
#define EFI_PAGE_SIZE (1UL << EFI_PAGE_SHIFT)
typedef struct { typedef struct {
u32 type; u32 type;
...@@ -157,11 +160,13 @@ typedef struct { ...@@ -157,11 +160,13 @@ typedef struct {
efi_table_hdr_t hdr; efi_table_hdr_t hdr;
void *raise_tpl; void *raise_tpl;
void *restore_tpl; void *restore_tpl;
void *allocate_pages; efi_status_t (*allocate_pages)(int, int, unsigned long,
void *free_pages; efi_physical_addr_t *);
void *get_memory_map; efi_status_t (*free_pages)(efi_physical_addr_t, unsigned long);
void *allocate_pool; efi_status_t (*get_memory_map)(unsigned long *, void *, unsigned long *,
void *free_pool; unsigned long *, u32 *);
efi_status_t (*allocate_pool)(int, unsigned long, void **);
efi_status_t (*free_pool)(void *);
void *create_event; void *create_event;
void *set_timer; void *set_timer;
void *wait_for_event; void *wait_for_event;
...@@ -171,7 +176,7 @@ typedef struct { ...@@ -171,7 +176,7 @@ typedef struct {
void *install_protocol_interface; void *install_protocol_interface;
void *reinstall_protocol_interface; void *reinstall_protocol_interface;
void *uninstall_protocol_interface; void *uninstall_protocol_interface;
void *handle_protocol; efi_status_t (*handle_protocol)(efi_handle_t, efi_guid_t *, void **);
void *__reserved; void *__reserved;
void *register_protocol_notify; void *register_protocol_notify;
void *locate_handle; void *locate_handle;
...@@ -181,7 +186,7 @@ typedef struct { ...@@ -181,7 +186,7 @@ typedef struct {
void *start_image; void *start_image;
void *exit; void *exit;
void *unload_image; void *unload_image;
void *exit_boot_services; efi_status_t (*exit_boot_services)(efi_handle_t, unsigned long);
void *get_next_monotonic_count; void *get_next_monotonic_count;
void *stall; void *stall;
void *set_watchdog_timer; void *set_watchdog_timer;
...@@ -404,6 +409,12 @@ typedef struct { ...@@ -404,6 +409,12 @@ typedef struct {
unsigned long table; unsigned long table;
} efi_config_table_t; } efi_config_table_t;
typedef struct {
efi_guid_t guid;
const char *name;
unsigned long *ptr;
} efi_config_table_type_t;
#define EFI_SYSTEM_TABLE_SIGNATURE ((u64)0x5453595320494249ULL) #define EFI_SYSTEM_TABLE_SIGNATURE ((u64)0x5453595320494249ULL)
#define EFI_2_30_SYSTEM_TABLE_REVISION ((2 << 16) | (30)) #define EFI_2_30_SYSTEM_TABLE_REVISION ((2 << 16) | (30))
...@@ -488,10 +499,6 @@ typedef struct { ...@@ -488,10 +499,6 @@ typedef struct {
unsigned long unload; unsigned long unload;
} efi_loaded_image_t; } efi_loaded_image_t;
typedef struct {
u64 revision;
void *open_volume;
} efi_file_io_interface_t;
typedef struct { typedef struct {
u64 size; u64 size;
...@@ -504,20 +511,30 @@ typedef struct { ...@@ -504,20 +511,30 @@ typedef struct {
efi_char16_t filename[1]; efi_char16_t filename[1];
} efi_file_info_t; } efi_file_info_t;
typedef struct { typedef struct _efi_file_handle {
u64 revision; u64 revision;
void *open; efi_status_t (*open)(struct _efi_file_handle *,
void *close; struct _efi_file_handle **,
efi_char16_t *, u64, u64);
efi_status_t (*close)(struct _efi_file_handle *);
void *delete; void *delete;
void *read; efi_status_t (*read)(struct _efi_file_handle *, unsigned long *,
void *);
void *write; void *write;
void *get_position; void *get_position;
void *set_position; void *set_position;
void *get_info; efi_status_t (*get_info)(struct _efi_file_handle *, efi_guid_t *,
unsigned long *, void *);
void *set_info; void *set_info;
void *flush; void *flush;
} efi_file_handle_t; } efi_file_handle_t;
typedef struct _efi_file_io_interface {
u64 revision;
int (*open_volume)(struct _efi_file_io_interface *,
efi_file_handle_t **);
} efi_file_io_interface_t;
#define EFI_FILE_MODE_READ 0x0000000000000001 #define EFI_FILE_MODE_READ 0x0000000000000001
#define EFI_FILE_MODE_WRITE 0x0000000000000002 #define EFI_FILE_MODE_WRITE 0x0000000000000002
#define EFI_FILE_MODE_CREATE 0x8000000000000000 #define EFI_FILE_MODE_CREATE 0x8000000000000000
...@@ -552,6 +569,7 @@ extern struct efi { ...@@ -552,6 +569,7 @@ extern struct efi {
efi_get_next_high_mono_count_t *get_next_high_mono_count; efi_get_next_high_mono_count_t *get_next_high_mono_count;
efi_reset_system_t *reset_system; efi_reset_system_t *reset_system;
efi_set_virtual_address_map_t *set_virtual_address_map; efi_set_virtual_address_map_t *set_virtual_address_map;
struct efi_memory_map *memmap;
} efi; } efi;
static inline int static inline int
...@@ -587,6 +605,7 @@ static inline efi_status_t efi_query_variable_store(u32 attributes, unsigned lon ...@@ -587,6 +605,7 @@ static inline efi_status_t efi_query_variable_store(u32 attributes, unsigned lon
} }
#endif #endif
extern void __iomem *efi_lookup_mapped_addr(u64 phys_addr); extern void __iomem *efi_lookup_mapped_addr(u64 phys_addr);
extern int efi_config_init(efi_config_table_type_t *arch_tables);
extern u64 efi_get_iobase (void); extern u64 efi_get_iobase (void);
extern u32 efi_mem_type (unsigned long phys_addr); extern u32 efi_mem_type (unsigned long phys_addr);
extern u64 efi_mem_attributes (unsigned long phys_addr); extern u64 efi_mem_attributes (unsigned long phys_addr);
...@@ -784,6 +803,13 @@ struct efivar_entry { ...@@ -784,6 +803,13 @@ struct efivar_entry {
struct kobject kobj; struct kobject kobj;
}; };
struct efi_simple_text_output_protocol {
void *reset;
efi_status_t (*output_string)(void *, void *);
void *test_string;
};
extern struct list_head efivar_sysfs_list; extern struct list_head efivar_sysfs_list;
static inline void static inline void
......
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