RISC-V: User-facing API
This patch contains code that is in some way visible to the user: including via system calls, the VDSO, module loading and signal handling. It also contains some generic code that is ABI visible. Signed-off-by: Palmer Dabbelt <palmer@dabbelt.com>
This commit is contained in:
Родитель
07037db5d4
Коммит
e2c0cdfba7
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012 Regents of the University of California
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _ASM_RISCV_MMU_H
|
||||||
|
#define _ASM_RISCV_MMU_H
|
||||||
|
|
||||||
|
#ifndef __ASSEMBLY__
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
void *vdso;
|
||||||
|
} mm_context_t;
|
||||||
|
|
||||||
|
#endif /* __ASSEMBLY__ */
|
||||||
|
|
||||||
|
#endif /* _ASM_RISCV_MMU_H */
|
|
@ -0,0 +1,118 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012 Regents of the University of California
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _ASM_RISCV_PTRACE_H
|
||||||
|
#define _ASM_RISCV_PTRACE_H
|
||||||
|
|
||||||
|
#include <uapi/asm/ptrace.h>
|
||||||
|
#include <asm/csr.h>
|
||||||
|
|
||||||
|
#ifndef __ASSEMBLY__
|
||||||
|
|
||||||
|
struct pt_regs {
|
||||||
|
unsigned long sepc;
|
||||||
|
unsigned long ra;
|
||||||
|
unsigned long sp;
|
||||||
|
unsigned long gp;
|
||||||
|
unsigned long tp;
|
||||||
|
unsigned long t0;
|
||||||
|
unsigned long t1;
|
||||||
|
unsigned long t2;
|
||||||
|
unsigned long s0;
|
||||||
|
unsigned long s1;
|
||||||
|
unsigned long a0;
|
||||||
|
unsigned long a1;
|
||||||
|
unsigned long a2;
|
||||||
|
unsigned long a3;
|
||||||
|
unsigned long a4;
|
||||||
|
unsigned long a5;
|
||||||
|
unsigned long a6;
|
||||||
|
unsigned long a7;
|
||||||
|
unsigned long s2;
|
||||||
|
unsigned long s3;
|
||||||
|
unsigned long s4;
|
||||||
|
unsigned long s5;
|
||||||
|
unsigned long s6;
|
||||||
|
unsigned long s7;
|
||||||
|
unsigned long s8;
|
||||||
|
unsigned long s9;
|
||||||
|
unsigned long s10;
|
||||||
|
unsigned long s11;
|
||||||
|
unsigned long t3;
|
||||||
|
unsigned long t4;
|
||||||
|
unsigned long t5;
|
||||||
|
unsigned long t6;
|
||||||
|
/* Supervisor CSRs */
|
||||||
|
unsigned long sstatus;
|
||||||
|
unsigned long sbadaddr;
|
||||||
|
unsigned long scause;
|
||||||
|
/* a0 value before the syscall */
|
||||||
|
unsigned long orig_a0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_64BIT
|
||||||
|
#define REG_FMT "%016lx"
|
||||||
|
#else
|
||||||
|
#define REG_FMT "%08lx"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define user_mode(regs) (((regs)->sstatus & SR_PS) == 0)
|
||||||
|
|
||||||
|
|
||||||
|
/* Helpers for working with the instruction pointer */
|
||||||
|
#define GET_IP(regs) ((regs)->sepc)
|
||||||
|
#define SET_IP(regs, val) (GET_IP(regs) = (val))
|
||||||
|
|
||||||
|
static inline unsigned long instruction_pointer(struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
return GET_IP(regs);
|
||||||
|
}
|
||||||
|
static inline void instruction_pointer_set(struct pt_regs *regs,
|
||||||
|
unsigned long val)
|
||||||
|
{
|
||||||
|
SET_IP(regs, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define profile_pc(regs) instruction_pointer(regs)
|
||||||
|
|
||||||
|
/* Helpers for working with the user stack pointer */
|
||||||
|
#define GET_USP(regs) ((regs)->sp)
|
||||||
|
#define SET_USP(regs, val) (GET_USP(regs) = (val))
|
||||||
|
|
||||||
|
static inline unsigned long user_stack_pointer(struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
return GET_USP(regs);
|
||||||
|
}
|
||||||
|
static inline void user_stack_pointer_set(struct pt_regs *regs,
|
||||||
|
unsigned long val)
|
||||||
|
{
|
||||||
|
SET_USP(regs, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Helpers for working with the frame pointer */
|
||||||
|
#define GET_FP(regs) ((regs)->s0)
|
||||||
|
#define SET_FP(regs, val) (GET_FP(regs) = (val))
|
||||||
|
|
||||||
|
static inline unsigned long frame_pointer(struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
return GET_FP(regs);
|
||||||
|
}
|
||||||
|
static inline void frame_pointer_set(struct pt_regs *regs,
|
||||||
|
unsigned long val)
|
||||||
|
{
|
||||||
|
SET_FP(regs, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __ASSEMBLY__ */
|
||||||
|
|
||||||
|
#endif /* _ASM_RISCV_PTRACE_H */
|
|
@ -0,0 +1,102 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
|
||||||
|
* Copyright 2010 Tilera Corporation. All Rights Reserved.
|
||||||
|
* Copyright 2015 Regents of the University of California, Berkeley
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* See asm-generic/syscall.h for descriptions of what we must do here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _ASM_RISCV_SYSCALL_H
|
||||||
|
#define _ASM_RISCV_SYSCALL_H
|
||||||
|
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
|
||||||
|
/* The array of function pointers for syscalls. */
|
||||||
|
extern void *sys_call_table[];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only the low 32 bits of orig_r0 are meaningful, so we return int.
|
||||||
|
* This importantly ignores the high bits on 64-bit, so comparisons
|
||||||
|
* sign-extend the low 32 bits.
|
||||||
|
*/
|
||||||
|
static inline int syscall_get_nr(struct task_struct *task,
|
||||||
|
struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
return regs->a7;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void syscall_set_nr(struct task_struct *task,
|
||||||
|
struct pt_regs *regs,
|
||||||
|
int sysno)
|
||||||
|
{
|
||||||
|
regs->a7 = sysno;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void syscall_rollback(struct task_struct *task,
|
||||||
|
struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
regs->a0 = regs->orig_a0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline long syscall_get_error(struct task_struct *task,
|
||||||
|
struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
unsigned long error = regs->a0;
|
||||||
|
|
||||||
|
return IS_ERR_VALUE(error) ? error : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline long syscall_get_return_value(struct task_struct *task,
|
||||||
|
struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
return regs->a0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void syscall_set_return_value(struct task_struct *task,
|
||||||
|
struct pt_regs *regs,
|
||||||
|
int error, long val)
|
||||||
|
{
|
||||||
|
regs->a0 = (long) error ?: val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void syscall_get_arguments(struct task_struct *task,
|
||||||
|
struct pt_regs *regs,
|
||||||
|
unsigned int i, unsigned int n,
|
||||||
|
unsigned long *args)
|
||||||
|
{
|
||||||
|
BUG_ON(i + n > 6);
|
||||||
|
if (i == 0) {
|
||||||
|
args[0] = regs->orig_a0;
|
||||||
|
args++;
|
||||||
|
i++;
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
memcpy(args, ®s->a1 + i * sizeof(regs->a1), n * sizeof(args[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void syscall_set_arguments(struct task_struct *task,
|
||||||
|
struct pt_regs *regs,
|
||||||
|
unsigned int i, unsigned int n,
|
||||||
|
const unsigned long *args)
|
||||||
|
{
|
||||||
|
BUG_ON(i + n > 6);
|
||||||
|
if (i == 0) {
|
||||||
|
regs->orig_a0 = args[0];
|
||||||
|
args++;
|
||||||
|
i++;
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
memcpy(®s->a1 + i * sizeof(regs->a1), args, n * sizeof(regs->a0));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _ASM_RISCV_SYSCALL_H */
|
|
@ -0,0 +1,16 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012 Regents of the University of California
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define __ARCH_HAVE_MMU
|
||||||
|
#define __ARCH_WANT_SYS_CLONE
|
||||||
|
#include <uapi/asm/unistd.h>
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012 ARM Limited
|
||||||
|
* Copyright (C) 2014 Regents of the University of California
|
||||||
|
* Copyright (C) 2017 SiFive
|
||||||
|
*
|
||||||
|
* 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_RISCV_VDSO_H
|
||||||
|
#define _ASM_RISCV_VDSO_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
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_RISCV_VDSO_H */
|
|
@ -0,0 +1,27 @@
|
||||||
|
# UAPI Header export list
|
||||||
|
include include/uapi/asm-generic/Kbuild.asm
|
||||||
|
|
||||||
|
generic-y += setup.h
|
||||||
|
generic-y += unistd.h
|
||||||
|
generic-y += errno.h
|
||||||
|
generic-y += fcntl.h
|
||||||
|
generic-y += ioctl.h
|
||||||
|
generic-y += ioctls.h
|
||||||
|
generic-y += ipcbuf.h
|
||||||
|
generic-y += mman.h
|
||||||
|
generic-y += msgbuf.h
|
||||||
|
generic-y += param.h
|
||||||
|
generic-y += poll.h
|
||||||
|
generic-y += posix_types.h
|
||||||
|
generic-y += resource.h
|
||||||
|
generic-y += sembuf.h
|
||||||
|
generic-y += shmbuf.h
|
||||||
|
generic-y += signal.h
|
||||||
|
generic-y += socket.h
|
||||||
|
generic-y += sockios.h
|
||||||
|
generic-y += stat.h
|
||||||
|
generic-y += statfs.h
|
||||||
|
generic-y += swab.h
|
||||||
|
generic-y += termbits.h
|
||||||
|
generic-y += termios.h
|
||||||
|
generic-y += types.h
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012 ARM Ltd.
|
||||||
|
* Copyright (C) 2015 Regents of the University of California
|
||||||
|
*
|
||||||
|
* 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 _UAPI_ASM_RISCV_AUXVEC_H
|
||||||
|
#define _UAPI_ASM_RISCV_AUXVEC_H
|
||||||
|
|
||||||
|
/* vDSO location */
|
||||||
|
#define AT_SYSINFO_EHDR 33
|
||||||
|
|
||||||
|
#endif /* _UAPI_ASM_RISCV_AUXVEC_H */
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012 ARM Ltd.
|
||||||
|
* Copyright (C) 2015 Regents of the University of California
|
||||||
|
*
|
||||||
|
* 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 _UAPI_ASM_RISCV_BITSPERLONG_H
|
||||||
|
#define _UAPI_ASM_RISCV_BITSPERLONG_H
|
||||||
|
|
||||||
|
#define __BITS_PER_LONG (__SIZEOF_POINTER__ * 8)
|
||||||
|
|
||||||
|
#include <asm-generic/bitsperlong.h>
|
||||||
|
|
||||||
|
#endif /* _UAPI_ASM_RISCV_BITSPERLONG_H */
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012 ARM Ltd.
|
||||||
|
* Copyright (C) 2015 Regents of the University of California
|
||||||
|
*
|
||||||
|
* 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 _UAPI_ASM_RISCV_BYTEORDER_H
|
||||||
|
#define _UAPI_ASM_RISCV_BYTEORDER_H
|
||||||
|
|
||||||
|
#include <linux/byteorder/little_endian.h>
|
||||||
|
|
||||||
|
#endif /* _UAPI_ASM_RISCV_BYTEORDER_H */
|
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
|
||||||
|
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
|
||||||
|
* Copyright (C) 2012 Regents of the University of California
|
||||||
|
*
|
||||||
|
* 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; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _UAPI_ASM_ELF_H
|
||||||
|
#define _UAPI_ASM_ELF_H
|
||||||
|
|
||||||
|
#include <asm/ptrace.h>
|
||||||
|
|
||||||
|
/* ELF register definitions */
|
||||||
|
typedef unsigned long elf_greg_t;
|
||||||
|
typedef struct user_regs_struct elf_gregset_t;
|
||||||
|
#define ELF_NGREG (sizeof(elf_gregset_t) / sizeof(elf_greg_t))
|
||||||
|
|
||||||
|
typedef union __riscv_fp_state elf_fpregset_t;
|
||||||
|
|
||||||
|
#define ELF_RISCV_R_SYM(r_info) ((r_info) >> 32)
|
||||||
|
#define ELF_RISCV_R_TYPE(r_info) ((r_info) & 0xffffffff)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RISC-V relocation types
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Relocation types used by the dynamic linker */
|
||||||
|
#define R_RISCV_NONE 0
|
||||||
|
#define R_RISCV_32 1
|
||||||
|
#define R_RISCV_64 2
|
||||||
|
#define R_RISCV_RELATIVE 3
|
||||||
|
#define R_RISCV_COPY 4
|
||||||
|
#define R_RISCV_JUMP_SLOT 5
|
||||||
|
#define R_RISCV_TLS_DTPMOD32 6
|
||||||
|
#define R_RISCV_TLS_DTPMOD64 7
|
||||||
|
#define R_RISCV_TLS_DTPREL32 8
|
||||||
|
#define R_RISCV_TLS_DTPREL64 9
|
||||||
|
#define R_RISCV_TLS_TPREL32 10
|
||||||
|
#define R_RISCV_TLS_TPREL64 11
|
||||||
|
|
||||||
|
/* Relocation types not used by the dynamic linker */
|
||||||
|
#define R_RISCV_BRANCH 16
|
||||||
|
#define R_RISCV_JAL 17
|
||||||
|
#define R_RISCV_CALL 18
|
||||||
|
#define R_RISCV_CALL_PLT 19
|
||||||
|
#define R_RISCV_GOT_HI20 20
|
||||||
|
#define R_RISCV_TLS_GOT_HI20 21
|
||||||
|
#define R_RISCV_TLS_GD_HI20 22
|
||||||
|
#define R_RISCV_PCREL_HI20 23
|
||||||
|
#define R_RISCV_PCREL_LO12_I 24
|
||||||
|
#define R_RISCV_PCREL_LO12_S 25
|
||||||
|
#define R_RISCV_HI20 26
|
||||||
|
#define R_RISCV_LO12_I 27
|
||||||
|
#define R_RISCV_LO12_S 28
|
||||||
|
#define R_RISCV_TPREL_HI20 29
|
||||||
|
#define R_RISCV_TPREL_LO12_I 30
|
||||||
|
#define R_RISCV_TPREL_LO12_S 31
|
||||||
|
#define R_RISCV_TPREL_ADD 32
|
||||||
|
#define R_RISCV_ADD8 33
|
||||||
|
#define R_RISCV_ADD16 34
|
||||||
|
#define R_RISCV_ADD32 35
|
||||||
|
#define R_RISCV_ADD64 36
|
||||||
|
#define R_RISCV_SUB8 37
|
||||||
|
#define R_RISCV_SUB16 38
|
||||||
|
#define R_RISCV_SUB32 39
|
||||||
|
#define R_RISCV_SUB64 40
|
||||||
|
#define R_RISCV_GNU_VTINHERIT 41
|
||||||
|
#define R_RISCV_GNU_VTENTRY 42
|
||||||
|
#define R_RISCV_ALIGN 43
|
||||||
|
#define R_RISCV_RVC_BRANCH 44
|
||||||
|
#define R_RISCV_RVC_JUMP 45
|
||||||
|
#define R_RISCV_LUI 46
|
||||||
|
#define R_RISCV_GPREL_I 47
|
||||||
|
#define R_RISCV_GPREL_S 48
|
||||||
|
#define R_RISCV_TPREL_I 49
|
||||||
|
#define R_RISCV_TPREL_S 50
|
||||||
|
#define R_RISCV_RELAX 51
|
||||||
|
|
||||||
|
#endif /* _UAPI_ASM_ELF_H */
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Copied from arch/arm64/include/asm/hwcap.h
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 ARM Ltd.
|
||||||
|
* Copyright (C) 2017 SiFive
|
||||||
|
*
|
||||||
|
* 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 __UAPI_ASM_HWCAP_H
|
||||||
|
#define __UAPI_ASM_HWCAP_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Linux saves the floating-point registers according to the ISA Linux is
|
||||||
|
* executing on, as opposed to the ISA the user program is compiled for. This
|
||||||
|
* is necessary for a handful of esoteric use cases: for example, userpsace
|
||||||
|
* threading libraries must be able to examine the actual machine state in
|
||||||
|
* order to fully reconstruct the state of a thread.
|
||||||
|
*/
|
||||||
|
#define COMPAT_HWCAP_ISA_I (1 << ('I' - 'A'))
|
||||||
|
#define COMPAT_HWCAP_ISA_M (1 << ('M' - 'A'))
|
||||||
|
#define COMPAT_HWCAP_ISA_A (1 << ('A' - 'A'))
|
||||||
|
#define COMPAT_HWCAP_ISA_F (1 << ('F' - 'A'))
|
||||||
|
#define COMPAT_HWCAP_ISA_D (1 << ('D' - 'A'))
|
||||||
|
#define COMPAT_HWCAP_ISA_C (1 << ('C' - 'A'))
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012 Regents of the University of California
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _UAPI_ASM_RISCV_PTRACE_H
|
||||||
|
#define _UAPI_ASM_RISCV_PTRACE_H
|
||||||
|
|
||||||
|
#ifndef __ASSEMBLY__
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* User-mode register state for core dumps, ptrace, sigcontext
|
||||||
|
*
|
||||||
|
* This decouples struct pt_regs from the userspace ABI.
|
||||||
|
* struct user_regs_struct must form a prefix of struct pt_regs.
|
||||||
|
*/
|
||||||
|
struct user_regs_struct {
|
||||||
|
unsigned long pc;
|
||||||
|
unsigned long ra;
|
||||||
|
unsigned long sp;
|
||||||
|
unsigned long gp;
|
||||||
|
unsigned long tp;
|
||||||
|
unsigned long t0;
|
||||||
|
unsigned long t1;
|
||||||
|
unsigned long t2;
|
||||||
|
unsigned long s0;
|
||||||
|
unsigned long s1;
|
||||||
|
unsigned long a0;
|
||||||
|
unsigned long a1;
|
||||||
|
unsigned long a2;
|
||||||
|
unsigned long a3;
|
||||||
|
unsigned long a4;
|
||||||
|
unsigned long a5;
|
||||||
|
unsigned long a6;
|
||||||
|
unsigned long a7;
|
||||||
|
unsigned long s2;
|
||||||
|
unsigned long s3;
|
||||||
|
unsigned long s4;
|
||||||
|
unsigned long s5;
|
||||||
|
unsigned long s6;
|
||||||
|
unsigned long s7;
|
||||||
|
unsigned long s8;
|
||||||
|
unsigned long s9;
|
||||||
|
unsigned long s10;
|
||||||
|
unsigned long s11;
|
||||||
|
unsigned long t3;
|
||||||
|
unsigned long t4;
|
||||||
|
unsigned long t5;
|
||||||
|
unsigned long t6;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct __riscv_f_ext_state {
|
||||||
|
__u32 f[32];
|
||||||
|
__u32 fcsr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct __riscv_d_ext_state {
|
||||||
|
__u64 f[32];
|
||||||
|
__u32 fcsr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct __riscv_q_ext_state {
|
||||||
|
__u64 f[64] __attribute__((aligned(16)));
|
||||||
|
__u32 fcsr;
|
||||||
|
/*
|
||||||
|
* Reserved for expansion of sigcontext structure. Currently zeroed
|
||||||
|
* upon signal, and must be zero upon sigreturn.
|
||||||
|
*/
|
||||||
|
__u32 reserved[3];
|
||||||
|
};
|
||||||
|
|
||||||
|
union __riscv_fp_state {
|
||||||
|
struct __riscv_f_ext_state f;
|
||||||
|
struct __riscv_d_ext_state d;
|
||||||
|
struct __riscv_q_ext_state q;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __ASSEMBLY__ */
|
||||||
|
|
||||||
|
#endif /* _UAPI_ASM_RISCV_PTRACE_H */
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012 Regents of the University of California
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _UAPI_ASM_RISCV_SIGCONTEXT_H
|
||||||
|
#define _UAPI_ASM_RISCV_SIGCONTEXT_H
|
||||||
|
|
||||||
|
#include <asm/ptrace.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Signal context structure
|
||||||
|
*
|
||||||
|
* This contains the context saved before a signal handler is invoked;
|
||||||
|
* it is restored by sys_sigreturn / sys_rt_sigreturn.
|
||||||
|
*/
|
||||||
|
struct sigcontext {
|
||||||
|
struct user_regs_struct sc_regs;
|
||||||
|
union __riscv_fp_state sc_fpregs;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _UAPI_ASM_RISCV_SIGCONTEXT_H */
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012 ARM Ltd.
|
||||||
|
* Copyright (C) 2016 SiFive, Inc.
|
||||||
|
*
|
||||||
|
* 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_SIGINFO_H
|
||||||
|
#define __ASM_SIGINFO_H
|
||||||
|
|
||||||
|
#define __ARCH_SI_PREAMBLE_SIZE (__SIZEOF_POINTER__ == 4 ? 12 : 16)
|
||||||
|
|
||||||
|
#include <asm-generic/siginfo.h>
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012 ARM Ltd.
|
||||||
|
* Copyright (C) 2017 SiFive, Inc.
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*
|
||||||
|
* This file was copied from arch/arm64/include/uapi/asm/ucontext.h
|
||||||
|
*/
|
||||||
|
#ifndef _UAPI__ASM_UCONTEXT_H
|
||||||
|
#define _UAPI__ASM_UCONTEXT_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
struct ucontext {
|
||||||
|
unsigned long uc_flags;
|
||||||
|
struct ucontext *uc_link;
|
||||||
|
stack_t uc_stack;
|
||||||
|
sigset_t uc_sigmask;
|
||||||
|
/* There's some padding here to allow sigset_t to be expanded in the
|
||||||
|
* future. Though this is unlikely, other architectures put uc_sigmask
|
||||||
|
* at the end of this structure and explicitly state it can be
|
||||||
|
* expanded, so we didn't want to box ourselves in here. */
|
||||||
|
__u8 __unused[1024 / 8 - sizeof(sigset_t)];
|
||||||
|
/* We can't put uc_sigmask at the end of this structure because we need
|
||||||
|
* to be able to expand sigcontext in the future. For example, the
|
||||||
|
* vector ISA extension will almost certainly add ISA state. We want
|
||||||
|
* to ensure all user-visible ISA state can be saved and restored via a
|
||||||
|
* ucontext, so we're putting this at the end in order to allow for
|
||||||
|
* infinite extensibility. Since we know this will be extended and we
|
||||||
|
* assume sigset_t won't be extended an extreme amount, we're
|
||||||
|
* prioritizing this. */
|
||||||
|
struct sigcontext uc_mcontext;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _UAPI__ASM_UCONTEXT_H */
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* Copied from arch/arm64/kernel/cpufeature.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 ARM Ltd.
|
||||||
|
* Copyright (C) 2017 SiFive
|
||||||
|
*
|
||||||
|
* 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/of.h>
|
||||||
|
#include <asm/processor.h>
|
||||||
|
#include <asm/hwcap.h>
|
||||||
|
|
||||||
|
unsigned long elf_hwcap __read_mostly;
|
||||||
|
|
||||||
|
void riscv_fill_hwcap(void)
|
||||||
|
{
|
||||||
|
struct device_node *node;
|
||||||
|
const char *isa;
|
||||||
|
size_t i;
|
||||||
|
static unsigned long isa2hwcap[256] = {0};
|
||||||
|
|
||||||
|
isa2hwcap['i'] = isa2hwcap['I'] = COMPAT_HWCAP_ISA_I;
|
||||||
|
isa2hwcap['m'] = isa2hwcap['M'] = COMPAT_HWCAP_ISA_M;
|
||||||
|
isa2hwcap['a'] = isa2hwcap['A'] = COMPAT_HWCAP_ISA_A;
|
||||||
|
isa2hwcap['f'] = isa2hwcap['F'] = COMPAT_HWCAP_ISA_F;
|
||||||
|
isa2hwcap['d'] = isa2hwcap['D'] = COMPAT_HWCAP_ISA_D;
|
||||||
|
isa2hwcap['c'] = isa2hwcap['C'] = COMPAT_HWCAP_ISA_C;
|
||||||
|
|
||||||
|
elf_hwcap = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We don't support running Linux on hertergenous ISA systems. For
|
||||||
|
* now, we just check the ISA of the first processor.
|
||||||
|
*/
|
||||||
|
node = of_find_node_by_type(NULL, "cpu");
|
||||||
|
if (!node) {
|
||||||
|
pr_warning("Unable to find \"cpu\" devicetree entry");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (of_property_read_string(node, "riscv,isa", &isa)) {
|
||||||
|
pr_warning("Unable to find \"riscv,isa\" devicetree entry");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < strlen(isa); ++i)
|
||||||
|
elf_hwcap |= isa2hwcap[(unsigned char)(isa[i])];
|
||||||
|
|
||||||
|
pr_info("elf_hwcap is 0x%lx", elf_hwcap);
|
||||||
|
}
|
|
@ -0,0 +1,217 @@
|
||||||
|
/*
|
||||||
|
* 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; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Zihao Yu
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/elf.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <linux/moduleloader.h>
|
||||||
|
|
||||||
|
static int apply_r_riscv_64_rela(struct module *me, u32 *location, Elf_Addr v)
|
||||||
|
{
|
||||||
|
*(u64 *)location = v;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int apply_r_riscv_branch_rela(struct module *me, u32 *location,
|
||||||
|
Elf_Addr v)
|
||||||
|
{
|
||||||
|
s64 offset = (void *)v - (void *)location;
|
||||||
|
u32 imm12 = (offset & 0x1000) << (31 - 12);
|
||||||
|
u32 imm11 = (offset & 0x800) >> (11 - 7);
|
||||||
|
u32 imm10_5 = (offset & 0x7e0) << (30 - 10);
|
||||||
|
u32 imm4_1 = (offset & 0x1e) << (11 - 4);
|
||||||
|
|
||||||
|
*location = (*location & 0x1fff07f) | imm12 | imm11 | imm10_5 | imm4_1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int apply_r_riscv_jal_rela(struct module *me, u32 *location,
|
||||||
|
Elf_Addr v)
|
||||||
|
{
|
||||||
|
s64 offset = (void *)v - (void *)location;
|
||||||
|
u32 imm20 = (offset & 0x100000) << (31 - 20);
|
||||||
|
u32 imm19_12 = (offset & 0xff000);
|
||||||
|
u32 imm11 = (offset & 0x800) << (20 - 11);
|
||||||
|
u32 imm10_1 = (offset & 0x7fe) << (30 - 10);
|
||||||
|
|
||||||
|
*location = (*location & 0xfff) | imm20 | imm19_12 | imm11 | imm10_1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int apply_r_riscv_pcrel_hi20_rela(struct module *me, u32 *location,
|
||||||
|
Elf_Addr v)
|
||||||
|
{
|
||||||
|
s64 offset = (void *)v - (void *)location;
|
||||||
|
s32 hi20;
|
||||||
|
|
||||||
|
if (offset != (s32)offset) {
|
||||||
|
pr_err(
|
||||||
|
"%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n",
|
||||||
|
me->name, v, location);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
hi20 = (offset + 0x800) & 0xfffff000;
|
||||||
|
*location = (*location & 0xfff) | hi20;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int apply_r_riscv_pcrel_lo12_i_rela(struct module *me, u32 *location,
|
||||||
|
Elf_Addr v)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* v is the lo12 value to fill. It is calculated before calling this
|
||||||
|
* handler.
|
||||||
|
*/
|
||||||
|
*location = (*location & 0xfffff) | ((v & 0xfff) << 20);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int apply_r_riscv_pcrel_lo12_s_rela(struct module *me, u32 *location,
|
||||||
|
Elf_Addr v)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* v is the lo12 value to fill. It is calculated before calling this
|
||||||
|
* handler.
|
||||||
|
*/
|
||||||
|
u32 imm11_5 = (v & 0xfe0) << (31 - 11);
|
||||||
|
u32 imm4_0 = (v & 0x1f) << (11 - 4);
|
||||||
|
|
||||||
|
*location = (*location & 0x1fff07f) | imm11_5 | imm4_0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int apply_r_riscv_call_plt_rela(struct module *me, u32 *location,
|
||||||
|
Elf_Addr v)
|
||||||
|
{
|
||||||
|
s64 offset = (void *)v - (void *)location;
|
||||||
|
s32 fill_v = offset;
|
||||||
|
u32 hi20, lo12;
|
||||||
|
|
||||||
|
if (offset != fill_v) {
|
||||||
|
pr_err(
|
||||||
|
"%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n",
|
||||||
|
me->name, v, location);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
hi20 = (offset + 0x800) & 0xfffff000;
|
||||||
|
lo12 = (offset - hi20) & 0xfff;
|
||||||
|
*location = (*location & 0xfff) | hi20;
|
||||||
|
*(location + 1) = (*(location + 1) & 0xfffff) | (lo12 << 20);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int apply_r_riscv_relax_rela(struct module *me, u32 *location,
|
||||||
|
Elf_Addr v)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int (*reloc_handlers_rela[]) (struct module *me, u32 *location,
|
||||||
|
Elf_Addr v) = {
|
||||||
|
[R_RISCV_64] = apply_r_riscv_64_rela,
|
||||||
|
[R_RISCV_BRANCH] = apply_r_riscv_branch_rela,
|
||||||
|
[R_RISCV_JAL] = apply_r_riscv_jal_rela,
|
||||||
|
[R_RISCV_PCREL_HI20] = apply_r_riscv_pcrel_hi20_rela,
|
||||||
|
[R_RISCV_PCREL_LO12_I] = apply_r_riscv_pcrel_lo12_i_rela,
|
||||||
|
[R_RISCV_PCREL_LO12_S] = apply_r_riscv_pcrel_lo12_s_rela,
|
||||||
|
[R_RISCV_CALL_PLT] = apply_r_riscv_call_plt_rela,
|
||||||
|
[R_RISCV_RELAX] = apply_r_riscv_relax_rela,
|
||||||
|
};
|
||||||
|
|
||||||
|
int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
|
||||||
|
unsigned int symindex, unsigned int relsec,
|
||||||
|
struct module *me)
|
||||||
|
{
|
||||||
|
Elf_Rela *rel = (void *) sechdrs[relsec].sh_addr;
|
||||||
|
int (*handler)(struct module *me, u32 *location, Elf_Addr v);
|
||||||
|
Elf_Sym *sym;
|
||||||
|
u32 *location;
|
||||||
|
unsigned int i, type;
|
||||||
|
Elf_Addr v;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
pr_debug("Applying relocate section %u to %u\n", relsec,
|
||||||
|
sechdrs[relsec].sh_info);
|
||||||
|
|
||||||
|
for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
|
||||||
|
/* This is where to make the change */
|
||||||
|
location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
|
||||||
|
+ rel[i].r_offset;
|
||||||
|
/* This is the symbol it is referring to */
|
||||||
|
sym = (Elf_Sym *)sechdrs[symindex].sh_addr
|
||||||
|
+ ELF_RISCV_R_SYM(rel[i].r_info);
|
||||||
|
if (IS_ERR_VALUE(sym->st_value)) {
|
||||||
|
/* Ignore unresolved weak symbol */
|
||||||
|
if (ELF_ST_BIND(sym->st_info) == STB_WEAK)
|
||||||
|
continue;
|
||||||
|
pr_warning("%s: Unknown symbol %s\n",
|
||||||
|
me->name, strtab + sym->st_name);
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = ELF_RISCV_R_TYPE(rel[i].r_info);
|
||||||
|
|
||||||
|
if (type < ARRAY_SIZE(reloc_handlers_rela))
|
||||||
|
handler = reloc_handlers_rela[type];
|
||||||
|
else
|
||||||
|
handler = NULL;
|
||||||
|
|
||||||
|
if (!handler) {
|
||||||
|
pr_err("%s: Unknown relocation type %u\n",
|
||||||
|
me->name, type);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
v = sym->st_value + rel[i].r_addend;
|
||||||
|
|
||||||
|
if (type == R_RISCV_PCREL_LO12_I || type == R_RISCV_PCREL_LO12_S) {
|
||||||
|
unsigned int j;
|
||||||
|
|
||||||
|
for (j = 0; j < sechdrs[relsec].sh_size / sizeof(*rel); j++) {
|
||||||
|
u64 hi20_loc =
|
||||||
|
sechdrs[sechdrs[relsec].sh_info].sh_addr
|
||||||
|
+ rel[j].r_offset;
|
||||||
|
/* Find the corresponding HI20 PC-relative relocation entry */
|
||||||
|
if (hi20_loc == sym->st_value) {
|
||||||
|
Elf_Sym *hi20_sym =
|
||||||
|
(Elf_Sym *)sechdrs[symindex].sh_addr
|
||||||
|
+ ELF_RISCV_R_SYM(rel[j].r_info);
|
||||||
|
u64 hi20_sym_val =
|
||||||
|
hi20_sym->st_value
|
||||||
|
+ rel[j].r_addend;
|
||||||
|
/* Calculate lo12 */
|
||||||
|
s64 offset = hi20_sym_val - hi20_loc;
|
||||||
|
s32 hi20 = (offset + 0x800) & 0xfffff000;
|
||||||
|
s32 lo12 = offset - hi20;
|
||||||
|
v = lo12;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (j == sechdrs[relsec].sh_size / sizeof(*rel)) {
|
||||||
|
pr_err(
|
||||||
|
"%s: Can not find HI20 PC-relative relocation information\n",
|
||||||
|
me->name);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res = handler(me, location, v);
|
||||||
|
if (res)
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2010 Tilera Corporation. All Rights Reserved.
|
||||||
|
* Copyright 2015 Regents of the University of California
|
||||||
|
* Copyright 2017 SiFive
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Copied from arch/tile/kernel/ptrace.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <asm/ptrace.h>
|
||||||
|
#include <asm/syscall.h>
|
||||||
|
#include <asm/thread_info.h>
|
||||||
|
#include <linux/ptrace.h>
|
||||||
|
#include <linux/elf.h>
|
||||||
|
#include <linux/regset.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/sched/task_stack.h>
|
||||||
|
#include <linux/tracehook.h>
|
||||||
|
#include <trace/events/syscalls.h>
|
||||||
|
|
||||||
|
enum riscv_regset {
|
||||||
|
REGSET_X,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int riscv_gpr_get(struct task_struct *target,
|
||||||
|
const struct user_regset *regset,
|
||||||
|
unsigned int pos, unsigned int count,
|
||||||
|
void *kbuf, void __user *ubuf)
|
||||||
|
{
|
||||||
|
struct pt_regs *regs;
|
||||||
|
|
||||||
|
regs = task_pt_regs(target);
|
||||||
|
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, regs, 0, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int riscv_gpr_set(struct task_struct *target,
|
||||||
|
const struct user_regset *regset,
|
||||||
|
unsigned int pos, unsigned int count,
|
||||||
|
const void *kbuf, const void __user *ubuf)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct pt_regs *regs;
|
||||||
|
|
||||||
|
regs = task_pt_regs(target);
|
||||||
|
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, ®s, 0, -1);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const struct user_regset riscv_user_regset[] = {
|
||||||
|
[REGSET_X] = {
|
||||||
|
.core_note_type = NT_PRSTATUS,
|
||||||
|
.n = ELF_NGREG,
|
||||||
|
.size = sizeof(elf_greg_t),
|
||||||
|
.align = sizeof(elf_greg_t),
|
||||||
|
.get = &riscv_gpr_get,
|
||||||
|
.set = &riscv_gpr_set,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct user_regset_view riscv_user_native_view = {
|
||||||
|
.name = "riscv",
|
||||||
|
.e_machine = EM_RISCV,
|
||||||
|
.regsets = riscv_user_regset,
|
||||||
|
.n = ARRAY_SIZE(riscv_user_regset),
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct user_regset_view *task_user_regset_view(struct task_struct *task)
|
||||||
|
{
|
||||||
|
return &riscv_user_native_view;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ptrace_disable(struct task_struct *child)
|
||||||
|
{
|
||||||
|
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
|
||||||
|
}
|
||||||
|
|
||||||
|
long arch_ptrace(struct task_struct *child, long request,
|
||||||
|
unsigned long addr, unsigned long data)
|
||||||
|
{
|
||||||
|
long ret = -EIO;
|
||||||
|
|
||||||
|
switch (request) {
|
||||||
|
default:
|
||||||
|
ret = ptrace_request(child, request, addr, data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allows PTRACE_SYSCALL to work. These are called from entry.S in
|
||||||
|
* {handle,ret_from}_syscall.
|
||||||
|
*/
|
||||||
|
void do_syscall_trace_enter(struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
if (test_thread_flag(TIF_SYSCALL_TRACE))
|
||||||
|
if (tracehook_report_syscall_entry(regs))
|
||||||
|
syscall_set_nr(current, regs, -1);
|
||||||
|
|
||||||
|
#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
|
||||||
|
if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
|
||||||
|
trace_sys_enter(regs, syscall_get_nr(current, regs));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_syscall_trace_exit(struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
if (test_thread_flag(TIF_SYSCALL_TRACE))
|
||||||
|
tracehook_report_syscall_exit(regs, 0);
|
||||||
|
|
||||||
|
#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
|
||||||
|
if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
|
||||||
|
trace_sys_exit(regs, regs->regs[0]);
|
||||||
|
#endif
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2017 Zihao Yu
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/export.h>
|
||||||
|
#include <linux/uaccess.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Assembly functions that may be used (directly or indirectly) by modules
|
||||||
|
*/
|
||||||
|
EXPORT_SYMBOL(__copy_user);
|
|
@ -0,0 +1,292 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2009 Sunplus Core Technology Co., Ltd.
|
||||||
|
* Chen Liqin <liqin.chen@sunplusct.com>
|
||||||
|
* Lennox Wu <lennox.wu@sunplusct.com>
|
||||||
|
* Copyright (C) 2012 Regents of the University of California
|
||||||
|
*
|
||||||
|
* 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; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* 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 the file COPYING, or write
|
||||||
|
* to the Free Software Foundation, Inc.,
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/signal.h>
|
||||||
|
#include <linux/uaccess.h>
|
||||||
|
#include <linux/syscalls.h>
|
||||||
|
#include <linux/tracehook.h>
|
||||||
|
#include <linux/linkage.h>
|
||||||
|
|
||||||
|
#include <asm/ucontext.h>
|
||||||
|
#include <asm/vdso.h>
|
||||||
|
#include <asm/switch_to.h>
|
||||||
|
#include <asm/csr.h>
|
||||||
|
|
||||||
|
#define DEBUG_SIG 0
|
||||||
|
|
||||||
|
struct rt_sigframe {
|
||||||
|
struct siginfo info;
|
||||||
|
struct ucontext uc;
|
||||||
|
};
|
||||||
|
|
||||||
|
static long restore_d_state(struct pt_regs *regs,
|
||||||
|
struct __riscv_d_ext_state __user *state)
|
||||||
|
{
|
||||||
|
long err;
|
||||||
|
err = __copy_from_user(¤t->thread.fstate, state, sizeof(*state));
|
||||||
|
if (likely(!err))
|
||||||
|
fstate_restore(current, regs);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long save_d_state(struct pt_regs *regs,
|
||||||
|
struct __riscv_d_ext_state __user *state)
|
||||||
|
{
|
||||||
|
fstate_save(current, regs);
|
||||||
|
return __copy_to_user(state, ¤t->thread.fstate, sizeof(*state));
|
||||||
|
}
|
||||||
|
|
||||||
|
static long restore_sigcontext(struct pt_regs *regs,
|
||||||
|
struct sigcontext __user *sc)
|
||||||
|
{
|
||||||
|
long err;
|
||||||
|
size_t i;
|
||||||
|
/* sc_regs is structured the same as the start of pt_regs */
|
||||||
|
err = __copy_from_user(regs, &sc->sc_regs, sizeof(sc->sc_regs));
|
||||||
|
if (unlikely(err))
|
||||||
|
return err;
|
||||||
|
/* Restore the floating-point state. */
|
||||||
|
err = restore_d_state(regs, &sc->sc_fpregs.d);
|
||||||
|
if (unlikely(err))
|
||||||
|
return err;
|
||||||
|
/* We support no other extension state at this time. */
|
||||||
|
for (i = 0; i < ARRAY_SIZE(sc->sc_fpregs.q.reserved); i++) {
|
||||||
|
u32 value;
|
||||||
|
err = __get_user(value, &sc->sc_fpregs.q.reserved[i]);
|
||||||
|
if (unlikely(err))
|
||||||
|
break;
|
||||||
|
if (value != 0)
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
SYSCALL_DEFINE0(rt_sigreturn)
|
||||||
|
{
|
||||||
|
struct pt_regs *regs = current_pt_regs();
|
||||||
|
struct rt_sigframe __user *frame;
|
||||||
|
struct task_struct *task;
|
||||||
|
sigset_t set;
|
||||||
|
|
||||||
|
/* Always make any pending restarted system calls return -EINTR */
|
||||||
|
current->restart_block.fn = do_no_restart_syscall;
|
||||||
|
|
||||||
|
frame = (struct rt_sigframe __user *)regs->sp;
|
||||||
|
|
||||||
|
if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
|
||||||
|
goto badframe;
|
||||||
|
|
||||||
|
if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
|
||||||
|
goto badframe;
|
||||||
|
|
||||||
|
set_current_blocked(&set);
|
||||||
|
|
||||||
|
if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
|
||||||
|
goto badframe;
|
||||||
|
|
||||||
|
if (restore_altstack(&frame->uc.uc_stack))
|
||||||
|
goto badframe;
|
||||||
|
|
||||||
|
return regs->a0;
|
||||||
|
|
||||||
|
badframe:
|
||||||
|
task = current;
|
||||||
|
if (show_unhandled_signals) {
|
||||||
|
pr_info_ratelimited(
|
||||||
|
"%s[%d]: bad frame in %s: frame=%p pc=%p sp=%p\n",
|
||||||
|
task->comm, task_pid_nr(task), __func__,
|
||||||
|
frame, (void *)regs->sepc, (void *)regs->sp);
|
||||||
|
}
|
||||||
|
force_sig(SIGSEGV, task);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long setup_sigcontext(struct rt_sigframe __user *frame,
|
||||||
|
struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
struct sigcontext __user *sc = &frame->uc.uc_mcontext;
|
||||||
|
long err;
|
||||||
|
size_t i;
|
||||||
|
/* sc_regs is structured the same as the start of pt_regs */
|
||||||
|
err = __copy_to_user(&sc->sc_regs, regs, sizeof(sc->sc_regs));
|
||||||
|
/* Save the floating-point state. */
|
||||||
|
err |= save_d_state(regs, &sc->sc_fpregs.d);
|
||||||
|
/* We support no other extension state at this time. */
|
||||||
|
for (i = 0; i < ARRAY_SIZE(sc->sc_fpregs.q.reserved); i++)
|
||||||
|
err |= __put_user(0, &sc->sc_fpregs.q.reserved[i]);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void __user *get_sigframe(struct ksignal *ksig,
|
||||||
|
struct pt_regs *regs, size_t framesize)
|
||||||
|
{
|
||||||
|
unsigned long sp;
|
||||||
|
/* Default to using normal stack */
|
||||||
|
sp = regs->sp;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we are on the alternate signal stack and would overflow it, don't.
|
||||||
|
* Return an always-bogus address instead so we will die with SIGSEGV.
|
||||||
|
*/
|
||||||
|
if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize)))
|
||||||
|
return (void __user __force *)(-1UL);
|
||||||
|
|
||||||
|
/* This is the X/Open sanctioned signal stack switching. */
|
||||||
|
sp = sigsp(sp, ksig) - framesize;
|
||||||
|
|
||||||
|
/* Align the stack frame. */
|
||||||
|
sp &= ~0xfUL;
|
||||||
|
|
||||||
|
return (void __user *)sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
|
||||||
|
struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
struct rt_sigframe __user *frame;
|
||||||
|
long err = 0;
|
||||||
|
|
||||||
|
frame = get_sigframe(ksig, regs, sizeof(*frame));
|
||||||
|
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
err |= copy_siginfo_to_user(&frame->info, &ksig->info);
|
||||||
|
|
||||||
|
/* Create the ucontext. */
|
||||||
|
err |= __put_user(0, &frame->uc.uc_flags);
|
||||||
|
err |= __put_user(NULL, &frame->uc.uc_link);
|
||||||
|
err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
|
||||||
|
err |= setup_sigcontext(frame, regs);
|
||||||
|
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
|
||||||
|
if (err)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
/* Set up to return from userspace. */
|
||||||
|
regs->ra = (unsigned long)VDSO_SYMBOL(
|
||||||
|
current->mm->context.vdso, rt_sigreturn);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up registers for signal handler.
|
||||||
|
* Registers that we don't modify keep the value they had from
|
||||||
|
* user-space at the time we took the signal.
|
||||||
|
* We always pass siginfo and mcontext, regardless of SA_SIGINFO,
|
||||||
|
* since some things rely on this (e.g. glibc's debug/segfault.c).
|
||||||
|
*/
|
||||||
|
regs->sepc = (unsigned long)ksig->ka.sa.sa_handler;
|
||||||
|
regs->sp = (unsigned long)frame;
|
||||||
|
regs->a0 = ksig->sig; /* a0: signal number */
|
||||||
|
regs->a1 = (unsigned long)(&frame->info); /* a1: siginfo pointer */
|
||||||
|
regs->a2 = (unsigned long)(&frame->uc); /* a2: ucontext pointer */
|
||||||
|
|
||||||
|
#if DEBUG_SIG
|
||||||
|
pr_info("SIG deliver (%s:%d): sig=%d pc=%p ra=%p sp=%p\n",
|
||||||
|
current->comm, task_pid_nr(current), ksig->sig,
|
||||||
|
(void *)regs->sepc, (void *)regs->ra, frame);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
sigset_t *oldset = sigmask_to_save();
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Are we from a system call? */
|
||||||
|
if (regs->scause == EXC_SYSCALL) {
|
||||||
|
/* If so, check system call restarting.. */
|
||||||
|
switch (regs->a0) {
|
||||||
|
case -ERESTART_RESTARTBLOCK:
|
||||||
|
case -ERESTARTNOHAND:
|
||||||
|
regs->a0 = -EINTR;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case -ERESTARTSYS:
|
||||||
|
if (!(ksig->ka.sa.sa_flags & SA_RESTART)) {
|
||||||
|
regs->a0 = -EINTR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* fallthrough */
|
||||||
|
case -ERESTARTNOINTR:
|
||||||
|
regs->a0 = regs->orig_a0;
|
||||||
|
regs->sepc -= 0x4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set up the stack frame */
|
||||||
|
ret = setup_rt_frame(ksig, oldset, regs);
|
||||||
|
|
||||||
|
signal_setup_done(ret, ksig, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_signal(struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
struct ksignal ksig;
|
||||||
|
|
||||||
|
if (get_signal(&ksig)) {
|
||||||
|
/* Actually deliver the signal */
|
||||||
|
handle_signal(&ksig, regs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Did we come from a system call? */
|
||||||
|
if (regs->scause == EXC_SYSCALL) {
|
||||||
|
/* Restart the system call - no handlers present */
|
||||||
|
switch (regs->a0) {
|
||||||
|
case -ERESTARTNOHAND:
|
||||||
|
case -ERESTARTSYS:
|
||||||
|
case -ERESTARTNOINTR:
|
||||||
|
regs->a0 = regs->orig_a0;
|
||||||
|
regs->sepc -= 0x4;
|
||||||
|
break;
|
||||||
|
case -ERESTART_RESTARTBLOCK:
|
||||||
|
regs->a0 = regs->orig_a0;
|
||||||
|
regs->a7 = __NR_restart_syscall;
|
||||||
|
regs->sepc -= 0x4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there is no signal to deliver, we just put the saved
|
||||||
|
* sigmask back.
|
||||||
|
*/
|
||||||
|
restore_saved_sigmask();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* notification of userspace execution resumption
|
||||||
|
* - triggered by the _TIF_WORK_MASK flags
|
||||||
|
*/
|
||||||
|
asmlinkage void do_notify_resume(struct pt_regs *regs,
|
||||||
|
unsigned long thread_info_flags)
|
||||||
|
{
|
||||||
|
/* Handle pending signal delivery */
|
||||||
|
if (thread_info_flags & _TIF_SIGPENDING)
|
||||||
|
do_signal(regs);
|
||||||
|
|
||||||
|
if (thread_info_flags & _TIF_NOTIFY_RESUME) {
|
||||||
|
clear_thread_flag(TIF_NOTIFY_RESUME);
|
||||||
|
tracehook_notify_resume(regs);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012 Regents of the University of California
|
||||||
|
* Copyright (C) 2014 Darius Rad <darius@bluespec.com>
|
||||||
|
* Copyright (C) 2017 SiFive
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/syscalls.h>
|
||||||
|
#include <asm/cmpxchg.h>
|
||||||
|
#include <asm/unistd.h>
|
||||||
|
|
||||||
|
static long riscv_sys_mmap(unsigned long addr, unsigned long len,
|
||||||
|
unsigned long prot, unsigned long flags,
|
||||||
|
unsigned long fd, off_t offset,
|
||||||
|
unsigned long page_shift_offset)
|
||||||
|
{
|
||||||
|
if (unlikely(offset & (~PAGE_MASK >> page_shift_offset)))
|
||||||
|
return -EINVAL;
|
||||||
|
return sys_mmap_pgoff(addr, len, prot, flags, fd,
|
||||||
|
offset >> (PAGE_SHIFT - page_shift_offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_64BIT
|
||||||
|
SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
|
||||||
|
unsigned long, prot, unsigned long, flags,
|
||||||
|
unsigned long, fd, off_t, offset)
|
||||||
|
{
|
||||||
|
return riscv_sys_mmap(addr, len, prot, flags, fd, offset, 0);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
SYSCALL_DEFINE6(mmap2, unsigned long, addr, unsigned long, len,
|
||||||
|
unsigned long, prot, unsigned long, flags,
|
||||||
|
unsigned long, fd, off_t, offset)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Note that the shift for mmap2 is constant (12),
|
||||||
|
* regardless of PAGE_SIZE
|
||||||
|
*/
|
||||||
|
return riscv_sys_mmap(addr, len, prot, flags, fd, offset, 12);
|
||||||
|
}
|
||||||
|
#endif /* !CONFIG_64BIT */
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2009 Arnd Bergmann <arnd@arndb.de>
|
||||||
|
* Copyright (C) 2012 Regents of the University of California
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/linkage.h>
|
||||||
|
#include <linux/syscalls.h>
|
||||||
|
#include <asm-generic/syscalls.h>
|
||||||
|
|
||||||
|
#undef __SYSCALL
|
||||||
|
#define __SYSCALL(nr, call) [nr] = (call),
|
||||||
|
|
||||||
|
void *sys_call_table[__NR_syscalls] = {
|
||||||
|
[0 ... __NR_syscalls - 1] = sys_ni_syscall,
|
||||||
|
#include <asm/unistd.h>
|
||||||
|
};
|
|
@ -0,0 +1,2 @@
|
||||||
|
vdso.lds
|
||||||
|
*.tmp
|
|
@ -0,0 +1,63 @@
|
||||||
|
# Copied from arch/tile/kernel/vdso/Makefile
|
||||||
|
|
||||||
|
# Symbols present in the vdso
|
||||||
|
vdso-syms = rt_sigreturn
|
||||||
|
|
||||||
|
# Files to link into the vdso
|
||||||
|
obj-vdso = $(patsubst %, %.o, $(vdso-syms))
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# Force dependency
|
||||||
|
$(obj)/vdso.o: $(obj)/vdso.so
|
||||||
|
|
||||||
|
# link rule for the .so file, .lds has to be first
|
||||||
|
SYSCFLAGS_vdso.so.dbg = $(c_flags)
|
||||||
|
$(obj)/vdso.so.dbg: $(src)/vdso.lds $(obj-vdso) FORCE
|
||||||
|
$(call if_changed,vdsold)
|
||||||
|
|
||||||
|
# We also create a special relocatable object that should mirror the symbol
|
||||||
|
# table and layout of the linked DSO. With ld -R we can then refer to
|
||||||
|
# these symbols in the kernel code rather than hand-coded addresses.
|
||||||
|
|
||||||
|
SYSCFLAGS_vdso.so.dbg = -shared -s -Wl,-soname=linux-vdso.so.1 \
|
||||||
|
$(call cc-ldoption, -Wl$(comma)--hash-style=both)
|
||||||
|
$(obj)/vdso-dummy.o: $(src)/vdso.lds $(obj)/rt_sigreturn.o FORCE
|
||||||
|
$(call if_changed,vdsold)
|
||||||
|
|
||||||
|
LDFLAGS_vdso-syms.o := -r -R
|
||||||
|
$(obj)/vdso-syms.o: $(obj)/vdso-dummy.o FORCE
|
||||||
|
$(call if_changed,ld)
|
||||||
|
|
||||||
|
# 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
|
||||||
|
# Add -lgcc so rv32 gets static muldi3 and lshrdi3 definitions.
|
||||||
|
# Make sure only to export the intended __vdso_xxx symbol offsets.
|
||||||
|
quiet_cmd_vdsold = VDSOLD $@
|
||||||
|
cmd_vdsold = $(CC) $(KCFLAGS) -nostdlib $(SYSCFLAGS_$(@F)) \
|
||||||
|
-Wl,-T,$(filter-out FORCE,$^) -o $@.tmp -lgcc && \
|
||||||
|
$(CROSS_COMPILE)objcopy \
|
||||||
|
$(patsubst %, -G __vdso_%, $(vdso-syms)) $@.tmp $@
|
||||||
|
|
||||||
|
# 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
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Regents of the University of California
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/linkage.h>
|
||||||
|
#include <asm/unistd.h>
|
||||||
|
|
||||||
|
.text
|
||||||
|
ENTRY(__vdso_rt_sigreturn)
|
||||||
|
.cfi_startproc
|
||||||
|
.cfi_signal_frame
|
||||||
|
li a7, __NR_rt_sigreturn
|
||||||
|
scall
|
||||||
|
.cfi_endproc
|
||||||
|
ENDPROC(__vdso_rt_sigreturn)
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Regents of the University of California
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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/riscv/kernel/vdso/vdso.so"
|
||||||
|
.balign PAGE_SIZE
|
||||||
|
vdso_end:
|
||||||
|
|
||||||
|
.previous
|
|
@ -0,0 +1,77 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012 Regents of the University of California
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
OUTPUT_ARCH(riscv)
|
||||||
|
|
||||||
|
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
|
||||||
|
.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.*) }
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This linker script is used both with -r and with -shared.
|
||||||
|
* For the layouts to match, we need to skip more than enough
|
||||||
|
* space for the dynamic symbol table, etc. If this amount is
|
||||||
|
* insufficient, ld -shared will error; simply increase it here.
|
||||||
|
*/
|
||||||
|
. = 0x800;
|
||||||
|
.text : { *(.text .text.*) } :text
|
||||||
|
|
||||||
|
.data : {
|
||||||
|
*(.got.plt) *(.got)
|
||||||
|
*(.data .data.* .gnu.linkonce.d.*)
|
||||||
|
*(.dynbss)
|
||||||
|
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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_4.15 {
|
||||||
|
global:
|
||||||
|
__vdso_rt_sigreturn;
|
||||||
|
__vdso_cmpxchg32;
|
||||||
|
__vdso_cmpxchg64;
|
||||||
|
local: *;
|
||||||
|
};
|
||||||
|
}
|
Загрузка…
Ссылка в новой задаче