Date: Mon, 17 Nov 1997 10:55:42 -0800 (PST) From: Sean Eric Fagan <sef@kithrup.com> To: hackers@freebsd.org Subject: temporary f00f workaround Message-ID: <199711171855.KAA07784@kithrup.com>
next in thread | raw e-mail | index | archive | help
Thanks to Cy Schubert and Johnathan Lemon for pointers. Note that this is not final, nor complete -- it doesn't deal with VM86 mode, with user-defined LDT's, nor with some of the annoyances that have to be done. But Johnathan's other patch won't work reliably (I have a small test program that tries to cause the TLB entries to be flushed, and then executes the f00f instruction -- and causes a hang). Cy also has another suggestion, involving remapping the page temporarily, which I haven't tried. Anyway, this should do for now. In general, you don't need to apply it unless you've got people you don't trust running programs on your system, or are extra paranoid about security, or want to try fleshing out the bits I don't have here. Enjoy. Index: identcpu.c =================================================================== RCS file: /usr/home/sef/CVS-kernel/sys/i386/i386/identcpu.c,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 identcpu.c --- identcpu.c 1997/03/01 02:57:12 1.1.1.1 +++ identcpu.c 1997/11/15 18:40:04 @@ -78,6 +78,10 @@ { "Pentium Pro", CPUCLASS_686 }, /* CPU_686 */ }; +#ifndef NO_PENTIUM_F00F_HACK +int has_f00f_bug = 0; +#endif + void identifycpu(void) { @@ -104,6 +108,9 @@ strcat(cpu_model, "i486 "); break; case 0x500: +#ifndef NO_PENTIUM_F00F_HACK + has_f00f_bug = 1; +#endif strcat(cpu_model, "Pentium"); /* nb no space */ break; case 0x600: Index: machdep.c =================================================================== RCS file: /usr/home/sef/CVS-kernel/sys/i386/i386/machdep.c,v retrieving revision 1.2 diff -u -r1.2 machdep.c --- machdep.c 1997/03/01 05:36:35 1.2 +++ machdep.c 1997/11/15 19:04:20 @@ -1002,6 +1002,12 @@ ssd->ssd_gran = sd->sd_gran; } +#ifndef NO_PENTIUM_F00F_HACK +struct gate_descriptor *t_idt; +unsigned char hack_idt[PAGE_SIZE * 3]; +extern int has_f00f_bug; +#endif + void init386(first) int first; @@ -1394,6 +1400,44 @@ proc0.p_addr->u_pcb.pcb_flags = 0; proc0.p_addr->u_pcb.pcb_cr3 = IdlePTD; } + +#ifndef NO_PENTIUM_F00F_HACK +void f00f_hack(void); +SYSINIT(f00f_hack, SI_SUB_INTRINSIC, SI_ORDER_FIRST, f00f_hack, NULL); + +void +f00f_hack(void) { + struct region_descriptor r_idt; + unsigned char *tmp; + int i; + vm_offset_t vp; + unsigned *pte; + + if (!has_f00f_bug) + return; + + printf("Intel Pentium F00F detected, installing workaround\n"); + + r_idt.rd_limit = sizeof(idt) - 1; + + tmp = (unsigned char*)roundup2((unsigned)hack_idt, PAGE_SIZE); + tmp += PAGE_SIZE - (7*8); /* Put seven entries in lower page */ + t_idt = (struct gate_descriptor *)tmp; + for (i = 0; i < NIDT; i++) { + t_idt[i] = idt[i]; + if (t_idt != (struct gate_descriptor*)tmp) { + printf("t_idt changed! i = %d\n", i); + t_idt = (struct gate_descriptor*)tmp; + } + } + r_idt.rd_base = (int) t_idt; + lidt(&r_idt); + vp = trunc_page(t_idt); + pte = (unsigned *)vtopte(vp); + *pte = *pte & ~PG_V; /* Mark page as not present */ + invlpg(vp); +} +#endif /* NO_PENTIUM_F00F_HACK */ /* * The registers are in the frame; the frame is in the user area of Index: trap.c =================================================================== RCS file: /usr/home/sef/CVS-kernel/sys/i386/i386/trap.c,v retrieving revision 1.2 diff -u -r1.2 trap.c --- trap.c 1997/03/01 05:36:37 1.2 +++ trap.c 1997/11/15 23:37:27 @@ -133,6 +133,13 @@ static void userret __P((struct proc *p, struct trapframe *frame, u_quad_t oticks)); +#ifndef NO_PENTIUM_F00F_HACK +extern struct gate_descriptor *t_idt; +extern int has_f00f_bug; +static int f00f_traps[] = { T_DIVIDE, T_TRCTRAP, T_NMI, T_BPTFLT, + T_OFLOW, T_BOUND, T_PRIVINFLT }; +#endif + static inline void userret(p, frame, oticks) struct proc *p; @@ -188,7 +195,7 @@ #ifdef DEBUG u_long eva; #endif - +restart: type = frame.tf_trapno; code = frame.tf_err; @@ -254,6 +261,8 @@ case T_PAGEFLT: /* page fault */ i = trap_pfault(&frame, TRUE); + if (i == -2) + goto restart; if (i == -1) return; if (i == 0) @@ -504,6 +513,7 @@ eva = rcr2(); va = trunc_page((vm_offset_t)eva); + if (va < VM_MIN_KERNEL_ADDRESS) { vm_offset_t v; vm_page_t mpte; @@ -599,6 +609,24 @@ eva = rcr2(); va = trunc_page((vm_offset_t)eva); +#ifndef NO_PENTIUM_F00F_HACK + if (has_f00f_bug && + (eva >= (unsigned int)t_idt) && + (eva <= (unsigned int)(((unsigned char*)t_idt) + 7*8))) { + int nr; + unsigned char inst; + nr = (eva - (unsigned int)t_idt)/8; + inst = fubyte(frame->tf_eip); + frame->tf_trapno = f00f_traps[nr]; + if (inst == 0xcc || inst == 0xce || inst == 0xcf) { + frame->tf_eip++; + } + if (inst == 0x62) { + frame->tf_eip += 2; + } + return -2; + } +#endif if (va >= KERNBASE) { /* * Don't allow user-mode faults in kernel address space.
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199711171855.KAA07784>