Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 28 Jun 2005 18:17:14 GMT
From:      Paul Saab <ps@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 79086 for review
Message-ID:  <200506281817.j5SIHEbP094468@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=79086

Change 79086 by ps@butter.corp on 2005/06/28 18:16:57

	With the help of Peter, add support for PAE crashdumps.

Affected files ...

.. //depot/projects/hammer/lib/libkvm/kvm_i386.c#4 edit
.. //depot/projects/hammer/lib/libkvm/kvm_private.h#2 edit

Differences ...

==== //depot/projects/hammer/lib/libkvm/kvm_i386.c#4 (text+ko) ====

@@ -73,10 +73,15 @@
 #define	ptob(x)		(i386_ptob(x))
 #endif
 
+#define	PG_FRAME_PAE	(~((uint64_t)PAGE_MASK))
+#define	PDRSHIFT_PAE	21
+#define NPTEPG_PAE	(PAGE_SIZE/sizeof(uint64_t))
+
 struct vmstate {
 	void		*mmapbase;
 	size_t		mmapsize;
-	pd_entry_t	*PTD;
+	void		*PTD;
+	int		pae;
 };
 
 /*
@@ -109,7 +114,7 @@
  * (Taken from kvm_ia64.c)
  */
 static size_t
-_kvm_pa2off(kvm_t *kd, uint64_t pa, u_long *ofs)
+_kvm_pa2off(kvm_t *kd, uint64_t pa, uint64_t *ofs)
 {
 	Elf_Ehdr *e = kd->vmst->mmapbase;
 	Elf_Phdr *p = (Elf_Phdr*)((char*)e + e->e_phoff);
@@ -173,29 +178,58 @@
 	else
 		kernbase = nlist[0].n_value;
 
-	nlist[0].n_name = "IdlePTD";
+	nlist[0].n_name = "IdlePDPT";
 	nlist[1].n_name = 0;
 
-	if (kvm_nlist(kd, nlist) != 0) {
-		_kvm_err(kd, kd->program, "bad namelist");
-		return (-1);
-	}
-	if (kvm_read(kd, (nlist[0].n_value - kernbase), &pa, sizeof(pa)) !=
-	    sizeof(pa)) {
-		_kvm_err(kd, kd->program, "cannot read IdlePTD");
-		return (-1);
-	}
-	PTD = _kvm_malloc(kd, PAGE_SIZE);
-	if (kvm_read(kd, pa, PTD, PAGE_SIZE) != PAGE_SIZE) {
-		_kvm_err(kd, kd->program, "cannot read PTD");
-		return (-1);
+	if (kvm_nlist(kd, nlist) == 0) {
+		uint64_t pa64;
+
+		if (kvm_read(kd, (nlist[0].n_value - kernbase), &pa,
+		    sizeof(pa)) != sizeof(pa)) {
+			_kvm_err(kd, kd->program, "cannot read IdlePDPT");
+			return (-1);
+		}
+
+		if (kvm_read(kd, pa, &pa64, sizeof(pa64)) != sizeof(pa64)) {
+			 _kvm_err(kd, kd->program, "Cannot read PDPT");
+			 return (-1);
+		}
+
+		PTD = _kvm_malloc(kd, 4 * PAGE_SIZE);
+		if (kvm_read(kd, pa64 & PG_FRAME_PAE, PTD, 4 * PAGE_SIZE) !=
+		    (4 * PAGE_SIZE)) {
+			_kvm_err(kd, kd->program, "cannot read PDPT");
+			return (-1);
+		}
+		kd->vmst->PTD = PTD;
+		kd->vmst->pae = 1;
+	} else {
+		nlist[0].n_name = "IdlePTD";
+		nlist[1].n_name = 0;
+
+		if (kvm_nlist(kd, nlist) != 0) {
+			_kvm_err(kd, kd->program, "bad namelist");
+			return (-1);
+		}
+		if (kvm_read(kd, (nlist[0].n_value - kernbase), &pa, sizeof(pa)) !=
+		    sizeof(pa)) {
+			_kvm_err(kd, kd->program, "cannot read IdlePTD");
+			return (-1);
+		}
+		PTD = _kvm_malloc(kd, PAGE_SIZE);
+		if (kvm_read(kd, pa, PTD, PAGE_SIZE) != PAGE_SIZE) {
+			_kvm_err(kd, kd->program, "cannot read PTD");
+			return (-1);
+		}
+		kd->vmst->PTD = PTD;
+		return (0);
+		kd->vmst->pae = 0;
 	}
-	kd->vmst->PTD = PTD;
 	return (0);
 }
 
 int
-_kvm_kvatop(kvm_t *kd, u_long va, u_long *pa)
+kvm_kvatop(kvm_t *kd, u_long va, uint64_t *pa)
 {
 	struct vmstate *vm;
 	u_long offset;
@@ -206,7 +240,9 @@
 	u_long pdeindex;
 	u_long pteindex;
 	size_t s;
-	u_long a, ofs;
+	u_long a;
+	uint64_t ofs;
+	uint32_t *PTD;
 
 
 	if (ISALIVE(kd)) {
@@ -215,13 +251,14 @@
 	}
 
 	vm = kd->vmst;
+	PTD = (uint32_t *)vm->PTD;
 	offset = va & (PAGE_SIZE - 1);
 
 	/*
 	 * If we are initializing (kernel page table descriptor pointer
 	 * not yet set) then return pa == va to avoid infinite recursion.
 	 */
-	if (vm->PTD == 0) {
+	if (PTD == 0) {
 		s = _kvm_pa2off(kd, va, pa);
 		if (s == 0) {
 			_kvm_err(kd, kd->program, 
@@ -232,7 +269,7 @@
 	}
 
 	pdeindex = va >> PDRSHIFT;
-	pde = vm->PTD[pdeindex];
+	pde = PTD[pdeindex];
 	if (((u_long)pde & PG_V) == 0)
 		goto invalid;
 
@@ -256,7 +293,7 @@
 	}
 
 	pteindex = (va >> PAGE_SHIFT) & (NPTEPG-1);
-	pte_pa = ((u_long)pde & PG_FRAME) + (pteindex * sizeof(pt_entry_t));
+	pte_pa = ((u_long)pde & PG_FRAME) + (pteindex * sizeof(pde));
 
 	s = _kvm_pa2off(kd, pte_pa, &ofs);
 	if (s <= sizeof pte) {
@@ -288,3 +325,109 @@
 	_kvm_err(kd, 0, "invalid address (%x)", va);
 	return (0);
 }
+
+int
+kvm_kvatop_pae(kvm_t *kd, u_long va, uint64_t *pa)
+{
+	struct vmstate *vm;
+	uint64_t offset;
+	uint64_t pte_pa;
+	uint64_t pde_pa;
+	uint64_t pde;
+	uint64_t pte;
+	u_long pdeindex;
+	u_long pteindex;
+	size_t s;
+	uint64_t a, ofs;
+	uint64_t *PTD;
+
+
+	if (ISALIVE(kd)) {
+		_kvm_err(kd, 0, "vatop called in live kernel!");
+		return((off_t)0);
+	}
+
+	vm = kd->vmst;
+	PTD = (uint64_t *)vm->PTD;
+	offset = va & (PAGE_SIZE - 1);
+
+	/*
+	 * If we are initializing (kernel page table descriptor pointer
+	 * not yet set) then return pa == va to avoid infinite recursion.
+	 */
+	if (PTD == 0) {
+		s = _kvm_pa2off(kd, va, pa);
+		if (s == 0) {
+			_kvm_err(kd, kd->program, 
+			    "_kvm_kvatop: bootstrap data not in dump");
+			goto invalid;
+		} else
+			return (PAGE_SIZE - offset);
+	}
+
+	pdeindex = va >> PDRSHIFT_PAE;
+	pde = PTD[pdeindex];
+	if (((u_long)pde & PG_V) == 0)
+		goto invalid;
+
+	if ((u_long)pde & PG_PS) {
+	      /*
+	       * No second-level page table; ptd describes one 4MB page.
+	       * (We assume that the kernel wouldn't set PG_PS without enabling
+	       * it cr0, and that the kernel doesn't support 36-bit physical
+	       * addresses).
+	       */
+#define	PAGE4M_MASK	(NBPDR - 1)
+#define	PG_FRAME4M	(~PAGE4M_MASK)
+		pde_pa = ((u_long)pde & PG_FRAME4M) + (va & PAGE4M_MASK);
+		s = _kvm_pa2off(kd, pde_pa, &ofs);
+		if (s <= sizeof pde) {
+			_kvm_syserr(kd, kd->program, "_kvm_kvatop: pde_pa not found");
+			goto invalid;
+		}
+		*pa = ofs;
+		return (NBPDR - (va & PAGE4M_MASK));
+	}
+
+	pteindex = (va >> PAGE_SHIFT) & (NPTEPG_PAE-1);
+	pte_pa = ((uint64_t)pde & PG_FRAME_PAE) + (pteindex * sizeof(pde));
+
+	s = _kvm_pa2off(kd, pte_pa, &ofs);
+	if (s <= sizeof pte) {
+		_kvm_err(kd, kd->program, "_kvm_kvatop: pdpe_pa not found");
+		goto invalid;
+	}
+
+	/* XXX This has to be a physical address read, kvm_read is virtual */
+	if (lseek(kd->pmfd, ofs, 0) == -1) {
+		_kvm_syserr(kd, kd->program, "_kvm_vatop: lseek");
+		goto invalid;
+	}
+	if (read(kd->pmfd, &pte, sizeof pte) != sizeof pte) {
+		_kvm_syserr(kd, kd->program, "_kvm_vatop: read");
+		goto invalid;
+	}
+	if (((uint64_t)pte & PG_V) == 0)
+		goto invalid;
+
+	a = ((uint64_t)pte & PG_FRAME_PAE) + offset;
+	s =_kvm_pa2off(kd, a, pa);
+	if (s == 0) {
+		_kvm_err(kd, kd->program, "_kvm_kvatop: address not in dump");
+		goto invalid;
+	} else
+		return (PAGE_SIZE - offset);
+
+invalid:
+	_kvm_err(kd, 0, "invalid address (%x)", va);
+	return (0);
+}
+
+int
+_kvm_kvatop(kvm_t *kd, u_long va, uint64_t *pa)
+{
+	if (kd->vmst->pae)
+		kvm_kvatop_pae(kd, va, pa);
+	else
+		kvm_kvatop(kd, va, pa);
+}

==== //depot/projects/hammer/lib/libkvm/kvm_private.h#2 (text+ko) ====

@@ -75,7 +75,7 @@
 void	 _kvm_freeprocs(kvm_t *kd);
 void	 _kvm_freevtop(kvm_t *);
 int	 _kvm_initvtop(kvm_t *);
-int	 _kvm_kvatop(kvm_t *, u_long, u_long *);
+int	 _kvm_kvatop(kvm_t *, u_long, uint64_t *);
 void	*_kvm_malloc(kvm_t *kd, size_t);
 void	*_kvm_realloc(kvm_t *kd, void *, size_t);
 void	 _kvm_syserr (kvm_t *kd, const char *program, const char *fmt, ...)



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200506281817.j5SIHEbP094468>