R481 for LAR
R482 for arch/x86 mods
Attached is a patch for 'noelf mode' + a FIX that is clean for lib/lar.c.
signed-off in patch.
ron
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 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 <[EMAIL PROTECTED]>
Index: lib/lar.c
===================================================================
--- lib/lar.c (revision 480)
+++ lib/lar.c (working copy)
@@ -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,104 @@
printk(BIOS_SPEW, "LAR: Start %p len 0x%x\n", archive->start,
archive->len);
+ /* 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 - 1)) &&
+ (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 +165,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 +173,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 +193,7 @@
{
int (*v) (void);
struct mem_file result;
+ int ret;
if ((u32) where != 0xFFFFFFFF) {
if (copy_file(archive, filename, where)) {
@@ -130,9 +211,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;
}
/**
--
linuxbios mailing list
[email protected]
http://www.linuxbios.org/mailman/listinfo/linuxbios