Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/aarch64 implement dumpsys() and friends for arm64.



details:   https://anonhg.NetBSD.org/src/rev/0702051ba622
branches:  trunk
changeset: 445686:0702051ba622
user:      mrg <mrg%NetBSD.org@localhost>
date:      Fri Nov 09 04:05:27 2018 +0000

description:
implement dumpsys() and friends for arm64.

this is almost a direct copy of the arm code, which is simply
as the basic structures about physical memory are the same
between arm and arm64.  the main change i made was to use
the direct map instead of a virtual dump page that is remapped
to whatever physical page is being dumped.

i also changed the existing cpu_kcore_hdr_t to include the
missing number of ram segments.

note that this is not a complete solution for crash dumps yet,
as the libkvm code needs some work.  i'm fairly positive that
this side is correct, as i can see the data i expect to see,
but libkvm's _kvm_kvtop() function returns garbage so far.

there is no "minidump" support here yet, ala amd64, but we
probably want it eventually.


ok skrll@.

diffstat:

 sys/arch/aarch64/aarch64/aarch64_machdep.c |  237 ++++++++++++++++++++++++++++-
 sys/arch/aarch64/aarch64/aarch64_reboot.c  |    6 +-
 sys/arch/aarch64/include/kcore.h           |    3 +-
 3 files changed, 239 insertions(+), 7 deletions(-)

diffs (truncated from 327 to 300 lines):

diff -r 6f75056aa559 -r 0702051ba622 sys/arch/aarch64/aarch64/aarch64_machdep.c
--- a/sys/arch/aarch64/aarch64/aarch64_machdep.c        Fri Nov 09 02:11:04 2018 +0000
+++ b/sys/arch/aarch64/aarch64/aarch64_machdep.c        Fri Nov 09 04:05:27 2018 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: aarch64_machdep.c,v 1.18 2018/11/01 20:34:49 maxv Exp $ */
+/* $NetBSD: aarch64_machdep.c,v 1.19 2018/11/09 04:05:27 mrg Exp $ */
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(1, "$NetBSD: aarch64_machdep.c,v 1.18 2018/11/01 20:34:49 maxv Exp $");
+__KERNEL_RCSID(1, "$NetBSD: aarch64_machdep.c,v 1.19 2018/11/09 04:05:27 mrg Exp $");
 
 #include "opt_arm_debug.h"
 #include "opt_ddb.h"
@@ -47,6 +47,9 @@
 #include <sys/msgbuf.h>
 #include <sys/sysctl.h>
 #include <sys/reboot.h>
+#include <sys/kcore.h>
+#include <sys/core.h>
+#include <sys/conf.h>
 #include <sys/asan.h>
 
 #include <dev/mm.h>
@@ -65,6 +68,7 @@
 #include <aarch64/pmap.h>
 #include <aarch64/pte.h>
 #include <aarch64/vmparam.h>
+#include <aarch64/kcore.h>
 
 #include <arch/evbarm/fdt/platform.h>
 #include <arm/fdt/arm_fdtvar.h>
@@ -107,6 +111,15 @@
 
 long kernend_extra;    /* extra memory allocated from round_page(_end[]) */
 
+/* dump configuration */
+int    cpu_dump(void);
+int    cpu_dumpsize(void);
+u_long cpu_dump_mempagecnt(void);
+
+uint32_t dumpmag = 0x8fca0101;  /* magic number for savecore */
+int     dumpsize = 0;           /* also for savecore */
+long    dumplo = 0;
+
 void
 cpu_kernel_vm_init(uint64_t memory_start, uint64_t memory_size)
 {
@@ -646,7 +659,227 @@
        banner();
 }
 
+/*
+ * cpu_dump: dump the machine-dependent kernel core dump headers.
+ */
+int
+cpu_dump(void)
+{
+       int (*dump)(dev_t, daddr_t, void *, size_t);
+       char bf[dbtob(1)];
+       kcore_seg_t *segp;
+       cpu_kcore_hdr_t *cpuhdrp;
+       phys_ram_seg_t *memsegp;
+       const struct bdevsw *bdev;
+       int i;
+
+       bdev = bdevsw_lookup(dumpdev);
+       if (bdev == NULL)
+               return (ENXIO);
+       dump = bdev->d_dump;
+
+       memset(bf, 0, sizeof bf);
+       segp = (kcore_seg_t *)bf;
+       cpuhdrp = (cpu_kcore_hdr_t *)&bf[ALIGN(sizeof(*segp))];
+       memsegp = &cpuhdrp->kh_ramsegs[0];
+
+       /*
+        * Generate a segment header.
+        */
+       CORE_SETMAGIC(*segp, KCORE_MAGIC, MID_MACHINE, CORE_CPU);
+       segp->c_size = dbtob(1) - ALIGN(sizeof(*segp));
+
+       /*
+        * Add the machine-dependent header info.
+        */
+       cpuhdrp->kh_tcr1 = reg_tcr_el1_read();
+       cpuhdrp->kh_ttbr1 = reg_ttbr1_el1_read();
+       cpuhdrp->kh_nramsegs = bootconfig.dramblocks;
+
+       /*
+        * Fill in the memory segment descriptors.
+        */
+       for (i = 0; i < bootconfig.dramblocks; i++) {
+               memsegp[i].start = bootconfig.dram[i].address;
+               memsegp[i].size = bootconfig.dram[i].pages * PAGE_SIZE;
+       }
+
+       return (dump(dumpdev, dumplo, bf, dbtob(1)));
+}
+
+void
+dumpsys(void)
+{
+       const struct bdevsw *bdev;
+       daddr_t blkno;
+       int psize;
+       int error;
+       paddr_t addr = 0;
+       int block;
+       psize_t len;
+       vaddr_t dumpspace;
+
+       /* flush everything out of caches */
+       cpu_dcache_wbinv_all();
+
+       if (dumpdev == NODEV)
+               return;
+       if (dumpsize == 0) {
+               cpu_dumpconf();
+       }
+       if (dumplo <= 0 || dumpsize == 0) {
+               printf("\ndump to dev %u,%u not possible\n",
+                   major(dumpdev), minor(dumpdev));
+               delay(5000000);
+               return;
+       }
+       printf("\ndumping to dev %u,%u offset %ld\n",
+           major(dumpdev), minor(dumpdev), dumplo);
+
+
+       bdev = bdevsw_lookup(dumpdev);
+       if (bdev == NULL || bdev->d_psize == NULL)
+               return;
+       psize = bdev_size(dumpdev);
+       printf("dump ");
+       if (psize == -1) {
+               printf("area unavailable\n");
+               return;
+       }
+
+       if ((error = cpu_dump()) != 0)
+               goto err;
+
+       blkno = dumplo + cpu_dumpsize();
+       error = 0;
+       len = 0;
+
+       for (block = 0; block < bootconfig.dramblocks && error == 0; ++block) {
+               addr = bootconfig.dram[block].address;
+               for (; addr < (bootconfig.dram[block].address
+                              + (bootconfig.dram[block].pages * PAGE_SIZE));
+                    addr += PAGE_SIZE) {
+                       if ((len % (1024*1024)) == 0)
+                               printf("%lu ", len / (1024*1024));
+
+                       if (!mm_md_direct_mapped_phys(addr, &dumpspace)) {
+                               error = ENOMEM;
+                               goto err;
+                       }
+                       error = (*bdev->d_dump)(dumpdev,
+                           blkno, (void *) dumpspace, PAGE_SIZE);
+
+                       if (error)
+                               goto err;
+                       blkno += btodb(PAGE_SIZE);
+                       len += PAGE_SIZE;
+               }
+       }
+err:
+       switch (error) {
+       case ENXIO:
+               printf("device bad\n");
+               break;
+
+       case EFAULT:
+               printf("device not ready\n");
+               break;
+
+       case EINVAL:
+               printf("area improper\n");
+               break;
+
+       case EIO:
+               printf("i/o error\n");
+               break;
+
+       case EINTR:
+               printf("aborted from console\n");
+               break;
+
+       case ENOMEM:
+               printf("no direct map for %lx\n", addr);
+               break;
+
+       case 0:
+               printf("succeeded\n");
+               break;
+
+       default:
+               printf("error %d\n", error);
+               break;
+       }
+       printf("\n\n");
+       delay(5000000);
+}
+
+/*
+ * cpu_dumpsize: calculate size of machine-dependent kernel core dump headers.
+ */
+int
+cpu_dumpsize(void)
+{
+       int size;
+
+       size = ALIGN(sizeof(kcore_seg_t)) + ALIGN(sizeof(cpu_kcore_hdr_t)) +
+           ALIGN(bootconfig.dramblocks * sizeof(phys_ram_seg_t));
+       if (roundup(size, dbtob(1)) != dbtob(1))
+               return -1;
+
+       return (1);
+}
+
+/*
+ * cpu_dump_mempagecnt: calculate the size of RAM (in pages) to be dumped.
+ */
+u_long
+cpu_dump_mempagecnt(void)
+{
+       u_long i, n;
+
+       n = 0;
+       for (i = 0; i < bootconfig.dramblocks; i++) {
+               n += bootconfig.dram[i].pages;
+       }
+
+       return (n);
+}
+
+/*
+ * This is called by main to set dumplo and dumpsize.
+ * Dumps always skip the first PAGE_SIZE of disk space
+ * in case there might be a disk label stored there.
+ * If there is extra space, put dump at the end to
+ * reduce the chance that swapping trashes it.
+ */
+
 void
 cpu_dumpconf(void)
 {
+       u_long nblks, dumpblks; /* size of dump area */
+
+       if (dumpdev == NODEV)
+               return;
+       nblks = bdev_size(dumpdev);
+       if (nblks <= ctod(1))
+               return;
+
+       dumpblks = cpu_dumpsize();
+       if (dumpblks < 0)
+               goto bad;
+       dumpblks += ctod(cpu_dump_mempagecnt());
+
+       /* If dump won't fit (incl. room for possible label), punt. */
+       if (dumpblks > (nblks - ctod(1)))
+               goto bad;
+
+       /* Put dump at end of partition */
+       dumplo = nblks - dumpblks;
+
+       /* dumpsize is in page units, and doesn't include headers. */
+       dumpsize = cpu_dump_mempagecnt();
+       return;
+
+ bad:
+       dumpsize = 0;
 }
diff -r 6f75056aa559 -r 0702051ba622 sys/arch/aarch64/aarch64/aarch64_reboot.c
--- a/sys/arch/aarch64/aarch64/aarch64_reboot.c Fri Nov 09 02:11:04 2018 +0000
+++ b/sys/arch/aarch64/aarch64/aarch64_reboot.c Fri Nov 09 04:05:27 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: aarch64_reboot.c,v 1.2 2018/05/31 23:22:50 mrg Exp $   */
+/*     $NetBSD: aarch64_reboot.c,v 1.3 2018/11/09 04:05:27 mrg Exp $   */
 
 /*
  * Copyright (c) 2002, 2003, 2005  Genetec Corporation.  All rights reserved.
@@ -122,7 +122,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: aarch64_reboot.c,v 1.2 2018/05/31 23:22:50 mrg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: aarch64_reboot.c,v 1.3 2018/11/09 04:05:27 mrg Exp $");
 
 #include <sys/param.h>
 #include <sys/device.h>
@@ -236,11 +236,9 @@
        /* Say NO to interrupts for the duration of the dump */



Home | Main Index | Thread Index | Old Index