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

nds32: VDSO support

This patch adds VDSO support. The VDSO code is currently used for
sys_rt_sigreturn() and optimised gettimeofday() (using the SoC timer counter).

Signed-off-by: Vincent Chen <vincentc@andestech.com>
Signed-off-by: Greentime Hu <greentime@andestech.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>

+816
+24
arch/nds32/include/asm/vdso.h
··· 1 + /* 2 + * SPDX-License-Identifier: GPL-2.0 3 + * Copyright (C) 2005-2017 Andes Technology Corporation 4 + */ 5 + 6 + #ifndef __ASM_VDSO_H 7 + #define __ASM_VDSO_H 8 + 9 + #ifdef __KERNEL__ 10 + 11 + #ifndef __ASSEMBLY__ 12 + 13 + #include <generated/vdso-offsets.h> 14 + 15 + #define VDSO_SYMBOL(base, name) \ 16 + ({ \ 17 + (unsigned long)(vdso_offset_##name + (unsigned long)(base)); \ 18 + }) 19 + 20 + #endif /* !__ASSEMBLY__ */ 21 + 22 + #endif /* __KERNEL__ */ 23 + 24 + #endif /* __ASM_VDSO_H */
+36
arch/nds32/include/asm/vdso_datapage.h
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (C) 2012 ARM Limited 3 + // Copyright (C) 2005-2017 Andes Technology Corporation 4 + #ifndef __ASM_VDSO_DATAPAGE_H 5 + #define __ASM_VDSO_DATAPAGE_H 6 + 7 + #ifdef __KERNEL__ 8 + 9 + #ifndef __ASSEMBLY__ 10 + 11 + struct vdso_data { 12 + bool cycle_count_down; /* timer cyclye counter is decrease with time */ 13 + u32 cycle_count_offset; /* offset of timer cycle counter register */ 14 + u32 seq_count; /* sequence count - odd during updates */ 15 + u32 xtime_coarse_sec; /* coarse time */ 16 + u32 xtime_coarse_nsec; 17 + 18 + u32 wtm_clock_sec; /* wall to monotonic offset */ 19 + u32 wtm_clock_nsec; 20 + u32 xtime_clock_sec; /* CLOCK_REALTIME - seconds */ 21 + u32 cs_mult; /* clocksource multiplier */ 22 + u32 cs_shift; /* Cycle to nanosecond divisor (power of two) */ 23 + 24 + u64 cs_cycle_last; /* last cycle value */ 25 + u64 cs_mask; /* clocksource mask */ 26 + 27 + u64 xtime_clock_nsec; /* CLOCK_REALTIME sub-ns base */ 28 + u32 tz_minuteswest; /* timezone info for gettimeofday(2) */ 29 + u32 tz_dsttime; 30 + }; 31 + 32 + #endif /* !__ASSEMBLY__ */ 33 + 34 + #endif /* __KERNEL__ */ 35 + 36 + #endif /* __ASM_VDSO_DATAPAGE_H */
+14
arch/nds32/include/asm/vdso_timer_info.h
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (C) 2005-2017 Andes Technology Corporation 3 + 4 + extern struct timer_info_t timer_info; 5 + #define EMPTY_VALUE ~(0UL) 6 + #define EMPTY_TIMER_MAPPING EMPTY_VALUE 7 + #define EMPTY_REG_OFFSET EMPTY_VALUE 8 + 9 + struct timer_info_t 10 + { 11 + bool cycle_count_down; 12 + unsigned long mapping_base; 13 + unsigned long cycle_count_reg_offset; 14 + };
+230
arch/nds32/kernel/vdso.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (C) 2012 ARM Limited 3 + // Copyright (C) 2005-2017 Andes Technology Corporation 4 + 5 + #include <linux/cache.h> 6 + #include <linux/clocksource.h> 7 + #include <linux/elf.h> 8 + #include <linux/err.h> 9 + #include <linux/errno.h> 10 + #include <linux/gfp.h> 11 + #include <linux/kernel.h> 12 + #include <linux/mm.h> 13 + #include <linux/sched.h> 14 + #include <linux/signal.h> 15 + #include <linux/slab.h> 16 + #include <linux/timekeeper_internal.h> 17 + #include <linux/vmalloc.h> 18 + #include <linux/random.h> 19 + 20 + #include <asm/cacheflush.h> 21 + #include <asm/vdso.h> 22 + #include <asm/vdso_datapage.h> 23 + #include <asm/vdso_timer_info.h> 24 + #include <asm/cache_info.h> 25 + extern struct cache_info L1_cache_info[2]; 26 + extern char vdso_start, vdso_end; 27 + static unsigned long vdso_pages __ro_after_init; 28 + static unsigned long timer_mapping_base; 29 + 30 + struct timer_info_t timer_info = { 31 + .cycle_count_down = true, 32 + .mapping_base = EMPTY_TIMER_MAPPING, 33 + .cycle_count_reg_offset = EMPTY_REG_OFFSET 34 + }; 35 + /* 36 + * The vDSO data page. 37 + */ 38 + static struct page *no_pages[] = { NULL }; 39 + 40 + static union { 41 + struct vdso_data data; 42 + u8 page[PAGE_SIZE]; 43 + } vdso_data_store __page_aligned_data; 44 + struct vdso_data *vdso_data = &vdso_data_store.data; 45 + static struct vm_special_mapping vdso_spec[2] __ro_after_init = { 46 + { 47 + .name = "[vvar]", 48 + .pages = no_pages, 49 + }, 50 + { 51 + .name = "[vdso]", 52 + }, 53 + }; 54 + 55 + static void get_timer_node_info(void) 56 + { 57 + timer_mapping_base = timer_info.mapping_base; 58 + vdso_data->cycle_count_offset = 59 + timer_info.cycle_count_reg_offset; 60 + vdso_data->cycle_count_down = 61 + timer_info.cycle_count_down; 62 + } 63 + 64 + static int __init vdso_init(void) 65 + { 66 + int i; 67 + struct page **vdso_pagelist; 68 + 69 + if (memcmp(&vdso_start, "\177ELF", 4)) { 70 + pr_err("vDSO is not a valid ELF object!\n"); 71 + return -EINVAL; 72 + } 73 + /* Creat a timer io mapping to get clock cycles counter */ 74 + get_timer_node_info(); 75 + 76 + vdso_pages = (&vdso_end - &vdso_start) >> PAGE_SHIFT; 77 + pr_info("vdso: %ld pages (%ld code @ %p, %ld data @ %p)\n", 78 + vdso_pages + 1, vdso_pages, &vdso_start, 1L, vdso_data); 79 + 80 + /* Allocate the vDSO pagelist */ 81 + vdso_pagelist = kcalloc(vdso_pages, sizeof(struct page *), GFP_KERNEL); 82 + if (vdso_pagelist == NULL) 83 + return -ENOMEM; 84 + 85 + for (i = 0; i < vdso_pages; i++) 86 + vdso_pagelist[i] = virt_to_page(&vdso_start + i * PAGE_SIZE); 87 + vdso_spec[1].pages = &vdso_pagelist[0]; 88 + 89 + return 0; 90 + } 91 + 92 + arch_initcall(vdso_init); 93 + 94 + unsigned long inline vdso_random_addr(unsigned long vdso_mapping_len) 95 + { 96 + unsigned long start = current->mm->mmap_base, end, offset, addr; 97 + start = PAGE_ALIGN(start); 98 + 99 + /* Round the lowest possible end address up to a PMD boundary. */ 100 + end = (start + vdso_mapping_len + PMD_SIZE - 1) & PMD_MASK; 101 + if (end >= TASK_SIZE) 102 + end = TASK_SIZE; 103 + end -= vdso_mapping_len; 104 + 105 + if (end > start) { 106 + offset = get_random_int() % (((end - start) >> PAGE_SHIFT) + 1); 107 + addr = start + (offset << PAGE_SHIFT); 108 + } else { 109 + addr = start; 110 + } 111 + return addr; 112 + } 113 + 114 + int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) 115 + { 116 + struct mm_struct *mm = current->mm; 117 + unsigned long vdso_base, vdso_text_len, vdso_mapping_len; 118 + struct vm_area_struct *vma; 119 + unsigned long addr = 0; 120 + pgprot_t prot; 121 + int ret, vvar_page_num = 2; 122 + 123 + vdso_text_len = vdso_pages << PAGE_SHIFT; 124 + 125 + if(timer_mapping_base == EMPTY_VALUE) 126 + vvar_page_num = 1; 127 + /* Be sure to map the data page */ 128 + vdso_mapping_len = vdso_text_len + vvar_page_num * PAGE_SIZE; 129 + #ifdef CONFIG_CPU_CACHE_ALIASING 130 + vdso_mapping_len += L1_cache_info[DCACHE].aliasing_num - 1; 131 + #endif 132 + 133 + if (down_write_killable(&mm->mmap_sem)) 134 + return -EINTR; 135 + 136 + addr = vdso_random_addr(vdso_mapping_len); 137 + vdso_base = get_unmapped_area(NULL, addr, vdso_mapping_len, 0, 0); 138 + if (IS_ERR_VALUE(vdso_base)) { 139 + ret = vdso_base; 140 + goto up_fail; 141 + } 142 + 143 + #ifdef CONFIG_CPU_CACHE_ALIASING 144 + { 145 + unsigned int aliasing_mask = 146 + L1_cache_info[DCACHE].aliasing_mask; 147 + unsigned int page_colour_ofs; 148 + page_colour_ofs = ((unsigned int)vdso_data & aliasing_mask) - 149 + (vdso_base & aliasing_mask); 150 + vdso_base += page_colour_ofs & aliasing_mask; 151 + } 152 + #endif 153 + 154 + vma = _install_special_mapping(mm, vdso_base, vvar_page_num * PAGE_SIZE, 155 + VM_READ | VM_MAYREAD, &vdso_spec[0]); 156 + if (IS_ERR(vma)) { 157 + ret = PTR_ERR(vma); 158 + goto up_fail; 159 + } 160 + 161 + /*Map vdata to user space */ 162 + ret = io_remap_pfn_range(vma, vdso_base, 163 + virt_to_phys(vdso_data) >> PAGE_SHIFT, 164 + PAGE_SIZE, vma->vm_page_prot); 165 + if (ret) 166 + goto up_fail; 167 + 168 + /*Map timer to user space */ 169 + vdso_base += PAGE_SIZE; 170 + prot = __pgprot(_PAGE_V | _PAGE_M_UR_KR | _PAGE_D | _PAGE_C_DEV); 171 + ret = io_remap_pfn_range(vma, vdso_base, timer_mapping_base >> PAGE_SHIFT, 172 + PAGE_SIZE, prot); 173 + if (ret) 174 + goto up_fail; 175 + 176 + /*Map vdso to user space */ 177 + vdso_base += PAGE_SIZE; 178 + mm->context.vdso = (void *)vdso_base; 179 + vma = _install_special_mapping(mm, vdso_base, vdso_text_len, 180 + VM_READ | VM_EXEC | 181 + VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC, 182 + &vdso_spec[1]); 183 + if (IS_ERR(vma)) { 184 + ret = PTR_ERR(vma); 185 + goto up_fail; 186 + } 187 + 188 + up_write(&mm->mmap_sem); 189 + return 0; 190 + 191 + up_fail: 192 + mm->context.vdso = NULL; 193 + up_write(&mm->mmap_sem); 194 + return ret; 195 + } 196 + 197 + static void vdso_write_begin(struct vdso_data *vdata) 198 + { 199 + ++vdso_data->seq_count; 200 + smp_wmb(); /* Pairs with smp_rmb in vdso_read_retry */ 201 + } 202 + 203 + static void vdso_write_end(struct vdso_data *vdata) 204 + { 205 + smp_wmb(); /* Pairs with smp_rmb in vdso_read_begin */ 206 + ++vdso_data->seq_count; 207 + } 208 + 209 + void update_vsyscall(struct timekeeper *tk) 210 + { 211 + vdso_write_begin(vdso_data); 212 + vdso_data->cs_mask = tk->tkr_mono.mask; 213 + vdso_data->cs_mult = tk->tkr_mono.mult; 214 + vdso_data->cs_shift = tk->tkr_mono.shift; 215 + vdso_data->cs_cycle_last = tk->tkr_mono.cycle_last; 216 + vdso_data->wtm_clock_sec = tk->wall_to_monotonic.tv_sec; 217 + vdso_data->wtm_clock_nsec = tk->wall_to_monotonic.tv_nsec; 218 + vdso_data->xtime_clock_sec = tk->xtime_sec; 219 + vdso_data->xtime_clock_nsec = tk->tkr_mono.xtime_nsec; 220 + vdso_data->xtime_coarse_sec = tk->xtime_sec; 221 + vdso_data->xtime_coarse_nsec = tk->tkr_mono.xtime_nsec >> 222 + tk->tkr_mono.shift; 223 + vdso_write_end(vdso_data); 224 + } 225 + 226 + void update_vsyscall_tz(void) 227 + { 228 + vdso_data->tz_minuteswest = sys_tz.tz_minuteswest; 229 + vdso_data->tz_dsttime = sys_tz.tz_dsttime; 230 + }
+82
arch/nds32/kernel/vdso/Makefile
··· 1 + # 2 + # Building a vDSO image for AArch64. 3 + # 4 + # Author: Will Deacon <will.deacon@arm.com> 5 + # Heavily based on the vDSO Makefiles for other archs. 6 + # 7 + 8 + obj-vdso := note.o datapage.o sigreturn.o gettimeofday.o 9 + 10 + # Build rules 11 + targets := $(obj-vdso) vdso.so vdso.so.dbg 12 + obj-vdso := $(addprefix $(obj)/, $(obj-vdso)) 13 + 14 + ccflags-y := -shared -fno-common -fno-builtin 15 + ccflags-y += -nostdlib -Wl,-soname=linux-vdso.so.1 \ 16 + $(call cc-ldoption, -Wl$(comma)--hash-style=sysv) 17 + ccflags-y += -fPIC -Wl,-shared -g 18 + 19 + # Disable gcov profiling for VDSO code 20 + GCOV_PROFILE := n 21 + 22 + 23 + obj-y += vdso.o 24 + extra-y += vdso.lds 25 + CPPFLAGS_vdso.lds += -P -C -U$(ARCH) 26 + 27 + # Force dependency 28 + $(obj)/vdso.o : $(obj)/vdso.so 29 + 30 + # Link rule for the .so file, .lds has to be first 31 + $(obj)/vdso.so.dbg: $(src)/vdso.lds $(obj-vdso) 32 + $(call if_changed,vdsold) 33 + 34 + 35 + # Strip rule for the .so file 36 + $(obj)/%.so: OBJCOPYFLAGS := -S 37 + $(obj)/%.so: $(obj)/%.so.dbg FORCE 38 + $(call if_changed,objcopy) 39 + 40 + # Generate VDSO offsets using helper script 41 + gen-vdsosym := $(srctree)/$(src)/gen_vdso_offsets.sh 42 + quiet_cmd_vdsosym = VDSOSYM $@ 43 + define cmd_vdsosym 44 + $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@ 45 + endef 46 + 47 + include/generated/vdso-offsets.h: $(obj)/vdso.so.dbg FORCE 48 + $(call if_changed,vdsosym) 49 + 50 + 51 + 52 + # Assembly rules for the .S files 53 + 54 + sigreturn.o : sigreturn.S 55 + $(call if_changed_dep,vdsoas) 56 + 57 + note.o : note.S 58 + $(call if_changed_dep,vdsoas) 59 + 60 + datapage.o : datapage.S 61 + $(call if_changed_dep,vdsoas) 62 + 63 + gettimeofday.o : gettimeofday.c FORCE 64 + $(call if_changed_dep,vdsocc) 65 + 66 + # Actual build commands 67 + quiet_cmd_vdsold = VDSOL $@ 68 + cmd_vdsold = $(CC) $(c_flags) -Wl,-n -Wl,-T $^ -o $@ 69 + quiet_cmd_vdsoas = VDSOA $@ 70 + cmd_vdsoas = $(CC) $(a_flags) -c -o $@ $< 71 + quiet_cmd_vdsocc = VDSOA $@ 72 + cmd_vdsocc = $(CC) $(c_flags) -c -o $@ $< 73 + 74 + # Install commands for the unstripped file 75 + quiet_cmd_vdso_install = INSTALL $@ 76 + cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@ 77 + 78 + vdso.so: $(obj)/vdso.so.dbg 79 + @mkdir -p $(MODLIB)/vdso 80 + $(call cmd,vdso_install) 81 + 82 + vdso_install: vdso.so
+21
arch/nds32/kernel/vdso/datapage.S
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (C) 2005-2017 Andes Technology Corporation 3 + 4 + #include <linux/linkage.h> 5 + #include <asm/page.h> 6 + 7 + ENTRY(__get_timerpage) 8 + sethi $r0, hi20(. + PAGE_SIZE + 8) 9 + ori $r0, $r0, lo12(. + PAGE_SIZE + 4) 10 + mfusr $r1, $pc 11 + sub $r0, $r1, $r0 12 + ret 13 + ENDPROC(__get_timerpage) 14 + 15 + ENTRY(__get_datapage) 16 + sethi $r0, hi20(. + 2*PAGE_SIZE + 8) 17 + ori $r0, $r0, lo12(. + 2*PAGE_SIZE + 4) 18 + mfusr $r1, $pc 19 + sub $r0, $r1, $r0 20 + ret 21 + ENDPROC(__get_datapage)
+15
arch/nds32/kernel/vdso/gen_vdso_offsets.sh
··· 1 + #!/bin/sh 2 + 3 + # 4 + # Match symbols in the DSO that look like VDSO_*; produce a header file 5 + # of constant offsets into the shared object. 6 + # 7 + # Doing this inside the Makefile will break the $(filter-out) function, 8 + # causing Kbuild to rebuild the vdso-offsets header file every time. 9 + # 10 + # Author: Will Deacon <will.deacon@arm.com 11 + # 12 + 13 + LC_ALL=C 14 + sed -n -e 's/^00*/0/' -e \ 15 + 's/^\([0-9a-fA-F]*\) . VDSO_\([a-zA-Z0-9_]*\)$/\#define vdso_offset_\2\t0x\1/p'
+270
arch/nds32/kernel/vdso/gettimeofday.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (C) 2005-2017 Andes Technology Corporation 3 + 4 + #include <linux/compiler.h> 5 + #include <linux/hrtimer.h> 6 + #include <linux/time.h> 7 + #include <asm/io.h> 8 + #include <asm/barrier.h> 9 + #include <asm/bug.h> 10 + #include <asm/page.h> 11 + #include <asm/unistd.h> 12 + #include <asm/vdso_datapage.h> 13 + #include <asm/vdso_timer_info.h> 14 + #include <asm/asm-offsets.h> 15 + 16 + #define X(x) #x 17 + #define Y(x) X(x) 18 + 19 + extern struct vdso_data *__get_datapage(void); 20 + extern struct vdso_data *__get_timerpage(void); 21 + 22 + static notrace unsigned int __vdso_read_begin(const struct vdso_data *vdata) 23 + { 24 + u32 seq; 25 + repeat: 26 + seq = READ_ONCE(vdata->seq_count); 27 + if (seq & 1) { 28 + cpu_relax(); 29 + goto repeat; 30 + } 31 + return seq; 32 + } 33 + 34 + static notrace unsigned int vdso_read_begin(const struct vdso_data *vdata) 35 + { 36 + unsigned int seq; 37 + 38 + seq = __vdso_read_begin(vdata); 39 + 40 + smp_rmb(); /* Pairs with smp_wmb in vdso_write_end */ 41 + return seq; 42 + } 43 + 44 + static notrace int vdso_read_retry(const struct vdso_data *vdata, u32 start) 45 + { 46 + smp_rmb(); /* Pairs with smp_wmb in vdso_write_begin */ 47 + return vdata->seq_count != start; 48 + } 49 + 50 + static notrace long clock_gettime_fallback(clockid_t _clkid, 51 + struct timespec *_ts) 52 + { 53 + register struct timespec *ts asm("$r1") = _ts; 54 + register clockid_t clkid asm("$r0") = _clkid; 55 + register long ret asm("$r0"); 56 + 57 + asm volatile ("movi $r15, %3\n" 58 + "syscall 0x0\n" 59 + :"=r" (ret) 60 + :"r"(clkid), "r"(ts), "i"(__NR_clock_gettime) 61 + :"$r15", "memory"); 62 + 63 + return ret; 64 + } 65 + 66 + static notrace int do_realtime_coarse(struct timespec *ts, 67 + struct vdso_data *vdata) 68 + { 69 + u32 seq; 70 + 71 + do { 72 + seq = vdso_read_begin(vdata); 73 + 74 + ts->tv_sec = vdata->xtime_coarse_sec; 75 + ts->tv_nsec = vdata->xtime_coarse_nsec; 76 + 77 + } while (vdso_read_retry(vdata, seq)); 78 + return 0; 79 + } 80 + 81 + static notrace int do_monotonic_coarse(struct timespec *ts, 82 + struct vdso_data *vdata) 83 + { 84 + struct timespec tomono; 85 + u32 seq; 86 + 87 + do { 88 + seq = vdso_read_begin(vdata); 89 + 90 + ts->tv_sec = vdata->xtime_coarse_sec; 91 + ts->tv_nsec = vdata->xtime_coarse_nsec; 92 + 93 + tomono.tv_sec = vdata->wtm_clock_sec; 94 + tomono.tv_nsec = vdata->wtm_clock_nsec; 95 + 96 + } while (vdso_read_retry(vdata, seq)); 97 + 98 + ts->tv_sec += tomono.tv_sec; 99 + timespec_add_ns(ts, tomono.tv_nsec); 100 + return 0; 101 + } 102 + 103 + static notrace inline u64 vgetsns(struct vdso_data *vdso) 104 + { 105 + u32 cycle_now; 106 + u32 cycle_delta; 107 + u32 *timer_cycle_base; 108 + 109 + timer_cycle_base = 110 + (u32 *) ((char *)__get_timerpage() + vdso->cycle_count_offset); 111 + cycle_now = readl_relaxed(timer_cycle_base); 112 + if (true == vdso->cycle_count_down) 113 + cycle_now = ~(*timer_cycle_base); 114 + cycle_delta = cycle_now - (u32) vdso->cs_cycle_last; 115 + return ((u64) cycle_delta & vdso->cs_mask) * vdso->cs_mult; 116 + } 117 + 118 + static notrace int do_realtime(struct timespec *ts, struct vdso_data *vdata) 119 + { 120 + unsigned count; 121 + u64 ns; 122 + do { 123 + count = vdso_read_begin(vdata); 124 + ts->tv_sec = vdata->xtime_clock_sec; 125 + ns = vdata->xtime_clock_nsec; 126 + ns += vgetsns(vdata); 127 + ns >>= vdata->cs_shift; 128 + } while (vdso_read_retry(vdata, count)); 129 + 130 + ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns); 131 + ts->tv_nsec = ns; 132 + 133 + return 0; 134 + } 135 + 136 + static notrace int do_monotonic(struct timespec *ts, struct vdso_data *vdata) 137 + { 138 + struct timespec tomono; 139 + u64 nsecs; 140 + u32 seq; 141 + 142 + do { 143 + seq = vdso_read_begin(vdata); 144 + 145 + ts->tv_sec = vdata->xtime_clock_sec; 146 + nsecs = vdata->xtime_clock_nsec; 147 + nsecs += vgetsns(vdata); 148 + nsecs >>= vdata->cs_shift; 149 + 150 + tomono.tv_sec = vdata->wtm_clock_sec; 151 + tomono.tv_nsec = vdata->wtm_clock_nsec; 152 + 153 + } while (vdso_read_retry(vdata, seq)); 154 + 155 + ts->tv_sec += tomono.tv_sec; 156 + ts->tv_nsec = 0; 157 + timespec_add_ns(ts, nsecs + tomono.tv_nsec); 158 + return 0; 159 + } 160 + 161 + notrace int __vdso_clock_gettime(clockid_t clkid, struct timespec *ts) 162 + { 163 + struct vdso_data *vdata; 164 + int ret = -1; 165 + 166 + vdata = __get_datapage(); 167 + if (vdata->cycle_count_offset == EMPTY_REG_OFFSET) 168 + return clock_gettime_fallback(clkid, ts); 169 + 170 + switch (clkid) { 171 + case CLOCK_REALTIME_COARSE: 172 + ret = do_realtime_coarse(ts, vdata); 173 + break; 174 + case CLOCK_MONOTONIC_COARSE: 175 + ret = do_monotonic_coarse(ts, vdata); 176 + break; 177 + case CLOCK_REALTIME: 178 + ret = do_realtime(ts, vdata); 179 + break; 180 + case CLOCK_MONOTONIC: 181 + ret = do_monotonic(ts, vdata); 182 + break; 183 + default: 184 + break; 185 + } 186 + 187 + if (ret) 188 + ret = clock_gettime_fallback(clkid, ts); 189 + 190 + return ret; 191 + } 192 + 193 + static notrace int clock_getres_fallback(clockid_t _clk_id, 194 + struct timespec *_res) 195 + { 196 + register clockid_t clk_id asm("$r0") = _clk_id; 197 + register struct timespec *res asm("$r1") = _res; 198 + register int ret asm("$r0"); 199 + 200 + asm volatile ("movi $r15, %3\n" 201 + "syscall 0x0\n" 202 + :"=r" (ret) 203 + :"r"(clk_id), "r"(res), "i"(__NR_clock_getres) 204 + :"$r15", "memory"); 205 + 206 + return ret; 207 + } 208 + 209 + notrace int __vdso_clock_getres(clockid_t clk_id, struct timespec *res) 210 + { 211 + if (res == NULL) 212 + return 0; 213 + switch (clk_id) { 214 + case CLOCK_REALTIME: 215 + case CLOCK_MONOTONIC: 216 + case CLOCK_MONOTONIC_RAW: 217 + res->tv_sec = 0; 218 + res->tv_nsec = CLOCK_REALTIME_RES; 219 + break; 220 + case CLOCK_REALTIME_COARSE: 221 + case CLOCK_MONOTONIC_COARSE: 222 + res->tv_sec = 0; 223 + res->tv_nsec = CLOCK_COARSE_RES; 224 + break; 225 + default: 226 + return clock_getres_fallback(clk_id, res); 227 + } 228 + return 0; 229 + } 230 + 231 + static notrace inline int gettimeofday_fallback(struct timeval *_tv, 232 + struct timezone *_tz) 233 + { 234 + register struct timeval *tv asm("$r0") = _tv; 235 + register struct timezone *tz asm("$r1") = _tz; 236 + register int ret asm("$r0"); 237 + 238 + asm volatile ("movi $r15, %3\n" 239 + "syscall 0x0\n" 240 + :"=r" (ret) 241 + :"r"(tv), "r"(tz), "i"(__NR_gettimeofday) 242 + :"$r15", "memory"); 243 + 244 + return ret; 245 + } 246 + 247 + notrace int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz) 248 + { 249 + struct timespec ts; 250 + struct vdso_data *vdata; 251 + int ret; 252 + 253 + vdata = __get_datapage(); 254 + 255 + if (vdata->cycle_count_offset == EMPTY_REG_OFFSET) 256 + return gettimeofday_fallback(tv, tz); 257 + 258 + ret = do_realtime(&ts, vdata); 259 + 260 + if (tv) { 261 + tv->tv_sec = ts.tv_sec; 262 + tv->tv_usec = ts.tv_nsec / 1000; 263 + } 264 + if (tz) { 265 + tz->tz_minuteswest = vdata->tz_minuteswest; 266 + tz->tz_dsttime = vdata->tz_dsttime; 267 + } 268 + 269 + return ret; 270 + }
+11
arch/nds32/kernel/vdso/note.S
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (C) 2012 ARM Limited 3 + // Copyright (C) 2005-2017 Andes Technology Corporation 4 + 5 + #include <linux/uts.h> 6 + #include <linux/version.h> 7 + #include <linux/elfnote.h> 8 + 9 + ELFNOTE_START(Linux, 0, "a") 10 + .long LINUX_VERSION_CODE 11 + ELFNOTE_END
+19
arch/nds32/kernel/vdso/sigreturn.S
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (C) 2012 ARM Limited 3 + // Copyright (C) 2005-2017 Andes Technology Corporation 4 + 5 + #include <linux/linkage.h> 6 + #include <asm/unistd.h> 7 + 8 + .text 9 + 10 + ENTRY(__kernel_rt_sigreturn) 11 + .cfi_startproc 12 + movi $r15, __NR_rt_sigreturn 13 + /* 14 + * The SWID of syscall should be __NR_rt_sigreturn to synchronize 15 + * the unwinding scheme in gcc 16 + */ 17 + syscall __NR_rt_sigreturn 18 + .cfi_endproc 19 + ENDPROC(__kernel_rt_sigreturn)
+18
arch/nds32/kernel/vdso/vdso.S
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (C) 2012 ARM Limited 3 + // Copyright (C) 2005-2017 Andes Technology Corporation 4 + 5 + #include <linux/init.h> 6 + #include <linux/linkage.h> 7 + #include <linux/const.h> 8 + #include <asm/page.h> 9 + 10 + .globl vdso_start, vdso_end 11 + .section .rodata 12 + .balign PAGE_SIZE 13 + vdso_start: 14 + .incbin "arch/nds32/kernel/vdso/vdso.so" 15 + .balign PAGE_SIZE 16 + vdso_end: 17 + 18 + .previous
+76
arch/nds32/kernel/vdso/vdso.lds.S
··· 1 + /* 2 + * SPDX-License-Identifier: GPL-2.0 3 + * Copyright (C) 2005-2017 Andes Technology Corporation 4 + */ 5 + 6 + 7 + #include <linux/const.h> 8 + #include <asm/page.h> 9 + #include <asm/vdso.h> 10 + 11 + OUTPUT_FORMAT("elf32-nds32le-linux", "elf32-nds32be-linux", "elf32-nds32le-linux") 12 + OUTPUT_ARCH(nds32) 13 + 14 + SECTIONS 15 + { 16 + . = SIZEOF_HEADERS; 17 + 18 + .hash : { *(.hash) } :text 19 + .gnu.hash : { *(.gnu.hash) } 20 + .dynsym : { *(.dynsym) } 21 + .dynstr : { *(.dynstr) } 22 + .gnu.version : { *(.gnu.version) } 23 + .gnu.version_d : { *(.gnu.version_d) } 24 + .gnu.version_r : { *(.gnu.version_r) } 25 + 26 + .note : { *(.note.*) } :text :note 27 + 28 + 29 + .text : { *(.text*) } :text 30 + 31 + .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr 32 + .eh_frame : { KEEP (*(.eh_frame)) } :text 33 + 34 + .dynamic : { *(.dynamic) } :text :dynamic 35 + 36 + .rodata : { *(.rodata*) } :text 37 + 38 + 39 + /DISCARD/ : { 40 + *(.note.GNU-stack) 41 + *(.data .data.* .gnu.linkonce.d.* .sdata*) 42 + *(.bss .sbss .dynbss .dynsbss) 43 + } 44 + } 45 + 46 + /* 47 + * We must supply the ELF program headers explicitly to get just one 48 + * PT_LOAD segment, and set the flags explicitly to make segments read-only. 49 + */ 50 + PHDRS 51 + { 52 + text PT_LOAD FLAGS(5) FILEHDR PHDRS; /* PF_R|PF_X */ 53 + dynamic PT_DYNAMIC FLAGS(4); /* PF_R */ 54 + note PT_NOTE FLAGS(4); /* PF_R */ 55 + eh_frame_hdr PT_GNU_EH_FRAME; 56 + } 57 + 58 + /* 59 + * This controls what symbols we export from the DSO. 60 + */ 61 + VERSION 62 + { 63 + LINUX_4 { 64 + global: 65 + __kernel_rt_sigreturn; 66 + __vdso_gettimeofday; 67 + __vdso_clock_getres; 68 + __vdso_clock_gettime; 69 + local: *; 70 + }; 71 + } 72 + 73 + /* 74 + * Make the rt_sigreturn code visible to the kernel. 75 + */ 76 + VDSO_rt_sigtramp = __kernel_rt_sigreturn;