summaryrefslogtreecommitdiffstats
path: root/qemu/roms/openbios/libopenbios/bootinfo_load.c
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/roms/openbios/libopenbios/bootinfo_load.c')
-rw-r--r--qemu/roms/openbios/libopenbios/bootinfo_load.c263
1 files changed, 263 insertions, 0 deletions
diff --git a/qemu/roms/openbios/libopenbios/bootinfo_load.c b/qemu/roms/openbios/libopenbios/bootinfo_load.c
new file mode 100644
index 000000000..fa9e36bd4
--- /dev/null
+++ b/qemu/roms/openbios/libopenbios/bootinfo_load.c
@@ -0,0 +1,263 @@
+/*
+ *
+ * <bootinfo_load.c>
+ *
+ * bootinfo file loader
+ *
+ * Copyright (C) 2009 Laurent Vivier (Laurent@vivier.eu)
+ *
+ * Original XML parser by Blue Swirl <blauwirbel@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2
+ *
+ */
+
+#include "config.h"
+#include "libopenbios/bindings.h"
+#include "libopenbios/bootinfo_load.h"
+#include "libopenbios/ofmem.h"
+#include "libc/vsprintf.h"
+
+//#define DEBUG_BOOTINFO
+
+#ifdef DEBUG_BOOTINFO
+#define DPRINTF(fmt, args...) \
+ do { printk("%s: " fmt, __func__ , ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...) \
+ do { } while (0)
+#endif
+
+static char *
+get_device( const char *path )
+{
+ int i;
+ static char buf[1024];
+
+ for (i = 0; i < sizeof(buf) && path[i] && path[i] != ':'; i++)
+ buf[i] = path[i];
+ buf[i] = 0;
+
+ return buf;
+}
+
+static char *
+get_partition( const char *path )
+{
+ static char buf[2];
+
+ buf[0] = '\0';
+ buf[1] = '\0';
+
+ while ( *path && *path != ':' )
+ path++;
+
+ if (!*path)
+ return buf;
+ path++;
+
+ if (path[0] == ',' || !strchr(path, ',')) /* if there is not a ',' or no partition id then return */
+ return buf;
+
+ /* Must be a partition id */
+ buf[0] = path[0];
+
+ return buf;
+}
+
+static char *
+get_filename( const char * path , char **dirname)
+{
+ static char buf[1024];
+ char *filename;
+
+ while ( *path && *path != ':' )
+ path++;
+
+ if (!*path) {
+ *dirname = NULL;
+ return NULL;
+ }
+ path++;
+
+ while ( *path && isdigit(*path) )
+ path++;
+
+ if (*path == ',')
+ path++;
+
+ strncpy(buf, path, sizeof(buf));
+ buf[sizeof(buf) - 1] = 0;
+
+ filename = strrchr(buf, '\\');
+ if (filename) {
+ *dirname = buf;
+ (*filename++) = 0;
+ } else {
+ *dirname = NULL;
+ filename = buf;
+ }
+
+ return filename;
+}
+
+int
+is_bootinfo(char *bootinfo)
+{
+ return (strncasecmp(bootinfo, "<chrp-boot", 10) ? 0 : -1);
+}
+
+int
+bootinfo_load(struct sys_info *info, const char *filename)
+{
+ // Currently not implemented
+ return LOADER_NOT_SUPPORT;
+}
+
+/*
+ Parse SGML structure like:
+ <chrp-boot>
+ <description>Debian/GNU Linux Installation on IBM CHRP hardware</description>
+ <os-name>Debian/GNU Linux for PowerPC</os-name>
+ <boot-script>boot &device;:\install\yaboot</boot-script>
+ <icon size=64,64 color-space=3,3,2>
+
+ CHRP system bindings are described at:
+ http://playground.sun.com/1275/bindings/chrp/chrp1_7a.ps
+*/
+
+void
+bootinfo_init_program(void)
+{
+ char *base;
+ int proplen;
+ phandle_t chosen;
+ int tag, taglen, script, scriptlen, scriptvalid, entity, chrp;
+ char tagbuf[128], c;
+ char *device, *filename, *directory, *partition;
+ int current, size;
+ char *bootscript;
+ char *tmp;
+ char bootpath[1024];
+
+ /* Parse the boot script */
+
+ chosen = find_dev("/chosen");
+ tmp = get_property(chosen, "bootpath", &proplen);
+ memcpy(bootpath, tmp, proplen);
+ bootpath[proplen] = 0;
+
+ DPRINTF("bootpath %s\n", bootpath);
+
+ device = get_device(bootpath);
+ partition = get_partition(bootpath);
+ filename = get_filename(bootpath, &directory);
+
+ 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;
+ }
+
+ chrp = 0;
+ tag = 0;
+ taglen = 0;
+ script = 0;
+ scriptvalid = 0;
+ scriptlen = 0;
+ entity = 0;
+ current = 0;
+ while (current < size) {
+
+ c = base[current++];
+
+ if (c == '<') {
+ script = 0;
+ tag = 1;
+ taglen = 0;
+ } else if (c == '>') {
+ tag = 0;
+ tagbuf[taglen] = '\0';
+ if (strncasecmp(tagbuf, "chrp-boot", 9) == 0) {
+ chrp = 1;
+ } else if (chrp == 1) {
+ if (strncasecmp(tagbuf, "boot-script", 11) == 0) {
+ script = 1;
+ scriptlen = 0;
+ } 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;
+ }
+ } else if (tag && taglen < sizeof(tagbuf)) {
+ tagbuf[taglen++] = c;
+ } else if (script && c == '&') {
+ entity = 1;
+ taglen = 0;
+ } else if (entity && c ==';') {
+ entity = 0;
+ tagbuf[taglen] = '\0';
+ if (strncasecmp(tagbuf, "lt", 2) == 0) {
+ bootscript[scriptlen++] = '<';
+ } else if (strncasecmp(tagbuf, "gt", 2) == 0) {
+ bootscript[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 if (entity && taglen < sizeof(tagbuf)) {
+ tagbuf[taglen++] = c;
+ } else if (script && scriptlen < size) {
+ bootscript[scriptlen++] = c;
+ }
+ }
+
+ /* If the payload is bootinfo then we execute it immediately */
+ if (scriptvalid) {
+ DPRINTF("bootscript: %s\n", bootscript);
+ feval(bootscript);
+ }
+ else
+ DPRINTF("Unable to parse bootinfo bootscript\n");
+}