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