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