diff options
-rw-r--r-- | lib/Makefile | 3 | ||||
-rw-r--r-- | lib/libkvm/kvm.c | 63 | ||||
-rw-r--r-- | lib/libkvm/kvm_sparc.c | 362 | ||||
-rw-r--r-- | sys/arch/sparc/sparc/machdep.c | 75 | ||||
-rw-r--r-- | sys/arch/sparc/sparc/pmap.c | 144 |
5 files changed, 266 insertions, 381 deletions
diff --git a/lib/Makefile b/lib/Makefile index 600439850df..6656e5e1787 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.20 1997/03/25 17:06:42 rahnds Exp $ +# $OpenBSD: Makefile,v 1.21 1997/06/11 10:32:14 grr Exp $ # $NetBSD: Makefile,v 1.20.4.1 1996/06/14 17:22:38 cgd Exp $ SUBDIR= csu libarch libc libcom_err libcompat libcurses libedit \ @@ -12,6 +12,7 @@ SUBDIR= csu libarch libc libcom_err libcompat libcurses libedit \ (${MACHINE} == "atari") || \ (${MACHINE} == "powerpc") || \ (${MACHINE} == "mvme88k") || \ + (${MACHINE} == "sparc") || \ (${MACHINE} == "sun3") SUBDIR+= libkvm .else diff --git a/lib/libkvm/kvm.c b/lib/libkvm/kvm.c index 034e540e77e..319ef202c1f 100644 --- a/lib/libkvm/kvm.c +++ b/lib/libkvm/kvm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kvm.c,v 1.7 1997/06/02 17:06:53 dm Exp $ */ +/* $OpenBSD: kvm.c,v 1.8 1997/06/11 10:32:15 grr Exp $ */ /* $NetBSD: kvm.c,v 1.43 1996/05/05 04:31:59 gwr Exp $ */ /*- @@ -42,7 +42,7 @@ #if 0 static char sccsid[] = "@(#)kvm.c 8.2 (Berkeley) 2/13/94"; #else -static char *rcsid = "$OpenBSD: kvm.c,v 1.7 1997/06/02 17:06:53 dm Exp $"; +static char *rcsid = "$OpenBSD: kvm.c,v 1.8 1997/06/11 10:32:15 grr Exp $"; #endif #endif /* LIBC_SCCS and not lint */ @@ -75,7 +75,7 @@ static char *rcsid = "$OpenBSD: kvm.c,v 1.7 1997/06/02 17:06:53 dm Exp $"; #include "kvm_private.h" -static int kvm_dbopen __P((kvm_t *, const char *)); +static int kvm_dbopen __P((kvm_t *)); static int _kvm_get_header __P((kvm_t *)); static kvm_t *_kvm_open __P((kvm_t *, const char *, const char *, const char *, int, char *)); @@ -221,6 +221,7 @@ _kvm_open(kd, uf, mf, sf, flag, errout) char *errout; { struct stat st; + int ufgiven; kd->db = 0; kd->pmfd = -1; @@ -240,7 +241,8 @@ _kvm_open(kd, uf, mf, sf, flag, errout) kd->cpu_data = 0; kd->dump_off = 0; - if (uf == 0) + ufgiven = (uf != NULL); + if (!ufgiven) uf = _PATH_UNIX; else if (strlen(uf) >= MAXPATHLEN) { _kvm_err(kd, kd->program, "exec file name too long"); @@ -284,14 +286,13 @@ _kvm_open(kd, uf, mf, sf, flag, errout) goto failed; } /* - * Open kvm nlist database. We go ahead and do this - * here so that we don't have to hold on to the vmunix - * path name. Since a kvm application will surely do - * a kvm_nlist(), this probably won't be a wasted effort. - * If the database cannot be opened, open the namelist - * argument so we revert to slow nlist() calls. + * Open kvm nlist database. We only try to use + * the pre-built database if the namelist file name + * pointer is NULL. If the database cannot or should + * not be opened, open the namelist argument so we + * revert to slow nlist() calls. */ - if (kvm_dbopen(kd, uf) < 0 && + if ((ufgiven || kvm_dbopen(kd) < 0) && (kd->nlfd = open(uf, O_RDONLY, 0)) < 0) { _kvm_syserr(kd, kd->program, "%s", uf); goto failed; @@ -324,7 +325,7 @@ failed: * Copy out the error if doing sane error semantics. */ if (errout != 0) - strcpy(errout, kd->errbuf); + (void)strncpy(errout, kd->errbuf, _POSIX2_LINE_MAX - 1); (void)kvm_close(kd); return (0); } @@ -471,10 +472,11 @@ off_t dump_off; sz = Read(kd, kd->pmfd, &cpu_hdr, sizeof(cpu_hdr)); if (sz != sizeof(cpu_hdr)) return (-1); - if (CORE_GETMAGIC(cpu_hdr) != KCORE_MAGIC) - return (-1); - if (CORE_GETMID(cpu_hdr) != MID_MACHINE) - return (-1); + if ((CORE_GETMAGIC(cpu_hdr) != KCORE_MAGIC) + || (CORE_GETMID(cpu_hdr) != MID_MACHINE)) { + _kvm_err(kd, 0, "invalid magic in cpu_hdr"); + return (0); + } hdr_size = ALIGN(sizeof(cpu_hdr)); /* @@ -513,9 +515,9 @@ off_t dump_off; /* * Now that we have a valid header, enable translations. */ - _kvm_initvtop(kd); - - return(hdr_size); + if (_kvm_initvtop(kd) == 0) + /* Success */ + return (hdr_size); fail: if (kd->kcore_hdr != NULL) { @@ -630,7 +632,7 @@ kvm_openfiles(uf, mf, sf, flag, errout) register kvm_t *kd; if ((kd = malloc(sizeof(*kd))) == NULL) { - (void)strcpy(errout, strerror(errno)); + (void)strncpy(errout, strerror(errno), _POSIX2_LINE_MAX - 1); return (0); } kd->program = 0; @@ -700,23 +702,16 @@ kvm_close(kd) * Only called for live kernels. Return 0 on success, -1 on failure. */ static int -kvm_dbopen(kd, uf) +kvm_dbopen(kd) kvm_t *kd; - const char *uf; { - char *cp; DBT rec; int dbversionlen; struct nlist nitem; char dbversion[_POSIX2_LINE_MAX]; char kversion[_POSIX2_LINE_MAX]; - char dbname[MAXPATHLEN]; - - if ((cp = strrchr(uf, '/')) != 0) - uf = cp + 1; - (void)snprintf(dbname, sizeof(dbname), "%skvm_%s.db", _PATH_VARDB, uf); - kd->db = dbopen(dbname, O_RDONLY, 0, DB_HASH, NULL); + kd->db = dbopen(_PATH_KVMDB, O_RDONLY, 0, DB_HASH, NULL); if (kd->db == 0) return (-1); /* @@ -765,14 +760,18 @@ kvm_nlist(kd, nl) struct nlist *nl; { register struct nlist *p; - register int nvalid; + register int nvalid, rv; /* * If we can't use the data base, revert to the * slow library call. */ - if (kd->db == 0) - return (__fdnlist(kd->nlfd, nl)); + if (kd->db == 0) { + rv = __fdnlist(kd->nlfd, nl); + if (rv == -1) + _kvm_err(kd, 0, "bad namelist"); + return (rv); + } /* * We can use the kvm data base. Go through each nlist entry diff --git a/lib/libkvm/kvm_sparc.c b/lib/libkvm/kvm_sparc.c index 7dc5ffa37d2..92ed157a9b3 100644 --- a/lib/libkvm/kvm_sparc.c +++ b/lib/libkvm/kvm_sparc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kvm_sparc.c,v 1.3 1997/02/26 16:46:34 niklas Exp $ */ +/* $OpenBSD: kvm_sparc.c,v 1.4 1997/06/11 10:32:16 grr Exp $ */ /* $NetBSD: kvm_sparc.c,v 1.9 1996/04/01 19:23:03 cgd Exp $ */ /*- @@ -42,7 +42,7 @@ #if 0 static char sccsid[] = "@(#)kvm_sparc.c 8.1 (Berkeley) 6/4/93"; #else -static char *rcsid = "$OpenBSD: kvm_sparc.c,v 1.3 1997/02/26 16:46:34 niklas Exp $"; +static char *rcsid = "$OpenBSD: kvm_sparc.c,v 1.4 1997/06/11 10:32:16 grr Exp $"; #endif #endif /* LIBC_SCCS and not lint */ @@ -55,8 +55,8 @@ static char *rcsid = "$OpenBSD: kvm_sparc.c,v 1.3 1997/02/26 16:46:34 niklas Exp #include <sys/user.h> #include <sys/proc.h> #include <sys/stat.h> -#include <sys/sysctl.h> -#include <sys/device.h> +#include <sys/core.h> +#include <sys/kcore.h> #include <unistd.h> #include <nlist.h> #include <kvm.h> @@ -64,100 +64,62 @@ static char *rcsid = "$OpenBSD: kvm_sparc.c,v 1.3 1997/02/26 16:46:34 niklas Exp #include <vm/vm.h> #include <vm/vm_param.h> #include <machine/autoconf.h> +#include <machine/kcore.h> #include <limits.h> #include <db.h> #include "kvm_private.h" -#define MA_SIZE 32 /* XXX */ -struct vmstate { - struct { - int x_seginval; /* [sun4/sun4c] only */ - int x_npmemarr; - struct memarr x_pmemarr[MA_SIZE]; - struct segmap x_segmap_store[NKREG*NSEGRG]; - } x; -#define seginval x.x_seginval -#define npmemarr x.x_npmemarr -#define pmemarr x.x_pmemarr -#define segmap_store x.x_segmap_store - int *pte; /* [sun4/sun4c] only */ -}; -#define NPMEG(vm) ((vm)->seginval+1) static int cputyp = -1; - -static int pgshift, nptesg; +static int pgshift; +static int nptesg; /* [sun4/sun4c] only */ #define VA_VPG(va) ((cputyp == CPU_SUN4C || cputyp == CPU_SUN4M) \ ? VA_SUN4C_VPG(va) \ : VA_SUN4_VPG(va)) -static int _kvm_mustinit __P((kvm_t *)); - -#if 0 -static int -getcputyp() -{ - int mib[2]; - size_t size; +#define VA_OFF(va) (va & (kd->nbpg - 1)) - mib[0] = CTL_HW; - mib[1] = HW_CLASS; - size = sizeof cputyp; - if (sysctl(mib, 2, &cputyp, &size, NULL, 0) == -1) - return (-1); -} -#endif -static int -_kvm_mustinit(kd) +void +_kvm_freevtop(kd) kvm_t *kd; { -static struct nlist nlist[2] = { -# define X_CPUTYP 0 - { "_cputyp" }, - { NULL }, - }; - off_t foff; - - if (cputyp != -1) - return 0; - - for (pgshift = 12; (1 << pgshift) != kd->nbpg; pgshift++) - ; - nptesg = NBPSG / kd->nbpg; - - if (kvm_nlist(kd, nlist) != 0) { - _kvm_err(kd, kd->program, "cannot find `cputyp' symbol"); - return (-1); - } - /* Assume kernel mappings are all within first memory bank. */ - foff = nlist[X_CPUTYP].n_value - KERNBASE; - if (lseek(kd->pmfd, foff, 0) == -1 || - read(kd->pmfd, &cputyp, sizeof(cputyp)) < 0) { - _kvm_err(kd, kd->program, "cannot read `cputyp"); - return (-1); + if (kd->vmst != 0) { + _kvm_err(kd, kd->program, "_kvm_freevtop: internal error"); + kd->vmst = 0; } - if (cputyp != CPU_SUN4 && - cputyp != CPU_SUN4C && - cputyp != CPU_SUN4M) - return (-1); - - return (0); } -void -_kvm_freevtop(kd) +/* + * Prepare for translation of kernel virtual addresses into offsets + * into crash dump files. We use the MMU specific goop written at the + * front of the crash dump by pmap_dumpmmu(). + */ +int +_kvm_initvtop(kd) kvm_t *kd; { - if (kd->vmst != 0) { - if (kd->vmst->pte != 0) - free(kd->vmst->pte); - free(kd->vmst); - kd->vmst = 0; + cpu_kcore_hdr_t *cpup = kd->cpu_data; + + switch (cputyp = cpup->cputype) { + case CPU_SUN4: + kd->nbpg = 8196; + pgshift = 13; + break; + case CPU_SUN4C: + case CPU_SUN4M: + kd->nbpg = 4096; + pgshift = 12; + break; + default: + _kvm_err(kd, kd->program, "Unsupported CPU type"); + return (-1); } + nptesg = NBPSG / kd->nbpg; + return (0); } /* @@ -172,7 +134,8 @@ _kvm_kvatop(kd, va, pa) u_long va; u_long *pa; { - if (_kvm_mustinit(kd) != 0) + if (cputyp == -1) + if (_kvm_initvtop(kd) != 0) return (-1); return ((cputyp == CPU_SUN4M) @@ -181,185 +144,50 @@ _kvm_kvatop(kd, va, pa) } /* - * Prepare for translation of kernel virtual addresses into offsets - * into crash dump files. We use the MMU specific goop written at the - * and of crash dump by pmap_dumpmmu(). - * (note: sun4/sun4c 2-level MMU specific) - */ -int -_kvm_initvtop(kd) - kvm_t *kd; -{ - if (_kvm_mustinit(kd) != 0) - return (-1); - - return ((cputyp == CPU_SUN4M) - ? _kvm_initvtop4m(kd) - : _kvm_initvtop44c(kd)); -} - -#define VA_OFF(va) (va & (kd->nbpg - 1)) - - -/* - * We use the MMU specific goop written at the end of crash dump - * by pmap_dumpmmu(). * (note: sun4 3-level MMU not yet supported) */ int -_kvm_initvtop44c(kd) - kvm_t *kd; -{ - register struct vmstate *vm; - register int i; - off_t foff; - struct stat st; - - if ((vm = kd->vmst) == 0) { - kd->vmst = vm = (struct vmstate *)_kvm_malloc(kd, sizeof(*vm)); - if (vm == 0) - return (-1); - } - - if (fstat(kd->pmfd, &st) < 0) - return (-1); - /* - * Read segment table. - */ - - foff = st.st_size - roundup(sizeof(vm->x), kd->nbpg); - errno = 0; - if (lseek(kd->pmfd, (off_t)foff, 0) == -1 && errno != 0 || - read(kd->pmfd, (char *)&vm->x, sizeof(vm->x)) < 0) { - _kvm_err(kd, kd->program, "cannot read segment map"); - return (-1); - } - - vm->pte = (int *)_kvm_malloc(kd, NPMEG(vm) * nptesg * sizeof(int)); - if (vm->pte == 0) { - free(kd->vmst); - kd->vmst = 0; - return (-1); - } - - /* - * Read PMEGs. - */ - foff = st.st_size - roundup(sizeof(vm->x), kd->nbpg) - - roundup(NPMEG(vm) * nptesg * sizeof(int), kd->nbpg); - - errno = 0; - if (lseek(kd->pmfd, foff, 0) == -1 && errno != 0 || - read(kd->pmfd, (char *)vm->pte, NPMEG(vm) * nptesg * sizeof(int)) < 0) { - _kvm_err(kd, kd->program, "cannot read PMEG table"); - return (-1); - } - - return (0); -} - -int _kvm_kvatop44c(kd, va, pa) kvm_t *kd; u_long va; u_long *pa; { - register int vr, vs, pte, off, nmem; - register struct vmstate *vm = kd->vmst; + register int vr, vs, pte; + cpu_kcore_hdr_t *cpup = kd->cpu_data; struct regmap *rp; struct segmap *sp; - struct memarr *mp; + int *ptes; if (va < KERNBASE) goto err; + /* + * Layout of CPU segment: + * cpu_kcore_hdr_t; + * [alignment] + * phys_ram_seg_t[cpup->nmemseg]; + * ptes[cpup->npmegs]; + */ + ptes = (int *)((int)kd->cpu_data + cpup->pmegoffset); + vr = VA_VREG(va); vs = VA_VSEG(va); - sp = &vm->segmap_store[(vr-NUREG)*NSEGRG + vs]; + sp = &cpup->segmap_store[(vr-NUREG)*NSEGRG + vs]; if (sp->sg_npte == 0) goto err; - if (sp->sg_pmeg == vm->seginval) + if (sp->sg_pmeg == cpup->npmeg - 1) /* =seginval */ goto err; - pte = vm->pte[sp->sg_pmeg * nptesg + VA_VPG(va)]; + pte = ptes[sp->sg_pmeg * nptesg + VA_VPG(va)]; if ((pte & PG_V) != 0) { - register long p, dumpoff = 0; + register long p, off = VA_OFF(va); - off = VA_OFF(va); p = (pte & PG_PFNUM) << pgshift; - /* Translate (sparse) pfnum to (packed) dump offset */ - for (mp = vm->pmemarr, nmem = vm->npmemarr; --nmem >= 0; mp++) { - if (mp->addr <= p && p < mp->addr + mp->len) - break; - dumpoff += mp->len; - } - if (nmem < 0) - goto err; - *pa = (dumpoff + p - mp->addr) | off; + *pa = p + off; return (kd->nbpg - off); } err: - _kvm_err(kd, 0, "invalid address (%lx)", va); - return (0); -} - -/* - * Prepare for translation of kernel virtual addresses into offsets - * into crash dump files. Since the sun4m pagetables are all in memory, - * we use nlist to bootstrap the translation tables. This assumes that - * the kernel mappings all reside in the first physical memory bank. - */ -int -_kvm_initvtop4m(kd) - kvm_t *kd; -{ - register int i; - register off_t foff; - register struct vmstate *vm; - struct stat st; -static struct nlist nlist[4] = { -# define X_KSEGSTORE 0 - { "_kernel_segmap_store" }, -# define X_PMEMARR 1 - { "_pmemarr" }, -# define X_NPMEMARR 2 - { "_npmemarr" }, - { NULL }, - }; - - if ((vm = kd->vmst) == 0) { - kd->vmst = vm = (struct vmstate *)_kvm_malloc(kd, sizeof(*vm)); - if (vm == 0) - return (-1); - } - - if (kvm_nlist(kd, nlist) != 0) { - _kvm_err(kd, kd->program, "cannot read symbols"); - return (-1); - } - - /* Assume kernel mappings are all within first memory bank. */ - foff = nlist[X_KSEGSTORE].n_value - KERNBASE; - if (lseek(kd->pmfd, foff, 0) == -1 || - read(kd->pmfd, vm->segmap_store, sizeof(vm->segmap_store)) < 0) { - _kvm_err(kd, kd->program, "cannot read segment map"); - return (-1); - } - - foff = nlist[X_PMEMARR].n_value - KERNBASE; - if (lseek(kd->pmfd, foff, 0) == -1 || - read(kd->pmfd, vm->pmemarr, sizeof(vm->pmemarr)) < 0) { - _kvm_err(kd, kd->program, "cannot read pmemarr"); - return (-1); - } - - foff = nlist[X_NPMEMARR].n_value - KERNBASE; - if (lseek(kd->pmfd, foff, 0) == -1 || - read(kd->pmfd, &vm->npmemarr, sizeof(vm->npmemarr)) < 0) { - _kvm_err(kd, kd->program, "cannot read npmemarr"); - return (-1); - } - + _kvm_err(kd, 0, "invalid address (%x)", va); return (0); } @@ -369,49 +197,85 @@ _kvm_kvatop4m(kd, va, pa) u_long va; u_long *pa; { - register struct vmstate *vm = kd->vmst; - register int vr, vs, nmem, off; + cpu_kcore_hdr_t *cpup = kd->cpu_data; + register int vr, vs; int pte; off_t foff; struct regmap *rp; struct segmap *sp; - struct memarr *mp; if (va < KERNBASE) goto err; + /* + * Layout of CPU segment: + * cpu_kcore_hdr_t; + * [alignment] + * phys_ram_seg_t[cpup->nmemseg]; + */ + vr = VA_VREG(va); vs = VA_VSEG(va); - sp = &vm->segmap_store[(vr-NUREG)*NSEGRG + vs]; + sp = &cpup->segmap_store[(vr-NUREG)*NSEGRG + vs]; if (sp->sg_npte == 0) goto err; - /* Assume kernel mappings are all within first memory bank. */ - foff = (long)&sp->sg_pte[VA_VPG(va)] - KERNBASE; + /* XXX - assume page tables in initial kernel DATA or BSS. */ + foff = _kvm_pa2off(kd, (u_long)&sp->sg_pte[VA_VPG(va)] - KERNBASE); + if (foff == (off_t)-1) + return (0); + if (lseek(kd->pmfd, foff, 0) == -1 || read(kd->pmfd, (void *)&pte, sizeof(pte)) < 0) { - _kvm_err(kd, kd->program, "cannot read pte"); - goto err; + _kvm_err(kd, kd->program, "cannot read pte for %x", va); + return (0); } if ((pte & SRMMU_TETYPE) == SRMMU_TEPTE) { - register long p, dumpoff = 0; + register long p, off = VA_OFF(va); - off = VA_OFF(va); p = (pte & SRMMU_PPNMASK) << SRMMU_PPNPASHIFT; - /* Translate (sparse) pfnum to (packed) dump offset */ - for (mp = vm->pmemarr, nmem = vm->npmemarr; --nmem >= 0; mp++) { - if (mp->addr <= p && p < mp->addr + mp->len) - break; - dumpoff += mp->len; - } - if (nmem < 0) - goto err; - *pa = (dumpoff + p - mp->addr) | off; + *pa = p + off; return (kd->nbpg - off); } err: - _kvm_err(kd, 0, "invalid address (%lx)", va); + _kvm_err(kd, 0, "invalid address (%x)", va); return (0); } + +/* + * Translate a physical address to a file-offset in the crash-dump. + */ +off_t +_kvm_pa2off(kd, pa) + kvm_t *kd; + u_long pa; +{ + cpu_kcore_hdr_t *cpup = kd->cpu_data; + phys_ram_seg_t *mp; + off_t off; + int nmem; + + /* + * Layout of CPU segment: + * cpu_kcore_hdr_t; + * [alignment] + * phys_ram_seg_t[cpup->nmemseg]; + */ + mp = (phys_ram_seg_t *)((int)kd->cpu_data + cpup->memsegoffset); + off = 0; + + /* Translate (sparse) pfnum to (packed) dump offset */ + for (nmem = cpup->nmemseg; --nmem >= 0; mp++) { + if (mp->start <= pa && pa < mp->start + mp->size) + break; + off += mp->size; + } + if (nmem < 0) { + _kvm_err(kd, 0, "invalid address (%x)", pa); + return (-1); + } + + return (kd->dump_off + off + pa - mp->start); +} diff --git a/sys/arch/sparc/sparc/machdep.c b/sys/arch/sparc/sparc/machdep.c index e305fcbd69a..081e5be5204 100644 --- a/sys/arch/sparc/sparc/machdep.c +++ b/sys/arch/sparc/sparc/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.21 1997/03/26 22:14:41 niklas Exp $ */ +/* $OpenBSD: machdep.c,v 1.22 1997/06/11 10:32:11 grr Exp $ */ /* $NetBSD: machdep.c,v 1.64 1996/05/19 04:12:56 mrg Exp $ */ /* @@ -703,6 +703,7 @@ boot(howto) /*NOTREACHED*/ } +/* XXX - dumpmag not eplicitly used, savecore may search for it to get here */ u_long dumpmag = 0x8fca0101; /* magic number for savecore */ int dumpsize = 0; /* also for savecore */ long dumplo = 0; @@ -710,46 +711,39 @@ long dumplo = 0; void dumpconf() { - register int nblks, nmem; - register struct memarr *mp; - extern struct memarr pmemarr[]; /* XXX */ - extern int npmemarr; /* XXX */ + register int nblks, dumpblks; - dumpsize = 0; - for (mp = pmemarr, nmem = npmemarr; --nmem >= 0; mp++) - dumpsize += btoc(mp->len); + if (dumpdev == NODEV || bdevsw[major(dumpdev)].d_psize == 0) + /* No usable dump device */ + return; - /* - * savecore views the image in units of pages (i.e., dumpsize is in - * pages) so we round the two mmu entities into page-sized chunks. - * The PMEGs (32kB) and the segment table (512 bytes plus padding) - * are appending to the end of the crash dump. - */ - dumpsize += pmap_dumpsize(); - if (dumpdev != NODEV && bdevsw[major(dumpdev)].d_psize) { nblks = (*bdevsw[major(dumpdev)].d_psize)(dumpdev); + + dumpblks = ctod(physmem) + ctod(pmap_dumpsize()); + if (dumpblks > (nblks - ctod(1))) /* - * Don't dump on the first CLBYTES (why CLBYTES?) - * in case the dump device includes a disk label. + * dump size is too big for the partition. + * Note, we safeguard a click at the front for a + * possible disk label. */ - if (dumplo < btodb(CLBYTES)) - dumplo = btodb(CLBYTES); + return; + + /* Put the dump at the end of the partition */ + dumplo = nblks - dumpblks; /* - * If dumpsize is too big for the partition, truncate it. - * Otherwise, put the dump at the end of the partition - * by making dumplo as large as possible. - */ - if (dumpsize > btoc(dbtob(nblks - dumplo))) - dumpsize = btoc(dbtob(nblks - dumplo)); - else if (dumplo + ctod(dumpsize) > nblks) - dumplo = nblks - ctod(dumpsize); - } + * savecore(8) expects dumpsize to be the number of pages + * of actual core dumped (i.e. excluding the MMU stuff). + */ + dumpsize = physmem; } #define BYTES_PER_DUMP (32 * 1024) /* must be a multiple of pagesize */ static vm_offset_t dumpspace; +/* + * Allocate the dump i/o buffer area during kernel memory allocation + */ caddr_t reserve_dumppages(p) caddr_t p; @@ -766,7 +760,7 @@ void dumpsys() { register int psize; - register daddr_t blkno; + daddr_t blkno; register int (*dump) __P((dev_t, daddr_t, caddr_t, size_t)); int error = 0; register struct memarr *mp; @@ -787,9 +781,10 @@ dumpsys() */ if (dumpsize == 0) dumpconf(); - if (dumplo < 0) + if (dumplo <= 0) return; - printf("\ndumping to dev %x, offset %ld\n", dumpdev, dumplo); + printf("\ndumping to dev(%d,%d), at offset %ld blocks\n", + major(dumpdev), minor(dumpdev), dumplo); psize = (*bdevsw[major(dumpdev)].d_psize)(dumpdev); printf("dump "); @@ -800,10 +795,16 @@ dumpsys() blkno = dumplo; dump = bdevsw[major(dumpdev)].d_dump; - for (mp = pmemarr, nmem = npmemarr; --nmem >= 0; mp++) { + printf("mmu "); + error = pmap_dumpmmu(dump, blkno); + blkno += ctod(pmap_dumpsize()); + + printf("memory "); + for (mp = pmemarr, nmem = npmemarr; --nmem >= 0 && error == 0; mp++) { register unsigned i = 0, n; register maddr = mp->addr; + /* XXX - what's so special about PA 0 that we can't dump it? */ if (maddr == 0) { /* Skip first page at physical address 0 */ maddr += NBPG; @@ -811,13 +812,15 @@ dumpsys() blkno += btodb(NBPG); } + printf("@%p:",maddr); + for (; i < mp->len; i += n) { n = mp->len - i; if (n > BYTES_PER_DUMP) n = BYTES_PER_DUMP; - /* print out how many MBs we have dumped */ - if (i && (i % (1024*1024)) == 0) + /* print out which MBs we are dumping */ + if (i % (1024*1024) <= NBPG) printf("%d ", i / (1024*1024)); (void) pmap_map(dumpspace, maddr, maddr + n, @@ -831,8 +834,6 @@ dumpsys() blkno += btodb(n); } } - if (!error) - error = pmap_dumpmmu(dump, blkno); switch (error) { diff --git a/sys/arch/sparc/sparc/pmap.c b/sys/arch/sparc/sparc/pmap.c index 07e1bc3be80..f5ec4ccc09f 100644 --- a/sys/arch/sparc/sparc/pmap.c +++ b/sys/arch/sparc/sparc/pmap.c @@ -62,6 +62,9 @@ #include <sys/proc.h> #include <sys/queue.h> #include <sys/malloc.h> +#include <sys/kcore.h> +#include <sys/core.h> +#include <sys/exec_aout.h> #include <vm/vm.h> #include <vm/vm_kern.h> @@ -73,6 +76,7 @@ #include <machine/oldmon.h> #include <machine/cpu.h> #include <machine/ctlreg.h> +#include <machine/kcore.h> #include <sparc/sparc/asm.h> #include <sparc/sparc/cache.h> @@ -6544,38 +6548,93 @@ pm_check_k(s, pm) /* Note: not as extensive as pm_check_u. */ int pmap_dumpsize() { - if (CPU_ISSUN4M) /* No need to dump on 4m; its in-core. */ - return (0); + long sz; + + sz = ALIGN(sizeof(kcore_seg_t)) + ALIGN(sizeof(cpu_kcore_hdr_t)); + sz += npmemarr * sizeof(phys_ram_seg_t); if (CPU_ISSUN4OR4C) - return btoc(((seginval + 1) * NPTESG * sizeof(int)) + - sizeof(seginval) + - sizeof(pmemarr) + - sizeof(kernel_segmap_store)); - return 0; + sz += (seginval + 1) * NPTESG * sizeof(int); + + return (btoc(sz)); } /* - * Write the mmu contents to the dump device. - * This gets appended to the end of a crash dump since - * there is no in-core copy of kernel memory mappings on a 4/4c machine. + * Write the dump header and memory mapping information at the front + * of the dumpfile to make life easy for savecore and libkvm. Also + * dump the MMU contents for Sun 4/4c systems since they don't have + * a separate incore copy of the kernel memory mappings. */ int pmap_dumpmmu(dump, blkno) register daddr_t blkno; register int (*dump) __P((dev_t, daddr_t, caddr_t, size_t)); { -#if defined(SUN4C) || defined(SUN4) - register int pmeg; - register int i; - register int *pte, *ptend; + kcore_seg_t *ksegp; + cpu_kcore_hdr_t *kcpup; + phys_ram_seg_t memseg; register int error = 0; - register int *kp; + register int i, memsegoffset, pmegoffset; int buffer[dbtob(1) / sizeof(int)]; -#endif + int *bp, *ep; +#if defined(SUN4C) || defined(SUN4) + register int pmeg; +#endif + +#define EXPEDITE(p,n) do { \ + int *sp = (int *)(p); \ + int sz = (n); \ + while (sz > 0) { \ + *bp++ = *sp++; \ + if (bp >= ep) { \ + error = (*dump)(dumpdev, blkno, \ + (caddr_t)buffer, dbtob(1)); \ + if (error != 0) \ + return (error); \ + ++blkno; \ + bp = buffer; \ + } \ + sz -= sizeof *sp; \ + } \ +} while (0) - if (CPU_ISSUN4M) /* No need to dump on 4m; its in-core. */ - return (0); + setcontext(0); + + /* Setup bookkeeping pointers */ + bp = buffer; + ep = &buffer[sizeof(buffer) / sizeof(buffer[0])]; + + /* Fill in MI segment header */ + ksegp = (kcore_seg_t *)bp; + CORE_SETMAGIC(*ksegp, KCORE_MAGIC, MID_MACHINE, CORE_CPU); + ksegp->c_size = ctob(pmap_dumpsize()) - ALIGN(sizeof(kcore_seg_t)); + + /* Fill in MD segment header (interpreted by MD part of libkvm) */ + kcpup = (cpu_kcore_hdr_t *)((int)bp + ALIGN(sizeof(kcore_seg_t))); + kcpup->cputype = cputyp; + kcpup->nmemseg = npmemarr; + kcpup->memsegoffset = memsegoffset = ALIGN(sizeof(cpu_kcore_hdr_t)); + kcpup->npmeg = (CPU_ISSUN4OR4C) ? seginval + 1 : 0; + kcpup->pmegoffset = pmegoffset = + memsegoffset + npmemarr * sizeof(phys_ram_seg_t); + + /* Note: we have assumed everything fits in buffer[] so far... */ + bp = (int *)&kcpup->segmap_store; + EXPEDITE(&kernel_segmap_store, sizeof(kernel_segmap_store)); + + /* Align storage for upcoming quad-aligned segment array */ + while (bp != (int *)ALIGN(bp)) { + int dummy = 0; + EXPEDITE(&dummy, sizeof dummy); + } + for (i = 0; i < npmemarr; i++) { + memseg.start = pmemarr[i].addr; + memseg.size = pmemarr[i].len; + EXPEDITE(&memseg, sizeof(phys_ram_seg_t)); + } + + if (CPU_ISSUN4M) + goto out; #if defined(SUN4C) || defined(SUN4) /* @@ -6588,67 +6647,28 @@ pmap_dumpmmu(dump, blkno) * address argument to getpte(). */ - setcontext(0); - /* * Go through the pmegs and dump each one. */ - pte = buffer; - ptend = &buffer[sizeof(buffer) / sizeof(buffer[0])]; for (pmeg = 0; pmeg <= seginval; ++pmeg) { register int va = 0; setsegmap(va, pmeg); i = NPTESG; do { - *pte++ = getpte4(va); - if (pte >= ptend) { - /* - * Note that we'll dump the last block - * the last time through the loops because - * all the PMEGs occupy 32KB which is - * a multiple of the block size. - */ - error = (*dump)(dumpdev, blkno, - (caddr_t)buffer, - dbtob(1)); - if (error != 0) - return (error); - ++blkno; - pte = buffer; - } + int pte = getpte4(va); + EXPEDITE(&pte, sizeof(pte)); va += NBPG; } while (--i > 0); } setsegmap(0, seginval); +#endif - /* - * Next, dump # of pmegs, the physical memory table and the - * kernel's segment map. - */ - pte = buffer; - *pte++ = seginval; - *pte++ = npmemarr; - bcopy((char *)pmemarr, (char *)pte, sizeof(pmemarr)); - pte = (int *)((int)pte + sizeof(pmemarr)); - kp = (int *)kernel_segmap_store; - i = sizeof(kernel_segmap_store) / sizeof(int); - do { - *pte++ = *kp++; - if (pte >= ptend) { - error = (*dump)(dumpdev, blkno, (caddr_t)buffer, - dbtob(1)); - if (error != 0) - return (error); - ++blkno; - pte = buffer; - } - } while (--i > 0); - if (pte != buffer) +out: + if (bp != buffer) error = (*dump)(dumpdev, blkno++, (caddr_t)buffer, dbtob(1)); return (error); -#endif } #ifdef EXTREME_DEBUG |