Skip site navigation (1)Skip section navigation (2)
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>