[OpenBIOS] [PATCH 2/4] ppc: add new context handler

Mark Cave-Ayland mark.cave-ayland at ilande.co.uk
Sun May 1 12:23:00 CEST 2016


Signed-off-by: Mark Cave-Ayland <mark.cave-ayland at ilande.co.uk>
---
 openbios-devel/arch/ppc/build.xml      |    1 +
 openbios-devel/arch/ppc/qemu/context.c |  123 ++++++++++++++++++++++++
 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, 327 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..e56da71
--- /dev/null
+++ b/openbios-devel/arch/ppc/qemu/context.c
@@ -0,0 +1,123 @@
+/*
+ * 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 *__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 %0\n\t" : "=r" (lr) : : );
+    asm __volatile__ ("bl __switch_context\n");
+    asm __volatile__ ("mtlr %0\n\t" : : "r" (lr) : );
+    
+    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))
-- 
1.7.10.4




More information about the OpenBIOS mailing list