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