Commit e93d2521 authored by Thomas Weißschuh's avatar Thomas Weißschuh Committed by Thomas Gleixner
Browse files

x86/vdso: Split virtual clock pages into dedicated mapping



The generic vdso data storage cannot handle the special pvclock and
hvclock pages. Split them into their own mapping, so the other vdso
storage can be migrated to the generic code.

Signed-off-by: default avatarThomas Weißschuh <thomas.weissschuh@linutronix.de>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/all/20241010-vdso-generic-base-v1-20-b64f0842d512@linutronix.de
parent 05a6b8c1
Loading
Loading
Loading
Loading
+6 −4
Original line number Diff line number Diff line
@@ -17,14 +17,16 @@ SECTIONS
	 * segment.
	 */

	vvar_start = . - 4 * PAGE_SIZE;
	vvar_start = . - __VVAR_PAGES * PAGE_SIZE;
	vvar_page  = vvar_start;

	vdso_rng_data = vvar_page + __VDSO_RND_DATA_OFFSET;

	pvclock_page = vvar_start + PAGE_SIZE;
	hvclock_page = vvar_start + 2 * PAGE_SIZE;
	timens_page  = vvar_start + 3 * PAGE_SIZE;
	timens_page  = vvar_start + PAGE_SIZE;

	vclock_pages = vvar_start + VDSO_NR_VCLOCK_PAGES * PAGE_SIZE;
	pvclock_page = vclock_pages + VDSO_PAGE_PVCLOCK_OFFSET * PAGE_SIZE;
	hvclock_page = vclock_pages + VDSO_PAGE_HVCLOCK_OFFSET * PAGE_SIZE;

	. = SIZEOF_HEADERS;

+53 −17
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include <asm/page.h>
#include <asm/desc.h>
#include <asm/cpufeature.h>
#include <asm/vdso/vsyscall.h>
#include <clocksource/hyperv_timer.h>

struct vdso_data *arch_get_vdso_data(void *vvar_page)
@@ -175,19 +176,7 @@ static vm_fault_t vvar_fault(const struct vm_special_mapping *sm,
		}

		return vmf_insert_pfn(vma, vmf->address, pfn);
	} else if (sym_offset == image->sym_pvclock_page) {
		struct pvclock_vsyscall_time_info *pvti =
			pvclock_get_pvti_cpu0_va();
		if (pvti && vclock_was_used(VDSO_CLOCKMODE_PVCLOCK)) {
			return vmf_insert_pfn_prot(vma, vmf->address,
					__pa(pvti) >> PAGE_SHIFT,
					pgprot_decrypted(vma->vm_page_prot));
		}
	} else if (sym_offset == image->sym_hvclock_page) {
		pfn = hv_get_tsc_pfn();

		if (pfn && vclock_was_used(VDSO_CLOCKMODE_HVCLOCK))
			return vmf_insert_pfn(vma, vmf->address, pfn);
	} else if (sym_offset == image->sym_timens_page) {
		struct page *timens_page = find_timens_vvar_page(vma);

@@ -201,6 +190,33 @@ static vm_fault_t vvar_fault(const struct vm_special_mapping *sm,
	return VM_FAULT_SIGBUS;
}

static vm_fault_t vvar_vclock_fault(const struct vm_special_mapping *sm,
				    struct vm_area_struct *vma, struct vm_fault *vmf)
{
	switch (vmf->pgoff) {
#ifdef CONFIG_PARAVIRT_CLOCK
	case VDSO_PAGE_PVCLOCK_OFFSET:
		struct pvclock_vsyscall_time_info *pvti =
			pvclock_get_pvti_cpu0_va();
		if (pvti && vclock_was_used(VDSO_CLOCKMODE_PVCLOCK))
			return vmf_insert_pfn_prot(vma, vmf->address,
					__pa(pvti) >> PAGE_SHIFT,
					pgprot_decrypted(vma->vm_page_prot));
		break;
#endif /* CONFIG_PARAVIRT_CLOCK */
#ifdef CONFIG_HYPERV_TIMER
	case VDSO_PAGE_HVCLOCK_OFFSET:
		unsigned long pfn = hv_get_tsc_pfn();

		if (pfn && vclock_was_used(VDSO_CLOCKMODE_HVCLOCK))
			return vmf_insert_pfn(vma, vmf->address, pfn);
		break;
#endif /* CONFIG_HYPERV_TIMER */
	}

	return VM_FAULT_SIGBUS;
}

static const struct vm_special_mapping vdso_mapping = {
	.name = "[vdso]",
	.fault = vdso_fault,
@@ -210,6 +226,10 @@ static const struct vm_special_mapping vvar_mapping = {
	.name = "[vvar]",
	.fault = vvar_fault,
};
static const struct vm_special_mapping vvar_vclock_mapping = {
	.name = "[vvar_vclock]",
	.fault = vvar_vclock_fault,
};

/*
 * Add vdso and vvar mappings to current process.
@@ -252,7 +272,7 @@ static int map_vdso(const struct vdso_image *image, unsigned long addr)

	vma = _install_special_mapping(mm,
				       addr,
				       -image->sym_vvar_start,
				       (__VVAR_PAGES - VDSO_NR_VCLOCK_PAGES) * PAGE_SIZE,
				       VM_READ|VM_MAYREAD|VM_IO|VM_DONTDUMP|
				       VM_PFNMAP,
				       &vvar_mapping);
@@ -260,10 +280,25 @@ static int map_vdso(const struct vdso_image *image, unsigned long addr)
	if (IS_ERR(vma)) {
		ret = PTR_ERR(vma);
		do_munmap(mm, text_start, image->size, NULL);
	} else {
		goto up_fail;
	}

	vma = _install_special_mapping(mm,
				       addr + (__VVAR_PAGES - VDSO_NR_VCLOCK_PAGES) * PAGE_SIZE,
				       VDSO_NR_VCLOCK_PAGES * PAGE_SIZE,
				       VM_READ|VM_MAYREAD|VM_IO|VM_DONTDUMP|
				       VM_PFNMAP,
				       &vvar_vclock_mapping);

	if (IS_ERR(vma)) {
		ret = PTR_ERR(vma);
		do_munmap(mm, text_start, image->size, NULL);
		do_munmap(mm, addr, image->size, NULL);
		goto up_fail;
	}

	current->mm->context.vdso = (void __user *)text_start;
	current->mm->context.vdso_image = image;
	}

up_fail:
	mmap_write_unlock(mm);
@@ -286,7 +321,8 @@ int map_vdso_once(const struct vdso_image *image, unsigned long addr)
	 */
	for_each_vma(vmi, vma) {
		if (vma_is_special_mapping(vma, &vdso_mapping) ||
				vma_is_special_mapping(vma, &vvar_mapping)) {
				vma_is_special_mapping(vma, &vvar_mapping) ||
				vma_is_special_mapping(vma, &vvar_vclock_mapping)) {
			mmap_write_unlock(mm);
			return -EEXIST;
		}
+5 −0
Original line number Diff line number Diff line
@@ -3,6 +3,11 @@
#define __ASM_VDSO_VSYSCALL_H

#define __VDSO_RND_DATA_OFFSET  640
#define __VVAR_PAGES	4

#define VDSO_NR_VCLOCK_PAGES	2
#define VDSO_PAGE_PVCLOCK_OFFSET	0
#define VDSO_PAGE_HVCLOCK_OFFSET	1

#ifndef __ASSEMBLY__