2343 lines
68 KiB
Diff
2343 lines
68 KiB
Diff
From 8cb4ccaf3be1258bfaa8069501028ad1e825489d Mon Sep 17 00:00:00 2001
|
|
From: Rob Clark <robdclark@gmail.com>
|
|
Date: Mon, 24 Jul 2017 10:15:08 -0400
|
|
Subject: [PATCH 01/13] efi_loader: add back optional efi_handler::open()
|
|
|
|
In some cases it is useful to defer creation of the protocol interface
|
|
object. So add back an optional ->open() hook that is used if
|
|
protcol_interface is NULL.
|
|
|
|
I've slightly simplified the fxn ptr signature to remove unneeded args,
|
|
and so compiler will complain if patches that used the "old way" are,
|
|
and which do not need this extra complexity, are rebased.
|
|
|
|
Signed-off-by: Rob Clark <robdclark@gmail.com>
|
|
---
|
|
include/efi_loader.h | 12 +++++++++++-
|
|
lib/efi_loader/efi_boottime.c | 30 ++++++++++++++++++++++++------
|
|
2 files changed, 35 insertions(+), 7 deletions(-)
|
|
|
|
diff --git a/include/efi_loader.h b/include/efi_loader.h
|
|
index 037cc7c543..03c4ed5e1c 100644
|
|
--- a/include/efi_loader.h
|
|
+++ b/include/efi_loader.h
|
|
@@ -70,10 +70,17 @@ extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;
|
|
/*
|
|
* When the UEFI payload wants to open a protocol on an object to get its
|
|
* interface (usually a struct with callback functions), this struct maps the
|
|
- * protocol GUID to the respective protocol interface */
|
|
+ * protocol GUID to the respective protocol interface.
|
|
+ *
|
|
+ * The optional ->open() fxn can be used for cases where the protocol
|
|
+ * interface is constructed on-demand, and is called if protocol_interface
|
|
+ * is NULL.
|
|
+ */
|
|
struct efi_handler {
|
|
const efi_guid_t *guid;
|
|
void *protocol_interface;
|
|
+ efi_status_t (EFIAPI *open)(void *handle, const efi_guid_t *protocol,
|
|
+ void **protocol_interface);
|
|
};
|
|
|
|
/*
|
|
@@ -191,6 +198,9 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
|
|
int efi_memory_init(void);
|
|
/* Adds new or overrides configuration table entry to the system table */
|
|
efi_status_t efi_install_configuration_table(const efi_guid_t *guid, void *table);
|
|
+efi_status_t efi_get_protocol(struct efi_object *efiobj,
|
|
+ struct efi_handler *handler,
|
|
+ void **protocol_interface);
|
|
|
|
#ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER
|
|
extern void *efi_bounce_buffer;
|
|
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
|
|
index 59479eddb9..4b78f6d556 100644
|
|
--- a/lib/efi_loader/efi_boottime.c
|
|
+++ b/lib/efi_loader/efi_boottime.c
|
|
@@ -1004,6 +1004,23 @@ out:
|
|
return EFI_EXIT(r);
|
|
}
|
|
|
|
+efi_status_t efi_get_protocol(struct efi_object *efiobj,
|
|
+ struct efi_handler *handler,
|
|
+ void **protocol_interface)
|
|
+{
|
|
+ efi_status_t ret = EFI_SUCCESS;
|
|
+
|
|
+ if (!handler->protocol_interface) {
|
|
+ ret = handler->open(efiobj->handle,
|
|
+ handler->guid,
|
|
+ &handler->protocol_interface);
|
|
+ }
|
|
+ *protocol_interface =
|
|
+ handler->protocol_interface;
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
static efi_status_t EFIAPI efi_locate_protocol(efi_guid_t *protocol,
|
|
void *registration,
|
|
void **protocol_interface)
|
|
@@ -1026,9 +1043,10 @@ static efi_status_t EFIAPI efi_locate_protocol(efi_guid_t *protocol,
|
|
if (!handler->guid)
|
|
continue;
|
|
if (!guidcmp(handler->guid, protocol)) {
|
|
- *protocol_interface =
|
|
- handler->protocol_interface;
|
|
- return EFI_EXIT(EFI_SUCCESS);
|
|
+ efi_status_t ret;
|
|
+ ret = efi_get_protocol(efiobj, handler,
|
|
+ protocol_interface);
|
|
+ return EFI_EXIT(ret);
|
|
}
|
|
}
|
|
}
|
|
@@ -1162,12 +1180,12 @@ static efi_status_t EFIAPI efi_open_protocol(
|
|
if (!hprotocol)
|
|
continue;
|
|
if (!guidcmp(hprotocol, protocol)) {
|
|
+ r = EFI_SUCCESS;
|
|
if (attributes !=
|
|
EFI_OPEN_PROTOCOL_TEST_PROTOCOL) {
|
|
- *protocol_interface =
|
|
- handler->protocol_interface;
|
|
+ r = efi_get_protocol(efiobj, handler,
|
|
+ protocol_interface);
|
|
}
|
|
- r = EFI_SUCCESS;
|
|
goto out;
|
|
}
|
|
}
|
|
--
|
|
2.13.3
|
|
|
|
From 784e48fe7488893209f4569a2a1664890fd75d4e Mon Sep 17 00:00:00 2001
|
|
From: Peter Jones <pjones@redhat.com>
|
|
Date: Tue, 25 Jul 2017 13:40:43 -0400
|
|
Subject: [PATCH 02/13] part: extract MBR signature from partitions
|
|
|
|
EFI client programs need the signature information from the partition
|
|
table to determine the disk a partition is on, so we need to fill that
|
|
in here.
|
|
|
|
Signed-off-by: Peter Jones <pjones@redhat.com>
|
|
[separated from efi_loader part, and fixed build-errors for non-
|
|
CONFIG_EFI_PARTITION case]
|
|
Signed-off-by: Rob Clark <robdclark@gmail.com>
|
|
---
|
|
disk/part_dos.c | 12 +++++++++---
|
|
disk/part_efi.c | 20 ++++++++++++++++++++
|
|
include/blk.h | 15 +++++++++++++++
|
|
include/efi.h | 4 ++++
|
|
include/part.h | 3 ++-
|
|
include/part_efi.h | 4 ----
|
|
6 files changed, 50 insertions(+), 8 deletions(-)
|
|
|
|
diff --git a/disk/part_dos.c b/disk/part_dos.c
|
|
index 7ede15ec26..850a538e83 100644
|
|
--- a/disk/part_dos.c
|
|
+++ b/disk/part_dos.c
|
|
@@ -89,14 +89,20 @@ static int test_block_type(unsigned char *buffer)
|
|
|
|
static int part_test_dos(struct blk_desc *dev_desc)
|
|
{
|
|
- ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, dev_desc->blksz);
|
|
+ ALLOC_CACHE_ALIGN_BUFFER(legacy_mbr, mbr, dev_desc->blksz);
|
|
|
|
- if (blk_dread(dev_desc, 0, 1, (ulong *)buffer) != 1)
|
|
+ if (blk_dread(dev_desc, 0, 1, (ulong *)mbr) != 1)
|
|
return -1;
|
|
|
|
- if (test_block_type(buffer) != DOS_MBR)
|
|
+ if (test_block_type((unsigned char *)mbr) != DOS_MBR)
|
|
return -1;
|
|
|
|
+ if (dev_desc->sig_type == SIG_TYPE_NONE &&
|
|
+ mbr->unique_mbr_signature != 0) {
|
|
+ dev_desc->sig_type = SIG_TYPE_MBR;
|
|
+ dev_desc->mbr_sig = mbr->unique_mbr_signature;
|
|
+ }
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/disk/part_efi.c b/disk/part_efi.c
|
|
index 1b7ba27947..71e4188455 100644
|
|
--- a/disk/part_efi.c
|
|
+++ b/disk/part_efi.c
|
|
@@ -871,11 +871,19 @@ static int is_pmbr_valid(legacy_mbr * mbr)
|
|
static int is_gpt_valid(struct blk_desc *dev_desc, u64 lba,
|
|
gpt_header *pgpt_head, gpt_entry **pgpt_pte)
|
|
{
|
|
+ ALLOC_CACHE_ALIGN_BUFFER(legacy_mbr, mbr, dev_desc->blksz);
|
|
+
|
|
if (!dev_desc || !pgpt_head) {
|
|
printf("%s: Invalid Argument(s)\n", __func__);
|
|
return 0;
|
|
}
|
|
|
|
+ /* Read MBR Header from device */
|
|
+ if (blk_dread(dev_desc, 0, 1, (ulong *)mbr) != 1) {
|
|
+ printf("*** ERROR: Can't read MBR header ***\n");
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
/* Read GPT Header from device */
|
|
if (blk_dread(dev_desc, (lbaint_t)lba, 1, pgpt_head) != 1) {
|
|
printf("*** ERROR: Can't read GPT header ***\n");
|
|
@@ -885,6 +893,18 @@ static int is_gpt_valid(struct blk_desc *dev_desc, u64 lba,
|
|
if (validate_gpt_header(pgpt_head, (lbaint_t)lba, dev_desc->lba))
|
|
return 0;
|
|
|
|
+ if (dev_desc->sig_type == SIG_TYPE_NONE) {
|
|
+ efi_guid_t empty = {};
|
|
+ if (memcmp(&pgpt_head->disk_guid, &empty, sizeof(empty))) {
|
|
+ dev_desc->sig_type = SIG_TYPE_GUID;
|
|
+ memcpy(&dev_desc->guid_sig, &pgpt_head->disk_guid,
|
|
+ sizeof(empty));
|
|
+ } else if (mbr->unique_mbr_signature != 0) {
|
|
+ dev_desc->sig_type = SIG_TYPE_MBR;
|
|
+ dev_desc->mbr_sig = mbr->unique_mbr_signature;
|
|
+ }
|
|
+ }
|
|
+
|
|
/* Read and allocate Partition Table Entries */
|
|
*pgpt_pte = alloc_read_gpt_entries(dev_desc, pgpt_head);
|
|
if (*pgpt_pte == NULL) {
|
|
diff --git a/include/blk.h b/include/blk.h
|
|
index ef29a07ee2..3a5e04c00d 100644
|
|
--- a/include/blk.h
|
|
+++ b/include/blk.h
|
|
@@ -8,6 +8,8 @@
|
|
#ifndef BLK_H
|
|
#define BLK_H
|
|
|
|
+#include <efi.h>
|
|
+
|
|
#ifdef CONFIG_SYS_64BIT_LBA
|
|
typedef uint64_t lbaint_t;
|
|
#define LBAFlength "ll"
|
|
@@ -35,6 +37,14 @@ enum if_type {
|
|
IF_TYPE_COUNT, /* Number of interface types */
|
|
};
|
|
|
|
+enum sig_type {
|
|
+ SIG_TYPE_NONE,
|
|
+ SIG_TYPE_MBR,
|
|
+ SIG_TYPE_GUID,
|
|
+
|
|
+ SIG_TYPE_COUNT /* Number of signature types */
|
|
+};
|
|
+
|
|
/*
|
|
* With driver model (CONFIG_BLK) this is uclass platform data, accessible
|
|
* with dev_get_uclass_platdata(dev)
|
|
@@ -62,6 +72,11 @@ struct blk_desc {
|
|
char vendor[40+1]; /* IDE model, SCSI Vendor */
|
|
char product[20+1]; /* IDE Serial no, SCSI product */
|
|
char revision[8+1]; /* firmware revision */
|
|
+ enum sig_type sig_type; /* Partition table signature type */
|
|
+ union {
|
|
+ uint32_t mbr_sig; /* MBR integer signature */
|
|
+ efi_guid_t guid_sig; /* GPT GUID Signature */
|
|
+ };
|
|
#if CONFIG_IS_ENABLED(BLK)
|
|
/*
|
|
* For now we have a few functions which take struct blk_desc as a
|
|
diff --git a/include/efi.h b/include/efi.h
|
|
index 02b78b31b1..87b0b43f20 100644
|
|
--- a/include/efi.h
|
|
+++ b/include/efi.h
|
|
@@ -28,6 +28,10 @@
|
|
|
|
struct efi_device_path;
|
|
|
|
+typedef struct {
|
|
+ u8 b[16];
|
|
+} efi_guid_t;
|
|
+
|
|
#define EFI_BITS_PER_LONG BITS_PER_LONG
|
|
|
|
/*
|
|
diff --git a/include/part.h b/include/part.h
|
|
index 83bce05a43..ac5ee895e9 100644
|
|
--- a/include/part.h
|
|
+++ b/include/part.h
|
|
@@ -259,8 +259,9 @@ struct part_driver {
|
|
#define U_BOOT_PART_TYPE(__name) \
|
|
ll_entry_declare(struct part_driver, __name, part_driver)
|
|
|
|
-#if CONFIG_IS_ENABLED(EFI_PARTITION)
|
|
#include <part_efi.h>
|
|
+
|
|
+#if CONFIG_IS_ENABLED(EFI_PARTITION)
|
|
/* disk/part_efi.c */
|
|
/**
|
|
* write_gpt_table() - Write the GUID Partition Table to disk
|
|
diff --git a/include/part_efi.h b/include/part_efi.h
|
|
index 317c044795..31e6bc6e14 100644
|
|
--- a/include/part_efi.h
|
|
+++ b/include/part_efi.h
|
|
@@ -58,10 +58,6 @@
|
|
/* linux/include/efi.h */
|
|
typedef u16 efi_char16_t;
|
|
|
|
-typedef struct {
|
|
- u8 b[16];
|
|
-} efi_guid_t;
|
|
-
|
|
/* based on linux/include/genhd.h */
|
|
struct partition {
|
|
u8 boot_ind; /* 0x80 - active */
|
|
--
|
|
2.13.3
|
|
|
|
From a6235e1a0f298f4e1e0271e772e457988f90ac2a Mon Sep 17 00:00:00 2001
|
|
From: Peter Jones <pjones@redhat.com>
|
|
Date: Wed, 21 Jun 2017 16:39:02 -0400
|
|
Subject: [PATCH 03/13] efi: add some more device path structures
|
|
|
|
Signed-off-by: Peter Jones <pjones@redhat.com>
|
|
---
|
|
include/efi_api.h | 49 +++++++++++++++++++++++++++++++++++++++++++++++--
|
|
1 file changed, 47 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/include/efi_api.h b/include/efi_api.h
|
|
index ec1b321e8e..85afbeb72b 100644
|
|
--- a/include/efi_api.h
|
|
+++ b/include/efi_api.h
|
|
@@ -290,22 +290,67 @@ struct efi_mac_addr {
|
|
u8 addr[32];
|
|
};
|
|
|
|
+#define DEVICE_PATH_TYPE_ACPI_DEVICE 0x02
|
|
+#define DEVICE_PATH_SUB_TYPE_ACPI_DEVICE 0x01
|
|
+
|
|
+#define EFI_PNP_ID(ID) (u32)(((ID) << 16) | 0x41D0)
|
|
+#define EISA_PNP_ID(ID) EFI_PNP_ID(ID)
|
|
+
|
|
+struct efi_device_path_acpi_path {
|
|
+ struct efi_device_path dp;
|
|
+ u32 hid;
|
|
+ u32 uid;
|
|
+} __packed;
|
|
+
|
|
#define DEVICE_PATH_TYPE_MESSAGING_DEVICE 0x03
|
|
+# define DEVICE_PATH_SUB_TYPE_MSG_USB 0x05
|
|
# define DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR 0x0b
|
|
+# define DEVICE_PATH_SUB_TYPE_MSG_SD 0x1a
|
|
+# define DEVICE_PATH_SUB_TYPE_MSG_MMC 0x1d
|
|
+
|
|
+struct efi_device_path_usb {
|
|
+ struct efi_device_path dp;
|
|
+ u8 parent_port_number;
|
|
+ u8 usb_interface;
|
|
+} __packed;
|
|
|
|
struct efi_device_path_mac_addr {
|
|
struct efi_device_path dp;
|
|
struct efi_mac_addr mac;
|
|
u8 if_type;
|
|
-};
|
|
+} __packed;
|
|
+
|
|
+struct efi_device_path_sd_mmc_path {
|
|
+ struct efi_device_path dp;
|
|
+ u8 slot_number;
|
|
+} __packed;
|
|
|
|
#define DEVICE_PATH_TYPE_MEDIA_DEVICE 0x04
|
|
+# define DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH 0x01
|
|
+# define DEVICE_PATH_SUB_TYPE_CDROM_PATH 0x02
|
|
# define DEVICE_PATH_SUB_TYPE_FILE_PATH 0x04
|
|
|
|
+struct efi_device_path_hard_drive_path {
|
|
+ struct efi_device_path dp;
|
|
+ u32 partition_number;
|
|
+ u64 partition_start;
|
|
+ u64 partition_end;
|
|
+ u8 partition_signature[16];
|
|
+ u8 partmap_type;
|
|
+ u8 signature_type;
|
|
+} __packed;
|
|
+
|
|
+struct efi_device_path_cdrom_path {
|
|
+ struct efi_device_path dp;
|
|
+ u32 boot_entry;
|
|
+ u64 partition_start;
|
|
+ u64 partition_end;
|
|
+} __packed;
|
|
+
|
|
struct efi_device_path_file_path {
|
|
struct efi_device_path dp;
|
|
u16 str[32];
|
|
-};
|
|
+} __packed;
|
|
|
|
#define BLOCK_IO_GUID \
|
|
EFI_GUID(0x964e5b21, 0x6459, 0x11d2, \
|
|
--
|
|
2.13.3
|
|
|
|
From 86eed9c21403969fdc69e508261a2e091c24897b Mon Sep 17 00:00:00 2001
|
|
From: Rob Clark <robdclark@gmail.com>
|
|
Date: Sun, 23 Jul 2017 11:25:53 -0400
|
|
Subject: [PATCH 04/13] fs: add fs_readdir()
|
|
|
|
Needed to support efi file protocol. The fallback.efi loader wants
|
|
to be able to read the contents of the /EFI directory to find an OS
|
|
to boot.
|
|
|
|
Currently only implemented for FAT, but that is all that UEFI is
|
|
required to support.
|
|
|
|
Signed-off-by: Rob Clark <robdclark@gmail.com>
|
|
---
|
|
fs/fat/fat.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++-------------
|
|
fs/fs.c | 25 +++++++++++++++++++++++++
|
|
include/fat.h | 4 +++-
|
|
include/fs.h | 21 +++++++++++++++++++++
|
|
4 files changed, 95 insertions(+), 14 deletions(-)
|
|
|
|
diff --git a/fs/fat/fat.c b/fs/fat/fat.c
|
|
index 9ad18f96ff..04d8616598 100644
|
|
--- a/fs/fat/fat.c
|
|
+++ b/fs/fat/fat.c
|
|
@@ -14,6 +14,7 @@
|
|
#include <config.h>
|
|
#include <exports.h>
|
|
#include <fat.h>
|
|
+#include <fs.h>
|
|
#include <asm/byteorder.h>
|
|
#include <part.h>
|
|
#include <malloc.h>
|
|
@@ -575,17 +576,25 @@ static __u8 mkcksum(const char name[8], const char ext[3])
|
|
/*
|
|
* Get the directory entry associated with 'filename' from the directory
|
|
* starting at 'startsect'
|
|
+ *
|
|
+ * Last two args are only used for dols==LS_READDIR
|
|
*/
|
|
__u8 get_dentfromdir_block[MAX_CLUSTSIZE]
|
|
__aligned(ARCH_DMA_MINALIGN);
|
|
|
|
-static dir_entry *get_dentfromdir(fsdata *mydata, int startsect,
|
|
- char *filename, dir_entry *retdent,
|
|
- int dols)
|
|
+static dir_entry *get_dentfromdir(fsdata *mydata, char *filename,
|
|
+ dir_entry *retdent, int dols,
|
|
+ loff_t pos, struct fs_dirent *d)
|
|
{
|
|
__u16 prevcksum = 0xffff;
|
|
__u32 curclust = START(retdent);
|
|
int files = 0, dirs = 0;
|
|
+ int readdir = 0;
|
|
+
|
|
+ if (dols == LS_READDIR) {
|
|
+ readdir = 1;
|
|
+ dols = 0;
|
|
+ }
|
|
|
|
debug("get_dentfromdir: %s\n", filename);
|
|
|
|
@@ -618,7 +627,7 @@ static dir_entry *get_dentfromdir(fsdata *mydata, int startsect,
|
|
get_vfatname(mydata, curclust,
|
|
get_dentfromdir_block,
|
|
dentptr, l_name);
|
|
- if (dols) {
|
|
+ if (dols || readdir) {
|
|
int isdir;
|
|
char dirc;
|
|
int doit = 0;
|
|
@@ -637,7 +646,14 @@ static dir_entry *get_dentfromdir(fsdata *mydata, int startsect,
|
|
}
|
|
}
|
|
if (doit) {
|
|
- if (dirc == ' ') {
|
|
+ if (readdir) {
|
|
+ if ((dirs + files - 1) == pos) {
|
|
+ strcpy(d->name, l_name);
|
|
+ if (!isdir)
|
|
+ d->size = FAT2CPU32(dentptr->size);
|
|
+ return NULL;
|
|
+ }
|
|
+ } else if (dirc == ' ') {
|
|
printf(" %8u %s%c\n",
|
|
FAT2CPU32(dentptr->size),
|
|
l_name,
|
|
@@ -676,7 +692,7 @@ static dir_entry *get_dentfromdir(fsdata *mydata, int startsect,
|
|
}
|
|
|
|
get_name(dentptr, s_name);
|
|
- if (dols) {
|
|
+ if (dols || readdir) {
|
|
int isdir = (dentptr->attr & ATTR_DIR);
|
|
char dirc;
|
|
int doit = 0;
|
|
@@ -694,7 +710,14 @@ static dir_entry *get_dentfromdir(fsdata *mydata, int startsect,
|
|
}
|
|
|
|
if (doit) {
|
|
- if (dirc == ' ') {
|
|
+ if (readdir) {
|
|
+ if ((dirs + files - 1) == pos) {
|
|
+ strcpy(d->name, s_name);
|
|
+ if (!isdir)
|
|
+ d->size = FAT2CPU32(dentptr->size);
|
|
+ return NULL;
|
|
+ }
|
|
+ } else if (dirc == ' ') {
|
|
printf(" %8u %s%c\n",
|
|
FAT2CPU32(dentptr->size),
|
|
s_name, dirc);
|
|
@@ -825,7 +848,7 @@ int do_fat_read_at(const char *filename, loff_t pos, void *buffer,
|
|
__u32 cursect;
|
|
int idx, isdir = 0;
|
|
int files = 0, dirs = 0;
|
|
- int ret = -1;
|
|
+ int ret = (dols == LS_READDIR) ? -ENOTDIR : -1;
|
|
int firsttime;
|
|
__u32 root_cluster = 0;
|
|
__u32 read_blk;
|
|
@@ -906,7 +929,8 @@ root_reparse:
|
|
if (!dols)
|
|
goto exit;
|
|
|
|
- dols = LS_ROOT;
|
|
+ if (dols == LS_YES)
|
|
+ dols = LS_ROOT;
|
|
} else if ((idx = dirdelim(fnamecopy)) >= 0) {
|
|
isdir = 1;
|
|
fnamecopy[idx] = '\0';
|
|
@@ -1151,8 +1175,6 @@ rootdir_done:
|
|
firsttime = 1;
|
|
|
|
while (isdir) {
|
|
- int startsect = mydata->data_begin
|
|
- + START(dentptr) * mydata->clust_size;
|
|
dir_entry dent;
|
|
char *nextname = NULL;
|
|
|
|
@@ -1177,10 +1199,14 @@ rootdir_done:
|
|
}
|
|
}
|
|
|
|
- if (get_dentfromdir(mydata, startsect, subname, dentptr,
|
|
- isdir ? 0 : dols) == NULL) {
|
|
+ if (get_dentfromdir(mydata, subname, dentptr,
|
|
+ isdir ? 0 : dols, pos, buffer) == NULL) {
|
|
if (dols && !isdir)
|
|
*size = 0;
|
|
+ if (dols == LS_READDIR) {
|
|
+ struct fs_dirent *dent = buffer;
|
|
+ ret = dent->name[0] ? 0 : -ENOENT;
|
|
+ }
|
|
goto exit;
|
|
}
|
|
|
|
@@ -1353,6 +1379,13 @@ int fat_read_file(const char *filename, void *buf, loff_t offset, loff_t len,
|
|
return ret;
|
|
}
|
|
|
|
+int fat_readdir(const char *filename, loff_t offset, struct fs_dirent *dent)
|
|
+{
|
|
+ loff_t actread;
|
|
+ return do_fat_read_at(filename, offset, dent, sizeof(*dent),
|
|
+ LS_READDIR, 0, &actread);
|
|
+}
|
|
+
|
|
void fat_close(void)
|
|
{
|
|
}
|
|
diff --git a/fs/fs.c b/fs/fs.c
|
|
index 595ff1fe69..42a028a6ce 100644
|
|
--- a/fs/fs.c
|
|
+++ b/fs/fs.c
|
|
@@ -69,6 +69,12 @@ static inline int fs_uuid_unsupported(char *uuid_str)
|
|
return -1;
|
|
}
|
|
|
|
+static inline int fs_readdir_unsupported(const char *filename, loff_t offset,
|
|
+ struct fs_dirent *dent)
|
|
+{
|
|
+ return -ENXIO;
|
|
+}
|
|
+
|
|
struct fstype_info {
|
|
int fstype;
|
|
char *name;
|
|
@@ -92,6 +98,7 @@ struct fstype_info {
|
|
loff_t len, loff_t *actwrite);
|
|
void (*close)(void);
|
|
int (*uuid)(char *uuid_str);
|
|
+ int (*readdir)(const char *filename, loff_t offset, struct fs_dirent *dent);
|
|
};
|
|
|
|
static struct fstype_info fstypes[] = {
|
|
@@ -112,6 +119,7 @@ static struct fstype_info fstypes[] = {
|
|
.write = fs_write_unsupported,
|
|
#endif
|
|
.uuid = fs_uuid_unsupported,
|
|
+ .readdir = fat_readdir,
|
|
},
|
|
#endif
|
|
#ifdef CONFIG_FS_EXT4
|
|
@@ -131,6 +139,7 @@ static struct fstype_info fstypes[] = {
|
|
.write = fs_write_unsupported,
|
|
#endif
|
|
.uuid = ext4fs_uuid,
|
|
+ .readdir = fs_readdir_unsupported,
|
|
},
|
|
#endif
|
|
#ifdef CONFIG_SANDBOX
|
|
@@ -146,6 +155,7 @@ static struct fstype_info fstypes[] = {
|
|
.read = fs_read_sandbox,
|
|
.write = fs_write_sandbox,
|
|
.uuid = fs_uuid_unsupported,
|
|
+ .readdir = fs_readdir_unsupported,
|
|
},
|
|
#endif
|
|
#ifdef CONFIG_CMD_UBIFS
|
|
@@ -161,6 +171,7 @@ static struct fstype_info fstypes[] = {
|
|
.read = ubifs_read,
|
|
.write = fs_write_unsupported,
|
|
.uuid = fs_uuid_unsupported,
|
|
+ .readdir = fs_readdir_unsupported,
|
|
},
|
|
#endif
|
|
{
|
|
@@ -175,6 +186,7 @@ static struct fstype_info fstypes[] = {
|
|
.read = fs_read_unsupported,
|
|
.write = fs_write_unsupported,
|
|
.uuid = fs_uuid_unsupported,
|
|
+ .readdir = fs_readdir_unsupported,
|
|
},
|
|
};
|
|
|
|
@@ -334,6 +346,19 @@ int fs_write(const char *filename, ulong addr, loff_t offset, loff_t len,
|
|
return ret;
|
|
}
|
|
|
|
+int fs_readdir(const char *filename, loff_t offset, struct fs_dirent *dent)
|
|
+{
|
|
+ struct fstype_info *info = fs_get_info(fs_type);
|
|
+ int ret;
|
|
+
|
|
+ memset(dent, 0, sizeof(*dent));
|
|
+
|
|
+ ret = info->readdir(filename, offset, dent);
|
|
+ fs_close();
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
int do_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
|
|
int fstype)
|
|
{
|
|
diff --git a/include/fat.h b/include/fat.h
|
|
index 71879f01ca..0ef3f5be16 100644
|
|
--- a/include/fat.h
|
|
+++ b/include/fat.h
|
|
@@ -61,8 +61,8 @@
|
|
/* Flags telling whether we should read a file or list a directory */
|
|
#define LS_NO 0
|
|
#define LS_YES 1
|
|
-#define LS_DIR 1
|
|
#define LS_ROOT 2
|
|
+#define LS_READDIR 3 /* read directory entry at specified offset */
|
|
|
|
#define ISDIRDELIM(c) ((c) == '/' || (c) == '\\')
|
|
|
|
@@ -210,5 +210,7 @@ int file_fat_write(const char *filename, void *buf, loff_t offset, loff_t len,
|
|
loff_t *actwrite);
|
|
int fat_read_file(const char *filename, void *buf, loff_t offset, loff_t len,
|
|
loff_t *actread);
|
|
+struct fs_dirent;
|
|
+int fat_readdir(const char *filename, loff_t offset, struct fs_dirent *dir);
|
|
void fat_close(void);
|
|
#endif /* _FAT_H_ */
|
|
diff --git a/include/fs.h b/include/fs.h
|
|
index 2f2aca8378..71051d7c66 100644
|
|
--- a/include/fs.h
|
|
+++ b/include/fs.h
|
|
@@ -79,6 +79,27 @@ int fs_write(const char *filename, ulong addr, loff_t offset, loff_t len,
|
|
loff_t *actwrite);
|
|
|
|
/*
|
|
+ * A directory entry.
|
|
+ */
|
|
+struct fs_dirent {
|
|
+ loff_t size;
|
|
+ char name[256];
|
|
+};
|
|
+
|
|
+/*
|
|
+ * fs_readdir - Read a directory.
|
|
+ *
|
|
+ * @filename: Name of file to read from
|
|
+ * @offset: The offset into the directory to read, ie. offset of N returns
|
|
+ * the N'th directory entry
|
|
+ * @dent: on success, filled in with directory entry
|
|
+ * @return 0 on success, -ENOTDIR if specified file is not a directory,
|
|
+ * or -ENOENT if offset is beyond last directory entry, or -ENXIO if
|
|
+ * operation is not supported.
|
|
+ */
|
|
+int fs_readdir(const char *filename, loff_t offset, struct fs_dirent *dent);
|
|
+
|
|
+/*
|
|
* Common implementation for various filesystem commands, optionally limited
|
|
* to a specific filesystem type via the fstype parameter.
|
|
*/
|
|
--
|
|
2.13.3
|
|
|
|
From 9c814af51bb6b2ac462f94d7a7d5484954a95d17 Mon Sep 17 00:00:00 2001
|
|
From: Rob Clark <robdclark@gmail.com>
|
|
Date: Thu, 27 Jul 2017 14:12:21 -0400
|
|
Subject: [PATCH 05/13] efi_loader: add device-path utils
|
|
|
|
Helpers to construct device-paths from devices, partitions, files, and
|
|
for parsing and manipulating device-paths.
|
|
|
|
For non-legacy devices, this will use u-boot's device-model to construct
|
|
device-paths which include bus hierarchy to construct device-paths. For
|
|
legacy devices we still fake it, but slightly more convincingly.
|
|
|
|
Signed-off-by: Rob Clark <robdclark@gmail.com>
|
|
---
|
|
include/efi_api.h | 10 +
|
|
include/efi_loader.h | 20 ++
|
|
lib/efi_loader/Makefile | 2 +-
|
|
lib/efi_loader/efi_device_path.c | 485 +++++++++++++++++++++++++++++++++++++++
|
|
4 files changed, 516 insertions(+), 1 deletion(-)
|
|
create mode 100644 lib/efi_loader/efi_device_path.c
|
|
|
|
diff --git a/include/efi_api.h b/include/efi_api.h
|
|
index 85afbeb72b..0ebe8d0283 100644
|
|
--- a/include/efi_api.h
|
|
+++ b/include/efi_api.h
|
|
@@ -305,6 +305,7 @@ struct efi_device_path_acpi_path {
|
|
#define DEVICE_PATH_TYPE_MESSAGING_DEVICE 0x03
|
|
# define DEVICE_PATH_SUB_TYPE_MSG_USB 0x05
|
|
# define DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR 0x0b
|
|
+# define DEVICE_PATH_SUB_TYPE_MSG_USB_CLASS 0x0f
|
|
# define DEVICE_PATH_SUB_TYPE_MSG_SD 0x1a
|
|
# define DEVICE_PATH_SUB_TYPE_MSG_MMC 0x1d
|
|
|
|
@@ -320,6 +321,15 @@ struct efi_device_path_mac_addr {
|
|
u8 if_type;
|
|
} __packed;
|
|
|
|
+struct efi_device_path_usb_class {
|
|
+ struct efi_device_path dp;
|
|
+ u16 vendor_id;
|
|
+ u16 product_id;
|
|
+ u8 device_class;
|
|
+ u8 device_subclass;
|
|
+ u8 device_protocol;
|
|
+} __packed;
|
|
+
|
|
struct efi_device_path_sd_mmc_path {
|
|
struct efi_device_path dp;
|
|
u8 slot_number;
|
|
diff --git a/include/efi_loader.h b/include/efi_loader.h
|
|
index 03c4ed5e1c..1028bfb75d 100644
|
|
--- a/include/efi_loader.h
|
|
+++ b/include/efi_loader.h
|
|
@@ -207,6 +207,26 @@ extern void *efi_bounce_buffer;
|
|
#define EFI_LOADER_BOUNCE_BUFFER_SIZE (64 * 1024 * 1024)
|
|
#endif
|
|
|
|
+
|
|
+struct efi_device_path *efi_dp_next(struct efi_device_path *dp);
|
|
+int efi_dp_match(struct efi_device_path *a, struct efi_device_path *b);
|
|
+struct efi_object *efi_dp_find_obj(struct efi_device_path *dp);
|
|
+unsigned efi_dp_size(struct efi_device_path *dp);
|
|
+struct efi_device_path *efi_dp_dup(struct efi_device_path *dp);
|
|
+
|
|
+struct efi_device_path *efi_dp_from_dev(struct udevice *dev);
|
|
+struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part);
|
|
+struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part,
|
|
+ const char *path);
|
|
+struct efi_device_path *efi_dp_from_eth(void);
|
|
+void efi_dp_split_file_path(struct efi_device_path *full_path,
|
|
+ struct efi_device_path **device_path,
|
|
+ struct efi_device_path **file_path);
|
|
+
|
|
+#define EFI_DP_TYPE(_dp, _type, _subtype) \
|
|
+ (((_dp)->type == DEVICE_PATH_TYPE_##_type) && \
|
|
+ ((_dp)->sub_type == DEVICE_PATH_SUB_TYPE_##_subtype))
|
|
+
|
|
/* Convert strings from normal C strings to uEFI strings */
|
|
static inline void ascii2unicode(u16 *unicode, const char *ascii)
|
|
{
|
|
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
|
|
index 30bf343a36..f35e5ce8a8 100644
|
|
--- a/lib/efi_loader/Makefile
|
|
+++ b/lib/efi_loader/Makefile
|
|
@@ -15,7 +15,7 @@ always := $(efiprogs-y)
|
|
|
|
obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o
|
|
obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o
|
|
-obj-y += efi_memory.o efi_device_path_to_text.o
|
|
+obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o
|
|
obj-$(CONFIG_LCD) += efi_gop.o
|
|
obj-$(CONFIG_DM_VIDEO) += efi_gop.o
|
|
obj-$(CONFIG_PARTITIONS) += efi_disk.o
|
|
diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
|
|
new file mode 100644
|
|
index 0000000000..b5acf73f98
|
|
--- /dev/null
|
|
+++ b/lib/efi_loader/efi_device_path.c
|
|
@@ -0,0 +1,485 @@
|
|
+/*
|
|
+ * EFI device path from u-boot device-model mapping
|
|
+ *
|
|
+ * (C) Copyright 2017 Rob Clark
|
|
+ *
|
|
+ * SPDX-License-Identifier: GPL-2.0+
|
|
+ */
|
|
+
|
|
+#include <common.h>
|
|
+#include <blk.h>
|
|
+#include <dm.h>
|
|
+#include <usb.h>
|
|
+#include <mmc.h>
|
|
+#include <efi_loader.h>
|
|
+#include <inttypes.h>
|
|
+#include <part.h>
|
|
+#include <malloc.h>
|
|
+
|
|
+/* template END node: */
|
|
+const static struct efi_device_path END = {
|
|
+ .type = DEVICE_PATH_TYPE_END,
|
|
+ .sub_type = DEVICE_PATH_SUB_TYPE_END,
|
|
+ .length = sizeof(END),
|
|
+};
|
|
+
|
|
+/* template ROOT node, a fictional ACPI PNP device: */
|
|
+const static struct efi_device_path_acpi_path ROOT = {
|
|
+ .dp = {
|
|
+ .type = DEVICE_PATH_TYPE_ACPI_DEVICE,
|
|
+ .sub_type = DEVICE_PATH_SUB_TYPE_ACPI_DEVICE,
|
|
+ .length = sizeof(ROOT),
|
|
+ },
|
|
+ .hid = EISA_PNP_ID(0x1337),
|
|
+ .uid = 0,
|
|
+};
|
|
+
|
|
+
|
|
+/*
|
|
+ * Iterate to next block in device-path, terminating (returning NULL)
|
|
+ * at /End* node.
|
|
+ */
|
|
+struct efi_device_path *efi_dp_next(struct efi_device_path *dp)
|
|
+{
|
|
+ if (dp == NULL)
|
|
+ return NULL;
|
|
+ dp = ((void *)dp) + dp->length;
|
|
+ if (dp->type == DEVICE_PATH_TYPE_END)
|
|
+ return NULL;
|
|
+ return dp;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Compare two device-paths, stopping when the shorter of the two hits
|
|
+ * an End* node. This is useful to, for example, compare a device-path
|
|
+ * representing a device with one representing a file on the device, or
|
|
+ * a device with a parent device.
|
|
+ */
|
|
+int efi_dp_match(struct efi_device_path *a, struct efi_device_path *b)
|
|
+{
|
|
+ while (1) {
|
|
+ int ret;
|
|
+
|
|
+ ret = memcmp(&a->length, &b->length, sizeof(a->length));
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = memcmp(a, b, a->length);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ a = efi_dp_next(a);
|
|
+ b = efi_dp_next(b);
|
|
+
|
|
+ if (!a || !b)
|
|
+ return 0;
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+/*
|
|
+ * See UEFI spec (section 3.1.2, about short-form device-paths..
|
|
+ * tl;dr: we can have a device-path that starts with a USB WWID
|
|
+ * or USB Class node, and a few other cases which don't encode
|
|
+ * the full device path with bus hierarchy:
|
|
+ *
|
|
+ * - MESSAGING:USB_WWID
|
|
+ * - MESSAGING:USB_CLASS
|
|
+ * - MEDIA:FILE_PATH
|
|
+ * - MEDIA:HARD_DRIVE
|
|
+ * - MESSAGING:URI
|
|
+ */
|
|
+static struct efi_device_path *shorten_path(struct efi_device_path *dp)
|
|
+{
|
|
+ while (dp) {
|
|
+ /*
|
|
+ * TODO: Add MESSAGING:USB_WWID and MESSAGING:URI..
|
|
+ * in practice fallback.efi just uses MEDIA:HARD_DRIVE
|
|
+ * so not sure when we would see these other cases.
|
|
+ */
|
|
+ if (EFI_DP_TYPE(dp, MESSAGING_DEVICE, MSG_USB_CLASS) ||
|
|
+ EFI_DP_TYPE(dp, MEDIA_DEVICE, HARD_DRIVE_PATH) ||
|
|
+ EFI_DP_TYPE(dp, MEDIA_DEVICE, FILE_PATH))
|
|
+ return dp;
|
|
+
|
|
+ dp = efi_dp_next(dp);
|
|
+ }
|
|
+
|
|
+ return dp;
|
|
+}
|
|
+
|
|
+static struct efi_object *find_obj(struct efi_device_path *dp, bool short_path)
|
|
+{
|
|
+ struct efi_object *efiobj;
|
|
+
|
|
+ list_for_each_entry(efiobj, &efi_obj_list, link) {
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) {
|
|
+ struct efi_handler *handler = &efiobj->protocols[i];
|
|
+ struct efi_device_path *obj_dp;
|
|
+ efi_status_t ret;
|
|
+
|
|
+ if (!handler->guid)
|
|
+ break;
|
|
+
|
|
+ if (guidcmp(handler->guid, &efi_guid_device_path))
|
|
+ continue;
|
|
+
|
|
+ ret = efi_get_protocol(efiobj, handler, (void **)&obj_dp);
|
|
+ if (ret != EFI_SUCCESS)
|
|
+ continue;
|
|
+
|
|
+ do {
|
|
+ if (efi_dp_match(dp, obj_dp) == 0)
|
|
+ return efiobj;
|
|
+
|
|
+ obj_dp = shorten_path(efi_dp_next(obj_dp));
|
|
+ } while (short_path && obj_dp);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+
|
|
+/* Find an efiobj from device-path */
|
|
+struct efi_object *efi_dp_find_obj(struct efi_device_path *dp)
|
|
+{
|
|
+ struct efi_object *efiobj;
|
|
+
|
|
+ efiobj = find_obj(dp, false);
|
|
+
|
|
+ if (!efiobj)
|
|
+ efiobj = find_obj(dp, true);
|
|
+
|
|
+ return efiobj;
|
|
+}
|
|
+
|
|
+/* return size not including End node: */
|
|
+unsigned efi_dp_size(struct efi_device_path *dp)
|
|
+{
|
|
+ unsigned sz = 0;
|
|
+
|
|
+ while (dp) {
|
|
+ sz += dp->length;
|
|
+ dp = efi_dp_next(dp);
|
|
+ }
|
|
+
|
|
+ return sz;
|
|
+}
|
|
+
|
|
+struct efi_device_path *efi_dp_dup(struct efi_device_path *dp)
|
|
+{
|
|
+ struct efi_device_path *ndp;
|
|
+ unsigned sz = efi_dp_size(dp) + sizeof(struct efi_device_path);
|
|
+
|
|
+ ndp = malloc(sz);
|
|
+ memcpy(ndp, dp, sz);
|
|
+
|
|
+ return ndp;
|
|
+}
|
|
+
|
|
+#ifdef CONFIG_DM
|
|
+/* size of device-path not including END node for device and all parents
|
|
+ * up to the root device.
|
|
+ */
|
|
+static unsigned dp_size(struct udevice *dev)
|
|
+{
|
|
+ if (!dev || !dev->driver)
|
|
+ return sizeof(ROOT);
|
|
+
|
|
+ switch (dev->driver->id) {
|
|
+ case UCLASS_ROOT:
|
|
+ case UCLASS_SIMPLE_BUS:
|
|
+ /* stop traversing parents at this point: */
|
|
+ return sizeof(ROOT);
|
|
+ case UCLASS_MMC:
|
|
+ return dp_size(dev->parent) + sizeof(struct efi_device_path_sd_mmc_path);
|
|
+ case UCLASS_MASS_STORAGE:
|
|
+ case UCLASS_USB_HUB:
|
|
+ return dp_size(dev->parent) + sizeof(struct efi_device_path_usb_class);
|
|
+ default:
|
|
+ /* just skip over unknown classes: */
|
|
+ return dp_size(dev->parent);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void *dp_fill(void *buf, struct udevice *dev)
|
|
+{
|
|
+ if (!dev || !dev->driver)
|
|
+ return buf;
|
|
+
|
|
+ switch (dev->driver->id) {
|
|
+ case UCLASS_ROOT:
|
|
+ case UCLASS_SIMPLE_BUS: {
|
|
+ /* stop traversing parents at this point: */
|
|
+ struct efi_device_path_acpi_path *adp = buf;
|
|
+ *adp = ROOT;
|
|
+ return &adp[1];
|
|
+ }
|
|
+#if defined(CONFIG_DM_MMC) && defined (CONFIG_MMC)
|
|
+ case UCLASS_MMC: {
|
|
+ struct efi_device_path_sd_mmc_path *sddp =
|
|
+ dp_fill(buf, dev->parent);
|
|
+ struct mmc *mmc = mmc_get_mmc_dev(dev);
|
|
+ struct blk_desc *desc = mmc_get_blk_desc(mmc);
|
|
+
|
|
+ sddp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
|
|
+ sddp->dp.sub_type = (desc->if_type == IF_TYPE_MMC) ?
|
|
+ DEVICE_PATH_SUB_TYPE_MSG_MMC :
|
|
+ DEVICE_PATH_SUB_TYPE_MSG_SD;
|
|
+ sddp->dp.length = sizeof(*sddp);
|
|
+ sddp->slot_number = 0; // XXX ???
|
|
+
|
|
+ return &sddp[1];
|
|
+ }
|
|
+#endif
|
|
+ case UCLASS_MASS_STORAGE:
|
|
+ case UCLASS_USB_HUB: {
|
|
+ struct efi_device_path_usb_class *udp =
|
|
+ dp_fill(buf, dev->parent);
|
|
+ struct usb_device *udev = dev_get_parent_priv(dev);
|
|
+ struct usb_device_descriptor *desc = &udev->descriptor;
|
|
+
|
|
+ udp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
|
|
+ udp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_USB_CLASS;
|
|
+ udp->dp.length = sizeof(*udp);
|
|
+ udp->vendor_id = desc->idVendor;
|
|
+ udp->product_id = desc->idProduct;
|
|
+ udp->device_class = desc->bDeviceClass;
|
|
+ udp->device_subclass = desc->bDeviceSubClass;
|
|
+ udp->device_protocol = desc->bDeviceProtocol;
|
|
+
|
|
+ return &udp[1];
|
|
+ }
|
|
+ default:
|
|
+ debug("unhandled device class: %s (%u)\n",
|
|
+ dev->name, dev->driver->id);
|
|
+ return dp_fill(buf, dev->parent);
|
|
+ }
|
|
+}
|
|
+
|
|
+/* Construct a device-path from a device: */
|
|
+struct efi_device_path *efi_dp_from_dev(struct udevice *dev)
|
|
+{
|
|
+ void *buf, *start;
|
|
+
|
|
+ start = buf = calloc(1, dp_size(dev) + sizeof(END));
|
|
+ buf = dp_fill(buf, dev);
|
|
+ *((struct efi_device_path *)buf) = END;
|
|
+
|
|
+ return start;
|
|
+}
|
|
+#endif
|
|
+
|
|
+static unsigned dp_part_size(struct blk_desc *desc, int part)
|
|
+{
|
|
+ unsigned dpsize;
|
|
+
|
|
+#ifdef CONFIG_BLK
|
|
+ dpsize = dp_size(desc->bdev->parent);
|
|
+#else
|
|
+ dpsize = sizeof(ROOT) + sizeof(struct efi_device_path_file_path);
|
|
+#endif
|
|
+
|
|
+ if (part == 0) /* the actual disk, not a partition */
|
|
+ return dpsize;
|
|
+
|
|
+ if (desc->part_type == PART_TYPE_ISO) {
|
|
+ dpsize += sizeof(struct efi_device_path_cdrom_path);
|
|
+ } else {
|
|
+ dpsize += sizeof(struct efi_device_path_hard_drive_path);
|
|
+ }
|
|
+
|
|
+ return dpsize;
|
|
+}
|
|
+
|
|
+static void *dp_part_fill(void *buf, struct blk_desc *desc, int part)
|
|
+{
|
|
+ disk_partition_t info;
|
|
+
|
|
+#ifdef CONFIG_BLK
|
|
+ buf = dp_fill(buf, desc->bdev->parent);
|
|
+#else
|
|
+ struct efi_device_path_file_path *fp;
|
|
+ char devname[32] = { 0 }; /* fp->str is u16[32] long */
|
|
+
|
|
+ snprintf(devname, sizeof(devname), "%d.%d.%d", desc->if_type,
|
|
+ desc->devnum, part);
|
|
+
|
|
+ memcpy(buf, &ROOT, sizeof(ROOT));
|
|
+ buf += sizeof(ROOT);
|
|
+
|
|
+ fp = buf;
|
|
+ fp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
|
|
+ fp->dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH;
|
|
+ fp->dp.length = sizeof(*fp);
|
|
+ ascii2unicode(fp->str, devname);
|
|
+ buf = &fp[1];
|
|
+#endif
|
|
+
|
|
+ if (part == 0) /* the actual disk, not a partition */
|
|
+ return buf;
|
|
+
|
|
+ part_get_info(desc, part, &info);
|
|
+
|
|
+ if (desc->part_type == PART_TYPE_ISO) {
|
|
+ struct efi_device_path_cdrom_path *cddp = buf;
|
|
+
|
|
+ cddp->boot_entry = part - 1;
|
|
+ cddp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
|
|
+ cddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_CDROM_PATH;
|
|
+ cddp->dp.length = sizeof (*cddp);
|
|
+ cddp->partition_start = info.start;
|
|
+ cddp->partition_end = info.size;
|
|
+
|
|
+ buf = &cddp[1];
|
|
+ } else {
|
|
+ struct efi_device_path_hard_drive_path *hddp = buf;
|
|
+
|
|
+ hddp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
|
|
+ hddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH;
|
|
+ hddp->dp.length = sizeof (*hddp);
|
|
+ hddp->partition_number = part - 1;
|
|
+ hddp->partition_start = info.start;
|
|
+ hddp->partition_end = info.size;
|
|
+ if (desc->part_type == PART_TYPE_EFI)
|
|
+ hddp->partmap_type = 2;
|
|
+ else
|
|
+ hddp->partmap_type = 1;
|
|
+ hddp->signature_type = desc->sig_type;
|
|
+ if (hddp->signature_type != 0)
|
|
+ memcpy(hddp->partition_signature, &desc->guid_sig,
|
|
+ sizeof(hddp->partition_signature));
|
|
+
|
|
+ buf = &hddp[1];
|
|
+ }
|
|
+
|
|
+ return buf;
|
|
+}
|
|
+
|
|
+
|
|
+/* Construct a device-path from a partition on a blk device: */
|
|
+struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part)
|
|
+{
|
|
+ void *buf, *start;
|
|
+
|
|
+ start = buf = calloc(1, dp_part_size(desc, part) + sizeof(END));
|
|
+
|
|
+ buf = dp_part_fill(buf, desc, part);
|
|
+
|
|
+ *((struct efi_device_path *)buf) = END;
|
|
+
|
|
+ return start;
|
|
+}
|
|
+
|
|
+/* convert path to an UEFI style path (ie. DOS style backslashes and utf16) */
|
|
+static void path_to_uefi(u16 *uefi, const char *path)
|
|
+{
|
|
+ while (*path) {
|
|
+ char c = *(path++);
|
|
+ if (c == '/')
|
|
+ c = '\\';
|
|
+ *(uefi++) = c;
|
|
+ }
|
|
+ *uefi = '\0';
|
|
+}
|
|
+
|
|
+/*
|
|
+ * If desc is NULL, this creates a path with only the file component,
|
|
+ * otherwise it creates a full path with both device and file components
|
|
+ */
|
|
+struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part,
|
|
+ const char *path)
|
|
+{
|
|
+ struct efi_device_path_file_path *fp;
|
|
+ void *buf, *start;
|
|
+ unsigned dpsize = 0, fpsize;
|
|
+
|
|
+ if (desc)
|
|
+ dpsize = dp_part_size(desc, part);
|
|
+
|
|
+ // TODO efi_device_path_file_path should be variable length:
|
|
+ fpsize = sizeof(struct efi_device_path) + 2 * (strlen(path) + 1);
|
|
+ dpsize += fpsize;
|
|
+
|
|
+ start = buf = calloc(1, dpsize + sizeof(END));
|
|
+
|
|
+ if (desc)
|
|
+ buf = dp_part_fill(buf, desc, part);
|
|
+
|
|
+ /* add file-path: */
|
|
+ fp = buf;
|
|
+ fp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
|
|
+ fp->dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH;
|
|
+ fp->dp.length = fpsize;
|
|
+ path_to_uefi(fp->str, path);
|
|
+ buf += fpsize;
|
|
+
|
|
+ *((struct efi_device_path *)buf) = END;
|
|
+
|
|
+ return start;
|
|
+}
|
|
+
|
|
+#ifdef CONFIG_NET
|
|
+struct efi_device_path *efi_dp_from_eth(void)
|
|
+{
|
|
+ struct efi_device_path_mac_addr *ndp;
|
|
+ void *buf, *start;
|
|
+ unsigned dpsize = 0;
|
|
+
|
|
+ assert(eth_get_dev());
|
|
+
|
|
+#ifdef CONFIG_DM_ETH
|
|
+ dpsize += dp_size(eth_get_dev());
|
|
+#else
|
|
+ dpsize += sizeof(ROOT);
|
|
+#endif
|
|
+ dpsize += sizeof(*ndp);
|
|
+
|
|
+ start = buf = calloc(1, dpsize + sizeof(END));
|
|
+
|
|
+#ifdef CONFIG_DM_ETH
|
|
+ buf = dp_fill(buf, eth_get_dev());
|
|
+#else
|
|
+ memcpy(buf, &ROOT, sizeof(ROOT));
|
|
+ buf += sizeof(ROOT);
|
|
+#endif
|
|
+
|
|
+ ndp = buf;
|
|
+ ndp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
|
|
+ ndp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR;
|
|
+ ndp->dp.length = sizeof(*ndp);
|
|
+ memcpy(ndp->mac.addr, eth_get_ethaddr(), ARP_HLEN);
|
|
+ buf = &ndp[1];
|
|
+
|
|
+ *((struct efi_device_path *)buf) = END;
|
|
+
|
|
+ return start;
|
|
+}
|
|
+#endif
|
|
+
|
|
+/*
|
|
+ * Helper to split a full device path (containing both device and file
|
|
+ * parts) into it's constituent parts.
|
|
+ */
|
|
+void efi_dp_split_file_path(struct efi_device_path *full_path,
|
|
+ struct efi_device_path **device_path,
|
|
+ struct efi_device_path **file_path)
|
|
+{
|
|
+ struct efi_device_path *p, *dp, *fp;
|
|
+
|
|
+ dp = efi_dp_dup(full_path);
|
|
+ p = dp;
|
|
+ while (!EFI_DP_TYPE(p, MEDIA_DEVICE, FILE_PATH))
|
|
+ p = efi_dp_next(p);
|
|
+ fp = efi_dp_dup(p);
|
|
+
|
|
+ p->type = DEVICE_PATH_TYPE_END;
|
|
+ p->sub_type = DEVICE_PATH_SUB_TYPE_END;
|
|
+ p->length = sizeof(*p);
|
|
+
|
|
+ *device_path = dp;
|
|
+ *file_path = fp;
|
|
+}
|
|
--
|
|
2.13.3
|
|
|
|
From 5685374b81f9ff62419a53fb2fd6f140add56def Mon Sep 17 00:00:00 2001
|
|
From: Rob Clark <robdclark@gmail.com>
|
|
Date: Mon, 31 Jul 2017 09:07:49 -0400
|
|
Subject: [PATCH 06/13] efi_loader: drop redundant efi_device_path_protocol
|
|
|
|
This is really the same thing as the efi_device_path struct.
|
|
|
|
Signed-off-by: Rob Clark <robdclark@gmail.com>
|
|
---
|
|
include/efi_api.h | 12 ++----------
|
|
lib/efi_loader/efi_device_path_to_text.c | 13 ++++++++-----
|
|
2 files changed, 10 insertions(+), 15 deletions(-)
|
|
|
|
diff --git a/include/efi_api.h b/include/efi_api.h
|
|
index 0ebe8d0283..7691a054a5 100644
|
|
--- a/include/efi_api.h
|
|
+++ b/include/efi_api.h
|
|
@@ -478,22 +478,14 @@ struct efi_console_control_protocol
|
|
EFI_GUID(0x8b843e20, 0x8132, 0x4852, \
|
|
0x90, 0xcc, 0x55, 0x1a, 0x4e, 0x4a, 0x7f, 0x1c)
|
|
|
|
-struct efi_device_path_protocol
|
|
-{
|
|
- uint8_t type;
|
|
- uint8_t sub_type;
|
|
- uint16_t length;
|
|
- uint8_t data[];
|
|
-};
|
|
-
|
|
struct efi_device_path_to_text_protocol
|
|
{
|
|
uint16_t *(EFIAPI *convert_device_node_to_text)(
|
|
- struct efi_device_path_protocol *device_node,
|
|
+ struct efi_device_path *device_node,
|
|
bool display_only,
|
|
bool allow_shortcuts);
|
|
uint16_t *(EFIAPI *convert_device_path_to_text)(
|
|
- struct efi_device_path_protocol *device_path,
|
|
+ struct efi_device_path *device_path,
|
|
bool display_only,
|
|
bool allow_shortcuts);
|
|
};
|
|
diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c
|
|
index 4b2f43f0c8..f9d071ac50 100644
|
|
--- a/lib/efi_loader/efi_device_path_to_text.c
|
|
+++ b/lib/efi_loader/efi_device_path_to_text.c
|
|
@@ -16,7 +16,7 @@ const efi_guid_t efi_guid_device_path_to_text_protocol =
|
|
EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID;
|
|
|
|
static uint16_t *efi_convert_device_node_to_text(
|
|
- struct efi_device_path_protocol *device_node,
|
|
+ struct efi_device_path *device_node,
|
|
bool display_only,
|
|
bool allow_shortcuts)
|
|
{
|
|
@@ -55,15 +55,18 @@ static uint16_t *efi_convert_device_node_to_text(
|
|
break;
|
|
case DEVICE_PATH_TYPE_MEDIA_DEVICE:
|
|
switch (device_node->sub_type) {
|
|
- case DEVICE_PATH_SUB_TYPE_FILE_PATH:
|
|
+ case DEVICE_PATH_SUB_TYPE_FILE_PATH: {
|
|
+ struct efi_device_path_file_path *fp =
|
|
+ (struct efi_device_path_file_path *)device_node;
|
|
buffer_size = device_node->length - 4;
|
|
r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES,
|
|
buffer_size, (void **) &buffer);
|
|
if (r != EFI_SUCCESS)
|
|
return NULL;
|
|
- memcpy(buffer, device_node->data, buffer_size);
|
|
+ memcpy(buffer, fp->str, buffer_size);
|
|
break;
|
|
}
|
|
+ }
|
|
break;
|
|
}
|
|
|
|
@@ -89,7 +92,7 @@ static uint16_t *efi_convert_device_node_to_text(
|
|
}
|
|
|
|
static uint16_t EFIAPI *efi_convert_device_node_to_text_ext(
|
|
- struct efi_device_path_protocol *device_node,
|
|
+ struct efi_device_path *device_node,
|
|
bool display_only,
|
|
bool allow_shortcuts)
|
|
{
|
|
@@ -105,7 +108,7 @@ static uint16_t EFIAPI *efi_convert_device_node_to_text_ext(
|
|
}
|
|
|
|
static uint16_t EFIAPI *efi_convert_device_path_to_text(
|
|
- struct efi_device_path_protocol *device_path,
|
|
+ struct efi_device_path *device_path,
|
|
bool display_only,
|
|
bool allow_shortcuts)
|
|
{
|
|
--
|
|
2.13.3
|
|
|
|
From 87811659b781575024ae3499f5b5f6d1ca4aefb0 Mon Sep 17 00:00:00 2001
|
|
From: Rob Clark <robdclark@gmail.com>
|
|
Date: Mon, 31 Jul 2017 11:25:49 -0400
|
|
Subject: [PATCH 07/13] efi_loader: add guidstr helper
|
|
|
|
There are a couple places where we'll need GUID -> string. So add a
|
|
helper.
|
|
|
|
Signed-off-by: Rob Clark <robdclark@gmail.com>
|
|
---
|
|
include/efi_loader.h | 15 +++++++++++++++
|
|
1 file changed, 15 insertions(+)
|
|
|
|
diff --git a/include/efi_loader.h b/include/efi_loader.h
|
|
index 1028bfb75d..e6c46f713e 100644
|
|
--- a/include/efi_loader.h
|
|
+++ b/include/efi_loader.h
|
|
@@ -239,6 +239,21 @@ static inline int guidcmp(const efi_guid_t *g1, const efi_guid_t *g2)
|
|
return memcmp(g1, g2, sizeof(efi_guid_t));
|
|
}
|
|
|
|
+static inline int guidstr(char *s, const efi_guid_t *g)
|
|
+{
|
|
+ /* unpacked-guid, otherwise we have to have to consider endianess */
|
|
+ struct {
|
|
+ uint32_t data1;
|
|
+ uint16_t data2;
|
|
+ uint16_t data3;
|
|
+ uint8_t data4[8];
|
|
+ } *ug = (void *)g;
|
|
+ return sprintf(s, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
|
+ ug->data1, ug->data2, ug->data3, ug->data4[0],
|
|
+ ug->data4[1], ug->data4[2], ug->data4[3], ug->data4[4],
|
|
+ ug->data4[5], ug->data4[6], ug->data4[7]);
|
|
+}
|
|
+
|
|
/*
|
|
* Use these to indicate that your code / data should go into the EFI runtime
|
|
* section and thus still be available when the OS is running
|
|
--
|
|
2.13.3
|
|
|
|
From 3cbfcc19afa80f28819630e2ff1e9b0ef71f1cce Mon Sep 17 00:00:00 2001
|
|
From: Rob Clark <robdclark@gmail.com>
|
|
Date: Mon, 31 Jul 2017 11:28:01 -0400
|
|
Subject: [PATCH 08/13] efi_loader: flesh out device-path to text
|
|
|
|
It needs to handle more device-path node types, and also multiple levels
|
|
of path hierarchy. To simplify this, initially construct utf8 string to
|
|
a temporary buffer, and then allocate the real utf16 buffer that is
|
|
returned. This should be mostly for debugging or at least not critical-
|
|
path so an extra copy won't hurt, and is saner than the alternative.
|
|
|
|
Signed-off-by: Rob Clark <robdclark@gmail.com>
|
|
---
|
|
include/efi_api.h | 1 +
|
|
include/efi_loader.h | 2 +
|
|
lib/efi_loader/efi_device_path_to_text.c | 223 ++++++++++++++++++++++---------
|
|
3 files changed, 163 insertions(+), 63 deletions(-)
|
|
|
|
diff --git a/include/efi_api.h b/include/efi_api.h
|
|
index 7691a054a5..dd79cace32 100644
|
|
--- a/include/efi_api.h
|
|
+++ b/include/efi_api.h
|
|
@@ -295,6 +295,7 @@ struct efi_mac_addr {
|
|
|
|
#define EFI_PNP_ID(ID) (u32)(((ID) << 16) | 0x41D0)
|
|
#define EISA_PNP_ID(ID) EFI_PNP_ID(ID)
|
|
+#define EISA_PNP_NUM(ID) ((ID) >> 16)
|
|
|
|
struct efi_device_path_acpi_path {
|
|
struct efi_device_path dp;
|
|
diff --git a/include/efi_loader.h b/include/efi_loader.h
|
|
index e6c46f713e..1ab4af0f88 100644
|
|
--- a/include/efi_loader.h
|
|
+++ b/include/efi_loader.h
|
|
@@ -59,6 +59,8 @@ extern struct efi_simple_input_interface efi_con_in;
|
|
extern const struct efi_console_control_protocol efi_console_control;
|
|
extern const struct efi_device_path_to_text_protocol efi_device_path_to_text;
|
|
|
|
+uint16_t *efi_dp_str(struct efi_device_path *dp);
|
|
+
|
|
extern const efi_guid_t efi_guid_console_control;
|
|
extern const efi_guid_t efi_guid_device_path;
|
|
extern const efi_guid_t efi_guid_loaded_image;
|
|
diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c
|
|
index f9d071ac50..d10a1319af 100644
|
|
--- a/lib/efi_loader/efi_device_path_to_text.c
|
|
+++ b/lib/efi_loader/efi_device_path_to_text.c
|
|
@@ -15,82 +15,179 @@
|
|
const efi_guid_t efi_guid_device_path_to_text_protocol =
|
|
EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID;
|
|
|
|
-static uint16_t *efi_convert_device_node_to_text(
|
|
- struct efi_device_path *device_node,
|
|
- bool display_only,
|
|
- bool allow_shortcuts)
|
|
+static char *dp_unknown(char *s, struct efi_device_path *dp)
|
|
{
|
|
- unsigned long buffer_size;
|
|
- efi_status_t r;
|
|
- uint16_t *buffer = NULL;
|
|
- int i;
|
|
+ s += sprintf(s, "/UNKNOWN(%04x,%04x)", dp->type, dp->sub_type);
|
|
+ return s;
|
|
+}
|
|
|
|
- switch (device_node->type) {
|
|
- case DEVICE_PATH_TYPE_END:
|
|
- return NULL;
|
|
- case DEVICE_PATH_TYPE_MESSAGING_DEVICE:
|
|
- switch (device_node->sub_type) {
|
|
- case DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR: {
|
|
- struct efi_device_path_mac_addr *dp =
|
|
- (struct efi_device_path_mac_addr *)device_node;
|
|
-
|
|
- if (dp->if_type != 0 && dp->if_type != 1)
|
|
- break;
|
|
- r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES,
|
|
- 2 * MAC_OUTPUT_LEN,
|
|
- (void **)&buffer);
|
|
- if (r != EFI_SUCCESS)
|
|
- return NULL;
|
|
- sprintf((char *)buffer,
|
|
- "MAC(%02x%02x%02x%02x%02x%02x,0x%1x)",
|
|
- dp->mac.addr[0], dp->mac.addr[1],
|
|
- dp->mac.addr[2], dp->mac.addr[3],
|
|
- dp->mac.addr[4], dp->mac.addr[5],
|
|
- dp->if_type);
|
|
- for (i = MAC_OUTPUT_LEN - 1; i >= 0; --i)
|
|
- buffer[i] = ((uint8_t *)buffer)[i];
|
|
+static char *dp_acpi(char *s, struct efi_device_path *dp)
|
|
+{
|
|
+ switch (dp->sub_type) {
|
|
+ case DEVICE_PATH_SUB_TYPE_ACPI_DEVICE: {
|
|
+ struct efi_device_path_acpi_path *adp =
|
|
+ (struct efi_device_path_acpi_path *)dp;
|
|
+ s += sprintf(s, "/Acpi(PNP%04x", EISA_PNP_NUM(adp->hid));
|
|
+ if (adp->uid)
|
|
+ s += sprintf(s, ",%d", adp->uid);
|
|
+ s += sprintf(s, ")");
|
|
+ break;
|
|
+ }
|
|
+ default:
|
|
+ s = dp_unknown(s, dp);
|
|
+ break;
|
|
+ }
|
|
+ return s;
|
|
+}
|
|
+
|
|
+static char *dp_msging(char *s, struct efi_device_path *dp)
|
|
+{
|
|
+ switch (dp->sub_type) {
|
|
+ case DEVICE_PATH_SUB_TYPE_MSG_USB: {
|
|
+ struct efi_device_path_usb *udp =
|
|
+ (struct efi_device_path_usb *)dp;
|
|
+ s += sprintf(s, "/Usb(0x%x,0x%x)", udp->parent_port_number,
|
|
+ udp->usb_interface);
|
|
+ break;
|
|
+ }
|
|
+ case DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR: {
|
|
+ struct efi_device_path_mac_addr *mdp =
|
|
+ (struct efi_device_path_mac_addr *)dp;
|
|
+
|
|
+ if (mdp->if_type != 0 && mdp->if_type != 1)
|
|
break;
|
|
- }
|
|
- }
|
|
+
|
|
+ s += sprintf(s, "/MAC(%02x%02x%02x%02x%02x%02x,0x%1x)",
|
|
+ mdp->mac.addr[0], mdp->mac.addr[1],
|
|
+ mdp->mac.addr[2], mdp->mac.addr[3],
|
|
+ mdp->mac.addr[4], mdp->mac.addr[5],
|
|
+ mdp->if_type);
|
|
+
|
|
+ break;
|
|
+ }
|
|
+ case DEVICE_PATH_SUB_TYPE_MSG_USB_CLASS: {
|
|
+ struct efi_device_path_usb_class *ucdp =
|
|
+ (struct efi_device_path_usb_class *)dp;
|
|
+
|
|
+ s += sprintf(s, "/USBClass(%x,%x,%x,%x,%x)",
|
|
+ ucdp->vendor_id, ucdp->product_id,
|
|
+ ucdp->device_class, ucdp->device_subclass,
|
|
+ ucdp->device_protocol);
|
|
+
|
|
+ break;
|
|
+ }
|
|
+ case DEVICE_PATH_SUB_TYPE_MSG_SD:
|
|
+ case DEVICE_PATH_SUB_TYPE_MSG_MMC: {
|
|
+ const char *typename =
|
|
+ (dp->sub_type == DEVICE_PATH_SUB_TYPE_MSG_SD) ?
|
|
+ "SDCard" : "MMC";
|
|
+ struct efi_device_path_sd_mmc_path *sddp =
|
|
+ (struct efi_device_path_sd_mmc_path *)dp;
|
|
+ s += sprintf(s, "/%s(Slot%u)", typename, sddp->slot_number);
|
|
+ break;
|
|
+ }
|
|
+ default:
|
|
+ s = dp_unknown(s, dp);
|
|
break;
|
|
- case DEVICE_PATH_TYPE_MEDIA_DEVICE:
|
|
- switch (device_node->sub_type) {
|
|
- case DEVICE_PATH_SUB_TYPE_FILE_PATH: {
|
|
- struct efi_device_path_file_path *fp =
|
|
- (struct efi_device_path_file_path *)device_node;
|
|
- buffer_size = device_node->length - 4;
|
|
- r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES,
|
|
- buffer_size, (void **) &buffer);
|
|
- if (r != EFI_SUCCESS)
|
|
- return NULL;
|
|
- memcpy(buffer, fp->str, buffer_size);
|
|
+ }
|
|
+ return s;
|
|
+}
|
|
+
|
|
+static char *dp_media(char *s, struct efi_device_path *dp)
|
|
+{
|
|
+ switch (dp->sub_type) {
|
|
+ case DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH: {
|
|
+ struct efi_device_path_hard_drive_path *hddp =
|
|
+ (struct efi_device_path_hard_drive_path *)dp;
|
|
+ void *sig = hddp->partition_signature;
|
|
+
|
|
+ switch (hddp->signature_type) {
|
|
+ case SIG_TYPE_MBR:
|
|
+ s += sprintf(s, "/HD(Part%d,Sig%08x)",
|
|
+ hddp->partition_number,
|
|
+ *(uint32_t *)sig);
|
|
break;
|
|
+ case SIG_TYPE_GUID:
|
|
+ s += sprintf(s, "HD(Part%d,Sig", hddp->partition_number);
|
|
+ s += guidstr(s, (efi_guid_t *)sig);
|
|
+ s += sprintf(s, ")");
|
|
+ default:
|
|
+ s += sprintf(s, "/HD(Part%d,MBRType=%02x,SigType=%02x)",
|
|
+ hddp->partition_number, hddp->partmap_type,
|
|
+ hddp->signature_type);
|
|
}
|
|
- }
|
|
+
|
|
+ break;
|
|
+ }
|
|
+ case DEVICE_PATH_SUB_TYPE_CDROM_PATH: {
|
|
+ struct efi_device_path_cdrom_path *cddp =
|
|
+ (struct efi_device_path_cdrom_path *)dp;
|
|
+ s += sprintf(s, "/CDROM(0x%x)", cddp->boot_entry);
|
|
+ break;
|
|
+ }
|
|
+ case DEVICE_PATH_SUB_TYPE_FILE_PATH: {
|
|
+ struct efi_device_path_file_path *fp =
|
|
+ (struct efi_device_path_file_path *)dp;
|
|
+ int slen = (dp->length - sizeof(*dp)) / 2;
|
|
+ s += sprintf(s, "/%-*ls", slen, fp->str);
|
|
+ break;
|
|
+ }
|
|
+ default:
|
|
+ s = dp_unknown(s, dp);
|
|
break;
|
|
}
|
|
+ return s;
|
|
+}
|
|
|
|
- /*
|
|
- * For all node types that we do not yet support return
|
|
- * 'UNKNOWN(type,subtype)'.
|
|
- */
|
|
- if (!buffer) {
|
|
- r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES,
|
|
- 2 * UNKNOWN_OUTPUT_LEN,
|
|
- (void **)&buffer);
|
|
- if (r != EFI_SUCCESS)
|
|
- return NULL;
|
|
- sprintf((char *)buffer,
|
|
- "UNKNOWN(%04x,%04x)",
|
|
- device_node->type,
|
|
- device_node->sub_type);
|
|
- for (i = UNKNOWN_OUTPUT_LEN - 1; i >= 0; --i)
|
|
- buffer[i] = ((uint8_t *)buffer)[i];
|
|
+static uint16_t *efi_convert_device_node_to_text(
|
|
+ struct efi_device_path *dp,
|
|
+ bool display_only,
|
|
+ bool allow_shortcuts)
|
|
+{
|
|
+ unsigned long len;
|
|
+ efi_status_t r;
|
|
+ char buf[512]; /* this ought be be big enough for worst case */
|
|
+ char *str = buf;
|
|
+ uint16_t *out;
|
|
+
|
|
+ while (dp) {
|
|
+ switch (dp->type) {
|
|
+ case DEVICE_PATH_TYPE_ACPI_DEVICE:
|
|
+ str = dp_acpi(str, dp);
|
|
+ break;
|
|
+ case DEVICE_PATH_TYPE_MESSAGING_DEVICE:
|
|
+ str = dp_msging(str, dp);
|
|
+ break;
|
|
+ case DEVICE_PATH_TYPE_MEDIA_DEVICE:
|
|
+ str = dp_media(str, dp);
|
|
+ break;
|
|
+ default:
|
|
+ str = dp_unknown(str, dp);
|
|
+ }
|
|
+
|
|
+ dp = efi_dp_next(dp);
|
|
}
|
|
|
|
- return buffer;
|
|
+ *str++ = '\0';
|
|
+
|
|
+ len = str - buf;
|
|
+ r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, 2 * len, (void **)&out);
|
|
+ if (r != EFI_SUCCESS)
|
|
+ return NULL;
|
|
+
|
|
+ ascii2unicode(out, buf);
|
|
+ out[len - 1] = 0;
|
|
+
|
|
+ return out;
|
|
}
|
|
|
|
+/* helper for debug prints.. efi_free_pool() the result. */
|
|
+uint16_t *efi_dp_str(struct efi_device_path *dp)
|
|
+{
|
|
+ return efi_convert_device_node_to_text(dp, true, true);
|
|
+}
|
|
+
|
|
+
|
|
static uint16_t EFIAPI *efi_convert_device_node_to_text_ext(
|
|
struct efi_device_path *device_node,
|
|
bool display_only,
|
|
--
|
|
2.13.3
|
|
|
|
From 281813fc5f8e13b20201eb4279bb32d296c99930 Mon Sep 17 00:00:00 2001
|
|
From: Rob Clark <robdclark@gmail.com>
|
|
Date: Thu, 27 Jul 2017 14:22:21 -0400
|
|
Subject: [PATCH 09/13] efi_loader: use proper device-paths for partitions
|
|
|
|
Also, create disk objects for the disk itself, in addition to the
|
|
partitions. (UEFI terminology is a bit confusing, a "disk" object is
|
|
really a partition.) This helps grub properly identify the boot device
|
|
since it is trying to match up partition "disk" object with it's parent
|
|
device.
|
|
|
|
Now instead of seeing devices like:
|
|
|
|
/File(sdhci@07864000.blk)/EndEntire
|
|
/File(usb_mass_storage.lun0)/EndEntire
|
|
|
|
You see:
|
|
|
|
/ACPI(133741d0,0)/UnknownMessaging(1d)/EndEntire
|
|
/ACPI(133741d0,0)/UnknownMessaging(1d)/HD(0,800,64000,dd904a8c00000000,1,1)/EndEntire
|
|
/ACPI(133741d0,0)/UnknownMessaging(1d)/HD(1,64800,200000,dd904a8c00000000,1,1)/EndEntire
|
|
/ACPI(133741d0,0)/UnknownMessaging(1d)/HD(2,264800,19a000,dd904a8c00000000,1,1)/EndEntire
|
|
/ACPI(133741d0,0)/USB(0,0)/USB(0,0)/USB(0,0)/EndEntire
|
|
/ACPI(133741d0,0)/USB(0,0)/USB(0,0)/USB(0,0)/HD(0,800,60000,38ca680200000000,1,1)/EndEntire
|
|
/ACPI(133741d0,0)/USB(0,0)/USB(0,0)/USB(0,0)/HD(1,61000,155000,38ca680200000000,1,1)/EndEntire
|
|
/ACPI(133741d0,0)/USB(0,0)/USB(0,0)/USB(0,0)/HD(2,20fa800,1bbf8800,38ca680200000000,1,1)/EndEntire
|
|
/ACPI(133741d0,0)/USB(0,0)/USB(0,0)/USB(0,0)/HD(3,1b6800,1f44000,38ca680200000000,1,1)/EndEntire
|
|
|
|
This is on a board with single USB disk and single sd-card. The
|
|
UnknownMessaging(1d) node in the device-path is the MMC device,
|
|
but grub_efi_print_device_path() hasn't been updated yet for some
|
|
of the newer device-path sub-types.
|
|
|
|
This patch is inspired by a patch originally from Peter Jones, but
|
|
re-worked to use efi_device_path, so it doesn't much resemble the
|
|
original.
|
|
|
|
Signed-off-by: Rob Clark <robdclark@gmail.com>
|
|
---
|
|
lib/efi_loader/efi_disk.c | 54 +++++++++++++++++++++++++++--------------------
|
|
1 file changed, 31 insertions(+), 23 deletions(-)
|
|
|
|
diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
|
|
index ed06485e33..eea65a402a 100644
|
|
--- a/lib/efi_loader/efi_disk.c
|
|
+++ b/lib/efi_loader/efi_disk.c
|
|
@@ -28,11 +28,13 @@ struct efi_disk_obj {
|
|
/* EFI Interface Media descriptor struct, referenced by ops */
|
|
struct efi_block_io_media media;
|
|
/* EFI device path to this block device */
|
|
- struct efi_device_path_file_path *dp;
|
|
+ struct efi_device_path *dp;
|
|
+ /* partition # */
|
|
+ unsigned part;
|
|
/* Offset into disk for simple partitions */
|
|
lbaint_t offset;
|
|
/* Internal block device */
|
|
- const struct blk_desc *desc;
|
|
+ struct blk_desc *desc;
|
|
};
|
|
|
|
static efi_status_t EFIAPI efi_disk_reset(struct efi_block_io *this,
|
|
@@ -172,26 +174,26 @@ static const struct efi_block_io block_io_disk_template = {
|
|
|
|
static void efi_disk_add_dev(const char *name,
|
|
const char *if_typename,
|
|
- const struct blk_desc *desc,
|
|
+ struct blk_desc *desc,
|
|
int dev_index,
|
|
- lbaint_t offset)
|
|
+ lbaint_t offset,
|
|
+ unsigned part)
|
|
{
|
|
struct efi_disk_obj *diskobj;
|
|
- struct efi_device_path_file_path *dp;
|
|
- int objlen = sizeof(*diskobj) + (sizeof(*dp) * 2);
|
|
|
|
/* Don't add empty devices */
|
|
if (!desc->lba)
|
|
return;
|
|
|
|
- diskobj = calloc(1, objlen);
|
|
+ diskobj = calloc(1, sizeof(*diskobj));
|
|
|
|
/* Fill in object data */
|
|
- dp = (void *)&diskobj[1];
|
|
+ diskobj->dp = efi_dp_from_part(desc, part);
|
|
+ diskobj->part = part;
|
|
diskobj->parent.protocols[0].guid = &efi_block_io_guid;
|
|
diskobj->parent.protocols[0].protocol_interface = &diskobj->ops;
|
|
diskobj->parent.protocols[1].guid = &efi_guid_device_path;
|
|
- diskobj->parent.protocols[1].protocol_interface = dp;
|
|
+ diskobj->parent.protocols[1].protocol_interface = diskobj->dp;
|
|
diskobj->parent.handle = diskobj;
|
|
diskobj->ops = block_io_disk_template;
|
|
diskobj->ifname = if_typename;
|
|
@@ -207,17 +209,6 @@ static void efi_disk_add_dev(const char *name,
|
|
diskobj->media.last_block = desc->lba - offset;
|
|
diskobj->ops.media = &diskobj->media;
|
|
|
|
- /* Fill in device path */
|
|
- diskobj->dp = dp;
|
|
- dp[0].dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
|
|
- dp[0].dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH;
|
|
- dp[0].dp.length = sizeof(*dp);
|
|
- ascii2unicode(dp[0].str, name);
|
|
-
|
|
- dp[1].dp.type = DEVICE_PATH_TYPE_END;
|
|
- dp[1].dp.sub_type = DEVICE_PATH_SUB_TYPE_END;
|
|
- dp[1].dp.length = sizeof(*dp);
|
|
-
|
|
/* Hook up to the device list */
|
|
list_add_tail(&diskobj->parent.link, &efi_obj_list);
|
|
}
|
|
@@ -236,14 +227,18 @@ static int efi_disk_create_eltorito(struct blk_desc *desc,
|
|
if (desc->part_type != PART_TYPE_ISO)
|
|
return 0;
|
|
|
|
+ /* and devices for each partition: */
|
|
while (!part_get_info(desc, part, &info)) {
|
|
snprintf(devname, sizeof(devname), "%s:%d", pdevname,
|
|
part);
|
|
efi_disk_add_dev(devname, if_typename, desc, diskid,
|
|
- info.start);
|
|
+ info.start, part);
|
|
part++;
|
|
disks++;
|
|
}
|
|
+
|
|
+ /* ... and add block device: */
|
|
+ efi_disk_add_dev(devname, if_typename, desc, diskid, 0, 0);
|
|
#endif
|
|
|
|
return disks;
|
|
@@ -271,9 +266,22 @@ int efi_disk_register(void)
|
|
uclass_next_device_check(&dev)) {
|
|
struct blk_desc *desc = dev_get_uclass_platdata(dev);
|
|
const char *if_typename = dev->driver->name;
|
|
+ disk_partition_t info;
|
|
+ int part = 1;
|
|
|
|
printf("Scanning disk %s...\n", dev->name);
|
|
- efi_disk_add_dev(dev->name, if_typename, desc, desc->devnum, 0);
|
|
+
|
|
+ /* add devices for each partition: */
|
|
+ while (!part_get_info(desc, part, &info)) {
|
|
+ efi_disk_add_dev(dev->name, if_typename, desc,
|
|
+ desc->devnum, 0, part);
|
|
+ part++;
|
|
+ }
|
|
+
|
|
+ /* ... and add block device: */
|
|
+ efi_disk_add_dev(dev->name, if_typename, desc,
|
|
+ desc->devnum, 0, 0);
|
|
+
|
|
disks++;
|
|
|
|
/*
|
|
@@ -309,7 +317,7 @@ int efi_disk_register(void)
|
|
|
|
snprintf(devname, sizeof(devname), "%s%d",
|
|
if_typename, i);
|
|
- efi_disk_add_dev(devname, if_typename, desc, i, 0);
|
|
+ efi_disk_add_dev(devname, if_typename, desc, i, 0, 0);
|
|
disks++;
|
|
|
|
/*
|
|
--
|
|
2.13.3
|
|
|
|
From c72b667b6ea2f3e2483a0ec0ac4f443d9e09863b Mon Sep 17 00:00:00 2001
|
|
From: Rob Clark <robdclark@gmail.com>
|
|
Date: Thu, 27 Jul 2017 16:50:45 -0400
|
|
Subject: [PATCH 10/13] efi_loader: use proper device-paths for net
|
|
|
|
Signed-off-by: Rob Clark <robdclark@gmail.com>
|
|
---
|
|
include/efi_loader.h | 2 +-
|
|
lib/efi_loader/efi_net.c | 24 +++---------------------
|
|
2 files changed, 4 insertions(+), 22 deletions(-)
|
|
|
|
diff --git a/include/efi_loader.h b/include/efi_loader.h
|
|
index 1ab4af0f88..c783d0da51 100644
|
|
--- a/include/efi_loader.h
|
|
+++ b/include/efi_loader.h
|
|
@@ -143,7 +143,7 @@ int efi_disk_register(void);
|
|
/* Called by bootefi to make GOP (graphical) interface available */
|
|
int efi_gop_register(void);
|
|
/* Called by bootefi to make the network interface available */
|
|
-int efi_net_register(void **handle);
|
|
+int efi_net_register(void);
|
|
/* Called by bootefi to make SMBIOS tables available */
|
|
void efi_smbios_register(void);
|
|
|
|
diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c
|
|
index 0b949d86e8..91f1e4a69e 100644
|
|
--- a/lib/efi_loader/efi_net.c
|
|
+++ b/lib/efi_loader/efi_net.c
|
|
@@ -26,9 +26,6 @@ struct efi_net_obj {
|
|
/* EFI Interface callback struct for network */
|
|
struct efi_simple_network net;
|
|
struct efi_simple_network_mode net_mode;
|
|
- /* Device path to the network adapter */
|
|
- struct efi_device_path_mac_addr dp_mac;
|
|
- struct efi_device_path_file_path dp_end;
|
|
/* PXE struct to transmit dhcp data */
|
|
struct efi_pxe pxe;
|
|
struct efi_pxe_mode pxe_mode;
|
|
@@ -210,19 +207,9 @@ void efi_net_set_dhcp_ack(void *pkt, int len)
|
|
}
|
|
|
|
/* This gets called from do_bootefi_exec(). */
|
|
-int efi_net_register(void **handle)
|
|
+int efi_net_register(void)
|
|
{
|
|
struct efi_net_obj *netobj;
|
|
- struct efi_device_path_mac_addr dp_net = {
|
|
- .dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE,
|
|
- .dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR,
|
|
- .dp.length = sizeof(dp_net),
|
|
- };
|
|
- struct efi_device_path_file_path dp_end = {
|
|
- .dp.type = DEVICE_PATH_TYPE_END,
|
|
- .dp.sub_type = DEVICE_PATH_SUB_TYPE_END,
|
|
- .dp.length = sizeof(dp_end),
|
|
- };
|
|
|
|
if (!eth_get_dev()) {
|
|
/* No eth device active, don't expose any */
|
|
@@ -236,7 +223,8 @@ int efi_net_register(void **handle)
|
|
netobj->parent.protocols[0].guid = &efi_net_guid;
|
|
netobj->parent.protocols[0].protocol_interface = &netobj->net;
|
|
netobj->parent.protocols[1].guid = &efi_guid_device_path;
|
|
- netobj->parent.protocols[1].protocol_interface = &netobj->dp_mac;
|
|
+ netobj->parent.protocols[1].protocol_interface =
|
|
+ efi_dp_from_eth();
|
|
netobj->parent.protocols[2].guid = &efi_pxe_guid;
|
|
netobj->parent.protocols[2].protocol_interface = &netobj->pxe;
|
|
netobj->parent.handle = &netobj->net;
|
|
@@ -255,9 +243,6 @@ int efi_net_register(void **handle)
|
|
netobj->net.receive = efi_net_receive;
|
|
netobj->net.mode = &netobj->net_mode;
|
|
netobj->net_mode.state = EFI_NETWORK_STARTED;
|
|
- netobj->dp_mac = dp_net;
|
|
- netobj->dp_end = dp_end;
|
|
- memcpy(netobj->dp_mac.mac.addr, eth_get_ethaddr(), 6);
|
|
memcpy(netobj->net_mode.current_address.mac_addr, eth_get_ethaddr(), 6);
|
|
netobj->net_mode.max_packet_size = PKTSIZE;
|
|
|
|
@@ -268,8 +253,5 @@ int efi_net_register(void **handle)
|
|
/* Hook net up to the device list */
|
|
list_add_tail(&netobj->parent.link, &efi_obj_list);
|
|
|
|
- if (handle)
|
|
- *handle = &netobj->net;
|
|
-
|
|
return 0;
|
|
}
|
|
--
|
|
2.13.3
|
|
|
|
From 52f916744dc8ac73f00480a906c4239160a007ad Mon Sep 17 00:00:00 2001
|
|
From: Rob Clark <robdclark@gmail.com>
|
|
Date: Thu, 27 Jul 2017 15:18:18 -0400
|
|
Subject: [PATCH 11/13] efi_loader: refactor boot device and loaded_image
|
|
handling
|
|
|
|
Get rid of the hacky fake boot-device and duplicate device-path
|
|
constructing (which needs to match what efi_disk and efi_net do).
|
|
Instead convert over to use efi_device_path helpers to construct
|
|
device-paths, and use that to look up the actual boot device.
|
|
|
|
Also, extract out a helper to plug things in properly to the
|
|
loaded_image. In a following patch we'll want to re-use this in
|
|
efi_load_image() to handle the case of loading an image from a
|
|
file_path.
|
|
|
|
Signed-off-by: Rob Clark <robdclark@gmail.com>
|
|
---
|
|
cmd/bootefi.c | 201 +++++++++++++-----------------------------
|
|
include/efi_loader.h | 3 +
|
|
lib/efi_loader/efi_boottime.c | 35 ++++++++
|
|
3 files changed, 97 insertions(+), 142 deletions(-)
|
|
|
|
diff --git a/cmd/bootefi.c b/cmd/bootefi.c
|
|
index d20775eccd..b9e1e5e131 100644
|
|
--- a/cmd/bootefi.c
|
|
+++ b/cmd/bootefi.c
|
|
@@ -22,97 +22,14 @@ DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
static uint8_t efi_obj_list_initalized;
|
|
|
|
-/*
|
|
- * When booting using the "bootefi" command, we don't know which
|
|
- * physical device the file came from. So we create a pseudo-device
|
|
- * called "bootefi" with the device path /bootefi.
|
|
- *
|
|
- * In addition to the originating device we also declare the file path
|
|
- * of "bootefi" based loads to be /bootefi.
|
|
- */
|
|
-static struct efi_device_path_file_path bootefi_image_path[] = {
|
|
- {
|
|
- .dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE,
|
|
- .dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH,
|
|
- .dp.length = sizeof(bootefi_image_path[0]),
|
|
- .str = { 'b','o','o','t','e','f','i' },
|
|
- }, {
|
|
- .dp.type = DEVICE_PATH_TYPE_END,
|
|
- .dp.sub_type = DEVICE_PATH_SUB_TYPE_END,
|
|
- .dp.length = sizeof(bootefi_image_path[0]),
|
|
- }
|
|
-};
|
|
-
|
|
-static struct efi_device_path_file_path bootefi_device_path[] = {
|
|
- {
|
|
- .dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE,
|
|
- .dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH,
|
|
- .dp.length = sizeof(bootefi_image_path[0]),
|
|
- .str = { 'b','o','o','t','e','f','i' },
|
|
- }, {
|
|
- .dp.type = DEVICE_PATH_TYPE_END,
|
|
- .dp.sub_type = DEVICE_PATH_SUB_TYPE_END,
|
|
- .dp.length = sizeof(bootefi_image_path[0]),
|
|
- }
|
|
-};
|
|
-
|
|
-/* The EFI loaded_image interface for the image executed via "bootefi" */
|
|
-static struct efi_loaded_image loaded_image_info = {
|
|
- .device_handle = bootefi_device_path,
|
|
- .file_path = bootefi_image_path,
|
|
-};
|
|
-
|
|
-/* The EFI object struct for the image executed via "bootefi" */
|
|
-static struct efi_object loaded_image_info_obj = {
|
|
- .handle = &loaded_image_info,
|
|
- .protocols = {
|
|
- {
|
|
- /*
|
|
- * When asking for the loaded_image interface, just
|
|
- * return handle which points to loaded_image_info
|
|
- */
|
|
- .guid = &efi_guid_loaded_image,
|
|
- .protocol_interface = &loaded_image_info,
|
|
- },
|
|
- {
|
|
- /*
|
|
- * When asking for the device path interface, return
|
|
- * bootefi_device_path
|
|
- */
|
|
- .guid = &efi_guid_device_path,
|
|
- .protocol_interface = bootefi_device_path,
|
|
- },
|
|
- {
|
|
- .guid = &efi_guid_console_control,
|
|
- .protocol_interface = (void *) &efi_console_control
|
|
- },
|
|
- {
|
|
- .guid = &efi_guid_device_path_to_text_protocol,
|
|
- .protocol_interface = (void *) &efi_device_path_to_text
|
|
- },
|
|
- },
|
|
-};
|
|
-
|
|
-/* The EFI object struct for the device the "bootefi" image was loaded from */
|
|
-static struct efi_object bootefi_device_obj = {
|
|
- .handle = bootefi_device_path,
|
|
- .protocols = {
|
|
- {
|
|
- /* When asking for the device path interface, return
|
|
- * bootefi_device_path */
|
|
- .guid = &efi_guid_device_path,
|
|
- .protocol_interface = bootefi_device_path
|
|
- }
|
|
- },
|
|
-};
|
|
+static struct efi_device_path *bootefi_image_path;
|
|
+static struct efi_device_path *bootefi_device_path;
|
|
|
|
/* Initialize and populate EFI object list */
|
|
static void efi_init_obj_list(void)
|
|
{
|
|
efi_obj_list_initalized = 1;
|
|
|
|
- list_add_tail(&loaded_image_info_obj.link, &efi_obj_list);
|
|
- list_add_tail(&bootefi_device_obj.link, &efi_obj_list);
|
|
efi_console_register();
|
|
#ifdef CONFIG_PARTITIONS
|
|
efi_disk_register();
|
|
@@ -121,13 +38,7 @@ static void efi_init_obj_list(void)
|
|
efi_gop_register();
|
|
#endif
|
|
#ifdef CONFIG_NET
|
|
- void *nethandle = loaded_image_info.device_handle;
|
|
- efi_net_register(&nethandle);
|
|
-
|
|
- if (!memcmp(bootefi_device_path[0].str, "N\0e\0t", 6))
|
|
- loaded_image_info.device_handle = nethandle;
|
|
- else
|
|
- loaded_image_info.device_handle = bootefi_device_path;
|
|
+ efi_net_register();
|
|
#endif
|
|
#ifdef CONFIG_GENERATE_SMBIOS_TABLE
|
|
efi_smbios_register();
|
|
@@ -210,14 +121,27 @@ static unsigned long efi_run_in_el2(asmlinkage ulong (*entry)(
|
|
* Load an EFI payload into a newly allocated piece of memory, register all
|
|
* EFI objects it would want to access and jump to it.
|
|
*/
|
|
-static unsigned long do_bootefi_exec(void *efi, void *fdt)
|
|
+static unsigned long do_bootefi_exec(void *efi, void *fdt,
|
|
+ struct efi_device_path *device_path,
|
|
+ struct efi_device_path *image_path)
|
|
{
|
|
+ struct efi_loaded_image loaded_image_info = {};
|
|
+ struct efi_object loaded_image_info_obj = {};
|
|
+ ulong ret;
|
|
+
|
|
ulong (*entry)(void *image_handle, struct efi_system_table *st)
|
|
asmlinkage;
|
|
ulong fdt_pages, fdt_size, fdt_start, fdt_end;
|
|
const efi_guid_t fdt_guid = EFI_FDT_GUID;
|
|
bootm_headers_t img = { 0 };
|
|
|
|
+ /* Initialize and populate EFI object list */
|
|
+ if (!efi_obj_list_initalized)
|
|
+ efi_init_obj_list();
|
|
+
|
|
+ efi_setup_loaded_image(&loaded_image_info, &loaded_image_info_obj,
|
|
+ device_path, image_path);
|
|
+
|
|
/*
|
|
* gd lives in a fixed register which may get clobbered while we execute
|
|
* the payload. So save it here and restore it on every callback entry
|
|
@@ -252,18 +176,18 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt)
|
|
|
|
/* Load the EFI payload */
|
|
entry = efi_load_pe(efi, &loaded_image_info);
|
|
- if (!entry)
|
|
- return -ENOENT;
|
|
-
|
|
- /* Initialize and populate EFI object list */
|
|
- if (!efi_obj_list_initalized)
|
|
- efi_init_obj_list();
|
|
+ if (!entry) {
|
|
+ ret = -ENOENT;
|
|
+ goto exit;
|
|
+ }
|
|
|
|
/* Call our payload! */
|
|
debug("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry);
|
|
|
|
if (setjmp(&loaded_image_info.exit_jmp)) {
|
|
- return loaded_image_info.exit_status;
|
|
+ ret = loaded_image_info.exit_status;
|
|
+ EFI_EXIT(ret);
|
|
+ goto exit;
|
|
}
|
|
|
|
#ifdef CONFIG_ARM64
|
|
@@ -282,7 +206,13 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt)
|
|
}
|
|
#endif
|
|
|
|
- return efi_do_enter(&loaded_image_info, &systab, entry);
|
|
+ ret = efi_do_enter(&loaded_image_info, &systab, entry);
|
|
+
|
|
+exit:
|
|
+ /* image has returned, loaded-image obj goes *poof*: */
|
|
+ list_del(&loaded_image_info_obj.link);
|
|
+
|
|
+ return ret;
|
|
}
|
|
|
|
|
|
@@ -315,7 +245,8 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|
}
|
|
|
|
printf("## Starting EFI application at %08lx ...\n", addr);
|
|
- r = do_bootefi_exec((void *)addr, (void*)fdt_addr);
|
|
+ r = do_bootefi_exec((void *)addr, (void*)fdt_addr,
|
|
+ bootefi_device_path, bootefi_image_path);
|
|
printf("## Application terminated, r = %lu\n",
|
|
r & ~EFI_ERROR_MASK);
|
|
|
|
@@ -344,58 +275,44 @@ U_BOOT_CMD(
|
|
bootefi_help_text
|
|
);
|
|
|
|
-void efi_set_bootdev(const char *dev, const char *devnr, const char *path)
|
|
+static int parse_partnum(const char *devnr)
|
|
{
|
|
- __maybe_unused struct blk_desc *desc;
|
|
- char devname[32] = { 0 }; /* dp->str is u16[32] long */
|
|
- char *colon, *s;
|
|
-
|
|
-#if defined(CONFIG_BLK) || CONFIG_IS_ENABLED(ISO_PARTITION)
|
|
- desc = blk_get_dev(dev, simple_strtol(devnr, NULL, 10));
|
|
-#endif
|
|
-
|
|
-#ifdef CONFIG_BLK
|
|
- if (desc) {
|
|
- snprintf(devname, sizeof(devname), "%s", desc->bdev->name);
|
|
- } else
|
|
-#endif
|
|
-
|
|
- {
|
|
- /* Assemble the condensed device name we use in efi_disk.c */
|
|
- snprintf(devname, sizeof(devname), "%s%s", dev, devnr);
|
|
+ const char *str = strchr(devnr, ':');
|
|
+ if (str) {
|
|
+ str++;
|
|
+ return simple_strtoul(str, NULL, 16);
|
|
}
|
|
+ return 0;
|
|
+}
|
|
|
|
- colon = strchr(devname, ':');
|
|
-
|
|
-#if CONFIG_IS_ENABLED(ISO_PARTITION)
|
|
- /* For ISOs we create partition block devices */
|
|
- if (desc && (desc->type != DEV_TYPE_UNKNOWN) &&
|
|
- (desc->part_type == PART_TYPE_ISO)) {
|
|
- if (!colon)
|
|
- snprintf(devname, sizeof(devname), "%s:1", devname);
|
|
+void efi_set_bootdev(const char *dev, const char *devnr, const char *path)
|
|
+{
|
|
+ char filename[32] = { 0 }; /* dp->str is u16[32] long */
|
|
+ char *s;
|
|
|
|
- colon = NULL;
|
|
- }
|
|
-#endif
|
|
+ if (strcmp(dev, "Net")) {
|
|
+ struct blk_desc *desc;
|
|
+ int part;
|
|
|
|
- if (colon)
|
|
- *colon = '\0';
|
|
+ desc = blk_get_dev(dev, simple_strtol(devnr, NULL, 10));
|
|
+ part = parse_partnum(devnr);
|
|
|
|
- /* Patch bootefi_device_path to the target device */
|
|
- memset(bootefi_device_path[0].str, 0, sizeof(bootefi_device_path[0].str));
|
|
- ascii2unicode(bootefi_device_path[0].str, devname);
|
|
+ bootefi_device_path = efi_dp_from_part(desc, part);
|
|
+ } else {
|
|
+#ifdef CONFIG_NET
|
|
+ bootefi_device_path = efi_dp_from_eth();
|
|
+#endif
|
|
+ }
|
|
|
|
- /* Patch bootefi_image_path to the target file path */
|
|
- memset(bootefi_image_path[0].str, 0, sizeof(bootefi_image_path[0].str));
|
|
if (strcmp(dev, "Net")) {
|
|
/* Add leading / to fs paths, because they're absolute */
|
|
- snprintf(devname, sizeof(devname), "/%s", path);
|
|
+ snprintf(filename, sizeof(filename), "/%s", path);
|
|
} else {
|
|
- snprintf(devname, sizeof(devname), "%s", path);
|
|
+ snprintf(filename, sizeof(filename), "%s", path);
|
|
}
|
|
/* DOS style file path: */
|
|
- s = devname;
|
|
+ s = filename;
|
|
while ((s = strchr(s, '/')))
|
|
*s++ = '\\';
|
|
- ascii2unicode(bootefi_image_path[0].str, devname);
|
|
+ bootefi_image_path = efi_dp_from_file(NULL, 0, filename);
|
|
}
|
|
diff --git a/include/efi_loader.h b/include/efi_loader.h
|
|
index c783d0da51..479fb6b63d 100644
|
|
--- a/include/efi_loader.h
|
|
+++ b/include/efi_loader.h
|
|
@@ -203,6 +203,9 @@ efi_status_t efi_install_configuration_table(const efi_guid_t *guid, void *table
|
|
efi_status_t efi_get_protocol(struct efi_object *efiobj,
|
|
struct efi_handler *handler,
|
|
void **protocol_interface);
|
|
+void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *obj,
|
|
+ struct efi_device_path *device_path,
|
|
+ struct efi_device_path *file_path);
|
|
|
|
#ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER
|
|
extern void *efi_bounce_buffer;
|
|
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
|
|
index 4b78f6d556..4a19fabdb3 100644
|
|
--- a/lib/efi_loader/efi_boottime.c
|
|
+++ b/lib/efi_loader/efi_boottime.c
|
|
@@ -714,6 +714,41 @@ static efi_status_t EFIAPI efi_install_configuration_table_ext(efi_guid_t *guid,
|
|
return EFI_EXIT(efi_install_configuration_table(guid, table));
|
|
}
|
|
|
|
+/* Initialize a loaded_image_info + loaded_image_info object with correct
|
|
+ * protocols, boot-device, etc.
|
|
+ */
|
|
+void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *obj,
|
|
+ struct efi_device_path *device_path,
|
|
+ struct efi_device_path *file_path)
|
|
+{
|
|
+ obj->handle = info;
|
|
+
|
|
+ /*
|
|
+ * When asking for the device path interface, return
|
|
+ * bootefi_device_path
|
|
+ */
|
|
+ obj->protocols[0].guid = &efi_guid_device_path;
|
|
+ obj->protocols[0].protocol_interface = device_path;
|
|
+
|
|
+ /*
|
|
+ * When asking for the loaded_image interface, just
|
|
+ * return handle which points to loaded_image_info
|
|
+ */
|
|
+ obj->protocols[1].guid = &efi_guid_loaded_image;
|
|
+ obj->protocols[1].protocol_interface = info;
|
|
+
|
|
+ obj->protocols[2].guid = &efi_guid_console_control;
|
|
+ obj->protocols[2].protocol_interface = (void *)&efi_console_control;
|
|
+
|
|
+ obj->protocols[3].guid = &efi_guid_device_path_to_text_protocol;
|
|
+ obj->protocols[3].protocol_interface = (void *)&efi_guid_device_path_to_text_protocol;
|
|
+
|
|
+ info->file_path = file_path;
|
|
+ info->device_handle = efi_dp_find_obj(device_path);
|
|
+
|
|
+ list_add_tail(&obj->link, &efi_obj_list);
|
|
+}
|
|
+
|
|
static efi_status_t EFIAPI efi_load_image(bool boot_policy,
|
|
efi_handle_t parent_image,
|
|
struct efi_device_path *file_path,
|
|
--
|
|
2.13.3
|