Subject: Initial diffs to make arm32 kernel core dumps work with savecore
To: None <port-arm@netbsd.org>
From: Chris Gilbert <chris@dokein.co.uk>
List: port-arm
Date: 12/15/2007 01:03:09
This is a multi-part message in MIME format.
--------------090900070401030903050304
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

Hi,

Following on from making cats actually be capable of dumping kernel 
cores I've updated the kernel code and libkvm code to support dumping 
the extra headers etc needed for savecore to work.  With some help from 
Nick (skrll@) I've added support to gdb to understand kernel core 
dumps.  Nick did the mknative work for gdb.

The updates to dumpsys and kcore.h were taken from similar code in i386.

The asm dumpsys and dodumpsys were inspired by amd64's method of dumping 
core, as it makes sure that the stack has a switchframe containing the 
registers, something savectx didn't get right.

These change remove the last active reference to savectx (which didn't 
work for dumpsys because the switchframe it placed on the stack is 
trashed by the dumpsys C code before the stack is saved to disk)

I've broken the diffs down into bite sized chunks:
kernel.diff - changes to the kernel to support dumping the extra info 
for savecore.  Adds kcore.h.
pkg_list.diff - adds kcore.h to the arm comp set.
libkvm.diff - adds support to libkvm to provide the functions it needs 
to save the core dump (room for optimisation as the L1 table could be 
cached in memory)
gdb_mknative.diff - Nick's run of mknative to provide a kvm target for 
gdb on arm
gdb_pcb.diff - Adding the processing of the dumppcb structure from the 
kernel core dump to gdb

The main item to highlight is the cpu_kcore_hdr structure in 
sys/arch/arm/include/kcore.h, as it's a new kernel->userland ABI for 
arm, I'd like to get it right first time if possible.  Currently I've 
defined it as:
typedef struct cpu_kcore_hdr {
    uint32_t    version;        /* structure version */
    uint32_t    isArm26;        /* indicates arm26 dump */
    uint32_t    PAKernelL1Table;    /* PA of PMAP_kernel L1 table */
    uint32_t    nmemsegs;        /* Number of RAM segments */
#if 0
    phys_ram_seg_t  memsegs[];        /* RAM segments */
#endif
} cpu_kcore_hdr_t;

This provides all the info I need, however, given I've placed a version 
field into it, I suspect the isArm26 field can go.  Also to improve 
forward/backwards compatibility I think I should add an offset to the 
memsegs, so it ends up as:

typedef struct cpu_kcore_hdr {
    uint32_t    version;        /* structure version */
    uint32_t    PAKernelL1Table;    /* PA of PMAP_kernel L1 table */
    uint32_t    nmemsegs;        /* Number of RAM segments */
    uint32_t    omemsegs;      /* offset from start of structure to 
memsegs []*/
#if 0
    phys_ram_seg_t  memsegs[];        /* RAM segments */
#endif
} cpu_kcore_hdr_t;

By using an offset it allows future versions to add extra fields to the 
structure, after omemsegs, and keep some level of backwards compatibility.

Am I allowing (over-engineering) for something that may never happen?  
I'm expecting that arm26 needs to save something different, and possibly 
arm v6 and v7 architectures will need something else as well, hence why 
I'm wanting to allow the ABI to have a bit of flexibility.

I guess the second area of ABI is the registers placed on the stack in 
dumpsys.  Something I was wondering is if it would help gdb by placing 
the cpsr onto the stack for gdb to be able to load, or does it not 
matter for a kernel dump.  (note r3 is saved purely to keep the stack 
8byte aligned)

The code has only been tested on cats, I need to do some builds on other 
arm based platforms to make sure they don't break :)

I'm aiming to tidy up the code (make sure it meets NetBSD style 
guidelines, and fix some tab vs space issues) on Monday, and check it 
in, so it'd be nice to have feedback by then.

Thanks,
Chris

--------------090900070401030903050304
Content-Type: text/plain;
 name="gdb_mknative.diff"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline;
 filename="gdb_mknative.diff"

Index: gnu/usr.bin/gdb6/arch/arm/defs.mk
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/gnu/usr.bin/gdb6/arch/arm/defs.mk,v
retrieving revision 1.3
diff -u -p -u -r1.3 defs.mk
--- gnu/usr.bin/gdb6/arch/arm/defs.mk	6 Dec 2006 18:25:29 -0000	1.3
+++ gnu/usr.bin/gdb6/arch/arm/defs.mk	14 Dec 2007 14:44:25 -0000
@@ -1,7 +1,7 @@
 # This file is automatically generated.  DO NOT EDIT!
-# Generated from: 	NetBSD: mknative-gdb,v 1.1 2006/05/29 19:10:58 nathan=
w Exp=20
-# Generated from: NetBSD: mknative.common,v 1.8 2006/05/26 19:17:21 mrg =
Exp=20
+# Generated from: 	NetBSD: mknative-gdb,v 1.2 2007/02/19 18:26:22 chs Ex=
p=20
+# Generated from: NetBSD: mknative.common,v 1.9 2007/02/05 18:26:01 apb =
Exp=20
 #
 G_INTERNAL_CFLAGS=3D     -I. -I${GNUHOSTDIST}/gdb -I${GNUHOSTDIST}/gdb/c=
onfig -DLOCALEDIR=3D"\"/usr/share/locale\"" -DHAVE_CONFIG_H -I${GNUHOSTDI=
ST}/gdb/../include/opcode -I${GNUHOSTDIST}/gdb/../readline/..  -I../bfd -=
I${GNUHOSTDIST}/gdb/../bfd -I${GNUHOSTDIST}/gdb/../include  -I../intl -I$=
{GNUHOSTDIST}/gdb/../intl  -DMI_OUT=3D1 -DTUI=3D1 -Wimplicit -Wreturn-typ=
e -Wcomment -Wtrigraphs -Wformat -Wparentheses -Wpointer-arith -Wformat-n=
onliteral -Wunused-label -Wunused-function -Wno-pointer-sign=20
-G_LIBGDB_OBS=3Darm-tdep.o armnbsd-tdep.o solib.o solib-svr4.o nbsd-tdep.=
o ser-base.o ser-unix.o ser-pipe.o ser-tcp.o fork-child.o inf-ptrace.o co=
relow.o nbsd-nat.o armnbsd-nat.o  remote.o dcache.o remote-utils.o tracep=
oint.o ax-general.o ax-gdb.o remote-fileio.o  cli-dump.o  cli-decode.o cl=
i-script.o cli-cmds.o cli-setshow.o cli-utils.o  cli-logging.o  cli-inter=
p.o mi-out.o mi-console.o  mi-cmds.o mi-cmd-env.o mi-cmd-var.o mi-cmd-bre=
ak.o mi-cmd-stack.o  mi-cmd-file.o mi-cmd-disas.o mi-symbol-cmds.o  mi-in=
terp.o  mi-main.o mi-parse.o mi-getopt.o mi-common.o posix-hdep.o tui-com=
mand.o  tui-data.o  tui-disasm.o  tui-file.o tui.o  tui-hooks.o  tui-inte=
rp.o  tui-io.o  tui-layout.o  tui-out.o  tui-regs.o  tui-source.o  tui-st=
ack.o  tui-win.o  tui-windata.o  tui-wingeneral.o  tui-winsource.o c-exp.=
o  cp-name-parser.o  objc-exp.o  ada-exp.o  jv-exp.o  f-exp.o m2-exp.o p-=
exp.o  version.o  annotate.o  auxv.o  bfd-target.o  blockframe.o breakpoi=
nt.o findvar.o regcache.o  charset.o disasm.o dummy-frame.o  source.o val=
ue.o eval.o valops.o valarith.o valprint.o printcmd.o  block.o symtab.o s=
ymfile.o symmisc.o linespec.o dictionary.o  infcall.o  infcmd.o infrun.o =
 expprint.o environ.o stack.o thread.o  exceptions.o  inf-child.o  interp=
s.o  main.o  macrotab.o macrocmd.o macroexp.o macroscope.o  event-loop.o =
event-top.o inf-loop.o completer.o  gdbarch.o arch-utils.o gdbtypes.o osa=
bi.o copying.o  memattr.o mem-break.o target.o parse.o language.o buildsy=
m.o  std-regs.o  signals.o  kod.o kod-cisco.o  gdb-events.o  exec.o bcach=
e.o objfiles.o observer.o minsyms.o maint.o demangle.o  dbxread.o coffrea=
d.o coff-pe-read.o elfread.o  dwarfread.o dwarf2read.o mipsread.o stabsre=
ad.o corefile.o  dwarf2expr.o dwarf2loc.o dwarf2-frame.o  ada-lang.o c-la=
ng.o f-lang.o objc-lang.o  ui-out.o cli-out.o  varobj.o wrapper.o  jv-lan=
g.o jv-valprint.o jv-typeprint.o  m2-lang.o p-lang.o p-typeprint.o p-valp=
rint.o  scm-exp.o scm-lang.o scm-valprint.o  sentinel-frame.o  complaints=
=2Eo typeprint.o  ada-typeprint.o c-typeprint.o f-typeprint.o m2-typeprin=
t.o  ada-valprint.o c-valprint.o cp-valprint.o f-valprint.o m2-valprint.o=
  nlmread.o serial.o mdebugread.o top.o utils.o  ui-file.o  user-regs.o  =
frame.o frame-unwind.o doublest.o  frame-base.o  gnu-v2-abi.o gnu-v3-abi.=
o hpacc-abi.o cp-abi.o cp-support.o  cp-namespace.o  reggroups.o regset.o=
  trad-frame.o  tramp-frame.o  solib.o solib-null.o  prologue-value.o inf=
low.o    init.o
+G_LIBGDB_OBS=3Darm-tdep.o armnbsd-tdep.o solib.o solib-svr4.o nbsd-tdep.=
o ser-base.o ser-unix.o ser-pipe.o ser-tcp.o fork-child.o inf-ptrace.o co=
relow.o nbsd-nat.o armnbsd-nat.o bsd-kvm.o  remote.o dcache.o remote-util=
s.o tracepoint.o ax-general.o ax-gdb.o remote-fileio.o  cli-dump.o  cli-d=
ecode.o cli-script.o cli-cmds.o cli-setshow.o cli-utils.o  cli-logging.o =
 cli-interp.o mi-out.o mi-console.o  mi-cmds.o mi-cmd-env.o mi-cmd-var.o =
mi-cmd-break.o mi-cmd-stack.o  mi-cmd-file.o mi-cmd-disas.o mi-symbol-cmd=
s.o  mi-interp.o  mi-main.o mi-parse.o mi-getopt.o mi-common.o nbsd-threa=
d.o posix-hdep.o tui-command.o  tui-data.o  tui-disasm.o  tui-file.o tui.=
o  tui-hooks.o  tui-interp.o  tui-io.o  tui-layout.o  tui-out.o  tui-regs=
=2Eo  tui-source.o  tui-stack.o  tui-win.o  tui-windata.o  tui-wingeneral=
=2Eo  tui-winsource.o c-exp.o  cp-name-parser.o  objc-exp.o  ada-exp.o  j=
v-exp.o  f-exp.o m2-exp.o p-exp.o  version.o  annotate.o  auxv.o  bfd-tar=
get.o  blockframe.o breakpoint.o findvar.o regcache.o  charset.o disasm.o=
 dummy-frame.o  source.o value.o eval.o valops.o valarith.o valprint.o pr=
intcmd.o  block.o symtab.o symfile.o symmisc.o linespec.o dictionary.o  i=
nfcall.o  infcmd.o infrun.o  expprint.o environ.o stack.o thread.o  excep=
tions.o  inf-child.o  interps.o  main.o  macrotab.o macrocmd.o macroexp.o=
 macroscope.o  event-loop.o event-top.o inf-loop.o completer.o  gdbarch.o=
 arch-utils.o gdbtypes.o osabi.o copying.o  memattr.o mem-break.o target.=
o parse.o language.o buildsym.o  std-regs.o  signals.o  kod.o kod-cisco.o=
  gdb-events.o  exec.o bcache.o objfiles.o observer.o minsyms.o maint.o d=
emangle.o  dbxread.o coffread.o coff-pe-read.o elfread.o  dwarfread.o dwa=
rf2read.o mipsread.o stabsread.o corefile.o  dwarf2expr.o dwarf2loc.o dwa=
rf2-frame.o  ada-lang.o c-lang.o f-lang.o objc-lang.o  ui-out.o cli-out.o=
  varobj.o wrapper.o  jv-lang.o jv-valprint.o jv-typeprint.o  m2-lang.o p=
-lang.o p-typeprint.o p-valprint.o  scm-exp.o scm-lang.o scm-valprint.o  =
sentinel-frame.o  complaints.o typeprint.o  ada-typeprint.o c-typeprint.o=
 f-typeprint.o m2-typeprint.o  ada-valprint.o c-valprint.o cp-valprint.o =
f-valprint.o m2-valprint.o  nlmread.o serial.o mdebugread.o top.o utils.o=
  ui-file.o  user-regs.o  frame.o frame-unwind.o doublest.o  frame-base.o=
  gnu-v2-abi.o gnu-v3-abi.o hpacc-abi.o cp-abi.o cp-support.o  cp-namespa=
ce.o  reggroups.o regset.o  trad-frame.o  tramp-frame.o  solib.o solib-nu=
ll.o  prologue-value.o inflow.o    init.o
 G_SIM_OBS=3D
Index: gnu/dist/gdb6/gdb/config/arm/nbsdelf.mh
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/gnu/dist/gdb6/gdb/config/arm/nbsdelf.mh,v
retrieving revision 1.2
diff -u -p -u -r1.2 nbsdelf.mh
--- gnu/dist/gdb6/gdb/config/arm/nbsdelf.mh	6 Dec 2006 18:25:29 -0000	1.2=

+++ gnu/dist/gdb6/gdb/config/arm/nbsdelf.mh	14 Dec 2007 14:44:25 -0000
@@ -1,2 +1,4 @@
 # Host: NetBSD/arm
-NATDEPFILES=3D fork-child.o inf-ptrace.o corelow.o nbsd-nat.o armnbsd-na=
t.o
+NATDEPFILES=3D fork-child.o inf-ptrace.o corelow.o nbsd-nat.o armnbsd-na=
t.o bsd-kvm.o
+
+LOADLIBES=3D -lkvm

--------------090900070401030903050304
Content-Type: text/plain;
 name="gdb_pcb.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="gdb_pcb.diff"

Index: gnu/dist/gdb6/gdb/armnbsd-nat.c
===================================================================
RCS file: /cvsroot/src/gnu/dist/gdb6/gdb/armnbsd-nat.c,v
retrieving revision 1.2
diff -u -p -r1.2 armnbsd-nat.c
--- gnu/dist/gdb6/gdb/armnbsd-nat.c	24 Feb 2007 12:36:27 -0000	1.2
+++ gnu/dist/gdb6/gdb/armnbsd-nat.c	15 Dec 2007 00:16:39 -0000
@@ -31,9 +31,11 @@
 #include <sys/ptrace.h>
 #include <machine/reg.h>
 #include <machine/frame.h>
+#include <machine/pcb.h>
 
 #include "arm-tdep.h"
 #include "inf-ptrace.h"
+#include "bsd-kvm.h"
 
 #ifndef HAVE_GREGSET_T
 typedef struct reg gregset_t;
@@ -47,6 +49,45 @@ typedef struct fpreg fpregset_t;
 
 extern int arm_apcs_32;
 
+static int
+armnbsd_supply_pcb (struct regcache *regcache, struct pcb *pcb)
+{
+	struct switchframe sf;
+	uint32_t r3, r4, r5, r6, r7, lr;
+	uint32_t sp;
+
+       	/* The stack pointer shouldn't be zero.  */
+    	if (pcb->pcb_un.un_32.pcb32_sp == 0)
+		return 0;
+
+
+	/* we need to pull some regs from the stack */
+       	read_memory (pcb->pcb_un.un_32.pcb32_sp, (gdb_byte *) &r3, sizeof(r3));
+	read_memory (pcb->pcb_un.un_32.pcb32_sp+4, (gdb_byte *) &r4, sizeof(r4));
+	read_memory (pcb->pcb_un.un_32.pcb32_sp+8, (gdb_byte *) &r5, sizeof(r5));
+	read_memory (pcb->pcb_un.un_32.pcb32_sp+12, (gdb_byte *) &r6, sizeof(r6));
+	read_memory (pcb->pcb_un.un_32.pcb32_sp+16, (gdb_byte *) &r7, sizeof(r7));
+       	read_memory (pcb->pcb_un.un_32.pcb32_sp+20, (gdb_byte *) &lr, sizeof(lr));
+
+	sp = pcb->pcb_un.un_32.pcb32_sp + 24;
+
+	regcache_raw_supply (regcache, 3, &r3);
+	regcache_raw_supply (regcache, 4, &r4);
+	regcache_raw_supply (regcache, 5, &r5);
+	regcache_raw_supply (regcache, 6, &r6);
+	regcache_raw_supply (regcache, 7, &r7);
+	regcache_raw_supply (regcache, 8, &pcb->pcb_un.un_32.pcb32_r8);
+	regcache_raw_supply (regcache, 9, &pcb->pcb_un.un_32.pcb32_r9);
+	regcache_raw_supply (regcache, 10, &pcb->pcb_un.un_32.pcb32_r10);
+	regcache_raw_supply (regcache, 11, &pcb->pcb_un.un_32.pcb32_r11);
+	regcache_raw_supply (regcache, 12, &pcb->pcb_un.un_32.pcb32_r12);
+	regcache_raw_supply (regcache, ARM_SP_REGNUM, &sp);
+	regcache_raw_supply (regcache, ARM_LR_REGNUM, &lr);
+	regcache_raw_supply (regcache, ARM_PC_REGNUM, &lr);
+
+	return 1;
+}
+
 void
 supply_gregset (gregset_t *gregset)
 {
@@ -551,4 +592,7 @@ _initialize_arm_netbsd_nat (void)
 
   deprecated_add_core_fns (&arm_netbsd_core_fns);
   deprecated_add_core_fns (&arm_netbsd_elfcore_fns);
+
+  /* support debugging kernel images */
+  bsd_kvm_add_target (armnbsd_supply_pcb);
 }

--------------090900070401030903050304
Content-Type: text/plain;
 name="kernel.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="kernel.diff"

Index: sys/arch/arm/arm32/locore.S
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/arm32/locore.S,v
retrieving revision 1.18
diff -u -p -r1.18 locore.S
--- sys/arch/arm/arm32/locore.S	11 Dec 2005 12:16:41 -0000	1.18
+++ sys/arch/arm/arm32/locore.S	15 Dec 2007 00:33:53 -0000
@@ -212,5 +212,31 @@ _C_LABEL(esym):	.word	_C_LABEL(end)
 ENTRY_NP(abort)
 	b	_C_LABEL(abort)
 
+/*
+ * part of doing a system dump, we need to build a switchframe on the stack
+ * and save it into the dump pcb
+ */
+
+ENTRY(dumpsys)
+	/* push registers onto stack */
+	stmfd	sp!, {r3-r7, lr}
+
+	/* fill in dumppcb */
+	ldr	r0, .Ldumppcb
+
+#ifndef __XSCALE__
+        add     r2, r0, #(PCB_R8)
+        stmia   r2, {r8-r13}
+#else
+        strd    r8, [r0, #(PCB_R8)]
+        strd    r10, [r0, #(PCB_R10)]
+        strd    r12, [r0, #(PCB_R12)]
+#endif
+
+	bl	_C_LABEL(dodumpsys)
+	ldmfd	sp!, {r3-r7, pc}
+
+.Ldumppcb:
+	.word	_C_LABEL(dumppcb)
 
 /* End of locore.S */
Index: sys/arch/arm/arm32/mem.c
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/arm32/mem.c,v
retrieving revision 1.19
diff -u -p -r1.19 mem.c
--- sys/arch/arm/arm32/mem.c	4 Mar 2007 10:21:26 -0000	1.19
+++ sys/arch/arm/arm32/mem.c	15 Dec 2007 00:33:54 -0000
@@ -91,7 +91,7 @@ __KERNEL_RCSID(0, "$NetBSD: mem.c,v 1.19
 
 #include <uvm/uvm_extern.h>
 
-extern char *memhook;            /* poor name! */
+extern vaddr_t memhook;            /* poor name! */
 void *zeropage;
 int physlock;
 
@@ -143,14 +143,14 @@ mmrw(dev, uio, flags)
 			v = uio->uio_offset;
 			prot = uio->uio_rw == UIO_READ ? VM_PROT_READ :
 			    VM_PROT_WRITE;
-			pmap_enter(pmap_kernel(), (vaddr_t)memhook,
+			pmap_enter(pmap_kernel(), memhook,
 			    trunc_page(v), prot, prot|PMAP_WIRED);
 			pmap_update(pmap_kernel());
 			o = uio->uio_offset & PGOFSET;
 			c = min(uio->uio_resid, (int)(PAGE_SIZE - o));
 			error = uiomove((char *)memhook + o, c, uio);
-			pmap_remove(pmap_kernel(), (vaddr_t)memhook,
-			    (vaddr_t)memhook + PAGE_SIZE);
+			pmap_remove(pmap_kernel(), memhook,
+			    memhook + PAGE_SIZE);
 			pmap_update(pmap_kernel());
 			break;
 
Index: sys/arch/arm/arm32/pmap.c
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/arm32/pmap.c,v
retrieving revision 1.169
diff -u -p -r1.169 pmap.c
--- sys/arch/arm/arm32/pmap.c	8 Nov 2007 11:10:28 -0000	1.169
+++ sys/arch/arm/arm32/pmap.c	15 Dec 2007 00:33:56 -0000
@@ -303,7 +303,7 @@ static paddr_t pmap_kernel_l2ptp_phys;
  */
 static pt_entry_t *csrc_pte, *cdst_pte;
 static vaddr_t csrcp, cdstp;
-char *memhook;
+vaddr_t memhook;
 extern void *msgbufaddr;
 
 /*
@@ -3963,7 +3963,7 @@ pmap_bootstrap(pd_entry_t *kernel_l1pt, 
 	pmap_set_pt_cache_mode(kernel_l1pt, (vaddr_t)csrc_pte);
 	pmap_alloc_specials(&virtual_avail, 1, &cdstp, &cdst_pte);
 	pmap_set_pt_cache_mode(kernel_l1pt, (vaddr_t)cdst_pte);
-	pmap_alloc_specials(&virtual_avail, 1, (void *)&memhook, NULL);
+	pmap_alloc_specials(&virtual_avail, 1, &memhook, NULL);
 	pmap_alloc_specials(&virtual_avail, round_page(MSGBUFSIZE) / PAGE_SIZE,
 	    (void *)&msgbufaddr, NULL);
 
@@ -4985,6 +4985,14 @@ pmap_uarea(vaddr_t va)
 }
 #endif /* ARM_MMU_XSCALE == 1 */
 
+/*
+ * return the PA of the current L1 table, for use when handling a crash dump
+ */
+uint32_t pmap_kernel_L1_addr()
+{
+	return pmap_kernel()->pm_l1->l1_physaddr;
+}
+
 #if defined(DDB)
 /*
  * A couple of ddb-callable functions for dumping pmaps
Index: sys/arch/arm/arm32/stubs.c
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/arm32/stubs.c,v
retrieving revision 1.17
diff -u -p -r1.17 stubs.c
--- sys/arch/arm/arm32/stubs.c	4 Mar 2007 05:59:37 -0000	1.17
+++ sys/arch/arm/arm32/stubs.c	15 Dec 2007 00:33:56 -0000
@@ -55,9 +55,17 @@ __KERNEL_RCSID(0, "$NetBSD: stubs.c,v 1.
 #include <machine/bootconfig.h>
 #include <machine/pcb.h>
 #include <arm/arm32/machdep.h>
+#include <arm/kcore.h>
+#include <sys/kcore.h>
+#include <sys/core.h>
+#include <sys/exec_aout.h>
 
 extern dev_t dumpdev;
 
+int	cpu_dump(void);
+int	cpu_dumpsize(void);
+u_long	cpu_dump_mempagecnt(void);
+
 /*
  * These variables are needed by /sbin/savecore
  */
@@ -69,7 +77,7 @@ struct pcb dumppcb;
 
 /*
  * This is called by main to set dumplo and dumpsize.
- * Dumps always skip the first CLBYTES of disk space
+ * 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.
@@ -79,46 +87,135 @@ void
 cpu_dumpconf()
 {
 	const struct bdevsw *bdev;
-	int nblks;	/* size of dump area */
+	int nblks, dumpblks;	/* size of dump area */
 
 	if (dumpdev == NODEV)
 		return;
 	bdev = bdevsw_lookup(dumpdev);
-	if (bdev == NULL) {
-		dumpdev = NODEV;
-		return;
-	}
+	if (bdev == NULL)
+		panic("dumpconf: bad dumpdev=0x%x", dumpdev);
 	if (bdev->d_psize == NULL)
 		return;
 	nblks = (*bdev->d_psize)(dumpdev);
 	if (nblks <= ctod(1))
 		return;
 
-	dumpsize = physmem;
+	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;
+}
+
+/*
+ * cpu_dump: dump the machine-dependent kernel core dump headers.
+ */
+int
+cpu_dump()
+{
+	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 = (phys_ram_seg_t *)&bf[ ALIGN(sizeof(*segp)) +
+	    ALIGN(sizeof(*cpuhdrp))];
+
+	/*
+	 * 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->version = 1;
+	cpuhdrp->isArm26 = 0;
+	cpuhdrp->PAKernelL1Table = pmap_kernel_L1_addr();
+	cpuhdrp->nmemsegs = 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)));
+}
+
+/*
+ * cpu_dumpsize: calculate size of machine-dependent kernel core dump headers.
+ */
+int
+cpu_dumpsize()
+{
+	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);
 
-	/* Always skip the first CLBYTES, in case there is a label there. */
-	if (dumplo < ctod(1))
-		dumplo = ctod(1);
-
-	/* Put dump at end of partition, and make it fit. */
-	if (dumpsize > dtoc(nblks - dumplo))
-		dumpsize = dtoc(nblks - dumplo);
-	if (dumplo < nblks - ctod(dumpsize))
-		dumplo = nblks - ctod(dumpsize);
+	return (1);
+}
+
+
+/*
+ * cpu_dump_mempagecnt: calculate the size of RAM (in pages) to be dumped.
+ */
+u_long
+cpu_dump_mempagecnt()
+{
+	u_long i, n;
+
+	n = 0;
+	for (i = 0; i < bootconfig.dramblocks; i++) {
+		n += bootconfig.dram[i].pages;
+	}
+
+	return (n);
 }
 
 /* This should be moved to machdep.c */
 
-extern char *memhook;		/* XXX */
+extern vaddr_t memhook;		/* XXX */
 
 /*
  * Doadump comes here after turning off memory management and
  * getting on the dump stack, either when called above, or by
  * the auto-restart code.
  */
+void dodumpsys(void);
 
 void
-dumpsys()
+dodumpsys()
 {
 	const struct bdevsw *bdev;
 	daddr_t blkno;
@@ -129,8 +226,6 @@ dumpsys()
 	int len;
 	vaddr_t dumpspace;
 
-	/* Save registers. */
-	savectx(&dumppcb);
 	/* flush everything out of caches */
 	cpu_dcache_wbinv_all();
 
@@ -138,19 +233,16 @@ dumpsys()
 		return;
 	if (dumpsize == 0) {
 		cpu_dumpconf();
-		if (dumpsize == 0)
-			return;
 	}
-	if (dumplo <= 0) {
+	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);
 
-	blkno = dumplo;
-	dumpspace = (vaddr_t) memhook;
 
 	bdev = bdevsw_lookup(dumpdev);
 	if (bdev == NULL || bdev->d_psize == NULL)
@@ -162,6 +254,11 @@ dumpsys()
 		return;
 	}
 
+	if ((error = cpu_dump()) != 0)
+		goto err;
+
+	blkno = dumplo + cpu_dumpsize();
+	dumpspace = memhook;
 	error = 0;
 	len = 0;
 
@@ -172,19 +269,18 @@ dumpsys()
 		     addr += PAGE_SIZE) {
 		    	if ((len % (1024*1024)) == 0)
 		    		printf("%d ", len / (1024*1024));
+
 			pmap_kenter_pa(dumpspace, addr, VM_PROT_READ);
 			pmap_update(pmap_kernel());
-
 			error = (*bdev->d_dump)(dumpdev,
 			    blkno, (void *) dumpspace, PAGE_SIZE);
-			pmap_kremove(dumpspace, PAGE_SIZE);
-			pmap_update(pmap_kernel());
-			if (error) break;
+
+			if (error) goto err;
 			blkno += btodb(PAGE_SIZE);
 			len += PAGE_SIZE;
 		}
 	}
-
+err:
 	switch (error) {
 	case ENXIO:
 		printf("device bad\n");
@@ -206,12 +302,16 @@ dumpsys()
 		printf("aborted from console\n");
 		break;
 
-	default:
+	case 0:
 		printf("succeeded\n");
 		break;
+
+	default:
+		printf("error %d\n", error);
+		break;
 	}
 	printf("\n\n");
-	delay(1000000);
+	delay(5000000);
 }
 
 /* End of stubs.c */
Index: sys/arch/arm/include/Makefile
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/include/Makefile,v
retrieving revision 1.34
diff -u -p -r1.34 Makefile
--- sys/arch/arm/include/Makefile	18 Feb 2007 15:53:55 -0000	1.34
+++ sys/arch/arm/include/Makefile	15 Dec 2007 00:33:56 -0000
@@ -11,7 +11,7 @@ INCS=	ansi.h aout_machdep.h armreg.h asm
 	ieee.h ieeefp.h \
 	int_const.h int_fmtio.h int_limits.h int_mwgwtypes.h int_types.h \
 	ipkdb.h \
-	limits.h lock.h \
+	limits.h kcore.h lock.h \
 	math.h mcontext.h mutex.h \
 	param.h pcb.h pmc.h proc.h profile.h rwlock.h \
 	ptrace.h \
Index: sys/arch/arm/include/kcore.h
===================================================================
RCS file: sys/arch/arm/include/kcore.h
diff -N sys/arch/arm/include/kcore.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sys/arch/arm/include/kcore.h	15 Dec 2007 00:33:56 -0000
@@ -0,0 +1,48 @@
+/*	$NetBSD: kcore.h,v 1.3 2005/12/26 19:23:59 perry Exp $	*/
+
+/*
+ * Copyright (c) 1996 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ * Modified for NetBSD/i386 by Jason R. Thorpe, Numerical Aerospace
+ * Simulation Facility, NASA Ames Research Center.
+ */
+
+#ifndef _ARM_KCORE_H_
+#define _ARM_KCORE_H_
+
+typedef struct cpu_kcore_hdr {
+	uint32_t	version;		/* structure version */
+	uint32_t	isArm26;		/* indicates arm26 dump */
+	uint32_t	PAKernelL1Table;	/* PA of PMAP_kernel L1 table */
+	uint32_t	nmemsegs;		/* Number of RAM segments */
+#if 0
+	phys_ram_seg_t  memsegs[];		/* RAM segments */
+#endif
+} cpu_kcore_hdr_t;
+
+#endif /* _ARM_KCORE_H_ */
Index: sys/arch/arm/include/arm32/pmap.h
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/include/arm32/pmap.h,v
retrieving revision 1.83
diff -u -p -r1.83 pmap.h
--- sys/arch/arm/include/arm32/pmap.h	17 Oct 2007 19:53:41 -0000	1.83
+++ sys/arch/arm/include/arm32/pmap.h	15 Dec 2007 00:33:57 -0000
@@ -291,6 +291,8 @@ void	pmap_devmap_register(const struct p
 bool	pmap_pageidlezero(paddr_t);
 #define PMAP_PAGEIDLEZERO(pa)	pmap_pageidlezero((pa))
 
+/* crash dump function */
+uint32_t pmap_kernel_L1_addr(void);
 /*
  * The current top of kernel VM
  */

--------------090900070401030903050304
Content-Type: text/plain;
 name="libkvm.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="libkvm.diff"

Index: lib/libkvm/kvm_arm.c
===================================================================
RCS file: /cvsroot/src/lib/libkvm/kvm_arm.c,v
retrieving revision 1.2
diff -u -p -r1.2 kvm_arm.c
--- lib/libkvm/kvm_arm.c	16 Jul 2001 05:45:52 -0000	1.2
+++ lib/libkvm/kvm_arm.c	15 Dec 2007 00:18:03 -0000
@@ -45,6 +45,11 @@
 #include <db.h>
 #include <limits.h>
 #include <kvm.h>
+#include <sys/kcore.h>
+#include <arm/kcore.h>
+#include <arm/arm32/pte.h>
+
+#include <unistd.h>
 
 #include "kvm_private.h"
 
@@ -69,6 +74,82 @@ _kvm_kvatop(kd, va, pa)
 	u_long va;
 	u_long *pa;
 {
+	cpu_kcore_hdr_t *cpu_kh;
+	pd_entry_t pde;
+	pt_entry_t pte;
+	uint32_t pde_pa, pte_pa;
+
+	if (ISALIVE(kd)) {
+		_kvm_err(kd, 0, "vatop called in live kernel!");
+		return (0);
+	}
+
+	cpu_kh = kd->cpu_data;
+
+	if (cpu_kh->version != 1)
+	{
+		_kvm_err(kd, 0, "unsupported kcore structure version");
+		return 0;
+	}
+
+	if (cpu_kh->isArm26)
+	{
+		_kvm_err(kd, 0, "arm26 kcore dumps not supported");
+		return 0;
+	}
+
+	/* first up we have to load in the L1 entry */
+	pde_pa = cpu_kh->PAKernelL1Table + ((va>>20) * sizeof(pd_entry_t));
+
+	if (pread(kd->pmfd, (void*)&pde, sizeof(pd_entry_t), 
+		 _kvm_pa2off(kd, pde_pa)) != sizeof(pd_entry_t)) {
+		_kvm_syserr(kd, 0, "could not read L1 entry");
+		return (0);
+	}
+
+	/* next work out what kind of record it is */
+	switch (pde & L1_TYPE_MASK)
+	{
+		case L1_TYPE_S:
+			/* an L1 section */
+			*pa = (pde & L1_S_FRAME) | (va & L1_S_OFFSET);
+			return L1_S_SIZE - (va & L1_S_OFFSET);
+		case L1_TYPE_C:
+			pte_pa = (pde & L1_C_ADDR_MASK)
+				| ((va & 0xff000) >> 10) ;
+			break;
+		case L1_TYPE_F:
+			pte_pa = (pde & L1_S_ADDR_MASK)
+				| ((va & 0xffc00) >> 8) ;
+			break;
+		default:
+			_kvm_syserr(kd, 0, "L1 entry is invalid");
+			return (0);
+	}
+
+	/* locate the pte and load it */
+	if (pread(kd->pmfd, (void*)&pte, sizeof(pt_entry_t),
+		_kvm_pa2off(kd, pte_pa)) != sizeof(pt_entry_t)) {
+		_kvm_syserr(kd, 0, "could not read L2 entry");
+		return (0);
+	}
+
+	switch (pte & L2_TYPE_MASK)
+	{
+		case L2_TYPE_L:
+			 *pa = (pte & L2_L_FRAME) | (va & L2_L_OFFSET);
+			 return (L2_L_SIZE - (va & L2_L_OFFSET));
+		case L2_TYPE_S:
+			 *pa = (pte & L2_S_FRAME) | (va & L2_S_OFFSET);
+			 return (L2_S_SIZE - (va & L2_S_OFFSET));
+		case L2_TYPE_T:
+			 *pa = (pte & L2_T_FRAME) | (va & L2_T_OFFSET);
+			 return (L2_T_SIZE - (va & L2_T_OFFSET));
+		default:
+			_kvm_syserr(kd, 0, "L2 entry is invalid");
+			return (0);
+	}
+
 	_kvm_err(kd, 0, "vatop not yet implemented!");
 	return 0;
 }
@@ -78,8 +159,24 @@ _kvm_pa2off(kd, pa)
 	kvm_t *kd;
 	u_long pa;
 {
-	_kvm_err(kd, 0, "pa2off not yet implemented!");
-	return 0;
+	cpu_kcore_hdr_t *cpu_kh;
+	phys_ram_seg_t *ramsegs;
+	off_t off;
+	int i;
+	
+	cpu_kh = kd->cpu_data;
+	ramsegs = (void *)((char *)(void *)cpu_kh + ALIGN(sizeof *cpu_kh));
+	
+	off = 0;
+	for (i = 0; i < cpu_kh->nmemsegs; i++) {
+		if (pa >= ramsegs[i].start &&
+			(pa - ramsegs[i].start) < ramsegs[i].size) {
+			off += (pa - ramsegs[i].start);
+			break;
+		}
+		off += ramsegs[i].size;
+	}
+									        	return (kd->dump_off + off);
 }
 
 /*

--------------090900070401030903050304
Content-Type: text/plain;
 name="pkg_list.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="pkg_list.diff"

Index: distrib/sets/lists/comp/ad.arm
===================================================================
RCS file: /cvsroot/src/distrib/sets/lists/comp/ad.arm,v
retrieving revision 1.27
diff -u -p -r1.27 ad.arm
--- distrib/sets/lists/comp/ad.arm	18 Feb 2007 18:47:36 -0000	1.27
+++ distrib/sets/lists/comp/ad.arm	15 Dec 2007 00:19:29 -0000
@@ -45,6 +45,7 @@
 ./usr/include/arm/iomd				comp-obsolete		obsolete
 ./usr/include/arm/iomd/vidc.h			comp-obsolete		obsolete
 ./usr/include/arm/ipkdb.h			comp-c-include
+./usr/include/arm/kcore.h			comp-c-include
 ./usr/include/arm/limits.h			comp-c-include
 ./usr/include/arm/lock.h			comp-c-include
 ./usr/include/arm/math.h			comp-c-include

--------------090900070401030903050304--