提交 87f3248c 编写于 作者: G 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: NGuo Ren <guoren@linux.alibaba.com>
Cc: Palmer Dabbelt <palmerdabbelt@google.com>
上级 e26db7ad
/* SPDX-License-Identifier: GPL-2.0 */ /* 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) /* movi r1, 127; addi r1, (139 - 127) */
{ #define SET_SYSCALL_ID .long 0x20b167f1
int err = 0;
/* movi r1, 127 */ #endif /* __ABI_CSKY_VDSO_H */
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;
}
...@@ -3,21 +3,7 @@ ...@@ -3,21 +3,7 @@
#ifndef __ABI_CSKY_VDSO_H #ifndef __ABI_CSKY_VDSO_H
#define __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) #endif /* __ABI_CSKY_VDSO_H */
{
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 */
...@@ -3,10 +3,23 @@ ...@@ -3,10 +3,23 @@
#ifndef __ASM_CSKY_VDSO_H #ifndef __ASM_CSKY_VDSO_H
#define __ASM_CSKY_VDSO_H #define __ASM_CSKY_VDSO_H
#include <abi/vdso.h> #include <linux/types.h>
struct csky_vdso { struct vdso_data {
unsigned short rt_signal_retcode[4];
}; };
/*
* 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 */ #endif /* __ASM_CSKY_VDSO_H */
# SPDX-License-Identifier: GPL-2.0-only # SPDX-License-Identifier: GPL-2.0-only
extra-y := head.o vmlinux.lds 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 += power.o syscall.o syscall_table.o setup.o
obj-y += process.o cpu-probe.o ptrace.o stacktrace.o obj-y += process.o cpu-probe.o ptrace.o stacktrace.o
obj-y += probes/ obj-y += probes/
......
...@@ -134,7 +134,6 @@ setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs) ...@@ -134,7 +134,6 @@ setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)
{ {
struct rt_sigframe *frame; struct rt_sigframe *frame;
int err = 0; int err = 0;
struct csky_vdso *vdso = current->mm->context.vdso;
frame = get_sigframe(ksig, regs, sizeof(*frame)); frame = get_sigframe(ksig, regs, sizeof(*frame));
if (!access_ok(frame, 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) ...@@ -152,7 +151,8 @@ setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)
return -EFAULT; return -EFAULT;
/* Set up to return from userspace. */ /* 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. * Set up registers for signal handler.
......
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. // 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/binfmts.h>
#include <linux/elf.h> #include <linux/elf.h>
#include <linux/vmalloc.h> #include <linux/err.h>
#include <linux/unistd.h> #include <linux/mm.h>
#include <linux/uaccess.h> #include <linux/slab.h>
#include <asm/page.h>
#include <asm/vdso.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) static unsigned int vdso_pages;
{ static struct page **vdso_pagelist;
struct csky_vdso *vdso;
int err = 0;
vdso_page = alloc_page(GFP_KERNEL);
if (!vdso_page)
panic("Cannot allocate vdso");
vdso = vmap(&vdso_page, 1, 0, PAGE_KERNEL); /*
if (!vdso) * The vDSO data page.
panic("Cannot map vdso"); */
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); static int __init vdso_init(void)
{
err = setup_vdso_page(vdso->rt_signal_retcode); unsigned int i;
if (err)
panic("Cannot set signal return code, err: %x.", err); 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; 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; 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); mmap_write_lock(mm);
if (IS_ERR_VALUE(addr)) { vdso_base = get_unmapped_area(NULL, 0, vdso_len, 0, 0);
ret = addr; if (IS_ERR_VALUE(vdso_base)) {
goto up_fail; ret = vdso_base;
goto end;
} }
ret = install_special_mapping( /*
mm, * Put vDSO base into mm struct. We need to do this before calling
addr, * install_special_mapping or the perf counter mmap tracking code
PAGE_SIZE, * will fail to recognise it as a vDSO (since arch_vma_name fails).
VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, */
&vdso_page); mm->context.vdso = (void *)vdso_base;
if (ret)
goto up_fail; 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); mmap_write_unlock(mm);
return ret; return ret;
} }
const char *arch_vma_name(struct vm_area_struct *vma) const char *arch_vma_name(struct vm_area_struct *vma)
{ {
if (vma->vm_mm == NULL) if (vma->vm_mm && (vma->vm_start == (long)vma->vm_mm->context.vdso))
return NULL;
if (vma->vm_start == (long)vma->vm_mm->context.vdso)
return "[vdso]"; return "[vdso]";
else if (vma->vm_mm && (vma->vm_start ==
return NULL; (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% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册