diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2007-03-03 21:37:28 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2007-03-03 21:37:28 +0000 |
commit | 301ce3789c0dded4c40ebb4c1197dee00cf0fc3e (patch) | |
tree | 44351c56ccd077c95b601f112ad6c7c4d156911e /sys/arch | |
parent | 8f58ce59b66d35d5d484c5cfb9f5967571339ac9 (diff) |
Kernel crash dumps and associated libkvm bits for landisk.
Diffstat (limited to 'sys/arch')
-rw-r--r-- | sys/arch/landisk/include/kcore.h | 1 | ||||
-rw-r--r-- | sys/arch/landisk/landisk/autoconf.c | 8 | ||||
-rw-r--r-- | sys/arch/landisk/landisk/machdep.c | 94 | ||||
-rw-r--r-- | sys/arch/sh/include/cpu.h | 5 | ||||
-rw-r--r-- | sys/arch/sh/include/kcore.h | 32 | ||||
-rw-r--r-- | sys/arch/sh/include/param.h | 14 | ||||
-rw-r--r-- | sys/arch/sh/sh/sh_machdep.c | 153 |
7 files changed, 282 insertions, 25 deletions
diff --git a/sys/arch/landisk/include/kcore.h b/sys/arch/landisk/include/kcore.h new file mode 100644 index 00000000000..9aafa045767 --- /dev/null +++ b/sys/arch/landisk/include/kcore.h @@ -0,0 +1 @@ +#include <sh/kcore.h> diff --git a/sys/arch/landisk/landisk/autoconf.c b/sys/arch/landisk/landisk/autoconf.c index 3f99c61e347..7facbd1c6fc 100644 --- a/sys/arch/landisk/landisk/autoconf.c +++ b/sys/arch/landisk/landisk/autoconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: autoconf.c,v 1.4 2006/11/06 19:42:52 miod Exp $ */ +/* $OpenBSD: autoconf.c,v 1.5 2007/03/03 21:37:27 miod Exp $ */ /* $NetBSD: autoconf.c,v 1.1 2006/09/01 21:26:18 uwe Exp $ */ /*- @@ -43,6 +43,7 @@ #include <dev/cons.h> +#include <machine/cpu.h> #include <machine/intr.h> int cold = 1; @@ -51,9 +52,6 @@ struct device *booted_device; struct device *root_device; void diskconf(void); -#ifdef notyet -void dumpconf(void); -#endif struct device *parsedisk(char *, int, int, dev_t *); void setroot(void); int findblkmajor(struct device *); @@ -85,9 +83,7 @@ diskconf(void) printf("boot device: %s\n", booted_device ? booted_device->dv_xname : "<unknown>"); setroot(); -#ifdef notyet dumpconf(); -#endif } static struct nam2blk { diff --git a/sys/arch/landisk/landisk/machdep.c b/sys/arch/landisk/landisk/machdep.c index cce14dadb6a..82a34ba864f 100644 --- a/sys/arch/landisk/landisk/machdep.c +++ b/sys/arch/landisk/landisk/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.8 2007/02/06 23:13:37 miod Exp $ */ +/* $OpenBSD: machdep.c,v 1.9 2007/03/03 21:37:27 miod Exp $ */ /* $NetBSD: machdep.c,v 1.1 2006/09/01 21:26:18 uwe Exp $ */ /*- @@ -81,6 +81,9 @@ #include <sys/mount.h> #include <sys/reboot.h> #include <sys/sysctl.h> +#include <sys/exec.h> +#include <sys/core.h> +#include <sys/kcore.h> #include <uvm/uvm_extern.h> @@ -95,6 +98,7 @@ #include <sh/mmu_sh4.h> #include <machine/cpu.h> +#include <machine/kcore.h> #include <landisk/landisk/landiskreg.h> @@ -109,6 +113,7 @@ char machine[] = MACHINE; /* landisk */ __dead void landisk_startup(int, char *); __dead void main(void); +void cpu_init_kcore_hdr(void); extern u_int32_t getramsize(void); @@ -153,6 +158,7 @@ landisk_startup(int howto, char *_esym) uvm_page_physload(atop(IOM_RAM_BEGIN), atop(IOM_RAM_BEGIN + ramsize), kernend, atop(IOM_RAM_BEGIN + ramsize), VM_FREELIST_DEFAULT); + cpu_init_kcore_hdr(); /* need to be done before pmap_bootstrap */ /* Initialize proc0 u-area */ sh_proc0_init(); @@ -193,7 +199,8 @@ boot(int howto) { if (cold) { - howto |= RB_HALT; + if ((howto & RB_USERREQ) == 0) + howto |= RB_HALT; goto haltsys; } @@ -204,19 +211,18 @@ boot(int howto) * If we've been adjusting the clock, the todr * will be out of synch; adjust it now. */ - resettodr(); + if ((howto & RB_TIMEBAD) == 0) + resettodr(); + else + printf("WARNING: not updating battery clock\n"); } - /* wait 1s */ - delay(1 * 1000 * 1000); - /* Disable interrupts. */ splhigh(); /* Do a dump if requested. */ - if ((howto & (RB_DUMP | RB_HALT)) == RB_DUMP) { + if (howto & RB_DUMP) dumpsys(); - } haltsys: doshutdownhooks(); @@ -225,6 +231,7 @@ haltsys: _reg_write_1(LANDISK_PWRMNG, PWRMNG_POWEROFF); delay(1 * 1000 * 1000); printf("POWEROFF FAILED!\n"); + howto |= RB_HALT; } if (howto & RB_HALT) { @@ -376,3 +383,74 @@ InitializeBsc(void) _reg_write_2(SH4_FRQCR, FRQCR_VAL); } #endif /* !DONT_INIT_BSC */ + +/* + * Dump the machine-dependent dump header. + */ +u_int +cpu_dump(int (*dump)(dev_t, daddr_t, caddr_t, size_t), daddr_t *blknop) +{ + extern cpu_kcore_hdr_t cpu_kcore_hdr; + char buf[dbtob(1)]; + cpu_kcore_hdr_t *h; + kcore_seg_t *kseg; + int rc; + +#ifdef DIAGNOSTIC + if (cpu_dumpsize() > btodb(sizeof buf)) { + printf("buffer too small in cpu_dump, "); + return (EINVAL); /* "aborted" */ + } +#endif + + bzero(buf, sizeof buf); + kseg = (kcore_seg_t *)buf; + h = (cpu_kcore_hdr_t *)(buf + ALIGN(sizeof(kcore_seg_t))); + + /* 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, h, sizeof(*h)); + /* We can now fill kptp in the header... */ + h->kcore_kptp = SH3_P1SEG_TO_PHYS((vaddr_t)pmap_kernel()->pm_ptp); + + rc = (*dump)(dumpdev, *blknop, buf, sizeof buf); + *blknop += btodb(sizeof buf); + return (rc); +} + +/* + * Return the size of the machine-dependent dump header, in disk blocks. + */ +u_int +cpu_dumpsize() +{ + u_int size; + + size = ALIGN(sizeof(kcore_seg_t)) + ALIGN(sizeof(cpu_kcore_hdr_t)); + return (btodb(roundup(size, dbtob(1)))); +} + +/* + * Fill the machine-dependent dump header. + */ +void +cpu_init_kcore_hdr() +{ + extern cpu_kcore_hdr_t cpu_kcore_hdr; + cpu_kcore_hdr_t *h = &cpu_kcore_hdr; + phys_ram_seg_t *seg = cpu_kcore_hdr.kcore_segs; + struct vm_physseg *physseg = vm_physmem; + u_int i; + + bzero(h, sizeof(*h)); + + h->kcore_nsegs = min(NPHYS_RAM_SEGS, (u_int)vm_nphysseg); + for (i = h->kcore_nsegs; i != 0; i--) { + seg->start = ptoa(physseg->start); + seg->size = (psize_t)ptoa(physseg->end - physseg->start); + seg++; + physseg++; + } +} diff --git a/sys/arch/sh/include/cpu.h b/sys/arch/sh/include/cpu.h index 721d3275b77..a4906007317 100644 --- a/sys/arch/sh/include/cpu.h +++ b/sys/arch/sh/include/cpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.h,v 1.5 2007/03/02 06:11:54 miod Exp $ */ +/* $OpenBSD: cpu.h,v 1.6 2007/03/03 21:37:27 miod Exp $ */ /* $NetBSD: cpu.h,v 1.41 2006/01/21 04:24:12 uwe Exp $ */ /*- @@ -207,6 +207,9 @@ void savectx(struct pcb *); struct fpreg; void fpu_save(struct fpreg *); void fpu_restore(struct fpreg *); +u_int cpu_dump(int (*)(dev_t, daddr_t, caddr_t, size_t), daddr_t *); +u_int cpu_dumpsize(void); +void dumpconf(void); void dumpsys(void); #endif /* _KERNEL */ #endif /* !_SH_CPU_H_ */ diff --git a/sys/arch/sh/include/kcore.h b/sys/arch/sh/include/kcore.h new file mode 100644 index 00000000000..29e3bc0800c --- /dev/null +++ b/sys/arch/sh/include/kcore.h @@ -0,0 +1,32 @@ +/* $OpenBSD: kcore.h,v 1.1 2007/03/03 21:37:27 miod Exp $ */ + +/* + * Copyright (c) 2007 Miodrag Vallat. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice, this permission notice, and the disclaimer below + * appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _SH_KCORE_H_ +#define _SH_KCORE_H_ + +/* this should be >= VM_PHYSSEG_MAX from <machine/vmparam.h> */ +#define NPHYS_RAM_SEGS 8 + +typedef struct cpu_kcore_hdr { + paddr_t kcore_kptp; + unsigned int kcore_nsegs; + phys_ram_seg_t kcore_segs[NPHYS_RAM_SEGS]; +} cpu_kcore_hdr_t; + +#endif /* _SH_KCORE_H_ */ diff --git a/sys/arch/sh/include/param.h b/sys/arch/sh/include/param.h index a2eec2d29ed..efb8a4b9dbb 100644 --- a/sys/arch/sh/include/param.h +++ b/sys/arch/sh/include/param.h @@ -1,4 +1,4 @@ -/* $OpenBSD: param.h,v 1.2 2006/11/03 17:28:01 drahn Exp $ */ +/* $OpenBSD: param.h,v 1.3 2007/03/03 21:37:27 miod Exp $ */ /* $NetBSD: param.h,v 1.15 2006/08/28 13:43:35 yamt Exp $ */ /*- @@ -104,13 +104,17 @@ #define MSGBUFSIZE NBPG /* default message buffer size */ #endif +/* pages to bytes */ #define btoc(x) (((x) + PAGE_MASK) >> PAGE_SHIFT) #define ctob(x) ((x) << PAGE_SHIFT) -#define btodb(bytes) /* calculates (bytes / DEV_BSIZE) */ \ - ((bytes) >> DEV_BSHIFT) -#define dbtob(db) /* calculates (db * DEV_BSIZE) */ \ - ((db) << DEV_BSHIFT) +/* pages to disk blocks */ +#define ctod(x) ((x) << (PAGE_SHIFT - DEV_BSHIFT)) +#define dtoc(x) ((x) >> (PAGE_SHIFT - DEV_BSHIFT)) + +/* bytes to disk blocks */ +#define btodb(x) ((x) >> DEV_BSHIFT) +#define dbtob(x) ((x) << DEV_BSHIFT) /* * Constants related to network buffer management. diff --git a/sys/arch/sh/sh/sh_machdep.c b/sys/arch/sh/sh/sh_machdep.c index 05b6bced8e8..a6b1e05916b 100644 --- a/sys/arch/sh/sh/sh_machdep.c +++ b/sys/arch/sh/sh/sh_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sh_machdep.c,v 1.9 2007/03/02 06:11:54 miod Exp $ */ +/* $OpenBSD: sh_machdep.c,v 1.10 2007/03/03 21:37:27 miod Exp $ */ /* $NetBSD: sh3_machdep.c,v 1.59 2006/03/04 01:13:36 uwe Exp $ */ /* @@ -101,6 +101,9 @@ #include <sys/user.h> #include <sys/sched.h> #include <sys/msg.h> +#include <sys/conf.h> +#include <sys/core.h> +#include <sys/kcore.h> #include <uvm/uvm_extern.h> @@ -112,6 +115,7 @@ #include <sh/mmu.h> #include <sh/trap.h> #include <sh/intr.h> +#include <sh/kcore.h> #ifdef NBUF int nbuf = NBUF; @@ -143,7 +147,7 @@ struct user *proc0paddr; /* init_main.c use this. */ struct pcb *curpcb; struct md_upte *curupte; /* SH3 wired u-area hack */ -#define VBR (uint8_t *)SH3_PHYS_TO_P1SEG(IOM_RAM_BEGIN) +#define VBR (u_int8_t *)SH3_PHYS_TO_P1SEG(IOM_RAM_BEGIN) vaddr_t ram_start = SH3_PHYS_TO_P1SEG(IOM_RAM_BEGIN); /* exception handler holder (sh/sh/vectors.S) */ extern char sh_vector_generic[], sh_vector_generic_end[]; @@ -160,9 +164,10 @@ caddr_t allocsys(caddr_t); /* * These variables are needed by /sbin/savecore */ -uint32_t dumpmag = 0x8fca0101; /* magic number */ -int dumpsize; /* pages */ +u_int32_t dumpmag = 0x8fca0101; /* magic number */ +u_int dumpsize; /* pages */ long dumplo; /* blocks */ +cpu_kcore_hdr_t cpu_kcore_hdr; int kbd_reset; @@ -424,9 +429,147 @@ allocsys(caddr_t v) } void +dumpconf() +{ + cpu_kcore_hdr_t *h = &cpu_kcore_hdr; + u_int dumpextra, totaldumpsize; /* in disk blocks */ + u_int seg, nblks; + int maj; + + if (dumpdev == NODEV) + return; + + maj = major(dumpdev); + if (maj < 0 || maj >= nblkdev) { + printf("dumpconf: bad dumpdev=0x%x\n", dumpdev); + dumpdev = NODEV; + return; + } + if (bdevsw[maj].d_psize == NULL) + return; + nblks = (u_int)(*bdevsw[maj].d_psize)(dumpdev); + if (nblks <= btodb(1U)) + return; + + dumpsize = 0; + for (seg = 0; seg < h->kcore_nsegs; seg++) + dumpsize += atop(h->kcore_segs[seg].size); + dumpextra = cpu_dumpsize(); + + /* Always skip the first block, in case there is a label there. */ + if (dumplo < btodb(1)); + dumplo = btodb(1); + + /* Put dump at the end of the partition, and make it fit. */ + totaldumpsize = ctod(dumpsize) + dumpextra; + if (totaldumpsize > nblks - dumplo) { + totaldumpsize = dbtob(nblks - dumplo); + dumpsize = dtoc(totaldumpsize - dumpextra); + } + if (dumplo < nblks - totaldumpsize) + dumplo = nblks - totaldumpsize; +} + +void dumpsys() { - /* TODO */ + cpu_kcore_hdr_t *h = &cpu_kcore_hdr; + daddr_t blkno; + int (*dump)(dev_t, daddr_t, caddr_t, size_t); + u_int page = 0; + paddr_t dumppa; + u_int seg; + int rc; + extern int msgbufmapped; + + /* Don't record dump messages in msgbuf. */ + msgbufmapped = 0; + + /* Make sure dump settings are valid. */ + if (dumpdev == NODEV) + return; + if (dumpsize == 0) { + dumpconf(); + if (dumpsize == 0) + return; + } + if (dumplo <= 0) { + printf("\ndump to dev 0x%x not possible, not enough space\n", + dumpdev); + return; + } + + dump = bdevsw[major(dumpdev)].d_dump; + blkno = dumplo; + + printf("\ndumping to dev 0x%x offset %ld\n", dumpdev, dumplo); + + printf("dump "); + + /* Write dump header */ + rc = cpu_dump(dump, &blkno); + if (rc != 0) + goto bad; + + for (seg = 0; seg < h->kcore_nsegs; seg++) { + u_int pagesleft; + + pagesleft = atop(h->kcore_segs[seg].size); + dumppa = (paddr_t)h->kcore_segs[seg].start; + + while (pagesleft != 0) { + u_int npages; + +#define NPGMB atop(1024 * 1024) + if (page != 0 && (page % NPGMB) == 0) + printf("%u ", page / NPGMB); + + /* do not dump more than 1MB at once */ + npages = min(pagesleft, NPGMB); +#undef NPGMB + npages = min(npages, dumpsize); + + rc = (*dump)(dumpdev, blkno, + (caddr_t)SH3_PHYS_TO_P2SEG(dumppa), ptoa(npages)); + if (rc != 0) + goto bad; + + pagesleft -= npages; + dumppa += ptoa(npages); + page += npages; + dumpsize -= npages; + if (dumpsize == 0) + goto bad; /* if truncated dump */ + blkno += ctod(npages); + } + } +bad: + switch (rc) { + case 0: + printf("succeeded\n"); + break; + 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\n"); + break; + default: + printf("error %d\n", rc); + break; + } + + /* make sure console can output our last message */ + delay(1 * 1000 * 1000); } /* |