Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / libopenbios / bootinfo_load.c
diff --git a/qemu/roms/openbios/libopenbios/bootinfo_load.c b/qemu/roms/openbios/libopenbios/bootinfo_load.c
new file mode 100644 (file)
index 0000000..fa9e36b
--- /dev/null
@@ -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");
+}