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 (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  * General machine architecture & implementation specific
  28  * assembly language routines.
  29  */
  30 #include "assym.h"
  31 
  32 #include <sys/asm_linkage.h>
  33 #include <sys/async.h>
  34 #include <sys/machthread.h>
  35 #include <sys/vis.h>
  36 #include <sys/machsig.h>
  37 
  38         ENTRY(set_trap_table)
  39         set     trap_table, %o1
  40         rdpr    %tba, %o0
  41         wrpr    %o1, %tba
  42         retl
  43         wrpr    %g0, WSTATE_KERN, %wstate
  44         SET_SIZE(set_trap_table)
  45 
  46         ! Store long word value at physical address
  47         !
  48         ! void  stdphys(uint64_t physaddr, uint64_t value)
  49         !
  50         ENTRY(stdphys)
  51         /*
  52          * disable interrupts, clear Address Mask to access 64 bit physaddr
  53          */
  54         rdpr    %pstate, %o4
  55         andn    %o4, PSTATE_IE | PSTATE_AM, %o5
  56         wrpr    %o5, 0, %pstate
  57         stxa    %o1, [%o0]ASI_MEM
  58         retl
  59         wrpr    %g0, %o4, %pstate       ! restore earlier pstate register value
  60         SET_SIZE(stdphys)
  61 
  62 
  63         ! Store long word value at physical i/o address
  64         !
  65         ! void  stdphysio(u_longlong_t physaddr, u_longlong_t value)
  66         !
  67         ENTRY(stdphysio)
  68         /*
  69          * disable interrupts, clear Address Mask to access 64 bit physaddr
  70          */
  71         rdpr    %pstate, %o4
  72         andn    %o4, PSTATE_IE | PSTATE_AM, %o5
  73         wrpr    %o5, 0, %pstate         ! clear IE, AM bits
  74         stxa    %o1, [%o0]ASI_IO
  75         retl
  76         wrpr    %g0, %o4, %pstate       ! restore earlier pstate register value
  77         SET_SIZE(stdphysio)
  78 
  79 
  80         !
  81         ! Load long word value at physical address
  82         !
  83         ! uint64_t lddphys(uint64_t physaddr)
  84         !
  85         ENTRY(lddphys)
  86         rdpr    %pstate, %o4
  87         andn    %o4, PSTATE_IE | PSTATE_AM, %o5
  88         wrpr    %o5, 0, %pstate
  89         ldxa    [%o0]ASI_MEM, %o0
  90         retl
  91         wrpr    %g0, %o4, %pstate       ! restore earlier pstate register value
  92         SET_SIZE(lddphys)
  93 
  94         !
  95         ! Load long word value at physical i/o address
  96         !
  97         ! unsigned long long lddphysio(u_longlong_t physaddr)
  98         !
  99         ENTRY(lddphysio)
 100         rdpr    %pstate, %o4
 101         andn    %o4, PSTATE_IE | PSTATE_AM, %o5
 102         wrpr    %o5, 0, %pstate ! clear IE, AM bits
 103         ldxa    [%o0]ASI_IO, %o0
 104         retl
 105         wrpr    %g0, %o4, %pstate       ! restore earlier pstate register value
 106         SET_SIZE(lddphysio)
 107 
 108         !
 109         ! Store value at physical address
 110         !
 111         ! void  stphys(uint64_t physaddr, int value)
 112         !
 113         ENTRY(stphys)
 114         rdpr    %pstate, %o4
 115         andn    %o4, PSTATE_IE | PSTATE_AM, %o5
 116         wrpr    %o5, 0, %pstate
 117         sta     %o1, [%o0]ASI_MEM
 118         retl
 119         wrpr    %g0, %o4, %pstate       ! restore earlier pstate register value
 120         SET_SIZE(stphys)
 121 
 122 
 123         !
 124         ! load value at physical address
 125         !
 126         ! int   ldphys(uint64_t physaddr)
 127         !
 128         ENTRY(ldphys)
 129         rdpr    %pstate, %o4
 130         andn    %o4, PSTATE_IE | PSTATE_AM, %o5
 131         wrpr    %o5, 0, %pstate
 132         lda     [%o0]ASI_MEM, %o0
 133         srl     %o0, 0, %o0     ! clear upper 32 bits
 134         retl
 135         wrpr    %g0, %o4, %pstate       ! restore earlier pstate register value
 136         SET_SIZE(ldphys)
 137 
 138         !
 139         ! Store value into physical address in I/O space
 140         !
 141         ! void stphysio(u_longlong_t physaddr, uint_t value)
 142         !
 143         ENTRY_NP(stphysio)
 144         rdpr    %pstate, %o4            /* read PSTATE reg */
 145         andn    %o4, PSTATE_IE | PSTATE_AM, %o5
 146         wrpr    %o5, 0, %pstate
 147         stwa    %o1, [%o0]ASI_IO        /* store value via bypass ASI */
 148         retl
 149         wrpr    %g0, %o4, %pstate       /* restore the PSTATE */
 150         SET_SIZE(stphysio)
 151 
 152         !
 153         ! Store value into physical address in I/O space
 154         !
 155         ! void sthphysio(u_longlong_t physaddr, ushort_t value)
 156         !
 157         ENTRY_NP(sthphysio)
 158         rdpr    %pstate, %o4            /* read PSTATE reg */
 159         andn    %o4, PSTATE_IE | PSTATE_AM, %o5
 160         wrpr    %o5, 0, %pstate
 161         stha    %o1, [%o0]ASI_IO        /* store value via bypass ASI */
 162         retl
 163         wrpr    %g0, %o4, %pstate               /* restore the PSTATE */
 164         SET_SIZE(sthphysio)
 165 
 166         !
 167         ! Store value into one byte physical address in I/O space
 168         !
 169         ! void stbphysio(u_longlong_t physaddr, uchar_t value)
 170         !
 171         ENTRY_NP(stbphysio)
 172         rdpr    %pstate, %o4            /* read PSTATE reg */
 173         andn    %o4, PSTATE_IE | PSTATE_AM, %o5
 174         wrpr    %o5, 0, %pstate
 175         stba    %o1, [%o0]ASI_IO        /* store byte via bypass ASI */
 176         retl
 177         wrpr    %g0, %o4, %pstate       /* restore the PSTATE */
 178         SET_SIZE(stbphysio)
 179 
 180         !
 181         ! load value at physical address in I/O space
 182         !
 183         ! uint_t   ldphysio(u_longlong_t physaddr)
 184         !
 185         ENTRY_NP(ldphysio)
 186         rdpr    %pstate, %o4            /* read PSTATE reg */
 187         andn    %o4, PSTATE_IE | PSTATE_AM, %o5
 188         wrpr    %o5, 0, %pstate
 189         lduwa   [%o0]ASI_IO, %o0        /* load value via bypass ASI */
 190         retl
 191         wrpr    %g0, %o4, %pstate       /* restore pstate */
 192         SET_SIZE(ldphysio)
 193 
 194         !
 195         ! load value at physical address in I/O space
 196         !
 197         ! ushort_t   ldhphysio(u_longlong_t physaddr)
 198         !
 199         ENTRY_NP(ldhphysio)
 200         rdpr    %pstate, %o4            /* read PSTATE reg */
 201         andn    %o4, PSTATE_IE | PSTATE_AM, %o5
 202         wrpr    %o5, 0, %pstate
 203         lduha   [%o0]ASI_IO, %o0        /* load value via bypass ASI */
 204         retl
 205         wrpr    %g0, %o4, %pstate       /* restore pstate */
 206         SET_SIZE(ldhphysio)
 207 
 208         !
 209         ! load byte value at physical address in I/O space
 210         !
 211         ! uchar_t   ldbphysio(u_longlong_t physaddr)
 212         !
 213         ENTRY_NP(ldbphysio)
 214         rdpr    %pstate, %o4            /* read PSTATE reg */
 215         andn    %o4, PSTATE_IE | PSTATE_AM, %o5
 216         wrpr    %o5, 0, %pstate
 217         lduba   [%o0]ASI_IO, %o0        /* load value via bypass ASI */
 218         retl
 219         wrpr    %g0, %o4, %pstate       /* restore pstate */
 220         SET_SIZE(ldbphysio)
 221 
 222 /*
 223  * save_gsr(kfpu_t *fp)
 224  * Store the graphics status register
 225  */
 226 
 227         ENTRY_NP(save_gsr)
 228         rd      %gsr, %g2                       ! save gsr
 229         retl
 230         stx     %g2, [%o0 + FPU_GSR]
 231         SET_SIZE(save_gsr)
 232 
 233         ENTRY_NP(restore_gsr)
 234         ldx     [%o0 + FPU_GSR], %g2
 235         wr      %g2, %g0, %gsr
 236         retl
 237         nop
 238         SET_SIZE(restore_gsr)
 239 
 240 /*
 241  * uint64_t
 242  * _fp_read_pgsr()
 243  * Get the graphics status register info from fp and return it
 244  */
 245 
 246         ENTRY_NP(_fp_read_pgsr)
 247         retl
 248         rd      %gsr, %o0
 249         SET_SIZE(_fp_read_pgsr)
 250 
 251 
 252 /*
 253  * uint64_t
 254  * get_gsr(kfpu_t *fp)
 255  * Get the graphics status register info from fp and return it
 256  */
 257 
 258         ENTRY_NP(get_gsr)
 259         retl
 260         ldx     [%o0 + FPU_GSR], %o0
 261         SET_SIZE(get_gsr)
 262 
 263 /*
 264  * _fp_write_pgsr(uint64_t *buf, kfpu_t *fp)
 265  * Set the graphics status register info to fp from buf
 266  */
 267 
 268         ENTRY_NP(_fp_write_pgsr)
 269         retl
 270         mov     %o0, %gsr
 271         SET_SIZE(_fp_write_pgsr)
 272 
 273 /*      
 274  * set_gsr(uint64_t buf, kfpu_t *fp)
 275  * Set the graphics status register info to fp from buf
 276  */
 277 
 278         ENTRY_NP(set_gsr)
 279         retl
 280         stx     %o0, [%o1 + FPU_GSR]
 281         SET_SIZE(set_gsr)
 282 
 283         ENTRY_NP(kdi_cpu_index)
 284         CPU_INDEX(%g1, %g2)
 285         jmp     %g7
 286         nop
 287         SET_SIZE(kdi_cpu_index)
 288 
 289         ENTRY_NP(kmdb_enter)
 290         t       ST_KMDB_TRAP
 291         retl
 292         nop
 293         SET_SIZE(kmdb_enter)
 294 
 295 /*
 296  * The Spitfire floating point code has been changed not to use install/
 297  * save/restore/fork/freectx() because of the special memcpy library
 298  * routines, which will lose too much performance if they have to go
 299  * through the fp_disabled trap (which used to call installctx()). So
 300  * now fp_save/fp_restore are called from resume, and they don't care
 301  * whether floating point was enabled from the user program via the
 302  * fp_enabled trap or from the memcpy library, which just turns on floating
 303  * point in the fprs register itself. The new routine lwp_freeregs is
 304  * called everywhere freectx is called, and code was added to the sun4u-
 305  * specific version of lwp_forkregs (which is called everywhere forkctx
 306  * is called) to handle forking the floating point registers.
 307  *
 308  * Note that for the fprs dirty upper/lower bits are not used for now,
 309  * because the #instructions to determine if we need to use them is probably
 310  * greater than the #insructions just using them. This is a possible future
 311  * optimization, only do it with very careful benchmarking!
 312  *
 313  * The fp_fksave and and fp_load were split into two routines for the
 314  * sake of efficiency between the getfpregs/xregs_getfpregs and
 315  * setfpregs/xregs_setfpregs. But note that for saving and restoring
 316  * context, both *must* happen. For prmachdep, aka access from [k]adb,
 317  * it's OK if only one part happens.
 318  */ 
 319 
 320 /*
 321  * fp_save(kfpu_t *fp)
 322  * fp_fksave(kfpu_t *fp)
 323  * Store the floating point registers.
 324  */
 325 
 326         ENTRY_NP(fp_save)
 327         ALTENTRY(fp_fksave)
 328         BSTORE_FPREGS(%o0, %o1)                 ! store V9 regs
 329         retl
 330         stx     %fsr, [%o0 + FPU_FSR]           ! store fsr
 331         SET_SIZE(fp_fksave)
 332         SET_SIZE(fp_save)
 333 
 334 /*
 335  * fp_v8_fksave(kfpu_t *fp)
 336  *
 337  * This is like the above routine but only saves the lower half.
 338  */
 339 
 340         ENTRY_NP(fp_v8_fksave)
 341         BSTORE_V8_FPREGS(%o0, %o1)              ! store V8 regs
 342         retl
 343         stx     %fsr, [%o0 + FPU_FSR]           ! store fsr
 344         SET_SIZE(fp_v8_fksave)
 345 
 346 /*
 347  * fp_v8p_fksave(kfpu_t *fp)
 348  *
 349  * This is like the above routine but only saves the upper half.
 350  */
 351 
 352         ENTRY_NP(fp_v8p_fksave)
 353         BSTORE_V8P_FPREGS(%o0, %o1)             ! store V9 extra regs
 354         retl
 355         stx     %fsr, [%o0 + FPU_FSR]           ! store fsr
 356         SET_SIZE(fp_v8p_fksave)
 357 
 358 /*
 359  * fp_restore(kfpu_t *fp)
 360  */
 361 
 362         ENTRY_NP(fp_restore)
 363         BLOAD_FPREGS(%o0, %o1)                  ! load V9 regs
 364         retl
 365         ldx     [%o0 + FPU_FSR], %fsr           ! restore fsr
 366         SET_SIZE(fp_restore)
 367 
 368 /*
 369  * fp_v8_load(kfpu_t *fp)
 370  */
 371 
 372         ENTRY_NP(fp_v8_load)
 373         BLOAD_V8_FPREGS(%o0, %o1)               ! load V8 regs
 374         retl
 375         ldx     [%o0 + FPU_FSR], %fsr           ! restore fsr
 376         SET_SIZE(fp_v8_load)
 377 
 378 /*
 379  * fp_v8p_load(kfpu_t *fp)
 380  */
 381 
 382         ENTRY_NP(fp_v8p_load)
 383         BLOAD_V8P_FPREGS(%o0, %o1)              ! load V9 extra regs
 384         retl
 385         ldx     [%o0 + FPU_FSR], %fsr           ! restore fsr
 386         SET_SIZE(fp_v8p_load)
 387