/******************************************************************************
 * Copyright (c) 2004, 2008 IBM Corporation
 * All rights reserved.
 * This program and the accompanying materials
 * are made available under the terms of the BSD License
 * which accompanies this distribution, and is available at
 * http://www.opensource.org/licenses/bsd-license.php
 *
 * Contributors:
 *     IBM Corporation - initial implementation
 *****************************************************************************/

#include <macros.h>

#define STACKSIZE 0x2000

	#
	# The generic exception code.
	#
	# Enter with GPR0 = vector, SPRG0 = saved GPR0
	#

	.section ".entry_text"

the_handler:
	.quad	handler

eregs:
	/* the_exception_frame is a C variable which is usually
	 * defined in $(TARG).c
	 * the_exception_frame can be accessed from paflof through
	 * the word eregs
	 * in the case an excpetion is handled paflof will read
	 * from eregs the values of all registers and print them
	 * out in the exception handler */
	.quad	the_exception_frame

handler:
	mtsprg 1,1	# SPRG1 = saved GPR1
	bcl 20,31,$+4
	mflr 1
	ld 1,eregs-$+4(1)	# GPR1 = address of register save area

	.irp i, 2,3,4,5,6,7,8,9,10,11,12,13,14,15, \
		16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
	std \i,\i*8(1)
	.endr		# save GPR2..GPR31

	li r3, 3        // GPR3 = mode (param_1, param_2)
	mr 4,0		// GPR4 = vector

	mfsprg 0,0
	std 0,0(1)	# save GPR0
	mfsprg 0,1
	std 0,8(1)	# save GPR1

	cmpwi	r4, 0x900	# Decrementer interrupt
	bne	0f
	mfdec	r5		# Save old value of decrementer as reason
	lis	r0,0x7fff	# Set decrementer to highest value 
	mtdec	r0
0:
	mfcr 0
	std 0,0x100(1)
	mfxer 0
	std 0,0x108(1)
	mfsprg 0,3	# save lr	
	std 0,0x110(1)
	mfsprg 0,2	# save ctr	
	std 0,0x118(1)
	mfsrr0 0
	std 0,0x120(1)
	mfsrr1 0
	std 0,0x128(1)
	mfdar 0
	std 0,0x130(1)
	mfdsisr 0
	std 0,0x138(1)	# save special regs

	bcl	20, 31, over
base:
	.align	3
.the_system_stack:
	.quad   the_system_stack+STACKSIZE-base
over:
	mflr	r2				/* gpr 2 is the base */
	ld	r1, .the_system_stack-base(r2)	/* load stack pointer */
	add	r1, r1, r2			/* add base */
	li	r0, 0
	stdu	r0, -0x10(r1)
	stdu	r1, -0x100(r1)

	lis 2,engine@ha
	ld 0,engine@l(2) # set up entry
	mtsrr0	0
		
	ld 2,8+engine@l(2) # set up TOC pointer

	rfid
#	b .engine	# ...and run!



	#
	# Swap non-volatile client interface regs, plus GPR3..GPR7.
	#

swap_ci_regs:
	/* save lr */
	mflr	r0
	/* let's find out where our client stack is */
	bcl	20, 31, client_over
client_base:
	.align	3
.the_client_frame:
	.quad   the_client_frame-client_base
client_over:
	mflr	r8				/* gpr 2 is the client_base */
	mtlr	r0				/* restore the original lr */
	ld	r0, .the_client_frame-client_base(r8)
	add	r8, r0, r8			/* add the client_base */
	/* r8 now contains the address of the_client_frame */

	.irp i, 1,2,3,4,5,6,7, \
		13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
	ld 0,\i*8(8)
	std \i,\i*8(8)
	mr \i,0
	.endr		# swap GPR1..7, GPR13..31

	ld 0,0x100(8)
	mfcr 9
	mtcrf 0xff,0
	std 9,0x100(8)	# swap CR

	ld 0,0x128(8)
	mfmsr 9
	mtmsrd 0
	sync
	isync
	std 9,0x128(8)	# swap MSR

	blr

	#
	# Entry point for the OF client interface.
	#

        .globl client_entry_point
        .section        ".opd","aw"
        .align 3
client_entry_point:
        .quad   .client_entry_point,.TOC.@tocbase,0
        .previous
        .type   .client_entry_point,@function
        .globl  .client_entry_point
.client_entry_point:
	mflr 4
	bl swap_ci_regs	# swap regs
	mtlr 4
	li 3, 0 # client call
	blr	

	#
	# Start the client.
	#

        .globl call_client
        .section        ".opd","aw"
        .align 3
call_client:
        .quad   .call_client,.TOC.@tocbase,0
        .previous
        .type   .call_client,@function
        .globl  .call_client

.call_client:	# called with r3 = address, returns r3
	mflr 4
	mtctr 3
	bl swap_ci_regs
	/* Check if LE loading */
	cmpwi 0,13,1
	beq 0f
	bctrl
	b 1f
0:	/* handle LE */
	mfmsr 13
	xori  13,13,1
	mtsrr1 13
	mfctr 13
	mr 12,13
	mtsrr0 13
	rfid
#if 0 /* in case we return back, still to be tested */
	.long 0x05009f42; /* bcl 20,31,$+4   */
	.long 0xa602c87d; /* mflr r14    */
	.long 0x1c00ce39; /* addi r14,r14,28   */
	.long 0xa600e07d; /* mfmsr r15    */
	.long 0x0100ef69; /* xori r15,r15,1   */
	.long 0xa603da7d; /* mtsrr0 r14    */
	.long 0xa603fb7d; /* mtsrr1 r15    */
	.long 0x2400004c; /* rfid */
#endif
1:
	bl swap_ci_regs
	mtlr 4
	li 3, -1 # client app return
	blr


	# Call another function via pointer in r6
	# (arguments can be provided in r3 to r5)
	# Destination function should jump back to lr
C_ENTRY(call_c)
	mtctr	r6
	bctr

.global the_system_stack
	.lcomm	the_system_stack, STACKSIZE, 16
