diff options
author | peter <peter@FreeBSD.org> | 2002-07-08 00:17:43 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 2002-07-08 00:17:43 +0000 |
commit | d67ae5f23f51adbdba955a259dd097c0d690715b (patch) | |
tree | c6cc831ed7c561cfc4c86386f0f5ffb423047cbd /sys/amd64 | |
parent | e06b8c244d38f8b7bff6834d9ba38b6dac296cf1 (diff) | |
download | FreeBSD-src-d67ae5f23f51adbdba955a259dd097c0d690715b.zip FreeBSD-src-d67ae5f23f51adbdba955a259dd097c0d690715b.tar.gz |
Fix a hideous TLB bug. pmap_unmapdev neglected to remove the device
mappings from the page tables, which were mapped with PG_G! We could
reuse the page table entry for another mapping (pmap_mapdev) but it
would never have cleared any remaining PG_G TLB entries.
Diffstat (limited to 'sys/amd64')
-rw-r--r-- | sys/amd64/amd64/pmap.c | 27 |
1 files changed, 23 insertions, 4 deletions
diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c index 9e3c6c3..a0c8ebe 100644 --- a/sys/amd64/amd64/pmap.c +++ b/sys/amd64/amd64/pmap.c @@ -3139,15 +3139,21 @@ pmap_mapdev(pa, size) panic("pmap_mapdev: Couldn't alloc kernel virtual memory"); pa = pa & PG_FRAME; - for (tmpva = va; size > 0;) { + for (tmpva = va; size > 0; ) { pte = vtopte(tmpva); *pte = pa | PG_RW | PG_V | pgeflag; +#ifdef SMP + cpu_invlpg((void *)tmpva); +#else + invltlb_1pg(tmpva); +#endif size -= PAGE_SIZE; tmpva += PAGE_SIZE; pa += PAGE_SIZE; } - invltlb(); - +#ifdef SMP + smp_invltlb(); +#endif return ((void *)(va + offset)); } @@ -3156,11 +3162,24 @@ pmap_unmapdev(va, size) vm_offset_t va; vm_size_t size; { - vm_offset_t base, offset; + vm_offset_t base, offset, tmpva; + pt_entry_t *pte; base = va & PG_FRAME; offset = va & PAGE_MASK; size = roundup(offset + size, PAGE_SIZE); + for (tmpva = base; tmpva < (base + size); tmpva += PAGE_SIZE) { + pte = vtopte(tmpva); + *pte = 0; +#ifdef SMP + cpu_invlpg((void *)tmpva); +#else + invltlb_1pg(tmpva); +#endif + } +#ifdef SMP + smp_invltlb(); +#endif kmem_free(kernel_map, base, size); } |