Pull request for UEFI sub-system for next

Bug fixes
 
 * avoid corruption of FAT file system when using long names
 * correct values for RuntimeServicesSupport concerning UEFI capsule update
 * link partition to block device via EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
 
 New feature
 
 * support EFI_LOAD_FILE_PROTOCOL in LoadImage() boot service
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEbcT5xx8ppvoGt20zxIHbvCwFGsQFAl/R2n4ACgkQxIHbvCwF
 GsSQqA/9Hckx74SkpunCpSog9G2npr8eapnO27jTw6Cq/P1aLpleKm7giYs3YVSq
 m8VcfCYgWH05R0C5KIO3hkvLg1vLJBF1hAiOmZNN3MRqp2ihy51j0MuxcCmY4sag
 9p6cgGaI0rSlsyAp9RAFErv7xL/y4o0XDeKNi/EbjJL5k2sysCKT/JyTIDZdE1hs
 /6YFuowlXYZgHsbVd1tlLDvZNG2FyVWhCyBe8YAh/aEszR0W7k376asFWe4BkWp0
 LsEpMn2xBOacVl6VCajYMO1OlUS9VsCBrbW0A8tbgUb26nqArP9U/EvtXL+JIQl2
 Xv078xCCRJ7Q0CvVu6QoIiD2v31RSLDSeavxCLWaw090YygHQ8vI7+JXJ1NnC3pa
 zrBccEvKkOyO+WXPWOb/Ruj0IaHzksNaMkQgGh8KvWnFjXxq7hpPJtrX3xri0MLS
 qQUAS/DOG9eL4poI3lMfeGoIKtCAfjXW80yWHTEAE1wGsk4xzsyf6igQS4eQ0Oen
 peoVnHaA2i4NruaPNa/8cgiypVr0iOBJsqTmj1RMhFz2aWIkgqcOm3RzIDRpoiFV
 dbXiMbktoJVOlO2y3htJvtC+f1CYz2/jNP/S+g2i6dbNwPS8PVH5G5ZUd2q0GYa1
 Rvf3M3gCByG1y/wYDsoUArjGfO6DFB6tqpK1xU/Ih4hbY4vXSqA=
 =800G
 -----END PGP SIGNATURE-----

Merge tag 'efi-next' of https://gitlab.denx.de/u-boot/custodians/u-boot-efi into next

Pull request for UEFI sub-system for next

Bug fixes

* avoid corruption of FAT file system when using long names
* correct values for RuntimeServicesSupport concerning UEFI capsule update
* link partition to block device via EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER

New feature

* support EFI_LOAD_FILE_PROTOCOL in LoadImage() boot service
This commit is contained in:
Tom Rini 2020-12-10 13:54:33 -05:00
commit ddaa949785
15 changed files with 1191 additions and 298 deletions

View File

@ -621,7 +621,7 @@ static int get_fs_info(fsdata *mydata)
/*
* The root directory is not cluster-aligned and may be on a
* "negative" cluster, this will be handled specially in
* next_cluster().
* fat_next_cluster().
*/
mydata->root_cluster = 0;
}
@ -647,44 +647,88 @@ static int get_fs_info(fsdata *mydata)
return 0;
}
/*
* Directory iterator, to simplify filesystem traversal
/**
* struct fat_itr - 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:
* 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);
* }
* .. code-block:: c
*
* For more complete example, see fat_itr_resolve()
* 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 a more complete example, see fat_itr_resolve().
*/
typedef struct {
fsdata *fsdata; /* filesystem parameters */
unsigned start_clust; /* first cluster */
unsigned clust; /* current cluster */
unsigned next_clust; /* next cluster if remaining == 0 */
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;
struct fat_itr {
/**
* @fsdata: filesystem parameters
*/
fsdata *fsdata;
/**
* @start_clust: first cluster
*/
unsigned int start_clust;
/**
* @clust: current cluster
*/
unsigned int clust;
/**
* @next_clust: next cluster if remaining == 0
*/
unsigned int next_clust;
/**
* @last_cluster: set if last cluster of directory reached
*/
int last_cluster;
/**
* @is_root: is iterator at root directory
*/
int is_root;
/**
* @remaining: remaining directory entries in current cluster
*/
int remaining;
/**
* @dent: current directory entry
*/
dir_entry *dent;
/**
* @dent_rem: remaining entries after long name start
*/
int dent_rem;
/**
* @dent_clust: cluster of long name start
*/
unsigned int dent_clust;
/**
* @dent_start: first directory entry for long name
*/
dir_entry *dent_start;
/**
* @l_name: long name of current directory entry
*/
char l_name[VFAT_MAXLEN_BYTES];
/**
* @s_name: short 8.3 name of current directory entry
*/
char s_name[14];
/**
* @name: l_name if there is one, else s_name
*/
char *name;
/**
* @block: buffer for current cluster
*/
u8 block[MAX_CLUSTSIZE] __aligned(ARCH_DMA_MINALIGN);
};
static int fat_itr_isdir(fat_itr *itr);
@ -702,7 +746,7 @@ static int fat_itr_root(fat_itr *itr, fsdata *fsdata)
return -ENXIO;
itr->fsdata = fsdata;
itr->start_clust = 0;
itr->start_clust = fsdata->root_cluster;
itr->clust = fsdata->root_cluster;
itr->next_clust = fsdata->root_cluster;
itr->dent = NULL;
@ -746,6 +790,7 @@ static void fat_itr_child(fat_itr *itr, fat_itr *parent)
} else {
itr->clust = parent->fsdata->root_cluster;
itr->next_clust = parent->fsdata->root_cluster;
itr->start_clust = parent->fsdata->root_cluster;
itr->is_root = 1;
}
itr->dent = NULL;
@ -753,7 +798,17 @@ static void fat_itr_child(fat_itr *itr, fat_itr *parent)
itr->last_cluster = 0;
}
static void *next_cluster(fat_itr *itr, unsigned *nbytes)
/**
* fat_next_cluster() - load next FAT cluster
*
* The function is used when iterating through directories. It loads the
* next cluster with directory entries
*
* @itr: directory iterator
* @nbytes: number of bytes read, 0 on error
* Return: first directory entry, NULL on error
*/
void *fat_next_cluster(fat_itr *itr, unsigned int *nbytes)
{
fsdata *mydata = itr->fsdata; /* for silly macros */
int ret;
@ -825,7 +880,7 @@ static dir_entry *next_dent(fat_itr *itr)
{
if (itr->remaining == 0) {
unsigned nbytes;
struct dir_entry *dent = next_cluster(itr, &nbytes);
struct dir_entry *dent = fat_next_cluster(itr, &nbytes);
/* have we reached the last cluster? */
if (!dent) {
@ -923,9 +978,13 @@ static int fat_itr_next(fat_itr *itr)
while (1) {
dent = next_dent(itr);
if (!dent)
if (!dent) {
itr->dent_start = NULL;
return 0;
}
itr->dent_rem = itr->remaining;
itr->dent_start = itr->dent;
itr->dent_clust = itr->clust;
if (dent->name[0] == DELETED_FLAG)
continue;
@ -1025,6 +1084,7 @@ static int fat_itr_resolve(fat_itr *itr, const char *path, unsigned type)
/* point back to itself */
itr->clust = itr->fsdata->root_cluster;
itr->next_clust = itr->fsdata->root_cluster;
itr->start_clust = itr->fsdata->root_cluster;
itr->dent = NULL;
itr->remaining = 0;
itr->last_cluster = 0;

View File

@ -8,25 +8,185 @@
#include <common.h>
#include <command.h>
#include <config.h>
#include <div64.h>
#include <fat.h>
#include <log.h>
#include <malloc.h>
#include <asm/byteorder.h>
#include <part.h>
#include <rand.h>
#include <asm/byteorder.h>
#include <asm/cache.h>
#include <linux/ctype.h>
#include <div64.h>
#include <linux/math64.h>
#include "fat.c"
static void uppercase(char *str, int len)
static dir_entry *find_directory_entry(fat_itr *itr, char *filename);
static int new_dir_table(fat_itr *itr);
/* Characters that may only be used in long file names */
static const char LONG_ONLY_CHARS[] = "+,;=[]";
/* Combined size of the name and ext fields in the directory entry */
#define SHORT_NAME_SIZE 11
/**
* str2fat() - convert string to valid FAT name characters
*
* Stop when reaching end of @src or a period.
* Ignore spaces.
* Replace characters that may only be used in long names by underscores.
* Convert lower case characters to upper case.
*
* To avoid assumptions about the code page we do not use characters
* above 0x7f for the short name.
*
* @dest: destination buffer
* @src: source buffer
* @length: size of destination buffer
* Return: number of bytes in destination buffer
*/
static int str2fat(char *dest, char *src, int length)
{
int i;
for (i = 0; i < len; i++) {
*str = toupper(*str);
str++;
for (i = 0; i < length; ++src) {
char c = *src;
if (!c || c == '.')
break;
if (c == ' ')
continue;
if (strchr(LONG_ONLY_CHARS, c) || c > 0x7f)
c = '_';
else if (c >= 'a' && c <= 'z')
c &= 0xdf;
dest[i] = c;
++i;
}
return i;
}
/**
* fat_move_to_cluster() - position to first directory entry in cluster
*
* @itr: directory iterator
* @cluster cluster
* Return: 0 for success, -EIO on error
*/
static int fat_move_to_cluster(fat_itr *itr, unsigned int cluster)
{
unsigned int nbytes;
/* position to the start of the directory */
itr->next_clust = cluster;
itr->last_cluster = 0;
if (!fat_next_cluster(itr, &nbytes))
return -EIO;
itr->dent = (dir_entry *)itr->block;
itr->remaining = nbytes / sizeof(dir_entry) - 1;
return 0;
}
/**
* set_name() - set short name in directory entry
*
* The function determines if the @filename is a valid short name.
* In this case no long name is needed.
*
* If a long name is needed, a short name is constructed.
*
* @itr: directory iterator
* @filename: long file name
* @shortname: buffer of 11 bytes to receive chosen short name and extension
* Return: number of directory entries needed, negative on error
*/
static int set_name(fat_itr *itr, const char *filename, char *shortname)
{
char *period;
char *pos;
int period_location;
char buf[13];
int i;
int ret;
struct {
char name[8];
char ext[3];
} dirent;
if (!filename)
return -EIO;
/* Initialize buffer */
memset(&dirent, ' ', sizeof(dirent));
/* Convert filename to upper case short name */
period = strrchr(filename, '.');
pos = (char *)filename;
if (*pos == '.') {
pos = period + 1;
period = 0;
}
if (period)
str2fat(dirent.ext, period + 1, sizeof(dirent.ext));
period_location = str2fat(dirent.name, pos, sizeof(dirent.name));
if (period_location < 0)
return period_location;
if (*dirent.name == ' ')
*dirent.name = '_';
/* 0xe5 signals a deleted directory entry. Replace it by 0x05. */
if (*dirent.name == 0xe5)
*dirent.name = 0x05;
/* If filename and short name are the same, quit. */
sprintf(buf, "%.*s.%.3s", period_location, dirent.name, dirent.ext);
if (!strcmp(buf, filename)) {
ret = 1;
goto out;
}
/* Construct an indexed short name */
for (i = 1; i < 0x200000; ++i) {
int suffix_len;
int suffix_start;
int j;
/* To speed up the search use random numbers */
if (i < 10) {
j = i;
} else {
j = 30 - fls(i);
j = 10 + (rand() >> j);
}
sprintf(buf, "~%d", j);
suffix_len = strlen(buf);
suffix_start = 8 - suffix_len;
if (suffix_start > period_location)
suffix_start = period_location;
memcpy(dirent.name + suffix_start, buf, suffix_len);
if (*dirent.ext != ' ')
sprintf(buf, "%.*s.%.3s", suffix_start + suffix_len,
dirent.name, dirent.ext);
else
sprintf(buf, "%.*s", suffix_start + suffix_len,
dirent.name);
debug("generated short name: %s\n", buf);
/* Check that the short name does not exist yet. */
ret = fat_move_to_cluster(itr, itr->start_clust);
if (ret)
return ret;
if (find_directory_entry(itr, buf))
continue;
debug("chosen short name: %s\n", buf);
/* Each long name directory entry takes 13 characters. */
ret = (strlen(filename) + 25) / 13;
goto out;
}
return -EIO;
out:
memcpy(shortname, dirent.name, SHORT_NAME_SIZE);
return ret;
}
static int total_sector;
@ -50,67 +210,6 @@ static int disk_write(__u32 block, __u32 nr_blocks, void *buf)
return ret;
}
/**
* set_name() - set short name in directory entry
*
* @dirent: directory entry
* @filename: long file name
*/
static void set_name(dir_entry *dirent, const char *filename)
{
char s_name[VFAT_MAXLEN_BYTES];
char *period;
int period_location, len, i, ext_num;
if (filename == NULL)
return;
len = strlen(filename);
if (len == 0)
return;
strncpy(s_name, filename, VFAT_MAXLEN_BYTES - 1);
s_name[VFAT_MAXLEN_BYTES - 1] = '\0';
uppercase(s_name, len);
period = strchr(s_name, '.');
if (period == NULL) {
period_location = len;
ext_num = 0;
} else {
period_location = period - s_name;
ext_num = len - period_location - 1;
}
/* Pad spaces when the length of file name is shorter than eight */
if (period_location < 8) {
memcpy(dirent->name, s_name, period_location);
for (i = period_location; i < 8; i++)
dirent->name[i] = ' ';
} else if (period_location == 8) {
memcpy(dirent->name, s_name, period_location);
} else {
memcpy(dirent->name, s_name, 6);
/*
* TODO: Translating two long names with the same first six
* characters to the same short name is utterly wrong.
* Short names must be unique.
*/
dirent->name[6] = '~';
dirent->name[7] = '1';
}
if (ext_num < 3) {
memcpy(dirent->ext, s_name + period_location + 1, ext_num);
for (i = ext_num; i < 3; i++)
dirent->ext[i] = ' ';
} else
memcpy(dirent->ext, s_name + period_location + 1, 3);
debug("name : %s\n", dirent->name);
debug("ext : %s\n", dirent->ext);
}
/*
* Write fat buffer into block device
*/
@ -152,6 +251,66 @@ static int flush_dirty_fat_buffer(fsdata *mydata)
return 0;
}
/**
* fat_find_empty_dentries() - find a sequence of available directory entries
*
* @itr: directory iterator
* @count: number of directory entries to find
* Return: 0 on success or negative error number
*/
static int fat_find_empty_dentries(fat_itr *itr, int count)
{
unsigned int cluster;
dir_entry *dent;
int remaining;
unsigned int n = 0;
int ret;
ret = fat_move_to_cluster(itr, itr->start_clust);
if (ret)
return ret;
for (;;) {
if (!itr->dent) {
log_debug("Not enough directory entries available\n");
return -ENOSPC;
}
switch (itr->dent->name[0]) {
case 0x00:
case DELETED_FLAG:
if (!n) {
/* Remember first deleted directory entry */
cluster = itr->clust;
dent = itr->dent;
remaining = itr->remaining;
}
++n;
if (n == count)
goto out;
break;
default:
n = 0;
break;
}
next_dent(itr);
if (!itr->dent &&
(!itr->is_root || itr->fsdata->fatsize == 32) &&
new_dir_table(itr))
return -ENOSPC;
}
out:
/* Position back to first directory entry */
if (itr->clust != cluster) {
ret = fat_move_to_cluster(itr, cluster);
if (ret)
return ret;
}
itr->dent = dent;
itr->remaining = remaining;
return 0;
}
/*
* Set the file name information from 'name' into 'slotptr',
*/
@ -221,15 +380,18 @@ name11_12:
return 1;
}
static int new_dir_table(fat_itr *itr);
static int flush_dir(fat_itr *itr);
/*
* Fill dir_slot entries with appropriate name, id, and attr
* 'itr' will point to a next entry
/**
* fill_dir_slot() - fill directory entries for long name
*
* @itr: directory iterator
* @l_name: long name
* @shortname: short name
* Return: 0 for success, -errno otherwise
*/
static int
fill_dir_slot(fat_itr *itr, const char *l_name)
fill_dir_slot(fat_itr *itr, const char *l_name, const char *shortname)
{
__u8 temp_dir_slot_buffer[MAX_LFN_SLOT * sizeof(dir_slot)];
dir_slot *slotptr = (dir_slot *)temp_dir_slot_buffer;
@ -237,7 +399,7 @@ fill_dir_slot(fat_itr *itr, const char *l_name)
int idx = 0, ret;
/* Get short file name checksum value */
checksum = mkcksum(itr->dent->name, itr->dent->ext);
checksum = mkcksum(shortname, shortname + 8);
do {
memset(slotptr, 0x00, sizeof(dir_slot));
@ -259,11 +421,9 @@ fill_dir_slot(fat_itr *itr, const char *l_name)
if (itr->remaining == 0)
flush_dir(itr);
/* allocate a cluster for more entries */
if (!fat_itr_next(itr) && !itr->dent)
if ((itr->is_root && itr->fsdata->fatsize != 32) ||
new_dir_table(itr))
return -1;
next_dent(itr);
if (!itr->dent)
return -EIO;
}
return 0;
@ -636,17 +796,32 @@ static int find_empty_cluster(fsdata *mydata)
return entry;
}
/*
* Allocate a cluster for additional directory entries
/**
* new_dir_table() - allocate a cluster for additional directory entries
*
* @itr: directory iterator
* Return: 0 on success, -EIO otherwise
*/
static int new_dir_table(fat_itr *itr)
{
fsdata *mydata = itr->fsdata;
int dir_newclust = 0;
int dir_oldclust = itr->clust;
unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
dir_newclust = find_empty_cluster(mydata);
set_fatent_value(mydata, itr->clust, dir_newclust);
/*
* Flush before updating FAT to ensure valid directory structure
* in case of failure.
*/
itr->clust = dir_newclust;
itr->next_clust = dir_newclust;
memset(itr->block, 0x00, bytesperclust);
if (flush_dir(itr))
return -EIO;
set_fatent_value(mydata, dir_oldclust, dir_newclust);
if (mydata->fatsize == 32)
set_fatent_value(mydata, dir_newclust, 0xffffff8);
else if (mydata->fatsize == 16)
@ -654,13 +829,8 @@ static int new_dir_table(fat_itr *itr)
else if (mydata->fatsize == 12)
set_fatent_value(mydata, dir_newclust, 0xff8);
itr->clust = dir_newclust;
itr->next_clust = dir_newclust;
if (flush_dirty_fat_buffer(mydata) < 0)
return -1;
memset(itr->block, 0x00, bytesperclust);
return -EIO;
itr->dent = (dir_entry *)itr->block;
itr->last_cluster = 1;
@ -961,24 +1131,35 @@ getit:
return 0;
}
/*
* Fill dir_entry
/**
* fill_dentry() - fill directory entry with shortname
*
* @mydata: private filesystem parameters
* @dentptr: directory entry
* @shortname: chosen short name
* @start_cluster: first cluster of file
* @size: file size
* @attr: file attributes
*/
static void fill_dentry(fsdata *mydata, dir_entry *dentptr,
const char *filename, __u32 start_cluster, __u32 size, __u8 attr)
const char *shortname, __u32 start_cluster, __u32 size, __u8 attr)
{
memset(dentptr, 0, sizeof(*dentptr));
set_start_cluster(mydata, dentptr, start_cluster);
dentptr->size = cpu_to_le32(size);
dentptr->attr = attr;
set_name(dentptr, filename);
memcpy(dentptr->name, shortname, SHORT_NAME_SIZE);
}
/*
* Find a directory entry based on filename or start cluster number
* If the directory entry is not found,
* the new position for writing a directory entry will be returned
/**
* find_directory_entry() - find a directory entry by filename
*
* @itr: directory iterator
* @filename: name of file to find
* Return: directory entry or NULL
*/
static dir_entry *find_directory_entry(fat_itr *itr, char *filename)
{
@ -1001,13 +1182,6 @@ static dir_entry *find_directory_entry(fat_itr *itr, char *filename)
return itr->dent;
}
/* allocate a cluster for more entries */
if (!itr->dent &&
(!itr->is_root || itr->fsdata->fatsize == 32) &&
new_dir_table(itr))
/* indicate that allocating dent failed */
itr->dent = NULL;
return NULL;
}
@ -1157,6 +1331,8 @@ int file_fat_write_at(const char *filename, loff_t pos, void *buffer,
retdent->size = cpu_to_le32(pos + size);
} else {
/* Create a new file */
char shortname[SHORT_NAME_SIZE];
int ndent;
if (itr->is_root) {
/* root dir cannot have "." or ".." */
@ -1167,31 +1343,30 @@ int file_fat_write_at(const char *filename, loff_t pos, void *buffer,
}
}
if (!itr->dent) {
printf("Error: allocating new dir entry\n");
ret = -EIO;
goto exit;
}
if (pos) {
/* No hole allowed */
ret = -EINVAL;
goto exit;
}
memset(itr->dent, 0, sizeof(*itr->dent));
/* Calculate checksum for short name */
set_name(itr->dent, filename);
/* Set long name entries */
if (fill_dir_slot(itr, filename)) {
ret = -EIO;
/* Check if long name is needed */
ndent = set_name(itr, filename, shortname);
if (ndent < 0) {
ret = ndent;
goto exit;
}
ret = fat_find_empty_dentries(itr, ndent);
if (ret)
goto exit;
if (ndent > 1) {
/* Set long name entries */
ret = fill_dir_slot(itr, filename, shortname);
if (ret)
goto exit;
}
/* Set short name entry */
fill_dentry(itr->fsdata, itr->dent, filename, 0, size,
fill_dentry(itr->fsdata, itr->dent, shortname, 0, size,
ATTR_ARCH);
retdent = itr->dent;
@ -1270,27 +1445,91 @@ exit:
return count;
}
static int delete_dentry(fat_itr *itr)
/**
* delete_single_dentry() - delete a single directory entry
*
* @itr: directory iterator
* Return: 0 for success
*/
static int delete_single_dentry(fat_itr *itr)
{
struct dir_entry *dent = itr->dent;
memset(dent, 0, sizeof(*dent));
dent->name[0] = DELETED_FLAG;
if (!itr->remaining) {
if (flush_dir(itr)) {
printf("error: writing directory entry\n");
return -EIO;
}
}
return 0;
}
/**
* delete_long_name() - delete long name directory entries
*
* @itr: directory iterator
* Return: 0 for success
*/
static int delete_long_name(fat_itr *itr)
{
struct dir_entry *dent = itr->dent;
int seqn = itr->dent->name[0] & ~LAST_LONG_ENTRY_MASK;
while (seqn--) {
int ret;
ret = delete_single_dentry(itr);
if (ret)
return ret;
dent = next_dent(itr);
if (!dent)
return -EIO;
}
return 0;
}
/**
* delete_dentry_long() - remove directory entry
*
* @itr: directory iterator
* Return: 0 for success
*/
static int delete_dentry_long(fat_itr *itr)
{
fsdata *mydata = itr->fsdata;
dir_entry *dentptr = itr->dent;
dir_entry *dent = itr->dent;
/* free cluster blocks */
clear_fatent(mydata, START(dentptr));
clear_fatent(mydata, START(dent));
if (flush_dirty_fat_buffer(mydata) < 0) {
printf("Error: flush fat buffer\n");
return -EIO;
}
/* Position to first directory entry for long name */
if (itr->clust != itr->dent_clust) {
int ret;
/*
* update a directory entry
* TODO:
* - long file name support
* - find and mark the "new" first invalid entry as name[0]=0x00
*/
memset(dentptr, 0, sizeof(*dentptr));
dentptr->name[0] = 0xe5;
ret = fat_move_to_cluster(itr, itr->dent_clust);
if (ret)
return ret;
}
itr->dent = itr->dent_start;
itr->remaining = itr->dent_rem;
dent = itr->dent_start;
/* Delete long name */
if ((dent->attr & ATTR_VFAT) == ATTR_VFAT &&
(dent->name[0] & LAST_LONG_ENTRY_MASK)) {
int ret;
ret = delete_long_name(itr);
if (ret)
return ret;
}
/* Delete short name */
delete_single_dentry(itr);
if (flush_dir(itr)) {
printf("error: writing directory entry\n");
return -EIO;
@ -1360,7 +1599,7 @@ int fat_unlink(const char *filename)
}
}
ret = delete_dentry(itr);
ret = delete_dentry_long(itr);
exit:
free(fsdata.fatbuf);
@ -1424,6 +1663,9 @@ int fat_mkdir(const char *new_dirname)
ret = -EEXIST;
goto exit;
} else {
char shortname[SHORT_NAME_SIZE];
int ndent;
if (itr->is_root) {
/* root dir cannot have "." or ".." */
if (!strcmp(l_dirname, ".") ||
@ -1433,20 +1675,24 @@ int fat_mkdir(const char *new_dirname)
}
}
if (!itr->dent) {
printf("Error: allocating new dir entry\n");
ret = -EIO;
/* Check if long name is needed */
ndent = set_name(itr, dirname, shortname);
if (ndent < 0) {
ret = ndent;
goto exit;
}
memset(itr->dent, 0, sizeof(*itr->dent));
/* Set short name to set alias checksum field in dir_slot */
set_name(itr->dent, dirname);
fill_dir_slot(itr, dirname);
ret = fat_find_empty_dentries(itr, ndent);
if (ret)
goto exit;
if (ndent > 1) {
/* Set long name entries */
ret = fill_dir_slot(itr, dirname, shortname);
if (ret)
goto exit;
}
/* Set attribute as archive for regular file */
fill_dentry(itr->fsdata, itr->dent, dirname, 0, 0,
fill_dentry(itr->fsdata, itr->dent, shortname, 0, 0,
ATTR_DIR | ATTR_ARCH);
retdent = itr->dent;
@ -1468,7 +1714,11 @@ int fat_mkdir(const char *new_dirname)
memcpy(dotdent[1].name, ".. ", 8);
memcpy(dotdent[1].ext, " ", 3);
dotdent[1].attr = ATTR_DIR | ATTR_ARCH;
set_start_cluster(mydata, &dotdent[1], itr->start_clust);
if (itr->is_root)
set_start_cluster(mydata, &dotdent[1], 0);
else
set_start_cluster(mydata, &dotdent[1], itr->start_clust);
ret = set_contents(mydata, retdent, 0, (__u8 *)dotdent,
bytesperclust, &actwrite);

View File

@ -195,6 +195,9 @@ extern const efi_guid_t efi_file_system_info_guid;
extern const efi_guid_t efi_guid_device_path_utilities_protocol;
/* GUID of the deprecated Unicode collation protocol */
extern const efi_guid_t efi_guid_unicode_collation_protocol;
/* GUIDs of the Load File and Load File2 protocol */
extern const efi_guid_t efi_guid_load_file_protocol;
extern const efi_guid_t efi_guid_load_file2_protocol;
/* GUID of the Unicode collation protocol */
extern const efi_guid_t efi_guid_unicode_collation_protocol2;
extern const efi_guid_t efi_guid_hii_config_routing_protocol;
@ -497,6 +500,11 @@ efi_status_t efi_search_protocol(const efi_handle_t handle,
efi_status_t efi_add_protocol(const efi_handle_t handle,
const efi_guid_t *protocol,
void *protocol_interface);
/* Open protocol */
efi_status_t efi_protocol_open(struct efi_handler *handler,
void **protocol_interface, void *agent_handle,
void *controller_handle, uint32_t attributes);
/* Delete protocol from a handle */
efi_status_t efi_remove_protocol(const efi_handle_t handle,
const efi_guid_t *protocol,

View File

@ -9,8 +9,9 @@
#ifndef _FAT_H_
#define _FAT_H_
#include <asm/byteorder.h>
#include <fs.h>
#include <asm/byteorder.h>
#include <asm/cache.h>
struct disk_partition;
@ -179,6 +180,9 @@ typedef struct {
int fats; /* Number of FATs */
} fsdata;
struct fat_itr;
typedef struct fat_itr fat_itr;
static inline u32 clust_to_sect(fsdata *fsdata, u32 clust)
{
return fsdata->data_begin + clust * fsdata->clust_size;
@ -208,4 +212,5 @@ void fat_closedir(struct fs_dir_stream *dirs);
int fat_unlink(const char *filename);
int fat_mkdir(const char *dirname);
void fat_close(void);
void *fat_next_cluster(fat_itr *itr, unsigned int *nbytes);
#endif /* _FAT_H_ */

View File

@ -168,7 +168,7 @@ config REGEX
choice
prompt "Pseudo-random library support type"
depends on NET_RANDOM_ETHADDR || RANDOM_UUID || CMD_UUID || \
RNG_SANDBOX || UT_LIB && AES
RNG_SANDBOX || UT_LIB && AES || FAT_WRITE
default LIB_RAND
help
Select the library to provide pseudo-random number generator

View File

@ -30,7 +30,7 @@ obj-y += efi_device_path.o
obj-$(CONFIG_EFI_DEVICE_PATH_TO_TEXT) += efi_device_path_to_text.o
obj-y += efi_device_path_utilities.o
obj-y += efi_file.o
obj-$(CONFIG_EFI_LOADER_HII) += efi_hii.o efi_hii_config.o
obj-$(CONFIG_EFI_LOADER_HII) += efi_hii.o
obj-y += efi_image_loader.o
obj-y += efi_memory.o
obj-y += efi_root_node.o

View File

@ -81,6 +81,9 @@ const efi_guid_t efi_guid_event_group_ready_to_boot =
/* event group ResetSystem() invoked (before ExitBootServices) */
const efi_guid_t efi_guid_event_group_reset_system =
EFI_EVENT_GROUP_RESET_SYSTEM;
/* GUIDs of the Load File and Load File2 protocols */
const efi_guid_t efi_guid_load_file_protocol = EFI_LOAD_FILE_PROTOCOL_GUID;
const efi_guid_t efi_guid_load_file2_protocol = EFI_LOAD_FILE2_PROTOCOL_GUID;
static efi_status_t EFIAPI efi_disconnect_controller(
efi_handle_t controller_handle,
@ -1770,30 +1773,108 @@ failure:
}
/**
* efi_load_image_from_path() - load an image using a file path
* efi_locate_device_path() - Get the device path and handle of an device
* implementing a protocol
* @protocol: GUID of the protocol
* @device_path: device path
* @device: handle of the device
*
* This function implements the LocateDevicePath service.
*
* See the Unified Extensible Firmware Interface (UEFI) specification for
* details.
*
* Return: status code
*/
static efi_status_t EFIAPI efi_locate_device_path(
const efi_guid_t *protocol,
struct efi_device_path **device_path,
efi_handle_t *device)
{
struct efi_device_path *dp;
size_t i;
struct efi_handler *handler;
efi_handle_t *handles;
size_t len, len_dp;
size_t len_best = 0;
efi_uintn_t no_handles;
u8 *remainder;
efi_status_t ret;
EFI_ENTRY("%pUl, %p, %p", protocol, device_path, device);
if (!protocol || !device_path || !*device_path) {
ret = EFI_INVALID_PARAMETER;
goto out;
}
/* Find end of device path */
len = efi_dp_instance_size(*device_path);
/* Get all handles implementing the protocol */
ret = EFI_CALL(efi_locate_handle_buffer(BY_PROTOCOL, protocol, NULL,
&no_handles, &handles));
if (ret != EFI_SUCCESS)
goto out;
for (i = 0; i < no_handles; ++i) {
/* Find the device path protocol */
ret = efi_search_protocol(handles[i], &efi_guid_device_path,
&handler);
if (ret != EFI_SUCCESS)
continue;
dp = (struct efi_device_path *)handler->protocol_interface;
len_dp = efi_dp_instance_size(dp);
/*
* This handle can only be a better fit
* if its device path length is longer than the best fit and
* if its device path length is shorter of equal the searched
* device path.
*/
if (len_dp <= len_best || len_dp > len)
continue;
/* Check if dp is a subpath of device_path */
if (memcmp(*device_path, dp, len_dp))
continue;
if (!device) {
ret = EFI_INVALID_PARAMETER;
goto out;
}
*device = handles[i];
len_best = len_dp;
}
if (len_best) {
remainder = (u8 *)*device_path + len_best;
*device_path = (struct efi_device_path *)remainder;
ret = EFI_SUCCESS;
} else {
ret = EFI_NOT_FOUND;
}
out:
return EFI_EXIT(ret);
}
/**
* efi_load_image_from_file() - load an image from file system
*
* Read a file into a buffer allocated as EFI_BOOT_SERVICES_DATA. It is the
* callers obligation to update the memory type as needed.
*
* @file_path: the path of the image to load
* @buffer: buffer containing the loaded image
* @size: size of the loaded image
* Return: status code
* @file_path: the path of the image to load
* @buffer: buffer containing the loaded image
* @size: size of the loaded image
* Return: status code
*/
static
efi_status_t efi_load_image_from_path(struct efi_device_path *file_path,
efi_status_t efi_load_image_from_file(struct efi_device_path *file_path,
void **buffer, efi_uintn_t *size)
{
struct efi_file_info *info = NULL;
struct efi_file_handle *f;
static efi_status_t ret;
efi_status_t ret;
u64 addr;
efi_uintn_t bs;
/* In case of failure nothing is returned */
*buffer = NULL;
*size = 0;
/* Open file */
f = efi_file_from_path(file_path);
if (!f)
@ -1841,6 +1922,86 @@ error:
return ret;
}
/**
* efi_load_image_from_path() - load an image using a file path
*
* Read a file into a buffer allocated as EFI_BOOT_SERVICES_DATA. It is the
* callers obligation to update the memory type as needed.
*
* @boot_policy: true for request originating from the boot manager
* @file_path: the path of the image to load
* @buffer: buffer containing the loaded image
* @size: size of the loaded image
* Return: status code
*/
static
efi_status_t efi_load_image_from_path(bool boot_policy,
struct efi_device_path *file_path,
void **buffer, efi_uintn_t *size)
{
efi_handle_t device;
efi_status_t ret;
struct efi_device_path *dp;
struct efi_load_file_protocol *load_file_protocol = NULL;
efi_uintn_t buffer_size;
uint64_t addr, pages;
const efi_guid_t *guid;
/* In case of failure nothing is returned */
*buffer = NULL;
*size = 0;
dp = file_path;
ret = EFI_CALL(efi_locate_device_path(
&efi_simple_file_system_protocol_guid, &dp, &device));
if (ret == EFI_SUCCESS)
return efi_load_image_from_file(file_path, buffer, size);
ret = EFI_CALL(efi_locate_device_path(
&efi_guid_load_file_protocol, &dp, &device));
if (ret == EFI_SUCCESS) {
guid = &efi_guid_load_file_protocol;
} else if (!boot_policy) {
guid = &efi_guid_load_file2_protocol;
ret = EFI_CALL(efi_locate_device_path(guid, &dp, &device));
}
if (ret != EFI_SUCCESS)
return EFI_NOT_FOUND;
ret = EFI_CALL(efi_handle_protocol(device, guid,
(void **)&load_file_protocol));
if (ret != EFI_SUCCESS)
return EFI_NOT_FOUND;
buffer_size = 0;
ret = load_file_protocol->load_file(load_file_protocol, dp,
boot_policy, &buffer_size,
NULL);
if (ret != EFI_BUFFER_TOO_SMALL)
goto out;
pages = efi_size_in_pages(buffer_size);
ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES, EFI_BOOT_SERVICES_DATA,
pages, &addr);
if (ret != EFI_SUCCESS) {
ret = EFI_OUT_OF_RESOURCES;
goto out;
}
ret = EFI_CALL(load_file_protocol->load_file(
load_file_protocol, dp, boot_policy,
&buffer_size, (void *)(uintptr_t)addr));
if (ret != EFI_SUCCESS)
efi_free_pages(addr, pages);
out:
if (load_file_protocol)
EFI_CALL(efi_close_protocol(device,
&efi_guid_load_file2_protocol,
efi_root, NULL));
if (ret == EFI_SUCCESS) {
*buffer = (void *)(uintptr_t)addr;
*size = buffer_size;
}
return ret;
}
/**
* efi_load_image() - load an EFI image into memory
* @boot_policy: true for request originating from the boot manager
@ -1883,8 +2044,8 @@ efi_status_t EFIAPI efi_load_image(bool boot_policy,
}
if (!source_buffer) {
ret = efi_load_image_from_path(file_path, &dest_buffer,
&source_size);
ret = efi_load_image_from_path(boot_policy, file_path,
&dest_buffer, &source_size);
if (ret != EFI_SUCCESS)
goto error;
} else {
@ -2403,88 +2564,6 @@ found:
return EFI_EXIT(EFI_SUCCESS);
}
/**
* efi_locate_device_path() - Get the device path and handle of an device
* implementing a protocol
* @protocol: GUID of the protocol
* @device_path: device path
* @device: handle of the device
*
* This function implements the LocateDevicePath service.
*
* See the Unified Extensible Firmware Interface (UEFI) specification for
* details.
*
* Return: status code
*/
static efi_status_t EFIAPI efi_locate_device_path(
const efi_guid_t *protocol,
struct efi_device_path **device_path,
efi_handle_t *device)
{
struct efi_device_path *dp;
size_t i;
struct efi_handler *handler;
efi_handle_t *handles;
size_t len, len_dp;
size_t len_best = 0;
efi_uintn_t no_handles;
u8 *remainder;
efi_status_t ret;
EFI_ENTRY("%pUl, %p, %p", protocol, device_path, device);
if (!protocol || !device_path || !*device_path) {
ret = EFI_INVALID_PARAMETER;
goto out;
}
/* Find end of device path */
len = efi_dp_instance_size(*device_path);
/* Get all handles implementing the protocol */
ret = EFI_CALL(efi_locate_handle_buffer(BY_PROTOCOL, protocol, NULL,
&no_handles, &handles));
if (ret != EFI_SUCCESS)
goto out;
for (i = 0; i < no_handles; ++i) {
/* Find the device path protocol */
ret = efi_search_protocol(handles[i], &efi_guid_device_path,
&handler);
if (ret != EFI_SUCCESS)
continue;
dp = (struct efi_device_path *)handler->protocol_interface;
len_dp = efi_dp_instance_size(dp);
/*
* This handle can only be a better fit
* if its device path length is longer than the best fit and
* if its device path length is shorter of equal the searched
* device path.
*/
if (len_dp <= len_best || len_dp > len)
continue;
/* Check if dp is a subpath of device_path */
if (memcmp(*device_path, dp, len_dp))
continue;
if (!device) {
ret = EFI_INVALID_PARAMETER;
goto out;
}
*device = handles[i];
len_best = len_dp;
}
if (len_best) {
remainder = (u8 *)*device_path + len_best;
*device_path = (struct efi_device_path *)remainder;
ret = EFI_SUCCESS;
} else {
ret = EFI_NOT_FOUND;
}
out:
return EFI_EXIT(ret);
}
/**
* efi_install_multiple_protocol_interfaces() - Install multiple protocol
* interfaces
@ -2700,7 +2779,7 @@ static void EFIAPI efi_set_mem(void *buffer, size_t size, uint8_t value)
*
* Return: status code
*/
static efi_status_t efi_protocol_open(
efi_status_t efi_protocol_open(
struct efi_handler *handler,
void **protocol_interface, void *agent_handle,
void *controller_handle, uint32_t attributes)

View File

@ -376,6 +376,23 @@ static efi_status_t efi_disk_add_dev(
/* Fill in object data */
if (part) {
struct efi_device_path *node = efi_dp_part_node(desc, part);
struct efi_handler *handler;
void *protocol_interface;
/* Parent must expose EFI_BLOCK_IO_PROTOCOL */
ret = efi_search_protocol(parent, &efi_block_io_guid, &handler);
if (ret != EFI_SUCCESS)
goto error;
/*
* Link the partition (child controller) to the block device
* (controller).
*/
ret = efi_protocol_open(handler, &protocol_interface, NULL,
&diskobj->header,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER);
if (ret != EFI_SUCCESS)
goto error;
diskobj->dp = efi_dp_append_node(dp_parent, node);
efi_free_pool(node);
@ -453,6 +470,9 @@ static efi_status_t efi_disk_add_dev(
}
}
return EFI_SUCCESS;
error:
efi_delete_handle(&diskobj->header);
return ret;
}
/**

View File

@ -1,9 +1,13 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* EFI Human Interface Infrastructure ... Configuration
* EFI Human Interface Infrastructure ... Configuration
*
* Copyright (c) 2017 Leif Lindholm
* Copyright (c) 2018 AKASHI Takahiro, Linaro Limited
* Copyright (c) 2017 Leif Lindholm
* Copyright (c) 2018 AKASHI Takahiro, Linaro Limited
*
* As this is still a non-working stub and the protocol is neither required
* by the EFI shell nor by the UEFI SCT this module has been removed from
* the Makefile.
*/
#include <common.h>

View File

@ -12,9 +12,6 @@
#include <efi_loader.h>
#include <efi_load_initrd.h>
static const efi_guid_t efi_guid_load_file2_protocol =
EFI_LOAD_FILE2_PROTOCOL_GUID;
static efi_status_t EFIAPI
efi_load_file2_initrd(struct efi_load_file_protocol *this,
struct efi_device_path *file_path, bool boot_policy,

View File

@ -77,9 +77,6 @@ efi_status_t efi_root_node_register(void)
/* HII database protocol */
&efi_guid_hii_database_protocol,
(void *)&efi_hii_database,
/* HII configuration routing protocol */
&efi_guid_hii_config_routing_protocol,
(void *)&efi_hii_config_routing,
#endif
NULL));
efi_root->type = EFI_OBJECT_TYPE_U_BOOT_FIRMWARE;

View File

@ -133,10 +133,6 @@ efi_status_t efi_init_runtime_supported(void)
#ifdef CONFIG_EFI_HAVE_RUNTIME_RESET
rt_table->runtime_services_supported |= EFI_RT_SUPPORTED_RESET_SYSTEM;
#endif
if (IS_ENABLED(CONFIG_EFI_RUNTIME_UPDATE_CAPSULE))
rt_table->runtime_services_supported |=
(EFI_RT_SUPPORTED_UPDATE_CAPSULE |
EFI_RT_SUPPORTED_QUERY_CAPSULE_CAPABILITIES);
ret = efi_install_configuration_table(&efi_rt_properties_table_guid,
rt_table);

View File

@ -25,9 +25,12 @@ efi_selftest_crc32.o \
efi_selftest_devicepath_util.o \
efi_selftest_events.o \
efi_selftest_event_groups.o \
efi_selftest_exception.o \
efi_selftest_exitbootservices.o \
efi_selftest_gop.o \
efi_selftest_load_file.o \
efi_selftest_loaded_image.o \
efi_selftest_loadimage.o \
efi_selftest_manageprotocols.o \
efi_selftest_mem.o \
efi_selftest_memory.o \
@ -35,6 +38,8 @@ efi_selftest_open_protocol.o \
efi_selftest_register_notify.o \
efi_selftest_reset.o \
efi_selftest_set_virtual_address_map.o \
efi_selftest_startimage_exit.o \
efi_selftest_startimage_return.o \
efi_selftest_textinput.o \
efi_selftest_textinputex.o \
efi_selftest_textoutput.o \
@ -65,12 +70,6 @@ ifeq ($(CONFIG_BLK)$(CONFIG_DOS_PARTITION),yy)
obj-y += efi_selftest_block_device.o
endif
obj-y += \
efi_selftest_exception.o \
efi_selftest_loadimage.o \
efi_selftest_startimage_exit.o \
efi_selftest_startimage_return.o
targets += \
efi_miniapp_file_image_exception.h \
efi_miniapp_file_image_exit.h \
@ -94,10 +93,12 @@ $(obj)/efi_miniapp_file_image_return.h: $(obj)/efi_selftest_miniapp_return.efi
$(obj)/../../tools/file2include $(obj)/efi_selftest_miniapp_return.efi > \
$(obj)/efi_miniapp_file_image_return.h
$(obj)/efi_selftest_loadimage.o: $(obj)/efi_miniapp_file_image_exit.h
$(obj)/efi_selftest_exception.o: $(obj)/efi_miniapp_file_image_exception.h
$(obj)/efi_selftest_load_file.o: $(obj)/efi_miniapp_file_image_exit.h
$(obj)/efi_selftest_loadimage.o: $(obj)/efi_miniapp_file_image_exit.h
$(obj)/efi_selftest_startimage_exit.o: $(obj)/efi_miniapp_file_image_exit.h
$(obj)/efi_selftest_startimage_return.o: $(obj)/efi_miniapp_file_image_return.h

View File

@ -0,0 +1,475 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* efi_selftest_load_file
*
* Copyright (c) 2020 Heinrich Schuchardt <xypron.glpk@gmx.de>
*
* This test checks the handling of the LOAD_FILE and the LOAD_FILE2 protocol
* by the LoadImage() service.
*/
#include <efi_selftest.h>
/* Include containing the miniapp.efi application */
#include "efi_miniapp_file_image_exit.h"
/* Block size of compressed disk image */
#define COMPRESSED_DISK_IMAGE_BLOCK_SIZE 8
/* Binary logarithm of the block size */
#define LB_BLOCK_SIZE 9
#define GUID_VENDOR \
EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d, \
0x08, 0x72, 0x81, 0x9c, 0x65, 0xfc, 0xbb, 0xd1)
#define GUID_VENDOR2 \
EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d, \
0x08, 0x72, 0x81, 0x9c, 0x65, 0xfc, 0xbb, 0xd2)
#define FILE_NAME_SIZE 16
static const efi_guid_t efi_st_guid_load_file_protocol =
EFI_LOAD_FILE_PROTOCOL_GUID;
static const efi_guid_t efi_st_guid_load_file2_protocol =
EFI_LOAD_FILE2_PROTOCOL_GUID;
static const efi_guid_t efi_st_guid_device_path =
EFI_DEVICE_PATH_PROTOCOL_GUID;
static efi_handle_t image_handle;
static struct efi_boot_services *boottime;
static efi_handle_t handle_lf;
static efi_handle_t handle_lf2;
/* One 8 byte block of the compressed disk image */
struct line {
size_t addr;
char *line;
};
/* Compressed file image */
struct compressed_file_image {
size_t length;
struct line lines[];
};
static struct compressed_file_image img = EFI_ST_DISK_IMG;
static int load_file_call_count;
static int load_file2_call_count;
/* Decompressed file image */
static u8 *image;
static struct {
struct efi_device_path_vendor v;
struct efi_device_path d;
} dp_lf_prot = {
{
{
DEVICE_PATH_TYPE_HARDWARE_DEVICE,
DEVICE_PATH_SUB_TYPE_VENDOR,
sizeof(struct efi_device_path_vendor),
},
GUID_VENDOR,
},
{
DEVICE_PATH_TYPE_END,
DEVICE_PATH_SUB_TYPE_END,
sizeof(struct efi_device_path),
},
};
static struct {
struct efi_device_path_vendor v;
struct efi_device_path_file_path f;
u16 file_name[FILE_NAME_SIZE];
struct efi_device_path e;
} dp_lf_file = {
{
{
DEVICE_PATH_TYPE_HARDWARE_DEVICE,
DEVICE_PATH_SUB_TYPE_VENDOR,
sizeof(struct efi_device_path_vendor),
},
GUID_VENDOR,
},
{
{
DEVICE_PATH_TYPE_MEDIA_DEVICE,
DEVICE_PATH_SUB_TYPE_FILE_PATH,
sizeof(struct efi_device_path_file_path) +
FILE_NAME_SIZE * sizeof(u16),
}
},
L"\\lf.efi",
{
DEVICE_PATH_TYPE_END,
DEVICE_PATH_SUB_TYPE_END,
sizeof(struct efi_device_path),
},
};
struct efi_device_path *dp_lf_file_remainder = &dp_lf_file.f.dp;
static struct {
struct efi_device_path_vendor v;
struct efi_device_path d;
} dp_lf2_prot = {
{
{
DEVICE_PATH_TYPE_HARDWARE_DEVICE,
DEVICE_PATH_SUB_TYPE_VENDOR,
sizeof(struct efi_device_path_vendor),
},
GUID_VENDOR2,
},
{
DEVICE_PATH_TYPE_END,
DEVICE_PATH_SUB_TYPE_END,
sizeof(struct efi_device_path),
},
};
static struct {
struct efi_device_path_vendor v;
struct efi_device_path_file_path f;
u16 file_name[FILE_NAME_SIZE];
struct efi_device_path e;
} dp_lf2_file = {
{
{
DEVICE_PATH_TYPE_HARDWARE_DEVICE,
DEVICE_PATH_SUB_TYPE_VENDOR,
sizeof(struct efi_device_path_vendor),
},
GUID_VENDOR2,
},
{
{
DEVICE_PATH_TYPE_MEDIA_DEVICE,
DEVICE_PATH_SUB_TYPE_FILE_PATH,
sizeof(struct efi_device_path_file_path) +
FILE_NAME_SIZE * sizeof(u16),
}
},
L"\\lf2.efi",
{
DEVICE_PATH_TYPE_END,
DEVICE_PATH_SUB_TYPE_END,
sizeof(struct efi_device_path),
},
};
struct efi_device_path *dp_lf2_file_remainder = &dp_lf2_file.f.dp;
/*
* Decompress the disk image.
*
* @image decompressed disk image
* @return status code
*/
static efi_status_t decompress(u8 **image)
{
u8 *buf;
size_t i;
size_t addr;
size_t len;
efi_status_t ret;
ret = boottime->allocate_pool(EFI_LOADER_DATA, img.length,
(void **)&buf);
if (ret != EFI_SUCCESS) {
efi_st_error("Out of memory\n");
return ret;
}
boottime->set_mem(buf, img.length, 0);
for (i = 0; ; ++i) {
if (!img.lines[i].line)
break;
addr = img.lines[i].addr;
len = COMPRESSED_DISK_IMAGE_BLOCK_SIZE;
if (addr + len > img.length)
len = img.length - addr;
boottime->copy_mem(buf + addr, img.lines[i].line, len);
}
*image = buf;
return ret;
}
/*
* load_file() - LoadFile() service of a EFI_LOAD_FILE_PROTOCOL
*
* @this: instance of EFI_LOAD_FILE_PROTOCOL
* @file_path: remaining device path
* @boot_policy: true if called by boot manager
* @buffer_size: (required) buffer size
* @buffer: buffer to which the file is to be loaded
*/
efi_status_t EFIAPI load_file(struct efi_load_file_protocol *this,
struct efi_device_path *file_path,
bool boot_policy,
efi_uintn_t *buffer_size,
void *buffer)
{
++load_file_call_count;
if (memcmp(file_path, dp_lf_file_remainder,
sizeof(struct efi_device_path_file_path) +
FILE_NAME_SIZE * sizeof(u16) +
sizeof(struct efi_device_path))) {
efi_st_error("Wrong remaining device path\n");
return EFI_NOT_FOUND;
}
if (this->load_file != load_file) {
efi_st_error("wrong this\n");
return EFI_INVALID_PARAMETER;
}
if (*buffer_size < img.length) {
*buffer_size = img.length;
return EFI_BUFFER_TOO_SMALL;
}
memcpy(buffer, image, img.length);
*buffer_size = img.length;
return EFI_SUCCESS;
}
/*
* load_file2() - LoadFile() service of a EFI_LOAD_FILE2_PROTOCOL
*
* @this: instance of EFI_LOAD_FILE2_PROTOCOL
* @file_path: remaining device path
* @boot_policy: true if called by boot manager
* @buffer_size: (required) buffer size
* @buffer: buffer to which the file is to be loaded
*/
efi_status_t EFIAPI load_file2(struct efi_load_file_protocol *this,
struct efi_device_path *file_path,
bool boot_policy,
efi_uintn_t *buffer_size,
void *buffer)
{
++load_file2_call_count;
if (memcmp(file_path, dp_lf2_file_remainder,
sizeof(struct efi_device_path_file_path) +
FILE_NAME_SIZE * sizeof(u16) +
sizeof(struct efi_device_path))) {
efi_st_error("Wrong remaining device path\n");
return EFI_NOT_FOUND;
}
if (this->load_file != load_file2) {
efi_st_error("wrong this\n");
return EFI_INVALID_PARAMETER;
}
if (boot_policy) {
efi_st_error("LOAD_FILE2 called with boot_policy = true");
return EFI_INVALID_PARAMETER;
}
if (*buffer_size < img.length) {
*buffer_size = img.length;
return EFI_BUFFER_TOO_SMALL;
}
memcpy(buffer, image, img.length);
*buffer_size = img.length;
return EFI_SUCCESS;
}
static struct efi_load_file_protocol lf_prot = {load_file};
static struct efi_load_file_protocol lf2_prot = {load_file2};
/*
* Setup unit test.
*
* Install an EFI_LOAD_FILE_PROTOCOL and an EFI_LOAD_FILE2_PROTOCOL.
*
* @handle: handle of the loaded image
* @systable: system table
* @return: EFI_ST_SUCCESS for success
*/
static int efi_st_load_file_setup(const efi_handle_t handle,
const struct efi_system_table *systable)
{
efi_status_t ret;
image_handle = handle;
boottime = systable->boottime;
/* Load the application image into memory */
decompress(&image);
ret = boottime->install_multiple_protocol_interfaces(
&handle_lf,
&efi_st_guid_device_path,
&dp_lf_prot,
&efi_st_guid_load_file_protocol,
&lf_prot,
NULL);
if (ret != EFI_SUCCESS) {
efi_st_error("InstallMultipleProtocolInterfaces failed\n");
return EFI_ST_FAILURE;
}
ret = boottime->install_multiple_protocol_interfaces(
&handle_lf2,
&efi_st_guid_device_path,
&dp_lf2_prot,
&efi_st_guid_load_file2_protocol,
&lf2_prot,
NULL);
if (ret != EFI_SUCCESS) {
efi_st_error("InstallMultipleProtocolInterfaces failed\n");
return EFI_ST_FAILURE;
}
return EFI_ST_SUCCESS;
}
/*
* Tear down unit test.
*
* @return: EFI_ST_SUCCESS for success
*/
static int efi_st_load_file_teardown(void)
{
efi_status_t ret = EFI_ST_SUCCESS;
if (handle_lf) {
ret = boottime->uninstall_multiple_protocol_interfaces(
handle_lf,
&efi_st_guid_device_path,
&dp_lf_prot,
&efi_st_guid_load_file_protocol,
&lf_prot,
NULL);
if (ret != EFI_SUCCESS) {
efi_st_error(
"UninstallMultipleProtocolInterfaces failed\n");
return EFI_ST_FAILURE;
}
}
if (handle_lf2) {
ret = boottime->uninstall_multiple_protocol_interfaces(
handle_lf2,
&efi_st_guid_device_path,
&dp_lf2_prot,
&efi_st_guid_load_file2_protocol,
&lf2_prot,
NULL);
if (ret != EFI_SUCCESS) {
efi_st_error(
"UninstallMultipleProtocolInterfaces failed\n");
return EFI_ST_FAILURE;
}
}
if (image) {
ret = boottime->free_pool(image);
if (ret != EFI_SUCCESS) {
efi_st_error("Failed to free image\n");
return EFI_ST_FAILURE;
}
}
return ret;
}
/*
* Execute unit test.
*
* Try loading an image via the EFI_LOAD_FILE_PROTOCOL and the
* EFI_LOAD_FILE2_PROTOCOL. Finally execute the image.
*
* @return: EFI_ST_SUCCESS for success
*/
static int efi_st_load_file_execute(void)
{
efi_status_t ret;
efi_handle_t handle;
efi_uintn_t exit_data_size = 0;
u16 *exit_data = NULL;
u16 expected_text[] = EFI_ST_SUCCESS_STR;
load_file_call_count = 0;
load_file2_call_count = 0;
handle = NULL;
ret = boottime->load_image(true, image_handle, &dp_lf_file.v.dp, NULL,
0, &handle);
if (ret != EFI_SUCCESS) {
efi_st_error("Failed to load image\n");
return EFI_ST_FAILURE;
}
if (load_file2_call_count || !load_file_call_count) {
efi_st_error("Wrong image loaded\n");
return EFI_ST_FAILURE;
}
ret = boottime->unload_image(handle);
if (ret != EFI_SUCCESS) {
efi_st_error("Failed to unload image\n");
return EFI_ST_FAILURE;
}
load_file_call_count = 0;
load_file2_call_count = 0;
handle = NULL;
ret = boottime->load_image(false, image_handle, &dp_lf_file.v.dp, NULL,
0, &handle);
if (ret != EFI_SUCCESS) {
efi_st_error("Failed to load image\n");
return EFI_ST_FAILURE;
}
if (load_file2_call_count || !load_file_call_count) {
efi_st_error("Wrong image loaded\n");
return EFI_ST_FAILURE;
}
ret = boottime->unload_image(handle);
if (ret != EFI_SUCCESS) {
efi_st_error("Failed to unload image\n");
return EFI_ST_FAILURE;
}
ret = boottime->load_image(true, image_handle, &dp_lf2_file.v.dp, NULL,
0, &handle);
if (ret != EFI_NOT_FOUND) {
efi_st_error(
"Boot manager should not use LOAD_FILE2_PROTOCOL\n");
return EFI_ST_FAILURE;
}
load_file_call_count = 0;
load_file2_call_count = 0;
handle = NULL;
ret = boottime->load_image(false, image_handle, &dp_lf2_file.v.dp, NULL,
0, &handle);
if (ret != EFI_SUCCESS) {
efi_st_error("Failed to load image\n");
return EFI_ST_FAILURE;
}
if (!load_file2_call_count || load_file_call_count) {
efi_st_error("Wrong image loaded\n");
return EFI_ST_FAILURE;
}
ret = boottime->start_image(handle, &exit_data_size, &exit_data);
if (ret != EFI_UNSUPPORTED) {
efi_st_error("Wrong return value from application\n");
return EFI_ST_FAILURE;
}
if (!exit_data || exit_data_size != sizeof(expected_text) ||
memcmp(exit_data, expected_text, sizeof(expected_text))) {
efi_st_error("Incorrect exit data\n");
return EFI_ST_FAILURE;
}
ret = boottime->free_pool(exit_data);
if (ret != EFI_SUCCESS) {
efi_st_error("Failed to free exit data\n");
return EFI_ST_FAILURE;
}
return EFI_ST_SUCCESS;
}
EFI_UNIT_TEST(load_file_protocol) = {
.name = "load file protocol",
.phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
.setup = efi_st_load_file_setup,
.execute = efi_st_load_file_execute,
.teardown = efi_st_load_file_teardown,
};

View File

@ -86,7 +86,6 @@ static int setup(const efi_handle_t handle,
static int execute(void)
{
efi_guid_t lf2_proto_guid = EFI_LOAD_FILE2_PROTOCOL_GUID;
struct efi_load_file_protocol *lf2;
struct efi_device_path *dp2, *dp2_invalid;
efi_status_t status;
@ -99,13 +98,15 @@ static int execute(void)
memset(buffer, 0, sizeof(buffer));
dp2 = (struct efi_device_path *)&dp;
status = boottime->locate_device_path(&lf2_proto_guid, &dp2, &handle);
status = boottime->locate_device_path(&efi_guid_load_file2_protocol,
&dp2, &handle);
if (status != EFI_SUCCESS) {
efi_st_error("Unable to locate device path\n");
return EFI_ST_FAILURE;
}
status = boottime->handle_protocol(handle, &lf2_proto_guid,
status = boottime->handle_protocol(handle,
&efi_guid_load_file2_protocol,
(void **)&lf2);
if (status != EFI_SUCCESS) {
efi_st_error("Unable to locate protocol\n");