/* $OpenBSD: ofwreal.S,v 1.3 2003/10/16 05:03:22 deraadt Exp $ */ /* $NetBSD: ofwreal.S,v 1.1 1996/09/30 16:34:51 ws Exp $ */ /* * Copyright (C) 1996 Wolfgang Solfrank. * Copyright (C) 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. */ /* * This file provides a real-mode client interface on machines, that * (incorrectly) only implement virtual mode client interface. * * It assumes though, that any actual memory in the machine is * mapped 1:1 even by the virtual mode OpenFirmware. * Furthermore it assumes that addresses returned by OpenFirmware are not * accessed by the client. * */ #include #include #include #include #define CACHELINE 32 /* Note that this value is really hardwired */ .data ofentry: .long 0 /* actual entry to firmware in virtual mode */ #define SRSIZE (16*4+4) #define SPRGSIZE (4*4) #define SDR1SIZE 4 #define MSRSIZE 4 #define SVSIZE (SRSIZE+SPRGSIZE+SDR1SIZE+MSRSIZE) #define BATSIZE (16*4) .global _C_LABEL(fwcall) _C_LABEL(fwcall): .long 0 .lcomm fwsave,SVSIZE,8 .lcomm fwbatsave,BATSIZE,8 .lcomm clsave,SVSIZE,8 .lcomm clbatsave,BATSIZE,8 .lcomm ofsrsave,16*4,4 /* 16 words of 4 bytes to store OF segment registers */ .lcomm srsave,16*4,4 /* 16 words of 4 bytes to swap OF segment registers*/ .globl _C_LABEL(ofmsr) _C_LABEL(ofmsr): .long 0 /* area to store msr for openfirmware*/ .text _ENTRY(_C_LABEL(ofw_init)) mflr %r31 /* save return address */ mr %r13,%r6 /* save args (only pointer used) */ lis %r8,ofentry@ha stw %r5,ofentry@l(%r8) /* save virtual mode firmware entry */ lis %r4,fwcall@ha /* call ofw directly until vm setup */ stw %r5,fwcall@l(%r4) mfmsr %r5 lis %r4,_C_LABEL(ofmsr)@ha /* save msr from openfirmware */ stw %r5,_C_LABEL(ofmsr)@l(%r4) #if 0 lis %r0,(0x80001ffe)@ha addi %r0,%r0,(0x80001ffe)@l mtdbatu 0,%r0 lis %r0,(0x80000022)@ha addi %r0,%r0,(0x80000022)@l mtdbatl 0,%r0 #endif lis %r3,fwsave@ha /* save the mmu values of the firmware */ addi %r3,%r3,fwsave@l lis %r4,fwbatsave@ha addi %r4,%r4,fwbatsave@l bl savemmu /* save openfirmware address mappings */ bl _C_LABEL(save_ofw_mapping) #if 0 /* dont really need the bats from firmware saved, 0 to disable */ lis %r3,fwbatsave@ha addi %r3,%r3,fwbatsave@l li %r4,64 li %r5,0 1: subi %r4,%r4,%r4 stwx %r5,%r4,%r3 cmpi 4,0,0 bne 1b #endif mr %r6,%r13 /* restore args pointer */ mtlr %r31 /* restore return address */ blr /* * Save everyting related to the mmu to the saveare pointed to by r3. */ .type savemmu,@function savemmu: mr %r6,%r4 /* r4 holds pointer to BAT save area */ li %r4,0 /* save SRs */ 1: addis %r4,%r4,-0x10000000@ha or. %r4,%r4,%r4 mfsrin %r5,%r4 stwu %r5,4(%r3) bne 1b mfibatl %r4,0 /* save BATs */ stw %r4,0(%r6) mfibatu %r4,0 stw %r4,4(%r6) mfibatl %r4,1 stw %r4,8(%r6) mfibatu %r4,1 stw %r4,0xc(%r6) mfibatl %r4,2 stw %r4,0x10(%r6) mfibatu %r4,2 stw %r4,0x14(%r6) mfibatl %r4,3 stw %r4,0x18(%r6) mfibatu %r4,3 stw %r4,0x1c(%r6) mfdbatl %r4,0 stw %r4,0x20(%r6) mfdbatu %r4,0 stw %r4,0x24(%r6) mfdbatl %r4,1 stw %r4,0x28(%r6) mfdbatu %r4,1 stw %r4,0x2c(%r6) mfdbatl %r4,2 stw %r4,0x30(%r6) mfdbatu %r4,2 stw %r4,0x34(%r6) mfdbatl %r4,3 stw %r4,0x38(%r6) mfdbatu %r4,3 stw %r4,0x3c(%r6) mfsprg %r4,0 /* save SPRGs */ stw %r4,4(%r3) mfsprg %r4,1 stw %r4,8(%r3) mfsprg %r4,2 stw %r4,12(%r3) mfsprg %r4,3 stw %r4,16(%r3) mfsdr1 %r4 /* save SDR1 */ stw %r4,20(%r3) addi %r4,%r3,24 mfmsr %r4 stw %r4,24(%r3) sync isync blr /* * Restore everyting related to the mmu from the savearea pointed to by r3. * and bats pointed to by r4. */ .type restoremmu,@function restoremmu: li %r0,0 mtmsr %r0 mr %r6,%r4 /* pointer to sr to restore */ li %r4,0 /* restore SRs */ 1: lwzu %r5,4(%r3) addis %r4,%r4,-0x10000000@ha or. %r4,%r4,%r4 mtsrin %r5,%r4 bne 1b mfmsr %r4 lis %r5,(PSL_IR|PSL_DR)@h /* turn off MMU */ ori %r5,%r5,(PSL_IR|PSL_DR)@l /* turn off MMU */ andc %r4,%r4,%r5 /* turn off MMU */ mtmsr %r4 isync li %r4,0 /* first, invalidate BATs */ mtibatu 0,%r4 mtibatu 1,%r4 mtibatu 2,%r4 mtibatu 3,%r4 mtdbatu 0,%r4 mtdbatu 1,%r4 mtdbatu 2,%r4 mtdbatu 3,%r4 lwz %r4,0(%r6) mtibatl 0,%r4 /* restore BATs */ lwz %r4,4(%r6) mtibatu 0,%r4 lwz %r4,8(%r6) mtibatl 1,%r4 lwz %r4,12(%r6) mtibatu 1,%r4 lwz %r4,16(%r6) mtibatl 2,%r4 lwz %r4,20(%r6) mtibatu 2,%r4 lwz %r4,24(%r6) mtibatl 3,%r4 lwz %r4,28(%r6) mtibatu 3,%r4 lwz %r4,32(%r6) mtdbatl 0,%r4 lwz %r4,36(%r6) mtdbatu 0,%r4 lwz %r4,40(%r6) mtdbatl 1,%r4 lwz %r4,44(%r6) mtdbatu 1,%r4 lwz %r4,48(%r6) mtdbatl 2,%r4 lwz %r4,52(%r6) mtdbatu 2,%r4 lwz %r4,56(%r6) mtdbatl 3,%r4 lwz %r4,60(%r6) mtdbatu 3,%r4 lwz %r4,4(%r3) mtsprg 0,4 /* restore SPRGs */ lwz %r4,8(%r3) mtsprg 1,4 lwz %r4,12(%r3) mtsprg 2,4 lwz %r4,16(%r3) mtsprg 3,4 sync /* remove everything from tlb */ lis %r4,0x40000@ha li %r5,0x1000 1: subf. %r4,%r5,%r4 tlbie %r4 bne 1b sync tlbsync sync lwz %r4,20(%r3) sync mtsdr1 %r4 /* restore SDR1 */ /* tlbia */ sync li %r5,0x40 mtctr %r5 li %r4,0 1: tlbie %r4 addi %r4,%r4,0x1000 bdnz 1b sync tlbsync sync lwz %r4,24(%r3) mtmsr %r4 isync blr _ENTRY(_C_LABEL(fwentry)) stwu %r1,-16(%r1) mflr %r4 stw %r4,20(%r1) stw %r3,12(%r1) /* save arg */ lis %r3,clsave@ha /* save mmu values of client */ addi %r3,%r3,clsave@l lis %r4,clbatsave@ha /* save mmu values of client */ addi %r4,%r4,clbatsave@l bl savemmu lis %r3,fwsave@ha /* restore mmu values of firmware */ addi %r3,%r3,fwsave@l lis %r4,fwbatsave@ha addi %r4,%r4,fwbatsave@l bl restoremmu lis %r3,ofentry@ha lwz %r3,ofentry@l(%r3) /* get actual firmware entry */ mtlr %r3 mfmsr %r4 ori %r4,%r4,PSL_IR|PSL_DR /* turn on MMU */ mtmsr %r4 isync lwz %r3,12(%r1) /* restore arg */ blrl /* do actual firmware call */ stw %r3,12(%r1) /* save return value */ lis %r3,fwsave@ha /* save mmu values of firmare */ addi %r3,%r3,fwsave@l /* (might not be necessary, but... */ lis %r4,fwbatsave@ha addi %r4,%r4,fwbatsave@l bl savemmu lis %r3,clsave@ha /* restore mmu values of client */ addi %r3,%r3,clsave@l lis %r4,clbatsave@ha /* save mmu values of client */ addi %r4,%r4,clbatsave@l bl restoremmu lwz %r4,20(%r1) lwz %r3,12(%r1) /* restore return value */ mtlr %r4 addi %r1,%r1,16 blr /* * OpenFirmware entry point */ _ENTRY(_C_LABEL(openfirmware)) stwu %r1,-16(%r1) mflr %r0 /* save return address */ stw %r0,20(%r1) lis %r4,fwcall@ha lwz %r4,fwcall@l(%r4) mtlr %r4 blrl lwz %r0,20(%r1) mtlr %r0 lwz %r1,0(%r1) 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; * } */ .lcomm firmstk,NBPG,16 .comm _C_LABEL(OF_buf),NBPG,PGOFSET _ENTRY(_C_LABEL(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 li %r6,0xf andc %r7,%r7,%r6 lis %r6,ofw_back@ha addi %r6,%r6,ofw_back@l subf %r4,%r5,%r7 /* make room for stack frame on new stack */ stwu %r1,-16(%r7) stw %r6,4(%r7) /* setup return pointer */ stw %r7,-16(%r4) addi %r3,%r1,%r8 addi %r1,%r4,-16 subi %r5,%r5,%r8 subi %r4,%r4,%r8 b _C_LABEL(ofbcopy) /* and copy it */ .type ofw_back,@function 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