[PATCH 4/5] Add address translation

Zachary Amsden
2007-04-18T17:49:22Z

Add a helper function to convert an arbitrary mapped virtual address to a
physical frame number.  Adapted from code by Chris Wright, added support
for large pages.

Because of the placement, this needs to be a macro; pgd_offset_k requires
init_mm to be defined, and getting the include files right seemed more
complicated than a macroized implementation.

A more proper location would be in asm/page.h, but that gets confounded
by the use of pgd_offset_k() again.

Signed-off-by: Zachary Amsden <zach@vmware.com>
Index: linux-2.6.13/include/asm-i386/pgtable.h
==================================================================---
linux-2.6.13.orig/include/asm-i386/pgtable.h	2005-08-24 09:43:27.000000000 -0700
+++ linux-2.6.13/include/asm-i386/pgtable.h	2005-08-24 09:47:38.000000000 -0700
@@ -388,6 +388,28 @@ static inline pte_t pte_modify(pte_t pte
 extern pte_t *lookup_address(unsigned long address);

 /*
+ * Helper function that returns physical page for virtual address.
+ * This assumes the mapping is valid.
+ */
+#define virt_to_pfn(_address) 					\
+({ 								\
+	unsigned long long __paddr;				\
+	pgd_t *pgd = pgd_offset_k(_address);			\
+	pud_t *pud = pud_offset(pgd, (_address));		\
+	pmd_t *pmd = pmd_offset(pud, (_address));		\
+	if (pmd_large(*pmd))					\
+		__paddr = (pmd_val(*pmd) & LARGE_PAGE_MASK) |	\
+			((_address) & ~LARGE_PAGE_MASK);	\
+	else {							\
+		pte_t *pte = pte_offset_kernel(pmd, (_address));\
+		__paddr = (pte_val(*pte) & PAGE_MASK) |		\
+			((_address) & ~PAGE_MASK);		\
+	}							\
+	__paddr >>= PAGE_SHIFT;					\
+	__paddr;						\
+})
+
+/*
  * Make a given kernel text page executable/non-executable.
  * Returns the previous executability setting of that page (which
  * is used to restore the previous state). Used by the SMP bootup code.