diff options
Diffstat (limited to 'arch/i386/mm')
-rw-r--r-- | arch/i386/mm/fault.c | 9 | ||||
-rw-r--r-- | arch/i386/mm/init.c | 64 |
2 files changed, 44 insertions, 29 deletions
diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c index e4847c070..8181fd6c7 100644 --- a/arch/i386/mm/fault.c +++ b/arch/i386/mm/fault.c @@ -186,16 +186,15 @@ bad_area: * * First we check if it was the bootup rw-test, though.. */ - if (wp_works_ok < 0 && address == 0xc0000000 && (error_code & 1)) { + if (wp_works_ok < 0 && address == TASK_SIZE && (error_code & 1)) { wp_works_ok = 1; - pg0[0] = pte_val(mk_pte(0, PAGE_SHARED)); + pg0[0] = pte_val(mk_pte(TASK_SIZE, PAGE_SHARED)); flush_tlb(); goto out; } - if (address < PAGE_SIZE) { + if (address < PAGE_SIZE) printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); - pg0[0] = pte_val(mk_pte(0, PAGE_SHARED)); - } else + else printk(KERN_ALERT "Unable to handle kernel paging request"); printk(" at virtual address %08lx\n",address); __asm__("movl %%cr3,%0" : "=r" (page)); diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c index 8f2852a48..6ed47e2ef 100644 --- a/arch/i386/mm/init.c +++ b/arch/i386/mm/init.c @@ -261,6 +261,43 @@ __initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_ return free_area_init(start_mem, end_mem); } +/* + * Test if the WP bit works in supervisor mode. It isn't supported on 386's + * and also on some strange 486's (NexGen etc.). All 586+'s are OK. The jumps + * before and after the test are here to work-around some nasty CPU bugs. + */ + +__initfunc(void test_wp_bit(void)) +{ + unsigned char tmp_reg; + unsigned long old = pg0[0]; + + printk("Checking if this processor honours the WP bit even in supervisor mode... "); + pg0[0] = pte_val(mk_pte(PAGE_OFFSET, PAGE_READONLY)); + local_flush_tlb(); + current->mm->mmap->vm_start += PAGE_SIZE; + __asm__ __volatile__( + "jmp 1f; 1:\n" + "movb %0,%1\n" + "movb %1,%0\n" + "jmp 1f; 1:\n" + :"=m" (*(char *) __va(0)), + "=q" (tmp_reg) + :/* no inputs */ + :"memory"); + pg0[0] = old; + local_flush_tlb(); + current->mm->mmap->vm_start -= PAGE_SIZE; + if (wp_works_ok < 0) { + wp_works_ok = 0; + printk("No.\n"); +#ifndef CONFIG_M386 + panic("This kernel doesn't support CPU's with broken WP. Recompile it for a 386!"); +#endif + } else + printk("Ok.\n"); +} + __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) { unsigned long start_low_mem = PAGE_SIZE; @@ -339,30 +376,9 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) reservedpages << (PAGE_SHIFT-10), datapages << (PAGE_SHIFT-10), initpages << (PAGE_SHIFT-10)); -/* test if the WP bit is honoured in supervisor mode */ - if (wp_works_ok < 0) { - unsigned char tmp_reg; - unsigned long old = pg0[0]; - printk("Checking if this processor honours the WP bit even in supervisor mode... "); - pg0[0] = pte_val(mk_pte(PAGE_OFFSET, PAGE_READONLY)); - local_flush_tlb(); - current->mm->mmap->vm_start += PAGE_SIZE; - __asm__ __volatile__( - "movb %0,%1 ; movb %1,%0" - :"=m" (*(char *) __va(0)), - "=q" (tmp_reg) - :/* no inputs */ - :"memory"); - pg0[0] = old; - local_flush_tlb(); - current->mm->mmap->vm_start -= PAGE_SIZE; - if (wp_works_ok < 0) { - wp_works_ok = 0; - printk("No.\n"); - } else - printk("Ok.\n"); - } - return; + + if (wp_works_ok < 0) + test_wp_bit(); } void free_initmem(void) |