/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * General machine architecture & implementation specific * assembly language routines. */ #if defined(lint) #include #include #include #else /* lint */ #include "assym.h" #endif /* lint */ #include #include #include #include #include #if defined(lint) caddr_t set_trap_table(void) { return ((caddr_t)0); } #else /* lint */ ENTRY(set_trap_table) set trap_table, %o1 rdpr %tba, %o0 wrpr %o1, %tba retl wrpr %g0, WSTATE_KERN, %wstate SET_SIZE(set_trap_table) #endif /* lint */ #if defined(lint) /*ARGSUSED*/ void stphys(uint64_t physaddr, int value) {} /*ARGSUSED*/ int ldphys(uint64_t physaddr) { return (0); } /*ARGSUSED*/ void stdphys(uint64_t physaddr, uint64_t value) {} /*ARGSUSED*/ uint64_t lddphys(uint64_t physaddr) { return (0x0ull); } /* ARGSUSED */ void stphysio(u_longlong_t physaddr, uint_t value) {} /* ARGSUSED */ uint_t ldphysio(u_longlong_t physaddr) { return(0); } /* ARGSUSED */ void sthphysio(u_longlong_t physaddr, ushort_t value) {} /* ARGSUSED */ ushort_t ldhphysio(u_longlong_t physaddr) { return(0); } /* ARGSUSED */ void stbphysio(u_longlong_t physaddr, uchar_t value) {} /* ARGSUSED */ uchar_t ldbphysio(u_longlong_t physaddr) { return(0); } /*ARGSUSED*/ void stdphysio(u_longlong_t physaddr, u_longlong_t value) {} /*ARGSUSED*/ u_longlong_t lddphysio(u_longlong_t physaddr) { return (0ull); } #else ! Store long word value at physical address ! ! void stdphys(uint64_t physaddr, uint64_t value) ! ENTRY(stdphys) /* * disable interrupts, clear Address Mask to access 64 bit physaddr */ rdpr %pstate, %o4 andn %o4, PSTATE_IE | PSTATE_AM, %o5 wrpr %o5, 0, %pstate stxa %o1, [%o0]ASI_MEM retl wrpr %g0, %o4, %pstate ! restore earlier pstate register value SET_SIZE(stdphys) ! Store long word value at physical i/o address ! ! void stdphysio(u_longlong_t physaddr, u_longlong_t value) ! ENTRY(stdphysio) /* * disable interrupts, clear Address Mask to access 64 bit physaddr */ rdpr %pstate, %o4 andn %o4, PSTATE_IE | PSTATE_AM, %o5 wrpr %o5, 0, %pstate ! clear IE, AM bits stxa %o1, [%o0]ASI_IO retl wrpr %g0, %o4, %pstate ! restore earlier pstate register value SET_SIZE(stdphysio) ! ! Load long word value at physical address ! ! uint64_t lddphys(uint64_t physaddr) ! ENTRY(lddphys) rdpr %pstate, %o4 andn %o4, PSTATE_IE | PSTATE_AM, %o5 wrpr %o5, 0, %pstate ldxa [%o0]ASI_MEM, %o0 retl wrpr %g0, %o4, %pstate ! restore earlier pstate register value SET_SIZE(lddphys) ! ! Load long word value at physical i/o address ! ! unsigned long long lddphysio(u_longlong_t physaddr) ! ENTRY(lddphysio) rdpr %pstate, %o4 andn %o4, PSTATE_IE | PSTATE_AM, %o5 wrpr %o5, 0, %pstate ! clear IE, AM bits ldxa [%o0]ASI_IO, %o0 retl wrpr %g0, %o4, %pstate ! restore earlier pstate register value SET_SIZE(lddphysio) ! ! Store value at physical address ! ! void stphys(uint64_t physaddr, int value) ! ENTRY(stphys) rdpr %pstate, %o4 andn %o4, PSTATE_IE | PSTATE_AM, %o5 wrpr %o5, 0, %pstate sta %o1, [%o0]ASI_MEM retl wrpr %g0, %o4, %pstate ! restore earlier pstate register value SET_SIZE(stphys) ! ! load value at physical address ! ! int ldphys(uint64_t physaddr) ! ENTRY(ldphys) rdpr %pstate, %o4 andn %o4, PSTATE_IE | PSTATE_AM, %o5 wrpr %o5, 0, %pstate lda [%o0]ASI_MEM, %o0 srl %o0, 0, %o0 ! clear upper 32 bits retl wrpr %g0, %o4, %pstate ! restore earlier pstate register value SET_SIZE(ldphys) ! ! Store value into physical address in I/O space ! ! void stphysio(u_longlong_t physaddr, uint_t value) ! ENTRY_NP(stphysio) rdpr %pstate, %o4 /* read PSTATE reg */ andn %o4, PSTATE_IE | PSTATE_AM, %o5 wrpr %o5, 0, %pstate stwa %o1, [%o0]ASI_IO /* store value via bypass ASI */ retl wrpr %g0, %o4, %pstate /* restore the PSTATE */ SET_SIZE(stphysio) ! ! Store value into physical address in I/O space ! ! void sthphysio(u_longlong_t physaddr, ushort_t value) ! ENTRY_NP(sthphysio) rdpr %pstate, %o4 /* read PSTATE reg */ andn %o4, PSTATE_IE | PSTATE_AM, %o5 wrpr %o5, 0, %pstate stha %o1, [%o0]ASI_IO /* store value via bypass ASI */ retl wrpr %g0, %o4, %pstate /* restore the PSTATE */ SET_SIZE(sthphysio) ! ! Store value into one byte physical address in I/O space ! ! void stbphysio(u_longlong_t physaddr, uchar_t value) ! ENTRY_NP(stbphysio) rdpr %pstate, %o4 /* read PSTATE reg */ andn %o4, PSTATE_IE | PSTATE_AM, %o5 wrpr %o5, 0, %pstate stba %o1, [%o0]ASI_IO /* store byte via bypass ASI */ retl wrpr %g0, %o4, %pstate /* restore the PSTATE */ SET_SIZE(stbphysio) ! ! load value at physical address in I/O space ! ! uint_t ldphysio(u_longlong_t physaddr) ! ENTRY_NP(ldphysio) rdpr %pstate, %o4 /* read PSTATE reg */ andn %o4, PSTATE_IE | PSTATE_AM, %o5 wrpr %o5, 0, %pstate lduwa [%o0]ASI_IO, %o0 /* load value via bypass ASI */ retl wrpr %g0, %o4, %pstate /* restore pstate */ SET_SIZE(ldphysio) ! ! load value at physical address in I/O space ! ! ushort_t ldhphysio(u_longlong_t physaddr) ! ENTRY_NP(ldhphysio) rdpr %pstate, %o4 /* read PSTATE reg */ andn %o4, PSTATE_IE | PSTATE_AM, %o5 wrpr %o5, 0, %pstate lduha [%o0]ASI_IO, %o0 /* load value via bypass ASI */ retl wrpr %g0, %o4, %pstate /* restore pstate */ SET_SIZE(ldhphysio) ! ! load byte value at physical address in I/O space ! ! uchar_t ldbphysio(u_longlong_t physaddr) ! ENTRY_NP(ldbphysio) rdpr %pstate, %o4 /* read PSTATE reg */ andn %o4, PSTATE_IE | PSTATE_AM, %o5 wrpr %o5, 0, %pstate lduba [%o0]ASI_IO, %o0 /* load value via bypass ASI */ retl wrpr %g0, %o4, %pstate /* restore pstate */ SET_SIZE(ldbphysio) #endif /* lint */ /* * save_gsr(kfpu_t *fp) * Store the graphics status register */ #if defined(lint) || defined(__lint) /* ARGSUSED */ void save_gsr(kfpu_t *fp) {} #else /* lint */ ENTRY_NP(save_gsr) rd %gsr, %g2 ! save gsr retl stx %g2, [%o0 + FPU_GSR] SET_SIZE(save_gsr) #endif /* lint */ #if defined(lint) || defined(__lint) /* ARGSUSED */ void restore_gsr(kfpu_t *fp) {} #else /* lint */ ENTRY_NP(restore_gsr) ldx [%o0 + FPU_GSR], %g2 wr %g2, %g0, %gsr retl nop SET_SIZE(restore_gsr) #endif /* lint */ /* * uint64_t * _fp_read_pgsr() * Get the graphics status register info from fp and return it */ #if defined(lint) || defined(__lint) /* ARGSUSED */ uint64_t _fp_read_pgsr(kfpu_t *fp) { return 0; } #else /* lint */ ENTRY_NP(_fp_read_pgsr) retl rd %gsr, %o0 SET_SIZE(_fp_read_pgsr) #endif /* lint */ /* * uint64_t * get_gsr(kfpu_t *fp) * Get the graphics status register info from fp and return it */ #if defined(lint) || defined(__lint) /* ARGSUSED */ uint64_t get_gsr(kfpu_t *fp) { return 0; } #else /* lint */ ENTRY_NP(get_gsr) retl ldx [%o0 + FPU_GSR], %o0 SET_SIZE(get_gsr) #endif /* * _fp_write_pgsr(uint64_t *buf, kfpu_t *fp) * Set the graphics status register info to fp from buf */ #if defined(lint) || defined(__lint) /* ARGSUSED */ void _fp_write_pgsr(uint64_t buf, kfpu_t *fp) {} #else /* lint */ ENTRY_NP(_fp_write_pgsr) retl mov %o0, %gsr SET_SIZE(_fp_write_pgsr) #endif /* lint */ /* * set_gsr(uint64_t buf, kfpu_t *fp) * Set the graphics status register info to fp from buf */ #if defined(lint) || defined(__lint) /* ARGSUSED */ void set_gsr(uint64_t buf, kfpu_t *fp) {} #else /* lint */ ENTRY_NP(set_gsr) retl stx %o0, [%o1 + FPU_GSR] SET_SIZE(set_gsr) #endif /* lint */ #if defined(lint) || defined(__lint) void kdi_cpu_index(void) { } #else /* lint */ ENTRY_NP(kdi_cpu_index) CPU_INDEX(%g1, %g2) jmp %g7 nop SET_SIZE(kdi_cpu_index) #endif /* lint */ #if defined(lint) || defined(__lint) void kmdb_enter(void) { } #else /* lint */ ENTRY_NP(kmdb_enter) t ST_KMDB_TRAP retl nop SET_SIZE(kmdb_enter) #endif /* lint */ /* * The Spitfire floating point code has been changed not to use install/ * save/restore/fork/freectx() because of the special memcpy library * routines, which will lose too much performance if they have to go * through the fp_disabled trap (which used to call installctx()). So * now fp_save/fp_restore are called from resume, and they don't care * whether floating point was enabled from the user program via the * fp_enabled trap or from the memcpy library, which just turns on floating * point in the fprs register itself. The new routine lwp_freeregs is * called everywhere freectx is called, and code was added to the sun4u- * specific version of lwp_forkregs (which is called everywhere forkctx * is called) to handle forking the floating point registers. * * Note that for the fprs dirty upper/lower bits are not used for now, * because the #instructions to determine if we need to use them is probably * greater than the #insructions just using them. This is a possible future * optimization, only do it with very careful benchmarking! * * The fp_fksave and and fp_load were split into two routines for the * sake of efficiency between the getfpregs/xregs_getfpregs and * setfpregs/xregs_setfpregs. But note that for saving and restoring * context, both *must* happen. For prmachdep, aka access from [k]adb, * it's OK if only one part happens. */ /* * fp_save(kfpu_t *fp) * fp_fksave(kfpu_t *fp) * Store the floating point registers. */ #if defined(lint) || defined(__lint) /* ARGSUSED */ void fp_save(kfpu_t *fp) {} /* ARGSUSED */ void fp_fksave(kfpu_t *fp) {} #else /* lint */ ENTRY_NP(fp_save) ALTENTRY(fp_fksave) BSTORE_FPREGS(%o0, %o1) ! store V9 regs retl stx %fsr, [%o0 + FPU_FSR] ! store fsr SET_SIZE(fp_fksave) SET_SIZE(fp_save) #endif /* lint */ /* * fp_v8_fksave(kfpu_t *fp) * * This is like the above routine but only saves the lower half. */ #if defined(lint) || defined(__lint) /* ARGSUSED */ void fp_v8_fksave(kfpu_t *fp) {} #else /* lint */ ENTRY_NP(fp_v8_fksave) BSTORE_V8_FPREGS(%o0, %o1) ! store V8 regs retl stx %fsr, [%o0 + FPU_FSR] ! store fsr SET_SIZE(fp_v8_fksave) #endif /* lint */ /* * fp_v8p_fksave(kfpu_t *fp) * * This is like the above routine but only saves the upper half. */ #if defined(lint) || defined(__lint) /* ARGSUSED */ void fp_v8p_fksave(kfpu_t *fp) {} #else /* lint */ ENTRY_NP(fp_v8p_fksave) BSTORE_V8P_FPREGS(%o0, %o1) ! store V9 extra regs retl stx %fsr, [%o0 + FPU_FSR] ! store fsr SET_SIZE(fp_v8p_fksave) #endif /* lint */ /* * fp_restore(kfpu_t *fp) */ #if defined(lint) || defined(__lint) /* ARGSUSED */ void fp_restore(kfpu_t *fp) {} #else /* lint */ ENTRY_NP(fp_restore) BLOAD_FPREGS(%o0, %o1) ! load V9 regs retl ldx [%o0 + FPU_FSR], %fsr ! restore fsr SET_SIZE(fp_restore) #endif /* lint */ /* * fp_v8_load(kfpu_t *fp) */ #if defined(lint) || defined(__lint) /* ARGSUSED */ void fp_v8_load(kfpu_t *fp) {} #else /* lint */ ENTRY_NP(fp_v8_load) BLOAD_V8_FPREGS(%o0, %o1) ! load V8 regs retl ldx [%o0 + FPU_FSR], %fsr ! restore fsr SET_SIZE(fp_v8_load) #endif /* lint */ /* * fp_v8p_load(kfpu_t *fp) */ #if defined(lint) || defined(__lint) /* ARGSUSED */ void fp_v8p_load(kfpu_t *fp) {} #else /* lint */ ENTRY_NP(fp_v8p_load) BLOAD_V8P_FPREGS(%o0, %o1) ! load V9 extra regs retl ldx [%o0 + FPU_FSR], %fsr ! restore fsr SET_SIZE(fp_v8p_load) #endif /* lint */