One of the primary reasons that issues with the quik bootloader were not detected earlier was because arch/ppc/qemu/main.c has a separate code path for forcing an old-world boot when -boot c is passed to QEMU.
This commit implements the bootcode loader as a core OpenBIOS loader which enables old-world payloads such as quik to be executed using:
load hd:,%BOOT go
Note that we also fix a bug in mac-parts.c to ensure that we don't try and interpose a filesystem package when %BOOT is passed as a filename.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk CC: Alexander Graf agraf@suse.de CC: Andreas Färber afaerber@suse.de --- openbios-devel/config/examples/ppc_config.xml | 1 + openbios-devel/forth/debugging/client.fs | 4 ++ openbios-devel/include/libopenbios/bootcode_load.h | 22 ++++++ openbios-devel/libopenbios/bootcode_load.c | 71 ++++++++++++++++++++ openbios-devel/libopenbios/build.xml | 1 + openbios-devel/libopenbios/load.c | 13 ++++ openbios-devel/packages/mac-parts.c | 16 ++--- 7 files changed, 119 insertions(+), 9 deletions(-) create mode 100644 openbios-devel/include/libopenbios/bootcode_load.h create mode 100644 openbios-devel/libopenbios/bootcode_load.c
diff --git a/openbios-devel/config/examples/ppc_config.xml b/openbios-devel/config/examples/ppc_config.xml index ccb616d..5bb789f 100644 --- a/openbios-devel/config/examples/ppc_config.xml +++ b/openbios-devel/config/examples/ppc_config.xml @@ -26,6 +26,7 @@ <option name="CONFIG_VGA_DEPTH" type="integer" value="8"/> <option name="CONFIG_LOADER_AOUT" type="boolean" value="false"/> <option name="CONFIG_LOADER_BOOTINFO" type="boolean" value="true"/> + <option name="CONFIG_LOADER_BOOTCODE" type="boolean" value="true"/> <option name="CONFIG_LOADER_ELF" type="boolean" value="true"/> <option name="CONFIG_LOADER_FCODE" type="boolean" value="false"/> <option name="CONFIG_LOADER_FORTH" type="boolean" value="false"/> diff --git a/openbios-devel/forth/debugging/client.fs b/openbios-devel/forth/debugging/client.fs index 24b1ec7..9da9b33 100644 --- a/openbios-devel/forth/debugging/client.fs +++ b/openbios-devel/forth/debugging/client.fs @@ -27,6 +27,9 @@ create saved-program-state saved-program-state.size allot variable state-valid 0 state-valid !
+variable want-bootcode +0 want-bootcode ! + variable file-size
: !load-size file-size ! ; @@ -44,6 +47,7 @@ variable file-size 5 constant aout 10 constant fcode 11 constant forth +12 constant bootcode
: init-program ( -- ) diff --git a/openbios-devel/include/libopenbios/bootcode_load.h b/openbios-devel/include/libopenbios/bootcode_load.h new file mode 100644 index 0000000..147783a --- /dev/null +++ b/openbios-devel/include/libopenbios/bootcode_load.h @@ -0,0 +1,22 @@ +/* + * Creation Date: <2010/03/22 18:00:00 mcayland> + * Time-stamp: <2010/03/22 18:00:00 mcayland> + * + * <bootcode_load.h> + * + * Raw bootcode (%BOOT) loader + * + * Copyright (C) 2013 Mark Cave-Ayland (mark.cave-ayland@ilande.co.uk) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#ifndef _H_BOOTCODELOAD +#define _H_BOOTCODELOAD + +extern int bootcode_load(ihandle_t dev); + +#endif /* _H__H_BOOTCODELOAD */ diff --git a/openbios-devel/libopenbios/bootcode_load.c b/openbios-devel/libopenbios/bootcode_load.c new file mode 100644 index 0000000..3644997 --- /dev/null +++ b/openbios-devel/libopenbios/bootcode_load.c @@ -0,0 +1,71 @@ +/* + * Raw bootcode loader (CHRP/Apple %BOOT) + * Written by Mark Cave-Ayland 2013 + */ + +#include "config.h" +#include "kernel/kernel.h" +#include "libopenbios/bindings.h" +#include "libopenbios/bootcode_load.h" +#include "libc/diskio.h" +#include "drivers/drivers.h" +#define printf printk +#define debug printk + +#define OLDWORLD_BOOTCODE_BASEADDR (0x3f4000) + +int +bootcode_load(ihandle_t dev) +{ + int retval = -1, count = 0, fd; + unsigned long bootcode, loadbase, offset; + + /* Mark the saved-program-state as invalid */ + feval("0 state-valid !"); + + fd = open_ih(dev); + if (fd == -1) { + goto out; + } + + /* Default to loading at load-base */ + fword("load-base"); + loadbase = POP(); + +#ifdef CONFIG_PPC + /* However Old World Macs need to load to a different address */ + if (is_oldworld()) { + loadbase = OLDWORLD_BOOTCODE_BASEADDR; + } +#endif + + bootcode = loadbase; + offset = 0; + + while(1) { + if (seek_io(fd, offset) == -1) + break; + count = read_io(fd, (void *)bootcode, 512); + offset += count; + bootcode += count; + } + + /* If we didn't read anything then exit */ + if (!count) { + goto out; + } + + /* Initialise saved-program-state */ + PUSH(loadbase); + feval("saved-program-state >sps.entry !"); + PUSH(offset); + feval("saved-program-state >sps.file-size !"); + feval("bootcode saved-program-state >sps.file-type !"); + + feval("-1 state-valid !"); + +out: + close_io(fd); + return retval; +} + diff --git a/openbios-devel/libopenbios/build.xml b/openbios-devel/libopenbios/build.xml index 04e3800..8c1fe3f 100644 --- a/openbios-devel/libopenbios/build.xml +++ b/openbios-devel/libopenbios/build.xml @@ -3,6 +3,7 @@ <library name="openbios" type="static" target="target"> <object source="aout_load.c" condition="LOADER_AOUT"/> <object source="bindings.c"/> + <object source="bootcode_load.c" condition="LOADER_BOOTCODE"/> <object source="bootinfo_load.c" condition="LOADER_BOOTINFO"/> <object source="client.c"/> <object source="console_common.c"/> diff --git a/openbios-devel/libopenbios/load.c b/openbios-devel/libopenbios/load.c index 2a2a7f9..1d50a82 100644 --- a/openbios-devel/libopenbios/load.c +++ b/openbios-devel/libopenbios/load.c @@ -36,6 +36,10 @@ #include "libopenbios/forth_load.h" #endif
+#ifdef CONFIG_LOADER_BOOTCODE +#include "libopenbios/bootcode_load.h" +#endif +
struct sys_info sys_info; void *elf_boot_notes = NULL; @@ -92,4 +96,13 @@ void load(ihandle_t dev) } #endif
+#ifdef CONFIG_LOADER_BOOTCODE + /* Check for a "raw" %BOOT bootcode payload */ + feval("want-bootcode @"); + valid = POP(); + if (valid) { + bootcode_load(dev); + } +#endif + } diff --git a/openbios-devel/packages/mac-parts.c b/openbios-devel/packages/mac-parts.c index 85d53f8..c29b554 100644 --- a/openbios-devel/packages/mac-parts.c +++ b/openbios-devel/packages/mac-parts.c @@ -89,8 +89,12 @@ macparts_open( macparts_info_t *di ) parnum = atol(parstr);
/* Detect if we are looking for the bootcode */ - if (strcmp(argstr, "%BOOT") == 0) + if (strcmp(argstr, "%BOOT") == 0) { want_bootcode = 1; + feval("1 want-bootcode !"); + } else { + feval("0 want-bootcode !"); + } }
DPRINTF("parstr: %s argstr: %s parnum: %d\n", parstr, argstr, parnum); @@ -285,16 +289,10 @@ macparts_open( macparts_info_t *di ) set_property(chosen_ph, "bootpath", bootpath, strlen(bootpath) + 1); } - - /* If the filename was %BOOT then it's not a real filename, so clear argstr before - attempting interpose */ - if (want_bootcode) { - argstr = strdup(""); - } - + /* If we have been asked to open a particular file, interpose the filesystem package with the passed filename as an argument */ - if (strlen(argstr)) { + if (!want_bootcode && strlen(argstr)) { push_str( argstr ); PUSH_ph( ph ); fword("interpose");
By adding the bootcode device to the bootdevice list as processed by load, we automatically attempt to invoke the bootcode loader as required.
As a consequence of this, we can now remove the separate C codepath used in order to facilitate an old-world boot.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk CC: Alexander Graf agraf@suse.de CC: Andreas Färber afaerber@suse.de --- openbios-devel/arch/ppc/qemu/init.c | 2 +- openbios-devel/arch/ppc/qemu/main.c | 139 ----------------------------------- 2 files changed, 1 insertion(+), 140 deletions(-)
diff --git a/openbios-devel/arch/ppc/qemu/init.c b/openbios-devel/arch/ppc/qemu/init.c index a8fc320..bb3f933 100644 --- a/openbios-devel/arch/ppc/qemu/init.c +++ b/openbios-devel/arch/ppc/qemu/init.c @@ -855,7 +855,7 @@ arch_of_init(void) }
/* Setup default boot devices */ - snprintf(buf, sizeof(buf), "%s:,\\:tbxi %s:,\ppc\bootinfo.txt", boot_path, boot_path); + snprintf(buf, sizeof(buf), "%s:,\\:tbxi %s:,\ppc\bootinfo.txt %s:,%%BOOT", boot_path, boot_path, boot_path); push_str(buf); fword("encode-string"); push_str("boot-device"); diff --git a/openbios-devel/arch/ppc/qemu/main.c b/openbios-devel/arch/ppc/qemu/main.c index f9c1a53..30a4375 100644 --- a/openbios-devel/arch/ppc/qemu/main.c +++ b/openbios-devel/arch/ppc/qemu/main.c @@ -39,141 +39,6 @@ #define ELF_DPRINTF(fmt, args...) SUBSYS_DPRINTF("ELF", fmt, ##args) #define NEWWORLD_DPRINTF(fmt, args...) SUBSYS_DPRINTF("NEWWORLD", fmt, ##args)
-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 int -get_partition( const char *path ) -{ - while ( *path && *path != ':' ) - path++; - - if (!*path) - return -1; - path++; - - if (!strchr(path, ',')) /* check if there is a ',' */ - return -1; - - return atol(path); -} - -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; -} - - -static void -encode_bootpath( const char *spec, const char *args ) -{ - char path[1024]; - phandle_t chosen_ph = find_dev("/chosen"); - char *filename, *directory; - int partition; - - if (spec) - return; - - filename = get_filename(spec, &directory); - partition = get_partition(spec); - if (partition == -1) - snprintf(path, sizeof(path), "%s:,%s\%s", get_device(spec), - directory, filename); - else - snprintf(path, sizeof(path), "%s:%d,%s\%s", get_device(spec), - partition, directory, filename); - - ELF_DPRINTF("bootpath %s bootargs %s\n", path, args); - set_property( chosen_ph, "bootpath", path, strlen(path)+1 ); - if (args) - set_property( chosen_ph, "bootargs", args, strlen(args)+1 ); -} - -#define OLDWORLD_BOOTCODE_BASEADDR (0x3f4000) - -static void -oldworld_boot( void ) -{ - int fd; - int len, total; - const char *path = "hd:,%BOOT"; - char *bootcode; - - if ((fd = open_io(path)) == -1) { - ELF_DPRINTF("Can't open %s\n", path); - return; - } - - - total = 0; - bootcode = (char*)OLDWORLD_BOOTCODE_BASEADDR; - while(1) { - if (seek_io(fd, total) == -1) - break; - len = read_io(fd, bootcode, 512); - bootcode += len; - total += len; - } - - close_io( fd ); - - if (total == 0) { - ELF_DPRINTF("Can't read %s\n", path); - return; - } - - encode_bootpath(path, "Linux"); - - if( ofmem_claim( OLDWORLD_BOOTCODE_BASEADDR, total, 0 ) == -1 ) - fatal_error("Claim failed!\n"); - - call_elf(0, 0, OLDWORLD_BOOTCODE_BASEADDR); - - return; -} - static void check_preloaded_kernel(void) { unsigned long kernel_image, kernel_size; @@ -213,9 +78,5 @@ boot( void ) check_preloaded_kernel(); }
- if (boot_device == 'c') { - oldworld_boot(); - } - update_nvram(); }