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 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26#pragma ident "%Z%%M% %I% %E% SMI" 27 28/* 29 * General machine architecture & implementation specific 30 * assembly language routines. 31 */ 32#if defined(lint) 33#include <sys/types.h> 34#include <sys/machsystm.h> 35#include <sys/t_lock.h> 36#else /* lint */ 37#include "assym.h" 38#endif /* lint */ 39 40#include <sys/asm_linkage.h> 41#include <sys/async.h> 42#include <sys/machthread.h> 43#include <sys/vis.h> 44#include <sys/machsig.h> 45 46#if defined(lint) 47caddr_t 48set_trap_table(void) 49{ 50 return ((caddr_t)0); 51} 52#else /* lint */ 53 54 ENTRY(set_trap_table) 55 set trap_table, %o1 56 rdpr %tba, %o0 57 wrpr %o1, %tba 58 retl 59 wrpr %g0, WSTATE_KERN, %wstate 60 SET_SIZE(set_trap_table) 61 62#endif /* lint */ 63 64#if defined(lint) 65 66/*ARGSUSED*/ 67void 68stphys(uint64_t physaddr, int value) 69{} 70 71/*ARGSUSED*/ 72int 73ldphys(uint64_t physaddr) 74{ return (0); } 75 76/*ARGSUSED*/ 77void 78stdphys(uint64_t physaddr, uint64_t value) 79{} 80 81/*ARGSUSED*/ 82uint64_t 83lddphys(uint64_t physaddr) 84{ return (0x0ull); } 85 86/* ARGSUSED */ 87void 88stphysio(u_longlong_t physaddr, uint_t value) 89{} 90 91/* ARGSUSED */ 92uint_t 93ldphysio(u_longlong_t physaddr) 94{ return(0); } 95 96/* ARGSUSED */ 97void 98sthphysio(u_longlong_t physaddr, ushort_t value) 99{} 100 101/* ARGSUSED */ 102ushort_t 103ldhphysio(u_longlong_t physaddr) 104{ return(0); } 105 106/* ARGSUSED */ 107void 108stbphysio(u_longlong_t physaddr, uchar_t value) 109{} 110 111/* ARGSUSED */ 112uchar_t 113ldbphysio(u_longlong_t physaddr) 114{ return(0); } 115 116/*ARGSUSED*/ 117void 118stdphysio(u_longlong_t physaddr, u_longlong_t value) 119{} 120 121/*ARGSUSED*/ 122u_longlong_t 123lddphysio(u_longlong_t physaddr) 124{ return (0ull); } 125 126#else 127 128 ! Store long word value at physical address 129 ! 130 ! void stdphys(uint64_t physaddr, uint64_t value) 131 ! 132 ENTRY(stdphys) 133 /* 134 * disable interrupts, clear Address Mask to access 64 bit physaddr 135 */ 136 rdpr %pstate, %o4 137 andn %o4, PSTATE_IE | PSTATE_AM, %o5 138 wrpr %o5, 0, %pstate 139 stxa %o1, [%o0]ASI_MEM 140 retl 141 wrpr %g0, %o4, %pstate ! restore earlier pstate register value 142 SET_SIZE(stdphys) 143 144 145 ! Store long word value at physical i/o address 146 ! 147 ! void stdphysio(u_longlong_t physaddr, u_longlong_t value) 148 ! 149 ENTRY(stdphysio) 150 /* 151 * disable interrupts, clear Address Mask to access 64 bit physaddr 152 */ 153 rdpr %pstate, %o4 154 andn %o4, PSTATE_IE | PSTATE_AM, %o5 155 wrpr %o5, 0, %pstate ! clear IE, AM bits 156 stxa %o1, [%o0]ASI_IO 157 retl 158 wrpr %g0, %o4, %pstate ! restore earlier pstate register value 159 SET_SIZE(stdphysio) 160 161 162 ! 163 ! Load long word value at physical address 164 ! 165 ! uint64_t lddphys(uint64_t physaddr) 166 ! 167 ENTRY(lddphys) 168 rdpr %pstate, %o4 169 andn %o4, PSTATE_IE | PSTATE_AM, %o5 170 wrpr %o5, 0, %pstate 171 ldxa [%o0]ASI_MEM, %o0 172 retl 173 wrpr %g0, %o4, %pstate ! restore earlier pstate register value 174 SET_SIZE(lddphys) 175 176 ! 177 ! Load long word value at physical i/o address 178 ! 179 ! unsigned long long lddphysio(u_longlong_t physaddr) 180 ! 181 ENTRY(lddphysio) 182 rdpr %pstate, %o4 183 andn %o4, PSTATE_IE | PSTATE_AM, %o5 184 wrpr %o5, 0, %pstate ! clear IE, AM bits 185 ldxa [%o0]ASI_IO, %o0 186 retl 187 wrpr %g0, %o4, %pstate ! restore earlier pstate register value 188 SET_SIZE(lddphysio) 189 190 ! 191 ! Store value at physical address 192 ! 193 ! void stphys(uint64_t physaddr, int value) 194 ! 195 ENTRY(stphys) 196 rdpr %pstate, %o4 197 andn %o4, PSTATE_IE | PSTATE_AM, %o5 198 wrpr %o5, 0, %pstate 199 sta %o1, [%o0]ASI_MEM 200 retl 201 wrpr %g0, %o4, %pstate ! restore earlier pstate register value 202 SET_SIZE(stphys) 203 204 205 ! 206 ! load value at physical address 207 ! 208 ! int ldphys(uint64_t physaddr) 209 ! 210 ENTRY(ldphys) 211 rdpr %pstate, %o4 212 andn %o4, PSTATE_IE | PSTATE_AM, %o5 213 wrpr %o5, 0, %pstate 214 lda [%o0]ASI_MEM, %o0 215 srl %o0, 0, %o0 ! clear upper 32 bits 216 retl 217 wrpr %g0, %o4, %pstate ! restore earlier pstate register value 218 SET_SIZE(ldphys) 219 220 ! 221 ! Store value into physical address in I/O space 222 ! 223 ! void stphysio(u_longlong_t physaddr, uint_t value) 224 ! 225 ENTRY_NP(stphysio) 226 rdpr %pstate, %o4 /* read PSTATE reg */ 227 andn %o4, PSTATE_IE | PSTATE_AM, %o5 228 wrpr %o5, 0, %pstate 229 stwa %o1, [%o0]ASI_IO /* store value via bypass ASI */ 230 retl 231 wrpr %g0, %o4, %pstate /* restore the PSTATE */ 232 SET_SIZE(stphysio) 233 234 ! 235 ! Store value into physical address in I/O space 236 ! 237 ! void sthphysio(u_longlong_t physaddr, ushort_t value) 238 ! 239 ENTRY_NP(sthphysio) 240 rdpr %pstate, %o4 /* read PSTATE reg */ 241 andn %o4, PSTATE_IE | PSTATE_AM, %o5 242 wrpr %o5, 0, %pstate 243 stha %o1, [%o0]ASI_IO /* store value via bypass ASI */ 244 retl 245 wrpr %g0, %o4, %pstate /* restore the PSTATE */ 246 SET_SIZE(sthphysio) 247 248 ! 249 ! Store value into one byte physical address in I/O space 250 ! 251 ! void stbphysio(u_longlong_t physaddr, uchar_t value) 252 ! 253 ENTRY_NP(stbphysio) 254 rdpr %pstate, %o4 /* read PSTATE reg */ 255 andn %o4, PSTATE_IE | PSTATE_AM, %o5 256 wrpr %o5, 0, %pstate 257 stba %o1, [%o0]ASI_IO /* store byte via bypass ASI */ 258 retl 259 wrpr %g0, %o4, %pstate /* restore the PSTATE */ 260 SET_SIZE(stbphysio) 261 262 ! 263 ! load value at physical address in I/O space 264 ! 265 ! uint_t ldphysio(u_longlong_t physaddr) 266 ! 267 ENTRY_NP(ldphysio) 268 rdpr %pstate, %o4 /* read PSTATE reg */ 269 andn %o4, PSTATE_IE | PSTATE_AM, %o5 270 wrpr %o5, 0, %pstate 271 lduwa [%o0]ASI_IO, %o0 /* load value via bypass ASI */ 272 retl 273 wrpr %g0, %o4, %pstate /* restore pstate */ 274 SET_SIZE(ldphysio) 275 276 ! 277 ! load value at physical address in I/O space 278 ! 279 ! ushort_t ldhphysio(u_longlong_t physaddr) 280 ! 281 ENTRY_NP(ldhphysio) 282 rdpr %pstate, %o4 /* read PSTATE reg */ 283 andn %o4, PSTATE_IE | PSTATE_AM, %o5 284 wrpr %o5, 0, %pstate 285 lduha [%o0]ASI_IO, %o0 /* load value via bypass ASI */ 286 retl 287 wrpr %g0, %o4, %pstate /* restore pstate */ 288 SET_SIZE(ldhphysio) 289 290 ! 291 ! load byte value at physical address in I/O space 292 ! 293 ! uchar_t ldbphysio(u_longlong_t physaddr) 294 ! 295 ENTRY_NP(ldbphysio) 296 rdpr %pstate, %o4 /* read PSTATE reg */ 297 andn %o4, PSTATE_IE | PSTATE_AM, %o5 298 wrpr %o5, 0, %pstate 299 lduba [%o0]ASI_IO, %o0 /* load value via bypass ASI */ 300 retl 301 wrpr %g0, %o4, %pstate /* restore pstate */ 302 SET_SIZE(ldbphysio) 303#endif /* lint */ 304 305/* 306 * save_gsr(kfpu_t *fp) 307 * Store the graphics status register 308 */ 309 310#if defined(lint) || defined(__lint) 311 312/* ARGSUSED */ 313void 314save_gsr(kfpu_t *fp) 315{} 316 317#else /* lint */ 318 319 ENTRY_NP(save_gsr) 320 rd %gsr, %g2 ! save gsr 321 retl 322 stx %g2, [%o0 + FPU_GSR] 323 SET_SIZE(save_gsr) 324 325#endif /* lint */ 326 327#if defined(lint) || defined(__lint) 328 329/* ARGSUSED */ 330void 331restore_gsr(kfpu_t *fp) 332{} 333 334#else /* lint */ 335 336 ENTRY_NP(restore_gsr) 337 ldx [%o0 + FPU_GSR], %g2 338 wr %g2, %g0, %gsr 339 retl 340 nop 341 SET_SIZE(restore_gsr) 342 343#endif /* lint */ 344 345/* 346 * uint64_t 347 * _fp_read_pgsr() 348 * Get the graphics status register info from fp and return it 349 */ 350 351#if defined(lint) || defined(__lint) 352 353/* ARGSUSED */ 354uint64_t 355_fp_read_pgsr(kfpu_t *fp) 356{ return 0; } 357 358#else /* lint */ 359 360 ENTRY_NP(_fp_read_pgsr) 361 retl 362 rd %gsr, %o0 363 SET_SIZE(_fp_read_pgsr) 364 365#endif /* lint */ 366 367 368/* 369 * uint64_t 370 * get_gsr(kfpu_t *fp) 371 * Get the graphics status register info from fp and return it 372 */ 373 374#if defined(lint) || defined(__lint) 375 376/* ARGSUSED */ 377uint64_t 378get_gsr(kfpu_t *fp) 379{ return 0; } 380 381#else /* lint */ 382 383 ENTRY_NP(get_gsr) 384 retl 385 ldx [%o0 + FPU_GSR], %o0 386 SET_SIZE(get_gsr) 387 388#endif 389 390/* 391 * _fp_write_pgsr(uint64_t *buf, kfpu_t *fp) 392 * Set the graphics status register info to fp from buf 393 */ 394 395#if defined(lint) || defined(__lint) 396 397/* ARGSUSED */ 398void 399_fp_write_pgsr(uint64_t buf, kfpu_t *fp) 400{} 401 402#else /* lint */ 403 404 ENTRY_NP(_fp_write_pgsr) 405 retl 406 mov %o0, %gsr 407 SET_SIZE(_fp_write_pgsr) 408 409#endif /* lint */ 410 411/* 412 * set_gsr(uint64_t buf, kfpu_t *fp) 413 * Set the graphics status register info to fp from buf 414 */ 415 416#if defined(lint) || defined(__lint) 417 418/* ARGSUSED */ 419void 420set_gsr(uint64_t buf, kfpu_t *fp) 421{} 422 423#else /* lint */ 424 425 ENTRY_NP(set_gsr) 426 retl 427 stx %o0, [%o1 + FPU_GSR] 428 SET_SIZE(set_gsr) 429 430#endif /* lint */ 431 432#if defined(lint) || defined(__lint) 433void 434kdi_cpu_index(void) 435{ 436} 437 438#else /* lint */ 439 440 ENTRY_NP(kdi_cpu_index) 441 CPU_INDEX(%g1, %g2) 442 jmp %g7 443 nop 444 SET_SIZE(kdi_cpu_index) 445 446#endif /* lint */ 447 448/* 449 * The Spitfire floating point code has been changed not to use install/ 450 * save/restore/fork/freectx() because of the special memcpy library 451 * routines, which will lose too much performance if they have to go 452 * through the fp_disabled trap (which used to call installctx()). So 453 * now fp_save/fp_restore are called from resume, and they don't care 454 * whether floating point was enabled from the user program via the 455 * fp_enabled trap or from the memcpy library, which just turns on floating 456 * point in the fprs register itself. The new routine lwp_freeregs is 457 * called everywhere freectx is called, and code was added to the sun4u- 458 * specific version of lwp_forkregs (which is called everywhere forkctx 459 * is called) to handle forking the floating point registers. 460 * 461 * Note that for the fprs dirty upper/lower bits are not used for now, 462 * because the #instructions to determine if we need to use them is probably 463 * greater than the #insructions just using them. This is a possible future 464 * optimization, only do it with very careful benchmarking! 465 * 466 * The fp_fksave and and fp_load were split into two routines for the 467 * sake of efficiency between the getfpregs/xregs_getfpregs and 468 * setfpregs/xregs_setfpregs. But note that for saving and restoring 469 * context, both *must* happen. For prmachdep, aka access from [k]adb, 470 * it's OK if only one part happens. 471 */ 472 473/* 474 * fp_save(kfpu_t *fp) 475 * fp_fksave(kfpu_t *fp) 476 * Store the floating point registers. 477 */ 478 479#if defined(lint) || defined(__lint) 480 481/* ARGSUSED */ 482void 483fp_save(kfpu_t *fp) 484{} 485 486/* ARGSUSED */ 487void 488fp_fksave(kfpu_t *fp) 489{} 490 491#else /* lint */ 492 493 ENTRY_NP(fp_save) 494 ALTENTRY(fp_fksave) 495 BSTORE_FPREGS(%o0, %o1) ! store V9 regs 496 retl 497 stx %fsr, [%o0 + FPU_FSR] ! store fsr 498 SET_SIZE(fp_fksave) 499 SET_SIZE(fp_save) 500 501#endif /* lint */ 502 503/* 504 * fp_v8_fksave(kfpu_t *fp) 505 * 506 * This is like the above routine but only saves the lower half. 507 */ 508 509#if defined(lint) || defined(__lint) 510 511/* ARGSUSED */ 512void 513fp_v8_fksave(kfpu_t *fp) 514{} 515 516#else /* lint */ 517 518 ENTRY_NP(fp_v8_fksave) 519 BSTORE_V8_FPREGS(%o0, %o1) ! store V8 regs 520 retl 521 stx %fsr, [%o0 + FPU_FSR] ! store fsr 522 SET_SIZE(fp_v8_fksave) 523 524#endif /* lint */ 525 526/* 527 * fp_v8p_fksave(kfpu_t *fp) 528 * 529 * This is like the above routine but only saves the upper half. 530 */ 531 532#if defined(lint) || defined(__lint) 533 534/* ARGSUSED */ 535void 536fp_v8p_fksave(kfpu_t *fp) 537{} 538 539#else /* lint */ 540 541 ENTRY_NP(fp_v8p_fksave) 542 BSTORE_V8P_FPREGS(%o0, %o1) ! store V9 extra regs 543 retl 544 stx %fsr, [%o0 + FPU_FSR] ! store fsr 545 SET_SIZE(fp_v8p_fksave) 546 547#endif /* lint */ 548 549/* 550 * fp_restore(kfpu_t *fp) 551 */ 552 553#if defined(lint) || defined(__lint) 554 555/* ARGSUSED */ 556void 557fp_restore(kfpu_t *fp) 558{} 559 560#else /* lint */ 561 562 ENTRY_NP(fp_restore) 563 BLOAD_FPREGS(%o0, %o1) ! load V9 regs 564 retl 565 ldx [%o0 + FPU_FSR], %fsr ! restore fsr 566 SET_SIZE(fp_restore) 567 568#endif /* lint */ 569 570/* 571 * fp_v8_load(kfpu_t *fp) 572 */ 573 574#if defined(lint) || defined(__lint) 575 576/* ARGSUSED */ 577void 578fp_v8_load(kfpu_t *fp) 579{} 580 581#else /* lint */ 582 583 ENTRY_NP(fp_v8_load) 584 BLOAD_V8_FPREGS(%o0, %o1) ! load V8 regs 585 retl 586 ldx [%o0 + FPU_FSR], %fsr ! restore fsr 587 SET_SIZE(fp_v8_load) 588 589#endif /* lint */ 590 591/* 592 * fp_v8p_load(kfpu_t *fp) 593 */ 594 595#if defined(lint) || defined(__lint) 596 597/* ARGSUSED */ 598void 599fp_v8p_load(kfpu_t *fp) 600{} 601 602#else /* lint */ 603 604 ENTRY_NP(fp_v8p_load) 605 BLOAD_V8P_FPREGS(%o0, %o1) ! load V9 extra regs 606 retl 607 ldx [%o0 + FPU_FSR], %fsr ! restore fsr 608 SET_SIZE(fp_v8p_load) 609 610#endif /* lint */ 611