1139825Simp/*- 296485Sjake * Copyright (c) 2002 Marcel Moolenaar 3105531Stmm * Copyright (c) 2002 Thomas Moestl 496485Sjake * All rights reserved. 596485Sjake * 696485Sjake * Redistribution and use in source and binary forms, with or without 796485Sjake * modification, are permitted provided that the following conditions 896485Sjake * are met: 996485Sjake * 1096485Sjake * 1. Redistributions of source code must retain the above copyright 1196485Sjake * notice, this list of conditions and the following disclaimer. 1296485Sjake * 2. Redistributions in binary form must reproduce the above copyright 1396485Sjake * notice, this list of conditions and the following disclaimer in the 1496485Sjake * documentation and/or other materials provided with the distribution. 1596485Sjake * 1696485Sjake * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1796485Sjake * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1896485Sjake * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1996485Sjake * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2096485Sjake * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2196485Sjake * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2296485Sjake * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2396485Sjake * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2496485Sjake * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2596485Sjake * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2696485Sjake */ 2796485Sjake 28224682Smarius#include <sys/cdefs.h> 29224682Smarius__FBSDID("$FreeBSD$"); 30224682Smarius 3196485Sjake#include <sys/param.h> 3296485Sjake#include <sys/systm.h> 3396485Sjake#include <sys/conf.h> 34105531Stmm#include <sys/cons.h> 3596485Sjake#include <sys/kernel.h> 3696485Sjake#include <sys/kerneldump.h> 37105531Stmm 3896485Sjake#include <vm/vm.h> 39108301Sjake#include <vm/vm_param.h> 4096485Sjake#include <vm/pmap.h> 4196485Sjake 42105531Stmm#include <machine/metadata.h> 43105531Stmm#include <machine/kerneldump.h> 44105531Stmm#include <machine/ofw_mem.h> 45105531Stmm#include <machine/tsb.h> 46108301Sjake#include <machine/tlb.h> 4796485Sjake 48105531StmmCTASSERT(sizeof(struct kerneldumpheader) == DEV_BSIZE); 4996485Sjake 5096485Sjakestatic struct kerneldumpheader kdh; 51105531Stmmstatic off_t dumplo, dumppos; 5296485Sjake 5396485Sjake/* Handle buffered writes. */ 5496485Sjakestatic char buffer[DEV_BSIZE]; 55105531Stmmstatic vm_size_t fragsz; 5696485Sjake 57105531Stmm#define MAXDUMPSZ (MAXDUMPPGS << PAGE_SHIFT) 58105531Stmm 5996485Sjakestatic int 6096485Sjakebuf_write(struct dumperinfo *di, char *ptr, size_t sz) 6196485Sjake{ 6296485Sjake size_t len; 6396485Sjake int error; 6496485Sjake 6596485Sjake while (sz) { 6696485Sjake len = DEV_BSIZE - fragsz; 6796485Sjake if (len > sz) 6896485Sjake len = sz; 6996485Sjake bcopy(ptr, buffer + fragsz, len); 7096485Sjake fragsz += len; 7196485Sjake ptr += len; 7296485Sjake sz -= len; 7396485Sjake if (fragsz == DEV_BSIZE) { 74175768Sru error = dump_write(di, buffer, 0, dumplo, 7596485Sjake DEV_BSIZE); 7696485Sjake if (error) 7796485Sjake return error; 7896485Sjake dumplo += DEV_BSIZE; 7996485Sjake fragsz = 0; 8096485Sjake } 8196485Sjake } 8296485Sjake 8396485Sjake return (0); 8496485Sjake} 8596485Sjake 8696485Sjakestatic int 8796485Sjakebuf_flush(struct dumperinfo *di) 8896485Sjake{ 8996485Sjake int error; 9096485Sjake 9196485Sjake if (fragsz == 0) 9296485Sjake return (0); 9396485Sjake 94175768Sru error = dump_write(di, buffer, 0, dumplo, DEV_BSIZE); 9596485Sjake dumplo += DEV_BSIZE; 96224682Smarius fragsz = 0; 9796485Sjake return (error); 9896485Sjake} 9996485Sjake 10096485Sjakestatic int 101113238Sjakereg_write(struct dumperinfo *di, vm_paddr_t pa, vm_size_t size) 10296485Sjake{ 103105531Stmm struct sparc64_dump_reg r; 10496485Sjake 105105531Stmm r.dr_pa = pa; 106105531Stmm r.dr_size = size; 107105531Stmm r.dr_offs = dumppos; 108105531Stmm dumppos += size; 109105531Stmm return (buf_write(di, (char *)&r, sizeof(r))); 110105531Stmm} 11196485Sjake 112105531Stmmstatic int 113113238Sjakeblk_dump(struct dumperinfo *di, vm_paddr_t pa, vm_size_t size) 114105531Stmm{ 115108301Sjake vm_size_t pos, rsz; 116108301Sjake vm_offset_t va; 117108301Sjake int c, counter, error, twiddle; 11896485Sjake 119105531Stmm printf(" chunk at %#lx: %ld bytes ", (u_long)pa, (long)size); 120105531Stmm 121123866Sobrien va = 0L; 122105531Stmm error = counter = twiddle = 0; 123105531Stmm for (pos = 0; pos < size; pos += MAXDUMPSZ, counter++) { 124105531Stmm if (counter % 128 == 0) 12596485Sjake printf("%c\b", "|/-\\"[twiddle++ & 3]); 126105531Stmm rsz = size - pos; 127105531Stmm rsz = (rsz > MAXDUMPSZ) ? MAXDUMPSZ : rsz; 128108301Sjake va = TLB_PHYS_TO_DIRECT(pa + pos); 129175768Sru error = dump_write(di, (void *)va, 0, dumplo, rsz); 13096485Sjake if (error) 13196485Sjake break; 132105531Stmm dumplo += rsz; 133105531Stmm 134105531Stmm /* Check for user abort. */ 135105531Stmm c = cncheckc(); 136105531Stmm if (c == 0x03) 137105531Stmm return (ECANCELED); 138105531Stmm if (c != -1) 139105531Stmm printf("(CTRL-C to abort) "); 14096485Sjake } 14196485Sjake printf("... %s\n", (error) ? "fail" : "ok"); 14296485Sjake return (error); 14396485Sjake} 14496485Sjake 14596485Sjakevoid 14696485Sjakedumpsys(struct dumperinfo *di) 14796485Sjake{ 148105531Stmm struct sparc64_dump_hdr hdr; 149105531Stmm vm_size_t size, totsize, hdrsize; 150105531Stmm int error, i, nreg; 15196485Sjake 15296485Sjake /* Calculate dump size. */ 153105531Stmm size = 0; 154105531Stmm nreg = sparc64_nmemreg; 155105531Stmm for (i = 0; i < sparc64_nmemreg; i++) 156105531Stmm size += sparc64_memreg[i].mr_size; 157105531Stmm /* Account for the header size. */ 158105531Stmm hdrsize = roundup2(sizeof(hdr) + sizeof(struct sparc64_dump_reg) * nreg, 159105531Stmm DEV_BSIZE); 160105531Stmm size += hdrsize; 16196485Sjake 162105531Stmm totsize = size + 2 * sizeof(kdh); 163105531Stmm if (totsize > di->mediasize) { 164105531Stmm printf("Insufficient space on device (need %ld, have %ld), " 165105531Stmm "refusing to dump.\n", (long)totsize, 166105531Stmm (long)di->mediasize); 167105531Stmm error = ENOSPC; 168105531Stmm goto fail; 169105531Stmm } 170105531Stmm 17196485Sjake /* Determine dump offset on device. */ 172105531Stmm dumplo = di->mediaoffset + di->mediasize - totsize; 17396485Sjake 174224682Smarius mkdumpheader(&kdh, KERNELDUMPMAGIC, KERNELDUMP_SPARC64_VERSION, size, 175224682Smarius di->blocksize); 17696485Sjake 177105531Stmm printf("Dumping %lu MB (%d chunks)\n", (u_long)(size >> 20), nreg); 17896485Sjake 17996485Sjake /* Dump leader */ 180175768Sru error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh)); 18196485Sjake if (error) 18296485Sjake goto fail; 18396485Sjake dumplo += sizeof(kdh); 18496485Sjake 185105531Stmm /* Dump the private header. */ 186105531Stmm hdr.dh_hdr_size = hdrsize; 187105531Stmm hdr.dh_tsb_pa = tsb_kernel_phys; 188105531Stmm hdr.dh_tsb_size = tsb_kernel_size; 189105531Stmm hdr.dh_tsb_mask = tsb_kernel_mask; 190105531Stmm hdr.dh_nregions = nreg; 191105531Stmm 192105531Stmm if (buf_write(di, (char *)&hdr, sizeof(hdr)) != 0) 19396485Sjake goto fail; 19496485Sjake 195105531Stmm dumppos = hdrsize; 196105531Stmm /* Now, write out the region descriptors. */ 197105531Stmm for (i = 0; i < sparc64_nmemreg; i++) { 198105531Stmm error = reg_write(di, sparc64_memreg[i].mr_start, 199105531Stmm sparc64_memreg[i].mr_size); 200105531Stmm if (error != 0) 201105531Stmm goto fail; 202105531Stmm } 20396485Sjake buf_flush(di); 20496485Sjake 205105531Stmm /* Dump memory chunks. */ 206105531Stmm for (i = 0; i < sparc64_nmemreg; i++) { 207105531Stmm error = blk_dump(di, sparc64_memreg[i].mr_start, 208105531Stmm sparc64_memreg[i].mr_size); 209105531Stmm if (error != 0) 210105531Stmm goto fail; 211105531Stmm } 21296485Sjake 21396485Sjake /* Dump trailer */ 214175768Sru error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh)); 21596485Sjake if (error) 21696485Sjake goto fail; 21796485Sjake 21896485Sjake /* Signal completion, signoff and exit stage left. */ 219175768Sru dump_write(di, NULL, 0, 0, 0); 22096485Sjake printf("\nDump complete\n"); 22196485Sjake return; 22296485Sjake 22396485Sjake fail: 22496485Sjake /* XXX It should look more like VMS :-) */ 22596485Sjake printf("** DUMP FAILED (ERROR %d) **\n", error); 22696485Sjake} 227