mirror of
https://github.com/brain-hackers/u-boot-brain
synced 2024-06-09 23:36:03 +09:00
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:
commit
ddaa949785
130
fs/fat/fat.c
130
fs/fat/fat.c
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
475
lib/efi_selftest/efi_selftest_load_file.c
Normal file
475
lib/efi_selftest/efi_selftest_load_file.c
Normal 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,
|
||||
};
|
|
@ -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");
|
||||
|
|
Loading…
Reference in New Issue
Block a user