History

powerpc/mm: Fix virt_addr_valid() etc. on 64-bit hash

virt_addr_valid() is supposed to tell you if it's OK to call virt_to_page() on an address. What this means in practice is that it should only return true for addresses in the linear mapping which are backed by a valid PFN. We are failing to properly check that the address is in the linear mapping, because virt_to_pfn() will return a valid looking PFN for more or less any address. That bug is actually caused by __pa(), used in virt_to_pfn(). eg: __pa(0xc000000000010000) = 0x10000 # Good __pa(0xd000000000010000) = 0x10000 # Bad! __pa(0x0000000000010000) = 0x10000 # Bad! This started happening after commit bdbc29c19b26 ("powerpc: Work around gcc miscompilation of __pa() on 64-bit") (Aug 2013), where we changed the definition of __pa() to work around a GCC bug. Prior to that we subtracted PAGE_OFFSET from the value passed to __pa(), meaning __pa() of a 0xd or 0x0 address would give you something bogus back. Until we can verify if that GCC bug is no longer an issue, or come up with another solution, this commit does the minimal fix to make virt_addr_valid() work, by explicitly checking that the address is in the linear mapping region.

Michael Ellerman committed 9 years ago

Commit e41e53c1 parent bfb99561 file · +12 −0Browse files

Unified · Split

arch/powerpc/include/asm/page.h+12−0
@@ -132,7 +132,19 @@ extern long long virt_phys_offset; · 131 unmodified lines
132132 #define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT)
133133 #define virt_to_page(kaddr) pfn_to_page(virt_to_pfn(kaddr))
134134 #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
135+
136+#ifdef CONFIG_PPC_BOOK3S_64
137+/*
138+ * On hash the vmalloc and other regions alias to the kernel region when passed
139+ * through __pa(), which virt_to_pfn() uses. That means virt_addr_valid() can
140+ * return true for some vmalloc addresses, which is incorrect. So explicitly
141+ * check that the address is in the kernel region.
142+ */
143+#define virt_addr_valid(kaddr) (REGION_ID(kaddr) == KERNEL_REGION_ID && \
144+ pfn_valid(virt_to_pfn(kaddr)))
145+#else
135146 #define virt_addr_valid(kaddr) pfn_valid(virt_to_pfn(kaddr))
147+#endif
136148
137149 /*
138150 * On Book-E parts we need __va to parse the device tree and we can't

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t