[LinuxBIOS] r484 - LinuxBIOSv3/lib

svn at openbios.org svn at openbios.org
Wed Aug 29 18:42:58 CEST 2007


Author: rminnich
Date: 2007-08-29 18:42:58 +0200 (Wed, 29 Aug 2007)
New Revision: 484

Modified:
   LinuxBIOSv3/lib/lar.c
Log:
This patch is for two things that are too hard to seperate, as they affect
one common file.

The first is the noelf option, which is a simple
modification to look for payloads in the form
payload/segmentX where X is a number.
The segments are assumed to be contiguously numbered and the code
steps when the first search fails (i.e. if 0 and 1 are there, and 2 
is not, the code stops and will not try to find 3). 
The lar code will use the loadaddress to load the segment. Currently,
the lar code will not run each loaded segment, but we need to consider
this for uwe's lbmenu work. Consider this implementation somewhat 
preliminary until we integrate lbmenu. There is the complex issue of 
interdependent segments, as in the kernel, where no single segment
can run until all are loaded. 

The second is the fix for improperly wrapping to 0 when
searching the LAR.

This has been tested with filo and BOCHS.

Signed-off-by: Ronald G. Minnich <rminnich at gmail.com>
Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006 at gmx.net>



Modified: LinuxBIOSv3/lib/lar.c
===================================================================
--- LinuxBIOSv3/lib/lar.c	2007-08-29 15:26:54 UTC (rev 483)
+++ LinuxBIOSv3/lib/lar.c	2007-08-29 16:42:58 UTC (rev 484)
@@ -31,6 +31,13 @@
 #define ntohl(x) (x)
 #endif
 
+int run_address(void *f)
+{
+	int (*v) (void);
+	v = f;
+	return v();
+}
+
 int find_file(struct mem_file *archive, char *filename, struct mem_file *result)
 {
 	char *walk, *fullname;
@@ -40,31 +47,108 @@
 	printk(BIOS_SPEW, "LAR: Start %p len 0x%x\n", archive->start,
 	       archive->len);
 
+	if (archive->len < sizeof(struct lar_header))
+		printk(BIOS_ERR, "Error: truncated archive (%d bytes); minimum possible size is %d bytes\n", 
+			archive->len, sizeof(struct lar_header));
+
+	/* Getting this for loop right is harder than it looks. All quantities are 
+	  * unsigned. The LAR stretches from (e.g.) 0xfff0000 for 0x100000 
+	  * bytes, i.e. to address ZERO. 
+	  * As a result, 'walk', can wrap to zero and keep going (this has been 
+	  * seen in practice). Recall that these are unsigned; walk can 
+	  * wrap to zero; so, question, when is walk less than any of these:
+	  * archive->start
+	  * Answer: once walk wraps to zero, it is < archive->start
+	  * archive->start + archive->len
+	  * archive->start + archive->len  - 1
+	  * Answer: In the case that archive->start + archive->len == 0, ALWAYS!
+	  * A lot of expressions have been tried and all have been wrong. 
+	  * So what would work? Simple:
+	  * test for walk < archive->start + archive->len - 1 to cover the case
+	  *	that the archive does NOT occupy ALL of the top of memory and 
+	  *	wrap to zero; 
+	  * and test for walk >= archive->start, 
+	  * to cover the case that you wrapped to zero. 
+	  * Unsigned pointer arithmetic that wraps to zero can be messy.
+	  */
 	for (walk = archive->start;
-	     (walk - 1) < (char *)(archive->start + archive->len - 1 ); walk += 16) {
+	     (walk < (char *)(archive->start + archive->len - sizeof(struct lar_header))) && 
+			(walk >= (char *)archive->start); walk += 16) {
 		if (strcmp(walk, MAGIC) != 0)
 			continue;
 
 		header = (struct lar_header *)walk;
 		fullname = walk + sizeof(struct lar_header);
 
-		printk(BIOS_SPEW, "LAR: current filename is %s\n", fullname);
+		printk(BIOS_SPEW, "LAR: search for %s\n", fullname);
 		// FIXME: check checksum
 
 		if (strcmp(fullname, filename) == 0) {
+			printk(BIOS_SPEW, "LAR: CHECK %s @ %p\n", fullname, header);
 			result->start = walk + ntohl(header->offset);
 			result->len = ntohl(header->len);
 			result->reallen = ntohl(header->reallen);
 			result->compression = ntohl(header->compression);
+			result->entry = (void *)ntohl(header->entry);
+			result->loadaddress = (void *)ntohl(header->loadaddress);
+			printk(BIOS_SPEW, 
+			"start %p len %d reallen %d compression %x entry %p loadaddress %p\n", 
+				result->start, result->len, result->reallen, 
+				result->compression, result->entry, result->loadaddress);
 			return 0;
 		}
 		// skip file
 		walk += (ntohl(header->len) + ntohl(header->offset) -
 			1) & 0xfffffff0;
 	}
+	printk(BIOS_SPEW, "NO FILE FOUND\n");
 	return 1;
 }
 
+
+void *load_file(struct mem_file *archive, char *filename)
+{
+	int ret;
+	struct mem_file result;
+	void *where;
+	void *entry;
+
+	ret = find_file(archive, filename, &result);
+	if (ret) {
+		printk(BIOS_INFO, "LAR: load_file: No such file '%s'\n",
+		       filename);
+		return (void *)-1;
+	}
+	entry = result.entry;
+	where = result.loadaddress;
+	printk(BIOS_SPEW, "LAR: Compression algorithm #%i used\n", result.compression);
+	/* no compression */
+	if (result.compression == 0) {
+		memcpy(where, result.start, result.len);
+		return entry;
+	}
+#ifdef CONFIG_COMPRESSION_LZMA
+	/* lzma */
+	unsigned long ulzma(unsigned char *src, unsigned char *dst);
+	if (result.compression == 1) {
+		ulzma(result.start, where);
+		return entry;
+	}
+#endif
+#ifdef CONFIG_COMPRESSION_NRV2B
+	/* nrv2b */
+	unsigned long unrv2b(u8 *src, u8 *dst, unsigned long *ilen_p);
+	if (result.compression == 2) {
+		int tmp;
+		unrv2b(result.start, where, &tmp);
+		return entry;
+	}
+#endif
+	printk(BIOS_INFO, "LAR: Compression algorithm #%i not supported!\n", result.compression);
+	return (void *)-1;
+}
+
+/* FIXME -- most of copy_file should be replaced by load_file */
 int copy_file(struct mem_file *archive, char *filename, void *where)
 {
 	int ret;
@@ -85,7 +169,7 @@
 	}
 #ifdef CONFIG_COMPRESSION_LZMA
 	/* lzma */
-	unsigned long ulzma(unsigned char * src, unsigned char * dst);
+	unsigned long ulzma(unsigned char *src, unsigned char *dst);
 	if (result.compression == 1) {
 		ulzma(result.start, where);
 		return 0;
@@ -93,7 +177,7 @@
 #endif
 #ifdef CONFIG_COMPRESSION_NRV2B
 	/* nrv2b */
-	unsigned long unrv2b(u8 * src, u8 * dst, unsigned long *ilen_p);
+	unsigned long unrv2b(u8 *src, u8 *dst, unsigned long *ilen_p);
 	if (result.compression == 2) {
 		int tmp;
 		unrv2b(result.start, where, &tmp);
@@ -113,6 +197,7 @@
 {
 	int (*v) (void);
 	struct mem_file result;
+	int ret;
 
 	if ((u32) where != 0xFFFFFFFF) {
 		if (copy_file(archive, filename, where)) {
@@ -130,9 +215,11 @@
 		}
 		where = result.start;
 	}
-
+	printk(BIOS_SPEW, "where is %p\n", where);
 	v = where;
-	return v();
+	ret =  v();
+	printk(BIOS_SPEW, "run_file returns with %d\n", ret);
+	return ret;
 }
 
 /**





More information about the coreboot mailing list