Home | History | Annotate | Line # | Download | only in m68k
      1 /*	$NetBSD: dumpsys.c,v 1.1 2026/04/09 12:49:35 thorpej Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1988 University of Utah.
      5  * Copyright (c) 1982, 1986, 1990, 1993
      6  *      The Regents of the University of California.  All rights reserved.
      7  *
      8  * This code is derived from software contributed to Berkeley by
      9  * the Systems Programming Group of the University of Utah Computer
     10  * Science Department.
     11  *
     12  * Redistribution and use in source and binary forms, with or without
     13  * modification, are permitted provided that the following conditions
     14  * are met:
     15  * 1. Redistributions of source code must retain the above copyright
     16  *    notice, this list of conditions and the following disclaimer.
     17  * 2. Redistributions in binary form must reproduce the above copyright
     18  *    notice, this list of conditions and the following disclaimer in the
     19  *    documentation and/or other materials provided with the distribution.
     20  * 3. Neither the name of the University nor the names of its contributors
     21  *    may be used to endorse or promote products derived from this software
     22  *    without specific prior written permission.
     23  *
     24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     34  * SUCH DAMAGE.
     35  *
     36  *      from: Utah Hdr: machdep.c 1.74 92/12/20
     37  *      from: @(#)machdep.c     8.10 (Berkeley) 4/20/94
     38  */
     39 
     40 #include <sys/cdefs.h>
     41 __KERNEL_RCSID(0, "$NetBSD: dumpsys.c,v 1.1 2026/04/09 12:49:35 thorpej Exp $");
     42 
     43 #include <sys/param.h>
     44 #include <sys/systm.h>
     45 #include <sys/kernel.h>
     46 #include <sys/proc.h>
     47 #include <sys/buf.h>
     48 #include <sys/reboot.h>
     49 #include <sys/conf.h>
     50 #include <sys/core.h>
     51 #include <sys/kcore.h>
     52 
     53 #include <machine/cpu.h>
     54 #include <machine/kcore.h>
     55 #include <machine/reg.h>
     56 #include <machine/pcb.h>
     57 
     58 #include <m68k/seglist.h>
     59 
     60 #include <uvm/uvm_extern.h>
     61 
     62 /*
     63  * Compute the size of the machine-dependent crash dump header.
     64  * Returns size in disk blocks.
     65  */
     66 #define	CHDRSIZE  (ALIGN(sizeof(kcore_seg_t)) + ALIGN(sizeof(cpu_kcore_hdr_t)))
     67 #define	MDHDRSIZE roundup(CHDRSIZE, dbtob(1))
     68 
     69 static int
     70 cpu_dumpsize(void)
     71 {
     72 	int sz = btodb(MDHDRSIZE);
     73 
     74 #ifdef __HAVE_M68K_PMAP_DUMPSYS
     75 	sz += pmap_dumpsize();
     76 #endif
     77 
     78 	return sz;
     79 }
     80 
     81 /*
     82  * Calculate size of RAM (in pages) to be dumped.
     83  */
     84 static u_long
     85 cpu_dump_mempagecnt(void)
     86 {
     87 	u_long i, n;
     88 	size_t size;
     89 
     90 	for (n = 0, i = 0; i < VM_PHYSSEG_MAX; i++) {
     91 		size = phys_seg_list[i].ps_end - phys_seg_list[i].ps_start;
     92 		if (size == 0) {
     93 			continue;
     94 		}
     95 		n += atop(size);
     96 	}
     97 	return n;
     98 }
     99 
    100 /*
    101  * Initialize machine-dependent portion of the crash dump header.
    102  */
    103 static void
    104 cpu_init_kcore_hdr(cpu_kcore_hdr_t *chdr)
    105 {
    106 	phys_ram_seg_t *ram_segs = pmap_init_kcore_hdr(chdr);
    107 	size_t size;
    108 	int i, j;
    109 
    110 	for (i = 0, j = 0; i < VM_PHYSSEG_MAX; i++) {
    111 		size = phys_seg_list[i].ps_end - phys_seg_list[i].ps_start;
    112 		if (size == 0) {
    113 			continue;
    114 		}
    115 		ram_segs[j].start = phys_seg_list[i].ps_start;
    116 		ram_segs[j].size = size;
    117 		j++;
    118 	}
    119 }
    120 
    121 /*
    122  * Called by dumpsys() to dump the crash dump header.
    123  */
    124 static int
    125 cpu_dump(int (*dump)(dev_t, daddr_t, void *, size_t), daddr_t *blknop)
    126 {
    127 	int buf[MDHDRSIZE / sizeof(int)];
    128 	cpu_kcore_hdr_t *chdr;
    129 	kcore_seg_t *kseg;
    130 	int error;
    131 
    132 	kseg = (kcore_seg_t *)buf;
    133 	chdr = (cpu_kcore_hdr_t *)&buf[ALIGN(sizeof(kcore_seg_t)) /
    134 	    sizeof(int)];
    135 
    136 	/* Create the segment header. */
    137 	CORE_SETMAGIC(*kseg, KCORE_MAGIC, MID_MACHINE, CORE_CPU);
    138 	kseg->c_size = MDHDRSIZE - ALIGN(sizeof(kcore_seg_t));
    139 
    140 	cpu_init_kcore_hdr(chdr);
    141 
    142 	error = (*dump)(dumpdev, *blknop, (void *)buf, sizeof(buf));
    143 	*blknop += btodb(sizeof(buf));
    144 
    145 	return error;
    146 }
    147 
    148 /*
    149  * These variables are needed by /sbin/savecore
    150  */
    151 uint32_t dumpmag = 0x8fca0101;	/* magic number */
    152 int	dumpsize = 0;		/* pages */
    153 long	dumplo = 0;		/* blocks */
    154 
    155 /*
    156  * This is called by main to set dumplo and dumpsize.
    157  * Dumps always skip the first PAGE_SIZE of disk space
    158  * in case there might be a disk label stored there.
    159  * If there is extra space, put dump at the end to
    160  * reduce the chance that swapping trashes it.
    161  */
    162 void
    163 cpu_dumpconf(void)
    164 {
    165 	int nblks, dumpblks;	/* size of dump area */
    166 	u_long npgs;
    167 
    168 	if (dumpdev == NODEV) {
    169 		goto bad;
    170 	}
    171 	nblks = bdev_size(dumpdev);
    172 	if (nblks <= ctod(1)) {
    173 		goto bad;
    174 	}
    175 
    176 	dumpblks = cpu_dumpsize();
    177 	if (dumpblks < 0) {
    178 		goto bad;
    179 	}
    180 	npgs = cpu_dump_mempagecnt();
    181 	dumpblks += ctod(npgs);
    182 
    183 	/* If dump won't fit (incl. room for possible label), punt. */
    184 	if (dumpblks > (nblks - ctod(1))) {
    185 		goto bad;
    186 	}
    187 
    188 	/* Put dump at end of partition */
    189 	dumplo = nblks - dumpblks;
    190 
    191 	/* dumpsize is in page units, and doesn't include headers. */
    192 	dumpsize = npgs;
    193 	return;
    194 
    195  bad:
    196 	dumpsize = 0;
    197 }
    198 
    199 /*
    200  * Dump physical memory onto the dump device.  Called by cpu_reboot().
    201  */
    202 void
    203 dumpsys(void)
    204 {
    205 	const struct bdevsw *bdev;
    206 	u_long memcl;
    207 	u_long maddr;
    208 	int psize, todo, npgs;
    209 	daddr_t blkno;
    210 	int (*dump)(dev_t, daddr_t, void *, size_t);
    211 	int error;
    212 
    213 	/* XXX Should save registers. */
    214 
    215 	if (dumpdev == NODEV) {
    216 		return;
    217 	}
    218 	bdev = bdevsw_lookup(dumpdev);
    219 	if (bdev == NULL || bdev->d_psize == NULL) {
    220 		return;
    221 	}
    222 
    223 	/*
    224 	 * For dumps during autoconfiguration,
    225 	 * if dump device has already configured...
    226 	 */
    227 	if (dumpsize == 0) {
    228 		cpu_dumpconf();
    229 	}
    230 	if (dumplo <= 0) {
    231 		printf("\ndump to dev %u,%u not possible\n",
    232 		    major(dumpdev), minor(dumpdev));
    233 		return;
    234 	}
    235 	printf("\ndumping to dev %u,%u offset %ld\n",
    236 	    major(dumpdev), minor(dumpdev), dumplo);
    237 
    238 	psize = bdev_size(dumpdev);
    239 	if (psize == -1) {
    240 		printf("dump area unavailable\n");
    241 		return;
    242 	}
    243 
    244 	/* XXX should purge all outstanding keystrokes. */
    245 
    246 	dump = bdev->d_dump;
    247 	blkno = dumplo;
    248 	todo = dumpsize;	/* pages */
    249 
    250 	if ((error = cpu_dump(dump, &blkno)) != 0) {
    251 		goto err;
    252 	}
    253 
    254 #ifdef __HAVE_M68K_PMAP_DUMPSYS
    255 	if ((error = pmap_dumpsys(dump, &blkno)) != 0) {
    256 		goto err;
    257 	}
    258 #endif
    259 
    260 	for (memcl = 0; memcl < VM_PHYSSEG_MAX; memcl++) {
    261 		maddr = phys_seg_list[memcl].ps_start;
    262 		npgs = m68k_btop(phys_seg_list[memcl].ps_end -
    263 				 phys_seg_list[memcl].ps_start);
    264 
    265 		while (npgs && todo) {
    266 			/* Print pages left after every 16. */
    267 			if (todo == dumpsize || (todo & 0xf) == 0) {
    268 				printf_nostamp("\rpages %6d", todo);
    269 			}
    270 
    271 			pmap_kenter_pa((vaddr_t)vmmap, maddr, VM_PROT_READ, 0);
    272 			pmap_update(pmap_kernel());
    273 
    274 			error = (*dump)(dumpdev, blkno, vmmap, PAGE_SIZE);
    275 
    276 			pmap_kremove((vaddr_t)vmmap, PAGE_SIZE);
    277 			pmap_update(pmap_kernel());
    278 
    279 			if (error) {
    280 				goto err;
    281 			}
    282 
    283 			maddr += PAGE_SIZE;
    284 			blkno += btodb(PAGE_SIZE);
    285 			npgs--;
    286 			todo--;
    287 		}
    288 	}
    289 
    290  err:
    291 	printf_nostamp("\rdump ");
    292 	switch (error) {
    293 	case ENXIO:
    294 		printf_nostamp("device bad\n");
    295 		break;
    296 
    297 	case EFAULT:
    298 		printf_nostamp("device not ready\n");
    299 		break;
    300 
    301 	case EINVAL:
    302 		printf_nostamp("area improper\n");
    303 		break;
    304 
    305 	case EIO:
    306 		printf_nostamp("i/o error\n");
    307 		break;
    308 
    309 	case EINTR:
    310 		printf_nostamp("aborted from console\n");
    311 		break;
    312 
    313 	case 0:
    314 		printf_nostamp("succeeded\n");
    315 		break;
    316 
    317 	default:
    318 		printf_nostamp("error %d\n", error);
    319 		break;
    320 	}
    321 	printf_nostamp("\n\n");
    322 	delay(5000);
    323 }
    324