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 <go...@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.
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to