/*
* Copyright 1991-1998 by Open Software Foundation, Inc.
* All Rights Reserved
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appears in all copies and
* that both the copyright notice and this permission notice appear in
* supporting documentation.
*
* OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE.
*
* IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
* NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* MkLinux
*/
#include <mach_kdb.h>
#include <mach_kgdb.h>
#include <mach_debug.h>
#include <assym.S>
#include <ppc/asm.h>
#include <ppc/proc_reg.h>
#include <mach/ppc/vm_param.h>
#include <ppc/POWERMAC/powermac.h>
/*
* vm_offset_t getrpc(void) - Return address of the function
* that called the current function
*/
/* By using this function, we force the caller to save its LR in a known
* location, which we can pick up and return. See PowerPC ELF specs.
*/
ENTRY(getrpc, TAG_NO_FRAME_USED)
lwz ARG0, FM_BACKPTR(r1) /* Load our backchain ptr */
lwz ARG0, FM_LR_SAVE(ARG0) /* Load previously saved LR */
blr /* And return */
/* Mask and unmask interrupts at the processor level */
ENTRY(interrupt_disable, TAG_NO_FRAME_USED)
mfmsr r0
rlwinm r0, r0, 0, MSR_EE_BIT+1, MSR_EE_BIT-1
mtmsr r0
blr
ENTRY(interrupt_enable, TAG_NO_FRAME_USED)
li r0, 0 /* Ensure R0 is 0 on 601 for sync */
cmpwi r0, 0
bne+ 0f
sync /* Flush any outstanding writes */
0:
mfmsr r0
ori r0, r0, MASK(MSR_EE)
mtmsr r0
isync
blr
#if MACH_KDB
/*
* Kernel debugger versions of the spl*() functions. This allows breakpoints
* in the spl*() functions.
*/
/* Mask and unmask interrupts at the processor level */
ENTRY(db_interrupt_disable, TAG_NO_FRAME_USED)
mfmsr r0
rlwinm r0, r0, 0, MSR_EE_BIT+1, MSR_EE_BIT-1
mtmsr r0
isync
blr
ENTRY(db_interrupt_enable, TAG_NO_FRAME_USED)
mfmsr r0
ori r0, r0, MASK(MSR_EE)
isync
sync /* Flush any outstanding writes */
mtmsr r0
isync
blr
#endif /* MACH_KDB */
#if MACH_KGDB
/* void call_kgdb_with_ctx(int type, int code, struct ppc_saved_state *ssp)
*
* Switch stacks to the kgdb stack, enter the debugger. On return,
* switch back to the previous stack
*
* If the kgdb stack is not free, we allocate ourselves a frame below
* the current kgdb frame. This should never occur in a perfect world.
*/
ENTRY(call_kgdb_with_ctx, TAG_NO_FRAME_USED)
/* Switch off interrupts */
li r0, MSR_SUPERVISOR_INT_OFF
mtmsr r0
isync
/* Save the link register in the caller's space */
mflr r0
stw r0, FM_LR_SAVE(r1)
/* Find the gdb stack and move on to it */
lwz r9, PP_GDBSTACKPTR(r2)
cmpwi r9, 0
bne 0f
/* The stack wasn't free - oops! recover old sp and allocate space */
lwz r9, SS_R1(ARG2) /* r9 holds stack ptr of trapped */
/* Make room for our saved state structure */
subi r9, r9, FM_REDZONE + SS_SIZE
0:
/* Here, r9 points to a valid kgdb stack address with a
* saved state structure above it, which we only use for r1
*/
stw r1, SS_R1(r9) /* Store old stack pointer */
li r0, 0
stw r0, PP_GDBSTACKPTR(r2) /* Mark gdb stack as busy */
/* Move to new stack, making room for a dummy frame */
subi r1, r9, FM_SIZE
stw r0, FM_BACKPTR(r1)
/* Call debugger */
bl EXT(kgdb_trap)
/* Ok, back from C.
*/
li r0, MSR_SUPERVISOR_INT_OFF
mtmsr r0
isync
addi r1, r1, FM_SIZE
/* Is this the first frame on the stack? */
lwz r4, PP_GDBSTACKPTR(r2)
cmp CR0, r4, r1
bne CR0, 0f
/* We are the last frame, mark stack as free */
stw r1, PP_GDBSTACKPTR(r2) /* Mark gdb stack as free */
/* Switch onto old stack and recover old lr before returning */
0:
lwz r1, SS_R1(r1)
lwz r0, FM_LR_SAVE(r1)
mtlr r0
blr
#endif /* MACH_KGDB */
/* The following routines are for C-support. They are usually
* inlined into the C using the specifications in proc_reg.h,
* but if optimisation is switched off, the inlining doesn't work
*/
ENTRY(get_got, TAG_NO_FRAME_USED)
mr ARG0, r2
blr
ENTRY(mflr, TAG_NO_FRAME_USED)
mflr ARG0
blr
ENTRY(mfpvr, TAG_NO_FRAME_USED)
mfpvr ARG0
blr
ENTRY(mtmsr, TAG_NO_FRAME_USED)
mtmsr ARG0
isync
blr
ENTRY(mfmsr, TAG_NO_FRAME_USED)
mfmsr ARG0
blr
ENTRY(mtsrin, TAG_NO_FRAME_USED)
isync
mtsrin ARG0, ARG1
isync
blr
ENTRY(mfsrin, TAG_NO_FRAME_USED)
mfsrin ARG0, ARG0
blr
ENTRY(mtsdr1, TAG_NO_FRAME_USED)
mtsdr1 ARG0
blr
ENTRY(mtdar, TAG_NO_FRAME_USED)
mtdar ARG0
blr
ENTRY(mfdar, TAG_NO_FRAME_USED)
mfdar ARG0
blr
ENTRY(mtdec, TAG_NO_FRAME_USED)
mtdec ARG0
blr
ENTRY(reloc_offset, TAG_NO_FRAME_USED)
mflr r0
bl 1f
1: mflr r3
lis r4,1b@ha
addi r4,r4,1b@l
subf r3,r4,r3
mtlr r0
blr
/* Decrementer frequency and realtime|timebase processor registers
* are different between ppc601 and ppc603/4, we define them all.
*/
ENTRY(isync_mfdec, TAG_NO_FRAME_USED)
isync
mfdec ARG0
blr
ENTRY(mftb, TAG_NO_FRAME_USED)
mftb ARG0
blr
ENTRY(mftbu, TAG_NO_FRAME_USED)
mftbu ARG0
blr
ENTRY(mfrtcl, TAG_NO_FRAME_USED)
mfspr ARG0, 5
blr
ENTRY(mfrtcu, TAG_NO_FRAME_USED)
mfspr ARG0, 4
blr
ENTRY(tlbie, TAG_NO_FRAME_USED)
tlbie ARG0
blr