mirror of
https://github.com/torvalds/linux.git
synced 2026-05-22 06:01:53 +02:00
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
This commit is contained in:
parent
0b3bc3354e
commit
46fe55b204
|
|
@ -53,7 +53,7 @@ config RISCV
|
|||
select ARCH_HAS_SYSCALL_WRAPPER
|
||||
select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
|
||||
select ARCH_HAS_UBSAN
|
||||
select ARCH_HAS_VDSO_TIME_DATA
|
||||
select ARCH_HAS_VDSO_ARCH_DATA if GENERIC_VDSO_DATA_STORE
|
||||
select ARCH_KEEP_MEMBLOCK if ACPI
|
||||
select ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE if 64BIT && MMU
|
||||
select ARCH_OPTIONAL_KERNEL_RWX if ARCH_HAS_STRICT_KERNEL_RWX
|
||||
|
|
@ -116,6 +116,7 @@ config RISCV
|
|||
select GENERIC_SCHED_CLOCK
|
||||
select GENERIC_SMP_IDLE_THREAD
|
||||
select GENERIC_TIME_VSYSCALL if MMU && 64BIT
|
||||
select GENERIC_VDSO_DATA_STORE if MMU
|
||||
select GENERIC_VDSO_TIME_NS if HAVE_GENERIC_VDSO
|
||||
select HARDIRQS_SW_RESEND
|
||||
select HAS_IOPORT if MMU
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
*/
|
||||
#ifdef CONFIG_MMU
|
||||
|
||||
#define __VVAR_PAGES 2
|
||||
#define __VDSO_PAGES 4
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#include <generated/vdso-offsets.h>
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef __RISCV_ASM_VDSO_TIME_DATA_H
|
||||
#define __RISCV_ASM_VDSO_TIME_DATA_H
|
||||
#ifndef __RISCV_ASM_VDSO_ARCH_DATA_H
|
||||
#define __RISCV_ASM_VDSO_ARCH_DATA_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <vdso/datapage.h>
|
||||
#include <asm/hwprobe.h>
|
||||
|
||||
struct arch_vdso_time_data {
|
||||
struct vdso_arch_data {
|
||||
/* Stash static answers to the hwprobe queries when all CPUs are selected. */
|
||||
__u64 all_cpu_hwprobe_values[RISCV_HWPROBE_MAX_KEY + 1];
|
||||
|
||||
|
|
@ -14,4 +14,4 @@ struct arch_vdso_time_data {
|
|||
__u8 homogeneous_cpus;
|
||||
};
|
||||
|
||||
#endif /* __RISCV_ASM_VDSO_TIME_DATA_H */
|
||||
#endif /* __RISCV_ASM_VDSO_ARCH_DATA_H */
|
||||
|
|
@ -69,7 +69,7 @@ int clock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
|
|||
#endif /* CONFIG_GENERIC_TIME_VSYSCALL */
|
||||
|
||||
static __always_inline u64 __arch_get_hw_counter(s32 clock_mode,
|
||||
const struct vdso_data *vd)
|
||||
const struct vdso_time_data *vd)
|
||||
{
|
||||
/*
|
||||
* The purpose of csr_read(CSR_TIME) is to trap the system into
|
||||
|
|
@ -79,18 +79,6 @@ static __always_inline u64 __arch_get_hw_counter(s32 clock_mode,
|
|||
return csr_read(CSR_TIME);
|
||||
}
|
||||
|
||||
static __always_inline const struct vdso_data *__arch_get_vdso_data(void)
|
||||
{
|
||||
return _vdso_data;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TIME_NS
|
||||
static __always_inline
|
||||
const struct vdso_data *__arch_get_timens_vdso_data(const struct vdso_data *vd)
|
||||
{
|
||||
return _timens_data;
|
||||
}
|
||||
#endif
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
|
||||
#endif /* __ASM_VDSO_GETTIMEOFDAY_H */
|
||||
|
|
|
|||
|
|
@ -6,15 +6,6 @@
|
|||
|
||||
#include <vdso/datapage.h>
|
||||
|
||||
extern struct vdso_data *vdso_data;
|
||||
|
||||
static __always_inline struct vdso_data *__riscv_get_k_vdso_data(void)
|
||||
{
|
||||
return vdso_data;
|
||||
}
|
||||
|
||||
#define __arch_get_k_vdso_data __riscv_get_k_vdso_data
|
||||
|
||||
/* The asm-generic header needs to be included after the definitions above */
|
||||
#include <asm-generic/vdso/vsyscall.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -450,8 +450,7 @@ static int do_riscv_hwprobe(struct riscv_hwprobe __user *pairs,
|
|||
|
||||
static int __init init_hwprobe_vdso_data(void)
|
||||
{
|
||||
struct vdso_data *vd = __arch_get_k_vdso_data();
|
||||
struct arch_vdso_time_data *avd = &vd->arch_data;
|
||||
struct vdso_arch_data *avd = vdso_k_arch_data;
|
||||
u64 id_bitsmash = 0;
|
||||
struct riscv_hwprobe pair;
|
||||
int key;
|
||||
|
|
|
|||
|
|
@ -13,20 +13,11 @@
|
|||
#include <linux/err.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/vdso.h>
|
||||
#include <linux/time_namespace.h>
|
||||
#include <linux/vdso_datastore.h>
|
||||
#include <vdso/datapage.h>
|
||||
#include <vdso/vsyscall.h>
|
||||
|
||||
enum vvar_pages {
|
||||
VVAR_DATA_PAGE_OFFSET,
|
||||
VVAR_TIMENS_PAGE_OFFSET,
|
||||
VVAR_NR_PAGES,
|
||||
};
|
||||
|
||||
#define VVAR_SIZE (VVAR_NR_PAGES << PAGE_SHIFT)
|
||||
|
||||
static union vdso_data_store vdso_data_store __page_aligned_data;
|
||||
struct vdso_data *vdso_data = vdso_data_store.data;
|
||||
#define VVAR_SIZE (VDSO_NR_PAGES << PAGE_SHIFT)
|
||||
|
||||
struct __vdso_info {
|
||||
const char *name;
|
||||
|
|
@ -79,78 +70,6 @@ static void __init __vdso_init(struct __vdso_info *vdso_info)
|
|||
vdso_info->cm->pages = vdso_pagelist;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TIME_NS
|
||||
struct vdso_data *arch_get_vdso_data(void *vvar_page)
|
||||
{
|
||||
return (struct vdso_data *)(vvar_page);
|
||||
}
|
||||
|
||||
static const struct vm_special_mapping rv_vvar_map;
|
||||
|
||||
/*
|
||||
* The vvar mapping contains data for a specific time namespace, so when a task
|
||||
* changes namespace we must unmap its vvar data for the old namespace.
|
||||
* Subsequent faults will map in data for the new namespace.
|
||||
*
|
||||
* For more details see timens_setup_vdso_data().
|
||||
*/
|
||||
int vdso_join_timens(struct task_struct *task, struct time_namespace *ns)
|
||||
{
|
||||
struct mm_struct *mm = task->mm;
|
||||
struct vm_area_struct *vma;
|
||||
VMA_ITERATOR(vmi, mm, 0);
|
||||
|
||||
mmap_read_lock(mm);
|
||||
|
||||
for_each_vma(vmi, vma) {
|
||||
if (vma_is_special_mapping(vma, &rv_vvar_map))
|
||||
zap_vma_pages(vma);
|
||||
}
|
||||
|
||||
mmap_read_unlock(mm);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static vm_fault_t vvar_fault(const struct vm_special_mapping *sm,
|
||||
struct vm_area_struct *vma, struct vm_fault *vmf)
|
||||
{
|
||||
struct page *timens_page = find_timens_vvar_page(vma);
|
||||
unsigned long pfn;
|
||||
|
||||
switch (vmf->pgoff) {
|
||||
case VVAR_DATA_PAGE_OFFSET:
|
||||
if (timens_page)
|
||||
pfn = page_to_pfn(timens_page);
|
||||
else
|
||||
pfn = sym_to_pfn(vdso_data);
|
||||
break;
|
||||
#ifdef CONFIG_TIME_NS
|
||||
case VVAR_TIMENS_PAGE_OFFSET:
|
||||
/*
|
||||
* If a task belongs to a time namespace then a namespace
|
||||
* specific VVAR is mapped with the VVAR_DATA_PAGE_OFFSET and
|
||||
* the real VVAR page is mapped with the VVAR_TIMENS_PAGE_OFFSET
|
||||
* offset.
|
||||
* See also the comment near timens_setup_vdso_data().
|
||||
*/
|
||||
if (!timens_page)
|
||||
return VM_FAULT_SIGBUS;
|
||||
pfn = sym_to_pfn(vdso_data);
|
||||
break;
|
||||
#endif /* CONFIG_TIME_NS */
|
||||
default:
|
||||
return VM_FAULT_SIGBUS;
|
||||
}
|
||||
|
||||
return vmf_insert_pfn(vma, vmf->address, pfn);
|
||||
}
|
||||
|
||||
static const struct vm_special_mapping rv_vvar_map = {
|
||||
.name = "[vvar]",
|
||||
.fault = vvar_fault,
|
||||
};
|
||||
|
||||
static struct vm_special_mapping rv_vdso_map __ro_after_init = {
|
||||
.name = "[vdso]",
|
||||
.mremap = vdso_mremap,
|
||||
|
|
@ -196,7 +115,7 @@ static int __setup_additional_pages(struct mm_struct *mm,
|
|||
unsigned long vdso_base, vdso_text_len, vdso_mapping_len;
|
||||
void *ret;
|
||||
|
||||
BUILD_BUG_ON(VVAR_NR_PAGES != __VVAR_PAGES);
|
||||
BUILD_BUG_ON(VDSO_NR_PAGES != __VDSO_PAGES);
|
||||
|
||||
vdso_text_len = vdso_info->vdso_pages << PAGE_SHIFT;
|
||||
/* Be sure to map the data page */
|
||||
|
|
@ -208,8 +127,7 @@ static int __setup_additional_pages(struct mm_struct *mm,
|
|||
goto up_fail;
|
||||
}
|
||||
|
||||
ret = _install_special_mapping(mm, vdso_base, VVAR_SIZE,
|
||||
(VM_READ | VM_MAYREAD | VM_PFNMAP), &rv_vvar_map);
|
||||
ret = vdso_install_vvar_mapping(mm, vdso_base);
|
||||
if (IS_ERR(ret))
|
||||
goto up_fail;
|
||||
|
||||
|
|
|
|||
|
|
@ -16,8 +16,7 @@ static int riscv_vdso_get_values(struct riscv_hwprobe *pairs, size_t pair_count,
|
|||
size_t cpusetsize, unsigned long *cpus,
|
||||
unsigned int flags)
|
||||
{
|
||||
const struct vdso_data *vd = __arch_get_vdso_data();
|
||||
const struct arch_vdso_time_data *avd = &vd->arch_data;
|
||||
const struct vdso_arch_data *avd = &vdso_u_arch_data;
|
||||
bool all_cpus = !cpusetsize && !cpus;
|
||||
struct riscv_hwprobe *p = pairs;
|
||||
struct riscv_hwprobe *end = pairs + pair_count;
|
||||
|
|
@ -51,8 +50,7 @@ static int riscv_vdso_get_cpus(struct riscv_hwprobe *pairs, size_t pair_count,
|
|||
size_t cpusetsize, unsigned long *cpus,
|
||||
unsigned int flags)
|
||||
{
|
||||
const struct vdso_data *vd = __arch_get_vdso_data();
|
||||
const struct arch_vdso_time_data *avd = &vd->arch_data;
|
||||
const struct vdso_arch_data *avd = &vdso_u_arch_data;
|
||||
struct riscv_hwprobe *p = pairs;
|
||||
struct riscv_hwprobe *end = pairs + pair_count;
|
||||
unsigned char *c = (unsigned char *)cpus;
|
||||
|
|
|
|||
|
|
@ -4,15 +4,14 @@
|
|||
*/
|
||||
#include <asm/page.h>
|
||||
#include <asm/vdso.h>
|
||||
#include <vdso/datapage.h>
|
||||
|
||||
OUTPUT_ARCH(riscv)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
PROVIDE(_vdso_data = . - __VVAR_PAGES * PAGE_SIZE);
|
||||
#ifdef CONFIG_TIME_NS
|
||||
PROVIDE(_timens_data = _vdso_data + PAGE_SIZE);
|
||||
#endif
|
||||
VDSO_VVAR_SYMS
|
||||
|
||||
. = SIZEOF_HEADERS;
|
||||
|
||||
.hash : { *(.hash) } :text
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user