]> git.ipfire.org Git - people/ms/u-boot.git/commitdiff
Merge tag 'signed-efi-next' of git://github.com/agraf/u-boot
authorTom Rini <trini@konsulko.com>
Sun, 28 Jan 2018 23:26:00 +0000 (18:26 -0500)
committerTom Rini <trini@konsulko.com>
Sun, 28 Jan 2018 23:26:00 +0000 (18:26 -0500)
Patch queue for efi - 2018-01-28

This is the second part of patches for 2018.03-rc1, fixing
a few minor issues and adding a readme file for iSCSI booting.

MAINTAINERS
cmd/bootefi.c
doc/README.iscsi [new file with mode: 0644]
include/efi.h
lib/efi_loader/Kconfig
lib/efi_loader/efi_bootmgr.c
lib/efi_loader/efi_boottime.c
lib/vsprintf.c
test/print_ut.c

index 0c7efde5a5b5cafb6c9866b786ad3899f8cb5963..0aecc18a6c6e92b93a50d408ad886e44eeeb124b 100644 (file)
@@ -289,6 +289,7 @@ EFI PAYLOAD
 M:     Alexander Graf <agraf@suse.de>
 S:     Maintained
 T:     git git://github.com/agraf/u-boot.git
+F:     doc/README.iscsi
 F:     include/efi*
 F:     lib/efi*/
 F:     test/py/tests/test_efi*
index 51213c0293c307b843b4a1da819d9141632b9d20..4233d36b72288c7fb611826aacc65eff2892693a 100644 (file)
@@ -126,8 +126,9 @@ static void *copy_fdt(void *fdt)
 
 static efi_status_t efi_do_enter(
                        efi_handle_t image_handle, struct efi_system_table *st,
-                       asmlinkage ulong (*entry)(efi_handle_t image_handle,
-                                                 struct efi_system_table *st))
+                       EFIAPI efi_status_t (*entry)(
+                               efi_handle_t image_handle,
+                               struct efi_system_table *st))
 {
        efi_status_t ret = EFI_LOAD_ERROR;
 
@@ -138,7 +139,7 @@ static efi_status_t efi_do_enter(
 }
 
 #ifdef CONFIG_ARM64
-static efi_status_t efi_run_in_el2(asmlinkage ulong (*entry)(
+static efi_status_t efi_run_in_el2(EFIAPI efi_status_t (*entry)(
                        efi_handle_t image_handle, struct efi_system_table *st),
                        efi_handle_t image_handle, struct efi_system_table *st)
 {
@@ -162,8 +163,8 @@ static efi_status_t do_bootefi_exec(void *efi, void *fdt,
        struct efi_device_path *memdp = NULL;
        ulong ret;
 
-       ulong (*entry)(efi_handle_t image_handle, struct efi_system_table *st)
-               asmlinkage;
+       EFIAPI efi_status_t (*entry)(efi_handle_t image_handle,
+                                    struct efi_system_table *st);
        ulong fdt_pages, fdt_size, fdt_start, fdt_end;
        const efi_guid_t fdt_guid = EFI_FDT_GUID;
        bootm_headers_t img = { 0 };
@@ -372,6 +373,9 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
                saddr = argv[1];
 
                addr = simple_strtoul(saddr, NULL, 16);
+               /* Check that a numeric value was passed */
+               if (!addr && *saddr != '0')
+                       return CMD_RET_USAGE;
 
                if (argc > 2) {
                        sfdt = argv[2];
diff --git a/doc/README.iscsi b/doc/README.iscsi
new file mode 100644 (file)
index 0000000..cb71c6e
--- /dev/null
@@ -0,0 +1,159 @@
+# iSCSI booting with U-Boot and iPXE
+
+## Motivation
+
+U-Boot has only a reduced set of supported network protocols. The focus for
+network booting has been on UDP based protocols. A TCP stack and HTTP support
+are expected to be integrated in 2018 together with a wget command.
+
+For booting a diskless computer this leaves us with BOOTP or DHCP to get the
+address of a boot script. TFTP or NFS can be used to load the boot script, the
+operating system kernel and the initial file system (initrd).
+
+These protocols are insecure. The client cannot validate the authenticity
+of the contacted servers. And the server cannot verify the identity of the
+client.
+
+Furthermore the services providing the operating system loader or kernel are
+not the ones that the operating system typically will use. Especially in a SAN
+environment this makes updating the operating system a hassle. After installing
+a new kernel version the boot files have to be copied to the TFTP server
+directory.
+
+The HTTPS protocol provides certificate based validation of servers. Sensitive
+data like passwords can be securely transmitted.
+
+The iSCSI protocol is used for connecting storage attached networks. It
+provides mutual authentication using the CHAP protocol. It typically runs on
+a TCP transport.
+
+Thus a better solution than DHCP/TFTP/NFS boot would be to load a boot script
+via HTTPS and to download any other files needed for booting via iSCSI from the
+same target where the operating system is installed.
+
+An alternative to implementing these protocols in U-Boot is to use an existing
+software that can run on top of U-Boot. iPXE is the "swiss army knife" of
+network booting. It supports both HTTPS and iSCSI. It has a scripting engine for
+fine grained control of the boot process and can provide a command shell.
+
+iPXE can be built as an EFI application (named snp.efi) which can be loaded and
+run by U-Boot.
+
+## Boot sequence
+
+U-Boot loads the EFI application iPXE snp.efi using the bootefi command. This
+application has network access via the simple network protocol offered by
+U-Boot.
+
+iPXE executes its internal script. This script may optionally chain load a
+secondary boot script via HTTPS or open a shell.
+
+For the further boot process iPXE connects to the iSCSI server. This includes
+the mutual authentication using the CHAP protocol. After the authentication iPXE
+has access to the iSCSI targets.
+
+For a selected iSCSI target iPXE sets up a handle with the block IO protocol. It
+uses the ConnectController boot service of U-Boot to request U-Boot to connect a
+file system driver. U-Boot reads from the iSCSI drive via the block IO protocol
+offered by iPXE. It creates the partition handles and installs the simple file
+protocol. Now iPXE can call the simple file protocol to load Grub. U-Boot uses
+the block IO protocol offered by iPXE to fulfill the request.
+
+Once Grub is started it uses the same block IO protocol to load Linux. Via
+the EFI stub Linux is called as an EFI application.
+
+```
+               +--------+          +--------+
+               |        | Runs     |        |
+               | U-Boot |=========>| iPXE   |
+               | EFI    |          | snp.efi|
++--------+     |        | DHCP     |        |
+|        |<====|********|<=========|        |
+| DHCP   |     |        | Get IP   |        |
+| Server |     |        | Address  |        |
+|        |====>|********|=========>|        |
++--------+     |        | Response |        |
+               |        |          |        |
+               |        |          |        |
++--------+     |        | HTTPS    |        |
+|        |<====|********|<=========|        |
+| HTTPS  |     |        | Load     |        |
+| Server |     |        | Script   |        |
+|        |====>|********|=========>|        |
++--------+     |        |          |        |
+               |        |          |        |
+               |        |          |        |
++--------+     |        | iSCSI    |        |
+|        |<====|********|<=========|        |
+| iSCSI  |     |        | Auth     |        |
+| Server |====>|********|=========>|        |
+|        |     |        |          |        |
+|        |     |        | Loads    |        |
+|        |<====|********|<=========|        |        +--------+
+|        |     |        | Grub     |        | Runs   |        |
+|        |====>|********|=========>|        |=======>| Grub   |
+|        |     |        |          |        |        |        |
+|        |     |        |          |        |        |        |
+|        |     |        |          |        | Loads  |        |
+|        |<====|********|<=========|********|<=======|        |      +--------+
+|        |     |        |          |        | Linux  |        | Runs |        |
+|        |====>|********|=========>|********|=======>|        |=====>| Linux  |
+|        |     |        |          |        |        |        |      |        |
++--------+     +--------+          +--------+        +--------+      |        |
+                                                                     |        |
+                                                                     |        |
+                                                                     | ~ ~ ~ ~|
+```
+
+## Security
+
+The iSCSI protocol is not encrypted. The traffic could be secured using IPsec
+but neither U-Boot nor iPXE does support this. So we should at least separate
+the iSCSI traffic from all other network traffic. This can be achieved using a
+virtual local area network (VLAN).
+
+## Configuration
+
+### iPXE
+
+For running iPXE on arm64 the bin-arm64-efi/snp.efi build target is needed.
+
+    git clone http://git.ipxe.org/ipxe.git
+    cd ipxe/src
+    make bin-arm64-efi/snp.efi -j6 EMBED=myscript.ipxe
+
+The available commands for the boot script are documented at:
+
+http://ipxe.org/cmd
+
+Credentials are managed as environment variables. These are described here:
+
+http://ipxe.org/cfg
+
+iPXE by default will put the CPU to rest when waiting for input. U-Boot does
+not wake it up due to missing interrupt support. To avoid this behavior create
+file src/config/local/nap.h.
+
+    /* nap.h */
+    #undef NAP_EFIX86
+    #undef NAP_EFIARM
+    #define NAP_NULL
+
+The supported commands in iPXE are controlled by an include, too. Putting the
+following into src/config/local/general.h is sufficient for most use cases.
+
+    /* general.h */
+    #define NSLOOKUP_CMD            /* Name resolution command */
+    #define PING_CMD                /* Ping command */
+    #define NTP_CMD                 /* NTP commands */
+    #define VLAN_CMD                /* VLAN commands */
+    #define IMAGE_EFI               /* EFI image support */
+    #define DOWNLOAD_PROTO_HTTPS    /* Secure Hypertext Transfer Protocol */
+    #define DOWNLOAD_PROTO_FTP      /* File Transfer Protocol */
+    #define DOWNLOAD_PROTO_NFS      /* Network File System Protocol */
+    #define DOWNLOAD_PROTO_FILE     /* Local file system access */
+
+## Links
+
+* https://ipxe.org - iPXE open source boot firmware
+* https://www.gnu.org/software/grub/ - GNU Grub (Grand Unified Bootloader)
index 2f0be9c86cb08a69ac94aee7a4c21755fd62710f..98bddbac1ad1e653b492b1fd62360f7735c95185 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/string.h>
 #include <linux/types.h>
 
-#ifdef CONFIG_EFI_STUB_64BIT
+#if CONFIG_EFI_STUB_64BIT || (!defined(CONFIG_EFI_STUB) && defined(__x86_64__))
 /* EFI uses the Microsoft ABI which is not the default for GCC */
 #define EFIAPI __attribute__((ms_abi))
 #else
index d2b6327119b401abf342da83c614bb26ea717158..827c267b601472fec86dad7548bab651d0181532 100644 (file)
@@ -1,6 +1,10 @@
 config EFI_LOADER
        bool "Support running EFI Applications in U-Boot"
        depends on (ARM || X86) && OF_LIBFDT
+       # We need EFI_STUB_64BIT to be set on x86_64 with EFI_STUB
+       depends on !EFI_STUB || !X86_64 || EFI_STUB_64BIT
+       # We need EFI_STUB_32BIT to be set on x86_32 with EFI_STUB
+       depends on !EFI_STUB || !X86 || X86_64 || EFI_STUB_32BIT
        default y
        help
          Select this option if you want to run EFI applications (like grub2)
index 857d88a879ec76b7508f5ca5321f3b74eafca93e..c96b9d48c5929fd029a4a2253cb186ed92251d71 100644 (file)
@@ -120,11 +120,9 @@ static void *try_load_entry(uint16_t n, struct efi_device_path **device_path,
 
        if (lo.attributes & LOAD_OPTION_ACTIVE) {
                efi_status_t ret;
-               u16 *str = NULL;
 
-               debug("%s: trying to load \"%ls\" from: %ls\n", __func__,
-                     lo.label, (str = efi_dp_str(lo.file_path)));
-               efi_free_pool(str);
+               debug("%s: trying to load \"%ls\" from %pD\n",
+                     __func__, lo.label, lo.file_path);
 
                ret = efi_load_image_from_path(lo.file_path, &image);
 
index 39d8511fe383bb1f06523a6f52b98c05d31782c9..da93498b36bbdec48b653e2046ca7e763479ff4c 100644 (file)
@@ -111,8 +111,11 @@ void efi_restore_gd(void)
 }
 
 /*
- * Two spaces per indent level, maxing out at 10.. which ought to be
- * enough for anyone ;-)
+ * Return a string for indenting with two spaces per level. A maximum of ten
+ * indent levels is supported. Higher indent levels will be truncated.
+ *
+ * @level      indent level
+ * @return     indent string
  */
 static const char *indent_string(int level)
 {
@@ -1364,16 +1367,18 @@ efi_status_t efi_setup_loaded_image(
        obj->handle = info;
 
        info->file_path = file_path;
-       if (device_path)
-               info->device_handle = efi_dp_find_obj(device_path, NULL);
 
-       /*
-        * When asking for the device path interface, return
-        * bootefi_device_path
-        */
-       ret = efi_add_protocol(obj->handle, &efi_guid_device_path, device_path);
-       if (ret != EFI_SUCCESS)
-               goto failure;
+       if (device_path) {
+               info->device_handle = efi_dp_find_obj(device_path, NULL);
+               /*
+                * When asking for the device path interface, return
+                * bootefi_device_path
+                */
+               ret = efi_add_protocol(obj->handle, &efi_guid_device_path,
+                                      device_path);
+               if (ret != EFI_SUCCESS)
+                       goto failure;
+       }
 
        /*
         * When asking for the loaded_image interface, just
@@ -1456,7 +1461,7 @@ error:
  * for details.
  *
  * @boot_policy                true for request originating from the boot manager
- * @parent_image       the calles's image handle
+ * @parent_image       the caller's image handle
  * @file_path          the path of the image to load
  * @source_buffer      memory location from which the image is installed
  * @source_size                size of the memory area from which the image is
@@ -1534,8 +1539,8 @@ static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
                                           unsigned long *exit_data_size,
                                           s16 **exit_data)
 {
-       asmlinkage ulong (*entry)(efi_handle_t image_handle,
-                                 struct efi_system_table *st);
+       EFIAPI efi_status_t (*entry)(efi_handle_t image_handle,
+                                    struct efi_system_table *st);
        struct efi_loaded_image *info = image_handle;
        efi_status_t ret;
 
@@ -1575,8 +1580,13 @@ static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
 
        ret = EFI_CALL(entry(image_handle, &systab));
 
-       /* Should usually never get here */
-       return EFI_EXIT(ret);
+       /*
+        * Usually UEFI applications call Exit() instead of returning.
+        * But because the world doesn not consist of ponies and unicorns,
+        * we're happy to emulate that behavior on behalf of a payload
+        * that forgot.
+        */
+       return EFI_CALL(systab.boottime->exit(image_handle, ret, 0, NULL));
 }
 
 /*
index 226f4eb3e5125878200fbeb1109d3ab24e41e260..5f7a5f17dc6917cf539c9b207698408a43eda493 100644 (file)
@@ -300,8 +300,9 @@ static char *device_path_string(char *buf, char *end, void *dp, int field_width,
 {
        u16 *str;
 
+       /* If dp == NULL output the string '<NULL>' */
        if (!dp)
-               return "<NULL>";
+               return string16(buf, end, dp, field_width, precision, flags);
 
        str = efi_dp_str((struct efi_device_path *)dp);
        if (!str)
index 1aa68be7a9ac6cef1e68e31e6f31b9472068091f..d8e9da8fa8f4141235ac01d7d1654f5b6314b1f7 100644 (file)
@@ -44,6 +44,10 @@ static void efi_ut_print(void)
 
        snprintf(str, sizeof(str), "_%pD_", buf);
        assert(!strcmp("_/SD(3)_", str));
+
+       /* NULL device path */
+       snprintf(str, sizeof(str), "_%pD_", NULL);
+       assert(!strcmp("_<NULL>_", str));
 #endif
 }