summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/asm-i386/pgtable.h1
-rw-r--r--mm/memory.c40
2 files changed, 41 insertions, 0 deletions
diff --git a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h
index c2ef3a5479ec..6d7508ca9b4e 100644
--- a/include/asm-i386/pgtable.h
+++ b/include/asm-i386/pgtable.h
@@ -192,6 +192,7 @@ extern unsigned long pg0[1024];
* The following only work if pte_present() is true.
* Undefined behaviour if not..
*/
+static inline int pte_user(pte_t pte) { return (pte).pte_low & _PAGE_USER; }
static inline int pte_read(pte_t pte) { return (pte).pte_low & _PAGE_USER; }
static inline int pte_exec(pte_t pte) { return (pte).pte_low & _PAGE_USER; }
static inline int pte_dirty(pte_t pte) { return (pte).pte_low & _PAGE_DIRTY; }
diff --git a/mm/memory.c b/mm/memory.c
index d9b86809380f..8397ea054459 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -51,6 +51,7 @@
#include <asm/uaccess.h>
#include <asm/tlb.h>
#include <asm/tlbflush.h>
+#include <asm/pgtable.h>
#include <linux/swapops.h>
@@ -688,6 +689,45 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
vma = find_extend_vma(mm, start);
+#ifdef FIXADDR_START
+ if (!vma && start >= FIXADDR_START && start < FIXADDR_TOP) {
+ static struct vm_area_struct fixmap_vma = {
+ /* Catch users - if there are any valid
+ ones, we can make this be "&init_mm" or
+ something. */
+ .vm_mm = NULL,
+ .vm_start = FIXADDR_START,
+ .vm_end = FIXADDR_TOP,
+ .vm_page_prot = PAGE_READONLY,
+ .vm_flags = VM_READ | VM_EXEC,
+ };
+ unsigned long pg = start & PAGE_MASK;
+ pgd_t *pgd;
+ pmd_t *pmd;
+ pte_t *pte;
+ pgd = pgd_offset_k(pg);
+ if (!pgd)
+ return i ? : -EFAULT;
+ pmd = pmd_offset(pgd, pg);
+ if (!pmd)
+ return i ? : -EFAULT;
+ pte = pte_offset_kernel(pmd, pg);
+ if (!pte || !pte_present(*pte) || !pte_user(*pte) ||
+ !(write ? pte_write(*pte) : pte_read(*pte)))
+ return i ? : -EFAULT;
+ if (pages) {
+ pages[i] = pte_page(*pte);
+ get_page(pages[i]);
+ }
+ if (vmas)
+ vmas[i] = &fixmap_vma;
+ i++;
+ start += PAGE_SIZE;
+ len--;
+ continue;
+ }
+#endif
+
if (!vma || (pages && (vma->vm_flags & VM_IO))
|| !(flags & vma->vm_flags))
return i ? : -EFAULT;