The current implementation of load/init-program has some fairly big hacks in order to work around the fact that we don't have per-architecture CPU contexts. An example of this is chained bootloaders used for SPARC64 which use Forth to alter the saved CPU context so that control is returned to a different address by directly executing init-program before return.
With all architectures now able to save/restore CPU contexts, these hacks can now be removed and init-program changed to be a single per-architecture implementation along with some associated tidy-ups.
I've given this a fairly thorough testing across all my OpenBIOS test images and as far as I can tell doesn't cause any regressions.
Requires the previously posted SPARC32 and SPARC64 context patches to be applied first.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk
v2: - Fix missing patch for XCOFF loader conversion - Switch aout_init_program() to use memmove() - Fix minor typo in aout_init_program() comment
Mark Cave-Ayland (25): libopenbios: rename saved-program-state to load-state libopenbios: introduce arch_init_program() in preparation for per-arch implementations all: create client program context once at startup client.fs: add load-state param variable amd64: introduce arch_init_program() implementation ppc: introduce arch_init_program() implementation SPARC32: introduce arch_init_program() implementation SPARC64: introduce arch_init_program() implementation x86: introduce arch_init_program() implementation libopenbios: add context wrappers for Fcode/Forth payloads SPARC32: move Forth/FCode over to use new context wrappers SPARC64: move Forth/FCode over to use new context wrappers x86: move Forth/FCode over to use new context wrappers elf: set boot notes in elf_load() if supplied SPARC64: remove start_client_image() libopenbios: move prototypes for start_elf() and __context into libopenbios libopenbios: move go() function into libopenbios aout: implement load/init-program as per IEEE-1275 specification bootcode: implement load/init-program as per IEEE-1275 specification elf: implement load/init-program as per IEEE-1275 specification fcode: implement load/init-program as per IEEE-1275 specification forth: implement load/init-program as per IEEE-1275 specification xcoff: implement load/init-program as per IEEE-1275 specification libopenbios: remove conditional logic from go() libopenbios: remove address parameter from start_elf()
arch/amd64/context.c | 51 ++++++++++++---- arch/ppc/qemu/context.c | 67 ++++++++++++++------- arch/ppc/qemu/init.c | 14 +---- arch/sparc32/boot.c | 71 +++------------------- arch/sparc32/boot.h | 6 +- arch/sparc32/context.c | 39 +++++++++--- arch/sparc32/openbios.c | 2 +- arch/sparc64/boot.c | 54 +---------------- arch/sparc64/boot.h | 6 -- arch/sparc64/context.c | 68 ++++++++++++--------- arch/sparc64/openbios.c | 1 - arch/unix/boot.c | 13 ++++ arch/x86/boot.c | 53 +---------------- arch/x86/boot.h | 6 +- arch/x86/context.c | 52 ++++++++++++---- arch/x86/openbios.c | 1 - forth/debugging/client.fs | 30 +++++----- include/libopenbios/bootcode_load.h | 2 + include/libopenbios/initprogram.h | 9 +++ include/libopenbios/xcoff_load.h | 2 +- libopenbios/aout_load.c | 48 +++++++-------- libopenbios/bootcode_load.c | 33 +++++++++-- libopenbios/elf_load.c | 28 ++++----- libopenbios/fcode_load.c | 32 ++++------ libopenbios/forth_load.c | 30 +++++----- libopenbios/init.c | 3 + libopenbios/initprogram.c | 45 ++++++++++++++ libopenbios/load.c | 58 +++++++++--------- libopenbios/xcoff_load.c | 111 +++++++++++++++++++++++++++++++---- 29 files changed, 526 insertions(+), 409 deletions(-)
The per-arch context is held via __context, so what he hold here is effectively just information about the last loaded file.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- arch/ppc/qemu/init.c | 2 +- arch/sparc32/boot.c | 6 +++--- arch/sparc64/boot.c | 6 +++--- arch/x86/boot.c | 6 +++--- forth/debugging/client.fs | 15 +++++++-------- libopenbios/aout_load.c | 6 +++--- libopenbios/bootcode_load.c | 8 ++++---- libopenbios/elf_load.c | 16 ++++++++-------- libopenbios/fcode_load.c | 8 ++++---- libopenbios/forth_load.c | 6 +++--- libopenbios/load.c | 10 +++++----- libopenbios/xcoff_load.c | 8 ++++---- 12 files changed, 48 insertions(+), 49 deletions(-)
diff --git a/arch/ppc/qemu/init.c b/arch/ppc/qemu/init.c index 8f264f4..f6bbce2 100644 --- a/arch/ppc/qemu/init.c +++ b/arch/ppc/qemu/init.c @@ -608,7 +608,7 @@ go(void) fword("insert-copyright-property"); }
- feval("saved-program-state >sps.entry @"); + feval("load-state >ls.entry @"); addr = POP();
start_elf((unsigned long)addr, 0); diff --git a/arch/sparc32/boot.c b/arch/sparc32/boot.c index 49ec4cf..af1a263 100644 --- a/arch/sparc32/boot.c +++ b/arch/sparc32/boot.c @@ -196,11 +196,11 @@ void go(void) int image_retval = 0;
/* Get the entry point and the type (see forth/debugging/client.fs) */ - feval("saved-program-state >sps.entry @"); + feval("load-state >ls.entry @"); address = POP(); - feval("saved-program-state >sps.file-type @"); + feval("load-state >ls.file-type @"); type = POP(); - feval("saved-program-state >sps.file-size @"); + feval("load-state >ls.file-size @"); size = POP();
setup_romvec(); diff --git a/arch/sparc64/boot.c b/arch/sparc64/boot.c index 5107be6..48922d4 100644 --- a/arch/sparc64/boot.c +++ b/arch/sparc64/boot.c @@ -25,11 +25,11 @@ void go(void) int image_retval = 0;
/* Get the entry point and the type (see forth/debugging/client.fs) */ - feval("saved-program-state >sps.entry @"); + feval("load-state >ls.entry @"); address = POP(); - feval("saved-program-state >sps.file-type @"); + feval("load-state >ls.file-type @"); type = POP(); - feval("saved-program-state >sps.file-size @"); + feval("load-state >ls.file-size @"); size = POP();
printk("\nJumping to entry point " FMT_ucellx " for type " FMT_ucellx "...\n", address, type); diff --git a/arch/x86/boot.c b/arch/x86/boot.c index d40ab8c..6573259 100644 --- a/arch/x86/boot.c +++ b/arch/x86/boot.c @@ -20,11 +20,11 @@ void go(void) int image_retval = 0;
/* Get the entry point and the type (see forth/debugging/client.fs) */ - feval("saved-program-state >sps.entry @"); + feval("load-state >ls.entry @"); address = POP(); - feval("saved-program-state >sps.file-type @"); + feval("load-state >ls.file-type @"); type = POP(); - feval("saved-program-state >sps.file-size @"); + feval("load-state >ls.file-size @"); size = POP();
printk("\nJumping to entry point " FMT_ucellx " for type " FMT_ucellx "...\n", address, type); diff --git a/forth/debugging/client.fs b/forth/debugging/client.fs index f374404..d1e2953 100644 --- a/forth/debugging/client.fs +++ b/forth/debugging/client.fs @@ -17,12 +17,12 @@
\ 7.6.2 Program download and execute
-struct ( saved-program-state ) - /n field >sps.entry - /n field >sps.file-size - /n field >sps.file-type -constant saved-program-state.size -create saved-program-state saved-program-state.size allot +struct ( load-state ) + /n field >ls.entry + /n field >ls.file-size + /n field >ls.file-type +constant load-state.size +create load-state load-state.size allot
variable state-valid 0 state-valid ! @@ -34,8 +34,7 @@ variable file-size : load-size file-size @ ;
-\ File types identified by (init-program) - +\ File types identified by (load-state) 0 constant elf-boot 1 constant elf 2 constant bootinfo diff --git a/libopenbios/aout_load.c b/libopenbios/aout_load.c index e9d2002..2433106 100644 --- a/libopenbios/aout_load.c +++ b/libopenbios/aout_load.c @@ -156,10 +156,10 @@ aout_load(struct sys_info *info, ihandle_t dev)
// Initialise saved-program-state PUSH(addr_fixup(start)); - feval("saved-program-state >sps.entry !"); + feval("load-state >ls.entry !"); PUSH(size); - feval("saved-program-state >sps.file-size !"); - feval("aout saved-program-state >sps.file-type !"); + feval("load-state >ls.file-size !"); + feval("aout load-state >ls.file-type !");
feval("-1 state-valid !");
diff --git a/libopenbios/bootcode_load.c b/libopenbios/bootcode_load.c index 0fabf55..c560240 100644 --- a/libopenbios/bootcode_load.c +++ b/libopenbios/bootcode_load.c @@ -83,12 +83,12 @@ bootcode_load(ihandle_t dev) size = offset; }
- /* Initialise saved-program-state */ + /* Initialise load-state */ PUSH(entry); - feval("saved-program-state >sps.entry !"); + feval("load-state >ls.entry !"); PUSH(size); - feval("saved-program-state >sps.file-size !"); - feval("bootcode saved-program-state >sps.file-type !"); + feval("load-state >ls.file-size !"); + feval("bootcode load-state >ls.file-type !");
feval("-1 state-valid !");
diff --git a/libopenbios/elf_load.c b/libopenbios/elf_load.c index 9c7850e..b0b19ee 100644 --- a/libopenbios/elf_load.c +++ b/libopenbios/elf_load.c @@ -441,9 +441,9 @@ elf_load(struct sys_info *info, ihandle_t dev, const char *cmdline, void **boot_ ELF */ if (boot_notes) { *boot_notes = (void *)virt_to_phys(build_boot_notes(info, cmdline)); - feval("elf-boot saved-program-state >sps.file-type !"); + feval("elf-boot load-state >ls.file-type !"); } else { - feval("elf saved-program-state >sps.file-type !"); + feval("elf load-state >ls.file-type !"); }
//debug("current time: %lu\n", currticks()); @@ -452,9 +452,9 @@ elf_load(struct sys_info *info, ihandle_t dev, const char *cmdline, void **boot_
// Initialise saved-program-state PUSH(addr_fixup(ehdr.e_entry)); - feval("saved-program-state >sps.entry !"); + feval("load-state >ls.entry !"); PUSH(file_size); - feval("saved-program-state >sps.file-size !"); + feval("load-state >ls.file-size !");
feval("-1 state-valid !");
@@ -526,12 +526,12 @@ elf_init_program(void) #endif }
- // Initialise saved-program-state + // Initialise load-state PUSH(ehdr->e_entry); - feval("saved-program-state >sps.entry !"); + feval("load-state >ls.entry !"); PUSH(total_size); - feval("saved-program-state >sps.file-size !"); - feval("elf saved-program-state >sps.file-type !"); + feval("load-state >ls.file-size !"); + feval("elf load-state >ls.file-type !");
feval("-1 state-valid !"); } diff --git a/libopenbios/fcode_load.c b/libopenbios/fcode_load.c index f4eb7bf..5258357 100644 --- a/libopenbios/fcode_load.c +++ b/libopenbios/fcode_load.c @@ -75,12 +75,12 @@ fcode_load(ihandle_t dev) debug("Loaded %lu bytes\n", size); debug("entry point is %#lx\n", start);
- // Initialise saved-program-state + // Initialise load-state PUSH(start); - feval("saved-program-state >sps.entry !"); + feval("load-state >ls.entry !"); PUSH(size); - feval("saved-program-state >sps.file-size !"); - feval("fcode saved-program-state >sps.file-type !"); + feval("load-state >ls.file-size !"); + feval("fcode load-state >ls.file-type !");
feval("-1 state-valid !");
diff --git a/libopenbios/forth_load.c b/libopenbios/forth_load.c index c3a1929..35835fb 100644 --- a/libopenbios/forth_load.c +++ b/libopenbios/forth_load.c @@ -65,10 +65,10 @@ int forth_load(ihandle_t dev)
// Initialise saved-program-state PUSH((ucell)forthtext); - feval("saved-program-state >sps.entry !"); + feval("load-state >ls.entry !"); PUSH((ucell)forthsize); - feval("saved-program-state >sps.file-size !"); - feval("forth saved-program-state >sps.file-type !"); + feval("load-state >ls.file-size !"); + feval("forth load-state >ls.file-type !");
feval("-1 state-valid !");
diff --git a/libopenbios/load.c b/libopenbios/load.c index 4bc12ea..1c54d19 100644 --- a/libopenbios/load.c +++ b/libopenbios/load.c @@ -71,7 +71,7 @@ void load(ihandle_t dev) feval("state-valid @"); valid = POP(); if (valid) { - feval("saved-program-state >sps.file-size @"); + feval("load-state >ls.file-size @"); return; } #endif @@ -81,7 +81,7 @@ void load(ihandle_t dev) feval("state-valid @"); valid = POP(); if (valid) { - feval("saved-program-state >sps.file-size @"); + feval("load-state >ls.file-size @"); return; } #endif @@ -91,7 +91,7 @@ void load(ihandle_t dev) feval("state-valid @"); valid = POP(); if (valid) { - feval("saved-program-state >sps.file-size @"); + feval("load-state >ls.file-size @"); return; } #endif @@ -101,7 +101,7 @@ void load(ihandle_t dev) feval("state-valid @"); valid = POP(); if (valid) { - feval("saved-program-state >sps.file-size @"); + feval("load-state >ls.file-size @"); return; } #endif @@ -112,7 +112,7 @@ void load(ihandle_t dev) feval("state-valid @"); valid = POP(); if (valid) { - feval("saved-program-state >sps.file-size @"); + feval("load-state >ls.file-size @"); return; } #endif diff --git a/libopenbios/xcoff_load.c b/libopenbios/xcoff_load.c index 0dcb28c..bd14343 100644 --- a/libopenbios/xcoff_load.c +++ b/libopenbios/xcoff_load.c @@ -136,12 +136,12 @@ xcoff_init_program(void)
DPRINTF("XCOFF entry point: %x\n", *(uint32_t*)ahdr->entry);
- // Initialise saved-program-state + // Initialise load-state PUSH(*(uint32_t*)(uintptr_t)ahdr->entry); - feval("saved-program-state >sps.entry !"); + feval("load-state >ls.entry !"); PUSH(total_size); - feval("saved-program-state >sps.file-size !"); - feval("xcoff saved-program-state >sps.file-type !"); + feval("load-state >ls.file-size !"); + feval("xcoff load-state >ls.file-type !");
feval("-1 state-valid !"); }
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- include/libopenbios/initprogram.h | 1 + 1 file changed, 1 insertion(+)
diff --git a/include/libopenbios/initprogram.h b/include/libopenbios/initprogram.h index 1684f5d..01fc0c1 100644 --- a/include/libopenbios/initprogram.h +++ b/include/libopenbios/initprogram.h @@ -17,6 +17,7 @@ #ifndef _H_INITPROGRAM #define _H_INITPROGRAM
+extern int arch_init_program(void); extern void init_program(void);
#endif /* _H_INITPROGRAM */
Make sure that __context points to it to potentially allow state to be viewed/altered beforehand.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- arch/amd64/context.c | 10 ++++++++-- arch/ppc/qemu/context.c | 13 ++++++++++--- arch/sparc32/context.c | 10 ++++++++-- arch/sparc64/context.c | 13 +++++++++---- arch/x86/context.c | 11 +++++++++-- 5 files changed, 44 insertions(+), 13 deletions(-)
diff --git a/arch/amd64/context.c b/arch/amd64/context.c index 33ab51e..be70afe 100644 --- a/arch/amd64/context.c +++ b/arch/amd64/context.c @@ -39,6 +39,9 @@ struct context main_ctx __attribute__((section (".initctx"))) = { * it is to switch/switched. */ struct context *__context = &main_ctx;
+/* Client program context */ +static struct context *client_ctx; + /* Stack for loaded ELF image */ static uint8_t image_stack[IMAGE_STACK_SIZE];
@@ -58,6 +61,10 @@ static void start_main(void) * We have to keep it in physical address since we will relocate. */ __boot_ctx = virt_to_phys(__context);
+ /* Set up client context */ + client_ctx = init_context(image_stack, sizeof image_stack, 1); + __context = client_ctx; + /* Start the real fun */ retval = openbios();
@@ -112,9 +119,8 @@ struct context *switch_to(struct context *ctx) /* Start ELF Boot image */ uint32_t start_elf(uint32_t entry_point, uint32_t param) { - struct context *ctx; + struct context *ctx = client_ctx;
- ctx = init_context(image_stack, sizeof image_stack, 1); ctx->eip = entry_point; ctx->param[0] = param; ctx->eax = 0xe1fb007; diff --git a/arch/ppc/qemu/context.c b/arch/ppc/qemu/context.c index 78205a2..74a604f 100644 --- a/arch/ppc/qemu/context.c +++ b/arch/ppc/qemu/context.c @@ -6,6 +6,7 @@ #include "config.h" #include "kernel/kernel.h" #include "context.h" +#include "libopenbios/bindings.h" #include "libopenbios/sys_info.h"
#define MAIN_STACK_SIZE 16384 @@ -49,6 +50,9 @@ static struct context main_ctx = { * it is to switch/switched. */ struct context * volatile __context = &main_ctx;
+/* Client program context */ +static struct context *client_ctx; + /* Stack for loaded ELF image */ static uint8_t image_stack[IMAGE_STACK_SIZE];
@@ -65,6 +69,10 @@ static void start_main(void) * We have to keep it in physical address since we will relocate. */ __boot_ctx = virt_to_phys(__context);
+ /* Set up client context */ + client_ctx = init_context(image_stack, sizeof image_stack, 1); + __context = client_ctx; + /* Start the real fun */ entry();
@@ -115,7 +123,7 @@ struct context *switch_to(struct context *ctx) /* Start ELF Boot image */ unsigned int start_elf(unsigned long entry_point, unsigned long param) { - struct context *ctx; + struct context *ctx = client_ctx;
/* According to IEEE 1275, PPC bindings: * @@ -127,8 +135,7 @@ unsigned int start_elf(unsigned long entry_point, unsigned long param) * * Yaboot and Linux use r3 and r4 for initrd address and size */ - - ctx = init_context(image_stack, sizeof image_stack, 1); + ctx->pc = entry_point; ctx->regs[REG_R5] = (unsigned long)of_client_callback; ctx->regs[REG_R6] = 0; diff --git a/arch/sparc32/context.c b/arch/sparc32/context.c index 555f628..50b9edf 100644 --- a/arch/sparc32/context.c +++ b/arch/sparc32/context.c @@ -33,6 +33,9 @@ static struct context main_ctx = { * it is to switch/switched. */ struct context * volatile __context = &main_ctx;
+/* Client program context */ +static struct context *client_ctx; + /* Stack for loaded ELF image */ static uint8_t image_stack[IMAGE_STACK_SIZE];
@@ -49,6 +52,10 @@ static void start_main(void) * We have to keep it in physical address since we will relocate. */ __boot_ctx = virt_to_phys(__context);
+ /* Set up client context */ + client_ctx = init_context(image_stack, sizeof image_stack, 1); + __context = client_ctx; + /* Start the real fun */ openbios();
@@ -102,9 +109,8 @@ struct context *switch_to(struct context *ctx) /* Start ELF Boot image */ unsigned int start_elf(unsigned long entry_point, unsigned long param) { - struct context *ctx; + struct context *ctx = client_ctx;
- ctx = init_context(image_stack, sizeof image_stack, 1); ctx->pc = entry_point; ctx->regs[REG_O0] = param;
diff --git a/arch/sparc64/context.c b/arch/sparc64/context.c index 5ab0045..1283c4c 100644 --- a/arch/sparc64/context.c +++ b/arch/sparc64/context.c @@ -33,6 +33,9 @@ static struct context main_ctx = { * it is to switch/switched. */ struct context * volatile __context = &main_ctx;
+/* Client program context */ +static struct context *client_ctx; + /* Stack for loaded ELF image */ static uint8_t image_stack[IMAGE_STACK_SIZE];
@@ -53,6 +56,10 @@ static void start_main(void) * We have to keep it in physical address since we will relocate. */ __boot_ctx = virt_to_phys(__context);
+ /* Set up client context */ + client_ctx = init_context(image_stack, sizeof image_stack, 1); + __context = client_ctx; + /* Start the real fun */ openbios();
@@ -104,9 +111,8 @@ struct context *switch_to(struct context *ctx) /* Start ELF Boot image */ uint64_t start_elf(uint64_t entry_point, uint64_t param) { - struct context *ctx; + struct context *ctx = client_ctx;
- ctx = init_context(image_stack, sizeof image_stack, 1); ctx->pc = entry_point; ctx->param[0] = param; //ctx->eax = 0xe1fb007; @@ -120,9 +126,8 @@ uint64_t start_elf(uint64_t entry_point, uint64_t param) /* Start client image */ uint64_t start_client_image(uint64_t entry_point, uint64_t cif_handler) { - struct context *ctx; + struct context *ctx = client_ctx;
- ctx = init_context(image_stack, sizeof image_stack, 0); ctx->pc = entry_point; ctx->npc = entry_point+4; ctx->regs[REG_O0] = 0; diff --git a/arch/x86/context.c b/arch/x86/context.c index d543f74..de852f4 100644 --- a/arch/x86/context.c +++ b/arch/x86/context.c @@ -45,6 +45,9 @@ static struct context main_ctx __attribute__((section (".initctx"))) = { * it is to switch/switched. */ struct context *__context = &main_ctx;
+/* Client program context */ +static struct context *client_ctx; + /* Stack for loaded ELF image */ static uint8_t image_stack[IMAGE_STACK_SIZE];
@@ -64,6 +67,11 @@ static void start_main(void) __boot_ctx = virt_to_phys(__context);
init_exceptions(); + + /* Set up client context */ + client_ctx = init_context(image_stack, sizeof image_stack, 1); + __context = client_ctx; + /* Start the real fun */ retval = openbios();
@@ -117,9 +125,8 @@ struct context *switch_to(struct context *ctx) /* Start ELF Boot image */ unsigned int start_elf(unsigned long entry_point, unsigned long param) { - struct context *ctx; + struct context *ctx = client_ctx;
- ctx = init_context(image_stack, sizeof image_stack, 1); ctx->eip = entry_point; ctx->param[0] = param; ctx->eax = 0xe1fb007;
This is in case we need to pass elf-boot parameters into the client executable.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- forth/debugging/client.fs | 1 + 1 file changed, 1 insertion(+)
diff --git a/forth/debugging/client.fs b/forth/debugging/client.fs index d1e2953..d3c986a 100644 --- a/forth/debugging/client.fs +++ b/forth/debugging/client.fs @@ -21,6 +21,7 @@ struct ( load-state ) /n field >ls.entry /n field >ls.file-size /n field >ls.file-type + /n field >ls.param constant load-state.size create load-state load-state.size allot
And switch start_elf() over to use it.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- arch/amd64/context.c | 42 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-)
diff --git a/arch/amd64/context.c b/arch/amd64/context.c index be70afe..4e792c7 100644 --- a/arch/amd64/context.c +++ b/arch/amd64/context.c @@ -5,6 +5,8 @@
#include "config.h" #include "kernel/kernel.h" +#include "libopenbios/bindings.h" +#include "libopenbios/initprogram.h" #include "segment.h" #include "context.h"
@@ -86,6 +88,16 @@ init_context(uint8_t *stack, uint32_t stack_size, int num_params) (stack + stack_size - (sizeof(*ctx) + num_params*sizeof(uint32_t))); memset(ctx, 0, sizeof(*ctx));
+ return ctx; +} + +/* init-program */ +int +arch_init_program(void) +{ + struct context volatile *ctx = __context; + ucell type, entry, param; + /* Fill in reasonable default for flat memory model */ ctx->gdt_base = virt_to_phys(gdt); ctx->gdt_limit = GDT_LIMIT; @@ -97,8 +109,26 @@ init_context(uint8_t *stack, uint32_t stack_size, int num_params) ctx->ss = FLAT_DS; ctx->esp = virt_to_phys(ESP_LOC(ctx)); ctx->return_addr = virt_to_phys(__exit_context); + + /* Set param */ + feval("load-state >ls.param @"); + param = POP(); + ctx->param[0] = param;
- return ctx; + /* Only elf-boot type has a param */ + feval("load-state >ls.file-type @"); + type = POP(); + if (type == 0) { + ctx->eax = 0xe1fb007; + ctx->ebx = param; + } + + /* Set entry point */ + feval("load-state >ls.entry @"); + entry = POP(); + ctx->eip = entry; + + return 0; }
/* Switch to another context. */ @@ -116,15 +146,15 @@ struct context *switch_to(struct context *ctx) return ret; }
-/* Start ELF Boot image */ +/* Start ELF image */ uint32_t start_elf(uint32_t entry_point, uint32_t param) { struct context *ctx = client_ctx;
- ctx->eip = entry_point; - ctx->param[0] = param; - ctx->eax = 0xe1fb007; - ctx->ebx = param; + PUSH(param); + feval("load-state >ls.param !"); + + arch_init_program();
ctx = switch_to(ctx); return ctx->eax;
And switch start_elf() over to use it.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- arch/ppc/qemu/context.c | 53 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 16 deletions(-)
diff --git a/arch/ppc/qemu/context.c b/arch/ppc/qemu/context.c index 74a604f..f956488 100644 --- a/arch/ppc/qemu/context.c +++ b/arch/ppc/qemu/context.c @@ -7,6 +7,7 @@ #include "kernel/kernel.h" #include "context.h" #include "libopenbios/bindings.h" +#include "libopenbios/initprogram.h" #include "libopenbios/sys_info.h"
#define MAIN_STACK_SIZE 16384 @@ -98,6 +99,41 @@ init_context(uint8_t *stack, uint32_t stack_size, int num_params) return ctx; }
+/* init-program */ +int +arch_init_program(void) +{ + volatile struct context *ctx = __context; + ucell entry, param; + + /* According to IEEE 1275, PPC bindings: + * + * MSR = FP, ME + (DR|IR) + * r1 = stack (32 K + 32 bytes link area above) + * r5 = client interface handler + * r6 = address of client program arguments (unused) + * r7 = length of client program arguments (unused) + * + * Yaboot and Linux use r3 and r4 for initrd address and size + */ + + ctx->regs[REG_R5] = (unsigned long)of_client_callback; + ctx->regs[REG_R6] = 0; + ctx->regs[REG_R7] = 0; + + /* Set param */ + feval("load-state >ls.param @"); + param = POP(); + ctx->param[0] = param; + + /* Set entry point */ + feval("load-state >ls.entry @"); + entry = POP(); + ctx->pc = entry; + + return 0; +} + /* Switch to another context. */ struct context *switch_to(struct context *ctx) { @@ -125,23 +161,8 @@ unsigned int start_elf(unsigned long entry_point, unsigned long param) { struct context *ctx = client_ctx;
- /* According to IEEE 1275, PPC bindings: - * - * MSR = FP, ME + (DR|IR) - * r1 = stack (32 K + 32 bytes link area above) - * r5 = client interface handler - * r6 = address of client program arguments (unused) - * r7 = length of client program arguments (unused) - * - * Yaboot and Linux use r3 and r4 for initrd address and size - */ + arch_init_program();
- ctx->pc = entry_point; - ctx->regs[REG_R5] = (unsigned long)of_client_callback; - ctx->regs[REG_R6] = 0; - ctx->regs[REG_R7] = 0; - ctx->param[0] = param; - ctx = switch_to(ctx); return ctx->regs[REG_R3]; }
And switch start_elf() over to use it.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- arch/sparc32/context.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-)
diff --git a/arch/sparc32/context.c b/arch/sparc32/context.c index 50b9edf..0a5b370 100644 --- a/arch/sparc32/context.c +++ b/arch/sparc32/context.c @@ -6,6 +6,8 @@ #include "config.h" #include "kernel/kernel.h" #include "context.h" +#include "libopenbios/bindings.h" +#include "libopenbios/initprogram.h" #include "libopenbios/sys_info.h" #include "boot.h" #include "openbios.h" @@ -63,6 +65,8 @@ static void start_main(void) __context = boot_ctx; }
+#define CTX_OFFSET(n) (sizeof(struct context) + n * sizeof(uint32_t)) + /* Setup a new context using the given stack. */ struct context * @@ -71,7 +75,7 @@ init_context(uint8_t *stack, uint32_t stack_size, int num_params) struct context *ctx;
ctx = (struct context *) - (stack + stack_size - (sizeof(*ctx) + num_params*sizeof(uint32_t))); + (stack + stack_size - CTX_OFFSET(num_params)); /* Use valid window state from startup */ memcpy(ctx, &main_ctx, sizeof(struct context));
@@ -82,6 +86,24 @@ init_context(uint8_t *stack, uint32_t stack_size, int num_params) return ctx; }
+/* init-program */ +int +arch_init_program(void) +{ + volatile struct context *ctx = __context; + ucell entry; + + ctx->regs[REG_O0] = (unsigned long)romvec; + ctx->regs[REG_SP] = (unsigned long)malloc(IMAGE_STACK_SIZE) + IMAGE_STACK_SIZE - CTX_OFFSET(1); + + /* Set entry point */ + feval("load-state >ls.entry @"); + entry = POP(); + ctx->pc = entry; + + return 0; +} + /* Switch to another context. */ struct context *switch_to(struct context *ctx) { @@ -111,8 +133,7 @@ unsigned int start_elf(unsigned long entry_point, unsigned long param) { struct context *ctx = client_ctx;
- ctx->pc = entry_point; - ctx->regs[REG_O0] = param; + arch_init_program();
ctx = switch_to(ctx); return ctx->regs[REG_O0];
And switch start_elf() over to use it.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- arch/sparc64/context.c | 50 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 12 deletions(-)
diff --git a/arch/sparc64/context.c b/arch/sparc64/context.c index 1283c4c..3177e8c 100644 --- a/arch/sparc64/context.c +++ b/arch/sparc64/context.c @@ -6,6 +6,8 @@ #include "config.h" #include "kernel/kernel.h" #include "context.h" +#include "libopenbios/bindings.h" +#include "libopenbios/initprogram.h" #include "libopenbios/sys_info.h" #include "boot.h" #include "openbios.h" @@ -72,6 +74,8 @@ static uint64_t ALIGN_SIZE(uint64_t x, uint64_t a) return (x + a - 1) & ~(a-1); }
+#define CTX_OFFSET(n) ALIGN_SIZE(sizeof(struct context) + n * sizeof(uint64_t), sizeof(uint64_t)) + /* Setup a new context using the given stack. */ struct context * @@ -80,18 +84,43 @@ init_context(uint8_t *stack, uint64_t stack_size, int num_params) struct context *ctx; uint8_t *stack_top = stack + stack_size;
- ctx = (struct context *) - (stack_top - ALIGN_SIZE(sizeof(*ctx) + num_params*sizeof(uint64_t), sizeof(uint64_t))); + ctx = (struct context *)(stack_top - CTX_OFFSET(num_params)); /* Use valid window state from startup */ memcpy(ctx, &main_ctx, sizeof(struct context));
/* Fill in reasonable default for flat memory model */ - ctx->regs[REG_SP] = virt_to_phys(stack_top - STACK_BIAS - 192); ctx->return_addr = virt_to_phys(__exit_context);
return ctx; }
+/* init-program */ +extern uint64_t sparc64_of_client_interface; + +int +arch_init_program(void) +{ + volatile struct context *ctx = __context; + ucell entry, param; + + ctx->regs[REG_O0] = 0; + ctx->regs[REG_O0+4] = (uint64_t)&sparc64_of_client_interface; + ctx->regs[REG_SP] = (uint64_t)malloc(IMAGE_STACK_SIZE) + IMAGE_STACK_SIZE - CTX_OFFSET(0) - STACK_BIAS; + + /* Set param */ + feval("load-state >ls.param @"); + param = POP(); + ctx->param[0] = param; + + /* Set entry point */ + feval("load-state >ls.entry @"); + entry = POP(); + ctx->pc = entry; + ctx->npc = entry+4; + + return 0; +} + /* Switch to another context. */ struct context *switch_to(struct context *ctx) { @@ -113,13 +142,13 @@ uint64_t start_elf(uint64_t entry_point, uint64_t param) { struct context *ctx = client_ctx;
- ctx->pc = entry_point; - ctx->param[0] = param; - //ctx->eax = 0xe1fb007; - //ctx->ebx = param; + PUSH(param); + feval("load-state >ls.param !");
+ arch_init_program(); + ctx = switch_to(ctx); - //return ctx->eax; + return 0; }
@@ -128,10 +157,7 @@ uint64_t start_client_image(uint64_t entry_point, uint64_t cif_handler) { struct context *ctx = client_ctx;
- ctx->pc = entry_point; - ctx->npc = entry_point+4; - ctx->regs[REG_O0] = 0; - ctx->regs[REG_O0+4] = cif_handler; + arch_init_program();
ctx = switch_to(ctx);
And switch start_elf() over to use it.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- arch/x86/context.c | 40 +++++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-)
diff --git a/arch/x86/context.c b/arch/x86/context.c index de852f4..6d57bfa 100644 --- a/arch/x86/context.c +++ b/arch/x86/context.c @@ -10,6 +10,8 @@ #include "kernel/kernel.h" #include "segment.h" #include "context.h" +#include "libopenbios/bindings.h" +#include "libopenbios/initprogram.h" #include "libopenbios/sys_info.h" #include "boot.h" #include "openbios.h" @@ -93,6 +95,16 @@ init_context(uint8_t *stack, uint32_t stack_size, int num_params) (stack + stack_size - (sizeof(*ctx) + num_params*sizeof(uint32_t))); memset(ctx, 0, sizeof(*ctx));
+ return ctx; +} + +/* init-program */ +int +arch_init_program(void) +{ + struct context volatile *ctx = __context; + ucell type, entry, param; + /* Fill in reasonable default for flat memory model */ ctx->gdt_base = virt_to_phys(gdt); ctx->gdt_limit = GDT_LIMIT; @@ -104,8 +116,26 @@ init_context(uint8_t *stack, uint32_t stack_size, int num_params) ctx->ss = FLAT_DS; ctx->esp = virt_to_phys(ESP_LOC(ctx)); ctx->return_addr = virt_to_phys(__exit_context); + + /* Set param */ + feval("load-state >ls.param @"); + param = POP(); + ctx->param[0] = param;
- return ctx; + /* Only elf-boot type has a param */ + feval("load-state >ls.file-type @"); + type = POP(); + if (type == 0) { + ctx->eax = 0xe1fb007; + ctx->ebx = param; + } + + /* Set entry point */ + feval("load-state >ls.entry @"); + entry = POP(); + ctx->eip = entry; + + return 0; }
/* Switch to another context. */ @@ -127,10 +157,10 @@ unsigned int start_elf(unsigned long entry_point, unsigned long param) { struct context *ctx = client_ctx;
- ctx->eip = entry_point; - ctx->param[0] = param; - ctx->eax = 0xe1fb007; - ctx->ebx = param; + PUSH(param); + feval("load-state >ls.param !"); + + arch_init_program();
ctx = switch_to(ctx); return ctx->eax;
This enables them to be launched from a native context.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- include/libopenbios/initprogram.h | 3 +++ libopenbios/initprogram.c | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+)
diff --git a/include/libopenbios/initprogram.h b/include/libopenbios/initprogram.h index 01fc0c1..406b84a 100644 --- a/include/libopenbios/initprogram.h +++ b/include/libopenbios/initprogram.h @@ -20,4 +20,7 @@ extern int arch_init_program(void); extern void init_program(void);
+void init_fcode_context(void); +void init_forth_context(void); + #endif /* _H_INITPROGRAM */ diff --git a/libopenbios/initprogram.c b/libopenbios/initprogram.c index 1fa33ba..9cf3780 100644 --- a/libopenbios/initprogram.c +++ b/libopenbios/initprogram.c @@ -83,3 +83,22 @@ void init_program(void) #endif
} + +void init_fcode_context(void) +{ + /* Execute FCode payload */ + printk("Evaluating FCode...\n"); + fword("load-base"); + PUSH(1); + fword("byte-load"); +} + + +void init_forth_context(void) +{ + /* Execute Forth payload */ + printk("Evaluating Forth...\n"); + fword("load-base"); + feval("load-state >ls.file-size @"); + fword("eval2"); +}
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- arch/sparc32/boot.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-)
diff --git a/arch/sparc32/boot.c b/arch/sparc32/boot.c index af1a263..c7b58a8 100644 --- a/arch/sparc32/boot.c +++ b/arch/sparc32/boot.c @@ -8,6 +8,7 @@ #include "drivers/drivers.h" #include "libc/diskio.h" #include "libc/vsprintf.h" +#include "libopenbios/initprogram.h" #include "libopenbios/ofmem.h" #include "libopenbios/sys_info.h" #include "openprom.h" @@ -192,7 +193,7 @@ static void setup_romvec(void)
void go(void) { - ucell address, type, size; + ucell address, type; int image_retval = 0;
/* Get the entry point and the type (see forth/debugging/client.fs) */ @@ -200,8 +201,6 @@ void go(void) address = POP(); feval("load-state >ls.file-type @"); type = POP(); - feval("load-state >ls.file-size @"); - size = POP();
setup_romvec();
@@ -231,19 +230,14 @@ void go(void)
case 0x10: /* Start Fcode image */ - printk("Evaluating FCode...\n"); - PUSH(address); - PUSH(1); - fword("byte-load"); - image_retval = 0; + image_retval = start_elf((unsigned long)&init_fcode_context, + (unsigned long)romvec); break;
case 0x11: /* Start Forth image */ - PUSH(address); - PUSH(size); - fword("eval2"); - image_retval = 0; + image_retval = start_elf((unsigned long)&init_forth_context, + (unsigned long)romvec); break; }
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- arch/sparc64/boot.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-)
diff --git a/arch/sparc64/boot.c b/arch/sparc64/boot.c index 48922d4..c2e3dc1 100644 --- a/arch/sparc64/boot.c +++ b/arch/sparc64/boot.c @@ -7,6 +7,7 @@ #include "arch/common/nvram.h" #include "libc/diskio.h" #include "libc/vsprintf.h" +#include "libopenbios/initprogram.h" #include "libopenbios/sys_info.h" #include "boot.h"
@@ -21,7 +22,7 @@ extern int sparc64_of_client_interface( int *params );
void go(void) { - ucell address, type, size; + ucell address, type; int image_retval = 0;
/* Get the entry point and the type (see forth/debugging/client.fs) */ @@ -29,8 +30,6 @@ void go(void) address = POP(); feval("load-state >ls.file-type @"); type = POP(); - feval("load-state >ls.file-size @"); - size = POP();
printk("\nJumping to entry point " FMT_ucellx " for type " FMT_ucellx "...\n", address, type);
@@ -52,19 +51,12 @@ void go(void)
case 0x10: /* Start Fcode image */ - printk("Evaluating FCode...\n"); - PUSH(address); - PUSH(1); - fword("byte-load"); - image_retval = 0; + image_retval = start_client_image((uint64_t)&init_fcode_context, (uint64_t)&sparc64_of_client_interface); break;
case 0x11: /* Start Forth image */ - PUSH(address); - PUSH(size); - fword("eval2"); - image_retval = 0; + image_retval = start_client_image((uint64_t)&init_forth_context, (uint64_t)&sparc64_of_client_interface); break; }
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- arch/x86/boot.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-)
diff --git a/arch/x86/boot.c b/arch/x86/boot.c index 6573259..1eae76c 100644 --- a/arch/x86/boot.c +++ b/arch/x86/boot.c @@ -11,12 +11,13 @@ #include "libopenbios/bindings.h" #include "arch/common/nvram.h" #include "libc/diskio.h" +#include "libopenbios/initprogram.h" #include "libopenbios/sys_info.h" #include "boot.h"
void go(void) { - ucell address, type, size; + ucell address, type; int image_retval = 0;
/* Get the entry point and the type (see forth/debugging/client.fs) */ @@ -24,8 +25,6 @@ void go(void) address = POP(); feval("load-state >ls.file-type @"); type = POP(); - feval("load-state >ls.file-size @"); - size = POP();
printk("\nJumping to entry point " FMT_ucellx " for type " FMT_ucellx "...\n", address, type);
@@ -47,19 +46,14 @@ void go(void)
case 0x10: /* Start Fcode image */ - printk("Evaluating FCode...\n"); - PUSH(address); - PUSH(1); - fword("byte-load"); - image_retval = 0; + image_retval = start_elf((unsigned long)&init_fcode_context, + (uint32_t)NULL); break;
case 0x11: /* Start Forth image */ - PUSH(address); - PUSH(size); - fword("eval2"); - image_retval = 0; + image_retval = start_elf((unsigned long)&init_forth_context, + (uint32_t)NULL); break; }
Since the parameter is now already available to arch_init_program(), there is no need to supply it separately to start_elf().
Remove the second parameter and fix up the callers, including standardising the prototype of start_elf() across all architectures.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- arch/amd64/context.c | 5 +---- arch/ppc/qemu/context.c | 4 ++-- arch/ppc/qemu/init.c | 4 ++-- arch/sparc32/boot.c | 25 +++++++++++-------------- arch/sparc32/boot.h | 2 +- arch/sparc32/context.c | 2 +- arch/sparc64/boot.c | 2 +- arch/sparc64/boot.h | 2 +- arch/sparc64/context.c | 5 +---- arch/x86/boot.c | 12 +++++------- arch/x86/boot.h | 2 +- arch/x86/context.c | 5 +---- libopenbios/elf_load.c | 2 ++ 13 files changed, 30 insertions(+), 42 deletions(-)
diff --git a/arch/amd64/context.c b/arch/amd64/context.c index 4e792c7..8837cbb 100644 --- a/arch/amd64/context.c +++ b/arch/amd64/context.c @@ -147,13 +147,10 @@ struct context *switch_to(struct context *ctx) }
/* Start ELF image */ -uint32_t start_elf(uint32_t entry_point, uint32_t param) +unsigned int start_elf(unsigned long entry_point) { struct context *ctx = client_ctx;
- PUSH(param); - feval("load-state >ls.param !"); - arch_init_program();
ctx = switch_to(ctx); diff --git a/arch/ppc/qemu/context.c b/arch/ppc/qemu/context.c index f956488..6fbec17 100644 --- a/arch/ppc/qemu/context.c +++ b/arch/ppc/qemu/context.c @@ -32,7 +32,7 @@ static void start_main(void); /* forward decl. */ void __exit_context(void); /* assembly routine */
-unsigned int start_elf(unsigned long entry_point, unsigned long param); +unsigned int start_elf(unsigned long entry_point); void entry(void); void of_client_callback(void);
@@ -157,7 +157,7 @@ struct context *switch_to(struct context *ctx) }
/* Start ELF Boot image */ -unsigned int start_elf(unsigned long entry_point, unsigned long param) +unsigned int start_elf(unsigned long entry_point) { struct context *ctx = client_ctx;
diff --git a/arch/ppc/qemu/init.c b/arch/ppc/qemu/init.c index f6bbce2..a401a9c 100644 --- a/arch/ppc/qemu/init.c +++ b/arch/ppc/qemu/init.c @@ -596,7 +596,7 @@ id_cpu(void) }
static void go(void); -unsigned int start_elf(unsigned long entry_point, unsigned long param); +unsigned int start_elf(unsigned long entry_point);
static void go(void) @@ -611,7 +611,7 @@ go(void) feval("load-state >ls.entry @"); addr = POP();
- start_elf((unsigned long)addr, 0); + start_elf((unsigned long)addr); }
static void kvm_of_init(void) diff --git a/arch/sparc32/boot.c b/arch/sparc32/boot.c index c7b58a8..d65913a 100644 --- a/arch/sparc32/boot.c +++ b/arch/sparc32/boot.c @@ -209,35 +209,27 @@ void go(void) switch (type) { case 0x0: /* Start ELF boot image */ - image_retval = start_elf((unsigned long)address, - (unsigned long)romvec); - + image_retval = start_elf((unsigned long)address); break;
case 0x1: /* Start ELF image */ - image_retval = start_elf((unsigned long)address, - (unsigned long)romvec); - + image_retval = start_elf((unsigned long)address); break;
case 0x5: /* Start a.out image */ - image_retval = start_elf((unsigned long)address, - (unsigned long)romvec); - + image_retval = start_elf((unsigned long)address); break;
case 0x10: /* Start Fcode image */ - image_retval = start_elf((unsigned long)&init_fcode_context, - (unsigned long)romvec); + image_retval = start_elf((unsigned long)&init_fcode_context); break;
case 0x11: /* Start Forth image */ - image_retval = start_elf((unsigned long)&init_forth_context, - (unsigned long)romvec); + image_retval = start_elf((unsigned long)&init_forth_context); break; }
@@ -250,6 +242,11 @@ void boot(void) /* Boot preloaded kernel */ if (kernel_size) { printk("[sparc] Kernel already loaded\n"); - start_elf(kernel_image, (unsigned long)romvec); + + PUSH(kernel_image); + feval("load-state >ls.entry !"); + + arch_init_program(); + start_elf(kernel_image); } } diff --git a/arch/sparc32/boot.h b/arch/sparc32/boot.h index 9bfc07e..6aabba3 100644 --- a/arch/sparc32/boot.h +++ b/arch/sparc32/boot.h @@ -11,7 +11,7 @@ int linux_load(struct sys_info *info, const char *file, const char *cmdline);
// context.c extern struct context * volatile __context; -unsigned int start_elf(unsigned long entry_point, unsigned long param); +unsigned int start_elf(unsigned long entry_point);
// boot.c extern const char *bootpath; diff --git a/arch/sparc32/context.c b/arch/sparc32/context.c index 0a5b370..44abc74 100644 --- a/arch/sparc32/context.c +++ b/arch/sparc32/context.c @@ -129,7 +129,7 @@ struct context *switch_to(struct context *ctx) }
/* Start ELF Boot image */ -unsigned int start_elf(unsigned long entry_point, unsigned long param) +unsigned int start_elf(unsigned long entry_point) { struct context *ctx = client_ctx;
diff --git a/arch/sparc64/boot.c b/arch/sparc64/boot.c index c2e3dc1..08d7f51 100644 --- a/arch/sparc64/boot.c +++ b/arch/sparc64/boot.c @@ -36,7 +36,7 @@ void go(void) switch (type) { case 0x0: /* Start ELF boot image */ - image_retval = start_elf(address, (uint64_t)&elf_boot_notes); + image_retval = start_elf(address); break;
case 0x1: diff --git a/arch/sparc64/boot.h b/arch/sparc64/boot.h index 3ab05e0..aa9894e 100644 --- a/arch/sparc64/boot.h +++ b/arch/sparc64/boot.h @@ -11,7 +11,7 @@ int linux_load(struct sys_info *info, const char *file, const char *cmdline);
// context.c extern struct context * volatile __context; -uint64_t start_elf(uint64_t entry_point, uint64_t param); +unsigned int start_elf(unsigned long entry_point); uint64_t start_client_image(uint64_t entry_point, uint64_t cif_handler);
// boot.c diff --git a/arch/sparc64/context.c b/arch/sparc64/context.c index 3177e8c..f07f1ef 100644 --- a/arch/sparc64/context.c +++ b/arch/sparc64/context.c @@ -138,13 +138,10 @@ struct context *switch_to(struct context *ctx) }
/* Start ELF Boot image */ -uint64_t start_elf(uint64_t entry_point, uint64_t param) +unsigned int start_elf(unsigned long entry_point) { struct context *ctx = client_ctx;
- PUSH(param); - feval("load-state >ls.param !"); - arch_init_program();
ctx = switch_to(ctx); diff --git a/arch/x86/boot.c b/arch/x86/boot.c index 1eae76c..688b24e 100644 --- a/arch/x86/boot.c +++ b/arch/x86/boot.c @@ -31,29 +31,27 @@ void go(void) switch (type) { case 0x0: /* Start ELF boot image */ - image_retval = start_elf(address, (uint32_t)&elf_boot_notes); + image_retval = start_elf(address); break;
case 0x1: /* Start ELF image */ - image_retval = start_elf(address, (uint32_t)NULL); + image_retval = start_elf(address); break;
case 0x5: /* Start a.out image */ - image_retval = start_elf(address, (uint32_t)NULL); + image_retval = start_elf(address); break;
case 0x10: /* Start Fcode image */ - image_retval = start_elf((unsigned long)&init_fcode_context, - (uint32_t)NULL); + image_retval = start_elf((unsigned long)&init_fcode_context); break;
case 0x11: /* Start Forth image */ - image_retval = start_elf((unsigned long)&init_forth_context, - (uint32_t)NULL); + image_retval = start_elf((unsigned long)&init_forth_context); break; }
diff --git a/arch/x86/boot.h b/arch/x86/boot.h index 749c608..fff6719 100644 --- a/arch/x86/boot.h +++ b/arch/x86/boot.h @@ -11,7 +11,7 @@ int linux_load(struct sys_info *info, const char *file, const char *cmdline);
/* context.c */ extern struct context *__context; -unsigned int start_elf(unsigned long entry_point, unsigned long param); +unsigned int start_elf(unsigned long entry_point);
/* boot.c */ extern void boot(void); diff --git a/arch/x86/context.c b/arch/x86/context.c index 6d57bfa..17d4f0e 100644 --- a/arch/x86/context.c +++ b/arch/x86/context.c @@ -153,13 +153,10 @@ struct context *switch_to(struct context *ctx) }
/* Start ELF Boot image */ -unsigned int start_elf(unsigned long entry_point, unsigned long param) +unsigned int start_elf(unsigned long entry_point) { struct context *ctx = client_ctx;
- PUSH(param); - feval("load-state >ls.param !"); - arch_init_program();
ctx = switch_to(ctx); diff --git a/libopenbios/elf_load.c b/libopenbios/elf_load.c index b0b19ee..aa81e4c 100644 --- a/libopenbios/elf_load.c +++ b/libopenbios/elf_load.c @@ -442,6 +442,8 @@ elf_load(struct sys_info *info, ihandle_t dev, const char *cmdline, void **boot_ if (boot_notes) { *boot_notes = (void *)virt_to_phys(build_boot_notes(info, cmdline)); feval("elf-boot load-state >ls.file-type !"); + PUSH((ucell)*boot_notes); + feval("elf-boot load-state >ls.param !"); } else { feval("elf load-state >ls.file-type !"); }
Since the client context is now set by arch_init_program(), start_elf() and start_client_image() are now identical so the latter can be removed.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- arch/sparc64/boot.c | 8 ++++---- arch/sparc64/boot.h | 1 - arch/sparc64/context.c | 12 ------------ 3 files changed, 4 insertions(+), 17 deletions(-)
diff --git a/arch/sparc64/boot.c b/arch/sparc64/boot.c index 08d7f51..9eac52c 100644 --- a/arch/sparc64/boot.c +++ b/arch/sparc64/boot.c @@ -41,22 +41,22 @@ void go(void)
case 0x1: /* Start ELF image */ - image_retval = start_client_image(address, (uint64_t)&sparc64_of_client_interface); + image_retval = start_elf(address); break;
case 0x5: /* Start a.out image */ - image_retval = start_client_image(address, (uint64_t)&sparc64_of_client_interface); + image_retval = start_elf(address); break;
case 0x10: /* Start Fcode image */ - image_retval = start_client_image((uint64_t)&init_fcode_context, (uint64_t)&sparc64_of_client_interface); + image_retval = start_elf((unsigned long)&init_fcode_context); break;
case 0x11: /* Start Forth image */ - image_retval = start_client_image((uint64_t)&init_forth_context, (uint64_t)&sparc64_of_client_interface); + image_retval = start_elf((unsigned long)&init_forth_context); break; }
diff --git a/arch/sparc64/boot.h b/arch/sparc64/boot.h index aa9894e..d7ca862 100644 --- a/arch/sparc64/boot.h +++ b/arch/sparc64/boot.h @@ -12,7 +12,6 @@ int linux_load(struct sys_info *info, const char *file, const char *cmdline); // context.c extern struct context * volatile __context; unsigned int start_elf(unsigned long entry_point); -uint64_t start_client_image(uint64_t entry_point, uint64_t cif_handler);
// boot.c extern uint64_t kernel_image; diff --git a/arch/sparc64/context.c b/arch/sparc64/context.c index f07f1ef..ed4d878 100644 --- a/arch/sparc64/context.c +++ b/arch/sparc64/context.c @@ -148,15 +148,3 @@ unsigned int start_elf(unsigned long entry_point)
return 0; } - -/* Start client image */ -uint64_t start_client_image(uint64_t entry_point, uint64_t cif_handler) -{ - struct context *ctx = client_ctx; - - arch_init_program(); - - ctx = switch_to(ctx); - - return 0; -}
Also fix up the incorrect x86 prototype which is missing the volatile qualifier.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- arch/ppc/qemu/context.c | 1 - arch/sparc32/boot.h | 4 ---- arch/sparc64/boot.h | 4 ---- arch/x86/boot.h | 4 ---- arch/x86/context.c | 2 +- include/libopenbios/initprogram.h | 3 +++ 6 files changed, 4 insertions(+), 14 deletions(-)
diff --git a/arch/ppc/qemu/context.c b/arch/ppc/qemu/context.c index 6fbec17..cbf2380 100644 --- a/arch/ppc/qemu/context.c +++ b/arch/ppc/qemu/context.c @@ -32,7 +32,6 @@ static void start_main(void); /* forward decl. */ void __exit_context(void); /* assembly routine */
-unsigned int start_elf(unsigned long entry_point); void entry(void); void of_client_callback(void);
diff --git a/arch/sparc32/boot.h b/arch/sparc32/boot.h index 6aabba3..0001699 100644 --- a/arch/sparc32/boot.h +++ b/arch/sparc32/boot.h @@ -9,10 +9,6 @@ // linux_load.c int linux_load(struct sys_info *info, const char *file, const char *cmdline);
-// context.c -extern struct context * volatile __context; -unsigned int start_elf(unsigned long entry_point); - // boot.c extern const char *bootpath; extern void boot(void); diff --git a/arch/sparc64/boot.h b/arch/sparc64/boot.h index d7ca862..f7b739f 100644 --- a/arch/sparc64/boot.h +++ b/arch/sparc64/boot.h @@ -9,10 +9,6 @@ // linux_load.c int linux_load(struct sys_info *info, const char *file, const char *cmdline);
-// context.c -extern struct context * volatile __context; -unsigned int start_elf(unsigned long entry_point); - // boot.c extern uint64_t kernel_image; extern uint64_t kernel_size; diff --git a/arch/x86/boot.h b/arch/x86/boot.h index fff6719..94c37b5 100644 --- a/arch/x86/boot.h +++ b/arch/x86/boot.h @@ -9,10 +9,6 @@ /* linux_load.c */ int linux_load(struct sys_info *info, const char *file, const char *cmdline);
-/* context.c */ -extern struct context *__context; -unsigned int start_elf(unsigned long entry_point); - /* boot.c */ extern void boot(void); extern void go(void); diff --git a/arch/x86/context.c b/arch/x86/context.c index 17d4f0e..6bb2f69 100644 --- a/arch/x86/context.c +++ b/arch/x86/context.c @@ -45,7 +45,7 @@ static struct context main_ctx __attribute__((section (".initctx"))) = {
/* This is used by assembly routine to load/store the context which * it is to switch/switched. */ -struct context *__context = &main_ctx; +struct context * volatile __context = &main_ctx;
/* Client program context */ static struct context *client_ctx; diff --git a/include/libopenbios/initprogram.h b/include/libopenbios/initprogram.h index 406b84a..c42d956 100644 --- a/include/libopenbios/initprogram.h +++ b/include/libopenbios/initprogram.h @@ -17,6 +17,9 @@ #ifndef _H_INITPROGRAM #define _H_INITPROGRAM
+extern struct context * volatile __context; +extern unsigned int start_elf(unsigned long address); + extern int arch_init_program(void); extern void init_program(void);
Add an (arch-go) hook for architectures that need to do their own thing before starting an image, and switch the callers over to use it.
Also clarify the state-valid check: any non-zero value is considered true.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- arch/ppc/qemu/init.c | 14 +++-------- arch/sparc32/boot.c | 48 +------------------------------------ arch/sparc32/boot.h | 2 +- arch/sparc32/openbios.c | 2 +- arch/sparc64/boot.c | 44 ---------------------------------- arch/sparc64/boot.h | 1 - arch/sparc64/openbios.c | 1 - arch/unix/boot.c | 8 +++++++ arch/x86/boot.c | 43 --------------------------------- arch/x86/boot.h | 2 +- arch/x86/openbios.c | 1 - forth/debugging/client.fs | 14 ++++++----- include/libopenbios/initprogram.h | 2 ++ libopenbios/init.c | 3 +++ libopenbios/initprogram.c | 33 +++++++++++++++++++++++++ 15 files changed, 61 insertions(+), 157 deletions(-)
diff --git a/arch/ppc/qemu/init.c b/arch/ppc/qemu/init.c index a401a9c..2f66ab4 100644 --- a/arch/ppc/qemu/init.c +++ b/arch/ppc/qemu/init.c @@ -595,23 +595,15 @@ id_cpu(void) } }
-static void go(void); -unsigned int start_elf(unsigned long entry_point); +static void arch_go(void);
static void -go(void) +arch_go(void) { - ucell addr; - /* Insert copyright property for MacOS 9 and below */ if (find_dev("/rom/macos")) { fword("insert-copyright-property"); } - - feval("load-state >ls.entry @"); - addr = POP(); - - start_elf((unsigned long)addr); }
static void kvm_of_init(void) @@ -1016,5 +1008,5 @@ arch_of_init(void) bind_func("(adler32)", adler32);
bind_func("platform-boot", boot); - bind_func("(go)", go); + bind_func("(arch-go)", arch_go); } diff --git a/arch/sparc32/boot.c b/arch/sparc32/boot.c index d65913a..35fd473 100644 --- a/arch/sparc32/boot.c +++ b/arch/sparc32/boot.c @@ -24,7 +24,7 @@ const void *romvec;
static struct linux_mlist_v0 *totphyslist, *availlist, *prommaplist;
-static void setup_romvec(void) +void setup_romvec(void) { /* SPARC32 is slightly unusual in that before invoking any loaders, a romvec array needs to be set up to pass certain parameters using a C struct. Hence this function @@ -191,52 +191,6 @@ static void setup_romvec(void) }
-void go(void) -{ - ucell address, type; - int image_retval = 0; - - /* Get the entry point and the type (see forth/debugging/client.fs) */ - feval("load-state >ls.entry @"); - address = POP(); - feval("load-state >ls.file-type @"); - type = POP(); - - setup_romvec(); - - printk("\nJumping to entry point " FMT_ucellx " for type " FMT_ucellx "...\n", address, type); - - switch (type) { - case 0x0: - /* Start ELF boot image */ - image_retval = start_elf((unsigned long)address); - break; - - case 0x1: - /* Start ELF image */ - image_retval = start_elf((unsigned long)address); - break; - - case 0x5: - /* Start a.out image */ - image_retval = start_elf((unsigned long)address); - break; - - case 0x10: - /* Start Fcode image */ - image_retval = start_elf((unsigned long)&init_fcode_context); - break; - - case 0x11: - /* Start Forth image */ - image_retval = start_elf((unsigned long)&init_forth_context); - break; - } - - printk("Image returned with return value %#x\n", image_retval); -} - - void boot(void) { /* Boot preloaded kernel */ diff --git a/arch/sparc32/boot.h b/arch/sparc32/boot.h index 0001699..e372acc 100644 --- a/arch/sparc32/boot.h +++ b/arch/sparc32/boot.h @@ -12,7 +12,7 @@ int linux_load(struct sys_info *info, const char *file, const char *cmdline); // boot.c extern const char *bootpath; extern void boot(void); -extern void go(void); +extern void setup_romvec(void);
// sys_info.c extern unsigned int qemu_mem_size; diff --git a/arch/sparc32/openbios.c b/arch/sparc32/openbios.c index 10ac9b9..dd31c23 100644 --- a/arch/sparc32/openbios.c +++ b/arch/sparc32/openbios.c @@ -915,7 +915,7 @@ arch_init( void ) device_end(); bind_func("platform-boot", boot ); - bind_func("(go)", go ); + bind_func("(arch-go)", setup_romvec ); /* Set up other properties */ push_str("/chosen"); diff --git a/arch/sparc64/boot.c b/arch/sparc64/boot.c index 9eac52c..7a287f2 100644 --- a/arch/sparc64/boot.c +++ b/arch/sparc64/boot.c @@ -19,50 +19,6 @@ char boot_device;
extern int sparc64_of_client_interface( int *params );
- -void go(void) -{ - ucell address, type; - int image_retval = 0; - - /* Get the entry point and the type (see forth/debugging/client.fs) */ - feval("load-state >ls.entry @"); - address = POP(); - feval("load-state >ls.file-type @"); - type = POP(); - - printk("\nJumping to entry point " FMT_ucellx " for type " FMT_ucellx "...\n", address, type); - - switch (type) { - case 0x0: - /* Start ELF boot image */ - image_retval = start_elf(address); - break; - - case 0x1: - /* Start ELF image */ - image_retval = start_elf(address); - break; - - case 0x5: - /* Start a.out image */ - image_retval = start_elf(address); - break; - - case 0x10: - /* Start Fcode image */ - image_retval = start_elf((unsigned long)&init_fcode_context); - break; - - case 0x11: - /* Start Forth image */ - image_retval = start_elf((unsigned long)&init_forth_context); - break; - } - - printk("Image returned with return value %#x\n", image_retval); -} - /* ( path len -- path len ) */
void boot(void) diff --git a/arch/sparc64/boot.h b/arch/sparc64/boot.h index f7b739f..fef0573 100644 --- a/arch/sparc64/boot.h +++ b/arch/sparc64/boot.h @@ -16,7 +16,6 @@ extern uint64_t qemu_cmdline; extern uint64_t cmdline_size; extern char boot_device; extern void boot(void); -extern void go(void);
// sys_info.c extern uint64_t qemu_mem_size; diff --git a/arch/sparc64/openbios.c b/arch/sparc64/openbios.c index 4557f7f..9a1d56c 100644 --- a/arch/sparc64/openbios.c +++ b/arch/sparc64/openbios.c @@ -586,7 +586,6 @@ arch_init( void ) obp_ticks_pointer = cell2pointer(POP());
bind_func("platform-boot", boot ); - bind_func("(go)", go); }
unsigned long isa_io_base; diff --git a/arch/unix/boot.c b/arch/unix/boot.c index f4a2942..d65681f 100644 --- a/arch/unix/boot.c +++ b/arch/unix/boot.c @@ -10,6 +10,7 @@
void boot(void); void *load_elf(char *spec); +unsigned int start_elf(unsigned long address);
void *load_elf(char *spec) @@ -82,3 +83,10 @@ boot( void ) else printk("failed.\n"); } + +unsigned int +start_elf(unsigned long address) +{ + return 0; +} + diff --git a/arch/x86/boot.c b/arch/x86/boot.c index 688b24e..61f6562 100644 --- a/arch/x86/boot.c +++ b/arch/x86/boot.c @@ -15,49 +15,6 @@ #include "libopenbios/sys_info.h" #include "boot.h"
-void go(void) -{ - ucell address, type; - int image_retval = 0; - - /* Get the entry point and the type (see forth/debugging/client.fs) */ - feval("load-state >ls.entry @"); - address = POP(); - feval("load-state >ls.file-type @"); - type = POP(); - - printk("\nJumping to entry point " FMT_ucellx " for type " FMT_ucellx "...\n", address, type); - - switch (type) { - case 0x0: - /* Start ELF boot image */ - image_retval = start_elf(address); - break; - - case 0x1: - /* Start ELF image */ - image_retval = start_elf(address); - break; - - case 0x5: - /* Start a.out image */ - image_retval = start_elf(address); - break; - - case 0x10: - /* Start Fcode image */ - image_retval = start_elf((unsigned long)&init_fcode_context); - break; - - case 0x11: - /* Start Forth image */ - image_retval = start_elf((unsigned long)&init_forth_context); - break; - } - - printk("Image returned with return value %#x\n", image_retval); -} -
void boot(void) { diff --git a/arch/x86/boot.h b/arch/x86/boot.h index 94c37b5..cdc5435 100644 --- a/arch/x86/boot.h +++ b/arch/x86/boot.h @@ -11,4 +11,4 @@ int linux_load(struct sys_info *info, const char *file, const char *cmdline);
/* boot.c */ extern void boot(void); -extern void go(void); + diff --git a/arch/x86/openbios.c b/arch/x86/openbios.c index 6145436..d8a0f9e 100644 --- a/arch/x86/openbios.c +++ b/arch/x86/openbios.c @@ -73,7 +73,6 @@ arch_init( void ) #endif device_end(); bind_func("platform-boot", boot ); - bind_func("(go)", go ); }
extern struct _console_ops arch_console_ops; diff --git a/forth/debugging/client.fs b/forth/debugging/client.fs index d3c986a..acad733 100644 --- a/forth/debugging/client.fs +++ b/forth/debugging/client.fs @@ -204,18 +204,20 @@ variable file-size ;
: go ( -- ) - state-valid @ not if + state-valid @ 0= if s" No valid state has been set by load or init-program" type cr exit then
- \ Call the architecture-specific code to launch the client image + \ Call any architecture-specific code + s" (arch-go)" $find if + execute + then + + \ go s" (go)" $find if execute - else - ." go is not yet implemented" - 2drop - then + then ;
diff --git a/include/libopenbios/initprogram.h b/include/libopenbios/initprogram.h index c42d956..33f2723 100644 --- a/include/libopenbios/initprogram.h +++ b/include/libopenbios/initprogram.h @@ -26,4 +26,6 @@ extern void init_program(void); void init_fcode_context(void); void init_forth_context(void);
+void go(void); + #endif /* _H_INITPROGRAM */ diff --git a/libopenbios/init.c b/libopenbios/init.c index 10fb55c..9b81821 100644 --- a/libopenbios/init.c +++ b/libopenbios/init.c @@ -24,4 +24,7 @@ openbios_init( void ) { // Bind the C implementation of (init-program) into Forth bind_func("(init-program)", init_program); + + // Bind the C implementation of (go) into Forth + bind_func("(go)", go); } diff --git a/libopenbios/initprogram.c b/libopenbios/initprogram.c index 9cf3780..93222b7 100644 --- a/libopenbios/initprogram.c +++ b/libopenbios/initprogram.c @@ -102,3 +102,36 @@ void init_forth_context(void) feval("load-state >ls.file-size @"); fword("eval2"); } + +void go(void) +{ + ucell address, type; + int image_retval = 0; + + /* Get the entry point and the type (see forth/debugging/client.fs) */ + feval("load-state >ls.entry @"); + address = POP(); + feval("load-state >ls.file-type @"); + type = POP(); + + printk("\nJumping to entry point " FMT_ucellx " for type " FMT_ucellx "...\n", address, type); + + switch (type) { + default: + /* Start native binary */ + image_retval = start_elf((unsigned long)address); + break; + + case 0x10: + /* Start Fcode image */ + image_retval = start_elf((unsigned long)&init_fcode_context); + break; + + case 0x11: + /* Start Forth image */ + image_retval = start_elf((unsigned long)&init_forth_context); + break; + } + + printk("Image returned with return value %#x\n", image_retval); +}
load should place the file at load-base, whilst init-program should parse the memory at load-base and set up the context accordingly.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- libopenbios/aout_load.c | 44 +++++++++++++++++++++++--------------------- libopenbios/load.c | 15 ++++++++------- 2 files changed, 31 insertions(+), 28 deletions(-)
diff --git a/libopenbios/aout_load.c b/libopenbios/aout_load.c index 2433106..548a9f8 100644 --- a/libopenbios/aout_load.c +++ b/libopenbios/aout_load.c @@ -10,15 +10,10 @@ #define CONFIG_SPARC64_PAGE_SIZE_8KB #endif
-/* NextStep bootloader on SPARC32 expects the a.out header directly - below load-base (0x4000) */ -#ifdef CONFIG_SPARC32 -#define AOUT_HEADER_COPY -#endif - #include "libopenbios/sys_info.h" #include "libopenbios/bindings.h" #include "libopenbios/aout_load.h" +#include "libopenbios/initprogram.h" #include "libc/diskio.h" #define printf printk #define debug printk @@ -85,7 +80,7 @@ aout_load(struct sys_info *info, ihandle_t dev)
/* Mark the saved-program-state as invalid */ feval("0 state-valid !"); - + fd = open_ih(dev); if (fd == -1) { goto out; @@ -123,15 +118,16 @@ aout_load(struct sys_info *info, ihandle_t dev) fword("load-base"); start = POP(); // N_TXTADDR(ehdr);
+ memcpy((void *)start, &ehdr, sizeof(ehdr)); + if (!check_mem_ranges(info, start, size)) goto out;
printf("Loading a.out %s...\n", image_name ? image_name : "image"); - seek_io(fd, offset + N_TXTOFF(ehdr));
if (N_MAGIC(ehdr) == NMAGIC) { - if ((size_t)read_io(fd, (void *)start, ehdr.a_text) != ehdr.a_text) { + if ((size_t)read_io(fd, (void *)(start + N_TXTOFF(ehdr)), ehdr.a_text) != ehdr.a_text) { printf("Can't read program text segment (size 0x" FMT_aout_ehdr ")\n", ehdr.a_text); goto out; } @@ -140,7 +136,7 @@ aout_load(struct sys_info *info, ihandle_t dev) goto out; } } else { - if ((size_t)read_io(fd, (void *)start, size) != size) { + if ((size_t)read_io(fd, (void *)(start + N_TXTOFF(ehdr)), size) != size) { printf("Can't read program (size 0x" FMT_sizet ")\n", size); goto out; } @@ -149,20 +145,11 @@ aout_load(struct sys_info *info, ihandle_t dev) debug("Loaded %lu bytes\n", size); debug("entry point is %#lx\n", start);
-#ifdef AOUT_HEADER_COPY - // Copy the a.out header just before start - memcpy((char *)(start - 0x20), &ehdr, 0x20); -#endif - // Initialise saved-program-state - PUSH(addr_fixup(start)); - feval("load-state >ls.entry !"); PUSH(size); feval("load-state >ls.file-size !"); feval("aout load-state >ls.file-type !");
- feval("-1 state-valid !"); - out: close_io(fd); return retval; @@ -171,6 +158,21 @@ out: void aout_init_program(void) { - // Currently not implemented - feval("0 state-valid !"); + ucell start, size; + + // Relocate a.out text down from load-base to load-base - header. This + // is similar to what OBP does and is needed for NextStep. + fword("load-base"); + start = POP(); + feval("load-state >ls.file-size @"); + size = POP(); + + memmove((char *)start - sizeof(struct exec), (char *)start, size); + + PUSH(start); + feval("load-state >ls.entry !"); + + arch_init_program(); + + feval("-1 state-valid !"); } diff --git a/libopenbios/load.c b/libopenbios/load.c index 1c54d19..f43679d 100644 --- a/libopenbios/load.c +++ b/libopenbios/load.c @@ -17,6 +17,7 @@ #include "config.h" #include "kernel/kernel.h" #include "libopenbios/bindings.h" +#include "libopenbios/initprogram.h" #include "libopenbios/sys_info.h" #include "libopenbios/load.h"
@@ -50,12 +51,15 @@ void load(ihandle_t dev) { /* Invoke the loaders on the specified device */ char *param; - ucell valid; + ucell valid = 0;
/* TODO: Currently the internal loader APIs use load-base directly, so drop the address */ POP();
+ /* Temporarily keep compiler quiet during transition */ + valid = valid; + #ifdef CONFIG_LOADER_ELF
/* Grab the boot arguments */ @@ -77,12 +81,9 @@ void load(ihandle_t dev) #endif
#ifdef CONFIG_LOADER_AOUT - aout_load(&sys_info, dev); - feval("state-valid @"); - valid = POP(); - if (valid) { - feval("load-state >ls.file-size @"); - return; + if (aout_load(&sys_info, dev) != LOADER_NOT_SUPPORT) { + feval("load-state >ls.file-size @"); + return; } #endif
load should place the file at load-base, whilst init-program should parse the memory at load-base and set up the context accordingly.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- include/libopenbios/bootcode_load.h | 2 ++ libopenbios/bootcode_load.c | 25 +++++++++++++++++++++++-- libopenbios/initprogram.c | 8 ++++++++ libopenbios/load.c | 9 +++------ 4 files changed, 36 insertions(+), 8 deletions(-)
diff --git a/include/libopenbios/bootcode_load.h b/include/libopenbios/bootcode_load.h index 147783a..b20380d 100644 --- a/include/libopenbios/bootcode_load.h +++ b/include/libopenbios/bootcode_load.h @@ -18,5 +18,7 @@ #define _H_BOOTCODELOAD
extern int bootcode_load(ihandle_t dev); +int is_bootcode(char *addr); +void bootcode_init_program(void);
#endif /* _H__H_BOOTCODELOAD */ diff --git a/libopenbios/bootcode_load.c b/libopenbios/bootcode_load.c index c560240..2a307ae 100644 --- a/libopenbios/bootcode_load.c +++ b/libopenbios/bootcode_load.c @@ -7,6 +7,7 @@ #include "kernel/kernel.h" #include "libopenbios/bindings.h" #include "libopenbios/bootcode_load.h" +#include "libopenbios/initprogram.h" #include "libc/diskio.h" #include "drivers/drivers.h" #define printf printk @@ -90,10 +91,30 @@ bootcode_load(ihandle_t dev) feval("load-state >ls.file-size !"); feval("bootcode load-state >ls.file-type !");
- feval("-1 state-valid !"); - out: close_io(fd); return retval; }
+int +is_bootcode(char *addr) +{ + /* Bootcode has no magic, and is executed directly. So we'll + * say that something is bootcode if the loader detected the + * %BOOT type sucessfully */ + ucell filetype; + + feval("load-state >ls.file-type @"); + filetype = POP(); + + return (filetype == 0x12); +} + +void +bootcode_init_program(void) +{ + /* Entry point is already set, just need to setup the context */ + arch_init_program(); + + feval("-1 state-valid !"); +} diff --git a/libopenbios/initprogram.c b/libopenbios/initprogram.c index 93222b7..1008a90 100644 --- a/libopenbios/initprogram.c +++ b/libopenbios/initprogram.c @@ -24,6 +24,7 @@ #include "libopenbios/aout_load.h" #endif
+#include "libopenbios/bootcode_load.h" #include "libopenbios/bootinfo_load.h" #include "libopenbios/elf_load.h" #include "libopenbios/fcode_load.h" @@ -47,6 +48,13 @@ void init_program(void) } #endif
+#ifdef CONFIG_LOADER_BOOTCODE + if (is_bootcode((char *)cell2pointer(addr))) { + bootcode_init_program(); + return; + } +#endif + #ifdef CONFIG_LOADER_BOOTINFO if (is_bootinfo((char *)cell2pointer(addr))) { bootinfo_init_program(); diff --git a/libopenbios/load.c b/libopenbios/load.c index f43679d..a78e3b3 100644 --- a/libopenbios/load.c +++ b/libopenbios/load.c @@ -109,12 +109,9 @@ void load(ihandle_t dev)
#ifdef CONFIG_LOADER_BOOTCODE /* Check for a "raw" %BOOT bootcode payload */ - bootcode_load(dev); - feval("state-valid @"); - valid = POP(); - if (valid) { - feval("load-state >ls.file-size @"); - return; + if (bootcode_load(dev) != LOADER_NOT_SUPPORT) { + feval("load-state >ls.file-size @"); + return; } #endif
load should place the file at load-base, whilst init-program should parse the memory at load-base and set up the context accordingly.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- arch/unix/boot.c | 7 ++++++- libopenbios/elf_load.c | 16 ++++++---------- libopenbios/load.c | 9 +++------ 3 files changed, 15 insertions(+), 17 deletions(-)
diff --git a/arch/unix/boot.c b/arch/unix/boot.c index d65681f..63a623d 100644 --- a/arch/unix/boot.c +++ b/arch/unix/boot.c @@ -5,12 +5,12 @@ #include "config.h" #include "libopenbios/bindings.h" #include "libopenbios/elf_load.h" +#include "libopenbios/initprogram.h" #include "arch/common/nvram.h" #include "libc/diskio.h"
void boot(void); void *load_elf(char *spec); -unsigned int start_elf(unsigned long address);
void *load_elf(char *spec) @@ -90,3 +90,8 @@ start_elf(unsigned long address) return 0; }
+int +arch_init_program(void) +{ + return 0; +} diff --git a/libopenbios/elf_load.c b/libopenbios/elf_load.c index aa81e4c..f09ccf6 100644 --- a/libopenbios/elf_load.c +++ b/libopenbios/elf_load.c @@ -11,6 +11,7 @@ #include "libopenbios/sys_info.h" #include "libopenbios/ipchecksum.h" #include "libopenbios/bindings.h" +#include "libopenbios/initprogram.h" #include "libopenbios/ofmem.h" #define printf printk #define debug printk @@ -453,13 +454,10 @@ elf_load(struct sys_info *info, ihandle_t dev, const char *cmdline, void **boot_ debug("entry point is " FMT_elf "\n", addr_fixup(ehdr.e_entry));
// Initialise saved-program-state - PUSH(addr_fixup(ehdr.e_entry)); - feval("load-state >ls.entry !"); PUSH(file_size); feval("load-state >ls.file-size !"); - - feval("-1 state-valid !"); - + feval("elf load-state >ls.file-type !"); + out: close_io(fd); if (phdr) @@ -483,7 +481,6 @@ elf_init_program(void) uintptr_t tmp;
/* TODO: manage ELF notes section */ - feval("0 state-valid !"); feval("load-base"); base = (char*)cell2pointer(POP());
@@ -531,9 +528,8 @@ elf_init_program(void) // Initialise load-state PUSH(ehdr->e_entry); feval("load-state >ls.entry !"); - PUSH(total_size); - feval("load-state >ls.file-size !"); - feval("elf load-state >ls.file-type !"); - + + arch_init_program(); + feval("-1 state-valid !"); } diff --git a/libopenbios/load.c b/libopenbios/load.c index a78e3b3..edc95cb 100644 --- a/libopenbios/load.c +++ b/libopenbios/load.c @@ -71,12 +71,9 @@ void load(ihandle_t dev) POP(); param = pop_fstr_copy();
- elf_load(&sys_info, dev, param, &elf_boot_notes); - feval("state-valid @"); - valid = POP(); - if (valid) { - feval("load-state >ls.file-size @"); - return; + if (elf_load(&sys_info, dev, param, &elf_boot_notes) != LOADER_NOT_SUPPORT) { + feval("load-state >ls.file-size @"); + return; } #endif
load should place the file at load-base, whilst init-program should parse the memory at load-base and set up the context accordingly.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- libopenbios/fcode_load.c | 26 ++++++++------------------ libopenbios/load.c | 9 +++------ 2 files changed, 11 insertions(+), 24 deletions(-)
diff --git a/libopenbios/fcode_load.c b/libopenbios/fcode_load.c index 5258357..3d2da2f 100644 --- a/libopenbios/fcode_load.c +++ b/libopenbios/fcode_load.c @@ -6,6 +6,7 @@ #include "kernel/kernel.h" #include "libopenbios/bindings.h" #include "libopenbios/fcode_load.h" +#include "libopenbios/initprogram.h" #include "libopenbios/sys_info.h" #include "libc/diskio.h" #define printf printk @@ -76,14 +77,10 @@ fcode_load(ihandle_t dev) debug("entry point is %#lx\n", start);
// Initialise load-state - PUSH(start); - feval("load-state >ls.entry !"); PUSH(size); feval("load-state >ls.file-size !"); feval("fcode load-state >ls.file-type !");
- feval("-1 state-valid !"); - out: close_io(fd); return retval; @@ -92,18 +89,11 @@ out: void fcode_init_program(void) { - /* If the payload is Fcode then we execute it immediately */ - ucell address; - - fword("load-base"); - address = POP(); - - if (!is_fcode((unsigned char *)address)) { - debug("Not a valid Fcode memory image\n"); - return; - } - - PUSH(address); - PUSH(1); - fword("byte-load"); + /* Use trampoline context to execute FCode */ + PUSH((ucell)&init_fcode_context); + feval("load-state >ls.entry !"); + + arch_init_program(); + + feval("-1 state-valid !"); } diff --git a/libopenbios/load.c b/libopenbios/load.c index edc95cb..1d64cc7 100644 --- a/libopenbios/load.c +++ b/libopenbios/load.c @@ -85,12 +85,9 @@ void load(ihandle_t dev) #endif
#ifdef CONFIG_LOADER_FCODE - fcode_load(dev); - feval("state-valid @"); - valid = POP(); - if (valid) { - feval("load-state >ls.file-size @"); - return; + if (fcode_load(dev) != LOADER_NOT_SUPPORT) { + feval("load-state >ls.file-size @"); + return; } #endif
load should place the file at load-base, whilst init-program should parse the memory at load-base and set up the context accordingly.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- libopenbios/forth_load.c | 26 +++++++++++++------------- libopenbios/load.c | 13 +++---------- 2 files changed, 16 insertions(+), 23 deletions(-)
diff --git a/libopenbios/forth_load.c b/libopenbios/forth_load.c index 35835fb..4433635 100644 --- a/libopenbios/forth_load.c +++ b/libopenbios/forth_load.c @@ -9,6 +9,7 @@ #include "config.h" #include "kernel/kernel.h" #include "libopenbios/bindings.h" +#include "libopenbios/initprogram.h" #include "libopenbios/sys_info.h" #include "libc/diskio.h" #include "libopenbios/forth_load.h" @@ -16,7 +17,6 @@ #define debug printk
static int fd; -static char *forthtext=NULL;
int is_forth(char *forth) { @@ -27,6 +27,7 @@ int forth_load(ihandle_t dev) { char magic[2]; unsigned long forthsize; + ucell *forthtext; int retval = -1;
/* Mark the saved-program-state as invalid */ @@ -52,37 +53,36 @@ int forth_load(ihandle_t dev) /* Calculate the file size by seeking to the end of the file */ seek_io(fd, -1); forthsize = tell(fd); - forthtext = malloc(forthsize+1); seek_io(fd, 0);
+ fword("load-base"); + forthtext = (void *)POP(); + printk("Loading forth source ..."); if ((size_t)read_io(fd, forthtext, forthsize) != forthsize) { printk("Can't read forth text\n"); goto out; } - forthtext[forthsize]=0; + forthtext[(forthsize / sizeof(ucell)) + 1]=0; printk("ok\n");
// Initialise saved-program-state - PUSH((ucell)forthtext); - feval("load-state >ls.entry !"); PUSH((ucell)forthsize); feval("load-state >ls.file-size !"); feval("forth load-state >ls.file-type !");
- feval("-1 state-valid !"); - - retval=0; - out: - //if (forthtext) - // free(forthtext); return retval; }
void forth_init_program(void) { - // Currently not implemented - feval("0 state-valid !"); + /* Use trampoline context to execute Forth */ + PUSH((ucell)&init_forth_context); + feval("load-state >ls.entry !"); + + arch_init_program(); + + feval("-1 state-valid !"); } diff --git a/libopenbios/load.c b/libopenbios/load.c index 1d64cc7..048f459 100644 --- a/libopenbios/load.c +++ b/libopenbios/load.c @@ -51,15 +51,11 @@ void load(ihandle_t dev) { /* Invoke the loaders on the specified device */ char *param; - ucell valid = 0;
/* TODO: Currently the internal loader APIs use load-base directly, so drop the address */ POP();
- /* Temporarily keep compiler quiet during transition */ - valid = valid; - #ifdef CONFIG_LOADER_ELF
/* Grab the boot arguments */ @@ -92,12 +88,9 @@ void load(ihandle_t dev) #endif
#ifdef CONFIG_LOADER_FORTH - forth_load(dev); - feval("state-valid @"); - valid = POP(); - if (valid) { - feval("load-state >ls.file-size @"); - return; + if (forth_load(dev) != LOADER_NOT_SUPPORT) { + feval("load-state >ls.file-size @"); + return; } #endif
load should place the file at load-base, whilst init-program should parse the memory at load-base and set up the context accordingly.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- include/libopenbios/xcoff_load.h | 2 +- libopenbios/load.c | 11 ++++ libopenbios/xcoff_load.c | 105 +++++++++++++++++++++++++++++++++++--- 3 files changed, 110 insertions(+), 8 deletions(-)
diff --git a/include/libopenbios/xcoff_load.h b/include/libopenbios/xcoff_load.h index 2ec693d..854d3ba 100644 --- a/include/libopenbios/xcoff_load.h +++ b/include/libopenbios/xcoff_load.h @@ -21,7 +21,7 @@ #include "libopenbios/sys_info.h"
extern int is_xcoff(COFF_filehdr_t *fhdr); -extern int xcoff_load(struct sys_info *info, const char *filename); +extern int xcoff_load(ihandle_t dev); extern void xcoff_init_program(void);
#endif /* _H_XCOFFLOAD */ diff --git a/libopenbios/load.c b/libopenbios/load.c index 048f459..174d221 100644 --- a/libopenbios/load.c +++ b/libopenbios/load.c @@ -37,6 +37,10 @@ #include "libopenbios/forth_load.h" #endif
+#ifdef CONFIG_LOADER_XCOFF +#include "libopenbios/xcoff_load.h" +#endif + #ifdef CONFIG_LOADER_BOOTCODE #include "libopenbios/bootcode_load.h" #endif @@ -94,6 +98,13 @@ void load(ihandle_t dev) } #endif
+#ifdef CONFIG_LOADER_XCOFF + if (xcoff_load(dev) != LOADER_NOT_SUPPORT) { + feval("load-state >ls.file-size @"); + return; + } +#endif + #ifdef CONFIG_LOADER_BOOTCODE /* Check for a "raw" %BOOT bootcode payload */ if (bootcode_load(dev) != LOADER_NOT_SUPPORT) { diff --git a/libopenbios/xcoff_load.c b/libopenbios/xcoff_load.c index bd14343..11c67d9 100644 --- a/libopenbios/xcoff_load.c +++ b/libopenbios/xcoff_load.c @@ -16,7 +16,9 @@
#include "config.h" #include "libopenbios/bindings.h" +#include "libopenbios/initprogram.h" #include "libopenbios/xcoff_load.h" +#include "libc/diskio.h"
#include "arch/common/xcoff.h"
@@ -44,10 +46,101 @@ is_xcoff(COFF_filehdr_t *fhdr) }
int -xcoff_load(struct sys_info *info, const char *filename) +xcoff_load(ihandle_t dev) { - // Currently not implemented - return LOADER_NOT_SUPPORT; + COFF_filehdr_t fhdr; + COFF_aouthdr_t ahdr; + COFF_scnhdr_t shdr; + uint32_t offset; + size_t total_size = 0; + int fd, i; + int retval = -1; + + /* Mark the saved-program-state as invalid */ + feval("0 state-valid !"); + + fd = open_ih(dev); + if (fd == -1) { + goto out; + } + + for (offset = 0; offset < 16 * 512; offset += 512) { + seek_io(fd, offset); + if (read_io(fd, &fhdr, sizeof fhdr) != sizeof fhdr) { + DPRINTF("Can't read XCOFF header\n"); + retval = LOADER_NOT_SUPPORT; + goto out; + } + + if (is_xcoff(&fhdr)) + break; + } + + /* Is it executable ? */ + if (fhdr.f_magic != 0x01DF && + (fhdr.f_flags & COFF_F_EXEC) == 0) { + DPRINTF("Not an executable XCOFF file %02x\n", fhdr.f_flags); + return retval; + } + + /* Optional header is a.out ? */ + if (fhdr.f_opthdr != sizeof(COFF_aouthdr_t)) { + DPRINTF("AOUT optional error size mismatch in XCOFF file\n"); + return retval; + } + + seek_io(fd, sizeof(COFF_filehdr_t)); + read_io(fd, &ahdr, sizeof(COFF_aouthdr_t)); + + /* check a.out magic number */ + if (ahdr.magic != AOUT_MAGIC) { + DPRINTF("Invalid AOUT optional header\n"); + return retval; + } + + offset = sizeof(COFF_filehdr_t) + sizeof(COFF_aouthdr_t); + + DPRINTF("XCOFF file with %d sections\n", fhdr.f_nscns); + + for (i = 0; i < fhdr.f_nscns; i++) { + DPRINTF("Read header at offset %0x\n", offset); + seek_io(fd, offset); + read_io(fd, &shdr, sizeof(COFF_scnhdr_t)); + + DPRINTF("Initializing '%s' section from %0x %0x to %0x (%0x)\n", + shdr.s_name, offset, shdr.s_scnptr, + shdr.s_vaddr, shdr.s_size); + + if (strcmp(shdr.s_name, ".text") == 0) { + read_io(fd, (void *)shdr.s_vaddr, shdr.s_size); + total_size += shdr.s_size; +#ifdef CONFIG_PPC + flush_icache_range((char*)(uintptr_t)shdr.s_vaddr, + (char*)(uintptr_t)(shdr.s_vaddr + shdr.s_size)); +#endif + } else if (strcmp(shdr.s_name, ".data") == 0) { + read_io(fd, (void *)shdr.s_vaddr, shdr.s_size); + total_size += shdr.s_size; + + } else if (strcmp(shdr.s_name, ".bss") == 0) { + memset((void *)(uintptr_t)shdr.s_vaddr, 0, shdr.s_size); + total_size += shdr.s_size; + } else { + DPRINTF(" Skip '%s' section\n", shdr.s_name); + } + offset += sizeof(COFF_scnhdr_t); + } + + DPRINTF("XCOFF entry point: %x\n", *(uint32_t*)ahdr.entry); + + // Initialise load-state + PUSH(total_size); + feval("load-state >ls.file-size !"); + feval("xcoff load-state >ls.file-type !"); + +out: + close_io(fd); + return retval; }
void @@ -61,8 +154,6 @@ xcoff_init_program(void) size_t total_size = 0; int i;
- feval("0 state-valid !"); - feval("load-base"); base = (char*)cell2pointer(POP());
@@ -139,9 +230,9 @@ xcoff_init_program(void) // Initialise load-state PUSH(*(uint32_t*)(uintptr_t)ahdr->entry); feval("load-state >ls.entry !"); - PUSH(total_size); - feval("load-state >ls.file-size !"); feval("xcoff load-state >ls.file-type !");
+ arch_init_program(); + feval("-1 state-valid !"); }
Now that each loader sets up its own context, there is no longer any need for conditional logic in go().
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- libopenbios/initprogram.c | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-)
diff --git a/libopenbios/initprogram.c b/libopenbios/initprogram.c index 1008a90..e87f930 100644 --- a/libopenbios/initprogram.c +++ b/libopenbios/initprogram.c @@ -124,22 +124,7 @@ void go(void)
printk("\nJumping to entry point " FMT_ucellx " for type " FMT_ucellx "...\n", address, type);
- switch (type) { - default: - /* Start native binary */ - image_retval = start_elf((unsigned long)address); - break; - - case 0x10: - /* Start Fcode image */ - image_retval = start_elf((unsigned long)&init_fcode_context); - break; - - case 0x11: - /* Start Forth image */ - image_retval = start_elf((unsigned long)&init_forth_context); - break; - } + image_retval = start_elf((unsigned long)address);
printk("Image returned with return value %#x\n", image_retval); }
Now that each loader sets up its own context, there is no need to pass in the address or set up the context ourselves.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- arch/amd64/context.c | 4 +--- arch/ppc/qemu/context.c | 4 +--- arch/sparc32/boot.c | 2 +- arch/sparc32/context.c | 4 +--- arch/sparc64/context.c | 4 +--- arch/unix/boot.c | 2 +- arch/x86/context.c | 4 +--- include/libopenbios/initprogram.h | 2 +- libopenbios/initprogram.c | 2 +- 9 files changed, 9 insertions(+), 19 deletions(-)
diff --git a/arch/amd64/context.c b/arch/amd64/context.c index 8837cbb..a47b2cf 100644 --- a/arch/amd64/context.c +++ b/arch/amd64/context.c @@ -147,12 +147,10 @@ struct context *switch_to(struct context *ctx) }
/* Start ELF image */ -unsigned int start_elf(unsigned long entry_point) +unsigned int start_elf(void) { struct context *ctx = client_ctx;
- arch_init_program(); - ctx = switch_to(ctx); return ctx->eax; } diff --git a/arch/ppc/qemu/context.c b/arch/ppc/qemu/context.c index cbf2380..717f942 100644 --- a/arch/ppc/qemu/context.c +++ b/arch/ppc/qemu/context.c @@ -156,12 +156,10 @@ struct context *switch_to(struct context *ctx) }
/* Start ELF Boot image */ -unsigned int start_elf(unsigned long entry_point) +unsigned int start_elf(void) { struct context *ctx = client_ctx;
- arch_init_program(); - ctx = switch_to(ctx); return ctx->regs[REG_R3]; } diff --git a/arch/sparc32/boot.c b/arch/sparc32/boot.c index 35fd473..d458658 100644 --- a/arch/sparc32/boot.c +++ b/arch/sparc32/boot.c @@ -201,6 +201,6 @@ void boot(void) feval("load-state >ls.entry !");
arch_init_program(); - start_elf(kernel_image); + start_elf(); } } diff --git a/arch/sparc32/context.c b/arch/sparc32/context.c index 44abc74..8ff8e92 100644 --- a/arch/sparc32/context.c +++ b/arch/sparc32/context.c @@ -129,12 +129,10 @@ struct context *switch_to(struct context *ctx) }
/* Start ELF Boot image */ -unsigned int start_elf(unsigned long entry_point) +unsigned int start_elf(void) { struct context *ctx = client_ctx;
- arch_init_program(); - ctx = switch_to(ctx); return ctx->regs[REG_O0]; } diff --git a/arch/sparc64/context.c b/arch/sparc64/context.c index ed4d878..18ed336 100644 --- a/arch/sparc64/context.c +++ b/arch/sparc64/context.c @@ -138,12 +138,10 @@ struct context *switch_to(struct context *ctx) }
/* Start ELF Boot image */ -unsigned int start_elf(unsigned long entry_point) +unsigned int start_elf(void) { struct context *ctx = client_ctx;
- arch_init_program(); - ctx = switch_to(ctx);
return 0; diff --git a/arch/unix/boot.c b/arch/unix/boot.c index 63a623d..ce84bb7 100644 --- a/arch/unix/boot.c +++ b/arch/unix/boot.c @@ -85,7 +85,7 @@ boot( void ) }
unsigned int -start_elf(unsigned long address) +start_elf(void) { return 0; } diff --git a/arch/x86/context.c b/arch/x86/context.c index 6bb2f69..3f6e95c 100644 --- a/arch/x86/context.c +++ b/arch/x86/context.c @@ -153,12 +153,10 @@ struct context *switch_to(struct context *ctx) }
/* Start ELF Boot image */ -unsigned int start_elf(unsigned long entry_point) +unsigned int start_elf(void) { struct context *ctx = client_ctx;
- arch_init_program(); - ctx = switch_to(ctx); return ctx->eax; } diff --git a/include/libopenbios/initprogram.h b/include/libopenbios/initprogram.h index 33f2723..5464435 100644 --- a/include/libopenbios/initprogram.h +++ b/include/libopenbios/initprogram.h @@ -18,7 +18,7 @@ #define _H_INITPROGRAM
extern struct context * volatile __context; -extern unsigned int start_elf(unsigned long address); +extern unsigned int start_elf(void);
extern int arch_init_program(void); extern void init_program(void); diff --git a/libopenbios/initprogram.c b/libopenbios/initprogram.c index e87f930..49b5dc2 100644 --- a/libopenbios/initprogram.c +++ b/libopenbios/initprogram.c @@ -124,7 +124,7 @@ void go(void)
printk("\nJumping to entry point " FMT_ucellx " for type " FMT_ucellx "...\n", address, type);
- image_retval = start_elf((unsigned long)address); + image_retval = start_elf();
printk("Image returned with return value %#x\n", image_retval); }