/*
 *   Creation Date: <2001/06/16 21:30:18 samuel>
 *   Time-stamp: <2003/04/04 16:32:06 samuel>
 *
 *	<init.S>
 *
 *	Asm glue for ELF images
 *
 *   Copyright (C) 2001, 2002, 2003 Samuel Rydh (samuel@ibrium.se)
 *
 *   This program is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU General Public License
 *   as published by the Free Software Foundation
 *
 */

#include "autoconf.h"
#include "asm/asmdefs.h"
#include "asm/processor.h"

/************************************************************************/
/*	Macros								*/
/************************************************************************/

#define ILLEGAL_VECTOR( v )	.org __vectors + v ; vector__##v: bl trap_error ;
#define VECTOR( v, dummystr )	.org __vectors + v ; vector__##v

#ifdef CONFIG_PPC_64BITSUPPORT

/* We're trying to use the same code for the ppc32 and ppc64 handlers here.
 * On ppc32 we only save/restore the registers, C considers volatile.
 *
 * On ppc64 on the other hand, we have to save/restore all registers, because
 * all OF code is 32 bits, which only saves/restores the low 32 bits of the
 * registers it clobbers.
 */

#define EXCEPTION_PREAMBLE_TEMPLATE \
	mtsprg1	r1 ;				/* scratch */ \
	mfcr	r1 ; \
	mtsprg2	r1 ;				/* scratch */ \
	lis	r1, 0x8000 ;			/* r1=0x80000000 */ \
	add.	r1,r1,r1 ;			/* r1=r1+r1 (high 32bit !0) */ \
	beq	1f; \
	\
	mfmsr	r1 ;				/* unset MSR_SF */ \
	clrldi	r1,r1,1 ; \
	mtmsrd	r1 ; \
1: \
	mfsprg0	r1 ;				/* exception stack in sprg0 */ \
.ifc ULONG_SIZE, 8 ; \
	addi	r1,r1,-(40 * ULONG_SIZE) ;	/* push exception frame */ \
.else ; \
	addi	r1,r1,-(20 * ULONG_SIZE) ;	/* push exception frame */ \
.endif ; \
 \
	stl	r0,(0 * ULONG_SIZE)(r1) ;	/* save r0 */ \
	mfsprg1	r0 ; \
	stl	r0,(1 * ULONG_SIZE)(r1) ;	/* save r1 */ \
	stl	r2,(2 * ULONG_SIZE)(r1) ;	/* save r2 */ \
	stl	r3,(3 * ULONG_SIZE)(r1) ;	/* save r3 */ \
	stl	r4,(4 * ULONG_SIZE)(r1) ; \
	stl	r5,(5 * ULONG_SIZE)(r1) ; \
	stl	r6,(6 * ULONG_SIZE)(r1) ; \
	stl	r7,(7 * ULONG_SIZE)(r1) ; \
	stl	r8,(8 * ULONG_SIZE)(r1) ; \
	stl	r9,(9 * ULONG_SIZE)(r1) ; \
	stl	r10,(10 * ULONG_SIZE)(r1) ; \
	stl	r11,(11 * ULONG_SIZE)(r1) ; \
	stl	r12,(12 * ULONG_SIZE)(r1) ; \
.ifc ULONG_SIZE, 8 ; \
	stl	r13,(17 * ULONG_SIZE)(r1) ; \
	stl	r14,(18 * ULONG_SIZE)(r1) ; \
	stl	r15,(19 * ULONG_SIZE)(r1) ; \
	stl	r16,(20 * ULONG_SIZE)(r1) ; \
	stl	r17,(21 * ULONG_SIZE)(r1) ; \
	stl	r18,(22 * ULONG_SIZE)(r1) ; \
	stl	r19,(23 * ULONG_SIZE)(r1) ; \
	stl	r20,(24 * ULONG_SIZE)(r1) ; \
	stl	r21,(25 * ULONG_SIZE)(r1) ; \
	stl	r22,(26 * ULONG_SIZE)(r1) ; \
	stl	r23,(27 * ULONG_SIZE)(r1) ; \
	stl	r24,(28 * ULONG_SIZE)(r1) ; \
	stl	r25,(29 * ULONG_SIZE)(r1) ; \
	stl	r26,(30 * ULONG_SIZE)(r1) ; \
	stl	r27,(31 * ULONG_SIZE)(r1) ; \
	stl	r28,(32 * ULONG_SIZE)(r1) ; \
	stl	r29,(33 * ULONG_SIZE)(r1) ; \
	stl	r30,(34 * ULONG_SIZE)(r1) ; \
	stl	r31,(35 * ULONG_SIZE)(r1) ; \
.endif ; \
 \
	mflr	r0 ; \
	stl	r0,(13 * ULONG_SIZE)(r1) ; \
	mfsprg2	r0 ; \
	stl	r0,(14 * ULONG_SIZE)(r1) ; \
	mfctr	r0 ; \
	stl	r0,(15 * ULONG_SIZE)(r1) ; \
	mfxer	r0 ; \
	stl	r0,(16 * ULONG_SIZE)(r1) ; \
 \
	/* 76(r1) unused */ \
	addi	r1,r1,-16 ;	/* C ABI uses 0(r1) and 4(r1)... */

#define EXCEPTION_EPILOGUE_TEMPLATE \
	addi	r1,r1,16 ;			/* pop ABI frame */ \
\
	ll	r0,(13 * ULONG_SIZE)(r1) ; \
	mtlr	r0 ; \
	ll	r0,(14 * ULONG_SIZE)(r1) ; \
	mtcr	r0 ; \
	ll	r0,(15 * ULONG_SIZE)(r1) ; \
	mtctr	r0 ; \
	ll	r0,(16 * ULONG_SIZE)(r1) ; \
	mtxer	r0 ; \
\
	ll	r0,(0 * ULONG_SIZE)(r1) ; \
	ll	r2,(2 * ULONG_SIZE)(r1) ; \
	ll	r3,(3 * ULONG_SIZE)(r1) ; \
	ll	r4,(4 * ULONG_SIZE)(r1) ; \
	ll	r5,(5 * ULONG_SIZE)(r1) ; \
	ll	r6,(6 * ULONG_SIZE)(r1) ; \
	ll	r7,(7 * ULONG_SIZE)(r1) ; \
	ll	r8,(8 * ULONG_SIZE)(r1) ; \
	ll	r9,(9 * ULONG_SIZE)(r1) ; \
	ll	r10,(10 * ULONG_SIZE)(r1) ; \
	ll	r11,(11 * ULONG_SIZE)(r1) ; \
	ll	r12,(12 * ULONG_SIZE)(r1) ; \
.ifc ULONG_SIZE, 8 ; \
	ll	r13,(17 * ULONG_SIZE)(r1) ; \
	ll	r14,(18 * ULONG_SIZE)(r1) ; \
	ll	r15,(19 * ULONG_SIZE)(r1) ; \
	ll	r16,(20 * ULONG_SIZE)(r1) ; \
	ll	r17,(21 * ULONG_SIZE)(r1) ; \
	ll	r18,(22 * ULONG_SIZE)(r1) ; \
	ll	r19,(23 * ULONG_SIZE)(r1) ; \
	ll	r20,(24 * ULONG_SIZE)(r1) ; \
	ll	r21,(25 * ULONG_SIZE)(r1) ; \
	ll	r22,(26 * ULONG_SIZE)(r1) ; \
	ll	r23,(27 * ULONG_SIZE)(r1) ; \
	ll	r24,(28 * ULONG_SIZE)(r1) ; \
	ll	r25,(29 * ULONG_SIZE)(r1) ; \
	ll	r26,(30 * ULONG_SIZE)(r1) ; \
	ll	r27,(31 * ULONG_SIZE)(r1) ; \
	ll	r28,(32 * ULONG_SIZE)(r1) ; \
	ll	r29,(33 * ULONG_SIZE)(r1) ; \
	ll	r30,(34 * ULONG_SIZE)(r1) ; \
	ll	r31,(35 * ULONG_SIZE)(r1) ; \
.endif ; \
	ll	r1,(1 * ULONG_SIZE)(r1) ;	/* restore stack at last */ \
	rfi

// PPC32

#define ULONG_SIZE		4
#define stl			stw
#define ll			lwz

.macro EXCEPTION_PREAMBLE
	EXCEPTION_PREAMBLE_TEMPLATE
.endm

.macro EXCEPTION_EPILOGUE
	EXCEPTION_EPILOGUE_TEMPLATE
.endm

#undef ULONG_SIZE
#undef stl
#undef ll

// PPC64

#define ULONG_SIZE		8
#define stl			std
#define ll			ld

.macro EXCEPTION_PREAMBLE_64
	EXCEPTION_PREAMBLE_TEMPLATE
.endm

.macro EXCEPTION_EPILOGUE_64
	EXCEPTION_EPILOGUE_TEMPLATE
.endm

#undef ULONG_SIZE
#undef stl
#undef ll

#define ULONG_SIZE 4
#define STACKFRAME_MINSIZE 16

#else /* !CONFIG_PPC_64BITSUPPORT */

#ifdef __powerpc64__

#define ULONG_SIZE 8
#define STACKFRAME_MINSIZE 48
#define stl std
#define ll  ld

#else

#define ULONG_SIZE 4
#define STACKFRAME_MINSIZE 16
#define stl stw
#define ll  lwz

#endif

.macro EXCEPTION_PREAMBLE
    mtsprg1 r1 /* scratch */
    mfsprg0 r1 /* exception stack in sprg0 */
    addi    r1, r1, -(20 * ULONG_SIZE) /* push exception frame */

    stl     r0,  ( 0 * ULONG_SIZE)(r1) /* save r0 */
    mfsprg1 r0
    stl     r0,  ( 1 * ULONG_SIZE)(r1) /* save r1 */
    stl     r2,  ( 2 * ULONG_SIZE)(r1) /* save r2 */
    stl     r3,  ( 3 * ULONG_SIZE)(r1) /* save r3 */
    stl     r4,  ( 4 * ULONG_SIZE)(r1)
    stl     r5,  ( 5 * ULONG_SIZE)(r1)
    stl     r6,  ( 6 * ULONG_SIZE)(r1)
    stl     r7,  ( 7 * ULONG_SIZE)(r1)
    stl     r8,  ( 8 * ULONG_SIZE)(r1)
    stl     r9,  ( 9 * ULONG_SIZE)(r1)
    stl     r10, (10 * ULONG_SIZE)(r1)
    stl     r11, (11 * ULONG_SIZE)(r1)
    stl     r12, (12 * ULONG_SIZE)(r1)

    mflr    r0
    stl     r0,  (13 * ULONG_SIZE)(r1)
    mfcr    r0
    stl     r0,  (14 * ULONG_SIZE)(r1)
    mfctr   r0
    stl     r0,  (15 * ULONG_SIZE)(r1)
    mfxer   r0
    stl     r0,  (16 * ULONG_SIZE)(r1)

    addi r1, r1, -STACKFRAME_MINSIZE /* C ABI saves LR and SP */
.endm

.macro EXCEPTION_EPILOGUE
    addi r1, r1,  STACKFRAME_MINSIZE /* pop ABI frame */

    ll    r0,  (13 * ULONG_SIZE)(r1)
    mtlr  r0
    ll    r0,  (14 * ULONG_SIZE)(r1)
    mtcr  r0
    ll    r0,  (15 * ULONG_SIZE)(r1)
    mtctr r0
    ll    r0,  (16 * ULONG_SIZE)(r1)
    mtxer r0

    ll    r0,  ( 0 * ULONG_SIZE)(r1)
    ll    r2,  ( 2 * ULONG_SIZE)(r1)
    ll    r3,  ( 3 * ULONG_SIZE)(r1)
    ll    r4,  ( 4 * ULONG_SIZE)(r1)
    ll    r5,  ( 5 * ULONG_SIZE)(r1)
    ll    r6,  ( 6 * ULONG_SIZE)(r1)
    ll    r7,  ( 7 * ULONG_SIZE)(r1)
    ll    r8,  ( 8 * ULONG_SIZE)(r1)
    ll    r9,  ( 9 * ULONG_SIZE)(r1)
    ll    r10, (10 * ULONG_SIZE)(r1)
    ll    r11, (11 * ULONG_SIZE)(r1)
    ll    r12, (12 * ULONG_SIZE)(r1)

    ll    r1,  ( 1 * ULONG_SIZE)(r1) /* restore stack at last */
    RFI
.endm

#endif /* !CONFIG_PPC_64BITSUPPORT */

/************************************************************************/
/*	vectors								*/
/************************************************************************/

        .section .text.vectors, "ax"
GLOBL(__vectors):
	nop			// NULL-jmp trap
1:	nop			//
	b	1b

call_dsi_exception:
	LOAD_REG_FUNC(r3, dsi_exception)
	mtctr	r3
	bctrl
	b	exception_return

call_isi_exception:
	LOAD_REG_FUNC(r3, isi_exception)
	mtctr	r3
	bctrl
	b	exception_return

exception_return:
	EXCEPTION_EPILOGUE

trap_error:
	lis	r1, 0x8000			/* r1=0x80000000 */
	add.	r1,r1,r1			/* r1=r1+r1 (high 32bit !0) */
	beq	1f

	mfmsr	r1  				/* unset MSR_SF */
	clrldi	r1,r1,1
	mtmsrd	r1
1:
	mflr	r3
	LOAD_REG_FUNC(r4, unexpected_excep)
	mtctr r4
	bctr

VECTOR( 0x100, "SRE" ):
        b       _entry

ILLEGAL_VECTOR( 0x200 )

VECTOR( 0x300, "DSI" ):
	b	real_dsi

ILLEGAL_VECTOR( 0x380 )

VECTOR( 0x400, "ISI" ):
	b	real_isi

ILLEGAL_VECTOR( 0x480 )

	ILLEGAL_VECTOR( 0x500 )
	ILLEGAL_VECTOR( 0x600 )
	ILLEGAL_VECTOR( 0x700 )

VECTOR( 0x800, "FPU" ):
	mtsprg1	r3
	mfsrr1	r3
	ori	r3,r3,0x2000
	mtsrr1	r3
	mfsprg1	r3
	RFI

ILLEGAL_VECTOR( 0x900 )
ILLEGAL_VECTOR( 0xa00 )
ILLEGAL_VECTOR( 0xb00 )
ILLEGAL_VECTOR( 0xc00 )
ILLEGAL_VECTOR( 0xd00 )
ILLEGAL_VECTOR( 0xe00 )
ILLEGAL_VECTOR( 0xf00 )
ILLEGAL_VECTOR( 0xf20 )
ILLEGAL_VECTOR( 0x1000 )
ILLEGAL_VECTOR( 0x1100 )
ILLEGAL_VECTOR( 0x1200 )
ILLEGAL_VECTOR( 0x1300 )
ILLEGAL_VECTOR( 0x1400 )
ILLEGAL_VECTOR( 0x1500 )
ILLEGAL_VECTOR( 0x1600 )
ILLEGAL_VECTOR( 0x1700 )

#ifdef CONFIG_PPC_64BITSUPPORT

VECTOR( 0x2000, "DSI_64" ):
	EXCEPTION_PREAMBLE_64
	LOAD_REG_IMMEDIATE(r3, dsi_exception)
	mtctr	r3
	bctrl
	EXCEPTION_EPILOGUE_64

VECTOR( 0x2200, "ISI_64" ):
	EXCEPTION_PREAMBLE_64
	LOAD_REG_IMMEDIATE(r3, isi_exception)
	mtctr	r3
	bctrl
	EXCEPTION_EPILOGUE_64

#endif

real_dsi:
	EXCEPTION_PREAMBLE
	b	call_dsi_exception

real_isi:
	EXCEPTION_PREAMBLE
	b	call_isi_exception

GLOBL(__vectors_end):

/************************************************************************/
/*	entry								*/
/************************************************************************/

GLOBL(_entry):

#ifdef CONFIG_PPC_64BITSUPPORT
	li	r0,0

	lis	r3, 0x8000			/* r1=0x80000000 */
	add.	r3,r3,r3			/* r1=r1+r1 (high 32bit !0) */
	beq	no_64bit			/* only true when !MSR_SF */

	/* clear MSR, disable MMU, SF */
	mtmsrd	r0
	b	real_entry

no_64bit:
	/* clear MSR, disable MMU */
	mtmsr	r0

real_entry:
#endif

	/* copy exception vectors */

	LOAD_REG_IMMEDIATE(r3, __vectors)
	li	r4,0
	li	r5,__vectors_end - __vectors + 16
	rlwinm	r5,r5,0,0,28
1:	lwz	r6,0(r3)
	lwz	r7,4(r3)
	lwz	r8,8(r3)
	lwz	r9,12(r3)
	stw	r6,0(r4)
	stw	r7,4(r4)
	stw	r8,8(r4)
	stw	r9,12(r4)
	dcbst	0,r4
	sync
	icbi	0,r4
	sync
	addi	r5,r5,-16
	addi	r3,r3,16
	addi	r4,r4,16
	cmpwi	r5,0
	bgt	1b
	isync

	bl compute_ramsize

	/* Memory map:
	 *
	 * Top +-------------------------+
	 *     |                         |
	 *     | ROM into RAM (1 MB)     |
	 *     |                         |
	 *     +-------------------------+
	 *     |                         |
	 *     | MMU Hash Table (64 kB)  |
	 *     |                         |
	 *     +-------------------------+
	 *     |                         |
	 *     | Exception Stack (32 kB) |
	 *     |                         |
	 *     +-------------------------+
	 *     |                         |
	 *     | Stack (64 kB)           |
	 *     |                         |
	 *     +-------------------------+
	 *     |                         |
	 *     | Client Stack (64 kB)    |
	 *     |                         |
	 *     +-------------------------+
	 *     |                         |
	 *     | Malloc Zone (2 MiB)     |
	 *     |                         |
	 *     +-------------------------+
	 *     :                         :
	 * Bottom
	 */

	addis	r1, r3, -16		/* ramsize - 1MB */

	/* setup hash table */

	addis	r1, r1, -1		/* - 64 kB */
	clrrwi	r1, r1, 5*4		/* & ~0xfffff */

	/* setup exception stack */

	mtsprg0	r1

	/* setup stack */

	addi	r1, r1, -32768		/* - 32 kB */

	/* save memory size in stack */

#ifdef __powerpc64__
	/* set up TOC pointer */

	LOAD_REG_IMMEDIATE(r2, setup_mmu)
	ld r2, 8(r2)
#endif

	bl	BRANCH_LABEL(setup_mmu)
	bl	BRANCH_LABEL(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)
        .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
#define SAVE_SPACE 320
#else
#define STKOFF 8
#define SAVE_SPACE 144
#endif
GLOBL(of_client_callback):

#ifdef CONFIG_PPC64
    PPC_STLU r1, -(STACKFRAME_MINSIZE + 16)(r1)
#else
    PPC_STLU r1, -STACKFRAME_MINSIZE(r1) /* fits within alignment */
#endif

	/* save r4 */

    PPC_STL r4, STKOFF(r1)

	/* save lr */

	mflr	r4
    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
	mr	r1,r4

    PPC_STL r2,  (STKOFF +  1 * ULONG_SIZE)(r1)
    PPC_STL r0,  (STKOFF +  2 * ULONG_SIZE)(r1)

	/* save ctr, cr and xer */

	mfctr	r2
    PPC_STL r2,  (STKOFF +  3 * ULONG_SIZE)(r1)
	mfcr	r2
    PPC_STL r2,  (STKOFF +  4 * ULONG_SIZE)(r1)
	mfxer	r2
    PPC_STL r2,  (STKOFF +  5 * 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)

#ifdef CONFIG_PPC64
    LOAD_REG_IMMEDIATE(r2, of_client_interface)
    ld  r2, 8(r2)
#endif
    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)

	/* restore ctr, cr and xer */

    PPC_LL  r2,  (STKOFF +  3 * ULONG_SIZE)(r1)
	mtctr	r2
    PPC_LL  r2,  (STKOFF +  4 * ULONG_SIZE)(r1)
	mtcr	r2
    PPC_LL  r2,  (STKOFF +  5 * 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)

	/* restore caller stack */

    PPC_LL  r1,  (STKOFF)(r1)

    PPC_LL  r4, PPC_LR_STKOFF(r1)
	mtlr	r4
    PPC_LL  r4, STKOFF(r1)
    PPC_LL  r1, 0(r1)

	blr

	/* rtas glue (must be reloctable) */
GLOBL(of_rtas_start):
	/* r3 = argument buffer, r4 = of_rtas_start */
	/* according to the CHRP standard, cr must be preserved (cr0/cr1 too?) */
	blr
GLOBL(of_rtas_end):


#define CACHE_LINE_SIZE         32
#define LG_CACHE_LINE_SIZE      5

/* flush_icache_range( unsigned long start, unsigned long stop) */
_GLOBAL(flush_icache_range):
        li      r5,CACHE_LINE_SIZE-1
        andc    r3,r3,r5
        subf    r4,r3,r4
        add     r4,r4,r5
        srwi.   r4,r4,LG_CACHE_LINE_SIZE
        beqlr
        mtctr   r4
        mr      r6,r3
1:      dcbst   0,r3
        addi    r3,r3,CACHE_LINE_SIZE
        bdnz    1b
        sync                            /* wait for dcbst's to get to ram */
        mtctr   r4
2:      icbi    0,r6
        addi    r6,r6,CACHE_LINE_SIZE
        bdnz    2b
        sync                            /* additional sync needed on g4 */
        isync
        blr

        /* Get RAM size from QEMU configuration device */

#define CFG_ADDR 0xf0000510
#define FW_CFG_RAM_SIZE         0x03

compute_ramsize:
        LOAD_REG_IMMEDIATE(r9, CFG_ADDR)
        li      r0,FW_CFG_RAM_SIZE
        sth     r0,0(r9)
        LOAD_REG_IMMEDIATE(r9, CFG_ADDR + 2)
        lbz     r1,0(r9)
        lbz     r0,0(r9)
        slwi    r0,r0,8
        or      r1,r1,r0
        lbz     r0,0(r9)
        slwi    r0,r0,16
        or      r1,r1,r0
        lbz     r0,0(r9)
        slwi    r0,r0,24
        or      r3,r1,r0
        blr

        /* Hard reset vector */
	.section .romentry,"ax"
	bl	_entry
