dump_machdep.c revision 175768
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 175768 2008-01-28 19:04:07Z ru $ 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/vm_param.h> 39#include <vm/pmap.h> 40 41#include <machine/metadata.h> 42#include <machine/kerneldump.h> 43#include <machine/ofw_mem.h> 44#include <machine/tsb.h> 45#include <machine/tlb.h> 46 47CTASSERT(sizeof(struct kerneldumpheader) == DEV_BSIZE); 48 49static struct kerneldumpheader kdh; 50static off_t dumplo, dumppos; 51 52/* Handle buffered writes. */ 53static char buffer[DEV_BSIZE]; 54static vm_size_t fragsz; 55 56#define MAXDUMPSZ (MAXDUMPPGS << PAGE_SHIFT) 57 58/* XXX should be MI */ 59static void 60mkdumpheader(struct kerneldumpheader *kdh, uint32_t archver, uint64_t dumplen, 61 uint32_t blksz) 62{ 63 64 bzero(kdh, sizeof(*kdh)); 65 strncpy(kdh->magic, KERNELDUMPMAGIC, sizeof(kdh->magic)); 66 strncpy(kdh->architecture, MACHINE_ARCH, sizeof(kdh->architecture)); 67 kdh->version = htod32(KERNELDUMPVERSION); 68 kdh->architectureversion = htod32(archver); 69 kdh->dumplength = htod64(dumplen); 70 kdh->dumptime = htod64(time_second); 71 kdh->blocksize = htod32(blksz); 72 strncpy(kdh->hostname, hostname, sizeof(kdh->hostname)); 73 strncpy(kdh->versionstring, version, sizeof(kdh->versionstring)); 74 if (panicstr != NULL) 75 strncpy(kdh->panicstring, panicstr, sizeof(kdh->panicstring)); 76 kdh->parity = kerneldump_parity(kdh); 77} 78 79static int 80buf_write(struct dumperinfo *di, char *ptr, size_t sz) 81{ 82 size_t len; 83 int error; 84 85 while (sz) { 86 len = DEV_BSIZE - fragsz; 87 if (len > sz) 88 len = sz; 89 bcopy(ptr, buffer + fragsz, len); 90 fragsz += len; 91 ptr += len; 92 sz -= len; 93 if (fragsz == DEV_BSIZE) { 94 error = dump_write(di, buffer, 0, dumplo, 95 DEV_BSIZE); 96 if (error) 97 return error; 98 dumplo += DEV_BSIZE; 99 fragsz = 0; 100 } 101 } 102 103 return (0); 104} 105 106static int 107buf_flush(struct dumperinfo *di) 108{ 109 int error; 110 111 if (fragsz == 0) 112 return (0); 113 114 error = dump_write(di, buffer, 0, dumplo, DEV_BSIZE); 115 dumplo += DEV_BSIZE; 116 return (error); 117} 118 119static int 120reg_write(struct dumperinfo *di, vm_paddr_t pa, vm_size_t size) 121{ 122 struct sparc64_dump_reg r; 123 124 r.dr_pa = pa; 125 r.dr_size = size; 126 r.dr_offs = dumppos; 127 dumppos += size; 128 return (buf_write(di, (char *)&r, sizeof(r))); 129} 130 131static int 132blk_dump(struct dumperinfo *di, vm_paddr_t pa, vm_size_t size) 133{ 134 vm_size_t pos, rsz; 135 vm_offset_t va; 136 int c, counter, error, twiddle; 137 138 printf(" chunk at %#lx: %ld bytes ", (u_long)pa, (long)size); 139 140 va = 0L; 141 error = counter = twiddle = 0; 142 for (pos = 0; pos < size; pos += MAXDUMPSZ, counter++) { 143 if (counter % 128 == 0) 144 printf("%c\b", "|/-\\"[twiddle++ & 3]); 145 rsz = size - pos; 146 rsz = (rsz > MAXDUMPSZ) ? MAXDUMPSZ : rsz; 147 va = TLB_PHYS_TO_DIRECT(pa + pos); 148 error = dump_write(di, (void *)va, 0, dumplo, rsz); 149 if (error) 150 break; 151 dumplo += rsz; 152 153 /* Check for user abort. */ 154 c = cncheckc(); 155 if (c == 0x03) 156 return (ECANCELED); 157 if (c != -1) 158 printf("(CTRL-C to abort) "); 159 } 160 printf("... %s\n", (error) ? "fail" : "ok"); 161 return (error); 162} 163 164void 165dumpsys(struct dumperinfo *di) 166{ 167 struct sparc64_dump_hdr hdr; 168 vm_size_t size, totsize, hdrsize; 169 int error, i, nreg; 170 171 /* Calculate dump size. */ 172 size = 0; 173 nreg = sparc64_nmemreg; 174 for (i = 0; i < sparc64_nmemreg; i++) 175 size += sparc64_memreg[i].mr_size; 176 /* Account for the header size. */ 177 hdrsize = roundup2(sizeof(hdr) + sizeof(struct sparc64_dump_reg) * nreg, 178 DEV_BSIZE); 179 size += hdrsize; 180 181 totsize = size + 2 * sizeof(kdh); 182 if (totsize > di->mediasize) { 183 printf("Insufficient space on device (need %ld, have %ld), " 184 "refusing to dump.\n", (long)totsize, 185 (long)di->mediasize); 186 error = ENOSPC; 187 goto fail; 188 } 189 190 /* Determine dump offset on device. */ 191 dumplo = di->mediaoffset + di->mediasize - totsize; 192 193 mkdumpheader(&kdh, KERNELDUMP_SPARC64_VERSION, size, di->blocksize); 194 195 printf("Dumping %lu MB (%d chunks)\n", (u_long)(size >> 20), nreg); 196 197 /* Dump leader */ 198 error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh)); 199 if (error) 200 goto fail; 201 dumplo += sizeof(kdh); 202 203 /* Dump the private header. */ 204 hdr.dh_hdr_size = hdrsize; 205 hdr.dh_tsb_pa = tsb_kernel_phys; 206 hdr.dh_tsb_size = tsb_kernel_size; 207 hdr.dh_tsb_mask = tsb_kernel_mask; 208 hdr.dh_nregions = nreg; 209 210 if (buf_write(di, (char *)&hdr, sizeof(hdr)) != 0) 211 goto fail; 212 213 dumppos = hdrsize; 214 /* Now, write out the region descriptors. */ 215 for (i = 0; i < sparc64_nmemreg; i++) { 216 error = reg_write(di, sparc64_memreg[i].mr_start, 217 sparc64_memreg[i].mr_size); 218 if (error != 0) 219 goto fail; 220 } 221 buf_flush(di); 222 223 /* Dump memory chunks. */ 224 for (i = 0; i < sparc64_nmemreg; i++) { 225 error = blk_dump(di, sparc64_memreg[i].mr_start, 226 sparc64_memreg[i].mr_size); 227 if (error != 0) 228 goto fail; 229 } 230 231 /* Dump trailer */ 232 error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh)); 233 if (error) 234 goto fail; 235 236 /* Signal completion, signoff and exit stage left. */ 237 dump_write(di, NULL, 0, 0, 0); 238 printf("\nDump complete\n"); 239 return; 240 241 fail: 242 /* XXX It should look more like VMS :-) */ 243 printf("** DUMP FAILED (ERROR %d) **\n", error); 244} 245