summaryrefslogtreecommitdiff
path: root/sys/arch
diff options
context:
space:
mode:
authorOwain Ainsworth <oga@cvs.openbsd.org>2011-07-03 20:22:08 +0000
committerOwain Ainsworth <oga@cvs.openbsd.org>2011-07-03 20:22:08 +0000
commit282fa76518aceafb0b63872c66ef044bb1e32887 (patch)
tree6c7d2a6197e03dacdfec6f2eaced7b1c7ab012cc /sys/arch
parentdc7a4eeb8d79ea3ec8ceab8730f271037fd1c858 (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.c69
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