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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26#include <sys/param.h> 27#include <sys/errno.h> 28#include <sys/asm_linkage.h> 29#include <sys/vtrace.h> 30#include <sys/machthread.h> 31#include <sys/clock.h> 32#include <sys/asi.h> 33#include <sys/fsr.h> 34#include <sys/privregs.h> 35 36#include "assym.h" 37 38/* 39 * Pseudo-code to aid in understanding the control flow of the 40 * bcopy/copyin/copyout routines. 41 * 42 * On entry: 43 * 44 * ! Determine whether to use the FP register version 45 * ! or the leaf routine version depending on size 46 * ! of copy and flags. Set up error handling accordingly. 47 * ! The transition point depends on whether the src and 48 * ! dst addresses can be aligned to long word, word, 49 * ! half word, or byte boundaries. 50 * ! 51 * ! WARNING: <Register usage convention> 52 * ! For FP version, %l6 holds previous error handling and 53 * ! a flag: TRAMP_FLAG (low bits) 54 * ! for leaf routine version, %o4 holds those values. 55 * ! So either %l6 or %o4 is reserved and not available for 56 * ! any other use. 57 * 58 * if (length <= VIS_COPY_THRESHOLD) ! start with a quick test 59 * go to small_copy; ! to speed short copies 60 * 61 * ! src, dst long word alignable 62 * if (hw_copy_limit_8 == 0) ! hw_copy disabled 63 * go to small_copy; 64 * if (length <= hw_copy_limit_8) 65 * go to small_copy; 66 * go to FPBLK_copy; 67 * } 68 * if (src,dst not alignable) { 69 * if (hw_copy_limit_1 == 0) ! hw_copy disabled 70 * go to small_copy; 71 * if (length <= hw_copy_limit_1) 72 * go to small_copy; 73 * go to FPBLK_copy; 74 * } 75 * if (src,dst halfword alignable) { 76 * if (hw_copy_limit_2 == 0) ! hw_copy disabled 77 * go to small_copy; 78 * if (length <= hw_copy_limit_2) 79 * go to small_copy; 80 * go to FPBLK_copy; 81 * } 82 * if (src,dst word alignable) { 83 * if (hw_copy_limit_4 == 0) ! hw_copy disabled 84 * go to small_copy; 85 * if (length <= hw_copy_limit_4) 86 * go to small_copy; 87 * go to FPBLK_copy; 88 * } 89 * 90 * small_copy: 91 * Setup_leaf_rtn_error_handler; ! diffs for each entry point 92 * 93 * if (count <= 3) ! fast path for tiny copies 94 * go to sm_left; ! special finish up code 95 * else 96 * if (count > CHKSIZE) ! medium sized copies 97 * go to sm_med ! tuned by alignment 98 * if(src&dst not both word aligned) { 99 * sm_movebytes: 100 * move byte by byte in 4-way unrolled loop 101 * fall into sm_left; 102 * sm_left: 103 * move 0-3 bytes byte at a time as needed. 104 * restore error handler and exit. 105 * 106 * } else { ! src&dst are word aligned 107 * check for at least 8 bytes left, 108 * move word at a time, unrolled by 2 109 * when fewer than 8 bytes left, 110 * sm_half: move half word at a time while 2 or more bytes left 111 * sm_byte: move final byte if necessary 112 * sm_exit: 113 * restore error handler and exit. 114 * } 115 * 116 * ! Medium length cases with at least CHKSIZE bytes available 117 * ! method: line up src and dst as best possible, then 118 * ! move data in 4-way unrolled loops. 119 * 120 * sm_med: 121 * if(src&dst unalignable) 122 * go to sm_movebytes 123 * if(src&dst halfword alignable) 124 * go to sm_movehalf 125 * if(src&dst word alignable) 126 * go to sm_moveword 127 * ! fall into long word movement 128 * move bytes until src is word aligned 129 * if not long word aligned, move a word 130 * move long words in 4-way unrolled loop until < 32 bytes left 131 * move long words in 1-way unrolled loop until < 8 bytes left 132 * if zero bytes left, goto sm_exit 133 * if one byte left, go to sm_byte 134 * else go to sm_half 135 * 136 * sm_moveword: 137 * move bytes until src is word aligned 138 * move words in 4-way unrolled loop until < 16 bytes left 139 * move words in 1-way unrolled loop until < 4 bytes left 140 * if zero bytes left, goto sm_exit 141 * if one byte left, go to sm_byte 142 * else go to sm_half 143 * 144 * sm_movehalf: 145 * move a byte if needed to align src on halfword 146 * move halfwords in 4-way unrolled loop until < 8 bytes left 147 * if zero bytes left, goto sm_exit 148 * if one byte left, go to sm_byte 149 * else go to sm_half 150 * 151 * 152 * FPBLK_copy: 153 * %l6 = curthread->t_lofault; 154 * if (%l6 != NULL) { 155 * membar #Sync 156 * curthread->t_lofault = .copyerr; 157 * caller_error_handler = TRUE ! %l6 |= 2 158 * } 159 * 160 * ! for FPU testing we must not migrate cpus 161 * if (curthread->t_lwp == NULL) { 162 * ! Kernel threads do not have pcb's in which to store 163 * ! the floating point state, so disallow preemption during 164 * ! the copy. This also prevents cpu migration. 165 * kpreempt_disable(curthread); 166 * } else { 167 * thread_nomigrate(); 168 * } 169 * 170 * old_fprs = %fprs; 171 * old_gsr = %gsr; 172 * if (%fprs.fef) { 173 * %fprs.fef = 1; 174 * save current fpregs on stack using blockstore 175 * } else { 176 * %fprs.fef = 1; 177 * } 178 * 179 * 180 * do_blockcopy_here; 181 * 182 * In lofault handler: 183 * curthread->t_lofault = .copyerr2; 184 * Continue on with the normal exit handler 185 * 186 * On normal exit: 187 * %gsr = old_gsr; 188 * if (old_fprs & FPRS_FEF) 189 * restore fpregs from stack using blockload 190 * else 191 * zero fpregs 192 * %fprs = old_fprs; 193 * membar #Sync 194 * curthread->t_lofault = (%l6 & ~3); 195 * ! following test omitted from copyin/copyout as they 196 * ! will always have a current thread 197 * if (curthread->t_lwp == NULL) 198 * kpreempt_enable(curthread); 199 * else 200 * thread_allowmigrate(); 201 * return (0) 202 * 203 * In second lofault handler (.copyerr2): 204 * We've tried to restore fp state from the stack and failed. To 205 * prevent from returning with a corrupted fp state, we will panic. 206 */ 207 208/* 209 * Comments about optimization choices 210 * 211 * The initial optimization decision in this code is to determine 212 * whether to use the FP registers for a copy or not. If we don't 213 * use the FP registers, we can execute the copy as a leaf routine, 214 * saving a register save and restore. Also, less elaborate setup 215 * is required, allowing short copies to be completed more quickly. 216 * For longer copies, especially unaligned ones (where the src and 217 * dst do not align to allow simple ldx,stx operation), the FP 218 * registers allow much faster copy operations. 219 * 220 * The estimated extra cost of the FP path will vary depending on 221 * src/dst alignment, dst offset from the next 64 byte FPblock store 222 * boundary, remaining src data after the last full dst cache line is 223 * moved whether the FP registers need to be saved, and some other 224 * minor issues. The average additional overhead is estimated to be 225 * 400 clocks. Since each non-repeated/predicted tst and branch costs 226 * around 10 clocks, elaborate calculation would slow down to all 227 * longer copies and only benefit a small portion of medium sized 228 * copies. Rather than incur such cost, we chose fixed transition 229 * points for each of the alignment choices. 230 * 231 * For the inner loop, here is a comparison of the per cache line 232 * costs for each alignment when src&dst are in cache: 233 * 234 * byte aligned: 108 clocks slower for non-FPBLK 235 * half aligned: 44 clocks slower for non-FPBLK 236 * word aligned: 12 clocks slower for non-FPBLK 237 * long aligned: 4 clocks >>faster<< for non-FPBLK 238 * 239 * The long aligned loop runs faster because it does no prefetching. 240 * That wins if the data is not in cache or there is too little 241 * data to gain much benefit from prefetching. But when there 242 * is more data and that data is not in cache, failing to prefetch 243 * can run much slower. In addition, there is a 2 Kbyte store queue 244 * which will cause the non-FPBLK inner loop to slow for larger copies. 245 * The exact tradeoff is strongly load and application dependent, with 246 * increasing risk of a customer visible performance regression if the 247 * non-FPBLK code is used for larger copies. Studies of synthetic in-cache 248 * vs out-of-cache copy tests in user space suggest 1024 bytes as a safe 249 * upper limit for the non-FPBLK code. To minimize performance regression 250 * risk while still gaining the primary benefits of the improvements to 251 * the non-FPBLK code, we set an upper bound of 1024 bytes for the various 252 * hw_copy_limit_*. Later experimental studies using different values 253 * of hw_copy_limit_* can be used to make further adjustments if 254 * appropriate. 255 * 256 * hw_copy_limit_1 = src and dst are byte aligned but not halfword aligned 257 * hw_copy_limit_2 = src and dst are halfword aligned but not word aligned 258 * hw_copy_limit_4 = src and dst are word aligned but not longword aligned 259 * hw_copy_limit_8 = src and dst are longword aligned 260 * 261 * To say that src and dst are word aligned means that after 262 * some initial alignment activity of moving 0 to 3 bytes, 263 * both the src and dst will be on word boundaries so that 264 * word loads and stores may be used. 265 * 266 * Default values at May,2005 are: 267 * hw_copy_limit_1 = 256 268 * hw_copy_limit_2 = 512 269 * hw_copy_limit_4 = 1024 270 * hw_copy_limit_8 = 1024 (or 1536 on some systems) 271 * 272 * 273 * If hw_copy_limit_? is set to zero, then use of FPBLK copy is 274 * disabled for that alignment choice. 275 * If hw_copy_limit_? is set to a value between 1 and VIS_COPY_THRESHOLD (256) 276 * the value of VIS_COPY_THRESHOLD is used. 277 * It is not envisioned that hw_copy_limit_? will be changed in the field 278 * It is provided to allow for disabling FPBLK copies and to allow 279 * easy testing of alternate values on future HW implementations 280 * that might have different cache sizes, clock rates or instruction 281 * timing rules. 282 * 283 * Our first test for FPBLK copies vs non-FPBLK copies checks a minimum 284 * threshold to speedup all shorter copies (less than 256). That 285 * saves an alignment test, memory reference, and enabling test 286 * for all short copies, or an estimated 24 clocks. 287 * 288 * The order in which these limits are checked does matter since each 289 * non-predicted tst and branch costs around 10 clocks. 290 * If src and dst are randomly selected addresses, 291 * 4 of 8 will not be alignable. 292 * 2 of 8 will be half word alignable. 293 * 1 of 8 will be word alignable. 294 * 1 of 8 will be long word alignable. 295 * But, tests on running kernels show that src and dst to copy code 296 * are typically not on random alignments. Structure copies and 297 * copies of larger data sizes are often on long word boundaries. 298 * So we test the long word alignment case first, then 299 * the byte alignment, then halfword, then word alignment. 300 * 301 * Several times, tests for length are made to split the code 302 * into subcases. These tests often allow later tests to be 303 * avoided. For example, within the non-FPBLK copy, we first 304 * check for tiny copies of 3 bytes or less. That allows us 305 * to use a 4-way unrolled loop for the general byte copy case 306 * without a test on loop entry. 307 * We subdivide the non-FPBLK case further into CHKSIZE bytes and less 308 * vs longer cases. For the really short case, we don't attempt 309 * align src and dst. We try to minimize special case tests in 310 * the shortest loops as each test adds a significant percentage 311 * to the total time. 312 * 313 * For the medium sized cases, we allow ourselves to adjust the 314 * src and dst alignment and provide special cases for each of 315 * the four adjusted alignment cases. The CHKSIZE that was used 316 * to decide between short and medium size was chosen to be 39 317 * as that allows for the worst case of 7 bytes of alignment 318 * shift and 4 times 8 bytes for the first long word unrolling. 319 * That knowledge saves an initial test for length on entry into 320 * the medium cases. If the general loop unrolling factor were 321 * to be increases, this number would also need to be adjusted. 322 * 323 * For all cases in the non-FPBLK code where it is known that at 324 * least 4 chunks of data are available for movement, the 325 * loop is unrolled by four. This 4-way loop runs in 8 clocks 326 * or 2 clocks per data element. 327 * 328 * Instruction alignment is forced by used of .align 16 directives 329 * and nops which are not executed in the code. This 330 * combination of operations shifts the alignment of following 331 * loops to insure that loops are aligned so that their instructions 332 * fall within the minimum number of 4 instruction fetch groups. 333 * If instructions are inserted or removed between the .align 334 * instruction and the unrolled loops, then the alignment needs 335 * to be readjusted. Misaligned loops can add a clock per loop 336 * iteration to the loop timing. 337 * 338 * In a few cases, code is duplicated to avoid a branch. Since 339 * a non-predicted tst and branch takes 10 clocks, this savings 340 * is judged an appropriate time-space tradeoff. 341 * 342 * Within the FPBLK-code, the prefetch method in the inner 343 * loop needs to be explained as it is not standard. Two 344 * prefetches are issued for each cache line instead of one. 345 * The primary one is at the maximum reach of 8 cache lines. 346 * Most of the time, that maximum prefetch reach gives the 347 * cache line more time to reach the processor for systems with 348 * higher processor clocks. But, sometimes memory interference 349 * can cause that prefetch to be dropped. Putting a second 350 * prefetch at a reach of 5 cache lines catches the drops 351 * three iterations later and shows a measured improvement 352 * in performance over any similar loop with a single prefetch. 353 * The prefetches are placed in the loop so they overlap with 354 * non-memory instructions, so that there is no extra cost 355 * when the data is already in-cache. 356 * 357 */ 358 359/* 360 * Notes on preserving existing fp state and on membars. 361 * 362 * When a copyOP decides to use fp we may have to preserve existing 363 * floating point state. It is not the caller's state that we need to 364 * preserve - the rest of the kernel does not use fp and, anyway, fp 365 * registers are volatile across a call. Some examples: 366 * 367 * - userland has fp state and is interrupted (device interrupt 368 * or trap) and within the interrupt/trap handling we use 369 * bcopy() 370 * - another (higher level) interrupt or trap handler uses bcopy 371 * while a bcopy from an earlier interrupt is still active 372 * - an asynchronous error trap occurs while fp state exists (in 373 * userland or in kernel copy) and the tl0 component of the handling 374 * uses bcopy 375 * - a user process with fp state incurs a copy-on-write fault and 376 * hwblkpagecopy always uses fp 377 * 378 * We therefore need a per-call place in which to preserve fp state - 379 * using our stack is ideal (and since fp copy cannot be leaf optimized 380 * because of calls it makes, this is no hardship). 381 * 382 * When we have finished fp copy (with it's repeated block stores) 383 * we must membar #Sync so that our block stores may complete before 384 * we either restore the original fp state into the fp registers or 385 * return to a caller which may initiate other fp operations that could 386 * modify the fp regs we used before the block stores complete. 387 * 388 * Synchronous faults (eg, unresolvable DMMU miss) that occur while 389 * t_lofault is not NULL will not panic but will instead trampoline 390 * to the registered lofault handler. There is no need for any 391 * membars for these - eg, our store to t_lofault will always be visible to 392 * ourselves and it is our cpu which will take any trap. 393 * 394 * Asynchronous faults (eg, uncorrectable ECC error from memory) that occur 395 * while t_lofault is not NULL will also not panic. Since we're copying 396 * to or from userland the extent of the damage is known - the destination 397 * buffer is incomplete. So trap handlers will trampoline to the lofault 398 * handler in this case which should take some form of error action to 399 * avoid using the incomplete buffer. The trap handler also flags the 400 * fault so that later return-from-trap handling (for the trap that brought 401 * this thread into the kernel in the first place) can notify the process 402 * and reboot the system (or restart the service with Greenline/Contracts). 403 * 404 * Asynchronous faults (eg, uncorrectable ECC error from memory) can 405 * result in deferred error traps - the trap is taken sometime after 406 * the event and the trap PC may not be the PC of the faulting access. 407 * Delivery of such pending traps can be forced by a membar #Sync, acting 408 * as an "error barrier" in this role. To accurately apply the user/kernel 409 * separation described in the preceding paragraph we must force delivery 410 * of deferred traps affecting kernel state before we install a lofault 411 * handler (if we interpose a new lofault handler on an existing one there 412 * is no need to repeat this), and we must force delivery of deferred 413 * errors affecting the lofault-protected region before we clear t_lofault. 414 * Failure to do so results in lost kernel state being interpreted as 415 * affecting a copyin/copyout only, or of an error that really only 416 * affects copy data being interpreted as losing kernel state. 417 * 418 * Since the copy operations may preserve and later restore floating 419 * point state that does not belong to the caller (see examples above), 420 * we must be careful in how we do this in order to prevent corruption 421 * of another program. 422 * 423 * To make sure that floating point state is always saved and restored 424 * correctly, the following "big rules" must be followed when the floating 425 * point registers will be used: 426 * 427 * 1. %l6 always holds the caller's lofault handler. Also in this register, 428 * Bit 1 (FPUSED_FLAG) indicates that the floating point registers are in 429 * use. Bit 2 (TRAMP_FLAG) indicates that the call was to bcopy, and a 430 * lofault handler was set coming in. 431 * 432 * 2. The FPUSED flag indicates that all FP state has been successfully stored 433 * on the stack. It should not be set until this save has been completed. 434 * 435 * 3. The FPUSED flag should not be cleared on exit until all FP state has 436 * been restored from the stack. If an error occurs while restoring 437 * data from the stack, the error handler can check this flag to see if 438 * a restore is necessary. 439 * 440 * 4. Code run under the new lofault handler must be kept to a minimum. In 441 * particular, any calls to FP_ALLOWMIGRATE, which could result in a call 442 * to kpreempt(), should not be made until after the lofault handler has 443 * been restored. 444 */ 445 446/* 447 * VIS_COPY_THRESHOLD indicates the minimum number of bytes needed 448 * to "break even" using FP/VIS-accelerated memory operations. 449 * The FPBLK code assumes a minimum number of bytes are available 450 * to be moved on entry. Check that code carefully before 451 * reducing VIS_COPY_THRESHOLD below 256. 452 */ 453/* 454 * This shadows sys/machsystm.h which can't be included due to the lack of 455 * _ASM guards in include files it references. Change it here, change it there. 456 */ 457#define VIS_COPY_THRESHOLD 256 458 459/* 460 * TEST for very short copies 461 * Be aware that the maximum unroll for the short unaligned case 462 * is SHORTCOPY+1 463 */ 464#define SHORTCOPY 3 465#define CHKSIZE 39 466 467/* 468 * Indicates that we're to trampoline to the error handler. 469 * Entry points bcopy, copyin_noerr, and copyout_noerr use this flag. 470 * kcopy, copyout, xcopyout, copyin, and xcopyin do not set this flag. 471 */ 472#define FPUSED_FLAG 1 473#define TRAMP_FLAG 2 474#define MASK_FLAGS 3 475 476/* 477 * Number of outstanding prefetches. 478 * first prefetch moves data from L2 to L1 (n_reads) 479 * second prefetch moves data from memory to L2 (one_read) 480 */ 481#define OLYMPUS_C_PREFETCH 24 482#define OLYMPUS_C_2ND_PREFETCH 12 483 484#define VIS_BLOCKSIZE 64 485 486/* 487 * Size of stack frame in order to accomodate a 64-byte aligned 488 * floating-point register save area and 2 64-bit temp locations. 489 * All copy functions use two quadrants of fp registers; to assure a 490 * block-aligned two block buffer in which to save we must reserve 491 * three blocks on stack. Not all functions preserve %pfrs on stack 492 * or need to preserve %gsr but we use HWCOPYFRAMESIZE for all. 493 * 494 * _______________________________________ <-- %fp + STACK_BIAS 495 * | We may need to preserve 2 quadrants | 496 * | of fp regs, but since we do so with | 497 * | BST/BLD we need room in which to | 498 * | align to VIS_BLOCKSIZE bytes. So | 499 * | this area is 3 * VIS_BLOCKSIZE. | <-- - SAVED_FPREGS_OFFSET 500 * |-------------------------------------| 501 * | 8 bytes to save %fprs | <-- - SAVED_FPRS_OFFSET 502 * |-------------------------------------| 503 * | 8 bytes to save %gsr | <-- - SAVED_GSR_OFFSET 504 * --------------------------------------- 505 */ 506#define HWCOPYFRAMESIZE ((VIS_BLOCKSIZE * (2 + 1)) + (2 * 8)) 507#define SAVED_FPREGS_OFFSET (VIS_BLOCKSIZE * 3) 508#define SAVED_FPREGS_ADJUST ((VIS_BLOCKSIZE * 2) - 1) 509#define SAVED_FPRS_OFFSET (SAVED_FPREGS_OFFSET + 8) 510#define SAVED_GSR_OFFSET (SAVED_FPRS_OFFSET + 8) 511 512/* 513 * Common macros used by the various versions of the block copy 514 * routines in this file. 515 */ 516 517/* 518 * In FP copies if we do not have preserved data to restore over 519 * the fp regs we used then we must zero those regs to avoid 520 * exposing portions of the data to later threads (data security). 521 * 522 * Copy functions use either quadrants 1 and 3 or 2 and 4. 523 * 524 * FZEROQ1Q3: Zero quadrants 1 and 3, ie %f0 - %f15 and %f32 - %f47 525 * FZEROQ2Q4: Zero quadrants 2 and 4, ie %f16 - %f31 and %f48 - %f63 526 * 527 * The instructions below are quicker than repeated fzero instructions 528 * since they can dispatch down two fp pipelines. 529 */ 530#define FZEROQ1Q3 \ 531 fzero %f0 ;\ 532 fmovd %f0, %f2 ;\ 533 fmovd %f0, %f4 ;\ 534 fmovd %f0, %f6 ;\ 535 fmovd %f0, %f8 ;\ 536 fmovd %f0, %f10 ;\ 537 fmovd %f0, %f12 ;\ 538 fmovd %f0, %f14 ;\ 539 fmovd %f0, %f32 ;\ 540 fmovd %f0, %f34 ;\ 541 fmovd %f0, %f36 ;\ 542 fmovd %f0, %f38 ;\ 543 fmovd %f0, %f40 ;\ 544 fmovd %f0, %f42 ;\ 545 fmovd %f0, %f44 ;\ 546 fmovd %f0, %f46 547 548#define FZEROQ2Q4 \ 549 fzero %f16 ;\ 550 fmovd %f0, %f18 ;\ 551 fmovd %f0, %f20 ;\ 552 fmovd %f0, %f22 ;\ 553 fmovd %f0, %f24 ;\ 554 fmovd %f0, %f26 ;\ 555 fmovd %f0, %f28 ;\ 556 fmovd %f0, %f30 ;\ 557 fmovd %f0, %f48 ;\ 558 fmovd %f0, %f50 ;\ 559 fmovd %f0, %f52 ;\ 560 fmovd %f0, %f54 ;\ 561 fmovd %f0, %f56 ;\ 562 fmovd %f0, %f58 ;\ 563 fmovd %f0, %f60 ;\ 564 fmovd %f0, %f62 565 566/* 567 * Macros to save and restore quadrants 1 and 3 or 2 and 4 to/from the stack. 568 * Used to save and restore in-use fp registers when we want to use FP 569 * and find fp already in use and copy size still large enough to justify 570 * the additional overhead of this save and restore. 571 * 572 * A membar #Sync is needed before save to sync fp ops initiated before 573 * the call to the copy function (by whoever has fp in use); for example 574 * an earlier block load to the quadrant we are about to save may still be 575 * "in flight". A membar #Sync is required at the end of the save to 576 * sync our block store (the copy code is about to begin ldd's to the 577 * first quadrant). 578 * 579 * Similarly: a membar #Sync before restore allows the block stores of 580 * the copy operation to complete before we fill the quadrants with their 581 * original data, and a membar #Sync after restore lets the block loads 582 * of the restore complete before we return to whoever has the fp regs 583 * in use. To avoid repeated membar #Sync we make it the responsibility 584 * of the copy code to membar #Sync immediately after copy is complete 585 * and before using the BLD_*_FROMSTACK macro. 586 */ 587#define BST_FPQ1Q3_TOSTACK(tmp1) \ 588 /* membar #Sync */ ;\ 589 add %fp, STACK_BIAS - SAVED_FPREGS_ADJUST, tmp1 ;\ 590 and tmp1, -VIS_BLOCKSIZE, tmp1 /* block align */ ;\ 591 stda %f0, [tmp1]ASI_BLK_P ;\ 592 add tmp1, VIS_BLOCKSIZE, tmp1 ;\ 593 stda %f32, [tmp1]ASI_BLK_P ;\ 594 membar #Sync 595 596#define BLD_FPQ1Q3_FROMSTACK(tmp1) \ 597 /* membar #Sync - provided at copy completion */ ;\ 598 add %fp, STACK_BIAS - SAVED_FPREGS_ADJUST, tmp1 ;\ 599 and tmp1, -VIS_BLOCKSIZE, tmp1 /* block align */ ;\ 600 ldda [tmp1]ASI_BLK_P, %f0 ;\ 601 add tmp1, VIS_BLOCKSIZE, tmp1 ;\ 602 ldda [tmp1]ASI_BLK_P, %f32 ;\ 603 membar #Sync 604 605#define BST_FPQ2Q4_TOSTACK(tmp1) \ 606 /* membar #Sync */ ;\ 607 add %fp, STACK_BIAS - SAVED_FPREGS_ADJUST, tmp1 ;\ 608 and tmp1, -VIS_BLOCKSIZE, tmp1 /* block align */ ;\ 609 stda %f16, [tmp1]ASI_BLK_P ;\ 610 add tmp1, VIS_BLOCKSIZE, tmp1 ;\ 611 stda %f48, [tmp1]ASI_BLK_P ;\ 612 membar #Sync 613 614#define BLD_FPQ2Q4_FROMSTACK(tmp1) \ 615 /* membar #Sync - provided at copy completion */ ;\ 616 add %fp, STACK_BIAS - SAVED_FPREGS_ADJUST, tmp1 ;\ 617 and tmp1, -VIS_BLOCKSIZE, tmp1 /* block align */ ;\ 618 ldda [tmp1]ASI_BLK_P, %f16 ;\ 619 add tmp1, VIS_BLOCKSIZE, tmp1 ;\ 620 ldda [tmp1]ASI_BLK_P, %f48 ;\ 621 membar #Sync 622 623/* 624 * FP_NOMIGRATE and FP_ALLOWMIGRATE. Prevent migration (or, stronger, 625 * prevent preemption if there is no t_lwp to save FP state to on context 626 * switch) before commencing a FP copy, and reallow it on completion or 627 * in error trampoline paths when we were using FP copy. 628 * 629 * Both macros may call other functions, so be aware that all outputs are 630 * forfeit after using these macros. For this reason we do not pass registers 631 * to use - we just use any outputs we want. 632 * 633 * Pseudo code: 634 * 635 * FP_NOMIGRATE: 636 * 637 * if (curthread->t_lwp) { 638 * thread_nomigrate(); 639 * } else { 640 * kpreempt_disable(); 641 * } 642 * 643 * FP_ALLOWMIGRATE: 644 * 645 * if (curthread->t_lwp) { 646 * thread_allowmigrate(); 647 * } else { 648 * kpreempt_enable(); 649 * } 650 */ 651 652#define FP_NOMIGRATE(label1, label2) \ 653 ldn [THREAD_REG + T_LWP], %o0 ;\ 654 brz,a,pn %o0, label1/**/f ;\ 655 ldsb [THREAD_REG + T_PREEMPT], %o1 ;\ 656 call thread_nomigrate ;\ 657 nop ;\ 658 ba label2/**/f ;\ 659 nop ;\ 660label1: ;\ 661 inc %o1 ;\ 662 stb %o1, [THREAD_REG + T_PREEMPT] ;\ 663label2: 664 665#define FP_ALLOWMIGRATE(label1, label2) \ 666 ldn [THREAD_REG + T_LWP], %o0 ;\ 667 brz,a,pn %o0, label1/**/f ;\ 668 ldsb [THREAD_REG + T_PREEMPT], %o1 ;\ 669 call thread_allowmigrate ;\ 670 nop ;\ 671 ba label2/**/f ;\ 672 nop ;\ 673label1: ;\ 674 dec %o1 ;\ 675 brnz,pn %o1, label2/**/f ;\ 676 stb %o1, [THREAD_REG + T_PREEMPT] ;\ 677 ldn [THREAD_REG + T_CPU], %o0 ;\ 678 ldub [%o0 + CPU_KPRUNRUN], %o0 ;\ 679 brz,pt %o0, label2/**/f ;\ 680 nop ;\ 681 call kpreempt ;\ 682 rdpr %pil, %o0 ;\ 683label2: 684 685/* 686 * Copy a block of storage, returning an error code if `from' or 687 * `to' takes a kernel pagefault which cannot be resolved. 688 * Returns errno value on pagefault error, 0 if all ok 689 */ 690 691 .seg ".text" 692 .align 4 693 694 ENTRY(kcopy) 695 696 cmp %o2, VIS_COPY_THRESHOLD ! check for leaf rtn case 697 bleu,pt %ncc, .kcopy_small ! go to larger cases 698 xor %o0, %o1, %o3 ! are src, dst alignable? 699 btst 7, %o3 ! 700 bz,pt %ncc, .kcopy_8 ! check for longword alignment 701 nop 702 btst 1, %o3 ! 703 bz,pt %ncc, .kcopy_2 ! check for half-word 704 nop 705 sethi %hi(hw_copy_limit_1), %o3 ! Check copy limit 706 ld [%o3 + %lo(hw_copy_limit_1)], %o3 707 tst %o3 708 bz,pn %icc, .kcopy_small ! if zero, disable HW copy 709 cmp %o2, %o3 ! if length <= limit 710 bleu,pt %ncc, .kcopy_small ! go to small copy 711 nop 712 ba,pt %ncc, .kcopy_more ! otherwise go to large copy 713 nop 714.kcopy_2: 715 btst 3, %o3 ! 716 bz,pt %ncc, .kcopy_4 ! check for word alignment 717 nop 718 sethi %hi(hw_copy_limit_2), %o3 ! Check copy limit 719 ld [%o3 + %lo(hw_copy_limit_2)], %o3 720 tst %o3 721 bz,pn %icc, .kcopy_small ! if zero, disable HW copy 722 cmp %o2, %o3 ! if length <= limit 723 bleu,pt %ncc, .kcopy_small ! go to small copy 724 nop 725 ba,pt %ncc, .kcopy_more ! otherwise go to large copy 726 nop 727.kcopy_4: 728 ! already checked longword, must be word aligned 729 sethi %hi(hw_copy_limit_4), %o3 ! Check copy limit 730 ld [%o3 + %lo(hw_copy_limit_4)], %o3 731 tst %o3 732 bz,pn %icc, .kcopy_small ! if zero, disable HW copy 733 cmp %o2, %o3 ! if length <= limit 734 bleu,pt %ncc, .kcopy_small ! go to small copy 735 nop 736 ba,pt %ncc, .kcopy_more ! otherwise go to large copy 737 nop 738.kcopy_8: 739 sethi %hi(hw_copy_limit_8), %o3 ! Check copy limit 740 ld [%o3 + %lo(hw_copy_limit_8)], %o3 741 tst %o3 742 bz,pn %icc, .kcopy_small ! if zero, disable HW copy 743 cmp %o2, %o3 ! if length <= limit 744 bleu,pt %ncc, .kcopy_small ! go to small copy 745 nop 746 ba,pt %ncc, .kcopy_more ! otherwise go to large copy 747 nop 748 749.kcopy_small: 750 sethi %hi(.sm_copyerr), %o5 ! sm_copyerr is lofault value 751 or %o5, %lo(.sm_copyerr), %o5 752 ldn [THREAD_REG + T_LOFAULT], %o4 ! save existing handler 753 membar #Sync ! sync error barrier 754 ba,pt %ncc, .sm_do_copy ! common code 755 stn %o5, [THREAD_REG + T_LOFAULT] ! set t_lofault 756 757.kcopy_more: 758 save %sp, -SA(MINFRAME + HWCOPYFRAMESIZE), %sp 759 sethi %hi(.copyerr), %l7 ! copyerr is lofault value 760 or %l7, %lo(.copyerr), %l7 761 ldn [THREAD_REG + T_LOFAULT], %l6 ! save existing handler 762 membar #Sync ! sync error barrier 763 ba,pt %ncc, .do_copy ! common code 764 stn %l7, [THREAD_REG + T_LOFAULT] ! set t_lofault 765 766 767/* 768 * We got here because of a fault during bcopy_more, called from kcopy or bcopy. 769 * Errno value is in %g1. bcopy_more uses fp quadrants 1 and 3. 770 */ 771.copyerr: 772 set .copyerr2, %l0 773 membar #Sync ! sync error barrier 774 stn %l0, [THREAD_REG + T_LOFAULT] ! set t_lofault 775 btst FPUSED_FLAG, %l6 776 bz %ncc, 1f 777 and %l6, TRAMP_FLAG, %l0 ! copy trampoline flag to %l0 778 779 ldx [%fp + STACK_BIAS - SAVED_GSR_OFFSET], %o2 ! restore gsr 780 wr %o2, 0, %gsr 781 782 ld [%fp + STACK_BIAS - SAVED_FPRS_OFFSET], %o3 783 btst FPRS_FEF, %o3 784 bz,pt %icc, 4f 785 nop 786 787 BLD_FPQ1Q3_FROMSTACK(%o2) 788 789 ba,pt %ncc, 1f 790 wr %o3, 0, %fprs ! restore fprs 791 7924: 793 FZEROQ1Q3 794 wr %o3, 0, %fprs ! restore fprs 795 796 ! 797 ! Need to cater for the different expectations of kcopy 798 ! and bcopy. kcopy will *always* set a t_lofault handler 799 ! If it fires, we're expected to just return the error code 800 ! and *not* to invoke any existing error handler. As far as 801 ! bcopy is concerned, we only set t_lofault if there was an 802 ! existing lofault handler. In that case we're expected to 803 ! invoke the previously existing handler after resetting the 804 ! t_lofault value. 805 ! 8061: 807 andn %l6, MASK_FLAGS, %l6 ! turn trampoline flag off 808 membar #Sync ! sync error barrier 809 stn %l6, [THREAD_REG + T_LOFAULT] ! restore old t_lofault 810 FP_ALLOWMIGRATE(5, 6) 811 812 btst TRAMP_FLAG, %l0 813 bnz,pn %ncc, 3f 814 nop 815 ret 816 restore %g1, 0, %o0 817 8183: 819 ! 820 ! We're here via bcopy. There *must* have been an error handler 821 ! in place otherwise we would have died a nasty death already. 822 ! 823 jmp %l6 ! goto real handler 824 restore %g0, 0, %o0 ! dispose of copy window 825 826/* 827 * We got here because of a fault in .copyerr. We can't safely restore fp 828 * state, so we panic. 829 */ 830fp_panic_msg: 831 .asciz "Unable to restore fp state after copy operation" 832 833 .align 4 834.copyerr2: 835 set fp_panic_msg, %o0 836 call panic 837 nop 838 839/* 840 * We got here because of a fault during a small kcopy or bcopy. 841 * No floating point registers are used by the small copies. 842 * Errno value is in %g1. 843 */ 844.sm_copyerr: 8451: 846 btst TRAMP_FLAG, %o4 847 membar #Sync 848 andn %o4, TRAMP_FLAG, %o4 849 bnz,pn %ncc, 3f 850 stn %o4, [THREAD_REG + T_LOFAULT] ! restore old t_lofault 851 retl 852 mov %g1, %o0 8533: 854 jmp %o4 ! goto real handler 855 mov %g0, %o0 ! 856 857 SET_SIZE(kcopy) 858 859 860/* 861 * Copy a block of storage - must not overlap (from + len <= to). 862 * Registers: l6 - saved t_lofault 863 * (for short copies, o4 - saved t_lofault) 864 * 865 * Copy a page of memory. 866 * Assumes double word alignment and a count >= 256. 867 */ 868 869 ENTRY(bcopy) 870 871 cmp %o2, VIS_COPY_THRESHOLD ! check for leaf rtn case 872 bleu,pt %ncc, .bcopy_small ! go to larger cases 873 xor %o0, %o1, %o3 ! are src, dst alignable? 874 btst 7, %o3 ! 875 bz,pt %ncc, .bcopy_8 ! check for longword alignment 876 nop 877 btst 1, %o3 ! 878 bz,pt %ncc, .bcopy_2 ! check for half-word 879 nop 880 sethi %hi(hw_copy_limit_1), %o3 ! Check copy limit 881 ld [%o3 + %lo(hw_copy_limit_1)], %o3 882 tst %o3 883 bz,pn %icc, .bcopy_small ! if zero, disable HW copy 884 cmp %o2, %o3 ! if length <= limit 885 bleu,pt %ncc, .bcopy_small ! go to small copy 886 nop 887 ba,pt %ncc, .bcopy_more ! otherwise go to large copy 888 nop 889.bcopy_2: 890 btst 3, %o3 ! 891 bz,pt %ncc, .bcopy_4 ! check for word alignment 892 nop 893 sethi %hi(hw_copy_limit_2), %o3 ! Check copy limit 894 ld [%o3 + %lo(hw_copy_limit_2)], %o3 895 tst %o3 896 bz,pn %icc, .bcopy_small ! if zero, disable HW copy 897 cmp %o2, %o3 ! if length <= limit 898 bleu,pt %ncc, .bcopy_small ! go to small copy 899 nop 900 ba,pt %ncc, .bcopy_more ! otherwise go to large copy 901 nop 902.bcopy_4: 903 ! already checked longword, must be word aligned 904 sethi %hi(hw_copy_limit_4), %o3 ! Check copy limit 905 ld [%o3 + %lo(hw_copy_limit_4)], %o3 906 tst %o3 907 bz,pn %icc, .bcopy_small ! if zero, disable HW copy 908 cmp %o2, %o3 ! if length <= limit 909 bleu,pt %ncc, .bcopy_small ! go to small copy 910 nop 911 ba,pt %ncc, .bcopy_more ! otherwise go to large copy 912 nop 913.bcopy_8: 914 sethi %hi(hw_copy_limit_8), %o3 ! Check copy limit 915 ld [%o3 + %lo(hw_copy_limit_8)], %o3 916 tst %o3 917 bz,pn %icc, .bcopy_small ! if zero, disable HW copy 918 cmp %o2, %o3 ! if length <= limit 919 bleu,pt %ncc, .bcopy_small ! go to small copy 920 nop 921 ba,pt %ncc, .bcopy_more ! otherwise go to large copy 922 nop 923 924 .align 16 925.bcopy_small: 926 ldn [THREAD_REG + T_LOFAULT], %o4 ! save t_lofault 927 tst %o4 928 bz,pt %icc, .sm_do_copy 929 nop 930 sethi %hi(.sm_copyerr), %o5 931 or %o5, %lo(.sm_copyerr), %o5 932 membar #Sync ! sync error barrier 933 stn %o5, [THREAD_REG + T_LOFAULT] ! install new vector 934 or %o4, TRAMP_FLAG, %o4 ! error should trampoline 935.sm_do_copy: 936 cmp %o2, SHORTCOPY ! check for really short case 937 bleu,pt %ncc, .bc_sm_left ! 938 cmp %o2, CHKSIZE ! check for medium length cases 939 bgu,pn %ncc, .bc_med ! 940 or %o0, %o1, %o3 ! prepare alignment check 941 andcc %o3, 0x3, %g0 ! test for alignment 942 bz,pt %ncc, .bc_sm_word ! branch to word aligned case 943.bc_sm_movebytes: 944 sub %o2, 3, %o2 ! adjust count to allow cc zero test 945.bc_sm_notalign4: 946 ldub [%o0], %o3 ! read byte 947 stb %o3, [%o1] ! write byte 948 subcc %o2, 4, %o2 ! reduce count by 4 949 ldub [%o0 + 1], %o3 ! repeat for a total of 4 bytes 950 add %o0, 4, %o0 ! advance SRC by 4 951 stb %o3, [%o1 + 1] 952 ldub [%o0 - 2], %o3 953 add %o1, 4, %o1 ! advance DST by 4 954 stb %o3, [%o1 - 2] 955 ldub [%o0 - 1], %o3 956 bgt,pt %ncc, .bc_sm_notalign4 ! loop til 3 or fewer bytes remain 957 stb %o3, [%o1 - 1] 958 add %o2, 3, %o2 ! restore count 959.bc_sm_left: 960 tst %o2 961 bz,pt %ncc, .bc_sm_exit ! check for zero length 962 deccc %o2 ! reduce count for cc test 963 ldub [%o0], %o3 ! move one byte 964 bz,pt %ncc, .bc_sm_exit 965 stb %o3, [%o1] 966 ldub [%o0 + 1], %o3 ! move another byte 967 deccc %o2 ! check for more 968 bz,pt %ncc, .bc_sm_exit 969 stb %o3, [%o1 + 1] 970 ldub [%o0 + 2], %o3 ! move final byte 971 ba,pt %ncc, .bc_sm_exit 972 stb %o3, [%o1 + 2] 973 .align 16 974 nop ! instruction alignment 975 ! see discussion at start of file 976.bc_sm_words: 977 lduw [%o0], %o3 ! read word 978.bc_sm_wordx: 979 subcc %o2, 8, %o2 ! update count 980 stw %o3, [%o1] ! write word 981 add %o0, 8, %o0 ! update SRC 982 lduw [%o0 - 4], %o3 ! read word 983 add %o1, 8, %o1 ! update DST 984 bgt,pt %ncc, .bc_sm_words ! loop til done 985 stw %o3, [%o1 - 4] ! write word 986 addcc %o2, 7, %o2 ! restore count 987 bz,pt %ncc, .bc_sm_exit 988 deccc %o2 989 bz,pt %ncc, .bc_sm_byte 990.bc_sm_half: 991 subcc %o2, 2, %o2 ! reduce count by 2 992 add %o0, 2, %o0 ! advance SRC by 2 993 lduh [%o0 - 2], %o3 ! read half word 994 add %o1, 2, %o1 ! advance DST by 2 995 bgt,pt %ncc, .bc_sm_half ! loop til done 996 sth %o3, [%o1 - 2] ! write half word 997 addcc %o2, 1, %o2 ! restore count 998 bz,pt %ncc, .bc_sm_exit 999 nop 1000.bc_sm_byte: 1001 ldub [%o0], %o3 1002 ba,pt %ncc, .bc_sm_exit 1003 stb %o3, [%o1] 1004 1005.bc_sm_word: 1006 subcc %o2, 4, %o2 ! update count 1007 bgt,pt %ncc, .bc_sm_wordx 1008 lduw [%o0], %o3 ! read word 1009 addcc %o2, 3, %o2 ! restore count 1010 bz,pt %ncc, .bc_sm_exit 1011 stw %o3, [%o1] ! write word 1012 deccc %o2 ! reduce count for cc test 1013 ldub [%o0 + 4], %o3 ! load one byte 1014 bz,pt %ncc, .bc_sm_exit 1015 stb %o3, [%o1 + 4] ! store one byte 1016 ldub [%o0 + 5], %o3 ! load second byte 1017 deccc %o2 1018 bz,pt %ncc, .bc_sm_exit 1019 stb %o3, [%o1 + 5] ! store second byte 1020 ldub [%o0 + 6], %o3 ! load third byte 1021 stb %o3, [%o1 + 6] ! store third byte 1022.bc_sm_exit: 1023 ldn [THREAD_REG + T_LOFAULT], %o3 1024 brz,pt %o3, .bc_sm_done 1025 nop 1026 membar #Sync ! sync error barrier 1027 andn %o4, TRAMP_FLAG, %o4 1028 stn %o4, [THREAD_REG + T_LOFAULT] ! restore old t_lofault 1029.bc_sm_done: 1030 retl 1031 mov %g0, %o0 ! return 0 1032 1033 .align 16 1034.bc_med: 1035 xor %o0, %o1, %o3 ! setup alignment check 1036 btst 1, %o3 1037 bnz,pt %ncc, .bc_sm_movebytes ! unaligned 1038 nop 1039 btst 3, %o3 1040 bnz,pt %ncc, .bc_med_half ! halfword aligned 1041 nop 1042 btst 7, %o3 1043 bnz,pt %ncc, .bc_med_word ! word aligned 1044 nop 1045.bc_med_long: 1046 btst 3, %o0 ! check for 1047 bz,pt %ncc, .bc_med_long1 ! word alignment 1048 nop 1049.bc_med_long0: 1050 ldub [%o0], %o3 ! load one byte 1051 inc %o0 1052 stb %o3,[%o1] ! store byte 1053 inc %o1 1054 btst 3, %o0 1055 bnz,pt %ncc, .bc_med_long0 1056 dec %o2 1057.bc_med_long1: ! word aligned 1058 btst 7, %o0 ! check for long word 1059 bz,pt %ncc, .bc_med_long2 1060 nop 1061 lduw [%o0], %o3 ! load word 1062 add %o0, 4, %o0 ! advance SRC by 4 1063 stw %o3, [%o1] ! store word 1064 add %o1, 4, %o1 ! advance DST by 4 1065 sub %o2, 4, %o2 ! reduce count by 4 1066! 1067! Now long word aligned and have at least 32 bytes to move 1068! 1069.bc_med_long2: 1070 sub %o2, 31, %o2 ! adjust count to allow cc zero test 1071.bc_med_lmove: 1072 ldx [%o0], %o3 ! read long word 1073 stx %o3, [%o1] ! write long word 1074 subcc %o2, 32, %o2 ! reduce count by 32 1075 ldx [%o0 + 8], %o3 ! repeat for a total for 4 long words 1076 add %o0, 32, %o0 ! advance SRC by 32 1077 stx %o3, [%o1 + 8] 1078 ldx [%o0 - 16], %o3 1079 add %o1, 32, %o1 ! advance DST by 32 1080 stx %o3, [%o1 - 16] 1081 ldx [%o0 - 8], %o3 1082 bgt,pt %ncc, .bc_med_lmove ! loop til 31 or fewer bytes left 1083 stx %o3, [%o1 - 8] 1084 addcc %o2, 24, %o2 ! restore count to long word offset 1085 ble,pt %ncc, .bc_med_lextra ! check for more long words to move 1086 nop 1087.bc_med_lword: 1088 ldx [%o0], %o3 ! read long word 1089 subcc %o2, 8, %o2 ! reduce count by 8 1090 stx %o3, [%o1] ! write long word 1091 add %o0, 8, %o0 ! advance SRC by 8 1092 bgt,pt %ncc, .bc_med_lword ! loop til 7 or fewer bytes left 1093 add %o1, 8, %o1 ! advance DST by 8 1094.bc_med_lextra: 1095 addcc %o2, 7, %o2 ! restore rest of count 1096 bz,pt %ncc, .bc_sm_exit ! if zero, then done 1097 deccc %o2 1098 bz,pt %ncc, .bc_sm_byte 1099 nop 1100 ba,pt %ncc, .bc_sm_half 1101 nop 1102 1103 .align 16 1104.bc_med_word: 1105 btst 3, %o0 ! check for 1106 bz,pt %ncc, .bc_med_word1 ! word alignment 1107 nop 1108.bc_med_word0: 1109 ldub [%o0], %o3 ! load one byte 1110 inc %o0 1111 stb %o3,[%o1] ! store byte 1112 inc %o1 1113 btst 3, %o0 1114 bnz,pt %ncc, .bc_med_word0 1115 dec %o2 1116! 1117! Now word aligned and have at least 36 bytes to move 1118! 1119.bc_med_word1: 1120 sub %o2, 15, %o2 ! adjust count to allow cc zero test 1121.bc_med_wmove: 1122 lduw [%o0], %o3 ! read word 1123 stw %o3, [%o1] ! write word 1124 subcc %o2, 16, %o2 ! reduce count by 16 1125 lduw [%o0 + 4], %o3 ! repeat for a total for 4 words 1126 add %o0, 16, %o0 ! advance SRC by 16 1127 stw %o3, [%o1 + 4] 1128 lduw [%o0 - 8], %o3 1129 add %o1, 16, %o1 ! advance DST by 16 1130 stw %o3, [%o1 - 8] 1131 lduw [%o0 - 4], %o3 1132 bgt,pt %ncc, .bc_med_wmove ! loop til 15 or fewer bytes left 1133 stw %o3, [%o1 - 4] 1134 addcc %o2, 12, %o2 ! restore count to word offset 1135 ble,pt %ncc, .bc_med_wextra ! check for more words to move 1136 nop 1137.bc_med_word2: 1138 lduw [%o0], %o3 ! read word 1139 subcc %o2, 4, %o2 ! reduce count by 4 1140 stw %o3, [%o1] ! write word 1141 add %o0, 4, %o0 ! advance SRC by 4 1142 bgt,pt %ncc, .bc_med_word2 ! loop til 3 or fewer bytes left 1143 add %o1, 4, %o1 ! advance DST by 4 1144.bc_med_wextra: 1145 addcc %o2, 3, %o2 ! restore rest of count 1146 bz,pt %ncc, .bc_sm_exit ! if zero, then done 1147 deccc %o2 1148 bz,pt %ncc, .bc_sm_byte 1149 nop 1150 ba,pt %ncc, .bc_sm_half 1151 nop 1152 1153 .align 16 1154.bc_med_half: 1155 btst 1, %o0 ! check for 1156 bz,pt %ncc, .bc_med_half1 ! half word alignment 1157 nop 1158 ldub [%o0], %o3 ! load one byte 1159 inc %o0 1160 stb %o3,[%o1] ! store byte 1161 inc %o1 1162 dec %o2 1163! 1164! Now half word aligned and have at least 38 bytes to move 1165! 1166.bc_med_half1: 1167 sub %o2, 7, %o2 ! adjust count to allow cc zero test 1168.bc_med_hmove: 1169 lduh [%o0], %o3 ! read half word 1170 sth %o3, [%o1] ! write half word 1171 subcc %o2, 8, %o2 ! reduce count by 8 1172 lduh [%o0 + 2], %o3 ! repeat for a total for 4 halfwords 1173 add %o0, 8, %o0 ! advance SRC by 8 1174 sth %o3, [%o1 + 2] 1175 lduh [%o0 - 4], %o3 1176 add %o1, 8, %o1 ! advance DST by 8 1177 sth %o3, [%o1 - 4] 1178 lduh [%o0 - 2], %o3 1179 bgt,pt %ncc, .bc_med_hmove ! loop til 7 or fewer bytes left 1180 sth %o3, [%o1 - 2] 1181 addcc %o2, 7, %o2 ! restore count 1182 bz,pt %ncc, .bc_sm_exit 1183 deccc %o2 1184 bz,pt %ncc, .bc_sm_byte 1185 nop 1186 ba,pt %ncc, .bc_sm_half 1187 nop 1188 1189 SET_SIZE(bcopy) 1190 1191/* 1192 * The _more entry points are not intended to be used directly by 1193 * any caller from outside this file. They are provided to allow 1194 * profiling and dtrace of the portions of the copy code that uses 1195 * the floating point registers. 1196 * This entry is particularly important as DTRACE (at least as of 1197 * 4/2004) does not support leaf functions. 1198 */ 1199 1200 ENTRY(bcopy_more) 1201.bcopy_more: 1202 prefetch [%o0], #n_reads 1203 save %sp, -SA(MINFRAME + HWCOPYFRAMESIZE), %sp 1204 ldn [THREAD_REG + T_LOFAULT], %l6 ! save t_lofault 1205 tst %l6 1206 bz,pt %ncc, .do_copy 1207 nop 1208 sethi %hi(.copyerr), %o2 1209 or %o2, %lo(.copyerr), %o2 1210 membar #Sync ! sync error barrier 1211 stn %o2, [THREAD_REG + T_LOFAULT] ! install new vector 1212 ! 1213 ! We've already captured whether t_lofault was zero on entry. 1214 ! We need to mark ourselves as being from bcopy since both 1215 ! kcopy and bcopy use the same code path. If TRAMP_FLAG is set 1216 ! and the saved lofault was zero, we won't reset lofault on 1217 ! returning. 1218 ! 1219 or %l6, TRAMP_FLAG, %l6 1220 1221/* 1222 * Copies that reach here are larger than VIS_COPY_THRESHOLD bytes 1223 * Also, use of FP registers has been tested to be enabled 1224 */ 1225.do_copy: 1226 FP_NOMIGRATE(6, 7) 1227 1228 rd %fprs, %o2 ! check for unused fp 1229 st %o2, [%fp + STACK_BIAS - SAVED_FPRS_OFFSET] ! save orig %fprs 1230 btst FPRS_FEF, %o2 1231 bz,a,pt %icc, .do_blockcopy 1232 wr %g0, FPRS_FEF, %fprs 1233 1234 BST_FPQ1Q3_TOSTACK(%o2) 1235 1236.do_blockcopy: 1237 rd %gsr, %o2 1238 stx %o2, [%fp + STACK_BIAS - SAVED_GSR_OFFSET] ! save gsr 1239 or %l6, FPUSED_FLAG, %l6 1240 1241#define REALSRC %i0 1242#define DST %i1 1243#define CNT %i2 1244#define SRC %i3 1245#define TMP %i5 1246 1247 andcc DST, VIS_BLOCKSIZE - 1, TMP 1248 bz,pt %ncc, 2f 1249 neg TMP 1250 add TMP, VIS_BLOCKSIZE, TMP 1251 1252 ! TMP = bytes required to align DST on FP_BLOCK boundary 1253 ! Using SRC as a tmp here 1254 cmp TMP, 3 1255 bleu,pt %ncc, 1f 1256 sub CNT,TMP,CNT ! adjust main count 1257 sub TMP, 3, TMP ! adjust for end of loop test 1258.bc_blkalign: 1259 ldub [REALSRC], SRC ! move 4 bytes per loop iteration 1260 stb SRC, [DST] 1261 subcc TMP, 4, TMP 1262 ldub [REALSRC + 1], SRC 1263 add REALSRC, 4, REALSRC 1264 stb SRC, [DST + 1] 1265 ldub [REALSRC - 2], SRC 1266 add DST, 4, DST 1267 stb SRC, [DST - 2] 1268 ldub [REALSRC - 1], SRC 1269 bgu,pt %ncc, .bc_blkalign 1270 stb SRC, [DST - 1] 1271 1272 addcc TMP, 3, TMP ! restore count adjustment 1273 bz,pt %ncc, 2f ! no bytes left? 1274 nop 12751: ldub [REALSRC], SRC 1276 inc REALSRC 1277 inc DST 1278 deccc TMP 1279 bgu %ncc, 1b 1280 stb SRC, [DST - 1] 1281 12822: 1283 membar #StoreLoad 1284 andn REALSRC, 0x7, SRC 1285 1286 ! SRC - 8-byte aligned 1287 ! DST - 64-byte aligned 1288 ldd [SRC], %f0 1289 prefetch [SRC + (1 * VIS_BLOCKSIZE)], #n_reads 1290 alignaddr REALSRC, %g0, %g0 1291 ldd [SRC + 0x08], %f2 1292 prefetch [SRC + (2 * VIS_BLOCKSIZE)], #n_reads 1293 faligndata %f0, %f2, %f32 1294 ldd [SRC + 0x10], %f4 1295 prefetch [SRC + (3 * VIS_BLOCKSIZE)], #n_reads 1296 faligndata %f2, %f4, %f34 1297 ldd [SRC + 0x18], %f6 1298 prefetch [SRC + (4 * VIS_BLOCKSIZE)], #one_read 1299 faligndata %f4, %f6, %f36 1300 ldd [SRC + 0x20], %f8 1301 prefetch [SRC + (8 * VIS_BLOCKSIZE)], #one_read 1302 faligndata %f6, %f8, %f38 1303 ldd [SRC + 0x28], %f10 1304 prefetch [SRC + (12 * VIS_BLOCKSIZE)], #one_read 1305 faligndata %f8, %f10, %f40 1306 ldd [SRC + 0x30], %f12 1307 prefetch [SRC + (16 * VIS_BLOCKSIZE)], #one_read 1308 faligndata %f10, %f12, %f42 1309 ldd [SRC + 0x38], %f14 1310 ldd [SRC + VIS_BLOCKSIZE], %f0 1311 sub CNT, VIS_BLOCKSIZE, CNT 1312 add SRC, VIS_BLOCKSIZE, SRC 1313 prefetch [SRC + (19 * VIS_BLOCKSIZE)], #one_read 1314 add REALSRC, VIS_BLOCKSIZE, REALSRC 1315 ba,pt %ncc, 1f 1316 prefetch [SRC + (23 * VIS_BLOCKSIZE)], #one_read 1317 .align 32 13181: 1319 ldd [SRC + 0x08], %f2 1320 faligndata %f12, %f14, %f44 1321 ldd [SRC + 0x10], %f4 1322 faligndata %f14, %f0, %f46 1323 stda %f32, [DST]ASI_BLK_P 1324 ldd [SRC + 0x18], %f6 1325 faligndata %f0, %f2, %f32 1326 ldd [SRC + 0x20], %f8 1327 faligndata %f2, %f4, %f34 1328 ldd [SRC + 0x28], %f10 1329 faligndata %f4, %f6, %f36 1330 ldd [SRC + 0x30], %f12 1331 faligndata %f6, %f8, %f38 1332 sub CNT, VIS_BLOCKSIZE, CNT 1333 ldd [SRC + 0x38], %f14 1334 faligndata %f8, %f10, %f40 1335 add DST, VIS_BLOCKSIZE, DST 1336 ldd [SRC + VIS_BLOCKSIZE], %f0 1337 faligndata %f10, %f12, %f42 1338 add REALSRC, VIS_BLOCKSIZE, REALSRC 1339 prefetch [SRC + (3 * VIS_BLOCKSIZE)], #n_reads 1340 add SRC, VIS_BLOCKSIZE, SRC 1341 prefetch [SRC + ((OLYMPUS_C_PREFETCH) * VIS_BLOCKSIZE)], #one_read 1342 cmp CNT, VIS_BLOCKSIZE + 8 1343 bgu,pt %ncc, 1b 1344 prefetch [SRC + ((OLYMPUS_C_2ND_PREFETCH) * VIS_BLOCKSIZE)], #one_read 1345 1346 ! only if REALSRC & 0x7 is 0 1347 cmp CNT, VIS_BLOCKSIZE 1348 bne %ncc, 3f 1349 andcc REALSRC, 0x7, %g0 1350 bz,pt %ncc, 2f 1351 nop 13523: 1353 faligndata %f12, %f14, %f44 1354 faligndata %f14, %f0, %f46 1355 stda %f32, [DST]ASI_BLK_P 1356 add DST, VIS_BLOCKSIZE, DST 1357 ba,pt %ncc, 3f 1358 nop 13592: 1360 ldd [SRC + 0x08], %f2 1361 fsrc1 %f12, %f44 1362 ldd [SRC + 0x10], %f4 1363 fsrc1 %f14, %f46 1364 stda %f32, [DST]ASI_BLK_P 1365 ldd [SRC + 0x18], %f6 1366 fsrc1 %f0, %f32 1367 ldd [SRC + 0x20], %f8 1368 fsrc1 %f2, %f34 1369 ldd [SRC + 0x28], %f10 1370 fsrc1 %f4, %f36 1371 ldd [SRC + 0x30], %f12 1372 fsrc1 %f6, %f38 1373 ldd [SRC + 0x38], %f14 1374 fsrc1 %f8, %f40 1375 sub CNT, VIS_BLOCKSIZE, CNT 1376 add DST, VIS_BLOCKSIZE, DST 1377 add SRC, VIS_BLOCKSIZE, SRC 1378 add REALSRC, VIS_BLOCKSIZE, REALSRC 1379 fsrc1 %f10, %f42 1380 fsrc1 %f12, %f44 1381 fsrc1 %f14, %f46 1382 stda %f32, [DST]ASI_BLK_P 1383 add DST, VIS_BLOCKSIZE, DST 1384 ba,a,pt %ncc, .bcb_exit 1385 nop 1386 13873: tst CNT 1388 bz,a,pt %ncc, .bcb_exit 1389 nop 1390 13915: ldub [REALSRC], TMP 1392 inc REALSRC 1393 inc DST 1394 deccc CNT 1395 bgu %ncc, 5b 1396 stb TMP, [DST - 1] 1397.bcb_exit: 1398 membar #Sync 1399 1400 ldx [%fp + STACK_BIAS - SAVED_GSR_OFFSET], %o2 ! restore gsr 1401 wr %o2, 0, %gsr 1402 1403 ld [%fp + STACK_BIAS - SAVED_FPRS_OFFSET], %o3 1404 btst FPRS_FEF, %o3 1405 bz,pt %icc, 4f 1406 nop 1407 1408 BLD_FPQ1Q3_FROMSTACK(%o2) 1409 1410 ba,pt %ncc, 2f 1411 wr %o3, 0, %fprs ! restore fprs 14124: 1413 FZEROQ1Q3 1414 wr %o3, 0, %fprs ! restore fprs 14152: 1416 membar #Sync ! sync error barrier 1417 andn %l6, MASK_FLAGS, %l6 1418 stn %l6, [THREAD_REG + T_LOFAULT] ! restore old t_lofault 1419 FP_ALLOWMIGRATE(5, 6) 1420 ret 1421 restore %g0, 0, %o0 1422 1423 SET_SIZE(bcopy_more) 1424 1425/* 1426 * Block copy with possibly overlapped operands. 1427 */ 1428 1429 ENTRY(ovbcopy) 1430 tst %o2 ! check count 1431 bgu,a %ncc, 1f ! nothing to do or bad arguments 1432 subcc %o0, %o1, %o3 ! difference of from and to address 1433 1434 retl ! return 1435 nop 14361: 1437 bneg,a %ncc, 2f 1438 neg %o3 ! if < 0, make it positive 14392: cmp %o2, %o3 ! cmp size and abs(from - to) 1440 bleu %ncc, bcopy ! if size <= abs(diff): use bcopy, 1441 .empty ! no overlap 1442 cmp %o0, %o1 ! compare from and to addresses 1443 blu %ncc, .ov_bkwd ! if from < to, copy backwards 1444 nop 1445 ! 1446 ! Copy forwards. 1447 ! 1448.ov_fwd: 1449 ldub [%o0], %o3 ! read from address 1450 inc %o0 ! inc from address 1451 stb %o3, [%o1] ! write to address 1452 deccc %o2 ! dec count 1453 bgu %ncc, .ov_fwd ! loop till done 1454 inc %o1 ! inc to address 1455 1456 retl ! return 1457 nop 1458 ! 1459 ! Copy backwards. 1460 ! 1461.ov_bkwd: 1462 deccc %o2 ! dec count 1463 ldub [%o0 + %o2], %o3 ! get byte at end of src 1464 bgu %ncc, .ov_bkwd ! loop till done 1465 stb %o3, [%o1 + %o2] ! delay slot, store at end of dst 1466 1467 retl ! return 1468 nop 1469 1470 SET_SIZE(ovbcopy) 1471 1472 1473/* 1474 * hwblkpagecopy() 1475 * 1476 * Copies exactly one page. This routine assumes the caller (ppcopy) 1477 * has already disabled kernel preemption and has checked 1478 * use_hw_bcopy. Preventing preemption also prevents cpu migration. 1479 */ 1480 ENTRY(hwblkpagecopy) 1481 ! get another window w/space for three aligned blocks of saved fpregs 1482 prefetch [%o0], #n_reads 1483 save %sp, -SA(MINFRAME + HWCOPYFRAMESIZE), %sp 1484 1485 ! %i0 - source address (arg) 1486 ! %i1 - destination address (arg) 1487 ! %i2 - length of region (not arg) 1488 ! %l0 - saved fprs 1489 ! %l1 - pointer to saved fpregs 1490 1491 rd %fprs, %l0 ! check for unused fp 1492 btst FPRS_FEF, %l0 1493 bz,a,pt %icc, 1f 1494 wr %g0, FPRS_FEF, %fprs 1495 1496 BST_FPQ1Q3_TOSTACK(%l1) 1497 14981: set PAGESIZE, CNT 1499 mov REALSRC, SRC 1500 1501 ldd [SRC], %f0 1502 prefetch [SRC + (1 * VIS_BLOCKSIZE)], #n_reads 1503 ldd [SRC + 0x08], %f2 1504 prefetch [SRC + (2 * VIS_BLOCKSIZE)], #n_reads 1505 fmovd %f0, %f32 1506 ldd [SRC + 0x10], %f4 1507 prefetch [SRC + (3 * VIS_BLOCKSIZE)], #n_reads 1508 fmovd %f2, %f34 1509 ldd [SRC + 0x18], %f6 1510 prefetch [SRC + (4 * VIS_BLOCKSIZE)], #one_read 1511 fmovd %f4, %f36 1512 ldd [SRC + 0x20], %f8 1513 prefetch [SRC + (8 * VIS_BLOCKSIZE)], #one_read 1514 fmovd %f6, %f38 1515 ldd [SRC + 0x28], %f10 1516 prefetch [SRC + (12 * VIS_BLOCKSIZE)], #one_read 1517 fmovd %f8, %f40 1518 ldd [SRC + 0x30], %f12 1519 prefetch [SRC + (16 * VIS_BLOCKSIZE)], #one_read 1520 fmovd %f10, %f42 1521 ldd [SRC + 0x38], %f14 1522 ldd [SRC + VIS_BLOCKSIZE], %f0 1523 sub CNT, VIS_BLOCKSIZE, CNT 1524 add SRC, VIS_BLOCKSIZE, SRC 1525 prefetch [SRC + (19 * VIS_BLOCKSIZE)], #one_read 1526 ba,pt %ncc, 2f 1527 prefetch [SRC + (23 * VIS_BLOCKSIZE)], #one_read 1528 .align 32 15292: 1530 ldd [SRC + 0x08], %f2 1531 fmovd %f12, %f44 1532 ldd [SRC + 0x10], %f4 1533 fmovd %f14, %f46 1534 stda %f32, [DST]ASI_BLK_P 1535 ldd [SRC + 0x18], %f6 1536 fmovd %f0, %f32 1537 ldd [SRC + 0x20], %f8 1538 fmovd %f2, %f34 1539 ldd [SRC + 0x28], %f10 1540 fmovd %f4, %f36 1541 ldd [SRC + 0x30], %f12 1542 fmovd %f6, %f38 1543 ldd [SRC + 0x38], %f14 1544 fmovd %f8, %f40 1545 ldd [SRC + VIS_BLOCKSIZE], %f0 1546 fmovd %f10, %f42 1547 sub CNT, VIS_BLOCKSIZE, CNT 1548 prefetch [SRC + (3 * VIS_BLOCKSIZE)], #n_reads 1549 add DST, VIS_BLOCKSIZE, DST 1550 prefetch [SRC + ((OLYMPUS_C_PREFETCH) * VIS_BLOCKSIZE)], #one_read 1551 add SRC, VIS_BLOCKSIZE, SRC 1552 cmp CNT, VIS_BLOCKSIZE + 8 1553 bgu,pt %ncc, 2b 1554 prefetch [SRC + ((OLYMPUS_C_2ND_PREFETCH) * VIS_BLOCKSIZE)], #one_read 1555 1556 ! trailing block 1557 ldd [SRC + 0x08], %f2 1558 fsrc1 %f12, %f44 1559 ldd [SRC + 0x10], %f4 1560 fsrc1 %f14, %f46 1561 stda %f32, [DST]ASI_BLK_P 1562 ldd [SRC + 0x18], %f6 1563 fsrc1 %f0, %f32 1564 ldd [SRC + 0x20], %f8 1565 fsrc1 %f2, %f34 1566 ldd [SRC + 0x28], %f10 1567 fsrc1 %f4, %f36 1568 ldd [SRC + 0x30], %f12 1569 fsrc1 %f6, %f38 1570 ldd [SRC + 0x38], %f14 1571 fsrc1 %f8, %f40 1572 sub CNT, VIS_BLOCKSIZE, CNT 1573 add DST, VIS_BLOCKSIZE, DST 1574 add SRC, VIS_BLOCKSIZE, SRC 1575 fsrc1 %f10, %f42 1576 fsrc1 %f12, %f44 1577 fsrc1 %f14, %f46 1578 stda %f32, [DST]ASI_BLK_P 1579 1580 membar #Sync 1581 1582 btst FPRS_FEF, %l0 1583 bz,pt %icc, 2f 1584 nop 1585 1586 BLD_FPQ1Q3_FROMSTACK(%l3) 1587 ba 3f 1588 nop 1589 15902: FZEROQ1Q3 1591 15923: wr %l0, 0, %fprs ! restore fprs 1593 ret 1594 restore %g0, 0, %o0 1595 1596 SET_SIZE(hwblkpagecopy) 1597 1598 1599/* 1600 * Transfer data to and from user space - 1601 * Note that these routines can cause faults 1602 * It is assumed that the kernel has nothing at 1603 * less than KERNELBASE in the virtual address space. 1604 * 1605 * Note that copyin(9F) and copyout(9F) are part of the 1606 * DDI/DKI which specifies that they return '-1' on "errors." 1607 * 1608 * Sigh. 1609 * 1610 * So there's two extremely similar routines - xcopyin() and xcopyout() 1611 * which return the errno that we've faithfully computed. This 1612 * allows other callers (e.g. uiomove(9F)) to work correctly. 1613 * Given that these are used pretty heavily, we expand the calling 1614 * sequences inline for all flavours (rather than making wrappers). 1615 * 1616 * There are also stub routines for xcopyout_little and xcopyin_little, 1617 * which currently are intended to handle requests of <= 16 bytes from 1618 * do_unaligned. Future enhancement to make them handle 8k pages efficiently 1619 * is left as an exercise... 1620 */ 1621 1622/* 1623 * Copy user data to kernel space (copyOP/xcopyOP/copyOP_noerr) 1624 * 1625 * General theory of operation: 1626 * 1627 * The only difference between copy{in,out} and 1628 * xcopy{in,out} is in the error handling routine they invoke 1629 * when a memory access error occurs. xcopyOP returns the errno 1630 * while copyOP returns -1 (see above). copy{in,out}_noerr set 1631 * a special flag (by oring the TRAMP_FLAG into the fault handler address) 1632 * if they are called with a fault handler already in place. That flag 1633 * causes the default handlers to trampoline to the previous handler 1634 * upon an error. 1635 * 1636 * None of the copyops routines grab a window until it's decided that 1637 * we need to do a HW block copy operation. This saves a window 1638 * spill/fill when we're called during socket ops. The typical IO 1639 * path won't cause spill/fill traps. 1640 * 1641 * This code uses a set of 4 limits for the maximum size that will 1642 * be copied given a particular input/output address alignment. 1643 * If the value for a particular limit is zero, the copy will be performed 1644 * by the plain copy loops rather than FPBLK. 1645 * 1646 * See the description of bcopy above for more details of the 1647 * data copying algorithm and the default limits. 1648 * 1649 */ 1650 1651/* 1652 * Copy kernel data to user space (copyout/xcopyout/xcopyout_little). 1653 */ 1654 1655/* 1656 * We save the arguments in the following registers in case of a fault: 1657 * kaddr - %l1 1658 * uaddr - %l2 1659 * count - %l3 1660 */ 1661#define SAVE_SRC %l1 1662#define SAVE_DST %l2 1663#define SAVE_COUNT %l3 1664 1665#define SM_SAVE_SRC %g4 1666#define SM_SAVE_DST %g5 1667#define SM_SAVE_COUNT %o5 1668#define ERRNO %l5 1669 1670 1671#define REAL_LOFAULT %l4 1672/* 1673 * Generic copyio fault handler. This is the first line of defense when a 1674 * fault occurs in (x)copyin/(x)copyout. In order for this to function 1675 * properly, the value of the 'real' lofault handler should be in REAL_LOFAULT. 1676 * This allows us to share common code for all the flavors of the copy 1677 * operations, including the _noerr versions. 1678 * 1679 * Note that this function will restore the original input parameters before 1680 * calling REAL_LOFAULT. So the real handler can vector to the appropriate 1681 * member of the t_copyop structure, if needed. 1682 */ 1683 ENTRY(copyio_fault) 1684 membar #Sync 1685 mov %g1,ERRNO ! save errno in ERRNO 1686 btst FPUSED_FLAG, %l6 1687 bz %ncc, 1f 1688 nop 1689 1690 ldx [%fp + STACK_BIAS - SAVED_GSR_OFFSET], %o2 1691 wr %o2, 0, %gsr ! restore gsr 1692 1693 ld [%fp + STACK_BIAS - SAVED_FPRS_OFFSET], %o3 1694 btst FPRS_FEF, %o3 1695 bz,pt %icc, 4f 1696 nop 1697 1698 BLD_FPQ2Q4_FROMSTACK(%o2) 1699 1700 ba,pt %ncc, 1f 1701 wr %o3, 0, %fprs ! restore fprs 1702 17034: 1704 FZEROQ2Q4 1705 wr %o3, 0, %fprs ! restore fprs 1706 17071: 1708 andn %l6, FPUSED_FLAG, %l6 1709 membar #Sync 1710 stn %l6, [THREAD_REG + T_LOFAULT] ! restore old t_lofault 1711 FP_ALLOWMIGRATE(5, 6) 1712 1713 mov SAVE_SRC, %i0 1714 mov SAVE_DST, %i1 1715 jmp REAL_LOFAULT 1716 mov SAVE_COUNT, %i2 1717 1718 SET_SIZE(copyio_fault) 1719 1720 1721 ENTRY(copyout) 1722 1723 cmp %o2, VIS_COPY_THRESHOLD ! check for leaf rtn case 1724 bleu,pt %ncc, .copyout_small ! go to larger cases 1725 xor %o0, %o1, %o3 ! are src, dst alignable? 1726 btst 7, %o3 ! 1727 bz,pt %ncc, .copyout_8 ! check for longword alignment 1728 nop 1729 btst 1, %o3 ! 1730 bz,pt %ncc, .copyout_2 ! check for half-word 1731 nop 1732 sethi %hi(hw_copy_limit_1), %o3 ! Check copy limit 1733 ld [%o3 + %lo(hw_copy_limit_1)], %o3 1734 tst %o3 1735 bz,pn %icc, .copyout_small ! if zero, disable HW copy 1736 cmp %o2, %o3 ! if length <= limit 1737 bleu,pt %ncc, .copyout_small ! go to small copy 1738 nop 1739 ba,pt %ncc, .copyout_more ! otherwise go to large copy 1740 nop 1741.copyout_2: 1742 btst 3, %o3 ! 1743 bz,pt %ncc, .copyout_4 ! check for word alignment 1744 nop 1745 sethi %hi(hw_copy_limit_2), %o3 ! Check copy limit 1746 ld [%o3 + %lo(hw_copy_limit_2)], %o3 1747 tst %o3 1748 bz,pn %icc, .copyout_small ! if zero, disable HW copy 1749 cmp %o2, %o3 ! if length <= limit 1750 bleu,pt %ncc, .copyout_small ! go to small copy 1751 nop 1752 ba,pt %ncc, .copyout_more ! otherwise go to large copy 1753 nop 1754.copyout_4: 1755 ! already checked longword, must be word aligned 1756 sethi %hi(hw_copy_limit_4), %o3 ! Check copy limit 1757 ld [%o3 + %lo(hw_copy_limit_4)], %o3 1758 tst %o3 1759 bz,pn %icc, .copyout_small ! if zero, disable HW copy 1760 cmp %o2, %o3 ! if length <= limit 1761 bleu,pt %ncc, .copyout_small ! go to small copy 1762 nop 1763 ba,pt %ncc, .copyout_more ! otherwise go to large copy 1764 nop 1765.copyout_8: 1766 sethi %hi(hw_copy_limit_8), %o3 ! Check copy limit 1767 ld [%o3 + %lo(hw_copy_limit_8)], %o3 1768 tst %o3 1769 bz,pn %icc, .copyout_small ! if zero, disable HW copy 1770 cmp %o2, %o3 ! if length <= limit 1771 bleu,pt %ncc, .copyout_small ! go to small copy 1772 nop 1773 ba,pt %ncc, .copyout_more ! otherwise go to large copy 1774 nop 1775 1776 .align 16 1777 nop ! instruction alignment 1778 ! see discussion at start of file 1779.copyout_small: 1780 sethi %hi(.sm_copyout_err), %o5 ! .sm_copyout_err is lofault 1781 or %o5, %lo(.sm_copyout_err), %o5 1782 ldn [THREAD_REG + T_LOFAULT], %o4 ! save existing handler 1783 membar #Sync ! sync error barrier 1784 stn %o5, [THREAD_REG + T_LOFAULT] ! set t_lofault 1785.sm_do_copyout: 1786 mov %o0, SM_SAVE_SRC 1787 mov %o1, SM_SAVE_DST 1788 cmp %o2, SHORTCOPY ! check for really short case 1789 bleu,pt %ncc, .co_sm_left ! 1790 mov %o2, SM_SAVE_COUNT 1791 cmp %o2, CHKSIZE ! check for medium length cases 1792 bgu,pn %ncc, .co_med ! 1793 or %o0, %o1, %o3 ! prepare alignment check 1794 andcc %o3, 0x3, %g0 ! test for alignment 1795 bz,pt %ncc, .co_sm_word ! branch to word aligned case 1796.co_sm_movebytes: 1797 sub %o2, 3, %o2 ! adjust count to allow cc zero test 1798.co_sm_notalign4: 1799 ldub [%o0], %o3 ! read byte 1800 subcc %o2, 4, %o2 ! reduce count by 4 1801 stba %o3, [%o1]ASI_USER ! write byte 1802 inc %o1 ! advance DST by 1 1803 ldub [%o0 + 1], %o3 ! repeat for a total of 4 bytes 1804 add %o0, 4, %o0 ! advance SRC by 4 1805 stba %o3, [%o1]ASI_USER 1806 inc %o1 ! advance DST by 1 1807 ldub [%o0 - 2], %o3 1808 stba %o3, [%o1]ASI_USER 1809 inc %o1 ! advance DST by 1 1810 ldub [%o0 - 1], %o3 1811 stba %o3, [%o1]ASI_USER 1812 bgt,pt %ncc, .co_sm_notalign4 ! loop til 3 or fewer bytes remain 1813 inc %o1 ! advance DST by 1 1814 add %o2, 3, %o2 ! restore count 1815.co_sm_left: 1816 tst %o2 1817 bz,pt %ncc, .co_sm_exit ! check for zero length 1818 nop 1819 ldub [%o0], %o3 ! load one byte 1820 deccc %o2 ! reduce count for cc test 1821 bz,pt %ncc, .co_sm_exit 1822 stba %o3,[%o1]ASI_USER ! store one byte 1823 ldub [%o0 + 1], %o3 ! load second byte 1824 deccc %o2 1825 inc %o1 1826 bz,pt %ncc, .co_sm_exit 1827 stba %o3,[%o1]ASI_USER ! store second byte 1828 ldub [%o0 + 2], %o3 ! load third byte 1829 inc %o1 1830 stba %o3,[%o1]ASI_USER ! store third byte 1831 membar #Sync ! sync error barrier 1832 stn %o4, [THREAD_REG + T_LOFAULT] ! restore old t_lofault 1833 retl 1834 mov %g0, %o0 ! return 0 1835 .align 16 1836.co_sm_words: 1837 lduw [%o0], %o3 ! read word 1838.co_sm_wordx: 1839 subcc %o2, 8, %o2 ! update count 1840 stwa %o3, [%o1]ASI_USER ! write word 1841 add %o0, 8, %o0 ! update SRC 1842 lduw [%o0 - 4], %o3 ! read word 1843 add %o1, 4, %o1 ! update DST 1844 stwa %o3, [%o1]ASI_USER ! write word 1845 bgt,pt %ncc, .co_sm_words ! loop til done 1846 add %o1, 4, %o1 ! update DST 1847 addcc %o2, 7, %o2 ! restore count 1848 bz,pt %ncc, .co_sm_exit 1849 nop 1850 deccc %o2 1851 bz,pt %ncc, .co_sm_byte 1852.co_sm_half: 1853 subcc %o2, 2, %o2 ! reduce count by 2 1854 lduh [%o0], %o3 ! read half word 1855 add %o0, 2, %o0 ! advance SRC by 2 1856 stha %o3, [%o1]ASI_USER ! write half word 1857 bgt,pt %ncc, .co_sm_half ! loop til done 1858 add %o1, 2, %o1 ! advance DST by 2 1859 addcc %o2, 1, %o2 ! restore count 1860 bz,pt %ncc, .co_sm_exit 1861 nop 1862.co_sm_byte: 1863 ldub [%o0], %o3 1864 stba %o3, [%o1]ASI_USER 1865 membar #Sync ! sync error barrier 1866 stn %o4, [THREAD_REG + T_LOFAULT] ! restore old t_lofault 1867 retl 1868 mov %g0, %o0 ! return 0 1869 .align 16 1870.co_sm_word: 1871 subcc %o2, 4, %o2 ! update count 1872 bgt,pt %ncc, .co_sm_wordx 1873 lduw [%o0], %o3 ! read word 1874 addcc %o2, 3, %o2 ! restore count 1875 bz,pt %ncc, .co_sm_exit 1876 stwa %o3, [%o1]ASI_USER ! write word 1877 deccc %o2 ! reduce count for cc test 1878 ldub [%o0 + 4], %o3 ! load one byte 1879 add %o1, 4, %o1 1880 bz,pt %ncc, .co_sm_exit 1881 stba %o3, [%o1]ASI_USER ! store one byte 1882 ldub [%o0 + 5], %o3 ! load second byte 1883 deccc %o2 1884 inc %o1 1885 bz,pt %ncc, .co_sm_exit 1886 stba %o3, [%o1]ASI_USER ! store second byte 1887 ldub [%o0 + 6], %o3 ! load third byte 1888 inc %o1 1889 stba %o3, [%o1]ASI_USER ! store third byte 1890.co_sm_exit: 1891 membar #Sync ! sync error barrier 1892 stn %o4, [THREAD_REG + T_LOFAULT] ! restore old t_lofault 1893 retl 1894 mov %g0, %o0 ! return 0 1895 1896 .align 16 1897.co_med: 1898 xor %o0, %o1, %o3 ! setup alignment check 1899 btst 1, %o3 1900 bnz,pt %ncc, .co_sm_movebytes ! unaligned 1901 nop 1902 btst 3, %o3 1903 bnz,pt %ncc, .co_med_half ! halfword aligned 1904 nop 1905 btst 7, %o3 1906 bnz,pt %ncc, .co_med_word ! word aligned 1907 nop 1908.co_med_long: 1909 btst 3, %o0 ! check for 1910 bz,pt %ncc, .co_med_long1 ! word alignment 1911 nop 1912.co_med_long0: 1913 ldub [%o0], %o3 ! load one byte 1914 inc %o0 1915 stba %o3,[%o1]ASI_USER ! store byte 1916 inc %o1 1917 btst 3, %o0 1918 bnz,pt %ncc, .co_med_long0 1919 dec %o2 1920.co_med_long1: ! word aligned 1921 btst 7, %o0 ! check for long word 1922 bz,pt %ncc, .co_med_long2 1923 nop 1924 lduw [%o0], %o3 ! load word 1925 add %o0, 4, %o0 ! advance SRC by 4 1926 stwa %o3, [%o1]ASI_USER ! store word 1927 add %o1, 4, %o1 ! advance DST by 4 1928 sub %o2, 4, %o2 ! reduce count by 4 1929! 1930! Now long word aligned and have at least 32 bytes to move 1931! 1932.co_med_long2: 1933 sub %o2, 31, %o2 ! adjust count to allow cc zero test 1934 sub %o1, 8, %o1 ! adjust pointer to allow store in 1935 ! branch delay slot instead of add 1936.co_med_lmove: 1937 add %o1, 8, %o1 ! advance DST by 8 1938 ldx [%o0], %o3 ! read long word 1939 subcc %o2, 32, %o2 ! reduce count by 32 1940 stxa %o3, [%o1]ASI_USER ! write long word 1941 add %o1, 8, %o1 ! advance DST by 8 1942 ldx [%o0 + 8], %o3 ! repeat for a total for 4 long words 1943 add %o0, 32, %o0 ! advance SRC by 32 1944 stxa %o3, [%o1]ASI_USER 1945 ldx [%o0 - 16], %o3 1946 add %o1, 8, %o1 ! advance DST by 8 1947 stxa %o3, [%o1]ASI_USER 1948 ldx [%o0 - 8], %o3 1949 add %o1, 8, %o1 ! advance DST by 8 1950 bgt,pt %ncc, .co_med_lmove ! loop til 31 or fewer bytes left 1951 stxa %o3, [%o1]ASI_USER 1952 add %o1, 8, %o1 ! advance DST by 8 1953 addcc %o2, 24, %o2 ! restore count to long word offset 1954 ble,pt %ncc, .co_med_lextra ! check for more long words to move 1955 nop 1956.co_med_lword: 1957 ldx [%o0], %o3 ! read long word 1958 subcc %o2, 8, %o2 ! reduce count by 8 1959 stxa %o3, [%o1]ASI_USER ! write long word 1960 add %o0, 8, %o0 ! advance SRC by 8 1961 bgt,pt %ncc, .co_med_lword ! loop til 7 or fewer bytes left 1962 add %o1, 8, %o1 ! advance DST by 8 1963.co_med_lextra: 1964 addcc %o2, 7, %o2 ! restore rest of count 1965 bz,pt %ncc, .co_sm_exit ! if zero, then done 1966 deccc %o2 1967 bz,pt %ncc, .co_sm_byte 1968 nop 1969 ba,pt %ncc, .co_sm_half 1970 nop 1971 1972 .align 16 1973 nop ! instruction alignment 1974 ! see discussion at start of file 1975.co_med_word: 1976 btst 3, %o0 ! check for 1977 bz,pt %ncc, .co_med_word1 ! word alignment 1978 nop 1979.co_med_word0: 1980 ldub [%o0], %o3 ! load one byte 1981 inc %o0 1982 stba %o3,[%o1]ASI_USER ! store byte 1983 inc %o1 1984 btst 3, %o0 1985 bnz,pt %ncc, .co_med_word0 1986 dec %o2 1987! 1988! Now word aligned and have at least 36 bytes to move 1989! 1990.co_med_word1: 1991 sub %o2, 15, %o2 ! adjust count to allow cc zero test 1992.co_med_wmove: 1993 lduw [%o0], %o3 ! read word 1994 subcc %o2, 16, %o2 ! reduce count by 16 1995 stwa %o3, [%o1]ASI_USER ! write word 1996 add %o1, 4, %o1 ! advance DST by 4 1997 lduw [%o0 + 4], %o3 ! repeat for a total for 4 words 1998 add %o0, 16, %o0 ! advance SRC by 16 1999 stwa %o3, [%o1]ASI_USER 2000 add %o1, 4, %o1 ! advance DST by 4 2001 lduw [%o0 - 8], %o3 2002 stwa %o3, [%o1]ASI_USER 2003 add %o1, 4, %o1 ! advance DST by 4 2004 lduw [%o0 - 4], %o3 2005 stwa %o3, [%o1]ASI_USER 2006 bgt,pt %ncc, .co_med_wmove ! loop til 15 or fewer bytes left 2007 add %o1, 4, %o1 ! advance DST by 4 2008 addcc %o2, 12, %o2 ! restore count to word offset 2009 ble,pt %ncc, .co_med_wextra ! check for more words to move 2010 nop 2011.co_med_word2: 2012 lduw [%o0], %o3 ! read word 2013 subcc %o2, 4, %o2 ! reduce count by 4 2014 stwa %o3, [%o1]ASI_USER ! write word 2015 add %o0, 4, %o0 ! advance SRC by 4 2016 bgt,pt %ncc, .co_med_word2 ! loop til 3 or fewer bytes left 2017 add %o1, 4, %o1 ! advance DST by 4 2018.co_med_wextra: 2019 addcc %o2, 3, %o2 ! restore rest of count 2020 bz,pt %ncc, .co_sm_exit ! if zero, then done 2021 deccc %o2 2022 bz,pt %ncc, .co_sm_byte 2023 nop 2024 ba,pt %ncc, .co_sm_half 2025 nop 2026 2027 .align 16 2028 nop ! instruction alignment 2029 nop ! see discussion at start of file 2030 nop 2031.co_med_half: 2032 btst 1, %o0 ! check for 2033 bz,pt %ncc, .co_med_half1 ! half word alignment 2034 nop 2035 ldub [%o0], %o3 ! load one byte 2036 inc %o0 2037 stba %o3,[%o1]ASI_USER ! store byte 2038 inc %o1 2039 dec %o2 2040! 2041! Now half word aligned and have at least 38 bytes to move 2042! 2043.co_med_half1: 2044 sub %o2, 7, %o2 ! adjust count to allow cc zero test 2045.co_med_hmove: 2046 lduh [%o0], %o3 ! read half word 2047 subcc %o2, 8, %o2 ! reduce count by 8 2048 stha %o3, [%o1]ASI_USER ! write half word 2049 add %o1, 2, %o1 ! advance DST by 2 2050 lduh [%o0 + 2], %o3 ! repeat for a total for 4 halfwords 2051 add %o0, 8, %o0 ! advance SRC by 8 2052 stha %o3, [%o1]ASI_USER 2053 add %o1, 2, %o1 ! advance DST by 2 2054 lduh [%o0 - 4], %o3 2055 stha %o3, [%o1]ASI_USER 2056 add %o1, 2, %o1 ! advance DST by 2 2057 lduh [%o0 - 2], %o3 2058 stha %o3, [%o1]ASI_USER 2059 bgt,pt %ncc, .co_med_hmove ! loop til 7 or fewer bytes left 2060 add %o1, 2, %o1 ! advance DST by 2 2061 addcc %o2, 7, %o2 ! restore count 2062 bz,pt %ncc, .co_sm_exit 2063 deccc %o2 2064 bz,pt %ncc, .co_sm_byte 2065 nop 2066 ba,pt %ncc, .co_sm_half 2067 nop 2068 2069/* 2070 * We got here because of a fault during short copyout. 2071 * Errno value is in ERRNO, but DDI/DKI says return -1 (sigh). 2072 */ 2073.sm_copyout_err: 2074 membar #Sync 2075 stn %o4, [THREAD_REG + T_LOFAULT] ! restore old t_lofault 2076 mov SM_SAVE_SRC, %o0 2077 mov SM_SAVE_DST, %o1 2078 mov SM_SAVE_COUNT, %o2 2079 ldn [THREAD_REG + T_COPYOPS], %o3 ! check for copyop handler 2080 tst %o3 2081 bz,pt %ncc, 3f ! if not, return error 2082 nop 2083 ldn [%o3 + CP_COPYOUT], %o5 ! if handler, invoke it with 2084 jmp %o5 ! original arguments 2085 nop 20863: 2087 retl 2088 or %g0, -1, %o0 ! return error value 2089 2090 SET_SIZE(copyout) 2091 2092/* 2093 * The _more entry points are not intended to be used directly by 2094 * any caller from outside this file. They are provided to allow 2095 * profiling and dtrace of the portions of the copy code that uses 2096 * the floating point registers. 2097 * This entry is particularly important as DTRACE (at least as of 2098 * 4/2004) does not support leaf functions. 2099 */ 2100 2101 ENTRY(copyout_more) 2102.copyout_more: 2103 prefetch [%o0], #n_reads 2104 save %sp, -SA(MINFRAME + HWCOPYFRAMESIZE), %sp 2105 set .copyout_err, REAL_LOFAULT 2106 2107/* 2108 * Copy outs that reach here are larger than VIS_COPY_THRESHOLD bytes 2109 */ 2110.do_copyout: 2111 set copyio_fault, %l7 ! .copyio_fault is lofault val 2112 2113 ldn [THREAD_REG + T_LOFAULT], %l6 ! save existing handler 2114 membar #Sync ! sync error barrier 2115 stn %l7, [THREAD_REG + T_LOFAULT] ! set t_lofault 2116 2117 mov %i0, SAVE_SRC 2118 mov %i1, SAVE_DST 2119 mov %i2, SAVE_COUNT 2120 2121 FP_NOMIGRATE(6, 7) 2122 2123 rd %fprs, %o2 ! check for unused fp 2124 st %o2, [%fp + STACK_BIAS - SAVED_FPRS_OFFSET] ! save orig %fprs 2125 btst FPRS_FEF, %o2 2126 bz,a,pt %icc, .do_blockcopyout 2127 wr %g0, FPRS_FEF, %fprs 2128 2129 BST_FPQ2Q4_TOSTACK(%o2) 2130 2131.do_blockcopyout: 2132 rd %gsr, %o2 2133 stx %o2, [%fp + STACK_BIAS - SAVED_GSR_OFFSET] ! save gsr 2134 or %l6, FPUSED_FLAG, %l6 2135 2136 andcc DST, VIS_BLOCKSIZE - 1, TMP 2137 mov ASI_USER, %asi 2138 bz,pt %ncc, 2f 2139 neg TMP 2140 add TMP, VIS_BLOCKSIZE, TMP 2141 2142 ! TMP = bytes required to align DST on FP_BLOCK boundary 2143 ! Using SRC as a tmp here 2144 cmp TMP, 3 2145 bleu,pt %ncc, 1f 2146 sub CNT,TMP,CNT ! adjust main count 2147 sub TMP, 3, TMP ! adjust for end of loop test 2148.co_blkalign: 2149 ldub [REALSRC], SRC ! move 4 bytes per loop iteration 2150 stba SRC, [DST]%asi 2151 subcc TMP, 4, TMP 2152 ldub [REALSRC + 1], SRC 2153 add REALSRC, 4, REALSRC 2154 stba SRC, [DST + 1]%asi 2155 ldub [REALSRC - 2], SRC 2156 add DST, 4, DST 2157 stba SRC, [DST - 2]%asi 2158 ldub [REALSRC - 1], SRC 2159 bgu,pt %ncc, .co_blkalign 2160 stba SRC, [DST - 1]%asi 2161 2162 addcc TMP, 3, TMP ! restore count adjustment 2163 bz,pt %ncc, 2f ! no bytes left? 2164 nop 21651: ldub [REALSRC], SRC 2166 inc REALSRC 2167 inc DST 2168 deccc TMP 2169 bgu %ncc, 1b 2170 stba SRC, [DST - 1]%asi 2171 21722: 2173 membar #StoreLoad 2174 andn REALSRC, 0x7, SRC 2175 2176 ! SRC - 8-byte aligned 2177 ! DST - 64-byte aligned 2178 ldd [SRC], %f16 2179 prefetch [SRC + (1 * VIS_BLOCKSIZE)], #n_reads 2180 alignaddr REALSRC, %g0, %g0 2181 ldd [SRC + 0x08], %f18 2182 prefetch [SRC + (2 * VIS_BLOCKSIZE)], #n_reads 2183 faligndata %f16, %f18, %f48 2184 ldd [SRC + 0x10], %f20 2185 prefetch [SRC + (3 * VIS_BLOCKSIZE)], #n_reads 2186 faligndata %f18, %f20, %f50 2187 ldd [SRC + 0x18], %f22 2188 prefetch [SRC + (4 * VIS_BLOCKSIZE)], #one_read 2189 faligndata %f20, %f22, %f52 2190 ldd [SRC + 0x20], %f24 2191 prefetch [SRC + (8 * VIS_BLOCKSIZE)], #one_read 2192 faligndata %f22, %f24, %f54 2193 ldd [SRC + 0x28], %f26 2194 prefetch [SRC + (12 * VIS_BLOCKSIZE)], #one_read 2195 faligndata %f24, %f26, %f56 2196 ldd [SRC + 0x30], %f28 2197 prefetch [SRC + (16 * VIS_BLOCKSIZE)], #one_read 2198 faligndata %f26, %f28, %f58 2199 ldd [SRC + 0x38], %f30 2200 ldd [SRC + VIS_BLOCKSIZE], %f16 2201 sub CNT, VIS_BLOCKSIZE, CNT 2202 add SRC, VIS_BLOCKSIZE, SRC 2203 prefetch [SRC + (19 * VIS_BLOCKSIZE)], #one_read 2204 add REALSRC, VIS_BLOCKSIZE, REALSRC 2205 ba,pt %ncc, 1f 2206 prefetch [SRC + (23 * VIS_BLOCKSIZE)], #one_read 2207 .align 32 22081: 2209 ldd [SRC + 0x08], %f18 2210 faligndata %f28, %f30, %f60 2211 ldd [SRC + 0x10], %f20 2212 faligndata %f30, %f16, %f62 2213 stda %f48, [DST]ASI_BLK_AIUS 2214 ldd [SRC + 0x18], %f22 2215 faligndata %f16, %f18, %f48 2216 ldd [SRC + 0x20], %f24 2217 faligndata %f18, %f20, %f50 2218 ldd [SRC + 0x28], %f26 2219 faligndata %f20, %f22, %f52 2220 ldd [SRC + 0x30], %f28 2221 faligndata %f22, %f24, %f54 2222 sub CNT, VIS_BLOCKSIZE, CNT 2223 ldd [SRC + 0x38], %f30 2224 faligndata %f24, %f26, %f56 2225 add DST, VIS_BLOCKSIZE, DST 2226 ldd [SRC + VIS_BLOCKSIZE], %f16 2227 faligndata %f26, %f28, %f58 2228 add REALSRC, VIS_BLOCKSIZE, REALSRC 2229 prefetch [SRC + (3 * VIS_BLOCKSIZE)], #n_reads 2230 add SRC, VIS_BLOCKSIZE, SRC 2231 prefetch [SRC + ((OLYMPUS_C_PREFETCH) * VIS_BLOCKSIZE)], #one_read 2232 cmp CNT, VIS_BLOCKSIZE + 8 2233 bgu,pt %ncc, 1b 2234 prefetch [SRC + ((OLYMPUS_C_2ND_PREFETCH) * VIS_BLOCKSIZE)], #one_read 2235 2236 ! only if REALSRC & 0x7 is 0 2237 cmp CNT, VIS_BLOCKSIZE 2238 bne %ncc, 3f 2239 andcc REALSRC, 0x7, %g0 2240 bz,pt %ncc, 2f 2241 nop 22423: 2243 faligndata %f28, %f30, %f60 2244 faligndata %f30, %f16, %f62 2245 stda %f48, [DST]ASI_BLK_AIUS 2246 add DST, VIS_BLOCKSIZE, DST 2247 ba,pt %ncc, 3f 2248 nop 22492: 2250 ldd [SRC + 0x08], %f18 2251 fsrc1 %f28, %f60 2252 ldd [SRC + 0x10], %f20 2253 fsrc1 %f30, %f62 2254 stda %f48, [DST]ASI_BLK_AIUS 2255 ldd [SRC + 0x18], %f22 2256 fsrc1 %f16, %f48 2257 ldd [SRC + 0x20], %f24 2258 fsrc1 %f18, %f50 2259 ldd [SRC + 0x28], %f26 2260 fsrc1 %f20, %f52 2261 ldd [SRC + 0x30], %f28 2262 fsrc1 %f22, %f54 2263 ldd [SRC + 0x38], %f30 2264 fsrc1 %f24, %f56 2265 sub CNT, VIS_BLOCKSIZE, CNT 2266 add DST, VIS_BLOCKSIZE, DST 2267 add SRC, VIS_BLOCKSIZE, SRC 2268 add REALSRC, VIS_BLOCKSIZE, REALSRC 2269 fsrc1 %f26, %f58 2270 fsrc1 %f28, %f60 2271 fsrc1 %f30, %f62 2272 stda %f48, [DST]ASI_BLK_AIUS 2273 add DST, VIS_BLOCKSIZE, DST 2274 ba,a,pt %ncc, 4f 2275 nop 2276 22773: tst CNT 2278 bz,a %ncc, 4f 2279 nop 2280 22815: ldub [REALSRC], TMP 2282 inc REALSRC 2283 inc DST 2284 deccc CNT 2285 bgu %ncc, 5b 2286 stba TMP, [DST - 1]%asi 22874: 2288 2289.copyout_exit: 2290 membar #Sync 2291 2292 ldx [%fp + STACK_BIAS - SAVED_GSR_OFFSET], %o2 2293 wr %o2, 0, %gsr ! restore gsr 2294 2295 ld [%fp + STACK_BIAS - SAVED_FPRS_OFFSET], %o3 2296 btst FPRS_FEF, %o3 2297 bz,pt %icc, 4f 2298 nop 2299 2300 BLD_FPQ2Q4_FROMSTACK(%o2) 2301 2302 ba,pt %ncc, 1f 2303 wr %o3, 0, %fprs ! restore fprs 2304 23054: 2306 FZEROQ2Q4 2307 wr %o3, 0, %fprs ! restore fprs 2308 23091: 2310 membar #Sync 2311 andn %l6, FPUSED_FLAG, %l6 2312 stn %l6, [THREAD_REG + T_LOFAULT] ! restore old t_lofault 2313 FP_ALLOWMIGRATE(5, 6) 2314 ret 2315 restore %g0, 0, %o0 2316 2317/* 2318 * We got here because of a fault during copyout. 2319 * Errno value is in ERRNO, but DDI/DKI says return -1 (sigh). 2320 */ 2321.copyout_err: 2322 ldn [THREAD_REG + T_COPYOPS], %o4 ! check for copyop handler 2323 tst %o4 2324 bz,pt %ncc, 2f ! if not, return error 2325 nop 2326 ldn [%o4 + CP_COPYOUT], %g2 ! if handler, invoke it with 2327 jmp %g2 ! original arguments 2328 restore %g0, 0, %g0 ! dispose of copy window 23292: 2330 ret 2331 restore %g0, -1, %o0 ! return error value 2332 2333 2334 SET_SIZE(copyout_more) 2335 2336 2337 ENTRY(xcopyout) 2338 cmp %o2, VIS_COPY_THRESHOLD ! check for leaf rtn case 2339 bleu,pt %ncc, .xcopyout_small ! go to larger cases 2340 xor %o0, %o1, %o3 ! are src, dst alignable? 2341 btst 7, %o3 ! 2342 bz,pt %ncc, .xcopyout_8 ! 2343 nop 2344 btst 1, %o3 ! 2345 bz,pt %ncc, .xcopyout_2 ! check for half-word 2346 nop 2347 sethi %hi(hw_copy_limit_1), %o3 ! Check copy limit 2348 ld [%o3 + %lo(hw_copy_limit_1)], %o3 2349 tst %o3 2350 bz,pn %icc, .xcopyout_small ! if zero, disable HW copy 2351 cmp %o2, %o3 ! if length <= limit 2352 bleu,pt %ncc, .xcopyout_small ! go to small copy 2353 nop 2354 ba,pt %ncc, .xcopyout_more ! otherwise go to large copy 2355 nop 2356.xcopyout_2: 2357 btst 3, %o3 ! 2358 bz,pt %ncc, .xcopyout_4 ! check for word alignment 2359 nop 2360 sethi %hi(hw_copy_limit_2), %o3 ! Check copy limit 2361 ld [%o3 + %lo(hw_copy_limit_2)], %o3 2362 tst %o3 2363 bz,pn %icc, .xcopyout_small ! if zero, disable HW copy 2364 cmp %o2, %o3 ! if length <= limit 2365 bleu,pt %ncc, .xcopyout_small ! go to small copy 2366 nop 2367 ba,pt %ncc, .xcopyout_more ! otherwise go to large copy 2368 nop 2369.xcopyout_4: 2370 ! already checked longword, must be word aligned 2371 sethi %hi(hw_copy_limit_4), %o3 ! Check copy limit 2372 ld [%o3 + %lo(hw_copy_limit_4)], %o3 2373 tst %o3 2374 bz,pn %icc, .xcopyout_small ! if zero, disable HW copy 2375 cmp %o2, %o3 ! if length <= limit 2376 bleu,pt %ncc, .xcopyout_small ! go to small copy 2377 nop 2378 ba,pt %ncc, .xcopyout_more ! otherwise go to large copy 2379 nop 2380.xcopyout_8: 2381 sethi %hi(hw_copy_limit_8), %o3 ! Check copy limit 2382 ld [%o3 + %lo(hw_copy_limit_8)], %o3 2383 tst %o3 2384 bz,pn %icc, .xcopyout_small ! if zero, disable HW copy 2385 cmp %o2, %o3 ! if length <= limit 2386 bleu,pt %ncc, .xcopyout_small ! go to small copy 2387 nop 2388 ba,pt %ncc, .xcopyout_more ! otherwise go to large copy 2389 nop 2390 2391.xcopyout_small: 2392 sethi %hi(.sm_xcopyout_err), %o5 ! .sm_xcopyout_err is lofault 2393 or %o5, %lo(.sm_xcopyout_err), %o5 2394 ldn [THREAD_REG + T_LOFAULT], %o4 ! save existing handler 2395 membar #Sync ! sync error barrier 2396 ba,pt %ncc, .sm_do_copyout ! common code 2397 stn %o5, [THREAD_REG + T_LOFAULT] ! set t_lofault 2398 2399.xcopyout_more: 2400 save %sp, -SA(MINFRAME + HWCOPYFRAMESIZE), %sp 2401 sethi %hi(.xcopyout_err), REAL_LOFAULT 2402 ba,pt %ncc, .do_copyout ! common code 2403 or REAL_LOFAULT, %lo(.xcopyout_err), REAL_LOFAULT 2404 2405/* 2406 * We got here because of fault during xcopyout 2407 * Errno value is in ERRNO 2408 */ 2409.xcopyout_err: 2410 ldn [THREAD_REG + T_COPYOPS], %o4 ! check for copyop handler 2411 tst %o4 2412 bz,pt %ncc, 2f ! if not, return error 2413 nop 2414 ldn [%o4 + CP_XCOPYOUT], %g2 ! if handler, invoke it with 2415 jmp %g2 ! original arguments 2416 restore %g0, 0, %g0 ! dispose of copy window 24172: 2418 ret 2419 restore ERRNO, 0, %o0 ! return errno value 2420 2421.sm_xcopyout_err: 2422 2423 membar #Sync 2424 stn %o4, [THREAD_REG + T_LOFAULT] ! restore old t_lofault 2425 mov SM_SAVE_SRC, %o0 2426 mov SM_SAVE_DST, %o1 2427 mov SM_SAVE_COUNT, %o2 2428 ldn [THREAD_REG + T_COPYOPS], %o3 ! check for copyop handler 2429 tst %o3 2430 bz,pt %ncc, 3f ! if not, return error 2431 nop 2432 ldn [%o3 + CP_XCOPYOUT], %o5 ! if handler, invoke it with 2433 jmp %o5 ! original arguments 2434 nop 24353: 2436 retl 2437 or %g1, 0, %o0 ! return errno value 2438 2439 SET_SIZE(xcopyout) 2440 2441 ENTRY(xcopyout_little) 2442 sethi %hi(.xcopyio_err), %o5 2443 or %o5, %lo(.xcopyio_err), %o5 2444 ldn [THREAD_REG + T_LOFAULT], %o4 2445 membar #Sync ! sync error barrier 2446 stn %o5, [THREAD_REG + T_LOFAULT] 2447 mov %o4, %o5 2448 2449 subcc %g0, %o2, %o3 2450 add %o0, %o2, %o0 2451 bz,pn %ncc, 2f ! check for zero bytes 2452 sub %o2, 1, %o4 2453 add %o0, %o4, %o0 ! start w/last byte 2454 add %o1, %o2, %o1 2455 ldub [%o0 + %o3], %o4 2456 24571: stba %o4, [%o1 + %o3]ASI_AIUSL 2458 inccc %o3 2459 sub %o0, 2, %o0 ! get next byte 2460 bcc,a,pt %ncc, 1b 2461 ldub [%o0 + %o3], %o4 2462 24632: 2464 membar #Sync ! sync error barrier 2465 stn %o5, [THREAD_REG + T_LOFAULT] ! restore old t_lofault 2466 retl 2467 mov %g0, %o0 ! return (0) 2468 2469 SET_SIZE(xcopyout_little) 2470 2471/* 2472 * Copy user data to kernel space (copyin/xcopyin/xcopyin_little) 2473 */ 2474 2475 ENTRY(copyin) 2476 cmp %o2, VIS_COPY_THRESHOLD ! check for leaf rtn case 2477 bleu,pt %ncc, .copyin_small ! go to larger cases 2478 xor %o0, %o1, %o3 ! are src, dst alignable? 2479 btst 7, %o3 ! 2480 bz,pt %ncc, .copyin_8 ! check for longword alignment 2481 nop 2482 btst 1, %o3 ! 2483 bz,pt %ncc, .copyin_2 ! check for half-word 2484 nop 2485 sethi %hi(hw_copy_limit_1), %o3 ! Check copy limit 2486 ld [%o3 + %lo(hw_copy_limit_1)], %o3 2487 tst %o3 2488 bz,pn %icc, .copyin_small ! if zero, disable HW copy 2489 cmp %o2, %o3 ! if length <= limit 2490 bleu,pt %ncc, .copyin_small ! go to small copy 2491 nop 2492 ba,pt %ncc, .copyin_more ! otherwise go to large copy 2493 nop 2494.copyin_2: 2495 btst 3, %o3 ! 2496 bz,pt %ncc, .copyin_4 ! check for word alignment 2497 nop 2498 sethi %hi(hw_copy_limit_2), %o3 ! Check copy limit 2499 ld [%o3 + %lo(hw_copy_limit_2)], %o3 2500 tst %o3 2501 bz,pn %icc, .copyin_small ! if zero, disable HW copy 2502 cmp %o2, %o3 ! if length <= limit 2503 bleu,pt %ncc, .copyin_small ! go to small copy 2504 nop 2505 ba,pt %ncc, .copyin_more ! otherwise go to large copy 2506 nop 2507.copyin_4: 2508 ! already checked longword, must be word aligned 2509 sethi %hi(hw_copy_limit_4), %o3 ! Check copy limit 2510 ld [%o3 + %lo(hw_copy_limit_4)], %o3 2511 tst %o3 2512 bz,pn %icc, .copyin_small ! if zero, disable HW copy 2513 cmp %o2, %o3 ! if length <= limit 2514 bleu,pt %ncc, .copyin_small ! go to small copy 2515 nop 2516 ba,pt %ncc, .copyin_more ! otherwise go to large copy 2517 nop 2518.copyin_8: 2519 sethi %hi(hw_copy_limit_8), %o3 ! Check copy limit 2520 ld [%o3 + %lo(hw_copy_limit_8)], %o3 2521 tst %o3 2522 bz,pn %icc, .copyin_small ! if zero, disable HW copy 2523 cmp %o2, %o3 ! if length <= limit 2524 bleu,pt %ncc, .copyin_small ! go to small copy 2525 nop 2526 ba,pt %ncc, .copyin_more ! otherwise go to large copy 2527 nop 2528 2529 .align 16 2530 nop ! instruction alignment 2531 ! see discussion at start of file 2532.copyin_small: 2533 sethi %hi(.sm_copyin_err), %o5 ! .sm_copyin_err is lofault 2534 or %o5, %lo(.sm_copyin_err), %o5 2535 ldn [THREAD_REG + T_LOFAULT], %o4 ! set/save t_lofault, no tramp 2536 membar #Sync ! sync error barrier 2537 stn %o5, [THREAD_REG + T_LOFAULT] 2538.sm_do_copyin: 2539 mov %o0, SM_SAVE_SRC 2540 mov %o1, SM_SAVE_DST 2541 cmp %o2, SHORTCOPY ! check for really short case 2542 bleu,pt %ncc, .ci_sm_left ! 2543 mov %o2, SM_SAVE_COUNT 2544 cmp %o2, CHKSIZE ! check for medium length cases 2545 bgu,pn %ncc, .ci_med ! 2546 or %o0, %o1, %o3 ! prepare alignment check 2547 andcc %o3, 0x3, %g0 ! test for alignment 2548 bz,pt %ncc, .ci_sm_word ! branch to word aligned case 2549.ci_sm_movebytes: 2550 sub %o2, 3, %o2 ! adjust count to allow cc zero test 2551.ci_sm_notalign4: 2552 lduba [%o0]ASI_USER, %o3 ! read byte 2553 subcc %o2, 4, %o2 ! reduce count by 4 2554 stb %o3, [%o1] ! write byte 2555 add %o0, 1, %o0 ! advance SRC by 1 2556 lduba [%o0]ASI_USER, %o3 ! repeat for a total of 4 bytes 2557 add %o0, 1, %o0 ! advance SRC by 1 2558 stb %o3, [%o1 + 1] 2559 add %o1, 4, %o1 ! advance DST by 4 2560 lduba [%o0]ASI_USER, %o3 2561 add %o0, 1, %o0 ! advance SRC by 1 2562 stb %o3, [%o1 - 2] 2563 lduba [%o0]ASI_USER, %o3 2564 add %o0, 1, %o0 ! advance SRC by 1 2565 bgt,pt %ncc, .ci_sm_notalign4 ! loop til 3 or fewer bytes remain 2566 stb %o3, [%o1 - 1] 2567 add %o2, 3, %o2 ! restore count 2568.ci_sm_left: 2569 tst %o2 2570 bz,pt %ncc, .ci_sm_exit 2571 nop 2572 lduba [%o0]ASI_USER, %o3 ! load one byte 2573 deccc %o2 ! reduce count for cc test 2574 bz,pt %ncc, .ci_sm_exit 2575 stb %o3,[%o1] ! store one byte 2576 inc %o0 2577 lduba [%o0]ASI_USER, %o3 ! load second byte 2578 deccc %o2 2579 bz,pt %ncc, .ci_sm_exit 2580 stb %o3,[%o1 + 1] ! store second byte 2581 inc %o0 2582 lduba [%o0]ASI_USER, %o3 ! load third byte 2583 stb %o3,[%o1 + 2] ! store third byte 2584 membar #Sync ! sync error barrier 2585 stn %o4, [THREAD_REG + T_LOFAULT] ! restore old t_lofault 2586 retl 2587 mov %g0, %o0 ! return 0 2588 .align 16 2589.ci_sm_words: 2590 lduwa [%o0]ASI_USER, %o3 ! read word 2591.ci_sm_wordx: 2592 subcc %o2, 8, %o2 ! update count 2593 stw %o3, [%o1] ! write word 2594 add %o0, 4, %o0 ! update SRC 2595 add %o1, 8, %o1 ! update DST 2596 lduwa [%o0]ASI_USER, %o3 ! read word 2597 add %o0, 4, %o0 ! update SRC 2598 bgt,pt %ncc, .ci_sm_words ! loop til done 2599 stw %o3, [%o1 - 4] ! write word 2600 addcc %o2, 7, %o2 ! restore count 2601 bz,pt %ncc, .ci_sm_exit 2602 nop 2603 deccc %o2 2604 bz,pt %ncc, .ci_sm_byte 2605.ci_sm_half: 2606 subcc %o2, 2, %o2 ! reduce count by 2 2607 lduha [%o0]ASI_USER, %o3 ! read half word 2608 add %o0, 2, %o0 ! advance SRC by 2 2609 add %o1, 2, %o1 ! advance DST by 2 2610 bgt,pt %ncc, .ci_sm_half ! loop til done 2611 sth %o3, [%o1 - 2] ! write half word 2612 addcc %o2, 1, %o2 ! restore count 2613 bz,pt %ncc, .ci_sm_exit 2614 nop 2615.ci_sm_byte: 2616 lduba [%o0]ASI_USER, %o3 2617 stb %o3, [%o1] 2618 membar #Sync ! sync error barrier 2619 stn %o4, [THREAD_REG + T_LOFAULT] ! restore old t_lofault 2620 retl 2621 mov %g0, %o0 ! return 0 2622 .align 16 2623.ci_sm_word: 2624 subcc %o2, 4, %o2 ! update count 2625 bgt,pt %ncc, .ci_sm_wordx 2626 lduwa [%o0]ASI_USER, %o3 ! read word 2627 addcc %o2, 3, %o2 ! restore count 2628 bz,pt %ncc, .ci_sm_exit 2629 stw %o3, [%o1] ! write word 2630 deccc %o2 ! reduce count for cc test 2631 add %o0, 4, %o0 2632 lduba [%o0]ASI_USER, %o3 ! load one byte 2633 bz,pt %ncc, .ci_sm_exit 2634 stb %o3, [%o1 + 4] ! store one byte 2635 inc %o0 2636 lduba [%o0]ASI_USER, %o3 ! load second byte 2637 deccc %o2 2638 bz,pt %ncc, .ci_sm_exit 2639 stb %o3, [%o1 + 5] ! store second byte 2640 inc %o0 2641 lduba [%o0]ASI_USER, %o3 ! load third byte 2642 stb %o3, [%o1 + 6] ! store third byte 2643.ci_sm_exit: 2644 membar #Sync ! sync error barrier 2645 stn %o4, [THREAD_REG + T_LOFAULT] ! restore old t_lofault 2646 retl 2647 mov %g0, %o0 ! return 0 2648 2649 .align 16 2650.ci_med: 2651 xor %o0, %o1, %o3 ! setup alignment check 2652 btst 1, %o3 2653 bnz,pt %ncc, .ci_sm_movebytes ! unaligned 2654 nop 2655 btst 3, %o3 2656 bnz,pt %ncc, .ci_med_half ! halfword aligned 2657 nop 2658 btst 7, %o3 2659 bnz,pt %ncc, .ci_med_word ! word aligned 2660 nop 2661.ci_med_long: 2662 btst 3, %o0 ! check for 2663 bz,pt %ncc, .ci_med_long1 ! word alignment 2664 nop 2665.ci_med_long0: 2666 lduba [%o0]ASI_USER, %o3 ! load one byte 2667 inc %o0 2668 stb %o3,[%o1] ! store byte 2669 inc %o1 2670 btst 3, %o0 2671 bnz,pt %ncc, .ci_med_long0 2672 dec %o2 2673.ci_med_long1: ! word aligned 2674 btst 7, %o0 ! check for long word 2675 bz,pt %ncc, .ci_med_long2 2676 nop 2677 lduwa [%o0]ASI_USER, %o3 ! load word 2678 add %o0, 4, %o0 ! advance SRC by 4 2679 stw %o3, [%o1] ! store word 2680 add %o1, 4, %o1 ! advance DST by 4 2681 sub %o2, 4, %o2 ! reduce count by 4 2682! 2683! Now long word aligned and have at least 32 bytes to move 2684! 2685.ci_med_long2: 2686 sub %o2, 31, %o2 ! adjust count to allow cc zero test 2687.ci_med_lmove: 2688 ldxa [%o0]ASI_USER, %o3 ! read long word 2689 subcc %o2, 32, %o2 ! reduce count by 32 2690 stx %o3, [%o1] ! write long word 2691 add %o0, 8, %o0 ! advance SRC by 8 2692 ldxa [%o0]ASI_USER, %o3 ! repeat for a total for 4 long words 2693 add %o0, 8, %o0 ! advance SRC by 8 2694 stx %o3, [%o1 + 8] 2695 add %o1, 32, %o1 ! advance DST by 32 2696 ldxa [%o0]ASI_USER, %o3 2697 add %o0, 8, %o0 ! advance SRC by 8 2698 stx %o3, [%o1 - 16] 2699 ldxa [%o0]ASI_USER, %o3 2700 add %o0, 8, %o0 ! advance SRC by 8 2701 bgt,pt %ncc, .ci_med_lmove ! loop til 31 or fewer bytes left 2702 stx %o3, [%o1 - 8] 2703 addcc %o2, 24, %o2 ! restore count to long word offset 2704 ble,pt %ncc, .ci_med_lextra ! check for more long words to move 2705 nop 2706.ci_med_lword: 2707 ldxa [%o0]ASI_USER, %o3 ! read long word 2708 subcc %o2, 8, %o2 ! reduce count by 8 2709 stx %o3, [%o1] ! write long word 2710 add %o0, 8, %o0 ! advance SRC by 8 2711 bgt,pt %ncc, .ci_med_lword ! loop til 7 or fewer bytes left 2712 add %o1, 8, %o1 ! advance DST by 8 2713.ci_med_lextra: 2714 addcc %o2, 7, %o2 ! restore rest of count 2715 bz,pt %ncc, .ci_sm_exit ! if zero, then done 2716 deccc %o2 2717 bz,pt %ncc, .ci_sm_byte 2718 nop 2719 ba,pt %ncc, .ci_sm_half 2720 nop 2721 2722 .align 16 2723 nop ! instruction alignment 2724 ! see discussion at start of file 2725.ci_med_word: 2726 btst 3, %o0 ! check for 2727 bz,pt %ncc, .ci_med_word1 ! word alignment 2728 nop 2729.ci_med_word0: 2730 lduba [%o0]ASI_USER, %o3 ! load one byte 2731 inc %o0 2732 stb %o3,[%o1] ! store byte 2733 inc %o1 2734 btst 3, %o0 2735 bnz,pt %ncc, .ci_med_word0 2736 dec %o2 2737! 2738! Now word aligned and have at least 36 bytes to move 2739! 2740.ci_med_word1: 2741 sub %o2, 15, %o2 ! adjust count to allow cc zero test 2742.ci_med_wmove: 2743 lduwa [%o0]ASI_USER, %o3 ! read word 2744 subcc %o2, 16, %o2 ! reduce count by 16 2745 stw %o3, [%o1] ! write word 2746 add %o0, 4, %o0 ! advance SRC by 4 2747 lduwa [%o0]ASI_USER, %o3 ! repeat for a total for 4 words 2748 add %o0, 4, %o0 ! advance SRC by 4 2749 stw %o3, [%o1 + 4] 2750 add %o1, 16, %o1 ! advance DST by 16 2751 lduwa [%o0]ASI_USER, %o3 2752 add %o0, 4, %o0 ! advance SRC by 4 2753 stw %o3, [%o1 - 8] 2754 lduwa [%o0]ASI_USER, %o3 2755 add %o0, 4, %o0 ! advance SRC by 4 2756 bgt,pt %ncc, .ci_med_wmove ! loop til 15 or fewer bytes left 2757 stw %o3, [%o1 - 4] 2758 addcc %o2, 12, %o2 ! restore count to word offset 2759 ble,pt %ncc, .ci_med_wextra ! check for more words to move 2760 nop 2761.ci_med_word2: 2762 lduwa [%o0]ASI_USER, %o3 ! read word 2763 subcc %o2, 4, %o2 ! reduce count by 4 2764 stw %o3, [%o1] ! write word 2765 add %o0, 4, %o0 ! advance SRC by 4 2766 bgt,pt %ncc, .ci_med_word2 ! loop til 3 or fewer bytes left 2767 add %o1, 4, %o1 ! advance DST by 4 2768.ci_med_wextra: 2769 addcc %o2, 3, %o2 ! restore rest of count 2770 bz,pt %ncc, .ci_sm_exit ! if zero, then done 2771 deccc %o2 2772 bz,pt %ncc, .ci_sm_byte 2773 nop 2774 ba,pt %ncc, .ci_sm_half 2775 nop 2776 2777 .align 16 2778 nop ! instruction alignment 2779 ! see discussion at start of file 2780.ci_med_half: 2781 btst 1, %o0 ! check for 2782 bz,pt %ncc, .ci_med_half1 ! half word alignment 2783 nop 2784 lduba [%o0]ASI_USER, %o3 ! load one byte 2785 inc %o0 2786 stb %o3,[%o1] ! store byte 2787 inc %o1 2788 dec %o2 2789! 2790! Now half word aligned and have at least 38 bytes to move 2791! 2792.ci_med_half1: 2793 sub %o2, 7, %o2 ! adjust count to allow cc zero test 2794.ci_med_hmove: 2795 lduha [%o0]ASI_USER, %o3 ! read half word 2796 subcc %o2, 8, %o2 ! reduce count by 8 2797 sth %o3, [%o1] ! write half word 2798 add %o0, 2, %o0 ! advance SRC by 2 2799 lduha [%o0]ASI_USER, %o3 ! repeat for a total for 4 halfwords 2800 add %o0, 2, %o0 ! advance SRC by 2 2801 sth %o3, [%o1 + 2] 2802 add %o1, 8, %o1 ! advance DST by 8 2803 lduha [%o0]ASI_USER, %o3 2804 add %o0, 2, %o0 ! advance SRC by 2 2805 sth %o3, [%o1 - 4] 2806 lduha [%o0]ASI_USER, %o3 2807 add %o0, 2, %o0 ! advance SRC by 2 2808 bgt,pt %ncc, .ci_med_hmove ! loop til 7 or fewer bytes left 2809 sth %o3, [%o1 - 2] 2810 addcc %o2, 7, %o2 ! restore count 2811 bz,pt %ncc, .ci_sm_exit 2812 deccc %o2 2813 bz,pt %ncc, .ci_sm_byte 2814 nop 2815 ba,pt %ncc, .ci_sm_half 2816 nop 2817 2818.sm_copyin_err: 2819 membar #Sync 2820 stn %o4, [THREAD_REG + T_LOFAULT] ! restore old t_lofault 2821 mov SM_SAVE_SRC, %o0 2822 mov SM_SAVE_DST, %o1 2823 mov SM_SAVE_COUNT, %o2 2824 ldn [THREAD_REG + T_COPYOPS], %o3 ! check for copyop handler 2825 tst %o3 2826 bz,pt %ncc, 3f ! if not, return error 2827 nop 2828 ldn [%o3 + CP_COPYIN], %o5 ! if handler, invoke it with 2829 jmp %o5 ! original arguments 2830 nop 28313: 2832 retl 2833 or %g0, -1, %o0 ! return errno value 2834 2835 SET_SIZE(copyin) 2836 2837 2838/* 2839 * The _more entry points are not intended to be used directly by 2840 * any caller from outside this file. They are provided to allow 2841 * profiling and dtrace of the portions of the copy code that uses 2842 * the floating point registers. 2843 * This entry is particularly important as DTRACE (at least as of 2844 * 4/2004) does not support leaf functions. 2845 */ 2846 2847 ENTRY(copyin_more) 2848.copyin_more: 2849 prefetch [%o0], #n_reads 2850 save %sp, -SA(MINFRAME + HWCOPYFRAMESIZE), %sp 2851 set .copyin_err, REAL_LOFAULT 2852 2853/* 2854 * Copy ins that reach here are larger than VIS_COPY_THRESHOLD bytes 2855 */ 2856.do_copyin: 2857 set copyio_fault, %l7 ! .copyio_fault is lofault val 2858 2859 ldn [THREAD_REG + T_LOFAULT], %l6 ! save existing handler 2860 membar #Sync ! sync error barrier 2861 stn %l7, [THREAD_REG + T_LOFAULT] ! set t_lofault 2862 2863 mov %i0, SAVE_SRC 2864 mov %i1, SAVE_DST 2865 mov %i2, SAVE_COUNT 2866 2867 FP_NOMIGRATE(6, 7) 2868 2869 rd %fprs, %o2 ! check for unused fp 2870 st %o2, [%fp + STACK_BIAS - SAVED_FPRS_OFFSET] ! save orig %fprs 2871 btst FPRS_FEF, %o2 2872 bz,a,pt %icc, .do_blockcopyin 2873 wr %g0, FPRS_FEF, %fprs 2874 2875 BST_FPQ2Q4_TOSTACK(%o2) 2876 2877.do_blockcopyin: 2878 rd %gsr, %o2 2879 stx %o2, [%fp + STACK_BIAS - SAVED_GSR_OFFSET] ! save gsr 2880 or %l6, FPUSED_FLAG, %l6 2881 2882 andcc DST, VIS_BLOCKSIZE - 1, TMP 2883 mov ASI_USER, %asi 2884 bz,pt %ncc, 2f 2885 neg TMP 2886 add TMP, VIS_BLOCKSIZE, TMP 2887 2888 ! TMP = bytes required to align DST on FP_BLOCK boundary 2889 ! Using SRC as a tmp here 2890 cmp TMP, 3 2891 bleu,pt %ncc, 1f 2892 sub CNT,TMP,CNT ! adjust main count 2893 sub TMP, 3, TMP ! adjust for end of loop test 2894.ci_blkalign: 2895 lduba [REALSRC]%asi, SRC ! move 4 bytes per loop iteration 2896 stb SRC, [DST] 2897 subcc TMP, 4, TMP 2898 lduba [REALSRC + 1]%asi, SRC 2899 add REALSRC, 4, REALSRC 2900 stb SRC, [DST + 1] 2901 lduba [REALSRC - 2]%asi, SRC 2902 add DST, 4, DST 2903 stb SRC, [DST - 2] 2904 lduba [REALSRC - 1]%asi, SRC 2905 bgu,pt %ncc, .ci_blkalign 2906 stb SRC, [DST - 1] 2907 2908 addcc TMP, 3, TMP ! restore count adjustment 2909 bz,pt %ncc, 2f ! no bytes left? 2910 nop 29111: lduba [REALSRC]%asi, SRC 2912 inc REALSRC 2913 inc DST 2914 deccc TMP 2915 bgu %ncc, 1b 2916 stb SRC, [DST - 1] 2917 29182: 2919 membar #StoreLoad 2920 andn REALSRC, 0x7, SRC 2921 2922 ! SRC - 8-byte aligned 2923 ! DST - 64-byte aligned 2924 ldda [SRC]%asi, %f16 2925 prefetcha [SRC + (1 * VIS_BLOCKSIZE)]%asi, #n_reads 2926 alignaddr REALSRC, %g0, %g0 2927 ldda [SRC + 0x08]%asi, %f18 2928 prefetcha [SRC + (2 * VIS_BLOCKSIZE)]%asi, #n_reads 2929 faligndata %f16, %f18, %f48 2930 ldda [SRC + 0x10]%asi, %f20 2931 prefetcha [SRC + (3 * VIS_BLOCKSIZE)]%asi, #n_reads 2932 faligndata %f18, %f20, %f50 2933 ldda [SRC + 0x18]%asi, %f22 2934 prefetcha [SRC + (4 * VIS_BLOCKSIZE)]%asi, #one_read 2935 faligndata %f20, %f22, %f52 2936 ldda [SRC + 0x20]%asi, %f24 2937 prefetcha [SRC + (8 * VIS_BLOCKSIZE)]%asi, #one_read 2938 faligndata %f22, %f24, %f54 2939 ldda [SRC + 0x28]%asi, %f26 2940 prefetcha [SRC + (12 * VIS_BLOCKSIZE)]%asi, #one_read 2941 faligndata %f24, %f26, %f56 2942 ldda [SRC + 0x30]%asi, %f28 2943 prefetcha [SRC + (16 * VIS_BLOCKSIZE)]%asi, #one_read 2944 faligndata %f26, %f28, %f58 2945 ldda [SRC + 0x38]%asi, %f30 2946 ldda [SRC + VIS_BLOCKSIZE]%asi, %f16 2947 sub CNT, VIS_BLOCKSIZE, CNT 2948 add SRC, VIS_BLOCKSIZE, SRC 2949 prefetcha [SRC + (19 * VIS_BLOCKSIZE)]%asi, #one_read 2950 add REALSRC, VIS_BLOCKSIZE, REALSRC 2951 ba,pt %ncc, 1f 2952 prefetcha [SRC + (23 * VIS_BLOCKSIZE)]%asi, #one_read 2953 .align 32 29541: 2955 ldda [SRC + 0x08]%asi, %f18 2956 faligndata %f28, %f30, %f60 2957 ldda [SRC + 0x10]%asi, %f20 2958 faligndata %f30, %f16, %f62 2959 stda %f48, [DST]ASI_BLK_P 2960 ldda [SRC + 0x18]%asi, %f22 2961 faligndata %f16, %f18, %f48 2962 ldda [SRC + 0x20]%asi, %f24 2963 faligndata %f18, %f20, %f50 2964 ldda [SRC + 0x28]%asi, %f26 2965 faligndata %f20, %f22, %f52 2966 ldda [SRC + 0x30]%asi, %f28 2967 faligndata %f22, %f24, %f54 2968 sub CNT, VIS_BLOCKSIZE, CNT 2969 ldda [SRC + 0x38]%asi, %f30 2970 faligndata %f24, %f26, %f56 2971 add DST, VIS_BLOCKSIZE, DST 2972 ldda [SRC + VIS_BLOCKSIZE]%asi, %f16 2973 faligndata %f26, %f28, %f58 2974 add REALSRC, VIS_BLOCKSIZE, REALSRC 2975 prefetcha [SRC + (3 * VIS_BLOCKSIZE)]%asi, #n_reads 2976 add SRC, VIS_BLOCKSIZE, SRC 2977 prefetcha [SRC + ((OLYMPUS_C_PREFETCH) * VIS_BLOCKSIZE)]%asi, #one_read 2978 cmp CNT, VIS_BLOCKSIZE + 8 2979 bgu,pt %ncc, 1b 2980 prefetcha [SRC + ((OLYMPUS_C_2ND_PREFETCH) * VIS_BLOCKSIZE)]%asi, #one_read 2981 2982 ! only if REALSRC & 0x7 is 0 2983 cmp CNT, VIS_BLOCKSIZE 2984 bne %ncc, 3f 2985 andcc REALSRC, 0x7, %g0 2986 bz,pt %ncc, 2f 2987 nop 29883: 2989 faligndata %f28, %f30, %f60 2990 faligndata %f30, %f16, %f62 2991 stda %f48, [DST]ASI_BLK_P 2992 add DST, VIS_BLOCKSIZE, DST 2993 ba,pt %ncc, 3f 2994 nop 29952: 2996 ldda [SRC + 0x08]%asi, %f18 2997 fsrc1 %f28, %f60 2998 ldda [SRC + 0x10]%asi, %f20 2999 fsrc1 %f30, %f62 3000 stda %f48, [DST]ASI_BLK_P 3001 ldda [SRC + 0x18]%asi, %f22 3002 fsrc1 %f16, %f48 3003 ldda [SRC + 0x20]%asi, %f24 3004 fsrc1 %f18, %f50 3005 ldda [SRC + 0x28]%asi, %f26 3006 fsrc1 %f20, %f52 3007 ldda [SRC + 0x30]%asi, %f28 3008 fsrc1 %f22, %f54 3009 ldda [SRC + 0x38]%asi, %f30 3010 fsrc1 %f24, %f56 3011 sub CNT, VIS_BLOCKSIZE, CNT 3012 add DST, VIS_BLOCKSIZE, DST 3013 add SRC, VIS_BLOCKSIZE, SRC 3014 add REALSRC, VIS_BLOCKSIZE, REALSRC 3015 fsrc1 %f26, %f58 3016 fsrc1 %f28, %f60 3017 fsrc1 %f30, %f62 3018 stda %f48, [DST]ASI_BLK_P 3019 add DST, VIS_BLOCKSIZE, DST 3020 ba,a,pt %ncc, 4f 3021 nop 3022 30233: tst CNT 3024 bz,a %ncc, 4f 3025 nop 3026 30275: lduba [REALSRC]ASI_USER, TMP 3028 inc REALSRC 3029 inc DST 3030 deccc CNT 3031 bgu %ncc, 5b 3032 stb TMP, [DST - 1] 30334: 3034 3035.copyin_exit: 3036 membar #Sync 3037 3038 ldx [%fp + STACK_BIAS - SAVED_GSR_OFFSET], %o2 ! restore gsr 3039 wr %o2, 0, %gsr 3040 3041 ld [%fp + STACK_BIAS - SAVED_FPRS_OFFSET], %o3 3042 btst FPRS_FEF, %o3 3043 bz,pt %icc, 4f 3044 nop 3045 3046 BLD_FPQ2Q4_FROMSTACK(%o2) 3047 3048 ba,pt %ncc, 1f 3049 wr %o3, 0, %fprs ! restore fprs 3050 30514: 3052 FZEROQ2Q4 3053 wr %o3, 0, %fprs ! restore fprs 3054 30551: 3056 membar #Sync ! sync error barrier 3057 andn %l6, FPUSED_FLAG, %l6 3058 stn %l6, [THREAD_REG + T_LOFAULT] ! restore old t_lofault 3059 FP_ALLOWMIGRATE(5, 6) 3060 ret 3061 restore %g0, 0, %o0 3062/* 3063 * We got here because of a fault during copyin 3064 * Errno value is in ERRNO, but DDI/DKI says return -1 (sigh). 3065 */ 3066.copyin_err: 3067 ldn [THREAD_REG + T_COPYOPS], %o4 ! check for copyop handler 3068 tst %o4 3069 bz,pt %ncc, 2f ! if not, return error 3070 nop 3071 ldn [%o4 + CP_COPYIN], %g2 ! if handler, invoke it with 3072 jmp %g2 ! original arguments 3073 restore %g0, 0, %g0 ! dispose of copy window 30742: 3075 ret 3076 restore %g0, -1, %o0 ! return error value 3077 3078 3079 SET_SIZE(copyin_more) 3080 3081 ENTRY(xcopyin) 3082 3083 cmp %o2, VIS_COPY_THRESHOLD ! check for leaf rtn case 3084 bleu,pt %ncc, .xcopyin_small ! go to larger cases 3085 xor %o0, %o1, %o3 ! are src, dst alignable? 3086 btst 7, %o3 ! 3087 bz,pt %ncc, .xcopyin_8 ! check for longword alignment 3088 nop 3089 btst 1, %o3 ! 3090 bz,pt %ncc, .xcopyin_2 ! check for half-word 3091 nop 3092 sethi %hi(hw_copy_limit_1), %o3 ! Check copy limit 3093 ld [%o3 + %lo(hw_copy_limit_1)], %o3 3094 tst %o3 3095 bz,pn %icc, .xcopyin_small ! if zero, disable HW copy 3096 cmp %o2, %o3 ! if length <= limit 3097 bleu,pt %ncc, .xcopyin_small ! go to small copy 3098 nop 3099 ba,pt %ncc, .xcopyin_more ! otherwise go to large copy 3100 nop 3101.xcopyin_2: 3102 btst 3, %o3 ! 3103 bz,pt %ncc, .xcopyin_4 ! check for word alignment 3104 nop 3105 sethi %hi(hw_copy_limit_2), %o3 ! Check copy limit 3106 ld [%o3 + %lo(hw_copy_limit_2)], %o3 3107 tst %o3 3108 bz,pn %icc, .xcopyin_small ! if zero, disable HW copy 3109 cmp %o2, %o3 ! if length <= limit 3110 bleu,pt %ncc, .xcopyin_small ! go to small copy 3111 nop 3112 ba,pt %ncc, .xcopyin_more ! otherwise go to large copy 3113 nop 3114.xcopyin_4: 3115 ! already checked longword, must be word aligned 3116 sethi %hi(hw_copy_limit_4), %o3 ! Check copy limit 3117 ld [%o3 + %lo(hw_copy_limit_4)], %o3 3118 tst %o3 3119 bz,pn %icc, .xcopyin_small ! if zero, disable HW copy 3120 cmp %o2, %o3 ! if length <= limit 3121 bleu,pt %ncc, .xcopyin_small ! go to small copy 3122 nop 3123 ba,pt %ncc, .xcopyin_more ! otherwise go to large copy 3124 nop 3125.xcopyin_8: 3126 sethi %hi(hw_copy_limit_8), %o3 ! Check copy limit 3127 ld [%o3 + %lo(hw_copy_limit_8)], %o3 3128 tst %o3 3129 bz,pn %icc, .xcopyin_small ! if zero, disable HW copy 3130 cmp %o2, %o3 ! if length <= limit 3131 bleu,pt %ncc, .xcopyin_small ! go to small copy 3132 nop 3133 ba,pt %ncc, .xcopyin_more ! otherwise go to large copy 3134 nop 3135 3136.xcopyin_small: 3137 sethi %hi(.sm_xcopyin_err), %o5 ! .sm_xcopyin_err is lofault value 3138 or %o5, %lo(.sm_xcopyin_err), %o5 3139 ldn [THREAD_REG + T_LOFAULT], %o4 ! set/save t_lofaul 3140 membar #Sync ! sync error barrier 3141 ba,pt %ncc, .sm_do_copyin ! common code 3142 stn %o5, [THREAD_REG + T_LOFAULT] 3143 3144.xcopyin_more: 3145 save %sp, -SA(MINFRAME + HWCOPYFRAMESIZE), %sp 3146 sethi %hi(.xcopyin_err), REAL_LOFAULT ! .xcopyin_err is lofault value 3147 ba,pt %ncc, .do_copyin 3148 or REAL_LOFAULT, %lo(.xcopyin_err), REAL_LOFAULT 3149 3150/* 3151 * We got here because of fault during xcopyin 3152 * Errno value is in ERRNO 3153 */ 3154.xcopyin_err: 3155 ldn [THREAD_REG + T_COPYOPS], %o4 ! check for copyop handler 3156 tst %o4 3157 bz,pt %ncc, 2f ! if not, return error 3158 nop 3159 ldn [%o4 + CP_XCOPYIN], %g2 ! if handler, invoke it with 3160 jmp %g2 ! original arguments 3161 restore %g0, 0, %g0 ! dispose of copy window 31622: 3163 ret 3164 restore ERRNO, 0, %o0 ! return errno value 3165 3166.sm_xcopyin_err: 3167 3168 membar #Sync 3169 stn %o4, [THREAD_REG + T_LOFAULT] ! restore old t_lofault 3170 mov SM_SAVE_SRC, %o0 3171 mov SM_SAVE_DST, %o1 3172 mov SM_SAVE_COUNT, %o2 3173 ldn [THREAD_REG + T_COPYOPS], %o3 ! check for copyop handler 3174 tst %o3 3175 bz,pt %ncc, 3f ! if not, return error 3176 nop 3177 ldn [%o3 + CP_XCOPYIN], %o5 ! if handler, invoke it with 3178 jmp %o5 ! original arguments 3179 nop 31803: 3181 retl 3182 or %g1, 0, %o0 ! return errno value 3183 3184 SET_SIZE(xcopyin) 3185 3186 ENTRY(xcopyin_little) 3187 sethi %hi(.xcopyio_err), %o5 3188 or %o5, %lo(.xcopyio_err), %o5 3189 ldn [THREAD_REG + T_LOFAULT], %o4 3190 membar #Sync ! sync error barrier 3191 stn %o5, [THREAD_REG + T_LOFAULT] 3192 mov %o4, %o5 3193 3194 subcc %g0, %o2, %o3 3195 add %o0, %o2, %o0 3196 bz,pn %ncc, 2f ! check for zero bytes 3197 sub %o2, 1, %o4 3198 add %o0, %o4, %o0 ! start w/last byte 3199 add %o1, %o2, %o1 3200 lduba [%o0 + %o3]ASI_AIUSL, %o4 3201 32021: stb %o4, [%o1 + %o3] 3203 inccc %o3 3204 sub %o0, 2, %o0 ! get next byte 3205 bcc,a,pt %ncc, 1b 3206 lduba [%o0 + %o3]ASI_AIUSL, %o4 3207 32082: 3209 membar #Sync ! sync error barrier 3210 stn %o5, [THREAD_REG + T_LOFAULT] ! restore old t_lofault 3211 retl 3212 mov %g0, %o0 ! return (0) 3213 3214.xcopyio_err: 3215 membar #Sync ! sync error barrier 3216 stn %o5, [THREAD_REG + T_LOFAULT] ! restore old t_lofault 3217 retl 3218 mov %g1, %o0 3219 3220 SET_SIZE(xcopyin_little) 3221 3222 3223/* 3224 * Copy a block of storage - must not overlap (from + len <= to). 3225 * No fault handler installed (to be called under on_fault()) 3226 */ 3227 ENTRY(copyin_noerr) 3228 3229 cmp %o2, VIS_COPY_THRESHOLD ! check for leaf rtn case 3230 bleu,pt %ncc, .copyin_ne_small ! go to larger cases 3231 xor %o0, %o1, %o3 ! are src, dst alignable? 3232 btst 7, %o3 ! 3233 bz,pt %ncc, .copyin_ne_8 ! check for longword alignment 3234 nop 3235 btst 1, %o3 ! 3236 bz,pt %ncc, .copyin_ne_2 ! check for half-word 3237 nop 3238 sethi %hi(hw_copy_limit_1), %o3 ! Check copy limit 3239 ld [%o3 + %lo(hw_copy_limit_1)], %o3 3240 tst %o3 3241 bz,pn %icc, .copyin_ne_small ! if zero, disable HW copy 3242 cmp %o2, %o3 ! if length <= limit 3243 bleu,pt %ncc, .copyin_ne_small ! go to small copy 3244 nop 3245 ba,pt %ncc, .copyin_noerr_more ! otherwise go to large copy 3246 nop 3247.copyin_ne_2: 3248 btst 3, %o3 ! 3249 bz,pt %ncc, .copyin_ne_4 ! check for word alignment 3250 nop 3251 sethi %hi(hw_copy_limit_2), %o3 ! Check copy limit 3252 ld [%o3 + %lo(hw_copy_limit_2)], %o3 3253 tst %o3 3254 bz,pn %icc, .copyin_ne_small ! if zero, disable HW copy 3255 cmp %o2, %o3 ! if length <= limit 3256 bleu,pt %ncc, .copyin_ne_small ! go to small copy 3257 nop 3258 ba,pt %ncc, .copyin_noerr_more ! otherwise go to large copy 3259 nop 3260.copyin_ne_4: 3261 ! already checked longword, must be word aligned 3262 sethi %hi(hw_copy_limit_4), %o3 ! Check copy limit 3263 ld [%o3 + %lo(hw_copy_limit_4)], %o3 3264 tst %o3 3265 bz,pn %icc, .copyin_ne_small ! if zero, disable HW copy 3266 cmp %o2, %o3 ! if length <= limit 3267 bleu,pt %ncc, .copyin_ne_small ! go to small copy 3268 nop 3269 ba,pt %ncc, .copyin_noerr_more ! otherwise go to large copy 3270 nop 3271.copyin_ne_8: 3272 sethi %hi(hw_copy_limit_8), %o3 ! Check copy limit 3273 ld [%o3 + %lo(hw_copy_limit_8)], %o3 3274 tst %o3 3275 bz,pn %icc, .copyin_ne_small ! if zero, disable HW copy 3276 cmp %o2, %o3 ! if length <= limit 3277 bleu,pt %ncc, .copyin_ne_small ! go to small copy 3278 nop 3279 ba,pt %ncc, .copyin_noerr_more ! otherwise go to large copy 3280 nop 3281 3282.copyin_ne_small: 3283 ldn [THREAD_REG + T_LOFAULT], %o4 3284 tst %o4 3285 bz,pn %ncc, .sm_do_copyin 3286 nop 3287 sethi %hi(.sm_copyio_noerr), %o5 3288 or %o5, %lo(.sm_copyio_noerr), %o5 3289 membar #Sync ! sync error barrier 3290 ba,pt %ncc, .sm_do_copyin 3291 stn %o5, [THREAD_REG + T_LOFAULT] ! set/save t_lofault 3292 3293.copyin_noerr_more: 3294 save %sp, -SA(MINFRAME + HWCOPYFRAMESIZE), %sp 3295 sethi %hi(.copyio_noerr), REAL_LOFAULT 3296 ba,pt %ncc, .do_copyin 3297 or REAL_LOFAULT, %lo(.copyio_noerr), REAL_LOFAULT 3298 3299.copyio_noerr: 3300 jmp %l6 3301 restore %g0,0,%g0 3302 3303.sm_copyio_noerr: 3304 membar #Sync 3305 stn %o4, [THREAD_REG + T_LOFAULT] ! restore t_lofault 3306 jmp %o4 3307 nop 3308 3309 SET_SIZE(copyin_noerr) 3310 3311/* 3312 * Copy a block of storage - must not overlap (from + len <= to). 3313 * No fault handler installed (to be called under on_fault()) 3314 */ 3315 3316 ENTRY(copyout_noerr) 3317 3318 cmp %o2, VIS_COPY_THRESHOLD ! check for leaf rtn case 3319 bleu,pt %ncc, .copyout_ne_small ! go to larger cases 3320 xor %o0, %o1, %o3 ! are src, dst alignable? 3321 btst 7, %o3 ! 3322 bz,pt %ncc, .copyout_ne_8 ! check for longword alignment 3323 nop 3324 btst 1, %o3 ! 3325 bz,pt %ncc, .copyout_ne_2 ! check for half-word 3326 nop 3327 sethi %hi(hw_copy_limit_1), %o3 ! Check copy limit 3328 ld [%o3 + %lo(hw_copy_limit_1)], %o3 3329 tst %o3 3330 bz,pn %icc, .copyout_ne_small ! if zero, disable HW copy 3331 cmp %o2, %o3 ! if length <= limit 3332 bleu,pt %ncc, .copyout_ne_small ! go to small copy 3333 nop 3334 ba,pt %ncc, .copyout_noerr_more ! otherwise go to large copy 3335 nop 3336.copyout_ne_2: 3337 btst 3, %o3 ! 3338 bz,pt %ncc, .copyout_ne_4 ! check for word alignment 3339 nop 3340 sethi %hi(hw_copy_limit_2), %o3 ! Check copy limit 3341 ld [%o3 + %lo(hw_copy_limit_2)], %o3 3342 tst %o3 3343 bz,pn %icc, .copyout_ne_small ! if zero, disable HW copy 3344 cmp %o2, %o3 ! if length <= limit 3345 bleu,pt %ncc, .copyout_ne_small ! go to small copy 3346 nop 3347 ba,pt %ncc, .copyout_noerr_more ! otherwise go to large copy 3348 nop 3349.copyout_ne_4: 3350 ! already checked longword, must be word aligned 3351 sethi %hi(hw_copy_limit_4), %o3 ! Check copy limit 3352 ld [%o3 + %lo(hw_copy_limit_4)], %o3 3353 tst %o3 3354 bz,pn %icc, .copyout_ne_small ! if zero, disable HW copy 3355 cmp %o2, %o3 ! if length <= limit 3356 bleu,pt %ncc, .copyout_ne_small ! go to small copy 3357 nop 3358 ba,pt %ncc, .copyout_noerr_more ! otherwise go to large copy 3359 nop 3360.copyout_ne_8: 3361 sethi %hi(hw_copy_limit_8), %o3 ! Check copy limit 3362 ld [%o3 + %lo(hw_copy_limit_8)], %o3 3363 tst %o3 3364 bz,pn %icc, .copyout_ne_small ! if zero, disable HW copy 3365 cmp %o2, %o3 ! if length <= limit 3366 bleu,pt %ncc, .copyout_ne_small ! go to small copy 3367 nop 3368 ba,pt %ncc, .copyout_noerr_more ! otherwise go to large copy 3369 nop 3370 3371.copyout_ne_small: 3372 ldn [THREAD_REG + T_LOFAULT], %o4 3373 tst %o4 3374 bz,pn %ncc, .sm_do_copyout 3375 nop 3376 sethi %hi(.sm_copyio_noerr), %o5 3377 or %o5, %lo(.sm_copyio_noerr), %o5 3378 membar #Sync ! sync error barrier 3379 ba,pt %ncc, .sm_do_copyout 3380 stn %o5, [THREAD_REG + T_LOFAULT] ! set/save t_lofault 3381 3382.copyout_noerr_more: 3383 save %sp, -SA(MINFRAME + HWCOPYFRAMESIZE), %sp 3384 sethi %hi(.copyio_noerr), REAL_LOFAULT 3385 ba,pt %ncc, .do_copyout 3386 or REAL_LOFAULT, %lo(.copyio_noerr), REAL_LOFAULT 3387 3388 SET_SIZE(copyout_noerr) 3389 3390 3391/* 3392 * hwblkclr - clears block-aligned, block-multiple-sized regions that are 3393 * longer than 256 bytes in length using spitfire's block stores. If 3394 * the criteria for using this routine are not met then it calls bzero 3395 * and returns 1. Otherwise 0 is returned indicating success. 3396 * Caller is responsible for ensuring use_hw_bzero is true and that 3397 * kpreempt_disable() has been called. 3398 */ 3399 ! %i0 - start address 3400 ! %i1 - length of region (multiple of 64) 3401 ! %l0 - saved fprs 3402 ! %l1 - pointer to saved %d0 block 3403 ! %l2 - saved curthread->t_lwp 3404 3405 ENTRY(hwblkclr) 3406 ! get another window w/space for one aligned block of saved fpregs 3407 save %sp, -SA(MINFRAME + 2*VIS_BLOCKSIZE), %sp 3408 3409 ! Must be block-aligned 3410 andcc %i0, (VIS_BLOCKSIZE-1), %g0 3411 bnz,pn %ncc, 1f 3412 nop 3413 3414 ! ... and must be 256 bytes or more 3415 cmp %i1, 256 3416 blu,pn %ncc, 1f 3417 nop 3418 3419 ! ... and length must be a multiple of VIS_BLOCKSIZE 3420 andcc %i1, (VIS_BLOCKSIZE-1), %g0 3421 bz,pn %ncc, 2f 3422 nop 3423 34241: ! punt, call bzero but notify the caller that bzero was used 3425 mov %i0, %o0 3426 call bzero 3427 mov %i1, %o1 3428 ret 3429 restore %g0, 1, %o0 ! return (1) - did not use block operations 3430 34312: rd %fprs, %l0 ! check for unused fp 3432 btst FPRS_FEF, %l0 3433 bz,pt %icc, 1f 3434 nop 3435 3436 ! save in-use fpregs on stack 3437 membar #Sync 3438 add %fp, STACK_BIAS - 65, %l1 3439 and %l1, -VIS_BLOCKSIZE, %l1 3440 stda %d0, [%l1]ASI_BLK_P 3441 34421: membar #StoreStore|#StoreLoad|#LoadStore 3443 wr %g0, FPRS_FEF, %fprs 3444 wr %g0, ASI_BLK_P, %asi 3445 3446 ! Clear block 3447 fzero %d0 3448 fzero %d2 3449 fzero %d4 3450 fzero %d6 3451 fzero %d8 3452 fzero %d10 3453 fzero %d12 3454 fzero %d14 3455 3456 mov 256, %i3 3457 ba,pt %ncc, .pz_doblock 3458 nop 3459 3460.pz_blkstart: 3461 ! stda %d0, [%i0 + 192]%asi ! in dly slot of branch that got us here 3462 stda %d0, [%i0 + 128]%asi 3463 stda %d0, [%i0 + 64]%asi 3464 stda %d0, [%i0]%asi 3465.pz_zinst: 3466 add %i0, %i3, %i0 3467 sub %i1, %i3, %i1 3468.pz_doblock: 3469 cmp %i1, 256 3470 bgeu,a %ncc, .pz_blkstart 3471 stda %d0, [%i0 + 192]%asi 3472 3473 cmp %i1, 64 3474 blu %ncc, .pz_finish 3475 3476 andn %i1, (64-1), %i3 3477 srl %i3, 4, %i2 ! using blocks, 1 instr / 16 words 3478 set .pz_zinst, %i4 3479 sub %i4, %i2, %i4 3480 jmp %i4 3481 nop 3482 3483.pz_finish: 3484 membar #Sync 3485 btst FPRS_FEF, %l0 3486 bz,a .pz_finished 3487 wr %l0, 0, %fprs ! restore fprs 3488 3489 ! restore fpregs from stack 3490 ldda [%l1]ASI_BLK_P, %d0 3491 membar #Sync 3492 wr %l0, 0, %fprs ! restore fprs 3493 3494.pz_finished: 3495 ret 3496 restore %g0, 0, %o0 ! return (bzero or not) 3497 3498 SET_SIZE(hwblkclr) 3499 3500 /* 3501 * Copy 32 bytes of data from src (%o0) to dst (%o1) 3502 * using physical addresses. 3503 */ 3504 ENTRY_NP(hw_pa_bcopy32) 3505 rdpr %pstate, %g1 3506 andn %g1, PSTATE_IE, %g2 3507 wrpr %g0, %g2, %pstate 3508 3509 rdpr %pstate, %g0 3510 ldxa [%o0]ASI_MEM, %o2 3511 add %o0, 8, %o0 3512 ldxa [%o0]ASI_MEM, %o3 3513 add %o0, 8, %o0 3514 ldxa [%o0]ASI_MEM, %o4 3515 add %o0, 8, %o0 3516 ldxa [%o0]ASI_MEM, %o5 3517 membar #Sync 3518 3519 stxa %o2, [%o1]ASI_MEM 3520 add %o1, 8, %o1 3521 stxa %o3, [%o1]ASI_MEM 3522 add %o1, 8, %o1 3523 stxa %o4, [%o1]ASI_MEM 3524 add %o1, 8, %o1 3525 stxa %o5, [%o1]ASI_MEM 3526 3527 retl 3528 wrpr %g0, %g1, %pstate 3529 3530 SET_SIZE(hw_pa_bcopy32) 3531 3532 DGDEF(use_hw_bcopy) 3533 .word 1 3534 DGDEF(use_hw_bzero) 3535 .word 1 3536 DGDEF(hw_copy_limit_1) 3537 .word 0 3538 DGDEF(hw_copy_limit_2) 3539 .word 0 3540 DGDEF(hw_copy_limit_4) 3541 .word 0 3542 DGDEF(hw_copy_limit_8) 3543 .word 0 3544 3545 .align 64 3546 .section ".text" 3547