Commit a114a18c authored by Linus Torvalds's avatar Linus Torvalds

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

Pull EFI fixes from Ingo Molnar:
 "Protect presistent EFI memory reservations from kexec, fix EFIFB early
  console, EFI stub graphics output fixes and other misc fixes."

* 'efi-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  efi: Don't attempt to map RCI2 config table if it doesn't exist
  efi/earlycon: Remap entire framebuffer after page initialization
  efi: Fix efi_loaded_image_t::unload type
  efi/gop: Fix memory leak in __gop_query32/64()
  efi/gop: Return EFI_SUCCESS if a usable GOP was found
  efi/gop: Return EFI_NOT_FOUND if there are no usable GOPs
  efi/memreserve: Register reservations as 'reserved' in /proc/iomem
parents ea200dec a470552e
...@@ -13,18 +13,57 @@ ...@@ -13,18 +13,57 @@
#include <asm/early_ioremap.h> #include <asm/early_ioremap.h>
static const struct console *earlycon_console __initdata;
static const struct font_desc *font; static const struct font_desc *font;
static u32 efi_x, efi_y; static u32 efi_x, efi_y;
static u64 fb_base; static u64 fb_base;
static pgprot_t fb_prot; static pgprot_t fb_prot;
static void *efi_fb;
/*
* EFI earlycon needs to use early_memremap() to map the framebuffer.
* But early_memremap() is not usable for 'earlycon=efifb keep_bootcon',
* memremap() should be used instead. memremap() will be available after
* paging_init() which is earlier than initcall callbacks. Thus adding this
* early initcall function early_efi_map_fb() to map the whole EFI framebuffer.
*/
static int __init efi_earlycon_remap_fb(void)
{
/* bail if there is no bootconsole or it has been disabled already */
if (!earlycon_console || !(earlycon_console->flags & CON_ENABLED))
return 0;
if (pgprot_val(fb_prot) == pgprot_val(PAGE_KERNEL))
efi_fb = memremap(fb_base, screen_info.lfb_size, MEMREMAP_WB);
else
efi_fb = memremap(fb_base, screen_info.lfb_size, MEMREMAP_WC);
return efi_fb ? 0 : -ENOMEM;
}
early_initcall(efi_earlycon_remap_fb);
static int __init efi_earlycon_unmap_fb(void)
{
/* unmap the bootconsole fb unless keep_bootcon has left it enabled */
if (efi_fb && !(earlycon_console->flags & CON_ENABLED))
memunmap(efi_fb);
return 0;
}
late_initcall(efi_earlycon_unmap_fb);
static __ref void *efi_earlycon_map(unsigned long start, unsigned long len) static __ref void *efi_earlycon_map(unsigned long start, unsigned long len)
{ {
if (efi_fb)
return efi_fb + start;
return early_memremap_prot(fb_base + start, len, pgprot_val(fb_prot)); return early_memremap_prot(fb_base + start, len, pgprot_val(fb_prot));
} }
static __ref void efi_earlycon_unmap(void *addr, unsigned long len) static __ref void efi_earlycon_unmap(void *addr, unsigned long len)
{ {
if (efi_fb)
return;
early_memunmap(addr, len); early_memunmap(addr, len);
} }
...@@ -201,6 +240,7 @@ static int __init efi_earlycon_setup(struct earlycon_device *device, ...@@ -201,6 +240,7 @@ static int __init efi_earlycon_setup(struct earlycon_device *device,
efi_earlycon_scroll_up(); efi_earlycon_scroll_up();
device->con->write = efi_earlycon_write; device->con->write = efi_earlycon_write;
earlycon_console = device->con;
return 0; return 0;
} }
EARLYCON_DECLARE(efifb, efi_earlycon_setup); EARLYCON_DECLARE(efifb, efi_earlycon_setup);
...@@ -979,6 +979,24 @@ static int __init efi_memreserve_map_root(void) ...@@ -979,6 +979,24 @@ static int __init efi_memreserve_map_root(void)
return 0; return 0;
} }
static int efi_mem_reserve_iomem(phys_addr_t addr, u64 size)
{
struct resource *res, *parent;
res = kzalloc(sizeof(struct resource), GFP_ATOMIC);
if (!res)
return -ENOMEM;
res->name = "reserved";
res->flags = IORESOURCE_MEM;
res->start = addr;
res->end = addr + size - 1;
/* we expect a conflict with a 'System RAM' region */
parent = request_resource_conflict(&iomem_resource, res);
return parent ? request_resource(parent, res) : 0;
}
int __ref efi_mem_reserve_persistent(phys_addr_t addr, u64 size) int __ref efi_mem_reserve_persistent(phys_addr_t addr, u64 size)
{ {
struct linux_efi_memreserve *rsv; struct linux_efi_memreserve *rsv;
...@@ -1003,7 +1021,7 @@ int __ref efi_mem_reserve_persistent(phys_addr_t addr, u64 size) ...@@ -1003,7 +1021,7 @@ int __ref efi_mem_reserve_persistent(phys_addr_t addr, u64 size)
rsv->entry[index].size = size; rsv->entry[index].size = size;
memunmap(rsv); memunmap(rsv);
return 0; return efi_mem_reserve_iomem(addr, size);
} }
memunmap(rsv); memunmap(rsv);
} }
...@@ -1013,6 +1031,12 @@ int __ref efi_mem_reserve_persistent(phys_addr_t addr, u64 size) ...@@ -1013,6 +1031,12 @@ int __ref efi_mem_reserve_persistent(phys_addr_t addr, u64 size)
if (!rsv) if (!rsv)
return -ENOMEM; return -ENOMEM;
rc = efi_mem_reserve_iomem(__pa(rsv), SZ_4K);
if (rc) {
free_page((unsigned long)rsv);
return rc;
}
/* /*
* The memremap() call above assumes that a linux_efi_memreserve entry * The memremap() call above assumes that a linux_efi_memreserve entry
* never crosses a page boundary, so let's ensure that this remains true * never crosses a page boundary, so let's ensure that this remains true
...@@ -1029,7 +1053,7 @@ int __ref efi_mem_reserve_persistent(phys_addr_t addr, u64 size) ...@@ -1029,7 +1053,7 @@ int __ref efi_mem_reserve_persistent(phys_addr_t addr, u64 size)
efi_memreserve_root->next = __pa(rsv); efi_memreserve_root->next = __pa(rsv);
spin_unlock(&efi_mem_reserve_persistent_lock); spin_unlock(&efi_mem_reserve_persistent_lock);
return 0; return efi_mem_reserve_iomem(addr, size);
} }
static int __init efi_memreserve_root_init(void) static int __init efi_memreserve_root_init(void)
......
...@@ -83,30 +83,6 @@ setup_pixel_info(struct screen_info *si, u32 pixels_per_scan_line, ...@@ -83,30 +83,6 @@ setup_pixel_info(struct screen_info *si, u32 pixels_per_scan_line,
} }
} }
static efi_status_t
__gop_query32(efi_system_table_t *sys_table_arg,
struct efi_graphics_output_protocol_32 *gop32,
struct efi_graphics_output_mode_info **info,
unsigned long *size, u64 *fb_base)
{
struct efi_graphics_output_protocol_mode_32 *mode;
efi_graphics_output_protocol_query_mode query_mode;
efi_status_t status;
unsigned long m;
m = gop32->mode;
mode = (struct efi_graphics_output_protocol_mode_32 *)m;
query_mode = (void *)(unsigned long)gop32->query_mode;
status = __efi_call_early(query_mode, (void *)gop32, mode->mode, size,
info);
if (status != EFI_SUCCESS)
return status;
*fb_base = mode->frame_buffer_base;
return status;
}
static efi_status_t static efi_status_t
setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si, setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si,
efi_guid_t *proto, unsigned long size, void **gop_handle) efi_guid_t *proto, unsigned long size, void **gop_handle)
...@@ -119,7 +95,7 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si, ...@@ -119,7 +95,7 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si,
u64 fb_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_NOT_FOUND; efi_status_t status;
u32 *handles = (u32 *)(unsigned long)gop_handle; u32 *handles = (u32 *)(unsigned long)gop_handle;
int i; int i;
...@@ -128,6 +104,7 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si, ...@@ -128,6 +104,7 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si,
nr_gops = size / sizeof(u32); nr_gops = size / sizeof(u32);
for (i = 0; i < nr_gops; i++) { for (i = 0; i < nr_gops; i++) {
struct efi_graphics_output_protocol_mode_32 *mode;
struct efi_graphics_output_mode_info *info = NULL; struct efi_graphics_output_mode_info *info = NULL;
efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID; efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID;
bool conout_found = false; bool conout_found = false;
...@@ -145,9 +122,11 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si, ...@@ -145,9 +122,11 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si,
if (status == EFI_SUCCESS) if (status == EFI_SUCCESS)
conout_found = true; conout_found = true;
status = __gop_query32(sys_table_arg, gop32, &info, &size, mode = (void *)(unsigned long)gop32->mode;
&current_fb_base); info = (void *)(unsigned long)mode->info;
if (status == EFI_SUCCESS && (!first_gop || conout_found) && current_fb_base = mode->frame_buffer_base;
if ((!first_gop || conout_found) &&
info->pixel_format != PIXEL_BLT_ONLY) { info->pixel_format != PIXEL_BLT_ONLY) {
/* /*
* Systems that use the UEFI Console Splitter may * Systems that use the UEFI Console Splitter may
...@@ -175,7 +154,7 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si, ...@@ -175,7 +154,7 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si,
/* Did we find any GOPs? */ /* Did we find any GOPs? */
if (!first_gop) if (!first_gop)
goto out; return EFI_NOT_FOUND;
/* EFI framebuffer */ /* EFI framebuffer */
si->orig_video_isVGA = VIDEO_TYPE_EFI; si->orig_video_isVGA = VIDEO_TYPE_EFI;
...@@ -197,32 +176,8 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si, ...@@ -197,32 +176,8 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si,
si->lfb_size = si->lfb_linelength * si->lfb_height; si->lfb_size = si->lfb_linelength * si->lfb_height;
si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS; si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS;
out:
return status;
}
static efi_status_t
__gop_query64(efi_system_table_t *sys_table_arg,
struct efi_graphics_output_protocol_64 *gop64,
struct efi_graphics_output_mode_info **info,
unsigned long *size, u64 *fb_base)
{
struct efi_graphics_output_protocol_mode_64 *mode;
efi_graphics_output_protocol_query_mode query_mode;
efi_status_t status;
unsigned long m;
m = gop64->mode;
mode = (struct efi_graphics_output_protocol_mode_64 *)m;
query_mode = (void *)(unsigned long)gop64->query_mode;
status = __efi_call_early(query_mode, (void *)gop64, mode->mode, size,
info);
if (status != EFI_SUCCESS)
return status;
*fb_base = mode->frame_buffer_base; return EFI_SUCCESS;
return status;
} }
static efi_status_t static efi_status_t
...@@ -237,7 +192,7 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si, ...@@ -237,7 +192,7 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si,
u64 fb_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_NOT_FOUND; efi_status_t status;
u64 *handles = (u64 *)(unsigned long)gop_handle; u64 *handles = (u64 *)(unsigned long)gop_handle;
int i; int i;
...@@ -246,6 +201,7 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si, ...@@ -246,6 +201,7 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si,
nr_gops = size / sizeof(u64); nr_gops = size / sizeof(u64);
for (i = 0; i < nr_gops; i++) { for (i = 0; i < nr_gops; i++) {
struct efi_graphics_output_protocol_mode_64 *mode;
struct efi_graphics_output_mode_info *info = NULL; struct efi_graphics_output_mode_info *info = NULL;
efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID; efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID;
bool conout_found = false; bool conout_found = false;
...@@ -263,9 +219,11 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si, ...@@ -263,9 +219,11 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si,
if (status == EFI_SUCCESS) if (status == EFI_SUCCESS)
conout_found = true; conout_found = true;
status = __gop_query64(sys_table_arg, gop64, &info, &size, mode = (void *)(unsigned long)gop64->mode;
&current_fb_base); info = (void *)(unsigned long)mode->info;
if (status == EFI_SUCCESS && (!first_gop || conout_found) && current_fb_base = mode->frame_buffer_base;
if ((!first_gop || conout_found) &&
info->pixel_format != PIXEL_BLT_ONLY) { info->pixel_format != PIXEL_BLT_ONLY) {
/* /*
* Systems that use the UEFI Console Splitter may * Systems that use the UEFI Console Splitter may
...@@ -293,7 +251,7 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si, ...@@ -293,7 +251,7 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si,
/* Did we find any GOPs? */ /* Did we find any GOPs? */
if (!first_gop) if (!first_gop)
goto out; return EFI_NOT_FOUND;
/* EFI framebuffer */ /* EFI framebuffer */
si->orig_video_isVGA = VIDEO_TYPE_EFI; si->orig_video_isVGA = VIDEO_TYPE_EFI;
...@@ -315,8 +273,8 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si, ...@@ -315,8 +273,8 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si,
si->lfb_size = si->lfb_linelength * si->lfb_height; si->lfb_size = si->lfb_linelength * si->lfb_height;
si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS; si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS;
out:
return status; return EFI_SUCCESS;
} }
/* /*
......
...@@ -81,6 +81,9 @@ static int __init efi_rci2_sysfs_init(void) ...@@ -81,6 +81,9 @@ static int __init efi_rci2_sysfs_init(void)
struct kobject *tables_kobj; struct kobject *tables_kobj;
int ret = -ENOMEM; int ret = -ENOMEM;
if (rci2_table_phys == EFI_INVALID_TABLE_ADDR)
return 0;
rci2_base = memremap(rci2_table_phys, rci2_base = memremap(rci2_table_phys,
sizeof(struct rci2_table_global_hdr), sizeof(struct rci2_table_global_hdr),
MEMREMAP_WB); MEMREMAP_WB);
......
...@@ -824,7 +824,7 @@ typedef struct { ...@@ -824,7 +824,7 @@ typedef struct {
__aligned_u64 image_size; __aligned_u64 image_size;
unsigned int image_code_type; unsigned int image_code_type;
unsigned int image_data_type; unsigned int image_data_type;
unsigned long unload; u32 unload;
} efi_loaded_image_32_t; } efi_loaded_image_32_t;
typedef struct { typedef struct {
...@@ -840,14 +840,14 @@ typedef struct { ...@@ -840,14 +840,14 @@ typedef struct {
__aligned_u64 image_size; __aligned_u64 image_size;
unsigned int image_code_type; unsigned int image_code_type;
unsigned int image_data_type; unsigned int image_data_type;
unsigned long unload; u64 unload;
} efi_loaded_image_64_t; } efi_loaded_image_64_t;
typedef struct { typedef struct {
u32 revision; u32 revision;
void *parent_handle; efi_handle_t parent_handle;
efi_system_table_t *system_table; efi_system_table_t *system_table;
void *device_handle; efi_handle_t device_handle;
void *file_path; void *file_path;
void *reserved; void *reserved;
u32 load_options_size; u32 load_options_size;
...@@ -856,7 +856,7 @@ typedef struct { ...@@ -856,7 +856,7 @@ typedef struct {
__aligned_u64 image_size; __aligned_u64 image_size;
unsigned int image_code_type; unsigned int image_code_type;
unsigned int image_data_type; unsigned int image_data_type;
unsigned long unload; efi_status_t (*unload)(efi_handle_t image_handle);
} efi_loaded_image_t; } efi_loaded_image_t;
......
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