|
|
1.1 root 1: /*
2: * File: ndp.c
3: *
4: * Purpose: all ndp-related functions, except for assembler routines
5: *
6: * $Log: ndp.c,v $
7: * Revision 1.7 93/06/14 13:43:02 bin
8: * Hal: kernel 78 update
9: *
10: * Revision 1.2 93/04/14 10:27:57 root
11: * r75
12: *
13: * Revision 1.1 92/11/09 17:09:23 root
14: * Just before adding vio segs.
15: *
16: */
17:
18: /*
19: * ----------------------------------------------------------------------
20: * Includes.
21: */
22: #include <sys/coherent.h>
23: #include <errno.h>
24: #include <sys/seg.h>
25:
26: /*
27: * ----------------------------------------------------------------------
28: * Definitions.
29: * Constants.
30: * Macros with argument lists.
31: * Typedefs.
32: * Enums.
33: */
34: /* bit positions in u.u_ndpFlags */
35: #define NF_NDP_USER 1 /* this process has used the ndp */
36: #define NF_NDP_SAVED 2 /* ndp status is saved in u area */
37: #define NF_EM_TRAPPED 4 /* no ndp, em trap has occurred */
38:
39: /* supported coprocessor types - will autosense if initially unpatched */
40: #define NDP_TYPE_UNPATCHED 0
41: #define NDP_TYPE_NONE 1
42: #define NDP_TYPE_287 2
43: #define NDP_TYPE_387 3
44: #define NDP_TYPE_486 4
45:
46: #define NDP_IRQ 13 /* 387 uses Irq for unmasked exceptions */
47: #define NDP_PORT 0xF0 /* 387 uses this port to clear exception */
48: /*
49: * ----------------------------------------------------------------------
50: * Functions.
51: * Import Functions.
52: * Export Functions.
53: * Local Functions.
54: */
55: void emFinit();
56: void emtrap();
57: void fptrap();
58: void ndpConRest();
59: void ndpDetach();
60: void ndpEmTraps();
61: void ndpEndProc();
62: void ndpIrq();
63: void ndpMine();
64: void ndpNewOwner();
65: void ndpNewProc();
66: char * ndpTypeName();
67: int rdEmTrapped();
68: int rdNdpSaved();
69: int rdNdpSavedU();
70: int rdNdpUser();
71: void senseNdp();
72: void wrEmTrapped();
73: void wrNdpSaved();
74: void wrNdpSavedU();
75: void wrNdpUser();
76:
77: /*
78: * ----------------------------------------------------------------------
79: * Global Data.
80: * Import Variables.
81: * Export Variables.
82: * Local Variables.
83: */
84:
85: /*
86: * ndp control word is 16 bits:
87: * 0000 RC:2 PC:2 01 PM:1 UM:1 OM:1 ZM:1 DM:1 IM:1
88: * RC - rounding control
89: * PC - precision control
90: * PM - precision mask
91: * UM - underflow mask
92: * OM - overflow mask
93: * ZM - zero divide mask
94: * DM - denormal operand mask
95: * IM - invalid operation mask
96: * for masks, 1 masks the exception
97: *
98: * iBCS2 page 3-46 specifies the following:
99: * 0000 : 00 10 : 0 1 1 1 : 0 0 1 0 = 0x0272
100: */
101:
102: /* Patchable ndp-related variables. */
103: short ndpCW = 0x0272; /* NDP Control Word at start of each NDP process. */
104: short ndpDump = 0; /* Patch to 1 for NDP register dump on FP exceptions. */
105: short ndpType = NDP_TYPE_UNPATCHED; /* Patch overrides NDP type sensing. */
106: int ndpEmSig = SIGFPE; /* signal sent on receiving emulator traps */
107:
108: /* Patchable emulator-related function pointers. */
109: int (*ndpEmFn)() = 0;
110: int (*ndpKfsave)() = 0;
111: int (*ndpKfrstor)() = 0;
112:
113: static int kerEm = 1; /* RAM copy of CR0 EM bit */
114: static int ndpUseg; /* system global address of U segment */
115: static PROC * ndpOwner; /* process whose stuff is now in ndp */
116:
117: /*
118: * ----------------------------------------------------------------------
119: * Code.
120: */
121:
122: /*
123: * Called from trap handler the first time a process executes an ndp
124: * instruction.
125: */
126: void
127: ndpNewOwner()
128: {
129: UPROC * up;
130:
131: /* disable further emulator traps for this process */
132: wrNdpUser(1);
133: ndpEmTraps(0);
134:
135: /* save old ndp status, if any process was using it */
136: if (ndpOwner) {
137: int work = workAlloc();
138: ptable1_v[work] = sysmem.u.pbase[btocrd(ndpUseg)] | SEG_RW;
139: mmuupd();
140: up = (UPROC *)(ctob(work) + U_OFFSET);
141: ndpSave(&up->u_ndpCon);
142: wrNdpSavedU(1, up);
143: workFree(work);
144: }
145:
146: /* Make current process NDP owner */
147: ndpMine();
148:
149: /* give process a clean ndp */
150: ndpInit(ndpCW);
151: }
152:
153: /*
154: * NDP initialization for a new process.
155: * Called at exec time.
156: * Sets defaults, before it is known whether the process uses NDP or not.
157: */
158: void
159: ndpNewProc()
160: {
161: /* default for a process is to trap on NDP instructions */
162: ndpEmTraps(1);
163: wrNdpUser(0);
164: wrNdpSaved(0);
165: wrEmTrapped(0);
166: }
167:
168: /*
169: * Restore some ndp info when doing a regular conrest().
170: * Called just after conrest - u area has just been restored.
171: */
172: void
173: ndpConRest()
174: {
175: UPROC * up;
176:
177: /* make CR0 EM bit match what this process needs */
178: ndpEmTraps(rdNdpUser() ? 0 : 1);
179:
180: /*
181: * If current process uses ndp, may need to fix ndp state
182: *
183: * By the nature of NDP save op's, if the NDP owner's NDP state
184: * is saved, then it's not in the NDP.
185: *
186: * So, we have to be careful (1) not to save twice, and (2) to
187: * restore, even if we are NDP owner, if NDP state is saved.
188: */
189: if (rdNdpUser()) {
190: if (ndpOwner != SELF) {
191: if (ndpOwner) { /* save old ndp state */
192: int work = workAlloc();
193: ptable1_v[work] =
194: sysmem.u.pbase[btocrd(ndpUseg)] | SEG_RW;
195: mmuupd();
196: up = (UPROC *)(ctob(work) + U_OFFSET);
197: if (!rdNdpSavedU(up)) {
198: ndpSave(&up->u_ndpCon);
199: wrNdpSavedU(1, up);
200: }
201: workFree(work);
202: }
203:
204: /* Make current process NDP owner and reload ndp state */
205: ndpMine();
206: ndpRestore(&u.u_ndpCon);
207: wrNdpSaved(0);
208: } else if (rdNdpSaved()) {
209: ndpRestore(&u.u_ndpCon);
210: wrNdpSaved(0);
211: }
212: }
213: }
214:
215: /*
216: * When a process exits, it relinquishes the ndp.
217: */
218: void
219: ndpEndProc()
220: {
221: if (SELF == ndpOwner)
222: ndpDetach();
223: }
224:
225: /*
226: * ----------------------------------------------------------------------
227: * Trap handlers.
228: */
229:
230: /*
231: * fptrap()
232: *
233: * Entered when NDP generates a CPU error.
234: * err is either SIFP or 0x0D40
235: */
236: #define RDUMP() { \
237: printf("\neax=%x ebx=%x ecx=%x edx=%x\n", eax, ebx, ecx, edx); \
238: printf("esi=%x edi=%x ebp=%x esp=%x\n", esi, edi, ebp, esp); \
239: printf("cs=%x ds=%x es=%x ss=%x fs=%x gs=%x\n", \
240: cs&0xffff, ds&0xffff, es&0xffff, ss&0xffff, fs&0xffff, gs&0xffff); \
241: printf("err #%d eip=%x uesp=%x cmd=%s\n", err, eip, uesp, u.u_comm); \
242: printf("efl=%x ", efl); }
243:
244: void
245: fptrap(gs, fs, es, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax, trapno, err,
246: eip, cs, efl, uesp, ss)
247: char *eip;
248: {
249: unsigned short sw; /* ndp status word */
250: struct _fpstate * fsp = &u.u_ndpCon;
251:
252: if (err == SIFP)
253: u.u_regl = &gs; /* hook in register set for consave/conrest */
254:
255: /*
256: * Send user a signal.
257: */
258: ndpSave(fsp);
259: /* Clear exception flag in NDP to prevent runaway trap. */
260: sw = fsp->status = fsp->sw;
261: fsp->sw &= 0x7f00;
262: wrNdpSaved(1);
263: if (ndpDump) {
264: RDUMP();
265: printf("\nfcs=%x fip=%x fos=%x foo=%x\n",
266: fsp->cssel&0xffff, fsp->ipoff,
267: fsp->datasel&0xffff, fsp->dataoff);
268: printf("User Floating Point Trap: ");
269: if (sw & 1)
270: printf("Invalid Operation");
271: else if (sw & 2)
272: printf("Denormalized Operand");
273: else if (sw & 4)
274: printf("Divide by Zero");
275: else if (sw & 8)
276: printf("Overflow");
277: else if (sw & 0x10)
278: printf("Underflow");
279: else if (sw & 0x20)
280: printf("Precision");
281: else
282: printf("???");
283: }
284: sendsig(SIGFPE, SELF);
285: }
286:
287: /*
288: * emtrap()
289: *
290: * Entered when NDP opcode is executed and EM bit of CR0 is 1.
291: * err is SIXNP (Device Not Available Fault)
292: */
293: void
294: emtrap(gs, fs, es, ds, edi, esi, ebp, esp, ebx, edx, ecx, eax, trapno, err,
295: eip, cs, efl, uesp, ss)
296: char *eip;
297: {
298: switch (ndpType) {
299: case NDP_TYPE_287:
300: case NDP_TYPE_387:
301: case NDP_TYPE_486:
302: ndpNewOwner();
303: break;
304: default:
305: if (ndpDump) {
306: RDUMP();
307: }
308: if (!rdEmTrapped()) {
309: wrEmTrapped(1);
310: emFinit(&u.u_ndpCon);
311: }
312: if (ndpEmFn) {
313: int looker = 1;
314:
315: /*
316: * No emulator lookahead if ptraced or
317: * single step process.
318: */
319: if ((SELF->p_flags & PFTRAC) || (u.u_regl[EFL] & MFTTB))
320: looker = 0;
321: (*ndpEmFn)(&gs, &u.u_ndpCon, looker);
322: } else
323: sendsig(ndpEmSig, SELF);
324: }
325: }
326:
327: /*
328: * IRQ 13 handler. Not used with 486.
329: */
330: void
331: ndpIrq()
332: {
333: struct _fpstate * fsp = &u.u_ndpCon;
334: unsigned short sw;
335:
336: outb(NDP_PORT, 0);
337: /*
338: * Send user a signal.
339: */
340: ndpSave(fsp);
341: /* Clear exception flag in NDP to prevent runaway trap. */
342: sw = fsp->status = fsp->sw;
343: fsp->sw &= 0x7f00;
344: wrNdpSaved(1);
345: if (ndpDump) {
346: printf("\nfcs=%x fip=%x fos=%x foo=%x\n",
347: fsp->cssel&0xffff, fsp->ipoff,
348: fsp->datasel&0xffff, fsp->dataoff);
349: printf("User 387 Trap: ");
350: if (sw & 1)
351: printf("Invalid Operation");
352: else if (sw & 2)
353: printf("Denormalized Operand");
354: else if (sw & 4)
355: printf("Divide by Zero");
356: else if (sw & 8)
357: printf("Overflow");
358: else if (sw & 0x10)
359: printf("Underflow");
360: else if (sw & 0x20)
361: printf("Precision");
362: else
363: printf("???");
364: }
365: sendsig(SIGFPE, SELF);
366: }
367:
368: /*
369: * ----------------------------------------------------------------------
370: * Routines concerned with whether current process has used the ndp.
371: */
372: int
373: rdNdpUser()
374: {
375: return (u.u_ndpFlags & NF_NDP_USER) ? 1 : 0;
376: }
377:
378: void
379: wrNdpUser(n)
380: int n;
381: {
382: if (n)
383: u.u_ndpFlags |= NF_NDP_USER;
384: else
385: u.u_ndpFlags &= ~NF_NDP_USER;
386: }
387:
388: /*
389: * Since saving NDP state is destructive, we need to keep track
390: * of where the current NDP state is - u area, or NDP?
391: */
392: int
393: rdNdpSaved()
394: {
395: return (u.u_ndpFlags & NF_NDP_SAVED) ? 1 : 0;
396: }
397:
398: int
399: rdNdpSavedU(up)
400: UPROC * up;
401: {
402: return (up->u_ndpFlags & NF_NDP_SAVED) ? 1 : 0;
403: }
404:
405: void
406: wrNdpSaved(n)
407: int n;
408: {
409: if (n)
410: u.u_ndpFlags |= NF_NDP_SAVED;
411: else
412: u.u_ndpFlags &= ~NF_NDP_SAVED;
413: }
414:
415: void
416: wrNdpSavedU(n, up)
417: int n;
418: UPROC * up;
419: {
420: if (n)
421: up->u_ndpFlags |= NF_NDP_SAVED;
422: else
423: up->u_ndpFlags &= ~NF_NDP_SAVED;
424: }
425:
426: /*
427: * Enable (1) or disable (0) emulator traps.
428: */
429: void
430: ndpEmTraps(n)
431: int n;
432: {
433: if (kerEm != n) {
434: kerEm = n;
435: setEm(n);
436: }
437: }
438:
439: /*
440: * Make ndp owned by no one.
441: */
442: void
443: ndpDetach()
444: {
445: ndpOwner = 0;
446: ndpUseg = 0;
447: }
448:
449: /*
450: * Make ndp owned by the current process.
451: */
452: void
453: ndpMine()
454: {
455: SR * srp = &(u.u_segl[SIUSERP]);
456: SEG * sp = srp->sr_segp;
457:
458: ndpOwner = SELF;
459: ndpUseg = MAPIO(sp->s_vmem, U_OFFSET);
460: }
461:
462: /*
463: * ----------------------------------------------------------------------
464: * Code concerned with identifying coprocessor type, and taking specialized
465: * action depending on the type.
466: */
467:
468: /*
469: * Using usual algorithms, determine existence and type of NDP.
470: * If interrupt vector needs to be set for FP exception, do it.
471: *
472: * If 2's bit of int11 is on, NDP is present.
473: */
474: void
475: senseNdp()
476: {
477: if (ndpType == NDP_TYPE_UNPATCHED) {
478: ndpEmTraps(0); /* Will need to do some FP code. */
479: ndpType = ndpSense(); /* Rely on assembler tricks now. */
480: ndpEmTraps(1);
481: }
482: if (ndpType == NDP_TYPE_387 || ndpType == NDP_TYPE_287) {
483: setivec(NDP_IRQ, ndpIrq);
484: }
485: }
486:
487: /*
488: * Called from main().
489: * Return name string for the type of coprocessor detected.
490: */
491: char *
492: ndpTypeName()
493: {
494: char * ret = "**ERROR: Bad ndp type**";
495:
496: switch(ndpType) {
497: case NDP_TYPE_NONE:
498: ret = "No NDP. ";
499: break;
500: case NDP_TYPE_287:
501: ret = "NDP=287. ";
502: break;
503: case NDP_TYPE_387:
504: ret = "NDP=387. ";
505: break;
506: case NDP_TYPE_486:
507: ret = "NDP=486. ";
508: break;
509: }
510: return ret;
511: }
512:
513: /*
514: * ----------------------------------------------------------------------
515: * Little routines for tracking emulator state.
516: */
517:
518: int
519: rdEmTrapped()
520: {
521: return (u.u_ndpFlags & NF_EM_TRAPPED) ? 1 : 0;
522: }
523:
524: void
525: wrEmTrapped(n)
526: int n;
527: {
528: if (n)
529: u.u_ndpFlags |= NF_EM_TRAPPED;
530: else
531: u.u_ndpFlags &= ~NF_EM_TRAPPED;
532: }
533:
534: /*
535: * Provide the emulator with a fresh context.
536: */
537: void
538: emFinit(fpsp)
539: struct _fpemstate * fpsp;
540: {
541: register int r;
542:
543: memset(fpsp, '\0', sizeof(struct _fpemstate)); /* mostly zeroes */
544: fpsp->cw = ndpCW;
545: for(r = 0; r < 8; r++)
546: fpsp->regs[r].tag = 7; /* Empty */
547: }
548:
549: /*
550: * ----------------------------------------------------------------------
551: * Functions to interface with the emulator.
552: */
553: get_fs_byte(cp)
554: char *cp;
555: {
556: char getubd();
557:
558: return getubd(cp);
559: }
560:
561: get_fs_word(sp)
562: short *sp;
563: {
564: short getusd();
565:
566: return getusd(sp);
567: }
568:
569: get_fs_long(lp)
570: long *lp;
571: {
572: long getuwd();
573:
574: return getuwd(lp);
575: }
576:
577: void
578: put_fs_byte(data, cp)
579: char *cp;
580: char data;
581: {
582: putubd(cp, data);
583: }
584:
585: void
586: put_fs_word(data, sp)
587: short *sp;
588: short data;
589: {
590: putusd(sp, data);
591: }
592:
593: void
594: put_fs_long(data, lp)
595: long *lp;
596: long data;
597: {
598: putuwd(lp, data);
599: }
600:
601: /*
602: * Return zero if out of bounds for write.
603: */
604: int
605: verify_area(cp, len)
606: int * cp;
607: int len;
608: {
609: int ret = useracc(cp, len, 1);
610:
611: if (!ret) {
612: #if 0
613: printf("Bad Em write, base=%x, len=%x, r.a.=%x",
614: cp, len, *(int *)((&cp) - 1));
615: #endif
616: sendsig(SIGSEGV, SELF);
617: }
618: return ret;
619: }
620:
621: /*
622: * print kernel message.
623: */
624: printk(s)
625: char *s;
626: {
627: puts(s);
628: }
629:
630: emSendsig()
631: {
632: sendsig(SIGFPE, SELF);
633: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.