svn commit: r214903 - in head/sys: conf mips/include mips/mips sys vm

Oleksandr Tymoshenko gonzo at FreeBSD.org
Sun Nov 7 03:09:03 UTC 2010


Author: gonzo
Date: Sun Nov  7 03:09:02 2010
New Revision: 214903
URL: http://svn.freebsd.org/changeset/base/214903

Log:
  - Add minidump support for FreeBSD/mips

Added:
  head/sys/mips/mips/minidump_machdep.c   (contents, props changed)
Modified:
  head/sys/conf/files.mips
  head/sys/mips/include/cpuregs.h
  head/sys/mips/include/md_var.h
  head/sys/mips/include/pmap.h
  head/sys/mips/mips/dump_machdep.c
  head/sys/mips/mips/machdep.c
  head/sys/sys/kerneldump.h
  head/sys/vm/vm_page.c

Modified: head/sys/conf/files.mips
==============================================================================
--- head/sys/conf/files.mips	Sun Nov  7 02:20:34 2010	(r214902)
+++ head/sys/conf/files.mips	Sun Nov  7 03:09:02 2010	(r214903)
@@ -55,6 +55,7 @@ mips/mips/db_trace.c		optional	ddb
 mips/mips/dump_machdep.c	standard
 mips/mips/in_cksum.c		optional	inet
 mips/mips/locore.S		standard	no-obj
+mips/mips/minidump_machdep.c	standard
 mips/mips/mem.c			optional	mem
 mips/mips/nexus.c		standard
 mips/mips/stack_machdep.c	optional	ddb | stack

Modified: head/sys/mips/include/cpuregs.h
==============================================================================
--- head/sys/mips/include/cpuregs.h	Sun Nov  7 02:20:34 2010	(r214902)
+++ head/sys/mips/include/cpuregs.h	Sun Nov  7 03:09:02 2010	(r214903)
@@ -181,6 +181,9 @@
 #define	MIPS_XUSEG_END			0x0000010000000000
 #define	MIPS_XKSEG_START		0xc000000000000000
 #define	MIPS_XKSEG_END			0xc00000ff80000000
+#define	MIPS_XKSEG_COMPAT32_START	0xffffffff80000000
+#define	MIPS_XKSEG_COMPAT32_END		0xffffffffffffffff
+#define	MIPS_XKSEG_TO_COMPAT32(va)	((va) & 0xffffffff)
 
 #ifdef __mips_n64
 #define	MIPS_DIRECT_MAPPABLE(pa)	1

Modified: head/sys/mips/include/md_var.h
==============================================================================
--- head/sys/mips/include/md_var.h	Sun Nov  7 02:20:34 2010	(r214902)
+++ head/sys/mips/include/md_var.h	Sun Nov  7 03:09:02 2010	(r214903)
@@ -42,6 +42,8 @@
 extern	long	Maxmem;
 extern	char	sigcode[];
 extern	int	szsigcode, szosigcode;
+extern	uint32_t *vm_page_dump;
+extern	int vm_page_dump_size;
 
 extern vm_offset_t kstack0;
 extern vm_offset_t kernel_kseg0_end;
@@ -74,4 +76,7 @@ void	platform_identify(void);
 
 extern int busdma_swi_pending;
 void	busdma_swi(void);
+
+struct dumperinfo;
+void minidumpsys(struct dumperinfo *);
 #endif /* !_MACHINE_MD_VAR_H_ */

Modified: head/sys/mips/include/pmap.h
==============================================================================
--- head/sys/mips/include/pmap.h	Sun Nov  7 02:20:34 2010	(r214902)
+++ head/sys/mips/include/pmap.h	Sun Nov  7 03:09:02 2010	(r214903)
@@ -144,6 +144,8 @@ extern vm_offset_t physmem_desc[PHYS_AVA
 extern vm_offset_t virtual_avail;
 extern vm_offset_t virtual_end;
 
+extern vm_paddr_t dump_avail[PHYS_AVAIL_ENTRIES + 2];
+
 #define	pmap_page_get_memattr(m)	VM_MEMATTR_DEFAULT
 #define	pmap_page_is_mapped(m)	(!TAILQ_EMPTY(&(m)->md.pv_list))
 #define	pmap_page_set_memattr(m, ma)	(void)0

Modified: head/sys/mips/mips/dump_machdep.c
==============================================================================
--- head/sys/mips/mips/dump_machdep.c	Sun Nov  7 02:20:34 2010	(r214902)
+++ head/sys/mips/mips/dump_machdep.c	Sun Nov  7 03:09:02 2010	(r214903)
@@ -1,35 +1,362 @@
 /*-
- * Copyright (c) 2006 Oleksandr Tymoshenko
+ * Copyright (c) 2002 Marcel Moolenaar
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification, immediately at the beginning of the file.
- * 2. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
  *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
  *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
-/* Note to writer, when using pmap_kenter_temporary() you must,
- * after using the va to write out the page, call 
- * pmap_kenter_temporary_free().  You should probably also
- * pin the dump thread to the CPU with sched_pin().
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/cons.h>
+#include <sys/sysctl.h>
+#include <sys/kernel.h>
+#include <sys/proc.h>
+#include <sys/kerneldump.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <machine/elf.h>
+#include <machine/md_var.h>
+#include <machine/pcb.h>
+#include <machine/cache.h>
+
+CTASSERT(sizeof(struct kerneldumpheader) == 512);
+
+int do_minidump = 1;
+TUNABLE_INT("debug.minidump", &do_minidump);
+SYSCTL_INT(_debug, OID_AUTO, minidump, CTLFLAG_RW, &do_minidump, 0,
+    "Enable mini crash dumps");
+
+/*
+ * Don't touch the first SIZEOF_METADATA bytes on the dump device. This
+ * is to protect us from metadata and to protect metadata from us.
  */
+#define	SIZEOF_METADATA		(64*1024)
+
+#define	MD_ALIGN(x)	(((off_t)(x) + PAGE_MASK) & ~PAGE_MASK)
+#define	DEV_ALIGN(x)	(((off_t)(x) + (DEV_BSIZE-1)) & ~(DEV_BSIZE-1))
+extern struct pcb dumppcb;
+
+struct md_pa {
+	vm_paddr_t md_start;
+	vm_paddr_t md_size;
+};
+
+typedef int callback_t(struct md_pa *, int, void *);
+
+static struct kerneldumpheader kdh;
+static off_t dumplo, fileofs;
+
+/* Handle buffered writes. */
+static char buffer[DEV_BSIZE];
+static size_t fragsz;
+
+/* XXX: I suppose 20 should be enough. */
+static struct md_pa dump_map[20];
+
+static void
+md_pa_init(void)
+{
+	int n, idx;
+
+	bzero(dump_map, sizeof(dump_map));
+	for (n = 0; n < sizeof(dump_map) / sizeof(dump_map[0]); n++) {
+		idx = n * 2;
+		if (dump_avail[idx] == 0 && dump_avail[idx + 1] == 0)
+			break;
+		dump_map[n].md_start = dump_avail[idx];
+		dump_map[n].md_size = dump_avail[idx + 1] - dump_avail[idx];
+	}
+}
+
+static struct md_pa *
+md_pa_first(void)
+{
+
+	return (&dump_map[0]);
+}
+
+static struct md_pa *
+md_pa_next(struct md_pa *mdp)
+{
+
+	mdp++;
+	if (mdp->md_size == 0)
+		mdp = NULL;
+	return (mdp);
+}
+
+static int
+buf_write(struct dumperinfo *di, char *ptr, size_t sz)
+{
+	size_t len;
+	int error;
+
+	while (sz) {
+		len = DEV_BSIZE - fragsz;
+		if (len > sz)
+			len = sz;
+		bcopy(ptr, buffer + fragsz, len);
+		fragsz += len;
+		ptr += len;
+		sz -= len;
+		if (fragsz == DEV_BSIZE) {
+			error = dump_write(di, buffer, 0, dumplo,
+			    DEV_BSIZE);
+			if (error)
+				return error;
+			dumplo += DEV_BSIZE;
+			fragsz = 0;
+		}
+	}
+
+	return (0);
+}
+
+static int
+buf_flush(struct dumperinfo *di)
+{
+	int error;
+
+	if (fragsz == 0)
+		return (0);
+
+	error = dump_write(di, buffer, 0, dumplo, DEV_BSIZE);
+	dumplo += DEV_BSIZE;
+	fragsz = 0;
+	return (error);
+}
+
+extern vm_offset_t kernel_l1kva;
+extern char *pouet2;
+
+static int
+cb_dumpdata(struct md_pa *mdp, int seqnr, void *arg)
+{
+	struct dumperinfo *di = (struct dumperinfo*)arg;
+	vm_paddr_t pa;
+	uint32_t pgs;
+	size_t counter, sz, chunk;
+	int c, error;
+
+	error = 0;	/* catch case in which chunk size is 0 */
+	counter = 0;
+	pgs = mdp->md_size / PAGE_SIZE;
+	pa = mdp->md_start;
+
+	printf("  chunk %d: %dMB (%d pages)", seqnr, pgs * PAGE_SIZE / (
+	    1024*1024), pgs);
+
+	/* Make sure we write coherent datas. */
+	mips_dcache_wbinv_all();
+	while (pgs) {
+		chunk = pgs;
+		if (chunk > MAXDUMPPGS)
+			chunk = MAXDUMPPGS;
+		sz = chunk << PAGE_SHIFT;
+		counter += sz;
+		if (counter >> 24) {
+			printf(" %d", pgs * PAGE_SIZE);
+			counter &= (1<<24) - 1;
+		}
+
+		error = dump_write(di, (void *)(pa),0, dumplo, sz);
+		if (error)
+			break;
+		dumplo += sz;
+		pgs -= chunk;
+		pa += sz;
+
+		/* Check for user abort. */
+		c = cncheckc();
+		if (c == 0x03)
+			return (ECANCELED);
+		if (c != -1)
+			printf(" (CTRL-C to abort) ");
+	}
+	printf(" ... %s\n", (error) ? "fail" : "ok");
+	return (error);
+}
+
+static int
+cb_dumphdr(struct md_pa *mdp, int seqnr, void *arg)
+{
+	struct dumperinfo *di = (struct dumperinfo*)arg;
+	Elf_Phdr phdr;
+	uint64_t size;
+	int error;
+
+	size = mdp->md_size;
+	bzero(&phdr, sizeof(phdr));
+	phdr.p_type = PT_LOAD;
+	phdr.p_flags = PF_R;			/* XXX */
+	phdr.p_offset = fileofs;
+	phdr.p_vaddr = mdp->md_start;
+	phdr.p_paddr = mdp->md_start;
+	phdr.p_filesz = size;
+	phdr.p_memsz = size;
+	phdr.p_align = PAGE_SIZE;
+
+	error = buf_write(di, (char*)&phdr, sizeof(phdr));
+	fileofs += phdr.p_filesz;
+	return (error);
+}
+
+static int
+cb_size(struct md_pa *mdp, int seqnr, void *arg)
+{
+	uint32_t *sz = (uint32_t*)arg;
+
+	*sz += (uint32_t)mdp->md_size;
+	return (0);
+}
+
+static int
+foreach_chunk(callback_t cb, void *arg)
+{
+	struct md_pa *mdp;
+	int error, seqnr;
+
+	seqnr = 0;
+	mdp = md_pa_first();
+	while (mdp != NULL) {
+		error = (*cb)(mdp, seqnr++, arg);
+		if (error)
+			return (-error);
+		mdp = md_pa_next(mdp);
+	}
+	return (seqnr);
+}
+
+void
+dumpsys(struct dumperinfo *di)
+{
+	Elf_Ehdr ehdr;
+	uint32_t dumpsize;
+	off_t hdrgap;
+	size_t hdrsz;
+	int error;
+
+	if (do_minidump) {
+		minidumpsys(di);
+		return;
+	}
+
+	bzero(&ehdr, sizeof(ehdr));
+	ehdr.e_ident[EI_MAG0] = ELFMAG0;
+	ehdr.e_ident[EI_MAG1] = ELFMAG1;
+	ehdr.e_ident[EI_MAG2] = ELFMAG2;
+	ehdr.e_ident[EI_MAG3] = ELFMAG3;
+	ehdr.e_ident[EI_CLASS] = ELF_CLASS;
+#if BYTE_ORDER == LITTLE_ENDIAN
+	ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
+#else
+	ehdr.e_ident[EI_DATA] = ELFDATA2MSB;
+#endif
+	ehdr.e_ident[EI_VERSION] = EV_CURRENT;
+	ehdr.e_ident[EI_OSABI] = ELFOSABI_STANDALONE;	/* XXX big picture? */
+	ehdr.e_type = ET_CORE;
+	ehdr.e_machine = EM_MIPS;
+	ehdr.e_phoff = sizeof(ehdr);
+	ehdr.e_flags = 0;
+	ehdr.e_ehsize = sizeof(ehdr);
+	ehdr.e_phentsize = sizeof(Elf_Phdr);
+	ehdr.e_shentsize = sizeof(Elf_Shdr);
+
+	md_pa_init();
+
+	/* Calculate dump size. */
+	dumpsize = 0L;
+	ehdr.e_phnum = foreach_chunk(cb_size, &dumpsize);
+	hdrsz = ehdr.e_phoff + ehdr.e_phnum * ehdr.e_phentsize;
+	fileofs = MD_ALIGN(hdrsz);
+	dumpsize += fileofs;
+	hdrgap = fileofs - DEV_ALIGN(hdrsz);
+
+	/* Determine dump offset on device. */
+	if (di->mediasize < SIZEOF_METADATA + dumpsize + sizeof(kdh) * 2) {
+		error = ENOSPC;
+		goto fail;
+	}
+	dumplo = di->mediaoffset + di->mediasize - dumpsize;
+	dumplo -= sizeof(kdh) * 2;
+
+	mkdumpheader(&kdh, KERNELDUMPMAGIC, KERNELDUMP_MIPS_VERSION, dumpsize, di->blocksize);
+
+	printf("Dumping %llu MB (%d chunks)\n", (long long)dumpsize >> 20,
+	    ehdr.e_phnum);
+
+	/* Dump leader */
+	error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh));
+	if (error)
+		goto fail;
+	dumplo += sizeof(kdh);
+
+	/* Dump ELF header */
+	error = buf_write(di, (char*)&ehdr, sizeof(ehdr));
+	if (error)
+		goto fail;
+
+	/* Dump program headers */
+	error = foreach_chunk(cb_dumphdr, di);
+	if (error < 0)
+		goto fail;
+	buf_flush(di);
+
+	/*
+	 * All headers are written using blocked I/O, so we know the
+	 * current offset is (still) block aligned. Skip the alignement
+	 * in the file to have the segment contents aligned at page
+	 * boundary. We cannot use MD_ALIGN on dumplo, because we don't
+	 * care and may very well be unaligned within the dump device.
+	 */
+	dumplo += hdrgap;
+
+	/* Dump memory chunks (updates dumplo) */
+	error = foreach_chunk(cb_dumpdata, di);
+	if (error < 0)
+		goto fail;
+
+	/* Dump trailer */
+	error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh));
+	if (error)
+		goto fail;
+
+	/* Signal completion, signoff and exit stage left. */
+	dump_write(di, NULL, 0, 0, 0);
+	printf("\nDump complete\n");
+	return;
+
+ fail:
+	if (error < 0)
+		error = -error;
+
+	if (error == ECANCELED)
+		printf("\nDump aborted\n");
+	else if (error == ENOSPC)
+		printf("\nDump failed. Partition too small.\n");
+	else
+		printf("\n** DUMP FAILED (ERROR %d) **\n", error);
+}

Modified: head/sys/mips/mips/machdep.c
==============================================================================
--- head/sys/mips/mips/machdep.c	Sun Nov  7 02:20:34 2010	(r214902)
+++ head/sys/mips/mips/machdep.c	Sun Nov  7 03:09:02 2010	(r214903)
@@ -138,6 +138,7 @@ struct pcpu *pcpup = (struct pcpu *)pcpu
 
 vm_offset_t phys_avail[PHYS_AVAIL_ENTRIES + 2];
 vm_offset_t physmem_desc[PHYS_AVAIL_ENTRIES + 2];
+vm_paddr_t dump_avail[PHYS_AVAIL_ENTRIES + 2];
 
 #ifdef UNIMPLEMENTED
 struct platform platform;
@@ -488,13 +489,6 @@ cpu_idle(int busy)
 		panic("ints disabled in idleproc!");
 }
 
-void
-dumpsys(struct dumperinfo *di __unused)
-{
-
-	printf("Kernel dumps not implemented on this architecture\n");
-}
-
 int
 cpu_idle_wakeup(int cpu)
 {

Added: head/sys/mips/mips/minidump_machdep.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/mips/mips/minidump_machdep.c	Sun Nov  7 03:09:02 2010	(r214903)
@@ -0,0 +1,340 @@
+/*-
+ * Copyright (c) 2010 Oleksandr Tymoshenko <gonzo at freebsd.org>
+ * Copyright (c) 2008 Semihalf, Grzegorz Bernacki
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * from: FreeBSD: src/sys/arm/arm/minidump_machdep.c v214223
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/cons.h>
+#include <sys/kernel.h>
+#include <sys/kerneldump.h>
+#include <sys/msgbuf.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <machine/pmap.h>
+#include <machine/atomic.h>
+#include <machine/elf.h>
+#include <machine/md_var.h>
+#include <machine/vmparam.h>
+#include <machine/minidump.h>
+#include <machine/cache.h>
+
+CTASSERT(sizeof(struct kerneldumpheader) == 512);
+
+/*
+ * Don't touch the first SIZEOF_METADATA bytes on the dump device. This
+ * is to protect us from metadata and to protect metadata from us.
+ */
+#define	SIZEOF_METADATA		(64*1024)
+
+uint32_t *vm_page_dump;
+int vm_page_dump_size;
+
+static struct kerneldumpheader kdh;
+static off_t dumplo;
+static off_t origdumplo;
+
+/* Handle chunked writes. */
+static uint64_t counter, progress;
+/* Just auxiliary bufffer */
+static char tmpbuffer[PAGE_SIZE];
+
+extern pd_entry_t *kernel_segmap;
+
+CTASSERT(sizeof(*vm_page_dump) == 4);
+
+static int
+is_dumpable(vm_paddr_t pa)
+{
+	int i;
+
+	for (i = 0; dump_avail[i] != 0 || dump_avail[i + 1] != 0; i += 2) {
+		if (pa >= dump_avail[i] && pa < dump_avail[i + 1])
+			return (1);
+	}
+	return (0);
+}
+
+static void
+dump_add_page(vm_paddr_t pa)
+{
+	int idx, bit;
+
+	pa >>= PAGE_SHIFT;
+	idx = pa >> 5;		/* 2^5 = 32 */
+	bit = pa & 31;
+	atomic_set_int(&vm_page_dump[idx], 1ul << bit);
+}
+
+static void
+dump_drop_page(vm_paddr_t pa)
+{
+	int idx, bit;
+
+	pa >>= PAGE_SHIFT;
+	idx = pa >> 5;		/* 2^5 = 32 */
+	bit = pa & 31;
+	atomic_clear_int(&vm_page_dump[idx], 1ul << bit);
+}
+
+#define PG2MB(pgs) (((pgs) + (1 << 8) - 1) >> 8)
+
+static int
+write_buffer(struct dumperinfo *di, char *ptr, size_t sz)
+{
+	size_t len;
+	int error, c;
+	u_int maxdumpsz;
+
+	maxdumpsz = di->maxiosize;
+
+	if (maxdumpsz == 0)	/* seatbelt */
+		maxdumpsz = PAGE_SIZE;
+
+	error = 0;
+
+	while (sz) {
+		len = min(maxdumpsz, sz);
+		counter += len;
+		progress -= len;
+
+		if (counter >> 22) {
+			printf(" %jd", PG2MB(progress >> PAGE_SHIFT));
+			counter &= (1<<22) - 1;
+		}
+
+		if (ptr) {
+			error = dump_write(di, ptr, 0, dumplo, len);
+			if (error)
+				return (error);
+			dumplo += len;
+			ptr += len;
+			sz -= len;
+		} else {
+			panic("pa is not supported");
+		}
+
+		/* Check for user abort. */
+		c = cncheckc();
+		if (c == 0x03)
+			return (ECANCELED);
+		if (c != -1)
+			printf(" (CTRL-C to abort) ");
+	}
+
+	return (0);
+}
+
+void
+minidumpsys(struct dumperinfo *di)
+{
+	struct minidumphdr mdhdr;
+	uint64_t dumpsize;
+	uint32_t ptesize;
+	uint32_t bits;
+	vm_paddr_t pa;
+	vm_offset_t prev_pte = 0;
+	uint32_t count = 0;
+	vm_offset_t va;
+	pt_entry_t *pte;
+	int i, bit, error;
+	void *dump_va;
+
+	/* Flush cache */
+	mips_dcache_wbinv_all();
+
+	counter = 0;
+	/* Walk page table pages, set bits in vm_page_dump */
+	ptesize = 0;
+
+	for (va = VM_MIN_KERNEL_ADDRESS; va < kernel_vm_end; va += NBPDR) {
+		ptesize += PAGE_SIZE;
+		pte = pmap_pte(kernel_pmap, va);
+		KASSERT(pte != NULL, ("pte for %jx is NULL", (uintmax_t)va));
+		for (i = 0; i < NPTEPG; i++) {
+			if (pte_test(&pte[i], PTE_V)) {
+				pa = TLBLO_PTE_TO_PA(pte[i]);
+				if (is_dumpable(pa))
+					dump_add_page(pa);
+			}
+		}
+	}
+
+	/*
+	 * Now mark pages from 0 to phys_avail[0], that's where kernel 
+	 * and pages allocated by pmap_steal reside
+	 */
+	for (pa = 0; pa < phys_avail[0]; pa += PAGE_SIZE) {
+		if (is_dumpable(pa))
+			dump_add_page(pa);
+	}
+
+	/* Calculate dump size. */
+	dumpsize = ptesize;
+	dumpsize += round_page(msgbufp->msg_size);
+	dumpsize += round_page(vm_page_dump_size);
+
+	for (i = 0; i < vm_page_dump_size / sizeof(*vm_page_dump); i++) {
+		bits = vm_page_dump[i];
+		while (bits) {
+			bit = ffs(bits) - 1;
+			pa = (((uint64_t)i * sizeof(*vm_page_dump) * NBBY) +
+			    bit) * PAGE_SIZE;
+			/* Clear out undumpable pages now if needed */
+			if (is_dumpable(pa))
+				dumpsize += PAGE_SIZE;
+			else
+				dump_drop_page(pa);
+			bits &= ~(1ul << bit);
+		}
+	}
+
+	dumpsize += PAGE_SIZE;
+
+	/* Determine dump offset on device. */
+	if (di->mediasize < SIZEOF_METADATA + dumpsize + sizeof(kdh) * 2) {
+		error = ENOSPC;
+		goto fail;
+	}
+
+	origdumplo = dumplo = di->mediaoffset + di->mediasize - dumpsize;
+	dumplo -= sizeof(kdh) * 2;
+	progress = dumpsize;
+
+	/* Initialize mdhdr */
+	bzero(&mdhdr, sizeof(mdhdr));
+	strcpy(mdhdr.magic, MINIDUMP_MAGIC);
+	mdhdr.version = MINIDUMP_VERSION;
+	mdhdr.msgbufsize = msgbufp->msg_size;
+	mdhdr.bitmapsize = vm_page_dump_size;
+	mdhdr.ptesize = ptesize;
+	mdhdr.kernbase = VM_MIN_KERNEL_ADDRESS;
+
+	mkdumpheader(&kdh, KERNELDUMPMAGIC, KERNELDUMP_MIPS_VERSION, dumpsize,
+	    di->blocksize);
+
+	printf("Physical memory: %ju MB\n", 
+	    (uintmax_t)ptoa((uintmax_t)physmem) / 1048576);
+	printf("Dumping %llu MB:", (long long)dumpsize >> 20);
+
+	/* Dump leader */
+	error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh));
+	if (error)
+		goto fail;
+	dumplo += sizeof(kdh);
+
+	/* Dump my header */
+	bzero(tmpbuffer, sizeof(tmpbuffer));
+	bcopy(&mdhdr, tmpbuffer, sizeof(mdhdr));
+	error = write_buffer(di, tmpbuffer, PAGE_SIZE);
+	if (error)
+		goto fail;
+
+	/* Dump msgbuf up front */
+	error = write_buffer(di, (char *)msgbufp->msg_ptr, 
+	    round_page(msgbufp->msg_size));
+	if (error)
+		goto fail;
+
+	/* Dump bitmap */
+	error = write_buffer(di, (char *)vm_page_dump,
+	    round_page(vm_page_dump_size));
+	if (error)
+		goto fail;
+
+	/* Dump kernel page table pages */
+	for (va = VM_MIN_KERNEL_ADDRESS; va < kernel_vm_end; va += NBPDR) {
+		pte = pmap_pte(kernel_pmap, va);
+		KASSERT(pte != NULL, ("pte for %jx is NULL", (uintmax_t)va));
+		if (!count) {
+			prev_pte = (vm_offset_t)pte;
+			count++;
+		}
+		else {
+			if ((vm_offset_t)pte == (prev_pte + count * PAGE_SIZE))
+				count++;
+			else {
+				error = write_buffer(di, (char*)prev_pte,
+				    count * PAGE_SIZE);
+				if (error)
+					goto fail;
+				count = 1;
+				prev_pte = (vm_offset_t)pte;
+			}
+		}
+	}
+
+	if (count) {
+		error = write_buffer(di, (char*)prev_pte, count * PAGE_SIZE);
+		if (error)
+			goto fail;
+		count = 0;
+		prev_pte = 0;
+	}
+
+	/* Dump memory chunks  page by page*/
+	for (i = 0; i < vm_page_dump_size / sizeof(*vm_page_dump); i++) {
+		bits = vm_page_dump[i];
+		while (bits) {
+			bit = ffs(bits) - 1;
+			pa = (((uint64_t)i * sizeof(*vm_page_dump) * NBBY) +
+			    bit) * PAGE_SIZE;
+			dump_va = pmap_kenter_temporary(pa, 0);
+			error = write_buffer(di, dump_va, PAGE_SIZE);
+			if (error)
+				goto fail;
+			pmap_kenter_temporary_free(pa);
+			bits &= ~(1ul << bit);
+		}
+	}
+
+	/* Dump trailer */
+	error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh));
+	if (error)
+		goto fail;
+	dumplo += sizeof(kdh);
+
+	/* Signal completion, signoff and exit stage left. */
+	dump_write(di, NULL, 0, 0, 0);
+	printf("\nDump complete\n");
+	return;
+
+fail:
+	if (error < 0)
+		error = -error;
+
+	if (error == ECANCELED)
+		printf("\nDump aborted\n");
+	else if (error == ENOSPC)
+		printf("\nDump failed. Partition too small.\n");
+	else
+		printf("\n** DUMP FAILED (ERROR %d) **\n", error);
+}

Modified: head/sys/sys/kerneldump.h
==============================================================================
--- head/sys/sys/kerneldump.h	Sun Nov  7 02:20:34 2010	(r214902)
+++ head/sys/sys/kerneldump.h	Sun Nov  7 03:09:02 2010	(r214903)
@@ -71,6 +71,7 @@ struct kerneldumpheader {
 #define	KERNELDUMP_ARM_VERSION		1
 #define	KERNELDUMP_I386_VERSION		2
 #define	KERNELDUMP_IA64_VERSION		1
+#define	KERNELDUMP_MIPS_VERSION		1
 #define	KERNELDUMP_POWERPC_VERSION	1
 #define	KERNELDUMP_SPARC64_VERSION	1
 #define	KERNELDUMP_TEXT_VERSION		1

Modified: head/sys/vm/vm_page.c
==============================================================================
--- head/sys/vm/vm_page.c	Sun Nov  7 02:20:34 2010	(r214902)
+++ head/sys/vm/vm_page.c	Sun Nov  7 03:09:02 2010	(r214903)
@@ -359,7 +359,8 @@ vm_page_startup(vm_offset_t vaddr)
 	bzero((void *)mapped, end - new_end);
 	uma_startup((void *)mapped, boot_pages);
 
-#if defined(__amd64__) || defined(__i386__) || defined(__arm__)
+#if defined(__amd64__) || defined(__i386__) || defined(__arm__) || \
+    defined(__mips__)
 	/*
 	 * Allocate a bitmap to indicate that a random physical page
 	 * needs to be included in a minidump.


More information about the svn-src-head mailing list