enough UEFI for standard distro boot
Subsystems (5)
cover enough UEFI for standard distro 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
Signature · 1 line
2.13.0
PATCH 1/20 fs: add fs_readdir()
Needed to support efi file protocol. The fallback.efi loader wants to be able to read the contents of the /EFI directory to find an OS to boot.
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.
--- fs/fs.c | 25 +++++++++++++++++++++++++ include/fs.h | 21 +++++++++++++++++++++ 2 files changed, 46 insertions(+)
fs/fs.c +25 -0
@@ -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) {
include/fs.h +21 -0
@@ -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. */
Signature · 1 line
2.13.0
PATCH 1/20 fs: add fs_readdir()
Quoted 9 lines · 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
Quoted 8 lines
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 <[email protected]>--- 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
PATCH 1/20 fs: add fs_readdir()
Quoted 13 lines · Stefan
Quoted 12 lines · 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.
Quoted 8 lines
Quoted 5 lines
Signed-off-by Rob Clark <[email protected]>--- 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 ;-)
Quoted 3 lines
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.
Quoted 4 lines
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.
Quoted 4 lines
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
PATCH 2/20 fs/fat: implement readdir
In reply to Rob ClarkYes, 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.
---
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(-)
fs/fat/fat.c +46 -13
@@ -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 ) { }
fs/fs.c +1 -1
@@ -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
include/fat.h +3 -1
@@ -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_ */
Signature · 1 line
2.13.0
PATCH 3/20 short-wchar
In reply to Rob ClarkFor 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.
--- config.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
config.mk +1 -1
@@ -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
Signature · 1 line
2.13.0
PATCH 3/20 short-wchar
Quoted 18 lines · Rob Clark
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 doutf32->utf8conversion.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.
Quoted 6 lines
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 <[email protected]>
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
Quoted 18 lines
--- config.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)config.mk +1
-1@@ -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
PATCH 3/20 short-wchar
Quoted 24 lines · Heinrich Schuchardt
Quoted 23 lines · Rob Clark
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 doutf32->utf8conversion.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.
Quoted 4 lines
Quoted 1 line
Not-signed-off-by Rob Clark <[email protected]>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" ;-)
Quoted 11 lines
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.cwithPARTITION_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
Quoted 23 lines
Best regards
Heinrich
Quoted 18 lines
--- config.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)config.mk +1
-1@@ -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
PATCH 4/20 part: extract MBR signature from partitions
In reply to Rob ClarkFrom: Peter Jones <[email protected]>
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.
[separated from efi_loader part, and fixed build-errors for non-
CONFIG_EFI_PARTITION case]
--- 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(-)
disk/part_dos.c +9 -3
@@ -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 ; }
disk/part_efi.c +20 -0
@@ -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 ) {
include/blk.h +15 -0
@@ -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
include/efi.h +4 -0
@@ -28,6 +28,10 @@struct efi_device_path ; +typedef struct { +u8 b[16 ]; +}efi_guid_t ; +#define EFI_BITS_PER_LONG BITS_PER_LONG/*
include/part.h +2 -1
@@ -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
include/part_efi.h +0 -4
@@ -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 */
Signature · 1 line
2.13.0
PATCH 5/20 efi: add some more device path structures
In reply to Rob ClarkFrom: Peter Jones <[email protected]>
--- include/efi_api.h | 49 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-)
include/efi_api.h +47 -2
@@ -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, \
Signature · 1 line
2.13.0
PATCH 6/20 common: add some utf16 handling helpers
In reply to Rob ClarkWe'll eventually want these in a few places in efi_loader, and also vsprintf.
--- 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
common/Makefile +1 -0
@@ -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)
common/charset.c new file +81 -0
81 lines not on this page · raw message
include/charset.h new file +18 -0
@@ -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_ */
lib/efi_loader/efi_console.c +3 -14
@@ -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); }
Signature · 1 line
2.13.0
PATCH 6/20 common: add some utf16 handling helpers
Quoted 123 lines · Rob Clark
We'll eventually want these in a few places in
efi_loader, and also vsprintf.Signed-off-by Rob Clark <[email protected]>--- 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.hcommon/Makefile +1
-0@@ -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)common/charset.c new file +81
-0@@ -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; +}include/charset.h new file +6
-0@@ -0,0 +1,18 @@ +/* +* charset conversion utils +* +* Copyright (c) 2017 Rob Clark +* +* SPDX-License-Identifier: GPL-2.0+
include/charset.h line 16
Quoted 10 lines
include/charset.h new file +10
-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.
Quoted 40 lines
include/charset.h new file +2
-0+ +#endif /* __CHARSET_H_ */ lib/efi_loader/efi_console.c +3
-15@@ -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
PATCH 6/20 common: add some utf16 handling helpers
In reply to Rob ClarkQuoted 55 lines · Rob Clark
We'll eventually want these in a few places in
efi_loader, and also vsprintf.Signed-off-by Rob Clark <[email protected]>--- 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.hcommon/Makefile +1
-0@@ -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)common/charset.c new file +25
-0@@ -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;
common/charset.c line 35
Quoted 10 lines
common/charset.c new file +10
-0+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.
Quoted 21 lines
common/charset.c new file +21
-0+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 ) {
common/charset.c line 66
Quoted 10 lines
common/charset.c new file +10
-0+ *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
Quoted 75 lines
common/charset.c new file +15
-0+ }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; +}include/charset.h new file +18
-0@@ -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_ */ lib/efi_loader/efi_console.c +3
-14@@ -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); }
PATCH 6/20 common: add some utf16 handling helpers
Quoted 60 lines · Heinrich Schuchardt
Quoted 59 lines · Rob Clark
We'll eventually want these in a few places in
efi_loader, and also vsprintf.Signed-off-by Rob Clark <[email protected]>--- 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.hcommon/Makefile +1
-0@@ -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)common/charset.c new file +29
-0@@ -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; +} +
Quoted 8 lines
common/charset.c line 35
Quoted 6 lines
common/charset.c new file +6
-0+/* 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)
Quoted 34 lines
Quoted 21 lines
common/charset.c new file +21
-0+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 ) {common/charset.c line 66
Quoted 10 lines
common/charset.c new file +10
-0+ *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:
Quoted 3 lines
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
Quoted 80 lines
Best regards
Heinrich
Quoted 75 lines
common/charset.c new file +15
-0+ }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; +}include/charset.h new file +18
-0@@ -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_ */ lib/efi_loader/efi_console.c +3
-14@@ -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); }
PATCH 7/20 vsprintf.c: add wide string (%ls) support
In reply to Rob ClarkThis is convenient for efi_loader which deals a lot with utf16.
--- lib/vsprintf.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-)
lib/vsprintf.c +28 -2
@@ -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' :
Signature · 1 line
2.13.0
PATCH 7/20 vsprintf.c: add wide string (%ls) support
Quoted 3 lines · Rob Clark
This is convenient for
efi_loaderwhich deals a lot with utf16.Signed-off-by Rob Clark <[email protected]>
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.
Quoted 17 lines
--- lib/vsprintf.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-)lib/vsprintf.c +1
-0@@ -17,6 +17,7 @@#include <linux/ctype.h> #include <common.h> +#include <charset.h> #include <div64.h> #define noinline __attribute__((noinline))
lib/vsprintf.c static char *string(char *buf, char *end, char *s, int field_width, · line 277
Quoted 7 lines
lib/vsprintf.c +4
-0@@ -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.
lib/vsprintf.c static char *string(char *buf, char *end, char *s, int field_width, · line 279
Quoted 2 lines
lib/vsprintf.c +2
-0+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.
Quoted 18 lines
lib/vsprintf.c +14
-0+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)]
lib/vsprintf.c repeat: · line 552
Quoted 6 lines
lib/vsprintf.c +1
-2@@ -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
Quoted 10 lines
lib/vsprintf.c +6
-0+ 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' :
PATCH 7/20 vsprintf.c: add wide string (%ls) support
Quoted 13 lines · Heinrich Schuchardt
Quoted 3 lines · Rob Clark
This is convenient for
efi_loaderwhich deals a lot with utf16.Signed-off-by Rob Clark <[email protected]>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.
Quoted 2 lines
These three patches can be reviewed independently of the
efi_loaderpatches 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
Quoted 20 lines
Quoted 20 lines
--- lib/vsprintf.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-)lib/vsprintf.c +1
-0@@ -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; }
Quoted 7 lines
lib/vsprintf.c static char *string(char *buf, char *end, char *s, int field_width, · line 277
Quoted 4 lines
lib/vsprintf.c +4
-0+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.
Quoted 6 lines
lib/vsprintf.c static char *string(char *buf, char *end, char *s, int field_width, · line 279
Quoted 3 lines
lib/vsprintf.c +2
-0+int len =utf16_strnlen (str, precision); +u8 utf8[len *MAX_UTF8_PER_UTF16 ];Didn't you forget 1 byte for \0 here?
Quoted 8 lines
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_strnlenfunction.
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.
Quoted 20 lines
Quoted 20 lines
lib/vsprintf.c +14
-0+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 ;
Quoted 9 lines
lib/vsprintf.c repeat: · line 552
Quoted 4 lines
lib/vsprintf.c +1
-2case '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
Quoted 14 lines
Best regards
Heinrich
Quoted 10 lines
lib/vsprintf.c +6
-0+ 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' :
PATCH 7/20 vsprintf.c: add wide string (%ls) support
Quoted 55 lines · Rob Clark
Quoted 13 lines · Heinrich Schuchardt
Quoted 3 lines · Rob Clark
This is convenient for
efi_loaderwhich deals a lot with utf16.Signed-off-by Rob Clark <[email protected]>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.Quoted 2 lines
These three patches can be reviewed independently of the
efi_loaderpatches 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_loaderpatchset that it is a dependencyQuoted 20 lines
Quoted 20 lines
--- lib/vsprintf.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-)lib/vsprintf.c +1
-0@@ -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; }Quoted 7 lines
lib/vsprintf.c static char *string(char *buf, char *end, char *s, int field_width, · line 277
Quoted 4 lines
lib/vsprintf.c +4
-0+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_loaderpatchset). (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)..
Quoted 4 lines
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
Quoted 73 lines
Quoted 7 lines
lib/vsprintf.c static char *string(char *buf, char *end, char *s, int field_width, · line 279
Quoted 4 lines
lib/vsprintf.c +2
-0+int len =utf16_strnlen (str, precision); +u8 utf8[len *MAX_UTF8_PER_UTF16 ];Didn't you forget 1 byte for \0 here?
Quoted 8 lines
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_strnlenfunction.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.
Quoted 20 lines
Quoted 20 lines
lib/vsprintf.c +14
-0+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 ;Quoted 9 lines
lib/vsprintf.c repeat: · line 552
Quoted 4 lines
lib/vsprintf.c +1
-2case '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,
-RQuoted 14 lines
Best regards
Heinrich
Quoted 10 lines
lib/vsprintf.c +6
-0+ 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' :
PATCH 7/20 vsprintf.c: add wide string (%ls) support
Quoted 70 lines
Am 09.08.2017 um 00:08 schrieb Heinrich Schuchardt <[email protected]>:
Quoted 56 lines · Rob Clark
Quoted 14 lines · Heinrich Schuchardt
Quoted 4 lines · Rob Clark
This is convenient for
efi_loaderwhich deals a lot with utf16.Signed-off-by Rob Clark <[email protected]>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.Quoted 2 lines
These three patches can be reviewed independently of the
efi_loaderpatches 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_loaderpatchset that it is a dependencyQuoted 20 lines
Quoted 20 lines
---
lib/vsprintf.c| 30 ++++++++++++++++++++++++++++--1 file changed, 28 insertions(+), 2 deletions(-)lib/vsprintf.c +1
-0@@ -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; }Quoted 7 lines
lib/vsprintf.c static char *string(char *buf, char *end, char *s, int field_width, · line 277
Quoted 4 lines
lib/vsprintf.c +4
-0+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_loaderpatchset). (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)..Quoted 4 lines
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 fordisk/part.cin C11 mode.
Quoted 7 lines
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
Quoted 80 lines
It looks ugly but does not consume more bytes once compiled.
Regards
Heinrich
Quoted 73 lines
Quoted 7 lines
lib/vsprintf.c static char *string(char *buf, char *end, char *s, int field_width, · line 279
Quoted 4 lines
lib/vsprintf.c +2
-0+int len =utf16_strnlen (str, precision); +u8 utf8[len *MAX_UTF8_PER_UTF16 ];Didn't you forget 1 byte for \0 here?
Quoted 8 lines
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_strnlenfunction.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.
Quoted 20 lines
Quoted 20 lines
lib/vsprintf.c +14
-0+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 ;Quoted 9 lines
lib/vsprintf.c repeat: · line 552
Quoted 4 lines
lib/vsprintf.c +1
-2case '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,
-RQuoted 14 lines
Best regards
Heinrich
Quoted 10 lines
lib/vsprintf.c +6
-0+ 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' :
PATCH 7/20 vsprintf.c: add wide string (%ls) support
In reply to Heinrich SchuchardtQuoted 61 lines · Heinrich Schuchardt
Quoted 55 lines · Rob Clark
Quoted 13 lines · Heinrich Schuchardt
Quoted 3 lines · Rob Clark
This is convenient for
efi_loaderwhich deals a lot with utf16.Signed-off-by Rob Clark <[email protected]>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.Quoted 2 lines
These three patches can be reviewed independently of the
efi_loaderpatches 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_loaderpatchset that it is a dependencyQuoted 20 lines
Quoted 20 lines
--- lib/vsprintf.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-)lib/vsprintf.c +1
-0@@ -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; }Quoted 7 lines
lib/vsprintf.c static char *string(char *buf, char *end, char *s, int field_width, · line 277
Quoted 4 lines
lib/vsprintf.c +4
-0+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_loaderpatchset). (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)..Quoted 4 lines
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.
Quoted 4 lines
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 fordisk/part.cin 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.)
Quoted 9 lines
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
PATCH 7/20 vsprintf.c: add wide string (%ls) support
Quoted 96 lines · Rob Clark
Quoted 61 lines · Heinrich Schuchardt
Quoted 55 lines · Rob Clark
Quoted 13 lines · Heinrich Schuchardt
Quoted 3 lines · Rob Clark
This is convenient for
efi_loaderwhich deals a lot with utf16.Signed-off-by Rob Clark <[email protected]>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.Quoted 2 lines
These three patches can be reviewed independently of the
efi_loaderpatches 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_loaderpatchset that it is a dependencyQuoted 20 lines
Quoted 20 lines
--- lib/vsprintf.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-)lib/vsprintf.c +1
-0@@ -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; }Quoted 7 lines
lib/vsprintf.c static char *string(char *buf, char *end, char *s, int field_width, · line 277
Quoted 4 lines
lib/vsprintf.c +4
-0+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_loaderpatchset). (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)..Quoted 4 lines
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.
Quoted 4 lines
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 fordisk/part.cin 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.)
Quoted 9 lines
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.cit isn't such a big deal, asefi_loaderwhere it would be more cumbersome.
Quoted 5 lines
Maybe we can write out u"<NULL>" longhand in
vsprintf.cas you suggest, but restrictefi_loaderto 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
PATCH 7/20 vsprintf.c: add wide string (%ls) support
Quoted 121 lines · Alexander Graf
Quoted 111 lines · Rob Clark
Quoted 73 lines · Heinrich Schuchardt
Quoted 65 lines · Rob Clark
Quoted 16 lines · Heinrich Schuchardt
Quoted 4 lines · Rob Clark
This is convenient for
efi_loaderwhich deals a lot with utf16.Signed-off-by Rob Clark <[email protected]>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.Quoted 2 lines
These three patches can be reviewed independently of the
efi_loaderpatches 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_loaderpatchset that it is a dependencyQuoted 21 lines
Quoted 21 lines
--- lib/vsprintf.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-)lib/vsprintf.c +1
-0@@ -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; }Quoted 9 lines
lib/vsprintf.c static char *string(char *buf, char *end, char *s, int field_width, · line 277
Quoted 4 lines
lib/vsprintf.c +4
-0+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_loaderpatchset). (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)..Quoted 4 lines
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.
Quoted 4 lines
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 fordisk/part.cin 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.)
Quoted 9 lines
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.cit isn't such a big deal, asefi_loaderwhere it would be more cumbersome.Quoted 5 lines
Maybe we can write out u"<NULL>" longhand in
vsprintf.cas you suggest, but restrictefi_loaderto 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..
Quoted 3 lines
I don't understand? We enable
EFI_LOADERon 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
Quoted 5 lines
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
PATCH 7/20 vsprintf.c: add wide string (%ls) support
Quoted 130 lines · Rob Clark
Quoted 121 lines · Alexander Graf
Quoted 111 lines · Rob Clark
Quoted 73 lines · Heinrich Schuchardt
Quoted 65 lines · Rob Clark
Quoted 16 lines · Heinrich Schuchardt
Quoted 4 lines · Rob Clark
This is convenient for
efi_loaderwhich deals a lot with utf16.Signed-off-by Rob Clark <[email protected]>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.Quoted 2 lines
These three patches can be reviewed independently of the
efi_loaderpatches 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_loaderpatchset that it is a dependencyQuoted 21 lines
Quoted 21 lines
--- lib/vsprintf.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-)lib/vsprintf.c +1
-0@@ -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; }Quoted 9 lines
lib/vsprintf.c static char *string(char *buf, char *end, char · line 278
Quoted 4 lines
lib/vsprintf.c +4
-0+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_loaderpatchset). (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)..Quoted 4 lines
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.
Quoted 4 lines
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 fordisk/part.cin 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.)
Quoted 9 lines
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.cit isn't such a big deal, asefi_loaderwhere it would be more cumbersome.Quoted 5 lines
Maybe we can write out u"<NULL>" longhand in
vsprintf.cas you suggest, but restrictefi_loaderto 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..Quoted 3 lines
I don't understand? We enable
EFI_LOADERon 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 ;-)
Quoted 7 lines
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
PATCH 7/20 vsprintf.c: add wide string (%ls) support
In reply to Rob ClarkQuoted 122 lines · Rob Clark
Quoted 121 lines · Alexander Graf
Quoted 116 lines · Rob Clark
Quoted 73 lines · Heinrich Schuchardt
Quoted 65 lines · Rob Clark
Quoted 16 lines · Heinrich Schuchardt
Quoted 4 lines · Rob Clark
This is convenient for
efi_loaderwhich deals a lot with utf16.Signed-off-by Rob Clark <[email protected]>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.Quoted 2 lines
These three patches can be reviewed independently of the
efi_loaderpatches 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_loaderpatchset that it is a dependencyQuoted 21 lines
Quoted 21 lines
--- lib/vsprintf.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-)lib/vsprintf.c +1
-0@@ -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; }Quoted 9 lines
lib/vsprintf.c static char *string(char *buf, char *end, char · line 278
Quoted 4 lines
lib/vsprintf.c +4
-0+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_loaderpatchset). (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)..Quoted 4 lines
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.
Quoted 4 lines
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 fordisk/part.cin 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.)
Quoted 9 lines
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.cit isn't such a big deal, asefi_loaderwhere it would be more cumbersome.Maybe we can write out u"<NULL>" longhand in
vsprintf.cas you suggest, but restrictefi_loaderto 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..
Quoted 7 lines
Quoted 3 lines
I don't understand? We enable
EFI_LOADERon 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!
Signature · 8 lines
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>
PATCH 7/20 vsprintf.c: add wide string (%ls) support
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
Quoted 121 lines · Rob Clark
Quoted 120 lines · Alexander Graf
Quoted 115 lines · Rob Clark
Quoted 71 lines · Heinrich Schuchardt
Quoted 63 lines · Rob Clark
Quoted 15 lines · Heinrich Schuchardt
Quoted 4 lines · Rob Clark
This is convenient for
efi_loaderwhich deals a lot with utf16.Signed-off-by Rob Clark <[email protected]>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.Quoted 2 lines
These three patches can be reviewed independently of the
efi_loaderpatches 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_loaderpatchset that it is a dependencyQuoted 21 lines
Quoted 21 lines
--- lib/vsprintf.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-)lib/vsprintf.c index renamed from lib/vsprintf.c +0
-0
874a2951f7..0c40f852ce100644lib/vsprintf.c +1
-0@@ -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;}
Quoted 7 lines
lib/vsprintf.c
Quoted 3 lines
lib/vsprintf.c +3
-0+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_loaderpatchset). (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)..Quoted 4 lines
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.
Quoted 4 lines
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 fordisk/part.cin 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.)
Quoted 9 lines
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.cit isn't such a big deal, asefi_loaderwhere it would be more cumbersome.Maybe we can write out u"<NULL>" longhand in
vsprintf.cas you suggest, but restrictefi_loaderto 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..
Quoted 7 lines
Quoted 3 lines
I don't understand? We enable
EFI_LOADERon 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.
PATCH 7/20 vsprintf.c: add wide string (%ls) support
In reply to Rob ClarkQuoted 10 lines
Quoted 4 lines
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 fordisk/part.cin 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
Quoted 35 lines
(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.)
Quoted 9 lines
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.cit isn't such a big deal, asefi_loaderwhere it would be more cumbersome.Maybe we can write out u"<NULL>" longhand in
vsprintf.cas you suggest, but restrictefi_loaderto 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
PATCH 7/20 vsprintf.c: add wide string (%ls) support
In reply to Heinrich SchuchardtQuoted 36 lines · Heinrich Schuchardt
Quoted 3 lines · Rob Clark
This is convenient for
efi_loaderwhich deals a lot with utf16.Signed-off-by Rob Clark <[email protected]>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_loaderpatches and probably will not be integrated via the efi-next tree.Quoted 20 lines
--- lib/vsprintf.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-)lib/vsprintf.c +1
-0@@ -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; }
Quoted 8 lines
lib/vsprintf.c static char *string(char *buf, char *end, char *s, int field_width, · line 277
Quoted 4 lines
lib/vsprintf.c +4
-0+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
PATCH 7/20 vsprintf.c: add wide string (%ls) support
In reply to Heinrich SchuchardtQuoted 5 lines · Heinrich Schuchardt
Quoted 4 lines · Rob Clark
(quoted diff) +0
-0@@ -528,8 +549,13 @@ repeat: continue;
Quoted 10 lines
lib/vsprintf.c repeat: · line 552
Quoted 4 lines
lib/vsprintf.c +1
-2case '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
PATCH 7/20 vsprintf.c: add wide string (%ls) support
Quoted 34 lines
Am 09.08.2017 um 14:38 schrieb Rob Clark <[email protected]>:
Quoted 6 lines · Heinrich Schuchardt
Quoted 5 lines · Rob Clark
(quoted diff) +0
-0@@ -528,8 +549,13 @@ repeat: continue;Quoted 10 lines
lib/vsprintf.c repeat: · line 552
Quoted 4 lines
lib/vsprintf.c +1
-2case '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 -WformatSo 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.)
Quoted 6 lines
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_LOADERselects.. or possibly just unconditionally.Thoughts?
If we select it, I'd rather have it be unconditional, to not oprn potential for undetected breakage.
Alex
Quoted 3 lines
BR,
-R
PATCH 7/20 vsprintf.c: add wide string (%ls) support
Quoted 34 lines · Alexander Graf
Quoted 34 lines
Am 09.08.2017 um 14:38 schrieb Rob Clark <[email protected]>:
Quoted 6 lines · Heinrich Schuchardt
Quoted 5 lines · Rob Clark
(quoted diff) +0
-0@@ -528,8 +549,13 @@ repeat: continue;Quoted 10 lines
lib/vsprintf.c repeat: · line 552
Quoted 4 lines
lib/vsprintf.c +1
-2case '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 -WformatSo 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.)
Quoted 9 lines
Quoted 6 lines
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_LOADERselects.. 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
PATCH 8/20 efi_loader: add back optional efi_handler::open()
In reply to Rob ClarkIn 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.
--- include/efi_loader.h | 12 +++++++++++- lib/efi_loader/efi_boottime.c | 30 ++++++++++++++++++++++++------ 2 files changed, 35 insertions(+), 7 deletions(-)
include/efi_loader.h +11 -1
@@ -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;
lib/efi_loader/efi_boottime.c +24 -6
@@ -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; } }
Signature · 1 line
2.13.0
PATCH 9/20 efi_loader: add device-path utils
In reply to Rob ClarkHelpers 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.
--- 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
include/efi_api.h +10 -0
@@ -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;
include/efi_loader.h +20 -0
@@ -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) {
lib/efi_loader/Makefile +1 -1
@@ -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
lib/efi_loader/efi_device_path.c new file +485 -0
485 lines not on this page · raw message
Signature · 1 line
2.13.0
PATCH 10/20 efi_loader: drop redundant efi_device_path_protocol
In reply to Rob ClarkThis is really the same thing as the efi_device_path struct.
--- include/efi_api.h | 12 ++---------- lib/efi_loader/efi_device_path_to_text.c | 13 ++++++++----- 2 files changed, 10 insertions(+), 15 deletions(-)
include/efi_api.h +2 -10
@@ -478,22 +478,14 @@ struct efi_console_control_protocolEFI_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); };
lib/efi_loader/efi_device_path_to_text.c +8 -5
@@ -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) {
Signature · 1 line
2.13.0
PATCH 11/20 efi_loader: add guidstr helper
In reply to Rob ClarkThere are a couple places where we'll need GUID -> string. So add a helper.
--- include/efi_loader.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
include/efi_loader.h +15 -0
@@ -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
Signature · 1 line
2.13.0
PATCH 11/20 efi_loader: add guidstr helper
Quoted 25 lines · Rob Clark
There are a couple places where we'll need GUID -> string. So add a helper.
Signed-off-by Rob Clark <[email protected]>--- include/efi_loader.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+)include/efi_loader.h +8
-0@@ -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 ];
include/efi_loader.h static inline int guidcmp(const efi_guid_t *g1, const efi_guid_t *g2) · line 259
Quoted 10 lines
include/efi_loader.h +7
-0+ } *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
PATCH 11/20 efi_loader: add guidstr helper
Quoted 40 lines · Heinrich Schuchardt
Quoted 25 lines · Rob Clark
There are a couple places where we'll need GUID -> string. So add a helper.
Signed-off-by Rob Clark <[email protected]>--- include/efi_loader.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+)include/efi_loader.h +8
-0@@ -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 ];include/efi_loader.h static inline int guidcmp(const efi_guid_t *g1, const efi_guid_t *g2) · line 259
Quoted 10 lines
include/efi_loader.h +7
-0+ } *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:
Quoted 8 lines
include/uuid.h:40
intuuid_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_strfor 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
PATCH 11/20 efi_loader: add guidstr helper
Quoted 57 lines · Rob Clark
Quoted 40 lines · Heinrich Schuchardt
Quoted 25 lines · Rob Clark
There are a couple places where we'll need GUID -> string. So add a helper.
Signed-off-by Rob Clark <[email protected]>--- include/efi_loader.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+)include/efi_loader.h +8
-0@@ -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 ];include/efi_loader.h static inline int guidcmp(const efi_guid_t *g1, const efi_guid_t *g2) · line 259
Quoted 10 lines
include/efi_loader.h +7
-0+ } *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:
Quoted 8 lines
include/uuid.h:40
intuuid_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_strfor 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.cand drop both this patch plus your patch that adds a macro to print GUIDs. (Andvsprintf.cshould re-useuuid_guid_get_str().. and I could re-useuuid_guid_get_bin()when I get around to implementingefi_get_next_variable(), so thanks for pointing that out.)
Quoted 3 lines
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 singledebug(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
PATCH 12/20 efi_loader: flesh out device-path to text
In reply to Rob ClarkIt 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.
--- 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(-)
include/efi_api.h +1 -0
@@ -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;
include/efi_loader.h +2 -0
@@ -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;
lib/efi_loader/efi_device_path_to_text.c +160 -63
242 lines not on this page · raw message
Signature · 1 line
2.13.0
PATCH 13/20 efi_loader: use proper device-paths for partitions
In reply to Rob ClarkAlso, 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.
--- lib/efi_loader/efi_disk.c | 54 +++++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 23 deletions(-)
lib/efi_loader/efi_disk.c +31 -23
@@ -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++;/*
Signature · 1 line
2.13.0
PATCH 13/20 efi_loader: use proper device-paths for partitions
Quoted 2 lines
From: Rob Clark <[email protected]>
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...
Quoted 23 lines
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)/EndEntireYou 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
Quoted 4 lines
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
PATCH 13/20 efi_loader: use proper device-paths for partitions
Quoted 43 lines · Mark Kettenis
Quoted 2 lines
From: Rob Clark <[email protected]>
Date: Fri, 4 Aug 2017 15:31:55 -0400Hi Rob,
OpenBSD has been an early adopter of
efi_loaderand 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...Quoted 23 lines
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)/EndEntireYou 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
Quoted 4 lines
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.
Quoted 7 lines
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
PATCH 13/20 efi_loader: use proper device-paths for partitions
Quoted 101 lines
Authentication-Results: xs4all.nl; spf=pass smtp.mailfrom=gmail.com;
dkim=pass header.d=gmail.com; dmarc=pass header.from=gmail.comDKIM-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 <[email protected]>
Date: Fri, 4 Aug 2017 16:57:50 -0400
Cc: U-Boot Mailing List <[email protected]>,
Heinrich Schuchardt <[email protected]>,
Peter Jones <[email protected]>
X-CNFS-Analysis: v=2.2 cv=eoad9chX c=1 sm=0 tr=0a=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_:22X-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.nlQuoted 43 lines · Mark Kettenis
Quoted 2 lines
From: Rob Clark <[email protected]>
Date: Fri, 4 Aug 2017 15:31:55 -0400Hi Rob,
OpenBSD has been an early adopter of
efi_loaderand 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...Quoted 23 lines
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)/EndEntireYou 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
Quoted 4 lines
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.
Quoted 7 lines
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.
Quoted 6 lines
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:
Quoted 1 line
Quoted 1 line
OpenBSD/armv7 BOOTARM 0.8
boot>
at that stage.
PATCH 13/20 efi_loader: use proper device-paths for partitions
Quoted 69 lines · Mark Kettenis
Quoted 59 lines · Mark Kettenis
Quoted 43 lines
Quoted 2 lines
From: Rob Clark <[email protected]>
Date: Fri, 4 Aug 2017 15:31:55 -0400Hi Rob,
OpenBSD has been an early adopter of
efi_loaderand 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...Quoted 23 lines
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)/EndEntireYou 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
Quoted 4 lines
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.
Quoted 7 lines
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.
Quoted 6 lines
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:
Quoted 7 lines
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
Quoted 56 lines
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 MiBCPU: 912000000Hz, AXI/AHB/APB: 3/2/2Trying 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.0scanning 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 abortpc : [<7ef8d878>] lr : [<7ef8d874>]reloc pc : [<
4a039878>] lr : [<4a039874>]
sp :7af29660ip : 00000000 fp :7af29774
r10:7efec230r9 :7af33ee0r8 : 00000000
r7 : 00000009 r6 :7ef9e8b8r5 :7af296a0r4 :7efa4495
r3 :7af296a0r2 :0000008cr1 :7af29658r0 : 00000004
Flags: nzCV IRQs off FIQs off ModeSVC_32
Resetting CPU ...
Quoted 8 lines
resetting ...
Normally it would print something like:
Quoted 1 line
Quoted 1 line
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
PATCH 13/20 efi_loader: use proper device-paths for partitions
In reply to Mark KettenisQuoted 5 lines
Date: Sat, 5 Aug 2017 16:01:51 +0200 (CEST)
From: Mark Kettenis <[email protected]>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 <[email protected]> Date: Wed Jun 21 16:39:02 2017 -0400
efi: add some more device path structures
PATCH 13/20 efi_loader: use proper device-paths for partitions
Quoted 10 lines · Mark Kettenis
Quoted 5 lines
Date: Sat, 5 Aug 2017 16:01:51 +0200 (CEST)
From: Mark Kettenis <[email protected]>Unfortunately something in this patch series breaks things for me on a Banana Pi:
And according to git bisect:
4e3e748a50fc3f43e20c7ff407184596d7c9a589is the first bad commit commit4e3e748a50fc3f43e20c7ff407184596d7c9a589
Quoted 7 lines
Author: Peter Jones <[email protected]> Date: Wed Jun 21 16:39:02 2017 -0400efi: add some more device path structures
Signed-off-by Peter Jones <[email protected]>Signed-off-by Rob Clark <[email protected]>
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
PATCH 13/20 efi_loader: use proper device-paths for partitions
Quoted 26 lines
From: Rob Clark <[email protected]>
Date: Sat, 5 Aug 2017 10:35:08 -0400Quoted 10 lines · Mark Kettenis
Quoted 5 lines
Date: Sat, 5 Aug 2017 16:01:51 +0200 (CEST)
From: Mark Kettenis <[email protected]>Unfortunately something in this patch series breaks things for me on a Banana Pi:
And according to git bisect:
4e3e748a50fc3f43e20c7ff407184596d7c9a589is the first bad commit commit4e3e748a50fc3f43e20c7ff407184596d7c9a589Quoted 7 lines
Author: Peter Jones <[email protected]> Date: Wed Jun 21 16:39:02 2017 -0400efi: add some more device path structures
Signed-off-by Peter Jones <[email protected]>Signed-off-by Rob Clark <[email protected]>hmm, odd.. it is only adding some #define's and structs that are not used until a later commit..
Quoted 6 lines
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.
Quoted 3 lines
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_pathptrs 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.
PATCH 13/20 efi_loader: use proper device-paths for partitions
Quoted 49 lines · Mark Kettenis
Quoted 26 lines
From: Rob Clark <[email protected]>
Date: Sat, 5 Aug 2017 10:35:08 -0400Quoted 10 lines · Mark Kettenis
Quoted 5 lines
Date: Sat, 5 Aug 2017 16:01:51 +0200 (CEST)
From: Mark Kettenis <[email protected]>Unfortunately something in this patch series breaks things for me on a Banana Pi:
And according to git bisect:
4e3e748a50fc3f43e20c7ff407184596d7c9a589is the first bad commit commit4e3e748a50fc3f43e20c7ff407184596d7c9a589Quoted 7 lines
Author: Peter Jones <[email protected]> Date: Wed Jun 21 16:39:02 2017 -0400efi: add some more device path structures
Signed-off-by Peter Jones <[email protected]>Signed-off-by Rob Clark <[email protected]>hmm, odd.. it is only adding some #define's and structs that are not used until a later commit..
Quoted 6 lines
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.
Quoted 3 lines
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_pathptrs to aligned addresses :-/Sadly that's not going to help you:
$ arm-none-eabi-addr2line -e u-boot 7ef8d878 ??:0I suppose it is faulting somewhere in BOOTARM.EFI,
Anyway, removing
__packedfrom structefi_device_path_file_pathmakes me boot again with a tree checked out out with that commit.
Quoted 7 lines
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_loadercode 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
PATCH 13/20 efi_loader: use proper device-paths for partitions
Quoted 60 lines · Rob Clark
Quoted 49 lines · Mark Kettenis
Quoted 26 lines
From: Rob Clark <[email protected]>
Date: Sat, 5 Aug 2017 10:35:08 -0400Quoted 10 lines · Mark Kettenis
Quoted 5 lines
Date: Sat, 5 Aug 2017 16:01:51 +0200 (CEST)
From: Mark Kettenis <[email protected]>Unfortunately something in this patch series breaks things for me on a Banana Pi:
And according to git bisect:
4e3e748a50fc3f43e20c7ff407184596d7c9a589is the first bad commit commit4e3e748a50fc3f43e20c7ff407184596d7c9a589Quoted 7 lines
Author: Peter Jones <[email protected]> Date: Wed Jun 21 16:39:02 2017 -0400efi: add some more device path structures
Signed-off-by Peter Jones <[email protected]>Signed-off-by Rob Clark <[email protected]>hmm, odd.. it is only adding some #define's and structs that are not used until a later commit..
Quoted 6 lines
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.
Quoted 3 lines
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_pathptrs to aligned addresses :-/Sadly that's not going to help you:
$ arm-none-eabi-addr2line -e u-boot 7ef8d878 ??:0I suppose it is faulting somewhere in BOOTARM.EFI,
Anyway, removing
__packedfrom structefi_device_path_file_pathmakes me boot again with a tree checked out out with that commit.Quoted 7 lines
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_loadercode has to align things properly I fear.Ok, so I have an idea for a reasonably (imho) sane way forward:
Quoted 8 lines
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
Quoted 18 lines
We'll just define
BROKEN_UNALIGNEDfor 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 theefi_device_pathheader 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
PATCH 13/20 efi_loader: use proper device-paths for partitions
Quoted 70 lines · Heinrich Schuchardt
Quoted 60 lines · Rob Clark
Quoted 49 lines · Mark Kettenis
Quoted 26 lines
From: Rob Clark <[email protected]>
Date: Sat, 5 Aug 2017 10:35:08 -0400Quoted 10 lines · Mark Kettenis
Quoted 5 lines
Date: Sat, 5 Aug 2017 16:01:51 +0200 (CEST)
From: Mark Kettenis <[email protected]>Unfortunately something in this patch series breaks things for me on a Banana Pi:
And according to git bisect:
4e3e748a50fc3f43e20c7ff407184596d7c9a589is the first bad commit commit4e3e748a50fc3f43e20c7ff407184596d7c9a589Quoted 7 lines
Author: Peter Jones <[email protected]> Date: Wed Jun 21 16:39:02 2017 -0400efi: add some more device path structures
Signed-off-by Peter Jones <[email protected]>Signed-off-by Rob Clark <[email protected]>hmm, odd.. it is only adding some #define's and structs that are not used until a later commit..
Quoted 6 lines
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.
Quoted 3 lines
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_pathptrs to aligned addresses :-/Sadly that's not going to help you:
$ arm-none-eabi-addr2line -e u-boot 7ef8d878 ??:0I suppose it is faulting somewhere in BOOTARM.EFI,
Anyway, removing
__packedfrom structefi_device_path_file_pathmakes me boot again with a tree checked out out with that commit.Quoted 7 lines
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_loadercode has to align things properly I fear.Ok, so I have an idea for a reasonably (imho) sane way forward:
Quoted 8 lines
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;
Quoted 1 line
Why do you need
_packedhere?
We probably crossed threads, but see the other email I sent that quoted the relevant part from the UEFI spec.
Quoted 18 lines
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; };
Quoted 3 lines
Everything is perfectly aligned to natural bounderies.
The only thing that does not conform to the UEFI standard is the length ofefi_mac_addr, which should be 6 forif_typein {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.
Quoted 1 line
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
PATCH 13/20 efi_loader: use proper device-paths for partitions
In reply to Rob ClarkQuoted 23 lines · Rob Clark
Quoted 10 lines · Mark Kettenis
Quoted 5 lines
Date: Sat, 5 Aug 2017 16:01:51 +0200 (CEST)
From: Mark Kettenis <[email protected]>Unfortunately something in this patch series breaks things for me on a Banana Pi:
And according to git bisect:
4e3e748a50fc3f43e20c7ff407184596d7c9a589is the first bad commit commit4e3e748a50fc3f43e20c7ff407184596d7c9a589Quoted 7 lines
Author: Peter Jones <[email protected]> Date: Wed Jun 21 16:39:02 2017 -0400efi: add some more device path structures
Signed-off-by Peter Jones <[email protected]>Signed-off-by Rob Clark <[email protected]>hmm, odd.. it is only adding some #define's and structs that are not used until a later commit..
Quoted 6 lines
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
Quoted 8 lines
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_pathptrs to aligned addresses :-/BR,
-R
PATCH 13/20 efi_loader: use proper device-paths for partitions
Quoted 39 lines · Heinrich Schuchardt
Quoted 23 lines · Rob Clark
Quoted 10 lines · Mark Kettenis
Quoted 5 lines
Date: Sat, 5 Aug 2017 16:01:51 +0200 (CEST)
From: Mark Kettenis <[email protected]>Unfortunately something in this patch series breaks things for me on a Banana Pi:
And according to git bisect:
4e3e748a50fc3f43e20c7ff407184596d7c9a589is the first bad commit commit4e3e748a50fc3f43e20c7ff407184596d7c9a589Quoted 7 lines
Author: Peter Jones <[email protected]> Date: Wed Jun 21 16:39:02 2017 -0400efi: add some more device path structures
Signed-off-by Peter Jones <[email protected]>Signed-off-by Rob Clark <[email protected]>hmm, odd.. it is only adding some #define's and structs that are not used until a later commit..
Quoted 6 lines
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>
Quoted 3 lines
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
Quoted 13 lines
Regards
Heinrich
Quoted 8 lines
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_pathptrs to aligned addresses :-/BR,
-R
PATCH 13/20 efi_loader: use proper device-paths for partitions
Quoted 40 lines · Rob Clark
Quoted 39 lines · Heinrich Schuchardt
Quoted 23 lines · Rob Clark
Quoted 10 lines · Mark Kettenis
Quoted 5 lines
Date: Sat, 5 Aug 2017 16:01:51 +0200 (CEST)
From: Mark Kettenis <[email protected]>Unfortunately something in this patch series breaks things for me on a Banana Pi:
And according to git bisect:
4e3e748a50fc3f43e20c7ff407184596d7c9a589is the first bad commit commit4e3e748a50fc3f43e20c7ff407184596d7c9a589Quoted 7 lines
Author: Peter Jones <[email protected]> Date: Wed Jun 21 16:39:02 2017 -0400efi: add some more device path structures
Signed-off-by Peter Jones <[email protected]>Signed-off-by Rob Clark <[email protected]>hmm, odd.. it is only adding some #define's and structs that are not used until a later commit..
Quoted 6 lines
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>
Quoted 8 lines
Quoted 3 lines
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
PATCH 13/20 efi_loader: use proper device-paths for partitions
Quoted 67 lines
From: Rob Clark <[email protected]>
Date: Sat, 5 Aug 2017 11:36:25 -0400Quoted 40 lines · Rob Clark
Quoted 39 lines · Heinrich Schuchardt
Quoted 23 lines · Rob Clark
Quoted 10 lines · Mark Kettenis
Quoted 5 lines
Date: Sat, 5 Aug 2017 16:01:51 +0200 (CEST)
From: Mark Kettenis <[email protected]>Unfortunately something in this patch series breaks things for me on a Banana Pi:
And according to git bisect:
4e3e748a50fc3f43e20c7ff407184596d7c9a589is the first bad commit commit4e3e748a50fc3f43e20c7ff407184596d7c9a589Quoted 7 lines
Author: Peter Jones <[email protected]> Date: Wed Jun 21 16:39:02 2017 -0400efi: add some more device path structures
Signed-off-by Peter Jones <[email protected]>Signed-off-by Rob Clark <[email protected]>hmm, odd.. it is only adding some #define's and structs that are not used until a later commit..
Quoted 6 lines
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>
Quoted 8 lines
Quoted 3 lines
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.
Quoted 7 lines
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...
PATCH 13/20 efi_loader: use proper device-paths for partitions
Quoted 85 lines · Mark Kettenis
Quoted 67 lines
From: Rob Clark <[email protected]>
Date: Sat, 5 Aug 2017 11:36:25 -0400Quoted 40 lines · Rob Clark
Quoted 39 lines · Heinrich Schuchardt
Quoted 23 lines · Rob Clark
Quoted 10 lines · Mark Kettenis
Quoted 5 lines
Date: Sat, 5 Aug 2017 16:01:51 +0200 (CEST)
From: Mark Kettenis <[email protected]>Unfortunately something in this patch series breaks things for me on a Banana Pi:
And according to git bisect:
4e3e748a50fc3f43e20c7ff407184596d7c9a589is the first bad commit commit4e3e748a50fc3f43e20c7ff407184596d7c9a589Quoted 7 lines
Author: Peter Jones <[email protected]> Date: Wed Jun 21 16:39:02 2017 -0400efi: add some more device path structures
Signed-off-by Peter Jones <[email protected]>Signed-off-by Rob Clark <[email protected]>hmm, odd.. it is only adding some #define's and structs that are not used until a later commit..
Quoted 6 lines
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>
Quoted 8 lines
Quoted 3 lines
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.
Quoted 7 lines
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;
Quoted 3 lines
#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.
Quoted 14 lines
Going back to the original crash report:
data abort
pc : [<7ef8d878>] lr : [<7ef8d874>]reloc pc : [<
4a039878>] lr : [<4a039874>]
sp :7af29660ip : 00000000 fp :7af29774
r10:7efec230r9 :7af33ee0r8 : 00000000
r7 : 00000009 r6 :7ef9e8b8r5 :7af296a0r4 :7efa4495
r3 :7af296a0r2 :0000008cr1 :7af29658r0 : 00000004
Flags: nzCV IRQs off FIQs off ModeSVC_32I think it is actually "reloc pc" instead of "pc" that we need to look at:
Quoted 6 lines
$ addr2line -e u-boot 0x4a039874 /home/kettenis/tmp/rclark/u-boot/include/efi_loader.h:272which 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
Quoted 12 lines
The relevant instruction is a 16-bit load:
4a039878:e1d430b4ldrh r3, [r4, #4]and with r4 =
7efa4495that will defenitely trap.Looking at the defenition
efi_guid_tin u-boot:typedef struct { u8 b[16]; } efi_guid_t;
Quoted 6 lines
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
PATCH 13/20 efi_loader: use proper device-paths for partitions
Quoted 144 lines · Rob Clark
Quoted 85 lines · Mark Kettenis
Quoted 67 lines
From: Rob Clark <[email protected]>
Date: Sat, 5 Aug 2017 11:36:25 -0400Quoted 40 lines · Rob Clark
Quoted 39 lines · Heinrich Schuchardt
Quoted 23 lines · Rob Clark
Quoted 10 lines · Mark Kettenis
Quoted 5 lines
Date: Sat, 5 Aug 2017 16:01:51 +0200 (CEST)
From: Mark Kettenis <[email protected]>Unfortunately something in this patch series breaks things for me on a Banana Pi:
And according to git bisect:
4e3e748a50fc3f43e20c7ff407184596d7c9a589is the first bad commit commit4e3e748a50fc3f43e20c7ff407184596d7c9a589Quoted 7 lines
Author: Peter Jones <[email protected]> Date: Wed Jun 21 16:39:02 2017 -0400efi: add some more device path structures
Signed-off-by Peter Jones <[email protected]>Signed-off-by Rob Clark <[email protected]>hmm, odd.. it is only adding some #define's and structs that are not used until a later commit..
Quoted 6 lines
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>
Quoted 8 lines
Quoted 3 lines
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.
Quoted 7 lines
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;Quoted 3 lines
#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.Quoted 14 lines
Going back to the original crash report:
data abort
pc : [<7ef8d878>] lr : [<7ef8d874>]reloc pc : [<
4a039878>] lr : [<4a039874>]
sp :7af29660ip : 00000000 fp :7af29774
r10:7efec230r9 :7af33ee0r8 : 00000000
r7 : 00000009 r6 :7ef9e8b8r5 :7af296a0r4 :7efa4495
r3 :7af296a0r2 :0000008cr1 :7af29658r0 : 00000004
Flags: nzCV IRQs off FIQs off ModeSVC_32I think it is actually "reloc pc" instead of "pc" that we need to look at:
Quoted 6 lines
$ addr2line -e u-boot 0x4a039874 /home/kettenis/tmp/rclark/u-boot/include/efi_loader.h:272which 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_GUIDuses 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
Quoted 12 lines
The relevant instruction is a 16-bit load:
4a039878:e1d430b4ldrh r3, [r4, #4]and with r4 =
7efa4495that will defenitely trap.Looking at the defenition
efi_guid_tin u-boot:typedef struct { u8 b[16]; } efi_guid_t;
Quoted 9 lines
Quoted 6 lines
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
PATCH 13/20 efi_loader: use proper device-paths for partitions
In reply to Mark KettenisQuoted 5 lines
Date: Sun, 6 Aug 2017 15:16:09 +0200 (CEST)
From: Mark Kettenis <[email protected]>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.
PATCH 13/20 efi_loader: use proper device-paths for partitions
Quoted 15 lines · Mark Kettenis
Quoted 5 lines
Date: Sun, 6 Aug 2017 15:16:09 +0200 (CEST)
From: Mark Kettenis <[email protected]>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 :7af2b820ip :7af69635fp :7ef5aee4
r10: 00000005 r9 :7af35ee0r8 :7efb4490
r7 :7af695e8r6 :7af69620r5 :0000005cr4 :7af2b828
r3 :7efae477r2 :0000005cr1 :0000002fr0 : 00000000
Flags: nzCv IRQs off FIQs off ModeSVC_32
Quoted 7 lines
addr2line -e u-boot.bin
0x4a003160/home/kettenis/tmp/rclark/u-boot/include/efi_loader.h:204which is the
ascii2unicode()function which is used inefi_disk_add_dev()and indeed does 16-bit stores to potentiaslly unaligned memory. And yes, adding__packedto structefi_device_file_pathwill 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
PATCH 13/20 efi_loader: use proper device-paths for partitions
Quoted 7 lines · Rob Clark
I've started trying to hack up
test_efi_loader.pyto 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
PATCH 13/20 efi_loader: use proper device-paths for partitions
Quoted 11 lines · Rob Clark
Quoted 7 lines · Rob Clark
I've started trying to hack up
test_efi_loader.pyto 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_tc2board 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
Quoted 47 lines
=> 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 failBS->LocateHandle()returns 0
undefined instructionpc : [<9eec65c4>] lr : [<9eeca390>]sp :
9fed7a18ip :0000003ffp :9fed7a2c
r10: 00000000 r9 :9eed4658r8 : 00000000
r7 :9eed1ce4r6 :9eed3538r5 :9fed7a6cr4 :9eed4658r3 : 00000000 r2 :9eed2f8er1 :9eed1ee0r0 : 00000000
Flags: nZCv IRQs off FIQs off ModeSVC_32Resetting 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
PATCH 13/20 efi_loader: use proper device-paths for partitions
In reply to Rob ClarkQuoted 11 lines · Rob Clark
Quoted 7 lines · Rob Clark
I've started trying to hack up
test_efi_loader.pyto 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_tc2board 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/
PATCH 13/20 efi_loader: use proper device-paths for partitions
In reply to Rob ClarkQuoted 12 lines
From: Rob Clark <[email protected]>
Date: Sun, 6 Aug 2017 11:34:15 -0400Quoted 7 lines · Rob Clark
I've started trying to hack up
test_efi_loader.pyto 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.
Quoted 2 lines
Making a bit of progress on this (running it on a
vexpress_ca15_tc2board in qemu).. any hint where I can find BOOTARM.EFI src code?
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.
Quoted 46 lines
=> 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 failBS->LocateHandle()returns 0
undefined instructionpc : [<9eec65c4>] lr : [<9eeca390>]sp :
9fed7a18ip :0000003ffp :9fed7a2c
r10: 00000000 r9 :9eed4658r8 : 00000000
r7 :9eed1ce4r6 :9eed3538r5 :9fed7a6cr4 :9eed4658r3 : 00000000 r2 :9eed2f8er1 :9eed1ee0r0 : 00000000
Flags: nZCv IRQs off FIQs off ModeSVC_32Resetting 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
PATCH 13/20 efi_loader: use proper device-paths for partitions
Quoted 15 lines · Mark Kettenis
Quoted 12 lines
From: Rob Clark <[email protected]>
Date: Sun, 6 Aug 2017 11:34:15 -0400Quoted 7 lines · Rob Clark
I've started trying to hack up
test_efi_loader.pyto 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.Quoted 2 lines
Making a bit of progress on this (running it on a
vexpress_ca15_tc2board in qemu).. any hint where I can find BOOTARM.EFI src code?
Quoted 6 lines
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 inefi_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())
Quoted 4 lines
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
PATCH 13/20 efi_loader: use proper device-paths for partitions
Quoted 44 lines · Rob Clark
Quoted 15 lines · Mark Kettenis
Quoted 12 lines
From: Rob Clark <[email protected]>
Date: Sun, 6 Aug 2017 11:34:15 -0400Quoted 7 lines · Rob Clark
I've started trying to hack up
test_efi_loader.pyto 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.Quoted 2 lines
Making a bit of progress on this (running it on a
vexpress_ca15_tc2board in qemu).. any hint where I can find BOOTARM.EFI src code?Quoted 6 lines
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 inefi_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::DeviceHandleshould 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 inefi_diskprobe())Quoted 4 lines
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.
Quoted 5 lines
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
PATCH 13/20 efi_loader: use proper device-paths for partitions
In reply to Rob ClarkQuoted 47 lines
From: Rob Clark <[email protected]>
Date: Sun, 6 Aug 2017 13:49:43 -0400Quoted 15 lines · Mark Kettenis
Quoted 12 lines
From: Rob Clark <[email protected]>
Date: Sun, 6 Aug 2017 11:34:15 -0400Quoted 7 lines · Rob Clark
I've started trying to hack up
test_efi_loader.pyto 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.Quoted 2 lines
Making a bit of progress on this (running it on a
vexpress_ca15_tc2board in qemu).. any hint where I can find BOOTARM.EFI src code?Quoted 6 lines
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 inefi_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::DeviceHandleshould 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 inefi_diskprobe())Quoted 4 lines
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.
Quoted 5 lines
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!
Quoted 4 lines
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.
Quoted 2 lines
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 setCONFIG_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 setCONFIG_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=yCONFIG_HAS_THUMB2=yCONFIG_ARM_ASM_UNIFIED=yCONFIG_CPU_V7=yCONFIG_SYS_ARM_ARCH=7CONFIG_SYS_CACHE_SHIFT_6=yCONFIG_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=yCONFIG_SPL_USE_ARCH_MEMCPY=yCONFIG_USE_ARCH_MEMSET=yCONFIG_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 setCONFIG_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 setCONFIG_SPL_GPIO_SUPPORT=yCONFIG_SPL_LIBCOMMON_SUPPORT=y CONFIG_SPL_LIBGENERIC_SUPPORT=y CONFIG_SYS_MALLOC_F_LEN=0x400CONFIG_CONS_INDEX=1CONFIG_SPL_MMC_SUPPORT=yCONFIG_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 setCONFIG_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=432CONFIG_DRAM_MBUS_CLK=300CONFIG_DRAM_ZQ=127
# CONFIG_DRAM_ODT_EN is not setCONFIG_DRAM_EMR1=4CONFIG_DRAM_TPR3=0CONFIG_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=0CONFIG_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 setCONFIG_VIDEO=yCONFIG_VIDEO_HDMI=y
# CONFIG_VIDEO_VGA is not setCONFIG_VIDEO_COMPOSITE=yCONFIG_VIDEO_LCD_MODE=""CONFIG_VIDEO_LCD_DCLK_PHASE=1CONFIG_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=3CONFIG_SPL_STACK_R_ADDR=0x4fe00000
# CONFIG_SPL_FAT_SUPPORT is not set CONFIG_CPU_V7_HAS_NONSEC=yCONFIG_CPU_V7_HAS_VIRT=yCONFIG_ARCH_SUPPORT_PSCI=yCONFIG_ARMV7_NONSEC=y
# CONFIG_ARMV7_BOOT_SEC_DEFAULT is not set CONFIG_ARMV7_VIRT=yCONFIG_ARMV7_PSCI=yCONFIG_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 setCONFIG_DEFAULT_DEVICE_TREE="sun7i-a20-bananapi"CONFIG_SMBIOS_PRODUCT_NAME="sunxi"
# CONFIG_DEBUG_UART is not setCONFIG_AHCI=y
#
# General setup
#CONFIG_LOCALVERSION=""CONFIG_LOCALVERSION_AUTO=yCONFIG_CC_OPTIMIZE_FOR_SIZE=yCONFIG_DISTRO_DEFAULTS=yCONFIG_SYS_MALLOC_F=yCONFIG_SPL_SYS_MALLOC_F_LEN=0x400CONFIG_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 setCONFIG_OF_BOARD_SETUP=y
# CONFIG_OF_SYSTEM_SETUP is not set
# CONFIG_OF_STDOUT_VIA_ALIAS is not setCONFIG_SYS_EXTRA_OPTIONS=""CONFIG_ARCH_FIXUP_FDT_MEMORY=y
#
# API
#
# CONFIG_API is not set
#
# Boot timing
#
# CONFIG_BOOTSTAGE is not setCONFIG_BOOTSTAGE_USER_COUNT=20CONFIG_BOOTSTAGE_RECORD_COUNT=30CONFIG_BOOTSTAGE_STASH_ADDR=0CONFIG_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 setCONFIG_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 setCONFIG_ENV_OFFSET=0x88000CONFIG_ENV_SIZE=0x20000CONFIG_BOOTDELAY=2
#
# Console
#CONFIG_MENU=y
# CONFIG_CONSOLE_RECORD is not set
# CONFIG_SILENT_CONSOLE is not setCONFIG_PRE_CONSOLE_BUFFER=yCONFIG_PRE_CON_BUF_SZ=4096CONFIG_PRE_CON_BUF_ADDR=0x4f000000CONFIG_CONSOLE_MUX=yCONFIG_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 setCONFIG_SYS_STDIO_DEREGISTER=y
# CONFIG_FIT_EMBED is not setCONFIG_DEFAULT_FDT_FILE=""
# CONFIG_VERSION_VARIABLE is not setCONFIG_DISPLAY_CPUINFO=yCONFIG_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=yCONFIG_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=yCONFIG_HUSH_PARSER=yCONFIG_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 setCONFIG_CMD_CONSOLE=y
# CONFIG_CMD_CPU is not set
# CONFIG_CMD_LICENSE is not set
#
# Boot commands
#CONFIG_CMD_BOOTD=yCONFIG_CMD_BOOTM=yCONFIG_CMD_BOOTZ=yCONFIG_CMD_BOOTEFI=yCONFIG_CMD_BOOTEFI_HELLO_COMPILE=y
# CONFIG_CMD_BOOTEFI_HELLO is not set
# CONFIG_CMD_BOOTMENU is not setCONFIG_CMD_ELF=yCONFIG_CMD_FDT=yCONFIG_CMD_GO=yCONFIG_CMD_RUN=yCONFIG_CMD_IMI=y
# CONFIG_CMD_IMLS is not setCONFIG_CMD_XIMG=yCONFIG_CMD_POWEROFF=y
#
# Environment commands
#
# CONFIG_CMD_ASKENV is not setCONFIG_CMD_EXPORTENV=yCONFIG_CMD_IMPORTENV=yCONFIG_CMD_EDITENV=y
# CONFIG_CMD_GREPENV is not setCONFIG_CMD_SAVEENV=yCONFIG_CMD_ENV_EXISTS=y
# CONFIG_CMD_ENV_CALLBACK is not set
# CONFIG_CMD_ENV_FLAGS is not set
#
# Memory commands
#CONFIG_CMD_MEMORY=yCONFIG_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 setCONFIG_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 setCONFIG_CMD_LOADB=yCONFIG_CMD_LOADS=y
# CONFIG_CMD_FLASH is not set
# CONFIG_CMD_GPT is not set
# CONFIG_CMD_ARMFLASH is not setCONFIG_CMD_MMC=y
# CONFIG_CMD_NAND is not setCONFIG_CMD_PART=y
# CONFIG_CMD_SF is not set
# CONFIG_CMD_SPI is not setCONFIG_CMD_I2C=yCONFIG_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 setCONFIG_CMD_GPIO=y
# CONFIG_CMD_FDC is not set
# CONFIG_CMD_SATA is not set
#
# Shell scripting commands
#CONFIG_CMD_ECHO=yCONFIG_CMD_ITEST=yCONFIG_CMD_SOURCE=yCONFIG_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 setCONFIG_CMD_DHCP=yCONFIG_CMD_PXE=yCONFIG_CMD_NFS=yCONFIG_CMD_MII=yCONFIG_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 setCONFIG_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=yCONFIG_CMD_EXT4=y
# CONFIG_CMD_EXT4_WRITE is not setCONFIG_CMD_FAT=yCONFIG_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 setCONFIG_DOS_PARTITION=y
# CONFIG_SPL_DOS_PARTITION is not setCONFIG_ISO_PARTITION=y
# CONFIG_SPL_ISO_PARTITION is not set
# CONFIG_AMIGA_PARTITION is not set
# CONFIG_SPL_AMIGA_PARTITION is not setCONFIG_EFI_PARTITION=yCONFIG_EFI_PARTITION_ENTRIES_OFF=0
# CONFIG_SPL_EFI_PARTITION is not setCONFIG_PARTITION_UUIDS=y
# CONFIG_SPL_PARTITION_UUIDS is not set
# CONFIG_PARTITION_TYPE_GUID is not setCONFIG_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 setCONFIG_OF_SEPARATE=y
# CONFIG_OF_EMBED is not set
# CONFIG_OF_BOARD is not setCONFIG_NET=y
# CONFIG_NET_RANDOM_ETHADDR is not setCONFIG_NETCONSOLE=yCONFIG_NET_TFTP_VARS=yCONFIG_BOOTP_PXE_CLIENTARCH=0x15CONFIG_BOOTP_VCI_STRING="U-Boot.armv7"
#
# Device Drivers
#
#
# Generic Driver Options
#CONFIG_DM=y
# CONFIG_SPL_DM is not setCONFIG_DM_WARN=yCONFIG_DM_DEVICE_REMOVE=yCONFIG_DM_STDIO=yCONFIG_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 setCONFIG_SIMPLE_BUS=yCONFIG_OF_TRANSLATE=yCONFIG_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 setCONFIG_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 setCONFIG_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 setCONFIG_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 setCONFIG_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 setCONFIG_DM_ETH=yCONFIG_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 setCONFIG_ETH_DESIGNWARE=y
# CONFIG_ETHOC is not set
# CONFIG_FTMAC100 is not set
# CONFIG_MACB is not setCONFIG_RGMII=y
# CONFIG_RTL8139 is not set
# CONFIG_RTL8169 is not setCONFIG_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 setCONFIG_AXP209_POWER=yCONFIG_AXP_DCDC2_VOLT=1400CONFIG_AXP_DCDC3_VOLT=1250CONFIG_AXP_ALDO2_VOLT=3000CONFIG_AXP_ALDO3_VOLT=0CONFIG_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=115200CONFIG_REQUIRE_SERIAL_CONSOLE=yCONFIG_SERIAL_PRESENT=yCONFIG_SPL_SERIAL_PRESENT=yCONFIG_DM_SERIAL=y
# CONFIG_SERIAL_IRQ_BUFFER is not setCONFIG_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 setCONFIG_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=yCONFIG_DM_USB=y
#
# USB Host Controller Drivers
#CONFIG_USB_HOST=y
# CONFIG_USB_XHCI_HCD is not setCONFIG_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=yCONFIG_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 setCONFIG_CFB_CONSOLE=y
# CONFIG_CFB_CONSOLE_ANSI is not setCONFIG_VGA_AS_SINGLE_DEVICE=yCONFIG_VIDEO_SW_CURSOR=y
# CONFIG_CONSOLE_EXTRA_INFO is not setCONFIG_CONSOLE_SCROLL_LINES=1
# CONFIG_VIDEO_CT69000 is not setCONFIG_SYS_CONSOLE_BG_COL=0x00CONFIG_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 setCONFIG_FS_FAT=yCONFIG_FAT_WRITE=yCONFIG_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 setCONFIG_HAVE_PRIVATE_LIBGCC=yCONFIG_USE_PRIVATE_LIBGCC=yCONFIG_SYS_HZ=1000CONFIG_USE_TINY_PRINTF=yCONFIG_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 setCONFIG_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=yCONFIG_SMBIOS_MANUFACTURER=""CONFIG_EFI_LOADER=y
# CONFIG_UNIT_TEST is not set
PATCH 13/20 efi_loader: use proper device-paths for partitions
Quoted 11 lines
Date: Sun, 6 Aug 2017 20:21:45 +0200 (CEST)
From: Mark Kettenis <[email protected]>Quoted 4 lines
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.
lib/efi_loader/efi_device_path.c +2 -2
@@ -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 );
PATCH 13/20 efi_loader: use proper device-paths for partitions
Quoted 20 lines · Mark Kettenis
Quoted 11 lines
Date: Sun, 6 Aug 2017 20:21:45 +0200 (CEST)
From: Mark Kettenis <[email protected]>Quoted 4 lines
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.
lib/efi_loader/efi_device_path.c +0
-0
lib/efi_loader/efi_device_path.c static void *dp_part_fill(void *buf, struct blk_desc *desc, int part) · line 312
Quoted 10 lines
lib/efi_loader/efi_device_path.c +2
-2@@ -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
PATCH 13/20 efi_loader: use proper device-paths for partitions
Quoted 29 lines · Rob Clark
Quoted 28 lines · Mark Kettenis
Quoted 11 lines
Date: Sun, 6 Aug 2017 20:21:45 +0200 (CEST)
From: Mark Kettenis <[email protected]>Quoted 4 lines
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.
lib/efi_loader/efi_device_path.c +2
-2@@ -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);
Quoted 10 lines
lib/efi_loader/efi_device_path.c static void *dp_part_fill(void *buf, struct blk_desc *desc, int part) · line 312
Quoted 2 lines
lib/efi_loader/efi_device_path.c +0
-0memcpy (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_pathis 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
PATCH 13/20 efi_loader: use proper device-paths for partitions
In reply to Mark KettenisQuoted 53 lines · Mark Kettenis
Quoted 47 lines
From: Rob Clark <[email protected]>
Date: Sun, 6 Aug 2017 13:49:43 -0400Quoted 15 lines · Mark Kettenis
Quoted 12 lines
From: Rob Clark <[email protected]>
Date: Sun, 6 Aug 2017 11:34:15 -0400Quoted 7 lines · Rob Clark
I've started trying to hack up
test_efi_loader.pyto 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.Quoted 2 lines
Making a bit of progress on this (running it on a
vexpress_ca15_tc2board in qemu).. any hint where I can find BOOTARM.EFI src code?Quoted 6 lines
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 inefi_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::DeviceHandleshould 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 inefi_diskprobe())Quoted 4 lines
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.
Quoted 5 lines
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..
Quoted 3 lines
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
PATCH 13/20 efi_loader: use proper device-paths for partitions
In reply to Rob ClarkQuoted 50 lines · Rob Clark
Quoted 7 lines · Rob Clark
I've started trying to hack up
test_efi_loader.pyto 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_tc2board 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 failBS->LocateHandle()returns 0
undefined instructionpc : [<9eec65c4>] lr : [<9eeca390>]sp :
9fed7a18ip :0000003ffp :9fed7a2c
r10: 00000000 r9 :9eed4658r8 : 00000000
r7 :9eed1ce4r6 :9eed3538r5 :9fed7a6cr4 :9eed4658r3 : 00000000 r2 :9eed2f8er1 :9eed1ee0r0 : 00000000
Flags: nZCv IRQs off FIQs off ModeSVC_32Resetting 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
Quoted 7 lines
*** 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 failefi_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
Quoted 1 line
Quoted 1 line
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
PATCH 13/20 efi_loader: use proper device-paths for partitions
Quoted 59 lines · Jonathan Gray
Quoted 50 lines · Rob Clark
Quoted 7 lines · Rob Clark
I've started trying to hack up
test_efi_loader.pyto 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_tc2board 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 failBS->LocateHandle()returns 0
undefined instructionpc : [<9eec65c4>] lr : [<9eeca390>]sp :
9fed7a18ip :0000003ffp :9fed7a2c
r10: 00000000 r9 :9eed4658r8 : 00000000
r7 :9eed1ce4r6 :9eed3538r5 :9fed7a6cr4 :9eed4658r3 : 00000000 r2 :9eed2f8er1 :9eed1ee0r0 : 00000000
Flags: nZCv IRQs off FIQs off ModeSVC_32Resetting 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: 0Quoted 7 lines
*** Warning - bad CRC, using default environment
In: serial Out: serial Err: serial Net: smc911x-0 Hit any key to stop autoboot: 2
Quoted 4 lines
Why does U-Boot not set
fdt_addr_ror fdtfile for vexpress? Worse yet trying to load to the defaultkernel_addr_rfails. 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
Quoted 133 lines
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.fsU-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: 0MMC Device 1 not found
no mmc device at slot 1
switch to partitions #0, OK
mmc0 is current device
env - environment handling commandsUsage:
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 ata0008000...
WARNING: Invalid device tree, expect boot to failefi_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_r0x81000000
=> 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 ata0008000...efi_load_pe: Invalid DOS Signature
## Application terminated, r = 2147483646
=> printenvkernel_addr_rkernel_addr_r=0xa0008000=> setenv
kernel_addr_r0x82000000
=> 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 disksQuoted 1 line
Quoted 1 line
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]=0xaad1c0OpenBSD/armv7 booting ...
arg00xc0dad1c0arg10x8e0arg20x86ed0000
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 at0x80db0000
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.orgOpenBSD 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: ID0x1190f500PROCID00x14000237pluart0 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
PATCH 13/20 efi_loader: use proper device-paths for partitions
Quoted 60 lines · Rob Clark
Quoted 59 lines · Jonathan Gray
Quoted 57 lines · Rob Clark
Quoted 7 lines · Rob Clark
I've started trying to hack up
test_efi_loader.pyto 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_tc2board 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 failBS->LocateHandle()returns 0
undefined instructionpc : [<9eec65c4>] lr : [<9eeca390>]sp :
9fed7a18ip :0000003ffp :9fed7a2c
r10: 00000000 r9 :9eed4658r8 : 00000000
r7 :9eed1ce4r6 :9eed3538r5 :9fed7a6cr4 :9eed4658r3 : 00000000 r2 :9eed2f8er1 :9eed1ee0r0 : 00000000
Flags: nZCv IRQs off FIQs off ModeSVC_32Resetting 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
Quoted 8 lines
Quoted 4 lines
Why does U-Boot not set
fdt_addr_ror fdtfile for vexpress? Worse yet trying to load to the defaultkernel_addr_rfails. 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
=> bdinfoarch_number = 0x000008E0boot_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
Quoted 1 line
Quoted 1 line
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
PATCH 13/20 efi_loader: use proper device-paths for partitions
In reply to Mark KettenisQuoted 4 lines · Mark Kettenis
OpenBSD doesn't run on the db410c. However, our EFI bootloader should just run. You can download it from:
Quoted 8 lines
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
Quoted 1 line
Quoted 1 line
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>
PATCH 13/20 efi_loader: use proper device-paths for partitions
Quoted 29 lines
From: Rob Clark <[email protected]>
Date: Sat, 5 Aug 2017 10:28:34 -0400Quoted 4 lines · Mark Kettenis
OpenBSD doesn't run on the db410c. However, our EFI bootloader should just run. You can download it from:
Quoted 8 lines
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 failQuoted 1 line
Quoted 1 line
OpenBSD/arm64 BOOTAA64 0.6
Quoted 16 lines
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).
PATCH 13/20 efi_loader: use proper device-paths for partitions
In reply to Mark KettenisOn Fri, Aug 04, 2017 at 10:41:32PM +0200, Mark Kettenis wrote:
[...]
Quoted 9 lines
..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.
Signature · 1 line
Peter
PATCH 14/20 efi_loader: use proper device-paths for net
In reply to Rob Clark--- lib/efi_loader/efi_net.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-)
lib/efi_loader/efi_net.c +2 -17
@@ -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 ;
Signature · 1 line
2.13.0
PATCH 15/20 efi_loader: refactor boot device and loaded_image handling
In reply to Rob ClarkGet 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.
--- 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(-)
cmd/bootefi.c +59 -142
@@ -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); }
include/efi_loader.h +4 -1
@@ -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 *tableefi_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;
lib/efi_loader/efi_boottime.c +35 -0
@@ -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,
lib/efi_loader/efi_net.c +1 -4
@@ -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 ; }
Signature · 1 line
2.13.0
PATCH 16/20 efi_loader: add file/filesys support
In reply to Rob Clarkfallback.efi (and probably other things) use UEFI's simple-file-system protocol and file support to search for OS's to boot.
--- 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
fs/fs.c +21 -0
@@ -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);
include/efi.h +2 -0
@@ -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 ;
include/efi_api.h +65 -0
69 lines not on this page · raw message
include/efi_loader.h +13 -0
@@ -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 */
include/fs.h +2 -0
@@ -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".
lib/efi_loader/Makefile +1 -0
@@ -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
lib/efi_loader/efi_disk.c +51 -0
69 lines not on this page · raw message
lib/efi_loader/efi_file.c new file +468 -0
468 lines not on this page · raw message
lib/efi_loader/efi_image_loader.c +3 -0
@@ -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)
Signature · 1 line
2.13.0
PATCH 17/20 efi_loader: support load_image() from a file-path
In reply to Rob ClarkPreviously we only supported the case when the EFI application loaded the image into memory for us. But fallback.efi does not do this.
--- lib/efi_loader/efi_boottime.c | 83 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 68 insertions(+), 15 deletions(-)
lib/efi_loader/efi_boottime.c +68 -15
@@ -749,6 +749,45 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *oblist_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 ); }
Signature · 1 line
2.13.0
PATCH 18/20 efi_loader: make pool allocations cacheline aligned
In reply to Rob ClarkThis 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.
--- lib/efi_loader/efi_memory.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
lib/efi_loader/efi_memory.c +3 -2
@@ -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 ;
Signature · 1 line
2.13.0
PATCH 19/20 efi_loader: efi variable support
In reply to Rob Clark--- 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
cmd/bootefi.c +4 -0
@@ -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);
include/efi.h +19 -0
@@ -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 *
include/efi_loader.h +10 -0
@@ -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 */
lib/efi_loader/Makefile +1 -1
@@ -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
lib/efi_loader/efi_boottime.c +5 -0
@@ -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 */
lib/efi_loader/efi_runtime.c +13 -4
@@ -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, };
lib/efi_loader/efi_variable.c new file +342 -0
342 lines not on this page · raw message
Signature · 1 line
2.13.0
PATCH 19/20 efi_loader: efi variable support
On 4 August 2017 at 13:32, Rob Clark <[email protected]> wrote:
Commit message?
Quoted 11 lines
Signed-off-by Rob Clark <[email protected]>--- 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
PATCH 20/20 efi_loader: add bootmgr
In reply to Rob ClarkSimilar 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.)
--- 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
cmd/bootefi.c +46 -2
@@ -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);
include/config_distro_bootcmd.h +5 -0
@@ -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 " \
include/efi_api.h +4 -0
@@ -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)
include/efi_loader.h +6 -0
@@ -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 */
lib/efi_loader/Makefile +1 -1
@@ -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
lib/efi_loader/efi_bootmgr.c new file +169 -0
169 lines not on this page · raw message
lib/efi_loader/efi_boottime.c +3 -3
@@ -749,8 +749,8 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *oblist_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);
lib/efi_loader/efi_image_loader.c +1 -0
@@ -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 =
Signature · 1 line
2.13.0
PATCH 20/20 efi_loader: add bootmgr
Quoted 9 lines · Rob Clark
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
Quoted 381 lines
Signed-off-by Rob Clark <[email protected]>--- 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.ccmd/bootefi.c +46
-2@@ -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);include/config_distro_bootcmd.h +5
-0@@ -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 " \include/efi_api.h +4
-0@@ -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)include/efi_loader.h +6
-0@@ -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 */ lib/efi_loader/Makefile +1
-1@@ -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.olib/efi_loader/efi_bootmgr.c new file +169
-0@@ -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; +}lib/efi_loader/efi_boottime.c +3
-3@@ -749,8 +749,8 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *oblist_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);lib/efi_loader/efi_image_loader.c +1
-0@@ -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 =
PATCH 20/20 efi_loader: add bootmgr
Quoted 12 lines · Heinrich Schuchardt
Quoted 9 lines · Rob Clark
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.)
Quoted 6 lines
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
Quoted 387 lines
Best regards
Heinrich
Quoted 381 lines
Signed-off-by Rob Clark <[email protected]>--- 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.ccmd/bootefi.c +46
-2@@ -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);include/config_distro_bootcmd.h +5
-0@@ -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 " \include/efi_api.h +4
-0@@ -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)include/efi_loader.h +6
-0@@ -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 */ lib/efi_loader/Makefile +1
-1@@ -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.olib/efi_loader/efi_bootmgr.c new file +169
-0@@ -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; +}lib/efi_loader/efi_boottime.c +3
-3@@ -749,8 +749,8 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *oblist_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);lib/efi_loader/efi_image_loader.c +1
-0@@ -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 =
PATCH 20/20 efi_loader: add bootmgr
Quoted 33 lines · Rob Clark
Quoted 12 lines · Heinrich Schuchardt
Quoted 9 lines · Rob Clark
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.)
Quoted 6 lines
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.
Quoted 3 lines
(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
Quoted 391 lines
BR,
-RQuoted 387 lines
Best regards
Heinrich
Quoted 381 lines
Signed-off-by Rob Clark <[email protected]>--- 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.ccmd/bootefi.c +46
-2@@ -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);include/config_distro_bootcmd.h +5
-0@@ -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 " \include/efi_api.h +4
-0@@ -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)include/efi_loader.h +6
-0@@ -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 */ lib/efi_loader/Makefile +1
-1@@ -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.olib/efi_loader/efi_bootmgr.c new file +169
-0@@ -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; +}lib/efi_loader/efi_boottime.c +3
-3@@ -749,8 +749,8 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *oblist_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);lib/efi_loader/efi_image_loader.c +1
-0@@ -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 =
PATCH 20/20 efi_loader: add bootmgr
In reply to Rob ClarkQuoted 15 lines · Rob Clark
Quoted 14 lines · Heinrich Schuchardt
Quoted 9 lines · Rob Clark
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.
Quoted 8 lines
Quoted 4 lines
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.
Quoted 9 lines
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.
Quoted 3 lines
(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.
Signature · 1 line
Peter
[U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
In reply to Rob ClarkSome 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.
---
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(-)
arch/arm/config.mk +1 -1
@@ -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
include/efi_api.h +30 -0
@@ -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 {
lib/efi_loader/efi_device_path.c +3 -0
@@ -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 ));
Signature · 1 line
2.13.0
[U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
Quoted 34 lines · Rob Clark
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_UNALIGNEDshould *only* be defined on archs that cannot do unaligned accesses.Signed-off-by Rob Clark <[email protected]>---
I'm not sure if there are other arch's that need -DBROKEN_UNALIGNEDMark, 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(-)arch/arm/config.mk +0
-0
arch/arm/config.mk LLVMS_RELFLAGS := $(call cc-option,-mllvm,) \ · line 31
Quoted 5 lines
arch/arm/config.mk +1
-1@@ -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
Quoted 91 lines
arch/arm/config.mk +0
-0ifdef CONFIG_ARM64 PLATFORM_ELFFLAGS += -B aarch64 -O elf64-littleaarch64include/efi_api.h +30
-0@@ -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 {lib/efi_loader/efi_device_path.c +3
-0@@ -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 ));
[U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
Quoted 43 lines · Heinrich Schuchardt
Quoted 34 lines · Rob Clark
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_UNALIGNEDshould *only* be defined on archs that cannot do unaligned accesses.Signed-off-by Rob Clark <[email protected]>---
I'm not sure if there are other arch's that need -DBROKEN_UNALIGNEDMark, 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(-)arch/arm/config.mk +0
-0arch/arm/config.mk LLVMS_RELFLAGS := $(call cc-option,-mllvm,) \ · line 31
Quoted 5 lines
arch/arm/config.mk +1
-1@@ -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_UNALIGNEDNAK
Quoted 7 lines
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
_packedat 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
Quoted 96 lines
Best regards
Heinrich
Quoted 91 lines
arch/arm/config.mk +0
-0ifdef CONFIG_ARM64 PLATFORM_ELFFLAGS += -B aarch64 -O elf64-littleaarch64include/efi_api.h +30
-0@@ -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 {lib/efi_loader/efi_device_path.c +3
-0@@ -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 ));
[U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
Quoted 47 lines · Rob Clark
Quoted 46 lines · Heinrich Schuchardt
Quoted 34 lines · Rob Clark
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_UNALIGNEDshould *only* be defined on archs that cannot do unaligned accesses.Signed-off-by Rob Clark <[email protected]>---
I'm not sure if there are other arch's that need -DBROKEN_UNALIGNEDMark, 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(-)arch/arm/config.mk +0
-0arch/arm/config.mk LLVMS_RELFLAGS := $(call cc-option,-mllvm,) \ · line 31
Quoted 5 lines
arch/arm/config.mk +1
-1@@ -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_UNALIGNEDNAK
We have more then ARM. And other architectures also create exceptions for unaligned access.
Quoted 8 lines
Quoted 4 lines
I hate platform specific code. It should not be used outside /arch.
To play it save you should not use
_packedat all! Use memcpy to transfer between aligned and unaligned memory.except for reasons I explained in the thread on the patch that added the
__packedin 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
Quoted 100 lines
BR,
-RQuoted 96 lines
Best regards
Heinrich
Quoted 91 lines
arch/arm/config.mk +0
-0ifdef CONFIG_ARM64 PLATFORM_ELFFLAGS += -B aarch64 -O elf64-littleaarch64include/efi_api.h +30
-0@@ -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 {lib/efi_loader/efi_device_path.c +3
-0@@ -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 ));
[U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
Quoted 53 lines · Rob Clark
Quoted 52 lines · Rob Clark
Quoted 50 lines · Heinrich Schuchardt
Quoted 34 lines · Rob Clark
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_UNALIGNEDshould *only* be defined on archs that cannot do unaligned accesses.Signed-off-by Rob Clark <[email protected]>---
I'm not sure if there are other arch's that need -DBROKEN_UNALIGNEDMark, 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(-)arch/arm/config.mk +0
-0arch/arm/config.mk LLVMS_RELFLAGS := $(call cc-option,-mllvm,) \ · line 31
Quoted 5 lines
arch/arm/config.mk +1
-1@@ -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_UNALIGNEDNAK
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
_packedat all! Use memcpy to transfer between aligned and unaligned memory.
Quoted 8 lines
Quoted 3 lines
except for reasons I explained in the thread on the patch that added the
__packedin 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_LOADERon 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
Quoted 103 lines
Quoted 102 lines
BR,
-RQuoted 96 lines
Best regards
Heinrich
Quoted 91 lines
arch/arm/config.mk +0
-0ifdef CONFIG_ARM64 PLATFORM_ELFFLAGS += -B aarch64 -O elf64-littleaarch64include/efi_api.h +30
-0@@ -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 {lib/efi_loader/efi_device_path.c +3
-0@@ -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 ));
[U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
Quoted 58 lines · Heinrich Schuchardt
Quoted 57 lines · Rob Clark
Quoted 55 lines · Rob Clark
Quoted 43 lines · Heinrich Schuchardt
Quoted 34 lines · Rob Clark
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_UNALIGNEDshould *only* be defined on archs that cannot do unaligned accesses.Signed-off-by Rob Clark <[email protected]>---
I'm not sure if there are other arch's that need -DBROKEN_UNALIGNEDMark, 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(-)arch/arm/config.mk +0
-0arch/arm/config.mk LLVMS_RELFLAGS := $(call cc-option,-mllvm,) \ · line 31
Quoted 5 lines
arch/arm/config.mk +1
-1@@ -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_UNALIGNEDNAK
Quoted 7 lines
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
_packedat all! Use memcpy to transfer between aligned and unaligned memory.except for reasons I explained in the thread on the patch that added the
__packedin the first place. Sorry, this is ugly but we have to do it.
Quoted 8 lines
Quoted 4 lines
well, to be fair, we don't *have* to do it. The alternative is disable
EFI_LOADERon 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
[U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
In reply to Rob ClarkQuoted 52 lines · Rob Clark
Quoted 43 lines · Heinrich Schuchardt
Quoted 34 lines · Rob Clark
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_UNALIGNEDshould *only* be defined on archs that cannot do unaligned accesses.Signed-off-by Rob Clark <[email protected]>---
I'm not sure if there are other arch's that need -DBROKEN_UNALIGNEDMark, 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(-)arch/arm/config.mk +0
-0arch/arm/config.mk LLVMS_RELFLAGS := $(call cc-option,-mllvm,) \ · line 31
Quoted 5 lines
arch/arm/config.mk +1
-1@@ -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_UNALIGNEDNAK
Quoted 7 lines
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
_packedat all! Use memcpy to transfer between aligned and unaligned memory.
Quoted 6 lines
except for reasons I explained in the thread on the patch that added the
__packedin 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
Quoted 99 lines
Quoted 98 lines
Best regards
Heinrich
Quoted 91 lines
arch/arm/config.mk +0
-0ifdef CONFIG_ARM64 PLATFORM_ELFFLAGS += -B aarch64 -O elf64-littleaarch64include/efi_api.h +30
-0@@ -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 {lib/efi_loader/efi_device_path.c +3
-0@@ -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 ));
[U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
Quoted 63 lines · Heinrich Schuchardt
Quoted 52 lines · Rob Clark
Quoted 43 lines · Heinrich Schuchardt
Quoted 34 lines · Rob Clark
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_UNALIGNEDshould *only* be defined on archs that cannot do unaligned accesses.Signed-off-by Rob Clark <[email protected]>---
I'm not sure if there are other arch's that need -DBROKEN_UNALIGNEDMark, 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(-)arch/arm/config.mk +0
-0arch/arm/config.mk LLVMS_RELFLAGS := $(call cc-option,-mllvm,) \ · line 31
Quoted 5 lines
arch/arm/config.mk +1
-1@@ -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_UNALIGNEDNAK
Quoted 7 lines
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
_packedat all! Use memcpy to transfer between aligned and unaligned memory.Quoted 6 lines
except for reasons I explained in the thread on the patch that added the
__packedin the first place. Sorry, this is ugly but we have to do it.BR,
-RAccording to the UEFI standard the nodes in paths are not to be assumed to be aligned.
Quoted 6 lines
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
__packeddoes 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
Quoted 104 lines
Best regards
Heinrich
Quoted 99 lines
Quoted 98 lines
Best regards
Heinrich
Quoted 91 lines
arch/arm/config.mk +0
-0ifdef CONFIG_ARM64 PLATFORM_ELFFLAGS += -B aarch64 -O elf64-littleaarch64include/efi_api.h +30
-0@@ -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 {lib/efi_loader/efi_device_path.c +3
-0@@ -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 ));
[U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
Quoted 69 lines · Rob Clark
Quoted 68 lines · Heinrich Schuchardt
Quoted 52 lines · Rob Clark
Quoted 43 lines · Heinrich Schuchardt
Quoted 34 lines · Rob Clark
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_UNALIGNEDshould *only* be defined on archs that cannot do unaligned accesses.Signed-off-by Rob Clark <[email protected]>---
I'm not sure if there are other arch's that need -DBROKEN_UNALIGNEDMark, 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(-)arch/arm/config.mk +0
-0arch/arm/config.mk LLVMS_RELFLAGS := $(call cc-option,-mllvm,) \ · line 31
Quoted 5 lines
arch/arm/config.mk +1
-1@@ -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_UNALIGNEDNAK
Quoted 7 lines
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
_packedat all! Use memcpy to transfer between aligned and unaligned memory.Quoted 6 lines
except for reasons I explained in the thread on the patch that added the
__packedin the first place. Sorry, this is ugly but we have to do it.BR,
-RAccording 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.
Quoted 6 lines
Quoted 1 line
To the idea of padding bytes and
__packeddoes not make sense.Ok, to be fair, you are right about device-paths passed too u-boot. On
BROKEN_UNALIGNEDarchs, 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
Quoted 119 lines
But the padding bytes +
__packeddoes 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_UNALIGNEDarchs (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,
-RQuoted 104 lines
Best regards
Heinrich
Quoted 99 lines
Quoted 98 lines
Best regards
Heinrich
Quoted 91 lines
arch/arm/config.mk +0
-0ifdef CONFIG_ARM64 PLATFORM_ELFFLAGS += -B aarch64 -O elf64-littleaarch64include/efi_api.h +30
-0@@ -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 {lib/efi_loader/efi_device_path.c +3
-0@@ -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 ));
[U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
Quoted 94 lines · Rob Clark
Quoted 69 lines · Rob Clark
Quoted 68 lines · Heinrich Schuchardt
Quoted 52 lines · Rob Clark
Quoted 43 lines · Heinrich Schuchardt
Quoted 34 lines · Rob Clark
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_UNALIGNEDshould *only* be defined on archs that cannot do unaligned accesses.Signed-off-by Rob Clark <[email protected]>---
I'm not sure if there are other arch's that need -DBROKEN_UNALIGNEDMark, 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(-)arch/arm/config.mk +0
-0arch/arm/config.mk LLVMS_RELFLAGS := $(call cc-option,-mllvm,) \ · line 31
Quoted 5 lines
arch/arm/config.mk +1
-1@@ -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_UNALIGNEDNAK
Quoted 7 lines
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
_packedat all! Use memcpy to transfer between aligned and unaligned memory.Quoted 6 lines
except for reasons I explained in the thread on the patch that added the
__packedin the first place. Sorry, this is ugly but we have to do it.BR,
-RAccording 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.
Quoted 6 lines
Quoted 1 line
To the idea of padding bytes and
__packeddoes not make sense.Ok, to be fair, you are right about device-paths passed too u-boot. On
BROKEN_UNALIGNEDarchs, 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, butefi_dp_sanitize()always allocates and copies onBROKEN_UNALIGNEDarchs andefi_dp_free()always free's onBROKEN_UNALIGNEDarchs, 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 onEFI_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 usingEFI_LOADERon anyBROKEN_UNALIGNEDarch
Quoted 22 lines
anyone who cares about armv7 + efi have a preference between always doing an extra alloc+copy+free vs
EFI_EXIT()magic?BR,
-RQuoted 15 lines
But the padding bytes +
__packeddoes 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_UNALIGNEDarchs (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
Quoted 96 lines
Quoted 95 lines
Quoted 95 lines
Quoted 94 lines
Quoted 93 lines
Quoted 92 lines
arch/arm/config.mk +0
-0ifdef CONFIG_ARM64 PLATFORM_ELFFLAGS += -B aarch64 -O elf64-littleaarch64include/efi_api.h +30
-0@@ -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 {lib/efi_loader/efi_device_path.c +3
-0@@ -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 ));
[U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
Quoted 95 lines · Heinrich Schuchardt
Quoted 94 lines · Rob Clark
Quoted 69 lines · Rob Clark
Quoted 68 lines · Heinrich Schuchardt
Quoted 52 lines · Rob Clark
Quoted 43 lines · Heinrich Schuchardt
Quoted 34 lines · Rob Clark
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_UNALIGNEDshould *only* be defined on archs that cannot do unaligned accesses.Signed-off-by Rob Clark <[email protected]>---
I'm not sure if there are other arch's that need -DBROKEN_UNALIGNEDMark, 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(-)arch/arm/config.mk +0
-0arch/arm/config.mk LLVMS_RELFLAGS := $(call cc-option,-mllvm,) \ · line 31
Quoted 5 lines
arch/arm/config.mk +1
-1@@ -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_UNALIGNEDNAK
Quoted 7 lines
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
_packedat all! Use memcpy to transfer between aligned and unaligned memory.Quoted 6 lines
except for reasons I explained in the thread on the patch that added the
__packedin the first place. Sorry, this is ugly but we have to do it.BR,
-RAccording 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.
Quoted 6 lines
Quoted 1 line
To the idea of padding bytes and
__packeddoes not make sense.Ok, to be fair, you are right about device-paths passed too u-boot. On
BROKEN_UNALIGNEDarchs, 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, butefi_dp_sanitize()always allocates and copies onBROKEN_UNALIGNEDarchs andefi_dp_free()always free's onBROKEN_UNALIGNEDarchs, 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 onEFI_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 usingEFI_LOADERon anyBROKEN_UNALIGNEDarch
Quoted 5 lines
Quoted 3 lines
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"..
Quoted 6 lines
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
[U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
Quoted 113 lines · Rob Clark
Quoted 95 lines · Heinrich Schuchardt
Quoted 94 lines · Rob Clark
Quoted 69 lines · Rob Clark
Quoted 68 lines · Heinrich Schuchardt
Quoted 52 lines · Rob Clark
Quoted 43 lines · Heinrich Schuchardt
Quoted 34 lines · Rob Clark
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_UNALIGNEDshould *only* be defined on archs that cannot do unaligned accesses.Signed-off-by Rob Clark <[email protected]>---
I'm not sure if there are other arch's that need -DBROKEN_UNALIGNEDMark, 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(-)arch/arm/config.mk +0
-0arch/arm/config.mk LLVMS_RELFLAGS := $(call cc-option,-mllvm,) \ · line 31
Quoted 5 lines
arch/arm/config.mk +1
-1@@ -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_UNALIGNEDNAK
Quoted 7 lines
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
_packedat all! Use memcpy to transfer between aligned and unaligned memory.Quoted 6 lines
except for reasons I explained in the thread on the patch that added the
__packedin the first place. Sorry, this is ugly but we have to do it.BR,
-RAccording 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.
Quoted 6 lines
Quoted 1 line
To the idea of padding bytes and
__packeddoes not make sense.Ok, to be fair, you are right about device-paths passed too u-boot. On
BROKEN_UNALIGNEDarchs, 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, butefi_dp_sanitize()always allocates and copies onBROKEN_UNALIGNEDarchs andefi_dp_free()always free's onBROKEN_UNALIGNEDarchs, 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 onEFI_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 usingEFI_LOADERon anyBROKEN_UNALIGNEDarchQuoted 5 lines
Quoted 3 lines
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"..
Quoted 5 lines
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.
Quoted 7 lines
Quoted 1 line
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
[U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
Quoted 125 lines
From: Alexander Graf <[email protected]>
Date: Mon, 7 Aug 2017 21:19:37 +0100Quoted 113 lines · Rob Clark
Quoted 95 lines · Heinrich Schuchardt
Quoted 94 lines · Rob Clark
Quoted 69 lines · Rob Clark
Quoted 68 lines · Heinrich Schuchardt
Quoted 52 lines · Rob Clark
Quoted 43 lines · Heinrich Schuchardt
Quoted 34 lines · Rob Clark
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_UNALIGNEDshould *only* be defined on archs that cannot do unaligned accesses.Signed-off-by Rob Clark <[email protected]>---
I'm not sure if there are other arch's that need -DBROKEN_UNALIGNEDMark, 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(-)arch/arm/config.mk +0
-0arch/arm/config.mk LLVMS_RELFLAGS := $(call cc-option,-mllvm,) \ · line 31
Quoted 5 lines
arch/arm/config.mk +1
-1@@ -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_UNALIGNEDNAK
Quoted 7 lines
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
_packedat all! Use memcpy to transfer between aligned and unaligned memory.Quoted 6 lines
except for reasons I explained in the thread on the patch that added the
__packedin the first place. Sorry, this is ugly but we have to do it.BR,
-RAccording 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.
Quoted 6 lines
Quoted 1 line
To the idea of padding bytes and
__packeddoes not make sense.Ok, to be fair, you are right about device-paths passed too u-boot. On
BROKEN_UNALIGNEDarchs, 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, butefi_dp_sanitize()always allocates and copies onBROKEN_UNALIGNEDarchs andefi_dp_free()always free's onBROKEN_UNALIGNEDarchs, 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 onEFI_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 usingEFI_LOADERon anyBROKEN_UNALIGNEDarchQuoted 5 lines
Quoted 3 lines
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"..
Quoted 5 lines
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.
Quoted 7 lines
Quoted 1 line
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 ;-))
Quoted 3 lines
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.
Quoted 3 lines
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.
Quoted 10 lines
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-accessor
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.
Quoted 4 lines
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.
Quoted 2 lines
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
[U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
Quoted 125 lines · Mark Kettenis
Quoted 125 lines
From: Alexander Graf <[email protected]>
Date: Mon, 7 Aug 2017 21:19:37 +0100Quoted 120 lines · Rob Clark
Quoted 95 lines · Heinrich Schuchardt
Quoted 94 lines · Rob Clark
Quoted 69 lines · Rob Clark
Quoted 68 lines · Heinrich Schuchardt
Quoted 52 lines · Rob Clark
Quoted 43 lines · Heinrich Schuchardt
Quoted 34 lines · Rob Clark
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_UNALIGNEDshould *only* be defined on archs that cannot do unaligned accesses.Signed-off-by Rob Clark <[email protected]>---
I'm not sure if there are other arch's that need -DBROKEN_UNALIGNEDMark, 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(-)arch/arm/config.mk +0
-0arch/arm/config.mk LLVMS_RELFLAGS := $(call cc-option,-mllvm,) \ · line 31
Quoted 5 lines
arch/arm/config.mk +1
-1@@ -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_UNALIGNEDNAK
Quoted 7 lines
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
_packedat all! Use memcpy to transfer between aligned and unaligned memory.Quoted 6 lines
except for reasons I explained in the thread on the patch that added the
__packedin the first place. Sorry, this is ugly but we have to do it.BR,
-RAccording 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.
Quoted 6 lines
Quoted 1 line
To the idea of padding bytes and
__packeddoes not make sense.Ok, to be fair, you are right about device-paths passed too u-boot. On
BROKEN_UNALIGNEDarchs, 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, butefi_dp_sanitize()always allocates and copies onBROKEN_UNALIGNEDarchs andefi_dp_free()always free's onBROKEN_UNALIGNEDarchs, 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 onEFI_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 usingEFI_LOADERon anyBROKEN_UNALIGNEDarchQuoted 5 lines
Quoted 3 lines
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"..
Quoted 6 lines
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 ;-))
Quoted 8 lines
Quoted 3 lines
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.
Quoted 10 lines
So UEFI payload that wants to support pre-ARMv7 hardware should make sure it doesn't do any unaligned access.
Quoted 3 lines
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).
Quoted 13 lines
Quoted 10 lines
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-accessor
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.
Quoted 7 lines
*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
__packedto 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.)
Quoted 7 lines
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.
Quoted 8 lines
Quoted 4 lines
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.
Quoted 7 lines
Quoted 2 lines
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
[U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
Quoted 139 lines
Am 07.08.2017 um 23:18 schrieb Rob Clark <[email protected]>:
Quoted 125 lines · Mark Kettenis
Quoted 125 lines
From: Alexander Graf <[email protected]>
Date: Mon, 7 Aug 2017 21:19:37 +0100Quoted 121 lines · Rob Clark
Quoted 96 lines · Heinrich Schuchardt
Quoted 95 lines · Rob Clark
Quoted 70 lines · Rob Clark
Quoted 69 lines · Heinrich Schuchardt
Quoted 53 lines · Rob Clark
Quoted 44 lines · Heinrich Schuchardt
Quoted 35 lines · Rob Clark
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_UNALIGNEDshould *only* be defined on archs that cannot do unaligned accesses.Signed-off-by Rob Clark <[email protected]>---
I'm not sure if there are other arch's that need -DBROKEN_UNALIGNEDMark, 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(-)arch/arm/config.mk +0
-0arch/arm/config.mk LLVMS_RELFLAGS := $(call cc-option,-mllvm,) \ · line 31
Quoted 5 lines
arch/arm/config.mk +1
-1@@ -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_UNALIGNEDNAK
Quoted 7 lines
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
_packedat all! Use memcpy to transfer between aligned and unaligned memory.Quoted 6 lines
except for reasons I explained in the thread on the patch that added the
__packedin the first place. Sorry, this is ugly but we have to do it.BR,
-RAccording 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.
Quoted 6 lines
Quoted 1 line
To the idea of padding bytes and
__packeddoes not make sense.Ok, to be fair, you are right about device-paths passed too u-boot. On
BROKEN_UNALIGNEDarchs, 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, butefi_dp_sanitize()always allocates and copies onBROKEN_UNALIGNEDarchs andefi_dp_free()always free's onBROKEN_UNALIGNEDarchs, 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 onEFI_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 usingEFI_LOADERon anyBROKEN_UNALIGNEDarchQuoted 5 lines
Quoted 3 lines
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"..
Quoted 6 lines
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 ;-))
Quoted 8 lines
Quoted 3 lines
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.
Quoted 6 lines
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.
Quoted 12 lines
Quoted 11 lines
So UEFI payload that wants to support pre-ARMv7 hardware should make sure it doesn't do any unaligned access.
Quoted 3 lines
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.
Quoted 7 lines
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
__packedon 'structefi_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.
Quoted 22 lines
Quoted 14 lines
Quoted 11 lines
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-accessor
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.
Quoted 7 lines
*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
__packedto 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.
Quoted 6 lines
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.
Quoted 46 lines
Quoted 8 lines
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.
Quoted 8 lines
Quoted 4 lines
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.
Quoted 7 lines
Quoted 2 lines
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
__packedbreaks 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.
Quoted 2 lines
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
[U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
Quoted 139 lines · Alexander Graf
Quoted 139 lines
Am 07.08.2017 um 23:18 schrieb Rob Clark <[email protected]>:
Quoted 133 lines · Mark Kettenis
Quoted 125 lines
From: Alexander Graf <[email protected]>
Date: Mon, 7 Aug 2017 21:19:37 +0100Quoted 114 lines · Rob Clark
Quoted 96 lines · Heinrich Schuchardt
Quoted 95 lines · Rob Clark
Quoted 70 lines · Rob Clark
Quoted 69 lines · Heinrich Schuchardt
Quoted 53 lines · Rob Clark
Quoted 44 lines · Heinrich Schuchardt
Quoted 35 lines · Rob Clark
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_UNALIGNEDshould *only* be defined on archs that cannot do unaligned accesses.Signed-off-by Rob Clark <[email protected]>---
I'm not sure if there are other arch's that need -DBROKEN_UNALIGNEDMark, 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(-)arch/arm/config.mk +0
-0arch/arm/config.mk LLVMS_RELFLAGS := $(call cc-option,-mllvm,) \ · line 31
Quoted 5 lines
arch/arm/config.mk +1
-1@@ -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_UNALIGNEDNAK
Quoted 7 lines
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
_packedat all! Use memcpy to transfer between aligned and unaligned memory.Quoted 6 lines
except for reasons I explained in the thread on the patch that added the
__packedin the first place. Sorry, this is ugly but we have to do it.BR,
-RAccording 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.
Quoted 6 lines
Quoted 1 line
To the idea of padding bytes and
__packeddoes not make sense.Ok, to be fair, you are right about device-paths passed too u-boot. On
BROKEN_UNALIGNEDarchs, 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, butefi_dp_sanitize()always allocates and copies onBROKEN_UNALIGNEDarchs andefi_dp_free()always free's onBROKEN_UNALIGNEDarchs, 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 onEFI_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 usingEFI_LOADERon anyBROKEN_UNALIGNEDarchQuoted 5 lines
Quoted 3 lines
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"..
Quoted 5 lines
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.
Quoted 7 lines
Quoted 1 line
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 ;-))
Quoted 3 lines
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.
Quoted 9 lines
Quoted 6 lines
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.
Quoted 20 lines
Quoted 12 lines
Quoted 11 lines
So UEFI payload that wants to support pre-ARMv7 hardware should make sure it doesn't do any unaligned access.
Quoted 3 lines
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.Quoted 7 lines
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
__packedon 'structefi_device_path' (which I've added locally and will be in the next revision of the patchset).
Quoted 2 lines
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?
Quoted 86 lines
Quoted 22 lines
Quoted 14 lines
Quoted 11 lines
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-accessor
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.
Quoted 7 lines
*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
__packedto 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.Quoted 6 lines
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.
Quoted 46 lines
Quoted 8 lines
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.
Quoted 8 lines
Quoted 4 lines
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.
Quoted 7 lines
Quoted 2 lines
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
__packedbreaks 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.Quoted 2 lines
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
[U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
Quoted 157 lines · Ard Biesheuvel
Quoted 139 lines · Alexander Graf
Quoted 139 lines
Am 07.08.2017 um 23:18 schrieb Rob Clark <[email protected]>:
Quoted 133 lines · Mark Kettenis
Quoted 125 lines
From: Alexander Graf <[email protected]>
Date: Mon, 7 Aug 2017 21:19:37 +0100Quoted 114 lines · Rob Clark
Quoted 96 lines · Heinrich Schuchardt
Quoted 95 lines · Rob Clark
Quoted 70 lines · Rob Clark
Quoted 69 lines · Heinrich Schuchardt
Quoted 53 lines · Rob Clark
Quoted 44 lines · Heinrich Schuchardt
Quoted 40 lines · Rob Clark
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 <[email protected]>
---
I'm not sure if there are other arch's that need -DBROKEN_UNALIGNEDMark, 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_UNALIGNEDNAK
Quoted 7 lines
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
_packedat all! Use memcpy to transfer between aligned and unaligned memory.Quoted 6 lines
except for reasons I explained in the thread on the patch that added the
__packedin the first place. Sorry, this is ugly but we have to do it.BR,
-RAccording 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.
Quoted 6 lines
Quoted 1 line
To the idea of padding bytes and
__packeddoes not make sense.Ok, to be fair, you are right about device-paths passed too u-boot. On
BROKEN_UNALIGNEDarchs, 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, butefi_dp_sanitize()always allocates and copies onBROKEN_UNALIGNEDarchs andefi_dp_free()always free's onBROKEN_UNALIGNEDarchs, 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 onEFI_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 usingEFI_LOADERon anyBROKEN_UNALIGNEDarchQuoted 5 lines
Quoted 3 lines
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"..
Quoted 5 lines
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.
Quoted 7 lines
Quoted 1 line
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 ;-))
Quoted 3 lines
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.
Quoted 9 lines
Quoted 6 lines
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).
Quoted 5 lines
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.
Quoted 19 lines
Quoted 19 lines
Quoted 18 lines
Quoted 10 lines
So UEFI payload that wants to support pre-ARMv7 hardware should make sure it doesn't do any unaligned access.
Quoted 3 lines
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
__packedon 'structefi_device_path' (which I've added locally and will be in the next revision of the patchset).
Quoted 7 lines
Quoted 3 lines
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
[U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
Quoted 18 lines · Leif Lindholm
Quoted 17 lines · Ard Biesheuvel
Quoted 15 lines · Alexander Graf
Quoted 11 lines
Am 07.08.2017 um 23:18 schrieb Rob Clark <[email protected]>:
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
__packedon 'structefi_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.
Quoted 8 lines
Quoted 3 lines
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
[U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
Quoted 38 lines · Rob Clark
Quoted 16 lines · Leif Lindholm
Quoted 15 lines · Ard Biesheuvel
Quoted 13 lines · Alexander Graf
Quoted 9 lines
Am 07.08.2017 um 23:18 schrieb Rob Clark <[email protected]>:
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
__packedon 'structefi_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.
Quoted 7 lines
Quoted 3 lines
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
__packedattribute 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.
Quoted 5 lines
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
[U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
In reply to Alexander GrafQuoted 168 lines · Alexander Graf
Quoted 139 lines
Am 07.08.2017 um 23:18 schrieb Rob Clark <[email protected]>:
Quoted 125 lines · Mark Kettenis
Quoted 125 lines
From: Alexander Graf <[email protected]>
Date: Mon, 7 Aug 2017 21:19:37 +0100Quoted 121 lines · Rob Clark
Quoted 96 lines · Heinrich Schuchardt
Quoted 95 lines · Rob Clark
Quoted 70 lines · Rob Clark
Quoted 69 lines · Heinrich Schuchardt
Quoted 53 lines · Rob Clark
Quoted 44 lines · Heinrich Schuchardt
Quoted 35 lines · Rob Clark
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_UNALIGNEDshould *only* be defined on archs that cannot do unaligned accesses.Signed-off-by Rob Clark <[email protected]>---
I'm not sure if there are other arch's that need -DBROKEN_UNALIGNEDMark, 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(-)arch/arm/config.mk +0
-0arch/arm/config.mk LLVMS_RELFLAGS := $(call cc-option,-mllvm,) \ · line 31
Quoted 5 lines
arch/arm/config.mk +1
-1@@ -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_UNALIGNEDNAK
Quoted 7 lines
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
_packedat all! Use memcpy to transfer between aligned and unaligned memory.Quoted 6 lines
except for reasons I explained in the thread on the patch that added the
__packedin the first place. Sorry, this is ugly but we have to do it.BR,
-RAccording 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.
Quoted 6 lines
Quoted 1 line
To the idea of padding bytes and
__packeddoes not make sense.Ok, to be fair, you are right about device-paths passed too u-boot. On
BROKEN_UNALIGNEDarchs, 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, butefi_dp_sanitize()always allocates and copies onBROKEN_UNALIGNEDarchs andefi_dp_free()always free's onBROKEN_UNALIGNEDarchs, 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 onEFI_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 usingEFI_LOADERon anyBROKEN_UNALIGNEDarchQuoted 5 lines
Quoted 3 lines
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"..
Quoted 6 lines
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 ;-))
Quoted 8 lines
Quoted 3 lines
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.
Quoted 6 lines
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.
Quoted 12 lines
Quoted 11 lines
So UEFI payload that wants to support pre-ARMv7 hardware should make sure it doesn't do any unaligned access.
Quoted 3 lines
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.Quoted 7 lines
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
__packedon 'structefi_device_path' (which I've added locally and will be in the next revision of the patchset).
Quoted 2 lines
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
[U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
In reply to Rob ClarkQuoted 237 lines
From: Rob Clark <[email protected]>
Date: Mon, 7 Aug 2017 18:18:50 -0400Quoted 125 lines · Mark Kettenis
Quoted 125 lines
From: Alexander Graf <[email protected]>
Date: Mon, 7 Aug 2017 21:19:37 +0100Quoted 120 lines · Rob Clark
Quoted 95 lines · Heinrich Schuchardt
Quoted 94 lines · Rob Clark
Quoted 69 lines · Rob Clark
Quoted 68 lines · Heinrich Schuchardt
Quoted 52 lines · Rob Clark
Quoted 43 lines · Heinrich Schuchardt
Quoted 34 lines · Rob Clark
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_UNALIGNEDshould *only* be defined on archs that cannot do unaligned accesses.Signed-off-by Rob Clark <[email protected]>---
I'm not sure if there are other arch's that need -DBROKEN_UNALIGNEDMark, 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(-)arch/arm/config.mk +0
-0arch/arm/config.mk LLVMS_RELFLAGS := $(call cc-option,-mllvm,) \ · line 31
Quoted 5 lines
arch/arm/config.mk +1
-1@@ -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_UNALIGNEDNAK
Quoted 7 lines
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
_packedat all! Use memcpy to transfer between aligned and unaligned memory.Quoted 6 lines
except for reasons I explained in the thread on the patch that added the
__packedin the first place. Sorry, this is ugly but we have to do it.BR,
-RAccording 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.
Quoted 6 lines
Quoted 1 line
To the idea of padding bytes and
__packeddoes not make sense.Ok, to be fair, you are right about device-paths passed too u-boot. On
BROKEN_UNALIGNEDarchs, 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, butefi_dp_sanitize()always allocates and copies onBROKEN_UNALIGNEDarchs andefi_dp_free()always free's onBROKEN_UNALIGNEDarchs, 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 onEFI_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 usingEFI_LOADERon anyBROKEN_UNALIGNEDarchQuoted 5 lines
Quoted 3 lines
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"..
Quoted 6 lines
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 ;-))
Quoted 8 lines
Quoted 3 lines
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.
Quoted 10 lines
So UEFI payload that wants to support pre-ARMv7 hardware should make sure it doesn't do any unaligned access.
Quoted 3 lines
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
__packedon 'structefi_device_path' (which I've added locally and will be in the next revision of the patchset).Quoted 13 lines
Quoted 10 lines
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-accessor
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.
Quoted 7 lines
*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
__packedto 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.)
Quoted 7 lines
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.
Quoted 8 lines
Quoted 4 lines
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.
Quoted 7 lines
Quoted 2 lines
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
__packedbreaks 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.
Quoted 2 lines
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
[U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
Quoted 34 lines · Mark Kettenis
Quoted 25 lines
From: Rob Clark <[email protected]>
Date: Mon, 7 Aug 2017 18:18:50 -0400Quoted 10 lines · Mark Kettenis
Quoted 5 lines
From: Alexander Graf <[email protected]>
Date: Mon, 7 Aug 2017 21:19:37 +0100For 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
__packedbreaks 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.Quoted 2 lines
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.
Quoted 12 lines
The problem that needs to be fixed is the manipulation of device path nodes in U-Boot itself. Using
__packedand -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 seemsascii2unicode()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 theascii2unicode()conversion into a suitably aligned buffer andmemcpy()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
[U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
Quoted 51 lines
From: Rob Clark <[email protected]>
Date: Tue, 8 Aug 2017 08:54:26 -0400Quoted 34 lines · Mark Kettenis
Quoted 25 lines
From: Rob Clark <[email protected]>
Date: Mon, 7 Aug 2017 18:18:50 -0400Quoted 10 lines · Mark Kettenis
Quoted 5 lines
From: Alexander Graf <[email protected]>
Date: Mon, 7 Aug 2017 21:19:37 +0100For 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
__packedbreaks 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.Quoted 2 lines
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.
Quoted 12 lines
The problem that needs to be fixed is the manipulation of device path nodes in U-Boot itself. Using
__packedand -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 seemsascii2unicode()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 theascii2unicode()conversion into a suitably aligned buffer andmemcpy()that into place.
Quoted 7 lines
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.
Quoted 8 lines
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.
[U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
Quoted 59 lines · Mark Kettenis
Quoted 51 lines
From: Rob Clark <[email protected]>
Date: Tue, 8 Aug 2017 08:54:26 -0400Quoted 34 lines · Mark Kettenis
Quoted 25 lines
From: Rob Clark <[email protected]>
Date: Mon, 7 Aug 2017 18:18:50 -0400Quoted 10 lines · Mark Kettenis
Quoted 5 lines
From: Alexander Graf <[email protected]>
Date: Mon, 7 Aug 2017 21:19:37 +0100For 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
__packedbreaks 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.Quoted 2 lines
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.
Quoted 12 lines
The problem that needs to be fixed is the manipulation of device path nodes in U-Boot itself. Using
__packedand -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 seemsascii2unicode()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 theascii2unicode()conversion into a suitably aligned buffer andmemcpy()that into place.Quoted 7 lines
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.
Quoted 3 lines
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.
Quoted 5 lines
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.
Quoted 26 lines
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__packedto fix another bug, but you'll have to deal with the consequences.Quoted 8 lines
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.
Quoted 3 lines
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.)
Quoted 5 lines
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
[U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
Quoted 4 lines · Rob Clark
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
[U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
In reply to Rob ClarkQuoted 131 lines · Rob Clark
Quoted 59 lines · Mark Kettenis
Quoted 51 lines
From: Rob Clark <[email protected]>
Date: Tue, 8 Aug 2017 08:54:26 -0400Quoted 34 lines · Mark Kettenis
Quoted 25 lines
From: Rob Clark <[email protected]>
Date: Mon, 7 Aug 2017 18:18:50 -0400Quoted 10 lines · Mark Kettenis
Quoted 5 lines
From: Alexander Graf <[email protected]>
Date: Mon, 7 Aug 2017 21:19:37 +0100For 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
__packedbreaks 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.Quoted 2 lines
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.
Quoted 12 lines
The problem that needs to be fixed is the manipulation of device path nodes in U-Boot itself. Using
__packedand -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 seemsascii2unicode()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 theascii2unicode()conversion into a suitably aligned buffer andmemcpy()that into place.Quoted 7 lines
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.Quoted 3 lines
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.
Quoted 5 lines
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.
Quoted 26 lines
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__packedto fix another bug, but you'll have to deal with the consequences.Quoted 8 lines
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.
Quoted 3 lines
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.)
Quoted 5 lines
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.
Quoted 7 lines
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
[U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
In reply to Rob ClarkQuoted 83 lines · Rob Clark
Quoted 63 lines · Heinrich Schuchardt
Quoted 52 lines · Rob Clark
Quoted 43 lines · Heinrich Schuchardt
Quoted 34 lines · Rob Clark
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_UNALIGNEDshould *only* be defined on archs that cannot do unaligned accesses.Signed-off-by Rob Clark <[email protected]>---
I'm not sure if there are other arch's that need -DBROKEN_UNALIGNEDMark, 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(-)arch/arm/config.mk +0
-0arch/arm/config.mk LLVMS_RELFLAGS := $(call cc-option,-mllvm,) \ · line 31
Quoted 5 lines
arch/arm/config.mk +1
-1@@ -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_UNALIGNEDNAK
Quoted 7 lines
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
_packedat all! Use memcpy to transfer between aligned and unaligned memory.Quoted 6 lines
except for reasons I explained in the thread on the patch that added the
__packedin the first place. Sorry, this is ugly but we have to do it.BR,
-RAccording to the UEFI standard the nodes in paths are not to be assumed to be aligned.
Quoted 6 lines
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
__packeddoes not make sense.Ok, to be fair, you are right about device-paths passed too u-boot. On
BROKEN_UNALIGNEDarchs, 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 +
__packeddoes 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.)
Quoted 5 lines
My proposal simply preserves the bug that we already have on
BROKEN_UNALIGNEDarchs (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
[U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses
In reply to Heinrich SchuchardtQuoted 60 lines · Heinrich Schuchardt
Quoted 52 lines · Rob Clark
Quoted 43 lines · Heinrich Schuchardt
Quoted 34 lines · Rob Clark
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_UNALIGNEDshould *only* be defined on archs that cannot do unaligned accesses.Signed-off-by Rob Clark <[email protected]>---
I'm not sure if there are other arch's that need -DBROKEN_UNALIGNEDMark, 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(-)arch/arm/config.mk +0
-0arch/arm/config.mk LLVMS_RELFLAGS := $(call cc-option,-mllvm,) \ · line 31
Quoted 5 lines
arch/arm/config.mk +1
-1@@ -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_UNALIGNEDNAK
Quoted 7 lines
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
_packedat all! Use memcpy to transfer between aligned and unaligned memory.Quoted 6 lines
except for reasons I explained in the thread on the patch that added the
__packedin the first place. Sorry, this is ugly but we have to do it.BR,
-R
Quoted 7 lines
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.
Quoted 1 line
To the idea of padding bytes and
__packeddoes 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.
Signature · 1 line
Peter
cover enough UEFI for standard distro boot
In reply to Rob ClarkQuoted 7 lines · Rob Clark
This patchset fleshes out
EFI_LOADERenough 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.
Quoted 6 lines
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!
Signature · 8 lines
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>
cover enough UEFI for standard distro boot
Quoted 16 lines · Tom Rini
Quoted 7 lines · Rob Clark
This patchset fleshes out
EFI_LOADERenough 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.Quoted 6 lines
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.
Quoted 5 lines
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