| 1 | /* |
| 2 | * ========== Copyright Header Begin ========================================== |
| 3 | * |
| 4 | * Hypervisor Software File: util.h |
| 5 | * |
| 6 | * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. |
| 7 | * |
| 8 | * - Do no alter or remove copyright notices |
| 9 | * |
| 10 | * - Redistribution and use of this software in source and binary forms, with |
| 11 | * or without modification, are permitted provided that the following |
| 12 | * conditions are met: |
| 13 | * |
| 14 | * - Redistribution of source code must retain the above copyright notice, |
| 15 | * this list of conditions and the following disclaimer. |
| 16 | * |
| 17 | * - Redistribution in binary form must reproduce the above copyright notice, |
| 18 | * this list of conditions and the following disclaimer in the |
| 19 | * documentation and/or other materials provided with the distribution. |
| 20 | * |
| 21 | * Neither the name of Sun Microsystems, Inc. or the names of contributors |
| 22 | * may be used to endorse or promote products derived from this software |
| 23 | * without specific prior written permission. |
| 24 | * |
| 25 | * This software is provided "AS IS," without a warranty of any kind. |
| 26 | * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, |
| 27 | * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A |
| 28 | * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN |
| 29 | * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR |
| 30 | * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR |
| 31 | * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN |
| 32 | * OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR |
| 33 | * FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE |
| 34 | * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, |
| 35 | * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF |
| 36 | * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. |
| 37 | * |
| 38 | * You acknowledge that this software is not designed, licensed or |
| 39 | * intended for use in the design, construction, operation or maintenance of |
| 40 | * any nuclear facility. |
| 41 | * |
| 42 | * ========== Copyright Header End ============================================ |
| 43 | */ |
| 44 | /* |
| 45 | * Copyright 2007 Sun Microsystems, Inc. All rights reserved. |
| 46 | * Use is subject to license terms. |
| 47 | */ |
| 48 | |
| 49 | #ifndef _UTIL_H |
| 50 | #define _UTIL_H |
| 51 | |
| 52 | #pragma ident "@(#)util.h 1.22 07/09/11 SMI" |
| 53 | |
| 54 | #ifdef __cplusplus |
| 55 | extern "C" { |
| 56 | #endif |
| 57 | |
| 58 | #include <vcpu.h> |
| 59 | #include <abort.h> |
| 60 | #include <strand.h> |
| 61 | #include <platform/util.h> |
| 62 | |
| 63 | /* |
| 64 | * Size generation constants |
| 65 | */ |
| 66 | #define KB * 1024 |
| 67 | #define MB * 1024LL KB |
| 68 | #define GB * 1024LL MB |
| 69 | |
| 70 | /* |
| 71 | * Time constants |
| 72 | */ |
| 73 | #define MHZ * 1000000 |
| 74 | #define NS_PER_S 1000000000 |
| 75 | #define MS_PER_NS 1000000 |
| 76 | |
| 77 | /* |
| 78 | * L2$ line state |
| 79 | */ |
| 80 | #define L2_LINE_CLEAN 0 |
| 81 | #define L2_LINE_DIRTY 1 |
| 82 | #define L2_LINE_INVALID 2 |
| 83 | #define L2_LINE_NOT_FOUND 3 |
| 84 | |
| 85 | /* |
| 86 | * prefetch function to invalidate an L2$ line |
| 87 | */ |
| 88 | #define INVALIDATE_CACHE_LINE 0x18 |
| 89 | |
| 90 | /* BEGIN CSTYLED */ |
| 91 | |
| 92 | /* |
| 93 | * VCPU2GUEST_STRUCT - get the current guestp from a vcpup |
| 94 | * |
| 95 | * Delay Slot: safe in a delay slot |
| 96 | * Register overlap: vcpu and root may be the same register |
| 97 | */ |
| 98 | #define VCPU2GUEST_STRUCT(vcpu, guest) \ |
| 99 | ldx [vcpu + CPU_GUEST], guest |
| 100 | |
| 101 | |
| 102 | /* FIXME: do we ever use the following? */ |
| 103 | /* |
| 104 | * VCPU2ROOT_STRUCT - get the rootp from a vcpup |
| 105 | * |
| 106 | * Delay Slot: safe in a delay slot if vcpup is valid |
| 107 | * Register overlap: vcpu and root may be the same register |
| 108 | */ |
| 109 | #define VCPU2ROOT_STRUCT(vcpu, root) \ |
| 110 | ldx [vcpu + CPU_ROOT], root |
| 111 | |
| 112 | |
| 113 | /* |
| 114 | * VCPU2STRAND_STRUCT - get the current strandp from a vcpup |
| 115 | * |
| 116 | * Delay Slot: safe in a delay slot |
| 117 | * Register overlap: vcpu and strand may be the same register |
| 118 | */ |
| 119 | #define VCPU2STRAND_STRUCT(vcpu, strand) \ |
| 120 | ldx [vcpu + CPU_STRAND], strand |
| 121 | |
| 122 | |
| 123 | #define HSCRATCH_STRAND_STRUCT HSCRATCH0 |
| 124 | #define HSCRATCH_VCPU_STRUCT HSCRATCH1 |
| 125 | #define SCRATCHPAD_MEMBAR /* nothing for niagara */ |
| 126 | |
| 127 | /* |
| 128 | * VCPU_STRUCT - get the current vcpup from scratch |
| 129 | * |
| 130 | * Delay Slot: not safe in a delay slot |
| 131 | */ |
| 132 | #define VCPU_STRUCT(vcpu) \ |
| 133 | mov HSCRATCH_VCPU_STRUCT, vcpu ;\ |
| 134 | ldxa [vcpu]ASI_HSCRATCHPAD, vcpu |
| 135 | |
| 136 | /* |
| 137 | * SET_VCPU_STRUCT - set the vcpup into scratch |
| 138 | */ |
| 139 | #define SET_VCPU_STRUCT(vcpu, scr1) \ |
| 140 | mov HSCRATCH_VCPU_STRUCT, scr1 ;\ |
| 141 | stxa vcpu, [scr1]ASI_HSCRATCHPAD ;\ |
| 142 | SCRATCHPAD_MEMBAR |
| 143 | |
| 144 | /* |
| 145 | * STRAND_STRUCT - get the current strandp from scratch |
| 146 | * |
| 147 | * Delay Slot: not safe in a delay slot |
| 148 | */ |
| 149 | #define STRAND_STRUCT(strand) \ |
| 150 | mov HSCRATCH_STRAND_STRUCT, strand ;\ |
| 151 | ldxa [strand]ASI_HSCRATCHPAD, strand |
| 152 | |
| 153 | /* |
| 154 | * SET_STRAND_STRUCT - set the strandp into scratch |
| 155 | */ |
| 156 | #define SET_STRAND_STRUCT(strand, scr1) \ |
| 157 | mov HSCRATCH_STRAND_STRUCT, scr1 ;\ |
| 158 | stxa strand, [scr1]ASI_HSCRATCHPAD ;\ |
| 159 | SCRATCHPAD_MEMBAR |
| 160 | |
| 161 | /* |
| 162 | * STRAND2CONFIG_STRUCT - get the current configp from strandp |
| 163 | */ |
| 164 | #define STRAND2CONFIG_STRUCT(strand, configp) \ |
| 165 | ldx [strand + STRAND_CONFIGP], configp |
| 166 | |
| 167 | /* |
| 168 | * CONFIG_STRUCT - get the current configp from scratch |
| 169 | * |
| 170 | * Delay Slot: safe in a delay slot |
| 171 | */ |
| 172 | #define CONFIG_STRUCT(configp) \ |
| 173 | STRAND_STRUCT(configp) ;\ |
| 174 | STRAND2CONFIG_STRUCT(configp, configp) |
| 175 | |
| 176 | /* For the moment alias */ |
| 177 | #define ROOT_STRUCT(configp) CONFIG_STRUCT(configp) |
| 178 | |
| 179 | /* |
| 180 | * LOCK_ADDR - get the lock address from scratch |
| 181 | * |
| 182 | * Delay Slot: not safe in a delay slot |
| 183 | */ |
| 184 | #define LOCK_ADDR(LOCK, addr) \ |
| 185 | CONFIG_STRUCT(addr) ;\ |
| 186 | inc LOCK, addr |
| 187 | |
| 188 | |
| 189 | /* |
| 190 | * VCPU_GUEST_STRUCT - get both the current vcpup and guestp from scratch |
| 191 | * |
| 192 | * Delay Slot: not safe in a delay slot |
| 193 | * Register overlap: if vcpu and guest are the same then only the guest |
| 194 | * is returned, see GUEST_STRUCT |
| 195 | */ |
| 196 | #define VCPU_GUEST_STRUCT(vcpu, guest) \ |
| 197 | VCPU_STRUCT(vcpu) ;\ |
| 198 | VCPU2GUEST_STRUCT(vcpu, guest) |
| 199 | |
| 200 | |
| 201 | /* |
| 202 | * GUEST_STRUCT - get the current guestp from scratch |
| 203 | * |
| 204 | * Delay Slot: safe in a delay slot |
| 205 | */ |
| 206 | #define GUEST_STRUCT(guest) \ |
| 207 | VCPU_GUEST_STRUCT(guest, guest) |
| 208 | |
| 209 | |
| 210 | /* |
| 211 | * CTRL_DOMAIN - returns the service domain guest structure ptr |
| 212 | * |
| 213 | * Delay Slot: Safe in a delay slot |
| 214 | */ |
| 215 | #define CTRL_DOMAIN(guestp, scr1, scr2) \ |
| 216 | CONFIG_STRUCT(scr1) ;\ |
| 217 | ldx [scr1 + CONFIG_HVCTL_LDC], scr2 ;\ |
| 218 | mulx scr2, LDC_ENDPOINT_SIZE, scr2 ;\ |
| 219 | ldx [scr1 + CONFIG_HV_LDCS], guestp ;\ |
| 220 | add guestp, scr2, guestp ;\ |
| 221 | ldx [guestp + LDC_TARGET_GUEST], guestp |
| 222 | |
| 223 | /* |
| 224 | * PID2CPUP - convert physical cpu number to a pointer to the vcpu |
| 225 | * cpu structure thats currently running on it. |
| 226 | * FIXME: This needs removing .. including all uses |
| 227 | * because it's just rubbish! |
| 228 | */ |
| 229 | #define PID2VCPUP(pid, cpup, scr1, scr2) \ |
| 230 | .pushlocals ;\ |
| 231 | mov %g0, scr2 ;\ |
| 232 | 1: ;\ |
| 233 | cmp scr2, (NVCPUS - 1) ;\ |
| 234 | bg,a 2f ;\ |
| 235 | mov %g0, cpup ;\ |
| 236 | set VCPU_SIZE, scr1 ;\ |
| 237 | mulx scr2, scr1, cpup ;\ |
| 238 | CONFIG_STRUCT(scr1) ;\ |
| 239 | ldx [scr1 + CONFIG_VCPUS], scr1 ;\ |
| 240 | add scr1, cpup, cpup ;\ |
| 241 | VCPU2STRAND_STRUCT(cpup, scr1) ;\ |
| 242 | ldub [scr1 + STRAND_ID], scr1 ;\ |
| 243 | cmp scr1, pid ;\ |
| 244 | bne,a %icc, 1b ;\ |
| 245 | inc scr2 ;\ |
| 246 | 2: ;\ |
| 247 | .poplocals |
| 248 | |
| 249 | |
| 250 | /* the VCPUID2CPUP macro below assumes the array step is 8 */ |
| 251 | #if GUEST_VCPUS_INCR != 8 |
| 252 | #error "GUEST_VCPUS_INCR is not 8" |
| 253 | #endif |
| 254 | |
| 255 | #define GUEST_VCPUS_SHIFT 3 |
| 256 | |
| 257 | /* |
| 258 | * VCPUID2CPUP - convert a guest virtual cpu number to a pointer |
| 259 | * to the corresponding virtual cpu struct |
| 260 | * |
| 261 | * Register overlap: vcpuid and cpup may be the same register |
| 262 | * Delay Slot: safe in a delay slot |
| 263 | */ |
| 264 | #define VCPUID2CPUP(guestp, vcpuid, cpup, fail_label, scr1) \ |
| 265 | cmp vcpuid, NVCPUS ;\ |
| 266 | bgeu,pn %xcc, fail_label ;\ |
| 267 | sllx vcpuid, GUEST_VCPUS_SHIFT, cpup ;\ |
| 268 | set GUEST_VCPUS, scr1 ;\ |
| 269 | add cpup, scr1, cpup ;\ |
| 270 | ldx [guestp + cpup], cpup ;\ |
| 271 | brz,pn cpup, fail_label ;\ |
| 272 | nop |
| 273 | |
| 274 | |
| 275 | /* |
| 276 | * PCPUID2COREID - derive core id from physical cpu id |
| 277 | * |
| 278 | * Register overlap: pid and coreid may be the same register |
| 279 | * Delay slot: safe and complete in a delay slot |
| 280 | */ |
| 281 | #define PCPUID2COREID(pid, coreid) \ |
| 282 | srlx pid, CPUID_2_COREID_SHIFT, coreid |
| 283 | |
| 284 | |
| 285 | /* |
| 286 | * Standard return-from-hcall with status "errno" |
| 287 | */ |
| 288 | #define HCALL_RET(errno) \ |
| 289 | mov errno, %o0 ;\ |
| 290 | done |
| 291 | |
| 292 | /* |
| 293 | * HVCALL - make a subroutine call |
| 294 | * HVJMP - jmp to subroutine in reg |
| 295 | * HVRET - return from a subroutine call |
| 296 | * |
| 297 | * This hypervisor has a convention of using %g7 as the the |
| 298 | * return address. |
| 299 | */ |
| 300 | #define HVCALL(x) \ |
| 301 | ba,pt %xcc, x ;\ |
| 302 | rd %pc, %g7 |
| 303 | |
| 304 | #define HVJMP(reg, pc) \ |
| 305 | jmpl reg, pc ;\ |
| 306 | nop |
| 307 | |
| 308 | #define HVRET \ |
| 309 | jmp %g7 + SZ_INSTR ;\ |
| 310 | nop |
| 311 | |
| 312 | /* |
| 313 | * Strand stack operations |
| 314 | * |
| 315 | * These macros are deprecated, but aliased for back compatibility |
| 316 | * CPU_PUSH - push a val into the stack |
| 317 | * CPU_POP - pop val from the stack |
| 318 | * These macros temporarily push and pop values that need storing |
| 319 | * STRAND_PUSH - push a val into the stack |
| 320 | * STRAND_POP - pop val from the stack |
| 321 | * |
| 322 | */ |
| 323 | |
| 324 | #define CPU_PUSH(val, scr1, scr2, scr3) \ |
| 325 | STRAND_PUSH(val, scr1, scr2) |
| 326 | |
| 327 | #define CPU_POP(val, scr1, scr2, scr3) \ |
| 328 | STRAND_POP(val, scr1) |
| 329 | |
| 330 | /* Stack is empty if ptr = 0 */ |
| 331 | |
| 332 | #define STRAND_PUSH(val, scr1, scr2) \ |
| 333 | STRAND_STRUCT(scr1) ;\ |
| 334 | add scr1, STRAND_MINI_STACK, scr1 ;\ |
| 335 | ldx [scr1 + MINI_STACK_PTR], scr2 /* get stack ptr */ ;\ |
| 336 | cmp scr2, MINI_STACK_VAL_INCR*MINI_STACK_DEPTH ;\ |
| 337 | bge,a,pn %xcc, hvabort ;\ |
| 338 | rd %pc, %g1 ;\ |
| 339 | add scr2, MINI_STACK_VAL_INCR, scr2 /* next element */ ;\ |
| 340 | stx scr2, [scr1 + MINI_STACK_PTR] ;\ |
| 341 | add scr2, scr1, scr2 ;\ |
| 342 | /* store at previous ptr value */ ;\ |
| 343 | stx val, [scr2 + MINI_STACK_VAL - MINI_STACK_VAL_INCR] |
| 344 | |
| 345 | |
| 346 | #define STRAND_POP(val, scr1) \ |
| 347 | STRAND_STRUCT(scr1) ;\ |
| 348 | add scr1, STRAND_MINI_STACK, scr1 ;\ |
| 349 | ldx [scr1 + MINI_STACK_PTR], val ;\ |
| 350 | brlez,a,pn val, hvabort ;\ |
| 351 | rd %pc, %g1 ;\ |
| 352 | sub val, MINI_STACK_VAL_INCR, val ;\ |
| 353 | stx val, [scr1 + MINI_STACK_PTR] ;\ |
| 354 | add scr1, val, scr1 ;\ |
| 355 | ldx [scr1 + MINI_STACK_VAL], val |
| 356 | |
| 357 | |
| 358 | /* |
| 359 | * ATOMIC_OR_64 - atomically logical-or a value in a memory location |
| 360 | */ |
| 361 | #define ATOMIC_OR_64(addr, value, scr1, scr2) \ |
| 362 | .pushlocals ;\ |
| 363 | ldx [addr], scr1 ;\ |
| 364 | 0: or scr1, value, scr2 ;\ |
| 365 | casx [addr], scr1, scr2 ;\ |
| 366 | cmp scr1, scr2 ;\ |
| 367 | bne,a,pn %xcc, 0b ;\ |
| 368 | mov scr2, scr1 ;\ |
| 369 | .poplocals |
| 370 | |
| 371 | /* |
| 372 | * ATOMIC_ANDN_64 - atomically logical-andn a value in a memory location |
| 373 | * Returns oldvalue |
| 374 | */ |
| 375 | #define ATOMIC_ANDN_64(addr, value, oldvalue, scr2) \ |
| 376 | .pushlocals ;\ |
| 377 | ldx [addr], oldvalue ;\ |
| 378 | 0: andn oldvalue, value, scr2 ;\ |
| 379 | casx [addr], oldvalue, scr2 ;\ |
| 380 | cmp oldvalue, scr2 ;\ |
| 381 | bne,a,pn %xcc, 0b ;\ |
| 382 | mov scr2, oldvalue ;\ |
| 383 | .poplocals |
| 384 | |
| 385 | /* |
| 386 | * ATOMIC_SWAP_64 - swaps the value at addr with newvalue, returns |
| 387 | * the previous contents of addr as oldvalue |
| 388 | */ |
| 389 | #define ATOMIC_SWAP_64(addr, newvalue, oldvalue, scr2) \ |
| 390 | .pushlocals ;\ |
| 391 | ldx [addr], scr2 ;\ |
| 392 | 0: mov newvalue, oldvalue ;\ |
| 393 | casx [addr], scr2, oldvalue ;\ |
| 394 | cmp scr2, oldvalue ;\ |
| 395 | bne,a,pn %xcc, 0b ;\ |
| 396 | mov oldvalue, scr2 ;\ |
| 397 | .poplocals |
| 398 | |
| 399 | /* |
| 400 | * ATOMIC_ADD_64 - atomically add to a value stored in memory |
| 401 | */ |
| 402 | #define ATOMIC_ADD_64(addr, value, newvalue, scr2) \ |
| 403 | .pushlocals ;\ |
| 404 | ldx [addr], newvalue ;\ |
| 405 | 0: add newvalue, value, scr2 ;\ |
| 406 | casx [addr], newvalue, scr2 ;\ |
| 407 | cmp newvalue, scr2 ;\ |
| 408 | bne,a,pn %xcc, 0b ;\ |
| 409 | mov scr2, newvalue ;\ |
| 410 | add newvalue, value, newvalue ;\ |
| 411 | .poplocals |
| 412 | |
| 413 | |
| 414 | /* |
| 415 | * Locking primitives |
| 416 | */ |
| 417 | #define MEMBAR_ENTER \ |
| 418 | /* membar #StoreLoad|#StoreStore not necessary on Niagara */ |
| 419 | #define MEMBAR_EXIT \ |
| 420 | /* membar #LoadStore|#StoreStore not necessary on Niagara */ |
| 421 | |
| 422 | /* |
| 423 | * SPINLOCK_ENTER - claim lock by setting it to cpu#+1 spinning until it is |
| 424 | * free |
| 425 | */ |
| 426 | #define SPINLOCK_ENTER(lock, scr1, scr2) \ |
| 427 | .pushlocals ;\ |
| 428 | STRAND_STRUCT(scr1) ;\ |
| 429 | ldub [scr1 + STRAND_ID], scr2 /* my ID */ ;\ |
| 430 | inc scr2 /* lockID = cpuid + 1 */ ;\ |
| 431 | mov 0, scr1 ;\ |
| 432 | 1: ;\ |
| 433 | brz,pn scr1, 2f ;\ |
| 434 | nop ;\ |
| 435 | ;\ |
| 436 | be,a %xcc, hvabort ;\ |
| 437 | rd %pc, %g1 ;\ |
| 438 | 2: ;\ |
| 439 | mov scr2, scr1 ;\ |
| 440 | casx [lock], %g0, scr1 /* if zero, write my lockID */ ;\ |
| 441 | brnz,a,pn scr1, 1b ;\ |
| 442 | cmp scr2, scr1 ;\ |
| 443 | MEMBAR_ENTER ;\ |
| 444 | .poplocals |
| 445 | |
| 446 | /* |
| 447 | * SPINLOCK_EXIT - release lock |
| 448 | */ |
| 449 | #define SPINLOCK_EXIT(lock) ;\ |
| 450 | MEMBAR_EXIT ;\ |
| 451 | stx %g0, [lock] |
| 452 | |
| 453 | #define IS_CPU_IN_ERROR(cpup, scr1) \ |
| 454 | ldx [cpup + CPU_STATUS], scr1 ;\ |
| 455 | cmp scr1, CPU_STATE_ERROR |
| 456 | |
| 457 | /* |
| 458 | * LABEL_ADDRESS(label, reg) |
| 459 | * |
| 460 | * Args: |
| 461 | * label - assembler label |
| 462 | * reg - will hold the address of the label |
| 463 | * |
| 464 | * Calculate the (relocated) address of the target label. Only |
| 465 | * works if the target label is no more than 4092 bytes away from |
| 466 | * the current assembly origin. Also requires that the label be |
| 467 | * in the same source file, and in the same section as the macro |
| 468 | * invokation. |
| 469 | */ |
| 470 | #define LABEL_ADDRESS(label, reg) \ |
| 471 | .pushlocals ;\ |
| 472 | 0: rd %pc, reg ;\ |
| 473 | add reg, (label) - 0b, reg ;\ |
| 474 | .poplocals |
| 475 | |
| 476 | |
| 477 | /* |
| 478 | * RELOC_OFFSET(scr, reg) |
| 479 | * |
| 480 | * Args: |
| 481 | * scr - scratch register, different from "reg" |
| 482 | * reg - will hold the value of the relocation offset |
| 483 | * |
| 484 | * Calculates the offset of the current image relative to the |
| 485 | * address assigned by the linker. The returned offset value can be |
| 486 | * subtracted from labels calcuated with "setx" to obtain the actual |
| 487 | * address after relocation. |
| 488 | */ |
| 489 | #define RELOC_OFFSET(scr, reg) \ |
| 490 | .pushlocals ;\ |
| 491 | setx 0f, scr, reg /* reg = linker */ ;\ |
| 492 | 0: rd %pc, scr /* scr = actual */ ;\ |
| 493 | sub reg, scr, reg /* reg = l - a */ ;\ |
| 494 | .poplocals |
| 495 | |
| 496 | #define DELAY_SECS(scr1, scr2, SECS) \ |
| 497 | CPU_STRUCT(scr1) ;\ |
| 498 | CPU2ROOT_STRUCT(scr1, scr2) ;\ |
| 499 | ldx [scr2 + CONFIG_STICKFREQUENCY], scr2 ;\ |
| 500 | mulx scr2, SECS, scr2 ;\ |
| 501 | rd STICK, scr1 ;\ |
| 502 | add scr1, scr2, scr1 ;\ |
| 503 | 0: ;\ |
| 504 | rd STICK, scr2 ;\ |
| 505 | cmp scr2, scr1 ;\ |
| 506 | blu %xcc, 0b ;\ |
| 507 | nop |
| 508 | |
| 509 | /* |
| 510 | * SMALL_COPY_MACRO - byte-wise copy a small region of memory. |
| 511 | * |
| 512 | * Args: |
| 513 | * src - starting address |
| 514 | * len - length of region to copy |
| 515 | * dest - destination address |
| 516 | * scr - scratch |
| 517 | * |
| 518 | * All arguments are clobbered. |
| 519 | */ |
| 520 | #define SMALL_COPY_MACRO(src, len, dest, scr) \ |
| 521 | .pushlocals ;\ |
| 522 | 1: ldub [src], scr ;\ |
| 523 | inc src ;\ |
| 524 | deccc len ;\ |
| 525 | stb scr, [dest] ;\ |
| 526 | bnz,pt %xcc, 1b ;\ |
| 527 | inc dest ;\ |
| 528 | .poplocals |
| 529 | |
| 530 | /* |
| 531 | * SMALL_ZERO_MACRO - byte-wise zero a small region of memory. |
| 532 | * |
| 533 | * Args: |
| 534 | * addr - starting address |
| 535 | * len - length of region to copy |
| 536 | * |
| 537 | * All arguments are clobbered. |
| 538 | */ |
| 539 | #define SMALL_ZERO_MACRO(addr, len) \ |
| 540 | .pushlocals ;\ |
| 541 | brz,pn len, 2f ;\ |
| 542 | nop ;\ |
| 543 | 1: stb %g0, [addr] ;\ |
| 544 | deccc len ;\ |
| 545 | bnz,pt %xcc, 1b ;\ |
| 546 | inc addr ;\ |
| 547 | 2: ;\ |
| 548 | .poplocals |
| 549 | |
| 550 | /* |
| 551 | * Cstyle macro for minimum |
| 552 | */ |
| 553 | #define MIN(x, y) \ |
| 554 | ((x) < (y) ? (x) : (y)) \ |
| 555 | |
| 556 | /* END CSTYLED */ |
| 557 | |
| 558 | #ifdef __cplusplus |
| 559 | } |
| 560 | #endif |
| 561 | |
| 562 | #endif /* _UTIL_H */ |