mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-25 22:20:45 +00:00
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:
commit
bd39d86420
9 changed files with 208 additions and 27 deletions
|
@ -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*
|
||||
|
|
|
@ -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
159
doc/README.iscsi
Normal 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)
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue