efi_loader: enough UEFI for standard distro boot
Subsystems (2)
v2 cover efi_loader: 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.
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.
This is implemented with the 'bootefi bootmgr' command.
If there are no bootable options the firmware falls back to loading \EFI\BOOT\bootaa64.efi (exact name varies depending on arch), which for distro's using fallback/shim (which should include most modern linux distros) then loads fallback.efi which uses the EFI_SIMPLE_FILE_SYSTEM_PROTCOL and EFI_FILE_PROTOCOL to search for any \EFI\*\boot.csv, and will then set BootOrder and BootXXXX EFI variables accordingly so that on next boot fallback.efi is not necessary.
The last 5 patches are a bit unrelated, just pulling forward some of the patches I have from the next patchset, to get Shell.efi and SCT working.
Peter Jones (2):
part: extract MBR signature from partitions
efi: add some more device path structures
Rob Clark (19):
part: move efi_guid_t
efi: add some missing __packed
efi_loader: add device-path utils
efi_loader: drop redundant efi_device_path_protocol
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
efi_loader: file_path should be variable length
efi_loader: set loaded image code/data type properly
efi_loader: print GUIDs
efi_loader: split out escape sequence based size query
efi_loader: Correctly figure out size for vidconsole
efi_loader: Some console improvements for vidconsole
cmd/bootefi.c | 249 ++++++-------- disk/part_dos.c | 12 +- disk/part_efi.c | 20 ++ include/blk.h | 15 + include/config_distro_bootcmd.h | 5 + include/efi.h | 25 ++ include/efi_api.h | 162 ++++++++- include/efi_loader.h | 62 +++- include/part.h | 3 +- include/part_efi.h | 4 - include/pe.h | 6 + lib/efi_loader/Makefile | 3 +- lib/efi_loader/efi_bootmgr.c | 169 ++++++++++ lib/efi_loader/efi_boottime.c | 162 +++++++-- lib/efi_loader/efi_console.c | 123 ++++--- lib/efi_loader/efi_device_path.c | 563 +++++++++++++++++++++++++++++++ lib/efi_loader/efi_device_path_to_text.c | 242 +++++++++---- lib/efi_loader/efi_disk.c | 86 +++-- lib/efi_loader/efi_file.c | 556 ++++++++++++++++++++++++++++++ lib/efi_loader/efi_image_loader.c | 26 ++ 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 | 335 ++++++++++++++++++ 24 files changed, 2520 insertions(+), 354 deletions(-) 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.5
PATCH v3 1/9 fs/fat: split out helper to init fsdata
Want to re-use this in fat dirent iterator in next patch.
--- fs/fat/fat.c | 73 +++++++++++++++++++++++++++++++++++------------------------ include/fat.h | 1 + 2 files changed, 44 insertions(+), 30 deletions(-)
fs/fat/fat.c +43 -30
@@ -808,35 +808,17 @@ exit:return ret; } -__u8 do_fat_read_at_block[MAX_CLUSTSIZE ] -__aligned(ARCH_DMA_MINALIGN) ; - -int do_fat_read_at (const char *filename,loff_t pos,void *buffer, -loff_t maxsize,int dols,int dogetsize,loff_t *size) +static int get_fs_info (fsdata *mydata) { -char fnamecopy[2048 ];boot_sector bs;volume_info volinfo; -fsdata datablock; -fsdata *mydata = &datablock; -dir_entry *dentptr =NULL ; -__u16 prevcksum =0xffff ; -char *subname ="" ; -__u32 cursect; -int idx, isdir =0 ; -int files =0 , dirs =0 ; -int ret =-1 ; -int firsttime;__u32 root_cluster =0 ; -__u32 read_blk; -int rootdir_size =0 ; -int buffer_blk_cnt; -int do_read; -__u8 *dir_ptr; +int ret; -if (read_bootsectandvi (&bs, &volinfo, &mydata->fatsize)) { + ret =read_bootsectandvi (&bs, &volinfo, &mydata->fatsize); +if (ret) {debug ("Error: reading boot sector\n" ); -return -1 ; +return ret; }if (mydata->fatsize ==32 ) {
@@ -848,8 +830,7 @@ int do_fat_read_at(const char *filename, loff_t pos, void *buffer, mydata->fat_sect = bs.reserved; - cursect = mydata->rootdir_sect - = mydata->fat_sect + mydata->fatlength * bs.fats; + mydata->rootdir_sect = mydata->fat_sect + mydata->fatlength * bs.fats; mydata->sect_size = (bs.sector_size[1 ] <<8 ) + bs.sector_size[0 ]; mydata->clust_size = bs.cluster_size;
@@ -863,12 +844,12 @@ int do_fat_read_at(const char *filename, loff_t pos, void *buffer, mydata->data_begin = mydata->rootdir_sect - (mydata->clust_size *2 ); }else { - rootdir_size = ((bs.dir_entries[1 ] * (int )256 + - bs.dir_entries[0 ]) * -sizeof (dir_entry)) / - mydata->sect_size; + mydata->rootdir_size = ((bs.dir_entries[1 ] * (int )256 + + bs.dir_entries[0 ]) * +sizeof (dir_entry)) / + mydata->sect_size; mydata->data_begin = mydata->rootdir_sect + - rootdir_size - + mydata->rootdir_size - (mydata->clust_size *2 ); }
@@ -893,6 +874,38 @@ int do_fat_read_at(const char *filename, loff_t pos, void *buffer,debug ("Sector size: %d, cluster size: %d\n" , mydata->sect_size, mydata->clust_size); +return 0 ; +} + +__u8 do_fat_read_at_block[MAX_CLUSTSIZE ] +__aligned(ARCH_DMA_MINALIGN) ; + +int do_fat_read_at (const char *filename,loff_t pos,void *buffer, +loff_t maxsize,int dols,int dogetsize,loff_t *size) +{ +char fnamecopy[2048 ]; +fsdata datablock; +fsdata *mydata = &datablock; +dir_entry *dentptr =NULL ; +__u16 prevcksum =0xffff ; +char *subname ="" ; +__u32 cursect; +int idx, isdir =0 ; +int files =0 , dirs =0 ; +int ret =-1 ; +int firsttime; +__u32 root_cluster =0 ; +__u32 read_blk; +int rootdir_size =0 ; +int buffer_blk_cnt; +int do_read; +__u8 *dir_ptr; + +if (get_fs_info (mydata)) +return -1 ; + + cursect = mydata->rootdir_sect; +/* "cwd" is always the root... */ while (ISDIRDELIM (*filename)) filename++;
include/fat.h +1 -0
@@ -174,6 +174,7 @@ typedef struct {__u16 clust_size;/* Size of clusters in sectors */ int data_begin;/* The sector of the first cluster, can be negative */ int fatbufnum;/* Used by get_fatent, init to -1 */ +int rootdir_size;/* Size of root dir for non-FAT32 */ } fsdata;typedef int (file_detectfs_func )(void );
Signature · 1 line
2.13.5
PATCH v2 1/21 part: move efi_guid_t
In reply to Rob ClarkPrep work for next patch.
--- include/efi.h | 4 ++++ include/part.h | 3 ++- include/part_efi.h | 4 ---- 3 files changed, 6 insertions(+), 5 deletions(-)
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
@@ -280,8 +280,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.5
PATCH v2 1/21 part: move efi_guid_t
Quoted 45 lines · Rob Clark
Prep work for next patch.
Signed-off-by Rob Clark <[email protected]>--- include/efi.h | 4 ++++ include/part.h | 3 ++- include/part_efi.h | 4 ---- 3 files changed, 6 insertions(+), 5 deletions(-)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@@ -280,8 +280,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
-0
include/part_efi.h line 63
Quoted 10 lines
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 */
The patch extends
https://lists.denx.de/pipermail/u-boot/2017-September/304970.html
[PATCH 1/1] efi_loader: move efi_guid_t typedef to efi.h
A descriptive commit message might be helpful.
PATCH v2 1/21 part: move efi_guid_t
In reply to Rob ClarkQuoted 1 line · Rob Clark
Prep work for next patch.
Move it where?
Quoted 13 lines
Signed-off-by Rob Clark <[email protected]>--- include/efi.h | 4 ++++ include/part.h | 3 ++- include/part_efi.h | 4 ---- 3 files changed, 6 insertions(+), 5 deletions(-)include/efi.h +0
-0
include/efi.h line 33
Quoted 6 lines
include/efi.h +3
-0@@ -28,6 +28,10 @@struct efi_device_path ; +typedef struct { +u8 b[16 ]; +}efi_guid_t ;
Please add a comment to this
PATCH v3 2/9 fs/fat: introduce new director iterators
In reply to Rob ClarkUntangle directory traversal into a simple iterator, to replace the existing multi-purpose do_fat_read_at() + get_dentfromdir().
--- fs/fat/fat.c | 356 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- include/fat.h | 7 ++ 2 files changed, 360 insertions(+), 3 deletions(-)
fs/fat/fat.c +353 -3
@@ -812,7 +812,6 @@ static int get_fs_info(fsdata *mydata) {boot_sector bs;volume_info volinfo; -__u32 root_cluster =0 ;int ret; ret =read_bootsectandvi (&bs, &volinfo, &mydata->fatsize);
@@ -822,7 +821,6 @@ static int get_fs_info(fsdata *mydata) }if (mydata->fatsize ==32 ) { - root_cluster = bs.root_cluster; mydata->fatlength = bs.fat32_length; }else { mydata->fatlength = bs.fat_length;
@@ -843,6 +841,7 @@ static int get_fs_info(fsdata *mydata)if (mydata->fatsize ==32 ) { mydata->data_begin = mydata->rootdir_sect - (mydata->clust_size *2 ); + mydata->root_cluster = bs.root_cluster; }else { mydata->rootdir_size = ((bs.dir_entries[1] * (int)256 + bs.dir_entries[0]) *
@@ -851,6 +850,9 @@ static int get_fs_info(fsdata *mydata) mydata->data_begin = mydata->rootdir_sect + mydata->rootdir_size - (mydata->clust_size *2 ); + mydata->root_cluster = (mydata->rootdir_sect - + mydata->data_begin) / + mydata->clust_size; } mydata->fatbufnum =-1 ;
@@ -868,7 +870,7 @@ static int get_fs_info(fsdata *mydata) mydata->fatsize, mydata->fat_sect, mydata->fatlength);debug ("Rootdir begins at cluster: %d, sector: %d, offset: %x\n" "Data begins at: %d\n" , - root_cluster, + mydata->root_cluster, mydata->rootdir_sect, mydata->rootdir_sect * mydata->sect_size, mydata->data_begin); debug("Sector size: %d, cluster size: %d\n", mydata->sect_size,
@@ -1245,6 +1247,354 @@ exit:return ret; } + +/* +* Directory iterator, to simplify filesystem traversal +* +* Implements an iterator pattern to traverse directory tables, +* transparently handling directory tables split across multiple +* clusters, and the difference between FAT12/FAT16 root directory +* (contiguous) and subdirectories + FAT32 root (chained). +* +* Rough usage: +* +* for (fat_itr_root(&itr, fsdata); fat_itr_next(&itr); ) { +* // to traverse down to a subdirectory pointed to by +* // current iterator position: +* fat_itr_child(&itr, &itr); +* } +* +* For more complete example, see fat_itr_resolve() +*/ + +typedef struct { +fsdata *fsdata;/* filesystem parameters */ +unsigned clust;/* current cluster */ +int last_cluster;/* set once we've read last cluster */ +int is_root;/* is iterator at root directory */ +int remaining;/* remaining dent's in current cluster */ + +/* current iterator position values: */ +dir_entry *dent;/* current directory entry */ +char l_name[VFAT_MAXLEN_BYTES ];/* long (vfat) name */ +char s_name[14 ];/* short 8.3 name */ +char *name;/* l_name if there is one, else s_name */ + +/* storage for current cluster in memory: */ +u8 block[MAX_CLUSTSIZE ]__aligned(ARCH_DMA_MINALIGN) ; +}fat_itr ; + +static int fat_itr_isdir (fat_itr *itr); + +/** +* fat_itr_root() - initialize an iterator to start at the root +* directory +* +* @itr: iterator to initialize +* @fsdata: filesystem data for the partition +* @return 0 on success, else -errno +*/ +static int fat_itr_root (fat_itr *itr,fsdata *fsdata) +{ +if (get_fs_info (fsdata)) +return -ENXIO ; + + itr->fsdata = fsdata; + itr->clust = fsdata->root_cluster; + itr->dent =NULL ; + itr->remaining =0 ; + itr->last_cluster =0 ; + itr->is_root =1 ; + +return 0 ; +} + +/** +* fat_itr_child() - initialize an iterator to descend into a sub- +* directory +* +* Initializes 'itr' to iterate the contents of the directory at +* the current cursor position of 'parent'. It is an error to +* call this if the current cursor of 'parent' is pointing at a +* regular file. +* +* Note that 'itr' and 'parent' can be the same pointer if you do +* not need to preserve 'parent' after this call, which is useful +* for traversing directory structure to resolve a file/directory. +* +* @itr: iterator to initialize +* @parent: the iterator pointing at a directory entry in the +* parent directory of the directory to iterate +*/ +static void fat_itr_child (fat_itr *itr,fat_itr *parent) +{ +fsdata *mydata = parent->fsdata;/* for silly macros */ +unsigned clustnum =START (parent->dent); + +assert (fat_itr_isdir (parent)); + + itr->fsdata = parent->fsdata; +if (clustnum >0 ) { + itr->clust = clustnum; + }else { + itr->clust = parent->fsdata->root_cluster; + } + itr->dent =NULL ; + itr->remaining =0 ; + itr->last_cluster =0 ; + itr->is_root =0 ; +} + +static void *next_cluster (fat_itr *itr) +{ +fsdata *mydata = itr->fsdata;/* for silly macros */ +int ret; +u32 sect; + +/* have we reached the end? */ +if (itr->last_cluster) +return NULL ; + + sect =clust_to_sect (itr->fsdata, itr->clust); + +debug ("FAT read(sect=%d), clust_size=%d, DIRENTSPERBLOCK=%zd\n" , + sect, itr->fsdata->clust_size,DIRENTSPERBLOCK ); + +/* +* NOTE: do_fat_read_at() had complicated logic to deal w/ +* vfat names that span multiple clusters in the fat16 case, +* which get_dentfromdir() probably also needed (and was +* missing). And not entirely sure what fat32 didn't have +* the same issue.. We solve that by only caring about one +* dent at a time and iteratively constructing the vfat long +* name. +*/ + ret =disk_read (sect, itr->fsdata->clust_size, + itr->block); +if (ret <0 ) { +debug ("Error: reading block\n" ); +return NULL ; + } + +if (itr->is_root && itr->fsdata->fatsize !=32 ) { + itr->clust++; + sect =clust_to_sect (itr->fsdata, itr->clust); +if (sect - itr->fsdata->rootdir_sect >= + itr->fsdata->rootdir_size) { +debug ("cursect: 0x%x\n" , itr->clust); + itr->last_cluster =1 ; + } + }else { + itr->clust =get_fatent (itr->fsdata, itr->clust); +if (CHECK_CLUST (itr->clust, itr->fsdata->fatsize)) { +debug ("cursect: 0x%x\n" , itr->clust); + itr->last_cluster =1 ; + } + } + +return itr->block; +} + +static dir_entry *next_dent (fat_itr *itr) +{ +if (itr->remaining ==0 ) { +struct dir_entry *dent =next_cluster (itr); +unsigned nbytes = itr->fsdata->sect_size * + itr->fsdata->clust_size; + +/* have we reached the last cluster? */ +if (!dent) +return NULL ; + + itr->remaining = nbytes /sizeof (dir_entry) -1 ; + itr->dent = dent; + }else { + itr->remaining--; + itr->dent++; + } + +/* have we reached the last valid entry? */ +if (itr->dent->name[0 ] ==0 ) +return NULL ; + +return itr->dent; +} + +static dir_entry *extract_vfat_name (fat_itr *itr) +{ +struct dir_entry *dent = itr->dent; +int seqn = itr->dent->name[0 ] & ~LAST_LONG_ENTRY_MASK ; +u8 chksum, alias_checksum = ((dir_slot *)dent)->alias_checksum; +int n =0 ; + +while (seqn--) { +char buf[13 ]; +int idx =0 ; + +slot2str ((dir_slot *)dent, buf, &idx); + +/* shift accumulated long-name up and copy new part in: */ +memmove (itr->l_name + idx, itr->l_name, n); +memcpy (itr->l_name, buf, idx); + n += idx; + + dent =next_dent (itr); +if (!dent) +return NULL ; + } + + itr->l_name[n] ='\0' ; + + chksum =mkcksum (dent->name, dent->ext); + +/* checksum mismatch could mean deleted file, etc.. skip it: */ +if (chksum != alias_checksum) { +debug ("** chksum=%x, alias_checksum=%x, l_name=%s, s_name=%8s.%3s\n" , + chksum, alias_checksum, itr->l_name, dent->name, dent->ext); +return NULL ; + } + +return dent; +} + +/** +* fat_itr_next() - step to the next entry in a directory +* +* Must be called once on a new iterator before the cursor is valid. +* +* @itr: the iterator to iterate +* @return boolean, 1 if success or 0 if no more entries in the +* current directory +*/ +static int fat_itr_next (fat_itr *itr) +{ +dir_entry *dent; + + itr->name =NULL ; + +while (1 ) { + dent =next_dent (itr); +if (!dent) +return 0 ; + +if (dent->name[0 ] ==DELETED_FLAG || + dent->name[0 ] == aRING) +continue ; + +if (dent->attr &ATTR_VOLUME ) { +if (vfat_enabled && + (dent->attr &ATTR_VFAT ) ==ATTR_VFAT && + (dent->name[0 ] &LAST_LONG_ENTRY_MASK )) { + dent =extract_vfat_name (itr); +if (!dent) +continue ; + itr->name = itr->l_name; +break ; + }else { +/* Volume label or VFAT entry, skip */ +continue ; + } + } + +break ; + } + +get_name (dent, itr->s_name); +if (!itr->name) + itr->name = itr->s_name; + +return 1 ; +} + +/** +* fat_itr_isdir() - is current cursor position pointing to a directory +* +* @itr: the iterator +* @return true if cursor is at a directory +*/ +static int fat_itr_isdir (fat_itr *itr) +{ +return !!(itr->dent->attr &ATTR_DIR ); +} + +/* +* Helpers: +*/ + +#define TYPE_FILE 0x1 +#define TYPE_DIR 0x2 +#define TYPE_ANY (TYPE_FILE | TYPE_DIR) + +/** +* fat_itr_resolve() - traverse directory structure to resolve the +* requested path. +* +* Traverse directory structure to the requested path. If the specified +* path is to a directory, this will descend into the directory and +* leave it iterator at the start of the directory. If the path is to a +* file, it will leave the iterator in the parent directory with current +* cursor at file's entry in the directory. +* +* @itr: iterator initialized to root +* @path: the requested path +* @type: bitmask of allowable file types +* @return 0 on success or -errno +*/ +static int fat_itr_resolve (fat_itr *itr,const char *path,unsigned type) +{ +const char *next; + +/* chomp any extra leading slashes: */ +while (path[0 ] &&ISDIRDELIM (path[0 ])) + path++; + +/* are we at the end? */ +if (strlen (path) ==0 ) { +if (!(type &TYPE_DIR )) +return -ENOENT ; +return 0 ; + } + +/* find length of next path entry: */ + next = path; +while (next[0 ] && !ISDIRDELIM (next[0 ])) + next++; + +while (fat_itr_next (itr)) { +int match =0 ; +unsigned n =max (strlen (itr->name), (size_t )(next - path)); + +/* check both long and short name: */ +if (!strncasecmp (path, itr->name, n)) + match =1 ; +else if (itr->name != itr->s_name && + !strncasecmp (path, itr->s_name, n)) + match =1 ; + +if (!match) +continue ; + +if (fat_itr_isdir (itr)) { +/* recurse into directory: */ +fat_itr_child (itr, itr); +return fat_itr_resolve (itr, next, type); + }else if (next[0 ]) { +/* +* If next is not empty then we have a case +* like: /path/to/realfile/nonsense +*/ +debug ("bad trailing path: %s\n" , next); +return -ENOENT ; + }else if (!(type &TYPE_FILE )) { +return -ENOTDIR ; + }else { +return 0 ; + } + } + +return -ENOENT ; +} +int do_fat_read (const char *filename,void *buffer,loff_t maxsize,int dols,loff_t *actread) {
include/fat.h +7 -0
@@ -175,8 +175,15 @@ typedef struct {int data_begin;/* The sector of the first cluster, can be negative */ int fatbufnum;/* Used by get_fatent, init to -1 */ int rootdir_size;/* Size of root dir for non-FAT32 */ +__u32 root_cluster;/* First cluster of root dir for FAT32 */ } fsdata; +/* TODO clean up places that are open-coding this: */ +static inline u32 clust_to_sect (fsdata *fsdata,u32 clust) +{ +return fsdata->data_begin + clust * fsdata->clust_size; +} +typedef int (file_detectfs_func )(void );typedef int (file_ls_func )(const char *dir); typedef int (file_read_func)(const char *filename, void *buffer,
Signature · 1 line
2.13.5
PATCH v3 2/9 fs/fat: introduce new director iterators
Quoted 9 lines · Rob Clark
Untangle directory traversal into a simple iterator, to replace the existing multi-purpose
do_fat_read_at()+get_dentfromdir().Signed-off-by Rob Clark <[email protected]>Reviewed-by �ukasz Majewski <[email protected]>--- fs/fat/fat.c | 356 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- include/fat.h | 7 ++ 2 files changed, 360 insertions(+), 3 deletions(-)
But I still think that fat_itr should not be a typedef, since this is something you are adding. I understand what you are saying about the existing code, but really that should be converted at some point, as you say.
PATCH v2 2/21 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 +++++++++++++++ 3 files changed, 44 insertions(+), 3 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
@@ -923,11 +923,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" );
@@ -937,6 +945,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"
@@ -36,6 +38,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)
@@ -63,6 +73,11 @@ struct blk_desc {char vendor[40 +1 ];/* IDE model, SCSI Vendor */ char product[20 +1 ];/* IDE Serial no, SCSI product */ char revision[8 +1 ];/* firmware revision */ +enum sig_type sig_type;/* Partition table signature type */ +union { +uint32_t mbr_sig;/* MBR integer signature */ +efi_guid_t guid_sig;/* GPT GUID Signature */ + };#if CONFIG_IS_ENABLED (BLK )/* * For now we have a few functions which take struct blk_desc as a
Signature · 1 line
2.13.5
PATCH v2 2/21 part: extract MBR signature from partitions
Hi Rob,
Quoted 7 lines · Rob Clark
From: 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.
Signed-off-by Peter Jones <[email protected]>
Quoted 9 lines
[separated from
efi_loaderpart, and fixed build-errors for non-
CONFIG_EFI_PARTITIONcase]Signed-off-by Rob Clark <[email protected]>--- disk/part_dos.c | 12 +++++++++--- disk/part_efi.c | 20 ++++++++++++++++++++ include/blk.h | 15 +++++++++++++++ 3 files changed, 44 insertions(+), 3 deletions(-)
Please see below.
Quoted 85 lines
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@@ -923,11 +923,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" );@@ -937,6 +945,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 +2
-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"
include/blk.h enum if_type { · line 41
Quoted 4 lines
include/blk.h +1
-0@@ -36,6 +38,14 @@ enum if_type { IF_TYPE_COUNT, /* Number of interface types */ }; +enum sig_type {
Please add a comment about what this is
Quoted 23 lines
include/blk.h +12
-1+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) @@ -63,6 +73,11 @@ struct blk_desc {char vendor[40 +1 ];/* IDE model, SCSI Vendor */ char product[20 +1 ];/* IDE Serial no, SCSI product */ char revision[8 +1 ];/* firmware revision */ +enum sig_type sig_type;/* Partition table signature type */ +union { +uint32_t mbr_sig;/* MBR integer signature */ +efi_guid_t guid_sig;/* GPT GUID Signature */ + };#if CONFIG_IS_ENABLED (BLK )/* * For now we have a few functions which take struct blk_desc as a --
Quoted 2 lines
2.13.5
Regards,
Simon
PATCH v2 3/21 efi: add some missing __packed
In reply to Rob ClarkAll of the device-path related structures should be packed. UEFI defines the device-path as a byte-aligned data structure.
--- include/efi_api.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
include/efi_api.h +4 -4
@@ -284,11 +284,11 @@ struct efi_device_path {u8 type;u8 sub_type;u16 length; -}; +} __packed;struct efi_mac_addr {u8 addr[32 ]; -}; +} __packed;#define DEVICE_PATH_TYPE_MESSAGING_DEVICE 0x03# define DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR 0x0b
@@ -297,7 +297,7 @@ struct efi_device_path_mac_addr {struct efi_device_path dp;struct efi_mac_addr mac;u8 if_type; -}; +} __packed;#define DEVICE_PATH_TYPE_MEDIA_DEVICE 0x04# define DEVICE_PATH_SUB_TYPE_FILE_PATH 0x04
@@ -305,7 +305,7 @@ struct efi_device_path_mac_addr {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.5
PATCH v2 3/21 efi: add some missing __packed
Quoted 7 lines · Rob Clark
All of the device-path related structures should be packed. UEFI defines the device-path as a byte-aligned data structure.
Signed-off-by Rob Clark <[email protected]>--- include/efi_api.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
PATCH v3 3/9 fat/fs: convert to directory iterators
In reply to Rob ClarkAnd drop a whole lot of ugly code!
--- fs/fat/fat.c | 722 +++++++--------------------------------------------------- include/fat.h | 6 - 2 files changed, 76 insertions(+), 652 deletions(-)
fs/fat/fat.c +76 -646
@@ -119,22 +119,6 @@ int fat_register_device(struct blk_desc *dev_desc, int part_no) }/* -* Get the first occurence of a directory delimiter ('/' or '\') in a string. -* Return index into string if found, -1 otherwise. -*/ -static int dirdelim (char *str) -{ -char *start = str; - -while (*str !='\0' ) { -if (ISDIRDELIM (*str)) -return str - start; - str++; - } -return -1 ; -} - -/* * Extract zero terminated short name from a directory entry. */ static void get_name (dir_entry *dirent,char *s_name)
@@ -468,95 +452,6 @@ static int slot2str(dir_slot *slotptr, char *l_name, int *idx)return 0 ; } -/* -* Extract the full long filename starting at 'retdent' (which is really -* a slot) into 'l_name'. If successful also copy the real directory entry -* into 'retdent' -* Return 0 on success, -1 otherwise. -*/ -static int -get_vfatname (fsdata *mydata,int curclust,__u8 *cluster, -dir_entry *retdent,char *l_name) -{ -dir_entry *realdent; -dir_slot *slotptr = (dir_slot *)retdent; -__u8 *buflimit = cluster + mydata->sect_size * ((curclust ==0 ) ? -PREFETCH_BLOCKS : - mydata->clust_size); -__u8 counter = (slotptr->id & ~LAST_LONG_ENTRY_MASK ) &0xff ; -int idx =0 ; - -if (counter >VFAT_MAXSEQ ) { -debug ("Error: VFAT name is too long\n" ); -return -1 ; - } - -while ((__u8 *)slotptr < buflimit) { -if (counter ==0 ) -break ; -if (((slotptr->id & ~LAST_LONG_ENTRY_MASK ) &0xff ) != counter) -return -1 ; - slotptr++; - counter--; - } - -if ((__u8 *)slotptr >= buflimit) { -dir_slot *slotptr2; - -if (curclust ==0 ) -return -1 ; - curclust =get_fatent (mydata, curclust); -if (CHECK_CLUST (curclust, mydata->fatsize)) { -debug ("curclust: 0x%x\n" , curclust); -printf ("Invalid FAT entry\n" ); -return -1 ; - } - -if (get_cluster (mydata, curclust, get_contents_vfatname_block, - mydata->clust_size * mydata->sect_size) !=0 ) { -debug ("Error: reading directory block\n" ); -return -1 ; - } - - slotptr2 = (dir_slot *)get_contents_vfatname_block; -while (counter >0 ) { -if (((slotptr2->id & ~LAST_LONG_ENTRY_MASK ) - &0xff ) != counter) -return -1 ; - slotptr2++; - counter--; - } - -/* Save the real directory entry */ - realdent = (dir_entry *)slotptr2; -while ((__u8 *)slotptr2 > get_contents_vfatname_block) { - slotptr2--; -slot2str (slotptr2, l_name, &idx); - } - }else { -/* Save the real directory entry */ - realdent = (dir_entry *)slotptr; - } - -do { - slotptr--; -if (slot2str (slotptr, l_name, &idx)) -break ; - }while (!(slotptr->id &LAST_LONG_ENTRY_MASK )); - - l_name[idx] ='\0' ; -if (*l_name ==DELETED_FLAG ) - *l_name ='\0' ; -else if (*l_name == aRING) - *l_name =DELETED_FLAG ; -downcase (l_name); - -/* Return the real directory entry */ -memcpy (retdent, realdent,sizeof (dir_entry)); - -return 0 ; -} -/* Calculate short name checksum */ static __u8 mkcksum (const char name[8 ],const char ext[3 ]) {
@@ -573,169 +468,13 @@ static __u8 mkcksum(const char name[8], const char ext[3]) }/* -* Get the directory entry associated with 'filename' from the directory -* starting at 'startsect' +* TODO these should go away once fat_write is reworked to use the +* directory iterator */ __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) -{ -__u16 prevcksum =0xffff ; -__u32 curclust =START (retdent); -int files =0 , dirs =0 ; - -debug ("get_dentfromdir: %s\n" , filename); - -while (1 ) { -dir_entry *dentptr; - -int i; - -if (get_cluster (mydata, curclust, get_dentfromdir_block, - mydata->clust_size * mydata->sect_size) !=0 ) { -debug ("Error: reading directory block\n" ); -return NULL ; - } - - dentptr = (dir_entry *)get_dentfromdir_block; - -for (i =0 ; i <DIRENTSPERCLUST ; i++) { -char s_name[14 ], l_name[VFAT_MAXLEN_BYTES ]; - - l_name[0 ] ='\0' ; -if (dentptr->name[0 ] ==DELETED_FLAG ) { - dentptr++; -continue ; - } -if ((dentptr->attr &ATTR_VOLUME )) { -if (vfat_enabled && - (dentptr->attr &ATTR_VFAT ) ==ATTR_VFAT && - (dentptr->name[0 ] &LAST_LONG_ENTRY_MASK )) { - prevcksum = ((dir_slot *)dentptr)->alias_checksum; -get_vfatname (mydata, curclust, - get_dentfromdir_block, - dentptr, l_name); -if (dols) { -int isdir; -char dirc; -int doit =0 ; - - isdir = (dentptr->attr &ATTR_DIR ); - -if (isdir) { - dirs++; - dirc ='/' ; - doit =1 ; - }else { - dirc =' ' ; -if (l_name[0 ] !=0 ) { - files++; - doit =1 ; - } - } -if (doit) { -if (dirc ==' ' ) { -printf (" %8u %s%c\n" , -FAT2CPU32 (dentptr->size), - l_name, - dirc); - }else { -printf (" %s%c\n" , - l_name, - dirc); - } - } - dentptr++; -continue ; - } -debug ("vfatname: |%s|\n" , l_name); - }else { -/* Volume label or VFAT entry */ - dentptr++; -continue ; - } - } -if (dentptr->name[0 ] ==0 ) { -if (dols) { -printf ("\n%d file(s), %d dir(s)\n\n" , - files, dirs); - } -debug ("Dentname == NULL - %d\n" , i); -return NULL ; - } -if (vfat_enabled) { -__u8 csum =mkcksum (dentptr->name, dentptr->ext); -if (dols && csum == prevcksum) { - prevcksum =0xffff ; - dentptr++; -continue ; - } - } - -get_name (dentptr, s_name); -if (dols) { -int isdir = (dentptr->attr &ATTR_DIR ); -char dirc; -int doit =0 ; - -if (isdir) { - dirs++; - dirc ='/' ; - doit =1 ; - }else { - dirc =' ' ; -if (s_name[0 ] !=0 ) { - files++; - doit =1 ; - } - } - -if (doit) { -if (dirc ==' ' ) { -printf (" %8u %s%c\n" , -FAT2CPU32 (dentptr->size), - s_name, dirc); - }else { -printf (" %s%c\n" , - s_name, dirc); - } - } - - dentptr++; -continue ; - } - -if (strcmp (filename, s_name) - &&strcmp (filename, l_name)) { -debug ("Mismatch: |%s|%s|\n" , s_name, l_name); - dentptr++; -continue ; - } - -memcpy (retdent, dentptr,sizeof (dir_entry)); - -debug ("DentName: %s" , s_name); -debug (", start: 0x%x" ,START (dentptr)); -debug (", size: 0x%x %s\n" , -FAT2CPU32 (dentptr->size), - (dentptr->attr &ATTR_DIR ) ?"(DIR)" :"" ); - -return retdent; - } - - curclust =get_fatent (mydata, curclust); -if (CHECK_CLUST (curclust, mydata->fatsize)) { -debug ("curclust: 0x%x\n" , curclust); -printf ("Invalid FAT entry\n" ); -return NULL ; - } - } - -return NULL ; -} +__u8 do_fat_read_at_block[MAX_CLUSTSIZE ] +__aligned(ARCH_DMA_MINALIGN) ;/* * Read boot sector and volume info from a FAT filesystem
@@ -879,374 +618,6 @@ static int get_fs_info(fsdata *mydata)return 0 ; } -__u8 do_fat_read_at_block[MAX_CLUSTSIZE ] -__aligned(ARCH_DMA_MINALIGN) ; - -int do_fat_read_at (const char *filename,loff_t pos,void *buffer, -loff_t maxsize,int dols,int dogetsize,loff_t *size) -{ -char fnamecopy[2048 ]; -fsdata datablock; -fsdata *mydata = &datablock; -dir_entry *dentptr =NULL ; -__u16 prevcksum =0xffff ; -char *subname ="" ; -__u32 cursect; -int idx, isdir =0 ; -int files =0 , dirs =0 ; -int ret =-1 ; -int firsttime; -__u32 root_cluster =0 ; -__u32 read_blk; -int rootdir_size =0 ; -int buffer_blk_cnt; -int do_read; -__u8 *dir_ptr; - -if (get_fs_info (mydata)) -return -1 ; - - cursect = mydata->rootdir_sect; - -/* "cwd" is always the root... */ -while (ISDIRDELIM (*filename)) - filename++; - -/* Make a copy of the filename and convert it to lowercase */ -strcpy (fnamecopy, filename); -downcase (fnamecopy); - -root_reparse: -if (*fnamecopy =='\0' ) { -if (!dols) - goto exit; - - dols =LS_ROOT ; - }else if ((idx =dirdelim (fnamecopy)) >=0 ) { - isdir =1 ; - fnamecopy[idx] ='\0' ; - subname = fnamecopy + idx +1 ; - -/* Handle multiple delimiters */ -while (ISDIRDELIM (*subname)) - subname++; - }else if (dols) { - isdir =1 ; - } - - buffer_blk_cnt =0 ; - firsttime =1 ; -while (1 ) { -int i; - -if (mydata->fatsize ==32 || firsttime) { - dir_ptr = do_fat_read_at_block; - firsttime =0 ; - }else { -/** -* FAT16 sector buffer modification: -* Each loop, the second buffered block is moved to -* the buffer begin, and two next sectors are read -* next to the previously moved one. So the sector -* buffer keeps always 3 sectors for fat16. -* And the current sector is the buffer second sector -* beside the "firsttime" read, when it is the first one. -* -* PREFETCH_BLOCKS is 2 for FAT16 == loop[0:1] -* n = computed root dir sector -* loop | cursect-1 | cursect | cursect+1 | -* 0 | sector n+0 | sector n+1 | none | -* 1 | none | sector n+0 | sector n+1 | -* 0 | sector n+1 | sector n+2 | sector n+3 | -* 1 | sector n+3 | ... -*/ - dir_ptr = (do_fat_read_at_block + mydata->sect_size); -memcpy (do_fat_read_at_block, dir_ptr, mydata->sect_size); - } - - do_read =1 ; - -if (mydata->fatsize ==32 && buffer_blk_cnt) - do_read =0 ; - -if (do_read) { - read_blk = (mydata->fatsize ==32 ) ? - mydata->clust_size :PREFETCH_BLOCKS ; - -debug ("FAT read(sect=%d, cnt:%d), clust_size=%d, DIRENTSPERBLOCK=%zd\n" , - cursect, read_blk, mydata->clust_size,DIRENTSPERBLOCK ); - -if (disk_read (cursect, read_blk, dir_ptr) <0 ) { -debug ("Error: reading rootdir block\n" ); - goto exit; - } - - dentptr = (dir_entry *)dir_ptr; - } - -for (i =0 ; i <DIRENTSPERBLOCK ; i++) { -char s_name[14 ], l_name[VFAT_MAXLEN_BYTES ]; -__u8 csum; - - l_name[0 ] ='\0' ; -if (dentptr->name[0 ] ==DELETED_FLAG ) { - dentptr++; -continue ; - } - -if (vfat_enabled) - csum =mkcksum (dentptr->name, dentptr->ext); - -if (dentptr->attr &ATTR_VOLUME ) { -if (vfat_enabled && - (dentptr->attr &ATTR_VFAT ) ==ATTR_VFAT && - (dentptr->name[0 ] &LAST_LONG_ENTRY_MASK )) { - prevcksum = - ((dir_slot *)dentptr)->alias_checksum; - -get_vfatname (mydata, - root_cluster, - dir_ptr, - dentptr, l_name); - -if (dols ==LS_ROOT ) { -char dirc; -int doit =0 ; -int isdir = - (dentptr->attr &ATTR_DIR ); - -if (isdir) { - dirs++; - dirc ='/' ; - doit =1 ; - }else { - dirc =' ' ; -if (l_name[0 ] !=0 ) { - files++; - doit =1 ; - } - } -if (doit) { -if (dirc ==' ' ) { -printf (" %8u %s%c\n" , -FAT2CPU32 (dentptr->size), - l_name, - dirc); - }else { -printf (" %s%c\n" , - l_name, - dirc); - } - } - dentptr++; -continue ; - } -debug ("Rootvfatname: |%s|\n" , - l_name); - }else { -/* Volume label or VFAT entry */ - dentptr++; -continue ; - } - }else if (dentptr->name[0 ] ==0 ) { -debug ("RootDentname == NULL - %d\n" , i); -if (dols ==LS_ROOT ) { -printf ("\n%d file(s), %d dir(s)\n\n" , - files, dirs); - ret =0 ; - } - goto exit; - } -else if (vfat_enabled && - dols ==LS_ROOT && csum == prevcksum) { - prevcksum =0xffff ; - dentptr++; -continue ; - } - -get_name (dentptr, s_name); - -if (dols ==LS_ROOT ) { -int isdir = (dentptr->attr &ATTR_DIR ); -char dirc; -int doit =0 ; - -if (isdir) { - dirc ='/' ; -if (s_name[0 ] !=0 ) { - dirs++; - doit =1 ; - } - }else { - dirc =' ' ; -if (s_name[0 ] !=0 ) { - files++; - doit =1 ; - } - } -if (doit) { -if (dirc ==' ' ) { -printf (" %8u %s%c\n" , -FAT2CPU32 (dentptr->size), - s_name, dirc); - }else { -printf (" %s%c\n" , - s_name, dirc); - } - } - dentptr++; -continue ; - } - -if (strcmp (fnamecopy, s_name) - &&strcmp (fnamecopy, l_name)) { -debug ("RootMismatch: |%s|%s|\n" , s_name, - l_name); - dentptr++; -continue ; - } - -if (isdir && !(dentptr->attr &ATTR_DIR )) - goto exit; - -debug ("RootName: %s" , s_name); -debug (", start: 0x%x" ,START (dentptr)); -debug (", size: 0x%x %s\n" , -FAT2CPU32 (dentptr->size), - isdir ?"(DIR)" :"" ); - - goto rootdir_done;/* We got a match */ - } -debug ("END LOOP: buffer_blk_cnt=%d clust_size=%d\n" , buffer_blk_cnt, - mydata->clust_size); - -/* -* On FAT32 we must fetch the FAT entries for the next -* root directory clusters when a cluster has been -* completely processed. -*/ - ++buffer_blk_cnt; -int rootdir_end =0 ; -if (mydata->fatsize ==32 ) { -if (buffer_blk_cnt == mydata->clust_size) { -int nxtsect =0 ; -int nxt_clust =0 ; - - nxt_clust =get_fatent (mydata, root_cluster); - rootdir_end =CHECK_CLUST (nxt_clust,32 ); - - nxtsect = mydata->data_begin + - (nxt_clust * mydata->clust_size); - - root_cluster = nxt_clust; - - cursect = nxtsect; - buffer_blk_cnt =0 ; - } - }else { -if (buffer_blk_cnt ==PREFETCH_BLOCKS ) - buffer_blk_cnt =0 ; - - rootdir_end = (++cursect - mydata->rootdir_sect >= - rootdir_size); - } - -/* If end of rootdir reached */ -if (rootdir_end) { -if (dols ==LS_ROOT ) { -printf ("\n%d file(s), %d dir(s)\n\n" , - files, dirs); - *size =0 ; - } - goto exit; - } - } -rootdir_done: - - firsttime =1 ; - -while (isdir) { -int startsect = mydata->data_begin - +START (dentptr) * mydata->clust_size; -dir_entry dent; -char *nextname =NULL ; - - dent = *dentptr; - dentptr = &dent; - - idx =dirdelim (subname); - -if (idx >=0 ) { - subname[idx] ='\0' ; - nextname = subname + idx +1 ; -/* Handle multiple delimiters */ -while (ISDIRDELIM (*nextname)) - nextname++; -if (dols && *nextname =='\0' ) - firsttime =0 ; - }else { -if (dols && firsttime) { - firsttime =0 ; - }else { - isdir =0 ; - } - } - -if (get_dentfromdir (mydata, startsect, subname, dentptr, - isdir ?0 : dols) ==NULL ) { -if (dols && !isdir) - *size =0 ; - goto exit; - } - -if (isdir && !(dentptr->attr &ATTR_DIR )) - goto exit; - -/* -* If we are looking for a directory, and found a directory -* type entry, and the entry is for the root directory (as -* denoted by a cluster number of 0), jump back to the start -* of the function, since at least on FAT12/16, the root dir -* lives in a hard-coded location and needs special handling -* to parse, rather than simply following the cluster linked -* list in the FAT, like other directories. -*/ -if (isdir && (dentptr->attr &ATTR_DIR ) && !START (dentptr)) { -/* -* Modify the filename to remove the prefix that gets -* back to the root directory, so the initial root dir -* parsing code can continue from where we are without -* confusion. -*/ -strcpy (fnamecopy, nextname ?:"" ); -/* -* Set up state the same way as the function does when -* first started. This is required for the root dir -* parsing code operates in its expected environment. -*/ - subname ="" ; - cursect = mydata->rootdir_sect; - isdir =0 ; - goto root_reparse; - } - -if (idx >=0 ) - subname = nextname; - } - -if (dogetsize) { - *size =FAT2CPU32 (dentptr->size); - ret =0 ; - }else { - ret =get_contents (mydata, dentptr, pos, buffer, maxsize, size); - } -debug ("Size: %u, got: %llu\n" ,FAT2CPU32 (dentptr->size), *size); - -exit: -free (mydata->fatbuf); -return ret; -} -/* * Directory iterator, to simplify filesystem traversal
@@ -1595,12 +966,6 @@ static int fat_itr_resolve(fat_itr *itr, const char *path, unsigned type)return -ENOENT ; } -int do_fat_read (const char *filename,void *buffer,loff_t maxsize,int dols, -loff_t *actread) -{ -return do_fat_read_at (filename,0 , buffer, maxsize, dols,0 , actread); -} -int file_fat_detectfs (void ) {boot_sector bs;
@@ -1665,31 +1030,96 @@ int file_fat_detectfs(void)int file_fat_ls (const char *dir) { -loff_t size; +fsdata fsdata; +fat_itr itrblock, *itr = &itrblock; +int files =0 , dirs =0 ; +int ret; + + ret =fat_itr_root (itr, &fsdata); +if (ret) +return ret; + + ret =fat_itr_resolve (itr, dir,TYPE_DIR ); +if (ret) +return ret; + +while (fat_itr_next (itr)) { +if (fat_itr_isdir (itr)) { +printf (" %s/\n" , itr->name); + dirs++; + }else { +printf (" %8u %s\n" , +FAT2CPU32 (itr->dent->size), + itr->name); + files++; + } + } -return do_fat_read (dir,NULL ,0 ,LS_YES , &size); +printf ("\n%d file(s), %d dir(s)\n\n" , files, dirs); + +return 0 ; }int fat_exists (const char *filename) { +fsdata fsdata; +fat_itr itrblock, *itr = &itrblock;int ret; -loff_t size; - ret =do_fat_read_at (filename,0 ,NULL ,0 ,LS_NO ,1 , &size); + ret =fat_itr_root (itr, &fsdata); +if (ret) +return 0 ; + + ret =fat_itr_resolve (itr, filename,TYPE_ANY );return ret ==0 ; }int fat_size (const char *filename,loff_t *size) { -return do_fat_read_at (filename,0 ,NULL ,0 ,LS_NO ,1 , size); +fsdata fsdata; +fat_itr itrblock, *itr = &itrblock; +int ret; + + ret =fat_itr_root (itr, &fsdata); +if (ret) +return ret; + + ret =fat_itr_resolve (itr, filename,TYPE_FILE ); +if (ret) { +/* +* Directories don't have size, but fs_size() is not +* expected to fail if passed a directory path: +*/ +fat_itr_root (itr, &fsdata); +if (!fat_itr_resolve (itr, filename,TYPE_DIR )) { + *size =0 ; +return 0 ; + } +return ret; + } + + *size =FAT2CPU32 (itr->dent->size); + +return 0 ; }int file_fat_read_at (const char *filename,loff_t pos,void *buffer,loff_t maxsize,loff_t *actread) { +fsdata fsdata; +fat_itr itrblock, *itr = &itrblock; +int ret; + + ret =fat_itr_root (itr, &fsdata); +if (ret) +return ret; + + ret =fat_itr_resolve (itr, filename,TYPE_FILE ); +if (ret) +return ret; +printf ("reading %s\n" , filename); -return do_fat_read_at (filename, pos, buffer, maxsize,LS_NO ,0 , - actread); +return get_contents (&fsdata, itr->dent, pos, buffer, maxsize, actread); }int file_fat_read (const char *filename,void *buffer,int maxsize)
include/fat.h +0 -6
@@ -58,12 +58,6 @@*/ #define LAST_LONG_ENTRY_MASK 0x40 -/* 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 ISDIRDELIM (c) ((c) == '/' || (c) == '\\')#define FSTYPE_NONE (-1)
Signature · 1 line
2.13.5
PATCH v2 4/21 efi: add some more device path structures
In reply to Rob ClarkFrom: Peter Jones <[email protected]>
--- include/efi_api.h | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+)
include/efi_api.h +54 -0
@@ -290,8 +290,38 @@ struct efi_mac_addr {u8 addr[32 ]; } __packed; +#define DEVICE_PATH_TYPE_HARDWARE_DEVICE 0x01 +# define DEVICE_PATH_SUB_TYPE_VENDOR 0x04 + +struct efi_device_path_vendor { +struct efi_device_path dp; +efi_guid_t guid; +u8 vendor_data[]; +} __packed; + +#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;
@@ -299,9 +329,33 @@ struct efi_device_path_mac_addr {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 ];
Signature · 1 line
2.13.5
PATCH v2 4/21 efi: add some more device path structures
Quoted 7 lines · Rob Clark
From: Peter Jones <[email protected]>
Signed-off-by Peter Jones <[email protected]>Signed-off-by Rob Clark <[email protected]>--- include/efi_api.h | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+)
PATCH v3 4/9 fs: add fs_readdir()
In reply to Rob ClarkNeeded 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.
Modelled after POSIX opendir()/readdir()/closedir(). Unlike the other fs APIs, this is stateful (ie. state is held in the FS_DIR "directory stream"), to avoid re-traversing of the directory structure at each step. The directory stream must be released with closedir() when it is no longer needed.
--- disk/part.c | 31 ++++++++++------- fs/fs.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ include/fs.h | 67 +++++++++++++++++++++++++++++++++++++ include/part.h | 9 +++++ 4 files changed, 199 insertions(+), 12 deletions(-)
disk/part.c +19 -12
@@ -331,6 +331,24 @@ int part_get_info(struct blk_desc *dev_desc, int part,return -1 ; } +int part_get_info_whole_disk (struct blk_desc *dev_desc,disk_partition_t *info) +{ + info->start =0 ; + info->size = dev_desc->lba; + info->blksz = dev_desc->blksz; + info->bootable =0 ; +strcpy ((char *)info->type,BOOT_PART_TYPE ); +strcpy ((char *)info->name,"Whole Disk" ); +#if CONFIG_IS_ENABLED (PARTITION_UUIDS ) + info->uuid[0 ] =0 ; +#endif +#ifdef CONFIG_PARTITION_TYPE_GUID + info->type_guid[0 ] =0 ; +#endif + +return 0 ; +} +int blk_get_device_by_str (const char *ifname,const char *dev_hwpart_str,struct blk_desc **dev_desc) {
@@ -523,18 +541,7 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str, (*dev_desc)->log2blksz =LOG2 ((*dev_desc)->blksz); - info->start =0 ; - info->size = (*dev_desc)->lba; - info->blksz = (*dev_desc)->blksz; - info->bootable =0 ; -strcpy ((char *)info->type,BOOT_PART_TYPE ); -strcpy ((char *)info->name,"Whole Disk" ); -#if CONFIG_IS_ENABLED (PARTITION_UUIDS ) - info->uuid[0 ] =0 ; -#endif -#ifdef CONFIG_PARTITION_TYPE_GUID - info->type_guid[0 ] =0 ; -#endif +part_get_info_whole_disk (*dev_desc, info); ret =0 ; goto cleanup;
fs/fs.c +104 -0
164 lines not on this page · raw message
include/fs.h +67 -0
79 lines not on this page · raw message
include/part.h +9 -0
@@ -98,6 +98,12 @@ int host_get_dev_err(int dev, struct blk_desc **blk_devp);/* disk/part.c */ int part_get_info (struct blk_desc *dev_desc,int part,disk_partition_t *info); +/** +* part_get_info_whole_disk() - get partition info for the special case of +* a partition occupying the entire disk. +*/ +int part_get_info_whole_disk (struct blk_desc *dev_desc,disk_partition_t *info); +void part_print (struct blk_desc *dev_desc);void part_init (struct blk_desc *dev_desc);void dev_print (struct blk_desc *dev_desc);
@@ -203,6 +209,9 @@ static inline struct blk_desc *mg_disk_get_dev(int dev) { return NULL; }static inline int part_get_info (struct blk_desc *dev_desc,int part,disk_partition_t *info) {return -1 ; } +static inline int part_get_info_whole_disk (struct blk_desc *dev_desc, +disk_partition_t *info) +{return -1 ; }static inline void part_print (struct blk_desc *dev_desc) {}static inline void part_init (struct blk_desc *dev_desc) {}static inline void dev_print (struct blk_desc *dev_desc) {}
Signature · 1 line
2.13.5
PATCH v2 5/21 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 | 26 ++ lib/efi_loader/Makefile | 2 +- lib/efi_loader/efi_boottime.c | 13 +- lib/efi_loader/efi_device_path.c | 563 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 611 insertions(+), 3 deletions(-) create mode 100644 lib/efi_loader/efi_device_path.c
include/efi_api.h +10 -0
@@ -314,6 +314,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
@@ -329,6 +330,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 +26 -0
@@ -197,6 +197,32 @@ extern void *efi_bounce_buffer;#define EFI_LOADER_BOUNCE_BUFFER_SIZE (64 * 1024 * 1024)#endif + +struct efi_device_path *efi_dp_next (const 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, +struct efi_device_path **rem); +unsigned efi_dp_size (const struct efi_device_path *dp); +struct efi_device_path *efi_dp_dup (const struct efi_device_path *dp); +struct efi_device_path *efi_dp_append (const struct efi_device_path *dp1, +const struct efi_device_path *dp2); +struct efi_device_path *efi_dp_append_node (const struct efi_device_path *dp, +const struct efi_device_path *node); + + +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_boottime.c +11 -2
@@ -665,8 +665,17 @@ static efi_status_t EFIAPI efi_locate_device_path(efi_guid_t *protocol,struct efi_device_path **device_path, efi_handle_t *device) { - EFI_ENTRY("%p, %p, %p", protocol, device_path, device); -return EFI_EXIT (EFI_NOT_FOUND ); + struct efi_object *efiobj; + +EFI_ENTRY ("%pUl, %p, %p" , protocol, device_path, device); + + efiobj =efi_dp_find_obj (*device_path, device_path); +if (!efiobj) +return EFI_EXIT (EFI_NOT_FOUND ); + + *device = efiobj->handle; + +return EFI_EXIT (EFI_SUCCESS ); }/* Collapses configuration table entries, removing index i */
lib/efi_loader/efi_device_path.c new file +563 -0
563 lines not on this page · raw message
Signature · 1 line
2.13.5
PATCH v2 5/21 efi_loader: add device-path utils
Hi Rob,
Quoted 8 lines · Rob Clark
Helpers to construct device-paths from devices, partitions, files, and for parsing and manipulating device-paths.
For non-legacy devices, this will use u-boot's device-model to construct device-paths which include bus hierarchy to construct device-paths. For legacy devices we still fake it, but slightly more convincingly.
Signed-off-by Rob Clark <[email protected]>
Quoted 8 lines
--- include/efi_api.h | 10 + include/efi_loader.h | 26 ++ lib/efi_loader/Makefile | 2 +- lib/efi_loader/efi_boottime.c | 13 +- lib/efi_loader/efi_device_path.c | 563 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 611 insertions(+), 3 deletions(-) create mode 100644 lib/efi_loader/efi_device_path.c
Since this is new code we should not need the ifdef CONFIG_BLK, DM_MMC, etc. here, right?
The deadline for CONFIG_BLK has been set as 2018.05.
Also can we add some simple unit tests for this code somewhere?
Regards,
Simon
PATCH v2 5/21 efi_loader: add device-path utils
Quoted 20 lines · Simon Glass
Hi Rob,
Quoted 8 lines · Rob Clark
Helpers to construct device-paths from devices, partitions, files, and for parsing and manipulating device-paths.
For non-legacy devices, this will use u-boot's device-model to construct device-paths which include bus hierarchy to construct device-paths. For legacy devices we still fake it, but slightly more convincingly.
Signed-off-by Rob Clark <[email protected]>Quoted 8 lines
--- include/efi_api.h | 10 + include/efi_loader.h | 26 ++ lib/efi_loader/Makefile | 2 +- lib/efi_loader/efi_boottime.c | 13 +- lib/efi_loader/efi_device_path.c | 563 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 611 insertions(+), 3 deletions(-) create mode 100644 lib/efi_loader/efi_device_path.c
Quoted 2 lines
Since this is new code we should not need the ifdef
CONFIG_BLK,DM_MMC, etc. here, right?
Alexander was pretty much against dropping support for legacy devices.. so I think we need that.
There are a bunch of different places where efi_loader can be cleaned up when we require DM..
Quoted 4 lines
The deadline for
CONFIG_BLKhas been set as 2018.05.Also can we add some simple unit tests for this code somewhere?
Getting some Shell.efi into the py tests would exercise this and a whole lot more. Although I think we need to add an aarch64 qemu device to travis?
BR,
-R
PATCH v3 5/9 fs/fat: implement opendir/readdir/closedir
In reply to Rob ClarkImplement the readdir interface using the directory iterators.
--- fs/fat/fat.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+)
fs/fat/fat.c +61 -0
@@ -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>
@@ -1146,6 +1147,66 @@ int fat_read_file(const char *filename, void *buf, loff_t offset, loff_t len,return ret; } +typedef struct { +struct fs_dir_stream parent; +struct fs_dirent dirent; +fsdata fsdata; +fat_itr itr; +}fat_dir ; + +int fat_opendir (const char *filename,struct fs_dir_stream **dirsp) +{ +fat_dir *dir =malloc (sizeof (*dir)); +int ret; + +if (!dir) +return -ENOMEM ; + + ret =fat_itr_root (&dir->itr, &dir->fsdata); +if (ret) + goto fail; + + ret =fat_itr_resolve (&dir->itr, filename,TYPE_DIR ); +if (ret) + goto fail; + + *dirsp = (struct fs_dir_stream *)dir; +return 0 ; + +fail: +free (dir); +return ret; +} + +int fat_readdir (struct fs_dir_stream *dirs,struct fs_dirent **dentp) +{ +fat_dir *dir = (fat_dir *)dirs; +struct fs_dirent *dent = &dir->dirent; + +if (!fat_itr_next (&dir->itr)) +return -ENOENT ; + +memset (dent,0 ,sizeof (*dent)); +strcpy (dent->name, dir->itr.name); + +if (fat_itr_isdir (&dir->itr)) { + dent->type =FS_DT_DIR ; + }else { + dent->type =FS_DT_REG ; + dent->size =FAT2CPU32 (dir->itr.dent->size); + } + + *dentp = dent; + +return 0 ; +} + +void fat_closedir (struct fs_dir_stream *dirs) +{ +fat_dir *dir = (fat_dir *)dirs; +free (dir); +} +void fat_close (void ) { }
Signature · 1 line
2.13.5
PATCH v2 6/21 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
@@ -487,22 +487,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.5
PATCH v3 6/9 fat/fs: remove a bunch of dead code
In reply to Rob ClarkSpotted by chance, when trying to remove file_fat_ls(), I noticed there were some dead users of the API.
--- fs/fat/Makefile | 4 -- fs/fat/file.c | 183 -------------------------------------------------------- include/fat.h | 20 ------- 3 files changed, 207 deletions(-) delete mode 100644 fs/fat/file.c
fs/fat/Makefile +0 -4
@@ -5,7 +5,3 @@ obj-$(CONFIG_FS_FAT) := fat.o obj-$(CONFIG_FAT_WRITE):= fat_write.o - -ifndef CONFIG_SPL_BUILD -obj-$(CONFIG_FS_FAT) += file.o -endif
fs/fat/file.c deleted +0 -183
183 lines not on this page · raw message
include/fat.h +0 -20
@@ -178,25 +178,6 @@ static inline u32 clust_to_sect(fsdata *fsdata, u32 clust)return fsdata->data_begin + clust * fsdata->clust_size; } -typedef int (file_detectfs_func )(void ); -typedef int (file_ls_func )(const char *dir); -typedef int (file_read_func )(const char *filename,void *buffer, -int maxsize); - -struct filesystem { -file_detectfs_func *detect; -file_ls_func *ls; -file_read_func *read; -const char name[12 ]; -}; - -/* FAT tables */ -file_detectfs_func file_fat_detectfs; -file_ls_func file_fat_ls; -file_read_func file_fat_read; - -/* Currently this doesn't check if the dir exists or is valid... */ -int file_cd (const char *path);int file_fat_detectfs (void );int file_fat_ls (const char *dir);int fat_exists (const char *filename);
@@ -204,7 +185,6 @@ int fat_size(const char *filename, loff_t *size);int file_fat_read_at (const char *filename,loff_t pos,void *buffer,loff_t maxsize,loff_t *actread);int file_fat_read (const char *filename,void *buffer,int maxsize); -const char *file_getfsname (int idx);int fat_set_blk_dev (struct blk_desc *rbdd,disk_partition_t *info);int fat_register_device (struct blk_desc *dev_desc,int part_no);
Signature · 1 line
2.13.5
PATCH v2 7/21 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 | 241 +++++++++++++++++++++++-------- 3 files changed, 181 insertions(+), 63 deletions(-)
include/efi_api.h +1 -0
@@ -304,6 +304,7 @@ struct efi_device_path_vendor {#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 +178 -63
260 lines not on this page · raw message
Signature · 1 line
2.13.5
PATCH v3 7/9 fat/fs: move ls to generic implementation
In reply to Rob ClarkAdd a generic implementation of 'ls' using opendir/readdir/closedir, and replace fat's custom implementation. Other filesystems should move to the generic implementation after they add opendir/readdir/closedir support.
--- fs/fat/fat.c | 32 -------------------------------- fs/fs.c | 35 +++++++++++++++++++++++++++++++++-- include/fat.h | 5 ++++- 3 files changed, 37 insertions(+), 35 deletions(-)
fs/fat/fat.c +0 -32
@@ -1029,38 +1029,6 @@ int file_fat_detectfs(void)return 0 ; } -int file_fat_ls (const char *dir) -{ -fsdata fsdata; -fat_itr itrblock, *itr = &itrblock; -int files =0 , dirs =0 ; -int ret; - - ret =fat_itr_root (itr, &fsdata); -if (ret) -return ret; - - ret =fat_itr_resolve (itr, dir,TYPE_DIR ); -if (ret) -return ret; - -while (fat_itr_next (itr)) { -if (fat_itr_isdir (itr)) { -printf (" %s/\n" , itr->name); - dirs++; - }else { -printf (" %8u %s\n" , -FAT2CPU32 (itr->dent->size), - itr->name); - files++; - } - } - -printf ("\n%d file(s), %d dir(s)\n\n" , files, dirs); - -return 0 ; -} -int fat_exists (const char *filename) {fsdata fsdata;
fs/fs.c +33 -2
@@ -37,6 +37,35 @@ static inline int fs_ls_unsupported(const char *dirname)return -1 ; } +/* generic implementation of ls in terms of opendir/readdir/closedir */ +__maybe_unused +static int fs_ls_generic (const char *dirname) +{ +struct fs_dir_stream *dirs; +struct fs_dirent *dent; +int nfiles =0 , ndirs =0 ; + + dirs =fs_opendir (dirname); +if (!dirs) +return -errno; + +while ((dent =fs_readdir (dirs))) { +if (dent->type ==FS_DT_DIR ) { +printf (" %s/\n" , dent->name); + ndirs++; + }else { +printf (" %8lld %s\n" , dent->size, dent->name); + nfiles++; + } + } + +fs_closedir (dirs); + +printf ("\n%d file(s), %d dir(s)\n\n" , nfiles, ndirs); + +return 0 ; +} +static inline int fs_exists_unsupported (const char *filename) {return 0 ;
@@ -123,7 +152,7 @@ static struct fstype_info fstypes[] = { .null_dev_desc_ok = false, .probe = fat_set_blk_dev, .close = fat_close, - .ls = file_fat_ls, + .ls = fs_ls_generic, .exists = fat_exists, .size = fat_size, .read = fat_read_file,
@@ -133,7 +162,9 @@ static struct fstype_info fstypes[] = { .write = fs_write_unsupported, #endif .uuid = fs_uuid_unsupported, - .opendir = fs_opendir_unsupported, + .opendir = fat_opendir, + .readdir = fat_readdir, + .closedir = fat_closedir, },#endif #ifdef CONFIG_FS_EXT4
include/fat.h +4 -1
@@ -11,6 +11,7 @@#define _FAT_H_#include <asm/byteorder.h> +#include <fs.h> #define CONFIG_SUPPORT_VFAT /* Maximum Long File Name length supported here is 128 UTF-16 code units */
@@ -179,7 +180,6 @@ static inline u32 clust_to_sect(fsdata *fsdata, u32 clust) }int file_fat_detectfs (void ); -int file_fat_ls (const char *dir);int fat_exists (const char *filename);int fat_size (const char *filename,loff_t *size); int file_fat_read_at(const char *filename, loff_t pos, void *buffer,
@@ -192,5 +192,8 @@ 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); +int fat_opendir (const char *filename,struct fs_dir_stream **dirsp); +int fat_readdir (struct fs_dir_stream *dirs,struct fs_dirent **dentp); +void fat_closedir (struct fs_dir_stream *dirs);void fat_close (void );#endif /* _FAT_H_ */
Signature · 1 line
2.13.5
PATCH v2 8/21 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.5
PATCH v3 8/9 fs/fat: fix case for FAT shortnames
In reply to Rob ClarkNoticed when comparing our output to linux. There are some lcase bits which control whether filename and/or extension should be downcase'd.
--- fs/fat/fat.c | 16 ++++++++++------ fs/fat/fat_write.c | 4 ++-- include/fat.h | 6 +++++- 3 files changed, 17 insertions(+), 9 deletions(-)
fs/fat/fat.c +10 -6
@@ -29,11 +29,13 @@ static const int vfat_enabled = 0;#endif /* -* Convert a string to lowercase. +* Convert a string to lowercase. Converts at most 'len' characters, +* 'len' may be larger than the length of 'str' if 'str' is NULL +* terminated. */ -static void downcase (char *str) +static void downcase (char *str,size_t len) { -while (*str !='\0' ) { +while (*str !='\0' && len--) { *str =tolower (*str); str++; }
@@ -131,10 +133,13 @@ static void get_name(dir_entry *dirent, char *s_name) ptr = s_name;while (*ptr && *ptr !=' ' ) ptr++; +if (dirent->lcase &CASE_LOWER_BASE ) +downcase (s_name, (unsigned )(ptr - s_name));if (dirent->ext[0 ] && dirent->ext[0 ] !=' ' ) { - *ptr ='.' ; - ptr++; + *ptr++ ='.' ;memcpy (ptr, dirent->ext,3 ); +if (dirent->lcase &CASE_LOWER_EXT ) +downcase (ptr,3 ); ptr[3 ] ='\0' ;while (*ptr && *ptr !=' ' ) ptr++;
@@ -144,7 +149,6 @@ static void get_name(dir_entry *dirent, char *s_name) *s_name ='\0' ; else if (*s_name == aRING) *s_name = DELETED_FLAG; -downcase (s_name); }static int flush_dirty_fat_buffer (fsdata *mydata);
fs/fat/fat_write.c +2 -2
@@ -345,7 +345,7 @@ get_long_file_name(fsdata *mydata, int curclust, __u8 *cluster, *l_name ='\0' ; else if (*l_name == aRING) *l_name = DELETED_FLAG; -downcase (l_name); +downcase (l_name,INT_MAX );/* Return the real directory entry */ *retdent = realdent;
@@ -981,7 +981,7 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size,memcpy (l_filename, filename, name_len); l_filename[name_len] =0 ;/* terminate the string */ -downcase (l_filename); +downcase (l_filename,INT_MAX ); startsect = mydata->rootdir_sect; retdent = find_directory_entry(mydata, startsect,
include/fat.h +5 -1
@@ -128,10 +128,14 @@ typedef struct volume_info/* Boot sign comes last, 2 bytes */ } volume_info; +/* see dir_entry::lcase: */ +#define CASE_LOWER_BASE 8/* base (name) is lower case */ +#define CASE_LOWER_EXT 16/* extension is lower case */ + typedef struct dir_entry { char name[8],ext[3]; /* Name and extension */ __u8 attr; /* Attribute bits */ - __u8 lcase; /* Case for base and extension */ + __u8 lcase; /* Case for name and ext (CASE_LOWER_x) */ __u8 ctime_ms; /* Creation time, milliseconds */ __u16 ctime; /* Creation time */ __u16 cdate; /* Creation date */
Signature · 1 line
2.13.5
PATCH v2 9/21 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.5
PATCH v3 9/9 fs/fat: Clean up open-coded sector <-> cluster conversions
In reply to Rob ClarkUse the clust_to_sect() helper that was introduced earlier, and add an inverse sect_to_clust(), plus update the various spots that open-coded this conversion previously.
--- fs/fat/fat.c | 8 +++----- fs/fat/fat_write.c | 8 +++----- include/fat.h | 6 +++++- 3 files changed, 11 insertions(+), 11 deletions(-)
fs/fat/fat.c +3 -5
@@ -257,8 +257,7 @@ get_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer, unsigned long size)int ret;if (clustnum >0 ) { - startsect = mydata->data_begin + - clustnum * mydata->clust_size; + startsect =clust_to_sect (mydata, clustnum); }else { startsect = mydata->rootdir_sect; }
@@ -594,9 +593,8 @@ static int get_fs_info(fsdata *mydata) mydata->data_begin = mydata->rootdir_sect + mydata->rootdir_size - (mydata->clust_size *2 ); - mydata->root_cluster = (mydata->rootdir_sect - - mydata->data_begin) / - mydata->clust_size; + mydata->root_cluster = +sect_to_clust (mydata, mydata->rootdir_sect); } mydata->fatbufnum =-1 ;
fs/fat/fat_write.c +3 -5
@@ -502,8 +502,7 @@ set_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer,int ret;if (clustnum >0 ) - startsect = mydata->data_begin + - clustnum * mydata->clust_size; + startsect =clust_to_sect (mydata, clustnum);else startsect = mydata->rootdir_sect;
@@ -751,8 +750,7 @@ static int check_overflow(fsdata *mydata, __u32 clustnum, loff_t size)__u32 startsect, sect_num, offset;if (clustnum >0 ) { - startsect = mydata->data_begin + - clustnum * mydata->clust_size; + startsect =clust_to_sect (mydata, clustnum); }else { startsect = mydata->rootdir_sect; }
@@ -791,7 +789,7 @@ static dir_entry *empty_dentptr;static dir_entry *find_directory_entry (fsdata *mydata,int startsect,char *filename,dir_entry *retdent,__u32 start) { -__u32 curclust = (startsect - mydata->data_begin) / mydata->clust_size; +__u32 curclust =sect_to_clust (mydata, startsect);debug ("get_dentfromdir: %s\n" , filename);
include/fat.h +5 -1
@@ -177,12 +177,16 @@ typedef struct {__u32 root_cluster;/* First cluster of root dir for FAT32 */ } fsdata; -/* TODO clean up places that are open-coding this: */ static inline u32 clust_to_sect (fsdata *fsdata,u32 clust) {return fsdata->data_begin + clust * fsdata->clust_size; } +static inline u32 sect_to_clust (fsdata *fsdata,u32 sect) +{ +return (sect - fsdata->data_begin) / fsdata->clust_size; +} +int file_fat_detectfs (void );int fat_exists (const char *filename);int fat_size (const char *filename,loff_t *size);
Signature · 1 line
2.13.5
PATCH v2 10/21 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 | 36 ++++++++ lib/efi_loader/efi_net.c | 5 +- 4 files changed, 100 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
@@ -136,7 +136,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 );
@@ -193,6 +193,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); +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 +36 -0
@@ -726,6 +726,42 @@ 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_device_path_to_text; + + info->file_path = file_path; + info->device_handle =efi_dp_find_obj (device_path,NULL ); + +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.5
PATCH v2 11/21 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.
--- include/efi.h | 2 + include/efi_api.h | 65 +++++ include/efi_loader.h | 13 + lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_disk.c | 32 +++ lib/efi_loader/efi_file.c | 556 ++++++++++++++++++++++++++++++++++++++ lib/efi_loader/efi_image_loader.c | 3 + 7 files changed, 672 insertions(+) create mode 100644 lib/efi_loader/efi_file.c
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;
@@ -140,6 +142,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);
@@ -168,6 +173,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 */
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 +32 -0
@@ -31,6 +31,8 @@ struct efi_disk_obj {struct efi_device_path *dp;/* partition # */ unsigned part; +/* handle to filesys proto (for partition objects) */ +struct efi_simple_file_system_protocol *volume;/* Offset into disk for simple partitions */ lbaint_t offset;/* Internal block device */
@@ -172,6 +174,28 @@ static const struct efi_block_io block_io_disk_template = { .flush_blocks = &efi_disk_flush_blocks, }; +/* +* Find filesystem from a device-path. The passed in path 'p' probably +* contains one or more /File(name) nodes, so the comparison stops at +* the first /File() node, and returns the pointer to that via 'rp'. +* This is mostly intended to be a helper to map a device-path to an +* efi_file_handle object. +*/ +struct efi_simple_file_system_protocol * +efi_fs_from_path (struct efi_device_path *fp) +{ +struct efi_object *efiobj; +struct efi_disk_obj *diskobj; + + efiobj =efi_dp_find_obj (fp,NULL ); +if (!efiobj) +return NULL ; + + diskobj = container_of(efiobj, struct efi_disk_obj, parent); + +return diskobj->volume; +} + static void efi_disk_add_dev(const char *name, const char *if_typename, struct blk_desc *desc,
@@ -194,6 +218,14 @@ static void efi_disk_add_dev(const char *name, diskobj->parent.protocols[0 ].protocol_interface = &diskobj->ops; diskobj->parent.protocols[1 ].guid = &efi_guid_device_path; diskobj->parent.protocols[1 ].protocol_interface = diskobj->dp; +if (part >=1 ) { + diskobj->volume =efi_simple_file_system (desc, part, + diskobj->dp); + diskobj->parent.protocols[2 ].guid = + &efi_simple_file_system_protocol_guid; + diskobj->parent.protocols[2 ].protocol_interface = + diskobj->volume; + } diskobj->parent.handle = diskobj; diskobj->ops = block_io_disk_template; diskobj->ifname = if_typename;
lib/efi_loader/efi_file.c new file +556 -0
556 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.5
PATCH v2 11/21 efi_loader: add file/filesys support
Quoted 4 lines · Rob Clark
fallback.efi (and probably other things) use UEFI's simple-file-system protocol and file support to search for OS's to boot.
Signed-off-by Rob Clark <[email protected]>
Quoted 10 lines
--- include/efi.h | 2 + include/efi_api.h | 65 +++++ include/efi_loader.h | 13 + lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_disk.c | 32 +++ lib/efi_loader/efi_file.c | 556 ++++++++++++++++++++++++++++++++++++++ lib/efi_loader/efi_image_loader.c | 3 + 7 files changed, 672 insertions(+) create mode 100644 lib/efi_loader/efi_file.c
What does sanitize_path() do? Please add a comment.
How do we test all this code?
PATCH v2 12/21 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 | 85 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 70 insertions(+), 15 deletions(-)
lib/efi_loader/efi_boottime.c +70 -15
@@ -762,6 +762,47 @@ 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,
@@ -769,25 +810,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);
@@ -796,7 +852,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.5
PATCH v2 13/21 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 = (size +sizeof (struct efi_pool_allocation ) + +EFI_PAGE_MASK ) >>EFI_PAGE_SHIFT ;if (size ==0 ) { *buffer =NULL ;
Signature · 1 line
2.13.5
PATCH v2 14/21 efi_loader: efi variable support
In reply to Rob ClarkAdd EFI variable support, mapping to u-boot environment variables. Variables are pretty important for setting up boot order, among other things. If the board supports saveenv, then it will be called in ExitBootServices() to persist variables set by the efi payload. (For example, fallback.efi configuring BootOrder and BootXXXX load-option variables.)
Variables are *not* currently exposed at runtime, post ExitBootServices. On boards without a dedicated device for storage, which the loaded OS is not trying to also use, this is rather tricky. One idea, at least for boards that can persist RAM across reboot, is to keep a "journal" of modified variables in RAM, and then turn halt into a reboot into u-boot, plus store variables, plus halt. Whatever the solution, it likely involves some per-board support.
Mapping between EFI variables and u-boot variables:
efi_$guid_$varname = {attributes}(type)value
For example:
efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_OsIndicationsSupported=
"{ro,boot,run}(blob)0000000000000000"
efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_BootOrder=
"(blob)00010000"The attributes are a comma separated list of these possible attributes:
+ ro - read-only
+ boot - boot-services access
+ run - runtime access
NOTE: with current implementation, no variables are available after ExitBootServices, and all are persisted (if possible).
If not specified, the attributes default to "{boot}".
The required type is one of:
+ utf8 - raw utf8 string
+ blob - arbitrary length hex string
--- cmd/bootefi.c | 4 + include/efi.h | 19 +++ include/efi_loader.h | 10 ++ lib/efi_loader/Makefile | 2 +- lib/efi_loader/efi_boottime.c | 6 + lib/efi_loader/efi_runtime.c | 17 ++- lib/efi_loader/efi_variable.c | 335 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 388 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: */ +env_set ("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
@@ -277,6 +277,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 +6 -0
@@ -8,6 +8,7 @@#include <common.h> #include <efi_loader.h> +#include <environment.h> #include <malloc.h> #include <asm/global_data.h> #include <libfdt_env.h>
@@ -942,6 +943,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: */ +env_save (); +#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 +335 -0
335 lines not on this page · raw message
Signature · 1 line
2.13.5
PATCH v2 14/21 efi_loader: efi variable support
Hi Rob,
Quoted 44 lines · Rob Clark
Add EFI variable support, mapping to u-boot environment variables. Variables are pretty important for setting up boot order, among other things. If the board supports saveenv, then it will be called in
ExitBootServices()to persist variables set by the efi payload. (For example, fallback.efi configuring BootOrder and BootXXXX load-option variables.)Variables are *not* currently exposed at runtime, post ExitBootServices. On boards without a dedicated device for storage, which the loaded OS is not trying to also use, this is rather tricky. One idea, at least for boards that can persist RAM across reboot, is to keep a "journal" of modified variables in RAM, and then turn halt into a reboot into u-boot, plus store variables, plus halt. Whatever the solution, it likely involves some per-board support.
Mapping between EFI variables and u-boot variables:
efi_$guid_$varname = {attributes}(type)value
For example:
efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_OsIndicationsSupported=
"{ro,boot,run}(blob)0000000000000000" efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_BootOrder= "(blob)00010000"The attributes are a comma separated list of these possible attributes:
+ ro - read-only
+ boot - boot-services access
+ run - runtime accessNOTE: with current implementation, no variables are available after ExitBootServices, and all are persisted (if possible).
If not specified, the attributes default to "{boot}".
The required type is one of:
+ utf8 - raw utf8 string
+ blob - arbitrary length hex stringSigned-off-by Rob Clark <[email protected]>
Quoted 10 lines
--- cmd/bootefi.c | 4 + include/efi.h | 19 +++ include/efi_loader.h | 10 ++ lib/efi_loader/Makefile | 2 +- lib/efi_loader/efi_boottime.c | 6 + lib/efi_loader/efi_runtime.c | 17 ++- lib/efi_loader/efi_variable.c | 335 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 388 insertions(+), 5 deletions(-) create mode 100644 lib/efi_loader/efi_variable.c
What does hex2mem() do? Please add a comment
This code looks fine but we need a simple way to test it. I think Herinrich is working on a single hello world test. That could be enhanced to set and read variables.
PATCH v2 14/21 efi_loader: efi variable support
Quoted 58 lines · Simon Glass
Hi Rob,
Quoted 44 lines · Rob Clark
Add EFI variable support, mapping to u-boot environment variables. Variables are pretty important for setting up boot order, among other things. If the board supports saveenv, then it will be called in
ExitBootServices()to persist variables set by the efi payload. (For example, fallback.efi configuring BootOrder and BootXXXX load-option variables.)Variables are *not* currently exposed at runtime, post ExitBootServices. On boards without a dedicated device for storage, which the loaded OS is not trying to also use, this is rather tricky. One idea, at least for boards that can persist RAM across reboot, is to keep a "journal" of modified variables in RAM, and then turn halt into a reboot into u-boot, plus store variables, plus halt. Whatever the solution, it likely involves some per-board support.
Mapping between EFI variables and u-boot variables:
efi_$guid_$varname = {attributes}(type)value
For example:
efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_OsIndicationsSupported=
"{ro,boot,run}(blob)0000000000000000" efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_BootOrder= "(blob)00010000"The attributes are a comma separated list of these possible attributes:
+ ro - read-only
+ boot - boot-services access
+ run - runtime accessNOTE: with current implementation, no variables are available after ExitBootServices, and all are persisted (if possible).
If not specified, the attributes default to "{boot}".
The required type is one of:
+ utf8 - raw utf8 string
+ blob - arbitrary length hex stringSigned-off-by Rob Clark <[email protected]>Quoted 10 lines
--- cmd/bootefi.c | 4 + include/efi.h | 19 +++ include/efi_loader.h | 10 ++ lib/efi_loader/Makefile | 2 +- lib/efi_loader/efi_boottime.c | 6 + lib/efi_loader/efi_runtime.c | 17 ++- lib/efi_loader/efi_variable.c | 335 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 388 insertions(+), 5 deletions(-) create mode 100644 lib/efi_loader/efi_variable.c
Quoted 5 lines
What does
hex2mem()do? Please add a commentThis code looks fine but we need a simple way to test it. I think Herinrich is working on a single hello world test. That could be enhanced to set and read variables.
tbh, just starting Shell.efi, let alone launching SCT.efi, requires all of this stuff (filesys, variables, installing/removing protocols, etc) to be working
Getting shell.efi into travis and running a couple "simple" commands seems like a better option.
BR,
-R
PATCH v2 15/21 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;
@@ -209,6 +210,8 @@ efi_status_t efi_install_configuration_table(const efi_guid_t *guid, void *tablevoid 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;
@@ -287,6 +290,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
@@ -763,8 +763,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;
@@ -824,7 +824,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.5
PATCH v2 15/21 efi_loader: add bootmgr
Quoted 11 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.)
Signed-off-by Rob Clark <[email protected]>
Quoted 11 lines
--- 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
Please can you add function comments to your static functions?
PATCH v2 16/21 efi_loader: file_path should be variable length
In reply to Rob ClarkAfter "efi_loader: refactor boot device and loaded_image handling" we can drop this hack.
--- include/efi_api.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
include/efi_api.h +1 -1
@@ -373,7 +373,7 @@ struct efi_device_path_cdrom_path {struct efi_device_path_file_path {struct efi_device_path dp; -u16 str[32 ]; +u16 str[]; } __packed;#define BLOCK_IO_GUID \
Signature · 1 line
2.13.5
PATCH v2 17/21 efi_loader: set loaded image code/data type properly
In reply to Rob ClarkThese should be set according to the image type. Shell.efi and SCT.efi use these fields to determine what sort of image they are loading.
--- include/pe.h | 6 ++++++ lib/efi_loader/efi_image_loader.c | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+)
include/pe.h +6 -0
@@ -62,6 +62,12 @@ typedef struct _IMAGE_DATA_DIRECTORY {#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 +/* PE32+ Subsystem type for EFI images */ +#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 +#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 +#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 +#define IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER 13 + typedef struct _IMAGE_OPTIONAL_HEADER64 { uint16_t Magic; /* 0x20b */ uint8_t MajorLinkerVersion;
lib/efi_loader/efi_image_loader.c +22 -0
@@ -94,6 +94,7 @@ void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info)unsigned long virt_size =0 ;bool can_run_nt64 = true;bool can_run_nt32 = true; +uint16_t image_type;#if defined(CONFIG_ARM64 ) can_run_nt32 = false;
@@ -139,6 +140,7 @@ void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info) entry = efi_reloc + opt->AddressOfEntryPoint; rel_size = opt->DataDirectory[rel_idx].Size; rel = efi_reloc + opt->DataDirectory[rel_idx].VirtualAddress; + image_type = opt->Subsystem; }else if (can_run_nt32 && (nt->OptionalHeader.Magic ==IMAGE_NT_OPTIONAL_HDR32_MAGIC )) {IMAGE_OPTIONAL_HEADER32 *opt = &nt->OptionalHeader;
@@ -152,12 +154,32 @@ void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info) entry = efi_reloc + opt->AddressOfEntryPoint; rel_size = opt->DataDirectory[rel_idx].Size; rel = efi_reloc + opt->DataDirectory[rel_idx].VirtualAddress; + image_type = opt->Subsystem; }else {printf ("%s: Invalid optional header magic %x\n" , __func__, nt->OptionalHeader.Magic);return NULL ; } +switch (image_type) { +case IMAGE_SUBSYSTEM_EFI_APPLICATION : + loaded_image_info->image_code_type =EFI_LOADER_CODE ; + loaded_image_info->image_data_type =EFI_LOADER_DATA ; +break ; +case IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER : + loaded_image_info->image_code_type =EFI_BOOT_SERVICES_CODE ; + loaded_image_info->image_data_type =EFI_BOOT_SERVICES_DATA ; +break ; +case IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER : +case IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER : + loaded_image_info->image_code_type =EFI_RUNTIME_SERVICES_CODE ; + loaded_image_info->image_data_type =EFI_RUNTIME_SERVICES_DATA ; +break ; +default : +printf ("%s: invalid image type: %u\n" , __func__, image_type); +break ; + } +/* Load sections into RAM */ for (i = num_sections -1 ; i >=0 ; i--) {IMAGE_SECTION_HEADER *sec = §ions[i];
Signature · 1 line
2.13.5
PATCH v2 18/21 efi_loader: print GUIDs
In reply to Rob ClarkUtilize printf GUID support to print GUIDs.
--- lib/efi_loader/efi_boottime.c | 22 +++++++++++----------- lib/efi_loader/efi_variable.c | 6 +++--- 2 files changed, 14 insertions(+), 14 deletions(-)
lib/efi_loader/efi_boottime.c +11 -11
@@ -514,7 +514,7 @@ static efi_status_t EFIAPI efi_install_protocol_interface_ext(void **handle, efi_guid_t *protocol, int protocol_interface_type, void *protocol_interface) { - EFI_ENTRY("%p, %p, %d, %p", handle, protocol, protocol_interface_type, + EFI_ENTRY("%p, %pUl, %d, %p", handle, protocol, protocol_interface_type, protocol_interface); return EFI_EXIT(efi_install_protocol_interface(handle, protocol,
@@ -526,7 +526,7 @@ static efi_status_t EFIAPI efi_reinstall_protocol_interface(void *handle, efi_guid_t *protocol, void *old_interface, void *new_interface) { -EFI_ENTRY ("%p, %p, %p, %p" , handle, protocol, old_interface, +EFI_ENTRY ("%p, %pUl, %p, %p" , handle, protocol, old_interface, new_interface);return EFI_EXIT (EFI_ACCESS_DENIED ); }
@@ -575,7 +575,7 @@ out: static efi_status_t EFIAPI efi_uninstall_protocol_interface_ext(void *handle,efi_guid_t *protocol,void *protocol_interface) { -EFI_ENTRY ("%p, %p, %p" , handle, protocol, protocol_interface); +EFI_ENTRY ("%p, %pUl, %p" , handle, protocol, protocol_interface);return EFI_EXIT (efi_uninstall_protocol_interface (handle, protocol, protocol_interface));
@@ -585,7 +585,7 @@ static efi_status_t EFIAPI efi_register_protocol_notify(efi_guid_t *protocol, struct efi_event *event, void **registration) { - EFI_ENTRY("%p, %p, %p", protocol, event, registration); + EFI_ENTRY("%pUl, %p, %p", protocol, event, registration);return EFI_EXIT (EFI_OUT_OF_RESOURCES ); }
@@ -655,7 +655,7 @@ static efi_status_t EFIAPI efi_locate_handle_ext( efi_guid_t *protocol, void *search_key, unsigned long *buffer_size, efi_handle_t *buffer) { -EFI_ENTRY ("%d, %p, %p, %p, %p" , search_type, protocol, search_key, +EFI_ENTRY ("%d, %pUl, %p, %p, %p" , search_type, protocol, search_key, buffer_size, buffer); return EFI_EXIT(efi_locate_handle(search_type, protocol, search_key,
@@ -723,7 +723,7 @@ efi_status_t efi_install_configuration_table(const efi_guid_t *guid, void *table static efi_status_t EFIAPI efi_install_configuration_table_ext(efi_guid_t *guid,void *table) { -EFI_ENTRY ("%p, %p" , guid, table); +EFI_ENTRY ("%pUl, %p" , guid, table);return EFI_EXIT (efi_install_configuration_table (guid, table)); }
@@ -1012,7 +1012,7 @@ static efi_status_t EFIAPI efi_close_protocol(void *handle, void *agent_handle, void *controller_handle) { - EFI_ENTRY("%p, %p, %p, %p", handle, protocol, agent_handle, + EFI_ENTRY("%p, %pUl, %p, %p", handle, protocol, agent_handle, controller_handle);return EFI_EXIT (EFI_NOT_FOUND ); }
@@ -1022,7 +1022,7 @@ static efi_status_t EFIAPI efi_open_protocol_information(efi_handle_t handle, struct efi_open_protocol_info_entry **entry_buffer, unsigned long *entry_count) { - EFI_ENTRY("%p, %p, %p, %p", handle, protocol, entry_buffer, + EFI_ENTRY("%p, %pUl, %p, %p", handle, protocol, entry_buffer, entry_count);return EFI_EXIT (EFI_NOT_FOUND ); }
@@ -1088,7 +1088,7 @@ static efi_status_t EFIAPI efi_locate_handle_buffer(efi_status_t r;unsigned long buffer_size =0 ; -EFI_ENTRY ("%d, %p, %p, %p, %p" , search_type, protocol, search_key, +EFI_ENTRY ("%d, %pUl, %p, %p, %p" , search_type, protocol, search_key, no_handles, buffer);if (!no_handles || !buffer) {
@@ -1120,7 +1120,7 @@ static efi_status_t EFIAPI efi_locate_protocol(efi_guid_t *protocol,struct list_head *lhandle;int i; -EFI_ENTRY ("%p, %p, %p" , protocol, registration, protocol_interface); +EFI_ENTRY ("%pUl, %p, %p" , protocol, registration, protocol_interface);if (!protocol || !protocol_interface)return EFI_EXIT (EFI_INVALID_PARAMETER );
@@ -1228,7 +1228,7 @@ static efi_status_t EFIAPI efi_open_protocol(int i;efi_status_t r =EFI_INVALID_PARAMETER ; -EFI_ENTRY ("%p, %p, %p, %p, %p, 0x%x" , handle, protocol, +EFI_ENTRY ("%p, %pUl, %p, %p, %p, 0x%x" , handle, protocol, protocol_interface, agent_handle, controller_handle, attributes);
lib/efi_loader/efi_variable.c +3 -3
@@ -187,7 +187,7 @@ efi_status_t EFIAPI efi_get_variable(s16 *variable_name,const char *val, *s;u32 attr; -EFI_ENTRY ("%p %p %p %p %p" , variable_name, vendor, attributes, +EFI_ENTRY ("\"%ls\" %pUl %p %p %p" , variable_name, vendor, attributes, data_size, data);if (!variable_name || !vendor || !data_size)
@@ -255,7 +255,7 @@ efi_status_t EFIAPI efi_get_next_variable(unsigned long *variable_name_size, s16 *variable_name, efi_guid_t *vendor) { - EFI_ENTRY("%p %p %p", variable_name_size, variable_name, vendor); + EFI_ENTRY("%p \"%ls\" %pUl", variable_name_size, variable_name, vendor);return EFI_EXIT (EFI_DEVICE_ERROR ); }
@@ -270,7 +270,7 @@ efi_status_t EFIAPI efi_set_variable(s16 *variable_name,char *val, *s;u32 attr; -EFI_ENTRY ("%p %p %x %lu %p" , variable_name, vendor, attributes, +EFI_ENTRY ("\"%ls\" %pUl %x %lu %p" , variable_name, vendor, attributes, data_size, data);if (!variable_name || !vendor)
Signature · 1 line
2.13.5
PATCH v2 19/21 efi_loader: split out escape sequence based size query
In reply to Rob ClarkWe need to do something different for vidconsole, since it cannot respond to the query on stdin. Prep work for next patch.
--- lib/efi_loader/efi_console.c | 53 +++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 23 deletions(-)
lib/efi_loader/efi_console.c +30 -23
@@ -186,6 +186,34 @@ static bool cout_mode_matches(struct cout_mode *mode, int rows, int cols)return (mode->rows == rows) && (mode->columns == cols); } +static int query_console_serial (int *rows,int *cols) +{ +/* Ask the terminal about its size */ +int n[3 ]; +u64 timeout; + +/* Empty input buffer */ +while (tstc ()) +getc (); + +printf (ESC "[18t" ); + +/* Check if we have a terminal that understands */ + timeout =timer_get_us () +1000000 ; +while (!tstc ()) +if (timer_get_us () > timeout) +return -1 ; + +/* Read {depth,rows,cols} */ +if (term_read_reply (n,3 ,'t' )) +return -1 ; + + *cols = n[2 ]; + *rows = n[1 ]; + +return 0 ; +} + static efi_status_t EFIAPI efi_cout_query_mode( struct efi_simple_text_output_protocol *this, unsigned long mode_number, unsigned long *columns,
@@ -194,33 +222,12 @@ static efi_status_t EFIAPI efi_cout_query_mode(EFI_ENTRY ("%p, %ld, %p, %p" , this, mode_number, columns, rows);if (!console_size_queried) { -/* Ask the terminal about its size */ -int n[3 ]; -int cols; -int rows; -u64 timeout; +int rows, cols; console_size_queried = true; -/* Empty input buffer */ -while (tstc ()) -getc (); - -printf (ESC "[18t" ); - -/* Check if we have a terminal that understands */ - timeout =timer_get_us () +1000000 ; -while (!tstc ()) -if (timer_get_us () > timeout) - goto out; - -/* Read {depth,rows,cols} */ -if (term_read_reply (n,3 ,'t' )) { +if (query_console_serial (&rows, &cols)) goto out; - } - - cols = n[2 ]; - rows = n[1 ];/* Test if we can have Mode 1 */ if (cols >=80 && rows >=50 ) {
Signature · 1 line
2.13.5
PATCH v2 20/21 efi_loader: Correctly figure out size for vidconsole
In reply to Rob ClarkIf stdout is vidconsole, we cannot rely on ANSI escape sequences to query the size, as vidconsole cannot reply on stdin. Instead special- case this if stdout is vidconsole.
--- lib/efi_loader/efi_console.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)
lib/efi_loader/efi_console.c +15 -1
@@ -8,7 +8,10 @@#include <common.h> #include <charset.h> +#include <dm/device.h> #include <efi_loader.h> +#include <stdio_dev.h> +#include <video_console.h> static bool console_size_queried;
@@ -222,12 +225,23 @@ static efi_status_t EFIAPI efi_cout_query_mode(EFI_ENTRY ("%p, %ld, %p, %p" , this, mode_number, columns, rows);if (!console_size_queried) { +const char *stdout_name =env_get ("stdout" );int rows, cols; console_size_queried = true; -if (query_console_serial (&rows, &cols)) +if (stdout_name && !strcmp (stdout_name,"vidconsole" ) && +IS_ENABLED (CONFIG_DM_VIDEO )) { +struct stdio_dev *stdout_dev = +stdio_get_by_name ("vidconsole" ); +struct udevice *dev = stdout_dev->priv; +struct vidconsole_priv *priv = +dev_get_uclass_priv (dev); + rows = priv->rows; + cols = priv->cols; + }else if (query_console_serial (&rows, &cols)) { goto out; + }/* Test if we can have Mode 1 */ if (cols >=80 && rows >=50 ) {
Signature · 1 line
2.13.5
PATCH v2 21/21 efi_loader: Some console improvements for vidconsole
In reply to Rob Clark1) use fputs() to reduce cache flushes from once-per-char to once-per-string
2) handle \r, \t, and \b in addition to just \n for tracking cursor position
3) cursor row/col are zero based, not one based
--- include/efi_api.h | 6 +++-- lib/efi_loader/efi_console.c | 58 ++++++++++++++++++++++++++------------------ 2 files changed, 39 insertions(+), 25 deletions(-)
include/efi_api.h +4 -2
@@ -29,6 +29,8 @@ enum efi_timer_delay { };#define UINTN size_t +typedef long INTN ; +typedef uint16_t *efi_string_t ;#define EVT_TIMER 0x80000000#define EVT_RUNTIME 0x40000000
@@ -427,10 +429,10 @@ struct efi_simple_text_output_protocol {void *reset;efi_status_t (EFIAPI *output_string)( struct efi_simple_text_output_protocol *this, - const unsigned short *str); + const efi_string_t str);efi_status_t (EFIAPI *test_string)( struct efi_simple_text_output_protocol *this, - const unsigned short *str); + const efi_string_t str); efi_status_t(EFIAPI *query_mode)( struct efi_simple_text_output_protocol *this, unsigned long mode_number, unsigned long *columns,
lib/efi_loader/efi_console.c +35 -23
76 lines not on this page · raw message
Signature · 1 line
2.13.5
PATCH v2 21/21 efi_loader: Some console improvements for vidconsole
Quoted 11 lines · Rob Clark
1) use
fputs()to reduce cache flushes from once-per-char to once-per-string
2) handle \r, \t, and \b in addition to just \n for tracking cursor position
3) cursor row/col are zero based, not one basedSigned-off-by Rob Clark <[email protected]>--- include/efi_api.h | 6 +++-- lib/efi_loader/efi_console.c | 58 ++++++++++++++++++++++++++------------------ 2 files changed, 39 insertions(+), 25 deletions(-)
v2 cover efi_loader: enough UEFI for standard distro boot
In reply to Rob ClarkBlerg.. pls ignore the resend of "readdir" patchset which hitched a ride on the git-send-email train.. apparently I should not send patches in the morning before coffee..
BR,
-R
Quoted 90 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.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 anEFI_LOAD_OPTION"struct" in order specified by BootOrder, and will boot the first bootable option.
c) TheEFI_LOAD_OPTIONspecifies a device-path which identifies the device and file path of the .efi payload to exectute.This is implemented with the 'bootefi bootmgr' command.
If there are no bootable options the firmware falls back to loading \EFI\BOOT\bootaa64.efi (exact name varies depending on arch), which for distro's using fallback/shim (which should include most modern linux distros) then loads fallback.efi which uses the
EFI_SIMPLE_FILE_SYSTEM_PROTCOLandEFI_FILE_PROTOCOLto search for any \EFI\*\boot.csv, and will then set BootOrder and BootXXXX EFI variables accordingly so that on next boot fallback.efi is not necessary.The last 5 patches are a bit unrelated, just pulling forward some of the patches I have from the next patchset, to get Shell.efi and SCT working.
Peter Jones (2):
part: extract MBR signature from partitions
efi: add some more device path structuresRob Clark (19):
part: moveefi_guid_t
efi: add some missing__packed
efi_loader: add device-path utils
efi_loader: drop redundantefi_device_path_protocol
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 andloaded_imagehandling
efi_loader: add file/filesys support
efi_loader: supportload_image()from a file-path
efi_loader: make pool allocations cacheline aligned
efi_loader: efi variable support
efi_loader: add bootmgr
efi_loader:file_pathshould be variable length
efi_loader: set loaded image code/data type properly
efi_loader: print GUIDs
efi_loader: split out escape sequence based size query
efi_loader: Correctly figure out size for vidconsole
efi_loader: Some console improvements for vidconsolecmd/bootefi.c | 249 ++++++-------- disk/part_dos.c | 12 +- disk/part_efi.c | 20 ++ include/blk.h | 15 + include/config_distro_bootcmd.h | 5 + include/efi.h | 25 ++ include/efi_api.h | 162 ++++++++- include/efi_loader.h | 62 +++- include/part.h | 3 +- include/part_efi.h | 4 - include/pe.h | 6 + lib/efi_loader/Makefile | 3 +- lib/efi_loader/efi_bootmgr.c | 169 ++++++++++ lib/efi_loader/efi_boottime.c | 162 +++++++-- lib/efi_loader/efi_console.c | 123 ++++--- lib/efi_loader/efi_device_path.c | 563 +++++++++++++++++++++++++++++++ lib/efi_loader/efi_device_path_to_text.c | 242 +++++++++---- lib/efi_loader/efi_disk.c | 86 +++-- lib/efi_loader/efi_file.c | 556 ++++++++++++++++++++++++++++++ lib/efi_loader/efi_image_loader.c | 26 ++ 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 | 335 ++++++++++++++++++ 24 files changed, 2520 insertions(+), 354 deletions(-) create mode 100644 lib/efi_loader/efi_bootmgr.c create mode 100644 lib/efi_loader/efi_device_path.c create mode 100644 lib/efi_loader/efi_file.c create mode 100644 lib/efi_loader/efi_variable.c--
2.13.5