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.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iQIcBAABAgAGBQJabjUeAAoJECszeR4D/txg4HMP/0kO9/rcJSaKx03xNSXmb0bI
 dyLrylFl3CvYVndlo66xdv1ZeZlTz4j6avCMJA/wD8LJubebHsATPml1zQHlHKXd
 UZWRcTs4gkEpUjxc6SAUfgIFmtLd/zRr6sDzgVqOAHY192S70sFckEJRGkddbzBk
 Y/AomvXdWr6n6GkZHq2L/8A5I/Yhl+xqX5y8K5BsDuy44nZVn8BprzYkTUMU5k8C
 Zx3j7S5NiEeVdzhCjJxDMJceh2tVc/MRLkedhZZAybQ+sTetVaQ1Q7PyPWakamoQ
 ohd0EercMQPod2x8S/aRI8CJksU4N1ulPLUs7qB4DfLu5zA0L7sJdPlj1w7Pbg4A
 DptTAtZV7I8wEpMbihgQcj5+HBejPtrAbDZKyjjxxIeL7fLv/j/L9cOsXYLMlEtY
 tGgmQG2C0fAMScp3lSxW4vACX7lNnPsqxZ1whgoHo0rRU60nzqBav6ZAIJq6HT+J
 yZKEcZY3frvyhDx54buyGSOOPSfBmbCXgNS/ejY8BDL86EXcG/WckOvn8d2Jc2Sw
 yOjWwRuhPiMjbJhCeMFtBv67tmt8gx0T0nj/v23ig7b8G93EgcHGUAbHQyqoFQR3
 v1nb70FGhuVluyyNGTsBGh0iUv0q1YK1/puLzh8Yh/DuSnkjibgWvNQpZfwl+4xI
 WdTDLIu38JvCkZuR2UOb
 =sVD7
 -----END PGP SIGNATURE-----

Merge tag 'signed-efi-next' of git://github.com/agraf/u-boot

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.
This commit is contained in:
Tom Rini 2018-01-28 18:26:00 -05:00
commit bd39d86420
9 changed files with 208 additions and 27 deletions

View 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*

View 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];

159
doc/README.iscsi Normal file
View file

@ -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)

View 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

View 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)

View 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);

View 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));
}
/*

View 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)

View 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
}