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: 7: #if defined(LIBC_SCCS) && !defined(KERNEL) && !defined(SUPERVISOR) 8: <@(#)csv.s 2.4 (2.11BSD GTE) 12/24/92\0> 9: .even 10: #endif 11: 12: /* 13: * C register save and restore routines. When a C routine is called its stack 14: * frame (after csv or ovhandlr have set things up) looks like this: 15: * 16: * _________________________________ 17: * | return address to caller | 18: * |-------------------------------| 19: * r5-> | old r5 ("frame pointer") | 20: * |-------------------------------| 21: * | previous __ovno | 22: * |-------------------------------| 23: * | old r4 | 24: * |-------------------------------| 25: * | old r3 | 26: * |-------------------------------| 27: * | old r2 | 28: * |-------------------------------| 29: * sp-> | empty parameter slot | 30: * |_______________________________| 31: * 32: * The "empty parameter slot" is a simple optimization the compiler uses to 33: * avoid overhead in its generated parameter cleanup code after a function 34: * has been called. Rather than (for example) generating: 35: * 36: * mov foo,-(sp) / push parameter 37: * jsr pc,bar / call function 38: * tst (sp)+ / throw away parameter 39: * 40: * The compiler always keeps one empty slot on the stack and generates: 41: * 42: * mov foo,(sp) / pass parameter 43: * jsr pc,bar / call function 44: * 45: * The savings are not quite so dramatic when more than one parameter is 46: * passed, but still worth the effort. If the function has any local stack 47: * variables, space for them will have be be allocated by the function thereby 48: * "moving" the empty parameter slot down. 49: */ 50: 51: /* 52: * KERNEP and SUPERVISOR (network code) notes: 53: * 54: * Stack checking can be enabled for the KERNEL (and SUPERVISOR network) 55: * by defining CHECKSTACK in the config file. Looks to see if the 56: * kernel and supervisor (network) stacks have collided, etc. 57: * 58: * Networking kernel doesn't currently need overlays (and probably never 59: * will). If it's ever necessary to overlay the networking code, it would 60: * be done in exactly the same manner as that used by the kernel. This would 61: * actually end up simplifying things ... 62: * 63: * It's debatable whether or not the standard library, KERNEL, and 64: * SUPERVISOR copies of csv/cret should be integrated this way, because 65: * the ifdef's sometimes make it hard to keep track of things. But the 66: * code and comments here are complicated enough that it's worth the effort 67: * to keep all three versions in general sync. 68: */ 69: #include "DEFS.h" 70: 71: #ifndef SUPERVISOR /* networking kernel doesn't use overlays */ 72: #ifdef KERNEL 73: #include "../machine/mch_iopage.h" 74: #include "../machine/koverlay.h" 75: #endif 76: 77: .data 78: #ifdef KERNEL 79: .globl ova, ovd / overlay descriptor tables 80: #endif 81: .globl __ovno / currently mapped overlay 82: __ovno: 0 83: .text 84: 85: .globl _etext / used by cret to determine returns to overlay 86: / area (any return address higher than _etext) 87: / the loader defines only if referenced 88: 89: /* 90: * The loader (/bin/ld) generates `thunks' for functions loaded in overlays. 91: * A thunk resides in the base segment and takes the name _foo which is the 92: * function's interface to the outside world (this allows pointers to functions 93: * to work even if functions are located in overlays). The function itself is 94: * renamed to ~foo. 95: * 96: * ovhndlr(1-9,a-f) are called from the thunks via a jsr r5 after r1 is set to 97: * the location of the first instruction in the subroutine after the call to 98: * csv (~foo+4). 99: * 100: * _foo: mov $~foo+4,r1 101: * jsr r5,ovhndlr`n' 102: * 103: * The ovhndlr`n' in turn move the requested overlay number into r0 and 104: * branch to ovhndlr which sets the overlay, simulates a csv and transfers to 105: * (r1) (~foo+4). Thus, the function's call to csv is bypassed. 106: */ 107: #define ovh(x, n) .globl ovhndlr/**/x; \ 108: ovhndlr/**/x: \ 109: mov $n,r0; \ 110: br ovhndlr; 111: 112: ovh(1,001); ovh(2,002); ovh(3,003); ovh(4,004) 113: ovh(5,005); ovh(6,006); ovh(7,007); ovh(8,010) 114: ovh(9,011); ovh(a,012); ovh(b,013); ovh(c,014) 115: ovh(d,015); ovh(e,016); ovh(f,017) 116: 117: #ifndef KERNEL 118: emt = 0104000 / overlays switched by emulator trap 119: / overlay number is placed in r0 120: #endif KERNEL 121: 122: /* 123: * ovhndlr(ov::r0, ~foo+4::r1, _foo+8::r5) 124: * 125: * Ovhandler builds the new stack frame as fast as possible to avoid problems 126: * with getting interrupted halfway through. if we get interrupted between the 127: * "jsr r5,ovhndlr`x'" and the "mov sp,r5" below and a longjmp is attempted, 128: * rollback will fail utterly. If we get interrupted before we finish saving 129: * registers reserved for register variables and an attempt is made to longjmp 130: * to the caller of our service routine rollback will incorrectly pull `saved' 131: * register values from the incomplete stack frame leading to 132: * non-deterministic behavior. 133: * 134: * There's very little that can be done about this asside from changing the 135: * entire stack frame sequence which involves changes to the compiler, loader, 136: * this file and any other routine (like rollback) which `knows' how the C 137: * stack frame is put together ... 138: */ 139: ovhndlr: 140: #if defined(KERNEL) && defined(CHECKSTACK) 141: cmp sp, $_u / before the u. area? 142: blo 9f / yes, assume it's remapped, so OK 143: cmp sp, $KERN_SBASE / falling off the bottom? 144: bhi 9f / no, also OK 145: spl 7 / lock out interrupts 146: halt / can't 'panic', that uses the stack! 147: br . / in case continue is done 148: 9: 149: #endif 150: mov sp,r5 / simulate a csv ... 151: mov __ovno,-(sp) 152: cmp r0,(sp) / is the requested overlay already mapped? 153: beq 1f 154: #ifdef KERNEL 155: mov PS,-(sp) / save PS 156: SPL7 157: mov r0,__ovno / set new overlay number 158: asl r0 / compute descriptor index and map 159: mov ova(r0), OVLY_PAR / the new overlay in 160: mov ovd(r0), OVLY_PDR 161: mov (sp)+,PS / restore PS, unmask interrupts 162: #else 163: emt / no, ask the kernel for it ... 164: mov r0,__ovno / and indicate the new overlay 165: /* 166: * SPECIAL NOTE: the pair of instructions "emt" and "mov r0,__ovno" 167: * form a race condition. A signal can interrupt the sequence 168: * causing all sorts of nastiness if the signal routine calls a 169: * routine in the old overlay or is itself in the old overlay ... 170: * There is no solution that doesn't involve changing the way 171: * an overlay switch from the kernal. Most [potential] solutions 172: * significantly increase the overhead of an overlay switch. 173: * A tenable solution has yet to be found ... 174: */ 175: #endif 176: 1: 177: mov r4,-(sp) 178: mov r3,-(sp) 179: mov r2,-(sp) 180: jsr pc,(r1) / jsr leaves empty parameter slot on stack 181: #endif /* !SUPERVISOR */ 182: 183: 184: /* 185: * Csv for routines called directly (in base or intra-overlay calls). 186: * no overlays have been changed, so we just save the previous overlay 187: * number on the stack. Note that r0 isn't set to the current overlay 188: * because we weren't called through a thunk. 189: */ 190: .globl csv 191: csv: 192: #if (defined(KERNEL) || defined(SUPERVISOR)) && defined(CHECKSTACK) 193: #ifdef SUPERVISOR 194: cmp sp,$NET_STOP / out of the top of the stack? 195: bhi 8f / yes, die 196: cmp sp,$NET_SBASE / falling off the bottom? 197: bhi 9f / no, so OK 198: 8: 199: spl 7 / lock out interrupts 200: halt / can't 'panic', that uses the stack! 201: br . / in case continue is done 202: 9: 203: #else 204: cmp sp,$_u / before the u. area? 205: blo 9f / assume it was remapped, so OK 206: cmp sp,$KERN_SBASE / falling off the bottom? 207: bhi 9f / no, so OK 208: spl 7 / lock out interrupts 209: halt / can't 'panic', that uses the stack! 210: br . / in case continue is done 211: 9: 212: #endif 213: #endif 214: mov r5,r1 / save transfer address, 215: mov sp,r5 216: #ifdef SUPERVISOR 217: clr -(sp) 218: #else 219: mov __ovno,-(sp) 220: #endif 221: mov r4,-(sp) 222: mov r3,-(sp) 223: mov r2,-(sp) 224: jsr pc,(r1) 225: 226: /* 227: * Cret is used by everyone so it has to check if we're returning to an 228: * overlay different from the one that may be currently mapped. 229: */ 230: .globl cret 231: cret: 232: #if (defined(KERNEL) || defined(SUPERVISOR)) && defined(CHECKSTACK) 233: #ifdef SUPERVISOR 234: cmp sp,$NET_STOP / out of the top of the stack? 235: bhi 8f / yes, die 236: cmp sp,$NET_SBASE / falling off the bottom? 237: bhi 9f / no, so OK 238: 8: 239: spl 7 / lock out interrupts 240: halt / can't 'panic', that uses the stack! 241: br . / in case continue is done 242: 9: 243: #else 244: cmp sp,$_u / before the u. area? 245: blo 9f / assume it was remapped, so OK 246: cmp sp,$KERN_SBASE / falling off the bottom? 247: bhi 9f / no, so OK 248: spl 7 / lock out interrupts 249: halt / can't 'panic', that uses the stack! 250: br . / in case continue is done 251: 9: 252: #endif 253: #endif 254: mov r5,r2 255: #ifdef SUPERVISOR 256: tst -(r2) / skip over overlay slot 257: #else 258: mov -(r2),r4 / r4 = old __ovno - if non-zero we've started 259: bne 2f / using overlays so we'll have to make 260: / sure the old overlay is mapped if we're 261: / returning to the overlay area 262: 1: 263: #endif 264: mov -(r2),r4 / restore registers, reset stack, pop frame 265: mov -(r2),r3 / pointer and return 266: mov -(r2),r2 267: mov r5,sp / (more interrupt problems here *sigh* ...) 268: mov (sp)+,r5 269: rts pc 270: #ifndef SUPERVISOR 271: 2: 272: /* 273: * Not returning to base segment, so check that the right 274: * overlay is mapped in, and if not change the mapping. 275: */ 276: cmp r4,__ovno / current overlay same as old overlay? 277: beq 1b / lucked out! 278: #if defined(KERNEL) && defined(INET) 279: cmp 2(r5),$Kretu / must always restore overlays if returning 280: beq 3f / from SKcall 281: #endif 282: cmp 2(r5),$_etext / returning to base segment? 283: blos 1b / sometimes things *do* work out ... 284: #ifdef KERNEL 285: 3: 286: mov PS,-(sp) / (sigh) returning to a different overlay 287: SPL7 288: mov r4,__ovno / set new overlay number 289: asl r4 / and map the new overlay in 290: mov ova(r4), OVLY_PAR 291: mov ovd(r4), OVLY_PDR 292: mov (sp)+,PS / restore PS, unmask interrupts 293: br 1b 294: #else 295: mov r0,r3 / (sigh) returning to a different overlay - 296: mov r4,r0 / have to save r0 because we can't trash 297: emt / a function result and ask UNIX to switch 298: mov r4,__ovno / the old overlay in 299: mov r3,r0 / note that as with ovhndlr the pair "emt" 300: br 1b / "mov r4,__ovno" can be interrupted 301: #endif 302: #endif /* !SUPERVISOR */