Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- config/examples/ppc_config.xml | 1 + forth/debugging/client.fs | 1 + include/libopenbios/prep_load.h | 24 +++++++++ libopenbios/build.xml | 1 + libopenbios/initprogram.c | 8 +++ libopenbios/load.c | 11 +++++ libopenbios/prep_load.c | 106 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 152 insertions(+) create mode 100644 include/libopenbios/prep_load.h create mode 100644 libopenbios/prep_load.c
diff --git a/config/examples/ppc_config.xml b/config/examples/ppc_config.xml index 0ac3817..3112ea5 100644 --- a/config/examples/ppc_config.xml +++ b/config/examples/ppc_config.xml @@ -32,6 +32,7 @@ <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"/> + <option name="CONFIG_LOADER_PREP" type="boolean" value="true"/> <option name="CONFIG_LOADER_XCOFF" type="boolean" value="true"/>
<!-- Filesystem Configuration --> diff --git a/forth/debugging/client.fs b/forth/debugging/client.fs index c8cd5b6..5ee6003 100644 --- a/forth/debugging/client.fs +++ b/forth/debugging/client.fs @@ -51,6 +51,7 @@ variable file-size 10 constant fcode 11 constant forth 12 constant bootcode +13 constant prep
: init-program ( -- ) diff --git a/include/libopenbios/prep_load.h b/include/libopenbios/prep_load.h new file mode 100644 index 0000000..ed1882e --- /dev/null +++ b/include/libopenbios/prep_load.h @@ -0,0 +1,24 @@ +/* + * Creation Date: <2010/03/22 18:00:00 mcayland> + * Time-stamp: <2010/03/22 18:00:00 mcayland> + * + * <prep_load.h> + * + * PReP boot partition loader + * + * Copyright (C) 2018 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_PREPLOAD +#define _H_PREPLOAD + +extern int prep_load(ihandle_t dev); +int is_prep(char *addr); +void prep_init_program(void); + +#endif /* _H_PREPLOAD */ diff --git a/libopenbios/build.xml b/libopenbios/build.xml index feb8f6c..0c89110 100644 --- a/libopenbios/build.xml +++ b/libopenbios/build.xml @@ -19,6 +19,7 @@ <object source="load.c"/> <object source="linuxbios_info.c" condition="LINUXBIOS"/> <object source="ofmem_common.c" condition="OFMEM"/> + <object source="prep_load.c" condition="LOADER_PREP"/> <object source="xcoff_load.c" condition="LOADER_XCOFF"/> <object source="video_common.c"/> </library> diff --git a/libopenbios/initprogram.c b/libopenbios/initprogram.c index ffd3254..3213378 100644 --- a/libopenbios/initprogram.c +++ b/libopenbios/initprogram.c @@ -29,6 +29,7 @@ #include "libopenbios/elf_load.h" #include "libopenbios/fcode_load.h" #include "libopenbios/forth_load.h" +#include "libopenbios/prep_load.h" #include "libopenbios/xcoff_load.h"
@@ -90,6 +91,13 @@ void init_program(void) } #endif
+#ifdef CONFIG_LOADER_PREP + if (is_prep((char *)cell2pointer(addr))) { + prep_init_program(); + return; + } +#endif + }
void init_fcode_context(void) diff --git a/libopenbios/load.c b/libopenbios/load.c index 174d221..16dc74a 100644 --- a/libopenbios/load.c +++ b/libopenbios/load.c @@ -45,6 +45,10 @@ #include "libopenbios/bootcode_load.h" #endif
+#ifdef CONFIG_LOADER_PREP +#include "libopenbios/prep_load.h" +#endif +
struct sys_info sys_info; void *elf_boot_notes = NULL; @@ -113,6 +117,13 @@ void load(ihandle_t dev) } #endif
+#ifdef CONFIG_LOADER_PREP + if (prep_load(dev) != LOADER_NOT_SUPPORT) { + feval("load-state >ls.file-size @"); + return; + } +#endif + /* Didn't load anything, so return zero size */ PUSH(0); } diff --git a/libopenbios/prep_load.c b/libopenbios/prep_load.c new file mode 100644 index 0000000..7942804 --- /dev/null +++ b/libopenbios/prep_load.c @@ -0,0 +1,106 @@ +/* + * PReP boot partition loader + * Written by Mark Cave-Ayland 2018 + */ + +#include "config.h" +#include "kernel/kernel.h" +#include "libopenbios/bindings.h" +#include "libopenbios/prep_load.h" +#include "libopenbios/initprogram.h" +#include "libopenbios/sys_info.h" +#include "libc/byteorder.h" +#include "libc/diskio.h" +#include "drivers/drivers.h" +#define printf printk +#define debug printk + + +int +prep_load(ihandle_t dev) +{ + int retval = LOADER_NOT_SUPPORT, fd, count, size; + ucell *loadbase; + unsigned char *image; + uint32_t entry_point_offset, load_image_length; + unsigned long entry; + + /* 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 = cell2pointer(POP()); + + /* Read block 2 containing the boot info */ + seek_io(fd, 512); + count = read_io(fd, (void *)loadbase, 512); + if (count != 512) { + goto out; + } + + entry_point_offset = __le32_to_cpu(loadbase[0]); + load_image_length = __le32_to_cpu(loadbase[1]); + + /* Load the entire image */ + size = 0; + image = (unsigned char *)loadbase; + entry = (uintptr_t)loadbase + entry_point_offset; + + seek_io(fd, 0); + while (size < load_image_length) { + count = read_io(fd, (void *)image, 512); + if (count == -1) { + break; + } + + size += count; + image += count; + } + + /* If we didn't read anything, something went wrong */ + if (!size) { + goto out; + } + + /* Set correct size */ + size = load_image_length; + + /* Initialise load-state */ + PUSH(entry); + feval("load-state >ls.entry !"); + PUSH(size); + feval("load-state >ls.file-size !"); + feval("prep load-state >ls.file-type !"); + +out: + close_io(fd); + return retval; +} + +int +is_prep(char *addr) +{ + /* PReP bootloaders are executed directly. So we'll say that something is + * PReP if the loader detected the PReP type sucessfully */ + ucell filetype; + + feval("load-state >ls.file-type @"); + filetype = POP(); + + return (filetype == 0x13); +} + +void +prep_init_program(void) +{ + /* Entry point is already set, just need to setup the context */ + arch_init_program(); + + feval("-1 state-valid !"); +}