Merge branch 'efi-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 13 Aug 2018 17:25:08 +0000 (10:25 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 13 Aug 2018 17:25:08 +0000 (10:25 -0700)
Pull EFI updates from Thomas Gleixner:
 "The EFI pile:

   - Make mixed mode UEFI runtime service invocations mutually
     exclusive, as mandated by the UEFI spec

   - Perform UEFI runtime services calls from a work queue so the calls
     into the firmware occur from a kernel thread

   - Honor the UEFI memory map attributes for live memory regions
     configured by UEFI as a framebuffer. This works around a coherency
     problem with KVM guests running on ARM.

   - Cleanups, improvements and fixes all over the place"

* 'efi-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  efivars: Call guid_parse() against guid_t type of variable
  efi/cper: Use consistent types for UUIDs
  efi/x86: Replace references to efi_early->is64 with efi_is_64bit()
  efi: Deduplicate efi_open_volume()
  efi/x86: Add missing NULL initialization in UGA draw protocol discovery
  efi/x86: Merge 32-bit and 64-bit UGA draw protocol setup routines
  efi/x86: Align efi_uga_draw_protocol typedef names to convention
  efi/x86: Merge the setup_efi_pci32() and setup_efi_pci64() routines
  efi/x86: Prevent reentrant firmware calls in mixed mode
  efi/esrt: Only call efi_mem_reserve() for boot services memory
  fbdev/efifb: Honour UEFI memory map attributes when mapping the FB
  efi: Drop type and attribute checks in efi_mem_desc_lookup()
  efi/libstub/arm: Add opt-in Kconfig option for the DTB loader
  efi: Remove the declaration of efi_late_init() as the function is unused
  efi/cper: Avoid using get_seconds()
  efi: Use a work queue to invoke EFI Runtime Services
  efi/x86: Use non-blocking SetVariable() for efi_delete_dummy_variable()
  efi/x86: Clean up the eboot code

17 files changed:
arch/arm/include/asm/efi.h
arch/arm64/include/asm/efi.h
arch/x86/boot/compressed/eboot.c
arch/x86/boot/compressed/eboot.h
arch/x86/platform/efi/efi_64.c
arch/x86/platform/efi/quirks.c
drivers/firmware/efi/Kconfig
drivers/firmware/efi/cper.c
drivers/firmware/efi/efi.c
drivers/firmware/efi/esrt.c
drivers/firmware/efi/libstub/arm-stub.c
drivers/firmware/efi/libstub/efi-stub-helper.c
drivers/firmware/efi/libstub/efistub.h
drivers/firmware/efi/runtime-wrappers.c
drivers/video/fbdev/efifb.c
fs/efivarfs/inode.c
include/linux/efi.h

index 17f1f1a814ff60968fdff9a18005c4448bc66690..38badaae8d9d712fe97ca5ac2f6b6de7198a44ec 100644 (file)
@@ -58,6 +58,9 @@ void efi_virtmap_unload(void);
 #define efi_call_runtime(f, ...)       sys_table_arg->runtime->f(__VA_ARGS__)
 #define efi_is_64bit()                 (false)
 
+#define efi_table_attr(table, attr, instance)                          \
+       ((table##_t *)instance)->attr
+
 #define efi_call_proto(protocol, f, instance, ...)                     \
        ((protocol##_t *)instance)->f(instance, ##__VA_ARGS__)
 
index 192d791f11036747704fedbc0839b37a4c1e49fc..7ed320895d1f463d1e95cd9ec6328a49eed765ae 100644 (file)
@@ -87,6 +87,9 @@ static inline unsigned long efi_get_max_initrd_addr(unsigned long dram_base,
 #define efi_call_runtime(f, ...)       sys_table_arg->runtime->f(__VA_ARGS__)
 #define efi_is_64bit()                 (true)
 
+#define efi_table_attr(table, attr, instance)                          \
+       ((table##_t *)instance)->attr
+
 #define efi_call_proto(protocol, f, instance, ...)                     \
        ((protocol##_t *)instance)->f(instance, ##__VA_ARGS__)
 
index e98522ea6f09ee2fb52c2d69f333e6d4916940e5..1458b1700fc7e4c580ea963920d199fd7a4fb625 100644 (file)
@@ -34,74 +34,13 @@ static void setup_boot_services##bits(struct efi_config *c)         \
                                                                        \
        table = (typeof(table))sys_table;                               \
                                                                        \
-       c->runtime_services = table->runtime;                           \
-       c->boot_services = table->boottime;                             \
-       c->text_output = table->con_out;                                \
+       c->runtime_services     = table->runtime;                       \
+       c->boot_services        = table->boottime;                      \
+       c->text_output          = table->con_out;                       \
 }
 BOOT_SERVICES(32);
 BOOT_SERVICES(64);
 
-static inline efi_status_t __open_volume32(void *__image, void **__fh)
-{
-       efi_file_io_interface_t *io;
-       efi_loaded_image_32_t *image = __image;
-       efi_file_handle_32_t *fh;
-       efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
-       efi_status_t status;
-       void *handle = (void *)(unsigned long)image->device_handle;
-       unsigned long func;
-
-       status = efi_call_early(handle_protocol, handle,
-                               &fs_proto, (void **)&io);
-       if (status != EFI_SUCCESS) {
-               efi_printk(sys_table, "Failed to handle fs_proto\n");
-               return status;
-       }
-
-       func = (unsigned long)io->open_volume;
-       status = efi_early->call(func, io, &fh);
-       if (status != EFI_SUCCESS)
-               efi_printk(sys_table, "Failed to open volume\n");
-
-       *__fh = fh;
-       return status;
-}
-
-static inline efi_status_t __open_volume64(void *__image, void **__fh)
-{
-       efi_file_io_interface_t *io;
-       efi_loaded_image_64_t *image = __image;
-       efi_file_handle_64_t *fh;
-       efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
-       efi_status_t status;
-       void *handle = (void *)(unsigned long)image->device_handle;
-       unsigned long func;
-
-       status = efi_call_early(handle_protocol, handle,
-                               &fs_proto, (void **)&io);
-       if (status != EFI_SUCCESS) {
-               efi_printk(sys_table, "Failed to handle fs_proto\n");
-               return status;
-       }
-
-       func = (unsigned long)io->open_volume;
-       status = efi_early->call(func, io, &fh);
-       if (status != EFI_SUCCESS)
-               efi_printk(sys_table, "Failed to open volume\n");
-
-       *__fh = fh;
-       return status;
-}
-
-efi_status_t
-efi_open_volume(efi_system_table_t *sys_table, void *__image, void **__fh)
-{
-       if (efi_early->is64)
-               return __open_volume64(__image, __fh);
-
-       return __open_volume32(__image, __fh);
-}
-
 void efi_char16_printk(efi_system_table_t *table, efi_char16_t *str)
 {
        efi_call_proto(efi_simple_text_output_protocol, output_string,
@@ -109,7 +48,7 @@ void efi_char16_printk(efi_system_table_t *table, efi_char16_t *str)
 }
 
 static efi_status_t
-__setup_efi_pci(efi_pci_io_protocol_t *pci, struct pci_setup_rom **__rom)
+preserve_pci_rom_image(efi_pci_io_protocol_t *pci, struct pci_setup_rom **__rom)
 {
        struct pci_setup_rom *rom = NULL;
        efi_status_t status;
@@ -134,16 +73,16 @@ __setup_efi_pci(efi_pci_io_protocol_t *pci, struct pci_setup_rom **__rom)
 
        status = efi_call_early(allocate_pool, EFI_LOADER_DATA, size, &rom);
        if (status != EFI_SUCCESS) {
-               efi_printk(sys_table, "Failed to alloc mem for rom\n");
+               efi_printk(sys_table, "Failed to allocate memory for 'rom'\n");
                return status;
        }
 
        memset(rom, 0, sizeof(*rom));
 
-       rom->data.type = SETUP_PCI;
-       rom->data.len = size - sizeof(struct setup_data);
-       rom->data.next = 0;
-       rom->pcilen = pci->romsize;
+       rom->data.type  = SETUP_PCI;
+       rom->data.len   = size - sizeof(struct setup_data);
+       rom->data.next  = 0;
+       rom->pcilen     = pci->romsize;
        *__rom = rom;
 
        status = efi_call_proto(efi_pci_io_protocol, pci.read, pci,
@@ -179,96 +118,6 @@ free_struct:
        return status;
 }
 
-static void
-setup_efi_pci32(struct boot_params *params, void **pci_handle,
-               unsigned long size)
-{
-       efi_pci_io_protocol_t *pci = NULL;
-       efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
-       u32 *handles = (u32 *)(unsigned long)pci_handle;
-       efi_status_t status;
-       unsigned long nr_pci;
-       struct setup_data *data;
-       int i;
-
-       data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
-
-       while (data && data->next)
-               data = (struct setup_data *)(unsigned long)data->next;
-
-       nr_pci = size / sizeof(u32);
-       for (i = 0; i < nr_pci; i++) {
-               struct pci_setup_rom *rom = NULL;
-               u32 h = handles[i];
-
-               status = efi_call_early(handle_protocol, h,
-                                       &pci_proto, (void **)&pci);
-
-               if (status != EFI_SUCCESS)
-                       continue;
-
-               if (!pci)
-                       continue;
-
-               status = __setup_efi_pci(pci, &rom);
-               if (status != EFI_SUCCESS)
-                       continue;
-
-               if (data)
-                       data->next = (unsigned long)rom;
-               else
-                       params->hdr.setup_data = (unsigned long)rom;
-
-               data = (struct setup_data *)rom;
-
-       }
-}
-
-static void
-setup_efi_pci64(struct boot_params *params, void **pci_handle,
-               unsigned long size)
-{
-       efi_pci_io_protocol_t *pci = NULL;
-       efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
-       u64 *handles = (u64 *)(unsigned long)pci_handle;
-       efi_status_t status;
-       unsigned long nr_pci;
-       struct setup_data *data;
-       int i;
-
-       data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
-
-       while (data && data->next)
-               data = (struct setup_data *)(unsigned long)data->next;
-
-       nr_pci = size / sizeof(u64);
-       for (i = 0; i < nr_pci; i++) {
-               struct pci_setup_rom *rom = NULL;
-               u64 h = handles[i];
-
-               status = efi_call_early(handle_protocol, h,
-                                       &pci_proto, (void **)&pci);
-
-               if (status != EFI_SUCCESS)
-                       continue;
-
-               if (!pci)
-                       continue;
-
-               status = __setup_efi_pci(pci, &rom);
-               if (status != EFI_SUCCESS)
-                       continue;
-
-               if (data)
-                       data->next = (unsigned long)rom;
-               else
-                       params->hdr.setup_data = (unsigned long)rom;
-
-               data = (struct setup_data *)rom;
-
-       }
-}
-
 /*
  * There's no way to return an informative status from this function,
  * because any analysis (and printing of error messages) needs to be
@@ -284,6 +133,9 @@ static void setup_efi_pci(struct boot_params *params)
        void **pci_handle = NULL;
        efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
        unsigned long size = 0;
+       unsigned long nr_pci;
+       struct setup_data *data;
+       int i;
 
        status = efi_call_early(locate_handle,
                                EFI_LOCATE_BY_PROTOCOL,
@@ -295,7 +147,7 @@ static void setup_efi_pci(struct boot_params *params)
                                        size, (void **)&pci_handle);
 
                if (status != EFI_SUCCESS) {
-                       efi_printk(sys_table, "Failed to alloc mem for pci_handle\n");
+                       efi_printk(sys_table, "Failed to allocate memory for 'pci_handle'\n");
                        return;
                }
 
@@ -307,10 +159,34 @@ static void setup_efi_pci(struct boot_params *params)
        if (status != EFI_SUCCESS)
                goto free_handle;
 
-       if (efi_early->is64)
-               setup_efi_pci64(params, pci_handle, size);
-       else
-               setup_efi_pci32(params, pci_handle, size);
+       data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
+
+       while (data && data->next)
+               data = (struct setup_data *)(unsigned long)data->next;
+
+       nr_pci = size / (efi_is_64bit() ? sizeof(u64) : sizeof(u32));
+       for (i = 0; i < nr_pci; i++) {
+               efi_pci_io_protocol_t *pci = NULL;
+               struct pci_setup_rom *rom;
+
+               status = efi_call_early(handle_protocol,
+                                       efi_is_64bit() ? ((u64 *)pci_handle)[i]
+                                                      : ((u32 *)pci_handle)[i],
+                                       &pci_proto, (void **)&pci);
+               if (status != EFI_SUCCESS || !pci)
+                       continue;
+
+               status = preserve_pci_rom_image(pci, &rom);
+               if (status != EFI_SUCCESS)
+                       continue;
+
+               if (data)
+                       data->next = (unsigned long)rom;
+               else
+                       params->hdr.setup_data = (unsigned long)rom;
+
+               data = (struct setup_data *)rom;
+       }
 
 free_handle:
        efi_call_early(free_pool, pci_handle);
@@ -341,8 +217,7 @@ static void retrieve_apple_device_properties(struct boot_params *boot_params)
                status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
                                        size + sizeof(struct setup_data), &new);
                if (status != EFI_SUCCESS) {
-                       efi_printk(sys_table,
-                                       "Failed to alloc mem for properties\n");
+                       efi_printk(sys_table, "Failed to allocate memory for 'properties'\n");
                        return;
                }
 
@@ -358,9 +233,9 @@ static void retrieve_apple_device_properties(struct boot_params *boot_params)
        new->next = 0;
 
        data = (struct setup_data *)(unsigned long)boot_params->hdr.setup_data;
-       if (!data)
+       if (!data) {
                boot_params->hdr.setup_data = (unsigned long)new;
-       else {
+       else {
                while (data->next)
                        data = (struct setup_data *)(unsigned long)data->next;
                data->next = (unsigned long)new;
@@ -380,81 +255,55 @@ static void setup_quirks(struct boot_params *boot_params)
        }
 }
 
+/*
+ * See if we have Universal Graphics Adapter (UGA) protocol
+ */
 static efi_status_t
-setup_uga32(void **uga_handle, unsigned long size, u32 *width, u32 *height)
+setup_uga(struct screen_info *si, efi_guid_t *uga_proto, unsigned long size)
 {
-       struct efi_uga_draw_protocol *uga = NULL, *first_uga;
-       efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID;
+       efi_status_t status;
+       u32 width, height;
+       void **uga_handle = NULL;
+       efi_uga_draw_protocol_t *uga = NULL, *first_uga;
        unsigned long nr_ugas;
-       u32 *handles = (u32 *)uga_handle;
-       efi_status_t status = EFI_INVALID_PARAMETER;
        int i;
 
-       first_uga = NULL;
-       nr_ugas = size / sizeof(u32);
-       for (i = 0; i < nr_ugas; i++) {
-               efi_guid_t pciio_proto = EFI_PCI_IO_PROTOCOL_GUID;
-               u32 w, h, depth, refresh;
-               void *pciio;
-               u32 handle = handles[i];
-
-               status = efi_call_early(handle_protocol, handle,
-                                       &uga_proto, (void **)&uga);
-               if (status != EFI_SUCCESS)
-                       continue;
-
-               efi_call_early(handle_protocol, handle, &pciio_proto, &pciio);
-
-               status = efi_early->call((unsigned long)uga->get_mode, uga,
-                                        &w, &h, &depth, &refresh);
-               if (status == EFI_SUCCESS && (!first_uga || pciio)) {
-                       *width = w;
-                       *height = h;
-
-                       /*
-                        * Once we've found a UGA supporting PCIIO,
-                        * don't bother looking any further.
-                        */
-                       if (pciio)
-                               break;
-
-                       first_uga = uga;
-               }
-       }
+       status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
+                               size, (void **)&uga_handle);
+       if (status != EFI_SUCCESS)
+               return status;
 
-       return status;
-}
+       status = efi_call_early(locate_handle,
+                               EFI_LOCATE_BY_PROTOCOL,
+                               uga_proto, NULL, &size, uga_handle);
+       if (status != EFI_SUCCESS)
+               goto free_handle;
 
-static efi_status_t
-setup_uga64(void **uga_handle, unsigned long size, u32 *width, u32 *height)
-{
-       struct efi_uga_draw_protocol *uga = NULL, *first_uga;
-       efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID;
-       unsigned long nr_ugas;
-       u64 *handles = (u64 *)uga_handle;
-       efi_status_t status = EFI_INVALID_PARAMETER;
-       int i;
+       height = 0;
+       width = 0;
 
        first_uga = NULL;
-       nr_ugas = size / sizeof(u64);
+       nr_ugas = size / (efi_is_64bit() ? sizeof(u64) : sizeof(u32));
        for (i = 0; i < nr_ugas; i++) {
                efi_guid_t pciio_proto = EFI_PCI_IO_PROTOCOL_GUID;
                u32 w, h, depth, refresh;
                void *pciio;
-               u64 handle = handles[i];
+               unsigned long handle = efi_is_64bit() ? ((u64 *)uga_handle)[i]
+                                                     : ((u32 *)uga_handle)[i];
 
                status = efi_call_early(handle_protocol, handle,
-                                       &uga_proto, (void **)&uga);
+                                       uga_proto, (void **)&uga);
                if (status != EFI_SUCCESS)
                        continue;
 
+               pciio = NULL;
                efi_call_early(handle_protocol, handle, &pciio_proto, &pciio);
 
-               status = efi_early->call((unsigned long)uga->get_mode, uga,
-                                        &w, &h, &depth, &refresh);
+               status = efi_call_proto(efi_uga_draw_protocol, get_mode, uga,
+                                       &w, &h, &depth, &refresh);
                if (status == EFI_SUCCESS && (!first_uga || pciio)) {
-                       *width = w;
-                       *height = h;
+                       width = w;
+                       height = h;
 
                        /*
                         * Once we've found a UGA supporting PCIIO,
@@ -467,59 +316,28 @@ setup_uga64(void **uga_handle, unsigned long size, u32 *width, u32 *height)
                }
        }
 
-       return status;
-}
-
-/*
- * See if we have Universal Graphics Adapter (UGA) protocol
- */
-static efi_status_t setup_uga(struct screen_info *si, efi_guid_t *uga_proto,
-                             unsigned long size)
-{
-       efi_status_t status;
-       u32 width, height;
-       void **uga_handle = NULL;
-
-       status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
-                               size, (void **)&uga_handle);
-       if (status != EFI_SUCCESS)
-               return status;
-
-       status = efi_call_early(locate_handle,
-                               EFI_LOCATE_BY_PROTOCOL,
-                               uga_proto, NULL, &size, uga_handle);
-       if (status != EFI_SUCCESS)
-               goto free_handle;
-
-       height = 0;
-       width = 0;
-
-       if (efi_early->is64)
-               status = setup_uga64(uga_handle, size, &width, &height);
-       else
-               status = setup_uga32(uga_handle, size, &width, &height);
-
        if (!width && !height)
                goto free_handle;
 
        /* EFI framebuffer */
-       si->orig_video_isVGA = VIDEO_TYPE_EFI;
+       si->orig_video_isVGA    = VIDEO_TYPE_EFI;
 
-       si->lfb_depth = 32;
-       si->lfb_width = width;
-       si->lfb_height = height;
+       si->lfb_depth           = 32;
+       si->lfb_width           = width;
+       si->lfb_height          = height;
 
-       si->red_size = 8;
-       si->red_pos = 16;
-       si->green_size = 8;
-       si->green_pos = 8;
-       si->blue_size = 8;
-       si->blue_pos = 0;
-       si->rsvd_size = 8;
-       si->rsvd_pos = 24;
+       si->red_size            = 8;
+       si->red_pos             = 16;
+       si->green_size          = 8;
+       si->green_pos           = 8;
+       si->blue_size           = 8;
+       si->blue_pos            = 0;
+       si->rsvd_size           = 8;
+       si->rsvd_pos            = 24;
 
 free_handle:
        efi_call_early(free_pool, uga_handle);
+
        return status;
 }
 
@@ -586,7 +404,7 @@ struct boot_params *make_boot_params(struct efi_config *c)
        if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
                return NULL;
 
-       if (efi_early->is64)
+       if (efi_is_64bit())
                setup_boot_services64(efi_early);
        else
                setup_boot_services32(efi_early);
@@ -601,7 +419,7 @@ struct boot_params *make_boot_params(struct efi_config *c)
        status = efi_low_alloc(sys_table, 0x4000, 1,
                               (unsigned long *)&boot_params);
        if (status != EFI_SUCCESS) {
-               efi_printk(sys_table, "Failed to alloc lowmem for boot params\n");
+               efi_printk(sys_table, "Failed to allocate lowmem for boot params\n");
                return NULL;
        }
 
@@ -617,9 +435,9 @@ struct boot_params *make_boot_params(struct efi_config *c)
         * Fill out some of the header fields ourselves because the
         * EFI firmware loader doesn't load the first sector.
         */
-       hdr->root_flags = 1;
-       hdr->vid_mode = 0xffff;
-       hdr->boot_flag = 0xAA55;
+       hdr->root_flags = 1;
+       hdr->vid_mode   = 0xffff;
+       hdr->boot_flag  = 0xAA55;
 
        hdr->type_of_loader = 0x21;
 
@@ -627,6 +445,7 @@ struct boot_params *make_boot_params(struct efi_config *c)
        cmdline_ptr = efi_convert_cmdline(sys_table, image, &options_size);
        if (!cmdline_ptr)
                goto fail;
+
        hdr->cmd_line_ptr = (unsigned long)cmdline_ptr;
        /* Fill in upper bits of command line address, NOP on 32 bit  */
        boot_params->ext_cmd_line_ptr = (u64)(unsigned long)cmdline_ptr >> 32;
@@ -663,10 +482,12 @@ struct boot_params *make_boot_params(struct efi_config *c)
        boot_params->ext_ramdisk_size  = (u64)ramdisk_size >> 32;
 
        return boot_params;
+
 fail2:
        efi_free(sys_table, options_size, hdr->cmd_line_ptr);
 fail:
        efi_free(sys_table, 0x4000, (unsigned long)boot_params);
+
        return NULL;
 }
 
@@ -678,7 +499,7 @@ static void add_e820ext(struct boot_params *params,
        unsigned long size;
 
        e820ext->type = SETUP_E820_EXT;
-       e820ext->len = nr_entries * sizeof(struct boot_e820_entry);
+       e820ext->len  = nr_entries * sizeof(struct boot_e820_entry);
        e820ext->next = 0;
 
        data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
@@ -692,8 +513,8 @@ static void add_e820ext(struct boot_params *params,
                params->hdr.setup_data = (unsigned long)e820ext;
 }
 
-static efi_status_t setup_e820(struct boot_params *params,
-                              struct setup_data *e820ext, u32 e820ext_size)
+static efi_status_t
+setup_e820(struct boot_params *params, struct setup_data *e820ext, u32 e820ext_size)
 {
        struct boot_e820_entry *entry = params->e820_table;
        struct efi_info *efi = &params->efi_info;
@@ -814,11 +635,10 @@ static efi_status_t alloc_e820ext(u32 nr_desc, struct setup_data **e820ext,
 }
 
 struct exit_boot_struct {
-       struct boot_params *boot_params;
-       struct efi_info *efi;
-       struct setup_data *e820ext;
-       __u32 e820ext_size;
-       bool is64;
+       struct boot_params      *boot_params;
+       struct efi_info         *efi;
+       struct setup_data       *e820ext;
+       __u32                   e820ext_size;
 };
 
 static efi_status_t exit_boot_func(efi_system_table_t *sys_table_arg,
@@ -845,25 +665,25 @@ static efi_status_t exit_boot_func(efi_system_table_t *sys_table_arg,
                first = false;
        }
 
-       signature = p->is64 ? EFI64_LOADER_SIGNATURE : EFI32_LOADER_SIGNATURE;
+       signature = efi_is_64bit() ? EFI64_LOADER_SIGNATURE
+                                  : EFI32_LOADER_SIGNATURE;
        memcpy(&p->efi->efi_loader_signature, signature, sizeof(__u32));
 
-       p->efi->efi_systab = (unsigned long)sys_table_arg;
-       p->efi->efi_memdesc_size = *map->desc_size;
-       p->efi->efi_memdesc_version = *map->desc_ver;
-       p->efi->efi_memmap = (unsigned long)*map->map;
-       p->efi->efi_memmap_size = *map->map_size;
+       p->efi->efi_systab              = (unsigned long)sys_table_arg;
+       p->efi->efi_memdesc_size        = *map->desc_size;
+       p->efi->efi_memdesc_version     = *map->desc_ver;
+       p->efi->efi_memmap              = (unsigned long)*map->map;
+       p->efi->efi_memmap_size         = *map->map_size;
 
 #ifdef CONFIG_X86_64
-       p->efi->efi_systab_hi = (unsigned long)sys_table_arg >> 32;
-       p->efi->efi_memmap_hi = (unsigned long)*map->map >> 32;
+       p->efi->efi_systab_hi           = (unsigned long)sys_table_arg >> 32;
+       p->efi->efi_memmap_hi           = (unsigned long)*map->map >> 32;
 #endif
 
        return EFI_SUCCESS;
 }
 
-static efi_status_t exit_boot(struct boot_params *boot_params,
-                             void *handle, bool is64)
+static efi_status_t exit_boot(struct boot_params *boot_params, void *handle)
 {
        unsigned long map_sz, key, desc_size, buff_size;
        efi_memory_desc_t *mem_map;
@@ -874,17 +694,16 @@ static efi_status_t exit_boot(struct boot_params *boot_params,
        struct efi_boot_memmap map;
        struct exit_boot_struct priv;
 
-       map.map =               &mem_map;
-       map.map_size =          &map_sz;
-       map.desc_size =         &desc_size;
-       map.desc_ver =          &desc_version;
-       map.key_ptr =           &key;
-       map.buff_size =         &buff_size;
-       priv.boot_params =      boot_params;
-       priv.efi =              &boot_params->efi_info;
-       priv.e820ext =          NULL;
-       priv.e820ext_size =     0;
-       priv.is64 =             is64;
+       map.map                 = &mem_map;
+       map.map_size            = &map_sz;
+       map.desc_size           = &desc_size;
+       map.desc_ver            = &desc_version;
+       map.key_ptr             = &key;
+       map.buff_size           = &buff_size;
+       priv.boot_params        = boot_params;
+       priv.efi                = &boot_params->efi_info;
+       priv.e820ext            = NULL;
+       priv.e820ext_size       = 0;
 
        /* Might as well exit boot services now */
        status = efi_exit_boot_services(sys_table, handle, &map, &priv,
@@ -892,10 +711,11 @@ static efi_status_t exit_boot(struct boot_params *boot_params,
        if (status != EFI_SUCCESS)
                return status;
 
-       e820ext = priv.e820ext;
-       e820ext_size = priv.e820ext_size;
+       e820ext                 = priv.e820ext;
+       e820ext_size            = priv.e820ext_size;
+
        /* Historic? */
-       boot_params->alt_mem_k = 32 * 1024;
+       boot_params->alt_mem_k  = 32 * 1024;
 
        status = setup_e820(boot_params, e820ext, e820ext_size);
        if (status != EFI_SUCCESS)
@@ -908,8 +728,8 @@ static efi_status_t exit_boot(struct boot_params *boot_params,
  * On success we return a pointer to a boot_params structure, and NULL
  * on failure.
  */
-struct boot_params *efi_main(struct efi_config *c,
-                            struct boot_params *boot_params)
+struct boot_params *
+efi_main(struct efi_config *c, struct boot_params *boot_params)
 {
        struct desc_ptr *gdt = NULL;
        efi_loaded_image_t *image;
@@ -918,13 +738,11 @@ struct boot_params *efi_main(struct efi_config *c,
        struct desc_struct *desc;
        void *handle;
        efi_system_table_t *_table;
-       bool is64;
 
        efi_early = c;
 
        _table = (efi_system_table_t *)(unsigned long)efi_early->table;
        handle = (void *)(unsigned long)efi_early->image_handle;
-       is64 = efi_early->is64;
 
        sys_table = _table;
 
@@ -932,7 +750,7 @@ struct boot_params *efi_main(struct efi_config *c,
        if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
                goto fail;
 
-       if (is64)
+       if (efi_is_64bit())
                setup_boot_services64(efi_early);
        else
                setup_boot_services32(efi_early);
@@ -957,7 +775,7 @@ struct boot_params *efi_main(struct efi_config *c,
        status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
                                sizeof(*gdt), (void **)&gdt);
        if (status != EFI_SUCCESS) {
-               efi_printk(sys_table, "Failed to alloc mem for gdt structure\n");
+               efi_printk(sys_table, "Failed to allocate memory for 'gdt' structure\n");
                goto fail;
        }
 
@@ -965,7 +783,7 @@ struct boot_params *efi_main(struct efi_config *c,
        status = efi_low_alloc(sys_table, gdt->size, 8,
                           (unsigned long *)&gdt->address);
        if (status != EFI_SUCCESS) {
-               efi_printk(sys_table, "Failed to alloc mem for gdt\n");
+               efi_printk(sys_table, "Failed to allocate memory for 'gdt'\n");
                goto fail;
        }
 
@@ -988,7 +806,7 @@ struct boot_params *efi_main(struct efi_config *c,
                hdr->code32_start = bzimage_addr;
        }
 
-       status = exit_boot(boot_params, handle, is64);
+       status = exit_boot(boot_params, handle);
        if (status != EFI_SUCCESS) {
                efi_printk(sys_table, "exit_boot() failed!\n");
                goto fail;
@@ -1002,19 +820,20 @@ struct boot_params *efi_main(struct efi_config *c,
 
        if (IS_ENABLED(CONFIG_X86_64)) {
                /* __KERNEL32_CS */
-               desc->limit0 = 0xffff;
-               desc->base0 = 0x0000;
-               desc->base1 = 0x0000;
-               desc->type = SEG_TYPE_CODE | SEG_TYPE_EXEC_READ;
-               desc->s = DESC_TYPE_CODE_DATA;
-               desc->dpl = 0;
-               desc->p = 1;
-               desc->limit1 = 0xf;
-               desc->avl = 0;
-               desc->l = 0;
-               desc->d = SEG_OP_SIZE_32BIT;
-               desc->g = SEG_GRANULARITY_4KB;
-               desc->base2 = 0x00;
+               desc->limit0    = 0xffff;
+               desc->base0     = 0x0000;
+               desc->base1     = 0x0000;
+               desc->type      = SEG_TYPE_CODE | SEG_TYPE_EXEC_READ;
+               desc->s         = DESC_TYPE_CODE_DATA;
+               desc->dpl       = 0;
+               desc->p         = 1;
+               desc->limit1    = 0xf;
+               desc->avl       = 0;
+               desc->l         = 0;
+               desc->d         = SEG_OP_SIZE_32BIT;
+               desc->g         = SEG_GRANULARITY_4KB;
+               desc->base2     = 0x00;
+
                desc++;
        } else {
                /* Second entry is unused on 32-bit */
@@ -1022,15 +841,16 @@ struct boot_params *efi_main(struct efi_config *c,
        }
 
        /* __KERNEL_CS */
-       desc->limit0 = 0xffff;
-       desc->base0 = 0x0000;
-       desc->base1 = 0x0000;
-       desc->type = SEG_TYPE_CODE | SEG_TYPE_EXEC_READ;
-       desc->s = DESC_TYPE_CODE_DATA;
-       desc->dpl = 0;
-       desc->p = 1;
-       desc->limit1 = 0xf;
-       desc->avl = 0;
+       desc->limit0    = 0xffff;
+       desc->base0     = 0x0000;
+       desc->base1     = 0x0000;
+       desc->type      = SEG_TYPE_CODE | SEG_TYPE_EXEC_READ;
+       desc->s         = DESC_TYPE_CODE_DATA;
+       desc->dpl       = 0;
+       desc->p         = 1;
+       desc->limit1    = 0xf;
+       desc->avl       = 0;
+
        if (IS_ENABLED(CONFIG_X86_64)) {
                desc->l = 1;
                desc->d = 0;
@@ -1038,41 +858,41 @@ struct boot_params *efi_main(struct efi_config *c,
                desc->l = 0;
                desc->d = SEG_OP_SIZE_32BIT;
        }
-       desc->g = SEG_GRANULARITY_4KB;
-       desc->base2 = 0x00;
+       desc->g         = SEG_GRANULARITY_4KB;
+       desc->base2     = 0x00;
        desc++;
 
        /* __KERNEL_DS */
-       desc->limit0 = 0xffff;
-       desc->base0 = 0x0000;
-       desc->base1 = 0x0000;
-       desc->type = SEG_TYPE_DATA | SEG_TYPE_READ_WRITE;
-       desc->s = DESC_TYPE_CODE_DATA;
-       desc->dpl = 0;
-       desc->p = 1;
-       desc->limit1 = 0xf;
-       desc->avl = 0;
-       desc->l = 0;
-       desc->d = SEG_OP_SIZE_32BIT;
-       desc->g = SEG_GRANULARITY_4KB;
-       desc->base2 = 0x00;
+       desc->limit0    = 0xffff;
+       desc->base0     = 0x0000;
+       desc->base1     = 0x0000;
+       desc->type      = SEG_TYPE_DATA | SEG_TYPE_READ_WRITE;
+       desc->s         = DESC_TYPE_CODE_DATA;
+       desc->dpl       = 0;
+       desc->p         = 1;
+       desc->limit1    = 0xf;
+       desc->avl       = 0;
+       desc->l         = 0;
+       desc->d         = SEG_OP_SIZE_32BIT;
+       desc->g         = SEG_GRANULARITY_4KB;
+       desc->base2     = 0x00;
        desc++;
 
        if (IS_ENABLED(CONFIG_X86_64)) {
                /* Task segment value */
-               desc->limit0 = 0x0000;
-               desc->base0 = 0x0000;
-               desc->base1 = 0x0000;
-               desc->type = SEG_TYPE_TSS;
-               desc->s = 0;
-               desc->dpl = 0;
-               desc->p = 1;
-               desc->limit1 = 0x0;
-               desc->avl = 0;
-               desc->l = 0;
-               desc->d = 0;
-               desc->g = SEG_GRANULARITY_4KB;
-               desc->base2 = 0x00;
+               desc->limit0    = 0x0000;
+               desc->base0     = 0x0000;
+               desc->base1     = 0x0000;
+               desc->type      = SEG_TYPE_TSS;
+               desc->s         = 0;
+               desc->dpl       = 0;
+               desc->p         = 1;
+               desc->limit1    = 0x0;
+               desc->avl       = 0;
+               desc->l         = 0;
+               desc->d         = 0;
+               desc->g         = SEG_GRANULARITY_4KB;
+               desc->base2     = 0x00;
                desc++;
        }
 
@@ -1082,5 +902,6 @@ struct boot_params *efi_main(struct efi_config *c,
        return boot_params;
 fail:
        efi_printk(sys_table, "efi_main() failed!\n");
+
        return NULL;
 }
index e799dc5c644872e65625b9442d194470a49d663c..8297387c4676124167207dc1383467a0b221c6ff 100644 (file)
 
 #define DESC_TYPE_CODE_DATA    (1 << 0)
 
-struct efi_uga_draw_protocol_32 {
+typedef struct {
        u32 get_mode;
        u32 set_mode;
        u32 blt;
-};
+} efi_uga_draw_protocol_32_t;
 
-struct efi_uga_draw_protocol_64 {
+typedef struct {
        u64 get_mode;
        u64 set_mode;
        u64 blt;
-};
+} efi_uga_draw_protocol_64_t;
 
-struct efi_uga_draw_protocol {
+typedef struct {
        void *get_mode;
        void *set_mode;
        void *blt;
-};
+} efi_uga_draw_protocol_t;
 
 #endif /* BOOT_COMPRESSED_EBOOT_H */
index 5f2eb32316073f15307aa28ac8b37a17230ea751..ee5d08f25ce45f21aa81550ce317760a2c745900 100644 (file)
@@ -636,6 +636,8 @@ void efi_switch_mm(struct mm_struct *mm)
 #ifdef CONFIG_EFI_MIXED
 extern efi_status_t efi64_thunk(u32, ...);
 
+static DEFINE_SPINLOCK(efi_runtime_lock);
+
 #define runtime_service32(func)                                                 \
 ({                                                                      \
        u32 table = (u32)(unsigned long)efi.systab;                      \
@@ -657,17 +659,14 @@ extern efi_status_t efi64_thunk(u32, ...);
 #define efi_thunk(f, ...)                                              \
 ({                                                                     \
        efi_status_t __s;                                               \
-       unsigned long __flags;                                          \
        u32 __func;                                                     \
                                                                        \
-       local_irq_save(__flags);                                        \
        arch_efi_call_virt_setup();                                     \
                                                                        \
        __func = runtime_service32(f);                                  \
        __s = efi64_thunk(__func, __VA_ARGS__);                         \
                                                                        \
        arch_efi_call_virt_teardown();                                  \
-       local_irq_restore(__flags);                                     \
                                                                        \
        __s;                                                            \
 })
@@ -702,14 +701,17 @@ static efi_status_t efi_thunk_get_time(efi_time_t *tm, efi_time_cap_t *tc)
 {
        efi_status_t status;
        u32 phys_tm, phys_tc;
+       unsigned long flags;
 
        spin_lock(&rtc_lock);
+       spin_lock_irqsave(&efi_runtime_lock, flags);
 
        phys_tm = virt_to_phys_or_null(tm);
        phys_tc = virt_to_phys_or_null(tc);
 
        status = efi_thunk(get_time, phys_tm, phys_tc);
 
+       spin_unlock_irqrestore(&efi_runtime_lock, flags);
        spin_unlock(&rtc_lock);
 
        return status;
@@ -719,13 +721,16 @@ static efi_status_t efi_thunk_set_time(efi_time_t *tm)
 {
        efi_status_t status;
        u32 phys_tm;
+       unsigned long flags;
 
        spin_lock(&rtc_lock);
+       spin_lock_irqsave(&efi_runtime_lock, flags);
 
        phys_tm = virt_to_phys_or_null(tm);
 
        status = efi_thunk(set_time, phys_tm);
 
+       spin_unlock_irqrestore(&efi_runtime_lock, flags);
        spin_unlock(&rtc_lock);
 
        return status;
@@ -737,8 +742,10 @@ efi_thunk_get_wakeup_time(efi_bool_t *enabled, efi_bool_t *pending,
 {
        efi_status_t status;
        u32 phys_enabled, phys_pending, phys_tm;
+       unsigned long flags;
 
        spin_lock(&rtc_lock);
+       spin_lock_irqsave(&efi_runtime_lock, flags);
 
        phys_enabled = virt_to_phys_or_null(enabled);
        phys_pending = virt_to_phys_or_null(pending);
@@ -747,6 +754,7 @@ efi_thunk_get_wakeup_time(efi_bool_t *enabled, efi_bool_t *pending,
        status = efi_thunk(get_wakeup_time, phys_enabled,
                             phys_pending, phys_tm);
 
+       spin_unlock_irqrestore(&efi_runtime_lock, flags);
        spin_unlock(&rtc_lock);
 
        return status;
@@ -757,13 +765,16 @@ efi_thunk_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
 {
        efi_status_t status;
        u32 phys_tm;
+       unsigned long flags;
 
        spin_lock(&rtc_lock);
+       spin_lock_irqsave(&efi_runtime_lock, flags);
 
        phys_tm = virt_to_phys_or_null(tm);
 
        status = efi_thunk(set_wakeup_time, enabled, phys_tm);
 
+       spin_unlock_irqrestore(&efi_runtime_lock, flags);
        spin_unlock(&rtc_lock);
 
        return status;
@@ -781,6 +792,9 @@ efi_thunk_get_variable(efi_char16_t *name, efi_guid_t *vendor,
        efi_status_t status;
        u32 phys_name, phys_vendor, phys_attr;
        u32 phys_data_size, phys_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&efi_runtime_lock, flags);
 
        phys_data_size = virt_to_phys_or_null(data_size);
        phys_vendor = virt_to_phys_or_null(vendor);
@@ -791,6 +805,8 @@ efi_thunk_get_variable(efi_char16_t *name, efi_guid_t *vendor,
        status = efi_thunk(get_variable, phys_name, phys_vendor,
                           phys_attr, phys_data_size, phys_data);
 
+       spin_unlock_irqrestore(&efi_runtime_lock, flags);
+
        return status;
 }
 
@@ -800,6 +816,34 @@ efi_thunk_set_variable(efi_char16_t *name, efi_guid_t *vendor,
 {
        u32 phys_name, phys_vendor, phys_data;
        efi_status_t status;
+       unsigned long flags;
+
+       spin_lock_irqsave(&efi_runtime_lock, flags);
+
+       phys_name = virt_to_phys_or_null_size(name, efi_name_size(name));
+       phys_vendor = virt_to_phys_or_null(vendor);
+       phys_data = virt_to_phys_or_null_size(data, data_size);
+
+       /* If data_size is > sizeof(u32) we've got problems */
+       status = efi_thunk(set_variable, phys_name, phys_vendor,
+                          attr, data_size, phys_data);
+
+       spin_unlock_irqrestore(&efi_runtime_lock, flags);
+
+       return status;
+}
+
+static efi_status_t
+efi_thunk_set_variable_nonblocking(efi_char16_t *name, efi_guid_t *vendor,
+                                  u32 attr, unsigned long data_size,
+                                  void *data)
+{
+       u32 phys_name, phys_vendor, phys_data;
+       efi_status_t status;
+       unsigned long flags;
+
+       if (!spin_trylock_irqsave(&efi_runtime_lock, flags))
+               return EFI_NOT_READY;
 
        phys_name = virt_to_phys_or_null_size(name, efi_name_size(name));
        phys_vendor = virt_to_phys_or_null(vendor);
@@ -809,6 +853,8 @@ efi_thunk_set_variable(efi_char16_t *name, efi_guid_t *vendor,
        status = efi_thunk(set_variable, phys_name, phys_vendor,
                           attr, data_size, phys_data);
 
+       spin_unlock_irqrestore(&efi_runtime_lock, flags);
+
        return status;
 }
 
@@ -819,6 +865,9 @@ efi_thunk_get_next_variable(unsigned long *name_size,
 {
        efi_status_t status;
        u32 phys_name_size, phys_name, phys_vendor;
+       unsigned long flags;
+
+       spin_lock_irqsave(&efi_runtime_lock, flags);
 
        phys_name_size = virt_to_phys_or_null(name_size);
        phys_vendor = virt_to_phys_or_null(vendor);
@@ -827,6 +876,8 @@ efi_thunk_get_next_variable(unsigned long *name_size,
        status = efi_thunk(get_next_variable, phys_name_size,
                           phys_name, phys_vendor);
 
+       spin_unlock_irqrestore(&efi_runtime_lock, flags);
+
        return status;
 }
 
@@ -835,10 +886,15 @@ efi_thunk_get_next_high_mono_count(u32 *count)
 {
        efi_status_t status;
        u32 phys_count;
+       unsigned long flags;
+
+       spin_lock_irqsave(&efi_runtime_lock, flags);
 
        phys_count = virt_to_phys_or_null(count);
        status = efi_thunk(get_next_high_mono_count, phys_count);
 
+       spin_unlock_irqrestore(&efi_runtime_lock, flags);
+
        return status;
 }
 
@@ -847,10 +903,15 @@ efi_thunk_reset_system(int reset_type, efi_status_t status,
                       unsigned long data_size, efi_char16_t *data)
 {
        u32 phys_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&efi_runtime_lock, flags);
 
        phys_data = virt_to_phys_or_null_size(data, data_size);
 
        efi_thunk(reset_system, reset_type, status, data_size, phys_data);
+
+       spin_unlock_irqrestore(&efi_runtime_lock, flags);
 }
 
 static efi_status_t
@@ -872,10 +933,13 @@ efi_thunk_query_variable_info(u32 attr, u64 *storage_space,
 {
        efi_status_t status;
        u32 phys_storage, phys_remaining, phys_max;
+       unsigned long flags;
 
        if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
                return EFI_UNSUPPORTED;
 
+       spin_lock_irqsave(&efi_runtime_lock, flags);
+
        phys_storage = virt_to_phys_or_null(storage_space);
        phys_remaining = virt_to_phys_or_null(remaining_space);
        phys_max = virt_to_phys_or_null(max_variable_size);
@@ -883,6 +947,35 @@ efi_thunk_query_variable_info(u32 attr, u64 *storage_space,
        status = efi_thunk(query_variable_info, attr, phys_storage,
                           phys_remaining, phys_max);
 
+       spin_unlock_irqrestore(&efi_runtime_lock, flags);
+
+       return status;
+}
+
+static efi_status_t
+efi_thunk_query_variable_info_nonblocking(u32 attr, u64 *storage_space,
+                                         u64 *remaining_space,
+                                         u64 *max_variable_size)
+{
+       efi_status_t status;
+       u32 phys_storage, phys_remaining, phys_max;
+       unsigned long flags;
+
+       if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
+               return EFI_UNSUPPORTED;
+
+       if (!spin_trylock_irqsave(&efi_runtime_lock, flags))
+               return EFI_NOT_READY;
+
+       phys_storage = virt_to_phys_or_null(storage_space);
+       phys_remaining = virt_to_phys_or_null(remaining_space);
+       phys_max = virt_to_phys_or_null(max_variable_size);
+
+       status = efi_thunk(query_variable_info, attr, phys_storage,
+                          phys_remaining, phys_max);
+
+       spin_unlock_irqrestore(&efi_runtime_lock, flags);
+
        return status;
 }
 
@@ -908,9 +1001,11 @@ void efi_thunk_runtime_setup(void)
        efi.get_variable = efi_thunk_get_variable;
        efi.get_next_variable = efi_thunk_get_next_variable;
        efi.set_variable = efi_thunk_set_variable;
+       efi.set_variable_nonblocking = efi_thunk_set_variable_nonblocking;
        efi.get_next_high_mono_count = efi_thunk_get_next_high_mono_count;
        efi.reset_system = efi_thunk_reset_system;
        efi.query_variable_info = efi_thunk_query_variable_info;
+       efi.query_variable_info_nonblocking = efi_thunk_query_variable_info_nonblocking;
        efi.update_capsule = efi_thunk_update_capsule;
        efi.query_capsule_caps = efi_thunk_query_capsule_caps;
 }
index 36c1f8b9f7e0c2df3dec1828e9f786f9d6c1ecfb..844d31cb8a0c7eae1dcb37ed48fa373564e83f22 100644 (file)
@@ -105,12 +105,11 @@ early_param("efi_no_storage_paranoia", setup_storage_paranoia);
 */
 void efi_delete_dummy_variable(void)
 {
-       efi.set_variable((efi_char16_t *)efi_dummy_name,
-                        &EFI_DUMMY_GUID,
-                        EFI_VARIABLE_NON_VOLATILE |
-                        EFI_VARIABLE_BOOTSERVICE_ACCESS |
-                        EFI_VARIABLE_RUNTIME_ACCESS,
-                        0, NULL);
+       efi.set_variable_nonblocking((efi_char16_t *)efi_dummy_name,
+                                    &EFI_DUMMY_GUID,
+                                    EFI_VARIABLE_NON_VOLATILE |
+                                    EFI_VARIABLE_BOOTSERVICE_ACCESS |
+                                    EFI_VARIABLE_RUNTIME_ACCESS, 0, NULL);
 }
 
 /*
@@ -249,7 +248,8 @@ void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size)
        int num_entries;
        void *new;
 
-       if (efi_mem_desc_lookup(addr, &md)) {
+       if (efi_mem_desc_lookup(addr, &md) ||
+           md.type != EFI_BOOT_SERVICES_DATA) {
                pr_err("Failed to lookup EFI memory descriptor for %pa\n", &addr);
                return;
        }
index 781a4a33755739438acb6430576f6f2221601f88..d8e159feb573f1a6cdc171bc90b5948b72cc45bd 100644 (file)
@@ -87,6 +87,18 @@ config EFI_RUNTIME_WRAPPERS
 config EFI_ARMSTUB
        bool
 
+config EFI_ARMSTUB_DTB_LOADER
+       bool "Enable the DTB loader"
+       depends on EFI_ARMSTUB
+       help
+         Select this config option to add support for the dtb= command
+         line parameter, allowing a device tree blob to be loaded into
+         memory from the EFI System Partition by the stub.
+
+         The device tree is typically provided by the platform or by
+         the bootloader, so this option is mostly for development
+         purposes only.
+
 config EFI_BOOTLOADER_CONTROL
        tristate "EFI Bootloader Control"
        depends on EFI_VARS
index 3bf0dca378a647f34e5fbc9092df224816e8f3a3..a7902fccdcfa4c5f39e42d6a4561d46a5a2a017b 100644 (file)
@@ -48,8 +48,21 @@ u64 cper_next_record_id(void)
 {
        static atomic64_t seq;
 
-       if (!atomic64_read(&seq))
-               atomic64_set(&seq, ((u64)get_seconds()) << 32);
+       if (!atomic64_read(&seq)) {
+               time64_t time = ktime_get_real_seconds();
+
+               /*
+                * This code is unlikely to still be needed in year 2106,
+                * but just in case, let's use a few more bits for timestamps
+                * after y2038 to be sure they keep increasing monotonically
+                * for the next few hundred years...
+                */
+               if (time < 0x80000000)
+                       atomic64_set(&seq, (ktime_get_real_seconds()) << 32);
+               else
+                       atomic64_set(&seq, 0x8000000000000000ull |
+                                          ktime_get_real_seconds() << 24);
+       }
 
        return atomic64_inc_return(&seq);
 }
@@ -459,7 +472,7 @@ cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata
                else
                        goto err_section_too_small;
 #if defined(CONFIG_ARM64) || defined(CONFIG_ARM)
-       } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PROC_ARM)) {
+       } else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) {
                struct cper_sec_proc_arm *arm_err = acpi_hest_get_payload(gdata);
 
                printk("%ssection_type: ARM processor error\n", newpfx);
index 232f4915223b519b3ee6580cb08354ac9b0a7016..d8a33a781a5709a69e74bb68a4218fa79f3b4e4e 100644 (file)
@@ -84,6 +84,8 @@ struct mm_struct efi_mm = {
        .mmlist                 = LIST_HEAD_INIT(efi_mm.mmlist),
 };
 
+struct workqueue_struct *efi_rts_wq;
+
 static bool disable_runtime;
 static int __init setup_noefi(char *arg)
 {
@@ -337,6 +339,18 @@ static int __init efisubsys_init(void)
        if (!efi_enabled(EFI_BOOT))
                return 0;
 
+       /*
+        * Since we process only one efi_runtime_service() at a time, an
+        * ordered workqueue (which creates only one execution context)
+        * should suffice all our needs.
+        */
+       efi_rts_wq = alloc_ordered_workqueue("efi_rts_wq", 0);
+       if (!efi_rts_wq) {
+               pr_err("Creating efi_rts_wq failed, EFI runtime services disabled.\n");
+               clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
+               return 0;
+       }
+
        /* We register the efi directory at /sys/firmware/efi */
        efi_kobj = kobject_create_and_add("efi", firmware_kobj);
        if (!efi_kobj) {
@@ -388,7 +402,7 @@ subsys_initcall(efisubsys_init);
  * and if so, populate the supplied memory descriptor with the appropriate
  * data.
  */
-int __init efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md)
+int efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md)
 {
        efi_memory_desc_t *md;
 
@@ -406,12 +420,6 @@ int __init efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md)
                u64 size;
                u64 end;
 
-               if (!(md->attribute & EFI_MEMORY_RUNTIME) &&
-                   md->type != EFI_BOOT_SERVICES_DATA &&
-                   md->type != EFI_RUNTIME_SERVICES_DATA) {
-                       continue;
-               }
-
                size = md->num_pages << EFI_PAGE_SHIFT;
                end = md->phys_addr + size;
                if (phys_addr >= md->phys_addr && phys_addr < end) {
index 1ab80e06e7c510b0ad730c2de0cbe30b4f826f48..5d06bd247d0731a652424d504293f028d291c1b8 100644 (file)
@@ -250,7 +250,10 @@ void __init efi_esrt_init(void)
                return;
 
        rc = efi_mem_desc_lookup(efi.esrt, &md);
-       if (rc < 0) {
+       if (rc < 0 ||
+           (!(md.attribute & EFI_MEMORY_RUNTIME) &&
+            md.type != EFI_BOOT_SERVICES_DATA &&
+            md.type != EFI_RUNTIME_SERVICES_DATA)) {
                pr_warn("ESRT header is not in the memory map.\n");
                return;
        }
@@ -326,7 +329,8 @@ void __init efi_esrt_init(void)
 
        end = esrt_data + size;
        pr_info("Reserving ESRT space from %pa to %pa.\n", &esrt_data, &end);
-       efi_mem_reserve(esrt_data, esrt_data_size);
+       if (md.type == EFI_BOOT_SERVICES_DATA)
+               efi_mem_reserve(esrt_data, esrt_data_size);
 
        pr_debug("esrt-init: loaded.\n");
 }
index 01a9d78ee4154702e89ab8534727dc1ab66998d4..6920033de6d411689719e64226112a19a8c8021d 100644 (file)
 
 static u64 virtmap_base = EFI_RT_VIRTUAL_BASE;
 
-efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg,
-                            void *__image, void **__fh)
-{
-       efi_file_io_interface_t *io;
-       efi_loaded_image_t *image = __image;
-       efi_file_handle_t *fh;
-       efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
-       efi_status_t status;
-       void *handle = (void *)(unsigned long)image->device_handle;
-
-       status = sys_table_arg->boottime->handle_protocol(handle,
-                                &fs_proto, (void **)&io);
-       if (status != EFI_SUCCESS) {
-               efi_printk(sys_table_arg, "Failed to handle fs_proto\n");
-               return status;
-       }
-
-       status = io->open_volume(io, &fh);
-       if (status != EFI_SUCCESS)
-               efi_printk(sys_table_arg, "Failed to open volume\n");
-
-       *__fh = fh;
-       return status;
-}
-
 void efi_char16_printk(efi_system_table_t *sys_table_arg,
                              efi_char16_t *str)
 {
@@ -202,9 +177,10 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
         * 'dtb=' unless UEFI Secure Boot is disabled.  We assume that secure
         * boot is enabled if we can't determine its state.
         */
-       if (secure_boot != efi_secureboot_mode_disabled &&
-           strstr(cmdline_ptr, "dtb=")) {
-               pr_efi(sys_table, "Ignoring DTB from command line.\n");
+       if (!IS_ENABLED(CONFIG_EFI_ARMSTUB_DTB_LOADER) ||
+            secure_boot != efi_secureboot_mode_disabled) {
+               if (strstr(cmdline_ptr, "dtb="))
+                       pr_efi(sys_table, "Ignoring DTB from command line.\n");
        } else {
                status = handle_cmdline_files(sys_table, image, cmdline_ptr,
                                              "dtb=",
index 50a9cab5a8340e542e2f8d12172bd4d500934d91..e94975f4655bdd50d1db4b4a8be728d266d7d02b 100644 (file)
@@ -413,6 +413,34 @@ static efi_status_t efi_file_close(void *handle)
        return efi_call_proto(efi_file_handle, close, handle);
 }
 
+static efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg,
+                                   efi_loaded_image_t *image,
+                                   efi_file_handle_t **__fh)
+{
+       efi_file_io_interface_t *io;
+       efi_file_handle_t *fh;
+       efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
+       efi_status_t status;
+       void *handle = (void *)(unsigned long)efi_table_attr(efi_loaded_image,
+                                                            device_handle,
+                                                            image);
+
+       status = efi_call_early(handle_protocol, handle,
+                               &fs_proto, (void **)&io);
+       if (status != EFI_SUCCESS) {
+               efi_printk(sys_table_arg, "Failed to handle fs_proto\n");
+               return status;
+       }
+
+       status = efi_call_proto(efi_file_io_interface, open_volume, io, &fh);
+       if (status != EFI_SUCCESS)
+               efi_printk(sys_table_arg, "Failed to open volume\n");
+       else
+               *__fh = fh;
+
+       return status;
+}
+
 /*
  * Parse the ASCII string 'cmdline' for EFI options, denoted by the efi=
  * option, e.g. efi=nochunk.
@@ -563,8 +591,7 @@ efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
 
                /* Only open the volume once. */
                if (!i) {
-                       status = efi_open_volume(sys_table_arg, image,
-                                                (void **)&fh);
+                       status = efi_open_volume(sys_table_arg, image, &fh);
                        if (status != EFI_SUCCESS)
                                goto free_files;
                }
index f59564b72ddcdc0fae2c438f71c0c3d414f4a627..32799cf039ef1562afc8f124ab7eb9d64342083c 100644 (file)
@@ -36,9 +36,6 @@ extern int __pure is_quiet(void);
 
 void efi_char16_printk(efi_system_table_t *, efi_char16_t *);
 
-efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, void *__image,
-                            void **__fh);
-
 unsigned long get_dram_base(efi_system_table_t *sys_table_arg);
 
 efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
index ae54870b27886b016b0924fb85004b2fc4323700..aa66cbf23512af3c6e9195cd5b3471533a8f8e42 100644 (file)
@@ -1,6 +1,15 @@
 /*
  * runtime-wrappers.c - Runtime Services function call wrappers
  *
+ * Implementation summary:
+ * -----------------------
+ * 1. When user/kernel thread requests to execute efi_runtime_service(),
+ * enqueue work to efi_rts_wq.
+ * 2. Caller thread waits for completion until the work is finished
+ * because it's dependent on the return status and execution of
+ * efi_runtime_service().
+ * For instance, get_variable() and get_next_variable().
+ *
  * Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
  *
  * Split off from arch/x86/platform/efi/efi.c
@@ -22,6 +31,9 @@
 #include <linux/mutex.h>
 #include <linux/semaphore.h>
 #include <linux/stringify.h>
+#include <linux/workqueue.h>
+#include <linux/completion.h>
+
 #include <asm/efi.h>
 
 /*
 #define __efi_call_virt(f, args...) \
        __efi_call_virt_pointer(efi.systab->runtime, f, args)
 
+/* efi_runtime_service() function identifiers */
+enum efi_rts_ids {
+       GET_TIME,
+       SET_TIME,
+       GET_WAKEUP_TIME,
+       SET_WAKEUP_TIME,
+       GET_VARIABLE,
+       GET_NEXT_VARIABLE,
+       SET_VARIABLE,
+       QUERY_VARIABLE_INFO,
+       GET_NEXT_HIGH_MONO_COUNT,
+       UPDATE_CAPSULE,
+       QUERY_CAPSULE_CAPS,
+};
+
+/*
+ * efi_runtime_work:   Details of EFI Runtime Service work
+ * @arg<1-5>:          EFI Runtime Service function arguments
+ * @status:            Status of executing EFI Runtime Service
+ * @efi_rts_id:                EFI Runtime Service function identifier
+ * @efi_rts_comp:      Struct used for handling completions
+ */
+struct efi_runtime_work {
+       void *arg1;
+       void *arg2;
+       void *arg3;
+       void *arg4;
+       void *arg5;
+       efi_status_t status;
+       struct work_struct work;
+       enum efi_rts_ids efi_rts_id;
+       struct completion efi_rts_comp;
+};
+
+/*
+ * efi_queue_work:     Queue efi_runtime_service() and wait until it's done
+ * @rts:               efi_runtime_service() function identifier
+ * @rts_arg<1-5>:      efi_runtime_service() function arguments
+ *
+ * Accesses to efi_runtime_services() are serialized by a binary
+ * semaphore (efi_runtime_lock) and caller waits until the work is
+ * finished, hence _only_ one work is queued at a time and the caller
+ * thread waits for completion.
+ */
+#define efi_queue_work(_rts, _arg1, _arg2, _arg3, _arg4, _arg5)                \
+({                                                                     \
+       struct efi_runtime_work efi_rts_work;                           \
+       efi_rts_work.status = EFI_ABORTED;                              \
+                                                                       \
+       init_completion(&efi_rts_work.efi_rts_comp);                    \
+       INIT_WORK_ONSTACK(&efi_rts_work.work, efi_call_rts);            \
+       efi_rts_work.arg1 = _arg1;                                      \
+       efi_rts_work.arg2 = _arg2;                                      \
+       efi_rts_work.arg3 = _arg3;                                      \
+       efi_rts_work.arg4 = _arg4;                                      \
+       efi_rts_work.arg5 = _arg5;                                      \
+       efi_rts_work.efi_rts_id = _rts;                                 \
+                                                                       \
+       /*                                                              \
+        * queue_work() returns 0 if work was already on queue,         \
+        * _ideally_ this should never happen.                          \
+        */                                                             \
+       if (queue_work(efi_rts_wq, &efi_rts_work.work))                 \
+               wait_for_completion(&efi_rts_work.efi_rts_comp);        \
+       else                                                            \
+               pr_err("Failed to queue work to efi_rts_wq.\n");        \
+                                                                       \
+       efi_rts_work.status;                                            \
+})
+
 void efi_call_virt_check_flags(unsigned long flags, const char *call)
 {
        unsigned long cur_flags, mismatch;
@@ -90,13 +172,98 @@ void efi_call_virt_check_flags(unsigned long flags, const char *call)
  */
 static DEFINE_SEMAPHORE(efi_runtime_lock);
 
+/*
+ * Calls the appropriate efi_runtime_service() with the appropriate
+ * arguments.
+ *
+ * Semantics followed by efi_call_rts() to understand efi_runtime_work:
+ * 1. If argument was a pointer, recast it from void pointer to original
+ * pointer type.
+ * 2. If argument was a value, recast it from void pointer to original
+ * pointer type and dereference it.
+ */
+static void efi_call_rts(struct work_struct *work)
+{
+       struct efi_runtime_work *efi_rts_work;
+       void *arg1, *arg2, *arg3, *arg4, *arg5;
+       efi_status_t status = EFI_NOT_FOUND;
+
+       efi_rts_work = container_of(work, struct efi_runtime_work, work);
+       arg1 = efi_rts_work->arg1;
+       arg2 = efi_rts_work->arg2;
+       arg3 = efi_rts_work->arg3;
+       arg4 = efi_rts_work->arg4;
+       arg5 = efi_rts_work->arg5;
+
+       switch (efi_rts_work->efi_rts_id) {
+       case GET_TIME:
+               status = efi_call_virt(get_time, (efi_time_t *)arg1,
+                                      (efi_time_cap_t *)arg2);
+               break;
+       case SET_TIME:
+               status = efi_call_virt(set_time, (efi_time_t *)arg1);
+               break;
+       case GET_WAKEUP_TIME:
+               status = efi_call_virt(get_wakeup_time, (efi_bool_t *)arg1,
+                                      (efi_bool_t *)arg2, (efi_time_t *)arg3);
+               break;
+       case SET_WAKEUP_TIME:
+               status = efi_call_virt(set_wakeup_time, *(efi_bool_t *)arg1,
+                                      (efi_time_t *)arg2);
+               break;
+       case GET_VARIABLE:
+               status = efi_call_virt(get_variable, (efi_char16_t *)arg1,
+                                      (efi_guid_t *)arg2, (u32 *)arg3,
+                                      (unsigned long *)arg4, (void *)arg5);
+               break;
+       case GET_NEXT_VARIABLE:
+               status = efi_call_virt(get_next_variable, (unsigned long *)arg1,
+                                      (efi_char16_t *)arg2,
+                                      (efi_guid_t *)arg3);
+               break;
+       case SET_VARIABLE:
+               status = efi_call_virt(set_variable, (efi_char16_t *)arg1,
+                                      (efi_guid_t *)arg2, *(u32 *)arg3,
+                                      *(unsigned long *)arg4, (void *)arg5);
+               break;
+       case QUERY_VARIABLE_INFO:
+               status = efi_call_virt(query_variable_info, *(u32 *)arg1,
+                                      (u64 *)arg2, (u64 *)arg3, (u64 *)arg4);
+               break;
+       case GET_NEXT_HIGH_MONO_COUNT:
+               status = efi_call_virt(get_next_high_mono_count, (u32 *)arg1);
+               break;
+       case UPDATE_CAPSULE:
+               status = efi_call_virt(update_capsule,
+                                      (efi_capsule_header_t **)arg1,
+                                      *(unsigned long *)arg2,
+                                      *(unsigned long *)arg3);
+               break;
+       case QUERY_CAPSULE_CAPS:
+               status = efi_call_virt(query_capsule_caps,
+                                      (efi_capsule_header_t **)arg1,
+                                      *(unsigned long *)arg2, (u64 *)arg3,
+                                      (int *)arg4);
+               break;
+       default:
+               /*
+                * Ideally, we should never reach here because a caller of this
+                * function should have put the right efi_runtime_service()
+                * function identifier into efi_rts_work->efi_rts_id
+                */
+               pr_err("Requested executing invalid EFI Runtime Service.\n");
+       }
+       efi_rts_work->status = status;
+       complete(&efi_rts_work->efi_rts_comp);
+}
+
 static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
 {
        efi_status_t status;
 
        if (down_interruptible(&efi_runtime_lock))
                return EFI_ABORTED;
-       status = efi_call_virt(get_time, tm, tc);
+       status = efi_queue_work(GET_TIME, tm, tc, NULL, NULL, NULL);
        up(&efi_runtime_lock);
        return status;
 }
@@ -107,7 +274,7 @@ static efi_status_t virt_efi_set_time(efi_time_t *tm)
 
        if (down_interruptible(&efi_runtime_lock))
                return EFI_ABORTED;
-       status = efi_call_virt(set_time, tm);
+       status = efi_queue_work(SET_TIME, tm, NULL, NULL, NULL, NULL);
        up(&efi_runtime_lock);
        return status;
 }
@@ -120,7 +287,8 @@ static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled,
 
        if (down_interruptible(&efi_runtime_lock))
                return EFI_ABORTED;
-       status = efi_call_virt(get_wakeup_time, enabled, pending, tm);
+       status = efi_queue_work(GET_WAKEUP_TIME, enabled, pending, tm, NULL,
+                               NULL);
        up(&efi_runtime_lock);
        return status;
 }
@@ -131,7 +299,8 @@ static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
 
        if (down_interruptible(&efi_runtime_lock))
                return EFI_ABORTED;
-       status = efi_call_virt(set_wakeup_time, enabled, tm);
+       status = efi_queue_work(SET_WAKEUP_TIME, &enabled, tm, NULL, NULL,
+                               NULL);
        up(&efi_runtime_lock);
        return status;
 }
@@ -146,8 +315,8 @@ static efi_status_t virt_efi_get_variable(efi_char16_t *name,
 
        if (down_interruptible(&efi_runtime_lock))
                return EFI_ABORTED;
-       status = efi_call_virt(get_variable, name, vendor, attr, data_size,
-                              data);
+       status = efi_queue_work(GET_VARIABLE, name, vendor, attr, data_size,
+                               data);
        up(&efi_runtime_lock);
        return status;
 }
@@ -160,7 +329,8 @@ static efi_status_t virt_efi_get_next_variable(unsigned long *name_size,
 
        if (down_interruptible(&efi_runtime_lock))
                return EFI_ABORTED;
-       status = efi_call_virt(get_next_variable, name_size, name, vendor);
+       status = efi_queue_work(GET_NEXT_VARIABLE, name_size, name, vendor,
+                               NULL, NULL);
        up(&efi_runtime_lock);
        return status;
 }
@@ -175,8 +345,8 @@ static efi_status_t virt_efi_set_variable(efi_char16_t *name,
 
        if (down_interruptible(&efi_runtime_lock))
                return EFI_ABORTED;
-       status = efi_call_virt(set_variable, name, vendor, attr, data_size,
-                              data);
+       status = efi_queue_work(SET_VARIABLE, name, vendor, &attr, &data_size,
+                               data);
        up(&efi_runtime_lock);
        return status;
 }
@@ -210,8 +380,8 @@ static efi_status_t virt_efi_query_variable_info(u32 attr,
 
        if (down_interruptible(&efi_runtime_lock))
                return EFI_ABORTED;
-       status = efi_call_virt(query_variable_info, attr, storage_space,
-                              remaining_space, max_variable_size);
+       status = efi_queue_work(QUERY_VARIABLE_INFO, &attr, storage_space,
+                               remaining_space, max_variable_size, NULL);
        up(&efi_runtime_lock);
        return status;
 }
@@ -242,7 +412,8 @@ static efi_status_t virt_efi_get_next_high_mono_count(u32 *count)
 
        if (down_interruptible(&efi_runtime_lock))
                return EFI_ABORTED;
-       status = efi_call_virt(get_next_high_mono_count, count);
+       status = efi_queue_work(GET_NEXT_HIGH_MONO_COUNT, count, NULL, NULL,
+                               NULL, NULL);
        up(&efi_runtime_lock);
        return status;
 }
@@ -272,7 +443,8 @@ static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules,
 
        if (down_interruptible(&efi_runtime_lock))
                return EFI_ABORTED;
-       status = efi_call_virt(update_capsule, capsules, count, sg_list);
+       status = efi_queue_work(UPDATE_CAPSULE, capsules, &count, &sg_list,
+                               NULL, NULL);
        up(&efi_runtime_lock);
        return status;
 }
@@ -289,8 +461,8 @@ static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules,
 
        if (down_interruptible(&efi_runtime_lock))
                return EFI_ABORTED;
-       status = efi_call_virt(query_capsule_caps, capsules, count, max_size,
-                              reset_type);
+       status = efi_queue_work(QUERY_CAPSULE_CAPS, capsules, &count,
+                               max_size, reset_type, NULL);
        up(&efi_runtime_lock);
        return status;
 }
index 46a4484e3da79196b32c06cfbd3d0f092d03147c..c6f78d27947b9dae5f00b148c325198956910095 100644 (file)
@@ -20,7 +20,7 @@
 #include <drm/drm_connector.h>  /* For DRM_MODE_PANEL_ORIENTATION_* */
 
 static bool request_mem_succeeded = false;
-static bool nowc = false;
+static u64 mem_flags = EFI_MEMORY_WC | EFI_MEMORY_UC;
 
 static struct fb_var_screeninfo efifb_defined = {
        .activate               = FB_ACTIVATE_NOW,
@@ -68,8 +68,12 @@ static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green,
 
 static void efifb_destroy(struct fb_info *info)
 {
-       if (info->screen_base)
-               iounmap(info->screen_base);
+       if (info->screen_base) {
+               if (mem_flags & (EFI_MEMORY_UC | EFI_MEMORY_WC))
+                       iounmap(info->screen_base);
+               else
+                       memunmap(info->screen_base);
+       }
        if (request_mem_succeeded)
                release_mem_region(info->apertures->ranges[0].base,
                                   info->apertures->ranges[0].size);
@@ -104,7 +108,7 @@ static int efifb_setup(char *options)
                        else if (!strncmp(this_opt, "width:", 6))
                                screen_info.lfb_width = simple_strtoul(this_opt+6, NULL, 0);
                        else if (!strcmp(this_opt, "nowc"))
-                               nowc = true;
+                               mem_flags &= ~EFI_MEMORY_WC;
                }
        }
 
@@ -164,6 +168,7 @@ static int efifb_probe(struct platform_device *dev)
        unsigned int size_remap;
        unsigned int size_total;
        char *option = NULL;
+       efi_memory_desc_t md;
 
        if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI || pci_dev_disabled)
                return -ENODEV;
@@ -272,12 +277,35 @@ static int efifb_probe(struct platform_device *dev)
        info->apertures->ranges[0].base = efifb_fix.smem_start;
        info->apertures->ranges[0].size = size_remap;
 
-       if (nowc)
-               info->screen_base = ioremap(efifb_fix.smem_start, efifb_fix.smem_len);
-       else
-               info->screen_base = ioremap_wc(efifb_fix.smem_start, efifb_fix.smem_len);
+       if (!efi_mem_desc_lookup(efifb_fix.smem_start, &md)) {
+               if ((efifb_fix.smem_start + efifb_fix.smem_len) >
+                   (md.phys_addr + (md.num_pages << EFI_PAGE_SHIFT))) {
+                       pr_err("efifb: video memory @ 0x%lx spans multiple EFI memory regions\n",
+                              efifb_fix.smem_start);
+                       err = -EIO;
+                       goto err_release_fb;
+               }
+               /*
+                * If the UEFI memory map covers the efifb region, we may only
+                * remap it using the attributes the memory map prescribes.
+                */
+               mem_flags |= EFI_MEMORY_WT | EFI_MEMORY_WB;
+               mem_flags &= md.attribute;
+       }
+       if (mem_flags & EFI_MEMORY_WC)
+               info->screen_base = ioremap_wc(efifb_fix.smem_start,
+                                              efifb_fix.smem_len);
+       else if (mem_flags & EFI_MEMORY_UC)
+               info->screen_base = ioremap(efifb_fix.smem_start,
+                                           efifb_fix.smem_len);
+       else if (mem_flags & EFI_MEMORY_WT)
+               info->screen_base = memremap(efifb_fix.smem_start,
+                                            efifb_fix.smem_len, MEMREMAP_WT);
+       else if (mem_flags & EFI_MEMORY_WB)
+               info->screen_base = memremap(efifb_fix.smem_start,
+                                            efifb_fix.smem_len, MEMREMAP_WB);
        if (!info->screen_base) {
-               pr_err("efifb: abort, cannot ioremap video memory 0x%x @ 0x%lx\n",
+               pr_err("efifb: abort, cannot remap video memory 0x%x @ 0x%lx\n",
                        efifb_fix.smem_len, efifb_fix.smem_start);
                err = -EIO;
                goto err_release_fb;
@@ -371,7 +399,10 @@ err_fb_dealoc:
 err_groups:
        sysfs_remove_groups(&dev->dev.kobj, efifb_groups);
 err_unmap:
-       iounmap(info->screen_base);
+       if (mem_flags & (EFI_MEMORY_UC | EFI_MEMORY_WC))
+               iounmap(info->screen_base);
+       else
+               memunmap(info->screen_base);
 err_release_fb:
        framebuffer_release(info);
 err_release_mem:
index 71fccccf317e8849580457680d6bd6ac3376c170..8c6ab6c95727ef219a9cb02845f1bb3e7046ad4d 100644 (file)
@@ -86,7 +86,9 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry,
        /* length of the variable name itself: remove GUID and separator */
        namelen = dentry->d_name.len - EFI_VARIABLE_GUID_LEN - 1;
 
-       uuid_le_to_bin(dentry->d_name.name + namelen + 1, &var->var.VendorGuid);
+       err = guid_parse(dentry->d_name.name + namelen + 1, &var->var.VendorGuid);
+       if (err)
+               goto out;
 
        if (efivar_variable_is_removable(var->var.VendorGuid,
                                         dentry->d_name.name, namelen))
index 56add823f1909e28c9e46775f12303c48096a13a..401e4b254e30b06a9b19e826bd289c893c0cfe86 100644 (file)
@@ -894,6 +894,16 @@ typedef struct _efi_file_handle {
        void *flush;
 } efi_file_handle_t;
 
+typedef struct {
+       u64 revision;
+       u32 open_volume;
+} efi_file_io_interface_32_t;
+
+typedef struct {
+       u64 revision;
+       u64 open_volume;
+} efi_file_io_interface_64_t;
+
 typedef struct _efi_file_io_interface {
        u64 revision;
        int (*open_volume)(struct _efi_file_io_interface *,
@@ -988,14 +998,12 @@ extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg);
 extern void efi_gettimeofday (struct timespec64 *ts);
 extern void efi_enter_virtual_mode (void);     /* switch EFI to virtual mode, if possible */
 #ifdef CONFIG_X86
-extern void efi_late_init(void);
 extern void efi_free_boot_services(void);
 extern efi_status_t efi_query_variable_store(u32 attributes,
                                             unsigned long size,
                                             bool nonblocking);
 extern void efi_find_mirror(void);
 #else
-static inline void efi_late_init(void) {}
 static inline void efi_free_boot_services(void) {}
 
 static inline efi_status_t efi_query_variable_store(u32 attributes,
@@ -1651,4 +1659,7 @@ struct linux_efi_tpm_eventlog {
 
 extern int efi_tpm_eventlog_init(void);
 
+/* Workqueue to queue EFI Runtime Services */
+extern struct workqueue_struct *efi_rts_wq;
+
 #endif /* _LINUX_EFI_H */