common_asm.s revision 023e71de9e5670cebc23dd51162833661d3d2d3b
/*
* 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
* 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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#if !defined(lint)
#include "assym.h"
#endif
/*
* General assembly language routines.
* It is the intent of this file to contain routines that are
* specific to cpu architecture.
*/
/*
* WARNING: If you add a fast trap handler which can be invoked by a
* non-privileged user, you may have to use the FAST_TRAP_DONE macro
* instead of "done" instruction to return back to the user mode. See
* comments for the "fast_trap_done" entry point for more information.
*/
#define FAST_TRAP_DONE \
#include <sys/machclock.h>
#if defined(lint)
#include <sys/lockstat.h>
#endif /* lint */
#include <sys/asm_linkage.h>
#include <sys/privregs.h>
#include <vm/hat_sfmmu.h>
#include <sys/machthread.h>
#include <sys/psr_compat.h>
#include <sys/isa_defs.h>
#include <sys/dditypes.h>
#include <sys/hypervisor_api.h>
#if !defined(lint)
#include "assym.h"
#endif
#define ICACHE_FLUSHSZ 0x20
#if defined(lint)
/*
* Softint generated when counter field of tick reg matches value field
* of tick_cmpr reg
*/
/*ARGSUSED*/
void
{}
#else /* lint */
1:
! future.
2:
#endif /* lint */
#if defined(lint)
void
tickcmpr_disable(void)
{}
#else
#endif
#if defined(lint)
/*
* tick_write_delta() increments %tick by the specified delta. This should
* only be called after a CPR event to assure that gethrtime() continues to
* increase monotonically. Obviously, writing %tick needs to de done very
* carefully to avoid introducing unnecessary %tick skew across CPUs. For
* this reason, we make sure we're i-cache hot before actually writing to
* %tick.
*
* NOTE: No provision for this on sun4v right now.
*/
/*ARGSUSED*/
void
{}
#else /* lint */
.seg ".text"
.asciz "tick_write_delta: not supported"
/*NOTREACHED*/
#endif
#if defined(lint)
/*
* return 1 if disabled
*/
int
tickcmpr_disabled(void)
{ return (0); }
#else /* lint */
#endif /* lint */
/*
* Get current tick
*/
#if defined(lint)
gettick(void)
{ return (0); }
#else /* lint */
#endif /* lint */
/*
* Get current tick. For trapstat use only.
*/
#if defined (lint)
rdtick()
{ return (0); }
#else
#endif /* lint */
/*
* Return the counter portion of the tick register.
*/
#if defined(lint)
gettick_counter(void)
{ return(0); }
gettick_npt(void)
{ return(0); }
getstick_npt(void)
{ return(0); }
#else /* lint */
#endif /* lint */
/*
* Provide a C callable interface to the trap that reads the hi-res timer.
* Returns 64-bit nanosecond timestamp in %o0 and %o1.
*/
#if defined(lint)
gethrtime(void)
{
return ((hrtime_t)0);
}
gethrtime_unscaled(void)
{
return ((hrtime_t)0);
}
gethrtime_max(void)
{
return ((hrtime_t)0);
}
void
{
*hrt = 0;
}
void
{
}
gethrestime_sec(void)
{
return (0);
}
void
{
}
/*ARGSUSED*/
void
hres_tick(void)
{
}
void
panic_hres_tick(void)
{
}
#else /* lint */
! hrtime_t's are signed, max hrtime_t must be positive
mov -1, %o2
brlz,a %g1, 1f
srlx %o2, 1, %g1
1:
retl
mov %g1, %o0
SET_SIZE(gethrtime_max)
ENTRY(scalehrtime)
ldx [%o0], %o1
NATIVE_TIME_TO_NSEC(%o1, %o2, %o3)
retl
stx %o1, [%o0]
SET_SIZE(scalehrtime)
/*
* Fast trap to return a timestamp, uses trap window, leaves traps
* disabled. Returns a 64-bit nanosecond timestamp in %o0 and %o1.
*
* This is the handler for the ST_GETHRTIME trap.
*/
ENTRY_NP(get_timestamp)
GET_HRTIME(%g1,%g2,%g3,%g4,%g5,%o0,%o1,%o2,__LINE__)
! %g1 = hrtime
srlx %g1, 32, %o0 ! %o0 = hi32(%g1)
srl %g1, 0, %o1 ! %o1 = lo32(%g1)
FAST_TRAP_DONE
SET_SIZE(get_timestamp)
/*
* Macro to convert GET_HRESTIME() bits into a timestamp.
*
* We use two separate macros so that the platform-dependent GET_HRESTIME()
* can be as small as possible; CONV_HRESTIME() implements the generic part.
*/
#define CONV_HRESTIME(hrestsec, hrestnsec, adj, nslt, nano) \
brz,pt adj, 3f; /* no adjustments, it's easy */ \
nop; /* delay: do nothing :( */ \
4:
/*
* Similar to gethrestime(), but gethrestime_sec() returns current hrestime
* seconds.
*/
/*
* Returns the hrestime on the last tick. This is simpler than gethrestime()
* and gethrestime_sec(): no conversion is required. gethrestime_lasttick()
* follows the same locking algorithm as GET_HRESTIME and GET_HRTIME,
* outlined in detail in clock.h. (Unlike GET_HRESTIME/GET_HRTIME, we don't
* rely on load dependencies to effect the membar #LoadLoad, instead declaring
* it explicitly.)
*/
0:
/*
* Fast trap for gettimeofday(). Returns a timestruc_t in %o0 and %o1.
*
* This is the handler for the ST_GETHRESTIME trap.
*/
/*
* Fast trap to return lwp virtual time, uses trap window, leaves traps
* disabled. Returns a 64-bit number in %o0:%o1, which is the number
* of nanoseconds consumed.
*
* This is the handler for the ST_GETHRVTIME trap.
*
* Register usage:
* %o0, %o1 = return lwp virtual time
* %o3 = lwp
* %g1 = scratch
* %g5 = scratch
*/
/*
* Subtract start time of current microstate from time
* of day to get increment for lwp virtual time.
*/
/*
* Add current value of ms_acct[LMS_USER]
*/
.seg ".text"
.asciz "hrtime_base stepping back"
8:
!
!
!
!
! hrestime_adj == 0 ?
1:
2:
5:
9:
!
!
#endif /* lint */
.seg ".text"
.asciz "kstat_q_exit: qlen == 0"
/*NOTREACHED*/
QRETURN; \
.align 16
.align 16
.align 16
.align 16
.align 16
.align 16
#endif /* lint */
#ifdef lint
volatile timestruc_t hrestime;
volatile int hres_lock;
int traptrace_use_stick;
#else
/*
* -- WARNING --
*
* The following variables MUST be together on a 128-byte boundary.
* In addition to the primary performance motivation (having them all
* on the same cache line(s)), code here and in the GET*TIME() macros
* assumes that they all have the same high 22 address bits (so
* there's only one sethi).
*/
.seg ".data"
/* XXX - above comment claims 128-bytes is necessary */
.align 64
.word 0, 0 /* int64_t */
.word 0, 0 /* hrtime_t */
.nword 0, 0 /* 2 longs */
.word 0, 0 /* int64_t */
.word 0
.word 0
.word 0, 0
.word 0
.align 8
.word 0, 0
.align 8
.word 0, 0
#endif
/*
* usec_delay(int n) [compatibility - should go one day]
* Delay by spinning.
*
* delay for n microseconds. numbers <= 0 delay 1 usec
*
* With UltraSPARC-III the combination of supporting mixed-speed CPUs
* and variable clock rate for power management requires that we
* use %stick to implement this routine.
*/
#if defined(lint)
/*ARGSUSED*/
void
{}
/*ARGSUSED*/
void
usec_delay(int n)
{}
#else /* lint */
0:
GET_NATIVE_TIME(%o2,%o3,%o4,__LINE__)
add %o1, %o2, %o1
1: cmp %o1, %o2
GET_NATIVE_TIME(%o2,%o3,%o4,__LINE__)
bgeu,pt %xcc, 1b
nop
retl
nop
SET_SIZE(usec_delay)
SET_SIZE(drv_usecwait)
#endif /* lint */
#if defined(lint)
/* ARGSUSED */
void
pil14_interrupt(int level)
{}
#else
/*
* Level-14 interrupt prologue.
*/
ENTRY_NP(pil14_interrupt)
CPU_ADDR(%g1, %g2)
rdpr %pil, %g6 ! %g6 = interrupted PIL
stn %g6, [%g1 + CPU_PROFILE_PIL] ! record interrupted PIL
rdpr %tstate, %g6
rdpr %tpc, %g5
btst TSTATE_PRIV, %g6 ! trap from supervisor mode?
bnz,a,pt %xcc, 1f
stn %g5, [%g1 + CPU_PROFILE_PC] ! if so, record kernel PC
stn %g5, [%g1 + CPU_PROFILE_UPC] ! if not, record user PC
ba pil_interrupt_common ! must be large-disp branch
stn %g0, [%g1 + CPU_PROFILE_PC] ! zero kernel PC
1: ba pil_interrupt_common ! must be large-disp branch
stn %g0, [%g1 + CPU_PROFILE_UPC] ! zero user PC
SET_SIZE(pil14_interrupt)
ENTRY_NP(tick_rtt)
!
! Load TICK_COMPARE into %o5; if bit 63 is set, then TICK_COMPARE is
! disabled. If TICK_COMPARE is enabled, we know that we need to
! interrupt. In this case, TICK_COMPARE may have been rewritten
! in the future.
!
! Note that %o5 is live until after 1f.
! XXX - there is a subroutine call while %o5 is live!
!
RD_TICKCMPR(%o5,%g1,%g2,__LINE__)
srlx %o5, TICKINT_DIS_SHFT, %g1
brnz,pt %g1, 2f
nop
rdpr %pstate, %g5
andn %g5, PSTATE_IE, %g1
wrpr %g0, %g1, %pstate ! Disable vec interrupts
sethi %hi(cbe_level14_inum), %o1
ldx [%o1 + %lo(cbe_level14_inum)], %o1
call intr_enqueue_req ! preserves %o5 and %g5
mov PIL_14, %o0
rd SOFTINT, %o4
set (TICK_INT_MASK | STICK_INT_MASK), %o0
andcc %o4, %o0, %g0
bz,a,pn %icc, 2f
wrpr %g0, %g5, %pstate ! Enable vec interrupts
wr %o0, CLEAR_SOFTINT
!
! we need to reprogram TICK_COMPARE to fire as soon as possible.
!
GET_NATIVE_TIME(%o0,%g1,%g2,__LINE__) ! %o0 = tick
cmp %o5, %o0 ! In the future?
bg,a,pt %xcc, 2f ! Yes, drive on.
wrpr %g0, %g5, %pstate ! delay: enable vec intr
!
!
#endif /* lint */
#if defined(lint)
/* ARGSUSED */
void
pil15_interrupt(int level)
{}
#else /* lint */
/*
* Level-15 interrupt prologue.
*/
#endif /* lint */
#if defined(lint)
/*
* Prefetch a page_t for write or read, this assumes a linear
* scan of sequential page_t's.
*/
/*ARGSUSED*/
void
prefetch_page_w(void *pp)
{}
/*ARGSUSED*/
void
prefetch_page_r(void *pp)
{}
#else /* lint */
/* XXXQ These should be inline templates, not functions */
#endif /* lint */
#if defined(lint)
/*
* Prefetch struct smap for write.
*/
/*ARGSUSED*/
void
prefetch_smap_w(void *smp)
{}
#else /* lint */
/* XXXQ These should be inline templates, not functions */
#endif /* lint */
/*
* Generic sun4v MMU and Cache operations.
*/
#if defined(lint)
/*ARGSUSED*/
void
{}
/*ARGSUSED*/
void
vtag_flushall(void)
{}
/*ARGSUSED*/
void
{}
/*ARGSUSED*/
void
{}
/*ARGSUSED*/
void
{}
/*ARGSUSED*/
void
{}
/*ARGSUSED*/
void
{}
/*ARGSUSED*/
void
{}
/*ARGSUSED*/
void
{}
#else /* lint */
/*
* flush page from the tlb
*
* %o0 = vaddr
* %o1 = sfmmup
*/
1:
1:
/*
* x-trap to unmap perm map entry
* %g1 = vaddr
* %g2 = ctxnum (KCONTEXT only)
*/
ba,a ptl1_panic
1:
/*
* x-trap to flush page from tlb and tsb
*
* %g1 = vaddr, zero-extended on 32-bit kernel
* %g2 = sfmmup
*
* assumes TSBE_TAG = 0
*/
1:
/*
* x-trap to flush pgcnt MMU_PAGESIZE pages from tlb
*
* %g1 = vaddr, zero-extended on 32-bit kernel
* %g2 = <sfmmup58|pgcnt6>, (pgcnt - 1) is pass'ed in via pgcnt6 bits.
*
* NOTE: this handler relies on the fact that no
* interrupts or traps can occur during the loop
* issuing the TLB_DEMAP operations. It is assumed
* that interrupts are disabled and this code is
* fetching from the kernel locked text address.
*
* assumes TSBE_TAG = 0
*/
1:
2:
1:
/*
* flush_instr_mem:
* Flush a portion of the I-$ starting at vaddr
* %o0 vaddr
* %o1 bytes to be flushed
*/
1:
#endif /* !lint */
#if !defined(CUSTOM_FPZERO)
/*
* fp_zero() - clear all fp data registers and the fsr
*/
void
fp_zero(void)
{}
#else /* lint */
.align 8
.xword 0
#endif /* lint */
#endif /* CUSTOM_FPZERO */