Index: openbios-devel/arch/sparc64/aoutload.c
===================================================================
--- openbios-devel.orig/arch/sparc64/aoutload.c
+++ openbios-devel/arch/sparc64/aoutload.c
@@ -125,19 +125,10 @@ int aout_load(struct sys_info *info, con
debug("entry point is %#lx\n", start);
printf("Jumping to entry point...\n");
-#if 1
{
- int (*entry)(unsigned long p1, unsigned long p2, unsigned long p3,
- unsigned long p4, unsigned long p5);
- extern int of_client_interface( int *params );
-
- entry = (void *) addr_fixup(start);
-
- __asm__ __volatile__("clr %i3\n");
-
- image_retval = entry(0, 0, 0, 0, (unsigned long)&of_client_interface);
+ extern int sparc64_of_client_interface( int *params );
+ image_retval = start_client_image(addr_fixup(start), (uint64_t)&sparc64_of_client_interface);
}
-#endif
printf("Image returned with return value %#x\n", image_retval);
retval = 0;
Index: openbios-devel/arch/sparc64/context.c
===================================================================
--- openbios-devel.orig/arch/sparc64/context.c
+++ openbios-devel/arch/sparc64/context.c
@@ -10,7 +10,7 @@
#include "boot.h"
#define MAIN_STACK_SIZE 16384
-#define IMAGE_STACK_SIZE 4096
+#define IMAGE_STACK_SIZE 4096*2
#define debug printk
@@ -23,7 +23,7 @@ void __exit_context(void); /* assembly r
* to start us up.
*/
static struct context main_ctx = {
- .regs[REG_SP] = (uint64_t) &_estack - 2047 - 96,
+ .regs[REG_SP] = (uint64_t) &_estack - STACK_BIAS - 96,
.pc = (uint64_t) start_main,
.npc = (uint64_t) start_main + 4,
.return_addr = (uint64_t) __exit_context,
@@ -31,7 +31,7 @@ static struct context main_ctx = {
/* 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;
/* Stack for loaded ELF image */
static uint8_t image_stack[IMAGE_STACK_SIZE];
@@ -62,19 +62,25 @@ static void start_main(void)
__context = boot_ctx;
}
+static uint64_t ALIGN_SIZE(uint64_t x, uint64_t a)
+{
+ return (x + a - 1) & ~(a-1);
+}
+
/* Setup a new context using the given stack.
*/
struct context *
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 + stack_size - (sizeof(*ctx) + num_params*sizeof(uint32_t)));
+ (stack_top - ALIGN_SIZE(sizeof(*ctx) + num_params*sizeof(uint64_t), sizeof(uint64_t)));
memset(ctx, 0, sizeof(*ctx));
/* Fill in reasonable default for flat memory model */
- ctx->regs[REG_SP] = virt_to_phys(SP_LOC(ctx));
+ ctx->regs[REG_SP] = virt_to_phys(stack_top - STACK_BIAS - 192);
ctx->return_addr = virt_to_phys(__exit_context);
return ctx;
@@ -85,10 +91,11 @@ struct context *switch_to(struct context
{
struct context *save, *ret;
- debug("switching to new context:\n");
+ debug("switching to new context: entry point %#llx stack 0x%016llx\n", ctx->pc, ctx->regs[REG_SP]);
save = __context;
__context = ctx;
//asm ("pushl %cs; call __switch_context");
+ asm ("call __switch_context_nosave; nop");
ret = __context;
__context = save;
return ret;
@@ -109,3 +116,18 @@ uint64_t start_elf(uint64_t entry_point,
//return ctx->eax;
return 0;
}
+
+/* Start client image */
+uint64_t start_client_image(uint64_t entry_point, uint64_t cif_handler)
+{
+ struct context *ctx;
+
+ ctx = init_context(image_stack, sizeof image_stack, 0);
+ ctx->pc = entry_point;
+ ctx->npc = entry_point+4;
+ ctx->regs[REG_O0+4] = cif_handler;
+
+ ctx = switch_to(ctx);
+
+ return 0;
+}
Index: openbios-devel/arch/sparc64/context.h
===================================================================
--- openbios-devel.orig/arch/sparc64/context.h
+++ openbios-devel/arch/sparc64/context.h
@@ -1,6 +1,8 @@
#ifndef SPARC64_CONTEXT_H
#define SPARC64_CONTEXT_H
+#define STACK_BIAS 2047
+
struct context {
/* General registers */
uint64_t regs[32];
Index: openbios-devel/arch/sparc64/boot.h
===================================================================
--- openbios-devel.orig/arch/sparc64/boot.h
+++ openbios-devel/arch/sparc64/boot.h
@@ -22,8 +22,9 @@ int linux_load(struct sys_info *info, co
int fcode_load(const char *filename);
// context.c
-extern struct context *__context;
+extern struct context * volatile __context;
uint64_t start_elf(uint64_t entry_point, uint64_t param);
+uint64_t start_client_image(uint64_t entry_point, uint64_t cif_handler);
// boot.c
extern struct sys_info sys_info;
Index: openbios-devel/arch/sparc64/build.xml
===================================================================
--- openbios-devel.orig/arch/sparc64/build.xml
+++ openbios-devel/arch/sparc64/build.xml
@@ -29,6 +29,10 @@
+
+
+
@@ -39,6 +43,7 @@
+
@@ -77,6 +82,7 @@
+
Index: openbios-devel/arch/sparc64/boot.c
===================================================================
--- openbios-devel.orig/arch/sparc64/boot.c
+++ openbios-devel/arch/sparc64/boot.c
@@ -26,11 +26,11 @@ void boot(void)
if (kernel_size) {
void (*entry)(unsigned long p1, unsigned long p2, unsigned long p3,
unsigned long p4, unsigned long p5);
- extern int of_client_interface( int *params );
+ extern int sparc64_of_client_interface( int *params );
printk("[sparc64] Kernel already loaded\n");
entry = (void *) (unsigned long)kernel_image;
- entry(0, 0, 0, 0, (unsigned long)&of_client_interface);
+ entry(0, 0, 0, 0, (unsigned long)&sparc64_of_client_interface);
}
if(!path) {
Index: openbios-devel/arch/sparc64/call-client.S
===================================================================
--- /dev/null
+++ openbios-devel/arch/sparc64/call-client.S
@@ -0,0 +1,44 @@
+ .globl sparc64_of_client_interface
+
+ .data
+ .align 8
+client_globals:
+ .skip 64
+
+ .text
+ .align 4
+ .register %g2, #scratch
+ .register %g3, #scratch
+ .register %g6, #scratch
+ .register %g7, #scratch
+/*
+ make some more space on stack since linux kernel only provides 128 bytes
+ without memory to spill registers (used by gcc in -O0 mode)
+*/
+
+sparc64_of_client_interface:
+ /* make sure caller's windows are on caller's stack */
+ flushw
+ save %sp, -248, %sp
+ stx %g1, [%sp + 2047 + 192 + 0]
+ stx %g2, [%sp + 2047 + 192 + 16]
+ stx %g3, [%sp + 2047 + 192 + 24]
+ stx %g4, [%sp + 2047 + 192 + 32]
+ stx %g5, [%sp + 2047 + 192 + 40]
+ stx %g6, [%sp + 2047 + 192 + 48]
+ stx %g7, [%sp + 2047 + 192 + 56]
+
+ call of_client_interface
+ mov %i0, %o0
+ mov %o0, %i0
+
+ ldx [%sp + 2047 + 192 + 0], %g1
+ ldx [%sp + 2047 + 192 + 16], %g2
+ ldx [%sp + 2047 + 192 + 24], %g3
+ ldx [%sp + 2047 + 192 + 32], %g4
+ ldx [%sp + 2047 + 192 + 40], %g5
+ ldx [%sp + 2047 + 192 + 48], %g6
+ ldx [%sp + 2047 + 192 + 56], %g7
+ return %i7+8
+ nop
+
Index: openbios-devel/arch/sparc64/switch.S
===================================================================
--- openbios-devel.orig/arch/sparc64/switch.S
+++ openbios-devel/arch/sparc64/switch.S
@@ -24,7 +24,12 @@
/* XXX: totally bogus for sparc, need to save and restore all windows */
__switch_context:
+
+ /* make sure caller's windows are on caller's stack */
+ flushw;
+
/* Save everything in current stack */
+
setx __context, %g2, %g1
stx %g3, [%g1 + 24]
stx %g4, [%g1 + 32]
@@ -61,7 +66,8 @@ __switch_context:
__switch_context_nosave:
/* Interrupts are not allowed... */
-
+ /* make sure caller's windows are on caller's stack */
+ flushw
/* Load all registers
*/
setx __context, %g2, %g1