mirror of https://github.com/torvalds/linux.git
MIPS: 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-13-13a4669dfc8c@linutronix.de
This commit is contained in:
parent
9bf39a65b2
commit
69896119dc
|
|
@ -51,6 +51,7 @@ config MIPS
|
||||||
select GENERIC_SMP_IDLE_THREAD
|
select GENERIC_SMP_IDLE_THREAD
|
||||||
select GENERIC_IDLE_POLL_SETUP
|
select GENERIC_IDLE_POLL_SETUP
|
||||||
select GENERIC_TIME_VSYSCALL
|
select GENERIC_TIME_VSYSCALL
|
||||||
|
select GENERIC_VDSO_DATA_STORE
|
||||||
select GUP_GET_PXX_LOW_HIGH if CPU_MIPS32 && PHYS_ADDR_T_64BIT
|
select GUP_GET_PXX_LOW_HIGH if CPU_MIPS32 && PHYS_ADDR_T_64BIT
|
||||||
select HAS_IOPORT if !NO_IOPORT_MAP || ISA
|
select HAS_IOPORT if !NO_IOPORT_MAP || ISA
|
||||||
select HAVE_ARCH_COMPILER_H
|
select HAVE_ARCH_COMPILER_H
|
||||||
|
|
|
||||||
|
|
@ -167,7 +167,7 @@ static __always_inline u64 read_r4k_count(void)
|
||||||
|
|
||||||
#ifdef CONFIG_CLKSRC_MIPS_GIC
|
#ifdef CONFIG_CLKSRC_MIPS_GIC
|
||||||
|
|
||||||
static __always_inline u64 read_gic_count(const struct vdso_data *data)
|
static __always_inline u64 read_gic_count(const struct vdso_time_data *data)
|
||||||
{
|
{
|
||||||
void __iomem *gic = get_gic(data);
|
void __iomem *gic = get_gic(data);
|
||||||
u32 hi, hi2, lo;
|
u32 hi, hi2, lo;
|
||||||
|
|
@ -184,7 +184,7 @@ static __always_inline u64 read_gic_count(const struct vdso_data *data)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static __always_inline u64 __arch_get_hw_counter(s32 clock_mode,
|
static __always_inline u64 __arch_get_hw_counter(s32 clock_mode,
|
||||||
const struct vdso_data *vd)
|
const struct vdso_time_data *vd)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_CSRC_R4K
|
#ifdef CONFIG_CSRC_R4K
|
||||||
if (clock_mode == VDSO_CLOCKMODE_R4K)
|
if (clock_mode == VDSO_CLOCKMODE_R4K)
|
||||||
|
|
@ -209,10 +209,11 @@ static inline bool mips_vdso_hres_capable(void)
|
||||||
}
|
}
|
||||||
#define __arch_vdso_hres_capable mips_vdso_hres_capable
|
#define __arch_vdso_hres_capable mips_vdso_hres_capable
|
||||||
|
|
||||||
static __always_inline const struct vdso_data *__arch_get_vdso_data(void)
|
static __always_inline const struct vdso_time_data *__arch_get_vdso_u_time_data(void)
|
||||||
{
|
{
|
||||||
return get_vdso_data();
|
return get_vdso_time_data();
|
||||||
}
|
}
|
||||||
|
#define __arch_get_vdso_u_time_data __arch_get_vdso_u_time_data
|
||||||
|
|
||||||
#endif /* !__ASSEMBLY__ */
|
#endif /* !__ASSEMBLY__ */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,16 +5,18 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <asm/sgidefs.h>
|
#include <asm/sgidefs.h>
|
||||||
|
#include <vdso/page.h>
|
||||||
|
|
||||||
|
#define __VDSO_PAGES 4
|
||||||
|
|
||||||
#ifndef __ASSEMBLY__
|
#ifndef __ASSEMBLY__
|
||||||
|
|
||||||
#include <asm/asm.h>
|
#include <asm/asm.h>
|
||||||
#include <asm/page.h>
|
|
||||||
#include <asm/vdso.h>
|
#include <asm/vdso.h>
|
||||||
|
|
||||||
static inline unsigned long get_vdso_base(void)
|
static inline const struct vdso_time_data *get_vdso_time_data(void)
|
||||||
{
|
{
|
||||||
unsigned long addr;
|
const struct vdso_time_data *addr;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We can't use cpu_has_mips_r6 since it needs the cpu_data[]
|
* We can't use cpu_has_mips_r6 since it needs the cpu_data[]
|
||||||
|
|
@ -27,7 +29,7 @@ static inline unsigned long get_vdso_base(void)
|
||||||
* We can't use addiupc because there is no label-label
|
* We can't use addiupc because there is no label-label
|
||||||
* support for the addiupc reloc
|
* support for the addiupc reloc
|
||||||
*/
|
*/
|
||||||
__asm__("lapc %0, _start \n"
|
__asm__("lapc %0, vdso_u_time_data \n"
|
||||||
: "=r" (addr) : :);
|
: "=r" (addr) : :);
|
||||||
#else
|
#else
|
||||||
/*
|
/*
|
||||||
|
|
@ -46,7 +48,7 @@ static inline unsigned long get_vdso_base(void)
|
||||||
" .set noreorder \n"
|
" .set noreorder \n"
|
||||||
" bal 1f \n"
|
" bal 1f \n"
|
||||||
" nop \n"
|
" nop \n"
|
||||||
" .word _start - . \n"
|
" .word vdso_u_time_data - . \n"
|
||||||
"1: lw %0, 0($31) \n"
|
"1: lw %0, 0($31) \n"
|
||||||
" " STR(PTR_ADDU) " %0, $31, %0 \n"
|
" " STR(PTR_ADDU) " %0, $31, %0 \n"
|
||||||
" .set pop \n"
|
" .set pop \n"
|
||||||
|
|
@ -58,14 +60,9 @@ static inline unsigned long get_vdso_base(void)
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline const struct vdso_data *get_vdso_data(void)
|
|
||||||
{
|
|
||||||
return (const struct vdso_data *)(get_vdso_base() - PAGE_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_CLKSRC_MIPS_GIC
|
#ifdef CONFIG_CLKSRC_MIPS_GIC
|
||||||
|
|
||||||
static inline void __iomem *get_gic(const struct vdso_data *data)
|
static inline void __iomem *get_gic(const struct vdso_time_data *data)
|
||||||
{
|
{
|
||||||
return (void __iomem *)((unsigned long)data & PAGE_MASK) - PAGE_SIZE;
|
return (void __iomem *)((unsigned long)data & PAGE_MASK) - PAGE_SIZE;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,22 +2,12 @@
|
||||||
#ifndef __ASM_VDSO_VSYSCALL_H
|
#ifndef __ASM_VDSO_VSYSCALL_H
|
||||||
#define __ASM_VDSO_VSYSCALL_H
|
#define __ASM_VDSO_VSYSCALL_H
|
||||||
|
|
||||||
|
#include <asm/page.h>
|
||||||
|
|
||||||
#ifndef __ASSEMBLY__
|
#ifndef __ASSEMBLY__
|
||||||
|
|
||||||
#include <vdso/datapage.h>
|
#include <vdso/datapage.h>
|
||||||
|
|
||||||
extern struct vdso_data *vdso_data;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Update the vDSO data page to keep in sync with kernel timekeeping.
|
|
||||||
*/
|
|
||||||
static __always_inline
|
|
||||||
struct vdso_data *__mips_get_k_vdso_data(void)
|
|
||||||
{
|
|
||||||
return vdso_data;
|
|
||||||
}
|
|
||||||
#define __arch_get_k_vdso_data __mips_get_k_vdso_data
|
|
||||||
|
|
||||||
/* The asm-generic header needs to be included after the definitions above */
|
/* The asm-generic header needs to be included after the definitions above */
|
||||||
#include <asm-generic/vdso/vsyscall.h>
|
#include <asm-generic/vdso/vsyscall.h>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
#include <linux/random.h>
|
#include <linux/random.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
#include <linux/vdso_datastore.h>
|
||||||
|
|
||||||
#include <asm/abi.h>
|
#include <asm/abi.h>
|
||||||
#include <asm/mips-cps.h>
|
#include <asm/mips-cps.h>
|
||||||
|
|
@ -23,20 +24,7 @@
|
||||||
#include <vdso/helpers.h>
|
#include <vdso/helpers.h>
|
||||||
#include <vdso/vsyscall.h>
|
#include <vdso/vsyscall.h>
|
||||||
|
|
||||||
/* Kernel-provided data used by the VDSO. */
|
static_assert(VDSO_NR_PAGES == __VDSO_PAGES);
|
||||||
static union vdso_data_store mips_vdso_data __page_aligned_data;
|
|
||||||
struct vdso_data *vdso_data = mips_vdso_data.data;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Mapping for the VDSO data/GIC pages. The real pages are mapped manually, as
|
|
||||||
* what we map and where within the area they are mapped is determined at
|
|
||||||
* runtime.
|
|
||||||
*/
|
|
||||||
static struct page *no_pages[] = { NULL };
|
|
||||||
static struct vm_special_mapping vdso_vvar_mapping = {
|
|
||||||
.name = "[vvar]",
|
|
||||||
.pages = no_pages,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void __init init_vdso_image(struct mips_vdso_image *image)
|
static void __init init_vdso_image(struct mips_vdso_image *image)
|
||||||
{
|
{
|
||||||
|
|
@ -90,7 +78,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
|
||||||
{
|
{
|
||||||
struct mips_vdso_image *image = current->thread.abi->vdso;
|
struct mips_vdso_image *image = current->thread.abi->vdso;
|
||||||
struct mm_struct *mm = current->mm;
|
struct mm_struct *mm = current->mm;
|
||||||
unsigned long gic_size, vvar_size, size, base, data_addr, vdso_addr, gic_pfn, gic_base;
|
unsigned long gic_size, size, base, data_addr, vdso_addr, gic_pfn, gic_base;
|
||||||
struct vm_area_struct *vma;
|
struct vm_area_struct *vma;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
|
@ -119,8 +107,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
|
||||||
* the counter registers at the start.
|
* the counter registers at the start.
|
||||||
*/
|
*/
|
||||||
gic_size = mips_gic_present() ? PAGE_SIZE : 0;
|
gic_size = mips_gic_present() ? PAGE_SIZE : 0;
|
||||||
vvar_size = gic_size + PAGE_SIZE;
|
size = gic_size + VDSO_NR_PAGES * PAGE_SIZE + image->size;
|
||||||
size = vvar_size + image->size;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find a region that's large enough for us to perform the
|
* Find a region that's large enough for us to perform the
|
||||||
|
|
@ -143,15 +130,13 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
|
||||||
*/
|
*/
|
||||||
if (cpu_has_dc_aliases) {
|
if (cpu_has_dc_aliases) {
|
||||||
base = __ALIGN_MASK(base, shm_align_mask);
|
base = __ALIGN_MASK(base, shm_align_mask);
|
||||||
base += ((unsigned long)vdso_data - gic_size) & shm_align_mask;
|
base += ((unsigned long)vdso_k_time_data - gic_size) & shm_align_mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
data_addr = base + gic_size;
|
data_addr = base + gic_size;
|
||||||
vdso_addr = data_addr + PAGE_SIZE;
|
vdso_addr = data_addr + VDSO_NR_PAGES * PAGE_SIZE;
|
||||||
|
|
||||||
vma = _install_special_mapping(mm, base, vvar_size,
|
vma = vdso_install_vvar_mapping(mm, data_addr);
|
||||||
VM_READ | VM_MAYREAD,
|
|
||||||
&vdso_vvar_mapping);
|
|
||||||
if (IS_ERR(vma)) {
|
if (IS_ERR(vma)) {
|
||||||
ret = PTR_ERR(vma);
|
ret = PTR_ERR(vma);
|
||||||
goto out;
|
goto out;
|
||||||
|
|
@ -161,6 +146,17 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
|
||||||
if (gic_size) {
|
if (gic_size) {
|
||||||
gic_base = (unsigned long)mips_gic_base + MIPS_GIC_USER_OFS;
|
gic_base = (unsigned long)mips_gic_base + MIPS_GIC_USER_OFS;
|
||||||
gic_pfn = PFN_DOWN(__pa(gic_base));
|
gic_pfn = PFN_DOWN(__pa(gic_base));
|
||||||
|
static const struct vm_special_mapping gic_mapping = {
|
||||||
|
.name = "[gic]",
|
||||||
|
.pages = (struct page **) { NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
vma = _install_special_mapping(mm, base, gic_size, VM_READ | VM_MAYREAD,
|
||||||
|
&gic_mapping);
|
||||||
|
if (IS_ERR(vma)) {
|
||||||
|
ret = PTR_ERR(vma);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
ret = io_remap_pfn_range(vma, base, gic_pfn, gic_size,
|
ret = io_remap_pfn_range(vma, base, gic_pfn, gic_size,
|
||||||
pgprot_noncached(vma->vm_page_prot));
|
pgprot_noncached(vma->vm_page_prot));
|
||||||
|
|
@ -168,13 +164,6 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Map data page. */
|
|
||||||
ret = remap_pfn_range(vma, data_addr,
|
|
||||||
virt_to_phys(vdso_data) >> PAGE_SHIFT,
|
|
||||||
PAGE_SIZE, vma->vm_page_prot);
|
|
||||||
if (ret)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
/* Map VDSO image. */
|
/* Map VDSO image. */
|
||||||
vma = _install_special_mapping(mm, vdso_addr, image->size,
|
vma = _install_special_mapping(mm, vdso_addr, image->size,
|
||||||
VM_READ | VM_EXEC |
|
VM_READ | VM_EXEC |
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <asm/sgidefs.h>
|
#include <asm/sgidefs.h>
|
||||||
|
#include <asm/vdso/vdso.h>
|
||||||
|
#include <vdso/datapage.h>
|
||||||
|
|
||||||
#if _MIPS_SIM == _MIPS_SIM_ABI64
|
#if _MIPS_SIM == _MIPS_SIM_ABI64
|
||||||
OUTPUT_FORMAT("elf64-tradlittlemips", "elf64-tradbigmips", "elf64-tradlittlemips")
|
OUTPUT_FORMAT("elf64-tradlittlemips", "elf64-tradbigmips", "elf64-tradlittlemips")
|
||||||
|
|
@ -18,7 +20,8 @@ OUTPUT_ARCH(mips)
|
||||||
|
|
||||||
SECTIONS
|
SECTIONS
|
||||||
{
|
{
|
||||||
PROVIDE(_start = .);
|
VDSO_VVAR_SYMS
|
||||||
|
|
||||||
. = SIZEOF_HEADERS;
|
. = SIZEOF_HEADERS;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue