[OpenBIOS] [PATCHv2 2/4] ppc: add new context handler
Mark Cave-Ayland
mark.cave-ayland at ilande.co.uk
Mon May 2 13:50:16 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 | 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))
--
1.7.10.4
More information about the OpenBIOS
mailing list