1: /* 2: * Copyright (c) 1987 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: * 6: * @(#)mch_xxx.s 1.5 (2.11BSD GTE) 12/15/94 7: */ 8: #include "DEFS.h" 9: #include "../machine/mch_iopage.h" 10: #include "../machine/koverlay.h" 11: 12: /* 13: * noop() 14: * 15: * Do nothing. Typically used to provide enough time for interrupts to 16: * happen between a pair of spl's in C. We use noop rather than inserting 17: * meaningless instructions between the spl's to prevent any future C 18: * optimizer `improvements' from causing problems. 19: * 20: * delay(usec) 21: * long usec; 22: * 23: * Delay (approximately) usec micro-seconds. It really isn't very acurrate 24: * since we can be interrupted and take much longer than we intended, but 25: * that's alright - we just don't want to come home early ... 26: */ 27: ENTRY(delay) 28: mov 2(sp),r0 / r0 = hiint(usec) 29: mov 4(sp),r1 / r1 = loint(usec) 30: ashc $1,r0 / sob's ~= 1/2 micro second, 31: beq 2f / oops, got passed a delay of 0L-leave 32: tst r1 33: /* 34: * If the low int of the loop counter is zero, the double sob loop 35: * below will perform correctly, otherwise the high byte must be 36: * increment. 37: */ 38: beq 1f 39: inc r0 / correct for looping 40: 1: 41: sob r1,1b / sit on our hands for a while ... 42: sob r0,1b 43: 2: 44: ENTRY(noop) 45: rts pc 46: 47: /* 48: * idle() 49: * 50: * Sit and wait for something to happen ... 51: */ 52: 53: /* 54: * If you have a console display it's amusing to see a slowly rotating 55: * sequence of lights in the display. If the system is very active the display 56: * will appear blurred. 57: */ 58: INT(LOCAL, rdisply, 0377) / idle pattern 59: INT(LOCAL, wcount, 2) / rotate rdisply every wcount calls 60: 61: ENTRY(idle) 62: mov PS,-(sp) / save current SPL, indicate that no 63: mov $1,_noproc / process is running 64: dec wcount / if (--wcount <= 0) { 65: bgt 1f 66: mov $2,wcount / wcount = 2 67: clc / rdisply <<= 1 68: rol rdisply 69: bpl 1f / if (``one shifted out'') 70: bis $1,rdisply / rdisply |= 1 71: 1: / } 72: mov rdisply,r0 / wait displays contents of r0 73: SPLLOW / set SPL low so we can be interrupted 74: wait / wait for something to happen 75: mov (sp)+,PS / restore previous SPL 76: rts pc / and return 77: 78: #ifdef PROF 79: /* 80: * These words are to insure that times reported for any following routine do 81: * not include those spent while in idle mode when statistics are gathered 82: * for system profiling. 83: */ 84: rts pc 85: rts pc 86: rts pc 87: #endif 88: 89: 90: /* 91: * setjmp(env) 92: * label_t *env; 93: * 94: * longjmp(u, env) 95: * resume(u, env) 96: * memaddr u; 97: * label_t *env; 98: * 99: * Setjmp(env) will save the process' current register variable, stack, 100: * overlay and program counter context and return a zero. 101: * 102: * Longjmp(u, env) (and resume) will will generate a "return(1)" from the last 103: * call to setjmp(env) by mapping in the user structure pointed to by u, 104: * restoring the context saved by setjmp in env and returning a one. Note that 105: * registers are recovered statically from the env buffer rather than 106: * dynamically from the stack ... 107: * 108: * This longjmp differs from the longjmp found in the standard library and the 109: * VAX 4.3 kernel - it's actually closer to the resume routine of the 4.3 110: * kernel and, indeed, even used to be called resume in the 2.9 kernel. 111: * We've given it both names to promote some degree of compatibility between 112: * the 4.3 and 2.10 C kernel source ... 113: */ 114: ENTRY(setjmp) 115: mov (sp)+,r1 / save return address 116: mov (sp),r0 / r0 = env 117: mov r2,(r0)+ / save register variables r2 - r4 118: mov r3,(r0)+ / in env ... 119: mov r4,(r0)+ 120: mov r5,(r0)+ / frame pointer, 121: mov sp,(r0)+ / stack pointer, 122: #ifdef INET 123: mov PS,-(sp) / network stack pointer, 124: mov $010340,PS 125: mfpd sp 126: #ifdef CHECKSTACK 127: cmp (sp),$NET_STOP / (check network stack pointer to 128: bhi 1f / make sure it's in the network 129: cmp (sp),$NET_SBASE / stack ...) 130: bhi 2f 131: 1: 132: halt 133: 2: 134: #endif 135: mov (sp)+,(r0)+ 136: mov (sp)+,PS 137: #endif 138: mov __ovno,(r0)+ / overlay number, 139: mov r1,(r0)+ / and return address 140: clr r0 / return a zero for the setjmp call 141: jmp (r1) 142: 143: ENTRY(longjmp) 144: ENTRY(resume) 145: mov 2(sp),r0 / r0 = u 146: mov 4(sp),r1 / r1 = env 147: SPL7 / can't let anything in till we 148: / (at least) get a valid stack ... 149: mov r0,KDSA6 / map new process' u structure in 150: #ifdef INET 151: mov r0,SDSA6 / map supervisor stack area to same 152: #endif 153: mov (r1)+,r2 / restore register variables 154: mov (r1)+,r3 / from env ... 155: mov (r1)+,r4 156: mov (r1)+,r5 / frame pointer, 157: mov (r1)+,sp / stack pointer, 158: #ifdef INET 159: mov PS,-(sp) / network stack pointer, 160: mov $010340,PS 161: mov (r1)+,-(sp) 162: mtpd sp 163: mov (sp)+,PS 164: #endif 165: mov (r1)+,r0 / grab return overlay number ... 166: cmp r0,__ovno / old overlay currently mapped in? 167: beq 1f 168: mov r0,__ovno / nope, set new overlay number 169: asl r0 / compute descriptor index and map 170: mov ova(r0),OVLY_PAR / the old overlay back in ... 171: mov ovd(r0),OVLY_PDR 172: 1: 173: mov $1001,SSR0 / J-11 bug, force MMU registers to start 174: / tracking again between processes 175: SPLLOW / release interrupts and transfer back 176: mov $1,r0 / to setjmp return with a return 177: jmp *(r1)+ / value of 1 178: 179: /* 180: * struct uprof { / profile arguments 181: * short *pr_base; / buffer base 182: * unsigned pr_size; / buffer size 183: * unsigned pr_off; / pc offset 184: * unsigned pr_scale; / pc scaling 185: * } u_prof; 186: * 187: * addupc(pc, pbuf, ticks) 188: * caddr_t pc; 189: * struct uprof *pbuf; 190: * int ticks; 191: * 192: * Addupc implements the profil(2) facility: 193: * 194: * b = (pc - pbuf->pr_off)>>1; 195: * b *= pbuf->pr_scale>>1; 196: * b >>= 14; { 2^14 = 2^16/2/2 - because of the two `>>'s above } 197: * if (b < pbuf->pr_size) { 198: * b += pbuf->pr_base; 199: * if (fuword(b, &w) < 0 || suword(b, w) < 0) 200: * pbuf->pr_scale = 0; { turn off profiling } 201: * } 202: */ 203: ENTRY(addupc) 204: mov r2,-(sp) / save register so we can use it 205: mov 6(sp),r2 / r2 = pbuf 206: mov 4(sp),r0 / r0 = pc 207: sub 4(r2),r0 / r0 -= pbuf->pr_off 208: clc / r0 >>= 1 { ensure high bit 0 } 209: ror r0 210: mov 6(r2),r1 / r1 = pbuf->pr_scale 211: clc / r1 >>= 1 { ensure high bit 0 } 212: ror r1 213: mul r1,r0 / r0:r1 = r0 * (pbuf->pr_scale>>1) 214: ashc $-14.,r0 / r0:r1 >>= 14 215: inc r1 / *round* r1 to a word offset 216: bic $1,r1 217: cmp r1,2(r2) / if r1 > pbuf->pr_size 218: bhis 3f / bug out ... 219: add (r2),r1 / r1 += pbuf->pr_base 220: mov nofault,-(sp) / set up for possible memory fault when 221: mov $1f,nofault / access pbuf->pr_base[r1] : branch 222: / to 1f on fault 223: mfpd (r1) / pbuf->pr_base[r1] += ticks 224: add 12.(sp),(sp) 225: mtpd (r1) 226: br 2f / (branch around fault code) 227: 1: / on fault: disable profiling 228: clr 6(r2) / (pbuf->pr_scale = 0) 229: 2: 230: mov (sp)+,nofault / reset fault branch 231: 3: 232: mov (sp)+,r2 / restore saved registers 233: rts pc / and return 234: 235: #ifndef ENABLE34 236: /* 237: * fioword(addr) 238: * caddr_t addr; 239: * 240: * Fetch a word from an address on the I/O page, 241: * returning -1 if address does not exist. 242: */ 243: ENTRY(fioword) 244: mov nofault,-(sp) 245: mov $2f,nofault 246: mov *4(sp),r0 247: 1: 248: mov (sp)+,nofault 249: rts pc 250: 2: 251: mov $-1,r0 252: br 1b 253: #endif 254: 255: /* 256: * error = copystr(fromaddr, toaddr, maxlength, lencopied) 257: * int error; 258: * caddr_t fromaddr, toaddr; 259: * u_int maxlength, *lencopied; 260: * 261: * Copy a null terminated string from one point to another in the kernel 262: * address space. Returns zero on success, ENOENT if maxlength exceeded. If 263: * lencopied is non-zero, *lencopied gets the length of the copy (including 264: * the null terminating byte). 265: */ 266: ENTRY(copystr) 267: mov r2,-(sp) / need an extra register 268: mov 4.(sp),r0 / r0 = fromaddr 269: mov 6.(sp),r1 / r1 = toaddr 270: mov 8.(sp),r2 / r2 = maxlength (remaining space) 271: beq 2f / (exit early with ENOENT if 0) 272: 1: 273: movb (r0)+,(r1)+ / move a byte 274: beq 3f / (done when we cross the null) 275: sob r2,1b / and loop as long as there's room 276: 2: 277: mov $ENOENT,r0 / ran out of room - indicate failure 278: br 4f / and exit ... 279: 3: 280: clr r0 / success! 281: 4: 282: tst 10.(sp) / does the caller want the copy length? 283: beq 5f 284: sub 6.(sp),r1 / yes, figure out how much we copied: 285: mov r1,*10.(sp) / *lencopied = r1 {toaddr'} - toaddr 286: 5: 287: mov (sp)+,r2 / restore registers 288: rts pc / and return 289: 290: 291: /* 292: * Zero the core associated with a buffer. Since this routine calls mapin 293: * without saving the current map, it cannot be called from interrupt routines. 294: */ 295: ENTRY(clrbuf) 296: mov 2(sp),-(sp) / pass bp to mapin 297: jsr pc,_mapin / r0 = buffer pointer 298: tst (sp)+ 299: 300: tst _fpp / do we have floating point hardware? 301: beq 2f / nope, use regular clr instructions 302: 303: stfps -(sp) / save old floating point status 304: setd / use double precision 305: mov $MAXBSIZE\/32.,r1 / clear 32 bytes per loop 306: 1: 307: clrf (r0)+ 308: clrf (r0)+ 309: clrf (r0)+ 310: clrf (r0)+ 311: sob r1,1b 312: 313: ldfps (sp)+ / restore floating point status 314: br 4f 315: 2: 316: mov $MAXBSIZE\/8.,r1 / clear 8 bytes per loop 317: 3: 318: clr (r0)+ 319: clr (r0)+ 320: clr (r0)+ 321: clr (r0)+ 322: sob r1,1b 323: 4: 324: #ifdef DIAGNOSTIC 325: jmp _mapout / map out buffer 326: 327: #else 328: 329: mov _seg5+SE_DESC,KDSD5 / normalseg5(); 330: mov _seg5+SE_ADDR,KDSA5 331: rts pc 332: #endif 333: 334: 335: #ifdef DIAGNOSTIC 336: SPACE(GLOBAL, _hasmap, 2) / (struct bp *): SEG5 mapped 337: #endif 338: 339: /* 340: * caddr_t 341: * mapin(bp) 342: * struct buf *bp; 343: * 344: * Map in an out-of-address space buffer. If this is done 345: * from interrupt level, the previous map must be saved before 346: * mapin, and restored after mapout; e.g. 347: * segm save; 348: * saveseg5(save); 349: * mapin(bp); 350: * ... 351: * mapout(bp); 352: * restorseg5(save); 353: * 354: * caddr_t 355: * mapin(bp) 356: * register struct buf *bp; 357: * { 358: * register u_int paddr; 359: * register u_int offset; 360: * 361: * #ifdef DIAGNOSTIC 362: * if (hasmap) { 363: * printf("mapping %o over %o\n", bp, hasmap); 364: * panic("mapin"); 365: * } 366: * hasmap = bp; 367: * #endif 368: * offset = (u_int)bp->b_un.b_addr & 077; 369: * paddr = bftopaddr(bp); 370: * mapseg5((u_short)paddr, 371: * (u_short)(((u_int)DEV_BSIZE << 2) | (u_int)RW)); 372: * return(SEG5 + offset); 373: * } 374: */ 375: ENTRY(mapin) 376: mov 2(sp),r0 / r0 = bp 377: #ifdef DIAGNOSTIC 378: tst _hasmap / is buffer already mapped in?? 379: beq 9f 380: mov _hasmap,-(sp) / oops ... print out a message and die 381: mov r0,-(sp) / with a panic 382: mov $1f,-(sp) 383: STRING(LOCAL, 1, <mapping %o over %o\n\0>) 384: jsr pc,_printf 385: cmp (sp)+,(sp)+ 386: mov $1f,(sp) 387: STRING(LOCAL, 1, <mapin\0>) 388: jsr pc,_panic 389: /*NOTREACHED*/ 390: 9: 391: mov r0,_hasmap / save mapin buffer address 392: #endif 393: mov B_ADDR(r0),r1 / r1 = bp->b_addr 394: movb B_XMEM(r0),r0 / r0 = bp->b_xmem 395: mov r1,-(sp) / for later... 396: ashc $-6,r0 / r0:r1 = bftopaddr(bp) 397: mov r1,KDSA5 / mapseg5((u_short)r0:r1, 398: mov $DEV_BSIZE\<2|RW,KDSD5 / (DEV_BSIZE << 2) | RW) 399: mov (sp)+,r0 400: bic $!077,r0 / return(SEG5 + (bp->b_un.b_addr&077)) 401: add $0120000,r0 402: rts pc 403: 404: 405: #ifdef DIAGNOSTIC 406: /* 407: * Map out buffer pointed to by bp and restore previous mapping. 408: * Mapout is handled by a macro in seg.h if DIAGNOSTIC isn't defined. 409: * 410: * #ifdef DIAGNOSTIC 411: * void 412: * mapout(bp) 413: * struct buf *bp; 414: * { 415: * if (bp != hasmap) { 416: * printf("unmapping %o, not %o\n", bp, hasmap); 417: * panic("mapout"); 418: * } 419: * hasmap = NULL; 420: * 421: * normalseg5(); 422: * } 423: * #endif 424: */ 425: ENTRY(mapout) 426: cmp 2(sp),_hasmap / mapping out same buffer that was 427: beq 9f / mapped in? 428: mov _hasmap,-(sp) / not good ... print out a message 429: mov 4(sp),-(sp) / and die 430: mov $1f,-(sp) 431: STRING(LOCAL, 1, <unmapping %o; not %o\n\0>) 432: jsr pc,_printf 433: cmp (sp)+,(sp)+ 434: mov $1f,(sp) 435: STRING(LOCAL, 1, <mapout\0>) 436: jsr pc,_panic 437: /*NOTREACHED*/ 438: 9: 439: clr _hasmap / indicate mapping clear 440: mov _seg5+SE_DESC,KDSD5 / normalseg5(); 441: mov _seg5+SE_ADDR,KDSA5 442: rts pc 443: #endif 444: 445: 446: /* 447: * Save current SEG5 and SEG6 mapping in map and setup normal mapping. 448: * 449: * #define KD6 (((USIZE-1)<<8) | RW) / proto descriptor for u. 450: * savemap(map) 451: * register mapinfo map; 452: * { 453: * map[0].se_desc = *KDSD5; 454: * map[0].se_addr = *KDSA5; 455: * map[1].se_desc = *KDSD6; 456: * map[1].se_addr = *KDSA6; 457: * if (kdsa6) { 458: * *KDSD6 = KD6; 459: * *KDSA6 = kdsa6; 460: * } 461: * normalseg5(seg5); 462: * } 463: */ 464: ENTRY(savemap) 465: mov 2(sp),r0 / r0 = map 466: mov KDSD5,(r0)+ / map[0].se_desc = *KDSD5 467: mov KDSA5,(r0)+ / map[0].se_addr = *KDSA5 468: mov KDSD6,(r0)+ / map[1].se_desc = *KDSD6 469: mov KDSA6,(r0) / map[1].se_addr = *KDSA6 470: tst _kdsa6 / SEG mapped out?? 471: beq 9f 472: mov $USIZE-1\<8|RW,KDSD6 / yep, map it in, *KDSD6 = (USIZE, RW) 473: mov _kdsa6,KDSA6 / *KDSA6 = kdsa6 474: 9: 475: mov _seg5+SE_DESC,KDSD5 / normalseg5(); 476: mov _seg5+SE_ADDR,KDSA5 477: rts pc 478: 479: /* 480: * Restore SEG5 and SEG6 mapping from map. 481: * 482: * restormap(map) 483: * register mapinfo map; 484: * { 485: * *KDSD5 = map[0].se_desc; 486: * *KDSA5 = map[0].se_addr; 487: * *KDSD6 = map[1].se_desc; 488: * *KDSA6 = map[1].se_addr; 489: * } 490: */ 491: ENTRY(restormap) 492: mov 2(sp),r0 / r0 = map 493: mov (r0)+,KDSD5 / *KDSD5 = map[0].se_desc 494: mov (r0)+,KDSA5 / *KDSA5 = map[0].se_addr 495: mov (r0)+,KDSD6 / *KDSD6 = map[1].se_desc 496: mov (r0),KDSA6 / *KDSA6 = map[1].se_addr 497: rts pc 498: 499: /* 500: * savfp(fps) 501: * struct fps *fps; 502: * 503: * Save current floating point processor state: floating point status register, 504: * and all six floating point registers. 505: */ 506: ENTRY(savfp) 507: tst _fpp / do we really have floating point 508: beq 1f / hardware?? 509: 510: mov 2(sp),r1 / r1 = fps 511: stfps (r1)+ / save floating point status register 512: setd / (always save registers as double) 513: movf fr0,(r1)+ / and save floating point registers 514: movf fr1,(r1)+ 515: movf fr2,(r1)+ 516: movf fr3,(r1)+ 517: movf fr4,fr0 518: movf fr0,(r1)+ 519: movf fr5,fr0 520: movf fr0,(r1)+ 521: 1: 522: rts pc 523: 524: /* 525: * restfp(fps) 526: * struct fps *fps; 527: * 528: * Restore floating point processor state. 529: */ 530: ENTRY(restfp) 531: tst _fpp / do we really have floating point 532: beq 1f / hardware?? 533: 534: mov 2(sp),r1 / r0 = r1 = fps 535: mov r1,r0 536: setd / (we saved the registers as double) 537: add $8.+2.,r1 / skip fpsr and fr0 for now 538: movf (r1)+,fr1 / restore fr1 thru fr3 539: movf (r1)+,fr2 540: movf (r1)+,fr3 541: movf (r1)+,fr0 / grab and restore saved fr4 and fr5 542: movf fr0,fr4 543: movf (r1)+,fr0 544: movf fr0,fr5 545: movf 2(r0),fr0 / restore fr0 546: ldfps (r0) / and floating point status register 547: 1: 548: rts pc 549: 550: /* 551: * stst(fperr) 552: * struct fperr *fperr; 553: * 554: * Save floating point error registers. The argument is a pointer to a two 555: * word structure as defined in <pdp/fperr>. 556: */ 557: ENTRY(stst) 558: tst _fpp / do we really have floating point 559: beq 1f / hardware?? 560: stst *2(sp) / simple, no? 561: 1: 562: rts pc 563: 564: /* 565: * scanc(size, str, table, mask) 566: * u_int size; 567: * u_char *str, table[]; 568: * u_char mask; 569: * 570: * Scan through str up to (but not including str[size]) stopping when a 571: * character who's entry in table has mask bits set. Return number of 572: * characters left in str. 573: */ 574: ENTRY(scanc) 575: mov 2(sp),r0 / r0 = size 576: beq 3f / exit early if zero 577: mov 4(sp),r1 / r1 = str 578: mov r2,-(sp) / r2 = table 579: mov 6+2(sp),r2 580: mov r3,-(sp) / r3 = mask 581: mov 10+4(sp),r3 582: mov r4,-(sp) / r4 is temporary 583: 1: / do 584: clr r4 / if (table[*str++] & mask) 585: bisb (r1)+,r4 586: add r2,r4 587: bitb r3,(r4) 588: bne 2f / break; 589: sob r0,1b / while (--size != 0) 590: 2: 591: mov (sp)+,r4 / restore registers 592: mov (sp)+,r3 593: mov (sp)+,r2 594: 3: 595: rts pc / and return size 596: 597: 598: /* 599: * locc(mask, size, str) 600: * u_char mask; 601: * u_int size; 602: * u_char *str; 603: * 604: * Scan through str up to (but not including str[size]) stopping when a 605: * character equals mask. Return number of characters left in str. 606: */ 607: ENTRY(locc) 608: mov 4(sp),r0 / r0 = size 609: beq 3f / exit early if zero 610: mov 6(sp),r1 / r1 = str 611: mov r2,-(sp) / r2 = mask 612: mov 2+2(sp),r2 613: 1: / do 614: cmpb (r1)+,r2 / if (*str++ == mask) 615: beq 2f 616: sob r0,1b / while (--size != 0) 617: 2: 618: mov (sp)+,r2 / restore registers 619: 3: 620: rts pc / and return size 621: 622: /* 623: * nextiv() 624: * 625: * Decrement _lastiv by size of a vector (4) and return the new value. 626: * Placed here for centralized access and easy calling from the networking 627: * (via SKcall) and 'autoconfig' (via ucall). 628: */ 629: ENTRY(nextiv) 630: sub $4,_lastiv / adjust last interrupt vector 631: mov _lastiv,r0 / put in right place for return value 632: rts pc / return assigned vector 633: 634: /* 635: * vattr_null() 636: * 637: * Initialize a inode attribute structure. See the comments in h/inode.h 638: * for more details. If the vnode/inode attribute structure (which is a 639: * subset of 4.4's) changes then this routine must change also. The 'sxt' 640: * sequences below are shorter/faster than "mov $VNOVAL,..." since VNOVAL 641: * is -1. 642: */ 643: ENTRY(vattr_null) 644: mov 2(sp),r0 / get address of vattr structure 645: mov $-1,(r0)+ / va_mode = VNOVAL 646: sxt (r0)+ / va_uid = VNOVAL 647: sxt (r0)+ / va_gid = VNOVAL 648: sxt (r0)+ / va_size - hi = VNOVAL 649: sxt (r0)+ / va_size - lo = VNOVAL 650: sxt (r0)+ / va_atime - hi = VNOVAL 651: sxt (r0)+ / va_atime - lo = VNOVAL 652: sxt (r0)+ / va_mtime - hi = VNOVAL 653: sxt (r0)+ / va_mtime - lo = VNOVAL 654: sxt (r0)+ / va_flags = VNOVAL 655: clr (r0)+ / va_vaflags = 0 656: rts pc