Index: identcpu.c =================================================================== RCS file: /home/cvsup/freebsd/CVS/src/sys/i386/i386/identcpu.c,v retrieving revision 1.33 retrieving revision 1.35 diff -u -r1.33 -r1.35 --- identcpu.c 1997/11/07 08:52:27 1.33 +++ identcpu.c 1997/12/04 14:35:38 1.35 @@ -107,6 +107,10 @@ ); } +#if defined(I586_CPU) && !defined(NO_F00F_HACK) +int has_f00f_bug = 0; +#endif + void printcpuinfo(void) { @@ -136,6 +140,14 @@ break; case 0x500: strcat(cpu_model, "Pentium"); /* nb no space */ +#if defined(I586_CPU) && !defined(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: /home/cvsup/freebsd/CVS/src/sys/i386/i386/machdep.c,v retrieving revision 1.274 retrieving revision 1.278 diff -u -r1.274 -r1.278 --- machdep.c 1997/11/24 18:35:11 1.274 +++ machdep.c 1997/12/04 21:21:24 1.278 @@ -866,6 +867,11 @@ #endif /* VM86 */ #endif +#if defined(I586_CPU) && !defined(NO_F00F_HACK) +struct gate_descriptor *t_idt; +extern int has_f00f_bug; +#endif + static struct i386tss dblfault_tss; static char dblfault_stack[PAGE_SIZE]; @@ -1533,6 +1539,40 @@ proc0.p_addr->u_pcb.pcb_mpnest = 1; proc0.p_addr->u_pcb.pcb_ext = 0; } + +#if defined(I586_CPU) && !defined(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; + + 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 (tmp == 0) + panic("kmem_alloc returned 0"); + if (((unsigned int)tmp & (PAGE_SIZE-1)) != 0) + panic("kmem_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); + if (vm_map_protect(kernel_map, tmp, tmp + PAGE_SIZE, + VM_PROT_READ, FALSE) != KERN_SUCCESS) + panic("vm_map_protect failed"); + return; +} +#endif /* defined(I586_CPU) && !NO_F00F_HACK */ int ptrace_set_pc(p, addr) Index: trap.c =================================================================== RCS file: /home/cvsup/freebsd/CVS/src/sys/i386/i386/trap.c,v retrieving revision 1.115 retrieving revision 1.118 diff -u -r1.115 -r1.118 --- trap.c 1997/11/24 13:25:37 1.115 +++ trap.c 1997/12/04 21:21:26 1.118 @@ -142,6 +143,11 @@ static void userret __P((struct proc *p, struct trapframe *frame, u_quad_t oticks)); +#if defined(I586_CPU) && !defined(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; @@ -211,6 +217,9 @@ u_long eva; #endif +#if defined(I586_CPU) && !defined(NO_F00F_HACK) +restart: +#endif type = frame.tf_trapno; code = frame.tf_err; @@ -276,6 +285,10 @@ i = trap_pfault(&frame, TRUE); if (i == -1) return; +#if defined(I586_CPU) && !defined(NO_F00F_HACK) + if (i == -2) + goto restart; +#endif if (i == 0) goto out; @@ -642,7 +655,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. */ +#if defined(I586_CPU) && !defined(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;