This patch provides a more memory-efficient method of allocating memory for the
boot script by using the actual script length (including entity translations)
instead of the file size.
Signed-off-by: Cormac O'Brien <i.am.cormac.obrien(a)gmail.com>
---
libopenbios/bootinfo_load.c | 102 +++++++++++++++++++++++++++++---------------
1 file changed, 67 insertions(+), 35 deletions(-)
diff --git a/libopenbios/bootinfo_load.c b/libopenbios/bootinfo_load.c
index fa9e36b..bd282f4 100644
--- a/libopenbios/bootinfo_load.c
+++ b/libopenbios/bootinfo_load.c
@@ -20,7 +20,7 @@
#include "libopenbios/ofmem.h"
#include "libc/vsprintf.h"
-//#define DEBUG_BOOTINFO
+#define DEBUG_BOOTINFO
#ifdef DEBUG_BOOTINFO
#define DPRINTF(fmt, args...) \
@@ -134,12 +134,13 @@ bootinfo_init_program(void)
char *base;
int proplen;
phandle_t chosen;
- int tag, taglen, script, scriptlen, scriptvalid, entity, chrp;
+ int tag, taglen, script, scriptind, scriptlen, scriptstart, scriptvalid,
+ entity, chrp;
char tagbuf[128], c;
char *device, *filename, *directory, *partition;
int current, size;
char *bootscript;
- char *tmp;
+ char *tmp;
char bootpath[1024];
/* Parse the boot script */
@@ -158,21 +159,14 @@ bootinfo_init_program(void)
feval("load-base");
base = (char*)cell2pointer(POP());
- feval("load-size");
- size = POP();
-
- bootscript = malloc(size);
- if (bootscript == NULL) {
- DPRINTF("Can't malloc %d bytes\n", size);
- return;
- }
-
if (!is_bootinfo(base)) {
DPRINTF("Not a valid bootinfo memory image\n");
- free(bootscript);
return;
}
+ feval("load-size");
+ size = POP();
+
chrp = 0;
tag = 0;
taglen = 0;
@@ -198,16 +192,10 @@ bootinfo_init_program(void)
if (strncasecmp(tagbuf, "boot-script", 11) == 0) {
script = 1;
scriptlen = 0;
+ scriptstart = current;
} else if (strncasecmp(tagbuf, "/boot-script", 12) == 0) {
-
script = 0;
- bootscript[scriptlen] = '\0';
-
- DPRINTF("got bootscript %s\n",
- bootscript);
-
scriptvalid = -1;
-
break;
} else if (strncasecmp(tagbuf, "/chrp-boot", 10) == 0)
break;
@@ -217,42 +205,86 @@ bootinfo_init_program(void)
} else if (script && c == '&') {
entity = 1;
taglen = 0;
- } else if (entity && c ==';') {
+ } else if (entity && c == ';') {
entity = 0;
tagbuf[taglen] = '\0';
if (strncasecmp(tagbuf, "lt", 2) == 0) {
- bootscript[scriptlen++] = '<';
+ scriptlen++;
} else if (strncasecmp(tagbuf, "gt", 2) == 0) {
- bootscript[scriptlen++] = '>';
+ scriptlen++;
} else if (strncasecmp(tagbuf, "device", 6) == 0) {
- strcpy(bootscript + scriptlen, device);
scriptlen += strlen(device);
} else if (strncasecmp(tagbuf, "partition", 9) == 0) {
- strcpy(bootscript + scriptlen, partition);
scriptlen += strlen(partition);
} else if (strncasecmp(tagbuf, "directory", 9) == 0) {
- strcpy(bootscript + scriptlen, directory);
scriptlen += strlen(directory);
} else if (strncasecmp(tagbuf, "filename", 8) == 0) {
- strcpy(bootscript + scriptlen, filename);
scriptlen += strlen(filename);
} else if (strncasecmp(tagbuf, "full-path", 9) == 0) {
- strcpy(bootscript + scriptlen, bootpath);
scriptlen += strlen(bootpath);
- } else { /* unknown, keep it */
- bootscript[scriptlen] = '&';
- strcpy(bootscript + scriptlen + 1, tagbuf);
- scriptlen += taglen + 1;
- bootscript[scriptlen] = ';';
- scriptlen++;
+ } else {
+ scriptlen += taglen + 2;
}
} else if (entity && taglen < sizeof(tagbuf)) {
tagbuf[taglen++] = c;
} else if (script && scriptlen < size) {
- bootscript[scriptlen++] = c;
+ scriptlen++;
+ }
+ }
+
+ bootscript = malloc(scriptlen * sizeof *bootscript + 1);
+ if (bootscript == NULL) {
+ DPRINTF("Can't malloc %d bytes\n", size);
+ return;
+ }
+
+ entity = 0;
+ scriptind = 0;
+ taglen = 0;
+ current = scriptstart;
+ while (current < scriptstart + scriptlen) {
+ c = base[current++];
+
+ if (c == '&') {
+ entity = 1;
+ taglen = 0;
+ } else if (entity && c == ';') {
+ entity = 0;
+ tagbuf[taglen] = '\0';
+ if (strncasecmp(tagbuf, "lt", 2) == 0) {
+ bootscript[scriptind++] = '<';
+ } else if (strncasecmp(tagbuf, "gt", 2) == 0) {
+ bootscript[scriptind++] = '>';
+ } else if (strncasecmp(tagbuf, "device", 6) == 0) {
+ strcpy(bootscript + scriptind, device);
+ scriptind += strlen(device);
+ } else if (strncasecmp(tagbuf, "partition", 9) == 0) {
+ strcpy(bootscript + scriptind, partition);
+ scriptind += strlen(partition);
+ } else if (strncasecmp(tagbuf, "directory", 9) == 0) {
+ strcpy(bootscript + scriptind, directory);
+ scriptind += strlen(directory);
+ } else if (strncasecmp(tagbuf, "filename", 8) == 0) {
+ strcpy(bootscript + scriptind, filename);
+ scriptlen += strlen(filename);
+ } else if (strncasecmp(tagbuf, "full-path", 9) == 0) {
+ strcpy(bootscript + scriptind, bootpath);
+ scriptlen += strlen(bootscript);
+ } else { /* unknown, keep it */
+ bootscript[scriptind++] = '&';
+ strcpy(bootscript + scriptind, tagbuf);
+ scriptind += taglen;
+ bootscript[scriptind++] = ';';
+ }
+ } else if (entity && taglen < sizeof(tagbuf)) {
+ tagbuf[taglen++] = c;
+ } else {
+ bootscript[scriptind++] = c;
}
}
+ bootscript[scriptlen] = '\0';
+
/* If the payload is bootinfo then we execute it immediately */
if (scriptvalid) {
DPRINTF("bootscript: %s\n", bootscript);
--
2.3.5