Date: Thu, 27 Nov 1997 11:54:14 -0800 (PST) From: Sean Eric Fagan <sef@kithrup.com> To: hackers@freebsd.org, security@freebsd.org Subject: Re: Updated f00f workaround Message-ID: <199711271954.LAA24160@kithrup.com>
next in thread | raw e-mail | index | archive | help
Okay, I took Stephen McKay's suggestions to heart, and here are what I hope are the final diffs. I'm currently running this kernel in multiuser mode, and haven't noticed any problems (yet, anyway ;)). Overhead should be minimal. 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/27 19:48:34 @@ -78,6 +78,10 @@ { "Pentium Pro", CPUCLASS_686 }, /* CPU_686 */ }; +#ifndef NO_F00F_HACK +int has_f00f_bug = 0; +#endif + void identifycpu(void) { @@ -105,6 +109,14 @@ break; case 0x500: strcat(cpu_model, "Pentium"); /* nb no space */ +#ifndef NO_F00F_HACK + /* + * XXX - If/when Intel fixes the bug, this + * should also check the version of the + * CPU, not just that it's a Pentium. + */ + has_f00f_bug = 1; +#endif break; case 0x600: strcat(cpu_model, "Pentium Pro"); 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/27 19:48:34 @@ -803,6 +803,11 @@ struct gate_descriptor idt[NIDT]; /* interrupt descriptor table */ union descriptor ldt[NLDT]; /* local descriptor table */ +#ifndef NO_F00F_HACK +struct gate_descriptor *t_idt; +int has_f00f_bug; +#endif + static struct i386tss dblfault_tss; static char dblfault_stack[PAGE_SIZE]; @@ -1394,6 +1399,42 @@ proc0.p_addr->u_pcb.pcb_flags = 0; proc0.p_addr->u_pcb.pcb_cr3 = IdlePTD; } + +#ifndef NO_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 = kmem_alloc(kernel_map, PAGE_SIZE * 2); + if (((unsigned int)tmp) & 4095) + panic("kern_alloc returned non-page-aligned memory"); + /* Put the first seven entries in the lower page */ + t_idt = (struct gate_descriptor*)(tmp + PAGE_SIZE - (7*8)); + bcopy(idt, t_idt, sizeof(idt)); + r_idt.rd_base = (int)t_idt; + lidt(&r_idt); + vp = trunc_page(t_idt); + if (vm_map_protect(kernel_map, tmp, tmp + (PAGE_SIZE*2), + VM_PROT_READ, FALSE) != KERN_SUCCESS) + panic("vm_map_protect failed"); + invlpg(vp); /* XXX -- is this necessary? */ + return; +} +#endif /* NO_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.3 diff -u -r1.3 trap.c --- trap.c 1997/11/24 08:19:19 1.3 +++ trap.c 1997/11/27 19:48:35 @@ -134,6 +134,11 @@ static void userret __P((struct proc *p, struct trapframe *frame, u_quad_t oticks)); +#ifndef NO_F00F_HACK +extern struct gate_descriptor *t_idt; +extern int has_f00f_bug; +#endif + static inline void userret(p, frame, oticks) struct proc *p; @@ -190,6 +195,9 @@ u_long eva; #endif +#ifndef NO_F00F_HACK +restart: +#endif type = frame.tf_trapno; code = frame.tf_err; @@ -257,6 +265,10 @@ i = trap_pfault(&frame, TRUE); if (i == -1) return; +#ifndef NO_F00F_HACK + if (i == -2) + goto restart; +#endif if (i == 0) goto out; @@ -603,7 +615,18 @@ if (va >= KERNBASE) { /* * Don't allow user-mode faults in kernel address space. + * An exception: if the faulting address is the invalid + * instruction entry in the IDT, then the Intel Pentium + * F00F bug workaround was triggered, and we need to + * treat it is as an illegal instruction, and not a page + * fault. */ +#ifndef NO_F00F_HACK + if ((eva == (unsigned int)&t_idt[6]) && has_f00f_bug) { + frame->tf_trapno = T_PRIVINFLT; + return -2; + } +#endif if (usermode) goto nogo;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199711271954.LAA24160>