lkml.org 
[lkml]   [2017]   [Nov]   [8]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 16/31] nds32: VDSO support
    Date
    From: Greentime Hu <greentime@andestech.com>

    Signed-off-by: Vincent Chen <vincentc@andestech.com>
    Signed-off-by: Greentime Hu <greentime@andestech.com>
    ---
    arch/nds32/include/asm/vdso.h | 35 ++++
    arch/nds32/include/asm/vdso_datapage.h | 51 ++++++
    arch/nds32/kernel/vdso.c | 243 ++++++++++++++++++++++++++
    arch/nds32/kernel/vdso/Makefile | 82 +++++++++
    arch/nds32/kernel/vdso/datapage.S | 34 ++++
    arch/nds32/kernel/vdso/gen_vdso_offsets.sh | 15 ++
    arch/nds32/kernel/vdso/gettimeofday.c | 260 ++++++++++++++++++++++++++++
    arch/nds32/kernel/vdso/note.S | 29 ++++
    arch/nds32/kernel/vdso/sigreturn.S | 32 ++++
    arch/nds32/kernel/vdso/vdso.S | 33 ++++
    arch/nds32/kernel/vdso/vdso.lds.S | 87 ++++++++++
    11 files changed, 901 insertions(+)
    create mode 100644 arch/nds32/include/asm/vdso.h
    create mode 100644 arch/nds32/include/asm/vdso_datapage.h
    create mode 100644 arch/nds32/kernel/vdso.c
    create mode 100644 arch/nds32/kernel/vdso/Makefile
    create mode 100644 arch/nds32/kernel/vdso/datapage.S
    create mode 100755 arch/nds32/kernel/vdso/gen_vdso_offsets.sh
    create mode 100644 arch/nds32/kernel/vdso/gettimeofday.c
    create mode 100644 arch/nds32/kernel/vdso/note.S
    create mode 100644 arch/nds32/kernel/vdso/sigreturn.S
    create mode 100644 arch/nds32/kernel/vdso/vdso.S
    create mode 100644 arch/nds32/kernel/vdso/vdso.lds.S

    diff --git a/arch/nds32/include/asm/vdso.h b/arch/nds32/include/asm/vdso.h
    new file mode 100644
    index 0000000..7298c49
    --- /dev/null
    +++ b/arch/nds32/include/asm/vdso.h
    @@ -0,0 +1,35 @@
    +/*
    + * Copyright (C) 2005-2017 Andes Technology Corporation
    + *
    + * This program is free software; you can redistribute it and/or modify
    + * it under the terms of the GNU General Public License version 2 as
    + * published by the Free Software Foundation.
    + *
    + * This program is distributed in the hope that it will be useful,
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    + * GNU General Public License for more details.
    + *
    + * You should have received a copy of the GNU General Public License
    + * along with this program. If not, see <http://www.gnu.org/licenses/>.
    + */
    +
    +#ifndef __ASM_VDSO_H
    +#define __ASM_VDSO_H
    +
    +#ifdef __KERNEL__
    +
    +#ifndef __ASSEMBLY__
    +
    +#include <generated/vdso-offsets.h>
    +
    +#define VDSO_SYMBOL(base, name) \
    +({ \
    + (unsigned long)(vdso_offset_##name + (unsigned long)(base)); \
    +})
    +
    +#endif /* !__ASSEMBLY__ */
    +
    +#endif /* __KERNEL__ */
    +
    +#endif /* __ASM_VDSO_H */
    diff --git a/arch/nds32/include/asm/vdso_datapage.h b/arch/nds32/include/asm/vdso_datapage.h
    new file mode 100644
    index 0000000..ffae33c
    --- /dev/null
    +++ b/arch/nds32/include/asm/vdso_datapage.h
    @@ -0,0 +1,51 @@
    +/*
    + * Adapted from arm64 version.
    + *
    + * Copyright (C) 2012 ARM Limited
    + * Copyright (C) 2005-2017 Andes Technology Corporation
    + *
    + * This program is free software; you can redistribute it and/or modify
    + * it under the terms of the GNU General Public License version 2 as
    + * published by the Free Software Foundation.
    + *
    + * This program is distributed in the hope that it will be useful,
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    + * GNU General Public License for more details.
    + *
    + * You should have received a copy of the GNU General Public License
    + * along with this program. If not, see <http://www.gnu.org/licenses/>.
    + */
    +#ifndef __ASM_VDSO_DATAPAGE_H
    +#define __ASM_VDSO_DATAPAGE_H
    +
    +#ifdef __KERNEL__
    +
    +#ifndef __ASSEMBLY__
    +
    +struct vdso_data {
    + bool cycle_count_down; /* timer cyclye counter is decrease with time */
    + u32 cycle_count_offset; /* offset of timer cycle counter register */
    + u32 seq_count; /* sequence count - odd during updates */
    + u32 xtime_coarse_sec; /* coarse time */
    + u32 xtime_coarse_nsec;
    +
    + u32 wtm_clock_sec; /* wall to monotonic offset */
    + u32 wtm_clock_nsec;
    + u32 xtime_clock_sec; /* CLOCK_REALTIME - seconds */
    + u32 cs_mult; /* clocksource multiplier */
    + u32 cs_shift; /* Cycle to nanosecond divisor (power of two) */
    +
    + u64 cs_cycle_last; /* last cycle value */
    + u64 cs_mask; /* clocksource mask */
    +
    + u64 xtime_clock_nsec; /* CLOCK_REALTIME sub-ns base */
    + u32 tz_minuteswest; /* timezone info for gettimeofday(2) */
    + u32 tz_dsttime;
    +};
    +
    +#endif /* !__ASSEMBLY__ */
    +
    +#endif /* __KERNEL__ */
    +
    +#endif /* __ASM_VDSO_DATAPAGE_H */
    diff --git a/arch/nds32/kernel/vdso.c b/arch/nds32/kernel/vdso.c
    new file mode 100644
    index 0000000..d7ef70c
    --- /dev/null
    +++ b/arch/nds32/kernel/vdso.c
    @@ -0,0 +1,243 @@
    +/*
    + * VDSO implementation for AArch64 and vector page setup for AArch32.
    + *
    + * Copyright (C) 2012 ARM Limited
    + * Copyright (C) 2005-2017 Andes Technology Corporation
    + *
    + * This program is free software; you can redistribute it and/or modify
    + * it under the terms of the GNU General Public License version 2 as
    + * published by the Free Software Foundation.
    + *
    + * This program is distributed in the hope that it will be useful,
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    + * GNU General Public License for more details.
    + *
    + * You should have received a copy of the GNU General Public License
    + * along with this program. If not, see <http://www.gnu.org/licenses/>.
    + *
    + * Author: Will Deacon <will.deacon@arm.com>
    + */
    +
    +#include <linux/cache.h>
    +#include <linux/clocksource.h>
    +#include <linux/elf.h>
    +#include <linux/err.h>
    +#include <linux/errno.h>
    +#include <linux/gfp.h>
    +#include <linux/kernel.h>
    +#include <linux/mm.h>
    +#include <linux/sched.h>
    +#include <linux/signal.h>
    +#include <linux/slab.h>
    +#include <linux/timekeeper_internal.h>
    +#include <linux/vmalloc.h>
    +
    +#include <linux/platform_device.h>
    +#include <linux/of_address.h>
    +#include <asm/cacheflush.h>
    +#include <asm/vdso.h>
    +#include <asm/vdso_datapage.h>
    +#include <linux/random.h>
    +#include <asm/cache_info.h>
    +extern struct cache_info L1_cache_info[2];
    +extern char vdso_start, vdso_end;
    +static unsigned long vdso_pages __ro_after_init;
    +struct resource timer_res;
    +
    +/*
    + * The vDSO data page.
    + */
    +static struct page *no_pages[] = { NULL };
    +
    +static union {
    + struct vdso_data data;
    + u8 page[PAGE_SIZE];
    +} vdso_data_store __page_aligned_data;
    +struct vdso_data *vdso_data = &vdso_data_store.data;
    +static struct vm_special_mapping vdso_spec[2] __ro_after_init = {
    + {
    + .name = "[vvar]",
    + .pages = no_pages,
    + },
    + {
    + .name = "[vdso]",
    + },
    +};
    +
    +static int grab_timer_node_info(void)
    +{
    + struct device_node *timer_node;
    +
    + timer_node = of_find_node_by_name(NULL, "timer");
    + of_property_read_u32(timer_node, "cycle-count-offset",
    + &vdso_data->cycle_count_offset);
    + vdso_data->cycle_count_down =
    + of_property_read_bool(timer_node, "cycle-count-down");
    + return of_address_to_resource(timer_node, 0, &timer_res);
    +}
    +
    +static int __init vdso_init(void)
    +{
    + int i;
    + struct page **vdso_pagelist;
    +
    + if (memcmp(&vdso_start, "\177ELF", 4)) {
    + pr_err("vDSO is not a valid ELF object!\n");
    + return -EINVAL;
    + }
    + /* Creat a timer io mapping to get clock cycles counter */
    + if (grab_timer_node_info())
    + return -ENODEV;
    +
    + vdso_pages = (&vdso_end - &vdso_start) >> PAGE_SHIFT;
    + pr_info("vdso: %ld pages (%ld code @ %p, %ld data @ %p)\n",
    + vdso_pages + 1, vdso_pages, &vdso_start, 1L, vdso_data);
    +
    + /* Allocate the vDSO pagelist */
    + vdso_pagelist = kcalloc(vdso_pages, sizeof(struct page *), GFP_KERNEL);
    + if (vdso_pagelist == NULL)
    + return -ENOMEM;
    +
    + for (i = 0; i < vdso_pages; i++)
    + vdso_pagelist[i] = virt_to_page(&vdso_start + i * PAGE_SIZE);
    + vdso_spec[1].pages = &vdso_pagelist[0];
    +
    + return 0;
    +}
    +
    +arch_initcall(vdso_init);
    +
    +unsigned long inline vdso_random_addr(unsigned long vdso_mapping_len)
    +{
    + unsigned long start = current->mm->mmap_base, end, offset, addr;
    + start = PAGE_ALIGN(start);
    +
    + /* Round the lowest possible end address up to a PMD boundary. */
    + end = (start + vdso_mapping_len + PMD_SIZE - 1) & PMD_MASK;
    + if (end >= TASK_SIZE)
    + end = TASK_SIZE;
    + end -= vdso_mapping_len;
    +
    + if (end > start) {
    + offset = get_random_int() % (((end - start) >> PAGE_SHIFT) + 1);
    + addr = start + (offset << PAGE_SHIFT);
    + } else {
    + addr = start;
    + }
    + return addr;
    +}
    +
    +int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
    +{
    + struct mm_struct *mm = current->mm;
    + unsigned long vdso_base, vdso_text_len, vdso_mapping_len;
    + struct vm_area_struct *vma;
    + unsigned long addr = 0;
    + pgprot_t prot;
    + int ret;
    +
    + vdso_text_len = vdso_pages << PAGE_SHIFT;
    + /* Be sure to map the data page */
    + vdso_mapping_len = vdso_text_len + 2 * PAGE_SIZE;
    +#ifndef CONFIG_CPU_CACHE_NONALIASING
    + vdso_mapping_len += L1_cache_info[DCACHE].aliasing_num - 1;
    +#endif
    +
    + if (down_write_killable(&mm->mmap_sem))
    + return -EINTR;
    +
    + addr = vdso_random_addr(vdso_mapping_len);
    + vdso_base = get_unmapped_area(NULL, addr, vdso_mapping_len, 0, 0);
    + if (IS_ERR_VALUE(vdso_base)) {
    + ret = vdso_base;
    + goto up_fail;
    + }
    +#ifndef CONFIG_CPU_CACHE_NONALIASING
    + {
    + unsigned int aliasing_mask =
    + L1_cache_info[DCACHE].aliasing_mask;
    + unsigned int page_colour_ofs;
    + page_colour_ofs = ((unsigned int)vdso_data & aliasing_mask) -
    + (vdso_base & aliasing_mask);
    + vdso_base += page_colour_ofs & aliasing_mask;
    + }
    +#endif
    + vma = _install_special_mapping(mm, vdso_base, 2 * PAGE_SIZE,
    + VM_READ | VM_MAYREAD, &vdso_spec[0]);
    + if (IS_ERR(vma)) {
    + ret = PTR_ERR(vma);
    + goto up_fail;
    + }
    +
    + /*Map vdata to user space */
    + ret = io_remap_pfn_range(vma, vdso_base,
    + virt_to_phys(vdso_data) >> PAGE_SHIFT,
    + PAGE_SIZE, vma->vm_page_prot);
    + if (ret)
    + goto up_fail;
    +
    + /*Map timer to user space */
    + vdso_base += PAGE_SIZE;
    + prot = __pgprot(_PAGE_V | _PAGE_M_UR_KR | _PAGE_D |
    + _PAGE_G | _PAGE_C_DEV);
    + ret = io_remap_pfn_range(vma, vdso_base, timer_res.start >> PAGE_SHIFT,
    + PAGE_SIZE, prot);
    + if (ret)
    + goto up_fail;
    +
    + /*Map vdso to user space */
    + vdso_base += PAGE_SIZE;
    + mm->context.vdso = (void *)vdso_base;
    + vma = _install_special_mapping(mm, vdso_base, vdso_text_len,
    + VM_READ | VM_EXEC |
    + VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
    + &vdso_spec[1]);
    + if (IS_ERR(vma)) {
    + ret = PTR_ERR(vma);
    + goto up_fail;
    + }
    +
    + up_write(&mm->mmap_sem);
    + return 0;
    +
    +up_fail:
    + mm->context.vdso = NULL;
    + up_write(&mm->mmap_sem);
    + return ret;
    +}
    +
    +static void vdso_write_begin(struct vdso_data *vdata)
    +{
    + ++vdso_data->seq_count;
    + smp_wmb(); /* Pairs with smp_rmb in vdso_read_retry */
    +}
    +
    +static void vdso_write_end(struct vdso_data *vdata)
    +{
    + smp_wmb(); /* Pairs with smp_rmb in vdso_read_begin */
    + ++vdso_data->seq_count;
    +}
    +
    +void update_vsyscall(struct timekeeper *tk)
    +{
    + vdso_write_begin(vdso_data);
    + vdso_data->cs_mask = tk->tkr_mono.mask;
    + vdso_data->cs_mult = tk->tkr_mono.mult;
    + vdso_data->cs_shift = tk->tkr_mono.shift;
    + vdso_data->cs_cycle_last = tk->tkr_mono.cycle_last;
    + vdso_data->wtm_clock_sec = tk->wall_to_monotonic.tv_sec;
    + vdso_data->wtm_clock_nsec = tk->wall_to_monotonic.tv_nsec;
    + vdso_data->xtime_clock_sec = tk->xtime_sec;
    + vdso_data->xtime_clock_nsec = tk->tkr_mono.xtime_nsec;
    + vdso_data->xtime_coarse_sec = tk->xtime_sec;
    + vdso_data->xtime_coarse_nsec = tk->tkr_mono.xtime_nsec >>
    + tk->tkr_mono.shift;
    + vdso_write_end(vdso_data);
    +}
    +
    +void update_vsyscall_tz(void)
    +{
    + vdso_data->tz_minuteswest = sys_tz.tz_minuteswest;
    + vdso_data->tz_dsttime = sys_tz.tz_dsttime;
    +}
    diff --git a/arch/nds32/kernel/vdso/Makefile b/arch/nds32/kernel/vdso/Makefile
    new file mode 100644
    index 0000000..e6c50a7
    --- /dev/null
    +++ b/arch/nds32/kernel/vdso/Makefile
    @@ -0,0 +1,82 @@
    +#
    +# Building a vDSO image for AArch64.
    +#
    +# Author: Will Deacon <will.deacon@arm.com>
    +# Heavily based on the vDSO Makefiles for other archs.
    +#
    +
    +obj-vdso := note.o datapage.o sigreturn.o gettimeofday.o
    +
    +# Build rules
    +targets := $(obj-vdso) vdso.so vdso.so.dbg
    +obj-vdso := $(addprefix $(obj)/, $(obj-vdso))
    +
    +ccflags-y := -shared -fno-common -fno-builtin
    +ccflags-y += -nostdlib -Wl,-soname=linux-vdso.so.1 \
    + $(call cc-ldoption, -Wl$(comma)--hash-style=sysv)
    +ccflags-y += -fPIC -Wl,-shared -g
    +
    +# Disable gcov profiling for VDSO code
    +GCOV_PROFILE := n
    +
    +
    +obj-y += vdso.o
    +extra-y += vdso.lds
    +CPPFLAGS_vdso.lds += -P -C -U$(ARCH)
    +
    +# Force dependency
    +$(obj)/vdso.o : $(obj)/vdso.so
    +
    +# Link rule for the .so file, .lds has to be first
    +$(obj)/vdso.so.dbg: $(src)/vdso.lds $(obj-vdso)
    + $(call if_changed,vdsold)
    +
    +
    +# Strip rule for the .so file
    +$(obj)/%.so: OBJCOPYFLAGS := -S
    +$(obj)/%.so: $(obj)/%.so.dbg FORCE
    + $(call if_changed,objcopy)
    +
    +# Generate VDSO offsets using helper script
    +gen-vdsosym := $(srctree)/$(src)/gen_vdso_offsets.sh
    +quiet_cmd_vdsosym = VDSOSYM $@
    +define cmd_vdsosym
    + $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@
    +endef
    +
    +include/generated/vdso-offsets.h: $(obj)/vdso.so.dbg FORCE
    + $(call if_changed,vdsosym)
    +
    +
    +
    +# Assembly rules for the .S files
    +
    +sigreturn.o : sigreturn.S
    + $(call if_changed_dep,vdsoas)
    +
    +note.o : note.S
    + $(call if_changed_dep,vdsoas)
    +
    +datapage.o : datapage.S
    + $(call if_changed_dep,vdsoas)
    +
    +gettimeofday.o : gettimeofday.c FORCE
    + $(call if_changed_dep,vdsocc)
    +
    +# Actual build commands
    +quiet_cmd_vdsold = VDSOL $@
    + cmd_vdsold = $(CC) $(c_flags) -Wl,-n -Wl,-T $^ -o $@
    +quiet_cmd_vdsoas = VDSOA $@
    + cmd_vdsoas = $(CC) $(a_flags) -c -o $@ $<
    +quiet_cmd_vdsocc = VDSOA $@
    + cmd_vdsocc = $(CC) $(c_flags) -c -o $@ $<
    +
    +# Install commands for the unstripped file
    +quiet_cmd_vdso_install = INSTALL $@
    + cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@
    +
    +vdso.so: $(obj)/vdso.so.dbg
    + @mkdir -p $(MODLIB)/vdso
    + $(call cmd,vdso_install)
    +
    +vdso_install: vdso.so
    diff --git a/arch/nds32/kernel/vdso/datapage.S b/arch/nds32/kernel/vdso/datapage.S
    new file mode 100644
    index 0000000..d86af66
    --- /dev/null
    +++ b/arch/nds32/kernel/vdso/datapage.S
    @@ -0,0 +1,34 @@
    +/*
    + * Copyright (C) 2005-2017 Andes Technology Corporation
    + *
    + * This program is free software; you can redistribute it and/or modify
    + * it under the terms of the GNU General Public License version 2 as
    + * published by the Free Software Foundation.
    + *
    + * This program is distributed in the hope that it will be useful,
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    + * GNU General Public License for more details.
    + *
    + * You should have received a copy of the GNU General Public License
    + * along with this program. If not, see <http://www.gnu.org/licenses/>.
    + */
    +
    +#include <linux/linkage.h>
    +#include <asm/page.h>
    +
    +ENTRY(__get_timerpage)
    + sethi $r0, hi20(. + PAGE_SIZE + 8)
    + ori $r0, $r0, lo12(. + PAGE_SIZE + 4)
    + mfusr $r1, $pc
    + sub $r0, $r1, $r0
    + ret
    +ENDPROC(__get_timerpage)
    +
    +ENTRY(__get_datapage)
    + sethi $r0, hi20(. + 2*PAGE_SIZE + 8)
    + ori $r0, $r0, lo12(. + 2*PAGE_SIZE + 4)
    + mfusr $r1, $pc
    + sub $r0, $r1, $r0
    + ret
    +ENDPROC(__get_datapage)
    diff --git a/arch/nds32/kernel/vdso/gen_vdso_offsets.sh b/arch/nds32/kernel/vdso/gen_vdso_offsets.sh
    new file mode 100755
    index 0000000..01924ff
    --- /dev/null
    +++ b/arch/nds32/kernel/vdso/gen_vdso_offsets.sh
    @@ -0,0 +1,15 @@
    +#!/bin/sh
    +
    +#
    +# Match symbols in the DSO that look like VDSO_*; produce a header file
    +# of constant offsets into the shared object.
    +#
    +# Doing this inside the Makefile will break the $(filter-out) function,
    +# causing Kbuild to rebuild the vdso-offsets header file every time.
    +#
    +# Author: Will Deacon <will.deacon@arm.com
    +#
    +
    +LC_ALL=C
    +sed -n -e 's/^00*/0/' -e \
    +'s/^\([0-9a-fA-F]*\) . VDSO_\([a-zA-Z0-9_]*\)$/\#define vdso_offset_\2\t0x\1/p'
    diff --git a/arch/nds32/kernel/vdso/gettimeofday.c b/arch/nds32/kernel/vdso/gettimeofday.c
    new file mode 100644
    index 0000000..3a93d4e
    --- /dev/null
    +++ b/arch/nds32/kernel/vdso/gettimeofday.c
    @@ -0,0 +1,260 @@
    +/*
    + * Copyright 2015 Mentor Graphics Corporation.
    + * Copyright (C) 2005-2017 Andes Technology Corporation
    + *
    + * This program is free software; you can redistribute it and/or
    + * modify it under the terms of the GNU General Public License
    + * as published by the Free Software Foundation; version 2 of the
    + * License.
    + *
    + * This program is distributed in the hope that it will be useful, but
    + * WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    + * General Public License for more details.
    + *
    + * You should have received a copy of the GNU General Public License
    + * along with this program. If not, see <http://www.gnu.org/licenses/>.
    + */
    +
    +#include <linux/compiler.h>
    +#include <linux/hrtimer.h>
    +#include <linux/time.h>
    +#include <asm/io.h>
    +#include <asm/barrier.h>
    +#include <asm/bug.h>
    +#include <asm/page.h>
    +#include <asm/unistd.h>
    +#include <asm/vdso_datapage.h>
    +#include <asm/asm-offsets.h>
    +
    +#define X(x) #x
    +#define Y(x) X(x)
    +
    +extern struct vdso_data *__get_datapage(void);
    +extern struct vdso_data *__get_timerpage(void);
    +
    +static notrace unsigned int __vdso_read_begin(const struct vdso_data *vdata)
    +{
    + u32 seq;
    +repeat:
    + seq = ACCESS_ONCE(vdata->seq_count);
    + if (seq & 1) {
    + cpu_relax();
    + goto repeat;
    + }
    + return seq;
    +}
    +
    +static notrace unsigned int vdso_read_begin(const struct vdso_data *vdata)
    +{
    + unsigned int seq;
    +
    + seq = __vdso_read_begin(vdata);
    +
    + smp_rmb(); /* Pairs with smp_wmb in vdso_write_end */
    + return seq;
    +}
    +
    +static notrace int vdso_read_retry(const struct vdso_data *vdata, u32 start)
    +{
    + smp_rmb(); /* Pairs with smp_wmb in vdso_write_begin */
    + return vdata->seq_count != start;
    +}
    +
    +static notrace long clock_gettime_fallback(clockid_t _clkid,
    + struct timespec *_ts)
    +{
    + register struct timespec *ts asm("$r1") = _ts;
    + register clockid_t clkid asm("$r0") = _clkid;
    + register long ret asm("$r0");
    +
    + asm volatile (" syscall " Y(__NR_clock_gettime) "\n":"=r"(ret)
    + :"r"(clkid), "r"(ts)
    + :"memory");
    +
    + return ret;
    +}
    +
    +static notrace int do_realtime_coarse(struct timespec *ts,
    + struct vdso_data *vdata)
    +{
    + u32 seq;
    +
    + do {
    + seq = vdso_read_begin(vdata);
    +
    + ts->tv_sec = vdata->xtime_coarse_sec;
    + ts->tv_nsec = vdata->xtime_coarse_nsec;
    +
    + } while (vdso_read_retry(vdata, seq));
    + return 0;
    +}
    +
    +static notrace int do_monotonic_coarse(struct timespec *ts,
    + struct vdso_data *vdata)
    +{
    + struct timespec tomono;
    + u32 seq;
    +
    + do {
    + seq = vdso_read_begin(vdata);
    +
    + ts->tv_sec = vdata->xtime_coarse_sec;
    + ts->tv_nsec = vdata->xtime_coarse_nsec;
    +
    + tomono.tv_sec = vdata->wtm_clock_sec;
    + tomono.tv_nsec = vdata->wtm_clock_nsec;
    +
    + } while (vdso_read_retry(vdata, seq));
    +
    + ts->tv_sec += tomono.tv_sec;
    + timespec_add_ns(ts, tomono.tv_nsec);
    + return 0;
    +}
    +
    +static inline u64 vgetsns(struct vdso_data *vdso)
    +{
    + u32 cycle_now;
    + u32 cycle_delta;
    + u32 *timer_cycle_base;
    +
    + timer_cycle_base =
    + (u32 *) ((char *)__get_timerpage() + vdso->cycle_count_offset);
    + cycle_now = readl_relaxed(timer_cycle_base);
    + if (true == vdso->cycle_count_down)
    + cycle_now = ~(*timer_cycle_base);
    + cycle_delta = cycle_now - (u32) vdso->cs_cycle_last;
    + return ((u64) cycle_delta & vdso->cs_mask) * vdso->cs_mult;
    +}
    +
    +static notrace int do_realtime(struct timespec *ts, struct vdso_data *vdata)
    +{
    + unsigned count;
    + u64 ns;
    + do {
    + count = vdso_read_begin(vdata);
    + ts->tv_sec = vdata->xtime_clock_sec;
    + ns = vdata->xtime_clock_nsec;
    + ns += vgetsns(vdata);
    + ns >>= vdata->cs_shift;
    + } while (vdso_read_retry(vdata, count));
    +
    + ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns);
    + ts->tv_nsec = ns;
    +
    + return 0;
    +}
    +
    +static notrace int do_monotonic(struct timespec *ts, struct vdso_data *vdata)
    +{
    + struct timespec tomono;
    + u64 nsecs;
    + u32 seq;
    +
    + do {
    + seq = vdso_read_begin(vdata);
    +
    + ts->tv_sec = vdata->xtime_clock_sec;
    + nsecs = vdata->xtime_clock_nsec;
    + nsecs += vgetsns(vdata);
    + nsecs >>= vdata->cs_shift;
    +
    + tomono.tv_sec = vdata->wtm_clock_sec;
    + tomono.tv_nsec = vdata->wtm_clock_nsec;
    +
    + } while (vdso_read_retry(vdata, seq));
    +
    + ts->tv_sec += tomono.tv_sec;
    + ts->tv_nsec = 0;
    + timespec_add_ns(ts, nsecs + tomono.tv_nsec);
    + return 0;
    +}
    +
    +notrace int __vdso_clock_gettime(clockid_t clkid, struct timespec *ts)
    +{
    + struct vdso_data *vdata;
    + int ret = -1;
    +
    + vdata = __get_datapage();
    +
    + switch (clkid) {
    + case CLOCK_REALTIME_COARSE:
    + ret = do_realtime_coarse(ts, vdata);
    + break;
    + case CLOCK_MONOTONIC_COARSE:
    + ret = do_monotonic_coarse(ts, vdata);
    + break;
    + case CLOCK_REALTIME:
    + ret = do_realtime(ts, vdata);
    + break;
    + case CLOCK_MONOTONIC:
    + ret = do_monotonic(ts, vdata);
    + break;
    + default:
    + break;
    + }
    +
    + if (ret)
    + ret = clock_gettime_fallback(clkid, ts);
    +
    + return ret;
    +}
    +
    +static notrace long clock_getres_fallback(clockid_t _clk_id,
    + struct timespec *_res)
    +{
    + register clockid_t clk_id asm("$r0") = _clk_id;
    + register struct timespec *res asm("$r1") = _res;
    + register long ret asm("$r0");
    +
    + asm volatile (" syscall " Y(__NR_clock_getres) " \n":"=r"(ret)
    + :"r"(clk_id), "r"(res)
    + :"memory");
    +
    + return ret;
    +}
    +
    +notrace int __vdso_clock_getres(clockid_t clk_id, struct timespec *res)
    +{
    + if (res == NULL)
    + return -EFAULT;
    + switch (clk_id) {
    + case CLOCK_REALTIME:
    + case CLOCK_MONOTONIC:
    + case CLOCK_MONOTONIC_RAW:
    + res->tv_sec = 0;
    + res->tv_nsec = CLOCK_REALTIME_RES;
    + break;
    + case CLOCK_REALTIME_COARSE:
    + case CLOCK_MONOTONIC_COARSE:
    + res->tv_sec = 0;
    + res->tv_nsec = CLOCK_COARSE_RES;
    + break;
    + default:
    + clock_getres_fallback(clk_id, res);
    + break;
    + }
    + return 0;
    +}
    +
    +notrace int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
    +{
    + struct timespec ts;
    + struct vdso_data *vdata;
    + int ret;
    +
    + vdata = __get_datapage();
    +
    + ret = do_realtime(&ts, vdata);
    +
    + if (tv) {
    + tv->tv_sec = ts.tv_sec;
    + tv->tv_usec = ts.tv_nsec / 1000;
    + }
    + if (tz) {
    + tz->tz_minuteswest = vdata->tz_minuteswest;
    + tz->tz_dsttime = vdata->tz_dsttime;
    + }
    +
    + return ret;
    +}
    diff --git a/arch/nds32/kernel/vdso/note.S b/arch/nds32/kernel/vdso/note.S
    new file mode 100644
    index 0000000..59c6397
    --- /dev/null
    +++ b/arch/nds32/kernel/vdso/note.S
    @@ -0,0 +1,29 @@
    +/*
    + * Copyright (C) 2012 ARM Limited
    + * Copyright (C) 2005-2017 Andes Technology Corporation
    + *
    + * This program is free software; you can redistribute it and/or modify
    + * it under the terms of the GNU General Public License version 2 as
    + * published by the Free Software Foundation.
    + *
    + * This program is distributed in the hope that it will be useful,
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    + * GNU General Public License for more details.
    + *
    + * You should have received a copy of the GNU General Public License
    + * along with this program. If not, see <http://www.gnu.org/licenses/>.
    + *
    + * Author: Will Deacon <will.deacon@arm.com>
    + *
    + * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text.
    + * Here we can supply some information useful to userland.
    + */
    +
    +#include <linux/uts.h>
    +#include <linux/version.h>
    +#include <linux/elfnote.h>
    +
    +ELFNOTE_START(Linux, 0, "a")
    + .long LINUX_VERSION_CODE
    +ELFNOTE_END
    diff --git a/arch/nds32/kernel/vdso/sigreturn.S b/arch/nds32/kernel/vdso/sigreturn.S
    new file mode 100644
    index 0000000..e3cd9d7
    --- /dev/null
    +++ b/arch/nds32/kernel/vdso/sigreturn.S
    @@ -0,0 +1,32 @@
    +/*
    + * Sigreturn trampoline for returning from a signal when the SA_RESTORER
    + * flag is not set.
    + *
    + * Copyright (C) 2012 ARM Limited
    + * Copyright (C) 2005-2017 Andes Technology Corporation
    + *
    + * This program is free software; you can redistribute it and/or modify
    + * it under the terms of the GNU General Public License version 2 as
    + * published by the Free Software Foundation.
    + *
    + * This program is distributed in the hope that it will be useful,
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    + * GNU General Public License for more details.
    + *
    + * You should have received a copy of the GNU General Public License
    + * along with this program. If not, see <http://www.gnu.org/licenses/>.
    + *
    + * Author: Will Deacon <will.deacon@arm.com>
    + */
    +
    +#include <linux/linkage.h>
    +#include <asm/unistd.h>
    +
    + .text
    +
    +ENTRY(__kernel_rt_sigreturn)
    + .cfi_startproc
    + syscall #__NR_rt_sigreturn
    + .cfi_endproc
    +ENDPROC(__kernel_rt_sigreturn)
    diff --git a/arch/nds32/kernel/vdso/vdso.S b/arch/nds32/kernel/vdso/vdso.S
    new file mode 100644
    index 0000000..4444082
    --- /dev/null
    +++ b/arch/nds32/kernel/vdso/vdso.S
    @@ -0,0 +1,33 @@
    +/*
    + * Copyright (C) 2012 ARM Limited
    + * Copyright (C) 2005-2017 Andes Technology Corporation
    + *
    + * This program is free software; you can redistribute it and/or modify
    + * it under the terms of the GNU General Public License version 2 as
    + * published by the Free Software Foundation.
    + *
    + * This program is distributed in the hope that it will be useful,
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    + * GNU General Public License for more details.
    + *
    + * You should have received a copy of the GNU General Public License
    + * along with this program. If not, see <http://www.gnu.org/licenses/>.
    + *
    + * Author: Will Deacon <will.deacon@arm.com>
    + */
    +
    +#include <linux/init.h>
    +#include <linux/linkage.h>
    +#include <linux/const.h>
    +#include <asm/page.h>
    +
    + .globl vdso_start, vdso_end
    + .section .rodata
    + .balign PAGE_SIZE
    +vdso_start:
    + .incbin "arch/nds32/kernel/vdso/vdso.so"
    + .balign PAGE_SIZE
    +vdso_end:
    +
    + .previous
    diff --git a/arch/nds32/kernel/vdso/vdso.lds.S b/arch/nds32/kernel/vdso/vdso.lds.S
    new file mode 100644
    index 0000000..9842ec7
    --- /dev/null
    +++ b/arch/nds32/kernel/vdso/vdso.lds.S
    @@ -0,0 +1,87 @@
    +/*
    + * Copyright (C) 2005-2017 Andes Technology Corporation
    + *
    + * This program is free software; you can redistribute it and/or modify
    + * it under the terms of the GNU General Public License version 2 as
    + * published by the Free Software Foundation.
    + *
    + * This program is distributed in the hope that it will be useful,
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    + * GNU General Public License for more details.
    + *
    + * You should have received a copy of the GNU General Public License
    + * along with this program. If not, see <http://www.gnu.org/licenses/>.
    + */
    +
    +
    +#include <linux/const.h>
    +#include <asm/page.h>
    +#include <asm/vdso.h>
    +
    +OUTPUT_FORMAT("elf32-nds32le-linux", "elf32-nds32be-linux", "elf32-nds32le-linux")
    +OUTPUT_ARCH(nds32)
    +
    +SECTIONS
    +{
    + . = SIZEOF_HEADERS;
    +
    + .hash : { *(.hash) } :text
    + .gnu.hash : { *(.gnu.hash) }
    + .dynsym : { *(.dynsym) }
    + .dynstr : { *(.dynstr) }
    + .gnu.version : { *(.gnu.version) }
    + .gnu.version_d : { *(.gnu.version_d) }
    + .gnu.version_r : { *(.gnu.version_r) }
    +
    + .note : { *(.note.*) } :text :note
    +
    +
    + .text : { *(.text*) } :text
    +
    + .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
    + .eh_frame : { KEEP (*(.eh_frame)) } :text
    +
    + .dynamic : { *(.dynamic) } :text :dynamic
    +
    + .rodata : { *(.rodata*) } :text
    +
    +
    + /DISCARD/ : {
    + *(.note.GNU-stack)
    + *(.data .data.* .gnu.linkonce.d.* .sdata*)
    + *(.bss .sbss .dynbss .dynsbss)
    + }
    +}
    +
    +/*
    + * We must supply the ELF program headers explicitly to get just one
    + * PT_LOAD segment, and set the flags explicitly to make segments read-only.
    + */
    +PHDRS
    +{
    + text PT_LOAD FLAGS(5) FILEHDR PHDRS; /* PF_R|PF_X */
    + dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
    + note PT_NOTE FLAGS(4); /* PF_R */
    + eh_frame_hdr PT_GNU_EH_FRAME;
    +}
    +
    +/*
    + * This controls what symbols we export from the DSO.
    + */
    +VERSION
    +{
    + LINUX_2.6 {
    + global:
    + __kernel_rt_sigreturn;
    + __vdso_gettimeofday;
    + __vdso_clock_getres;
    + __vdso_clock_gettime;
    + local: *;
    + };
    +}
    +
    +/*
    + * Make the rt_sigreturn code visible to the kernel.
    + */
    +VDSO_rt_sigtramp = __kernel_rt_sigreturn;
    --
    1.7.9.5
    \
     
     \ /
      Last update: 2017-11-08 21:10    [W:4.395 / U:0.236 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site