On 01/25/2017 12:57 PM, Khalid Aziz wrote:
@@ -157,6 +158,24 @@ int __get_user_pages_fast(unsigned long start,
int nr_pages, int write,
pgd_t *pgdp;
int nr = 0;
+#ifdef CONFIG_SPARC64
+ if (adi_capable()) {
+ long addr = start;
+
+ /* If userspace has passed a versioned address, kernel
+ * will not find it in the VMAs since it does not store
+ * the version tags in the list of VMAs. Storing version
+ * tags in list of VMAs is impractical since they can be
+ * changed any time from userspace without dropping into
+ * kernel. Any address search in VMAs will be done with
+ * non-versioned addresses. Ensure the ADI version bits
+ * are dropped here by sign extending the last bit before
+ * ADI bits. IOMMU does not implement version tags.
+ */
+ addr = (addr << (long)adi_nbits()) >> (long)adi_nbits();
So you are depending on the sign extension to clear the ADI bits... but
this only happens if there is a zero in that "last bit before ADI bits".
If the last bit is a 1, then the ADI bits will be set instead of
cleared. That seems like an unintended consequence given the comment. I
am aware of the value of adi_nbits() and of the number of valid bits in
a virtual address on the M7 processor, but wouldn't using 'unsigned
long' for everything here guarantee the ADI bits get cleared regardless
of the state of the last non-adi bit?