|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /*
26: * Copyright (c) 1993 NeXT Computer, Inc.
27: *
28: * Protected mode emulation.
29: *
30: * HISTORY
31: *
32: * 8 Apr 1993 ? at NeXT
33: * Created.
34: */
35:
36: #import <mach/mach_types.h>
37:
38: #import <architecture/i386/sel.h>
39: #import <architecture/i386/table.h>
40:
41: #import <machdep/i386/trap.h>
42: #import <machdep/i386/desc_inline.h>
43: #import <machdep/i386/err_inline.h>
44:
45: #import "PCprivate.h"
46: #import "PCmiscInline.h"
47: #import "PCtaskInline.h"
48:
49: static __inline__
50: boolean_t
51: fetch_LDT_entry(
52: thread_t thread,
53: unsigned int index,
54: ldt_entry_t *desc
55: )
56: {
57: PCshared_t shared = threadPCShared(thread);
58: unsigned int byte_index = index * sizeof (ldt_entry_t);
59:
60: if (shared->LDT.length <= byte_index)
61: return (FALSE);
62:
63: return (fetch8Byte(thread, shared->LDT.address + byte_index, desc));
64: }
65:
66: static __inline__
67: boolean_t
68: fetch_IDT_entry(
69: thread_t thread,
70: unsigned int index,
71: idt_entry_t *desc
72: )
73: {
74: PCshared_t shared = threadPCShared(thread);
75: unsigned int byte_index = index * sizeof (ldt_entry_t);
76:
77: if (shared->IDT.length <= byte_index)
78: return (FALSE);
79:
80: return (fetch8Byte(thread, shared->IDT.address + byte_index, desc));
81: }
82:
83: static
84: boolean_t
85: fetch_desc(
86: thread_t thread,
87: sel_t sel,
88: dt_entry_t *desc
89: )
90: {
91: if (sel.ti != SEL_LDT)
92: return (FALSE);
93:
94: return (fetch_LDT_entry(thread, sel.index, (ldt_entry_t *)desc));
95: }
96:
97: static __inline__
98: vm_offset_t
99: segment_base(
100: data_desc_t *desc
101: )
102: {
103: conv_base_t _base = { 0 };
104:
105: _base.fields.base00 = desc->base00;
106: _base.fields.base16 = desc->base16;
107: _base.fields.base24 = desc->base24;
108:
109: return (_base.word);
110: }
111:
112: static __inline__
113: boolean_t
114: fetch_segment_4byte(
115: thread_t thread,
116: data_desc_t *desc,
117: vm_offset_t offset,
118: boolean_t offsz,
119: unsigned int *data
120: )
121: {
122: vm_offset_t base = segment_base(desc);
123:
124: if (!offsz)
125: offset &= 0xffff;
126:
127: return (fetch4Byte(thread, base + offset, data));
128: }
129:
130: static
131: boolean_t __inline__
132: fetch_segment(
133: thread_t thread,
134: data_desc_t *desc,
135: vm_offset_t offset,
136: boolean_t offsz,
137: void *data,
138: unsigned int length
139: )
140: {
141: #define sdata ((unsigned short *)data)
142: vm_offset_t base = segment_base(desc);
143: unsigned int offmsk;
144:
145: if (offsz)
146: offmsk = 0xffffffff;
147: else
148: offmsk = 0xffff;
149:
150: thread->recover = (vm_offset_t)&&fault;
151:
152: while (length > 0) {
153: offset &= offmsk;
154:
155: asm volatile(
156: "movw %%fs:%1,%0"
157: : "=q" (*sdata)
158: : "m" (*(unsigned short *)(base + offset)));
159:
160: sdata++; offset += sizeof (*sdata); length -= sizeof (*sdata);
161: }
162:
163: thread->recover = 0;
164: return (TRUE);
165:
166: fault:
167: thread->recover = 0;
168: return (FALSE);
169:
170: #undef sdata
171: }
172:
173: static __inline__
174: boolean_t
175: store_segment(
176: thread_t thread,
177: data_desc_t *desc,
178: vm_offset_t offset,
179: boolean_t offsz,
180: void *data,
181: unsigned int length
182: )
183: {
184: #define sdata ((unsigned short *)data)
185: vm_offset_t base = segment_base(desc);
186: unsigned int offmsk;
187:
188: if (offsz)
189: offmsk = 0xffffffff;
190: else
191: offmsk = 0xffff;
192:
193: thread->recover = (vm_offset_t)&&fault;
194:
195: while (length > 0) {
196: offset &= offmsk;
197:
198: asm volatile(
199: "movw %0,%%fs:%1"
200: :
201: : "r" (*sdata), "m" (*(unsigned short *)(base + offset)));
202:
203: sdata++; offset += sizeof (*sdata); length -= sizeof (*sdata);
204: }
205:
206: thread->recover = 0;
207: return (TRUE);
208:
209: fault:
210: thread->recover = 0;
211: return (FALSE);
212:
213: #undef sdata
214: }
215:
216: static
217: boolean_t
218: handle_bop(
219: thread_t thread,
220: thread_saved_state_t *state
221: )
222: {
223: PCcontext_t context = threadPCContext(thread);
224: code_desc_t code;
225: data_desc_t stack;
226: unsigned int inst;
227: unsigned char bbyte;
228:
229: if (!fetch_desc(thread, state->frame.cs, (dt_entry_t *)&code))
230: return (FALSE);
231:
232: if (!fetch_segment_4byte(
233: thread,
234: (data_desc_t *)&code, state->frame.eip, code.opsz,
235: &inst))
236: return (FALSE);
237:
238: if (*(unsigned short *)&inst != 0xC4C4)
239: return (FALSE);
240:
241: bbyte = *((unsigned char *)&inst + 2);
242:
243: if (bbyte == 0xFE) {
244: PCcancelTimers(context);
245:
246: context->callHandler = PC_HANDLE_EXIT;
247:
248: PCcallMonitor(thread, state);
249: /* NOTREACHED */
250: }
251: else if (bbyte == 0xFA) {
252: PCbopFA_t args;
253:
254: if (!fetch_desc(thread, state->frame.ss, (dt_entry_t *)&stack))
255: return (FALSE);
256:
257: if (!fetch_segment(
258: thread,
259: &stack, state->frame.esp, stack.stksz,
260: &args, sizeof (args)))
261: return (FALSE);
262:
263: return (PCbopFA(thread, state, &args));
264: }
265: else if (bbyte == 0xFC) {
266: PCbopFC_t args;
267:
268: if (!fetch_desc(thread, state->frame.ss, (dt_entry_t *)&stack))
269: return (FALSE);
270:
271: if (!fetch_segment(
272: thread,
273: &stack, state->frame.esp, stack.stksz,
274: &args, sizeof (args)))
275: return (FALSE);
276:
277: return (PCbopFC(thread, state, &args));
278: /* NOTREACHED */
279: }
280: else if (bbyte == 0xFD) {
281: PCbopFD_t args;
282:
283: if (!fetch_desc(thread, state->frame.ss, (dt_entry_t *)&stack))
284: return (FALSE);
285:
286: if (!fetch_segment(
287: thread,
288: &stack, state->frame.esp, stack.stksz,
289: &args, sizeof (args)))
290: return (FALSE);
291:
292: PCbopFD(thread, state, &args);
293: /* NOTREACHED */
294: }
295: else {
296: context->trapNum = bbyte;
297: context->callHandler = PC_HANDLE_BOP;
298:
299: PCcallMonitor(thread, state);
300: /* NOTREACHED */
301: }
302: }
303:
304: static
305: boolean_t
306: emulate_CLI(
307: thread_t thread,
308: thread_saved_state_t *state,
309: code_desc_t *desc
310: )
311: {
312: PCcontext_t context = threadPCContext(thread);
313:
314: if (desc->opsz)
315: state->frame.eip += 1;
316: else
317: (unsigned short)state->frame.eip += 1;
318:
319: context->IF_flag = FALSE;
320:
321: return (TRUE);
322: }
323:
324: static
325: boolean_t
326: emulate_STI(
327: thread_t thread,
328: thread_saved_state_t *state,
329: code_desc_t *desc
330: )
331: {
332: PCcontext_t context = threadPCContext(thread);
333:
334: if (desc->opsz)
335: state->frame.eip += 1;
336: else
337: (unsigned short)state->frame.eip += 1;
338:
339: if (!context->IF_flag) {
340: context->IF_flag = TRUE;
341:
342: context->pendingCallbacks |= (context->runOptions & PC_RUN_IF_SET);
343: }
344:
345: return (TRUE);
346: }
347:
348: static
349: boolean_t
350: push_frame16_err_code(
351: thread_t thread,
352: thread_saved_state_t *state,
353: boolean_t IF_flag,
354: err_code_t err
355: )
356: {
357: struct {
358: unsigned short err;
359: unsigned short ip;
360: sel_t cs;
361: unsigned short flags;
362: } frame;
363: data_desc_t stack;
364:
365: if (!fetch_desc(thread, state->frame.ss, (dt_entry_t *)&stack))
366: return (FALSE); /* not possible */
367:
368: frame.err = err_to_error_code(err);
369:
370: frame.ip = state->frame.eip;
371: frame.cs = state->frame.cs;
372:
373: frame.flags = state->frame.eflags;
374: if (IF_flag)
375: frame.flags |= EFL_IF;
376: else
377: frame.flags &= ~EFL_IF;
378:
379: if (!store_segment(
380: thread,
381: &stack,
382: state->frame.esp - sizeof (frame), stack.stksz,
383: &frame, sizeof (frame)))
384: return (FALSE);
385:
386: if (stack.stksz)
387: state->frame.esp -= sizeof (frame);
388: else
389: (unsigned short)state->frame.esp -= sizeof (frame);
390:
391: return (TRUE);
392: }
393:
394: static
395: boolean_t
396: push_frame16(
397: thread_t thread,
398: thread_saved_state_t *state,
399: boolean_t IF_flag
400: )
401: {
402: struct {
403: unsigned short ip;
404: sel_t cs;
405: unsigned short flags;
406: } frame;
407: data_desc_t stack;
408:
409: if (!fetch_desc(thread, state->frame.ss, (dt_entry_t *)&stack))
410: return (FALSE); /* not possible */
411:
412: frame.ip = state->frame.eip;
413: frame.cs = state->frame.cs;
414:
415: frame.flags = state->frame.eflags;
416: if (IF_flag)
417: frame.flags |= EFL_IF;
418: else
419: frame.flags &= ~EFL_IF;
420:
421: if (!store_segment(
422: thread,
423: &stack,
424: state->frame.esp - sizeof (frame), stack.stksz,
425: &frame, sizeof (frame)))
426: return (FALSE);
427:
428: if (stack.stksz)
429: state->frame.esp -= sizeof (frame);
430: else
431: (unsigned short)state->frame.esp -= sizeof (frame);
432:
433: return (TRUE);
434: }
435:
436: static
437: boolean_t
438: push_frame32_err_code(
439: thread_t thread,
440: thread_saved_state_t *state,
441: boolean_t IF_flag,
442: err_code_t err
443: )
444: {
445: struct {
446: err_code_t err;
447: unsigned int eip;
448: sel_t cs;
449: unsigned short :16;
450: unsigned int eflags;
451: } frame;
452: data_desc_t stack;
453:
454: if (!fetch_desc(thread, state->frame.ss, (dt_entry_t *)&stack))
455: return (FALSE); /* not possible */
456:
457: frame.err = err;
458:
459: frame.eip = state->frame.eip;
460: frame.cs = state->frame.cs;
461:
462: frame.eflags = state->frame.eflags;
463: if (IF_flag)
464: frame.eflags |= EFL_IF;
465: else
466: frame.eflags &= ~EFL_IF;
467:
468: if (!store_segment(
469: thread,
470: &stack,
471: state->frame.esp - sizeof (frame), stack.stksz,
472: &frame, sizeof (frame)))
473: return (FALSE);
474:
475: if (stack.stksz)
476: state->frame.esp -= sizeof (frame);
477: else
478: (unsigned short)state->frame.esp -= sizeof (frame);
479:
480: return (TRUE);
481: }
482:
483: static
484: boolean_t
485: push_frame32(
486: thread_t thread,
487: thread_saved_state_t *state,
488: boolean_t IF_flag
489: )
490: {
491: struct {
492: unsigned int eip;
493: sel_t cs;
494: unsigned short :16;
495: unsigned int eflags;
496: } frame;
497: data_desc_t stack;
498:
499: if (!fetch_desc(thread, state->frame.ss, (dt_entry_t *)&stack))
500: return (FALSE); /* not possible */
501:
502: frame.eip = state->frame.eip;
503: frame.cs = state->frame.cs;
504:
505: frame.eflags = state->frame.eflags;
506: if (IF_flag)
507: frame.eflags |= EFL_IF;
508: else
509: frame.eflags &= ~EFL_IF;
510:
511: if (!store_segment(
512: thread,
513: &stack,
514: state->frame.esp - sizeof (frame), stack.stksz,
515: &frame, sizeof (frame)))
516: return (FALSE);
517:
518: if (stack.stksz)
519: state->frame.esp -= sizeof (frame);
520: else
521: (unsigned short)state->frame.esp -= sizeof (frame);
522:
523: return (TRUE);
524: }
525:
526: static __inline__
527: void
528: enter_gate(
529: except_frame_t *frame,
530: trap_gate_t *gate,
531: boolean_t preserve_trace
532: )
533: {
534: conv_offset_t _offset = { 0 };
535:
536: _offset.fields.offset00 = gate->offset00;
537: _offset.fields.offset16 = gate->offset16;
538:
539: frame->eip = _offset.word;
540: frame->cs = gate->seg;
541:
542: if (!preserve_trace)
543: frame->eflags &= ~EFL_TF;
544: }
545:
546: static
547: boolean_t
548: emulate_exception(
549: thread_t thread,
550: thread_saved_state_t *state,
551: int trapno,
552: err_code_t err,
553: boolean_t inhibit_err_code
554: )
555: {
556: PCcontext_t context;
557: trap_gate_t gate;
558: boolean_t is_intr, is_32bit;
559: code_desc_t code;
560:
561: context = threadPCContext(thread);
562:
563: if (!fetch_IDT_entry(thread, trapno, (idt_entry_t *)&gate))
564: return (FALSE); /* GP(trapno*8+2+EXT) */
565:
566: switch (gate.type) {
567:
568: case DESC_INTR_GATE:
569: is_32bit = TRUE;
570: is_intr = TRUE;
571: break;
572:
573: case DESC_TRAP_GATE:
574: is_32bit = TRUE;
575: is_intr = FALSE;
576: break;
577:
578: case 0x06:
579: is_32bit = FALSE;
580: is_intr = TRUE;
581: break;
582:
583: case 0x07:
584: is_32bit = FALSE;
585: is_intr = FALSE;
586: break;
587:
588: default:
589: return (FALSE); /* GP(trapno*8+2+EXT) */
590: }
591:
592: if (!gate.present)
593: return (FALSE); /* NP(trapno*8+2+EXT) */
594:
595: if (!fetch_desc(thread, gate.seg, (dt_entry_t *)&code))
596: return (FALSE); /* GP(selector+EXT) */
597:
598: if ((code.type & 0x18) != 0x18) // if (!code)
599: return (FALSE); /* GP(selector+EXT) */
600:
601: if (!code.present)
602: return (FALSE); /* NP(selector+EXT) */
603:
604: if (inhibit_err_code || (trapno < 8) || trapno == 16 || (trapno > 17)) {
605: if (is_32bit) {
606: if (!push_frame32(thread, state, context->IF_flag))
607: return (FALSE);
608: }
609: else {
610: if (!push_frame16(thread, state, context->IF_flag))
611: return (FALSE);
612: }
613: }
614: else
615: {
616: if (is_32bit) {
617: if (!push_frame32_err_code(thread, state, context->IF_flag, err))
618: return (FALSE);
619: }
620: else {
621: if (!push_frame16_err_code(thread, state, context->IF_flag, err))
622: return (FALSE);
623: }
624: }
625:
626: #define preserveTrace ((context->debugOptions & PC_DEBUG_PRESERVE_TRACE) != 0)
627: enter_gate(&state->frame, &gate, preserveTrace);
628: #undef preserveTrace
629:
630: if (is_intr)
631: context->IF_flag = FALSE;
632:
633: return (TRUE);
634: }
635:
636: static
637: boolean_t
638: handle_exception(
639: thread_t thread,
640: thread_saved_state_t *state
641: )
642: {
643: PCshared_t shared;
644: PCcontext_t context;
645:
646: shared = threadPCShared(thread);
647: context = currentContext(shared);
648:
649: if (maskIsSet(&shared->faultMask, state->trapno)) {
650: context->trapNum = state->trapno;
651: context->errCode = err_to_error_code(state->frame.err);
652: context->callHandler = PC_HANDLE_FAULT;
653:
654: PCcallMonitor(thread, state);
655: /* NOTREACHED */
656: }
657:
658: if (!emulate_exception(
659: thread,
660: state, state->trapno, state->frame.err,
661: FALSE))
662: return (FALSE);
663:
664: return (TRUE);
665: }
666:
667: static
668: boolean_t
669: emulate_INTn(
670: thread_t thread,
671: thread_saved_state_t *state,
672: code_desc_t *desc,
673: unsigned int inst
674: )
675: {
676: PCshared_t shared;
677: PCcontext_t context;
678: unsigned char trapno;
679: err_code_t err = { 0 };
680:
681: shared = threadPCShared(thread);
682: context = currentContext(shared);
683:
684: trapno = *((unsigned char *)&inst + 1);
685:
686: if (maskIsSet(&shared->intNMask, trapno)) {
687: context->trapNum = trapno;
688: context->errCode = 0;
689: if (trapno <= 7)
690: context->callHandler = PC_HANDLE_FAULT;
691: else
692: context->callHandler = PC_HANDLE_INTN;
693:
694: PCcallMonitor(thread, state);
695: /* NOTREACHED */
696: }
697:
698: if (desc->opsz)
699: state->frame.eip += 2;
700: else
701: (unsigned short)state->frame.eip += 2;
702:
703: if (!emulate_exception(thread, state, trapno, err, TRUE)) {
704: if (desc->opsz)
705: state->frame.eip -= 2;
706: else
707: (unsigned short)state->frame.eip -= 2;
708: return (FALSE);
709: }
710:
711: return (TRUE);
712: }
713:
714: static
715: boolean_t
716: emulate_instruction(
717: thread_t thread,
718: thread_saved_state_t *state
719: )
720: {
721: code_desc_t code;
722: unsigned int inst;
723: unsigned char ibyte;
724:
725: if (!fetch_desc(thread, state->frame.cs, (dt_entry_t *)&code))
726: return (FALSE);
727:
728: if (!fetch_segment_4byte(
729: thread,
730: (data_desc_t *)&code, state->frame.eip, code.opsz,
731: &inst))
732: return (FALSE);
733:
734: ibyte = *(unsigned char *)&inst;
735:
736: if (ibyte == 0xCD)
737: return (emulate_INTn(thread, state, &code, inst));
738:
739: if (ibyte == 0xFA)
740: return (emulate_CLI(thread, state, &code));
741:
742: if (ibyte == 0xFB)
743: return (emulate_STI(thread, state, &code));
744:
745: return (FALSE);
746: }
747:
748: boolean_t
749: PCemulatePROT(
750: thread_t thread,
751: thread_saved_state_t *state
752: )
753: {
754: if (state->trapno == T_GENERAL_PROTECTION) {
755: if (!emulate_instruction(thread,state))
756: return handle_exception(thread, state);
757: else
758: return TRUE;
759: }
760: else
761: if (state->trapno == T_INVALID_OPCODE) {
762: if (!handle_bop(thread, state))
763: return handle_exception(thread, state);
764: else
765: return TRUE;
766: }
767: else
768: return handle_exception(thread, state);
769: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.