Skip to content

Commit

Permalink
Merge branch 'x86-efi-for-linus' of git://git.kernel.org/pub/scm/linu…
Browse files Browse the repository at this point in the history
…x/kernel/git/tip/tip

Pull x86/EFI changes from Ingo Molnar:
 "EFI loader robustness enhancements plus smaller fixes"

* 'x86-efi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  efi: Fix the ACPI BGRT driver for images located in EFI boot services memory
  efi: Add a function to look up existing IO memory mappings
  efi: Defer freeing boot services memory until after ACPI init
  x86, EFI: Calculate the EFI framebuffer size instead of trusting the firmware
  efifb: Skip DMI checks if the bootloader knows what it's doing
  efi: initialize efi.runtime_version to make query_variable_info/update_capsule workable
  efi: Build EFI stub with EFI-appropriate options
  X86: Improve GOP detection in the EFI boot stub
  • Loading branch information
torvalds committed Oct 1, 2012
2 parents 58ae9c0 + 2223af3 commit 3b29b03
Show file tree
Hide file tree
Showing 13 changed files with 207 additions and 97 deletions.
3 changes: 3 additions & 0 deletions arch/x86/boot/compressed/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ VMLINUX_OBJS = $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o \
$(obj)/string.o $(obj)/cmdline.o $(obj)/early_serial_console.o \
$(obj)/piggy.o

$(obj)/eboot.o: KBUILD_CFLAGS += -fshort-wchar -mno-red-zone
$(obj)/efi_stub_$(BITS).o: KBUILD_CLFAGS += -fshort-wchar -mno-red-zone

ifeq ($(CONFIG_EFI_STUB), y)
VMLINUX_OBJS += $(obj)/eboot.o $(obj)/efi_stub_$(BITS).o
endif
Expand Down
34 changes: 20 additions & 14 deletions arch/x86/boot/compressed/eboot.c
Original file line number Diff line number Diff line change
Expand Up @@ -276,28 +276,31 @@ static efi_status_t setup_gop(struct screen_info *si, efi_guid_t *proto,
nr_gops = size / sizeof(void *);
for (i = 0; i < nr_gops; i++) {
struct efi_graphics_output_mode_info *info;
efi_guid_t pciio_proto = EFI_PCI_IO_PROTOCOL_GUID;
void *pciio;
efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID;
bool conout_found = false;
void *dummy;
void *h = gop_handle[i];

status = efi_call_phys3(sys_table->boottime->handle_protocol,
h, proto, &gop);
if (status != EFI_SUCCESS)
continue;

efi_call_phys3(sys_table->boottime->handle_protocol,
h, &pciio_proto, &pciio);
status = efi_call_phys3(sys_table->boottime->handle_protocol,
h, &conout_proto, &dummy);

if (status == EFI_SUCCESS)
conout_found = true;

status = efi_call_phys4(gop->query_mode, gop,
gop->mode->mode, &size, &info);
if (status == EFI_SUCCESS && (!first_gop || pciio)) {
if (status == EFI_SUCCESS && (!first_gop || conout_found)) {
/*
* Apple provide GOPs that are not backed by
* real hardware (they're used to handle
* multiple displays). The workaround is to
* search for a GOP implementing the PCIIO
* protocol, and if one isn't found, to just
* fallback to the first GOP.
* Systems that use the UEFI Console Splitter may
* provide multiple GOP devices, not all of which are
* backed by real hardware. The workaround is to search
* for a GOP implementing the ConOut protocol, and if
* one isn't found, to just fall back to the first GOP.
*/
width = info->horizontal_resolution;
height = info->vertical_resolution;
Expand All @@ -308,10 +311,10 @@ static efi_status_t setup_gop(struct screen_info *si, efi_guid_t *proto,
pixels_per_scan_line = info->pixels_per_scan_line;

/*
* Once we've found a GOP supporting PCIIO,
* Once we've found a GOP supporting ConOut,
* don't bother looking any further.
*/
if (pciio)
if (conout_found)
break;

first_gop = gop;
Expand All @@ -328,7 +331,6 @@ static efi_status_t setup_gop(struct screen_info *si, efi_guid_t *proto,
si->lfb_width = width;
si->lfb_height = height;
si->lfb_base = fb_base;
si->lfb_size = fb_size;
si->pages = 1;

if (pixel_format == PIXEL_RGB_RESERVED_8BIT_PER_COLOR) {
Expand Down Expand Up @@ -376,6 +378,10 @@ static efi_status_t setup_gop(struct screen_info *si, efi_guid_t *proto,
si->rsvd_pos = 0;
}

si->lfb_size = si->lfb_linelength * si->lfb_height;

si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS;

free_handle:
efi_call_phys1(sys_table->boottime->free_pool, gop_handle);
return status;
Expand Down
4 changes: 4 additions & 0 deletions arch/x86/boot/compressed/eboot.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
#define EFI_PAGE_SIZE (1UL << EFI_PAGE_SHIFT)
#define EFI_READ_CHUNK_SIZE (1024 * 1024)

#define EFI_CONSOLE_OUT_DEVICE_GUID \
EFI_GUID(0xd3b36f2c, 0xd551, 0x11d4, 0x9a, 0x46, 0x0, 0x90, 0x27, \
0x3f, 0xc1, 0x4d)

#define PIXEL_RGB_RESERVED_8BIT_PER_COLOR 0
#define PIXEL_BGR_RESERVED_8BIT_PER_COLOR 1
#define PIXEL_BIT_MASK 2
Expand Down
1 change: 1 addition & 0 deletions arch/x86/platform/efi/Makefile
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
obj-$(CONFIG_EFI) += efi.o efi_$(BITS).o efi_stub_$(BITS).o
obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o
76 changes: 76 additions & 0 deletions arch/x86/platform/efi/efi-bgrt.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright 2012 Intel Corporation
* Author: Josh Triplett <[email protected]>
*
* Based on the bgrt driver:
* Copyright 2012 Red Hat, Inc <[email protected]>
* Author: Matthew Garrett
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/acpi.h>
#include <linux/efi.h>
#include <linux/efi-bgrt.h>

struct acpi_table_bgrt *bgrt_tab;
void *bgrt_image;
size_t bgrt_image_size;

struct bmp_header {
u16 id;
u32 size;
} __packed;

void efi_bgrt_init(void)
{
acpi_status status;
void __iomem *image;
bool ioremapped = false;
struct bmp_header bmp_header;

if (acpi_disabled)
return;

status = acpi_get_table("BGRT", 0,
(struct acpi_table_header **)&bgrt_tab);
if (ACPI_FAILURE(status))
return;

if (bgrt_tab->version != 1)
return;
if (bgrt_tab->image_type != 0 || !bgrt_tab->image_address)
return;

image = efi_lookup_mapped_addr(bgrt_tab->image_address);
if (!image) {
image = ioremap(bgrt_tab->image_address, sizeof(bmp_header));
ioremapped = true;
if (!image)
return;
}

memcpy_fromio(&bmp_header, image, sizeof(bmp_header));
if (ioremapped)
iounmap(image);
bgrt_image_size = bmp_header.size;

bgrt_image = kmalloc(bgrt_image_size, GFP_KERNEL);
if (!bgrt_image)
return;

if (ioremapped) {
image = ioremap(bgrt_tab->image_address, bmp_header.size);
if (!image) {
kfree(bgrt_image);
bgrt_image = NULL;
return;
}
}

memcpy_fromio(bgrt_image, image, bgrt_image_size);
if (ioremapped)
iounmap(image);
}
66 changes: 53 additions & 13 deletions arch/x86/platform/efi/efi.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/efi.h>
#include <linux/efi-bgrt.h>
#include <linux/export.h>
#include <linux/bootmem.h>
#include <linux/memblock.h>
Expand Down Expand Up @@ -419,10 +420,21 @@ void __init efi_reserve_boot_services(void)
}
}

static void __init efi_free_boot_services(void)
static void __init efi_unmap_memmap(void)
{
if (memmap.map) {
early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size);
memmap.map = NULL;
}
}

void __init efi_free_boot_services(void)
{
void *p;

if (!efi_native)
return;

for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
efi_memory_desc_t *md = p;
unsigned long long start = md->phys_addr;
Expand All @@ -438,6 +450,8 @@ static void __init efi_free_boot_services(void)

free_bootmem_late(start, size);
}

efi_unmap_memmap();
}

static int __init efi_systab_init(void *phys)
Expand Down Expand Up @@ -732,6 +746,11 @@ void __init efi_init(void)
#endif
}

void __init efi_late_init(void)
{
efi_bgrt_init();
}

void __init efi_set_executable(efi_memory_desc_t *md, bool executable)
{
u64 addr, npages;
Expand Down Expand Up @@ -763,6 +782,34 @@ 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;
}

/*
* This function will switch the EFI runtime services to virtual mode.
* Essentially, look through the EFI memmap and map every region that
Expand All @@ -787,8 +834,10 @@ void __init efi_enter_virtual_mode(void)
* non-native EFI
*/

if (!efi_native)
goto out;
if (!efi_native) {
efi_unmap_memmap();
return;
}

/* Merge contiguous regions of the same type and attribute */
for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
Expand Down Expand Up @@ -877,19 +926,13 @@ void __init efi_enter_virtual_mode(void)
panic("EFI call to SetVirtualAddressMap() failed!");
}

/*
* Thankfully, it does seem that no runtime services other than
* SetVirtualAddressMap() will touch boot services code, so we can
* get rid of it all at this point
*/
efi_free_boot_services();

/*
* Now that EFI is in virtual mode, update the function
* pointers in the runtime service table to the new virtual addresses.
*
* Call EFI services through wrapper functions.
*/
efi.runtime_version = efi_systab.fw_revision;
efi.get_time = virt_efi_get_time;
efi.set_time = virt_efi_set_time;
efi.get_wakeup_time = virt_efi_get_wakeup_time;
Expand All @@ -906,9 +949,6 @@ void __init efi_enter_virtual_mode(void)
if (__supported_pte_mask & _PAGE_NX)
runtime_code_page_mkexec();

out:
early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size);
memmap.map = NULL;
kfree(new_memmap);
}

Expand Down
4 changes: 2 additions & 2 deletions drivers/acpi/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -385,8 +385,8 @@ config ACPI_CUSTOM_METHOD
to override that restriction).

config ACPI_BGRT
tristate "Boottime Graphics Resource Table support"
default n
bool "Boottime Graphics Resource Table support"
depends on EFI
help
This driver adds support for exposing the ACPI Boottime Graphics
Resource Table, which allows the operating system to obtain
Expand Down
Loading

0 comments on commit 3b29b03

Please sign in to comment.