]> Git Repo - linux.git/commitdiff
Merge branch 'x86-efi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <[email protected]>
Tue, 5 Aug 2014 00:13:50 +0000 (17:13 -0700)
committerLinus Torvalds <[email protected]>
Tue, 5 Aug 2014 00:13:50 +0000 (17:13 -0700)
Pull EFI changes from Ingo Molnar:
 "Main changes in this cycle are:

   - arm64 efi stub fixes, preservation of FP/SIMD registers across
     firmware calls, and conversion of the EFI stub code into a static
     library - Ard Biesheuvel

   - Xen EFI support - Daniel Kiper

   - Support for autoloading the efivars driver - Lee, Chun-Yi

   - Use the PE/COFF headers in the x86 EFI boot stub to request that
     the stub be loaded with CONFIG_PHYSICAL_ALIGN alignment - Michael
     Brown

   - Consolidate all the x86 EFI quirks into one file - Saurabh Tangri

   - Additional error logging in x86 EFI boot stub - Ulf Winkelvos

   - Support loading initrd above 4G in EFI boot stub - Yinghai Lu

   - EFI reboot patches for ACPI hardware reduced platforms"

* 'x86-efi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (31 commits)
  efi/arm64: Handle missing virtual mapping for UEFI System Table
  arch/x86/xen: Silence compiler warnings
  xen: Silence compiler warnings
  x86/efi: Request desired alignment via the PE/COFF headers
  x86/efi: Add better error logging to EFI boot stub
  efi: Autoload efivars
  efi: Update stale locking comment for struct efivars
  arch/x86: Remove efi_set_rtc_mmss()
  arch/x86: Replace plain strings with constants
  xen: Put EFI machinery in place
  xen: Define EFI related stuff
  arch/x86: Remove redundant set_bit(EFI_MEMMAP) call
  arch/x86: Remove redundant set_bit(EFI_SYSTEM_TABLES) call
  efi: Introduce EFI_PARAVIRT flag
  arch/x86: Do not access EFI memory map if it is not available
  efi: Use early_mem*() instead of early_io*()
  arch/ia64: Define early_memunmap()
  x86/reboot: Add EFI reboot quirk for ACPI Hardware Reduced flag
  efi/reboot: Allow powering off machines using EFI
  efi/reboot: Add generic wrapper around EfiResetSystem()
  ...

1  2 
arch/arm64/Kconfig
arch/arm64/Makefile
arch/arm64/kernel/Makefile
arch/x86/Kconfig
arch/x86/boot/header.S
arch/x86/xen/enlighten.c
arch/x86/xen/xen-ops.h
drivers/firmware/efi/efi.c
drivers/firmware/efi/libstub/fdt.c

diff --combined arch/arm64/Kconfig
index f3b584be76d7195b14908846e0c00dab097a179e,3a0a4ce4c7518273dddf14cc6453ac7a5efb0dd2..b0f9c9db95903f1368540a7678d2294a6dd773c5
@@@ -1,17 -1,14 +1,17 @@@
  config ARM64
        def_bool y
        select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
 -      select ARCH_USE_CMPXCHG_LOCKREF
        select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
 +      select ARCH_USE_CMPXCHG_LOCKREF
 +      select ARCH_SUPPORTS_ATOMIC_RMW
        select ARCH_WANT_OPTIONAL_GPIOLIB
        select ARCH_WANT_COMPAT_IPC_PARSE_VERSION
        select ARCH_WANT_FRAME_POINTERS
        select ARM_AMBA
        select ARM_ARCH_TIMER
        select ARM_GIC
 +      select AUDIT_ARCH_COMPAT_GENERIC
 +      select ARM_GIC_V3
        select BUILDTIME_EXTABLE_SORT
        select CLONE_BACKWARDS
        select COMMON_CLK
        select GENERIC_STRNLEN_USER
        select GENERIC_TIME_VSYSCALL
        select HARDIRQS_SW_RESEND
 +      select HAVE_ARCH_AUDITSYSCALL
        select HAVE_ARCH_JUMP_LABEL
        select HAVE_ARCH_KGDB
        select HAVE_ARCH_TRACEHOOK
        select HAVE_C_RECORDMCOUNT
 +      select HAVE_CC_STACKPROTECTOR
        select HAVE_DEBUG_BUGVERBOSE
        select HAVE_DEBUG_KMEMLEAK
        select HAVE_DMA_API_DEBUG
@@@ -66,7 -61,6 +66,7 @@@
        select RTC_LIB
        select SPARSE_IRQ
        select SYSCTL_EXCEPTION_TRACE
 +      select HAVE_CONTEXT_TRACKING
        help
          ARM 64-bit (AArch64) Linux support.
  
@@@ -159,63 -153,14 +159,63 @@@ endmen
  
  menu "Kernel Features"
  
 +choice
 +      prompt "Page size"
 +      default ARM64_4K_PAGES
 +      help
 +        Page size (translation granule) configuration.
 +
 +config ARM64_4K_PAGES
 +      bool "4KB"
 +      help
 +        This feature enables 4KB pages support.
 +
  config ARM64_64K_PAGES
 -      bool "Enable 64KB pages support"
 +      bool "64KB"
        help
          This feature enables 64KB pages support (4KB by default)
          allowing only two levels of page tables and faster TLB
          look-up. AArch32 emulation is not available when this feature
          is enabled.
  
 +endchoice
 +
 +choice
 +      prompt "Virtual address space size"
 +      default ARM64_VA_BITS_39 if ARM64_4K_PAGES
 +      default ARM64_VA_BITS_42 if ARM64_64K_PAGES
 +      help
 +        Allows choosing one of multiple possible virtual address
 +        space sizes. The level of translation table is determined by
 +        a combination of page size and virtual address space size.
 +
 +config ARM64_VA_BITS_39
 +      bool "39-bit"
 +      depends on ARM64_4K_PAGES
 +
 +config ARM64_VA_BITS_42
 +      bool "42-bit"
 +      depends on ARM64_64K_PAGES
 +
 +config ARM64_VA_BITS_48
 +      bool "48-bit"
 +      depends on BROKEN
 +
 +endchoice
 +
 +config ARM64_VA_BITS
 +      int
 +      default 39 if ARM64_VA_BITS_39
 +      default 42 if ARM64_VA_BITS_42
 +      default 48 if ARM64_VA_BITS_48
 +
 +config ARM64_PGTABLE_LEVELS
 +      int
 +      default 2 if ARM64_64K_PAGES && ARM64_VA_BITS_42
 +      default 3 if ARM64_64K_PAGES && ARM64_VA_BITS_48
 +      default 3 if ARM64_4K_PAGES && ARM64_VA_BITS_39
 +      default 4 if ARM64_4K_PAGES && ARM64_VA_BITS_48
 +
  config CPU_BIG_ENDIAN
         bool "Build big-endian kernel"
         help
@@@ -347,12 -292,18 +347,18 @@@ config CMDLINE_FORC
          This is useful if you cannot or don't want to change the
          command-line options your boot loader passes to the kernel.
  
+ config EFI_STUB
+       bool
  config EFI
        bool "UEFI runtime support"
        depends on OF && !CPU_BIG_ENDIAN
        select LIBFDT
        select UCS2_STRING
        select EFI_PARAMS_FROM_FDT
+       select EFI_RUNTIME_WRAPPERS
+       select EFI_STUB
+       select EFI_ARMSTUB
        default y
        help
          This option provides support for runtime services provided
diff --combined arch/arm64/Makefile
index e8d025c1459e034ddaa11efaf11e8da31808e365,5836717d2f6654c4ccdf1e9b1b1358b04a3f7a75..57833546bf003b5f8ffe5e70fb65c10c8dd1ef55
@@@ -38,11 -38,7 +38,11 @@@ CHECKFLAGS  += -D__aarch64_
  head-y                := arch/arm64/kernel/head.o
  
  # The byte offset of the kernel image in RAM from the start of RAM.
 +ifeq ($(CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET), y)
 +TEXT_OFFSET := $(shell awk 'BEGIN {srand(); printf "0x%04x0\n", int(65535 * rand())}')
 +else
  TEXT_OFFSET := 0x00080000
 +endif
  
  export        TEXT_OFFSET GZFLAGS
  
@@@ -52,6 -48,7 +52,7 @@@ core-$(CONFIG_XEN) += arch/arm64/xen
  core-$(CONFIG_CRYPTO) += arch/arm64/crypto/
  libs-y                := arch/arm64/lib/ $(libs-y)
  libs-y                += $(LIBGCC)
+ libs-$(CONFIG_EFI_STUB) += drivers/firmware/efi/libstub/
  
  # Default target when executing plain make
  KBUILD_IMAGE  := Image.gz
index 27c72ef4fd7a1725432ae9c18f35096beb14065d,afaeb734295afc8efc8111fb475f35437edb2298..df7ef8768fc25eeb6557e7cdb229483faef05699
@@@ -4,8 -4,7 +4,7 @@@
  
  CPPFLAGS_vmlinux.lds  := -DTEXT_OFFSET=$(TEXT_OFFSET)
  AFLAGS_head.o         := -DTEXT_OFFSET=$(TEXT_OFFSET)
- CFLAGS_efi-stub.o     := -DTEXT_OFFSET=$(TEXT_OFFSET) \
-                          -I$(src)/../../../scripts/dtc/libfdt
+ CFLAGS_efi-stub.o     := -DTEXT_OFFSET=$(TEXT_OFFSET)
  
  CFLAGS_REMOVE_ftrace.o = -pg
  CFLAGS_REMOVE_insn.o = -pg
@@@ -15,8 -14,7 +14,8 @@@ CFLAGS_REMOVE_return_address.o = -p
  arm64-obj-y           := cputable.o debug-monitors.o entry.o irq.o fpsimd.o   \
                           entry-fpsimd.o process.o ptrace.o setup.o signal.o   \
                           sys.o stacktrace.o time.o traps.o io.o vdso.o        \
 -                         hyp-stub.o psci.o cpu_ops.o insn.o return_address.o
 +                         hyp-stub.o psci.o cpu_ops.o insn.o return_address.o  \
 +                         cpuinfo.o
  
  arm64-obj-$(CONFIG_COMPAT)            += sys32.o kuser32.o signal32.o         \
                                           sys_compat.o
diff --combined arch/x86/Kconfig
index 2840c27d44790cdc55faf2695ff171649d1fcbeb,801ed36c2e497a2aafdc4c5dde98a75f135fff6b..3fc7d724d0a3678421b8783c05b40ff33913a4fa
@@@ -54,6 -54,7 +54,6 @@@ config X8
        select HAVE_FUNCTION_TRACER
        select HAVE_FUNCTION_GRAPH_TRACER
        select HAVE_FUNCTION_GRAPH_FP_TEST
 -      select HAVE_FUNCTION_TRACE_MCOUNT_TEST
        select HAVE_SYSCALL_TRACEPOINTS
        select SYSCTL_EXCEPTION_TRACE
        select HAVE_KVM
        select HAVE_CC_STACKPROTECTOR
        select GENERIC_CPU_AUTOPROBE
        select HAVE_ARCH_AUDITSYSCALL
 +      select ARCH_SUPPORTS_ATOMIC_RMW
  
  config INSTRUCTION_DECODER
        def_bool y
@@@ -1522,6 -1522,7 +1522,7 @@@ config EF
        bool "EFI runtime service support"
        depends on ACPI
        select UCS2_STRING
+       select EFI_RUNTIME_WRAPPERS
        ---help---
          This enables the kernel to use EFI runtime services that are
          available (such as the EFI variable services).
@@@ -1672,6 -1673,7 +1673,6 @@@ config RELOCATABL
  config RANDOMIZE_BASE
        bool "Randomize the address of the kernel image"
        depends on RELOCATABLE
 -      depends on !HIBERNATION
        default n
        ---help---
           Randomizes the physical and virtual address at which the
diff --combined arch/x86/boot/header.S
index 7a6d43a554d7789316c9980080eaad17026105ae,1fdb350c4a58e9c0c385dbb4b00be4c2064132f9..16ef02596db2daf1fa8eadd9c17fd994ec3c21b3
@@@ -91,9 -91,10 +91,9 @@@ bs_die
  
        .section ".bsdata", "a"
  bugger_off_msg:
 -      .ascii  "Direct floppy boot is not supported. "
 -      .ascii  "Use a boot loader program instead.\r\n"
 +      .ascii  "Use a boot loader.\r\n"
        .ascii  "\n"
 -      .ascii  "Remove disk and press any key to reboot ...\r\n"
 +      .ascii  "Remove disk and press any key to reboot...\r\n"
        .byte   0
  
  #ifdef CONFIG_EFI_STUB
@@@ -107,7 -108,7 +107,7 @@@ coff_header
  #else
        .word   0x8664                          # x86-64
  #endif
 -      .word   3                               # nr_sections
 +      .word   4                               # nr_sections
        .long   0                               # TimeDateStamp
        .long   0                               # PointerToSymbolTable
        .long   1                               # NumberOfSymbols
@@@ -154,7 -155,7 +154,7 @@@ extra_header_fields
  #else
        .quad   0                               # ImageBase
  #endif
-       .long   0x20                            # SectionAlignment
+       .long   CONFIG_PHYSICAL_ALIGN           # SectionAlignment
        .long   0x20                            # FileAlignment
        .word   0                               # MajorOperatingSystemVersion
        .word   0                               # MinorOperatingSystemVersion
@@@ -249,25 -250,6 +249,25 @@@ section_table
        .word   0                               # NumberOfLineNumbers
        .long   0x60500020                      # Characteristics (section flags)
  
 +      #
 +      # The offset & size fields are filled in by build.c.
 +      #
 +      .ascii  ".bss"
 +      .byte   0
 +      .byte   0
 +      .byte   0
 +      .byte   0
 +      .long   0
 +      .long   0x0
 +      .long   0                               # Size of initialized data
 +                                              # on disk
 +      .long   0x0
 +      .long   0                               # PointerToRelocations
 +      .long   0                               # PointerToLineNumbers
 +      .word   0                               # NumberOfRelocations
 +      .word   0                               # NumberOfLineNumbers
 +      .long   0xc8000080                      # Characteristics (section flags)
 +
  #endif /* CONFIG_EFI_STUB */
  
        # Kernel attributes; used by setup.  This is part 1 of the
diff --combined arch/x86/xen/enlighten.c
index ffb101e457310e578e6b7c5b6a603a52d3571dc8,2cd0463dd262c4490a28c3bea5b5b2d4a718f2ee..94813515fdd66f4685a5dc632b346551536dd125
@@@ -1537,10 -1537,7 +1537,10 @@@ asmlinkage __visible void __init xen_st
        if (!xen_pvh_domain())
                pv_cpu_ops = xen_cpu_ops;
  
 -      x86_init.resources.memory_setup = xen_memory_setup;
 +      if (xen_feature(XENFEAT_auto_translated_physmap))
 +              x86_init.resources.memory_setup = xen_auto_xlated_memory_setup;
 +      else
 +              x86_init.resources.memory_setup = xen_memory_setup;
        x86_init.oem.arch_setup = xen_arch_setup;
        x86_init.oem.banner = xen_banner;
  
  
        xen_setup_runstate_info(0);
  
+       xen_efi_init();
        /* Start the world */
  #ifdef CONFIG_X86_32
        i386_start_kernel();
diff --combined arch/x86/xen/xen-ops.h
index 97d87659f77964946e103a83f654c0169ddf5885,75f98fe5a53187e78c4f4c77cf9215381e1635b9..28c7e0be56e424632950df56612dce34645599b0
@@@ -36,7 -36,6 +36,7 @@@ void xen_mm_unpin_all(void)
  void xen_set_pat(u64);
  
  char * __init xen_memory_setup(void);
 +char * xen_auto_xlated_memory_setup(void);
  void __init xen_arch_setup(void);
  void xen_enable_sysenter(void);
  void xen_enable_syscall(void);
@@@ -105,6 -104,14 +105,14 @@@ static inline void __init xen_init_apic
  }
  #endif
  
+ #ifdef CONFIG_XEN_EFI
+ extern void xen_efi_init(void);
+ #else
+ static inline void __init xen_efi_init(void)
+ {
+ }
+ #endif
  /* Declare an asm function, along with symbols needed to make it
     inlineable */
  #define DECL_ASM(ret, name, ...)              \
index dc79346689e6040dfe127b609d99655da079d26a,36ffa1747e8463149e5be0810567d9ca6b91fdad..64ecbb501c5080df5e36b90dd73501b7dac881d4
@@@ -23,6 -23,7 +23,7 @@@
  #include <linux/of.h>
  #include <linux/of_fdt.h>
  #include <linux/io.h>
+ #include <linux/platform_device.h>
  
  struct efi __read_mostly efi = {
        .mps        = EFI_INVALID_TABLE_ADDR,
@@@ -104,16 -105,19 +105,19 @@@ static struct attribute *efi_subsys_att
  static umode_t efi_attr_is_visible(struct kobject *kobj,
                                   struct attribute *attr, int n)
  {
-       umode_t mode = attr->mode;
-       if (attr == &efi_attr_fw_vendor.attr)
-               return (efi.fw_vendor == EFI_INVALID_TABLE_ADDR) ? 0 : mode;
-       else if (attr == &efi_attr_runtime.attr)
-               return (efi.runtime == EFI_INVALID_TABLE_ADDR) ? 0 : mode;
-       else if (attr == &efi_attr_config_table.attr)
-               return (efi.config_table == EFI_INVALID_TABLE_ADDR) ? 0 : mode;
+       if (attr == &efi_attr_fw_vendor.attr) {
+               if (efi_enabled(EFI_PARAVIRT) ||
+                               efi.fw_vendor == EFI_INVALID_TABLE_ADDR)
+                       return 0;
+       } else if (attr == &efi_attr_runtime.attr) {
+               if (efi.runtime == EFI_INVALID_TABLE_ADDR)
+                       return 0;
+       } else if (attr == &efi_attr_config_table.attr) {
+               if (efi.config_table == EFI_INVALID_TABLE_ADDR)
+                       return 0;
+       }
  
-       return mode;
+       return attr->mode;
  }
  
  static struct attribute_group efi_subsys_attr_group = {
@@@ -298,7 -302,7 +302,7 @@@ int __init efi_config_init(efi_config_t
                        if (table64 >> 32) {
                                pr_cont("\n");
                                pr_err("Table located above 4GB, disabling EFI.\n");
-                               early_iounmap(config_tables,
+                               early_memunmap(config_tables,
                                               efi.systab->nr_tables * sz);
                                return -EINVAL;
                        }
                tablep += sz;
        }
        pr_cont("\n");
-       early_iounmap(config_tables, efi.systab->nr_tables * sz);
+       early_memunmap(config_tables, efi.systab->nr_tables * sz);
  
        set_bit(EFI_CONFIG_TABLES, &efi.flags);
  
        return 0;
  }
  
+ #ifdef CONFIG_EFI_VARS_MODULE
+ static int __init efi_load_efivars(void)
+ {
+       struct platform_device *pdev;
+       if (!efi_enabled(EFI_RUNTIME_SERVICES))
+               return 0;
+       pdev = platform_device_register_simple("efivars", 0, NULL, 0);
+       return IS_ERR(pdev) ? PTR_ERR(pdev) : 0;
+ }
+ device_initcall(efi_load_efivars);
+ #endif
  #ifdef CONFIG_EFI_PARAMS_FROM_FDT
  
  #define UEFI_PARAM(name, prop, field)                    \
@@@ -346,7 -364,6 +364,7 @@@ static __initdata struct 
  
  struct param_info {
        int verbose;
 +      int found;
        void *params;
  };
  
@@@ -354,21 -371,25 +372,21 @@@ static int __init fdt_find_uefi_params(
                                       int depth, void *data)
  {
        struct param_info *info = data;
 -      void *prop, *dest;
 -      unsigned long len;
 +      const void *prop;
 +      void *dest;
        u64 val;
 -      int i;
 +      int i, len;
  
        if (depth != 1 ||
            (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0))
                return 0;
  
 -      pr_info("Getting parameters from FDT:\n");
 -
        for (i = 0; i < ARRAY_SIZE(dt_params); i++) {
                prop = of_get_flat_dt_prop(node, dt_params[i].propname, &len);
 -              if (!prop) {
 -                      pr_err("Can't find %s in device tree!\n",
 -                             dt_params[i].name);
 +              if (!prop)
                        return 0;
 -              }
                dest = info->params + dt_params[i].offset;
 +              info->found++;
  
                val = of_read_number(prop, len / sizeof(u32));
  
  int __init efi_get_fdt_params(struct efi_fdt_params *params, int verbose)
  {
        struct param_info info;
 +      int ret;
 +
 +      pr_info("Getting EFI parameters from FDT:\n");
  
        info.verbose = verbose;
 +      info.found = 0;
        info.params = params;
  
 -      return of_scan_flat_dt(fdt_find_uefi_params, &info);
 +      ret = of_scan_flat_dt(fdt_find_uefi_params, &info);
 +      if (!info.found)
 +              pr_info("UEFI not found.\n");
 +      else if (!ret)
 +              pr_err("Can't find '%s' in device tree!\n",
 +                     dt_params[info.found].name);
 +
 +      return ret;
  }
  #endif /* CONFIG_EFI_PARAMS_FROM_FDT */
index 0000000000000000000000000000000000000000,86d2934840e2c1a4766afdf782a696d6ab2e60f7..a56bb3528755377b8fd6cb29dbd5fcb85692a55d
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,279 +1,279 @@@
 -              const char *type, *name;
+ /*
+  * FDT related Helper functions used by the EFI stub on multiple
+  * architectures. This should be #included by the EFI stub
+  * implementation files.
+  *
+  * Copyright 2013 Linaro Limited; author Roy Franz
+  *
+  * This file is part of the Linux kernel, and is made available
+  * under the terms of the GNU General Public License version 2.
+  *
+  */
+ #include <linux/efi.h>
+ #include <linux/libfdt.h>
+ #include <asm/efi.h>
+ efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,
+                       unsigned long orig_fdt_size,
+                       void *fdt, int new_fdt_size, char *cmdline_ptr,
+                       u64 initrd_addr, u64 initrd_size,
+                       efi_memory_desc_t *memory_map,
+                       unsigned long map_size, unsigned long desc_size,
+                       u32 desc_ver)
+ {
+       int node, prev;
+       int status;
+       u32 fdt_val32;
+       u64 fdt_val64;
+       /* Do some checks on provided FDT, if it exists*/
+       if (orig_fdt) {
+               if (fdt_check_header(orig_fdt)) {
+                       pr_efi_err(sys_table, "Device Tree header not valid!\n");
+                       return EFI_LOAD_ERROR;
+               }
+               /*
+                * We don't get the size of the FDT if we get if from a
+                * configuration table.
+                */
+               if (orig_fdt_size && fdt_totalsize(orig_fdt) > orig_fdt_size) {
+                       pr_efi_err(sys_table, "Truncated device tree! foo!\n");
+                       return EFI_LOAD_ERROR;
+               }
+       }
+       if (orig_fdt)
+               status = fdt_open_into(orig_fdt, fdt, new_fdt_size);
+       else
+               status = fdt_create_empty_tree(fdt, new_fdt_size);
+       if (status != 0)
+               goto fdt_set_fail;
+       /*
+        * Delete any memory nodes present. We must delete nodes which
+        * early_init_dt_scan_memory may try to use.
+        */
+       prev = 0;
+       for (;;) {
++              const char *type;
+               int len;
+               node = fdt_next_node(fdt, prev, NULL);
+               if (node < 0)
+                       break;
+               type = fdt_getprop(fdt, node, "device_type", &len);
+               if (type && strncmp(type, "memory", len) == 0) {
+                       fdt_del_node(fdt, node);
+                       continue;
+               }
+               prev = node;
+       }
+       node = fdt_subnode_offset(fdt, 0, "chosen");
+       if (node < 0) {
+               node = fdt_add_subnode(fdt, 0, "chosen");
+               if (node < 0) {
+                       status = node; /* node is error code when negative */
+                       goto fdt_set_fail;
+               }
+       }
+       if ((cmdline_ptr != NULL) && (strlen(cmdline_ptr) > 0)) {
+               status = fdt_setprop(fdt, node, "bootargs", cmdline_ptr,
+                                    strlen(cmdline_ptr) + 1);
+               if (status)
+                       goto fdt_set_fail;
+       }
+       /* Set initrd address/end in device tree, if present */
+       if (initrd_size != 0) {
+               u64 initrd_image_end;
+               u64 initrd_image_start = cpu_to_fdt64(initrd_addr);
+               status = fdt_setprop(fdt, node, "linux,initrd-start",
+                                    &initrd_image_start, sizeof(u64));
+               if (status)
+                       goto fdt_set_fail;
+               initrd_image_end = cpu_to_fdt64(initrd_addr + initrd_size);
+               status = fdt_setprop(fdt, node, "linux,initrd-end",
+                                    &initrd_image_end, sizeof(u64));
+               if (status)
+                       goto fdt_set_fail;
+       }
+       /* Add FDT entries for EFI runtime services in chosen node. */
+       node = fdt_subnode_offset(fdt, 0, "chosen");
+       fdt_val64 = cpu_to_fdt64((u64)(unsigned long)sys_table);
+       status = fdt_setprop(fdt, node, "linux,uefi-system-table",
+                            &fdt_val64, sizeof(fdt_val64));
+       if (status)
+               goto fdt_set_fail;
+       fdt_val64 = cpu_to_fdt64((u64)(unsigned long)memory_map);
+       status = fdt_setprop(fdt, node, "linux,uefi-mmap-start",
+                            &fdt_val64,  sizeof(fdt_val64));
+       if (status)
+               goto fdt_set_fail;
+       fdt_val32 = cpu_to_fdt32(map_size);
+       status = fdt_setprop(fdt, node, "linux,uefi-mmap-size",
+                            &fdt_val32,  sizeof(fdt_val32));
+       if (status)
+               goto fdt_set_fail;
+       fdt_val32 = cpu_to_fdt32(desc_size);
+       status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-size",
+                            &fdt_val32, sizeof(fdt_val32));
+       if (status)
+               goto fdt_set_fail;
+       fdt_val32 = cpu_to_fdt32(desc_ver);
+       status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-ver",
+                            &fdt_val32, sizeof(fdt_val32));
+       if (status)
+               goto fdt_set_fail;
+       /*
+        * Add kernel version banner so stub/kernel match can be
+        * verified.
+        */
+       status = fdt_setprop_string(fdt, node, "linux,uefi-stub-kern-ver",
+                            linux_banner);
+       if (status)
+               goto fdt_set_fail;
+       return EFI_SUCCESS;
+ fdt_set_fail:
+       if (status == -FDT_ERR_NOSPACE)
+               return EFI_BUFFER_TOO_SMALL;
+       return EFI_LOAD_ERROR;
+ }
+ #ifndef EFI_FDT_ALIGN
+ #define EFI_FDT_ALIGN EFI_PAGE_SIZE
+ #endif
+ /*
+  * Allocate memory for a new FDT, then add EFI, commandline, and
+  * initrd related fields to the FDT.  This routine increases the
+  * FDT allocation size until the allocated memory is large
+  * enough.  EFI allocations are in EFI_PAGE_SIZE granules,
+  * which are fixed at 4K bytes, so in most cases the first
+  * allocation should succeed.
+  * EFI boot services are exited at the end of this function.
+  * There must be no allocations between the get_memory_map()
+  * call and the exit_boot_services() call, so the exiting of
+  * boot services is very tightly tied to the creation of the FDT
+  * with the final memory map in it.
+  */
+ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
+                                           void *handle,
+                                           unsigned long *new_fdt_addr,
+                                           unsigned long max_addr,
+                                           u64 initrd_addr, u64 initrd_size,
+                                           char *cmdline_ptr,
+                                           unsigned long fdt_addr,
+                                           unsigned long fdt_size)
+ {
+       unsigned long map_size, desc_size;
+       u32 desc_ver;
+       unsigned long mmap_key;
+       efi_memory_desc_t *memory_map;
+       unsigned long new_fdt_size;
+       efi_status_t status;
+       /*
+        * Estimate size of new FDT, and allocate memory for it. We
+        * will allocate a bigger buffer if this ends up being too
+        * small, so a rough guess is OK here.
+        */
+       new_fdt_size = fdt_size + EFI_PAGE_SIZE;
+       while (1) {
+               status = efi_high_alloc(sys_table, new_fdt_size, EFI_FDT_ALIGN,
+                                       new_fdt_addr, max_addr);
+               if (status != EFI_SUCCESS) {
+                       pr_efi_err(sys_table, "Unable to allocate memory for new device tree.\n");
+                       goto fail;
+               }
+               /*
+                * Now that we have done our final memory allocation (and free)
+                * we can get the memory map key  needed for
+                * exit_boot_services().
+                */
+               status = efi_get_memory_map(sys_table, &memory_map, &map_size,
+                                           &desc_size, &desc_ver, &mmap_key);
+               if (status != EFI_SUCCESS)
+                       goto fail_free_new_fdt;
+               status = update_fdt(sys_table,
+                                   (void *)fdt_addr, fdt_size,
+                                   (void *)*new_fdt_addr, new_fdt_size,
+                                   cmdline_ptr, initrd_addr, initrd_size,
+                                   memory_map, map_size, desc_size, desc_ver);
+               /* Succeeding the first time is the expected case. */
+               if (status == EFI_SUCCESS)
+                       break;
+               if (status == EFI_BUFFER_TOO_SMALL) {
+                       /*
+                        * We need to allocate more space for the new
+                        * device tree, so free existing buffer that is
+                        * too small.  Also free memory map, as we will need
+                        * to get new one that reflects the free/alloc we do
+                        * on the device tree buffer.
+                        */
+                       efi_free(sys_table, new_fdt_size, *new_fdt_addr);
+                       sys_table->boottime->free_pool(memory_map);
+                       new_fdt_size += EFI_PAGE_SIZE;
+               } else {
+                       pr_efi_err(sys_table, "Unable to constuct new device tree.\n");
+                       goto fail_free_mmap;
+               }
+       }
+       /* Now we are ready to exit_boot_services.*/
+       status = sys_table->boottime->exit_boot_services(handle, mmap_key);
+       if (status == EFI_SUCCESS)
+               return status;
+       pr_efi_err(sys_table, "Exit boot services failed.\n");
+ fail_free_mmap:
+       sys_table->boottime->free_pool(memory_map);
+ fail_free_new_fdt:
+       efi_free(sys_table, new_fdt_size, *new_fdt_addr);
+ fail:
+       return EFI_LOAD_ERROR;
+ }
+ void *get_fdt(efi_system_table_t *sys_table)
+ {
+       efi_guid_t fdt_guid = DEVICE_TREE_GUID;
+       efi_config_table_t *tables;
+       void *fdt;
+       int i;
+       tables = (efi_config_table_t *) sys_table->tables;
+       fdt = NULL;
+       for (i = 0; i < sys_table->nr_tables; i++)
+               if (efi_guidcmp(tables[i].guid, fdt_guid) == 0) {
+                       fdt = (void *) tables[i].table;
+                       break;
+        }
+       return fdt;
+ }
This page took 0.101209 seconds and 4 git commands to generate.