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
This commit is contained in:
commit
a114a18c7d
|
@ -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,
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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;
|
||||||
¤t_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,
|
||||||
|
|
||||||
/* 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,
|
||||||
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
|
return EFI_SUCCESS;
|
||||||
__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 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,
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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;
|
||||||
¤t_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,
|
||||||
|
|
||||||
/* 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,
|
||||||
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)
|
||||||
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 {
|
||||||
__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 {
|
||||||
__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 {
|
||||||
__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;
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue