mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-10-31 16:54:21 +00:00 
			
		
		
		
	lib: Add early cpio decoder
Add a simple cpio decoder without library dependencies for the purpose of extracting components from the initramfs blob for early kernel uses. Intended consumers so far are microcode and ACPI override. Signed-off-by: H. Peter Anvin <hpa@linux.intel.com> Link: http://lkml.kernel.org/r/1349043837-22659-2-git-send-email-trenn@suse.de Cc: Len Brown <lenb@kernel.org> Cc: Fenghua Yu <fenghua.yu@intel.com> Signed-off-by: Thomas Renninger <trenn@suse.de> Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
This commit is contained in:
		
							parent
							
								
									979570e029
								
							
						
					
					
						commit
						e6459606b0
					
				
					 3 changed files with 163 additions and 1 deletions
				
			
		
							
								
								
									
										17
									
								
								include/linux/earlycpio.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								include/linux/earlycpio.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | ||||||
|  | #ifndef _LINUX_EARLYCPIO_H | ||||||
|  | #define _LINUX_EARLYCPIO_H | ||||||
|  | 
 | ||||||
|  | #include <linux/types.h> | ||||||
|  | 
 | ||||||
|  | #define MAX_CPIO_FILE_NAME 18 | ||||||
|  | 
 | ||||||
|  | struct cpio_data { | ||||||
|  | 	void *data; | ||||||
|  | 	size_t size; | ||||||
|  | 	char name[MAX_CPIO_FILE_NAME]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct cpio_data find_cpio_data(const char *path, void *data, size_t len, | ||||||
|  | 				long *offset); | ||||||
|  | 
 | ||||||
|  | #endif /* _LINUX_EARLYCPIO_H */ | ||||||
|  | @ -12,7 +12,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \ | ||||||
| 	 idr.o int_sqrt.o extable.o prio_tree.o \
 | 	 idr.o int_sqrt.o extable.o prio_tree.o \
 | ||||||
| 	 sha1.o md5.o irq_regs.o reciprocal_div.o argv_split.o \
 | 	 sha1.o md5.o irq_regs.o reciprocal_div.o argv_split.o \
 | ||||||
| 	 proportions.o flex_proportions.o prio_heap.o ratelimit.o show_mem.o \
 | 	 proportions.o flex_proportions.o prio_heap.o ratelimit.o show_mem.o \
 | ||||||
| 	 is_single_threaded.o plist.o decompress.o | 	 is_single_threaded.o plist.o decompress.o earlycpio.o | ||||||
| 
 | 
 | ||||||
| lib-$(CONFIG_MMU) += ioremap.o | lib-$(CONFIG_MMU) += ioremap.o | ||||||
| lib-$(CONFIG_SMP) += cpumask.o | lib-$(CONFIG_SMP) += cpumask.o | ||||||
|  |  | ||||||
							
								
								
									
										145
									
								
								lib/earlycpio.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								lib/earlycpio.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,145 @@ | ||||||
|  | /* ----------------------------------------------------------------------- *
 | ||||||
|  |  * | ||||||
|  |  *   Copyright 2012 Intel Corporation; author H. Peter Anvin | ||||||
|  |  * | ||||||
|  |  *   This file is part of the Linux kernel, and is made available | ||||||
|  |  *   under the terms of the GNU General Public License version 2, as | ||||||
|  |  *   published by the Free Software Foundation. | ||||||
|  |  * | ||||||
|  |  *   This program is distributed in the hope it will be useful, but | ||||||
|  |  *   WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||||
|  |  *   General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * ----------------------------------------------------------------------- */ | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * earlycpio.c | ||||||
|  |  * | ||||||
|  |  * Find a specific cpio member; must precede any compressed content. | ||||||
|  |  * This is used to locate data items in the initramfs used by the | ||||||
|  |  * kernel itself during early boot (before the main initramfs is | ||||||
|  |  * decompressed.)  It is the responsibility of the initramfs creator | ||||||
|  |  * to ensure that these items are uncompressed at the head of the | ||||||
|  |  * blob.  Depending on the boot loader or package tool that may be a | ||||||
|  |  * separate file or part of the same file. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include <linux/earlycpio.h> | ||||||
|  | #include <linux/kernel.h> | ||||||
|  | #include <linux/string.h> | ||||||
|  | 
 | ||||||
|  | enum cpio_fields { | ||||||
|  | 	C_MAGIC, | ||||||
|  | 	C_INO, | ||||||
|  | 	C_MODE, | ||||||
|  | 	C_UID, | ||||||
|  | 	C_GID, | ||||||
|  | 	C_NLINK, | ||||||
|  | 	C_MTIME, | ||||||
|  | 	C_FILESIZE, | ||||||
|  | 	C_MAJ, | ||||||
|  | 	C_MIN, | ||||||
|  | 	C_RMAJ, | ||||||
|  | 	C_RMIN, | ||||||
|  | 	C_NAMESIZE, | ||||||
|  | 	C_CHKSUM, | ||||||
|  | 	C_NFIELDS | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * cpio_data find_cpio_data - Search for files in an uncompressed cpio | ||||||
|  |  * @path:   The directory to search for, including a slash at the end | ||||||
|  |  * @data:   Pointer to the the cpio archive or a header inside | ||||||
|  |  * @len:    Remaining length of the cpio based on data pointer | ||||||
|  |  * @offset: When a matching file is found, this is the offset to the | ||||||
|  |  *          beginning of the cpio. It can be used to iterate through | ||||||
|  |  *          the cpio to find all files inside of a directory path | ||||||
|  |  * | ||||||
|  |  * @return: struct cpio_data containing the address, length and | ||||||
|  |  *          filename (with the directory path cut off) of the found file. | ||||||
|  |  *          If you search for a filename and not for files in a directory, | ||||||
|  |  *          pass the absolute path of the filename in the cpio and make sure | ||||||
|  |  *          the match returned an empty filename string. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | struct cpio_data __cpuinit find_cpio_data(const char *path, void *data, | ||||||
|  | 					  size_t len,  long *offset) | ||||||
|  | { | ||||||
|  | 	const size_t cpio_header_len = 8*C_NFIELDS - 2; | ||||||
|  | 	struct cpio_data cd = { NULL, 0, "" }; | ||||||
|  | 	const char *p, *dptr, *nptr; | ||||||
|  | 	unsigned int ch[C_NFIELDS], *chp, v; | ||||||
|  | 	unsigned char c, x; | ||||||
|  | 	size_t mypathsize = strlen(path); | ||||||
|  | 	int i, j; | ||||||
|  | 
 | ||||||
|  | 	p = data; | ||||||
|  | 
 | ||||||
|  | 	while (len > cpio_header_len) { | ||||||
|  | 		if (!*p) { | ||||||
|  | 			/* All cpio headers need to be 4-byte aligned */ | ||||||
|  | 			p += 4; | ||||||
|  | 			len -= 4; | ||||||
|  | 			continue; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		j = 6;		/* The magic field is only 6 characters */ | ||||||
|  | 		chp = ch; | ||||||
|  | 		for (i = C_NFIELDS; i; i--) { | ||||||
|  | 			v = 0; | ||||||
|  | 			while (j--) { | ||||||
|  | 				v <<= 4; | ||||||
|  | 				c = *p++; | ||||||
|  | 
 | ||||||
|  | 				x = c - '0'; | ||||||
|  | 				if (x < 10) { | ||||||
|  | 					v += x; | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				x = (c | 0x20) - 'a'; | ||||||
|  | 				if (x < 6) { | ||||||
|  | 					v += x + 10; | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				goto quit; /* Invalid hexadecimal */ | ||||||
|  | 			} | ||||||
|  | 			*chp++ = v; | ||||||
|  | 			j = 8;	/* All other fields are 8 characters */ | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if ((ch[C_MAGIC] - 0x070701) > 1) | ||||||
|  | 			goto quit; /* Invalid magic */ | ||||||
|  | 
 | ||||||
|  | 		len -= cpio_header_len; | ||||||
|  | 
 | ||||||
|  | 		dptr = PTR_ALIGN(p + ch[C_NAMESIZE], 4); | ||||||
|  | 		nptr = PTR_ALIGN(dptr + ch[C_FILESIZE], 4); | ||||||
|  | 
 | ||||||
|  | 		if (nptr > p + len || dptr < p || nptr < dptr) | ||||||
|  | 			goto quit; /* Buffer overrun */ | ||||||
|  | 
 | ||||||
|  | 		if ((ch[C_MODE] & 0170000) == 0100000 && | ||||||
|  | 		    ch[C_NAMESIZE] >= mypathsize && | ||||||
|  | 		    !memcmp(p, path, mypathsize)) { | ||||||
|  | 			*offset = (long)nptr - (long)data; | ||||||
|  | 			if (ch[C_NAMESIZE] - mypathsize >= MAX_CPIO_FILE_NAME) { | ||||||
|  | 				pr_warn( | ||||||
|  | 				"File %s exceeding MAX_CPIO_FILE_NAME [%d]\n", | ||||||
|  | 				p, MAX_CPIO_FILE_NAME); | ||||||
|  | 			} | ||||||
|  | 			strlcpy(cd.name, p + mypathsize, MAX_CPIO_FILE_NAME); | ||||||
|  | 
 | ||||||
|  | 			cd.data = (void *)dptr; | ||||||
|  | 			cd.size = ch[C_FILESIZE]; | ||||||
|  | 			return cd; /* Found it! */ | ||||||
|  | 		} | ||||||
|  | 		len -= (nptr - p); | ||||||
|  | 		p = nptr; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | quit: | ||||||
|  | 	return cd; | ||||||
|  | } | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 H. Peter Anvin
						H. Peter Anvin