diff options
Diffstat (limited to 'i386')
-rw-r--r-- | i386/Makefrag.am | 1 | ||||
-rw-r--r-- | i386/configfrag.ac | 3 | ||||
-rw-r--r-- | i386/i386/fpe_linkage.c | 363 | ||||
-rw-r--r-- | i386/i386/fpu.c | 72 | ||||
-rw-r--r-- | i386/i386/fpu.h | 28 | ||||
-rw-r--r-- | i386/i386/gdt.h | 5 | ||||
-rw-r--r-- | i386/i386/trap.c | 9 |
7 files changed, 2 insertions, 479 deletions
diff --git a/i386/Makefrag.am b/i386/Makefrag.am index f34c7cc..50b7afd 100644 --- a/i386/Makefrag.am +++ b/i386/Makefrag.am @@ -80,7 +80,6 @@ libkernel_a_SOURCES += \ i386/i386/debug_i386.c \ i386/i386/debug_trace.S \ i386/i386/eflags.h \ - i386/i386/fpe_linkage.c \ i386/i386/fpu.c \ i386/i386/fpu.h \ i386/i386/gdt.c \ diff --git a/i386/configfrag.ac b/i386/configfrag.ac index d32f2b8..a82ce5c 100644 --- a/i386/configfrag.ac +++ b/i386/configfrag.ac @@ -28,9 +28,6 @@ AC_DEFINE([i386], [1], [i386]) # i386/bogus/com.h AC_DEFINE([NCOM], [4], [NCOM]) -# i386/bogus/fpe.h -AC_DEFINE([FPE], [0], [We do not have a floating point implementation.]) - # i386/bogus/lpr.h AC_DEFINE([NLPR], [1], [NLPR]) diff --git a/i386/i386/fpe_linkage.c b/i386/i386/fpe_linkage.c deleted file mode 100644 index f0ac34e..0000000 --- a/i386/i386/fpe_linkage.c +++ /dev/null @@ -1,363 +0,0 @@ -/* - * Mach Operating System - * Copyright (c) 1991 Carnegie Mellon University - * All Rights Reserved. - * - * Permission to use, copy, modify and distribute this software and its - * documentation is hereby granted, provided that both the copyright - * notice and this permission notice appear in all copies of the - * software, derivative works or modified versions, and any portions - * thereof, and that both notices appear in supporting documentation. - * - * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" - * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR - * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * - * Carnegie Mellon requests users of this software to return to - * - * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU - * School of Computer Science - * Carnegie Mellon University - * Pittsburgh PA 15213-3890 - * - * any improvements or extensions that they make and grant Carnegie Mellon - * the rights to redistribute these changes. - */ - -/* - * Support routines for FP emulator. - */ - -#if FPE - -#include <cpus.h> - -#include <mach/std_types.h> -#include <mach/exception.h> -#include <mach/thread_status.h> - -#include <kern/cpu_number.h> -#include <kern/debug.h> -#include <kern/thread.h> - -#include <vm/vm_kern.h> - -#include <mach/machine/eflags.h> -#include "vm_param.h" -#include <i386/pmap.h> -#include <i386/thread.h> -#include <i386/fpu.h> -#include "proc_reg.h" -#include "seg.h" -#include "idt.h" -#include "gdt.h" - -#if NCPUS > 1 -#include <i386/mp_desc.h> -#endif - -extern vm_offset_t kvtophys(); - -/* - * Symbols exported from FPE emulator. - */ -extern char fpe_start[]; /* start of emulator text; - also emulation entry point */ -extern char fpe_end[]; /* end of emulator text */ -extern int fpe_reg_segment; - /* word holding segment number for - FPE register/status area */ -extern char fpe_recover[]; /* emulation fault recovery entry point */ - -extern void fix_desc(); - -#if NCPUS > 1 -#define curr_gdt(mycpu) (mp_gdt[mycpu]) -#define curr_idt(mycpu) (mp_desc_table[mycpu]->idt) -#else -#define curr_gdt(mycpu) (gdt) -#define curr_idt(mycpu) (idt) -#endif - -#define gdt_desc_p(mycpu,sel) \ - ((struct real_descriptor *)&curr_gdt(mycpu)[sel_idx(sel)]) -#define idt_desc_p(mycpu,idx) \ - ((struct real_gate *)&curr_idt(mycpu)[idx]) - -void set_user_access(); /* forward */ -void enable_fpe(register struct i386_fpsave_state *ifps); - -/* - * long pointer for calling FPE register recovery routine. - */ -struct long_ptr { - unsigned long offset; - unsigned short segment; -}; - -struct long_ptr fpe_recover_ptr; - -/* - * Initialize descriptors for FP emulator. - */ -void -fpe_init() -{ - register struct real_descriptor *gdt_p; - register struct real_gate *idt_p; - - /* - * Map in the pages for the FP emulator: - * read-only, user-accessible. - */ - set_user_access(pmap_kernel(), - (vm_offset_t)fpe_start, - (vm_offset_t)fpe_end, - FALSE); - - /* - * Put the USER_FPREGS segment value in the FP emulator. - */ - fpe_reg_segment = USER_FPREGS; - - /* - * Change exception 7 gate (coprocessor not present) - * to a trap gate to the FPE code segment. - */ - idt_p = idt_desc_p(cpu_number(), 7); - idt_p->offset_low = 0; /* offset of FPE entry */ - idt_p->offset_high = 0; - idt_p->selector = FPE_CS; /* FPE code segment */ - idt_p->word_count = 0; - idt_p->access = ACC_P|ACC_PL_K|ACC_TRAP_GATE; - /* trap gate */ - /* kernel privileges only, - so INT $7 does not call - the emulator */ - - /* - * Build GDT entry for FP code segment. - */ - gdt_p = gdt_desc_p(cpu_number(), FPE_CS); - gdt_p->base_low = ((vm_offset_t) fpe_start) & 0xffff; - gdt_p->base_med = (((vm_offset_t) fpe_start) >> 16) & 0xff; - gdt_p->base_high = ((vm_offset_t) fpe_start) >> 24; - gdt_p->limit_low = (vm_offset_t) fpe_end - - (vm_offset_t) fpe_start - - 1; - gdt_p->limit_high = 0; - gdt_p->granularity = SZ_32; - gdt_p->access = ACC_P|ACC_PL_K|ACC_CODE_CR; - /* conforming segment, - usable by kernel */ - - /* - * Build GDT entry for user FP state area - template, - * since each thread has its own. - */ - gdt_p = gdt_desc_p(cpu_number(), USER_FPREGS); - /* descriptor starts as 0 */ - gdt_p->limit_low = sizeof(struct i386_fp_save) - + sizeof(struct i386_fp_regs) - - 1; - gdt_p->limit_high = 0; - gdt_p->granularity = 0; - gdt_p->access = ACC_PL_U|ACC_DATA_W; - /* start as "not present" */ - - /* - * Set up the recovery routine pointer - */ - fpe_recover_ptr.offset = fpe_recover - fpe_start; - fpe_recover_ptr.segment = FPE_CS; - - /* - * Set i386 to emulate coprocessor. - */ - set_cr0((get_cr0() & ~CR0_MP) | CR0_EM); -} - -/* - * Enable FPE use for a new thread. - * Allocates the FP save area. - */ -boolean_t -fp_emul_error(regs) - struct i386_saved_state *regs; -{ - register struct i386_fpsave_state *ifps; - register vm_offset_t start_va; - - if ((regs->err & 0xfffc) != (USER_FPREGS & ~SEL_PL)) - return FALSE; - - /* - * Make the FPU save area user-accessible (by FPE) - */ - ifps = current_thread()->pcb->ims.ifps; - if (ifps == 0) { - /* - * No FP register state yet - allocate it. - */ - fp_state_alloc(); - ifps = current_thread()->pcb->ims.ifps; - } - - panic("fp_emul_error: FP emulation is probably broken because of VM changes; fix! XXX"); - start_va = (vm_offset_t) &ifps->fp_save_state; - set_user_access(current_map()->pmap, - start_va, - start_va + sizeof(struct i386_fp_save), - TRUE); - - /* - * Enable FPE use for this thread - */ - enable_fpe(ifps); - - return TRUE; -} - -/* - * Enable FPE use. ASSUME that kernel does NOT use FPU - * except to handle user exceptions. - */ -void -enable_fpe(ifps) - register struct i386_fpsave_state *ifps; -{ - struct real_descriptor *dp; - vm_offset_t start_va; - - dp = gdt_desc_p(cpu_number(), USER_FPREGS); - start_va = (vm_offset_t)&ifps->fp_save_state; - - dp->base_low = start_va & 0xffff; - dp->base_med = (start_va >> 16) & 0xff; - dp->base_high = start_va >> 24; - dp->access |= ACC_P; -} - -void -disable_fpe() -{ - /* - * The kernel might be running with fs & gs segments - * which refer to USER_FPREGS, if we entered the kernel - * from a FP-using thread. We have to clear these segments - * lest we get a Segment Not Present trap. This would happen - * if the kernel took an interrupt or fault after clearing - * the present bit but before exiting to user space (which - * would reset fs & gs from the current user thread). - */ - - asm volatile("xorw %ax, %ax\n\t" - "movw %ax, %fs\n\t" - "movw %ax, %gs\n\t":::"ax"); - - gdt_desc_p(cpu_number(), USER_FPREGS)->access &= ~ACC_P; -} - -void -set_user_access(pmap, start, end, writable) - pmap_t pmap; - vm_offset_t start; - vm_offset_t end; - boolean_t writable; -{ - register vm_offset_t va; - register pt_entry_t * dirbase = pmap->dirbase; - register pt_entry_t * ptep; - register pt_entry_t * pdep; - - start = i386_trunc_page(start); - end = i386_round_page(end); - - for (va = start; va < end; va += I386_PGBYTES) { - - pdep = &dirbase[lin2pdenum(kvtolin(va))]; - *pdep |= INTEL_PTE_USER; - ptep = (pt_entry_t *)ptetokv(*pdep); - ptep = &ptep[ptenum(va)]; - *ptep |= INTEL_PTE_USER; - if (!writable) - *ptep &= ~INTEL_PTE_WRITE; - } -} - -/* - * Route exception through emulator fixup routine if - * it occured within the emulator. - */ -extern void exception(); - -void -fpe_exception_fixup(exc, code, subcode) - int exc, code, subcode; -{ - thread_t thread = current_thread(); - pcb_t pcb = thread->pcb; - - if (pcb->iss.efl & EFL_VM) { - /* - * The emulator doesn`t handle V86 mode. - * If this is a GP fault on the emulator`s - * code segment, change it to an FP not present - * fault. - */ - if (exc == EXC_BAD_INSTRUCTION - && code == EXC_I386_GPFLT - && subcode == FPE_CS + 1) - { - exc = EXC_ARITHMETIC; /* arithmetic error: */ - code = EXC_I386_NOEXT; /* no FPU */ - subcode = 0; - } - } - else - if ((pcb->iss.cs & 0xfffc) == FPE_CS) { - /* - * Pass registers to emulator, - * to let it fix them up. - * The emulator fixup routine knows about - * an i386_thread_state. - */ - struct i386_thread_state tstate; - unsigned int count; - - count = i386_THREAD_STATE_COUNT; - (void) thread_getstatus(thread, - i386_REGS_SEGS_STATE, - (thread_state_t) &tstate, - &count); - - /* - * long call to emulator register recovery routine - */ - asm volatile("pushl %0; lcall %1; addl $4,%%esp" - : - : "r" (&tstate), - "m" (fpe_recover_ptr) ); - - (void) thread_setstatus(thread, - i386_REGS_SEGS_STATE, - (thread_state_t) &tstate, - count); - /* - * In addition, check for a GP fault on 'int 16' in - * the emulator, since the interrupt gate is protected. - * If so, change it to an arithmetic error. - */ - if (exc == EXC_BAD_INSTRUCTION - && code == EXC_I386_GPFLT - && subcode == 8*16+2) /* idt[16] */ - { - exc = EXC_ARITHMETIC; - code = EXC_I386_EXTERR; - subcode = pcb->ims.ifps->fp_save_state.fp_status; - } - } - exception(exc, code, subcode); -} -#endif /* FPE. */ - diff --git a/i386/i386/fpu.c b/i386/i386/fpu.c index 17f5dab..ad88a5d 100644 --- a/i386/i386/fpu.c +++ b/i386/i386/fpu.c @@ -138,19 +138,11 @@ init_fpu() set_cr0(get_cr0() | CR0_TS | CR0_MP); } else { -#if FPE - /* - * Use the floating-point emulator. - */ - fp_kind = FP_SOFT; - fpe_init(); -#else /* no fpe */ /* * NO FPU. */ fp_kind = FP_NO; set_cr0(get_cr0() | CR0_EM); -#endif } } @@ -277,39 +269,7 @@ ASSERT_IPL(SPL0); ifps->fp_save_state.fp_opcode = user_fp_state->fp_opcode; ifps->fp_save_state.fp_dp = user_fp_state->fp_dp; ifps->fp_save_state.fp_ds = user_fp_state->fp_ds; - -#if FPE - if (fp_kind == FP_SOFT) { - /* - * The emulator stores the registers by physical - * register number, not from top-of-stack. - * Shuffle the registers into the correct order. - */ - register char *src; /* user regs */ - register char *dst; /* kernel regs */ - int i; - - src = (char *)user_fp_regs; - dst = (char *)&ifps->fp_regs; - i = (ifps->fp_save_state.fp_status & FPS_TOS) - >> FPS_TOS_SHIFT; /* physical register - for st(0) */ - if (i == 0) - memcpy(dst, src, 8 * 10); - else { - memcpy(dst + 10 * i, - src, - 10 * (8 - i)); - memcpy(dst, - src + 10 * (8 - i), - 10 * i); - } - } - else - ifps->fp_regs = *user_fp_regs; -#else /* no FPE */ ifps->fp_regs = *user_fp_regs; -#endif /* FPE */ simple_unlock(&pcb->lock); if (new_ifps != 0) @@ -387,39 +347,7 @@ ASSERT_IPL(SPL0); user_fp_state->fp_opcode = ifps->fp_save_state.fp_opcode; user_fp_state->fp_dp = ifps->fp_save_state.fp_dp; user_fp_state->fp_ds = ifps->fp_save_state.fp_ds; - -#if FPE - if (fp_kind == FP_SOFT) { - /* - * The emulator stores the registers by physical - * register number, not from top-of-stack. - * Shuffle the registers into the correct order. - */ - register char *src; /* kernel regs */ - register char *dst; /* user regs */ - int i; - - src = (char *)&ifps->fp_regs; - dst = (char *)user_fp_regs; - i = (ifps->fp_save_state.fp_status & FPS_TOS) - >> FPS_TOS_SHIFT; /* physical register - for st(0) */ - if (i == 0) - memcpy(dst, src, 8 * 10); - else { - memcpy(dst, - src + 10 * i, - 10 * (8 - i)); - memcpy(dst + 10 * (8 - i), - src, - 10 * i); - } - } - else - *user_fp_regs = ifps->fp_regs; -#else /* no FPE */ *user_fp_regs = ifps->fp_regs; -#endif /* FPE */ } simple_unlock(&pcb->lock); diff --git a/i386/i386/fpu.h b/i386/i386/fpu.h index bb332ad..3e92de7 100644 --- a/i386/i386/fpu.h +++ b/i386/i386/fpu.h @@ -69,32 +69,6 @@ #define fwait() \ asm("fwait"); -/* - * If floating-point instructions are emulated, - * we must load the floating-point register selector - * when switching to a new thread. - */ -#if FPE -extern void disable_fpe(); -extern void enable_fpe(); - -#define fpu_save_context(thread) \ - { \ - if (fp_kind == FP_SOFT) \ - disable_fpe(); \ - else \ - set_ts(); \ - } - -#define fpu_load_context(pcb) \ - { \ - register struct i386_fpsave_state *ifps; \ - if (fp_kind == FP_SOFT && (ifps = pcb->ims.ifps) != 0) \ - enable_fpe(ifps); \ - } - -#else /* no FPE */ - #define fpu_load_context(pcb) /* @@ -124,8 +98,6 @@ extern void enable_fpe(); #endif /* NCPUS == 1 */ -#endif /* no FPE */ - extern int fp_kind; #endif /* _I386_FPU_H_ */ diff --git a/i386/i386/gdt.h b/i386/i386/gdt.h index 4715759..558bd15 100644 --- a/i386/i386/gdt.h +++ b/i386/i386/gdt.h @@ -45,9 +45,8 @@ #define USER_LDT 0x28 /* place for per-thread LDT */ #define USER_TSS 0x30 /* place for per-thread TSS that holds IO bitmap */ -#define FPE_CS 0x38 /* floating-point emulator code */ -#define USER_FPREGS 0x40 /* user-mode access to saved - floating-point registers */ +/* 0x38 was FPE_CS, now free */ +/* 0x40 was USER_FPREGS, now free */ #define USER_GDT 0x48 /* user-defined GDT entries */ #define USER_GDT_SLOTS 2 diff --git a/i386/i386/trap.c b/i386/i386/trap.c index 068a0b3..bd0d8e0 100644 --- a/i386/i386/trap.c +++ b/i386/i386/trap.c @@ -480,11 +480,6 @@ printf("user trap %d error %d sub %08x\n", type, code, subcode); break; case T_SEGMENT_NOT_PRESENT: -#if FPE - if (fp_emul_error(regs)) - return 0; -#endif /* FPE */ - exc = EXC_BAD_INSTRUCTION; code = EXC_I386_SEGNPFLT; subcode = regs->err & 0xffff; @@ -1035,11 +1030,7 @@ i386_exception(exc, code, subcode) ast_off(cpu_number(), AST_I386_FP); splx(s); -#if FPE - fpe_exception_fixup(exc, code, subcode); -#else exception(exc, code, subcode); -#endif /*NOTREACHED*/ } |