|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * @OSF_COPYRIGHT@
24: */
25: /*
26: * Mach Operating System
27: * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University
28: * All Rights Reserved.
29: *
30: * Permission to use, copy, modify and distribute this software and its
31: * documentation is hereby granted, provided that both the copyright
32: * notice and this permission notice appear in all copies of the
33: * software, derivative works or modified versions, and any portions
34: * thereof, and that both notices appear in supporting documentation.
35: *
36: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
37: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
38: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
39: *
40: * Carnegie Mellon requests users of this software to return to
41: *
42: * Software Distribution Coordinator or [email protected]
43: * School of Computer Science
44: * Carnegie Mellon University
45: * Pittsburgh PA 15213-3890
46: *
47: * any improvements or extensions that they make and grant Carnegie Mellon
48: * the rights to redistribute these changes.
49: */
50: /*
51: */
52: /*
53: * Hardware trap/fault handler.
54: */
55:
56: #include <cpus.h>
57: #include <fast_idle.h>
58: #include <mach_kdb.h>
59: #include <mach_kgdb.h>
60: #include <mach_kdp.h>
61: #include <mach_ldebug.h>
62:
63: #include <types.h>
64: #include <i386/eflags.h>
65: #include <i386/trap.h>
66: #include <i386/pmap.h>
67: #include <i386/fpu.h>
68:
69: #include <mach/exception.h>
70: #include <mach/kern_return.h>
71: #include <mach/vm_param.h>
72: #include <mach/i386/thread_status.h>
73:
74: #include <vm/vm_kern.h>
75: #include <vm/vm_fault.h>
76:
77: #include <kern/etap_macros.h>
78: #include <kern/kern_types.h>
79: #include <kern/ast.h>
80: #include <kern/thread.h>
81: #include <kern/task.h>
82: #include <kern/sched.h>
83: #include <kern/sched_prim.h>
84: #include <kern/exception.h>
85: #include <kern/spl.h>
86: #include <kern/misc_protos.h>
87:
88: #if MACH_KGDB
89: #include <kgdb/kgdb_defs.h>
90: #endif /* MACH_KGDB */
91:
92: #include <i386/intel_read_fault.h>
93:
94: #if MACH_KGDB
95: #include <kgdb/kgdb_defs.h>
96: #endif /* MACH_KGDB */
97:
98: #if MACH_KDB
99: #include <ddb/db_watch.h>
100: #include <ddb/db_run.h>
101: #include <ddb/db_break.h>
102: #include <ddb/db_trap.h>
103: #endif /* MACH_KDB */
104:
105: #include <string.h>
106:
107: #include <i386/io_emulate.h>
108:
109: /*
110: * Forward declarations
111: */
112: extern void user_page_fault_continue(
113: kern_return_t kr);
114:
115: extern boolean_t v86_assist(
116: thread_t thread,
117: struct i386_saved_state *regs);
118:
119: extern boolean_t check_io_fault(
120: struct i386_saved_state *regs);
121:
122: extern int inst_fetch(
123: int eip,
124: int cs);
125:
126: #if MACH_KDB
127: boolean_t debug_all_traps_with_kdb = FALSE;
128: extern struct db_watchpoint *db_watchpoint_list;
129: extern boolean_t db_watchpoints_inserted;
130: extern boolean_t db_breakpoints_inserted;
131:
132: void
133: thread_kdb_return(void)
134: {
135: register thread_act_t thr_act = current_act();
136: register thread_t cur_thr = current_thread();
137: register struct i386_saved_state *regs = USER_REGS(thr_act);
138:
139: if (kdb_trap(regs->trapno, regs->err, regs)) {
140: #if MACH_LDEBUG
141: assert(cur_thr->mutex_count == 0);
142: #endif /* MACH_LDEBUG */
143: check_simple_locks();
144: thread_exception_return();
145: /*NOTREACHED*/
146: }
147: }
148: boolean_t let_ddb_vm_fault = FALSE;
149:
150: #if NCPUS > 1
151: extern int kdb_active[NCPUS];
152: #endif /* NCPUS > 1 */
153:
154: #endif /* MACH_KDB */
155:
156: void
157: user_page_fault_continue(
158: kern_return_t kr)
159: {
160: register thread_act_t thr_act = current_act();
161: register thread_t cur_thr = current_thread();
162: register struct i386_saved_state *regs = USER_REGS(thr_act);
163:
164: if (kr == KERN_SUCCESS) {
165: #if MACH_KDB
166: if (!db_breakpoints_inserted) {
167: db_set_breakpoints();
168: }
169: if (db_watchpoint_list &&
170: db_watchpoints_inserted &&
171: (regs->err & T_PF_WRITE) &&
172: db_find_watchpoint(thr_act->map,
173: (vm_offset_t)regs->cr2,
174: regs))
175: kdb_trap(T_WATCHPOINT, 0, regs);
176: #endif /* MACH_KDB */
177: thread_exception_return();
178: /*NOTREACHED*/
179: }
180:
181: #if MACH_KDB
182: if (debug_all_traps_with_kdb &&
183: kdb_trap(regs->trapno, regs->err, regs)) {
184: #if MACH_LDEBUG
185: assert(cur_thr->mutex_count == 0);
186: #endif /* MACH_LDEBUG */
187: check_simple_locks();
188: thread_exception_return();
189: /*NOTREACHED*/
190: }
191: #endif /* MACH_KDB */
192:
193: i386_exception(EXC_BAD_ACCESS, kr, regs->cr2);
194: /*NOTREACHED*/
195: }
196:
197: /*
198: * Fault recovery in copyin/copyout routines.
199: */
200: struct recovery {
201: int fault_addr;
202: int recover_addr;
203: };
204:
205: extern struct recovery recover_table[];
206: extern struct recovery recover_table_end[];
207:
208: /*
209: * Recovery from Successful fault in copyout does not
210: * return directly - it retries the pte check, since
211: * the 386 ignores write protection in kernel mode.
212: */
213: extern struct recovery retry_table[];
214: extern struct recovery retry_table_end[];
215:
216: char * trap_type[] = {TRAP_NAMES};
217: int TRAP_TYPES = sizeof(trap_type)/sizeof(trap_type[0]);
218:
219: /*
220: * Trap from kernel mode. Only page-fault errors are recoverable,
221: * and then only in special circumstances. All other errors are
222: * fatal. Return value indicates if trap was handled.
223: */
224: boolean_t
225: kernel_trap(
226: register struct i386_saved_state *regs)
227: {
228: int exc;
229: int code;
230: int subcode;
231: register int type;
232: vm_map_t map;
233: kern_return_t result;
234: register thread_t thread;
235: thread_act_t thr_act;
236: etap_data_t probe_data;
237: pt_entry_t *pte;
238: extern vm_offset_t vm_last_phys;
239:
240: type = regs->trapno;
241: code = regs->err;
242: thread = current_thread();
243: thr_act = current_act();
244:
245: ETAP_DATA_LOAD(probe_data[0], regs->trapno);
246: ETAP_DATA_LOAD(probe_data[1], MACH_PORT_NULL);
247: ETAP_DATA_LOAD(probe_data[2], MACH_PORT_NULL);
248: ETAP_PROBE_DATA(ETAP_P_EXCEPTION,
249: 0,
250: thread,
251: &probe_data,
252: ETAP_DATA_ENTRY*3);
253:
254: switch (type) {
255: case T_PREEMPT:
256: return (TRUE);
257:
258: case T_NO_FPU:
259: fpnoextflt();
260: return (TRUE);
261:
262: case T_FPU_FAULT:
263: fpextovrflt();
264: return (TRUE);
265:
266: case T_FLOATING_POINT_ERROR:
267: fpexterrflt();
268: return (TRUE);
269:
270: case T_PAGE_FAULT:
271: /*
272: * If the current map is a submap of the kernel map,
273: * and the address is within that map, fault on that
274: * map. If the same check is done in vm_fault
275: * (vm_map_lookup), we may deadlock on the kernel map
276: * lock.
277: */
278: #if MACH_KDB
279: mp_disable_preemption();
280: if (db_active
281: #if NCPUS > 1
282: && kdb_active[cpu_number()]
283: #endif /* NCPUS > 1 */
284: && !let_ddb_vm_fault) {
285: /*
286: * Force kdb to handle this one.
287: */
288: mp_enable_preemption();
289: return (FALSE);
290: }
291: mp_enable_preemption();
292: #endif /* MACH_KDB */
293: subcode = regs->cr2; /* get faulting address */
294:
295: if (subcode > LINEAR_KERNEL_ADDRESS) {
296: map = kernel_map;
297: subcode -= LINEAR_KERNEL_ADDRESS;
298: } else if (thr_act == THR_ACT_NULL || thread == THREAD_NULL)
299: map = kernel_map;
300: else {
301: map = thr_act->map;
302: }
303:
304: #if MACH_KDB
305: /*
306: * Check for watchpoint on kernel static data.
307: * vm_fault would fail in this case
308: */
309: if (map == kernel_map &&
310: db_watchpoint_list &&
311: db_watchpoints_inserted &&
312: (code & T_PF_WRITE) &&
313: (vm_offset_t)subcode < vm_last_phys &&
314: ((*(pte = pmap_pte(kernel_pmap, (vm_offset_t)subcode))) &
315: INTEL_PTE_WRITE) == 0) {
316: *pte = INTEL_PTE_VALID | INTEL_PTE_WRITE |
317: pa_to_pte(trunc_page((vm_offset_t)subcode) -
318: VM_MIN_KERNEL_ADDRESS);
319: result = KERN_SUCCESS;
320: } else
321: #endif /* MACH_KDB */
322: {
323: /*
324: * Since the 386 ignores write protection in
325: * kernel mode, always try for write permission
326: * first. If that fails and the fault was a
327: * read fault, retry with read permission.
328: */
329: result = vm_fault(map,
330: trunc_page((vm_offset_t)subcode),
331: VM_PROT_READ|VM_PROT_WRITE,
332: FALSE);
333: }
334: #if MACH_KDB
335: if (result == KERN_SUCCESS) {
336: /* Look for watchpoints */
337: if (db_watchpoint_list &&
338: db_watchpoints_inserted &&
339: (code & T_PF_WRITE) &&
340: db_find_watchpoint(map,
341: (vm_offset_t)subcode, regs))
342: kdb_trap(T_WATCHPOINT, 0, regs);
343: }
344: else
345: #endif /* MACH_KDB */
346: if ((code & T_PF_WRITE) == 0 &&
347: result == KERN_PROTECTION_FAILURE)
348: {
349: /*
350: * Must expand vm_fault by hand,
351: * so that we can ask for read-only access
352: * but enter a (kernel)writable mapping.
353: */
354: result = intel_read_fault(map,
355: trunc_page((vm_offset_t)subcode));
356: }
357:
358: if (result == KERN_SUCCESS) {
359: /*
360: * Certain faults require that we back up
361: * the EIP.
362: */
363: register struct recovery *rp;
364:
365: for (rp = retry_table; rp < retry_table_end; rp++) {
366: if (regs->eip == rp->fault_addr) {
367: regs->eip = rp->recover_addr;
368: break;
369: }
370: }
371: return (TRUE);
372: }
373:
374: /* fall through */
375:
376: case T_GENERAL_PROTECTION:
377:
378: /*
379: * If there is a failure recovery address
380: * for this fault, go there.
381: */
382: {
383: register struct recovery *rp;
384:
385: for (rp = recover_table;
386: rp < recover_table_end;
387: rp++) {
388: if (regs->eip == rp->fault_addr) {
389: regs->eip = rp->recover_addr;
390: return (TRUE);
391: }
392: }
393: }
394:
395: /*
396: * Check thread recovery address also -
397: * v86 assist uses it.
398: */
399: if (thread->recover) {
400: regs->eip = thread->recover;
401: thread->recover = 0;
402: return (TRUE);
403: }
404:
405: /*
406: * Unanticipated page-fault errors in kernel
407: * should not happen.
408: */
409: /* fall through... */
410:
411: default:
412: /*
413: * ...and return failure, so that locore can call into
414: * debugger.
415: */
416: #if MACH_KDP
417: kdp_i386_trap(type, regs, result, regs->cr2);
418: #endif
419: return (FALSE);
420: }
421: return (TRUE);
422: }
423:
424: /*
425: * Called if both kernel_trap() and kdb_trap() fail.
426: */
427: void
428: panic_trap(
429: register struct i386_saved_state *regs)
430: {
431: int code;
432: register int type;
433:
434: type = regs->trapno;
435: code = regs->err;
436:
437: printf("trap type %d, code = %x, pc = %x\n",
438: type, code, regs->eip);
439: panic("trap");
440: }
441:
442:
443: /*
444: * Trap from user mode.
445: */
446: void
447: user_trap(
448: register struct i386_saved_state *regs)
449: {
450: int exc;
451: int code;
452: int subcode;
453: register int type;
454: vm_map_t map;
455: vm_prot_t prot;
456: kern_return_t result;
457: register thread_act_t thr_act = current_act();
458: thread_t thread = (thr_act ? thr_act->thread : THREAD_NULL);
459: boolean_t kernel_act = thr_act->kernel_loaded;
460: etap_data_t probe_data;
461:
462: if (regs->efl & EFL_VM) {
463: /*
464: * If hardware assist can handle exception,
465: * continue execution.
466: */
467: if (v86_assist(thread, regs))
468: return;
469: }
470:
471: type = regs->trapno;
472: code = 0;
473: subcode = 0;
474:
475: switch (type) {
476:
477: case T_DIVIDE_ERROR:
478: exc = EXC_ARITHMETIC;
479: code = EXC_I386_DIV;
480: break;
481:
482: case T_DEBUG:
483: #if MACH_KDP
484: /* Trap to KDP */
485: kdp_raise_exception(EXC_BREAKPOINT, EXC_I386_BPTFLT, 0, regs);
486: #endif
487: #if MACH_KGDB
488: if (kgdb_user_trap(regs)) {
489: return;
490: }
491: #endif
492: #if MACH_KDB
493: if (db_in_single_step()) {
494: if (kdb_trap(type, regs->err, regs))
495: return;
496: }
497: #endif
498: exc = EXC_BREAKPOINT;
499: code = EXC_I386_SGL;
500: break;
501:
502: case T_INT3:
503:
504: #if MACH_KDP
505: kdp_raise_exception(EXC_BREAKPOINT, EXC_I386_BPTFLT, 0, regs);
506: #endif
507: #if MACH_KGDB
508: if (kgdb_user_trap(regs)) {
509: return;
510: }
511: #endif
512: #if MACH_KDB
513: {
514: thread_act_t curact = current_act();
515:
516: if (db_find_breakpoint_here(
517: (curact && !curact->kernel_loaded)?
518: curact->task: TASK_NULL,
519: regs->eip - 1)) {
520: if (kdb_trap(type, regs->err, regs))
521: return;
522: }
523: }
524: #endif
525: exc = EXC_BREAKPOINT;
526: code = EXC_I386_BPT;
527: break;
528:
529: case T_OVERFLOW:
530: exc = EXC_ARITHMETIC;
531: code = EXC_I386_INTO;
532: break;
533:
534: case T_OUT_OF_BOUNDS:
535: exc = EXC_SOFTWARE;
536: code = EXC_I386_BOUND;
537: break;
538:
539: case T_INVALID_OPCODE:
540: exc = EXC_BAD_INSTRUCTION;
541: code = EXC_I386_INVOP;
542: break;
543:
544: case T_NO_FPU:
545: case 32: /* XXX */
546: fpnoextflt();
547: return;
548:
549: case T_FPU_FAULT:
550: fpextovrflt();
551: return;
552:
553: case 10: /* invalid TSS == iret with NT flag set */
554: exc = EXC_BAD_INSTRUCTION;
555: code = EXC_I386_INVTSSFLT;
556: subcode = regs->err & 0xffff;
557: break;
558:
559: case T_SEGMENT_NOT_PRESENT:
560: exc = EXC_BAD_INSTRUCTION;
561: code = EXC_I386_SEGNPFLT;
562: subcode = regs->err & 0xffff;
563: break;
564:
565: case T_STACK_FAULT:
566: exc = EXC_BAD_INSTRUCTION;
567: code = EXC_I386_STKFLT;
568: subcode = regs->err & 0xffff;
569: break;
570:
571: case T_GENERAL_PROTECTION:
572: if (!(regs->efl & EFL_VM)) {
573: if (check_io_fault(regs))
574: return;
575: }
576: exc = EXC_BAD_INSTRUCTION;
577: code = EXC_I386_GPFLT;
578: subcode = regs->err & 0xffff;
579: break;
580:
581: case T_PAGE_FAULT:
582: subcode = regs->cr2;
583: prot = VM_PROT_READ|VM_PROT_WRITE;
584: if (kernel_act == FALSE) {
585: if (!(regs->err & T_PF_WRITE))
586: prot = VM_PROT_READ;
587: (void) user_page_fault_continue(vm_fault(thr_act->map,
588: trunc_page((vm_offset_t)subcode),
589: prot,
590: FALSE));
591: /* NOTREACHED */
592: }
593: else {
594: if (subcode > LINEAR_KERNEL_ADDRESS) {
595: map = kernel_map;
596: subcode -= LINEAR_KERNEL_ADDRESS;
597: }
598: result = vm_fault(thr_act->map,
599: trunc_page((vm_offset_t)subcode),
600: prot,
601: FALSE);
602: if (result != KERN_SUCCESS) {
603: /*
604: * Must expand vm_fault by hand,
605: * so that we can ask for read-only access
606: * but enter a (kernel) writable mapping.
607: */
608: result = intel_read_fault(thr_act->map,
609: trunc_page((vm_offset_t)subcode));
610: }
611: user_page_fault_continue(result);
612: /*NOTREACHED*/
613: }
614: break;
615:
616: case T_FLOATING_POINT_ERROR:
617: fpexterrflt();
618: return;
619:
620: default:
621: #if MACH_KGDB
622: Debugger("Unanticipated user trap");
623: return;
624: #endif /* MACH_KGDB */
625: #if MACH_KDB
626: if (kdb_trap(type, regs->err, regs))
627: return;
628: #endif /* MACH_KDB */
629: printf("user trap type %d, code = %x, pc = %x\n",
630: type, regs->err, regs->eip);
631: panic("user trap");
632: return;
633: }
634:
635: #if MACH_KDB
636: if (debug_all_traps_with_kdb &&
637: kdb_trap(type, regs->err, regs))
638: return;
639: #endif /* MACH_KDB */
640:
641: #if ETAP_EVENT_MONITOR
642: if (thread != THREAD_NULL) {
643: ETAP_DATA_LOAD(probe_data[0], regs->trapno);
644: ETAP_DATA_LOAD(probe_data[1],
645: thr_act->exc_actions[exc].port);
646: ETAP_DATA_LOAD(probe_data[2],
647: thr_act->task->exc_actions[exc].port);
648: ETAP_PROBE_DATA(ETAP_P_EXCEPTION,
649: 0,
650: thread,
651: &probe_data,
652: ETAP_DATA_ENTRY*3);
653: }
654: #endif /* ETAP_EVENT_MONITOR */
655:
656: i386_exception(exc, code, subcode);
657: /*NOTREACHED*/
658: }
659:
660: /*
661: * V86 mode assist for interrupt handling.
662: */
663: boolean_t v86_assist_on = TRUE;
664: boolean_t v86_unsafe_ok = FALSE;
665: boolean_t v86_do_sti_cli = TRUE;
666: boolean_t v86_do_sti_immediate = FALSE;
667:
668: #define V86_IRET_PENDING 0x4000
669:
670: int cli_count = 0;
671: int sti_count = 0;
672:
673: boolean_t
674: v86_assist(
675: thread_t thread,
676: register struct i386_saved_state *regs)
677: {
678: register struct v86_assist_state *v86 = &thread->top_act->mact.pcb->ims.v86s;
679:
680: /*
681: * Build an 8086 address. Use only when off is known to be 16 bits.
682: */
683: #define Addr8086(seg,off) ((((seg) & 0xffff) << 4) + (off))
684:
685: #define EFL_V86_SAFE ( EFL_OF | EFL_DF | EFL_TF \
686: | EFL_SF | EFL_ZF | EFL_AF \
687: | EFL_PF | EFL_CF )
688: struct iret_32 {
689: int eip;
690: int cs;
691: int eflags;
692: };
693: struct iret_16 {
694: unsigned short ip;
695: unsigned short cs;
696: unsigned short flags;
697: };
698: union iret_struct {
699: struct iret_32 iret_32;
700: struct iret_16 iret_16;
701: };
702:
703: struct int_vec {
704: unsigned short ip;
705: unsigned short cs;
706: };
707:
708: if (!v86_assist_on)
709: return FALSE;
710:
711: /*
712: * If delayed STI pending, enable interrupts.
713: * Turn off tracing if on only to delay STI.
714: */
715: if (v86->flags & V86_IF_PENDING) {
716: v86->flags &= ~V86_IF_PENDING;
717: v86->flags |= EFL_IF;
718: if ((v86->flags & EFL_TF) == 0)
719: regs->efl &= ~EFL_TF;
720: }
721:
722: if (regs->trapno == T_DEBUG) {
723:
724: if (v86->flags & EFL_TF) {
725: /*
726: * Trace flag was also set - it has priority
727: */
728: return FALSE; /* handle as single-step */
729: }
730: /*
731: * Fall through to check for interrupts.
732: */
733: }
734: else if (regs->trapno == T_GENERAL_PROTECTION) {
735: /*
736: * General protection error - must be an 8086 instruction
737: * to emulate.
738: */
739: register int eip;
740: boolean_t addr_32 = FALSE;
741: boolean_t data_32 = FALSE;
742: int io_port;
743:
744: /*
745: * Set up error handler for bad instruction/data
746: * fetches.
747: */
748: __asm__("movl $(addr_error), %0" : : "m" (thread->recover));
749:
750: eip = regs->eip;
751: while (TRUE) {
752: unsigned char opcode;
753:
754: if (eip > 0xFFFF) {
755: thread->recover = 0;
756: return FALSE; /* GP fault: IP out of range */
757: }
758:
759: opcode = *(unsigned char *)Addr8086(regs->cs,eip);
760: eip++;
761: switch (opcode) {
762: case 0xf0: /* lock */
763: case 0xf2: /* repne */
764: case 0xf3: /* repe */
765: case 0x2e: /* cs */
766: case 0x36: /* ss */
767: case 0x3e: /* ds */
768: case 0x26: /* es */
769: case 0x64: /* fs */
770: case 0x65: /* gs */
771: /* ignore prefix */
772: continue;
773:
774: case 0x66: /* data size */
775: data_32 = TRUE;
776: continue;
777:
778: case 0x67: /* address size */
779: addr_32 = TRUE;
780: continue;
781:
782: case 0xe4: /* inb imm */
783: case 0xe5: /* inw imm */
784: case 0xe6: /* outb imm */
785: case 0xe7: /* outw imm */
786: io_port = *(unsigned char *)Addr8086(regs->cs, eip);
787: eip++;
788: goto do_in_out;
789:
790: case 0xec: /* inb dx */
791: case 0xed: /* inw dx */
792: case 0xee: /* outb dx */
793: case 0xef: /* outw dx */
794: case 0x6c: /* insb */
795: case 0x6d: /* insw */
796: case 0x6e: /* outsb */
797: case 0x6f: /* outsw */
798: io_port = regs->edx & 0xffff;
799:
800: do_in_out:
801: if (!data_32)
802: opcode |= 0x6600; /* word IO */
803:
804: switch (emulate_io(regs, opcode, io_port)) {
805: case EM_IO_DONE:
806: /* instruction executed */
807: break;
808: case EM_IO_RETRY:
809: /* port mapped, retry instruction */
810: thread->recover = 0;
811: return TRUE;
812: case EM_IO_ERROR:
813: /* port not mapped */
814: thread->recover = 0;
815: return FALSE;
816: }
817: break;
818:
819: case 0xfa: /* cli */
820: if (!v86_do_sti_cli) {
821: thread->recover = 0;
822: return (FALSE);
823: }
824:
825: v86->flags &= ~EFL_IF;
826: /* disable simulated interrupts */
827: cli_count++;
828: break;
829:
830: case 0xfb: /* sti */
831: if (!v86_do_sti_cli) {
832: thread->recover = 0;
833: return (FALSE);
834: }
835:
836: if ((v86->flags & EFL_IF) == 0) {
837: if (v86_do_sti_immediate) {
838: v86->flags |= EFL_IF;
839: } else {
840: v86->flags |= V86_IF_PENDING;
841: regs->efl |= EFL_TF;
842: }
843: /* single step to set IF next inst. */
844: }
845: sti_count++;
846: break;
847:
848: case 0x9c: /* pushf */
849: {
850: int flags;
851: vm_offset_t sp;
852: int size;
853:
854: flags = regs->efl;
855: if ((v86->flags & EFL_IF) == 0)
856: flags &= ~EFL_IF;
857:
858: if ((v86->flags & EFL_TF) == 0)
859: flags &= ~EFL_TF;
860: else flags |= EFL_TF;
861:
862: sp = regs->uesp;
863: if (!addr_32)
864: sp &= 0xffff;
865: else if (sp > 0xffff)
866: goto stack_error;
867: size = (data_32) ? 4 : 2;
868: if (sp < size)
869: goto stack_error;
870: sp -= size;
871: if (copyout((char *)&flags,
872: (char *)Addr8086(regs->ss,sp),
873: size))
874: goto addr_error;
875: if (addr_32)
876: regs->uesp = sp;
877: else
878: regs->uesp = (regs->uesp & 0xffff0000) | sp;
879: break;
880: }
881:
882: case 0x9d: /* popf */
883: {
884: vm_offset_t sp;
885: int nflags;
886:
887: sp = regs->uesp;
888: if (!addr_32)
889: sp &= 0xffff;
890: else if (sp > 0xffff)
891: goto stack_error;
892:
893: if (data_32) {
894: if (sp > 0xffff - sizeof(int))
895: goto stack_error;
896: nflags = *(int *)Addr8086(regs->ss,sp);
897: sp += sizeof(int);
898: }
899: else {
900: if (sp > 0xffff - sizeof(short))
901: goto stack_error;
902: nflags = *(unsigned short *)
903: Addr8086(regs->ss,sp);
904: sp += sizeof(short);
905: }
906: if (addr_32)
907: regs->uesp = sp;
908: else
909: regs->uesp = (regs->uesp & 0xffff0000) | sp;
910:
911: if (v86->flags & V86_IRET_PENDING) {
912: v86->flags = nflags & (EFL_TF | EFL_IF);
913: v86->flags |= V86_IRET_PENDING;
914: } else {
915: v86->flags = nflags & (EFL_TF | EFL_IF);
916: }
917: regs->efl = (regs->efl & ~EFL_V86_SAFE)
918: | (nflags & EFL_V86_SAFE);
919: break;
920: }
921: case 0xcf: /* iret */
922: {
923: vm_offset_t sp;
924: int nflags;
925: int size;
926: union iret_struct iret_struct;
927:
928: v86->flags &= ~V86_IRET_PENDING;
929: sp = regs->uesp;
930: if (!addr_32)
931: sp &= 0xffff;
932: else if (sp > 0xffff)
933: goto stack_error;
934:
935: if (data_32) {
936: if (sp > 0xffff - sizeof(struct iret_32))
937: goto stack_error;
938: iret_struct.iret_32 =
939: *(struct iret_32 *) Addr8086(regs->ss,sp);
940: sp += sizeof(struct iret_32);
941: }
942: else {
943: if (sp > 0xffff - sizeof(struct iret_16))
944: goto stack_error;
945: iret_struct.iret_16 =
946: *(struct iret_16 *) Addr8086(regs->ss,sp);
947: sp += sizeof(struct iret_16);
948: }
949: if (addr_32)
950: regs->uesp = sp;
951: else
952: regs->uesp = (regs->uesp & 0xffff0000) | sp;
953:
954: if (data_32) {
955: eip = iret_struct.iret_32.eip;
956: regs->cs = iret_struct.iret_32.cs & 0xffff;
957: nflags = iret_struct.iret_32.eflags;
958: }
959: else {
960: eip = iret_struct.iret_16.ip;
961: regs->cs = iret_struct.iret_16.cs;
962: nflags = iret_struct.iret_16.flags;
963: }
964:
965: v86->flags = nflags & (EFL_TF | EFL_IF);
966: regs->efl = (regs->efl & ~EFL_V86_SAFE)
967: | (nflags & EFL_V86_SAFE);
968: break;
969: }
970: default:
971: /*
972: * Instruction not emulated here.
973: */
974: thread->recover = 0;
975: return FALSE;
976: }
977: break; /* exit from 'while TRUE' */
978: }
979: regs->eip = (regs->eip & 0xffff0000 | eip);
980: }
981: else {
982: /*
983: * Not a trap we handle.
984: */
985: thread->recover = 0;
986: return FALSE;
987: }
988:
989: if ((v86->flags & EFL_IF) && ((v86->flags & V86_IRET_PENDING)==0)) {
990:
991: struct v86_interrupt_table *int_table;
992: int int_count;
993: int vec;
994: int i;
995:
996: int_table = (struct v86_interrupt_table *) v86->int_table;
997: int_count = v86->int_count;
998:
999: vec = 0;
1000: for (i = 0; i < int_count; int_table++, i++) {
1001: if (!int_table->mask && int_table->count > 0) {
1002: int_table->count--;
1003: vec = int_table->vec;
1004: break;
1005: }
1006: }
1007: if (vec != 0) {
1008: /*
1009: * Take this interrupt
1010: */
1011: vm_offset_t sp;
1012: struct iret_16 iret_16;
1013: struct int_vec int_vec;
1014:
1015: sp = regs->uesp & 0xffff;
1016: if (sp < sizeof(struct iret_16))
1017: goto stack_error;
1018: sp -= sizeof(struct iret_16);
1019: iret_16.ip = regs->eip;
1020: iret_16.cs = regs->cs;
1021: iret_16.flags = regs->efl & 0xFFFF;
1022: if ((v86->flags & EFL_TF) == 0)
1023: iret_16.flags &= ~EFL_TF;
1024: else iret_16.flags |= EFL_TF;
1025:
1026: (void) memcpy((char *) &int_vec,
1027: (char *) (sizeof(struct int_vec) * vec),
1028: sizeof (struct int_vec));
1029: if (copyout((char *)&iret_16,
1030: (char *)Addr8086(regs->ss,sp),
1031: sizeof(struct iret_16)))
1032: goto addr_error;
1033: regs->uesp = (regs->uesp & 0xFFFF0000) | (sp & 0xffff);
1034: regs->eip = int_vec.ip;
1035: regs->cs = int_vec.cs;
1036: regs->efl &= ~EFL_TF;
1037: v86->flags &= ~(EFL_IF | EFL_TF);
1038: v86->flags |= V86_IRET_PENDING;
1039: }
1040: }
1041:
1042: thread->recover = 0;
1043: return TRUE;
1044:
1045: /*
1046: * On address error, report a page fault.
1047: * XXX report GP fault - we don`t save
1048: * the faulting address.
1049: */
1050: addr_error:
1051: __asm__("addr_error:;");
1052: thread->recover = 0;
1053: return FALSE;
1054:
1055: /*
1056: * On stack address error, return stack fault (12).
1057: */
1058: stack_error:
1059: thread->recover = 0;
1060: regs->trapno = T_STACK_FAULT;
1061: return FALSE;
1062: }
1063:
1064: /*
1065: * Handle AST traps for i386.
1066: * Check for delayed floating-point exception from
1067: * AT-bus machines.
1068: */
1069:
1070: extern void log_thread_action (thread_t, char *);
1071:
1072: void
1073: i386_astintr(int preemption)
1074: {
1075: int mycpu;
1076: ast_t mask = AST_ALL;
1077: spl_t s;
1078: thread_t self = current_thread();
1079:
1080: s = splsched(); /* block interrupts to check reasons */
1081: mp_disable_preemption();
1082: mycpu = cpu_number();
1083: if (need_ast[mycpu] & AST_I386_FP) {
1084: /*
1085: * AST was for delayed floating-point exception -
1086: * FP interrupt occured while in kernel.
1087: * Turn off this AST reason and handle the FPU error.
1088: */
1089:
1090: ast_off(AST_I386_FP);
1091: mp_enable_preemption();
1092: splx(s);
1093:
1094: fpexterrflt();
1095: }
1096: else {
1097: /*
1098: * Not an FPU trap. Handle the AST.
1099: * Interrupts are still blocked.
1100: */
1101:
1102: if (preemption) {
1103:
1104: /*
1105: * We don't want to process any AST if we were in
1106: * kernel-mode and the current thread is in any
1107: * funny state (waiting and/or suspended).
1108: */
1109:
1110: thread_lock (self);
1111:
1112: if (thread_not_preemptable(self) || self->preempt) {
1113: ast_off(AST_URGENT);
1114: thread_unlock (self);
1115: mp_enable_preemption();
1116: splx(s);
1117: return;
1118: }
1119: else mask = AST_PREEMPT;
1120: mp_enable_preemption();
1121:
1122: /*
1123: self->preempt = TH_NOT_PREEMPTABLE;
1124: */
1125:
1126: thread_unlock (self);
1127: } else {
1128: mp_enable_preemption();
1129: }
1130:
1131: ast_taken(preemption, mask, s
1132: #if FAST_IDLE
1133: ,NO_IDLE_THREAD
1134: #endif /* FAST_IDLE */
1135: );
1136: /*
1137: self->preempt = TH_PREEMPTABLE;
1138: */
1139: }
1140: }
1141:
1142: /*
1143: * Handle exceptions for i386.
1144: *
1145: * If we are an AT bus machine, we must turn off the AST for a
1146: * delayed floating-point exception.
1147: *
1148: * If we are providing floating-point emulation, we may have
1149: * to retrieve the real register values from the floating point
1150: * emulator.
1151: */
1152: void
1153: i386_exception(
1154: int exc,
1155: int code,
1156: int subcode)
1157: {
1158: spl_t s;
1159: exception_data_type_t codes[EXCEPTION_CODE_MAX];
1160:
1161: /*
1162: * Turn off delayed FPU error handling.
1163: */
1164: s = splsched();
1165: mp_disable_preemption();
1166: ast_off(AST_I386_FP);
1167: mp_enable_preemption();
1168: splx(s);
1169:
1170: codes[0] = code; /* new exception interface */
1171: codes[1] = subcode;
1172: exception(exc, codes, 2);
1173: /*NOTREACHED*/
1174: }
1175:
1176: boolean_t
1177: check_io_fault(
1178: struct i386_saved_state *regs)
1179: {
1180: int eip, opcode, io_port;
1181: boolean_t data_16 = FALSE;
1182:
1183: /*
1184: * Get the instruction.
1185: */
1186: eip = regs->eip;
1187:
1188: for (;;) {
1189: opcode = inst_fetch(eip, regs->cs);
1190: eip++;
1191: switch (opcode) {
1192: case 0x66: /* data-size prefix */
1193: data_16 = TRUE;
1194: continue;
1195:
1196: case 0xf3: /* rep prefix */
1197: case 0x26: /* es */
1198: case 0x2e: /* cs */
1199: case 0x36: /* ss */
1200: case 0x3e: /* ds */
1201: case 0x64: /* fs */
1202: case 0x65: /* gs */
1203: continue;
1204:
1205: case 0xE4: /* inb imm */
1206: case 0xE5: /* inl imm */
1207: case 0xE6: /* outb imm */
1208: case 0xE7: /* outl imm */
1209: /* port is immediate byte */
1210: io_port = inst_fetch(eip, regs->cs);
1211: eip++;
1212: break;
1213:
1214: case 0xEC: /* inb dx */
1215: case 0xED: /* inl dx */
1216: case 0xEE: /* outb dx */
1217: case 0xEF: /* outl dx */
1218: case 0x6C: /* insb */
1219: case 0x6D: /* insl */
1220: case 0x6E: /* outsb */
1221: case 0x6F: /* outsl */
1222: /* port is in DX register */
1223: io_port = regs->edx & 0xFFFF;
1224: break;
1225:
1226: default:
1227: return FALSE;
1228: }
1229: break;
1230: }
1231:
1232: if (data_16)
1233: opcode |= 0x6600; /* word IO */
1234:
1235: switch (emulate_io(regs, opcode, io_port)) {
1236: case EM_IO_DONE:
1237: /* instruction executed */
1238: regs->eip = eip;
1239: return TRUE;
1240:
1241: case EM_IO_RETRY:
1242: /* port mapped, retry instruction */
1243: return TRUE;
1244:
1245: case EM_IO_ERROR:
1246: /* port not mapped */
1247: return FALSE;
1248: }
1249: return FALSE;
1250: }
1251:
1252: void
1253: kernel_preempt_check (void)
1254: {
1255: mp_disable_preemption();
1256: if ((need_ast[cpu_number()] & AST_URGENT) &&
1257: #if NCPUS > 1
1258: get_interrupt_level() == 1
1259: #else /* NCPUS > 1 */
1260: get_interrupt_level() == 0
1261: #endif /* NCPUS > 1 */
1262: ) {
1263: mp_enable_preemption_no_check();
1264: __asm__ volatile (" int $0xff");
1265: } else {
1266: mp_enable_preemption_no_check();
1267: }
1268: }
1269:
1270: #if MACH_KDB
1271:
1272: extern void db_i386_state(struct i386_saved_state *regs);
1273:
1274: #include <ddb/db_output.h>
1275:
1276: void
1277: db_i386_state(
1278: struct i386_saved_state *regs)
1279: {
1280: db_printf("eip %8x\n", regs->eip);
1281: db_printf("trap %8x\n", regs->trapno);
1282: db_printf("err %8x\n", regs->err);
1283: db_printf("efl %8x\n", regs->efl);
1284: db_printf("ebp %8x\n", regs->ebp);
1285: db_printf("esp %8x\n", regs->esp);
1286: db_printf("uesp %8x\n", regs->uesp);
1287: db_printf("cs %8x\n", regs->cs & 0xff);
1288: db_printf("ds %8x\n", regs->ds & 0xff);
1289: db_printf("es %8x\n", regs->es & 0xff);
1290: db_printf("fs %8x\n", regs->fs & 0xff);
1291: db_printf("gs %8x\n", regs->gs & 0xff);
1292: db_printf("ss %8x\n", regs->ss & 0xff);
1293: db_printf("eax %8x\n", regs->eax);
1294: db_printf("ebx %8x\n", regs->ebx);
1295: db_printf("ecx %8x\n", regs->ecx);
1296: db_printf("edx %8x\n", regs->edx);
1297: db_printf("esi %8x\n", regs->esi);
1298: db_printf("edi %8x\n", regs->edi);
1299: }
1300:
1301: #endif /* MACH_KDB */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.