From 7cd4002083367418f3cdb6fec53e27884664a6a6 Mon Sep 17 00:00:00 2001 From: Ben Gras Date: Mon, 2 Jan 2012 18:20:02 +0100 Subject: [PATCH] vm: clear map cache after kernel requests . fixes a dirty tlb situation (i.e. random crashes) on some hardware, seemingly new intel architectures (e.g. my desktop i7 machine) --- kernel/arch/i386/memory.c | 6 +++--- servers/vm/arch/i386/pagetable.c | 21 ++++++++++++++++++++- servers/vm/main.c | 3 +++ 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/kernel/arch/i386/memory.c b/kernel/arch/i386/memory.c index 8098355c5..d512f07bf 100644 --- a/kernel/arch/i386/memory.c +++ b/kernel/arch/i386/memory.c @@ -31,7 +31,7 @@ PUBLIC int i386_paging_enabled = 0; PRIVATE int psok = 0; -#define FREE_PDES_PER_CPU 3 +#define FREE_PDES_PER_CPU 2 #define MAX_FREEPDES (FREE_PDES_PER_CPU * CONFIG_MAX_CPUS) PRIVATE int nfreepdes = 0, freepdes[MAX_FREEPDES]; @@ -145,7 +145,7 @@ PRIVATE int lin_lin_copy(const struct proc *srcproc, vir_bytes srclinaddr, proc_nr_t procslot; assert(vm_running); - assert(nfreepdes >= 3); + assert(nfreepdes >= 2); assert(get_cpulocal_var(ptproc)); assert(get_cpulocal_var(proc_ptr)); @@ -645,7 +645,7 @@ int vm_phys_memset(phys_bytes ph, const u8_t c, phys_bytes bytes) return OK; } - assert(nfreepdes >= 3); + assert(nfreepdes >= 2); assert(get_cpulocal_var(ptproc)->p_seg.p_cr3_v); diff --git a/servers/vm/arch/i386/pagetable.c b/servers/vm/arch/i386/pagetable.c index bbd2183e9..4c0ee2008 100644 --- a/servers/vm/arch/i386/pagetable.c +++ b/servers/vm/arch/i386/pagetable.c @@ -36,6 +36,10 @@ #include "memory.h" +/* Free PDE slots we tell kernel about */ +#define FREE_PDES 2 +PRIVATE int first_free_pde = -1; + /* PDE used to map in kernel, kernel physical address. */ PRIVATE int id_map_high_pde = -1, pagedir_pde = -1; PRIVATE u32_t global_bit = 0, pagedir_pde_val; @@ -638,6 +642,18 @@ PUBLIC int pt_ptmap(struct vmproc *src_vmp, struct vmproc *dst_vmp) return OK; } +PUBLIC int pt_clearmapcache(void) +{ + int f; + /* Make sure kernel will invalidate tlb when using current + * pagetable (i.e. vm's) to make new mappings before new cr3 + * is loaded. + */ + for(f = first_free_pde; f < first_free_pde+FREE_PDES; f++) { + vmprocess->vm_pt.pt_dir[f] = 0; + } +} + /*===========================================================================* * pt_writemap * *===========================================================================*/ @@ -876,6 +892,7 @@ PUBLIC void pt_init(phys_bytes usedlimit) vir_bytes sparepages_mem; phys_bytes sparepages_ph; vir_bytes ptr; + int f = 0; /* Shorthand. */ newpt = &vmprocess->vm_pt; @@ -1030,10 +1047,12 @@ PUBLIC void pt_init(phys_bytes usedlimit) I386_VM_PRESENT | I386_VM_USER | I386_VM_WRITE; /* Tell kernel about free pde's. */ - while(free_pde*I386_BIG_PAGE_SIZE < VM_PROCSTART) { + first_free_pde = free_pde; + while(free_pde*I386_BIG_PAGE_SIZE < VM_PROCSTART && f < FREE_PDES) { if((r=sys_vmctl(SELF, VMCTL_I386_FREEPDE, free_pde++)) != OK) { panic("VMCTL_I386_FREEPDE failed: %d", r); } + f++; } /* first pde in use by process. */ diff --git a/servers/vm/main.c b/servers/vm/main.c index 576522319..43a07b78d 100644 --- a/servers/vm/main.c +++ b/servers/vm/main.c @@ -112,6 +112,7 @@ PUBLIC int main(void) "message!\n", msg.m_source); } do_pagefaults(&msg); + pt_clearmapcache(); /* * do not reply to this call, the caller is unblocked by * a sys_vmctl() call in do_pagefaults if success. VM panics @@ -419,6 +420,8 @@ PRIVATE void sef_cb_signal_handler(int signo) if(missing_spares > 0) { pt_cycle(); /* pagetable code wants to be called */ } + + pt_clearmapcache(); } /*===========================================================================* -- 2.44.0