Author: andrew
Date: Sun Oct 19 20:23:31 2014
New Revision: 273284
URL: https://svnweb.freebsd.org/changeset/base/273284

Log:
  Allow libkvm to get the kernel va to pa delta without the need for
  physaddr. This should allow for a kernel where PHYSADDR and KERNPHYSADDR
  are both undefined.
  
  For now libkvm will use the old method of reading physaddr and kernaddr
  to allow it to work with old kernels. This could be removed in the future
  when enough time has passed.
  
  Differential Revision:        https://reviews.freebsd.org/D939
  MFC after:    1 week

Modified:
  head/lib/libkvm/kvm_arm.c
  head/sys/arm/arm/dump_machdep.c
  head/sys/sys/elf_common.h

Modified: head/lib/libkvm/kvm_arm.c
==============================================================================
--- head/lib/libkvm/kvm_arm.c   Sun Oct 19 18:41:22 2014        (r273283)
+++ head/lib/libkvm/kvm_arm.c   Sun Oct 19 20:23:31 2014        (r273284)
@@ -132,8 +132,10 @@ _kvm_initvtop(kvm_t *kd)
        u_long kernbase, physaddr, pa;
        pd_entry_t *l1pt;
        Elf32_Ehdr *ehdr;
+       Elf32_Phdr *phdr;
        size_t hdrsz;
        char minihdr[8];
+       int found, i;
 
        if (!kd->rawdump) {
                if (pread(kd->pmfd, &minihdr, 8, 0) == 8) {
@@ -158,19 +160,33 @@ _kvm_initvtop(kvm_t *kd)
        hdrsz = ehdr->e_phoff + ehdr->e_phentsize * ehdr->e_phnum;
        if (_kvm_maphdrs(kd, hdrsz) == -1)
                return (-1);
-       nl[0].n_name = "kernbase";
-       nl[1].n_name = NULL;
-       if (kvm_nlist(kd, nl) != 0)
-               kernbase = KERNBASE;
-       else
-               kernbase = nl[0].n_value;
 
-       nl[0].n_name = "physaddr";
-       if (kvm_nlist(kd, nl) != 0) {
-               _kvm_err(kd, kd->program, "couldn't get phys addr");
-               return (-1);
+       phdr = (Elf32_Phdr *)((uint8_t *)ehdr + ehdr->e_phoff);
+       found = 0;
+       for (i = 0; i < ehdr->e_phnum; i++) {
+               if (phdr[i].p_type == PT_DUMP_DELTA) {
+                       kernbase = phdr[i].p_vaddr;
+                       physaddr = phdr[i].p_paddr;
+                       found = 1;
+                       break;
+               }
+       }
+
+       nl[1].n_name = NULL;
+       if (!found) {
+               nl[0].n_name = "kernbase";
+               if (kvm_nlist(kd, nl) != 0)
+                       kernbase = KERNBASE;
+               else
+                       kernbase = nl[0].n_value;
+
+               nl[0].n_name = "physaddr";
+               if (kvm_nlist(kd, nl) != 0) {
+                       _kvm_err(kd, kd->program, "couldn't get phys addr");
+                       return (-1);
+               }
+               physaddr = nl[0].n_value;
        }
-       physaddr = nl[0].n_value;
        nl[0].n_name = "kernel_l1pa";
        if (kvm_nlist(kd, nl) != 0) {
                _kvm_err(kd, kd->program, "bad namelist");

Modified: head/sys/arm/arm/dump_machdep.c
==============================================================================
--- head/sys/arm/arm/dump_machdep.c     Sun Oct 19 18:41:22 2014        
(r273283)
+++ head/sys/arm/arm/dump_machdep.c     Sun Oct 19 20:23:31 2014        
(r273284)
@@ -245,6 +245,29 @@ cb_dumphdr(struct md_pa *mdp, int seqnr,
        return (error);
 }
 
+/*
+ * Add a header to be used by libkvm to get the va to pa delta
+ */
+static int
+dump_os_header(struct dumperinfo *di)
+{
+       Elf_Phdr phdr;
+       int error;
+
+       bzero(&phdr, sizeof(phdr));
+       phdr.p_type = PT_DUMP_DELTA;
+       phdr.p_flags = PF_R;                    /* XXX */
+       phdr.p_offset = 0;
+       phdr.p_vaddr = KERNVIRTADDR;
+       phdr.p_paddr = pmap_kextract(KERNVIRTADDR);
+       phdr.p_filesz = 0;
+       phdr.p_memsz = 0;
+       phdr.p_align = PAGE_SIZE;
+
+       error = buf_write(di, (char*)&phdr, sizeof(phdr));
+       return (error);
+}
+
 static int
 cb_size(struct md_pa *mdp, int seqnr, void *arg)
 {
@@ -308,7 +331,7 @@ dumpsys(struct dumperinfo *di)
 
        /* Calculate dump size. */
        dumpsize = 0L;
-       ehdr.e_phnum = foreach_chunk(cb_size, &dumpsize);
+       ehdr.e_phnum = foreach_chunk(cb_size, &dumpsize) + 1;
        hdrsz = ehdr.e_phoff + ehdr.e_phnum * ehdr.e_phentsize;
        fileofs = MD_ALIGN(hdrsz);
        dumpsize += fileofs;
@@ -325,7 +348,7 @@ dumpsys(struct dumperinfo *di)
        mkdumpheader(&kdh, KERNELDUMPMAGIC, KERNELDUMP_ARM_VERSION, dumpsize, 
di->blocksize);
 
        printf("Dumping %llu MB (%d chunks)\n", (long long)dumpsize >> 20,
-           ehdr.e_phnum);
+           ehdr.e_phnum - 1);
 
        /* Dump leader */
        error = dump_write(di, &kdh, 0, dumplo, sizeof(kdh));
@@ -340,6 +363,8 @@ dumpsys(struct dumperinfo *di)
 
        /* Dump program headers */
        error = foreach_chunk(cb_dumphdr, di);
+       if (error >= 0)
+               error = dump_os_header(di);
        if (error < 0)
                goto fail;
        buf_flush(di);

Modified: head/sys/sys/elf_common.h
==============================================================================
--- head/sys/sys/elf_common.h   Sun Oct 19 18:41:22 2014        (r273283)
+++ head/sys/sys/elf_common.h   Sun Oct 19 20:23:31 2014        (r273284)
@@ -340,6 +340,8 @@ typedef struct {
 #define        PT_GNU_EH_FRAME 0x6474e550
 #define        PT_GNU_STACK    0x6474e551
 #define        PT_GNU_RELRO    0x6474e552
+#define        PT_DUMP_DELTA   0x6fb5d000      /* va->pa map for kernel dumps
+                                          (currently arm). */
 #define        PT_LOSUNW       0x6ffffffa
 #define        PT_SUNWBSS      0x6ffffffa      /* Sun Specific segment */
 #define        PT_SUNWSTACK    0x6ffffffb      /* describes the stack segment 
*/
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to