Re: New pentium bug workaround - please test..

Mikael Pettersson (Mikael.Pettersson@sophia.inria.fr)
Mon, 24 Nov 1997 14:18:20 +0100 (MET)


On Wed, 19 Nov 1997, Linus Torvalds wrote:

> On Wed, 19 Nov 1997, Hans Lermen wrote:
> >
> > In principal you are right, but the 'alias' version would require
> > _one_ page of mem only while your solution needs _two_ pages.
> > ( admitted, I forgot to do __freepage() for the lower page in my patch )
>
> What we could just do, is to re-use the original page that contained the
> very original IDT - and keep modifying that original page through its
> original address. We'd just also map that page (read-only) to another
> address, and use lidt to point to that one (but the kernel would still use
> the original "idt").

I've adapted Hans' 2.0.32 VM-alias patch for 2.1.66 (2.1.65 + Linus'
pre-66 patch posted Wed 19 Nov 1997). Not many differences except I
had to use an ".align 2048" directive to get the idt properly aligned.
(When placing idt after the .org 0x6000 in head.S, all hell broke
loose. I guess something else wanted that piece of VM...)
I also removed the (now unnecessary) pointers to the idt/gdt tables.

/Mikael

diff -ru linux-2.1.66-pre1/arch/i386/kernel/head.S linux-2.1.66-pre2/arch/i386/kernel/head.S
--- linux-2.1.66-pre1/arch/i386/kernel/head.S Sat Nov 15 02:52:12 1997
+++ linux-2.1.66-pre2/arch/i386/kernel/head.S Sun Nov 23 01:06:45 1997
@@ -289,7 +289,7 @@
movw %dx,%ax /* selector = 0x0010 = cs */
movw $0x8E00,%dx /* interrupt gate - dpl=0, present */

- lea SYMBOL_NAME(idt_table),%edi
+ lea SYMBOL_NAME(idt),%edi
mov $256,%ecx
rp_sidt:
movl %eax,(%edi)
@@ -340,21 +340,17 @@
#endif


-.globl SYMBOL_NAME(idt)
-.globl SYMBOL_NAME(gdt)
-
ALIGN
.word 0
-idt_descr:
+.globl SYMBOL_NAME(idt_descr)
+SYMBOL_NAME(idt_descr):
.word IDT_ENTRIES*8-1 # idt contains 256 entries
-SYMBOL_NAME(idt):
- .long SYMBOL_NAME(idt_table)
+ .long SYMBOL_NAME(idt)

.word 0
gdt_descr:
.word GDT_ENTRIES*8-1
-SYMBOL_NAME(gdt):
- .long SYMBOL_NAME(gdt_table)
+ .long SYMBOL_NAME(gdt)

/*
* This is initialized to create a identity-mapping at 0-4M (for bootup
@@ -523,9 +519,9 @@
*/
.data

-ALIGN
+ .align 2048
/* 256 quadwords - 2048 bytes of idt */
-ENTRY(idt_table)
+ENTRY(idt)
.fill 256,8,0 # idt is uninitialized

/*
@@ -538,7 +534,7 @@
* NOTE! Make sure the gdt descriptor in head.S matches this if you
* change anything.
*/
-ENTRY(gdt_table)
+ENTRY(gdt)
.quad 0x0000000000000000 /* NULL descriptor */
.quad 0x0000000000000000 /* not used */
.quad 0x00cf9a000000ffff /* 0x10 kernel 4GB code at 0x00000000 */
diff -ru linux-2.1.66-pre1/arch/i386/kernel/trampoline.S linux-2.1.66-pre2/arch/i386/kernel/trampoline.S
--- linux-2.1.66-pre1/arch/i386/kernel/trampoline.S Sat Nov 15 03:30:40 1997
+++ linux-2.1.66-pre2/arch/i386/kernel/trampoline.S Sat Nov 22 23:15:12 1997
@@ -61,8 +61,8 @@
.word 0, 0 # idt base = 0L

gdt_48:
- .word 0x0800 # gdt limit = 2048, 256 GDT entries
- .long gdt_table-0xc0000000 # gdt base = gdt (first SMP CPU)
+ .word 0x07ff # gdt limit = 2047, (256 GDT entries)*8-1
+ .long gdt-0xc0000000 # gdt base = gdt (first SMP CPU)

.globl SYMBOL_NAME(trampoline_end)
SYMBOL_NAME_LABEL(trampoline_end)
diff -ru linux-2.1.66-pre1/arch/i386/kernel/traps.c linux-2.1.66-pre2/arch/i386/kernel/traps.c
--- linux-2.1.66-pre1/arch/i386/kernel/traps.c Sun Nov 23 20:17:22 1997
+++ linux-2.1.66-pre2/arch/i386/kernel/traps.c Sun Nov 23 01:54:37 1997
@@ -415,36 +415,30 @@

__initfunc(void trap_init_f00f_bug(void))
{
- unsigned long page;
pgd_t * pgd;
pmd_t * pmd;
pte_t * pte;
+ unsigned long page;
+ unsigned long idtaddr;
+
+ page = (unsigned long)vmalloc(PAGE_SIZE);
+ idtaddr = (unsigned long)idt;
+ idt_descr.limit = 256*8-1;
+ idt_descr.base = (struct desc_struct*)(page + (idtaddr & ~PAGE_MASK));

- /*
- * Allocate a new page in virtual address space,
- * and move the IDT to have entry #7 starting at
- * the beginning of the page. We'll force a page
- * fault for IDT entries #0-#6..
- */
- page = (unsigned long) vmalloc(PAGE_SIZE);
- memcpy((void *) page, idt_table, 256*8);
+ printk("idt at 0x%08lX aliased read-only at 0x%08lX\n",
+ idtaddr, (long)idt_descr.base);

pgd = pgd_offset(&init_mm, page);
pmd = pmd_offset(pgd, page);
pte = pte_offset(pmd, page);
+ free_page(pte_page(*pte));
+ set_pte(pte, mk_pte(idtaddr & PAGE_MASK, PAGE_KERNEL));
*pte = pte_wrprotect(*pte);
local_flush_tlb();

- /*
- * "idt" is magic - it overlaps the idt_descr
- * variable so that updating idt will automatically
- * update the idt descriptor..
- */
- idt = (struct desc_struct *)page;
__asm__ __volatile__("lidt %0": "=m" (idt_descr));
}
-
-

__initfunc(void trap_init(void))
{
diff -ru linux-2.1.66-pre1/arch/i386/mm/fault.c linux-2.1.66-pre2/arch/i386/mm/fault.c
--- linux-2.1.66-pre1/arch/i386/mm/fault.c Sun Nov 23 20:17:22 1997
+++ linux-2.1.66-pre2/arch/i386/mm/fault.c Sat Nov 22 22:18:32 1997
@@ -183,7 +183,7 @@
if (pentium_f00f_bug) {
unsigned long nr;

- nr = (address - (unsigned long) idt) >> 3;
+ nr = (address - (unsigned long) idt_descr.base) >> 3;

if (nr == 6) {
unlock_kernel();
diff -ru linux-2.1.66-pre1/include/linux/head.h linux-2.1.66-pre2/include/linux/head.h
--- linux-2.1.66-pre1/include/linux/head.h Sat Nov 15 03:39:55 1997
+++ linux-2.1.66-pre2/include/linux/head.h Sat Nov 22 22:35:52 1997
@@ -5,16 +5,14 @@
unsigned long a,b;
};

-extern struct desc_struct idt_table[],gdt_table[];
-extern struct desc_struct *idt, *gdt;
+extern struct desc_struct idt[],gdt[];

struct Xgt_desc_struct {
- unsigned short size;
- unsigned long address __attribute__((packed));
+ unsigned short limit;
+ struct desc_struct *base __attribute__((packed));
};

-#define idt_descr (*(struct Xgt_desc_struct *)((char *)&idt - 2))
-#define gdt_descr (*(struct Xgt_desc_struct *)((char *)&gdt - 2))
+extern struct Xgt_desc_struct idt_descr;

#define GDT_NUL 0
#define GDT_CODE 1