dump_machdep.c revision 105531
1/* 2 * Copyright (c) 2002 Marcel Moolenaar 3 * Copyright (c) 2002 Thomas Moestl 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 * 27 * $FreeBSD: head/sys/sparc64/sparc64/dump_machdep.c 105531 2002-10-20 17:03:15Z tmm $ 28 */ 29 30#include <sys/param.h> 31#include <sys/systm.h> 32#include <sys/conf.h> 33#include <sys/cons.h> 34#include <sys/kernel.h> 35#include <sys/kerneldump.h> 36 37#include <vm/vm.h> 38#include <vm/pmap.h> 39 40#include <machine/metadata.h> 41#include <machine/kerneldump.h> 42#include <machine/ofw_mem.h> 43#include <machine/tsb.h> 44 45CTASSERT(sizeof(struct kerneldumpheader) == DEV_BSIZE); 46 47extern struct ofw_mem_region sparc64_memreg[]; 48extern int sparc64_nmemreg; 49 50static struct kerneldumpheader kdh; 51static off_t dumplo, dumppos; 52 53/* Handle buffered writes. */ 54static char buffer[DEV_BSIZE]; 55static vm_size_t fragsz; 56 57#define MAXDUMPSZ (MAXDUMPPGS << PAGE_SHIFT) 58 59/* XXX should be MI */ 60static void 61mkdumpheader(struct kerneldumpheader *kdh, uint32_t archver, uint64_t dumplen, 62 uint32_t blksz) 63{ 64 65 bzero(kdh, sizeof(*kdh)); 66 strncpy(kdh->magic, KERNELDUMPMAGIC, sizeof(kdh->magic)); 67 strncpy(kdh->architecture, MACHINE_ARCH, sizeof(kdh->architecture)); 68 kdh->version = htod32(KERNELDUMPVERSION); 69 kdh->architectureversion = htod32(archver); 70 kdh->dumplength = htod64(dumplen); 71 kdh->dumptime = htod64(time_second); 72 kdh->blocksize = htod32(blksz); 73 strncpy(kdh->hostname, hostname, sizeof(kdh->hostname)); 74 strncpy(kdh->versionstring, version, sizeof(kdh->versionstring)); 75 if (panicstr != NULL) 76 strncpy(kdh->panicstring, panicstr, sizeof(kdh->panicstring)); 77 kdh->parity = kerneldump_parity(kdh); 78} 79 80static int 81buf_write(struct dumperinfo *di, char *ptr, size_t sz) 82{ 83 size_t len; 84 int error; 85 86 while (sz) { 87 len = DEV_BSIZE - fragsz; 88 if (len > sz) 89 len = sz; 90 bcopy(ptr, buffer + fragsz, len); 91 fragsz += len; 92 ptr += len; 93 sz -= len; 94 if (fragsz == DEV_BSIZE) { 95 error = di->dumper(di->priv, buffer, 0, dumplo, 96 DEV_BSIZE); 97 if (error) 98 return error; 99 dumplo += DEV_BSIZE; 100 fragsz = 0; 101 } 102 } 103 104 return (0); 105} 106 107static int 108buf_flush(struct dumperinfo *di) 109{ 110 int error; 111 112 if (fragsz == 0) 113 return (0); 114 115 error = di->dumper(di->priv, buffer, 0, dumplo, DEV_BSIZE); 116 dumplo += DEV_BSIZE; 117 return (error); 118} 119 120static int 121reg_write(struct dumperinfo *di, vm_offset_t pa, vm_size_t size) 122{ 123 struct sparc64_dump_reg r; 124 125 r.dr_pa = pa; 126 r.dr_size = size; 127 r.dr_offs = dumppos; 128 dumppos += size; 129 return (buf_write(di, (char *)&r, sizeof(r))); 130} 131 132static int 133blk_dump(struct dumperinfo *di, vm_offset_t pa, vm_size_t size) 134{ 135 vm_size_t pos, npg, rsz; 136 void *va; 137 int c, counter, error, i, twiddle; 138 139 printf(" chunk at %#lx: %ld bytes ", (u_long)pa, (long)size); 140 141 va = NULL; 142 error = counter = twiddle = 0; 143 for (pos = 0; pos < size; pos += MAXDUMPSZ, counter++) { 144 if (counter % 128 == 0) 145 printf("%c\b", "|/-\\"[twiddle++ & 3]); 146 rsz = size - pos; 147 rsz = (rsz > MAXDUMPSZ) ? MAXDUMPSZ : rsz; 148 npg = rsz >> PAGE_SHIFT; 149 for (i = 0; i < npg; i++) 150 va = pmap_kenter_temporary(pa + pos + i * PAGE_SIZE, i); 151 error = di->dumper(di->priv, va, 0, dumplo, rsz); 152 if (error) 153 break; 154 dumplo += rsz; 155 156 /* Check for user abort. */ 157 c = cncheckc(); 158 if (c == 0x03) 159 return (ECANCELED); 160 if (c != -1) 161 printf("(CTRL-C to abort) "); 162 } 163 printf("... %s\n", (error) ? "fail" : "ok"); 164 return (error); 165} 166 167void 168dumpsys(struct dumperinfo *di) 169{ 170 struct sparc64_dump_hdr hdr; 171 vm_size_t size, totsize, hdrsize; 172 int error, i, nreg; 173 174 /* Calculate dump size. */ 175 size = 0; 176 nreg = sparc64_nmemreg; 177 for (i = 0; i < sparc64_nmemreg; i++) 178 size += sparc64_memreg[i].mr_size; 179 /* Account for the header size. */ 180 hdrsize = roundup2(sizeof(hdr) + sizeof(struct sparc64_dump_reg) * nreg, 181 DEV_BSIZE); 182 size += hdrsize; 183 184 totsize = size + 2 * sizeof(kdh); 185 if (totsize > di->mediasize) { 186 printf("Insufficient space on device (need %ld, have %ld), " 187 "refusing to dump.\n", (long)totsize, 188 (long)di->mediasize); 189 error = ENOSPC; 190 goto fail; 191 } 192 193 /* Determine dump offset on device. */ 194 dumplo = di->mediaoffset + di->mediasize - totsize; 195 196 mkdumpheader(&kdh, KERNELDUMP_SPARC64_VERSION, size, di->blocksize); 197 198 printf("Dumping %lu MB (%d chunks)\n", (u_long)(size >> 20), nreg); 199 200 /* Dump leader */ 201 error = di->dumper(di->priv, &kdh, 0, dumplo, sizeof(kdh)); 202 if (error) 203 goto fail; 204 dumplo += sizeof(kdh); 205 206 /* Dump the private header. */ 207 hdr.dh_hdr_size = hdrsize; 208 hdr.dh_tsb_pa = tsb_kernel_phys; 209 hdr.dh_tsb_size = tsb_kernel_size; 210 hdr.dh_tsb_mask = tsb_kernel_mask; 211 hdr.dh_nregions = nreg; 212 213 if (buf_write(di, (char *)&hdr, sizeof(hdr)) != 0) 214 goto fail; 215 216 dumppos = hdrsize; 217 /* Now, write out the region descriptors. */ 218 for (i = 0; i < sparc64_nmemreg; i++) { 219 error = reg_write(di, sparc64_memreg[i].mr_start, 220 sparc64_memreg[i].mr_size); 221 if (error != 0) 222 goto fail; 223 } 224 buf_flush(di); 225 226 /* Dump memory chunks. */ 227 for (i = 0; i < sparc64_nmemreg; i++) { 228 error = blk_dump(di, sparc64_memreg[i].mr_start, 229 sparc64_memreg[i].mr_size); 230 if (error != 0) 231 goto fail; 232 } 233 234 /* Dump trailer */ 235 error = di->dumper(di->priv, &kdh, 0, dumplo, sizeof(kdh)); 236 if (error) 237 goto fail; 238 239 /* Signal completion, signoff and exit stage left. */ 240 di->dumper(di->priv, NULL, 0, 0, 0); 241 printf("\nDump complete\n"); 242 return; 243 244 fail: 245 /* XXX It should look more like VMS :-) */ 246 printf("** DUMP FAILED (ERROR %d) **\n", error); 247} 248