Implement new crash dump format. Mostly taken from hp300, extended to

support multiple physical RAM segments by me.  Garbage collect functions
obsoleted by this change.
This commit is contained in:
scottr 1997-04-23 19:15:16 +00:00
parent 1cf91041df
commit c1c244e0a3
2 changed files with 297 additions and 177 deletions

View File

@ -0,0 +1,8 @@
/* $NetBSD: kcore.h,v 1.1 1997/04/23 19:15:16 scottr Exp $ */
#ifndef _MACHINE_KCORE_H_
#define _MACHINE_KCORE_H_
#include <m68k/kcore.h>
#endif

View File

@ -1,4 +1,4 @@
/* $NetBSD: machdep.c,v 1.145 1997/04/16 07:16:49 scottr Exp $ */ /* $NetBSD: machdep.c,v 1.146 1997/04/23 19:15:21 scottr Exp $ */
/* /*
* Copyright (c) 1996 Jason R. Thorpe. All rights reserved. * Copyright (c) 1996 Jason R. Thorpe. All rights reserved.
@ -87,6 +87,8 @@
#include <sys/proc.h> #include <sys/proc.h>
#include <sys/buf.h> #include <sys/buf.h>
#include <sys/exec.h> #include <sys/exec.h>
#include <sys/core.h>
#include <sys/kcore.h>
#include <sys/vnode.h> #include <sys/vnode.h>
#include <sys/reboot.h> #include <sys/reboot.h>
#include <sys/conf.h> #include <sys/conf.h>
@ -121,6 +123,7 @@
#include <machine/psl.h> #include <machine/psl.h>
#include <machine/pte.h> #include <machine/pte.h>
#include <machine/bus.h> #include <machine/bus.h>
#include <machine/kcore.h> /* XXX should be pulled in by sys/kcore.h */
#include <net/netisr.h> #include <net/netisr.h>
#define MAXMEM 64*1024*CLSIZE /* XXX - from cmap.h */ #define MAXMEM 64*1024*CLSIZE /* XXX - from cmap.h */
@ -219,10 +222,20 @@ static iomem_malloc_safe;
static void identifycpu __P((void)); static void identifycpu __P((void));
static u_long get_physical __P((u_int, u_long *)); static u_long get_physical __P((u_int, u_long *));
void dumpsys __P((void));
int bus_mem_add_mapping __P((bus_addr_t, bus_size_t, int cpu_dumpsize __P((void));
int, bus_space_handle_t *)); int cpu_dump __P((int (*)(dev_t, daddr_t, caddr_t, size_t), daddr_t *));
void cpu_init_kcore_hdr __P((void));
void dumpsys __P((void));
int bus_mem_add_mapping __P((bus_addr_t, bus_size_t,
int, bus_space_handle_t *));
/*
* Machine-dependent crash dump header info.
*/
cpu_kcore_hdr_t cpu_kcore_hdr;
/* /*
* Console initialization: called early on from main, * Console initialization: called early on from main,
@ -269,6 +282,11 @@ cpu_startup(void)
vm_size_t size = 0; /* To avoid compiler warning */ vm_size_t size = 0; /* To avoid compiler warning */
int delay; int delay;
/*
* Initialize the kernel crash dump header.
*/
cpu_init_kcore_hdr();
/* /*
* Initialize error message buffer (at end of core). * Initialize error message buffer (at end of core).
* high[numranges-1] was decremented in pmap_bootstrap. * high[numranges-1] was decremented in pmap_bootstrap.
@ -537,10 +555,8 @@ cpu_reboot(howto, bootstr)
splhigh(); splhigh();
/* If rebooting and a dump is requested, do it. */ /* If rebooting and a dump is requested, do it. */
if (howto & RB_DUMP) { if (howto & RB_DUMP)
savectx(&dumppcb); /* XXX this goes away soon */
dumpsys(); dumpsys();
}
haltsys: haltsys:
/* Run any shutdown hooks. */ /* Run any shutdown hooks. */
@ -566,17 +582,157 @@ cpu_reboot(howto, bootstr)
* Map ROM where the MacOS likes it, so we can reboot, * Map ROM where the MacOS likes it, so we can reboot,
* hopefully. * hopefully.
*/ */
pmap_map(MacOSROMBase, MacOSROMBase, pmap_map(MacOSROMBase, MacOSROMBase, MacOSROMBase + 4 * 1024 * 1024,
MacOSROMBase + 4 * 1024 * 1024, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE);
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE);
printf("rebooting...\n"); printf("rebooting...\n");
DELAY(1000000); DELAY(1000000);
doboot(); doboot();
/* NOTREACHED */ /* NOTREACHED */
} }
/*
* Initialize the kernel crash dump header.
*/
void
cpu_init_kcore_hdr()
{
cpu_kcore_hdr_t *h = &cpu_kcore_hdr;
struct m68k_kcore_hdr *m = &h->un._m68k;
int i, j, k;
extern char end[];
bzero(&cpu_kcore_hdr, sizeof(cpu_kcore_hdr));
/*
* Initialize the `dispatcher' portion of the header.
*/
strcpy(h->name, machine);
h->page_size = NBPG;
h->kernbase = KERNBASE;
/*
* Fill in information about our MMU configuration.
*/
m->mmutype = mmutype;
m->sg_v = SG_V;
m->sg_frame = SG_FRAME;
m->sg_ishift = SG_ISHIFT;
m->sg_pmask = SG_PMASK;
m->sg40_shift1 = SG4_SHIFT1;
m->sg40_mask2 = SG4_MASK2;
m->sg40_shift2 = SG4_SHIFT2;
m->sg40_mask3 = SG4_MASK3;
m->sg40_shift3 = SG4_SHIFT3;
m->sg40_addr1 = SG4_ADDR1;
m->sg40_addr2 = SG4_ADDR2;
m->pg_v = PG_V;
m->pg_frame = PG_FRAME;
/*
* Initialize pointer to kernel segment table.
*/
m->sysseg_pa = (u_int32_t)(pmap_kernel()->pm_stpa);
/*
* Initialize relocation value such that:
*
* pa = (va - KERNBASE) + reloc
*/
m->reloc = load_addr;
/*
* Define the end of the relocatable range.
*/
m->relocend = (u_int32_t)end;
/*
* mac68k has multiple RAM segments on some models.
*/
m->ram_segs[0].start = low[0];
m->ram_segs[0].size = high[0] - low[0];
for (i = 1; i < numranges; i++) {
if ((high[i] - low[i]) == 0)
continue; /* shouldn't happen, but be safe */
/*
* Sort and coalesce RAM segments, as required by libkvm.
*/
for (j = 0; m->ram_segs[j].size; j++) {
if (low[i] < m->ram_segs[j].start)
break; /* Insert before this segment */
if (low[i] <=
(m->ram_segs[j].start + m->ram_segs[j].size))
break; /* Overlapping or adjoining */
}
if (m->ram_segs[j].size) {
if (low[i] < m->ram_segs[j].start) {
/* Make room for new segment. */
for (k = j; m->ram_segs[k].size; k++)
/* counting... */;
for (; k > j; k--) {
m->ram_segs[k].start =
m->ram_segs[k - 1].start;
m->ram_segs[k].size =
m->ram_segs[k - 1].size;
}
} else if (low[i] <=
(m->ram_segs[j].start + m->ram_segs[j].size)) {
/* Coalesce segments. */
if (high[i] > (m->ram_segs[j].start +
m->ram_segs[j].size))
m->ram_segs[j].size =
high[i] - m->ram_segs[j].start;
continue;
}
}
m->ram_segs[j].start = low[i];
m->ram_segs[j].size = high[i] - low[i];
}
}
/*
* Compute the size of the machine-dependent crash dump header.
* Returns size in disk blocks.
*/
int
cpu_dumpsize()
{
int size;
size = ALIGN(sizeof(kcore_seg_t)) + ALIGN(sizeof(cpu_kcore_hdr_t));
return (btodb(roundup(size, dbtob(1))));
}
/*
* Called by dumpsys() to dump the machine-dependent header.
*/
int
cpu_dump(dump, blknop)
int (*dump) __P((dev_t, daddr_t, caddr_t, size_t));
daddr_t *blknop;
{
int buf[dbtob(1) / sizeof(int)];
cpu_kcore_hdr_t *chdr;
kcore_seg_t *kseg;
int error;
kseg = (kcore_seg_t *)buf;
chdr = (cpu_kcore_hdr_t *)&buf[ALIGN(sizeof(kcore_seg_t)) /
sizeof(int)];
/* Create the segment header. */
CORE_SETMAGIC(*kseg, KCORE_MAGIC, MID_MACHINE, CORE_CPU);
kseg->c_size = dbtob(1) - ALIGN(sizeof(kcore_seg_t));
bcopy(&cpu_kcore_hdr, chdr, sizeof(cpu_kcore_hdr_t));
error = (*dump)(dumpdev, *blknop, (caddr_t)buf, sizeof(buf));
*blknop += btodb(sizeof(buf));
return (error);
}
/* /*
* These variables are needed by /sbin/savecore * These variables are needed by /sbin/savecore
*/ */
@ -584,20 +740,6 @@ u_long dumpmag = 0x8fca0101; /* magic number */
int dumpsize = 0; /* pages */ int dumpsize = 0; /* pages */
long dumplo = 0; /* blocks */ long dumplo = 0; /* blocks */
static int get_max_page __P((void));
static int
get_max_page()
{
int i, max = 0;
for (i = 0; i < numranges; i++) {
if (high[i] > max)
max = high[i];
}
return max;
}
/* /*
* This is called by main to set dumplo and dumpsize. * This is called by main to set dumplo and dumpsize.
* Dumps always skip the first CLBYTES of disk space in * Dumps always skip the first CLBYTES of disk space in
@ -608,8 +750,12 @@ get_max_page()
void void
cpu_dumpconf() cpu_dumpconf()
{ {
int nblks; cpu_kcore_hdr_t *h = &cpu_kcore_hdr;
int maj; struct m68k_kcore_hdr *m = &h->un._m68k;
int chdrsize; /* size of dump header */
int nblks; /* size of dump area */
int maj;
int i;
if (dumpdev == NODEV) if (dumpdev == NODEV)
return; return;
@ -620,20 +766,123 @@ cpu_dumpconf()
if (bdevsw[maj].d_psize == NULL) if (bdevsw[maj].d_psize == NULL)
return; return;
nblks = (*bdevsw[maj].d_psize) (dumpdev); nblks = (*bdevsw[maj].d_psize) (dumpdev);
if (nblks <= ctod(1)) chdrsize = cpu_dumpsize();
dumpsize = 0;
for (i = 0; m->ram_segs[i].size && i < M68K_NPHYS_RAM_SEGS; i++)
dumpsize += btoc(m->ram_segs[i].size);
/*
* Check to see if we will fit. Note we always skip the
* first CLBYTES in case there is a disk label there.
*/
if (nblks < (ctod(dumpsize) + chdrsize + ctod(1))) {
dumpsize = 0;
dumplo = -1;
return; return;
}
dumpsize = btoc(get_max_page()); /*
* Put dump at the end of the partition.
*/
dumplo = (nblks - 1) - ctod(dumpsize) - chdrsize;
}
/* Always skip the first CLBYTES, in case there is a label there. */ void
if (dumplo < ctod(1)) dumpsys()
dumplo = ctod(1); {
cpu_kcore_hdr_t *h = &cpu_kcore_hdr;
struct m68k_kcore_hdr *m = &h->un._m68k;
daddr_t blkno; /* current block to write */
/* dump routine */
int (*dump) __P((dev_t, daddr_t, caddr_t, size_t));
int pg; /* page being dumped */
vm_offset_t maddr; /* PA being dumped */
int seg; /* RAM segment being dumped */
int error; /* error code from (*dump)() */
/* Put dump at end of partition, and make it fit. */ /* XXX initialized here because of gcc lossage */
if (dumpsize > dtoc(nblks - dumplo)) seg = 0;
dumpsize = dtoc(nblks - dumplo); maddr = m->ram_segs[seg].start;
if (dumplo < nblks - ctod(dumpsize)) pg = 0;
dumplo = nblks - ctod(dumpsize);
/* Don't put dump messages in msgbuf. */
msgbufmapped = 0;
/* Make sure dump device is valid. */
if (dumpdev == NODEV)
return;
if (dumpsize == 0) {
cpu_dumpconf();
if (dumpsize == 0)
return;
}
if (dumplo < 0)
return;
dump = bdevsw[major(dumpdev)].d_dump;
blkno = dumplo;
printf("\ndumping to dev %x, offset %ld\n", dumpdev, dumplo);
printf("dump ");
/* Write the dump header. */
error = cpu_dump(dump, &blkno);
if (error)
goto bad;
for (pg = 0; pg < dumpsize; pg++) {
#define NPGMB (1024*1024/NBPG)
/* print out how many MBs we have dumped */
if (pg && (pg % NPGMB) == 0)
printf("%d ", pg / NPGMB);
#undef NPGMB
while (maddr >=
(m->ram_segs[seg].start + m->ram_segs[seg].size)) {
if (++seg >= M68K_NPHYS_RAM_SEGS ||
m->ram_segs[seg].size == 0) {
error = EINVAL; /* XXX ?? */
goto bad;
}
maddr = m->ram_segs[seg].start;
}
pmap_enter(pmap_kernel(), (vm_offset_t)vmmap, maddr,
VM_PROT_READ, TRUE);
error = (*dump)(dumpdev, blkno, vmmap, NBPG);
bad:
switch (error) {
case 0:
maddr += NBPG;
blkno += btodb(NBPG);
break;
case ENXIO:
printf("device bad\n");
return;
case EFAULT:
printf("device not ready\n");
return;
case EINVAL:
printf("area improper\n");
return;
case EIO:
printf("i/o error\n");
return;
case EINTR:
printf("aborted from console\n");
return;
default:
printf("error %d\n", error);
return;
}
}
printf("succeeded\n");
} }
/* /*
@ -645,8 +894,6 @@ cpu_dumpconf()
static vm_offset_t dumpspace; static vm_offset_t dumpspace;
vm_offset_t reserve_dumppages __P((vm_offset_t)); vm_offset_t reserve_dumppages __P((vm_offset_t));
static int find_range __P((vm_offset_t));
static int find_next_range __P((vm_offset_t));
vm_offset_t vm_offset_t
reserve_dumppages(p) reserve_dumppages(p)
@ -656,142 +903,6 @@ reserve_dumppages(p)
return (p + BYTES_PER_DUMP); return (p + BYTES_PER_DUMP);
} }
static int
find_range(pa)
vm_offset_t pa;
{
int i;
for (i = 0; i < numranges; i++) {
if (low[i] <= pa && pa < high[i])
return i;
}
return -1;
}
static int
find_next_range(pa)
vm_offset_t pa;
{
int i, near, best, t;
near = -1;
best = 0x7FFFFFFF;
for (i = 0; i < numranges; i++) {
if (low[i] <= pa && pa < high[i])
return i;
t = low[i] - pa;
if (t > 0) {
if (t < best) {
near = i;
best = t;
}
}
}
return near;
}
void
dumpsys()
{
unsigned bytes, i, n;
int range;
int maddr, psize;
daddr_t blkno;
int (*dump) __P((dev_t, daddr_t, caddr_t, size_t));
int error = 0;
msgbufmapped = 0; /* don't record dump msgs in msgbuf */
if (dumpdev == NODEV)
return;
/*
* For dumps during autoconfiguration,
* if dump device has already configured...
*/
if (dumpsize == 0)
cpu_dumpconf();
if (dumplo < 0)
return;
printf("\ndumping to dev %x, offset %ld\n", dumpdev, dumplo);
psize = (*bdevsw[major(dumpdev)].d_psize) (dumpdev);
printf("dump ");
if (psize == -1) {
printf("area unavailable.\n");
return;
}
bytes = get_max_page();
maddr = 0;
range = find_range(0);
blkno = dumplo;
dump = bdevsw[major(dumpdev)].d_dump;
for (i = 0; i < bytes; i += n) {
/*
* Avoid dumping "holes."
*/
if ((range == -1) || (i >= high[range])) {
range = find_next_range(i);
if (range == -1) {
error = EIO;
break;
}
n = low[range] - i;
maddr += n;
blkno += btodb(n);
continue;
}
/* Print out how many MBs we have to go. */
n = bytes - i;
if (n && (n % (1024 * 1024)) == 0)
printf("%d ", n / (1024 * 1024));
/* Limit size for next transfer. */
if (n > BYTES_PER_DUMP)
n = BYTES_PER_DUMP;
(void) pmap_map(dumpspace, maddr, maddr + n, VM_PROT_READ);
error = (*dump) (dumpdev, blkno, (caddr_t) dumpspace, n);
if (error)
break;
maddr += n;
blkno += btodb(n); /* XXX? */
}
switch (error) {
case ENXIO:
printf("device bad\n");
break;
case EFAULT:
printf("device not ready\n");
break;
case EINVAL:
printf("area improper\n");
break;
case EIO:
printf("i/o error\n");
break;
case EINTR:
printf("aborted from console\n");
break;
case 0:
printf("succeeded\n");
break;
default:
printf("error %d\n", error);
break;
}
printf("\n\n");
delay(5000000); /* 5 seconds */
}
/* /*
* Return the best possible estimate of the time in the timeval * Return the best possible estimate of the time in the timeval
* to which tvp points. We do this by returning the current time * to which tvp points. We do this by returning the current time
@ -1088,9 +1199,10 @@ getenvvars(flag, buf)
char *buf; char *buf;
{ {
extern u_long bootdev, videobitdepth, videosize; extern u_long bootdev, videobitdepth, videosize;
extern u_long end, esym; extern u_long esym;
extern u_long macos_boottime, MacOSROMBase; extern u_long macos_boottime, MacOSROMBase;
extern long macos_gmtbias; extern long macos_gmtbias;
extern char end[];
int root_scsi_id; int root_scsi_id;
/* /*
@ -1153,7 +1265,7 @@ getenvvars(flag, buf)
#ifndef SYMTAB_SPACE #ifndef SYMTAB_SPACE
if (esym == 0) if (esym == 0)
#endif #endif
esym = (long) &end; esym = (u_int32_t)end;
/* Get MacOS time */ /* Get MacOS time */
macos_boottime = getenv("BOOTTIME"); macos_boottime = getenv("BOOTTIME");