Commit a114a18c authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
Loading
Loading
Loading
Loading
+40 −0
Original line number Diff line number Diff line
@@ -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);
+26 −2
Original line number Diff line number Diff line
@@ -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)
+19 −61
Original line number Diff line number Diff 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
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,
				       &current_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,
				       &current_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;
}

/*
+3 −0
Original line number Diff line number Diff line
@@ -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);
+5 −5
Original line number Diff line number Diff line
@@ -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;