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