|
@@ -102,18 +102,69 @@ static const struct vm_special_mapping text_mapping = {
|
|
|
.fault = vdso_fault,
|
|
|
};
|
|
|
|
|
|
+static int vvar_fault(const struct vm_special_mapping *sm,
|
|
|
+ struct vm_area_struct *vma, struct vm_fault *vmf)
|
|
|
+{
|
|
|
+ const struct vdso_image *image = vma->vm_mm->context.vdso_image;
|
|
|
+ long sym_offset;
|
|
|
+ int ret = -EFAULT;
|
|
|
+
|
|
|
+ if (!image)
|
|
|
+ return VM_FAULT_SIGBUS;
|
|
|
+
|
|
|
+ sym_offset = (long)(vmf->pgoff << PAGE_SHIFT) +
|
|
|
+ image->sym_vvar_start;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Sanity check: a symbol offset of zero means that the page
|
|
|
+ * does not exist for this vdso image, not that the page is at
|
|
|
+ * offset zero relative to the text mapping. This should be
|
|
|
+ * impossible here, because sym_offset should only be zero for
|
|
|
+ * the page past the end of the vvar mapping.
|
|
|
+ */
|
|
|
+ if (sym_offset == 0)
|
|
|
+ return VM_FAULT_SIGBUS;
|
|
|
+
|
|
|
+ if (sym_offset == image->sym_vvar_page) {
|
|
|
+ ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address,
|
|
|
+ __pa_symbol(&__vvar_page) >> PAGE_SHIFT);
|
|
|
+ } else if (sym_offset == image->sym_hpet_page) {
|
|
|
+#ifdef CONFIG_HPET_TIMER
|
|
|
+ if (hpet_address) {
|
|
|
+ ret = vm_insert_pfn_prot(
|
|
|
+ vma,
|
|
|
+ (unsigned long)vmf->virtual_address,
|
|
|
+ hpet_address >> PAGE_SHIFT,
|
|
|
+ pgprot_noncached(PAGE_READONLY));
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ } else if (sym_offset == image->sym_pvclock_page) {
|
|
|
+ struct pvclock_vsyscall_time_info *pvti =
|
|
|
+ pvclock_pvti_cpu0_va();
|
|
|
+ if (pvti) {
|
|
|
+ ret = vm_insert_pfn(
|
|
|
+ vma,
|
|
|
+ (unsigned long)vmf->virtual_address,
|
|
|
+ __pa(pvti) >> PAGE_SHIFT);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ret == 0 || ret == -EBUSY)
|
|
|
+ return VM_FAULT_NOPAGE;
|
|
|
+
|
|
|
+ return VM_FAULT_SIGBUS;
|
|
|
+}
|
|
|
+
|
|
|
static int map_vdso(const struct vdso_image *image, bool calculate_addr)
|
|
|
{
|
|
|
struct mm_struct *mm = current->mm;
|
|
|
struct vm_area_struct *vma;
|
|
|
unsigned long addr, text_start;
|
|
|
int ret = 0;
|
|
|
- static struct page *no_pages[] = {NULL};
|
|
|
- static struct vm_special_mapping vvar_mapping = {
|
|
|
+ static const struct vm_special_mapping vvar_mapping = {
|
|
|
.name = "[vvar]",
|
|
|
- .pages = no_pages,
|
|
|
+ .fault = vvar_fault,
|
|
|
};
|
|
|
- struct pvclock_vsyscall_time_info *pvti;
|
|
|
|
|
|
if (calculate_addr) {
|
|
|
addr = vdso_addr(current->mm->start_stack,
|
|
@@ -153,7 +204,8 @@ static int map_vdso(const struct vdso_image *image, bool calculate_addr)
|
|
|
vma = _install_special_mapping(mm,
|
|
|
addr,
|
|
|
-image->sym_vvar_start,
|
|
|
- VM_READ|VM_MAYREAD,
|
|
|
+ VM_READ|VM_MAYREAD|VM_IO|VM_DONTDUMP|
|
|
|
+ VM_PFNMAP,
|
|
|
&vvar_mapping);
|
|
|
|
|
|
if (IS_ERR(vma)) {
|
|
@@ -161,41 +213,6 @@ static int map_vdso(const struct vdso_image *image, bool calculate_addr)
|
|
|
goto up_fail;
|
|
|
}
|
|
|
|
|
|
- if (image->sym_vvar_page)
|
|
|
- ret = remap_pfn_range(vma,
|
|
|
- text_start + image->sym_vvar_page,
|
|
|
- __pa_symbol(&__vvar_page) >> PAGE_SHIFT,
|
|
|
- PAGE_SIZE,
|
|
|
- PAGE_READONLY);
|
|
|
-
|
|
|
- if (ret)
|
|
|
- goto up_fail;
|
|
|
-
|
|
|
-#ifdef CONFIG_HPET_TIMER
|
|
|
- if (hpet_address && image->sym_hpet_page) {
|
|
|
- ret = io_remap_pfn_range(vma,
|
|
|
- text_start + image->sym_hpet_page,
|
|
|
- hpet_address >> PAGE_SHIFT,
|
|
|
- PAGE_SIZE,
|
|
|
- pgprot_noncached(PAGE_READONLY));
|
|
|
-
|
|
|
- if (ret)
|
|
|
- goto up_fail;
|
|
|
- }
|
|
|
-#endif
|
|
|
-
|
|
|
- pvti = pvclock_pvti_cpu0_va();
|
|
|
- if (pvti && image->sym_pvclock_page) {
|
|
|
- ret = remap_pfn_range(vma,
|
|
|
- text_start + image->sym_pvclock_page,
|
|
|
- __pa(pvti) >> PAGE_SHIFT,
|
|
|
- PAGE_SIZE,
|
|
|
- PAGE_READONLY);
|
|
|
-
|
|
|
- if (ret)
|
|
|
- goto up_fail;
|
|
|
- }
|
|
|
-
|
|
|
up_fail:
|
|
|
if (ret)
|
|
|
current->mm->context.vdso = NULL;
|