mirror of
				https://github.com/smaeul/u-boot.git
				synced 2025-10-31 03:58:17 +00: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
					
				
							
								
								
									
										118
									
								
								fs/fat/fat.c
									
									
									
									
									
								
							
							
						
						
									
										118
									
								
								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 | 		 * The root directory is not cluster-aligned and may be on a | ||||||
| 		 * "negative" cluster, this will be handled specially in | 		 * "negative" cluster, this will be handled specially in | ||||||
| 		 * next_cluster(). | 		 * fat_next_cluster(). | ||||||
| 		 */ | 		 */ | ||||||
| 		mydata->root_cluster = 0; | 		mydata->root_cluster = 0; | ||||||
| 	} | 	} | ||||||
| @ -647,16 +647,17 @@ static int get_fs_info(fsdata *mydata) | |||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | /**
 | ||||||
| /*
 |  * struct fat_itr - directory iterator, to simplify filesystem traversal | ||||||
|  * Directory iterator, to simplify filesystem traversal |  | ||||||
|  * |  * | ||||||
|  * Implements an iterator pattern to traverse directory tables, |  * Implements an iterator pattern to traverse directory tables, | ||||||
|  * transparently handling directory tables split across multiple |  * transparently handling directory tables split across multiple | ||||||
|  * clusters, and the difference between FAT12/FAT16 root directory |  * clusters, and the difference between FAT12/FAT16 root directory | ||||||
|  * (contiguous) and subdirectories + FAT32 root (chained). |  * (contiguous) and subdirectories + FAT32 root (chained). | ||||||
|  * |  * | ||||||
|  * Rough usage: |  * Rough usage | ||||||
|  |  * | ||||||
|  |  * .. code-block:: c | ||||||
|  * |  * | ||||||
|  *     for (fat_itr_root(&itr, fsdata); fat_itr_next(&itr); ) { |  *     for (fat_itr_root(&itr, fsdata); fat_itr_next(&itr); ) { | ||||||
|  *         // to traverse down to a subdirectory pointed to by
 |  *         // to traverse down to a subdirectory pointed to by
 | ||||||
| @ -664,27 +665,70 @@ static int get_fs_info(fsdata *mydata) | |||||||
|  *         fat_itr_child(&itr, &itr); |  *         fat_itr_child(&itr, &itr); | ||||||
|  *     } |  *     } | ||||||
|  * |  * | ||||||
|  * For more complete example, see fat_itr_resolve() |  * For a more complete example, see fat_itr_resolve(). | ||||||
|  |  */ | ||||||
|  | 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 | ||||||
| 	 */ | 	 */ | ||||||
| 
 |  | ||||||
| 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); | 	u8 block[MAX_CLUSTSIZE] __aligned(ARCH_DMA_MINALIGN); | ||||||
| } fat_itr; | }; | ||||||
| 
 | 
 | ||||||
| static int fat_itr_isdir(fat_itr *itr); | static int fat_itr_isdir(fat_itr *itr); | ||||||
| 
 | 
 | ||||||
| @ -702,7 +746,7 @@ static int fat_itr_root(fat_itr *itr, fsdata *fsdata) | |||||||
| 		return -ENXIO; | 		return -ENXIO; | ||||||
| 
 | 
 | ||||||
| 	itr->fsdata = fsdata; | 	itr->fsdata = fsdata; | ||||||
| 	itr->start_clust = 0; | 	itr->start_clust = fsdata->root_cluster; | ||||||
| 	itr->clust = fsdata->root_cluster; | 	itr->clust = fsdata->root_cluster; | ||||||
| 	itr->next_clust = fsdata->root_cluster; | 	itr->next_clust = fsdata->root_cluster; | ||||||
| 	itr->dent = NULL; | 	itr->dent = NULL; | ||||||
| @ -746,6 +790,7 @@ static void fat_itr_child(fat_itr *itr, fat_itr *parent) | |||||||
| 	} else { | 	} else { | ||||||
| 		itr->clust = parent->fsdata->root_cluster; | 		itr->clust = parent->fsdata->root_cluster; | ||||||
| 		itr->next_clust = parent->fsdata->root_cluster; | 		itr->next_clust = parent->fsdata->root_cluster; | ||||||
|  | 		itr->start_clust = parent->fsdata->root_cluster; | ||||||
| 		itr->is_root = 1; | 		itr->is_root = 1; | ||||||
| 	} | 	} | ||||||
| 	itr->dent = NULL; | 	itr->dent = NULL; | ||||||
| @ -753,7 +798,17 @@ static void fat_itr_child(fat_itr *itr, fat_itr *parent) | |||||||
| 	itr->last_cluster = 0; | 	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 */ | 	fsdata *mydata = itr->fsdata;  /* for silly macros */ | ||||||
| 	int ret; | 	int ret; | ||||||
| @ -825,7 +880,7 @@ static dir_entry *next_dent(fat_itr *itr) | |||||||
| { | { | ||||||
| 	if (itr->remaining == 0) { | 	if (itr->remaining == 0) { | ||||||
| 		unsigned nbytes; | 		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? */ | 		/* have we reached the last cluster? */ | ||||||
| 		if (!dent) { | 		if (!dent) { | ||||||
| @ -923,9 +978,13 @@ static int fat_itr_next(fat_itr *itr) | |||||||
| 
 | 
 | ||||||
| 	while (1) { | 	while (1) { | ||||||
| 		dent = next_dent(itr); | 		dent = next_dent(itr); | ||||||
| 		if (!dent) | 		if (!dent) { | ||||||
|  | 			itr->dent_start = NULL; | ||||||
| 			return 0; | 			return 0; | ||||||
| 
 | 		} | ||||||
|  | 		itr->dent_rem = itr->remaining; | ||||||
|  | 		itr->dent_start = itr->dent; | ||||||
|  | 		itr->dent_clust = itr->clust; | ||||||
| 		if (dent->name[0] == DELETED_FLAG) | 		if (dent->name[0] == DELETED_FLAG) | ||||||
| 			continue; | 			continue; | ||||||
| 
 | 
 | ||||||
| @ -1025,6 +1084,7 @@ static int fat_itr_resolve(fat_itr *itr, const char *path, unsigned type) | |||||||
| 			/* point back to itself */ | 			/* point back to itself */ | ||||||
| 			itr->clust = itr->fsdata->root_cluster; | 			itr->clust = itr->fsdata->root_cluster; | ||||||
| 			itr->next_clust = itr->fsdata->root_cluster; | 			itr->next_clust = itr->fsdata->root_cluster; | ||||||
|  | 			itr->start_clust = itr->fsdata->root_cluster; | ||||||
| 			itr->dent = NULL; | 			itr->dent = NULL; | ||||||
| 			itr->remaining = 0; | 			itr->remaining = 0; | ||||||
| 			itr->last_cluster = 0; | 			itr->last_cluster = 0; | ||||||
|  | |||||||
| @ -8,25 +8,185 @@ | |||||||
| #include <common.h> | #include <common.h> | ||||||
| #include <command.h> | #include <command.h> | ||||||
| #include <config.h> | #include <config.h> | ||||||
|  | #include <div64.h> | ||||||
| #include <fat.h> | #include <fat.h> | ||||||
| #include <log.h> | #include <log.h> | ||||||
| #include <malloc.h> | #include <malloc.h> | ||||||
| #include <asm/byteorder.h> |  | ||||||
| #include <part.h> | #include <part.h> | ||||||
|  | #include <rand.h> | ||||||
|  | #include <asm/byteorder.h> | ||||||
| #include <asm/cache.h> | #include <asm/cache.h> | ||||||
| #include <linux/ctype.h> | #include <linux/ctype.h> | ||||||
| #include <div64.h> |  | ||||||
| #include <linux/math64.h> | #include <linux/math64.h> | ||||||
| #include "fat.c" | #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; | 	int i; | ||||||
| 
 | 
 | ||||||
| 	for (i = 0; i < len; i++) { | 	for (i = 0; i < length; ++src) { | ||||||
| 		*str = toupper(*str); | 		char c = *src; | ||||||
| 		str++; | 
 | ||||||
|  | 		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; | static int total_sector; | ||||||
| @ -50,67 +210,6 @@ static int disk_write(__u32 block, __u32 nr_blocks, void *buf) | |||||||
| 	return ret; | 	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 |  * Write fat buffer into block device | ||||||
|  */ |  */ | ||||||
| @ -152,6 +251,66 @@ static int flush_dirty_fat_buffer(fsdata *mydata) | |||||||
| 	return 0; | 	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', |  * Set the file name information from 'name' into 'slotptr', | ||||||
|  */ |  */ | ||||||
| @ -221,15 +380,18 @@ name11_12: | |||||||
| 	return 1; | 	return 1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int new_dir_table(fat_itr *itr); |  | ||||||
| static int flush_dir(fat_itr *itr); | static int flush_dir(fat_itr *itr); | ||||||
| 
 | 
 | ||||||
| /*
 | /**
 | ||||||
|  * Fill dir_slot entries with appropriate name, id, and attr |  * fill_dir_slot() - fill directory entries for long name | ||||||
|  * 'itr' will point to a next entry |  * | ||||||
|  |  * @itr:	directory iterator | ||||||
|  |  * @l_name:	long name | ||||||
|  |  * @shortname:	short name | ||||||
|  |  * Return:	0 for success, -errno otherwise | ||||||
|  */ |  */ | ||||||
| static int | 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)]; | 	__u8 temp_dir_slot_buffer[MAX_LFN_SLOT * sizeof(dir_slot)]; | ||||||
| 	dir_slot *slotptr = (dir_slot *)temp_dir_slot_buffer; | 	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; | 	int idx = 0, ret; | ||||||
| 
 | 
 | ||||||
| 	/* Get short file name checksum value */ | 	/* Get short file name checksum value */ | ||||||
| 	checksum = mkcksum(itr->dent->name, itr->dent->ext); | 	checksum = mkcksum(shortname, shortname + 8); | ||||||
| 
 | 
 | ||||||
| 	do { | 	do { | ||||||
| 		memset(slotptr, 0x00, sizeof(dir_slot)); | 		memset(slotptr, 0x00, sizeof(dir_slot)); | ||||||
| @ -259,11 +421,9 @@ fill_dir_slot(fat_itr *itr, const char *l_name) | |||||||
| 		if (itr->remaining == 0) | 		if (itr->remaining == 0) | ||||||
| 			flush_dir(itr); | 			flush_dir(itr); | ||||||
| 
 | 
 | ||||||
| 		/* allocate a cluster for more entries */ | 		next_dent(itr); | ||||||
| 		if (!fat_itr_next(itr) && !itr->dent) | 		if (!itr->dent) | ||||||
| 			if ((itr->is_root && itr->fsdata->fatsize != 32) || | 			return -EIO; | ||||||
| 			    new_dir_table(itr)) |  | ||||||
| 				return -1; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| @ -636,17 +796,32 @@ static int find_empty_cluster(fsdata *mydata) | |||||||
| 	return entry; | 	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) | static int new_dir_table(fat_itr *itr) | ||||||
| { | { | ||||||
| 	fsdata *mydata = itr->fsdata; | 	fsdata *mydata = itr->fsdata; | ||||||
| 	int dir_newclust = 0; | 	int dir_newclust = 0; | ||||||
|  | 	int dir_oldclust = itr->clust; | ||||||
| 	unsigned int bytesperclust = mydata->clust_size * mydata->sect_size; | 	unsigned int bytesperclust = mydata->clust_size * mydata->sect_size; | ||||||
| 
 | 
 | ||||||
| 	dir_newclust = find_empty_cluster(mydata); | 	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) | 	if (mydata->fatsize == 32) | ||||||
| 		set_fatent_value(mydata, dir_newclust, 0xffffff8); | 		set_fatent_value(mydata, dir_newclust, 0xffffff8); | ||||||
| 	else if (mydata->fatsize == 16) | 	else if (mydata->fatsize == 16) | ||||||
| @ -654,13 +829,8 @@ static int new_dir_table(fat_itr *itr) | |||||||
| 	else if (mydata->fatsize == 12) | 	else if (mydata->fatsize == 12) | ||||||
| 		set_fatent_value(mydata, dir_newclust, 0xff8); | 		set_fatent_value(mydata, dir_newclust, 0xff8); | ||||||
| 
 | 
 | ||||||
| 	itr->clust = dir_newclust; |  | ||||||
| 	itr->next_clust = dir_newclust; |  | ||||||
| 
 |  | ||||||
| 	if (flush_dirty_fat_buffer(mydata) < 0) | 	if (flush_dirty_fat_buffer(mydata) < 0) | ||||||
| 		return -1; | 		return -EIO; | ||||||
| 
 |  | ||||||
| 	memset(itr->block, 0x00, bytesperclust); |  | ||||||
| 
 | 
 | ||||||
| 	itr->dent = (dir_entry *)itr->block; | 	itr->dent = (dir_entry *)itr->block; | ||||||
| 	itr->last_cluster = 1; | 	itr->last_cluster = 1; | ||||||
| @ -961,24 +1131,35 @@ getit: | |||||||
| 	return 0; | 	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, | 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); | 	set_start_cluster(mydata, dentptr, start_cluster); | ||||||
| 	dentptr->size = cpu_to_le32(size); | 	dentptr->size = cpu_to_le32(size); | ||||||
| 
 | 
 | ||||||
| 	dentptr->attr = attr; | 	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 |  * find_directory_entry() - find a directory entry by filename | ||||||
|  * If the directory entry is not found, |  * | ||||||
|  * the new position for writing a directory entry will be returned |  * @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) | 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; | 			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; | 	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); | 		retdent->size = cpu_to_le32(pos + size); | ||||||
| 	} else { | 	} else { | ||||||
| 		/* Create a new file */ | 		/* Create a new file */ | ||||||
|  | 		char shortname[SHORT_NAME_SIZE]; | ||||||
|  | 		int ndent; | ||||||
| 
 | 
 | ||||||
| 		if (itr->is_root) { | 		if (itr->is_root) { | ||||||
| 			/* root dir cannot have "." or ".." */ | 			/* 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) { | 		if (pos) { | ||||||
| 			/* No hole allowed */ | 			/* No hole allowed */ | ||||||
| 			ret = -EINVAL; | 			ret = -EINVAL; | ||||||
| 			goto exit; | 			goto exit; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		memset(itr->dent, 0, sizeof(*itr->dent)); | 		/* Check if long name is needed */ | ||||||
| 
 | 		ndent = set_name(itr, filename, shortname); | ||||||
| 		/* Calculate checksum for short name */ | 		if (ndent < 0) { | ||||||
| 		set_name(itr->dent, filename); | 			ret = ndent; | ||||||
| 
 | 			goto exit; | ||||||
|  | 		} | ||||||
|  | 		ret = fat_find_empty_dentries(itr, ndent); | ||||||
|  | 		if (ret) | ||||||
|  | 			goto exit; | ||||||
|  | 		if (ndent > 1) { | ||||||
| 			/* Set long name entries */ | 			/* Set long name entries */ | ||||||
| 		if (fill_dir_slot(itr, filename)) { | 			ret = fill_dir_slot(itr, filename, shortname); | ||||||
| 			ret = -EIO; | 			if (ret) | ||||||
| 				goto exit; | 				goto exit; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		/* Set short name entry */ | 		/* Set short name entry */ | ||||||
| 		fill_dentry(itr->fsdata, itr->dent, filename, 0, size, | 		fill_dentry(itr->fsdata, itr->dent, shortname, 0, size, | ||||||
| 			    ATTR_ARCH); | 			    ATTR_ARCH); | ||||||
| 
 | 
 | ||||||
| 		retdent = itr->dent; | 		retdent = itr->dent; | ||||||
| @ -1270,27 +1445,91 @@ exit: | |||||||
| 	return count; | 	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; | 	fsdata *mydata = itr->fsdata; | ||||||
| 	dir_entry *dentptr = itr->dent; | 	dir_entry *dent = itr->dent; | ||||||
| 
 | 
 | ||||||
| 	/* free cluster blocks */ | 	/* free cluster blocks */ | ||||||
| 	clear_fatent(mydata, START(dentptr)); | 	clear_fatent(mydata, START(dent)); | ||||||
| 	if (flush_dirty_fat_buffer(mydata) < 0) { | 	if (flush_dirty_fat_buffer(mydata) < 0) { | ||||||
| 		printf("Error: flush fat buffer\n"); | 		printf("Error: flush fat buffer\n"); | ||||||
| 		return -EIO; | 		return -EIO; | ||||||
| 	} | 	} | ||||||
|  | 	/* Position to first directory entry for long name */ | ||||||
|  | 	if (itr->clust != itr->dent_clust) { | ||||||
|  | 		int ret; | ||||||
| 
 | 
 | ||||||
| 	/*
 | 		ret = fat_move_to_cluster(itr, itr->dent_clust); | ||||||
| 	 * update a directory entry | 		if (ret) | ||||||
| 	 * TODO: | 			return ret; | ||||||
| 	 *  - long file name support | 	} | ||||||
| 	 *  - find and mark the "new" first invalid entry as name[0]=0x00 | 	itr->dent = itr->dent_start; | ||||||
| 	 */ | 	itr->remaining = itr->dent_rem; | ||||||
| 	memset(dentptr, 0, sizeof(*dentptr)); | 	dent = itr->dent_start; | ||||||
| 	dentptr->name[0] = 0xe5; | 	/* 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)) { | 	if (flush_dir(itr)) { | ||||||
| 		printf("error: writing directory entry\n"); | 		printf("error: writing directory entry\n"); | ||||||
| 		return -EIO; | 		return -EIO; | ||||||
| @ -1360,7 +1599,7 @@ int fat_unlink(const char *filename) | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ret = delete_dentry(itr); | 	ret = delete_dentry_long(itr); | ||||||
| 
 | 
 | ||||||
| exit: | exit: | ||||||
| 	free(fsdata.fatbuf); | 	free(fsdata.fatbuf); | ||||||
| @ -1424,6 +1663,9 @@ int fat_mkdir(const char *new_dirname) | |||||||
| 		ret = -EEXIST; | 		ret = -EEXIST; | ||||||
| 		goto exit; | 		goto exit; | ||||||
| 	} else { | 	} else { | ||||||
|  | 		char shortname[SHORT_NAME_SIZE]; | ||||||
|  | 		int ndent; | ||||||
|  | 
 | ||||||
| 		if (itr->is_root) { | 		if (itr->is_root) { | ||||||
| 			/* root dir cannot have "." or ".." */ | 			/* root dir cannot have "." or ".." */ | ||||||
| 			if (!strcmp(l_dirname, ".") || | 			if (!strcmp(l_dirname, ".") || | ||||||
| @ -1433,20 +1675,24 @@ int fat_mkdir(const char *new_dirname) | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (!itr->dent) { | 		/* Check if long name is needed */ | ||||||
| 			printf("Error: allocating new dir entry\n"); | 		ndent = set_name(itr, dirname, shortname); | ||||||
| 			ret = -EIO; | 		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, dirname, shortname); | ||||||
|  | 			if (ret) | ||||||
| 				goto exit; | 				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); |  | ||||||
| 
 |  | ||||||
| 		/* Set attribute as archive for regular file */ | 		/* 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); | 			    ATTR_DIR | ATTR_ARCH); | ||||||
| 
 | 
 | ||||||
| 		retdent = itr->dent; | 		retdent = itr->dent; | ||||||
| @ -1468,6 +1714,10 @@ int fat_mkdir(const char *new_dirname) | |||||||
| 	memcpy(dotdent[1].name, "..      ", 8); | 	memcpy(dotdent[1].name, "..      ", 8); | ||||||
| 	memcpy(dotdent[1].ext, "   ", 3); | 	memcpy(dotdent[1].ext, "   ", 3); | ||||||
| 	dotdent[1].attr = ATTR_DIR | ATTR_ARCH; | 	dotdent[1].attr = ATTR_DIR | ATTR_ARCH; | ||||||
|  | 
 | ||||||
|  | 	if (itr->is_root) | ||||||
|  | 		set_start_cluster(mydata, &dotdent[1], 0); | ||||||
|  | 	else | ||||||
| 		set_start_cluster(mydata, &dotdent[1], itr->start_clust); | 		set_start_cluster(mydata, &dotdent[1], itr->start_clust); | ||||||
| 
 | 
 | ||||||
| 	ret = set_contents(mydata, retdent, 0, (__u8 *)dotdent, | 	ret = set_contents(mydata, retdent, 0, (__u8 *)dotdent, | ||||||
|  | |||||||
| @ -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; | extern const efi_guid_t efi_guid_device_path_utilities_protocol; | ||||||
| /* GUID of the deprecated Unicode collation protocol */ | /* GUID of the deprecated Unicode collation protocol */ | ||||||
| extern const efi_guid_t efi_guid_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 */ | /* GUID of the Unicode collation protocol */ | ||||||
| extern const efi_guid_t efi_guid_unicode_collation_protocol2; | extern const efi_guid_t efi_guid_unicode_collation_protocol2; | ||||||
| extern const efi_guid_t efi_guid_hii_config_routing_protocol; | 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, | efi_status_t efi_add_protocol(const efi_handle_t handle, | ||||||
| 			      const efi_guid_t *protocol, | 			      const efi_guid_t *protocol, | ||||||
| 			      void *protocol_interface); | 			      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 */ | /* Delete protocol from a handle */ | ||||||
| efi_status_t efi_remove_protocol(const efi_handle_t handle, | efi_status_t efi_remove_protocol(const efi_handle_t handle, | ||||||
| 				 const efi_guid_t *protocol, | 				 const efi_guid_t *protocol, | ||||||
|  | |||||||
| @ -9,8 +9,9 @@ | |||||||
| #ifndef _FAT_H_ | #ifndef _FAT_H_ | ||||||
| #define _FAT_H_ | #define _FAT_H_ | ||||||
| 
 | 
 | ||||||
| #include <asm/byteorder.h> |  | ||||||
| #include <fs.h> | #include <fs.h> | ||||||
|  | #include <asm/byteorder.h> | ||||||
|  | #include <asm/cache.h> | ||||||
| 
 | 
 | ||||||
| struct disk_partition; | struct disk_partition; | ||||||
| 
 | 
 | ||||||
| @ -179,6 +180,9 @@ typedef struct { | |||||||
| 	int	fats;		/* Number of FATs */ | 	int	fats;		/* Number of FATs */ | ||||||
| } fsdata; | } fsdata; | ||||||
| 
 | 
 | ||||||
|  | struct fat_itr; | ||||||
|  | typedef struct fat_itr fat_itr; | ||||||
|  | 
 | ||||||
| static inline u32 clust_to_sect(fsdata *fsdata, u32 clust) | static inline u32 clust_to_sect(fsdata *fsdata, u32 clust) | ||||||
| { | { | ||||||
| 	return fsdata->data_begin + clust * fsdata->clust_size; | 	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_unlink(const char *filename); | ||||||
| int fat_mkdir(const char *dirname); | int fat_mkdir(const char *dirname); | ||||||
| void fat_close(void); | void fat_close(void); | ||||||
|  | void *fat_next_cluster(fat_itr *itr, unsigned int *nbytes); | ||||||
| #endif /* _FAT_H_ */ | #endif /* _FAT_H_ */ | ||||||
|  | |||||||
| @ -168,7 +168,7 @@ config REGEX | |||||||
| choice | choice | ||||||
| 	prompt "Pseudo-random library support type" | 	prompt "Pseudo-random library support type" | ||||||
| 	depends on NET_RANDOM_ETHADDR || RANDOM_UUID || CMD_UUID || \ | 	depends on NET_RANDOM_ETHADDR || RANDOM_UUID || CMD_UUID || \ | ||||||
| 		   RNG_SANDBOX || UT_LIB && AES | 		   RNG_SANDBOX || UT_LIB && AES || FAT_WRITE | ||||||
| 	default LIB_RAND | 	default LIB_RAND | ||||||
| 	help | 	help | ||||||
| 	  Select the library to provide pseudo-random number generator | 	  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-$(CONFIG_EFI_DEVICE_PATH_TO_TEXT) += efi_device_path_to_text.o | ||||||
| obj-y += efi_device_path_utilities.o | obj-y += efi_device_path_utilities.o | ||||||
| obj-y += efi_file.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_image_loader.o | ||||||
| obj-y += efi_memory.o | obj-y += efi_memory.o | ||||||
| obj-y += efi_root_node.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) */ | /* event group ResetSystem() invoked (before ExitBootServices) */ | ||||||
| const efi_guid_t efi_guid_event_group_reset_system = | const efi_guid_t efi_guid_event_group_reset_system = | ||||||
| 			EFI_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( | static efi_status_t EFIAPI efi_disconnect_controller( | ||||||
| 					efi_handle_t controller_handle, | 					efi_handle_t controller_handle, | ||||||
| @ -1770,7 +1773,89 @@ 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 |  * Read a file into a buffer allocated as EFI_BOOT_SERVICES_DATA. It is the | ||||||
|  * callers obligation to update the memory type as needed. |  * callers obligation to update the memory type as needed. | ||||||
| @ -1781,19 +1866,15 @@ failure: | |||||||
|  * Return:		status code |  * Return:		status code | ||||||
|  */ |  */ | ||||||
| static | 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) | 				      void **buffer, efi_uintn_t *size) | ||||||
| { | { | ||||||
| 	struct efi_file_info *info = NULL; | 	struct efi_file_info *info = NULL; | ||||||
| 	struct efi_file_handle *f; | 	struct efi_file_handle *f; | ||||||
| 	static efi_status_t ret; | 	efi_status_t ret; | ||||||
| 	u64 addr; | 	u64 addr; | ||||||
| 	efi_uintn_t bs; | 	efi_uintn_t bs; | ||||||
| 
 | 
 | ||||||
| 	/* In case of failure nothing is returned */ |  | ||||||
| 	*buffer = NULL; |  | ||||||
| 	*size = 0; |  | ||||||
| 
 |  | ||||||
| 	/* Open file */ | 	/* Open file */ | ||||||
| 	f = efi_file_from_path(file_path); | 	f = efi_file_from_path(file_path); | ||||||
| 	if (!f) | 	if (!f) | ||||||
| @ -1841,6 +1922,86 @@ error: | |||||||
| 	return ret; | 	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 |  * efi_load_image() - load an EFI image into memory | ||||||
|  * @boot_policy:   true for request originating from the boot manager |  * @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) { | 	if (!source_buffer) { | ||||||
| 		ret = efi_load_image_from_path(file_path, &dest_buffer, | 		ret = efi_load_image_from_path(boot_policy, file_path, | ||||||
| 					       &source_size); | 					       &dest_buffer, &source_size); | ||||||
| 		if (ret != EFI_SUCCESS) | 		if (ret != EFI_SUCCESS) | ||||||
| 			goto error; | 			goto error; | ||||||
| 	} else { | 	} else { | ||||||
| @ -2403,88 +2564,6 @@ found: | |||||||
| 	return EFI_EXIT(EFI_SUCCESS); | 	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 |  * efi_install_multiple_protocol_interfaces() - Install multiple protocol | ||||||
|  *                                              interfaces |  *                                              interfaces | ||||||
| @ -2700,7 +2779,7 @@ static void EFIAPI efi_set_mem(void *buffer, size_t size, uint8_t value) | |||||||
|  * |  * | ||||||
|  * Return: status code |  * Return: status code | ||||||
|  */ |  */ | ||||||
| static efi_status_t efi_protocol_open( | efi_status_t efi_protocol_open( | ||||||
| 			struct efi_handler *handler, | 			struct efi_handler *handler, | ||||||
| 			void **protocol_interface, void *agent_handle, | 			void **protocol_interface, void *agent_handle, | ||||||
| 			void *controller_handle, uint32_t attributes) | 			void *controller_handle, uint32_t attributes) | ||||||
|  | |||||||
| @ -376,6 +376,23 @@ static efi_status_t efi_disk_add_dev( | |||||||
| 	/* Fill in object data */ | 	/* Fill in object data */ | ||||||
| 	if (part) { | 	if (part) { | ||||||
| 		struct efi_device_path *node = efi_dp_part_node(desc, 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); | 		diskobj->dp = efi_dp_append_node(dp_parent, node); | ||||||
| 		efi_free_pool(node); | 		efi_free_pool(node); | ||||||
| @ -453,6 +470,9 @@ static efi_status_t efi_disk_add_dev( | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return EFI_SUCCESS; | 	return EFI_SUCCESS; | ||||||
|  | error: | ||||||
|  | 	efi_delete_handle(&diskobj->header); | ||||||
|  | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  | |||||||
| @ -4,6 +4,10 @@ | |||||||
|  * |  * | ||||||
|  * Copyright (c) 2017 Leif Lindholm |  * Copyright (c) 2017 Leif Lindholm | ||||||
|  * Copyright (c) 2018 AKASHI Takahiro, Linaro Limited |  * 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> | #include <common.h> | ||||||
|  | |||||||
| @ -12,9 +12,6 @@ | |||||||
| #include <efi_loader.h> | #include <efi_loader.h> | ||||||
| #include <efi_load_initrd.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 | static efi_status_t EFIAPI | ||||||
| efi_load_file2_initrd(struct efi_load_file_protocol *this, | efi_load_file2_initrd(struct efi_load_file_protocol *this, | ||||||
| 		      struct efi_device_path *file_path, bool boot_policy, | 		      struct efi_device_path *file_path, bool boot_policy, | ||||||
|  | |||||||
| @ -77,9 +77,6 @@ efi_status_t efi_root_node_register(void) | |||||||
| 			 /* HII database protocol */ | 			 /* HII database protocol */ | ||||||
| 			 &efi_guid_hii_database_protocol, | 			 &efi_guid_hii_database_protocol, | ||||||
| 			 (void *)&efi_hii_database, | 			 (void *)&efi_hii_database, | ||||||
| 			 /* HII configuration routing protocol */ |  | ||||||
| 			 &efi_guid_hii_config_routing_protocol, |  | ||||||
| 			 (void *)&efi_hii_config_routing, |  | ||||||
| #endif | #endif | ||||||
| 			 NULL)); | 			 NULL)); | ||||||
| 	efi_root->type = EFI_OBJECT_TYPE_U_BOOT_FIRMWARE; | 	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 | #ifdef CONFIG_EFI_HAVE_RUNTIME_RESET | ||||||
| 	rt_table->runtime_services_supported |= EFI_RT_SUPPORTED_RESET_SYSTEM; | 	rt_table->runtime_services_supported |= EFI_RT_SUPPORTED_RESET_SYSTEM; | ||||||
| #endif | #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, | 	ret = efi_install_configuration_table(&efi_rt_properties_table_guid, | ||||||
| 					      rt_table); | 					      rt_table); | ||||||
|  | |||||||
| @ -25,9 +25,12 @@ efi_selftest_crc32.o \ | |||||||
| efi_selftest_devicepath_util.o \ | efi_selftest_devicepath_util.o \ | ||||||
| efi_selftest_events.o \ | efi_selftest_events.o \ | ||||||
| efi_selftest_event_groups.o \ | efi_selftest_event_groups.o \ | ||||||
|  | efi_selftest_exception.o \ | ||||||
| efi_selftest_exitbootservices.o \ | efi_selftest_exitbootservices.o \ | ||||||
| efi_selftest_gop.o \ | efi_selftest_gop.o \ | ||||||
|  | efi_selftest_load_file.o \ | ||||||
| efi_selftest_loaded_image.o \ | efi_selftest_loaded_image.o \ | ||||||
|  | efi_selftest_loadimage.o \ | ||||||
| efi_selftest_manageprotocols.o \ | efi_selftest_manageprotocols.o \ | ||||||
| efi_selftest_mem.o \ | efi_selftest_mem.o \ | ||||||
| efi_selftest_memory.o \ | efi_selftest_memory.o \ | ||||||
| @ -35,6 +38,8 @@ efi_selftest_open_protocol.o \ | |||||||
| efi_selftest_register_notify.o \ | efi_selftest_register_notify.o \ | ||||||
| efi_selftest_reset.o \ | efi_selftest_reset.o \ | ||||||
| efi_selftest_set_virtual_address_map.o \ | efi_selftest_set_virtual_address_map.o \ | ||||||
|  | efi_selftest_startimage_exit.o \ | ||||||
|  | efi_selftest_startimage_return.o \ | ||||||
| efi_selftest_textinput.o \ | efi_selftest_textinput.o \ | ||||||
| efi_selftest_textinputex.o \ | efi_selftest_textinputex.o \ | ||||||
| efi_selftest_textoutput.o \ | efi_selftest_textoutput.o \ | ||||||
| @ -65,12 +70,6 @@ ifeq ($(CONFIG_BLK)$(CONFIG_DOS_PARTITION),yy) | |||||||
| obj-y += efi_selftest_block_device.o | obj-y += efi_selftest_block_device.o | ||||||
| endif | endif | ||||||
| 
 | 
 | ||||||
| obj-y += \
 |  | ||||||
| efi_selftest_exception.o \ |  | ||||||
| efi_selftest_loadimage.o \ |  | ||||||
| efi_selftest_startimage_exit.o \ |  | ||||||
| efi_selftest_startimage_return.o |  | ||||||
| 
 |  | ||||||
| targets += \
 | targets += \
 | ||||||
| efi_miniapp_file_image_exception.h \ | efi_miniapp_file_image_exception.h \ | ||||||
| efi_miniapp_file_image_exit.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)/../../tools/file2include $(obj)/efi_selftest_miniapp_return.efi > \
 | ||||||
| 	$(obj)/efi_miniapp_file_image_return.h | 	$(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_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_exit.o: $(obj)/efi_miniapp_file_image_exit.h | ||||||
| 
 | 
 | ||||||
| $(obj)/efi_selftest_startimage_return.o: $(obj)/efi_miniapp_file_image_return.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) | static int execute(void) | ||||||
| { | { | ||||||
| 	efi_guid_t lf2_proto_guid = EFI_LOAD_FILE2_PROTOCOL_GUID; |  | ||||||
| 	struct efi_load_file_protocol *lf2; | 	struct efi_load_file_protocol *lf2; | ||||||
| 	struct efi_device_path *dp2, *dp2_invalid; | 	struct efi_device_path *dp2, *dp2_invalid; | ||||||
| 	efi_status_t status; | 	efi_status_t status; | ||||||
| @ -99,13 +98,15 @@ static int execute(void) | |||||||
| 	memset(buffer, 0, sizeof(buffer)); | 	memset(buffer, 0, sizeof(buffer)); | ||||||
| 
 | 
 | ||||||
| 	dp2 = (struct efi_device_path *)&dp; | 	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) { | 	if (status != EFI_SUCCESS) { | ||||||
| 		efi_st_error("Unable to locate device path\n"); | 		efi_st_error("Unable to locate device path\n"); | ||||||
| 		return EFI_ST_FAILURE; | 		return EFI_ST_FAILURE; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	status = boottime->handle_protocol(handle, &lf2_proto_guid, | 	status = boottime->handle_protocol(handle, | ||||||
|  | 					   &efi_guid_load_file2_protocol, | ||||||
| 					   (void **)&lf2); | 					   (void **)&lf2); | ||||||
| 	if (status != EFI_SUCCESS) { | 	if (status != EFI_SUCCESS) { | ||||||
| 		efi_st_error("Unable to locate protocol\n"); | 		efi_st_error("Unable to locate protocol\n"); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user