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>
