Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

riscv: vdso: Switch to generic storage implementation

The generic storage implementation provides the same features as the
custom one. However it can be shared between architectures, making
maintenance easier.

Co-developed-by: Nam Cao <namcao@linutronix.de>
Signed-off-by: Nam Cao <namcao@linutronix.de>
Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/all/20250204-vdso-store-rng-v3-9-13a4669dfc8c@linutronix.de

authored by

Thomas Weißschuh and committed by
Thomas Gleixner
46fe55b2 0b3bc335

+18 -124
+2 -1
arch/riscv/Kconfig
··· 53 53 select ARCH_HAS_SYSCALL_WRAPPER 54 54 select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST 55 55 select ARCH_HAS_UBSAN 56 - select ARCH_HAS_VDSO_TIME_DATA 56 + select ARCH_HAS_VDSO_ARCH_DATA if GENERIC_VDSO_DATA_STORE 57 57 select ARCH_KEEP_MEMBLOCK if ACPI 58 58 select ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE if 64BIT && MMU 59 59 select ARCH_OPTIONAL_KERNEL_RWX if ARCH_HAS_STRICT_KERNEL_RWX ··· 116 116 select GENERIC_SCHED_CLOCK 117 117 select GENERIC_SMP_IDLE_THREAD 118 118 select GENERIC_TIME_VSYSCALL if MMU && 64BIT 119 + select GENERIC_VDSO_DATA_STORE if MMU 119 120 select GENERIC_VDSO_TIME_NS if HAVE_GENERIC_VDSO 120 121 select HARDIRQS_SW_RESEND 121 122 select HAS_IOPORT if MMU
+1 -1
arch/riscv/include/asm/vdso.h
··· 14 14 */ 15 15 #ifdef CONFIG_MMU 16 16 17 - #define __VVAR_PAGES 2 17 + #define __VDSO_PAGES 4 18 18 19 19 #ifndef __ASSEMBLY__ 20 20 #include <generated/vdso-offsets.h>
+1 -13
arch/riscv/include/asm/vdso/gettimeofday.h
··· 69 69 #endif /* CONFIG_GENERIC_TIME_VSYSCALL */ 70 70 71 71 static __always_inline u64 __arch_get_hw_counter(s32 clock_mode, 72 - const struct vdso_data *vd) 72 + const struct vdso_time_data *vd) 73 73 { 74 74 /* 75 75 * The purpose of csr_read(CSR_TIME) is to trap the system into ··· 79 79 return csr_read(CSR_TIME); 80 80 } 81 81 82 - static __always_inline const struct vdso_data *__arch_get_vdso_data(void) 83 - { 84 - return _vdso_data; 85 - } 86 - 87 - #ifdef CONFIG_TIME_NS 88 - static __always_inline 89 - const struct vdso_data *__arch_get_timens_vdso_data(const struct vdso_data *vd) 90 - { 91 - return _timens_data; 92 - } 93 - #endif 94 82 #endif /* !__ASSEMBLY__ */ 95 83 96 84 #endif /* __ASM_VDSO_GETTIMEOFDAY_H */
+4 -4
arch/riscv/include/asm/vdso/time_data.h arch/riscv/include/asm/vdso/arch_data.h
··· 1 1 /* SPDX-License-Identifier: GPL-2.0 */ 2 - #ifndef __RISCV_ASM_VDSO_TIME_DATA_H 3 - #define __RISCV_ASM_VDSO_TIME_DATA_H 2 + #ifndef __RISCV_ASM_VDSO_ARCH_DATA_H 3 + #define __RISCV_ASM_VDSO_ARCH_DATA_H 4 4 5 5 #include <linux/types.h> 6 6 #include <vdso/datapage.h> 7 7 #include <asm/hwprobe.h> 8 8 9 - struct arch_vdso_time_data { 9 + struct vdso_arch_data { 10 10 /* Stash static answers to the hwprobe queries when all CPUs are selected. */ 11 11 __u64 all_cpu_hwprobe_values[RISCV_HWPROBE_MAX_KEY + 1]; 12 12 ··· 14 14 __u8 homogeneous_cpus; 15 15 }; 16 16 17 - #endif /* __RISCV_ASM_VDSO_TIME_DATA_H */ 17 + #endif /* __RISCV_ASM_VDSO_ARCH_DATA_H */
-9
arch/riscv/include/asm/vdso/vsyscall.h
··· 6 6 7 7 #include <vdso/datapage.h> 8 8 9 - extern struct vdso_data *vdso_data; 10 - 11 - static __always_inline struct vdso_data *__riscv_get_k_vdso_data(void) 12 - { 13 - return vdso_data; 14 - } 15 - 16 - #define __arch_get_k_vdso_data __riscv_get_k_vdso_data 17 - 18 9 /* The asm-generic header needs to be included after the definitions above */ 19 10 #include <asm-generic/vdso/vsyscall.h> 20 11
+1 -2
arch/riscv/kernel/sys_hwprobe.c
··· 450 450 451 451 static int __init init_hwprobe_vdso_data(void) 452 452 { 453 - struct vdso_data *vd = __arch_get_k_vdso_data(); 454 - struct arch_vdso_time_data *avd = &vd->arch_data; 453 + struct vdso_arch_data *avd = vdso_k_arch_data; 455 454 u64 id_bitsmash = 0; 456 455 struct riscv_hwprobe pair; 457 456 int key;
+4 -86
arch/riscv/kernel/vdso.c
··· 13 13 #include <linux/err.h> 14 14 #include <asm/page.h> 15 15 #include <asm/vdso.h> 16 - #include <linux/time_namespace.h> 16 + #include <linux/vdso_datastore.h> 17 17 #include <vdso/datapage.h> 18 18 #include <vdso/vsyscall.h> 19 19 20 - enum vvar_pages { 21 - VVAR_DATA_PAGE_OFFSET, 22 - VVAR_TIMENS_PAGE_OFFSET, 23 - VVAR_NR_PAGES, 24 - }; 25 - 26 - #define VVAR_SIZE (VVAR_NR_PAGES << PAGE_SHIFT) 27 - 28 - static union vdso_data_store vdso_data_store __page_aligned_data; 29 - struct vdso_data *vdso_data = vdso_data_store.data; 20 + #define VVAR_SIZE (VDSO_NR_PAGES << PAGE_SHIFT) 30 21 31 22 struct __vdso_info { 32 23 const char *name; ··· 70 79 vdso_info->cm->pages = vdso_pagelist; 71 80 } 72 81 73 - #ifdef CONFIG_TIME_NS 74 - struct vdso_data *arch_get_vdso_data(void *vvar_page) 75 - { 76 - return (struct vdso_data *)(vvar_page); 77 - } 78 - 79 - static const struct vm_special_mapping rv_vvar_map; 80 - 81 - /* 82 - * The vvar mapping contains data for a specific time namespace, so when a task 83 - * changes namespace we must unmap its vvar data for the old namespace. 84 - * Subsequent faults will map in data for the new namespace. 85 - * 86 - * For more details see timens_setup_vdso_data(). 87 - */ 88 - int vdso_join_timens(struct task_struct *task, struct time_namespace *ns) 89 - { 90 - struct mm_struct *mm = task->mm; 91 - struct vm_area_struct *vma; 92 - VMA_ITERATOR(vmi, mm, 0); 93 - 94 - mmap_read_lock(mm); 95 - 96 - for_each_vma(vmi, vma) { 97 - if (vma_is_special_mapping(vma, &rv_vvar_map)) 98 - zap_vma_pages(vma); 99 - } 100 - 101 - mmap_read_unlock(mm); 102 - return 0; 103 - } 104 - #endif 105 - 106 - static vm_fault_t vvar_fault(const struct vm_special_mapping *sm, 107 - struct vm_area_struct *vma, struct vm_fault *vmf) 108 - { 109 - struct page *timens_page = find_timens_vvar_page(vma); 110 - unsigned long pfn; 111 - 112 - switch (vmf->pgoff) { 113 - case VVAR_DATA_PAGE_OFFSET: 114 - if (timens_page) 115 - pfn = page_to_pfn(timens_page); 116 - else 117 - pfn = sym_to_pfn(vdso_data); 118 - break; 119 - #ifdef CONFIG_TIME_NS 120 - case VVAR_TIMENS_PAGE_OFFSET: 121 - /* 122 - * If a task belongs to a time namespace then a namespace 123 - * specific VVAR is mapped with the VVAR_DATA_PAGE_OFFSET and 124 - * the real VVAR page is mapped with the VVAR_TIMENS_PAGE_OFFSET 125 - * offset. 126 - * See also the comment near timens_setup_vdso_data(). 127 - */ 128 - if (!timens_page) 129 - return VM_FAULT_SIGBUS; 130 - pfn = sym_to_pfn(vdso_data); 131 - break; 132 - #endif /* CONFIG_TIME_NS */ 133 - default: 134 - return VM_FAULT_SIGBUS; 135 - } 136 - 137 - return vmf_insert_pfn(vma, vmf->address, pfn); 138 - } 139 - 140 - static const struct vm_special_mapping rv_vvar_map = { 141 - .name = "[vvar]", 142 - .fault = vvar_fault, 143 - }; 144 - 145 82 static struct vm_special_mapping rv_vdso_map __ro_after_init = { 146 83 .name = "[vdso]", 147 84 .mremap = vdso_mremap, ··· 115 196 unsigned long vdso_base, vdso_text_len, vdso_mapping_len; 116 197 void *ret; 117 198 118 - BUILD_BUG_ON(VVAR_NR_PAGES != __VVAR_PAGES); 199 + BUILD_BUG_ON(VDSO_NR_PAGES != __VDSO_PAGES); 119 200 120 201 vdso_text_len = vdso_info->vdso_pages << PAGE_SHIFT; 121 202 /* Be sure to map the data page */ ··· 127 208 goto up_fail; 128 209 } 129 210 130 - ret = _install_special_mapping(mm, vdso_base, VVAR_SIZE, 131 - (VM_READ | VM_MAYREAD | VM_PFNMAP), &rv_vvar_map); 211 + ret = vdso_install_vvar_mapping(mm, vdso_base); 132 212 if (IS_ERR(ret)) 133 213 goto up_fail; 134 214
+2 -4
arch/riscv/kernel/vdso/hwprobe.c
··· 16 16 size_t cpusetsize, unsigned long *cpus, 17 17 unsigned int flags) 18 18 { 19 - const struct vdso_data *vd = __arch_get_vdso_data(); 20 - const struct arch_vdso_time_data *avd = &vd->arch_data; 19 + const struct vdso_arch_data *avd = &vdso_u_arch_data; 21 20 bool all_cpus = !cpusetsize && !cpus; 22 21 struct riscv_hwprobe *p = pairs; 23 22 struct riscv_hwprobe *end = pairs + pair_count; ··· 50 51 size_t cpusetsize, unsigned long *cpus, 51 52 unsigned int flags) 52 53 { 53 - const struct vdso_data *vd = __arch_get_vdso_data(); 54 - const struct arch_vdso_time_data *avd = &vd->arch_data; 54 + const struct vdso_arch_data *avd = &vdso_u_arch_data; 55 55 struct riscv_hwprobe *p = pairs; 56 56 struct riscv_hwprobe *end = pairs + pair_count; 57 57 unsigned char *c = (unsigned char *)cpus;
+3 -4
arch/riscv/kernel/vdso/vdso.lds.S
··· 4 4 */ 5 5 #include <asm/page.h> 6 6 #include <asm/vdso.h> 7 + #include <vdso/datapage.h> 7 8 8 9 OUTPUT_ARCH(riscv) 9 10 10 11 SECTIONS 11 12 { 12 - PROVIDE(_vdso_data = . - __VVAR_PAGES * PAGE_SIZE); 13 - #ifdef CONFIG_TIME_NS 14 - PROVIDE(_timens_data = _vdso_data + PAGE_SIZE); 15 - #endif 13 + VDSO_VVAR_SYMS 14 + 16 15 . = SIZEOF_HEADERS; 17 16 18 17 .hash : { *(.hash) } :text