Commit 87f3248c authored by Guo Ren's avatar Guo Ren

csky: Reconstruct VDSO framework

Reconstruct vdso framework to support future vsyscall,
vgettimeofday features. These are very important features to reduce
system calls into the kernel for performance improvement.

The patch is reference RISC-V's
Signed-off-by: default avatarGuo Ren <guoren@linux.alibaba.com>
Cc: Palmer Dabbelt <palmerdabbelt@google.com>
parent e26db7ad
/* SPDX-License-Identifier: GPL-2.0 */
#include <linux/uaccess.h>
#ifndef __ABI_CSKY_VDSO_H
#define __ABI_CSKY_VDSO_H
static inline int setup_vdso_page(unsigned short *ptr)
{
int err = 0;
/* movi r1, 127; addi r1, (139 - 127) */
#define SET_SYSCALL_ID .long 0x20b167f1
/* movi r1, 127 */
err |= __put_user(0x67f1, ptr + 0);
/* addi r1, (139 - 127) */
err |= __put_user(0x20b1, ptr + 1);
/* trap 0 */
err |= __put_user(0x0008, ptr + 2);
return err;
}
#endif /* __ABI_CSKY_VDSO_H */
......@@ -3,21 +3,7 @@
#ifndef __ABI_CSKY_VDSO_H
#define __ABI_CSKY_VDSO_H
#include <linux/uaccess.h>
/* movi r7, 173 */
#define SET_SYSCALL_ID .long 0x008bea07
static inline int setup_vdso_page(unsigned short *ptr)
{
int err = 0;
/* movi r7, 173 */
err |= __put_user(0xea07, ptr);
err |= __put_user(0x008b, ptr+1);
/* trap 0 */
err |= __put_user(0xc000, ptr+2);
err |= __put_user(0x2020, ptr+3);
return err;
}
#endif /* __ABI_CSKY_STRING_H */
#endif /* __ABI_CSKY_VDSO_H */
......@@ -3,10 +3,23 @@
#ifndef __ASM_CSKY_VDSO_H
#define __ASM_CSKY_VDSO_H
#include <abi/vdso.h>
#include <linux/types.h>
struct csky_vdso {
unsigned short rt_signal_retcode[4];
struct vdso_data {
};
/*
* The VDSO symbols are mapped into Linux so we can just use regular symbol
* addressing to get their offsets in userspace. The symbols are mapped at an
* offset of 0, but since the linker must support setting weak undefined
* symbols to the absolute address 0 it also happens to support other low
* addresses even when the code model suggests those low addresses would not
* otherwise be availiable.
*/
#define VDSO_SYMBOL(base, name) \
({ \
extern const char __vdso_##name[]; \
(void __user *)((unsigned long)(base) + __vdso_##name); \
})
#endif /* __ASM_CSKY_VDSO_H */
# SPDX-License-Identifier: GPL-2.0-only
extra-y := head.o vmlinux.lds
obj-y += entry.o atomic.o signal.o traps.o irq.o time.o vdso.o
obj-y += entry.o atomic.o signal.o traps.o irq.o time.o vdso.o vdso/
obj-y += power.o syscall.o syscall_table.o setup.o
obj-y += process.o cpu-probe.o ptrace.o stacktrace.o
obj-y += probes/
......
......@@ -134,7 +134,6 @@ setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)
{
struct rt_sigframe *frame;
int err = 0;
struct csky_vdso *vdso = current->mm->context.vdso;
frame = get_sigframe(ksig, regs, sizeof(*frame));
if (!access_ok(frame, sizeof(*frame)))
......@@ -152,7 +151,8 @@ setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)
return -EFAULT;
/* Set up to return from userspace. */
regs->lr = (unsigned long)(vdso->rt_signal_retcode);
regs->lr = (unsigned long)VDSO_SYMBOL(
current->mm->context.vdso, rt_sigreturn);
/*
* Set up registers for signal handler.
......
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/binfmts.h>
#include <linux/elf.h>
#include <linux/vmalloc.h>
#include <linux/unistd.h>
#include <linux/uaccess.h>
#include <linux/err.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <asm/page.h>
#include <asm/vdso.h>
#include <asm/cacheflush.h>
static struct page *vdso_page;
extern char vdso_start[], vdso_end[];
static int __init init_vdso(void)
{
struct csky_vdso *vdso;
int err = 0;
vdso_page = alloc_page(GFP_KERNEL);
if (!vdso_page)
panic("Cannot allocate vdso");
static unsigned int vdso_pages;
static struct page **vdso_pagelist;
vdso = vmap(&vdso_page, 1, 0, PAGE_KERNEL);
if (!vdso)
panic("Cannot map vdso");
/*
* The vDSO data page.
*/
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;
clear_page(vdso);
err = setup_vdso_page(vdso->rt_signal_retcode);
if (err)
panic("Cannot set signal return code, err: %x.", err);
static int __init vdso_init(void)
{
unsigned int i;
vdso_pages = (vdso_end - vdso_start) >> PAGE_SHIFT;
vdso_pagelist =
kcalloc(vdso_pages + 1, sizeof(struct page *), GFP_KERNEL);
if (unlikely(vdso_pagelist == NULL)) {
pr_err("vdso: pagelist allocation failed\n");
return -ENOMEM;
}
dcache_wb_range((unsigned long)vdso, (unsigned long)vdso + 16);
for (i = 0; i < vdso_pages; i++) {
struct page *pg;
vunmap(vdso);
pg = virt_to_page(vdso_start + (i << PAGE_SHIFT));
vdso_pagelist[i] = pg;
}
vdso_pagelist[i] = virt_to_page(vdso_data);
return 0;
}
subsys_initcall(init_vdso);
arch_initcall(vdso_init);
int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
int arch_setup_additional_pages(struct linux_binprm *bprm,
int uses_interp)
{
int ret;
unsigned long addr;
struct mm_struct *mm = current->mm;
unsigned long vdso_base, vdso_len;
int ret;
mmap_write_lock(mm);
vdso_len = (vdso_pages + 1) << PAGE_SHIFT;
addr = get_unmapped_area(NULL, STACK_TOP, PAGE_SIZE, 0, 0);
if (IS_ERR_VALUE(addr)) {
ret = addr;
goto up_fail;
mmap_write_lock(mm);
vdso_base = get_unmapped_area(NULL, 0, vdso_len, 0, 0);
if (IS_ERR_VALUE(vdso_base)) {
ret = vdso_base;
goto end;
}
ret = install_special_mapping(
mm,
addr,
PAGE_SIZE,
VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
&vdso_page);
if (ret)
goto up_fail;
/*
* Put vDSO base into mm struct. We need to do this before calling
* install_special_mapping or the perf counter mmap tracking code
* will fail to recognise it as a vDSO (since arch_vma_name fails).
*/
mm->context.vdso = (void *)vdso_base;
ret =
install_special_mapping(mm, vdso_base, vdso_pages << PAGE_SHIFT,
(VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC),
vdso_pagelist);
if (unlikely(ret)) {
mm->context.vdso = NULL;
goto end;
}
mm->context.vdso = (void *)addr;
vdso_base += (vdso_pages << PAGE_SHIFT);
ret = install_special_mapping(mm, vdso_base, PAGE_SIZE,
(VM_READ | VM_MAYREAD), &vdso_pagelist[vdso_pages]);
up_fail:
if (unlikely(ret))
mm->context.vdso = NULL;
end:
mmap_write_unlock(mm);
return ret;
}
const char *arch_vma_name(struct vm_area_struct *vma)
{
if (vma->vm_mm == NULL)
return NULL;
if (vma->vm_start == (long)vma->vm_mm->context.vdso)
if (vma->vm_mm && (vma->vm_start == (long)vma->vm_mm->context.vdso))
return "[vdso]";
else
return NULL;
if (vma->vm_mm && (vma->vm_start ==
(long)vma->vm_mm->context.vdso + PAGE_SIZE))
return "[vdso_data]";
return NULL;
}
# SPDX-License-Identifier: GPL-2.0-only
vdso.lds
*.tmp
vdso-syms.S
# SPDX-License-Identifier: GPL-2.0-only
# Absolute relocation type $(ARCH_REL_TYPE_ABS) needs to be defined before
# the inclusion of generic Makefile.
ARCH_REL_TYPE_ABS := R_CKCORE_ADDR32|R_CKCORE_JUMP_SLOT
include $(srctree)/lib/vdso/Makefile
# Symbols present in the vdso
vdso-syms = rt_sigreturn
# Files to link into the vdso
obj-vdso = $(patsubst %, %.o, $(vdso-syms)) note.o
ccflags-y := -fno-stack-protector
# Build rules
targets := $(obj-vdso) vdso.so vdso.so.dbg vdso.lds vdso-dummy.o
obj-vdso := $(addprefix $(obj)/, $(obj-vdso))
obj-y += vdso.o vdso-syms.o
CPPFLAGS_vdso.lds += -P -C -U$(ARCH)
# Disable gcov profiling for VDSO code
GCOV_PROFILE := n
KCOV_INSTRUMENT := n
# Force dependency
$(obj)/vdso.o: $(obj)/vdso.so
SYSCFLAGS_vdso.so.dbg = $(c_flags)
$(obj)/vdso.so.dbg: $(src)/vdso.lds $(obj-vdso) FORCE
$(call if_changed,vdsold)
SYSCFLAGS_vdso.so.dbg = -shared -s -Wl,-soname=linux-vdso.so.1 \
-Wl,--build-id=sha1 -Wl,--hash-style=both
$(obj)/vdso-syms.S: $(obj)/vdso.so FORCE
$(call if_changed,so2s)
# strip rule for the .so file
$(obj)/%.so: OBJCOPYFLAGS := -S
$(obj)/%.so: $(obj)/%.so.dbg FORCE
$(call if_changed,objcopy)
# actual build commands
# The DSO images are built using a special linker script
# Make sure only to export the intended __vdso_xxx symbol offsets.
quiet_cmd_vdsold = VDSOLD $@
cmd_vdsold = $(CC) $(KBUILD_CFLAGS) $(call cc-option, -no-pie) -nostdlib -nostartfiles $(SYSCFLAGS_$(@F)) \
-Wl,-T,$(filter-out FORCE,$^) -o $@.tmp && \
$(CROSS_COMPILE)objcopy \
$(patsubst %, -G __vdso_%, $(vdso-syms)) $@.tmp $@ && \
rm $@.tmp
# Extracts symbol offsets from the VDSO, converting them into an assembly file
# that contains the same symbols at the same offsets.
quiet_cmd_so2s = SO2S $@
cmd_so2s = $(NM) -D $< | $(srctree)/$(src)/so2s.sh > $@
# 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
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* 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/elfnote.h>
#include <linux/version.h>
ELFNOTE_START(Linux, 0, "a")
.long LINUX_VERSION_CODE
ELFNOTE_END
/* SPDX-License-Identifier: GPL-2.0-only */
#include <linux/linkage.h>
#include <asm/unistd.h>
#include <abi/vdso.h>
.text
ENTRY(__vdso_rt_sigreturn)
.cfi_startproc
.cfi_signal_frame
SET_SYSCALL_ID
trap 0
.cfi_endproc
ENDPROC(__vdso_rt_sigreturn)
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0+
sed 's!\([0-9a-f]*\) T \([a-z0-9_]*\)\(@@LINUX_5.10\)*!.global \2\n.set \2,0x\1!' \
| grep '^\.'
/* SPDX-License-Identifier: GPL-2.0-only */
#include <linux/init.h>
#include <linux/linkage.h>
#include <asm/page.h>
__PAGE_ALIGNED_DATA
.globl vdso_start, vdso_end
.balign PAGE_SIZE
vdso_start:
.incbin "arch/csky/kernel/vdso/vdso.so"
.balign PAGE_SIZE
vdso_end:
.previous
/* SPDX-License-Identifier: GPL-2.0-only */
#include <asm/page.h>
OUTPUT_ARCH(csky)
SECTIONS
{
PROVIDE(_vdso_data = . + PAGE_SIZE);
. = 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
.dynamic : { *(.dynamic) } :text :dynamic
.eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
.eh_frame : { KEEP (*(.eh_frame)) } :text
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
. = 0x800;
.text : { *(.text .text.*) } :text
.data : {
*(.got.plt) *(.got)
*(.data .data.* .gnu.linkonce.d.*)
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
}
}
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;
}
VERSION
{
LINUX_5.10 {
global:
__vdso_rt_sigreturn;
local: *;
};
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment