All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH v0 00/20] enough UEFI for standard distro boot
@ 2017-08-04 19:31 Rob Clark
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 01/20] fs: add fs_readdir() Rob Clark
                   ` (21 more replies)
  0 siblings, 22 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-04 19:31 UTC (permalink / raw)
  To: u-boot

This patchset fleshes out EFI_LOADER enough to support booting an
upstream \EFI\BOOT\bootaa64.efi (which then loads fallback.efi and
then eventually the per-distro shim.efi which loads the per-distro
grubaa64.efi) without resorting to hacks to hard-code u-boot to load
a particular distro's grub, or other hacks like setting up the
distro installation as live-media.

The first seven patches add dependencies that will be needed later
in the series.  Patches 8-15 make u-boot work with upstream grub,
without relying on distro patches.  Patches 16-19 add missing bits
of the UEFI implementation needed to support shim/fallback.  And
finally patch 20 adds bootmanager support to avoid shim/fallback
after first boot.

Background: with a normal UEFI implementation, the boot process is:

a) firmware (u-boot) looks at BootOrder and the BootXXXX variables
   to try to determine what to boot.
b) the firmware will look at the BootXXXX variables (which contain
   an EFI_LOAD_OPTION "struct" in order specified by BootOrder, and
   will boot the first bootable option.
c) The EFI_LOAD_OPTION specifies a device-path which identifies the
   device and file path of the .efi payload to exectute.

If there are no bootable options the firmware falls back to loading
\EFI\BOOT\bootaa64.efi (exact name varies depending on arch), which
then loads fallback.efi which uses the EFI_SIMPLE_FILE_SYSTEM_PROTCOL
and EFI_FILE_PROTOCOL to search for \EFI\*\boot.csv, and will then
set BootOrder and BootXXXX EFI variables accordingly so that on next
boot fallback.efi is not necessary.

(I'm ignoring secure boot, it is out of scope here.)

For example, if you had both fedora and opensuse installed on the
same disk in different partitions, you would have both:

 + \EFI\fedora\boot.csv
 + \EFI\opensuse\boot.csv

The former would contain the filename of \EFI\fedora\shim.efi and the
latter to \EFI\opensuse\shim.efi (each of which would know to load
\EFI\fedora\grubaa64.efi or \EFI\opensuse\grubaa64.efi).  Based on
this, fallback.efi would setup EFI_LOAD_OPTION's Boot0000 and
Boot0001 (and BootOrder would control the order the load-options
are considered).

With a real UEFI fw there would also be some sort of boot-order menu
(ie. hold down f9 at boot, and get a menu to pick which of the Boot*
load-options to try first).  That is not part of this patchset but
would be a useful next step to allow installing multiple operating
systems on the same disk.

This patchset provides EFI variable support during bootservices,
so viewing or modifying EFI variables after linux ExitBootServices()'s
is not possible.  If the board supports saveenv() this will be called
in efi_exit_boot_services() to persist variables that where set during
the boot process.  Making variables available after EBS is tricky on
hardware that does not have dedicated storage, as after EBS u-boot no
longer controls the devices.  An approach that Alexander Graf
suggested, is that since reboot/halt is controlled via UEFI, is that
on boards that can ensure memory is persisted across reboot, to
store modified EFI variables in a special memory location and turn
halt into reboot uboot -> appropriate setenv() calls -> saveenv() ->
halt in order to persist modified variables.  Which is also not part
of this patchset, and will likely require some board-specific help.

There will be some updates to this patchset depending on whether we
move to c11 as Heinrich suggested (ie s/L"string"/u"string" and some
changeups in the vsprintf patch).  But rather than calling this an
RFC (which I figured was more likely to get ignored for review) I
am calling this a v0.

Thanks to Peter Jones for a couple of the patches, and a bunch of help
understanding what the things above the UEFI fw expect (and fixing a
few shim and grub bugs that we found along the way).

Peter Jones (2):
  part: extract MBR signature from partitions
  efi: add some more device path structures

Rob Clark (18):
  fs: add fs_readdir()
  fs/fat: implement readdir
  short-wchar
  common: add some utf16 handling helpers
  vsprintf.c: add wide string (%ls) support
  efi_loader: add back optional efi_handler::open()
  efi_loader: add device-path utils
  efi_loader: drop redundant efi_device_path_protocol
  efi_loader: add guidstr helper
  efi_loader: flesh out device-path to text
  efi_loader: use proper device-paths for partitions
  efi_loader: use proper device-paths for net
  efi_loader: refactor boot device and loaded_image handling
  efi_loader: add file/filesys support
  efi_loader: support load_image() from a file-path
  efi_loader: make pool allocations cacheline aligned
  efi_loader: efi variable support
  efi_loader: add bootmgr

 cmd/bootefi.c                            | 249 +++++++---------
 common/Makefile                          |   1 +
 common/charset.c                         |  81 ++++++
 config.mk                                |   2 +-
 disk/part_dos.c                          |  12 +-
 disk/part_efi.c                          |  20 ++
 fs/fat/fat.c                             |  59 +++-
 fs/fs.c                                  |  46 +++
 include/blk.h                            |  15 +
 include/charset.h                        |  18 ++
 include/config_distro_bootcmd.h          |   5 +
 include/efi.h                            |  25 ++
 include/efi_api.h                        | 141 ++++++++-
 include/efi_loader.h                     |  83 +++++-
 include/fat.h                            |   4 +-
 include/fs.h                             |  23 ++
 include/part.h                           |   3 +-
 include/part_efi.h                       |   4 -
 lib/efi_loader/Makefile                  |   3 +-
 lib/efi_loader/efi_bootmgr.c             | 169 +++++++++++
 lib/efi_loader/efi_boottime.c            | 153 ++++++++--
 lib/efi_loader/efi_console.c             |  17 +-
 lib/efi_loader/efi_device_path.c         | 485 +++++++++++++++++++++++++++++++
 lib/efi_loader/efi_device_path_to_text.c | 224 ++++++++++----
 lib/efi_loader/efi_disk.c                | 105 +++++--
 lib/efi_loader/efi_file.c                | 468 +++++++++++++++++++++++++++++
 lib/efi_loader/efi_image_loader.c        |   4 +
 lib/efi_loader/efi_memory.c              |   5 +-
 lib/efi_loader/efi_net.c                 |  24 +-
 lib/efi_loader/efi_runtime.c             |  17 +-
 lib/efi_loader/efi_variable.c            | 342 ++++++++++++++++++++++
 lib/vsprintf.c                           |  30 +-
 32 files changed, 2508 insertions(+), 329 deletions(-)
 create mode 100644 common/charset.c
 create mode 100644 include/charset.h
 create mode 100644 lib/efi_loader/efi_bootmgr.c
 create mode 100644 lib/efi_loader/efi_device_path.c
 create mode 100644 lib/efi_loader/efi_file.c
 create mode 100644 lib/efi_loader/efi_variable.c

-- 
2.13.0

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 01/20] fs: add fs_readdir()
  2017-08-04 19:31 [U-Boot] [PATCH v0 00/20] enough UEFI for standard distro boot Rob Clark
@ 2017-08-04 19:31 ` Rob Clark
  2017-08-07 18:19   ` Brüns, Stefan
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 02/20] fs/fat: implement readdir Rob Clark
                   ` (20 subsequent siblings)
  21 siblings, 1 reply; 116+ messages in thread
From: Rob Clark @ 2017-08-04 19:31 UTC (permalink / raw)
  To: u-boot

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.

For reference, the expected EFI semantics are described in (v2.7 of UEFI
spec) in section 13.5 (page 609).  Or for convenience, see:

  http://wiki.phoenix.com/wiki/index.php/EFI_FILE_PROTOCOL#Read.28.29

The EFI level semantics are implemented in a later patch, so they are
not too important to the understanding of this patch.

Signed-off-by: Rob Clark <robdclark@gmail.com>
---
 fs/fs.c      | 25 +++++++++++++++++++++++++
 include/fs.h | 21 +++++++++++++++++++++
 2 files changed, 46 insertions(+)

diff --git a/fs/fs.c b/fs/fs.c
index 595ff1fe69..5ac4226ece 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 = fs_readdir_unsupported,
 	},
 #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/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.0

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 02/20] fs/fat: implement readdir
  2017-08-04 19:31 [U-Boot] [PATCH v0 00/20] enough UEFI for standard distro boot Rob Clark
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 01/20] fs: add fs_readdir() Rob Clark
@ 2017-08-04 19:31 ` Rob Clark
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 03/20] short-wchar Rob Clark
                   ` (19 subsequent siblings)
  21 siblings, 0 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-04 19:31 UTC (permalink / raw)
  To: u-boot

Yes, this is super-hacky.  The FAT code is quite ugly, and this doesn't
improve things.  But it doesn't make it significantly worse either.  The
better option would be a massive FAT re-write to get rid of the hacky
way that fat_file_ls() works.  Volunteers welcome.

Signed-off-by: Rob Clark <robdclark@gmail.com>
---
Yeah, not my proudest patch, but there is little that can be done in
fat.c to be proud of short of re-writing it.. which I am not signing
up for.  I don't think it makes things that much worse than it already
is, but if you disagree I still suggest we merge the previous patch,
to enable merging the efi_loader patches that directly or indirectly
depend on it.  At least then we minimize what is not upstream in order
to have a useful UEFI implementation in u-boot.

 fs/fat/fat.c  | 59 ++++++++++++++++++++++++++++++++++++++++++++++-------------
 fs/fs.c       |  2 +-
 include/fat.h |  4 +++-
 3 files changed, 50 insertions(+), 15 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 5ac4226ece..42a028a6ce 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -119,7 +119,7 @@ static struct fstype_info fstypes[] = {
 		.write = fs_write_unsupported,
 #endif
 		.uuid = fs_uuid_unsupported,
-		.readdir = fs_readdir_unsupported,
+		.readdir = fat_readdir,
 	},
 #endif
 #ifdef CONFIG_FS_EXT4
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_ */
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 03/20] short-wchar
  2017-08-04 19:31 [U-Boot] [PATCH v0 00/20] enough UEFI for standard distro boot Rob Clark
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 01/20] fs: add fs_readdir() Rob Clark
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 02/20] fs/fat: implement readdir Rob Clark
@ 2017-08-04 19:31 ` Rob Clark
  2017-08-04 20:28   ` Heinrich Schuchardt
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 04/20] part: extract MBR signature from partitions Rob Clark
                   ` (18 subsequent siblings)
  21 siblings, 1 reply; 116+ messages in thread
From: Rob Clark @ 2017-08-04 19:31 UTC (permalink / raw)
  To: u-boot

For now, pending conclusion on proposal about using c11 and u"string"
instead of L"string" plus -fshort-wchar.

Background: UEFI uses utf16 strings universally.  An UEFI implementation
that does not use -fshort-wchar has to do a lot of cumbersome charset
conversion back/forth.  Mixing object files that use -fshort-wchar and
others that do not is a bad idea (and gcc will warn about it).  There
are 3 reasonable solutions that I can think of:

 1) Use -fshort-wchar across the board.  We don't dynamically link
    against other shared libraries at runtime, so there isn't much
    downside to this approach.  Heinrich brought up ext4, which uses
    utf32, but I guess this mostly matters for fs_ls(), and it does
    not seem so bad for it to do utf32->utf8 conversion.

 2) Use -fshort-wchar only if CONFIG_EFI_LOADER=y.. UEFI only requires
    fat/vfat so we don't need ext4 and efi loader at the same time.

 3) Go with Heinrich's suggestion of requiring c11.  Possibly this
    requirement could be loosened to only require c11 for efi loader.
    This seems like the best approach, and at least no one has so
    far brought up any objection to his proposal.

Not-signed-off-by: Rob Clark <robdclark@gmail.com>
---
 config.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config.mk b/config.mk
index b77d58903c..5ad9e7198d 100644
--- a/config.mk
+++ b/config.mk
@@ -74,7 +74,7 @@ endif
 RELFLAGS := $(PLATFORM_RELFLAGS)
 
 PLATFORM_CPPFLAGS += $(RELFLAGS)
-PLATFORM_CPPFLAGS += -pipe
+PLATFORM_CPPFLAGS += -pipe -fshort-wchar
 
 LDFLAGS += $(PLATFORM_LDFLAGS)
 LDFLAGS_FINAL += -Bstatic
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 04/20] part: extract MBR signature from partitions
  2017-08-04 19:31 [U-Boot] [PATCH v0 00/20] enough UEFI for standard distro boot Rob Clark
                   ` (2 preceding siblings ...)
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 03/20] short-wchar Rob Clark
@ 2017-08-04 19:31 ` Rob Clark
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 05/20] efi: add some more device path structures Rob Clark
                   ` (17 subsequent siblings)
  21 siblings, 0 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-04 19:31 UTC (permalink / raw)
  To: u-boot

From: Peter Jones <pjones@redhat.com>

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 */
+	};
 #ifdef CONFIG_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.0

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 05/20] efi: add some more device path structures
  2017-08-04 19:31 [U-Boot] [PATCH v0 00/20] enough UEFI for standard distro boot Rob Clark
                   ` (3 preceding siblings ...)
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 04/20] part: extract MBR signature from partitions Rob Clark
@ 2017-08-04 19:31 ` Rob Clark
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 06/20] common: add some utf16 handling helpers Rob Clark
                   ` (16 subsequent siblings)
  21 siblings, 0 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-04 19:31 UTC (permalink / raw)
  To: u-boot

From: Peter Jones <pjones@redhat.com>

Signed-off-by: Peter Jones <pjones@redhat.com>
Signed-off-by: Rob Clark <robdclark@gmail.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.0

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 06/20] common: add some utf16 handling helpers
  2017-08-04 19:31 [U-Boot] [PATCH v0 00/20] enough UEFI for standard distro boot Rob Clark
                   ` (4 preceding siblings ...)
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 05/20] efi: add some more device path structures Rob Clark
@ 2017-08-04 19:31 ` Rob Clark
  2017-08-06  5:17   ` Simon Glass
  2017-08-08 22:50   ` [U-Boot] [U-Boot, v0, " Heinrich Schuchardt
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 07/20] vsprintf.c: add wide string (%ls) support Rob Clark
                   ` (15 subsequent siblings)
  21 siblings, 2 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-04 19:31 UTC (permalink / raw)
  To: u-boot

We'll eventually want these in a few places in efi_loader, and also
vsprintf.

Signed-off-by: Rob Clark <robdclark@gmail.com>
---
 common/Makefile              |  1 +
 common/charset.c             | 81 ++++++++++++++++++++++++++++++++++++++++++++
 include/charset.h            | 18 ++++++++++
 lib/efi_loader/efi_console.c | 17 ++--------
 4 files changed, 103 insertions(+), 14 deletions(-)
 create mode 100644 common/charset.c
 create mode 100644 include/charset.h

diff --git a/common/Makefile b/common/Makefile
index 60681c845c..44c8e1ba52 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -175,5 +175,6 @@ obj-$(CONFIG_CMD_DFU) += dfu.o
 obj-y += command.o
 obj-y += s_record.o
 obj-y += xyzModem.o
+obj-y += charset.o
 
 CFLAGS_env_embedded.o := -Wa,--no-warn -DENV_CRC=$(shell tools/envcrc 2>/dev/null)
diff --git a/common/charset.c b/common/charset.c
new file mode 100644
index 0000000000..eaff2e542e
--- /dev/null
+++ b/common/charset.c
@@ -0,0 +1,81 @@
+/*
+ *  charset conversion utils
+ *
+ *  Copyright (c) 2017 Rob Clark
+ *
+ *  SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <charset.h>
+
+/*
+ * utf8/utf16 conversion mostly lifted from grub
+ */
+
+size_t utf16_strlen(uint16_t *in)
+{
+	size_t i;
+	for (i = 0; in[i]; i++);
+	return i;
+}
+
+size_t utf16_strnlen(const uint16_t *in, size_t count)
+{
+	size_t i;
+	for (i = 0; count-- && in[i]; i++);
+	return i;
+}
+
+/* Convert UTF-16 to UTF-8.  */
+uint8_t *utf16_to_utf8(uint8_t *dest, const uint16_t *src, size_t size)
+{
+	uint32_t code_high = 0;
+
+	while (size--) {
+		uint32_t code = *src++;
+
+		if (code_high) {
+			if (code >= 0xDC00 && code <= 0xDFFF) {
+				/* Surrogate pair.  */
+				code = ((code_high - 0xD800) << 10) + (code - 0xDC00) + 0x10000;
+
+				*dest++ = (code >> 18) | 0xF0;
+				*dest++ = ((code >> 12) & 0x3F) | 0x80;
+				*dest++ = ((code >> 6) & 0x3F) | 0x80;
+				*dest++ = (code & 0x3F) | 0x80;
+			} else {
+				/* Error...  */
+				*dest++ = '?';
+				/* *src may be valid. Don't eat it.  */
+				src--;
+			}
+
+			code_high = 0;
+		} else {
+			if (code <= 0x007F) {
+				*dest++ = code;
+			} else if (code <= 0x07FF) {
+				*dest++ = (code >> 6) | 0xC0;
+				*dest++ = (code & 0x3F) | 0x80;
+			} else if (code >= 0xD800 && code <= 0xDBFF) {
+				code_high = code;
+				continue;
+			} else if (code >= 0xDC00 && code <= 0xDFFF) {
+				/* Error... */
+				*dest++ = '?';
+			} else if (code < 0x10000) {
+				*dest++ = (code >> 12) | 0xE0;
+				*dest++ = ((code >> 6) & 0x3F) | 0x80;
+				*dest++ = (code & 0x3F) | 0x80;
+			} else {
+				*dest++ = (code >> 18) | 0xF0;
+				*dest++ = ((code >> 12) & 0x3F) | 0x80;
+				*dest++ = ((code >> 6) & 0x3F) | 0x80;
+				*dest++ = (code & 0x3F) | 0x80;
+			}
+		}
+	}
+
+	return dest;
+}
diff --git a/include/charset.h b/include/charset.h
new file mode 100644
index 0000000000..2ee1172182
--- /dev/null
+++ b/include/charset.h
@@ -0,0 +1,18 @@
+/*
+ *  charset conversion utils
+ *
+ *  Copyright (c) 2017 Rob Clark
+ *
+ *  SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __CHARSET_H_
+#define __CHARSET_H_
+
+#define MAX_UTF8_PER_UTF16 4
+
+size_t utf16_strlen(uint16_t *in);
+size_t utf16_strnlen(const uint16_t *in, size_t count);
+uint8_t *utf16_to_utf8(uint8_t *dest, const uint16_t *src, size_t size);
+
+#endif /* __CHARSET_H_ */
diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
index 5ebce4b544..3fc82b8726 100644
--- a/lib/efi_loader/efi_console.c
+++ b/lib/efi_loader/efi_console.c
@@ -7,6 +7,7 @@
  */
 
 #include <common.h>
+#include <charset.h>
 #include <efi_loader.h>
 
 static bool console_size_queried;
@@ -138,20 +139,8 @@ static efi_status_t EFIAPI efi_cout_reset(
 
 static void print_unicode_in_utf8(u16 c)
 {
-	char utf8[4] = { 0 };
-	char *b = utf8;
-
-	if (c < 0x80) {
-		*(b++) = c;
-	} else if (c < 0x800) {
-		*(b++) = 192 + c / 64;
-		*(b++) = 128 + c % 64;
-	} else {
-		*(b++) = 224 + c / 4096;
-		*(b++) = 128 + c / 64 % 64;
-		*(b++) = 128 + c % 64;
-	}
-
+	char utf8[MAX_UTF8_PER_UTF16] = { 0 };
+	utf16_to_utf8((u8 *)utf8, &c, 1);
 	puts(utf8);
 }
 
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 07/20] vsprintf.c: add wide string (%ls) support
  2017-08-04 19:31 [U-Boot] [PATCH v0 00/20] enough UEFI for standard distro boot Rob Clark
                   ` (5 preceding siblings ...)
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 06/20] common: add some utf16 handling helpers Rob Clark
@ 2017-08-04 19:31 ` Rob Clark
  2017-08-08 22:03   ` [U-Boot] [U-Boot, v0, " Heinrich Schuchardt
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 08/20] efi_loader: add back optional efi_handler::open() Rob Clark
                   ` (14 subsequent siblings)
  21 siblings, 1 reply; 116+ messages in thread
From: Rob Clark @ 2017-08-04 19:31 UTC (permalink / raw)
  To: u-boot

This is convenient for efi_loader which deals a lot with utf16.

Signed-off-by: Rob Clark <robdclark@gmail.com>
---
 lib/vsprintf.c | 30 ++++++++++++++++++++++++++++--
 1 file changed, 28 insertions(+), 2 deletions(-)

diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 874a2951f7..0c40f852ce 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -17,6 +17,7 @@
 #include <linux/ctype.h>
 
 #include <common.h>
+#include <charset.h>
 
 #include <div64.h>
 #define noinline __attribute__((noinline))
@@ -270,6 +271,26 @@ static char *string(char *buf, char *end, char *s, int field_width,
 	return buf;
 }
 
+static char *string16(char *buf, char *end, u16 *s, int field_width,
+		int precision, int flags)
+{
+	u16 *str = s ? s : L"<NULL>";
+	int len = utf16_strnlen(str, precision);
+	u8 utf8[len * MAX_UTF8_PER_UTF16];
+	int i;
+
+	*utf16_to_utf8(utf8, str, len) = '\0';
+
+	if (!(flags & LEFT))
+		while (len < field_width--)
+			ADDCH(buf, ' ');
+	for (i = 0; i < len; ++i)
+		ADDCH(buf, utf8[i]);
+	while (len < field_width--)
+		ADDCH(buf, ' ');
+	return buf;
+}
+
 #ifdef CONFIG_CMD_NET
 static const char hex_asc[] = "0123456789abcdef";
 #define hex_asc_lo(x)	hex_asc[((x) & 0x0f)]
@@ -528,8 +549,13 @@ repeat:
 			continue;
 
 		case 's':
-			str = string(str, end, va_arg(args, char *),
-				     field_width, precision, flags);
+			if (qualifier == 'l') {
+				str = string16(str, end, va_arg(args, u16 *),
+					       field_width, precision, flags);
+			} else {
+				str = string(str, end, va_arg(args, char *),
+					     field_width, precision, flags);
+			}
 			continue;
 
 		case 'p':
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 08/20] efi_loader: add back optional efi_handler::open()
  2017-08-04 19:31 [U-Boot] [PATCH v0 00/20] enough UEFI for standard distro boot Rob Clark
                   ` (6 preceding siblings ...)
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 07/20] vsprintf.c: add wide string (%ls) support Rob Clark
@ 2017-08-04 19:31 ` Rob Clark
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 09/20] efi_loader: add device-path utils Rob Clark
                   ` (13 subsequent siblings)
  21 siblings, 0 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-04 19:31 UTC (permalink / raw)
  To: u-boot

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.0

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 09/20] efi_loader: add device-path utils
  2017-08-04 19:31 [U-Boot] [PATCH v0 00/20] enough UEFI for standard distro boot Rob Clark
                   ` (7 preceding siblings ...)
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 08/20] efi_loader: add back optional efi_handler::open() Rob Clark
@ 2017-08-04 19:31 ` Rob Clark
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 10/20] efi_loader: drop redundant efi_device_path_protocol Rob Clark
                   ` (12 subsequent siblings)
  21 siblings, 0 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-04 19:31 UTC (permalink / raw)
  To: u-boot

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.0

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 10/20] efi_loader: drop redundant efi_device_path_protocol
  2017-08-04 19:31 [U-Boot] [PATCH v0 00/20] enough UEFI for standard distro boot Rob Clark
                   ` (8 preceding siblings ...)
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 09/20] efi_loader: add device-path utils Rob Clark
@ 2017-08-04 19:31 ` Rob Clark
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 11/20] efi_loader: add guidstr helper Rob Clark
                   ` (11 subsequent siblings)
  21 siblings, 0 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-04 19:31 UTC (permalink / raw)
  To: u-boot

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.0

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 11/20] efi_loader: add guidstr helper
  2017-08-04 19:31 [U-Boot] [PATCH v0 00/20] enough UEFI for standard distro boot Rob Clark
                   ` (9 preceding siblings ...)
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 10/20] efi_loader: drop redundant efi_device_path_protocol Rob Clark
@ 2017-08-04 19:31 ` Rob Clark
  2017-08-05 19:33   ` Heinrich Schuchardt
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 12/20] efi_loader: flesh out device-path to text Rob Clark
                   ` (10 subsequent siblings)
  21 siblings, 1 reply; 116+ messages in thread
From: Rob Clark @ 2017-08-04 19:31 UTC (permalink / raw)
  To: u-boot

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.0

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 12/20] efi_loader: flesh out device-path to text
  2017-08-04 19:31 [U-Boot] [PATCH v0 00/20] enough UEFI for standard distro boot Rob Clark
                   ` (10 preceding siblings ...)
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 11/20] efi_loader: add guidstr helper Rob Clark
@ 2017-08-04 19:31 ` Rob Clark
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions Rob Clark
                   ` (9 subsequent siblings)
  21 siblings, 0 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-04 19:31 UTC (permalink / raw)
  To: u-boot

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.0

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-04 19:31 [U-Boot] [PATCH v0 00/20] enough UEFI for standard distro boot Rob Clark
                   ` (11 preceding siblings ...)
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 12/20] efi_loader: flesh out device-path to text Rob Clark
@ 2017-08-04 19:31 ` Rob Clark
  2017-08-04 20:41   ` Mark Kettenis
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 14/20] efi_loader: use proper device-paths for net Rob Clark
                   ` (8 subsequent siblings)
  21 siblings, 1 reply; 116+ messages in thread
From: Rob Clark @ 2017-08-04 19:31 UTC (permalink / raw)
  To: u-boot

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 at 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.0

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 14/20] efi_loader: use proper device-paths for net
  2017-08-04 19:31 [U-Boot] [PATCH v0 00/20] enough UEFI for standard distro boot Rob Clark
                   ` (12 preceding siblings ...)
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions Rob Clark
@ 2017-08-04 19:31 ` Rob Clark
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 15/20] efi_loader: refactor boot device and loaded_image handling Rob Clark
                   ` (7 subsequent siblings)
  21 siblings, 0 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-04 19:31 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Rob Clark <robdclark@gmail.com>
---
 lib/efi_loader/efi_net.c | 19 ++-----------------
 1 file changed, 2 insertions(+), 17 deletions(-)

diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c
index 0b949d86e8..aa0618fd3a 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;
@@ -213,16 +210,6 @@ void efi_net_set_dhcp_ack(void *pkt, int len)
 int efi_net_register(void **handle)
 {
 	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;
 
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 15/20] efi_loader: refactor boot device and loaded_image handling
  2017-08-04 19:31 [U-Boot] [PATCH v0 00/20] enough UEFI for standard distro boot Rob Clark
                   ` (13 preceding siblings ...)
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 14/20] efi_loader: use proper device-paths for net Rob Clark
@ 2017-08-04 19:31 ` Rob Clark
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 16/20] efi_loader: add file/filesys support Rob Clark
                   ` (6 subsequent siblings)
  21 siblings, 0 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-04 19:31 UTC (permalink / raw)
  To: u-boot

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          |   5 +-
 lib/efi_loader/efi_boottime.c |  35 ++++++++
 lib/efi_loader/efi_net.c      |   5 +-
 4 files changed, 99 insertions(+), 147 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 1ab4af0f88..479fb6b63d 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);
 
@@ -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,
diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c
index aa0618fd3a..91f1e4a69e 100644
--- a/lib/efi_loader/efi_net.c
+++ b/lib/efi_loader/efi_net.c
@@ -207,7 +207,7 @@ 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;
 
@@ -253,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.0

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 16/20] efi_loader: add file/filesys support
  2017-08-04 19:31 [U-Boot] [PATCH v0 00/20] enough UEFI for standard distro boot Rob Clark
                   ` (14 preceding siblings ...)
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 15/20] efi_loader: refactor boot device and loaded_image handling Rob Clark
@ 2017-08-04 19:31 ` Rob Clark
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 17/20] efi_loader: support load_image() from a file-path Rob Clark
                   ` (5 subsequent siblings)
  21 siblings, 0 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-04 19:31 UTC (permalink / raw)
  To: u-boot

fallback.efi (and probably other things) use UEFI's simple-file-system
protocol and file support to search for OS's to boot.

Signed-off-by: Rob Clark <robdclark@gmail.com>
---
 fs/fs.c                           |  21 ++
 include/efi.h                     |   2 +
 include/efi_api.h                 |  65 ++++++
 include/efi_loader.h              |  13 ++
 include/fs.h                      |   2 +
 lib/efi_loader/Makefile           |   1 +
 lib/efi_loader/efi_disk.c         |  51 +++++
 lib/efi_loader/efi_file.c         | 468 ++++++++++++++++++++++++++++++++++++++
 lib/efi_loader/efi_image_loader.c |   3 +
 9 files changed, 626 insertions(+)
 create mode 100644 lib/efi_loader/efi_file.c

diff --git a/fs/fs.c b/fs/fs.c
index 42a028a6ce..a269619b51 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -247,6 +247,27 @@ int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype)
 	return -1;
 }
 
+/* set current blk device w/ blk_desc + partition # */
+int fs_set_blk_dev2(struct blk_desc *desc, int part)
+{
+	struct fstype_info *info;
+	int ret, i;
+
+	ret = part_get_info(desc, part, &fs_partition);
+	if (ret)
+		return ret;
+	fs_dev_desc = desc;
+
+	for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) {
+		if (!info->probe(fs_dev_desc, &fs_partition)) {
+			fs_type = info->fstype;
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
 static void fs_close(void)
 {
 	struct fstype_info *info = fs_get_info(fs_type);
diff --git a/include/efi.h b/include/efi.h
index 87b0b43f20..ddd2b96417 100644
--- a/include/efi.h
+++ b/include/efi.h
@@ -81,6 +81,8 @@ typedef struct {
 #define EFI_IP_ADDRESS_CONFLICT		(EFI_ERROR_MASK | 34)
 #define EFI_HTTP_ERROR			(EFI_ERROR_MASK | 35)
 
+#define EFI_WARN_DELETE_FAILURE	2
+
 typedef unsigned long efi_status_t;
 typedef u64 efi_physical_addr_t;
 typedef u64 efi_virtual_addr_t;
diff --git a/include/efi_api.h b/include/efi_api.h
index dd79cace32..1a542846b3 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -657,4 +657,69 @@ struct efi_pxe {
 	struct efi_pxe_mode *mode;
 };
 
+#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID \
+	EFI_GUID(0x964e5b22, 0x6459, 0x11d2, \
+		 0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
+#define EFI_FILE_PROTOCOL_REVISION 0x00010000
+
+struct efi_file_handle {
+	u64 rev;
+	efi_status_t (EFIAPI *open)(struct efi_file_handle *file,
+			struct efi_file_handle **new_handle,
+			s16 *file_name, u64 open_mode, u64 attributes);
+	efi_status_t (EFIAPI *close)(struct efi_file_handle *file);
+	efi_status_t (EFIAPI *delete)(struct efi_file_handle *file);
+	efi_status_t (EFIAPI *read)(struct efi_file_handle *file,
+			u64 *buffer_size, void *buffer);
+	efi_status_t (EFIAPI *write)(struct efi_file_handle *file,
+			u64 *buffer_size, void *buffer);
+	efi_status_t (EFIAPI *getpos)(struct efi_file_handle *file,
+			u64 *pos);
+	efi_status_t (EFIAPI *setpos)(struct efi_file_handle *file,
+			u64 pos);
+	efi_status_t (EFIAPI *getinfo)(struct efi_file_handle *file,
+			efi_guid_t *info_type, u64 *buffer_size, void *buffer);
+	efi_status_t (EFIAPI *setinfo)(struct efi_file_handle *file,
+			efi_guid_t *info_type, u64 buffer_size, void *buffer);
+	efi_status_t (EFIAPI *flush)(struct efi_file_handle *file);
+};
+
+#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID \
+	EFI_GUID(0x964e5b22, 0x6459, 0x11d2, \
+		 0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
+#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION 0x00010000
+
+struct efi_simple_file_system_protocol {
+	u64 rev;
+	efi_status_t (EFIAPI *open_volume)(struct efi_simple_file_system_protocol *this,
+			struct efi_file_handle **root);
+};
+
+#define EFI_FILE_INFO_GUID \
+	EFI_GUID(0x9576e92, 0x6d3f, 0x11d2, \
+		 0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
+
+#define EFI_FILE_MODE_READ	0x0000000000000001
+#define EFI_FILE_MODE_WRITE	0x0000000000000002
+#define EFI_FILE_MODE_CREATE	0x8000000000000000
+
+#define EFI_FILE_READ_ONLY	0x0000000000000001
+#define EFI_FILE_HIDDEN		0x0000000000000002
+#define EFI_FILE_SYSTEM		0x0000000000000004
+#define EFI_FILE_RESERVED	0x0000000000000008
+#define EFI_FILE_DIRECTORY	0x0000000000000010
+#define EFI_FILE_ARCHIVE	0x0000000000000020
+#define EFI_FILE_VALID_ATTR	0x0000000000000037
+
+struct efi_file_info {
+	u64 size;
+	u64 file_size;
+	u64 physical_size;
+	struct efi_time create_time;
+	struct efi_time last_access_time;
+	struct efi_time modification_time;
+	u64 attribute;
+	s16 file_name[0];
+};
+
 #endif
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 479fb6b63d..4210d5f19a 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -65,6 +65,8 @@ 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;
 extern const efi_guid_t efi_guid_device_path_to_text_protocol;
+extern const efi_guid_t efi_simple_file_system_protocol_guid;
+extern const efi_guid_t efi_file_info_guid;
 
 extern unsigned int __efi_runtime_start, __efi_runtime_stop;
 extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;
@@ -147,6 +149,9 @@ int efi_net_register(void);
 /* Called by bootefi to make SMBIOS tables available */
 void efi_smbios_register(void);
 
+struct efi_simple_file_system_protocol *
+efi_fs_from_path(struct efi_device_path *fp);
+
 /* Called by networking code to memorize the dhcp ack package */
 void efi_net_set_dhcp_ack(void *pkt, int len);
 
@@ -175,6 +180,14 @@ efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type,
 /* Call this to signal an event */
 void efi_signal_event(struct efi_event *event);
 
+/* open file system: */
+struct efi_simple_file_system_protocol * efi_simple_file_system(
+		struct blk_desc *desc, int part, struct efi_device_path *dp);
+
+/* open file from device-path: */
+struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp);
+
+
 /* Generic EFI memory allocator, call this to get memory */
 void *efi_alloc(uint64_t len, int memory_type);
 /* More specific EFI memory allocator, called by EFI payloads */
diff --git a/include/fs.h b/include/fs.h
index 71051d7c66..7e920916e3 100644
--- a/include/fs.h
+++ b/include/fs.h
@@ -26,6 +26,8 @@
  */
 int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype);
 
+int fs_set_blk_dev2(struct blk_desc *desc, int part);
+
 /*
  * Print the list of files on the partition previously set by fs_set_blk_dev(),
  * in directory "dirname".
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index f35e5ce8a8..cce92cfeb5 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -16,6 +16,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 efi_device_path.o
+obj-y += efi_file.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_disk.c b/lib/efi_loader/efi_disk.c
index eea65a402a..f7565ad937 100644
--- a/lib/efi_loader/efi_disk.c
+++ b/lib/efi_loader/efi_disk.c
@@ -31,6 +31,8 @@ struct efi_disk_obj {
 	struct efi_device_path *dp;
 	/* partition # */
 	unsigned part;
+	/* handle to filesys proto (for partition objects) */
+	struct efi_simple_file_system_protocol *volume;
 	/* Offset into disk for simple partitions */
 	lbaint_t offset;
 	/* Internal block device */
@@ -172,6 +174,49 @@ static const struct efi_block_io block_io_disk_template = {
 	.flush_blocks = &efi_disk_flush_blocks,
 };
 
+static efi_status_t EFIAPI efi_disk_open_fs(void *handle,
+					    const efi_guid_t *protocol,
+					    void **protocol_interface)
+{
+	struct efi_disk_obj *diskobj = handle;
+
+	if (!diskobj->volume) {
+		diskobj->volume =
+			efi_simple_file_system(diskobj->desc,
+					       diskobj->part,
+					       diskobj->dp);
+	}
+
+	*protocol_interface = diskobj->volume;
+
+	return EFI_SUCCESS;
+}
+
+/*
+ * Find filesystem from a device-path.  The passed in path 'p' probably
+ * contains one or more /File(name) nodes, so the comparison stops at
+ * the first /File() node, and returns the pointer to that via 'rp'.
+ * This is mostly intended to be a helper to map a device-path to an
+ * efi_file_handle object.
+ */
+struct efi_simple_file_system_protocol *
+efi_fs_from_path(struct efi_device_path *fp)
+{
+	struct efi_simple_file_system_protocol *volume;
+	struct efi_object *efiobj;
+	struct efi_disk_obj *diskobj;
+
+	efiobj = efi_dp_find_obj(fp);
+	if (!efiobj)
+		return NULL;
+
+	diskobj = container_of(efiobj, struct efi_disk_obj, parent);
+
+	efi_disk_open_fs(diskobj, NULL, (void **)&volume);
+
+	return volume;
+}
+
 static void efi_disk_add_dev(const char *name,
 			     const char *if_typename,
 			     struct blk_desc *desc,
@@ -194,6 +239,12 @@ static void efi_disk_add_dev(const char *name,
 	diskobj->parent.protocols[0].protocol_interface = &diskobj->ops;
 	diskobj->parent.protocols[1].guid = &efi_guid_device_path;
 	diskobj->parent.protocols[1].protocol_interface = diskobj->dp;
+	if (part >= 1) {
+		diskobj->parent.protocols[2].guid =
+			&efi_simple_file_system_protocol_guid;
+		diskobj->parent.protocols[2].open =
+			efi_disk_open_fs;
+	}
 	diskobj->parent.handle = diskobj;
 	diskobj->ops = block_io_disk_template;
 	diskobj->ifname = if_typename;
diff --git a/lib/efi_loader/efi_file.c b/lib/efi_loader/efi_file.c
new file mode 100644
index 0000000000..7bdd16c649
--- /dev/null
+++ b/lib/efi_loader/efi_file.c
@@ -0,0 +1,468 @@
+/*
+ *  EFI utils
+ *
+ *  Copyright (c) 2017 Rob Clark
+ *
+ *  SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <charset.h>
+#include <efi_loader.h>
+#include <malloc.h>
+#include <fs.h>
+
+struct file_system {
+	struct efi_simple_file_system_protocol base;
+	struct efi_device_path *dp;
+	struct blk_desc *desc;
+	int part;
+};
+#define to_fs(x) container_of(x, struct file_system, base)
+
+struct file_handle {
+	struct efi_file_handle base;
+	struct file_system *fs;
+	loff_t offset;       /* current file position/cursor */
+	int isdir;
+	char path[0];
+};
+#define to_fh(x) container_of(x, struct file_handle, base)
+
+static const struct efi_file_handle efi_file_handle_protocol;
+
+static char *basename(struct file_handle *fh)
+{
+	char *s = strrchr(fh->path, '/');
+	if (s)
+		return s + 1;
+	return fh->path;
+}
+
+static int set_blk_dev(struct file_handle *fh)
+{
+	return fs_set_blk_dev2(fh->fs->desc, fh->fs->part);
+}
+
+static int is_dir(struct file_handle *fh, const char *filename)
+{
+	char buf[256];
+	struct fs_dirent d;
+	const char *path;
+	int ret;
+
+	if (!filename) {
+		path = fh->path;
+	} else {
+		ret = snprintf(buf, sizeof(buf), "%s/%s",
+				fh->path, filename);
+		if (ret >= sizeof(buf))
+			return 0;
+		path = buf;
+	}
+
+	set_blk_dev(fh);
+	ret = fs_readdir(path, 0, &d);
+	if (ret == -ENOTDIR) {
+		return 0;
+	} else if (ret == -ENXIO) {
+		debug("WARNING: cannot read directories!\n");
+		/*
+		 * We don't know, assume regular file, but if
+		 * the EFI app tries to read a directory, it
+		 * won't work properly.  This will be a problem
+		 * for fallback.efi as it searches /EFI/ for
+		 * OS installations.  Too bad.
+		 */
+		return 0;
+	} else {
+		return 1;
+	}
+}
+
+/* NOTE: despite what you would expect, 'file_name' is actually a path.
+ * With windoze style backlashes, ofc.
+ */
+static struct efi_file_handle *file_open(struct file_system *fs,
+		struct file_handle *parent, s16 *file_name)
+{
+	struct file_handle *fh;
+	char f0[MAX_UTF8_PER_UTF16] = {0};
+	int plen = 0;
+	int flen = 0;
+
+	if (file_name)
+		utf16_to_utf8((u8 *)f0, (u16 *)file_name, 1);
+
+	/* we could have a parent, but also an absolute path: */
+	if (f0[0] == '\\') {
+		plen = 0;
+		flen = utf16_strlen((u16 *)file_name);
+	} else if (parent) {
+		plen = strlen(parent->path) + 1;
+		flen = utf16_strlen((u16 *)file_name);
+	}
+
+	/* +2 is for null and '/' */
+	fh = calloc(1, sizeof(*fh) + plen + (flen * MAX_UTF8_PER_UTF16) + 2);
+
+	fh->base = efi_file_handle_protocol;
+	fh->fs = fs;
+
+	if (parent) {
+		char *p = fh->path;
+
+		if (plen > 0) {
+			strcpy(p, parent->path);
+			p += plen - 1;
+			*p++ = '/';
+		}
+
+		utf16_to_utf8((u8 *)p, (u16 *)file_name, flen);
+
+		/* sanitize path: */
+		while ((p = strchr(p, '\\')))
+			*p++ = '/';
+
+		/* check if file exists: */
+		if (set_blk_dev(fh))
+			goto error;
+		if (!fs_exists(fh->path))
+			goto error;
+
+		/* figure out if file is a directory: */
+		fh->isdir = is_dir(fh, NULL);
+	} else {
+		fh->isdir = 1;
+		strcpy(fh->path, "");
+	}
+
+	return &fh->base;
+
+error:
+	free(fh);
+	return NULL;
+}
+
+static efi_status_t EFIAPI efi_file_open(struct efi_file_handle *file,
+		struct efi_file_handle **new_handle,
+		s16 *file_name, u64 open_mode, u64 attributes)
+{
+	struct file_handle *fh = to_fh(file);
+
+	EFI_ENTRY("%p, %p, %p, %llu, %llu", file, new_handle, file_name,
+		open_mode, attributes);
+
+	*new_handle = file_open(fh->fs, fh, file_name);
+	if (!*new_handle)
+		return EFI_EXIT(EFI_NOT_FOUND);
+
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_file_close(struct efi_file_handle *file)
+{
+	struct file_handle *fh = to_fh(file);
+	EFI_ENTRY("%p", file);
+	free(fh);
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_file_delete(struct efi_file_handle *file)
+{
+	efi_file_close(file);
+	return EFI_WARN_DELETE_FAILURE;
+}
+
+static efi_status_t file_read(struct file_handle *fh, u64 *buffer_size,
+		void *buffer)
+{
+	loff_t actread;
+
+	if (fs_read(fh->path, (ulong)buffer, fh->offset,
+			*buffer_size, &actread))
+		return EFI_DEVICE_ERROR;
+
+	*buffer_size = actread;
+	fh->offset += actread;
+
+	return EFI_SUCCESS;
+}
+
+static efi_status_t dir_read(struct file_handle *fh, u64 *buffer_size,
+		void *buffer)
+{
+	struct efi_file_info *info = buffer;
+	struct fs_dirent dent;
+	unsigned required_size;
+	int ret;
+
+	ret = fs_readdir(fh->path, fh->offset, &dent);
+
+	if (ret == -ENOENT) {
+		/* no more files in directory: */
+		/* workaround shim.efi bug/quirk.. as find_boot_csv()
+		 * loops through directory contents, it initially calls
+		 * read w/ zero length buffer to find out how much mem
+		 * to allocate for the EFI_FILE_INFO, then allocates,
+		 * and then calls a 2nd time.  If we return size of
+		 * zero the first time, it happily passes that to
+		 * AllocateZeroPool(), and when that returns NULL it
+		 * thinks it is EFI_OUT_OF_RESOURCES.  So on first
+		 * call return a non-zero size:
+		 */
+		if (*buffer_size == 0)
+			*buffer_size = sizeof(*info);
+		else
+			*buffer_size = 0;
+		return EFI_SUCCESS;
+	} else if (ret) {
+		return EFI_DEVICE_ERROR;
+	}
+
+	/* check buffer size: */
+	required_size = sizeof(*info) + 2 * (strlen(dent.name) + 1);
+	if (*buffer_size < required_size) {
+		*buffer_size = required_size;
+		return EFI_BUFFER_TOO_SMALL;
+	}
+
+	*buffer_size = required_size;
+	memset(info, 0, required_size);
+
+	info->size = required_size;
+	info->file_size = dent.size;
+	info->physical_size = dent.size;
+
+	if (is_dir(fh, dent.name))
+		info->attribute |= EFI_FILE_DIRECTORY;
+
+	ascii2unicode((u16 *)info->file_name, dent.name);
+
+	fh->offset++;
+
+	return EFI_SUCCESS;
+}
+
+static efi_status_t EFIAPI efi_file_read(struct efi_file_handle *file,
+		u64 *buffer_size, void *buffer)
+{
+	struct file_handle *fh = to_fh(file);
+	efi_status_t ret = EFI_SUCCESS;
+
+	EFI_ENTRY("%p, %p, %p", file, buffer_size, buffer);
+
+	if (set_blk_dev(fh)) {
+		ret = EFI_DEVICE_ERROR;
+		goto error;
+	}
+
+	if (fh->isdir) {
+		ret = dir_read(fh, buffer_size, buffer);
+	} else {
+		ret = file_read(fh, buffer_size, buffer);
+	}
+
+error:
+	return EFI_EXIT(ret);
+}
+
+static efi_status_t EFIAPI efi_file_write(struct efi_file_handle *file,
+		u64 *buffer_size, void *buffer)
+{
+	EFI_ENTRY("%p, %p, %p", file, buffer_size, buffer);
+	return EFI_EXIT(EFI_WRITE_PROTECTED);
+}
+
+static efi_status_t EFIAPI efi_file_getpos(struct efi_file_handle *file,
+		u64 *pos)
+{
+	struct file_handle *fh = to_fh(file);
+	EFI_ENTRY("%p, %p", file, pos);
+	*pos = fh->offset;
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_file_setpos(struct efi_file_handle *file,
+		u64 pos)
+{
+	struct file_handle *fh = to_fh(file);
+	efi_status_t ret = EFI_SUCCESS;
+
+	EFI_ENTRY("%p, %llu", file, pos);
+
+	if (fh->isdir && (pos != 0)) {
+		ret = EFI_UNSUPPORTED;
+		goto error;
+	}
+
+	if (pos == ~0ULL) {
+		loff_t file_size;
+
+		if (set_blk_dev(fh)) {
+			ret = EFI_DEVICE_ERROR;
+			goto error;
+		}
+
+		if (fs_size(fh->path, &file_size)) {
+			ret = EFI_DEVICE_ERROR;
+			goto error;
+		}
+
+		pos = file_size;
+	}
+
+	fh->offset = pos;
+
+error:
+	return EFI_EXIT(ret);
+}
+
+static efi_status_t EFIAPI efi_file_getinfo(struct efi_file_handle *file,
+		efi_guid_t *info_type, u64 *buffer_size, void *buffer)
+{
+	struct file_handle *fh = to_fh(file);
+	efi_status_t ret = EFI_SUCCESS;
+
+	EFI_ENTRY("%p, %p, %p, %p", file, info_type, buffer_size, buffer);
+
+	if (!guidcmp(info_type, &efi_file_info_guid)) {
+		struct efi_file_info *info = buffer;
+		char *filename = basename(fh);
+		unsigned required_size;
+		loff_t file_size;
+
+		/* check buffer size: */
+		required_size = sizeof(*info) + 2 * (strlen(filename) + 1);
+		if (*buffer_size < required_size) {
+			*buffer_size = required_size;
+			ret = EFI_BUFFER_TOO_SMALL;
+			goto error;
+		}
+
+		if (set_blk_dev(fh)) {
+			ret = EFI_DEVICE_ERROR;
+			goto error;
+		}
+
+		if (fs_size(fh->path, &file_size)) {
+			ret = EFI_DEVICE_ERROR;
+			goto error;
+		}
+
+		memset(info, 0, required_size);
+
+		info->size = required_size;
+		info->file_size = file_size;
+		info->physical_size = file_size;
+
+		if (fh->isdir)
+			info->attribute |= EFI_FILE_DIRECTORY;
+
+		ascii2unicode((u16 *)info->file_name, filename);
+	} else {
+		ret = EFI_UNSUPPORTED;
+	}
+
+error:
+	return EFI_EXIT(ret);
+}
+
+static efi_status_t EFIAPI efi_file_setinfo(struct efi_file_handle *file,
+		efi_guid_t *info_type, u64 buffer_size, void *buffer)
+{
+	EFI_ENTRY("%p, %p, %llu, %p", file, info_type, buffer_size, buffer);
+	return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+static efi_status_t EFIAPI efi_file_flush(struct efi_file_handle *file)
+{
+	EFI_ENTRY("%p", file);
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static const struct efi_file_handle efi_file_handle_protocol = {
+	.rev = EFI_FILE_PROTOCOL_REVISION,
+	.open = efi_file_open,
+	.close = efi_file_close,
+	.delete = efi_file_delete,
+	.read = efi_file_read,
+	.write = efi_file_write,
+	.getpos = efi_file_getpos,
+	.setpos = efi_file_setpos,
+	.getinfo = efi_file_getinfo,
+	.setinfo = efi_file_setinfo,
+	.flush = efi_file_flush,
+};
+
+struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp)
+{
+	struct efi_simple_file_system_protocol *v;
+	struct efi_file_handle *f;
+	efi_status_t ret;
+
+	v = efi_fs_from_path(fp);
+	if (!v)
+		return NULL;
+
+	EFI_CALL(ret = v->open_volume(v, &f));
+	if (ret != EFI_SUCCESS)
+		return NULL;
+
+	/* skip over device-path nodes before the file path: */
+	while (fp && !EFI_DP_TYPE(fp, MEDIA_DEVICE, FILE_PATH)) {
+		fp = efi_dp_next(fp);
+	}
+
+	while (fp) {
+		struct efi_device_path_file_path *fdp =
+			container_of(fp, struct efi_device_path_file_path, dp);
+		struct efi_file_handle *f2;
+
+		if (!EFI_DP_TYPE(fp, MEDIA_DEVICE, FILE_PATH)) {
+			printf("bad file path!\n");
+			f->close(f);
+			return NULL;
+		}
+
+		EFI_CALL(ret = f->open(f, &f2, (s16 *)fdp->str, EFI_FILE_MODE_READ, 0));
+		if (ret != EFI_SUCCESS)
+			return NULL;
+
+		fp = efi_dp_next(fp);
+
+		EFI_CALL(f->close(f));
+		f = f2;
+	}
+
+	return f;
+}
+
+static efi_status_t EFIAPI
+efi_open_volume(struct efi_simple_file_system_protocol *this,
+		struct efi_file_handle **root)
+{
+	struct file_system *fs = to_fs(this);
+
+	EFI_ENTRY("%p, %p", this, root);
+
+	*root = file_open(fs, NULL, NULL);
+
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+struct efi_simple_file_system_protocol *
+efi_simple_file_system(struct blk_desc *desc, int part,
+		       struct efi_device_path *dp)
+{
+	struct file_system *fs;
+
+	fs = calloc(1, sizeof(*fs));
+	fs->base.rev = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION;
+	fs->base.open_volume = efi_open_volume;
+	fs->desc = desc;
+	fs->part = part;
+	fs->dp = dp;
+
+	return &fs->base;
+}
diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c
index f961407f50..469acae082 100644
--- a/lib/efi_loader/efi_image_loader.c
+++ b/lib/efi_loader/efi_image_loader.c
@@ -17,6 +17,9 @@ DECLARE_GLOBAL_DATA_PTR;
 
 const efi_guid_t efi_guid_device_path = DEVICE_PATH_GUID;
 const efi_guid_t efi_guid_loaded_image = LOADED_IMAGE_GUID;
+const efi_guid_t efi_simple_file_system_protocol_guid =
+		EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
+const efi_guid_t efi_file_info_guid = EFI_FILE_INFO_GUID;
 
 static efi_status_t efi_loader_relocate(const IMAGE_BASE_RELOCATION *rel,
 			unsigned long rel_size, void *efi_reloc)
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 17/20] efi_loader: support load_image() from a file-path
  2017-08-04 19:31 [U-Boot] [PATCH v0 00/20] enough UEFI for standard distro boot Rob Clark
                   ` (15 preceding siblings ...)
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 16/20] efi_loader: add file/filesys support Rob Clark
@ 2017-08-04 19:31 ` Rob Clark
  2017-08-04 19:32 ` [U-Boot] [PATCH v0 18/20] efi_loader: make pool allocations cacheline aligned Rob Clark
                   ` (4 subsequent siblings)
  21 siblings, 0 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-04 19:31 UTC (permalink / raw)
  To: u-boot

Previously we only supported the case when the EFI application loaded
the image into memory for us.  But fallback.efi does not do this.

Signed-off-by: Rob Clark <robdclark@gmail.com>
---
 lib/efi_loader/efi_boottime.c | 83 +++++++++++++++++++++++++++++++++++--------
 1 file changed, 68 insertions(+), 15 deletions(-)

diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index 4a19fabdb3..6187065fdd 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -749,6 +749,45 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob
 	list_add_tail(&obj->link, &efi_obj_list);
 }
 
+static efi_status_t load_image_from_path(struct efi_device_path *file_path,
+					 void **buffer)
+{
+	struct efi_file_info *info = NULL;
+	struct efi_file_handle *f;
+	static efi_status_t ret;
+	uint64_t bs;
+
+	f = efi_file_from_path(file_path);
+	if (!f)
+		return EFI_DEVICE_ERROR;
+
+	bs = 0;
+	EFI_CALL(ret = f->getinfo(f, (efi_guid_t *)&efi_file_info_guid, &bs, info));
+	if (ret == EFI_BUFFER_TOO_SMALL) {
+		info = malloc(bs);
+		EFI_CALL(ret = f->getinfo(f, (efi_guid_t *)&efi_file_info_guid, &bs, info));
+	}
+	if (ret != EFI_SUCCESS)
+		goto error;
+
+	ret = efi_allocate_pool(EFI_LOADER_DATA, info->file_size, buffer);
+	if (ret)
+		goto error;
+
+	EFI_CALL(ret = f->read(f, &info->file_size, *buffer));
+
+error:
+	free(info);
+	EFI_CALL(f->close(f));
+
+	if (ret != EFI_SUCCESS) {
+		efi_free_pool(*buffer);
+		*buffer = NULL;
+	}
+
+	return ret;
+}
+
 static efi_status_t EFIAPI efi_load_image(bool boot_policy,
 					  efi_handle_t parent_image,
 					  struct efi_device_path *file_path,
@@ -756,25 +795,40 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy,
 					  unsigned long source_size,
 					  efi_handle_t *image_handle)
 {
-	static struct efi_object loaded_image_info_obj = {
-		.protocols = {
-			{
-				.guid = &efi_guid_loaded_image,
-			},
-		},
-	};
 	struct efi_loaded_image *info;
 	struct efi_object *obj;
 
 	EFI_ENTRY("%d, %p, %p, %p, %ld, %p", boot_policy, parent_image,
 		  file_path, source_buffer, source_size, image_handle);
-	info = malloc(sizeof(*info));
-	loaded_image_info_obj.protocols[0].protocol_interface = info;
-	obj = malloc(sizeof(loaded_image_info_obj));
-	memset(info, 0, sizeof(*info));
-	memcpy(obj, &loaded_image_info_obj, sizeof(loaded_image_info_obj));
-	obj->handle = info;
-	info->file_path = file_path;
+
+	info = calloc(1, sizeof(*info));
+	obj = calloc(1, sizeof(*obj));
+
+	if (!source_buffer) {
+		struct efi_device_path *dp, *fp;
+		efi_status_t ret;
+
+		ret = load_image_from_path(file_path, &source_buffer);
+		if (ret != EFI_SUCCESS) {
+			free(info);
+			free(obj);
+			return EFI_EXIT(ret);
+		}
+
+		/*
+		 * split file_path which contains both the device and
+		 * file parts:
+		 */
+		efi_dp_split_file_path(file_path, &dp, &fp);
+
+		efi_setup_loaded_image(info, obj, dp, fp);
+	} else {
+		/* In this case, file_path is the "device" path, ie.
+		 * something like a HARDWARE_DEVICE:MEMORY_MAPPED
+		 */
+		efi_setup_loaded_image(info, obj, file_path, NULL);
+	}
+
 	info->reserved = efi_load_pe(source_buffer, info);
 	if (!info->reserved) {
 		free(info);
@@ -783,7 +837,6 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy,
 	}
 
 	*image_handle = info;
-	list_add_tail(&obj->link, &efi_obj_list);
 
 	return EFI_EXIT(EFI_SUCCESS);
 }
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 18/20] efi_loader: make pool allocations cacheline aligned
  2017-08-04 19:31 [U-Boot] [PATCH v0 00/20] enough UEFI for standard distro boot Rob Clark
                   ` (16 preceding siblings ...)
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 17/20] efi_loader: support load_image() from a file-path Rob Clark
@ 2017-08-04 19:32 ` Rob Clark
  2017-08-04 19:32 ` [U-Boot] [PATCH v0 19/20] efi_loader: efi variable support Rob Clark
                   ` (3 subsequent siblings)
  21 siblings, 0 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-04 19:32 UTC (permalink / raw)
  To: u-boot

This avoids printf() spam about file reads (such as loading an image)
into unaligned buffers (and the associated memcpy()).  And generally
seems like a good idea.

Signed-off-by: Rob Clark <robdclark@gmail.com>
---
 lib/efi_loader/efi_memory.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
index 9e079f1fa3..2ba8d8b42b 100644
--- a/lib/efi_loader/efi_memory.c
+++ b/lib/efi_loader/efi_memory.c
@@ -43,7 +43,7 @@ void *efi_bounce_buffer;
  */
 struct efi_pool_allocation {
 	u64 num_pages;
-	char data[];
+	char data[] __attribute__((aligned(ARCH_DMA_MINALIGN)));
 };
 
 /*
@@ -356,7 +356,8 @@ efi_status_t efi_allocate_pool(int pool_type, unsigned long size,
 {
 	efi_status_t r;
 	efi_physical_addr_t t;
-	u64 num_pages = (size + sizeof(u64) + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT;
+	u64 num_pages = DIV_ROUND_UP(size + sizeof(struct efi_pool_allocation),
+				     EFI_PAGE_SIZE);
 
 	if (size == 0) {
 		*buffer = NULL;
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 19/20] efi_loader: efi variable support
  2017-08-04 19:31 [U-Boot] [PATCH v0 00/20] enough UEFI for standard distro boot Rob Clark
                   ` (17 preceding siblings ...)
  2017-08-04 19:32 ` [U-Boot] [PATCH v0 18/20] efi_loader: make pool allocations cacheline aligned Rob Clark
@ 2017-08-04 19:32 ` Rob Clark
  2017-08-06  5:17   ` Simon Glass
  2017-08-04 19:32 ` [U-Boot] [PATCH v0 20/20] efi_loader: add bootmgr Rob Clark
                   ` (2 subsequent siblings)
  21 siblings, 1 reply; 116+ messages in thread
From: Rob Clark @ 2017-08-04 19:32 UTC (permalink / raw)
  To: u-boot

Signed-off-by: Rob Clark <robdclark@gmail.com>
---
 cmd/bootefi.c                 |   4 +
 include/efi.h                 |  19 +++
 include/efi_loader.h          |  10 ++
 lib/efi_loader/Makefile       |   2 +-
 lib/efi_loader/efi_boottime.c |   5 +
 lib/efi_loader/efi_runtime.c  |  17 ++-
 lib/efi_loader/efi_variable.c | 342 ++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 394 insertions(+), 5 deletions(-)
 create mode 100644 lib/efi_loader/efi_variable.c

diff --git a/cmd/bootefi.c b/cmd/bootefi.c
index b9e1e5e131..80f52e9e35 100644
--- a/cmd/bootefi.c
+++ b/cmd/bootefi.c
@@ -181,6 +181,10 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt,
 		goto exit;
 	}
 
+	/* we don't support much: */
+	setenv("efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_OsIndicationsSupported",
+			"{ro,boot}(blob)0000000000000000");
+
 	/* Call our payload! */
 	debug("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry);
 
diff --git a/include/efi.h b/include/efi.h
index ddd2b96417..dbd482a5db 100644
--- a/include/efi.h
+++ b/include/efi.h
@@ -324,6 +324,25 @@ extern char image_base[];
 /* Start and end of U-Boot image (for payload) */
 extern char _binary_u_boot_bin_start[], _binary_u_boot_bin_end[];
 
+/*
+ * Variable Attributes
+ */
+#define EFI_VARIABLE_NON_VOLATILE       0x0000000000000001
+#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002
+#define EFI_VARIABLE_RUNTIME_ACCESS     0x0000000000000004
+#define EFI_VARIABLE_HARDWARE_ERROR_RECORD 0x0000000000000008
+#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x0000000000000010
+#define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x0000000000000020
+#define EFI_VARIABLE_APPEND_WRITE	0x0000000000000040
+
+#define EFI_VARIABLE_MASK 	(EFI_VARIABLE_NON_VOLATILE | \
+				EFI_VARIABLE_BOOTSERVICE_ACCESS | \
+				EFI_VARIABLE_RUNTIME_ACCESS | \
+				EFI_VARIABLE_HARDWARE_ERROR_RECORD | \
+				EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | \
+				EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | \
+				EFI_VARIABLE_APPEND_WRITE)
+
 /**
  * efi_get_sys_table() - Get access to the main EFI system table
  *
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 4210d5f19a..f14fdfa58e 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -296,6 +296,16 @@ efi_status_t __efi_runtime EFIAPI efi_get_time(
 			struct efi_time_cap *capabilities);
 void efi_get_time_init(void);
 
+efi_status_t EFIAPI efi_get_variable(s16 *variable_name,
+		efi_guid_t *vendor, u32 *attributes,
+		unsigned long *data_size, void *data);
+efi_status_t EFIAPI efi_get_next_variable(
+		unsigned long *variable_name_size,
+		s16 *variable_name, efi_guid_t *vendor);
+efi_status_t EFIAPI efi_set_variable(s16 *variable_name,
+		efi_guid_t *vendor, u32 attributes,
+		unsigned long data_size, void *data);
+
 #else /* defined(EFI_LOADER) && !defined(CONFIG_SPL_BUILD) */
 
 /* Without CONFIG_EFI_LOADER we don't have a runtime section, stub it out */
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index cce92cfeb5..f58cb13337 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -16,7 +16,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 efi_device_path.o
-obj-y += efi_file.o
+obj-y += efi_file.o efi_variable.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_boottime.c b/lib/efi_loader/efi_boottime.c
index 6187065fdd..19eaea8baf 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -927,6 +927,11 @@ static efi_status_t EFIAPI efi_exit_boot_services(void *image_handle,
 {
 	EFI_ENTRY("%p, %ld", image_handle, map_key);
 
+#if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE)
+	/* save any EFI variables that have been written: */
+	saveenv();
+#endif
+
 	board_quiesce_devices();
 
 	/* Fix up caches for EFI payloads if necessary */
diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c
index dd52755d1d..7615090ba3 100644
--- a/lib/efi_loader/efi_runtime.c
+++ b/lib/efi_loader/efi_runtime.c
@@ -184,7 +184,16 @@ static const struct efi_runtime_detach_list_struct efi_runtime_detach_list[] = {
 		/* Clean up system table */
 		.ptr = &systab.boottime,
 		.patchto = NULL,
-	},
+	}, {
+		.ptr = &efi_runtime_services.get_variable,
+		.patchto = &efi_device_error,
+	}, {
+		.ptr = &efi_runtime_services.get_next_variable,
+		.patchto = &efi_device_error,
+	}, {
+		.ptr = &efi_runtime_services.set_variable,
+		.patchto = &efi_device_error,
+	}
 };
 
 static bool efi_runtime_tobedetached(void *p)
@@ -382,9 +391,9 @@ struct efi_runtime_services __efi_runtime_data efi_runtime_services = {
 	.set_wakeup_time = (void *)&efi_unimplemented,
 	.set_virtual_address_map = &efi_set_virtual_address_map,
 	.convert_pointer = (void *)&efi_invalid_parameter,
-	.get_variable = (void *)&efi_device_error,
-	.get_next_variable = (void *)&efi_device_error,
-	.set_variable = (void *)&efi_device_error,
+	.get_variable = efi_get_variable,
+	.get_next_variable = efi_get_next_variable,
+	.set_variable = efi_set_variable,
 	.get_next_high_mono_count = (void *)&efi_device_error,
 	.reset_system = &efi_reset_system_boottime,
 };
diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c
new file mode 100644
index 0000000000..721b14807f
--- /dev/null
+++ b/lib/efi_loader/efi_variable.c
@@ -0,0 +1,342 @@
+/*
+ *  EFI utils
+ *
+ *  Copyright (c) 2017 Rob Clark
+ *
+ *  SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <malloc.h>
+#include <charset.h>
+#include <efi_loader.h>
+
+#define READ_ONLY BIT(31)
+
+/* Mapping between EFI variables and u-boot variables:
+ *
+ *   efi_$guid_$varname = {attributes}(type)value
+ *
+ * For example:
+ *
+ *   efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_OsIndicationsSupported=
+ *      "{ro,boot,run}(blob)0000000000000000"
+ *   efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_BootOrder=
+ *      "(blob)00010000"
+ *
+ * The attributes are a comma separated list of these possible attributes:
+
+ *   + ro   - read-only
+ *   + boot - boot-services access
+ *   + run  - runtime access
+ *
+ * NOTE: with current implementation, no variables are available after
+ * ExitBootServices, and all are persisted (if possible).
+ *
+ * If not specified, the attributes default to "{boot}".
+ *
+ * The required type is one of:
+ *
+ *   + utf8 - raw utf8 string
+ *   + blob - arbitrary length hex string
+ *
+ * Maybe a utf16 type would be useful to for a string value to be auto
+ * converted to utf16?
+ */
+
+#define MAX_VAR_NAME 31
+#define MAX_NATIVE_VAR_NAME \
+	(strlen("efi_xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxxxxxx_") + \
+		(MAX_VAR_NAME * MAX_UTF8_PER_UTF16))
+
+static int hex(unsigned char ch)
+{
+	if (ch >= 'a' && ch <= 'f')
+		return ch-'a'+10;
+	if (ch >= '0' && ch <= '9')
+		return ch-'0';
+	if (ch >= 'A' && ch <= 'F')
+		return ch-'A'+10;
+	return -1;
+}
+
+static const char * hex2mem(u8 *mem, const char *hexstr, int count)
+{
+	memset(mem, 0, count/2);
+
+	do {
+		int nibble;
+
+		*mem = 0;
+
+		if (!count || !*hexstr)
+			break;
+
+		nibble = hex(*hexstr);
+		if (nibble < 0)
+			break;
+
+		*mem = nibble;
+		count--;
+		hexstr++;
+
+		if (!count || !*hexstr)
+			break;
+
+		nibble = hex(*hexstr);
+		if (nibble < 0)
+			break;
+
+		*mem = (*mem << 4) | nibble;
+		count--;
+		hexstr++;
+		mem++;
+
+	} while (1);
+
+	if (*hexstr)
+		return hexstr;
+
+	return NULL;
+}
+
+static char * mem2hex(char *hexstr, const u8 *mem, int count)
+{
+	static const char hexchars[] = "0123456789abcdef";
+
+	while (count-- > 0) {
+		u8 ch = *mem++;
+		*hexstr++ = hexchars[ch >> 4];
+		*hexstr++ = hexchars[ch & 0xf];
+	}
+
+	return hexstr;
+}
+
+static efi_status_t efi_to_native(char *native, s16 *variable_name,
+		efi_guid_t *vendor)
+{
+	size_t len;
+
+	len = utf16_strlen((u16 *)variable_name);
+	if (len >= MAX_VAR_NAME)
+		return EFI_DEVICE_ERROR;
+
+	native += sprintf(native, "efi_");
+	native += guidstr(native, vendor);
+	native += sprintf(native, "_");
+	native  = (char *)utf16_to_utf8((u8 *)native, (u16 *)variable_name, len);
+	*native = '\0';
+
+	return EFI_SUCCESS;
+}
+
+static const char * prefix(const char *str, const char *prefix)
+{
+	while (*str && *prefix) {
+		if (*str != *prefix)
+			break;
+		str++;
+		prefix++;
+	}
+
+	if (*prefix)
+		return NULL;
+
+	return str;
+}
+
+/* parse attributes part of variable value, if present: */
+static const char * parse_attr(const char *str, u32 *attrp)
+{
+	u32 attr = 0;
+	char sep = '{';
+
+	if (*str != '{') {
+		*attrp = EFI_VARIABLE_BOOTSERVICE_ACCESS;
+		return str;
+	}
+
+	while (*str == sep) {
+		const char *s;
+
+		str++;
+
+		if ((s = prefix(str, "ro"))) {
+			attr |= READ_ONLY;
+		} else if ((s = prefix(str, "boot"))) {
+			attr |= EFI_VARIABLE_BOOTSERVICE_ACCESS;
+		} else if ((s = prefix(str, "run"))) {
+			attr |= EFI_VARIABLE_RUNTIME_ACCESS;
+		} else {
+			printf("invalid attribute: %s\n", str);
+			break;
+		}
+
+		str = s;
+		sep = ',';
+	}
+
+	str++;
+
+	*attrp = attr;
+
+	return str;
+}
+
+/* http://wiki.phoenix.com/wiki/index.php/EFI_RUNTIME_SERVICES#GetVariable.28.29 */
+efi_status_t EFIAPI efi_get_variable(s16 *variable_name,
+		efi_guid_t *vendor, u32 *attributes,
+		unsigned long *data_size, void *data)
+{
+	char native_name[MAX_NATIVE_VAR_NAME + 1];
+	efi_status_t ret;
+	unsigned long in_size;
+	const char *val, *s;
+	u32 attr;
+
+	EFI_ENTRY("%p %p %p %p %p", variable_name, vendor, attributes,
+			data_size, data);
+
+	if (!variable_name || !vendor || !data_size)
+		return EFI_EXIT(EFI_INVALID_PARAMETER);
+
+	ret = efi_to_native(native_name, variable_name, vendor);
+	if (ret)
+		return EFI_EXIT(ret);
+
+	debug("%s: get '%s'\n", __func__, native_name);
+
+	val = getenv(native_name);
+	if (!val)
+		return EFI_EXIT(EFI_NOT_FOUND);
+
+	val = parse_attr(val, &attr);
+
+	in_size = *data_size;
+
+	if ((s = prefix(val, "(blob)"))) {
+		unsigned len = strlen(s);
+
+		/* two characters per byte: */
+		len = DIV_ROUND_UP(len, 2);
+		*data_size = len;
+
+		if (in_size < len)
+			return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
+
+		if (!data)
+			return EFI_EXIT(EFI_INVALID_PARAMETER);
+
+		if (hex2mem(data, s, len * 2))
+			return EFI_EXIT(EFI_DEVICE_ERROR);
+
+		debug("%s: got value: \"%s\"\n", __func__, s);
+	} else if ((s = prefix(val, "(string)"))) {
+		unsigned len = strlen(s) + 1;
+
+		*data_size = len;
+
+		if (in_size < len)
+			return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
+
+		if (!data)
+			return EFI_EXIT(EFI_INVALID_PARAMETER);
+
+		memcpy(data, s, len);
+		((char *)data)[len] = '\0';
+
+		debug("%s: got value: \"%s\"\n", __func__, (char *)data);
+	} else {
+		debug("%s: invalid value: '%s'\n", __func__, val);
+		return EFI_EXIT(EFI_DEVICE_ERROR);
+	}
+
+	if (attributes)
+		*attributes = attr & EFI_VARIABLE_MASK;
+
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+/* http://wiki.phoenix.com/wiki/index.php/EFI_RUNTIME_SERVICES#GetNextVariableName.28.29 */
+efi_status_t EFIAPI efi_get_next_variable(
+		unsigned long *variable_name_size,
+		s16 *variable_name, efi_guid_t *vendor)
+{
+	EFI_ENTRY("%p %p %p", variable_name_size, variable_name, vendor);
+
+	return EFI_EXIT(EFI_DEVICE_ERROR);
+}
+
+/* http://wiki.phoenix.com/wiki/index.php/EFI_RUNTIME_SERVICES#SetVariable.28.29 */
+efi_status_t EFIAPI efi_set_variable(s16 *variable_name,
+		efi_guid_t *vendor, u32 attributes,
+		unsigned long data_size, void *data)
+{
+	char native_name[MAX_NATIVE_VAR_NAME + 1];
+	efi_status_t ret = EFI_SUCCESS;
+	char *val, *s;
+	u32 attr;
+
+	EFI_ENTRY("%p %p %x %lu %p", variable_name, vendor, attributes,
+			data_size, data);
+
+	if (!variable_name || !vendor || !data_size)
+		return EFI_EXIT(EFI_INVALID_PARAMETER);
+
+	ret = efi_to_native(native_name, variable_name, vendor);
+	if (ret)
+		return EFI_EXIT(ret);
+
+#define ACCESS_ATTR (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)
+
+	if ((data_size == 0) || !(attributes & ACCESS_ATTR)) {
+		/* delete the variable: */
+		setenv(native_name, NULL);
+		return EFI_EXIT(EFI_SUCCESS);
+	}
+
+	val = getenv(native_name);
+	if (val) {
+		parse_attr(val, &attr);
+
+		if (attr & READ_ONLY)
+			return EFI_EXIT(EFI_WRITE_PROTECTED);
+	}
+
+	val = malloc(2 * data_size + strlen("{ro,run,boot}(blob)") + 1);
+	if (!val)
+		return EFI_EXIT(EFI_OUT_OF_RESOURCES);
+
+	s = val;
+
+	/* store attributes: */
+	attributes &= (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS);
+	s += sprintf(s, "{");
+	while (attributes) {
+		u32 attr = 1 << (ffs(attributes) - 1);
+
+		if (attr == EFI_VARIABLE_BOOTSERVICE_ACCESS)
+			s += sprintf(s, "boot");
+		else if (attr == EFI_VARIABLE_RUNTIME_ACCESS)
+			s += sprintf(s, "run");
+
+		attributes &= ~attr;
+		if (attributes)
+			s += sprintf(s, ",");
+	}
+	s += sprintf(s, "}");
+
+	/* store payload: */
+	s += sprintf(s, "(blob)");
+	s = mem2hex(s, data, data_size);
+	*s = '\0';
+
+	debug("%s: setting: %s=%s\n", __func__, native_name, val);
+
+	if (setenv(native_name, val))
+		ret = EFI_DEVICE_ERROR;
+
+	free(val);
+
+	return EFI_EXIT(ret);
+}
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 20/20] efi_loader: add bootmgr
  2017-08-04 19:31 [U-Boot] [PATCH v0 00/20] enough UEFI for standard distro boot Rob Clark
                   ` (18 preceding siblings ...)
  2017-08-04 19:32 ` [U-Boot] [PATCH v0 19/20] efi_loader: efi variable support Rob Clark
@ 2017-08-04 19:32 ` Rob Clark
  2017-08-04 20:06   ` Heinrich Schuchardt
  2017-08-05 15:58 ` [U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses Rob Clark
  2017-08-10  1:32 ` [U-Boot] [PATCH v0 00/20] enough UEFI for standard distro boot Tom Rini
  21 siblings, 1 reply; 116+ messages in thread
From: Rob Clark @ 2017-08-04 19:32 UTC (permalink / raw)
  To: u-boot

Similar to a "real" UEFI implementation, the bootmgr looks at the
BootOrder and BootXXXX variables to try to find an EFI payload to load
and boot.  This is added as a sub-command of bootefi.

The idea is that the distro bootcmd would first try loading a payload
via the bootmgr, and then if that fails (ie. first boot or corrupted
EFI variables) it would fallback to loading bootaa64.efi.  (Which
would then load fallback.efi which would look for \EFI\*\boot.csv and
populate BootOrder and BootXXXX based on what it found.)

Signed-off-by: Rob Clark <robdclark@gmail.com>
---
 cmd/bootefi.c                     |  48 ++++++++++-
 include/config_distro_bootcmd.h   |   5 ++
 include/efi_api.h                 |   4 +
 include/efi_loader.h              |   6 ++
 lib/efi_loader/Makefile           |   2 +-
 lib/efi_loader/efi_bootmgr.c      | 169 ++++++++++++++++++++++++++++++++++++++
 lib/efi_loader/efi_boottime.c     |   6 +-
 lib/efi_loader/efi_image_loader.c |   1 +
 8 files changed, 235 insertions(+), 6 deletions(-)
 create mode 100644 lib/efi_loader/efi_bootmgr.c

diff --git a/cmd/bootefi.c b/cmd/bootefi.c
index 80f52e9e35..02a0dd159b 100644
--- a/cmd/bootefi.c
+++ b/cmd/bootefi.c
@@ -219,6 +219,36 @@ exit:
 	return ret;
 }
 
+static int do_bootefi_bootmgr_exec(unsigned long fdt_addr)
+{
+	struct efi_device_path *device_path, *file_path;
+	void *addr;
+	efi_status_t r;
+
+	/* Initialize and populate EFI object list */
+	if (!efi_obj_list_initalized)
+		efi_init_obj_list();
+
+	/*
+	 * 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
+	 */
+	efi_save_gd();
+
+	addr = efi_bootmgr_load(&device_path, &file_path);
+	if (!addr)
+		return 1;
+
+	printf("## Starting EFI application at %p ...\n", addr);
+	r = do_bootefi_exec(addr, (void*)fdt_addr, device_path, file_path);
+	printf("## Application terminated, r = %lu\n",
+	       r & ~EFI_ERROR_MASK);
+
+	if (r != EFI_SUCCESS)
+		return 1;
+
+	return 0;
+}
 
 /* Interpreter command to boot an arbitrary EFI image from memory */
 static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
@@ -237,7 +267,14 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		memcpy((char *)addr, __efi_hello_world_begin, size);
 	} else
 #endif
-	{
+	if (!strcmp(argv[1], "bootmgr")) {
+		unsigned long fdt_addr = 0;
+
+		if (argc > 2)
+			fdt_addr = simple_strtoul(argv[2], NULL, 16);
+
+		return do_bootefi_bootmgr_exec(fdt_addr);
+	} else {
 		saddr = argv[1];
 
 		addr = simple_strtoul(saddr, NULL, 16);
@@ -270,7 +307,11 @@ static char bootefi_help_text[] =
 	"hello\n"
 	"  - boot a sample Hello World application stored within U-Boot"
 #endif
-	;
+	"bootmgr [fdt addr]\n"
+	"  - load and boot EFI payload based on BootOrder/BootXXXX variables.\n"
+	"\n"
+	"    If specified, the device tree located at <fdt address> gets\n"
+	"    exposed as EFI configuration table.\n";
 #endif
 
 U_BOOT_CMD(
@@ -308,6 +349,9 @@ void efi_set_bootdev(const char *dev, const char *devnr, const char *path)
 #endif
 	}
 
+	if (!path)
+		return;
+
 	if (strcmp(dev, "Net")) {
 		/* Add leading / to fs paths, because they're absolute */
 		snprintf(filename, sizeof(filename), "/%s", path);
diff --git a/include/config_distro_bootcmd.h b/include/config_distro_bootcmd.h
index d8dab8e46a..94ccab02d2 100644
--- a/include/config_distro_bootcmd.h
+++ b/include/config_distro_bootcmd.h
@@ -112,6 +112,11 @@
 
 #define BOOTENV_SHARED_EFI                                                \
 	"boot_efi_binary="                                                \
+		"if fdt addr ${fdt_addr_r}; then "                        \
+			"bootefi bootmgr ${fdt_addr_r};"                  \
+		"else "                                                   \
+			"bootefi bootmgr ${fdtcontroladdr};"              \
+		"fi;"                                                     \
 		"load ${devtype} ${devnum}:${distro_bootpart} "           \
 			"${kernel_addr_r} efi/boot/"BOOTEFI_NAME"; "      \
 		"if fdt addr ${fdt_addr_r}; then "                        \
diff --git a/include/efi_api.h b/include/efi_api.h
index 1a542846b3..ef91e34c7b 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -211,6 +211,10 @@ struct efi_runtime_services {
 	EFI_GUID(0x00000000, 0x0000, 0x0000, 0x00, 0x00, \
 		 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)
 
+#define EFI_GLOBAL_VARIABLE_GUID \
+	EFI_GUID(0x8be4df61, 0x93ca, 0x11d2, 0xaa, 0x0d, \
+		 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c)
+
 #define LOADED_IMAGE_PROTOCOL_GUID \
 	EFI_GUID(0x5b1b31a1, 0x9562, 0x11d2, 0x8e, 0x3f, \
 		 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
diff --git a/include/efi_loader.h b/include/efi_loader.h
index f14fdfa58e..e3eb932f54 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -61,6 +61,7 @@ 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_global_variable_guid;
 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;
@@ -219,6 +220,8 @@ efi_status_t efi_get_protocol(struct efi_object *efiobj,
 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);
+efi_status_t efi_load_image_from_path(struct efi_device_path *file_path,
+				      void **buffer);
 
 #ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER
 extern void *efi_bounce_buffer;
@@ -306,6 +309,9 @@ efi_status_t EFIAPI efi_set_variable(s16 *variable_name,
 		efi_guid_t *vendor, u32 attributes,
 		unsigned long data_size, void *data);
 
+void *efi_bootmgr_load(struct efi_device_path **device_path,
+		       struct efi_device_path **file_path);
+
 #else /* defined(EFI_LOADER) && !defined(CONFIG_SPL_BUILD) */
 
 /* Without CONFIG_EFI_LOADER we don't have a runtime section, stub it out */
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index f58cb13337..930c0e218e 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -16,7 +16,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 efi_device_path.o
-obj-y += efi_file.o efi_variable.o
+obj-y += efi_file.o efi_variable.o efi_bootmgr.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_bootmgr.c b/lib/efi_loader/efi_bootmgr.c
new file mode 100644
index 0000000000..8246ddd48f
--- /dev/null
+++ b/lib/efi_loader/efi_bootmgr.c
@@ -0,0 +1,169 @@
+/*
+ *  EFI utils
+ *
+ *  Copyright (c) 2017 Rob Clark
+ *
+ *  SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <charset.h>
+#include <malloc.h>
+#include <efi_loader.h>
+
+static const struct efi_boot_services *bs;
+static const struct efi_runtime_services *rs;
+
+#define LOAD_OPTION_ACTIVE		0x00000001
+#define LOAD_OPTION_FORCE_RECONNECT	0x00000002
+#define LOAD_OPTION_HIDDEN		0x00000008
+
+/*
+ * bootmgr implements the logic of trying to find a payload to boot
+ * based on the BootOrder + BootXXXX variables, and then loading it.
+ *
+ * TODO detecting a special key held (f9?) and displaying a boot menu
+ * like you would get on a PC would be clever.
+ *
+ * TODO if we had a way to write and persist variables after the OS
+ * has started, we'd also want to check OsIndications to see if we
+ * should do normal or recovery boot.
+ */
+
+
+/*
+ * See section 3.1.3 in the v2.7 UEFI spec for more details on
+ * the layout of EFI_LOAD_OPTION.  In short it is:
+ *
+ *    typedef struct _EFI_LOAD_OPTION {
+ *        UINT32 Attributes;
+ *        UINT16 FilePathListLength;
+ *        // CHAR16 Description[];   <-- variable length, NULL terminated
+ *        // EFI_DEVICE_PATH_PROTOCOL FilePathList[];  <-- FilePathListLength bytes
+ *        // UINT8 OptionalData[];
+ *    } EFI_LOAD_OPTION;
+ */
+struct load_option {
+	u32 attributes;
+	u16 file_path_length;
+	u16 *label;
+	struct efi_device_path *file_path;
+	u8 *optional_data;
+};
+
+static void parse_load_option(struct load_option *lo, void *ptr)
+{
+	lo->attributes = *(u32 *)ptr;
+	ptr += sizeof(u32);
+
+	lo->file_path_length = *(u16 *)ptr;
+	ptr += sizeof(u16);
+
+	lo->label = ptr;
+	ptr += (utf16_strlen(lo->label) + 1) * 2;
+
+	lo->file_path = ptr;
+	ptr += lo->file_path_length;
+
+	lo->optional_data = ptr;
+}
+
+/* free() the result */
+static void *get_var(u16 *name, const efi_guid_t *vendor,
+		     unsigned long *size)
+{
+	efi_guid_t *v = (efi_guid_t *)vendor;
+	efi_status_t ret;
+	void *buf = NULL;
+
+	*size = 0;
+	EFI_CALL(ret = rs->get_variable((s16 *)name, v, NULL, size, buf));
+	if (ret == EFI_BUFFER_TOO_SMALL) {
+		buf = malloc(*size);
+		EFI_CALL(ret = rs->get_variable((s16 *)name, v, NULL, size, buf));
+	}
+
+	if (ret != EFI_SUCCESS) {
+		free(buf);
+		*size = 0;
+		return NULL;
+	}
+
+	return buf;
+}
+
+static void *try_load_entry(uint16_t n, struct efi_device_path **device_path,
+			    struct efi_device_path **file_path)
+{
+	struct load_option lo;
+	u16 varname[] = L"Boot0000";
+	u16 hexmap[] = L"0123456789ABCDEF";
+	void *load_option, *image = NULL;
+	unsigned long size;
+
+	varname[4] = hexmap[(n & 0xf000) >> 12];
+	varname[5] = hexmap[(n & 0x0f00) >> 8];
+	varname[6] = hexmap[(n & 0x00f0) >> 4];
+	varname[7] = hexmap[(n & 0x000f) >> 0];
+
+	load_option = get_var(varname, &efi_global_variable_guid, &size);
+	if (!load_option)
+		return NULL;
+
+	parse_load_option(&lo, load_option);
+
+	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);
+
+		ret = efi_load_image_from_path(lo.file_path, &image);
+
+		if (ret != EFI_SUCCESS)
+			goto error;
+
+		printf("Booting: %ls\n", lo.label);
+		efi_dp_split_file_path(lo.file_path, device_path, file_path);
+	}
+
+error:
+	free(load_option);
+
+	return image;
+}
+
+void *efi_bootmgr_load(struct efi_device_path **device_path,
+		       struct efi_device_path **file_path)
+{
+	uint16_t *bootorder;
+	unsigned long size;
+	void *image = NULL;
+	int i, num;
+
+	__efi_entry_check();
+
+	bs = systab.boottime;
+	rs = systab.runtime;
+
+	bootorder = get_var(L"BootOrder", &efi_global_variable_guid, &size);
+	if (!bootorder)
+		goto error;
+
+	num = size / sizeof(uint16_t);
+	for (i = 0; i < num; i++) {
+		debug("%s: trying to load Boot%04X\n", __func__, bootorder[i]);
+		image = try_load_entry(bootorder[i], device_path, file_path);
+		if (image)
+			break;
+	}
+
+	free(bootorder);
+
+error:
+	__efi_exit_check();
+
+	return image;
+}
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index 19eaea8baf..5ff2d2d4b0 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -749,8 +749,8 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob
 	list_add_tail(&obj->link, &efi_obj_list);
 }
 
-static efi_status_t load_image_from_path(struct efi_device_path *file_path,
-					 void **buffer)
+efi_status_t efi_load_image_from_path(struct efi_device_path *file_path,
+				      void **buffer)
 {
 	struct efi_file_info *info = NULL;
 	struct efi_file_handle *f;
@@ -808,7 +808,7 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy,
 		struct efi_device_path *dp, *fp;
 		efi_status_t ret;
 
-		ret = load_image_from_path(file_path, &source_buffer);
+		ret = efi_load_image_from_path(file_path, &source_buffer);
 		if (ret != EFI_SUCCESS) {
 			free(info);
 			free(obj);
diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c
index 469acae082..242e6a504b 100644
--- a/lib/efi_loader/efi_image_loader.c
+++ b/lib/efi_loader/efi_image_loader.c
@@ -15,6 +15,7 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+const efi_guid_t efi_global_variable_guid = EFI_GLOBAL_VARIABLE_GUID;
 const efi_guid_t efi_guid_device_path = DEVICE_PATH_GUID;
 const efi_guid_t efi_guid_loaded_image = LOADED_IMAGE_GUID;
 const efi_guid_t efi_simple_file_system_protocol_guid =
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 20/20] efi_loader: add bootmgr
  2017-08-04 19:32 ` [U-Boot] [PATCH v0 20/20] efi_loader: add bootmgr Rob Clark
@ 2017-08-04 20:06   ` Heinrich Schuchardt
  2017-08-04 20:28     ` Rob Clark
  0 siblings, 1 reply; 116+ messages in thread
From: Heinrich Schuchardt @ 2017-08-04 20:06 UTC (permalink / raw)
  To: u-boot

On 08/04/2017 09:32 PM, Rob Clark wrote:
> Similar to a "real" UEFI implementation, the bootmgr looks at the
> BootOrder and BootXXXX variables to try to find an EFI payload to load
> and boot.  This is added as a sub-command of bootefi.
> 
> The idea is that the distro bootcmd would first try loading a payload
> via the bootmgr, and then if that fails (ie. first boot or corrupted
> EFI variables) it would fallback to loading bootaa64.efi.  (Which
> would then load fallback.efi which would look for \EFI\*\boot.csv and
> populate BootOrder and BootXXXX based on what it found.)


I wonder if this implementation is Fedora specific.

For Debian I could not find any reference to boot.csv.
And it is not mentioned in the UEFI 2.7 spec.

Please, provide the specification that your work is based on.

Best regards

Heinrich


> 
> Signed-off-by: Rob Clark <robdclark@gmail.com>
> ---
>  cmd/bootefi.c                     |  48 ++++++++++-
>  include/config_distro_bootcmd.h   |   5 ++
>  include/efi_api.h                 |   4 +
>  include/efi_loader.h              |   6 ++
>  lib/efi_loader/Makefile           |   2 +-
>  lib/efi_loader/efi_bootmgr.c      | 169 ++++++++++++++++++++++++++++++++++++++
>  lib/efi_loader/efi_boottime.c     |   6 +-
>  lib/efi_loader/efi_image_loader.c |   1 +
>  8 files changed, 235 insertions(+), 6 deletions(-)
>  create mode 100644 lib/efi_loader/efi_bootmgr.c
> 
> diff --git a/cmd/bootefi.c b/cmd/bootefi.c
> index 80f52e9e35..02a0dd159b 100644
> --- a/cmd/bootefi.c
> +++ b/cmd/bootefi.c
> @@ -219,6 +219,36 @@ exit:
>  	return ret;
>  }
>  
> +static int do_bootefi_bootmgr_exec(unsigned long fdt_addr)
> +{
> +	struct efi_device_path *device_path, *file_path;
> +	void *addr;
> +	efi_status_t r;
> +
> +	/* Initialize and populate EFI object list */
> +	if (!efi_obj_list_initalized)
> +		efi_init_obj_list();
> +
> +	/*
> +	 * 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
> +	 */
> +	efi_save_gd();
> +
> +	addr = efi_bootmgr_load(&device_path, &file_path);
> +	if (!addr)
> +		return 1;
> +
> +	printf("## Starting EFI application at %p ...\n", addr);
> +	r = do_bootefi_exec(addr, (void*)fdt_addr, device_path, file_path);
> +	printf("## Application terminated, r = %lu\n",
> +	       r & ~EFI_ERROR_MASK);
> +
> +	if (r != EFI_SUCCESS)
> +		return 1;
> +
> +	return 0;
> +}
>  
>  /* Interpreter command to boot an arbitrary EFI image from memory */
>  static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
> @@ -237,7 +267,14 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
>  		memcpy((char *)addr, __efi_hello_world_begin, size);
>  	} else
>  #endif
> -	{
> +	if (!strcmp(argv[1], "bootmgr")) {
> +		unsigned long fdt_addr = 0;
> +
> +		if (argc > 2)
> +			fdt_addr = simple_strtoul(argv[2], NULL, 16);
> +
> +		return do_bootefi_bootmgr_exec(fdt_addr);
> +	} else {
>  		saddr = argv[1];
>  
>  		addr = simple_strtoul(saddr, NULL, 16);
> @@ -270,7 +307,11 @@ static char bootefi_help_text[] =
>  	"hello\n"
>  	"  - boot a sample Hello World application stored within U-Boot"
>  #endif
> -	;
> +	"bootmgr [fdt addr]\n"
> +	"  - load and boot EFI payload based on BootOrder/BootXXXX variables.\n"
> +	"\n"
> +	"    If specified, the device tree located at <fdt address> gets\n"
> +	"    exposed as EFI configuration table.\n";
>  #endif
>  
>  U_BOOT_CMD(
> @@ -308,6 +349,9 @@ void efi_set_bootdev(const char *dev, const char *devnr, const char *path)
>  #endif
>  	}
>  
> +	if (!path)
> +		return;
> +
>  	if (strcmp(dev, "Net")) {
>  		/* Add leading / to fs paths, because they're absolute */
>  		snprintf(filename, sizeof(filename), "/%s", path);
> diff --git a/include/config_distro_bootcmd.h b/include/config_distro_bootcmd.h
> index d8dab8e46a..94ccab02d2 100644
> --- a/include/config_distro_bootcmd.h
> +++ b/include/config_distro_bootcmd.h
> @@ -112,6 +112,11 @@
>  
>  #define BOOTENV_SHARED_EFI                                                \
>  	"boot_efi_binary="                                                \
> +		"if fdt addr ${fdt_addr_r}; then "                        \
> +			"bootefi bootmgr ${fdt_addr_r};"                  \
> +		"else "                                                   \
> +			"bootefi bootmgr ${fdtcontroladdr};"              \
> +		"fi;"                                                     \
>  		"load ${devtype} ${devnum}:${distro_bootpart} "           \
>  			"${kernel_addr_r} efi/boot/"BOOTEFI_NAME"; "      \
>  		"if fdt addr ${fdt_addr_r}; then "                        \
> diff --git a/include/efi_api.h b/include/efi_api.h
> index 1a542846b3..ef91e34c7b 100644
> --- a/include/efi_api.h
> +++ b/include/efi_api.h
> @@ -211,6 +211,10 @@ struct efi_runtime_services {
>  	EFI_GUID(0x00000000, 0x0000, 0x0000, 0x00, 0x00, \
>  		 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)
>  
> +#define EFI_GLOBAL_VARIABLE_GUID \
> +	EFI_GUID(0x8be4df61, 0x93ca, 0x11d2, 0xaa, 0x0d, \
> +		 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c)
> +
>  #define LOADED_IMAGE_PROTOCOL_GUID \
>  	EFI_GUID(0x5b1b31a1, 0x9562, 0x11d2, 0x8e, 0x3f, \
>  		 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
> diff --git a/include/efi_loader.h b/include/efi_loader.h
> index f14fdfa58e..e3eb932f54 100644
> --- a/include/efi_loader.h
> +++ b/include/efi_loader.h
> @@ -61,6 +61,7 @@ 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_global_variable_guid;
>  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;
> @@ -219,6 +220,8 @@ efi_status_t efi_get_protocol(struct efi_object *efiobj,
>  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);
> +efi_status_t efi_load_image_from_path(struct efi_device_path *file_path,
> +				      void **buffer);
>  
>  #ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER
>  extern void *efi_bounce_buffer;
> @@ -306,6 +309,9 @@ efi_status_t EFIAPI efi_set_variable(s16 *variable_name,
>  		efi_guid_t *vendor, u32 attributes,
>  		unsigned long data_size, void *data);
>  
> +void *efi_bootmgr_load(struct efi_device_path **device_path,
> +		       struct efi_device_path **file_path);
> +
>  #else /* defined(EFI_LOADER) && !defined(CONFIG_SPL_BUILD) */
>  
>  /* Without CONFIG_EFI_LOADER we don't have a runtime section, stub it out */
> diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
> index f58cb13337..930c0e218e 100644
> --- a/lib/efi_loader/Makefile
> +++ b/lib/efi_loader/Makefile
> @@ -16,7 +16,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 efi_device_path.o
> -obj-y += efi_file.o efi_variable.o
> +obj-y += efi_file.o efi_variable.o efi_bootmgr.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_bootmgr.c b/lib/efi_loader/efi_bootmgr.c
> new file mode 100644
> index 0000000000..8246ddd48f
> --- /dev/null
> +++ b/lib/efi_loader/efi_bootmgr.c
> @@ -0,0 +1,169 @@
> +/*
> + *  EFI utils
> + *
> + *  Copyright (c) 2017 Rob Clark
> + *
> + *  SPDX-License-Identifier:     GPL-2.0+
> + */
> +
> +#include <common.h>
> +#include <charset.h>
> +#include <malloc.h>
> +#include <efi_loader.h>
> +
> +static const struct efi_boot_services *bs;
> +static const struct efi_runtime_services *rs;
> +
> +#define LOAD_OPTION_ACTIVE		0x00000001
> +#define LOAD_OPTION_FORCE_RECONNECT	0x00000002
> +#define LOAD_OPTION_HIDDEN		0x00000008
> +
> +/*
> + * bootmgr implements the logic of trying to find a payload to boot
> + * based on the BootOrder + BootXXXX variables, and then loading it.
> + *
> + * TODO detecting a special key held (f9?) and displaying a boot menu
> + * like you would get on a PC would be clever.
> + *
> + * TODO if we had a way to write and persist variables after the OS
> + * has started, we'd also want to check OsIndications to see if we
> + * should do normal or recovery boot.
> + */
> +
> +
> +/*
> + * See section 3.1.3 in the v2.7 UEFI spec for more details on
> + * the layout of EFI_LOAD_OPTION.  In short it is:
> + *
> + *    typedef struct _EFI_LOAD_OPTION {
> + *        UINT32 Attributes;
> + *        UINT16 FilePathListLength;
> + *        // CHAR16 Description[];   <-- variable length, NULL terminated
> + *        // EFI_DEVICE_PATH_PROTOCOL FilePathList[];  <-- FilePathListLength bytes
> + *        // UINT8 OptionalData[];
> + *    } EFI_LOAD_OPTION;
> + */
> +struct load_option {
> +	u32 attributes;
> +	u16 file_path_length;
> +	u16 *label;
> +	struct efi_device_path *file_path;
> +	u8 *optional_data;
> +};
> +
> +static void parse_load_option(struct load_option *lo, void *ptr)
> +{
> +	lo->attributes = *(u32 *)ptr;
> +	ptr += sizeof(u32);
> +
> +	lo->file_path_length = *(u16 *)ptr;
> +	ptr += sizeof(u16);
> +
> +	lo->label = ptr;
> +	ptr += (utf16_strlen(lo->label) + 1) * 2;
> +
> +	lo->file_path = ptr;
> +	ptr += lo->file_path_length;
> +
> +	lo->optional_data = ptr;
> +}
> +
> +/* free() the result */
> +static void *get_var(u16 *name, const efi_guid_t *vendor,
> +		     unsigned long *size)
> +{
> +	efi_guid_t *v = (efi_guid_t *)vendor;
> +	efi_status_t ret;
> +	void *buf = NULL;
> +
> +	*size = 0;
> +	EFI_CALL(ret = rs->get_variable((s16 *)name, v, NULL, size, buf));
> +	if (ret == EFI_BUFFER_TOO_SMALL) {
> +		buf = malloc(*size);
> +		EFI_CALL(ret = rs->get_variable((s16 *)name, v, NULL, size, buf));
> +	}
> +
> +	if (ret != EFI_SUCCESS) {
> +		free(buf);
> +		*size = 0;
> +		return NULL;
> +	}
> +
> +	return buf;
> +}
> +
> +static void *try_load_entry(uint16_t n, struct efi_device_path **device_path,
> +			    struct efi_device_path **file_path)
> +{
> +	struct load_option lo;
> +	u16 varname[] = L"Boot0000";
> +	u16 hexmap[] = L"0123456789ABCDEF";
> +	void *load_option, *image = NULL;
> +	unsigned long size;
> +
> +	varname[4] = hexmap[(n & 0xf000) >> 12];
> +	varname[5] = hexmap[(n & 0x0f00) >> 8];
> +	varname[6] = hexmap[(n & 0x00f0) >> 4];
> +	varname[7] = hexmap[(n & 0x000f) >> 0];
> +
> +	load_option = get_var(varname, &efi_global_variable_guid, &size);
> +	if (!load_option)
> +		return NULL;
> +
> +	parse_load_option(&lo, load_option);
> +
> +	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);
> +
> +		ret = efi_load_image_from_path(lo.file_path, &image);
> +
> +		if (ret != EFI_SUCCESS)
> +			goto error;
> +
> +		printf("Booting: %ls\n", lo.label);
> +		efi_dp_split_file_path(lo.file_path, device_path, file_path);
> +	}
> +
> +error:
> +	free(load_option);
> +
> +	return image;
> +}
> +
> +void *efi_bootmgr_load(struct efi_device_path **device_path,
> +		       struct efi_device_path **file_path)
> +{
> +	uint16_t *bootorder;
> +	unsigned long size;
> +	void *image = NULL;
> +	int i, num;
> +
> +	__efi_entry_check();
> +
> +	bs = systab.boottime;
> +	rs = systab.runtime;
> +
> +	bootorder = get_var(L"BootOrder", &efi_global_variable_guid, &size);
> +	if (!bootorder)
> +		goto error;
> +
> +	num = size / sizeof(uint16_t);
> +	for (i = 0; i < num; i++) {
> +		debug("%s: trying to load Boot%04X\n", __func__, bootorder[i]);
> +		image = try_load_entry(bootorder[i], device_path, file_path);
> +		if (image)
> +			break;
> +	}
> +
> +	free(bootorder);
> +
> +error:
> +	__efi_exit_check();
> +
> +	return image;
> +}
> diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
> index 19eaea8baf..5ff2d2d4b0 100644
> --- a/lib/efi_loader/efi_boottime.c
> +++ b/lib/efi_loader/efi_boottime.c
> @@ -749,8 +749,8 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob
>  	list_add_tail(&obj->link, &efi_obj_list);
>  }
>  
> -static efi_status_t load_image_from_path(struct efi_device_path *file_path,
> -					 void **buffer)
> +efi_status_t efi_load_image_from_path(struct efi_device_path *file_path,
> +				      void **buffer)
>  {
>  	struct efi_file_info *info = NULL;
>  	struct efi_file_handle *f;
> @@ -808,7 +808,7 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy,
>  		struct efi_device_path *dp, *fp;
>  		efi_status_t ret;
>  
> -		ret = load_image_from_path(file_path, &source_buffer);
> +		ret = efi_load_image_from_path(file_path, &source_buffer);
>  		if (ret != EFI_SUCCESS) {
>  			free(info);
>  			free(obj);
> diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c
> index 469acae082..242e6a504b 100644
> --- a/lib/efi_loader/efi_image_loader.c
> +++ b/lib/efi_loader/efi_image_loader.c
> @@ -15,6 +15,7 @@
>  
>  DECLARE_GLOBAL_DATA_PTR;
>  
> +const efi_guid_t efi_global_variable_guid = EFI_GLOBAL_VARIABLE_GUID;
>  const efi_guid_t efi_guid_device_path = DEVICE_PATH_GUID;
>  const efi_guid_t efi_guid_loaded_image = LOADED_IMAGE_GUID;
>  const efi_guid_t efi_simple_file_system_protocol_guid =
> 

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 20/20] efi_loader: add bootmgr
  2017-08-04 20:06   ` Heinrich Schuchardt
@ 2017-08-04 20:28     ` Rob Clark
  2017-08-04 20:29       ` Rob Clark
  2017-08-04 22:46       ` Peter Jones
  0 siblings, 2 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-04 20:28 UTC (permalink / raw)
  To: u-boot

On Fri, Aug 4, 2017 at 4:06 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
> On 08/04/2017 09:32 PM, Rob Clark wrote:
>> Similar to a "real" UEFI implementation, the bootmgr looks at the
>> BootOrder and BootXXXX variables to try to find an EFI payload to load
>> and boot.  This is added as a sub-command of bootefi.
>>
>> The idea is that the distro bootcmd would first try loading a payload
>> via the bootmgr, and then if that fails (ie. first boot or corrupted
>> EFI variables) it would fallback to loading bootaa64.efi.  (Which
>> would then load fallback.efi which would look for \EFI\*\boot.csv and
>> populate BootOrder and BootXXXX based on what it found.)
>
>
> I wonder if this implementation is Fedora specific.
>
> For Debian I could not find any reference to boot.csv.
> And it is not mentioned in the UEFI 2.7 spec.
>
> Please, provide the specification that your work is based on.

The references to boot.csv are based on looking at how shim/fallback
work.. perhaps that is not standardized.  I'll let Peter Jones comment
on that if he knows better what windows and other linux distro's do.

The bootmanager implementation is based on UEFI spec (sect 3.1 in
v2.7), which does not depend on boot.csv or how shim/fallback program
the BootOrder/BootXXXX variables.  But simply that they do.  I'm not
particularly familiar with the boot chain on Debian, it is entirely
possible that it works differently.  My comments about boot.csv where
merely to try to provide context (and are quite possibly misleading on
some distro's), but are irrelevant to the bootmgr implementation which
only cares about BootOrder/BootXXXX, as described in sect 3.1.

(There are a lot of details that I skipped over in the bootmgr
implementation, simply because secure boot or setting of efi variables
from the OS is not implemented, so they are not yet relevant.)

BR,
-R


> Best regards
>
> Heinrich
>
>
>>
>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>> ---
>>  cmd/bootefi.c                     |  48 ++++++++++-
>>  include/config_distro_bootcmd.h   |   5 ++
>>  include/efi_api.h                 |   4 +
>>  include/efi_loader.h              |   6 ++
>>  lib/efi_loader/Makefile           |   2 +-
>>  lib/efi_loader/efi_bootmgr.c      | 169 ++++++++++++++++++++++++++++++++++++++
>>  lib/efi_loader/efi_boottime.c     |   6 +-
>>  lib/efi_loader/efi_image_loader.c |   1 +
>>  8 files changed, 235 insertions(+), 6 deletions(-)
>>  create mode 100644 lib/efi_loader/efi_bootmgr.c
>>
>> diff --git a/cmd/bootefi.c b/cmd/bootefi.c
>> index 80f52e9e35..02a0dd159b 100644
>> --- a/cmd/bootefi.c
>> +++ b/cmd/bootefi.c
>> @@ -219,6 +219,36 @@ exit:
>>       return ret;
>>  }
>>
>> +static int do_bootefi_bootmgr_exec(unsigned long fdt_addr)
>> +{
>> +     struct efi_device_path *device_path, *file_path;
>> +     void *addr;
>> +     efi_status_t r;
>> +
>> +     /* Initialize and populate EFI object list */
>> +     if (!efi_obj_list_initalized)
>> +             efi_init_obj_list();
>> +
>> +     /*
>> +      * 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
>> +      */
>> +     efi_save_gd();
>> +
>> +     addr = efi_bootmgr_load(&device_path, &file_path);
>> +     if (!addr)
>> +             return 1;
>> +
>> +     printf("## Starting EFI application at %p ...\n", addr);
>> +     r = do_bootefi_exec(addr, (void*)fdt_addr, device_path, file_path);
>> +     printf("## Application terminated, r = %lu\n",
>> +            r & ~EFI_ERROR_MASK);
>> +
>> +     if (r != EFI_SUCCESS)
>> +             return 1;
>> +
>> +     return 0;
>> +}
>>
>>  /* Interpreter command to boot an arbitrary EFI image from memory */
>>  static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
>> @@ -237,7 +267,14 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
>>               memcpy((char *)addr, __efi_hello_world_begin, size);
>>       } else
>>  #endif
>> -     {
>> +     if (!strcmp(argv[1], "bootmgr")) {
>> +             unsigned long fdt_addr = 0;
>> +
>> +             if (argc > 2)
>> +                     fdt_addr = simple_strtoul(argv[2], NULL, 16);
>> +
>> +             return do_bootefi_bootmgr_exec(fdt_addr);
>> +     } else {
>>               saddr = argv[1];
>>
>>               addr = simple_strtoul(saddr, NULL, 16);
>> @@ -270,7 +307,11 @@ static char bootefi_help_text[] =
>>       "hello\n"
>>       "  - boot a sample Hello World application stored within U-Boot"
>>  #endif
>> -     ;
>> +     "bootmgr [fdt addr]\n"
>> +     "  - load and boot EFI payload based on BootOrder/BootXXXX variables.\n"
>> +     "\n"
>> +     "    If specified, the device tree located at <fdt address> gets\n"
>> +     "    exposed as EFI configuration table.\n";
>>  #endif
>>
>>  U_BOOT_CMD(
>> @@ -308,6 +349,9 @@ void efi_set_bootdev(const char *dev, const char *devnr, const char *path)
>>  #endif
>>       }
>>
>> +     if (!path)
>> +             return;
>> +
>>       if (strcmp(dev, "Net")) {
>>               /* Add leading / to fs paths, because they're absolute */
>>               snprintf(filename, sizeof(filename), "/%s", path);
>> diff --git a/include/config_distro_bootcmd.h b/include/config_distro_bootcmd.h
>> index d8dab8e46a..94ccab02d2 100644
>> --- a/include/config_distro_bootcmd.h
>> +++ b/include/config_distro_bootcmd.h
>> @@ -112,6 +112,11 @@
>>
>>  #define BOOTENV_SHARED_EFI                                                \
>>       "boot_efi_binary="                                                \
>> +             "if fdt addr ${fdt_addr_r}; then "                        \
>> +                     "bootefi bootmgr ${fdt_addr_r};"                  \
>> +             "else "                                                   \
>> +                     "bootefi bootmgr ${fdtcontroladdr};"              \
>> +             "fi;"                                                     \
>>               "load ${devtype} ${devnum}:${distro_bootpart} "           \
>>                       "${kernel_addr_r} efi/boot/"BOOTEFI_NAME"; "      \
>>               "if fdt addr ${fdt_addr_r}; then "                        \
>> diff --git a/include/efi_api.h b/include/efi_api.h
>> index 1a542846b3..ef91e34c7b 100644
>> --- a/include/efi_api.h
>> +++ b/include/efi_api.h
>> @@ -211,6 +211,10 @@ struct efi_runtime_services {
>>       EFI_GUID(0x00000000, 0x0000, 0x0000, 0x00, 0x00, \
>>                0x00, 0x00, 0x00, 0x00, 0x00, 0x00)
>>
>> +#define EFI_GLOBAL_VARIABLE_GUID \
>> +     EFI_GUID(0x8be4df61, 0x93ca, 0x11d2, 0xaa, 0x0d, \
>> +              0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c)
>> +
>>  #define LOADED_IMAGE_PROTOCOL_GUID \
>>       EFI_GUID(0x5b1b31a1, 0x9562, 0x11d2, 0x8e, 0x3f, \
>>                0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
>> diff --git a/include/efi_loader.h b/include/efi_loader.h
>> index f14fdfa58e..e3eb932f54 100644
>> --- a/include/efi_loader.h
>> +++ b/include/efi_loader.h
>> @@ -61,6 +61,7 @@ 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_global_variable_guid;
>>  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;
>> @@ -219,6 +220,8 @@ efi_status_t efi_get_protocol(struct efi_object *efiobj,
>>  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);
>> +efi_status_t efi_load_image_from_path(struct efi_device_path *file_path,
>> +                                   void **buffer);
>>
>>  #ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER
>>  extern void *efi_bounce_buffer;
>> @@ -306,6 +309,9 @@ efi_status_t EFIAPI efi_set_variable(s16 *variable_name,
>>               efi_guid_t *vendor, u32 attributes,
>>               unsigned long data_size, void *data);
>>
>> +void *efi_bootmgr_load(struct efi_device_path **device_path,
>> +                    struct efi_device_path **file_path);
>> +
>>  #else /* defined(EFI_LOADER) && !defined(CONFIG_SPL_BUILD) */
>>
>>  /* Without CONFIG_EFI_LOADER we don't have a runtime section, stub it out */
>> diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
>> index f58cb13337..930c0e218e 100644
>> --- a/lib/efi_loader/Makefile
>> +++ b/lib/efi_loader/Makefile
>> @@ -16,7 +16,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 efi_device_path.o
>> -obj-y += efi_file.o efi_variable.o
>> +obj-y += efi_file.o efi_variable.o efi_bootmgr.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_bootmgr.c b/lib/efi_loader/efi_bootmgr.c
>> new file mode 100644
>> index 0000000000..8246ddd48f
>> --- /dev/null
>> +++ b/lib/efi_loader/efi_bootmgr.c
>> @@ -0,0 +1,169 @@
>> +/*
>> + *  EFI utils
>> + *
>> + *  Copyright (c) 2017 Rob Clark
>> + *
>> + *  SPDX-License-Identifier:     GPL-2.0+
>> + */
>> +
>> +#include <common.h>
>> +#include <charset.h>
>> +#include <malloc.h>
>> +#include <efi_loader.h>
>> +
>> +static const struct efi_boot_services *bs;
>> +static const struct efi_runtime_services *rs;
>> +
>> +#define LOAD_OPTION_ACTIVE           0x00000001
>> +#define LOAD_OPTION_FORCE_RECONNECT  0x00000002
>> +#define LOAD_OPTION_HIDDEN           0x00000008
>> +
>> +/*
>> + * bootmgr implements the logic of trying to find a payload to boot
>> + * based on the BootOrder + BootXXXX variables, and then loading it.
>> + *
>> + * TODO detecting a special key held (f9?) and displaying a boot menu
>> + * like you would get on a PC would be clever.
>> + *
>> + * TODO if we had a way to write and persist variables after the OS
>> + * has started, we'd also want to check OsIndications to see if we
>> + * should do normal or recovery boot.
>> + */
>> +
>> +
>> +/*
>> + * See section 3.1.3 in the v2.7 UEFI spec for more details on
>> + * the layout of EFI_LOAD_OPTION.  In short it is:
>> + *
>> + *    typedef struct _EFI_LOAD_OPTION {
>> + *        UINT32 Attributes;
>> + *        UINT16 FilePathListLength;
>> + *        // CHAR16 Description[];   <-- variable length, NULL terminated
>> + *        // EFI_DEVICE_PATH_PROTOCOL FilePathList[];  <-- FilePathListLength bytes
>> + *        // UINT8 OptionalData[];
>> + *    } EFI_LOAD_OPTION;
>> + */
>> +struct load_option {
>> +     u32 attributes;
>> +     u16 file_path_length;
>> +     u16 *label;
>> +     struct efi_device_path *file_path;
>> +     u8 *optional_data;
>> +};
>> +
>> +static void parse_load_option(struct load_option *lo, void *ptr)
>> +{
>> +     lo->attributes = *(u32 *)ptr;
>> +     ptr += sizeof(u32);
>> +
>> +     lo->file_path_length = *(u16 *)ptr;
>> +     ptr += sizeof(u16);
>> +
>> +     lo->label = ptr;
>> +     ptr += (utf16_strlen(lo->label) + 1) * 2;
>> +
>> +     lo->file_path = ptr;
>> +     ptr += lo->file_path_length;
>> +
>> +     lo->optional_data = ptr;
>> +}
>> +
>> +/* free() the result */
>> +static void *get_var(u16 *name, const efi_guid_t *vendor,
>> +                  unsigned long *size)
>> +{
>> +     efi_guid_t *v = (efi_guid_t *)vendor;
>> +     efi_status_t ret;
>> +     void *buf = NULL;
>> +
>> +     *size = 0;
>> +     EFI_CALL(ret = rs->get_variable((s16 *)name, v, NULL, size, buf));
>> +     if (ret == EFI_BUFFER_TOO_SMALL) {
>> +             buf = malloc(*size);
>> +             EFI_CALL(ret = rs->get_variable((s16 *)name, v, NULL, size, buf));
>> +     }
>> +
>> +     if (ret != EFI_SUCCESS) {
>> +             free(buf);
>> +             *size = 0;
>> +             return NULL;
>> +     }
>> +
>> +     return buf;
>> +}
>> +
>> +static void *try_load_entry(uint16_t n, struct efi_device_path **device_path,
>> +                         struct efi_device_path **file_path)
>> +{
>> +     struct load_option lo;
>> +     u16 varname[] = L"Boot0000";
>> +     u16 hexmap[] = L"0123456789ABCDEF";
>> +     void *load_option, *image = NULL;
>> +     unsigned long size;
>> +
>> +     varname[4] = hexmap[(n & 0xf000) >> 12];
>> +     varname[5] = hexmap[(n & 0x0f00) >> 8];
>> +     varname[6] = hexmap[(n & 0x00f0) >> 4];
>> +     varname[7] = hexmap[(n & 0x000f) >> 0];
>> +
>> +     load_option = get_var(varname, &efi_global_variable_guid, &size);
>> +     if (!load_option)
>> +             return NULL;
>> +
>> +     parse_load_option(&lo, load_option);
>> +
>> +     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);
>> +
>> +             ret = efi_load_image_from_path(lo.file_path, &image);
>> +
>> +             if (ret != EFI_SUCCESS)
>> +                     goto error;
>> +
>> +             printf("Booting: %ls\n", lo.label);
>> +             efi_dp_split_file_path(lo.file_path, device_path, file_path);
>> +     }
>> +
>> +error:
>> +     free(load_option);
>> +
>> +     return image;
>> +}
>> +
>> +void *efi_bootmgr_load(struct efi_device_path **device_path,
>> +                    struct efi_device_path **file_path)
>> +{
>> +     uint16_t *bootorder;
>> +     unsigned long size;
>> +     void *image = NULL;
>> +     int i, num;
>> +
>> +     __efi_entry_check();
>> +
>> +     bs = systab.boottime;
>> +     rs = systab.runtime;
>> +
>> +     bootorder = get_var(L"BootOrder", &efi_global_variable_guid, &size);
>> +     if (!bootorder)
>> +             goto error;
>> +
>> +     num = size / sizeof(uint16_t);
>> +     for (i = 0; i < num; i++) {
>> +             debug("%s: trying to load Boot%04X\n", __func__, bootorder[i]);
>> +             image = try_load_entry(bootorder[i], device_path, file_path);
>> +             if (image)
>> +                     break;
>> +     }
>> +
>> +     free(bootorder);
>> +
>> +error:
>> +     __efi_exit_check();
>> +
>> +     return image;
>> +}
>> diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
>> index 19eaea8baf..5ff2d2d4b0 100644
>> --- a/lib/efi_loader/efi_boottime.c
>> +++ b/lib/efi_loader/efi_boottime.c
>> @@ -749,8 +749,8 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob
>>       list_add_tail(&obj->link, &efi_obj_list);
>>  }
>>
>> -static efi_status_t load_image_from_path(struct efi_device_path *file_path,
>> -                                      void **buffer)
>> +efi_status_t efi_load_image_from_path(struct efi_device_path *file_path,
>> +                                   void **buffer)
>>  {
>>       struct efi_file_info *info = NULL;
>>       struct efi_file_handle *f;
>> @@ -808,7 +808,7 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy,
>>               struct efi_device_path *dp, *fp;
>>               efi_status_t ret;
>>
>> -             ret = load_image_from_path(file_path, &source_buffer);
>> +             ret = efi_load_image_from_path(file_path, &source_buffer);
>>               if (ret != EFI_SUCCESS) {
>>                       free(info);
>>                       free(obj);
>> diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c
>> index 469acae082..242e6a504b 100644
>> --- a/lib/efi_loader/efi_image_loader.c
>> +++ b/lib/efi_loader/efi_image_loader.c
>> @@ -15,6 +15,7 @@
>>
>>  DECLARE_GLOBAL_DATA_PTR;
>>
>> +const efi_guid_t efi_global_variable_guid = EFI_GLOBAL_VARIABLE_GUID;
>>  const efi_guid_t efi_guid_device_path = DEVICE_PATH_GUID;
>>  const efi_guid_t efi_guid_loaded_image = LOADED_IMAGE_GUID;
>>  const efi_guid_t efi_simple_file_system_protocol_guid =
>>
>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 03/20] short-wchar
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 03/20] short-wchar Rob Clark
@ 2017-08-04 20:28   ` Heinrich Schuchardt
  2017-08-04 20:36     ` Rob Clark
  0 siblings, 1 reply; 116+ messages in thread
From: Heinrich Schuchardt @ 2017-08-04 20:28 UTC (permalink / raw)
  To: u-boot

On 08/04/2017 09:31 PM, Rob Clark wrote:
> For now, pending conclusion on proposal about using c11 and u"string"
> instead of L"string" plus -fshort-wchar.
> 
> Background: UEFI uses utf16 strings universally.  An UEFI implementation
> that does not use -fshort-wchar has to do a lot of cumbersome charset
> conversion back/forth.  Mixing object files that use -fshort-wchar and
> others that do not is a bad idea (and gcc will warn about it).  There
> are 3 reasonable solutions that I can think of:
> 
>  1) Use -fshort-wchar across the board.  We don't dynamically link
>     against other shared libraries at runtime, so there isn't much
>     downside to this approach.  Heinrich brought up ext4, which uses
>     utf32, but I guess this mostly matters for fs_ls(), and it does
>     not seem so bad for it to do utf32->utf8 conversion.
> 
>  2) Use -fshort-wchar only if CONFIG_EFI_LOADER=y.. UEFI only requires
>     fat/vfat so we don't need ext4 and efi loader at the same time.
> 
>  3) Go with Heinrich's suggestion of requiring c11.  Possibly this
>     requirement could be loosened to only require c11 for efi loader.
>     This seems like the best approach, and at least no one has so
>     far brought up any objection to his proposal.
> 
> Not-signed-off-by: Rob Clark <robdclark@gmail.com>

Do I understand you right?
You do not want the current version of the patch series merged?

It might have been better to replace [PATCH] by [RFC] in the subject
lines of the patch set in this case.

I am currently trying to find out if the switch to C11 is possible, cf.
https://travis-ci.org/xypron2/u-boot/builds/261098363.

Unfortunately Travis uses gcc 4.8.2 for some jobs which does not yet
support C11.

Furthermore there seems to be some problem in disk/part_efi.c with
PARTITION_SYSTEM_GUID.

Best regards

Heinrich

> ---
>  config.mk | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/config.mk b/config.mk
> index b77d58903c..5ad9e7198d 100644
> --- a/config.mk
> +++ b/config.mk
> @@ -74,7 +74,7 @@ endif
>  RELFLAGS := $(PLATFORM_RELFLAGS)
>  
>  PLATFORM_CPPFLAGS += $(RELFLAGS)
> -PLATFORM_CPPFLAGS += -pipe
> +PLATFORM_CPPFLAGS += -pipe -fshort-wchar
>  
>  LDFLAGS += $(PLATFORM_LDFLAGS)
>  LDFLAGS_FINAL += -Bstatic
> 

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 20/20] efi_loader: add bootmgr
  2017-08-04 20:28     ` Rob Clark
@ 2017-08-04 20:29       ` Rob Clark
  2017-08-04 22:46       ` Peter Jones
  1 sibling, 0 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-04 20:29 UTC (permalink / raw)
  To: u-boot

On Fri, Aug 4, 2017 at 4:28 PM, Rob Clark <robdclark@gmail.com> wrote:
> On Fri, Aug 4, 2017 at 4:06 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>> On 08/04/2017 09:32 PM, Rob Clark wrote:
>>> Similar to a "real" UEFI implementation, the bootmgr looks at the
>>> BootOrder and BootXXXX variables to try to find an EFI payload to load
>>> and boot.  This is added as a sub-command of bootefi.
>>>
>>> The idea is that the distro bootcmd would first try loading a payload
>>> via the bootmgr, and then if that fails (ie. first boot or corrupted
>>> EFI variables) it would fallback to loading bootaa64.efi.  (Which
>>> would then load fallback.efi which would look for \EFI\*\boot.csv and
>>> populate BootOrder and BootXXXX based on what it found.)
>>
>>
>> I wonder if this implementation is Fedora specific.
>>
>> For Debian I could not find any reference to boot.csv.
>> And it is not mentioned in the UEFI 2.7 spec.
>>
>> Please, provide the specification that your work is based on.
>
> The references to boot.csv are based on looking at how shim/fallback
> work.. perhaps that is not standardized.  I'll let Peter Jones comment
> on that if he knows better what windows and other linux distro's do.
>
> The bootmanager implementation is based on UEFI spec (sect 3.1 in
> v2.7), which does not depend on boot.csv or how shim/fallback program
> the BootOrder/BootXXXX variables.  But simply that they do.  I'm not
> particularly familiar with the boot chain on Debian, it is entirely
> possible that it works differently.  My comments about boot.csv where
> merely to try to provide context (and are quite possibly misleading on
> some distro's), but are irrelevant to the bootmgr implementation which
> only cares about BootOrder/BootXXXX, as described in sect 3.1.
>
> (There are a lot of details that I skipped over in the bootmgr
> implementation, simply because secure boot or setting of efi variables
> from the OS is not implemented, so they are not yet relevant.)

and in case it wasn't clear, that means the implementation is not
fedora specific, even if my description in the cover letter is.

BR,
-R


> BR,
> -R
>
>
>> Best regards
>>
>> Heinrich
>>
>>
>>>
>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>> ---
>>>  cmd/bootefi.c                     |  48 ++++++++++-
>>>  include/config_distro_bootcmd.h   |   5 ++
>>>  include/efi_api.h                 |   4 +
>>>  include/efi_loader.h              |   6 ++
>>>  lib/efi_loader/Makefile           |   2 +-
>>>  lib/efi_loader/efi_bootmgr.c      | 169 ++++++++++++++++++++++++++++++++++++++
>>>  lib/efi_loader/efi_boottime.c     |   6 +-
>>>  lib/efi_loader/efi_image_loader.c |   1 +
>>>  8 files changed, 235 insertions(+), 6 deletions(-)
>>>  create mode 100644 lib/efi_loader/efi_bootmgr.c
>>>
>>> diff --git a/cmd/bootefi.c b/cmd/bootefi.c
>>> index 80f52e9e35..02a0dd159b 100644
>>> --- a/cmd/bootefi.c
>>> +++ b/cmd/bootefi.c
>>> @@ -219,6 +219,36 @@ exit:
>>>       return ret;
>>>  }
>>>
>>> +static int do_bootefi_bootmgr_exec(unsigned long fdt_addr)
>>> +{
>>> +     struct efi_device_path *device_path, *file_path;
>>> +     void *addr;
>>> +     efi_status_t r;
>>> +
>>> +     /* Initialize and populate EFI object list */
>>> +     if (!efi_obj_list_initalized)
>>> +             efi_init_obj_list();
>>> +
>>> +     /*
>>> +      * 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
>>> +      */
>>> +     efi_save_gd();
>>> +
>>> +     addr = efi_bootmgr_load(&device_path, &file_path);
>>> +     if (!addr)
>>> +             return 1;
>>> +
>>> +     printf("## Starting EFI application at %p ...\n", addr);
>>> +     r = do_bootefi_exec(addr, (void*)fdt_addr, device_path, file_path);
>>> +     printf("## Application terminated, r = %lu\n",
>>> +            r & ~EFI_ERROR_MASK);
>>> +
>>> +     if (r != EFI_SUCCESS)
>>> +             return 1;
>>> +
>>> +     return 0;
>>> +}
>>>
>>>  /* Interpreter command to boot an arbitrary EFI image from memory */
>>>  static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
>>> @@ -237,7 +267,14 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
>>>               memcpy((char *)addr, __efi_hello_world_begin, size);
>>>       } else
>>>  #endif
>>> -     {
>>> +     if (!strcmp(argv[1], "bootmgr")) {
>>> +             unsigned long fdt_addr = 0;
>>> +
>>> +             if (argc > 2)
>>> +                     fdt_addr = simple_strtoul(argv[2], NULL, 16);
>>> +
>>> +             return do_bootefi_bootmgr_exec(fdt_addr);
>>> +     } else {
>>>               saddr = argv[1];
>>>
>>>               addr = simple_strtoul(saddr, NULL, 16);
>>> @@ -270,7 +307,11 @@ static char bootefi_help_text[] =
>>>       "hello\n"
>>>       "  - boot a sample Hello World application stored within U-Boot"
>>>  #endif
>>> -     ;
>>> +     "bootmgr [fdt addr]\n"
>>> +     "  - load and boot EFI payload based on BootOrder/BootXXXX variables.\n"
>>> +     "\n"
>>> +     "    If specified, the device tree located at <fdt address> gets\n"
>>> +     "    exposed as EFI configuration table.\n";
>>>  #endif
>>>
>>>  U_BOOT_CMD(
>>> @@ -308,6 +349,9 @@ void efi_set_bootdev(const char *dev, const char *devnr, const char *path)
>>>  #endif
>>>       }
>>>
>>> +     if (!path)
>>> +             return;
>>> +
>>>       if (strcmp(dev, "Net")) {
>>>               /* Add leading / to fs paths, because they're absolute */
>>>               snprintf(filename, sizeof(filename), "/%s", path);
>>> diff --git a/include/config_distro_bootcmd.h b/include/config_distro_bootcmd.h
>>> index d8dab8e46a..94ccab02d2 100644
>>> --- a/include/config_distro_bootcmd.h
>>> +++ b/include/config_distro_bootcmd.h
>>> @@ -112,6 +112,11 @@
>>>
>>>  #define BOOTENV_SHARED_EFI                                                \
>>>       "boot_efi_binary="                                                \
>>> +             "if fdt addr ${fdt_addr_r}; then "                        \
>>> +                     "bootefi bootmgr ${fdt_addr_r};"                  \
>>> +             "else "                                                   \
>>> +                     "bootefi bootmgr ${fdtcontroladdr};"              \
>>> +             "fi;"                                                     \
>>>               "load ${devtype} ${devnum}:${distro_bootpart} "           \
>>>                       "${kernel_addr_r} efi/boot/"BOOTEFI_NAME"; "      \
>>>               "if fdt addr ${fdt_addr_r}; then "                        \
>>> diff --git a/include/efi_api.h b/include/efi_api.h
>>> index 1a542846b3..ef91e34c7b 100644
>>> --- a/include/efi_api.h
>>> +++ b/include/efi_api.h
>>> @@ -211,6 +211,10 @@ struct efi_runtime_services {
>>>       EFI_GUID(0x00000000, 0x0000, 0x0000, 0x00, 0x00, \
>>>                0x00, 0x00, 0x00, 0x00, 0x00, 0x00)
>>>
>>> +#define EFI_GLOBAL_VARIABLE_GUID \
>>> +     EFI_GUID(0x8be4df61, 0x93ca, 0x11d2, 0xaa, 0x0d, \
>>> +              0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c)
>>> +
>>>  #define LOADED_IMAGE_PROTOCOL_GUID \
>>>       EFI_GUID(0x5b1b31a1, 0x9562, 0x11d2, 0x8e, 0x3f, \
>>>                0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
>>> diff --git a/include/efi_loader.h b/include/efi_loader.h
>>> index f14fdfa58e..e3eb932f54 100644
>>> --- a/include/efi_loader.h
>>> +++ b/include/efi_loader.h
>>> @@ -61,6 +61,7 @@ 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_global_variable_guid;
>>>  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;
>>> @@ -219,6 +220,8 @@ efi_status_t efi_get_protocol(struct efi_object *efiobj,
>>>  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);
>>> +efi_status_t efi_load_image_from_path(struct efi_device_path *file_path,
>>> +                                   void **buffer);
>>>
>>>  #ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER
>>>  extern void *efi_bounce_buffer;
>>> @@ -306,6 +309,9 @@ efi_status_t EFIAPI efi_set_variable(s16 *variable_name,
>>>               efi_guid_t *vendor, u32 attributes,
>>>               unsigned long data_size, void *data);
>>>
>>> +void *efi_bootmgr_load(struct efi_device_path **device_path,
>>> +                    struct efi_device_path **file_path);
>>> +
>>>  #else /* defined(EFI_LOADER) && !defined(CONFIG_SPL_BUILD) */
>>>
>>>  /* Without CONFIG_EFI_LOADER we don't have a runtime section, stub it out */
>>> diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
>>> index f58cb13337..930c0e218e 100644
>>> --- a/lib/efi_loader/Makefile
>>> +++ b/lib/efi_loader/Makefile
>>> @@ -16,7 +16,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 efi_device_path.o
>>> -obj-y += efi_file.o efi_variable.o
>>> +obj-y += efi_file.o efi_variable.o efi_bootmgr.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_bootmgr.c b/lib/efi_loader/efi_bootmgr.c
>>> new file mode 100644
>>> index 0000000000..8246ddd48f
>>> --- /dev/null
>>> +++ b/lib/efi_loader/efi_bootmgr.c
>>> @@ -0,0 +1,169 @@
>>> +/*
>>> + *  EFI utils
>>> + *
>>> + *  Copyright (c) 2017 Rob Clark
>>> + *
>>> + *  SPDX-License-Identifier:     GPL-2.0+
>>> + */
>>> +
>>> +#include <common.h>
>>> +#include <charset.h>
>>> +#include <malloc.h>
>>> +#include <efi_loader.h>
>>> +
>>> +static const struct efi_boot_services *bs;
>>> +static const struct efi_runtime_services *rs;
>>> +
>>> +#define LOAD_OPTION_ACTIVE           0x00000001
>>> +#define LOAD_OPTION_FORCE_RECONNECT  0x00000002
>>> +#define LOAD_OPTION_HIDDEN           0x00000008
>>> +
>>> +/*
>>> + * bootmgr implements the logic of trying to find a payload to boot
>>> + * based on the BootOrder + BootXXXX variables, and then loading it.
>>> + *
>>> + * TODO detecting a special key held (f9?) and displaying a boot menu
>>> + * like you would get on a PC would be clever.
>>> + *
>>> + * TODO if we had a way to write and persist variables after the OS
>>> + * has started, we'd also want to check OsIndications to see if we
>>> + * should do normal or recovery boot.
>>> + */
>>> +
>>> +
>>> +/*
>>> + * See section 3.1.3 in the v2.7 UEFI spec for more details on
>>> + * the layout of EFI_LOAD_OPTION.  In short it is:
>>> + *
>>> + *    typedef struct _EFI_LOAD_OPTION {
>>> + *        UINT32 Attributes;
>>> + *        UINT16 FilePathListLength;
>>> + *        // CHAR16 Description[];   <-- variable length, NULL terminated
>>> + *        // EFI_DEVICE_PATH_PROTOCOL FilePathList[];  <-- FilePathListLength bytes
>>> + *        // UINT8 OptionalData[];
>>> + *    } EFI_LOAD_OPTION;
>>> + */
>>> +struct load_option {
>>> +     u32 attributes;
>>> +     u16 file_path_length;
>>> +     u16 *label;
>>> +     struct efi_device_path *file_path;
>>> +     u8 *optional_data;
>>> +};
>>> +
>>> +static void parse_load_option(struct load_option *lo, void *ptr)
>>> +{
>>> +     lo->attributes = *(u32 *)ptr;
>>> +     ptr += sizeof(u32);
>>> +
>>> +     lo->file_path_length = *(u16 *)ptr;
>>> +     ptr += sizeof(u16);
>>> +
>>> +     lo->label = ptr;
>>> +     ptr += (utf16_strlen(lo->label) + 1) * 2;
>>> +
>>> +     lo->file_path = ptr;
>>> +     ptr += lo->file_path_length;
>>> +
>>> +     lo->optional_data = ptr;
>>> +}
>>> +
>>> +/* free() the result */
>>> +static void *get_var(u16 *name, const efi_guid_t *vendor,
>>> +                  unsigned long *size)
>>> +{
>>> +     efi_guid_t *v = (efi_guid_t *)vendor;
>>> +     efi_status_t ret;
>>> +     void *buf = NULL;
>>> +
>>> +     *size = 0;
>>> +     EFI_CALL(ret = rs->get_variable((s16 *)name, v, NULL, size, buf));
>>> +     if (ret == EFI_BUFFER_TOO_SMALL) {
>>> +             buf = malloc(*size);
>>> +             EFI_CALL(ret = rs->get_variable((s16 *)name, v, NULL, size, buf));
>>> +     }
>>> +
>>> +     if (ret != EFI_SUCCESS) {
>>> +             free(buf);
>>> +             *size = 0;
>>> +             return NULL;
>>> +     }
>>> +
>>> +     return buf;
>>> +}
>>> +
>>> +static void *try_load_entry(uint16_t n, struct efi_device_path **device_path,
>>> +                         struct efi_device_path **file_path)
>>> +{
>>> +     struct load_option lo;
>>> +     u16 varname[] = L"Boot0000";
>>> +     u16 hexmap[] = L"0123456789ABCDEF";
>>> +     void *load_option, *image = NULL;
>>> +     unsigned long size;
>>> +
>>> +     varname[4] = hexmap[(n & 0xf000) >> 12];
>>> +     varname[5] = hexmap[(n & 0x0f00) >> 8];
>>> +     varname[6] = hexmap[(n & 0x00f0) >> 4];
>>> +     varname[7] = hexmap[(n & 0x000f) >> 0];
>>> +
>>> +     load_option = get_var(varname, &efi_global_variable_guid, &size);
>>> +     if (!load_option)
>>> +             return NULL;
>>> +
>>> +     parse_load_option(&lo, load_option);
>>> +
>>> +     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);
>>> +
>>> +             ret = efi_load_image_from_path(lo.file_path, &image);
>>> +
>>> +             if (ret != EFI_SUCCESS)
>>> +                     goto error;
>>> +
>>> +             printf("Booting: %ls\n", lo.label);
>>> +             efi_dp_split_file_path(lo.file_path, device_path, file_path);
>>> +     }
>>> +
>>> +error:
>>> +     free(load_option);
>>> +
>>> +     return image;
>>> +}
>>> +
>>> +void *efi_bootmgr_load(struct efi_device_path **device_path,
>>> +                    struct efi_device_path **file_path)
>>> +{
>>> +     uint16_t *bootorder;
>>> +     unsigned long size;
>>> +     void *image = NULL;
>>> +     int i, num;
>>> +
>>> +     __efi_entry_check();
>>> +
>>> +     bs = systab.boottime;
>>> +     rs = systab.runtime;
>>> +
>>> +     bootorder = get_var(L"BootOrder", &efi_global_variable_guid, &size);
>>> +     if (!bootorder)
>>> +             goto error;
>>> +
>>> +     num = size / sizeof(uint16_t);
>>> +     for (i = 0; i < num; i++) {
>>> +             debug("%s: trying to load Boot%04X\n", __func__, bootorder[i]);
>>> +             image = try_load_entry(bootorder[i], device_path, file_path);
>>> +             if (image)
>>> +                     break;
>>> +     }
>>> +
>>> +     free(bootorder);
>>> +
>>> +error:
>>> +     __efi_exit_check();
>>> +
>>> +     return image;
>>> +}
>>> diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
>>> index 19eaea8baf..5ff2d2d4b0 100644
>>> --- a/lib/efi_loader/efi_boottime.c
>>> +++ b/lib/efi_loader/efi_boottime.c
>>> @@ -749,8 +749,8 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob
>>>       list_add_tail(&obj->link, &efi_obj_list);
>>>  }
>>>
>>> -static efi_status_t load_image_from_path(struct efi_device_path *file_path,
>>> -                                      void **buffer)
>>> +efi_status_t efi_load_image_from_path(struct efi_device_path *file_path,
>>> +                                   void **buffer)
>>>  {
>>>       struct efi_file_info *info = NULL;
>>>       struct efi_file_handle *f;
>>> @@ -808,7 +808,7 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy,
>>>               struct efi_device_path *dp, *fp;
>>>               efi_status_t ret;
>>>
>>> -             ret = load_image_from_path(file_path, &source_buffer);
>>> +             ret = efi_load_image_from_path(file_path, &source_buffer);
>>>               if (ret != EFI_SUCCESS) {
>>>                       free(info);
>>>                       free(obj);
>>> diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c
>>> index 469acae082..242e6a504b 100644
>>> --- a/lib/efi_loader/efi_image_loader.c
>>> +++ b/lib/efi_loader/efi_image_loader.c
>>> @@ -15,6 +15,7 @@
>>>
>>>  DECLARE_GLOBAL_DATA_PTR;
>>>
>>> +const efi_guid_t efi_global_variable_guid = EFI_GLOBAL_VARIABLE_GUID;
>>>  const efi_guid_t efi_guid_device_path = DEVICE_PATH_GUID;
>>>  const efi_guid_t efi_guid_loaded_image = LOADED_IMAGE_GUID;
>>>  const efi_guid_t efi_simple_file_system_protocol_guid =
>>>
>>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 03/20] short-wchar
  2017-08-04 20:28   ` Heinrich Schuchardt
@ 2017-08-04 20:36     ` Rob Clark
  0 siblings, 0 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-04 20:36 UTC (permalink / raw)
  To: u-boot

On Fri, Aug 4, 2017 at 4:28 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
> On 08/04/2017 09:31 PM, Rob Clark wrote:
>> For now, pending conclusion on proposal about using c11 and u"string"
>> instead of L"string" plus -fshort-wchar.
>>
>> Background: UEFI uses utf16 strings universally.  An UEFI implementation
>> that does not use -fshort-wchar has to do a lot of cumbersome charset
>> conversion back/forth.  Mixing object files that use -fshort-wchar and
>> others that do not is a bad idea (and gcc will warn about it).  There
>> are 3 reasonable solutions that I can think of:
>>
>>  1) Use -fshort-wchar across the board.  We don't dynamically link
>>     against other shared libraries at runtime, so there isn't much
>>     downside to this approach.  Heinrich brought up ext4, which uses
>>     utf32, but I guess this mostly matters for fs_ls(), and it does
>>     not seem so bad for it to do utf32->utf8 conversion.
>>
>>  2) Use -fshort-wchar only if CONFIG_EFI_LOADER=y.. UEFI only requires
>>     fat/vfat so we don't need ext4 and efi loader at the same time.
>>
>>  3) Go with Heinrich's suggestion of requiring c11.  Possibly this
>>     requirement could be loosened to only require c11 for efi loader.
>>     This seems like the best approach, and at least no one has so
>>     far brought up any objection to his proposal.
>>
>> Not-signed-off-by: Rob Clark <robdclark@gmail.com>
>
> Do I understand you right?
> You do not want the current version of the patch series merged?

nope, I fully expect review comments and updates, hence calling it
"v0".. I just don't want it to be ignored, as is the tendency for
large RFC's on other lists that I am on.  Hence the
"Not-signed-off-by" ;-)

> It might have been better to replace [PATCH] by [RFC] in the subject
> lines of the patch set in this case.
>
> I am currently trying to find out if the switch to C11 is possible, cf.
> https://travis-ci.org/xypron2/u-boot/builds/261098363.
>
> Unfortunately Travis uses gcc 4.8.2 for some jobs which does not yet
> support C11.
>
> Furthermore there seems to be some problem in disk/part_efi.c with
> PARTITION_SYSTEM_GUID.

hmm, link/pastebin error, and I can have a look?  On my wip branch
that included this patchset, plus other bits needed to make it work on
db410c, I didn't see any such issues, but I might have screwed
something up in splitting up the db410c and related fixes from the
efi_loader patchset.

I do have some regressions on a couple of the vexpress boards, which
are totally unrelated to the patch that introduces the regression and
I cannot reproduce locally (although locally I have newer gcc and
qemu).  See [1] which is introduced by patch 15.  I'm pretty sure this
is a problem with the test environment (either gcc or qemu), but not
quite sure what to do about it.

[1] https://travis-ci.org/robclark/u-boot/jobs/260997492

BR,
-R

> Best regards
>
> Heinrich
>
>> ---
>>  config.mk | 2 +-
>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/config.mk b/config.mk
>> index b77d58903c..5ad9e7198d 100644
>> --- a/config.mk
>> +++ b/config.mk
>> @@ -74,7 +74,7 @@ endif
>>  RELFLAGS := $(PLATFORM_RELFLAGS)
>>
>>  PLATFORM_CPPFLAGS += $(RELFLAGS)
>> -PLATFORM_CPPFLAGS += -pipe
>> +PLATFORM_CPPFLAGS += -pipe -fshort-wchar
>>
>>  LDFLAGS += $(PLATFORM_LDFLAGS)
>>  LDFLAGS_FINAL += -Bstatic
>>
>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions Rob Clark
@ 2017-08-04 20:41   ` Mark Kettenis
  2017-08-04 20:57     ` Rob Clark
  2017-08-07 17:32     ` Peter Jones
  0 siblings, 2 replies; 116+ messages in thread
From: Mark Kettenis @ 2017-08-04 20:41 UTC (permalink / raw)
  To: u-boot

> From: Rob Clark <robdclark@gmail.com>
> Date: Fri,  4 Aug 2017 15:31:55 -0400

Hi Rob,

OpenBSD has been an early adopter of efi_loader and pretty much
completely relies on it for booting OpenBSD/armv7 and OpenBSD/arm64.
We use our own bootloader which is fairly lightweight.  Obviously we'd
like to keep it working if this patchset gets adopted.  We don't make
use of EFI variables and don't really plan to make use of them on our
ARM platforms.  But obviously we have to deal with device paths...

> 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 at 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.

..and what you're sketching out here should work with recent enough
versions of our bootloader.

However, to me having an ACPI Device Path component in there doesn't
make much sense on a board without ACPI.  It certainly doesn't help
mapping a boot path back to an actual hardware device.  Wouldn't it be
more logical to a Hardware Device Path there instead?  In particular a
Memory Mapped Device Path would make a lot of sense as the start
address would make it fairly easy to do the mapping.

Cheers,

Mark

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-04 20:41   ` Mark Kettenis
@ 2017-08-04 20:57     ` Rob Clark
  2017-08-05 14:01       ` Mark Kettenis
  2017-08-07 17:32     ` Peter Jones
  1 sibling, 1 reply; 116+ messages in thread
From: Rob Clark @ 2017-08-04 20:57 UTC (permalink / raw)
  To: u-boot

On Fri, Aug 4, 2017 at 4:41 PM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>> From: Rob Clark <robdclark@gmail.com>
>> Date: Fri,  4 Aug 2017 15:31:55 -0400
>
> Hi Rob,
>
> OpenBSD has been an early adopter of efi_loader and pretty much
> completely relies on it for booting OpenBSD/armv7 and OpenBSD/arm64.
> We use our own bootloader which is fairly lightweight.  Obviously we'd
> like to keep it working if this patchset gets adopted.  We don't make
> use of EFI variables and don't really plan to make use of them on our
> ARM platforms.  But obviously we have to deal with device paths...
>
>> 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 at 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.
>
> ..and what you're sketching out here should work with recent enough
> versions of our bootloader.
>
> However, to me having an ACPI Device Path component in there doesn't
> make much sense on a board without ACPI.  It certainly doesn't help
> mapping a boot path back to an actual hardware device.  Wouldn't it be
> more logical to a Hardware Device Path there instead?  In particular a
> Memory Mapped Device Path would make a lot of sense as the start
> address would make it fairly easy to do the mapping.
>

It was pretty much an arbitrary choice, and it wouldn't be hard to
change.  From my reading of the grub code, all it really cares about
is that there is *some* parent of the "partition" HD device.  I'm not
really sure what maps best in a UEFI world to the "soc" node in a
device tree world.  I'm certainly open to changing this.

It would be cool if you have a chance to give this a try w/ OpenBSD
and let me know if you run into issues.  I want this to be something
that works across-distro so I'll try to help as much as I can.  (Not
sure if there is an OpenBSD port for db410c, but I guess there is
always qemu..).  Fwiw, if git pull/cherry-pick is easier than grabbing
patches from list, then [1].

[1] https://github.com/robclark/u-boot/commits/enough-uefi-for-shim

BR,
-R

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 20/20] efi_loader: add bootmgr
  2017-08-04 20:28     ` Rob Clark
  2017-08-04 20:29       ` Rob Clark
@ 2017-08-04 22:46       ` Peter Jones
  1 sibling, 0 replies; 116+ messages in thread
From: Peter Jones @ 2017-08-04 22:46 UTC (permalink / raw)
  To: u-boot

On Fri, Aug 04, 2017 at 04:28:05PM -0400, Rob Clark wrote:
> On Fri, Aug 4, 2017 at 4:06 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
> > On 08/04/2017 09:32 PM, Rob Clark wrote:
> >> Similar to a "real" UEFI implementation, the bootmgr looks at the
> >> BootOrder and BootXXXX variables to try to find an EFI payload to load
> >> and boot.  This is added as a sub-command of bootefi.
> >>
> >> The idea is that the distro bootcmd would first try loading a payload
> >> via the bootmgr, and then if that fails (ie. first boot or corrupted
> >> EFI variables) it would fallback to loading bootaa64.efi.  (Which
> >> would then load fallback.efi which would look for \EFI\*\boot.csv and
> >> populate BootOrder and BootXXXX based on what it found.)
> >
> >
> > I wonder if this implementation is Fedora specific.
> >
> > For Debian I could not find any reference to boot.csv.
> > And it is not mentioned in the UEFI 2.7 spec.
> >
> > Please, provide the specification that your work is based on.
> 
> The references to boot.csv are based on looking at how shim/fallback
> work.. perhaps that is not standardized.  I'll let Peter Jones comment
> on that if he knows better what windows and other linux distro's do.

The boot.csv parts are part of fallback.efi, which is part of shim.
It's not distro specific, though not every distro uses it (though I
thought debian had started doing so very recently), and fallback.efi +
boot.csv is still strictly optional.  But as Rob says below - the boot
methodology fallback employs is based on what the spec says the boot
manager will do.  A distro could also just stick a second copy of their
normal bootloader in /EFI/BOOT/BOOTAA64.EFI and it would boot through
the recovery path every time until somebody manually created a boot
variable.  fallback is just shim's method of setting the variables
automatically, and it is fairly widely deployed.  I'm pretty sure SuSE
and Ubuntu both use it, for example.

> The bootmanager implementation is based on UEFI spec (sect 3.1 in
> v2.7), which does not depend on boot.csv or how shim/fallback program
> the BootOrder/BootXXXX variables.  But simply that they do.  I'm not
> particularly familiar with the boot chain on Debian, it is entirely
> possible that it works differently.  My comments about boot.csv where
> merely to try to provide context (and are quite possibly misleading on
> some distro's), but are irrelevant to the bootmgr implementation which
> only cares about BootOrder/BootXXXX, as described in sect 3.1.
> 
> (There are a lot of details that I skipped over in the bootmgr
> implementation, simply because secure boot or setting of efi variables
> from the OS is not implemented, so they are not yet relevant.)

This is still all correct.

-- 
  Peter

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-04 20:57     ` Rob Clark
@ 2017-08-05 14:01       ` Mark Kettenis
  2017-08-05 14:19         ` Rob Clark
                           ` (2 more replies)
  0 siblings, 3 replies; 116+ messages in thread
From: Mark Kettenis @ 2017-08-05 14:01 UTC (permalink / raw)
  To: u-boot

> Authentication-Results: xs4all.nl; spf=pass smtp.mailfrom=gmail.com;
> 	dkim=pass header.d=gmail.com; dmarc=pass header.from=gmail.com
> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
>         d=gmail.com; s=20161025;
>         h=mime-version:in-reply-to:references:from:date:message-id:subject:to
>          :cc;
>         bh=qkk49+XF6+Jn7RUjFU/ZFP7/ho5kdUEUNpSrCpqy9yw=;
>         b=knLDTd1vrl7R3BnRReKrxUD1UxYSIahqh5VTND3PEt1cLHtskGRiDc280ADRTm6ffV
>          izImBjr6hq94Qu/Jnbd6kn7+jSDuhDva9FU1/ZndFaNkTUhsatlgtvrK5RzJ38FpwvLa
>          0X7Y8NuVm99K+ijWdKI34YruaZfz47t863L40UYJhjdaj3/TLdIWrC/NzEBiQ/fXemHU
>          8mN1HM9JBD7STB64mMlDSttSTC2vJOPyX81CCbDnXLI/puqcyXewaJ+kW8Km+VDra2xs
>          PIWVzyA0PoV7nIihMbkrv95K7GQgpSOUUL7nlEmAreQoEbCCb8Iw2inSe6LqhN6IbJ4u
>          Js9A==
> X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
>         d=1e100.net; s=20161025;
>         h=x-gm-message-state:mime-version:in-reply-to:references:from:date
>          :message-id:subject:to:cc;
>         bh=qkk49+XF6+Jn7RUjFU/ZFP7/ho5kdUEUNpSrCpqy9yw=;
>         b=kiBq9lLF93IqOIhjRAbghuqi5rcOJ7mf7OvAvgo8T4qg72k9iEBX84R7yIY7KVyDpX
>          DxV+JJDPePbOtIN3qxpmIZF6vqT/HJ0w+z8RnsUiUGJxGCxTA9R97e+tcB1Ovh7zRIJe
>          JPSP/6/TqRmFgrlIsZdoPZAsypVgTx/AHfdMA/z3l4EOOdSOcd3AOd+sDdGnhCAm2G0+
>          QyAXxkxleKeB3t2AvXKiXpJknXzSb9FxM+0ug0gAPlTTT7d2JFEOZ43gzgLCTTsCVDdL
>          lWiJepjIeynmIuGKwcZJpFdV6C8nx2RMztWLpbhPMrbbR+eLkQcaJnJJrgv859lzbUrM
>          9XhQ==
> X-Gm-Message-State: AHYfb5hmb8q9IgSaZxMt3OsQOUjxd0l+fyjrLiox4JEB/7NaaHlf1K9h
> 	HiWJc8WMqU156stR2hj9qS4oZRxkCuHp0xg=
> X-Received: by 10.25.59.29 with SMTP id i29mr1058615lfa.224.1501880271850;
>  Fri, 04 Aug 2017 13:57:51 -0700 (PDT)
> From: Rob Clark <robdclark@gmail.com>
> Date: Fri, 4 Aug 2017 16:57:50 -0400
> Cc: U-Boot Mailing List <u-boot@lists.denx.de>,
>         Heinrich Schuchardt <xypron.glpk@gmx.de>,
>         Peter Jones <pjones@redhat.com>
> X-CNFS-Analysis: v=2.2 cv=eoad9chX c=1 sm=0 tr=0
> 	a=bdpqe3ZLSLbgpdprsY8WZA==:117 a=IkcTkHD0fZMA:10 a=x7bEGLp0ZPQA:10
> 	a=D2htVsi0J-IA:10 a=KeKAF7QvOSUA:10 a=pGLkceISAAAA:8 a=NEAV23lmAAAA:8
> 	a=YyEjxAJ5dRpCWmjka9UA:9 a=QEXdDO2ut3YA:10 a=6kGIvZw6iX1k4Y-7sg4_:22
> X-Virus-Scanned: by XS4ALL Virus Scanner
> X-XS4ALL-Spam-Score: -0.1 () DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU,
> 	FREEMAIL_FROM, SPF_PASS
> X-XS4ALL-Spam: NO
> Envelope-To: mark.kettenis at xs4all.nl
> 
> On Fri, Aug 4, 2017 at 4:41 PM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
> >> From: Rob Clark <robdclark@gmail.com>
> >> Date: Fri,  4 Aug 2017 15:31:55 -0400
> >
> > Hi Rob,
> >
> > OpenBSD has been an early adopter of efi_loader and pretty much
> > completely relies on it for booting OpenBSD/armv7 and OpenBSD/arm64.
> > We use our own bootloader which is fairly lightweight.  Obviously we'd
> > like to keep it working if this patchset gets adopted.  We don't make
> > use of EFI variables and don't really plan to make use of them on our
> > ARM platforms.  But obviously we have to deal with device paths...
> >
> >> 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 at 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.
> >
> > ..and what you're sketching out here should work with recent enough
> > versions of our bootloader.
> >
> > However, to me having an ACPI Device Path component in there doesn't
> > make much sense on a board without ACPI.  It certainly doesn't help
> > mapping a boot path back to an actual hardware device.  Wouldn't it be
> > more logical to a Hardware Device Path there instead?  In particular a
> > Memory Mapped Device Path would make a lot of sense as the start
> > address would make it fairly easy to do the mapping.
> >
> 
> It was pretty much an arbitrary choice, and it wouldn't be hard to
> change.  From my reading of the grub code, all it really cares about
> is that there is *some* parent of the "partition" HD device.  I'm not
> really sure what maps best in a UEFI world to the "soc" node in a
> device tree world.  I'm certainly open to changing this.
> 
> It would be cool if you have a chance to give this a try w/ OpenBSD
> and let me know if you run into issues.  I want this to be something
> that works across-distro so I'll try to help as much as I can.  (Not
> sure if there is an OpenBSD port for db410c, but I guess there is
> always qemu..).  Fwiw, if git pull/cherry-pick is easier than grabbing
> patches from list, then [1].

OpenBSD doesn't run on the db410c.  However, our EFI bootloader should
just run.  You can download it from:

  http://ftp.openbsd.org/pub/OpenBSD/snapshots/arm64/BOOTAA64.EFI

for the 64-bit (AArch64) and

  http://ftp.openbsd.org/pub/OpenBSD/snapshots/armv7/BOOTARM.EFI

for the 32-bit version (AArch32).

Unfortunately something in this patch series breaks things for me on a
Banana Pi:

U-Boot SPL 2017.09-rc1-00020-g2ad6933c64-dirty (Aug 05 2017 - 15:26:15)
DRAM: 1024 MiB
CPU: 912000000Hz, AXI/AHB/APB: 3/2/2
Trying to boot from MMC1

                                
U-Boot 2017.09-rc1-00020-g2ad6933c64-dirty (Aug 05 2017 - 15:26:15 +0200) Allwinner Technology

CPU:   Allwinner A20 (SUN7I)
Model: LeMaker Banana Pi
I2C:   ready
DRAM:  1 GiB
MMC:   SUNXI SD/MMC: 0
*** Warning - bad CRC, using default environment

Setting up a 720x576i composite-pal console (overscan 32x20)
In:    serial
Out:   vga
Err:   vga
SCSI:  Target spinup took 0 ms.
AHCI 0001.0100 32 slots 1 ports 3 Gbps 0x1 impl SATA mode
flags: ncq stag pm led clo only pmp pio slum part ccc apst
Net:   eth0: ethernet at 01c50000
starting USB...
USB0:   USB EHCI 1.00
USB1:   USB OHCI 1.0
USB2:   USB EHCI 1.00
USB3:   USB OHCI 1.0
scanning bus 0 for devices... 1 USB Device(s) found
scanning bus 2 for devices... 1 USB Device(s) found
       scanning usb for storage devices... 0 Storage Device(s) found
Hit any key to stop autoboot:  0
switch to partitions #0, OK
mmc0 is current device
Scanning mmc 0:1...
Found EFI removable media binary efi/boot/bootarm.efi
Scanning disks on scsi...
Scanning disks on usb...
Scanning disks on mmc...
MMC Device 1 not found
MMC Device 2 not found
MMC Device 3 not found
Found 6 disks
data abort
pc : [<7ef8d878>]          lr : [<7ef8d874>]
reloc pc : [<4a039878>]    lr : [<4a039874>]
sp : 7af29660  ip : 00000000     fp : 7af29774
r10: 7efec230  r9 : 7af33ee0     r8 : 00000000
r7 : 00000009  r6 : 7ef9e8b8     r5 : 7af296a0  r4 : 7efa4495
r3 : 7af296a0  r2 : 0000008c     r1 : 7af29658  r0 : 00000004
Flags: nzCV  IRQs off  FIQs off  Mode SVC_32
Resetting CPU ...                        

resetting ...

Normally it would print something like:

  >> OpenBSD/armv7 BOOTARM 0.8
  boot>

at that stage.

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-05 14:01       ` Mark Kettenis
@ 2017-08-05 14:19         ` Rob Clark
  2017-08-05 14:28         ` Mark Kettenis
  2017-08-05 14:28         ` Rob Clark
  2 siblings, 0 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-05 14:19 UTC (permalink / raw)
  To: u-boot

On Sat, Aug 5, 2017 at 10:01 AM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>>
>> On Fri, Aug 4, 2017 at 4:41 PM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>> >> From: Rob Clark <robdclark@gmail.com>
>> >> Date: Fri,  4 Aug 2017 15:31:55 -0400
>> >
>> > Hi Rob,
>> >
>> > OpenBSD has been an early adopter of efi_loader and pretty much
>> > completely relies on it for booting OpenBSD/armv7 and OpenBSD/arm64.
>> > We use our own bootloader which is fairly lightweight.  Obviously we'd
>> > like to keep it working if this patchset gets adopted.  We don't make
>> > use of EFI variables and don't really plan to make use of them on our
>> > ARM platforms.  But obviously we have to deal with device paths...
>> >
>> >> 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 at 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.
>> >
>> > ..and what you're sketching out here should work with recent enough
>> > versions of our bootloader.
>> >
>> > However, to me having an ACPI Device Path component in there doesn't
>> > make much sense on a board without ACPI.  It certainly doesn't help
>> > mapping a boot path back to an actual hardware device.  Wouldn't it be
>> > more logical to a Hardware Device Path there instead?  In particular a
>> > Memory Mapped Device Path would make a lot of sense as the start
>> > address would make it fairly easy to do the mapping.
>> >
>>
>> It was pretty much an arbitrary choice, and it wouldn't be hard to
>> change.  From my reading of the grub code, all it really cares about
>> is that there is *some* parent of the "partition" HD device.  I'm not
>> really sure what maps best in a UEFI world to the "soc" node in a
>> device tree world.  I'm certainly open to changing this.
>>
>> It would be cool if you have a chance to give this a try w/ OpenBSD
>> and let me know if you run into issues.  I want this to be something
>> that works across-distro so I'll try to help as much as I can.  (Not
>> sure if there is an OpenBSD port for db410c, but I guess there is
>> always qemu..).  Fwiw, if git pull/cherry-pick is easier than grabbing
>> patches from list, then [1].
>
> OpenBSD doesn't run on the db410c.  However, our EFI bootloader should
> just run.  You can download it from:
>
>   http://ftp.openbsd.org/pub/OpenBSD/snapshots/arm64/BOOTAA64.EFI
>
> for the 64-bit (AArch64) and
>
>   http://ftp.openbsd.org/pub/OpenBSD/snapshots/armv7/BOOTARM.EFI
>
> for the 32-bit version (AArch32).

oh, good point..  I can try that

> Unfortunately something in this patch series breaks things for me on a
> Banana Pi:
>
> U-Boot SPL 2017.09-rc1-00020-g2ad6933c64-dirty (Aug 05 2017 - 15:26:15)
> DRAM: 1024 MiB
> CPU: 912000000Hz, AXI/AHB/APB: 3/2/2
> Trying to boot from MMC1
>
>
> U-Boot 2017.09-rc1-00020-g2ad6933c64-dirty (Aug 05 2017 - 15:26:15 +0200) Allwinner Technology
>
> CPU:   Allwinner A20 (SUN7I)
> Model: LeMaker Banana Pi
> I2C:   ready
> DRAM:  1 GiB
> MMC:   SUNXI SD/MMC: 0
> *** Warning - bad CRC, using default environment
>
> Setting up a 720x576i composite-pal console (overscan 32x20)
> In:    serial
> Out:   vga
> Err:   vga
> SCSI:  Target spinup took 0 ms.
> AHCI 0001.0100 32 slots 1 ports 3 Gbps 0x1 impl SATA mode
> flags: ncq stag pm led clo only pmp pio slum part ccc apst
> Net:   eth0: ethernet at 01c50000
> starting USB...
> USB0:   USB EHCI 1.00
> USB1:   USB OHCI 1.0
> USB2:   USB EHCI 1.00
> USB3:   USB OHCI 1.0
> scanning bus 0 for devices... 1 USB Device(s) found
> scanning bus 2 for devices... 1 USB Device(s) found
>        scanning usb for storage devices... 0 Storage Device(s) found
> Hit any key to stop autoboot:  0
> switch to partitions #0, OK
> mmc0 is current device
> Scanning mmc 0:1...
> Found EFI removable media binary efi/boot/bootarm.efi
> Scanning disks on scsi...
> Scanning disks on usb...
> Scanning disks on mmc...
> MMC Device 1 not found
> MMC Device 2 not found
> MMC Device 3 not found
> Found 6 disks
> data abort
> pc : [<7ef8d878>]          lr : [<7ef8d874>]
> reloc pc : [<4a039878>]    lr : [<4a039874>]
> sp : 7af29660  ip : 00000000     fp : 7af29774
> r10: 7efec230  r9 : 7af33ee0     r8 : 00000000
> r7 : 00000009  r6 : 7ef9e8b8     r5 : 7af296a0  r4 : 7efa4495
> r3 : 7af296a0  r2 : 0000008c     r1 : 7af29658  r0 : 00000004
> Flags: nzCV  IRQs off  FIQs off  Mode SVC_32
> Resetting CPU ...
>
> resetting ...
>
> Normally it would print something like:
>
>   >> OpenBSD/armv7 BOOTARM 0.8
>   boot>
>
> at that stage.

hmm, well I'll give a quick try w/ your bootaa64.efi, but I guess this
is probably something board specific.

Could you:

  $(CROSS_COMPILE)-addr2line -e u-boot 7ef8d878

while you still have the build handy?

BR,
-R

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-05 14:01       ` Mark Kettenis
  2017-08-05 14:19         ` Rob Clark
@ 2017-08-05 14:28         ` Mark Kettenis
  2017-08-05 14:35           ` Rob Clark
  2017-08-05 14:28         ` Rob Clark
  2 siblings, 1 reply; 116+ messages in thread
From: Mark Kettenis @ 2017-08-05 14:28 UTC (permalink / raw)
  To: u-boot

> Date: Sat, 5 Aug 2017 16:01:51 +0200 (CEST)
> From: Mark Kettenis <mark.kettenis@xs4all.nl>
> 
> Unfortunately something in this patch series breaks things for me on a
> Banana Pi:

And according to git bisect:

4e3e748a50fc3f43e20c7ff407184596d7c9a589 is the first bad commit
commit 4e3e748a50fc3f43e20c7ff407184596d7c9a589
Author: Peter Jones <pjones@redhat.com>
Date:   Wed Jun 21 16:39:02 2017 -0400

    efi: add some more device path structures
    
    Signed-off-by: Peter Jones <pjones@redhat.com>
    Signed-off-by: Rob Clark <robdclark@gmail.com>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-05 14:01       ` Mark Kettenis
  2017-08-05 14:19         ` Rob Clark
  2017-08-05 14:28         ` Mark Kettenis
@ 2017-08-05 14:28         ` Rob Clark
  2017-08-06 12:53           ` Mark Kettenis
  2 siblings, 1 reply; 116+ messages in thread
From: Rob Clark @ 2017-08-05 14:28 UTC (permalink / raw)
  To: u-boot

On Sat, Aug 5, 2017 at 10:01 AM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>
> OpenBSD doesn't run on the db410c.  However, our EFI bootloader should
> just run.  You can download it from:
>
>   http://ftp.openbsd.org/pub/OpenBSD/snapshots/arm64/BOOTAA64.EFI
>
> for the 64-bit (AArch64) and
>
>   http://ftp.openbsd.org/pub/OpenBSD/snapshots/armv7/BOOTARM.EFI
>
> for the 32-bit version (AArch32).
>

Yup, this appears to work, I think this is about what you'd expect
without having an openbsd fs:

dragonboard410c => load mmc 0:1 ${kernel_addr_r} efi/openbsd/bootaa64.efi
reading efi/openbsd/bootaa64.efi
75732 bytes read in 35 ms (2.1 MiB/s)
dragonboard410c => bootefi ${kernel_addr_r} ${fdt_addr_r}
## Starting EFI application at 81000000 ...
Scanning disk sdhci at 07864000.blk...
Found 1 disks
WARNING: Invalid device tree, expect boot to fail
>> OpenBSD/arm64 BOOTAA64 0.6
sd0: getdisklabel: no disk label
open(sd0a:/etc/boot.conf): bad partition
boot>
sd0: getdisklabel: no disk label
cannot open sd0a:/etc/random.seed: bad partition
booting sd0a:/bsd: sd0: getdisklabel: no disk label
open sd0a:/bsd: bad partition
 failed(95). will try /bsd
boot>
sd0: getdisklabel: no disk label
cannot open sd0a:/etc/random.seed: bad partition
booting sd0a:/bsd: sd0: getdisklabel: no disk label
open sd0a:/bsd: bad partition
 failed(95). will try /bsd
Turning timeout off.
boot>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-05 14:28         ` Mark Kettenis
@ 2017-08-05 14:35           ` Rob Clark
  2017-08-05 15:08             ` Mark Kettenis
  2017-08-05 15:10             ` Heinrich Schuchardt
  0 siblings, 2 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-05 14:35 UTC (permalink / raw)
  To: u-boot

On Sat, Aug 5, 2017 at 10:28 AM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>> Date: Sat, 5 Aug 2017 16:01:51 +0200 (CEST)
>> From: Mark Kettenis <mark.kettenis@xs4all.nl>
>>
>> Unfortunately something in this patch series breaks things for me on a
>> Banana Pi:
>
> And according to git bisect:
>
> 4e3e748a50fc3f43e20c7ff407184596d7c9a589 is the first bad commit
> commit 4e3e748a50fc3f43e20c7ff407184596d7c9a589
> Author: Peter Jones <pjones@redhat.com>
> Date:   Wed Jun 21 16:39:02 2017 -0400
>
>     efi: add some more device path structures
>
>     Signed-off-by: Peter Jones <pjones@redhat.com>
>     Signed-off-by: Rob Clark <robdclark@gmail.com>


hmm, odd.. it is only adding some #define's and structs that are not
used until a later commit..

although it does also make 'struct efi_device_path_mac_addr' __packed,
which it should have been before.  Is this an armv7?  I wonder if we
have some troubles with unaligned accesses on armv7 that we don't have
on aarch64 (or maybe compiler isn't turning access to device-path
nodes into byte accesses if it can't do unaligned accesses.  (The node
in the device-path structure are byte-packed.)

addr2line the faulting address I guess should confirm that.  If this
is the issue, it's going to be a bit sad since we'll have to do a lot
of copying back/forth of efi_device_path ptrs to aligned addresses :-/

BR,
-R

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-05 14:35           ` Rob Clark
@ 2017-08-05 15:08             ` Mark Kettenis
  2017-08-05 15:22               ` Rob Clark
  2017-08-05 15:10             ` Heinrich Schuchardt
  1 sibling, 1 reply; 116+ messages in thread
From: Mark Kettenis @ 2017-08-05 15:08 UTC (permalink / raw)
  To: u-boot

> From: Rob Clark <robdclark@gmail.com>
> Date: Sat, 5 Aug 2017 10:35:08 -0400
> 
> On Sat, Aug 5, 2017 at 10:28 AM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
> >> Date: Sat, 5 Aug 2017 16:01:51 +0200 (CEST)
> >> From: Mark Kettenis <mark.kettenis@xs4all.nl>
> >>
> >> Unfortunately something in this patch series breaks things for me on a
> >> Banana Pi:
> >
> > And according to git bisect:
> >
> > 4e3e748a50fc3f43e20c7ff407184596d7c9a589 is the first bad commit
> > commit 4e3e748a50fc3f43e20c7ff407184596d7c9a589
> > Author: Peter Jones <pjones@redhat.com>
> > Date:   Wed Jun 21 16:39:02 2017 -0400
> >
> >     efi: add some more device path structures
> >
> >     Signed-off-by: Peter Jones <pjones@redhat.com>
> >     Signed-off-by: Rob Clark <robdclark@gmail.com>
> 
> 
> hmm, odd.. it is only adding some #define's and structs that are not
> used until a later commit..
> 
> although it does also make 'struct efi_device_path_mac_addr' __packed,
> which it should have been before.  Is this an armv7?  I wonder if we
> have some troubles with unaligned accesses on armv7 that we don't have
> on aarch64 (or maybe compiler isn't turning access to device-path
> nodes into byte accesses if it can't do unaligned accesses.  (The node
> in the device-path structure are byte-packed.)

This is indeed armv7.

> addr2line the faulting address I guess should confirm that.  If this
> is the issue, it's going to be a bit sad since we'll have to do a lot
> of copying back/forth of efi_device_path ptrs to aligned addresses :-/

Sadly that's not going to help you:

  $ arm-none-eabi-addr2line -e u-boot 7ef8d878
  ??:0

I suppose it is faulting somewhere in BOOTARM.EFI, 

Anyway, removing __packed from struct efi_device_path_file_path makes
me boot again with a tree checked out out with that commit.

Our bootloader code doesn't explicitly enable alignment faults.  But
of course the UEFI standard says that for AArc32 platforms:

 * Unaligned access should be enabled if supported; Alignment faults
    are enabled otherwise.

So the efi_loader code has to align things properly I fear.

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-05 14:35           ` Rob Clark
  2017-08-05 15:08             ` Mark Kettenis
@ 2017-08-05 15:10             ` Heinrich Schuchardt
  2017-08-05 15:24               ` Rob Clark
  1 sibling, 1 reply; 116+ messages in thread
From: Heinrich Schuchardt @ 2017-08-05 15:10 UTC (permalink / raw)
  To: u-boot

On 08/05/2017 04:35 PM, Rob Clark wrote:
> On Sat, Aug 5, 2017 at 10:28 AM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>>> Date: Sat, 5 Aug 2017 16:01:51 +0200 (CEST)
>>> From: Mark Kettenis <mark.kettenis@xs4all.nl>
>>>
>>> Unfortunately something in this patch series breaks things for me on a
>>> Banana Pi:
>>
>> And according to git bisect:
>>
>> 4e3e748a50fc3f43e20c7ff407184596d7c9a589 is the first bad commit
>> commit 4e3e748a50fc3f43e20c7ff407184596d7c9a589
>> Author: Peter Jones <pjones@redhat.com>
>> Date:   Wed Jun 21 16:39:02 2017 -0400
>>
>>     efi: add some more device path structures
>>
>>     Signed-off-by: Peter Jones <pjones@redhat.com>
>>     Signed-off-by: Rob Clark <robdclark@gmail.com>
> 
> 
> hmm, odd.. it is only adding some #define's and structs that are not
> used until a later commit..
> 
> although it does also make 'struct efi_device_path_mac_addr' __packed,
> which it should have been before.  Is this an armv7?  I wonder if we
> have some troubles with unaligned accesses on armv7 that we don't have
> on aarch64 (or maybe compiler isn't turning access to device-path
> nodes into byte accesses if it can't do unaligned accesses.  (The node
> in the device-path structure are byte-packed.)

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka15414.html

<cite>On older processors, such as ARM9 family based processors, an
unaligned load had to be synthesised in software.  Typically by doing a
series of small accesses, and combining the results. ... Unaligned
access support must be enabled by setting the SCTLR.A bit in the system
control coprocessor</cite>

Generally packing structures is not a good idea performance-wise. The
sequence of fields should be carefully chosen to fill up to powers of
two (2, 4 , 8).

Regards

Heinrich

> 
> addr2line the faulting address I guess should confirm that.  If this
> is the issue, it's going to be a bit sad since we'll have to do a lot
> of copying back/forth of efi_device_path ptrs to aligned addresses :-/
> 
> BR,
> -R
> 

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-05 15:08             ` Mark Kettenis
@ 2017-08-05 15:22               ` Rob Clark
  2017-08-05 16:02                 ` Heinrich Schuchardt
  0 siblings, 1 reply; 116+ messages in thread
From: Rob Clark @ 2017-08-05 15:22 UTC (permalink / raw)
  To: u-boot

On Sat, Aug 5, 2017 at 11:08 AM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>> From: Rob Clark <robdclark@gmail.com>
>> Date: Sat, 5 Aug 2017 10:35:08 -0400
>>
>> On Sat, Aug 5, 2017 at 10:28 AM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>> >> Date: Sat, 5 Aug 2017 16:01:51 +0200 (CEST)
>> >> From: Mark Kettenis <mark.kettenis@xs4all.nl>
>> >>
>> >> Unfortunately something in this patch series breaks things for me on a
>> >> Banana Pi:
>> >
>> > And according to git bisect:
>> >
>> > 4e3e748a50fc3f43e20c7ff407184596d7c9a589 is the first bad commit
>> > commit 4e3e748a50fc3f43e20c7ff407184596d7c9a589
>> > Author: Peter Jones <pjones@redhat.com>
>> > Date:   Wed Jun 21 16:39:02 2017 -0400
>> >
>> >     efi: add some more device path structures
>> >
>> >     Signed-off-by: Peter Jones <pjones@redhat.com>
>> >     Signed-off-by: Rob Clark <robdclark@gmail.com>
>>
>>
>> hmm, odd.. it is only adding some #define's and structs that are not
>> used until a later commit..
>>
>> although it does also make 'struct efi_device_path_mac_addr' __packed,
>> which it should have been before.  Is this an armv7?  I wonder if we
>> have some troubles with unaligned accesses on armv7 that we don't have
>> on aarch64 (or maybe compiler isn't turning access to device-path
>> nodes into byte accesses if it can't do unaligned accesses.  (The node
>> in the device-path structure are byte-packed.)
>
> This is indeed armv7.
>
>> addr2line the faulting address I guess should confirm that.  If this
>> is the issue, it's going to be a bit sad since we'll have to do a lot
>> of copying back/forth of efi_device_path ptrs to aligned addresses :-/
>
> Sadly that's not going to help you:
>
>   $ arm-none-eabi-addr2line -e u-boot 7ef8d878
>   ??:0
>
> I suppose it is faulting somewhere in BOOTARM.EFI,
>
> Anyway, removing __packed from struct efi_device_path_file_path makes
> me boot again with a tree checked out out with that commit.
>
> Our bootloader code doesn't explicitly enable alignment faults.  But
> of course the UEFI standard says that for AArc32 platforms:
>
>  * Unaligned access should be enabled if supported; Alignment faults
>     are enabled otherwise.
>
> So the efi_loader code has to align things properly I fear.

Ok, so I have an idea for a reasonably (imho) sane way forward:

  struct efi_device_path_mac_addr {
      struct efi_device_path dp;
      struct efi_mac_addr mac;
      u8 if_type;
  #ifdef BROKEN_UNALIGNED
      u8 pad[3];
  #endif
  } __packed;

We'll just define BROKEN_UNALIGNED for armv7 and any other arch's that
can't handle unaligned accesses.  Technically it is a bit outside the
way things are *supposed* to work according to my understanding of the
UEFI spec.  But all the code I've seen that parses the device-paths
honors the length field in the efi_device_path header to find the
start of the next node in the path.  I can't guarantee that you'll be
able to boot windows from u-boot (but I guess that isn't what most
people care about ;-)), but it at least won't be more broken than it
was before on these archs.

It will take a bit of extra special handling for
efi_device_path_file_path (which is variable length) but with my
patchset that only gets constructed in one place, so it isn't so bad.

BR,
-R

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-05 15:10             ` Heinrich Schuchardt
@ 2017-08-05 15:24               ` Rob Clark
  2017-08-05 15:36                 ` Rob Clark
  0 siblings, 1 reply; 116+ messages in thread
From: Rob Clark @ 2017-08-05 15:24 UTC (permalink / raw)
  To: u-boot

On Sat, Aug 5, 2017 at 11:10 AM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
> On 08/05/2017 04:35 PM, Rob Clark wrote:
>> On Sat, Aug 5, 2017 at 10:28 AM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>>>> Date: Sat, 5 Aug 2017 16:01:51 +0200 (CEST)
>>>> From: Mark Kettenis <mark.kettenis@xs4all.nl>
>>>>
>>>> Unfortunately something in this patch series breaks things for me on a
>>>> Banana Pi:
>>>
>>> And according to git bisect:
>>>
>>> 4e3e748a50fc3f43e20c7ff407184596d7c9a589 is the first bad commit
>>> commit 4e3e748a50fc3f43e20c7ff407184596d7c9a589
>>> Author: Peter Jones <pjones@redhat.com>
>>> Date:   Wed Jun 21 16:39:02 2017 -0400
>>>
>>>     efi: add some more device path structures
>>>
>>>     Signed-off-by: Peter Jones <pjones@redhat.com>
>>>     Signed-off-by: Rob Clark <robdclark@gmail.com>
>>
>>
>> hmm, odd.. it is only adding some #define's and structs that are not
>> used until a later commit..
>>
>> although it does also make 'struct efi_device_path_mac_addr' __packed,
>> which it should have been before.  Is this an armv7?  I wonder if we
>> have some troubles with unaligned accesses on armv7 that we don't have
>> on aarch64 (or maybe compiler isn't turning access to device-path
>> nodes into byte accesses if it can't do unaligned accesses.  (The node
>> in the device-path structure are byte-packed.)
>
> http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka15414.html
>
> <cite>On older processors, such as ARM9 family based processors, an
> unaligned load had to be synthesised in software.  Typically by doing a
> series of small accesses, and combining the results. ... Unaligned
> access support must be enabled by setting the SCTLR.A bit in the system
> control coprocessor</cite>
>
> Generally packing structures is not a good idea performance-wise. The
> sequence of fields should be carefully chosen to fill up to powers of
> two (2, 4 , 8).

Yeah, it was clearly a dumb idea for UEFI to not make device-path
nodes word aligned.  But when implementing a standard, we don't have a
choice but to implement it properly, warts and all :-/

BR,
-R


> Regards
>
> Heinrich
>
>>
>> addr2line the faulting address I guess should confirm that.  If this
>> is the issue, it's going to be a bit sad since we'll have to do a lot
>> of copying back/forth of efi_device_path ptrs to aligned addresses :-/
>>
>> BR,
>> -R
>>
>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-05 15:24               ` Rob Clark
@ 2017-08-05 15:36                 ` Rob Clark
  2017-08-06 13:16                   ` Mark Kettenis
  0 siblings, 1 reply; 116+ messages in thread
From: Rob Clark @ 2017-08-05 15:36 UTC (permalink / raw)
  To: u-boot

On Sat, Aug 5, 2017 at 11:24 AM, Rob Clark <robdclark@gmail.com> wrote:
> On Sat, Aug 5, 2017 at 11:10 AM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>> On 08/05/2017 04:35 PM, Rob Clark wrote:
>>> On Sat, Aug 5, 2017 at 10:28 AM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>>>>> Date: Sat, 5 Aug 2017 16:01:51 +0200 (CEST)
>>>>> From: Mark Kettenis <mark.kettenis@xs4all.nl>
>>>>>
>>>>> Unfortunately something in this patch series breaks things for me on a
>>>>> Banana Pi:
>>>>
>>>> And according to git bisect:
>>>>
>>>> 4e3e748a50fc3f43e20c7ff407184596d7c9a589 is the first bad commit
>>>> commit 4e3e748a50fc3f43e20c7ff407184596d7c9a589
>>>> Author: Peter Jones <pjones@redhat.com>
>>>> Date:   Wed Jun 21 16:39:02 2017 -0400
>>>>
>>>>     efi: add some more device path structures
>>>>
>>>>     Signed-off-by: Peter Jones <pjones@redhat.com>
>>>>     Signed-off-by: Rob Clark <robdclark@gmail.com>
>>>
>>>
>>> hmm, odd.. it is only adding some #define's and structs that are not
>>> used until a later commit..
>>>
>>> although it does also make 'struct efi_device_path_mac_addr' __packed,
>>> which it should have been before.  Is this an armv7?  I wonder if we
>>> have some troubles with unaligned accesses on armv7 that we don't have
>>> on aarch64 (or maybe compiler isn't turning access to device-path
>>> nodes into byte accesses if it can't do unaligned accesses.  (The node
>>> in the device-path structure are byte-packed.)
>>
>> http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka15414.html
>>
>> <cite>On older processors, such as ARM9 family based processors, an
>> unaligned load had to be synthesised in software.  Typically by doing a
>> series of small accesses, and combining the results. ... Unaligned
>> access support must be enabled by setting the SCTLR.A bit in the system
>> control coprocessor</cite>
>>
>> Generally packing structures is not a good idea performance-wise. The
>> sequence of fields should be carefully chosen to fill up to powers of
>> two (2, 4 , 8).
>
> Yeah, it was clearly a dumb idea for UEFI to not make device-path
> nodes word aligned.  But when implementing a standard, we don't have a
> choice but to implement it properly, warts and all :-/
>

btw, just for reference (if anyone is curious), see sect 10.3.1 in
UEFI spec v2.7.  If you don't want to bother looking it up, here is
the exact wording:

   A Device Path is a series of generic Device Path nodes. The first
   Device Path node starts at byte offset zero of the Device Path.
   The next Device Path node starts at the end of the previous Device
   Path node. Therefore all nodes are byte-packed data structures that
   may appear on any byte boundary. All code references to device path
   notes must assume all fields are unaligned. Since every Device Path
   node contains a length field in a known place, it is possible to
   traverse Device Path nodes that are of an unknown type. There is
   no limit to the number, type, or sequence of nodes in a Device Path.

So clearly what we were doing before was incorrect.. but cheating w/
extra padding bytes on arch's that cannot handle unaligned accesses
will avoid having to go fix grub, bootaa64/shim/fallback (and anything
else that uses gnu-efi), and apparently openbsd's bootaa64.efi.  It is
kinda weird to be using efi on these arch's in the first place, so I
guess I don't feel as badly about the padding bytes hack on those
arch's.  (But we should not use the hack on aarch64.)

BR,
-R

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
  2017-08-04 19:31 [U-Boot] [PATCH v0 00/20] enough UEFI for standard distro boot Rob Clark
                   ` (19 preceding siblings ...)
  2017-08-04 19:32 ` [U-Boot] [PATCH v0 20/20] efi_loader: add bootmgr Rob Clark
@ 2017-08-05 15:58 ` Rob Clark
  2017-08-05 16:12   ` Heinrich Schuchardt
  2017-08-10  1:32 ` [U-Boot] [PATCH v0 00/20] enough UEFI for standard distro boot Tom Rini
  21 siblings, 1 reply; 116+ messages in thread
From: Rob Clark @ 2017-08-05 15:58 UTC (permalink / raw)
  To: u-boot

Some arch's have trouble with unaligned accesses.  Technically
EFI device-path structs should be byte aligned, and the next node
in the path starts immediately after the previous.  Meaning that
a pointer to an 'struct efi_device_path' is not necessarily word
aligned.  See section 10.3.1 in v2.7 of UEFI spec.

This causes problems not just for u-boot, but also most/all EFI
payloads loaded by u-boot on these archs.  Fortunately the common
practice for traversing a device path is to rely on the length
field in the header, rather than the specified length of the
particular device path type+subtype.  So the EFI_DP_PAD() macro
will add the specified number of bytes to the tail of device path
structs to pad them to word alignment.

Technically this is non-compliant, BROKEN_UNALIGNED should *only*
be defined on archs that cannot do unaligned accesses.

Signed-off-by: Rob Clark <robdclark@gmail.com>
---
I'm not sure if there are other arch's that need -DBROKEN_UNALIGNED

Mark, this is untested but I think it should solve your crash on the
Banana Pi.  Could you give it a try when you get a chance?

 arch/arm/config.mk               |  2 +-
 include/efi_api.h                | 30 ++++++++++++++++++++++++++++++
 lib/efi_loader/efi_device_path.c |  3 +++
 3 files changed, 34 insertions(+), 1 deletion(-)

diff --git a/arch/arm/config.mk b/arch/arm/config.mk
index 1a77779db4..067dc93a9d 100644
--- a/arch/arm/config.mk
+++ b/arch/arm/config.mk
@@ -28,7 +28,7 @@ LLVMS_RELFLAGS		:= $(call cc-option,-mllvm,) \
 			$(call cc-option,-arm-use-movt=0,)
 PLATFORM_RELFLAGS	+= $(LLVM_RELFLAGS)
 
-PLATFORM_CPPFLAGS += -D__ARM__
+PLATFORM_CPPFLAGS += -D__ARM__ -DBROKEN_UNALIGNED
 
 ifdef CONFIG_ARM64
 PLATFORM_ELFFLAGS += -B aarch64 -O elf64-littleaarch64
diff --git a/include/efi_api.h b/include/efi_api.h
index ef91e34c7b..ddd1e6100a 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -284,6 +284,31 @@ struct efi_loaded_image {
 #define DEVICE_PATH_TYPE_END			0x7f
 #  define DEVICE_PATH_SUB_TYPE_END		0xff
 
+/*
+ * Some arch's have trouble with unaligned accesses.  Technically
+ * EFI device-path structs should be byte aligned, and the next node
+ * in the path starts immediately after the previous.  Meaning that
+ * a pointer to an 'struct efi_device_path' is not necessarily word
+ * aligned.  See section 10.3.1 in v2.7 of UEFI spec.
+ *
+ * This causes problems not just for u-boot, but also most/all EFI
+ * payloads loaded by u-boot on these archs.  Fortunately the common
+ * practice for traversing a device path is to rely on the length
+ * field in the header, rather than the specified length of the
+ * particular device path type+subtype.  So the EFI_DP_PAD() macro
+ * will add the specified number of bytes to the tail of device path
+ * structs to pad them to word alignment.
+ *
+ * Technically this is non-compliant, BROKEN_UNALIGNED should *only*
+ * be defined on archs that cannot do unaligned accesses.
+ */
+
+#ifdef BROKEN_UNALIGNED
+#  define EFI_DP_PAD(n)  u8 __pad[n]
+#else
+#  define EFI_DP_PAD(n)
+#endif
+
 struct efi_device_path {
 	u8 type;
 	u8 sub_type;
@@ -318,12 +343,14 @@ struct efi_device_path_usb {
 	struct efi_device_path dp;
 	u8 parent_port_number;
 	u8 usb_interface;
+	EFI_DP_PAD(2);
 } __packed;
 
 struct efi_device_path_mac_addr {
 	struct efi_device_path dp;
 	struct efi_mac_addr mac;
 	u8 if_type;
+	EFI_DP_PAD(3);
 } __packed;
 
 struct efi_device_path_usb_class {
@@ -333,11 +360,13 @@ struct efi_device_path_usb_class {
 	u8 device_class;
 	u8 device_subclass;
 	u8 device_protocol;
+	EFI_DP_PAD(1);
 } __packed;
 
 struct efi_device_path_sd_mmc_path {
 	struct efi_device_path dp;
 	u8 slot_number;
+	EFI_DP_PAD(3);
 } __packed;
 
 #define DEVICE_PATH_TYPE_MEDIA_DEVICE		0x04
@@ -353,6 +382,7 @@ struct efi_device_path_hard_drive_path {
 	u8 partition_signature[16];
 	u8 partmap_type;
 	u8 signature_type;
+	EFI_DP_PAD(1);
 } __packed;
 
 struct efi_device_path_cdrom_path {
diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
index b5acf73f98..515a1f4737 100644
--- a/lib/efi_loader/efi_device_path.c
+++ b/lib/efi_loader/efi_device_path.c
@@ -402,6 +402,9 @@ struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part,
 
 	// TODO efi_device_path_file_path should be variable length:
 	fpsize = sizeof(struct efi_device_path) + 2 * (strlen(path) + 1);
+#ifdef BROKEN_UNALIGNED
+	fpsize = ALIGN(fpsize, 4);
+#endif
 	dpsize += fpsize;
 
 	start = buf = calloc(1, dpsize + sizeof(END));
-- 
2.13.0

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-05 15:22               ` Rob Clark
@ 2017-08-05 16:02                 ` Heinrich Schuchardt
  2017-08-05 16:13                   ` Rob Clark
  0 siblings, 1 reply; 116+ messages in thread
From: Heinrich Schuchardt @ 2017-08-05 16:02 UTC (permalink / raw)
  To: u-boot

On 08/05/2017 05:22 PM, Rob Clark wrote:
> On Sat, Aug 5, 2017 at 11:08 AM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>>> From: Rob Clark <robdclark@gmail.com>
>>> Date: Sat, 5 Aug 2017 10:35:08 -0400
>>>
>>> On Sat, Aug 5, 2017 at 10:28 AM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>>>>> Date: Sat, 5 Aug 2017 16:01:51 +0200 (CEST)
>>>>> From: Mark Kettenis <mark.kettenis@xs4all.nl>
>>>>>
>>>>> Unfortunately something in this patch series breaks things for me on a
>>>>> Banana Pi:
>>>>
>>>> And according to git bisect:
>>>>
>>>> 4e3e748a50fc3f43e20c7ff407184596d7c9a589 is the first bad commit
>>>> commit 4e3e748a50fc3f43e20c7ff407184596d7c9a589
>>>> Author: Peter Jones <pjones@redhat.com>
>>>> Date:   Wed Jun 21 16:39:02 2017 -0400
>>>>
>>>>     efi: add some more device path structures
>>>>
>>>>     Signed-off-by: Peter Jones <pjones@redhat.com>
>>>>     Signed-off-by: Rob Clark <robdclark@gmail.com>
>>>
>>>
>>> hmm, odd.. it is only adding some #define's and structs that are not
>>> used until a later commit..
>>>
>>> although it does also make 'struct efi_device_path_mac_addr' __packed,
>>> which it should have been before.  Is this an armv7?  I wonder if we
>>> have some troubles with unaligned accesses on armv7 that we don't have
>>> on aarch64 (or maybe compiler isn't turning access to device-path
>>> nodes into byte accesses if it can't do unaligned accesses.  (The node
>>> in the device-path structure are byte-packed.)
>>
>> This is indeed armv7.
>>
>>> addr2line the faulting address I guess should confirm that.  If this
>>> is the issue, it's going to be a bit sad since we'll have to do a lot
>>> of copying back/forth of efi_device_path ptrs to aligned addresses :-/
>>
>> Sadly that's not going to help you:
>>
>>   $ arm-none-eabi-addr2line -e u-boot 7ef8d878
>>   ??:0
>>
>> I suppose it is faulting somewhere in BOOTARM.EFI,
>>
>> Anyway, removing __packed from struct efi_device_path_file_path makes
>> me boot again with a tree checked out out with that commit.
>>
>> Our bootloader code doesn't explicitly enable alignment faults.  But
>> of course the UEFI standard says that for AArc32 platforms:
>>
>>  * Unaligned access should be enabled if supported; Alignment faults
>>     are enabled otherwise.
>>
>> So the efi_loader code has to align things properly I fear.
> 
> Ok, so I have an idea for a reasonably (imho) sane way forward:
> 
>   struct efi_device_path_mac_addr {
>       struct efi_device_path dp;
>       struct efi_mac_addr mac;
>       u8 if_type;
>   #ifdef BROKEN_UNALIGNED
>       u8 pad[3];
>   #endif
>   } __packed;

Why do you need _packed here?

These are the current definitions (before your patches):

struct efi_device_path {
        u8 type;
        u8 sub_type;
        u16 length;
};

struct efi_mac_addr {
        u8 addr[32];
};

struct efi_device_path_mac_addr {
        struct efi_device_path dp;
        struct efi_mac_addr mac;
        u8 if_type;
};

Everything is perfectly aligned to natural bounderies.
The only thing that does not conform to the UEFI standard is the length
of efi_mac_addr, which should be 6 for if_type in {0, 1}.

If you want to copy the data to or from unaligned addresses use memcpy.

Best regards

Heinrich

> 
> We'll just define BROKEN_UNALIGNED for armv7 and any other arch's that
> can't handle unaligned accesses.  Technically it is a bit outside the
> way things are *supposed* to work according to my understanding of the
> UEFI spec.  But all the code I've seen that parses the device-paths
> honors the length field in the efi_device_path header to find the
> start of the next node in the path.  I can't guarantee that you'll be
> able to boot windows from u-boot (but I guess that isn't what most
> people care about ;-)), but it at least won't be more broken than it
> was before on these archs.
> 
> It will take a bit of extra special handling for
> efi_device_path_file_path (which is variable length) but with my
> patchset that only gets constructed in one place, so it isn't so bad.
> 
> BR,
> -R
> 

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
  2017-08-05 15:58 ` [U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses Rob Clark
@ 2017-08-05 16:12   ` Heinrich Schuchardt
  2017-08-05 16:16     ` Rob Clark
  0 siblings, 1 reply; 116+ messages in thread
From: Heinrich Schuchardt @ 2017-08-05 16:12 UTC (permalink / raw)
  To: u-boot

On 08/05/2017 05:58 PM, Rob Clark wrote:
> Some arch's have trouble with unaligned accesses.  Technically
> EFI device-path structs should be byte aligned, and the next node
> in the path starts immediately after the previous.  Meaning that
> a pointer to an 'struct efi_device_path' is not necessarily word
> aligned.  See section 10.3.1 in v2.7 of UEFI spec.
> 
> This causes problems not just for u-boot, but also most/all EFI
> payloads loaded by u-boot on these archs.  Fortunately the common
> practice for traversing a device path is to rely on the length
> field in the header, rather than the specified length of the
> particular device path type+subtype.  So the EFI_DP_PAD() macro
> will add the specified number of bytes to the tail of device path
> structs to pad them to word alignment.
> 
> Technically this is non-compliant, BROKEN_UNALIGNED should *only*
> be defined on archs that cannot do unaligned accesses.
> 
> Signed-off-by: Rob Clark <robdclark@gmail.com>
> ---
> I'm not sure if there are other arch's that need -DBROKEN_UNALIGNED
> 
> Mark, this is untested but I think it should solve your crash on the
> Banana Pi.  Could you give it a try when you get a chance?
> 
>  arch/arm/config.mk               |  2 +-
>  include/efi_api.h                | 30 ++++++++++++++++++++++++++++++
>  lib/efi_loader/efi_device_path.c |  3 +++
>  3 files changed, 34 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm/config.mk b/arch/arm/config.mk
> index 1a77779db4..067dc93a9d 100644
> --- a/arch/arm/config.mk
> +++ b/arch/arm/config.mk
> @@ -28,7 +28,7 @@ LLVMS_RELFLAGS		:= $(call cc-option,-mllvm,) \
>  			$(call cc-option,-arm-use-movt=0,)
>  PLATFORM_RELFLAGS	+= $(LLVM_RELFLAGS)
>  
> -PLATFORM_CPPFLAGS += -D__ARM__
> +PLATFORM_CPPFLAGS += -D__ARM__ -DBROKEN_UNALIGNED

NAK

We have more then ARM. And other architectures also create exceptions
for unaligned access.

I hate platform specific code. It should not be used outside /arch.

To play it save you should not use _packed at all!
Use memcpy to transfer between aligned and unaligned memory.

Best regards

Heinrich

>  
>  ifdef CONFIG_ARM64
>  PLATFORM_ELFFLAGS += -B aarch64 -O elf64-littleaarch64
> diff --git a/include/efi_api.h b/include/efi_api.h
> index ef91e34c7b..ddd1e6100a 100644
> --- a/include/efi_api.h
> +++ b/include/efi_api.h
> @@ -284,6 +284,31 @@ struct efi_loaded_image {
>  #define DEVICE_PATH_TYPE_END			0x7f
>  #  define DEVICE_PATH_SUB_TYPE_END		0xff
>  
> +/*
> + * Some arch's have trouble with unaligned accesses.  Technically
> + * EFI device-path structs should be byte aligned, and the next node
> + * in the path starts immediately after the previous.  Meaning that
> + * a pointer to an 'struct efi_device_path' is not necessarily word
> + * aligned.  See section 10.3.1 in v2.7 of UEFI spec.
> + *
> + * This causes problems not just for u-boot, but also most/all EFI
> + * payloads loaded by u-boot on these archs.  Fortunately the common
> + * practice for traversing a device path is to rely on the length
> + * field in the header, rather than the specified length of the
> + * particular device path type+subtype.  So the EFI_DP_PAD() macro
> + * will add the specified number of bytes to the tail of device path
> + * structs to pad them to word alignment.
> + *
> + * Technically this is non-compliant, BROKEN_UNALIGNED should *only*
> + * be defined on archs that cannot do unaligned accesses.
> + */
> +
> +#ifdef BROKEN_UNALIGNED
> +#  define EFI_DP_PAD(n)  u8 __pad[n]
> +#else
> +#  define EFI_DP_PAD(n)
> +#endif
> +
>  struct efi_device_path {
>  	u8 type;
>  	u8 sub_type;
> @@ -318,12 +343,14 @@ struct efi_device_path_usb {
>  	struct efi_device_path dp;
>  	u8 parent_port_number;
>  	u8 usb_interface;
> +	EFI_DP_PAD(2);
>  } __packed;
>  
>  struct efi_device_path_mac_addr {
>  	struct efi_device_path dp;
>  	struct efi_mac_addr mac;
>  	u8 if_type;
> +	EFI_DP_PAD(3);
>  } __packed;
>  
>  struct efi_device_path_usb_class {
> @@ -333,11 +360,13 @@ struct efi_device_path_usb_class {
>  	u8 device_class;
>  	u8 device_subclass;
>  	u8 device_protocol;
> +	EFI_DP_PAD(1);
>  } __packed;
>  
>  struct efi_device_path_sd_mmc_path {
>  	struct efi_device_path dp;
>  	u8 slot_number;
> +	EFI_DP_PAD(3);
>  } __packed;
>  
>  #define DEVICE_PATH_TYPE_MEDIA_DEVICE		0x04
> @@ -353,6 +382,7 @@ struct efi_device_path_hard_drive_path {
>  	u8 partition_signature[16];
>  	u8 partmap_type;
>  	u8 signature_type;
> +	EFI_DP_PAD(1);
>  } __packed;
>  
>  struct efi_device_path_cdrom_path {
> diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
> index b5acf73f98..515a1f4737 100644
> --- a/lib/efi_loader/efi_device_path.c
> +++ b/lib/efi_loader/efi_device_path.c
> @@ -402,6 +402,9 @@ struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part,
>  
>  	// TODO efi_device_path_file_path should be variable length:
>  	fpsize = sizeof(struct efi_device_path) + 2 * (strlen(path) + 1);
> +#ifdef BROKEN_UNALIGNED
> +	fpsize = ALIGN(fpsize, 4);
> +#endif
>  	dpsize += fpsize;
>  
>  	start = buf = calloc(1, dpsize + sizeof(END));
> 

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-05 16:02                 ` Heinrich Schuchardt
@ 2017-08-05 16:13                   ` Rob Clark
  0 siblings, 0 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-05 16:13 UTC (permalink / raw)
  To: u-boot

On Sat, Aug 5, 2017 at 12:02 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
> On 08/05/2017 05:22 PM, Rob Clark wrote:
>> On Sat, Aug 5, 2017 at 11:08 AM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>>>> From: Rob Clark <robdclark@gmail.com>
>>>> Date: Sat, 5 Aug 2017 10:35:08 -0400
>>>>
>>>> On Sat, Aug 5, 2017 at 10:28 AM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>>>>>> Date: Sat, 5 Aug 2017 16:01:51 +0200 (CEST)
>>>>>> From: Mark Kettenis <mark.kettenis@xs4all.nl>
>>>>>>
>>>>>> Unfortunately something in this patch series breaks things for me on a
>>>>>> Banana Pi:
>>>>>
>>>>> And according to git bisect:
>>>>>
>>>>> 4e3e748a50fc3f43e20c7ff407184596d7c9a589 is the first bad commit
>>>>> commit 4e3e748a50fc3f43e20c7ff407184596d7c9a589
>>>>> Author: Peter Jones <pjones@redhat.com>
>>>>> Date:   Wed Jun 21 16:39:02 2017 -0400
>>>>>
>>>>>     efi: add some more device path structures
>>>>>
>>>>>     Signed-off-by: Peter Jones <pjones@redhat.com>
>>>>>     Signed-off-by: Rob Clark <robdclark@gmail.com>
>>>>
>>>>
>>>> hmm, odd.. it is only adding some #define's and structs that are not
>>>> used until a later commit..
>>>>
>>>> although it does also make 'struct efi_device_path_mac_addr' __packed,
>>>> which it should have been before.  Is this an armv7?  I wonder if we
>>>> have some troubles with unaligned accesses on armv7 that we don't have
>>>> on aarch64 (or maybe compiler isn't turning access to device-path
>>>> nodes into byte accesses if it can't do unaligned accesses.  (The node
>>>> in the device-path structure are byte-packed.)
>>>
>>> This is indeed armv7.
>>>
>>>> addr2line the faulting address I guess should confirm that.  If this
>>>> is the issue, it's going to be a bit sad since we'll have to do a lot
>>>> of copying back/forth of efi_device_path ptrs to aligned addresses :-/
>>>
>>> Sadly that's not going to help you:
>>>
>>>   $ arm-none-eabi-addr2line -e u-boot 7ef8d878
>>>   ??:0
>>>
>>> I suppose it is faulting somewhere in BOOTARM.EFI,
>>>
>>> Anyway, removing __packed from struct efi_device_path_file_path makes
>>> me boot again with a tree checked out out with that commit.
>>>
>>> Our bootloader code doesn't explicitly enable alignment faults.  But
>>> of course the UEFI standard says that for AArc32 platforms:
>>>
>>>  * Unaligned access should be enabled if supported; Alignment faults
>>>     are enabled otherwise.
>>>
>>> So the efi_loader code has to align things properly I fear.
>>
>> Ok, so I have an idea for a reasonably (imho) sane way forward:
>>
>>   struct efi_device_path_mac_addr {
>>       struct efi_device_path dp;
>>       struct efi_mac_addr mac;
>>       u8 if_type;
>>   #ifdef BROKEN_UNALIGNED
>>       u8 pad[3];
>>   #endif
>>   } __packed;
>
> Why do you need _packed here?

We probably crossed threads, but see the other email I sent that
quoted the relevant part from the UEFI spec.

> These are the current definitions (before your patches):
>
> struct efi_device_path {
>         u8 type;
>         u8 sub_type;
>         u16 length;
> };
>
> struct efi_mac_addr {
>         u8 addr[32];
> };
>
> struct efi_device_path_mac_addr {
>         struct efi_device_path dp;
>         struct efi_mac_addr mac;
>         u8 if_type;
> };
>
> Everything is perfectly aligned to natural bounderies.
> The only thing that does not conform to the UEFI standard is the length
> of efi_mac_addr, which should be 6 for if_type in {0, 1}.

Actually, the mac is fixed size and zero padded, see 10.3.5.11.  The
only thing incorrect here was the missing __packed.

> If you want to copy the data to or from unaligned addresses use memcpy.

The problem isn't *just* u-boot.  We could do that, but it would be
annoying and make the code much more convoluted.  But that doesn't
solve the problem for grub/shim/fallback/etc.

BR,
-R

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
  2017-08-05 16:12   ` Heinrich Schuchardt
@ 2017-08-05 16:16     ` Rob Clark
  2017-08-05 16:19       ` Rob Clark
  2017-08-05 16:52       ` Heinrich Schuchardt
  0 siblings, 2 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-05 16:16 UTC (permalink / raw)
  To: u-boot

On Sat, Aug 5, 2017 at 12:12 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
> On 08/05/2017 05:58 PM, Rob Clark wrote:
>> Some arch's have trouble with unaligned accesses.  Technically
>> EFI device-path structs should be byte aligned, and the next node
>> in the path starts immediately after the previous.  Meaning that
>> a pointer to an 'struct efi_device_path' is not necessarily word
>> aligned.  See section 10.3.1 in v2.7 of UEFI spec.
>>
>> This causes problems not just for u-boot, but also most/all EFI
>> payloads loaded by u-boot on these archs.  Fortunately the common
>> practice for traversing a device path is to rely on the length
>> field in the header, rather than the specified length of the
>> particular device path type+subtype.  So the EFI_DP_PAD() macro
>> will add the specified number of bytes to the tail of device path
>> structs to pad them to word alignment.
>>
>> Technically this is non-compliant, BROKEN_UNALIGNED should *only*
>> be defined on archs that cannot do unaligned accesses.
>>
>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>> ---
>> I'm not sure if there are other arch's that need -DBROKEN_UNALIGNED
>>
>> Mark, this is untested but I think it should solve your crash on the
>> Banana Pi.  Could you give it a try when you get a chance?
>>
>>  arch/arm/config.mk               |  2 +-
>>  include/efi_api.h                | 30 ++++++++++++++++++++++++++++++
>>  lib/efi_loader/efi_device_path.c |  3 +++
>>  3 files changed, 34 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/arm/config.mk b/arch/arm/config.mk
>> index 1a77779db4..067dc93a9d 100644
>> --- a/arch/arm/config.mk
>> +++ b/arch/arm/config.mk
>> @@ -28,7 +28,7 @@ LLVMS_RELFLAGS              := $(call cc-option,-mllvm,) \
>>                       $(call cc-option,-arm-use-movt=0,)
>>  PLATFORM_RELFLAGS    += $(LLVM_RELFLAGS)
>>
>> -PLATFORM_CPPFLAGS += -D__ARM__
>> +PLATFORM_CPPFLAGS += -D__ARM__ -DBROKEN_UNALIGNED
>
> NAK
>
> We have more then ARM. And other architectures also create exceptions
> for unaligned access.
>
> I hate platform specific code. It should not be used outside /arch.
>
> To play it save you should not use _packed at all!
> Use memcpy to transfer between aligned and unaligned memory.

except for reasons I explained in the thread on the patch that added
the __packed in the first place.  Sorry, this is ugly but we have to
do it.

BR,
-R


> Best regards
>
> Heinrich
>
>>
>>  ifdef CONFIG_ARM64
>>  PLATFORM_ELFFLAGS += -B aarch64 -O elf64-littleaarch64
>> diff --git a/include/efi_api.h b/include/efi_api.h
>> index ef91e34c7b..ddd1e6100a 100644
>> --- a/include/efi_api.h
>> +++ b/include/efi_api.h
>> @@ -284,6 +284,31 @@ struct efi_loaded_image {
>>  #define DEVICE_PATH_TYPE_END                 0x7f
>>  #  define DEVICE_PATH_SUB_TYPE_END           0xff
>>
>> +/*
>> + * Some arch's have trouble with unaligned accesses.  Technically
>> + * EFI device-path structs should be byte aligned, and the next node
>> + * in the path starts immediately after the previous.  Meaning that
>> + * a pointer to an 'struct efi_device_path' is not necessarily word
>> + * aligned.  See section 10.3.1 in v2.7 of UEFI spec.
>> + *
>> + * This causes problems not just for u-boot, but also most/all EFI
>> + * payloads loaded by u-boot on these archs.  Fortunately the common
>> + * practice for traversing a device path is to rely on the length
>> + * field in the header, rather than the specified length of the
>> + * particular device path type+subtype.  So the EFI_DP_PAD() macro
>> + * will add the specified number of bytes to the tail of device path
>> + * structs to pad them to word alignment.
>> + *
>> + * Technically this is non-compliant, BROKEN_UNALIGNED should *only*
>> + * be defined on archs that cannot do unaligned accesses.
>> + */
>> +
>> +#ifdef BROKEN_UNALIGNED
>> +#  define EFI_DP_PAD(n)  u8 __pad[n]
>> +#else
>> +#  define EFI_DP_PAD(n)
>> +#endif
>> +
>>  struct efi_device_path {
>>       u8 type;
>>       u8 sub_type;
>> @@ -318,12 +343,14 @@ struct efi_device_path_usb {
>>       struct efi_device_path dp;
>>       u8 parent_port_number;
>>       u8 usb_interface;
>> +     EFI_DP_PAD(2);
>>  } __packed;
>>
>>  struct efi_device_path_mac_addr {
>>       struct efi_device_path dp;
>>       struct efi_mac_addr mac;
>>       u8 if_type;
>> +     EFI_DP_PAD(3);
>>  } __packed;
>>
>>  struct efi_device_path_usb_class {
>> @@ -333,11 +360,13 @@ struct efi_device_path_usb_class {
>>       u8 device_class;
>>       u8 device_subclass;
>>       u8 device_protocol;
>> +     EFI_DP_PAD(1);
>>  } __packed;
>>
>>  struct efi_device_path_sd_mmc_path {
>>       struct efi_device_path dp;
>>       u8 slot_number;
>> +     EFI_DP_PAD(3);
>>  } __packed;
>>
>>  #define DEVICE_PATH_TYPE_MEDIA_DEVICE                0x04
>> @@ -353,6 +382,7 @@ struct efi_device_path_hard_drive_path {
>>       u8 partition_signature[16];
>>       u8 partmap_type;
>>       u8 signature_type;
>> +     EFI_DP_PAD(1);
>>  } __packed;
>>
>>  struct efi_device_path_cdrom_path {
>> diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
>> index b5acf73f98..515a1f4737 100644
>> --- a/lib/efi_loader/efi_device_path.c
>> +++ b/lib/efi_loader/efi_device_path.c
>> @@ -402,6 +402,9 @@ struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part,
>>
>>       // TODO efi_device_path_file_path should be variable length:
>>       fpsize = sizeof(struct efi_device_path) + 2 * (strlen(path) + 1);
>> +#ifdef BROKEN_UNALIGNED
>> +     fpsize = ALIGN(fpsize, 4);
>> +#endif
>>       dpsize += fpsize;
>>
>>       start = buf = calloc(1, dpsize + sizeof(END));
>>
>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
  2017-08-05 16:16     ` Rob Clark
@ 2017-08-05 16:19       ` Rob Clark
  2017-08-05 16:26         ` Heinrich Schuchardt
  2017-08-05 16:52       ` Heinrich Schuchardt
  1 sibling, 1 reply; 116+ messages in thread
From: Rob Clark @ 2017-08-05 16:19 UTC (permalink / raw)
  To: u-boot

On Sat, Aug 5, 2017 at 12:16 PM, Rob Clark <robdclark@gmail.com> wrote:
> On Sat, Aug 5, 2017 at 12:12 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>> On 08/05/2017 05:58 PM, Rob Clark wrote:
>>> Some arch's have trouble with unaligned accesses.  Technically
>>> EFI device-path structs should be byte aligned, and the next node
>>> in the path starts immediately after the previous.  Meaning that
>>> a pointer to an 'struct efi_device_path' is not necessarily word
>>> aligned.  See section 10.3.1 in v2.7 of UEFI spec.
>>>
>>> This causes problems not just for u-boot, but also most/all EFI
>>> payloads loaded by u-boot on these archs.  Fortunately the common
>>> practice for traversing a device path is to rely on the length
>>> field in the header, rather than the specified length of the
>>> particular device path type+subtype.  So the EFI_DP_PAD() macro
>>> will add the specified number of bytes to the tail of device path
>>> structs to pad them to word alignment.
>>>
>>> Technically this is non-compliant, BROKEN_UNALIGNED should *only*
>>> be defined on archs that cannot do unaligned accesses.
>>>
>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>> ---
>>> I'm not sure if there are other arch's that need -DBROKEN_UNALIGNED
>>>
>>> Mark, this is untested but I think it should solve your crash on the
>>> Banana Pi.  Could you give it a try when you get a chance?
>>>
>>>  arch/arm/config.mk               |  2 +-
>>>  include/efi_api.h                | 30 ++++++++++++++++++++++++++++++
>>>  lib/efi_loader/efi_device_path.c |  3 +++
>>>  3 files changed, 34 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/arch/arm/config.mk b/arch/arm/config.mk
>>> index 1a77779db4..067dc93a9d 100644
>>> --- a/arch/arm/config.mk
>>> +++ b/arch/arm/config.mk
>>> @@ -28,7 +28,7 @@ LLVMS_RELFLAGS              := $(call cc-option,-mllvm,) \
>>>                       $(call cc-option,-arm-use-movt=0,)
>>>  PLATFORM_RELFLAGS    += $(LLVM_RELFLAGS)
>>>
>>> -PLATFORM_CPPFLAGS += -D__ARM__
>>> +PLATFORM_CPPFLAGS += -D__ARM__ -DBROKEN_UNALIGNED
>>
>> NAK
>>
>> We have more then ARM. And other architectures also create exceptions
>> for unaligned access.
>>
>> I hate platform specific code. It should not be used outside /arch.
>>
>> To play it save you should not use _packed at all!
>> Use memcpy to transfer between aligned and unaligned memory.
>
> except for reasons I explained in the thread on the patch that added
> the __packed in the first place.  Sorry, this is ugly but we have to
> do it.

well, to be fair, we don't *have* to do it.  The alternative is
disable EFI_LOADER on archs that cannot do unaligned accesses.  But
this seemed like the better option.

BR,
-R


> BR,
> -R
>
>
>> Best regards
>>
>> Heinrich
>>
>>>
>>>  ifdef CONFIG_ARM64
>>>  PLATFORM_ELFFLAGS += -B aarch64 -O elf64-littleaarch64
>>> diff --git a/include/efi_api.h b/include/efi_api.h
>>> index ef91e34c7b..ddd1e6100a 100644
>>> --- a/include/efi_api.h
>>> +++ b/include/efi_api.h
>>> @@ -284,6 +284,31 @@ struct efi_loaded_image {
>>>  #define DEVICE_PATH_TYPE_END                 0x7f
>>>  #  define DEVICE_PATH_SUB_TYPE_END           0xff
>>>
>>> +/*
>>> + * Some arch's have trouble with unaligned accesses.  Technically
>>> + * EFI device-path structs should be byte aligned, and the next node
>>> + * in the path starts immediately after the previous.  Meaning that
>>> + * a pointer to an 'struct efi_device_path' is not necessarily word
>>> + * aligned.  See section 10.3.1 in v2.7 of UEFI spec.
>>> + *
>>> + * This causes problems not just for u-boot, but also most/all EFI
>>> + * payloads loaded by u-boot on these archs.  Fortunately the common
>>> + * practice for traversing a device path is to rely on the length
>>> + * field in the header, rather than the specified length of the
>>> + * particular device path type+subtype.  So the EFI_DP_PAD() macro
>>> + * will add the specified number of bytes to the tail of device path
>>> + * structs to pad them to word alignment.
>>> + *
>>> + * Technically this is non-compliant, BROKEN_UNALIGNED should *only*
>>> + * be defined on archs that cannot do unaligned accesses.
>>> + */
>>> +
>>> +#ifdef BROKEN_UNALIGNED
>>> +#  define EFI_DP_PAD(n)  u8 __pad[n]
>>> +#else
>>> +#  define EFI_DP_PAD(n)
>>> +#endif
>>> +
>>>  struct efi_device_path {
>>>       u8 type;
>>>       u8 sub_type;
>>> @@ -318,12 +343,14 @@ struct efi_device_path_usb {
>>>       struct efi_device_path dp;
>>>       u8 parent_port_number;
>>>       u8 usb_interface;
>>> +     EFI_DP_PAD(2);
>>>  } __packed;
>>>
>>>  struct efi_device_path_mac_addr {
>>>       struct efi_device_path dp;
>>>       struct efi_mac_addr mac;
>>>       u8 if_type;
>>> +     EFI_DP_PAD(3);
>>>  } __packed;
>>>
>>>  struct efi_device_path_usb_class {
>>> @@ -333,11 +360,13 @@ struct efi_device_path_usb_class {
>>>       u8 device_class;
>>>       u8 device_subclass;
>>>       u8 device_protocol;
>>> +     EFI_DP_PAD(1);
>>>  } __packed;
>>>
>>>  struct efi_device_path_sd_mmc_path {
>>>       struct efi_device_path dp;
>>>       u8 slot_number;
>>> +     EFI_DP_PAD(3);
>>>  } __packed;
>>>
>>>  #define DEVICE_PATH_TYPE_MEDIA_DEVICE                0x04
>>> @@ -353,6 +382,7 @@ struct efi_device_path_hard_drive_path {
>>>       u8 partition_signature[16];
>>>       u8 partmap_type;
>>>       u8 signature_type;
>>> +     EFI_DP_PAD(1);
>>>  } __packed;
>>>
>>>  struct efi_device_path_cdrom_path {
>>> diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
>>> index b5acf73f98..515a1f4737 100644
>>> --- a/lib/efi_loader/efi_device_path.c
>>> +++ b/lib/efi_loader/efi_device_path.c
>>> @@ -402,6 +402,9 @@ struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part,
>>>
>>>       // TODO efi_device_path_file_path should be variable length:
>>>       fpsize = sizeof(struct efi_device_path) + 2 * (strlen(path) + 1);
>>> +#ifdef BROKEN_UNALIGNED
>>> +     fpsize = ALIGN(fpsize, 4);
>>> +#endif
>>>       dpsize += fpsize;
>>>
>>>       start = buf = calloc(1, dpsize + sizeof(END));
>>>
>>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
  2017-08-05 16:19       ` Rob Clark
@ 2017-08-05 16:26         ` Heinrich Schuchardt
  2017-08-05 16:46           ` Rob Clark
  0 siblings, 1 reply; 116+ messages in thread
From: Heinrich Schuchardt @ 2017-08-05 16:26 UTC (permalink / raw)
  To: u-boot

On 08/05/2017 06:19 PM, Rob Clark wrote:
> On Sat, Aug 5, 2017 at 12:16 PM, Rob Clark <robdclark@gmail.com> wrote:
>> On Sat, Aug 5, 2017 at 12:12 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>>> On 08/05/2017 05:58 PM, Rob Clark wrote:
>>>> Some arch's have trouble with unaligned accesses.  Technically
>>>> EFI device-path structs should be byte aligned, and the next node
>>>> in the path starts immediately after the previous.  Meaning that
>>>> a pointer to an 'struct efi_device_path' is not necessarily word
>>>> aligned.  See section 10.3.1 in v2.7 of UEFI spec.
>>>>
>>>> This causes problems not just for u-boot, but also most/all EFI
>>>> payloads loaded by u-boot on these archs.  Fortunately the common
>>>> practice for traversing a device path is to rely on the length
>>>> field in the header, rather than the specified length of the
>>>> particular device path type+subtype.  So the EFI_DP_PAD() macro
>>>> will add the specified number of bytes to the tail of device path
>>>> structs to pad them to word alignment.
>>>>
>>>> Technically this is non-compliant, BROKEN_UNALIGNED should *only*
>>>> be defined on archs that cannot do unaligned accesses.
>>>>
>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>>> ---
>>>> I'm not sure if there are other arch's that need -DBROKEN_UNALIGNED
>>>>
>>>> Mark, this is untested but I think it should solve your crash on the
>>>> Banana Pi.  Could you give it a try when you get a chance?
>>>>
>>>>  arch/arm/config.mk               |  2 +-
>>>>  include/efi_api.h                | 30 ++++++++++++++++++++++++++++++
>>>>  lib/efi_loader/efi_device_path.c |  3 +++
>>>>  3 files changed, 34 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/arch/arm/config.mk b/arch/arm/config.mk
>>>> index 1a77779db4..067dc93a9d 100644
>>>> --- a/arch/arm/config.mk
>>>> +++ b/arch/arm/config.mk
>>>> @@ -28,7 +28,7 @@ LLVMS_RELFLAGS              := $(call cc-option,-mllvm,) \
>>>>                       $(call cc-option,-arm-use-movt=0,)
>>>>  PLATFORM_RELFLAGS    += $(LLVM_RELFLAGS)
>>>>
>>>> -PLATFORM_CPPFLAGS += -D__ARM__
>>>> +PLATFORM_CPPFLAGS += -D__ARM__ -DBROKEN_UNALIGNED
>>>
>>> NAK
>>>
>>> We have more then ARM. And other architectures also create exceptions
>>> for unaligned access.
>>>
>>> I hate platform specific code. It should not be used outside /arch.
>>>
>>> To play it save you should not use _packed at all!
>>> Use memcpy to transfer between aligned and unaligned memory.
>>
>> except for reasons I explained in the thread on the patch that added
>> the __packed in the first place.  Sorry, this is ugly but we have to
>> do it.
> 
> well, to be fair, we don't *have* to do it.  The alternative is
> disable EFI_LOADER on archs that cannot do unaligned accesses.  But
> this seemed like the better option.
> 

In which UEFI protocol do you need the packed structures?
Why can't you use memcpy to provide/read the data in these protocols?
Why can't you use padding on all architectures?

Best regards

Heinrich

> 
> 
>> BR,
>> -R
>>
>>
>>> Best regards
>>>
>>> Heinrich
>>>
>>>>
>>>>  ifdef CONFIG_ARM64
>>>>  PLATFORM_ELFFLAGS += -B aarch64 -O elf64-littleaarch64
>>>> diff --git a/include/efi_api.h b/include/efi_api.h
>>>> index ef91e34c7b..ddd1e6100a 100644
>>>> --- a/include/efi_api.h
>>>> +++ b/include/efi_api.h
>>>> @@ -284,6 +284,31 @@ struct efi_loaded_image {
>>>>  #define DEVICE_PATH_TYPE_END                 0x7f
>>>>  #  define DEVICE_PATH_SUB_TYPE_END           0xff
>>>>
>>>> +/*
>>>> + * Some arch's have trouble with unaligned accesses.  Technically
>>>> + * EFI device-path structs should be byte aligned, and the next node
>>>> + * in the path starts immediately after the previous.  Meaning that
>>>> + * a pointer to an 'struct efi_device_path' is not necessarily word
>>>> + * aligned.  See section 10.3.1 in v2.7 of UEFI spec.
>>>> + *
>>>> + * This causes problems not just for u-boot, but also most/all EFI
>>>> + * payloads loaded by u-boot on these archs.  Fortunately the common
>>>> + * practice for traversing a device path is to rely on the length
>>>> + * field in the header, rather than the specified length of the
>>>> + * particular device path type+subtype.  So the EFI_DP_PAD() macro
>>>> + * will add the specified number of bytes to the tail of device path
>>>> + * structs to pad them to word alignment.
>>>> + *
>>>> + * Technically this is non-compliant, BROKEN_UNALIGNED should *only*
>>>> + * be defined on archs that cannot do unaligned accesses.
>>>> + */
>>>> +
>>>> +#ifdef BROKEN_UNALIGNED
>>>> +#  define EFI_DP_PAD(n)  u8 __pad[n]
>>>> +#else
>>>> +#  define EFI_DP_PAD(n)
>>>> +#endif
>>>> +
>>>>  struct efi_device_path {
>>>>       u8 type;
>>>>       u8 sub_type;
>>>> @@ -318,12 +343,14 @@ struct efi_device_path_usb {
>>>>       struct efi_device_path dp;
>>>>       u8 parent_port_number;
>>>>       u8 usb_interface;
>>>> +     EFI_DP_PAD(2);
>>>>  } __packed;
>>>>
>>>>  struct efi_device_path_mac_addr {
>>>>       struct efi_device_path dp;
>>>>       struct efi_mac_addr mac;
>>>>       u8 if_type;
>>>> +     EFI_DP_PAD(3);
>>>>  } __packed;
>>>>
>>>>  struct efi_device_path_usb_class {
>>>> @@ -333,11 +360,13 @@ struct efi_device_path_usb_class {
>>>>       u8 device_class;
>>>>       u8 device_subclass;
>>>>       u8 device_protocol;
>>>> +     EFI_DP_PAD(1);
>>>>  } __packed;
>>>>
>>>>  struct efi_device_path_sd_mmc_path {
>>>>       struct efi_device_path dp;
>>>>       u8 slot_number;
>>>> +     EFI_DP_PAD(3);
>>>>  } __packed;
>>>>
>>>>  #define DEVICE_PATH_TYPE_MEDIA_DEVICE                0x04
>>>> @@ -353,6 +382,7 @@ struct efi_device_path_hard_drive_path {
>>>>       u8 partition_signature[16];
>>>>       u8 partmap_type;
>>>>       u8 signature_type;
>>>> +     EFI_DP_PAD(1);
>>>>  } __packed;
>>>>
>>>>  struct efi_device_path_cdrom_path {
>>>> diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
>>>> index b5acf73f98..515a1f4737 100644
>>>> --- a/lib/efi_loader/efi_device_path.c
>>>> +++ b/lib/efi_loader/efi_device_path.c
>>>> @@ -402,6 +402,9 @@ struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part,
>>>>
>>>>       // TODO efi_device_path_file_path should be variable length:
>>>>       fpsize = sizeof(struct efi_device_path) + 2 * (strlen(path) + 1);
>>>> +#ifdef BROKEN_UNALIGNED
>>>> +     fpsize = ALIGN(fpsize, 4);
>>>> +#endif
>>>>       dpsize += fpsize;
>>>>
>>>>       start = buf = calloc(1, dpsize + sizeof(END));
>>>>
>>>
> 

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
  2017-08-05 16:26         ` Heinrich Schuchardt
@ 2017-08-05 16:46           ` Rob Clark
  0 siblings, 0 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-05 16:46 UTC (permalink / raw)
  To: u-boot

On Sat, Aug 5, 2017 at 12:26 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
> On 08/05/2017 06:19 PM, Rob Clark wrote:
>> On Sat, Aug 5, 2017 at 12:16 PM, Rob Clark <robdclark@gmail.com> wrote:
>>> On Sat, Aug 5, 2017 at 12:12 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>>>> On 08/05/2017 05:58 PM, Rob Clark wrote:
>>>>> Some arch's have trouble with unaligned accesses.  Technically
>>>>> EFI device-path structs should be byte aligned, and the next node
>>>>> in the path starts immediately after the previous.  Meaning that
>>>>> a pointer to an 'struct efi_device_path' is not necessarily word
>>>>> aligned.  See section 10.3.1 in v2.7 of UEFI spec.
>>>>>
>>>>> This causes problems not just for u-boot, but also most/all EFI
>>>>> payloads loaded by u-boot on these archs.  Fortunately the common
>>>>> practice for traversing a device path is to rely on the length
>>>>> field in the header, rather than the specified length of the
>>>>> particular device path type+subtype.  So the EFI_DP_PAD() macro
>>>>> will add the specified number of bytes to the tail of device path
>>>>> structs to pad them to word alignment.
>>>>>
>>>>> Technically this is non-compliant, BROKEN_UNALIGNED should *only*
>>>>> be defined on archs that cannot do unaligned accesses.
>>>>>
>>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>>>> ---
>>>>> I'm not sure if there are other arch's that need -DBROKEN_UNALIGNED
>>>>>
>>>>> Mark, this is untested but I think it should solve your crash on the
>>>>> Banana Pi.  Could you give it a try when you get a chance?
>>>>>
>>>>>  arch/arm/config.mk               |  2 +-
>>>>>  include/efi_api.h                | 30 ++++++++++++++++++++++++++++++
>>>>>  lib/efi_loader/efi_device_path.c |  3 +++
>>>>>  3 files changed, 34 insertions(+), 1 deletion(-)
>>>>>
>>>>> diff --git a/arch/arm/config.mk b/arch/arm/config.mk
>>>>> index 1a77779db4..067dc93a9d 100644
>>>>> --- a/arch/arm/config.mk
>>>>> +++ b/arch/arm/config.mk
>>>>> @@ -28,7 +28,7 @@ LLVMS_RELFLAGS              := $(call cc-option,-mllvm,) \
>>>>>                       $(call cc-option,-arm-use-movt=0,)
>>>>>  PLATFORM_RELFLAGS    += $(LLVM_RELFLAGS)
>>>>>
>>>>> -PLATFORM_CPPFLAGS += -D__ARM__
>>>>> +PLATFORM_CPPFLAGS += -D__ARM__ -DBROKEN_UNALIGNED
>>>>
>>>> NAK
>>>>
>>>> We have more then ARM. And other architectures also create exceptions
>>>> for unaligned access.
>>>>
>>>> I hate platform specific code. It should not be used outside /arch.
>>>>
>>>> To play it save you should not use _packed at all!
>>>> Use memcpy to transfer between aligned and unaligned memory.
>>>
>>> except for reasons I explained in the thread on the patch that added
>>> the __packed in the first place.  Sorry, this is ugly but we have to
>>> do it.
>>
>> well, to be fair, we don't *have* to do it.  The alternative is
>> disable EFI_LOADER on archs that cannot do unaligned accesses.  But
>> this seemed like the better option.
>>
>
> In which UEFI protocol do you need the packed structures?
> Why can't you use memcpy to provide/read the data in these protocols?
> Why can't you use padding on all architectures?


The device-path protocol, as described in section 10.3 in the UEFI
spec.  And as I already explained, the problem isn't just u-boot but
also all the various efi payloads loaded and executed directly or
indirectly by u-boot.  Please feel free to send patches to these
various projects to fix those problems on armv7/etc.  I guess it will
take a while to get them all upstream, if they are accepted (really,
*why* are we using efi on these archs?) and trickle out into distros.

I'll repeat the section I previously quoted from 10.3.1 in the other
email thread:

   A Device Path is a series of generic Device Path nodes. The first
   Device Path node starts at byte offset zero of the Device Path.
   The next Device Path node starts at the end of the previous Device
   Path node. Therefore all nodes are byte-packed data structures that
   may appear on any byte boundary. All code references to device path
   notes must assume all fields are unaligned. Since every Device Path
   node contains a length field in a known place, it is possible to
   traverse Device Path nodes that are of an unknown type. There is
   no limit to the number, type, or sequence of nodes in a Device Path.

What we were doing before was incorrect.  Sorry, but if we are
implementing the UEFI spec, we need to implement the UEFI spec, not
what we wish the UEFI spec was.  I fixed the bug in u-boot, and that
exposed the problem in openbsd's bootaa64.efi.  But I've spent enough
time looking at shim/fallback/grub to say that they probably have the
same problem on armv7 (and any other arch's that cannot do unaligned
access).

This patch allows us to not break stuff that currently works by
accident on these archs, but do things correctly on aarch64 and archs
that *can* do unaligned access.  This is better than doing things
incorrectly on aarch64, and better than breaking archs that relied on
this existing bug in u-boot's UEFI implementation.

BR,
-R

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
  2017-08-05 16:16     ` Rob Clark
  2017-08-05 16:19       ` Rob Clark
@ 2017-08-05 16:52       ` Heinrich Schuchardt
  2017-08-05 17:06         ` Rob Clark
  2017-08-07 17:15         ` Peter Jones
  1 sibling, 2 replies; 116+ messages in thread
From: Heinrich Schuchardt @ 2017-08-05 16:52 UTC (permalink / raw)
  To: u-boot

On 08/05/2017 06:16 PM, Rob Clark wrote:
> On Sat, Aug 5, 2017 at 12:12 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>> On 08/05/2017 05:58 PM, Rob Clark wrote:
>>> Some arch's have trouble with unaligned accesses.  Technically
>>> EFI device-path structs should be byte aligned, and the next node
>>> in the path starts immediately after the previous.  Meaning that
>>> a pointer to an 'struct efi_device_path' is not necessarily word
>>> aligned.  See section 10.3.1 in v2.7 of UEFI spec.
>>>
>>> This causes problems not just for u-boot, but also most/all EFI
>>> payloads loaded by u-boot on these archs.  Fortunately the common
>>> practice for traversing a device path is to rely on the length
>>> field in the header, rather than the specified length of the
>>> particular device path type+subtype.  So the EFI_DP_PAD() macro
>>> will add the specified number of bytes to the tail of device path
>>> structs to pad them to word alignment.
>>>
>>> Technically this is non-compliant, BROKEN_UNALIGNED should *only*
>>> be defined on archs that cannot do unaligned accesses.
>>>
>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>> ---
>>> I'm not sure if there are other arch's that need -DBROKEN_UNALIGNED
>>>
>>> Mark, this is untested but I think it should solve your crash on the
>>> Banana Pi.  Could you give it a try when you get a chance?
>>>
>>>  arch/arm/config.mk               |  2 +-
>>>  include/efi_api.h                | 30 ++++++++++++++++++++++++++++++
>>>  lib/efi_loader/efi_device_path.c |  3 +++
>>>  3 files changed, 34 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/arch/arm/config.mk b/arch/arm/config.mk
>>> index 1a77779db4..067dc93a9d 100644
>>> --- a/arch/arm/config.mk
>>> +++ b/arch/arm/config.mk
>>> @@ -28,7 +28,7 @@ LLVMS_RELFLAGS              := $(call cc-option,-mllvm,) \
>>>                       $(call cc-option,-arm-use-movt=0,)
>>>  PLATFORM_RELFLAGS    += $(LLVM_RELFLAGS)
>>>
>>> -PLATFORM_CPPFLAGS += -D__ARM__
>>> +PLATFORM_CPPFLAGS += -D__ARM__ -DBROKEN_UNALIGNED
>>
>> NAK
>>
>> We have more then ARM. And other architectures also create exceptions
>> for unaligned access.
>>
>> I hate platform specific code. It should not be used outside /arch.
>>
>> To play it save you should not use _packed at all!
>> Use memcpy to transfer between aligned and unaligned memory.
> 
> except for reasons I explained in the thread on the patch that added
> the __packed in the first place.  Sorry, this is ugly but we have to
> do it.
> 
> BR,
> -R

According to the UEFI standard the nodes in paths are not to be assumed
to be aligned.

So even if you use padding bytes in paths that you pass to the EFI
application you should not expect that the EFI application does the
same. Expect the EFI application either to remove them or send new nodes
without padding.

To the idea of padding bytes and __packed does not make sense.

Best regards

Heinrich

> 
> 
>> Best regards
>>
>> Heinrich
>>
>>>
>>>  ifdef CONFIG_ARM64
>>>  PLATFORM_ELFFLAGS += -B aarch64 -O elf64-littleaarch64
>>> diff --git a/include/efi_api.h b/include/efi_api.h
>>> index ef91e34c7b..ddd1e6100a 100644
>>> --- a/include/efi_api.h
>>> +++ b/include/efi_api.h
>>> @@ -284,6 +284,31 @@ struct efi_loaded_image {
>>>  #define DEVICE_PATH_TYPE_END                 0x7f
>>>  #  define DEVICE_PATH_SUB_TYPE_END           0xff
>>>
>>> +/*
>>> + * Some arch's have trouble with unaligned accesses.  Technically
>>> + * EFI device-path structs should be byte aligned, and the next node
>>> + * in the path starts immediately after the previous.  Meaning that
>>> + * a pointer to an 'struct efi_device_path' is not necessarily word
>>> + * aligned.  See section 10.3.1 in v2.7 of UEFI spec.
>>> + *
>>> + * This causes problems not just for u-boot, but also most/all EFI
>>> + * payloads loaded by u-boot on these archs.  Fortunately the common
>>> + * practice for traversing a device path is to rely on the length
>>> + * field in the header, rather than the specified length of the
>>> + * particular device path type+subtype.  So the EFI_DP_PAD() macro
>>> + * will add the specified number of bytes to the tail of device path
>>> + * structs to pad them to word alignment.
>>> + *
>>> + * Technically this is non-compliant, BROKEN_UNALIGNED should *only*
>>> + * be defined on archs that cannot do unaligned accesses.
>>> + */
>>> +
>>> +#ifdef BROKEN_UNALIGNED
>>> +#  define EFI_DP_PAD(n)  u8 __pad[n]
>>> +#else
>>> +#  define EFI_DP_PAD(n)
>>> +#endif
>>> +
>>>  struct efi_device_path {
>>>       u8 type;
>>>       u8 sub_type;
>>> @@ -318,12 +343,14 @@ struct efi_device_path_usb {
>>>       struct efi_device_path dp;
>>>       u8 parent_port_number;
>>>       u8 usb_interface;
>>> +     EFI_DP_PAD(2);
>>>  } __packed;
>>>
>>>  struct efi_device_path_mac_addr {
>>>       struct efi_device_path dp;
>>>       struct efi_mac_addr mac;
>>>       u8 if_type;
>>> +     EFI_DP_PAD(3);
>>>  } __packed;
>>>
>>>  struct efi_device_path_usb_class {
>>> @@ -333,11 +360,13 @@ struct efi_device_path_usb_class {
>>>       u8 device_class;
>>>       u8 device_subclass;
>>>       u8 device_protocol;
>>> +     EFI_DP_PAD(1);
>>>  } __packed;
>>>
>>>  struct efi_device_path_sd_mmc_path {
>>>       struct efi_device_path dp;
>>>       u8 slot_number;
>>> +     EFI_DP_PAD(3);
>>>  } __packed;
>>>
>>>  #define DEVICE_PATH_TYPE_MEDIA_DEVICE                0x04
>>> @@ -353,6 +382,7 @@ struct efi_device_path_hard_drive_path {
>>>       u8 partition_signature[16];
>>>       u8 partmap_type;
>>>       u8 signature_type;
>>> +     EFI_DP_PAD(1);
>>>  } __packed;
>>>
>>>  struct efi_device_path_cdrom_path {
>>> diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
>>> index b5acf73f98..515a1f4737 100644
>>> --- a/lib/efi_loader/efi_device_path.c
>>> +++ b/lib/efi_loader/efi_device_path.c
>>> @@ -402,6 +402,9 @@ struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part,
>>>
>>>       // TODO efi_device_path_file_path should be variable length:
>>>       fpsize = sizeof(struct efi_device_path) + 2 * (strlen(path) + 1);
>>> +#ifdef BROKEN_UNALIGNED
>>> +     fpsize = ALIGN(fpsize, 4);
>>> +#endif
>>>       dpsize += fpsize;
>>>
>>>       start = buf = calloc(1, dpsize + sizeof(END));
>>>
>>
> 

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
  2017-08-05 16:52       ` Heinrich Schuchardt
@ 2017-08-05 17:06         ` Rob Clark
  2017-08-05 18:43           ` Rob Clark
  2017-08-07 16:56           ` Rob Clark
  2017-08-07 17:15         ` Peter Jones
  1 sibling, 2 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-05 17:06 UTC (permalink / raw)
  To: u-boot

On Sat, Aug 5, 2017 at 12:52 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
> On 08/05/2017 06:16 PM, Rob Clark wrote:
>> On Sat, Aug 5, 2017 at 12:12 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>>> On 08/05/2017 05:58 PM, Rob Clark wrote:
>>>> Some arch's have trouble with unaligned accesses.  Technically
>>>> EFI device-path structs should be byte aligned, and the next node
>>>> in the path starts immediately after the previous.  Meaning that
>>>> a pointer to an 'struct efi_device_path' is not necessarily word
>>>> aligned.  See section 10.3.1 in v2.7 of UEFI spec.
>>>>
>>>> This causes problems not just for u-boot, but also most/all EFI
>>>> payloads loaded by u-boot on these archs.  Fortunately the common
>>>> practice for traversing a device path is to rely on the length
>>>> field in the header, rather than the specified length of the
>>>> particular device path type+subtype.  So the EFI_DP_PAD() macro
>>>> will add the specified number of bytes to the tail of device path
>>>> structs to pad them to word alignment.
>>>>
>>>> Technically this is non-compliant, BROKEN_UNALIGNED should *only*
>>>> be defined on archs that cannot do unaligned accesses.
>>>>
>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>>> ---
>>>> I'm not sure if there are other arch's that need -DBROKEN_UNALIGNED
>>>>
>>>> Mark, this is untested but I think it should solve your crash on the
>>>> Banana Pi.  Could you give it a try when you get a chance?
>>>>
>>>>  arch/arm/config.mk               |  2 +-
>>>>  include/efi_api.h                | 30 ++++++++++++++++++++++++++++++
>>>>  lib/efi_loader/efi_device_path.c |  3 +++
>>>>  3 files changed, 34 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/arch/arm/config.mk b/arch/arm/config.mk
>>>> index 1a77779db4..067dc93a9d 100644
>>>> --- a/arch/arm/config.mk
>>>> +++ b/arch/arm/config.mk
>>>> @@ -28,7 +28,7 @@ LLVMS_RELFLAGS              := $(call cc-option,-mllvm,) \
>>>>                       $(call cc-option,-arm-use-movt=0,)
>>>>  PLATFORM_RELFLAGS    += $(LLVM_RELFLAGS)
>>>>
>>>> -PLATFORM_CPPFLAGS += -D__ARM__
>>>> +PLATFORM_CPPFLAGS += -D__ARM__ -DBROKEN_UNALIGNED
>>>
>>> NAK
>>>
>>> We have more then ARM. And other architectures also create exceptions
>>> for unaligned access.
>>>
>>> I hate platform specific code. It should not be used outside /arch.
>>>
>>> To play it save you should not use _packed at all!
>>> Use memcpy to transfer between aligned and unaligned memory.
>>
>> except for reasons I explained in the thread on the patch that added
>> the __packed in the first place.  Sorry, this is ugly but we have to
>> do it.
>>
>> BR,
>> -R
>
> According to the UEFI standard the nodes in paths are not to be assumed
> to be aligned.
>
> So even if you use padding bytes in paths that you pass to the EFI
> application you should not expect that the EFI application does the
> same. Expect the EFI application either to remove them or send new nodes
> without padding.
>
> To the idea of padding bytes and __packed does not make sense.

Ok, to be fair, you are right about device-paths passed too u-boot.
On BROKEN_UNALIGNED archs, we should sanitise with a copy to an
aligned device-path in *addition* to what I proposed.  I can make a
patch to add a helper to do this a bit later.

But the padding bytes + __packed does make total sense because it
avoids breaking efi payloads that already exist in the field.  The
crash that Mark saw was not in u-boot, but in openbsd's bootaa64.efi.
(It is possibly that we just get lucky here in u-boot since I add the
/End node after the mac address by something the compiler turns into a
memcpy.)

My proposal simply preserves the bug that we already have on
BROKEN_UNALIGNED archs (but makes the improvement that it fixes the
bug on aarch64 and any other arch that can do unaligned access), to
keep existing efi payloads working.

BR,
-R

> Best regards
>
> Heinrich
>
>>
>>
>>> Best regards
>>>
>>> Heinrich
>>>
>>>>
>>>>  ifdef CONFIG_ARM64
>>>>  PLATFORM_ELFFLAGS += -B aarch64 -O elf64-littleaarch64
>>>> diff --git a/include/efi_api.h b/include/efi_api.h
>>>> index ef91e34c7b..ddd1e6100a 100644
>>>> --- a/include/efi_api.h
>>>> +++ b/include/efi_api.h
>>>> @@ -284,6 +284,31 @@ struct efi_loaded_image {
>>>>  #define DEVICE_PATH_TYPE_END                 0x7f
>>>>  #  define DEVICE_PATH_SUB_TYPE_END           0xff
>>>>
>>>> +/*
>>>> + * Some arch's have trouble with unaligned accesses.  Technically
>>>> + * EFI device-path structs should be byte aligned, and the next node
>>>> + * in the path starts immediately after the previous.  Meaning that
>>>> + * a pointer to an 'struct efi_device_path' is not necessarily word
>>>> + * aligned.  See section 10.3.1 in v2.7 of UEFI spec.
>>>> + *
>>>> + * This causes problems not just for u-boot, but also most/all EFI
>>>> + * payloads loaded by u-boot on these archs.  Fortunately the common
>>>> + * practice for traversing a device path is to rely on the length
>>>> + * field in the header, rather than the specified length of the
>>>> + * particular device path type+subtype.  So the EFI_DP_PAD() macro
>>>> + * will add the specified number of bytes to the tail of device path
>>>> + * structs to pad them to word alignment.
>>>> + *
>>>> + * Technically this is non-compliant, BROKEN_UNALIGNED should *only*
>>>> + * be defined on archs that cannot do unaligned accesses.
>>>> + */
>>>> +
>>>> +#ifdef BROKEN_UNALIGNED
>>>> +#  define EFI_DP_PAD(n)  u8 __pad[n]
>>>> +#else
>>>> +#  define EFI_DP_PAD(n)
>>>> +#endif
>>>> +
>>>>  struct efi_device_path {
>>>>       u8 type;
>>>>       u8 sub_type;
>>>> @@ -318,12 +343,14 @@ struct efi_device_path_usb {
>>>>       struct efi_device_path dp;
>>>>       u8 parent_port_number;
>>>>       u8 usb_interface;
>>>> +     EFI_DP_PAD(2);
>>>>  } __packed;
>>>>
>>>>  struct efi_device_path_mac_addr {
>>>>       struct efi_device_path dp;
>>>>       struct efi_mac_addr mac;
>>>>       u8 if_type;
>>>> +     EFI_DP_PAD(3);
>>>>  } __packed;
>>>>
>>>>  struct efi_device_path_usb_class {
>>>> @@ -333,11 +360,13 @@ struct efi_device_path_usb_class {
>>>>       u8 device_class;
>>>>       u8 device_subclass;
>>>>       u8 device_protocol;
>>>> +     EFI_DP_PAD(1);
>>>>  } __packed;
>>>>
>>>>  struct efi_device_path_sd_mmc_path {
>>>>       struct efi_device_path dp;
>>>>       u8 slot_number;
>>>> +     EFI_DP_PAD(3);
>>>>  } __packed;
>>>>
>>>>  #define DEVICE_PATH_TYPE_MEDIA_DEVICE                0x04
>>>> @@ -353,6 +382,7 @@ struct efi_device_path_hard_drive_path {
>>>>       u8 partition_signature[16];
>>>>       u8 partmap_type;
>>>>       u8 signature_type;
>>>> +     EFI_DP_PAD(1);
>>>>  } __packed;
>>>>
>>>>  struct efi_device_path_cdrom_path {
>>>> diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
>>>> index b5acf73f98..515a1f4737 100644
>>>> --- a/lib/efi_loader/efi_device_path.c
>>>> +++ b/lib/efi_loader/efi_device_path.c
>>>> @@ -402,6 +402,9 @@ struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part,
>>>>
>>>>       // TODO efi_device_path_file_path should be variable length:
>>>>       fpsize = sizeof(struct efi_device_path) + 2 * (strlen(path) + 1);
>>>> +#ifdef BROKEN_UNALIGNED
>>>> +     fpsize = ALIGN(fpsize, 4);
>>>> +#endif
>>>>       dpsize += fpsize;
>>>>
>>>>       start = buf = calloc(1, dpsize + sizeof(END));
>>>>
>>>
>>
>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
  2017-08-05 17:06         ` Rob Clark
@ 2017-08-05 18:43           ` Rob Clark
  2017-08-05 20:05             ` Heinrich Schuchardt
  2017-08-07 16:56           ` Rob Clark
  1 sibling, 1 reply; 116+ messages in thread
From: Rob Clark @ 2017-08-05 18:43 UTC (permalink / raw)
  To: u-boot

On Sat, Aug 5, 2017 at 1:06 PM, Rob Clark <robdclark@gmail.com> wrote:
> On Sat, Aug 5, 2017 at 12:52 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>> On 08/05/2017 06:16 PM, Rob Clark wrote:
>>> On Sat, Aug 5, 2017 at 12:12 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>>>> On 08/05/2017 05:58 PM, Rob Clark wrote:
>>>>> Some arch's have trouble with unaligned accesses.  Technically
>>>>> EFI device-path structs should be byte aligned, and the next node
>>>>> in the path starts immediately after the previous.  Meaning that
>>>>> a pointer to an 'struct efi_device_path' is not necessarily word
>>>>> aligned.  See section 10.3.1 in v2.7 of UEFI spec.
>>>>>
>>>>> This causes problems not just for u-boot, but also most/all EFI
>>>>> payloads loaded by u-boot on these archs.  Fortunately the common
>>>>> practice for traversing a device path is to rely on the length
>>>>> field in the header, rather than the specified length of the
>>>>> particular device path type+subtype.  So the EFI_DP_PAD() macro
>>>>> will add the specified number of bytes to the tail of device path
>>>>> structs to pad them to word alignment.
>>>>>
>>>>> Technically this is non-compliant, BROKEN_UNALIGNED should *only*
>>>>> be defined on archs that cannot do unaligned accesses.
>>>>>
>>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>>>> ---
>>>>> I'm not sure if there are other arch's that need -DBROKEN_UNALIGNED
>>>>>
>>>>> Mark, this is untested but I think it should solve your crash on the
>>>>> Banana Pi.  Could you give it a try when you get a chance?
>>>>>
>>>>>  arch/arm/config.mk               |  2 +-
>>>>>  include/efi_api.h                | 30 ++++++++++++++++++++++++++++++
>>>>>  lib/efi_loader/efi_device_path.c |  3 +++
>>>>>  3 files changed, 34 insertions(+), 1 deletion(-)
>>>>>
>>>>> diff --git a/arch/arm/config.mk b/arch/arm/config.mk
>>>>> index 1a77779db4..067dc93a9d 100644
>>>>> --- a/arch/arm/config.mk
>>>>> +++ b/arch/arm/config.mk
>>>>> @@ -28,7 +28,7 @@ LLVMS_RELFLAGS              := $(call cc-option,-mllvm,) \
>>>>>                       $(call cc-option,-arm-use-movt=0,)
>>>>>  PLATFORM_RELFLAGS    += $(LLVM_RELFLAGS)
>>>>>
>>>>> -PLATFORM_CPPFLAGS += -D__ARM__
>>>>> +PLATFORM_CPPFLAGS += -D__ARM__ -DBROKEN_UNALIGNED
>>>>
>>>> NAK
>>>>
>>>> We have more then ARM. And other architectures also create exceptions
>>>> for unaligned access.
>>>>
>>>> I hate platform specific code. It should not be used outside /arch.
>>>>
>>>> To play it save you should not use _packed at all!
>>>> Use memcpy to transfer between aligned and unaligned memory.
>>>
>>> except for reasons I explained in the thread on the patch that added
>>> the __packed in the first place.  Sorry, this is ugly but we have to
>>> do it.
>>>
>>> BR,
>>> -R
>>
>> According to the UEFI standard the nodes in paths are not to be assumed
>> to be aligned.
>>
>> So even if you use padding bytes in paths that you pass to the EFI
>> application you should not expect that the EFI application does the
>> same. Expect the EFI application either to remove them or send new nodes
>> without padding.
>>
>> To the idea of padding bytes and __packed does not make sense.
>
> Ok, to be fair, you are right about device-paths passed too u-boot.
> On BROKEN_UNALIGNED archs, we should sanitise with a copy to an
> aligned device-path in *addition* to what I proposed.  I can make a
> patch to add a helper to do this a bit later.

so thinking about this a bit, I have two options in mind:

 + efi_dp_sanitize() + efi_dp_free() helpers that are no-ops on
   archs that can do unaligned access, but efi_dp_sanitize() always
   allocates and copies on BROKEN_UNALIGNED archs and efi_dp_free()
   always free's on BROKEN_UNALIGNED archs, even if the dp passed
   from efi payload doesn't require it.

 + efi_dp_sanitize() that is no-op on archs that can do unaligned
   access but only allocates/copies when passed a device path that
   would result in unaligned access, plus hook some mechanism to
   auto-free on EFI_EXIT().. which is slightly tricky w/ nesting of
   efi calls, but not impossible and at least avoids the problem
   of missing calls to free the dup'd device-path.. which is the
   sort of leak I might miss since I'm not using EFI_LOADER on any
   BROKEN_UNALIGNED arch

anyone who cares about armv7 + efi have a preference between always
doing an extra alloc+copy+free vs EFI_EXIT() magic?

BR,
-R


> But the padding bytes + __packed does make total sense because it
> avoids breaking efi payloads that already exist in the field.  The
> crash that Mark saw was not in u-boot, but in openbsd's bootaa64.efi.
> (It is possibly that we just get lucky here in u-boot since I add the
> /End node after the mac address by something the compiler turns into a
> memcpy.)
>
> My proposal simply preserves the bug that we already have on
> BROKEN_UNALIGNED archs (but makes the improvement that it fixes the
> bug on aarch64 and any other arch that can do unaligned access), to
> keep existing efi payloads working.
>
> BR,
> -R
>
>> Best regards
>>
>> Heinrich
>>
>>>
>>>
>>>> Best regards
>>>>
>>>> Heinrich
>>>>
>>>>>
>>>>>  ifdef CONFIG_ARM64
>>>>>  PLATFORM_ELFFLAGS += -B aarch64 -O elf64-littleaarch64
>>>>> diff --git a/include/efi_api.h b/include/efi_api.h
>>>>> index ef91e34c7b..ddd1e6100a 100644
>>>>> --- a/include/efi_api.h
>>>>> +++ b/include/efi_api.h
>>>>> @@ -284,6 +284,31 @@ struct efi_loaded_image {
>>>>>  #define DEVICE_PATH_TYPE_END                 0x7f
>>>>>  #  define DEVICE_PATH_SUB_TYPE_END           0xff
>>>>>
>>>>> +/*
>>>>> + * Some arch's have trouble with unaligned accesses.  Technically
>>>>> + * EFI device-path structs should be byte aligned, and the next node
>>>>> + * in the path starts immediately after the previous.  Meaning that
>>>>> + * a pointer to an 'struct efi_device_path' is not necessarily word
>>>>> + * aligned.  See section 10.3.1 in v2.7 of UEFI spec.
>>>>> + *
>>>>> + * This causes problems not just for u-boot, but also most/all EFI
>>>>> + * payloads loaded by u-boot on these archs.  Fortunately the common
>>>>> + * practice for traversing a device path is to rely on the length
>>>>> + * field in the header, rather than the specified length of the
>>>>> + * particular device path type+subtype.  So the EFI_DP_PAD() macro
>>>>> + * will add the specified number of bytes to the tail of device path
>>>>> + * structs to pad them to word alignment.
>>>>> + *
>>>>> + * Technically this is non-compliant, BROKEN_UNALIGNED should *only*
>>>>> + * be defined on archs that cannot do unaligned accesses.
>>>>> + */
>>>>> +
>>>>> +#ifdef BROKEN_UNALIGNED
>>>>> +#  define EFI_DP_PAD(n)  u8 __pad[n]
>>>>> +#else
>>>>> +#  define EFI_DP_PAD(n)
>>>>> +#endif
>>>>> +
>>>>>  struct efi_device_path {
>>>>>       u8 type;
>>>>>       u8 sub_type;
>>>>> @@ -318,12 +343,14 @@ struct efi_device_path_usb {
>>>>>       struct efi_device_path dp;
>>>>>       u8 parent_port_number;
>>>>>       u8 usb_interface;
>>>>> +     EFI_DP_PAD(2);
>>>>>  } __packed;
>>>>>
>>>>>  struct efi_device_path_mac_addr {
>>>>>       struct efi_device_path dp;
>>>>>       struct efi_mac_addr mac;
>>>>>       u8 if_type;
>>>>> +     EFI_DP_PAD(3);
>>>>>  } __packed;
>>>>>
>>>>>  struct efi_device_path_usb_class {
>>>>> @@ -333,11 +360,13 @@ struct efi_device_path_usb_class {
>>>>>       u8 device_class;
>>>>>       u8 device_subclass;
>>>>>       u8 device_protocol;
>>>>> +     EFI_DP_PAD(1);
>>>>>  } __packed;
>>>>>
>>>>>  struct efi_device_path_sd_mmc_path {
>>>>>       struct efi_device_path dp;
>>>>>       u8 slot_number;
>>>>> +     EFI_DP_PAD(3);
>>>>>  } __packed;
>>>>>
>>>>>  #define DEVICE_PATH_TYPE_MEDIA_DEVICE                0x04
>>>>> @@ -353,6 +382,7 @@ struct efi_device_path_hard_drive_path {
>>>>>       u8 partition_signature[16];
>>>>>       u8 partmap_type;
>>>>>       u8 signature_type;
>>>>> +     EFI_DP_PAD(1);
>>>>>  } __packed;
>>>>>
>>>>>  struct efi_device_path_cdrom_path {
>>>>> diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
>>>>> index b5acf73f98..515a1f4737 100644
>>>>> --- a/lib/efi_loader/efi_device_path.c
>>>>> +++ b/lib/efi_loader/efi_device_path.c
>>>>> @@ -402,6 +402,9 @@ struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part,
>>>>>
>>>>>       // TODO efi_device_path_file_path should be variable length:
>>>>>       fpsize = sizeof(struct efi_device_path) + 2 * (strlen(path) + 1);
>>>>> +#ifdef BROKEN_UNALIGNED
>>>>> +     fpsize = ALIGN(fpsize, 4);
>>>>> +#endif
>>>>>       dpsize += fpsize;
>>>>>
>>>>>       start = buf = calloc(1, dpsize + sizeof(END));
>>>>>
>>>>
>>>
>>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 11/20] efi_loader: add guidstr helper
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 11/20] efi_loader: add guidstr helper Rob Clark
@ 2017-08-05 19:33   ` Heinrich Schuchardt
  2017-08-05 19:56     ` Rob Clark
  0 siblings, 1 reply; 116+ messages in thread
From: Heinrich Schuchardt @ 2017-08-05 19:33 UTC (permalink / raw)
  To: u-boot

On 08/04/2017 09:31 PM, Rob Clark wrote:
> 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
> 


You may want to have a look at these:

include/uuid.h:40
int uuid_guid_get_bin(const char *guid_str, unsigned char *guid_bin);

int uuid_guid_get_str(unsigned char *guid_bin, char *guid_str);

With a conversion to uchar* you should be able to use uuid_guid_get_str
for your purposes. So this patch could be eliminated from the series.

Regards

Heinrich

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 11/20] efi_loader: add guidstr helper
  2017-08-05 19:33   ` Heinrich Schuchardt
@ 2017-08-05 19:56     ` Rob Clark
  2017-08-05 20:18       ` Heinrich Schuchardt
  0 siblings, 1 reply; 116+ messages in thread
From: Rob Clark @ 2017-08-05 19:56 UTC (permalink / raw)
  To: u-boot

On Sat, Aug 5, 2017 at 3:33 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
> On 08/04/2017 09:31 PM, Rob Clark wrote:
>> 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
>>
>
>
> You may want to have a look at these:
>
> include/uuid.h:40
> int uuid_guid_get_bin(const char *guid_str, unsigned char *guid_bin);
>
> int uuid_guid_get_str(unsigned char *guid_bin, char *guid_str);
>
> With a conversion to uchar* you should be able to use uuid_guid_get_str
> for your purposes. So this patch could be eliminated from the series.
>

hmm, wow, those seem a bit over-engineered.  But I think we should add
this to vsprintf.c and drop both this patch plus your patch that adds
a macro to print GUIDs.  (And vsprintf.c should re-use
uuid_guid_get_str().. and I could re-use uuid_guid_get_bin() when I
get around to implementing efi_get_next_variable(), so thanks for
pointing that out.)

BR,
-R

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
  2017-08-05 18:43           ` Rob Clark
@ 2017-08-05 20:05             ` Heinrich Schuchardt
  2017-08-05 20:31               ` Rob Clark
  0 siblings, 1 reply; 116+ messages in thread
From: Heinrich Schuchardt @ 2017-08-05 20:05 UTC (permalink / raw)
  To: u-boot

On 08/05/2017 08:43 PM, Rob Clark wrote:
> On Sat, Aug 5, 2017 at 1:06 PM, Rob Clark <robdclark@gmail.com> wrote:
>> On Sat, Aug 5, 2017 at 12:52 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>>> On 08/05/2017 06:16 PM, Rob Clark wrote:
>>>> On Sat, Aug 5, 2017 at 12:12 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>>>>> On 08/05/2017 05:58 PM, Rob Clark wrote:
>>>>>> Some arch's have trouble with unaligned accesses.  Technically
>>>>>> EFI device-path structs should be byte aligned, and the next node
>>>>>> in the path starts immediately after the previous.  Meaning that
>>>>>> a pointer to an 'struct efi_device_path' is not necessarily word
>>>>>> aligned.  See section 10.3.1 in v2.7 of UEFI spec.
>>>>>>
>>>>>> This causes problems not just for u-boot, but also most/all EFI
>>>>>> payloads loaded by u-boot on these archs.  Fortunately the common
>>>>>> practice for traversing a device path is to rely on the length
>>>>>> field in the header, rather than the specified length of the
>>>>>> particular device path type+subtype.  So the EFI_DP_PAD() macro
>>>>>> will add the specified number of bytes to the tail of device path
>>>>>> structs to pad them to word alignment.
>>>>>>
>>>>>> Technically this is non-compliant, BROKEN_UNALIGNED should *only*
>>>>>> be defined on archs that cannot do unaligned accesses.
>>>>>>
>>>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>>>>> ---
>>>>>> I'm not sure if there are other arch's that need -DBROKEN_UNALIGNED
>>>>>>
>>>>>> Mark, this is untested but I think it should solve your crash on the
>>>>>> Banana Pi.  Could you give it a try when you get a chance?
>>>>>>
>>>>>>  arch/arm/config.mk               |  2 +-
>>>>>>  include/efi_api.h                | 30 ++++++++++++++++++++++++++++++
>>>>>>  lib/efi_loader/efi_device_path.c |  3 +++
>>>>>>  3 files changed, 34 insertions(+), 1 deletion(-)
>>>>>>
>>>>>> diff --git a/arch/arm/config.mk b/arch/arm/config.mk
>>>>>> index 1a77779db4..067dc93a9d 100644
>>>>>> --- a/arch/arm/config.mk
>>>>>> +++ b/arch/arm/config.mk
>>>>>> @@ -28,7 +28,7 @@ LLVMS_RELFLAGS              := $(call cc-option,-mllvm,) \
>>>>>>                       $(call cc-option,-arm-use-movt=0,)
>>>>>>  PLATFORM_RELFLAGS    += $(LLVM_RELFLAGS)
>>>>>>
>>>>>> -PLATFORM_CPPFLAGS += -D__ARM__
>>>>>> +PLATFORM_CPPFLAGS += -D__ARM__ -DBROKEN_UNALIGNED
>>>>>
>>>>> NAK
>>>>>
>>>>> We have more then ARM. And other architectures also create exceptions
>>>>> for unaligned access.
>>>>>
>>>>> I hate platform specific code. It should not be used outside /arch.
>>>>>
>>>>> To play it save you should not use _packed at all!
>>>>> Use memcpy to transfer between aligned and unaligned memory.
>>>>
>>>> except for reasons I explained in the thread on the patch that added
>>>> the __packed in the first place.  Sorry, this is ugly but we have to
>>>> do it.
>>>>
>>>> BR,
>>>> -R
>>>
>>> According to the UEFI standard the nodes in paths are not to be assumed
>>> to be aligned.
>>>
>>> So even if you use padding bytes in paths that you pass to the EFI
>>> application you should not expect that the EFI application does the
>>> same. Expect the EFI application either to remove them or send new nodes
>>> without padding.
>>>
>>> To the idea of padding bytes and __packed does not make sense.
>>
>> Ok, to be fair, you are right about device-paths passed too u-boot.
>> On BROKEN_UNALIGNED archs, we should sanitise with a copy to an
>> aligned device-path in *addition* to what I proposed.  I can make a
>> patch to add a helper to do this a bit later.
> 
> so thinking about this a bit, I have two options in mind:
> 
>  + efi_dp_sanitize() + efi_dp_free() helpers that are no-ops on
>    archs that can do unaligned access, but efi_dp_sanitize() always
>    allocates and copies on BROKEN_UNALIGNED archs and efi_dp_free()
>    always free's on BROKEN_UNALIGNED archs, even if the dp passed
>    from efi payload doesn't require it.
> 
>  + efi_dp_sanitize() that is no-op on archs that can do unaligned
>    access but only allocates/copies when passed a device path that
>    would result in unaligned access, plus hook some mechanism to
>    auto-free on EFI_EXIT().. which is slightly tricky w/ nesting of
>    efi calls, but not impossible and at least avoids the problem
>    of missing calls to free the dup'd device-path.. which is the
>    sort of leak I might miss since I'm not using EFI_LOADER on any
>    BROKEN_UNALIGNED arch
> 
> anyone who cares about armv7 + efi have a preference between always
> doing an extra alloc+copy+free vs EFI_EXIT() magic?
> 
> BR,
> -R
> 
> 
>> But the padding bytes + __packed does make total sense because it
>> avoids breaking efi payloads that already exist in the field.  The
>> crash that Mark saw was not in u-boot, but in openbsd's bootaa64.efi.
>> (It is possibly that we just get lucky here in u-boot since I add the
>> /End node after the mac address by something the compiler turns into a
>> memcpy.)
>>
>> My proposal simply preserves the bug that we already have on
>> BROKEN_UNALIGNED archs (but makes the improvement that it fixes the
>> bug on aarch64 and any other arch that can do unaligned access), to
>> keep existing efi payloads working.
>>
>> BR,
>> -R
>>

Please, go for the simplest code.
I cannot imagine that copying takes more than 10ms for starting grub on
any architecture. So the user will not notice it anyway.
Assume every architecture requiring alignment for which you do not have
proof of the contrary.

Even on ARM64 there are op codes that fail without alignment.

Regards

Heinrich

>>>>>
>>>>>>
>>>>>>  ifdef CONFIG_ARM64
>>>>>>  PLATFORM_ELFFLAGS += -B aarch64 -O elf64-littleaarch64
>>>>>> diff --git a/include/efi_api.h b/include/efi_api.h
>>>>>> index ef91e34c7b..ddd1e6100a 100644
>>>>>> --- a/include/efi_api.h
>>>>>> +++ b/include/efi_api.h
>>>>>> @@ -284,6 +284,31 @@ struct efi_loaded_image {
>>>>>>  #define DEVICE_PATH_TYPE_END                 0x7f
>>>>>>  #  define DEVICE_PATH_SUB_TYPE_END           0xff
>>>>>>
>>>>>> +/*
>>>>>> + * Some arch's have trouble with unaligned accesses.  Technically
>>>>>> + * EFI device-path structs should be byte aligned, and the next node
>>>>>> + * in the path starts immediately after the previous.  Meaning that
>>>>>> + * a pointer to an 'struct efi_device_path' is not necessarily word
>>>>>> + * aligned.  See section 10.3.1 in v2.7 of UEFI spec.
>>>>>> + *
>>>>>> + * This causes problems not just for u-boot, but also most/all EFI
>>>>>> + * payloads loaded by u-boot on these archs.  Fortunately the common
>>>>>> + * practice for traversing a device path is to rely on the length
>>>>>> + * field in the header, rather than the specified length of the
>>>>>> + * particular device path type+subtype.  So the EFI_DP_PAD() macro
>>>>>> + * will add the specified number of bytes to the tail of device path
>>>>>> + * structs to pad them to word alignment.
>>>>>> + *
>>>>>> + * Technically this is non-compliant, BROKEN_UNALIGNED should *only*
>>>>>> + * be defined on archs that cannot do unaligned accesses.
>>>>>> + */
>>>>>> +
>>>>>> +#ifdef BROKEN_UNALIGNED
>>>>>> +#  define EFI_DP_PAD(n)  u8 __pad[n]
>>>>>> +#else
>>>>>> +#  define EFI_DP_PAD(n)
>>>>>> +#endif
>>>>>> +
>>>>>>  struct efi_device_path {
>>>>>>       u8 type;
>>>>>>       u8 sub_type;
>>>>>> @@ -318,12 +343,14 @@ struct efi_device_path_usb {
>>>>>>       struct efi_device_path dp;
>>>>>>       u8 parent_port_number;
>>>>>>       u8 usb_interface;
>>>>>> +     EFI_DP_PAD(2);
>>>>>>  } __packed;
>>>>>>
>>>>>>  struct efi_device_path_mac_addr {
>>>>>>       struct efi_device_path dp;
>>>>>>       struct efi_mac_addr mac;
>>>>>>       u8 if_type;
>>>>>> +     EFI_DP_PAD(3);
>>>>>>  } __packed;
>>>>>>
>>>>>>  struct efi_device_path_usb_class {
>>>>>> @@ -333,11 +360,13 @@ struct efi_device_path_usb_class {
>>>>>>       u8 device_class;
>>>>>>       u8 device_subclass;
>>>>>>       u8 device_protocol;
>>>>>> +     EFI_DP_PAD(1);
>>>>>>  } __packed;
>>>>>>
>>>>>>  struct efi_device_path_sd_mmc_path {
>>>>>>       struct efi_device_path dp;
>>>>>>       u8 slot_number;
>>>>>> +     EFI_DP_PAD(3);
>>>>>>  } __packed;
>>>>>>
>>>>>>  #define DEVICE_PATH_TYPE_MEDIA_DEVICE                0x04
>>>>>> @@ -353,6 +382,7 @@ struct efi_device_path_hard_drive_path {
>>>>>>       u8 partition_signature[16];
>>>>>>       u8 partmap_type;
>>>>>>       u8 signature_type;
>>>>>> +     EFI_DP_PAD(1);
>>>>>>  } __packed;
>>>>>>
>>>>>>  struct efi_device_path_cdrom_path {
>>>>>> diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
>>>>>> index b5acf73f98..515a1f4737 100644
>>>>>> --- a/lib/efi_loader/efi_device_path.c
>>>>>> +++ b/lib/efi_loader/efi_device_path.c
>>>>>> @@ -402,6 +402,9 @@ struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part,
>>>>>>
>>>>>>       // TODO efi_device_path_file_path should be variable length:
>>>>>>       fpsize = sizeof(struct efi_device_path) + 2 * (strlen(path) + 1);
>>>>>> +#ifdef BROKEN_UNALIGNED
>>>>>> +     fpsize = ALIGN(fpsize, 4);
>>>>>> +#endif
>>>>>>       dpsize += fpsize;
>>>>>>
>>>>>>       start = buf = calloc(1, dpsize + sizeof(END));
>>>>>>
>>>>>
>>>>
>>>
> 

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 11/20] efi_loader: add guidstr helper
  2017-08-05 19:56     ` Rob Clark
@ 2017-08-05 20:18       ` Heinrich Schuchardt
  0 siblings, 0 replies; 116+ messages in thread
From: Heinrich Schuchardt @ 2017-08-05 20:18 UTC (permalink / raw)
  To: u-boot

On 08/05/2017 09:56 PM, Rob Clark wrote:
> On Sat, Aug 5, 2017 at 3:33 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>> On 08/04/2017 09:31 PM, Rob Clark wrote:
>>> 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
>>>
>>
>>
>> You may want to have a look at these:
>>
>> include/uuid.h:40
>> int uuid_guid_get_bin(const char *guid_str, unsigned char *guid_bin);
>>
>> int uuid_guid_get_str(unsigned char *guid_bin, char *guid_str);
>>
>> With a conversion to uchar* you should be able to use uuid_guid_get_str
>> for your purposes. So this patch could be eliminated from the series.
>>
> 
> hmm, wow, those seem a bit over-engineered.  But I think we should add
> this to vsprintf.c and drop both this patch plus your patch that adds
> a macro to print GUIDs.  (And vsprintf.c should re-use
> uuid_guid_get_str().. and I could re-use uuid_guid_get_bin() when I
> get around to implementing efi_get_next_variable(), so thanks for
> pointing that out.)
> 
> BR,
> -R
> 

In the case of guidstr we are switching two functions where the existing
one has one constant extra parameter.

In EFI_PRINT_GUID we would replace a single
debug(format, guid)
by code that would have to check _DEBUG that only is used inside the
definition of debug, a variable declaration, a call to uuid_guid_get_str
and a printf.

I think we should not evaluate _DEBUG outside include/common.h.

Regards

Heinrich

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
  2017-08-05 20:05             ` Heinrich Schuchardt
@ 2017-08-05 20:31               ` Rob Clark
  2017-08-07 20:19                 ` Alexander Graf
  0 siblings, 1 reply; 116+ messages in thread
From: Rob Clark @ 2017-08-05 20:31 UTC (permalink / raw)
  To: u-boot

On Sat, Aug 5, 2017 at 4:05 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
> On 08/05/2017 08:43 PM, Rob Clark wrote:
>> On Sat, Aug 5, 2017 at 1:06 PM, Rob Clark <robdclark@gmail.com> wrote:
>>> On Sat, Aug 5, 2017 at 12:52 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>>>> On 08/05/2017 06:16 PM, Rob Clark wrote:
>>>>> On Sat, Aug 5, 2017 at 12:12 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>>>>>> On 08/05/2017 05:58 PM, Rob Clark wrote:
>>>>>>> Some arch's have trouble with unaligned accesses.  Technically
>>>>>>> EFI device-path structs should be byte aligned, and the next node
>>>>>>> in the path starts immediately after the previous.  Meaning that
>>>>>>> a pointer to an 'struct efi_device_path' is not necessarily word
>>>>>>> aligned.  See section 10.3.1 in v2.7 of UEFI spec.
>>>>>>>
>>>>>>> This causes problems not just for u-boot, but also most/all EFI
>>>>>>> payloads loaded by u-boot on these archs.  Fortunately the common
>>>>>>> practice for traversing a device path is to rely on the length
>>>>>>> field in the header, rather than the specified length of the
>>>>>>> particular device path type+subtype.  So the EFI_DP_PAD() macro
>>>>>>> will add the specified number of bytes to the tail of device path
>>>>>>> structs to pad them to word alignment.
>>>>>>>
>>>>>>> Technically this is non-compliant, BROKEN_UNALIGNED should *only*
>>>>>>> be defined on archs that cannot do unaligned accesses.
>>>>>>>
>>>>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>>>>>> ---
>>>>>>> I'm not sure if there are other arch's that need -DBROKEN_UNALIGNED
>>>>>>>
>>>>>>> Mark, this is untested but I think it should solve your crash on the
>>>>>>> Banana Pi.  Could you give it a try when you get a chance?
>>>>>>>
>>>>>>>  arch/arm/config.mk               |  2 +-
>>>>>>>  include/efi_api.h                | 30 ++++++++++++++++++++++++++++++
>>>>>>>  lib/efi_loader/efi_device_path.c |  3 +++
>>>>>>>  3 files changed, 34 insertions(+), 1 deletion(-)
>>>>>>>
>>>>>>> diff --git a/arch/arm/config.mk b/arch/arm/config.mk
>>>>>>> index 1a77779db4..067dc93a9d 100644
>>>>>>> --- a/arch/arm/config.mk
>>>>>>> +++ b/arch/arm/config.mk
>>>>>>> @@ -28,7 +28,7 @@ LLVMS_RELFLAGS              := $(call cc-option,-mllvm,) \
>>>>>>>                       $(call cc-option,-arm-use-movt=0,)
>>>>>>>  PLATFORM_RELFLAGS    += $(LLVM_RELFLAGS)
>>>>>>>
>>>>>>> -PLATFORM_CPPFLAGS += -D__ARM__
>>>>>>> +PLATFORM_CPPFLAGS += -D__ARM__ -DBROKEN_UNALIGNED
>>>>>>
>>>>>> NAK
>>>>>>
>>>>>> We have more then ARM. And other architectures also create exceptions
>>>>>> for unaligned access.
>>>>>>
>>>>>> I hate platform specific code. It should not be used outside /arch.
>>>>>>
>>>>>> To play it save you should not use _packed at all!
>>>>>> Use memcpy to transfer between aligned and unaligned memory.
>>>>>
>>>>> except for reasons I explained in the thread on the patch that added
>>>>> the __packed in the first place.  Sorry, this is ugly but we have to
>>>>> do it.
>>>>>
>>>>> BR,
>>>>> -R
>>>>
>>>> According to the UEFI standard the nodes in paths are not to be assumed
>>>> to be aligned.
>>>>
>>>> So even if you use padding bytes in paths that you pass to the EFI
>>>> application you should not expect that the EFI application does the
>>>> same. Expect the EFI application either to remove them or send new nodes
>>>> without padding.
>>>>
>>>> To the idea of padding bytes and __packed does not make sense.
>>>
>>> Ok, to be fair, you are right about device-paths passed too u-boot.
>>> On BROKEN_UNALIGNED archs, we should sanitise with a copy to an
>>> aligned device-path in *addition* to what I proposed.  I can make a
>>> patch to add a helper to do this a bit later.
>>
>> so thinking about this a bit, I have two options in mind:
>>
>>  + efi_dp_sanitize() + efi_dp_free() helpers that are no-ops on
>>    archs that can do unaligned access, but efi_dp_sanitize() always
>>    allocates and copies on BROKEN_UNALIGNED archs and efi_dp_free()
>>    always free's on BROKEN_UNALIGNED archs, even if the dp passed
>>    from efi payload doesn't require it.
>>
>>  + efi_dp_sanitize() that is no-op on archs that can do unaligned
>>    access but only allocates/copies when passed a device path that
>>    would result in unaligned access, plus hook some mechanism to
>>    auto-free on EFI_EXIT().. which is slightly tricky w/ nesting of
>>    efi calls, but not impossible and at least avoids the problem
>>    of missing calls to free the dup'd device-path.. which is the
>>    sort of leak I might miss since I'm not using EFI_LOADER on any
>>    BROKEN_UNALIGNED arch
>>
>> anyone who cares about armv7 + efi have a preference between always
>> doing an extra alloc+copy+free vs EFI_EXIT() magic?
>>
>
> Please, go for the simplest code.

well, the source of my question was there are two definitions of
"simplest" here, ie "simplest to use" and "simplest helpers".. I'm
mostly worried about future patches that use the helpers introducing
leaks.  But actually I think a reasonable middle ground is "simplest
helpers plus always make the helpers not no-ops for DEBUG builds"..

> I cannot imagine that copying takes more than 10ms for starting grub on
> any architecture. So the user will not notice it anyway.
> Assume every architecture requiring alignment for which you do not have
> proof of the contrary.
>
> Even on ARM64 there are op codes that fail without alignment.

iirc the restrictions where mostly about device memory, and atomics.
Which should not apply here.  (And we have aarch64 servers in
production with grub, which doesn't take any protections about
unaligned device-path nodes, using non u-boot EFI implementations.  So
maybe that counts as proof to the contrary ;-))

BR,
-R

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 06/20] common: add some utf16 handling helpers
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 06/20] common: add some utf16 handling helpers Rob Clark
@ 2017-08-06  5:17   ` Simon Glass
  2017-08-08 22:50   ` [U-Boot] [U-Boot, v0, " Heinrich Schuchardt
  1 sibling, 0 replies; 116+ messages in thread
From: Simon Glass @ 2017-08-06  5:17 UTC (permalink / raw)
  To: u-boot

On 4 August 2017 at 13:31, Rob Clark <robdclark@gmail.com> wrote:
> We'll eventually want these in a few places in efi_loader, and also
> vsprintf.
>
> Signed-off-by: Rob Clark <robdclark@gmail.com>
> ---
>  common/Makefile              |  1 +
>  common/charset.c             | 81 ++++++++++++++++++++++++++++++++++++++++++++
>  include/charset.h            | 18 ++++++++++
>  lib/efi_loader/efi_console.c | 17 ++--------
>  4 files changed, 103 insertions(+), 14 deletions(-)
>  create mode 100644 common/charset.c
>  create mode 100644 include/charset.h
>
> diff --git a/common/Makefile b/common/Makefile
> index 60681c845c..44c8e1ba52 100644
> --- a/common/Makefile
> +++ b/common/Makefile
> @@ -175,5 +175,6 @@ obj-$(CONFIG_CMD_DFU) += dfu.o
>  obj-y += command.o
>  obj-y += s_record.o
>  obj-y += xyzModem.o
> +obj-y += charset.o
>
>  CFLAGS_env_embedded.o := -Wa,--no-warn -DENV_CRC=$(shell tools/envcrc 2>/dev/null)
> diff --git a/common/charset.c b/common/charset.c
> new file mode 100644
> index 0000000000..eaff2e542e
> --- /dev/null
> +++ b/common/charset.c
> @@ -0,0 +1,81 @@
> +/*
> + *  charset conversion utils
> + *
> + *  Copyright (c) 2017 Rob Clark
> + *
> + *  SPDX-License-Identifier:     GPL-2.0+
> + */
> +
> +#include <common.h>
> +#include <charset.h>
> +
> +/*
> + * utf8/utf16 conversion mostly lifted from grub
> + */
> +
> +size_t utf16_strlen(uint16_t *in)
> +{
> +       size_t i;
> +       for (i = 0; in[i]; i++);
> +       return i;
> +}
> +
> +size_t utf16_strnlen(const uint16_t *in, size_t count)
> +{
> +       size_t i;
> +       for (i = 0; count-- && in[i]; i++);
> +       return i;
> +}
> +
> +/* Convert UTF-16 to UTF-8.  */
> +uint8_t *utf16_to_utf8(uint8_t *dest, const uint16_t *src, size_t size)
> +{
> +       uint32_t code_high = 0;
> +
> +       while (size--) {
> +               uint32_t code = *src++;
> +
> +               if (code_high) {
> +                       if (code >= 0xDC00 && code <= 0xDFFF) {
> +                               /* Surrogate pair.  */
> +                               code = ((code_high - 0xD800) << 10) + (code - 0xDC00) + 0x10000;
> +
> +                               *dest++ = (code >> 18) | 0xF0;
> +                               *dest++ = ((code >> 12) & 0x3F) | 0x80;
> +                               *dest++ = ((code >> 6) & 0x3F) | 0x80;
> +                               *dest++ = (code & 0x3F) | 0x80;
> +                       } else {
> +                               /* Error...  */
> +                               *dest++ = '?';
> +                               /* *src may be valid. Don't eat it.  */
> +                               src--;
> +                       }
> +
> +                       code_high = 0;
> +               } else {
> +                       if (code <= 0x007F) {
> +                               *dest++ = code;
> +                       } else if (code <= 0x07FF) {
> +                               *dest++ = (code >> 6) | 0xC0;
> +                               *dest++ = (code & 0x3F) | 0x80;
> +                       } else if (code >= 0xD800 && code <= 0xDBFF) {
> +                               code_high = code;
> +                               continue;
> +                       } else if (code >= 0xDC00 && code <= 0xDFFF) {
> +                               /* Error... */
> +                               *dest++ = '?';
> +                       } else if (code < 0x10000) {
> +                               *dest++ = (code >> 12) | 0xE0;
> +                               *dest++ = ((code >> 6) & 0x3F) | 0x80;
> +                               *dest++ = (code & 0x3F) | 0x80;
> +                       } else {
> +                               *dest++ = (code >> 18) | 0xF0;
> +                               *dest++ = ((code >> 12) & 0x3F) | 0x80;
> +                               *dest++ = ((code >> 6) & 0x3F) | 0x80;
> +                               *dest++ = (code & 0x3F) | 0x80;
> +                       }
> +               }
> +       }
> +
> +       return dest;
> +}
> diff --git a/include/charset.h b/include/charset.h
> new file mode 100644
> index 0000000000..2ee1172182
> --- /dev/null
> +++ b/include/charset.h
> @@ -0,0 +1,18 @@
> +/*
> + *  charset conversion utils
> + *
> + *  Copyright (c) 2017 Rob Clark
> + *
> + *  SPDX-License-Identifier:     GPL-2.0+
> + */
> +
> +#ifndef __CHARSET_H_
> +#define __CHARSET_H_
> +
> +#define MAX_UTF8_PER_UTF16 4
> +
> +size_t utf16_strlen(uint16_t *in);
> +size_t utf16_strnlen(const uint16_t *in, size_t count);
> +uint8_t *utf16_to_utf8(uint8_t *dest, const uint16_t *src, size_t size);

Please don't add new exported functions without comments.

> +
> +#endif /* __CHARSET_H_ */
> diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
> index 5ebce4b544..3fc82b8726 100644
> --- a/lib/efi_loader/efi_console.c
> +++ b/lib/efi_loader/efi_console.c
> @@ -7,6 +7,7 @@
>   */
>
>  #include <common.h>
> +#include <charset.h>
>  #include <efi_loader.h>
>
>  static bool console_size_queried;
> @@ -138,20 +139,8 @@ static efi_status_t EFIAPI efi_cout_reset(
>
>  static void print_unicode_in_utf8(u16 c)
>  {
> -       char utf8[4] = { 0 };
> -       char *b = utf8;
> -
> -       if (c < 0x80) {
> -               *(b++) = c;
> -       } else if (c < 0x800) {
> -               *(b++) = 192 + c / 64;
> -               *(b++) = 128 + c % 64;
> -       } else {
> -               *(b++) = 224 + c / 4096;
> -               *(b++) = 128 + c / 64 % 64;
> -               *(b++) = 128 + c % 64;
> -       }
> -
> +       char utf8[MAX_UTF8_PER_UTF16] = { 0 };
> +       utf16_to_utf8((u8 *)utf8, &c, 1);
>         puts(utf8);
>  }
>
> --
> 2.13.0
>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 19/20] efi_loader: efi variable support
  2017-08-04 19:32 ` [U-Boot] [PATCH v0 19/20] efi_loader: efi variable support Rob Clark
@ 2017-08-06  5:17   ` Simon Glass
  0 siblings, 0 replies; 116+ messages in thread
From: Simon Glass @ 2017-08-06  5:17 UTC (permalink / raw)
  To: u-boot

On 4 August 2017 at 13:32, Rob Clark <robdclark@gmail.com> wrote:

Commit message?

> Signed-off-by: Rob Clark <robdclark@gmail.com>
> ---
>  cmd/bootefi.c                 |   4 +
>  include/efi.h                 |  19 +++
>  include/efi_loader.h          |  10 ++
>  lib/efi_loader/Makefile       |   2 +-
>  lib/efi_loader/efi_boottime.c |   5 +
>  lib/efi_loader/efi_runtime.c  |  17 ++-
>  lib/efi_loader/efi_variable.c | 342 ++++++++++++++++++++++++++++++++++++++++++
>  7 files changed, 394 insertions(+), 5 deletions(-)
>  create mode 100644 lib/efi_loader/efi_variable.c

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-05 14:28         ` Rob Clark
@ 2017-08-06 12:53           ` Mark Kettenis
  0 siblings, 0 replies; 116+ messages in thread
From: Mark Kettenis @ 2017-08-06 12:53 UTC (permalink / raw)
  To: u-boot

> From: Rob Clark <robdclark@gmail.com>
> Date: Sat, 5 Aug 2017 10:28:34 -0400
> 
> On Sat, Aug 5, 2017 at 10:01 AM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
> >
> > OpenBSD doesn't run on the db410c.  However, our EFI bootloader should
> > just run.  You can download it from:
> >
> >   http://ftp.openbsd.org/pub/OpenBSD/snapshots/arm64/BOOTAA64.EFI
> >
> > for the 64-bit (AArch64) and
> >
> >   http://ftp.openbsd.org/pub/OpenBSD/snapshots/armv7/BOOTARM.EFI
> >
> > for the 32-bit version (AArch32).
> >
> 
> Yup, this appears to work, I think this is about what you'd expect
> without having an openbsd fs:
> 
> dragonboard410c => load mmc 0:1 ${kernel_addr_r} efi/openbsd/bootaa64.efi
> reading efi/openbsd/bootaa64.efi
> 75732 bytes read in 35 ms (2.1 MiB/s)
> dragonboard410c => bootefi ${kernel_addr_r} ${fdt_addr_r}
> ## Starting EFI application at 81000000 ...
> Scanning disk sdhci at 07864000.blk...
> Found 1 disks
> WARNING: Invalid device tree, expect boot to fail
> >> OpenBSD/arm64 BOOTAA64 0.6
> sd0: getdisklabel: no disk label
> open(sd0a:/etc/boot.conf): bad partition
> boot>
> sd0: getdisklabel: no disk label
> cannot open sd0a:/etc/random.seed: bad partition
> booting sd0a:/bsd: sd0: getdisklabel: no disk label
> open sd0a:/bsd: bad partition
>  failed(95). will try /bsd
> boot>
> sd0: getdisklabel: no disk label
> cannot open sd0a:/etc/random.seed: bad partition
> booting sd0a:/bsd: sd0: getdisklabel: no disk label
> open sd0a:/bsd: bad partition
>  failed(95). will try /bsd
> Turning timeout off.
> boot>

Right.  At that point it is trying to load the OpenBSD kernel from a
UFS/FFS filesystem, which fails because you don't have a BSD disklabel
on your SD/MMC device.  And even if it could, it would be game over
pretty quickly as the OpenBSD kernel doesn't support the UART on your
board (yet).

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-05 15:36                 ` Rob Clark
@ 2017-08-06 13:16                   ` Mark Kettenis
  2017-08-06 14:17                     ` Rob Clark
  2017-08-06 14:28                     ` Mark Kettenis
  0 siblings, 2 replies; 116+ messages in thread
From: Mark Kettenis @ 2017-08-06 13:16 UTC (permalink / raw)
  To: u-boot

> From: Rob Clark <robdclark@gmail.com>
> Date: Sat, 5 Aug 2017 11:36:25 -0400
> 
> On Sat, Aug 5, 2017 at 11:24 AM, Rob Clark <robdclark@gmail.com> wrote:
> > On Sat, Aug 5, 2017 at 11:10 AM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
> >> On 08/05/2017 04:35 PM, Rob Clark wrote:
> >>> On Sat, Aug 5, 2017 at 10:28 AM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
> >>>>> Date: Sat, 5 Aug 2017 16:01:51 +0200 (CEST)
> >>>>> From: Mark Kettenis <mark.kettenis@xs4all.nl>
> >>>>>
> >>>>> Unfortunately something in this patch series breaks things for me on a
> >>>>> Banana Pi:
> >>>>
> >>>> And according to git bisect:
> >>>>
> >>>> 4e3e748a50fc3f43e20c7ff407184596d7c9a589 is the first bad commit
> >>>> commit 4e3e748a50fc3f43e20c7ff407184596d7c9a589
> >>>> Author: Peter Jones <pjones@redhat.com>
> >>>> Date:   Wed Jun 21 16:39:02 2017 -0400
> >>>>
> >>>>     efi: add some more device path structures
> >>>>
> >>>>     Signed-off-by: Peter Jones <pjones@redhat.com>
> >>>>     Signed-off-by: Rob Clark <robdclark@gmail.com>
> >>>
> >>>
> >>> hmm, odd.. it is only adding some #define's and structs that are not
> >>> used until a later commit..
> >>>
> >>> although it does also make 'struct efi_device_path_mac_addr' __packed,
> >>> which it should have been before.  Is this an armv7?  I wonder if we
> >>> have some troubles with unaligned accesses on armv7 that we don't have
> >>> on aarch64 (or maybe compiler isn't turning access to device-path
> >>> nodes into byte accesses if it can't do unaligned accesses.  (The node
> >>> in the device-path structure are byte-packed.)
> >>
> >> http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka15414.html
> >>
> >> <cite>On older processors, such as ARM9 family based processors, an
> >> unaligned load had to be synthesised in software.  Typically by doing a
> >> series of small accesses, and combining the results. ... Unaligned
> >> access support must be enabled by setting the SCTLR.A bit in the system
> >> control coprocessor</cite>
> >>
> >> Generally packing structures is not a good idea performance-wise. The
> >> sequence of fields should be carefully chosen to fill up to powers of
> >> two (2, 4 , 8).
> >
> > Yeah, it was clearly a dumb idea for UEFI to not make device-path
> > nodes word aligned.  But when implementing a standard, we don't have a
> > choice but to implement it properly, warts and all :-/
> >
> 
> btw, just for reference (if anyone is curious), see sect 10.3.1 in
> UEFI spec v2.7.  If you don't want to bother looking it up, here is
> the exact wording:
> 
>    A Device Path is a series of generic Device Path nodes. The first
>    Device Path node starts at byte offset zero of the Device Path.
>    The next Device Path node starts at the end of the previous Device
>    Path node. Therefore all nodes are byte-packed data structures that
>    may appear on any byte boundary. All code references to device path
>    notes must assume all fields are unaligned. Since every Device Path
>    node contains a length field in a known place, it is possible to
>    traverse Device Path nodes that are of an unknown type. There is
>    no limit to the number, type, or sequence of nodes in a Device Path.
> 
> So clearly what we were doing before was incorrect.. but cheating w/
> extra padding bytes on arch's that cannot handle unaligned accesses
> will avoid having to go fix grub, bootaa64/shim/fallback (and anything
> else that uses gnu-efi), and apparently openbsd's bootaa64.efi.  It is
> kinda weird to be using efi on these arch's in the first place, so I
> guess I don't feel as badly about the padding bytes hack on those
> arch's.  (But we should not use the hack on aarch64.)

Looking a bit more closely at the OpenBSD efiboot code, I'm pretty
sure we handle the parsing of device path nodes correctly.  We use an
incarnation of the Intel EFI header files which have:

typedef struct _EFI_DEVICE_PATH {
        UINT8                           Type;
        UINT8                           SubType;
        UINT8                           Length[2];
} EFI_DEVICE_PATH;

#define DevicePathNodeLength(a)     ( ((a)->Length[0]) | ((a)->Length[1] << 8) )

so this is all done using byte access.

Going back to the original crash report:

data abort
pc : [<7ef8d878>]          lr : [<7ef8d874>]
reloc pc : [<4a039878>]    lr : [<4a039874>]
sp : 7af29660  ip : 00000000     fp : 7af29774
r10: 7efec230  r9 : 7af33ee0     r8 : 00000000
r7 : 00000009  r6 : 7ef9e8b8     r5 : 7af296a0  r4 : 7efa4495
r3 : 7af296a0  r2 : 0000008c     r1 : 7af29658  r0 : 00000004
Flags: nzCV  IRQs off  FIQs off  Mode SVC_32

I think it is actually "reloc pc" instead of "pc" that we need to look
at:

$ addr2line -e u-boot 0x4a039874 
/home/kettenis/tmp/rclark/u-boot/include/efi_loader.h:272

which points at the guidstr() function.  That code certainly looks
suspicious.  It will defenitely trigger alignment faults if the guid
isn't 32-bit aligned.

The relevant instruction is a 16-bit load:

  4a039878:       e1d430b4        ldrh    r3, [r4, #4]

and with r4 = 7efa4495 that will defenitely trap.

Looking at the defenition efi_guid_t in u-boot:

  typedef struct {
          u8 b[16];
  } efi_guid_t;

there is no guarantee that GUIDs are properly aligned, so you'll need
to fix the guidstr function introduced in commit
b6d913c6101ba891eb2bcb08a4ee9fc8fb57367.

Things are already broken before that commit though, so there is
another problem.  I'll see if I can figure out what it is...

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-06 13:16                   ` Mark Kettenis
@ 2017-08-06 14:17                     ` Rob Clark
  2017-08-06 14:26                       ` Rob Clark
  2017-08-06 14:28                     ` Mark Kettenis
  1 sibling, 1 reply; 116+ messages in thread
From: Rob Clark @ 2017-08-06 14:17 UTC (permalink / raw)
  To: u-boot

On Sun, Aug 6, 2017 at 9:16 AM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>> From: Rob Clark <robdclark@gmail.com>
>> Date: Sat, 5 Aug 2017 11:36:25 -0400
>>
>> On Sat, Aug 5, 2017 at 11:24 AM, Rob Clark <robdclark@gmail.com> wrote:
>> > On Sat, Aug 5, 2017 at 11:10 AM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>> >> On 08/05/2017 04:35 PM, Rob Clark wrote:
>> >>> On Sat, Aug 5, 2017 at 10:28 AM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>> >>>>> Date: Sat, 5 Aug 2017 16:01:51 +0200 (CEST)
>> >>>>> From: Mark Kettenis <mark.kettenis@xs4all.nl>
>> >>>>>
>> >>>>> Unfortunately something in this patch series breaks things for me on a
>> >>>>> Banana Pi:
>> >>>>
>> >>>> And according to git bisect:
>> >>>>
>> >>>> 4e3e748a50fc3f43e20c7ff407184596d7c9a589 is the first bad commit
>> >>>> commit 4e3e748a50fc3f43e20c7ff407184596d7c9a589
>> >>>> Author: Peter Jones <pjones@redhat.com>
>> >>>> Date:   Wed Jun 21 16:39:02 2017 -0400
>> >>>>
>> >>>>     efi: add some more device path structures
>> >>>>
>> >>>>     Signed-off-by: Peter Jones <pjones@redhat.com>
>> >>>>     Signed-off-by: Rob Clark <robdclark@gmail.com>
>> >>>
>> >>>
>> >>> hmm, odd.. it is only adding some #define's and structs that are not
>> >>> used until a later commit..
>> >>>
>> >>> although it does also make 'struct efi_device_path_mac_addr' __packed,
>> >>> which it should have been before.  Is this an armv7?  I wonder if we
>> >>> have some troubles with unaligned accesses on armv7 that we don't have
>> >>> on aarch64 (or maybe compiler isn't turning access to device-path
>> >>> nodes into byte accesses if it can't do unaligned accesses.  (The node
>> >>> in the device-path structure are byte-packed.)
>> >>
>> >> http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka15414.html
>> >>
>> >> <cite>On older processors, such as ARM9 family based processors, an
>> >> unaligned load had to be synthesised in software.  Typically by doing a
>> >> series of small accesses, and combining the results. ... Unaligned
>> >> access support must be enabled by setting the SCTLR.A bit in the system
>> >> control coprocessor</cite>
>> >>
>> >> Generally packing structures is not a good idea performance-wise. The
>> >> sequence of fields should be carefully chosen to fill up to powers of
>> >> two (2, 4 , 8).
>> >
>> > Yeah, it was clearly a dumb idea for UEFI to not make device-path
>> > nodes word aligned.  But when implementing a standard, we don't have a
>> > choice but to implement it properly, warts and all :-/
>> >
>>
>> btw, just for reference (if anyone is curious), see sect 10.3.1 in
>> UEFI spec v2.7.  If you don't want to bother looking it up, here is
>> the exact wording:
>>
>>    A Device Path is a series of generic Device Path nodes. The first
>>    Device Path node starts at byte offset zero of the Device Path.
>>    The next Device Path node starts at the end of the previous Device
>>    Path node. Therefore all nodes are byte-packed data structures that
>>    may appear on any byte boundary. All code references to device path
>>    notes must assume all fields are unaligned. Since every Device Path
>>    node contains a length field in a known place, it is possible to
>>    traverse Device Path nodes that are of an unknown type. There is
>>    no limit to the number, type, or sequence of nodes in a Device Path.
>>
>> So clearly what we were doing before was incorrect.. but cheating w/
>> extra padding bytes on arch's that cannot handle unaligned accesses
>> will avoid having to go fix grub, bootaa64/shim/fallback (and anything
>> else that uses gnu-efi), and apparently openbsd's bootaa64.efi.  It is
>> kinda weird to be using efi on these arch's in the first place, so I
>> guess I don't feel as badly about the padding bytes hack on those
>> arch's.  (But we should not use the hack on aarch64.)
>
> Looking a bit more closely at the OpenBSD efiboot code, I'm pretty
> sure we handle the parsing of device path nodes correctly.  We use an
> incarnation of the Intel EFI header files which have:
>
> typedef struct _EFI_DEVICE_PATH {
>         UINT8                           Type;
>         UINT8                           SubType;
>         UINT8                           Length[2];
> } EFI_DEVICE_PATH;
>
> #define DevicePathNodeLength(a)     ( ((a)->Length[0]) | ((a)->Length[1] << 8) )
>
> so this is all done using byte access.

Hmm, I assume the OpenBSD efiboot code does look at the payload of
device-path nodes, like HARDDRIVE_DEVICE_PATH.. which does use u32 and
u64 fields (which would be unaligned).  Although that might not be the
problem here.

> Going back to the original crash report:
>
> data abort
> pc : [<7ef8d878>]          lr : [<7ef8d874>]
> reloc pc : [<4a039878>]    lr : [<4a039874>]
> sp : 7af29660  ip : 00000000     fp : 7af29774
> r10: 7efec230  r9 : 7af33ee0     r8 : 00000000
> r7 : 00000009  r6 : 7ef9e8b8     r5 : 7af296a0  r4 : 7efa4495
> r3 : 7af296a0  r2 : 0000008c     r1 : 7af29658  r0 : 00000004
> Flags: nzCV  IRQs off  FIQs off  Mode SVC_32
>
> I think it is actually "reloc pc" instead of "pc" that we need to look
> at:
>
> $ addr2line -e u-boot 0x4a039874
> /home/kettenis/tmp/rclark/u-boot/include/efi_loader.h:272
>
> which points at the guidstr() function.  That code certainly looks
> suspicious.  It will defenitely trigger alignment faults if the guid
> isn't 32-bit aligned.

hmm, interesting.  At least gnu-efi's EFI_GUID uses the same
u32+u16+u16+u8[8] layout.  And iirc so did linux kernel and grub, so
it seemed like u-boot was the odd one out for using u8[16].  Although
maybe we are printing one of our own guid's or openbsd efiboot is also
using u8[16].

Either way I've dropped this patch and instead added %pG support to
vsprintf, using uuid_bin_to_str() which only does byte accesses.

The latest can be found here:

  https://github.com/robclark/u-boot/commits/enough-uefi-for-shim

  https://github.com/robclark/u-boot.git enough-uefi-for-shim


> The relevant instruction is a 16-bit load:
>
>   4a039878:       e1d430b4        ldrh    r3, [r4, #4]
>
> and with r4 = 7efa4495 that will defenitely trap.
>
> Looking at the defenition efi_guid_t in u-boot:
>
>   typedef struct {
>           u8 b[16];
>   } efi_guid_t;
>
> there is no guarantee that GUIDs are properly aligned, so you'll need
> to fix the guidstr function introduced in commit
> b6d913c6101ba891eb2bcb08a4ee9fc8fb57367.
>
> Things are already broken before that commit though, so there is
> another problem.  I'll see if I can figure out what it is...

Thanks

BR,
-R

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-06 14:17                     ` Rob Clark
@ 2017-08-06 14:26                       ` Rob Clark
  0 siblings, 0 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-06 14:26 UTC (permalink / raw)
  To: u-boot

On Sun, Aug 6, 2017 at 10:17 AM, Rob Clark <robdclark@gmail.com> wrote:
> On Sun, Aug 6, 2017 at 9:16 AM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>>> From: Rob Clark <robdclark@gmail.com>
>>> Date: Sat, 5 Aug 2017 11:36:25 -0400
>>>
>>> On Sat, Aug 5, 2017 at 11:24 AM, Rob Clark <robdclark@gmail.com> wrote:
>>> > On Sat, Aug 5, 2017 at 11:10 AM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>>> >> On 08/05/2017 04:35 PM, Rob Clark wrote:
>>> >>> On Sat, Aug 5, 2017 at 10:28 AM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>>> >>>>> Date: Sat, 5 Aug 2017 16:01:51 +0200 (CEST)
>>> >>>>> From: Mark Kettenis <mark.kettenis@xs4all.nl>
>>> >>>>>
>>> >>>>> Unfortunately something in this patch series breaks things for me on a
>>> >>>>> Banana Pi:
>>> >>>>
>>> >>>> And according to git bisect:
>>> >>>>
>>> >>>> 4e3e748a50fc3f43e20c7ff407184596d7c9a589 is the first bad commit
>>> >>>> commit 4e3e748a50fc3f43e20c7ff407184596d7c9a589
>>> >>>> Author: Peter Jones <pjones@redhat.com>
>>> >>>> Date:   Wed Jun 21 16:39:02 2017 -0400
>>> >>>>
>>> >>>>     efi: add some more device path structures
>>> >>>>
>>> >>>>     Signed-off-by: Peter Jones <pjones@redhat.com>
>>> >>>>     Signed-off-by: Rob Clark <robdclark@gmail.com>
>>> >>>
>>> >>>
>>> >>> hmm, odd.. it is only adding some #define's and structs that are not
>>> >>> used until a later commit..
>>> >>>
>>> >>> although it does also make 'struct efi_device_path_mac_addr' __packed,
>>> >>> which it should have been before.  Is this an armv7?  I wonder if we
>>> >>> have some troubles with unaligned accesses on armv7 that we don't have
>>> >>> on aarch64 (or maybe compiler isn't turning access to device-path
>>> >>> nodes into byte accesses if it can't do unaligned accesses.  (The node
>>> >>> in the device-path structure are byte-packed.)
>>> >>
>>> >> http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka15414.html
>>> >>
>>> >> <cite>On older processors, such as ARM9 family based processors, an
>>> >> unaligned load had to be synthesised in software.  Typically by doing a
>>> >> series of small accesses, and combining the results. ... Unaligned
>>> >> access support must be enabled by setting the SCTLR.A bit in the system
>>> >> control coprocessor</cite>
>>> >>
>>> >> Generally packing structures is not a good idea performance-wise. The
>>> >> sequence of fields should be carefully chosen to fill up to powers of
>>> >> two (2, 4 , 8).
>>> >
>>> > Yeah, it was clearly a dumb idea for UEFI to not make device-path
>>> > nodes word aligned.  But when implementing a standard, we don't have a
>>> > choice but to implement it properly, warts and all :-/
>>> >
>>>
>>> btw, just for reference (if anyone is curious), see sect 10.3.1 in
>>> UEFI spec v2.7.  If you don't want to bother looking it up, here is
>>> the exact wording:
>>>
>>>    A Device Path is a series of generic Device Path nodes. The first
>>>    Device Path node starts at byte offset zero of the Device Path.
>>>    The next Device Path node starts at the end of the previous Device
>>>    Path node. Therefore all nodes are byte-packed data structures that
>>>    may appear on any byte boundary. All code references to device path
>>>    notes must assume all fields are unaligned. Since every Device Path
>>>    node contains a length field in a known place, it is possible to
>>>    traverse Device Path nodes that are of an unknown type. There is
>>>    no limit to the number, type, or sequence of nodes in a Device Path.
>>>
>>> So clearly what we were doing before was incorrect.. but cheating w/
>>> extra padding bytes on arch's that cannot handle unaligned accesses
>>> will avoid having to go fix grub, bootaa64/shim/fallback (and anything
>>> else that uses gnu-efi), and apparently openbsd's bootaa64.efi.  It is
>>> kinda weird to be using efi on these arch's in the first place, so I
>>> guess I don't feel as badly about the padding bytes hack on those
>>> arch's.  (But we should not use the hack on aarch64.)
>>
>> Looking a bit more closely at the OpenBSD efiboot code, I'm pretty
>> sure we handle the parsing of device path nodes correctly.  We use an
>> incarnation of the Intel EFI header files which have:
>>
>> typedef struct _EFI_DEVICE_PATH {
>>         UINT8                           Type;
>>         UINT8                           SubType;
>>         UINT8                           Length[2];
>> } EFI_DEVICE_PATH;
>>
>> #define DevicePathNodeLength(a)     ( ((a)->Length[0]) | ((a)->Length[1] << 8) )
>>
>> so this is all done using byte access.
>
> Hmm, I assume the OpenBSD efiboot code does look at the payload of
> device-path nodes, like HARDDRIVE_DEVICE_PATH.. which does use u32 and
> u64 fields (which would be unaligned).  Although that might not be the
> problem here.
>
>> Going back to the original crash report:
>>
>> data abort
>> pc : [<7ef8d878>]          lr : [<7ef8d874>]
>> reloc pc : [<4a039878>]    lr : [<4a039874>]
>> sp : 7af29660  ip : 00000000     fp : 7af29774
>> r10: 7efec230  r9 : 7af33ee0     r8 : 00000000
>> r7 : 00000009  r6 : 7ef9e8b8     r5 : 7af296a0  r4 : 7efa4495
>> r3 : 7af296a0  r2 : 0000008c     r1 : 7af29658  r0 : 00000004
>> Flags: nzCV  IRQs off  FIQs off  Mode SVC_32
>>
>> I think it is actually "reloc pc" instead of "pc" that we need to look
>> at:
>>
>> $ addr2line -e u-boot 0x4a039874
>> /home/kettenis/tmp/rclark/u-boot/include/efi_loader.h:272
>>
>> which points at the guidstr() function.  That code certainly looks
>> suspicious.  It will defenitely trigger alignment faults if the guid
>> isn't 32-bit aligned.
>
> hmm, interesting.  At least gnu-efi's EFI_GUID uses the same
> u32+u16+u16+u8[8] layout.  And iirc so did linux kernel and grub, so
> it seemed like u-boot was the odd one out for using u8[16].  Although
> maybe we are printing one of our own guid's or openbsd efiboot is also
> using u8[16].
>
> Either way I've dropped this patch and instead added %pG support to
> vsprintf, using uuid_bin_to_str() which only does byte accesses.
>
> The latest can be found here:
>
>   https://github.com/robclark/u-boot/commits/enough-uefi-for-shim
>
>   https://github.com/robclark/u-boot.git enough-uefi-for-shim
>
>
>> The relevant instruction is a 16-bit load:
>>
>>   4a039878:       e1d430b4        ldrh    r3, [r4, #4]
>>
>> and with r4 = 7efa4495 that will defenitely trap.
>>
>> Looking at the defenition efi_guid_t in u-boot:
>>
>>   typedef struct {
>>           u8 b[16];
>>   } efi_guid_t;
>>
>> there is no guarantee that GUIDs are properly aligned, so you'll need
>> to fix the guidstr function introduced in commit
>> b6d913c6101ba891eb2bcb08a4ee9fc8fb57367.
>>
>> Things are already broken before that commit though, so there is
>> another problem.  I'll see if I can figure out what it is...
>
> Thanks
>

btw, we do have some travis tests that run grub.efi (in qemu) on armv7
and others.. maybe adding OpenBSD's efiboot to the test suit would be
a good idea?   (And eventually shim+fallback.efi after this patchset
is merged..)

BR,
-R

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-06 13:16                   ` Mark Kettenis
  2017-08-06 14:17                     ` Rob Clark
@ 2017-08-06 14:28                     ` Mark Kettenis
  2017-08-06 14:45                       ` Rob Clark
  1 sibling, 1 reply; 116+ messages in thread
From: Mark Kettenis @ 2017-08-06 14:28 UTC (permalink / raw)
  To: u-boot

> Date: Sun, 6 Aug 2017 15:16:09 +0200 (CEST)
> From: Mark Kettenis <mark.kettenis@xs4all.nl>
> 
> Things are already broken before that commit though, so there is
> another problem.  I'll see if I can figure out what it is...

data abort
pc : [<7ef59160>]          lr : [<7ef59118>]
reloc pc : [<4a003160>]    lr : [<4a003118>]
sp : 7af2b820  ip : 7af69635     fp : 7ef5aee4
r10: 00000005  r9 : 7af35ee0     r8 : 7efb4490
r7 : 7af695e8  r6 : 7af69620     r5 : 0000005c  r4 : 7af2b828
r3 : 7efae477  r2 : 0000005c     r1 : 0000002f  r0 : 00000000
Flags: nzCv  IRQs off  FIQs off  Mode SVC_32

addr2line -e u-boot.bin 0x4a003160
/home/kettenis/tmp/rclark/u-boot/include/efi_loader.h:204

which is the ascii2unicode() function which is used in
efi_disk_add_dev() and indeed does 16-bit stores to potentiaslly
unaligned memory.  And yes, adding __packed to struct
efi_device_file_path will trigger the unaligned access in this case.

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-06 14:28                     ` Mark Kettenis
@ 2017-08-06 14:45                       ` Rob Clark
  2017-08-06 15:34                         ` Rob Clark
  0 siblings, 1 reply; 116+ messages in thread
From: Rob Clark @ 2017-08-06 14:45 UTC (permalink / raw)
  To: u-boot

On Sun, Aug 6, 2017 at 10:28 AM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>> Date: Sun, 6 Aug 2017 15:16:09 +0200 (CEST)
>> From: Mark Kettenis <mark.kettenis@xs4all.nl>
>>
>> Things are already broken before that commit though, so there is
>> another problem.  I'll see if I can figure out what it is...
>
> data abort
> pc : [<7ef59160>]          lr : [<7ef59118>]
> reloc pc : [<4a003160>]    lr : [<4a003118>]
> sp : 7af2b820  ip : 7af69635     fp : 7ef5aee4
> r10: 00000005  r9 : 7af35ee0     r8 : 7efb4490
> r7 : 7af695e8  r6 : 7af69620     r5 : 0000005c  r4 : 7af2b828
> r3 : 7efae477  r2 : 0000005c     r1 : 0000002f  r0 : 00000000
> Flags: nzCv  IRQs off  FIQs off  Mode SVC_32
>
> addr2line -e u-boot.bin 0x4a003160
> /home/kettenis/tmp/rclark/u-boot/include/efi_loader.h:204
>
> which is the ascii2unicode() function which is used in
> efi_disk_add_dev() and indeed does 16-bit stores to potentiaslly
> unaligned memory.  And yes, adding __packed to struct
> efi_device_file_path will trigger the unaligned access in this case.

Hmm, I could see that.  Have you had a chance to try with "efi_loader:
hack for archs that cannot do unaligned accesses"?  (That patch should
probably be squashed back in to various earlier patches, but I figured
keeping it separate for now would be easier to review.)
ascii2unicode() is probably only the first place that would hit
unaligned accesses..

But that all said, [1] seems to imply armv7 *can* do unaligned
accesses.  So maybe this is a banana-pi specific issue.  Maybe some
cp15 bit not set correctly?  (Otherwise I think I should have it this
issue in travis with tests that load grub.efi on various qemu
platforms.)


[1] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka15414.html

I've started trying to hack up test_efi_loader.py to add a test that
loads OpenBSD's bootloader..  kinda muddling through it at this point,
since not a py expert or too familiar w/ u-boot's test framework.  But
I'll see if I can get to the point where I can run the same thing on
various arm7 and aarch64 devices in qemu.

BR,
-R

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-06 14:45                       ` Rob Clark
@ 2017-08-06 15:34                         ` Rob Clark
  2017-08-06 16:00                           ` Heinrich Schuchardt
                                             ` (3 more replies)
  0 siblings, 4 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-06 15:34 UTC (permalink / raw)
  To: u-boot

On Sun, Aug 6, 2017 at 10:45 AM, Rob Clark <robdclark@gmail.com> wrote:
>
> I've started trying to hack up test_efi_loader.py to add a test that
> loads OpenBSD's bootloader..  kinda muddling through it at this point,
> since not a py expert or too familiar w/ u-boot's test framework.  But
> I'll see if I can get to the point where I can run the same thing on
> various arm7 and aarch64 devices in qemu.
>

Making a bit of progress on this (running it on a vexpress_ca15_tc2
board in qemu).. any hint where I can find BOOTARM.EFI src code?

=> tftpboot 80400000 obsdboot.efi
smc911x: MAC 52:54:00:12:34:56
smc911x: detected LAN9118 controller
smc911x: phy initialized
smc911x: MAC 52:54:00:12:34:56
Using smc911x-0 device
TFTP from server 10.0.2.2; our IP address is 10.0.2.15
Filename 'obsdboot.efi'.
Load address: 0x80400000
Loading: *%08#####
12.4 MiB/s
done
Bytes transferred = 64908 (fd8c hex)
smc911x: MAC 52:54:00:12:34:56
=> crc32 80400000 $filesize
CRC32 for 80400000 ... 8040fd8b ==> a9ac4fcf
=> bootefi 80400000
## Starting EFI application at 80400000 ...
WARNING: Invalid device tree, expect boot to fail
BS->LocateHandle() returns 0
undefined instruction
pc : [<9eec65c4>]   lr : [<9eeca390>]
sp : 9fed7a18  ip : 0000003f fp : 9fed7a2c
r10: 00000000  r9 : 9eed4658 r8 : 00000000
r7 : 9eed1ce4  r6 : 9eed3538 r5 : 9fed7a6c  r4 : 9eed4658
r3 : 00000000  r2 : 9eed2f8e r1 : 9eed1ee0  r0 : 00000000
Flags: nZCv  IRQs off  FIQs off  Mode SVC_32
Resetting CPU ...

resetting ...


U-Boot 2017.09-rc1-00025-g534695d189 (Aug 06 2017 - 06:58:16 -0400)

DRAM:  1 GiB
WARNING: Caches not enabled
Flash: 128 MiB
MMC:   MMC: 0
*** Warning - bad CRC, using default environment

In:    serial
Out:   serial
Err:   serial
Net:   smc911x-0
Hit any key to stop autoboot:  2

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-06 15:34                         ` Rob Clark
@ 2017-08-06 16:00                           ` Heinrich Schuchardt
  2017-08-06 16:14                           ` Jonathan Gray
                                             ` (2 subsequent siblings)
  3 siblings, 0 replies; 116+ messages in thread
From: Heinrich Schuchardt @ 2017-08-06 16:00 UTC (permalink / raw)
  To: u-boot

On 08/06/2017 05:34 PM, Rob Clark wrote:
> On Sun, Aug 6, 2017 at 10:45 AM, Rob Clark <robdclark@gmail.com> wrote:
>>
>> I've started trying to hack up test_efi_loader.py to add a test that
>> loads OpenBSD's bootloader..  kinda muddling through it at this point,
>> since not a py expert or too familiar w/ u-boot's test framework.  But
>> I'll see if I can get to the point where I can run the same thing on
>> various arm7 and aarch64 devices in qemu.
>>
> 
> Making a bit of progress on this (running it on a vexpress_ca15_tc2
> board in qemu).. any hint where I can find BOOTARM.EFI src code?

On Debian arm64 the following commands create bootaa64.efi.

sudo apt-get install grub-efi-arm64
sudo update-grub
sudo grub-install --target=arm64-efi --boot-directory=/boot
--efi-directory=/EFI  {/EFI is my mounted FAT partition}

I guess you can do the same on armhf to create bootarm.efi

Regards

Heinrich


> 
> => tftpboot 80400000 obsdboot.efi
> smc911x: MAC 52:54:00:12:34:56
> smc911x: detected LAN9118 controller
> smc911x: phy initialized
> smc911x: MAC 52:54:00:12:34:56
> Using smc911x-0 device
> TFTP from server 10.0.2.2; our IP address is 10.0.2.15
> Filename 'obsdboot.efi'.
> Load address: 0x80400000
> Loading: *%08#####
> 12.4 MiB/s
> done
> Bytes transferred = 64908 (fd8c hex)
> smc911x: MAC 52:54:00:12:34:56
> => crc32 80400000 $filesize
> CRC32 for 80400000 ... 8040fd8b ==> a9ac4fcf
> => bootefi 80400000
> ## Starting EFI application at 80400000 ...
> WARNING: Invalid device tree, expect boot to fail
> BS->LocateHandle() returns 0
> undefined instruction
> pc : [<9eec65c4>]   lr : [<9eeca390>]
> sp : 9fed7a18  ip : 0000003f fp : 9fed7a2c
> r10: 00000000  r9 : 9eed4658 r8 : 00000000
> r7 : 9eed1ce4  r6 : 9eed3538 r5 : 9fed7a6c  r4 : 9eed4658
> r3 : 00000000  r2 : 9eed2f8e r1 : 9eed1ee0  r0 : 00000000
> Flags: nZCv  IRQs off  FIQs off  Mode SVC_32
> Resetting CPU ...
> 
> resetting ...
> 
> 
> U-Boot 2017.09-rc1-00025-g534695d189 (Aug 06 2017 - 06:58:16 -0400)
> 
> DRAM:  1 GiB
> WARNING: Caches not enabled
> Flash: 128 MiB
> MMC:   MMC: 0
> *** Warning - bad CRC, using default environment
> 
> In:    serial
> Out:   serial
> Err:   serial
> Net:   smc911x-0
> Hit any key to stop autoboot:  2
> 

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-06 15:34                         ` Rob Clark
  2017-08-06 16:00                           ` Heinrich Schuchardt
@ 2017-08-06 16:14                           ` Jonathan Gray
  2017-08-06 17:28                           ` Mark Kettenis
  2017-08-07 15:47                           ` Jonathan Gray
  3 siblings, 0 replies; 116+ messages in thread
From: Jonathan Gray @ 2017-08-06 16:14 UTC (permalink / raw)
  To: u-boot

On Sun, Aug 06, 2017 at 11:34:15AM -0400, Rob Clark wrote:
> On Sun, Aug 6, 2017 at 10:45 AM, Rob Clark <robdclark@gmail.com> wrote:
> >
> > I've started trying to hack up test_efi_loader.py to add a test that
> > loads OpenBSD's bootloader..  kinda muddling through it at this point,
> > since not a py expert or too familiar w/ u-boot's test framework.  But
> > I'll see if I can get to the point where I can run the same thing on
> > various arm7 and aarch64 devices in qemu.
> >
> 
> Making a bit of progress on this (running it on a vexpress_ca15_tc2
> board in qemu).. any hint where I can find BOOTARM.EFI src code?

https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/sys/arch/armv7/stand/efiboot/
https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/sys/stand/efi/include/

https://www.openbsd.org/anoncvs.html

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-06 15:34                         ` Rob Clark
  2017-08-06 16:00                           ` Heinrich Schuchardt
  2017-08-06 16:14                           ` Jonathan Gray
@ 2017-08-06 17:28                           ` Mark Kettenis
  2017-08-06 17:49                             ` Rob Clark
  2017-08-07 15:47                           ` Jonathan Gray
  3 siblings, 1 reply; 116+ messages in thread
From: Mark Kettenis @ 2017-08-06 17:28 UTC (permalink / raw)
  To: u-boot

> From: Rob Clark <robdclark@gmail.com>
> Date: Sun, 6 Aug 2017 11:34:15 -0400
> 
> On Sun, Aug 6, 2017 at 10:45 AM, Rob Clark <robdclark@gmail.com> wrote:
> >
> > I've started trying to hack up test_efi_loader.py to add a test that
> > loads OpenBSD's bootloader..  kinda muddling through it at this point,
> > since not a py expert or too familiar w/ u-boot's test framework.  But
> > I'll see if I can get to the point where I can run the same thing on
> > various arm7 and aarch64 devices in qemu.
> >
> 
> Making a bit of progress on this (running it on a vexpress_ca15_tc2
> board in qemu).. any hint where I can find BOOTARM.EFI src code?

https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/sys/arch/armv7/stand/efiboot/efiboot.c?rev=1.17&content-type=text/x-cvsweb-markup

Your failure below looks a bit different from what I'm getting on the
Banana Pi now.  There I get stuck because the 2nd BS->HandleProtocol()
call in efi_main() fails.  Somehow the device path of the registered
disk devices isn't matched correctly to the boot device path...

BTW, the OpenBSD code runs fine without the alignment hack.  Our code
is pretty minimal and doesn't actualy look into the device path
components.  It just matches the components based on type and by soing
memcmp.

> => tftpboot 80400000 obsdboot.efi
> smc911x: MAC 52:54:00:12:34:56
> smc911x: detected LAN9118 controller
> smc911x: phy initialized
> smc911x: MAC 52:54:00:12:34:56
> Using smc911x-0 device
> TFTP from server 10.0.2.2; our IP address is 10.0.2.15
> Filename 'obsdboot.efi'.
> Load address: 0x80400000
> Loading: *%08#####
> 12.4 MiB/s
> done
> Bytes transferred = 64908 (fd8c hex)
> smc911x: MAC 52:54:00:12:34:56
> => crc32 80400000 $filesize
> CRC32 for 80400000 ... 8040fd8b ==> a9ac4fcf
> => bootefi 80400000
> ## Starting EFI application at 80400000 ...
> WARNING: Invalid device tree, expect boot to fail
> BS->LocateHandle() returns 0
> undefined instruction
> pc : [<9eec65c4>]   lr : [<9eeca390>]
> sp : 9fed7a18  ip : 0000003f fp : 9fed7a2c
> r10: 00000000  r9 : 9eed4658 r8 : 00000000
> r7 : 9eed1ce4  r6 : 9eed3538 r5 : 9fed7a6c  r4 : 9eed4658
> r3 : 00000000  r2 : 9eed2f8e r1 : 9eed1ee0  r0 : 00000000
> Flags: nZCv  IRQs off  FIQs off  Mode SVC_32
> Resetting CPU ...
> 
> resetting ...
> 
> 
> U-Boot 2017.09-rc1-00025-g534695d189 (Aug 06 2017 - 06:58:16 -0400)
> 
> DRAM:  1 GiB
> WARNING: Caches not enabled
> Flash: 128 MiB
> MMC:   MMC: 0
> *** Warning - bad CRC, using default environment
> 
> In:    serial
> Out:   serial
> Err:   serial
> Net:   smc911x-0
> Hit any key to stop autoboot:  2
> 

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-06 17:28                           ` Mark Kettenis
@ 2017-08-06 17:49                             ` Rob Clark
  2017-08-06 18:13                               ` Peter Robinson
  2017-08-06 18:21                               ` Mark Kettenis
  0 siblings, 2 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-06 17:49 UTC (permalink / raw)
  To: u-boot

On Sun, Aug 6, 2017 at 1:28 PM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>> From: Rob Clark <robdclark@gmail.com>
>> Date: Sun, 6 Aug 2017 11:34:15 -0400
>>
>> On Sun, Aug 6, 2017 at 10:45 AM, Rob Clark <robdclark@gmail.com> wrote:
>> >
>> > I've started trying to hack up test_efi_loader.py to add a test that
>> > loads OpenBSD's bootloader..  kinda muddling through it at this point,
>> > since not a py expert or too familiar w/ u-boot's test framework.  But
>> > I'll see if I can get to the point where I can run the same thing on
>> > various arm7 and aarch64 devices in qemu.
>> >
>>
>> Making a bit of progress on this (running it on a vexpress_ca15_tc2
>> board in qemu).. any hint where I can find BOOTARM.EFI src code?
>
> https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/sys/arch/armv7/stand/efiboot/efiboot.c?rev=1.17&content-type=text/x-cvsweb-markup
>
> Your failure below looks a bit different from what I'm getting on the
> Banana Pi now.  There I get stuck because the 2nd BS->HandleProtocol()
> call in efi_main() fails.  Somehow the device path of the registered
> disk devices isn't matched correctly to the boot device path...

that is.. odd.. mind adding in lib/efi_loader/Makefile:

  ccflags-y += -DDEBUG=1

?

(you can make the console output easier to read again w/ #undef DEBUG
at top of efi_console.c)

With my complete patchset (ie. assuming this isn't in the middle of a
bisect between 13/20 and 15/20) the device paths for the diskobj and
EFI_LOADED_IMAGE::DeviceHandle should be constructed identically.
(Ie. the patchset consolidates the two different places it was
constructed before... and also fixes the thing I notice you work
around in efi_diskprobe())

> BTW, the OpenBSD code runs fine without the alignment hack.  Our code
> is pretty minimal and doesn't actualy look into the device path
> components.  It just matches the components based on type and by soing
> memcmp.

Hmm, well I do suspect there are still cases where u-boot could crash
because of unaligned access without the hack.  Although I'm less
convinced that we should need the hack on armv7 and more thinking this
is something specific about banana-pi (or allwinner?).  The
vexpress_ca15_tc2 "board" in qemu seems to be working properly..

Mind sending me or pastebin'ing your u-boot .config?  There are some
different device-path construction depending on legacy vs
CONFIG_DM+CONFIG_BLK (the legacy case *looks* right to me, and is used
by vexpress_ca15_tc2.. so I think it should work..)

If OpenBSD supports the vexpress boards, I guess with a suitable qemu
-sd disk.img I should be able to try booting all the way to OS..

BR,
-R

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-06 17:49                             ` Rob Clark
@ 2017-08-06 18:13                               ` Peter Robinson
  2017-08-06 18:21                               ` Mark Kettenis
  1 sibling, 0 replies; 116+ messages in thread
From: Peter Robinson @ 2017-08-06 18:13 UTC (permalink / raw)
  To: u-boot

On Sun, Aug 6, 2017 at 6:49 PM, Rob Clark <robdclark@gmail.com> wrote:
> On Sun, Aug 6, 2017 at 1:28 PM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>>> From: Rob Clark <robdclark@gmail.com>
>>> Date: Sun, 6 Aug 2017 11:34:15 -0400
>>>
>>> On Sun, Aug 6, 2017 at 10:45 AM, Rob Clark <robdclark@gmail.com> wrote:
>>> >
>>> > I've started trying to hack up test_efi_loader.py to add a test that
>>> > loads OpenBSD's bootloader..  kinda muddling through it at this point,
>>> > since not a py expert or too familiar w/ u-boot's test framework.  But
>>> > I'll see if I can get to the point where I can run the same thing on
>>> > various arm7 and aarch64 devices in qemu.
>>> >
>>>
>>> Making a bit of progress on this (running it on a vexpress_ca15_tc2
>>> board in qemu).. any hint where I can find BOOTARM.EFI src code?
>>
>> https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/sys/arch/armv7/stand/efiboot/efiboot.c?rev=1.17&content-type=text/x-cvsweb-markup
>>
>> Your failure below looks a bit different from what I'm getting on the
>> Banana Pi now.  There I get stuck because the 2nd BS->HandleProtocol()
>> call in efi_main() fails.  Somehow the device path of the registered
>> disk devices isn't matched correctly to the boot device path...
>
> that is.. odd.. mind adding in lib/efi_loader/Makefile:
>
>   ccflags-y += -DDEBUG=1
>
> ?
>
> (you can make the console output easier to read again w/ #undef DEBUG
> at top of efi_console.c)
>
> With my complete patchset (ie. assuming this isn't in the middle of a
> bisect between 13/20 and 15/20) the device paths for the diskobj and
> EFI_LOADED_IMAGE::DeviceHandle should be constructed identically.
> (Ie. the patchset consolidates the two different places it was
> constructed before... and also fixes the thing I notice you work
> around in efi_diskprobe())
>
>> BTW, the OpenBSD code runs fine without the alignment hack.  Our code
>> is pretty minimal and doesn't actualy look into the device path
>> components.  It just matches the components based on type and by soing
>> memcmp.
>
> Hmm, well I do suspect there are still cases where u-boot could crash
> because of unaligned access without the hack.  Although I'm less
> convinced that we should need the hack on armv7 and more thinking this
> is something specific about banana-pi (or allwinner?).  The
> vexpress_ca15_tc2 "board" in qemu seems to be working properly..

All AllWinner SoCs are Cortex-A series so ARMv7, in the case of the
banana pi series are AW A20s so are Cortex-A7 based so should be fine
too

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-06 17:49                             ` Rob Clark
  2017-08-06 18:13                               ` Peter Robinson
@ 2017-08-06 18:21                               ` Mark Kettenis
  2017-08-06 18:37                                 ` Mark Kettenis
  2017-08-06 18:41                                 ` Rob Clark
  1 sibling, 2 replies; 116+ messages in thread
From: Mark Kettenis @ 2017-08-06 18:21 UTC (permalink / raw)
  To: u-boot

> From: Rob Clark <robdclark@gmail.com>
> Date: Sun, 6 Aug 2017 13:49:43 -0400
> 
> On Sun, Aug 6, 2017 at 1:28 PM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
> >> From: Rob Clark <robdclark@gmail.com>
> >> Date: Sun, 6 Aug 2017 11:34:15 -0400
> >>
> >> On Sun, Aug 6, 2017 at 10:45 AM, Rob Clark <robdclark@gmail.com> wrote:
> >> >
> >> > I've started trying to hack up test_efi_loader.py to add a test that
> >> > loads OpenBSD's bootloader..  kinda muddling through it at this point,
> >> > since not a py expert or too familiar w/ u-boot's test framework.  But
> >> > I'll see if I can get to the point where I can run the same thing on
> >> > various arm7 and aarch64 devices in qemu.
> >> >
> >>
> >> Making a bit of progress on this (running it on a vexpress_ca15_tc2
> >> board in qemu).. any hint where I can find BOOTARM.EFI src code?
> >
> > https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/sys/arch/armv7/stand/efiboot/efiboot.c?rev=1.17&content-type=text/x-cvsweb-markup
> >
> > Your failure below looks a bit different from what I'm getting on the
> > Banana Pi now.  There I get stuck because the 2nd BS->HandleProtocol()
> > call in efi_main() fails.  Somehow the device path of the registered
> > disk devices isn't matched correctly to the boot device path...
> 
> that is.. odd.. mind adding in lib/efi_loader/Makefile:
> 
>   ccflags-y += -DDEBUG=1
> 
> ?
> 
> (you can make the console output easier to read again w/ #undef DEBUG
> at top of efi_console.c)
> 
> With my complete patchset (ie. assuming this isn't in the middle of a
> bisect between 13/20 and 15/20) the device paths for the diskobj and
> EFI_LOADED_IMAGE::DeviceHandle should be constructed identically.
> (Ie. the patchset consolidates the two different places it was
> constructed before... and also fixes the thing I notice you work
> around in efi_diskprobe())
> 
> > BTW, the OpenBSD code runs fine without the alignment hack.  Our code
> > is pretty minimal and doesn't actualy look into the device path
> > components.  It just matches the components based on type and by soing
> > memcmp.
> 
> Hmm, well I do suspect there are still cases where u-boot could crash
> because of unaligned access without the hack.  Although I'm less
> convinced that we should need the hack on armv7 and more thinking this
> is something specific about banana-pi (or allwinner?).  The
> vexpress_ca15_tc2 "board" in qemu seems to be working properly..

I suspect qemu simply doesn't emulate the alignment trap.  The u-boot
startup code explicitly enables alignment fauls on armv7.  See
arch/arm/cpu/armv7/start.S:152.  This helps catching bugs!

> Mind sending me or pastebin'ing your u-boot .config?  There are some
> different device-path construction depending on legacy vs
> CONFIG_DM+CONFIG_BLK (the legacy case *looks* right to me, and is used
> by vexpress_ca15_tc2.. so I think it should work..)

See below.  The Banana Pi (and all other sunxi boards) indeed uses the
legacy code path.  And I think there is a bug in the legacy codepath
where it encodes the partition in the "file" path component.

> If OpenBSD supports the vexpress boards, I guess with a suitable qemu
> -sd disk.img I should be able to try booting all the way to OS..

I think it does.  We don't have a "miniroot" image for it though.  It
might be possible to take 

  http://ftp.openbsd.org/pub/OpenBSD/snapshots/armv7/miniroot-cubie-61.fs

and dd the vexpress u-boot into the right location and copy the device
tree onto the msdos filesystem in that image.

#
# Automatically generated file; DO NOT EDIT.
# U-Boot 2017.09-rc1 Configuration
#
CONFIG_CREATE_ARCH_SYMLINK=y
# CONFIG_ARC is not set
CONFIG_ARM=y
# CONFIG_M68K is not set
# CONFIG_MICROBLAZE is not set
# CONFIG_MIPS is not set
# CONFIG_NDS32 is not set
# CONFIG_NIOS2 is not set
# CONFIG_PPC is not set
# CONFIG_SANDBOX is not set
# CONFIG_SH is not set
# CONFIG_X86 is not set
# CONFIG_XTENSA is not set
CONFIG_SYS_ARCH="arm"
CONFIG_SYS_CPU="armv7"
CONFIG_SYS_SOC="sunxi"
CONFIG_SYS_BOARD="sunxi"
CONFIG_SYS_CONFIG_NAME="sun7i"

#
# ARM architecture
#
CONFIG_HAS_VBAR=y
CONFIG_HAS_THUMB2=y
CONFIG_ARM_ASM_UNIFIED=y
CONFIG_CPU_V7=y
CONFIG_SYS_ARM_ARCH=7
CONFIG_SYS_CACHE_SHIFT_6=y
CONFIG_SYS_CACHELINE_SIZE=64
# CONFIG_ARM_SMCCC is not set
# CONFIG_SEMIHOSTING is not set
# CONFIG_SYS_THUMB_BUILD is not set
CONFIG_SPL_SYS_THUMB_BUILD=y
# CONFIG_SYS_L2CACHE_OFF is not set
# CONFIG_ENABLE_ARM_SOC_BOOT0_HOOK is not set
# CONFIG_ARM_CORTEX_CPU_IS_UP is not set
CONFIG_USE_ARCH_MEMCPY=y
CONFIG_SPL_USE_ARCH_MEMCPY=y
CONFIG_USE_ARCH_MEMSET=y
CONFIG_SPL_USE_ARCH_MEMSET=y
# CONFIG_ARM64_SUPPORT_AARCH32 is not set
# CONFIG_ARCH_AT91 is not set
# CONFIG_TARGET_EDB93XX is not set
# CONFIG_TARGET_ASPENITE is not set
# CONFIG_TARGET_GPLUGD is not set
# CONFIG_ARCH_DAVINCI is not set
# CONFIG_KIRKWOOD is not set
# CONFIG_ARCH_MVEBU is not set
# CONFIG_TARGET_DEVKIT3250 is not set
# CONFIG_TARGET_WORK_92105 is not set
# CONFIG_TARGET_MX25PDK is not set
# CONFIG_TARGET_ZMX25 is not set
# CONFIG_TARGET_APF27 is not set
# CONFIG_TARGET_APX4DEVKIT is not set
# CONFIG_TARGET_XFI3 is not set
# CONFIG_TARGET_M28EVK is not set
# CONFIG_TARGET_MX23EVK is not set
# CONFIG_TARGET_MX28EVK is not set
# CONFIG_TARGET_MX23_OLINUXINO is not set
# CONFIG_TARGET_BG0900 is not set
# CONFIG_TARGET_SANSA_FUZE_PLUS is not set
# CONFIG_TARGET_SC_SPS_1 is not set
# CONFIG_ORION5X is not set
# CONFIG_TARGET_SPEAR300 is not set
# CONFIG_TARGET_SPEAR310 is not set
# CONFIG_TARGET_SPEAR320 is not set
# CONFIG_TARGET_SPEAR600 is not set
# CONFIG_TARGET_STV0991 is not set
# CONFIG_TARGET_X600 is not set
# CONFIG_TARGET_IMX31_PHYCORE is not set
# CONFIG_TARGET_IMX31_PHYCORE_EET is not set
# CONFIG_TARGET_MX31ADS is not set
# CONFIG_TARGET_MX31PDK is not set
# CONFIG_TARGET_WOODBURN is not set
# CONFIG_TARGET_WOODBURN_SD is not set
# CONFIG_TARGET_FLEA3 is not set
# CONFIG_TARGET_MX35PDK is not set
# CONFIG_ARCH_BCM283X is not set
# CONFIG_TARGET_VEXPRESS_CA15_TC2 is not set
# CONFIG_TARGET_VEXPRESS_CA5X2 is not set
# CONFIG_TARGET_VEXPRESS_CA9X4 is not set
# CONFIG_TARGET_BCM23550_W1D is not set
# CONFIG_TARGET_BCM28155_AP is not set
# CONFIG_TARGET_BCMCYGNUS is not set
# CONFIG_TARGET_BCMNSP is not set
# CONFIG_TARGET_BCMNS2 is not set
# CONFIG_ARCH_EXYNOS is not set
# CONFIG_ARCH_S5PC1XX is not set
# CONFIG_ARCH_HIGHBANK is not set
# CONFIG_ARCH_INTEGRATOR is not set
# CONFIG_ARCH_KEYSTONE is not set
# CONFIG_ARCH_OMAP2PLUS is not set
# CONFIG_ARCH_MESON is not set
# CONFIG_ARCH_MX7ULP is not set
# CONFIG_ARCH_MX7 is not set
# CONFIG_ARCH_MX6 is not set
# CONFIG_ARCH_MX5 is not set
# CONFIG_ARCH_RMOBILE is not set
# CONFIG_TARGET_S32V234EVB is not set
# CONFIG_ARCH_SNAPDRAGON is not set
# CONFIG_ARCH_SOCFPGA is not set
CONFIG_ARCH_SUNXI=y
# CONFIG_TARGET_TS4600 is not set
# CONFIG_ARCH_VF610 is not set
# CONFIG_ARCH_ZYNQ is not set
# CONFIG_ARCH_ZYNQMP is not set
# CONFIG_TEGRA is not set
# CONFIG_TARGET_VEXPRESS64_AEMV8A is not set
# CONFIG_TARGET_VEXPRESS64_BASE_FVP is not set
# CONFIG_TARGET_VEXPRESS64_BASE_FVP_DRAM is not set
# CONFIG_TARGET_VEXPRESS64_JUNO is not set
# CONFIG_TARGET_LS2080A_EMU is not set
# CONFIG_TARGET_LS2080A_SIMU is not set
# CONFIG_TARGET_LS2080AQDS is not set
# CONFIG_TARGET_LS2080ARDB is not set
# CONFIG_TARGET_LS2081ARDB is not set
# CONFIG_TARGET_HIKEY is not set
# CONFIG_TARGET_POPLAR is not set
# CONFIG_TARGET_LS1012AQDS is not set
# CONFIG_TARGET_LS1012ARDB is not set
# CONFIG_TARGET_LS1012AFRDM is not set
# CONFIG_TARGET_LS1021AQDS is not set
# CONFIG_TARGET_LS1021ATWR is not set
# CONFIG_TARGET_LS1021AIOT is not set
# CONFIG_TARGET_LS1043AQDS is not set
# CONFIG_TARGET_LS1043ARDB is not set
# CONFIG_TARGET_LS1046AQDS is not set
# CONFIG_TARGET_LS1046ARDB is not set
# CONFIG_TARGET_H2200 is not set
# CONFIG_TARGET_ZIPITZ2 is not set
# CONFIG_TARGET_COLIBRI_PXA270 is not set
# CONFIG_ARCH_UNIPHIER is not set
# CONFIG_STM32 is not set
# CONFIG_ARCH_STI is not set
# CONFIG_ARCH_ROCKCHIP is not set
# CONFIG_TARGET_THUNDERX_88XX is not set
# CONFIG_ARCH_ASPEED is not set
CONFIG_SPL_GPIO_SUPPORT=y
CONFIG_SPL_LIBCOMMON_SUPPORT=y
CONFIG_SPL_LIBGENERIC_SUPPORT=y
CONFIG_SYS_MALLOC_F_LEN=0x400
CONFIG_CONS_INDEX=1
CONFIG_SPL_MMC_SUPPORT=y
CONFIG_SPL_SERIAL_SUPPORT=y
# CONFIG_SPL_DRIVERS_MISC_SUPPORT is not set
CONFIG_SPL_LIBDISK_SUPPORT=y
# CONFIG_SPL_NAND_SUPPORT is not set
# CONFIG_SPL_SPI_FLASH_SUPPORT is not set
# CONFIG_SPL_SPI_SUPPORT is not set
# CONFIG_SPL_WATCHDOG_SUPPORT is not set
CONFIG_IDENT_STRING=" Allwinner Technology"
# CONFIG_SUNXI_HIGH_SRAM is not set
CONFIG_SUNXI_GEN_SUN4I=y
# CONFIG_MACH_SUN4I is not set
# CONFIG_MACH_SUN5I is not set
# CONFIG_MACH_SUN6I is not set
CONFIG_MACH_SUN7I=y
# CONFIG_MACH_SUN8I_A23 is not set
# CONFIG_MACH_SUN8I_A33 is not set
# CONFIG_MACH_SUN8I_A83T is not set
# CONFIG_MACH_SUN8I_H3 is not set
# CONFIG_MACH_SUN8I_R40 is not set
# CONFIG_MACH_SUN8I_V3S is not set
# CONFIG_MACH_SUN9I is not set
# CONFIG_MACH_SUN50I is not set
# CONFIG_MACH_SUN50I_H5 is not set
# CONFIG_RESERVE_ALLWINNER_BOOT0_HEADER is not set
CONFIG_DRAM_CLK=432
CONFIG_DRAM_MBUS_CLK=300
CONFIG_DRAM_ZQ=127
# CONFIG_DRAM_ODT_EN is not set
CONFIG_DRAM_EMR1=4
CONFIG_DRAM_TPR3=0
CONFIG_DRAM_DQS_GATING_DELAY=0
CONFIG_DRAM_TIMINGS_VENDOR_MAGIC=y
# CONFIG_DRAM_TIMINGS_DDR3_1066F_1333H is not set
# CONFIG_DRAM_TIMINGS_DDR3_800E_1066G_1333J is not set
CONFIG_SYS_CLK_FREQ=912000000
# CONFIG_UART0_PORT_F is not set
# CONFIG_OLD_SUNXI_KERNEL_COMPAT is not set
CONFIG_MACPWR="PH23"
CONFIG_MMC0_CD_PIN=""
CONFIG_MMC1_CD_PIN=""
CONFIG_MMC2_CD_PIN=""
CONFIG_MMC3_CD_PIN=""
CONFIG_MMC1_PINS=""
CONFIG_MMC2_PINS=""
CONFIG_MMC3_PINS=""
CONFIG_MMC_SUNXI_SLOT_EXTRA=-1
CONFIG_INITIAL_USB_SCAN_DELAY=0
CONFIG_USB0_VBUS_PIN=""
CONFIG_USB0_VBUS_DET=""
CONFIG_USB0_ID_DET=""
CONFIG_USB1_VBUS_PIN="PH6"
CONFIG_USB2_VBUS_PIN="PH3"
CONFIG_USB3_VBUS_PIN=""
CONFIG_I2C0_ENABLE=y
# CONFIG_I2C1_ENABLE is not set
# CONFIG_I2C2_ENABLE is not set
# CONFIG_I2C3_ENABLE is not set
# CONFIG_I2C4_ENABLE is not set
# CONFIG_AXP_GPIO is not set
CONFIG_VIDEO=y
CONFIG_VIDEO_HDMI=y
# CONFIG_VIDEO_VGA is not set
CONFIG_VIDEO_COMPOSITE=y
CONFIG_VIDEO_LCD_MODE=""
CONFIG_VIDEO_LCD_DCLK_PHASE=1
CONFIG_VIDEO_LCD_POWER=""
CONFIG_VIDEO_LCD_RESET=""
CONFIG_VIDEO_LCD_BL_EN=""
CONFIG_VIDEO_LCD_BL_PWM=""
CONFIG_VIDEO_LCD_BL_PWM_ACTIVE_LOW=y
# CONFIG_VIDEO_LCD_PANEL_I2C is not set
CONFIG_VIDEO_LCD_IF_PARALLEL=y
# CONFIG_SUNXI_DE2 is not set
CONFIG_VIDEO_LCD_PANEL_PARALLEL=y
# CONFIG_VIDEO_LCD_PANEL_LVDS is not set
# CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828 is not set
# CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804 is not set
# CONFIG_VIDEO_LCD_PANEL_HITACHI_TX18D42VM is not set
# CONFIG_VIDEO_LCD_TL059WV5C0 is not set
CONFIG_SATAPWR=""
CONFIG_GMAC_TX_DELAY=3
CONFIG_SPL_STACK_R_ADDR=0x4fe00000
# CONFIG_SPL_FAT_SUPPORT is not set
CONFIG_CPU_V7_HAS_NONSEC=y
CONFIG_CPU_V7_HAS_VIRT=y
CONFIG_ARCH_SUPPORT_PSCI=y
CONFIG_ARMV7_NONSEC=y
# CONFIG_ARMV7_BOOT_SEC_DEFAULT is not set
CONFIG_ARMV7_VIRT=y
CONFIG_ARMV7_PSCI=y
CONFIG_ARMV7_PSCI_NR_CPUS=4
# CONFIG_ARMV7_LPAE is not set
# CONFIG_CMD_DEKBLOB is not set
# CONFIG_CMD_HDMIDETECT is not set

#
# ARM debug
#
# CONFIG_DEBUG_LL is not set
CONFIG_DEFAULT_DEVICE_TREE="sun7i-a20-bananapi"
CONFIG_SMBIOS_PRODUCT_NAME="sunxi"
# CONFIG_DEBUG_UART is not set
CONFIG_AHCI=y

#
# General setup
#
CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_DISTRO_DEFAULTS=y
CONFIG_SYS_MALLOC_F=y
CONFIG_SPL_SYS_MALLOC_F_LEN=0x400
CONFIG_EXPERT=y
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
# CONFIG_TOOLS_DEBUG is not set
# CONFIG_PHYS_64BIT is not set

#
# Boot images
#
# CONFIG_FIT is not set
CONFIG_OF_BOARD_SETUP=y
# CONFIG_OF_SYSTEM_SETUP is not set
# CONFIG_OF_STDOUT_VIA_ALIAS is not set
CONFIG_SYS_EXTRA_OPTIONS=""
CONFIG_ARCH_FIXUP_FDT_MEMORY=y

#
# API
#
# CONFIG_API is not set

#
# Boot timing
#
# CONFIG_BOOTSTAGE is not set
CONFIG_BOOTSTAGE_USER_COUNT=20
CONFIG_BOOTSTAGE_RECORD_COUNT=30
CONFIG_BOOTSTAGE_STASH_ADDR=0
CONFIG_BOOTSTAGE_STASH_SIZE=0x1000

#
# Boot media
#
# CONFIG_NAND_BOOT is not set
# CONFIG_ONENAND_BOOT is not set
# CONFIG_QSPI_BOOT is not set
# CONFIG_SATA_BOOT is not set
# CONFIG_SD_BOOT is not set
# CONFIG_SPI_BOOT is not set

#
# Environment
#
# CONFIG_ENV_IS_IN_DATAFLASH is not set
# CONFIG_ENV_IS_IN_EEPROM is not set
# CONFIG_ENV_IS_IN_FAT is not set
# CONFIG_ENV_IS_IN_FLASH is not set
CONFIG_ENV_IS_IN_MMC=y
# CONFIG_ENV_IS_IN_NAND is not set
# CONFIG_ENV_IS_IN_NVRAM is not set
# CONFIG_ENV_IS_IN_ONENAND is not set
# CONFIG_ENV_IS_IN_REMOTE is not set
# CONFIG_ENV_IS_IN_SPI_FLASH is not set
# CONFIG_ENV_IS_IN_UBI is not set
# CONFIG_ENV_IS_NOWHERE is not set
CONFIG_ENV_OFFSET=0x88000
CONFIG_ENV_SIZE=0x20000
CONFIG_BOOTDELAY=2

#
# Console
#
CONFIG_MENU=y
# CONFIG_CONSOLE_RECORD is not set
# CONFIG_SILENT_CONSOLE is not set
CONFIG_PRE_CONSOLE_BUFFER=y
CONFIG_PRE_CON_BUF_SZ=4096
CONFIG_PRE_CON_BUF_ADDR=0x4f000000
CONFIG_CONSOLE_MUX=y
CONFIG_SYS_CONSOLE_IS_IN_ENV=y
# CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE is not set
# CONFIG_SYS_CONSOLE_ENV_OVERWRITE is not set
# CONFIG_SYS_CONSOLE_INFO_QUIET is not set
CONFIG_SYS_STDIO_DEREGISTER=y
# CONFIG_FIT_EMBED is not set
CONFIG_DEFAULT_FDT_FILE=""
# CONFIG_VERSION_VARIABLE is not set
CONFIG_DISPLAY_CPUINFO=y
CONFIG_DISPLAY_BOARDINFO=y

#
# Start-up hooks
#
# CONFIG_ARCH_EARLY_INIT_R is not set
# CONFIG_ARCH_MISC_INIT is not set
# CONFIG_BOARD_EARLY_INIT_F is not set

#
# Security support
#
CONFIG_HASH=y

#
# SPL / TPL
#
CONFIG_SUPPORT_SPL=y
CONFIG_SPL=y
# CONFIG_SPL_BOARD_INIT is not set
CONFIG_SPL_RAW_IMAGE_SUPPORT=y
CONFIG_SPL_LEGACY_IMAGE_SUPPORT=y
CONFIG_SPL_SYS_MALLOC_SIMPLE=y
CONFIG_SPL_STACK_R=y
CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN=0x100000
# CONFIG_SPL_SEPARATE_BSS is not set
# CONFIG_SPL_DISPLAY_PRINT is not set
CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR=y
CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x50
# CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION is not set
# CONFIG_SPL_CPU_SUPPORT is not set
# CONFIG_SPL_CRYPTO_SUPPORT is not set
# CONFIG_SPL_HASH_SUPPORT is not set
# CONFIG_SPL_DMA_SUPPORT is not set
# CONFIG_SPL_ENV_SUPPORT is not set
# CONFIG_SPL_EXT_SUPPORT is not set
# CONFIG_SPL_FPGA_SUPPORT is not set
CONFIG_SPL_I2C_SUPPORT=y
# CONFIG_SPL_MPC8XXX_INIT_DDR_SUPPORT is not set
# CONFIG_SPL_MTD_SUPPORT is not set
# CONFIG_SPL_MUSB_NEW_SUPPORT is not set
# CONFIG_SPL_NET_SUPPORT is not set
# CONFIG_SPL_NO_CPU_SUPPORT is not set
# CONFIG_SPL_NOR_SUPPORT is not set
# CONFIG_SPL_XIP_SUPPORT is not set
# CONFIG_SPL_ONENAND_SUPPORT is not set
# CONFIG_SPL_OS_BOOT is not set
# CONFIG_SPL_PCI_SUPPORT is not set
# CONFIG_SPL_PCH_SUPPORT is not set
# CONFIG_SPL_POST_MEM_SUPPORT is not set
CONFIG_SPL_POWER_SUPPORT=y
# CONFIG_SPL_RAM_SUPPORT is not set
# CONFIG_SPL_RTC_SUPPORT is not set
# CONFIG_SPL_SATA_SUPPORT is not set
# CONFIG_SPL_TIMER_SUPPORT is not set
# CONFIG_SPL_USB_HOST_SUPPORT is not set
# CONFIG_SPL_USB_GADGET_SUPPORT is not set
# CONFIG_SPL_YMODEM_SUPPORT is not set

#
# Command line interface
#
CONFIG_CMDLINE=y
CONFIG_HUSH_PARSER=y
CONFIG_SYS_PROMPT="=> "

#
# Autoboot options
#
CONFIG_AUTOBOOT=y
# CONFIG_AUTOBOOT_KEYED is not set

#
# FASTBOOT
#
# CONFIG_FASTBOOT is not set

#
# Commands
#

#
# Info commands
#
CONFIG_CMD_BDI=y
# CONFIG_CMD_CONFIG is not set
CONFIG_CMD_CONSOLE=y
# CONFIG_CMD_CPU is not set
# CONFIG_CMD_LICENSE is not set

#
# Boot commands
#
CONFIG_CMD_BOOTD=y
CONFIG_CMD_BOOTM=y
CONFIG_CMD_BOOTZ=y
CONFIG_CMD_BOOTEFI=y
CONFIG_CMD_BOOTEFI_HELLO_COMPILE=y
# CONFIG_CMD_BOOTEFI_HELLO is not set
# CONFIG_CMD_BOOTMENU is not set
CONFIG_CMD_ELF=y
CONFIG_CMD_FDT=y
CONFIG_CMD_GO=y
CONFIG_CMD_RUN=y
CONFIG_CMD_IMI=y
# CONFIG_CMD_IMLS is not set
CONFIG_CMD_XIMG=y
CONFIG_CMD_POWEROFF=y

#
# Environment commands
#
# CONFIG_CMD_ASKENV is not set
CONFIG_CMD_EXPORTENV=y
CONFIG_CMD_IMPORTENV=y
CONFIG_CMD_EDITENV=y
# CONFIG_CMD_GREPENV is not set
CONFIG_CMD_SAVEENV=y
CONFIG_CMD_ENV_EXISTS=y
# CONFIG_CMD_ENV_CALLBACK is not set
# CONFIG_CMD_ENV_FLAGS is not set

#
# Memory commands
#
CONFIG_CMD_MEMORY=y
CONFIG_CMD_CRC32=y
# CONFIG_CRC32_VERIFY is not set
# CONFIG_CMD_EEPROM is not set
# CONFIG_CMD_MD5SUM is not set
# CONFIG_CMD_SHA1SUM is not set
# CONFIG_LOOPW is not set
# CONFIG_CMD_MEMTEST is not set
# CONFIG_CMD_MX_CYCLIC is not set
# CONFIG_CMD_MEMINFO is not set

#
# Compression commands
#
# CONFIG_CMD_LZMADEC is not set
# CONFIG_CMD_UNZIP is not set
# CONFIG_CMD_ZIP is not set

#
# Device access commands
#
# CONFIG_CMD_CLK is not set
CONFIG_CMD_DM=y
# CONFIG_CMD_DEMO is not set
# CONFIG_CMD_IDE is not set
# CONFIG_CMD_IO is not set
# CONFIG_CMD_IOTRACE is not set
CONFIG_CMD_LOADB=y
CONFIG_CMD_LOADS=y
# CONFIG_CMD_FLASH is not set
# CONFIG_CMD_GPT is not set
# CONFIG_CMD_ARMFLASH is not set
CONFIG_CMD_MMC=y
# CONFIG_CMD_NAND is not set
CONFIG_CMD_PART=y
# CONFIG_CMD_SF is not set
# CONFIG_CMD_SPI is not set
CONFIG_CMD_I2C=y
CONFIG_CMD_USB=y
# CONFIG_CMD_DFU is not set
# CONFIG_CMD_USB_MASS_STORAGE is not set
# CONFIG_CMD_FPGA is not set
# CONFIG_CMD_FPGAD is not set
# CONFIG_CMD_FUSE is not set
CONFIG_CMD_GPIO=y
# CONFIG_CMD_FDC is not set
# CONFIG_CMD_SATA is not set

#
# Shell scripting commands
#
CONFIG_CMD_ECHO=y
CONFIG_CMD_ITEST=y
CONFIG_CMD_SOURCE=y
CONFIG_CMD_SETEXPR=y

#
# Network commands
#
CONFIG_CMD_NET=y
# CONFIG_CMD_TFTPPUT is not set
# CONFIG_CMD_TFTPSRV is not set
# CONFIG_CMD_RARP is not set
CONFIG_CMD_DHCP=y
CONFIG_CMD_PXE=y
CONFIG_CMD_NFS=y
CONFIG_CMD_MII=y
CONFIG_CMD_PING=y
# CONFIG_CMD_CDP is not set
# CONFIG_CMD_SNTP is not set
# CONFIG_CMD_DNS is not set
# CONFIG_CMD_LINK_LOCAL is not set
# CONFIG_CMD_ETHSW is not set

#
# Misc commands
#
# CONFIG_CMD_BMP is not set
# CONFIG_CMD_BSP is not set
# CONFIG_CMD_BKOPS_ENABLE is not set
# CONFIG_CMD_CACHE is not set
# CONFIG_CMD_DISPLAY is not set
# CONFIG_CMD_LED is not set
# CONFIG_CMD_DATE is not set
# CONFIG_CMD_TIME is not set
# CONFIG_CMD_GETTIME is not set
CONFIG_CMD_MISC=y
# CONFIG_CMD_TIMER is not set
# CONFIG_CMD_QFW is not set

#
# Power commands
#

#
# Security commands
#
# CONFIG_CMD_AES is not set
# CONFIG_CMD_BLOB is not set
# CONFIG_CMD_HASH is not set

#
# Firmware commands
#

#
# Filesystem commands
#
CONFIG_CMD_EXT2=y
CONFIG_CMD_EXT4=y
# CONFIG_CMD_EXT4_WRITE is not set
CONFIG_CMD_FAT=y
CONFIG_CMD_FS_GENERIC=y
# CONFIG_CMD_FS_UUID is not set
# CONFIG_CMD_JFFS2 is not set
# CONFIG_CMD_MTDPARTS is not set

#
# Debug commands
#
# CONFIG_CMD_BEDBUG is not set
# CONFIG_CMD_DIAG is not set
# CONFIG_CMD_KGDB is not set
# CONFIG_CMD_UBI is not set

#
# Partition Types
#
CONFIG_PARTITIONS=y
# CONFIG_MAC_PARTITION is not set
# CONFIG_SPL_MAC_PARTITION is not set
CONFIG_DOS_PARTITION=y
# CONFIG_SPL_DOS_PARTITION is not set
CONFIG_ISO_PARTITION=y
# CONFIG_SPL_ISO_PARTITION is not set
# CONFIG_AMIGA_PARTITION is not set
# CONFIG_SPL_AMIGA_PARTITION is not set
CONFIG_EFI_PARTITION=y
CONFIG_EFI_PARTITION_ENTRIES_OFF=0
# CONFIG_SPL_EFI_PARTITION is not set
CONFIG_PARTITION_UUIDS=y
# CONFIG_SPL_PARTITION_UUIDS is not set
# CONFIG_PARTITION_TYPE_GUID is not set
CONFIG_SUPPORT_OF_CONTROL=y

#
# Device Tree Control
#
CONFIG_OF_CONTROL=y
# CONFIG_OF_BOARD_FIXUP is not set
# CONFIG_SPL_OF_CONTROL is not set
# CONFIG_OF_LIVE is not set
CONFIG_OF_SEPARATE=y
# CONFIG_OF_EMBED is not set
# CONFIG_OF_BOARD is not set
CONFIG_NET=y
# CONFIG_NET_RANDOM_ETHADDR is not set
CONFIG_NETCONSOLE=y
CONFIG_NET_TFTP_VARS=y
CONFIG_BOOTP_PXE_CLIENTARCH=0x15
CONFIG_BOOTP_VCI_STRING="U-Boot.armv7"

#
# Device Drivers
#

#
# Generic Driver Options
#
CONFIG_DM=y
# CONFIG_SPL_DM is not set
CONFIG_DM_WARN=y
CONFIG_DM_DEVICE_REMOVE=y
CONFIG_DM_STDIO=y
CONFIG_DM_SEQ_ALIAS=y
# CONFIG_SPL_DM_SEQ_ALIAS is not set
# CONFIG_REGMAP is not set
# CONFIG_SPL_REGMAP is not set
# CONFIG_DEVRES is not set
CONFIG_SIMPLE_BUS=y
CONFIG_OF_TRANSLATE=y
CONFIG_DM_DEV_READ_INLINE=y
# CONFIG_ADC is not set
# CONFIG_ADC_EXYNOS is not set
# CONFIG_ADC_SANDBOX is not set
# CONFIG_SATA is not set
CONFIG_SCSI=y

#
# SATA/SCSI device support
#
# CONFIG_BLK is not set
# CONFIG_BLOCK_CACHE is not set
# CONFIG_IDE is not set

#
# Clock
#
# CONFIG_CLK is not set
# CONFIG_CPU is not set

#
# Hardware crypto devices
#
# CONFIG_FSL_CAAM is not set
# CONFIG_SYS_FSL_SEC_BE is not set
# CONFIG_SYS_FSL_SEC_LE is not set

#
# Demo for driver model
#
# CONFIG_DM_DEMO is not set

#
# DFU support
#

#
# DMA Support
#
# CONFIG_DMA is not set
# CONFIG_TI_EDMA3 is not set

#
# FPGA support
#
# CONFIG_FPGA_ALTERA is not set
# CONFIG_FPGA_SOCFPGA is not set
# CONFIG_FPGA_XILINX is not set

#
# GPIO Support
#
CONFIG_DM_GPIO=y
# CONFIG_ALTERA_PIO is not set
# CONFIG_DWAPB_GPIO is not set
# CONFIG_AT91_GPIO is not set
# CONFIG_ATMEL_PIO4 is not set
# CONFIG_INTEL_BROADWELL_GPIO is not set
# CONFIG_IMX_RGPIO2P is not set
# CONFIG_LPC32XX_GPIO is not set
# CONFIG_MSM_GPIO is not set
# CONFIG_ROCKCHIP_GPIO is not set
# CONFIG_TEGRA_GPIO is not set
# CONFIG_TEGRA186_GPIO is not set
# CONFIG_VYBRID_GPIO is not set
# CONFIG_DM_74X164 is not set
# CONFIG_DM_PCA953X is not set
# CONFIG_MPC85XX_GPIO is not set

#
# I2C support
#
# CONFIG_DM_I2C is not set
# CONFIG_DM_I2C_COMPAT is not set
# CONFIG_SYS_I2C_DW is not set
# CONFIG_SYS_I2C_IMX_LPI2C is not set
CONFIG_DM_KEYBOARD=y
# CONFIG_CROS_EC_KEYB is not set
# CONFIG_I8042_KEYB is not set

#
# LED Support
#
# CONFIG_LED is not set
# CONFIG_LED_STATUS is not set

#
# Mailbox Controller Support
#
# CONFIG_DM_MAILBOX is not set

#
# Memory Controller drivers
#

#
# Multifunction device drivers
#
# CONFIG_MISC is not set
# CONFIG_CROS_EC is not set
# CONFIG_DS4510 is not set
# CONFIG_FSL_SEC_MON is not set
# CONFIG_MXC_OCOTP is not set
# CONFIG_NUVOTON_NCT6102D is not set
# CONFIG_PWRSEQ is not set
# CONFIG_PCA9551_LED is not set
# CONFIG_WINBOND_W83627 is not set

#
# MMC Host controller Support
#
CONFIG_MMC=y
# CONFIG_DM_MMC is not set
# CONFIG_SPL_MMC_TINY is not set
# CONFIG_MMC_DW is not set
# CONFIG_MMC_MXC is not set
# CONFIG_MMC_MXS is not set
# CONFIG_MMC_PCI is not set
# CONFIG_MMC_OMAP_HS is not set
# CONFIG_MMC_SDHCI is not set
CONFIG_MMC_SUNXI=y

#
# MTD Support
#
# CONFIG_MTD is not set
# CONFIG_MTD_NOR_FLASH is not set

#
# NAND Device Support
#
# CONFIG_NAND_DENALI is not set
# CONFIG_NAND_VF610_NFC is not set
# CONFIG_NAND_PXA3XX is not set
# CONFIG_NAND_SUNXI is not set
# CONFIG_NAND_ARASAN is not set
# CONFIG_NAND_ZYNQ is not set

#
# Generic NAND options
#
# CONFIG_SYS_NAND_U_BOOT_LOCATIONS is not set
# CONFIG_SPL_NAND_DENALI is not set

#
# SPI Flash Support
#
# CONFIG_SPI_FLASH is not set
# CONFIG_SPL_SPI_SUNXI is not set

#
# UBI support
#
# CONFIG_MTD_UBI is not set
# CONFIG_BITBANGMII is not set
# CONFIG_MV88E6352_SWITCH is not set
CONFIG_PHYLIB=y
# CONFIG_MV88E61XX_SWITCH is not set
# CONFIG_PHYLIB_10G is not set
# CONFIG_PHY_AQUANTIA is not set
# CONFIG_PHY_ATHEROS is not set
# CONFIG_PHY_BROADCOM is not set
# CONFIG_PHY_CORTINA is not set
# CONFIG_PHY_DAVICOM is not set
# CONFIG_PHY_ET1011C is not set
# CONFIG_PHY_LXT is not set
# CONFIG_PHY_MARVELL is not set
# CONFIG_PHY_MICREL is not set
# CONFIG_PHY_MSCC is not set
# CONFIG_PHY_NATSEMI is not set
# CONFIG_PHY_REALTEK is not set
# CONFIG_PHY_SMSC is not set
# CONFIG_PHY_TERANETICS is not set
# CONFIG_PHY_TI is not set
# CONFIG_PHY_VITESSE is not set
# CONFIG_PHY_XILINX is not set
# CONFIG_PHY_FIXED is not set
CONFIG_DM_ETH=y
CONFIG_NETDEVICES=y
# CONFIG_PHY_GIGE is not set
# CONFIG_ALTERA_TSE is not set
# CONFIG_DWC_ETH_QOS is not set
# CONFIG_E1000 is not set
CONFIG_ETH_DESIGNWARE=y
# CONFIG_ETHOC is not set
# CONFIG_FTMAC100 is not set
# CONFIG_MACB is not set
CONFIG_RGMII=y
# CONFIG_RTL8139 is not set
# CONFIG_RTL8169 is not set
CONFIG_SUN7I_GMAC=y
# CONFIG_SUN4I_EMAC is not set
# CONFIG_SUN8I_EMAC is not set
# CONFIG_GMAC_ROCKCHIP is not set
# CONFIG_PCI is not set

#
# PHY Subsystem
#
# CONFIG_PHY is not set
# CONFIG_SPL_PHY is not set
# CONFIG_MVEBU_COMPHY_SUPPORT is not set

#
# Pin controllers
#
# CONFIG_PINCTRL is not set

#
# Power
#

#
# Power Domain Support
#
# CONFIG_POWER_DOMAIN is not set
# CONFIG_DM_PMIC is not set
# CONFIG_PMIC_AS3722 is not set
# CONFIG_POWER_MC34VR500 is not set
# CONFIG_DM_REGULATOR is not set
# CONFIG_SUNXI_NO_PMIC is not set
CONFIG_AXP209_POWER=y
CONFIG_AXP_DCDC2_VOLT=1400
CONFIG_AXP_DCDC3_VOLT=1250
CONFIG_AXP_ALDO2_VOLT=3000
CONFIG_AXP_ALDO3_VOLT=0
CONFIG_AXP_ALDO4_VOLT=0
# CONFIG_DM_PWM is not set
# CONFIG_PWM_SANDBOX is not set
# CONFIG_RAM is not set

#
# Remote Processor drivers
#

#
# Reset Controller Support
#
# CONFIG_DM_RESET is not set

#
# Real Time Clock
#
# CONFIG_DM_RTC is not set

#
# Serial drivers
#
CONFIG_BAUDRATE=115200
CONFIG_REQUIRE_SERIAL_CONSOLE=y
CONFIG_SERIAL_PRESENT=y
CONFIG_SPL_SERIAL_PRESENT=y
CONFIG_DM_SERIAL=y
# CONFIG_SERIAL_IRQ_BUFFER is not set
CONFIG_SPL_DM_SERIAL=y
# CONFIG_TPL_DM_SERIAL is not set
# CONFIG_DEBUG_UART_SKIP_INIT is not set
# CONFIG_ALTERA_JTAG_UART is not set
# CONFIG_ALTERA_UART is not set
# CONFIG_ATMEL_USART is not set
# CONFIG_FSL_LPUART is not set
# CONFIG_MVEBU_A3700_UART is not set
CONFIG_SYS_NS16550=y
# CONFIG_MSM_SERIAL is not set
# CONFIG_PXA_SERIAL is not set

#
# Sound support
#
# CONFIG_SOUND is not set

#
# SPI Support
#
# CONFIG_DM_SPI is not set
# CONFIG_SOFT_SPI is not set
# CONFIG_FSL_ESPI is not set
# CONFIG_FSL_QSPI is not set
# CONFIG_TI_QSPI is not set

#
# SPMI support
#
# CONFIG_SPMI is not set

#
# System reset device drivers
#
# CONFIG_SYSRESET is not set
# CONFIG_SYSRESET_SYSCON is not set
# CONFIG_SYSRESET_WATCHDOG is not set
# CONFIG_DM_THERMAL is not set

#
# Timer Support
#
# CONFIG_TIMER is not set

#
# TPM support
#
CONFIG_USB=y
CONFIG_DM_USB=y

#
# USB Host Controller Drivers
#
CONFIG_USB_HOST=y
# CONFIG_USB_XHCI_HCD is not set
CONFIG_USB_EHCI_HCD=y
# CONFIG_USB_EHCI_MSM is not set
# CONFIG_USB_EHCI_GENERIC is not set
# CONFIG_USB_OHCI_HCD is not set
# CONFIG_USB_UHCI_HCD is not set
# CONFIG_USB_DWC2 is not set

#
# MUSB Controller Driver
#
# CONFIG_USB_MUSB_HOST is not set
# CONFIG_USB_MUSB_GADGET is not set
# CONFIG_USB_MUSB_TI is not set

#
# ULPI drivers
#

#
# USB peripherals
#
CONFIG_USB_STORAGE=y
CONFIG_USB_KEYBOARD=y
# CONFIG_USB_GADGET is not set

#
# Graphics support
#
# CONFIG_DM_VIDEO is not set
# CONFIG_SYS_WHITE_ON_BLACK is not set

#
# TrueType Fonts
#
# CONFIG_VIDEO_VESA is not set
# CONFIG_VIDEO_LCD_ANX9804 is not set
# CONFIG_VIDEO_LCD_SSD2828 is not set
# CONFIG_VIDEO_LCD_HITACHI_TX18D42VM is not set
# CONFIG_VIDEO_MVEBU is not set
# CONFIG_DISPLAY is not set
# CONFIG_VIDEO_FSL_DCU_FB is not set
# CONFIG_VIDEO_TEGRA20 is not set
# CONFIG_VIDEO_BRIDGE is not set
CONFIG_CFB_CONSOLE=y
# CONFIG_CFB_CONSOLE_ANSI is not set
CONFIG_VGA_AS_SINGLE_DEVICE=y
CONFIG_VIDEO_SW_CURSOR=y
# CONFIG_CONSOLE_EXTRA_INFO is not set
CONFIG_CONSOLE_SCROLL_LINES=1
# CONFIG_VIDEO_CT69000 is not set
CONFIG_SYS_CONSOLE_BG_COL=0x00
CONFIG_SYS_CONSOLE_FG_COL=0xa0
# CONFIG_LCD is not set

#
# Watchdog Timer Support
#
# CONFIG_BCM2835_WDT is not set
# CONFIG_ULP_WATCHDOG is not set
# CONFIG_WDT is not set
# CONFIG_PHYS_TO_BUS is not set

#
# File systems
#
# CONFIG_FS_CBFS is not set
CONFIG_FS_FAT=y
CONFIG_FAT_WRITE=y
CONFIG_FS_FAT_MAX_CLUSTSIZE=65536
# CONFIG_FS_JFFS2 is not set
# CONFIG_FS_CRAMFS is not set

#
# Library routines
#
# CONFIG_CC_OPTIMIZE_LIBS_FOR_SPEED is not set
CONFIG_HAVE_PRIVATE_LIBGCC=y
CONFIG_USE_PRIVATE_LIBGCC=y
CONFIG_SYS_HZ=1000
CONFIG_USE_TINY_PRINTF=y
CONFIG_REGEX=y
# CONFIG_LIB_RAND is not set
# CONFIG_SPL_TINY_MEMSET is not set
# CONFIG_CMD_DHRYSTONE is not set

#
# Security support
#
# CONFIG_AES is not set
# CONFIG_RSA is not set
# CONFIG_TPM is not set

#
# Hashing Support
#
# CONFIG_SHA1 is not set
# CONFIG_SHA256 is not set
# CONFIG_SHA_HW_ACCEL is not set

#
# Compression Support
#
# CONFIG_LZ4 is not set
# CONFIG_LZMA is not set
# CONFIG_LZO is not set
# CONFIG_ERRNO_STR is not set
CONFIG_OF_LIBFDT=y
# CONFIG_OF_LIBFDT_OVERLAY is not set
# CONFIG_SPL_OF_LIBFDT is not set
# CONFIG_FDT_FIXUP_PARTITIONS is not set

#
# System tables
#
CONFIG_GENERATE_SMBIOS_TABLE=y
CONFIG_SMBIOS_MANUFACTURER=""
CONFIG_EFI_LOADER=y
# CONFIG_UNIT_TEST is not set

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-06 18:21                               ` Mark Kettenis
@ 2017-08-06 18:37                                 ` Mark Kettenis
  2017-08-06 18:47                                   ` Rob Clark
  2017-08-06 18:41                                 ` Rob Clark
  1 sibling, 1 reply; 116+ messages in thread
From: Mark Kettenis @ 2017-08-06 18:37 UTC (permalink / raw)
  To: u-boot

> Date: Sun, 6 Aug 2017 20:21:45 +0200 (CEST)
> From: Mark Kettenis <mark.kettenis@xs4all.nl>
> 
> > Mind sending me or pastebin'ing your u-boot .config?  There are some
> > different device-path construction depending on legacy vs
> > CONFIG_DM+CONFIG_BLK (the legacy case *looks* right to me, and is used
> > by vexpress_ca15_tc2.. so I think it should work..)
> 
> See below.  The Banana Pi (and all other sunxi boards) indeed uses the
> legacy code path.  And I think there is a bug in the legacy codepath
> where it encodes the partition in the "file" path component.

If I fix the code to not insert the partition number there, I can boot
from SD card and SATA again.

diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
index b5acf73f98..8ba0db2d7a 100644
--- a/lib/efi_loader/efi_device_path.c
+++ b/lib/efi_loader/efi_device_path.c
@@ -305,8 +305,8 @@ static void *dp_part_fill(void *buf, struct blk_desc *desc, int part)
 	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);
+	snprintf(devname, sizeof(devname), "%d.%d", desc->if_type,
+		 desc->devnum);
 
 	memcpy(buf, &ROOT, sizeof(ROOT));
 	buf += sizeof(ROOT);

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-06 18:21                               ` Mark Kettenis
  2017-08-06 18:37                                 ` Mark Kettenis
@ 2017-08-06 18:41                                 ` Rob Clark
  1 sibling, 0 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-06 18:41 UTC (permalink / raw)
  To: u-boot

On Sun, Aug 6, 2017 at 2:21 PM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>> From: Rob Clark <robdclark@gmail.com>
>> Date: Sun, 6 Aug 2017 13:49:43 -0400
>>
>> On Sun, Aug 6, 2017 at 1:28 PM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>> >> From: Rob Clark <robdclark@gmail.com>
>> >> Date: Sun, 6 Aug 2017 11:34:15 -0400
>> >>
>> >> On Sun, Aug 6, 2017 at 10:45 AM, Rob Clark <robdclark@gmail.com> wrote:
>> >> >
>> >> > I've started trying to hack up test_efi_loader.py to add a test that
>> >> > loads OpenBSD's bootloader..  kinda muddling through it at this point,
>> >> > since not a py expert or too familiar w/ u-boot's test framework.  But
>> >> > I'll see if I can get to the point where I can run the same thing on
>> >> > various arm7 and aarch64 devices in qemu.
>> >> >
>> >>
>> >> Making a bit of progress on this (running it on a vexpress_ca15_tc2
>> >> board in qemu).. any hint where I can find BOOTARM.EFI src code?
>> >
>> > https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/sys/arch/armv7/stand/efiboot/efiboot.c?rev=1.17&content-type=text/x-cvsweb-markup
>> >
>> > Your failure below looks a bit different from what I'm getting on the
>> > Banana Pi now.  There I get stuck because the 2nd BS->HandleProtocol()
>> > call in efi_main() fails.  Somehow the device path of the registered
>> > disk devices isn't matched correctly to the boot device path...
>>
>> that is.. odd.. mind adding in lib/efi_loader/Makefile:
>>
>>   ccflags-y += -DDEBUG=1
>>
>> ?
>>
>> (you can make the console output easier to read again w/ #undef DEBUG
>> at top of efi_console.c)
>>
>> With my complete patchset (ie. assuming this isn't in the middle of a
>> bisect between 13/20 and 15/20) the device paths for the diskobj and
>> EFI_LOADED_IMAGE::DeviceHandle should be constructed identically.
>> (Ie. the patchset consolidates the two different places it was
>> constructed before... and also fixes the thing I notice you work
>> around in efi_diskprobe())
>>
>> > BTW, the OpenBSD code runs fine without the alignment hack.  Our code
>> > is pretty minimal and doesn't actualy look into the device path
>> > components.  It just matches the components based on type and by soing
>> > memcmp.
>>
>> Hmm, well I do suspect there are still cases where u-boot could crash
>> because of unaligned access without the hack.  Although I'm less
>> convinced that we should need the hack on armv7 and more thinking this
>> is something specific about banana-pi (or allwinner?).  The
>> vexpress_ca15_tc2 "board" in qemu seems to be working properly..
>
> I suspect qemu simply doesn't emulate the alignment trap.  The u-boot
> startup code explicitly enables alignment fauls on armv7.  See
> arch/arm/cpu/armv7/start.S:152.  This helps catching bugs!

Hmm, that is a really bad idea with EFI_LOADER.. since the efi payload
is inheriting this setting.


BR,
-R

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-06 18:37                                 ` Mark Kettenis
@ 2017-08-06 18:47                                   ` Rob Clark
  2017-08-06 18:53                                     ` Rob Clark
  0 siblings, 1 reply; 116+ messages in thread
From: Rob Clark @ 2017-08-06 18:47 UTC (permalink / raw)
  To: u-boot

On Sun, Aug 6, 2017 at 2:37 PM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>> Date: Sun, 6 Aug 2017 20:21:45 +0200 (CEST)
>> From: Mark Kettenis <mark.kettenis@xs4all.nl>
>>
>> > Mind sending me or pastebin'ing your u-boot .config?  There are some
>> > different device-path construction depending on legacy vs
>> > CONFIG_DM+CONFIG_BLK (the legacy case *looks* right to me, and is used
>> > by vexpress_ca15_tc2.. so I think it should work..)
>>
>> See below.  The Banana Pi (and all other sunxi boards) indeed uses the
>> legacy code path.  And I think there is a bug in the legacy codepath
>> where it encodes the partition in the "file" path component.
>
> If I fix the code to not insert the partition number there, I can boot
> from SD card and SATA again.
>
> diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
> index b5acf73f98..8ba0db2d7a 100644
> --- a/lib/efi_loader/efi_device_path.c
> +++ b/lib/efi_loader/efi_device_path.c
> @@ -305,8 +305,8 @@ static void *dp_part_fill(void *buf, struct blk_desc *desc, int part)
>         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);
> +       snprintf(devname, sizeof(devname), "%d.%d", desc->if_type,
> +                desc->devnum);
>
>         memcpy(buf, &ROOT, sizeof(ROOT));
>         buf += sizeof(ROOT);


Hmm, that is probably not a good idea, since now the disk object along
w/ partition objects will have same devicepath.  (One change from
before is now we have diskobjs for the disk (part=0) and child
diskobjs for each partition.. fwiw in UEFI terminology a
efi_device_path_hard_drive_path is actually a partition.. for maximum
confusion)

Probably that we have a file-path node w/ child hard-drive objects is
confusing your previous workaround.. let me see if I can come up with
something better.

BR,
-R

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-06 18:47                                   ` Rob Clark
@ 2017-08-06 18:53                                     ` Rob Clark
  0 siblings, 0 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-06 18:53 UTC (permalink / raw)
  To: u-boot

On Sun, Aug 6, 2017 at 2:47 PM, Rob Clark <robdclark@gmail.com> wrote:
> On Sun, Aug 6, 2017 at 2:37 PM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>>> Date: Sun, 6 Aug 2017 20:21:45 +0200 (CEST)
>>> From: Mark Kettenis <mark.kettenis@xs4all.nl>
>>>
>>> > Mind sending me or pastebin'ing your u-boot .config?  There are some
>>> > different device-path construction depending on legacy vs
>>> > CONFIG_DM+CONFIG_BLK (the legacy case *looks* right to me, and is used
>>> > by vexpress_ca15_tc2.. so I think it should work..)
>>>
>>> See below.  The Banana Pi (and all other sunxi boards) indeed uses the
>>> legacy code path.  And I think there is a bug in the legacy codepath
>>> where it encodes the partition in the "file" path component.
>>
>> If I fix the code to not insert the partition number there, I can boot
>> from SD card and SATA again.
>>
>> diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
>> index b5acf73f98..8ba0db2d7a 100644
>> --- a/lib/efi_loader/efi_device_path.c
>> +++ b/lib/efi_loader/efi_device_path.c
>> @@ -305,8 +305,8 @@ static void *dp_part_fill(void *buf, struct blk_desc *desc, int part)
>>         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);
>> +       snprintf(devname, sizeof(devname), "%d.%d", desc->if_type,
>> +                desc->devnum);
>>
>>         memcpy(buf, &ROOT, sizeof(ROOT));
>>         buf += sizeof(ROOT);
>
>
> Hmm, that is probably not a good idea, since now the disk object along
> w/ partition objects will have same devicepath.  (One change from
> before is now we have diskobjs for the disk (part=0) and child
> diskobjs for each partition.. fwiw in UEFI terminology a
> efi_device_path_hard_drive_path is actually a partition.. for maximum
> confusion)

Oh, scratch that.. you are right, part shouldn't be in the string..
since it results in the children having different parent device paths.

(It is still probably a bit funny to file-paths for parent of the
partition objects.. I'll try to come up with something a bit better.)

BR,
-R

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-06 15:34                         ` Rob Clark
                                             ` (2 preceding siblings ...)
  2017-08-06 17:28                           ` Mark Kettenis
@ 2017-08-07 15:47                           ` Jonathan Gray
  2017-08-07 16:16                             ` Rob Clark
  3 siblings, 1 reply; 116+ messages in thread
From: Jonathan Gray @ 2017-08-07 15:47 UTC (permalink / raw)
  To: u-boot

On Sun, Aug 06, 2017 at 11:34:15AM -0400, Rob Clark wrote:
> On Sun, Aug 6, 2017 at 10:45 AM, Rob Clark <robdclark@gmail.com> wrote:
> >
> > I've started trying to hack up test_efi_loader.py to add a test that
> > loads OpenBSD's bootloader..  kinda muddling through it at this point,
> > since not a py expert or too familiar w/ u-boot's test framework.  But
> > I'll see if I can get to the point where I can run the same thing on
> > various arm7 and aarch64 devices in qemu.
> >
> 
> Making a bit of progress on this (running it on a vexpress_ca15_tc2
> board in qemu).. any hint where I can find BOOTARM.EFI src code?
> 
> => tftpboot 80400000 obsdboot.efi
> smc911x: MAC 52:54:00:12:34:56
> smc911x: detected LAN9118 controller
> smc911x: phy initialized
> smc911x: MAC 52:54:00:12:34:56
> Using smc911x-0 device
> TFTP from server 10.0.2.2; our IP address is 10.0.2.15
> Filename 'obsdboot.efi'.
> Load address: 0x80400000
> Loading: *%08#####
> 12.4 MiB/s
> done
> Bytes transferred = 64908 (fd8c hex)
> smc911x: MAC 52:54:00:12:34:56
> => crc32 80400000 $filesize
> CRC32 for 80400000 ... 8040fd8b ==> a9ac4fcf
> => bootefi 80400000
> ## Starting EFI application at 80400000 ...
> WARNING: Invalid device tree, expect boot to fail
> BS->LocateHandle() returns 0
> undefined instruction
> pc : [<9eec65c4>]   lr : [<9eeca390>]
> sp : 9fed7a18  ip : 0000003f fp : 9fed7a2c
> r10: 00000000  r9 : 9eed4658 r8 : 00000000
> r7 : 9eed1ce4  r6 : 9eed3538 r5 : 9fed7a6c  r4 : 9eed4658
> r3 : 00000000  r2 : 9eed2f8e r1 : 9eed1ee0  r0 : 00000000
> Flags: nZCv  IRQs off  FIQs off  Mode SVC_32
> Resetting CPU ...
> 
> resetting ...
> 
> 
> U-Boot 2017.09-rc1-00025-g534695d189 (Aug 06 2017 - 06:58:16 -0400)
> 
> DRAM:  1 GiB
> WARNING: Caches not enabled
> Flash: 128 MiB
> MMC:   MMC: 0
> *** Warning - bad CRC, using default environment
> 
> In:    serial
> Out:   serial
> Err:   serial
> Net:   smc911x-0
> Hit any key to stop autoboot:  2

Why does U-Boot not set fdt_addr_r or fdtfile for vexpress?  Worse yet
trying to load to the default kernel_addr_r fails.  So it requires a
script or manual commands to boot instead of the usual distro boot
arrangement?

There is some kind of hard hang on OpenBSD with vexpress at the moment
and there is no driver for the sd/mmc but getting to that point seemed
quite a bit more painful than using U-Boot on real hardware.

After adding vexpress-v2p-ca15-tc1.dtb to the FAT16 on miniroot-panda-61.fs:

$ qemu-system-arm -M vexpress-a15 -kernel vexpress_ca15_tc2/u-boot -nographic -sd miniroot-panda-61.fs

U-Boot 2017.09-rc1 (Aug 02 2017 - 10:55:19 +1000)

DRAM:  128 MiB
WARNING: Caches not enabled
Flash: 128 MiB
MMC:   MMC: 0
*** Warning - bad CRC, using default environment

In:    serial
Out:   serial
Err:   serial
Net:   smc911x-0
Hit any key to stop autoboot:  0 
MMC Device 1 not found
no mmc device at slot 1
switch to partitions #0, OK
mmc0 is current device
env - environment handling commands

Usage:
env default [-f] -a - [forcibly] reset default environment
env default [-f] var [...] - [forcibly] reset variable(s) to their default values
env delete [-f] var [...] - [forcibly] delete variable(s)
env export [-t | -b | -c] [-s size] addr [var ...] - export environment
env import [-d] [-t [-r] | -b | -c] addr [size] - import environment
env print [-a | name ...] - print environment
env run var [...] - run commands in an environment variable
env save - save environment
env set [-f] name [arg ...]

Scanning mmc 0:1...
Found EFI removable media binary efi/boot/bootarm.efi
reading efi/boot/bootarm.efi
64908 bytes read in 52 ms (1.2 MiB/s)
## Starting EFI application at a0008000 ...
WARNING: Invalid device tree, expect boot to fail
efi_load_pe: Invalid DOS Signature
## Application terminated, r = 2147483646
EFI LOAD FAILED: continuing...
smc911x: MAC 52:54:00:12:34:56
smc911x: detected LAN9118 controller
smc911x: phy initialized
smc911x: MAC 52:54:00:12:34:56
BOOTP broadcast 1
DHCP client bound to address 10.0.2.15 (3 ms)
*** Warning: no boot file name; using '0A00020F.img'
Using smc911x-0 device
TFTP from server 10.0.2.2; our IP address is 10.0.2.15
Filename '0A00020F.img'.
Load address: 0xa0008000
Loading: *
TFTP error: 'Access violation' (2)

...

=> setenv fdt_addr_r 0x81000000
=> setenv fdtfile vexpress-v2p-ca15-tc1.dtb
reading vexpress-v2p-ca15-tc1.dtb
13384 bytes read in 22 ms (593.8 KiB/s)
=> load mmc 0:1 ${kernel_addr_r} efi/boot/bootarm.efi
reading efi/boot/bootarm.efi
64908 bytes read in 51 ms (1.2 MiB/s)
=> bootefi ${kernel_addr_r} ${fdt_addr_r}
## Starting EFI application at a0008000 ...
efi_load_pe: Invalid DOS Signature
## Application terminated, r = 2147483646
=> printenv kernel_addr_r
kernel_addr_r=0xa0008000

=> setenv kernel_addr_r 0x82000000
=> load mmc 0:1 ${kernel_addr_r} efi/boot/bootarm.efi
reading efi/boot/bootarm.efi
64908 bytes read in 49 ms (1.3 MiB/s)
=> bootefi ${kernel_addr_r} ${fdt_addr_r}
## Starting EFI application at 82000000 ...
Scanning disks on mmc...
MMC Device 1 not found
MMC Device 2 not found
MMC Device 3 not found
Found 1 disks
>> OpenBSD/armv7 BOOTARM 0.8
boot> 
cannot open sd0a:/etc/random.seed: No such file or directory
booting sd0a:/bsd: 2265112+7989364+447000 [80+314496+149702]=0xaad1c0

OpenBSD/armv7 booting ...
arg0 0xc0dad1c0 arg1 0x8e0 arg2 0x86ed0000
Allocating page tables
freestart = 0x80dae000, free_pages = 29266 (0x00007252)
IRQ stack: p0x80ddc000 v0xc0ddc000
ABT stack: p0x80ddd000 v0xc0ddd000
UND stack: p0x80dde000 v0xc0dde000
SVC stack: p0x80ddf000 v0xc0ddf000
Creating L1 page table at 0x80db0000
Mapping kernel
Constructing L2 page tables
undefined page pmap board type: 2272
Copyright (c) 1982, 1986, 1989, 1991, 1993
        The Regents of the University of California.  All rights reserved.
Copyright (c) 1995-2017 OpenBSD. All rights reserved.  https://www.OpenBSD.org

OpenBSD 6.1-current (RAMDISK) #30: Sat Aug  5 22:01:16 MDT 2017
    deraadt at armv7.openbsd.org:/usr/src/sys/arch/armv7/compile/RAMDISK
real mem  = 134217728 (128MB)
avail mem = 117125120 (111MB)
mainbus0 at root: V2P-CA15
cpu0 at mainbus0: ARM Cortex-A15 r2p1 (ARMv7)
cpu0: DC enabled IC enabled WB disabled EABT branch prediction enabled
cpu0: 32KB(64b/l,2way) I-cache, 32KB(64b/l,2way) wr-back D-cache
cortex0 at mainbus0
ampintc0 at mainbus0 nirq 160, ncpu 1
agtimer0 at mainbus0: tick rate 62500 KHz
simplebus0 at mainbus0: "smb"
simplebus1 at simplebus0: "motherboard"
simplebus2 at simplebus1: "iofpga"
sysreg0 at simplebus2: ID 0x1190f500 PROCID0 0x14000237
pluart0 at simplebus2: console
pluart1 at simplebus2
pluart2 at simplebus2
pluart3 at simplebus2
plrtc0 at simplebus2
simplebus3 at mainbus0: "hsb"
boot device: lookup 'sd0a:/bsd' failed.
root on rd0a swap on rd0b dump on rd0b
e

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-07 15:47                           ` Jonathan Gray
@ 2017-08-07 16:16                             ` Rob Clark
  2017-08-08  1:36                               ` Jonathan Gray
  0 siblings, 1 reply; 116+ messages in thread
From: Rob Clark @ 2017-08-07 16:16 UTC (permalink / raw)
  To: u-boot

On Mon, Aug 7, 2017 at 11:47 AM, Jonathan Gray <jsg@jsg.id.au> wrote:
> On Sun, Aug 06, 2017 at 11:34:15AM -0400, Rob Clark wrote:
>> On Sun, Aug 6, 2017 at 10:45 AM, Rob Clark <robdclark@gmail.com> wrote:
>> >
>> > I've started trying to hack up test_efi_loader.py to add a test that
>> > loads OpenBSD's bootloader..  kinda muddling through it at this point,
>> > since not a py expert or too familiar w/ u-boot's test framework.  But
>> > I'll see if I can get to the point where I can run the same thing on
>> > various arm7 and aarch64 devices in qemu.
>> >
>>
>> Making a bit of progress on this (running it on a vexpress_ca15_tc2
>> board in qemu).. any hint where I can find BOOTARM.EFI src code?
>>
>> => tftpboot 80400000 obsdboot.efi
>> smc911x: MAC 52:54:00:12:34:56
>> smc911x: detected LAN9118 controller
>> smc911x: phy initialized
>> smc911x: MAC 52:54:00:12:34:56
>> Using smc911x-0 device
>> TFTP from server 10.0.2.2; our IP address is 10.0.2.15
>> Filename 'obsdboot.efi'.
>> Load address: 0x80400000
>> Loading: *%08#####
>> 12.4 MiB/s
>> done
>> Bytes transferred = 64908 (fd8c hex)
>> smc911x: MAC 52:54:00:12:34:56
>> => crc32 80400000 $filesize
>> CRC32 for 80400000 ... 8040fd8b ==> a9ac4fcf
>> => bootefi 80400000
>> ## Starting EFI application at 80400000 ...
>> WARNING: Invalid device tree, expect boot to fail
>> BS->LocateHandle() returns 0
>> undefined instruction
>> pc : [<9eec65c4>]   lr : [<9eeca390>]
>> sp : 9fed7a18  ip : 0000003f fp : 9fed7a2c
>> r10: 00000000  r9 : 9eed4658 r8 : 00000000
>> r7 : 9eed1ce4  r6 : 9eed3538 r5 : 9fed7a6c  r4 : 9eed4658
>> r3 : 00000000  r2 : 9eed2f8e r1 : 9eed1ee0  r0 : 00000000
>> Flags: nZCv  IRQs off  FIQs off  Mode SVC_32
>> Resetting CPU ...
>>
>> resetting ...
>>
>>
>> U-Boot 2017.09-rc1-00025-g534695d189 (Aug 06 2017 - 06:58:16 -0400)
>>
>> DRAM:  1 GiB
>> WARNING: Caches not enabled
>> Flash: 128 MiB
>> MMC:   MMC: 0
>> *** Warning - bad CRC, using default environment
>>
>> In:    serial
>> Out:   serial
>> Err:   serial
>> Net:   smc911x-0
>> Hit any key to stop autoboot:  2
>
> Why does U-Boot not set fdt_addr_r or fdtfile for vexpress?  Worse yet
> trying to load to the default kernel_addr_r fails.  So it requires a
> script or manual commands to boot instead of the usual distro boot
> arrangement?

I suspect this is specific to the test framework (probably not
enabling distro-boot-cmd so that the test framework can run the cmds
it wants??)

BR,
-R

> There is some kind of hard hang on OpenBSD with vexpress at the moment
> and there is no driver for the sd/mmc but getting to that point seemed
> quite a bit more painful than using U-Boot on real hardware.
>
> After adding vexpress-v2p-ca15-tc1.dtb to the FAT16 on miniroot-panda-61.fs:
>
> $ qemu-system-arm -M vexpress-a15 -kernel vexpress_ca15_tc2/u-boot -nographic -sd miniroot-panda-61.fs
>
> U-Boot 2017.09-rc1 (Aug 02 2017 - 10:55:19 +1000)
>
> DRAM:  128 MiB
> WARNING: Caches not enabled
> Flash: 128 MiB
> MMC:   MMC: 0
> *** Warning - bad CRC, using default environment
>
> In:    serial
> Out:   serial
> Err:   serial
> Net:   smc911x-0
> Hit any key to stop autoboot:  0
> MMC Device 1 not found
> no mmc device at slot 1
> switch to partitions #0, OK
> mmc0 is current device
> env - environment handling commands
>
> Usage:
> env default [-f] -a - [forcibly] reset default environment
> env default [-f] var [...] - [forcibly] reset variable(s) to their default values
> env delete [-f] var [...] - [forcibly] delete variable(s)
> env export [-t | -b | -c] [-s size] addr [var ...] - export environment
> env import [-d] [-t [-r] | -b | -c] addr [size] - import environment
> env print [-a | name ...] - print environment
> env run var [...] - run commands in an environment variable
> env save - save environment
> env set [-f] name [arg ...]
>
> Scanning mmc 0:1...
> Found EFI removable media binary efi/boot/bootarm.efi
> reading efi/boot/bootarm.efi
> 64908 bytes read in 52 ms (1.2 MiB/s)
> ## Starting EFI application at a0008000 ...
> WARNING: Invalid device tree, expect boot to fail
> efi_load_pe: Invalid DOS Signature
> ## Application terminated, r = 2147483646
> EFI LOAD FAILED: continuing...
> smc911x: MAC 52:54:00:12:34:56
> smc911x: detected LAN9118 controller
> smc911x: phy initialized
> smc911x: MAC 52:54:00:12:34:56
> BOOTP broadcast 1
> DHCP client bound to address 10.0.2.15 (3 ms)
> *** Warning: no boot file name; using '0A00020F.img'
> Using smc911x-0 device
> TFTP from server 10.0.2.2; our IP address is 10.0.2.15
> Filename '0A00020F.img'.
> Load address: 0xa0008000
> Loading: *
> TFTP error: 'Access violation' (2)
>
> ...
>
> => setenv fdt_addr_r 0x81000000
> => setenv fdtfile vexpress-v2p-ca15-tc1.dtb
> reading vexpress-v2p-ca15-tc1.dtb
> 13384 bytes read in 22 ms (593.8 KiB/s)
> => load mmc 0:1 ${kernel_addr_r} efi/boot/bootarm.efi
> reading efi/boot/bootarm.efi
> 64908 bytes read in 51 ms (1.2 MiB/s)
> => bootefi ${kernel_addr_r} ${fdt_addr_r}
> ## Starting EFI application at a0008000 ...
> efi_load_pe: Invalid DOS Signature
> ## Application terminated, r = 2147483646
> => printenv kernel_addr_r
> kernel_addr_r=0xa0008000
>
> => setenv kernel_addr_r 0x82000000
> => load mmc 0:1 ${kernel_addr_r} efi/boot/bootarm.efi
> reading efi/boot/bootarm.efi
> 64908 bytes read in 49 ms (1.3 MiB/s)
> => bootefi ${kernel_addr_r} ${fdt_addr_r}
> ## Starting EFI application at 82000000 ...
> Scanning disks on mmc...
> MMC Device 1 not found
> MMC Device 2 not found
> MMC Device 3 not found
> Found 1 disks
>>> OpenBSD/armv7 BOOTARM 0.8
> boot>
> cannot open sd0a:/etc/random.seed: No such file or directory
> booting sd0a:/bsd: 2265112+7989364+447000 [80+314496+149702]=0xaad1c0
>
> OpenBSD/armv7 booting ...
> arg0 0xc0dad1c0 arg1 0x8e0 arg2 0x86ed0000
> Allocating page tables
> freestart = 0x80dae000, free_pages = 29266 (0x00007252)
> IRQ stack: p0x80ddc000 v0xc0ddc000
> ABT stack: p0x80ddd000 v0xc0ddd000
> UND stack: p0x80dde000 v0xc0dde000
> SVC stack: p0x80ddf000 v0xc0ddf000
> Creating L1 page table at 0x80db0000
> Mapping kernel
> Constructing L2 page tables
> undefined page pmap board type: 2272
> Copyright (c) 1982, 1986, 1989, 1991, 1993
>         The Regents of the University of California.  All rights reserved.
> Copyright (c) 1995-2017 OpenBSD. All rights reserved.  https://www.OpenBSD.org
>
> OpenBSD 6.1-current (RAMDISK) #30: Sat Aug  5 22:01:16 MDT 2017
>     deraadt at armv7.openbsd.org:/usr/src/sys/arch/armv7/compile/RAMDISK
> real mem  = 134217728 (128MB)
> avail mem = 117125120 (111MB)
> mainbus0 at root: V2P-CA15
> cpu0 at mainbus0: ARM Cortex-A15 r2p1 (ARMv7)
> cpu0: DC enabled IC enabled WB disabled EABT branch prediction enabled
> cpu0: 32KB(64b/l,2way) I-cache, 32KB(64b/l,2way) wr-back D-cache
> cortex0 at mainbus0
> ampintc0 at mainbus0 nirq 160, ncpu 1
> agtimer0 at mainbus0: tick rate 62500 KHz
> simplebus0 at mainbus0: "smb"
> simplebus1 at simplebus0: "motherboard"
> simplebus2 at simplebus1: "iofpga"
> sysreg0 at simplebus2: ID 0x1190f500 PROCID0 0x14000237
> pluart0 at simplebus2: console
> pluart1 at simplebus2
> pluart2 at simplebus2
> pluart3 at simplebus2
> plrtc0 at simplebus2
> simplebus3 at mainbus0: "hsb"
> boot device: lookup 'sd0a:/bsd' failed.
> root on rd0a swap on rd0b dump on rd0b
> e

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
  2017-08-05 17:06         ` Rob Clark
  2017-08-05 18:43           ` Rob Clark
@ 2017-08-07 16:56           ` Rob Clark
  1 sibling, 0 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-07 16:56 UTC (permalink / raw)
  To: u-boot

On Sat, Aug 5, 2017 at 1:06 PM, Rob Clark <robdclark@gmail.com> wrote:
> On Sat, Aug 5, 2017 at 12:52 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>> On 08/05/2017 06:16 PM, Rob Clark wrote:
>>> On Sat, Aug 5, 2017 at 12:12 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>>>> On 08/05/2017 05:58 PM, Rob Clark wrote:
>>>>> Some arch's have trouble with unaligned accesses.  Technically
>>>>> EFI device-path structs should be byte aligned, and the next node
>>>>> in the path starts immediately after the previous.  Meaning that
>>>>> a pointer to an 'struct efi_device_path' is not necessarily word
>>>>> aligned.  See section 10.3.1 in v2.7 of UEFI spec.
>>>>>
>>>>> This causes problems not just for u-boot, but also most/all EFI
>>>>> payloads loaded by u-boot on these archs.  Fortunately the common
>>>>> practice for traversing a device path is to rely on the length
>>>>> field in the header, rather than the specified length of the
>>>>> particular device path type+subtype.  So the EFI_DP_PAD() macro
>>>>> will add the specified number of bytes to the tail of device path
>>>>> structs to pad them to word alignment.
>>>>>
>>>>> Technically this is non-compliant, BROKEN_UNALIGNED should *only*
>>>>> be defined on archs that cannot do unaligned accesses.
>>>>>
>>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>>>> ---
>>>>> I'm not sure if there are other arch's that need -DBROKEN_UNALIGNED
>>>>>
>>>>> Mark, this is untested but I think it should solve your crash on the
>>>>> Banana Pi.  Could you give it a try when you get a chance?
>>>>>
>>>>>  arch/arm/config.mk               |  2 +-
>>>>>  include/efi_api.h                | 30 ++++++++++++++++++++++++++++++
>>>>>  lib/efi_loader/efi_device_path.c |  3 +++
>>>>>  3 files changed, 34 insertions(+), 1 deletion(-)
>>>>>
>>>>> diff --git a/arch/arm/config.mk b/arch/arm/config.mk
>>>>> index 1a77779db4..067dc93a9d 100644
>>>>> --- a/arch/arm/config.mk
>>>>> +++ b/arch/arm/config.mk
>>>>> @@ -28,7 +28,7 @@ LLVMS_RELFLAGS              := $(call cc-option,-mllvm,) \
>>>>>                       $(call cc-option,-arm-use-movt=0,)
>>>>>  PLATFORM_RELFLAGS    += $(LLVM_RELFLAGS)
>>>>>
>>>>> -PLATFORM_CPPFLAGS += -D__ARM__
>>>>> +PLATFORM_CPPFLAGS += -D__ARM__ -DBROKEN_UNALIGNED
>>>>
>>>> NAK
>>>>
>>>> We have more then ARM. And other architectures also create exceptions
>>>> for unaligned access.
>>>>
>>>> I hate platform specific code. It should not be used outside /arch.
>>>>
>>>> To play it save you should not use _packed at all!
>>>> Use memcpy to transfer between aligned and unaligned memory.
>>>
>>> except for reasons I explained in the thread on the patch that added
>>> the __packed in the first place.  Sorry, this is ugly but we have to
>>> do it.
>>>
>>> BR,
>>> -R
>>
>> According to the UEFI standard the nodes in paths are not to be assumed
>> to be aligned.
>>
>> So even if you use padding bytes in paths that you pass to the EFI
>> application you should not expect that the EFI application does the
>> same. Expect the EFI application either to remove them or send new nodes
>> without padding.
>>
>> To the idea of padding bytes and __packed does not make sense.
>
> Ok, to be fair, you are right about device-paths passed too u-boot.
> On BROKEN_UNALIGNED archs, we should sanitise with a copy to an
> aligned device-path in *addition* to what I proposed.  I can make a
> patch to add a helper to do this a bit later.
>
> But the padding bytes + __packed does make total sense because it
> avoids breaking efi payloads that already exist in the field.  The
> crash that Mark saw was not in u-boot, but in openbsd's bootaa64.efi.
> (It is possibly that we just get lucky here in u-boot since I add the
> /End node after the mac address by something the compiler turns into a
> memcpy.)
>
> My proposal simply preserves the bug that we already have on
> BROKEN_UNALIGNED archs (but makes the improvement that it fixes the
> bug on aarch64 and any other arch that can do unaligned access), to
> keep existing efi payloads working.
>

Ok, so I took a closer look at the assembly generated, and I realized
that with __packed structs, gcc seems to be generating ldrb+orr's for
*all* the fields, in other words it isn't assuming alignment of the
device-path pointer.  The only potential problem right now is that we
are missing __packed on 'struct efi_device_path' itself, so
dereferencing the length field could cause unaligned access.  Adding
the missing __packed annotation turns the generated code into a pair
of ldrb's plus an orr.  I'll add the missing __packed on
efi_device_path to my patchset.

(I'm basing this on the asm generated for vexpress_ca15_tc2 build.)

That is the good news.. the bad news is this probably still ends up
being a problem in a few places w/ utf16 strings (ie.
ascii2unicode()'ing into a filepath node, or converting filenames
passed from efi payload from utf16..).. I'll have to think a bit about
how best to handle that.  But at least this is all stuff that never
worked before in the first place, so I guess we don't have to solve it
immediately.

BR,
-R

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
  2017-08-05 16:52       ` Heinrich Schuchardt
  2017-08-05 17:06         ` Rob Clark
@ 2017-08-07 17:15         ` Peter Jones
  1 sibling, 0 replies; 116+ messages in thread
From: Peter Jones @ 2017-08-07 17:15 UTC (permalink / raw)
  To: u-boot

On Sat, Aug 05, 2017 at 06:52:59PM +0200, Heinrich Schuchardt wrote:
> On 08/05/2017 06:16 PM, Rob Clark wrote:
> > On Sat, Aug 5, 2017 at 12:12 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
> >> On 08/05/2017 05:58 PM, Rob Clark wrote:
> >>> Some arch's have trouble with unaligned accesses.  Technically
> >>> EFI device-path structs should be byte aligned, and the next node
> >>> in the path starts immediately after the previous.  Meaning that
> >>> a pointer to an 'struct efi_device_path' is not necessarily word
> >>> aligned.  See section 10.3.1 in v2.7 of UEFI spec.
> >>>
> >>> This causes problems not just for u-boot, but also most/all EFI
> >>> payloads loaded by u-boot on these archs.  Fortunately the common
> >>> practice for traversing a device path is to rely on the length
> >>> field in the header, rather than the specified length of the
> >>> particular device path type+subtype.  So the EFI_DP_PAD() macro
> >>> will add the specified number of bytes to the tail of device path
> >>> structs to pad them to word alignment.
> >>>
> >>> Technically this is non-compliant, BROKEN_UNALIGNED should *only*
> >>> be defined on archs that cannot do unaligned accesses.
> >>>
> >>> Signed-off-by: Rob Clark <robdclark@gmail.com>
> >>> ---
> >>> I'm not sure if there are other arch's that need -DBROKEN_UNALIGNED
> >>>
> >>> Mark, this is untested but I think it should solve your crash on the
> >>> Banana Pi.  Could you give it a try when you get a chance?
> >>>
> >>>  arch/arm/config.mk               |  2 +-
> >>>  include/efi_api.h                | 30 ++++++++++++++++++++++++++++++
> >>>  lib/efi_loader/efi_device_path.c |  3 +++
> >>>  3 files changed, 34 insertions(+), 1 deletion(-)
> >>>
> >>> diff --git a/arch/arm/config.mk b/arch/arm/config.mk
> >>> index 1a77779db4..067dc93a9d 100644
> >>> --- a/arch/arm/config.mk
> >>> +++ b/arch/arm/config.mk
> >>> @@ -28,7 +28,7 @@ LLVMS_RELFLAGS              := $(call cc-option,-mllvm,) \
> >>>                       $(call cc-option,-arm-use-movt=0,)
> >>>  PLATFORM_RELFLAGS    += $(LLVM_RELFLAGS)
> >>>
> >>> -PLATFORM_CPPFLAGS += -D__ARM__
> >>> +PLATFORM_CPPFLAGS += -D__ARM__ -DBROKEN_UNALIGNED
> >>
> >> NAK
> >>
> >> We have more then ARM. And other architectures also create exceptions
> >> for unaligned access.
> >>
> >> I hate platform specific code. It should not be used outside /arch.
> >>
> >> To play it save you should not use _packed at all!
> >> Use memcpy to transfer between aligned and unaligned memory.
> > 
> > except for reasons I explained in the thread on the patch that added
> > the __packed in the first place.  Sorry, this is ugly but we have to
> > do it.
> > 
> > BR,
> > -R
> 
> According to the UEFI standard the nodes in paths are not to be assumed
> to be aligned.
> 
> So even if you use padding bytes in paths that you pass to the EFI
> application you should not expect that the EFI application does the
> same. Expect the EFI application either to remove them or send new nodes
> without padding.

Well, you do need it to be packed though.  We've tried in recent years
to make sure all the fields pack naturally in new device paths types,
but unfortunately some of the ones that have been in use for more than a
decade were defined poorly; in particular, Hard Drive device paths do
not pack naturally.  In Rob's patch he's got this:

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;
        EFI_DP_PAD(1);
} __packed;

If it's not packed, there's no circumstance that partition_number and
partition_start will ever both be correctly aligned.  Without the
padding (which is questionable under the spec), the next header won't
be.  That implies any code that's given this structure will have to do
fixups when checking the length, just to traverse the device path, even
when you don't do anything with the payload data.

Here's a quick test case that shows the different ways it can be packed
wrong, as well as the right way (I wrote this before looking at Rob's
definition above, but they're materially the same):

https://pjones.fedorapeople.org/efidp_packed/dp.c
https://pjones.fedorapeople.org/efidp_packed/output

There are a couple of different ways to get partition_number correct,
but only if both the header and the payload are packed does
payload.start ever get aligned correctly.

> To the idea of padding bytes and __packed does not make sense.

Padding I'm not so sure about; if everything is packed, the compiler
should generate direct accesses correctly.  So the only cases we
actually have to worry about are when a pointer to a field >u8 is passed
some place that dereferences it.

-- 
        Peter

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-04 20:41   ` Mark Kettenis
  2017-08-04 20:57     ` Rob Clark
@ 2017-08-07 17:32     ` Peter Jones
  1 sibling, 0 replies; 116+ messages in thread
From: Peter Jones @ 2017-08-07 17:32 UTC (permalink / raw)
  To: u-boot

On Fri, Aug 04, 2017 at 10:41:32PM +0200, Mark Kettenis wrote:
[...]
> ..and what you're sketching out here should work with recent enough
> versions of our bootloader.
> 
> However, to me having an ACPI Device Path component in there doesn't
> make much sense on a board without ACPI.  It certainly doesn't help
> mapping a boot path back to an actual hardware device.  Wouldn't it be
> more logical to a Hardware Device Path there instead?  In particular a
> Memory Mapped Device Path would make a lot of sense as the start
> address would make it fairly easy to do the mapping.

It was really an arbitrary choice, as Rob said.  I don't think there's
any big problem with changing it, but I'm not sure Memory Mapped is
correct.  As I read it, StartingAddress and EndingAddress in that class
should be pointing at some window into a memory map entry that is
holding the thing described /by/ the node, but there's really nothing
here.  It's just an arbitrary root node.

If we want something other than the ACPI path I made up, we should
probably just go with a Vendor Specific Device Path with a constant
well-known GUID of our choosing.  e61d73b9-a384-4acc-aeab-82e828f3628b,
say.

-- 
        Peter

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 01/20] fs: add fs_readdir()
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 01/20] fs: add fs_readdir() Rob Clark
@ 2017-08-07 18:19   ` Brüns, Stefan
  2017-08-07 19:11     ` Rob Clark
  0 siblings, 1 reply; 116+ messages in thread
From: Brüns, Stefan @ 2017-08-07 18:19 UTC (permalink / raw)
  To: u-boot

On Freitag, 4. August 2017 21:31:43 CEST Rob Clark wrote:
> 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.
> 
> For reference, the expected EFI semantics are described in (v2.7 of UEFI
> spec) in section 13.5 (page 609).  Or for convenience, see:
> 
>   http://wiki.phoenix.com/wiki/index.php/EFI_FILE_PROTOCOL#Read.28.29
> 
> The EFI level semantics are implemented in a later patch, so they are
> not too important to the understanding of this patch.
> 
> Signed-off-by: Rob Clark <robdclark@gmail.com>
> ---
>  fs/fs.c      | 25 +++++++++++++++++++++++++
>  include/fs.h | 21 +++++++++++++++++++++
>  2 files changed, 46 insertions(+)

Still, the commit message is in no way helpful when trying to understand what 
your changes are actually doing.

You introduce an arbitrary new API in the filesystem level (you neither expose 
an existing API, nor are you implementing the API requested by EFI, nor 
anything roughly resembling it).

The API you expose adds an index-based directory lookup, while EFI wants an 
POSIX-like directory stream. After reading through both the EFI spec and U-
Boots file system code, its clear you want to have some matching layer between 
the mostly stateless U-Boot filesystem layer and the stateful EFI API.

Please provide a thorough description why you create this new API in the fs 
layer, state that it is a hack to achieve what you want. If sometime later 
someone else wants to clean this up (both the FAT implementation, and the 
API), she/he should not have to go through all the code.

Regards,

Stefan

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 01/20] fs: add fs_readdir()
  2017-08-07 18:19   ` Brüns, Stefan
@ 2017-08-07 19:11     ` Rob Clark
  0 siblings, 0 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-07 19:11 UTC (permalink / raw)
  To: u-boot

On Mon, Aug 7, 2017 at 2:19 PM, Brüns, Stefan
<Stefan.Bruens@rwth-aachen.de> wrote:
> On Freitag, 4. August 2017 21:31:43 CEST Rob Clark wrote:
>> 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.
>>
>> For reference, the expected EFI semantics are described in (v2.7 of UEFI
>> spec) in section 13.5 (page 609).  Or for convenience, see:
>>
>>   http://wiki.phoenix.com/wiki/index.php/EFI_FILE_PROTOCOL#Read.28.29
>>
>> The EFI level semantics are implemented in a later patch, so they are
>> not too important to the understanding of this patch.
>>
>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>> ---
>>  fs/fs.c      | 25 +++++++++++++++++++++++++
>>  include/fs.h | 21 +++++++++++++++++++++
>>  2 files changed, 46 insertions(+)
>
> Still, the commit message is in no way helpful when trying to understand what
> your changes are actually doing.

You were the one that wanted a reference to the relevant EFI protocol,
even though it is not terribly useful for understanding this patch ;-)

> You introduce an arbitrary new API in the filesystem level (you neither expose
> an existing API, nor are you implementing the API requested by EFI, nor
> anything roughly resembling it).

I am exposing the API needed to implement the EFI API.  I am not sure
why you describe it as arbitrary.  I would describe it as posix
readdir() ported to fs's stateless design.  Ie. not quite the same,
neither are any of fs's other APIs.

> The API you expose adds an index-based directory lookup, while EFI wants an
> POSIX-like directory stream. After reading through both the EFI spec and U-
> Boots file system code, its clear you want to have some matching layer between
> the mostly stateless U-Boot filesystem layer and the stateful EFI API.

What EFI wants and the way the u-boot filesystem API works are two
completely different things.  The u-boot fs APIs are stateless.  EFI
is not, not just for directories but also for file read/write.  Please
see patch 16/20.

> Please provide a thorough description why you create this new API in the fs
> layer, state that it is a hack to achieve what you want. If sometime later
> someone else wants to clean this up (both the FAT implementation, and the
> API), she/he should not have to go through all the code.

The fat implementation is a hack, but the API is not.  Ie. it does
exactly what the comment in fs.h describes.  (I might do it
differently if u-boot had a concept of file handles that were
stateful.  But that is a bit of a departure from how u-boot's fs
works.)

BR,
-R

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
  2017-08-05 20:31               ` Rob Clark
@ 2017-08-07 20:19                 ` Alexander Graf
  2017-08-07 21:14                   ` Mark Kettenis
  0 siblings, 1 reply; 116+ messages in thread
From: Alexander Graf @ 2017-08-07 20:19 UTC (permalink / raw)
  To: u-boot



On 05.08.17 21:31, Rob Clark wrote:
> On Sat, Aug 5, 2017 at 4:05 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>> On 08/05/2017 08:43 PM, Rob Clark wrote:
>>> On Sat, Aug 5, 2017 at 1:06 PM, Rob Clark <robdclark@gmail.com> wrote:
>>>> On Sat, Aug 5, 2017 at 12:52 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>>>>> On 08/05/2017 06:16 PM, Rob Clark wrote:
>>>>>> On Sat, Aug 5, 2017 at 12:12 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>>>>>>> On 08/05/2017 05:58 PM, Rob Clark wrote:
>>>>>>>> Some arch's have trouble with unaligned accesses.  Technically
>>>>>>>> EFI device-path structs should be byte aligned, and the next node
>>>>>>>> in the path starts immediately after the previous.  Meaning that
>>>>>>>> a pointer to an 'struct efi_device_path' is not necessarily word
>>>>>>>> aligned.  See section 10.3.1 in v2.7 of UEFI spec.
>>>>>>>>
>>>>>>>> This causes problems not just for u-boot, but also most/all EFI
>>>>>>>> payloads loaded by u-boot on these archs.  Fortunately the common
>>>>>>>> practice for traversing a device path is to rely on the length
>>>>>>>> field in the header, rather than the specified length of the
>>>>>>>> particular device path type+subtype.  So the EFI_DP_PAD() macro
>>>>>>>> will add the specified number of bytes to the tail of device path
>>>>>>>> structs to pad them to word alignment.
>>>>>>>>
>>>>>>>> Technically this is non-compliant, BROKEN_UNALIGNED should *only*
>>>>>>>> be defined on archs that cannot do unaligned accesses.
>>>>>>>>
>>>>>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>>>>>>> ---
>>>>>>>> I'm not sure if there are other arch's that need -DBROKEN_UNALIGNED
>>>>>>>>
>>>>>>>> Mark, this is untested but I think it should solve your crash on the
>>>>>>>> Banana Pi.  Could you give it a try when you get a chance?
>>>>>>>>
>>>>>>>>   arch/arm/config.mk               |  2 +-
>>>>>>>>   include/efi_api.h                | 30 ++++++++++++++++++++++++++++++
>>>>>>>>   lib/efi_loader/efi_device_path.c |  3 +++
>>>>>>>>   3 files changed, 34 insertions(+), 1 deletion(-)
>>>>>>>>
>>>>>>>> diff --git a/arch/arm/config.mk b/arch/arm/config.mk
>>>>>>>> index 1a77779db4..067dc93a9d 100644
>>>>>>>> --- a/arch/arm/config.mk
>>>>>>>> +++ b/arch/arm/config.mk
>>>>>>>> @@ -28,7 +28,7 @@ LLVMS_RELFLAGS              := $(call cc-option,-mllvm,) \
>>>>>>>>                        $(call cc-option,-arm-use-movt=0,)
>>>>>>>>   PLATFORM_RELFLAGS    += $(LLVM_RELFLAGS)
>>>>>>>>
>>>>>>>> -PLATFORM_CPPFLAGS += -D__ARM__
>>>>>>>> +PLATFORM_CPPFLAGS += -D__ARM__ -DBROKEN_UNALIGNED
>>>>>>>
>>>>>>> NAK
>>>>>>>
>>>>>>> We have more then ARM. And other architectures also create exceptions
>>>>>>> for unaligned access.
>>>>>>>
>>>>>>> I hate platform specific code. It should not be used outside /arch.
>>>>>>>
>>>>>>> To play it save you should not use _packed at all!
>>>>>>> Use memcpy to transfer between aligned and unaligned memory.
>>>>>>
>>>>>> except for reasons I explained in the thread on the patch that added
>>>>>> the __packed in the first place.  Sorry, this is ugly but we have to
>>>>>> do it.
>>>>>>
>>>>>> BR,
>>>>>> -R
>>>>>
>>>>> According to the UEFI standard the nodes in paths are not to be assumed
>>>>> to be aligned.
>>>>>
>>>>> So even if you use padding bytes in paths that you pass to the EFI
>>>>> application you should not expect that the EFI application does the
>>>>> same. Expect the EFI application either to remove them or send new nodes
>>>>> without padding.
>>>>>
>>>>> To the idea of padding bytes and __packed does not make sense.
>>>>
>>>> Ok, to be fair, you are right about device-paths passed too u-boot.
>>>> On BROKEN_UNALIGNED archs, we should sanitise with a copy to an
>>>> aligned device-path in *addition* to what I proposed.  I can make a
>>>> patch to add a helper to do this a bit later.
>>>
>>> so thinking about this a bit, I have two options in mind:
>>>
>>>   + efi_dp_sanitize() + efi_dp_free() helpers that are no-ops on
>>>     archs that can do unaligned access, but efi_dp_sanitize() always
>>>     allocates and copies on BROKEN_UNALIGNED archs and efi_dp_free()
>>>     always free's on BROKEN_UNALIGNED archs, even if the dp passed
>>>     from efi payload doesn't require it.
>>>
>>>   + efi_dp_sanitize() that is no-op on archs that can do unaligned
>>>     access but only allocates/copies when passed a device path that
>>>     would result in unaligned access, plus hook some mechanism to
>>>     auto-free on EFI_EXIT().. which is slightly tricky w/ nesting of
>>>     efi calls, but not impossible and at least avoids the problem
>>>     of missing calls to free the dup'd device-path.. which is the
>>>     sort of leak I might miss since I'm not using EFI_LOADER on any
>>>     BROKEN_UNALIGNED arch
>>>
>>> anyone who cares about armv7 + efi have a preference between always
>>> doing an extra alloc+copy+free vs EFI_EXIT() magic?
>>>
>>
>> Please, go for the simplest code.
> 
> well, the source of my question was there are two definitions of
> "simplest" here, ie "simplest to use" and "simplest helpers".. I'm
> mostly worried about future patches that use the helpers introducing
> leaks.  But actually I think a reasonable middle ground is "simplest
> helpers plus always make the helpers not no-ops for DEBUG builds"..
> 
>> I cannot imagine that copying takes more than 10ms for starting grub on
>> any architecture. So the user will not notice it anyway.
>> Assume every architecture requiring alignment for which you do not have
>> proof of the contrary.
>>
>> Even on ARM64 there are op codes that fail without alignment.
> 
> iirc the restrictions where mostly about device memory, and atomics.
> Which should not apply here.  (And we have aarch64 servers in
> production with grub, which doesn't take any protections about
> unaligned device-path nodes, using non u-boot EFI implementations.  So
> maybe that counts as proof to the contrary ;-))

The UEFI spec mandates that unaligned access are fixed up properly 
(usually by hardware). We violate the spec on 32bit ARM, but do fulfill 
it on AArch64.

The reason things worked before really was just that both U-Boot and 
grub were compiled with -mno-unaligned-access, so they never issued 
unaligned accesses.

Which system broke for Mark? Banana pi mostly has 32bit SBCs, so I 
assume it's one of those? In that case, we would need to either

   1) hack up the openbsd loader to also get compiled with 
-mno-unaligned-access

or

   2) rework the 32bit arm mmu code to enable the MMU plus hardware 
unaligned fixups on all systems. (that's a *lot* of work)

To me personally, UEFI in 32bit ARM land is a nice to have standardized 
platform, but not something where we really need to be fully standards 
compliant in every aspect. I think "making things work" is good enough 
there.

For AArch64 things are different. There we should strive for full UEFI 
compliance as it's "the future" :).


Alex

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
  2017-08-07 20:19                 ` Alexander Graf
@ 2017-08-07 21:14                   ` Mark Kettenis
  2017-08-07 22:18                     ` Rob Clark
  0 siblings, 1 reply; 116+ messages in thread
From: Mark Kettenis @ 2017-08-07 21:14 UTC (permalink / raw)
  To: u-boot

> From: Alexander Graf <agraf@suse.de>
> Date: Mon, 7 Aug 2017 21:19:37 +0100
> 
> On 05.08.17 21:31, Rob Clark wrote:
> > On Sat, Aug 5, 2017 at 4:05 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
> >> On 08/05/2017 08:43 PM, Rob Clark wrote:
> >>> On Sat, Aug 5, 2017 at 1:06 PM, Rob Clark <robdclark@gmail.com> wrote:
> >>>> On Sat, Aug 5, 2017 at 12:52 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
> >>>>> On 08/05/2017 06:16 PM, Rob Clark wrote:
> >>>>>> On Sat, Aug 5, 2017 at 12:12 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
> >>>>>>> On 08/05/2017 05:58 PM, Rob Clark wrote:
> >>>>>>>> Some arch's have trouble with unaligned accesses.  Technically
> >>>>>>>> EFI device-path structs should be byte aligned, and the next node
> >>>>>>>> in the path starts immediately after the previous.  Meaning that
> >>>>>>>> a pointer to an 'struct efi_device_path' is not necessarily word
> >>>>>>>> aligned.  See section 10.3.1 in v2.7 of UEFI spec.
> >>>>>>>>
> >>>>>>>> This causes problems not just for u-boot, but also most/all EFI
> >>>>>>>> payloads loaded by u-boot on these archs.  Fortunately the common
> >>>>>>>> practice for traversing a device path is to rely on the length
> >>>>>>>> field in the header, rather than the specified length of the
> >>>>>>>> particular device path type+subtype.  So the EFI_DP_PAD() macro
> >>>>>>>> will add the specified number of bytes to the tail of device path
> >>>>>>>> structs to pad them to word alignment.
> >>>>>>>>
> >>>>>>>> Technically this is non-compliant, BROKEN_UNALIGNED should *only*
> >>>>>>>> be defined on archs that cannot do unaligned accesses.
> >>>>>>>>
> >>>>>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
> >>>>>>>> ---
> >>>>>>>> I'm not sure if there are other arch's that need -DBROKEN_UNALIGNED
> >>>>>>>>
> >>>>>>>> Mark, this is untested but I think it should solve your crash on the
> >>>>>>>> Banana Pi.  Could you give it a try when you get a chance?
> >>>>>>>>
> >>>>>>>>   arch/arm/config.mk               |  2 +-
> >>>>>>>>   include/efi_api.h                | 30 ++++++++++++++++++++++++++++++
> >>>>>>>>   lib/efi_loader/efi_device_path.c |  3 +++
> >>>>>>>>   3 files changed, 34 insertions(+), 1 deletion(-)
> >>>>>>>>
> >>>>>>>> diff --git a/arch/arm/config.mk b/arch/arm/config.mk
> >>>>>>>> index 1a77779db4..067dc93a9d 100644
> >>>>>>>> --- a/arch/arm/config.mk
> >>>>>>>> +++ b/arch/arm/config.mk
> >>>>>>>> @@ -28,7 +28,7 @@ LLVMS_RELFLAGS              := $(call cc-option,-mllvm,) \
> >>>>>>>>                        $(call cc-option,-arm-use-movt=0,)
> >>>>>>>>   PLATFORM_RELFLAGS    += $(LLVM_RELFLAGS)
> >>>>>>>>
> >>>>>>>> -PLATFORM_CPPFLAGS += -D__ARM__
> >>>>>>>> +PLATFORM_CPPFLAGS += -D__ARM__ -DBROKEN_UNALIGNED
> >>>>>>>
> >>>>>>> NAK
> >>>>>>>
> >>>>>>> We have more then ARM. And other architectures also create exceptions
> >>>>>>> for unaligned access.
> >>>>>>>
> >>>>>>> I hate platform specific code. It should not be used outside /arch.
> >>>>>>>
> >>>>>>> To play it save you should not use _packed at all!
> >>>>>>> Use memcpy to transfer between aligned and unaligned memory.
> >>>>>>
> >>>>>> except for reasons I explained in the thread on the patch that added
> >>>>>> the __packed in the first place.  Sorry, this is ugly but we have to
> >>>>>> do it.
> >>>>>>
> >>>>>> BR,
> >>>>>> -R
> >>>>>
> >>>>> According to the UEFI standard the nodes in paths are not to be assumed
> >>>>> to be aligned.
> >>>>>
> >>>>> So even if you use padding bytes in paths that you pass to the EFI
> >>>>> application you should not expect that the EFI application does the
> >>>>> same. Expect the EFI application either to remove them or send new nodes
> >>>>> without padding.
> >>>>>
> >>>>> To the idea of padding bytes and __packed does not make sense.
> >>>>
> >>>> Ok, to be fair, you are right about device-paths passed too u-boot.
> >>>> On BROKEN_UNALIGNED archs, we should sanitise with a copy to an
> >>>> aligned device-path in *addition* to what I proposed.  I can make a
> >>>> patch to add a helper to do this a bit later.
> >>>
> >>> so thinking about this a bit, I have two options in mind:
> >>>
> >>>   + efi_dp_sanitize() + efi_dp_free() helpers that are no-ops on
> >>>     archs that can do unaligned access, but efi_dp_sanitize() always
> >>>     allocates and copies on BROKEN_UNALIGNED archs and efi_dp_free()
> >>>     always free's on BROKEN_UNALIGNED archs, even if the dp passed
> >>>     from efi payload doesn't require it.
> >>>
> >>>   + efi_dp_sanitize() that is no-op on archs that can do unaligned
> >>>     access but only allocates/copies when passed a device path that
> >>>     would result in unaligned access, plus hook some mechanism to
> >>>     auto-free on EFI_EXIT().. which is slightly tricky w/ nesting of
> >>>     efi calls, but not impossible and at least avoids the problem
> >>>     of missing calls to free the dup'd device-path.. which is the
> >>>     sort of leak I might miss since I'm not using EFI_LOADER on any
> >>>     BROKEN_UNALIGNED arch
> >>>
> >>> anyone who cares about armv7 + efi have a preference between always
> >>> doing an extra alloc+copy+free vs EFI_EXIT() magic?
> >>>
> >>
> >> Please, go for the simplest code.
> > 
> > well, the source of my question was there are two definitions of
> > "simplest" here, ie "simplest to use" and "simplest helpers".. I'm
> > mostly worried about future patches that use the helpers introducing
> > leaks.  But actually I think a reasonable middle ground is "simplest
> > helpers plus always make the helpers not no-ops for DEBUG builds"..
> > 
> >> I cannot imagine that copying takes more than 10ms for starting grub on
> >> any architecture. So the user will not notice it anyway.
> >> Assume every architecture requiring alignment for which you do not have
> >> proof of the contrary.
> >>
> >> Even on ARM64 there are op codes that fail without alignment.
> > 
> > iirc the restrictions where mostly about device memory, and atomics.
> > Which should not apply here.  (And we have aarch64 servers in
> > production with grub, which doesn't take any protections about
> > unaligned device-path nodes, using non u-boot EFI implementations.  So
> > maybe that counts as proof to the contrary ;-))
> 
> The UEFI spec mandates that unaligned access are fixed up properly 
> (usually by hardware). We violate the spec on 32bit ARM, but do fulfill 
> it on AArch64.

Actually for AArch32 the spec says:

  Unaligned access should be enabled if supported; Alignment faults
  are enabled otherwise.

So UEFI payload that wants to support pre-ARMv7 hardware should make
sure it doesn't do any unaligned access.

> The reason things worked before really was just that both U-Boot and 
> grub were compiled with -mno-unaligned-access, so they never issued 
> unaligned accesses.

That in itself is not enough to prevent unaligned access.  If you
explicitly cast an unaligned pointer to say (uint32_t *) and then
dereference it, you'll create an unaligned access.

> Which system broke for Mark? Banana pi mostly has 32bit SBCs, so I 
> assume it's one of those? In that case, we would need to either
> 
>    1) hack up the openbsd loader to also get compiled with 
> -mno-unaligned-access
> 
> or
> 
>    2) rework the 32bit arm mmu code to enable the MMU plus hardware 
> unaligned fixups on all systems. (that's a *lot* of work)

The system that broke was Cortex-A7 based, so ARMv7.

*However*, the OpenBSD bootloader does not perform any unaligned
access.  *All* cases of unaligned access that I encountered while
testing/debugging Rob's code were in U-Boot itself.  This was mostly a
consequence from a diff in the series that added __packed to the
device path node structs and then passed members of those structs to
functions that accessed the contents of tose (now byte aligned
structs) through (uint16_t *) or (uint32_t *) pointers.

There was initially some confusion because I used the pc reported by
U-Boot to look up the faulting instruction whereas I should have been
using the reloc_pc.

I think Rob is worried about grub/shim/fallback.efi doing unaligned
access of device path nodes on armv7.  But I'm not sure he has any
evidence beyond looking at code.

> To me personally, UEFI in 32bit ARM land is a nice to have standardized 
> platform, but not something where we really need to be fully standards 
> compliant in every aspect. I think "making things work" is good enough 
> there.

Right.  For us UEFI us just a convenient way to re-use the U-Boot
device driver code to load a kernel from a UFS/FFS filesystem.

> For AArch64 things are different. There we should strive for full UEFI 
> compliance as it's "the future" :).

Even there just making things work would be good enough for me ;).
Our AArach64 bootloader is almost identical to the AArch32 one and
works on a real UEFI implementation as well (SoftIron Overdrive 1000).

Cheers,

Mark

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
  2017-08-07 21:14                   ` Mark Kettenis
@ 2017-08-07 22:18                     ` Rob Clark
  2017-08-08  6:52                       ` Alexander Graf
  2017-08-08 12:26                       ` Mark Kettenis
  0 siblings, 2 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-07 22:18 UTC (permalink / raw)
  To: u-boot

On Mon, Aug 7, 2017 at 5:14 PM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>> From: Alexander Graf <agraf@suse.de>
>> Date: Mon, 7 Aug 2017 21:19:37 +0100
>>
>> On 05.08.17 21:31, Rob Clark wrote:
>> > On Sat, Aug 5, 2017 at 4:05 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>> >> On 08/05/2017 08:43 PM, Rob Clark wrote:
>> >>> On Sat, Aug 5, 2017 at 1:06 PM, Rob Clark <robdclark@gmail.com> wrote:
>> >>>> On Sat, Aug 5, 2017 at 12:52 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>> >>>>> On 08/05/2017 06:16 PM, Rob Clark wrote:
>> >>>>>> On Sat, Aug 5, 2017 at 12:12 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>> >>>>>>> On 08/05/2017 05:58 PM, Rob Clark wrote:
>> >>>>>>>> Some arch's have trouble with unaligned accesses.  Technically
>> >>>>>>>> EFI device-path structs should be byte aligned, and the next node
>> >>>>>>>> in the path starts immediately after the previous.  Meaning that
>> >>>>>>>> a pointer to an 'struct efi_device_path' is not necessarily word
>> >>>>>>>> aligned.  See section 10.3.1 in v2.7 of UEFI spec.
>> >>>>>>>>
>> >>>>>>>> This causes problems not just for u-boot, but also most/all EFI
>> >>>>>>>> payloads loaded by u-boot on these archs.  Fortunately the common
>> >>>>>>>> practice for traversing a device path is to rely on the length
>> >>>>>>>> field in the header, rather than the specified length of the
>> >>>>>>>> particular device path type+subtype.  So the EFI_DP_PAD() macro
>> >>>>>>>> will add the specified number of bytes to the tail of device path
>> >>>>>>>> structs to pad them to word alignment.
>> >>>>>>>>
>> >>>>>>>> Technically this is non-compliant, BROKEN_UNALIGNED should *only*
>> >>>>>>>> be defined on archs that cannot do unaligned accesses.
>> >>>>>>>>
>> >>>>>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>> >>>>>>>> ---
>> >>>>>>>> I'm not sure if there are other arch's that need -DBROKEN_UNALIGNED
>> >>>>>>>>
>> >>>>>>>> Mark, this is untested but I think it should solve your crash on the
>> >>>>>>>> Banana Pi.  Could you give it a try when you get a chance?
>> >>>>>>>>
>> >>>>>>>>   arch/arm/config.mk               |  2 +-
>> >>>>>>>>   include/efi_api.h                | 30 ++++++++++++++++++++++++++++++
>> >>>>>>>>   lib/efi_loader/efi_device_path.c |  3 +++
>> >>>>>>>>   3 files changed, 34 insertions(+), 1 deletion(-)
>> >>>>>>>>
>> >>>>>>>> diff --git a/arch/arm/config.mk b/arch/arm/config.mk
>> >>>>>>>> index 1a77779db4..067dc93a9d 100644
>> >>>>>>>> --- a/arch/arm/config.mk
>> >>>>>>>> +++ b/arch/arm/config.mk
>> >>>>>>>> @@ -28,7 +28,7 @@ LLVMS_RELFLAGS              := $(call cc-option,-mllvm,) \
>> >>>>>>>>                        $(call cc-option,-arm-use-movt=0,)
>> >>>>>>>>   PLATFORM_RELFLAGS    += $(LLVM_RELFLAGS)
>> >>>>>>>>
>> >>>>>>>> -PLATFORM_CPPFLAGS += -D__ARM__
>> >>>>>>>> +PLATFORM_CPPFLAGS += -D__ARM__ -DBROKEN_UNALIGNED
>> >>>>>>>
>> >>>>>>> NAK
>> >>>>>>>
>> >>>>>>> We have more then ARM. And other architectures also create exceptions
>> >>>>>>> for unaligned access.
>> >>>>>>>
>> >>>>>>> I hate platform specific code. It should not be used outside /arch.
>> >>>>>>>
>> >>>>>>> To play it save you should not use _packed at all!
>> >>>>>>> Use memcpy to transfer between aligned and unaligned memory.
>> >>>>>>
>> >>>>>> except for reasons I explained in the thread on the patch that added
>> >>>>>> the __packed in the first place.  Sorry, this is ugly but we have to
>> >>>>>> do it.
>> >>>>>>
>> >>>>>> BR,
>> >>>>>> -R
>> >>>>>
>> >>>>> According to the UEFI standard the nodes in paths are not to be assumed
>> >>>>> to be aligned.
>> >>>>>
>> >>>>> So even if you use padding bytes in paths that you pass to the EFI
>> >>>>> application you should not expect that the EFI application does the
>> >>>>> same. Expect the EFI application either to remove them or send new nodes
>> >>>>> without padding.
>> >>>>>
>> >>>>> To the idea of padding bytes and __packed does not make sense.
>> >>>>
>> >>>> Ok, to be fair, you are right about device-paths passed too u-boot.
>> >>>> On BROKEN_UNALIGNED archs, we should sanitise with a copy to an
>> >>>> aligned device-path in *addition* to what I proposed.  I can make a
>> >>>> patch to add a helper to do this a bit later.
>> >>>
>> >>> so thinking about this a bit, I have two options in mind:
>> >>>
>> >>>   + efi_dp_sanitize() + efi_dp_free() helpers that are no-ops on
>> >>>     archs that can do unaligned access, but efi_dp_sanitize() always
>> >>>     allocates and copies on BROKEN_UNALIGNED archs and efi_dp_free()
>> >>>     always free's on BROKEN_UNALIGNED archs, even if the dp passed
>> >>>     from efi payload doesn't require it.
>> >>>
>> >>>   + efi_dp_sanitize() that is no-op on archs that can do unaligned
>> >>>     access but only allocates/copies when passed a device path that
>> >>>     would result in unaligned access, plus hook some mechanism to
>> >>>     auto-free on EFI_EXIT().. which is slightly tricky w/ nesting of
>> >>>     efi calls, but not impossible and at least avoids the problem
>> >>>     of missing calls to free the dup'd device-path.. which is the
>> >>>     sort of leak I might miss since I'm not using EFI_LOADER on any
>> >>>     BROKEN_UNALIGNED arch
>> >>>
>> >>> anyone who cares about armv7 + efi have a preference between always
>> >>> doing an extra alloc+copy+free vs EFI_EXIT() magic?
>> >>>
>> >>
>> >> Please, go for the simplest code.
>> >
>> > well, the source of my question was there are two definitions of
>> > "simplest" here, ie "simplest to use" and "simplest helpers".. I'm
>> > mostly worried about future patches that use the helpers introducing
>> > leaks.  But actually I think a reasonable middle ground is "simplest
>> > helpers plus always make the helpers not no-ops for DEBUG builds"..
>> >
>> >> I cannot imagine that copying takes more than 10ms for starting grub on
>> >> any architecture. So the user will not notice it anyway.
>> >> Assume every architecture requiring alignment for which you do not have
>> >> proof of the contrary.
>> >>
>> >> Even on ARM64 there are op codes that fail without alignment.
>> >
>> > iirc the restrictions where mostly about device memory, and atomics.
>> > Which should not apply here.  (And we have aarch64 servers in
>> > production with grub, which doesn't take any protections about
>> > unaligned device-path nodes, using non u-boot EFI implementations.  So
>> > maybe that counts as proof to the contrary ;-))
>>
>> The UEFI spec mandates that unaligned access are fixed up properly
>> (usually by hardware). We violate the spec on 32bit ARM, but do fulfill
>> it on AArch64.
>
> Actually for AArch32 the spec says:
>
>   Unaligned access should be enabled if supported; Alignment faults
>   are enabled otherwise.

It is a bit strange to me that alignment faults are disabled by
default, but presumably is disabled out of reset..  I don't totally
understand the connection to having mmu disabled, unless all memory is
treated like device memory without mmu enabled.  (Which, also,
wouldn't that be super-slow?)  But anyway, I guess that is a bit
beside the point.

> So UEFI payload that wants to support pre-ARMv7 hardware should make
> sure it doesn't do any unaligned access.
>
>> The reason things worked before really was just that both U-Boot and
>> grub were compiled with -mno-unaligned-access, so they never issued
>> unaligned accesses.
>
> That in itself is not enough to prevent unaligned access.  If you
> explicitly cast an unaligned pointer to say (uint32_t *) and then
> dereference it, you'll create an unaligned access.

This is problematic around file nodes in the device path.  Adding the
padding bytes to the end of each device-path struct would "solve"
that, and if pre-aarch64 we are aiming at "good enough to work", I
kinda think that this the approach we should go for.  Other than
file-path nodes, the rest of the issues in u-boot should be solved by
addition of missing __packed on 'struct efi_device_path' (which I've
added locally and will be in the next revision of the patchset).

>> Which system broke for Mark? Banana pi mostly has 32bit SBCs, so I
>> assume it's one of those? In that case, we would need to either
>>
>>    1) hack up the openbsd loader to also get compiled with
>> -mno-unaligned-access
>>
>> or
>>
>>    2) rework the 32bit arm mmu code to enable the MMU plus hardware
>> unaligned fixups on all systems. (that's a *lot* of work)
>
> The system that broke was Cortex-A7 based, so ARMv7.
>
> *However*, the OpenBSD bootloader does not perform any unaligned
> access.  *All* cases of unaligned access that I encountered while
> testing/debugging Rob's code were in U-Boot itself.  This was mostly a
> consequence from a diff in the series that added __packed to the
> device path node structs and then passed members of those structs to
> functions that accessed the contents of tose (now byte aligned
> structs) through (uint16_t *) or (uint32_t *) pointers.

Yeah.. the padding byte approach I suggested would solve this.  Not
*really* compliant, but should work for all the payload code I've come
across.  We definitely shouldn't enable the padding bytes on aarch64,
but I think padding bytes would be a pragmatic solution for armv7 and
earlier.  (And hopefully someday someone enables mmu on armv7 so we
can turn off the hack there too.)

> There was initially some confusion because I used the pc reported by
> U-Boot to look up the faulting instruction whereas I should have been
> using the reloc_pc.
>
> I think Rob is worried about grub/shim/fallback.efi doing unaligned
> access of device path nodes on armv7.  But I'm not sure he has any
> evidence beyond looking at code.

It will definitely be an issue (if grub/shim/fallback were not
compiled with -mno-unaligned-access) in some of the debug code that
prints out device-paths.  I haven't checked the compiler flags used w/
shim/fallback.

Parsing MEDIA_DEVICE:HARD_DRIVE nodes would be an issue regardless
without -mno-unaligned-access, although we might be getting lucky by
just not hitting debug paths.  Some of the other issues would be
hidden by padding bytes at the end of the DP structs which would keep
the file-path nodes word aligned.

>> To me personally, UEFI in 32bit ARM land is a nice to have standardized
>> platform, but not something where we really need to be fully standards
>> compliant in every aspect. I think "making things work" is good enough
>> there.
>
> Right.  For us UEFI us just a convenient way to re-use the U-Boot
> device driver code to load a kernel from a UFS/FFS filesystem.
>
>> For AArch64 things are different. There we should strive for full UEFI
>> compliance as it's "the future" :).
>
> Even there just making things work would be good enough for me ;).
> Our AArach64 bootloader is almost identical to the AArch32 one and
> works on a real UEFI implementation as well (SoftIron Overdrive 1000).
>

I think we should make the aarch64 implementation fully compliant (ie.
addition of missing __packed's and no extra padding bytes).  I won't
loose sleep if some efi payloads don't work on pre-aarch64 (we should
be able to keep things that were working before working).  If adding
missing __packed breaks things on platforms that can't do unaligned
access, the solution is not to remove __packed, but to conditionally
add padding bytes at the end of the struct.  That way we keep things
working as before on the old platforms, but make things work correctly
on aarch64.

I'll add back my patch for EFI_DP_PAD() to this patchset, since this
seems like the sensible way forward.

BR,
-R

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions
  2017-08-07 16:16                             ` Rob Clark
@ 2017-08-08  1:36                               ` Jonathan Gray
  0 siblings, 0 replies; 116+ messages in thread
From: Jonathan Gray @ 2017-08-08  1:36 UTC (permalink / raw)
  To: u-boot

On Mon, Aug 07, 2017 at 12:16:54PM -0400, Rob Clark wrote:
> On Mon, Aug 7, 2017 at 11:47 AM, Jonathan Gray <jsg@jsg.id.au> wrote:
> > On Sun, Aug 06, 2017 at 11:34:15AM -0400, Rob Clark wrote:
> >> On Sun, Aug 6, 2017 at 10:45 AM, Rob Clark <robdclark@gmail.com> wrote:
> >> >
> >> > I've started trying to hack up test_efi_loader.py to add a test that
> >> > loads OpenBSD's bootloader..  kinda muddling through it at this point,
> >> > since not a py expert or too familiar w/ u-boot's test framework.  But
> >> > I'll see if I can get to the point where I can run the same thing on
> >> > various arm7 and aarch64 devices in qemu.
> >> >
> >>
> >> Making a bit of progress on this (running it on a vexpress_ca15_tc2
> >> board in qemu).. any hint where I can find BOOTARM.EFI src code?
> >>
> >> => tftpboot 80400000 obsdboot.efi
> >> smc911x: MAC 52:54:00:12:34:56
> >> smc911x: detected LAN9118 controller
> >> smc911x: phy initialized
> >> smc911x: MAC 52:54:00:12:34:56
> >> Using smc911x-0 device
> >> TFTP from server 10.0.2.2; our IP address is 10.0.2.15
> >> Filename 'obsdboot.efi'.
> >> Load address: 0x80400000
> >> Loading: *%08#####
> >> 12.4 MiB/s
> >> done
> >> Bytes transferred = 64908 (fd8c hex)
> >> smc911x: MAC 52:54:00:12:34:56
> >> => crc32 80400000 $filesize
> >> CRC32 for 80400000 ... 8040fd8b ==> a9ac4fcf
> >> => bootefi 80400000
> >> ## Starting EFI application at 80400000 ...
> >> WARNING: Invalid device tree, expect boot to fail
> >> BS->LocateHandle() returns 0
> >> undefined instruction
> >> pc : [<9eec65c4>]   lr : [<9eeca390>]
> >> sp : 9fed7a18  ip : 0000003f fp : 9fed7a2c
> >> r10: 00000000  r9 : 9eed4658 r8 : 00000000
> >> r7 : 9eed1ce4  r6 : 9eed3538 r5 : 9fed7a6c  r4 : 9eed4658
> >> r3 : 00000000  r2 : 9eed2f8e r1 : 9eed1ee0  r0 : 00000000
> >> Flags: nZCv  IRQs off  FIQs off  Mode SVC_32
> >> Resetting CPU ...
> >>
> >> resetting ...
> >>
> >>
> >> U-Boot 2017.09-rc1-00025-g534695d189 (Aug 06 2017 - 06:58:16 -0400)
> >>
> >> DRAM:  1 GiB
> >> WARNING: Caches not enabled
> >> Flash: 128 MiB
> >> MMC:   MMC: 0
> >> *** Warning - bad CRC, using default environment
> >>
> >> In:    serial
> >> Out:   serial
> >> Err:   serial
> >> Net:   smc911x-0
> >> Hit any key to stop autoboot:  2
> >
> > Why does U-Boot not set fdt_addr_r or fdtfile for vexpress?  Worse yet
> > trying to load to the default kernel_addr_r fails.  So it requires a
> > script or manual commands to boot instead of the usual distro boot
> > arrangement?
> 
> I suspect this is specific to the test framework (probably not
> enabling distro-boot-cmd so that the test framework can run the cmds
> it wants??)

I didn't attempt to use the test framework, just loaded the result
of building vexpress_ca15_tc2_defconfig into qemu.

It looks like the load addresses are only good for >= 1G physmem.

U-Boot 2017.09-rc1 (Aug 02 2017 - 10:55:19 +1000)

DRAM:  128 MiB
WARNING: Caches not enabled
Flash: 128 MiB
MMC:   MMC: 0
*** Warning - bad CRC, using default environment

In:    serial
Out:   serial
Err:   serial
Net:   smc911x-0
Hit any key to stop autoboot:  0
=> printenv
arch=arm
baudrate=38400
board=vexpress
board_name=vexpress
boot_a_script=load ${devtype} ${devnum}:${distro_bootpart} ${scriptaddr} ${prefix}${script}; source ${scriptaddr}
boot_efi_binary=load ${devtype} ${devnum}:${distro_bootpart} ${kernel_addr_r} efi/boot/bootarm.efi; if fdt addr ${fdt_addr_r}; then bootefi ${kernel_addr_r} ${fdt_addr_r};else bootefi ${kernel_addr_r} ${fdtcontroladdr};fi
boot_extlinux=sysboot ${devtype} ${devnum}:${distro_bootpart} any ${scriptaddr} ${prefix}extlinux/extlinux.conf
boot_prefixes=/ /boot/
boot_script_dhcp=boot.scr.uimg
boot_scripts=boot.scr.uimg boot.scr
boot_targets=mmc1 mmc0 pxe dhcp
bootcmd=run distro_bootcmd; run bootflash;
bootcmd_dhcp=if dhcp ${scriptaddr} ${boot_script_dhcp}; then source ${scriptaddr}; fi;setenv efi_fdtfile ${fdtfile}; if test -z "${fdtfile}" -a -n "${soc}"; then setenv efi_fdtfile ${soc}-${board}${boardver}.dtb; fi; setenv efi_old_vci ${bootp_vci};setenv efi_old_arch ${bootp_arch};setenv bootp_vci PXEClient:Arch:00010:UNDI:003000;setenv bootp_arch 0xa;if dhcp ${kernel_addr_r}; then tftpboot ${fdt_addr_r} dtb/${efi_fdtfile};if fdt addr ${fdt_addr_r}; then bootefi ${kernel_addr_r} ${fdt_addr_r}; else bootefi ${kernel_addr_r} ${fdtcontroladdr};fi;fi;setenv bootp_vci ${efi_old_vci};setenv bootp_arch ${efi_old_arch};setenv efi_fdtfile;setenv efi_old_arch;setenv efi_old_vci;
bootcmd_mmc0=setenv devnum 0; run mmc_boot
bootcmd_mmc1=setenv devnum 1; run mmc_boot
bootcmd_pxe=dhcp; if pxe get; then pxe boot; fi
bootdelay=2
bootflash=run flashargs; cp ${ramdisk_addr} ${ramdisk_addr_r} ${maxramdisk}; bootm ${kernel_addr} ${ramdisk_addr_r}
console=ttyAMA0,38400n8
cpu=armv7
distro_bootcmd=for target in ${boot_targets}; do run bootcmd_${target}; done
dram=1024M
efi_dtb_prefixes=/ /dtb/ /dtb/current/
ethact=smc911x-0
ethaddr=52:54:00:12:34:56
flashargs=setenv bootargs root=${root} console=${console} mem=${dram} mtdparts=${mtd} mmci.fmax=190000 devtmpfs.mount=0	 vmalloc=256M
kernel_addr=0x0c100000
kernel_addr_r=0xa0008000
load_efi_dtb=load ${devtype} ${devnum}:${distro_bootpart} ${fdt_addr_r} ${prefix}${efi_fdtfile}
loadaddr=0xa0008000
maxramdisk=0x1800000
mmc_boot=if mmc dev ${devnum}; then setenv devtype mmc; run scan_dev_for_boot_part; fi
mtd=armflash:1M at 0x800000(uboot),7M at 0x1000000(kernel),24M at 0x2000000(initrd)
pxefile_addr_r=0xa8000000
ramdisk_addr=0x0c800000
ramdisk_addr_r=0x81000000
root=/dev/sda1 rw
scan_dev_for_boot=echo Scanning ${devtype} ${devnum}:${distro_bootpart}...; for prefix in ${boot_prefixes}; do run scan_dev_for_extlinux; run scan_dev_for_scripts; done;run scan_dev_for_efi;
scan_dev_for_boot_part=part list ${devtype} ${devnum} -bootable devplist; env exists devplist || setenv devplist 1; for distro_bootpart in ${devplist}; do if fstype ${devtype} ${devnum}:${distro_bootpart} bootfstype; then run scan_dev_for_boot; fi; done
scan_dev_for_efi=setenv efi_fdtfile ${fdtfile}; if test -z "${fdtfile}" -a -n "${soc}"; then setenv efi_fdtfile ${soc}-${board}${boardver}.dtb; fi; for prefix in ${efi_dtb_prefixes}; do if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${efi_fdtfile}; then run load_efi_dtb; fi;done;if test -e ${devtype} ${devnum}:${distro_bootpart} efi/boot/bootarm.efi; then echo Found EFI removable media binary efi/boot/bootarm.efi; run boot_efi_binary; echo EFI LOAD FAILED: continuing...; fi; setenv efi_fdtfile
scan_dev_for_extlinux=if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}extlinux/extlinux.conf; then echo Found ${prefix}extlinux/extlinux.conf; run boot_extlinux; echo SCRIPT FAILED: continuing...; fi
scan_dev_for_scripts=for script in ${boot_scripts}; do if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${script}; then echo Found U-Boot script ${prefix}${script}; run boot_a_script; echo SCRIPT FAILED: continuing...; fi; done
scriptaddr=0xa8000000
stderr=serial
stdin=serial
stdout=serial
vendor=armltd

Environment size: 3974/262140 bytes
=> bdinfo
arch_number = 0x000008E0
boot_params = 0x80002000
DRAM bank   = 0x00000000
-> start    = 0x80000000
-> size     = 0x08000000
DRAM bank   = 0x00000001
-> start    = 0xA0000000
-> size     = 0x00000004
eth0name    = smc911x-0
ethaddr     = 52:54:00:12:34:56
current eth = smc911x-0
ip_addr     = <NULL>
baudrate    = 38400 bps
TLB addr    = 0x87FF0000
relocaddr   = 0x87F7B000
reloc off   = 0x0777B000
irq_sp      = 0x87EDAEF0
sp start    = 0x87EDAEE0

With -m 512

U-Boot 2017.09-rc1 (Aug 02 2017 - 10:55:19 +1000)

DRAM:  512 MiB
WARNING: Caches not enabled
Flash: 128 MiB
MMC:   MMC: 0
*** Warning - bad CRC, using default environment

In:    serial
Out:   serial
Err:   serial
Net:   smc911x-0
Hit any key to stop autoboot:  0 
=> bdinfo
arch_number = 0x000008E0
boot_params = 0x80002000
DRAM bank   = 0x00000000
-> start    = 0x80000000
-> size     = 0x20000000
DRAM bank   = 0x00000001
-> start    = 0xA0000000
-> size     = 0x00000004
eth0name    = smc911x-0
ethaddr     = 52:54:00:12:34:56
current eth = smc911x-0
ip_addr     = <NULL>
baudrate    = 38400 bps
TLB addr    = 0x9FFF0000
relocaddr   = 0x9FF7B000
reloc off   = 0x1F77B000
irq_sp      = 0x9FEDAEF0
sp start    = 0x9FEDAEE0

With -m 1024

U-Boot 2017.09-rc1 (Aug 02 2017 - 10:55:19 +1000)

DRAM:  1 GiB
WARNING: Caches not enabled
Flash: 128 MiB
MMC:   MMC: 0
*** Warning - bad CRC, using default environment

In:    serial
Out:   serial
Err:   serial
Net:   smc911x-0
Hit any key to stop autoboot:  0 
=> bdinfo
arch_number = 0x000008E0
boot_params = 0x80002000
DRAM bank   = 0x00000000
-> start    = 0x80000000
-> size     = 0x20000000
DRAM bank   = 0x00000001
-> start    = 0xA0000000
-> size     = 0x20000000
eth0name    = smc911x-0
ethaddr     = 52:54:00:12:34:56
current eth = smc911x-0
ip_addr     = <NULL>
baudrate    = 38400 bps
TLB addr    = 0x9FFF0000
relocaddr   = 0x9FF7B000
reloc off   = 0x1F77B000
irq_sp      = 0x9FEDAEF0
sp start    = 0x9FEDAEE0

-m 1024 works with ${kernel_addr_r} instead of giving
"efi_load_pe: Invalid DOS Signature"

=> setenv fdt_addr_r 0x81000000
=> setenv fdtfile vexpress-v2p-ca15-tc1.dtb
=> load mmc 0:1 ${fdt_addr_r} ${fdtfile}
reading vexpress-v2p-ca15-tc1.dtb
13384 bytes read in 22 ms (593.8 KiB/s)
=> load mmc 0:1 ${kernel_addr_r} efi/boot/bootarm.efi
reading efi/boot/bootarm.efi
64908 bytes read in 49 ms (1.3 MiB/s)
=> bootefi ${kernel_addr_r} ${fdt_addr_r}
## Starting EFI application at a0008000 ...
Scanning disks on mmc...
MMC Device 1 not found
MMC Device 2 not found
MMC Device 3 not found
Found 1 disks
>> OpenBSD/armv7 BOOTARM 0.8
boot> 
cannot open sd0a:/etc/random.seed: No such file or directory
booting sd0a:/bsd: 2265112+7989364+447000 [80+314496+149702]=0xaad1c0

OpenBSD/armv7 booting ...
arg0 0xc0dad1c0 arg1 0x8e0 arg2 0x88000000
Allocating page tables
freestart = 0x80dae000, free_pages = 127570 (0x0001f252)
IRQ stack: p0x80ddc000 v0xc0ddc000
ABT stack: p0x80ddd000 v0xc0ddd000
UND stack: p0x80dde000 v0xc0dde000
SVC stack: p0x80ddf000 v0xc0ddf000
Creating L1 page table at 0x80db0000
Mapping kernel
Constructing L2 page tables
undefined page pmap board type: 2272
Copyright (c) 1982, 1986, 1989, 1991, 1993
        The Regents of the University of California.  All rights reserved.
Copyright (c) 1995-2017 OpenBSD. All rights reserved.  https://www.OpenBSD.org

OpenBSD 6.1-current (RAMDISK) #30: Sat Aug  5 22:01:16 MDT 2017
    deraadt at armv7.openbsd.org:/usr/src/sys/arch/armv7/compile/RAMDISK
real mem  = 1073741824 (1024MB)
avail mem = 1038520320 (990MB)
mainbus0 at root: V2P-CA15
cpu0 at mainbus0: ARM Cortex-A15 r2p1 (ARMv7)
cpu0: DC enabled IC enabled WB disabled EABT branch prediction enabled
cpu0: 32KB(64b/l,2way) I-cache, 32KB(64b/l,2way) wr-back D-cache
cortex0 at mainbus0
ampintc0 at mainbus0 nirq 160, ncpu 1
agtimer0 at mainbus0: tick rate 62500 KHz
simplebus0 at mainbus0: "smb"
simplebus1 at simplebus0: "motherboard"
simplebus2 at simplebus1: "iofpga"
sysreg0 at simplebus2: ID 0x1190f500 PROCID0 0x14000237
pluart0 at simplebus2: console
pluart1 at simplebus2
pluart2 at simplebus2
pluart3 at simplebus2
plrtc0 at simplebus2
simplebus3 at mainbus0: "hsb"
boot device: lookup 'sd0a:/bsd' failed.
root on rd0a swap on rd0b dump on rd0b
e

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
  2017-08-07 22:18                     ` Rob Clark
@ 2017-08-08  6:52                       ` Alexander Graf
  2017-08-08  8:11                         ` Ard Biesheuvel
  2017-08-08  9:27                         ` Rob Clark
  2017-08-08 12:26                       ` Mark Kettenis
  1 sibling, 2 replies; 116+ messages in thread
From: Alexander Graf @ 2017-08-08  6:52 UTC (permalink / raw)
  To: u-boot



> Am 07.08.2017 um 23:18 schrieb Rob Clark <robdclark@gmail.com>:
> 
> On Mon, Aug 7, 2017 at 5:14 PM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>>> From: Alexander Graf <agraf@suse.de>
>>> Date: Mon, 7 Aug 2017 21:19:37 +0100
>>> 
>>>> On 05.08.17 21:31, Rob Clark wrote:
>>>>> On Sat, Aug 5, 2017 at 4:05 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>>>>>> On 08/05/2017 08:43 PM, Rob Clark wrote:
>>>>>>> On Sat, Aug 5, 2017 at 1:06 PM, Rob Clark <robdclark@gmail.com> wrote:
>>>>>>>> On Sat, Aug 5, 2017 at 12:52 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>>>>>>>>> On 08/05/2017 06:16 PM, Rob Clark wrote:
>>>>>>>>>> On Sat, Aug 5, 2017 at 12:12 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>>>>>>>>>>> On 08/05/2017 05:58 PM, Rob Clark wrote:
>>>>>>>>>>> Some arch's have trouble with unaligned accesses.  Technically
>>>>>>>>>>> EFI device-path structs should be byte aligned, and the next node
>>>>>>>>>>> in the path starts immediately after the previous.  Meaning that
>>>>>>>>>>> a pointer to an 'struct efi_device_path' is not necessarily word
>>>>>>>>>>> aligned.  See section 10.3.1 in v2.7 of UEFI spec.
>>>>>>>>>>> 
>>>>>>>>>>> This causes problems not just for u-boot, but also most/all EFI
>>>>>>>>>>> payloads loaded by u-boot on these archs.  Fortunately the common
>>>>>>>>>>> practice for traversing a device path is to rely on the length
>>>>>>>>>>> field in the header, rather than the specified length of the
>>>>>>>>>>> particular device path type+subtype.  So the EFI_DP_PAD() macro
>>>>>>>>>>> will add the specified number of bytes to the tail of device path
>>>>>>>>>>> structs to pad them to word alignment.
>>>>>>>>>>> 
>>>>>>>>>>> Technically this is non-compliant, BROKEN_UNALIGNED should *only*
>>>>>>>>>>> be defined on archs that cannot do unaligned accesses.
>>>>>>>>>>> 
>>>>>>>>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>>>>>>>>>> ---
>>>>>>>>>>> I'm not sure if there are other arch's that need -DBROKEN_UNALIGNED
>>>>>>>>>>> 
>>>>>>>>>>> Mark, this is untested but I think it should solve your crash on the
>>>>>>>>>>> Banana Pi.  Could you give it a try when you get a chance?
>>>>>>>>>>> 
>>>>>>>>>>>  arch/arm/config.mk               |  2 +-
>>>>>>>>>>>  include/efi_api.h                | 30 ++++++++++++++++++++++++++++++
>>>>>>>>>>>  lib/efi_loader/efi_device_path.c |  3 +++
>>>>>>>>>>>  3 files changed, 34 insertions(+), 1 deletion(-)
>>>>>>>>>>> 
>>>>>>>>>>> diff --git a/arch/arm/config.mk b/arch/arm/config.mk
>>>>>>>>>>> index 1a77779db4..067dc93a9d 100644
>>>>>>>>>>> --- a/arch/arm/config.mk
>>>>>>>>>>> +++ b/arch/arm/config.mk
>>>>>>>>>>> @@ -28,7 +28,7 @@ LLVMS_RELFLAGS              := $(call cc-option,-mllvm,) \
>>>>>>>>>>>                       $(call cc-option,-arm-use-movt=0,)
>>>>>>>>>>>  PLATFORM_RELFLAGS    += $(LLVM_RELFLAGS)
>>>>>>>>>>> 
>>>>>>>>>>> -PLATFORM_CPPFLAGS += -D__ARM__
>>>>>>>>>>> +PLATFORM_CPPFLAGS += -D__ARM__ -DBROKEN_UNALIGNED
>>>>>>>>>> 
>>>>>>>>>> NAK
>>>>>>>>>> 
>>>>>>>>>> We have more then ARM. And other architectures also create exceptions
>>>>>>>>>> for unaligned access.
>>>>>>>>>> 
>>>>>>>>>> I hate platform specific code. It should not be used outside /arch.
>>>>>>>>>> 
>>>>>>>>>> To play it save you should not use _packed at all!
>>>>>>>>>> Use memcpy to transfer between aligned and unaligned memory.
>>>>>>>>> 
>>>>>>>>> except for reasons I explained in the thread on the patch that added
>>>>>>>>> the __packed in the first place.  Sorry, this is ugly but we have to
>>>>>>>>> do it.
>>>>>>>>> 
>>>>>>>>> BR,
>>>>>>>>> -R
>>>>>>>> 
>>>>>>>> According to the UEFI standard the nodes in paths are not to be assumed
>>>>>>>> to be aligned.
>>>>>>>> 
>>>>>>>> So even if you use padding bytes in paths that you pass to the EFI
>>>>>>>> application you should not expect that the EFI application does the
>>>>>>>> same. Expect the EFI application either to remove them or send new nodes
>>>>>>>> without padding.
>>>>>>>> 
>>>>>>>> To the idea of padding bytes and __packed does not make sense.
>>>>>>> 
>>>>>>> Ok, to be fair, you are right about device-paths passed too u-boot.
>>>>>>> On BROKEN_UNALIGNED archs, we should sanitise with a copy to an
>>>>>>> aligned device-path in *addition* to what I proposed.  I can make a
>>>>>>> patch to add a helper to do this a bit later.
>>>>>> 
>>>>>> so thinking about this a bit, I have two options in mind:
>>>>>> 
>>>>>>  + efi_dp_sanitize() + efi_dp_free() helpers that are no-ops on
>>>>>>    archs that can do unaligned access, but efi_dp_sanitize() always
>>>>>>    allocates and copies on BROKEN_UNALIGNED archs and efi_dp_free()
>>>>>>    always free's on BROKEN_UNALIGNED archs, even if the dp passed
>>>>>>    from efi payload doesn't require it.
>>>>>> 
>>>>>>  + efi_dp_sanitize() that is no-op on archs that can do unaligned
>>>>>>    access but only allocates/copies when passed a device path that
>>>>>>    would result in unaligned access, plus hook some mechanism to
>>>>>>    auto-free on EFI_EXIT().. which is slightly tricky w/ nesting of
>>>>>>    efi calls, but not impossible and at least avoids the problem
>>>>>>    of missing calls to free the dup'd device-path.. which is the
>>>>>>    sort of leak I might miss since I'm not using EFI_LOADER on any
>>>>>>    BROKEN_UNALIGNED arch
>>>>>> 
>>>>>> anyone who cares about armv7 + efi have a preference between always
>>>>>> doing an extra alloc+copy+free vs EFI_EXIT() magic?
>>>>>> 
>>>>> 
>>>>> Please, go for the simplest code.
>>>> 
>>>> well, the source of my question was there are two definitions of
>>>> "simplest" here, ie "simplest to use" and "simplest helpers".. I'm
>>>> mostly worried about future patches that use the helpers introducing
>>>> leaks.  But actually I think a reasonable middle ground is "simplest
>>>> helpers plus always make the helpers not no-ops for DEBUG builds"..
>>>> 
>>>>> I cannot imagine that copying takes more than 10ms for starting grub on
>>>>> any architecture. So the user will not notice it anyway.
>>>>> Assume every architecture requiring alignment for which you do not have
>>>>> proof of the contrary.
>>>>> 
>>>>> Even on ARM64 there are op codes that fail without alignment.
>>>> 
>>>> iirc the restrictions where mostly about device memory, and atomics.
>>>> Which should not apply here.  (And we have aarch64 servers in
>>>> production with grub, which doesn't take any protections about
>>>> unaligned device-path nodes, using non u-boot EFI implementations.  So
>>>> maybe that counts as proof to the contrary ;-))
>>> 
>>> The UEFI spec mandates that unaligned access are fixed up properly
>>> (usually by hardware). We violate the spec on 32bit ARM, but do fulfill
>>> it on AArch64.
>> 
>> Actually for AArch32 the spec says:
>> 
>>  Unaligned access should be enabled if supported; Alignment faults
>>  are enabled otherwise.
> 
> It is a bit strange to me that alignment faults are disabled by
> default, but presumably is disabled out of reset..  I don't totally
> understand the connection to having mmu disabled, unless all memory is
> treated like device memory without mmu enabled.  (Which, also,
> wouldn't that be super-slow?)  But anyway, I guess that is a bit
> beside the point.

It is treated as device memory with mmu disabled, yes.

> 
>> So UEFI payload that wants to support pre-ARMv7 hardware should make
>> sure it doesn't do any unaligned access.
>> 
>>> The reason things worked before really was just that both U-Boot and
>>> grub were compiled with -mno-unaligned-access, so they never issued
>>> unaligned accesses.
>> 
>> That in itself is not enough to prevent unaligned access.  If you
>> explicitly cast an unaligned pointer to say (uint32_t *) and then
>> dereference it, you'll create an unaligned access.
> 
> This is problematic around file nodes in the device path.  Adding the
> padding bytes to the end of each device-path struct would "solve"
> that, and if pre-aarch64 we are aiming at "good enough to work", I
> kinda think that this the approach we should go for.  Other than
> file-path nodes, the rest of the issues in u-boot should be solved by
> addition of missing __packed on 'struct efi_device_path' (which I've
> added locally and will be in the next revision of the patchset).

Let's ask Leif and Ard if that is actually correct. If I remember correctly, edk2 some times leverages automatic padding from the compiler on structs.

> 
>>> Which system broke for Mark? Banana pi mostly has 32bit SBCs, so I
>>> assume it's one of those? In that case, we would need to either
>>> 
>>>   1) hack up the openbsd loader to also get compiled with
>>> -mno-unaligned-access
>>> 
>>> or
>>> 
>>>   2) rework the 32bit arm mmu code to enable the MMU plus hardware
>>> unaligned fixups on all systems. (that's a *lot* of work)
>> 
>> The system that broke was Cortex-A7 based, so ARMv7.
>> 
>> *However*, the OpenBSD bootloader does not perform any unaligned
>> access.  *All* cases of unaligned access that I encountered while
>> testing/debugging Rob's code were in U-Boot itself.  This was mostly a
>> consequence from a diff in the series that added __packed to the
>> device path node structs and then passed members of those structs to
>> functions that accessed the contents of tose (now byte aligned
>> structs) through (uint16_t *) or (uint32_t *) pointers.
> 
> Yeah.. the padding byte approach I suggested would solve this.  Not
> *really* compliant, but should work for all the payload code I've come
> across.  We definitely shouldn't enable the padding bytes on aarch64,
> but I think padding bytes would be a pragmatic solution for armv7 and
> earlier.  (And hopefully someday someone enables mmu on armv7 so we
> can turn off the hack there too.)

The problem really is inconsistency. Some 32bit arm platforms enable the mmu, some don't.

> 
>> There was initially some confusion because I used the pc reported by
>> U-Boot to look up the faulting instruction whereas I should have been
>> using the reloc_pc.
>> 
>> I think Rob is worried about grub/shim/fallback.efi doing unaligned
>> access of device path nodes on armv7.  But I'm not sure he has any
>> evidence beyond looking at code.
> 
> It will definitely be an issue (if grub/shim/fallback were not
> compiled with -mno-unaligned-access) in some of the debug code that
> prints out device-paths.  I haven't checked the compiler flags used w/
> shim/fallback.
> 
> Parsing MEDIA_DEVICE:HARD_DRIVE nodes would be an issue regardless
> without -mno-unaligned-access, although we might be getting lucky by
> just not hitting debug paths.  Some of the other issues would be
> hidden by padding bytes at the end of the DP structs which would keep
> the file-path nodes word aligned.
> 
>>> To me personally, UEFI in 32bit ARM land is a nice to have standardized
>>> platform, but not something where we really need to be fully standards
>>> compliant in every aspect. I think "making things work" is good enough
>>> there.
>> 
>> Right.  For us UEFI us just a convenient way to re-use the U-Boot
>> device driver code to load a kernel from a UFS/FFS filesystem.
>> 
>>> For AArch64 things are different. There we should strive for full UEFI
>>> compliance as it's "the future" :).
>> 
>> Even there just making things work would be good enough for me ;).
>> Our AArach64 bootloader is almost identical to the AArch32 one and
>> works on a real UEFI implementation as well (SoftIron Overdrive 1000).
>> 
> 
> I think we should make the aarch64 implementation fully compliant (ie.
> addition of missing __packed's and no extra padding bytes).  I won't
> loose sleep if some efi payloads don't work on pre-aarch64 (we should
> be able to keep things that were working before working).  If adding
> missing __packed breaks things on platforms that can't do unaligned
> access, the solution is not to remove __packed, but to conditionally
> add padding bytes at the end of the struct.  That way we keep things
> working as before on the old platforms, but make things work correctly
> on aarch64.
> 
> I'll add back my patch for EFI_DP_PAD() to this patchset, since this
> seems like the sensible way forward.

Let's make sure we get an ack from Leif/Ard for that approach :)


Alex

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
  2017-08-08  6:52                       ` Alexander Graf
@ 2017-08-08  8:11                         ` Ard Biesheuvel
  2017-08-08 11:32                           ` Leif Lindholm
  2017-08-08  9:27                         ` Rob Clark
  1 sibling, 1 reply; 116+ messages in thread
From: Ard Biesheuvel @ 2017-08-08  8:11 UTC (permalink / raw)
  To: u-boot

On 8 August 2017 at 07:52, Alexander Graf <agraf@suse.de> wrote:
>
>
>> Am 07.08.2017 um 23:18 schrieb Rob Clark <robdclark@gmail.com>:
>>
>> On Mon, Aug 7, 2017 at 5:14 PM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>>>> From: Alexander Graf <agraf@suse.de>
>>>> Date: Mon, 7 Aug 2017 21:19:37 +0100
>>>>
>>>>> On 05.08.17 21:31, Rob Clark wrote:
>>>>>> On Sat, Aug 5, 2017 at 4:05 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>>>>>>> On 08/05/2017 08:43 PM, Rob Clark wrote:
>>>>>>>> On Sat, Aug 5, 2017 at 1:06 PM, Rob Clark <robdclark@gmail.com> wrote:
>>>>>>>>> On Sat, Aug 5, 2017 at 12:52 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>>>>>>>>>> On 08/05/2017 06:16 PM, Rob Clark wrote:
>>>>>>>>>>> On Sat, Aug 5, 2017 at 12:12 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>>>>>>>>>>>> On 08/05/2017 05:58 PM, Rob Clark wrote:
>>>>>>>>>>>> Some arch's have trouble with unaligned accesses.  Technically
>>>>>>>>>>>> EFI device-path structs should be byte aligned, and the next node
>>>>>>>>>>>> in the path starts immediately after the previous.  Meaning that
>>>>>>>>>>>> a pointer to an 'struct efi_device_path' is not necessarily word
>>>>>>>>>>>> aligned.  See section 10.3.1 in v2.7 of UEFI spec.
>>>>>>>>>>>>
>>>>>>>>>>>> This causes problems not just for u-boot, but also most/all EFI
>>>>>>>>>>>> payloads loaded by u-boot on these archs.  Fortunately the common
>>>>>>>>>>>> practice for traversing a device path is to rely on the length
>>>>>>>>>>>> field in the header, rather than the specified length of the
>>>>>>>>>>>> particular device path type+subtype.  So the EFI_DP_PAD() macro
>>>>>>>>>>>> will add the specified number of bytes to the tail of device path
>>>>>>>>>>>> structs to pad them to word alignment.
>>>>>>>>>>>>
>>>>>>>>>>>> Technically this is non-compliant, BROKEN_UNALIGNED should *only*
>>>>>>>>>>>> be defined on archs that cannot do unaligned accesses.
>>>>>>>>>>>>
>>>>>>>>>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>>>>>>>>>>> ---
>>>>>>>>>>>> I'm not sure if there are other arch's that need -DBROKEN_UNALIGNED
>>>>>>>>>>>>
>>>>>>>>>>>> Mark, this is untested but I think it should solve your crash on the
>>>>>>>>>>>> Banana Pi.  Could you give it a try when you get a chance?
>>>>>>>>>>>>
>>>>>>>>>>>>  arch/arm/config.mk               |  2 +-
>>>>>>>>>>>>  include/efi_api.h                | 30 ++++++++++++++++++++++++++++++
>>>>>>>>>>>>  lib/efi_loader/efi_device_path.c |  3 +++
>>>>>>>>>>>>  3 files changed, 34 insertions(+), 1 deletion(-)
>>>>>>>>>>>>
>>>>>>>>>>>> diff --git a/arch/arm/config.mk b/arch/arm/config.mk
>>>>>>>>>>>> index 1a77779db4..067dc93a9d 100644
>>>>>>>>>>>> --- a/arch/arm/config.mk
>>>>>>>>>>>> +++ b/arch/arm/config.mk
>>>>>>>>>>>> @@ -28,7 +28,7 @@ LLVMS_RELFLAGS              := $(call cc-option,-mllvm,) \
>>>>>>>>>>>>                       $(call cc-option,-arm-use-movt=0,)
>>>>>>>>>>>>  PLATFORM_RELFLAGS    += $(LLVM_RELFLAGS)
>>>>>>>>>>>>
>>>>>>>>>>>> -PLATFORM_CPPFLAGS += -D__ARM__
>>>>>>>>>>>> +PLATFORM_CPPFLAGS += -D__ARM__ -DBROKEN_UNALIGNED
>>>>>>>>>>>
>>>>>>>>>>> NAK
>>>>>>>>>>>
>>>>>>>>>>> We have more then ARM. And other architectures also create exceptions
>>>>>>>>>>> for unaligned access.
>>>>>>>>>>>
>>>>>>>>>>> I hate platform specific code. It should not be used outside /arch.
>>>>>>>>>>>
>>>>>>>>>>> To play it save you should not use _packed at all!
>>>>>>>>>>> Use memcpy to transfer between aligned and unaligned memory.
>>>>>>>>>>
>>>>>>>>>> except for reasons I explained in the thread on the patch that added
>>>>>>>>>> the __packed in the first place.  Sorry, this is ugly but we have to
>>>>>>>>>> do it.
>>>>>>>>>>
>>>>>>>>>> BR,
>>>>>>>>>> -R
>>>>>>>>>
>>>>>>>>> According to the UEFI standard the nodes in paths are not to be assumed
>>>>>>>>> to be aligned.
>>>>>>>>>
>>>>>>>>> So even if you use padding bytes in paths that you pass to the EFI
>>>>>>>>> application you should not expect that the EFI application does the
>>>>>>>>> same. Expect the EFI application either to remove them or send new nodes
>>>>>>>>> without padding.
>>>>>>>>>
>>>>>>>>> To the idea of padding bytes and __packed does not make sense.
>>>>>>>>
>>>>>>>> Ok, to be fair, you are right about device-paths passed too u-boot.
>>>>>>>> On BROKEN_UNALIGNED archs, we should sanitise with a copy to an
>>>>>>>> aligned device-path in *addition* to what I proposed.  I can make a
>>>>>>>> patch to add a helper to do this a bit later.
>>>>>>>
>>>>>>> so thinking about this a bit, I have two options in mind:
>>>>>>>
>>>>>>>  + efi_dp_sanitize() + efi_dp_free() helpers that are no-ops on
>>>>>>>    archs that can do unaligned access, but efi_dp_sanitize() always
>>>>>>>    allocates and copies on BROKEN_UNALIGNED archs and efi_dp_free()
>>>>>>>    always free's on BROKEN_UNALIGNED archs, even if the dp passed
>>>>>>>    from efi payload doesn't require it.
>>>>>>>
>>>>>>>  + efi_dp_sanitize() that is no-op on archs that can do unaligned
>>>>>>>    access but only allocates/copies when passed a device path that
>>>>>>>    would result in unaligned access, plus hook some mechanism to
>>>>>>>    auto-free on EFI_EXIT().. which is slightly tricky w/ nesting of
>>>>>>>    efi calls, but not impossible and at least avoids the problem
>>>>>>>    of missing calls to free the dup'd device-path.. which is the
>>>>>>>    sort of leak I might miss since I'm not using EFI_LOADER on any
>>>>>>>    BROKEN_UNALIGNED arch
>>>>>>>
>>>>>>> anyone who cares about armv7 + efi have a preference between always
>>>>>>> doing an extra alloc+copy+free vs EFI_EXIT() magic?
>>>>>>>
>>>>>>
>>>>>> Please, go for the simplest code.
>>>>>
>>>>> well, the source of my question was there are two definitions of
>>>>> "simplest" here, ie "simplest to use" and "simplest helpers".. I'm
>>>>> mostly worried about future patches that use the helpers introducing
>>>>> leaks.  But actually I think a reasonable middle ground is "simplest
>>>>> helpers plus always make the helpers not no-ops for DEBUG builds"..
>>>>>
>>>>>> I cannot imagine that copying takes more than 10ms for starting grub on
>>>>>> any architecture. So the user will not notice it anyway.
>>>>>> Assume every architecture requiring alignment for which you do not have
>>>>>> proof of the contrary.
>>>>>>
>>>>>> Even on ARM64 there are op codes that fail without alignment.
>>>>>
>>>>> iirc the restrictions where mostly about device memory, and atomics.
>>>>> Which should not apply here.  (And we have aarch64 servers in
>>>>> production with grub, which doesn't take any protections about
>>>>> unaligned device-path nodes, using non u-boot EFI implementations.  So
>>>>> maybe that counts as proof to the contrary ;-))
>>>>
>>>> The UEFI spec mandates that unaligned access are fixed up properly
>>>> (usually by hardware). We violate the spec on 32bit ARM, but do fulfill
>>>> it on AArch64.
>>>
>>> Actually for AArch32 the spec says:
>>>
>>>  Unaligned access should be enabled if supported; Alignment faults
>>>  are enabled otherwise.
>>
>> It is a bit strange to me that alignment faults are disabled by
>> default, but presumably is disabled out of reset..  I don't totally
>> understand the connection to having mmu disabled, unless all memory is
>> treated like device memory without mmu enabled.  (Which, also,
>> wouldn't that be super-slow?)  But anyway, I guess that is a bit
>> beside the point.
>
> It is treated as device memory with mmu disabled, yes.
>

Yes, and this is really the only sane thing that can be done, given
that the page tables not only contain VA/PA translations (which I
guess U-boot, like UEFI, does not use), but also the memory types of
the various regions. So without page tables, the CPU has no clue which
accesses it can cache (to memory) and which accesses it cannot (to
devices).

Actually, my recommendation is to always run non-trivial code (i.e., C
code) with caching enabled. In UEFI, we do rely on -mno-unaligned
access (or -mstrict-align) to ensure the C code does not get optimized
to use uncached accesses, but as Alex pointed out, this is not a
complete solution.

>>
>>> So UEFI payload that wants to support pre-ARMv7 hardware should make
>>> sure it doesn't do any unaligned access.
>>>
>>>> The reason things worked before really was just that both U-Boot and
>>>> grub were compiled with -mno-unaligned-access, so they never issued
>>>> unaligned accesses.
>>>
>>> That in itself is not enough to prevent unaligned access.  If you
>>> explicitly cast an unaligned pointer to say (uint32_t *) and then
>>> dereference it, you'll create an unaligned access.
>>
>> This is problematic around file nodes in the device path.  Adding the
>> padding bytes to the end of each device-path struct would "solve"
>> that, and if pre-aarch64 we are aiming at "good enough to work", I
>> kinda think that this the approach we should go for.  Other than
>> file-path nodes, the rest of the issues in u-boot should be solved by
>> addition of missing __packed on 'struct efi_device_path' (which I've
>> added locally and will be in the next revision of the patchset).
>
> Let's ask Leif and Ard if that is actually correct. If I remember correctly, edk2 some times leverages automatic padding from the compiler on structs.
>

I guess that that might work, if U-boot is the only agent
instantiating device path structures. But what do you mean by
'correct' in this context?

>>
>>>> Which system broke for Mark? Banana pi mostly has 32bit SBCs, so I
>>>> assume it's one of those? In that case, we would need to either
>>>>
>>>>   1) hack up the openbsd loader to also get compiled with
>>>> -mno-unaligned-access
>>>>
>>>> or
>>>>
>>>>   2) rework the 32bit arm mmu code to enable the MMU plus hardware
>>>> unaligned fixups on all systems. (that's a *lot* of work)
>>>
>>> The system that broke was Cortex-A7 based, so ARMv7.
>>>
>>> *However*, the OpenBSD bootloader does not perform any unaligned
>>> access.  *All* cases of unaligned access that I encountered while
>>> testing/debugging Rob's code were in U-Boot itself.  This was mostly a
>>> consequence from a diff in the series that added __packed to the
>>> device path node structs and then passed members of those structs to
>>> functions that accessed the contents of tose (now byte aligned
>>> structs) through (uint16_t *) or (uint32_t *) pointers.
>>
>> Yeah.. the padding byte approach I suggested would solve this.  Not
>> *really* compliant, but should work for all the payload code I've come
>> across.  We definitely shouldn't enable the padding bytes on aarch64,
>> but I think padding bytes would be a pragmatic solution for armv7 and
>> earlier.  (And hopefully someday someone enables mmu on armv7 so we
>> can turn off the hack there too.)
>
> The problem really is inconsistency. Some 32bit arm platforms enable the mmu, some don't.
>
>>
>>> There was initially some confusion because I used the pc reported by
>>> U-Boot to look up the faulting instruction whereas I should have been
>>> using the reloc_pc.
>>>
>>> I think Rob is worried about grub/shim/fallback.efi doing unaligned
>>> access of device path nodes on armv7.  But I'm not sure he has any
>>> evidence beyond looking at code.
>>
>> It will definitely be an issue (if grub/shim/fallback were not
>> compiled with -mno-unaligned-access) in some of the debug code that
>> prints out device-paths.  I haven't checked the compiler flags used w/
>> shim/fallback.
>>
>> Parsing MEDIA_DEVICE:HARD_DRIVE nodes would be an issue regardless
>> without -mno-unaligned-access, although we might be getting lucky by
>> just not hitting debug paths.  Some of the other issues would be
>> hidden by padding bytes at the end of the DP structs which would keep
>> the file-path nodes word aligned.
>>
>>>> To me personally, UEFI in 32bit ARM land is a nice to have standardized
>>>> platform, but not something where we really need to be fully standards
>>>> compliant in every aspect. I think "making things work" is good enough
>>>> there.
>>>
>>> Right.  For us UEFI us just a convenient way to re-use the U-Boot
>>> device driver code to load a kernel from a UFS/FFS filesystem.
>>>
>>>> For AArch64 things are different. There we should strive for full UEFI
>>>> compliance as it's "the future" :).
>>>
>>> Even there just making things work would be good enough for me ;).
>>> Our AArach64 bootloader is almost identical to the AArch32 one and
>>> works on a real UEFI implementation as well (SoftIron Overdrive 1000).
>>>
>>
>> I think we should make the aarch64 implementation fully compliant (ie.
>> addition of missing __packed's and no extra padding bytes).  I won't
>> loose sleep if some efi payloads don't work on pre-aarch64 (we should
>> be able to keep things that were working before working).  If adding
>> missing __packed breaks things on platforms that can't do unaligned
>> access, the solution is not to remove __packed, but to conditionally
>> add padding bytes at the end of the struct.  That way we keep things
>> working as before on the old platforms, but make things work correctly
>> on aarch64.
>>
>> I'll add back my patch for EFI_DP_PAD() to this patchset, since this
>> seems like the sensible way forward.
>
> Let's make sure we get an ack from Leif/Ard for that approach :)
>
>
> Alex
>
>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
  2017-08-08  6:52                       ` Alexander Graf
  2017-08-08  8:11                         ` Ard Biesheuvel
@ 2017-08-08  9:27                         ` Rob Clark
  1 sibling, 0 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-08  9:27 UTC (permalink / raw)
  To: u-boot

On Tue, Aug 8, 2017 at 2:52 AM, Alexander Graf <agraf@suse.de> wrote:
>
>
>> Am 07.08.2017 um 23:18 schrieb Rob Clark <robdclark@gmail.com>:
>>
>> On Mon, Aug 7, 2017 at 5:14 PM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>>>> From: Alexander Graf <agraf@suse.de>
>>>> Date: Mon, 7 Aug 2017 21:19:37 +0100
>>>>
>>>>> On 05.08.17 21:31, Rob Clark wrote:
>>>>>> On Sat, Aug 5, 2017 at 4:05 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>>>>>>> On 08/05/2017 08:43 PM, Rob Clark wrote:
>>>>>>>> On Sat, Aug 5, 2017 at 1:06 PM, Rob Clark <robdclark@gmail.com> wrote:
>>>>>>>>> On Sat, Aug 5, 2017 at 12:52 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>>>>>>>>>> On 08/05/2017 06:16 PM, Rob Clark wrote:
>>>>>>>>>>> On Sat, Aug 5, 2017 at 12:12 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>>>>>>>>>>>> On 08/05/2017 05:58 PM, Rob Clark wrote:
>>>>>>>>>>>> Some arch's have trouble with unaligned accesses.  Technically
>>>>>>>>>>>> EFI device-path structs should be byte aligned, and the next node
>>>>>>>>>>>> in the path starts immediately after the previous.  Meaning that
>>>>>>>>>>>> a pointer to an 'struct efi_device_path' is not necessarily word
>>>>>>>>>>>> aligned.  See section 10.3.1 in v2.7 of UEFI spec.
>>>>>>>>>>>>
>>>>>>>>>>>> This causes problems not just for u-boot, but also most/all EFI
>>>>>>>>>>>> payloads loaded by u-boot on these archs.  Fortunately the common
>>>>>>>>>>>> practice for traversing a device path is to rely on the length
>>>>>>>>>>>> field in the header, rather than the specified length of the
>>>>>>>>>>>> particular device path type+subtype.  So the EFI_DP_PAD() macro
>>>>>>>>>>>> will add the specified number of bytes to the tail of device path
>>>>>>>>>>>> structs to pad them to word alignment.
>>>>>>>>>>>>
>>>>>>>>>>>> Technically this is non-compliant, BROKEN_UNALIGNED should *only*
>>>>>>>>>>>> be defined on archs that cannot do unaligned accesses.
>>>>>>>>>>>>
>>>>>>>>>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>>>>>>>>>>> ---
>>>>>>>>>>>> I'm not sure if there are other arch's that need -DBROKEN_UNALIGNED
>>>>>>>>>>>>
>>>>>>>>>>>> Mark, this is untested but I think it should solve your crash on the
>>>>>>>>>>>> Banana Pi.  Could you give it a try when you get a chance?
>>>>>>>>>>>>
>>>>>>>>>>>>  arch/arm/config.mk               |  2 +-
>>>>>>>>>>>>  include/efi_api.h                | 30 ++++++++++++++++++++++++++++++
>>>>>>>>>>>>  lib/efi_loader/efi_device_path.c |  3 +++
>>>>>>>>>>>>  3 files changed, 34 insertions(+), 1 deletion(-)
>>>>>>>>>>>>
>>>>>>>>>>>> diff --git a/arch/arm/config.mk b/arch/arm/config.mk
>>>>>>>>>>>> index 1a77779db4..067dc93a9d 100644
>>>>>>>>>>>> --- a/arch/arm/config.mk
>>>>>>>>>>>> +++ b/arch/arm/config.mk
>>>>>>>>>>>> @@ -28,7 +28,7 @@ LLVMS_RELFLAGS              := $(call cc-option,-mllvm,) \
>>>>>>>>>>>>                       $(call cc-option,-arm-use-movt=0,)
>>>>>>>>>>>>  PLATFORM_RELFLAGS    += $(LLVM_RELFLAGS)
>>>>>>>>>>>>
>>>>>>>>>>>> -PLATFORM_CPPFLAGS += -D__ARM__
>>>>>>>>>>>> +PLATFORM_CPPFLAGS += -D__ARM__ -DBROKEN_UNALIGNED
>>>>>>>>>>>
>>>>>>>>>>> NAK
>>>>>>>>>>>
>>>>>>>>>>> We have more then ARM. And other architectures also create exceptions
>>>>>>>>>>> for unaligned access.
>>>>>>>>>>>
>>>>>>>>>>> I hate platform specific code. It should not be used outside /arch.
>>>>>>>>>>>
>>>>>>>>>>> To play it save you should not use _packed at all!
>>>>>>>>>>> Use memcpy to transfer between aligned and unaligned memory.
>>>>>>>>>>
>>>>>>>>>> except for reasons I explained in the thread on the patch that added
>>>>>>>>>> the __packed in the first place.  Sorry, this is ugly but we have to
>>>>>>>>>> do it.
>>>>>>>>>>
>>>>>>>>>> BR,
>>>>>>>>>> -R
>>>>>>>>>
>>>>>>>>> According to the UEFI standard the nodes in paths are not to be assumed
>>>>>>>>> to be aligned.
>>>>>>>>>
>>>>>>>>> So even if you use padding bytes in paths that you pass to the EFI
>>>>>>>>> application you should not expect that the EFI application does the
>>>>>>>>> same. Expect the EFI application either to remove them or send new nodes
>>>>>>>>> without padding.
>>>>>>>>>
>>>>>>>>> To the idea of padding bytes and __packed does not make sense.
>>>>>>>>
>>>>>>>> Ok, to be fair, you are right about device-paths passed too u-boot.
>>>>>>>> On BROKEN_UNALIGNED archs, we should sanitise with a copy to an
>>>>>>>> aligned device-path in *addition* to what I proposed.  I can make a
>>>>>>>> patch to add a helper to do this a bit later.
>>>>>>>
>>>>>>> so thinking about this a bit, I have two options in mind:
>>>>>>>
>>>>>>>  + efi_dp_sanitize() + efi_dp_free() helpers that are no-ops on
>>>>>>>    archs that can do unaligned access, but efi_dp_sanitize() always
>>>>>>>    allocates and copies on BROKEN_UNALIGNED archs and efi_dp_free()
>>>>>>>    always free's on BROKEN_UNALIGNED archs, even if the dp passed
>>>>>>>    from efi payload doesn't require it.
>>>>>>>
>>>>>>>  + efi_dp_sanitize() that is no-op on archs that can do unaligned
>>>>>>>    access but only allocates/copies when passed a device path that
>>>>>>>    would result in unaligned access, plus hook some mechanism to
>>>>>>>    auto-free on EFI_EXIT().. which is slightly tricky w/ nesting of
>>>>>>>    efi calls, but not impossible and at least avoids the problem
>>>>>>>    of missing calls to free the dup'd device-path.. which is the
>>>>>>>    sort of leak I might miss since I'm not using EFI_LOADER on any
>>>>>>>    BROKEN_UNALIGNED arch
>>>>>>>
>>>>>>> anyone who cares about armv7 + efi have a preference between always
>>>>>>> doing an extra alloc+copy+free vs EFI_EXIT() magic?
>>>>>>>
>>>>>>
>>>>>> Please, go for the simplest code.
>>>>>
>>>>> well, the source of my question was there are two definitions of
>>>>> "simplest" here, ie "simplest to use" and "simplest helpers".. I'm
>>>>> mostly worried about future patches that use the helpers introducing
>>>>> leaks.  But actually I think a reasonable middle ground is "simplest
>>>>> helpers plus always make the helpers not no-ops for DEBUG builds"..
>>>>>
>>>>>> I cannot imagine that copying takes more than 10ms for starting grub on
>>>>>> any architecture. So the user will not notice it anyway.
>>>>>> Assume every architecture requiring alignment for which you do not have
>>>>>> proof of the contrary.
>>>>>>
>>>>>> Even on ARM64 there are op codes that fail without alignment.
>>>>>
>>>>> iirc the restrictions where mostly about device memory, and atomics.
>>>>> Which should not apply here.  (And we have aarch64 servers in
>>>>> production with grub, which doesn't take any protections about
>>>>> unaligned device-path nodes, using non u-boot EFI implementations.  So
>>>>> maybe that counts as proof to the contrary ;-))
>>>>
>>>> The UEFI spec mandates that unaligned access are fixed up properly
>>>> (usually by hardware). We violate the spec on 32bit ARM, but do fulfill
>>>> it on AArch64.
>>>
>>> Actually for AArch32 the spec says:
>>>
>>>  Unaligned access should be enabled if supported; Alignment faults
>>>  are enabled otherwise.
>>
>> It is a bit strange to me that alignment faults are disabled by
>> default, but presumably is disabled out of reset..  I don't totally
>> understand the connection to having mmu disabled, unless all memory is
>> treated like device memory without mmu enabled.  (Which, also,
>> wouldn't that be super-slow?)  But anyway, I guess that is a bit
>> beside the point.
>
> It is treated as device memory with mmu disabled, yes.
>
>>
>>> So UEFI payload that wants to support pre-ARMv7 hardware should make
>>> sure it doesn't do any unaligned access.
>>>
>>>> The reason things worked before really was just that both U-Boot and
>>>> grub were compiled with -mno-unaligned-access, so they never issued
>>>> unaligned accesses.
>>>
>>> That in itself is not enough to prevent unaligned access.  If you
>>> explicitly cast an unaligned pointer to say (uint32_t *) and then
>>> dereference it, you'll create an unaligned access.
>>
>> This is problematic around file nodes in the device path.  Adding the
>> padding bytes to the end of each device-path struct would "solve"
>> that, and if pre-aarch64 we are aiming at "good enough to work", I
>> kinda think that this the approach we should go for.  Other than
>> file-path nodes, the rest of the issues in u-boot should be solved by
>> addition of missing __packed on 'struct efi_device_path' (which I've
>> added locally and will be in the next revision of the patchset).
>
> Let's ask Leif and Ard if that is actually correct. If I remember correctly, edk2 some times leverages automatic padding from the compiler on structs.
>

in edk2's DevicePath.h it does '#pragma pack(1)' before all the device
path structs (aka equiv of adding packed attribute to each struct) and
then '#pragma pack()' after (disabling the packing)

Also, fwiw I couldn't find anywhere in edk2 that was enabling
alignment faults, but probably they have the mmu enabled and
configured 1:1 similar to aarch64 in u-boot.

BR,
-R

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
  2017-08-08  8:11                         ` Ard Biesheuvel
@ 2017-08-08 11:32                           ` Leif Lindholm
  2017-08-08 12:01                             ` Rob Clark
  0 siblings, 1 reply; 116+ messages in thread
From: Leif Lindholm @ 2017-08-08 11:32 UTC (permalink / raw)
  To: u-boot

On Tue, Aug 08, 2017 at 09:11:14AM +0100, Ard Biesheuvel wrote:
> On 8 August 2017 at 07:52, Alexander Graf <agraf@suse.de> wrote:
> >
> >
> >> Am 07.08.2017 um 23:18 schrieb Rob Clark <robdclark@gmail.com>:
> >>
> >> On Mon, Aug 7, 2017 at 5:14 PM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
> >>>> From: Alexander Graf <agraf@suse.de>
> >>>> Date: Mon, 7 Aug 2017 21:19:37 +0100
> >>>>
> >>>>> On 05.08.17 21:31, Rob Clark wrote:
> >>>>>> On Sat, Aug 5, 2017 at 4:05 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
> >>>>>>> On 08/05/2017 08:43 PM, Rob Clark wrote:
> >>>>>>>> On Sat, Aug 5, 2017 at 1:06 PM, Rob Clark <robdclark@gmail.com> wrote:
> >>>>>>>>> On Sat, Aug 5, 2017 at 12:52 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
> >>>>>>>>>> On 08/05/2017 06:16 PM, Rob Clark wrote:
> >>>>>>>>>>> On Sat, Aug 5, 2017 at 12:12 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
> >>>>>>>>>>>> On 08/05/2017 05:58 PM, Rob Clark wrote:
> >>>>>>>>>>>> Some arch's have trouble with unaligned accesses.  Technically
> >>>>>>>>>>>> EFI device-path structs should be byte aligned, and the next node
> >>>>>>>>>>>> in the path starts immediately after the previous.  Meaning that
> >>>>>>>>>>>> a pointer to an 'struct efi_device_path' is not necessarily word
> >>>>>>>>>>>> aligned.  See section 10.3.1 in v2.7 of UEFI spec.
> >>>>>>>>>>>>
> >>>>>>>>>>>> This causes problems not just for u-boot, but also most/all EFI
> >>>>>>>>>>>> payloads loaded by u-boot on these archs.  Fortunately the common
> >>>>>>>>>>>> practice for traversing a device path is to rely on the length
> >>>>>>>>>>>> field in the header, rather than the specified length of the
> >>>>>>>>>>>> particular device path type+subtype.  So the EFI_DP_PAD() macro
> >>>>>>>>>>>> will add the specified number of bytes to the tail of device path
> >>>>>>>>>>>> structs to pad them to word alignment.
> >>>>>>>>>>>>
> >>>>>>>>>>>> Technically this is non-compliant, BROKEN_UNALIGNED should *only*
> >>>>>>>>>>>> be defined on archs that cannot do unaligned accesses.
> >>>>>>>>>>>>
> >>>>>>>>>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
> >>>>>>>>>>>> ---
> >>>>>>>>>>>> I'm not sure if there are other arch's that need -DBROKEN_UNALIGNED
> >>>>>>>>>>>>
> >>>>>>>>>>>> Mark, this is untested but I think it should solve your crash on the
> >>>>>>>>>>>> Banana Pi.  Could you give it a try when you get a chance?
> >>>>>>>>>>>>
> >>>>>>>>>>>>  arch/arm/config.mk               |  2 +-
> >>>>>>>>>>>>  include/efi_api.h                | 30 ++++++++++++++++++++++++++++++
> >>>>>>>>>>>>  lib/efi_loader/efi_device_path.c |  3 +++
> >>>>>>>>>>>>  3 files changed, 34 insertions(+), 1 deletion(-)
> >>>>>>>>>>>>
> >>>>>>>>>>>> diff --git a/arch/arm/config.mk b/arch/arm/config.mk
> >>>>>>>>>>>> index 1a77779db4..067dc93a9d 100644
> >>>>>>>>>>>> --- a/arch/arm/config.mk
> >>>>>>>>>>>> +++ b/arch/arm/config.mk
> >>>>>>>>>>>> @@ -28,7 +28,7 @@ LLVMS_RELFLAGS              := $(call cc-option,-mllvm,) \
> >>>>>>>>>>>>                       $(call cc-option,-arm-use-movt=0,)
> >>>>>>>>>>>>  PLATFORM_RELFLAGS    += $(LLVM_RELFLAGS)
> >>>>>>>>>>>>
> >>>>>>>>>>>> -PLATFORM_CPPFLAGS += -D__ARM__
> >>>>>>>>>>>> +PLATFORM_CPPFLAGS += -D__ARM__ -DBROKEN_UNALIGNED
> >>>>>>>>>>>
> >>>>>>>>>>> NAK
> >>>>>>>>>>>
> >>>>>>>>>>> We have more then ARM. And other architectures also create exceptions
> >>>>>>>>>>> for unaligned access.
> >>>>>>>>>>>
> >>>>>>>>>>> I hate platform specific code. It should not be used outside /arch.
> >>>>>>>>>>>
> >>>>>>>>>>> To play it save you should not use _packed at all!
> >>>>>>>>>>> Use memcpy to transfer between aligned and unaligned memory.
> >>>>>>>>>>
> >>>>>>>>>> except for reasons I explained in the thread on the patch that added
> >>>>>>>>>> the __packed in the first place.  Sorry, this is ugly but we have to
> >>>>>>>>>> do it.
> >>>>>>>>>>
> >>>>>>>>>> BR,
> >>>>>>>>>> -R
> >>>>>>>>>
> >>>>>>>>> According to the UEFI standard the nodes in paths are not to be assumed
> >>>>>>>>> to be aligned.
> >>>>>>>>>
> >>>>>>>>> So even if you use padding bytes in paths that you pass to the EFI
> >>>>>>>>> application you should not expect that the EFI application does the
> >>>>>>>>> same. Expect the EFI application either to remove them or send new nodes
> >>>>>>>>> without padding.
> >>>>>>>>>
> >>>>>>>>> To the idea of padding bytes and __packed does not make sense.
> >>>>>>>>
> >>>>>>>> Ok, to be fair, you are right about device-paths passed too u-boot.
> >>>>>>>> On BROKEN_UNALIGNED archs, we should sanitise with a copy to an
> >>>>>>>> aligned device-path in *addition* to what I proposed.  I can make a
> >>>>>>>> patch to add a helper to do this a bit later.
> >>>>>>>
> >>>>>>> so thinking about this a bit, I have two options in mind:
> >>>>>>>
> >>>>>>>  + efi_dp_sanitize() + efi_dp_free() helpers that are no-ops on
> >>>>>>>    archs that can do unaligned access, but efi_dp_sanitize() always
> >>>>>>>    allocates and copies on BROKEN_UNALIGNED archs and efi_dp_free()
> >>>>>>>    always free's on BROKEN_UNALIGNED archs, even if the dp passed
> >>>>>>>    from efi payload doesn't require it.
> >>>>>>>
> >>>>>>>  + efi_dp_sanitize() that is no-op on archs that can do unaligned
> >>>>>>>    access but only allocates/copies when passed a device path that
> >>>>>>>    would result in unaligned access, plus hook some mechanism to
> >>>>>>>    auto-free on EFI_EXIT().. which is slightly tricky w/ nesting of
> >>>>>>>    efi calls, but not impossible and at least avoids the problem
> >>>>>>>    of missing calls to free the dup'd device-path.. which is the
> >>>>>>>    sort of leak I might miss since I'm not using EFI_LOADER on any
> >>>>>>>    BROKEN_UNALIGNED arch
> >>>>>>>
> >>>>>>> anyone who cares about armv7 + efi have a preference between always
> >>>>>>> doing an extra alloc+copy+free vs EFI_EXIT() magic?
> >>>>>>>
> >>>>>>
> >>>>>> Please, go for the simplest code.
> >>>>>
> >>>>> well, the source of my question was there are two definitions of
> >>>>> "simplest" here, ie "simplest to use" and "simplest helpers".. I'm
> >>>>> mostly worried about future patches that use the helpers introducing
> >>>>> leaks.  But actually I think a reasonable middle ground is "simplest
> >>>>> helpers plus always make the helpers not no-ops for DEBUG builds"..
> >>>>>
> >>>>>> I cannot imagine that copying takes more than 10ms for starting grub on
> >>>>>> any architecture. So the user will not notice it anyway.
> >>>>>> Assume every architecture requiring alignment for which you do not have
> >>>>>> proof of the contrary.
> >>>>>>
> >>>>>> Even on ARM64 there are op codes that fail without alignment.
> >>>>>
> >>>>> iirc the restrictions where mostly about device memory, and atomics.
> >>>>> Which should not apply here.  (And we have aarch64 servers in
> >>>>> production with grub, which doesn't take any protections about
> >>>>> unaligned device-path nodes, using non u-boot EFI implementations.  So
> >>>>> maybe that counts as proof to the contrary ;-))
> >>>>
> >>>> The UEFI spec mandates that unaligned access are fixed up properly
> >>>> (usually by hardware). We violate the spec on 32bit ARM, but do fulfill
> >>>> it on AArch64.
> >>>
> >>> Actually for AArch32 the spec says:
> >>>
> >>>  Unaligned access should be enabled if supported; Alignment faults
> >>>  are enabled otherwise.
> >>
> >> It is a bit strange to me that alignment faults are disabled by
> >> default, but presumably is disabled out of reset..  I don't totally
> >> understand the connection to having mmu disabled, unless all memory is
> >> treated like device memory without mmu enabled.  (Which, also,
> >> wouldn't that be super-slow?)  But anyway, I guess that is a bit
> >> beside the point.
> >
> > It is treated as device memory with mmu disabled, yes.
> >
> 
> Yes, and this is really the only sane thing that can be done, given
> that the page tables not only contain VA/PA translations (which I
> guess U-boot, like UEFI, does not use), but also the memory types of
> the various regions. So without page tables, the CPU has no clue which
> accesses it can cache (to memory) and which accesses it cannot (to
> devices).
> 
> Actually, my recommendation is to always run non-trivial code (i.e., C
> code) with caching enabled. In UEFI, we do rely on -mno-unaligned
> access (or -mstrict-align) to ensure the C code does not get optimized
> to use uncached accesses, but as Alex pointed out, this is not a
> complete solution.

To nitpick: in EDK2, we rely on -mstrict-align/-mno-unaligned-access
in the PEI (Pre-EFI Initilization) phase. Once we present a
UEFI-compliant interface, unaligned accesses are used.

> >>> So UEFI payload that wants to support pre-ARMv7 hardware should make
> >>> sure it doesn't do any unaligned access.
> >>>
> >>>> The reason things worked before really was just that both U-Boot and
> >>>> grub were compiled with -mno-unaligned-access, so they never issued
> >>>> unaligned accesses.
> >>>
> >>> That in itself is not enough to prevent unaligned access.  If you
> >>> explicitly cast an unaligned pointer to say (uint32_t *) and then
> >>> dereference it, you'll create an unaligned access.
> >>
> >> This is problematic around file nodes in the device path.  Adding the
> >> padding bytes to the end of each device-path struct would "solve"
> >> that, and if pre-aarch64 we are aiming at "good enough to work", I
> >> kinda think that this the approach we should go for.  Other than
> >> file-path nodes, the rest of the issues in u-boot should be solved by
> >> addition of missing __packed on 'struct efi_device_path' (which I've
> >> added locally and will be in the next revision of the patchset).
> >
> > Let's ask Leif and Ard if that is actually correct. If I remember
> > correctly, edk2 some times leverages automatic padding from the
> > compiler on structs.
> 
> I guess that that might work, if U-boot is the only agent
> instantiating device path structures. But what do you mean by
> 'correct' in this context?

Well, if that is the case, are we risking the ability to in the future
support loading drivers or protocols at runtime. (This would for
example exclude Shim compatibility or running the UEFI Shell.)

/
    Leif

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
  2017-08-08 11:32                           ` Leif Lindholm
@ 2017-08-08 12:01                             ` Rob Clark
  2017-08-08 12:39                               ` Leif Lindholm
  0 siblings, 1 reply; 116+ messages in thread
From: Rob Clark @ 2017-08-08 12:01 UTC (permalink / raw)
  To: u-boot

On Tue, Aug 8, 2017 at 7:32 AM, Leif Lindholm <leif.lindholm@linaro.org> wrote:
> On Tue, Aug 08, 2017 at 09:11:14AM +0100, Ard Biesheuvel wrote:
>> On 8 August 2017 at 07:52, Alexander Graf <agraf@suse.de> wrote:
>> >
>> >
>> >> Am 07.08.2017 um 23:18 schrieb Rob Clark <robdclark@gmail.com>:
>> >>
>> >> This is problematic around file nodes in the device path.  Adding the
>> >> padding bytes to the end of each device-path struct would "solve"
>> >> that, and if pre-aarch64 we are aiming at "good enough to work", I
>> >> kinda think that this the approach we should go for.  Other than
>> >> file-path nodes, the rest of the issues in u-boot should be solved by
>> >> addition of missing __packed on 'struct efi_device_path' (which I've
>> >> added locally and will be in the next revision of the patchset).
>> >
>> > Let's ask Leif and Ard if that is actually correct. If I remember
>> > correctly, edk2 some times leverages automatic padding from the
>> > compiler on structs.
>>
>> I guess that that might work, if U-boot is the only agent
>> instantiating device path structures. But what do you mean by
>> 'correct' in this context?
>
> Well, if that is the case, are we risking the ability to in the future
> support loading drivers or protocols at runtime. (This would for
> example exclude Shim compatibility or running the UEFI Shell.)
>

My proposal (and this is only for <=armv6 and armv7 until someone gets
around to enabling mmu and disabling alignment faults) is to add
padding bytes at the end of the various device-path structs to at
least keep the structs (and things like utf16 string in file-path
struct) aligned, and rely on efi payload and u-boot to be compiled
with -mno-unaligned-access if it needs to access fields within the
device-path structs.

This is *essentially* what u-boot does implicitly at the moment (by
missing __packed attribute on certain structs).  I want to fix that on
aarch64, but without the padding bytes it causes a some unaligned
accesses in u-boot on armv7 devices.

I think the goal for armv7 is more to have enough uefi for grub and
OpenBSD's bootloader.  If fancy things like loading drivers and
protocols@runtime doesn't work, well these didn't work before so I
won't loose much sleep.  But I would like that to work properly on
aarch64.

BR,
-R

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
  2017-08-07 22:18                     ` Rob Clark
  2017-08-08  6:52                       ` Alexander Graf
@ 2017-08-08 12:26                       ` Mark Kettenis
  2017-08-08 12:54                         ` Rob Clark
  1 sibling, 1 reply; 116+ messages in thread
From: Mark Kettenis @ 2017-08-08 12:26 UTC (permalink / raw)
  To: u-boot

> From: Rob Clark <robdclark@gmail.com>
> Date: Mon, 7 Aug 2017 18:18:50 -0400
> 
> On Mon, Aug 7, 2017 at 5:14 PM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
> >> From: Alexander Graf <agraf@suse.de>
> >> Date: Mon, 7 Aug 2017 21:19:37 +0100
> >>
> >> On 05.08.17 21:31, Rob Clark wrote:
> >> > On Sat, Aug 5, 2017 at 4:05 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
> >> >> On 08/05/2017 08:43 PM, Rob Clark wrote:
> >> >>> On Sat, Aug 5, 2017 at 1:06 PM, Rob Clark <robdclark@gmail.com> wrote:
> >> >>>> On Sat, Aug 5, 2017 at 12:52 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
> >> >>>>> On 08/05/2017 06:16 PM, Rob Clark wrote:
> >> >>>>>> On Sat, Aug 5, 2017 at 12:12 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
> >> >>>>>>> On 08/05/2017 05:58 PM, Rob Clark wrote:
> >> >>>>>>>> Some arch's have trouble with unaligned accesses.  Technically
> >> >>>>>>>> EFI device-path structs should be byte aligned, and the next node
> >> >>>>>>>> in the path starts immediately after the previous.  Meaning that
> >> >>>>>>>> a pointer to an 'struct efi_device_path' is not necessarily word
> >> >>>>>>>> aligned.  See section 10.3.1 in v2.7 of UEFI spec.
> >> >>>>>>>>
> >> >>>>>>>> This causes problems not just for u-boot, but also most/all EFI
> >> >>>>>>>> payloads loaded by u-boot on these archs.  Fortunately the common
> >> >>>>>>>> practice for traversing a device path is to rely on the length
> >> >>>>>>>> field in the header, rather than the specified length of the
> >> >>>>>>>> particular device path type+subtype.  So the EFI_DP_PAD() macro
> >> >>>>>>>> will add the specified number of bytes to the tail of device path
> >> >>>>>>>> structs to pad them to word alignment.
> >> >>>>>>>>
> >> >>>>>>>> Technically this is non-compliant, BROKEN_UNALIGNED should *only*
> >> >>>>>>>> be defined on archs that cannot do unaligned accesses.
> >> >>>>>>>>
> >> >>>>>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
> >> >>>>>>>> ---
> >> >>>>>>>> I'm not sure if there are other arch's that need -DBROKEN_UNALIGNED
> >> >>>>>>>>
> >> >>>>>>>> Mark, this is untested but I think it should solve your crash on the
> >> >>>>>>>> Banana Pi.  Could you give it a try when you get a chance?
> >> >>>>>>>>
> >> >>>>>>>>   arch/arm/config.mk               |  2 +-
> >> >>>>>>>>   include/efi_api.h                | 30 ++++++++++++++++++++++++++++++
> >> >>>>>>>>   lib/efi_loader/efi_device_path.c |  3 +++
> >> >>>>>>>>   3 files changed, 34 insertions(+), 1 deletion(-)
> >> >>>>>>>>
> >> >>>>>>>> diff --git a/arch/arm/config.mk b/arch/arm/config.mk
> >> >>>>>>>> index 1a77779db4..067dc93a9d 100644
> >> >>>>>>>> --- a/arch/arm/config.mk
> >> >>>>>>>> +++ b/arch/arm/config.mk
> >> >>>>>>>> @@ -28,7 +28,7 @@ LLVMS_RELFLAGS              := $(call cc-option,-mllvm,) \
> >> >>>>>>>>                        $(call cc-option,-arm-use-movt=0,)
> >> >>>>>>>>   PLATFORM_RELFLAGS    += $(LLVM_RELFLAGS)
> >> >>>>>>>>
> >> >>>>>>>> -PLATFORM_CPPFLAGS += -D__ARM__
> >> >>>>>>>> +PLATFORM_CPPFLAGS += -D__ARM__ -DBROKEN_UNALIGNED
> >> >>>>>>>
> >> >>>>>>> NAK
> >> >>>>>>>
> >> >>>>>>> We have more then ARM. And other architectures also create exceptions
> >> >>>>>>> for unaligned access.
> >> >>>>>>>
> >> >>>>>>> I hate platform specific code. It should not be used outside /arch.
> >> >>>>>>>
> >> >>>>>>> To play it save you should not use _packed at all!
> >> >>>>>>> Use memcpy to transfer between aligned and unaligned memory.
> >> >>>>>>
> >> >>>>>> except for reasons I explained in the thread on the patch that added
> >> >>>>>> the __packed in the first place.  Sorry, this is ugly but we have to
> >> >>>>>> do it.
> >> >>>>>>
> >> >>>>>> BR,
> >> >>>>>> -R
> >> >>>>>
> >> >>>>> According to the UEFI standard the nodes in paths are not to be assumed
> >> >>>>> to be aligned.
> >> >>>>>
> >> >>>>> So even if you use padding bytes in paths that you pass to the EFI
> >> >>>>> application you should not expect that the EFI application does the
> >> >>>>> same. Expect the EFI application either to remove them or send new nodes
> >> >>>>> without padding.
> >> >>>>>
> >> >>>>> To the idea of padding bytes and __packed does not make sense.
> >> >>>>
> >> >>>> Ok, to be fair, you are right about device-paths passed too u-boot.
> >> >>>> On BROKEN_UNALIGNED archs, we should sanitise with a copy to an
> >> >>>> aligned device-path in *addition* to what I proposed.  I can make a
> >> >>>> patch to add a helper to do this a bit later.
> >> >>>
> >> >>> so thinking about this a bit, I have two options in mind:
> >> >>>
> >> >>>   + efi_dp_sanitize() + efi_dp_free() helpers that are no-ops on
> >> >>>     archs that can do unaligned access, but efi_dp_sanitize() always
> >> >>>     allocates and copies on BROKEN_UNALIGNED archs and efi_dp_free()
> >> >>>     always free's on BROKEN_UNALIGNED archs, even if the dp passed
> >> >>>     from efi payload doesn't require it.
> >> >>>
> >> >>>   + efi_dp_sanitize() that is no-op on archs that can do unaligned
> >> >>>     access but only allocates/copies when passed a device path that
> >> >>>     would result in unaligned access, plus hook some mechanism to
> >> >>>     auto-free on EFI_EXIT().. which is slightly tricky w/ nesting of
> >> >>>     efi calls, but not impossible and at least avoids the problem
> >> >>>     of missing calls to free the dup'd device-path.. which is the
> >> >>>     sort of leak I might miss since I'm not using EFI_LOADER on any
> >> >>>     BROKEN_UNALIGNED arch
> >> >>>
> >> >>> anyone who cares about armv7 + efi have a preference between always
> >> >>> doing an extra alloc+copy+free vs EFI_EXIT() magic?
> >> >>>
> >> >>
> >> >> Please, go for the simplest code.
> >> >
> >> > well, the source of my question was there are two definitions of
> >> > "simplest" here, ie "simplest to use" and "simplest helpers".. I'm
> >> > mostly worried about future patches that use the helpers introducing
> >> > leaks.  But actually I think a reasonable middle ground is "simplest
> >> > helpers plus always make the helpers not no-ops for DEBUG builds"..
> >> >
> >> >> I cannot imagine that copying takes more than 10ms for starting grub on
> >> >> any architecture. So the user will not notice it anyway.
> >> >> Assume every architecture requiring alignment for which you do not have
> >> >> proof of the contrary.
> >> >>
> >> >> Even on ARM64 there are op codes that fail without alignment.
> >> >
> >> > iirc the restrictions where mostly about device memory, and atomics.
> >> > Which should not apply here.  (And we have aarch64 servers in
> >> > production with grub, which doesn't take any protections about
> >> > unaligned device-path nodes, using non u-boot EFI implementations.  So
> >> > maybe that counts as proof to the contrary ;-))
> >>
> >> The UEFI spec mandates that unaligned access are fixed up properly
> >> (usually by hardware). We violate the spec on 32bit ARM, but do fulfill
> >> it on AArch64.
> >
> > Actually for AArch32 the spec says:
> >
> >   Unaligned access should be enabled if supported; Alignment faults
> >   are enabled otherwise.
> 
> It is a bit strange to me that alignment faults are disabled by
> default, but presumably is disabled out of reset..  I don't totally
> understand the connection to having mmu disabled, unless all memory is
> treated like device memory without mmu enabled.  (Which, also,
> wouldn't that be super-slow?)  But anyway, I guess that is a bit
> beside the point.
> 
> > So UEFI payload that wants to support pre-ARMv7 hardware should make
> > sure it doesn't do any unaligned access.
> >
> >> The reason things worked before really was just that both U-Boot and
> >> grub were compiled with -mno-unaligned-access, so they never issued
> >> unaligned accesses.
> >
> > That in itself is not enough to prevent unaligned access.  If you
> > explicitly cast an unaligned pointer to say (uint32_t *) and then
> > dereference it, you'll create an unaligned access.
> 
> This is problematic around file nodes in the device path.  Adding the
> padding bytes to the end of each device-path struct would "solve"
> that, and if pre-aarch64 we are aiming at "good enough to work", I
> kinda think that this the approach we should go for.  Other than
> file-path nodes, the rest of the issues in u-boot should be solved by
> addition of missing __packed on 'struct efi_device_path' (which I've
> added locally and will be in the next revision of the patchset).
> 
> >> Which system broke for Mark? Banana pi mostly has 32bit SBCs, so I
> >> assume it's one of those? In that case, we would need to either
> >>
> >>    1) hack up the openbsd loader to also get compiled with
> >> -mno-unaligned-access
> >>
> >> or
> >>
> >>    2) rework the 32bit arm mmu code to enable the MMU plus hardware
> >> unaligned fixups on all systems. (that's a *lot* of work)
> >
> > The system that broke was Cortex-A7 based, so ARMv7.
> >
> > *However*, the OpenBSD bootloader does not perform any unaligned
> > access.  *All* cases of unaligned access that I encountered while
> > testing/debugging Rob's code were in U-Boot itself.  This was mostly a
> > consequence from a diff in the series that added __packed to the
> > device path node structs and then passed members of those structs to
> > functions that accessed the contents of tose (now byte aligned
> > structs) through (uint16_t *) or (uint32_t *) pointers.
> 
> Yeah.. the padding byte approach I suggested would solve this.  Not
> *really* compliant, but should work for all the payload code I've come
> across.  We definitely shouldn't enable the padding bytes on aarch64,
> but I think padding bytes would be a pragmatic solution for armv7 and
> earlier.  (And hopefully someday someone enables mmu on armv7 so we
> can turn off the hack there too.)
> 
> > There was initially some confusion because I used the pc reported by
> > U-Boot to look up the faulting instruction whereas I should have been
> > using the reloc_pc.
> >
> > I think Rob is worried about grub/shim/fallback.efi doing unaligned
> > access of device path nodes on armv7.  But I'm not sure he has any
> > evidence beyond looking at code.
> 
> It will definitely be an issue (if grub/shim/fallback were not
> compiled with -mno-unaligned-access) in some of the debug code that
> prints out device-paths.  I haven't checked the compiler flags used w/
> shim/fallback.
> 
> Parsing MEDIA_DEVICE:HARD_DRIVE nodes would be an issue regardless
> without -mno-unaligned-access, although we might be getting lucky by
> just not hitting debug paths.  Some of the other issues would be
> hidden by padding bytes at the end of the DP structs which would keep
> the file-path nodes word aligned.
> 
> >> To me personally, UEFI in 32bit ARM land is a nice to have standardized
> >> platform, but not something where we really need to be fully standards
> >> compliant in every aspect. I think "making things work" is good enough
> >> there.
> >
> > Right.  For us UEFI us just a convenient way to re-use the U-Boot
> > device driver code to load a kernel from a UFS/FFS filesystem.
> >
> >> For AArch64 things are different. There we should strive for full UEFI
> >> compliance as it's "the future" :).
> >
> > Even there just making things work would be good enough for me ;).
> > Our AArach64 bootloader is almost identical to the AArch32 one and
> > works on a real UEFI implementation as well (SoftIron Overdrive 1000).
> >
> 
> I think we should make the aarch64 implementation fully compliant (ie.
> addition of missing __packed's and no extra padding bytes).  I won't
> loose sleep if some efi payloads don't work on pre-aarch64 (we should
> be able to keep things that were working before working).  If adding
> missing __packed breaks things on platforms that can't do unaligned
> access, the solution is not to remove __packed, but to conditionally
> add padding bytes at the end of the struct.  That way we keep things
> working as before on the old platforms, but make things work correctly
> on aarch64.
> 
> I'll add back my patch for EFI_DP_PAD() to this patchset, since this
> seems like the sensible way forward.

Adding padding does not magically align things on a >8-bit boundary.
And as Peter pointed out, the hard drive device path type is
inherently unalignable.  The UEFI payload simply has to deal with
that.  If grub/shim/fallback.efi is currently broken, it will have to
be fixed to be usable with U-Boot on 32-bit ARM.

The problem that needs to be fixed is the manipulation of device path
nodes in U-Boot itself.  Using __packed and -mno-aligned-access should
take care of any parsing done through the device path node struct
types.  But whenever a member of such a struct is passed to some other
function that function should be careful not to do unaligned access.
After you fixed the GUID printing code it seems ascii2unicode() is the
only function left that does an unaligned access.  Perhaps the
solution here is to simply stop using file path nodes in U-Boot like
you already suggested.  Or otherwise just do the ascii2unicode()
conversion into a suitably aligned buffer and memcpy() that into
place.

Cheers,

Mark

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
  2017-08-08 12:01                             ` Rob Clark
@ 2017-08-08 12:39                               ` Leif Lindholm
  0 siblings, 0 replies; 116+ messages in thread
From: Leif Lindholm @ 2017-08-08 12:39 UTC (permalink / raw)
  To: u-boot

On Tue, Aug 08, 2017 at 08:01:10AM -0400, Rob Clark wrote:
> On Tue, Aug 8, 2017 at 7:32 AM, Leif Lindholm <leif.lindholm@linaro.org> wrote:
> > On Tue, Aug 08, 2017 at 09:11:14AM +0100, Ard Biesheuvel wrote:
> >> On 8 August 2017 at 07:52, Alexander Graf <agraf@suse.de> wrote:
> >> >> Am 07.08.2017 um 23:18 schrieb Rob Clark <robdclark@gmail.com>:
> >> >>
> >> >> This is problematic around file nodes in the device path.  Adding the
> >> >> padding bytes to the end of each device-path struct would "solve"
> >> >> that, and if pre-aarch64 we are aiming at "good enough to work", I
> >> >> kinda think that this the approach we should go for.  Other than
> >> >> file-path nodes, the rest of the issues in u-boot should be solved by
> >> >> addition of missing __packed on 'struct efi_device_path' (which I've
> >> >> added locally and will be in the next revision of the patchset).
> >> >
> >> > Let's ask Leif and Ard if that is actually correct. If I remember
> >> > correctly, edk2 some times leverages automatic padding from the
> >> > compiler on structs.
> >>
> >> I guess that that might work, if U-boot is the only agent
> >> instantiating device path structures. But what do you mean by
> >> 'correct' in this context?
> >
> > Well, if that is the case, are we risking the ability to in the future
> > support loading drivers or protocols at runtime. (This would for
> > example exclude Shim compatibility or running the UEFI Shell.)
> 
> My proposal (and this is only for <=armv6 and armv7 until someone gets
> around to enabling mmu and disabling alignment faults) is to add
> padding bytes at the end of the various device-path structs to at
> least keep the structs (and things like utf16 string in file-path
> struct) aligned, and rely on efi payload and u-boot to be compiled
> with -mno-unaligned-access if it needs to access fields within the
> device-path structs.
> 
> This is *essentially* what u-boot does implicitly at the moment (by
> missing __packed attribute on certain structs).  I want to fix that on
> aarch64, but without the padding bytes it causes a some unaligned
> accesses in u-boot on armv7 devices.
>
> I think the goal for armv7 is more to have enough uefi for grub and
> OpenBSD's bootloader.  If fancy things like loading drivers and
> protocols at runtime doesn't work, well these didn't work before so I
> won't loose much sleep.  But I would like that to work properly on
> aarch64.

I'm all for the just enough approach (I just keep hoping for feature
creep). If this means certain aspects will not be supportable, what I
want is for it to be not supportable in a predictable manner.

So I guess what I'd like is that if we do this, then we either turn
the efi_*install_* functions back into just returning
EFI_OUT_OF_RESOURCES on these platforms, or worst case make them
scream bloody murder (but progress and hope for the best - like [1]).

[1] https://lists.denx.de/pipermail/u-boot/2016-January/241454.html

/
    Leif

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
  2017-08-08 12:26                       ` Mark Kettenis
@ 2017-08-08 12:54                         ` Rob Clark
  2017-08-08 13:33                           ` Mark Kettenis
  0 siblings, 1 reply; 116+ messages in thread
From: Rob Clark @ 2017-08-08 12:54 UTC (permalink / raw)
  To: u-boot

On Tue, Aug 8, 2017 at 8:26 AM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>> From: Rob Clark <robdclark@gmail.com>
>> Date: Mon, 7 Aug 2017 18:18:50 -0400
>>
>> On Mon, Aug 7, 2017 at 5:14 PM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>> >> From: Alexander Graf <agraf@suse.de>
>> >> Date: Mon, 7 Aug 2017 21:19:37 +0100
>> >>
>> >> For AArch64 things are different. There we should strive for full UEFI
>> >> compliance as it's "the future" :).
>> >
>> > Even there just making things work would be good enough for me ;).
>> > Our AArach64 bootloader is almost identical to the AArch32 one and
>> > works on a real UEFI implementation as well (SoftIron Overdrive 1000).
>> >
>>
>> I think we should make the aarch64 implementation fully compliant (ie.
>> addition of missing __packed's and no extra padding bytes).  I won't
>> loose sleep if some efi payloads don't work on pre-aarch64 (we should
>> be able to keep things that were working before working).  If adding
>> missing __packed breaks things on platforms that can't do unaligned
>> access, the solution is not to remove __packed, but to conditionally
>> add padding bytes at the end of the struct.  That way we keep things
>> working as before on the old platforms, but make things work correctly
>> on aarch64.
>>
>> I'll add back my patch for EFI_DP_PAD() to this patchset, since this
>> seems like the sensible way forward.
>
> Adding padding does not magically align things on a >8-bit boundary.
> And as Peter pointed out, the hard drive device path type is
> inherently unalignable.  The UEFI payload simply has to deal with
> that.  If grub/shim/fallback.efi is currently broken, it will have to
> be fixed to be usable with U-Boot on 32-bit ARM.
>
> The problem that needs to be fixed is the manipulation of device path
> nodes in U-Boot itself.  Using __packed and -mno-aligned-access should
> take care of any parsing done through the device path node struct
> types.  But whenever a member of such a struct is passed to some other
> function that function should be careful not to do unaligned access.
> After you fixed the GUID printing code it seems ascii2unicode() is the
> only function left that does an unaligned access.  Perhaps the
> solution here is to simply stop using file path nodes in U-Boot like
> you already suggested.  Or otherwise just do the ascii2unicode()
> conversion into a suitably aligned buffer and memcpy() that into
> place.
>

It is also a problem with all the utf16 string handling, which shows
up all over the place.  For example if efi payload (or
efi_load_image()) took the file path string from a device-path, which
was unaligned.  I'm not really a fan of trying to deal with this
everywhere, since it is making the code much more cumbersome for the
benefit of platforms that are broken (and still will be broken in ways
we cannot prevent) from an EFI standpoint.

So I'm pretty much NAK on playing whack-a-mole with unaligned utf16
string handling in u-boot.  Padding bytes at end of device-path
structs won't solve everything.. that can only be done by making
unaligned accesses work.  (And hey, maybe we can trap the faults and
emulate on armv6 if someone cares enough?)  But the padding bytes will
keep things working to the extent that they work today, in an
non-obtrusive way, that is good enough for armv6/armv7 and it lets us
fix things properly on aarch64.  So that is progress.

(And I kind of agree with Leif from the other email on this thread
that efi_*install* should probably scream scary warning msgs on
BROKEN_UNALIGNED platforms.)

BR,
-R

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
  2017-08-08 12:54                         ` Rob Clark
@ 2017-08-08 13:33                           ` Mark Kettenis
  2017-08-08 14:03                             ` Rob Clark
  0 siblings, 1 reply; 116+ messages in thread
From: Mark Kettenis @ 2017-08-08 13:33 UTC (permalink / raw)
  To: u-boot

> From: Rob Clark <robdclark@gmail.com>
> Date: Tue, 8 Aug 2017 08:54:26 -0400
> 
> On Tue, Aug 8, 2017 at 8:26 AM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
> >> From: Rob Clark <robdclark@gmail.com>
> >> Date: Mon, 7 Aug 2017 18:18:50 -0400
> >>
> >> On Mon, Aug 7, 2017 at 5:14 PM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
> >> >> From: Alexander Graf <agraf@suse.de>
> >> >> Date: Mon, 7 Aug 2017 21:19:37 +0100
> >> >>
> >> >> For AArch64 things are different. There we should strive for full UEFI
> >> >> compliance as it's "the future" :).
> >> >
> >> > Even there just making things work would be good enough for me ;).
> >> > Our AArach64 bootloader is almost identical to the AArch32 one and
> >> > works on a real UEFI implementation as well (SoftIron Overdrive 1000).
> >> >
> >>
> >> I think we should make the aarch64 implementation fully compliant (ie.
> >> addition of missing __packed's and no extra padding bytes).  I won't
> >> loose sleep if some efi payloads don't work on pre-aarch64 (we should
> >> be able to keep things that were working before working).  If adding
> >> missing __packed breaks things on platforms that can't do unaligned
> >> access, the solution is not to remove __packed, but to conditionally
> >> add padding bytes at the end of the struct.  That way we keep things
> >> working as before on the old platforms, but make things work correctly
> >> on aarch64.
> >>
> >> I'll add back my patch for EFI_DP_PAD() to this patchset, since this
> >> seems like the sensible way forward.
> >
> > Adding padding does not magically align things on a >8-bit boundary.
> > And as Peter pointed out, the hard drive device path type is
> > inherently unalignable.  The UEFI payload simply has to deal with
> > that.  If grub/shim/fallback.efi is currently broken, it will have to
> > be fixed to be usable with U-Boot on 32-bit ARM.
> >
> > The problem that needs to be fixed is the manipulation of device path
> > nodes in U-Boot itself.  Using __packed and -mno-aligned-access should
> > take care of any parsing done through the device path node struct
> > types.  But whenever a member of such a struct is passed to some other
> > function that function should be careful not to do unaligned access.
> > After you fixed the GUID printing code it seems ascii2unicode() is the
> > only function left that does an unaligned access.  Perhaps the
> > solution here is to simply stop using file path nodes in U-Boot like
> > you already suggested.  Or otherwise just do the ascii2unicode()
> > conversion into a suitably aligned buffer and memcpy() that into
> > place.
> >
> 
> It is also a problem with all the utf16 string handling, which shows
> up all over the place.  For example if efi payload (or
> efi_load_image()) took the file path string from a device-path, which
> was unaligned.  I'm not really a fan of trying to deal with this
> everywhere, since it is making the code much more cumbersome for the
> benefit of platforms that are broken (and still will be broken in ways
> we cannot prevent) from an EFI standpoint.

Sorry, but I object to using the term broken here.  Alignment is a
rather fundamental aspect of how computers work and even on x86 you
can't completely ignore that aspect.  And from an EFI standard...

The EFI standard clearly states that for Aarch32 (2.3.5 AArch32
Platforms):

  Unaligned access should be enabled if supported; Alignment faults
  are enabled otherwise.

In other words, a generic Aarch32 EFI payload should expect that
unaligned access faults.  

The EFI standard also says (2.3.1 Data Types):

  Unless otherwise specified all data types are naturally
  aligned. Structures are aligned on boundaries equal to the largest
  internal datum of the structure and internal data are implicitly
  padded to achieve natural alignment.

The "unless otherwise specified" clearly applies to device path nodes,
but outside that scope utf16 strings should be 16-bit aligned.  So if
the file path passed to efi_load_image() isn't 16-bit aligned that is
a U-Boot bug.  Note that this became a bug in patch 13/20 where you
added __packed.  I understand that you introduced __packed to fix
another bug, but you'll have to deal with the consequences.

> So I'm pretty much NAK on playing whack-a-mole with unaligned utf16
> string handling in u-boot.  Padding bytes at end of device-path
> structs won't solve everything.. that can only be done by making
> unaligned accesses work.  (And hey, maybe we can trap the faults and
> emulate on armv6 if someone cares enough?)  But the padding bytes will
> keep things working to the extent that they work today, in an
> non-obtrusive way, that is good enough for armv6/armv7 and it lets us
> fix things properly on aarch64.  So that is progress.

Adding the padding *will not* fix anything.  It just makes the
structures bigger.  The compiler is still free to align them on an odd
boundary.

Sorry there is no way around it.  You'll need to be careful about
alignment anywhere where you convert data into and out of device
paths.  But you certainly don't need to check every place where utf16
strings are used.  The compiler will make sure things will be
naturally aligned unless you explicitly tell it not to do that.

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
  2017-08-08 13:33                           ` Mark Kettenis
@ 2017-08-08 14:03                             ` Rob Clark
  2017-08-08 14:10                               ` Rob Clark
  2017-08-08 18:20                               ` Rob Clark
  0 siblings, 2 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-08 14:03 UTC (permalink / raw)
  To: u-boot

On Tue, Aug 8, 2017 at 9:33 AM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>> From: Rob Clark <robdclark@gmail.com>
>> Date: Tue, 8 Aug 2017 08:54:26 -0400
>>
>> On Tue, Aug 8, 2017 at 8:26 AM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>> >> From: Rob Clark <robdclark@gmail.com>
>> >> Date: Mon, 7 Aug 2017 18:18:50 -0400
>> >>
>> >> On Mon, Aug 7, 2017 at 5:14 PM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>> >> >> From: Alexander Graf <agraf@suse.de>
>> >> >> Date: Mon, 7 Aug 2017 21:19:37 +0100
>> >> >>
>> >> >> For AArch64 things are different. There we should strive for full UEFI
>> >> >> compliance as it's "the future" :).
>> >> >
>> >> > Even there just making things work would be good enough for me ;).
>> >> > Our AArach64 bootloader is almost identical to the AArch32 one and
>> >> > works on a real UEFI implementation as well (SoftIron Overdrive 1000).
>> >> >
>> >>
>> >> I think we should make the aarch64 implementation fully compliant (ie.
>> >> addition of missing __packed's and no extra padding bytes).  I won't
>> >> loose sleep if some efi payloads don't work on pre-aarch64 (we should
>> >> be able to keep things that were working before working).  If adding
>> >> missing __packed breaks things on platforms that can't do unaligned
>> >> access, the solution is not to remove __packed, but to conditionally
>> >> add padding bytes at the end of the struct.  That way we keep things
>> >> working as before on the old platforms, but make things work correctly
>> >> on aarch64.
>> >>
>> >> I'll add back my patch for EFI_DP_PAD() to this patchset, since this
>> >> seems like the sensible way forward.
>> >
>> > Adding padding does not magically align things on a >8-bit boundary.
>> > And as Peter pointed out, the hard drive device path type is
>> > inherently unalignable.  The UEFI payload simply has to deal with
>> > that.  If grub/shim/fallback.efi is currently broken, it will have to
>> > be fixed to be usable with U-Boot on 32-bit ARM.
>> >
>> > The problem that needs to be fixed is the manipulation of device path
>> > nodes in U-Boot itself.  Using __packed and -mno-aligned-access should
>> > take care of any parsing done through the device path node struct
>> > types.  But whenever a member of such a struct is passed to some other
>> > function that function should be careful not to do unaligned access.
>> > After you fixed the GUID printing code it seems ascii2unicode() is the
>> > only function left that does an unaligned access.  Perhaps the
>> > solution here is to simply stop using file path nodes in U-Boot like
>> > you already suggested.  Or otherwise just do the ascii2unicode()
>> > conversion into a suitably aligned buffer and memcpy() that into
>> > place.
>> >
>>
>> It is also a problem with all the utf16 string handling, which shows
>> up all over the place.  For example if efi payload (or
>> efi_load_image()) took the file path string from a device-path, which
>> was unaligned.  I'm not really a fan of trying to deal with this
>> everywhere, since it is making the code much more cumbersome for the
>> benefit of platforms that are broken (and still will be broken in ways
>> we cannot prevent) from an EFI standpoint.
>
> Sorry, but I object to using the term broken here.  Alignment is a
> rather fundamental aspect of how computers work and even on x86 you
> can't completely ignore that aspect.  And from an EFI standard...

ok, s/broken/defies expectations/ if you prefer then.  I think it
amounts to the same thing.

> The EFI standard clearly states that for Aarch32 (2.3.5 AArch32
> Platforms):
>
>   Unaligned access should be enabled if supported; Alignment faults
>   are enabled otherwise.

Yes, unaligned access should be enabled if supported.. not "if the
UEFI implementation supports it".  Presumably the "alignment faults
are enabled otherwise" is referring to armv4 and armv5.

It also says that MMU should be enabled and SCTLR.A=0 on armv6 and
armv7 (so I guess even armv6 supports unaligned access).

In that regard, I still think the term "broken" fits.

> In other words, a generic Aarch32 EFI payload should expect that
> unaligned access faults.
>
> The EFI standard also says (2.3.1 Data Types):
>
>   Unless otherwise specified all data types are naturally
>   aligned. Structures are aligned on boundaries equal to the largest
>   internal datum of the structure and internal data are implicitly
>   padded to achieve natural alignment.
>
> The "unless otherwise specified" clearly applies to device path nodes,
> but outside that scope utf16 strings should be 16-bit aligned.  So if
> the file path passed to efi_load_image() isn't 16-bit aligned that is
> a U-Boot bug.  Note that this became a bug in patch 13/20 where you
> added __packed.  I understand that you introduced __packed to fix
> another bug, but you'll have to deal with the consequences.
>
>> So I'm pretty much NAK on playing whack-a-mole with unaligned utf16
>> string handling in u-boot.  Padding bytes at end of device-path
>> structs won't solve everything.. that can only be done by making
>> unaligned accesses work.  (And hey, maybe we can trap the faults and
>> emulate on armv6 if someone cares enough?)  But the padding bytes will
>> keep things working to the extent that they work today, in an
>> non-obtrusive way, that is good enough for armv6/armv7 and it lets us
>> fix things properly on aarch64.  So that is progress.
>
> Adding the padding *will not* fix anything.  It just makes the
> structures bigger.  The compiler is still free to align them on an odd
> boundary.

It will "fix" what was "broken" by adding __packed ;-)

It makes the structures bigger to align the next structure to a word
boundary, which *mostly* aligns fields within the structure to their
natural alignment.

I agree it isn't really a fix.  It's a workaround.  But it has the
consequence that utf16 strings in a device-path will be naturally
aligned, in case they get passed back into some other efi api.  (And
that also applies to USB WWID nodes, we we aren't using for anything
else yet.. from a quick look I don't see anywhere else where utf16
strings are used in a device-path.)

> Sorry there is no way around it.  You'll need to be careful about
> alignment anywhere where you convert data into and out of device
> paths.  But you certainly don't need to check every place where utf16
> strings are used.  The compiler will make sure things will be
> naturally aligned unless you explicitly tell it not to do that.

I'm worried about the case where efi payload takes a utf16 path out of
a device-path and passes it back to file->open().

I suppose special case handling in efi_load_image() wouldn't be too
bad.  It won't fix every theoretical problem on armv7 without
unaligned access disabled.

BR,
-R

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
  2017-08-08 14:03                             ` Rob Clark
@ 2017-08-08 14:10                               ` Rob Clark
  2017-08-08 18:20                               ` Rob Clark
  1 sibling, 0 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-08 14:10 UTC (permalink / raw)
  To: u-boot

On Tue, Aug 8, 2017 at 10:03 AM, Rob Clark <robdclark@gmail.com> wrote:
> I suppose special case handling in efi_load_image() wouldn't be too
> bad.  It won't fix every theoretical problem on armv7 without
> unaligned access disabled.
>

s/disabled/enabled/

BR,
-R

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
  2017-08-08 14:03                             ` Rob Clark
  2017-08-08 14:10                               ` Rob Clark
@ 2017-08-08 18:20                               ` Rob Clark
  1 sibling, 0 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-08 18:20 UTC (permalink / raw)
  To: u-boot

On Tue, Aug 8, 2017 at 10:03 AM, Rob Clark <robdclark@gmail.com> wrote:
> On Tue, Aug 8, 2017 at 9:33 AM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>>> From: Rob Clark <robdclark@gmail.com>
>>> Date: Tue, 8 Aug 2017 08:54:26 -0400
>>>
>>> On Tue, Aug 8, 2017 at 8:26 AM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>>> >> From: Rob Clark <robdclark@gmail.com>
>>> >> Date: Mon, 7 Aug 2017 18:18:50 -0400
>>> >>
>>> >> On Mon, Aug 7, 2017 at 5:14 PM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote:
>>> >> >> From: Alexander Graf <agraf@suse.de>
>>> >> >> Date: Mon, 7 Aug 2017 21:19:37 +0100
>>> >> >>
>>> >> >> For AArch64 things are different. There we should strive for full UEFI
>>> >> >> compliance as it's "the future" :).
>>> >> >
>>> >> > Even there just making things work would be good enough for me ;).
>>> >> > Our AArach64 bootloader is almost identical to the AArch32 one and
>>> >> > works on a real UEFI implementation as well (SoftIron Overdrive 1000).
>>> >> >
>>> >>
>>> >> I think we should make the aarch64 implementation fully compliant (ie.
>>> >> addition of missing __packed's and no extra padding bytes).  I won't
>>> >> loose sleep if some efi payloads don't work on pre-aarch64 (we should
>>> >> be able to keep things that were working before working).  If adding
>>> >> missing __packed breaks things on platforms that can't do unaligned
>>> >> access, the solution is not to remove __packed, but to conditionally
>>> >> add padding bytes at the end of the struct.  That way we keep things
>>> >> working as before on the old platforms, but make things work correctly
>>> >> on aarch64.
>>> >>
>>> >> I'll add back my patch for EFI_DP_PAD() to this patchset, since this
>>> >> seems like the sensible way forward.
>>> >
>>> > Adding padding does not magically align things on a >8-bit boundary.
>>> > And as Peter pointed out, the hard drive device path type is
>>> > inherently unalignable.  The UEFI payload simply has to deal with
>>> > that.  If grub/shim/fallback.efi is currently broken, it will have to
>>> > be fixed to be usable with U-Boot on 32-bit ARM.
>>> >
>>> > The problem that needs to be fixed is the manipulation of device path
>>> > nodes in U-Boot itself.  Using __packed and -mno-aligned-access should
>>> > take care of any parsing done through the device path node struct
>>> > types.  But whenever a member of such a struct is passed to some other
>>> > function that function should be careful not to do unaligned access.
>>> > After you fixed the GUID printing code it seems ascii2unicode() is the
>>> > only function left that does an unaligned access.  Perhaps the
>>> > solution here is to simply stop using file path nodes in U-Boot like
>>> > you already suggested.  Or otherwise just do the ascii2unicode()
>>> > conversion into a suitably aligned buffer and memcpy() that into
>>> > place.
>>> >
>>>
>>> It is also a problem with all the utf16 string handling, which shows
>>> up all over the place.  For example if efi payload (or
>>> efi_load_image()) took the file path string from a device-path, which
>>> was unaligned.  I'm not really a fan of trying to deal with this
>>> everywhere, since it is making the code much more cumbersome for the
>>> benefit of platforms that are broken (and still will be broken in ways
>>> we cannot prevent) from an EFI standpoint.
>>
>> Sorry, but I object to using the term broken here.  Alignment is a
>> rather fundamental aspect of how computers work and even on x86 you
>> can't completely ignore that aspect.  And from an EFI standard...
>
> ok, s/broken/defies expectations/ if you prefer then.  I think it
> amounts to the same thing.
>
>> The EFI standard clearly states that for Aarch32 (2.3.5 AArch32
>> Platforms):
>>
>>   Unaligned access should be enabled if supported; Alignment faults
>>   are enabled otherwise.
>
> Yes, unaligned access should be enabled if supported.. not "if the
> UEFI implementation supports it".  Presumably the "alignment faults
> are enabled otherwise" is referring to armv4 and armv5.
>
> It also says that MMU should be enabled and SCTLR.A=0 on armv6 and
> armv7 (so I guess even armv6 supports unaligned access).
>
> In that regard, I still think the term "broken" fits.
>
>> In other words, a generic Aarch32 EFI payload should expect that
>> unaligned access faults.
>>
>> The EFI standard also says (2.3.1 Data Types):
>>
>>   Unless otherwise specified all data types are naturally
>>   aligned. Structures are aligned on boundaries equal to the largest
>>   internal datum of the structure and internal data are implicitly
>>   padded to achieve natural alignment.
>>
>> The "unless otherwise specified" clearly applies to device path nodes,
>> but outside that scope utf16 strings should be 16-bit aligned.  So if
>> the file path passed to efi_load_image() isn't 16-bit aligned that is
>> a U-Boot bug.  Note that this became a bug in patch 13/20 where you
>> added __packed.  I understand that you introduced __packed to fix
>> another bug, but you'll have to deal with the consequences.
>>
>>> So I'm pretty much NAK on playing whack-a-mole with unaligned utf16
>>> string handling in u-boot.  Padding bytes at end of device-path
>>> structs won't solve everything.. that can only be done by making
>>> unaligned accesses work.  (And hey, maybe we can trap the faults and
>>> emulate on armv6 if someone cares enough?)  But the padding bytes will
>>> keep things working to the extent that they work today, in an
>>> non-obtrusive way, that is good enough for armv6/armv7 and it lets us
>>> fix things properly on aarch64.  So that is progress.
>>
>> Adding the padding *will not* fix anything.  It just makes the
>> structures bigger.  The compiler is still free to align them on an odd
>> boundary.
>
> It will "fix" what was "broken" by adding __packed ;-)
>
> It makes the structures bigger to align the next structure to a word
> boundary, which *mostly* aligns fields within the structure to their
> natural alignment.
>
> I agree it isn't really a fix.  It's a workaround.  But it has the
> consequence that utf16 strings in a device-path will be naturally
> aligned, in case they get passed back into some other efi api.  (And
> that also applies to USB WWID nodes, we we aren't using for anything
> else yet.. from a quick look I don't see anywhere else where utf16
> strings are used in a device-path.)
>
>> Sorry there is no way around it.  You'll need to be careful about
>> alignment anywhere where you convert data into and out of device
>> paths.  But you certainly don't need to check every place where utf16
>> strings are used.  The compiler will make sure things will be
>> naturally aligned unless you explicitly tell it not to do that.
>
> I'm worried about the case where efi payload takes a utf16 path out of
> a device-path and passes it back to file->open().
>
> I suppose special case handling in efi_load_image() wouldn't be too
> bad.  It won't fix every theoretical problem on armv7 without
> unaligned access enabled.
>

Since I don't have an armv7 board w/ u-boot to test, I've done some
experiments w/ SCTLR.A=1 on armv8:


GRUB:

Note, by default built w/out -mstrict-align on aarch64, which crashes.
With -mstrict-align, it seems to work with or without extra padding.

Kernel does crash relatively early, I guess not expecting to have
unaligned accesses disabled.


SHIM/FALLBACK:

Both seem to crash in both shim and fallback with and without padding.
Note that shim and fallback do not seem to ever be built with
-mstrict-align, which is probably the issue.  So I wouldn't expect
these to work on armv7 right now without at least recompiling.

fallback.efi is the one where I half suspect we'll see issues if there
are any, but without my patchset it won't run on u-boot at all, and
with my patchset it will run on aarch64 (but not armv7, at least until
it is recompiled).  So I'm tempted not to care at this point.



OpenBSD bootloader:

Works both with and without padding, at least until the point where it
can't find an OpenBSD filesystem and then sits there at boot prompt.



SUMMARY:

Mark's initial problem wasn't even with device-paths, but was with
guidstr(), iirc.  Which is superceded by the patch adding vsprintf
support for %pG (which works bytewise, so it doesn't have the same
problem as guidstr).

Beyond that, right now the only place we construct a file-path (and
call ascii2unicode()) is the EFI_LOADED_IMAGE::FilePath (which is not
preceded by the "device" part of a device-path, so it is already word
aligned).

So tl;dr: we can skip the padding for now, it doesn't fix anything
enough to go from broken to working.  And without it nothing that was
working before stops working.


BR,
-R

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [U-Boot, v0, 07/20] vsprintf.c: add wide string (%ls) support
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 07/20] vsprintf.c: add wide string (%ls) support Rob Clark
@ 2017-08-08 22:03   ` Heinrich Schuchardt
  2017-08-08 22:44     ` Rob Clark
                       ` (2 more replies)
  0 siblings, 3 replies; 116+ messages in thread
From: Heinrich Schuchardt @ 2017-08-08 22:03 UTC (permalink / raw)
  To: u-boot

On 08/04/2017 09:31 PM, Rob Clark wrote:
> This is convenient for efi_loader which deals a lot with utf16.
> 
> Signed-off-by: Rob Clark <robdclark@gmail.com>

Please, put this patch together with
[PATCH] vsprintf.c: add GUID printing
https://patchwork.ozlabs.org/patch/798362/
and
[PATCH v0 06/20] common: add some utf16 handling helpers
https://patchwork.ozlabs.org/patch/797968/
into a separate patch series.

These three patches can be reviewed independently of the efi_loader
patches and probably will not be integrated via the efi-next tree.

> ---
>  lib/vsprintf.c | 30 ++++++++++++++++++++++++++++--
>  1 file changed, 28 insertions(+), 2 deletions(-)
> 
> diff --git a/lib/vsprintf.c b/lib/vsprintf.c
> index 874a2951f7..0c40f852ce 100644
> --- a/lib/vsprintf.c
> +++ b/lib/vsprintf.c
> @@ -17,6 +17,7 @@
>  #include <linux/ctype.h>
>  
>  #include <common.h>
> +#include <charset.h>
>  
>  #include <div64.h>
>  #define noinline __attribute__((noinline))
> @@ -270,6 +271,26 @@ static char *string(char *buf, char *end, char *s, int field_width,
>  	return buf;
>  }
>  
> +static char *string16(char *buf, char *end, u16 *s, int field_width,
> +		int precision, int flags)
> +{
> +	u16 *str = s ? s : L"<NULL>";
Please, do not use the L-notation here as it requires -fshort-wchar.
As we currently cannot switch the complete project to C11 you cannot use
the u-notation either.

> +	int len = utf16_strnlen(str, precision);
> +	u8 utf8[len * MAX_UTF8_PER_UTF16];

Didn't you forget 1 byte for \0 here?

This is what strlnlen does:

The strnlen() function returns the number of characters in the string
pointed to by s, **excluding** the terminating null byte ('\0'), but at
most maxlen.

I would expect the exclusion of the terminating null word by an
utf16_strnlen function.

> +	int i;
> +
> +	*utf16_to_utf8(utf8, str, len) = '\0';
> +
> +	if (!(flags & LEFT))
> +		while (len < field_width--)
> +			ADDCH(buf, ' ');
> +	for (i = 0; i < len; ++i)
> +		ADDCH(buf, utf8[i]);
> +	while (len < field_width--)
> +		ADDCH(buf, ' ');
> +	return buf;
> +}
> +
>  #ifdef CONFIG_CMD_NET
>  static const char hex_asc[] = "0123456789abcdef";
>  #define hex_asc_lo(x)	hex_asc[((x) & 0x0f)]
> @@ -528,8 +549,13 @@ repeat:
>  			continue;
>  
>  		case 's':
> -			str = string(str, end, va_arg(args, char *),
> -				     field_width, precision, flags);
> +			if (qualifier == 'l') {

%ls refers to wchar with implementation dependent width in the C standard.
There is no qualifier for 16-bit wchar. Couldn't we use %us here in
reference to the u-notation ( u'MyString' ). This would leave the path
open for a standard compliant '%ls'.

Best regards

Heinrich

> +				str = string16(str, end, va_arg(args, u16 *),
> +					       field_width, precision, flags);
> +			} else {
> +				str = string(str, end, va_arg(args, char *),
> +					     field_width, precision, flags);
> +			}
>  			continue;
>  
>  		case 'p':
> 

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [U-Boot, v0, 07/20] vsprintf.c: add wide string (%ls) support
  2017-08-08 22:03   ` [U-Boot] [U-Boot, v0, " Heinrich Schuchardt
@ 2017-08-08 22:44     ` Rob Clark
  2017-08-08 23:08       ` Heinrich Schuchardt
  2017-08-08 22:52     ` Rob Clark
  2017-08-09 13:38     ` Rob Clark
  2 siblings, 1 reply; 116+ messages in thread
From: Rob Clark @ 2017-08-08 22:44 UTC (permalink / raw)
  To: u-boot

On Tue, Aug 8, 2017 at 6:03 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
> On 08/04/2017 09:31 PM, Rob Clark wrote:
>> This is convenient for efi_loader which deals a lot with utf16.
>>
>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>
> Please, put this patch together with
> [PATCH] vsprintf.c: add GUID printing
> https://patchwork.ozlabs.org/patch/798362/
> and
> [PATCH v0 06/20] common: add some utf16 handling helpers
> https://patchwork.ozlabs.org/patch/797968/
> into a separate patch series.
>
> These three patches can be reviewed independently of the efi_loader
> patches and probably will not be integrated via the efi-next tree.

I'll resend these as a separate patchset, and just not in next
revision of efi_loader patchset that it is a dependency

>> ---
>>  lib/vsprintf.c | 30 ++++++++++++++++++++++++++++--
>>  1 file changed, 28 insertions(+), 2 deletions(-)
>>
>> diff --git a/lib/vsprintf.c b/lib/vsprintf.c
>> index 874a2951f7..0c40f852ce 100644
>> --- a/lib/vsprintf.c
>> +++ b/lib/vsprintf.c
>> @@ -17,6 +17,7 @@
>>  #include <linux/ctype.h>
>>
>>  #include <common.h>
>> +#include <charset.h>
>>
>>  #include <div64.h>
>>  #define noinline __attribute__((noinline))
>> @@ -270,6 +271,26 @@ static char *string(char *buf, char *end, char *s, int field_width,
>>       return buf;
>>  }
>>
>> +static char *string16(char *buf, char *end, u16 *s, int field_width,
>> +             int precision, int flags)
>> +{
>> +     u16 *str = s ? s : L"<NULL>";
> Please, do not use the L-notation here as it requires -fshort-wchar.
> As we currently cannot switch the complete project to C11 you cannot use
> the u-notation either.

current plan was to either switch whole project to -fshort-wchar or
c11 and rework these patches (as well as a few patches in the
efi_loader patchset).  (In the c11 case, I'm not sure what we'll use
as the fmt string, since afaict that isn't specified.  We could use %S
although that seems to be a deprecated way to do %ls, or something
different like %A, I guess)..

how far are we from c11?  If there is stuff I can do to help let me
know.  If feasible, I'd rather do that first rather than have a bunch
of stuff in vsprintf and elsewhere that needs to be cleaned up later
after the switch.

>
>> +     int len = utf16_strnlen(str, precision);
>> +     u8 utf8[len * MAX_UTF8_PER_UTF16];
>
> Didn't you forget 1 byte for \0 here?
>
> This is what strlnlen does:
>
> The strnlen() function returns the number of characters in the string
> pointed to by s, **excluding** the terminating null byte ('\0'), but at
> most maxlen.
>
> I would expect the exclusion of the terminating null word by an
> utf16_strnlen function.

you are right, but fixing the wrong problem.. the code is definitely
wrong since length of a utf16 string != length of a utf8 string, and
we don't need to append a null terminator.. so my logic below using
'len' is wrong.  I'll fix that in the next version.

>> +     int i;
>> +
>> +     *utf16_to_utf8(utf8, str, len) = '\0';
>> +
>> +     if (!(flags & LEFT))
>> +             while (len < field_width--)
>> +                     ADDCH(buf, ' ');
>> +     for (i = 0; i < len; ++i)
>> +             ADDCH(buf, utf8[i]);
>> +     while (len < field_width--)
>> +             ADDCH(buf, ' ');
>> +     return buf;
>> +}
>> +
>>  #ifdef CONFIG_CMD_NET
>>  static const char hex_asc[] = "0123456789abcdef";
>>  #define hex_asc_lo(x)        hex_asc[((x) & 0x0f)]
>> @@ -528,8 +549,13 @@ repeat:
>>                       continue;
>>
>>               case 's':
>> -                     str = string(str, end, va_arg(args, char *),
>> -                                  field_width, precision, flags);
>> +                     if (qualifier == 'l') {
>
> %ls refers to wchar with implementation dependent width in the C standard.
> There is no qualifier for 16-bit wchar. Couldn't we use %us here in
> reference to the u-notation ( u'MyString' ). This would leave the path
> open for a standard compliant '%ls'.

hmm, yeah, that is a clever idea, and I like it better than %A or %S..
so if we go the c11 route I'll do that.  The c11 committee should have
thought of that ;-)

BR,
-R

> Best regards
>
> Heinrich
>
>> +                             str = string16(str, end, va_arg(args, u16 *),
>> +                                            field_width, precision, flags);
>> +                     } else {
>> +                             str = string(str, end, va_arg(args, char *),
>> +                                          field_width, precision, flags);
>> +                     }
>>                       continue;
>>
>>               case 'p':
>>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [U-Boot, v0, 06/20] common: add some utf16 handling helpers
  2017-08-04 19:31 ` [U-Boot] [PATCH v0 06/20] common: add some utf16 handling helpers Rob Clark
  2017-08-06  5:17   ` Simon Glass
@ 2017-08-08 22:50   ` Heinrich Schuchardt
  2017-08-08 23:21     ` Rob Clark
  1 sibling, 1 reply; 116+ messages in thread
From: Heinrich Schuchardt @ 2017-08-08 22:50 UTC (permalink / raw)
  To: u-boot

On 08/04/2017 09:31 PM, Rob Clark wrote:
> We'll eventually want these in a few places in efi_loader, and also
> vsprintf.
> 
> Signed-off-by: Rob Clark <robdclark@gmail.com>
> ---
>  common/Makefile              |  1 +
>  common/charset.c             | 81 ++++++++++++++++++++++++++++++++++++++++++++
>  include/charset.h            | 18 ++++++++++
>  lib/efi_loader/efi_console.c | 17 ++--------
>  4 files changed, 103 insertions(+), 14 deletions(-)
>  create mode 100644 common/charset.c
>  create mode 100644 include/charset.h
> 
> diff --git a/common/Makefile b/common/Makefile
> index 60681c845c..44c8e1ba52 100644
> --- a/common/Makefile
> +++ b/common/Makefile
> @@ -175,5 +175,6 @@ obj-$(CONFIG_CMD_DFU) += dfu.o
>  obj-y += command.o
>  obj-y += s_record.o
>  obj-y += xyzModem.o
> +obj-y += charset.o
>  
>  CFLAGS_env_embedded.o := -Wa,--no-warn -DENV_CRC=$(shell tools/envcrc 2>/dev/null)
> diff --git a/common/charset.c b/common/charset.c
> new file mode 100644
> index 0000000000..eaff2e542e
> --- /dev/null
> +++ b/common/charset.c
> @@ -0,0 +1,81 @@
> +/*
> + *  charset conversion utils
> + *
> + *  Copyright (c) 2017 Rob Clark
> + *
> + *  SPDX-License-Identifier:     GPL-2.0+
> + */
> +
> +#include <common.h>
> +#include <charset.h>
> +
> +/*
> + * utf8/utf16 conversion mostly lifted from grub
> + */
> +
> +size_t utf16_strlen(uint16_t *in)
> +{
> +	size_t i;
> +	for (i = 0; in[i]; i++);
> +	return i;
> +}
> +
> +size_t utf16_strnlen(const uint16_t *in, size_t count)
> +{
> +	size_t i;
> +	for (i = 0; count-- && in[i]; i++);
> +	return i;
> +}
> +
> +/* Convert UTF-16 to UTF-8.  */
> +uint8_t *utf16_to_utf8(uint8_t *dest, const uint16_t *src, size_t size)
> +{
> +	uint32_t code_high = 0;
> +
> +	while (size--) {

We should not read past the trailing null world. Check *src == 0 somewhere.

> +		uint32_t code = *src++;
> +
> +		if (code_high) {
> +			if (code >= 0xDC00 && code <= 0xDFFF) {
> +				/* Surrogate pair.  */
> +				code = ((code_high - 0xD800) << 10) + (code - 0xDC00) + 0x10000;
> +
> +				*dest++ = (code >> 18) | 0xF0;
> +				*dest++ = ((code >> 12) & 0x3F) | 0x80;
> +				*dest++ = ((code >> 6) & 0x3F) | 0x80;
> +				*dest++ = (code & 0x3F) | 0x80;
> +			} else {
> +				/* Error...  */
> +				*dest++ = '?';
> +				/* *src may be valid. Don't eat it.  */
> +				src--;
> +			}
> +
> +			code_high = 0;
> +		} else {
> +			if (code <= 0x007F) {
> +				*dest++ = code;
> +			} else if (code <= 0x07FF) {
> +				*dest++ = (code >> 6) | 0xC0;
> +				*dest++ = (code & 0x3F) | 0x80;
> +			} else if (code >= 0xD800 && code <= 0xDBFF) {
> +				code_high = code;
> +				continue;
> +			} else if (code >= 0xDC00 && code <= 0xDFFF) {
> +				/* Error... */
> +				*dest++ = '?';

The error handling is somewhat inconsistent:

No output if code 0xD800-0xDBFF is the last word.
Output '?' for 0xDC00-0xDFFF where not expected.
Output extraneous '?' for 0xD800-0xDBFF not followed by 0xDC00-0xDBFF.

Best regards

Heinrich

> +			} else if (code < 0x10000) {
> +				*dest++ = (code >> 12) | 0xE0;
> +				*dest++ = ((code >> 6) & 0x3F) | 0x80;
> +				*dest++ = (code & 0x3F) | 0x80;
> +			} else {
> +				*dest++ = (code >> 18) | 0xF0;
> +				*dest++ = ((code >> 12) & 0x3F) | 0x80;
> +				*dest++ = ((code >> 6) & 0x3F) | 0x80;
> +				*dest++ = (code & 0x3F) | 0x80;
> +			}
> +		}
> +	}
> +
> +	return dest;
> +}
> diff --git a/include/charset.h b/include/charset.h
> new file mode 100644
> index 0000000000..2ee1172182
> --- /dev/null
> +++ b/include/charset.h
> @@ -0,0 +1,18 @@
> +/*
> + *  charset conversion utils
> + *
> + *  Copyright (c) 2017 Rob Clark
> + *
> + *  SPDX-License-Identifier:     GPL-2.0+
> + */
> +
> +#ifndef __CHARSET_H_
> +#define __CHARSET_H_
> +
> +#define MAX_UTF8_PER_UTF16 4
> +
> +size_t utf16_strlen(uint16_t *in);
> +size_t utf16_strnlen(const uint16_t *in, size_t count);
> +uint8_t *utf16_to_utf8(uint8_t *dest, const uint16_t *src, size_t size);
> +
> +#endif /* __CHARSET_H_ */
> diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
> index 5ebce4b544..3fc82b8726 100644
> --- a/lib/efi_loader/efi_console.c
> +++ b/lib/efi_loader/efi_console.c
> @@ -7,6 +7,7 @@
>   */
>  
>  #include <common.h>
> +#include <charset.h>
>  #include <efi_loader.h>
>  
>  static bool console_size_queried;
> @@ -138,20 +139,8 @@ static efi_status_t EFIAPI efi_cout_reset(
>  
>  static void print_unicode_in_utf8(u16 c)
>  {
> -	char utf8[4] = { 0 };
> -	char *b = utf8;
> -
> -	if (c < 0x80) {
> -		*(b++) = c;
> -	} else if (c < 0x800) {
> -		*(b++) = 192 + c / 64;
> -		*(b++) = 128 + c % 64;
> -	} else {
> -		*(b++) = 224 + c / 4096;
> -		*(b++) = 128 + c / 64 % 64;
> -		*(b++) = 128 + c % 64;
> -	}
> -
> +	char utf8[MAX_UTF8_PER_UTF16] = { 0 };
> +	utf16_to_utf8((u8 *)utf8, &c, 1);
>  	puts(utf8);
>  }
>  
> 

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [U-Boot, v0, 07/20] vsprintf.c: add wide string (%ls) support
  2017-08-08 22:03   ` [U-Boot] [U-Boot, v0, " Heinrich Schuchardt
  2017-08-08 22:44     ` Rob Clark
@ 2017-08-08 22:52     ` Rob Clark
  2017-08-09 13:38     ` Rob Clark
  2 siblings, 0 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-08 22:52 UTC (permalink / raw)
  To: u-boot

On Tue, Aug 8, 2017 at 6:03 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
> On 08/04/2017 09:31 PM, Rob Clark wrote:
>> This is convenient for efi_loader which deals a lot with utf16.
>>
>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>
> Please, put this patch together with
> [PATCH] vsprintf.c: add GUID printing
> https://patchwork.ozlabs.org/patch/798362/
> and
> [PATCH v0 06/20] common: add some utf16 handling helpers
> https://patchwork.ozlabs.org/patch/797968/
> into a separate patch series.
>
> These three patches can be reviewed independently of the efi_loader
> patches and probably will not be integrated via the efi-next tree.
>
>> ---
>>  lib/vsprintf.c | 30 ++++++++++++++++++++++++++++--
>>  1 file changed, 28 insertions(+), 2 deletions(-)
>>
>> diff --git a/lib/vsprintf.c b/lib/vsprintf.c
>> index 874a2951f7..0c40f852ce 100644
>> --- a/lib/vsprintf.c
>> +++ b/lib/vsprintf.c
>> @@ -17,6 +17,7 @@
>>  #include <linux/ctype.h>
>>
>>  #include <common.h>
>> +#include <charset.h>
>>
>>  #include <div64.h>
>>  #define noinline __attribute__((noinline))
>> @@ -270,6 +271,26 @@ static char *string(char *buf, char *end, char *s, int field_width,
>>       return buf;
>>  }
>>
>> +static char *string16(char *buf, char *end, u16 *s, int field_width,
>> +             int precision, int flags)
>> +{
>> +     u16 *str = s ? s : L"<NULL>";
> Please, do not use the L-notation here as it requires -fshort-wchar.
> As we currently cannot switch the complete project to C11 you cannot use
> the u-notation either.
>

actually, one thought..  unlike -fshort-wchar, we could probably
switch u-boot over to c11 piecemeal, if there are a lot of places
where things need to be fixed for c11.  For example start by switching
efi_loader and vsprintf.c ;-)

(I'm not completely sure what the issues are, so this may or may not
make sense.. but if c11 is causing a lot of compile errors all over
the place, this might be a reasonable approach.)

BR,
-R

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [U-Boot, v0, 07/20] vsprintf.c: add wide string (%ls) support
  2017-08-08 22:44     ` Rob Clark
@ 2017-08-08 23:08       ` Heinrich Schuchardt
  2017-08-08 23:20         ` Alexander Graf
  2017-08-08 23:39         ` Rob Clark
  0 siblings, 2 replies; 116+ messages in thread
From: Heinrich Schuchardt @ 2017-08-08 23:08 UTC (permalink / raw)
  To: u-boot

On 08/09/2017 12:44 AM, Rob Clark wrote:
> On Tue, Aug 8, 2017 at 6:03 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>> On 08/04/2017 09:31 PM, Rob Clark wrote:
>>> This is convenient for efi_loader which deals a lot with utf16.
>>>
>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>
>> Please, put this patch together with
>> [PATCH] vsprintf.c: add GUID printing
>> https://patchwork.ozlabs.org/patch/798362/
>> and
>> [PATCH v0 06/20] common: add some utf16 handling helpers
>> https://patchwork.ozlabs.org/patch/797968/
>> into a separate patch series.
>>
>> These three patches can be reviewed independently of the efi_loader
>> patches and probably will not be integrated via the efi-next tree.
> 
> I'll resend these as a separate patchset, and just not in next
> revision of efi_loader patchset that it is a dependency
> 
>>> ---
>>>  lib/vsprintf.c | 30 ++++++++++++++++++++++++++++--
>>>  1 file changed, 28 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/lib/vsprintf.c b/lib/vsprintf.c
>>> index 874a2951f7..0c40f852ce 100644
>>> --- a/lib/vsprintf.c
>>> +++ b/lib/vsprintf.c
>>> @@ -17,6 +17,7 @@
>>>  #include <linux/ctype.h>
>>>
>>>  #include <common.h>
>>> +#include <charset.h>
>>>
>>>  #include <div64.h>
>>>  #define noinline __attribute__((noinline))
>>> @@ -270,6 +271,26 @@ static char *string(char *buf, char *end, char *s, int field_width,
>>>       return buf;
>>>  }
>>>
>>> +static char *string16(char *buf, char *end, u16 *s, int field_width,
>>> +             int precision, int flags)
>>> +{
>>> +     u16 *str = s ? s : L"<NULL>";
>> Please, do not use the L-notation here as it requires -fshort-wchar.
>> As we currently cannot switch the complete project to C11 you cannot use
>> the u-notation either.
> 
> current plan was to either switch whole project to -fshort-wchar or
> c11 and rework these patches (as well as a few patches in the
> efi_loader patchset).  (In the c11 case, I'm not sure what we'll use
> as the fmt string, since afaict that isn't specified.  We could use %S
> although that seems to be a deprecated way to do %ls, or something
> different like %A, I guess)..
> 
> how far are we from c11?  If there is stuff I can do to help let me
> know.  If feasible, I'd rather do that first rather than have a bunch
> of stuff in vsprintf and elsewhere that needs to be cleaned up later
> after the switch.

buildman downloads very old compilers (gcc < 4.8) from kernel.org which
do not support C11.
Travis CI uses Ubuntu 14.04 with gcc 4.8.4 which incorrectly throws an
error for disk/part.c in C11 mode.

To get things right we would have to
* build our own cross tool chains based on a current gcc version
* use our own tool chain in Travis for x86-64 or use a docker
  container with a current gcc version.

In the long run heading for C11 would be the right thing to do.
Until then use an initializer { '<', 'N', 'U', 'L', 'L', '>' }.
It looks ugly but does not consume more bytes once compiled.

Regards

Heinrich

> 
>>
>>> +     int len = utf16_strnlen(str, precision);
>>> +     u8 utf8[len * MAX_UTF8_PER_UTF16];
>>
>> Didn't you forget 1 byte for \0 here?
>>
>> This is what strlnlen does:
>>
>> The strnlen() function returns the number of characters in the string
>> pointed to by s, **excluding** the terminating null byte ('\0'), but at
>> most maxlen.
>>
>> I would expect the exclusion of the terminating null word by an
>> utf16_strnlen function.
> 
> you are right, but fixing the wrong problem.. the code is definitely
> wrong since length of a utf16 string != length of a utf8 string, and
> we don't need to append a null terminator.. so my logic below using
> 'len' is wrong.  I'll fix that in the next version.
> 
>>> +     int i;
>>> +
>>> +     *utf16_to_utf8(utf8, str, len) = '\0';
>>> +
>>> +     if (!(flags & LEFT))
>>> +             while (len < field_width--)
>>> +                     ADDCH(buf, ' ');
>>> +     for (i = 0; i < len; ++i)
>>> +             ADDCH(buf, utf8[i]);
>>> +     while (len < field_width--)
>>> +             ADDCH(buf, ' ');
>>> +     return buf;
>>> +}
>>> +
>>>  #ifdef CONFIG_CMD_NET
>>>  static const char hex_asc[] = "0123456789abcdef";
>>>  #define hex_asc_lo(x)        hex_asc[((x) & 0x0f)]
>>> @@ -528,8 +549,13 @@ repeat:
>>>                       continue;
>>>
>>>               case 's':
>>> -                     str = string(str, end, va_arg(args, char *),
>>> -                                  field_width, precision, flags);
>>> +                     if (qualifier == 'l') {
>>
>> %ls refers to wchar with implementation dependent width in the C standard.
>> There is no qualifier for 16-bit wchar. Couldn't we use %us here in
>> reference to the u-notation ( u'MyString' ). This would leave the path
>> open for a standard compliant '%ls'.
> 
> hmm, yeah, that is a clever idea, and I like it better than %A or %S..
> so if we go the c11 route I'll do that.  The c11 committee should have
> thought of that ;-)
> 
> BR,
> -R
> 
>> Best regards
>>
>> Heinrich
>>
>>> +                             str = string16(str, end, va_arg(args, u16 *),
>>> +                                            field_width, precision, flags);
>>> +                     } else {
>>> +                             str = string(str, end, va_arg(args, char *),
>>> +                                          field_width, precision, flags);
>>> +                     }
>>>                       continue;
>>>
>>>               case 'p':
>>>
> 

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [U-Boot, v0, 07/20] vsprintf.c: add wide string (%ls) support
  2017-08-08 23:08       ` Heinrich Schuchardt
@ 2017-08-08 23:20         ` Alexander Graf
  2017-08-08 23:39         ` Rob Clark
  1 sibling, 0 replies; 116+ messages in thread
From: Alexander Graf @ 2017-08-08 23:20 UTC (permalink / raw)
  To: u-boot



> Am 09.08.2017 um 00:08 schrieb Heinrich Schuchardt <xypron.glpk@gmx.de>:
> 
>> On 08/09/2017 12:44 AM, Rob Clark wrote:
>>> On Tue, Aug 8, 2017 at 6:03 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>>>> On 08/04/2017 09:31 PM, Rob Clark wrote:
>>>> This is convenient for efi_loader which deals a lot with utf16.
>>>> 
>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>> 
>>> Please, put this patch together with
>>> [PATCH] vsprintf.c: add GUID printing
>>> https://patchwork.ozlabs.org/patch/798362/
>>> and
>>> [PATCH v0 06/20] common: add some utf16 handling helpers
>>> https://patchwork.ozlabs.org/patch/797968/
>>> into a separate patch series.
>>> 
>>> These three patches can be reviewed independently of the efi_loader
>>> patches and probably will not be integrated via the efi-next tree.
>> 
>> I'll resend these as a separate patchset, and just not in next
>> revision of efi_loader patchset that it is a dependency
>> 
>>>> ---
>>>> lib/vsprintf.c | 30 ++++++++++++++++++++++++++++--
>>>> 1 file changed, 28 insertions(+), 2 deletions(-)
>>>> 
>>>> diff --git a/lib/vsprintf.c b/lib/vsprintf.c
>>>> index 874a2951f7..0c40f852ce 100644
>>>> --- a/lib/vsprintf.c
>>>> +++ b/lib/vsprintf.c
>>>> @@ -17,6 +17,7 @@
>>>> #include <linux/ctype.h>
>>>> 
>>>> #include <common.h>
>>>> +#include <charset.h>
>>>> 
>>>> #include <div64.h>
>>>> #define noinline __attribute__((noinline))
>>>> @@ -270,6 +271,26 @@ static char *string(char *buf, char *end, char *s, int field_width,
>>>>      return buf;
>>>> }
>>>> 
>>>> +static char *string16(char *buf, char *end, u16 *s, int field_width,
>>>> +             int precision, int flags)
>>>> +{
>>>> +     u16 *str = s ? s : L"<NULL>";
>>> Please, do not use the L-notation here as it requires -fshort-wchar.
>>> As we currently cannot switch the complete project to C11 you cannot use
>>> the u-notation either.
>> 
>> current plan was to either switch whole project to -fshort-wchar or
>> c11 and rework these patches (as well as a few patches in the
>> efi_loader patchset).  (In the c11 case, I'm not sure what we'll use
>> as the fmt string, since afaict that isn't specified.  We could use %S
>> although that seems to be a deprecated way to do %ls, or something
>> different like %A, I guess)..
>> 
>> how far are we from c11?  If there is stuff I can do to help let me
>> know.  If feasible, I'd rather do that first rather than have a bunch
>> of stuff in vsprintf and elsewhere that needs to be cleaned up later
>> after the switch.
> 
> buildman downloads very old compilers (gcc < 4.8) from kernel.org which
> do not support C11.
> Travis CI uses Ubuntu 14.04 with gcc 4.8.4 which incorrectly throws an
> error for disk/part.c in C11 mode.
> 
> To get things right we would have to
> * build our own cross tool chains based on a current gcc version
> * use our own tool chain in Travis for x86-64 or use a docker
>  container with a current gcc version.
> 
> In the long run heading for C11 would be the right thing to do.
> Until then use an initializer { '<', 'N', 'U', 'L', 'L', '>' }.

Don't forget the , 0 :)

Alex

> It looks ugly but does not consume more bytes once compiled.
> 
> Regards
> 
> Heinrich
> 
>> 
>>> 
>>>> +     int len = utf16_strnlen(str, precision);
>>>> +     u8 utf8[len * MAX_UTF8_PER_UTF16];
>>> 
>>> Didn't you forget 1 byte for \0 here?
>>> 
>>> This is what strlnlen does:
>>> 
>>> The strnlen() function returns the number of characters in the string
>>> pointed to by s, **excluding** the terminating null byte ('\0'), but at
>>> most maxlen.
>>> 
>>> I would expect the exclusion of the terminating null word by an
>>> utf16_strnlen function.
>> 
>> you are right, but fixing the wrong problem.. the code is definitely
>> wrong since length of a utf16 string != length of a utf8 string, and
>> we don't need to append a null terminator.. so my logic below using
>> 'len' is wrong.  I'll fix that in the next version.
>> 
>>>> +     int i;
>>>> +
>>>> +     *utf16_to_utf8(utf8, str, len) = '\0';
>>>> +
>>>> +     if (!(flags & LEFT))
>>>> +             while (len < field_width--)
>>>> +                     ADDCH(buf, ' ');
>>>> +     for (i = 0; i < len; ++i)
>>>> +             ADDCH(buf, utf8[i]);
>>>> +     while (len < field_width--)
>>>> +             ADDCH(buf, ' ');
>>>> +     return buf;
>>>> +}
>>>> +
>>>> #ifdef CONFIG_CMD_NET
>>>> static const char hex_asc[] = "0123456789abcdef";
>>>> #define hex_asc_lo(x)        hex_asc[((x) & 0x0f)]
>>>> @@ -528,8 +549,13 @@ repeat:
>>>>                      continue;
>>>> 
>>>>              case 's':
>>>> -                     str = string(str, end, va_arg(args, char *),
>>>> -                                  field_width, precision, flags);
>>>> +                     if (qualifier == 'l') {
>>> 
>>> %ls refers to wchar with implementation dependent width in the C standard.
>>> There is no qualifier for 16-bit wchar. Couldn't we use %us here in
>>> reference to the u-notation ( u'MyString' ). This would leave the path
>>> open for a standard compliant '%ls'.
>> 
>> hmm, yeah, that is a clever idea, and I like it better than %A or %S..
>> so if we go the c11 route I'll do that.  The c11 committee should have
>> thought of that ;-)
>> 
>> BR,
>> -R
>> 
>>> Best regards
>>> 
>>> Heinrich
>>> 
>>>> +                             str = string16(str, end, va_arg(args, u16 *),
>>>> +                                            field_width, precision, flags);
>>>> +                     } else {
>>>> +                             str = string(str, end, va_arg(args, char *),
>>>> +                                          field_width, precision, flags);
>>>> +                     }
>>>>                      continue;
>>>> 
>>>>              case 'p':
>>>> 
>> 
> 

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [U-Boot, v0, 06/20] common: add some utf16 handling helpers
  2017-08-08 22:50   ` [U-Boot] [U-Boot, v0, " Heinrich Schuchardt
@ 2017-08-08 23:21     ` Rob Clark
  0 siblings, 0 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-08 23:21 UTC (permalink / raw)
  To: u-boot

On Tue, Aug 8, 2017 at 6:50 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
> On 08/04/2017 09:31 PM, Rob Clark wrote:
>> We'll eventually want these in a few places in efi_loader, and also
>> vsprintf.
>>
>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>> ---
>>  common/Makefile              |  1 +
>>  common/charset.c             | 81 ++++++++++++++++++++++++++++++++++++++++++++
>>  include/charset.h            | 18 ++++++++++
>>  lib/efi_loader/efi_console.c | 17 ++--------
>>  4 files changed, 103 insertions(+), 14 deletions(-)
>>  create mode 100644 common/charset.c
>>  create mode 100644 include/charset.h
>>
>> diff --git a/common/Makefile b/common/Makefile
>> index 60681c845c..44c8e1ba52 100644
>> --- a/common/Makefile
>> +++ b/common/Makefile
>> @@ -175,5 +175,6 @@ obj-$(CONFIG_CMD_DFU) += dfu.o
>>  obj-y += command.o
>>  obj-y += s_record.o
>>  obj-y += xyzModem.o
>> +obj-y += charset.o
>>
>>  CFLAGS_env_embedded.o := -Wa,--no-warn -DENV_CRC=$(shell tools/envcrc 2>/dev/null)
>> diff --git a/common/charset.c b/common/charset.c
>> new file mode 100644
>> index 0000000000..eaff2e542e
>> --- /dev/null
>> +++ b/common/charset.c
>> @@ -0,0 +1,81 @@
>> +/*
>> + *  charset conversion utils
>> + *
>> + *  Copyright (c) 2017 Rob Clark
>> + *
>> + *  SPDX-License-Identifier:     GPL-2.0+
>> + */
>> +
>> +#include <common.h>
>> +#include <charset.h>
>> +
>> +/*
>> + * utf8/utf16 conversion mostly lifted from grub
>> + */
>> +
>> +size_t utf16_strlen(uint16_t *in)
>> +{
>> +     size_t i;
>> +     for (i = 0; in[i]; i++);
>> +     return i;
>> +}
>> +
>> +size_t utf16_strnlen(const uint16_t *in, size_t count)
>> +{
>> +     size_t i;
>> +     for (i = 0; count-- && in[i]; i++);
>> +     return i;
>> +}
>> +
>> +/* Convert UTF-16 to UTF-8.  */
>> +uint8_t *utf16_to_utf8(uint8_t *dest, const uint16_t *src, size_t size)
>> +{
>> +     uint32_t code_high = 0;
>> +
>> +     while (size--) {
>
> We should not read past the trailing null world. Check *src == 0 somewhere.

so, all the places this is used in u-boot, and all the places I've
seen it used in grub (which is where this code comes from.. I won't
claim to the a utfN expert, this is the first time I've looked at this
sort of thing), you already know the string length.. either via
"protocol" (ie. you know the size of the file-path efi_device_path
element) or you have to do one of the utf16_strlen() variants before
calling this to know the size of the output string.

so utf16_to_utf8() shouldn't rely on null terminators, that seems like
it is just a sign the caller is doing something wrong.

Not sure if there is an equiv to WARN_ON() in u-boot.. maybe just
assert()?  But checking for null should be more of an
assert()/WARN_ON() sort of thing, imho.

I'll add an assert(size == utf16_strnlen(src, size)) (unless someone
has something better to suggest)

>> +             uint32_t code = *src++;
>> +
>> +             if (code_high) {
>> +                     if (code >= 0xDC00 && code <= 0xDFFF) {
>> +                             /* Surrogate pair.  */
>> +                             code = ((code_high - 0xD800) << 10) + (code - 0xDC00) + 0x10000;
>> +
>> +                             *dest++ = (code >> 18) | 0xF0;
>> +                             *dest++ = ((code >> 12) & 0x3F) | 0x80;
>> +                             *dest++ = ((code >> 6) & 0x3F) | 0x80;
>> +                             *dest++ = (code & 0x3F) | 0x80;
>> +                     } else {
>> +                             /* Error...  */
>> +                             *dest++ = '?';
>> +                             /* *src may be valid. Don't eat it.  */
>> +                             src--;
>> +                     }
>> +
>> +                     code_high = 0;
>> +             } else {
>> +                     if (code <= 0x007F) {
>> +                             *dest++ = code;
>> +                     } else if (code <= 0x07FF) {
>> +                             *dest++ = (code >> 6) | 0xC0;
>> +                             *dest++ = (code & 0x3F) | 0x80;
>> +                     } else if (code >= 0xD800 && code <= 0xDBFF) {
>> +                             code_high = code;
>> +                             continue;
>> +                     } else if (code >= 0xDC00 && code <= 0xDFFF) {
>> +                             /* Error... */
>> +                             *dest++ = '?';
>
> The error handling is somewhat inconsistent:
>
> No output if code 0xD800-0xDBFF is the last word.
> Output '?' for 0xDC00-0xDFFF where not expected.
> Output extraneous '?' for 0xD800-0xDBFF not followed by 0xDC00-0xDBFF.

if you have something better to suggest I look at let me know.  Seems
like (and I'm assuming the grub code can't be too bad since it boots a
whole lot of linux systems every day) this should only happen with a
malformed utf16 string?

(for the record, my only contribution to this code is utf16_strnlen()
and comments (and correcting grub2's painful indentation style :-P))

BR,
-R


> Best regards
>
> Heinrich
>
>> +                     } else if (code < 0x10000) {
>> +                             *dest++ = (code >> 12) | 0xE0;
>> +                             *dest++ = ((code >> 6) & 0x3F) | 0x80;
>> +                             *dest++ = (code & 0x3F) | 0x80;
>> +                     } else {
>> +                             *dest++ = (code >> 18) | 0xF0;
>> +                             *dest++ = ((code >> 12) & 0x3F) | 0x80;
>> +                             *dest++ = ((code >> 6) & 0x3F) | 0x80;
>> +                             *dest++ = (code & 0x3F) | 0x80;
>> +                     }
>> +             }
>> +     }
>> +
>> +     return dest;
>> +}
>> diff --git a/include/charset.h b/include/charset.h
>> new file mode 100644
>> index 0000000000..2ee1172182
>> --- /dev/null
>> +++ b/include/charset.h
>> @@ -0,0 +1,18 @@
>> +/*
>> + *  charset conversion utils
>> + *
>> + *  Copyright (c) 2017 Rob Clark
>> + *
>> + *  SPDX-License-Identifier:     GPL-2.0+
>> + */
>> +
>> +#ifndef __CHARSET_H_
>> +#define __CHARSET_H_
>> +
>> +#define MAX_UTF8_PER_UTF16 4
>> +
>> +size_t utf16_strlen(uint16_t *in);
>> +size_t utf16_strnlen(const uint16_t *in, size_t count);
>> +uint8_t *utf16_to_utf8(uint8_t *dest, const uint16_t *src, size_t size);
>> +
>> +#endif /* __CHARSET_H_ */
>> diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
>> index 5ebce4b544..3fc82b8726 100644
>> --- a/lib/efi_loader/efi_console.c
>> +++ b/lib/efi_loader/efi_console.c
>> @@ -7,6 +7,7 @@
>>   */
>>
>>  #include <common.h>
>> +#include <charset.h>
>>  #include <efi_loader.h>
>>
>>  static bool console_size_queried;
>> @@ -138,20 +139,8 @@ static efi_status_t EFIAPI efi_cout_reset(
>>
>>  static void print_unicode_in_utf8(u16 c)
>>  {
>> -     char utf8[4] = { 0 };
>> -     char *b = utf8;
>> -
>> -     if (c < 0x80) {
>> -             *(b++) = c;
>> -     } else if (c < 0x800) {
>> -             *(b++) = 192 + c / 64;
>> -             *(b++) = 128 + c % 64;
>> -     } else {
>> -             *(b++) = 224 + c / 4096;
>> -             *(b++) = 128 + c / 64 % 64;
>> -             *(b++) = 128 + c % 64;
>> -     }
>> -
>> +     char utf8[MAX_UTF8_PER_UTF16] = { 0 };
>> +     utf16_to_utf8((u8 *)utf8, &c, 1);
>>       puts(utf8);
>>  }
>>
>>
>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [U-Boot, v0, 07/20] vsprintf.c: add wide string (%ls) support
  2017-08-08 23:08       ` Heinrich Schuchardt
  2017-08-08 23:20         ` Alexander Graf
@ 2017-08-08 23:39         ` Rob Clark
  2017-08-08 23:55           ` Alexander Graf
  2017-08-09  8:50           ` Peter Robinson
  1 sibling, 2 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-08 23:39 UTC (permalink / raw)
  To: u-boot

On Tue, Aug 8, 2017 at 7:08 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
> On 08/09/2017 12:44 AM, Rob Clark wrote:
>> On Tue, Aug 8, 2017 at 6:03 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>>> On 08/04/2017 09:31 PM, Rob Clark wrote:
>>>> This is convenient for efi_loader which deals a lot with utf16.
>>>>
>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>>
>>> Please, put this patch together with
>>> [PATCH] vsprintf.c: add GUID printing
>>> https://patchwork.ozlabs.org/patch/798362/
>>> and
>>> [PATCH v0 06/20] common: add some utf16 handling helpers
>>> https://patchwork.ozlabs.org/patch/797968/
>>> into a separate patch series.
>>>
>>> These three patches can be reviewed independently of the efi_loader
>>> patches and probably will not be integrated via the efi-next tree.
>>
>> I'll resend these as a separate patchset, and just not in next
>> revision of efi_loader patchset that it is a dependency
>>
>>>> ---
>>>>  lib/vsprintf.c | 30 ++++++++++++++++++++++++++++--
>>>>  1 file changed, 28 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/lib/vsprintf.c b/lib/vsprintf.c
>>>> index 874a2951f7..0c40f852ce 100644
>>>> --- a/lib/vsprintf.c
>>>> +++ b/lib/vsprintf.c
>>>> @@ -17,6 +17,7 @@
>>>>  #include <linux/ctype.h>
>>>>
>>>>  #include <common.h>
>>>> +#include <charset.h>
>>>>
>>>>  #include <div64.h>
>>>>  #define noinline __attribute__((noinline))
>>>> @@ -270,6 +271,26 @@ static char *string(char *buf, char *end, char *s, int field_width,
>>>>       return buf;
>>>>  }
>>>>
>>>> +static char *string16(char *buf, char *end, u16 *s, int field_width,
>>>> +             int precision, int flags)
>>>> +{
>>>> +     u16 *str = s ? s : L"<NULL>";
>>> Please, do not use the L-notation here as it requires -fshort-wchar.
>>> As we currently cannot switch the complete project to C11 you cannot use
>>> the u-notation either.
>>
>> current plan was to either switch whole project to -fshort-wchar or
>> c11 and rework these patches (as well as a few patches in the
>> efi_loader patchset).  (In the c11 case, I'm not sure what we'll use
>> as the fmt string, since afaict that isn't specified.  We could use %S
>> although that seems to be a deprecated way to do %ls, or something
>> different like %A, I guess)..
>>
>> how far are we from c11?  If there is stuff I can do to help let me
>> know.  If feasible, I'd rather do that first rather than have a bunch
>> of stuff in vsprintf and elsewhere that needs to be cleaned up later
>> after the switch.
>
> buildman downloads very old compilers (gcc < 4.8) from kernel.org which
> do not support C11.
> Travis CI uses Ubuntu 14.04 with gcc 4.8.4 which incorrectly throws an
> error for disk/part.c in C11 mode.

ugg, 4.8 is pretty old..   Not sure how much older than 4.8 buildman
uses.  It seems like *some* c11 was supported w/ >=4.6 so if we
approach the conversion piecemeal (for example skipping code that
triggers gcc bugs on old compilers) we might be able to keep 4.8.4
working until travis provides something newer.

(btw, even going back say 8 fedora releases or more, I've used distro
packaged arm and aarch64 toolchains exclusively.. are there that many
distro's where we really can't assume availability of an
cross-toolchain?  If there isn't something newer from kernel.org can
we just drop relying on ancient prebuilt toolchains?  I'm anyways not
hugely a fan of downloading binary executables from even kernel.org,
instead of using something from a distro build system which I at least
know is very locked down.)

> To get things right we would have to
> * build our own cross tool chains based on a current gcc version
> * use our own tool chain in Travis for x86-64 or use a docker
>   container with a current gcc version.
>
> In the long run heading for C11 would be the right thing to do.
> Until then use an initializer { '<', 'N', 'U', 'L', 'L', '>' }.
> It looks ugly but does not consume more bytes once compiled.
>

Sure, that I'm less worried about, as much as adding stuff that is
very soon going to be legacy.  Even in vfprintf.c it isn't such a big
deal, as efi_loader where it would be more cumbersome.

Maybe we can write out u"<NULL>" longhand in vsprintf.c as you
suggest, but restrict efi_loader to gcc >= 4.9?  That seems like it
shouldn't be a problem for any arm/arm64 device and it shouldn't be a
problem for any device that is likely to have an efi payload to load
in the first place..

BR,
-R

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [U-Boot, v0, 07/20] vsprintf.c: add wide string (%ls) support
  2017-08-08 23:39         ` Rob Clark
@ 2017-08-08 23:55           ` Alexander Graf
  2017-08-09  0:14             ` Rob Clark
  2017-08-09  8:50           ` Peter Robinson
  1 sibling, 1 reply; 116+ messages in thread
From: Alexander Graf @ 2017-08-08 23:55 UTC (permalink / raw)
  To: u-boot



On 09.08.17 00:39, Rob Clark wrote:
> On Tue, Aug 8, 2017 at 7:08 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>> On 08/09/2017 12:44 AM, Rob Clark wrote:
>>> On Tue, Aug 8, 2017 at 6:03 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>>>> On 08/04/2017 09:31 PM, Rob Clark wrote:
>>>>> This is convenient for efi_loader which deals a lot with utf16.
>>>>>
>>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>>>
>>>> Please, put this patch together with
>>>> [PATCH] vsprintf.c: add GUID printing
>>>> https://patchwork.ozlabs.org/patch/798362/
>>>> and
>>>> [PATCH v0 06/20] common: add some utf16 handling helpers
>>>> https://patchwork.ozlabs.org/patch/797968/
>>>> into a separate patch series.
>>>>
>>>> These three patches can be reviewed independently of the efi_loader
>>>> patches and probably will not be integrated via the efi-next tree.
>>>
>>> I'll resend these as a separate patchset, and just not in next
>>> revision of efi_loader patchset that it is a dependency
>>>
>>>>> ---
>>>>>   lib/vsprintf.c | 30 ++++++++++++++++++++++++++++--
>>>>>   1 file changed, 28 insertions(+), 2 deletions(-)
>>>>>
>>>>> diff --git a/lib/vsprintf.c b/lib/vsprintf.c
>>>>> index 874a2951f7..0c40f852ce 100644
>>>>> --- a/lib/vsprintf.c
>>>>> +++ b/lib/vsprintf.c
>>>>> @@ -17,6 +17,7 @@
>>>>>   #include <linux/ctype.h>
>>>>>
>>>>>   #include <common.h>
>>>>> +#include <charset.h>
>>>>>
>>>>>   #include <div64.h>
>>>>>   #define noinline __attribute__((noinline))
>>>>> @@ -270,6 +271,26 @@ static char *string(char *buf, char *end, char *s, int field_width,
>>>>>        return buf;
>>>>>   }
>>>>>
>>>>> +static char *string16(char *buf, char *end, u16 *s, int field_width,
>>>>> +             int precision, int flags)
>>>>> +{
>>>>> +     u16 *str = s ? s : L"<NULL>";
>>>> Please, do not use the L-notation here as it requires -fshort-wchar.
>>>> As we currently cannot switch the complete project to C11 you cannot use
>>>> the u-notation either.
>>>
>>> current plan was to either switch whole project to -fshort-wchar or
>>> c11 and rework these patches (as well as a few patches in the
>>> efi_loader patchset).  (In the c11 case, I'm not sure what we'll use
>>> as the fmt string, since afaict that isn't specified.  We could use %S
>>> although that seems to be a deprecated way to do %ls, or something
>>> different like %A, I guess)..
>>>
>>> how far are we from c11?  If there is stuff I can do to help let me
>>> know.  If feasible, I'd rather do that first rather than have a bunch
>>> of stuff in vsprintf and elsewhere that needs to be cleaned up later
>>> after the switch.
>>
>> buildman downloads very old compilers (gcc < 4.8) from kernel.org which
>> do not support C11.
>> Travis CI uses Ubuntu 14.04 with gcc 4.8.4 which incorrectly throws an
>> error for disk/part.c in C11 mode.
> 
> ugg, 4.8 is pretty old..   Not sure how much older than 4.8 buildman
> uses.  It seems like *some* c11 was supported w/ >=4.6 so if we
> approach the conversion piecemeal (for example skipping code that
> triggers gcc bugs on old compilers) we might be able to keep 4.8.4
> working until travis provides something newer.
> 
> (btw, even going back say 8 fedora releases or more, I've used distro
> packaged arm and aarch64 toolchains exclusively.. are there that many
> distro's where we really can't assume availability of an
> cross-toolchain?  If there isn't something newer from kernel.org can
> we just drop relying on ancient prebuilt toolchains?  I'm anyways not
> hugely a fan of downloading binary executables from even kernel.org,
> instead of using something from a distro build system which I at least
> know is very locked down.)
> 
>> To get things right we would have to
>> * build our own cross tool chains based on a current gcc version
>> * use our own tool chain in Travis for x86-64 or use a docker
>>    container with a current gcc version.
>>
>> In the long run heading for C11 would be the right thing to do.
>> Until then use an initializer { '<', 'N', 'U', 'L', 'L', '>' }.
>> It looks ugly but does not consume more bytes once compiled.
>>
> 
> Sure, that I'm less worried about, as much as adding stuff that is
> very soon going to be legacy.  Even in vfprintf.c it isn't such a big
> deal, as efi_loader where it would be more cumbersome.
> 
> Maybe we can write out u"<NULL>" longhand in vsprintf.c as you
> suggest, but restrict efi_loader to gcc >= 4.9?  That seems like it
> shouldn't be a problem for any arm/arm64 device and it shouldn't be a
> problem for any device that is likely to have an efi payload to load
> in the first place..

I don't understand? We enable EFI_LOADER on all arm/arm64 systems for a 
good reason, so they all get checked by travis. If we break travis, that 
won't do anyone any good.

I do remember however that Tom wanted to set certain compiler versions 
as minimum required versions. Tom, do you remember which one that was?


Alex

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [U-Boot, v0, 07/20] vsprintf.c: add wide string (%ls) support
  2017-08-08 23:55           ` Alexander Graf
@ 2017-08-09  0:14             ` Rob Clark
  2017-08-09  1:14               ` Rob Clark
  2017-08-09 11:27               ` Tom Rini
  0 siblings, 2 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-09  0:14 UTC (permalink / raw)
  To: u-boot

On Tue, Aug 8, 2017 at 7:55 PM, Alexander Graf <agraf@suse.de> wrote:
>
>
> On 09.08.17 00:39, Rob Clark wrote:
>>
>> On Tue, Aug 8, 2017 at 7:08 PM, Heinrich Schuchardt <xypron.glpk@gmx.de>
>> wrote:
>>>
>>> On 08/09/2017 12:44 AM, Rob Clark wrote:
>>>>
>>>> On Tue, Aug 8, 2017 at 6:03 PM, Heinrich Schuchardt <xypron.glpk@gmx.de>
>>>> wrote:
>>>>>
>>>>> On 08/04/2017 09:31 PM, Rob Clark wrote:
>>>>>>
>>>>>> This is convenient for efi_loader which deals a lot with utf16.
>>>>>>
>>>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>>>>
>>>>>
>>>>> Please, put this patch together with
>>>>> [PATCH] vsprintf.c: add GUID printing
>>>>> https://patchwork.ozlabs.org/patch/798362/
>>>>> and
>>>>> [PATCH v0 06/20] common: add some utf16 handling helpers
>>>>> https://patchwork.ozlabs.org/patch/797968/
>>>>> into a separate patch series.
>>>>>
>>>>> These three patches can be reviewed independently of the efi_loader
>>>>> patches and probably will not be integrated via the efi-next tree.
>>>>
>>>>
>>>> I'll resend these as a separate patchset, and just not in next
>>>> revision of efi_loader patchset that it is a dependency
>>>>
>>>>>> ---
>>>>>>   lib/vsprintf.c | 30 ++++++++++++++++++++++++++++--
>>>>>>   1 file changed, 28 insertions(+), 2 deletions(-)
>>>>>>
>>>>>> diff --git a/lib/vsprintf.c b/lib/vsprintf.c
>>>>>> index 874a2951f7..0c40f852ce 100644
>>>>>> --- a/lib/vsprintf.c
>>>>>> +++ b/lib/vsprintf.c
>>>>>> @@ -17,6 +17,7 @@
>>>>>>   #include <linux/ctype.h>
>>>>>>
>>>>>>   #include <common.h>
>>>>>> +#include <charset.h>
>>>>>>
>>>>>>   #include <div64.h>
>>>>>>   #define noinline __attribute__((noinline))
>>>>>> @@ -270,6 +271,26 @@ static char *string(char *buf, char *end, char
>>>>>> *s, int field_width,
>>>>>>        return buf;
>>>>>>   }
>>>>>>
>>>>>> +static char *string16(char *buf, char *end, u16 *s, int field_width,
>>>>>> +             int precision, int flags)
>>>>>> +{
>>>>>> +     u16 *str = s ? s : L"<NULL>";
>>>>>
>>>>> Please, do not use the L-notation here as it requires -fshort-wchar.
>>>>> As we currently cannot switch the complete project to C11 you cannot
>>>>> use
>>>>> the u-notation either.
>>>>
>>>>
>>>> current plan was to either switch whole project to -fshort-wchar or
>>>> c11 and rework these patches (as well as a few patches in the
>>>> efi_loader patchset).  (In the c11 case, I'm not sure what we'll use
>>>> as the fmt string, since afaict that isn't specified.  We could use %S
>>>> although that seems to be a deprecated way to do %ls, or something
>>>> different like %A, I guess)..
>>>>
>>>> how far are we from c11?  If there is stuff I can do to help let me
>>>> know.  If feasible, I'd rather do that first rather than have a bunch
>>>> of stuff in vsprintf and elsewhere that needs to be cleaned up later
>>>> after the switch.
>>>
>>>
>>> buildman downloads very old compilers (gcc < 4.8) from kernel.org which
>>> do not support C11.
>>> Travis CI uses Ubuntu 14.04 with gcc 4.8.4 which incorrectly throws an
>>> error for disk/part.c in C11 mode.
>>
>>
>> ugg, 4.8 is pretty old..   Not sure how much older than 4.8 buildman
>> uses.  It seems like *some* c11 was supported w/ >=4.6 so if we
>> approach the conversion piecemeal (for example skipping code that
>> triggers gcc bugs on old compilers) we might be able to keep 4.8.4
>> working until travis provides something newer.
>>
>> (btw, even going back say 8 fedora releases or more, I've used distro
>> packaged arm and aarch64 toolchains exclusively.. are there that many
>> distro's where we really can't assume availability of an
>> cross-toolchain?  If there isn't something newer from kernel.org can
>> we just drop relying on ancient prebuilt toolchains?  I'm anyways not
>> hugely a fan of downloading binary executables from even kernel.org,
>> instead of using something from a distro build system which I at least
>> know is very locked down.)
>>
>>> To get things right we would have to
>>> * build our own cross tool chains based on a current gcc version
>>> * use our own tool chain in Travis for x86-64 or use a docker
>>>    container with a current gcc version.
>>>
>>> In the long run heading for C11 would be the right thing to do.
>>> Until then use an initializer { '<', 'N', 'U', 'L', 'L', '>' }.
>>> It looks ugly but does not consume more bytes once compiled.
>>>
>>
>> Sure, that I'm less worried about, as much as adding stuff that is
>> very soon going to be legacy.  Even in vfprintf.c it isn't such a big
>> deal, as efi_loader where it would be more cumbersome.
>>
>> Maybe we can write out u"<NULL>" longhand in vsprintf.c as you
>> suggest, but restrict efi_loader to gcc >= 4.9?  That seems like it
>> shouldn't be a problem for any arm/arm64 device and it shouldn't be a
>> problem for any device that is likely to have an efi payload to load
>> in the first place..
>
>
> I don't understand? We enable EFI_LOADER on all arm/arm64 systems for a good
> reason, so they all get checked by travis. If we break travis, that won't do
> anyone any good.

I was more thinking if there was some oddball non-arm arch that u-boot
supported which didn't haven good mainline gcc support and required
something ancient ;-)

For arm/arm64, it seems like we could somehow come up w/ a solution
using a new enough toolchain, given that arm support in gcc has been
good for a long time.. not like the old days where we had to use some
codesourcery build (or figure out how to compile the cs src code drop
ourselves).  A toolchain >= 4.9 for arm/arm64 shouldn't be hard to
come by.

BR,
-R

> I do remember however that Tom wanted to set certain compiler versions as
> minimum required versions. Tom, do you remember which one that was?
>
>
> Alex

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [U-Boot, v0, 07/20] vsprintf.c: add wide string (%ls) support
  2017-08-09  0:14             ` Rob Clark
@ 2017-08-09  1:14               ` Rob Clark
  2017-08-09 11:27               ` Tom Rini
  1 sibling, 0 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-09  1:14 UTC (permalink / raw)
  To: u-boot

On Tue, Aug 8, 2017 at 8:14 PM, Rob Clark <robdclark@gmail.com> wrote:
> On Tue, Aug 8, 2017 at 7:55 PM, Alexander Graf <agraf@suse.de> wrote:
>>
>>
>> On 09.08.17 00:39, Rob Clark wrote:
>>>
>>> On Tue, Aug 8, 2017 at 7:08 PM, Heinrich Schuchardt <xypron.glpk@gmx.de>
>>> wrote:
>>>>
>>>> On 08/09/2017 12:44 AM, Rob Clark wrote:
>>>>>
>>>>> On Tue, Aug 8, 2017 at 6:03 PM, Heinrich Schuchardt <xypron.glpk@gmx.de>
>>>>> wrote:
>>>>>>
>>>>>> On 08/04/2017 09:31 PM, Rob Clark wrote:
>>>>>>>
>>>>>>> This is convenient for efi_loader which deals a lot with utf16.
>>>>>>>
>>>>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
>>>>>>
>>>>>>
>>>>>> Please, put this patch together with
>>>>>> [PATCH] vsprintf.c: add GUID printing
>>>>>> https://patchwork.ozlabs.org/patch/798362/
>>>>>> and
>>>>>> [PATCH v0 06/20] common: add some utf16 handling helpers
>>>>>> https://patchwork.ozlabs.org/patch/797968/
>>>>>> into a separate patch series.
>>>>>>
>>>>>> These three patches can be reviewed independently of the efi_loader
>>>>>> patches and probably will not be integrated via the efi-next tree.
>>>>>
>>>>>
>>>>> I'll resend these as a separate patchset, and just not in next
>>>>> revision of efi_loader patchset that it is a dependency
>>>>>
>>>>>>> ---
>>>>>>>   lib/vsprintf.c | 30 ++++++++++++++++++++++++++++--
>>>>>>>   1 file changed, 28 insertions(+), 2 deletions(-)
>>>>>>>
>>>>>>> diff --git a/lib/vsprintf.c b/lib/vsprintf.c
>>>>>>> index 874a2951f7..0c40f852ce 100644
>>>>>>> --- a/lib/vsprintf.c
>>>>>>> +++ b/lib/vsprintf.c
>>>>>>> @@ -17,6 +17,7 @@
>>>>>>>   #include <linux/ctype.h>
>>>>>>>
>>>>>>>   #include <common.h>
>>>>>>> +#include <charset.h>
>>>>>>>
>>>>>>>   #include <div64.h>
>>>>>>>   #define noinline __attribute__((noinline))
>>>>>>> @@ -270,6 +271,26 @@ static char *string(char *buf, char *end, char
>>>>>>> *s, int field_width,
>>>>>>>        return buf;
>>>>>>>   }
>>>>>>>
>>>>>>> +static char *string16(char *buf, char *end, u16 *s, int field_width,
>>>>>>> +             int precision, int flags)
>>>>>>> +{
>>>>>>> +     u16 *str = s ? s : L"<NULL>";
>>>>>>
>>>>>> Please, do not use the L-notation here as it requires -fshort-wchar.
>>>>>> As we currently cannot switch the complete project to C11 you cannot
>>>>>> use
>>>>>> the u-notation either.
>>>>>
>>>>>
>>>>> current plan was to either switch whole project to -fshort-wchar or
>>>>> c11 and rework these patches (as well as a few patches in the
>>>>> efi_loader patchset).  (In the c11 case, I'm not sure what we'll use
>>>>> as the fmt string, since afaict that isn't specified.  We could use %S
>>>>> although that seems to be a deprecated way to do %ls, or something
>>>>> different like %A, I guess)..
>>>>>
>>>>> how far are we from c11?  If there is stuff I can do to help let me
>>>>> know.  If feasible, I'd rather do that first rather than have a bunch
>>>>> of stuff in vsprintf and elsewhere that needs to be cleaned up later
>>>>> after the switch.
>>>>
>>>>
>>>> buildman downloads very old compilers (gcc < 4.8) from kernel.org which
>>>> do not support C11.
>>>> Travis CI uses Ubuntu 14.04 with gcc 4.8.4 which incorrectly throws an
>>>> error for disk/part.c in C11 mode.
>>>
>>>
>>> ugg, 4.8 is pretty old..   Not sure how much older than 4.8 buildman
>>> uses.  It seems like *some* c11 was supported w/ >=4.6 so if we
>>> approach the conversion piecemeal (for example skipping code that
>>> triggers gcc bugs on old compilers) we might be able to keep 4.8.4
>>> working until travis provides something newer.
>>>
>>> (btw, even going back say 8 fedora releases or more, I've used distro
>>> packaged arm and aarch64 toolchains exclusively.. are there that many
>>> distro's where we really can't assume availability of an
>>> cross-toolchain?  If there isn't something newer from kernel.org can
>>> we just drop relying on ancient prebuilt toolchains?  I'm anyways not
>>> hugely a fan of downloading binary executables from even kernel.org,
>>> instead of using something from a distro build system which I at least
>>> know is very locked down.)
>>>
>>>> To get things right we would have to
>>>> * build our own cross tool chains based on a current gcc version
>>>> * use our own tool chain in Travis for x86-64 or use a docker
>>>>    container with a current gcc version.
>>>>
>>>> In the long run heading for C11 would be the right thing to do.
>>>> Until then use an initializer { '<', 'N', 'U', 'L', 'L', '>' }.
>>>> It looks ugly but does not consume more bytes once compiled.
>>>>
>>>
>>> Sure, that I'm less worried about, as much as adding stuff that is
>>> very soon going to be legacy.  Even in vfprintf.c it isn't such a big
>>> deal, as efi_loader where it would be more cumbersome.
>>>
>>> Maybe we can write out u"<NULL>" longhand in vsprintf.c as you
>>> suggest, but restrict efi_loader to gcc >= 4.9?  That seems like it
>>> shouldn't be a problem for any arm/arm64 device and it shouldn't be a
>>> problem for any device that is likely to have an efi payload to load
>>> in the first place..
>>
>>
>> I don't understand? We enable EFI_LOADER on all arm/arm64 systems for a good
>> reason, so they all get checked by travis. If we break travis, that won't do
>> anyone any good.
>
> I was more thinking if there was some oddball non-arm arch that u-boot
> supported which didn't haven good mainline gcc support and required
> something ancient ;-)
>
> For arm/arm64, it seems like we could somehow come up w/ a solution
> using a new enough toolchain, given that arm support in gcc has been
> good for a long time.. not like the old days where we had to use some
> codesourcery build (or figure out how to compile the cs src code drop
> ourselves).  A toolchain >= 4.9 for arm/arm64 shouldn't be hard to
> come by.
>

btw, I haven't confirmed it yet (I don't have such an old compiler
handy) but I *think* according to [1] that gcc 4.7 should be new
enough for u"string" literals.. which is kind of the main thing we
want at this point.

that sets the compiler version dependency bar *pretty* low..

[1] https://gcc.gnu.org/gcc-4.7/changes.html

BR,
-R

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [U-Boot, v0, 07/20] vsprintf.c: add wide string (%ls) support
  2017-08-08 23:39         ` Rob Clark
  2017-08-08 23:55           ` Alexander Graf
@ 2017-08-09  8:50           ` Peter Robinson
  1 sibling, 0 replies; 116+ messages in thread
From: Peter Robinson @ 2017-08-09  8:50 UTC (permalink / raw)
  To: u-boot

>> buildman downloads very old compilers (gcc < 4.8) from kernel.org which
>> do not support C11.
>> Travis CI uses Ubuntu 14.04 with gcc 4.8.4 which incorrectly throws an
>> error for disk/part.c in C11 mode.
>
> ugg, 4.8 is pretty old..   Not sure how much older than 4.8 buildman
> uses.  It seems like *some* c11 was supported w/ >=4.6 so if we
> approach the conversion piecemeal (for example skipping code that
> triggers gcc bugs on old compilers) we might be able to keep 4.8.4
> working until travis provides something newer.

For reference el7 (RHEL/CentOS etc) has gcc 4.8.5

> (btw, even going back say 8 fedora releases or more, I've used distro
> packaged arm and aarch64 toolchains exclusively.. are there that many
> distro's where we really can't assume availability of an
> cross-toolchain?  If there isn't something newer from kernel.org can
> we just drop relying on ancient prebuilt toolchains?  I'm anyways not
> hugely a fan of downloading binary executables from even kernel.org,
> instead of using something from a distro build system which I at least
> know is very locked down.)
>
>> To get things right we would have to
>> * build our own cross tool chains based on a current gcc version
>> * use our own tool chain in Travis for x86-64 or use a docker
>>   container with a current gcc version.
>>
>> In the long run heading for C11 would be the right thing to do.
>> Until then use an initializer { '<', 'N', 'U', 'L', 'L', '>' }.
>> It looks ugly but does not consume more bytes once compiled.
>>
>
> Sure, that I'm less worried about, as much as adding stuff that is
> very soon going to be legacy.  Even in vfprintf.c it isn't such a big
> deal, as efi_loader where it would be more cumbersome.
>
> Maybe we can write out u"<NULL>" longhand in vsprintf.c as you
> suggest, but restrict efi_loader to gcc >= 4.9?  That seems like it
> shouldn't be a problem for any arm/arm64 device and it shouldn't be a
> problem for any device that is likely to have an efi payload to load
> in the first place..
>
> BR,
> -R
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> https://lists.denx.de/listinfo/u-boot

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [U-Boot, v0, 07/20] vsprintf.c: add wide string (%ls) support
  2017-08-09  0:14             ` Rob Clark
  2017-08-09  1:14               ` Rob Clark
@ 2017-08-09 11:27               ` Tom Rini
  2017-08-10  2:16                 ` rick at andestech.com
  1 sibling, 1 reply; 116+ messages in thread
From: Tom Rini @ 2017-08-09 11:27 UTC (permalink / raw)
  To: u-boot

On Tue, Aug 08, 2017 at 08:14:41PM -0400, Rob Clark wrote:
> On Tue, Aug 8, 2017 at 7:55 PM, Alexander Graf <agraf@suse.de> wrote:
> >
> >
> > On 09.08.17 00:39, Rob Clark wrote:
> >>
> >> On Tue, Aug 8, 2017 at 7:08 PM, Heinrich Schuchardt <xypron.glpk@gmx.de>
> >> wrote:
> >>>
> >>> On 08/09/2017 12:44 AM, Rob Clark wrote:
> >>>>
> >>>> On Tue, Aug 8, 2017 at 6:03 PM, Heinrich Schuchardt <xypron.glpk@gmx.de>
> >>>> wrote:
> >>>>>
> >>>>> On 08/04/2017 09:31 PM, Rob Clark wrote:
> >>>>>>
> >>>>>> This is convenient for efi_loader which deals a lot with utf16.
> >>>>>>
> >>>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
> >>>>>
> >>>>>
> >>>>> Please, put this patch together with
> >>>>> [PATCH] vsprintf.c: add GUID printing
> >>>>> https://patchwork.ozlabs.org/patch/798362/
> >>>>> and
> >>>>> [PATCH v0 06/20] common: add some utf16 handling helpers
> >>>>> https://patchwork.ozlabs.org/patch/797968/
> >>>>> into a separate patch series.
> >>>>>
> >>>>> These three patches can be reviewed independently of the efi_loader
> >>>>> patches and probably will not be integrated via the efi-next tree.
> >>>>
> >>>>
> >>>> I'll resend these as a separate patchset, and just not in next
> >>>> revision of efi_loader patchset that it is a dependency
> >>>>
> >>>>>> ---
> >>>>>>   lib/vsprintf.c | 30 ++++++++++++++++++++++++++++--
> >>>>>>   1 file changed, 28 insertions(+), 2 deletions(-)
> >>>>>>
> >>>>>> diff --git a/lib/vsprintf.c b/lib/vsprintf.c
> >>>>>> index 874a2951f7..0c40f852ce 100644
> >>>>>> --- a/lib/vsprintf.c
> >>>>>> +++ b/lib/vsprintf.c
> >>>>>> @@ -17,6 +17,7 @@
> >>>>>>   #include <linux/ctype.h>
> >>>>>>
> >>>>>>   #include <common.h>
> >>>>>> +#include <charset.h>
> >>>>>>
> >>>>>>   #include <div64.h>
> >>>>>>   #define noinline __attribute__((noinline))
> >>>>>> @@ -270,6 +271,26 @@ static char *string(char *buf, char *end, char
> >>>>>> *s, int field_width,
> >>>>>>        return buf;
> >>>>>>   }
> >>>>>>
> >>>>>> +static char *string16(char *buf, char *end, u16 *s, int field_width,
> >>>>>> +             int precision, int flags)
> >>>>>> +{
> >>>>>> +     u16 *str = s ? s : L"<NULL>";
> >>>>>
> >>>>> Please, do not use the L-notation here as it requires -fshort-wchar.
> >>>>> As we currently cannot switch the complete project to C11 you cannot
> >>>>> use
> >>>>> the u-notation either.
> >>>>
> >>>>
> >>>> current plan was to either switch whole project to -fshort-wchar or
> >>>> c11 and rework these patches (as well as a few patches in the
> >>>> efi_loader patchset).  (In the c11 case, I'm not sure what we'll use
> >>>> as the fmt string, since afaict that isn't specified.  We could use %S
> >>>> although that seems to be a deprecated way to do %ls, or something
> >>>> different like %A, I guess)..
> >>>>
> >>>> how far are we from c11?  If there is stuff I can do to help let me
> >>>> know.  If feasible, I'd rather do that first rather than have a bunch
> >>>> of stuff in vsprintf and elsewhere that needs to be cleaned up later
> >>>> after the switch.
> >>>
> >>>
> >>> buildman downloads very old compilers (gcc < 4.8) from kernel.org which
> >>> do not support C11.
> >>> Travis CI uses Ubuntu 14.04 with gcc 4.8.4 which incorrectly throws an
> >>> error for disk/part.c in C11 mode.
> >>
> >>
> >> ugg, 4.8 is pretty old..   Not sure how much older than 4.8 buildman
> >> uses.  It seems like *some* c11 was supported w/ >=4.6 so if we
> >> approach the conversion piecemeal (for example skipping code that
> >> triggers gcc bugs on old compilers) we might be able to keep 4.8.4
> >> working until travis provides something newer.
> >>
> >> (btw, even going back say 8 fedora releases or more, I've used distro
> >> packaged arm and aarch64 toolchains exclusively.. are there that many
> >> distro's where we really can't assume availability of an
> >> cross-toolchain?  If there isn't something newer from kernel.org can
> >> we just drop relying on ancient prebuilt toolchains?  I'm anyways not
> >> hugely a fan of downloading binary executables from even kernel.org,
> >> instead of using something from a distro build system which I at least
> >> know is very locked down.)
> >>
> >>> To get things right we would have to
> >>> * build our own cross tool chains based on a current gcc version
> >>> * use our own tool chain in Travis for x86-64 or use a docker
> >>>    container with a current gcc version.
> >>>
> >>> In the long run heading for C11 would be the right thing to do.
> >>> Until then use an initializer { '<', 'N', 'U', 'L', 'L', '>' }.
> >>> It looks ugly but does not consume more bytes once compiled.
> >>>
> >>
> >> Sure, that I'm less worried about, as much as adding stuff that is
> >> very soon going to be legacy.  Even in vfprintf.c it isn't such a big
> >> deal, as efi_loader where it would be more cumbersome.
> >>
> >> Maybe we can write out u"<NULL>" longhand in vsprintf.c as you
> >> suggest, but restrict efi_loader to gcc >= 4.9?  That seems like it
> >> shouldn't be a problem for any arm/arm64 device and it shouldn't be a
> >> problem for any device that is likely to have an efi payload to load
> >> in the first place..
> >
> >
> > I don't understand? We enable EFI_LOADER on all arm/arm64 systems for a good
> > reason, so they all get checked by travis. If we break travis, that won't do
> > anyone any good.
> 
> I was more thinking if there was some oddball non-arm arch that u-boot
> supported which didn't haven good mainline gcc support and required
> something ancient ;-)

So, with v2018.01 I want to say that for ARM*, gcc-6.x is the minimum.

Looking around, nds32 requires gcc-4.4.4.  NDS32 folks, is there a newer
toolchain available?

Other than that, everything else has a gcc-6.x available in some form or
another.  Thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170809/20d99599/attachment.sig>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [U-Boot, v0, 07/20] vsprintf.c: add wide string (%ls) support
  2017-08-08 22:03   ` [U-Boot] [U-Boot, v0, " Heinrich Schuchardt
  2017-08-08 22:44     ` Rob Clark
  2017-08-08 22:52     ` Rob Clark
@ 2017-08-09 13:38     ` Rob Clark
  2017-08-09 13:48       ` Alexander Graf
  2 siblings, 1 reply; 116+ messages in thread
From: Rob Clark @ 2017-08-09 13:38 UTC (permalink / raw)
  To: u-boot

On Tue, Aug 8, 2017 at 6:03 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
> On 08/04/2017 09:31 PM, Rob Clark wrote:
>>
>> @@ -528,8 +549,13 @@ repeat:
>>                       continue;
>>
>>               case 's':
>> -                     str = string(str, end, va_arg(args, char *),
>> -                                  field_width, precision, flags);
>> +                     if (qualifier == 'l') {
>
> %ls refers to wchar with implementation dependent width in the C standard.
> There is no qualifier for 16-bit wchar. Couldn't we use %us here in
> reference to the u-notation ( u'MyString' ). This would leave the path
> open for a standard compliant '%ls'.
>

So two drawbacks I'm running into when converting to c11 u"string"
style, compared to the -fshort-wchar:

1) with -fshort-wchar plus %ls, gcc knows how to typecheck the
printf/sprintf/etc args
2) introducing a non-standard conversion character (since there
doesn't seem to be a standard one) means we need to drop -Wformat

So far, afaict, the only argument against -fshort-wchar seems to be
that someday ext4 might support utf32 filenames?  (And really
-fshort-wchar doesn't preclude that.  So I'm not sure this is a valid
argument.)

So independent of c11 (which might be a good idea for other reasons),
I'm back to thinking we should use -fshort-wchar.  Possibly as a
kconfig option that EFI_LOADER selects.. or possibly just
unconditionally.

Thoughts?

BR,
-R

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [U-Boot, v0, 07/20] vsprintf.c: add wide string (%ls) support
  2017-08-09 13:38     ` Rob Clark
@ 2017-08-09 13:48       ` Alexander Graf
  2017-08-09 14:35         ` Rob Clark
  0 siblings, 1 reply; 116+ messages in thread
From: Alexander Graf @ 2017-08-09 13:48 UTC (permalink / raw)
  To: u-boot



> Am 09.08.2017 um 14:38 schrieb Rob Clark <robdclark@gmail.com>:
> 
>> On Tue, Aug 8, 2017 at 6:03 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>>> On 08/04/2017 09:31 PM, Rob Clark wrote:
>>> 
>>> @@ -528,8 +549,13 @@ repeat:
>>>                      continue;
>>> 
>>>              case 's':
>>> -                     str = string(str, end, va_arg(args, char *),
>>> -                                  field_width, precision, flags);
>>> +                     if (qualifier == 'l') {
>> 
>> %ls refers to wchar with implementation dependent width in the C standard.
>> There is no qualifier for 16-bit wchar. Couldn't we use %us here in
>> reference to the u-notation ( u'MyString' ). This would leave the path
>> open for a standard compliant '%ls'.
>> 
> 
> So two drawbacks I'm running into when converting to c11 u"string"
> style, compared to the -fshort-wchar:
> 
> 1) with -fshort-wchar plus %ls, gcc knows how to typecheck the
> printf/sprintf/etc args
> 2) introducing a non-standard conversion character (since there
> doesn't seem to be a standard one) means we need to drop -Wformat
> 
> So far, afaict, the only argument against -fshort-wchar seems to be
> that someday ext4 might support utf32 filenames?  (And really
> -fshort-wchar doesn't preclude that.  So I'm not sure this is a valid
> argument.)
> 
> So independent of c11 (which might be a good idea for other reasons),
> I'm back to thinking we should use -fshort-wchar.  Possibly as a
> kconfig option that EFI_LOADER selects.. or possibly just
> unconditionally.
> 
> Thoughts?

If we select it, I'd rather have it be unconditional, to not oprn potential for undetected breakage.

Alex

> 
> BR,
> -R

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [U-Boot, v0, 07/20] vsprintf.c: add wide string (%ls) support
  2017-08-09 13:48       ` Alexander Graf
@ 2017-08-09 14:35         ` Rob Clark
  0 siblings, 0 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-09 14:35 UTC (permalink / raw)
  To: u-boot

On Wed, Aug 9, 2017 at 9:48 AM, Alexander Graf <agraf@suse.de> wrote:
>
>
>> Am 09.08.2017 um 14:38 schrieb Rob Clark <robdclark@gmail.com>:
>>
>>> On Tue, Aug 8, 2017 at 6:03 PM, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
>>>> On 08/04/2017 09:31 PM, Rob Clark wrote:
>>>>
>>>> @@ -528,8 +549,13 @@ repeat:
>>>>                      continue;
>>>>
>>>>              case 's':
>>>> -                     str = string(str, end, va_arg(args, char *),
>>>> -                                  field_width, precision, flags);
>>>> +                     if (qualifier == 'l') {
>>>
>>> %ls refers to wchar with implementation dependent width in the C standard.
>>> There is no qualifier for 16-bit wchar. Couldn't we use %us here in
>>> reference to the u-notation ( u'MyString' ). This would leave the path
>>> open for a standard compliant '%ls'.
>>>
>>
>> So two drawbacks I'm running into when converting to c11 u"string"
>> style, compared to the -fshort-wchar:
>>
>> 1) with -fshort-wchar plus %ls, gcc knows how to typecheck the
>> printf/sprintf/etc args
>> 2) introducing a non-standard conversion character (since there
>> doesn't seem to be a standard one) means we need to drop -Wformat
>>
>> So far, afaict, the only argument against -fshort-wchar seems to be
>> that someday ext4 might support utf32 filenames?  (And really
>> -fshort-wchar doesn't preclude that.  So I'm not sure this is a valid
>> argument.)
>>
>> So independent of c11 (which might be a good idea for other reasons),
>> I'm back to thinking we should use -fshort-wchar.  Possibly as a
>> kconfig option that EFI_LOADER selects.. or possibly just
>> unconditionally.
>>
>> Thoughts?
>
> If we select it, I'd rather have it be unconditional, to not oprn potential for undetected breakage.
>

I could go either way on kconfig option vs unconditional
-fshort-wchar.  Although as far as breakage, that seems pretty
solvable by adding a fallback.efi -> grub.efi test, and maybe
something that exercises device-path-to-text, in travis.

I suppose it might be useful, for example, for TINY_PRINTF to depend
on !CC_SHORT_WCHAR?  Not sure.

I'll include a patch w/ kconfig option in my patchset for now, but
happy to drop it if folks want to do -fshort-wchar unconditionally.

BR,
-R

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 00/20] enough UEFI for standard distro boot
  2017-08-04 19:31 [U-Boot] [PATCH v0 00/20] enough UEFI for standard distro boot Rob Clark
                   ` (20 preceding siblings ...)
  2017-08-05 15:58 ` [U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses Rob Clark
@ 2017-08-10  1:32 ` Tom Rini
  2017-08-10 10:41   ` Rob Clark
  21 siblings, 1 reply; 116+ messages in thread
From: Tom Rini @ 2017-08-10  1:32 UTC (permalink / raw)
  To: u-boot

On Fri, Aug 04, 2017 at 03:31:42PM -0400, Rob Clark wrote:

> This patchset fleshes out EFI_LOADER enough to support booting an
> upstream \EFI\BOOT\bootaa64.efi (which then loads fallback.efi and
> then eventually the per-distro shim.efi which loads the per-distro
> grubaa64.efi) without resorting to hacks to hard-code u-boot to load
> a particular distro's grub, or other hacks like setting up the
> distro installation as live-media.
> 
> The first seven patches add dependencies that will be needed later
> in the series.  Patches 8-15 make u-boot work with upstream grub,
> without relying on distro patches.  Patches 16-19 add missing bits
> of the UEFI implementation needed to support shim/fallback.  And
> finally patch 20 adds bootmanager support to avoid shim/fallback
> after first boot.

In concept, I am in agreement with the goals of this patch series.  In
specifics, I'm going to skim around v0 and see if there's anything in
particular that I feel I need to jump in and comment on at this point.
Thanks for working on this!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170809/bd0e7617/attachment.sig>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [U-Boot, v0, 07/20] vsprintf.c: add wide string (%ls) support
  2017-08-09 11:27               ` Tom Rini
@ 2017-08-10  2:16                 ` rick at andestech.com
  0 siblings, 0 replies; 116+ messages in thread
From: rick at andestech.com @ 2017-08-10  2:16 UTC (permalink / raw)
  To: u-boot

Hi Tom

Yes, Nds32 has a newer toolchain gcc 4.9 available now.

Rick

-----Original Message-----
From: Tom Rini [mailto:trini at konsulko.com]
Sent: Wednesday, August 09, 2017 7:27 PM
To: Rob Clark; Rick Jian-Zhi Chen(陳建志)
Cc: Alexander Graf; Heinrich Schuchardt; U-Boot Mailing List; Peter Jones; Simon Glass; Sekhar Nori; Bin Meng
Subject: Re: [U-Boot,v0,07/20] vsprintf.c: add wide string (%ls) support

On Tue, Aug 08, 2017 at 08:14:41PM -0400, Rob Clark wrote:
> On Tue, Aug 8, 2017 at 7:55 PM, Alexander Graf <agraf@suse.de> wrote:
> >
> >
> > On 09.08.17 00:39, Rob Clark wrote:
> >>
> >> On Tue, Aug 8, 2017 at 7:08 PM, Heinrich Schuchardt
> >> <xypron.glpk@gmx.de>
> >> wrote:
> >>>
> >>> On 08/09/2017 12:44 AM, Rob Clark wrote:
> >>>>
> >>>> On Tue, Aug 8, 2017 at 6:03 PM, Heinrich Schuchardt
> >>>> <xypron.glpk@gmx.de>
> >>>> wrote:
> >>>>>
> >>>>> On 08/04/2017 09:31 PM, Rob Clark wrote:
> >>>>>>
> >>>>>> This is convenient for efi_loader which deals a lot with utf16.
> >>>>>>
> >>>>>> Signed-off-by: Rob Clark <robdclark@gmail.com>
> >>>>>
> >>>>>
> >>>>> Please, put this patch together with [PATCH] vsprintf.c: add
> >>>>> GUID printing https://patchwork.ozlabs.org/patch/798362/
> >>>>> and
> >>>>> [PATCH v0 06/20] common: add some utf16 handling helpers
> >>>>> https://patchwork.ozlabs.org/patch/797968/
> >>>>> into a separate patch series.
> >>>>>
> >>>>> These three patches can be reviewed independently of the
> >>>>> efi_loader patches and probably will not be integrated via the efi-next tree.
> >>>>
> >>>>
> >>>> I'll resend these as a separate patchset, and just not in next
> >>>> revision of efi_loader patchset that it is a dependency
> >>>>
> >>>>>> ---
> >>>>>>   lib/vsprintf.c | 30 ++++++++++++++++++++++++++++--
> >>>>>>   1 file changed, 28 insertions(+), 2 deletions(-)
> >>>>>>
> >>>>>> diff --git a/lib/vsprintf.c b/lib/vsprintf.c index
> >>>>>> 874a2951f7..0c40f852ce 100644
> >>>>>> --- a/lib/vsprintf.c
> >>>>>> +++ b/lib/vsprintf.c
> >>>>>> @@ -17,6 +17,7 @@
> >>>>>>   #include <linux/ctype.h>
> >>>>>>
> >>>>>>   #include <common.h>
> >>>>>> +#include <charset.h>
> >>>>>>
> >>>>>>   #include <div64.h>
> >>>>>>   #define noinline __attribute__((noinline)) @@ -270,6 +271,26
> >>>>>> @@ static char *string(char *buf, char *end, char *s, int
> >>>>>> field_width,
> >>>>>>        return buf;
> >>>>>>   }
> >>>>>>
> >>>>>> +static char *string16(char *buf, char *end, u16 *s, int field_width,
> >>>>>> +             int precision, int flags) {
> >>>>>> +     u16 *str = s ? s : L"<NULL>";
> >>>>>
> >>>>> Please, do not use the L-notation here as it requires -fshort-wchar.
> >>>>> As we currently cannot switch the complete project to C11 you
> >>>>> cannot use the u-notation either.
> >>>>
> >>>>
> >>>> current plan was to either switch whole project to -fshort-wchar or
> >>>> c11 and rework these patches (as well as a few patches in the
> >>>> efi_loader patchset).  (In the c11 case, I'm not sure what we'll use
> >>>> as the fmt string, since afaict that isn't specified.  We could use %S
> >>>> although that seems to be a deprecated way to do %ls, or something
> >>>> different like %A, I guess)..
> >>>>
> >>>> how far are we from c11?  If there is stuff I can do to help let me
> >>>> know.  If feasible, I'd rather do that first rather than have a bunch
> >>>> of stuff in vsprintf and elsewhere that needs to be cleaned up later
> >>>> after the switch.
> >>>
> >>>
> >>> buildman downloads very old compilers (gcc < 4.8) from kernel.org which
> >>> do not support C11.
> >>> Travis CI uses Ubuntu 14.04 with gcc 4.8.4 which incorrectly throws an
> >>> error for disk/part.c in C11 mode.
> >>
> >>
> >> ugg, 4.8 is pretty old..   Not sure how much older than 4.8 buildman
> >> uses.  It seems like *some* c11 was supported w/ >=4.6 so if we
> >> approach the conversion piecemeal (for example skipping code that
> >> triggers gcc bugs on old compilers) we might be able to keep 4.8.4
> >> working until travis provides something newer.
> >>
> >> (btw, even going back say 8 fedora releases or more, I've used distro
> >> packaged arm and aarch64 toolchains exclusively.. are there that many
> >> distro's where we really can't assume availability of an
> >> cross-toolchain?  If there isn't something newer from kernel.org can
> >> we just drop relying on ancient prebuilt toolchains?  I'm anyways not
> >> hugely a fan of downloading binary executables from even kernel.org,
> >> instead of using something from a distro build system which I at least
> >> know is very locked down.)
> >>
> >>> To get things right we would have to
> >>> * build our own cross tool chains based on a current gcc version
> >>> * use our own tool chain in Travis for x86-64 or use a docker
> >>>    container with a current gcc version.
> >>>
> >>> In the long run heading for C11 would be the right thing to do.
> >>> Until then use an initializer { '<', 'N', 'U', 'L', 'L', '>' }.
> >>> It looks ugly but does not consume more bytes once compiled.
> >>>
> >>
> >> Sure, that I'm less worried about, as much as adding stuff that is
> >> very soon going to be legacy.  Even in vfprintf.c it isn't such a big
> >> deal, as efi_loader where it would be more cumbersome.
> >>
> >> Maybe we can write out u"<NULL>" longhand in vsprintf.c as you
> >> suggest, but restrict efi_loader to gcc >= 4.9?  That seems like it
> >> shouldn't be a problem for any arm/arm64 device and it shouldn't be a
> >> problem for any device that is likely to have an efi payload to load
> >> in the first place..
> >
> >
> > I don't understand? We enable EFI_LOADER on all arm/arm64 systems for a good
> > reason, so they all get checked by travis. If we break travis, that won't do
> > anyone any good.
>
> I was more thinking if there was some oddball non-arm arch that u-boot
> supported which didn't haven good mainline gcc support and required
> something ancient ;-)

So, with v2018.01 I want to say that for ARM*, gcc-6.x is the minimum.

Looking around, nds32 requires gcc-4.4.4.  NDS32 folks, is there a newer
toolchain available?

Other than that, everything else has a gcc-6.x available in some form or
another.  Thanks!

--
Tom
CONFIDENTIALITY NOTICE:

This e-mail (and its attachments) may contain confidential and legally privileged information or information protected from disclosure. If you are not the intended recipient, you are hereby notified that any disclosure, copying, distribution, or use of the information contained herein is strictly prohibited. In this case, please immediately notify the sender by return e-mail, delete the message (and any accompanying documents) and destroy all printed hard copies. Thank you for your cooperation.

Copyright ANDES TECHNOLOGY CORPORATION - All Rights Reserved.

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v0 00/20] enough UEFI for standard distro boot
  2017-08-10  1:32 ` [U-Boot] [PATCH v0 00/20] enough UEFI for standard distro boot Tom Rini
@ 2017-08-10 10:41   ` Rob Clark
  0 siblings, 0 replies; 116+ messages in thread
From: Rob Clark @ 2017-08-10 10:41 UTC (permalink / raw)
  To: u-boot

On Wed, Aug 9, 2017 at 9:32 PM, Tom Rini <trini@konsulko.com> wrote:
> On Fri, Aug 04, 2017 at 03:31:42PM -0400, Rob Clark wrote:
>
>> This patchset fleshes out EFI_LOADER enough to support booting an
>> upstream \EFI\BOOT\bootaa64.efi (which then loads fallback.efi and
>> then eventually the per-distro shim.efi which loads the per-distro
>> grubaa64.efi) without resorting to hacks to hard-code u-boot to load
>> a particular distro's grub, or other hacks like setting up the
>> distro installation as live-media.
>>
>> The first seven patches add dependencies that will be needed later
>> in the series.  Patches 8-15 make u-boot work with upstream grub,
>> without relying on distro patches.  Patches 16-19 add missing bits
>> of the UEFI implementation needed to support shim/fallback.  And
>> finally patch 20 adds bootmanager support to avoid shim/fallback
>> after first boot.
>
> In concept, I am in agreement with the goals of this patch series.  In
> specifics, I'm going to skim around v0 and see if there's anything in
> particular that I feel I need to jump in and comment on at this point.
> Thanks for working on this!
>

There is one remaining regression in travis (well, actually two
identical ones) on vexpress which I am pretty stumped by:

https://travis-ci.org/robclark/u-boot/jobs/262841862

I cannot reproduce that outside of travis (although I am using distro
qemu).  I "bisected" it a few days back by cutting down the travis
config to just those two vexpress platforms and pushing different
stages of this patchset to a test branch.  It seemed to be
'efi_loader: refactor boot device and loaded_image handling' that was
triggering it.  Although that patch (or really any of them) don't
touch anything near printenv.  Possibly it could be a build size issue
with EFI_LOADER getting slightly bigger?  I tried updating travis to
use qemu 2.9.0 (which modulo any possible distro patches should match
what I have when I run locally on fedora 26), but that didn't help.

I'm at a bit of a loss about what to do.. I guess I can have a closer
look and see if we have any distro patches on qemu that look somehow
related.  I don't see how this can possibly be a problem w/ the
efi_loader patchset.  Any suggestions welcome.

BR,
-R

^ permalink raw reply	[flat|nested] 116+ messages in thread

end of thread, other threads:[~2017-08-10 10:41 UTC | newest]

Thread overview: 116+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-08-04 19:31 [U-Boot] [PATCH v0 00/20] enough UEFI for standard distro boot Rob Clark
2017-08-04 19:31 ` [U-Boot] [PATCH v0 01/20] fs: add fs_readdir() Rob Clark
2017-08-07 18:19   ` Brüns, Stefan
2017-08-07 19:11     ` Rob Clark
2017-08-04 19:31 ` [U-Boot] [PATCH v0 02/20] fs/fat: implement readdir Rob Clark
2017-08-04 19:31 ` [U-Boot] [PATCH v0 03/20] short-wchar Rob Clark
2017-08-04 20:28   ` Heinrich Schuchardt
2017-08-04 20:36     ` Rob Clark
2017-08-04 19:31 ` [U-Boot] [PATCH v0 04/20] part: extract MBR signature from partitions Rob Clark
2017-08-04 19:31 ` [U-Boot] [PATCH v0 05/20] efi: add some more device path structures Rob Clark
2017-08-04 19:31 ` [U-Boot] [PATCH v0 06/20] common: add some utf16 handling helpers Rob Clark
2017-08-06  5:17   ` Simon Glass
2017-08-08 22:50   ` [U-Boot] [U-Boot, v0, " Heinrich Schuchardt
2017-08-08 23:21     ` Rob Clark
2017-08-04 19:31 ` [U-Boot] [PATCH v0 07/20] vsprintf.c: add wide string (%ls) support Rob Clark
2017-08-08 22:03   ` [U-Boot] [U-Boot, v0, " Heinrich Schuchardt
2017-08-08 22:44     ` Rob Clark
2017-08-08 23:08       ` Heinrich Schuchardt
2017-08-08 23:20         ` Alexander Graf
2017-08-08 23:39         ` Rob Clark
2017-08-08 23:55           ` Alexander Graf
2017-08-09  0:14             ` Rob Clark
2017-08-09  1:14               ` Rob Clark
2017-08-09 11:27               ` Tom Rini
2017-08-10  2:16                 ` rick at andestech.com
2017-08-09  8:50           ` Peter Robinson
2017-08-08 22:52     ` Rob Clark
2017-08-09 13:38     ` Rob Clark
2017-08-09 13:48       ` Alexander Graf
2017-08-09 14:35         ` Rob Clark
2017-08-04 19:31 ` [U-Boot] [PATCH v0 08/20] efi_loader: add back optional efi_handler::open() Rob Clark
2017-08-04 19:31 ` [U-Boot] [PATCH v0 09/20] efi_loader: add device-path utils Rob Clark
2017-08-04 19:31 ` [U-Boot] [PATCH v0 10/20] efi_loader: drop redundant efi_device_path_protocol Rob Clark
2017-08-04 19:31 ` [U-Boot] [PATCH v0 11/20] efi_loader: add guidstr helper Rob Clark
2017-08-05 19:33   ` Heinrich Schuchardt
2017-08-05 19:56     ` Rob Clark
2017-08-05 20:18       ` Heinrich Schuchardt
2017-08-04 19:31 ` [U-Boot] [PATCH v0 12/20] efi_loader: flesh out device-path to text Rob Clark
2017-08-04 19:31 ` [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions Rob Clark
2017-08-04 20:41   ` Mark Kettenis
2017-08-04 20:57     ` Rob Clark
2017-08-05 14:01       ` Mark Kettenis
2017-08-05 14:19         ` Rob Clark
2017-08-05 14:28         ` Mark Kettenis
2017-08-05 14:35           ` Rob Clark
2017-08-05 15:08             ` Mark Kettenis
2017-08-05 15:22               ` Rob Clark
2017-08-05 16:02                 ` Heinrich Schuchardt
2017-08-05 16:13                   ` Rob Clark
2017-08-05 15:10             ` Heinrich Schuchardt
2017-08-05 15:24               ` Rob Clark
2017-08-05 15:36                 ` Rob Clark
2017-08-06 13:16                   ` Mark Kettenis
2017-08-06 14:17                     ` Rob Clark
2017-08-06 14:26                       ` Rob Clark
2017-08-06 14:28                     ` Mark Kettenis
2017-08-06 14:45                       ` Rob Clark
2017-08-06 15:34                         ` Rob Clark
2017-08-06 16:00                           ` Heinrich Schuchardt
2017-08-06 16:14                           ` Jonathan Gray
2017-08-06 17:28                           ` Mark Kettenis
2017-08-06 17:49                             ` Rob Clark
2017-08-06 18:13                               ` Peter Robinson
2017-08-06 18:21                               ` Mark Kettenis
2017-08-06 18:37                                 ` Mark Kettenis
2017-08-06 18:47                                   ` Rob Clark
2017-08-06 18:53                                     ` Rob Clark
2017-08-06 18:41                                 ` Rob Clark
2017-08-07 15:47                           ` Jonathan Gray
2017-08-07 16:16                             ` Rob Clark
2017-08-08  1:36                               ` Jonathan Gray
2017-08-05 14:28         ` Rob Clark
2017-08-06 12:53           ` Mark Kettenis
2017-08-07 17:32     ` Peter Jones
2017-08-04 19:31 ` [U-Boot] [PATCH v0 14/20] efi_loader: use proper device-paths for net Rob Clark
2017-08-04 19:31 ` [U-Boot] [PATCH v0 15/20] efi_loader: refactor boot device and loaded_image handling Rob Clark
2017-08-04 19:31 ` [U-Boot] [PATCH v0 16/20] efi_loader: add file/filesys support Rob Clark
2017-08-04 19:31 ` [U-Boot] [PATCH v0 17/20] efi_loader: support load_image() from a file-path Rob Clark
2017-08-04 19:32 ` [U-Boot] [PATCH v0 18/20] efi_loader: make pool allocations cacheline aligned Rob Clark
2017-08-04 19:32 ` [U-Boot] [PATCH v0 19/20] efi_loader: efi variable support Rob Clark
2017-08-06  5:17   ` Simon Glass
2017-08-04 19:32 ` [U-Boot] [PATCH v0 20/20] efi_loader: add bootmgr Rob Clark
2017-08-04 20:06   ` Heinrich Schuchardt
2017-08-04 20:28     ` Rob Clark
2017-08-04 20:29       ` Rob Clark
2017-08-04 22:46       ` Peter Jones
2017-08-05 15:58 ` [U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses Rob Clark
2017-08-05 16:12   ` Heinrich Schuchardt
2017-08-05 16:16     ` Rob Clark
2017-08-05 16:19       ` Rob Clark
2017-08-05 16:26         ` Heinrich Schuchardt
2017-08-05 16:46           ` Rob Clark
2017-08-05 16:52       ` Heinrich Schuchardt
2017-08-05 17:06         ` Rob Clark
2017-08-05 18:43           ` Rob Clark
2017-08-05 20:05             ` Heinrich Schuchardt
2017-08-05 20:31               ` Rob Clark
2017-08-07 20:19                 ` Alexander Graf
2017-08-07 21:14                   ` Mark Kettenis
2017-08-07 22:18                     ` Rob Clark
2017-08-08  6:52                       ` Alexander Graf
2017-08-08  8:11                         ` Ard Biesheuvel
2017-08-08 11:32                           ` Leif Lindholm
2017-08-08 12:01                             ` Rob Clark
2017-08-08 12:39                               ` Leif Lindholm
2017-08-08  9:27                         ` Rob Clark
2017-08-08 12:26                       ` Mark Kettenis
2017-08-08 12:54                         ` Rob Clark
2017-08-08 13:33                           ` Mark Kettenis
2017-08-08 14:03                             ` Rob Clark
2017-08-08 14:10                               ` Rob Clark
2017-08-08 18:20                               ` Rob Clark
2017-08-07 16:56           ` Rob Clark
2017-08-07 17:15         ` Peter Jones
2017-08-10  1:32 ` [U-Boot] [PATCH v0 00/20] enough UEFI for standard distro boot Tom Rini
2017-08-10 10:41   ` Rob Clark

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.