/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (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 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * This file is through cpp before being used as * an inline. It contains support routines used * only by DR for the copy-rename sequence. */ #if defined(lint) #include #else #include "assym.h" #endif /* lint */ #include #include #include #include #include #include #include #include #include #include #ifndef lint /* * arg1 = icache_size * arg2 = icache_linesize */ #define ICACHE_FLUSHALL(lbl, arg1, arg2, tmp1) \ ldxa [%g0]ASI_LSU, tmp1 ;\ btst LSU_IC, tmp1 ;\ bz,pn %icc, lbl/**/1 ;\ sub arg1, arg2, tmp1 ;\ lbl/**/0: ;\ stxa %g0, [tmp1]ASI_IC_TAG ;\ membar #Sync ;\ cmp %g0, tmp1 ;\ bne,pt %icc, lbl/**/0 ;\ sub tmp1, arg2, tmp1 ;\ lbl/**/1: /* * arg1 = dcache_size * arg2 = dcache_linesize */ #define DCACHE_FLUSHALL(lbl, arg1, arg2, tmp1) \ ldxa [%g0]ASI_LSU, tmp1 ;\ btst LSU_DC, tmp1 ;\ bz,pn %icc, lbl/**/1 ;\ sub arg1, arg2, tmp1 ;\ lbl/**/0: ;\ stxa %g0, [tmp1]ASI_DC_TAG ;\ membar #Sync ;\ cmp %g0, tmp1 ;\ bne,pt %icc, lbl/**/0 ;\ sub tmp1, arg2, tmp1 ;\ lbl/**/1: /* * arg1 = ecache flush physaddr * arg2 = size * arg3 = ecache_linesize */ #define ECACHE_FLUSHALL(lbl, arg1, arg2, arg3, tmp1, tmp2) \ rdpr %pstate, tmp1 ;\ andn tmp1, PSTATE_IE | PSTATE_AM, tmp2 ;\ wrpr %g0, tmp2, %pstate ;\ b lbl/**/1 ;\ lbl/**/0: ;\ sub arg2, arg3, arg2 ;\ lbl/**/1: ;\ brgez,a arg2, lbl/**/0 ;\ ldxa [arg1 + arg2]ASI_MEM, %g0 ;\ wrpr %g0, tmp1, %pstate #ifdef SF_ERRATA_32 #define SF_WORKAROUND(tmp1, tmp2) \ sethi %hi(FLUSH_ADDR), tmp2 ;\ set MMU_PCONTEXT, tmp1 ;\ stxa %g0, [tmp1]ASI_DMMU ;\ flush tmp2 ; #else #define SF_WORKAROUND(tmp1, tmp2) #endif /* SF_ERRATA_32 */ /* * arg1 = vaddr * arg2 = ctxnum * - disable interrupts and clear address mask * to access 64 bit physaddr * - Blow out the TLB. * . If it's kernel context, then use primary context. * . Otherwise, use secondary. */ #define VTAG_FLUSHPAGE(lbl, arg1, arg2, tmp1, tmp2, tmp3, tmp4) \ rdpr %pstate, tmp1 ;\ andn tmp1, PSTATE_IE | PSTATE_AM, tmp2 ;\ wrpr tmp2, 0, %pstate ;\ brnz,pt arg2, lbl/**/1 ;\ sethi %hi(FLUSH_ADDR), tmp2 ;\ stxa %g0, [arg1]ASI_DTLB_DEMAP ;\ stxa %g0, [arg1]ASI_ITLB_DEMAP ;\ b lbl/**/5 ;\ flush tmp2 ;\ lbl/**/1: ;\ set MMU_SCONTEXT, tmp3 ;\ ldxa [tmp3]ASI_DMMU, tmp4 ;\ or DEMAP_SECOND | DEMAP_PAGE_TYPE, arg1, arg1 ;\ cmp tmp4, arg2 ;\ be,a,pt %icc, lbl/**/4 ;\ nop ;\ stxa arg2, [tmp3]ASI_DMMU ;\ lbl/**/4: ;\ stxa %g0, [arg1]ASI_DTLB_DEMAP ;\ stxa %g0, [arg1]ASI_ITLB_DEMAP ;\ flush tmp2 ;\ be,a,pt %icc, lbl/**/5 ;\ nop ;\ stxa tmp4, [tmp3]ASI_DMMU ;\ flush tmp2 ;\ lbl/**/5: ;\ wrpr %g0, tmp1, %pstate /* * arg1 = dtlb entry * - Before first compare: * tmp4 = tte * tmp5 = vaddr * tmp6 = cntxnum */ #define DTLB_FLUSH_UNLOCKED(lbl, arg1, tmp1, tmp2, tmp3, \ tmp4, tmp5, tmp6) \ lbl/**/0: ;\ sllx arg1, 3, tmp3 ;\ SF_WORKAROUND(tmp1, tmp2) ;\ ldxa [tmp3]ASI_DTLB_ACCESS, tmp4 ;\ srlx tmp4, 6, tmp4 ;\ andcc tmp4, 1, %g0 ;\ bnz,pn %xcc, lbl/**/1 ;\ srlx tmp4, 57, tmp4 ;\ andcc tmp4, 1, %g0 ;\ beq,pn %xcc, lbl/**/1 ;\ nop ;\ set TAGREAD_CTX_MASK, tmp1 ;\ ldxa [tmp3]ASI_DTLB_TAGREAD, tmp2 ;\ and tmp2, tmp1, tmp6 ;\ andn tmp2, tmp1, tmp5 ;\ VTAG_FLUSHPAGE(VD, tmp5, tmp6, tmp1, tmp2, tmp3, tmp4) ;\ lbl/**/1: ;\ brgz,pt arg1, lbl/**/0 ;\ sub arg1, 1, arg1 /* * arg1 = itlb entry * - Before first compare: * tmp4 = tte * tmp5 = vaddr * tmp6 = cntxnum */ #define ITLB_FLUSH_UNLOCKED(lbl, arg1, tmp1, tmp2, tmp3, \ tmp4, tmp5, tmp6) \ lbl/**/0: ;\ sllx arg1, 3, tmp3 ;\ SF_WORKAROUND(tmp1, tmp2) ;\ ldxa [tmp3]ASI_ITLB_ACCESS, tmp4 ;\ srlx tmp4, 6, tmp4 ;\ andcc tmp4, 1, %g0 ;\ bnz,pn %xcc, lbl/**/1 ;\ srlx tmp4, 57, tmp4 ;\ andcc tmp4, 1, %g0 ;\ beq,pn %xcc, lbl/**/1 ;\ nop ;\ set TAGREAD_CTX_MASK, tmp1 ;\ ldxa [tmp3]ASI_ITLB_TAGREAD, tmp2 ;\ and tmp2, tmp1, tmp6 ;\ andn tmp2, tmp1, tmp5 ;\ VTAG_FLUSHPAGE(VI, tmp5, tmp6, tmp1, tmp2, tmp3, tmp4) ;\ lbl/**/1: ;\ brgz,pt arg1, lbl/**/0 ;\ sub arg1, 1, arg1 #define CLEARTL(lvl) \ wrpr %g0, lvl, %tl ;\ wrpr %g0, %g0, %tpc ;\ wrpr %g0, %g0, %tnpc ;\ wrpr %g0, %g0, %tt #define SWITCH_STACK(estk) \ flushw ;\ sub estk, SA(KFPUSIZE+GSR_SIZE), estk ;\ andn estk, 0x3f, estk ;\ sub estk, SA(MINFRAME) + STACK_BIAS, %sp ;\ mov estk, %fp #endif /* !lint */ #if defined(lint) /*ARGSUSED*/ void drmach_shutdown_asm(uint64_t mbox_addr) {} #else /* lint */ ENTRY_NP(drmach_shutdown_asm) mov %o0, %o5 ldxa [%o5]ASI_MEM, %o0 ! get 8-byte estack in o0 add %o5, 8, %o5 ldxa [%o5]ASI_MEM, %o1 ! get 8-byte flushaddr in o1 add %o5, 8, %o5 lda [%o5]ASI_MEM, %o2 ! get 4-byte size in o2 srl %o2, 0, %o2 add %o5, 4, %o5 lda [%o5]ASI_MEM, %o3 ! get 4-byte linesize in o3 srl %o3, 0, %o3 add %o5, 4, %o5 ldxa [%o5]ASI_MEM, %o4 ! get 8-byte physaddr in o4 ! %o0 = base (va mapping this code in bbsram) ! %o1 = flushaddr for ecache ! %o2 = size to use for ecache flush ! %o3 = ecache linesize ! %o4 = phys addr of byte to clear when finished ! ! output: Stores a zero at [%o4]ASI_MEM membar #LoadStore ! ! Switch stack pointer to bbsram ! SWITCH_STACK(%o0) ! ! Get some globals ! mov %o3, %g1 ! ecache_linesize mov %o4, %o0 ! physaddr byte to clear sethi %hi(dcache_linesize), %g2 ld [%g2 + %lo(dcache_linesize)], %g2 sethi %hi(dcache_size), %g3 ld [%g3 + %lo(dcache_size)], %g3 sethi %hi(icache_linesize), %g4 ld [%g4 + %lo(icache_linesize)], %g4 sethi %hi(icache_size), %g5 ld [%g5 + %lo(icache_size)], %g5 sethi %hi(dtlb_entries), %o5 ld [%o5 + %lo(dtlb_entries)], %o5 sllx %o5, 32, %o5 srlx %o5, 32, %o5 sethi %hi(itlb_entries), %o3 ld [%o3 + %lo(itlb_entries)], %o3 ! ! cram Xtlb_entries into a single register (%o5) ! %o5 upper 32 = itlb_entries ! lower 32 = dtlb_entries ! sllx %o3, 32, %o3 or %o5, %o3, %o5 ! ! Flush E$ ! ECACHE_FLUSHALL(EC, %o1, %o2, %g1, %o3, %o4) ! ! %o1 & %o2 now available ! membar #Sync ! ! Flush D$ ! DCACHE_FLUSHALL(DC, %g3, %g2, %o3) ! ! Flush I$ ! ICACHE_FLUSHALL(IC, %g5, %g4, %o3) membar #Sync ! ! Flush dtlb's ! srlx %o5, 32, %g5 ! %g5 = itlb_entries sllx %o5, 32, %o5 srlx %o5, 32, %g1 sub %g1, 1, %g1 ! %g1 = dtlb_entries - 1 DTLB_FLUSH_UNLOCKED(D, %g1, %g3, %g4, %o2, %o3, %o4, %o5) ! ! Flush itlb's ! sub %g5, 1, %g1 ! %g1 = itlb_entries - 1 ITLB_FLUSH_UNLOCKED(I, %g1, %g3, %g4, %o2, %o3, %o4, %o5) membar #Sync ! ! Clear byte to signal finished. ! stba %g0, [%o0]ASI_MEM membar #Sync ! ! read ensures that last write completed (has left queue in the PC chip) ! lduba [%o0]ASI_MEM, %g0 5: ba 5b nop SET_SIZE(drmach_shutdown_asm) .global drmach_shutdown_asm_end .skip 2048 drmach_shutdown_asm_end: #endif /* lint */