1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License, Version 1.0 only
   6  * (the "License").  You may not use this file except in compliance
   7  * with the License.
   8  *
   9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10  * or http://www.opensolaris.org/os/licensing.
  11  * See the License for the specific language governing permissions
  12  * and limitations under the License.
  13  *
  14  * When distributing Covered Code, include this CDDL HEADER in each
  15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16  * If applicable, add the following below this CDDL HEADER, with the
  17  * fields enclosed by brackets "[]" replaced with your own identifying
  18  * information: Portions Copyright [yyyy] [name of copyright owner]
  19  *
  20  * CDDL HEADER END
  21  */
  22 /*
  23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #pragma ident   "%Z%%M% %I%     %E% SMI"
  28 
  29 #if defined(lint)
  30 #include <sys/types.h>
  31 #else   /* lint */
  32 #include "assym.h"
  33 #endif  /* lint */
  34 
  35 #include <sys/asm_linkage.h>
  36 #include <sys/machthread.h>               /* for reg definition */
  37 
  38 #include <sys/machasi.h>          /* sun4u ASI */
  39 #include <sys/mmu.h>
  40 #include <sys/privregs.h>
  41 #include <sys/machparam.h>
  42 #include <vm/hat_sfmmu.h>
  43 #include <sys/cpr_impl.h>
  44 #include <sys/intreg.h>
  45 #include <sys/clock.h>
  46 
  47 /*
  48  * resume kernel entry point from cprboot
  49  *      1. restore I/D TSB registers
  50  *      2. restore primary and secondary context registers
  51  *      3. initialize cpu state registers
  52  *      4. set up the thread and lwp registers for the cpr process
  53  *      5. switch to kernel trap
  54  *      6. restore checkpoint pc and stack pointer
  55  *      7. longjmp back to kernel
  56  *
  57  * registers from cprboot:exit_to_kernel()
  58  *      %o0     prom cookie
  59  *      %o1     struct sun4u_machdep *mdp
  60  *
  61  * Any change to this register assignment
  62  * require changes to cprboot_srt0.s
  63  */
  64 
  65 #if defined(lint)
  66 
  67 /* ARGSUSED */
  68 void
  69 i_cpr_resume_setup(void *cookie, csu_md_t *mdp)
  70 {}
  71 
  72 /* ARGSUSED */
  73 int
  74 i_cpr_cif_wrapper(void *args)
  75 { return (0); }
  76 
  77 /* ARGSUSED */
  78 void
  79 dtlb_wr_entry(uint_t index, tte_t *tte, uint64_t *va_tag)
  80 {}
  81 
  82 /* ARGSUSED */
  83 void
  84 itlb_wr_entry(uint_t index, tte_t *tte, uint64_t *va_tag)
  85 {}
  86 
  87 #else   /* lint */
  88 
  89         !
  90         ! reserve 4k for cpr tmp stack; tstack should be first,
  91         ! any new data symbols should be added after tstack.
  92         !
  93         .seg    ".data"
  94         .global i_cpr_data_page, i_cpr_tstack_size
  95         .global i_cpr_orig_cif
  96 
  97         .align  MMU_PAGESIZE
  98 i_cpr_data_page:
  99         .skip   4096
 100 i_cpr_tstack:
 101         .word   0
 102 i_cpr_tstack_size:
 103         .word   4096
 104 
 105         .align  8
 106 prom_tba:
 107         .word   0, 0
 108 i_cpr_orig_cif:
 109         .nword  0
 110 i_cpr_tmp_cif:
 111         .nword  0
 112 
 113 
 114         !
 115         ! set text to begin at a page boundary so we can
 116         ! map this one page and jump to it from cprboot
 117         !
 118         .seg    ".text"
 119         .align  MMU_PAGESIZE
 120 
 121         ENTRY(i_cpr_resume_setup)
 122         !
 123         ! save %o args to locals
 124         !
 125         mov     %o0, %l4
 126         mov     %o1, %l5
 127 
 128         !
 129         ! Restore PCONTEXT
 130         !
 131         sethi   %hi(FLUSH_ADDR), %g3
 132         ld      [%l5 + CPR_MD_PRI], %g1         ! mdp->mmu_ctx_pri
 133         set     MMU_PCONTEXT, %g2
 134         stxa    %g1, [%g2]ASI_DMMU
 135         flush   %g3
 136 
 137         !
 138         ! Restore SCONTEXT.  We do not need to set up the TSB
 139         ! registers.  Since we are restoring INVALID_CONTEXT into
 140         ! the secondary context the HAT will do that for us.
 141         !
 142         ld      [%l5 + CPR_MD_SEC], %g1         ! mdp->mmu_ctx_sec
 143         set     MMU_SCONTEXT, %g2
 144         stxa    %g1, [%g2]ASI_DMMU
 145         flush   %g3
 146 
 147         !
 148         ! Allow user rdtick, and rdstick if applicable
 149         !
 150         CLEARTICKNPT
 151 
 152         !
 153         ! copy saved thread pointer to %g7
 154         !
 155         ldx     [%l5 + CPR_MD_THRP], THREAD_REG         ! mdp->thrp
 156 
 157         !
 158         ! since csu_md_t lives in a cprboot data page,
 159         ! copy select data to registers for later use
 160         ! before freeing cprboot text/data pages
 161         !
 162         ldx     [%l5 + CPR_MD_QSAV_PC], %l7     ! l7 = mdp->qsav_pc
 163         ldx     [%l5 + CPR_MD_QSAV_SP], %l6     ! l6 = mdp->qsav_sp
 164 
 165         !
 166         ! save cookie from the new/tmp prom
 167         !
 168         set     i_cpr_tmp_cif, %g1
 169         stn     %l4, [%g1]
 170 
 171         !
 172         ! save prom tba
 173         !
 174         set     prom_tba, %g1
 175         rdpr    %tba, %g2
 176         stx     %g2, [%g1]
 177 
 178         !
 179         ! start slave cpus, pause them within kernel text,
 180         ! and restore the original prom pages
 181         !
 182         call    i_cpr_mp_setup
 183         nop
 184 
 185         !
 186         ! since this routine is entered only by a jmp from cprboot,
 187         ! we can set cpr_suspend_succeeded here
 188         !
 189         set     cpr_suspend_succeeded, %l0
 190         mov     1, %l1
 191         st      %l1, [%l0]
 192 
 193         !
 194         ! special shortened version of longjmp
 195         ! Don't need to flushw
 196         !
 197         mov     %l7, %i7                ! i7 = saved pc
 198         mov     %l6, %fp                ! i6 = saved sp
 199         ret                             ! return 1
 200         restore %g0, 1, %o0             ! takes underflow, switches stack
 201         SET_SIZE(i_cpr_resume_setup)
 202 
 203 
 204         !
 205         ! while running on the new/tmp prom, the prom's trap table
 206         ! must be used to handle translations within prom space
 207         ! since the kernel's mappings may not match this prom.
 208         !
 209         ! always set %tba to the prom's trap table before calling
 210         ! any prom service; after returning, read %tba again;
 211         ! if the %tba wasn't changed by the prom service,
 212         ! restore the original %tba.
 213         !
 214         ! a call stack looks like this:
 215         !
 216         ! current prom cookie
 217         ! [i_cpr_cif_wrapper]
 218         ! client_handler
 219         ! p1275_sparc_cif_handler
 220         ! prom_xxx
 221         !
 222         ENTRY(i_cpr_cif_wrapper)
 223         save    %sp, -SA64(MINFRAME64 + 8), %sp
 224         rdpr    %tba, %o5               ! read original %tba
 225         stx     %o5, [%fp + V9BIAS64 - 8]
 226         set     prom_tba, %l4
 227         ldx     [%l4], %o4              ! read prom_tba
 228         wrpr    %o4, %tba               ! switch to prom trap table
 229 
 230         set     i_cpr_tmp_cif, %g3      ! cookie for new/tmp prom
 231         ldn     [%g3], %g4
 232         jmpl    %g4, %o7                ! call prom service
 233         mov     %i0, %o0
 234 
 235         ldx     [%l4], %o4              ! read prom_tba
 236         rdpr    %tba, %o3               ! read current %tba
 237         cmp     %o3, %o4                ! did prom change %tba ?
 238         bne,pn  %xcc, 1f                ! yes, dont reset %tba
 239         nop
 240         ldx     [%fp + V9BIAS64 - 8], %o5
 241         wrpr    %o5, %tba               ! no change, restore orignal
 242 1:
 243         ret
 244         restore %g0, %o0, %o0
 245         SET_SIZE(i_cpr_cif_wrapper)
 246 
 247 
 248         !
 249         ! write dtlb entry at index
 250         !
 251         ENTRY(dtlb_wr_entry)
 252         sllx    %o0, 3, %o0                     ! index << 3
 253         ldx     [%o1], %o5                      ! o5 = tte.ll
 254         ldx     [%o2], %o4                      ! o4 = va_tag
 255         srlx    %o4, MMU_PAGESHIFT, %o4         ! clear any page offset
 256         sllx    %o4, MMU_PAGESHIFT, %o4         ! o4 = va_tag & PAGEMASK
 257         set     MMU_TAG_ACCESS, %o3
 258         stxa    %o4, [%o3]ASI_DMMU
 259         stxa    %o5, [%o0]ASI_DTLB_ACCESS
 260         membar  #Sync
 261         retl
 262         nop
 263         SET_SIZE(dtlb_wr_entry)
 264 
 265 
 266         !
 267         ! write itlb entry at index
 268         !
 269         ENTRY(itlb_wr_entry)
 270         sllx    %o0, 3, %o0                     ! index << 3
 271         ldx     [%o1], %o5                      ! o5 = tte.ll
 272         ldx     [%o2], %o4                      ! o4 = va_tag
 273         srlx    %o4, MMU_PAGESHIFT, %o4         ! clear any page offset
 274         sllx    %o4, MMU_PAGESHIFT, %o4         ! o4 = va_tag & PAGEMASK
 275         set     MMU_TAG_ACCESS, %o3
 276         stxa    %o4, [%o3]ASI_IMMU
 277         stxa    %o5, [%o0]ASI_ITLB_ACCESS
 278         membar  #Sync
 279         retl
 280         nop
 281         SET_SIZE(itlb_wr_entry)
 282 
 283 #endif /* !lint */