diff options
author | Owain Ainsworth <oga@cvs.openbsd.org> | 2011-07-03 20:22:08 +0000 |
---|---|---|
committer | Owain Ainsworth <oga@cvs.openbsd.org> | 2011-07-03 20:22:08 +0000 |
commit | 282fa76518aceafb0b63872c66ef044bb1e32887 (patch) | |
tree | 6c7d2a6197e03dacdfec6f2eaced7b1c7ab012cc /sys/arch | |
parent | dc7a4eeb8d79ea3ec8ceab8730f271037fd1c858 (diff) |
Fix boot dump on bigmem machines.
Allocate a bouncebuffer at boot time and bounce all pages over
0xffffffff through it.
``looks right but not tested'' miod@, ok krw (who watched me test it on
his monster laptop.
Diffstat (limited to 'sys/arch')
-rw-r--r-- | sys/arch/amd64/amd64/machdep.c | 69 |
1 files changed, 64 insertions, 5 deletions
diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c index 20c53cad618..6baafb47ed2 100644 --- a/sys/arch/amd64/amd64/machdep.c +++ b/sys/arch/amd64/amd64/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.144 2011/06/26 22:39:59 deraadt Exp $ */ +/* $OpenBSD: machdep.c,v 1.145 2011/07/03 20:22:07 oga Exp $ */ /* $NetBSD: machdep.c,v 1.3 2003/05/07 22:58:18 fvdl Exp $ */ /*- @@ -165,6 +165,11 @@ u_int64_t dumpmem_high; extern int boothowto; int cpu_class; +paddr_t dumpmem_paddr; +vaddr_t dumpmem_vaddr; +psize_t dumpmem_sz; + + char *ssym = NULL; vaddr_t kern_end; @@ -790,6 +795,7 @@ cpu_dump(void) kcore_seg_t *segp; cpu_kcore_hdr_t *cpuhdrp; phys_ram_seg_t *memsegp; + caddr_t va; int i; dump = bdevsw[major(dumpdev)].d_dump; @@ -820,7 +826,17 @@ cpu_dump(void) memsegp[i].size = mem_clusters[i].size & ~PAGE_MASK; } - return (dump(dumpdev, dumplo, (caddr_t)buf, dbtob(1))); + /* + * If we have dump memory then assume the kernel stack is in high + * memory and bounce + */ + if (dumpmem_vaddr != 0) { + bcopy(buf, (char *)dumpmem_vaddr, sizeof(buf)); + va = (caddr_t)dumpmem_vaddr; + } else { + va = (caddr_t)buf; + } + return (dump(dumpdev, dumplo, va, dbtob(1))); } /* @@ -870,6 +886,7 @@ dumpsys(void) u_long totalbytesleft, bytes, i, n, memseg; u_long maddr; daddr64_t blkno; + void *va; int (*dump)(dev_t, daddr64_t, caddr_t, size_t); int error; @@ -925,9 +942,16 @@ dumpsys(void) n = bytes - i; if (n > BYTES_PER_DUMP) n = BYTES_PER_DUMP; + if (maddr > 0xffffffff) { + va = (void *)dumpmem_vaddr; + if (n > dumpmem_sz) + n = dumpmem_sz; + bcopy((void *)PMAP_DIRECT_MAP(maddr), va, n); + } else { + va = (void *)PMAP_DIRECT_MAP(maddr); + } - error = (*dump)(dumpdev, blkno, - (caddr_t)PMAP_DIRECT_MAP(maddr), n); + error = (*dump)(dumpdev, blkno, va, n); if (error) goto err; maddr += n; @@ -1414,6 +1438,42 @@ init_x86_64(paddr_t first_avail) } /* + * Steal some memory for a dump bouncebuffer if we have memory over + * the 32-bit barrier. + */ + if (avail_end > 0xffffffff) { + struct vm_physseg *vps = NULL; + psize_t sz = round_page(MAX(BYTES_PER_DUMP, dbtob(1))); + + /* XXX assumes segments are ordered */ + for (x = 0; x < vm_nphysseg; x++) { + vps = &vm_physmem[x]; + /* Find something between 16meg and 4gig */ + if (ptoa(vps->avail_end) <= 0xffffffff && + ptoa(vps->avail_start) >= 0xffffff) + break; + } + if (x == vm_nphysseg) + panic("init_x86_64: no memory between " + "0xffffff-0xffffffff"); + + /* Shrink so it'll fit in the segment. */ + if ((vps->avail_end - vps->avail_start) < atop(sz)) + sz = ptoa(vps->avail_end - vps->avail_start); + + vps->avail_end -= atop(sz); + vps->end -= atop(sz); + dumpmem_paddr = ptoa(vps->avail_end); + dumpmem_vaddr = PMAP_DIRECT_MAP(dumpmem_paddr); + dumpmem_sz = sz; + + /* Remove the last segment if it now has no pages. */ + if (vps->start == vps->end) { + for (vm_nphysseg--; x < vm_nphysseg; x++) + vm_physmem[x] = vm_physmem[x + 1]; + } + } + /* * XXXfvdl todo: acpi wakeup code. */ @@ -1491,7 +1551,6 @@ init_x86_64(paddr_t first_avail) kgdb_connect(1); } #endif - } #ifdef KGDB |