diff options
Diffstat (limited to 'qemu/roms/openbios/libopenbios/bootinfo_load.c')
-rw-r--r-- | qemu/roms/openbios/libopenbios/bootinfo_load.c | 263 |
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"); +} |