NetBSD-5.0.2/sys/arch/powerpc/oea/ofw_subr.S
/* $NetBSD: ofw_subr.S,v 1.8 2008/04/08 02:33:03 garbled Exp $ */
/*
* Copyright (C) 1995, 1996 Wolfgang Solfrank.
* Copyright (C) 1995, 1996 TooLs GmbH.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by TooLs GmbH.
* 4. The name of TooLs GmbH may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
.local firmstk
.globl openfirmware_entry
.local ofwsrsave
.local OF_buffer
.data
GLOBAL(ofmsr)
.long 0,0,0,0,0 /* msr & sprg[0-3] used in OF */
GLOBAL(ofwsprg0save)
.long 0
GLOBAL(ofwreal_incharge)
.long 0
.comm firmstk,NBPG,8
.comm OF_buffer,NBPG,4
.comm openfirmware_entry,4,4 /* openfirmware entry point */
.comm ofwsrsave,64,4 /* openfirmware SR savearea */
/*
* Called by start to save the initial OFW state so we can restore it
* when call back to OFW.
*/
ENTRY_NOPROFILE(ofwinit)
#ifdef FIRMWORKSBUGS
mfmsr %r0
andi. %r0,%r0,PSL_IR|PSL_DR
beq 1f
li %r8,1
lis %r9,ofwreal_incharge@ha
stw %r8,ofwreal_incharge@l(9)
mflr %r30
bl _C_LABEL(ofwr_init)
mtlr %r30
1:
#endif
lis %r8,openfirmware_entry@ha
stw %r5,openfirmware_entry@l(%r8) /* save client interface handler*/
mfmsr %r0
lis %r9,ofmsr@ha
stwu %r0,ofmsr@l(%r9) /* save initial MSR value */
mfsprg %r0,0 /* save SPRGs */
stwu %r0,4(%r9)
mfsprg %r0,1
stwu %r0,4(%r9)
mfsprg %r0,2
stwu %r0,4(%r9)
mfsprg %r0,3
stw %r0,4(%r9)
lis %r8,OF_buffer@ha
addi %r8,%r8,OF_buffer@l
lis %r9,_C_LABEL(OF_buf)@ha
stw %r8,_C_LABEL(OF_buf)@l(%r9)
blr
/*
* OpenFirmware entry point
*/
.text
ENTRY(openfirmware)
mflr %r0 /* save return address */
stw %r0,4(%r1)
stwu %r1,-16(%r1) /* setup stack frame */
lis %r4,openfirmware_entry@ha /* get firmware entry point */
lwz %r4,openfirmware_entry@l(%r4)
mtlr %r4
mfsprg %r5,0 /* save current sprg0 (curcpu) */
lis %r4,ofwsprg0save@ha
addi %r4,%r4,ofwsprg0save@l
stw %r5,0(%r4)
#ifdef FIRMWORKSBUGS
lis %r4,ofwreal_incharge@ha
lwz %r4,ofwreal_incharge@l(%r4)
cmpwi %r4,1
bne 1f
blrl
b 4f
1:
#endif
mfmsr %r4 /* save msr */
stw %r4,8(%r1)
li %r0,0 /* clear battable translations */
mtmsr %r0
#if defined (PPC_OEA) || defined (PPC_OEA64_BRIDGE)
mtdbatu 2,%r0
mtdbatu 3,%r0
mtibatu 2,%r0
mtibatu 3,%r0
#endif /* PPC_OEA */
lis %r4,ofwsrsave@ha /* save current SRs */
addi %r4,%r4,ofwsrsave@l
li %r5,0
1: mfsrin %r0,%r5
stw %r0,0(%r4)
addi %r4,%r4,4
addis %r5,%r5,0x10000000@h
cmpwi %r5,0
bne 1b
lis %r4,_C_LABEL(ofw_pmap)@ha /* load OFW SR */
addi %r4,%r4,_C_LABEL(ofw_pmap)@l
lwz %r0,PM_KERNELSR(%r4)
cmpwi %r0,0 /* pm_sr[KERNEL_SR] == 0? */
beq 2f /* then skip (not initialized yet) */
li %r5,0
1: lwz %r0,0(%r4)
mtsrin %r0,%r5
addi %r4,%r4,4
addis %r5,%r5,0x10000000@h
cmpwi %r5,0
bne 1b
2:
lis %r4,ofmsr@ha /* Open Firmware msr + sprg[0-3] */
lwzu %r5,ofmsr+16@l(%r4)
mtsprg 3,%r5
lwzu %r5,-4(%r4)
mtsprg 2,%r5
lwzu %r5,-4(%r4)
mtsprg 1,%r5
lwzu %r5,-4(%r4)
mtsprg 0,%r5
lwz %r5,-4(%r4)
mtmsr %r5
isync
blrl /* call Open Firmware */
lis %r4,ofwsrsave@ha /* restore saved SRs */
addi %r4,%r4,ofwsrsave@l
li %r5,0
1: lwz %r0,0(%r4)
mtsrin %r0,%r5
addi %r4,%r4,4
addis %r5,%r5,0x10000000@h
cmpwi %r5,0
bne 1b
lwz %r4,8(%r1) /* restore msr */
mtmsr %r4
isync
4:
lis %r4,ofwsprg0save@ha /* restore saved sprg0 (curcpu) */
addi %r4,%r4,ofwsprg0save@l
lwz %r5,0(%r4)
mtsprg 0,%r5
lwz %r1,0(%r1) /* and return */
lwz %r0,4(%r1)
mtlr %r0
blr
/*
* Switch to/from OpenFirmware real mode stack
*
* Note: has to be called as the very first thing in OpenFirmware interface
* routines.
* E.g.:
* int
* OF_xxx(arg1, arg2)
* type arg1, arg2;
* {
* static struct {
* char *name;
* int nargs;
* int nreturns;
* char *method;
* int arg1;
* int arg2;
* int ret;
* } args = {
* "xxx",
* 2,
* 1,
* };
*
* ofw_stack();
* args.arg1 = arg1;
* args.arg2 = arg2;
* if (openfirmware(&args) < 0)
* return -1;
* return args.ret;
* }
*/
ENTRY(ofw_stack)
mfmsr %r8 /* turn off interrupts */
andi. %r0,%r8,~(PSL_EE|PSL_RI)@l
mtmsr %r0
stw %r8,4(%r1) /* abuse return address slot */
lwz %r5,0(%r1) /* get length of stack frame */
subf %r5,%r1,%r5
lis %r7,firmstk+NBPG-8@ha
addi %r7,%r7,firmstk+NBPG-8@l
lis %r6,ofw_back@ha
addi %r6,%r6,ofw_back@l
subf %r4,%r5,%r7 /* make room for stack frame on
new stack */
stw %r6,-4(%r7) /* setup return pointer */
stwu %r1,-8(%r7)
stw %r7,-8(%r4)
addi %r3,%r1,8
addi %r1,%r4,-8
subi %r5,%r5,8
b _C_LABEL(ofbcopy) /* and copy it */
ofw_back:
lwz %r1,0(%r1) /* get callers original stack pointer */
lwz %r0,4(%r1) /* get saved msr from abused slot */
mtmsr %r0
lwz %r1,0(%r1) /* return */
lwz %r0,4(%r1)
mtlr %r0
blr