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>
|
||||
|
||||
static const struct console *earlycon_console __initdata;
|
||||
static const struct font_desc *font;
|
||||
static u32 efi_x, efi_y;
|
||||
static u64 fb_base;
|
||||
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)
|
||||
{
|
||||
if (efi_fb)
|
||||
return efi_fb + start;
|
||||
|
||||
return early_memremap_prot(fb_base + start, len, pgprot_val(fb_prot));
|
||||
}
|
||||
|
||||
static __ref void efi_earlycon_unmap(void *addr, unsigned long len)
|
||||
{
|
||||
if (efi_fb)
|
||||
return;
|
||||
|
||||
early_memunmap(addr, len);
|
||||
}
|
||||
|
||||
|
@ -201,6 +240,7 @@ static int __init efi_earlycon_setup(struct earlycon_device *device,
|
|||
efi_earlycon_scroll_up();
|
||||
|
||||
device->con->write = efi_earlycon_write;
|
||||
earlycon_console = device->con;
|
||||
return 0;
|
||||
}
|
||||
EARLYCON_DECLARE(efifb, efi_earlycon_setup);
|
||||
|
|
|
@ -979,6 +979,24 @@ static int __init efi_memreserve_map_root(void)
|
|||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
memunmap(rsv);
|
||||
return 0;
|
||||
return efi_mem_reserve_iomem(addr, size);
|
||||
}
|
||||
memunmap(rsv);
|
||||
}
|
||||
|
@ -1013,6 +1031,12 @@ int __ref efi_mem_reserve_persistent(phys_addr_t addr, u64 size)
|
|||
if (!rsv)
|
||||
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
|
||||
* 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);
|
||||
spin_unlock(&efi_mem_reserve_persistent_lock);
|
||||
|
||||
return 0;
|
||||
return efi_mem_reserve_iomem(addr, size);
|
||||
}
|
||||
|
||||
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
|
||||
setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si,
|
||||
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;
|
||||
struct efi_pixel_bitmask pixel_info;
|
||||
int pixel_format;
|
||||
efi_status_t status = EFI_NOT_FOUND;
|
||||
efi_status_t status;
|
||||
u32 *handles = (u32 *)(unsigned long)gop_handle;
|
||||
int i;
|
||||
|
||||
|
@ -128,6 +104,7 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si,
|
|||
|
||||
nr_gops = size / sizeof(u32);
|
||||
for (i = 0; i < nr_gops; i++) {
|
||||
struct efi_graphics_output_protocol_mode_32 *mode;
|
||||
struct efi_graphics_output_mode_info *info = NULL;
|
||||
efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID;
|
||||
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)
|
||||
conout_found = true;
|
||||
|
||||
status = __gop_query32(sys_table_arg, gop32, &info, &size,
|
||||
¤t_fb_base);
|
||||
if (status == EFI_SUCCESS && (!first_gop || conout_found) &&
|
||||
mode = (void *)(unsigned long)gop32->mode;
|
||||
info = (void *)(unsigned long)mode->info;
|
||||
current_fb_base = mode->frame_buffer_base;
|
||||
|
||||
if ((!first_gop || conout_found) &&
|
||||
info->pixel_format != PIXEL_BLT_ONLY) {
|
||||
/*
|
||||
* 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? */
|
||||
if (!first_gop)
|
||||
goto out;
|
||||
return EFI_NOT_FOUND;
|
||||
|
||||
/* EFI framebuffer */
|
||||
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->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 status;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
static efi_status_t
|
||||
|
@ -237,7 +192,7 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si,
|
|||
u64 fb_base;
|
||||
struct efi_pixel_bitmask pixel_info;
|
||||
int pixel_format;
|
||||
efi_status_t status = EFI_NOT_FOUND;
|
||||
efi_status_t status;
|
||||
u64 *handles = (u64 *)(unsigned long)gop_handle;
|
||||
int i;
|
||||
|
||||
|
@ -246,6 +201,7 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si,
|
|||
|
||||
nr_gops = size / sizeof(u64);
|
||||
for (i = 0; i < nr_gops; i++) {
|
||||
struct efi_graphics_output_protocol_mode_64 *mode;
|
||||
struct efi_graphics_output_mode_info *info = NULL;
|
||||
efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID;
|
||||
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)
|
||||
conout_found = true;
|
||||
|
||||
status = __gop_query64(sys_table_arg, gop64, &info, &size,
|
||||
¤t_fb_base);
|
||||
if (status == EFI_SUCCESS && (!first_gop || conout_found) &&
|
||||
mode = (void *)(unsigned long)gop64->mode;
|
||||
info = (void *)(unsigned long)mode->info;
|
||||
current_fb_base = mode->frame_buffer_base;
|
||||
|
||||
if ((!first_gop || conout_found) &&
|
||||
info->pixel_format != PIXEL_BLT_ONLY) {
|
||||
/*
|
||||
* 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? */
|
||||
if (!first_gop)
|
||||
goto out;
|
||||
return EFI_NOT_FOUND;
|
||||
|
||||
/* EFI framebuffer */
|
||||
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->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;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
if (rci2_table_phys == EFI_INVALID_TABLE_ADDR)
|
||||
return 0;
|
||||
|
||||
rci2_base = memremap(rci2_table_phys,
|
||||
sizeof(struct rci2_table_global_hdr),
|
||||
MEMREMAP_WB);
|
||||
|
|
|
@ -824,7 +824,7 @@ typedef struct {
|
|||
__aligned_u64 image_size;
|
||||
unsigned int image_code_type;
|
||||
unsigned int image_data_type;
|
||||
unsigned long unload;
|
||||
u32 unload;
|
||||
} efi_loaded_image_32_t;
|
||||
|
||||
typedef struct {
|
||||
|
@ -840,14 +840,14 @@ typedef struct {
|
|||
__aligned_u64 image_size;
|
||||
unsigned int image_code_type;
|
||||
unsigned int image_data_type;
|
||||
unsigned long unload;
|
||||
u64 unload;
|
||||
} efi_loaded_image_64_t;
|
||||
|
||||
typedef struct {
|
||||
u32 revision;
|
||||
void *parent_handle;
|
||||
efi_handle_t parent_handle;
|
||||
efi_system_table_t *system_table;
|
||||
void *device_handle;
|
||||
efi_handle_t device_handle;
|
||||
void *file_path;
|
||||
void *reserved;
|
||||
u32 load_options_size;
|
||||
|
@ -856,7 +856,7 @@ typedef struct {
|
|||
__aligned_u64 image_size;
|
||||
unsigned int image_code_type;
|
||||
unsigned int image_data_type;
|
||||
unsigned long unload;
|
||||
efi_status_t (*unload)(efi_handle_t image_handle);
|
||||
} efi_loaded_image_t;
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue