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