This patch series is part of a much larger WIP series designed to remove various hacks from the load/init-program/go words. However in order for the follow-on series to work, all architectures must build an execution context similar to the IEEE1275 specification description of saved-program-state.
PPC is the only architecture which doesn't make use of contexts when entering/leaving the Forth environment, so start by adding this functionality in order that it can be expanded on further with later patches. While no functionality is changed by this patch, there should be no regressions when attempting to boot existing client images.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk
v2: - Use single asm invocation in switch_to() with clobber register - Fix unsigned int -> unsigned long - Fix missing volatile from __context pointer
Mark Cave-Ayland (4): ppc: move call_elf() to separate switch.S file ppc: add new context handler ppc: use separate context to call client images ppc: unify CIF save stack layout with that of new context stack
openbios-devel/arch/ppc/build.xml | 2 + openbios-devel/arch/ppc/qemu/context.c | 140 ++++++++++++++++++ openbios-devel/arch/ppc/qemu/context.h | 34 +++++ openbios-devel/arch/ppc/qemu/init.c | 4 +- openbios-devel/arch/ppc/qemu/ldscript | 6 +- openbios-devel/arch/ppc/qemu/start.S | 244 +++++++++++++------------------- openbios-devel/arch/ppc/qemu/switch.S | 211 +++++++++++++++++++++++++++ openbios-devel/include/arch/ppc/io.h | 2 +- 8 files changed, 494 insertions(+), 149 deletions(-) create mode 100644 openbios-devel/arch/ppc/qemu/context.c create mode 100644 openbios-devel/arch/ppc/qemu/context.h create mode 100644 openbios-devel/arch/ppc/qemu/switch.S
Separate out the context switch code into a separate file, similar as to how is already done with the other architectures.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- openbios-devel/arch/ppc/build.xml | 1 + openbios-devel/arch/ppc/qemu/start.S | 47 ++--------------------------- openbios-devel/arch/ppc/qemu/switch.S | 52 +++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 44 deletions(-) create mode 100644 openbios-devel/arch/ppc/qemu/switch.S
diff --git a/openbios-devel/arch/ppc/build.xml b/openbios-devel/arch/ppc/build.xml index 29f6601..b40c81c 100644 --- a/openbios-devel/arch/ppc/build.xml +++ b/openbios-devel/arch/ppc/build.xml @@ -182,6 +182,7 @@ $(call quiet-command,$(NM) $@.nostrip | sort > $(ODIR)/openbios-qemu.syms," GEN $(TARGET_DIR)$@.syms") $(call quiet-command,$(STRIP) $@.nostrip -o $@," STRIP $(TARGET_DIR)$@")</rule> <object source="qemu/start.S"/> + <object source="qemu/switch.S"/> <object source="timebase.S"/> <external-object source="libqemu.a"/> <external-object source="libbootstrap.a"/> diff --git a/openbios-devel/arch/ppc/qemu/start.S b/openbios-devel/arch/ppc/qemu/start.S index ae2fd53..483c498 100644 --- a/openbios-devel/arch/ppc/qemu/start.S +++ b/openbios-devel/arch/ppc/qemu/start.S @@ -486,52 +486,11 @@ real_entry: 1: nop b 1b
- - /* 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 - */ .data -saved_stack: - DATA_LONG(0) +_GLOBAL(saved_stack): + DATA_LONG(0) + .previous - /* void call_elf( arg1, arg2, entry ) */ -_GLOBAL(call_elf): - mflr r0 - PPC_STLU r1, -STACKFRAME_MINSIZE(r1) - PPC_STL r0, (STACKFRAME_MINSIZE + PPC_LR_STKOFF)(r1) - mtlr r5 - LOAD_REG_IMMEDIATE(r8, saved_stack) // save our stack pointer - PPC_STL r1,0(r8) - mfsdr1 r1 - addi r1, r1, -32768 /* - 32 KiB exception stack */ - addis r1, r1, -1 /* - 64 KiB stack */ - LOAD_REG_IMMEDIATE(r5, of_client_callback) // r5 = callback - li r6,0 // r6 = address of client program arguments (unused) - li r7,0 // r7 = length of client program arguments (unused) - li r0,MSR_FP | MSR_ME | MSR_DR | MSR_IR - MTMSRD(r0) - blrl - -#ifdef CONFIG_PPC64 - /* Restore SF bit */ - LOAD_REG_IMMEDIATE(r0, MSR_SF | MSR_FP | MSR_ME | MSR_DR | MSR_IR) - MTMSRD(r0) -#endif - LOAD_REG_IMMEDIATE(r8, saved_stack) // restore stack pointer - mr r1,r8 - PPC_LL r0, (STACKFRAME_MINSIZE + PPC_LR_STKOFF)(r1) - mtlr r0 - addi r1, r1, STACKFRAME_MINSIZE - // XXX: should restore r12-r31 etc.. - // we should not really come here though - blr
#ifdef __powerpc64__ #define STKOFF STACKFRAME_MINSIZE diff --git a/openbios-devel/arch/ppc/qemu/switch.S b/openbios-devel/arch/ppc/qemu/switch.S new file mode 100644 index 0000000..eabd6d0 --- /dev/null +++ b/openbios-devel/arch/ppc/qemu/switch.S @@ -0,0 +1,52 @@ +#include "autoconf.h" +#include "asm/asmdefs.h" +#include "asm/processor.h" + +#ifdef CONFIG_PPC_64BITSUPPORT + #define STACKFRAME_MINSIZE 48 +#else /* !CONFIG_PPC_64BITSUPPORT */ + #define STACKFRAME_MINSIZE 16 +#endif + + /* 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 + */ + + /* void call_elf( arg1, arg2, entry ) */ +_GLOBAL(call_elf): + mflr r0 + PPC_STLU r1, -STACKFRAME_MINSIZE(r1) + PPC_STL r0, (STACKFRAME_MINSIZE + PPC_LR_STKOFF)(r1) + mtlr r5 + LOAD_REG_IMMEDIATE(r8, saved_stack) // save our stack pointer + PPC_STL r1,0(r8) + mfsdr1 r1 + addi r1, r1, -32768 /* - 32 KiB exception stack */ + addis r1, r1, -1 /* - 64 KiB stack */ + LOAD_REG_IMMEDIATE(r5, of_client_callback) // r5 = callback + li r6,0 // r6 = address of client program arguments (unused) + li r7,0 // r7 = length of client program arguments (unused) + li r0,MSR_FP | MSR_ME | MSR_DR | MSR_IR + MTMSRD(r0) + blrl + +#ifdef CONFIG_PPC64 + /* Restore SF bit */ + LOAD_REG_IMMEDIATE(r0, MSR_SF | MSR_FP | MSR_ME | MSR_DR | MSR_IR) + MTMSRD(r0) +#endif + LOAD_REG_IMMEDIATE(r8, saved_stack) // restore stack pointer + mr r1,r8 + PPC_LL r0, (STACKFRAME_MINSIZE + PPC_LR_STKOFF)(r1) + mtlr r0 + addi r1, r1, STACKFRAME_MINSIZE + // XXX: should restore r12-r31 etc.. + // we should not really come here though + blrl
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- openbios-devel/arch/ppc/build.xml | 1 + openbios-devel/arch/ppc/qemu/context.c | 125 ++++++++++++++++++++++++ openbios-devel/arch/ppc/qemu/context.h | 34 +++++++ openbios-devel/arch/ppc/qemu/ldscript | 6 +- openbios-devel/arch/ppc/qemu/start.S | 2 +- openbios-devel/arch/ppc/qemu/switch.S | 165 +++++++++++++++++++++++++++++++- openbios-devel/include/arch/ppc/io.h | 2 +- 7 files changed, 329 insertions(+), 6 deletions(-) create mode 100644 openbios-devel/arch/ppc/qemu/context.c create mode 100644 openbios-devel/arch/ppc/qemu/context.h
diff --git a/openbios-devel/arch/ppc/build.xml b/openbios-devel/arch/ppc/build.xml index b40c81c..e606313 100644 --- a/openbios-devel/arch/ppc/build.xml +++ b/openbios-devel/arch/ppc/build.xml @@ -183,6 +183,7 @@ $(call quiet-command,$(STRIP) $@.nostrip -o $@," STRIP $(TARGET_DIR)$@")</rule> <object source="qemu/start.S"/> <object source="qemu/switch.S"/> + <object source="qemu/context.c"/> <object source="timebase.S"/> <external-object source="libqemu.a"/> <external-object source="libbootstrap.a"/> diff --git a/openbios-devel/arch/ppc/qemu/context.c b/openbios-devel/arch/ppc/qemu/context.c new file mode 100644 index 0000000..93b6175 --- /dev/null +++ b/openbios-devel/arch/ppc/qemu/context.c @@ -0,0 +1,125 @@ +/* + * context switching + * 2003-10 by SONE Takeshi + */ + +#include "config.h" +#include "kernel/kernel.h" +#include "context.h" +#include "libopenbios/sys_info.h" + +#define MAIN_STACK_SIZE 16384 +#define IMAGE_STACK_SIZE 4096*2 + +#define debug printk + +#ifdef CONFIG_PPC_64BITSUPPORT + #ifdef __powerpc64__ + #define ULONG_SIZE 8 + #define STACKFRAME_MINSIZE 48 + #define STKOFF STACKFRAME_MINSIZE + #define SAVE_SPACE 320 + #else + #define ULONG_SIZE 4 + #define STACKFRAME_MINSIZE 16 + #define STKOFF 8 + #define SAVE_SPACE 144 + #endif +#endif + +static void start_main(void); /* forward decl. */ +void __exit_context(void); /* assembly routine */ + +unsigned int start_elf(unsigned long entry_point, unsigned long param); +void entry(void); + +/* + * Main context structure + * It is placed at the bottom of our stack, and loaded by assembly routine + * to start us up. + */ +static struct context main_ctx = { + .sp = (unsigned long) &_estack - SAVE_SPACE, + .pc = (unsigned long) start_main, + .return_addr = (unsigned long) __exit_context, +}; + +/* This is used by assembly routine to load/store the context which + * it is to switch/switched. */ +struct context * volatile __context = &main_ctx; + +/* Stack for loaded ELF image */ +static uint8_t image_stack[IMAGE_STACK_SIZE]; + +/* Pointer to startup context (physical address) */ +unsigned long __boot_ctx; + +/* + * Main starter + * This is the C function that runs first. + */ +static void start_main(void) +{ + /* Save startup context, so we can refer to it later. + * We have to keep it in physical address since we will relocate. */ + __boot_ctx = virt_to_phys(__context); + + /* Start the real fun */ + entry(); + + /* Returning from here should jump to __exit_context */ + __context = boot_ctx; +} + +/* Setup a new context using the given stack. + */ +struct context * +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(unsigned long))); + memset(ctx, 0, sizeof(*ctx)); + + /* Fill in reasonable default for flat memory model */ + ctx->sp = virt_to_phys(SP_LOC(ctx)); + ctx->return_addr = virt_to_phys(__exit_context); + + return ctx; +} + +/* Switch to another context. */ +struct context *switch_to(struct context *ctx) +{ + volatile struct context *save; + struct context *ret; + unsigned int lr; + + debug("switching to new context:\n"); + save = __context; + __context = ctx; + + asm __volatile__ ("mflr %%r9\n\t" + "stw %%r9, %0\n\t" + "bl __switch_context\n\t" + "lwz %%r9, %0\n\t" + "mtlr %%r9\n\t" : "=m" (lr) : "m" (lr) : "%r9" ); + + ret = __context; + __context = (struct context *)save; + return ret; +} + +/* Start ELF Boot image */ +unsigned int start_elf(unsigned long entry_point, unsigned long param) +{ + struct context *ctx; + + ctx = init_context(image_stack, sizeof image_stack, 1); + ctx->pc = entry_point; + ctx->param[0] = param; + + ctx = switch_to(ctx); + return ctx->regs[REG_R3]; +} diff --git a/openbios-devel/arch/ppc/qemu/context.h b/openbios-devel/arch/ppc/qemu/context.h new file mode 100644 index 0000000..8135bb4 --- /dev/null +++ b/openbios-devel/arch/ppc/qemu/context.h @@ -0,0 +1,34 @@ +#ifndef PPC_CONTEXT_H +#define PPC_CONTEXT_H + +struct context { +#define SP_LOC(ctx) (&(ctx)->sp) + unsigned long _sp; + unsigned long return_addr; + unsigned long sp; + unsigned long pc; + /* General registers */ + unsigned long regs[34]; +#define REG_R3 3 +#define REG_R5 8 +#define REG_R6 9 +#define REG_R7 10 + /* Flags */ + /* Optional stack contents */ + unsigned long param[0]; +}; + +/* Create a new context in the given stack */ +struct context * +init_context(uint8_t *stack, uint32_t stack_size, int num_param); + +/* Switch context */ +struct context *switch_to(struct context *); + +/* Holds physical address of boot context */ +extern unsigned long __boot_ctx; + +/* This can always be safely used to refer to the boot context */ +#define boot_ctx ((struct context *) phys_to_virt(__boot_ctx)) + +#endif /* PPC_CONTEXT_H */ diff --git a/openbios-devel/arch/ppc/qemu/ldscript b/openbios-devel/arch/ppc/qemu/ldscript index 8027b39..11ebf4b 100644 --- a/openbios-devel/arch/ppc/qemu/ldscript +++ b/openbios-devel/arch/ppc/qemu/ldscript @@ -51,7 +51,11 @@ SECTIONS *(.bss) *(.bss.*) *(COMMON) - _ebss = .; + + _stack = .; + . += CSTACK_SIZE; + . = ALIGN(16); + _estack = .; }
. = HRESET_ADDR; diff --git a/openbios-devel/arch/ppc/qemu/start.S b/openbios-devel/arch/ppc/qemu/start.S index 483c498..a62d46e 100644 --- a/openbios-devel/arch/ppc/qemu/start.S +++ b/openbios-devel/arch/ppc/qemu/start.S @@ -482,7 +482,7 @@ real_entry: #endif
bl BRANCH_LABEL(setup_mmu) - bl BRANCH_LABEL(entry) + bl BRANCH_LABEL(__switch_context_nosave) 1: nop b 1b
diff --git a/openbios-devel/arch/ppc/qemu/switch.S b/openbios-devel/arch/ppc/qemu/switch.S index eabd6d0..c3d9d70 100644 --- a/openbios-devel/arch/ppc/qemu/switch.S +++ b/openbios-devel/arch/ppc/qemu/switch.S @@ -2,10 +2,19 @@ #include "asm/asmdefs.h" #include "asm/processor.h"
+ #ifdef CONFIG_PPC_64BITSUPPORT - #define STACKFRAME_MINSIZE 48 -#else /* !CONFIG_PPC_64BITSUPPORT */ - #define STACKFRAME_MINSIZE 16 + #ifdef __powerpc64__ + #define ULONG_SIZE 8 + #define STACKFRAME_MINSIZE 48 + #define STKOFF STACKFRAME_MINSIZE + #define SAVE_SPACE 320 + #else + #define ULONG_SIZE 4 + #define STACKFRAME_MINSIZE 16 + #define STKOFF 8 + #define SAVE_SPACE 144 + #endif #endif
/* According to IEEE 1275, PPC bindings: @@ -50,3 +59,153 @@ _GLOBAL(call_elf): // XXX: should restore r12-r31 etc.. // we should not really come here though blrl + +/* + * Switch execution context + * This saves registers in the stack, then + * switches the stack, and restores everything from the new stack. + * This function takes no argument. New stack pointer is + * taken from global variable __context, and old stack pointer + * is also saved to __context. This way we can just jump to + * this routine to get back to the original context. + */ + +_GLOBAL(__switch_context): + /* save internal stack pointer */ +#ifdef CONFIG_PPC64 + PPC_STL r1, -(SAVE_SPACE + 16) + STKOFF(r1) +#else + PPC_STL r1, -SAVE_SPACE + STKOFF(r1) +#endif + +#ifdef CONFIG_PPC64 + PPC_STLU r1, -(SAVE_SPACE + 16)(r1) +#else + PPC_STLU r1, -SAVE_SPACE(r1) /* fits within alignment */ +#endif + + /* r4, r5 */ + PPC_STL r4, (STKOFF + 9 * ULONG_SIZE)(r1) + PPC_STL r5, (STKOFF + 10 * ULONG_SIZE)(r1) + + /* link register */ + mflr r4 + PPC_STL r4, PPC_LR_STKOFF(r1) + PPC_STL r4, (STKOFF + ULONG_SIZE)(r1) + + PPC_STL r3, (STKOFF + 5 * ULONG_SIZE)(r1) + PPC_STL r2, (STKOFF + 4 * ULONG_SIZE)(r1) + PPC_STL r0, (STKOFF + 3 * ULONG_SIZE)(r1) + + /* ctr, cr and xer */ + mfctr r4 + PPC_STL r4, (STKOFF + 6 * ULONG_SIZE)(r1) + mfcr r4 + PPC_STL r4, (STKOFF + 7 * ULONG_SIZE)(r1) + mfxer r4 + PPC_STL r4, (STKOFF + 8 * ULONG_SIZE)(r1) + + /* r6-r31 */ + PPC_STL r6, (STKOFF + 11 * ULONG_SIZE)(r1) + PPC_STL r7, (STKOFF + 12 * ULONG_SIZE)(r1) + PPC_STL r8, (STKOFF + 13 * ULONG_SIZE)(r1) + PPC_STL r9, (STKOFF + 14 * ULONG_SIZE)(r1) + PPC_STL r10, (STKOFF + 15 * ULONG_SIZE)(r1) + PPC_STL r11, (STKOFF + 16 * ULONG_SIZE)(r1) + PPC_STL r12, (STKOFF + 17 * ULONG_SIZE)(r1) + PPC_STL r13, (STKOFF + 18 * ULONG_SIZE)(r1) + PPC_STL r14, (STKOFF + 19 * ULONG_SIZE)(r1) + PPC_STL r15, (STKOFF + 20 * ULONG_SIZE)(r1) + PPC_STL r16, (STKOFF + 21 * ULONG_SIZE)(r1) + PPC_STL r17, (STKOFF + 22 * ULONG_SIZE)(r1) + PPC_STL r18, (STKOFF + 23 * ULONG_SIZE)(r1) + PPC_STL r19, (STKOFF + 24 * ULONG_SIZE)(r1) + PPC_STL r20, (STKOFF + 25 * ULONG_SIZE)(r1) + PPC_STL r21, (STKOFF + 26 * ULONG_SIZE)(r1) + PPC_STL r22, (STKOFF + 27 * ULONG_SIZE)(r1) + PPC_STL r23, (STKOFF + 28 * ULONG_SIZE)(r1) + PPC_STL r24, (STKOFF + 29 * ULONG_SIZE)(r1) + PPC_STL r25, (STKOFF + 30 * ULONG_SIZE)(r1) + PPC_STL r26, (STKOFF + 31 * ULONG_SIZE)(r1) + PPC_STL r27, (STKOFF + 32 * ULONG_SIZE)(r1) + PPC_STL r28, (STKOFF + 33 * ULONG_SIZE)(r1) + PPC_STL r29, (STKOFF + 34 * ULONG_SIZE)(r1) + PPC_STL r30, (STKOFF + 35 * ULONG_SIZE)(r1) + PPC_STL r31, (STKOFF + 36 * ULONG_SIZE)(r1) + + /* swap context */ + LOAD_REG_IMMEDIATE(r4, __context) + PPC_LL r5, 0(r4) + PPC_STL r1, 0(r4) + mr r4, r5 + + b __set_context + +_GLOBAL(__switch_context_nosave): + LOAD_REG_IMMEDIATE(r4, __context) + PPC_LL r4, 0(r4) + +__set_context: + /* link register */ + PPC_LL r5, (STKOFF + ULONG_SIZE)(r4) + mtlr r5 + + PPC_LL r3, (STKOFF + 5 * ULONG_SIZE)(r4) + PPC_LL r2, (STKOFF + 4 * ULONG_SIZE)(r4) + PPC_LL r0, (STKOFF + 3 * ULONG_SIZE)(r4) + + /* ctr, cr and xer */ + PPC_LL r5, (STKOFF + 6 * ULONG_SIZE)(r4) + mtctr r5 + PPC_LL r5, (STKOFF + 7 * ULONG_SIZE)(r4) + mtcr r5 + PPC_LL r5, (STKOFF + 8 * ULONG_SIZE)(r4) + mtxer r5 + + /* r5-r31 */ + PPC_LL r5, (STKOFF + 10 * ULONG_SIZE)(r4) + PPC_LL r6, (STKOFF + 11 * ULONG_SIZE)(r4) + PPC_LL r7, (STKOFF + 12 * ULONG_SIZE)(r4) + PPC_LL r8, (STKOFF + 13 * ULONG_SIZE)(r4) + PPC_LL r9, (STKOFF + 14 * ULONG_SIZE)(r4) + PPC_LL r10, (STKOFF + 15 * ULONG_SIZE)(r4) + PPC_LL r11, (STKOFF + 16 * ULONG_SIZE)(r4) + PPC_LL r12, (STKOFF + 17 * ULONG_SIZE)(r4) + PPC_LL r13, (STKOFF + 18 * ULONG_SIZE)(r4) + PPC_LL r14, (STKOFF + 19 * ULONG_SIZE)(r4) + PPC_LL r15, (STKOFF + 20 * ULONG_SIZE)(r4) + PPC_LL r16, (STKOFF + 21 * ULONG_SIZE)(r4) + PPC_LL r17, (STKOFF + 22 * ULONG_SIZE)(r4) + PPC_LL r18, (STKOFF + 23 * ULONG_SIZE)(r4) + PPC_LL r19, (STKOFF + 24 * ULONG_SIZE)(r4) + PPC_LL r20, (STKOFF + 25 * ULONG_SIZE)(r4) + PPC_LL r21, (STKOFF + 26 * ULONG_SIZE)(r4) + PPC_LL r22, (STKOFF + 27 * ULONG_SIZE)(r4) + PPC_LL r23, (STKOFF + 28 * ULONG_SIZE)(r4) + PPC_LL r24, (STKOFF + 29 * ULONG_SIZE)(r4) + PPC_LL r25, (STKOFF + 30 * ULONG_SIZE)(r4) + PPC_LL r26, (STKOFF + 31 * ULONG_SIZE)(r4) + PPC_LL r27, (STKOFF + 32 * ULONG_SIZE)(r4) + PPC_LL r28, (STKOFF + 33 * ULONG_SIZE)(r4) + PPC_LL r29, (STKOFF + 34 * ULONG_SIZE)(r4) + PPC_LL r30, (STKOFF + 35 * ULONG_SIZE)(r4) + PPC_LL r31, (STKOFF + 36 * ULONG_SIZE)(r4) + + /* r4, r1 */ + PPC_LL r1, STKOFF(r4) + PPC_LL r4, (STKOFF + 8 * ULONG_SIZE)(r4) + + LOAD_REG_IMMEDIATE(r0, MSR_FP | MSR_ME | MSR_DR | MSR_IR) + MTMSRD(r0) + + blrl + +#ifdef CONFIG_PPC64 + /* Restore SF bit */ + LOAD_REG_IMMEDIATE(r0, MSR_SF | MSR_FP | MSR_ME | MSR_DR | MSR_IR) + MTMSRD(r0) +#endif + +_GLOBAL(__exit_context): + /* Get back to the original context */ + b __switch_context diff --git a/openbios-devel/include/arch/ppc/io.h b/openbios-devel/include/arch/ppc/io.h index 3449c5b..39c60d7 100644 --- a/openbios-devel/include/arch/ppc/io.h +++ b/openbios-devel/include/arch/ppc/io.h @@ -6,7 +6,7 @@ #define NO_QEMU_PROTOS #include "arch/common/fw_cfg.h"
-extern char _start, _end; +extern char _start, _end, _estack; extern unsigned long virt_offset;
#define phys_to_virt(phys) ((void *) ((unsigned long) (phys) - virt_offset))
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- openbios-devel/arch/ppc/qemu/context.c | 15 +++++++++++++++ openbios-devel/arch/ppc/qemu/init.c | 4 +++- 2 files changed, 18 insertions(+), 1 deletion(-)
diff --git a/openbios-devel/arch/ppc/qemu/context.c b/openbios-devel/arch/ppc/qemu/context.c index 93b6175..78205a2 100644 --- a/openbios-devel/arch/ppc/qemu/context.c +++ b/openbios-devel/arch/ppc/qemu/context.c @@ -32,6 +32,7 @@ void __exit_context(void); /* assembly routine */
unsigned int start_elf(unsigned long entry_point, unsigned long param); void entry(void); +void of_client_callback(void);
/* * Main context structure @@ -116,8 +117,22 @@ unsigned int start_elf(unsigned long entry_point, unsigned long param) { struct context *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 + */ + 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; + ctx->regs[REG_R7] = 0; ctx->param[0] = param;
ctx = switch_to(ctx); diff --git a/openbios-devel/arch/ppc/qemu/init.c b/openbios-devel/arch/ppc/qemu/init.c index b76c570..8f264f4 100644 --- a/openbios-devel/arch/ppc/qemu/init.c +++ b/openbios-devel/arch/ppc/qemu/init.c @@ -35,6 +35,7 @@ #define NO_QEMU_PROTOS #include "arch/common/fw_cfg.h" #include "arch/ppc/processor.h" +#include "context.h"
#define UUID_FMT "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"
@@ -595,6 +596,7 @@ id_cpu(void) }
static void go(void); +unsigned int start_elf(unsigned long entry_point, unsigned long param);
static void go(void) @@ -609,7 +611,7 @@ go(void) feval("saved-program-state >sps.entry @"); addr = POP();
- call_elf(0, 0, addr); + start_elf((unsigned long)addr, 0); }
static void kvm_of_init(void)
This makes it possible to define a Forth structure in future that can access the contents of either context directly.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk --- openbios-devel/arch/ppc/qemu/start.S | 195 ++++++++++++++++------------------ 1 file changed, 94 insertions(+), 101 deletions(-)
diff --git a/openbios-devel/arch/ppc/qemu/start.S b/openbios-devel/arch/ppc/qemu/start.S index a62d46e..33ca1e0 100644 --- a/openbios-devel/arch/ppc/qemu/start.S +++ b/openbios-devel/arch/ppc/qemu/start.S @@ -499,133 +499,126 @@ _GLOBAL(saved_stack): #define STKOFF 8 #define SAVE_SPACE 144 #endif -GLOBL(of_client_callback):
+GLOBL(of_client_callback): #ifdef CONFIG_PPC64 - PPC_STLU r1, -(STACKFRAME_MINSIZE + 16)(r1) + PPC_STLU r1, -(STACKFRAME_MINSIZE + 16)(r1) #else - PPC_STLU r1, -STACKFRAME_MINSIZE(r1) /* fits within alignment */ + PPC_STLU r1, -STACKFRAME_MINSIZE(r1) /* fits within alignment */ #endif
/* save r4 */ - - PPC_STL r4, STKOFF(r1) - + PPC_STL r4, STKOFF(r1) + /* save lr */ - mflr r4 - PPC_STL r4, PPC_LR_STKOFF(r1) - + PPC_STL r4, PPC_LR_STKOFF(r1) + /* restore OF stack */ - LOAD_REG_IMMEDIATE(r4, saved_stack) - PPC_LL r4, 0(r4) - - PPC_STLU r4,-SAVE_SPACE(r4) - PPC_STL r1,(STKOFF)(r4) // save caller stack + PPC_LL r4, 0(r4) + + PPC_STLU r4, -SAVE_SPACE(r4) + PPC_STL r1, (STKOFF)(r4) // save caller stack mr r1,r4 - - PPC_STL r2, (STKOFF + 1 * ULONG_SIZE)(r1) - PPC_STL r0, (STKOFF + 2 * ULONG_SIZE)(r1) - + + PPC_STL r3, (STKOFF + 5 * ULONG_SIZE)(r1) + PPC_STL r2, (STKOFF + 4 * ULONG_SIZE)(r1) + PPC_STL r0, (STKOFF + 3 * ULONG_SIZE)(r1) + /* save ctr, cr and xer */ - mfctr r2 - PPC_STL r2, (STKOFF + 3 * ULONG_SIZE)(r1) + PPC_STL r2, (STKOFF + 6 * ULONG_SIZE)(r1) mfcr r2 - PPC_STL r2, (STKOFF + 4 * ULONG_SIZE)(r1) + PPC_STL r2, (STKOFF + 7 * ULONG_SIZE)(r1) mfxer r2 - PPC_STL r2, (STKOFF + 5 * ULONG_SIZE)(r1) - + PPC_STL r2, (STKOFF + 8 * ULONG_SIZE)(r1) + /* save r5 - r31 */ - - PPC_STL r5, (STKOFF + 6 * ULONG_SIZE)(r1) - PPC_STL r6, (STKOFF + 7 * ULONG_SIZE)(r1) - PPC_STL r7, (STKOFF + 8 * ULONG_SIZE)(r1) - PPC_STL r8, (STKOFF + 9 * ULONG_SIZE)(r1) - PPC_STL r9, (STKOFF + 10 * ULONG_SIZE)(r1) - PPC_STL r10, (STKOFF + 11 * ULONG_SIZE)(r1) - PPC_STL r11, (STKOFF + 12 * ULONG_SIZE)(r1) - PPC_STL r12, (STKOFF + 13 * ULONG_SIZE)(r1) - PPC_STL r13, (STKOFF + 14 * ULONG_SIZE)(r1) - PPC_STL r14, (STKOFF + 15 * ULONG_SIZE)(r1) - PPC_STL r15, (STKOFF + 16 * ULONG_SIZE)(r1) - PPC_STL r16, (STKOFF + 17 * ULONG_SIZE)(r1) - PPC_STL r17, (STKOFF + 18 * ULONG_SIZE)(r1) - PPC_STL r18, (STKOFF + 19 * ULONG_SIZE)(r1) - PPC_STL r19, (STKOFF + 20 * ULONG_SIZE)(r1) - PPC_STL r20, (STKOFF + 21 * ULONG_SIZE)(r1) - PPC_STL r21, (STKOFF + 22 * ULONG_SIZE)(r1) - PPC_STL r22, (STKOFF + 23 * ULONG_SIZE)(r1) - PPC_STL r23, (STKOFF + 24 * ULONG_SIZE)(r1) - PPC_STL r24, (STKOFF + 25 * ULONG_SIZE)(r1) - PPC_STL r25, (STKOFF + 26 * ULONG_SIZE)(r1) - PPC_STL r26, (STKOFF + 27 * ULONG_SIZE)(r1) - PPC_STL r27, (STKOFF + 28 * ULONG_SIZE)(r1) - PPC_STL r28, (STKOFF + 29 * ULONG_SIZE)(r1) - PPC_STL r29, (STKOFF + 30 * ULONG_SIZE)(r1) - PPC_STL r30, (STKOFF + 31 * ULONG_SIZE)(r1) - PPC_STL r31, (STKOFF + 32 * ULONG_SIZE)(r1) - + PPC_STL r5, (STKOFF + 10 * ULONG_SIZE)(r1) + PPC_STL r6, (STKOFF + 11 * ULONG_SIZE)(r1) + PPC_STL r7, (STKOFF + 12 * ULONG_SIZE)(r1) + PPC_STL r8, (STKOFF + 13 * ULONG_SIZE)(r1) + PPC_STL r9, (STKOFF + 14 * ULONG_SIZE)(r1) + PPC_STL r10, (STKOFF + 15 * ULONG_SIZE)(r1) + PPC_STL r11, (STKOFF + 16 * ULONG_SIZE)(r1) + PPC_STL r12, (STKOFF + 17 * ULONG_SIZE)(r1) + PPC_STL r13, (STKOFF + 18 * ULONG_SIZE)(r1) + PPC_STL r14, (STKOFF + 19 * ULONG_SIZE)(r1) + PPC_STL r15, (STKOFF + 20 * ULONG_SIZE)(r1) + PPC_STL r16, (STKOFF + 21 * ULONG_SIZE)(r1) + PPC_STL r17, (STKOFF + 22 * ULONG_SIZE)(r1) + PPC_STL r18, (STKOFF + 23 * ULONG_SIZE)(r1) + PPC_STL r19, (STKOFF + 24 * ULONG_SIZE)(r1) + PPC_STL r20, (STKOFF + 25 * ULONG_SIZE)(r1) + PPC_STL r21, (STKOFF + 26 * ULONG_SIZE)(r1) + PPC_STL r22, (STKOFF + 27 * ULONG_SIZE)(r1) + PPC_STL r23, (STKOFF + 28 * ULONG_SIZE)(r1) + PPC_STL r24, (STKOFF + 29 * ULONG_SIZE)(r1) + PPC_STL r25, (STKOFF + 30 * ULONG_SIZE)(r1) + PPC_STL r26, (STKOFF + 31 * ULONG_SIZE)(r1) + PPC_STL r27, (STKOFF + 32 * ULONG_SIZE)(r1) + PPC_STL r28, (STKOFF + 33 * ULONG_SIZE)(r1) + PPC_STL r29, (STKOFF + 34 * ULONG_SIZE)(r1) + PPC_STL r30, (STKOFF + 35 * ULONG_SIZE)(r1) + PPC_STL r31, (STKOFF + 36 * ULONG_SIZE)(r1) + #ifdef CONFIG_PPC64 - LOAD_REG_IMMEDIATE(r2, of_client_interface) - ld r2, 8(r2) + LOAD_REG_IMMEDIATE(r2, of_client_interface) + ld r2, 8(r2) #endif - bl BRANCH_LABEL(of_client_interface) - + + bl BRANCH_LABEL(of_client_interface) + /* restore r5 - r31 */ - - PPC_LL r5, (STKOFF + 6 * ULONG_SIZE)(r1) - PPC_LL r6, (STKOFF + 7 * ULONG_SIZE)(r1) - PPC_LL r7, (STKOFF + 8 * ULONG_SIZE)(r1) - PPC_LL r8, (STKOFF + 9 * ULONG_SIZE)(r1) - PPC_LL r9, (STKOFF + 10 * ULONG_SIZE)(r1) - PPC_LL r10, (STKOFF + 11 * ULONG_SIZE)(r1) - PPC_LL r11, (STKOFF + 12 * ULONG_SIZE)(r1) - PPC_LL r12, (STKOFF + 13 * ULONG_SIZE)(r1) - PPC_LL r13, (STKOFF + 14 * ULONG_SIZE)(r1) - PPC_LL r14, (STKOFF + 15 * ULONG_SIZE)(r1) - PPC_LL r15, (STKOFF + 16 * ULONG_SIZE)(r1) - PPC_LL r16, (STKOFF + 17 * ULONG_SIZE)(r1) - PPC_LL r17, (STKOFF + 18 * ULONG_SIZE)(r1) - PPC_LL r18, (STKOFF + 19 * ULONG_SIZE)(r1) - PPC_LL r19, (STKOFF + 20 * ULONG_SIZE)(r1) - PPC_LL r20, (STKOFF + 21 * ULONG_SIZE)(r1) - PPC_LL r21, (STKOFF + 22 * ULONG_SIZE)(r1) - PPC_LL r22, (STKOFF + 23 * ULONG_SIZE)(r1) - PPC_LL r23, (STKOFF + 24 * ULONG_SIZE)(r1) - PPC_LL r24, (STKOFF + 25 * ULONG_SIZE)(r1) - PPC_LL r25, (STKOFF + 26 * ULONG_SIZE)(r1) - PPC_LL r26, (STKOFF + 27 * ULONG_SIZE)(r1) - PPC_LL r27, (STKOFF + 28 * ULONG_SIZE)(r1) - PPC_LL r28, (STKOFF + 29 * ULONG_SIZE)(r1) - PPC_LL r29, (STKOFF + 30 * ULONG_SIZE)(r1) - PPC_LL r30, (STKOFF + 31 * ULONG_SIZE)(r1) - PPC_LL r31, (STKOFF + 32 * ULONG_SIZE)(r1) - + PPC_LL r5, (STKOFF + 10 * ULONG_SIZE)(r1) + PPC_LL r6, (STKOFF + 11 * ULONG_SIZE)(r1) + PPC_LL r7, (STKOFF + 12 * ULONG_SIZE)(r1) + PPC_LL r8, (STKOFF + 13 * ULONG_SIZE)(r1) + PPC_LL r9, (STKOFF + 14 * ULONG_SIZE)(r1) + PPC_LL r10, (STKOFF + 15 * ULONG_SIZE)(r1) + PPC_LL r11, (STKOFF + 16 * ULONG_SIZE)(r1) + PPC_LL r12, (STKOFF + 17 * ULONG_SIZE)(r1) + PPC_LL r13, (STKOFF + 18 * ULONG_SIZE)(r1) + PPC_LL r14, (STKOFF + 19 * ULONG_SIZE)(r1) + PPC_LL r15, (STKOFF + 20 * ULONG_SIZE)(r1) + PPC_LL r16, (STKOFF + 21 * ULONG_SIZE)(r1) + PPC_LL r17, (STKOFF + 22 * ULONG_SIZE)(r1) + PPC_LL r18, (STKOFF + 23 * ULONG_SIZE)(r1) + PPC_LL r19, (STKOFF + 24 * ULONG_SIZE)(r1) + PPC_LL r20, (STKOFF + 25 * ULONG_SIZE)(r1) + PPC_LL r21, (STKOFF + 26 * ULONG_SIZE)(r1) + PPC_LL r22, (STKOFF + 27 * ULONG_SIZE)(r1) + PPC_LL r23, (STKOFF + 28 * ULONG_SIZE)(r1) + PPC_LL r24, (STKOFF + 29 * ULONG_SIZE)(r1) + PPC_LL r25, (STKOFF + 30 * ULONG_SIZE)(r1) + PPC_LL r26, (STKOFF + 31 * ULONG_SIZE)(r1) + PPC_LL r27, (STKOFF + 32 * ULONG_SIZE)(r1) + PPC_LL r28, (STKOFF + 33 * ULONG_SIZE)(r1) + PPC_LL r29, (STKOFF + 34 * ULONG_SIZE)(r1) + PPC_LL r30, (STKOFF + 35 * ULONG_SIZE)(r1) + PPC_LL r31, (STKOFF + 36 * ULONG_SIZE)(r1) + /* restore ctr, cr and xer */ - - PPC_LL r2, (STKOFF + 3 * ULONG_SIZE)(r1) + PPC_LL r2, (STKOFF + 6 * ULONG_SIZE)(r1) mtctr r2 - PPC_LL r2, (STKOFF + 4 * ULONG_SIZE)(r1) + PPC_LL r2, (STKOFF + 7 * ULONG_SIZE)(r1) mtcr r2 - PPC_LL r2, (STKOFF + 5 * ULONG_SIZE)(r1) + PPC_LL r2, (STKOFF + 8 * ULONG_SIZE)(r1) mtxer r2 - + /* restore r0 and r2 */ - - PPC_LL r2, (STKOFF + 1 * ULONG_SIZE)(r1) - PPC_LL r0, (STKOFF + 2 * ULONG_SIZE)(r1) - + PPC_LL r2, (STKOFF + 4 * ULONG_SIZE)(r1) + PPC_LL r0, (STKOFF + 3 * ULONG_SIZE)(r1) + /* restore caller stack */ - - PPC_LL r1, (STKOFF)(r1) - - PPC_LL r4, PPC_LR_STKOFF(r1) + PPC_LL r1, (STKOFF)(r1) + + PPC_LL r4, PPC_LR_STKOFF(r1) mtlr r4 - PPC_LL r4, STKOFF(r1) - PPC_LL r1, 0(r1) - + PPC_LL r4, STKOFF(r1) + PPC_LL r1, 0(r1) + blr
/* rtas glue (must be reloctable) */
On May 2, 2016, at 7:50 AM, Mark Cave-Ayland wrote:
This patch series is part of a much larger WIP series designed to remove various hacks from the load/init-program/go words. However in order for the follow-on series to work, all architectures must build an execution context similar to the IEEE1275 specification description of saved-program-state.
PPC is the only architecture which doesn't make use of contexts when entering/leaving the Forth environment, so start by adding this functionality in order that it can be expanded on further with later patches. While no functionality is changed by this patch, there should be no regressions when attempting to boot existing client images.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk
v2:
- Use single asm invocation in switch_to() with clobber register
- Fix unsigned int -> unsigned long
- Fix missing volatile from __context pointer
This patch set does work better than the first one. Debian Linux, Darwin, and Mac OS 10.4 all boot with your patches. The only one to that did not work is Mac OS 9.2. Even when I add the '\r' to '\n' patch, it still doesn't boot. It could be a problem on my end. Or it could be you are on to something...
On May 2, 2016, at 7:50 AM, Mark Cave-Ayland wrote:
This patch series is part of a much larger WIP series designed to remove various hacks from the load/init-program/go words. However in order for the follow-on series to work, all architectures must build an execution context similar to the IEEE1275 specification description of saved-program-state.
PPC is the only architecture which doesn't make use of contexts when entering/leaving the Forth environment, so start by adding this functionality in order that it can be expanded on further with later patches. While no functionality is changed by this patch, there should be no regressions when attempting to boot existing client images.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk
v2:
- Use single asm invocation in switch_to() with clobber register
- Fix unsigned int -> unsigned long
- Fix missing volatile from __context pointer
Just wanted to add that Mac OS 9.2 does boot with your patches. It was a local problem that prevented it from booting. Thanks.
On 02/05/16 16:13, Programmingkid wrote:
On May 2, 2016, at 7:50 AM, Mark Cave-Ayland wrote:
This patch series is part of a much larger WIP series designed to remove various hacks from the load/init-program/go words. However in order for the follow-on series to work, all architectures must build an execution context similar to the IEEE1275 specification description of saved-program-state.
PPC is the only architecture which doesn't make use of contexts when entering/leaving the Forth environment, so start by adding this functionality in order that it can be expanded on further with later patches. While no functionality is changed by this patch, there should be no regressions when attempting to boot existing client images.
Signed-off-by: Mark Cave-Ayland mark.cave-ayland@ilande.co.uk
v2:
- Use single asm invocation in switch_to() with clobber register
- Fix unsigned int -> unsigned long
- Fix missing volatile from __context pointer
Just wanted to add that Mac OS 9.2 does boot with your patches. It was a local problem that prevented it from booting. Thanks.
Great, thanks for testing. I'll see if anyone else has any further feedback before pushing on with this.
ATB,
Mark.