Module Name:    src
Committed By:   mrg
Date:           Fri Nov  9 04:05:27 UTC 2018

Modified Files:
        src/sys/arch/aarch64/aarch64: aarch64_machdep.c aarch64_reboot.c
        src/sys/arch/aarch64/include: kcore.h

Log Message:
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@.


To generate a diff of this commit:
cvs rdiff -u -r1.18 -r1.19 src/sys/arch/aarch64/aarch64/aarch64_machdep.c
cvs rdiff -u -r1.2 -r1.3 src/sys/arch/aarch64/aarch64/aarch64_reboot.c
cvs rdiff -u -r1.1 -r1.2 src/sys/arch/aarch64/include/kcore.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/aarch64/aarch64/aarch64_machdep.c
diff -u src/sys/arch/aarch64/aarch64/aarch64_machdep.c:1.18 src/sys/arch/aarch64/aarch64/aarch64_machdep.c:1.19
--- src/sys/arch/aarch64/aarch64/aarch64_machdep.c:1.18	Thu Nov  1 20:34:49 2018
+++ src/sys/arch/aarch64/aarch64/aarch64_machdep.c	Fri Nov  9 04:05:27 2018
@@ -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 @@ __KERNEL_RCSID(1, "$NetBSD: aarch64_mach
 #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 @@ __KERNEL_RCSID(1, "$NetBSD: aarch64_mach
 #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 @@ u_long kern_vtopdiff __attribute__((__se
 
 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 @@ cpu_startup(void)
 	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;
 }

Index: src/sys/arch/aarch64/aarch64/aarch64_reboot.c
diff -u src/sys/arch/aarch64/aarch64/aarch64_reboot.c:1.2 src/sys/arch/aarch64/aarch64/aarch64_reboot.c:1.3
--- src/sys/arch/aarch64/aarch64/aarch64_reboot.c:1.2	Thu May 31 23:22:50 2018
+++ src/sys/arch/aarch64/aarch64/aarch64_reboot.c	Fri Nov  9 04:05:27 2018
@@ -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 @@ cpu_reboot(int howto, char *bootstr)
 	/* Say NO to interrupts for the duration of the dump */
 	int s = splhigh();
 
-#if notyet	/* XXX */
 	/* Do a dump if requested. */
 	if ((howto & (RB_DUMP | RB_HALT)) == RB_DUMP)
 		dumpsys();
-#endif
 
 	splx(s);
 

Index: src/sys/arch/aarch64/include/kcore.h
diff -u src/sys/arch/aarch64/include/kcore.h:1.1 src/sys/arch/aarch64/include/kcore.h:1.2
--- src/sys/arch/aarch64/include/kcore.h:1.1	Sun Aug 10 05:47:38 2014
+++ src/sys/arch/aarch64/include/kcore.h	Fri Nov  9 04:05:27 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: kcore.h,v 1.1 2014/08/10 05:47:38 matt Exp $ */
+/* $NetBSD: kcore.h,v 1.2 2018/11/09 04:05:27 mrg Exp $ */
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -37,6 +37,7 @@
 typedef struct cpu_kcore_hdr {
 	uint64_t kh_tcr1;		/* TCR for EL1 */
 	uint64_t kh_ttbr1;		/* TTBR for EL1 */
+	uint64_t kh_nramsegs;
 	phys_ram_seg_t kh_ramsegs[0];
 } cpu_kcore_hdr_t;
 

Reply via email to